summaryrefslogtreecommitdiff
path: root/chromium/content
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/content')
-rw-r--r--chromium/content/BUILD.gn29
-rw-r--r--chromium/content/DEPS15
-rw-r--r--chromium/content/OWNERS1
-rw-r--r--chromium/content/app/BUILD.gn29
-rw-r--r--chromium/content/app/DEPS5
-rw-r--r--chromium/content/app/OWNERS1
-rw-r--r--chromium/content/app/android/child_process_service.cc24
-rw-r--r--chromium/content/app/android/content_main.cc2
-rw-r--r--chromium/content/app/android/library_loader_hooks.cc34
-rw-r--r--chromium/content/app/android/library_loader_hooks.h26
-rw-r--r--chromium/content/app/content_main_runner.cc159
-rw-r--r--chromium/content/app/mac/mac_init.h17
-rw-r--r--chromium/content/app/mac/mac_init.mm25
-rw-r--r--chromium/content/app/mojo/mojo_browsertest.cc2
-rw-r--r--chromium/content/app/mojo/mojo_init.cc26
-rw-r--r--chromium/content/app/mojo/mojo_init.h2
-rw-r--r--chromium/content/app/resources/content_resources.grd50
-rw-r--r--chromium/content/app/resources/default_100_percent/broken_image.pngbin448 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_cast_off.pngbin37155 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_cast_on.pngbin37155 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_closedcaption.pngbin2499 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_closedcaption_disabled.pngbin2764 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_closedcaption_down.pngbin8520 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_closedcaption_hover.pngbin7995 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_fullscreen.pngbin1116 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_fullscreen_disabled.pngbin780 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_fullscreen_down.pngbin4844 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_fullscreen_hover.pngbin4649 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_overlay_cast_off.pngbin1293 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_overlay_play.pngbin1243 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_pause.pngbin814 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_pause_down.pngbin4687 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_pause_hover.pngbin4507 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_play.pngbin1243 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_play_disabled.pngbin1007 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_play_down.pngbin5591 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_play_hover.pngbin5434 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_slider_thumb.pngbin4035 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_slider_thumb_down.pngbin5450 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_slider_thumb_hover.pngbin5294 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_sound_disabled.pngbin1283 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_sound_level0.pngbin1051 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_sound_level0_down.pngbin10516 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_sound_level0_hover.pngbin10396 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_sound_level1.pngbin962 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_sound_level1_down.pngbin5440 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_sound_level1_hover.pngbin5257 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_sound_level2.pngbin1263 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_sound_level2_down.pngbin10327 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_sound_level2_hover.pngbin10113 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_sound_level3.pngbin1669 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_sound_level3_down.pngbin12290 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_sound_level3_hover.pngbin12122 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_volume_slider_thumb.pngbin3749 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_volume_slider_thumb_disabled.pngbin2516 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_volume_slider_thumb_down.pngbin4941 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/mediaplayer_volume_slider_thumb_hover.pngbin4773 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/overhang_pattern.pngbin20057 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/overhang_shadow.pngbin151 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/pan_icon.pngbin136 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/password_generation.pngbin407 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/password_generation_hover.pngbin408 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/search_cancel.pngbin744 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/search_cancel_pressed.pngbin761 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/search_magnifier.pngbin872 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/search_magnifier_results.pngbin1040 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_100_percent/textarea_resize_corner.pngbin92 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_200_percent/broken_image.pngbin810 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_200_percent/pan_icon.pngbin141 -> 0 bytes
-rw-r--r--chromium/content/app/resources/default_200_percent/textarea_resize_corner.pngbin147 -> 0 bytes
-rw-r--r--chromium/content/app/startup_helper_win.cc5
-rw-r--r--chromium/content/app/strings/content_strings.grd37
-rw-r--r--chromium/content/browser/BUILD.gn144
-rw-r--r--chromium/content/browser/DEPS34
-rw-r--r--chromium/content/browser/OWNERS1
-rw-r--r--chromium/content/browser/accessibility/accessibility_event_recorder.cc26
-rw-r--r--chromium/content/browser/accessibility/accessibility_event_recorder.h52
-rw-r--r--chromium/content/browser/accessibility/accessibility_event_recorder_mac.mm153
-rw-r--r--chromium/content/browser/accessibility/accessibility_event_recorder_win.cc292
-rw-r--r--chromium/content/browser/accessibility/accessibility_ipc_error_browsertest.cc2
-rw-r--r--chromium/content/browser/accessibility/accessibility_tree_formatter.cc37
-rw-r--r--chromium/content/browser/accessibility/accessibility_tree_formatter.h47
-rw-r--r--chromium/content/browser/accessibility/accessibility_tree_formatter_android.cc16
-rw-r--r--chromium/content/browser/accessibility/accessibility_tree_formatter_mac.mm21
-rw-r--r--chromium/content/browser/accessibility/accessibility_tree_formatter_utils_win.cc107
-rw-r--r--chromium/content/browser/accessibility/accessibility_tree_formatter_utils_win.h5
-rw-r--r--chromium/content/browser/accessibility/accessibility_tree_formatter_win.cc13
-rw-r--r--chromium/content/browser/accessibility/accessibility_ui.cc3
-rw-r--r--chromium/content/browser/accessibility/accessibility_ui.h6
-rw-r--r--chromium/content/browser/accessibility/accessibility_win_browsertest.cc950
-rw-r--r--chromium/content/browser/accessibility/android_granularity_movement_browsertest.cc2
-rw-r--r--chromium/content/browser/accessibility/android_hit_testing_browsertest.cc2
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility.cc323
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility.h62
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_android.cc86
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_android.h10
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_cocoa.h5
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_cocoa.mm648
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_mac.h2
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_mac_unittest.mm2
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager.cc78
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager.h26
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager_android.cc40
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager_android.h12
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager_mac.h7
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager_mac.mm47
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager_unittest.cc62
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager_win.cc185
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager_win.h17
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_state_impl.cc3
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_state_impl.h14
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_state_impl_win.cc3
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_win.cc1456
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_win.h263
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_win_unittest.cc330
-rw-r--r--chromium/content/browser/accessibility/cross_platform_accessibility_browsertest.cc22
-rw-r--r--chromium/content/browser/accessibility/dump_accessibility_browsertest_base.cc246
-rw-r--r--chromium/content/browser/accessibility/dump_accessibility_browsertest_base.h90
-rw-r--r--chromium/content/browser/accessibility/dump_accessibility_events_browsertest.cc260
-rw-r--r--chromium/content/browser/accessibility/dump_accessibility_tree_browsertest.cc949
-rw-r--r--chromium/content/browser/accessibility/one_shot_accessibility_tree_search.cc182
-rw-r--r--chromium/content/browser/accessibility/one_shot_accessibility_tree_search.h105
-rw-r--r--chromium/content/browser/accessibility/one_shot_accessibility_tree_search_unittest.cc174
-rw-r--r--chromium/content/browser/accessibility/site_per_process_accessibility_browsertest.cc70
-rw-r--r--chromium/content/browser/accessibility/snapshot_ax_tree_browsertest.cc77
-rw-r--r--chromium/content/browser/android/animation_utils.h33
-rw-r--r--chromium/content/browser/android/browser_startup_controller.h6
-rw-r--r--chromium/content/browser/android/browser_surface_texture_manager.cc8
-rw-r--r--chromium/content/browser/android/browser_surface_texture_manager.h16
-rw-r--r--chromium/content/browser/android/child_process_launcher_android.cc18
-rw-r--r--chromium/content/browser/android/composited_touch_handle_drawable.cc61
-rw-r--r--chromium/content/browser/android/composited_touch_handle_drawable.h25
-rw-r--r--chromium/content/browser/android/content_protocol_handler_impl.cc43
-rw-r--r--chromium/content/browser/android/content_protocol_handler_impl.h45
-rw-r--r--chromium/content/browser/android/content_readback_handler.cc26
-rw-r--r--chromium/content/browser/android/content_readback_handler.h5
-rw-r--r--chromium/content/browser/android/content_settings.cc58
-rw-r--r--chromium/content/browser/android/content_settings.h37
-rw-r--r--chromium/content/browser/android/content_startup_flags.cc17
-rw-r--r--chromium/content/browser/android/content_video_view.cc42
-rw-r--r--chromium/content/browser/android/content_video_view.h9
-rw-r--r--chromium/content/browser/android/content_view_core_impl.cc235
-rw-r--r--chromium/content/browser/android/content_view_core_impl.h89
-rw-r--r--chromium/content/browser/android/content_view_render_view.cc42
-rw-r--r--chromium/content/browser/android/content_view_render_view.h9
-rw-r--r--chromium/content/browser/android/content_view_statics.cc9
-rw-r--r--chromium/content/browser/android/content_view_statics.h6
-rw-r--r--chromium/content/browser/android/date_time_chooser_android.cc26
-rw-r--r--chromium/content/browser/android/date_time_chooser_android.h7
-rw-r--r--chromium/content/browser/android/deferred_download_observer.cc31
-rw-r--r--chromium/content/browser/android/deferred_download_observer.h41
-rw-r--r--chromium/content/browser/android/download_controller_android_impl.cc65
-rw-r--r--chromium/content/browser/android/download_controller_android_impl.h33
-rw-r--r--chromium/content/browser/android/edge_effect.cc65
-rw-r--r--chromium/content/browser/android/edge_effect.h31
-rw-r--r--chromium/content/browser/android/edge_effect_base.h1
-rw-r--r--chromium/content/browser/android/edge_effect_l.cc44
-rw-r--r--chromium/content/browser/android/edge_effect_l.h33
-rw-r--r--chromium/content/browser/android/gesture_event_type.h6
-rw-r--r--chromium/content/browser/android/in_process/DEPS1
-rw-r--r--chromium/content/browser/android/in_process/OWNERS1
-rw-r--r--chromium/content/browser/android/in_process/context_provider_in_process.cc235
-rw-r--r--chromium/content/browser/android/in_process/context_provider_in_process.h95
-rw-r--r--chromium/content/browser/android/in_process/synchronous_compositor_external_begin_frame_source.cc67
-rw-r--r--chromium/content/browser/android/in_process/synchronous_compositor_external_begin_frame_source.h44
-rw-r--r--chromium/content/browser/android/in_process/synchronous_compositor_factory_impl.cc179
-rw-r--r--chromium/content/browser/android/in_process/synchronous_compositor_factory_impl.h38
-rw-r--r--chromium/content/browser/android/in_process/synchronous_compositor_impl.cc194
-rw-r--r--chromium/content/browser/android/in_process/synchronous_compositor_impl.h74
-rw-r--r--chromium/content/browser/android/in_process/synchronous_compositor_output_surface.cc125
-rw-r--r--chromium/content/browser/android/in_process/synchronous_compositor_output_surface.h52
-rw-r--r--chromium/content/browser/android/in_process/synchronous_compositor_registry.cc171
-rw-r--r--chromium/content/browser/android/in_process/synchronous_compositor_registry.h75
-rw-r--r--chromium/content/browser/android/in_process/synchronous_input_event_filter.cc21
-rw-r--r--chromium/content/browser/android/in_process/synchronous_input_event_filter.h18
-rw-r--r--chromium/content/browser/android/interstitial_page_delegate_android.h10
-rw-r--r--chromium/content/browser/android/java/gin_java_bound_object.cc6
-rw-r--r--chromium/content/browser/android/java/gin_java_bound_object.h22
-rw-r--r--chromium/content/browser/android/java/gin_java_bound_object_delegate.h16
-rw-r--r--chromium/content/browser/android/java/gin_java_bridge_dispatcher_host.cc543
-rw-r--r--chromium/content/browser/android/java/gin_java_bridge_dispatcher_host.h115
-rw-r--r--chromium/content/browser/android/java/gin_java_method_invocation_helper.cc7
-rw-r--r--chromium/content/browser/android/java/gin_java_method_invocation_helper.h10
-rw-r--r--chromium/content/browser/android/java/gin_java_method_invocation_helper_unittest.cc50
-rw-r--r--chromium/content/browser/android/java/gin_java_script_to_java_types_coercion.cc4
-rw-r--r--chromium/content/browser/android/load_url_params.cc21
-rw-r--r--chromium/content/browser/android/media_players_observer.cc59
-rw-r--r--chromium/content/browser/android/media_players_observer.h51
-rw-r--r--chromium/content/browser/android/overscroll_controller_android.cc294
-rw-r--r--chromium/content/browser/android/overscroll_controller_android.h91
-rw-r--r--chromium/content/browser/android/overscroll_glow.cc134
-rw-r--r--chromium/content/browser/android/overscroll_glow.h79
-rw-r--r--chromium/content/browser/android/overscroll_refresh.cc104
-rw-r--r--chromium/content/browser/android/overscroll_refresh.h104
-rw-r--r--chromium/content/browser/android/overscroll_refresh_unittest.cc241
-rw-r--r--chromium/content/browser/android/popup_touch_handle_drawable.cc43
-rw-r--r--chromium/content/browser/android/popup_touch_handle_drawable.h21
-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.cc12
-rw-r--r--chromium/content/browser/android/ui_resource_provider_impl.cc72
-rw-r--r--chromium/content/browser/android/ui_resource_provider_impl.h55
-rw-r--r--chromium/content/browser/android/url_request_content_job.cc228
-rw-r--r--chromium/content/browser/android/url_request_content_job.h103
-rw-r--r--chromium/content/browser/android/url_request_content_job_unittest.cc198
-rw-r--r--chromium/content/browser/android/web_contents_observer_android.cc325
-rw-r--r--chromium/content/browser/android/web_contents_observer_android.h88
-rw-r--r--chromium/content/browser/android/web_contents_observer_proxy.cc290
-rw-r--r--chromium/content/browser/android/web_contents_observer_proxy.h87
-rw-r--r--chromium/content/browser/appcache/appcache_database.cc38
-rw-r--r--chromium/content/browser/appcache/appcache_database.h6
-rw-r--r--chromium/content/browser/appcache/appcache_disk_cache.cc109
-rw-r--r--chromium/content/browser/appcache/appcache_disk_cache.h5
-rw-r--r--chromium/content/browser/appcache/appcache_entry.h2
-rw-r--r--chromium/content/browser/appcache/appcache_group.cc4
-rw-r--r--chromium/content/browser/appcache/appcache_group.h4
-rw-r--r--chromium/content/browser/appcache/appcache_host.cc12
-rw-r--r--chromium/content/browser/appcache/appcache_host.h3
-rw-r--r--chromium/content/browser/appcache/appcache_interceptor.cc68
-rw-r--r--chromium/content/browser/appcache/appcache_interceptor.h52
-rw-r--r--chromium/content/browser/appcache/appcache_manifest_parser.cc5
-rw-r--r--chromium/content/browser/appcache/appcache_request_handler.cc26
-rw-r--r--chromium/content/browser/appcache/appcache_request_handler.h9
-rw-r--r--chromium/content/browser/appcache/appcache_request_handler_unittest.cc86
-rw-r--r--chromium/content/browser/appcache/appcache_response.cc156
-rw-r--r--chromium/content/browser/appcache/appcache_response.h50
-rw-r--r--chromium/content/browser/appcache/appcache_response_unittest.cc102
-rw-r--r--chromium/content/browser/appcache/appcache_storage.h6
-rw-r--r--chromium/content/browser/appcache/appcache_storage_impl.cc96
-rw-r--r--chromium/content/browser/appcache/appcache_storage_impl.h11
-rw-r--r--chromium/content/browser/appcache/appcache_storage_impl_unittest.cc8
-rw-r--r--chromium/content/browser/appcache/appcache_update_job.cc46
-rw-r--r--chromium/content/browser/appcache/appcache_update_job.h2
-rw-r--r--chromium/content/browser/appcache/appcache_update_job_unittest.cc34
-rw-r--r--chromium/content/browser/appcache/appcache_url_request_job.cc6
-rw-r--r--chromium/content/browser/appcache/appcache_url_request_job.h2
-rw-r--r--chromium/content/browser/appcache/appcache_url_request_job_unittest.cc16
-rw-r--r--chromium/content/browser/appcache/chrome_appcache_service.cc11
-rw-r--r--chromium/content/browser/appcache/mock_appcache_storage.cc7
-rw-r--r--chromium/content/browser/appcache/mock_appcache_storage.h3
-rw-r--r--chromium/content/browser/appcache/view_appcache_internals_job.cc13
-rw-r--r--chromium/content/browser/background_sync/BUILD.gn11
-rw-r--r--chromium/content/browser/background_sync/OWNERS1
-rw-r--r--chromium/content/browser/background_sync/PRESUBMIT.py12
-rw-r--r--chromium/content/browser/background_sync/background_sync.proto47
-rw-r--r--chromium/content/browser/background_sync/background_sync_context_impl.cc60
-rw-r--r--chromium/content/browser/background_sync/background_sync_context_impl.h53
-rw-r--r--chromium/content/browser/background_sync/background_sync_manager.cc881
-rw-r--r--chromium/content/browser/background_sync/background_sync_manager.h317
-rw-r--r--chromium/content/browser/background_sync/background_sync_manager_unittest.cc1161
-rw-r--r--chromium/content/browser/background_sync/background_sync_network_observer.cc64
-rw-r--r--chromium/content/browser/background_sync/background_sync_network_observer.h45
-rw-r--r--chromium/content/browser/background_sync/background_sync_network_observer_unittest.cc108
-rw-r--r--chromium/content/browser/background_sync/background_sync_proto.gyp17
-rw-r--r--chromium/content/browser/bad_message.cc22
-rw-r--r--chromium/content/browser/bad_message.h57
-rw-r--r--chromium/content/browser/battery_status/OWNERS2
-rw-r--r--chromium/content/browser/battery_status/battery_monitor_impl_browsertest.cc155
-rw-r--r--chromium/content/browser/battery_status/battery_monitor_integration_browsertest.cc177
-rw-r--r--chromium/content/browser/battery_status/battery_status_browsertest.cc167
-rw-r--r--chromium/content/browser/battery_status/battery_status_message_filter.h36
-rw-r--r--chromium/content/browser/bluetooth/DEPS3
-rw-r--r--chromium/content/browser/bluetooth/OWNERS1
-rw-r--r--chromium/content/browser/bluetooth/PRESUBMIT.py14
-rw-r--r--chromium/content/browser/bluetooth/bluetooth_dispatcher_host.cc221
-rw-r--r--chromium/content/browser/bluetooth/bluetooth_dispatcher_host.h86
-rw-r--r--chromium/content/browser/bootstrap_sandbox_mac.cc7
-rw-r--r--chromium/content/browser/browser.gni15
-rw-r--r--chromium/content/browser/browser_child_process_host_impl.cc73
-rw-r--r--chromium/content/browser/browser_child_process_host_impl.h14
-rw-r--r--chromium/content/browser/browser_context.cc27
-rw-r--r--chromium/content/browser/browser_ipc_logging.cc2
-rw-r--r--chromium/content/browser/browser_main.cc6
-rw-r--r--chromium/content/browser/browser_main_loop.cc292
-rw-r--r--chromium/content/browser/browser_main_loop.h26
-rw-r--r--chromium/content/browser/browser_main_runner.cc58
-rw-r--r--chromium/content/browser/browser_plugin/browser_plugin_embedder.cc111
-rw-r--r--chromium/content/browser/browser_plugin/browser_plugin_embedder.h61
-rw-r--r--chromium/content/browser/browser_plugin/browser_plugin_guest.cc410
-rw-r--r--chromium/content/browser/browser_plugin/browser_plugin_guest.h112
-rw-r--r--chromium/content/browser/browser_plugin/browser_plugin_message_filter.cc32
-rw-r--r--chromium/content/browser/browser_plugin/browser_plugin_message_filter.h8
-rw-r--r--chromium/content/browser/browser_process_sub_thread.cc6
-rw-r--r--chromium/content/browser/browser_shutdown_profile_dumper.cc20
-rw-r--r--chromium/content/browser/browser_side_navigation_browsertest.cc188
-rw-r--r--chromium/content/browser/browser_thread_impl.cc17
-rw-r--r--chromium/content/browser/browser_url_handler_impl.cc15
-rw-r--r--chromium/content/browser/browser_url_handler_impl.h7
-rw-r--r--chromium/content/browser/cache_storage/BUILD.gn11
-rw-r--r--chromium/content/browser/cache_storage/OWNERS4
-rw-r--r--chromium/content/browser/cache_storage/PRESUBMIT.py14
-rw-r--r--chromium/content/browser/cache_storage/cache_storage.cc860
-rw-r--r--chromium/content/browser/cache_storage/cache_storage.h226
-rw-r--r--chromium/content/browser/cache_storage/cache_storage.proto46
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_cache.cc1275
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_cache.h226
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_cache_unittest.cc871
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_context_impl.cc104
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_context_impl.h87
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_dispatcher_host.cc433
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_dispatcher_host.h155
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_manager.cc364
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_manager.h159
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_manager_unittest.cc800
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_proto.gyp17
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_quota_client.cc95
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_quota_client.h53
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_scheduler.cc47
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_scheduler.h51
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_scheduler_unittest.cc81
-rw-r--r--chromium/content/browser/child_process_launcher.cc763
-rw-r--r--chromium/content/browser/child_process_launcher.h55
-rw-r--r--chromium/content/browser/child_process_launcher_browsertest.cc70
-rw-r--r--chromium/content/browser/child_process_security_policy_browsertest.cc3
-rw-r--r--chromium/content/browser/child_process_security_policy_impl.h4
-rw-r--r--chromium/content/browser/cocoa/system_hotkey_helper_mac.mm4
-rw-r--r--chromium/content/browser/cocoa/system_hotkey_map_unittest.mm4
-rw-r--r--chromium/content/browser/compositor/DEPS3
-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.cc59
-rw-r--r--chromium/content/browser/compositor/browser_compositor_output_surface.h33
-rw-r--r--chromium/content/browser/compositor/browser_compositor_output_surface_proxy.cc58
-rw-r--r--chromium/content/browser/compositor/browser_compositor_output_surface_proxy.h51
-rw-r--r--chromium/content/browser/compositor/browser_compositor_overlay_candidate_validator.h28
-rw-r--r--chromium/content/browser/compositor/browser_compositor_overlay_candidate_validator_ozone.cc76
-rw-r--r--chromium/content/browser/compositor/browser_compositor_overlay_candidate_validator_ozone.h41
-rw-r--r--chromium/content/browser/compositor/browser_compositor_view_mac.h118
-rw-r--r--chromium/content/browser/compositor/browser_compositor_view_mac.mm131
-rw-r--r--chromium/content/browser/compositor/buffer_queue.cc75
-rw-r--r--chromium/content/browser/compositor/buffer_queue.h23
-rw-r--r--chromium/content/browser/compositor/buffer_queue_unittest.cc197
-rw-r--r--chromium/content/browser/compositor/delegated_frame_host.cc402
-rw-r--r--chromium/content/browser/compositor/delegated_frame_host.h133
-rw-r--r--chromium/content/browser/compositor/gpu_browser_compositor_output_surface.cc94
-rw-r--r--chromium/content/browser/compositor/gpu_browser_compositor_output_surface.h33
-rw-r--r--chromium/content/browser/compositor/gpu_process_transport_factory.cc439
-rw-r--r--chromium/content/browser/compositor/gpu_process_transport_factory.h36
-rw-r--r--chromium/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc43
-rw-r--r--chromium/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h10
-rw-r--r--chromium/content/browser/compositor/image_transport_factory.h13
-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/offscreen_browser_compositor_output_surface.cc152
-rw-r--r--chromium/content/browser/compositor/offscreen_browser_compositor_output_surface.h62
-rw-r--r--chromium/content/browser/compositor/onscreen_display_client.cc96
-rw-r--r--chromium/content/browser/compositor/onscreen_display_client.h70
-rw-r--r--chromium/content/browser/compositor/overlay_candidate_validator_ozone.cc58
-rw-r--r--chromium/content/browser/compositor/overlay_candidate_validator_ozone.h39
-rw-r--r--chromium/content/browser/compositor/reflector_impl.cc330
-rw-r--r--chromium/content/browser/compositor/reflector_impl.h144
-rw-r--r--chromium/content/browser/compositor/reflector_impl_unittest.cc222
-rw-r--r--chromium/content/browser/compositor/reflector_texture.cc48
-rw-r--r--chromium/content/browser/compositor/reflector_texture.h47
-rw-r--r--chromium/content/browser/compositor/resize_lock.h2
-rw-r--r--chromium/content/browser/compositor/software_browser_compositor_output_surface.cc39
-rw-r--r--chromium/content/browser/compositor/software_browser_compositor_output_surface.h11
-rw-r--r--chromium/content/browser/compositor/software_browser_compositor_output_surface_unittest.cc13
-rw-r--r--chromium/content/browser/compositor/software_layer_mac.h22
-rw-r--r--chromium/content/browser/compositor/software_layer_mac.mm68
-rw-r--r--chromium/content/browser/compositor/software_output_device_mac.mm6
-rw-r--r--chromium/content/browser/compositor/software_output_device_ozone.cc2
-rw-r--r--chromium/content/browser/compositor/software_output_device_ozone.h8
-rw-r--r--chromium/content/browser/compositor/software_output_device_ozone_unittest.cc124
-rw-r--r--chromium/content/browser/compositor/software_output_device_win.cc129
-rw-r--r--chromium/content/browser/compositor/software_output_device_win.h49
-rw-r--r--chromium/content/browser/compositor/software_output_device_x11.cc14
-rw-r--r--chromium/content/browser/compositor/surface_display_output_surface.cc90
-rw-r--r--chromium/content/browser/compositor/surface_display_output_surface.h63
-rw-r--r--chromium/content/browser/cross_site_transfer_browsertest.cc82
-rw-r--r--chromium/content/browser/device_monitor_mac.mm51
-rw-r--r--chromium/content/browser/device_monitor_udev.cc9
-rw-r--r--chromium/content/browser/device_sensors/ambient_light_mac.cc78
-rw-r--r--chromium/content/browser/device_sensors/ambient_light_mac.h40
-rw-r--r--chromium/content/browser/device_sensors/data_fetcher_shared_memory.h20
-rw-r--r--chromium/content/browser/device_sensors/data_fetcher_shared_memory_android.cc5
-rw-r--r--chromium/content/browser/device_sensors/data_fetcher_shared_memory_base.cc12
-rw-r--r--chromium/content/browser/device_sensors/data_fetcher_shared_memory_base.h2
-rw-r--r--chromium/content/browser/device_sensors/data_fetcher_shared_memory_base_unittest.cc6
-rw-r--r--chromium/content/browser/device_sensors/data_fetcher_shared_memory_chromeos.cc53
-rw-r--r--chromium/content/browser/device_sensors/data_fetcher_shared_memory_default.cc12
-rw-r--r--chromium/content/browser/device_sensors/data_fetcher_shared_memory_mac.cc95
-rw-r--r--chromium/content/browser/device_sensors/data_fetcher_shared_memory_win.cc127
-rw-r--r--chromium/content/browser/device_sensors/device_inertial_sensor_browsertest.cc124
-rw-r--r--chromium/content/browser/device_sensors/device_inertial_sensor_service.cc4
-rw-r--r--chromium/content/browser/device_sensors/device_light_message_filter.cc2
-rw-r--r--chromium/content/browser/device_sensors/device_motion_message_filter.cc2
-rw-r--r--chromium/content/browser/device_sensors/device_orientation_message_filter.cc2
-rw-r--r--chromium/content/browser/device_sensors/sensor_manager_android.cc156
-rw-r--r--chromium/content/browser/device_sensors/sensor_manager_android.h13
-rw-r--r--chromium/content/browser/device_sensors/sensor_manager_android_unittest.cc16
-rw-r--r--chromium/content/browser/device_sensors/sensor_manager_chromeos.cc173
-rw-r--r--chromium/content/browser/device_sensors/sensor_manager_chromeos.h69
-rw-r--r--chromium/content/browser/device_sensors/sensor_manager_chromeos_unittest.cc228
-rw-r--r--chromium/content/browser/devtools/BUILD.gn58
-rw-r--r--chromium/content/browser/devtools/OWNERS1
-rw-r--r--chromium/content/browser/devtools/browser_devtools_agent_host.cc65
-rw-r--r--chromium/content/browser/devtools/browser_devtools_agent_host.h44
-rw-r--r--chromium/content/browser/devtools/browser_protocol.json22
-rw-r--r--chromium/content/browser/devtools/devtools.gyp9
-rw-r--r--chromium/content/browser/devtools/devtools_agent_host_impl.cc104
-rw-r--r--chromium/content/browser/devtools/devtools_agent_host_impl.h12
-rw-r--r--chromium/content/browser/devtools/devtools_frame_trace_recorder.cc141
-rw-r--r--chromium/content/browser/devtools/devtools_frame_trace_recorder.h36
-rw-r--r--chromium/content/browser/devtools/devtools_frontend_host_impl.cc40
-rw-r--r--chromium/content/browser/devtools/devtools_frontend_host_impl.h7
-rw-r--r--chromium/content/browser/devtools/devtools_http_handler_impl.cc989
-rw-r--r--chromium/content/browser/devtools/devtools_http_handler_impl.h138
-rw-r--r--chromium/content/browser/devtools/devtools_http_handler_unittest.cc165
-rw-r--r--chromium/content/browser/devtools/devtools_manager.cc99
-rw-r--r--chromium/content/browser/devtools/devtools_manager.h44
-rw-r--r--chromium/content/browser/devtools/devtools_manager_unittest.cc243
-rw-r--r--chromium/content/browser/devtools/devtools_netlog_observer.cc13
-rw-r--r--chromium/content/browser/devtools/devtools_netlog_observer.h2
-rw-r--r--chromium/content/browser/devtools/devtools_protocol.cc331
-rw-r--r--chromium/content/browser/devtools/devtools_protocol.h195
-rw-r--r--chromium/content/browser/devtools/devtools_resources.gyp46
-rw-r--r--chromium/content/browser/devtools/devtools_system_info_handler.cc130
-rw-r--r--chromium/content/browser/devtools/devtools_system_info_handler.h28
-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.cc207
-rw-r--r--chromium/content/browser/devtools/embedded_worker_devtools_manager.h119
-rw-r--r--chromium/content/browser/devtools/embedded_worker_devtools_manager_unittest.cc298
-rw-r--r--chromium/content/browser/devtools/forwarding_agent_host.cc22
-rw-r--r--chromium/content/browser/devtools/forwarding_agent_host.h8
-rw-r--r--chromium/content/browser/devtools/ipc_devtools_agent_host.cc42
-rw-r--r--chromium/content/browser/devtools/ipc_devtools_agent_host.h11
-rw-r--r--chromium/content/browser/devtools/protocol/color_picker.cc71
-rw-r--r--chromium/content/browser/devtools/protocol/color_picker.h8
-rw-r--r--chromium/content/browser/devtools/protocol/devtools_protocol_browsertest.cc264
-rw-r--r--chromium/content/browser/devtools/protocol/devtools_protocol_client.cc133
-rw-r--r--chromium/content/browser/devtools/protocol/devtools_protocol_client.h57
-rw-r--r--chromium/content/browser/devtools/protocol/devtools_protocol_handler.cc105
-rw-r--r--chromium/content/browser/devtools/protocol/devtools_protocol_handler.h33
-rwxr-xr-xchromium/content/browser/devtools/protocol/devtools_protocol_handler_generator.py622
-rw-r--r--chromium/content/browser/devtools/protocol/dom_handler.cc4
-rw-r--r--chromium/content/browser/devtools/protocol/dom_handler.h8
-rw-r--r--chromium/content/browser/devtools/protocol/emulation_handler.cc215
-rw-r--r--chromium/content/browser/devtools/protocol/emulation_handler.h76
-rw-r--r--chromium/content/browser/devtools/protocol/input_handler.cc435
-rw-r--r--chromium/content/browser/devtools/protocol/input_handler.h83
-rw-r--r--chromium/content/browser/devtools/protocol/inspector_handler.cc4
-rw-r--r--chromium/content/browser/devtools/protocol/inspector_handler.h4
-rw-r--r--chromium/content/browser/devtools/protocol/network_handler.cc235
-rw-r--r--chromium/content/browser/devtools/protocol/network_handler.h24
-rw-r--r--chromium/content/browser/devtools/protocol/page_handler.cc481
-rw-r--r--chromium/content/browser/devtools/protocol/page_handler.h88
-rw-r--r--chromium/content/browser/devtools/protocol/power_handler.cc18
-rw-r--r--chromium/content/browser/devtools/protocol/power_handler.h2
-rw-r--r--chromium/content/browser/devtools/protocol/service_worker_handler.cc526
-rw-r--r--chromium/content/browser/devtools/protocol/service_worker_handler.h106
-rw-r--r--chromium/content/browser/devtools/protocol/system_info_handler.cc233
-rw-r--r--chromium/content/browser/devtools/protocol/system_info_handler.h59
-rw-r--r--chromium/content/browser/devtools/protocol/tethering_handler.cc407
-rw-r--r--chromium/content/browser/devtools/protocol/tethering_handler.h62
-rw-r--r--chromium/content/browser/devtools/protocol/tracing_handler.cc97
-rw-r--r--chromium/content/browser/devtools/protocol/tracing_handler.h29
-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_frame_devtools_agent_host.cc535
-rw-r--r--chromium/content/browser/devtools/render_frame_devtools_agent_host.h144
-rw-r--r--chromium/content/browser/devtools/render_view_devtools_agent_host.cc514
-rw-r--r--chromium/content/browser/devtools/render_view_devtools_agent_host.h138
-rw-r--r--chromium/content/browser/devtools/renderer_overrides_handler_browsertest.cc137
-rw-r--r--chromium/content/browser/devtools/service_worker_devtools_agent_host.cc123
-rw-r--r--chromium/content/browser/devtools/service_worker_devtools_agent_host.h50
-rw-r--r--chromium/content/browser/devtools/service_worker_devtools_manager.cc185
-rw-r--r--chromium/content/browser/devtools/service_worker_devtools_manager.h122
-rw-r--r--chromium/content/browser/devtools/shared_worker_devtools_agent_host.cc64
-rw-r--r--chromium/content/browser/devtools/shared_worker_devtools_agent_host.h41
-rw-r--r--chromium/content/browser/devtools/shared_worker_devtools_manager.cc104
-rw-r--r--chromium/content/browser/devtools/shared_worker_devtools_manager.h68
-rw-r--r--chromium/content/browser/devtools/shared_worker_devtools_manager_unittest.cc298
-rw-r--r--chromium/content/browser/devtools/site_per_process_devtools_browsertest.cc111
-rw-r--r--chromium/content/browser/devtools/tethering_handler.cc441
-rw-r--r--chromium/content/browser/devtools/tethering_handler.h53
-rw-r--r--chromium/content/browser/devtools/worker_devtools_agent_host.cc144
-rw-r--r--chromium/content/browser/devtools/worker_devtools_agent_host.h70
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_area.cc158
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_area.h47
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_area_unittest.cc80
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_context_impl.cc107
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_context_impl.h40
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_context_impl_unittest.cc122
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_context_wrapper.cc10
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_context_wrapper.h4
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_database_unittest.cc11
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_host.cc73
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_host.h22
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_message_filter.cc30
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_message_filter.h10
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_namespace.cc286
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_namespace.h80
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_session.cc87
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_session.h18
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_task_runner.h13
-rw-r--r--chromium/content/browser/dom_storage/session_storage_database.cc13
-rw-r--r--chromium/content/browser/dom_storage/session_storage_namespace_impl.cc35
-rw-r--r--chromium/content/browser/dom_storage/session_storage_namespace_impl.h14
-rw-r--r--chromium/content/browser/download/base_file.cc16
-rw-r--r--chromium/content/browser/download/base_file.h2
-rw-r--r--chromium/content/browser/download/base_file_linux.cc2
-rw-r--r--chromium/content/browser/download/base_file_mac.cc2
-rw-r--r--chromium/content/browser/download/base_file_win.cc2
-rw-r--r--chromium/content/browser/download/download_browsertest.cc67
-rw-r--r--chromium/content/browser/download/download_create_info.h2
-rw-r--r--chromium/content/browser/download/download_file_impl.cc10
-rw-r--r--chromium/content/browser/download/download_file_impl.h2
-rw-r--r--chromium/content/browser/download/download_item_impl.cc143
-rw-r--r--chromium/content/browser/download/download_item_impl.h2
-rw-r--r--chromium/content/browser/download/download_item_impl_unittest.cc3
-rw-r--r--chromium/content/browser/download/download_manager_impl.cc31
-rw-r--r--chromium/content/browser/download/download_manager_impl_unittest.cc18
-rw-r--r--chromium/content/browser/download/download_net_log_parameters.cc63
-rw-r--r--chromium/content/browser/download/download_net_log_parameters.h43
-rw-r--r--chromium/content/browser/download/download_resource_handler.cc64
-rw-r--r--chromium/content/browser/download/download_resource_handler.h4
-rw-r--r--chromium/content/browser/download/download_stats.cc19
-rw-r--r--chromium/content/browser/download/drag_download_file.cc16
-rw-r--r--chromium/content/browser/download/drag_download_file_browsertest.cc7
-rw-r--r--chromium/content/browser/download/file_metadata_mac.mm1
-rw-r--r--chromium/content/browser/download/file_metadata_unittest_linux.cc4
-rw-r--r--chromium/content/browser/download/mhtml_generation_manager.cc14
-rw-r--r--chromium/content/browser/download/save_file.cc4
-rw-r--r--chromium/content/browser/download/save_file_manager.cc60
-rw-r--r--chromium/content/browser/download/save_package.cc20
-rw-r--r--chromium/content/browser/download/save_package_unittest.cc2
-rw-r--r--chromium/content/browser/file_descriptor_info_impl.cc21
-rw-r--r--chromium/content/browser/file_descriptor_info_impl.h8
-rw-r--r--chromium/content/browser/fileapi/blob_storage_context_unittest.cc267
-rw-r--r--chromium/content/browser/fileapi/blob_storage_host.cc5
-rw-r--r--chromium/content/browser/fileapi/blob_storage_host.h18
-rw-r--r--chromium/content/browser/fileapi/blob_url_request_job_unittest.cc55
-rw-r--r--chromium/content/browser/fileapi/browser_file_system_helper.cc2
-rw-r--r--chromium/content/browser/fileapi/chrome_blob_storage_context.cc35
-rw-r--r--chromium/content/browser/fileapi/chrome_blob_storage_context.h12
-rw-r--r--chromium/content/browser/fileapi/copy_or_move_file_validator_unittest.cc2
-rw-r--r--chromium/content/browser/fileapi/copy_or_move_operation_delegate_unittest.cc9
-rw-r--r--chromium/content/browser/fileapi/external_mount_points_unittest.cc17
-rw-r--r--chromium/content/browser/fileapi/file_system_browsertest.cc2
-rw-r--r--chromium/content/browser/fileapi/file_system_context_unittest.cc21
-rw-r--r--chromium/content/browser/fileapi/file_system_dir_url_request_job_unittest.cc14
-rw-r--r--chromium/content/browser/fileapi/file_system_operation_impl_unittest.cc2
-rw-r--r--chromium/content/browser/fileapi/file_system_operation_impl_write_unittest.cc1
-rw-r--r--chromium/content/browser/fileapi/file_system_operation_runner_unittest.cc89
-rw-r--r--chromium/content/browser/fileapi/file_system_quota_client_unittest.cc8
-rw-r--r--chromium/content/browser/fileapi/file_system_url_request_job_unittest.cc5
-rw-r--r--chromium/content/browser/fileapi/file_writer_delegate_unittest.cc7
-rw-r--r--chromium/content/browser/fileapi/fileapi_message_filter.cc95
-rw-r--r--chromium/content/browser/fileapi/fileapi_message_filter.h7
-rw-r--r--chromium/content/browser/fileapi/fileapi_message_filter_unittest.cc8
-rw-r--r--chromium/content/browser/fileapi/local_file_stream_reader_unittest.cc2
-rw-r--r--chromium/content/browser/fileapi/mock_file_change_observer.h6
-rw-r--r--chromium/content/browser/fileapi/mock_file_update_observer.h6
-rw-r--r--chromium/content/browser/fileapi/mock_url_request_delegate.cc2
-rw-r--r--chromium/content/browser/fileapi/mock_url_request_delegate.h6
-rw-r--r--chromium/content/browser/fileapi/obfuscated_file_util_unittest.cc6
-rw-r--r--chromium/content/browser/fileapi/transient_file_util_unittest.cc2
-rw-r--r--chromium/content/browser/fileapi/upload_file_system_file_element_reader.cc2
-rw-r--r--chromium/content/browser/frame_host/DEPS1
-rw-r--r--chromium/content/browser/frame_host/cross_process_frame_connector.cc3
-rw-r--r--chromium/content/browser/frame_host/cross_process_frame_connector.h2
-rw-r--r--chromium/content/browser/frame_host/cross_site_transferring_request.cc2
-rw-r--r--chromium/content/browser/frame_host/debug_urls.cc57
-rw-r--r--chromium/content/browser/frame_host/frame_accessibility.cc90
-rw-r--r--chromium/content/browser/frame_host/frame_accessibility.h31
-rw-r--r--chromium/content/browser/frame_host/frame_navigation_entry.cc40
-rw-r--r--chromium/content/browser/frame_host/frame_navigation_entry.h91
-rw-r--r--chromium/content/browser/frame_host/frame_tree.cc194
-rw-r--r--chromium/content/browser/frame_host/frame_tree.h56
-rw-r--r--chromium/content/browser/frame_host/frame_tree_browsertest.cc205
-rw-r--r--chromium/content/browser/frame_host/frame_tree_node.cc235
-rw-r--r--chromium/content/browser/frame_host/frame_tree_node.h115
-rw-r--r--chromium/content/browser/frame_host/frame_tree_unittest.cc208
-rw-r--r--chromium/content/browser/frame_host/interstitial_page_impl.cc54
-rw-r--r--chromium/content/browser/frame_host/interstitial_page_impl.h15
-rw-r--r--chromium/content/browser/frame_host/interstitial_page_navigator_impl.cc4
-rw-r--r--chromium/content/browser/frame_host/interstitial_page_navigator_impl.h1
-rw-r--r--chromium/content/browser/frame_host/navigation_controller_android.cc51
-rw-r--r--chromium/content/browser/frame_host/navigation_controller_android.h13
-rw-r--r--chromium/content/browser/frame_host/navigation_controller_delegate.h11
-rw-r--r--chromium/content/browser/frame_host/navigation_controller_impl.cc458
-rw-r--r--chromium/content/browser/frame_host/navigation_controller_impl.h66
-rw-r--r--chromium/content/browser/frame_host/navigation_controller_impl_browsertest.cc1388
-rw-r--r--chromium/content/browser/frame_host/navigation_controller_impl_unittest.cc1385
-rw-r--r--chromium/content/browser/frame_host/navigation_entry_impl.cc261
-rw-r--r--chromium/content/browser/frame_host/navigation_entry_impl.h129
-rw-r--r--chromium/content/browser/frame_host/navigation_entry_impl_unittest.cc23
-rw-r--r--chromium/content/browser/frame_host/navigation_entry_screenshot_manager.cc41
-rw-r--r--chromium/content/browser/frame_host/navigation_entry_screenshot_manager.h5
-rw-r--r--chromium/content/browser/frame_host/navigation_request.cc178
-rw-r--r--chromium/content/browser/frame_host/navigation_request.h125
-rw-r--r--chromium/content/browser/frame_host/navigation_request_info.cc20
-rw-r--r--chromium/content/browser/frame_host/navigation_request_info.h30
-rw-r--r--chromium/content/browser/frame_host/navigator.cc18
-rw-r--r--chromium/content/browser/frame_host/navigator.h55
-rw-r--r--chromium/content/browser/frame_host/navigator_delegate.h22
-rw-r--r--chromium/content/browser/frame_host/navigator_impl.cc484
-rw-r--r--chromium/content/browser/frame_host/navigator_impl.h38
-rw-r--r--chromium/content/browser/frame_host/navigator_impl_unittest.cc1203
-rw-r--r--chromium/content/browser/frame_host/popup_menu_helper_mac.h2
-rw-r--r--chromium/content/browser/frame_host/popup_menu_helper_mac.mm18
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_delegate.cc13
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_delegate.h43
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_factory.cc17
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_factory.h10
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_impl.cc957
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_impl.h244
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_impl_browsertest.cc192
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_manager.cc1185
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_manager.h278
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_manager_browsertest.cc241
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_manager_unittest.cc766
-rw-r--r--chromium/content/browser/frame_host/render_frame_message_filter.cc21
-rw-r--r--chromium/content/browser/frame_host/render_frame_message_filter.h2
-rw-r--r--chromium/content/browser/frame_host/render_frame_proxy_host.cc159
-rw-r--r--chromium/content/browser/frame_host/render_frame_proxy_host.h22
-rw-r--r--chromium/content/browser/frame_host/render_widget_host_view_child_frame.cc45
-rw-r--r--chromium/content/browser/frame_host/render_widget_host_view_child_frame.h25
-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.cc54
-rw-r--r--chromium/content/browser/frame_host/render_widget_host_view_guest.h22
-rw-r--r--chromium/content/browser/frame_host/render_widget_host_view_guest_unittest.cc6
-rw-r--r--chromium/content/browser/gamepad/gamepad_consumer.h6
-rw-r--r--chromium/content/browser/gamepad/gamepad_platform_data_fetcher.h4
-rw-r--r--chromium/content/browser/gamepad/gamepad_platform_data_fetcher_android.cc2
-rw-r--r--chromium/content/browser/gamepad/gamepad_platform_data_fetcher_android.h8
-rw-r--r--chromium/content/browser/gamepad/gamepad_platform_data_fetcher_linux.cc48
-rw-r--r--chromium/content/browser/gamepad/gamepad_platform_data_fetcher_mac.h2
-rw-r--r--chromium/content/browser/gamepad/gamepad_platform_data_fetcher_mac.mm11
-rw-r--r--chromium/content/browser/gamepad/gamepad_platform_data_fetcher_win.cc10
-rw-r--r--chromium/content/browser/gamepad/gamepad_platform_data_fetcher_win.h8
-rw-r--r--chromium/content/browser/gamepad/gamepad_provider.cc21
-rw-r--r--chromium/content/browser/gamepad/gamepad_provider_unittest.cc6
-rw-r--r--chromium/content/browser/gamepad/gamepad_service.h4
-rw-r--r--chromium/content/browser/gamepad/gamepad_standard_mappings_linux.cc43
-rw-r--r--chromium/content/browser/gamepad/gamepad_standard_mappings_mac.mm54
-rw-r--r--chromium/content/browser/gamepad/gamepad_standard_mappings_win.cc57
-rw-r--r--chromium/content/browser/gamepad/raw_input_data_fetcher_win.cc43
-rw-r--r--chromium/content/browser/gamepad/raw_input_data_fetcher_win.h8
-rw-r--r--chromium/content/browser/gamepad/xbox_data_fetcher_mac.cc4
-rw-r--r--chromium/content/browser/geofencing/geofencing_dispatcher_host.cc4
-rw-r--r--chromium/content/browser/geofencing/geofencing_dispatcher_host.h2
-rw-r--r--chromium/content/browser/geofencing/geofencing_manager.cc128
-rw-r--r--chromium/content/browser/geofencing/geofencing_manager.h24
-rw-r--r--chromium/content/browser/geofencing/geofencing_manager_unittest.cc337
-rw-r--r--chromium/content/browser/geofencing/geofencing_provider.h2
-rw-r--r--chromium/content/browser/geofencing/geofencing_registration_delegate.h2
-rw-r--r--chromium/content/browser/geofencing/geofencing_service.h2
-rw-r--r--chromium/content/browser/geofencing/mock_geofencing_service.cc123
-rw-r--r--chromium/content/browser/geofencing/mock_geofencing_service.h47
-rw-r--r--chromium/content/browser/geolocation/empty_wifi_data_provider.h8
-rw-r--r--chromium/content/browser/geolocation/geolocation_dispatcher_host.cc144
-rw-r--r--chromium/content/browser/geolocation/geolocation_dispatcher_host.h76
-rw-r--r--chromium/content/browser/geolocation/geolocation_provider_impl.cc14
-rw-r--r--chromium/content/browser/geolocation/geolocation_provider_impl_unittest.cc8
-rw-r--r--chromium/content/browser/geolocation/geolocation_service_impl.cc64
-rw-r--r--chromium/content/browser/geolocation/geolocation_service_impl.h20
-rw-r--r--chromium/content/browser/geolocation/location_arbitrator.h2
-rw-r--r--chromium/content/browser/geolocation/location_arbitrator_impl.cc13
-rw-r--r--chromium/content/browser/geolocation/location_provider_android.h12
-rw-r--r--chromium/content/browser/geolocation/location_provider_base.h6
-rw-r--r--chromium/content/browser/geolocation/mock_location_arbitrator.h2
-rw-r--r--chromium/content/browser/geolocation/network_location_request.cc4
-rw-r--r--chromium/content/browser/geolocation/wifi_data_provider_chromeos.cc3
-rw-r--r--chromium/content/browser/geolocation/wifi_data_provider_chromeos.h8
-rw-r--r--chromium/content/browser/geolocation/wifi_data_provider_chromeos_unittest.cc4
-rw-r--r--chromium/content/browser/geolocation/wifi_data_provider_win.cc8
-rw-r--r--chromium/content/browser/geolocation/wifi_data_provider_win.h6
-rw-r--r--chromium/content/browser/geolocation/wifi_polling_policy.h6
-rw-r--r--chromium/content/browser/gpu/browser_gpu_channel_host_factory.cc247
-rw-r--r--chromium/content/browser/gpu/browser_gpu_channel_host_factory.h53
-rw-r--r--chromium/content/browser/gpu/browser_gpu_memory_buffer_manager.cc241
-rw-r--r--chromium/content/browser/gpu/browser_gpu_memory_buffer_manager.h55
-rw-r--r--chromium/content/browser/gpu/compositor_util.cc102
-rw-r--r--chromium/content/browser/gpu/compositor_util.h20
-rw-r--r--chromium/content/browser/gpu/compositor_util_browsertest.cc33
-rw-r--r--chromium/content/browser/gpu/gpu_data_manager_impl.cc11
-rw-r--r--chromium/content/browser/gpu/gpu_data_manager_impl.h10
-rw-r--r--chromium/content/browser/gpu/gpu_data_manager_impl_private.cc121
-rw-r--r--chromium/content/browser/gpu/gpu_data_manager_impl_private.h9
-rw-r--r--chromium/content/browser/gpu/gpu_data_manager_impl_private_unittest.cc2
-rw-r--r--chromium/content/browser/gpu/gpu_internals_ui.cc45
-rw-r--r--chromium/content/browser/gpu/gpu_internals_ui.h6
-rw-r--r--chromium/content/browser/gpu/gpu_ipc_browsertests.cc62
-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.cc79
-rw-r--r--chromium/content/browser/gpu/gpu_process_host.h16
-rw-r--r--chromium/content/browser/gpu/gpu_process_host_ui_shim.cc89
-rw-r--r--chromium/content/browser/gpu/gpu_process_host_ui_shim.h7
-rw-r--r--chromium/content/browser/gpu/gpu_surface_tracker.h2
-rw-r--r--chromium/content/browser/gpu/shader_disk_cache.cc16
-rw-r--r--chromium/content/browser/histogram_controller.cc10
-rw-r--r--chromium/content/browser/histogram_internals_request_job.cc6
-rw-r--r--chromium/content/browser/histogram_message_filter.cc2
-rw-r--r--chromium/content/browser/histogram_synchronizer.cc22
-rw-r--r--chromium/content/browser/host_zoom_level_context.cc32
-rw-r--r--chromium/content/browser/host_zoom_level_context.h61
-rw-r--r--chromium/content/browser/host_zoom_map_impl.cc145
-rw-r--r--chromium/content/browser/host_zoom_map_impl.h34
-rw-r--r--chromium/content/browser/host_zoom_map_impl_browsertest.cc86
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_active_blob_registry.h2
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_backing_store.cc624
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_backing_store.h92
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_backing_store_unittest.cc57
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_blob_info.cc7
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_blob_info.h4
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_browsertest.cc190
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_callbacks.cc201
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_callbacks.h13
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_cleanup_on_io_error_unittest.cc10
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_connection.cc21
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_connection.h3
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_context_impl.cc101
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_context_impl.h12
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_cursor.cc7
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_cursor.h2
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_database.cc201
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_database.h12
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_database_error.cc28
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_database_error.h19
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_dispatcher_host.cc133
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_dispatcher_host.h12
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_factory.h2
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_factory_impl.cc10
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_factory_impl.h2
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_factory_unittest.cc4
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_index_writer.cc2
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_internals_ui.cc31
-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.h2
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_leveldb_coding_unittest.cc8
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_metadata.cc42
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_metadata.h21
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_quota_client.cc2
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_quota_client.h3
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_return_value.h27
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_tracing.h2
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_transaction.cc18
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_transaction.h2
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_transaction_coordinator.cc4
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_value.cc7
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_value.h2
-rw-r--r--chromium/content/browser/indexed_db/leveldb/leveldb_database.cc20
-rw-r--r--chromium/content/browser/indexed_db/leveldb/leveldb_unittest.cc1
-rw-r--r--chromium/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.cc29
-rw-r--r--chromium/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.h1
-rw-r--r--chromium/content/browser/indexed_db/mock_indexed_db_factory.h5
-rw-r--r--chromium/content/browser/loader/async_resource_handler.cc49
-rw-r--r--chromium/content/browser/loader/async_resource_handler.h3
-rw-r--r--chromium/content/browser/loader/buffered_resource_handler.cc47
-rw-r--r--chromium/content/browser/loader/buffered_resource_handler.h7
-rw-r--r--chromium/content/browser/loader/buffered_resource_handler_unittest.cc286
-rw-r--r--chromium/content/browser/loader/certificate_resource_handler.cc92
-rw-r--r--chromium/content/browser/loader/certificate_resource_handler.h18
-rw-r--r--chromium/content/browser/loader/cross_site_resource_handler.cc13
-rw-r--r--chromium/content/browser/loader/global_routing_id.h6
-rw-r--r--chromium/content/browser/loader/navigation_resource_handler.cc5
-rw-r--r--chromium/content/browser/loader/navigation_resource_handler.h2
-rw-r--r--chromium/content/browser/loader/navigation_url_loader.cc11
-rw-r--r--chromium/content/browser/loader/navigation_url_loader.h5
-rw-r--r--chromium/content/browser/loader/navigation_url_loader_delegate.h11
-rw-r--r--chromium/content/browser/loader/navigation_url_loader_factory.h4
-rw-r--r--chromium/content/browser/loader/navigation_url_loader_impl.cc18
-rw-r--r--chromium/content/browser/loader/navigation_url_loader_impl.h11
-rw-r--r--chromium/content/browser/loader/navigation_url_loader_impl_core.cc20
-rw-r--r--chromium/content/browser/loader/navigation_url_loader_impl_core.h8
-rw-r--r--chromium/content/browser/loader/navigation_url_loader_unittest.cc37
-rw-r--r--chromium/content/browser/loader/power_save_block_resource_throttle.cc2
-rw-r--r--chromium/content/browser/loader/redirect_to_file_resource_handler.cc2
-rw-r--r--chromium/content/browser/loader/resource_dispatcher_host_browsertest.cc56
-rw-r--r--chromium/content/browser/loader/resource_dispatcher_host_impl.cc475
-rw-r--r--chromium/content/browser/loader/resource_dispatcher_host_impl.h57
-rw-r--r--chromium/content/browser/loader/resource_dispatcher_host_unittest.cc236
-rw-r--r--chromium/content/browser/loader/resource_loader.cc90
-rw-r--r--chromium/content/browser/loader/resource_loader.h12
-rw-r--r--chromium/content/browser/loader/resource_loader_unittest.cc332
-rw-r--r--chromium/content/browser/loader/resource_message_delegate.h6
-rw-r--r--chromium/content/browser/loader/resource_message_filter.cc9
-rw-r--r--chromium/content/browser/loader/resource_message_filter.h8
-rw-r--r--chromium/content/browser/loader/resource_request_info_impl.cc20
-rw-r--r--chromium/content/browser/loader/resource_request_info_impl.h7
-rw-r--r--chromium/content/browser/loader/resource_scheduler.cc127
-rw-r--r--chromium/content/browser/loader/resource_scheduler_unittest.cc6
-rw-r--r--chromium/content/browser/loader/temporary_file_stream.cc6
-rw-r--r--chromium/content/browser/loader/temporary_file_stream_unittest.cc2
-rw-r--r--chromium/content/browser/loader/throttling_resource_handler.cc2
-rw-r--r--chromium/content/browser/loader/upload_data_stream_builder.cc27
-rw-r--r--chromium/content/browser/loader/upload_data_stream_builder_unittest.cc97
-rw-r--r--chromium/content/browser/mach_broker_mac.h42
-rw-r--r--chromium/content/browser/mach_broker_mac.mm221
-rw-r--r--chromium/content/browser/mach_broker_mac_unittest.cc31
-rw-r--r--chromium/content/browser/manifest/manifest_browsertest.cc234
-rw-r--r--chromium/content/browser/manifest/manifest_manager_host.cc26
-rw-r--r--chromium/content/browser/manifest/manifest_manager_host.h6
-rw-r--r--chromium/content/browser/media/OWNERS14
-rw-r--r--chromium/content/browser/media/android/browser_demuxer_android.cc62
-rw-r--r--chromium/content/browser/media/android/browser_demuxer_android.h20
-rw-r--r--chromium/content/browser/media/android/browser_media_player_manager.cc148
-rw-r--r--chromium/content/browser/media/android/browser_media_player_manager.h74
-rw-r--r--chromium/content/browser/media/android/media_drm_credential_manager.cc8
-rw-r--r--chromium/content/browser/media/android/media_drm_credential_manager.h4
-rw-r--r--chromium/content/browser/media/android/media_resource_getter_impl.cc37
-rw-r--r--chromium/content/browser/media/android/media_resource_getter_impl.h37
-rw-r--r--chromium/content/browser/media/audio_state_provider.cc30
-rw-r--r--chromium/content/browser/media/audio_state_provider.h57
-rw-r--r--chromium/content/browser/media/audio_stream_monitor.cc38
-rw-r--r--chromium/content/browser/media/audio_stream_monitor.h29
-rw-r--r--chromium/content/browser/media/audio_stream_monitor_unittest.cc12
-rw-r--r--chromium/content/browser/media/capture/OWNERS1
-rw-r--r--chromium/content/browser/media/capture/animated_content_sampler.cc293
-rw-r--r--chromium/content/browser/media/capture/animated_content_sampler.h157
-rw-r--r--chromium/content/browser/media/capture/animated_content_sampler_unittest.cc818
-rw-r--r--chromium/content/browser/media/capture/aura_window_capture_machine.cc449
-rw-r--r--chromium/content/browser/media/capture/aura_window_capture_machine.h128
-rw-r--r--chromium/content/browser/media/capture/capture_resolution_chooser.cc120
-rw-r--r--chromium/content/browser/media/capture/capture_resolution_chooser.h59
-rw-r--r--chromium/content/browser/media/capture/capture_resolution_chooser_unittest.cc169
-rw-r--r--chromium/content/browser/media/capture/content_video_capture_device_core.cc144
-rw-r--r--chromium/content/browser/media/capture/content_video_capture_device_core.h39
-rw-r--r--chromium/content/browser/media/capture/desktop_capture_device.cc202
-rw-r--r--chromium/content/browser/media/capture/desktop_capture_device_aura.cc510
-rw-r--r--chromium/content/browser/media/capture/desktop_capture_device_aura.h2
-rw-r--r--chromium/content/browser/media/capture/desktop_capture_device_aura_unittest.cc53
-rw-r--r--chromium/content/browser/media/capture/desktop_capture_device_unittest.cc345
-rw-r--r--chromium/content/browser/media/capture/feedback_signal_accumulator.cc56
-rw-r--r--chromium/content/browser/media/capture/feedback_signal_accumulator.h67
-rw-r--r--chromium/content/browser/media/capture/feedback_signal_accumulator_unittest.cc202
-rw-r--r--chromium/content/browser/media/capture/smooth_event_sampler.cc100
-rw-r--r--chromium/content/browser/media/capture/smooth_event_sampler.h60
-rw-r--r--chromium/content/browser/media/capture/smooth_event_sampler_unittest.cc488
-rw-r--r--chromium/content/browser/media/capture/video_capture_oracle.cc297
-rw-r--r--chromium/content/browser/media/capture/video_capture_oracle.h161
-rw-r--r--chromium/content/browser/media/capture/video_capture_oracle_unittest.cc1099
-rw-r--r--chromium/content/browser/media/capture/web_contents_audio_input_stream.cc11
-rw-r--r--chromium/content/browser/media/capture/web_contents_audio_input_stream.h2
-rw-r--r--chromium/content/browser/media/capture/web_contents_audio_input_stream_unittest.cc13
-rw-r--r--chromium/content/browser/media/capture/web_contents_audio_muter.cc19
-rw-r--r--chromium/content/browser/media/capture/web_contents_tracker.cc58
-rw-r--r--chromium/content/browser/media/capture/web_contents_tracker.h36
-rw-r--r--chromium/content/browser/media/capture/web_contents_video_capture_device.cc187
-rw-r--r--chromium/content/browser/media/capture/web_contents_video_capture_device_unittest.cc363
-rw-r--r--chromium/content/browser/media/cdm/browser_cdm_manager.cc546
-rw-r--r--chromium/content/browser/media/cdm/browser_cdm_manager.h140
-rw-r--r--chromium/content/browser/media/encrypted_media_browsertest.cc31
-rw-r--r--chromium/content/browser/media/media_browsertest.cc29
-rw-r--r--chromium/content/browser/media/media_canplaytype_browsertest.cc504
-rw-r--r--chromium/content/browser/media/media_internals.cc395
-rw-r--r--chromium/content/browser/media/media_internals.h36
-rw-r--r--chromium/content/browser/media/media_internals_handler.cc2
-rw-r--r--chromium/content/browser/media/media_internals_proxy.cc29
-rw-r--r--chromium/content/browser/media/media_internals_proxy.h2
-rw-r--r--chromium/content/browser/media/media_internals_unittest.cc37
-rw-r--r--chromium/content/browser/media/media_source_browsertest.cc2
-rw-r--r--chromium/content/browser/media/media_web_contents_observer.cc28
-rw-r--r--chromium/content/browser/media/media_web_contents_observer.h21
-rw-r--r--chromium/content/browser/media/midi_dispatcher_host.cc140
-rw-r--r--chromium/content/browser/media/midi_dispatcher_host.h64
-rw-r--r--chromium/content/browser/media/midi_host.cc48
-rw-r--r--chromium/content/browser/media/midi_host.h35
-rw-r--r--chromium/content/browser/media/midi_host_unittest.cc144
-rw-r--r--chromium/content/browser/media/webrtc_aecdump_browsertest.cc12
-rw-r--r--chromium/content/browser/media/webrtc_browsertest.cc84
-rw-r--r--chromium/content/browser/media/webrtc_getusermedia_browsertest.cc179
-rw-r--r--chromium/content/browser/media/webrtc_identity_store.cc24
-rw-r--r--chromium/content/browser/media/webrtc_identity_store.h2
-rw-r--r--chromium/content/browser/media/webrtc_identity_store_backend.cc29
-rw-r--r--chromium/content/browser/media/webrtc_identity_store_backend.h6
-rw-r--r--chromium/content/browser/media/webrtc_identity_store_unittest.cc30
-rw-r--r--chromium/content/browser/media/webrtc_internals.cc30
-rw-r--r--chromium/content/browser/media/webrtc_internals.h2
-rw-r--r--chromium/content/browser/media/webrtc_internals_browsertest.cc4
-rw-r--r--chromium/content/browser/media/webrtc_internals_message_handler.cc2
-rw-r--r--chromium/content/browser/media/webrtc_internals_unittest.cc50
-rw-r--r--chromium/content/browser/media/webrtc_webcam_browsertest.cc2
-rw-r--r--chromium/content/browser/message_port_message_filter.cc40
-rw-r--r--chromium/content/browser/message_port_message_filter.h30
-rw-r--r--chromium/content/browser/message_port_provider.cc116
-rw-r--r--chromium/content/browser/message_port_provider_browsertest.cc145
-rw-r--r--chromium/content/browser/message_port_service.cc185
-rw-r--r--chromium/content/browser/message_port_service.h51
-rw-r--r--chromium/content/browser/mojo/mojo_application_host.cc54
-rw-r--r--chromium/content/browser/mojo/mojo_application_host.h26
-rw-r--r--chromium/content/browser/mojo/service_registrar_android.cc33
-rw-r--r--chromium/content/browser/mojo/service_registrar_android.h25
-rw-r--r--chromium/content/browser/mojo/service_registry_android.h4
-rw-r--r--chromium/content/browser/navigator_connect/OWNERS1
-rw-r--r--chromium/content/browser/navigator_connect/navigator_connect_context_impl.cc106
-rw-r--r--chromium/content/browser/navigator_connect/navigator_connect_context_impl.h65
-rw-r--r--chromium/content/browser/navigator_connect/navigator_connect_dispatcher_host.cc63
-rw-r--r--chromium/content/browser/navigator_connect/navigator_connect_dispatcher_host.h61
-rw-r--r--chromium/content/browser/navigator_connect/navigator_connect_service_worker_service_factory.cc201
-rw-r--r--chromium/content/browser/navigator_connect/navigator_connect_service_worker_service_factory.h61
-rw-r--r--chromium/content/browser/net/sqlite_persistent_cookie_store.cc319
-rw-r--r--chromium/content/browser/net/sqlite_persistent_cookie_store.h4
-rw-r--r--chromium/content/browser/net/sqlite_persistent_cookie_store_perftest.cc10
-rw-r--r--chromium/content/browser/net/sqlite_persistent_cookie_store_unittest.cc175
-rw-r--r--chromium/content/browser/net_info_browsertest.cc2
-rw-r--r--chromium/content/browser/notification_service_impl.h6
-rw-r--r--chromium/content/browser/notifications/BUILD.gn11
-rw-r--r--chromium/content/browser/notifications/DEPS3
-rw-r--r--chromium/content/browser/notifications/OWNERS3
-rw-r--r--chromium/content/browser/notifications/notification_database.cc381
-rw-r--r--chromium/content/browser/notifications/notification_database.h195
-rw-r--r--chromium/content/browser/notifications/notification_database_data.proto43
-rw-r--r--chromium/content/browser/notifications/notification_database_data_conversions.cc98
-rw-r--r--chromium/content/browser/notifications/notification_database_data_conversions.h30
-rw-r--r--chromium/content/browser/notifications/notification_database_data_unittest.cc89
-rw-r--r--chromium/content/browser/notifications/notification_database_unittest.cc592
-rw-r--r--chromium/content/browser/notifications/notification_event_dispatcher_impl.cc211
-rw-r--r--chromium/content/browser/notifications/notification_event_dispatcher_impl.h38
-rw-r--r--chromium/content/browser/notifications/notification_message_filter.cc260
-rw-r--r--chromium/content/browser/notifications/notification_message_filter.h77
-rw-r--r--chromium/content/browser/notifications/notification_proto.gyp17
-rw-r--r--chromium/content/browser/notifications/page_notification_delegate.cc3
-rw-r--r--chromium/content/browser/notifications/page_notification_delegate.h2
-rw-r--r--chromium/content/browser/notifications/platform_notification_context_impl.cc429
-rw-r--r--chromium/content/browser/notifications/platform_notification_context_impl.h161
-rw-r--r--chromium/content/browser/notifications/platform_notification_context_unittest.cc448
-rw-r--r--chromium/content/browser/pepper_flash_settings_helper_impl.cc4
-rw-r--r--chromium/content/browser/permissions/OWNERS2
-rw-r--r--chromium/content/browser/permissions/permission_service_context.cc85
-rw-r--r--chromium/content/browser/permissions/permission_service_context.h57
-rw-r--r--chromium/content/browser/permissions/permission_service_impl.cc284
-rw-r--r--chromium/content/browser/permissions/permission_service_impl.h108
-rw-r--r--chromium/content/browser/plugin_browsertest.cc35
-rw-r--r--chromium/content/browser/plugin_data_remover_impl.cc12
-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.cc97
-rw-r--r--chromium/content/browser/plugin_loader_posix.h23
-rw-r--r--chromium/content/browser/plugin_loader_posix_unittest.cc26
-rw-r--r--chromium/content/browser/plugin_process_host.cc31
-rw-r--r--chromium/content/browser/plugin_process_host_mac.cc4
-rw-r--r--chromium/content/browser/plugin_service_impl.cc83
-rw-r--r--chromium/content/browser/plugin_service_impl.h15
-rw-r--r--chromium/content/browser/plugin_service_impl_browsertest.cc14
-rw-r--r--chromium/content/browser/power_profiler/power_data_provider_ia_win.cc4
-rw-r--r--chromium/content/browser/power_profiler/power_data_provider_ia_win.h10
-rw-r--r--chromium/content/browser/power_profiler/power_event.cc4
-rw-r--r--chromium/content/browser/power_profiler/power_profiler_service.cc4
-rw-r--r--chromium/content/browser/power_save_blocker_android.cc91
-rw-r--r--chromium/content/browser/power_save_blocker_chromeos.cc56
-rw-r--r--chromium/content/browser/power_save_blocker_impl.cc6
-rw-r--r--chromium/content/browser/power_save_blocker_impl.h15
-rw-r--r--chromium/content/browser/power_save_blocker_mac.cc23
-rw-r--r--chromium/content/browser/power_save_blocker_ozone.cc3
-rw-r--r--chromium/content/browser/power_save_blocker_win.cc25
-rw-r--r--chromium/content/browser/power_save_blocker_x11.cc100
-rw-r--r--chromium/content/browser/power_usage_monitor_impl.cc276
-rw-r--r--chromium/content/browser/power_usage_monitor_impl.h133
-rw-r--r--chromium/content/browser/power_usage_monitor_impl_unittest.cc167
-rw-r--r--chromium/content/browser/ppapi_plugin_process_host.cc43
-rw-r--r--chromium/content/browser/ppapi_plugin_process_host.h5
-rw-r--r--chromium/content/browser/presentation/OWNERS3
-rw-r--r--chromium/content/browser/presentation/presentation_service_impl.cc674
-rw-r--r--chromium/content/browser/presentation/presentation_service_impl.h346
-rw-r--r--chromium/content/browser/presentation/presentation_service_impl_unittest.cc840
-rw-r--r--chromium/content/browser/presentation/presentation_type_converters.cc29
-rw-r--r--chromium/content/browser/presentation/presentation_type_converters.h50
-rw-r--r--chromium/content/browser/presentation/presentation_type_converters_unittest.cc34
-rw-r--r--chromium/content/browser/profiler_controller_impl.cc73
-rw-r--r--chromium/content/browser/profiler_controller_impl.h13
-rw-r--r--chromium/content/browser/profiler_message_filter.cc5
-rw-r--r--chromium/content/browser/profiler_message_filter.h5
-rw-r--r--chromium/content/browser/push_messaging/OWNERS9
-rw-r--r--chromium/content/browser/push_messaging/push_messaging_message_filter.cc855
-rw-r--r--chromium/content/browser/push_messaging/push_messaging_message_filter.h151
-rw-r--r--chromium/content/browser/push_messaging/push_messaging_router.cc111
-rw-r--r--chromium/content/browser/quota/quota_database_unittest.cc1
-rw-r--r--chromium/content/browser/quota_dispatcher_host.cc3
-rw-r--r--chromium/content/browser/renderer_data_memoizing_store.h6
-rw-r--r--chromium/content/browser/renderer_host/DEPS2
-rw-r--r--chromium/content/browser/renderer_host/OWNERS3
-rw-r--r--chromium/content/browser/renderer_host/begin_frame_observer_proxy.cc70
-rw-r--r--chromium/content/browser/renderer_host/begin_frame_observer_proxy.h60
-rw-r--r--chromium/content/browser/renderer_host/begin_frame_observer_proxy_unittest.cc97
-rw-r--r--chromium/content/browser/renderer_host/clipboard_message_filter.cc200
-rw-r--r--chromium/content/browser/renderer_host/clipboard_message_filter.h35
-rw-r--r--chromium/content/browser/renderer_host/clipboard_message_filter_unittest.cc132
-rw-r--r--chromium/content/browser/renderer_host/compositor_impl_android.cc294
-rw-r--r--chromium/content/browser/renderer_host/compositor_impl_android.h118
-rw-r--r--chromium/content/browser/renderer_host/compositor_resize_lock_aura.cc2
-rw-r--r--chromium/content/browser/renderer_host/database_message_filter.cc53
-rw-r--r--chromium/content/browser/renderer_host/database_message_filter.h10
-rw-r--r--chromium/content/browser/renderer_host/delegated_frame_evictor.cc11
-rw-r--r--chromium/content/browser/renderer_host/delegated_frame_evictor.h1
-rw-r--r--chromium/content/browser/renderer_host/dip_util.cc43
-rw-r--r--chromium/content/browser/renderer_host/dip_util.h9
-rw-r--r--chromium/content/browser/renderer_host/display_link_mac.cc67
-rw-r--r--chromium/content/browser/renderer_host/display_link_mac.h18
-rw-r--r--chromium/content/browser/renderer_host/event_with_latency_info.h4
-rw-r--r--chromium/content/browser/renderer_host/frame_metadata_util.cc39
-rw-r--r--chromium/content/browser/renderer_host/frame_metadata_util.h26
-rw-r--r--chromium/content/browser/renderer_host/gamepad_browser_message_filter.cc10
-rw-r--r--chromium/content/browser/renderer_host/image_transport_factory_android.cc160
-rw-r--r--chromium/content/browser/renderer_host/image_transport_factory_android.h58
-rw-r--r--chromium/content/browser/renderer_host/ime_adapter_android.cc75
-rw-r--r--chromium/content/browser/renderer_host/ime_adapter_android.h4
-rw-r--r--chromium/content/browser/renderer_host/input/OWNERS2
-rw-r--r--chromium/content/browser/renderer_host/input/gesture_event_queue.cc148
-rw-r--r--chromium/content/browser/renderer_host/input/gesture_event_queue.h39
-rw-r--r--chromium/content/browser/renderer_host/input/gesture_event_queue_unittest.cc36
-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_ack_handler.h2
-rw-r--r--chromium/content/browser/renderer_host/input/input_router.h17
-rw-r--r--chromium/content/browser/renderer_host/input/input_router_client.h10
-rw-r--r--chromium/content/browser/renderer_host/input/input_router_config_helper.cc36
-rw-r--r--chromium/content/browser/renderer_host/input/input_router_impl.cc168
-rw-r--r--chromium/content/browser/renderer_host/input/input_router_impl.h37
-rw-r--r--chromium/content/browser/renderer_host/input/input_router_impl_perftest.cc20
-rw-r--r--chromium/content/browser/renderer_host/input/input_router_impl_unittest.cc351
-rw-r--r--chromium/content/browser/renderer_host/input/mock_input_ack_handler.h2
-rw-r--r--chromium/content/browser/renderer_host/input/mock_input_router_client.cc21
-rw-r--r--chromium/content/browser/renderer_host/input/mock_input_router_client.h5
-rw-r--r--chromium/content/browser/renderer_host/input/motion_event_android.cc34
-rw-r--r--chromium/content/browser/renderer_host/input/motion_event_android.h55
-rw-r--r--chromium/content/browser/renderer_host/input/motion_event_android_unittest.cc54
-rw-r--r--chromium/content/browser/renderer_host/input/motion_event_web.cc16
-rw-r--r--chromium/content/browser/renderer_host/input/motion_event_web.h3
-rw-r--r--chromium/content/browser/renderer_host/input/mouse_wheel_rails_filter_mac.cc38
-rw-r--r--chromium/content/browser/renderer_host/input/mouse_wheel_rails_filter_mac.h27
-rw-r--r--chromium/content/browser/renderer_host/input/mouse_wheel_rails_filter_unittest_mac.cc64
-rw-r--r--chromium/content/browser/renderer_host/input/render_widget_host_latency_tracker.cc470
-rw-r--r--chromium/content/browser/renderer_host/input/render_widget_host_latency_tracker.h78
-rw-r--r--chromium/content/browser/renderer_host/input/render_widget_host_latency_tracker_unittest.cc224
-rw-r--r--chromium/content/browser/renderer_host/input/selection_event_type.h29
-rw-r--r--chromium/content/browser/renderer_host/input/stylus_text_selector.cc141
-rw-r--r--chromium/content/browser/renderer_host/input/stylus_text_selector.h78
-rw-r--r--chromium/content/browser/renderer_host/input/stylus_text_selector_unittest.cc247
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_gesture.cc4
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_gesture_controller.cc2
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_gesture_controller_unittest.cc519
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_gesture_target_android.h16
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_gesture_target_aura.cc8
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_smooth_drag_gesture.cc57
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_smooth_drag_gesture.h38
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_smooth_move_gesture.cc374
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_smooth_move_gesture.h118
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_smooth_scroll_gesture.cc281
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_smooth_scroll_gesture.h71
-rw-r--r--chromium/content/browser/renderer_host/input/tap_suppression_controller.cc2
-rw-r--r--chromium/content/browser/renderer_host/input/timeout_monitor.cc68
-rw-r--r--chromium/content/browser/renderer_host/input/timeout_monitor.h3
-rw-r--r--chromium/content/browser/renderer_host/input/touch_action_browsertest.cc12
-rw-r--r--chromium/content/browser/renderer_host/input/touch_action_filter.cc66
-rw-r--r--chromium/content/browser/renderer_host/input/touch_action_filter.h2
-rw-r--r--chromium/content/browser/renderer_host/input/touch_action_filter_unittest.cc382
-rw-r--r--chromium/content/browser/renderer_host/input/touch_emulator.cc108
-rw-r--r--chromium/content/browser/renderer_host/input/touch_emulator.h22
-rw-r--r--chromium/content/browser/renderer_host/input/touch_emulator_unittest.cc70
-rw-r--r--chromium/content/browser/renderer_host/input/touch_event_queue.cc305
-rw-r--r--chromium/content/browser/renderer_host/input/touch_event_queue.h56
-rw-r--r--chromium/content/browser/renderer_host/input/touch_event_queue_unittest.cc731
-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.cc11
-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/web_input_event_builders_win.cc18
-rw-r--r--chromium/content/browser/renderer_host/input/web_input_event_builders_win.h9
-rw-r--r--chromium/content/browser/renderer_host/input/web_input_event_unittest.cc57
-rw-r--r--chromium/content/browser/renderer_host/input/web_input_event_util.cc253
-rw-r--r--chromium/content/browser/renderer_host/input/web_input_event_util.h14
-rw-r--r--chromium/content/browser/renderer_host/input/web_input_event_util_posix.cc16
-rw-r--r--chromium/content/browser/renderer_host/input/web_input_event_util_posix.h1
-rw-r--r--chromium/content/browser/renderer_host/input/web_input_event_util_unittest.cc51
-rw-r--r--chromium/content/browser/renderer_host/legacy_render_widget_host_win.cc93
-rw-r--r--chromium/content/browser/renderer_host/legacy_render_widget_host_win.h45
-rw-r--r--chromium/content/browser/renderer_host/legacy_render_widget_host_win_delegate.h26
-rw-r--r--chromium/content/browser/renderer_host/media/OWNERS11
-rw-r--r--chromium/content/browser/renderer_host/media/audio_input_device_manager.cc2
-rw-r--r--chromium/content/browser/renderer_host/media/audio_input_device_manager.h3
-rw-r--r--chromium/content/browser/renderer_host/media/audio_input_renderer_host.cc26
-rw-r--r--chromium/content/browser/renderer_host/media/audio_input_renderer_host.h12
-rw-r--r--chromium/content/browser/renderer_host/media/audio_renderer_host.cc98
-rw-r--r--chromium/content/browser/renderer_host/media/audio_renderer_host.h18
-rw-r--r--chromium/content/browser/renderer_host/media/audio_renderer_host_unittest.cc6
-rw-r--r--chromium/content/browser/renderer_host/media/audio_sync_reader.cc2
-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_unittest.cc4
-rw-r--r--chromium/content/browser/renderer_host/media/media_stream_manager.cc116
-rw-r--r--chromium/content/browser/renderer_host/media/media_stream_manager.h2
-rw-r--r--chromium/content/browser/renderer_host/media/media_stream_provider.h3
-rw-r--r--chromium/content/browser/renderer_host/media/media_stream_ui_proxy.cc65
-rw-r--r--chromium/content/browser/renderer_host/media/media_stream_ui_proxy.h4
-rw-r--r--chromium/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc98
-rw-r--r--chromium/content/browser/renderer_host/media/mock_media_observer.cc13
-rw-r--r--chromium/content/browser/renderer_host/media/mock_media_observer.h32
-rw-r--r--chromium/content/browser/renderer_host/media/peer_connection_tracker_host.cc6
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_buffer_pool.cc336
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_buffer_pool.h119
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_buffer_pool_unittest.cc265
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_controller.cc500
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_controller.h55
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_controller_event_handler.cc23
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_controller_event_handler.h49
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_controller_unittest.cc420
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_device_client.cc673
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_device_client.h90
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_host.cc186
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_host.h83
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_host_unittest.cc100
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_manager.cc329
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_manager.h111
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_manager_unittest.cc66
-rw-r--r--chromium/content/browser/renderer_host/media/webrtc_identity_service_host_unittest.cc14
-rw-r--r--chromium/content/browser/renderer_host/native_web_keyboard_event.cc27
-rw-r--r--chromium/content/browser/renderer_host/native_web_keyboard_event_aura.cc13
-rw-r--r--chromium/content/browser/renderer_host/native_web_keyboard_event_mac.mm11
-rw-r--r--chromium/content/browser/renderer_host/overscroll_controller.cc17
-rw-r--r--chromium/content/browser/renderer_host/overscroll_controller.h3
-rw-r--r--chromium/content/browser/renderer_host/overscroll_controller_delegate.h5
-rw-r--r--chromium/content/browser/renderer_host/p2p/OWNERS1
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_dispatcher_host.cc17
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host.cc15
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host.h4
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_tcp.cc30
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_test_utils.cc6
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_test_utils.h14
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_udp.cc58
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_udp.h3
-rw-r--r--chromium/content/browser/renderer_host/pepper/browser_ppapi_host_impl.cc108
-rw-r--r--chromium/content/browser/renderer_host/pepper/browser_ppapi_host_impl.h56
-rw-r--r--chromium/content/browser/renderer_host/pepper/browser_ppapi_host_test.cc2
-rw-r--r--chromium/content/browser/renderer_host/pepper/content_browser_pepper_host_factory.cc66
-rw-r--r--chromium/content/browser/renderer_host/pepper/content_browser_pepper_host_factory.h8
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_file_io_host.cc2
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_file_io_host.h6
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_flash_file_message_filter.cc6
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_flash_file_message_filter.h2
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_gamepad_host.cc2
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_gamepad_host_unittest.cc14
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_printing_host_unittest.cc2
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_renderer_connection.cc2
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_socket_utils.cc2
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc2
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_tcp_socket.cc2
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc169
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h30
-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_win.cc15
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.cc415
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.h56
-rw-r--r--chromium/content/browser/renderer_host/render_message_filter.cc248
-rw-r--r--chromium/content/browser/renderer_host/render_message_filter.h43
-rw-r--r--chromium/content/browser/renderer_host/render_process_host_browsertest.cc45
-rw-r--r--chromium/content/browser/renderer_host/render_process_host_impl.cc485
-rw-r--r--chromium/content/browser/renderer_host/render_process_host_impl.h59
-rw-r--r--chromium/content/browser/renderer_host/render_view_host_delegate.cc12
-rw-r--r--chromium/content/browser/renderer_host/render_view_host_delegate.h41
-rw-r--r--chromium/content/browser/renderer_host/render_view_host_impl.cc386
-rw-r--r--chromium/content/browser/renderer_host/render_view_host_impl.h78
-rw-r--r--chromium/content/browser/renderer_host/render_view_host_unittest.cc14
-rw-r--r--chromium/content/browser/renderer_host/render_widget_helper.cc50
-rw-r--r--chromium/content/browser/renderer_host/render_widget_helper.h25
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_browsertest.cc30
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_delegate.cc5
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_delegate.h17
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_impl.cc783
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_impl.h216
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_unittest.cc328
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_android.cc1268
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_android.h342
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_aura.cc803
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_aura.h138
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc952
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_base.cc34
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_base.h61
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_browsertest.cc302
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_mac.h129
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_mac.mm405
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_mac_dictionary_helper.h2
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper_unittest.mm4
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm222
-rw-r--r--chromium/content/browser/renderer_host/renderer_frame_manager.cc68
-rw-r--r--chromium/content/browser/renderer_host/renderer_frame_manager.h26
-rw-r--r--chromium/content/browser/renderer_host/sandbox_ipc_linux.cc60
-rw-r--r--chromium/content/browser/renderer_host/sandbox_ipc_linux.h13
-rw-r--r--chromium/content/browser/renderer_host/software_frame_manager.cc180
-rw-r--r--chromium/content/browser/renderer_host/software_frame_manager.h79
-rw-r--r--chromium/content/browser/renderer_host/software_frame_manager_unittest.cc266
-rw-r--r--chromium/content/browser/renderer_host/text_input_client_mac.h2
-rw-r--r--chromium/content/browser/renderer_host/text_input_client_mac_unittest.mm7
-rw-r--r--chromium/content/browser/renderer_host/text_input_client_message_filter.mm2
-rw-r--r--chromium/content/browser/renderer_host/ui_events_helper.cc223
-rw-r--r--chromium/content/browser/renderer_host/ui_events_helper.h10
-rw-r--r--chromium/content/browser/renderer_host/web_input_event_aura.cc259
-rw-r--r--chromium/content/browser/renderer_host/web_input_event_aura.h12
-rw-r--r--chromium/content/browser/renderer_host/web_input_event_aura_unittest.cc193
-rw-r--r--chromium/content/browser/renderer_host/webmenurunner_mac.h2
-rw-r--r--chromium/content/browser/renderer_host/websocket_dispatcher_host.cc112
-rw-r--r--chromium/content/browser/renderer_host/websocket_dispatcher_host.h65
-rw-r--r--chromium/content/browser/renderer_host/websocket_dispatcher_host_unittest.cc249
-rw-r--r--chromium/content/browser/renderer_host/websocket_host.cc116
-rw-r--r--chromium/content/browser/renderer_host/websocket_host.h27
-rw-r--r--chromium/content/browser/resolve_proxy_msg_helper_unittest.cc79
-rw-r--r--chromium/content/browser/resource_context_impl.cc38
-rw-r--r--chromium/content/browser/resource_context_impl.h12
-rw-r--r--chromium/content/browser/resources/accessibility/OWNERS2
-rw-r--r--chromium/content/browser/resources/accessibility/accessibility.html9
-rw-r--r--chromium/content/browser/resources/accessibility/accessibility.js15
-rw-r--r--chromium/content/browser/resources/gpu/gpu_internals.html6
-rw-r--r--chromium/content/browser/resources/gpu/info_view.html5
-rw-r--r--chromium/content/browser/resources/gpu/info_view.js8
-rw-r--r--chromium/content/browser/resources/gpu/timeline_test.html2
-rw-r--r--chromium/content/browser/resources/indexed_db/indexeddb_internals.css5
-rw-r--r--chromium/content/browser/resources/indexed_db/indexeddb_internals.html12
-rw-r--r--chromium/content/browser/resources/media/OWNERS3
-rw-r--r--chromium/content/browser/resources/media/client_renderer.js205
-rw-r--r--chromium/content/browser/resources/media/disjoint_range_set_test.html2
-rw-r--r--chromium/content/browser/resources/media/dump_creator.js4
-rw-r--r--chromium/content/browser/resources/media/media_internals.css54
-rw-r--r--chromium/content/browser/resources/media/media_internals.html175
-rw-r--r--chromium/content/browser/resources/media/media_internals.js1
-rw-r--r--chromium/content/browser/resources/media/ssrc_info_manager.js4
-rw-r--r--chromium/content/browser/resources/media/stats_table.js4
-rw-r--r--chromium/content/browser/resources/media/webrtc_internals.html4
-rw-r--r--chromium/content/browser/resources/media/webrtc_internals.js14
-rw-r--r--chromium/content/browser/resources/service_worker/serviceworker_internals.html18
-rw-r--r--chromium/content/browser/resources/service_worker/serviceworker_internals.js9
-rw-r--r--chromium/content/browser/safe_util_win.h6
-rw-r--r--chromium/content/browser/screen_orientation/screen_orientation_browsertest.cc71
-rw-r--r--chromium/content/browser/screen_orientation/screen_orientation_delegate_android.cc3
-rw-r--r--chromium/content/browser/screen_orientation/screen_orientation_delegate_android.h18
-rw-r--r--chromium/content/browser/screen_orientation/screen_orientation_dispatcher_host_impl.h2
-rw-r--r--chromium/content/browser/screen_orientation/screen_orientation_message_filter_android.h4
-rw-r--r--chromium/content/browser/security_exploit_browsertest.cc166
-rw-r--r--chromium/content/browser/service_worker/BUILD.gn4
-rw-r--r--chromium/content/browser/service_worker/PRESUBMIT.py14
-rw-r--r--chromium/content/browser/service_worker/embedded_worker_instance.cc273
-rw-r--r--chromium/content/browser/service_worker/embedded_worker_instance.h78
-rw-r--r--chromium/content/browser/service_worker/embedded_worker_instance_unittest.cc79
-rw-r--r--chromium/content/browser/service_worker/embedded_worker_registry.cc20
-rw-r--r--chromium/content/browser/service_worker/embedded_worker_registry.h13
-rw-r--r--chromium/content/browser/service_worker/embedded_worker_test_helper.cc81
-rw-r--r--chromium/content/browser/service_worker/embedded_worker_test_helper.h15
-rw-r--r--chromium/content/browser/service_worker/service_worker_browsertest.cc700
-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.cc241
-rw-r--r--chromium/content/browser/service_worker/service_worker_context_core.h64
-rw-r--r--chromium/content/browser/service_worker/service_worker_context_observer.h33
-rw-r--r--chromium/content/browser/service_worker/service_worker_context_request_handler.cc6
-rw-r--r--chromium/content/browser/service_worker/service_worker_context_request_handler_unittest.cc53
-rw-r--r--chromium/content/browser/service_worker/service_worker_context_unittest.cc235
-rw-r--r--chromium/content/browser/service_worker/service_worker_context_watcher.cc253
-rw-r--r--chromium/content/browser/service_worker/service_worker_context_watcher.h102
-rw-r--r--chromium/content/browser/service_worker/service_worker_context_wrapper.cc374
-rw-r--r--chromium/content/browser/service_worker/service_worker_context_wrapper.h94
-rw-r--r--chromium/content/browser/service_worker/service_worker_controllee_request_handler.cc40
-rw-r--r--chromium/content/browser/service_worker/service_worker_controllee_request_handler.h2
-rw-r--r--chromium/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc34
-rw-r--r--chromium/content/browser/service_worker/service_worker_database.cc345
-rw-r--r--chromium/content/browser/service_worker/service_worker_database.h46
-rw-r--r--chromium/content/browser/service_worker/service_worker_database_task_manager.h6
-rw-r--r--chromium/content/browser/service_worker/service_worker_database_unittest.cc630
-rw-r--r--chromium/content/browser/service_worker/service_worker_disk_cache.cc6
-rw-r--r--chromium/content/browser/service_worker/service_worker_disk_cache.h9
-rw-r--r--chromium/content/browser/service_worker/service_worker_dispatcher_host.cc372
-rw-r--r--chromium/content/browser/service_worker/service_worker_dispatcher_host.h51
-rw-r--r--chromium/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc205
-rw-r--r--chromium/content/browser/service_worker/service_worker_fetch_dispatcher.cc4
-rw-r--r--chromium/content/browser/service_worker/service_worker_fetch_dispatcher.h4
-rw-r--r--chromium/content/browser/service_worker/service_worker_handle.cc58
-rw-r--r--chromium/content/browser/service_worker/service_worker_handle.h42
-rw-r--r--chromium/content/browser/service_worker/service_worker_handle_unittest.cc70
-rw-r--r--chromium/content/browser/service_worker/service_worker_info.cc16
-rw-r--r--chromium/content/browser/service_worker/service_worker_info.h16
-rw-r--r--chromium/content/browser/service_worker/service_worker_internals_ui.cc208
-rw-r--r--chromium/content/browser/service_worker/service_worker_internals_ui.h7
-rw-r--r--chromium/content/browser/service_worker/service_worker_job_coordinator.cc40
-rw-r--r--chromium/content/browser/service_worker/service_worker_job_coordinator.h17
-rw-r--r--chromium/content/browser/service_worker/service_worker_job_unittest.cc808
-rw-r--r--chromium/content/browser/service_worker/service_worker_metrics.cc79
-rw-r--r--chromium/content/browser/service_worker/service_worker_metrics.h32
-rw-r--r--chromium/content/browser/service_worker/service_worker_process_manager.cc14
-rw-r--r--chromium/content/browser/service_worker/service_worker_process_manager.h4
-rw-r--r--chromium/content/browser/service_worker/service_worker_proto.gyp5
-rw-r--r--chromium/content/browser/service_worker/service_worker_provider_host.cc540
-rw-r--r--chromium/content/browser/service_worker/service_worker_provider_host.h161
-rw-r--r--chromium/content/browser/service_worker/service_worker_provider_host_unittest.cc146
-rw-r--r--chromium/content/browser/service_worker/service_worker_read_from_cache_job.cc27
-rw-r--r--chromium/content/browser/service_worker/service_worker_read_from_cache_job.h4
-rw-r--r--chromium/content/browser/service_worker/service_worker_register_job.cc194
-rw-r--r--chromium/content/browser/service_worker/service_worker_register_job.h42
-rw-r--r--chromium/content/browser/service_worker/service_worker_register_job_base.h4
-rw-r--r--chromium/content/browser/service_worker/service_worker_registration.cc214
-rw-r--r--chromium/content/browser/service_worker/service_worker_registration.h42
-rw-r--r--chromium/content/browser/service_worker/service_worker_registration_handle.cc104
-rw-r--r--chromium/content/browser/service_worker/service_worker_registration_handle.h16
-rw-r--r--chromium/content/browser/service_worker/service_worker_registration_status.cc25
-rw-r--r--chromium/content/browser/service_worker/service_worker_registration_status.h1
-rw-r--r--chromium/content/browser/service_worker/service_worker_registration_unittest.cc29
-rw-r--r--chromium/content/browser/service_worker/service_worker_request_handler.cc48
-rw-r--r--chromium/content/browser/service_worker/service_worker_request_handler.h13
-rw-r--r--chromium/content/browser/service_worker/service_worker_request_handler_unittest.cc26
-rw-r--r--chromium/content/browser/service_worker/service_worker_script_cache_map.cc59
-rw-r--r--chromium/content/browser/service_worker/service_worker_script_cache_map.h23
-rw-r--r--chromium/content/browser/service_worker/service_worker_storage.cc374
-rw-r--r--chromium/content/browser/service_worker/service_worker_storage.h101
-rw-r--r--chromium/content/browser/service_worker/service_worker_storage_unittest.cc436
-rw-r--r--chromium/content/browser/service_worker/service_worker_unregister_job.cc28
-rw-r--r--chromium/content/browser/service_worker/service_worker_unregister_job.h13
-rw-r--r--chromium/content/browser/service_worker/service_worker_url_request_job.cc234
-rw-r--r--chromium/content/browser/service_worker/service_worker_url_request_job.h39
-rw-r--r--chromium/content/browser/service_worker/service_worker_url_request_job_unittest.cc475
-rw-r--r--chromium/content/browser/service_worker/service_worker_utils.cc84
-rw-r--r--chromium/content/browser/service_worker/service_worker_utils.h14
-rw-r--r--chromium/content/browser/service_worker/service_worker_utils_unittest.cc326
-rw-r--r--chromium/content/browser/service_worker/service_worker_version.cc1507
-rw-r--r--chromium/content/browser/service_worker/service_worker_version.h333
-rw-r--r--chromium/content/browser/service_worker/service_worker_version_unittest.cc288
-rw-r--r--chromium/content/browser/service_worker/service_worker_write_to_cache_job.cc137
-rw-r--r--chromium/content/browser/service_worker/service_worker_write_to_cache_job.h7
-rw-r--r--chromium/content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc16
-rw-r--r--chromium/content/browser/shareable_file_reference_unittest.cc61
-rw-r--r--chromium/content/browser/shared_worker/shared_worker_host.cc15
-rw-r--r--chromium/content/browser/shared_worker/shared_worker_instance.h2
-rw-r--r--chromium/content/browser/shared_worker/shared_worker_message_filter.cc2
-rw-r--r--chromium/content/browser/shared_worker/shared_worker_service_impl.cc22
-rw-r--r--chromium/content/browser/shared_worker/shared_worker_service_impl.h6
-rw-r--r--chromium/content/browser/shared_worker/shared_worker_service_impl_unittest.cc49
-rw-r--r--chromium/content/browser/shared_worker/worker_browsertest.cc105
-rw-r--r--chromium/content/browser/shared_worker/worker_storage_partition.h6
-rw-r--r--chromium/content/browser/signed_certificate_timestamp_store_impl.h6
-rw-r--r--chromium/content/browser/site_instance_impl.cc22
-rw-r--r--chromium/content/browser/site_instance_impl_unittest.cc106
-rw-r--r--chromium/content/browser/site_per_process_browsertest.cc2099
-rw-r--r--chromium/content/browser/site_per_process_browsertest.h16
-rw-r--r--chromium/content/browser/speech/OWNERS2
-rw-r--r--chromium/content/browser/speech/audio_buffer.cc17
-rw-r--r--chromium/content/browser/speech/audio_buffer.h13
-rw-r--r--chromium/content/browser/speech/audio_encoder.cc2
-rw-r--r--chromium/content/browser/speech/chunked_byte_buffer.cc4
-rw-r--r--chromium/content/browser/speech/endpointer/endpointer_unittest.cc2
-rw-r--r--chromium/content/browser/speech/google_one_shot_remote_engine.cc28
-rw-r--r--chromium/content/browser/speech/google_streaming_remote_engine.cc98
-rw-r--r--chromium/content/browser/speech/google_streaming_remote_engine.h13
-rw-r--r--chromium/content/browser/speech/google_streaming_remote_engine_unittest.cc73
-rw-r--r--chromium/content/browser/speech/speech_recognition_browsertest.cc11
-rw-r--r--chromium/content/browser/speech/speech_recognition_engine.h4
-rw-r--r--chromium/content/browser/speech/speech_recognition_manager_impl.cc51
-rw-r--r--chromium/content/browser/speech/speech_recognizer_impl.cc48
-rw-r--r--chromium/content/browser/speech/speech_recognizer_impl_android.cc28
-rw-r--r--chromium/content/browser/speech/speech_recognizer_impl_android.h12
-rw-r--r--chromium/content/browser/speech/speech_recognizer_impl_unittest.cc4
-rw-r--r--chromium/content/browser/ssl/OWNERS5
-rw-r--r--chromium/content/browser/ssl/ssl_client_auth_handler.cc186
-rw-r--r--chromium/content/browser/ssl/ssl_client_auth_handler.h54
-rw-r--r--chromium/content/browser/ssl/ssl_error_handler.cc16
-rw-r--r--chromium/content/browser/ssl/ssl_manager.cc15
-rw-r--r--chromium/content/browser/ssl/ssl_policy.cc35
-rw-r--r--chromium/content/browser/ssl/ssl_policy_backend.cc14
-rw-r--r--chromium/content/browser/ssl/ssl_policy_backend.h7
-rw-r--r--chromium/content/browser/storage_partition_impl.cc159
-rw-r--r--chromium/content/browser/storage_partition_impl.h36
-rw-r--r--chromium/content/browser/storage_partition_impl_map.cc16
-rw-r--r--chromium/content/browser/storage_partition_impl_map.h6
-rw-r--r--chromium/content/browser/streams/stream.cc6
-rw-r--r--chromium/content/browser/streams/stream.h3
-rw-r--r--chromium/content/browser/streams/stream_context.cc2
-rw-r--r--chromium/content/browser/streams/stream_register_observer.h25
-rw-r--r--chromium/content/browser/streams/stream_registry.cc33
-rw-r--r--chromium/content/browser/streams/stream_registry.h14
-rw-r--r--chromium/content/browser/streams/stream_unittest.cc81
-rw-r--r--chromium/content/browser/streams/stream_url_request_job.cc4
-rw-r--r--chromium/content/browser/streams/stream_url_request_job.h3
-rw-r--r--chromium/content/browser/streams/stream_url_request_job_unittest.cc4
-rw-r--r--chromium/content/browser/system_message_window_win.h6
-rw-r--r--chromium/content/browser/system_message_window_win_unittest.cc4
-rw-r--r--chromium/content/browser/tcmalloc_internals_request_job.cc10
-rw-r--r--chromium/content/browser/theme_helper_mac.mm16
-rw-r--r--chromium/content/browser/time_zone_monitor.cc32
-rw-r--r--chromium/content/browser/time_zone_monitor_android.h2
-rw-r--r--chromium/content/browser/time_zone_monitor_chromeos.cc4
-rw-r--r--chromium/content/browser/time_zone_monitor_linux.cc12
-rw-r--r--chromium/content/browser/time_zone_monitor_win.cc30
-rw-r--r--chromium/content/browser/tracing/BUILD.gn18
-rw-r--r--chromium/content/browser/tracing/etw_system_event_consumer_win.cc21
-rw-r--r--chromium/content/browser/tracing/etw_system_event_consumer_win.h6
-rw-r--r--chromium/content/browser/tracing/file_tracing_provider_impl.cc55
-rw-r--r--chromium/content/browser/tracing/file_tracing_provider_impl.h35
-rw-r--r--chromium/content/browser/tracing/trace_message_filter.cc65
-rw-r--r--chromium/content/browser/tracing/trace_message_filter.h26
-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.cc117
-rw-r--r--chromium/content/browser/tracing/tracing_controller_impl.cc401
-rw-r--r--chromium/content/browser/tracing/tracing_controller_impl.h85
-rw-r--r--chromium/content/browser/tracing/tracing_controller_impl_data_sinks.cc302
-rw-r--r--chromium/content/browser/tracing/tracing_resources.gyp16
-rw-r--r--chromium/content/browser/tracing/tracing_ui.cc148
-rw-r--r--chromium/content/browser/tracing/tracing_ui.h15
-rw-r--r--chromium/content/browser/transition_browsertest.cc2
-rw-r--r--chromium/content/browser/transition_request_manager.cc37
-rw-r--r--chromium/content/browser/transition_request_manager_unittest.cc66
-rw-r--r--chromium/content/browser/udev_linux.cc14
-rw-r--r--chromium/content/browser/utility_process_host_impl.cc94
-rw-r--r--chromium/content/browser/utility_process_host_impl.h18
-rw-r--r--chromium/content/browser/vibration/vibration_message_filter.cc67
-rw-r--r--chromium/content/browser/vibration/vibration_message_filter.h34
-rw-r--r--chromium/content/browser/vibration/vibration_provider_android.cc56
-rw-r--r--chromium/content/browser/vibration/vibration_provider_android.h30
-rw-r--r--chromium/content/browser/web_contents/aura/gesture_nav_simple.cc19
-rw-r--r--chromium/content/browser/web_contents/aura/image_window_delegate.cc97
-rw-r--r--chromium/content/browser/web_contents/aura/image_window_delegate.h61
-rw-r--r--chromium/content/browser/web_contents/aura/overscroll_navigation_overlay.cc288
-rw-r--r--chromium/content/browser/web_contents/aura/overscroll_navigation_overlay.h127
-rw-r--r--chromium/content/browser/web_contents/aura/overscroll_navigation_overlay_unittest.cc367
-rw-r--r--chromium/content/browser/web_contents/aura/overscroll_window_animation.cc177
-rw-r--r--chromium/content/browser/web_contents/aura/overscroll_window_animation.h130
-rw-r--r--chromium/content/browser/web_contents/aura/overscroll_window_animation_unittest.cc226
-rw-r--r--chromium/content/browser/web_contents/aura/overscroll_window_delegate.cc131
-rw-r--r--chromium/content/browser/web_contents/aura/overscroll_window_delegate.h73
-rw-r--r--chromium/content/browser/web_contents/aura/overscroll_window_delegate_unittest.cc253
-rw-r--r--chromium/content/browser/web_contents/aura/shadow_layer_delegate.cc6
-rw-r--r--chromium/content/browser/web_contents/aura/shadow_layer_delegate.h4
-rw-r--r--chromium/content/browser/web_contents/aura/window_slider.cc309
-rw-r--r--chromium/content/browser/web_contents/aura/window_slider.h156
-rw-r--r--chromium/content/browser/web_contents/aura/window_slider_unittest.cc642
-rw-r--r--chromium/content/browser/web_contents/opened_by_dom_browsertest.cc5
-rw-r--r--chromium/content/browser/web_contents/touch_editable_impl_aura.cc71
-rw-r--r--chromium/content/browser/web_contents/touch_editable_impl_aura.h30
-rw-r--r--chromium/content/browser/web_contents/touch_editable_impl_aura_browsertest.cc219
-rw-r--r--chromium/content/browser/web_contents/web_contents_android.cc276
-rw-r--r--chromium/content/browser/web_contents/web_contents_android.h34
-rw-r--r--chromium/content/browser/web_contents/web_contents_impl.cc1130
-rw-r--r--chromium/content/browser/web_contents/web_contents_impl.h231
-rw-r--r--chromium/content/browser/web_contents/web_contents_impl_browsertest.cc177
-rw-r--r--chromium/content/browser/web_contents/web_contents_impl_unittest.cc1231
-rw-r--r--chromium/content/browser/web_contents/web_contents_view.h4
-rw-r--r--chromium/content/browser/web_contents/web_contents_view_android.cc7
-rw-r--r--chromium/content/browser/web_contents/web_contents_view_android.h83
-rw-r--r--chromium/content/browser/web_contents/web_contents_view_aura.cc480
-rw-r--r--chromium/content/browser/web_contents/web_contents_view_aura.h67
-rw-r--r--chromium/content/browser/web_contents/web_contents_view_aura_browsertest.cc59
-rw-r--r--chromium/content/browser/web_contents/web_contents_view_guest.cc26
-rw-r--r--chromium/content/browser/web_contents/web_contents_view_guest.h5
-rw-r--r--chromium/content/browser/web_contents/web_contents_view_mac.h3
-rw-r--r--chromium/content/browser/web_contents/web_contents_view_mac.mm56
-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.mm17
-rw-r--r--chromium/content/browser/web_contents/web_drag_dest_mac_unittest.mm8
-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.cc8
-rw-r--r--chromium/content/browser/webui/content_web_ui_controller_factory.h3
-rw-r--r--chromium/content/browser/webui/generic_handler.h2
-rw-r--r--chromium/content/browser/webui/shared_resources_data_source.cc96
-rw-r--r--chromium/content/browser/webui/shared_resources_data_source.h10
-rw-r--r--chromium/content/browser/webui/url_data_manager.cc6
-rw-r--r--chromium/content/browser/webui/url_data_manager_backend.cc19
-rw-r--r--chromium/content/browser/webui/url_data_manager_backend.h10
-rw-r--r--chromium/content/browser/webui/url_data_manager_backend_unittest.cc58
-rw-r--r--chromium/content/browser/webui/url_data_source_impl.cc2
-rw-r--r--chromium/content/browser/webui/web_ui_data_source_impl.cc10
-rw-r--r--chromium/content/browser/webui/web_ui_mojo_browsertest.cc43
-rw-r--r--chromium/content/browser/zygote_host/zygote_host_impl_linux.cc106
-rw-r--r--chromium/content/browser/zygote_host/zygote_host_impl_linux.h5
-rw-r--r--chromium/content/child/BUILD.gn41
-rw-r--r--chromium/content/child/DEPS14
-rw-r--r--chromium/content/child/appcache/appcache_frontend_impl.cc104
-rw-r--r--chromium/content/child/assert_matching_enums.cc45
-rw-r--r--chromium/content/child/background_sync/OWNERS1
-rw-r--r--chromium/content/child/background_sync/PRESUBMIT.py12
-rw-r--r--chromium/content/child/background_sync/background_sync_provider.cc242
-rw-r--r--chromium/content/child/background_sync/background_sync_provider.h80
-rw-r--r--chromium/content/child/background_sync/background_sync_provider_thread_proxy.cc168
-rw-r--r--chromium/content/child/background_sync/background_sync_provider_thread_proxy.h77
-rw-r--r--chromium/content/child/background_sync/background_sync_type_converters.cc129
-rw-r--r--chromium/content/child/background_sync/background_sync_type_converters.h87
-rw-r--r--chromium/content/child/background_sync/background_sync_type_converters_unittest.cc181
-rw-r--r--chromium/content/child/blink_platform_impl.cc721
-rw-r--r--chromium/content/child/blink_platform_impl.h71
-rw-r--r--chromium/content/child/blink_platform_impl_unittest.cc132
-rw-r--r--chromium/content/child/bluetooth/OWNERS1
-rw-r--r--chromium/content/child/bluetooth/PRESUBMIT.py14
-rw-r--r--chromium/content/child/bluetooth/bluetooth_dispatcher.cc172
-rw-r--r--chromium/content/child/bluetooth/bluetooth_dispatcher.h87
-rw-r--r--chromium/content/child/bluetooth/bluetooth_message_filter.cc37
-rw-r--r--chromium/content/child/bluetooth/bluetooth_message_filter.h30
-rw-r--r--chromium/content/child/bluetooth/web_bluetooth_impl.cc57
-rw-r--r--chromium/content/child/bluetooth/web_bluetooth_impl.h33
-rw-r--r--chromium/content/child/browser_font_resource_trusted.cc67
-rw-r--r--chromium/content/child/browser_font_resource_trusted.h3
-rw-r--r--chromium/content/child/child.gni15
-rw-r--r--chromium/content/child/child_discardable_shared_memory_manager.cc274
-rw-r--r--chromium/content/child/child_discardable_shared_memory_manager.h38
-rw-r--r--chromium/content/child/child_gpu_memory_buffer_manager.cc1
-rw-r--r--chromium/content/child/child_histogram_message_filter.cc1
-rw-r--r--chromium/content/child/child_histogram_message_filter.h6
-rw-r--r--chromium/content/child/child_message_filter.cc4
-rw-r--r--chromium/content/child/child_message_filter.h8
-rw-r--r--chromium/content/child/child_process.cc8
-rw-r--r--chromium/content/child/child_process.h12
-rw-r--r--chromium/content/child/child_resource_message_filter.h5
-rw-r--r--chromium/content/child/child_shared_bitmap_manager.cc111
-rw-r--r--chromium/content/child/child_shared_bitmap_manager.h18
-rw-r--r--chromium/content/child/child_thread.cc606
-rw-r--r--chromium/content/child/child_thread.h277
-rw-r--r--chromium/content/child/child_thread_impl.cc688
-rw-r--r--chromium/content/child/child_thread_impl.h337
-rw-r--r--chromium/content/child/child_thread_impl_browsertest.cc116
-rw-r--r--chromium/content/child/database_util.cc31
-rw-r--r--chromium/content/child/database_util.h4
-rw-r--r--chromium/content/child/file_info_util.cc7
-rw-r--r--chromium/content/child/fileapi/file_system_dispatcher.cc34
-rw-r--r--chromium/content/child/fileapi/webfilesystem_impl.cc299
-rw-r--r--chromium/content/child/fileapi/webfilesystem_impl.h11
-rw-r--r--chromium/content/child/fileapi/webfilewriter_impl.cc33
-rw-r--r--chromium/content/child/fileapi/webfilewriter_impl.h5
-rw-r--r--chromium/content/child/geofencing/geofencing_dispatcher.cc21
-rw-r--r--chromium/content/child/geofencing/geofencing_dispatcher.h10
-rw-r--r--chromium/content/child/geofencing/geofencing_message_filter.cc33
-rw-r--r--chromium/content/child/geofencing/geofencing_message_filter.h22
-rw-r--r--chromium/content/child/geofencing/web_geofencing_provider_impl.cc13
-rw-r--r--chromium/content/child/geofencing/web_geofencing_provider_impl.h11
-rw-r--r--chromium/content/child/image_decoder.h2
-rw-r--r--chromium/content/child/indexed_db/indexed_db_dispatcher.cc141
-rw-r--r--chromium/content/child/indexed_db/indexed_db_dispatcher.h18
-rw-r--r--chromium/content/child/indexed_db/indexed_db_dispatcher_unittest.cc17
-rw-r--r--chromium/content/child/indexed_db/indexed_db_key_builders.h6
-rw-r--r--chromium/content/child/indexed_db/indexed_db_message_filter.cc37
-rw-r--r--chromium/content/child/indexed_db/indexed_db_message_filter.h24
-rw-r--r--chromium/content/child/indexed_db/webidbcursor_impl.cc13
-rw-r--r--chromium/content/child/indexed_db/webidbcursor_impl.h6
-rw-r--r--chromium/content/child/indexed_db/webidbcursor_impl_unittest.cc19
-rw-r--r--chromium/content/child/indexed_db/webidbdatabase_impl.cc23
-rw-r--r--chromium/content/child/indexed_db/webidbdatabase_impl.h13
-rw-r--r--chromium/content/child/indexed_db/webidbfactory_impl.h6
-rw-r--r--chromium/content/child/mojo/mojo_application.cc24
-rw-r--r--chromium/content/child/mojo/mojo_application.h13
-rw-r--r--chromium/content/child/navigator_connect/OWNERS1
-rw-r--r--chromium/content/child/navigator_connect/navigator_connect_dispatcher.cc36
-rw-r--r--chromium/content/child/navigator_connect/navigator_connect_dispatcher.h32
-rw-r--r--chromium/content/child/navigator_connect/navigator_connect_provider.cc104
-rw-r--r--chromium/content/child/navigator_connect/navigator_connect_provider.h80
-rw-r--r--chromium/content/child/notifications/OWNERS3
-rw-r--r--chromium/content/child/notifications/notification_data_conversions.cc55
-rw-r--r--chromium/content/child/notifications/notification_data_conversions.h24
-rw-r--r--chromium/content/child/notifications/notification_data_conversions_unittest.cc137
-rw-r--r--chromium/content/child/notifications/notification_dispatcher.cc64
-rw-r--r--chromium/content/child/notifications/notification_dispatcher.h27
-rw-r--r--chromium/content/child/notifications/notification_image_loader.cc113
-rw-r--r--chromium/content/child/notifications/notification_image_loader.h108
-rw-r--r--chromium/content/child/notifications/notification_manager.cc271
-rw-r--r--chromium/content/child/notifications/notification_manager.h68
-rw-r--r--chromium/content/child/notifications/pending_notifications_tracker.cc116
-rw-r--r--chromium/content/child/notifications/pending_notifications_tracker.h107
-rw-r--r--chromium/content/child/npapi/npobject_util.h6
-rw-r--r--chromium/content/child/npapi/plugin_host.cc20
-rw-r--r--chromium/content/child/npapi/plugin_instance.cc2
-rw-r--r--chromium/content/child/npapi/plugin_instance.h4
-rw-r--r--chromium/content/child/npapi/plugin_lib.cc8
-rw-r--r--chromium/content/child/npapi/plugin_stream_url.h2
-rw-r--r--chromium/content/child/npapi/plugin_string_stream.h6
-rw-r--r--chromium/content/child/npapi/plugin_url_fetcher.cc49
-rw-r--r--chromium/content/child/npapi/plugin_url_fetcher.h17
-rw-r--r--chromium/content/child/npapi/webplugin.h2
-rw-r--r--chromium/content/child/npapi/webplugin_accelerated_surface_mac.h2
-rw-r--r--chromium/content/child/npapi/webplugin_delegate.h3
-rw-r--r--chromium/content/child/npapi/webplugin_delegate_impl.cc6
-rw-r--r--chromium/content/child/npapi/webplugin_delegate_impl.h24
-rw-r--r--chromium/content/child/npapi/webplugin_delegate_impl_mac.mm9
-rw-r--r--chromium/content/child/npapi/webplugin_delegate_impl_win.cc27
-rw-r--r--chromium/content/child/npapi/webplugin_ime_win.cc16
-rw-r--r--chromium/content/child/npapi/webplugin_ime_win.h38
-rw-r--r--chromium/content/child/permissions/OWNERS1
-rw-r--r--chromium/content/child/permissions/permission_dispatcher.cc284
-rw-r--r--chromium/content/child/permissions/permission_dispatcher.h125
-rw-r--r--chromium/content/child/permissions/permission_dispatcher_thread_proxy.cc126
-rw-r--r--chromium/content/child/permissions/permission_dispatcher_thread_proxy.h68
-rw-r--r--chromium/content/child/permissions/permission_observers_registry.cc32
-rw-r--r--chromium/content/child/permissions/permission_observers_registry.h35
-rw-r--r--chromium/content/child/plugin_messages.h11
-rw-r--r--chromium/content/child/power_monitor_broadcast_source.h2
-rw-r--r--chromium/content/child/push_messaging/OWNERS1
-rw-r--r--chromium/content/child/push_messaging/push_dispatcher.cc63
-rw-r--r--chromium/content/child/push_messaging/push_dispatcher.h44
-rw-r--r--chromium/content/child/push_messaging/push_provider.cc277
-rw-r--r--chromium/content/child/push_messaging/push_provider.h106
-rw-r--r--chromium/content/child/quota_dispatcher.cc27
-rw-r--r--chromium/content/child/quota_message_filter.cc52
-rw-r--r--chromium/content/child/quota_message_filter.h23
-rw-r--r--chromium/content/child/request_extra_data.h2
-rw-r--r--chromium/content/child/request_info.cc5
-rw-r--r--chromium/content/child/request_info.h16
-rw-r--r--chromium/content/child/resource_dispatcher.cc407
-rw-r--r--chromium/content/child/resource_dispatcher.h74
-rw-r--r--chromium/content/child/resource_dispatcher_unittest.cc194
-rw-r--r--chromium/content/child/resource_loader_bridge.cc13
-rw-r--r--chromium/content/child/resource_loader_bridge.h92
-rw-r--r--chromium/content/child/resource_scheduling_filter.cc45
-rw-r--r--chromium/content/child/resource_scheduling_filter.h46
-rw-r--r--chromium/content/child/runtime_features.cc120
-rw-r--r--chromium/content/child/service_worker/service_worker_dispatcher.cc357
-rw-r--r--chromium/content/child/service_worker/service_worker_dispatcher.h84
-rw-r--r--chromium/content/child/service_worker/service_worker_dispatcher_unittest.cc219
-rw-r--r--chromium/content/child/service_worker/service_worker_handle_reference.h1
-rw-r--r--chromium/content/child/service_worker/service_worker_message_filter.cc56
-rw-r--r--chromium/content/child/service_worker/service_worker_message_filter.h26
-rw-r--r--chromium/content/child/service_worker/service_worker_network_provider.cc21
-rw-r--r--chromium/content/child/service_worker/service_worker_network_provider.h4
-rw-r--r--chromium/content/child/service_worker/service_worker_provider_context.cc119
-rw-r--r--chromium/content/child/service_worker/service_worker_provider_context.h54
-rw-r--r--chromium/content/child/service_worker/service_worker_registration_handle_reference.cc2
-rw-r--r--chromium/content/child/service_worker/web_service_worker_impl.cc30
-rw-r--r--chromium/content/child/service_worker/web_service_worker_impl.h10
-rw-r--r--chromium/content/child/service_worker/web_service_worker_provider_impl.cc66
-rw-r--r--chromium/content/child/service_worker/web_service_worker_provider_impl.h10
-rw-r--r--chromium/content/child/service_worker/web_service_worker_registration_impl.h3
-rw-r--r--chromium/content/child/shared_worker_devtools_agent.cc39
-rw-r--r--chromium/content/child/shared_worker_devtools_agent.h5
-rw-r--r--chromium/content/child/simple_webmimeregistry_impl.cc38
-rw-r--r--chromium/content/child/simple_webmimeregistry_impl.h3
-rw-r--r--chromium/content/child/site_isolation_policy.cc4
-rw-r--r--chromium/content/child/site_isolation_policy_browsertest.cc9
-rw-r--r--chromium/content/child/thread_safe_sender.cc10
-rw-r--r--chromium/content/child/thread_safe_sender.h15
-rw-r--r--chromium/content/child/threaded_data_provider.cc176
-rw-r--r--chromium/content/child/threaded_data_provider.h44
-rw-r--r--chromium/content/child/v8_value_converter_impl.cc557
-rw-r--r--chromium/content/child/v8_value_converter_impl.h98
-rw-r--r--chromium/content/child/v8_value_converter_impl_unittest.cc875
-rw-r--r--chromium/content/child/web_data_consumer_handle_impl.cc2
-rw-r--r--chromium/content/child/web_data_consumer_handle_impl.h2
-rw-r--r--chromium/content/child/web_data_consumer_handle_impl_unittest.cc2
-rw-r--r--chromium/content/child/web_discardable_memory_impl.cc25
-rw-r--r--chromium/content/child/web_discardable_memory_impl.h5
-rw-r--r--chromium/content/child/web_gesture_curve_impl.cc97
-rw-r--r--chromium/content/child/web_gesture_curve_impl.h53
-rw-r--r--chromium/content/child/web_gesture_curve_impl_unittest.cc72
-rw-r--r--chromium/content/child/web_memory_allocator_dump_impl.cc30
-rw-r--r--chromium/content/child/web_memory_allocator_dump_impl.h44
-rw-r--r--chromium/content/child/web_memory_dump_provider_adapter.cc27
-rw-r--r--chromium/content/child/web_memory_dump_provider_adapter.h46
-rw-r--r--chromium/content/child/web_process_memory_dump_impl.cc38
-rw-r--r--chromium/content/child/web_process_memory_dump_impl.h50
-rw-r--r--chromium/content/child/web_url_loader_impl.cc592
-rw-r--r--chromium/content/child/web_url_loader_impl.h29
-rw-r--r--chromium/content/child/web_url_loader_impl_unittest.cc203
-rw-r--r--chromium/content/child/web_url_request_util.cc94
-rw-r--r--chromium/content/child/web_url_request_util.h20
-rw-r--r--chromium/content/child/webblobregistry_impl.cc185
-rw-r--r--chromium/content/child/webblobregistry_impl.h23
-rw-r--r--chromium/content/child/webcrypto/OWNERS2
-rw-r--r--chromium/content/child/webcrypto/algorithm_dispatch.cc253
-rw-r--r--chromium/content/child/webcrypto/algorithm_dispatch.h97
-rw-r--r--chromium/content/child/webcrypto/algorithm_implementation.cc131
-rw-r--r--chromium/content/child/webcrypto/algorithm_implementation.h157
-rw-r--r--chromium/content/child/webcrypto/algorithm_registry.cc90
-rw-r--r--chromium/content/child/webcrypto/algorithm_registry.h32
-rw-r--r--chromium/content/child/webcrypto/crypto_data.cc29
-rw-r--r--chromium/content/child/webcrypto/crypto_data.h49
-rw-r--r--chromium/content/child/webcrypto/generate_key_result.cc63
-rw-r--r--chromium/content/child/webcrypto/generate_key_result.h60
-rw-r--r--chromium/content/child/webcrypto/jwk.cc711
-rw-r--r--chromium/content/child/webcrypto/jwk.h245
-rw-r--r--chromium/content/child/webcrypto/nss/aes_cbc_nss.cc128
-rw-r--r--chromium/content/child/webcrypto/nss/aes_gcm_nss.cc191
-rw-r--r--chromium/content/child/webcrypto/nss/aes_key_nss.cc134
-rw-r--r--chromium/content/child/webcrypto/nss/aes_key_nss.h77
-rw-r--r--chromium/content/child/webcrypto/nss/aes_kw_nss.cc206
-rw-r--r--chromium/content/child/webcrypto/nss/hmac_nss.cc240
-rw-r--r--chromium/content/child/webcrypto/nss/key_nss.cc96
-rw-r--r--chromium/content/child/webcrypto/nss/key_nss.h109
-rw-r--r--chromium/content/child/webcrypto/nss/rsa_key_nss.cc852
-rw-r--r--chromium/content/child/webcrypto/nss/rsa_key_nss.h92
-rw-r--r--chromium/content/child/webcrypto/nss/rsa_oaep_nss.cc246
-rw-r--r--chromium/content/child/webcrypto/nss/rsa_ssa_nss.cc144
-rw-r--r--chromium/content/child/webcrypto/nss/sha_nss.cc160
-rw-r--r--chromium/content/child/webcrypto/nss/sym_key_nss.cc94
-rw-r--r--chromium/content/child/webcrypto/nss/sym_key_nss.h39
-rw-r--r--chromium/content/child/webcrypto/nss/util_nss.cc95
-rw-r--r--chromium/content/child/webcrypto/nss/util_nss.h113
-rw-r--r--chromium/content/child/webcrypto/openssl/aes_cbc_openssl.cc139
-rw-r--r--chromium/content/child/webcrypto/openssl/aes_ctr_openssl.cc288
-rw-r--r--chromium/content/child/webcrypto/openssl/aes_gcm_openssl.cc88
-rw-r--r--chromium/content/child/webcrypto/openssl/aes_key_openssl.cc124
-rw-r--r--chromium/content/child/webcrypto/openssl/aes_key_openssl.h67
-rw-r--r--chromium/content/child/webcrypto/openssl/aes_kw_openssl.cc94
-rw-r--r--chromium/content/child/webcrypto/openssl/hmac_openssl.cc216
-rw-r--r--chromium/content/child/webcrypto/openssl/key_openssl.cc73
-rw-r--r--chromium/content/child/webcrypto/openssl/key_openssl.h83
-rw-r--r--chromium/content/child/webcrypto/openssl/rsa_key_openssl.cc389
-rw-r--r--chromium/content/child/webcrypto/openssl/rsa_key_openssl.h83
-rw-r--r--chromium/content/child/webcrypto/openssl/rsa_oaep_openssl.cc153
-rw-r--r--chromium/content/child/webcrypto/openssl/rsa_pss_openssl.cc67
-rw-r--r--chromium/content/child/webcrypto/openssl/rsa_sign_openssl.cc155
-rw-r--r--chromium/content/child/webcrypto/openssl/rsa_sign_openssl.h44
-rw-r--r--chromium/content/child/webcrypto/openssl/rsa_ssa_openssl.cc61
-rw-r--r--chromium/content/child/webcrypto/openssl/sha_openssl.cc140
-rw-r--r--chromium/content/child/webcrypto/openssl/sym_key_openssl.cc60
-rw-r--r--chromium/content/child/webcrypto/openssl/sym_key_openssl.h34
-rw-r--r--chromium/content/child/webcrypto/openssl/util_openssl.cc249
-rw-r--r--chromium/content/child/webcrypto/openssl/util_openssl.h87
-rw-r--r--chromium/content/child/webcrypto/platform_crypto.h43
-rw-r--r--chromium/content/child/webcrypto/status.cc258
-rw-r--r--chromium/content/child/webcrypto/status.h235
-rw-r--r--chromium/content/child/webcrypto/structured_clone.cc136
-rw-r--r--chromium/content/child/webcrypto/structured_clone.h34
-rw-r--r--chromium/content/child/webcrypto/webcrypto_impl.cc727
-rw-r--r--chromium/content/child/webcrypto/webcrypto_impl.h114
-rw-r--r--chromium/content/child/webcrypto/webcrypto_util.cc259
-rw-r--r--chromium/content/child/webcrypto/webcrypto_util.h83
-rw-r--r--chromium/content/child/webmessageportchannel_impl.cc188
-rw-r--r--chromium/content/child/webmessageportchannel_impl.h47
-rw-r--r--chromium/content/child/websocket_bridge.cc24
-rw-r--r--chromium/content/child/websocket_bridge.h30
-rw-r--r--chromium/content/child/webthemeengine_impl_default.cc57
-rw-r--r--chromium/content/child/webthemeengine_impl_default.h8
-rw-r--r--chromium/content/child/webthread_impl.cc140
-rw-r--r--chromium/content/child/webthread_impl.h79
-rw-r--r--chromium/content/child/worker_task_runner.cc84
-rw-r--r--chromium/content/child/worker_task_runner.h31
-rw-r--r--chromium/content/child/worker_task_runner_unittest.cc8
-rw-r--r--chromium/content/child/worker_thread_message_filter.cc48
-rw-r--r--chromium/content/child/worker_thread_message_filter.h58
-rw-r--r--chromium/content/child/worker_thread_task_runner.cc38
-rw-r--r--chromium/content/child/worker_thread_task_runner.h39
-rw-r--r--chromium/content/common/BUILD.gn309
-rw-r--r--chromium/content/common/DEPS27
-rw-r--r--chromium/content/common/OWNERS4
-rw-r--r--chromium/content/common/accessibility_messages.h13
-rw-r--r--chromium/content/common/android/address_parser.cc10
-rw-r--r--chromium/content/common/android/address_parser.h6
-rw-r--r--chromium/content/common/android/address_parser_internal.cc6
-rw-r--r--chromium/content/common/android/address_parser_internal.h10
-rw-r--r--chromium/content/common/android/address_parser_unittest.cc5
-rw-r--r--chromium/content/common/android/gin_java_bridge_value_unittest.cc9
-rw-r--r--chromium/content/common/android/surface_texture_manager.h3
-rw-r--r--chromium/content/common/appcache_interfaces.cc10
-rw-r--r--chromium/content/common/appcache_interfaces.h13
-rw-r--r--chromium/content/common/application_setup.mojom12
-rw-r--r--chromium/content/common/background_sync_service.mojom33
-rw-r--r--chromium/content/common/bluetooth/DEPS4
-rw-r--r--chromium/content/common/bluetooth/OWNERS14
-rw-r--r--chromium/content/common/bluetooth/PRESUBMIT.py14
-rw-r--r--chromium/content/common/bluetooth/bluetooth_device.cc58
-rw-r--r--chromium/content/common/bluetooth/bluetooth_device.h48
-rw-r--r--chromium/content/common/bluetooth/bluetooth_error.h21
-rw-r--r--chromium/content/common/bluetooth/bluetooth_messages.h148
-rw-r--r--chromium/content/common/browser_plugin/browser_plugin_constants.h4
-rw-r--r--chromium/content/common/browser_plugin/browser_plugin_messages.h152
-rw-r--r--chromium/content/common/cache_storage/OWNERS18
-rw-r--r--chromium/content/common/cache_storage/cache_storage_messages.h197
-rw-r--r--chromium/content/common/cache_storage/cache_storage_types.cc16
-rw-r--r--chromium/content/common/cache_storage/cache_storage_types.h62
-rw-r--r--chromium/content/common/cc_messages.cc26
-rw-r--r--chromium/content/common/cc_messages.h27
-rw-r--r--chromium/content/common/cc_messages_perftest.cc6
-rw-r--r--chromium/content/common/cc_messages_unittest.cc166
-rw-r--r--chromium/content/common/child_process_host_impl.cc62
-rw-r--r--chromium/content/common/child_process_host_impl.h8
-rw-r--r--chromium/content/common/child_process_messages.h40
-rw-r--r--chromium/content/common/child_process_sandbox_support_impl_linux.cc36
-rw-r--r--chromium/content/common/clipboard_messages.h51
-rw-r--r--chromium/content/common/common.gni18
-rw-r--r--chromium/content/common/common_param_traits_unittest.cc4
-rw-r--r--chromium/content/common/content_message_generator.h5
-rw-r--r--chromium/content/common/content_param_traits.cc23
-rw-r--r--chromium/content/common/content_param_traits.h12
-rw-r--r--chromium/content/common/content_param_traits_macros.h2
-rw-r--r--chromium/content/common/content_switches_internal.cc66
-rw-r--r--chromium/content/common/content_switches_internal.h10
-rw-r--r--chromium/content/common/cookie_data.cc32
-rw-r--r--chromium/content/common/cookie_data.h50
-rw-r--r--chromium/content/common/cursors/webcursor.h4
-rw-r--r--chromium/content/common/cursors/webcursor_mac.mm4
-rw-r--r--chromium/content/common/cursors/webcursor_ozone.cc20
-rw-r--r--chromium/content/common/database_connections_unittest.cc22
-rw-r--r--chromium/content/common/database_messages.h6
-rw-r--r--chromium/content/common/desktop_notification_messages.h49
-rw-r--r--chromium/content/common/device_sensors/device_motion_hardware_buffer.h2
-rw-r--r--chromium/content/common/device_sensors/device_orientation_hardware_buffer.h2
-rw-r--r--chromium/content/common/devtools_messages.h46
-rw-r--r--chromium/content/common/discardable_shared_memory_heap.cc377
-rw-r--r--chromium/content/common/discardable_shared_memory_heap.h156
-rw-r--r--chromium/content/common/discardable_shared_memory_heap_perftest.cc99
-rw-r--r--chromium/content/common/discardable_shared_memory_heap_unittest.cc306
-rw-r--r--chromium/content/common/dom_storage/dom_storage_map.cc21
-rw-r--r--chromium/content/common/dom_storage/dom_storage_map.h2
-rw-r--r--chromium/content/common/dom_storage/dom_storage_messages.h18
-rw-r--r--chromium/content/common/drag_event_source_info.h2
-rw-r--r--chromium/content/common/drag_messages.h6
-rw-r--r--chromium/content/common/drag_traits.h2
-rw-r--r--chromium/content/common/dwrite_font_platform_win.cc1229
-rw-r--r--chromium/content/common/dwrite_font_platform_win_unittest.cc71
-rw-r--r--chromium/content/common/fileapi/webblob_messages.h10
-rw-r--r--chromium/content/common/font_cache_dispatcher_win.cc21
-rw-r--r--chromium/content/common/font_cache_dispatcher_win.h11
-rw-r--r--chromium/content/common/font_config_ipc_linux.cc92
-rw-r--r--chromium/content/common/font_config_ipc_linux.h19
-rw-r--r--chromium/content/common/frame_message_enums.h22
-rw-r--r--chromium/content/common/frame_messages.h410
-rw-r--r--chromium/content/common/frame_replication_state.cc21
-rw-r--r--chromium/content/common/frame_replication_state.h95
-rw-r--r--chromium/content/common/gamepad_param_traits.cc2
-rw-r--r--chromium/content/common/gamepad_param_traits.h2
-rw-r--r--chromium/content/common/geofencing_messages.h12
-rw-r--r--chromium/content/common/geofencing_status.cc32
-rw-r--r--chromium/content/common/geofencing_status.h34
-rw-r--r--chromium/content/common/geofencing_types.cc32
-rw-r--r--chromium/content/common/geofencing_types.h48
-rw-r--r--chromium/content/common/geolocation_messages.h46
-rw-r--r--chromium/content/common/geolocation_service.mojom15
-rw-r--r--chromium/content/common/gpu/client/DEPS4
-rw-r--r--chromium/content/common/gpu/client/command_buffer_metrics.cc153
-rw-r--r--chromium/content/common/gpu/client/command_buffer_metrics.h37
-rw-r--r--chromium/content/common/gpu/client/command_buffer_proxy_impl.cc119
-rw-r--r--chromium/content/common/gpu/client/command_buffer_proxy_impl.h31
-rw-r--r--chromium/content/common/gpu/client/context_provider_command_buffer.cc45
-rw-r--r--chromium/content/common/gpu/client/context_provider_command_buffer.h34
-rw-r--r--chromium/content/common/gpu/client/gl_helper.cc198
-rw-r--r--chromium/content/common/gpu/client/gl_helper.h21
-rw-r--r--chromium/content/common/gpu/client/gl_helper_benchmark.cc6
-rw-r--r--chromium/content/common/gpu/client/gl_helper_scaling.cc6
-rw-r--r--chromium/content/common/gpu/client/gl_helper_scaling.h4
-rw-r--r--chromium/content/common/gpu/client/gl_helper_unittest.cc90
-rw-r--r--chromium/content/common/gpu/client/gpu_channel_host.cc164
-rw-r--r--chromium/content/common/gpu/client/gpu_channel_host.h43
-rw-r--r--chromium/content/common/gpu/client/gpu_in_process_context_tests.cc4
-rw-r--r--chromium/content/common/gpu/client/gpu_memory_buffer_factory_host.cc27
-rw-r--r--chromium/content/common/gpu/client/gpu_memory_buffer_factory_host.h13
-rw-r--r--chromium/content/common/gpu/client/gpu_memory_buffer_impl.cc145
-rw-r--r--chromium/content/common/gpu/client/gpu_memory_buffer_impl.h63
-rw-r--r--chromium/content/common/gpu/client/gpu_memory_buffer_impl_android.cc99
-rw-r--r--chromium/content/common/gpu/client/gpu_memory_buffer_impl_io_surface.cc143
-rw-r--r--chromium/content/common/gpu/client/gpu_memory_buffer_impl_io_surface.h25
-rw-r--r--chromium/content/common/gpu/client/gpu_memory_buffer_impl_linux.cc70
-rw-r--r--chromium/content/common/gpu/client/gpu_memory_buffer_impl_mac.cc96
-rw-r--r--chromium/content/common/gpu/client/gpu_memory_buffer_impl_ozone.cc99
-rw-r--r--chromium/content/common/gpu/client/gpu_memory_buffer_impl_ozone_native_buffer.cc125
-rw-r--r--chromium/content/common/gpu/client/gpu_memory_buffer_impl_ozone_native_buffer.h30
-rw-r--r--chromium/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.cc143
-rw-r--r--chromium/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h30
-rw-r--r--chromium/content/common/gpu/client/gpu_memory_buffer_impl_surface_texture.cc162
-rw-r--r--chromium/content/common/gpu/client/gpu_memory_buffer_impl_surface_texture.h31
-rw-r--r--chromium/content/common/gpu/client/gpu_memory_buffer_impl_unittest.cc153
-rw-r--r--chromium/content/common/gpu/client/gpu_memory_buffer_impl_win.cc70
-rw-r--r--chromium/content/common/gpu/client/gpu_video_decode_accelerator_host.cc14
-rw-r--r--chromium/content/common/gpu/client/gpu_video_decode_accelerator_host.h5
-rw-r--r--chromium/content/common/gpu/client/gpu_video_encode_accelerator_host.cc61
-rw-r--r--chromium/content/common/gpu/client/gpu_video_encode_accelerator_host.h6
-rw-r--r--chromium/content/common/gpu/client/grcontext_for_webgraphicscontext3d.cc90
-rw-r--r--chromium/content/common/gpu/client/grcontext_for_webgraphicscontext3d.h41
-rw-r--r--chromium/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc48
-rw-r--r--chromium/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h13
-rw-r--r--chromium/content/common/gpu/devtools_gpu_agent.cc80
-rw-r--r--chromium/content/common/gpu/devtools_gpu_agent.h51
-rw-r--r--chromium/content/common/gpu/devtools_gpu_instrumentation.cc50
-rw-r--r--chromium/content/common/gpu/devtools_gpu_instrumentation.h65
-rw-r--r--chromium/content/common/gpu/gpu_channel.cc156
-rw-r--r--chromium/content/common/gpu/gpu_channel.h46
-rw-r--r--chromium/content/common/gpu/gpu_channel_manager.cc130
-rw-r--r--chromium/content/common/gpu/gpu_channel_manager.h46
-rw-r--r--chromium/content/common/gpu/gpu_channel_manager_unittest.cc223
-rw-r--r--chromium/content/common/gpu/gpu_command_buffer_stub.cc144
-rw-r--r--chromium/content/common/gpu/gpu_command_buffer_stub.h11
-rw-r--r--chromium/content/common/gpu/gpu_memory_buffer_factory.cc66
-rw-r--r--chromium/content/common/gpu/gpu_memory_buffer_factory.h40
-rw-r--r--chromium/content/common/gpu/gpu_memory_buffer_factory_android.cc88
-rw-r--r--chromium/content/common/gpu/gpu_memory_buffer_factory_io_surface.cc115
-rw-r--r--chromium/content/common/gpu/gpu_memory_buffer_factory_io_surface.h37
-rw-r--r--chromium/content/common/gpu/gpu_memory_buffer_factory_linux.cc67
-rw-r--r--chromium/content/common/gpu/gpu_memory_buffer_factory_mac.cc88
-rw-r--r--chromium/content/common/gpu/gpu_memory_buffer_factory_ozone.cc94
-rw-r--r--chromium/content/common/gpu/gpu_memory_buffer_factory_ozone_native_buffer.cc93
-rw-r--r--chromium/content/common/gpu/gpu_memory_buffer_factory_ozone_native_buffer.h61
-rw-r--r--chromium/content/common/gpu/gpu_memory_buffer_factory_shared_memory.cc83
-rw-r--r--chromium/content/common/gpu/gpu_memory_buffer_factory_shared_memory.h54
-rw-r--r--chromium/content/common/gpu/gpu_memory_buffer_factory_surface_texture.cc67
-rw-r--r--chromium/content/common/gpu/gpu_memory_buffer_factory_surface_texture.h40
-rw-r--r--chromium/content/common/gpu/gpu_memory_buffer_factory_unittest.cc58
-rw-r--r--chromium/content/common/gpu/gpu_memory_buffer_factory_win.cc67
-rw-r--r--chromium/content/common/gpu/gpu_memory_manager.cc11
-rw-r--r--chromium/content/common/gpu/gpu_memory_manager.h2
-rw-r--r--chromium/content/common/gpu/gpu_memory_manager_client.h2
-rw-r--r--chromium/content/common/gpu/gpu_memory_manager_unittest.cc4
-rw-r--r--chromium/content/common/gpu/gpu_memory_tracking.h2
-rw-r--r--chromium/content/common/gpu/gpu_memory_uma_stats.h2
-rw-r--r--chromium/content/common/gpu/gpu_messages.h86
-rw-r--r--chromium/content/common/gpu/gpu_process_launch_causes.h1
-rw-r--r--chromium/content/common/gpu/image_transport_surface.cc112
-rw-r--r--chromium/content/common/gpu/image_transport_surface.h17
-rw-r--r--chromium/content/common/gpu/image_transport_surface_android.cc10
-rw-r--r--chromium/content/common/gpu/image_transport_surface_calayer_mac.h35
-rw-r--r--chromium/content/common/gpu/image_transport_surface_calayer_mac.mm369
-rw-r--r--chromium/content/common/gpu/image_transport_surface_fbo_mac.h18
-rw-r--r--chromium/content/common/gpu/image_transport_surface_fbo_mac.mm114
-rw-r--r--chromium/content/common/gpu/image_transport_surface_iosurface_mac.cc22
-rw-r--r--chromium/content/common/gpu/image_transport_surface_iosurface_mac.h16
-rw-r--r--chromium/content/common/gpu/image_transport_surface_linux.cc10
-rw-r--r--chromium/content/common/gpu/image_transport_surface_mac.mm13
-rw-r--r--chromium/content/common/gpu/image_transport_surface_win.cc2
-rw-r--r--chromium/content/common/gpu/media/DEPS4
-rw-r--r--chromium/content/common/gpu/media/OWNERS5
-rw-r--r--chromium/content/common/gpu/media/accelerated_video_decoder.h63
-rw-r--r--chromium/content/common/gpu/media/android_video_decode_accelerator.cc29
-rw-r--r--chromium/content/common/gpu/media/android_video_decode_accelerator.h22
-rw-r--r--chromium/content/common/gpu/media/android_video_decode_accelerator_unittest.cc28
-rw-r--r--chromium/content/common/gpu/media/android_video_encode_accelerator.cc82
-rw-r--r--chromium/content/common/gpu/media/android_video_encode_accelerator.h29
-rw-r--r--chromium/content/common/gpu/media/dxva_video_decode_accelerator.cc1617
-rw-r--r--chromium/content/common/gpu/media/dxva_video_decode_accelerator.h206
-rw-r--r--chromium/content/common/gpu/media/exynos_v4l2_video_device.cc211
-rw-r--r--chromium/content/common/gpu/media/exynos_v4l2_video_device.h58
-rw-r--r--chromium/content/common/gpu/media/fake_video_decode_accelerator.cc175
-rw-r--r--chromium/content/common/gpu/media/fake_video_decode_accelerator.h71
-rw-r--r--chromium/content/common/gpu/media/generic_v4l2_device.cc299
-rw-r--r--chromium/content/common/gpu/media/generic_v4l2_device.h66
-rw-r--r--chromium/content/common/gpu/media/gpu_video_accelerator_util.cc133
-rw-r--r--chromium/content/common/gpu/media/gpu_video_accelerator_util.h53
-rw-r--r--chromium/content/common/gpu/media/gpu_video_decode_accelerator.cc297
-rw-r--r--chromium/content/common/gpu/media/gpu_video_decode_accelerator.h48
-rw-r--r--chromium/content/common/gpu/media/gpu_video_encode_accelerator.cc152
-rw-r--r--chromium/content/common/gpu/media/gpu_video_encode_accelerator.h22
-rw-r--r--chromium/content/common/gpu/media/h264_decoder.cc1292
-rw-r--r--chromium/content/common/gpu/media/h264_decoder.h262
-rw-r--r--chromium/content/common/gpu/media/h264_dpb.cc96
-rw-r--r--chromium/content/common/gpu/media/h264_dpb.h60
-rw-r--r--chromium/content/common/gpu/media/rendering_helper.cc317
-rw-r--r--chromium/content/common/gpu/media/rendering_helper.h38
-rw-r--r--chromium/content/common/gpu/media/tegra_v4l2_device.cc223
-rw-r--r--chromium/content/common/gpu/media/tegra_v4l2_device.h58
-rw-r--r--chromium/content/common/gpu/media/tegra_v4l2_video_device.cc220
-rw-r--r--chromium/content/common/gpu/media/tegra_v4l2_video_device.h58
-rw-r--r--chromium/content/common/gpu/media/v4l2.sig10
-rw-r--r--chromium/content/common/gpu/media/v4l2_device.cc297
-rw-r--r--chromium/content/common/gpu/media/v4l2_device.h130
-rw-r--r--chromium/content/common/gpu/media/v4l2_image_processor.cc36
-rw-r--r--chromium/content/common/gpu/media/v4l2_image_processor.h20
-rw-r--r--chromium/content/common/gpu/media/v4l2_slice_video_decode_accelerator.cc2515
-rw-r--r--chromium/content/common/gpu/media/v4l2_slice_video_decode_accelerator.h397
-rw-r--r--chromium/content/common/gpu/media/v4l2_stub_header.fragment8
-rw-r--r--chromium/content/common/gpu/media/v4l2_video_decode_accelerator.cc376
-rw-r--r--chromium/content/common/gpu/media/v4l2_video_decode_accelerator.h88
-rw-r--r--chromium/content/common/gpu/media/v4l2_video_device.cc143
-rw-r--r--chromium/content/common/gpu/media/v4l2_video_device.h102
-rw-r--r--chromium/content/common/gpu/media/v4l2_video_encode_accelerator.cc301
-rw-r--r--chromium/content/common/gpu/media/v4l2_video_encode_accelerator.h60
-rw-r--r--chromium/content/common/gpu/media/va.sigs10
-rw-r--r--chromium/content/common/gpu/media/va_drm.sigs8
-rw-r--r--chromium/content/common/gpu/media/va_stub_header.fragment3
-rw-r--r--chromium/content/common/gpu/media/va_surface.h17
-rw-r--r--chromium/content/common/gpu/media/va_x11.sigs9
-rw-r--r--chromium/content/common/gpu/media/vaapi_drm_picture.cc135
-rw-r--r--chromium/content/common/gpu/media/vaapi_drm_picture.h66
-rw-r--r--chromium/content/common/gpu/media/vaapi_h264_decoder.cc1700
-rw-r--r--chromium/content/common/gpu/media/vaapi_h264_decoder.h295
-rw-r--r--chromium/content/common/gpu/media/vaapi_h264_decoder_unittest.cc385
-rw-r--r--chromium/content/common/gpu/media/vaapi_jpeg_decoder.cc303
-rw-r--r--chromium/content/common/gpu/media/vaapi_jpeg_decoder.h45
-rw-r--r--chromium/content/common/gpu/media/vaapi_jpeg_decoder_unittest.cc136
-rw-r--r--chromium/content/common/gpu/media/vaapi_picture.cc53
-rw-r--r--chromium/content/common/gpu/media/vaapi_picture.h82
-rw-r--r--chromium/content/common/gpu/media/vaapi_tfp_picture.cc81
-rw-r--r--chromium/content/common/gpu/media/vaapi_tfp_picture.h58
-rw-r--r--chromium/content/common/gpu/media/vaapi_video_decode_accelerator.cc1162
-rw-r--r--chromium/content/common/gpu/media/vaapi_video_decode_accelerator.h131
-rw-r--r--chromium/content/common/gpu/media/vaapi_video_encode_accelerator.cc244
-rw-r--r--chromium/content/common/gpu/media/vaapi_video_encode_accelerator.h45
-rw-r--r--chromium/content/common/gpu/media/vaapi_wrapper.cc693
-rw-r--r--chromium/content/common/gpu/media/vaapi_wrapper.h235
-rw-r--r--chromium/content/common/gpu/media/video_decode_accelerator_unittest.cc514
-rw-r--r--chromium/content/common/gpu/media/video_encode_accelerator_unittest.cc655
-rw-r--r--chromium/content/common/gpu/media/vp8_decoder.cc197
-rw-r--r--chromium/content/common/gpu/media/vp8_decoder.h107
-rw-r--r--chromium/content/common/gpu/media/vp8_picture.cc23
-rw-r--r--chromium/content/common/gpu/media/vp8_picture.h31
-rw-r--r--chromium/content/common/gpu/media/vt.sig3
-rw-r--r--chromium/content/common/gpu/media/vt_stubs_header.fragment1
-rw-r--r--chromium/content/common/gpu/media/vt_video_decode_accelerator.cc1168
-rw-r--r--chromium/content/common/gpu/media/vt_video_decode_accelerator.h222
-rw-r--r--chromium/content/common/gpu/stream_texture_android.cc2
-rw-r--r--chromium/content/common/gpu/stream_texture_android.h34
-rw-r--r--chromium/content/common/gpu/surface_handle_types_mac.cc53
-rw-r--r--chromium/content/common/gpu/surface_handle_types_mac.h35
-rw-r--r--chromium/content/common/gpu/sync_point_manager.cc84
-rw-r--r--chromium/content/common/gpu/sync_point_manager.h60
-rw-r--r--chromium/content/common/gpu/x_util.cc15
-rw-r--r--chromium/content/common/gpu/x_util.h16
-rw-r--r--chromium/content/common/handle_enumerator_win.cc322
-rw-r--r--chromium/content/common/handle_enumerator_win.h55
-rw-r--r--chromium/content/common/host_discardable_shared_memory_manager.cc280
-rw-r--r--chromium/content/common/host_discardable_shared_memory_manager.h67
-rw-r--r--chromium/content/common/host_discardable_shared_memory_manager_unittest.cc42
-rw-r--r--chromium/content/common/host_shared_bitmap_manager.cc160
-rw-r--r--chromium/content/common/host_shared_bitmap_manager.h52
-rw-r--r--chromium/content/common/host_shared_bitmap_manager_unittest.cc39
-rw-r--r--chromium/content/common/image_messages.h7
-rw-r--r--chromium/content/common/in_process_child_thread_params.cc18
-rw-r--r--chromium/content/common/in_process_child_thread_params.h38
-rw-r--r--chromium/content/common/indexed_db/indexed_db_constants.h2
-rw-r--r--chromium/content/common/indexed_db/indexed_db_key.cc13
-rw-r--r--chromium/content/common/indexed_db/indexed_db_key.h33
-rw-r--r--chromium/content/common/indexed_db/indexed_db_key_path.cc5
-rw-r--r--chromium/content/common/indexed_db/indexed_db_key_path.h4
-rw-r--r--chromium/content/common/indexed_db/indexed_db_key_range.cc22
-rw-r--r--chromium/content/common/indexed_db/indexed_db_key_range.h17
-rw-r--r--chromium/content/common/indexed_db/indexed_db_messages.h81
-rw-r--r--chromium/content/common/indexed_db/indexed_db_param_traits.cc8
-rw-r--r--chromium/content/common/input/gesture_event_stream_validator.cc30
-rw-r--r--chromium/content/common/input/gesture_event_stream_validator.h6
-rw-r--r--chromium/content/common/input/gesture_event_stream_validator_unittest.cc30
-rw-r--r--chromium/content/common/input/input_event_stream_validator.cc7
-rw-r--r--chromium/content/common/input/input_event_stream_validator.h6
-rw-r--r--chromium/content/common/input/input_param_traits.cc14
-rw-r--r--chromium/content/common/input/input_param_traits_unittest.cc17
-rw-r--r--chromium/content/common/input/synthetic_gesture_params.h1
-rw-r--r--chromium/content/common/input/synthetic_pinch_gesture_params.h6
-rw-r--r--chromium/content/common/input/synthetic_smooth_drag_gesture_params.cc43
-rw-r--r--chromium/content/common/input/synthetic_smooth_drag_gesture_params.h37
-rw-r--r--chromium/content/common/input/synthetic_smooth_scroll_gesture_params.cc2
-rw-r--r--chromium/content/common/input/synthetic_smooth_scroll_gesture_params.h10
-rw-r--r--chromium/content/common/input/synthetic_tap_gesture_params.h8
-rw-r--r--chromium/content/common/input/synthetic_web_input_event_builders.cc25
-rw-r--r--chromium/content/common/input/synthetic_web_input_event_builders.h8
-rw-r--r--chromium/content/common/input/touch_action.h16
-rw-r--r--chromium/content/common/input/touch_event_stream_validator.cc78
-rw-r--r--chromium/content/common/input/touch_event_stream_validator.h6
-rw-r--r--chromium/content/common/input/web_input_event_traits.cc28
-rw-r--r--chromium/content/common/input/web_input_event_traits_unittest.cc36
-rw-r--r--chromium/content/common/input_messages.h28
-rw-r--r--chromium/content/common/mac/attributed_string_coder.mm6
-rw-r--r--chromium/content/common/mac/font_descriptor.h4
-rw-r--r--chromium/content/common/mac/font_loader.h2
-rw-r--r--chromium/content/common/mac/font_loader.mm9
-rw-r--r--chromium/content/common/manifest_manager_messages.h8
-rw-r--r--chromium/content/common/media/OWNERS4
-rw-r--r--chromium/content/common/media/audio_messages.h16
-rw-r--r--chromium/content/common/media/cdm_messages.h104
-rw-r--r--chromium/content/common/media/cdm_messages_enums.h11
-rw-r--r--chromium/content/common/media/media_param_traits.cc24
-rw-r--r--chromium/content/common/media/media_player_messages_android.h16
-rw-r--r--chromium/content/common/media/media_stream_options.cc1
-rw-r--r--chromium/content/common/media/media_stream_options.h4
-rw-r--r--chromium/content/common/media/midi_messages.h37
-rw-r--r--chromium/content/common/media/video_capture.h2
-rw-r--r--chromium/content/common/media/video_capture_messages.h36
-rw-r--r--chromium/content/common/message_port_messages.h40
-rw-r--r--chromium/content/common/message_router.h3
-rw-r--r--chromium/content/common/mojo/DEPS3
-rw-r--r--chromium/content/common/mojo/channel_init.cc69
-rw-r--r--chromium/content/common/mojo/channel_init.h61
-rw-r--r--chromium/content/common/mojo/service_registry_impl.cc30
-rw-r--r--chromium/content/common/mojo/service_registry_impl.h21
-rw-r--r--chromium/content/common/navigation_params.cc124
-rw-r--r--chromium/content/common/navigation_params.h194
-rw-r--r--chromium/content/common/navigator_connect_messages.h32
-rw-r--r--chromium/content/common/origin_util.cc66
-rw-r--r--chromium/content/common/origin_util_unittest.cc51
-rw-r--r--chromium/content/common/p2p_messages.h12
-rw-r--r--chromium/content/common/p2p_socket_type.h10
-rw-r--r--chromium/content/common/page_state_serialization.cc32
-rw-r--r--chromium/content/common/page_state_serialization.h9
-rw-r--r--chromium/content/common/page_state_serialization_unittest.cc19
-rw-r--r--chromium/content/common/pepper_file_util.cc22
-rw-r--r--chromium/content/common/pepper_file_util.h9
-rw-r--r--chromium/content/common/pepper_plugin_list.cc19
-rw-r--r--chromium/content/common/pepper_renderer_instance_data.cc16
-rw-r--r--chromium/content/common/pepper_renderer_instance_data.h7
-rw-r--r--chromium/content/common/permission_service.mojom36
-rw-r--r--chromium/content/common/platform_notification_messages.h86
-rw-r--r--chromium/content/common/plugin_list.cc6
-rw-r--r--chromium/content/common/plugin_list.h14
-rw-r--r--chromium/content/common/plugin_list_unittest.cc2
-rw-r--r--chromium/content/common/plugin_process_messages.h2
-rw-r--r--chromium/content/common/presentation/OWNERS3
-rw-r--r--chromium/content/common/presentation/presentation_service.mojom115
-rw-r--r--chromium/content/common/process_type.cc2
-rw-r--r--chromium/content/common/push_messaging_messages.h97
-rw-r--r--chromium/content/common/quota_messages.h2
-rw-r--r--chromium/content/common/render_frame_setup.mojom7
-rw-r--r--chromium/content/common/resource_messages.cc4
-rw-r--r--chromium/content/common/resource_messages.h6
-rw-r--r--chromium/content/common/sandbox_init_mac.h2
-rw-r--r--chromium/content/common/sandbox_init_win.cc5
-rw-r--r--chromium/content/common/sandbox_linux/android/sandbox_bpf_base_policy_android.cc8
-rw-r--r--chromium/content/common/sandbox_linux/android/sandbox_bpf_base_policy_android.h4
-rw-r--r--chromium/content/common/sandbox_linux/bpf_cros_arm_gpu_policy_linux.cc63
-rw-r--r--chromium/content/common/sandbox_linux/bpf_cros_arm_gpu_policy_linux.h2
-rw-r--r--chromium/content/common/sandbox_linux/bpf_gpu_policy_linux.cc139
-rw-r--r--chromium/content/common/sandbox_linux/bpf_gpu_policy_linux.h17
-rw-r--r--chromium/content/common/sandbox_linux/bpf_ppapi_policy_linux.cc2
-rw-r--r--chromium/content/common/sandbox_linux/bpf_renderer_policy_linux.cc2
-rw-r--r--chromium/content/common/sandbox_linux/bpf_utility_policy_linux.cc2
-rw-r--r--chromium/content/common/sandbox_linux/sandbox_debug_handling_linux.cc79
-rw-r--r--chromium/content/common/sandbox_linux/sandbox_debug_handling_linux.h25
-rw-r--r--chromium/content/common/sandbox_linux/sandbox_init_linux.cc9
-rw-r--r--chromium/content/common/sandbox_linux/sandbox_linux.cc166
-rw-r--r--chromium/content/common/sandbox_linux/sandbox_linux.h52
-rw-r--r--chromium/content/common/sandbox_linux/sandbox_seccomp_bpf_linux.cc80
-rw-r--r--chromium/content/common/sandbox_linux/sandbox_seccomp_bpf_linux.h19
-rw-r--r--chromium/content/common/sandbox_mac.mm11
-rw-r--r--chromium/content/common/sandbox_mac_diraccess_unittest.mm8
-rw-r--r--chromium/content/common/sandbox_mac_system_access_unittest.mm2
-rw-r--r--chromium/content/common/sandbox_mac_unittest_helper.mm8
-rw-r--r--chromium/content/common/sandbox_win.cc118
-rw-r--r--chromium/content/common/screen_orientation_messages.h10
-rw-r--r--chromium/content/common/send_zygote_child_ping_linux.cc21
-rw-r--r--chromium/content/common/service_worker/embedded_worker_messages.h7
-rw-r--r--chromium/content/common/service_worker/service_worker_client_info.cc44
-rw-r--r--chromium/content/common/service_worker/service_worker_client_info.h45
-rw-r--r--chromium/content/common/service_worker/service_worker_messages.h298
-rw-r--r--chromium/content/common/service_worker/service_worker_status_code.cc13
-rw-r--r--chromium/content/common/service_worker/service_worker_status_code.h19
-rw-r--r--chromium/content/common/service_worker/service_worker_types.cc30
-rw-r--r--chromium/content/common/service_worker/service_worker_types.h75
-rw-r--r--chromium/content/common/set_process_title.cc3
-rw-r--r--chromium/content/common/shareable_file_reference_unittest.cc61
-rw-r--r--chromium/content/common/speech_recognition_messages.h2
-rw-r--r--chromium/content/common/ssl_status_serialization.cc13
-rw-r--r--chromium/content/common/swapped_out_messages.cc6
-rw-r--r--chromium/content/common/text_input_client_messages.h2
-rw-r--r--chromium/content/common/user_agent.cc24
-rw-r--r--chromium/content/common/view_message_enums.h6
-rw-r--r--chromium/content/common/view_messages.h348
-rw-r--r--chromium/content/common/webplugin_geometry.h2
-rw-r--r--chromium/content/common/websocket.h2
-rw-r--r--chromium/content/common/websocket_messages.h122
-rw-r--r--chromium/content/content.gni6
-rw-r--r--chromium/content/content.gyp60
-rw-r--r--chromium/content/content_app.gypi20
-rw-r--r--chromium/content/content_browser.gypi512
-rw-r--r--chromium/content/content_browsertests.isolate61
-rw-r--r--chromium/content/content_child.gypi154
-rw-r--r--chromium/content/content_common.gypi253
-rw-r--r--chromium/content/content_common_mojo_bindings.gyp42
-rw-r--r--chromium/content/content_common_mojo_bindings.gypi32
-rw-r--r--chromium/content/content_gl_tests.isolate2
-rw-r--r--chromium/content/content_gpu.gypi10
-rw-r--r--chromium/content/content_jni.gypi5
-rw-r--r--chromium/content/content_nacl_nonsfi.gyp44
-rw-r--r--chromium/content/content_plugin.gypi3
-rw-r--r--chromium/content/content_ppapi_plugin.gypi2
-rw-r--r--chromium/content/content_renderer.gypi201
-rw-r--r--chromium/content/content_resources.grd15
-rw-r--r--chromium/content/content_shell.gypi113
-rw-r--r--chromium/content/content_shell_test_apk.isolate20
-rw-r--r--chromium/content/content_tests.gypi1489
-rw-r--r--chromium/content/content_unittests.isolate75
-rw-r--r--chromium/content/content_utility.gypi5
-rw-r--r--chromium/content/gpu/BUILD.gn26
-rw-r--r--chromium/content/gpu/gpu_child_thread.cc53
-rw-r--r--chromium/content/gpu/gpu_child_thread.h7
-rw-r--r--chromium/content/gpu/gpu_main.cc95
-rw-r--r--chromium/content/gpu/gpu_watchdog_thread.cc93
-rw-r--r--chromium/content/gpu/gpu_watchdog_thread.h23
-rw-r--r--chromium/content/gpu/in_process_gpu_thread.cc11
-rw-r--r--chromium/content/gpu/in_process_gpu_thread.h9
-rw-r--r--chromium/content/plugin/BUILD.gn4
-rw-r--r--chromium/content/plugin/plugin_channel.cc5
-rw-r--r--chromium/content/plugin/plugin_main.cc6
-rw-r--r--chromium/content/plugin/plugin_thread.cc11
-rw-r--r--chromium/content/plugin/plugin_thread.h4
-rw-r--r--chromium/content/plugin/webplugin_accelerated_surface_proxy_mac.cc2
-rw-r--r--chromium/content/plugin/webplugin_accelerated_surface_proxy_mac.h6
-rw-r--r--chromium/content/plugin/webplugin_delegate_stub.cc5
-rw-r--r--chromium/content/plugin/webplugin_delegate_stub.h2
-rw-r--r--chromium/content/plugin/webplugin_proxy.cc4
-rw-r--r--chromium/content/plugin/webplugin_proxy.h13
-rw-r--r--chromium/content/ppapi_plugin/BUILD.gn20
-rw-r--r--chromium/content/ppapi_plugin/broker_process_dispatcher.cc6
-rw-r--r--chromium/content/ppapi_plugin/ppapi_blink_platform_impl.cc50
-rw-r--r--chromium/content/ppapi_plugin/ppapi_blink_platform_impl.h2
-rw-r--r--chromium/content/ppapi_plugin/ppapi_broker_main.cc7
-rw-r--r--chromium/content/ppapi_plugin/ppapi_plugin_main.cc8
-rw-r--r--chromium/content/ppapi_plugin/ppapi_thread.cc46
-rw-r--r--chromium/content/ppapi_plugin/ppapi_thread.h14
-rw-r--r--chromium/content/public/android/BUILD.gn51
-rw-r--r--chromium/content/public/android/DEPS2
-rw-r--r--chromium/content/public/android/OWNERS1
-rw-r--r--chromium/content/public/app/BUILD.gn61
-rw-r--r--chromium/content/public/app/android_library_loader_hooks.h28
-rw-r--r--chromium/content/public/app/content_main_delegate.cc4
-rw-r--r--chromium/content/public/app/content_main_delegate.h10
-rw-r--r--chromium/content/public/browser/BUILD.gn14
-rw-r--r--chromium/content/public/browser/android/OWNERS2
-rw-r--r--chromium/content/public/browser/android/browser_media_player_manager.cc17
-rw-r--r--chromium/content/public/browser/android/browser_media_player_manager.h22
-rw-r--r--chromium/content/public/browser/android/compositor.h22
-rw-r--r--chromium/content/public/browser/android/compositor_client.h3
-rw-r--r--chromium/content/public/browser/android/content_protocol_handler.h32
-rw-r--r--chromium/content/public/browser/android/content_view_core.h11
-rw-r--r--chromium/content/public/browser/android/content_view_layer_renderer.h6
-rw-r--r--chromium/content/public/browser/android/devtools_auth.h6
-rw-r--r--chromium/content/public/browser/android/external_video_surface_container.h8
-rw-r--r--chromium/content/public/browser/android/layer_tree_build_helper.h31
-rw-r--r--chromium/content/public/browser/android/synchronous_compositor.h28
-rw-r--r--chromium/content/public/browser/android/synchronous_compositor_client.h9
-rw-r--r--chromium/content/public/browser/android/ui_resource_client_android.h30
-rw-r--r--chromium/content/public/browser/android/ui_resource_provider.h29
-rw-r--r--chromium/content/public/browser/browser_child_process_host.h7
-rw-r--r--chromium/content/public/browser/browser_child_process_observer.h4
-rw-r--r--chromium/content/public/browser/browser_context.h36
-rw-r--r--chromium/content/public/browser/browser_message_filter.cc45
-rw-r--r--chromium/content/public/browser/browser_message_filter.h13
-rw-r--r--chromium/content/public/browser/browser_plugin_guest_delegate.cc18
-rw-r--r--chromium/content/public/browser/browser_plugin_guest_delegate.h45
-rw-r--r--chromium/content/public/browser/browser_plugin_guest_manager.cc9
-rw-r--r--chromium/content/public/browser/browser_plugin_guest_manager.h10
-rw-r--r--chromium/content/public/browser/browser_ppapi_host.h4
-rw-r--r--chromium/content/public/browser/browser_thread.h16
-rw-r--r--chromium/content/public/browser/browser_url_handler.h5
-rw-r--r--chromium/content/public/browser/cert_store.h2
-rw-r--r--chromium/content/public/browser/child_process_data.h10
-rw-r--r--chromium/content/public/browser/child_process_security_policy.h3
-rw-r--r--chromium/content/public/browser/client_certificate_delegate.h35
-rw-r--r--chromium/content/public/browser/content_browser_client.cc103
-rw-r--r--chromium/content/public/browser/content_browser_client.h163
-rw-r--r--chromium/content/public/browser/cookie_crypto_delegate.h22
-rw-r--r--chromium/content/public/browser/cookie_store_factory.h10
-rw-r--r--chromium/content/public/browser/desktop_media_id.cc2
-rw-r--r--chromium/content/public/browser/desktop_notification_delegate.h2
-rw-r--r--chromium/content/public/browser/devtools_agent_host.h40
-rw-r--r--chromium/content/public/browser/devtools_frontend_host.h15
-rw-r--r--chromium/content/public/browser/devtools_http_handler.h88
-rw-r--r--chromium/content/public/browser/devtools_http_handler_delegate.h42
-rw-r--r--chromium/content/public/browser/devtools_manager_delegate.h22
-rwxr-xr-xchromium/content/public/browser/devtools_protocol_constants_generator.py211
-rw-r--r--chromium/content/public/browser/devtools_target.h67
-rw-r--r--chromium/content/public/browser/download_manager.h2
-rw-r--r--chromium/content/public/browser/download_url_parameters.cc4
-rw-r--r--chromium/content/public/browser/download_url_parameters.h10
-rw-r--r--chromium/content/public/browser/file_descriptor_info.h5
-rw-r--r--chromium/content/public/browser/focused_node_details.h19
-rw-r--r--chromium/content/public/browser/gpu_data_manager.h6
-rw-r--r--chromium/content/public/browser/guest_host.h37
-rw-r--r--chromium/content/public/browser/host_zoom_map.h34
-rw-r--r--chromium/content/public/browser/indexed_db_context.h5
-rw-r--r--chromium/content/public/browser/indexed_db_info.cc6
-rw-r--r--chromium/content/public/browser/indexed_db_info.h7
-rw-r--r--chromium/content/public/browser/interstitial_page.h7
-rw-r--r--chromium/content/public/browser/interstitial_page_delegate.cc13
-rw-r--r--chromium/content/public/browser/interstitial_page_delegate.h8
-rw-r--r--chromium/content/public/browser/invalidate_type.h5
-rw-r--r--chromium/content/public/browser/javascript_dialog_manager.h5
-rw-r--r--chromium/content/public/browser/message_port_delegate.h44
-rw-r--r--chromium/content/public/browser/message_port_provider.h83
-rw-r--r--chromium/content/public/browser/native_web_keyboard_event.h33
-rw-r--r--chromium/content/public/browser/navigation_controller.cc13
-rw-r--r--chromium/content/public/browser/navigation_controller.h34
-rw-r--r--chromium/content/public/browser/navigation_details.cc2
-rw-r--r--chromium/content/public/browser/navigation_entry.h11
-rw-r--r--chromium/content/public/browser/navigation_type.h18
-rw-r--r--chromium/content/public/browser/navigator_connect_context.h36
-rw-r--r--chromium/content/public/browser/navigator_connect_service_factory.h49
-rw-r--r--chromium/content/public/browser/notification_database_data.h34
-rw-r--r--chromium/content/public/browser/notification_details.h2
-rw-r--r--chromium/content/public/browser/notification_event_dispatcher.h49
-rw-r--r--chromium/content/public/browser/notification_registrar.cc8
-rw-r--r--chromium/content/public/browser/notification_service.h10
-rw-r--r--chromium/content/public/browser/notification_types.h7
-rw-r--r--chromium/content/public/browser/page_navigator.cc2
-rw-r--r--chromium/content/public/browser/page_navigator.h11
-rw-r--r--chromium/content/public/browser/permission_manager.h61
-rw-r--r--chromium/content/public/browser/permission_type.h16
-rw-r--r--chromium/content/public/browser/platform_notification_context.h80
-rw-r--r--chromium/content/public/browser/platform_notification_service.h87
-rw-r--r--chromium/content/public/browser/plugin_data_remover.h4
-rw-r--r--chromium/content/public/browser/plugin_service.h13
-rw-r--r--chromium/content/public/browser/plugin_service_filter.h11
-rw-r--r--chromium/content/public/browser/power_save_blocker.h17
-rw-r--r--chromium/content/public/browser/power_usage_monitor.h17
-rw-r--r--chromium/content/public/browser/presentation_screen_availability_listener.h34
-rw-r--r--chromium/content/public/browser/presentation_service_delegate.h163
-rw-r--r--chromium/content/public/browser/presentation_session.cc30
-rw-r--r--chromium/content/public/browser/presentation_session.h45
-rw-r--r--chromium/content/public/browser/presentation_session_message.cc56
-rw-r--r--chromium/content/public/browser/presentation_session_message.h52
-rw-r--r--chromium/content/public/browser/profiler_controller.h13
-rw-r--r--chromium/content/public/browser/profiler_subscriber.h3
-rw-r--r--chromium/content/public/browser/push_messaging_service.cc160
-rw-r--r--chromium/content/public/browser/push_messaging_service.h108
-rw-r--r--chromium/content/public/browser/readback_types.h32
-rw-r--r--chromium/content/public/browser/render_frame_host.h31
-rw-r--r--chromium/content/public/browser/render_process_host.h83
-rw-r--r--chromium/content/public/browser/render_view_host.h38
-rw-r--r--chromium/content/public/browser/render_widget_host.h24
-rw-r--r--chromium/content/public/browser/render_widget_host_iterator.h2
-rw-r--r--chromium/content/public/browser/render_widget_host_view.h14
-rw-r--r--chromium/content/public/browser/render_widget_host_view_frame_subscriber.h6
-rw-r--r--chromium/content/public/browser/resource_context.h8
-rw-r--r--chromium/content/public/browser/resource_dispatcher_host.h1
-rw-r--r--chromium/content/public/browser/resource_dispatcher_host_delegate.cc12
-rw-r--r--chromium/content/public/browser/resource_dispatcher_host_delegate.h6
-rw-r--r--chromium/content/public/browser/resource_request_info.h5
-rw-r--r--chromium/content/public/browser/resource_throttle.h21
-rw-r--r--chromium/content/public/browser/screen_orientation_delegate.h7
-rw-r--r--chromium/content/public/browser/screen_orientation_dispatcher_host.h2
-rw-r--r--chromium/content/public/browser/screen_orientation_provider.cc6
-rw-r--r--chromium/content/public/browser/screen_orientation_provider.h2
-rw-r--r--chromium/content/public/browser/service_worker_context.h30
-rw-r--r--chromium/content/public/browser/session_storage_namespace.h43
-rw-r--r--chromium/content/public/browser/signed_certificate_timestamp_store.h2
-rw-r--r--chromium/content/public/browser/site_instance.h3
-rw-r--r--chromium/content/public/browser/speech_recognition_manager_delegate.h4
-rw-r--r--chromium/content/public/browser/speech_recognition_session_config.h6
-rw-r--r--chromium/content/public/browser/speech_recognition_session_context.h2
-rw-r--r--chromium/content/public/browser/speech_recognition_session_preamble.cc17
-rw-r--r--chromium/content/public/browser/speech_recognition_session_preamble.h38
-rw-r--r--chromium/content/public/browser/ssl_host_state_delegate.h10
-rw-r--r--chromium/content/public/browser/storage_partition.h18
-rw-r--r--chromium/content/public/browser/trace_uploader.h34
-rw-r--r--chromium/content/public/browser/tracing_controller.h46
-rw-r--r--chromium/content/public/browser/tracing_delegate.h30
-rw-r--r--chromium/content/public/browser/url_data_source.h10
-rw-r--r--chromium/content/public/browser/utility_process_host.h14
-rw-r--r--chromium/content/public/browser/vibration_provider.h23
-rw-r--r--chromium/content/public/browser/web_contents.cc16
-rw-r--r--chromium/content/public/browser/web_contents.h78
-rw-r--r--chromium/content/public/browser/web_contents_delegate.cc35
-rw-r--r--chromium/content/public/browser/web_contents_delegate.h89
-rw-r--r--chromium/content/public/browser/web_contents_observer.cc6
-rw-r--r--chromium/content/public/browser/web_contents_observer.h116
-rw-r--r--chromium/content/public/browser/web_contents_user_data.h2
-rw-r--r--chromium/content/public/browser/web_contents_view_delegate.cc8
-rw-r--r--chromium/content/public/browser/web_contents_view_delegate.h4
-rw-r--r--chromium/content/public/browser/web_ui_controller_factory.h6
-rw-r--r--chromium/content/public/browser/web_ui_message_handler.h2
-rw-r--r--chromium/content/public/browser/worker_service.h2
-rw-r--r--chromium/content/public/browser/zoom_level_delegate.h21
-rw-r--r--chromium/content/public/child/BUILD.gn24
-rw-r--r--chromium/content/public/child/DEPS3
-rw-r--r--chromium/content/public/child/child_thread.h37
-rw-r--r--chromium/content/public/child/image_decoder_utils.h11
-rw-r--r--chromium/content/public/child/v8_value_converter.h127
-rw-r--r--chromium/content/public/common/BUILD.gn20
-rw-r--r--chromium/content/public/common/OWNERS4
-rw-r--r--chromium/content/public/common/background_sync.mojom33
-rw-r--r--chromium/content/public/common/child_process_host.h8
-rw-r--r--chromium/content/public/common/child_process_host_delegate.h4
-rw-r--r--chromium/content/public/common/child_process_sandbox_support_linux.h4
-rw-r--r--chromium/content/public/common/common_param_traits.cc6
-rw-r--r--chromium/content/public/common/common_param_traits.h4
-rw-r--r--chromium/content/public/common/common_param_traits_macros.h30
-rw-r--r--chromium/content/public/common/console_message_level.h2
-rw-r--r--chromium/content/public/common/content_client.cc1
-rw-r--r--chromium/content/public/common/content_client.h7
-rw-r--r--chromium/content/public/common/content_descriptors.h9
-rw-r--r--chromium/content/public/common/content_switches.cc347
-rw-r--r--chromium/content/public/common/content_switches.h103
-rw-r--r--chromium/content/public/common/context_menu_params.h2
-rw-r--r--chromium/content/public/common/dwrite_font_platform_win.h41
-rw-r--r--chromium/content/public/common/favicon_url.h6
-rw-r--r--chromium/content/public/common/frame_navigate_params.cc1
-rw-r--r--chromium/content/public/common/frame_navigate_params.h6
-rw-r--r--chromium/content/public/common/geoposition.h2
-rw-r--r--chromium/content/public/common/injection_test_win.h6
-rw-r--r--chromium/content/public/common/manifest.cc15
-rw-r--r--chromium/content/public/common/manifest.h35
-rw-r--r--chromium/content/public/common/media_stream_request.cc5
-rw-r--r--chromium/content/public/common/media_stream_request.h10
-rw-r--r--chromium/content/public/common/menu_item.cc1
-rw-r--r--chromium/content/public/common/menu_item.h1
-rw-r--r--chromium/content/public/common/message_port_types.cc46
-rw-r--r--chromium/content/public/common/message_port_types.h48
-rw-r--r--chromium/content/public/common/mojo_channel_switches.cc37
-rw-r--r--chromium/content/public/common/mojo_channel_switches.h23
-rw-r--r--chromium/content/public/common/navigator_connect_client.cc21
-rw-r--r--chromium/content/public/common/navigator_connect_client.h33
-rw-r--r--chromium/content/public/common/origin_util.h26
-rw-r--r--chromium/content/public/common/pepper_plugin_info.cc5
-rw-r--r--chromium/content/public/common/pepper_plugin_info.h4
-rw-r--r--chromium/content/public/common/permission_status.mojom11
-rw-r--r--chromium/content/public/common/persistent_notification_status.h32
-rw-r--r--chromium/content/public/common/platform_notification_data.cc13
-rw-r--r--chromium/content/public/common/platform_notification_data.h69
-rw-r--r--chromium/content/public/common/presentation_constants.cc11
-rw-r--r--chromium/content/public/common/presentation_constants.h19
-rw-r--r--chromium/content/public/common/push_messaging_status.cc50
-rw-r--r--chromium/content/public/common/push_messaging_status.h150
-rw-r--r--chromium/content/public/common/referrer.cc61
-rw-r--r--chromium/content/public/common/referrer.h39
-rw-r--r--chromium/content/public/common/renderer_preferences.cc17
-rw-r--r--chromium/content/public/common/renderer_preferences.h45
-rw-r--r--chromium/content/public/common/resource_devtools_info.h6
-rw-r--r--chromium/content/public/common/resource_response.cc2
-rw-r--r--chromium/content/public/common/resource_type.h38
-rw-r--r--chromium/content/public/common/sandbox_init.h14
-rw-r--r--chromium/content/public/common/sandbox_linux.h10
-rw-r--r--chromium/content/public/common/send_zygote_child_ping_linux.h18
-rw-r--r--chromium/content/public/common/service_registry.h11
-rw-r--r--chromium/content/public/common/show_desktop_notification_params.cc16
-rw-r--r--chromium/content/public/common/show_desktop_notification_params.h39
-rw-r--r--chromium/content/public/common/socket_permission_request.h6
-rw-r--r--chromium/content/public/common/speech_recognition_error.h19
-rw-r--r--chromium/content/public/common/top_controls_state.h2
-rw-r--r--chromium/content/public/common/transition_element.h2
-rw-r--r--chromium/content/public/common/url_constants.cc1
-rw-r--r--chromium/content/public/common/url_constants.h1
-rw-r--r--chromium/content/public/common/url_utils.cc2
-rw-r--r--chromium/content/public/common/user_agent.h6
-rw-r--r--chromium/content/public/common/web_preferences.cc121
-rw-r--r--chromium/content/public/common/web_preferences.h57
-rw-r--r--chromium/content/public/common/webplugininfo.h6
-rw-r--r--chromium/content/public/common/window_container_type.h2
-rw-r--r--chromium/content/public/plugin/BUILD.gn8
-rw-r--r--chromium/content/public/renderer/BUILD.gn30
-rw-r--r--chromium/content/public/renderer/DEPS4
-rw-r--r--chromium/content/public/renderer/browser_plugin_delegate.cc20
-rw-r--r--chromium/content/public/renderer/browser_plugin_delegate.h21
-rw-r--r--chromium/content/public/renderer/content_renderer_client.cc29
-rw-r--r--chromium/content/public/renderer/content_renderer_client.h55
-rw-r--r--chromium/content/public/renderer/document_state.h4
-rw-r--r--chromium/content/public/renderer/isolated_world_ids.h23
-rw-r--r--chromium/content/public/renderer/media_stream_api.cc121
-rw-r--r--chromium/content/public/renderer/media_stream_api.h41
-rw-r--r--chromium/content/public/renderer/media_stream_audio_sink.cc13
-rw-r--r--chromium/content/public/renderer/media_stream_audio_sink.h36
-rw-r--r--chromium/content/public/renderer/media_stream_video_sink.h22
-rw-r--r--chromium/content/public/renderer/navigation_state.cc18
-rw-r--r--chromium/content/public/renderer/navigation_state.h119
-rw-r--r--chromium/content/public/renderer/platform_event_observer.h10
-rw-r--r--chromium/content/public/renderer/plugin_instance_throttler.h108
-rw-r--r--chromium/content/public/renderer/render_frame.h32
-rw-r--r--chromium/content/public/renderer/render_frame_observer.h30
-rw-r--r--chromium/content/public/renderer/render_frame_observer_tracker.h12
-rw-r--r--chromium/content/public/renderer/render_process_observer.h2
-rw-r--r--chromium/content/public/renderer/render_thread.h25
-rw-r--r--chromium/content/public/renderer/render_view.h15
-rw-r--r--chromium/content/public/renderer/render_view_observer.h17
-rw-r--r--chromium/content/public/renderer/render_view_observer_tracker.h11
-rw-r--r--chromium/content/public/renderer/renderer_gamepad_provider.h2
-rw-r--r--chromium/content/public/renderer/resource_fetcher.h10
-rw-r--r--chromium/content/public/renderer/v8_value_converter.h127
-rw-r--r--chromium/content/public/renderer/video_encode_accelerator.cc6
-rw-r--r--chromium/content/public/renderer/video_encode_accelerator.h4
-rw-r--r--chromium/content/public/renderer/webrtc_log_message_delegate.h6
-rw-r--r--chromium/content/public/utility/BUILD.gn9
-rw-r--r--chromium/content/public/utility/DEPS3
-rw-r--r--chromium/content/public/utility/content_utility_client.h5
-rw-r--r--chromium/content/public/utility/utility_thread.h18
-rw-r--r--chromium/content/renderer/BUILD.gn66
-rw-r--r--chromium/content/renderer/DEPS6
-rw-r--r--chromium/content/renderer/OWNERS2
-rw-r--r--chromium/content/renderer/accessibility/blink_ax_enum_conversion.cc116
-rw-r--r--chromium/content/renderer/accessibility/blink_ax_enum_conversion.h12
-rw-r--r--chromium/content/renderer/accessibility/blink_ax_tree_source.cc119
-rw-r--r--chromium/content/renderer/accessibility/blink_ax_tree_source.h6
-rw-r--r--chromium/content/renderer/accessibility/renderer_accessibility.cc34
-rw-r--r--chromium/content/renderer/accessibility/renderer_accessibility.h7
-rw-r--r--chromium/content/renderer/accessibility/renderer_accessibility_browsertest.cc34
-rw-r--r--chromium/content/renderer/active_notification_tracker.cc67
-rw-r--r--chromium/content/renderer/active_notification_tracker.h47
-rw-r--r--chromium/content/renderer/active_notification_tracker_unittest.cc29
-rw-r--r--chromium/content/renderer/android/address_detector.h16
-rw-r--r--chromium/content/renderer/android/email_detector.h14
-rw-r--r--chromium/content/renderer/android/phone_number_detector.cc6
-rw-r--r--chromium/content/renderer/android/phone_number_detector.h16
-rw-r--r--chromium/content/renderer/android/phone_number_detector_unittest.cc13
-rw-r--r--chromium/content/renderer/android/renderer_date_time_picker.h4
-rw-r--r--chromium/content/renderer/android/synchronous_compositor_factory.cc3
-rw-r--r--chromium/content/renderer/android/synchronous_compositor_factory.h21
-rw-r--r--chromium/content/renderer/battery_status/battery_status_dispatcher.cc17
-rw-r--r--chromium/content/renderer/battery_status/battery_status_dispatcher.h13
-rw-r--r--chromium/content/renderer/battery_status/battery_status_dispatcher_unittest.cc68
-rw-r--r--chromium/content/renderer/browser_plugin/browser_plugin.cc321
-rw-r--r--chromium/content/renderer/browser_plugin/browser_plugin.h74
-rw-r--r--chromium/content/renderer/browser_plugin/browser_plugin_manager.cc64
-rw-r--r--chromium/content/renderer/browser_plugin/browser_plugin_manager.h52
-rw-r--r--chromium/content/renderer/browser_render_view_browsertest.cc2
-rw-r--r--chromium/content/renderer/cache_storage/OWNERS4
-rw-r--r--chromium/content/renderer/cache_storage/cache_storage_dispatcher.cc674
-rw-r--r--chromium/content/renderer/cache_storage/cache_storage_dispatcher.h223
-rw-r--r--chromium/content/renderer/cache_storage/cache_storage_message_filter.cc38
-rw-r--r--chromium/content/renderer/cache_storage/cache_storage_message_filter.h32
-rw-r--r--chromium/content/renderer/cache_storage/webserviceworkercachestorage_impl.cc63
-rw-r--r--chromium/content/renderer/cache_storage/webserviceworkercachestorage_impl.h58
-rw-r--r--chromium/content/renderer/child_frame_compositing_helper.cc19
-rw-r--r--chromium/content/renderer/child_frame_compositing_helper.h2
-rw-r--r--chromium/content/renderer/chrome_object_extensions_utils.cc10
-rw-r--r--chromium/content/renderer/chrome_object_extensions_utils.h4
-rw-r--r--chromium/content/renderer/clipboard_client.h81
-rw-r--r--chromium/content/renderer/clipboard_utils.h2
-rw-r--r--chromium/content/renderer/context_menu_params_builder.cc2
-rw-r--r--chromium/content/renderer/device_sensors/device_light_event_pump_unittest.cc2
-rw-r--r--chromium/content/renderer/device_sensors/device_motion_event_pump.cc2
-rw-r--r--chromium/content/renderer/device_sensors/device_motion_event_pump.h2
-rw-r--r--chromium/content/renderer/device_sensors/device_motion_event_pump_unittest.cc57
-rw-r--r--chromium/content/renderer/device_sensors/device_orientation_event_pump.cc2
-rw-r--r--chromium/content/renderer/device_sensors/device_orientation_event_pump.h2
-rw-r--r--chromium/content/renderer/device_sensors/device_orientation_event_pump_unittest.cc4
-rw-r--r--chromium/content/renderer/device_sensors/device_sensor_event_pump.h6
-rw-r--r--chromium/content/renderer/devtools/devtools_agent.cc242
-rw-r--r--chromium/content/renderer/devtools/devtools_agent.h96
-rw-r--r--chromium/content/renderer/devtools/devtools_agent_filter.cc19
-rw-r--r--chromium/content/renderer/devtools/devtools_agent_filter.h1
-rw-r--r--chromium/content/renderer/devtools/devtools_client.cc16
-rw-r--r--chromium/content/renderer/devtools/devtools_client.h10
-rw-r--r--chromium/content/renderer/devtools/lock_free_circular_queue.h135
-rw-r--r--chromium/content/renderer/devtools/v8_sampling_profiler.cc627
-rw-r--r--chromium/content/renderer/devtools/v8_sampling_profiler.h45
-rw-r--r--chromium/content/renderer/devtools/v8_sampling_profiler_browsertest.cc146
-rw-r--r--chromium/content/renderer/disambiguation_popup_helper.cc2
-rw-r--r--chromium/content/renderer/disambiguation_popup_helper_unittest.cc6
-rw-r--r--chromium/content/renderer/dom_automation_controller.cc6
-rw-r--r--chromium/content/renderer/dom_serializer_browsertest.cc5
-rw-r--r--chromium/content/renderer/dom_storage/dom_storage_cached_area.cc18
-rw-r--r--chromium/content/renderer/dom_storage/dom_storage_cached_area.h11
-rw-r--r--chromium/content/renderer/dom_storage/dom_storage_cached_area_unittest.cc6
-rw-r--r--chromium/content/renderer/dom_storage/dom_storage_dispatcher.cc38
-rw-r--r--chromium/content/renderer/dom_storage/dom_storage_dispatcher.h1
-rw-r--r--chromium/content/renderer/dom_storage/dom_storage_proxy.h5
-rw-r--r--chromium/content/renderer/external_popup_menu.cc2
-rw-r--r--chromium/content/renderer/external_popup_menu.h6
-rw-r--r--chromium/content/renderer/external_popup_menu_browsertest.cc18
-rw-r--r--chromium/content/renderer/fetchers/image_resource_fetcher.cc69
-rw-r--r--chromium/content/renderer/fetchers/image_resource_fetcher.h73
-rw-r--r--chromium/content/renderer/fetchers/manifest_fetcher.cc6
-rw-r--r--chromium/content/renderer/fetchers/manifest_fetcher.h2
-rw-r--r--chromium/content/renderer/fetchers/multi_resolution_image_resource_fetcher.cc22
-rw-r--r--chromium/content/renderer/fetchers/multi_resolution_image_resource_fetcher.h1
-rw-r--r--chromium/content/renderer/fetchers/resource_fetcher_impl.cc58
-rw-r--r--chromium/content/renderer/fetchers/resource_fetcher_impl.h14
-rw-r--r--chromium/content/renderer/fetchers/web_url_loader_client_impl.cc9
-rw-r--r--chromium/content/renderer/fetchers/web_url_loader_client_impl.h2
-rw-r--r--chromium/content/renderer/gamepad_shared_memory_reader.cc2
-rw-r--r--chromium/content/renderer/geolocation_dispatcher.cc62
-rw-r--r--chromium/content/renderer/geolocation_dispatcher.h14
-rw-r--r--chromium/content/renderer/gin_browsertest.cc2
-rw-r--r--chromium/content/renderer/gpu/OWNERS1
-rw-r--r--chromium/content/renderer/gpu/compositor_dependencies.h66
-rw-r--r--chromium/content/renderer/gpu/compositor_external_begin_frame_source.cc73
-rw-r--r--chromium/content/renderer/gpu/compositor_external_begin_frame_source.h78
-rw-r--r--chromium/content/renderer/gpu/compositor_forwarding_message_filter.cc79
-rw-r--r--chromium/content/renderer/gpu/compositor_forwarding_message_filter.h74
-rw-r--r--chromium/content/renderer/gpu/compositor_forwarding_message_filter_unittest.cc82
-rw-r--r--chromium/content/renderer/gpu/compositor_output_surface.cc64
-rw-r--r--chromium/content/renderer/gpu/compositor_output_surface.h20
-rw-r--r--chromium/content/renderer/gpu/compositor_software_output_device.cc233
-rw-r--r--chromium/content/renderer/gpu/compositor_software_output_device.h101
-rw-r--r--chromium/content/renderer/gpu/delegated_compositor_output_surface.cc2
-rw-r--r--chromium/content/renderer/gpu/delegated_compositor_output_surface.h2
-rw-r--r--chromium/content/renderer/gpu/frame_swap_message_queue.cc21
-rw-r--r--chromium/content/renderer/gpu/frame_swap_message_queue.h15
-rw-r--r--chromium/content/renderer/gpu/frame_swap_message_queue_unittest.cc53
-rw-r--r--chromium/content/renderer/gpu/gpu_benchmarking_extension.cc289
-rw-r--r--chromium/content/renderer/gpu/gpu_benchmarking_extension.h8
-rw-r--r--chromium/content/renderer/gpu/mailbox_output_surface.cc2
-rw-r--r--chromium/content/renderer/gpu/mailbox_output_surface.h4
-rw-r--r--chromium/content/renderer/gpu/queue_message_swap_promise.cc18
-rw-r--r--chromium/content/renderer/gpu/queue_message_swap_promise.h13
-rw-r--r--chromium/content/renderer/gpu/queue_message_swap_promise_unittest.cc111
-rw-r--r--chromium/content/renderer/gpu/render_widget_compositor.cc541
-rw-r--r--chromium/content/renderer/gpu/render_widget_compositor.h81
-rw-r--r--chromium/content/renderer/gpu/render_widget_compositor_unittest.cc248
-rw-r--r--chromium/content/renderer/gpu/stream_texture_host_android.cc4
-rw-r--r--chromium/content/renderer/gpu/stream_texture_host_android.h6
-rw-r--r--chromium/content/renderer/history_controller.cc69
-rw-r--r--chromium/content/renderer/history_controller.h11
-rw-r--r--chromium/content/renderer/history_entry.cc5
-rw-r--r--chromium/content/renderer/history_serialization.cc24
-rw-r--r--chromium/content/renderer/image_loading_helper.cc34
-rw-r--r--chromium/content/renderer/image_loading_helper.h6
-rw-r--r--chromium/content/renderer/ime_event_guard.h6
-rw-r--r--chromium/content/renderer/in_process_renderer_thread.cc12
-rw-r--r--chromium/content/renderer/in_process_renderer_thread.h7
-rw-r--r--chromium/content/renderer/input/input_event_filter.cc35
-rw-r--r--chromium/content/renderer/input/input_event_filter.h10
-rw-r--r--chromium/content/renderer/input/input_event_filter_unittest.cc23
-rw-r--r--chromium/content/renderer/input/input_handler_manager.cc59
-rw-r--r--chromium/content/renderer/input/input_handler_manager.h32
-rw-r--r--chromium/content/renderer/input/input_handler_manager_client.h4
-rw-r--r--chromium/content/renderer/input/input_handler_proxy.cc484
-rw-r--r--chromium/content/renderer/input/input_handler_proxy.h25
-rw-r--r--chromium/content/renderer/input/input_handler_proxy_client.h2
-rw-r--r--chromium/content/renderer/input/input_handler_proxy_unittest.cc258
-rw-r--r--chromium/content/renderer/input/input_handler_wrapper.cc4
-rw-r--r--chromium/content/renderer/input/input_handler_wrapper.h2
-rw-r--r--chromium/content/renderer/input/input_scroll_elasticity_controller.cc661
-rw-r--r--chromium/content/renderer/input/input_scroll_elasticity_controller.h189
-rw-r--r--chromium/content/renderer/input/input_scroll_elasticity_controller_unittest.cc387
-rw-r--r--chromium/content/renderer/input/main_thread_input_event_filter.cc40
-rw-r--r--chromium/content/renderer/input/main_thread_input_event_filter.h45
-rw-r--r--chromium/content/renderer/java/gin_java_bridge_dispatcher.cc31
-rw-r--r--chromium/content/renderer/java/gin_java_bridge_dispatcher.h8
-rw-r--r--chromium/content/renderer/java/gin_java_bridge_object.cc103
-rw-r--r--chromium/content/renderer/java/gin_java_bridge_object.h20
-rw-r--r--chromium/content/renderer/java/gin_java_bridge_value_converter.cc31
-rw-r--r--chromium/content/renderer/java/gin_java_bridge_value_converter.h32
-rw-r--r--chromium/content/renderer/java/gin_java_bridge_value_converter_unittest.cc24
-rw-r--r--chromium/content/renderer/java/gin_java_function_invocation_helper.cc109
-rw-r--r--chromium/content/renderer/java/gin_java_function_invocation_helper.h37
-rw-r--r--chromium/content/renderer/manifest/manifest_manager.cc49
-rw-r--r--chromium/content/renderer/manifest/manifest_manager.h4
-rw-r--r--chromium/content/renderer/manifest/manifest_parser.cc438
-rw-r--r--chromium/content/renderer/manifest/manifest_parser.h161
-rw-r--r--chromium/content/renderer/manifest/manifest_parser_unittest.cc493
-rw-r--r--chromium/content/renderer/manifest/manifest_uma_util.h2
-rw-r--r--chromium/content/renderer/media/DEPS6
-rw-r--r--chromium/content/renderer/media/OWNERS15
-rw-r--r--chromium/content/renderer/media/android/audio_decoder_android.cc8
-rw-r--r--chromium/content/renderer/media/android/media_source_delegate.cc55
-rw-r--r--chromium/content/renderer/media/android/media_source_delegate.h35
-rw-r--r--chromium/content/renderer/media/android/renderer_demuxer_android.h4
-rw-r--r--chromium/content/renderer/media/android/renderer_media_player_manager.cc52
-rw-r--r--chromium/content/renderer/media/android/renderer_media_player_manager.h30
-rw-r--r--chromium/content/renderer/media/android/stream_texture_factory.h2
-rw-r--r--chromium/content/renderer/media/android/stream_texture_factory_impl.cc16
-rw-r--r--chromium/content/renderer/media/android/stream_texture_factory_impl.h22
-rw-r--r--chromium/content/renderer/media/android/stream_texture_factory_synchronous_impl.cc10
-rw-r--r--chromium/content/renderer/media/android/stream_texture_factory_synchronous_impl.h22
-rw-r--r--chromium/content/renderer/media/android/webmediaplayer_android.cc475
-rw-r--r--chromium/content/renderer/media/android/webmediaplayer_android.h99
-rw-r--r--chromium/content/renderer/media/audio_device_factory.cc13
-rw-r--r--chromium/content/renderer/media/audio_device_factory.h16
-rw-r--r--chromium/content/renderer/media/audio_input_message_filter.cc22
-rw-r--r--chromium/content/renderer/media/audio_input_message_filter.h8
-rw-r--r--chromium/content/renderer/media/audio_message_filter.cc56
-rw-r--r--chromium/content/renderer/media/audio_message_filter.h25
-rw-r--r--chromium/content/renderer/media/audio_message_filter_unittest.cc7
-rw-r--r--chromium/content/renderer/media/audio_renderer_mixer_manager.cc24
-rw-r--r--chromium/content/renderer/media/audio_renderer_mixer_manager.h15
-rw-r--r--chromium/content/renderer/media/audio_renderer_mixer_manager_unittest.cc38
-rw-r--r--chromium/content/renderer/media/cdm_session_adapter.cc199
-rw-r--r--chromium/content/renderer/media/cdm_session_adapter.h150
-rw-r--r--chromium/content/renderer/media/crypto/cdm_initialized_promise.cc30
-rw-r--r--chromium/content/renderer/media/crypto/cdm_initialized_promise.h39
-rw-r--r--chromium/content/renderer/media/crypto/encrypted_media_player_support_impl.cc475
-rw-r--r--chromium/content/renderer/media/crypto/encrypted_media_player_support_impl.h130
-rw-r--r--chromium/content/renderer/media/crypto/key_systems.cc650
-rw-r--r--chromium/content/renderer/media/crypto/key_systems.h80
-rw-r--r--chromium/content/renderer/media/crypto/key_systems_support_uma.cc136
-rw-r--r--chromium/content/renderer/media/crypto/key_systems_support_uma.h57
-rw-r--r--chromium/content/renderer/media/crypto/key_systems_unittest.cc649
-rw-r--r--chromium/content/renderer/media/crypto/ppapi_decryptor.cc177
-rw-r--r--chromium/content/renderer/media/crypto/ppapi_decryptor.h84
-rw-r--r--chromium/content/renderer/media/crypto/proxy_decryptor.cc312
-rw-r--r--chromium/content/renderer/media/crypto/proxy_decryptor.h131
-rw-r--r--chromium/content/renderer/media/crypto/proxy_media_keys.cc326
-rw-r--r--chromium/content/renderer/media/crypto/proxy_media_keys.h149
-rw-r--r--chromium/content/renderer/media/crypto/render_cdm_factory.cc104
-rw-r--r--chromium/content/renderer/media/crypto/render_cdm_factory.h31
-rw-r--r--chromium/content/renderer/media/crypto/renderer_cdm_manager.cc163
-rw-r--r--chromium/content/renderer/media/crypto/renderer_cdm_manager.h65
-rw-r--r--chromium/content/renderer/media/media_permission_dispatcher.cc96
-rw-r--r--chromium/content/renderer/media/media_permission_dispatcher.h53
-rw-r--r--chromium/content/renderer/media/media_renderer_service_provider.cc23
-rw-r--r--chromium/content/renderer/media/media_renderer_service_provider.h35
-rw-r--r--chromium/content/renderer/media/media_stream_audio_level_calculator.cc39
-rw-r--r--chromium/content/renderer/media/media_stream_audio_level_calculator.h23
-rw-r--r--chromium/content/renderer/media/media_stream_audio_processor.cc201
-rw-r--r--chromium/content/renderer/media/media_stream_audio_processor.h41
-rw-r--r--chromium/content/renderer/media/media_stream_audio_processor_options.cc132
-rw-r--r--chromium/content/renderer/media/media_stream_audio_processor_options.h34
-rw-r--r--chromium/content/renderer/media/media_stream_audio_processor_unittest.cc132
-rw-r--r--chromium/content/renderer/media/media_stream_audio_sink_owner.cc29
-rw-r--r--chromium/content/renderer/media/media_stream_audio_sink_owner.h12
-rw-r--r--chromium/content/renderer/media/media_stream_audio_source.cc23
-rw-r--r--chromium/content/renderer/media/media_stream_audio_source.h2
-rw-r--r--chromium/content/renderer/media/media_stream_audio_track_sink.h29
-rw-r--r--chromium/content/renderer/media/media_stream_center.h29
-rw-r--r--chromium/content/renderer/media/media_stream_renderer_factory.cc18
-rw-r--r--chromium/content/renderer/media/media_stream_renderer_factory.h1
-rw-r--r--chromium/content/renderer/media/media_stream_track.h7
-rw-r--r--chromium/content/renderer/media/media_stream_video_capture_source_unittest.cc184
-rw-r--r--chromium/content/renderer/media/media_stream_video_capturer_source.cc233
-rw-r--r--chromium/content/renderer/media/media_stream_video_capturer_source.h57
-rw-r--r--chromium/content/renderer/media/media_stream_video_source.cc74
-rw-r--r--chromium/content/renderer/media/media_stream_video_source.h42
-rw-r--r--chromium/content/renderer/media/media_stream_video_source_unittest.cc3
-rw-r--r--chromium/content/renderer/media/media_stream_video_track.cc93
-rw-r--r--chromium/content/renderer/media/media_stream_video_track.h8
-rw-r--r--chromium/content/renderer/media/media_stream_video_track_unittest.cc6
-rw-r--r--chromium/content/renderer/media/midi_dispatcher.cc44
-rw-r--r--chromium/content/renderer/media/midi_dispatcher.h13
-rw-r--r--chromium/content/renderer/media/midi_message_filter.cc102
-rw-r--r--chromium/content/renderer/media/midi_message_filter.h40
-rw-r--r--chromium/content/renderer/media/midi_message_filter_unittest.cc34
-rw-r--r--chromium/content/renderer/media/mock_data_channel_impl.cc74
-rw-r--r--chromium/content/renderer/media/mock_data_channel_impl.h52
-rw-r--r--chromium/content/renderer/media/mock_media_constraint_factory.h6
-rw-r--r--chromium/content/renderer/media/mock_media_stream_registry.cc3
-rw-r--r--chromium/content/renderer/media/mock_media_stream_video_sink.cc1
-rw-r--r--chromium/content/renderer/media/mock_media_stream_video_sink.h14
-rw-r--r--chromium/content/renderer/media/mock_media_stream_video_source.cc13
-rw-r--r--chromium/content/renderer/media/mock_media_stream_video_source.h14
-rw-r--r--chromium/content/renderer/media/mock_peer_connection_impl.cc86
-rw-r--r--chromium/content/renderer/media/mock_peer_connection_impl.h52
-rw-r--r--chromium/content/renderer/media/native_handle_impl.cc16
-rw-r--r--chromium/content/renderer/media/native_handle_impl.h32
-rw-r--r--chromium/content/renderer/media/peer_connection_audio_sink_owner.cc71
-rw-r--r--chromium/content/renderer/media/peer_connection_audio_sink_owner.h54
-rw-r--r--chromium/content/renderer/media/peer_connection_tracker.cc78
-rw-r--r--chromium/content/renderer/media/peer_connection_tracker.h6
-rw-r--r--chromium/content/renderer/media/remote_media_stream_impl.cc59
-rw-r--r--chromium/content/renderer/media/remote_media_stream_impl.h5
-rw-r--r--chromium/content/renderer/media/render_media_client.cc103
-rw-r--r--chromium/content/renderer/media/render_media_client.h66
-rw-r--r--chromium/content/renderer/media/render_media_client_unittest.cc166
-rw-r--r--chromium/content/renderer/media/render_media_log.cc72
-rw-r--r--chromium/content/renderer/media/render_media_log.h9
-rw-r--r--chromium/content/renderer/media/render_media_log_unittest.cc42
-rw-r--r--chromium/content/renderer/media/renderer_gpu_video_accelerator_factories.cc100
-rw-r--r--chromium/content/renderer/media/renderer_gpu_video_accelerator_factories.h27
-rw-r--r--chromium/content/renderer/media/renderer_webaudiodevice_impl.cc5
-rw-r--r--chromium/content/renderer/media/renderer_webaudiodevice_impl.h6
-rw-r--r--chromium/content/renderer/media/rtc_data_channel_handler.cc90
-rw-r--r--chromium/content/renderer/media/rtc_data_channel_handler.h36
-rw-r--r--chromium/content/renderer/media/rtc_data_channel_handler_unittest.cc80
-rw-r--r--chromium/content/renderer/media/rtc_dtmf_sender_handler.cc6
-rw-r--r--chromium/content/renderer/media/rtc_dtmf_sender_handler.h6
-rw-r--r--chromium/content/renderer/media/rtc_peer_connection_handler.cc121
-rw-r--r--chromium/content/renderer/media/rtc_peer_connection_handler.h1
-rw-r--r--chromium/content/renderer/media/rtc_peer_connection_handler_unittest.cc12
-rw-r--r--chromium/content/renderer/media/rtc_video_decoder.cc133
-rw-r--r--chromium/content/renderer/media/rtc_video_decoder.h9
-rw-r--r--chromium/content/renderer/media/rtc_video_decoder_factory.cc2
-rw-r--r--chromium/content/renderer/media/rtc_video_decoder_factory.h2
-rw-r--r--chromium/content/renderer/media/rtc_video_decoder_unittest.cc29
-rw-r--r--chromium/content/renderer/media/rtc_video_encoder.cc47
-rw-r--r--chromium/content/renderer/media/rtc_video_encoder.h12
-rw-r--r--chromium/content/renderer/media/rtc_video_encoder_factory.cc33
-rw-r--r--chromium/content/renderer/media/rtc_video_encoder_factory.h7
-rw-r--r--chromium/content/renderer/media/rtc_video_renderer.cc14
-rw-r--r--chromium/content/renderer/media/rtc_video_renderer.h28
-rw-r--r--chromium/content/renderer/media/speech_recognition_audio_sink.cc21
-rw-r--r--chromium/content/renderer/media/speech_recognition_audio_sink.h9
-rw-r--r--chromium/content/renderer/media/speech_recognition_audio_sink_unittest.cc90
-rw-r--r--chromium/content/renderer/media/user_media_client_impl.cc128
-rw-r--r--chromium/content/renderer/media/user_media_client_impl.h15
-rw-r--r--chromium/content/renderer/media/user_media_client_impl_unittest.cc14
-rw-r--r--chromium/content/renderer/media/video_capture_impl.cc152
-rw-r--r--chromium/content/renderer/media/video_capture_impl.h63
-rw-r--r--chromium/content/renderer/media/video_capture_impl_manager.cc70
-rw-r--r--chromium/content/renderer/media/video_capture_impl_manager.h46
-rw-r--r--chromium/content/renderer/media/video_capture_impl_manager_unittest.cc15
-rw-r--r--chromium/content/renderer/media/video_capture_impl_unittest.cc3
-rw-r--r--chromium/content/renderer/media/video_capture_message_filter.cc41
-rw-r--r--chromium/content/renderer/media/video_capture_message_filter.h34
-rw-r--r--chromium/content/renderer/media/video_capture_message_filter_unittest.cc100
-rw-r--r--chromium/content/renderer/media/video_source_handler.cc13
-rw-r--r--chromium/content/renderer/media/video_track_adapter.cc277
-rw-r--r--chromium/content/renderer/media/video_track_adapter.h5
-rw-r--r--chromium/content/renderer/media/webaudio_capturer_source.cc60
-rw-r--r--chromium/content/renderer/media/webaudio_capturer_source.h31
-rw-r--r--chromium/content/renderer/media/webcontentdecryptionmodule_impl.cc103
-rw-r--r--chromium/content/renderer/media/webcontentdecryptionmodule_impl.h82
-rw-r--r--chromium/content/renderer/media/webcontentdecryptionmodulesession_impl.cc210
-rw-r--r--chromium/content/renderer/media/webcontentdecryptionmodulesession_impl.h98
-rw-r--r--chromium/content/renderer/media/webmediaplayer_ms.cc113
-rw-r--r--chromium/content/renderer/media/webmediaplayer_ms.h26
-rw-r--r--chromium/content/renderer/media/webrtc/DEPS5
-rw-r--r--chromium/content/renderer/media/webrtc/OWNERS2
-rw-r--r--chromium/content/renderer/media/webrtc/media_stream_remote_video_source.cc161
-rw-r--r--chromium/content/renderer/media/webrtc/media_stream_remote_video_source.h52
-rw-r--r--chromium/content/renderer/media/webrtc/media_stream_remote_video_source_unittest.cc17
-rw-r--r--chromium/content/renderer/media/webrtc/media_stream_track_metrics.cc2
-rw-r--r--chromium/content/renderer/media/webrtc/mock_peer_connection_dependency_factory.cc14
-rw-r--r--chromium/content/renderer/media/webrtc/mock_peer_connection_dependency_factory.h4
-rw-r--r--chromium/content/renderer/media/webrtc/peer_connection_dependency_factory.cc124
-rw-r--r--chromium/content/renderer/media/webrtc/peer_connection_dependency_factory.h35
-rw-r--r--chromium/content/renderer/media/webrtc/track_observer.cc111
-rw-r--r--chromium/content/renderer/media/webrtc/track_observer.h37
-rw-r--r--chromium/content/renderer/media/webrtc/video_destination_handler.cc36
-rw-r--r--chromium/content/renderer/media/webrtc/video_destination_handler.h7
-rw-r--r--chromium/content/renderer/media/webrtc/video_destination_handler_unittest.cc3
-rw-r--r--chromium/content/renderer/media/webrtc/webrtc_audio_sink_adapter.cc29
-rw-r--r--chromium/content/renderer/media/webrtc/webrtc_audio_sink_adapter.h10
-rw-r--r--chromium/content/renderer/media/webrtc/webrtc_local_audio_track_adapter.cc19
-rw-r--r--chromium/content/renderer/media/webrtc/webrtc_local_audio_track_adapter_unittest.cc31
-rw-r--r--chromium/content/renderer/media/webrtc/webrtc_media_stream_adapter_unittest.cc13
-rw-r--r--chromium/content/renderer/media/webrtc/webrtc_video_capturer_adapter.cc321
-rw-r--r--chromium/content/renderer/media/webrtc/webrtc_video_capturer_adapter.h2
-rw-r--r--chromium/content/renderer/media/webrtc/webrtc_video_track_adapter.cc13
-rw-r--r--chromium/content/renderer/media/webrtc_audio_capturer.cc171
-rw-r--r--chromium/content/renderer/media/webrtc_audio_capturer.h54
-rw-r--r--chromium/content/renderer/media/webrtc_audio_capturer_unittest.cc89
-rw-r--r--chromium/content/renderer/media/webrtc_audio_device_impl.cc152
-rw-r--r--chromium/content/renderer/media/webrtc_audio_device_impl.h59
-rw-r--r--chromium/content/renderer/media/webrtc_audio_device_not_impl.cc25
-rw-r--r--chromium/content/renderer/media/webrtc_audio_device_not_impl.h5
-rw-r--r--chromium/content/renderer/media/webrtc_audio_renderer.cc12
-rw-r--r--chromium/content/renderer/media/webrtc_audio_renderer.h4
-rw-r--r--chromium/content/renderer/media/webrtc_audio_renderer_unittest.cc5
-rw-r--r--chromium/content/renderer/media/webrtc_identity_service_unittest.cc36
-rw-r--r--chromium/content/renderer/media/webrtc_local_audio_renderer.cc86
-rw-r--r--chromium/content/renderer/media/webrtc_local_audio_renderer.h16
-rw-r--r--chromium/content/renderer/media/webrtc_local_audio_source_provider.cc22
-rw-r--r--chromium/content/renderer/media/webrtc_local_audio_source_provider.h15
-rw-r--r--chromium/content/renderer/media/webrtc_local_audio_source_provider_unittest.cc44
-rw-r--r--chromium/content/renderer/media/webrtc_local_audio_track.cc106
-rw-r--r--chromium/content/renderer/media/webrtc_local_audio_track.h27
-rw-r--r--chromium/content/renderer/media/webrtc_local_audio_track_unittest.cc97
-rw-r--r--chromium/content/renderer/media/webrtc_logging.h6
-rw-r--r--chromium/content/renderer/memory_benchmarking_extension.cc4
-rw-r--r--chromium/content/renderer/menu_item_builder.cc1
-rw-r--r--chromium/content/renderer/mojo/service_registry_js_wrapper.cc2
-rw-r--r--chromium/content/renderer/mojo/service_registry_js_wrapper.h2
-rw-r--r--chromium/content/renderer/navigation_state_impl.cc51
-rw-r--r--chromium/content/renderer/navigation_state_impl.h77
-rw-r--r--chromium/content/renderer/net_info_helper.h6
-rw-r--r--chromium/content/renderer/notification_icon_loader.cc83
-rw-r--r--chromium/content/renderer/notification_icon_loader.h73
-rw-r--r--chromium/content/renderer/notification_permission_dispatcher.cc51
-rw-r--r--chromium/content/renderer/notification_permission_dispatcher.h10
-rw-r--r--chromium/content/renderer/notification_provider.cc165
-rw-r--r--chromium/content/renderer/notification_provider.h66
-rw-r--r--chromium/content/renderer/npapi/webplugin_delegate_proxy.cc123
-rw-r--r--chromium/content/renderer/npapi/webplugin_delegate_proxy.h21
-rw-r--r--chromium/content/renderer/npapi/webplugin_impl.cc48
-rw-r--r--chromium/content/renderer/npapi/webplugin_impl.h25
-rw-r--r--chromium/content/renderer/p2p/ipc_network_manager.cc47
-rw-r--r--chromium/content/renderer/p2p/ipc_socket_factory.cc141
-rw-r--r--chromium/content/renderer/p2p/port_allocator.cc18
-rw-r--r--chromium/content/renderer/p2p/port_allocator.h8
-rw-r--r--chromium/content/renderer/p2p/socket_client.h12
-rw-r--r--chromium/content/renderer/p2p/socket_client_delegate.h2
-rw-r--r--chromium/content/renderer/p2p/socket_client_impl.cc47
-rw-r--r--chromium/content/renderer/p2p/socket_client_impl.h24
-rw-r--r--chromium/content/renderer/p2p/socket_dispatcher.cc12
-rw-r--r--chromium/content/renderer/p2p/socket_dispatcher.h2
-rw-r--r--chromium/content/renderer/pepper/DEPS1
-rw-r--r--chromium/content/renderer/pepper/audio_helper.cc20
-rw-r--r--chromium/content/renderer/pepper/content_decryptor_delegate.cc416
-rw-r--r--chromium/content/renderer/pepper/content_decryptor_delegate.h95
-rw-r--r--chromium/content/renderer/pepper/content_renderer_pepper_host_factory.cc79
-rw-r--r--chromium/content/renderer/pepper/content_renderer_pepper_host_factory.h2
-rw-r--r--chromium/content/renderer/pepper/event_conversion.cc113
-rw-r--r--chromium/content/renderer/pepper/fullscreen_container.h6
-rw-r--r--chromium/content/renderer/pepper/gfx_conversion.h8
-rw-r--r--chromium/content/renderer/pepper/host_array_buffer_var.cc9
-rw-r--r--chromium/content/renderer/pepper/host_array_buffer_var.h8
-rw-r--r--chromium/content/renderer/pepper/host_dispatcher_wrapper.cc19
-rw-r--r--chromium/content/renderer/pepper/host_globals.cc2
-rw-r--r--chromium/content/renderer/pepper/host_resource_var.h6
-rw-r--r--chromium/content/renderer/pepper/host_var_tracker.cc10
-rw-r--r--chromium/content/renderer/pepper/host_var_tracker.h6
-rw-r--r--chromium/content/renderer/pepper/host_var_tracker_unittest.cc6
-rw-r--r--chromium/content/renderer/pepper/message_channel.cc43
-rw-r--r--chromium/content/renderer/pepper/message_channel.h12
-rw-r--r--chromium/content/renderer/pepper/mock_renderer_ppapi_host.cc2
-rw-r--r--chromium/content/renderer/pepper/pepper_audio_input_host.cc14
-rw-r--r--chromium/content/renderer/pepper/pepper_browser_connection.cc8
-rw-r--r--chromium/content/renderer/pepper/pepper_camera_device_host.cc126
-rw-r--r--chromium/content/renderer/pepper/pepper_camera_device_host.h67
-rw-r--r--chromium/content/renderer/pepper/pepper_compositor_host.cc53
-rw-r--r--chromium/content/renderer/pepper/pepper_compositor_host.h11
-rw-r--r--chromium/content/renderer/pepper/pepper_file_chooser_host_unittest.cc7
-rw-r--r--chromium/content/renderer/pepper/pepper_file_system_host.cc4
-rw-r--r--chromium/content/renderer/pepper/pepper_graphics_2d_host.cc25
-rw-r--r--chromium/content/renderer/pepper/pepper_graphics_2d_host.h5
-rw-r--r--chromium/content/renderer/pepper/pepper_graphics_2d_host_unittest.cc6
-rw-r--r--chromium/content/renderer/pepper/pepper_media_stream_audio_track_host.cc114
-rw-r--r--chromium/content/renderer/pepper/pepper_media_stream_audio_track_host.h40
-rw-r--r--chromium/content/renderer/pepper/pepper_media_stream_track_host_base.cc9
-rw-r--r--chromium/content/renderer/pepper/pepper_media_stream_video_track_host.cc62
-rw-r--r--chromium/content/renderer/pepper/pepper_media_stream_video_track_host.h4
-rw-r--r--chromium/content/renderer/pepper/pepper_platform_audio_input.cc2
-rw-r--r--chromium/content/renderer/pepper/pepper_platform_audio_output.cc5
-rw-r--r--chromium/content/renderer/pepper/pepper_platform_audio_output.h8
-rw-r--r--chromium/content/renderer/pepper/pepper_platform_camera_device.cc131
-rw-r--r--chromium/content/renderer/pepper/pepper_platform_camera_device.h73
-rw-r--r--chromium/content/renderer/pepper/pepper_platform_video_capture.cc3
-rw-r--r--chromium/content/renderer/pepper/pepper_platform_video_capture.h3
-rw-r--r--chromium/content/renderer/pepper/pepper_plugin_instance_impl.cc673
-rw-r--r--chromium/content/renderer/pepper/pepper_plugin_instance_impl.h102
-rw-r--r--chromium/content/renderer/pepper/pepper_plugin_instance_metrics.cc108
-rw-r--r--chromium/content/renderer/pepper/pepper_plugin_instance_metrics.h29
-rw-r--r--chromium/content/renderer/pepper/pepper_plugin_instance_throttler.cc30
-rw-r--r--chromium/content/renderer/pepper/pepper_plugin_instance_throttler.h29
-rw-r--r--chromium/content/renderer/pepper/pepper_try_catch.cc38
-rw-r--r--chromium/content/renderer/pepper/pepper_try_catch.h12
-rw-r--r--chromium/content/renderer/pepper/pepper_url_loader_host.cc7
-rw-r--r--chromium/content/renderer/pepper/pepper_url_request_unittest.cc5
-rw-r--r--chromium/content/renderer/pepper/pepper_video_capture_host.cc28
-rw-r--r--chromium/content/renderer/pepper/pepper_video_capture_host.h5
-rw-r--r--chromium/content/renderer/pepper/pepper_video_decoder_host.cc40
-rw-r--r--chromium/content/renderer/pepper/pepper_video_decoder_host.h4
-rw-r--r--chromium/content/renderer/pepper/pepper_video_destination_host.cc23
-rw-r--r--chromium/content/renderer/pepper/pepper_video_destination_host.h7
-rw-r--r--chromium/content/renderer/pepper/pepper_video_encoder_host.cc671
-rw-r--r--chromium/content/renderer/pepper/pepper_video_encoder_host.h164
-rw-r--r--chromium/content/renderer/pepper/pepper_video_source_host.cc87
-rw-r--r--chromium/content/renderer/pepper/pepper_video_source_host.h5
-rw-r--r--chromium/content/renderer/pepper/pepper_webplugin_impl.cc34
-rw-r--r--chromium/content/renderer/pepper/pepper_webplugin_impl.h21
-rw-r--r--chromium/content/renderer/pepper/pepper_webplugin_impl_browsertest.cc207
-rw-r--r--chromium/content/renderer/pepper/pepper_websocket_host.cc4
-rw-r--r--chromium/content/renderer/pepper/plugin_instance_throttler_impl.cc220
-rw-r--r--chromium/content/renderer/pepper/plugin_instance_throttler_impl.h118
-rw-r--r--chromium/content/renderer/pepper/plugin_instance_throttler_impl_unittest.cc219
-rw-r--r--chromium/content/renderer/pepper/plugin_module.cc118
-rw-r--r--chromium/content/renderer/pepper/plugin_object.cc28
-rw-r--r--chromium/content/renderer/pepper/plugin_object.h8
-rw-r--r--chromium/content/renderer/pepper/plugin_power_saver_helper.cc127
-rw-r--r--chromium/content/renderer/pepper/plugin_power_saver_helper.h50
-rw-r--r--chromium/content/renderer/pepper/plugin_power_saver_helper_browsertest.cc117
-rw-r--r--chromium/content/renderer/pepper/ppb_audio_impl.cc56
-rw-r--r--chromium/content/renderer/pepper/ppb_audio_impl.h13
-rw-r--r--chromium/content/renderer/pepper/ppb_broker_impl.cc4
-rw-r--r--chromium/content/renderer/pepper/ppb_broker_impl.h2
-rw-r--r--chromium/content/renderer/pepper/ppb_buffer_impl.cc10
-rw-r--r--chromium/content/renderer/pepper/ppb_graphics_3d_impl.cc13
-rw-r--r--chromium/content/renderer/pepper/ppb_graphics_3d_impl.h1
-rw-r--r--chromium/content/renderer/pepper/ppb_image_data_impl.cc89
-rw-r--r--chromium/content/renderer/pepper/ppb_image_data_impl.h4
-rw-r--r--chromium/content/renderer/pepper/ppb_scrollbar_impl.h2
-rw-r--r--chromium/content/renderer/pepper/ppb_var_deprecated_impl.cc31
-rw-r--r--chromium/content/renderer/pepper/ppb_video_decoder_impl.cc42
-rw-r--r--chromium/content/renderer/pepper/ppb_video_decoder_impl.h9
-rw-r--r--chromium/content/renderer/pepper/renderer_ppapi_host_impl.cc11
-rw-r--r--chromium/content/renderer/pepper/renderer_ppapi_host_impl.h2
-rw-r--r--chromium/content/renderer/pepper/renderer_restrict_dispatch_group.h6
-rw-r--r--chromium/content/renderer/pepper/resource_converter.cc16
-rw-r--r--chromium/content/renderer/pepper/resource_converter.h22
-rw-r--r--chromium/content/renderer/pepper/resource_creation_impl.cc20
-rw-r--r--chromium/content/renderer/pepper/resource_creation_impl.h3
-rw-r--r--chromium/content/renderer/pepper/url_request_info_util.h2
-rw-r--r--chromium/content/renderer/pepper/usb_key_code_conversion.cc25
-rw-r--r--chromium/content/renderer/pepper/usb_key_code_conversion.h29
-rw-r--r--chromium/content/renderer/pepper/usb_key_code_conversion_linux.cc5
-rw-r--r--chromium/content/renderer/pepper/usb_key_code_conversion_mac.cc5
-rw-r--r--chromium/content/renderer/pepper/usb_key_code_conversion_win.cc5
-rw-r--r--chromium/content/renderer/pepper/v8_var_converter.cc90
-rw-r--r--chromium/content/renderer/pepper/v8_var_converter.h22
-rw-r--r--chromium/content/renderer/pepper/v8_var_converter_unittest.cc58
-rw-r--r--chromium/content/renderer/pepper/v8object_var.cc2
-rw-r--r--chromium/content/renderer/pepper/v8object_var.h2
-rw-r--r--chromium/content/renderer/pepper/video_decoder_shim.cc677
-rw-r--r--chromium/content/renderer/pepper/video_decoder_shim.h18
-rw-r--r--chromium/content/renderer/pepper/video_encoder_shim.cc402
-rw-r--r--chromium/content/renderer/pepper/video_encoder_shim.h76
-rw-r--r--chromium/content/renderer/presentation/OWNERS3
-rw-r--r--chromium/content/renderer/presentation/presentation_dispatcher.cc366
-rw-r--r--chromium/content/renderer/presentation/presentation_dispatcher.h98
-rw-r--r--chromium/content/renderer/presentation/presentation_session_client.cc35
-rw-r--r--chromium/content/renderer/presentation/presentation_session_client.h37
-rw-r--r--chromium/content/renderer/push_messaging/OWNERS1
-rw-r--r--chromium/content/renderer/push_messaging/push_messaging_dispatcher.cc139
-rw-r--r--chromium/content/renderer/push_messaging/push_messaging_dispatcher.h68
-rw-r--r--chromium/content/renderer/push_messaging_dispatcher.cc136
-rw-r--r--chromium/content/renderer/push_messaging_dispatcher.h72
-rw-r--r--chromium/content/renderer/push_permission_dispatcher.cc48
-rw-r--r--chromium/content/renderer/push_permission_dispatcher.h41
-rw-r--r--chromium/content/renderer/render_font_warmup_win.cc4
-rw-r--r--chromium/content/renderer/render_frame_impl.cc2151
-rw-r--r--chromium/content/renderer/render_frame_impl.h357
-rw-r--r--chromium/content/renderer/render_frame_impl_browsertest.cc150
-rw-r--r--chromium/content/renderer/render_frame_proxy.cc179
-rw-r--r--chromium/content/renderer/render_frame_proxy.h30
-rw-r--r--chromium/content/renderer/render_process_impl.cc3
-rw-r--r--chromium/content/renderer/render_thread_impl.cc766
-rw-r--r--chromium/content/renderer/render_thread_impl.h231
-rw-r--r--chromium/content/renderer/render_thread_impl_browsertest.cc268
-rw-r--r--chromium/content/renderer/render_view_browsertest.cc994
-rw-r--r--chromium/content/renderer/render_view_impl.cc1098
-rw-r--r--chromium/content/renderer/render_view_impl.h192
-rw-r--r--chromium/content/renderer/render_view_impl_android.cc64
-rw-r--r--chromium/content/renderer/render_view_impl_params.cc45
-rw-r--r--chromium/content/renderer/render_view_impl_params.h63
-rw-r--r--chromium/content/renderer/render_view_linux.cc40
-rw-r--r--chromium/content/renderer/render_view_win.cc45
-rw-r--r--chromium/content/renderer/render_widget.cc780
-rw-r--r--chromium/content/renderer/render_widget.h136
-rw-r--r--chromium/content/renderer/render_widget_browsertest.cc79
-rw-r--r--chromium/content/renderer/render_widget_fullscreen.cc13
-rw-r--r--chromium/content/renderer/render_widget_fullscreen.h3
-rw-r--r--chromium/content/renderer/render_widget_fullscreen_pepper.cc9
-rw-r--r--chromium/content/renderer/render_widget_fullscreen_pepper.h1
-rw-r--r--chromium/content/renderer/render_widget_unittest.cc10
-rw-r--r--chromium/content/renderer/renderer.gni11
-rw-r--r--chromium/content/renderer/renderer_blink_platform_impl.cc223
-rw-r--r--chromium/content/renderer/renderer_blink_platform_impl.h43
-rw-r--r--chromium/content/renderer/renderer_clipboard_client.cc180
-rw-r--r--chromium/content/renderer/renderer_clipboard_client.h43
-rw-r--r--chromium/content/renderer/renderer_clipboard_delegate.cc167
-rw-r--r--chromium/content/renderer/renderer_clipboard_delegate.h66
-rw-r--r--chromium/content/renderer/renderer_font_platform_win.cc423
-rw-r--r--chromium/content/renderer/renderer_font_platform_win.h17
-rw-r--r--chromium/content/renderer/renderer_main.cc47
-rw-r--r--chromium/content/renderer/renderer_main_platform_delegate.h6
-rw-r--r--chromium/content/renderer/renderer_main_platform_delegate_android.cc21
-rw-r--r--chromium/content/renderer/renderer_main_platform_delegate_linux.cc9
-rw-r--r--chromium/content/renderer/renderer_main_platform_delegate_win.cc37
-rw-r--r--chromium/content/renderer/renderer_webcookiejar_impl.cc42
-rw-r--r--chromium/content/renderer/renderer_webcookiejar_impl.h5
-rw-r--r--chromium/content/renderer/resizing_mode_selector.cc3
-rw-r--r--chromium/content/renderer/resource_fetcher_browsertest.cc34
-rw-r--r--chromium/content/renderer/sad_plugin.cc2
-rw-r--r--chromium/content/renderer/savable_resources_browsertest.cc2
-rw-r--r--chromium/content/renderer/scheduler/OWNERS3
-rw-r--r--chromium/content/renderer/scheduler/null_renderer_scheduler.cc79
-rw-r--r--chromium/content/renderer/scheduler/null_renderer_scheduler.h36
-rw-r--r--chromium/content/renderer/scheduler/renderer_scheduler.cc23
-rw-r--r--chromium/content/renderer/scheduler/renderer_scheduler.h63
-rw-r--r--chromium/content/renderer/scheduler/renderer_scheduler_impl.cc218
-rw-r--r--chromium/content/renderer/scheduler/renderer_scheduler_impl.h128
-rw-r--r--chromium/content/renderer/scheduler/renderer_scheduler_impl_unittest.cc411
-rw-r--r--chromium/content/renderer/scheduler/renderer_task_queue_selector.cc122
-rw-r--r--chromium/content/renderer/scheduler/renderer_task_queue_selector.h91
-rw-r--r--chromium/content/renderer/scheduler/renderer_task_queue_selector_unittest.cc201
-rw-r--r--chromium/content/renderer/scheduler/resource_dispatch_throttler.cc146
-rw-r--r--chromium/content/renderer/scheduler/resource_dispatch_throttler.h72
-rw-r--r--chromium/content/renderer/scheduler/resource_dispatch_throttler_unittest.cc370
-rw-r--r--chromium/content/renderer/scheduler/single_thread_idle_task_runner.cc38
-rw-r--r--chromium/content/renderer/scheduler/single_thread_idle_task_runner.h49
-rw-r--r--chromium/content/renderer/scheduler/task_queue_manager.cc294
-rw-r--r--chromium/content/renderer/scheduler/task_queue_manager.h118
-rw-r--r--chromium/content/renderer/scheduler/task_queue_manager_unittest.cc358
-rw-r--r--chromium/content/renderer/scheduler/task_queue_selector.h37
-rw-r--r--chromium/content/renderer/scheduler/web_scheduler_impl.cc45
-rw-r--r--chromium/content/renderer/scheduler/web_scheduler_impl.h38
-rw-r--r--chromium/content/renderer/scoped_clipboard_writer_glue.cc36
-rw-r--r--chromium/content/renderer/scoped_clipboard_writer_glue.h30
-rw-r--r--chromium/content/renderer/screen_orientation/screen_orientation_dispatcher.h2
-rw-r--r--chromium/content/renderer/screen_orientation/screen_orientation_dispatcher_unittest.cc9
-rw-r--r--chromium/content/renderer/service_worker/embedded_worker_context_client.cc215
-rw-r--r--chromium/content/renderer/service_worker/embedded_worker_context_client.h60
-rw-r--r--chromium/content/renderer/service_worker/embedded_worker_context_message_filter.cc41
-rw-r--r--chromium/content/renderer/service_worker/embedded_worker_context_message_filter.h20
-rw-r--r--chromium/content/renderer/service_worker/embedded_worker_devtools_agent.cc1
-rw-r--r--chromium/content/renderer/service_worker/embedded_worker_dispatcher.cc2
-rw-r--r--chromium/content/renderer/service_worker/embedded_worker_dispatcher.h4
-rw-r--r--chromium/content/renderer/service_worker/service_worker_cache_storage_dispatcher.cc542
-rw-r--r--chromium/content/renderer/service_worker/service_worker_cache_storage_dispatcher.h159
-rw-r--r--chromium/content/renderer/service_worker/service_worker_script_context.cc387
-rw-r--r--chromium/content/renderer/service_worker/service_worker_script_context.h96
-rw-r--r--chromium/content/renderer/service_worker/service_worker_type_util.cc62
-rw-r--r--chromium/content/renderer/service_worker/service_worker_type_util.h27
-rw-r--r--chromium/content/renderer/shared_memory_seqlock_reader.cc2
-rw-r--r--chromium/content/renderer/shared_worker/embedded_shared_worker_content_settings_client_proxy.cc63
-rw-r--r--chromium/content/renderer/shared_worker/embedded_shared_worker_content_settings_client_proxy.h47
-rw-r--r--chromium/content/renderer/shared_worker/embedded_shared_worker_permission_client_proxy.cc62
-rw-r--r--chromium/content/renderer/shared_worker/embedded_shared_worker_permission_client_proxy.h47
-rw-r--r--chromium/content/renderer/shared_worker/embedded_shared_worker_stub.cc102
-rw-r--r--chromium/content/renderer/shared_worker/embedded_shared_worker_stub.h21
-rw-r--r--chromium/content/renderer/shared_worker_repository.cc4
-rw-r--r--chromium/content/renderer/skia_benchmarking_extension.cc119
-rw-r--r--chromium/content/renderer/skia_benchmarking_extension.h2
-rw-r--r--chromium/content/renderer/skia_benchmarking_extension_unittest.cc135
-rw-r--r--chromium/content/renderer/speech_recognition_dispatcher.cc14
-rw-r--r--chromium/content/renderer/stats_collection_controller.cc4
-rw-r--r--chromium/content/renderer/text_input_client_observer.cc2
-rw-r--r--chromium/content/renderer/text_input_client_observer.h2
-rw-r--r--chromium/content/renderer/v8_value_converter_impl.cc557
-rw-r--r--chromium/content/renderer/v8_value_converter_impl.h98
-rw-r--r--chromium/content/renderer/v8_value_converter_impl_unittest.cc875
-rw-r--r--chromium/content/renderer/visual_state_browsertest.cc123
-rw-r--r--chromium/content/renderer/web_ui_extension.cc8
-rw-r--r--chromium/content/renderer/web_ui_mojo.cc11
-rw-r--r--chromium/content/renderer/web_ui_mojo.h11
-rw-r--r--chromium/content/renderer/web_ui_mojo_context_state.cc6
-rw-r--r--chromium/content/renderer/web_ui_mojo_context_state.h2
-rw-r--r--chromium/content/renderer/web_ui_runner.cc6
-rw-r--r--chromium/content/renderer/web_ui_runner.h6
-rw-r--r--chromium/content/renderer/webclipboard_impl.cc105
-rw-r--r--chromium/content/renderer/webclipboard_impl.h7
-rw-r--r--chromium/content/renderer/webgraphicscontext3d_provider_impl.cc7
-rw-r--r--chromium/content/renderer/webgraphicscontext3d_provider_impl.h10
-rw-r--r--chromium/content/renderer/webscrollbarbehavior_impl_gtkoraura.h6
-rw-r--r--chromium/content/renderer/webscrollbarbehavior_impl_mac.h6
-rw-r--r--chromium/content/shell/common/DEPS3
-rw-r--r--chromium/content/shell/common/layout_test/layout_test_messages.cc33
-rw-r--r--chromium/content/shell/common/layout_test/layout_test_messages.h40
-rw-r--r--chromium/content/shell/common/leak_detection_result.h19
-rw-r--r--chromium/content/shell/common/shell_content_client.cc94
-rw-r--r--chromium/content/shell/common/shell_content_client.h34
-rw-r--r--chromium/content/shell/common/shell_messages.cc33
-rw-r--r--chromium/content/shell/common/shell_messages.h111
-rw-r--r--chromium/content/shell/common/shell_switches.cc71
-rw-r--r--chromium/content/shell/common/shell_switches.h32
-rw-r--r--chromium/content/shell/common/shell_test_configuration.cc15
-rw-r--r--chromium/content/shell/common/shell_test_configuration.h44
-rw-r--r--chromium/content/shell/common/test_runner/OWNERS6
-rw-r--r--chromium/content/shell/common/test_runner/test_preferences.cc58
-rw-r--r--chromium/content/shell/common/test_runner/test_preferences.h57
-rw-r--r--chromium/content/shell/common/v8_breakpad_support_win.cc32
-rw-r--r--chromium/content/shell/common/v8_breakpad_support_win.h15
-rw-r--r--chromium/content/utility/BUILD.gn7
-rw-r--r--chromium/content/utility/DEPS1
-rw-r--r--chromium/content/utility/in_process_utility_thread.cc12
-rw-r--r--chromium/content/utility/in_process_utility_thread.h7
-rw-r--r--chromium/content/utility/utility_blink_platform_impl.cc24
-rw-r--r--chromium/content/utility/utility_blink_platform_impl.h30
-rw-r--r--chromium/content/utility/utility_main.cc6
-rw-r--r--chromium/content/utility/utility_thread_impl.cc42
-rw-r--r--chromium/content/utility/utility_thread_impl.h27
-rw-r--r--chromium/content/utility/webthread_impl_for_utility_thread.cc37
-rw-r--r--chromium/content/utility/webthread_impl_for_utility_thread.h35
-rw-r--r--chromium/content/zygote/zygote_linux.cc119
-rw-r--r--chromium/content/zygote/zygote_linux.h18
-rw-r--r--chromium/content/zygote/zygote_main_linux.cc203
3109 files changed, 164977 insertions, 102582 deletions
diff --git a/chromium/content/BUILD.gn b/chromium/content/BUILD.gn
index 7f246689419..2a7878c74fc 100644
--- a/chromium/content/BUILD.gn
+++ b/chromium/content/BUILD.gn
@@ -38,7 +38,7 @@ config("content_implementation") {
# when doing a component build).
content_shared_components = [
- "//content/gpu",
+ "//content/gpu:gpu_sources",
"//content/public/browser:browser_sources",
"//content/public/child:child_sources",
"//content/public/common:common_sources",
@@ -48,14 +48,13 @@ content_shared_components = [
]
if (enable_plugins) {
- content_shared_components += [ "//content/ppapi_plugin" ]
+ content_shared_components += [ "//content/ppapi_plugin:ppapi_plugin_sources" ]
}
if (is_component_build) {
shared_library("content") {
- public_deps = content_shared_components + [
- "//content/public/app:both_sources",
- ]
+ public_deps =
+ content_shared_components + [ "//content/public/app:both_sources" ]
}
} else {
group("content") {
@@ -78,6 +77,24 @@ grit("resources") {
source_set("export") {
visibility = [ "//content/*" ]
sources = [
- "content/common/content_export.h"
+ "content/common/content_export.h",
]
}
+
+# In the GYP build, this file is listed in several targets. In GN just have
+# those targets depend on this one. This can be depended on for any
+# platform for simplicity, and is a no-op on non-Windows.
+source_set("startup_helper_win") {
+ if (is_win) {
+ sources = [
+ "app/startup_helper_win.cc",
+ "public/app/startup_helper_win.h",
+ ]
+
+ deps = [
+ "//base",
+ "//base:i18n",
+ "//sandbox",
+ ]
+ }
+}
diff --git a/chromium/content/DEPS b/chromium/content/DEPS
index d3543fc43d6..5a9805e6009 100644
--- a/chromium/content/DEPS
+++ b/chromium/content/DEPS
@@ -33,10 +33,6 @@ include_rules = [
"+dbus",
"+gpu",
"+mojo/common",
- "+mojo/edk/embedder",
- "+mojo/edk/js",
- "+mojo/edk/test",
- "+mojo/public",
"+net",
"+ppapi",
"+printing",
@@ -63,8 +59,13 @@ include_rules = [
"+third_party/angle",
"+third_party/flac",
"+third_party/libjingle",
+ "+third_party/mojo/src/mojo/edk/embedder",
+ "+third_party/mojo/src/mojo/edk/js",
+ "+third_party/mojo/src/mojo/edk/test",
+ "+third_party/mojo/src/mojo/public",
"+third_party/mozilla",
"+third_party/npapi/bindings",
+ "+third_party/ocmock",
"+third_party/re2",
"+third_party/skia",
"+third_party/sqlite",
@@ -75,6 +76,7 @@ include_rules = [
"+third_party/WebKit/public/platform",
"+third_party/WebKit/public/web",
+ "+ui/accelerated_widget_mac",
"+ui/accessibility",
"+ui/android",
# Aura is analogous to Win32 or a Gtk, so it is allowed.
@@ -94,12 +96,14 @@ include_rules = [
"+ui/snapshot",
"+ui/strings/grit/ui_strings.h",
"+ui/surface",
+ "+ui/touch_selection",
"+ui/wm",
# Content knows about grd files, but the specifics of how to get a resource
# given its id is left to the embedder.
"-ui/base/l10n",
"-ui/base/resource",
- # This file isn't related to grd, so it's fine.
+ # These files aren't related to grd, so they're fine.
+ "+ui/base/l10n/l10n_util_android.h",
"+ui/base/l10n/l10n_util_win.h",
# Content shouldn't depend on views. While we technically don't need this
@@ -109,7 +113,6 @@ include_rules = [
"+storage/browser",
"+storage/common",
- "+webkit",
# For generated JNI includes.
"+jni",
diff --git a/chromium/content/OWNERS b/chromium/content/OWNERS
index 593bbb4cdd7..af383e66aee 100644
--- a/chromium/content/OWNERS
+++ b/chromium/content/OWNERS
@@ -12,6 +12,7 @@ sievers@chromium.org
# These are for the common case of adding or renaming files. If you're doing
# structural changes, please get a review from a reviewer in this file.
per-file *.gypi=*
+per-file content_nacl_nonsfi.gyp=*
# Mac Sandbox profiles.
per-file *.sb=set noparent
diff --git a/chromium/content/app/BUILD.gn b/chromium/content/app/BUILD.gn
index 517082d5cae..463d9f18b4d 100644
--- a/chromium/content/app/BUILD.gn
+++ b/chromium/content/app/BUILD.gn
@@ -2,33 +2,38 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# TODO(GYP) enable chrome_multiple_dll support
-is_chrome_multiple_dll = false
+import("//build/config/chrome_build.gni")
content_app_sources = [
"android/app_jni_registrar.cc",
"android/app_jni_registrar.h",
"android/child_process_service.cc",
"android/child_process_service.h",
+ "android/content_jni_onload.cc",
"android/content_main.cc",
"android/content_main.h",
"android/library_loader_hooks.cc",
+ "android/library_loader_hooks.h",
"content_main.cc",
"content_main_runner.cc",
+ "mac/mac_init.mm",
+ "mac/mac_init.h",
"mojo/mojo_init.cc",
"mojo/mojo_init.h",
- "startup_helper_win.cc",
]
content_app_deps = [
"//base",
"//base:i18n",
+
# This is needed by app/content_main_runner.cc
# TODO(brettw) this shouldn't be here, only final executables should be
# picking the allocator.
"//base/allocator",
"//content:export",
+ "//content:startup_helper_win",
"//content/public/common:common_sources",
+ "//content/public/common:mojo_bindings",
"//crypto",
"//ui/base",
"//ui/gfx",
@@ -41,8 +46,10 @@ if (is_win) {
content_app_sources -= [ "content_main.cc" ]
content_app_deps += [
"//content/public/android:jni",
+ "//device/vibration",
"//skia",
- "//third_party/android_tools:cpu_features"
+ "//third_party/android_tools:cpu_features",
+ "//ui/android",
]
}
@@ -54,9 +61,9 @@ if (is_ios) {
]
} else {
content_app_deps += [
- "//mojo/edk/system",
+ "//mojo/application/public/interfaces",
"//mojo/environment:chromium",
- "//mojo/public/interfaces/application",
+ "//third_party/mojo/src/mojo/edk/system",
]
}
@@ -65,8 +72,8 @@ content_app_extra_configs = [
"//content:content_implementation",
]
-if (!is_chrome_multiple_dll) {
- content_app_deps += [ "//content/gpu" ]
+if (!is_multi_dll_chrome) {
+ content_app_deps += [ "//content/gpu:gpu_sources" ]
}
# This includes the app sources for both the browser and child processes.
@@ -80,7 +87,7 @@ source_set("both") {
deps = content_app_deps
}
-if (is_chrome_multiple_dll) {
+if (is_multi_dll_chrome) {
# It doesn't make sense to do the browser/child dll split in component mode.
assert(!is_component_build)
@@ -91,7 +98,7 @@ if (is_chrome_multiple_dll) {
configs += content_app_extra_configs
deps = content_app_deps
- defines += [ "CHROME_MULTIPLE_DLL_BROWSER" ]
+ defines = [ "CHROME_MULTIPLE_DLL_BROWSER" ]
}
source_set("child") {
@@ -101,6 +108,6 @@ if (is_chrome_multiple_dll) {
configs += content_app_extra_configs
deps = content_app_deps
- defines += [ "CHROME_MULTIPLE_DLL_CHILD" ]
+ defines = [ "CHROME_MULTIPLE_DLL_CHILD" ]
}
}
diff --git a/chromium/content/app/DEPS b/chromium/content/app/DEPS
index 2f0a8fe96f4..22ca08ad082 100644
--- a/chromium/content/app/DEPS
+++ b/chromium/content/app/DEPS
@@ -1,7 +1,12 @@
include_rules = [
"+content",
"+device/battery",
+ "+device/bluetooth",
+ "+device/vibration",
# For loading V8's initial snapshot from external files.
"+gin/public/isolate_holder.h",
+ "+gin/public/snapshot_fd_data.h",
+ "+gin/v8_initializer.h",
"+media/base", # For initializing media library.
+ "+media/midi", # For initializing midi library.
]
diff --git a/chromium/content/app/OWNERS b/chromium/content/app/OWNERS
deleted file mode 100644
index df3bbfd3b1b..00000000000
--- a/chromium/content/app/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-agl@chromium.org
diff --git a/chromium/content/app/android/child_process_service.cc b/chromium/content/app/android/child_process_service.cc
index 9d46e080c82..bfbcde06b63 100644
--- a/chromium/content/app/android/child_process_service.cc
+++ b/chromium/content/app/android/child_process_service.cc
@@ -12,11 +12,10 @@
#include "base/android/memory_pressure_listener_android.h"
#include "base/logging.h"
#include "base/posix/global_descriptors.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
#include "content/common/android/surface_texture_manager.h"
#include "content/common/android/surface_texture_peer.h"
#include "content/common/gpu/gpu_surface_lookup.h"
-#include "content/public/app/android_library_loader_hooks.h"
#include "content/public/common/content_descriptors.h"
#include "ipc/ipc_descriptors.h"
#include "jni/ChildProcessService_jni.h"
@@ -44,16 +43,15 @@ class SurfaceTextureManagerImpl : public SurfaceTextureManager,
SurfaceTexturePeer::InitInstance(this);
GpuSurfaceLookup::InitInstance(this);
}
- virtual ~SurfaceTextureManagerImpl() {
+ ~SurfaceTextureManagerImpl() override {
SurfaceTexturePeer::InitInstance(NULL);
GpuSurfaceLookup::InitInstance(NULL);
}
// Overridden from SurfaceTextureManager:
- virtual void RegisterSurfaceTexture(
- int surface_texture_id,
- int client_id,
- gfx::SurfaceTexture* surface_texture) override {
+ void RegisterSurfaceTexture(int surface_texture_id,
+ int client_id,
+ gfx::SurfaceTexture* surface_texture) override {
JNIEnv* env = base::android::AttachCurrentThread();
Java_ChildProcessService_createSurfaceTextureSurface(
env,
@@ -62,13 +60,13 @@ class SurfaceTextureManagerImpl : public SurfaceTextureManager,
client_id,
surface_texture->j_surface_texture().obj());
}
- virtual void UnregisterSurfaceTexture(int surface_texture_id,
- int client_id) override {
+ void UnregisterSurfaceTexture(int surface_texture_id,
+ int client_id) override {
JNIEnv* env = base::android::AttachCurrentThread();
Java_ChildProcessService_destroySurfaceTextureSurface(
env, service_.obj(), surface_texture_id, client_id);
}
- virtual gfx::AcceleratedWidget AcquireNativeWidgetForSurfaceTexture(
+ gfx::AcceleratedWidget AcquireNativeWidgetForSurfaceTexture(
int surface_texture_id) override {
JNIEnv* env = base::android::AttachCurrentThread();
gfx::ScopedJavaSurface surface(
@@ -89,7 +87,7 @@ class SurfaceTextureManagerImpl : public SurfaceTextureManager,
}
// Overridden from SurfaceTexturePeer:
- virtual void EstablishSurfaceTexturePeer(
+ void EstablishSurfaceTexturePeer(
base::ProcessHandle pid,
scoped_refptr<gfx::SurfaceTexture> surface_texture,
int primary_id,
@@ -105,7 +103,7 @@ class SurfaceTextureManagerImpl : public SurfaceTextureManager,
}
// Overridden from GpuSurfaceLookup:
- virtual gfx::AcceleratedWidget AcquireNativeWidget(int surface_id) override {
+ gfx::AcceleratedWidget AcquireNativeWidget(int surface_id) override {
JNIEnv* env = base::android::AttachCurrentThread();
gfx::ScopedJavaSurface surface(
content::Java_ChildProcessService_getViewSurface(
@@ -188,7 +186,7 @@ bool RegisterChildProcessService(JNIEnv* env) {
}
void ShutdownMainThread(JNIEnv* env, jobject obj) {
- ChildThread::ShutdownThread();
+ ChildThreadImpl::ShutdownThread();
}
} // namespace content
diff --git a/chromium/content/app/android/content_main.cc b/chromium/content/app/android/content_main.cc
index 55657496e09..f322017bdbe 100644
--- a/chromium/content/app/android/content_main.cc
+++ b/chromium/content/app/android/content_main.cc
@@ -7,8 +7,8 @@
#include "base/at_exit.h"
#include "base/base_switches.h"
#include "base/command_line.h"
-#include "base/debug/trace_event.h"
#include "base/lazy_instance.h"
+#include "base/trace_event/trace_event.h"
#include "content/public/app/content_main.h"
#include "content/public/app/content_main_delegate.h"
#include "content/public/app/content_main_runner.h"
diff --git a/chromium/content/app/android/library_loader_hooks.cc b/chromium/content/app/android/library_loader_hooks.cc
index d09e21e9622..a67dd5d3a1f 100644
--- a/chromium/content/app/android/library_loader_hooks.cc
+++ b/chromium/content/app/android/library_loader_hooks.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/public/app/android_library_loader_hooks.h"
+#include "content/app/android/library_loader_hooks.h"
#include "base/android/base_jni_registrar.h"
#include "base/android/command_line_android.h"
@@ -11,10 +11,10 @@
#include "base/android/jni_string.h"
#include "base/base_switches.h"
#include "base/command_line.h"
-#include "base/debug/trace_event.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/strings/string_util.h"
+#include "base/trace_event/trace_event.h"
#include "base/tracked_objects.h"
#include "content/app/android/app_jni_registrar.h"
#include "content/browser/android/browser_jni_registrar.h"
@@ -22,9 +22,12 @@
#include "content/common/content_constants_internal.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/result_codes.h"
-#include "device/battery/android/battery_jni_registrar.h"
+#include "device/bluetooth/android/bluetooth_jni_registrar.h"
+#include "device/vibration/android/vibration_jni_registrar.h"
#include "media/base/android/media_jni_registrar.h"
+#include "media/midi/midi_jni_registrar.h"
#include "net/android/net_jni_registrar.h"
+#include "ui/android/ui_android_jni_registrar.h"
#include "ui/base/android/ui_base_jni_registrar.h"
#include "ui/gfx/android/gfx_jni_registrar.h"
#include "ui/gl/android/gl_jni_registrar.h"
@@ -63,12 +66,21 @@ bool EnsureJniRegistered(JNIEnv* env) {
if (!content::android::RegisterAppJni(env))
return false;
- if (!device::android::RegisterBatteryJni(env))
+ if (!device::android::RegisterBluetoothJni(env))
+ return false;
+
+ if (!device::android::RegisterVibrationJni(env))
return false;
if (!media::RegisterJni(env))
return false;
+ if (!media::midi::RegisterJni(env))
+ return false;
+
+ if (!ui::RegisterUIAndroidJni(env))
+ return false;
+
g_jni_init_done = true;
}
@@ -79,19 +91,19 @@ bool LibraryLoaded(JNIEnv* env, jclass clazz) {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kTraceStartup)) {
- base::debug::CategoryFilter category_filter(
+ base::trace_event::CategoryFilter category_filter(
command_line->GetSwitchValueASCII(switches::kTraceStartup));
- base::debug::TraceLog::GetInstance()->SetEnabled(
+ base::trace_event::TraceLog::GetInstance()->SetEnabled(
category_filter,
- base::debug::TraceLog::RECORDING_MODE,
- base::debug::TraceOptions());
+ base::trace_event::TraceLog::RECORDING_MODE,
+ base::trace_event::TraceOptions());
}
// Android's main browser loop is custom so we set the browser
// name here as early as possible.
TRACE_EVENT_BEGIN_ETW("BrowserMain", 0, "");
- base::debug::TraceLog::GetInstance()->SetProcessName("Browser");
- base::debug::TraceLog::GetInstance()->SetProcessSortIndex(
+ base::trace_event::TraceLog::GetInstance()->SetProcessName("Browser");
+ base::trace_event::TraceLog::GetInstance()->SetProcessSortIndex(
kTraceEventBrowserProcessSortIndex);
// Can only use event tracing after setting up the command line.
@@ -108,7 +120,7 @@ bool LibraryLoaded(JNIEnv* env, jclass clazz) {
VLOG(0) << "Chromium logging enabled: level = " << logging::GetMinLogLevel()
<< ", default verbosity = " << logging::GetVlogVerbosity();
- return EnsureJniRegistered(env);
+ return true;
}
} // namespace content
diff --git a/chromium/content/app/android/library_loader_hooks.h b/chromium/content/app/android/library_loader_hooks.h
new file mode 100644
index 00000000000..a1cb075afd3
--- /dev/null
+++ b/chromium/content/app/android/library_loader_hooks.h
@@ -0,0 +1,26 @@
+// 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_APP_ANDROID_LIBRARY_LOADER_HOOKS_H_
+#define CONTENT_APP_ANDROID_LIBRARY_LOADER_HOOKS_H_
+
+#include <jni.h>
+
+#include "base/basictypes.h"
+
+namespace content {
+
+// Register all content JNI functions now, rather than waiting for the process
+// of fully loading the native library to complete.
+bool EnsureJniRegistered(JNIEnv* env);
+
+// Do the intialization of content needed immediately after the native library
+// has loaded.
+// This is designed to be used as a hook function to be passed to
+// base::android::SetLibraryLoadedHook
+bool LibraryLoaded(JNIEnv* env, jclass clazz);
+
+} // namespace content
+
+#endif // CONTENT_APP_ANDROID_LIBRARY_LOADER_HOOKS_H_
diff --git a/chromium/content/app/content_main_runner.cc b/chromium/content/app/content_main_runner.cc
index 05e45bd791c..279536b09b9 100644
--- a/chromium/content/app/content_main_runner.cc
+++ b/chromium/content/app/content_main_runner.cc
@@ -10,22 +10,23 @@
#include "base/at_exit.h"
#include "base/command_line.h"
#include "base/debug/debugger.h"
-#include "base/debug/trace_event.h"
#include "base/files/file_path.h"
#include "base/i18n/icu_util.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
-#include "base/metrics/stats_table.h"
+#include "base/metrics/statistics_recorder.h"
#include "base/path_service.h"
#include "base/process/launch.h"
#include "base/process/memory.h"
#include "base/process/process_handle.h"
#include "base/profiler/alternate_timer.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/trace_event/trace_event.h"
#include "content/browser/browser_main.h"
#include "content/common/set_process_title.h"
#include "content/common/url_schemes.h"
@@ -51,11 +52,7 @@
#include "ui/base/ui_base_switches.h"
#ifdef V8_USE_EXTERNAL_STARTUP_DATA
-#include "gin/public/isolate_holder.h"
-#endif
-
-#if defined(OS_ANDROID)
-#include "content/public/common/content_descriptors.h"
+#include "gin/v8_initializer.h"
#endif
#if defined(USE_TCMALLOC)
@@ -81,12 +78,14 @@
#include <cstring>
#include "base/strings/string_number_conversions.h"
+#include "base/trace_event/trace_event_etw_export_win.h"
#include "ui/base/win/atl_module.h"
#include "ui/gfx/win/dpi.h"
#elif defined(OS_MACOSX)
#include "base/mac/scoped_nsautorelease_pool.h"
#if !defined(OS_IOS)
#include "base/power_monitor/power_monitor_device_source.h"
+#include "content/app/mac/mac_init.h"
#include "content/browser/mach_broker_mac.h"
#include "content/common/sandbox_init_mac.h"
#endif // !OS_IOS
@@ -99,6 +98,7 @@
#include "content/public/common/content_descriptors.h"
#if !defined(OS_MACOSX)
+#include "content/public/common/content_descriptors.h"
#include "content/public/common/zygote_fork_delegate_linux.h"
#endif
#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
@@ -211,38 +211,6 @@ static base::ProcessId GetBrowserPid(const base::CommandLine& command_line) {
}
#endif
-static void InitializeStatsTable(const base::CommandLine& command_line) {
- // Initialize the Stats Counters table. With this initialized,
- // the StatsViewer can be utilized to read counters outside of
- // Chrome. These lines can be commented out to effectively turn
- // counters 'off'. The table is created and exists for the life
- // of the process. It is not cleaned up.
- if (command_line.HasSwitch(switches::kEnableStatsTable)) {
- // NOTIMPLEMENTED: we probably need to shut this down correctly to avoid
- // leaking shared memory regions on posix platforms.
-#if defined(OS_POSIX)
- // Stats table is in the global file descriptors table on Posix.
- base::GlobalDescriptors* global_descriptors =
- base::GlobalDescriptors::GetInstance();
- base::FileDescriptor table_ident;
- if (global_descriptors->MaybeGet(kStatsTableSharedMemFd) != -1) {
- // Open the shared memory file descriptor passed by the browser process.
- table_ident = base::FileDescriptor(
- global_descriptors->Get(kStatsTableSharedMemFd), false);
- }
-#elif defined(OS_WIN)
- // Stats table is in a named segment on Windows. Use the PID to make this
- // unique on the system.
- std::string table_ident =
- base::StringPrintf("%s-%u", kStatsFilename,
- static_cast<unsigned int>(GetBrowserPid(command_line)));
-#endif
- base::StatsTable* stats_table =
- new base::StatsTable(table_ident, kStatsMaxThreads, kStatsMaxCounters);
- base::StatsTable::set_current(stats_table);
- }
-}
-
class ContentClientInitializer {
public:
static void Set(const std::string& process_type,
@@ -334,11 +302,6 @@ int RunZygote(const MainFunctionParams& main_function_params,
command_line.GetSwitchValueASCII(switches::kProcessType);
ContentClientInitializer::Set(process_type, delegate);
- // The StatsTable must be initialized in each process; we already
- // initialized for the browser process, now we need to initialize
- // within the new processes as well.
- InitializeStatsTable(command_line);
-
MainFunctionParams main_params(command_line);
main_params.zygote_child = true;
@@ -486,6 +449,7 @@ class ContentMainRunnerImpl : public ContentMainRunner {
int Initialize(const ContentMainParams& params) override {
ui_task_ = params.ui_task;
+ base::EnableTerminationOnOutOfMemory();
#if defined(OS_WIN)
RegisterInvalidParamHandler();
ui::win::CreateATLModuleIfNeeded();
@@ -535,6 +499,10 @@ class ContentMainRunnerImpl : public ContentMainRunner {
}
#endif // !OS_MACOSX && USE_TCMALLOC
+#if !defined(OS_IOS)
+ base::GlobalDescriptors* g_fds = base::GlobalDescriptors::GetInstance();
+#endif
+
// On Android,
// - setlocale() is not supported.
// - We do not override the signal handlers so that we can get
@@ -547,8 +515,6 @@ class ContentMainRunnerImpl : public ContentMainRunner {
setlocale(LC_ALL, "");
SetupSignalHandlers();
-
- base::GlobalDescriptors* g_fds = base::GlobalDescriptors::GetInstance();
g_fds->Set(kPrimaryIPCChannel,
kPrimaryIPCChannel + base::GlobalDescriptors::kBaseDescriptor);
#endif // !OS_ANDROID && !OS_IOS
@@ -556,7 +522,8 @@ class ContentMainRunnerImpl : public ContentMainRunner {
#if defined(OS_LINUX) || defined(OS_OPENBSD)
g_fds->Set(kCrashDumpSignal,
kCrashDumpSignal + base::GlobalDescriptors::kBaseDescriptor);
-#endif
+#endif // OS_LINUX || OS_OPENBSD
+
#endif // !OS_WIN
@@ -577,12 +544,16 @@ class ContentMainRunnerImpl : public ContentMainRunner {
}
#endif // !OS_ANDROID && !OS_IOS
-#if defined(OS_MACOSX)
+ // Don't create this loop on iOS, since the outer loop is already handled
+ // and a loop that's destroyed in shutdown interleaves badly with the event
+ // loop pool on iOS.
+#if defined(OS_MACOSX) && !defined(OS_IOS)
// We need this pool for all the objects created before we get to the
// event loop, but we don't want to leave them hanging around until the
// app quits. Each "main" needs to flush this pool right before it goes into
// its main event loop to get rid of the cruft.
autorelease_pool_.reset(new base::mac::ScopedNSAutoreleasePool());
+ InitializeMac();
#endif
// On Android, the command line is initialized when library is loaded and
@@ -600,9 +571,13 @@ class ContentMainRunnerImpl : public ContentMainRunner {
base::CommandLine::Init(argc, argv);
- if (!delegate_ || delegate_->ShouldEnableTerminationOnHeapCorruption())
- base::EnableTerminationOnHeapCorruption();
- base::EnableTerminationOnOutOfMemory();
+ base::EnableTerminationOnHeapCorruption();
+
+ // TODO(yiyaoliu, vadimt): Remove this once crbug.com/453640 is fixed.
+ // Enable profiler recording right after command line is initialized so that
+ // browser startup can be instrumented.
+ if (delegate_ && delegate_->ShouldEnableProfilerRecording())
+ tracked_objects::ScopedTracker::Enable();
#if !defined(OS_IOS)
SetProcessTitleFromCommandLine(argv);
@@ -653,14 +628,20 @@ class ContentMainRunnerImpl : public ContentMainRunner {
// Enable startup tracing asap to avoid early TRACE_EVENT calls being
// ignored.
if (command_line.HasSwitch(switches::kTraceStartup)) {
- base::debug::CategoryFilter category_filter(
+ base::trace_event::CategoryFilter category_filter(
command_line.GetSwitchValueASCII(switches::kTraceStartup));
- base::debug::TraceLog::GetInstance()->SetEnabled(
+ base::trace_event::TraceLog::GetInstance()->SetEnabled(
category_filter,
- base::debug::TraceLog::RECORDING_MODE,
- base::debug::TraceOptions(
- base::debug::RECORD_UNTIL_FULL));
+ base::trace_event::TraceLog::RECORDING_MODE,
+ base::trace_event::TraceOptions(
+ base::trace_event::RECORD_UNTIL_FULL));
}
+#if defined(OS_WIN)
+ // Enable exporting of events to ETW if requested on the command line.
+ if (command_line.HasSwitch(switches::kTraceExportEventsToETW))
+ base::trace_event::TraceEventETWExport::EnableETWExport();
+#endif // OS_WIN
+
#if !defined(OS_ANDROID)
// Android tracing started at the beginning of the method.
// Other OSes have to wait till we get here in order for all the memory
@@ -705,7 +686,7 @@ class ContentMainRunnerImpl : public ContentMainRunner {
}
#endif
-#if defined(USE_NSS)
+#if defined(USE_NSS_CERTS)
crypto::EarlySetupForNSSInit();
#endif
@@ -714,34 +695,52 @@ class ContentMainRunnerImpl : public ContentMainRunner {
RegisterContentSchemes(true);
#if defined(OS_ANDROID)
- int icudata_fd = base::GlobalDescriptors::GetInstance()->MaybeGet(
- kAndroidICUDataDescriptor);
- if (icudata_fd != -1)
- CHECK(base::i18n::InitializeICUWithFileDescriptor(icudata_fd));
- else
+ int icudata_fd = g_fds->MaybeGet(kAndroidICUDataDescriptor);
+ if (icudata_fd != -1) {
+ auto icudata_region = g_fds->GetRegion(kAndroidICUDataDescriptor);
+ CHECK(base::i18n::InitializeICUWithFileDescriptor(icudata_fd,
+ icudata_region));
+ } else {
CHECK(base::i18n::InitializeICU());
+ }
+#else
+ CHECK(base::i18n::InitializeICU());
+#endif // OS_ANDROID
-#ifdef V8_USE_EXTERNAL_STARTUP_DATA
- int v8_natives_fd = base::GlobalDescriptors::GetInstance()->MaybeGet(
- kV8NativesDataDescriptor);
- int v8_snapshot_fd = base::GlobalDescriptors::GetInstance()->MaybeGet(
- kV8SnapshotDataDescriptor);
+ base::StatisticsRecorder::Initialize();
+
+#if defined(V8_USE_EXTERNAL_STARTUP_DATA)
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+#if !defined(OS_ANDROID)
+ // kV8NativesDataDescriptor and kV8SnapshotDataDescriptor could be shared
+ // with child processes via file descriptors. On Android they are set in
+ // ChildProcessService::InternalInitChildProcess, otherwise set them here.
+ if (command_line.HasSwitch(switches::kV8NativesPassedByFD)) {
+ g_fds->Set(
+ kV8NativesDataDescriptor,
+ kV8NativesDataDescriptor + base::GlobalDescriptors::kBaseDescriptor);
+ }
+ if (command_line.HasSwitch(switches::kV8SnapshotPassedByFD)) {
+ g_fds->Set(
+ kV8SnapshotDataDescriptor,
+ kV8SnapshotDataDescriptor + base::GlobalDescriptors::kBaseDescriptor);
+ }
+#endif // !OS_ANDROID
+ int v8_natives_fd = g_fds->MaybeGet(kV8NativesDataDescriptor);
+ int v8_snapshot_fd = g_fds->MaybeGet(kV8SnapshotDataDescriptor);
if (v8_natives_fd != -1 && v8_snapshot_fd != -1) {
- CHECK(gin::IsolateHolder::LoadV8SnapshotFD(v8_natives_fd,
- v8_snapshot_fd));
+ auto v8_natives_region = g_fds->GetRegion(kV8NativesDataDescriptor);
+ auto v8_snapshot_region = g_fds->GetRegion(kV8SnapshotDataDescriptor);
+ CHECK(gin::V8Initializer::LoadV8SnapshotFromFD(
+ v8_natives_fd, v8_natives_region.offset, v8_natives_region.size,
+ v8_snapshot_fd, v8_snapshot_region.offset, v8_snapshot_region.size));
} else {
- CHECK(gin::IsolateHolder::LoadV8Snapshot());
+ CHECK(gin::V8Initializer::LoadV8Snapshot());
}
-#endif // V8_USE_EXTERNAL_STARTUP_DATA
-
#else
- CHECK(base::i18n::InitializeICU());
-#ifdef V8_USE_EXTERNAL_STARTUP_DATA
- CHECK(gin::IsolateHolder::LoadV8Snapshot());
-#endif // V8_USE_EXTERNAL_STARTUP_DATA
-#endif // OS_ANDROID
-
- InitializeStatsTable(command_line);
+ CHECK(gin::V8Initializer::LoadV8Snapshot());
+#endif // OS_POSIX && !OS_MACOSX
+#endif // V8_USE_EXTERNAL_STARTUP_DATA
if (delegate_)
delegate_->PreSandboxStartup();
@@ -811,7 +810,7 @@ class ContentMainRunnerImpl : public ContentMainRunner {
#endif // _CRTDBG_MAP_ALLOC
#endif // OS_WIN
-#if defined(OS_MACOSX)
+#if defined(OS_MACOSX) && !defined(OS_IOS)
autorelease_pool_.reset(NULL);
#endif
diff --git a/chromium/content/app/mac/mac_init.h b/chromium/content/app/mac/mac_init.h
new file mode 100644
index 00000000000..58e2af75980
--- /dev/null
+++ b/chromium/content/app/mac/mac_init.h
@@ -0,0 +1,17 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_APP_MAC_MAC_INIT_H_
+#define CONTENT_APP_MAC_MAC_INIT_H_
+
+#include "content/common/content_export.h"
+
+namespace content {
+
+// Perform any necessary Mac initialization.
+CONTENT_EXPORT void InitializeMac();
+
+} // namespace content
+
+#endif // CONTENT_APP_MAC_MAC_INIT_H_
diff --git a/chromium/content/app/mac/mac_init.mm b/chromium/content/app/mac/mac_init.mm
new file mode 100644
index 00000000000..042663c7674
--- /dev/null
+++ b/chromium/content/app/mac/mac_init.mm
@@ -0,0 +1,25 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/app/mac/mac_init.h"
+
+#include <Cocoa/Cocoa.h>
+
+#include "base/mac/mac_util.h"
+
+namespace content {
+
+void InitializeMac() {
+ [[NSUserDefaults standardUserDefaults] registerDefaults:@{
+ @"NSTreatUnknownArgumentsAsOpen": @"NO",
+ // CoreAnimation has poor performance and CoreAnimation and
+ // non-CoreAnimation exhibit window flickering when layers are not hosted
+ // in the window server, which is the default when not not using the
+ // 10.9 SDK.
+ // TODO: Remove this when we build with the 10.9 SDK.
+ @"NSWindowHostsLayersInWindowServer": @(base::mac::IsOSMavericksOrLater())
+ }];
+}
+
+} // namespace content
diff --git a/chromium/content/app/mojo/mojo_browsertest.cc b/chromium/content/app/mojo/mojo_browsertest.cc
index b516107333f..c7f179cd173 100644
--- a/chromium/content/app/mojo/mojo_browsertest.cc
+++ b/chromium/content/app/mojo/mojo_browsertest.cc
@@ -3,8 +3,8 @@
// found in the LICENSE file.
#include "content/public/test/content_browser_test.h"
-#include "mojo/public/c/system/core.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/mojo/src/mojo/public/c/system/core.h"
namespace content {
diff --git a/chromium/content/app/mojo/mojo_init.cc b/chromium/content/app/mojo/mojo_init.cc
index 755b6b19b9f..bf92f64886f 100644
--- a/chromium/content/app/mojo/mojo_init.cc
+++ b/chromium/content/app/mojo/mojo_init.cc
@@ -4,15 +4,33 @@
#include "content/app/mojo/mojo_init.h"
+#include "base/lazy_instance.h"
#include "base/memory/scoped_ptr.h"
-#include "mojo/edk/embedder/embedder.h"
-#include "mojo/edk/embedder/simple_platform_support.h"
+#include "ipc/ipc_channel.h"
+#include "third_party/mojo/src/mojo/edk/embedder/configuration.h"
+#include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
+#include "third_party/mojo/src/mojo/edk/embedder/simple_platform_support.h"
namespace content {
+namespace {
+
+class MojoInitializer {
+ public:
+ MojoInitializer() {
+ mojo::embedder::GetConfiguration()->max_message_num_bytes =
+ IPC::Channel::kMaximumMessageSize;
+ mojo::embedder::Init(scoped_ptr<mojo::embedder::PlatformSupport>(
+ new mojo::embedder::SimplePlatformSupport()));
+ }
+};
+
+base::LazyInstance<MojoInitializer>::Leaky mojo_initializer;
+
+} // namespace
+
void InitializeMojo() {
- mojo::embedder::Init(scoped_ptr<mojo::embedder::PlatformSupport>(
- new mojo::embedder::SimplePlatformSupport()));
+ mojo_initializer.Get();
}
} // namespace content
diff --git a/chromium/content/app/mojo/mojo_init.h b/chromium/content/app/mojo/mojo_init.h
index 4a4e5d4284c..fc4fa7b7dba 100644
--- a/chromium/content/app/mojo/mojo_init.h
+++ b/chromium/content/app/mojo/mojo_init.h
@@ -14,4 +14,4 @@ CONTENT_EXPORT void InitializeMojo();
} // namespace content
-#endif // CONTENT_COMMON_MOJO_MOJO_INIT_H_
+#endif // CONTENT_APP_MOJO_MOJO_INIT_H_
diff --git a/chromium/content/app/resources/content_resources.grd b/chromium/content/app/resources/content_resources.grd
index 9c4373b47a1..75913e3e35a 100644
--- a/chromium/content/app/resources/content_resources.grd
+++ b/chromium/content/app/resources/content_resources.grd
@@ -9,49 +9,7 @@
</outputs>
<release seq="1">
<structures fallback_to_low_resolution="true">
- <structure type="chrome_scaled_image" name="IDR_BROKENIMAGE" file="broken_image.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_PAUSE_BUTTON" file="mediaplayer_pause.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_PAUSE_BUTTON_HOVER" file="mediaplayer_pause_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_PAUSE_BUTTON_DOWN" file="mediaplayer_pause_down.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_PLAY_BUTTON" file="mediaplayer_play.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_PLAY_BUTTON_HOVER" file="mediaplayer_play_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_PLAY_BUTTON_DOWN" file="mediaplayer_play_down.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_PLAY_BUTTON_DISABLED" file="mediaplayer_play_disabled.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_SOUND_LEVEL3_BUTTON" file="mediaplayer_sound_level3.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_SOUND_LEVEL3_BUTTON_HOVER" file="mediaplayer_sound_level3_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_SOUND_LEVEL3_BUTTON_DOWN" file="mediaplayer_sound_level3_down.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_SOUND_LEVEL2_BUTTON" file="mediaplayer_sound_level2.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_SOUND_LEVEL2_BUTTON_HOVER" file="mediaplayer_sound_level2_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_SOUND_LEVEL2_BUTTON_DOWN" file="mediaplayer_sound_level2_down.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_SOUND_LEVEL1_BUTTON" file="mediaplayer_sound_level1.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_SOUND_LEVEL1_BUTTON_HOVER" file="mediaplayer_sound_level1_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_SOUND_LEVEL1_BUTTON_DOWN" file="mediaplayer_sound_level1_down.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_SOUND_LEVEL0_BUTTON" file="mediaplayer_sound_level0.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_SOUND_LEVEL0_BUTTON_HOVER" file="mediaplayer_sound_level0_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_SOUND_LEVEL0_BUTTON_DOWN" file="mediaplayer_sound_level0_down.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_SOUND_DISABLED" file="mediaplayer_sound_disabled.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_SLIDER_THUMB" file="mediaplayer_slider_thumb.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_SLIDER_THUMB_HOVER" file="mediaplayer_slider_thumb_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_SLIDER_THUMB_DOWN" file="mediaplayer_slider_thumb_down.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_VOLUME_SLIDER_THUMB" file="mediaplayer_volume_slider_thumb.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_VOLUME_SLIDER_THUMB_HOVER" file="mediaplayer_volume_slider_thumb_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_VOLUME_SLIDER_THUMB_DOWN" file="mediaplayer_volume_slider_thumb_down.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_VOLUME_SLIDER_THUMB_DISABLED" file="mediaplayer_volume_slider_thumb_disabled.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_CLOSEDCAPTION_BUTTON" file="mediaplayer_closedcaption.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_CLOSEDCAPTION_BUTTON_HOVER" file="mediaplayer_closedcaption_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_CLOSEDCAPTION_BUTTON_DOWN" file="mediaplayer_closedcaption_down.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_CLOSEDCAPTION_BUTTON_DISABLED" file="mediaplayer_closedcaption_disabled.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_FULLSCREEN_BUTTON" file="mediaplayer_fullscreen.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_FULLSCREEN_BUTTON_HOVER" file="mediaplayer_fullscreen_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_FULLSCREEN_BUTTON_DOWN" file="mediaplayer_fullscreen_down.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_FULLSCREEN_BUTTON_DISABLED" file="mediaplayer_fullscreen_disabled.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_CAST_BUTTON_OFF" file="mediaplayer_cast_off.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_CAST_BUTTON_ON" file="mediaplayer_cast_on.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_OVERLAY_CAST_BUTTON_OFF" file="mediaplayer_overlay_cast_off.png" />
- <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_OVERLAY_PLAY_BUTTON" file="mediaplayer_overlay_play.png" />
<if expr="is_macosx">
- <structure type="chrome_scaled_image" name="IDR_OVERHANG_PATTERN" file="overhang_pattern.png" />
- <structure type="chrome_scaled_image" name="IDR_OVERHANG_SHADOW" file="overhang_shadow.png" />
<structure type="chrome_scaled_image" name="IDR_ALIAS_CURSOR" file="alias_cursor.png" />
<structure type="chrome_scaled_image" name="IDR_CELL_CURSOR" file="cell_cursor.png" />
<structure type="chrome_scaled_image" name="IDR_EAST_RESIZE_CURSOR" file="east_resize_cursor.png" />
@@ -76,14 +34,6 @@
<structure type="chrome_scaled_image" name="IDR_ZOOMIN_CURSOR" file="zoom_in_cursor.png" />
<structure type="chrome_scaled_image" name="IDR_ZOOMOUT_CURSOR" file="zoom_out_cursor.png" />
</if>
- <structure type="chrome_scaled_image" name="IDR_PAN_SCROLL_ICON" file="pan_icon.png" />
- <structure type="chrome_scaled_image" name="IDR_SEARCH_CANCEL" file="search_cancel.png" />
- <structure type="chrome_scaled_image" name="IDR_SEARCH_CANCEL_PRESSED" file="search_cancel_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_SEARCH_MAGNIFIER" file="search_magnifier.png" />
- <structure type="chrome_scaled_image" name="IDR_SEARCH_MAGNIFIER_RESULTS" file="search_magnifier_results.png" />
- <structure type="chrome_scaled_image" name="IDR_TEXTAREA_RESIZER" file="textarea_resize_corner.png" />
- <structure type="chrome_scaled_image" name="IDR_PASSWORD_GENERATION_ICON" file="password_generation.png" />
- <structure type="chrome_scaled_image" name="IDR_PASSWORD_GENERATION_ICON_HOVER" file="password_generation_hover.png" />
</structures>
</release>
</grit>
diff --git a/chromium/content/app/resources/default_100_percent/broken_image.png b/chromium/content/app/resources/default_100_percent/broken_image.png
deleted file mode 100644
index ad76cc1965b..00000000000
--- a/chromium/content/app/resources/default_100_percent/broken_image.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_cast_off.png b/chromium/content/app/resources/default_100_percent/mediaplayer_cast_off.png
deleted file mode 100644
index 050022d2fe5..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_cast_off.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_cast_on.png b/chromium/content/app/resources/default_100_percent/mediaplayer_cast_on.png
deleted file mode 100644
index 4f24bf9ea69..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_cast_on.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_closedcaption.png b/chromium/content/app/resources/default_100_percent/mediaplayer_closedcaption.png
deleted file mode 100644
index a92b3d2051d..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_closedcaption.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_closedcaption_disabled.png b/chromium/content/app/resources/default_100_percent/mediaplayer_closedcaption_disabled.png
deleted file mode 100644
index 7ac1a898758..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_closedcaption_disabled.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_closedcaption_down.png b/chromium/content/app/resources/default_100_percent/mediaplayer_closedcaption_down.png
deleted file mode 100644
index 60da8a2973f..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_closedcaption_down.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_closedcaption_hover.png b/chromium/content/app/resources/default_100_percent/mediaplayer_closedcaption_hover.png
deleted file mode 100644
index a3e069f991e..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_closedcaption_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_fullscreen.png b/chromium/content/app/resources/default_100_percent/mediaplayer_fullscreen.png
deleted file mode 100644
index 713a87796d2..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_fullscreen.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_fullscreen_disabled.png b/chromium/content/app/resources/default_100_percent/mediaplayer_fullscreen_disabled.png
deleted file mode 100644
index f0958a64c0f..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_fullscreen_disabled.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_fullscreen_down.png b/chromium/content/app/resources/default_100_percent/mediaplayer_fullscreen_down.png
deleted file mode 100644
index 3a6cd5db13a..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_fullscreen_down.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_fullscreen_hover.png b/chromium/content/app/resources/default_100_percent/mediaplayer_fullscreen_hover.png
deleted file mode 100644
index 38e33304dfa..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_fullscreen_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_overlay_cast_off.png b/chromium/content/app/resources/default_100_percent/mediaplayer_overlay_cast_off.png
deleted file mode 100644
index e16f58e57a6..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_overlay_cast_off.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_overlay_play.png b/chromium/content/app/resources/default_100_percent/mediaplayer_overlay_play.png
deleted file mode 100644
index cfd48d74e28..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_overlay_play.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_pause.png b/chromium/content/app/resources/default_100_percent/mediaplayer_pause.png
deleted file mode 100644
index b488e97a66b..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_pause.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_pause_down.png b/chromium/content/app/resources/default_100_percent/mediaplayer_pause_down.png
deleted file mode 100644
index bf754e9c4bd..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_pause_down.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_pause_hover.png b/chromium/content/app/resources/default_100_percent/mediaplayer_pause_hover.png
deleted file mode 100644
index ac3334c4c88..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_pause_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_play.png b/chromium/content/app/resources/default_100_percent/mediaplayer_play.png
deleted file mode 100644
index 1e53d435809..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_play.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_play_disabled.png b/chromium/content/app/resources/default_100_percent/mediaplayer_play_disabled.png
deleted file mode 100644
index 8e1220018cc..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_play_disabled.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_play_down.png b/chromium/content/app/resources/default_100_percent/mediaplayer_play_down.png
deleted file mode 100644
index fa6a243429b..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_play_down.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_play_hover.png b/chromium/content/app/resources/default_100_percent/mediaplayer_play_hover.png
deleted file mode 100644
index a71c2f327a8..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_play_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_slider_thumb.png b/chromium/content/app/resources/default_100_percent/mediaplayer_slider_thumb.png
deleted file mode 100644
index 4cc24d1591a..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_slider_thumb.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_slider_thumb_down.png b/chromium/content/app/resources/default_100_percent/mediaplayer_slider_thumb_down.png
deleted file mode 100644
index 483101d9067..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_slider_thumb_down.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_slider_thumb_hover.png b/chromium/content/app/resources/default_100_percent/mediaplayer_slider_thumb_hover.png
deleted file mode 100644
index 2a968424f5d..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_slider_thumb_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_sound_disabled.png b/chromium/content/app/resources/default_100_percent/mediaplayer_sound_disabled.png
deleted file mode 100644
index 38fa4baaa95..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_sound_disabled.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_sound_level0.png b/chromium/content/app/resources/default_100_percent/mediaplayer_sound_level0.png
deleted file mode 100644
index 22d6a109de7..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_sound_level0.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_sound_level0_down.png b/chromium/content/app/resources/default_100_percent/mediaplayer_sound_level0_down.png
deleted file mode 100644
index d956e5810c2..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_sound_level0_down.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_sound_level0_hover.png b/chromium/content/app/resources/default_100_percent/mediaplayer_sound_level0_hover.png
deleted file mode 100644
index 56214a1494c..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_sound_level0_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_sound_level1.png b/chromium/content/app/resources/default_100_percent/mediaplayer_sound_level1.png
deleted file mode 100644
index 2c6809abb1b..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_sound_level1.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_sound_level1_down.png b/chromium/content/app/resources/default_100_percent/mediaplayer_sound_level1_down.png
deleted file mode 100644
index faa188841ec..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_sound_level1_down.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_sound_level1_hover.png b/chromium/content/app/resources/default_100_percent/mediaplayer_sound_level1_hover.png
deleted file mode 100644
index 1fdaf21003a..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_sound_level1_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_sound_level2.png b/chromium/content/app/resources/default_100_percent/mediaplayer_sound_level2.png
deleted file mode 100644
index e98c51d306c..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_sound_level2.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_sound_level2_down.png b/chromium/content/app/resources/default_100_percent/mediaplayer_sound_level2_down.png
deleted file mode 100644
index 37f5d76942c..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_sound_level2_down.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_sound_level2_hover.png b/chromium/content/app/resources/default_100_percent/mediaplayer_sound_level2_hover.png
deleted file mode 100644
index e44356bb2ef..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_sound_level2_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_sound_level3.png b/chromium/content/app/resources/default_100_percent/mediaplayer_sound_level3.png
deleted file mode 100644
index 05caa642439..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_sound_level3.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_sound_level3_down.png b/chromium/content/app/resources/default_100_percent/mediaplayer_sound_level3_down.png
deleted file mode 100644
index db384048586..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_sound_level3_down.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_sound_level3_hover.png b/chromium/content/app/resources/default_100_percent/mediaplayer_sound_level3_hover.png
deleted file mode 100644
index 838b07f34d7..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_sound_level3_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_volume_slider_thumb.png b/chromium/content/app/resources/default_100_percent/mediaplayer_volume_slider_thumb.png
deleted file mode 100644
index c4620f54259..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_volume_slider_thumb.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_volume_slider_thumb_disabled.png b/chromium/content/app/resources/default_100_percent/mediaplayer_volume_slider_thumb_disabled.png
deleted file mode 100644
index d32434b6d2a..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_volume_slider_thumb_disabled.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_volume_slider_thumb_down.png b/chromium/content/app/resources/default_100_percent/mediaplayer_volume_slider_thumb_down.png
deleted file mode 100644
index 98ee8509264..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_volume_slider_thumb_down.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/mediaplayer_volume_slider_thumb_hover.png b/chromium/content/app/resources/default_100_percent/mediaplayer_volume_slider_thumb_hover.png
deleted file mode 100644
index 93cca9b325f..00000000000
--- a/chromium/content/app/resources/default_100_percent/mediaplayer_volume_slider_thumb_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/overhang_pattern.png b/chromium/content/app/resources/default_100_percent/overhang_pattern.png
deleted file mode 100644
index 838e87c3238..00000000000
--- a/chromium/content/app/resources/default_100_percent/overhang_pattern.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/overhang_shadow.png b/chromium/content/app/resources/default_100_percent/overhang_shadow.png
deleted file mode 100644
index 4e0fc4b720c..00000000000
--- a/chromium/content/app/resources/default_100_percent/overhang_shadow.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/pan_icon.png b/chromium/content/app/resources/default_100_percent/pan_icon.png
deleted file mode 100644
index e07d96255b8..00000000000
--- a/chromium/content/app/resources/default_100_percent/pan_icon.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/password_generation.png b/chromium/content/app/resources/default_100_percent/password_generation.png
deleted file mode 100644
index 2b45ac3ac26..00000000000
--- a/chromium/content/app/resources/default_100_percent/password_generation.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/password_generation_hover.png b/chromium/content/app/resources/default_100_percent/password_generation_hover.png
deleted file mode 100644
index a832cdc81ed..00000000000
--- a/chromium/content/app/resources/default_100_percent/password_generation_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/search_cancel.png b/chromium/content/app/resources/default_100_percent/search_cancel.png
deleted file mode 100644
index 1291bf84302..00000000000
--- a/chromium/content/app/resources/default_100_percent/search_cancel.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/search_cancel_pressed.png b/chromium/content/app/resources/default_100_percent/search_cancel_pressed.png
deleted file mode 100644
index 4abc0fd4ac0..00000000000
--- a/chromium/content/app/resources/default_100_percent/search_cancel_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/search_magnifier.png b/chromium/content/app/resources/default_100_percent/search_magnifier.png
deleted file mode 100644
index 0aea5daeded..00000000000
--- a/chromium/content/app/resources/default_100_percent/search_magnifier.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/search_magnifier_results.png b/chromium/content/app/resources/default_100_percent/search_magnifier_results.png
deleted file mode 100644
index 2f773c06943..00000000000
--- a/chromium/content/app/resources/default_100_percent/search_magnifier_results.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_100_percent/textarea_resize_corner.png b/chromium/content/app/resources/default_100_percent/textarea_resize_corner.png
deleted file mode 100644
index a379bdd3053..00000000000
--- a/chromium/content/app/resources/default_100_percent/textarea_resize_corner.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_200_percent/broken_image.png b/chromium/content/app/resources/default_200_percent/broken_image.png
deleted file mode 100644
index 45edebcd515..00000000000
--- a/chromium/content/app/resources/default_200_percent/broken_image.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_200_percent/pan_icon.png b/chromium/content/app/resources/default_200_percent/pan_icon.png
deleted file mode 100644
index d9c0c1592ac..00000000000
--- a/chromium/content/app/resources/default_200_percent/pan_icon.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/resources/default_200_percent/textarea_resize_corner.png b/chromium/content/app/resources/default_200_percent/textarea_resize_corner.png
deleted file mode 100644
index 77fa3cac8ba..00000000000
--- a/chromium/content/app/resources/default_200_percent/textarea_resize_corner.png
+++ /dev/null
Binary files differ
diff --git a/chromium/content/app/startup_helper_win.cc b/chromium/content/app/startup_helper_win.cc
index ab85a43e806..187a0f08702 100644
--- a/chromium/content/app/startup_helper_win.cc
+++ b/chromium/content/app/startup_helper_win.cc
@@ -43,7 +43,8 @@ void InitializeSandboxInfo(sandbox::SandboxInterfaceInfo* info) {
// Ensure the proper mitigations are enforced for the browser process.
sandbox::ApplyProcessMitigationsToCurrentProcess(
sandbox::MITIGATION_DEP |
- sandbox::MITIGATION_DEP_NO_ATL_THUNK);
+ sandbox::MITIGATION_DEP_NO_ATL_THUNK |
+ sandbox::MITIGATION_HARDEN_TOKEN_IL_POLICY);
}
}
@@ -52,8 +53,6 @@ void InitializeSandboxInfo(sandbox::SandboxInterfaceInfo* info) {
void RegisterInvalidParamHandler() {
_set_invalid_parameter_handler(InvalidParameter);
_set_purecall_handler(PureCall);
- // Also enable the new handler for malloc() based failures.
- _set_new_mode(1);
}
void SetupCRT(const base::CommandLine& command_line) {
diff --git a/chromium/content/app/strings/content_strings.grd b/chromium/content/app/strings/content_strings.grd
index 0f864cb5d76..e853a97fedb 100644
--- a/chromium/content/app/strings/content_strings.grd
+++ b/chromium/content/app/strings/content_strings.grd
@@ -344,6 +344,15 @@ below:
<message name="IDS_AX_ROLE_COMPLEMENTARY" desc="accessibility role description for complementary">
complementary
</message>
+ <message name="IDS_AX_ROLE_DESCRIPTION_DETAIL" desc="accessibility role description for a definition">
+ definition
+ </message>
+ <message name="IDS_AX_ROLE_DESCRIPTION_LIST" desc="accessibility role description for a definition list">
+ definition list
+ </message>
+ <message name="IDS_AX_ROLE_DESCRIPTION_TERM" desc="accessibility role description for description term(as in a description list)">
+ term
+ </message>
<message name="IDS_AX_ROLE_WEB_AREA" desc="accessibility role description for web area">
HTML content
</message>
@@ -359,6 +368,9 @@ below:
<message name="IDS_AX_ROLE_HEADING" desc="accessibility role description for headings">
heading
</message>
+ <message name="IDS_AX_ROLE_FIGURE" desc="accessibility role description for figure">
+ figure
+ </message>
<message name="IDS_AX_ROLE_REGION" desc="accessibility role description for region">
region
</message>
@@ -382,6 +394,21 @@ below:
<message name="IDS_AX_ROLE_NAVIGATIONAL_LINK" desc="accessibility role description for group of navigational links.">
navigation
</message>
+ <message name="IDS_AX_ROLE_FORM" desc="accessibility role description for form">
+ form
+ </message>
+ <message name="IDS_AX_ROLE_MATH" desc="accessibility role description for math">
+ math
+ </message>
+ <message name="IDS_AX_ROLE_STATUS" desc="accessibility role description for status">
+ status
+ </message>
+ <message name="IDS_AX_ROLE_SEARCH_BOX" desc="accessibility role description for search text field">
+ search text field
+ </message>
+ <message name="IDS_AX_ROLE_SWITCH" desc="accessibility role description for switch">
+ switch
+ </message>
<message name="IDS_AX_BUTTON_ACTION_VERB" desc="Verb stating the action that will occur when a button is pressed, as used by accessibility.">
press
@@ -514,7 +541,11 @@ below:
pause playback
</message>
- <message name="IDS_AX_MEDIA_SLIDER_HELP" desc="accessibility help description for timeline slider">
+ <message name="IDS_AX_MEDIA_AUDIO_SLIDER_HELP" desc="accessibility help description for audio timeline slider">
+ audio time scrubber
+ </message>
+
+ <message name="IDS_AX_MEDIA_VIDEO_SLIDER_HELP" desc="accessibility help description for video timeline slider">
movie time scrubber
</message>
@@ -718,8 +749,8 @@ below:
Please lengthen this text to <ph name="MIN_CHARACTERS">$2<ex>101</ex></ph> characters or more (you are currently using <ph name="CURRENT_LENGTH">$1<ex>100</ex></ph> characters).
</message>
- <message name="IDS_PLUGIN_INITIALIZATION_ERROR" desc="A message displayed when a plug-in failed to load">
- Couldn't load plug-in.
+ <message name="IDS_PLUGIN_INITIALIZATION_ERROR" desc="A message displayed when a plugin failed to load">
+ Couldn't load plugin.
</message>
</messages>
diff --git a/chromium/content/browser/BUILD.gn b/chromium/content/browser/BUILD.gn
index a420b9e9826..78fa0ee7969 100644
--- a/chromium/content/browser/BUILD.gn
+++ b/chromium/content/browser/BUILD.gn
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/crypto.gni")
import("//build/config/features.gni")
import("//build/config/ui.gni")
import("//content/browser/browser.gni")
@@ -20,12 +21,17 @@ source_set("browser") {
deps = [
"//base",
"//base:base_static",
+ "//components/mime_util",
"//content:resources",
- "//content/browser/service_worker:proto",
+ "//content/browser/background_sync:background_sync_proto",
+ "//content/browser/cache_storage:cache_storage_proto",
+ "//content/browser/notifications:notification_proto",
+ "//content/browser/service_worker:service_worker_proto",
"//content/browser/speech/proto",
"//content/public/common:common_sources",
"//crypto",
"//device/battery",
+ "//device/vibration",
"//google_apis",
"//net",
"//skia",
@@ -38,6 +44,7 @@ source_set("browser") {
"//ui/accessibility",
"//ui/accessibility:ax_gen",
"//ui/base",
+ "//ui/base/ime",
"//ui/events",
"//ui/events:gesture_detection",
"//ui/gfx",
@@ -68,7 +75,8 @@ source_set("browser") {
} else {
# Normal non-iOS sources get everything.
sources = rebase_path(content_browser_gypi_values.private_browser_sources,
- ".", "//content")
+ ".",
+ "//content")
# TODO(GYP) these generated files are listed as sources in content_browser.
# This is a bit suspicious. The GN grit template will make a source set
@@ -77,45 +85,49 @@ source_set("browser") {
#
# Need this annoying rebase_path call to match what happened with the
# sources.
- sources -= rebase_path([
- "$root_gen_dir/webkit/grit/devtools_resources.h",
- "$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/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",
- ], ".")
+ sources -= rebase_path(
+ [
+ "$root_gen_dir/blink/grit/devtools_resources.h",
+ "$root_gen_dir/blink/grit/devtools_resources_map.cc",
+ "$root_gen_dir/blink/grit/devtools_resources_map.h",
+ "$root_gen_dir/content/browser/tracing/grit/tracing_resources.h",
+ "$root_gen_dir/ui/resources/grit/webui_resources_map.cc",
+ ],
+ ".")
# Non-iOS deps.
deps += [
"//cc",
"//cc/surfaces",
+ "//components/scheduler:common",
"//content/app/resources",
"//content/app/strings",
+ "//content/browser/devtools:gen_devtools_protocol_handler",
"//content/browser/devtools:resources",
"//content/common:mojo_bindings",
"//content/public/common:mojo_bindings",
- "//mojo/public/cpp/bindings",
- "//mojo/public/interfaces/application",
- "//mojo/public/js",
- "//net:http_server",
+ "//device/bluetooth",
+ "//mojo/application/public/interfaces",
"//storage/browser",
"//storage/common",
+ "//third_party/WebKit/public:image_resources",
"//third_party/WebKit/public:resources",
"//third_party/angle:commit_id",
"//third_party/icu",
"//third_party/leveldatabase",
"//third_party/libyuv",
+ "//third_party/mojo/src/mojo/public/cpp/bindings",
+ "//third_party/mojo/src/mojo/public/js",
+ "//ui/events/blink",
"//ui/resources",
"//ui/surface",
+ "//ui/touch_selection",
]
}
configs += [
"//content:content_implementation",
+ "//third_party/WebKit/public:debug_devtools",
]
if (toolkit_views) {
@@ -130,9 +142,9 @@ source_set("browser") {
deps += [ "//third_party/power_gadget" ]
} else {
sources += [
- "power_profiler/power_data_provider_dummy.cc",
"file_descriptor_info_impl.cc",
"file_descriptor_info_impl.h",
+ "power_profiler/power_data_provider_dummy.cc",
]
sources -= [ "renderer_host/web_input_event_aurawin.cc" ]
}
@@ -145,12 +157,12 @@ source_set("browser") {
deps += [ "//printing" ]
}
-# TODO(GYP)
-# ['OS!="ios" and chrome_multiple_dll!=1', {
-# 'dependencies': [
-# '../third_party/WebKit/public/blink.gyp:blink',
-# ],
-# }],
+ # TODO(GYP)
+ # ['OS!="ios" and chrome_multiple_dll!=1', {
+ # 'dependencies': [
+ # '../third_party/WebKit/public/blink.gyp:blink',
+ # ],
+ # }],
if (!is_mac && !is_ios) {
deps += [ "//sandbox" ]
}
@@ -160,7 +172,8 @@ source_set("browser") {
if (enable_webrtc) {
sources += rebase_path(content_browser_gypi_values.webrtc_browser_sources,
- ".", "//content")
+ ".",
+ "//content")
deps += [ "//jingle:jingle_glue" ]
if (is_linux) {
deps += [ "//third_party/libjingle:libjingle_webrtc" ]
@@ -174,6 +187,8 @@ source_set("browser") {
]
if (use_aura) {
sources += [
+ "media/capture/aura_window_capture_machine.cc",
+ "media/capture/aura_window_capture_machine.h",
"media/capture/desktop_capture_device_aura.cc",
"media/capture/desktop_capture_device_aura.h",
]
@@ -202,17 +217,19 @@ source_set("browser") {
"dinput8.lib",
"dwmapi.lib",
"dxguid.lib",
+ "oleacc.lib",
"sensorsapi.lib",
"portabledeviceguids.lib",
]
+
# TODI(GYP)
-# 'msvs_settings': {
-# 'VCLinkerTool': {
-# 'DelayLoadDLLs': [
-# 'dinput8.dll',
-# 'user32.dll',
-# 'dwmapi.dll',
-# ],
+ # 'msvs_settings': {
+ # 'VCLinkerTool': {
+ # 'DelayLoadDLLs': [
+ # 'dinput8.dll',
+ # 'user32.dll',
+ # 'dwmapi.dll',
+ # ],
}
if (is_linux) {
@@ -220,7 +237,7 @@ source_set("browser") {
}
if (use_udev) {
- configs += [ "//build/config/linux:udev" ]
+ deps += [ "//device/udev_linux" ]
} else {
# Remove udev-specific sources.
sources -= [
@@ -239,10 +256,11 @@ source_set("browser") {
if (enable_plugins) {
sources += rebase_path(content_browser_gypi_values.plugin_browser_sources,
- ".", "//content")
+ ".",
+ "//content")
deps += [
- "//ppapi:ppapi_ipc",
- "//ppapi:ppapi_shared",
+ "//ppapi/proxy:ipc",
+ "//ppapi/shared_impl",
]
if (!use_ozone || use_pango) {
sources -= [ "renderer_host/pepper/pepper_truetype_font_list_ozone.cc" ]
@@ -258,16 +276,17 @@ source_set("browser") {
if (use_x11) {
configs += [ "//build/config/linux:x11" ]
+ deps += [ "//ui/gfx/x" ]
}
# 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", ]
+ sources -= [ "power_save_blocker_ozone.cc" ]
}
if (is_chromeos || !use_x11) {
- sources -= [ "power_save_blocker_x11.cc", ]
+ sources -= [ "power_save_blocker_x11.cc" ]
}
# Dealing with *wifi_data_provider_*.cc is also a bit complicated given
@@ -288,16 +307,16 @@ source_set("browser") {
if (is_android) {
sources += rebase_path(content_browser_gypi_values.android_browser_sources,
- ".", "//content")
+ ".",
+ "//content")
sources -= [
"browser_ipc_logging.cc",
"device_sensors/data_fetcher_shared_memory_default.cc",
- "font_list_async.cc",
"geolocation/network_location_provider.cc",
"geolocation/network_location_provider.h",
"geolocation/network_location_request.cc",
"geolocation/network_location_request.h",
- "renderer_host/native_web_keyboard_event.cc",
+ "renderer_host/begin_frame_observer_proxy.cc",
"tracing/tracing_ui.cc",
"tracing/tracing_ui.h",
@@ -327,6 +346,7 @@ source_set("browser") {
"//content/public/android:jni",
"//media",
"//mojo/android:libsystem_java",
+ "//ui/android",
]
libs += [ "jnigraphics" ]
}
@@ -337,10 +357,20 @@ source_set("browser") {
"geolocation/empty_wifi_data_provider.cc",
"geolocation/empty_wifi_data_provider.h",
]
- libs += [ "bsm" ]
+ deps += [
+ "//sandbox/mac:sandbox",
+ "//third_party/mozilla",
+ "//third_party/sudden_motion_sensor",
+ "//ui/accelerated_widget_mac",
+ ]
+ libs += [
+ "bsm",
+ "QTKit.framework",
+ ]
}
if (is_chromeos) {
+ sources -= [ "device_sensors/data_fetcher_shared_memory_default.cc" ]
deps += [
"//chromeos",
"//chromeos:power_manager_proto",
@@ -350,11 +380,14 @@ source_set("browser") {
if (use_aura) {
deps += [
"//ui/aura",
+ "//ui/aura_extra",
"//ui/strings",
"//ui/wm",
]
} else { # Not aura.
sources -= [
+ "renderer_host/compositor_resize_lock_aura.cc",
+ "renderer_host/compositor_resize_lock_aura.h",
"renderer_host/input/synthetic_gesture_target_aura.cc",
"renderer_host/input/synthetic_gesture_target_aura.h",
"renderer_host/native_web_keyboard_event_aura.cc",
@@ -366,14 +399,14 @@ source_set("browser") {
"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/overscroll_window_animation.cc",
+ "web_contents/aura/overscroll_window_animation.h",
+ "web_contents/aura/overscroll_window_delegate.cc",
+ "web_contents/aura/overscroll_window_delegate.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",
@@ -382,9 +415,10 @@ source_set("browser") {
}
if (use_aura || is_mac) {
- sources += rebase_path(
- content_browser_gypi_values.compositor_browser_sources,
- ".", "//content")
+ sources +=
+ rebase_path(content_browser_gypi_values.compositor_browser_sources,
+ ".",
+ "//content")
if (!use_x11) {
sources -= [
"compositor/software_output_device_x11.cc",
@@ -394,8 +428,8 @@ source_set("browser") {
if (!use_ozone) {
sources -= [
- "compositor/overlay_candidate_validator_ozone.cc",
- "compositor/overlay_candidate_validator_ozone.h",
+ "compositor/browser_compositor_overlay_candidate_validator_ozone.cc",
+ "compositor/browser_compositor_overlay_candidate_validator_ozone.h",
"compositor/software_output_device_ozone.cc",
"compositor/software_output_device_ozone.h",
]
@@ -422,4 +456,12 @@ source_set("browser") {
"media/media_web_contents_observer.h",
]
}
+
+ if (is_linux && use_openssl) {
+ deps += [ "//third_party/boringssl" ]
+ }
+
+ if (enable_media_mojo_renderer) {
+ deps += [ "//media/mojo/services:renderer_service" ]
+ }
}
diff --git a/chromium/content/browser/DEPS b/chromium/content/browser/DEPS
index c99434f0d7d..e673dcc966e 100644
--- a/chromium/content/browser/DEPS
+++ b/chromium/content/browser/DEPS
@@ -1,21 +1,26 @@
include_rules = [
+ # Allow inclusion of specific components that we depend on. We may only
+ # depend on components which we share with the mojo html_viewer.
+ "+components/mime_util",
+ "+components/scheduler/common",
+ "+components/tracing",
+
"+content/app/strings/grit", # For generated headers
"+content/public/browser",
"+device/battery", # For battery status service.
+ "+device/vibration", # For Vibration API
"+media/audio", # For audio input for speech input feature.
"+media/base", # For Android JNI registration.
+ "+media/filters", # For reporting GPU decoding UMA.
"+media/midi", # For Web MIDI API
+ "+media/mojo", # For mojo media services.
"+media/video", # For Video Device monitoring in Mac.
"+mojo",
"+sql",
+ "+ui/aura_extra",
"+ui/webui",
"+win8/util",
- # TODO(joi): This was misplaced; need to move it somewhere else,
- # since //content shouldn't depend on //components, which is a layer
- # 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.
@@ -32,44 +37,43 @@ include_rules = [
"+chromeos",
"+third_party/cros_system_api",
- "-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/WebCircularGeofencingRegion.h",
"+third_party/WebKit/public/platform/WebCursorInfo.h",
+ "+third_party/WebKit/public/platform/WebDisplayMode.h",
+ "+third_party/WebKit/public/platform/WebFocusType.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/WebReferrerPolicy.h",
+ "+third_party/WebKit/public/platform/WebScreenInfo.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",
+ "+third_party/WebKit/public/platform/modules/indexeddb/WebIDBDatabaseException.h",
+ "+third_party/WebKit/public/platform/modules/indexeddb/WebIDBTypes.h",
+ "+third_party/WebKit/public/platform/modules/notifications/WebNotificationPermission.h",
+ "+third_party/WebKit/public/platform/modules/push_messaging/WebPushPermissionStatus.h",
"+third_party/WebKit/public/web/mac/WebScrollbarTheme.h",
"+third_party/WebKit/public/web/WebAXEnums.h",
"+third_party/WebKit/public/web/WebCompositionUnderline.h",
"+third_party/WebKit/public/web/WebConsoleMessage.h",
"+third_party/WebKit/public/web/WebContentSecurityPolicy.h",
+ "+third_party/WebKit/public/web/WebDeviceEmulationParams.h",
"+third_party/WebKit/public/web/WebDragOperation.h",
"+third_party/WebKit/public/web/WebDragStatus.h",
"+third_party/WebKit/public/web/WebFindOptions.h",
"+third_party/WebKit/public/web/WebInputEvent.h",
"+third_party/WebKit/public/web/WebMediaPlayerAction.h",
- "+third_party/WebKit/public/web/WebNotificationPresenter.h",
"+third_party/WebKit/public/web/WebPageSerializerClient.h",
"+third_party/WebKit/public/web/WebPluginAction.h",
"+third_party/WebKit/public/web/WebPopupType.h",
diff --git a/chromium/content/browser/OWNERS b/chromium/content/browser/OWNERS
index 51f5662fd5a..bf262eb3cc9 100644
--- a/chromium/content/browser/OWNERS
+++ b/chromium/content/browser/OWNERS
@@ -2,6 +2,7 @@ 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_unittest.cc=tsepez@chromium.org
per-file child_process_security_unittest.cc=creis@chromium.org
+per-file host_zoom_*=wjmaclean@chromium.org
per-file power_save_blocker_chromeos.cc=derat@chromium.org
# Mac Sandbox profiles.
diff --git a/chromium/content/browser/accessibility/accessibility_event_recorder.cc b/chromium/content/browser/accessibility/accessibility_event_recorder.cc
new file mode 100644
index 00000000000..01c5b0d7400
--- /dev/null
+++ b/chromium/content/browser/accessibility/accessibility_event_recorder.cc
@@ -0,0 +1,26 @@
+// Copyright 2014 The Chromium Authors. 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/port.h"
+#include "content/browser/accessibility/accessibility_event_recorder.h"
+
+namespace content {
+
+AccessibilityEventRecorder::AccessibilityEventRecorder(
+ BrowserAccessibilityManager* manager)
+ : manager_(manager) {
+}
+
+AccessibilityEventRecorder::~AccessibilityEventRecorder() {
+}
+
+#if !defined(OS_WIN) && !defined(OS_MACOSX)
+// static
+AccessibilityEventRecorder* AccessibilityEventRecorder::Create(
+ BrowserAccessibilityManager* manager) {
+ return new AccessibilityEventRecorder(manager);
+}
+#endif
+
+} // namespace content
diff --git a/chromium/content/browser/accessibility/accessibility_event_recorder.h b/chromium/content/browser/accessibility/accessibility_event_recorder.h
new file mode 100644
index 00000000000..d214f372b45
--- /dev/null
+++ b/chromium/content/browser/accessibility/accessibility_event_recorder.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_ACCESSIBILITY_ACCESSIBILITY_EVENT_RECORDER_H_
+#define CONTENT_BROWSER_ACCESSIBILITY_ACCESSIBILITY_EVENT_RECORDER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "content/common/content_export.h"
+
+namespace content {
+
+class BrowserAccessibilityManager;
+
+// Listens for native accessibility events fired by a given
+// BrowserAccessibilityManager and saves human-readable log strings for
+// each event fired to a vector. Construct an instance of this class to
+// begin listening, call GetEventLogs() to get all of the logs so far, and
+// destroy it to stop listening.
+//
+// A log string should be of the form "<event> on <node>" where <event> is
+// the name of the event fired (platform-specific) and <node> is information
+// about the accessibility node on which the event was fired, for example its
+// role and name.
+//
+// The implementation is highly platform-specific; a subclass is needed for
+// each platform does most of the work.
+class AccessibilityEventRecorder {
+ public:
+ // Construct the right platform-specific subclass.
+ static AccessibilityEventRecorder* Create(
+ BrowserAccessibilityManager* manager);
+ virtual ~AccessibilityEventRecorder();
+
+ // Access the vector of human-readable event logs, one string per event.
+ const std::vector<std::string>& event_logs() { return event_logs_; }
+
+ protected:
+ explicit AccessibilityEventRecorder(BrowserAccessibilityManager* manager);
+
+ BrowserAccessibilityManager* manager_;
+ std::vector<std::string> event_logs_;
+
+ DISALLOW_COPY_AND_ASSIGN(AccessibilityEventRecorder);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_ACCESSIBILITY_ACCESSIBILITY_EVENT_RECORDER_H_
diff --git a/chromium/content/browser/accessibility/accessibility_event_recorder_mac.mm b/chromium/content/browser/accessibility/accessibility_event_recorder_mac.mm
new file mode 100644
index 00000000000..95967f43b64
--- /dev/null
+++ b/chromium/content/browser/accessibility/accessibility_event_recorder_mac.mm
@@ -0,0 +1,153 @@
+// 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/accessibility/accessibility_event_recorder.h"
+
+#include <string>
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/mac/foundation_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/browser/accessibility/browser_accessibility_manager.h"
+
+namespace content {
+
+// Implementation of AccessibilityEventRecorder that uses AXObserver to
+// watch for NSAccessibility events.
+class AccessibilityEventRecorderMac : public AccessibilityEventRecorder {
+ public:
+ explicit AccessibilityEventRecorderMac(BrowserAccessibilityManager* manager);
+ ~AccessibilityEventRecorderMac() override;
+
+ // Callback executed every time we receive an event notification.
+ void EventReceived(AXUIElementRef element, CFStringRef notification);
+
+ private:
+ // Add one notification to the list of notifications monitored by our
+ // observer.
+ void AddNotification(NSString* notification);
+
+ // Convenience function to get the value of an AX attribute from
+ // an AXUIElementRef as a string.
+ std::string GetAXAttributeValue(
+ AXUIElementRef element, NSString* attribute_name);
+
+ // The AXUIElement for the Chrome application.
+ AXUIElementRef application_;
+
+ // The AXObserver we use to monitor AX notifications.
+ AXObserverRef observer_ref_;
+};
+
+// Callback function registered using AXObserverCreate.
+static void EventReceivedThunk(
+ AXObserverRef observer_ref,
+ AXUIElementRef element,
+ CFStringRef notification,
+ void *refcon) {
+ AccessibilityEventRecorderMac* this_ptr =
+ static_cast<AccessibilityEventRecorderMac*>(refcon);
+ this_ptr->EventReceived(element, notification);
+}
+
+// static
+AccessibilityEventRecorder* AccessibilityEventRecorder::Create(
+ BrowserAccessibilityManager* manager) {
+ return new AccessibilityEventRecorderMac(manager);
+}
+
+AccessibilityEventRecorderMac::AccessibilityEventRecorderMac(
+ BrowserAccessibilityManager* manager)
+ : AccessibilityEventRecorder(manager),
+ observer_ref_(0) {
+ // Get Chrome's process id.
+ int pid = [[NSProcessInfo processInfo] processIdentifier];
+ if (kAXErrorSuccess != AXObserverCreate(
+ pid, EventReceivedThunk, &observer_ref_)) {
+ LOG(FATAL) << "Failed to create AXObserverRef";
+ }
+
+ // Get an AXUIElement for the Chrome application.
+ application_ = AXUIElementCreateApplication(pid);
+ if (!application_)
+ LOG(FATAL) << "Failed to create AXUIElement for application.";
+
+ // Add the notifications we care about to the observer.
+ AddNotification(NSAccessibilityFocusedUIElementChangedNotification);
+ AddNotification(NSAccessibilityRowCountChangedNotification);
+ AddNotification(NSAccessibilitySelectedChildrenChangedNotification);
+ AddNotification(NSAccessibilitySelectedRowsChangedNotification);
+ AddNotification(NSAccessibilitySelectedTextChangedNotification);
+ AddNotification(NSAccessibilityValueChangedNotification);
+ AddNotification(@"AXLayoutComplete");
+ AddNotification(@"AXLiveRegionChanged");
+ AddNotification(@"AXLoadComplete");
+ AddNotification(@"AXRowCollapsed");
+ AddNotification(@"AXRowExpanded");
+
+ // Add the observer to the current message loop.
+ CFRunLoopAddSource(
+ [[NSRunLoop currentRunLoop] getCFRunLoop],
+ AXObserverGetRunLoopSource(observer_ref_),
+ kCFRunLoopDefaultMode);
+}
+
+AccessibilityEventRecorderMac::~AccessibilityEventRecorderMac() {
+ CFRelease(application_);
+ CFRelease(observer_ref_);
+}
+
+void AccessibilityEventRecorderMac::AddNotification(NSString* notification) {
+ AXObserverAddNotification(observer_ref_,
+ application_,
+ static_cast<CFStringRef>(notification),
+ this);
+}
+
+std::string AccessibilityEventRecorderMac::GetAXAttributeValue(
+ AXUIElementRef element, NSString* attribute_name) {
+ CFTypeRef value;
+ AXError err = AXUIElementCopyAttributeValue(
+ element, static_cast<CFStringRef>(attribute_name), &value);
+ if (err != kAXErrorSuccess)
+ return std::string();
+ return base::SysNSStringToUTF8(
+ base::mac::CFToNSCast(static_cast<CFStringRef>(value)));
+}
+
+void AccessibilityEventRecorderMac::EventReceived(
+ AXUIElementRef element,
+ CFStringRef notification) {
+ std::string notification_str = base::SysNSStringToUTF8(
+ base::mac::CFToNSCast(notification));
+ std::string role = GetAXAttributeValue(element, NSAccessibilityRoleAttribute);
+ if (role.empty())
+ return;
+ std::string log = base::StringPrintf("%s on %s",
+ notification_str.c_str(), role.c_str());
+
+ std::string title = GetAXAttributeValue(element,
+ NSAccessibilityTitleAttribute);
+ if (!title.empty())
+ log += base::StringPrintf(" AXTitle=\"%s\"", title.c_str());
+
+ std::string description = GetAXAttributeValue(element,
+ NSAccessibilityDescriptionAttribute);
+ if (!description.empty())
+ log += base::StringPrintf(" AXDescription=\"%s\"", description.c_str());
+
+ std::string value = GetAXAttributeValue(element,
+ NSAccessibilityValueAttribute);
+ if (!value.empty())
+ log += base::StringPrintf(" AXValue=\"%s\"", value.c_str());
+
+ event_logs_.push_back(log);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/accessibility/accessibility_event_recorder_win.cc b/chromium/content/browser/accessibility/accessibility_event_recorder_win.cc
new file mode 100644
index 00000000000..1d4336ee742
--- /dev/null
+++ b/chromium/content/browser/accessibility/accessibility_event_recorder_win.cc
@@ -0,0 +1,292 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/accessibility/accessibility_event_recorder.h"
+
+#include <oleacc.h>
+
+#include <string>
+
+#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 "base/win/scoped_bstr.h"
+#include "base/win/scoped_comptr.h"
+#include "base/win/scoped_variant.h"
+#include "content/browser/accessibility/accessibility_tree_formatter_utils_win.h"
+#include "content/browser/accessibility/browser_accessibility_manager.h"
+#include "content/browser/accessibility/browser_accessibility_win.h"
+#include "third_party/iaccessible2/ia2_api_all.h"
+#include "ui/base/win/atl_module.h"
+
+namespace content {
+
+namespace {
+
+std::string RoleVariantToString(const base::win::ScopedVariant& role) {
+ if (role.type() == VT_I4) {
+ return base::UTF16ToUTF8(IAccessibleRoleToString(V_I4(role.ptr())));
+ } else if (role.type() == VT_BSTR) {
+ return base::UTF16ToUTF8(
+ base::string16(V_BSTR(role.ptr()), SysStringLen(V_BSTR(role.ptr()))));
+ }
+ return std::string();
+}
+
+HRESULT QueryIAccessible2(IAccessible* accessible, IAccessible2** accessible2) {
+ base::win::ScopedComPtr<IServiceProvider> service_provider;
+ HRESULT hr = accessible->QueryInterface(service_provider.Receive());
+ return SUCCEEDED(hr) ?
+ service_provider->QueryService(IID_IAccessible2, accessible2) : hr;
+}
+
+HRESULT QueryIAccessibleText(IAccessible* accessible,
+ IAccessibleText** accessible_text) {
+ base::win::ScopedComPtr<IServiceProvider> service_provider;
+ HRESULT hr = accessible->QueryInterface(service_provider.Receive());
+ return SUCCEEDED(hr) ?
+ service_provider->QueryService(IID_IAccessibleText, accessible_text) : hr;
+}
+
+std::string BstrToUTF8(BSTR bstr) {
+ base::string16 str16(bstr, SysStringLen(bstr));
+
+ // IAccessibleText returns the text you get by appending all static text
+ // children, with an "embedded object character" for each non-text child.
+ // Pretty-print the embedded object character as <obj> so that test output
+ // is human-readable.
+ base::ReplaceChars(str16, L"\xfffc", L"<obj>", &str16);
+
+ return base::UTF16ToUTF8(str16);
+}
+
+std::string AccessibilityEventToStringUTF8(int32 event_id) {
+ return base::UTF16ToUTF8(AccessibilityEventToString(event_id));
+}
+
+} // namespace
+
+class AccessibilityEventRecorderWin : public AccessibilityEventRecorder {
+ public:
+ explicit AccessibilityEventRecorderWin(BrowserAccessibilityManager* manager);
+ ~AccessibilityEventRecorderWin() override;
+
+ // Callback registered by SetWinEventHook. Just calls OnWinEventHook.
+ static void CALLBACK WinEventHookThunk(
+ HWINEVENTHOOK handle,
+ DWORD event,
+ HWND hwnd,
+ LONG obj_id,
+ LONG child_id,
+ DWORD event_thread,
+ DWORD event_time);
+
+ private:
+ // Called by the thunk registered by SetWinEventHook. Retrives accessibility
+ // info about the node the event was fired on and appends a string to
+ // the event log.
+ void OnWinEventHook(HWINEVENTHOOK handle,
+ DWORD event,
+ HWND hwnd,
+ LONG obj_id,
+ LONG child_id,
+ DWORD event_thread,
+ DWORD event_time);
+
+ // Wrapper around AccessibleObjectFromWindow because the function call
+ // inexplicably flakes sometimes on build/trybots.
+ HRESULT AccessibleObjectFromWindowWrapper(
+ HWND hwnd, DWORD dwId, REFIID riid, void **ppvObject);
+
+ HWINEVENTHOOK win_event_hook_handle_;
+ static AccessibilityEventRecorderWin* instance_;
+};
+
+// static
+AccessibilityEventRecorderWin*
+AccessibilityEventRecorderWin::instance_ = nullptr;
+
+// static
+AccessibilityEventRecorder* AccessibilityEventRecorder::Create(
+ BrowserAccessibilityManager* manager) {
+ return new AccessibilityEventRecorderWin(manager);
+}
+
+// static
+void CALLBACK AccessibilityEventRecorderWin::WinEventHookThunk(
+ HWINEVENTHOOK handle,
+ DWORD event,
+ HWND hwnd,
+ LONG obj_id,
+ LONG child_id,
+ DWORD event_thread,
+ DWORD event_time) {
+ if (instance_) {
+ instance_->OnWinEventHook(handle, event, hwnd, obj_id, child_id,
+ event_thread, event_time);
+ }
+}
+
+AccessibilityEventRecorderWin::AccessibilityEventRecorderWin(
+ BrowserAccessibilityManager* manager)
+ : AccessibilityEventRecorder(manager) {
+ CHECK(!instance_) << "There can be only one instance of"
+ << " WinAccessibilityEventMonitor at a time.";
+ instance_ = this;
+ win_event_hook_handle_ = SetWinEventHook(
+ EVENT_MIN,
+ EVENT_MAX,
+ GetModuleHandle(NULL),
+ &AccessibilityEventRecorderWin::WinEventHookThunk,
+ GetCurrentProcessId(),
+ 0, // Hook all threads
+ WINEVENT_INCONTEXT);
+ CHECK(win_event_hook_handle_);
+}
+
+AccessibilityEventRecorderWin::~AccessibilityEventRecorderWin() {
+ UnhookWinEvent(win_event_hook_handle_);
+ instance_ = NULL;
+}
+
+void AccessibilityEventRecorderWin::OnWinEventHook(
+ HWINEVENTHOOK handle,
+ DWORD event,
+ HWND hwnd,
+ LONG obj_id,
+ LONG child_id,
+ DWORD event_thread,
+ DWORD event_time) {
+ base::win::ScopedComPtr<IAccessible> browser_accessible;
+ HRESULT hr = AccessibleObjectFromWindowWrapper(
+ hwnd,
+ obj_id,
+ IID_IAccessible,
+ reinterpret_cast<void**>(browser_accessible.Receive()));
+ if (!SUCCEEDED(hr)) {
+ // Note: our event hook will pick up some superfluous events we
+ // don't care about, so it's safe to just ignore these failures.
+ // Same below for other HRESULT checks.
+ VLOG(1) << "Ignoring result " << hr << " from AccessibleObjectFromWindow";
+ return;
+ }
+
+ base::win::ScopedVariant childid_variant(child_id);
+ base::win::ScopedComPtr<IDispatch> dispatch;
+ hr = browser_accessible->get_accChild(childid_variant, dispatch.Receive());
+ if (!SUCCEEDED(hr) || !dispatch) {
+ VLOG(1) << "Ignoring result " << hr << " and result " << dispatch
+ << " from get_accChild";
+ return;
+ }
+
+ base::win::ScopedComPtr<IAccessible> iaccessible;
+ hr = dispatch.QueryInterface(iaccessible.Receive());
+ if (!SUCCEEDED(hr)) {
+ VLOG(1) << "Ignoring result " << hr << " from QueryInterface";
+ return;
+ }
+
+ std::string event_str = AccessibilityEventToStringUTF8(event);
+ if (event_str.empty()) {
+ VLOG(1) << "Ignoring event " << event;
+ return;
+ }
+
+ base::win::ScopedVariant childid_self(CHILDID_SELF);
+ base::win::ScopedVariant role;
+ iaccessible->get_accRole(childid_self, role.Receive());
+ base::win::ScopedBstr name_bstr;
+ iaccessible->get_accName(childid_self, name_bstr.Receive());
+ base::win::ScopedBstr value_bstr;
+ iaccessible->get_accValue(childid_self, value_bstr.Receive());
+ base::win::ScopedVariant state;
+ iaccessible->get_accState(childid_self, state.Receive());
+ int ia_state = V_I4(state.ptr());
+
+ // Avoid flakiness. Events fired on a WINDOW are out of the control
+ // of a test.
+ if (role.type() == VT_I4 && ROLE_SYSTEM_WINDOW == V_I4(role.ptr())) {
+ VLOG(1) << "Ignoring event " << event << " on ROLE_SYSTEM_WINDOW";
+ return;
+ }
+
+ // Avoid flakiness. The "offscreen" state depends on whether the browser
+ // window is frontmost or not, and "hottracked" depends on whether the
+ // mouse cursor happens to be over the element.
+ ia_state &= (~STATE_SYSTEM_OFFSCREEN & ~STATE_SYSTEM_HOTTRACKED);
+
+ // The "readonly" state is set on almost every node and doesn't typically
+ // change, so filter it out to keep the output less verbose.
+ ia_state &= ~STATE_SYSTEM_READONLY;
+
+ AccessibleStates ia2_state = 0;
+ base::win::ScopedComPtr<IAccessible2> iaccessible2;
+ hr = QueryIAccessible2(iaccessible.get(), iaccessible2.Receive());
+ if (SUCCEEDED(hr))
+ iaccessible2->get_states(&ia2_state);
+
+ std::string log = base::StringPrintf(
+ "%s on role=%s", event_str.c_str(), RoleVariantToString(role).c_str());
+ if (name_bstr.Length() > 0)
+ log += base::StringPrintf(" name=\"%s\"", BstrToUTF8(name_bstr).c_str());
+ if (value_bstr.Length() > 0)
+ log += base::StringPrintf(" value=\"%s\"", BstrToUTF8(value_bstr).c_str());
+ log += " ";
+ log += base::UTF16ToUTF8(IAccessibleStateToString(ia_state));
+ log += " ";
+ log += base::UTF16ToUTF8(IAccessible2StateToString(ia2_state));
+
+ // For TEXT_REMOVED and TEXT_INSERTED events, query the text that was
+ // inserted or removed and include that in the log.
+ base::win::ScopedComPtr<IAccessibleText> accessible_text;
+ hr = QueryIAccessibleText(iaccessible.get(), accessible_text.Receive());
+ if (SUCCEEDED(hr)) {
+ if (event == IA2_EVENT_TEXT_REMOVED) {
+ IA2TextSegment old_text;
+ if (SUCCEEDED(accessible_text->get_oldText(&old_text))) {
+ log += base::StringPrintf(" old_text={'%s' start=%d end=%d}",
+ BstrToUTF8(old_text.text).c_str(),
+ old_text.start,
+ old_text.end);
+ }
+ }
+ if (event == IA2_EVENT_TEXT_INSERTED) {
+ IA2TextSegment new_text;
+ if (SUCCEEDED(accessible_text->get_newText(&new_text))) {
+ log += base::StringPrintf(" new_text={'%s' start=%d end=%d}",
+ BstrToUTF8(new_text.text).c_str(),
+ new_text.start,
+ new_text.end);
+ }
+ }
+ }
+
+ log = base::UTF16ToUTF8(
+ base::CollapseWhitespace(base::UTF8ToUTF16(log), true));
+ event_logs_.push_back(log);
+}
+
+HRESULT AccessibilityEventRecorderWin::AccessibleObjectFromWindowWrapper(
+ HWND hwnd, DWORD dw_id, REFIID riid, void** ppv_object) {
+ HRESULT hr = ::AccessibleObjectFromWindow(hwnd, dw_id, riid, ppv_object);
+ if (SUCCEEDED(hr))
+ return hr;
+
+ // The above call to ::AccessibleObjectFromWindow fails for unknown
+ // reasons every once in a while on the bots. Work around it by grabbing
+ // the object directly from the BrowserAccessibilityManager.
+ HWND accessibility_hwnd =
+ manager_->delegate()->AccessibilityGetAcceleratedWidget();
+ if (accessibility_hwnd != hwnd)
+ return E_FAIL;
+
+ IAccessible* obj = manager_->GetRoot()->ToBrowserAccessibilityWin();
+ obj->AddRef();
+ *ppv_object = obj;
+ return S_OK;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/accessibility/accessibility_ipc_error_browsertest.cc b/chromium/content/browser/accessibility/accessibility_ipc_error_browsertest.cc
index 5702a33ded3..da6921f6299 100644
--- a/chromium/content/browser/accessibility/accessibility_ipc_error_browsertest.cc
+++ b/chromium/content/browser/accessibility/accessibility_ipc_error_browsertest.cc
@@ -107,7 +107,7 @@ IN_PROC_BROWSER_TEST_F(AccessibilityIpcErrorBrowserTest,
// Get the accessibility tree, ensure it reflects the final state of the
// document.
- const ui::AXNode* root = tree->GetRoot();
+ const ui::AXNode* root = tree->root();
// Use this for debugging if the test fails.
VLOG(1) << tree->ToString();
diff --git a/chromium/content/browser/accessibility/accessibility_tree_formatter.cc b/chromium/content/browser/accessibility/accessibility_tree_formatter.cc
index d4c189fb6f1..2ca2a8544fd 100644
--- a/chromium/content/browser/accessibility/accessibility_tree_formatter.cc
+++ b/chromium/content/browser/accessibility/accessibility_tree_formatter.cc
@@ -17,14 +17,17 @@
namespace content {
namespace {
-const int kIndentSpaces = 4;
+const char kIndentSymbol = '+';
+const int kIndentSymbolCount = 2;
const char* kSkipString = "@NO_DUMP";
+const char* kSkipChildren = "@NO_CHILDREN_DUMP";
const char* kChildrenDictAttr = "children";
}
AccessibilityTreeFormatter::AccessibilityTreeFormatter(
BrowserAccessibility* root)
- : root_(root) {
+ : root_(root),
+ show_ids_(false) {
Initialize();
}
@@ -75,12 +78,16 @@ void AccessibilityTreeFormatter::RecursiveBuildAccessibilityTree(
void AccessibilityTreeFormatter::RecursiveFormatAccessibilityTree(
const base::DictionaryValue& dict, base::string16* contents, int depth) {
- base::string16 line =
- ToString(dict, base::string16(depth * kIndentSpaces, ' '));
+ base::string16 indent = base::string16(depth * kIndentSymbolCount,
+ kIndentSymbol);
+ base::string16 line = indent + ToString(dict);
if (line.find(base::ASCIIToUTF16(kSkipString)) != base::string16::npos)
return;
- *contents += line;
+ *contents += line + base::ASCIIToUTF16("\n");
+ if (line.find(base::ASCIIToUTF16(kSkipChildren)) != base::string16::npos)
+ return;
+
const base::ListValue* children;
dict.GetList(kChildrenDictAttr, &children);
const base::DictionaryValue* child_dict;
@@ -97,12 +104,10 @@ void AccessibilityTreeFormatter::AddProperties(const BrowserAccessibility& node,
}
base::string16 AccessibilityTreeFormatter::ToString(
- const base::DictionaryValue& node,
- const base::string16& indent) {
+ const base::DictionaryValue& node) {
int id_value;
node.GetInteger("id", &id_value);
- return indent + base::IntToString16(id_value) +
- base::ASCIIToUTF16("\n");
+ return base::IntToString16(id_value);
}
void AccessibilityTreeFormatter::Initialize() {}
@@ -140,11 +145,14 @@ void AccessibilityTreeFormatter::SetFilters(
filters_ = filters;
}
+// static
bool AccessibilityTreeFormatter::MatchesFilters(
- const base::string16& text, bool default_result) const {
- std::vector<Filter>::const_iterator iter = filters_.begin();
+ const std::vector<Filter>& filters,
+ const base::string16& text,
+ bool default_result) {
+ std::vector<Filter>::const_iterator iter = filters.begin();
bool allow = default_result;
- for (iter = filters_.begin(); iter != filters_.end(); ++iter) {
+ for (iter = filters.begin(); iter != filters.end(); ++iter) {
if (MatchPattern(text, iter->match_str)) {
if (iter->type == Filter::ALLOW_EMPTY)
allow = true;
@@ -157,6 +165,11 @@ bool AccessibilityTreeFormatter::MatchesFilters(
return allow;
}
+bool AccessibilityTreeFormatter::MatchesFilters(
+ const base::string16& text, bool default_result) const {
+ return MatchesFilters(filters_, text, default_result);
+}
+
base::string16 AccessibilityTreeFormatter::FormatCoordinates(
const char* name, const char* x_name, const char* y_name,
const base::DictionaryValue& value) {
diff --git a/chromium/content/browser/accessibility/accessibility_tree_formatter.h b/chromium/content/browser/accessibility/accessibility_tree_formatter.h
index 39c6a4aa283..8db914a9fa5 100644
--- a/chromium/content/browser/accessibility/accessibility_tree_formatter.h
+++ b/chromium/content/browser/accessibility/accessibility_tree_formatter.h
@@ -27,8 +27,28 @@ class CONTENT_EXPORT AccessibilityTreeFormatter {
explicit AccessibilityTreeFormatter(BrowserAccessibility* root);
virtual ~AccessibilityTreeFormatter();
+ // A single filter specification. See GetAllowString() and GetDenyString()
+ // for more information.
+ struct Filter {
+ enum Type {
+ ALLOW,
+ ALLOW_EMPTY,
+ DENY
+ };
+ base::string16 match_str;
+ Type type;
+
+ Filter(base::string16 match_str, Type type)
+ : match_str(match_str), type(type) {}
+ };
+
static AccessibilityTreeFormatter* Create(WebContents* wc);
+ static bool MatchesFilters(
+ const std::vector<Filter>& filters,
+ const base::string16& text,
+ bool default_result);
+
// Populates the given DictionaryValue with the accessibility tree.
// The dictionary contains a key/value pair for each attribute of the node,
// plus a "children" attribute containing a list of all child nodes.
@@ -54,25 +74,14 @@ class CONTENT_EXPORT AccessibilityTreeFormatter {
// Dumps a BrowserAccessibility tree into a string.
void FormatAccessibilityTree(base::string16* contents);
- // A single filter specification. See GetAllowString() and GetDenyString()
- // for more information.
- struct Filter {
- enum Type {
- ALLOW,
- ALLOW_EMPTY,
- DENY
- };
- base::string16 match_str;
- Type type;
-
- Filter(base::string16 match_str, Type type)
- : match_str(match_str), type(type) {}
- };
-
// Set regular expression filters that apply to each component of every
// line before it's output.
void SetFilters(const std::vector<Filter>& filters);
+ // If true, the internal accessibility id of each node will be included
+ // in its output.
+ void set_show_ids(bool show_ids) { show_ids_ = show_ids; }
+
// Suffix of the expectation file corresponding to html file.
// Example:
// HTML test: test-file.html
@@ -119,10 +128,7 @@ class CONTENT_EXPORT AccessibilityTreeFormatter {
const base::DictionaryValue& value);
// Returns a platform specific representation of a BrowserAccessibility.
- // Should be zero or more complete lines, each with |prefix| prepended
- // (to indent each line).
- base::string16 ToString(const base::DictionaryValue& node,
- const base::string16& indent);
+ base::string16 ToString(const base::DictionaryValue& node);
void Initialize();
@@ -141,6 +147,9 @@ class CONTENT_EXPORT AccessibilityTreeFormatter {
// Filters used when formatting the accessibility tree as text.
std::vector<Filter> filters_;
+ // Whether or not node ids should be included in the dump.
+ bool show_ids_;
+
DISALLOW_COPY_AND_ASSIGN(AccessibilityTreeFormatter);
};
diff --git a/chromium/content/browser/accessibility/accessibility_tree_formatter_android.cc b/chromium/content/browser/accessibility/accessibility_tree_formatter_android.cc
index 65f8fa3d0fa..97cfc7f909a 100644
--- a/chromium/content/browser/accessibility/accessibility_tree_formatter_android.cc
+++ b/chromium/content/browser/accessibility/accessibility_tree_formatter_android.cc
@@ -10,6 +10,7 @@
#include "base/android/jni_string.h"
#include "base/files/file_path.h"
#include "base/json/json_writer.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"
@@ -35,6 +36,7 @@ const char* BOOL_ATTRIBUTES[] = {
"heading",
"hierarchical",
"invisible",
+ "link",
"multiline",
"password",
"range",
@@ -68,6 +70,8 @@ void AccessibilityTreeFormatter::Initialize() {
void AccessibilityTreeFormatter::AddProperties(
const BrowserAccessibility& node, base::DictionaryValue* dict) {
+ dict->SetInteger("id", node.GetId());
+
const BrowserAccessibilityAndroid* android_node =
static_cast<const BrowserAccessibilityAndroid*>(&node);
@@ -88,6 +92,7 @@ void AccessibilityTreeFormatter::AddProperties(
dict->SetBoolean("heading", android_node->IsHeading());
dict->SetBoolean("hierarchical", android_node->IsHierarchical());
dict->SetBoolean("invisible", !android_node->IsVisibleToUser());
+ dict->SetBoolean("link", android_node->IsLink());
dict->SetBoolean("multiline", android_node->IsMultiLine());
dict->SetBoolean("range", android_node->IsRangeType());
dict->SetBoolean("password", android_node->IsPassword());
@@ -115,10 +120,15 @@ void AccessibilityTreeFormatter::AddProperties(
}
base::string16 AccessibilityTreeFormatter::ToString(
- const base::DictionaryValue& dict,
- const base::string16& indent) {
+ const base::DictionaryValue& dict) {
base::string16 line;
+ if (show_ids_) {
+ int id_value;
+ dict.GetInteger("id", &id_value);
+ WriteAttribute(true, base::IntToString16(id_value), &line);
+ }
+
base::string16 class_value;
dict.GetString("class", &class_value);
WriteAttribute(true, base::UTF16ToUTF8(class_value), &line);
@@ -150,7 +160,7 @@ base::string16 AccessibilityTreeFormatter::ToString(
&line);
}
- return indent + line + base::ASCIIToUTF16("\n");
+ return line;
}
// static
diff --git a/chromium/content/browser/accessibility/accessibility_tree_formatter_mac.mm b/chromium/content/browser/accessibility/accessibility_tree_formatter_mac.mm
index 7d5c1bf1ee1..7b992253ee4 100644
--- a/chromium/content/browser/accessibility/accessibility_tree_formatter_mac.mm
+++ b/chromium/content/browser/accessibility/accessibility_tree_formatter_mac.mm
@@ -9,6 +9,7 @@
#include "base/basictypes.h"
#include "base/files/file_path.h"
#include "base/json/json_writer.h"
+#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
@@ -160,14 +161,21 @@ NSArray* BuildAllAttributesArray() {
@"AXARIABusy",
@"AXARIALive",
@"AXARIARelevant",
+ @"AXARIASetSize",
+ @"AXARIAPosInSet",
NSAccessibilityColumnIndexRangeAttribute,
+ @"AXDropEffects",
NSAccessibilityEnabledAttribute,
+ NSAccessibilityExpandedAttribute,
NSAccessibilityFocusedAttribute,
+ @"AXGrabbed",
NSAccessibilityIndexAttribute,
@"AXLoaded",
@"AXLoadingProcess",
NSAccessibilityNumberOfCharactersAttribute,
+ NSAccessibilitySortDirectionAttribute,
NSAccessibilityOrientationAttribute,
+ @"AXPlaceholder",
@"AXRequired",
NSAccessibilityRowIndexRangeAttribute,
NSAccessibilitySelectedChildrenAttribute,
@@ -177,7 +185,6 @@ NSArray* BuildAllAttributesArray() {
NSAccessibilityVisibleChildrenAttribute,
@"AXVisited",
@"AXLinkedUIElements",
- NSAccessibilityExpandedAttribute,
nil];
return [array retain];
}
@@ -190,6 +197,7 @@ void AccessibilityTreeFormatter::Initialize() {
void AccessibilityTreeFormatter::AddProperties(const BrowserAccessibility& node,
base::DictionaryValue* dict) {
+ dict->SetInteger("id", node.GetId());
BrowserAccessibilityCocoa* cocoa_node =
const_cast<BrowserAccessibility*>(&node)->ToBrowserAccessibilityCocoa();
NSArray* supportedAttributes = [cocoa_node accessibilityAttributeNames];
@@ -221,9 +229,14 @@ void AccessibilityTreeFormatter::AddProperties(const BrowserAccessibility& node,
}
base::string16 AccessibilityTreeFormatter::ToString(
- const base::DictionaryValue& dict,
- const base::string16& indent) {
+ const base::DictionaryValue& dict) {
base::string16 line;
+ if (show_ids_) {
+ int id_value;
+ dict.GetInteger("id", &id_value);
+ WriteAttribute(true, base::IntToString16(id_value), &line);
+ }
+
NSArray* defaultAttributes =
[NSArray arrayWithObjects:NSAccessibilityTitleAttribute,
NSAccessibilityValueAttribute,
@@ -278,7 +291,7 @@ base::string16 AccessibilityTreeFormatter::ToString(
&line);
}
- return indent + line + base::ASCIIToUTF16("\n");
+ return line;
}
// static
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 02159bca1ad..063f5cd759c 100644
--- a/chromium/content/browser/accessibility/accessibility_tree_formatter_utils_win.cc
+++ b/chromium/content/browser/accessibility/accessibility_tree_formatter_utils_win.cc
@@ -16,37 +16,39 @@
namespace content {
namespace {
-class AccessibilityRoleStateMap {
+class AccessibilityEnumMap {
public:
- static AccessibilityRoleStateMap* GetInstance();
+ static AccessibilityEnumMap* GetInstance();
std::map<int32, base::string16> ia_role_string_map;
std::map<int32, base::string16> ia2_role_string_map;
std::map<int32, base::string16> ia_state_string_map;
std::map<int32, base::string16> ia2_state_string_map;
+ std::map<int32, base::string16> event_string_map;
private:
- AccessibilityRoleStateMap();
- virtual ~AccessibilityRoleStateMap() {}
+ AccessibilityEnumMap();
+ virtual ~AccessibilityEnumMap() {}
- friend struct DefaultSingletonTraits<AccessibilityRoleStateMap>;
+ friend struct DefaultSingletonTraits<AccessibilityEnumMap>;
- DISALLOW_COPY_AND_ASSIGN(AccessibilityRoleStateMap);
+ DISALLOW_COPY_AND_ASSIGN(AccessibilityEnumMap);
};
// static
-AccessibilityRoleStateMap* AccessibilityRoleStateMap::GetInstance() {
- return Singleton<AccessibilityRoleStateMap,
- LeakySingletonTraits<AccessibilityRoleStateMap> >::get();
+AccessibilityEnumMap* AccessibilityEnumMap::GetInstance() {
+ return Singleton<AccessibilityEnumMap,
+ LeakySingletonTraits<AccessibilityEnumMap> >::get();
}
-AccessibilityRoleStateMap::AccessibilityRoleStateMap() {
+AccessibilityEnumMap::AccessibilityEnumMap() {
// Convenience macros for generating readable strings.
#define IA_ROLE_MAP(x) ia_role_string_map[x] = L###x; \
ia2_role_string_map[x] = L###x;
#define IA2_ROLE_MAP(x) ia2_role_string_map[x] = L###x;
#define IA_STATE_MAP(x) ia_state_string_map[STATE_SYSTEM_##x] = L###x;
#define IA2_STATE_MAP(x) ia2_state_string_map[x] = L###x;
+#define EVENT_MAP(x) event_string_map[x] = L###x;
// MSAA / IAccessible roles. Each one of these is also a valid
// IAccessible2 role, the IA_ROLE_MAP macro adds it to both.
@@ -200,6 +202,7 @@ AccessibilityRoleStateMap::AccessibilityRoleStateMap() {
IA2_STATE_MAP(IA2_STATE_CHECKABLE)
IA2_STATE_MAP(IA2_STATE_DEFUNCT)
IA2_STATE_MAP(IA2_STATE_EDITABLE)
+ IA2_STATE_MAP(IA2_STATE_HORIZONTAL)
IA2_STATE_MAP(IA2_STATE_ICONIFIED)
IA2_STATE_MAP(IA2_STATE_INVALID_ENTRY)
IA2_STATE_MAP(IA2_STATE_MANAGES_DESCENDANTS)
@@ -211,28 +214,96 @@ AccessibilityRoleStateMap::AccessibilityRoleStateMap() {
IA2_STATE_MAP(IA2_STATE_STALE)
IA2_STATE_MAP(IA2_STATE_SUPPORTS_AUTOCOMPLETION)
IA2_STATE_MAP(IA2_STATE_TRANSIENT)
+ IA2_STATE_MAP(IA2_STATE_VERTICAL)
// Untested states include those that would be repeated on nearly every node,
// or would vary based on window size.
- // IA2_STATE_MAP(IA2_STATE_HORIZONTAL) // Untested.
// IA2_STATE_MAP(IA2_STATE_OPAQUE) // Untested.
- // IA2_STATE_MAP(IA2_STATE_VERTICAL) // Untested.
+
+ EVENT_MAP(EVENT_OBJECT_CREATE)
+ EVENT_MAP(EVENT_OBJECT_DESTROY)
+ EVENT_MAP(EVENT_OBJECT_SHOW)
+ EVENT_MAP(EVENT_OBJECT_HIDE)
+ EVENT_MAP(EVENT_OBJECT_REORDER)
+ EVENT_MAP(EVENT_OBJECT_FOCUS)
+ EVENT_MAP(EVENT_OBJECT_SELECTION)
+ EVENT_MAP(EVENT_OBJECT_SELECTIONADD)
+ EVENT_MAP(EVENT_OBJECT_SELECTIONREMOVE)
+ EVENT_MAP(EVENT_OBJECT_SELECTIONWITHIN)
+ EVENT_MAP(EVENT_OBJECT_STATECHANGE)
+ EVENT_MAP(EVENT_OBJECT_LOCATIONCHANGE)
+ EVENT_MAP(EVENT_OBJECT_NAMECHANGE)
+ EVENT_MAP(EVENT_OBJECT_DESCRIPTIONCHANGE)
+ EVENT_MAP(EVENT_OBJECT_VALUECHANGE)
+ EVENT_MAP(EVENT_OBJECT_PARENTCHANGE)
+ EVENT_MAP(EVENT_OBJECT_HELPCHANGE)
+ EVENT_MAP(EVENT_OBJECT_DEFACTIONCHANGE)
+ EVENT_MAP(EVENT_OBJECT_ACCELERATORCHANGE)
+ EVENT_MAP(EVENT_OBJECT_INVOKED)
+ EVENT_MAP(EVENT_OBJECT_TEXTSELECTIONCHANGED)
+ EVENT_MAP(EVENT_OBJECT_CONTENTSCROLLED)
+ EVENT_MAP(EVENT_OBJECT_LIVEREGIONCHANGED)
+ EVENT_MAP(EVENT_OBJECT_HOSTEDOBJECTSINVALIDATED)
+ EVENT_MAP(EVENT_OBJECT_DRAGSTART)
+ EVENT_MAP(EVENT_OBJECT_DRAGCANCEL)
+ EVENT_MAP(EVENT_OBJECT_DRAGCOMPLETE)
+ EVENT_MAP(EVENT_OBJECT_DRAGENTER)
+ EVENT_MAP(EVENT_OBJECT_DRAGLEAVE)
+ EVENT_MAP(EVENT_OBJECT_DRAGDROPPED)
+ EVENT_MAP(EVENT_SYSTEM_ALERT)
+ EVENT_MAP(EVENT_SYSTEM_SCROLLINGSTART)
+ EVENT_MAP(EVENT_SYSTEM_SCROLLINGEND)
+ EVENT_MAP(IA2_EVENT_ACTION_CHANGED)
+ EVENT_MAP(IA2_EVENT_ACTIVE_DECENDENT_CHANGED)
+ EVENT_MAP(IA2_EVENT_ACTIVE_DESCENDANT_CHANGED)
+ EVENT_MAP(IA2_EVENT_DOCUMENT_ATTRIBUTE_CHANGED)
+ EVENT_MAP(IA2_EVENT_DOCUMENT_CONTENT_CHANGED)
+ EVENT_MAP(IA2_EVENT_DOCUMENT_LOAD_COMPLETE)
+ EVENT_MAP(IA2_EVENT_DOCUMENT_LOAD_STOPPED)
+ EVENT_MAP(IA2_EVENT_DOCUMENT_RELOAD)
+ EVENT_MAP(IA2_EVENT_HYPERLINK_END_INDEX_CHANGED)
+ EVENT_MAP(IA2_EVENT_HYPERLINK_NUMBER_OF_ANCHORS_CHANGED)
+ EVENT_MAP(IA2_EVENT_HYPERLINK_SELECTED_LINK_CHANGED)
+ EVENT_MAP(IA2_EVENT_HYPERTEXT_LINK_ACTIVATED)
+ EVENT_MAP(IA2_EVENT_HYPERTEXT_LINK_SELECTED)
+ EVENT_MAP(IA2_EVENT_HYPERLINK_START_INDEX_CHANGED)
+ EVENT_MAP(IA2_EVENT_HYPERTEXT_CHANGED)
+ EVENT_MAP(IA2_EVENT_HYPERTEXT_NLINKS_CHANGED)
+ EVENT_MAP(IA2_EVENT_OBJECT_ATTRIBUTE_CHANGED)
+ EVENT_MAP(IA2_EVENT_PAGE_CHANGED)
+ EVENT_MAP(IA2_EVENT_SECTION_CHANGED)
+ EVENT_MAP(IA2_EVENT_TABLE_CAPTION_CHANGED)
+ EVENT_MAP(IA2_EVENT_TABLE_COLUMN_DESCRIPTION_CHANGED)
+ EVENT_MAP(IA2_EVENT_TABLE_COLUMN_HEADER_CHANGED)
+ EVENT_MAP(IA2_EVENT_TABLE_MODEL_CHANGED)
+ EVENT_MAP(IA2_EVENT_TABLE_ROW_DESCRIPTION_CHANGED)
+ EVENT_MAP(IA2_EVENT_TABLE_ROW_HEADER_CHANGED)
+ EVENT_MAP(IA2_EVENT_TABLE_SUMMARY_CHANGED)
+ EVENT_MAP(IA2_EVENT_TEXT_ATTRIBUTE_CHANGED)
+ EVENT_MAP(IA2_EVENT_TEXT_CARET_MOVED)
+ EVENT_MAP(IA2_EVENT_TEXT_CHANGED)
+ EVENT_MAP(IA2_EVENT_TEXT_COLUMN_CHANGED)
+ EVENT_MAP(IA2_EVENT_TEXT_INSERTED)
+ EVENT_MAP(IA2_EVENT_TEXT_REMOVED)
+ EVENT_MAP(IA2_EVENT_TEXT_UPDATED)
+ EVENT_MAP(IA2_EVENT_TEXT_SELECTION_CHANGED)
+ EVENT_MAP(IA2_EVENT_VISIBLE_DATA_CHANGED)
}
} // namespace.
base::string16 IAccessibleRoleToString(int32 ia_role) {
- return AccessibilityRoleStateMap::GetInstance()->ia_role_string_map[ia_role];
+ return AccessibilityEnumMap::GetInstance()->ia_role_string_map[ia_role];
}
base::string16 IAccessible2RoleToString(int32 ia_role) {
- return AccessibilityRoleStateMap::GetInstance()->ia2_role_string_map[ia_role];
+ return AccessibilityEnumMap::GetInstance()->ia2_role_string_map[ia_role];
}
void IAccessibleStateToStringVector(int32 ia_state,
std::vector<base::string16>* result) {
const std::map<int32, base::string16>& state_string_map =
- AccessibilityRoleStateMap::GetInstance()->ia_state_string_map;
+ AccessibilityEnumMap::GetInstance()->ia_state_string_map;
std::map<int32, base::string16>::const_iterator it;
for (it = state_string_map.begin(); it != state_string_map.end(); ++it) {
if (it->first & ia_state)
@@ -249,7 +320,7 @@ base::string16 IAccessibleStateToString(int32 ia_state) {
void IAccessible2StateToStringVector(int32 ia2_state,
std::vector<base::string16>* result) {
const std::map<int32, base::string16>& state_string_map =
- AccessibilityRoleStateMap::GetInstance()->ia2_state_string_map;
+ AccessibilityEnumMap::GetInstance()->ia2_state_string_map;
std::map<int32, base::string16>::const_iterator it;
for (it = state_string_map.begin(); it != state_string_map.end(); ++it) {
if (it->first & ia2_state)
@@ -263,4 +334,8 @@ base::string16 IAccessible2StateToString(int32 ia2_state) {
return JoinString(strings, ',');
}
+base::string16 AccessibilityEventToString(int32 event_id) {
+ return AccessibilityEnumMap::GetInstance()->event_string_map[event_id];
+}
+
} // namespace content
diff --git a/chromium/content/browser/accessibility/accessibility_tree_formatter_utils_win.h b/chromium/content/browser/accessibility/accessibility_tree_formatter_utils_win.h
index 86b377a64ef..37d93b5095b 100644
--- a/chromium/content/browser/accessibility/accessibility_tree_formatter_utils_win.h
+++ b/chromium/content/browser/accessibility/accessibility_tree_formatter_utils_win.h
@@ -20,7 +20,10 @@ CONTENT_EXPORT void IAccessibleStateToStringVector(
int32 ia_state, std::vector<base::string16>* result);
CONTENT_EXPORT base::string16 IAccessible2StateToString(int32 ia2_state);
CONTENT_EXPORT void IAccessible2StateToStringVector(
- int32 ia_state, std::vector<base::string16>* result);
+ int32 ia_state, std::vector<base::string16>* result);
+
+// Handles both IAccessible/MSAA events and IAccessible2 events.
+CONTENT_EXPORT base::string16 AccessibilityEventToString(int32 event_id);
} // namespace content
diff --git a/chromium/content/browser/accessibility/accessibility_tree_formatter_win.cc b/chromium/content/browser/accessibility/accessibility_tree_formatter_win.cc
index 31367b40344..87850a62d35 100644
--- a/chromium/content/browser/accessibility/accessibility_tree_formatter_win.cc
+++ b/chromium/content/browser/accessibility/accessibility_tree_formatter_win.cc
@@ -9,6 +9,7 @@
#include <string>
#include "base/files/file_path.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"
@@ -58,6 +59,7 @@ void AccessibilityTreeFormatter::Initialize() {
void AccessibilityTreeFormatter::AddProperties(
const BrowserAccessibility& node, base::DictionaryValue* dict) {
+ dict->SetInteger("id", node.GetId());
BrowserAccessibilityWin* acc_obj =
const_cast<BrowserAccessibility*>(&node)->ToBrowserAccessibilityWin();
@@ -199,10 +201,15 @@ void AccessibilityTreeFormatter::AddProperties(
}
base::string16 AccessibilityTreeFormatter::ToString(
- const base::DictionaryValue& dict,
- const base::string16& indent) {
+ const base::DictionaryValue& dict) {
base::string16 line;
+ if (show_ids_) {
+ int id_value;
+ dict.GetInteger("id", &id_value);
+ WriteAttribute(true, base::IntToString16(id_value), &line);
+ }
+
base::string16 role_value;
dict.GetString("role", &role_value);
WriteAttribute(true, base::UTF16ToUTF8(role_value), &line);
@@ -283,7 +290,7 @@ base::string16 AccessibilityTreeFormatter::ToString(
}
}
- return indent + line + base::ASCIIToUTF16("\n");
+ return line;
}
// static
diff --git a/chromium/content/browser/accessibility/accessibility_ui.cc b/chromium/content/browser/accessibility/accessibility_ui.cc
index a8a5d97ad3e..3bfa6ee62b2 100644
--- a/chromium/content/browser/accessibility/accessibility_ui.cc
+++ b/chromium/content/browser/accessibility/accessibility_ui.cc
@@ -66,7 +66,7 @@ base::DictionaryValue* BuildTargetDescriptor(
base::DictionaryValue* BuildTargetDescriptor(RenderViewHost* rvh) {
WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
WebContents::FromRenderViewHost(rvh));
- AccessibilityMode accessibility_mode = web_contents->GetAccessibilityMode();
+ AccessibilityMode accessibility_mode = AccessibilityModeOff;
std::string title;
GURL url;
@@ -80,6 +80,7 @@ base::DictionaryValue* BuildTargetDescriptor(RenderViewHost* rvh) {
NavigationEntry* entry = controller.GetVisibleEntry();
if (entry != NULL && entry->GetURL().is_valid())
favicon_url = entry->GetFavicon().url;
+ accessibility_mode = web_contents->GetAccessibilityMode();
}
return BuildTargetDescriptor(url,
diff --git a/chromium/content/browser/accessibility/accessibility_ui.h b/chromium/content/browser/accessibility/accessibility_ui.h
index 014514a1363..bdab0c628c8 100644
--- a/chromium/content/browser/accessibility/accessibility_ui.h
+++ b/chromium/content/browser/accessibility/accessibility_ui.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CHROME_BROWSER_UI_WEBUI_ACCESSIBILITY_UI_H_
-#define CHROME_BROWSER_UI_WEBUI_ACCESSIBILITY_UI_H_
+#ifndef CONTENT_BROWSER_ACCESSIBILITY_ACCESSIBILITY_UI_H_
+#define CONTENT_BROWSER_ACCESSIBILITY_ACCESSIBILITY_UI_H_
#include "content/public/browser/web_ui_controller.h"
#include "content/public/browser/web_ui_data_source.h"
@@ -29,4 +29,4 @@ class AccessibilityUI : public WebUIController {
} // namespace content
-#endif // CHROME_BROWSER_UI_WEBUI_ACCESSIBILITY_UI_H_
+#endif // CONTENT_BROWSER_ACCESSIBILITY_ACCESSIBILITY_UI_H_
diff --git a/chromium/content/browser/accessibility/accessibility_win_browsertest.cc b/chromium/content/browser/accessibility/accessibility_win_browsertest.cc
index 058e033ae4e..7c3480d5c40 100644
--- a/chromium/content/browser/accessibility/accessibility_win_browsertest.cc
+++ b/chromium/content/browser/accessibility/accessibility_win_browsertest.cc
@@ -5,11 +5,13 @@
#include <vector>
#include "base/memory/scoped_ptr.h"
-#include "base/strings/utf_string_conversions.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/sys_string_conversions.h"
#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.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"
@@ -22,6 +24,7 @@
#include "content/public/test/content_browser_test_utils.h"
#include "content/shell/browser/shell.h"
#include "content/test/accessibility_browser_test_utils.h"
+#include "net/base/escape.h"
#include "third_party/iaccessible2/ia2_api_all.h"
#include "third_party/isimpledom/ISimpleDOMNode.h"
#include "ui/aura/window.h"
@@ -31,9 +34,195 @@ namespace content {
namespace {
-// Helpers --------------------------------------------------------------------
-base::win::ScopedComPtr<IAccessible> GetAccessibleFromResultVariant(
+const char INPUT_CONTENTS[] = "Moz/5.0 (ST 6.x; WWW33) "
+ "WebKit \"KHTML, like\".";
+const char TEXTAREA_CONTENTS[] = "Moz/5.0 (ST 6.x; WWW33)\n"
+ "WebKit \n\"KHTML, like\".";
+const LONG CONTENTS_LENGTH = static_cast<LONG>(
+ (sizeof(INPUT_CONTENTS) - 1) / sizeof(char));
+
+
+// AccessibilityWinBrowserTest ------------------------------------------------
+
+class AccessibilityWinBrowserTest : public ContentBrowserTest {
+ public:
+ AccessibilityWinBrowserTest();
+ ~AccessibilityWinBrowserTest() override;
+
+ protected:
+ class AccessibleChecker;
+ void LoadInitialAccessibilityTreeFromHtml(const std::string& html);
+ IAccessible* GetRendererAccessible();
+ void ExecuteScript(const std::wstring& script);
+ void SetUpInputField(
+ base::win::ScopedComPtr<IAccessibleText>* input_text);
+ void SetUpTextareaField(
+ base::win::ScopedComPtr<IAccessibleText>* textarea_text);
+
+
+ static base::win::ScopedComPtr<IAccessible>
+ AccessibilityWinBrowserTest::GetAccessibleFromVariant(
+ IAccessible* parent,
+ VARIANT* var);
+ static HRESULT QueryIAccessible2(IAccessible* accessible,
+ IAccessible2** accessible2);
+ static void FindNodeInAccessibilityTree(IAccessible* node,
+ int32 expected_role,
+ const std::wstring& expected_name,
+ int32 depth,
+ bool* found);
+ static void CheckTextAtOffset(
+ base::win::ScopedComPtr<IAccessibleText>& element,
+ LONG offset,
+ IA2TextBoundaryType boundary_type,
+ LONG expected_start_offset,
+ LONG expected_end_offset,
+ const std::wstring& expected_text);
+ static std::vector<base::win::ScopedVariant> GetAllAccessibleChildren(
+ IAccessible* element);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AccessibilityWinBrowserTest);
+};
+
+AccessibilityWinBrowserTest::AccessibilityWinBrowserTest() {
+}
+
+AccessibilityWinBrowserTest::~AccessibilityWinBrowserTest() {
+}
+
+void AccessibilityWinBrowserTest::LoadInitialAccessibilityTreeFromHtml(
+ const std::string& html) {
+ AccessibilityNotificationWaiter waiter(
+ shell(), AccessibilityModeComplete,
+ ui::AX_EVENT_LOAD_COMPLETE);
+ GURL html_data_url("data:text/html," + html);
+ NavigateToURL(shell(), html_data_url);
+ waiter.WaitForNotification();
+}
+
+// Retrieve the MSAA client accessibility object for the Render Widget Host View
+// of the selected tab.
+IAccessible* AccessibilityWinBrowserTest::GetRendererAccessible() {
+ content::WebContents* web_contents = shell()->web_contents();
+ return web_contents->GetRenderWidgetHostView()->GetNativeViewAccessible();
+}
+
+void AccessibilityWinBrowserTest::ExecuteScript(const std::wstring& script) {
+ shell()->web_contents()->GetMainFrame()->ExecuteJavaScript(script);
+}
+
+// Loads a page with an input text field and places sample text in it. Also,
+// places the caret on the last character.
+void AccessibilityWinBrowserTest::SetUpInputField(
+ base::win::ScopedComPtr<IAccessibleText>* input_text) {
+ ASSERT_NE(nullptr, input_text);
+ LoadInitialAccessibilityTreeFromHtml(std::string("<!DOCTYPE html><html><body>"
+ "<form><label for='textField'>Browser name:</label>"
+ "<input type='text' id='textField' name='name' value='") +
+ net::EscapeQueryParamValue(INPUT_CONTENTS, false) + std::string(
+ "'></form></body></html>"));
+
+ // Retrieve the IAccessible interface for the web page.
+ base::win::ScopedComPtr<IAccessible> document(GetRendererAccessible());
+ std::vector<base::win::ScopedVariant> document_children =
+ GetAllAccessibleChildren(document.get());
+ ASSERT_EQ(1, document_children.size());
+
+ base::win::ScopedComPtr<IAccessible2> form;
+ HRESULT hr = QueryIAccessible2(GetAccessibleFromVariant(
+ document.get(), document_children[0].AsInput()).get(), form.Receive());
+ ASSERT_EQ(S_OK, hr);
+ std::vector<base::win::ScopedVariant> form_children =
+ GetAllAccessibleChildren(form.get());
+ ASSERT_EQ(2, form_children.size());
+
+ // Find the input text field.
+ base::win::ScopedComPtr<IAccessible2> input;
+ hr = QueryIAccessible2(GetAccessibleFromVariant(
+ form.get(), form_children[1].AsInput()).get(), input.Receive());
+ ASSERT_EQ(S_OK, hr);
+ LONG input_role = 0;
+ hr = input->role(&input_role);
+ ASSERT_EQ(S_OK, hr);
+ ASSERT_EQ(ROLE_SYSTEM_TEXT, input_role);
+
+ // Retrieve the IAccessibleText interface for the field.
+ hr = input.QueryInterface(input_text->Receive());
+ ASSERT_EQ(S_OK, hr);
+
+ // Set the caret on the last character.
+ AccessibilityNotificationWaiter waiter(
+ shell(), AccessibilityModeComplete,
+ ui::AX_EVENT_TEXT_SELECTION_CHANGED);
+ std::wstring caret_offset = base::UTF16ToWide(base::IntToString16(
+ static_cast<int>(CONTENTS_LENGTH - 1)));
+ ExecuteScript(std::wstring(
+ L"var textField = document.getElementById('textField');"
+ L"textField.focus();"
+ L"textField.setSelectionRange(") +
+ caret_offset + L"," + caret_offset + L");");
+ waiter.WaitForNotification();
+}
+
+// Loads a page with a textarea text field and places sample text in it. Also,
+// places the caret on the last character.
+void AccessibilityWinBrowserTest::SetUpTextareaField(
+ base::win::ScopedComPtr<IAccessibleText>* textarea_text) {
+ ASSERT_NE(nullptr, textarea_text);
+ LoadInitialAccessibilityTreeFromHtml(std::string("<!DOCTYPE html><html><body>"
+ "<textarea id='textField' rows='3' cols='60'>") +
+ net::EscapeQueryParamValue(TEXTAREA_CONTENTS, false) + std::string(
+ "</textarea></body></html>"));
+
+ // Retrieve the IAccessible interface for the web page.
+ base::win::ScopedComPtr<IAccessible> document(GetRendererAccessible());
+ std::vector<base::win::ScopedVariant> document_children =
+ GetAllAccessibleChildren(document.get());
+ ASSERT_EQ(1, document_children.size());
+
+ base::win::ScopedComPtr<IAccessible2> section;
+ HRESULT hr = QueryIAccessible2(GetAccessibleFromVariant(
+ document.get(), document_children[0].AsInput()).get(), section.Receive());
+ ASSERT_EQ(S_OK, hr);
+ std::vector<base::win::ScopedVariant> section_children =
+ GetAllAccessibleChildren(section.get());
+ ASSERT_EQ(1, section_children.size());
+
+ // Find the textarea text field.
+ base::win::ScopedComPtr<IAccessible2> textarea;
+ hr = QueryIAccessible2(GetAccessibleFromVariant(
+ section.get(), section_children[0].AsInput()).get(), textarea.Receive());
+ ASSERT_EQ(S_OK, hr);
+ LONG textarea_role = 0;
+ hr = textarea->role(&textarea_role);
+ ASSERT_EQ(S_OK, hr);
+ ASSERT_EQ(ROLE_SYSTEM_TEXT, textarea_role);
+
+ // Retrieve the IAccessibleText interface for the field.
+ hr = textarea.QueryInterface(textarea_text->Receive());
+ ASSERT_EQ(S_OK, hr);
+
+ // Set the caret on the last character.
+ AccessibilityNotificationWaiter waiter(
+ shell(), AccessibilityModeComplete,
+ ui::AX_EVENT_TEXT_SELECTION_CHANGED);
+ std::wstring caret_offset = base::UTF16ToWide(base::IntToString16(
+ static_cast<int>(CONTENTS_LENGTH - 1)));
+ ExecuteScript(std::wstring(
+ L"var textField = document.getElementById('textField');"
+ L"textField.focus();"
+ L"textField.setSelectionRange(") +
+ caret_offset + L"," + caret_offset + L");");
+ waiter.WaitForNotification();
+}
+
+
+// Static helpers ------------------------------------------------
+
+base::win::ScopedComPtr<IAccessible>
+AccessibilityWinBrowserTest::GetAccessibleFromVariant(
IAccessible* parent,
VARIANT* var) {
base::win::ScopedComPtr<IAccessible> ptr;
@@ -41,7 +230,7 @@ base::win::ScopedComPtr<IAccessible> GetAccessibleFromResultVariant(
case VT_DISPATCH: {
IDispatch* dispatch = V_DISPATCH(var);
if (dispatch)
- ptr.QueryFrom(dispatch);
+ dispatch->QueryInterface(ptr.Receive());
break;
}
@@ -49,7 +238,7 @@ base::win::ScopedComPtr<IAccessible> GetAccessibleFromResultVariant(
base::win::ScopedComPtr<IDispatch> dispatch;
HRESULT hr = parent->get_accChild(*var, dispatch.Receive());
EXPECT_TRUE(SUCCEEDED(hr));
- if (dispatch)
+ if (dispatch.get())
dispatch.QueryInterface(ptr.Receive());
break;
}
@@ -57,9 +246,11 @@ base::win::ScopedComPtr<IAccessible> GetAccessibleFromResultVariant(
return ptr;
}
-HRESULT QueryIAccessible2(IAccessible* accessible, IAccessible2** accessible2) {
- // TODO(ctguil): For some reason querying the IAccessible2 interface from
- // IAccessible fails.
+HRESULT AccessibilityWinBrowserTest::QueryIAccessible2(
+ IAccessible* accessible,
+ IAccessible2** accessible2) {
+ // IA2 Spec dictates that IServiceProvider should be used instead of
+ // QueryInterface when retrieving IAccessible2.
base::win::ScopedComPtr<IServiceProvider> service_provider;
HRESULT hr = accessible->QueryInterface(service_provider.Receive());
return SUCCEEDED(hr) ?
@@ -69,11 +260,12 @@ HRESULT QueryIAccessible2(IAccessible* accessible, IAccessible2** accessible2) {
// Recursively search through all of the descendants reachable from an
// IAccessible node and return true if we find one with the given role
// and name.
-void RecursiveFindNodeInAccessibilityTree(IAccessible* node,
- int32 expected_role,
- const std::wstring& expected_name,
- int32 depth,
- bool* found) {
+void AccessibilityWinBrowserTest::FindNodeInAccessibilityTree(
+ IAccessible* node,
+ int32 expected_role,
+ const std::wstring& expected_name,
+ int32 depth,
+ bool* found) {
base::win::ScopedBstr name_bstr;
base::win::ScopedVariant childid_self(CHILDID_SELF);
node->get_accName(childid_self, name_bstr.Receive());
@@ -87,30 +279,21 @@ void RecursiveFindNodeInAccessibilityTree(IAccessible* node,
for (int i = 0; i < depth; i++)
printf(" ");
printf("role=%s name=%s\n",
- base::WideToUTF8(IAccessibleRoleToString(V_I4(&role))).c_str(),
- base::WideToUTF8(name).c_str());
+ base::WideToUTF8(IAccessibleRoleToString(V_I4(role.ptr()))).c_str(),
+ base::WideToUTF8(name).c_str());
- if (expected_role == V_I4(&role) && expected_name == name) {
+ if (expected_role == V_I4(role.ptr()) && expected_name == name) {
*found = true;
return;
}
- LONG child_count = 0;
- HRESULT hr = node->get_accChildCount(&child_count);
- ASSERT_EQ(S_OK, hr);
-
- scoped_ptr<VARIANT[]> child_array(new VARIANT[child_count]);
- LONG obtained_count = 0;
- hr = AccessibleChildren(
- node, 0, child_count, child_array.get(), &obtained_count);
- ASSERT_EQ(S_OK, hr);
- ASSERT_EQ(child_count, obtained_count);
-
- for (int index = 0; index < obtained_count; index++) {
+ std::vector<base::win::ScopedVariant> children = GetAllAccessibleChildren(
+ node);
+ for (size_t i = 0; i < children.size(); ++i) {
base::win::ScopedComPtr<IAccessible> child_accessible(
- GetAccessibleFromResultVariant(node, &child_array.get()[index]));
+ GetAccessibleFromVariant(node, children[i].AsInput()));
if (child_accessible) {
- RecursiveFindNodeInAccessibilityTree(
+ FindNodeInAccessibilityTree(
child_accessible.get(), expected_role, expected_name, depth + 1,
found);
if (*found)
@@ -119,54 +302,60 @@ void RecursiveFindNodeInAccessibilityTree(IAccessible* node,
}
}
-
-// AccessibilityWinBrowserTest ------------------------------------------------
-
-class AccessibilityWinBrowserTest : public ContentBrowserTest {
- public:
- AccessibilityWinBrowserTest();
- virtual ~AccessibilityWinBrowserTest();
-
- protected:
- void LoadInitialAccessibilityTreeFromHtml(const std::string& html);
- IAccessible* GetRendererAccessible();
- void ExecuteScript(const std::wstring& script);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(AccessibilityWinBrowserTest);
-};
-
-AccessibilityWinBrowserTest::AccessibilityWinBrowserTest() {
-}
-
-AccessibilityWinBrowserTest::~AccessibilityWinBrowserTest() {
+// Ensures that the text and the start and end offsets retrieved using
+// get_textAtOffset match the expected values.
+void AccessibilityWinBrowserTest::CheckTextAtOffset(
+ base::win::ScopedComPtr<IAccessibleText>& element,
+ LONG offset,
+ IA2TextBoundaryType boundary_type,
+ LONG expected_start_offset,
+ LONG expected_end_offset,
+ const std::wstring& expected_text) {
+ testing::Message message;
+ message << "While checking for \'" << expected_text << "\' at " <<
+ expected_start_offset << '-' << expected_end_offset << '.';
+ SCOPED_TRACE(message);
+
+ LONG start_offset = 0;
+ LONG end_offset = 0;
+ base::win::ScopedBstr text;
+ HRESULT hr = element->get_textAtOffset(
+ offset, boundary_type,
+ &start_offset, &end_offset, text.Receive());
+ EXPECT_EQ(S_OK, hr);
+ EXPECT_EQ(expected_start_offset, start_offset);
+ EXPECT_EQ(expected_end_offset, end_offset);
+ EXPECT_EQ(expected_text, std::wstring(text, text.Length()));
}
-void AccessibilityWinBrowserTest::LoadInitialAccessibilityTreeFromHtml(
- const std::string& html) {
- AccessibilityNotificationWaiter waiter(
- shell(), AccessibilityModeComplete,
- ui::AX_EVENT_LOAD_COMPLETE);
- GURL html_data_url("data:text/html," + html);
- NavigateToURL(shell(), html_data_url);
- waiter.WaitForNotification();
-}
+std::vector<base::win::ScopedVariant>
+AccessibilityWinBrowserTest::GetAllAccessibleChildren(
+ IAccessible* element) {
+ LONG child_count = 0;
+ HRESULT hr = element->get_accChildCount(&child_count);
+ EXPECT_EQ(S_OK, hr);
+ if (child_count <= 0)
+ return std::vector<base::win::ScopedVariant>();
-// Retrieve the MSAA client accessibility object for the Render Widget Host View
-// of the selected tab.
-IAccessible* AccessibilityWinBrowserTest::GetRendererAccessible() {
- content::WebContents* web_contents = shell()->web_contents();
- return web_contents->GetRenderWidgetHostView()->GetNativeViewAccessible();
-}
+ scoped_ptr<VARIANT[]> children_array(new VARIANT[child_count]);
+ LONG obtained_count = 0;
+ hr = AccessibleChildren(
+ element, 0, child_count, children_array.get(), &obtained_count);
+ EXPECT_EQ(S_OK, hr);
+ EXPECT_EQ(child_count, obtained_count);
-void AccessibilityWinBrowserTest::ExecuteScript(const std::wstring& script) {
- shell()->web_contents()->GetMainFrame()->ExecuteJavaScript(script);
+ std::vector<base::win::ScopedVariant> children(
+ static_cast<size_t>(child_count));
+ for (size_t i = 0; i < children.size(); i++) {
+ children[i].Reset(children_array[i]);
+ }
+ return children;
}
// AccessibleChecker ----------------------------------------------------------
-class AccessibleChecker {
+class AccessibilityWinBrowserTest::AccessibleChecker {
public:
// This constructor can be used if the IA2 role will be the same as the MSAA
// role.
@@ -228,9 +417,10 @@ class AccessibleChecker {
AccessibleCheckerVector children_;
};
-AccessibleChecker::AccessibleChecker(const std::wstring& expected_name,
- int32 expected_role,
- const std::wstring& expected_value)
+AccessibilityWinBrowserTest::AccessibleChecker::AccessibleChecker(
+ const std::wstring& expected_name,
+ int32 expected_role,
+ const std::wstring& expected_value)
: name_(expected_name),
role_(expected_role),
ia2_role_(expected_role),
@@ -238,10 +428,11 @@ AccessibleChecker::AccessibleChecker(const std::wstring& expected_name,
state_(-1) {
}
-AccessibleChecker::AccessibleChecker(const std::wstring& expected_name,
- int32 expected_role,
- int32 expected_ia2_role,
- const std::wstring& expected_value)
+AccessibilityWinBrowserTest::AccessibleChecker::AccessibleChecker(
+ const std::wstring& expected_name,
+ int32 expected_role,
+ int32 expected_ia2_role,
+ const std::wstring& expected_value)
: name_(expected_name),
role_(expected_role),
ia2_role_(expected_ia2_role),
@@ -249,10 +440,11 @@ AccessibleChecker::AccessibleChecker(const std::wstring& expected_name,
state_(-1) {
}
-AccessibleChecker::AccessibleChecker(const std::wstring& expected_name,
- const std::wstring& expected_role,
- int32 expected_ia2_role,
- const std::wstring& expected_value)
+AccessibilityWinBrowserTest::AccessibleChecker::AccessibleChecker(
+ const std::wstring& expected_name,
+ const std::wstring& expected_role,
+ int32 expected_ia2_role,
+ const std::wstring& expected_value)
: name_(expected_name),
role_(expected_role.c_str()),
ia2_role_(expected_ia2_role),
@@ -260,14 +452,15 @@ AccessibleChecker::AccessibleChecker(const std::wstring& expected_name,
state_(-1) {
}
-void AccessibleChecker::AppendExpectedChild(
+void AccessibilityWinBrowserTest::AccessibleChecker::AppendExpectedChild(
AccessibleChecker* expected_child) {
children_.push_back(expected_child);
}
-void AccessibleChecker::CheckAccessible(IAccessible* accessible) {
- SCOPED_TRACE("while checking " +
- base::UTF16ToUTF8(RoleVariantToString(role_)));
+void AccessibilityWinBrowserTest::AccessibleChecker::CheckAccessible(
+ IAccessible* accessible) {
+ SCOPED_TRACE("While checking "
+ + base::UTF16ToUTF8(RoleVariantToString(role_)));
CheckAccessibleName(accessible);
CheckAccessibleRole(accessible);
CheckIA2Role(accessible);
@@ -276,15 +469,18 @@ void AccessibleChecker::CheckAccessible(IAccessible* accessible) {
CheckAccessibleChildren(accessible);
}
-void AccessibleChecker::SetExpectedValue(const std::wstring& expected_value) {
+void AccessibilityWinBrowserTest::AccessibleChecker::SetExpectedValue(
+ const std::wstring& expected_value) {
value_ = expected_value;
}
-void AccessibleChecker::SetExpectedState(LONG expected_state) {
+void AccessibilityWinBrowserTest::AccessibleChecker::SetExpectedState(
+ LONG expected_state) {
state_ = expected_state;
}
-void AccessibleChecker::CheckAccessibleName(IAccessible* accessible) {
+void AccessibilityWinBrowserTest::AccessibleChecker::CheckAccessibleName(
+ IAccessible* accessible) {
base::win::ScopedBstr name;
base::win::ScopedVariant childid_self(CHILDID_SELF);
HRESULT hr = accessible->get_accName(childid_self, name.Receive());
@@ -299,7 +495,8 @@ void AccessibleChecker::CheckAccessibleName(IAccessible* accessible) {
}
}
-void AccessibleChecker::CheckAccessibleRole(IAccessible* accessible) {
+void AccessibilityWinBrowserTest::AccessibleChecker::CheckAccessibleRole(
+ IAccessible* accessible) {
base::win::ScopedVariant role;
base::win::ScopedVariant childid_self(CHILDID_SELF);
HRESULT hr = accessible->get_accRole(childid_self, role.Receive());
@@ -309,7 +506,8 @@ void AccessibleChecker::CheckAccessibleRole(IAccessible* accessible) {
<< "\nGot role: " << RoleVariantToString(role);
}
-void AccessibleChecker::CheckIA2Role(IAccessible* accessible) {
+void AccessibilityWinBrowserTest::AccessibleChecker::CheckIA2Role(
+ IAccessible* accessible) {
base::win::ScopedComPtr<IAccessible2> accessible2;
HRESULT hr = QueryIAccessible2(accessible, accessible2.Receive());
ASSERT_EQ(S_OK, hr);
@@ -321,7 +519,8 @@ void AccessibleChecker::CheckIA2Role(IAccessible* accessible) {
<< "\nGot ia2 role: " << IAccessible2RoleToString(ia2_role);
}
-void AccessibleChecker::CheckAccessibleValue(IAccessible* accessible) {
+void AccessibilityWinBrowserTest::AccessibleChecker::CheckAccessibleValue(
+ IAccessible* accessible) {
// Don't check the value if if's a DOCUMENT role, because the value
// is supposed to be the url (and we don't keep track of that in the
// test expectations).
@@ -329,7 +528,7 @@ void AccessibleChecker::CheckAccessibleValue(IAccessible* accessible) {
base::win::ScopedVariant childid_self(CHILDID_SELF);
HRESULT hr = accessible->get_accRole(childid_self, role.Receive());
ASSERT_EQ(S_OK, hr);
- if (role.type() == VT_I4 && V_I4(&role) == ROLE_SYSTEM_DOCUMENT)
+ if (role.type() == VT_I4 && V_I4(role.ptr()) == ROLE_SYSTEM_DOCUMENT)
return;
// Get the value.
@@ -341,7 +540,8 @@ void AccessibleChecker::CheckAccessibleValue(IAccessible* accessible) {
EXPECT_EQ(value_, std::wstring(value, value.Length()));
}
-void AccessibleChecker::CheckAccessibleState(IAccessible* accessible) {
+void AccessibilityWinBrowserTest::AccessibleChecker::CheckAccessibleState(
+ IAccessible* accessible) {
if (state_ < 0)
return;
@@ -350,7 +550,7 @@ void AccessibleChecker::CheckAccessibleState(IAccessible* accessible) {
HRESULT hr = accessible->get_accState(childid_self, state.Receive());
EXPECT_EQ(S_OK, hr);
ASSERT_EQ(VT_I4, state.type());
- LONG obj_state = V_I4(&state);
+ LONG obj_state = V_I4(state.ptr());
// Avoid flakiness. The "offscreen" state depends on whether the browser
// window is frontmost or not, and "hottracked" depends on whether the
// mouse cursor happens to be over the element.
@@ -360,36 +560,34 @@ void AccessibleChecker::CheckAccessibleState(IAccessible* accessible) {
<< "\nGot state: " << IAccessibleStateToString(obj_state);
}
-void AccessibleChecker::CheckAccessibleChildren(IAccessible* parent) {
- LONG child_count = 0;
- HRESULT hr = parent->get_accChildCount(&child_count);
- EXPECT_EQ(S_OK, hr);
+void AccessibilityWinBrowserTest::AccessibleChecker::CheckAccessibleChildren(
+ IAccessible* parent) {
+ std::vector<base::win::ScopedVariant> obtained_children =
+ GetAllAccessibleChildren(parent);
+ size_t child_count = obtained_children.size();
ASSERT_EQ(child_count, children_.size());
- scoped_ptr<VARIANT[]> child_array(new VARIANT[child_count]);
- LONG obtained_count = 0;
- hr = AccessibleChildren(parent, 0, child_count,
- child_array.get(), &obtained_count);
- ASSERT_EQ(S_OK, hr);
- ASSERT_EQ(child_count, obtained_count);
-
- VARIANT* child = child_array.get();
- for (AccessibleCheckerVector::iterator child_checker = children_.begin();
- child_checker != children_.end();
+ AccessibleCheckerVector::iterator child_checker;
+ std::vector<base::win::ScopedVariant>::iterator child;
+ for (child_checker = children_.begin(),
+ child = obtained_children.begin();
+ child_checker != children_.end()
+ && child != obtained_children.end();
++child_checker, ++child) {
base::win::ScopedComPtr<IAccessible> child_accessible(
- GetAccessibleFromResultVariant(parent, child));
+ GetAccessibleFromVariant(parent, child->AsInput()));
ASSERT_TRUE(child_accessible.get());
- (*child_checker)->CheckAccessible(child_accessible);
+ (*child_checker)->CheckAccessible(child_accessible.get());
}
}
-base::string16 AccessibleChecker::RoleVariantToString(
+base::string16
+AccessibilityWinBrowserTest::AccessibleChecker::RoleVariantToString(
const base::win::ScopedVariant& role) {
if (role.type() == VT_I4)
- return IAccessibleRoleToString(V_I4(&role));
+ return IAccessibleRoleToString(V_I4(role.ptr()));
if (role.type() == VT_BSTR)
- return base::string16(V_BSTR(&role), SysStringLen(V_BSTR(&role)));
+ return base::string16(V_BSTR(role.ptr()), SysStringLen(V_BSTR(role.ptr())));
return base::string16();
}
@@ -667,7 +865,7 @@ IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
ASSERT_EQ(S_OK, hr);
bool found = false;
- RecursiveFindNodeInAccessibilityTree(
+ FindNodeInAccessibilityTree(
browser_accessible.get(), ROLE_SYSTEM_DOCUMENT, L"MyDocument", 0, &found);
ASSERT_EQ(found, true);
}
@@ -684,15 +882,16 @@ IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
// Get the ISimpleDOM object for the document.
base::win::ScopedComPtr<IServiceProvider> service_provider;
- HRESULT hr = static_cast<IAccessible*>(document_accessible)->QueryInterface(
- service_provider.Receive());
+ HRESULT hr = static_cast<IAccessible*>(document_accessible.get())
+ ->QueryInterface(service_provider.Receive());
ASSERT_EQ(S_OK, hr);
const GUID refguid = {0x0c539790, 0x12e4, 0x11cf,
0xb6, 0x61, 0x00, 0xaa, 0x00, 0x4c, 0xd6, 0xd8};
base::win::ScopedComPtr<ISimpleDOMNode> document_isimpledomnode;
- hr = static_cast<IServiceProvider *>(service_provider)->QueryService(
- refguid, IID_ISimpleDOMNode,
- reinterpret_cast<void**>(document_isimpledomnode.Receive()));
+ hr = static_cast<IServiceProvider*>(service_provider.get())
+ ->QueryService(
+ refguid, IID_ISimpleDOMNode,
+ reinterpret_cast<void**>(document_isimpledomnode.Receive()));
ASSERT_EQ(S_OK, hr);
base::win::ScopedBstr node_name;
@@ -753,4 +952,519 @@ IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest, TestRoleGroup) {
document_checker.CheckAccessible(GetRendererAccessible());
}
+IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
+ TestSetCaretOffset) {
+ base::win::ScopedComPtr<IAccessibleText> input_text;
+ SetUpInputField(&input_text);
+
+ LONG caret_offset = 0;
+ HRESULT hr = input_text->get_caretOffset(&caret_offset);
+ EXPECT_EQ(S_OK, hr);
+ EXPECT_EQ(CONTENTS_LENGTH - 1, caret_offset);
+
+ AccessibilityNotificationWaiter waiter(
+ shell(), AccessibilityModeComplete,
+ ui::AX_EVENT_TEXT_SELECTION_CHANGED);
+ caret_offset = 0;
+ hr = input_text->setCaretOffset(caret_offset);
+ EXPECT_EQ(S_OK, hr);
+ waiter.WaitForNotification();
+
+ hr = input_text->get_caretOffset(&caret_offset);
+ EXPECT_EQ(S_OK, hr);
+ EXPECT_EQ(0, caret_offset);
+}
+
+IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
+ TestMultiLineSetCaretOffset) {
+ base::win::ScopedComPtr<IAccessibleText> textarea_text;
+ SetUpTextareaField(&textarea_text);
+
+ LONG caret_offset = 0;
+ HRESULT hr = textarea_text->get_caretOffset(&caret_offset);
+ EXPECT_EQ(S_OK, hr);
+ EXPECT_EQ(CONTENTS_LENGTH - 1, caret_offset);
+
+ AccessibilityNotificationWaiter waiter(
+ shell(), AccessibilityModeComplete,
+ ui::AX_EVENT_TEXT_SELECTION_CHANGED);
+ caret_offset = 0;
+ hr = textarea_text->setCaretOffset(caret_offset);
+ EXPECT_EQ(S_OK, hr);
+ waiter.WaitForNotification();
+
+ hr = textarea_text->get_caretOffset(&caret_offset);
+ EXPECT_EQ(S_OK, hr);
+ EXPECT_EQ(0, caret_offset);
+}
+
+IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
+ TestTextAtOffsetWithInvalidArgs) {
+ base::win::ScopedComPtr<IAccessibleText> input_text;
+ SetUpInputField(&input_text);
+ HRESULT hr = input_text->get_textAtOffset(
+ 0, IA2_TEXT_BOUNDARY_CHAR, NULL, NULL, NULL);
+ EXPECT_EQ(E_INVALIDARG, hr);
+
+ // Test invalid offset.
+ LONG start_offset = 0;
+ LONG end_offset = 0;
+ base::win::ScopedBstr text;
+ LONG invalid_offset = -5;
+ hr = input_text->get_textAtOffset(
+ invalid_offset, IA2_TEXT_BOUNDARY_CHAR,
+ &start_offset, &end_offset, text.Receive());
+ EXPECT_EQ(E_INVALIDARG, hr);
+ EXPECT_EQ(0, start_offset);
+ EXPECT_EQ(0, end_offset);
+ EXPECT_EQ(nullptr, static_cast<BSTR>(text));
+ invalid_offset = CONTENTS_LENGTH + 1;
+ hr = input_text->get_textAtOffset(
+ invalid_offset, IA2_TEXT_BOUNDARY_WORD,
+ &start_offset, &end_offset, text.Receive());
+ EXPECT_EQ(E_INVALIDARG, hr);
+ EXPECT_EQ(0, start_offset);
+ EXPECT_EQ(0, end_offset);
+ EXPECT_EQ(nullptr, static_cast<BSTR>(text));
+
+ // According to the IA2 Spec, only line boundaries should succeed when
+ // the offset is one past the end of the text.
+ invalid_offset = CONTENTS_LENGTH;
+ hr = input_text->get_textAtOffset(
+ invalid_offset, IA2_TEXT_BOUNDARY_CHAR,
+ &start_offset, &end_offset, text.Receive());
+ EXPECT_EQ(S_FALSE, hr);
+ EXPECT_EQ(0, start_offset);
+ EXPECT_EQ(0, end_offset);
+ EXPECT_EQ(nullptr, static_cast<BSTR>(text));
+ hr = input_text->get_textAtOffset(
+ invalid_offset, IA2_TEXT_BOUNDARY_WORD,
+ &start_offset, &end_offset, text.Receive());
+ EXPECT_EQ(S_FALSE, hr);
+ EXPECT_EQ(0, start_offset);
+ EXPECT_EQ(0, end_offset);
+ EXPECT_EQ(nullptr, static_cast<BSTR>(text));
+ hr = input_text->get_textAtOffset(
+ invalid_offset, IA2_TEXT_BOUNDARY_SENTENCE,
+ &start_offset, &end_offset, text.Receive());
+ EXPECT_EQ(S_FALSE, hr);
+ EXPECT_EQ(0, start_offset);
+ EXPECT_EQ(0, end_offset);
+ EXPECT_EQ(nullptr, static_cast<BSTR>(text));
+ hr = input_text->get_textAtOffset(
+ invalid_offset, IA2_TEXT_BOUNDARY_ALL,
+ &start_offset, &end_offset, text.Receive());
+ EXPECT_EQ(S_FALSE, hr);
+ EXPECT_EQ(0, start_offset);
+ EXPECT_EQ(0, end_offset);
+ EXPECT_EQ(nullptr, static_cast<BSTR>(text));
+
+ // The same behavior should be observed when the special offset
+ // IA2_TEXT_OFFSET_LENGTH is used.
+ hr = input_text->get_textAtOffset(
+ IA2_TEXT_OFFSET_LENGTH, IA2_TEXT_BOUNDARY_CHAR,
+ &start_offset, &end_offset, text.Receive());
+ EXPECT_EQ(S_FALSE, hr);
+ EXPECT_EQ(0, start_offset);
+ EXPECT_EQ(0, end_offset);
+ EXPECT_EQ(nullptr, static_cast<BSTR>(text));
+ hr = input_text->get_textAtOffset(
+ IA2_TEXT_OFFSET_LENGTH, IA2_TEXT_BOUNDARY_WORD,
+ &start_offset, &end_offset, text.Receive());
+ EXPECT_EQ(S_FALSE, hr);
+ EXPECT_EQ(0, start_offset);
+ EXPECT_EQ(0, end_offset);
+ EXPECT_EQ(nullptr, static_cast<BSTR>(text));
+ hr = input_text->get_textAtOffset(
+ IA2_TEXT_OFFSET_LENGTH, IA2_TEXT_BOUNDARY_SENTENCE,
+ &start_offset, &end_offset, text.Receive());
+ EXPECT_EQ(S_FALSE, hr);
+ EXPECT_EQ(0, start_offset);
+ EXPECT_EQ(0, end_offset);
+ EXPECT_EQ(nullptr, static_cast<BSTR>(text));
+ hr = input_text->get_textAtOffset(
+ IA2_TEXT_OFFSET_LENGTH, IA2_TEXT_BOUNDARY_ALL,
+ &start_offset, &end_offset, text.Receive());
+ EXPECT_EQ(S_FALSE, hr);
+ EXPECT_EQ(0, start_offset);
+ EXPECT_EQ(0, end_offset);
+ EXPECT_EQ(nullptr, static_cast<BSTR>(text));
+}
+
+IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
+ TestMultiLineTextAtOffsetWithInvalidArgs) {
+ base::win::ScopedComPtr<IAccessibleText> textarea_text;
+ SetUpTextareaField(&textarea_text);
+ HRESULT hr = textarea_text->get_textAtOffset(
+ 0, IA2_TEXT_BOUNDARY_CHAR, NULL, NULL, NULL);
+ EXPECT_EQ(E_INVALIDARG, hr);
+
+ // Test invalid offset.
+ LONG start_offset = 0;
+ LONG end_offset = 0;
+ base::win::ScopedBstr text;
+ LONG invalid_offset = -5;
+ hr = textarea_text->get_textAtOffset(
+ invalid_offset, IA2_TEXT_BOUNDARY_CHAR,
+ &start_offset, &end_offset, text.Receive());
+ EXPECT_EQ(E_INVALIDARG, hr);
+ EXPECT_EQ(0, start_offset);
+ EXPECT_EQ(0, end_offset);
+ EXPECT_EQ(nullptr, static_cast<BSTR>(text));
+ invalid_offset = CONTENTS_LENGTH + 1;
+ hr = textarea_text->get_textAtOffset(
+ invalid_offset, IA2_TEXT_BOUNDARY_WORD,
+ &start_offset, &end_offset, text.Receive());
+ EXPECT_EQ(E_INVALIDARG, hr);
+ EXPECT_EQ(0, start_offset);
+ EXPECT_EQ(0, end_offset);
+ EXPECT_EQ(nullptr, static_cast<BSTR>(text));
+
+ // According to the IA2 Spec, only line boundaries should succeed when
+ // the offset is one past the end of the text.
+ invalid_offset = CONTENTS_LENGTH;
+ hr = textarea_text->get_textAtOffset(
+ invalid_offset, IA2_TEXT_BOUNDARY_CHAR,
+ &start_offset, &end_offset, text.Receive());
+ EXPECT_EQ(S_FALSE, hr);
+ EXPECT_EQ(0, start_offset);
+ EXPECT_EQ(0, end_offset);
+ EXPECT_EQ(nullptr, static_cast<BSTR>(text));
+ hr = textarea_text->get_textAtOffset(
+ invalid_offset, IA2_TEXT_BOUNDARY_WORD,
+ &start_offset, &end_offset, text.Receive());
+ EXPECT_EQ(S_FALSE, hr);
+ EXPECT_EQ(0, start_offset);
+ EXPECT_EQ(0, end_offset);
+ EXPECT_EQ(nullptr, static_cast<BSTR>(text));
+ hr = textarea_text->get_textAtOffset(
+ invalid_offset, IA2_TEXT_BOUNDARY_SENTENCE,
+ &start_offset, &end_offset, text.Receive());
+ EXPECT_EQ(S_FALSE, hr);
+ EXPECT_EQ(0, start_offset);
+ EXPECT_EQ(0, end_offset);
+ EXPECT_EQ(nullptr, static_cast<BSTR>(text));
+ hr = textarea_text->get_textAtOffset(
+ invalid_offset, IA2_TEXT_BOUNDARY_ALL,
+ &start_offset, &end_offset, text.Receive());
+ EXPECT_EQ(S_FALSE, hr);
+ EXPECT_EQ(0, start_offset);
+ EXPECT_EQ(0, end_offset);
+ EXPECT_EQ(nullptr, static_cast<BSTR>(text));
+
+ // The same behavior should be observed when the special offset
+ // IA2_TEXT_OFFSET_LENGTH is used.
+ hr = textarea_text->get_textAtOffset(
+ IA2_TEXT_OFFSET_LENGTH, IA2_TEXT_BOUNDARY_CHAR,
+ &start_offset, &end_offset, text.Receive());
+ EXPECT_EQ(S_FALSE, hr);
+ EXPECT_EQ(0, start_offset);
+ EXPECT_EQ(0, end_offset);
+ EXPECT_EQ(nullptr, static_cast<BSTR>(text));
+ hr = textarea_text->get_textAtOffset(
+ IA2_TEXT_OFFSET_LENGTH, IA2_TEXT_BOUNDARY_WORD,
+ &start_offset, &end_offset, text.Receive());
+ EXPECT_EQ(S_FALSE, hr);
+ EXPECT_EQ(0, start_offset);
+ EXPECT_EQ(0, end_offset);
+ EXPECT_EQ(nullptr, static_cast<BSTR>(text));
+ hr = textarea_text->get_textAtOffset(
+ IA2_TEXT_OFFSET_LENGTH, IA2_TEXT_BOUNDARY_SENTENCE,
+ &start_offset, &end_offset, text.Receive());
+ EXPECT_EQ(S_FALSE, hr);
+ EXPECT_EQ(0, start_offset);
+ EXPECT_EQ(0, end_offset);
+ EXPECT_EQ(nullptr, static_cast<BSTR>(text));
+ hr = textarea_text->get_textAtOffset(
+ IA2_TEXT_OFFSET_LENGTH, IA2_TEXT_BOUNDARY_ALL,
+ &start_offset, &end_offset, text.Receive());
+ EXPECT_EQ(S_FALSE, hr);
+ EXPECT_EQ(0, start_offset);
+ EXPECT_EQ(0, end_offset);
+ EXPECT_EQ(nullptr, static_cast<BSTR>(text));
+}
+
+IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
+ TestTextAtOffsetWithBoundaryCharacter) {
+ base::win::ScopedComPtr<IAccessibleText> input_text;
+ SetUpInputField(&input_text);
+ for (LONG offset = 0; offset < CONTENTS_LENGTH; ++offset) {
+ std::wstring expected_text(1, INPUT_CONTENTS[offset]);
+ LONG expected_start_offset = offset;
+ LONG expected_end_offset = offset + 1;
+ CheckTextAtOffset(input_text, offset, IA2_TEXT_BOUNDARY_CHAR,
+ expected_start_offset, expected_end_offset, expected_text);
+ }
+
+ for (LONG offset = CONTENTS_LENGTH - 1; offset >= 0; --offset) {
+ std::wstring expected_text(1, INPUT_CONTENTS[offset]);
+ LONG expected_start_offset = offset;
+ LONG expected_end_offset = offset + 1;
+ CheckTextAtOffset(input_text, offset, IA2_TEXT_BOUNDARY_CHAR,
+ expected_start_offset, expected_end_offset, expected_text);
+ }
+
+ CheckTextAtOffset(input_text, IA2_TEXT_OFFSET_CARET,
+ IA2_TEXT_BOUNDARY_CHAR, CONTENTS_LENGTH - 1, CONTENTS_LENGTH, L".");
+}
+
+IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
+ TestMultiLineTextAtOffsetWithBoundaryCharacter) {
+ base::win::ScopedComPtr<IAccessibleText> textarea_text;
+ SetUpTextareaField(&textarea_text);
+ for (LONG offset = 0; offset < CONTENTS_LENGTH; ++offset) {
+ std::wstring expected_text(1, TEXTAREA_CONTENTS[offset]);
+ LONG expected_start_offset = offset;
+ LONG expected_end_offset = offset + 1;
+ CheckTextAtOffset(textarea_text, offset, IA2_TEXT_BOUNDARY_CHAR,
+ expected_start_offset, expected_end_offset, expected_text);
+ }
+
+ for (LONG offset = CONTENTS_LENGTH - 1; offset >= 0; --offset) {
+ std::wstring expected_text(1, TEXTAREA_CONTENTS[offset]);
+ LONG expected_start_offset = offset;
+ LONG expected_end_offset = offset + 1;
+ CheckTextAtOffset(textarea_text, offset, IA2_TEXT_BOUNDARY_CHAR,
+ expected_start_offset, expected_end_offset, expected_text);
+ }
+
+ CheckTextAtOffset(textarea_text, IA2_TEXT_OFFSET_CARET,
+ IA2_TEXT_BOUNDARY_CHAR, CONTENTS_LENGTH - 1, CONTENTS_LENGTH, L".");
+}
+
+IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
+ TestTextAtOffsetWithBoundaryWord) {
+ base::win::ScopedComPtr<IAccessibleText> input_text;
+ SetUpInputField(&input_text);
+
+ // Trailing punctuation should be included as part of the previous word.
+ CheckTextAtOffset(input_text, 0, IA2_TEXT_BOUNDARY_WORD,
+ 0, 4, L"Moz/");
+ CheckTextAtOffset(input_text, 2, IA2_TEXT_BOUNDARY_WORD,
+ 0, 4, L"Moz/");
+
+ // If the offset is at the punctuation, it should return
+ // the previous word.
+ CheckTextAtOffset(input_text, 3, IA2_TEXT_BOUNDARY_WORD,
+ 0, 4, L"Moz/");
+
+ // Numbers with a decimal point ("." for U.S), should be treated as one word.
+ // Also, trailing punctuation that occurs after empty space should be part of
+ // the word. ("5.0 (" and not "5.0 ".)
+ CheckTextAtOffset(input_text, 4, IA2_TEXT_BOUNDARY_WORD,
+ 4, 9, L"5.0 (");
+ CheckTextAtOffset(input_text, 5, IA2_TEXT_BOUNDARY_WORD,
+ 4, 9, L"5.0 (");
+ CheckTextAtOffset(input_text, 6, IA2_TEXT_BOUNDARY_WORD,
+ 4, 9, L"5.0 (");
+ CheckTextAtOffset(input_text, 7, IA2_TEXT_BOUNDARY_WORD,
+ 4, 9, L"5.0 (");
+
+ // Leading punctuation should not be included with the word after it.
+ CheckTextAtOffset(input_text, 8, IA2_TEXT_BOUNDARY_WORD,
+ 4, 9, L"5.0 (");
+ CheckTextAtOffset(input_text, 11, IA2_TEXT_BOUNDARY_WORD,
+ 9, 12, L"ST ");
+
+ // Numbers separated from letters with trailing punctuation should
+ // be split into two words. Same for abreviations like "i.e.".
+ CheckTextAtOffset(input_text, 12, IA2_TEXT_BOUNDARY_WORD,
+ 12, 14, L"6.");
+ CheckTextAtOffset(input_text, 15, IA2_TEXT_BOUNDARY_WORD,
+ 14, 17, L"x; ");
+
+ // Words with numbers should be treated like ordinary words.
+ CheckTextAtOffset(input_text, 17, IA2_TEXT_BOUNDARY_WORD,
+ 17, 24, L"WWW33) ");
+ CheckTextAtOffset(input_text, 23, IA2_TEXT_BOUNDARY_WORD,
+ 17, 24, L"WWW33) ");
+
+ // Multiple trailing empty spaces should be part of the word preceding it.
+ CheckTextAtOffset(input_text, 28, IA2_TEXT_BOUNDARY_WORD,
+ 24, 33, L"WebKit \"");
+ CheckTextAtOffset(input_text, 31, IA2_TEXT_BOUNDARY_WORD,
+ 24, 33, L"WebKit \"");
+ CheckTextAtOffset(input_text, 32, IA2_TEXT_BOUNDARY_WORD,
+ 24, 33, L"WebKit \"");
+
+ // Leading punctuation such as quotation marks should not be part of the word.
+ CheckTextAtOffset(input_text, 33, IA2_TEXT_BOUNDARY_WORD,
+ 33, 40, L"KHTML, ");
+ CheckTextAtOffset(input_text, 38, IA2_TEXT_BOUNDARY_WORD,
+ 33, 40, L"KHTML, ");
+
+ // Trailing final punctuation should be part of the last word.
+ CheckTextAtOffset(input_text, 41, IA2_TEXT_BOUNDARY_WORD,
+ 40, CONTENTS_LENGTH, L"like\".");
+ CheckTextAtOffset(input_text, 45, IA2_TEXT_BOUNDARY_WORD,
+ 40, CONTENTS_LENGTH, L"like\".");
+
+ // Test special offsets.
+ CheckTextAtOffset(input_text, IA2_TEXT_OFFSET_CARET,
+ IA2_TEXT_BOUNDARY_WORD, 40, CONTENTS_LENGTH, L"like\".");
+}
+
+IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
+ TestMultiLineTextAtOffsetWithBoundaryWord) {
+ base::win::ScopedComPtr<IAccessibleText> textarea_text;
+ SetUpTextareaField(&textarea_text);
+
+ // Trailing punctuation should be included as part of the previous word.
+ CheckTextAtOffset(textarea_text, 0, IA2_TEXT_BOUNDARY_WORD,
+ 0, 4, L"Moz/");
+ CheckTextAtOffset(textarea_text, 2, IA2_TEXT_BOUNDARY_WORD,
+ 0, 4, L"Moz/");
+
+ // If the offset is at the punctuation, it should return
+ // the previous word.
+ CheckTextAtOffset(textarea_text, 3, IA2_TEXT_BOUNDARY_WORD,
+ 0, 4, L"Moz/");
+
+ // Numbers with a decimal point ("." for U.S), should be treated as one word.
+ // Also, trailing punctuation that occurs after empty space should be part of
+ // the word. ("5.0 (" and not "5.0 ".)
+ CheckTextAtOffset(textarea_text, 4, IA2_TEXT_BOUNDARY_WORD,
+ 4, 9, L"5.0 (");
+ CheckTextAtOffset(textarea_text, 5, IA2_TEXT_BOUNDARY_WORD,
+ 4, 9, L"5.0 (");
+ CheckTextAtOffset(textarea_text, 6, IA2_TEXT_BOUNDARY_WORD,
+ 4, 9, L"5.0 (");
+ CheckTextAtOffset(textarea_text, 7, IA2_TEXT_BOUNDARY_WORD,
+ 4, 9, L"5.0 (");
+
+ // Leading punctuation should not be included with the word after it.
+ CheckTextAtOffset(textarea_text, 8, IA2_TEXT_BOUNDARY_WORD,
+ 4, 9, L"5.0 (");
+ CheckTextAtOffset(textarea_text, 11, IA2_TEXT_BOUNDARY_WORD,
+ 9, 12, L"ST ");
+
+ // Numbers separated from letters with trailing punctuation should
+ // be split into two words. Same for abreviations like "i.e.".
+ CheckTextAtOffset(textarea_text, 12, IA2_TEXT_BOUNDARY_WORD,
+ 12, 14, L"6.");
+ CheckTextAtOffset(textarea_text, 15, IA2_TEXT_BOUNDARY_WORD,
+ 14, 17, L"x; ");
+
+ // Words with numbers should be treated like ordinary words.
+ CheckTextAtOffset(textarea_text, 17, IA2_TEXT_BOUNDARY_WORD,
+ 17, 24, L"WWW33)\n");
+ CheckTextAtOffset(textarea_text, 23, IA2_TEXT_BOUNDARY_WORD,
+ 17, 24, L"WWW33)\n");
+
+ // Multiple trailing empty spaces should be part of the word preceding it.
+ CheckTextAtOffset(textarea_text, 28, IA2_TEXT_BOUNDARY_WORD,
+ 24, 33, L"WebKit \n\"");
+ CheckTextAtOffset(textarea_text, 31, IA2_TEXT_BOUNDARY_WORD,
+ 24, 33, L"WebKit \n\"");
+ CheckTextAtOffset(textarea_text, 32, IA2_TEXT_BOUNDARY_WORD,
+ 24, 33, L"WebKit \n\"");
+
+ // Leading punctuation such as quotation marks should not be part of the word.
+ CheckTextAtOffset(textarea_text, 33, IA2_TEXT_BOUNDARY_WORD,
+ 33, 40, L"KHTML, ");
+ CheckTextAtOffset(textarea_text, 38, IA2_TEXT_BOUNDARY_WORD,
+ 33, 40, L"KHTML, ");
+
+ // Trailing final punctuation should be part of the last word.
+ CheckTextAtOffset(textarea_text, 41, IA2_TEXT_BOUNDARY_WORD,
+ 40, CONTENTS_LENGTH, L"like\".");
+ CheckTextAtOffset(textarea_text, 45, IA2_TEXT_BOUNDARY_WORD,
+ 40, CONTENTS_LENGTH, L"like\".");
+
+ // Test special offsets.
+ CheckTextAtOffset(textarea_text, IA2_TEXT_OFFSET_CARET,
+ IA2_TEXT_BOUNDARY_WORD, 40, CONTENTS_LENGTH, L"like\".");
+}
+
+IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
+ TestTextAtOffsetWithBoundarySentence) {
+ base::win::ScopedComPtr<IAccessibleText> input_text;
+ SetUpInputField(&input_text);
+
+ // Sentence navigation is not currently implemented.
+ LONG start_offset = 0;
+ LONG end_offset = 0;
+ base::win::ScopedBstr text;
+ HRESULT hr = input_text->get_textAtOffset(
+ 5, IA2_TEXT_BOUNDARY_SENTENCE,
+ &start_offset, &end_offset, text.Receive());
+ EXPECT_EQ(S_FALSE, hr);
+}
+
+IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
+ TestMultiLineTextAtOffsetWithBoundarySentence) {
+ base::win::ScopedComPtr<IAccessibleText> textarea_text;
+ SetUpTextareaField(&textarea_text);
+
+ // Sentence navigation is not currently implemented.
+ LONG start_offset = 0;
+ LONG end_offset = 0;
+ base::win::ScopedBstr text;
+ HRESULT hr = textarea_text->get_textAtOffset(
+ 25, IA2_TEXT_BOUNDARY_SENTENCE,
+ &start_offset, &end_offset, text.Receive());
+ EXPECT_EQ(S_FALSE, hr);
+}
+
+IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
+ TestTextAtOffsetWithBoundaryLine) {
+ base::win::ScopedComPtr<IAccessibleText> input_text;
+ SetUpInputField(&input_text);
+
+ // Single line text fields should return the whole text.
+ CheckTextAtOffset(input_text, 0, IA2_TEXT_BOUNDARY_LINE,
+ 0, CONTENTS_LENGTH, base::SysUTF8ToWide(INPUT_CONTENTS));
+
+ // Test special offsets.
+ CheckTextAtOffset(input_text, IA2_TEXT_OFFSET_LENGTH, IA2_TEXT_BOUNDARY_LINE,
+ 0, CONTENTS_LENGTH, base::SysUTF8ToWide(INPUT_CONTENTS));
+ CheckTextAtOffset(input_text, IA2_TEXT_OFFSET_CARET, IA2_TEXT_BOUNDARY_LINE,
+ 0, CONTENTS_LENGTH, base::SysUTF8ToWide(INPUT_CONTENTS));
+}
+
+IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
+ TestMultiLineTextAtOffsetWithBoundaryLine) {
+ base::win::ScopedComPtr<IAccessibleText> textarea_text;
+ SetUpTextareaField(&textarea_text);
+
+ CheckTextAtOffset(textarea_text, 0, IA2_TEXT_BOUNDARY_LINE,
+ 0, 24, L"Moz/5.0 (ST 6.x; WWW33)\n");
+
+ // If the offset is at the newline, return the line preceding it.
+ CheckTextAtOffset(textarea_text, 31, IA2_TEXT_BOUNDARY_LINE,
+ 24, 32, L"WebKit \n");
+
+ // Last line does not have a trailing newline.
+ CheckTextAtOffset(textarea_text, 32, IA2_TEXT_BOUNDARY_LINE,
+ 32, CONTENTS_LENGTH, L"\"KHTML, like\".");
+
+ // An offset one past the last character should return the last line.
+ CheckTextAtOffset(textarea_text, CONTENTS_LENGTH, IA2_TEXT_BOUNDARY_LINE,
+ 32, CONTENTS_LENGTH, L"\"KHTML, like\".");
+
+ // Test special offsets.
+ CheckTextAtOffset(textarea_text, IA2_TEXT_OFFSET_LENGTH,
+ IA2_TEXT_BOUNDARY_LINE, 32, CONTENTS_LENGTH, L"\"KHTML, like\".");
+ CheckTextAtOffset(textarea_text, IA2_TEXT_OFFSET_CARET,
+ IA2_TEXT_BOUNDARY_LINE, 32, CONTENTS_LENGTH, L"\"KHTML, like\".");
+}
+
+IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
+ TestTextAtOffsetWithBoundaryAll) {
+ base::win::ScopedComPtr<IAccessibleText> input_text;
+ SetUpInputField(&input_text);
+
+ CheckTextAtOffset(input_text, 0, IA2_TEXT_BOUNDARY_ALL,
+ 0, CONTENTS_LENGTH, base::SysUTF8ToWide(INPUT_CONTENTS));
+}
+
+IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
+ TestMultiLineTextAtOffsetWithBoundaryAll) {
+ base::win::ScopedComPtr<IAccessibleText> textarea_text;
+ SetUpTextareaField(&textarea_text);
+
+ CheckTextAtOffset(textarea_text, CONTENTS_LENGTH - 1, IA2_TEXT_BOUNDARY_ALL,
+ 0, CONTENTS_LENGTH, base::SysUTF8ToWide(TEXTAREA_CONTENTS));
+}
+
} // namespace content
diff --git a/chromium/content/browser/accessibility/android_granularity_movement_browsertest.cc b/chromium/content/browser/accessibility/android_granularity_movement_browsertest.cc
index 975da4ceeb8..b24fa757896 100644
--- a/chromium/content/browser/accessibility/android_granularity_movement_browsertest.cc
+++ b/chromium/content/browser/accessibility/android_granularity_movement_browsertest.cc
@@ -33,7 +33,7 @@ const int GRANULARITY_LINE =
class AndroidGranularityMovementBrowserTest : public ContentBrowserTest {
public:
AndroidGranularityMovementBrowserTest() {}
- virtual ~AndroidGranularityMovementBrowserTest() {}
+ ~AndroidGranularityMovementBrowserTest() override {}
BrowserAccessibility* LoadUrlAndGetAccessibilityRoot(const GURL& url) {
NavigateToURL(shell(), GURL(url::kAboutBlankURL));
diff --git a/chromium/content/browser/accessibility/android_hit_testing_browsertest.cc b/chromium/content/browser/accessibility/android_hit_testing_browsertest.cc
index f483286f7ca..12817d10b0c 100644
--- a/chromium/content/browser/accessibility/android_hit_testing_browsertest.cc
+++ b/chromium/content/browser/accessibility/android_hit_testing_browsertest.cc
@@ -32,7 +32,7 @@ namespace content {
class AndroidHitTestingBrowserTest : public ContentBrowserTest {
public:
AndroidHitTestingBrowserTest() {}
- virtual ~AndroidHitTestingBrowserTest() {}
+ ~AndroidHitTestingBrowserTest() override {}
};
IN_PROC_BROWSER_TEST_F(AndroidHitTestingBrowserTest,
diff --git a/chromium/content/browser/accessibility/browser_accessibility.cc b/chromium/content/browser/accessibility/browser_accessibility.cc
index a700e9a9fd3..89acabc8d30 100644
--- a/chromium/content/browser/accessibility/browser_accessibility.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility.cc
@@ -4,12 +4,15 @@
#include "content/browser/accessibility/browser_accessibility.h"
+#include <algorithm>
+
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/common/accessibility_messages.h"
+#include "ui/accessibility/ax_text_utils.h"
namespace content {
@@ -38,11 +41,6 @@ void BrowserAccessibility::Init(BrowserAccessibilityManager* manager,
node_ = node;
}
-void BrowserAccessibility::OnDataChanged() {
- GetStringAttribute(ui::AX_ATTR_NAME, &name_);
- GetStringAttribute(ui::AX_ATTR_VALUE, &value_);
-}
-
bool BrowserAccessibility::PlatformIsLeaf() const {
if (InternalChildCount() == 0)
return true;
@@ -51,10 +49,9 @@ bool BrowserAccessibility::PlatformIsLeaf() const {
// implementation details, but we want to expose them as leaves
// to platform accessibility APIs.
switch (GetRole()) {
- case ui::AX_ROLE_EDITABLE_TEXT:
+ case ui::AX_ROLE_LINE_BREAK:
case ui::AX_ROLE_SLIDER:
case ui::AX_ROLE_STATIC_TEXT:
- case ui::AX_ROLE_TEXT_AREA:
case ui::AX_ROLE_TEXT_FIELD:
return true;
default:
@@ -96,6 +93,17 @@ BrowserAccessibility* BrowserAccessibility::PlatformGetChild(
return result;
}
+bool BrowserAccessibility::PlatformIsChildOfLeaf() const {
+ BrowserAccessibility* ancestor = GetParent();
+ while (ancestor) {
+ if (ancestor->PlatformIsLeaf())
+ return true;
+ ancestor = ancestor->GetParent();
+ }
+
+ return false;
+}
+
BrowserAccessibility* BrowserAccessibility::GetPreviousSibling() {
if (GetParent() && GetIndexInParent() > 0)
return GetParent()->InternalGetChild(GetIndexInParent() - 1);
@@ -124,7 +132,7 @@ BrowserAccessibility* BrowserAccessibility::InternalGetChild(
uint32 child_index) const {
if (!node_ || !manager_)
return NULL;
- return manager_->GetFromAXNode(node_->children()[child_index]);
+ return manager_->GetFromAXNode(node_->ChildAtIndex(child_index));
}
BrowserAccessibility* BrowserAccessibility::GetParent() const {
@@ -180,43 +188,7 @@ BrowserAccessibility::GetHtmlAttributes() const {
gfx::Rect BrowserAccessibility::GetLocalBoundsRect() const {
gfx::Rect bounds = GetLocation();
-
- // Walk up the parent chain. Every time we encounter a Web Area, offset
- // based on the scroll bars and then offset based on the origin of that
- // nested web area.
- BrowserAccessibility* parent = GetParent();
- bool need_to_offset_web_area =
- (GetRole() == ui::AX_ROLE_WEB_AREA ||
- GetRole() == ui::AX_ROLE_ROOT_WEB_AREA);
- while (parent) {
- if (need_to_offset_web_area &&
- parent->GetLocation().width() > 0 &&
- parent->GetLocation().height() > 0) {
- bounds.Offset(parent->GetLocation().x(), parent->GetLocation().y());
- need_to_offset_web_area = false;
- }
-
- // On some platforms, we don't want to take the root scroll offsets
- // into account.
- if (parent->GetRole() == ui::AX_ROLE_ROOT_WEB_AREA &&
- !manager()->UseRootScrollOffsetsWhenComputingBounds()) {
- break;
- }
-
- if (parent->GetRole() == ui::AX_ROLE_WEB_AREA ||
- parent->GetRole() == ui::AX_ROLE_ROOT_WEB_AREA) {
- int sx = 0;
- int sy = 0;
- if (parent->GetIntAttribute(ui::AX_ATTR_SCROLL_X, &sx) &&
- parent->GetIntAttribute(ui::AX_ATTR_SCROLL_Y, &sy)) {
- bounds.Offset(-sx, -sy);
- }
- need_to_offset_web_area = true;
- }
- parent = parent->GetParent();
- }
-
- return bounds;
+ return ElementBoundsToLocalBounds(bounds);
}
gfx::Rect BrowserAccessibility::GetGlobalBoundsRect() const {
@@ -246,7 +218,7 @@ gfx::Rect BrowserAccessibility::GetLocalBoundsForRange(int start, int len)
}
start -= child_len;
}
- return bounds;
+ return ElementBoundsToLocalBounds(bounds);
}
int end = start + len;
@@ -256,7 +228,12 @@ gfx::Rect BrowserAccessibility::GetLocalBoundsForRange(int start, int len)
gfx::Rect bounds;
for (size_t i = 0; i < InternalChildCount() && child_end < start + len; ++i) {
BrowserAccessibility* child = InternalGetChild(i);
- DCHECK_EQ(child->GetRole(), ui::AX_ROLE_INLINE_TEXT_BOX);
+ if (child->GetRole() != ui::AX_ROLE_INLINE_TEXT_BOX) {
+ DLOG(WARNING) << "BrowserAccessibility objects with role STATIC_TEXT " <<
+ "should have children of role INLINE_TEXT_BOX.";
+ continue;
+ }
+
std::string child_text;
child->GetStringAttribute(ui::AX_ATTR_VALUE, &child_text);
int child_len = static_cast<int>(child_text.size());
@@ -285,28 +262,28 @@ gfx::Rect BrowserAccessibility::GetLocalBoundsForRange(int start, int len)
gfx::Rect child_overlap_rect;
switch (text_direction) {
case ui::AX_TEXT_DIRECTION_NONE:
- case ui::AX_TEXT_DIRECTION_LR: {
+ case ui::AX_TEXT_DIRECTION_LTR: {
int left = child_rect.x() + start_pixel_offset;
int right = child_rect.x() + end_pixel_offset;
child_overlap_rect = gfx::Rect(left, child_rect.y(),
right - left, child_rect.height());
break;
}
- case ui::AX_TEXT_DIRECTION_RL: {
+ case ui::AX_TEXT_DIRECTION_RTL: {
int right = child_rect.right() - start_pixel_offset;
int left = child_rect.right() - end_pixel_offset;
child_overlap_rect = gfx::Rect(left, child_rect.y(),
right - left, child_rect.height());
break;
}
- case ui::AX_TEXT_DIRECTION_TB: {
+ case ui::AX_TEXT_DIRECTION_TTB: {
int top = child_rect.y() + start_pixel_offset;
int bottom = child_rect.y() + end_pixel_offset;
child_overlap_rect = gfx::Rect(child_rect.x(), top,
child_rect.width(), bottom - top);
break;
}
- case ui::AX_TEXT_DIRECTION_BT: {
+ case ui::AX_TEXT_DIRECTION_BTT: {
int bottom = child_rect.bottom() - start_pixel_offset;
int top = child_rect.bottom() - end_pixel_offset;
child_overlap_rect = gfx::Rect(child_rect.x(), top,
@@ -323,7 +300,7 @@ gfx::Rect BrowserAccessibility::GetLocalBoundsForRange(int start, int len)
bounds.Union(child_overlap_rect);
}
- return bounds;
+ return ElementBoundsToLocalBounds(bounds);
}
gfx::Rect BrowserAccessibility::GetGlobalBoundsForRange(int start, int len)
@@ -337,6 +314,108 @@ gfx::Rect BrowserAccessibility::GetGlobalBoundsForRange(int start, int len)
return bounds;
}
+int BrowserAccessibility::GetWordStartBoundary(
+ int start, ui::TextBoundaryDirection direction) const {
+ DCHECK_GE(start, -1);
+ // Special offset that indicates that a word boundary has not been found.
+ int word_start_not_found = GetStaticTextLenRecursive();
+ int word_start = word_start_not_found;
+
+ switch (GetRole()) {
+ case ui::AX_ROLE_STATIC_TEXT: {
+ int prev_word_start = word_start_not_found;
+ int child_start = 0;
+ int child_end = 0;
+
+ // Go through the inline text boxes.
+ for (size_t i = 0; i < InternalChildCount(); ++i) {
+ // The next child starts where the previous one ended.
+ child_start = child_end;
+ BrowserAccessibility* child = InternalGetChild(i);
+ DCHECK_EQ(child->GetRole(), ui::AX_ROLE_INLINE_TEXT_BOX);
+ const std::string& child_text = child->GetStringAttribute(
+ ui::AX_ATTR_VALUE);
+ int child_len = static_cast<int>(child_text.size());
+ child_end += child_len; // End is one past the last character.
+
+ const std::vector<int32>& word_starts = child->GetIntListAttribute(
+ ui::AX_ATTR_WORD_STARTS);
+ if (word_starts.empty()) {
+ word_start = child_end;
+ continue;
+ }
+
+ int local_start = start - child_start;
+ std::vector<int32>::const_iterator iter = std::upper_bound(
+ word_starts.begin(), word_starts.end(), local_start);
+ if (iter != word_starts.end()) {
+ if (direction == ui::FORWARDS_DIRECTION) {
+ word_start = child_start + *iter;
+ } else if (direction == ui::BACKWARDS_DIRECTION) {
+ if (iter == word_starts.begin()) {
+ // Return the position of the last word in the previous child.
+ word_start = prev_word_start;
+ } else {
+ word_start = child_start + *(iter - 1);
+ }
+ } else {
+ NOTREACHED();
+ }
+ break;
+ }
+
+ // No word start that is greater than the requested offset has been
+ // found.
+ prev_word_start = child_start + *(iter - 1);
+ if (direction == ui::FORWARDS_DIRECTION) {
+ word_start = child_end;
+ } else if (direction == ui::BACKWARDS_DIRECTION) {
+ word_start = prev_word_start;
+ } else {
+ NOTREACHED();
+ }
+ }
+ return word_start;
+ }
+
+ case ui::AX_ROLE_LINE_BREAK:
+ // Words never start at a line break.
+ return word_start_not_found;
+
+ default:
+ // If there are no children, the word start boundary is still unknown or
+ // found previously depending on the direction.
+ if (!InternalChildCount())
+ return word_start_not_found;
+
+ int child_start = 0;
+ for (size_t i = 0; i < InternalChildCount(); ++i) {
+ BrowserAccessibility* child = InternalGetChild(i);
+ int child_len = child->GetStaticTextLenRecursive();
+ int child_word_start = child->GetWordStartBoundary(start, direction);
+ if (child_word_start < child_len) {
+ // We have found a possible word boundary.
+ word_start = child_start + child_word_start;
+ }
+
+ // Decide when to stop searching.
+ if ((word_start != word_start_not_found &&
+ direction == ui::FORWARDS_DIRECTION) ||
+ (start < child_len &&
+ direction == ui::BACKWARDS_DIRECTION)) {
+ break;
+ }
+
+ child_start += child_len;
+ if (start >= child_len)
+ start -= child_len;
+ else
+ start = -1;
+ }
+ return word_start;
+ }
+}
+
BrowserAccessibility* BrowserAccessibility::BrowserAccessibilityForPoint(
const gfx::Point& point) {
// The best result found that's a child of this object.
@@ -384,9 +463,6 @@ BrowserAccessibility* BrowserAccessibility::BrowserAccessibilityForPoint(
void BrowserAccessibility::Destroy() {
// Allow the object to fire a TextRemoved notification.
- name_.clear();
- value_.clear();
-
manager_->NotifyAccessibilityEvent(ui::AX_EVENT_HIDE, this);
node_ = NULL;
manager_ = NULL;
@@ -557,24 +633,6 @@ bool BrowserAccessibility::GetString16Attribute(
return true;
}
-void BrowserAccessibility::SetStringAttribute(
- ui::AXStringAttribute attribute, const std::string& value) {
- if (!node_)
- return;
- ui::AXNodeData data = GetData();
- for (size_t i = 0; i < data.string_attributes.size(); ++i) {
- if (data.string_attributes[i].first == attribute) {
- data.string_attributes[i].second = value;
- node_->SetData(data);
- return;
- }
- }
- if (!value.empty()) {
- data.string_attributes.push_back(std::make_pair(attribute, value));
- node_->SetData(data);
- }
-}
-
bool BrowserAccessibility::HasIntListAttribute(
ui::AXIntListAttribute attribute) const {
const ui::AXNodeData& data = GetData();
@@ -663,6 +721,12 @@ bool BrowserAccessibility::HasState(ui::AXState state_enum) const {
return (GetState() >> state_enum) & 1;
}
+bool BrowserAccessibility::IsCellOrTableHeaderRole() const {
+ return (GetRole() == ui::AX_ROLE_CELL ||
+ GetRole() == ui::AX_ROLE_COLUMN_HEADER ||
+ GetRole() == ui::AX_ROLE_ROW_HEADER);
+}
+
bool BrowserAccessibility::IsEditableText() const {
// These roles don't have readonly set, but they're not editable text.
if (GetRole() == ui::AX_ROLE_SCROLL_AREA ||
@@ -675,24 +739,63 @@ bool BrowserAccessibility::IsEditableText() const {
// or contenteditable. We also check for editable text roles to cover
// another element that has role=textbox set on it.
return (!HasState(ui::AX_STATE_READ_ONLY) ||
- GetRole() == ui::AX_ROLE_TEXT_FIELD ||
- GetRole() == ui::AX_ROLE_TEXT_AREA);
+ GetRole() == ui::AX_ROLE_TEXT_FIELD);
}
-std::string BrowserAccessibility::GetTextRecursive() const {
- if (!name_.empty()) {
- return name_;
+bool BrowserAccessibility::IsWebAreaForPresentationalIframe() const {
+ if (GetRole() != ui::AX_ROLE_WEB_AREA &&
+ GetRole() != ui::AX_ROLE_ROOT_WEB_AREA) {
+ return false;
}
- std::string result;
- for (uint32 i = 0; i < PlatformChildCount(); ++i)
- result += PlatformGetChild(i)->GetTextRecursive();
- return result;
+ BrowserAccessibility* parent = GetParent();
+ if (!parent)
+ return false;
+
+ BrowserAccessibility* grandparent = parent->GetParent();
+ if (!grandparent)
+ return false;
+
+ return grandparent->GetRole() == ui::AX_ROLE_IFRAME_PRESENTATIONAL;
+}
+
+bool BrowserAccessibility::IsControl() const {
+ switch (GetRole()) {
+ case ui::AX_ROLE_BUTTON:
+ case ui::AX_ROLE_BUTTON_DROP_DOWN:
+ case ui::AX_ROLE_CHECK_BOX:
+ case ui::AX_ROLE_COLOR_WELL:
+ case ui::AX_ROLE_COMBO_BOX:
+ case ui::AX_ROLE_DISCLOSURE_TRIANGLE:
+ case ui::AX_ROLE_LIST_BOX:
+ case ui::AX_ROLE_MENU_BAR:
+ case ui::AX_ROLE_MENU_BUTTON:
+ case ui::AX_ROLE_MENU_ITEM:
+ case ui::AX_ROLE_MENU_ITEM_CHECK_BOX:
+ case ui::AX_ROLE_MENU_ITEM_RADIO:
+ case ui::AX_ROLE_MENU:
+ case ui::AX_ROLE_POP_UP_BUTTON:
+ case ui::AX_ROLE_RADIO_BUTTON:
+ case ui::AX_ROLE_SCROLL_BAR:
+ case ui::AX_ROLE_SEARCH_BOX:
+ case ui::AX_ROLE_SLIDER:
+ case ui::AX_ROLE_SPIN_BUTTON:
+ case ui::AX_ROLE_SWITCH:
+ case ui::AX_ROLE_TAB:
+ case ui::AX_ROLE_TEXT_FIELD:
+ case ui::AX_ROLE_TOGGLE_BUTTON:
+ case ui::AX_ROLE_TREE:
+ return true;
+ default:
+ return false;
+ }
}
int BrowserAccessibility::GetStaticTextLenRecursive() const {
- if (GetRole() == ui::AX_ROLE_STATIC_TEXT)
+ if (GetRole() == ui::AX_ROLE_STATIC_TEXT ||
+ GetRole() == ui::AX_ROLE_LINE_BREAK) {
return static_cast<int>(GetStringAttribute(ui::AX_ATTR_VALUE).size());
+ }
int len = 0;
for (size_t i = 0; i < InternalChildCount(); ++i)
@@ -700,4 +803,58 @@ int BrowserAccessibility::GetStaticTextLenRecursive() const {
return len;
}
+BrowserAccessibility* BrowserAccessibility::GetParentForBoundsCalculation()
+ const {
+ if (!node_ || !manager_)
+ return NULL;
+ ui::AXNode* parent = node_->parent();
+ if (parent)
+ return manager_->GetFromAXNode(parent);
+
+ if (!manager_->delegate())
+ return NULL;
+
+ return manager_->delegate()->AccessibilityGetParentFrame();
+}
+
+gfx::Rect BrowserAccessibility::ElementBoundsToLocalBounds(gfx::Rect bounds)
+ const {
+ // Walk up the parent chain. Every time we encounter a Web Area, offset
+ // based on the scroll bars and then offset based on the origin of that
+ // nested web area.
+ BrowserAccessibility* parent = GetParentForBoundsCalculation();
+ bool need_to_offset_web_area =
+ (GetRole() == ui::AX_ROLE_WEB_AREA ||
+ GetRole() == ui::AX_ROLE_ROOT_WEB_AREA);
+ while (parent) {
+ if (need_to_offset_web_area &&
+ parent->GetLocation().width() > 0 &&
+ parent->GetLocation().height() > 0) {
+ bounds.Offset(parent->GetLocation().x(), parent->GetLocation().y());
+ need_to_offset_web_area = false;
+ }
+
+ // On some platforms, we don't want to take the root scroll offsets
+ // into account.
+ if (parent->GetRole() == ui::AX_ROLE_ROOT_WEB_AREA &&
+ !manager()->UseRootScrollOffsetsWhenComputingBounds()) {
+ break;
+ }
+
+ if (parent->GetRole() == ui::AX_ROLE_WEB_AREA ||
+ parent->GetRole() == ui::AX_ROLE_ROOT_WEB_AREA) {
+ int sx = 0;
+ int sy = 0;
+ if (parent->GetIntAttribute(ui::AX_ATTR_SCROLL_X, &sx) &&
+ parent->GetIntAttribute(ui::AX_ATTR_SCROLL_Y, &sy)) {
+ bounds.Offset(-sx, -sy);
+ }
+ need_to_offset_web_area = true;
+ }
+ parent = parent->GetParentForBoundsCalculation();
+ }
+
+ return bounds;
+}
+
} // namespace content
diff --git a/chromium/content/browser/accessibility/browser_accessibility.h b/chromium/content/browser/accessibility/browser_accessibility.h
index 6318e64b53d..643e5950d5a 100644
--- a/chromium/content/browser/accessibility/browser_accessibility.h
+++ b/chromium/content/browser/accessibility/browser_accessibility.h
@@ -17,6 +17,7 @@
#include "third_party/WebKit/public/web/WebAXEnums.h"
#include "ui/accessibility/ax_node.h"
#include "ui/accessibility/ax_node_data.h"
+#include "ui/accessibility/ax_text_utils.h"
#if defined(OS_MACOSX) && __OBJC__
@class BrowserAccessibilityCocoa;
@@ -56,15 +57,9 @@ class CONTENT_EXPORT BrowserAccessibility {
// Called after the object is first initialized and again every time
// its data changes.
- virtual void OnDataChanged();
+ virtual void OnDataChanged() {}
- // Called after an atomic update to the tree finished and this object
- // was created or changed in this update.
- virtual void OnUpdateFinished() {}
-
- // Returns true if this is a native platform-specific object, vs a
- // cross-platform generic object.
- virtual bool IsNative() const;
+ virtual void OnSubtreeWillBeDeleted() {}
// Called when the location changed.
virtual void OnLocationChanged() {}
@@ -88,6 +83,11 @@ class CONTENT_EXPORT BrowserAccessibility {
// invalid index. Returns NULL if PlatformIsLeaf() returns true.
BrowserAccessibility* PlatformGetChild(uint32 child_index) const;
+ // Returns true if an ancestor of this node (not including itself) is a
+ // leaf node, meaning that this node is not actually exposed to the
+ // platform.
+ bool PlatformIsChildOfLeaf() const;
+
// Return the previous sibling of this object, or NULL if it's the first
// child of its parent.
BrowserAccessibility* GetPreviousSibling();
@@ -112,6 +112,19 @@ class CONTENT_EXPORT BrowserAccessibility {
// the role is WebAXRoleStaticText.
gfx::Rect GetGlobalBoundsForRange(int start, int len) const;
+ // Searches in the given text and from the given offset until the start of
+ // the next or previous word is found and returns its position.
+ // In case there is no word boundary before or after the given offset, it
+ // returns one past the last character, i.e. the text's length.
+ // If the given offset is already at the start of a word, returns the start
+ // of the next word if the search is forwards and the given offset if it is
+ // backwards.
+ // If the start offset is equal to -1 and the search is in the forwards
+ // direction, returns the start boundary of the first word.
+ // Start offsets that are not in the range -1 to text length are invalid.
+ int GetWordStartBoundary(
+ int start, ui::TextBoundaryDirection direction) const;
+
// Returns the deepest descendant that contains the specified point
// (in global screen coordinates).
BrowserAccessibility* BrowserAccessibilityForPoint(const gfx::Point& point);
@@ -140,10 +153,6 @@ class CONTENT_EXPORT BrowserAccessibility {
BrowserAccessibilityManager* manager() const { return manager_; }
bool instance_active() const { return node_ != NULL; }
ui::AXNode* node() const { return node_; }
- const std::string& name() const { return name_; }
- const std::string& value() const { return value_; }
- void set_name(const std::string& name) { name_ = name; }
- void set_value(const std::string& value) { value_ = value; }
// These access the internal accessibility tree, which doesn't necessarily
// reflect the accessibility tree that should be exposed on each platform.
@@ -164,6 +173,11 @@ class CONTENT_EXPORT BrowserAccessibility {
typedef base::StringPairs HtmlAttributes;
const HtmlAttributes& GetHtmlAttributes() const;
+ // Returns true if this is a native platform-specific object, vs a
+ // cross-platform generic object. Don't call ToBrowserAccessibilityXXX if
+ // IsNative returns false.
+ virtual bool IsNative() const;
+
#if defined(OS_MACOSX) && __OBJC__
BrowserAccessibilityCocoa* ToBrowserAccessibilityCocoa();
#elif defined(OS_WIN)
@@ -214,9 +228,6 @@ class CONTENT_EXPORT BrowserAccessibility {
bool GetIntListAttribute(ui::AXIntListAttribute attribute,
std::vector<int32>* value) const;
- void SetStringAttribute(ui::AXStringAttribute attribute,
- const std::string& value);
-
// Retrieve the value of a html attribute from the attribute map and
// returns true if found.
bool GetHtmlAttribute(const char* attr, base::string16* value) const;
@@ -241,11 +252,17 @@ class CONTENT_EXPORT BrowserAccessibility {
// Returns true if the bit corresponding to the given state enum is 1.
bool HasState(ui::AXState state_enum) const;
+ // Returns true if this node is an cell or an table header.
+ bool IsCellOrTableHeaderRole() const;
+
// Returns true if this node is an editable text field of any kind.
bool IsEditableText() const;
- // Append the text from this node and its children.
- std::string GetTextRecursive() const;
+ // True if this is a web area, and its grandparent is a presentational iframe.
+ bool IsWebAreaForPresentationalIframe() const;
+
+ // Is any control, like a button, text field, etc.
+ bool IsControl() const;
protected:
BrowserAccessibility();
@@ -261,8 +278,15 @@ class CONTENT_EXPORT BrowserAccessibility {
// including this object if it's static text.
int GetStaticTextLenRecursive() const;
- std::string name_;
- std::string value_;
+ // Similar to GetParent(), but includes nodes that are the host of a
+ // subtree rather than skipping over them - because they contain important
+ // bounds offsets.
+ BrowserAccessibility* GetParentForBoundsCalculation() const;
+
+ // Convert the bounding rectangle of an element (which is relative to
+ // its nearest scrollable ancestor) to local bounds (which are relative
+ // to the top of the web accessibility tree).
+ gfx::Rect ElementBoundsToLocalBounds(gfx::Rect bounds) const;
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 53189cbf1d1..a9e10ab7da7 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_android.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_android.cc
@@ -133,11 +133,14 @@ bool BrowserAccessibilityAndroid::IsCheckable() const {
}
bool BrowserAccessibilityAndroid::IsChecked() const {
- return HasState(ui::AX_STATE_CHECKED);
+ return (HasState(ui::AX_STATE_CHECKED) || HasState(ui::AX_STATE_PRESSED));
}
bool BrowserAccessibilityAndroid::IsClickable() const {
- return (PlatformIsLeaf() && !GetText().empty());
+ if (!PlatformIsLeaf())
+ return false;
+
+ return IsFocusable() || !GetText().empty();
}
bool BrowserAccessibilityAndroid::IsCollection() const {
@@ -169,9 +172,7 @@ bool BrowserAccessibilityAndroid::IsDismissable() const {
}
bool BrowserAccessibilityAndroid::IsEditableText() const {
- return (GetRole() == ui::AX_ROLE_EDITABLE_TEXT ||
- GetRole() == ui::AX_ROLE_TEXT_AREA ||
- GetRole() == ui::AX_ROLE_TEXT_FIELD);
+ return GetRole() == ui::AX_ROLE_TEXT_FIELD;
}
bool BrowserAccessibilityAndroid::IsEnabled() const {
@@ -192,6 +193,11 @@ bool BrowserAccessibilityAndroid::IsFocused() const {
}
bool BrowserAccessibilityAndroid::IsHeading() const {
+ BrowserAccessibilityAndroid* parent =
+ static_cast<BrowserAccessibilityAndroid*>(GetParent());
+ if (parent && parent->IsHeading())
+ return true;
+
return (GetRole() == ui::AX_ROLE_COLUMN_HEADER ||
GetRole() == ui::AX_ROLE_HEADING ||
GetRole() == ui::AX_ROLE_ROW_HEADER);
@@ -204,12 +210,12 @@ bool BrowserAccessibilityAndroid::IsHierarchical() const {
}
bool BrowserAccessibilityAndroid::IsLink() const {
- return GetRole() == ui::AX_ROLE_LINK ||
- GetRole() == ui::AX_ROLE_IMAGE_MAP_LINK;
+ return (GetRole() == ui::AX_ROLE_LINK ||
+ GetRole() == ui::AX_ROLE_IMAGE_MAP_LINK);
}
bool BrowserAccessibilityAndroid::IsMultiLine() const {
- return GetRole() == ui::AX_ROLE_TEXT_AREA;
+ return HasState(ui::AX_STATE_MULTILINE);
}
bool BrowserAccessibilityAndroid::IsPassword() const {
@@ -218,6 +224,7 @@ bool BrowserAccessibilityAndroid::IsPassword() const {
bool BrowserAccessibilityAndroid::IsRangeType() const {
return (GetRole() == ui::AX_ROLE_PROGRESS_INDICATOR ||
+ GetRole() == ui::AX_ROLE_METER ||
GetRole() == ui::AX_ROLE_SCROLL_BAR ||
GetRole() == ui::AX_ROLE_SLIDER);
}
@@ -246,10 +253,9 @@ bool BrowserAccessibilityAndroid::CanOpenPopup() const {
const char* BrowserAccessibilityAndroid::GetClassName() const {
const char* class_name = NULL;
- switch(GetRole()) {
- case ui::AX_ROLE_EDITABLE_TEXT:
+ switch (GetRole()) {
+ case ui::AX_ROLE_SEARCH_BOX:
case ui::AX_ROLE_SPIN_BUTTON:
- case ui::AX_ROLE_TEXT_AREA:
case ui::AX_ROLE_TEXT_FIELD:
class_name = "android.widget.EditText";
break;
@@ -268,6 +274,7 @@ const char* BrowserAccessibilityAndroid::GetClassName() const {
class_name = "android.widget.Button";
break;
case ui::AX_ROLE_CHECK_BOX:
+ case ui::AX_ROLE_SWITCH:
class_name = "android.widget.CheckBox";
break;
case ui::AX_ROLE_RADIO_BUTTON:
@@ -328,26 +335,26 @@ base::string16 BrowserAccessibilityAndroid::GetText() const {
// First, always return the |value| attribute if this is an
// input field.
- if (!value().empty()) {
+ base::string16 value = GetString16Attribute(ui::AX_ATTR_VALUE);
+ if (!value.empty()) {
if (HasState(ui::AX_STATE_EDITABLE))
- return base::UTF8ToUTF16(value());
+ return 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());
+ return 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);
+ int color = GetIntAttribute(ui::AX_ATTR_COLOR_VALUE);
+ int red = (color >> 16) & 0xFF;
+ int green = (color >> 8) & 0xFF;
+ int blue = color & 0xFF;
return base::UTF8ToUTF16(
base::StringPrintf("#%02X%02X%02X", red, green, blue));
}
@@ -355,8 +362,9 @@ base::string16 BrowserAccessibilityAndroid::GetText() const {
// 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());
+ base::string16 name = GetString16Attribute(ui::AX_ATTR_NAME);
+ if (!name.empty() && GetRole() == ui::AX_ROLE_LINK)
+ return name;
// If there's no text value, the basic rule is: prefer description
// (aria-labelledby or aria-label), then help (title), then name
@@ -371,8 +379,6 @@ base::string16 BrowserAccessibilityAndroid::GetText() const {
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);
@@ -383,16 +389,22 @@ base::string16 BrowserAccessibilityAndroid::GetText() const {
base::string16 text;
if (!description.empty())
text = description;
- else if (title_elem_id && !name().empty())
- text = base::UTF8ToUTF16(name());
+ else if (title_elem_id && !name.empty())
+ text = name;
else if (!help.empty())
text = help;
- else if (!name().empty())
- text = base::UTF8ToUTF16(name());
+ else if (!name.empty())
+ text = name;
else if (!placeholder.empty())
text = placeholder;
- else if (!value().empty())
- text = base::UTF8ToUTF16(value());
+ else if (!value.empty())
+ text = value;
+ else if (title_elem_id) {
+ BrowserAccessibility* title_elem =
+ manager()->GetFromID(title_elem_id);
+ if (title_elem)
+ text = static_cast<BrowserAccessibilityAndroid*>(title_elem)->GetText();
+ }
// This is called from PlatformIsLeaf, so don't call PlatformChildCount
// from within this!
@@ -430,11 +442,11 @@ base::string16 BrowserAccessibilityAndroid::GetText() const {
int BrowserAccessibilityAndroid::GetItemIndex() const {
int index = 0;
- switch(GetRole()) {
+ switch (GetRole()) {
case ui::AX_ROLE_LIST_ITEM:
case ui::AX_ROLE_LIST_BOX_OPTION:
case ui::AX_ROLE_TREE_ITEM:
- index = GetIndexInParent();
+ index = GetIntAttribute(ui::AX_ATTR_POS_IN_SET) - 1;
break;
case ui::AX_ROLE_SLIDER:
case ui::AX_ROLE_PROGRESS_INDICATOR: {
@@ -453,7 +465,7 @@ int BrowserAccessibilityAndroid::GetItemIndex() const {
int BrowserAccessibilityAndroid::GetItemCount() const {
int count = 0;
- switch(GetRole()) {
+ switch (GetRole()) {
case ui::AX_ROLE_LIST:
case ui::AX_ROLE_LIST_BOX:
case ui::AX_ROLE_DESCRIPTION_LIST:
@@ -557,7 +569,8 @@ int BrowserAccessibilityAndroid::GetSelectionEnd() const {
}
int BrowserAccessibilityAndroid::GetEditableTextLength() const {
- return value().length();
+ base::string16 value = GetString16Attribute(ui::AX_ATTR_VALUE);
+ return value.length();
}
int BrowserAccessibilityAndroid::AndroidInputType() const {
@@ -570,7 +583,7 @@ int BrowserAccessibilityAndroid::AndroidInputType() const {
if (!GetHtmlAttribute("type", &type))
return ANDROID_TEXT_INPUTTYPE_TYPE_TEXT;
- if (type == "" || type == "text" || type == "search")
+ if (type.empty() || type == "text" || type == "search")
return ANDROID_TEXT_INPUTTYPE_TYPE_TEXT;
else if (type == "date")
return ANDROID_TEXT_INPUTTYPE_TYPE_DATETIME_DATE;
@@ -825,9 +838,10 @@ void BrowserAccessibilityAndroid::OnDataChanged() {
BrowserAccessibility::OnDataChanged();
if (IsEditableText()) {
- if (base::UTF8ToUTF16(value()) != new_value_) {
+ base::string16 value = GetString16Attribute(ui::AX_ATTR_VALUE);
+ if (value != new_value_) {
old_value_ = new_value_;
- new_value_ = base::UTF8ToUTF16(value());
+ new_value_ = value;
}
}
diff --git a/chromium/content/browser/accessibility/browser_accessibility_android.h b/chromium/content/browser/accessibility/browser_accessibility_android.h
index 70579ab9b85..203812c3fcf 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_android.h
+++ b/chromium/content/browser/accessibility/browser_accessibility_android.h
@@ -13,11 +13,11 @@ namespace content {
class CONTENT_EXPORT BrowserAccessibilityAndroid : public BrowserAccessibility {
public:
// Overrides from BrowserAccessibility.
- virtual void OnDataChanged() override;
- virtual bool IsNative() const override;
- virtual void OnLocationChanged() override;
+ void OnDataChanged() override;
+ bool IsNative() const override;
+ void OnLocationChanged() override;
- virtual bool PlatformIsLeaf() const override;
+ bool PlatformIsLeaf() const override;
bool CanScrollForward() const;
bool CanScrollBackward() const;
@@ -127,4 +127,4 @@ class CONTENT_EXPORT BrowserAccessibilityAndroid : public BrowserAccessibility {
} // namespace content
-#endif // CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_ANDROID_H_
+#endif // CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_ANDROID_H_
diff --git a/chromium/content/browser/accessibility/browser_accessibility_cocoa.h b/chromium/content/browser/accessibility/browser_accessibility_cocoa.h
index 0f01a7a8777..8df7a90a5be 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_cocoa.h
+++ b/chromium/content/browser/accessibility/browser_accessibility_cocoa.h
@@ -41,6 +41,9 @@
// the manager.
- (content::BrowserAccessibilityDelegate*)delegate;
+// Get the BrowserAccessibility that this object wraps.
+- (content::BrowserAccessibility*)browserAccessibility;
+
// Convert the local objet's origin to a global point.
- (NSPoint)pointInScreen:(NSPoint)origin
size:(NSSize)size;
@@ -117,4 +120,4 @@
@property(nonatomic, readonly) id window;
@end
-#endif // CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_COCOA_H_
+#endif // CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_COCOA_H_
diff --git a/chromium/content/browser/accessibility/browser_accessibility_cocoa.mm b/chromium/content/browser/accessibility/browser_accessibility_cocoa.mm
index ac81de7ab39..3e72cb1d6a8 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_cocoa.mm
+++ b/chromium/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -15,6 +15,7 @@
#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/browser/accessibility/one_shot_accessibility_tree_search.h"
#include "content/public/common/content_client.h"
#import "ui/accessibility/platform/ax_platform_node_mac.h"
@@ -24,14 +25,20 @@
extern "C" void NSAccessibilityUnregisterUniqueIdForUIElement(id element);
using ui::AXNodeData;
+using content::AccessibilityMatchPredicate;
using content::BrowserAccessibility;
+using content::BrowserAccessibilityDelegate;
using content::BrowserAccessibilityManager;
using content::BrowserAccessibilityManagerMac;
using content::ContentClient;
+using content::OneShotAccessibilityTreeSearch;
typedef ui::AXStringAttribute StringAttribute;
namespace {
+// VoiceOver uses -1 to mean "no limit" for AXResultsLimit.
+const int kAXResultsLimitNoLimit = -1;
+
// Returns an autoreleased copy of the AXNodeData's attribute.
NSString* NSStringForStringAttribute(
BrowserAccessibility* browserAccessibility,
@@ -49,6 +56,281 @@ bool GetState(BrowserAccessibility* accessibility, ui::AXState state) {
// A mapping from an accessibility attribute to its method name.
NSDictionary* attributeToMethodNameMap = nil;
+// Given a search key provided to AXUIElementCountForSearchPredicate or
+// AXUIElementsForSearchPredicate, return a predicate that can be added
+// to OneShotAccessibilityTreeSearch.
+AccessibilityMatchPredicate PredicateForSearchKey(NSString* searchKey) {
+ if ([searchKey isEqualToString:@"AXAnyTypeSearchKey"]) {
+ return [](BrowserAccessibility* start, BrowserAccessibility* current) {
+ return true;
+ };
+ } else if ([searchKey isEqualToString:@"AXBlockquoteSameLevelSearchKey"] ||
+ [searchKey isEqualToString:@"AXBlockquoteSearchKey"]) {
+ return [](BrowserAccessibility* start, BrowserAccessibility* current) {
+ // TODO(dmazzoni): implement the "same level" part.
+ return current->GetRole() == ui::AX_ROLE_BLOCKQUOTE;
+ };
+ } else if ([searchKey isEqualToString:@"AXBoldFontSearchKey"]) {
+ // TODO(dmazzoni): implement this.
+ return nullptr;
+ } else if ([searchKey isEqualToString:@"AXButtonSearchKey"]) {
+ return [](BrowserAccessibility* start, BrowserAccessibility* current) {
+ return (current->GetRole() == ui::AX_ROLE_BUTTON ||
+ current->GetRole() == ui::AX_ROLE_MENU_BUTTON ||
+ current->GetRole() == ui::AX_ROLE_POP_UP_BUTTON ||
+ current->GetRole() == ui::AX_ROLE_SWITCH ||
+ current->GetRole() == ui::AX_ROLE_TOGGLE_BUTTON);
+ };
+ } else if ([searchKey isEqualToString:@"AXCheckBoxSearchKey"]) {
+ return [](BrowserAccessibility* start, BrowserAccessibility* current) {
+ return (current->GetRole() == ui::AX_ROLE_CHECK_BOX ||
+ current->GetRole() == ui::AX_ROLE_MENU_ITEM_CHECK_BOX);
+ };
+ } else if ([searchKey isEqualToString:@"AXControlSearchKey"]) {
+ return [](BrowserAccessibility* start, BrowserAccessibility* current) {
+ if (current->IsControl())
+ return true;
+ if (current->HasState(ui::AX_STATE_FOCUSABLE) &&
+ current->GetRole() != ui::AX_ROLE_IMAGE_MAP_LINK &&
+ current->GetRole() != ui::AX_ROLE_LINK) {
+ return true;
+ }
+ return false;
+ };
+ } else if ([searchKey isEqualToString:@"AXDifferentTypeSearchKey"]) {
+ return [](BrowserAccessibility* start, BrowserAccessibility* current) {
+ return current->GetRole() != start->GetRole();
+ };
+ } else if ([searchKey isEqualToString:@"AXFontChangeSearchKey"]) {
+ // TODO(dmazzoni): implement this.
+ return nullptr;
+ } else if ([searchKey isEqualToString:@"AXFontColorChangeSearchKey"]) {
+ // TODO(dmazzoni): implement this.
+ return nullptr;
+ } else if ([searchKey isEqualToString:@"AXFrameSearchKey"]) {
+ return [](BrowserAccessibility* start, BrowserAccessibility* current) {
+ if (current->IsWebAreaForPresentationalIframe())
+ return false;
+ if (!current->GetParent())
+ return false;
+ return (current->GetRole() == ui::AX_ROLE_WEB_AREA ||
+ current->GetRole() == ui::AX_ROLE_ROOT_WEB_AREA);
+ };
+ } else if ([searchKey isEqualToString:@"AXGraphicSearchKey"]) {
+ return [](BrowserAccessibility* start, BrowserAccessibility* current) {
+ return current->GetRole() == ui::AX_ROLE_IMAGE;
+ };
+ } else if ([searchKey isEqualToString:@"AXHeadingLevel1SearchKey"]) {
+ return [](BrowserAccessibility* start, BrowserAccessibility* current) {
+ return (current->GetRole() == ui::AX_ROLE_HEADING &&
+ current->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 1);
+ };
+ } else if ([searchKey isEqualToString:@"AXHeadingLevel2SearchKey"]) {
+ return [](BrowserAccessibility* start, BrowserAccessibility* current) {
+ return (current->GetRole() == ui::AX_ROLE_HEADING &&
+ current->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 2);
+ };
+ } else if ([searchKey isEqualToString:@"AXHeadingLevel3SearchKey"]) {
+ return [](BrowserAccessibility* start, BrowserAccessibility* current) {
+ return (current->GetRole() == ui::AX_ROLE_HEADING &&
+ current->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 3);
+ };
+ } else if ([searchKey isEqualToString:@"AXHeadingLevel4SearchKey"]) {
+ return [](BrowserAccessibility* start, BrowserAccessibility* current) {
+ return (current->GetRole() == ui::AX_ROLE_HEADING &&
+ current->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 4);
+ };
+ } else if ([searchKey isEqualToString:@"AXHeadingLevel5SearchKey"]) {
+ return [](BrowserAccessibility* start, BrowserAccessibility* current) {
+ return (current->GetRole() == ui::AX_ROLE_HEADING &&
+ current->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 5);
+ };
+ } else if ([searchKey isEqualToString:@"AXHeadingLevel6SearchKey"]) {
+ return [](BrowserAccessibility* start, BrowserAccessibility* current) {
+ return (current->GetRole() == ui::AX_ROLE_HEADING &&
+ current->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 6);
+ };
+ } else if ([searchKey isEqualToString:@"AXHeadingSameLevelSearchKey"]) {
+ return [](BrowserAccessibility* start, BrowserAccessibility* current) {
+ return (current->GetRole() == ui::AX_ROLE_HEADING &&
+ start->GetRole() == ui::AX_ROLE_HEADING &&
+ (current->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) ==
+ start->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL)));
+ };
+ } else if ([searchKey isEqualToString:@"AXHeadingSearchKey"]) {
+ return [](BrowserAccessibility* start, BrowserAccessibility* current) {
+ return current->GetRole() == ui::AX_ROLE_HEADING;
+ };
+ } else if ([searchKey isEqualToString:@"AXHighlightedSearchKey"]) {
+ // TODO(dmazzoni): implement this.
+ return nullptr;
+ } else if ([searchKey isEqualToString:@"AXItalicFontSearchKey"]) {
+ // TODO(dmazzoni): implement this.
+ return nullptr;
+ } else if ([searchKey isEqualToString:@"AXLandmarkSearchKey"]) {
+ return [](BrowserAccessibility* start, BrowserAccessibility* current) {
+ return (current->GetRole() == ui::AX_ROLE_APPLICATION ||
+ current->GetRole() == ui::AX_ROLE_BANNER ||
+ current->GetRole() == ui::AX_ROLE_COMPLEMENTARY ||
+ current->GetRole() == ui::AX_ROLE_CONTENT_INFO ||
+ current->GetRole() == ui::AX_ROLE_FORM ||
+ current->GetRole() == ui::AX_ROLE_MAIN ||
+ current->GetRole() == ui::AX_ROLE_NAVIGATION ||
+ current->GetRole() == ui::AX_ROLE_SEARCH);
+ };
+ } else if ([searchKey isEqualToString:@"AXLinkSearchKey"]) {
+ return [](BrowserAccessibility* start, BrowserAccessibility* current) {
+ return current->GetRole() == ui::AX_ROLE_LINK;
+ };
+ } else if ([searchKey isEqualToString:@"AXListSearchKey"]) {
+ return [](BrowserAccessibility* start, BrowserAccessibility* current) {
+ return current->GetRole() == ui::AX_ROLE_LIST;
+ };
+ } else if ([searchKey isEqualToString:@"AXLiveRegionSearchKey"]) {
+ return [](BrowserAccessibility* start, BrowserAccessibility* current) {
+ return current->HasStringAttribute(ui::AX_ATTR_LIVE_STATUS);
+ };
+ } else if ([searchKey isEqualToString:@"AXMisspelledWordSearchKey"]) {
+ // TODO(dmazzoni): implement this.
+ return nullptr;
+ } else if ([searchKey isEqualToString:@"AXOutlineSearchKey"]) {
+ return [](BrowserAccessibility* start, BrowserAccessibility* current) {
+ return current->GetRole() == ui::AX_ROLE_TREE;
+ };
+ } else if ([searchKey isEqualToString:@"AXPlainTextSearchKey"]) {
+ // TODO(dmazzoni): implement this.
+ return nullptr;
+ } else if ([searchKey isEqualToString:@"AXRadioGroupSearchKey"]) {
+ return [](BrowserAccessibility* start, BrowserAccessibility* current) {
+ return current->GetRole() == ui::AX_ROLE_RADIO_GROUP;
+ };
+ } else if ([searchKey isEqualToString:@"AXSameTypeSearchKey"]) {
+ return [](BrowserAccessibility* start, BrowserAccessibility* current) {
+ return current->GetRole() == start->GetRole();
+ };
+ } else if ([searchKey isEqualToString:@"AXStaticTextSearchKey"]) {
+ return [](BrowserAccessibility* start, BrowserAccessibility* current) {
+ return current->GetRole() == ui::AX_ROLE_STATIC_TEXT;
+ };
+ } else if ([searchKey isEqualToString:@"AXStyleChangeSearchKey"]) {
+ // TODO(dmazzoni): implement this.
+ return nullptr;
+ } else if ([searchKey isEqualToString:@"AXTableSameLevelSearchKey"]) {
+ return [](BrowserAccessibility* start, BrowserAccessibility* current) {
+ // TODO(dmazzoni): implement the "same level" part.
+ return current->GetRole() == ui::AX_ROLE_GRID ||
+ current->GetRole() == ui::AX_ROLE_TABLE;
+ };
+ } else if ([searchKey isEqualToString:@"AXTableSearchKey"]) {
+ return [](BrowserAccessibility* start, BrowserAccessibility* current) {
+ return current->GetRole() == ui::AX_ROLE_GRID ||
+ current->GetRole() == ui::AX_ROLE_TABLE;
+ };
+ } else if ([searchKey isEqualToString:@"AXTextFieldSearchKey"]) {
+ return [](BrowserAccessibility* start, BrowserAccessibility* current) {
+ return current->GetRole() == ui::AX_ROLE_TEXT_FIELD;
+ };
+ } else if ([searchKey isEqualToString:@"AXUnderlineSearchKey"]) {
+ // TODO(dmazzoni): implement this.
+ return nullptr;
+ } else if ([searchKey isEqualToString:@"AXUnvisitedLinkSearchKey"]) {
+ return [](BrowserAccessibility* start, BrowserAccessibility* current) {
+ return (current->GetRole() == ui::AX_ROLE_LINK &&
+ !current->HasState(ui::AX_STATE_VISITED));
+ };
+ } else if ([searchKey isEqualToString:@"AXVisitedLinkSearchKey"]) {
+ return [](BrowserAccessibility* start, BrowserAccessibility* current) {
+ return (current->GetRole() == ui::AX_ROLE_LINK &&
+ current->HasState(ui::AX_STATE_VISITED));
+ };
+ }
+
+ return nullptr;
+}
+
+// Initialize a OneShotAccessibilityTreeSearch object given the parameters
+// passed to AXUIElementCountForSearchPredicate or
+// AXUIElementsForSearchPredicate. Return true on success.
+bool InitializeAccessibilityTreeSearch(
+ OneShotAccessibilityTreeSearch* search,
+ id parameter) {
+ if (![parameter isKindOfClass:[NSDictionary class]])
+ return false;
+ NSDictionary* dictionary = parameter;
+
+ id startElementParameter = [dictionary objectForKey:@"AXStartElement"];
+ BrowserAccessibility* startNode = nullptr;
+ if ([startElementParameter isKindOfClass:[BrowserAccessibilityCocoa class]]) {
+ BrowserAccessibilityCocoa* startNodeCocoa =
+ (BrowserAccessibilityCocoa*)startElementParameter;
+ startNode = [startNodeCocoa browserAccessibility];
+ }
+
+ bool immediateDescendantsOnly = false;
+ NSNumber *immediateDescendantsOnlyParameter =
+ [dictionary objectForKey:@"AXImmediateDescendantsOnly"];
+ if ([immediateDescendantsOnlyParameter isKindOfClass:[NSNumber class]])
+ immediateDescendantsOnly = [immediateDescendantsOnlyParameter boolValue];
+
+ bool visibleOnly = false;
+ NSNumber *visibleOnlyParameter = [dictionary objectForKey:@"AXVisibleOnly"];
+ if ([visibleOnlyParameter isKindOfClass:[NSNumber class]])
+ visibleOnly = [visibleOnlyParameter boolValue];
+
+ content::OneShotAccessibilityTreeSearch::Direction direction =
+ content::OneShotAccessibilityTreeSearch::FORWARDS;
+ NSString* directionParameter = [dictionary objectForKey:@"AXDirection"];
+ if ([directionParameter isKindOfClass:[NSString class]]) {
+ if ([directionParameter isEqualToString:@"AXDirectionNext"])
+ direction = content::OneShotAccessibilityTreeSearch::FORWARDS;
+ else if ([directionParameter isEqualToString:@"AXDirectionPrevious"])
+ direction = content::OneShotAccessibilityTreeSearch::BACKWARDS;
+ }
+
+ int resultsLimit = kAXResultsLimitNoLimit;
+ NSNumber* resultsLimitParameter = [dictionary objectForKey:@"AXResultsLimit"];
+ if ([resultsLimitParameter isKindOfClass:[NSNumber class]])
+ resultsLimit = [resultsLimitParameter intValue];
+
+ std::string searchText;
+ NSString* searchTextParameter = [dictionary objectForKey:@"AXSearchText"];
+ if ([searchTextParameter isKindOfClass:[NSString class]])
+ searchText = base::SysNSStringToUTF8(searchTextParameter);
+
+ search->SetStartNode(startNode);
+ search->SetDirection(direction);
+ search->SetImmediateDescendantsOnly(immediateDescendantsOnly);
+ search->SetVisibleOnly(visibleOnly);
+ search->SetSearchText(searchText);
+
+ // Mac uses resultsLimit == -1 for unlimited, that that's
+ // the default for OneShotAccessibilityTreeSearch already.
+ // Only set the results limit if it's nonnegative.
+ if (resultsLimit >= 0)
+ search->SetResultLimit(resultsLimit);
+
+ id searchKey = [dictionary objectForKey:@"AXSearchKey"];
+ if ([searchKey isKindOfClass:[NSString class]]) {
+ AccessibilityMatchPredicate predicate =
+ PredicateForSearchKey((NSString*)searchKey);
+ if (predicate)
+ search->AddPredicate(predicate);
+ } else if ([searchKey isKindOfClass:[NSArray class]]) {
+ size_t searchKeyCount = static_cast<size_t>([searchKey count]);
+ for (size_t i = 0; i < searchKeyCount; ++i) {
+ id key = [searchKey objectAtIndex:i];
+ if ([key isKindOfClass:[NSString class]]) {
+ AccessibilityMatchPredicate predicate =
+ PredicateForSearchKey((NSString*)key);
+ if (predicate)
+ search->AddPredicate(predicate);
+ }
+ }
+ }
+
+ return true;
+}
+
} // namespace
@implementation BrowserAccessibilityCocoa
@@ -107,11 +389,17 @@ NSDictionary* attributeToMethodNameMap = nil;
{ @"AXARIAAtomic", @"ariaAtomic" },
{ @"AXARIABusy", @"ariaBusy" },
{ @"AXARIALive", @"ariaLive" },
+ { @"AXARIASetSize", @"ariaSetSize" },
+ { @"AXARIAPosInSet", @"ariaPosInSet" },
{ @"AXARIARelevant", @"ariaRelevant" },
+ { @"AXDropEffects", @"dropeffect" },
+ { @"AXGrabbed", @"grabbed" },
{ @"AXInvalid", @"invalid" },
{ @"AXLoaded", @"loaded" },
{ @"AXLoadingProgress", @"loadingProgress" },
+ { @"AXPlaceholder", @"placeholder" },
{ @"AXRequired", @"required" },
+ { @"AXSortDirection", @"sortDirection" },
{ @"AXVisited", @"visited" },
};
@@ -151,9 +439,8 @@ NSDictionary* attributeToMethodNameMap = nil;
}
- (NSNumber*)ariaBusy {
- bool boolValue = browserAccessibility_->GetBoolAttribute(
- ui::AX_ATTR_LIVE_BUSY);
- return [NSNumber numberWithBool:boolValue];
+ return [NSNumber numberWithBool:
+ GetState(browserAccessibility_, ui::AX_STATE_BUSY)];
}
- (NSString*)ariaLive {
@@ -166,6 +453,16 @@ NSDictionary* attributeToMethodNameMap = nil;
browserAccessibility_, ui::AX_ATTR_LIVE_RELEVANT);
}
+- (NSNumber*)ariaPosInSet {
+ return [NSNumber numberWithInt:
+ browserAccessibility_->GetIntAttribute(ui::AX_ATTR_POS_IN_SET)];
+}
+
+- (NSNumber*)ariaSetSize {
+ return [NSNumber numberWithInt:
+ browserAccessibility_->GetIntAttribute(ui::AX_ATTR_SET_SIZE)];
+}
+
// Returns an array of BrowserAccessibilityCocoa objects, representing the
// accessibility children of this object.
- (NSArray*)children {
@@ -233,7 +530,7 @@ NSDictionary* attributeToMethodNameMap = nil;
}
- (NSValue*)columnIndexRange {
- if ([self internalRole] != ui::AX_ROLE_CELL)
+ if (!browserAccessibility_->IsCellOrTableHeaderRole())
return nil;
int column = -1;
@@ -325,6 +622,11 @@ NSDictionary* attributeToMethodNameMap = nil;
return nil;
}
+- (NSString*)dropeffect {
+ return NSStringForStringAttribute(
+ browserAccessibility_, ui::AX_ATTR_DROPEFFECT);
+}
+
- (NSNumber*)enabled {
return [NSNumber numberWithBool:
GetState(browserAccessibility_, ui::AX_STATE_ENABLED)];
@@ -342,6 +644,11 @@ NSDictionary* attributeToMethodNameMap = nil;
return ret;
}
+- (NSNumber*)grabbed {
+ bool boolValue = browserAccessibility_->GetBoolAttribute(ui::AX_ATTR_GRABBED);
+ return [NSNumber numberWithBool:boolValue];
+}
+
- (id)header {
int headerElementId = -1;
if ([self internalRole] == ui::AX_ROLE_TABLE ||
@@ -391,15 +698,40 @@ NSDictionary* attributeToMethodNameMap = nil;
}
- (NSString*)invalid {
- base::string16 invalidUTF;
- if (!browserAccessibility_->GetHtmlAttribute("aria-invalid", &invalidUTF))
- return NULL;
- NSString* invalid = base::SysUTF16ToNSString(invalidUTF);
- if ([invalid isEqualToString:@"false"] ||
- [invalid isEqualToString:@""]) {
+ int invalidState;
+ if (!browserAccessibility_->GetIntAttribute(
+ ui::AX_ATTR_INVALID_STATE, &invalidState))
return @"false";
+
+ switch (invalidState) {
+ case ui::AX_INVALID_STATE_FALSE:
+ return @"false";
+ case ui::AX_INVALID_STATE_TRUE:
+ return @"true";
+ case ui::AX_INVALID_STATE_SPELLING:
+ return @"spelling";
+ case ui::AX_INVALID_STATE_GRAMMAR:
+ return @"grammar";
+ case ui::AX_INVALID_STATE_OTHER:
+ {
+ std::string ariaInvalidValue;
+ if (browserAccessibility_->GetStringAttribute(
+ ui::AX_ATTR_ARIA_INVALID_VALUE,
+ &ariaInvalidValue))
+ return base::SysUTF8ToNSString(ariaInvalidValue);
+ // Return @"true" since we cannot be more specific about the value.
+ return @"true";
+ }
+ default:
+ NOTREACHED();
}
- return invalid;
+
+ return @"false";
+}
+
+- (NSString*)placeholder {
+ return NSStringForStringAttribute(
+ browserAccessibility_, ui::AX_ATTR_PLACEHOLDER);
}
- (void)addLinkedUIElementsFromAttribute:(ui::AXIntListAttribute)attribute
@@ -447,24 +779,18 @@ NSDictionary* attributeToMethodNameMap = nil;
}
- (NSString*)orientation {
- // We present a spin button as a vertical slider, with a role description
- // of "spin button".
- 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
+ else if (GetState(browserAccessibility_, ui::AX_STATE_HORIZONTAL))
return NSAccessibilityHorizontalOrientationValue;
+
+ return @"";
}
- (NSNumber*)numberOfCharacters {
- return [NSNumber numberWithInt:browserAccessibility_->value().length()];
+ std::string value = browserAccessibility_->GetStringAttribute(
+ ui::AX_ATTR_VALUE);
+ return [NSNumber numberWithInt:value.size()];
}
// The origin of this accessibility object in the page's document.
@@ -512,14 +838,26 @@ NSDictionary* attributeToMethodNameMap = nil;
nil;
}
+- (content::BrowserAccessibility*)browserAccessibility {
+ return browserAccessibility_;
+}
+
- (NSPoint)pointInScreen:(NSPoint)origin
size:(NSSize)size {
if (!browserAccessibility_)
return NSZeroPoint;
- gfx::Rect bounds(origin.x, origin.y, size.width, size.height);
- gfx::Point point = [self delegate]->AccessibilityOriginInScreen(bounds);
- return NSMakePoint(point.x(), point.y());
+ // Get the delegate for the topmost BrowserAccessibilityManager, because
+ // that's the only one that can convert points to their origin in the screen.
+ BrowserAccessibilityDelegate* delegate =
+ browserAccessibility_->manager()->GetDelegateFromRootManager();
+ if (delegate) {
+ gfx::Rect bounds(origin.x, origin.y, size.width, size.height);
+ gfx::Point point = delegate->AccessibilityOriginInScreen(bounds);
+ return NSMakePoint(point.x(), point.y());
+ } else {
+ return NSZeroPoint;
+ }
}
// Returns a string indicating the NSAccessibility role of this object.
@@ -541,6 +879,17 @@ NSDictionary* attributeToMethodNameMap = nil;
else
return NSAccessibilityButtonRole;
}
+ if (role == ui::AX_ROLE_TEXT_FIELD &&
+ browserAccessibility_->HasState(ui::AX_STATE_MULTILINE)) {
+ return NSAccessibilityTextAreaRole;
+ }
+
+ // If this is a web area for a presentational iframe, give it a role of
+ // something other than WebArea so that the fact that it's a separate doc
+ // is not exposed to AT.
+ if (browserAccessibility_->IsWebAreaForPresentationalIframe())
+ return NSAccessibilityGroupRole;
+
return [AXPlatformNodeCocoa nativeRoleFromAXRole:role];
}
@@ -566,8 +915,9 @@ NSDictionary* attributeToMethodNameMap = nil;
IDS_AX_ROLE_HEADING));
}
- if ([role isEqualToString:NSAccessibilityGroupRole] ||
- [role isEqualToString:NSAccessibilityRadioButtonRole]) {
+ if (([role isEqualToString:NSAccessibilityGroupRole] ||
+ [role isEqualToString:NSAccessibilityRadioButtonRole]) &&
+ !browserAccessibility_->IsWebAreaForPresentationalIframe()) {
std::string role;
if (browserAccessibility_->GetHtmlAttribute("role", &role)) {
ui::AXRole internalRole = [self internalRole];
@@ -593,12 +943,30 @@ NSDictionary* attributeToMethodNameMap = nil;
case ui::AX_ROLE_CONTENT_INFO:
return base::SysUTF16ToNSString(content_client->GetLocalizedString(
IDS_AX_ROLE_ADDRESS));
+ case ui::AX_ROLE_DESCRIPTION_LIST:
+ return base::SysUTF16ToNSString(content_client->GetLocalizedString(
+ IDS_AX_ROLE_DESCRIPTION_LIST));
+ case ui::AX_ROLE_DESCRIPTION_LIST_DETAIL:
+ return base::SysUTF16ToNSString(content_client->GetLocalizedString(
+ IDS_AX_ROLE_DESCRIPTION_DETAIL));
+ case ui::AX_ROLE_DESCRIPTION_LIST_TERM:
+ return base::SysUTF16ToNSString(content_client->GetLocalizedString(
+ IDS_AX_ROLE_DESCRIPTION_TERM));
+ case ui::AX_ROLE_FIGURE:
+ return base::SysUTF16ToNSString(content_client->GetLocalizedString(
+ IDS_AX_ROLE_FIGURE));
case ui::AX_ROLE_FOOTER:
return base::SysUTF16ToNSString(content_client->GetLocalizedString(
IDS_AX_ROLE_FOOTER));
+ case ui::AX_ROLE_FORM:
+ return base::SysUTF16ToNSString(content_client->GetLocalizedString(
+ IDS_AX_ROLE_FORM));
case ui::AX_ROLE_MAIN:
return base::SysUTF16ToNSString(content_client->GetLocalizedString(
IDS_AX_ROLE_MAIN_CONTENT));
+ case ui::AX_ROLE_MATH:
+ return base::SysUTF16ToNSString(content_client->GetLocalizedString(
+ IDS_AX_ROLE_MATH));
case ui::AX_ROLE_NAVIGATION:
return base::SysUTF16ToNSString(content_client->GetLocalizedString(
IDS_AX_ROLE_NAVIGATIONAL_LINK));
@@ -609,6 +977,15 @@ NSDictionary* attributeToMethodNameMap = nil;
// This control is similar to what VoiceOver calls a "stepper".
return base::SysUTF16ToNSString(content_client->GetLocalizedString(
IDS_AX_ROLE_STEPPER));
+ case ui::AX_ROLE_STATUS:
+ return base::SysUTF16ToNSString(content_client->GetLocalizedString(
+ IDS_AX_ROLE_STATUS));
+ case ui::AX_ROLE_SEARCH_BOX:
+ return base::SysUTF16ToNSString(content_client->GetLocalizedString(
+ IDS_AX_ROLE_SEARCH_BOX));
+ case ui::AX_ROLE_SWITCH:
+ return base::SysUTF16ToNSString(content_client->GetLocalizedString(
+ IDS_AX_ROLE_SWITCH));
case ui::AX_ROLE_TOGGLE_BUTTON:
return base::SysUTF16ToNSString(content_client->GetLocalizedString(
IDS_AX_ROLE_TOGGLE_BUTTON));
@@ -640,7 +1017,7 @@ NSDictionary* attributeToMethodNameMap = nil;
}
- (NSValue*)rowIndexRange {
- if ([self internalRole] != ui::AX_ROLE_CELL)
+ if (!browserAccessibility_->IsCellOrTableHeaderRole())
return nil;
int row = -1;
@@ -681,35 +1058,49 @@ NSDictionary* attributeToMethodNameMap = nil;
- (NSArray*)selectedChildren {
NSMutableArray* ret = [[[NSMutableArray alloc] init] autorelease];
-
BrowserAccessibilityManager* manager = browserAccessibility_->manager();
- BrowserAccessibility* focusedChild =
- manager->GetFocus(browserAccessibility_);
- if (focusedChild && focusedChild != browserAccessibility_) {
+ BrowserAccessibility* focusedChild = manager->GetFocus(browserAccessibility_);
+
+ // If it's not multiselectable, try to skip iterating over the
+ // children.
+ if (!GetState(browserAccessibility_, ui::AX_STATE_MULTISELECTABLE)) {
// First try the focused child.
- [ret addObject:focusedChild->ToBrowserAccessibilityCocoa()];
- } else {
+ if (focusedChild && focusedChild != browserAccessibility_) {
+ [ret addObject:focusedChild->ToBrowserAccessibilityCocoa()];
+ return ret;
+ }
+
// Next try the active descendant.
int activeDescendantId;
if (browserAccessibility_->GetIntAttribute(
ui::AX_ATTR_ACTIVEDESCENDANT_ID, &activeDescendantId)) {
BrowserAccessibility* activeDescendant =
manager->GetFromID(activeDescendantId);
- if (activeDescendant)
+ 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;
}
}
}
+ // If it's multiselectable or if the previous attempts failed,
+ // 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()];
+ }
+
+ // And if nothing's selected but one has focus, use the focused one.
+ if ([ret count] == 0 &&
+ focusedChild &&
+ focusedChild != browserAccessibility_) {
+ [ret addObject:focusedChild->ToBrowserAccessibilityCocoa()];
+ }
+
return ret;
}
@@ -719,6 +1110,28 @@ NSDictionary* attributeToMethodNameMap = nil;
return [NSValue valueWithSize:NSMakeSize(bounds.width(), bounds.height())];
}
+- (NSString*)sortDirection {
+ int sortDirection;
+ if (!browserAccessibility_->GetIntAttribute(
+ ui::AX_ATTR_SORT_DIRECTION, &sortDirection))
+ return @"";
+
+ switch (sortDirection) {
+ case ui::AX_SORT_DIRECTION_UNSORTED:
+ return @"";
+ case ui::AX_SORT_DIRECTION_ASCENDING:
+ return @"AXSortDirectionAscending";
+ case ui::AX_SORT_DIRECTION_DESCENDING:
+ return @"AXSortDirectionDescending";
+ case ui::AX_SORT_DIRECTION_OTHER:
+ return @"AXSortDirectionUnknown";
+ default:
+ NOTREACHED();
+ }
+
+ return @"";
+}
+
// Returns a subrole based upon the role.
- (NSString*) subrole {
ui::AXRole browserAccessibilityRole = [self internalRole];
@@ -728,7 +1141,7 @@ NSDictionary* attributeToMethodNameMap = nil;
}
if (browserAccessibilityRole == ui::AX_ROLE_DESCRIPTION_LIST)
- return @"AXDescriptionList";
+ return @"AXDefinitionList";
if (browserAccessibilityRole == ui::AX_ROLE_LIST)
return @"AXContentList";
@@ -834,6 +1247,7 @@ NSDictionary* attributeToMethodNameMap = nil;
return [NSNumber numberWithInt:value];
} else if ([role isEqualToString:NSAccessibilityProgressIndicatorRole] ||
[role isEqualToString:NSAccessibilitySliderRole] ||
+ [role isEqualToString:NSAccessibilityIncrementorRole] ||
[role isEqualToString:NSAccessibilityScrollBarRole]) {
float floatValue;
if (browserAccessibility_->GetFloatAttribute(
@@ -841,15 +1255,14 @@ NSDictionary* attributeToMethodNameMap = nil;
return [NSNumber numberWithFloat:floatValue];
}
} else if ([role isEqualToString:NSAccessibilityColorWellRole]) {
- int r = browserAccessibility_->GetIntAttribute(
- ui::AX_ATTR_COLOR_VALUE_RED);
- int g = browserAccessibility_->GetIntAttribute(
- ui::AX_ATTR_COLOR_VALUE_GREEN);
- int b = browserAccessibility_->GetIntAttribute(
- ui::AX_ATTR_COLOR_VALUE_BLUE);
+ int color = browserAccessibility_->GetIntAttribute(
+ ui::AX_ATTR_COLOR_VALUE);
+ int red = (color >> 16) & 0xFF;
+ int green = (color >> 8) & 0xFF;
+ int blue = color & 0xFF;
// This string matches the one returned by a native Mac color well.
return [NSString stringWithFormat:@"rgb %7.5f %7.5f %7.5f 1",
- r / 255., g / 255., b / 255.];
+ red / 255., green / 255., blue / 255.];
}
return NSStringForStringAttribute(
@@ -862,8 +1275,9 @@ NSDictionary* attributeToMethodNameMap = nil;
}
- (NSValue*)visibleCharacterRange {
- return [NSValue valueWithRange:
- NSMakeRange(0, browserAccessibility_->value().length())];
+ std::string value = browserAccessibility_->GetStringAttribute(
+ ui::AX_ATTR_VALUE);
+ return [NSValue valueWithRange:NSMakeRange(0, value.size())];
}
- (NSArray*)visibleCells {
@@ -913,6 +1327,9 @@ NSDictionary* attributeToMethodNameMap = nil;
BrowserAccessibilityManagerMac* manager =
static_cast<BrowserAccessibilityManagerMac*>(
browserAccessibility_->manager());
+ if (!manager || !manager->parent_view())
+ return nil;
+
return [manager->parent_view() window];
}
@@ -977,7 +1394,9 @@ NSDictionary* attributeToMethodNameMap = nil;
const std::vector<int32>& line_breaks =
browserAccessibility_->GetIntListAttribute(
ui::AX_ATTR_LINE_BREAKS);
- int len = static_cast<int>(browserAccessibility_->value().size());
+ std::string value = browserAccessibility_->GetStringAttribute(
+ ui::AX_ATTR_VALUE);
+ int len = static_cast<int>(value.size());
if ([attribute isEqualToString:
NSAccessibilityStringForRangeParameterizedAttribute]) {
@@ -1047,7 +1466,7 @@ NSDictionary* attributeToMethodNameMap = nil;
j < child->PlatformChildCount();
++j) {
BrowserAccessibility* cell = child->PlatformGetChild(j);
- if (cell->GetRole() != ui::AX_ROLE_CELL)
+ if (!cell->IsCellOrTableHeaderRole())
continue;
int colIndex;
if (!cell->GetIntAttribute(
@@ -1078,6 +1497,26 @@ NSDictionary* attributeToMethodNameMap = nil;
pointInScreen.x, pointInScreen.y, rect.width(), rect.height());
return [NSValue valueWithRect:nsrect];
}
+ if ([attribute isEqualToString:@"AXUIElementCountForSearchPredicate"]) {
+ OneShotAccessibilityTreeSearch search(browserAccessibility_->manager());
+ if (InitializeAccessibilityTreeSearch(&search, parameter))
+ return [NSNumber numberWithInt:search.CountMatches()];
+ return nil;
+ }
+
+ if ([attribute isEqualToString:@"AXUIElementsForSearchPredicate"]) {
+ OneShotAccessibilityTreeSearch search(browserAccessibility_->manager());
+ if (InitializeAccessibilityTreeSearch(&search, parameter)) {
+ size_t count = search.CountMatches();
+ NSMutableArray* result = [NSMutableArray arrayWithCapacity:count];
+ for (size_t i = 0; i < count; ++i) {
+ BrowserAccessibility* match = search.GetMatchAtIndex(i);
+ [result addObject:match->ToBrowserAccessibilityCocoa()];
+ }
+ return result;
+ }
+ return nil;
+ }
// TODO(dtseng): support the following attributes.
if ([attribute isEqualTo:
@@ -1098,15 +1537,21 @@ NSDictionary* attributeToMethodNameMap = nil;
if (!browserAccessibility_)
return nil;
+ // General attributes.
+ NSMutableArray* ret = [NSMutableArray arrayWithObjects:
+ @"AXUIElementCountForSearchPredicate",
+ @"AXUIElementsForSearchPredicate",
+ nil];
+
if ([[self role] isEqualToString:NSAccessibilityTableRole] ||
[[self role] isEqualToString:NSAccessibilityGridRole]) {
- return [NSArray arrayWithObjects:
+ [ret addObjectsFromArray:[NSArray arrayWithObjects:
NSAccessibilityCellForColumnAndRowParameterizedAttribute,
- nil];
+ nil]];
}
if ([[self role] isEqualToString:NSAccessibilityTextFieldRole] ||
[[self role] isEqualToString:NSAccessibilityTextAreaRole]) {
- return [NSArray arrayWithObjects:
+ [ret addObjectsFromArray:[NSArray arrayWithObjects:
NSAccessibilityLineForIndexParameterizedAttribute,
NSAccessibilityRangeForLineParameterizedAttribute,
NSAccessibilityStringForRangeParameterizedAttribute,
@@ -1116,14 +1561,14 @@ NSDictionary* attributeToMethodNameMap = nil;
NSAccessibilityRTFForRangeParameterizedAttribute,
NSAccessibilityAttributedStringForRangeParameterizedAttribute,
NSAccessibilityStyleRangeForIndexParameterizedAttribute,
- nil];
+ nil]];
}
if ([self internalRole] == ui::AX_ROLE_STATIC_TEXT) {
- return [NSArray arrayWithObjects:
+ [ret addObjectsFromArray:[NSArray arrayWithObjects:
NSAccessibilityBoundsForRangeParameterizedAttribute,
- nil];
+ nil]];
}
- return nil;
+ return ret;
}
// Returns an array of action names that this object will respond to.
@@ -1136,8 +1581,8 @@ NSDictionary* attributeToMethodNameMap = nil;
NSString* role = [self role];
// TODO(dtseng): this should only get set when there's a default action.
if (![role isEqualToString:NSAccessibilityStaticTextRole] &&
- ![role isEqualToString:NSAccessibilityTextAreaRole] &&
- ![role isEqualToString:NSAccessibilityTextFieldRole]) {
+ ![role isEqualToString:NSAccessibilityTextFieldRole] &&
+ ![role isEqualToString:NSAccessibilityTextAreaRole]) {
[ret addObject:NSAccessibilityPressAction];
}
@@ -1190,7 +1635,6 @@ NSDictionary* attributeToMethodNameMap = nil;
NSAccessibilityChildrenAttribute,
NSAccessibilityDescriptionAttribute,
NSAccessibilityEnabledAttribute,
- NSAccessibilityExpandedAttribute,
NSAccessibilityFocusedAttribute,
NSAccessibilityHelpAttribute,
NSAccessibilityLinkedUIElementsAttribute,
@@ -1206,7 +1650,6 @@ NSDictionary* attributeToMethodNameMap = nil;
NSAccessibilityWindowAttribute,
@"AXAccessKey",
@"AXInvalid",
- @"AXRequired",
@"AXVisited",
nil];
@@ -1236,6 +1679,7 @@ NSDictionary* attributeToMethodNameMap = nil;
[ret addObjectsFromArray:[NSArray arrayWithObjects:
NSAccessibilityColumnIndexRangeAttribute,
NSAccessibilityRowIndexRangeAttribute,
+ @"AXSortDirection",
nil]];
} else if ([role isEqualToString:@"AXWebArea"]) {
[ret addObjectsFromArray:[NSArray arrayWithObjects:
@@ -1255,11 +1699,11 @@ NSDictionary* attributeToMethodNameMap = nil;
[ret addObject:NSAccessibilityTabsAttribute];
} else if ([role isEqualToString:NSAccessibilityProgressIndicatorRole] ||
[role isEqualToString:NSAccessibilitySliderRole] ||
+ [role isEqualToString:NSAccessibilityIncrementorRole] ||
[role isEqualToString:NSAccessibilityScrollBarRole]) {
[ret addObjectsFromArray:[NSArray arrayWithObjects:
NSAccessibilityMaxValueAttribute,
NSAccessibilityMinValueAttribute,
- NSAccessibilityOrientationAttribute,
NSAccessibilityValueDescriptionAttribute,
nil]];
} else if ([subrole isEqualToString:NSAccessibilityOutlineRowSubrole]) {
@@ -1290,7 +1734,6 @@ NSDictionary* attributeToMethodNameMap = nil;
}
} else if ([role isEqualToString:NSAccessibilityListRole]) {
[ret addObjectsFromArray:[NSArray arrayWithObjects:
- NSAccessibilityOrientationAttribute,
NSAccessibilitySelectedChildrenAttribute,
NSAccessibilityVisibleChildrenAttribute,
nil]];
@@ -1303,22 +1746,82 @@ NSDictionary* attributeToMethodNameMap = nil;
nil]];
}
+ // Position in set and Set size
+ if (browserAccessibility_->HasIntAttribute(ui::AX_ATTR_POS_IN_SET)) {
+ [ret addObjectsFromArray:[NSArray arrayWithObjects:
+ @"AXARIAPosInSet",
+ nil]];
+ }
+ if (browserAccessibility_->HasIntAttribute(ui::AX_ATTR_SET_SIZE)) {
+ [ret addObjectsFromArray:[NSArray arrayWithObjects:
+ @"AXARIASetSize",
+ nil]];
+ }
+
// Live regions.
if (browserAccessibility_->HasStringAttribute(
ui::AX_ATTR_LIVE_STATUS)) {
[ret addObjectsFromArray:[NSArray arrayWithObjects:
@"AXARIALive",
- @"AXARIARelevant",
nil]];
}
if (browserAccessibility_->HasStringAttribute(
- ui::AX_ATTR_CONTAINER_LIVE_STATUS)) {
+ ui::AX_ATTR_LIVE_RELEVANT)) {
+ [ret addObjectsFromArray:[NSArray arrayWithObjects:
+ @"AXARIARelevant",
+ nil]];
+ }
+ if (browserAccessibility_->HasBoolAttribute(
+ ui::AX_ATTR_LIVE_ATOMIC)) {
[ret addObjectsFromArray:[NSArray arrayWithObjects:
@"AXARIAAtomic",
+ nil]];
+ }
+ if (browserAccessibility_->HasBoolAttribute(
+ ui::AX_ATTR_LIVE_BUSY)) {
+ [ret addObjectsFromArray:[NSArray arrayWithObjects:
@"AXARIABusy",
nil]];
}
+ if (browserAccessibility_->HasStringAttribute(
+ ui::AX_ATTR_DROPEFFECT)) {
+ [ret addObjectsFromArray:[NSArray arrayWithObjects:
+ @"AXDropEffects",
+ nil]];
+ }
+
+ // Add aria-grabbed attribute only if it has true.
+ if (browserAccessibility_->HasBoolAttribute(ui::AX_ATTR_GRABBED)) {
+ [ret addObjectsFromArray:[NSArray arrayWithObjects:
+ @"AXGrabbed",
+ nil]];
+ }
+
+ // Add expanded attribute only if it has expanded or collapsed state.
+ if (GetState(browserAccessibility_, ui::AX_STATE_EXPANDED) ||
+ GetState(browserAccessibility_, ui::AX_STATE_COLLAPSED)) {
+ [ret addObjectsFromArray:[NSArray arrayWithObjects:
+ NSAccessibilityExpandedAttribute,
+ nil]];
+ }
+
+ if (GetState(browserAccessibility_, ui::AX_STATE_VERTICAL)
+ || GetState(browserAccessibility_, ui::AX_STATE_HORIZONTAL)) {
+ [ret addObjectsFromArray:[NSArray arrayWithObjects:
+ NSAccessibilityOrientationAttribute, nil]];
+ }
+
+ if (browserAccessibility_->HasStringAttribute(ui::AX_ATTR_PLACEHOLDER)) {
+ [ret addObjectsFromArray:[NSArray arrayWithObjects:
+ @"AXPlaceholder", nil]];
+ }
+
+ if (GetState(browserAccessibility_, ui::AX_STATE_REQUIRED)) {
+ [ret addObjectsFromArray:[NSArray arrayWithObjects:
+ @"AXRequired", nil]];
+ }
+
// Title UI Element.
if (browserAccessibility_->HasIntAttribute(ui::AX_ATTR_TITLE_UI_ELEMENT) ||
(browserAccessibility_->HasIntListAttribute(ui::AX_ATTR_LABELLEDBY_IDS) &&
@@ -1480,4 +1983,3 @@ NSDictionary* attributeToMethodNameMap = nil;
}
@end
-
diff --git a/chromium/content/browser/accessibility/browser_accessibility_mac.h b/chromium/content/browser/accessibility/browser_accessibility_mac.h
index 9802c60734f..a574086d597 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_mac.h
+++ b/chromium/content/browser/accessibility/browser_accessibility_mac.h
@@ -48,4 +48,4 @@ class BrowserAccessibilityMac : public BrowserAccessibility {
} // namespace content
-#endif // CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MAC_H_
+#endif // CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MAC_H_
diff --git a/chromium/content/browser/accessibility/browser_accessibility_mac_unittest.mm b/chromium/content/browser/accessibility/browser_accessibility_mac_unittest.mm
index 11388c8c027..34874e3e49a 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_mac_unittest.mm
+++ b/chromium/content/browser/accessibility/browser_accessibility_mac_unittest.mm
@@ -18,7 +18,7 @@ namespace content {
class BrowserAccessibilityTest : public ui::CocoaTest {
public:
- virtual void SetUp() {
+ void SetUp() override {
CocoaTest::SetUp();
RebuildAccessibilityTree();
}
diff --git a/chromium/content/browser/accessibility/browser_accessibility_manager.cc b/chromium/content/browser/accessibility/browser_accessibility_manager.cc
index 1e368c6f8d8..9fe18ca30c3 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager.cc
@@ -79,6 +79,7 @@ BrowserAccessibilityManager::BrowserAccessibilityManager(
factory_(factory),
tree_(new ui::AXSerializableTree()),
focus_(NULL),
+ user_is_navigating_away_(false),
osk_state_(OSK_ALLOWED) {
tree_->SetDelegate(this);
}
@@ -91,6 +92,7 @@ BrowserAccessibilityManager::BrowserAccessibilityManager(
factory_(factory),
tree_(new ui::AXSerializableTree()),
focus_(NULL),
+ user_is_navigating_away_(false),
osk_state_(OSK_ALLOWED) {
tree_->SetDelegate(this);
Initialize(initial_tree);
@@ -112,7 +114,7 @@ void BrowserAccessibilityManager::Initialize(
}
if (!focus_)
- SetFocus(tree_->GetRoot(), false);
+ SetFocus(tree_->root(), false);
}
// static
@@ -126,7 +128,7 @@ ui::AXTreeUpdate BrowserAccessibilityManager::GetEmptyDocument() {
}
BrowserAccessibility* BrowserAccessibilityManager::GetRoot() {
- return GetFromAXNode(tree_->GetRoot());
+ return GetFromAXNode(tree_->root());
}
BrowserAccessibility* BrowserAccessibilityManager::GetFromAXNode(
@@ -152,6 +154,22 @@ void BrowserAccessibilityManager::OnWindowBlurred() {
NotifyAccessibilityEvent(ui::AX_EVENT_BLUR, GetFromAXNode(focus_));
}
+void BrowserAccessibilityManager::UserIsNavigatingAway() {
+ user_is_navigating_away_ = true;
+}
+
+void BrowserAccessibilityManager::UserIsReloading() {
+ user_is_navigating_away_ = true;
+}
+
+void BrowserAccessibilityManager::NavigationSucceeded() {
+ user_is_navigating_away_ = false;
+}
+
+void BrowserAccessibilityManager::NavigationFailed() {
+ user_is_navigating_away_ = false;
+}
+
void BrowserAccessibilityManager::GotMouseDown() {
osk_state_ = OSK_ALLOWED_WITHIN_FOCUSED_OBJECT;
NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_));
@@ -180,13 +198,11 @@ void BrowserAccessibilityManager::OnAccessibilityEvents(
// Set focus to the root if it's not anywhere else.
if (!focus_) {
- SetFocus(tree_->GetRoot(), false);
+ SetFocus(tree_->root(), false);
should_send_initial_focus = true;
}
}
- OnTreeUpdateFinished();
-
if (should_send_initial_focus &&
(!delegate_ || delegate_->AccessibilityViewHasFocus())) {
NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_));
@@ -290,10 +306,21 @@ BrowserAccessibility* BrowserAccessibilityManager::GetActiveDescendantFocus(
BrowserAccessibility* BrowserAccessibilityManager::GetFocus(
BrowserAccessibility* root) {
- if (focus_ && (!root || focus_->IsDescendantOf(root->node())))
- return GetFromAXNode(focus_);
+ if (!focus_)
+ return NULL;
- return NULL;
+ if (root && !focus_->IsDescendantOf(root->node()))
+ return NULL;
+
+ BrowserAccessibility* obj = GetFromAXNode(focus_);
+ if (delegate() && obj->HasBoolAttribute(ui::AX_ATTR_IS_AX_TREE_HOST)) {
+ BrowserAccessibilityManager* child_manager =
+ delegate()->AccessibilityGetChildFrame(obj->GetId());
+ if (child_manager)
+ return child_manager->GetFocus(child_manager->GetRoot());
+ }
+
+ return obj;
}
void BrowserAccessibilityManager::SetFocus(ui::AXNode* node, bool notify) {
@@ -348,8 +375,9 @@ void BrowserAccessibilityManager::SetTextSelection(
}
gfx::Rect BrowserAccessibilityManager::GetViewBounds() {
- if (delegate_)
- return delegate_->AccessibilityGetViewBounds();
+ BrowserAccessibilityDelegate* delegate = GetDelegateFromRootManager();
+ if (delegate)
+ return delegate->AccessibilityGetViewBounds();
return gfx::Rect();
}
@@ -389,8 +417,8 @@ BrowserAccessibility* BrowserAccessibilityManager::PreviousInTreeOrder(
void BrowserAccessibilityManager::OnNodeWillBeDeleted(ui::AXNode* node) {
if (node == focus_ && tree_) {
- if (node != tree_->GetRoot())
- SetFocus(tree_->GetRoot(), false);
+ if (node != tree_->root())
+ SetFocus(tree_->root(), false);
else
focus_ = NULL;
}
@@ -400,6 +428,12 @@ void BrowserAccessibilityManager::OnNodeWillBeDeleted(ui::AXNode* node) {
id_wrapper_map_.erase(node->id());
}
+void BrowserAccessibilityManager::OnSubtreeWillBeDeleted(ui::AXNode* node) {
+ BrowserAccessibility* obj = GetFromAXNode(node);
+ if (obj)
+ obj->OnSubtreeWillBeDeleted();
+}
+
void BrowserAccessibilityManager::OnNodeCreated(ui::AXNode* node) {
BrowserAccessibility* wrapper = factory_->Create();
wrapper->Init(this, node);
@@ -411,12 +445,22 @@ void BrowserAccessibilityManager::OnNodeChanged(ui::AXNode* node) {
GetFromAXNode(node)->OnDataChanged();
}
-void BrowserAccessibilityManager::OnNodeCreationFinished(ui::AXNode* node) {
- GetFromAXNode(node)->OnUpdateFinished();
+void BrowserAccessibilityManager::OnAtomicUpdateFinished(
+ bool root_changed,
+ const std::vector<ui::AXTreeDelegate::Change>& changes) {
}
-void BrowserAccessibilityManager::OnNodeChangeFinished(ui::AXNode* node) {
- GetFromAXNode(node)->OnUpdateFinished();
+BrowserAccessibilityDelegate*
+ BrowserAccessibilityManager::GetDelegateFromRootManager() {
+ BrowserAccessibilityManager* manager = this;
+ while (manager->delegate()) {
+ BrowserAccessibility* host_node_in_parent_frame =
+ manager->delegate()->AccessibilityGetParentFrame();
+ if (!host_node_in_parent_frame)
+ break;
+ manager = host_node_in_parent_frame->manager();
+ }
+ return manager->delegate();
}
ui::AXTreeUpdate BrowserAccessibilityManager::SnapshotAXTreeForTesting() {
@@ -424,7 +468,7 @@ ui::AXTreeUpdate BrowserAccessibilityManager::SnapshotAXTreeForTesting() {
tree_->CreateTreeSource());
ui::AXTreeSerializer<const ui::AXNode*> serializer(tree_source.get());
ui::AXTreeUpdate update;
- serializer.SerializeChanges(tree_->GetRoot(), &update);
+ serializer.SerializeChanges(tree_->root(), &update);
return update;
}
diff --git a/chromium/content/browser/accessibility/browser_accessibility_manager.h b/chromium/content/browser/accessibility/browser_accessibility_manager.h
index c0e59fa1d68..f60bd025eb2 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager.h
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager.h
@@ -75,6 +75,8 @@ class CONTENT_EXPORT BrowserAccessibilityDelegate {
virtual gfx::NativeViewAccessible AccessibilityGetNativeViewAccessible() = 0;
virtual BrowserAccessibilityManager* AccessibilityGetChildFrame(
int accessibility_node_id) = 0;
+ virtual void AccessibilityGetAllChildFrames(
+ std::vector<BrowserAccessibilityManager*>* child_frames) = 0;
virtual BrowserAccessibility* AccessibilityGetParentFrame() = 0;
};
@@ -144,6 +146,12 @@ class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXTreeDelegate {
// view lost focus.
virtual void OnWindowBlurred();
+ // Notify the accessibility manager about page navigation.
+ void UserIsNavigatingAway();
+ virtual void UserIsReloading();
+ void NavigationSucceeded();
+ void NavigationFailed();
+
// Called to notify the accessibility manager that a mouse down event
// occurred in the tab.
void GotMouseDown();
@@ -233,17 +241,23 @@ class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXTreeDelegate {
// AXTreeDelegate implementation.
void OnNodeWillBeDeleted(ui::AXNode* node) override;
+ void OnSubtreeWillBeDeleted(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 {}
+ void OnAtomicUpdateFinished(
+ bool root_changed,
+ const std::vector<ui::AXTreeDelegate::Change>& changes) override;
BrowserAccessibilityDelegate* delegate() const { return delegate_; }
void set_delegate(BrowserAccessibilityDelegate* delegate) {
delegate_ = delegate;
}
+ // If this BrowserAccessibilityManager is a child frame or guest frame,
+ // return the BrowserAccessibilityDelegate from the highest ancestor frame
+ // in the frame tree.
+ BrowserAccessibilityDelegate* GetDelegateFromRootManager();
+
// Get a snapshot of the current tree as an AXTreeUpdate.
ui::AXTreeUpdate SnapshotAXTreeForTesting();
@@ -257,9 +271,6 @@ class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXTreeDelegate {
BrowserAccessibilityDelegate* delegate,
BrowserAccessibilityFactory* factory);
- // Called at the end of updating the tree.
- virtual void OnTreeUpdateFinished() {}
-
private:
// The following states keep track of whether or not the
// on-screen keyboard is allowed to be shown.
@@ -299,6 +310,9 @@ class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXTreeDelegate {
// A mapping from a node id to its wrapper of type BrowserAccessibility.
base::hash_map<int32, BrowserAccessibility*> id_wrapper_map_;
+ // True if the user has initiated a navigation to another page.
+ bool user_is_navigating_away_;
+
// The on-screen keyboard state.
OnScreenKeyboardState osk_state_;
diff --git a/chromium/content/browser/accessibility/browser_accessibility_manager_android.cc b/chromium/content/browser/accessibility/browser_accessibility_manager_android.cc
index fd4e0ff9fae..d140ec00cf8 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager_android.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager_android.cc
@@ -71,8 +71,8 @@ BrowserAccessibilityManagerAndroid::BrowserAccessibilityManagerAndroid(
BrowserAccessibilityDelegate* delegate,
BrowserAccessibilityFactory* factory)
: BrowserAccessibilityManager(delegate, factory) {
- SetContentViewCore(content_view_core);
Initialize(initial_tree);
+ SetContentViewCore(content_view_core);
}
BrowserAccessibilityManagerAndroid::~BrowserAccessibilityManagerAndroid() {
@@ -173,10 +173,9 @@ void BrowserAccessibilityManagerAndroid::NotifyAccessibilityEvent(
Java_BrowserAccessibilityManager_handleTextSelectionChanged(
env, obj.obj(), node->GetId());
break;
- case ui::AX_EVENT_CHILDREN_CHANGED:
case ui::AX_EVENT_TEXT_CHANGED:
case ui::AX_EVENT_VALUE_CHANGED:
- if (node->IsEditableText()) {
+ if (node->IsEditableText() && GetFocus(GetRoot()) == node) {
Java_BrowserAccessibilityManager_handleEditableTextChanged(
env, obj.obj(), node->GetId());
} else if (android_node->IsSlider()) {
@@ -254,12 +253,9 @@ 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(),
@@ -267,6 +263,16 @@ jboolean BrowserAccessibilityManagerAndroid::PopulateAccessibilityNodeInfo(
node->IsScrollable(),
node->IsSelected(),
node->IsVisibleToUser());
+ Java_BrowserAccessibilityManager_addAccessibilityNodeInfoActions(
+ env, obj, info,
+ id,
+ node->CanScrollForward(),
+ node->CanScrollBackward(),
+ node->IsClickable(),
+ node->IsEditableText(),
+ node->IsEnabled(),
+ node->IsFocusable(),
+ node->IsFocused());
Java_BrowserAccessibilityManager_setAccessibilityNodeInfoClassName(
env, obj, info,
base::android::ConvertUTF8ToJavaString(env, node->GetClassName()).obj());
@@ -293,8 +299,7 @@ jboolean BrowserAccessibilityManagerAndroid::PopulateAccessibilityNodeInfo(
absolute_rect.width(), absolute_rect.height(),
is_root);
- // New KitKat APIs
- Java_BrowserAccessibilityManager_setAccessibilityNodeInfoKitKatAttributes(
+ Java_BrowserAccessibilityManager_setAccessibilityNodeInfoLollipopAttributes(
env, obj, info,
node->CanOpenPopup(),
node->IsContentInvalid(),
@@ -393,8 +398,7 @@ jboolean BrowserAccessibilityManagerAndroid::PopulateAccessibilityEvent(
break;
}
- // Backwards-compatible fallback for new KitKat APIs.
- Java_BrowserAccessibilityManager_setAccessibilityEventKitKatAttributes(
+ Java_BrowserAccessibilityManager_setAccessibilityEventLollipopAttributes(
env, obj, event,
node->CanOpenPopup(),
node->IsContentInvalid(),
@@ -724,13 +728,17 @@ void BrowserAccessibilityManagerAndroid::SetAccessibilityFocus(
delegate_->AccessibilitySetAccessibilityFocus(id);
}
-void BrowserAccessibilityManagerAndroid::OnRootChanged(ui::AXNode* new_root) {
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
- if (obj.is_null())
- return;
+void BrowserAccessibilityManagerAndroid::OnAtomicUpdateFinished(
+ bool root_changed,
+ const std::vector<ui::AXTreeDelegate::Change>& changes) {
+ if (root_changed) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+ if (obj.is_null())
+ return;
- Java_BrowserAccessibilityManager_handleNavigate(env, obj.obj());
+ Java_BrowserAccessibilityManager_handleNavigate(env, obj.obj());
+ }
}
bool
diff --git a/chromium/content/browser/accessibility/browser_accessibility_manager_android.h b/chromium/content/browser/accessibility/browser_accessibility_manager_android.h
index f0e2d344ac1..6ab9ae83f9f 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager_android.h
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager_android.h
@@ -41,7 +41,7 @@ class CONTENT_EXPORT BrowserAccessibilityManagerAndroid
BrowserAccessibilityDelegate* delegate,
BrowserAccessibilityFactory* factory = new BrowserAccessibilityFactory());
- virtual ~BrowserAccessibilityManagerAndroid();
+ ~BrowserAccessibilityManagerAndroid() override;
static ui::AXTreeUpdate GetEmptyDocument();
@@ -49,8 +49,8 @@ class CONTENT_EXPORT BrowserAccessibilityManagerAndroid
base::android::ScopedJavaLocalRef<jobject> content_view_core);
// Implementation of BrowserAccessibilityManager.
- virtual void NotifyAccessibilityEvent(
- ui::AXEvent event_type, BrowserAccessibility* node) override;
+ void NotifyAccessibilityEvent(ui::AXEvent event_type,
+ BrowserAccessibility* node) override;
// --------------------------------------------------------------------------
// Methods called from Java via JNI
@@ -123,9 +123,11 @@ class CONTENT_EXPORT BrowserAccessibilityManagerAndroid
protected:
// AXTreeDelegate overrides.
- virtual void OnRootChanged(ui::AXNode* new_root) override;
+ void OnAtomicUpdateFinished(
+ bool root_changed,
+ const std::vector<ui::AXTreeDelegate::Change>& changes) override;
- virtual bool UseRootScrollOffsetsWhenComputingBounds() override;
+ 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 b754a4b4468..02115e8e1f4 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager_mac.h
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager_mac.h
@@ -31,8 +31,9 @@ class CONTENT_EXPORT BrowserAccessibilityManagerMac
NSView* parent_view() { return parent_view_; }
private:
- void OnNodeCreationFinished(ui::AXNode* node) override;
- void OnTreeUpdateFinished() override;
+ void OnAtomicUpdateFinished(
+ bool root_changed,
+ const std::vector<ui::AXTreeDelegate::Change>& changes) override;
// This gives BrowserAccessibilityManager::Create access to the class
// constructor.
@@ -40,8 +41,6 @@ class CONTENT_EXPORT BrowserAccessibilityManagerMac
NSView* parent_view_;
- bool created_live_region_;
-
DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityManagerMac);
};
diff --git a/chromium/content/browser/accessibility/browser_accessibility_manager_mac.mm b/chromium/content/browser/accessibility/browser_accessibility_manager_mac.mm
index 2000d025acc..8f6b21854c5 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager_mac.mm
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager_mac.mm
@@ -26,8 +26,7 @@ BrowserAccessibilityManagerMac::BrowserAccessibilityManagerMac(
BrowserAccessibilityDelegate* delegate,
BrowserAccessibilityFactory* factory)
: BrowserAccessibilityManager(delegate, factory),
- parent_view_(parent_view),
- created_live_region_(false) {
+ parent_view_(parent_view) {
Initialize(initial_tree);
}
@@ -45,8 +44,14 @@ ui::AXTreeUpdate BrowserAccessibilityManagerMac::GetEmptyDocument() {
BrowserAccessibility* BrowserAccessibilityManagerMac::GetFocus(
BrowserAccessibility* root) {
- BrowserAccessibility* node = GetActiveDescendantFocus(root);
- return node;
+ // On Mac, list boxes should always get focus on the whole list, otherwise
+ // information about the number of selected items will never be reported.
+ BrowserAccessibility* node = BrowserAccessibilityManager::GetFocus(root);
+ if (node && node->GetRole() == ui::AX_ROLE_LIST_BOX)
+ return node;
+
+ // For other roles, follow the active descendant.
+ return GetActiveDescendantFocus(root);
}
void BrowserAccessibilityManagerMac::NotifyAccessibilityEvent(
@@ -55,6 +60,15 @@ void BrowserAccessibilityManagerMac::NotifyAccessibilityEvent(
if (!node->IsNative())
return;
+ if (event_type == ui::AX_EVENT_FOCUS &&
+ node->GetRole() == ui::AX_ROLE_LIST_BOX_OPTION &&
+ node->HasState(ui::AX_STATE_SELECTED) &&
+ node->GetParent() &&
+ node->GetParent()->GetRole() == ui::AX_ROLE_LIST_BOX) {
+ node = node->GetParent();
+ SetFocus(node, false);
+ }
+
// Refer to AXObjectCache.mm (webkit).
NSString* event_id = @"";
switch (event_type) {
@@ -140,19 +154,28 @@ void BrowserAccessibilityManagerMac::NotifyAccessibilityEvent(
LOG(WARNING) << "Unknown accessibility event: " << event_type;
return;
}
+
BrowserAccessibilityCocoa* native_node = node->ToBrowserAccessibilityCocoa();
DCHECK(native_node);
NSAccessibilityPostNotification(native_node, event_id);
}
-void BrowserAccessibilityManagerMac::OnNodeCreationFinished(ui::AXNode* node) {
- BrowserAccessibility* obj = GetFromAXNode(node);
- if (obj && obj->HasStringAttribute(ui::AX_ATTR_LIVE_STATUS))
- created_live_region_ = true;
-}
+void BrowserAccessibilityManagerMac::OnAtomicUpdateFinished(
+ bool root_changed, const std::vector<ui::AXTreeDelegate::Change>& changes) {
+ BrowserAccessibilityManager::OnAtomicUpdateFinished(root_changed, changes);
-void BrowserAccessibilityManagerMac::OnTreeUpdateFinished() {
- if (!created_live_region_)
+ bool created_live_region = false;
+ for (size_t i = 0; i < changes.size(); ++i) {
+ if (changes[i].type != NODE_CREATED && changes[i].type != SUBTREE_CREATED)
+ continue;
+ BrowserAccessibility* obj = GetFromAXNode(changes[i].node);
+ if (obj && obj->HasStringAttribute(ui::AX_ATTR_LIVE_STATUS)) {
+ created_live_region = true;
+ break;
+ }
+ }
+
+ if (!created_live_region)
return;
// This code is to work around a bug in VoiceOver, where a new live
@@ -164,8 +187,6 @@ void BrowserAccessibilityManagerMac::OnTreeUpdateFinished() {
static_cast<BrowserAccessibilityMac*>(GetRoot());
root->RecreateNativeObject();
NotifyAccessibilityEvent(ui::AX_EVENT_CHILDREN_CHANGED, root);
-
- created_live_region_ = false;
}
} // namespace content
diff --git a/chromium/content/browser/accessibility/browser_accessibility_manager_unittest.cc b/chromium/content/browser/accessibility/browser_accessibility_manager_unittest.cc
index 8e2e3d033b9..544d42d509e 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager_unittest.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager_unittest.cc
@@ -95,6 +95,8 @@ class TestBrowserAccessibilityDelegate
return NULL;
}
BrowserAccessibility* AccessibilityGetParentFrame() override { return NULL; }
+ void AccessibilityGetAllChildFrames(
+ std::vector<BrowserAccessibilityManager*>* child_frames) override {}
bool got_fatal_error() const { return got_fatal_error_; }
void reset_got_fatal_error() { got_fatal_error_ = false; }
@@ -646,7 +648,7 @@ TEST(BrowserAccessibilityManagerTest, BoundsForRange) {
inline_text1.role = ui::AX_ROLE_INLINE_TEXT_BOX;
inline_text1.location = gfx::Rect(100, 100, 29, 9);
inline_text1.AddIntAttribute(ui::AX_ATTR_TEXT_DIRECTION,
- ui::AX_TEXT_DIRECTION_LR);
+ ui::AX_TEXT_DIRECTION_LTR);
std::vector<int32> character_offsets1;
character_offsets1.push_back(6); // 0
character_offsets1.push_back(11); // 1
@@ -665,7 +667,7 @@ TEST(BrowserAccessibilityManagerTest, BoundsForRange) {
inline_text2.role = ui::AX_ROLE_INLINE_TEXT_BOX;
inline_text2.location = gfx::Rect(100, 109, 28, 9);
inline_text2.AddIntAttribute(ui::AX_ATTR_TEXT_DIRECTION,
- ui::AX_TEXT_DIRECTION_LR);
+ ui::AX_TEXT_DIRECTION_LTR);
std::vector<int32> character_offsets2;
character_offsets2.push_back(5);
character_offsets2.push_back(10);
@@ -741,7 +743,7 @@ TEST(BrowserAccessibilityManagerTest, BoundsForRangeBiDi) {
inline_text1.role = ui::AX_ROLE_INLINE_TEXT_BOX;
inline_text1.location = gfx::Rect(100, 100, 30, 20);
inline_text1.AddIntAttribute(ui::AX_ATTR_TEXT_DIRECTION,
- ui::AX_TEXT_DIRECTION_LR);
+ ui::AX_TEXT_DIRECTION_LTR);
std::vector<int32> character_offsets1;
character_offsets1.push_back(10); // 0
character_offsets1.push_back(20); // 1
@@ -756,7 +758,7 @@ TEST(BrowserAccessibilityManagerTest, BoundsForRangeBiDi) {
inline_text2.role = ui::AX_ROLE_INLINE_TEXT_BOX;
inline_text2.location = gfx::Rect(130, 100, 30, 20);
inline_text2.AddIntAttribute(ui::AX_ATTR_TEXT_DIRECTION,
- ui::AX_TEXT_DIRECTION_RL);
+ ui::AX_TEXT_DIRECTION_RTL);
std::vector<int32> character_offsets2;
character_offsets2.push_back(10);
character_offsets2.push_back(20);
@@ -796,6 +798,54 @@ TEST(BrowserAccessibilityManagerTest, BoundsForRangeBiDi) {
static_text_accessible->GetLocalBoundsForRange(2, 2).ToString());
}
+TEST(BrowserAccessibilityManagerTest, BoundsForRangeScrolledWindow) {
+ ui::AXNodeData root;
+ root.id = 1;
+ root.role = ui::AX_ROLE_ROOT_WEB_AREA;
+ root.AddIntAttribute(ui::AX_ATTR_SCROLL_X, 25);
+ root.AddIntAttribute(ui::AX_ATTR_SCROLL_Y, 50);
+
+ ui::AXNodeData static_text;
+ static_text.id = 2;
+ static_text.SetValue("ABC");
+ static_text.role = ui::AX_ROLE_STATIC_TEXT;
+ static_text.location = gfx::Rect(100, 100, 16, 9);
+ root.child_ids.push_back(2);
+
+ ui::AXNodeData inline_text;
+ inline_text.id = 3;
+ inline_text.SetValue("ABC");
+ inline_text.role = ui::AX_ROLE_INLINE_TEXT_BOX;
+ inline_text.location = gfx::Rect(100, 100, 16, 9);
+ inline_text.AddIntAttribute(ui::AX_ATTR_TEXT_DIRECTION,
+ ui::AX_TEXT_DIRECTION_LTR);
+ std::vector<int32> character_offsets1;
+ character_offsets1.push_back(6); // 0
+ character_offsets1.push_back(11); // 1
+ character_offsets1.push_back(16); // 2
+ inline_text.AddIntListAttribute(
+ ui::AX_ATTR_CHARACTER_OFFSETS, character_offsets1);
+ static_text.child_ids.push_back(3);
+
+ scoped_ptr<BrowserAccessibilityManager> manager(
+ BrowserAccessibilityManager::Create(
+ MakeAXTreeUpdate(root, static_text, inline_text),
+ NULL,
+ new CountedBrowserAccessibilityFactory()));
+
+ BrowserAccessibility* root_accessible = manager->GetRoot();
+ BrowserAccessibility* static_text_accessible =
+ root_accessible->PlatformGetChild(0);
+
+ if (manager->UseRootScrollOffsetsWhenComputingBounds()) {
+ EXPECT_EQ(gfx::Rect(75, 50, 16, 9).ToString(),
+ static_text_accessible->GetLocalBoundsForRange(0, 3).ToString());
+ } else {
+ EXPECT_EQ(gfx::Rect(100, 100, 16, 9).ToString(),
+ static_text_accessible->GetLocalBoundsForRange(0, 3).ToString());
+ }
+}
+
#if defined(OS_WIN)
#define MAYBE_BoundsForRangeOnParentElement \
DISABLED_BoundsForRangeOnParentElement
@@ -841,7 +891,7 @@ TEST(BrowserAccessibilityManagerTest, MAYBE_BoundsForRangeOnParentElement) {
inline_text1.role = ui::AX_ROLE_INLINE_TEXT_BOX;
inline_text1.location = gfx::Rect(100, 100, 40, 20);
inline_text1.AddIntAttribute(ui::AX_ATTR_TEXT_DIRECTION,
- ui::AX_TEXT_DIRECTION_LR);
+ ui::AX_TEXT_DIRECTION_LTR);
std::vector<int32> character_offsets1;
character_offsets1.push_back(20); // 0
character_offsets1.push_back(40); // 1
@@ -854,7 +904,7 @@ TEST(BrowserAccessibilityManagerTest, MAYBE_BoundsForRangeOnParentElement) {
inline_text2.role = ui::AX_ROLE_INLINE_TEXT_BOX;
inline_text2.location = gfx::Rect(160, 100, 40, 20);
inline_text2.AddIntAttribute(ui::AX_ATTR_TEXT_DIRECTION,
- ui::AX_TEXT_DIRECTION_LR);
+ ui::AX_TEXT_DIRECTION_LTR);
std::vector<int32> character_offsets2;
character_offsets2.push_back(20); // 0
character_offsets2.push_back(40); // 1
diff --git a/chromium/content/browser/accessibility/browser_accessibility_manager_win.cc b/chromium/content/browser/accessibility/browser_accessibility_manager_win.cc
index b7424870cea..24a30896508 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager_win.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager_win.cc
@@ -4,6 +4,8 @@
#include "content/browser/accessibility/browser_accessibility_manager_win.h"
+#include <vector>
+
#include "base/command_line.h"
#include "base/win/scoped_comptr.h"
#include "base/win/windows_version.h"
@@ -73,22 +75,73 @@ IAccessible* BrowserAccessibilityManagerWin::GetParentIAccessible() {
return delegate_->AccessibilityGetNativeViewAccessible();
}
-void BrowserAccessibilityManagerWin::MaybeCallNotifyWinEvent(DWORD event,
- LONG child_id) {
- if (!delegate_)
+void BrowserAccessibilityManagerWin::MaybeCallNotifyWinEvent(
+ DWORD event, BrowserAccessibility* node) {
+ BrowserAccessibilityDelegate* delegate = GetDelegateFromRootManager();
+ if (!delegate) {
+ // This line and other LOG(WARNING) lines are temporary, to debug
+ // flaky failures in DumpAccessibilityEvent* tests.
+ // http://crbug.com/440579
+ LOG(WARNING) << "Not firing AX event because of no delegate";
+ return;
+ }
+
+ if (!node->IsNative())
return;
- HWND hwnd = delegate_->AccessibilityGetAcceleratedWidget();
- if (!hwnd)
+ HWND hwnd = delegate->AccessibilityGetAcceleratedWidget();
+ if (!hwnd) {
+ LOG(WARNING) << "Not firing AX event because of no hwnd";
+ 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;
+
+ // It doesn't make sense to fire a REORDER event on a leaf node; that
+ // happens when the node has internal children line inline text boxes.
+ if (event == EVENT_OBJECT_REORDER && node->PlatformIsLeaf())
+ return;
+
+ // Don't fire focus, or load complete notifications if the
+ // window isn't focused, because that can confuse screen readers into
+ // entering their "browse" mode.
+ if ((event == EVENT_OBJECT_FOCUS ||
+ event == IA2_EVENT_DOCUMENT_LOAD_COMPLETE) &&
+ (!delegate_->AccessibilityViewHasFocus())) {
return;
+ }
+
+ // NVDA gets confused if we focus the main document element when it hasn't
+ // finished loading and it has no children at all, so suppress that event.
+ if (event == EVENT_OBJECT_FOCUS &&
+ node == GetRoot() &&
+ node->PlatformChildCount() == 0 &&
+ !node->HasState(ui::AX_STATE_BUSY) &&
+ !node->GetBoolAttribute(ui::AX_ATTR_DOC_LOADED)) {
+ return;
+ }
+
+ // If a focus event is needed on the root, fire that first before
+ // this event.
+ if (event == EVENT_OBJECT_FOCUS && node == GetRoot())
+ focus_event_on_root_needed_ = false;
+ else if (focus_event_on_root_needed_)
+ OnWindowFocused();
+ LONG child_id = node->ToBrowserAccessibilityWin()->unique_id_win();
::NotifyWinEvent(event, hwnd, OBJID_CLIENT, child_id);
}
-
void BrowserAccessibilityManagerWin::OnNodeCreated(ui::AXNode* node) {
BrowserAccessibilityManager::OnNodeCreated(node);
BrowserAccessibility* obj = GetFromAXNode(node);
+ if (!obj)
+ return;
+ if (!obj->IsNative())
+ return;
LONG unique_id_win = obj->ToBrowserAccessibilityWin()->unique_id_win();
unique_id_to_ax_id_map_[unique_id_win] = obj->GetId();
}
@@ -98,6 +151,8 @@ void BrowserAccessibilityManagerWin::OnNodeWillBeDeleted(ui::AXNode* node) {
BrowserAccessibility* obj = GetFromAXNode(node);
if (!obj)
return;
+ if (!obj->IsNative())
+ return;
unique_id_to_ax_id_map_.erase(
obj->ToBrowserAccessibilityWin()->unique_id_win());
if (obj == tracked_scroll_object_) {
@@ -121,15 +176,27 @@ void BrowserAccessibilityManagerWin::OnWindowFocused() {
// Try to fire a focus event on the root first and then the focused node.
// This will clear focus_event_on_root_needed_ if successful.
- if (focus_ != tree_->GetRoot())
+ if (focus_ != tree_->root())
NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetRoot());
BrowserAccessibilityManager::OnWindowFocused();
}
+void BrowserAccessibilityManagerWin::UserIsReloading() {
+ MaybeCallNotifyWinEvent(IA2_EVENT_DOCUMENT_RELOAD, GetRoot());
+}
+
void BrowserAccessibilityManagerWin::NotifyAccessibilityEvent(
ui::AXEvent event_type,
BrowserAccessibility* node) {
- if (!delegate_ || !delegate_->AccessibilityGetAcceleratedWidget())
+ BrowserAccessibilityDelegate* root_delegate = GetDelegateFromRootManager();
+ if (!root_delegate || !root_delegate->AccessibilityGetAcceleratedWidget()) {
+ LOG(WARNING) << "Not firing AX event because of no root_delegate or hwnd";
+ return;
+ }
+
+ // Don't fire events when this document might be stale as the user has
+ // started navigating to a new document.
+ if (user_is_navigating_away_)
return;
// Inline text boxes are an internal implementation detail, we don't
@@ -143,7 +210,7 @@ void BrowserAccessibilityManagerWin::NotifyAccessibilityEvent(
if ((event_type == ui::AX_EVENT_FOCUS ||
event_type == ui::AX_EVENT_BLUR ||
event_type == ui::AX_EVENT_LOAD_COMPLETE) &&
- (!delegate_ || !delegate_->AccessibilityViewHasFocus())) {
+ !root_delegate->AccessibilityViewHasFocus()) {
return;
}
@@ -172,9 +239,6 @@ void BrowserAccessibilityManagerWin::NotifyAccessibilityEvent(
case ui::AX_EVENT_ALERT:
event_id = EVENT_SYSTEM_ALERT;
break;
- case ui::AX_EVENT_ARIA_ATTRIBUTE_CHANGED:
- event_id = IA2_EVENT_OBJECT_ATTRIBUTE_CHANGED;
- break;
case ui::AX_EVENT_AUTOCORRECTION_OCCURED:
event_id = IA2_EVENT_OBJECT_ATTRIBUTE_CHANGED;
break;
@@ -183,18 +247,12 @@ void BrowserAccessibilityManagerWin::NotifyAccessibilityEvent(
event_id = EVENT_OBJECT_FOCUS;
node = GetRoot();
break;
- case ui::AX_EVENT_CHECKED_STATE_CHANGED:
- event_id = EVENT_OBJECT_STATECHANGE;
- break;
case ui::AX_EVENT_CHILDREN_CHANGED:
event_id = EVENT_OBJECT_REORDER;
break;
case ui::AX_EVENT_FOCUS:
event_id = EVENT_OBJECT_FOCUS;
break;
- case ui::AX_EVENT_INVALID_STATUS_CHANGED:
- event_id = EVENT_OBJECT_STATECHANGE;
- break;
case ui::AX_EVENT_LIVE_REGION_CHANGED:
if (node->GetBoolAttribute(ui::AX_ATTR_CONTAINER_LIVE_BUSY))
return;
@@ -203,18 +261,6 @@ void BrowserAccessibilityManagerWin::NotifyAccessibilityEvent(
case ui::AX_EVENT_LOAD_COMPLETE:
event_id = IA2_EVENT_DOCUMENT_LOAD_COMPLETE;
break;
- case ui::AX_EVENT_MENU_LIST_ITEM_SELECTED:
- event_id = EVENT_OBJECT_FOCUS;
- break;
- case ui::AX_EVENT_MENU_LIST_VALUE_CHANGED:
- event_id = EVENT_OBJECT_VALUECHANGE;
- break;
- case ui::AX_EVENT_HIDE:
- event_id = EVENT_OBJECT_HIDE;
- break;
- case ui::AX_EVENT_SHOW:
- event_id = EVENT_OBJECT_SHOW;
- break;
case ui::AX_EVENT_SCROLL_POSITION_CHANGED:
event_id = EVENT_SYSTEM_SCROLLINGEND;
break;
@@ -224,15 +270,9 @@ void BrowserAccessibilityManagerWin::NotifyAccessibilityEvent(
case ui::AX_EVENT_SELECTED_CHILDREN_CHANGED:
event_id = EVENT_OBJECT_SELECTIONWITHIN;
break;
- case ui::AX_EVENT_TEXT_CHANGED:
- event_id = EVENT_OBJECT_NAMECHANGE;
- break;
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;
- break;
default:
// Not all WebKit accessibility events result in a Windows
// accessibility notification.
@@ -244,8 +284,7 @@ void BrowserAccessibilityManagerWin::NotifyAccessibilityEvent(
// the AT client will then call get_accChild on the HWND's accessibility
// object and pass it that same id, which we can use to retrieve the
// IAccessible for this node.
- LONG child_id = node->ToBrowserAccessibilityWin()->unique_id_win();
- MaybeCallNotifyWinEvent(event_id, child_id);
+ MaybeCallNotifyWinEvent(event_id, node);
}
// If this is a layout complete notification (sent when a container scrolls)
@@ -255,17 +294,57 @@ void BrowserAccessibilityManagerWin::NotifyAccessibilityEvent(
tracked_scroll_object_ &&
tracked_scroll_object_->IsDescendantOf(node)) {
MaybeCallNotifyWinEvent(
- IA2_EVENT_VISIBLE_DATA_CHANGED,
- tracked_scroll_object_->ToBrowserAccessibilityWin()->unique_id_win());
+ IA2_EVENT_VISIBLE_DATA_CHANGED, tracked_scroll_object_);
tracked_scroll_object_->Release();
tracked_scroll_object_ = NULL;
}
}
-void BrowserAccessibilityManagerWin::OnRootChanged(ui::AXNode* new_root) {
- // In order to make screen readers aware of the new accessibility root,
- // we need to fire a focus event on it.
- OnWindowFocused();
+void BrowserAccessibilityManagerWin::OnAtomicUpdateFinished(
+ bool root_changed,
+ const std::vector<ui::AXTreeDelegate::Change>& changes) {
+ BrowserAccessibilityManager::OnAtomicUpdateFinished(root_changed, changes);
+
+ if (root_changed) {
+ // In order to make screen readers aware of the new accessibility root,
+ // we need to fire a focus event on it.
+ OnWindowFocused();
+ }
+
+ // Do a sequence of Windows-specific updates on each node. Each one is
+ // done in a single pass that must complete before the next step starts.
+ // The first step moves win_attributes_ to old_win_attributes_ and then
+ // recomputes all of win_attributes_ other than IAccessibleText.
+ for (size_t i = 0; i < changes.size(); ++i) {
+ BrowserAccessibility* obj = GetFromAXNode(changes[i].node);
+ if (obj && obj->IsNative() && !obj->PlatformIsChildOfLeaf())
+ obj->ToBrowserAccessibilityWin()->UpdateStep1ComputeWinAttributes();
+ }
+
+ // The next step updates the hypertext of each node, which is a
+ // concatenation of all of its child text nodes, so it can't run until
+ // the text of all of the nodes was computed in the previous step.
+ for (size_t i = 0; i < changes.size(); ++i) {
+ BrowserAccessibility* obj = GetFromAXNode(changes[i].node);
+ if (obj && obj->IsNative() && !obj->PlatformIsChildOfLeaf())
+ obj->ToBrowserAccessibilityWin()->UpdateStep2ComputeHypertext();
+ }
+
+ // The third step fires events on nodes based on what's changed - like
+ // if the name, value, or description changed, or if the hypertext had
+ // text inserted or removed. It's able to figure out exactly what changed
+ // because we still have old_win_attributes_ populated.
+ // This step has to run after the previous two steps complete because the
+ // client may walk the tree when it receives any of these events.
+ // At the end, it deletes old_win_attributes_ since they're not needed
+ // anymore.
+ for (size_t i = 0; i < changes.size(); ++i) {
+ BrowserAccessibility* obj = GetFromAXNode(changes[i].node);
+ if (obj && obj->IsNative() && !obj->PlatformIsChildOfLeaf()) {
+ obj->ToBrowserAccessibilityWin()->UpdateStep3FireEvents(
+ changes[i].type == AXTreeDelegate::SUBTREE_CREATED);
+ }
+ }
}
void BrowserAccessibilityManagerWin::TrackScrollingObject(
@@ -282,9 +361,25 @@ BrowserAccessibilityWin* BrowserAccessibilityManagerWin::GetFromUniqueIdWin(
unique_id_to_ax_id_map_.find(unique_id_win);
if (iter != unique_id_to_ax_id_map_.end()) {
BrowserAccessibility* result = GetFromID(iter->second);
- if (result)
+ if (result && result->IsNative())
return result->ToBrowserAccessibilityWin();
}
+
+ // Also search all child frames, such as out-of-process iframes or
+ // guest browser plugins.
+ if (delegate()) {
+ std::vector<BrowserAccessibilityManager*> child_frames;
+ delegate()->AccessibilityGetAllChildFrames(&child_frames);
+ for (size_t i = 0; i < child_frames.size(); ++i) {
+ BrowserAccessibilityManagerWin* child_manager =
+ child_frames[i]->ToBrowserAccessibilityManagerWin();
+ BrowserAccessibilityWin* result =
+ child_manager->GetFromUniqueIdWin(unique_id_win);
+ if (result)
+ return result;
+ }
+ }
+
return NULL;
}
diff --git a/chromium/content/browser/accessibility/browser_accessibility_manager_win.h b/chromium/content/browser/accessibility/browser_accessibility_manager_win.h
index 8eaa9490c85..c33f5923b57 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager_win.h
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager_win.h
@@ -23,7 +23,7 @@ class CONTENT_EXPORT BrowserAccessibilityManagerWin
BrowserAccessibilityDelegate* delegate,
BrowserAccessibilityFactory* factory = new BrowserAccessibilityFactory());
- virtual ~BrowserAccessibilityManagerWin();
+ ~BrowserAccessibilityManagerWin() override;
static ui::AXTreeUpdate GetEmptyDocument();
@@ -34,15 +34,16 @@ class CONTENT_EXPORT BrowserAccessibilityManagerWin
IAccessible* GetParentIAccessible();
// Calls NotifyWinEvent if the parent window's IAccessible pointer is known.
- void MaybeCallNotifyWinEvent(DWORD event, LONG child_id);
+ void MaybeCallNotifyWinEvent(DWORD event, BrowserAccessibility* node);
// AXTree methods
- virtual void OnNodeWillBeDeleted(ui::AXNode* node) override;
- virtual void OnNodeCreated(ui::AXNode* node) override;
+ void OnNodeWillBeDeleted(ui::AXNode* node) override;
+ void OnNodeCreated(ui::AXNode* node) override;
// BrowserAccessibilityManager methods
- virtual void OnWindowFocused() override;
- virtual void NotifyAccessibilityEvent(
+ void OnWindowFocused() override;
+ void UserIsReloading() override;
+ void NotifyAccessibilityEvent(
ui::AXEvent event_type, BrowserAccessibility* node) override;
// Track this object and post a VISIBLE_DATA_CHANGED notification when
@@ -59,7 +60,9 @@ class CONTENT_EXPORT BrowserAccessibilityManagerWin
protected:
// BrowserAccessibilityManager methods
- virtual void OnRootChanged(ui::AXNode* new_root) override;
+ void OnAtomicUpdateFinished(
+ bool root_changed,
+ const std::vector<ui::AXTreeDelegate::Change>& changes) override;
private:
// Give BrowserAccessibilityManager::Create access to our constructor.
diff --git a/chromium/content/browser/accessibility/browser_accessibility_state_impl.cc b/chromium/content/browser/accessibility/browser_accessibility_state_impl.cc
index 597b13ac0c1..5d68c2c58d8 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_state_impl.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_state_impl.cc
@@ -31,7 +31,8 @@ BrowserAccessibilityStateImpl* BrowserAccessibilityStateImpl::GetInstance() {
BrowserAccessibilityStateImpl::BrowserAccessibilityStateImpl()
: BrowserAccessibilityState(),
- accessibility_mode_(AccessibilityModeOff) {
+ accessibility_mode_(AccessibilityModeOff),
+ disable_hot_tracking_(false) {
ResetAccessibilityModeValue();
#if defined(OS_WIN)
// On Windows, UpdateHistograms calls some system functions with unknown
diff --git a/chromium/content/browser/accessibility/browser_accessibility_state_impl.h b/chromium/content/browser/accessibility/browser_accessibility_state_impl.h
index 4c8884373d6..77249163f40 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_state_impl.h
+++ b/chromium/content/browser/accessibility/browser_accessibility_state_impl.h
@@ -60,6 +60,18 @@ class CONTENT_EXPORT BrowserAccessibilityStateImpl
// removed.
void RemoveAccessibilityMode(AccessibilityMode mode);
+ // Accessibility objects can have the "hot tracked" state set when
+ // the mouse is hovering over them, but this makes tests flaky because
+ // the test behaves differently when the mouse happens to be over an
+ // element. This is a global switch to not use the "hot tracked" state
+ // in a test.
+ void set_disable_hot_tracking_for_testing(bool disable_hot_tracking) {
+ disable_hot_tracking_ = disable_hot_tracking;
+ }
+ bool disable_hot_tracking_for_testing() const {
+ return disable_hot_tracking_;
+ }
+
private:
friend class base::RefCountedThreadSafe<BrowserAccessibilityStateImpl>;
friend struct DefaultSingletonTraits<BrowserAccessibilityStateImpl>;
@@ -84,6 +96,8 @@ class CONTENT_EXPORT BrowserAccessibilityStateImpl
std::vector<base::Closure> histogram_callbacks_;
+ bool disable_hot_tracking_;
+
DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityStateImpl);
};
diff --git a/chromium/content/browser/accessibility/browser_accessibility_state_impl_win.cc b/chromium/content/browser/accessibility/browser_accessibility_state_impl_win.cc
index 28f05e0e7ec..ddce50ec60e 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_state_impl_win.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_state_impl_win.cc
@@ -8,6 +8,7 @@
#include <psapi.h>
#include "base/files/file_path.h"
+#include "base/macros.h"
#include "base/metrics/histogram.h"
#include "base/strings/string_util.h"
@@ -56,7 +57,7 @@ void BrowserAccessibilityStateImpl::UpdatePlatformSpecificHistograms() {
size_t module_count = bytes_required / sizeof(HMODULE);
for (size_t i = 0; i < module_count; i++) {
TCHAR filename[MAX_PATH];
- GetModuleFileName(modules[i], filename, sizeof(filename));
+ GetModuleFileName(modules[i], filename, arraysize(filename));
base::string16 module_name(base::FilePath(filename).BaseName().value());
if (LowerCaseEqualsASCII(module_name, "fsdomsrv.dll"))
jaws = true;
diff --git a/chromium/content/browser/accessibility/browser_accessibility_win.cc b/chromium/content/browser/accessibility/browser_accessibility_win.cc
index 924ad75105b..3d5907bb173 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_win.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_win.cc
@@ -35,7 +35,7 @@ const GUID GUID_IAccessibleContentDocument = {
0xa5d8e1f3, 0x3571, 0x4d8f,
0x95, 0x21, 0x07, 0xed, 0x28, 0xfb, 0x07, 0x2e};
-const base::char16 BrowserAccessibilityWin::kEmbeddedCharacter[] = L"\xfffc";
+const base::char16 BrowserAccessibilityWin::kEmbeddedCharacter = L'\xfffc';
// static
LONG BrowserAccessibilityWin::next_unique_id_win_ =
@@ -63,15 +63,16 @@ class BrowserAccessibilityRelation
CONTENT_EXPORT void AddTarget(int target_id);
// IAccessibleRelation methods.
- CONTENT_EXPORT STDMETHODIMP get_relationType(BSTR* relation_type);
- CONTENT_EXPORT STDMETHODIMP get_nTargets(long* n_targets);
- CONTENT_EXPORT STDMETHODIMP get_target(long target_index, IUnknown** target);
- CONTENT_EXPORT STDMETHODIMP get_targets(long max_targets,
- IUnknown** targets,
- long* n_targets);
+ CONTENT_EXPORT STDMETHODIMP get_relationType(BSTR* relation_type) override;
+ CONTENT_EXPORT STDMETHODIMP get_nTargets(long* n_targets) override;
+ CONTENT_EXPORT STDMETHODIMP
+ get_target(long target_index, IUnknown** target) override;
+ CONTENT_EXPORT STDMETHODIMP
+ get_targets(long max_targets, IUnknown** targets, long* n_targets) override;
// IAccessibleRelation methods not implemented.
- CONTENT_EXPORT STDMETHODIMP get_localizedRelationType(BSTR* relation_type) {
+ CONTENT_EXPORT STDMETHODIMP
+ get_localizedRelationType(BSTR* relation_type) override {
return E_NOTIMPL;
}
@@ -175,6 +176,20 @@ STDMETHODIMP BrowserAccessibilityRelation::get_targets(long max_targets,
}
//
+// BrowserAccessibilityWin::WinAttributes
+//
+
+BrowserAccessibilityWin::WinAttributes::WinAttributes()
+ : ia_role(0),
+ ia_state(0),
+ ia2_role(0),
+ ia2_state(0) {
+}
+
+BrowserAccessibilityWin::WinAttributes::~WinAttributes() {
+}
+
+//
// BrowserAccessibilityWin
//
@@ -192,12 +207,7 @@ BrowserAccessibilityWin* BrowserAccessibility::ToBrowserAccessibilityWin() {
}
BrowserAccessibilityWin::BrowserAccessibilityWin()
- : ia_role_(0),
- ia_state_(0),
- ia2_role_(0),
- ia2_state_(0),
- first_time_(true),
- old_ia_state_(0),
+ : win_attributes_(new WinAttributes()),
previous_scroll_x_(0),
previous_scroll_y_(0) {
// Start unique IDs at -1 and decrement each time, because get_accChild
@@ -382,7 +392,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_accDefaultAction(VARIANT var_id,
return E_INVALIDARG;
return target->GetStringAttributeAsBstr(
- ui::AX_ATTR_SHORTCUT, def_action);
+ ui::AX_ATTR_ACTION, def_action);
}
STDMETHODIMP BrowserAccessibilityWin::get_accDescription(VARIANT var_id,
@@ -397,8 +407,14 @@ STDMETHODIMP BrowserAccessibilityWin::get_accDescription(VARIANT var_id,
if (!target)
return E_INVALIDARG;
- return target->GetStringAttributeAsBstr(
- ui::AX_ATTR_DESCRIPTION, desc);
+ base::string16 description_str = target->description();
+ if (description_str.empty())
+ return S_FALSE;
+
+ *desc = SysAllocString(description_str.c_str());
+
+ DCHECK(*desc);
+ return S_OK;
}
STDMETHODIMP BrowserAccessibilityWin::get_accFocus(VARIANT* focus_child) {
@@ -434,8 +450,14 @@ STDMETHODIMP BrowserAccessibilityWin::get_accHelp(VARIANT var_id, BSTR* help) {
if (!target)
return E_INVALIDARG;
- return target->GetStringAttributeAsBstr(
- ui::AX_ATTR_HELP, help);
+ base::string16 help_str = target->help();
+ if (help_str.empty())
+ return S_FALSE;
+
+ *help = SysAllocString(help_str.c_str());
+
+ DCHECK(*help);
+ return S_OK;
}
STDMETHODIMP BrowserAccessibilityWin::get_accKeyboardShortcut(VARIANT var_id,
@@ -465,24 +487,24 @@ STDMETHODIMP BrowserAccessibilityWin::get_accName(VARIANT var_id, BSTR* name) {
if (!target)
return E_INVALIDARG;
- std::string name_str = target->name();
+ base::string16 name_str = target->name();
// If the name is empty, see if it's labeled by another element.
if (name_str.empty()) {
int title_elem_id;
if (target->GetIntAttribute(ui::AX_ATTR_TITLE_UI_ELEMENT,
&title_elem_id)) {
- BrowserAccessibility* title_elem =
- manager()->GetFromID(title_elem_id);
+ BrowserAccessibilityWin* title_elem =
+ manager()->GetFromID(title_elem_id)->ToBrowserAccessibilityWin();
if (title_elem)
- name_str = title_elem->GetTextRecursive();
+ name_str = title_elem->GetNameRecursive();
}
}
if (name_str.empty())
return S_FALSE;
- *name = SysAllocString(base::UTF8ToUTF16(name_str).c_str());
+ *name = SysAllocString(name_str.c_str());
DCHECK(*name);
return S_OK;
@@ -530,12 +552,12 @@ STDMETHODIMP BrowserAccessibilityWin::get_accRole(VARIANT var_id,
if (!target)
return E_INVALIDARG;
- if (!target->role_name_.empty()) {
+ if (!target->role_name().empty()) {
role->vt = VT_BSTR;
- role->bstrVal = SysAllocString(target->role_name_.c_str());
+ role->bstrVal = SysAllocString(target->role_name().c_str());
} else {
role->vt = VT_I4;
- role->lVal = target->ia_role_;
+ role->lVal = target->ia_role();
}
return S_OK;
}
@@ -553,7 +575,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_accState(VARIANT var_id,
return E_INVALIDARG;
state->vt = VT_I4;
- state->lVal = target->ia_state_;
+ state->lVal = target->ia_state();
if (manager()->GetFocus(NULL) == this)
state->lVal |= STATE_SYSTEM_FOCUSED;
@@ -583,22 +605,20 @@ STDMETHODIMP BrowserAccessibilityWin::get_accValue(VARIANT var_id,
// Expose color well value.
if (target->ia2_role() == IA2_ROLE_COLOR_CHOOSER) {
- int r = target->GetIntAttribute(
- ui::AX_ATTR_COLOR_VALUE_RED);
- int g = target->GetIntAttribute(
- ui::AX_ATTR_COLOR_VALUE_GREEN);
- int b = target->GetIntAttribute(
- ui::AX_ATTR_COLOR_VALUE_BLUE);
+ int color = target->GetIntAttribute(ui::AX_ATTR_COLOR_VALUE);
+ int red = (color >> 16) & 0xFF;
+ int green = (color >> 8) & 0xFF;
+ int blue = color & 0xFF;
base::string16 value_text;
- value_text = base::IntToString16((r * 100) / 255) + L"% red " +
- base::IntToString16((g * 100) / 255) + L"% green " +
- base::IntToString16((b * 100) / 255) + L"% blue";
+ value_text = base::IntToString16((red * 100) / 255) + L"% red " +
+ base::IntToString16((green * 100) / 255) + L"% green " +
+ base::IntToString16((blue * 100) / 255) + L"% blue";
*value = SysAllocString(value_text.c_str());
DCHECK(*value);
return S_OK;
}
- *value = SysAllocString(base::UTF8ToUTF16(target->value()).c_str());
+ *value = SysAllocString(target->value().c_str());
DCHECK(*value);
return S_OK;
}
@@ -670,6 +690,15 @@ STDMETHODIMP BrowserAccessibilityWin::accSelect(
return S_FALSE;
}
+STDMETHODIMP
+BrowserAccessibilityWin::put_accName(VARIANT var_id, BSTR put_name) {
+ return E_NOTIMPL;
+}
+STDMETHODIMP
+BrowserAccessibilityWin::put_accValue(VARIANT var_id, BSTR put_val) {
+ return E_NOTIMPL;
+}
+
//
// IAccessible2 methods.
//
@@ -681,7 +710,7 @@ STDMETHODIMP BrowserAccessibilityWin::role(LONG* role) {
if (!role)
return E_INVALIDARG;
- *role = ia2_role_;
+ *role = ia2_role();
return S_OK;
}
@@ -696,10 +725,9 @@ STDMETHODIMP BrowserAccessibilityWin::get_attributes(BSTR* attributes) {
// The iaccessible2 attributes are a set of key-value pairs
// separated by semicolons, with a colon between the key and the value.
base::string16 str;
- for (unsigned int i = 0; i < ia2_attributes_.size(); ++i) {
- if (i != 0)
- str += L';';
- str += ia2_attributes_[i];
+ const std::vector<base::string16>& attributes_list = ia2_attributes();
+ for (unsigned int i = 0; i < attributes_list.size(); ++i) {
+ str += attributes_list[i] + L';';
}
if (str.empty())
@@ -717,7 +745,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_states(AccessibleStates* states) {
if (!states)
return E_INVALIDARG;
- *states = ia2_state_;
+ *states = ia2_state();
return S_OK;
}
@@ -886,15 +914,42 @@ STDMETHODIMP BrowserAccessibilityWin::get_groupPosition(
if (!group_level || !similar_items_in_group || !position_in_group)
return E_INVALIDARG;
- if (GetRole() == ui::AX_ROLE_LIST_BOX_OPTION &&
- GetParent() &&
- GetParent()->GetRole() == ui::AX_ROLE_LIST_BOX) {
- *group_level = 0;
- *similar_items_in_group = GetParent()->PlatformChildCount();
- *position_in_group = GetIndexInParent() + 1;
- return S_OK;
- }
+ *group_level = 0;
+ *similar_items_in_group = GetIntAttribute(ui::AX_ATTR_SET_SIZE);
+ *position_in_group = GetIntAttribute(ui::AX_ATTR_POS_IN_SET);
+ return S_OK;
+}
+
+//
+// IAccessibleEx methods not implemented.
+//
+STDMETHODIMP BrowserAccessibilityWin::get_extendedRole(BSTR* extended_role) {
+ return E_NOTIMPL;
+}
+STDMETHODIMP
+BrowserAccessibilityWin::get_localizedExtendedRole(
+ BSTR* localized_extended_role) {
+ return E_NOTIMPL;
+}
+STDMETHODIMP
+BrowserAccessibilityWin::get_nExtendedStates(LONG* n_extended_states) {
+ return E_NOTIMPL;
+}
+STDMETHODIMP
+BrowserAccessibilityWin::get_extendedStates(LONG max_extended_states,
+ BSTR** extended_states,
+ LONG* n_extended_states) {
+ return E_NOTIMPL;
+}
+STDMETHODIMP
+BrowserAccessibilityWin::get_localizedExtendedStates(
+ LONG max_localized_extended_states,
+ BSTR** localized_extended_states,
+ LONG* n_localized_extended_states) {
+ return E_NOTIMPL;
+}
+STDMETHODIMP BrowserAccessibilityWin::get_locale(IA2Locale* locale) {
return E_NOTIMPL;
}
@@ -981,8 +1036,13 @@ STDMETHODIMP BrowserAccessibilityWin::get_description(BSTR* desc) {
if (!desc)
return E_INVALIDARG;
- return GetStringAttributeAsBstr(
- ui::AX_ATTR_DESCRIPTION, desc);
+ if (description().empty())
+ return S_FALSE;
+
+ *desc = SysAllocString(description().c_str());
+
+ DCHECK(*desc);
+ return S_OK;
}
STDMETHODIMP BrowserAccessibilityWin::get_imagePosition(
@@ -1158,8 +1218,10 @@ STDMETHODIMP BrowserAccessibilityWin::get_columnDescription(long column,
return S_OK;
}
- return cell->GetStringAttributeAsBstr(
- ui::AX_ATTR_DESCRIPTION, description);
+ if (cell->description().size() > 0) {
+ *description = SysAllocString(cell->description().c_str());
+ return S_OK;
+ }
}
}
@@ -1345,8 +1407,10 @@ STDMETHODIMP BrowserAccessibilityWin::get_rowDescription(long row,
return S_OK;
}
- return cell->GetStringAttributeAsBstr(
- ui::AX_ATTR_DESCRIPTION, description);
+ if (cell->description().size() > 0) {
+ *description = SysAllocString(cell->description().c_str());
+ return S_OK;
+ }
}
}
@@ -1564,6 +1628,27 @@ STDMETHODIMP BrowserAccessibilityWin::get_rowColumnExtentsAtIndex(
return S_FALSE;
}
+STDMETHODIMP BrowserAccessibilityWin::selectRow(long row) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::selectColumn(long column) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::unselectRow(long row) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::unselectColumn(long column) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP
+BrowserAccessibilityWin::get_modelChange(IA2TableModelChange* model_change) {
+ return E_NOTIMPL;
+}
+
//
// IAccessibleTable2 methods.
//
@@ -1916,9 +2001,14 @@ STDMETHODIMP BrowserAccessibilityWin::get_caretOffset(LONG* offset) {
if (!offset)
return E_INVALIDARG;
+ // IA2 spec says that caret offset should be -1 if the object is not focused.
+ if (manager()->GetFocus(this) != this) {
+ *offset = -1;
+ return S_FALSE;
+ }
+
*offset = 0;
- if (GetRole() == ui::AX_ROLE_TEXT_FIELD ||
- GetRole() == ui::AX_ROLE_TEXT_AREA) {
+ if (IsEditableText()) {
int sel_start = 0;
if (GetIntAttribute(ui::AX_ATTR_TEXT_SEL_START,
&sel_start))
@@ -1973,8 +2063,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_nSelections(LONG* n_selections) {
return E_INVALIDARG;
*n_selections = 0;
- if (GetRole() == ui::AX_ROLE_TEXT_FIELD ||
- GetRole() == ui::AX_ROLE_TEXT_AREA) {
+ if (IsEditableText()) {
int sel_start = 0;
int sel_end = 0;
if (GetIntAttribute(ui::AX_ATTR_TEXT_SEL_START,
@@ -1996,10 +2085,13 @@ STDMETHODIMP BrowserAccessibilityWin::get_selection(LONG selection_index,
if (!start_offset || !end_offset || selection_index != 0)
return E_INVALIDARG;
+ LONG n_selections = 0;
+ if (FAILED(get_nSelections(&n_selections)) || n_selections < 1)
+ return E_INVALIDARG;
+
*start_offset = 0;
*end_offset = 0;
- if (GetRole() == ui::AX_ROLE_TEXT_FIELD ||
- GetRole() == ui::AX_ROLE_TEXT_AREA) {
+ if (IsEditableText()) {
int sel_start = 0;
int sel_end = 0;
if (GetIntAttribute(
@@ -2065,6 +2157,15 @@ STDMETHODIMP BrowserAccessibilityWin::get_textAtOffset(
if (!start_offset || !end_offset || !text)
return E_INVALIDARG;
+ const base::string16& text_str = TextForIAccessibleText();
+ HandleSpecialTextOffset(text_str, &offset);
+ if (offset < 0)
+ return E_INVALIDARG;
+
+ LONG text_len = text_str.length();
+ if (offset > text_len)
+ return E_INVALIDARG;
+
// The IAccessible2 spec says we don't have to implement the "sentence"
// boundary type, we can just let the screenreader handle it.
if (boundary_type == IA2_TEXT_BOUNDARY_SENTENCE) {
@@ -2074,7 +2175,14 @@ STDMETHODIMP BrowserAccessibilityWin::get_textAtOffset(
return S_FALSE;
}
- const base::string16& text_str = TextForIAccessibleText();
+ // According to the IA2 Spec, only line boundaries should succeed when
+ // the offset is one past the end of the text.
+ if (offset == text_len && boundary_type != IA2_TEXT_BOUNDARY_LINE) {
+ *start_offset = 0;
+ *end_offset = 0;
+ *text = nullptr;
+ return S_FALSE;
+ }
*start_offset = FindBoundary(
text_str, boundary_type, offset, ui::BACKWARDS_DIRECTION);
@@ -2148,11 +2256,18 @@ STDMETHODIMP BrowserAccessibilityWin::get_newText(IA2TextSegment* new_text) {
if (!new_text)
return E_INVALIDARG;
- base::string16 text = TextForIAccessibleText();
+ if (!old_win_attributes_)
+ return E_FAIL;
+
+ int start, old_len, new_len;
+ ComputeHypertextRemovedAndInserted(&start, &old_len, &new_len);
+ if (new_len == 0)
+ return E_FAIL;
- new_text->text = SysAllocString(text.c_str());
- new_text->start = 0;
- new_text->end = static_cast<long>(text.size());
+ base::string16 substr = hypertext().substr(start, new_len);
+ new_text->text = SysAllocString(substr.c_str());
+ new_text->start = static_cast<long>(start);
+ new_text->end = static_cast<long>(start + new_len);
return S_OK;
}
@@ -2163,9 +2278,19 @@ STDMETHODIMP BrowserAccessibilityWin::get_oldText(IA2TextSegment* old_text) {
if (!old_text)
return E_INVALIDARG;
- old_text->text = SysAllocString(old_text_.c_str());
- old_text->start = 0;
- old_text->end = static_cast<long>(old_text_.size());
+ if (!old_win_attributes_)
+ return E_FAIL;
+
+ int start, old_len, new_len;
+ ComputeHypertextRemovedAndInserted(&start, &old_len, &new_len);
+ if (old_len == 0)
+ return E_FAIL;
+
+ base::string16 old_hypertext = old_win_attributes_->hypertext;
+ base::string16 substr = old_hypertext.substr(start, old_len);
+ old_text->text = SysAllocString(substr.c_str());
+ old_text->start = static_cast<long>(start);
+ old_text->end = static_cast<long>(start + old_len);
return S_OK;
}
@@ -2256,6 +2381,17 @@ STDMETHODIMP BrowserAccessibilityWin::setSelection(LONG selection_index,
}
//
+// IAccessibleText methods not implemented.
+//
+
+STDMETHODIMP BrowserAccessibilityWin::get_attributes(LONG offset,
+ LONG* start_offset,
+ LONG* end_offset,
+ BSTR* text_attributes) {
+ return E_NOTIMPL;
+}
+
+//
// IAccessibleHypertext methods.
//
@@ -2266,7 +2402,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_nHyperlinks(long* hyperlink_count) {
if (!hyperlink_count)
return E_INVALIDARG;
- *hyperlink_count = hyperlink_offset_to_index_.size();
+ *hyperlink_count = hyperlink_offset_to_index().size();
return S_OK;
}
@@ -2278,14 +2414,19 @@ STDMETHODIMP BrowserAccessibilityWin::get_hyperlink(
if (!hyperlink ||
index < 0 ||
- index >= static_cast<long>(hyperlinks_.size())) {
+ index >= static_cast<long>(hyperlinks().size())) {
return E_INVALIDARG;
}
+ int32 id = hyperlinks()[index];
BrowserAccessibilityWin* child =
- InternalGetChild(hyperlinks_[index])->ToBrowserAccessibilityWin();
- *hyperlink = static_cast<IAccessibleHyperlink*>(child->NewReference());
- return S_OK;
+ manager()->GetFromID(id)->ToBrowserAccessibilityWin();
+ if (child) {
+ *hyperlink = static_cast<IAccessibleHyperlink*>(child->NewReference());
+ return S_OK;
+ }
+
+ return E_FAIL;
}
STDMETHODIMP BrowserAccessibilityWin::get_hyperlinkIndex(
@@ -2299,12 +2440,14 @@ STDMETHODIMP BrowserAccessibilityWin::get_hyperlinkIndex(
*hyperlink_index = -1;
- if (char_index < 0 || char_index >= static_cast<long>(hypertext_.size()))
+ if (char_index < 0 ||
+ char_index >= static_cast<long>(hypertext().size())) {
return E_INVALIDARG;
+ }
std::map<int32, int32>::iterator it =
- hyperlink_offset_to_index_.find(char_index);
- if (it == hyperlink_offset_to_index_.end())
+ hyperlink_offset_to_index().find(char_index);
+ if (it == hyperlink_offset_to_index().end())
return E_FAIL;
*hyperlink_index = it->second;
@@ -2312,6 +2455,56 @@ STDMETHODIMP BrowserAccessibilityWin::get_hyperlinkIndex(
}
//
+// IAccessibleHyperlink not implemented.
+//
+
+STDMETHODIMP BrowserAccessibilityWin::get_anchor(long index, VARIANT* anchor) {
+ return E_NOTIMPL;
+}
+STDMETHODIMP
+BrowserAccessibilityWin::get_anchorTarget(long index, VARIANT* anchor_target) {
+ return E_NOTIMPL;
+}
+STDMETHODIMP BrowserAccessibilityWin::get_startIndex(long* index) {
+ return E_NOTIMPL;
+}
+STDMETHODIMP BrowserAccessibilityWin::get_endIndex(long* index) {
+ return E_NOTIMPL;
+}
+STDMETHODIMP BrowserAccessibilityWin::get_valid(boolean* valid) {
+ return E_NOTIMPL;
+}
+
+//
+// IAccessibleAction not implemented.
+//
+
+STDMETHODIMP BrowserAccessibilityWin::nActions(long* n_actions) {
+ return E_NOTIMPL;
+}
+STDMETHODIMP BrowserAccessibilityWin::doAction(long action_index) {
+ return E_NOTIMPL;
+}
+STDMETHODIMP
+BrowserAccessibilityWin::get_description(long action_index, BSTR* description) {
+ return E_NOTIMPL;
+}
+STDMETHODIMP BrowserAccessibilityWin::get_keyBinding(long action_index,
+ long n_max_bindings,
+ BSTR** key_bindings,
+ long* n_bindings) {
+ return E_NOTIMPL;
+}
+STDMETHODIMP BrowserAccessibilityWin::get_name(long action_index, BSTR* name) {
+ return E_NOTIMPL;
+}
+STDMETHODIMP
+BrowserAccessibilityWin::get_localizedName(long action_index,
+ BSTR* localized_name) {
+ return E_NOTIMPL;
+}
+
+//
// IAccessibleValue methods.
//
@@ -2423,6 +2616,17 @@ STDMETHODIMP BrowserAccessibilityWin::get_docType(BSTR* doc_type) {
ui::AX_ATTR_DOC_DOCTYPE, doc_type);
}
+STDMETHODIMP
+BrowserAccessibilityWin::get_nameSpaceURIForID(short name_space_id,
+ BSTR* name_space_uri) {
+ return E_NOTIMPL;
+}
+STDMETHODIMP
+BrowserAccessibilityWin::put_alternateViewMediaTypes(
+ BSTR* comma_separated_media_types) {
+ return E_NOTIMPL;
+}
+
//
// ISimpleDOMNode methods.
//
@@ -2449,14 +2653,14 @@ STDMETHODIMP BrowserAccessibilityWin::get_nodeInfo(
*node_name = NULL;
*name_space_id = 0;
- *node_value = SysAllocString(base::UTF8ToUTF16(value()).c_str());
+ *node_value = SysAllocString(value().c_str());
*num_children = PlatformChildCount();
*unique_id = unique_id_win_;
- if (ia_role_ == ROLE_SYSTEM_DOCUMENT) {
+ if (ia_role() == ROLE_SYSTEM_DOCUMENT) {
*node_type = NODETYPE_DOCUMENT;
- } else if (ia_role_ == ROLE_SYSTEM_TEXT &&
- ((ia2_state_ & IA2_STATE_EDITABLE) == 0)) {
+ } else if (ia_role() == ROLE_SYSTEM_TEXT &&
+ ((ia2_state() & IA2_STATE_EDITABLE) == 0)) {
*node_type = NODETYPE_TEXT;
} else {
*node_type = NODETYPE_ELEMENT;
@@ -2686,6 +2890,19 @@ STDMETHODIMP BrowserAccessibilityWin::get_childAt(
return S_OK;
}
+STDMETHODIMP BrowserAccessibilityWin::get_innerHTML(BSTR* innerHTML) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP
+BrowserAccessibilityWin::get_localInterface(void** local_interface) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_language(BSTR* language) {
+ return E_NOTIMPL;
+}
+
//
// ISimpleDOMText methods.
//
@@ -2763,6 +2980,10 @@ STDMETHODIMP BrowserAccessibilityWin::scrollToSubstring(
return S_OK;
}
+STDMETHODIMP BrowserAccessibilityWin::get_fontFamily(BSTR* font_family) {
+ return E_NOTIMPL;
+}
+
//
// IServiceProvider methods.
//
@@ -2819,6 +3040,27 @@ STDMETHODIMP BrowserAccessibilityWin::QueryService(REFGUID guidService,
return E_FAIL;
}
+STDMETHODIMP
+BrowserAccessibilityWin::GetObjectForChild(long child_id, IAccessibleEx** ret) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP
+BrowserAccessibilityWin::GetIAccessiblePair(IAccessible** acc, long* child_id) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::GetRuntimeId(SAFEARRAY** runtime_id) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP
+BrowserAccessibilityWin::ConvertReturnedElement(
+ IRawElementProviderSimple* element,
+ IAccessibleEx** acc) {
+ return E_NOTIMPL;
+}
+
STDMETHODIMP BrowserAccessibilityWin::GetPatternProvider(PATTERNID id,
IUnknown** provider) {
DVLOG(1) << "In Function: "
@@ -2855,6 +3097,16 @@ STDMETHODIMP BrowserAccessibilityWin::GetPropertyValue(PROPERTYID id,
return S_OK;
}
+STDMETHODIMP BrowserAccessibilityWin::get_ProviderOptions(
+ enum ProviderOptions* ret) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_HostRawElementProvider(
+ IRawElementProviderSimple** provider) {
+ return E_NOTIMPL;
+}
+
//
// CComObjectRootEx methods.
//
@@ -2865,8 +3117,9 @@ HRESULT WINAPI BrowserAccessibilityWin::InternalQueryInterface(
const _ATL_INTMAP_ENTRY* entries,
REFIID iid,
void** object) {
- int32 ia_role =
- reinterpret_cast<BrowserAccessibilityWin*>(this_ptr)->ia_role_;
+ BrowserAccessibilityWin* accessibility =
+ reinterpret_cast<BrowserAccessibilityWin*>(this_ptr);
+ int32 ia_role = accessibility->ia_role();
if (iid == IID_IAccessibleImage) {
if (ia_role != ROLE_SYSTEM_GRAPHIC) {
*object = NULL;
@@ -2878,7 +3131,7 @@ HRESULT WINAPI BrowserAccessibilityWin::InternalQueryInterface(
return E_NOINTERFACE;
}
} else if (iid == IID_IAccessibleTableCell) {
- if (ia_role != ROLE_SYSTEM_CELL) {
+ if (!accessibility->IsCellOrTableHeaderRole()) {
*object = NULL;
return E_NOINTERFACE;
}
@@ -2904,14 +3157,23 @@ HRESULT WINAPI BrowserAccessibilityWin::InternalQueryInterface(
// Private methods.
//
-// Called every time this node's data changes.
-void BrowserAccessibilityWin::OnDataChanged() {
- BrowserAccessibility::OnDataChanged();
+void BrowserAccessibilityWin::UpdateStep1ComputeWinAttributes() {
+ // Swap win_attributes_ to old_win_attributes_, allowing us to see
+ // exactly what changed and fire appropriate events. Note that
+ // old_win_attributes_ is cleared at the end of UpdateStep3FireEvents.
+ old_win_attributes_.swap(win_attributes_);
+ win_attributes_.reset(new WinAttributes());
InitRoleAndState();
+ win_attributes_->ia2_attributes.clear();
+
+ // Expose autocomplete attribute for combobox and textbox.
+ StringAttributeToIA2(ui::AX_ATTR_AUTO_COMPLETE, "autocomplete");
+
// Expose the "display" and "tag" attributes.
StringAttributeToIA2(ui::AX_ATTR_DISPLAY, "display");
+ StringAttributeToIA2(ui::AX_ATTR_DROPEFFECT, "dropeffect");
StringAttributeToIA2(ui::AX_ATTR_TEXT_INPUT_TYPE, "text-input-type");
StringAttributeToIA2(ui::AX_ATTR_HTML_TAG, "tag");
StringAttributeToIA2(ui::AX_ATTR_ROLE, "xml-roles");
@@ -2919,22 +3181,16 @@ void BrowserAccessibilityWin::OnDataChanged() {
// Expose "level" attribute for headings, trees, etc.
IntAttributeToIA2(ui::AX_ATTR_HIERARCHICAL_LEVEL, "level");
- // Expose the set size and position in set for listbox options.
- if (GetRole() == ui::AX_ROLE_LIST_BOX_OPTION &&
- GetParent() &&
- GetParent()->GetRole() == ui::AX_ROLE_LIST_BOX) {
- ia2_attributes_.push_back(
- L"setsize:" + base::IntToString16(GetParent()->PlatformChildCount()));
- ia2_attributes_.push_back(
- L"setsize:" + base::IntToString16(GetIndexInParent() + 1));
- }
+ // Expose the set size and position in set.
+ IntAttributeToIA2(ui::AX_ATTR_SET_SIZE, "setsize");
+ IntAttributeToIA2(ui::AX_ATTR_POS_IN_SET, "posinset");
- 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");
+ 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) {
+ win_attributes_->ia2_attributes.push_back(L"checkable:true");
}
// Expose live region attributes.
@@ -2943,6 +3199,9 @@ void BrowserAccessibilityWin::OnDataChanged() {
BoolAttributeToIA2(ui::AX_ATTR_LIVE_ATOMIC, "atomic");
BoolAttributeToIA2(ui::AX_ATTR_LIVE_BUSY, "busy");
+ // Expose aria-grabbed attributes.
+ BoolAttributeToIA2(ui::AX_ATTR_GRABBED, "grabbed");
+
// Expose container live region attributes.
StringAttributeToIA2(ui::AX_ATTR_CONTAINER_LIVE_STATUS,
"container-live");
@@ -2953,15 +3212,8 @@ void BrowserAccessibilityWin::OnDataChanged() {
BoolAttributeToIA2(ui::AX_ATTR_CONTAINER_LIVE_BUSY,
"container-busy");
- // Expose slider value.
- if (ia_role_ == ROLE_SYSTEM_PROGRESSBAR ||
- ia_role_ == ROLE_SYSTEM_SCROLLBAR ||
- ia_role_ == ROLE_SYSTEM_SLIDER) {
- ia2_attributes_.push_back(L"valuetext:" + GetValueText());
- }
-
// Expose table cell index.
- if (ia_role_ == ROLE_SYSTEM_CELL) {
+ if (IsCellOrTableHeaderRole()) {
BrowserAccessibility* table = GetParent();
while (table && table->GetRole() != ui::AX_ROLE_TABLE)
table = table->GetParent();
@@ -2970,13 +3222,72 @@ void BrowserAccessibilityWin::OnDataChanged() {
ui::AX_ATTR_UNIQUE_CELL_IDS);
for (size_t i = 0; i < unique_cell_ids.size(); ++i) {
if (unique_cell_ids[i] == GetId()) {
- ia2_attributes_.push_back(
+ win_attributes_->ia2_attributes.push_back(
base::string16(L"table-cell-index:") + base::IntToString16(i));
}
}
}
}
+ // Expose invalid state for form controls and elements with aria-invalid.
+ int invalid_state;
+ if (GetIntAttribute(ui::AX_ATTR_INVALID_STATE, &invalid_state)) {
+ // TODO(nektar): Handle the possibility of having multiple aria-invalid
+ // attributes defined, e.g., "invalid:spelling,grammar".
+ switch (invalid_state) {
+ case ui::AX_INVALID_STATE_FALSE:
+ win_attributes_->ia2_attributes.push_back(L"invalid:false");
+ break;
+ case ui::AX_INVALID_STATE_TRUE:
+ win_attributes_->ia2_attributes.push_back(L"invalid:true");
+ break;
+ case ui::AX_INVALID_STATE_SPELLING:
+ win_attributes_->ia2_attributes.push_back(L"invalid:spelling");
+ break;
+ case ui::AX_INVALID_STATE_GRAMMAR:
+ win_attributes_->ia2_attributes.push_back(L"invalid:grammar");
+ break;
+ case ui::AX_INVALID_STATE_OTHER:
+ {
+ base::string16 aria_invalid_value;
+ if (GetString16Attribute(ui::AX_ATTR_ARIA_INVALID_VALUE,
+ &aria_invalid_value)) {
+ win_attributes_->ia2_attributes.push_back(
+ L"invalid:" + aria_invalid_value);
+ } else {
+ // Set the attribute to L"true", since we cannot be more specific.
+ win_attributes_->ia2_attributes.push_back(L"invalid:true");
+ }
+ }
+ break;
+ default:
+ NOTREACHED();
+ }
+ }
+
+ // Expose row or column header sort direction.
+ int32 sort_direction;
+ if ((ia_role() == ROLE_SYSTEM_COLUMNHEADER ||
+ ia_role() == ROLE_SYSTEM_ROWHEADER) &&
+ GetIntAttribute(ui::AX_ATTR_SORT_DIRECTION, &sort_direction)) {
+ switch (sort_direction) {
+ case ui::AX_SORT_DIRECTION_UNSORTED:
+ win_attributes_->ia2_attributes.push_back(L"sort:none");
+ break;
+ case ui::AX_SORT_DIRECTION_ASCENDING:
+ win_attributes_->ia2_attributes.push_back(L"sort:ascending");
+ break;
+ case ui::AX_SORT_DIRECTION_DESCENDING:
+ win_attributes_->ia2_attributes.push_back(L"sort:descending");
+ break;
+ case ui::AX_SORT_DIRECTION_OTHER:
+ win_attributes_->ia2_attributes.push_back(L"sort:other");
+ break;
+ default:
+ NOTREACHED();
+ }
+ }
+
// The calculation of the accessible name of an element has been
// standardized in the HTML to Platform Accessibility APIs Implementation
// Guide (http://www.w3.org/TR/html-aapi/). In order to return the
@@ -2998,16 +3309,16 @@ void BrowserAccessibilityWin::OnDataChanged() {
// always returns the primary name in "name" and the secondary name,
// if any, in "description".
- int title_elem_id = GetIntAttribute(
- ui::AX_ATTR_TITLE_UI_ELEMENT);
- std::string help = GetStringAttribute(ui::AX_ATTR_HELP);
- std::string description = GetStringAttribute(
- ui::AX_ATTR_DESCRIPTION);
+ int title_elem_id = GetIntAttribute(ui::AX_ATTR_TITLE_UI_ELEMENT);
+ base::string16 name = GetString16Attribute(ui::AX_ATTR_NAME);
+ base::string16 description = GetString16Attribute(ui::AX_ATTR_DESCRIPTION);
+ base::string16 help = GetString16Attribute(ui::AX_ATTR_HELP);
+ base::string16 value = GetString16Attribute(ui::AX_ATTR_VALUE);
// WebKit annoyingly puts the title in the description if there's no other
// description, which just confuses the rest of the logic. Put it back.
// Now "help" is always the value of the "title" attribute, if present.
- std::string title_attr;
+ base::string16 title_attr;
if (GetHtmlAttribute("title", &title_attr) &&
description == title_attr &&
help.empty()) {
@@ -3019,55 +3330,57 @@ void BrowserAccessibilityWin::OnDataChanged() {
// it's nonempty, and the help should become the description if
// there's no description - or the name if there's no name or description.
if (!description.empty()) {
- set_name(description);
+ name = description;
description.clear();
}
if (!help.empty() && description.empty()) {
description = help;
help.clear();
}
- if (!description.empty() && name().empty() && !title_elem_id) {
- set_name(description);
+ if (!description.empty() && name.empty() && !title_elem_id) {
+ name = description;
description.clear();
}
// If it's a text field, also consider the placeholder.
- std::string placeholder;
+ base::string16 placeholder;
if (GetRole() == ui::AX_ROLE_TEXT_FIELD &&
HasState(ui::AX_STATE_FOCUSABLE) &&
GetHtmlAttribute("placeholder", &placeholder)) {
- if (name().empty() && !title_elem_id) {
- set_name(placeholder);
+ if (name.empty() && !title_elem_id) {
+ name = placeholder;
} else if (description.empty()) {
description = placeholder;
}
}
- SetStringAttribute(ui::AX_ATTR_DESCRIPTION, description);
- SetStringAttribute(ui::AX_ATTR_HELP, help);
-
// On Windows, the value of a document should be its url.
if (GetRole() == ui::AX_ROLE_ROOT_WEB_AREA ||
GetRole() == ui::AX_ROLE_WEB_AREA) {
- set_value(GetStringAttribute(ui::AX_ATTR_DOC_URL));
+ value = GetString16Attribute(ui::AX_ATTR_DOC_URL);
}
// For certain roles (listbox option, static text, and list marker)
// WebKit stores the main accessible text in the "value" - swap it so
// that it's the "name".
- if (name().empty() &&
- (GetRole() == ui::AX_ROLE_LIST_BOX_OPTION ||
- GetRole() == ui::AX_ROLE_STATIC_TEXT ||
- GetRole() == ui::AX_ROLE_LIST_MARKER)) {
- std::string tmp = value();
- set_value(name());
- set_name(tmp);
+ if (name.empty() &&
+ (GetRole() == ui::AX_ROLE_STATIC_TEXT ||
+ GetRole() == ui::AX_ROLE_LIST_MARKER ||
+ IsListBoxOptionOrMenuListOption())) {
+ base::string16 tmp = value;
+ value = name;
+ name = tmp;
}
// If this doesn't have a value and is linked then set its value to the url
// attribute. This allows screen readers to read an empty link's destination.
- if (value().empty() && (ia_state_ & STATE_SYSTEM_LINKED))
- set_value(GetStringAttribute(ui::AX_ATTR_URL));
+ if (value.empty() && (ia_state() & STATE_SYSTEM_LINKED))
+ value = GetString16Attribute(ui::AX_ATTR_URL);
+
+ win_attributes_->name = name;
+ win_attributes_->description = description;
+ win_attributes_->help = help;
+ win_attributes_->value = value;
// Clear any old relationships between this node and other nodes.
for (size_t i = 0; i < relations_.size(); ++i)
@@ -3086,88 +3399,151 @@ void BrowserAccessibilityWin::OnDataChanged() {
relation->AddTarget(title_elem_id);
relations_.push_back(relation);
}
+
+ // Expose slider value.
+ if (ia_role() == ROLE_SYSTEM_PROGRESSBAR ||
+ ia_role() == ROLE_SYSTEM_SCROLLBAR ||
+ ia_role() == ROLE_SYSTEM_SLIDER) {
+ win_attributes_->ia2_attributes.push_back(L"valuetext:" + GetValueText());
+ }
+
+ // If this is a web area for a presentational iframe, give it a role of
+ // something other than DOCUMENT so that the fact that it's a separate doc
+ // is not exposed to AT.
+ if (IsWebAreaForPresentationalIframe()) {
+ win_attributes_->ia_role = ROLE_SYSTEM_GROUPING;
+ win_attributes_->ia2_role = ROLE_SYSTEM_GROUPING;
+ }
}
-void BrowserAccessibilityWin::OnUpdateFinished() {
- // Construct the hypertext for this node.
- hyperlink_offset_to_index_.clear();
- hyperlinks_.clear();
- hypertext_.clear();
+void BrowserAccessibilityWin::UpdateStep2ComputeHypertext() {
+ // Construct the hypertext for this node, which contains the concatenation
+ // of all of the static text of this node's children and an embedded object
+ // character for all non-static-text children. Build up a map from the
+ // character index of each embedded object character to the id of the
+ // child object it points to.
for (unsigned int i = 0; i < PlatformChildCount(); ++i) {
- BrowserAccessibility* child = PlatformGetChild(i);
+ BrowserAccessibilityWin* child =
+ PlatformGetChild(i)->ToBrowserAccessibilityWin();
if (child->GetRole() == ui::AX_ROLE_STATIC_TEXT) {
- hypertext_ += base::UTF8ToUTF16(child->name());
+ win_attributes_->hypertext += child->name();
} else {
- hyperlink_offset_to_index_[hypertext_.size()] = hyperlinks_.size();
- hypertext_ += kEmbeddedCharacter;
- hyperlinks_.push_back(i);
+ int32 char_offset = hypertext().size();
+ int32 child_id = child->GetId();
+ int32 index = hyperlinks().size();
+ win_attributes_->hyperlink_offset_to_index[char_offset] = index;
+ win_attributes_->hyperlinks.push_back(child_id);
+ win_attributes_->hypertext += kEmbeddedCharacter;
}
}
- DCHECK_EQ(hyperlink_offset_to_index_.size(), hyperlinks_.size());
-
- // Fire an event when an alert first appears.
- if (GetRole() == ui::AX_ROLE_ALERT && first_time_)
- manager()->NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, this);
-
- // Fire events if text has changed.
- base::string16 text = TextForIAccessibleText();
- if (previous_text_ != text) {
- if (!previous_text_.empty() && !text.empty()) {
- manager()->NotifyAccessibilityEvent(
- ui::AX_EVENT_SHOW, this);
- }
+}
- // TODO(dmazzoni): Look into HIDE events, too.
+void BrowserAccessibilityWin::UpdateStep3FireEvents(bool is_subtree_creation) {
+ BrowserAccessibilityManagerWin* manager =
+ this->manager()->ToBrowserAccessibilityManagerWin();
- old_text_ = previous_text_;
- previous_text_ = text;
+ // Fire an event when an alert first appears.
+ if (ia_role() == ROLE_SYSTEM_ALERT &&
+ old_win_attributes_->ia_role != ROLE_SYSTEM_ALERT) {
+ manager->NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, this);
}
- BrowserAccessibilityManagerWin* manager =
- this->manager()->ToBrowserAccessibilityManagerWin();
+ // Fire an event when a new subtree is created.
+ if (is_subtree_creation)
+ manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_SHOW, this);
+
+ // The rest of the events only fire on changes, not on new objects.
+ if (old_win_attributes_->ia_role != 0 ||
+ !old_win_attributes_->role_name.empty()) {
+ // Fire an event if the name, description, help, or value changes.
+ if (name() != old_win_attributes_->name)
+ manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, this);
+ if (description() != old_win_attributes_->description)
+ manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_DESCRIPTIONCHANGE, this);
+ if (help() != old_win_attributes_->help)
+ manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_HELPCHANGE, this);
+ if (value() != old_win_attributes_->value)
+ manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_VALUECHANGE, this);
+ if (ia_state() != old_win_attributes_->ia_state)
+ manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_STATECHANGE, this);
- // Fire events if the state has changed.
- if (!first_time_ && ia_state_ != old_ia_state_) {
// Normally focus events are handled elsewhere, however
// focus for managed descendants is platform-specific.
// Fire a focus event if the focused descendant in a multi-select
// list box changes.
if (GetRole() == ui::AX_ROLE_LIST_BOX_OPTION &&
- (ia_state_ & STATE_SYSTEM_FOCUSABLE) &&
- (ia_state_ & STATE_SYSTEM_SELECTABLE) &&
- (ia_state_ & STATE_SYSTEM_FOCUSED) &&
- !(old_ia_state_ & STATE_SYSTEM_FOCUSED)) {
- manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_FOCUS, unique_id_win());
+ (ia_state() & STATE_SYSTEM_FOCUSABLE) &&
+ (ia_state() & STATE_SYSTEM_SELECTABLE) &&
+ (ia_state() & STATE_SYSTEM_FOCUSED) &&
+ !(old_win_attributes_->ia_state & STATE_SYSTEM_FOCUSED)) {
+ manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_FOCUS, this);
}
- if ((ia_state_ & STATE_SYSTEM_SELECTED) &&
- !(old_ia_state_ & STATE_SYSTEM_SELECTED)) {
- manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_SELECTIONADD,
- unique_id_win());
- } else if (!(ia_state_ & STATE_SYSTEM_SELECTED) &&
- (old_ia_state_ & STATE_SYSTEM_SELECTED)) {
- manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_SELECTIONREMOVE,
- unique_id_win());
+ // Handle selection being added or removed.
+ bool is_selected_now = (ia_state() & STATE_SYSTEM_SELECTED) != 0;
+ bool was_selected_before =
+ (old_win_attributes_->ia_state & STATE_SYSTEM_SELECTED) != 0;
+ if (is_selected_now || was_selected_before) {
+ bool multiselect = false;
+ if (GetParent() && GetParent()->HasState(ui::AX_STATE_MULTISELECTABLE))
+ multiselect = true;
+
+ if (multiselect) {
+ // In a multi-select box, fire SELECTIONADD and SELECTIONREMOVE events.
+ if (is_selected_now && !was_selected_before) {
+ manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_SELECTIONADD, this);
+ } else if (!is_selected_now && was_selected_before) {
+ manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_SELECTIONREMOVE, this);
+ }
+ } else if (is_selected_now && !was_selected_before) {
+ // In a single-select box, only fire SELECTION events.
+ manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_SELECTION, this);
+ }
}
- old_ia_state_ = ia_state_;
- }
+ // Fire an event if this container object has scrolled.
+ int sx = 0;
+ int sy = 0;
+ if (GetIntAttribute(ui::AX_ATTR_SCROLL_X, &sx) &&
+ GetIntAttribute(ui::AX_ATTR_SCROLL_Y, &sy)) {
+ if (sx != previous_scroll_x_ || sy != previous_scroll_y_)
+ manager->MaybeCallNotifyWinEvent(EVENT_SYSTEM_SCROLLINGEND, this);
+ previous_scroll_x_ = sx;
+ previous_scroll_y_ = sy;
+ }
- // Fire an event if this container object has scrolled.
- int sx = 0;
- int sy = 0;
- if (GetIntAttribute(ui::AX_ATTR_SCROLL_X, &sx) &&
- GetIntAttribute(ui::AX_ATTR_SCROLL_Y, &sy)) {
- if (!first_time_ &&
- (sx != previous_scroll_x_ || sy != previous_scroll_y_)) {
- manager->MaybeCallNotifyWinEvent(EVENT_SYSTEM_SCROLLINGEND,
- unique_id_win());
+ // Changing a static text node can affect the IAccessibleText hypertext
+ // of the parent node, so force an update on the parent.
+ BrowserAccessibilityWin* parent = GetParent()->ToBrowserAccessibilityWin();
+ if (parent &&
+ GetRole() == ui::AX_ROLE_STATIC_TEXT &&
+ name() != old_win_attributes_->name) {
+ parent->UpdateStep1ComputeWinAttributes();
+ parent->UpdateStep2ComputeHypertext();
+ parent->UpdateStep3FireEvents(false);
+ }
+
+ // Fire hypertext-related events.
+ int start, old_len, new_len;
+ ComputeHypertextRemovedAndInserted(&start, &old_len, &new_len);
+ if (old_len > 0) {
+ // In-process screen readers may call IAccessibleText::get_oldText
+ // in reaction to this event to retrieve the text that was removed.
+ manager->MaybeCallNotifyWinEvent(IA2_EVENT_TEXT_REMOVED, this);
+ }
+ if (new_len > 0) {
+ // In-process screen readers may call IAccessibleText::get_newText
+ // in reaction to this event to retrieve the text that was inserted.
+ manager->MaybeCallNotifyWinEvent(IA2_EVENT_TEXT_INSERTED, this);
}
- previous_scroll_x_ = sx;
- previous_scroll_y_ = sy;
}
- first_time_ = false;
+ old_win_attributes_.reset(nullptr);
+}
+
+void BrowserAccessibilityWin::OnSubtreeWillBeDeleted() {
+ manager()->ToBrowserAccessibilityManagerWin()->MaybeCallNotifyWinEvent(
+ EVENT_OBJECT_HIDE, this);
}
void BrowserAccessibilityWin::NativeAddReference() {
@@ -3184,7 +3560,7 @@ bool BrowserAccessibilityWin::IsNative() const {
void BrowserAccessibilityWin::OnLocationChanged() {
manager()->ToBrowserAccessibilityManagerWin()->MaybeCallNotifyWinEvent(
- EVENT_OBJECT_LOCATIONCHANGE, unique_id_win());
+ EVENT_OBJECT_LOCATIONCHANGE, this);
}
BrowserAccessibilityWin* BrowserAccessibilityWin::NewReference() {
@@ -3229,8 +3605,10 @@ void BrowserAccessibilityWin::StringAttributeToIA2(
ui::AXStringAttribute attribute,
const char* ia2_attr) {
base::string16 value;
- if (GetString16Attribute(attribute, &value))
- ia2_attributes_.push_back(base::ASCIIToUTF16(ia2_attr) + L":" + value);
+ if (GetString16Attribute(attribute, &value)) {
+ win_attributes_->ia2_attributes.push_back(
+ base::ASCIIToUTF16(ia2_attr) + L":" + value);
+ }
}
void BrowserAccessibilityWin::BoolAttributeToIA2(
@@ -3238,8 +3616,9 @@ void BrowserAccessibilityWin::BoolAttributeToIA2(
const char* ia2_attr) {
bool value;
if (GetBoolAttribute(attribute, &value)) {
- ia2_attributes_.push_back((base::ASCIIToUTF16(ia2_attr) + L":") +
- (value ? L"true" : L"false"));
+ win_attributes_->ia2_attributes.push_back(
+ (base::ASCIIToUTF16(ia2_attr) + L":") +
+ (value ? L"true" : L"false"));
}
}
@@ -3248,14 +3627,28 @@ void BrowserAccessibilityWin::IntAttributeToIA2(
const char* ia2_attr) {
int value;
if (GetIntAttribute(attribute, &value)) {
- ia2_attributes_.push_back(base::ASCIIToUTF16(ia2_attr) + L":" +
- base::IntToString16(value));
+ win_attributes_->ia2_attributes.push_back(
+ base::ASCIIToUTF16(ia2_attr) + L":" +
+ base::IntToString16(value));
+ }
+}
+
+base::string16 BrowserAccessibilityWin::GetNameRecursive() const {
+ if (!name().empty()) {
+ return name();
+ }
+
+ base::string16 result;
+ for (uint32 i = 0; i < PlatformChildCount(); ++i) {
+ result += PlatformGetChild(i)->ToBrowserAccessibilityWin()->
+ GetNameRecursive();
}
+ return result;
}
base::string16 BrowserAccessibilityWin::GetValueText() {
float fval;
- base::string16 value = base::UTF8ToUTF16(this->value());
+ base::string16 value = this->value();
if (value.empty() &&
GetFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE, &fval)) {
@@ -3265,10 +3658,78 @@ base::string16 BrowserAccessibilityWin::GetValueText() {
}
base::string16 BrowserAccessibilityWin::TextForIAccessibleText() {
- if (IsEditableText())
- return base::UTF8ToUTF16(value());
- return (GetRole() == ui::AX_ROLE_STATIC_TEXT) ?
- base::UTF8ToUTF16(name()) : hypertext_;
+ if (IsEditableText() || GetRole() == ui::AX_ROLE_MENU_LIST_OPTION)
+ return value();
+ return (GetRole() == ui::AX_ROLE_STATIC_TEXT) ? name() : hypertext();
+}
+
+bool BrowserAccessibilityWin::IsSameHypertextCharacter(size_t old_char_index,
+ size_t new_char_index) {
+ CHECK(old_win_attributes_);
+
+ // For anything other than the "embedded character", we just compare the
+ // characters directly.
+ base::char16 old_ch = old_win_attributes_->hypertext[old_char_index];
+ base::char16 new_ch = win_attributes_->hypertext[new_char_index];
+ if (old_ch != new_ch)
+ return false;
+ if (old_ch == new_ch && new_ch != kEmbeddedCharacter)
+ return true;
+
+ // If it's an embedded character, they're only identical if the child id
+ // the hyperlink points to is the same.
+ std::map<int32, int32>& old_offset_to_index =
+ old_win_attributes_->hyperlink_offset_to_index;
+ std::vector<int32>& old_hyperlinks = old_win_attributes_->hyperlinks;
+ int32 old_hyperlinks_count = static_cast<int32>(old_hyperlinks.size());
+ std::map<int32, int32>::iterator iter;
+ iter = old_offset_to_index.find(old_char_index);
+ int old_index = (iter != old_offset_to_index.end()) ? iter->second : -1;
+ int old_child_id = (old_index >= 0 && old_index < old_hyperlinks_count) ?
+ old_hyperlinks[old_index] : -1;
+
+ std::map<int32, int32>& new_offset_to_index =
+ win_attributes_->hyperlink_offset_to_index;
+ std::vector<int32>& new_hyperlinks = win_attributes_->hyperlinks;
+ int32 new_hyperlinks_count = static_cast<int32>(new_hyperlinks.size());
+ iter = new_offset_to_index.find(new_char_index);
+ int new_index = (iter != new_offset_to_index.end()) ? iter->second : -1;
+ int new_child_id = (new_index >= 0 && new_index < new_hyperlinks_count) ?
+ new_hyperlinks[new_index] : -1;
+
+ return old_child_id == new_child_id;
+}
+
+void BrowserAccessibilityWin::ComputeHypertextRemovedAndInserted(
+ int* start, int* old_len, int* new_len) {
+ CHECK(old_win_attributes_);
+
+ *start = 0;
+ *old_len = 0;
+ *new_len = 0;
+
+ const base::string16& old_text = old_win_attributes_->hypertext;
+ const base::string16& new_text = hypertext();
+
+ size_t common_prefix = 0;
+ while (common_prefix < old_text.size() &&
+ common_prefix < new_text.size() &&
+ IsSameHypertextCharacter(common_prefix, common_prefix)) {
+ ++common_prefix;
+ }
+
+ size_t common_suffix = 0;
+ while (common_prefix + common_suffix < old_text.size() &&
+ common_prefix + common_suffix < new_text.size() &&
+ IsSameHypertextCharacter(
+ old_text.size() - common_suffix - 1,
+ new_text.size() - common_suffix - 1)) {
+ ++common_suffix;
+ }
+
+ *start = common_prefix;
+ *old_len = old_text.size() - common_prefix - common_suffix;
+ *new_len = new_text.size() - common_prefix - common_suffix;
}
void BrowserAccessibilityWin::HandleSpecialTextOffset(
@@ -3283,16 +3744,22 @@ void BrowserAccessibilityWin::HandleSpecialTextOffset(
ui::TextBoundaryType BrowserAccessibilityWin::IA2TextBoundaryToTextBoundary(
IA2TextBoundaryType ia2_boundary) {
switch(ia2_boundary) {
- case IA2_TEXT_BOUNDARY_CHAR: return ui::CHAR_BOUNDARY;
- case IA2_TEXT_BOUNDARY_WORD: return ui::WORD_BOUNDARY;
- case IA2_TEXT_BOUNDARY_LINE: return ui::LINE_BOUNDARY;
- case IA2_TEXT_BOUNDARY_SENTENCE: return ui::SENTENCE_BOUNDARY;
- case IA2_TEXT_BOUNDARY_PARAGRAPH: return ui::PARAGRAPH_BOUNDARY;
- case IA2_TEXT_BOUNDARY_ALL: return ui::ALL_BOUNDARY;
+ case IA2_TEXT_BOUNDARY_CHAR:
+ return ui::CHAR_BOUNDARY;
+ case IA2_TEXT_BOUNDARY_WORD:
+ return ui::WORD_BOUNDARY;
+ case IA2_TEXT_BOUNDARY_LINE:
+ return ui::LINE_BOUNDARY;
+ case IA2_TEXT_BOUNDARY_SENTENCE:
+ return ui::SENTENCE_BOUNDARY;
+ case IA2_TEXT_BOUNDARY_PARAGRAPH:
+ return ui::PARAGRAPH_BOUNDARY;
+ case IA2_TEXT_BOUNDARY_ALL:
+ return ui::ALL_BOUNDARY;
default:
NOTREACHED();
- return ui::CHAR_BOUNDARY;
}
+ return ui::CHAR_BOUNDARY;
}
LONG BrowserAccessibilityWin::FindBoundary(
@@ -3301,6 +3768,11 @@ LONG BrowserAccessibilityWin::FindBoundary(
LONG start_offset,
ui::TextBoundaryDirection direction) {
HandleSpecialTextOffset(text, &start_offset);
+ if (ia2_boundary == IA2_TEXT_BOUNDARY_WORD &&
+ GetRole() == ui::AX_ROLE_TEXT_FIELD) {
+ return GetWordStartBoundary(static_cast<int>(start_offset), direction);
+ }
+
ui::TextBoundaryType boundary = IA2TextBoundaryToTextBoundary(ia2_boundary);
const std::vector<int32>& line_breaks = GetIntListAttribute(
ui::AX_ATTR_LINE_BREAKS);
@@ -3312,531 +3784,543 @@ BrowserAccessibilityWin* BrowserAccessibilityWin::GetFromID(int32 id) {
return manager()->GetFromID(id)->ToBrowserAccessibilityWin();
}
+bool BrowserAccessibilityWin::IsListBoxOptionOrMenuListOption() {
+ if (!GetParent())
+ return false;
+
+ int32 role = GetRole();
+ int32 parent_role = GetParent()->GetRole();
+
+ if (role == ui::AX_ROLE_LIST_BOX_OPTION &&
+ parent_role == ui::AX_ROLE_LIST_BOX) {
+ return true;
+ }
+
+ if (role == ui::AX_ROLE_MENU_LIST_OPTION &&
+ parent_role == ui::AX_ROLE_MENU_LIST_POPUP) {
+ return true;
+ }
+
+ return false;
+}
+
void BrowserAccessibilityWin::InitRoleAndState() {
- ia_state_ = 0;
- ia2_state_ = IA2_STATE_OPAQUE;
- ia2_attributes_.clear();
+ int32 ia_role = 0;
+ int32 ia_state = 0;
+ base::string16 role_name;
+ int32 ia2_role = 0;
+ int32 ia2_state = IA2_STATE_OPAQUE;
if (HasState(ui::AX_STATE_BUSY))
- ia_state_ |= STATE_SYSTEM_BUSY;
+ ia_state |= STATE_SYSTEM_BUSY;
if (HasState(ui::AX_STATE_CHECKED))
- ia_state_ |= STATE_SYSTEM_CHECKED;
+ ia_state |= STATE_SYSTEM_CHECKED;
if (HasState(ui::AX_STATE_COLLAPSED))
- ia_state_ |= STATE_SYSTEM_COLLAPSED;
+ ia_state |= STATE_SYSTEM_COLLAPSED;
if (HasState(ui::AX_STATE_EXPANDED))
- ia_state_ |= STATE_SYSTEM_EXPANDED;
+ ia_state |= STATE_SYSTEM_EXPANDED;
if (HasState(ui::AX_STATE_FOCUSABLE))
- ia_state_ |= STATE_SYSTEM_FOCUSABLE;
+ ia_state |= STATE_SYSTEM_FOCUSABLE;
if (HasState(ui::AX_STATE_HASPOPUP))
- ia_state_ |= STATE_SYSTEM_HASPOPUP;
- if (HasState(ui::AX_STATE_HOVERED))
- ia_state_ |= STATE_SYSTEM_HOTTRACKED;
+ ia_state |= STATE_SYSTEM_HASPOPUP;
if (HasState(ui::AX_STATE_INDETERMINATE))
- ia_state_ |= STATE_SYSTEM_INDETERMINATE;
+ ia_state |= STATE_SYSTEM_INDETERMINATE;
+ if (HasIntAttribute(ui::AX_ATTR_INVALID_STATE) &&
+ GetIntAttribute(ui::AX_ATTR_INVALID_STATE) != ui::AX_INVALID_STATE_FALSE)
+ ia2_state |= IA2_STATE_INVALID_ENTRY;
if (HasState(ui::AX_STATE_INVISIBLE))
- ia_state_ |= STATE_SYSTEM_INVISIBLE;
+ ia_state |= STATE_SYSTEM_INVISIBLE;
if (HasState(ui::AX_STATE_LINKED))
- ia_state_ |= STATE_SYSTEM_LINKED;
+ ia_state |= STATE_SYSTEM_LINKED;
if (HasState(ui::AX_STATE_MULTISELECTABLE)) {
- ia_state_ |= STATE_SYSTEM_EXTSELECTABLE;
- ia_state_ |= STATE_SYSTEM_MULTISELECTABLE;
+ ia_state |= STATE_SYSTEM_EXTSELECTABLE;
+ ia_state |= STATE_SYSTEM_MULTISELECTABLE;
}
// TODO(ctguil): Support STATE_SYSTEM_EXTSELECTABLE/accSelect.
if (HasState(ui::AX_STATE_OFFSCREEN))
- ia_state_ |= STATE_SYSTEM_OFFSCREEN;
+ ia_state |= STATE_SYSTEM_OFFSCREEN;
if (HasState(ui::AX_STATE_PRESSED))
- ia_state_ |= STATE_SYSTEM_PRESSED;
+ ia_state |= STATE_SYSTEM_PRESSED;
if (HasState(ui::AX_STATE_PROTECTED))
- ia_state_ |= STATE_SYSTEM_PROTECTED;
+ ia_state |= STATE_SYSTEM_PROTECTED;
if (HasState(ui::AX_STATE_REQUIRED))
- ia2_state_ |= IA2_STATE_REQUIRED;
+ ia2_state |= IA2_STATE_REQUIRED;
if (HasState(ui::AX_STATE_SELECTABLE))
- ia_state_ |= STATE_SYSTEM_SELECTABLE;
+ ia_state |= STATE_SYSTEM_SELECTABLE;
if (HasState(ui::AX_STATE_SELECTED))
- ia_state_ |= STATE_SYSTEM_SELECTED;
+ ia_state |= STATE_SYSTEM_SELECTED;
if (HasState(ui::AX_STATE_VISITED))
- ia_state_ |= STATE_SYSTEM_TRAVERSED;
+ ia_state |= STATE_SYSTEM_TRAVERSED;
if (!HasState(ui::AX_STATE_ENABLED))
- ia_state_ |= STATE_SYSTEM_UNAVAILABLE;
- if (HasState(ui::AX_STATE_VERTICAL)) {
- ia2_state_ |= IA2_STATE_VERTICAL;
- } else {
- ia2_state_ |= IA2_STATE_HORIZONTAL;
- }
+ ia_state |= STATE_SYSTEM_UNAVAILABLE;
+ if (HasState(ui::AX_STATE_VERTICAL))
+ ia2_state |= IA2_STATE_VERTICAL;
+ if (HasState(ui::AX_STATE_HORIZONTAL))
+ ia2_state |= IA2_STATE_HORIZONTAL;
if (HasState(ui::AX_STATE_VISITED))
- ia_state_ |= STATE_SYSTEM_TRAVERSED;
+ ia_state |= STATE_SYSTEM_TRAVERSED;
+
+ // Expose whether or not the mouse is over an element, but suppress
+ // this for tests because it can make the test results flaky depending
+ // on the position of the mouse.
+ BrowserAccessibilityStateImpl* accessibility_state =
+ BrowserAccessibilityStateImpl::GetInstance();
+ if (!accessibility_state->disable_hot_tracking_for_testing()) {
+ if (HasState(ui::AX_STATE_HOVERED))
+ ia_state |= STATE_SYSTEM_HOTTRACKED;
+ }
// WebKit marks everything as readonly unless it's editable text, so if it's
// not readonly, mark it as editable now. The final computation of the
// READONLY state for MSAA is below, after the switch.
if (!HasState(ui::AX_STATE_READ_ONLY))
- ia2_state_ |= IA2_STATE_EDITABLE;
-
- base::string16 invalid;
- if (GetHtmlAttribute("aria-invalid", &invalid))
- ia2_state_ |= IA2_STATE_INVALID_ENTRY;
+ ia2_state |= IA2_STATE_EDITABLE;
if (GetBoolAttribute(ui::AX_ATTR_BUTTON_MIXED))
- ia_state_ |= STATE_SYSTEM_MIXED;
+ ia_state |= STATE_SYSTEM_MIXED;
if (GetBoolAttribute(ui::AX_ATTR_CAN_SET_VALUE))
- ia2_state_ |= IA2_STATE_EDITABLE;
+ ia2_state |= IA2_STATE_EDITABLE;
+
+ if (!GetStringAttribute(ui::AX_ATTR_AUTO_COMPLETE).empty())
+ ia2_state |= IA2_STATE_SUPPORTS_AUTOCOMPLETION;
base::string16 html_tag = GetString16Attribute(
ui::AX_ATTR_HTML_TAG);
- ia_role_ = 0;
- ia2_role_ = 0;
switch (GetRole()) {
case ui::AX_ROLE_ALERT:
- ia_role_ = ROLE_SYSTEM_ALERT;
+ ia_role = ROLE_SYSTEM_ALERT;
break;
case ui::AX_ROLE_ALERT_DIALOG:
- ia_role_ = ROLE_SYSTEM_DIALOG;
+ ia_role = ROLE_SYSTEM_DIALOG;
break;
case ui::AX_ROLE_APPLICATION:
- ia_role_ = ROLE_SYSTEM_APPLICATION;
+ ia_role = ROLE_SYSTEM_APPLICATION;
break;
case ui::AX_ROLE_ARTICLE:
- ia_role_ = ROLE_SYSTEM_DOCUMENT;
- ia_state_ |= STATE_SYSTEM_READONLY;
+ 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;
+ 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;
+ role_name = html_tag;
+ ia2_role = IA2_ROLE_SECTION;
break;
case ui::AX_ROLE_BUSY_INDICATOR:
- ia_role_ = ROLE_SYSTEM_ANIMATION;
- ia_state_ |= STATE_SYSTEM_READONLY;
+ ia_role = ROLE_SYSTEM_ANIMATION;
+ ia_state |= STATE_SYSTEM_READONLY;
break;
case ui::AX_ROLE_BUTTON:
- ia_role_ = ROLE_SYSTEM_PUSHBUTTON;
- bool is_aria_pressed_defined;
- bool is_mixed;
- if (GetAriaTristate("aria-pressed", &is_aria_pressed_defined, &is_mixed))
- ia_state_ |= STATE_SYSTEM_PRESSED;
- if (is_aria_pressed_defined)
- ia2_role_ = IA2_ROLE_TOGGLE_BUTTON;
- if (is_mixed)
- ia_state_ |= STATE_SYSTEM_MIXED;
+ ia_role = ROLE_SYSTEM_PUSHBUTTON;
break;
case ui::AX_ROLE_CANVAS:
if (GetBoolAttribute(ui::AX_ATTR_CANVAS_HAS_FALLBACK)) {
- role_name_ = L"canvas";
- ia2_role_ = IA2_ROLE_CANVAS;
+ role_name = L"canvas";
+ ia2_role = IA2_ROLE_CANVAS;
} else {
- ia_role_ = ROLE_SYSTEM_GRAPHIC;
+ ia_role = ROLE_SYSTEM_GRAPHIC;
}
break;
+ case ui::AX_ROLE_CAPTION:
+ ia_role = ROLE_SYSTEM_TEXT;
+ ia2_role = IA2_ROLE_CAPTION;
+ break;
case ui::AX_ROLE_CELL:
- ia_role_ = ROLE_SYSTEM_CELL;
+ ia_role = ROLE_SYSTEM_CELL;
break;
case ui::AX_ROLE_CHECK_BOX:
- ia_role_ = ROLE_SYSTEM_CHECKBUTTON;
- ia2_state_ |= IA2_STATE_CHECKABLE;
+ ia_role = ROLE_SYSTEM_CHECKBUTTON;
+ ia2_state |= IA2_STATE_CHECKABLE;
break;
case ui::AX_ROLE_COLOR_WELL:
- ia_role_ = ROLE_SYSTEM_CLIENT;
- ia2_role_ = IA2_ROLE_COLOR_CHOOSER;
+ ia_role = ROLE_SYSTEM_TEXT;
+ ia2_role = IA2_ROLE_COLOR_CHOOSER;
break;
case ui::AX_ROLE_COLUMN:
- ia_role_ = ROLE_SYSTEM_COLUMN;
+ ia_role = ROLE_SYSTEM_COLUMN;
break;
case ui::AX_ROLE_COLUMN_HEADER:
- ia_role_ = ROLE_SYSTEM_COLUMNHEADER;
+ ia_role = ROLE_SYSTEM_COLUMNHEADER;
break;
case ui::AX_ROLE_COMBO_BOX:
- ia_role_ = ROLE_SYSTEM_COMBOBOX;
+ ia_role = ROLE_SYSTEM_COMBOBOX;
break;
case ui::AX_ROLE_COMPLEMENTARY:
- ia_role_ = ROLE_SYSTEM_GROUPING;
- ia2_role_ = IA2_ROLE_NOTE;
+ 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;
+ 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;
+ 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;
+ role_name = L"div";
+ ia_role = ROLE_SYSTEM_GROUPING;
+ ia2_role = IA2_ROLE_SECTION;
break;
case ui::AX_ROLE_DEFINITION:
- role_name_ = html_tag;
- ia2_role_ = IA2_ROLE_PARAGRAPH;
- ia_state_ |= STATE_SYSTEM_READONLY;
+ role_name = html_tag;
+ ia2_role = IA2_ROLE_PARAGRAPH;
+ ia_state |= STATE_SYSTEM_READONLY;
break;
case ui::AX_ROLE_DESCRIPTION_LIST_DETAIL:
- role_name_ = html_tag;
- ia2_role_ = IA2_ROLE_PARAGRAPH;
- ia_state_ |= STATE_SYSTEM_READONLY;
+ role_name = html_tag;
+ ia_role = ROLE_SYSTEM_TEXT;
+ ia2_role = IA2_ROLE_PARAGRAPH;
break;
case ui::AX_ROLE_DESCRIPTION_LIST:
- role_name_ = html_tag;
- ia_role_ = ROLE_SYSTEM_LIST;
- ia_state_ |= STATE_SYSTEM_READONLY;
+ 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;
+ 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;
+ role_name = html_tag;
+ ia_role = ROLE_SYSTEM_GROUPING;
break;
case ui::AX_ROLE_DIALOG:
- ia_role_ = ROLE_SYSTEM_DIALOG;
+ ia_role = ROLE_SYSTEM_DIALOG;
break;
case ui::AX_ROLE_DISCLOSURE_TRIANGLE:
- ia_role_ = ROLE_SYSTEM_PUSHBUTTON;
+ ia_role = ROLE_SYSTEM_PUSHBUTTON;
break;
case ui::AX_ROLE_DOCUMENT:
case ui::AX_ROLE_ROOT_WEB_AREA:
case ui::AX_ROLE_WEB_AREA:
- ia_role_ = ROLE_SYSTEM_DOCUMENT;
- ia_state_ |= STATE_SYSTEM_READONLY;
- ia_state_ |= STATE_SYSTEM_FOCUSABLE;
+ ia_role = ROLE_SYSTEM_DOCUMENT;
+ ia_state |= STATE_SYSTEM_READONLY;
+ ia_state |= STATE_SYSTEM_FOCUSABLE;
break;
- case ui::AX_ROLE_EDITABLE_TEXT:
- ia_role_ = ROLE_SYSTEM_TEXT;
- ia2_state_ |= IA2_STATE_SINGLE_LINE;
- ia2_state_ |= IA2_STATE_EDITABLE;
+ case ui::AX_ROLE_EMBEDDED_OBJECT:
+ ia_role = ROLE_SYSTEM_CLIENT;
+ ia2_role = IA2_ROLE_EMBEDDED_OBJECT;
break;
case ui::AX_ROLE_FIGCAPTION:
- role_name_ = html_tag;
- ia2_role_ = IA2_ROLE_CAPTION;
+ 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;
+ ia_role = ROLE_SYSTEM_GROUPING;
break;
case ui::AX_ROLE_FORM:
- role_name_ = L"form";
- ia2_role_ = IA2_ROLE_FORM;
+ role_name = L"form";
+ ia2_role = IA2_ROLE_FORM;
break;
case ui::AX_ROLE_FOOTER:
- ia_role_ = IA2_ROLE_FOOTER;
- ia_state_ |= STATE_SYSTEM_READONLY;
+ ia_role = ROLE_SYSTEM_GROUPING;
+ ia2_role = IA2_ROLE_FOOTER;
break;
case ui::AX_ROLE_GRID:
- ia_role_ = ROLE_SYSTEM_TABLE;
- ia_state_ |= STATE_SYSTEM_READONLY;
+ ia_role = ROLE_SYSTEM_TABLE;
+ ia_state |= STATE_SYSTEM_READONLY;
break;
case ui::AX_ROLE_GROUP: {
base::string16 aria_role = GetString16Attribute(
ui::AX_ATTR_ROLE);
if (aria_role == L"group" || html_tag == L"fieldset") {
- ia_role_ = ROLE_SYSTEM_GROUPING;
+ ia_role = ROLE_SYSTEM_GROUPING;
} else if (html_tag == L"li") {
- ia_role_ = ROLE_SYSTEM_LISTITEM;
- ia_state_ |= STATE_SYSTEM_READONLY;
+ ia_role = ROLE_SYSTEM_LISTITEM;
+ ia_state |= STATE_SYSTEM_READONLY;
} else {
if (html_tag.empty())
- role_name_ = L"div";
+ role_name = L"div";
else
- role_name_ = html_tag;
- ia2_role_ = IA2_ROLE_SECTION;
+ role_name = html_tag;
+ ia2_role = IA2_ROLE_SECTION;
}
break;
}
- case ui::AX_ROLE_GROW_AREA:
- ia_role_ = ROLE_SYSTEM_GRIP;
- ia_state_ |= STATE_SYSTEM_READONLY;
- break;
case ui::AX_ROLE_HEADING:
- role_name_ = html_tag;
- ia2_role_ = IA2_ROLE_HEADING;
- break;
- case ui::AX_ROLE_HORIZONTAL_RULE:
- ia_role_ = ROLE_SYSTEM_SEPARATOR;
+ role_name = html_tag;
+ ia2_role = IA2_ROLE_HEADING;
break;
case ui::AX_ROLE_IFRAME:
- ia_role_ = ROLE_SYSTEM_DOCUMENT;
- ia2_role_ = IA2_ROLE_INTERNAL_FRAME;
- ia_state_ = STATE_SYSTEM_READONLY;
+ ia_role = ROLE_SYSTEM_DOCUMENT;
+ ia2_role = IA2_ROLE_INTERNAL_FRAME;
+ ia_state = STATE_SYSTEM_READONLY;
+ break;
+ case ui::AX_ROLE_IFRAME_PRESENTATIONAL:
+ ia_role = ROLE_SYSTEM_GROUPING;
break;
case ui::AX_ROLE_IMAGE:
- ia_role_ = ROLE_SYSTEM_GRAPHIC;
- ia_state_ |= STATE_SYSTEM_READONLY;
+ ia_role = ROLE_SYSTEM_GRAPHIC;
+ ia_state |= STATE_SYSTEM_READONLY;
break;
case ui::AX_ROLE_IMAGE_MAP:
- role_name_ = html_tag;
- ia2_role_ = IA2_ROLE_IMAGE_MAP;
- ia_state_ |= STATE_SYSTEM_READONLY;
+ role_name = html_tag;
+ ia2_role = IA2_ROLE_IMAGE_MAP;
+ ia_state |= STATE_SYSTEM_READONLY;
break;
case ui::AX_ROLE_IMAGE_MAP_LINK:
- ia_role_ = ROLE_SYSTEM_LINK;
- ia_state_ |= STATE_SYSTEM_LINKED;
- ia_state_ |= STATE_SYSTEM_READONLY;
+ ia_role = ROLE_SYSTEM_LINK;
+ ia_state |= STATE_SYSTEM_LINKED;
+ ia_state |= STATE_SYSTEM_READONLY;
break;
case ui::AX_ROLE_LABEL_TEXT:
- ia_role_ = ROLE_SYSTEM_TEXT;
- ia2_role_ = IA2_ROLE_LABEL;
- break;
- case ui::AX_ROLE_SEARCH:
- ia_role_ = ROLE_SYSTEM_GROUPING;
- ia2_role_ = IA2_ROLE_SECTION;
+ case ui::AX_ROLE_LEGEND:
+ ia_role = ROLE_SYSTEM_TEXT;
+ ia2_role = IA2_ROLE_LABEL;
break;
case ui::AX_ROLE_LINK:
- ia_role_ = ROLE_SYSTEM_LINK;
- ia_state_ |= STATE_SYSTEM_LINKED;
+ ia_role = ROLE_SYSTEM_LINK;
+ ia_state |= STATE_SYSTEM_LINKED;
break;
case ui::AX_ROLE_LIST:
- ia_role_ = ROLE_SYSTEM_LIST;
- ia_state_ |= STATE_SYSTEM_READONLY;
+ ia_role = ROLE_SYSTEM_LIST;
+ ia_state |= STATE_SYSTEM_READONLY;
break;
case ui::AX_ROLE_LIST_BOX:
- ia_role_ = ROLE_SYSTEM_LIST;
+ ia_role = ROLE_SYSTEM_LIST;
break;
case ui::AX_ROLE_LIST_BOX_OPTION:
- ia_role_ = ROLE_SYSTEM_LISTITEM;
- if (ia_state_ & STATE_SYSTEM_SELECTABLE) {
- ia_state_ |= STATE_SYSTEM_FOCUSABLE;
+ ia_role = ROLE_SYSTEM_LISTITEM;
+ if (ia_state & STATE_SYSTEM_SELECTABLE) {
+ ia_state |= STATE_SYSTEM_FOCUSABLE;
if (HasState(ui::AX_STATE_FOCUSED))
- ia_state_ |= STATE_SYSTEM_FOCUSED;
+ ia_state |= STATE_SYSTEM_FOCUSED;
}
break;
case ui::AX_ROLE_LIST_ITEM:
- ia_role_ = ROLE_SYSTEM_LISTITEM;
- ia_state_ |= STATE_SYSTEM_READONLY;
+ ia_role = ROLE_SYSTEM_LISTITEM;
+ ia_state |= STATE_SYSTEM_READONLY;
break;
case ui::AX_ROLE_MAIN:
- ia_role_ = ROLE_SYSTEM_GROUPING;
- ia2_role_ = IA2_ROLE_PARAGRAPH;
+ ia_role = ROLE_SYSTEM_GROUPING;
+ ia2_role = IA2_ROLE_PARAGRAPH;
break;
case ui::AX_ROLE_MARQUEE:
- ia_role_ = ROLE_SYSTEM_ANIMATION;
+ ia_role = ROLE_SYSTEM_ANIMATION;
break;
case ui::AX_ROLE_MATH:
- ia_role_ = ROLE_SYSTEM_EQUATION;
+ ia_role = ROLE_SYSTEM_EQUATION;
break;
case ui::AX_ROLE_MENU:
case ui::AX_ROLE_MENU_BUTTON:
- ia_role_ = ROLE_SYSTEM_MENUPOPUP;
+ ia_role = ROLE_SYSTEM_MENUPOPUP;
break;
case ui::AX_ROLE_MENU_BAR:
- ia_role_ = ROLE_SYSTEM_MENUBAR;
+ ia_role = ROLE_SYSTEM_MENUBAR;
break;
case ui::AX_ROLE_MENU_ITEM:
- ia_role_ = ROLE_SYSTEM_MENUITEM;
+ 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;
+ 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;
+ 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;
+ ia_role = ROLE_SYSTEM_LIST;
+ ia2_state &= ~(IA2_STATE_EDITABLE);
break;
case ui::AX_ROLE_MENU_LIST_OPTION:
- ia_role_ = ROLE_SYSTEM_LISTITEM;
- if (ia_state_ & STATE_SYSTEM_SELECTABLE) {
- ia_state_ |= STATE_SYSTEM_FOCUSABLE;
+ ia_role = ROLE_SYSTEM_LISTITEM;
+ ia2_state &= ~(IA2_STATE_EDITABLE);
+ if (ia_state & STATE_SYSTEM_SELECTABLE) {
+ ia_state |= STATE_SYSTEM_FOCUSABLE;
if (HasState(ui::AX_STATE_FOCUSED))
- ia_state_ |= STATE_SYSTEM_FOCUSED;
+ ia_state |= STATE_SYSTEM_FOCUSED;
}
break;
case ui::AX_ROLE_METER:
- role_name_ = html_tag;
- ia_role_ = ROLE_SYSTEM_PROGRESSBAR;
+ 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;
+ 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;
- ia_state_ |= STATE_SYSTEM_READONLY;
+ ia_role = ROLE_SYSTEM_GROUPING;
+ ia2_role = IA2_ROLE_NOTE;
break;
case ui::AX_ROLE_OUTLINE:
- ia_role_ = ROLE_SYSTEM_OUTLINE;
+ ia_role = ROLE_SYSTEM_OUTLINE;
break;
case ui::AX_ROLE_PARAGRAPH:
- role_name_ = L"P";
- ia2_role_ = IA2_ROLE_PARAGRAPH;
+ role_name = L"P";
+ ia2_role = IA2_ROLE_PARAGRAPH;
break;
case ui::AX_ROLE_POP_UP_BUTTON:
if (html_tag == L"select") {
- ia_role_ = ROLE_SYSTEM_COMBOBOX;
+ ia_role = ROLE_SYSTEM_COMBOBOX;
} else {
- ia_role_ = ROLE_SYSTEM_BUTTONMENU;
+ 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;
+ 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;
+ ia_role = ROLE_SYSTEM_PROGRESSBAR;
+ ia_state |= STATE_SYSTEM_READONLY;
break;
case ui::AX_ROLE_RADIO_BUTTON:
- ia_role_ = ROLE_SYSTEM_RADIOBUTTON;
+ ia_role = ROLE_SYSTEM_RADIOBUTTON;
+ ia2_state = IA2_STATE_CHECKABLE;
break;
case ui::AX_ROLE_RADIO_GROUP:
- ia_role_ = ROLE_SYSTEM_GROUPING;
+ ia_role = ROLE_SYSTEM_GROUPING;
break;
case ui::AX_ROLE_REGION:
if (html_tag == L"section") {
- ia_role_ = ROLE_SYSTEM_GROUPING;
- ia2_role_ = IA2_ROLE_SECTION;
+ ia_role = ROLE_SYSTEM_GROUPING;
+ ia2_role = IA2_ROLE_SECTION;
} else {
- ia_role_ = ROLE_SYSTEM_PANE;
+ ia_role = ROLE_SYSTEM_PANE;
}
break;
case ui::AX_ROLE_ROW:
- ia_role_ = ROLE_SYSTEM_ROW;
+ ia_role = ROLE_SYSTEM_ROW;
break;
case ui::AX_ROLE_ROW_HEADER:
- ia_role_ = ROLE_SYSTEM_ROWHEADER;
+ ia_role = ROLE_SYSTEM_ROWHEADER;
+ break;
+ case ui::AX_ROLE_RUBY:
+ ia_role = ROLE_SYSTEM_TEXT;
+ ia2_role = IA2_ROLE_TEXT_FRAME;
break;
case ui::AX_ROLE_RULER:
- ia_role_ = ROLE_SYSTEM_CLIENT;
- ia2_role_ = IA2_ROLE_RULER;
- ia_state_ |= STATE_SYSTEM_READONLY;
+ ia_role = ROLE_SYSTEM_CLIENT;
+ ia2_role = IA2_ROLE_RULER;
+ ia_state |= STATE_SYSTEM_READONLY;
break;
case ui::AX_ROLE_SCROLL_AREA:
- ia_role_ = ROLE_SYSTEM_CLIENT;
- ia2_role_ = IA2_ROLE_SCROLL_PANE;
- ia_state_ |= STATE_SYSTEM_READONLY;
- ia2_state_ &= ~(IA2_STATE_EDITABLE);
+ ia_role = ROLE_SYSTEM_CLIENT;
+ ia2_role = IA2_ROLE_SCROLL_PANE;
+ ia_state |= STATE_SYSTEM_READONLY;
+ ia2_state &= ~(IA2_STATE_EDITABLE);
break;
case ui::AX_ROLE_SCROLL_BAR:
- ia_role_ = ROLE_SYSTEM_SCROLLBAR;
+ ia_role = ROLE_SYSTEM_SCROLLBAR;
+ break;
+ case ui::AX_ROLE_SEARCH:
+ ia_role = ROLE_SYSTEM_GROUPING;
+ ia2_role = IA2_ROLE_SECTION;
break;
case ui::AX_ROLE_SLIDER:
- ia_role_ = ROLE_SYSTEM_SLIDER;
+ ia_role = ROLE_SYSTEM_SLIDER;
break;
case ui::AX_ROLE_SPIN_BUTTON:
- ia_role_ = ROLE_SYSTEM_SPINBUTTON;
+ ia_role = ROLE_SYSTEM_SPINBUTTON;
break;
case ui::AX_ROLE_SPIN_BUTTON_PART:
- ia_role_ = ROLE_SYSTEM_PUSHBUTTON;
- break;
- case ui::AX_ROLE_SPLIT_GROUP:
- ia_role_ = ROLE_SYSTEM_CLIENT;
- ia2_role_ = IA2_ROLE_SPLIT_PANE;
- ia_state_ |= STATE_SYSTEM_READONLY;
+ ia_role = ROLE_SYSTEM_PUSHBUTTON;
break;
case ui::AX_ROLE_ANNOTATION:
case ui::AX_ROLE_LIST_MARKER:
case ui::AX_ROLE_STATIC_TEXT:
- ia_role_ = ROLE_SYSTEM_STATICTEXT;
+ ia_role = ROLE_SYSTEM_STATICTEXT;
break;
case ui::AX_ROLE_STATUS:
- ia_role_ = ROLE_SYSTEM_STATUSBAR;
- ia_state_ |= STATE_SYSTEM_READONLY;
+ ia_role = ROLE_SYSTEM_STATUSBAR;
break;
case ui::AX_ROLE_SPLITTER:
- ia_role_ = ROLE_SYSTEM_SEPARATOR;
+ ia_role = ROLE_SYSTEM_SEPARATOR;
break;
case ui::AX_ROLE_SVG_ROOT:
- ia_role_ = ROLE_SYSTEM_GRAPHIC;
+ ia_role = ROLE_SYSTEM_GRAPHIC;
+ break;
+ case ui::AX_ROLE_SWITCH:
+ role_name = L"switch";
+ ia2_role = IA2_ROLE_TOGGLE_BUTTON;
break;
case ui::AX_ROLE_TAB:
- ia_role_ = ROLE_SYSTEM_PAGETAB;
+ ia_role = ROLE_SYSTEM_PAGETAB;
break;
case ui::AX_ROLE_TABLE: {
base::string16 aria_role = GetString16Attribute(
ui::AX_ATTR_ROLE);
if (aria_role == L"treegrid") {
- ia_role_ = ROLE_SYSTEM_OUTLINE;
+ ia_role = ROLE_SYSTEM_OUTLINE;
} else {
- ia_role_ = ROLE_SYSTEM_TABLE;
+ ia_role = ROLE_SYSTEM_TABLE;
}
break;
}
case ui::AX_ROLE_TABLE_HEADER_CONTAINER:
- ia_role_ = ROLE_SYSTEM_GROUPING;
- ia2_role_ = IA2_ROLE_SECTION;
- ia_state_ |= STATE_SYSTEM_READONLY;
+ ia_role = ROLE_SYSTEM_GROUPING;
+ ia2_role = IA2_ROLE_SECTION;
+ ia_state |= STATE_SYSTEM_READONLY;
break;
case ui::AX_ROLE_TAB_LIST:
- ia_role_ = ROLE_SYSTEM_PAGETABLIST;
+ ia_role = ROLE_SYSTEM_PAGETABLIST;
break;
case ui::AX_ROLE_TAB_PANEL:
- ia_role_ = ROLE_SYSTEM_PROPERTYPAGE;
+ ia_role = ROLE_SYSTEM_PROPERTYPAGE;
break;
case ui::AX_ROLE_TOGGLE_BUTTON:
- ia_role_ = ROLE_SYSTEM_PUSHBUTTON;
- ia2_role_ = IA2_ROLE_TOGGLE_BUTTON;
- break;
- case ui::AX_ROLE_TEXT_AREA:
- ia_role_ = ROLE_SYSTEM_TEXT;
- ia2_state_ |= IA2_STATE_MULTI_LINE;
- ia2_state_ |= IA2_STATE_EDITABLE;
- ia2_state_ |= IA2_STATE_SELECTABLE_TEXT;
+ ia_role = ROLE_SYSTEM_PUSHBUTTON;
+ ia2_role = IA2_ROLE_TOGGLE_BUTTON;
break;
case ui::AX_ROLE_TEXT_FIELD:
- ia_role_ = ROLE_SYSTEM_TEXT;
- ia2_state_ |= IA2_STATE_SINGLE_LINE;
- ia2_state_ |= IA2_STATE_EDITABLE;
- ia2_state_ |= IA2_STATE_SELECTABLE_TEXT;
+ case ui::AX_ROLE_SEARCH_BOX:
+ ia_role = ROLE_SYSTEM_TEXT;
+ if (HasState(ui::AX_STATE_MULTILINE))
+ ia2_state |= IA2_STATE_MULTI_LINE;
+ else
+ ia2_state |= IA2_STATE_SINGLE_LINE;
+ ia2_state |= IA2_STATE_EDITABLE;
+ ia2_state |= IA2_STATE_SELECTABLE_TEXT;
break;
case ui::AX_ROLE_TIME:
- ia_role_ = ROLE_SYSTEM_SPINBUTTON;
+ ia_role = ROLE_SYSTEM_SPINBUTTON;
break;
case ui::AX_ROLE_TIMER:
- ia_role_ = ROLE_SYSTEM_CLOCK;
- ia_state_ |= STATE_SYSTEM_READONLY;
+ ia_role = ROLE_SYSTEM_CLOCK;
+ ia_state |= STATE_SYSTEM_READONLY;
break;
case ui::AX_ROLE_TOOLBAR:
- ia_role_ = ROLE_SYSTEM_TOOLBAR;
- ia_state_ |= STATE_SYSTEM_READONLY;
+ ia_role = ROLE_SYSTEM_TOOLBAR;
+ ia_state |= STATE_SYSTEM_READONLY;
break;
case ui::AX_ROLE_TOOLTIP:
- ia_role_ = ROLE_SYSTEM_TOOLTIP;
- ia_state_ |= STATE_SYSTEM_READONLY;
+ ia_role = ROLE_SYSTEM_TOOLTIP;
+ ia_state |= STATE_SYSTEM_READONLY;
break;
case ui::AX_ROLE_TREE:
- ia_role_ = ROLE_SYSTEM_OUTLINE;
+ ia_role = ROLE_SYSTEM_OUTLINE;
break;
case ui::AX_ROLE_TREE_GRID:
- ia_role_ = ROLE_SYSTEM_OUTLINE;
+ ia_role = ROLE_SYSTEM_OUTLINE;
break;
case ui::AX_ROLE_TREE_ITEM:
- ia_role_ = ROLE_SYSTEM_OUTLINEITEM;
+ ia_role = ROLE_SYSTEM_OUTLINEITEM;
+ break;
+ case ui::AX_ROLE_LINE_BREAK:
+ ia_role = ROLE_SYSTEM_WHITESPACE;
break;
case ui::AX_ROLE_WINDOW:
- ia_role_ = ROLE_SYSTEM_WINDOW;
+ ia_role = ROLE_SYSTEM_WINDOW;
break;
// TODO(dmazzoni): figure out the proper MSAA role for all of these.
- case ui::AX_ROLE_BROWSER:
case ui::AX_ROLE_DIRECTORY:
- case ui::AX_ROLE_DRAWER:
- case ui::AX_ROLE_HELP_TAG:
case ui::AX_ROLE_IGNORED:
- case ui::AX_ROLE_INCREMENTOR:
case ui::AX_ROLE_LOG:
- 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:
case ui::AX_ROLE_SLIDER_THUMB:
- case ui::AX_ROLE_SYSTEM_WIDE:
- case ui::AX_ROLE_VALUE_INDICATOR:
default:
- ia_role_ = ROLE_SYSTEM_CLIENT;
+ ia_role = ROLE_SYSTEM_CLIENT;
break;
}
@@ -3847,21 +4331,27 @@ void BrowserAccessibilityWin::InitRoleAndState() {
// We clear the READONLY state on focusable controls and on a document.
// Everything else, the majority of objects, do not have this state set.
if (HasState(ui::AX_STATE_FOCUSABLE) &&
- ia_role_ != ROLE_SYSTEM_DOCUMENT) {
- ia_state_ &= ~(STATE_SYSTEM_READONLY);
+ ia_role != ROLE_SYSTEM_DOCUMENT) {
+ ia_state &= ~(STATE_SYSTEM_READONLY);
}
if (!HasState(ui::AX_STATE_READ_ONLY))
- ia_state_ &= ~(STATE_SYSTEM_READONLY);
+ ia_state &= ~(STATE_SYSTEM_READONLY);
if (GetBoolAttribute(ui::AX_ATTR_ARIA_READONLY))
- ia_state_ |= STATE_SYSTEM_READONLY;
+ ia_state |= STATE_SYSTEM_READONLY;
// The role should always be set.
- DCHECK(!role_name_.empty() || ia_role_);
+ DCHECK(!role_name.empty() || ia_role);
// If we didn't explicitly set the IAccessible2 role, make it the same
// as the MSAA role.
- if (!ia2_role_)
- ia2_role_ = ia_role_;
+ if (!ia2_role)
+ ia2_role = ia_role;
+
+ win_attributes_->ia_role = ia_role;
+ win_attributes_->ia_state = ia_state;
+ win_attributes_->role_name = role_name;
+ win_attributes_->ia2_role = ia2_role;
+ win_attributes_->ia2_state = ia2_state;
}
} // namespace content
diff --git a/chromium/content/browser/accessibility/browser_accessibility_win.h b/chromium/content/browser/accessibility/browser_accessibility_win.h
index cd339d53c91..1cd7b3c2c29 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_win.h
+++ b/chromium/content/browser/accessibility/browser_accessibility_win.h
@@ -82,7 +82,7 @@ BrowserAccessibilityWin
// Represents a non-static text node in IAccessibleHypertext. This character
// is embedded in the response to IAccessibleText::get_text, indicating the
// position where a non-static text child object appears.
- CONTENT_EXPORT static const base::char16 kEmbeddedCharacter[];
+ CONTENT_EXPORT static const base::char16 kEmbeddedCharacter;
// Mappings from roles and states to human readable strings. Initialize
// with |InitializeStringMaps|.
@@ -91,21 +91,28 @@ BrowserAccessibilityWin
CONTENT_EXPORT BrowserAccessibilityWin();
- CONTENT_EXPORT virtual ~BrowserAccessibilityWin();
+ CONTENT_EXPORT ~BrowserAccessibilityWin() override;
// The Windows-specific unique ID, used as the child ID for MSAA methods
// like NotifyWinEvent, and as the unique ID for IAccessible2 and ISimpleDOM.
LONG unique_id_win() const { return unique_id_win_; }
+ // Called after an atomic tree update completes. See
+ // BrowserAccessibilityManagerWin::OnAtomicUpdateFinished for more
+ // details on what these do.
+ CONTENT_EXPORT void UpdateStep1ComputeWinAttributes();
+ CONTENT_EXPORT void UpdateStep2ComputeHypertext();
+ CONTENT_EXPORT void UpdateStep3FireEvents(bool is_subtree_creation);
+ CONTENT_EXPORT void UpdateStep4DeleteOldWinAttributes();
+
//
// 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() override;
+ CONTENT_EXPORT void OnSubtreeWillBeDeleted() override;
+ CONTENT_EXPORT void NativeAddReference() override;
+ CONTENT_EXPORT void NativeReleaseReference() override;
+ CONTENT_EXPORT bool IsNative() const override;
+ CONTENT_EXPORT void OnLocationChanged() override;
//
// IAccessible methods.
@@ -183,13 +190,9 @@ BrowserAccessibilityWin
// Deprecated methods, not implemented.
CONTENT_EXPORT STDMETHODIMP
- put_accName(VARIANT var_id, BSTR put_name) override {
- return E_NOTIMPL;
- }
+ put_accName(VARIANT var_id, BSTR put_name) override;
CONTENT_EXPORT STDMETHODIMP
- put_accValue(VARIANT var_id, BSTR put_val) override {
- return E_NOTIMPL;
- }
+ put_accValue(VARIANT var_id, BSTR put_val) override;
//
// IAccessible2 methods.
@@ -239,32 +242,20 @@ BrowserAccessibilityWin
//
// IAccessibleEx methods not implemented.
//
- CONTENT_EXPORT STDMETHODIMP get_extendedRole(BSTR* extended_role) override {
- return E_NOTIMPL;
- }
+ CONTENT_EXPORT STDMETHODIMP get_extendedRole(BSTR* extended_role) override;
CONTENT_EXPORT STDMETHODIMP
- get_localizedExtendedRole(BSTR* localized_extended_role) override {
- return E_NOTIMPL;
- }
+ get_localizedExtendedRole(BSTR* localized_extended_role) override;
CONTENT_EXPORT STDMETHODIMP
- get_nExtendedStates(LONG* n_extended_states) override {
- return E_NOTIMPL;
- }
+ get_nExtendedStates(LONG* n_extended_states) override;
CONTENT_EXPORT STDMETHODIMP
get_extendedStates(LONG max_extended_states,
BSTR** extended_states,
- LONG* n_extended_states) override {
- return E_NOTIMPL;
- }
+ LONG* n_extended_states) override;
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) override {
- return E_NOTIMPL;
- }
+ LONG* n_localized_extended_states) override;
+ CONTENT_EXPORT STDMETHODIMP get_locale(IA2Locale* locale) override;
//
// IAccessibleApplication methods.
@@ -370,24 +361,16 @@ BrowserAccessibilityWin
long* column_extents,
boolean* is_selected) override;
- CONTENT_EXPORT STDMETHODIMP selectRow(long row) override { return E_NOTIMPL; }
+ CONTENT_EXPORT STDMETHODIMP selectRow(long row) override;
- CONTENT_EXPORT STDMETHODIMP selectColumn(long column) override {
- return E_NOTIMPL;
- }
+ CONTENT_EXPORT STDMETHODIMP selectColumn(long column) override;
- CONTENT_EXPORT STDMETHODIMP unselectRow(long row) override {
- return E_NOTIMPL;
- }
+ CONTENT_EXPORT STDMETHODIMP unselectRow(long row) override;
- CONTENT_EXPORT STDMETHODIMP unselectColumn(long column) override {
- return E_NOTIMPL;
- }
+ CONTENT_EXPORT STDMETHODIMP unselectColumn(long column) override;
CONTENT_EXPORT STDMETHODIMP
- get_modelChange(IA2TableModelChange* model_change) override {
- return E_NOTIMPL;
- }
+ get_modelChange(IA2TableModelChange* model_change) override;
//
// IAccessibleTable2 methods.
@@ -525,9 +508,7 @@ BrowserAccessibilityWin
CONTENT_EXPORT STDMETHODIMP get_attributes(LONG offset,
LONG* start_offset,
LONG* end_offset,
- BSTR* text_attributes) override {
- return E_NOTIMPL;
- }
+ BSTR* text_attributes) override;
//
// IAccessibleHypertext methods.
@@ -542,47 +523,25 @@ BrowserAccessibilityWin
get_hyperlinkIndex(long char_index, long* hyperlink_index) override;
// IAccessibleHyperlink not implemented.
- CONTENT_EXPORT STDMETHODIMP get_anchor(long index, VARIANT* anchor) override {
- return E_NOTIMPL;
- }
+ CONTENT_EXPORT STDMETHODIMP get_anchor(long index, VARIANT* anchor) override;
CONTENT_EXPORT STDMETHODIMP
- get_anchorTarget(long index, VARIANT* anchor_target) override {
- return E_NOTIMPL;
- }
- CONTENT_EXPORT STDMETHODIMP get_startIndex(long* index) override {
- return E_NOTIMPL;
- }
- CONTENT_EXPORT STDMETHODIMP get_endIndex(long* index) override {
- return E_NOTIMPL;
- }
- CONTENT_EXPORT STDMETHODIMP get_valid(boolean* valid) override {
- return E_NOTIMPL;
- }
+ get_anchorTarget(long index, VARIANT* anchor_target) override;
+ CONTENT_EXPORT STDMETHODIMP get_startIndex(long* index) override;
+ CONTENT_EXPORT STDMETHODIMP get_endIndex(long* index) override;
+ CONTENT_EXPORT STDMETHODIMP get_valid(boolean* valid) override;
// IAccessibleAction not implemented.
- CONTENT_EXPORT STDMETHODIMP nActions(long* n_actions) override {
- return E_NOTIMPL;
- }
- CONTENT_EXPORT STDMETHODIMP doAction(long action_index) override {
- return E_NOTIMPL;
- }
+ CONTENT_EXPORT STDMETHODIMP nActions(long* n_actions) override;
+ CONTENT_EXPORT STDMETHODIMP doAction(long action_index) override;
CONTENT_EXPORT STDMETHODIMP
- get_description(long action_index, BSTR* description) override {
- return E_NOTIMPL;
- }
+ get_description(long action_index, BSTR* description) override;
CONTENT_EXPORT STDMETHODIMP get_keyBinding(long action_index,
long n_max_bindings,
BSTR** key_bindings,
- long* n_bindings) override {
- return E_NOTIMPL;
- }
- CONTENT_EXPORT STDMETHODIMP get_name(long action_index, BSTR* name) override {
- return E_NOTIMPL;
- }
+ long* n_bindings) override;
+ CONTENT_EXPORT STDMETHODIMP get_name(long action_index, BSTR* name) override;
CONTENT_EXPORT STDMETHODIMP
- get_localizedName(long action_index, BSTR* localized_name) override {
- return E_NOTIMPL;
- }
+ get_localizedName(long action_index, BSTR* localized_name) override;
//
// IAccessibleValue methods.
@@ -609,13 +568,9 @@ BrowserAccessibilityWin
CONTENT_EXPORT STDMETHODIMP get_docType(BSTR* doc_type) override;
CONTENT_EXPORT STDMETHODIMP
- get_nameSpaceURIForID(short name_space_id, BSTR* name_space_uri) override {
- return E_NOTIMPL;
- }
+ get_nameSpaceURIForID(short name_space_id, BSTR* name_space_uri) override;
CONTENT_EXPORT STDMETHODIMP
- put_alternateViewMediaTypes(BSTR* comma_separated_media_types) override {
- return E_NOTIMPL;
- }
+ put_alternateViewMediaTypes(BSTR* comma_separated_media_types) override;
//
// ISimpleDOMNode methods.
@@ -670,18 +625,12 @@ BrowserAccessibilityWin
CONTENT_EXPORT STDMETHODIMP
get_childAt(unsigned int child_index, ISimpleDOMNode** node) override;
- CONTENT_EXPORT STDMETHODIMP get_innerHTML(BSTR* innerHTML) override {
- return E_NOTIMPL;
- }
+ CONTENT_EXPORT STDMETHODIMP get_innerHTML(BSTR* innerHTML) override;
CONTENT_EXPORT STDMETHODIMP
- get_localInterface(void** local_interface) override {
- return E_NOTIMPL;
- }
+ get_localInterface(void** local_interface) override;
- CONTENT_EXPORT STDMETHODIMP get_language(BSTR* language) override {
- return E_NOTIMPL;
- }
+ CONTENT_EXPORT STDMETHODIMP get_language(BSTR* language) override;
//
// ISimpleDOMText methods.
@@ -708,9 +657,7 @@ BrowserAccessibilityWin
CONTENT_EXPORT STDMETHODIMP
scrollToSubstring(unsigned int start_index, unsigned int end_index) override;
- CONTENT_EXPORT STDMETHODIMP get_fontFamily(BSTR* font_family) override {
- return E_NOTIMPL;
- }
+ CONTENT_EXPORT STDMETHODIMP get_fontFamily(BSTR* font_family) override;
//
// IServiceProvider methods.
@@ -721,24 +668,16 @@ BrowserAccessibilityWin
// IAccessibleEx methods not implemented.
CONTENT_EXPORT STDMETHODIMP
- GetObjectForChild(long child_id, IAccessibleEx** ret) override {
- return E_NOTIMPL;
- }
+ GetObjectForChild(long child_id, IAccessibleEx** ret) override;
CONTENT_EXPORT STDMETHODIMP
- GetIAccessiblePair(IAccessible** acc, long* child_id) override {
- return E_NOTIMPL;
- }
+ GetIAccessiblePair(IAccessible** acc, long* child_id) override;
- CONTENT_EXPORT STDMETHODIMP GetRuntimeId(SAFEARRAY** runtime_id) override {
- return E_NOTIMPL;
- }
+ CONTENT_EXPORT STDMETHODIMP GetRuntimeId(SAFEARRAY** runtime_id) override;
CONTENT_EXPORT STDMETHODIMP
ConvertReturnedElement(IRawElementProviderSimple* element,
- IAccessibleEx** acc) override {
- return E_NOTIMPL;
- }
+ IAccessibleEx** acc) override;
//
// IRawElementProviderSimple methods.
@@ -754,14 +693,9 @@ BrowserAccessibilityWin
// IRawElementProviderSimple methods not implemented
//
CONTENT_EXPORT STDMETHODIMP
- get_ProviderOptions(enum ProviderOptions* ret) override {
- return E_NOTIMPL;
- }
-
+ get_ProviderOptions(enum ProviderOptions* ret) override;
CONTENT_EXPORT STDMETHODIMP
- get_HostRawElementProvider(IRawElementProviderSimple** provider) override {
- return E_NOTIMPL;
- }
+ get_HostRawElementProvider(IRawElementProviderSimple** provider) override;
//
// CComObjectRootEx methods.
@@ -775,14 +709,23 @@ BrowserAccessibilityWin
void** object);
// Accessors.
- int32 ia_role() const { return ia_role_; }
- int32 ia_state() const { return ia_state_; }
- const base::string16& role_name() const { return role_name_; }
- int32 ia2_role() const { return ia2_role_; }
- int32 ia2_state() const { return ia2_state_; }
+ int32 ia_role() const { return win_attributes_->ia_role; }
+ int32 ia_state() const { return win_attributes_->ia_state; }
+ const base::string16& role_name() const { return win_attributes_->role_name; }
+ int32 ia2_role() const { return win_attributes_->ia2_role; }
+ int32 ia2_state() const { return win_attributes_->ia2_state; }
const std::vector<base::string16>& ia2_attributes() const {
- return ia2_attributes_;
+ return win_attributes_->ia2_attributes;
}
+ base::string16 name() const { return win_attributes_->name; }
+ base::string16 description() const { return win_attributes_->description; }
+ base::string16 help() const { return win_attributes_->help; }
+ base::string16 value() const { return win_attributes_->value; }
+ base::string16 hypertext() const { return win_attributes_->hypertext; }
+ std::map<int32, int32>& hyperlink_offset_to_index() const {
+ return win_attributes_->hyperlink_offset_to_index;
+ }
+ std::vector<int32>& hyperlinks() const { return win_attributes_->hyperlinks; }
private:
// Add one to the reference count and return the same object. Always
@@ -823,6 +766,9 @@ BrowserAccessibilityWin
void IntAttributeToIA2(ui::AXIntAttribute attribute,
const char* ia2_attr);
+ // Append the accessible name from this node and its children.
+ base::string16 GetNameRecursive() const;
+
// Get the value text, which might come from the floating-point
// value for some roles.
base::string16 GetValueText();
@@ -831,6 +777,10 @@ BrowserAccessibilityWin
// be the name, it may be the value, etc. depending on the role.
base::string16 TextForIAccessibleText();
+ bool IsSameHypertextCharacter(size_t old_char_index, size_t new_char_index);
+ void ComputeHypertextRemovedAndInserted(
+ int* start, int* old_len, int* new_len);
+
// If offset is a member of IA2TextSpecialOffsets this function updates the
// value of offset and returns, otherwise offset remains unchanged.
void HandleSpecialTextOffset(const base::string16& text, LONG* offset);
@@ -850,51 +800,56 @@ BrowserAccessibilityWin
// does not make a new reference.
BrowserAccessibilityWin* GetFromID(int32 id);
+ // Returns true if this is a list box option with a parent of type list box,
+ // or a menu list option with a parent of type menu list popup.
+ bool IsListBoxOptionOrMenuListOption();
+
// Windows-specific unique ID (unique within the browser process),
// used for get_accChild, NotifyWinEvent, and as the unique ID for
// IAccessible2 and ISimpleDOM.
LONG unique_id_win_;
- // IAccessible role and state.
- int32 ia_role_;
- int32 ia_state_;
- base::string16 role_name_;
+ struct WinAttributes {
+ WinAttributes();
+ ~WinAttributes();
- // IAccessible2 role and state.
- int32 ia2_role_;
- int32 ia2_state_;
+ // IAccessible role and state.
+ int32 ia_role;
+ int32 ia_state;
+ base::string16 role_name;
- // IAccessible2 attributes.
- std::vector<base::string16> ia2_attributes_;
+ // IAccessible name, description, help, value.
+ base::string16 name;
+ base::string16 description;
+ base::string16 help;
+ base::string16 value;
- // True in Initialize when the object is first created, and false
- // subsequent times.
- bool first_time_;
+ // IAccessible2 role and state.
+ int32 ia2_role;
+ int32 ia2_state;
- // The previous text, before the last update to this object.
- base::string16 previous_text_;
+ // IAccessible2 attributes.
+ std::vector<base::string16> ia2_attributes;
- // The old text to return in IAccessibleText::get_oldText - this is like
- // previous_text_ except that it's NOT updated when the object
- // is initialized again but the text doesn't change.
- base::string16 old_text_;
+ // Hypertext.
+ base::string16 hypertext;
- // The previous state, used to see if there was a state change.
- int32 old_ia_state_;
+ // Maps the |hypertext_| embedded character offset to an index in
+ // |hyperlinks_|.
+ std::map<int32, int32> hyperlink_offset_to_index;
- // Relationships between this node and other nodes.
- std::vector<BrowserAccessibilityRelation*> relations_;
+ // The id of a BrowserAccessibilityWin for each hyperlink.
+ std::vector<int32> hyperlinks;
+ };
- // The text of this node including embedded hyperlink characters.
- base::string16 hypertext_;
+ scoped_ptr<WinAttributes> win_attributes_;
- // Maps the |hypertext_| embedded character offset to an index in
- // |hyperlinks_|.
- std::map<int32, int32> hyperlink_offset_to_index_;
+ // Only valid during the scope of a IA2_EVENT_TEXT_REMOVED or
+ // IA2_EVENT_TEXT_INSERTED event.
+ scoped_ptr<WinAttributes> old_win_attributes_;
- // Collection of non-static text child indicies, each of which corresponds to
- // a hyperlink.
- std::vector<int32> hyperlinks_;
+ // Relationships between this node and other nodes.
+ std::vector<BrowserAccessibilityRelation*> relations_;
// The previous scroll position, so we can tell if this object scrolled.
int previous_scroll_x_;
diff --git a/chromium/content/browser/accessibility/browser_accessibility_win_unittest.cc b/chromium/content/browser/accessibility/browser_accessibility_win_unittest.cc
index ccda97873d7..501490e2117 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_win_unittest.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_win_unittest.cc
@@ -11,7 +11,9 @@
#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 "content/public/test/test_browser_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/win/atl_module.h"
@@ -25,7 +27,7 @@ namespace {
class CountedBrowserAccessibility : public BrowserAccessibilityWin {
public:
CountedBrowserAccessibility();
- virtual ~CountedBrowserAccessibility();
+ ~CountedBrowserAccessibility() override;
static void reset() { num_instances_ = 0; }
static int num_instances() { return num_instances_; }
@@ -56,9 +58,9 @@ class CountedBrowserAccessibilityFactory : public BrowserAccessibilityFactory {
CountedBrowserAccessibilityFactory();
private:
- virtual ~CountedBrowserAccessibilityFactory();
+ ~CountedBrowserAccessibilityFactory() override;
- virtual BrowserAccessibility* Create() override;
+ BrowserAccessibility* Create() override;
DISALLOW_COPY_AND_ASSIGN(CountedBrowserAccessibilityFactory);
};
@@ -86,10 +88,12 @@ BrowserAccessibility* CountedBrowserAccessibilityFactory::Create() {
class BrowserAccessibilityTest : public testing::Test {
public:
BrowserAccessibilityTest();
- virtual ~BrowserAccessibilityTest();
+ ~BrowserAccessibilityTest() override;
private:
- virtual void SetUp() override;
+ void SetUp() override;
+
+ content::TestBrowserThreadBundle thread_bundle_;
DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityTest);
};
@@ -320,94 +324,156 @@ TEST_F(BrowserAccessibilityTest, TestChildrenChangeNoLeaks) {
}
TEST_F(BrowserAccessibilityTest, TestTextBoundaries) {
- std::string text1_value = "One two three.\nFour five six.";
-
- ui::AXNodeData text1;
- text1.id = 11;
- text1.role = ui::AX_ROLE_TEXT_FIELD;
- text1.state = 0;
- text1.AddStringAttribute(ui::AX_ATTR_VALUE, text1_value);
- std::vector<int32> line_breaks;
- line_breaks.push_back(15);
- text1.AddIntListAttribute(
- ui::AX_ATTR_LINE_BREAKS, line_breaks);
+ std::string line1 = "One two three.";
+ std::string line2 = "Four five six.";
+ std::string text_value = line1 + '\n' + line2;
ui::AXNodeData root;
root.id = 1;
root.role = ui::AX_ROLE_ROOT_WEB_AREA;
- root.state = 0;
- root.child_ids.push_back(11);
+ root.child_ids.push_back(2);
+
+ ui::AXNodeData text_field;
+ text_field.id = 2;
+ text_field.role = ui::AX_ROLE_TEXT_FIELD;
+ text_field.AddStringAttribute(ui::AX_ATTR_VALUE, text_value);
+ std::vector<int32> line_start_offsets;
+ line_start_offsets.push_back(15);
+ text_field.AddIntListAttribute(
+ ui::AX_ATTR_LINE_BREAKS, line_start_offsets);
+ text_field.child_ids.push_back(3);
+ text_field.child_ids.push_back(5);
+ text_field.child_ids.push_back(6);
+
+ ui::AXNodeData static_text1;
+ static_text1.id = 3;
+ static_text1.role = ui::AX_ROLE_STATIC_TEXT;
+ static_text1.AddStringAttribute(ui::AX_ATTR_VALUE, line1);
+ static_text1.child_ids.push_back(4);
+
+ ui::AXNodeData inline_box1;
+ inline_box1.id = 4;
+ inline_box1.role = ui::AX_ROLE_INLINE_TEXT_BOX;
+ inline_box1.AddStringAttribute(ui::AX_ATTR_VALUE, line1);
+ std::vector<int32> word_start_offsets1;
+ word_start_offsets1.push_back(0);
+ word_start_offsets1.push_back(4);
+ word_start_offsets1.push_back(8);
+ inline_box1.AddIntListAttribute(
+ ui::AX_ATTR_WORD_STARTS, word_start_offsets1);
+
+ ui::AXNodeData line_break;
+ line_break.id = 5;
+ line_break.role = ui::AX_ROLE_LINE_BREAK;
+ line_break.AddStringAttribute(ui::AX_ATTR_VALUE, "\n");
+
+ ui::AXNodeData static_text2;
+ static_text2.id = 6;
+ static_text2.role = ui::AX_ROLE_STATIC_TEXT;
+ static_text2.AddStringAttribute(ui::AX_ATTR_VALUE, line2);
+ static_text2.child_ids.push_back(7);
+
+ ui::AXNodeData inline_box2;
+ inline_box2.id = 7;
+ inline_box2.role = ui::AX_ROLE_INLINE_TEXT_BOX;
+ inline_box2.AddStringAttribute(ui::AX_ATTR_VALUE, line2);
+ std::vector<int32> word_start_offsets2;
+ word_start_offsets2.push_back(0);
+ word_start_offsets2.push_back(5);
+ word_start_offsets2.push_back(10);
+ inline_box2.AddIntListAttribute(
+ ui::AX_ATTR_WORD_STARTS, word_start_offsets2);
CountedBrowserAccessibility::reset();
scoped_ptr<BrowserAccessibilityManager> manager(
BrowserAccessibilityManager::Create(
- MakeAXTreeUpdate(root, text1),
- NULL, new CountedBrowserAccessibilityFactory()));
- ASSERT_EQ(2, CountedBrowserAccessibility::num_instances());
+ MakeAXTreeUpdate(root, text_field, static_text1, inline_box1,
+ line_break, static_text2, inline_box2),
+ nullptr, new CountedBrowserAccessibilityFactory()));
+ ASSERT_EQ(7, CountedBrowserAccessibility::num_instances());
BrowserAccessibilityWin* root_obj =
manager->GetRoot()->ToBrowserAccessibilityWin();
- BrowserAccessibilityWin* text1_obj =
+ ASSERT_NE(nullptr, root_obj);
+ ASSERT_EQ(1, root_obj->PlatformChildCount());
+
+ BrowserAccessibilityWin* text_field_obj =
root_obj->PlatformGetChild(0)->ToBrowserAccessibilityWin();
+ ASSERT_NE(nullptr, text_field_obj);
- long text1_len;
- ASSERT_EQ(S_OK, text1_obj->get_nCharacters(&text1_len));
+ long text_len;
+ EXPECT_EQ(S_OK, text_field_obj->get_nCharacters(&text_len));
base::win::ScopedBstr text;
- ASSERT_EQ(S_OK, text1_obj->get_text(0, text1_len, text.Receive()));
- ASSERT_EQ(text1_value, base::UTF16ToUTF8(base::string16(text)));
+ EXPECT_EQ(S_OK, text_field_obj->get_text(0, text_len, text.Receive()));
+ EXPECT_EQ(text_value, base::UTF16ToUTF8(base::string16(text)));
text.Reset();
- ASSERT_EQ(S_OK, text1_obj->get_text(0, 4, text.Receive()));
- ASSERT_STREQ(L"One ", text);
+ EXPECT_EQ(S_OK, text_field_obj->get_text(0, 4, text.Receive()));
+ EXPECT_STREQ(L"One ", text);
text.Reset();
long start;
long end;
- ASSERT_EQ(S_OK, text1_obj->get_textAtOffset(
+ EXPECT_EQ(S_OK, text_field_obj->get_textAtOffset(
1, IA2_TEXT_BOUNDARY_CHAR, &start, &end, text.Receive()));
- ASSERT_EQ(1, start);
- ASSERT_EQ(2, end);
- ASSERT_STREQ(L"n", text);
+ EXPECT_EQ(1, start);
+ EXPECT_EQ(2, end);
+ EXPECT_STREQ(L"n", text);
+ text.Reset();
+
+ EXPECT_EQ(S_FALSE, text_field_obj->get_textAtOffset(
+ text_len, IA2_TEXT_BOUNDARY_CHAR, &start, &end, text.Receive()));
+ EXPECT_EQ(0, start);
+ EXPECT_EQ(0, end);
+ EXPECT_EQ(nullptr, text);
text.Reset();
- ASSERT_EQ(S_FALSE, text1_obj->get_textAtOffset(
- text1_len, IA2_TEXT_BOUNDARY_CHAR, &start, &end, text.Receive()));
- ASSERT_EQ(text1_len, start);
- ASSERT_EQ(text1_len, end);
+ EXPECT_EQ(S_FALSE, text_field_obj->get_textAtOffset(
+ text_len, IA2_TEXT_BOUNDARY_WORD, &start, &end, text.Receive()));
+ EXPECT_EQ(0, start);
+ EXPECT_EQ(0, end);
+ EXPECT_EQ(nullptr, text);
text.Reset();
- ASSERT_EQ(S_OK, text1_obj->get_textAtOffset(
+ EXPECT_EQ(S_OK, text_field_obj->get_textAtOffset(
1, IA2_TEXT_BOUNDARY_WORD, &start, &end, text.Receive()));
- ASSERT_EQ(0, start);
- ASSERT_EQ(3, end);
- ASSERT_STREQ(L"One", text);
+ EXPECT_EQ(0, start);
+ EXPECT_EQ(4, end);
+ EXPECT_STREQ(L"One ", text);
text.Reset();
- ASSERT_EQ(S_OK, text1_obj->get_textAtOffset(
+ EXPECT_EQ(S_OK, text_field_obj->get_textAtOffset(
6, IA2_TEXT_BOUNDARY_WORD, &start, &end, text.Receive()));
- ASSERT_EQ(4, start);
- ASSERT_EQ(7, end);
- ASSERT_STREQ(L"two", text);
+ EXPECT_EQ(4, start);
+ EXPECT_EQ(8, end);
+ EXPECT_STREQ(L"two ", text);
text.Reset();
- ASSERT_EQ(S_OK, text1_obj->get_textAtOffset(
- text1_len, IA2_TEXT_BOUNDARY_WORD, &start, &end, text.Receive()));
- ASSERT_EQ(25, start);
- ASSERT_EQ(29, end);
- ASSERT_STREQ(L"six.", text);
+ EXPECT_EQ(S_OK, text_field_obj->get_textAtOffset(
+ text_len - 1, IA2_TEXT_BOUNDARY_WORD, &start, &end, text.Receive()));
+ EXPECT_EQ(25, start);
+ EXPECT_EQ(29, end);
+ EXPECT_STREQ(L"six.", text);
text.Reset();
- ASSERT_EQ(S_OK, text1_obj->get_textAtOffset(
+ EXPECT_EQ(S_OK, text_field_obj->get_textAtOffset(
1, IA2_TEXT_BOUNDARY_LINE, &start, &end, text.Receive()));
- ASSERT_EQ(0, start);
- ASSERT_EQ(15, end);
- ASSERT_STREQ(L"One two three.\n", text);
+ EXPECT_EQ(0, start);
+ EXPECT_EQ(15, end);
+ EXPECT_STREQ(L"One two three.\n", text);
+ text.Reset();
+
+ EXPECT_EQ(S_OK, text_field_obj->get_textAtOffset(
+ text_len, IA2_TEXT_BOUNDARY_LINE, &start, &end, text.Receive()));
+ EXPECT_EQ(15, start);
+ EXPECT_EQ(text_len, end);
+ EXPECT_STREQ(L"Four five six.", text);
text.Reset();
- ASSERT_EQ(S_OK,
- text1_obj->get_text(0, IA2_TEXT_OFFSET_LENGTH, text.Receive()));
- ASSERT_STREQ(L"One two three.\nFour five six.", text);
+ EXPECT_EQ(S_OK, text_field_obj->get_text(
+ 0, IA2_TEXT_OFFSET_LENGTH, text.Receive()));
+ EXPECT_EQ(text_value, base::UTF16ToUTF8(base::string16(text)));
// Delete the manager and test that all BrowserAccessibility instances are
// deleted.
@@ -441,7 +507,7 @@ TEST_F(BrowserAccessibilityTest, TestSimpleHypertext) {
CountedBrowserAccessibility::reset();
scoped_ptr<BrowserAccessibilityManager> manager(
BrowserAccessibilityManager::Create(
- MakeAXTreeUpdate(root, root, text1, text2),
+ MakeAXTreeUpdate(root, text1, text2),
NULL, new CountedBrowserAccessibilityFactory()));
ASSERT_EQ(3, CountedBrowserAccessibility::num_instances());
@@ -546,7 +612,7 @@ TEST_F(BrowserAccessibilityTest, TestComplexHypertext) {
base::win::ScopedBstr text;
ASSERT_EQ(S_OK, root_obj->get_text(0, text_len, text.Receive()));
const std::string embed = base::UTF16ToUTF8(
- BrowserAccessibilityWin::kEmbeddedCharacter);
+ base::string16(1, BrowserAccessibilityWin::kEmbeddedCharacter));
EXPECT_EQ(text1_name + embed + text2_name + embed,
base::UTF16ToUTF8(base::string16(text)));
text.Reset();
@@ -703,4 +769,152 @@ TEST_F(BrowserAccessibilityTest, EmptyDocHasUniqueIdWin) {
ASSERT_EQ(root, manager->GetFromUniqueIdWin(unique_id_win));
}
+TEST_F(BrowserAccessibilityTest, TestIA2Attributes) {
+ ui::AXNodeData checkbox;
+ checkbox.id = 2;
+ checkbox.SetName("Checkbox");
+ checkbox.role = ui::AX_ROLE_CHECK_BOX;
+ checkbox.state = 1 << ui::AX_STATE_CHECKED;
+
+ ui::AXNodeData root;
+ root.id = 1;
+ root.SetName("Document");
+ root.role = ui::AX_ROLE_ROOT_WEB_AREA;
+ root.state = (1 << ui::AX_STATE_READ_ONLY) | (1 << ui::AX_STATE_FOCUSABLE);
+ root.child_ids.push_back(2);
+
+ CountedBrowserAccessibility::reset();
+ scoped_ptr<BrowserAccessibilityManager> manager(
+ BrowserAccessibilityManager::Create(
+ MakeAXTreeUpdate(root, checkbox),
+ nullptr, new CountedBrowserAccessibilityFactory()));
+ ASSERT_EQ(2, CountedBrowserAccessibility::num_instances());
+
+ ASSERT_NE(nullptr, manager->GetRoot());
+ BrowserAccessibilityWin* root_accessible =
+ manager->GetRoot()->ToBrowserAccessibilityWin();
+ ASSERT_NE(nullptr, root_accessible);
+ ASSERT_EQ(1, root_accessible->PlatformChildCount());
+ BrowserAccessibilityWin* checkbox_accessible =
+ root_accessible->PlatformGetChild(0)->ToBrowserAccessibilityWin();
+ ASSERT_NE(nullptr, checkbox_accessible);
+
+ base::win::ScopedBstr attributes;
+ HRESULT hr = checkbox_accessible->get_attributes(attributes.Receive());
+ EXPECT_EQ(S_OK, hr);
+ EXPECT_NE(nullptr, static_cast<BSTR>(attributes));
+ std::wstring attributes_str(attributes, attributes.Length());
+ EXPECT_EQ(L"checkable:true;", attributes_str);
+
+ manager.reset();
+ ASSERT_EQ(0, CountedBrowserAccessibility::num_instances());
+}
+
+/**
+ * Ensures that ui::AX_ATTR_TEXT_SEL_START/END attributes are correctly used to
+ * determine caret position and text selection in various types of editable
+ * elements.
+ */
+TEST_F(BrowserAccessibilityTest, TestCaretAndTextSelection) {
+ ui::AXNodeData root;
+ root.id = 1;
+ root.role = ui::AX_ROLE_ROOT_WEB_AREA;
+ root.state = (1 << ui::AX_STATE_READ_ONLY) | (1 << ui::AX_STATE_FOCUSABLE);
+
+ ui::AXNodeData combo_box;
+ combo_box.id = 2;
+ combo_box.role = ui::AX_ROLE_COMBO_BOX;
+ combo_box.state = (1 << ui::AX_STATE_FOCUSABLE) | (1 << ui::AX_STATE_FOCUSED);
+ combo_box.SetValue("Test1");
+ // Place the caret between 't' and 'e'.
+ combo_box.AddIntAttribute(ui::AX_ATTR_TEXT_SEL_START, 1);
+ combo_box.AddIntAttribute(ui::AX_ATTR_TEXT_SEL_END, 1);
+
+ ui::AXNodeData text_field;
+ text_field.id = 3;
+ text_field.role = ui::AX_ROLE_TEXT_FIELD;
+ text_field.state = 1 << ui::AX_STATE_FOCUSABLE;
+ text_field.SetValue("Test2");
+ // Select the letter 'e'.
+ text_field.AddIntAttribute(ui::AX_ATTR_TEXT_SEL_START, 1);
+ text_field.AddIntAttribute(ui::AX_ATTR_TEXT_SEL_END, 2);
+
+ root.child_ids.push_back(2);
+ root.child_ids.push_back(3);
+
+ CountedBrowserAccessibility::reset();
+ scoped_ptr<BrowserAccessibilityManager> manager(
+ BrowserAccessibilityManager::Create(
+ MakeAXTreeUpdate(root, combo_box, text_field),
+ nullptr, new CountedBrowserAccessibilityFactory()));
+ ASSERT_EQ(3, CountedBrowserAccessibility::num_instances());
+
+ ASSERT_NE(nullptr, manager->GetRoot());
+ BrowserAccessibilityWin* root_accessible =
+ manager->GetRoot()->ToBrowserAccessibilityWin();
+ ASSERT_NE(nullptr, root_accessible);
+ ASSERT_EQ(2, root_accessible->PlatformChildCount());
+
+ BrowserAccessibilityWin* combo_box_accessible =
+ root_accessible->PlatformGetChild(0)->ToBrowserAccessibilityWin();
+ ASSERT_NE(nullptr, combo_box_accessible);
+ manager->SetFocus(combo_box_accessible, false /* notify */);
+ ASSERT_EQ(combo_box_accessible,
+ manager->GetFocus(root_accessible)->ToBrowserAccessibilityWin());
+ BrowserAccessibilityWin* text_field_accessible =
+ root_accessible->PlatformGetChild(1)->ToBrowserAccessibilityWin();
+ ASSERT_NE(nullptr, text_field_accessible);
+
+ // -2 is never a valid offset.
+ LONG caret_offset = -2;
+ LONG n_selections = -2;
+ LONG selection_start = -2;
+ LONG selection_end = -2;
+
+ // Test get_caretOffset.
+ HRESULT hr = combo_box_accessible->get_caretOffset(&caret_offset);;
+ EXPECT_EQ(S_OK, hr);
+ EXPECT_EQ(1L, caret_offset);
+ // caret_offset should be -1 when the object is not focused.
+ hr = text_field_accessible->get_caretOffset(&caret_offset);;
+ EXPECT_EQ(S_FALSE, hr);
+ EXPECT_EQ(-1L, caret_offset);
+
+ // Move the focus to the text field.
+ combo_box.state &= ~(1 << ui::AX_STATE_FOCUSED);
+ text_field.state |= 1 << ui::AX_STATE_FOCUSED;
+ manager->SetFocus(text_field_accessible, false /* notify */);
+ ASSERT_EQ(text_field_accessible,
+ manager->GetFocus(root_accessible)->ToBrowserAccessibilityWin());
+
+ // The caret should be at the start of the selection.
+ hr = text_field_accessible->get_caretOffset(&caret_offset);;
+ EXPECT_EQ(S_OK, hr);
+ EXPECT_EQ(1L, caret_offset);
+
+ // Test get_nSelections.
+ hr = combo_box_accessible->get_nSelections(&n_selections);;
+ EXPECT_EQ(S_OK, hr);
+ EXPECT_EQ(0L, n_selections);
+ hr = text_field_accessible->get_nSelections(&n_selections);;
+ EXPECT_EQ(S_OK, hr);
+ EXPECT_EQ(1L, n_selections);
+
+ // Test get_selection.
+ hr = combo_box_accessible->get_selection(
+ 0L /* selection_index */, &selection_start, &selection_end);;
+ EXPECT_EQ(E_INVALIDARG, hr); // No selections available.
+ // Invalid in_args should not modify out_args.
+ EXPECT_EQ(-2L, selection_start);
+ EXPECT_EQ(-2L, selection_end);
+ hr = text_field_accessible->get_selection(
+ 0L /* selection_index */, &selection_start, &selection_end);;
+ EXPECT_EQ(S_OK, hr);
+ EXPECT_EQ(1L, selection_start);
+ EXPECT_EQ(2L, selection_end);
+
+ manager.reset();
+ ASSERT_EQ(0, CountedBrowserAccessibility::num_instances());
+}
+
} // 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 8f83ed97b10..215a94e5f97 100644
--- a/chromium/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
+++ b/chromium/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
@@ -47,7 +47,7 @@ class CrossPlatformAccessibilityBrowserTest : public ContentBrowserTest {
return waiter.GetAXTree();
}
- // Make sure each node in the tree has an unique id.
+ // Make sure each node in the tree has a unique id.
void RecursiveAssertUniqueIds(
const ui::AXNode* node, base::hash_set<int>* ids) {
ASSERT_TRUE(ids->find(node->id()) == ids->end());
@@ -142,7 +142,7 @@ IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
GURL url(url_str);
NavigateToURL(shell(), url);
const ui::AXTree& tree = GetAXTree();
- const ui::AXNode* root = tree.GetRoot();
+ const ui::AXNode* root = tree.root();
// Check properties of the root element of the tree.
EXPECT_STREQ(url_str,
@@ -160,7 +160,7 @@ IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
GetAttr(root, ui::AX_ATTR_NAME).c_str());
EXPECT_EQ(ui::AX_ROLE_ROOT_WEB_AREA, root->data().role);
- // Check properites of the BODY element.
+ // Check properties of the BODY element.
ASSERT_EQ(1, root->child_count());
const ui::AXNode* body = root->ChildAtIndex(0);
EXPECT_EQ(ui::AX_ROLE_GROUP, body->data().role);
@@ -213,7 +213,7 @@ IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
NavigateToURL(shell(), url);
const ui::AXTree& tree = GetAXTree();
- const ui::AXNode* root = tree.GetRoot();
+ const ui::AXNode* root = tree.root();
ASSERT_EQ(1, root->child_count());
const ui::AXNode* body = root->ChildAtIndex(0);
ASSERT_EQ(1, body->child_count());
@@ -245,7 +245,7 @@ IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
NavigateToURL(shell(), url);
const ui::AXTree& tree = GetAXTree();
- const ui::AXNode* root = tree.GetRoot();
+ const ui::AXNode* root = tree.root();
ASSERT_EQ(1, root->child_count());
const ui::AXNode* body = root->ChildAtIndex(0);
ASSERT_EQ(1, body->child_count());
@@ -275,7 +275,7 @@ IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
NavigateToURL(shell(), url);
const ui::AXTree& tree = GetAXTree();
- const ui::AXNode* root = tree.GetRoot();
+ const ui::AXNode* root = tree.root();
ASSERT_EQ(1, root->child_count());
const ui::AXNode* table = root->ChildAtIndex(0);
EXPECT_EQ(ui::AX_ROLE_TABLE, table->data().role);
@@ -324,7 +324,7 @@ IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
NavigateToURL(shell(), url);
const ui::AXTree& tree = GetAXTree();
- const ui::AXNode* root = tree.GetRoot();
+ const ui::AXNode* root = tree.root();
base::hash_set<int> ids;
RecursiveAssertUniqueIds(root, &ids);
}
@@ -346,7 +346,7 @@ IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
NavigateToURL(shell(), url);
const ui::AXTree& tree = GetAXTree();
- const ui::AXNode* root = tree.GetRoot();
+ const ui::AXNode* root = tree.root();
ASSERT_EQ(1, root->child_count());
const ui::AXNode* body = root->ChildAtIndex(0);
ASSERT_EQ(3, body->child_count());
@@ -397,7 +397,7 @@ IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
NavigateToURL(shell(), url);
const ui::AXTree& tree = GetAXTree();
- const ui::AXNode* root = tree.GetRoot();
+ const ui::AXNode* root = tree.root();
base::hash_set<int> ids;
RecursiveAssertUniqueIds(root, &ids);
}
@@ -425,7 +425,7 @@ IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
NavigateToURL(shell(), url);
const ui::AXTree& tree = GetAXTree();
- const ui::AXNode* root = tree.GetRoot();
+ const ui::AXNode* root = tree.root();
const ui::AXNode* table = root->ChildAtIndex(0);
EXPECT_EQ(ui::AX_ROLE_TABLE, table->data().role);
ASSERT_GE(table->child_count(), 5);
@@ -488,7 +488,7 @@ IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
GURL url(url_str);
NavigateToURL(shell(), url);
const ui::AXTree& tree = GetAXTree();
- const ui::AXNode* root = tree.GetRoot();
+ const ui::AXNode* root = tree.root();
ASSERT_EQ(1, root->child_count());
const ui::AXNode* textbox = root->ChildAtIndex(0);
EXPECT_EQ(true, GetBoolAttr(textbox, ui::AX_ATTR_CAN_SET_VALUE));
diff --git a/chromium/content/browser/accessibility/dump_accessibility_browsertest_base.cc b/chromium/content/browser/accessibility/dump_accessibility_browsertest_base.cc
new file mode 100644
index 00000000000..d09b852ff34
--- /dev/null
+++ b/chromium/content/browser/accessibility/dump_accessibility_browsertest_base.cc
@@ -0,0 +1,246 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/accessibility/dump_accessibility_browsertest_base.h"
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/path_service.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/browser/accessibility/accessibility_tree_formatter.h"
+#include "content/browser/accessibility/browser_accessibility.h"
+#include "content/browser/accessibility/browser_accessibility_manager.h"
+#include "content/browser/accessibility/browser_accessibility_state_impl.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/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"
+
+namespace content {
+
+namespace {
+
+const char kCommentToken = '#';
+const char kMarkSkipFile[] = "#<skip";
+const char kMarkEndOfFile[] = "<-- End-of-file -->";
+const char kSignalDiff[] = "*";
+
+} // namespace
+
+typedef AccessibilityTreeFormatter::Filter Filter;
+
+DumpAccessibilityTestBase::DumpAccessibilityTestBase() {
+}
+
+DumpAccessibilityTestBase::~DumpAccessibilityTestBase() {
+}
+
+base::string16
+DumpAccessibilityTestBase::DumpUnfilteredAccessibilityTreeAsString() {
+ WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
+ shell()->web_contents());
+ AccessibilityTreeFormatter formatter(
+ web_contents->GetRootBrowserAccessibilityManager()->GetRoot());
+ std::vector<Filter> filters;
+ filters.push_back(Filter(base::ASCIIToUTF16("*"), Filter::ALLOW));
+ formatter.SetFilters(filters);
+ formatter.set_show_ids(true);
+ base::string16 ax_tree_dump;
+ formatter.FormatAccessibilityTree(&ax_tree_dump);
+ return ax_tree_dump;
+}
+
+std::vector<int> DumpAccessibilityTestBase::DiffLines(
+ const std::vector<std::string>& expected_lines,
+ const std::vector<std::string>& actual_lines) {
+ int actual_lines_count = actual_lines.size();
+ int expected_lines_count = expected_lines.size();
+ std::vector<int> diff_lines;
+ int i = 0, j = 0;
+ while (i < actual_lines_count && j < expected_lines_count) {
+ if (expected_lines[j].size() == 0 ||
+ expected_lines[j][0] == kCommentToken) {
+ // Skip comment lines and blank lines in expected output.
+ ++j;
+ continue;
+ }
+
+ if (actual_lines[i] != expected_lines[j])
+ diff_lines.push_back(j);
+ ++i;
+ ++j;
+ }
+
+ // Actual file has been fully checked.
+ return diff_lines;
+}
+
+void DumpAccessibilityTestBase::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();
+ iter != lines.end();
+ ++iter) {
+ const std::string& line = *iter;
+ const std::string& allow_empty_str =
+ AccessibilityTreeFormatter::GetAllowEmptyString();
+ const std::string& allow_str =
+ 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())),
+ Filter::ALLOW_EMPTY));
+ } else if (StartsWithASCII(line, allow_str, true)) {
+ filters->push_back(Filter(base::UTF8ToUTF16(
+ line.substr(allow_str.size())),
+ Filter::ALLOW));
+ } else if (StartsWithASCII(line, deny_str, true)) {
+ 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());
+ }
+ }
+}
+
+void DumpAccessibilityTestBase::RunTest(
+ const base::FilePath file_path, const char* file_dir) {
+ // Disable the "hot tracked" state (set when the mouse is hovering over
+ // an object) because it makes test output change based on the mouse position.
+ BrowserAccessibilityStateImpl::GetInstance()->
+ set_disable_hot_tracking_for_testing(true);
+
+ NavigateToURL(shell(), GURL(url::kAboutBlankURL));
+
+ // Output the test path to help anyone who encounters a failure and needs
+ // to know where to look.
+ printf("Testing: %s\n", file_path.MaybeAsASCII().c_str());
+
+ std::string html_contents;
+ base::ReadFileToString(file_path, &html_contents);
+
+ // Read the expected file.
+ std::string expected_contents_raw;
+ base::FilePath expected_file =
+ base::FilePath(file_path.RemoveExtension().value() +
+ AccessibilityTreeFormatter::GetExpectedFileSuffix());
+ base::ReadFileToString(expected_file, &expected_contents_raw);
+
+ // Tolerate Windows-style line endings (\r\n) in the expected file:
+ // normalize by deleting all \r from the file (if any) to leave only \n.
+ std::string expected_contents;
+ base::RemoveChars(expected_contents_raw, "\r", &expected_contents);
+
+ if (!expected_contents.compare(0, strlen(kMarkSkipFile), kMarkSkipFile)) {
+ printf("Skipping this test on this platform.\n");
+ return;
+ }
+
+ // Parse filters and other directives in the test file.
+ std::string wait_for;
+ AddDefaultFilters(&filters_);
+ ParseHtmlForExtraDirectives(html_contents, &filters_, &wait_for);
+
+ // Load the page.
+ base::string16 html_contents16;
+ html_contents16 = base::UTF8ToUTF16(html_contents);
+ GURL url = GetTestUrl(file_dir, file_path.BaseName().MaybeAsASCII().c_str());
+
+ // If there's a @WAIT-FOR directive, set up an accessibility notification
+ // waiter that returns on any event; we'll stop when we get the text we're
+ // waiting for, or time out. Otherwise just wait specifically for
+ // the "load complete" event.
+ scoped_ptr<AccessibilityNotificationWaiter> waiter;
+ if (!wait_for.empty()) {
+ waiter.reset(new AccessibilityNotificationWaiter(
+ shell(), AccessibilityModeComplete, ui::AX_EVENT_NONE));
+ } else {
+ waiter.reset(new AccessibilityNotificationWaiter(
+ shell(), AccessibilityModeComplete, ui::AX_EVENT_LOAD_COMPLETE));
+ }
+
+ // Load the test html.
+ 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.
+ do {
+ waiter->WaitForNotification();
+ if (!wait_for.empty()) {
+ base::string16 tree_dump = DumpUnfilteredAccessibilityTreeAsString();
+ if (base::UTF16ToUTF8(tree_dump).find(wait_for) != std::string::npos)
+ wait_for.clear();
+ }
+ } while (!wait_for.empty());
+
+ // Call the subclass to dump the output.
+ std::vector<std::string> actual_lines = Dump();
+
+ // Perform a diff (or write the initial baseline).
+ std::vector<std::string> expected_lines;
+ Tokenize(expected_contents, "\n", &expected_lines);
+ // Marking the end of the file with a line of text ensures that
+ // file length differences are found.
+ expected_lines.push_back(kMarkEndOfFile);
+ actual_lines.push_back(kMarkEndOfFile);
+ std::string actual_contents = JoinString(actual_lines, "\n");
+
+ std::vector<int> diff_lines = DiffLines(expected_lines, actual_lines);
+ bool is_different = diff_lines.size() > 0;
+ EXPECT_FALSE(is_different);
+ if (is_different) {
+ OnDiffFailed();
+
+ // Mark the expected lines which did not match actual output with a *.
+ printf("* Line Expected\n");
+ printf("- ---- --------\n");
+ for (int line = 0, diff_index = 0;
+ line < static_cast<int>(expected_lines.size());
+ ++line) {
+ bool is_diff = false;
+ if (diff_index < static_cast<int>(diff_lines.size()) &&
+ diff_lines[diff_index] == line) {
+ is_diff = true;
+ ++diff_index;
+ }
+ printf("%1s %4d %s\n", is_diff? kSignalDiff : "", line + 1,
+ expected_lines[line].c_str());
+ }
+ printf("\nActual\n");
+ printf("------\n");
+ printf("%s\n", actual_contents.c_str());
+ }
+
+ if (!base::PathExists(expected_file)) {
+ base::FilePath actual_file =
+ base::FilePath(file_path.RemoveExtension().value() +
+ AccessibilityTreeFormatter::GetActualFileSuffix());
+
+ EXPECT_TRUE(base::WriteFile(
+ actual_file, actual_contents.c_str(), actual_contents.size()));
+
+ ADD_FAILURE() << "No expectation found. Create it by doing:\n"
+ << "mv " << actual_file.LossyDisplayName() << " "
+ << expected_file.LossyDisplayName();
+ }
+}
+
+} // namespace content
diff --git a/chromium/content/browser/accessibility/dump_accessibility_browsertest_base.h b/chromium/content/browser/accessibility/dump_accessibility_browsertest_base.h
new file mode 100644
index 00000000000..591d5b99f55
--- /dev/null
+++ b/chromium/content/browser/accessibility/dump_accessibility_browsertest_base.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.
+
+#include <string>
+#include <vector>
+
+#include "base/strings/string16.h"
+#include "content/browser/accessibility/accessibility_tree_formatter.h"
+#include "content/public/test/content_browser_test.h"
+
+namespace content {
+
+// Base class for an accessibility browsertest that takes an HTML file as
+// input, loads it into a tab, dumps some accessibility data in text format,
+// then compares that text to an expectation file in the same directory.
+//
+// The system was inspired by WebKit/Blink LayoutTests, but customized for
+// testing accessibility in Chromium.
+class DumpAccessibilityTestBase : public ContentBrowserTest {
+ public:
+ DumpAccessibilityTestBase();
+ ~DumpAccessibilityTestBase() override;
+
+ // Given a path to an HTML file relative to the test directory,
+ // loads the HTML, loads the accessibility tree, calls Dump(), then
+ // compares the output to the expected result and has the test succeed
+ // or fail based on the diff.
+ void RunTest(const base::FilePath file_path, const char* file_dir);
+
+ protected:
+ //
+ // For subclasses to override:
+ //
+
+ // This is called by RunTest after the document has finished loading,
+ // including the load complete accessibility event. The subclass should
+ // dump whatever that specific test wants to dump, returning the result
+ // as a sequence of strings.
+ virtual std::vector<std::string> Dump() = 0;
+
+ // Add the default filters that are applied to all tests.
+ virtual void AddDefaultFilters(
+ std::vector<AccessibilityTreeFormatter::Filter>* filters) = 0;
+
+ // This gets called if the diff didn't match; the test can print
+ // additional useful info.
+ virtual void OnDiffFailed() {}
+
+ //
+ // Helpers
+ //
+
+ // Dump the whole accessibility tree, without applying any filters,
+ // and return it as a string.
+ base::string16 DumpUnfilteredAccessibilityTreeAsString();
+
+ // Utility helper that does a comment-aware equality check.
+ // Returns array of lines from expected file which are different.
+ std::vector<int> DiffLines(const std::vector<std::string>& expected_lines,
+ const std::vector<std::string>& actual_lines);
+
+ // 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<AccessibilityTreeFormatter::Filter>* filters,
+ std::string* wait_for);
+
+ // The default filters plus the filters loaded from the test file.
+ std::vector<AccessibilityTreeFormatter::Filter> filters_;
+};
+
+} // namespace content
diff --git a/chromium/content/browser/accessibility/dump_accessibility_events_browsertest.cc b/chromium/content/browser/accessibility/dump_accessibility_events_browsertest.cc
new file mode 100644
index 00000000000..3a9f62ac229
--- /dev/null
+++ b/chromium/content/browser/accessibility/dump_accessibility_events_browsertest.cc
@@ -0,0 +1,260 @@
+// 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 <set>
+#include <string>
+#include <vector>
+
+#include "base/path_service.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/browser/accessibility/accessibility_event_recorder.h"
+#include "content/browser/accessibility/accessibility_tree_formatter.h"
+#include "content/browser/accessibility/browser_accessibility.h"
+#include "content/browser/accessibility/browser_accessibility_manager.h"
+#include "content/browser/accessibility/dump_accessibility_browsertest_base.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/common/content_paths.h"
+#include "content/shell/browser/shell.h"
+#include "content/test/accessibility_browser_test_utils.h"
+
+namespace content {
+
+typedef AccessibilityTreeFormatter::Filter Filter;
+
+// Tests that the right platform-specific accessibility events are fired
+// in response to things that happen in a web document.
+//
+// Similar to DumpAccessibilityTree in that each test consists of a
+// single HTML file, possibly with a few special directives in comments,
+// and then expectation files in text format for each platform.
+//
+// While DumpAccessibilityTree just loads the document and then
+// prints out a text representation of the accessibility tree,
+// DumpAccessibilityEvents loads the document, then executes the
+// JavaScript function "go()", then it records and dumps all accessibility
+// events generated as a result of that "go" function executing.
+//
+// How each event is dumped is platform-specific, but should be of the
+// form:
+//
+// <event> on <node>
+//
+// ...where <event> is the name of the event, and <node> is a description
+// of the node the event fired on, such as the node's role and name.
+//
+// As with DumpAccessibilityTree, DumpAccessibilityEvents takes the events
+// dumped from that particular html file and compares it to the expectation
+// file in the same directory (for example, test-name-expected-win.txt)
+// and the test fails if they don't agree.
+//
+// Currently it's not possible to test for accessibility events that
+// don't fire immediately (i.e. within the call scope of the call to "go()");
+// the test framework calls "go()" and then sends a sentinel event signaling
+// the end of the test; anything received after that is too late.
+class DumpAccessibilityEventsTest : public DumpAccessibilityTestBase {
+ public:
+ void AddDefaultFilters(std::vector<Filter>* filters) override {
+ }
+
+ std::vector<std::string> Dump() override;
+
+ void OnDiffFailed() override;
+ void RunEventTest(const base::FilePath::CharType* file_path);
+
+ private:
+ base::string16 initial_tree_;
+ base::string16 final_tree_;
+};
+
+std::vector<std::string> DumpAccessibilityEventsTest::Dump() {
+ WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
+ shell()->web_contents());
+ scoped_ptr<AccessibilityEventRecorder> event_recorder(
+ AccessibilityEventRecorder::Create(
+ web_contents->GetRootBrowserAccessibilityManager()));
+
+ // Save a copy of the accessibility tree (as a text dump); we'll
+ // log this for the user later if the test fails.
+ initial_tree_ = DumpUnfilteredAccessibilityTreeAsString();
+
+ // Create a waiter that waits for any one accessibility event.
+ // This will ensure that after calling the go() function, we
+ // block until we've received an accessibility event generated as
+ // a result of this function.
+ scoped_ptr<AccessibilityNotificationWaiter> waiter;
+ waiter.reset(new AccessibilityNotificationWaiter(
+ shell(), AccessibilityModeComplete, ui::AX_EVENT_NONE));
+
+
+ web_contents->GetMainFrame()->ExecuteJavaScript(
+ base::ASCIIToUTF16("go()"));
+
+ // Wait for at least one accessibility event generated in response to
+ // that function.
+ waiter->WaitForNotification();
+
+ // More than one accessibility event could have been generated.
+ // To make sure we've received all accessibility events, add a
+ // sentinel by calling AccessibilityHitTest and waiting for a HOVER
+ // event in response.
+ waiter.reset(new AccessibilityNotificationWaiter(
+ shell(), AccessibilityModeComplete, ui::AX_EVENT_HOVER));
+ BrowserAccessibilityManager* manager =
+ web_contents->GetRootBrowserAccessibilityManager();
+ manager->delegate()->AccessibilityHitTest(gfx::Point(0, 0));
+ waiter->WaitForNotification();
+
+ // Save a copy of the final accessibility tree (as a text dump); we'll
+ // log this for the user later if the test fails.
+ final_tree_ = DumpUnfilteredAccessibilityTreeAsString();
+
+ // Dump the event logs, running them through any filters specified
+ // in the HTML file.
+ std::vector<std::string> event_logs = event_recorder->event_logs();
+ std::vector<std::string> result;
+ for (size_t i = 0; i < event_logs.size(); ++i) {
+ if (AccessibilityTreeFormatter::MatchesFilters(
+ filters_, base::UTF8ToUTF16(event_logs[i]), true)) {
+ result.push_back(event_logs[i]);
+ }
+ }
+ return result;
+}
+
+void DumpAccessibilityEventsTest::OnDiffFailed() {
+ printf("\n");
+ printf("Initial accessibility tree (after load complete):\n");
+ printf("%s\n", base::UTF16ToUTF8(initial_tree_).c_str());
+ printf("\n");
+ printf("Final accessibility tree after events fired:\n");
+ printf("%s\n", base::UTF16ToUTF8(final_tree_).c_str());
+ printf("\n");
+}
+
+void DumpAccessibilityEventsTest::RunEventTest(
+ const base::FilePath::CharType* file_path) {
+ base::FilePath dir_test_data;
+ ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &dir_test_data));
+ base::FilePath test_path(dir_test_data.AppendASCII("accessibility")
+ .AppendASCII("event"));
+ ASSERT_TRUE(base::PathExists(test_path)) << test_path.LossyDisplayName();
+
+ base::FilePath event_file = test_path.Append(base::FilePath(file_path));
+ RunTest(event_file, "accessibility/event");
+}
+
+// TODO(dmazzoni): port these tests to run on all platforms.
+#if defined(OS_WIN) || defined(OS_MACOSX)
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
+ AccessibilityEventsAddAlert) {
+ RunEventTest(FILE_PATH_LITERAL("add-alert.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
+ AccessibilityEventsAddChild) {
+ RunEventTest(FILE_PATH_LITERAL("add-child.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
+ AccessibilityEventsAddHiddenAttribute) {
+ RunEventTest(FILE_PATH_LITERAL("add-hidden-attribute.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
+ AccessibilityEventsAddHiddenAttributeSubtree) {
+ RunEventTest(FILE_PATH_LITERAL("add-hidden-attribute-subtree.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
+ AccessibilityEventsAddSubtree) {
+ RunEventTest(FILE_PATH_LITERAL("add-subtree.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
+ AccessibilityEventsCheckedStateChanged) {
+ RunEventTest(FILE_PATH_LITERAL("checked-state-changed.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
+ AccessibilityEventsCSSDisplay) {
+ RunEventTest(FILE_PATH_LITERAL("css-display.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
+ AccessibilityEventsCSSVisibility) {
+ RunEventTest(FILE_PATH_LITERAL("css-visibility.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
+ AccessibilityEventsDescriptionChange) {
+ RunEventTest(FILE_PATH_LITERAL("description-change.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
+ AccessibilityEventsInnerHtmlChange) {
+ RunEventTest(FILE_PATH_LITERAL("inner-html-change.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
+ AccessibilityEventsInputTypeTextValueChanged) {
+ RunEventTest(FILE_PATH_LITERAL("input-type-text-value-changed.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
+ AccessibilityEventsListboxFocus) {
+ RunEventTest(FILE_PATH_LITERAL("listbox-focus.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
+ AccessibilityEventsListboxNext) {
+ RunEventTest(FILE_PATH_LITERAL("listbox-next.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
+ AccessibilityEventsMenuListFocus) {
+ RunEventTest(FILE_PATH_LITERAL("menulist-focus.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
+ AccessibilityEventsMenuListNext) {
+ RunEventTest(FILE_PATH_LITERAL("menulist-next.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
+ AccessibilityEventsNameChange) {
+ RunEventTest(FILE_PATH_LITERAL("name-change.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
+ AccessibilityEventsRemoveChild) {
+ RunEventTest(FILE_PATH_LITERAL("remove-child.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
+ AccessibilityEventsRemoveHiddenAttribute) {
+ RunEventTest(FILE_PATH_LITERAL("remove-hidden-attribute.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(
+ DumpAccessibilityEventsTest,
+ AccessibilityEventsRemoveHiddenAttributeSubtree) {
+ RunEventTest(FILE_PATH_LITERAL("remove-hidden-attribute-subtree.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
+ AccessibilityEventsRemoveSubtree) {
+ RunEventTest(FILE_PATH_LITERAL("remove-subtree.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
+ AccessibilityEventsTextChanged) {
+ RunEventTest(FILE_PATH_LITERAL("text-changed.html"));
+}
+
+#endif // defined(OS_WIN)
+
+} // namespace content
diff --git a/chromium/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/chromium/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
index fbe8f475b32..e21137ea0f8 100644
--- a/chromium/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
+++ b/chromium/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -7,28 +7,20 @@
#include <vector>
#include "base/command_line.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"
#include "base/strings/utf_string_conversions.h"
#include "content/browser/accessibility/accessibility_tree_formatter.h"
#include "content/browser/accessibility/browser_accessibility.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
-#include "content/browser/renderer_host/render_view_host_impl.h"
-#include "content/browser/renderer_host/render_widget_host_view_base.h"
+#include "content/browser/accessibility/dump_accessibility_browsertest_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"
-#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"
#if defined(OS_MACOSX)
#include "base/mac/mac_util.h"
@@ -43,114 +35,27 @@
namespace content {
-namespace {
-
-const char kCommentToken = '#';
-const char kMarkSkipFile[] = "#<skip";
-const char kMarkEndOfFile[] = "<-- End-of-file -->";
-const char kSignalDiff[] = "*";
-
-} // namespace
-
typedef AccessibilityTreeFormatter::Filter Filter;
// This test takes a snapshot of the platform BrowserAccessibility tree and
// tests it against an expected baseline.
//
// The flow of the test is as outlined below.
-// 1. Load an html file from chrome/test/data/accessibility.
+// 1. Load an html file from content/test/data/accessibility.
// 2. Read the expectation.
// 3. Browse to the page and serialize the platform specific tree into a human
// readable string.
// 4. Perform a comparison between actual and expected and fail if they do not
// exactly match.
-class DumpAccessibilityTreeTest : public ContentBrowserTest {
+class DumpAccessibilityTreeTest : public DumpAccessibilityTestBase {
public:
- // Utility helper that does a comment aware equality check.
- // Returns array of lines from expected file which are different.
- std::vector<int> DiffLines(const std::vector<std::string>& expected_lines,
- const std::vector<std::string>& actual_lines) {
- int actual_lines_count = actual_lines.size();
- int expected_lines_count = expected_lines.size();
- std::vector<int> diff_lines;
- int i = 0, j = 0;
- while (i < actual_lines_count && j < expected_lines_count) {
- if (expected_lines[j].size() == 0 ||
- expected_lines[j][0] == kCommentToken) {
- // Skip comment lines and blank lines in expected output.
- ++j;
- continue;
- }
-
- if (actual_lines[i] != expected_lines[j])
- diff_lines.push_back(j);
- ++i;
- ++j;
- }
-
- // Actual file has been fully checked.
- return diff_lines;
- }
-
- void AddDefaultFilters(std::vector<Filter>* filters) {
+ void AddDefaultFilters(std::vector<Filter>* filters) override {
filters->push_back(Filter(base::ASCIIToUTF16("FOCUSABLE"), Filter::ALLOW));
filters->push_back(Filter(base::ASCIIToUTF16("READONLY"), Filter::ALLOW));
filters->push_back(Filter(base::ASCIIToUTF16("name*"), Filter::ALLOW));
filters->push_back(Filter(base::ASCIIToUTF16("*=''"), Filter::DENY));
}
- // 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();
- iter != lines.end();
- ++iter) {
- const std::string& line = *iter;
- const std::string& allow_empty_str =
- AccessibilityTreeFormatter::GetAllowEmptyString();
- const std::string& allow_str =
- 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())),
- Filter::ALLOW_EMPTY));
- } else if (StartsWithASCII(line, allow_str, true)) {
- filters->push_back(Filter(base::UTF8ToUTF16(
- line.substr(allow_str.size())),
- Filter::ALLOW));
- } else if (StartsWithASCII(line, deny_str, true)) {
- 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());
- }
- }
- }
-
void SetUpCommandLine(base::CommandLine* command_line) override {
ContentBrowserTest::SetUpCommandLine(command_line);
// Enable <dialog>, which is used in some tests.
@@ -158,637 +63,744 @@ class DumpAccessibilityTreeTest : public ContentBrowserTest {
switches::kEnableExperimentalWebPlatformFeatures);
}
- void RunTest(const base::FilePath::CharType* file_path);
-};
+ void RunAriaTest(const base::FilePath::CharType* file_path) {
+ base::FilePath dir_test_data;
+ ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &dir_test_data));
+ base::FilePath test_path(dir_test_data.AppendASCII("accessibility")
+ .AppendASCII("aria"));
+ ASSERT_TRUE(base::PathExists(test_path)) << test_path.LossyDisplayName();
-void DumpAccessibilityTreeTest::RunTest(
- const base::FilePath::CharType* file_path) {
- NavigateToURL(shell(), GURL(url::kAboutBlankURL));
-
- // Setup test paths.
- base::FilePath dir_test_data;
- ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &dir_test_data));
- base::FilePath test_path(
- dir_test_data.Append(FILE_PATH_LITERAL("accessibility")));
- ASSERT_TRUE(base::PathExists(test_path))
- << test_path.LossyDisplayName();
-
- base::FilePath html_file = test_path.Append(base::FilePath(file_path));
- // Output the test path to help anyone who encounters a failure and needs
- // to know where to look.
- printf("Testing: %s\n", html_file.MaybeAsASCII().c_str());
-
- std::string html_contents;
- base::ReadFileToString(html_file, &html_contents);
-
- // Read the expected file.
- std::string expected_contents_raw;
- base::FilePath expected_file =
- base::FilePath(html_file.RemoveExtension().value() +
- AccessibilityTreeFormatter::GetExpectedFileSuffix());
- base::ReadFileToString(expected_file, &expected_contents_raw);
-
- // Tolerate Windows-style line endings (\r\n) in the expected file:
- // normalize by deleting all \r from the file (if any) to leave only \n.
- std::string expected_contents;
- base::RemoveChars(expected_contents_raw, "\r", &expected_contents);
-
- if (!expected_contents.compare(0, strlen(kMarkSkipFile), kMarkSkipFile)) {
- printf("Skipping this test on this platform.\n");
- return;
+ base::FilePath aria_file = test_path.Append(base::FilePath(file_path));
+ RunTest(aria_file, "accessibility/aria");
}
- // 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());
-
- // 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));
+ void RunHtmlTest(const base::FilePath::CharType* file_path) {
+ base::FilePath dir_test_data;
+ ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &dir_test_data));
+ base::FilePath test_path(dir_test_data.AppendASCII("accessibility")
+ .AppendASCII("html"));
+ ASSERT_TRUE(base::PathExists(test_path)) << test_path.LossyDisplayName();
+
+ base::FilePath html_file = test_path.Append(base::FilePath(file_path));
+ RunTest(html_file, "accessibility/html");
}
- // 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;
+ std::vector<std::string> Dump() override {
+ WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
+ shell()->web_contents());
AccessibilityTreeFormatter formatter(
web_contents->GetRootBrowserAccessibilityManager()->GetRoot());
- formatter.SetFilters(filters);
+ formatter.SetFilters(filters_);
+ base::string16 actual_contents_utf16;
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).
- std::vector<std::string> actual_lines, expected_lines;
- Tokenize(actual_contents, "\n", &actual_lines);
- Tokenize(expected_contents, "\n", &expected_lines);
- // Marking the end of the file with a line of text ensures that
- // file length differences are found.
- expected_lines.push_back(kMarkEndOfFile);
- actual_lines.push_back(kMarkEndOfFile);
-
- std::vector<int> diff_lines = DiffLines(expected_lines, actual_lines);
- bool is_different = diff_lines.size() > 0;
- EXPECT_FALSE(is_different);
- if (is_different) {
- // Mark the expected lines which did not match actual output with a *.
- printf("* Line Expected\n");
- printf("- ---- --------\n");
- for (int line = 0, diff_index = 0;
- line < static_cast<int>(expected_lines.size());
- ++line) {
- bool is_diff = false;
- if (diff_index < static_cast<int>(diff_lines.size()) &&
- diff_lines[diff_index] == line) {
- is_diff = true;
- ++diff_index;
- }
- printf("%1s %4d %s\n", is_diff? kSignalDiff : "", line + 1,
- expected_lines[line].c_str());
- }
- printf("\nActual\n");
- printf("------\n");
- printf("%s\n", actual_contents.c_str());
- }
-
- if (!base::PathExists(expected_file)) {
- base::FilePath actual_file =
- base::FilePath(html_file.RemoveExtension().value() +
- AccessibilityTreeFormatter::GetActualFileSuffix());
-
- EXPECT_TRUE(base::WriteFile(
- actual_file, actual_contents.c_str(), actual_contents.size()));
-
- ADD_FAILURE() << "No expectation found. Create it by doing:\n"
- << "mv " << actual_file.LossyDisplayName() << " "
- << expected_file.LossyDisplayName();
+ std::string actual_contents = base::UTF16ToUTF8(actual_contents_utf16);
+ std::vector<std::string> actual_lines;
+ Tokenize(actual_contents, "\n", &actual_lines);
+ return actual_lines;
}
-}
+};
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityA) {
- RunTest(FILE_PATH_LITERAL("a.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("a.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAbbr) {
- RunTest(FILE_PATH_LITERAL("abbr.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("abbr.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAddress) {
- RunTest(FILE_PATH_LITERAL("address.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("address.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityArea) {
- RunTest(FILE_PATH_LITERAL("area.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("area.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAName) {
- RunTest(FILE_PATH_LITERAL("a-name.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("a-name.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityANameCalc) {
- RunTest(FILE_PATH_LITERAL("a-name-calc.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("a-name-calc.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityANoText) {
- RunTest(FILE_PATH_LITERAL("a-no-text.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("a-no-text.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAOnclick) {
- RunTest(FILE_PATH_LITERAL("a-onclick.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("a-onclick.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityAriaActivedescendant) {
- RunTest(FILE_PATH_LITERAL("aria-activedescendant.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-activedescendant.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaAlert) {
- RunTest(FILE_PATH_LITERAL("aria-alert.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-alert.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ AccessibilityAriaAlertDialog) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-alertdialog.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityAriaApplication) {
- RunTest(FILE_PATH_LITERAL("aria-application.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-application.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaArticle) {
- RunTest(FILE_PATH_LITERAL("aria-article.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-article.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaAtomic) {
- RunTest(FILE_PATH_LITERAL("aria-atomic.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-atomic.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityAriaAutocomplete) {
- RunTest(FILE_PATH_LITERAL("aria-autocomplete.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-autocomplete.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaBanner) {
- RunTest(FILE_PATH_LITERAL("aria-banner.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-banner.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaBusy) {
- RunTest(FILE_PATH_LITERAL("aria-busy.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-busy.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaButton) {
- RunTest(FILE_PATH_LITERAL("aria-button.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-button.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaCheckBox) {
- RunTest(FILE_PATH_LITERAL("aria-checkbox.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-checkbox.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaChecked) {
- RunTest(FILE_PATH_LITERAL("aria-checked.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-checked.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityAriaColumnHeader) {
- RunTest(FILE_PATH_LITERAL("aria-columnheader.html"));
+ RunAriaTest(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,
DISABLED_AccessibilityAriaCombobox) {
- RunTest(FILE_PATH_LITERAL("aria-combobox.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-combobox.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityAriaComplementary) {
- RunTest(FILE_PATH_LITERAL("aria-complementary.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-complementary.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityAriaContentInfo) {
- RunTest(FILE_PATH_LITERAL("aria-contentinfo.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-contentinfo.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaControls) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-controls.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaDefinition) {
- RunTest(FILE_PATH_LITERAL("aria-definition.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-definition.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ AccessibilityAriaDescribedBy) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-describedby.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaDialog) {
- RunTest(FILE_PATH_LITERAL("aria-dialog.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-dialog.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaDirectory) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-directory.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaDisabled) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-disabled.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaDocument) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-document.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaDropEffect) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-dropeffect.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaExpanded) {
- RunTest(FILE_PATH_LITERAL("aria-expanded.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-expanded.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaHasPopup) {
- RunTest(FILE_PATH_LITERAL("aria-haspopup.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-haspopup.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaHeading) {
- RunTest(FILE_PATH_LITERAL("aria-heading.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-heading.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaHidden) {
- RunTest(FILE_PATH_LITERAL("aria-hidden.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-hidden.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
MAYBE(AccessibilityAriaFlowto)) {
- RunTest(FILE_PATH_LITERAL("aria-flowto.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-flowto.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaForm) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-form.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaGrabbed) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-grabbed.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaGrid) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-grid.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaGridCell) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-gridcell.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaGroup) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-group.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaImg) {
- RunTest(FILE_PATH_LITERAL("aria-img.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-img.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaInvalid) {
- RunTest(FILE_PATH_LITERAL("aria-invalid.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-invalid.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaLabel) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-label.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityAriaLabelledByHeading) {
- RunTest(FILE_PATH_LITERAL("aria-labelledby-heading.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-labelledby-heading.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaLevel) {
- RunTest(FILE_PATH_LITERAL("aria-level.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-level.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaLink) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-link.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaList) {
- RunTest(FILE_PATH_LITERAL("aria-list.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-list.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaListBox) {
- RunTest(FILE_PATH_LITERAL("aria-listbox.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-listbox.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityAriaListBoxActiveDescendant) {
- RunTest(FILE_PATH_LITERAL("aria-listbox-activedescendant.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-listbox-activedescendant.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityAriaListBoxAriaSelected) {
- RunTest(FILE_PATH_LITERAL("aria-listbox-aria-selected.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-listbox-aria-selected.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityAriaListBoxChildFocus) {
- RunTest(FILE_PATH_LITERAL("aria-listbox-childfocus.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-listbox-childfocus.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaListItem) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-listitem.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaLive) {
- RunTest(FILE_PATH_LITERAL("aria-live.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-live.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ AccessibilityAriaLiveWithContent) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-live-with-content.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaLog) {
- RunTest(FILE_PATH_LITERAL("aria-log.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-log.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaMain) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-main.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaMarquee) {
- RunTest(FILE_PATH_LITERAL("aria-marquee.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-marquee.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaMenu) {
- RunTest(FILE_PATH_LITERAL("aria-menu.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-menu.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaMenuBar) {
- RunTest(FILE_PATH_LITERAL("aria-menubar.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-menubar.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaMenuItem) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-menuitem.html"));
+}
+
+// crbug.com/442278 will stop creating new text elements representing title.
+// Re-baseline after the Blink change goes in
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ DISABLED_AccessibilityAriaMenuItemCheckBox) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-menuitemcheckbox.html"));
}
+// crbug.com/442278 will stop creating new text elements representing title.
+// Re-baseline after the Blink change goes in
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
- AccessibilityAriaMenuItemCheckBox) {
- RunTest(FILE_PATH_LITERAL("aria-menuitemcheckbox.html"));
+ DISABLED_AccessibilityAriaMenuItemRadio) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-menuitemradio.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaMultiline) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-multiline.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
- AccessibilityAriaMenuItemRadio) {
- RunTest(FILE_PATH_LITERAL("aria-menuitemradio.html"));
+ AccessibilityAriaMultiselectable) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-multiselectable.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaNavigation) {
- RunTest(FILE_PATH_LITERAL("aria-navigation.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-navigation.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaNote) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-note.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityAriaOrientation) {
- RunTest(FILE_PATH_LITERAL("aria-orientation.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-orientation.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaMath) {
- RunTest(FILE_PATH_LITERAL("aria-math.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-math.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaNone) {
- RunTest(FILE_PATH_LITERAL("aria-none.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-none.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaOption) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-option.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaPosinset) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-posinset.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityAriaPresentation) {
- RunTest(FILE_PATH_LITERAL("aria-presentation.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-presentation.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaPressed) {
- RunTest(FILE_PATH_LITERAL("aria-pressed.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-pressed.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityAriaProgressbar) {
- RunTest(FILE_PATH_LITERAL("aria-progressbar.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-progressbar.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaRadio) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-radio.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityAriaRadiogroup) {
- RunTest(FILE_PATH_LITERAL("aria-radiogroup.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-radiogroup.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaReadonly) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-readonly.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaRegion) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-region.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaRelevant) {
- RunTest(FILE_PATH_LITERAL("aria-relevant.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-relevant.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaRequired) {
- RunTest(FILE_PATH_LITERAL("aria-required.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-required.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaRow) {
- RunTest(FILE_PATH_LITERAL("aria-row.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-row.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaRowGroup) {
- RunTest(FILE_PATH_LITERAL("aria-rowgroup.html"));
+ RunAriaTest(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, AccessibilityAriaRowHeader) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-rowheader.html"));
}
-IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaRegion) {
- RunTest(FILE_PATH_LITERAL("aria-region.html"));
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaScrollbar) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-scrollbar.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaSearch) {
- RunTest(FILE_PATH_LITERAL("aria-search.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-search.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaSearchBox) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-searchbox.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaSelected) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-selected.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaSeparator) {
- RunTest(FILE_PATH_LITERAL("aria-separator.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-separator.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaSetsize) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-setsize.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaSlider) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-slider.html"));
}
-IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaSort) {
- RunTest(FILE_PATH_LITERAL("aria-sort.html"));
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ AccessibilityAriaSortOnAriaGrid) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-sort-aria-grid.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ AccessibilityAriaSortOnHtmlTable) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-sort-html-table.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityAriaSpinButton) {
- RunTest(FILE_PATH_LITERAL("aria-spinbutton.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-spinbutton.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaStatus) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-status.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaSwitch) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-switch.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaTab) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-tab.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaTabList) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-tablist.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaTabPanel) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-tabpanel.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaTextbox) {
- RunTest(FILE_PATH_LITERAL("aria-textbox.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-textbox.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaTimer) {
- RunTest(FILE_PATH_LITERAL("aria-timer.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-timer.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityAriaToggleButton) {
- RunTest(FILE_PATH_LITERAL("aria-togglebutton.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-togglebutton.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaToolbar) {
- RunTest(FILE_PATH_LITERAL("aria-toolbar.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-toolbar.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaTooltip) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-tooltip.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaTree) {
- RunTest(FILE_PATH_LITERAL("aria-tree.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-tree.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaTreeGrid) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-treegrid.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaValueMin) {
- RunTest(FILE_PATH_LITERAL("aria-valuemin.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-valuemin.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaValueMax) {
- RunTest(FILE_PATH_LITERAL("aria-valuemax.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-valuemax.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaValueNow) {
- RunTest(FILE_PATH_LITERAL("aria-valuenow.html"));
+ RunAriaTest(FILE_PATH_LITERAL("aria-valuenow.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaValueText) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-valuetext.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityArticle) {
- RunTest(FILE_PATH_LITERAL("article.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("article.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAside) {
- RunTest(FILE_PATH_LITERAL("aside.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("aside.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAudio) {
- RunTest(FILE_PATH_LITERAL("audio.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("audio.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAWithImg) {
- RunTest(FILE_PATH_LITERAL("a-with-img.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("a-with-img.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityB) {
+ RunHtmlTest(FILE_PATH_LITERAL("b.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityBase) {
+ RunHtmlTest(FILE_PATH_LITERAL("base.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityBdo) {
- RunTest(FILE_PATH_LITERAL("bdo.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("bdo.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityBlockquote) {
- RunTest(FILE_PATH_LITERAL("blockquote.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("blockquote.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityBody) {
- RunTest(FILE_PATH_LITERAL("body.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("body.html"));
}
-IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityBR) {
- RunTest(FILE_PATH_LITERAL("br.html"));
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, DISABLED_AccessibilityBR) {
+ RunHtmlTest(FILE_PATH_LITERAL("br.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityButton) {
- RunTest(FILE_PATH_LITERAL("button.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("button.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityButtonNameCalc) {
- RunTest(FILE_PATH_LITERAL("button-name-calc.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("button-name-calc.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityCanvas) {
- RunTest(FILE_PATH_LITERAL("canvas.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("canvas.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityCaption) {
- RunTest(FILE_PATH_LITERAL("caption.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("caption.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityCheckboxNameCalc) {
- RunTest(FILE_PATH_LITERAL("checkbox-name-calc.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("checkbox-name-calc.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityCite) {
- RunTest(FILE_PATH_LITERAL("cite.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("cite.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityCode) {
+ RunHtmlTest(FILE_PATH_LITERAL("code.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityCol) {
- RunTest(FILE_PATH_LITERAL("col.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("col.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityColgroup) {
- RunTest(FILE_PATH_LITERAL("colgroup.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("colgroup.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityDd) {
+ RunHtmlTest(FILE_PATH_LITERAL("dd.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityDel) {
- RunTest(FILE_PATH_LITERAL("del.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("del.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityDetails) {
- RunTest(FILE_PATH_LITERAL("details.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("details.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityDfn) {
- RunTest(FILE_PATH_LITERAL("dfn.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("dfn.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityDialog) {
- RunTest(FILE_PATH_LITERAL("dialog.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("dialog.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityDiv) {
- RunTest(FILE_PATH_LITERAL("div.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("div.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityDl) {
- RunTest(FILE_PATH_LITERAL("dl.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("dl.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityDt) {
- RunTest(FILE_PATH_LITERAL("dt.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("dt.html"));
}
-//Disabled because of https://codereview.chromium.org/696953002 temporarily.
-//After blink code is merged, it will be enabled.
+#if defined(OS_ANDROID)
+// Flaky failures: http://crbug.com/445929.
+#define MAYBE_AccessibilityContenteditableDescendants \
+ DISABLED_AccessibilityContenteditableDescendants
+#else
+#define MAYBE_AccessibilityContenteditableDescendants \
+ AccessibilityContenteditableDescendants
+#endif
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
DISABLED_AccessibilityContenteditableDescendants) {
- RunTest(FILE_PATH_LITERAL("contenteditable-descendants.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("contenteditable-descendants.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityEm) {
- RunTest(FILE_PATH_LITERAL("em.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("em.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityEmbed) {
+ RunHtmlTest(FILE_PATH_LITERAL("embed.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityFieldset) {
- RunTest(FILE_PATH_LITERAL("fieldset.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("fieldset.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityFigcaption) {
- RunTest(FILE_PATH_LITERAL("figcaption.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("figcaption.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityFigure) {
- RunTest(FILE_PATH_LITERAL("figure.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("figure.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityFooter) {
- RunTest(FILE_PATH_LITERAL("footer.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("footer.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityForm) {
- RunTest(FILE_PATH_LITERAL("form.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("form.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityFrameset) {
- RunTest(FILE_PATH_LITERAL("frameset.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("frameset.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityHead) {
- RunTest(FILE_PATH_LITERAL("head.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("head.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityHeader) {
- RunTest(FILE_PATH_LITERAL("header.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("header.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityHeading) {
- RunTest(FILE_PATH_LITERAL("heading.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("heading.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityHR) {
- RunTest(FILE_PATH_LITERAL("hr.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("hr.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityHTML) {
+ RunHtmlTest(FILE_PATH_LITERAL("html.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityI) {
- RunTest(FILE_PATH_LITERAL("i.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("i.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityIframe) {
- RunTest(FILE_PATH_LITERAL("iframe.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("iframe.html"));
}
+// Flaky. See http://crbug.com/224659.
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
- AccessibilityIframeCoordinates) {
- RunTest(FILE_PATH_LITERAL("iframe-coordinates.html"));
+ DISABLED_AccessibilityIframeCoordinates) {
+ RunHtmlTest(FILE_PATH_LITERAL("iframe-coordinates.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ AccessibilityIframePresentational) {
+ RunHtmlTest(FILE_PATH_LITERAL("iframe-presentational.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityImg) {
- RunTest(FILE_PATH_LITERAL("img.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("img.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputButton) {
- RunTest(FILE_PATH_LITERAL("input-button.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("input-button.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityInputButtonInMenu) {
- RunTest(FILE_PATH_LITERAL("input-button-in-menu.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("input-button-in-menu.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputCheckBox) {
- RunTest(FILE_PATH_LITERAL("input-checkbox.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("input-checkbox.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityInputCheckBoxInMenu) {
- RunTest(FILE_PATH_LITERAL("input-checkbox-in-menu.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("input-checkbox-in-menu.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputColor) {
- RunTest(FILE_PATH_LITERAL("input-color.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("input-color.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputDate) {
- RunTest(FILE_PATH_LITERAL("input-date.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("input-date.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputDateTime) {
- RunTest(FILE_PATH_LITERAL("input-datetime.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("input-datetime.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
@@ -798,298 +810,363 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
if (base::mac::IsOSMavericks())
return;
#endif
- RunTest(FILE_PATH_LITERAL("input-datetime-local.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("input-datetime-local.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputEmail) {
+ RunHtmlTest(FILE_PATH_LITERAL("input-email.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputFile) {
+ RunHtmlTest(FILE_PATH_LITERAL("input-file.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputHidden) {
+ RunHtmlTest(FILE_PATH_LITERAL("input-hidden.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputImage) {
+ RunHtmlTest(FILE_PATH_LITERAL("input-image.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityInputImageButtonInMenu) {
- RunTest(FILE_PATH_LITERAL("input-image-button-in-menu.html"));
+ RunHtmlTest(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"));
+ RunHtmlTest(FILE_PATH_LITERAL("input-month.html"));
}
#else
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputMonth) {
- RunTest(FILE_PATH_LITERAL("input-month.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("input-month.html"));
}
#endif
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputPassword) {
+ RunHtmlTest(FILE_PATH_LITERAL("input-password.html"));
+}
+
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputRadio) {
- RunTest(FILE_PATH_LITERAL("input-radio.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("input-radio.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ AccessibilityInputRadioInMenu) {
+ RunHtmlTest(FILE_PATH_LITERAL("input-radio-in-menu.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputRange) {
- RunTest(FILE_PATH_LITERAL("input-range.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("input-range.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputReset) {
- RunTest(FILE_PATH_LITERAL("input-reset.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("input-reset.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputSearch) {
- RunTest(FILE_PATH_LITERAL("input-search.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("input-search.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilitySmall) {
+ RunHtmlTest(FILE_PATH_LITERAL("small.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputSubmit) {
- RunTest(FILE_PATH_LITERAL("input-submit.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("input-submit.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ AccessibilityInputSuggestionsSourceElement) {
+ RunHtmlTest(FILE_PATH_LITERAL("input-suggestions-source-element.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputTel) {
- RunTest(FILE_PATH_LITERAL("input-tel.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("input-tel.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputText) {
- RunTest(FILE_PATH_LITERAL("input-text.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("input-text.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityInputTextNameCalc) {
- RunTest(FILE_PATH_LITERAL("input-text-name-calc.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("input-text-name-calc.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputTextValue) {
- RunTest(FILE_PATH_LITERAL("input-text-value.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("input-text-value.html"));
}
-IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputTime) {
- RunTest(FILE_PATH_LITERAL("input-time.html"));
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ DISABLED_AccessibilityInputTime) {
+ RunHtmlTest(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,
- AccessibilityInputTypes) {
- RunTest(FILE_PATH_LITERAL("input-types.html"));
+ DISABLED_AccessibilityInputTypes) {
+ RunHtmlTest(FILE_PATH_LITERAL("input-types.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputUrl) {
- RunTest(FILE_PATH_LITERAL("input-url.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("input-url.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputWeek) {
- RunTest(FILE_PATH_LITERAL("input-week.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("input-week.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityIns) {
- RunTest(FILE_PATH_LITERAL("ins.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("ins.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityKeygen) {
+ RunHtmlTest(FILE_PATH_LITERAL("keygen.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityLabel) {
- RunTest(FILE_PATH_LITERAL("label.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("label.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityLandmark) {
- RunTest(FILE_PATH_LITERAL("landmark.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("landmark.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityLegend) {
- RunTest(FILE_PATH_LITERAL("legend.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("legend.html"));
}
-IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityLink) {
- RunTest(FILE_PATH_LITERAL("link.html"));
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityLi) {
+ RunHtmlTest(FILE_PATH_LITERAL("li.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"));
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityLink) {
+ RunHtmlTest(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_AccessibilityListMarkers) {
- RunTest(FILE_PATH_LITERAL("list-markers.html"));
+ AccessibilityLinkInsideHeading) {
+ RunHtmlTest(FILE_PATH_LITERAL("link-inside-heading.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityList) {
+ RunHtmlTest(FILE_PATH_LITERAL("list.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityListMarkers) {
+ RunHtmlTest(FILE_PATH_LITERAL("list-markers.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityMain) {
- RunTest(FILE_PATH_LITERAL("main.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("main.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityMark) {
- RunTest(FILE_PATH_LITERAL("mark.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("mark.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityMath) {
- RunTest(FILE_PATH_LITERAL("math.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("math.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityMenutypecontext) {
- RunTest(FILE_PATH_LITERAL("menu-type-context.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("menu-type-context.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityMeta) {
- RunTest(FILE_PATH_LITERAL("meta.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("meta.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityMeter) {
- RunTest(FILE_PATH_LITERAL("meter.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("meter.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityModalDialogClosed) {
- RunTest(FILE_PATH_LITERAL("modal-dialog-closed.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("modal-dialog-closed.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityModalDialogOpened) {
- RunTest(FILE_PATH_LITERAL("modal-dialog-opened.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("modal-dialog-opened.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityModalDialogInIframeClosed) {
- RunTest(FILE_PATH_LITERAL("modal-dialog-in-iframe-closed.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("modal-dialog-in-iframe-closed.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityModalDialogInIframeOpened) {
- RunTest(FILE_PATH_LITERAL("modal-dialog-in-iframe-opened.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("modal-dialog-in-iframe-opened.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityModalDialogStack) {
- RunTest(FILE_PATH_LITERAL("modal-dialog-stack.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("modal-dialog-stack.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityNavigation) {
- RunTest(FILE_PATH_LITERAL("navigation.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("navigation.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityNoscript) {
- RunTest(FILE_PATH_LITERAL("noscript.html"));
+ RunHtmlTest(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, AccessibilityOl) {
+ RunHtmlTest(FILE_PATH_LITERAL("ol.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityObject) {
- RunTest(FILE_PATH_LITERAL("object.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("object.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityOptgroup) {
+ RunHtmlTest(FILE_PATH_LITERAL("optgroup.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityOptionindatalist) {
- RunTest(FILE_PATH_LITERAL("option-in-datalist.html"));
+ RunHtmlTest(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,
+ DISABLED_AccessibilityOutput) {
+ RunHtmlTest(FILE_PATH_LITERAL("output.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityP) {
- RunTest(FILE_PATH_LITERAL("p.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("p.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityParam) {
- RunTest(FILE_PATH_LITERAL("param.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("param.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityPre) {
- RunTest(FILE_PATH_LITERAL("pre.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("pre.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityProgress) {
- RunTest(FILE_PATH_LITERAL("progress.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("progress.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityQ) {
- RunTest(FILE_PATH_LITERAL("q.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("q.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityRuby) {
+ RunHtmlTest(FILE_PATH_LITERAL("ruby.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityS) {
- RunTest(FILE_PATH_LITERAL("s.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("s.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilitySamp) {
- RunTest(FILE_PATH_LITERAL("samp.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("samp.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityScript) {
+ RunHtmlTest(FILE_PATH_LITERAL("script.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilitySection) {
- RunTest(FILE_PATH_LITERAL("section.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("section.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilitySelect) {
- RunTest(FILE_PATH_LITERAL("select.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("select.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilitySource) {
- RunTest(FILE_PATH_LITERAL("source.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("source.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilitySpan) {
- RunTest(FILE_PATH_LITERAL("span.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("span.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityStrong) {
+ RunHtmlTest(FILE_PATH_LITERAL("strong.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityStyle) {
+ RunHtmlTest(FILE_PATH_LITERAL("style.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilitySub) {
- RunTest(FILE_PATH_LITERAL("sub.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("sub.html"));
}
-IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilitySummary) {
- RunTest(FILE_PATH_LITERAL("summary.html"));
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilitySup) {
+ RunHtmlTest(FILE_PATH_LITERAL("sup.html"));
}
-IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilitySvg) {
- RunTest(FILE_PATH_LITERAL("svg.html"));
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilitySummary) {
+ RunHtmlTest(FILE_PATH_LITERAL("summary.html"));
}
-IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityTab) {
- RunTest(FILE_PATH_LITERAL("tab.html"));
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilitySvg) {
+ RunHtmlTest(FILE_PATH_LITERAL("svg.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityTableSimple) {
- RunTest(FILE_PATH_LITERAL("table-simple.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("table-simple.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
- AccessibilityTableThRowHeader) {
- RunTest(FILE_PATH_LITERAL("table-th-rowheader.html"));
+ AccessibilityTableThRowHeader) {
+ RunHtmlTest(FILE_PATH_LITERAL("table-th-rowheader.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
- AccessibilityTableTbodyTfoot) {
- RunTest(FILE_PATH_LITERAL("table-thead-tbody-tfoot.html"));
+ AccessibilityTableTbodyTfoot) {
+ RunHtmlTest(FILE_PATH_LITERAL("table-thead-tbody-tfoot.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityTableSpans) {
- RunTest(FILE_PATH_LITERAL("table-spans.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("table-spans.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityTextArea) {
- RunTest(FILE_PATH_LITERAL("textarea.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("textarea.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityTime) {
- RunTest(FILE_PATH_LITERAL("time.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("time.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityTitle) {
- RunTest(FILE_PATH_LITERAL("title.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("title.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityTransition) {
- RunTest(FILE_PATH_LITERAL("transition.html"));
+ RunHtmlTest(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, AccessibilityUl) {
+ RunHtmlTest(FILE_PATH_LITERAL("ul.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityVar) {
- RunTest(FILE_PATH_LITERAL("var.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("var.html"));
+}
+
+// crbug.com/281952
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, DISABLED_AccessibilityVideo) {
+ RunHtmlTest(FILE_PATH_LITERAL("video.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityWbr) {
- RunTest(FILE_PATH_LITERAL("wbr.html"));
+ RunHtmlTest(FILE_PATH_LITERAL("wbr.html"));
}
} // namespace content
diff --git a/chromium/content/browser/accessibility/one_shot_accessibility_tree_search.cc b/chromium/content/browser/accessibility/one_shot_accessibility_tree_search.cc
new file mode 100644
index 00000000000..a0b85f9e3ff
--- /dev/null
+++ b/chromium/content/browser/accessibility/one_shot_accessibility_tree_search.cc
@@ -0,0 +1,182 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/accessibility/one_shot_accessibility_tree_search.h"
+
+#include "base/i18n/case_conversion.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/browser/accessibility/browser_accessibility.h"
+#include "content/browser/accessibility/browser_accessibility_manager.h"
+
+namespace content {
+
+// Given a node, populate a vector with all of the strings from that node's
+// attributes that might be relevant for a text search.
+void GetNodeStrings(BrowserAccessibility* node,
+ std::vector<base::string16>* strings) {
+ if (node->HasStringAttribute(ui::AX_ATTR_NAME))
+ strings->push_back(node->GetString16Attribute(ui::AX_ATTR_NAME));
+ if (node->HasStringAttribute(ui::AX_ATTR_DESCRIPTION))
+ strings->push_back(node->GetString16Attribute(ui::AX_ATTR_DESCRIPTION));
+ if (node->HasStringAttribute(ui::AX_ATTR_HELP))
+ strings->push_back(node->GetString16Attribute(ui::AX_ATTR_HELP));
+ if (node->HasStringAttribute(ui::AX_ATTR_VALUE))
+ strings->push_back(node->GetString16Attribute(ui::AX_ATTR_VALUE));
+ if (node->HasStringAttribute(ui::AX_ATTR_PLACEHOLDER))
+ strings->push_back(node->GetString16Attribute(ui::AX_ATTR_PLACEHOLDER));
+}
+
+OneShotAccessibilityTreeSearch::OneShotAccessibilityTreeSearch(
+ BrowserAccessibilityManager* tree)
+ : tree_(tree),
+ start_node_(nullptr),
+ direction_(OneShotAccessibilityTreeSearch::FORWARDS),
+ result_limit_(UNLIMITED_RESULTS),
+ immediate_descendants_only_(false),
+ visible_only_(false),
+ did_search_(false) {
+}
+
+OneShotAccessibilityTreeSearch::~OneShotAccessibilityTreeSearch() {
+}
+
+void OneShotAccessibilityTreeSearch::SetStartNode(
+ BrowserAccessibility* start_node) {
+ DCHECK(!did_search_);
+ start_node_ = start_node;
+}
+
+void OneShotAccessibilityTreeSearch::SetDirection(Direction direction) {
+ DCHECK(!did_search_);
+ direction_ = direction;
+}
+
+void OneShotAccessibilityTreeSearch::SetResultLimit(int result_limit) {
+ DCHECK(!did_search_);
+ result_limit_ = result_limit;
+}
+
+void OneShotAccessibilityTreeSearch::SetImmediateDescendantsOnly(
+ bool immediate_descendants_only) {
+ DCHECK(!did_search_);
+ immediate_descendants_only_ = immediate_descendants_only;
+}
+
+void OneShotAccessibilityTreeSearch::SetVisibleOnly(bool visible_only) {
+ DCHECK(!did_search_);
+ visible_only_ = visible_only;
+}
+
+void OneShotAccessibilityTreeSearch::SetSearchText(const std::string& text) {
+ DCHECK(!did_search_);
+ search_text_ = text;
+}
+
+void OneShotAccessibilityTreeSearch::AddPredicate(
+ AccessibilityMatchPredicate predicate) {
+ DCHECK(!did_search_);
+ predicates_.push_back(predicate);
+}
+
+size_t OneShotAccessibilityTreeSearch::CountMatches() {
+ if (!did_search_)
+ Search();
+
+ return matches_.size();
+}
+
+BrowserAccessibility* OneShotAccessibilityTreeSearch::GetMatchAtIndex(
+ size_t index) {
+ if (!did_search_)
+ Search();
+
+ CHECK(index < matches_.size());
+ return matches_[index];
+}
+
+void OneShotAccessibilityTreeSearch::Search()
+{
+ if (immediate_descendants_only_) {
+ SearchByIteratingOverChildren();
+ } else {
+ SearchByWalkingTree();
+ }
+}
+
+void OneShotAccessibilityTreeSearch::SearchByIteratingOverChildren() {
+ if (!start_node_)
+ return;
+
+ for (unsigned i = 0;
+ i < start_node_->PlatformChildCount() &&
+ (result_limit_ == UNLIMITED_RESULTS ||
+ static_cast<int>(matches_.size()) < result_limit_);
+ ++i) {
+ BrowserAccessibility* child = start_node_->PlatformGetChild(i);
+ if (Matches(child))
+ matches_.push_back(child);
+ }
+}
+
+void OneShotAccessibilityTreeSearch::SearchByWalkingTree() {
+ BrowserAccessibility* node = nullptr;
+ if (start_node_) {
+ if (direction_ == FORWARDS)
+ node = tree_->NextInTreeOrder(start_node_);
+ else
+ node = tree_->PreviousInTreeOrder(start_node_);
+ } else {
+ start_node_ = tree_->GetRoot();
+ node = start_node_;
+ }
+
+ while (node && (result_limit_ == UNLIMITED_RESULTS ||
+ static_cast<int>(matches_.size()) < result_limit_)) {
+ if (Matches(node))
+ matches_.push_back(node);
+
+ if (direction_ == FORWARDS)
+ node = tree_->NextInTreeOrder(node);
+ else
+ node = tree_->PreviousInTreeOrder(node);
+ }
+}
+
+bool OneShotAccessibilityTreeSearch::Matches(BrowserAccessibility* node) {
+ for (size_t i = 0; i < predicates_.size(); ++i) {
+ if (!predicates_[i](start_node_, node))
+ return false;
+ }
+
+ if (visible_only_) {
+ if (node->HasState(ui::AX_STATE_INVISIBLE) ||
+ node->HasState(ui::AX_STATE_OFFSCREEN)) {
+ return false;
+ }
+ }
+
+ if (!search_text_.empty()) {
+ base::string16 search_text_lower =
+ base::i18n::ToLower(base::UTF8ToUTF16(search_text_));
+ std::vector<base::string16> node_strings;
+ GetNodeStrings(node, &node_strings);
+ bool found_text_match = false;
+ for (size_t i = 0; i < node_strings.size(); ++i) {
+ base::string16 node_string_lower =
+ base::i18n::ToLower(node_strings[i]);
+ if (node_string_lower.find(search_text_lower) !=
+ base::string16::npos) {
+ found_text_match = true;
+ break;
+ }
+ }
+ if (!found_text_match)
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/accessibility/one_shot_accessibility_tree_search.h b/chromium/content/browser/accessibility/one_shot_accessibility_tree_search.h
new file mode 100644
index 00000000000..f1c8012cefa
--- /dev/null
+++ b/chromium/content/browser/accessibility/one_shot_accessibility_tree_search.h
@@ -0,0 +1,105 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_ACCESSIBILITY_ACCESSIBILITY_TREE_SEARCH_H_
+#define CONTENT_BROWSER_ACCESSIBILITY_ACCESSIBILITY_TREE_SEARCH_H_
+
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "content/common/content_export.h"
+
+namespace content {
+
+class BrowserAccessibility;
+class BrowserAccessibilityManager;
+
+// A function that returns whether or not a given node matches, given the
+// start element of the search as an optional comparator.
+typedef bool (*AccessibilityMatchPredicate)(
+ BrowserAccessibility* start_element,
+ BrowserAccessibility* this_element);
+
+// This class provides an interface for searching the accessibility tree from
+// a given starting node, with a few built-in options and allowing an arbitrary
+// number of predicates that can be used to restrict the search.
+//
+// This class is meant to perform one search. Initialize it, then iterate
+// over the matches, and then delete it.
+//
+// This class stores raw pointers to the matches in the tree! Don't keep this
+// object around if the tree is mutating.
+class CONTENT_EXPORT OneShotAccessibilityTreeSearch {
+ public:
+ enum Direction { FORWARDS, BACKWARDS };
+
+ const int UNLIMITED_RESULTS = -1;
+
+ OneShotAccessibilityTreeSearch(BrowserAccessibilityManager* tree);
+ virtual ~OneShotAccessibilityTreeSearch();
+
+ //
+ // Search parameters. All of these are optional.
+ //
+
+ // Sets the node where the search starts. The first potential match will
+ // be the one immediately following this one. This node will be used as
+ // the first arguement to any predicates.
+ void SetStartNode(BrowserAccessibility* start_node);
+
+ // Search forwards or backwards in an in-order traversal of the tree.
+ void SetDirection(Direction direction);
+
+ // Set the maximum number of results, or UNLIMITED_RESULTS
+ // for no limit (default).
+ void SetResultLimit(int result_limit);
+
+ // If true, only searches children of |start_node| and doesn't
+ // recurse.
+ void SetImmediateDescendantsOnly(bool immediate_descendants_only);
+
+ // If true, only considers nodes that aren't invisible or offscreen.
+ void SetVisibleOnly(bool visible_only);
+
+ // Restricts the matches to only nodes where |text| is found as a
+ // substring of any of that node's accessible text, including its
+ // name, description, or value. Case-insensitive.
+ void SetSearchText(const std::string& text);
+
+ // Restricts the matches to only those that satisfy all predicates.
+ void AddPredicate(AccessibilityMatchPredicate predicate);
+
+ //
+ // Calling either of these executes the search.
+ //
+
+ size_t CountMatches();
+ BrowserAccessibility* GetMatchAtIndex(size_t index);
+
+ private:
+ void Search();
+ void SearchByWalkingTree();
+ void SearchByIteratingOverChildren();
+ bool Matches(BrowserAccessibility* node);
+
+ BrowserAccessibilityManager* tree_;
+ BrowserAccessibility* start_node_;
+ Direction direction_;
+ int result_limit_;
+ bool immediate_descendants_only_;
+ bool visible_only_;
+ std::string search_text_;
+
+ std::vector<AccessibilityMatchPredicate> predicates_;
+ std::vector<BrowserAccessibility*> matches_;
+
+ bool did_search_;
+
+ DISALLOW_COPY_AND_ASSIGN(OneShotAccessibilityTreeSearch);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_ACCESSIBILITY_ACCESSIBILITY_TREE_SEARCH_H_
diff --git a/chromium/content/browser/accessibility/one_shot_accessibility_tree_search_unittest.cc b/chromium/content/browser/accessibility/one_shot_accessibility_tree_search_unittest.cc
new file mode 100644
index 00000000000..abc5112bea8
--- /dev/null
+++ b/chromium/content/browser/accessibility/one_shot_accessibility_tree_search_unittest.cc
@@ -0,0 +1,174 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/scoped_ptr.h"
+#include "content/browser/accessibility/browser_accessibility.h"
+#include "content/browser/accessibility/browser_accessibility_manager.h"
+#include "content/browser/accessibility/one_shot_accessibility_tree_search.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+namespace {
+
+class TestBrowserAccessibilityManager : public BrowserAccessibilityManager {
+ public:
+ TestBrowserAccessibilityManager(const ui::AXTreeUpdate& initial_tree)
+ : BrowserAccessibilityManager(initial_tree,
+ nullptr,
+ new BrowserAccessibilityFactory()) {}
+};
+
+} // namespace
+
+class OneShotAccessibilityTreeSearchTest : public testing::Test {
+ public:
+ OneShotAccessibilityTreeSearchTest() {}
+ ~OneShotAccessibilityTreeSearchTest() override {}
+
+ protected:
+ void SetUp() override;
+
+ scoped_ptr<BrowserAccessibilityManager> tree_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(OneShotAccessibilityTreeSearchTest);
+};
+
+void OneShotAccessibilityTreeSearchTest::SetUp() {
+ ui::AXNodeData root;
+ root.id = 1;
+ root.SetName("Document");
+ root.role = ui::AX_ROLE_ROOT_WEB_AREA;
+ root.state = 0;
+ root.child_ids.push_back(2);
+ root.child_ids.push_back(3);
+ root.child_ids.push_back(6);
+
+ ui::AXNodeData heading;
+ heading.id = 2;
+ heading.SetName("Heading");
+ heading.role = ui::AX_ROLE_HEADING;
+ heading.state = 0;
+
+ ui::AXNodeData list;
+ list.id = 3;
+ list.role = ui::AX_ROLE_LIST;
+ list.state = 0;
+ list.child_ids.push_back(4);
+ list.child_ids.push_back(5);
+
+ ui::AXNodeData list_item_1;
+ list_item_1.id = 4;
+ list_item_1.SetName("Autobots");
+ list_item_1.role = ui::AX_ROLE_LIST_ITEM;
+ list_item_1.state = 0;
+
+ ui::AXNodeData list_item_2;
+ list_item_2.id = 5;
+ list_item_2.SetName("Decepticons");
+ list_item_2.role = ui::AX_ROLE_LIST_ITEM;
+ list_item_2.state = 0;
+
+ ui::AXNodeData footer;
+ footer.id = 6;
+ footer.SetName("Footer");
+ footer.role = ui::AX_ROLE_FOOTER;
+ footer.state = 1 << ui::AX_STATE_OFFSCREEN;
+
+ tree_.reset(new TestBrowserAccessibilityManager(
+ MakeAXTreeUpdate(root, heading, list, list_item_1, list_item_2, footer)));
+}
+
+TEST_F(OneShotAccessibilityTreeSearchTest, GetAll) {
+ OneShotAccessibilityTreeSearch search(tree_.get());
+ ASSERT_EQ(6U, search.CountMatches());
+}
+
+TEST_F(OneShotAccessibilityTreeSearchTest, ForwardsWithStartNode) {
+ OneShotAccessibilityTreeSearch search(tree_.get());
+ search.SetStartNode(tree_->GetFromID(4));
+ ASSERT_EQ(2U, search.CountMatches());
+ EXPECT_EQ(5, search.GetMatchAtIndex(0)->GetId());
+ EXPECT_EQ(6, search.GetMatchAtIndex(1)->GetId());
+}
+
+TEST_F(OneShotAccessibilityTreeSearchTest, BackwardsWithStartNode) {
+ OneShotAccessibilityTreeSearch search(tree_.get());
+ search.SetStartNode(tree_->GetFromID(4));
+ search.SetDirection(OneShotAccessibilityTreeSearch::BACKWARDS);
+ ASSERT_EQ(3U, search.CountMatches());
+ EXPECT_EQ(3, search.GetMatchAtIndex(0)->GetId());
+ EXPECT_EQ(2, search.GetMatchAtIndex(1)->GetId());
+ EXPECT_EQ(1, search.GetMatchAtIndex(2)->GetId());
+}
+
+TEST_F(OneShotAccessibilityTreeSearchTest, ResultLimitZero) {
+ OneShotAccessibilityTreeSearch search(tree_.get());
+ search.SetResultLimit(0);
+ ASSERT_EQ(0U, search.CountMatches());
+}
+
+TEST_F(OneShotAccessibilityTreeSearchTest, ResultLimitFive) {
+ OneShotAccessibilityTreeSearch search(tree_.get());
+ search.SetResultLimit(5);
+ ASSERT_EQ(5U, search.CountMatches());
+}
+
+TEST_F(OneShotAccessibilityTreeSearchTest, DescendantsOnly) {
+ OneShotAccessibilityTreeSearch search(tree_.get());
+ search.SetStartNode(tree_->GetFromID(1));
+ search.SetImmediateDescendantsOnly(true);
+ ASSERT_EQ(3U, search.CountMatches());
+ EXPECT_EQ(2, search.GetMatchAtIndex(0)->GetId());
+ EXPECT_EQ(3, search.GetMatchAtIndex(1)->GetId());
+ EXPECT_EQ(6, search.GetMatchAtIndex(2)->GetId());
+}
+
+TEST_F(OneShotAccessibilityTreeSearchTest, VisibleOnly) {
+ OneShotAccessibilityTreeSearch search(tree_.get());
+ search.SetVisibleOnly(true);
+ ASSERT_EQ(5U, search.CountMatches());
+ EXPECT_EQ(1, search.GetMatchAtIndex(0)->GetId());
+ EXPECT_EQ(2, search.GetMatchAtIndex(1)->GetId());
+ EXPECT_EQ(3, search.GetMatchAtIndex(2)->GetId());
+ EXPECT_EQ(4, search.GetMatchAtIndex(3)->GetId());
+ EXPECT_EQ(5, search.GetMatchAtIndex(4)->GetId());
+}
+
+TEST_F(OneShotAccessibilityTreeSearchTest, CaseInsensitiveStringMatch) {
+ OneShotAccessibilityTreeSearch search(tree_.get());
+ search.SetSearchText("eCEptiCOn");
+ ASSERT_EQ(1U, search.CountMatches());
+ EXPECT_EQ(5, search.GetMatchAtIndex(0)->GetId());
+}
+
+TEST_F(OneShotAccessibilityTreeSearchTest, OnePredicate) {
+ OneShotAccessibilityTreeSearch search(tree_.get());
+ search.AddPredicate([](BrowserAccessibility* start,
+ BrowserAccessibility* current) {
+ return current->GetRole() == ui::AX_ROLE_LIST_ITEM;
+ });
+ ASSERT_EQ(2U, search.CountMatches());
+ EXPECT_EQ(4, search.GetMatchAtIndex(0)->GetId());
+ EXPECT_EQ(5, search.GetMatchAtIndex(1)->GetId());
+}
+
+TEST_F(OneShotAccessibilityTreeSearchTest, TwoPredicates) {
+ OneShotAccessibilityTreeSearch search(tree_.get());
+ search.AddPredicate([](BrowserAccessibility* start,
+ BrowserAccessibility* current) {
+ return (current->GetRole() == ui::AX_ROLE_LIST ||
+ current->GetRole() == ui::AX_ROLE_LIST_ITEM);
+ });
+ search.AddPredicate([](BrowserAccessibility* start,
+ BrowserAccessibility* current) {
+ return (current->GetId() % 2 == 1);
+ });
+ ASSERT_EQ(2U, search.CountMatches());
+ EXPECT_EQ(3, search.GetMatchAtIndex(0)->GetId());
+ EXPECT_EQ(5, search.GetMatchAtIndex(1)->GetId());
+}
+
+} // 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
index 12cdc89376c..bf9c189a202 100644
--- a/chromium/content/browser/accessibility/site_per_process_accessibility_browsertest.cc
+++ b/chromium/content/browser/accessibility/site_per_process_accessibility_browsertest.cc
@@ -4,6 +4,7 @@
#include "base/command_line.h"
#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.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"
@@ -28,6 +29,7 @@
#include "content/test/content_browser_test_utils_internal.h"
#include "net/dns/mock_host_resolver.h"
#include "url/gurl.h"
+#include "url/url_constants.h"
namespace content {
@@ -37,13 +39,19 @@ class SitePerProcessAccessibilityBrowserTest
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
+// Utility function to determine if an accessibility tree has finished loading
+// or if the tree represents a page that hasn't finished loading yet.
+bool AccessibilityTreeIsLoaded(BrowserAccessibilityManager* manager) {
+ BrowserAccessibility* root = manager->GetRoot();
+ return (root->GetFloatAttribute(ui::AX_ATTR_DOC_LOADING_PROGRESS) == 1.0 &&
+ root->GetStringAttribute(ui::AX_ATTR_DOC_URL) != url::kAboutBlankURL);
+}
+
+// Times out on Android, not clear if it's an actual bug or just slow.
+#if defined(OS_ANDROID)
#define MAYBE_CrossSiteIframeAccessibility DISABLED_CrossSiteIframeAccessibility
+#else
+#define MAYBE_CrossSiteIframeAccessibility CrossSiteIframeAccessibility
#endif
IN_PROC_BROWSER_TEST_F(SitePerProcessAccessibilityBrowserTest,
MAYBE_CrossSiteIframeAccessibility) {
@@ -69,13 +77,10 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessAccessibilityBrowserTest,
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::Replacements replace_host;
GURL cross_site_url(test_server()->GetURL("files/title2.html"));
- replace_host.SetHostStr(foo_com);
+ replace_host.SetHostStr("foo.com");
cross_site_url = cross_site_url.ReplaceComponents(replace_host);
NavigateFrameToURL(root->child_at(0), cross_site_url);
@@ -84,14 +89,10 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessAccessibilityBrowserTest,
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);
+ // Wait for the accessibility tree from the main frame to load.
+ // Because we created the AccessibilityNotificationWaiter before accessibility
+ // was enabled, we're guaranteed to get a LOAD_COMPLETE event.
main_frame_accessibility_waiter.WaitForNotification();
- child_frame_accessibility_waiter.WaitForNotification();
RenderFrameHostImpl* main_frame = static_cast<RenderFrameHostImpl*>(
shell()->web_contents()->GetMainFrame());
@@ -99,48 +100,63 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessAccessibilityBrowserTest,
main_frame->browser_accessibility_manager();
VLOG(1) << "Main frame accessibility tree:\n"
<< main_frame_manager->SnapshotAXTreeForTesting().ToString();
+ EXPECT_TRUE(AccessibilityTreeIsLoaded(main_frame_manager));
+ // Next, wait for the accessibility tree from the cross-process iframe
+ // to load. Since accessibility was enabled at the time this frame was
+ // created, we need to check to see if it's already loaded first, and
+ // only create an AccessibilityNotificationWaiter if it's not.
+ RenderFrameHostImpl* child_frame = static_cast<RenderFrameHostImpl*>(
+ child->current_frame_host());
BrowserAccessibilityManager* child_frame_manager =
child_frame->browser_accessibility_manager();
+ if (!AccessibilityTreeIsLoaded(child_frame_manager)) {
+ VLOG(1) << "Child frame accessibility tree is not loaded, waiting...";
+ AccessibilityNotificationWaiter child_frame_accessibility_waiter(
+ child_frame, ui::AX_EVENT_LOAD_COMPLETE);
+ child_frame_accessibility_waiter.WaitForNotification();
+ }
+ EXPECT_TRUE(AccessibilityTreeIsLoaded(child_frame_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());
+ EXPECT_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());
+ EXPECT_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());
+ EXPECT_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());
+ EXPECT_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());
+ EXPECT_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());
+ EXPECT_EQ("Title Of Awesomeness",
+ ax_child_frame_root->GetStringAttribute(ui::AX_ATTR_NAME));
BrowserAccessibility* ax_child_frame_group =
ax_child_frame_root->PlatformGetChild(0);
- ASSERT_EQ(ui::AX_ROLE_GROUP, ax_child_frame_group->GetRole());
+ EXPECT_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());
+ EXPECT_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);
+ EXPECT_EQ(ax_child_frame_root->GetParent(), ax_scroll_area);
}
} // namespace content
diff --git a/chromium/content/browser/accessibility/snapshot_ax_tree_browsertest.cc b/chromium/content/browser/accessibility/snapshot_ax_tree_browsertest.cc
new file mode 100644
index 00000000000..af82404c176
--- /dev/null
+++ b/chromium/content/browser/accessibility/snapshot_ax_tree_browsertest.cc
@@ -0,0 +1,77 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/callback.h"
+#include "content/browser/web_contents/web_contents_impl.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 "testing/gtest/include/gtest/gtest.h"
+#include "ui/accessibility/ax_node.h"
+#include "ui/accessibility/ax_tree.h"
+
+namespace content {
+
+namespace {
+
+class AXTreeSnapshotWaiter {
+ public:
+ AXTreeSnapshotWaiter() : loop_runner_(new MessageLoopRunner()) {}
+
+ void Wait() {
+ loop_runner_->Run();
+ }
+
+ const ui::AXTreeUpdate& snapshot() const { return snapshot_; }
+
+ void ReceiveSnapshot(const ui::AXTreeUpdate& snapshot) {
+ snapshot_ = snapshot;
+ loop_runner_->Quit();
+ }
+
+ private:
+ ui::AXTreeUpdate snapshot_;
+ scoped_refptr<MessageLoopRunner> loop_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(AXTreeSnapshotWaiter);
+};
+
+} // namespace
+
+class SnapshotAXTreeBrowserTest : public ContentBrowserTest {
+ public:
+ SnapshotAXTreeBrowserTest() {}
+ ~SnapshotAXTreeBrowserTest() override {}
+};
+
+IN_PROC_BROWSER_TEST_F(SnapshotAXTreeBrowserTest,
+ SnapshotAccessibilityTreeFromWebContents) {
+ GURL url("data:text/html,<button>Click</button>");
+ NavigateToURL(shell(), url);
+
+ WebContentsImpl* web_contents =
+ static_cast<WebContentsImpl*>(shell()->web_contents());
+
+ AXTreeSnapshotWaiter waiter;
+ web_contents->RequestAXTreeSnapshot(
+ base::Bind(&AXTreeSnapshotWaiter::ReceiveSnapshot,
+ base::Unretained(&waiter)));
+ waiter.Wait();
+
+ // Dump the whole tree if one of the assertions below fails
+ // to aid in debugging why it failed.
+ SCOPED_TRACE(waiter.snapshot().ToString());
+
+ ui::AXTree tree(waiter.snapshot());
+ ui::AXNode* root = tree.root();
+ ASSERT_NE(nullptr, root);
+ ASSERT_EQ(ui::AX_ROLE_ROOT_WEB_AREA, root->data().role);
+ ui::AXNode* group = root->ChildAtIndex(0);
+ ASSERT_EQ(ui::AX_ROLE_GROUP, group->data().role);
+ ui::AXNode* button = group->ChildAtIndex(0);
+ ASSERT_EQ(ui::AX_ROLE_BUTTON, button->data().role);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/android/animation_utils.h b/chromium/content/browser/android/animation_utils.h
new file mode 100644
index 00000000000..e20d2eb9e50
--- /dev/null
+++ b/chromium/content/browser/android/animation_utils.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_ANDROID_ANIMATION_UTILS_H_
+#define CONTENT_BROWSER_ANDROID_ANIMATION_UTILS_H_
+
+namespace content {
+
+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 content
+
+#endif // CONTENT_BROWSER_ANDROID_ANIMATION_UTILS_H_
diff --git a/chromium/content/browser/android/browser_startup_controller.h b/chromium/content/browser/android/browser_startup_controller.h
index 6fa334e8f3a..a7f05c9ce3a 100644
--- a/chromium/content/browser/android/browser_startup_controller.h
+++ b/chromium/content/browser/android/browser_startup_controller.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_BROWSER_STARTUP_CONTROLLER_H_
-#define CONTENT_BROWSER_BROWSER_STARTUP_CONTROLLER_H_
+#ifndef CONTENT_BROWSER_ANDROID_BROWSER_STARTUP_CONTROLLER_H_
+#define CONTENT_BROWSER_ANDROID_BROWSER_STARTUP_CONTROLLER_H_
#include <jni.h>
@@ -15,4 +15,4 @@ void BrowserStartupComplete(int result);
bool RegisterBrowserStartupController(JNIEnv* env);
} // namespace content
-#endif // CONTENT_BROWSER_BROWSER_STARTUP_CONTROLLER_H_
+#endif // CONTENT_BROWSER_ANDROID_BROWSER_STARTUP_CONTROLLER_H_
diff --git a/chromium/content/browser/android/browser_surface_texture_manager.cc b/chromium/content/browser/android/browser_surface_texture_manager.cc
index 44669839f2b..832036b1864 100644
--- a/chromium/content/browser/android/browser_surface_texture_manager.cc
+++ b/chromium/content/browser/android/browser_surface_texture_manager.cc
@@ -12,7 +12,7 @@
#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/browser/web_contents/web_contents_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"
@@ -50,10 +50,10 @@ static void SetSurfacePeer(scoped_refptr<gfx::SurfaceTexture> surface_texture,
return;
}
- RenderViewHostImpl* view =
- static_cast<RenderViewHostImpl*>(frame->GetRenderViewHost());
+ WebContentsImpl* web_contents =
+ static_cast<WebContentsImpl*>(WebContents::FromRenderFrameHost(frame));
BrowserMediaPlayerManager* player_manager =
- view->media_web_contents_observer()->GetMediaPlayerManager(frame);
+ web_contents->media_web_contents_observer()->GetMediaPlayerManager(frame);
if (!player_manager) {
DVLOG(1) << "Cannot find the media player manager for frame " << frame;
return;
diff --git a/chromium/content/browser/android/browser_surface_texture_manager.h b/chromium/content/browser/android/browser_surface_texture_manager.h
index 7776d30ee7f..959d2705488 100644
--- a/chromium/content/browser/android/browser_surface_texture_manager.h
+++ b/chromium/content/browser/android/browser_surface_texture_manager.h
@@ -15,20 +15,18 @@ class BrowserSurfaceTextureManager : public SurfaceTextureManager,
public SurfaceTexturePeer {
public:
BrowserSurfaceTextureManager();
- virtual ~BrowserSurfaceTextureManager();
+ ~BrowserSurfaceTextureManager() override;
// 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(
+ void RegisterSurfaceTexture(int surface_texture_id,
+ int client_id,
+ gfx::SurfaceTexture* surface_texture) override;
+ void UnregisterSurfaceTexture(int surface_texture_id, int client_id) override;
+ gfx::AcceleratedWidget AcquireNativeWidgetForSurfaceTexture(
int surface_texture_id) override;
// Overridden from SurfaceTexturePeer:
- virtual void EstablishSurfaceTexturePeer(
+ void EstablishSurfaceTexturePeer(
base::ProcessHandle render_process_handle,
scoped_refptr<gfx::SurfaceTexture> surface_texture,
int render_frame_id,
diff --git a/chromium/content/browser/android/child_process_launcher_android.cc b/chromium/content/browser/android/child_process_launcher_android.cc
index c937fce174a..161493b503d 100644
--- a/chromium/content/browser/android/child_process_launcher_android.cc
+++ b/chromium/content/browser/android/child_process_launcher_android.cc
@@ -12,7 +12,7 @@
#include "content/browser/media/android/browser_media_player_manager.h"
#include "content/browser/media/media_web_contents_observer.h"
#include "content/browser/renderer_host/compositor_impl_android.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/render_process_host.h"
#include "content/public/common/content_switches.h"
@@ -59,10 +59,10 @@ static void SetSurfacePeer(
return;
}
- RenderViewHostImpl* view =
- static_cast<RenderViewHostImpl*>(frame->GetRenderViewHost());
+ WebContentsImpl* web_contents =
+ static_cast<WebContentsImpl*>(WebContents::FromRenderFrameHost(frame));
BrowserMediaPlayerManager* player_manager =
- view->media_web_contents_observer()->GetMediaPlayerManager(frame);
+ web_contents->media_web_contents_observer()->GetMediaPlayerManager(frame);
if (!player_manager) {
DVLOG(1) << "Cannot find the media player manager for frame " << frame;
return;
@@ -128,14 +128,12 @@ void StartChildProcess(
env->GetBooleanArrayElements(j_file_auto_close.obj(), NULL);
base::android::CheckException(env);
for (size_t i = 0; i < file_count; ++i) {
- // 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));
+ file_fds[i] = files_to_register->GetFDAt(i);
PCHECK(0 <= file_fds[i]);
+ file_auto_close[i] = files_to_register->OwnsFD(file_fds[i]);
+ if (file_auto_close[i])
+ ignore_result(files_to_register->ReleaseFD(file_fds[i]).release());
}
env->ReleaseIntArrayElements(j_file_ids.obj(), file_ids, 0);
env->ReleaseIntArrayElements(j_file_fds.obj(), file_fds, 0);
diff --git a/chromium/content/browser/android/composited_touch_handle_drawable.cc b/chromium/content/browser/android/composited_touch_handle_drawable.cc
index aa7c71920c1..91a019eba89 100644
--- a/chromium/content/browser/android/composited_touch_handle_drawable.cc
+++ b/chromium/content/browser/android/composited_touch_handle_drawable.cc
@@ -4,9 +4,9 @@
#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 "base/trace_event/trace_event.h"
#include "cc/layers/ui_resource_layer.h"
#include "jni/HandleViewResources_jni.h"
#include "ui/gfx/android/java_bitmap.h"
@@ -50,16 +50,16 @@ class HandleResources {
center_bitmap_.setImmutable();
}
- const SkBitmap& GetBitmap(TouchHandleOrientation orientation) {
+ const SkBitmap& GetBitmap(ui::TouchHandleOrientation orientation) {
DCHECK(loaded_);
switch (orientation) {
- case TOUCH_HANDLE_LEFT:
+ case ui::TouchHandleOrientation::LEFT:
return left_bitmap_;
- case TOUCH_HANDLE_RIGHT:
+ case ui::TouchHandleOrientation::RIGHT:
return right_bitmap_;
- case TOUCH_HANDLE_CENTER:
+ case ui::TouchHandleOrientation::CENTER:
return center_bitmap_;
- case TOUCH_HANDLE_ORIENTATION_UNDEFINED:
+ case ui::TouchHandleOrientation::UNDEFINED:
NOTREACHED() << "Invalid touch handle orientation.";
};
return center_bitmap_;
@@ -83,7 +83,7 @@ CompositedTouchHandleDrawable::CompositedTouchHandleDrawable(
float dpi_scale,
jobject context)
: dpi_scale_(dpi_scale),
- orientation_(TOUCH_HANDLE_ORIENTATION_UNDEFINED),
+ orientation_(ui::TouchHandleOrientation::UNDEFINED),
layer_(cc::UIResourceLayer::Create()) {
g_selection_resources.Get().LoadIfNecessary(context);
DCHECK(root_layer);
@@ -91,15 +91,18 @@ CompositedTouchHandleDrawable::CompositedTouchHandleDrawable(
}
CompositedTouchHandleDrawable::~CompositedTouchHandleDrawable() {
- Detach();
+ DetachLayer();
}
void CompositedTouchHandleDrawable::SetEnabled(bool enabled) {
layer_->SetIsDrawable(enabled);
+ // Force a position update in case the disabled layer's properties are stale.
+ if (enabled)
+ UpdateLayerPosition();
}
void CompositedTouchHandleDrawable::SetOrientation(
- TouchHandleOrientation orientation) {
+ ui::TouchHandleOrientation orientation) {
DCHECK(layer_->parent());
orientation_ = orientation;
@@ -108,53 +111,51 @@ void CompositedTouchHandleDrawable::SetOrientation(
layer_->SetBounds(gfx::Size(bitmap.width(), bitmap.height()));
switch (orientation_) {
- case TOUCH_HANDLE_LEFT:
+ case ui::TouchHandleOrientation::LEFT:
focal_offset_from_origin_ = gfx::Vector2dF(bitmap.width() * 0.75f, 0);
break;
- case TOUCH_HANDLE_RIGHT:
+ case ui::TouchHandleOrientation::RIGHT:
focal_offset_from_origin_ = gfx::Vector2dF(bitmap.width() * 0.25f, 0);
break;
- case TOUCH_HANDLE_CENTER:
+ case ui::TouchHandleOrientation::CENTER:
focal_offset_from_origin_ = gfx::Vector2dF(bitmap.width() * 0.5f, 0);
break;
- case TOUCH_HANDLE_ORIENTATION_UNDEFINED:
+ case ui::TouchHandleOrientation::UNDEFINED:
NOTREACHED() << "Invalid touch handle orientation.";
break;
};
- layer_->SetPosition(focal_position_ - focal_offset_from_origin_);
+ UpdateLayerPosition();
}
void CompositedTouchHandleDrawable::SetAlpha(float alpha) {
DCHECK(layer_->parent());
- layer_->SetOpacity(std::max(0.f, std::min(1.f, alpha)));
+ alpha = std::max(0.f, std::min(1.f, alpha));
+ bool hidden = alpha <= 0;
+ layer_->SetOpacity(alpha);
+ layer_->SetHideLayerAndSubtree(hidden);
}
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);
+ UpdateLayerPosition();
}
-bool CompositedTouchHandleDrawable::IntersectsWith(
- const gfx::RectF& rect) const {
- return BoundingRect().Intersects(gfx::ScaleRect(rect, dpi_scale_));
+gfx::RectF CompositedTouchHandleDrawable::GetVisibleBounds() const {
+ return gfx::ScaleRect(gfx::RectF(layer_->position().x(),
+ layer_->position().y(),
+ layer_->bounds().width(),
+ layer_->bounds().height()),
+ 1.f / dpi_scale_);
}
-void CompositedTouchHandleDrawable::Detach() {
+void CompositedTouchHandleDrawable::DetachLayer() {
layer_->RemoveFromParent();
}
-gfx::RectF CompositedTouchHandleDrawable::BoundingRect() const {
- return gfx::RectF(layer_->position().x(),
- layer_->position().y(),
- layer_->bounds().width(),
- layer_->bounds().height());
+void CompositedTouchHandleDrawable::UpdateLayerPosition() {
+ layer_->SetPosition(focal_position_ - focal_offset_from_origin_);
}
// static
diff --git a/chromium/content/browser/android/composited_touch_handle_drawable.h b/chromium/content/browser/android/composited_touch_handle_drawable.h
index c4f5f45b2a1..28c6910b9d4 100644
--- a/chromium/content/browser/android/composited_touch_handle_drawable.h
+++ b/chromium/content/browser/android/composited_touch_handle_drawable.h
@@ -5,7 +5,7 @@
#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 "ui/touch_selection/touch_handle.h"
#include "base/android/jni_android.h"
#include "cc/layers/ui_resource_layer.h"
@@ -13,29 +13,28 @@
namespace content {
// Touch handle drawable implementation backed by a cc layer.
-class CompositedTouchHandleDrawable : public TouchHandleDrawable {
+class CompositedTouchHandleDrawable : public ui::TouchHandleDrawable {
public:
CompositedTouchHandleDrawable(cc::Layer* root_layer,
float dpi_scale,
jobject context);
- virtual ~CompositedTouchHandleDrawable();
+ ~CompositedTouchHandleDrawable() override;
- // 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;
+ // ui::TouchHandleDrawable implementation.
+ void SetEnabled(bool enabled) override;
+ void SetOrientation(ui::TouchHandleOrientation orientation) override;
+ void SetAlpha(float alpha) override;
+ void SetFocus(const gfx::PointF& position) override;
+ gfx::RectF GetVisibleBounds() const override;
static bool RegisterHandleViewResources(JNIEnv* env);
private:
- void Detach();
- gfx::RectF BoundingRect() const;
+ void DetachLayer();
+ void UpdateLayerPosition();
const float dpi_scale_;
- TouchHandleOrientation orientation_;
+ ui::TouchHandleOrientation orientation_;
gfx::PointF focal_position_;
gfx::Vector2dF focal_offset_from_origin_;
scoped_refptr<cc::UIResourceLayer> layer_;
diff --git a/chromium/content/browser/android/content_protocol_handler_impl.cc b/chromium/content/browser/android/content_protocol_handler_impl.cc
new file mode 100644
index 00000000000..f5e5d208f8f
--- /dev/null
+++ b/chromium/content/browser/android/content_protocol_handler_impl.cc
@@ -0,0 +1,43 @@
+// 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/android/content_protocol_handler_impl.h"
+
+#include "base/task_runner.h"
+#include "content/browser/android/url_request_content_job.h"
+#include "net/base/net_errors.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_error_job.h"
+
+namespace content {
+
+// static
+ContentProtocolHandler* ContentProtocolHandler::Create(
+ const scoped_refptr<base::TaskRunner>& content_task_runner) {
+ return new ContentProtocolHandlerImpl(content_task_runner);
+}
+
+ContentProtocolHandlerImpl::ContentProtocolHandlerImpl(
+ const scoped_refptr<base::TaskRunner>& content_task_runner)
+ : content_task_runner_(content_task_runner) {}
+
+ContentProtocolHandlerImpl::~ContentProtocolHandlerImpl() {}
+
+net::URLRequestJob* ContentProtocolHandlerImpl::MaybeCreateJob(
+ net::URLRequest* request, net::NetworkDelegate* network_delegate) const {
+ if (!network_delegate) {
+ return new net::URLRequestErrorJob(
+ request, network_delegate, net::ERR_ACCESS_DENIED);
+ }
+ return new URLRequestContentJob(
+ request, network_delegate, base::FilePath(request->url().spec()),
+ content_task_runner_);
+}
+
+bool ContentProtocolHandlerImpl::IsSafeRedirectTarget(
+ const GURL& location) const {
+ return false;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/android/content_protocol_handler_impl.h b/chromium/content/browser/android/content_protocol_handler_impl.h
new file mode 100644
index 00000000000..f593a84bb88
--- /dev/null
+++ b/chromium/content/browser/android/content_protocol_handler_impl.h
@@ -0,0 +1,45 @@
+// 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_ANDROID_CONTENT_PROTOCOL_HANDLER_IMPL_H_
+#define CONTENT_BROWSER_ANDROID_CONTENT_PROTOCOL_HANDLER_IMPL_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "content/public/browser/android/content_protocol_handler.h"
+
+class GURL;
+
+namespace base {
+class TaskRunner;
+}
+
+namespace net {
+class NetworkDelegate;
+class URLRequestJob;
+}
+
+namespace content {
+
+// Implements a ProtocolHandler for content scheme jobs. If |network_delegate_|
+// is NULL, then all file requests will fail with ERR_ACCESS_DENIED.
+class ContentProtocolHandlerImpl : public ContentProtocolHandler {
+ public:
+ explicit ContentProtocolHandlerImpl(
+ const scoped_refptr<base::TaskRunner>& content_task_runner);
+ ~ContentProtocolHandlerImpl() override;
+ net::URLRequestJob* MaybeCreateJob(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) const override;
+ bool IsSafeRedirectTarget(const GURL& location) const override;
+
+ private:
+ const scoped_refptr<base::TaskRunner> content_task_runner_;
+ DISALLOW_COPY_AND_ASSIGN(ContentProtocolHandlerImpl);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_ANDROID_CONTENT_PROTOCOL_HANDLER_IMPL_H_
diff --git a/chromium/content/browser/android/content_readback_handler.cc b/chromium/content/browser/android/content_readback_handler.cc
index 414bf0abe67..6ff62e43c07 100644
--- a/chromium/content/browser/android/content_readback_handler.cc
+++ b/chromium/content/browser/android/content_readback_handler.cc
@@ -11,27 +11,25 @@
#include "content/browser/android/content_view_core_impl.h"
#include "jni/ContentReadbackHandler_jni.h"
#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/base/android/window_android.h"
-#include "ui/base/android/window_android_compositor.h"
+#include "ui/android/window_android.h"
+#include "ui/android/window_android_compositor.h"
#include "ui/gfx/android/java_bitmap.h"
-#include "ui/gfx/rect.h"
+#include "ui/gfx/geometry/rect.h"
namespace content {
namespace {
-typedef base::Callback<void(bool, const SkBitmap&)> ResultCallback;
-
void OnFinishCopyOutputRequest(
- const ResultCallback& result_callback,
+ const ReadbackRequestCallback& result_callback,
scoped_ptr<cc::CopyOutputResult> copy_output_result) {
if (!copy_output_result->HasBitmap()) {
- result_callback.Run(false, SkBitmap());
+ result_callback.Run(SkBitmap(), READBACK_FAILED);
return;
}
scoped_ptr<SkBitmap> bitmap = copy_output_result->TakeBitmap();
- result_callback.Run(true, *bitmap);
+ result_callback.Run(*bitmap, READBACK_SUCCESS);
}
} // anonymous namespace
@@ -64,7 +62,7 @@ void ContentReadbackHandler::GetContentBitmap(JNIEnv* env,
ContentViewCore::GetNativeContentViewCore(env, content_view_core);
DCHECK(view);
- ResultCallback result_callback =
+ ReadbackRequestCallback result_callback =
base::Bind(&ContentReadbackHandler::OnFinishReadback,
weak_factory_.GetWeakPtr(),
readback_id);
@@ -82,7 +80,7 @@ void ContentReadbackHandler::GetCompositorBitmap(JNIEnv* env,
reinterpret_cast<ui::WindowAndroid*>(native_window_android);
DCHECK(window_android);
- ResultCallback result_callback =
+ ReadbackRequestCallback result_callback =
base::Bind(&ContentReadbackHandler::OnFinishReadback,
weak_factory_.GetWeakPtr(),
readback_id);
@@ -105,15 +103,15 @@ void ContentReadbackHandler::GetCompositorBitmap(JNIEnv* env,
ContentReadbackHandler::~ContentReadbackHandler() {}
void ContentReadbackHandler::OnFinishReadback(int readback_id,
- bool success,
- const SkBitmap& bitmap) {
+ const SkBitmap& bitmap,
+ ReadbackResponse response) {
JNIEnv* env = base::android::AttachCurrentThread();
ScopedJavaLocalRef<jobject> java_bitmap;
- if (success)
+ if (response == READBACK_SUCCESS)
java_bitmap = gfx::ConvertToJavaBitmap(&bitmap);
Java_ContentReadbackHandler_notifyGetBitmapFinished(
- env, java_obj_.obj(), readback_id, java_bitmap.obj());
+ env, java_obj_.obj(), readback_id, java_bitmap.obj(), response);
}
// static
diff --git a/chromium/content/browser/android/content_readback_handler.h b/chromium/content/browser/android/content_readback_handler.h
index 403bdd0a7af..66b2c8588d4 100644
--- a/chromium/content/browser/android/content_readback_handler.h
+++ b/chromium/content/browser/android/content_readback_handler.h
@@ -10,6 +10,7 @@
#include "base/android/jni_weak_ref.h"
#include "base/callback.h"
#include "base/memory/weak_ptr.h"
+#include "content/public/browser/readback_types.h"
class SkBitmap;
@@ -48,8 +49,8 @@ class ContentReadbackHandler {
virtual ~ContentReadbackHandler();
void OnFinishReadback(int readback_id,
- bool success,
- const SkBitmap& bitmap);
+ const SkBitmap& bitmap,
+ ReadbackResponse response);
base::android::ScopedJavaGlobalRef<jobject> java_obj_;
base::WeakPtrFactory<ContentReadbackHandler> weak_factory_;
diff --git a/chromium/content/browser/android/content_settings.cc b/chromium/content/browser/android/content_settings.cc
deleted file mode 100644
index 2d32143807a..00000000000
--- a/chromium/content/browser/android/content_settings.cc
+++ /dev/null
@@ -1,58 +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/content_settings.h"
-
-#include "base/android/jni_android.h"
-#include "content/browser/android/content_view_core_impl.h"
-#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"
-
-namespace content {
-
-ContentSettings::ContentSettings(JNIEnv* env,
- jobject obj,
- WebContents* contents)
- : WebContentsObserver(contents),
- content_settings_(env, obj) {
-}
-
-ContentSettings::~ContentSettings() {
- JNIEnv* env = base::android::AttachCurrentThread();
- ScopedJavaLocalRef<jobject> obj = content_settings_.get(env);
- if (obj.obj()) {
- Java_ContentSettings_onNativeContentSettingsDestroyed(env, obj.obj(),
- reinterpret_cast<intptr_t>(this));
- }
-}
-
-// static
-bool ContentSettings::RegisterContentSettings(JNIEnv* env) {
- return RegisterNativesImpl(env);
-}
-
-bool ContentSettings::GetJavaScriptEnabled(JNIEnv* env, jobject obj) {
- RenderViewHost* render_view_host = web_contents()->GetRenderViewHost();
- if (!render_view_host)
- return false;
- return render_view_host->GetWebkitPreferences().javascript_enabled;
-}
-
-void ContentSettings::WebContentsDestroyed() {
- delete this;
-}
-
-static jlong Init(JNIEnv* env, jobject obj, jlong nativeContentViewCore) {
- WebContents* web_contents =
- reinterpret_cast<ContentViewCoreImpl*>(nativeContentViewCore)
- ->GetWebContents();
- ContentSettings* content_settings =
- new ContentSettings(env, obj, web_contents);
- return reinterpret_cast<intptr_t>(content_settings);
-}
-
-} // namespace content
diff --git a/chromium/content/browser/android/content_settings.h b/chromium/content/browser/android/content_settings.h
deleted file mode 100644
index 79dd1da4d38..00000000000
--- a/chromium/content/browser/android/content_settings.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_CONTENT_SETTINGS_H_
-#define CONTENT_BROWSER_ANDROID_CONTENT_SETTINGS_H_
-
-#include <jni.h>
-
-#include "base/android/jni_weak_ref.h"
-#include "content/public/browser/web_contents_observer.h"
-
-namespace content {
-
-class ContentSettings : public WebContentsObserver {
- public:
- ContentSettings(JNIEnv* env, jobject obj,
- WebContents* contents);
-
- static bool RegisterContentSettings(JNIEnv* env);
-
- bool GetJavaScriptEnabled(JNIEnv* env, jobject obj);
-
- private:
- // Self-deletes when the underlying WebContents is destroyed.
- virtual ~ContentSettings();
-
- // WebContentsObserver overrides:
- virtual void WebContentsDestroyed() override;
-
- // The Java counterpart to this class.
- JavaObjectWeakGlobalRef content_settings_;
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_ANDROID_CONTENT_SETTINGS_H_
diff --git a/chromium/content/browser/android/content_startup_flags.cc b/chromium/content/browser/android/content_startup_flags.cc
index d531dbb65a6..e6798255180 100644
--- a/chromium/content/browser/android/content_startup_flags.cc
+++ b/chromium/content/browser/android/content_startup_flags.cc
@@ -4,10 +4,12 @@
#include "content/browser/android/content_startup_flags.h"
+#include "base/android/build_info.h"
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
+#include "base/sys_info.h"
#include "cc/base/switches.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/common/content_constants.h"
@@ -57,15 +59,18 @@ void SetContentCommandLineFlags(bool single_process,
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.
- parsed_command_line->AppendSwitch(switches::kInProcessGPU);
- parsed_command_line->AppendSwitch(switches::kDisableGpuShaderDiskCache);
+ // There is no software fallback on Android, so don't limit GPU crashes.
+ parsed_command_line->AppendSwitch(switches::kDisableGpuProcessCrashLimit);
+
+ // On legacy low-memory devices the behavior has not been studied with regard
+ // to having an extra process with similar priority as the foreground renderer
+ // and given that the system will often be looking for a process to be killed
+ // on such systems.
+ if (base::SysInfo::IsLowEndDevice())
+ parsed_command_line->AppendSwitch(switches::kInProcessGPU);
- parsed_command_line->AppendSwitch(switches::kEnableViewport);
parsed_command_line->AppendSwitch(switches::kEnableViewportMeta);
parsed_command_line->AppendSwitch(
switches::kMainFrameResizesAreOrientationChanges);
diff --git a/chromium/content/browser/android/content_video_view.cc b/chromium/content/browser/android/content_video_view.cc
index 68b0b5f0cad..2a5ce048b55 100644
--- a/chromium/content/browser/android/content_video_view.cc
+++ b/chromium/content/browser/android/content_video_view.cc
@@ -167,43 +167,11 @@ void ContentVideoView::UpdateMediaMetadata() {
}
}
-int ContentVideoView::GetVideoWidth(JNIEnv*, jobject obj) const {
- media::MediaPlayerAndroid* player = manager_->GetFullscreenPlayer();
- return player ? player->GetVideoWidth() : 0;
-}
-
-int ContentVideoView::GetVideoHeight(JNIEnv*, jobject obj) const {
- media::MediaPlayerAndroid* player = manager_->GetFullscreenPlayer();
- return player ? player->GetVideoHeight() : 0;
-}
-
-int ContentVideoView::GetDurationInMilliSeconds(JNIEnv*, jobject obj) const {
- media::MediaPlayerAndroid* player = manager_->GetFullscreenPlayer();
- return player ? player->GetDuration().InMilliseconds() : -1;
-}
-
-int ContentVideoView::GetCurrentPosition(JNIEnv*, jobject obj) const {
- media::MediaPlayerAndroid* player = manager_->GetFullscreenPlayer();
- return player ? player->GetCurrentTime().InMilliseconds() : 0;
-}
-
bool ContentVideoView::IsPlaying(JNIEnv*, jobject obj) {
media::MediaPlayerAndroid* player = manager_->GetFullscreenPlayer();
return player ? player->IsPlaying() : false;
}
-void ContentVideoView::SeekTo(JNIEnv*, jobject obj, jint msec) {
- manager_->FullscreenPlayerSeek(msec);
-}
-
-void ContentVideoView::Play(JNIEnv*, jobject obj) {
- manager_->FullscreenPlayerPlay();
-}
-
-void ContentVideoView::Pause(JNIEnv*, jobject obj) {
- manager_->FullscreenPlayerPause();
-}
-
void ContentVideoView::ExitFullscreen(
JNIEnv*, jobject, jboolean release_media_player) {
j_content_video_view_.reset();
@@ -228,13 +196,19 @@ ScopedJavaLocalRef<jobject> ContentVideoView::GetJavaObject(JNIEnv* env) {
}
JavaObjectWeakGlobalRef ContentVideoView::CreateJavaObject() {
- ContentViewCoreImpl* content_view_core = manager_->GetContentViewCore();
+ ContentViewCore* content_view_core = manager_->GetContentViewCore();
JNIEnv* env = AttachCurrentThread();
+
+ base::android::ScopedJavaLocalRef<jobject> j_content_view_core =
+ content_view_core->GetJavaObject();
+ if (j_content_view_core.is_null())
+ return JavaObjectWeakGlobalRef(env, nullptr);
+
return JavaObjectWeakGlobalRef(
env,
Java_ContentVideoView_createContentVideoView(
env,
- content_view_core->GetJavaObject().obj(),
+ j_content_view_core.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 7946792cf29..37b7f2e8be7 100644
--- a/chromium/content/browser/android/content_video_view.h
+++ b/chromium/content/browser/android/content_video_view.h
@@ -41,10 +41,6 @@ class ContentVideoView {
static ContentVideoView* GetInstance();
// Getter method called by the Java class to get the media information.
- int GetVideoWidth(JNIEnv*, jobject obj) const;
- int GetVideoHeight(JNIEnv*, jobject obj) const;
- int GetDurationInMilliSeconds(JNIEnv*, jobject obj) const;
- int GetCurrentPosition(JNIEnv*, jobject obj) const;
bool IsPlaying(JNIEnv*, jobject obj);
void RequestMediaMetadata(JNIEnv*, jobject obj);
@@ -53,11 +49,6 @@ class ContentVideoView {
// as we are quitting the app.
void ExitFullscreen(JNIEnv*, jobject, jboolean release_media_player);
- // Media control method called by the Java class.
- void SeekTo(JNIEnv*, jobject obj, jint msec);
- void Play(JNIEnv*, jobject obj);
- void Pause(JNIEnv*, jobject obj);
-
// Called by the Java class to pass the surface object to the player.
void SetSurface(JNIEnv*, jobject obj, jobject surface);
diff --git a/chromium/content/browser/android/content_view_core_impl.cc b/chromium/content/browser/android/content_view_core_impl.cc
index 12117bf5dfb..978e76d5132 100644
--- a/chromium/content/browser/android/content_view_core_impl.cc
+++ b/chromium/content/browser/android/content_view_core_impl.cc
@@ -51,12 +51,13 @@
#include "content/public/common/user_agent.h"
#include "jni/ContentViewCore_jni.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
-#include "ui/base/android/view_android.h"
-#include "ui/base/android/window_android.h"
+#include "ui/android/view_android.h"
+#include "ui/android/window_android.h"
#include "ui/gfx/android/java_bitmap.h"
+#include "ui/gfx/geometry/point_conversions.h"
+#include "ui/gfx/geometry/size_conversions.h"
+#include "ui/gfx/geometry/size_f.h"
#include "ui/gfx/screen.h"
-#include "ui/gfx/size_conversions.h"
-#include "ui/gfx/size_f.h"
using base::android::AttachCurrentThread;
using base::android::ConvertJavaStringToUTF16;
@@ -147,7 +148,6 @@ int ToGestureEventType(WebInputEvent::Type type) {
case WebInputEvent::GesturePinchUpdate:
return GESTURE_EVENT_TYPE_PINCH_BY;
case WebInputEvent::GestureTwoFingerTap:
- case WebInputEvent::GestureScrollUpdateWithoutPropagation:
default:
NOTREACHED() << "Invalid source gesture type: "
<< WebInputEventTraits::GetName(type);
@@ -172,7 +172,7 @@ class ContentViewCoreImpl::ContentViewUserData
: content_view_core_(content_view_core) {
}
- virtual ~ContentViewUserData() {
+ ~ContentViewUserData() override {
// TODO(joth): When chrome has finished removing the TabContents class (see
// crbug.com/107201) consider inverting relationship, so ContentViewCore
// would own WebContents. That effectively implies making the WebContents
@@ -215,7 +215,7 @@ ContentViewCoreImpl::ContentViewCoreImpl(
JNIEnv* env,
jobject obj,
WebContents* web_contents,
- ui::ViewAndroid* view_android,
+ jobject view_android_delegate,
ui::WindowAndroid* window_android,
jobject java_bridge_retained_object_set)
: WebContentsObserver(web_contents),
@@ -223,13 +223,12 @@ ContentViewCoreImpl::ContentViewCoreImpl(
web_contents_(static_cast<WebContentsImpl*>(web_contents)),
root_layer_(cc::SolidColorLayer::Create()),
dpi_scale_(GetPrimaryDisplayDeviceScaleFactor()),
- view_android_(view_android),
+ view_android_(new ui::ViewAndroid(view_android_delegate, window_android)),
window_android_(window_android),
device_orientation_(0),
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));
@@ -249,14 +248,16 @@ ContentViewCoreImpl::ContentViewCoreImpl(
BuildUserAgentFromOSAndProduct(kLinuxInfoStr, product);
web_contents->SetUserAgentOverride(spoofed_ua);
- java_bridge_dispatcher_host_.reset(
+ java_bridge_dispatcher_host_ =
new GinJavaBridgeDispatcherHost(web_contents,
- java_bridge_retained_object_set));
+ java_bridge_retained_object_set);
InitWebContents();
}
ContentViewCoreImpl::~ContentViewCoreImpl() {
+ root_layer_->RemoveFromParent();
+
JNIEnv* env = base::android::AttachCurrentThread();
ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
java_ref_.reset();
@@ -337,14 +338,15 @@ void ContentViewCoreImpl::RenderViewHostChanged(RenderViewHost* old_host,
}
RenderWidgetHostViewAndroid*
- ContentViewCoreImpl::GetRenderWidgetHostViewAndroid() {
+ ContentViewCoreImpl::GetRenderWidgetHostViewAndroid() const {
RenderWidgetHostView* rwhv = NULL;
if (web_contents_) {
rwhv = web_contents_->GetRenderWidgetHostView();
if (web_contents_->ShowingInterstitialPage()) {
- rwhv = static_cast<InterstitialPageImpl*>(
- web_contents_->GetInterstitialPage())->
- GetRenderViewHost()->GetView();
+ rwhv = web_contents_->GetInterstitialPage()
+ ->GetMainFrame()
+ ->GetRenderViewHost()
+ ->GetView();
}
}
return static_cast<RenderWidgetHostViewAndroid*>(rwhv);
@@ -379,7 +381,8 @@ void ContentViewCoreImpl::UpdateFrameInfo(
const gfx::SizeF& content_size,
const gfx::SizeF& viewport_size,
const gfx::Vector2dF& controls_offset,
- const gfx::Vector2dF& content_offset) {
+ const gfx::Vector2dF& content_offset,
+ bool is_mobile_optimized_hint) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (obj.is_null())
@@ -400,7 +403,8 @@ void ContentViewCoreImpl::UpdateFrameInfo(
viewport_size.width(),
viewport_size.height(),
controls_offset.y(),
- content_offset.y());
+ content_offset.y(),
+ is_mobile_optimized_hint);
}
void ContentViewCoreImpl::SetTitle(const base::string16& title) {
@@ -581,6 +585,13 @@ bool ContentViewCoreImpl::HasFocus() {
return Java_ContentViewCore_hasFocus(env, obj.obj());
}
+void ContentViewCoreImpl::RequestDisallowInterceptTouchEvent() {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+ if (!obj.is_null())
+ Java_ContentViewCore_requestDisallowInterceptTouchEvent(env, obj.obj());
+}
+
void ContentViewCoreImpl::OnSelectionChanged(const std::string& text) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
@@ -590,25 +601,32 @@ void ContentViewCoreImpl::OnSelectionChanged(const std::string& text) {
Java_ContentViewCore_onSelectionChanged(env, obj.obj(), jtext.obj());
}
-void ContentViewCoreImpl::OnSelectionEvent(SelectionEventType event,
- const gfx::PointF& position) {
+void ContentViewCoreImpl::OnSelectionEvent(ui::SelectionEventType event,
+ const gfx::PointF& selection_anchor,
+ const gfx::RectF& selection_rect) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
if (j_obj.is_null())
return;
+
+ gfx::PointF selection_anchor_pix =
+ gfx::ScalePoint(selection_anchor, dpi_scale());
+ gfx::RectF selection_rect_pix = gfx::ScaleRect(selection_rect, dpi_scale());
Java_ContentViewCore_onSelectionEvent(
- env, j_obj.obj(), event, position.x(), position.y());
+ env, j_obj.obj(), event, selection_anchor_pix.x(),
+ selection_anchor_pix.y(), selection_rect_pix.x(), selection_rect_pix.y(),
+ selection_rect_pix.right(), selection_rect_pix.bottom());
}
-scoped_ptr<TouchHandleDrawable>
+scoped_ptr<ui::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<ui::TouchHandleDrawable>();
}
- return scoped_ptr<TouchHandleDrawable>(new PopupTouchHandleDrawable(
+ return scoped_ptr<ui::TouchHandleDrawable>(new PopupTouchHandleDrawable(
Java_ContentViewCore_createPopupTouchHandleDrawable(env, obj.obj()),
dpi_scale_));
}
@@ -624,24 +642,24 @@ void ContentViewCoreImpl::ShowPastePopup(int x_dip, int y_dip) {
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (obj.is_null())
return;
- Java_ContentViewCore_showPastePopupWithFeedback(env, obj.obj(),
- static_cast<jint>(x_dip),
- static_cast<jint>(y_dip));
+ Java_ContentViewCore_showPastePopupWithFeedback(
+ env, obj.obj(), static_cast<jint>(x_dip * dpi_scale()),
+ static_cast<jint>(y_dip * dpi_scale()));
}
void ContentViewCoreImpl::GetScaledContentBitmap(
float scale,
- SkColorType color_type,
+ SkColorType preferred_color_type,
gfx::Rect src_subrect,
- const base::Callback<void(bool, const SkBitmap&)>& result_callback) {
+ ReadbackRequestCallback& result_callback) {
RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid();
- if (!view) {
- result_callback.Run(false, SkBitmap());
+ if (!view || preferred_color_type == kUnknown_SkColorType) {
+ result_callback.Run(SkBitmap(), READBACK_FAILED);
return;
}
- view->GetScaledContentBitmap(scale, color_type, src_subrect,
- result_callback);
+ view->GetScaledContentBitmap(scale, preferred_color_type, src_subrect,
+ result_callback);
}
void ContentViewCoreImpl::StartContentIntent(const GURL& content_url) {
@@ -717,7 +735,8 @@ ScopedJavaLocalRef<jobject> ContentViewCoreImpl::GetContext() const {
gfx::Size ContentViewCoreImpl::GetViewSize() const {
gfx::Size size = GetViewportSizeDip();
- size.Enlarge(0, -GetTopControlsLayoutHeightDip());
+ if (DoTopControlsShrinkBlinkSize())
+ size.Enlarge(0, -GetTopControlsHeightDip());
return size;
}
@@ -741,12 +760,12 @@ gfx::Size ContentViewCoreImpl::GetViewportSizePix() const {
Java_ContentViewCore_getViewportHeightPix(env, j_obj.obj()));
}
-int ContentViewCoreImpl::GetTopControlsLayoutHeightPix() const {
+int ContentViewCoreImpl::GetTopControlsHeightPix() const {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
if (j_obj.is_null())
return 0;
- return Java_ContentViewCore_getTopControlsLayoutHeightPix(env, j_obj.obj());
+ return Java_ContentViewCore_getTopControlsHeightPix(env, j_obj.obj());
}
gfx::Size ContentViewCoreImpl::GetViewportSizeDip() const {
@@ -754,8 +773,16 @@ gfx::Size ContentViewCoreImpl::GetViewportSizeDip() const {
gfx::ScaleSize(GetViewportSizePix(), 1.0f / dpi_scale()));
}
-float ContentViewCoreImpl::GetTopControlsLayoutHeightDip() const {
- return GetTopControlsLayoutHeightPix() / dpi_scale();
+bool ContentViewCoreImpl::DoTopControlsShrinkBlinkSize() const {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
+ if (j_obj.is_null())
+ return false;
+ return Java_ContentViewCore_doTopControlsShrinkBlinkSize(env, j_obj.obj());
+}
+
+float ContentViewCoreImpl::GetTopControlsHeightDip() const {
+ return GetTopControlsHeightPix() / dpi_scale();
}
void ContentViewCoreImpl::AttachLayer(scoped_refptr<cc::Layer> layer) {
@@ -774,7 +801,7 @@ void ContentViewCoreImpl::MoveRangeSelectionExtent(const gfx::PointF& extent) {
if (!web_contents_)
return;
- web_contents_->MoveRangeSelectionExtent(gfx::Point(extent.x(), extent.y()));
+ web_contents_->MoveRangeSelectionExtent(gfx::ToRoundedPoint(extent));
}
void ContentViewCoreImpl::SelectBetweenCoordinates(const gfx::PointF& base,
@@ -782,8 +809,8 @@ void ContentViewCoreImpl::SelectBetweenCoordinates(const gfx::PointF& base,
if (!web_contents_)
return;
- gfx::Point base_point = gfx::Point(base.x(), base.y());
- gfx::Point extent_point = gfx::Point(extent.x(), extent.y());
+ gfx::Point base_point = gfx::ToRoundedPoint(base);
+ gfx::Point extent_point = gfx::ToRoundedPoint(extent);
if (base_point == extent_point)
return;
@@ -791,15 +818,15 @@ void ContentViewCoreImpl::SelectBetweenCoordinates(const gfx::PointF& base,
}
ui::ViewAndroid* ContentViewCoreImpl::GetViewAndroid() const {
- return view_android_;
+ return view_android_.get();
}
ui::WindowAndroid* ContentViewCoreImpl::GetWindowAndroid() const {
return window_android_;
}
-scoped_refptr<cc::Layer> ContentViewCoreImpl::GetLayer() const {
- return root_layer_.get();
+const scoped_refptr<cc::Layer>& ContentViewCoreImpl::GetLayer() const {
+ return root_layer_;
}
// ----------------------------------------------------------------------------
@@ -946,7 +973,8 @@ jboolean ContentViewCoreImpl::SendMouseWheelEvent(JNIEnv* env,
jlong time_ms,
jfloat x,
jfloat y,
- jfloat vertical_axis) {
+ jfloat vertical_axis,
+ jfloat horizontal_axis) {
RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
if (!rwhv)
return false;
@@ -956,6 +984,10 @@ jboolean ContentViewCoreImpl::SendMouseWheelEvent(JNIEnv* env,
direction = WebMouseWheelEventBuilder::DIRECTION_UP;
} else if (vertical_axis < 0) {
direction = WebMouseWheelEventBuilder::DIRECTION_DOWN;
+ } else if (horizontal_axis > 0) {
+ direction = WebMouseWheelEventBuilder::DIRECTION_RIGHT;
+ } else if (horizontal_axis < 0) {
+ direction = WebMouseWheelEventBuilder::DIRECTION_LEFT;
} else {
return false;
}
@@ -1023,16 +1055,24 @@ void ContentViewCoreImpl::FlingStart(JNIEnv* env, jobject obj, jlong time_ms,
void ContentViewCoreImpl::FlingCancel(JNIEnv* env, jobject obj, jlong time_ms) {
WebGestureEvent event = MakeGestureEvent(
WebInputEvent::GestureFlingCancel, time_ms, 0, 0);
+ event.data.flingCancel.preventBoosting = true;
+
SendGestureEvent(event);
}
void ContentViewCoreImpl::SingleTap(JNIEnv* env, jobject obj, jlong time_ms,
jfloat x, jfloat y) {
- WebGestureEvent event = MakeGestureEvent(
+ // Tap gestures should always be preceded by a TapDown, ensuring consistency
+ // with the touch-based gesture detection pipeline.
+ WebGestureEvent tap_down_event = MakeGestureEvent(
+ WebInputEvent::GestureTapDown, time_ms, x, y);
+ tap_down_event.data.tap.tapCount = 1;
+ SendGestureEvent(tap_down_event);
+
+ WebGestureEvent tap_event = MakeGestureEvent(
WebInputEvent::GestureTap, time_ms, x, y);
- event.data.tap.tapCount = 1;
-
- SendGestureEvent(event);
+ tap_event.data.tap.tapCount = 1;
+ SendGestureEvent(tap_event);
}
void ContentViewCoreImpl::DoubleTap(JNIEnv* env, jobject obj, jlong time_ms,
@@ -1210,6 +1250,34 @@ void ContentViewCoreImpl::SetAccessibilityEnabled(JNIEnv* env, jobject obj,
SetAccessibilityEnabledInternal(enabled);
}
+void ContentViewCoreImpl::SetTextTrackSettings(JNIEnv* env,
+ jobject obj,
+ jstring textTrackBackgroundColor,
+ jstring textTrackFontFamily,
+ jstring textTrackFontStyle,
+ jstring textTrackFontVariant,
+ jstring textTrackTextColor,
+ jstring textTrackTextShadow,
+ jstring textTrackTextSize) {
+ FrameMsg_TextTrackSettings_Params params;
+ params.text_track_background_color = ConvertJavaStringToUTF8(
+ env, textTrackBackgroundColor);
+ params.text_track_font_family = ConvertJavaStringToUTF8(
+ env, textTrackFontFamily);
+ params.text_track_font_style = ConvertJavaStringToUTF8(
+ env, textTrackFontStyle);
+ params.text_track_font_variant = ConvertJavaStringToUTF8(
+ env, textTrackFontVariant);
+ params.text_track_text_color = ConvertJavaStringToUTF8(
+ env, textTrackTextColor);
+ params.text_track_text_shadow = ConvertJavaStringToUTF8(
+ env, textTrackTextShadow);
+ params.text_track_text_size = ConvertJavaStringToUTF8(
+ env, textTrackTextSize);
+
+ web_contents_->GetMainFrame()->SetTextTrackSettings(params);
+}
+
bool ContentViewCoreImpl::IsFullscreenRequiredForOrientationLock() const {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
@@ -1280,6 +1348,12 @@ void ContentViewCoreImpl::SetBackgroundOpaque(JNIEnv* env, jobject jobj,
}
}
+void ContentViewCoreImpl::SetDrawsContent(JNIEnv* env,
+ jobject jobj,
+ jboolean draws) {
+ GetLayer()->SetHideLayerAndSubtree(!draws);
+}
+
void ContentViewCoreImpl::RequestTextSurroundingSelection(
int max_length,
const base::Callback<
@@ -1297,6 +1371,16 @@ void ContentViewCoreImpl::RequestTextSurroundingSelection(
}
}
+void ContentViewCoreImpl::OnShowUnhandledTapUIIfNeeded(int x_dip, int y_dip) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+ if (obj.is_null())
+ return;
+ Java_ContentViewCore_onShowUnhandledTapUIIfNeeded(
+ env, obj.obj(), static_cast<jint>(x_dip * dpi_scale()),
+ static_cast<jint>(y_dip * dpi_scale()));
+}
+
void ContentViewCoreImpl::OnSmartClipDataExtracted(
const base::string16& text,
const base::string16& html,
@@ -1319,22 +1403,67 @@ void ContentViewCoreImpl::WebContentsDestroyed() {
wcva->SetContentViewCore(NULL);
}
+bool ContentViewCoreImpl::PullStart() {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+ if (!obj.is_null())
+ return Java_ContentViewCore_onOverscrollRefreshStart(env, obj.obj());
+ return false;
+}
+
+void ContentViewCoreImpl::PullUpdate(float delta) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+ if (!obj.is_null())
+ Java_ContentViewCore_onOverscrollRefreshUpdate(env, obj.obj(), delta);
+}
+
+void ContentViewCoreImpl::PullRelease(bool allow_refresh) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+ if (!obj.is_null()) {
+ Java_ContentViewCore_onOverscrollRefreshRelease(env, obj.obj(),
+ allow_refresh);
+ }
+}
+
+void ContentViewCoreImpl::PullReset() {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+ if (!obj.is_null())
+ Java_ContentViewCore_onOverscrollRefreshReset(env, obj.obj());
+}
+
// This is called for each ContentView.
jlong Init(JNIEnv* env,
jobject obj,
- jlong native_web_contents,
- jlong view_android,
+ jobject web_contents,
+ jobject view_android_delegate,
jlong window_android,
jobject retained_objects_set) {
ContentViewCoreImpl* view = new ContentViewCoreImpl(
- env, obj,
- reinterpret_cast<WebContents*>(native_web_contents),
- reinterpret_cast<ui::ViewAndroid*>(view_android),
+ env, obj, WebContents::FromJavaWebContents(web_contents),
+ view_android_delegate,
reinterpret_cast<ui::WindowAndroid*>(window_android),
retained_objects_set);
return reinterpret_cast<intptr_t>(view);
}
+static jobject FromWebContentsAndroid(
+ JNIEnv* env,
+ jclass clazz,
+ jobject jweb_contents) {
+ WebContents* web_contents = WebContents::FromJavaWebContents(jweb_contents);
+ if (!web_contents)
+ return NULL;
+
+ ContentViewCore* view = ContentViewCore::FromWebContents(web_contents);
+ if (!view)
+ return NULL;
+
+ return view->GetJavaObject().Release();
+}
+
bool RegisterContentViewCore(JNIEnv* env) {
return RegisterNativesImpl(env);
}
diff --git a/chromium/content/browser/android/content_view_core_impl.h b/chromium/content/browser/android/content_view_core_impl.h
index 8a823ee72b8..0ca7c647247 100644
--- a/chromium/content/browser/android/content_view_core_impl.h
+++ b/chromium/content/browser/android/content_view_core_impl.h
@@ -13,13 +13,14 @@
#include "base/i18n/rtl.h"
#include "base/memory/scoped_ptr.h"
#include "base/process/process.h"
+#include "content/browser/android/overscroll_refresh.h"
#include "content/browser/renderer_host/render_widget_host_view_android.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/android/content_view_core.h"
#include "content/public/browser/web_contents_observer.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/rect_f.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/rect_f.h"
#include "url/gurl.h"
namespace ui {
@@ -34,34 +35,33 @@ class RenderFrameHost;
class RenderWidgetHostViewAndroid;
struct MenuItem;
-// TODO(jrg): this is a shell. Upstream the rest.
class ContentViewCoreImpl : public ContentViewCore,
+ public OverscrollRefreshHandler,
public WebContentsObserver {
public:
static ContentViewCoreImpl* FromWebContents(WebContents* web_contents);
ContentViewCoreImpl(JNIEnv* env,
jobject obj,
WebContents* web_contents,
- ui::ViewAndroid* view_android,
+ jobject view_android,
ui::WindowAndroid* window_android,
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 ShowPastePopup(int x, int y) override;
- virtual void GetScaledContentBitmap(
+ base::android::ScopedJavaLocalRef<jobject> GetJavaObject() override;
+ WebContents* GetWebContents() const override;
+ ui::ViewAndroid* GetViewAndroid() const override;
+ ui::WindowAndroid* GetWindowAndroid() const override;
+ const scoped_refptr<cc::Layer>& GetLayer() const override;
+ void ShowPastePopup(int x, int y) override;
+ void GetScaledContentBitmap(
float scale,
- SkColorType color_type,
+ SkColorType preferred_color_type,
gfx::Rect src_subrect,
- const base::Callback<void(bool, const SkBitmap&)>& result_callback)
- override;
- virtual float GetDpiScale() const override;
- virtual void PauseOrResumeGeolocation(bool should_pause) override;
- virtual void RequestTextSurroundingSelection(
+ ReadbackRequestCallback& result_callback) override;
+ float GetDpiScale() const override;
+ void PauseOrResumeGeolocation(bool should_pause) override;
+ void RequestTextSurroundingSelection(
int max_length,
const base::Callback<void(const base::string16& content,
int start_offset,
@@ -120,7 +120,8 @@ class ContentViewCoreImpl : public ContentViewCore,
jlong time_ms,
jfloat x,
jfloat y,
- jfloat vertical_axis);
+ jfloat vertical_axis,
+ jfloat horizontal_axis);
void ScrollBegin(JNIEnv* env, jobject obj, jlong time_ms,
jfloat x, jfloat y, jfloat hintx, jfloat hinty);
void ScrollEnd(JNIEnv* env, jobject obj, jlong time_ms);
@@ -172,6 +173,16 @@ class ContentViewCoreImpl : public ContentViewCore,
void SetAccessibilityEnabled(JNIEnv* env, jobject obj, bool enabled);
+ void SetTextTrackSettings(JNIEnv* env,
+ jobject obj,
+ jstring textTrackBackgroundColor,
+ jstring textTrackFontFamily,
+ jstring textTrackFontStyle,
+ jstring textTrackFontVariant,
+ jstring textTrackTextColor,
+ jstring textTrackTextShadow,
+ jstring textTrackTextSize);
+
void ExtractSmartClipData(JNIEnv* env,
jobject obj,
jint x,
@@ -180,6 +191,7 @@ class ContentViewCoreImpl : public ContentViewCore,
jint height);
void SetBackgroundOpaque(JNIEnv* env, jobject jobj, jboolean opaque);
+ void SetDrawsContent(JNIEnv* env, jobject jobj, jboolean draws);
jint GetCurrentRenderProcessId(JNIEnv* env, jobject obj);
@@ -210,7 +222,8 @@ class ContentViewCoreImpl : public ContentViewCore,
const gfx::SizeF& content_size,
const gfx::SizeF& viewport_size,
const gfx::Vector2dF& controls_offset,
- const gfx::Vector2dF& content_offset);
+ const gfx::Vector2dF& content_offset,
+ bool is_mobile_optimized_hint);
void UpdateImeAdapter(long native_ime_adapter,
int text_input_type,
@@ -226,13 +239,15 @@ class ContentViewCoreImpl : public ContentViewCore,
void OnBackgroundColorChanged(SkColor color);
bool HasFocus();
+ void RequestDisallowInterceptTouchEvent();
void OnGestureEventAck(const blink::WebGestureEvent& event,
InputEventAckState ack_result);
bool FilterInputEvent(const blink::WebInputEvent& event);
void OnSelectionChanged(const std::string& text);
- void OnSelectionEvent(SelectionEventType event,
- const gfx::PointF& anchor_position);
- scoped_ptr<TouchHandleDrawable> CreatePopupTouchHandleDrawable();
+ void OnSelectionEvent(ui::SelectionEventType event,
+ const gfx::PointF& selection_anchor,
+ const gfx::RectF& selection_rect);
+ scoped_ptr<ui::TouchHandleDrawable> CreatePopupTouchHandleDrawable();
void StartContentIntent(const GURL& content_url);
@@ -268,7 +283,8 @@ class ContentViewCoreImpl : public ContentViewCore,
gfx::Size GetPhysicalBackingSize() const;
gfx::Size GetViewportSizeDip() const;
- float GetTopControlsLayoutHeightDip() const;
+ bool DoTopControlsShrinkBlinkSize() const;
+ float GetTopControlsHeightDip() const;
void AttachLayer(scoped_refptr<cc::Layer> layer);
void RemoveLayer(scoped_refptr<cc::Layer> layer);
@@ -278,17 +294,25 @@ class ContentViewCoreImpl : public ContentViewCore,
void SelectBetweenCoordinates(const gfx::PointF& base,
const gfx::PointF& extent);
+ void OnShowUnhandledTapUIIfNeeded(int x_dip, int y_dip);
+
private:
class ContentViewUserData;
friend class ContentViewUserData;
- virtual ~ContentViewCoreImpl();
+ ~ContentViewCoreImpl() override;
// WebContentsObserver implementation.
- virtual void RenderViewReady() override;
- virtual void RenderViewHostChanged(RenderViewHost* old_host,
- RenderViewHost* new_host) override;
- virtual void WebContentsDestroyed() override;
+ void RenderViewReady() override;
+ void RenderViewHostChanged(RenderViewHost* old_host,
+ RenderViewHost* new_host) override;
+ void WebContentsDestroyed() override;
+
+ // OverscrollRefreshHandler implementation.
+ bool PullStart() override;
+ void PullUpdate(float delta) override;
+ void PullRelease(bool allow_refresh) override;
+ void PullReset() override;
// --------------------------------------------------------------------------
// Other private methods and data
@@ -296,13 +320,13 @@ class ContentViewCoreImpl : public ContentViewCore,
void InitWebContents();
- RenderWidgetHostViewAndroid* GetRenderWidgetHostViewAndroid();
+ RenderWidgetHostViewAndroid* GetRenderWidgetHostViewAndroid() const;
blink::WebGestureEvent MakeGestureEvent(
blink::WebInputEvent::Type type, int64 time_ms, float x, float y) const;
gfx::Size GetViewportSizePix() const;
- int GetTopControlsLayoutHeightPix() const;
+ int GetTopControlsHeightPix() const;
void SendGestureEvent(const blink::WebGestureEvent& event);
@@ -329,7 +353,7 @@ class ContentViewCoreImpl : public ContentViewCore,
// The Android view that can be used to add and remove decoration layers
// like AutofillPopup.
- ui::ViewAndroid* view_android_;
+ scoped_ptr<ui::ViewAndroid> view_android_;
// The owning window that has a hold of main application activity.
ui::WindowAndroid* window_android_;
@@ -341,8 +365,7 @@ class ContentViewCoreImpl : public ContentViewCore,
bool accessibility_enabled_;
// Manages injecting Java objects.
- scoped_ptr<GinJavaBridgeDispatcherHost>
- java_bridge_dispatcher_host_;
+ scoped_refptr<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 deae6733c4e..eb6a695d121 100644
--- a/chromium/content/browser/android/content_view_render_view.cc
+++ b/chromium/content/browser/android/content_view_render_view.cc
@@ -15,11 +15,9 @@
#include "content/browser/android/content_view_core_impl.h"
#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"
+#include "ui/gfx/geometry/size.h"
#include <android/bitmap.h>
#include <android/native_window_jni.h>
@@ -28,24 +26,6 @@ using base::android::ScopedJavaLocalRef;
namespace content {
-namespace {
-
-class LayerTreeBuildHelperImpl : public LayerTreeBuildHelper {
- public:
- LayerTreeBuildHelperImpl() {}
- virtual ~LayerTreeBuildHelperImpl() {}
-
- virtual scoped_refptr<cc::Layer> GetLayerTree(
- scoped_refptr<cc::Layer> content_root_layer) override {
- return content_root_layer;
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(LayerTreeBuildHelperImpl);
-};
-
-} // anonymous namespace
-
// static
bool ContentViewRenderView::RegisterContentViewRenderView(JNIEnv* env) {
return RegisterNativesImpl(env);
@@ -54,25 +34,13 @@ bool ContentViewRenderView::RegisterContentViewRenderView(JNIEnv* env) {
ContentViewRenderView::ContentViewRenderView(JNIEnv* env,
jobject obj,
gfx::NativeWindow root_window)
- : layer_tree_build_helper_(new LayerTreeBuildHelperImpl()),
- root_window_(root_window),
- current_surface_format_(0) {
+ : root_window_(root_window), current_surface_format_(0) {
java_obj_.Reset(env, obj);
}
ContentViewRenderView::~ContentViewRenderView() {
}
-void ContentViewRenderView::SetLayerTreeBuildHelper(JNIEnv* env,
- jobject obj,
- jlong native_build_helper) {
- CHECK(native_build_helper);
-
- LayerTreeBuildHelper* build_helper =
- reinterpret_cast<LayerTreeBuildHelper*>(native_build_helper);
- layer_tree_build_helper_.reset(build_helper);
- InitCompositor();
-}
// static
static jlong Init(JNIEnv* env,
jobject obj,
@@ -93,10 +61,8 @@ void ContentViewRenderView::SetCurrentContentViewCore(
InitCompositor();
ContentViewCoreImpl* content_view_core =
reinterpret_cast<ContentViewCoreImpl*>(native_content_view_core);
- compositor_->SetRootLayer(content_view_core
- ? layer_tree_build_helper_->GetLayerTree(
- content_view_core->GetLayer())
- : scoped_refptr<cc::Layer>());
+ compositor_->SetRootLayer(content_view_core ? content_view_core->GetLayer()
+ : scoped_refptr<cc::Layer>());
}
void ContentViewRenderView::SurfaceCreated(
diff --git a/chromium/content/browser/android/content_view_render_view.h b/chromium/content/browser/android/content_view_render_view.h
index ed3f03cc3fa..c79936db30b 100644
--- a/chromium/content/browser/android/content_view_render_view.h
+++ b/chromium/content/browser/android/content_view_render_view.h
@@ -34,8 +34,6 @@ class ContentViewRenderView : public CompositorClient {
void Destroy(JNIEnv* env, jobject obj);
void SetCurrentContentViewCore(JNIEnv* env, jobject obj,
jlong native_content_view_core);
- void SetLayerTreeBuildHelper(
- JNIEnv* env, jobject obj, jlong native_build_helper);
void SurfaceCreated(JNIEnv* env, jobject obj);
void SurfaceDestroyed(JNIEnv* env, jobject obj);
void SurfaceChanged(JNIEnv* env, jobject obj,
@@ -49,16 +47,15 @@ class ContentViewRenderView : public CompositorClient {
jlong GetUIResourceProvider(JNIEnv* env, jobject obj);
// CompositorClient implementation
- virtual void Layout() override;
- virtual void OnSwapBuffersCompleted(int pending_swap_buffers) override;
+ void Layout() override;
+ void OnSwapBuffersCompleted(int pending_swap_buffers) override;
private:
- virtual ~ContentViewRenderView();
+ ~ContentViewRenderView() override;
void InitCompositor();
base::android::ScopedJavaGlobalRef<jobject> java_obj_;
- scoped_ptr<LayerTreeBuildHelper> layer_tree_build_helper_;
scoped_ptr<content::Compositor> compositor_;
diff --git a/chromium/content/browser/android/content_view_statics.cc b/chromium/content/browser/android/content_view_statics.cc
index 1c4e9035d15..e0f26a0fff8 100644
--- a/chromium/content/browser/android/content_view_statics.cc
+++ b/chromium/content/browser/android/content_view_statics.cc
@@ -40,14 +40,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::TerminationStatus status,
- int exit_code) override {
+ void RenderProcessExited(content::RenderProcessHost* host,
+ base::TerminationStatus status,
+ int exit_code) override {
StopWatching(host);
}
- virtual void RenderProcessHostDestroyed(
- content::RenderProcessHost* host) override {
+ void RenderProcessHostDestroyed(content::RenderProcessHost* host) override {
StopWatching(host);
}
diff --git a/chromium/content/browser/android/content_view_statics.h b/chromium/content/browser/android/content_view_statics.h
index e640fec551e..00402531a3a 100644
--- a/chromium/content/browser/android/content_view_statics.h
+++ b/chromium/content/browser/android/content_view_statics.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_ANDROID_VIEW_STATICS_H_
-#define CONTENT_BROWSER_ANDROID_VIEW_STATICS_H_
+#ifndef CONTENT_BROWSER_ANDROID_CONTENT_VIEW_STATICS_H_
+#define CONTENT_BROWSER_ANDROID_CONTENT_VIEW_STATICS_H_
namespace content {
@@ -11,4 +11,4 @@ bool RegisterWebViewStatics(JNIEnv* env);
}
-#endif // CONTENT_BROWSER_ANDROID_VIEW_STATICS_H_
+#endif // CONTENT_BROWSER_ANDROID_CONTENT_VIEW_STATICS_H_
diff --git a/chromium/content/browser/android/date_time_chooser_android.cc b/chromium/content/browser/android/date_time_chooser_android.cc
index 31ff4656bef..b555ef6d6b2 100644
--- a/chromium/content/browser/android/date_time_chooser_android.cc
+++ b/chromium/content/browser/android/date_time_chooser_android.cc
@@ -13,7 +13,7 @@
#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"
+#include "ui/android/window_android.h"
using base::android::AttachCurrentThread;
using base::android::ConvertJavaStringToUTF16;
@@ -49,19 +49,6 @@ DateTimeChooserAndroid::DateTimeChooserAndroid()
DateTimeChooserAndroid::~DateTimeChooserAndroid() {
}
-// static
-void DateTimeChooserAndroid::InitializeDateInputTypes(
- int text_input_type_date, int text_input_type_date_time,
- int text_input_type_date_time_local, int text_input_type_month,
- int text_input_type_time, int text_input_type_week) {
- JNIEnv* env = AttachCurrentThread();
- Java_DateTimeChooserAndroid_initializeDateInputTypes(
- env,
- text_input_type_date, text_input_type_date_time,
- text_input_type_date_time_local, text_input_type_month,
- text_input_type_time, text_input_type_week);
-}
-
void DateTimeChooserAndroid::ReplaceDateTime(JNIEnv* env,
jobject,
jdouble value) {
@@ -120,16 +107,7 @@ void DateTimeChooserAndroid::ShowDialog(
// Native JNI methods
// ----------------------------------------------------------------------------
bool RegisterDateTimeChooserAndroid(JNIEnv* env) {
- bool registered = RegisterNativesImpl(env);
- if (registered)
- DateTimeChooserAndroid::InitializeDateInputTypes(
- ui::TEXT_INPUT_TYPE_DATE,
- ui::TEXT_INPUT_TYPE_DATE_TIME,
- ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL,
- ui::TEXT_INPUT_TYPE_MONTH,
- ui::TEXT_INPUT_TYPE_TIME,
- ui::TEXT_INPUT_TYPE_WEEK);
- return registered;
+ return RegisterNativesImpl(env);
}
} // namespace content
diff --git a/chromium/content/browser/android/date_time_chooser_android.h b/chromium/content/browser/android/date_time_chooser_android.h
index 1a29b4a0f05..6e6c8954b9c 100644
--- a/chromium/content/browser/android/date_time_chooser_android.h
+++ b/chromium/content/browser/android/date_time_chooser_android.h
@@ -43,13 +43,6 @@ class DateTimeChooserAndroid {
// Closes the dialog without propagating any changes.
void CancelDialog(JNIEnv* env, jobject);
- // Propagates the different types of accepted date/time values to the
- // java side.
- static void InitializeDateInputTypes(
- int text_input_type_date, int text_input_type_date_time,
- int text_input_type_date_time_local, int text_input_type_month,
- int text_input_type_time, int text_input_type_week);
-
private:
RenderViewHost* host_;
diff --git a/chromium/content/browser/android/deferred_download_observer.cc b/chromium/content/browser/android/deferred_download_observer.cc
new file mode 100644
index 00000000000..b1c6c7de9d2
--- /dev/null
+++ b/chromium/content/browser/android/deferred_download_observer.cc
@@ -0,0 +1,31 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/android/deferred_download_observer.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "content/browser/android/download_controller_android_impl.h"
+#include "content/public/browser/web_contents.h"
+
+namespace content {
+
+DeferredDownloadObserver::DeferredDownloadObserver(
+ WebContents* web_contents,
+ const base::Closure& deferred_download_cb)
+ : WebContentsObserver(web_contents),
+ deferred_download_cb_(deferred_download_cb) {
+}
+
+DeferredDownloadObserver::~DeferredDownloadObserver() {}
+
+void DeferredDownloadObserver::WasShown() {
+ deferred_download_cb_.Run();
+ DownloadControllerAndroidImpl::GetInstance()->CancelDeferredDownload(this);
+}
+
+void DeferredDownloadObserver::WebContentsDestroyed() {
+ DownloadControllerAndroidImpl::GetInstance()->CancelDeferredDownload(this);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/android/deferred_download_observer.h b/chromium/content/browser/android/deferred_download_observer.h
new file mode 100644
index 00000000000..f1df3178ba9
--- /dev/null
+++ b/chromium/content/browser/android/deferred_download_observer.h
@@ -0,0 +1,41 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_ANDROID_DEFERRED_DOWNLOAD_OBSERVER_H_
+#define CONTENT_BROWSER_ANDROID_DEFERRED_DOWNLOAD_OBSERVER_H_
+
+#include "base/callback.h"
+#include "base/containers/scoped_ptr_hash_map.h"
+#include "content/public/browser/web_contents_observer.h"
+
+namespace content {
+class WebContents;
+
+// Class for handling deferred downloads inside a WebContents. In document
+// mode, it is possible that a download starts before ContentViewCore gets
+// created. This class listens to the WebContentsObserver::WasShown() method
+// before running the download tasks to make sure ContentViewCore is attached
+// to WebContents.
+// TODO(qinmin): Remove this when java Tab object creation is no longer pending
+// on Activity creation.
+class DeferredDownloadObserver : public WebContentsObserver {
+ public:
+ DeferredDownloadObserver(WebContents* web_contents,
+ const base::Closure& deferred_download_cb);
+ ~DeferredDownloadObserver() override;
+
+ // WebContentsObserver method.
+ void WasShown() override;
+ void WebContentsDestroyed() override;
+
+ private:
+ // Callback to run when WebContents gets shown.
+ base::Closure deferred_download_cb_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeferredDownloadObserver);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_ANDROID_DEFERRED_DOWNLOAD_OBSERVER_H_
diff --git a/chromium/content/browser/android/download_controller_android_impl.cc b/chromium/content/browser/android/download_controller_android_impl.cc
index 08cea4be685..353e2611b3e 100644
--- a/chromium/content/browser/android/download_controller_android_impl.cc
+++ b/chromium/content/browser/android/download_controller_android_impl.cc
@@ -11,6 +11,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/time/time.h"
#include "content/browser/android/content_view_core_impl.h"
+#include "content/browser/android/deferred_download_observer.h"
#include "content/browser/download/download_item_impl.h"
#include "content/browser/download/download_manager_impl.h"
#include "content/browser/loader/resource_dispatcher_host_impl.h"
@@ -84,9 +85,20 @@ void DownloadControllerAndroidImpl::Init(JNIEnv* env, jobject obj) {
java_object_->obj = env->NewWeakGlobalRef(obj);
}
+void DownloadControllerAndroidImpl::CancelDeferredDownload(
+ DeferredDownloadObserver* observer) {
+ for (auto iter = deferred_downloads_.begin();
+ iter != deferred_downloads_.end(); ++iter) {
+ if (*iter == observer) {
+ deferred_downloads_.erase(iter);
+ return;
+ }
+ }
+}
+
void DownloadControllerAndroidImpl::CreateGETDownload(
int render_process_id, int render_view_id, int request_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
GlobalRequestID global_id(render_process_id, request_id);
// We are yielding the UI thread and render_view_host may go away by
@@ -106,7 +118,7 @@ void DownloadControllerAndroidImpl::CreateGETDownload(
void DownloadControllerAndroidImpl::PrepareDownloadInfo(
const GlobalRequestID& global_id,
const GetDownloadInfoCB& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
net::URLRequest* request =
ResourceDispatcherHostImpl::Get()->GetURLRequest(global_id);
@@ -138,7 +150,7 @@ void DownloadControllerAndroidImpl::PrepareDownloadInfo(
void DownloadControllerAndroidImpl::CheckPolicyAndLoadCookies(
const DownloadInfoAndroid& info, const GetDownloadInfoCB& callback,
const GlobalRequestID& global_id, const net::CookieList& cookie_list) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
net::URLRequest* request =
ResourceDispatcherHostImpl::Get()->GetURLRequest(global_id);
@@ -158,7 +170,7 @@ void DownloadControllerAndroidImpl::CheckPolicyAndLoadCookies(
void DownloadControllerAndroidImpl::DoLoadCookies(
const DownloadInfoAndroid& info, const GetDownloadInfoCB& callback,
const GlobalRequestID& global_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
net::CookieOptions options;
options.set_include_httponly();
@@ -189,7 +201,7 @@ void DownloadControllerAndroidImpl::OnCookieResponse(
void DownloadControllerAndroidImpl::StartDownloadOnUIThread(
const GetDownloadInfoCB& callback,
const DownloadInfoAndroid& info) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE, base::Bind(callback, info));
}
@@ -197,18 +209,29 @@ void DownloadControllerAndroidImpl::StartDownloadOnUIThread(
void DownloadControllerAndroidImpl::StartAndroidDownload(
int render_process_id, int render_view_id,
const DownloadInfoAndroid& info) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
JNIEnv* env = base::android::AttachCurrentThread();
// Call newHttpGetDownload
- ScopedJavaLocalRef<jobject> view = GetContentView(render_process_id,
- render_view_id);
- if (view.is_null()) {
+ WebContents* web_contents = GetWebContents(render_process_id, render_view_id);
+ if (!web_contents) {
// The view went away. Can't proceed.
LOG(ERROR) << "Download failed on URL:" << info.url.spec();
return;
}
-
+ ScopedJavaLocalRef<jobject> view =
+ GetContentViewCoreFromWebContents(web_contents);
+ if (view.is_null()) {
+ // ContentViewCore might not have been created yet, pass a callback to
+ // DeferredDownloadTaskManager so that the download can restart when
+ // ContentViewCore is created.
+ deferred_downloads_.push_back(new DeferredDownloadObserver(
+ web_contents,
+ base::Bind(&DownloadControllerAndroidImpl::StartAndroidDownload,
+ base::Unretained(this), render_process_id, render_view_id,
+ info)));
+ return;
+ }
ScopedJavaLocalRef<jstring> jurl =
ConvertUTF8ToJavaString(env, info.url.spec());
ScopedJavaLocalRef<jstring> juser_agent =
@@ -237,7 +260,7 @@ void DownloadControllerAndroidImpl::StartAndroidDownload(
void DownloadControllerAndroidImpl::OnDownloadStarted(
DownloadItem* download_item) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!download_item->GetWebContents())
return;
@@ -262,7 +285,7 @@ void DownloadControllerAndroidImpl::OnDownloadStarted(
}
void DownloadControllerAndroidImpl::OnDownloadUpdated(DownloadItem* item) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (item->IsDangerous() && (item->GetState() != DownloadItem::CANCELLED))
OnDangerousDownload(item);
@@ -329,18 +352,15 @@ void DownloadControllerAndroidImpl::OnDangerousDownload(DownloadItem* item) {
}
}
-ScopedJavaLocalRef<jobject> DownloadControllerAndroidImpl::GetContentView(
+WebContents* DownloadControllerAndroidImpl::GetWebContents(
int render_process_id, int render_view_id) {
RenderViewHost* render_view_host =
RenderViewHost::FromID(render_process_id, render_view_id);
if (!render_view_host)
- return ScopedJavaLocalRef<jobject>();
-
- WebContents* web_contents =
- render_view_host->GetDelegate()->GetAsWebContents();
+ return NULL;
- return GetContentViewCoreFromWebContents(web_contents);
+ return render_view_host->GetDelegate()->GetAsWebContents();
}
ScopedJavaLocalRef<jobject>
@@ -371,14 +391,17 @@ DownloadControllerAndroidImpl::JavaObject*
void DownloadControllerAndroidImpl::StartContextMenuDownload(
const ContextMenuParams& params, WebContents* web_contents, bool is_link) {
const GURL& url = is_link ? params.link_url : params.src_url;
- const GURL& referrer = params.frame_url.is_empty() ?
+ const GURL& referring_url = params.frame_url.is_empty() ?
params.page_url : params.frame_url;
DownloadManagerImpl* dlm = static_cast<DownloadManagerImpl*>(
BrowserContext::GetDownloadManager(web_contents->GetBrowserContext()));
scoped_ptr<DownloadUrlParameters> dl_params(
DownloadUrlParameters::FromWebContents(web_contents, url));
- dl_params->set_referrer(
- Referrer(referrer, params.referrer_policy));
+ content::Referrer referrer = content::Referrer::SanitizeForRequest(
+ url,
+ content::Referrer(referring_url.GetAsReferrer(),
+ params.referrer_policy));
+ dl_params->set_referrer(referrer);
if (is_link)
dl_params->set_referrer_encoding(params.frame_charset);
else
diff --git a/chromium/content/browser/android/download_controller_android_impl.h b/chromium/content/browser/android/download_controller_android_impl.h
index 7bc71bf74e2..dd391238cde 100644
--- a/chromium/content/browser/android/download_controller_android_impl.h
+++ b/chromium/content/browser/android/download_controller_android_impl.h
@@ -24,6 +24,7 @@
#include "base/android/jni_weak_ref.h"
#include "base/android/scoped_java_ref.h"
#include "base/callback.h"
+#include "base/memory/scoped_vector.h"
#include "base/memory/singleton.h"
#include "content/public/browser/android/download_controller_android.h"
#include "content/public/browser/download_item.h"
@@ -36,6 +37,7 @@ class URLRequest;
namespace content {
struct GlobalRequestID;
+class DeferredDownloadObserver;
class RenderViewHost;
class WebContents;
@@ -48,6 +50,10 @@ class DownloadControllerAndroidImpl : public DownloadControllerAndroid,
// Called when DownloadController Java object is instantiated.
void Init(JNIEnv* env, jobject obj);
+
+ // Removes a deferred download from |deferred_downloads_|.
+ void CancelDeferredDownload(DeferredDownloadObserver* observer);
+
private:
// Used to store all the information about an Android download.
struct DownloadInfoAndroid {
@@ -73,20 +79,22 @@ class DownloadControllerAndroidImpl : public DownloadControllerAndroid,
struct JavaObject;
friend struct DefaultSingletonTraits<DownloadControllerAndroidImpl>;
DownloadControllerAndroidImpl();
- virtual ~DownloadControllerAndroidImpl();
+ ~DownloadControllerAndroidImpl() override;
// DownloadControllerAndroid implementation.
- virtual void CreateGETDownload(int render_process_id, int render_view_id,
- int request_id) override;
- virtual void OnDownloadStarted(DownloadItem* download_item) override;
- virtual void StartContextMenuDownload(
- const ContextMenuParams& params, WebContents* web_contents,
- bool is_link) override;
- virtual void DangerousDownloadValidated(
- WebContents* web_contents, int download_id, bool accept) override;
+ void CreateGETDownload(int render_process_id,
+ int render_view_id,
+ int request_id) override;
+ void OnDownloadStarted(DownloadItem* download_item) override;
+ void StartContextMenuDownload(const ContextMenuParams& params,
+ WebContents* web_contents,
+ bool is_link) override;
+ void DangerousDownloadValidated(WebContents* web_contents,
+ int download_id,
+ bool accept) override;
// DownloadItem::Observer interface.
- virtual void OnDownloadUpdated(DownloadItem* item) override;
+ void OnDownloadUpdated(DownloadItem* item) override;
typedef base::Callback<void(const DownloadInfoAndroid&)>
GetDownloadInfoCB;
@@ -114,14 +122,15 @@ class DownloadControllerAndroidImpl : public DownloadControllerAndroid,
base::android::ScopedJavaLocalRef<jobject> GetContentViewCoreFromWebContents(
WebContents* web_contents);
- base::android::ScopedJavaLocalRef<jobject> GetContentView(
- int render_process_id, int render_view_id);
+ WebContents* GetWebContents(int render_process_id, int render_view_id);
// Creates Java object if it is not created already and returns it.
JavaObject* GetJavaObject();
JavaObject* java_object_;
+ ScopedVector<DeferredDownloadObserver> deferred_downloads_;
+
DISALLOW_COPY_AND_ASSIGN(DownloadControllerAndroidImpl);
};
diff --git a/chromium/content/browser/android/edge_effect.cc b/chromium/content/browser/android/edge_effect.cc
index 00c1aa51c0c..f1b6ee807b8 100644
--- a/chromium/content/browser/android/edge_effect.cc
+++ b/chromium/content/browser/android/edge_effect.cc
@@ -6,12 +6,17 @@
#include "cc/layers/layer.h"
#include "cc/layers/ui_resource_layer.h"
-#include "ui/base/android/system_ui_resource_manager.h"
+#include "content/browser/android/animation_utils.h"
+#include "ui/android/resources/resource_manager.h"
+#include "ui/android/resources/system_ui_resource_type.h"
namespace content {
namespace {
+const ui::SystemUIResourceType kEdgeResourceId = ui::OVERSCROLL_EDGE;
+const ui::SystemUIResourceType kGlowResourceId = ui::OVERSCROLL_GLOW;
+
// Time it will take the effect to fully recede in ms
const int kRecedeTimeMs = 1000;
@@ -52,33 +57,12 @@ 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;
-}
-
-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
class EdgeEffect::EffectLayer {
public:
- EffectLayer(ui::SystemUIResourceManager::ResourceType resource_type,
- ui::SystemUIResourceManager* resource_manager)
+ EffectLayer(ui::SystemUIResourceType resource_type,
+ ui::ResourceManager* resource_manager)
: ui_resource_layer_(cc::UIResourceLayer::Create()),
resource_type_(resource_type),
resource_manager_(resource_manager) {}
@@ -88,8 +72,6 @@ class EdgeEffect::EffectLayer {
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); }
@@ -97,8 +79,8 @@ class EdgeEffect::EffectLayer {
void Update(const gfx::Size& size,
const gfx::Transform& transform,
float opacity) {
- ui_resource_layer_->SetUIResourceId(
- resource_manager_->GetUIResourceId(resource_type_));
+ ui_resource_layer_->SetUIResourceId(resource_manager_->GetUIResourceId(
+ ui::ANDROID_RESOURCE_TYPE_SYSTEM, resource_type_));
ui_resource_layer_->SetIsDrawable(true);
ui_resource_layer_->SetTransformOrigin(
gfx::Point3F(size.width() * 0.5f, 0, 0));
@@ -108,18 +90,16 @@ class EdgeEffect::EffectLayer {
}
scoped_refptr<cc::UIResourceLayer> ui_resource_layer_;
- ui::SystemUIResourceManager::ResourceType resource_type_;
- ui::SystemUIResourceManager* resource_manager_;
+ ui::SystemUIResourceType resource_type_;
+ ui::ResourceManager* resource_manager_;
DISALLOW_COPY_AND_ASSIGN(EffectLayer);
};
-EdgeEffect::EdgeEffect(ui::SystemUIResourceManager* resource_manager,
+EdgeEffect::EdgeEffect(ui::ResourceManager* resource_manager,
float device_scale_factor)
- : edge_(new EffectLayer(ui::SystemUIResourceManager::OVERSCROLL_EDGE,
- resource_manager)),
- glow_(new EffectLayer(ui::SystemUIResourceManager::OVERSCROLL_GLOW,
- resource_manager)),
+ : edge_(new EffectLayer(kEdgeResourceId, resource_manager)),
+ glow_(new EffectLayer(kGlowResourceId, resource_manager)),
base_edge_height_(kEdgeHeightAtMdpi * device_scale_factor),
base_glow_height_(kGlowHeightAtMdpi * device_scale_factor),
edge_alpha_(0),
@@ -325,6 +305,10 @@ bool EdgeEffect::Update(base::TimeTicks current_time) {
return !IsFinished();
}
+float EdgeEffect::GetAlpha() const {
+ return IsFinished() ? 0.f : std::max(glow_alpha_, edge_alpha_);
+}
+
void EdgeEffect::ApplyToLayers(const gfx::SizeF& size,
const gfx::Transform& transform) {
if (IsFinished())
@@ -359,13 +343,12 @@ void EdgeEffect::SetParent(cc::Layer* parent) {
}
// static
-void EdgeEffect::PreloadResources(
- ui::SystemUIResourceManager* resource_manager) {
+void EdgeEffect::PreloadResources(ui::ResourceManager* resource_manager) {
DCHECK(resource_manager);
- resource_manager->PreloadResource(
- ui::SystemUIResourceManager::OVERSCROLL_EDGE);
- resource_manager->PreloadResource(
- ui::SystemUIResourceManager::OVERSCROLL_GLOW);
+ resource_manager->PreloadResource(ui::ANDROID_RESOURCE_TYPE_SYSTEM,
+ kEdgeResourceId);
+ resource_manager->PreloadResource(ui::ANDROID_RESOURCE_TYPE_SYSTEM,
+ kGlowResourceId);
}
} // namespace content
diff --git a/chromium/content/browser/android/edge_effect.h b/chromium/content/browser/android/edge_effect.h
index 8fb5c5f55d3..21962210c20 100644
--- a/chromium/content/browser/android/edge_effect.h
+++ b/chromium/content/browser/android/edge_effect.h
@@ -13,7 +13,7 @@ class Layer;
}
namespace ui {
-class SystemUIResourceManager;
+class ResourceManager;
}
namespace content {
@@ -24,26 +24,27 @@ namespace content {
// All coordinates and dimensions are in device pixels.
class EdgeEffect : public EdgeEffectBase {
public:
- explicit EdgeEffect(ui::SystemUIResourceManager* resource_manager,
+ explicit EdgeEffect(ui::ResourceManager* resource_manager,
float device_scale_factor);
- virtual ~EdgeEffect();
+ ~EdgeEffect() override;
- 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;
+ void Pull(base::TimeTicks current_time,
+ float delta_distance,
+ float displacement) override;
+ void Absorb(base::TimeTicks current_time, float velocity) override;
+ bool Update(base::TimeTicks current_time) override;
+ void Release(base::TimeTicks current_time) override;
- virtual void Finish() override;
- virtual bool IsFinished() const override;
+ void Finish() override;
+ bool IsFinished() const override;
+ float GetAlpha() const override;
- virtual void ApplyToLayers(const gfx::SizeF& size,
- const gfx::Transform& transform) override;
- virtual void SetParent(cc::Layer* parent) override;
+ void ApplyToLayers(const gfx::SizeF& size,
+ const gfx::Transform& transform) override;
+ void SetParent(cc::Layer* parent) override;
// Thread-safe trigger to load resources.
- static void PreloadResources(ui::SystemUIResourceManager* resource_manager);
+ static void PreloadResources(ui::ResourceManager* resource_manager);
private:
class EffectLayer;
diff --git a/chromium/content/browser/android/edge_effect_base.h b/chromium/content/browser/android/edge_effect_base.h
index f7df20dfe16..1947b4506e3 100644
--- a/chromium/content/browser/android/edge_effect_base.h
+++ b/chromium/content/browser/android/edge_effect_base.h
@@ -38,6 +38,7 @@ class EdgeEffectBase {
virtual void Finish() = 0;
virtual bool IsFinished() const = 0;
+ virtual float GetAlpha() const = 0;
virtual void ApplyToLayers(const gfx::SizeF& size,
const gfx::Transform& transform) = 0;
diff --git a/chromium/content/browser/android/edge_effect_l.cc b/chromium/content/browser/android/edge_effect_l.cc
index ccec8a41c47..728db67dbe8 100644
--- a/chromium/content/browser/android/edge_effect_l.cc
+++ b/chromium/content/browser/android/edge_effect_l.cc
@@ -5,7 +5,9 @@
#include "content/browser/android/edge_effect_l.h"
#include "cc/layers/ui_resource_layer.h"
-#include "ui/base/android/system_ui_resource_manager.h"
+#include "content/browser/android/animation_utils.h"
+#include "ui/android/resources/resource_manager.h"
+#include "ui/android/resources/system_ui_resource_type.h"
namespace content {
@@ -40,33 +42,11 @@ 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;
-}
+const ui::SystemUIResourceType kResourceId = ui::OVERSCROLL_GLOW_L;
} // namespace
-EdgeEffectL::EdgeEffectL(ui::SystemUIResourceManager* resource_manager)
+EdgeEffectL::EdgeEffectL(ui::ResourceManager* resource_manager)
: resource_manager_(resource_manager),
glow_(cc::UIResourceLayer::Create()),
glow_alpha_(0),
@@ -231,6 +211,10 @@ bool EdgeEffectL::Update(base::TimeTicks current_time) {
return !IsFinished() || one_last_frame;
}
+float EdgeEffectL::GetAlpha() const {
+ return IsFinished() ? 0.f : glow_alpha_;
+}
+
void EdgeEffectL::ApplyToLayers(const gfx::SizeF& size,
const gfx::Transform& transform) {
if (IsFinished())
@@ -255,7 +239,8 @@ void EdgeEffectL::ApplyToLayers(const gfx::SizeF& size,
r, std::min(1.f, glow_scale_y_) * base_glow_scale * bounds_.height());
glow_->SetIsDrawable(true);
- glow_->SetUIResourceId(resource_manager_->GetUIResourceId(kResourceType));
+ glow_->SetUIResourceId(resource_manager_->GetUIResourceId(
+ ui::ANDROID_RESOURCE_TYPE_SYSTEM, kResourceId));
glow_->SetTransformOrigin(gfx::Point3F(bounds_.width() * 0.5f, 0, 0));
glow_->SetBounds(image_bounds);
glow_->SetContentsOpaque(false);
@@ -273,14 +258,13 @@ void EdgeEffectL::ApplyToLayers(const gfx::SizeF& size,
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) {
+void EdgeEffectL::PreloadResources(ui::ResourceManager* resource_manager) {
DCHECK(resource_manager);
- resource_manager->PreloadResource(kResourceType);
+ resource_manager->PreloadResource(ui::ANDROID_RESOURCE_TYPE_SYSTEM,
+ kResourceId);
}
} // namespace content
diff --git a/chromium/content/browser/android/edge_effect_l.h b/chromium/content/browser/android/edge_effect_l.h
index a24309c8da3..872de821039 100644
--- a/chromium/content/browser/android/edge_effect_l.h
+++ b/chromium/content/browser/android/edge_effect_l.h
@@ -17,7 +17,7 @@ class UIResourceLayer;
}
namespace ui {
-class SystemUIResourceManager;
+class ResourceManager;
}
namespace content {
@@ -28,28 +28,29 @@ namespace content {
// All coordinates and dimensions are in device pixels.
class EdgeEffectL : public EdgeEffectBase {
public:
- explicit EdgeEffectL(ui::SystemUIResourceManager* resource_manager);
- virtual ~EdgeEffectL();
+ explicit EdgeEffectL(ui::ResourceManager* resource_manager);
+ ~EdgeEffectL() override;
- 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;
+ void Pull(base::TimeTicks current_time,
+ float delta_distance,
+ float displacement) override;
+ void Absorb(base::TimeTicks current_time, float velocity) override;
+ bool Update(base::TimeTicks current_time) override;
+ void Release(base::TimeTicks current_time) override;
- virtual void Finish() override;
- virtual bool IsFinished() const override;
+ void Finish() override;
+ bool IsFinished() const override;
+ float GetAlpha() const override;
- virtual void ApplyToLayers(const gfx::SizeF& size,
- const gfx::Transform& transform) override;
- virtual void SetParent(cc::Layer* parent) override;
+ void ApplyToLayers(const gfx::SizeF& size,
+ const gfx::Transform& transform) override;
+ void SetParent(cc::Layer* parent) override;
// Thread-safe trigger to load resources.
- static void PreloadResources(ui::SystemUIResourceManager* resource_manager);
+ static void PreloadResources(ui::ResourceManager* resource_manager);
private:
- ui::SystemUIResourceManager* const resource_manager_;
+ ui::ResourceManager* const resource_manager_;
scoped_refptr<cc::UIResourceLayer> glow_;
diff --git a/chromium/content/browser/android/gesture_event_type.h b/chromium/content/browser/android/gesture_event_type.h
index ce87c901db3..1b4854ceba9 100644
--- a/chromium/content/browser/android/gesture_event_type.h
+++ b/chromium/content/browser/android/gesture_event_type.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_ANDROID_GESTURE_EVENT_TYPE_
-#define CONTENT_BROWSER_ANDROID_GESTURE_EVENT_TYPE_
+#ifndef CONTENT_BROWSER_ANDROID_GESTURE_EVENT_TYPE_H_
+#define CONTENT_BROWSER_ANDROID_GESTURE_EVENT_TYPE_H_
namespace content {
@@ -36,5 +36,5 @@ enum GestureEventType {
} // namespace content
-#endif // CONTENT_BROWSER_ANDROID_GESTURE_EVENT_TYPE_
+#endif // CONTENT_BROWSER_ANDROID_GESTURE_EVENT_TYPE_H_
diff --git a/chromium/content/browser/android/in_process/DEPS b/chromium/content/browser/android/in_process/DEPS
index a8ba3f4cb57..6954b5f4b1f 100644
--- a/chromium/content/browser/android/in_process/DEPS
+++ b/chromium/content/browser/android/in_process/DEPS
@@ -1,4 +1,5 @@
include_rules = [
+ "+cc/blink",
# Required for SynchronousCompositor (in --single-process mode only).
"+content/public/renderer/android",
"+content/renderer",
diff --git a/chromium/content/browser/android/in_process/OWNERS b/chromium/content/browser/android/in_process/OWNERS
new file mode 100644
index 00000000000..57a0c64f500
--- /dev/null
+++ b/chromium/content/browser/android/in_process/OWNERS
@@ -0,0 +1 @@
+boliu@chromium.org
diff --git a/chromium/content/browser/android/in_process/context_provider_in_process.cc b/chromium/content/browser/android/in_process/context_provider_in_process.cc
new file mode 100644
index 00000000000..3f0f341f299
--- /dev/null
+++ b/chromium/content/browser/android/in_process/context_provider_in_process.cc
@@ -0,0 +1,235 @@
+// 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/android/in_process/context_provider_in_process.h"
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/strings/stringprintf.h"
+#include "cc/output/managed_memory_policy.h"
+#include "content/common/gpu/client/grcontext_for_webgraphicscontext3d.h"
+#include "gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.h"
+#include "gpu/command_buffer/client/gles2_implementation.h"
+#include "third_party/skia/include/gpu/GrContext.h"
+
+using gpu_blink::WebGraphicsContext3DInProcessCommandBufferImpl;
+
+namespace content {
+
+class ContextProviderInProcess::LostContextCallbackProxy
+ : public blink::WebGraphicsContext3D::WebGraphicsContextLostCallback {
+ public:
+ explicit LostContextCallbackProxy(ContextProviderInProcess* provider)
+ : provider_(provider) {
+ provider_->context3d_->setContextLostCallback(this);
+ }
+
+ virtual ~LostContextCallbackProxy() {
+ provider_->context3d_->setContextLostCallback(NULL);
+ }
+
+ virtual void onContextLost() {
+ provider_->OnLostContext();
+ }
+
+ private:
+ ContextProviderInProcess* provider_;
+};
+
+// static
+scoped_refptr<ContextProviderInProcess> ContextProviderInProcess::Create(
+ scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> context3d,
+ const std::string& debug_name) {
+ if (!context3d)
+ return NULL;
+ return new ContextProviderInProcess(context3d.Pass(), debug_name);
+}
+
+// static
+scoped_refptr<ContextProviderInProcess>
+ContextProviderInProcess::CreateOffscreen(
+ bool lose_context_when_out_of_memory) {
+ blink::WebGraphicsContext3D::Attributes attributes;
+ attributes.depth = false;
+ attributes.stencil = true;
+ attributes.antialias = false;
+ attributes.shareResources = true;
+ attributes.noAutomaticFlushes = true;
+
+ return Create(
+ WebGraphicsContext3DInProcessCommandBufferImpl::CreateOffscreenContext(
+ attributes, lose_context_when_out_of_memory),
+ "Offscreen");
+}
+
+ContextProviderInProcess::ContextProviderInProcess(
+ scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> context3d,
+ const std::string& debug_name)
+ : context3d_(context3d.Pass()),
+ destroyed_(false),
+ debug_name_(debug_name) {
+ DCHECK(main_thread_checker_.CalledOnValidThread());
+ DCHECK(context3d_);
+ context_thread_checker_.DetachFromThread();
+}
+
+ContextProviderInProcess::~ContextProviderInProcess() {
+ DCHECK(main_thread_checker_.CalledOnValidThread() ||
+ context_thread_checker_.CalledOnValidThread());
+}
+
+blink::WebGraphicsContext3D* ContextProviderInProcess::WebContext3D() {
+ DCHECK(lost_context_callback_proxy_); // Is bound to thread.
+ DCHECK(context_thread_checker_.CalledOnValidThread());
+
+ return context3d_.get();
+}
+
+bool ContextProviderInProcess::BindToCurrentThread() {
+ DCHECK(context3d_);
+
+ // This is called on the thread the context will be used.
+ DCHECK(context_thread_checker_.CalledOnValidThread());
+
+ if (lost_context_callback_proxy_)
+ return true;
+
+ if (!context3d_->InitializeOnCurrentThread())
+ return false;
+
+ InitializeCapabilities();
+
+ std::string unique_context_name =
+ base::StringPrintf("%s-%p", debug_name_.c_str(), context3d_.get());
+ context3d_->traceBeginCHROMIUM("gpu_toplevel",
+ unique_context_name.c_str());
+
+ lost_context_callback_proxy_.reset(new LostContextCallbackProxy(this));
+ return true;
+}
+
+void ContextProviderInProcess::DetachFromThread() {
+ context_thread_checker_.DetachFromThread();
+}
+
+void ContextProviderInProcess::InitializeCapabilities() {
+ capabilities_.gpu = context3d_->GetImplementation()->capabilities();
+
+ size_t mapped_memory_limit = context3d_->GetMappedMemoryLimit();
+ capabilities_.max_transfer_buffer_usage_bytes =
+ mapped_memory_limit ==
+ WebGraphicsContext3DInProcessCommandBufferImpl::kNoLimit
+ ? std::numeric_limits<size_t>::max()
+ : mapped_memory_limit;
+}
+
+cc::ContextProvider::Capabilities
+ContextProviderInProcess::ContextCapabilities() {
+ DCHECK(lost_context_callback_proxy_); // Is bound to thread.
+ DCHECK(context_thread_checker_.CalledOnValidThread());
+ return capabilities_;
+}
+
+::gpu::gles2::GLES2Interface* ContextProviderInProcess::ContextGL() {
+ DCHECK(context3d_);
+ DCHECK(lost_context_callback_proxy_); // Is bound to thread.
+ DCHECK(context_thread_checker_.CalledOnValidThread());
+
+ return context3d_->GetGLInterface();
+}
+
+::gpu::ContextSupport* ContextProviderInProcess::ContextSupport() {
+ DCHECK(context3d_);
+ if (!lost_context_callback_proxy_)
+ return NULL; // Not bound to anything.
+
+ DCHECK(context_thread_checker_.CalledOnValidThread());
+
+ return context3d_->GetContextSupport();
+}
+
+class GrContext* ContextProviderInProcess::GrContext() {
+ DCHECK(lost_context_callback_proxy_); // Is bound to thread.
+ DCHECK(context_thread_checker_.CalledOnValidThread());
+
+ if (gr_context_)
+ return gr_context_->get();
+
+ gr_context_.reset(new GrContextForWebGraphicsContext3D(context3d_.get()));
+ return gr_context_->get();
+}
+
+void ContextProviderInProcess::InvalidateGrContext(uint32_t state) {
+ DCHECK(lost_context_callback_proxy_); // Is bound to thread.
+ DCHECK(context_thread_checker_.CalledOnValidThread());
+
+ if (gr_context_)
+ return gr_context_->get()->resetContext(state);
+}
+
+void ContextProviderInProcess::SetupLock() {
+ context3d_->SetLock(&context_lock_);
+}
+
+base::Lock* ContextProviderInProcess::GetLock() {
+ return &context_lock_;
+}
+
+bool ContextProviderInProcess::IsContextLost() {
+ DCHECK(lost_context_callback_proxy_); // Is bound to thread.
+ DCHECK(context_thread_checker_.CalledOnValidThread());
+
+ return context3d_->isContextLost();
+}
+
+void ContextProviderInProcess::VerifyContexts() {
+ DCHECK(lost_context_callback_proxy_); // Is bound to thread.
+ DCHECK(context_thread_checker_.CalledOnValidThread());
+
+ if (context3d_->isContextLost())
+ OnLostContext();
+}
+
+void ContextProviderInProcess::DeleteCachedResources() {
+ DCHECK(context_thread_checker_.CalledOnValidThread());
+
+ if (gr_context_)
+ gr_context_->FreeGpuResources();
+}
+
+void ContextProviderInProcess::OnLostContext() {
+ DCHECK(context_thread_checker_.CalledOnValidThread());
+ {
+ base::AutoLock lock(destroyed_lock_);
+ if (destroyed_)
+ return;
+ destroyed_ = true;
+ }
+ if (!lost_context_callback_.is_null())
+ base::ResetAndReturn(&lost_context_callback_).Run();
+ if (gr_context_)
+ gr_context_->OnLostContext();
+}
+
+bool ContextProviderInProcess::DestroyedOnMainThread() {
+ DCHECK(main_thread_checker_.CalledOnValidThread());
+
+ base::AutoLock lock(destroyed_lock_);
+ return destroyed_;
+}
+
+void ContextProviderInProcess::SetLostContextCallback(
+ const LostContextCallback& lost_context_callback) {
+ DCHECK(context_thread_checker_.CalledOnValidThread());
+ DCHECK(lost_context_callback_.is_null() ||
+ lost_context_callback.is_null());
+ lost_context_callback_ = lost_context_callback;
+}
+
+void ContextProviderInProcess::SetMemoryPolicyChangedCallback(
+ const MemoryPolicyChangedCallback& memory_policy_changed_callback) {
+ // There's no memory manager for the in-process implementation.
+}
+
+} // namespace content
diff --git a/chromium/content/browser/android/in_process/context_provider_in_process.h b/chromium/content/browser/android/in_process/context_provider_in_process.h
new file mode 100644
index 00000000000..946184a4eec
--- /dev/null
+++ b/chromium/content/browser/android/in_process/context_provider_in_process.h
@@ -0,0 +1,95 @@
+// 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_ANDROID_IN_PROCESS_CONTEXT_PROVIDER_IN_PROCESS_H_
+#define CONTENT_BROWSER_ANDROID_IN_PROCESS_CONTEXT_PROVIDER_IN_PROCESS_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread_checker.h"
+#include "cc/blink/context_provider_web_context.h"
+
+namespace blink { class WebGraphicsContext3D; }
+
+namespace gpu_blink {
+class WebGraphicsContext3DInProcessCommandBufferImpl;
+}
+
+namespace content {
+
+class GrContextForWebGraphicsContext3D;
+
+class ContextProviderInProcess
+ : NON_EXPORTED_BASE(public cc_blink::ContextProviderWebContext) {
+ public:
+ static scoped_refptr<ContextProviderInProcess> Create(
+ scoped_ptr<gpu_blink::WebGraphicsContext3DInProcessCommandBufferImpl>
+ context3d,
+ const std::string& debug_name);
+
+ // Uses default attributes for creating an offscreen context.
+ static scoped_refptr<ContextProviderInProcess> CreateOffscreen(
+ bool lose_context_when_out_of_memory);
+
+ private:
+ ContextProviderInProcess(
+ scoped_ptr<gpu_blink::WebGraphicsContext3DInProcessCommandBufferImpl>
+ context3d,
+ const std::string& debug_name);
+ ~ContextProviderInProcess() override;
+
+ // cc_blink::ContextProviderWebContext:
+ blink::WebGraphicsContext3D* WebContext3D() override;
+
+ // cc::ContextProvider:
+ bool BindToCurrentThread() override;
+ void DetachFromThread() override;
+ Capabilities ContextCapabilities() override;
+ ::gpu::gles2::GLES2Interface* ContextGL() override;
+ ::gpu::ContextSupport* ContextSupport() override;
+ class GrContext* GrContext() override;
+ void InvalidateGrContext(uint32_t state) override;
+ void SetupLock() override;
+ base::Lock* GetLock() override;
+ bool IsContextLost() override;
+ void VerifyContexts() override;
+ void DeleteCachedResources() override;
+ bool DestroyedOnMainThread() override;
+ void SetLostContextCallback(
+ const LostContextCallback& lost_context_callback) override;
+ void SetMemoryPolicyChangedCallback(
+ const MemoryPolicyChangedCallback& memory_policy_changed_callback)
+ override;
+
+ void OnLostContext();
+ void InitializeCapabilities();
+
+ base::ThreadChecker main_thread_checker_;
+ base::ThreadChecker context_thread_checker_;
+
+ scoped_ptr<gpu_blink::WebGraphicsContext3DInProcessCommandBufferImpl>
+ context3d_;
+ scoped_ptr<GrContextForWebGraphicsContext3D> gr_context_;
+
+ LostContextCallback lost_context_callback_;
+
+ base::Lock destroyed_lock_;
+ bool destroyed_;
+
+ base::Lock context_lock_;
+ std::string debug_name_;
+ class LostContextCallbackProxy;
+ scoped_ptr<LostContextCallbackProxy> lost_context_callback_proxy_;
+
+ cc::ContextProvider::Capabilities capabilities_;
+
+ DISALLOW_COPY_AND_ASSIGN(ContextProviderInProcess);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_ANDROID_IN_PROCESS_CONTEXT_PROVIDER_IN_PROCESS_H_
diff --git a/chromium/content/browser/android/in_process/synchronous_compositor_external_begin_frame_source.cc b/chromium/content/browser/android/in_process/synchronous_compositor_external_begin_frame_source.cc
new file mode 100644
index 00000000000..f1105f756ce
--- /dev/null
+++ b/chromium/content/browser/android/in_process/synchronous_compositor_external_begin_frame_source.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/android/in_process/synchronous_compositor_external_begin_frame_source.h"
+
+#include "cc/output/begin_frame_args.h"
+#include "content/browser/android/in_process/synchronous_compositor_impl.h"
+#include "content/browser/android/in_process/synchronous_compositor_registry.h"
+#include "content/public/browser/browser_thread.h"
+#include "ui/gfx/frame_time.h"
+
+namespace content {
+
+SynchronousCompositorExternalBeginFrameSource::
+ SynchronousCompositorExternalBeginFrameSource(int routing_id)
+ : routing_id_(routing_id),
+ registered_(false),
+ compositor_(nullptr) {
+}
+
+SynchronousCompositorExternalBeginFrameSource::
+ ~SynchronousCompositorExternalBeginFrameSource() {
+ DCHECK(CalledOnValidThread());
+
+ if (registered_) {
+ SynchronousCompositorRegistry::GetInstance()->UnregisterBeginFrameSource(
+ routing_id_, this);
+ }
+ DCHECK(!compositor_);
+}
+
+void SynchronousCompositorExternalBeginFrameSource::BeginFrame(
+ const cc::BeginFrameArgs& args) {
+ DCHECK(CalledOnValidThread());
+ CallOnBeginFrame(args);
+}
+
+void SynchronousCompositorExternalBeginFrameSource::SetCompositor(
+ SynchronousCompositorImpl* compositor) {
+ DCHECK(CalledOnValidThread());
+ compositor_ = compositor;
+}
+
+void SynchronousCompositorExternalBeginFrameSource::OnNeedsBeginFramesChange(
+ bool needs_begin_frames) {
+ DCHECK(CalledOnValidThread());
+ if (compositor_)
+ compositor_->OnNeedsBeginFramesChange(needs_begin_frames);
+}
+
+void SynchronousCompositorExternalBeginFrameSource::SetClientReady() {
+ DCHECK(CalledOnValidThread());
+ SynchronousCompositorRegistry::GetInstance()->RegisterBeginFrameSource(
+ routing_id_, this);
+ registered_ = true;
+}
+
+// Not using base::NonThreadSafe as we want to enforce a more exacting threading
+// requirement: SynchronousCompositorExternalBeginFrameSource() must only be
+// used on the UI thread.
+bool
+SynchronousCompositorExternalBeginFrameSource::CalledOnValidThread() const {
+ return BrowserThread::CurrentlyOn(BrowserThread::UI);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/android/in_process/synchronous_compositor_external_begin_frame_source.h b/chromium/content/browser/android/in_process/synchronous_compositor_external_begin_frame_source.h
new file mode 100644
index 00000000000..ee82f70a27c
--- /dev/null
+++ b/chromium/content/browser/android/in_process/synchronous_compositor_external_begin_frame_source.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_ANDROID_IN_PROCESS_SYNCHRONOUS_COMPOSITOR_EXTERNAL_BEGIN_FRAME_SOURCE_H_
+#define CONTENT_BROWSER_ANDROID_IN_PROCESS_SYNCHRONOUS_COMPOSITOR_EXTERNAL_BEGIN_FRAME_SOURCE_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "cc/scheduler/begin_frame_source.h"
+
+namespace content {
+class SynchronousCompositorImpl;
+
+// Make sure that this is initialized and set to compositor before output
+// surface is bound to compositor.
+class SynchronousCompositorExternalBeginFrameSource
+ : public cc::BeginFrameSourceMixIn {
+ public:
+ explicit SynchronousCompositorExternalBeginFrameSource(int routing_id);
+ ~SynchronousCompositorExternalBeginFrameSource() override;
+
+ void BeginFrame(const cc::BeginFrameArgs& args);
+ void SetCompositor(SynchronousCompositorImpl* compositor);
+
+ // cc::BeginFrameSourceMixIn implementation.
+ void OnNeedsBeginFramesChange(bool needs_begin_frames) override;
+ void SetClientReady() override;
+
+ private:
+ bool CalledOnValidThread() const;
+
+ const int routing_id_;
+ bool registered_;
+
+ // Not owned. This can be null when compositor is gone first than BFS.
+ SynchronousCompositorImpl* compositor_;
+
+ DISALLOW_COPY_AND_ASSIGN(SynchronousCompositorExternalBeginFrameSource);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_ANDROID_IN_PROCESS_SYNCHRONOUS_COMPOSITOR_EXTERNAL_BEGIN_FRAME_SOURCE_H_
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 2bde4a45856..f6ff81f294d 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,24 +4,36 @@
#include "content/browser/android/in_process/synchronous_compositor_factory_impl.h"
+#include "base/command_line.h"
#include "base/observer_list.h"
+#include "base/sys_info.h"
+#include "content/browser/android/in_process/context_provider_in_process.h"
+#include "content/browser/android/in_process/synchronous_compositor_external_begin_frame_source.h"
+#include "content/browser/android/in_process/synchronous_compositor_impl.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/blink/webgraphicscontext3d_in_process_command_buffer_impl.h"
#include "gpu/command_buffer/client/gl_in_process_context.h"
#include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "gpu/command_buffer/service/gpu_switches.h"
#include "ui/gl/android/surface_texture.h"
#include "ui/gl/gl_surface.h"
#include "ui/gl/gl_surface_stub.h"
-#include "webkit/common/gpu/context_provider_in_process.h"
-#include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"
-using webkit::gpu::ContextProviderWebContext;
+using cc_blink::ContextProviderWebContext;
+using gpu_blink::WebGraphicsContext3DImpl;
+using gpu_blink::WebGraphicsContext3DInProcessCommandBufferImpl;
namespace content {
namespace {
+struct ContextHolder {
+ scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> command_buffer;
+ gpu::GLInProcessContext* gl_in_process_context;
+};
+
blink::WebGraphicsContext3D::Attributes GetDefaultAttribs() {
blink::WebGraphicsContext3D::Attributes attributes;
attributes.antialias = false;
@@ -33,79 +45,39 @@ blink::WebGraphicsContext3D::Attributes GetDefaultAttribs() {
return attributes;
}
-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::gles2::ContextCreationAttribHelper in_process_attribs;
- WebGraphicsContext3DImpl::ConvertAttributes(
- attributes, &in_process_attribs);
- 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(
+ContextHolder CreateContextHolder(
+ const blink::WebGraphicsContext3D::Attributes& attributes,
scoped_refptr<gpu::InProcessCommandBuffer::Service> service,
- const gpu::GLInProcessContextSharedMemoryLimits& mem_limits) {
- const gfx::GpuPreference gpu_preference = gfx::PreferDiscreteGpu;
+ const gpu::GLInProcessContextSharedMemoryLimits& mem_limits,
+ bool is_offscreen) {
gpu::gles2::ContextCreationAttribHelper in_process_attribs;
- WebGraphicsContext3DImpl::ConvertAttributes(
- GetDefaultAttribs(), &in_process_attribs);
+ WebGraphicsContext3DImpl::ConvertAttributes(attributes, &in_process_attribs);
in_process_attribs.lose_context_when_out_of_memory = true;
scoped_ptr<gpu::GLInProcessContext> context(gpu::GLInProcessContext::Create(
service,
NULL /* surface */,
- false /* is_offscreen */,
+ is_offscreen,
gfx::kNullAcceleratedWidget,
gfx::Size(1, 1),
NULL /* share_context */,
- false /* share_resources */,
+ attributes.shareResources,
in_process_attribs,
- gpu_preference,
+ gfx::PreferDiscreteGpu,
mem_limits,
nullptr,
nullptr));
- return context.Pass();
-}
-
-scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> WrapContext(
- scoped_ptr<gpu::GLInProcessContext> context) {
- if (!context.get())
- return scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>();
- return scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>(
- WebGraphicsContext3DInProcessCommandBufferImpl::WrapContext(
- context.Pass(), GetDefaultAttribs()));
-}
+ gpu::GLInProcessContext* context_ptr = context.get();
-scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>
-WrapContextWithAttributes(
- scoped_ptr<gpu::GLInProcessContext> context,
- const blink::WebGraphicsContext3D::Attributes& attributes) {
- if (!context.get())
- return scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>();
+ ContextHolder holder;
+ holder.command_buffer =
+ scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>(
+ WebGraphicsContext3DInProcessCommandBufferImpl::WrapContext(
+ context.Pass(), attributes));
+ holder.gl_in_process_context = context_ptr;
- return scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>(
- WebGraphicsContext3DInProcessCommandBufferImpl::WrapContext(
- context.Pass(), attributes));
+ return holder;
}
} // namespace
@@ -114,30 +86,27 @@ class SynchronousCompositorFactoryImpl::VideoContextProvider
: public StreamTextureFactorySynchronousImpl::ContextProvider {
public:
VideoContextProvider(
- scoped_ptr<gpu::GLInProcessContext> gl_in_process_context)
- : gl_in_process_context_(gl_in_process_context.get()) {
-
- context_provider_ = webkit::gpu::ContextProviderInProcess::Create(
- WrapContext(gl_in_process_context.Pass()),
- "Video-Offscreen-main-thread");
+ scoped_refptr<cc::ContextProvider> context_provider,
+ gpu::GLInProcessContext* gl_in_process_context)
+ : context_provider_(context_provider),
+ gl_in_process_context_(gl_in_process_context) {
context_provider_->BindToCurrentThread();
}
- virtual scoped_refptr<gfx::SurfaceTexture> GetSurfaceTexture(
+ scoped_refptr<gfx::SurfaceTexture> GetSurfaceTexture(
uint32 stream_id) override {
return gl_in_process_context_->GetSurfaceTexture(stream_id);
}
- virtual gpu::gles2::GLES2Interface* ContextGL() override {
+ gpu::gles2::GLES2Interface* ContextGL() override {
return context_provider_->ContextGL();
}
- virtual void AddObserver(StreamTextureFactoryContextObserver* obs) override {
+ void AddObserver(StreamTextureFactoryContextObserver* obs) override {
observer_list_.AddObserver(obs);
}
- virtual void RemoveObserver(
- StreamTextureFactoryContextObserver* obs) override {
+ void RemoveObserver(StreamTextureFactoryContextObserver* obs) override {
observer_list_.RemoveObserver(obs);
}
@@ -149,7 +118,7 @@ class SynchronousCompositorFactoryImpl::VideoContextProvider
private:
friend class base::RefCountedThreadSafe<VideoContextProvider>;
- virtual ~VideoContextProvider() {}
+ ~VideoContextProvider() override {}
scoped_refptr<cc::ContextProvider> context_provider_;
gpu::GLInProcessContext* gl_in_process_context_;
@@ -158,7 +127,6 @@ class SynchronousCompositorFactoryImpl::VideoContextProvider
DISALLOW_COPY_AND_ASSIGN(VideoContextProvider);
};
-using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;
SynchronousCompositorFactoryImpl::SynchronousCompositorFactoryImpl()
: record_full_layer_(true),
@@ -182,10 +150,13 @@ scoped_ptr<cc::OutputSurface>
SynchronousCompositorFactoryImpl::CreateOutputSurface(
int routing_id,
scoped_refptr<content::FrameSwapMessageQueue> frame_swap_message_queue) {
- scoped_ptr<SynchronousCompositorOutputSurface> output_surface(
- new SynchronousCompositorOutputSurface(routing_id,
- frame_swap_message_queue));
- return output_surface.Pass();
+ scoped_refptr<cc::ContextProvider> onscreen_context =
+ CreateContextProviderForCompositor();
+ scoped_refptr<cc::ContextProvider> worker_context =
+ CreateContextProviderForCompositor();
+
+ return make_scoped_ptr(new SynchronousCompositorOutputSurface(
+ onscreen_context, worker_context, routing_id, frame_swap_message_queue));
}
InputHandlerManagerClient*
@@ -193,27 +164,39 @@ SynchronousCompositorFactoryImpl::GetInputHandlerManagerClient() {
return synchronous_input_event_filter();
}
+scoped_ptr<cc::BeginFrameSource>
+SynchronousCompositorFactoryImpl::CreateExternalBeginFrameSource(
+ int routing_id) {
+ return make_scoped_ptr(
+ new SynchronousCompositorExternalBeginFrameSource(routing_id));
+}
+
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);
+ ContextHolder holder = CreateContextHolder(
+ attributes, nullptr, gpu::GLInProcessContextSharedMemoryLimits(), true);
+ return ContextProviderInProcess::Create(holder.command_buffer.Pass(),
+ debug_name);
}
-scoped_refptr<cc::ContextProvider> SynchronousCompositorFactoryImpl::
- CreateOnscreenContextProviderForCompositorThread() {
- DCHECK(service_.get());
-
+scoped_refptr<cc::ContextProvider>
+SynchronousCompositorFactoryImpl::CreateContextProviderForCompositor() {
+ blink::WebGraphicsContext3D::Attributes attributes = GetDefaultAttribs();
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_, mem_limits)),
- "Child-Compositor");
+ if (base::SysInfo::IsLowEndDevice()) {
+ // But twice of half here because 16bit texture is not supported.
+ mem_limits.mapped_memory_reclaim_limit = 2 * 1024 * 1024;
+ } else {
+ mem_limits.mapped_memory_reclaim_limit = 6 * 1024 * 1024;
+ }
+ ContextHolder holder =
+ CreateContextHolder(attributes, nullptr, mem_limits, true);
+ return ContextProviderInProcess::Create(holder.command_buffer.Pass(),
+ "Child-Compositor");
}
scoped_refptr<StreamTextureFactory>
@@ -227,11 +210,13 @@ SynchronousCompositorFactoryImpl::CreateStreamTextureFactory(int frame_id) {
return factory;
}
-webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl*
+WebGraphicsContext3DInProcessCommandBufferImpl*
SynchronousCompositorFactoryImpl::CreateOffscreenGraphicsContext3D(
const blink::WebGraphicsContext3D::Attributes& attributes) {
- return WrapContextWithAttributes(CreateOffscreenContext(attributes),
- attributes).release();
+ ContextHolder holder = CreateContextHolder(
+ attributes, nullptr,
+ gpu::GLInProcessContextSharedMemoryLimits(), true);
+ return holder.command_buffer.release();
}
void SynchronousCompositorFactoryImpl::CompositorInitializedHardwareDraw() {
@@ -281,9 +266,17 @@ SynchronousCompositorFactoryImpl::TryCreateStreamTextureFactory() {
if (!video_context_provider_.get()) {
DCHECK(service_.get());
+ blink::WebGraphicsContext3D::Attributes attributes = GetDefaultAttribs();
+ attributes.shareResources = false;
+ // This needs to run in on-screen |service_| context due to SurfaceTexture
+ // limitations.
+ ContextHolder holder =
+ CreateContextHolder(attributes, service_,
+ gpu::GLInProcessContextSharedMemoryLimits(), false);
video_context_provider_ = new VideoContextProvider(
- CreateContext(service_,
- gpu::GLInProcessContextSharedMemoryLimits()));
+ ContextProviderInProcess::Create(holder.command_buffer.Pass(),
+ "Video-Offscreen-main-thread"),
+ holder.gl_in_process_context);
}
return video_context_provider_;
}
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 dd7467a5849..81a49301d21 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
@@ -6,47 +6,46 @@
#define CONTENT_BROWSER_ANDROID_IN_PROCESS_SYNCHRONOUS_COMPOSITOR_FACTORY_IMPL_H_
#include "base/synchronization/lock.h"
+#include "cc/blink/context_provider_web_context.h"
#include "content/browser/android/in_process/synchronous_input_event_filter.h"
#include "content/renderer/android/synchronous_compositor_factory.h"
#include "content/renderer/media/android/stream_texture_factory_synchronous_impl.h"
#include "gpu/command_buffer/service/in_process_command_buffer.h"
-#include "webkit/common/gpu/context_provider_web_context.h"
namespace gpu {
class GLInProcessContext;
}
-namespace webkit {
-namespace gpu {
+namespace gpu_blink {
class WebGraphicsContext3DInProcessCommandBufferImpl;
}
-}
namespace content {
class SynchronousCompositorFactoryImpl : public SynchronousCompositorFactory {
public:
SynchronousCompositorFactoryImpl();
- virtual ~SynchronousCompositorFactoryImpl();
+ ~SynchronousCompositorFactoryImpl() override;
// SynchronousCompositorFactory
- virtual scoped_refptr<base::MessageLoopProxy> GetCompositorMessageLoop()
- override;
- virtual bool RecordFullLayer() override;
- virtual scoped_ptr<cc::OutputSurface> CreateOutputSurface(
+ scoped_refptr<base::MessageLoopProxy> GetCompositorMessageLoop() override;
+ bool RecordFullLayer() override;
+ 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>
- CreateOffscreenContextProvider(
- const blink::WebGraphicsContext3D::Attributes& attributes,
- const std::string& debug_name) override;
- virtual scoped_refptr<StreamTextureFactory> CreateStreamTextureFactory(
+ InputHandlerManagerClient* GetInputHandlerManagerClient() override;
+ scoped_ptr<cc::BeginFrameSource> CreateExternalBeginFrameSource(
+ int routing_id) override;
+ scoped_refptr<cc_blink::ContextProviderWebContext>
+ CreateOffscreenContextProvider(
+ const blink::WebGraphicsContext3D::Attributes& attributes,
+ const std::string& debug_name) override;
+ scoped_refptr<StreamTextureFactory> CreateStreamTextureFactory(
int view_id) override;
- virtual webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl*
- CreateOffscreenGraphicsContext3D(
- const blink::WebGraphicsContext3D::Attributes& attributes) override;
+ gpu_blink::WebGraphicsContext3DInProcessCommandBufferImpl*
+ CreateOffscreenGraphicsContext3D(
+ const blink::WebGraphicsContext3D::Attributes& attributes) override;
SynchronousInputEventFilter* synchronous_input_event_filter() {
return &synchronous_input_event_filter_;
@@ -58,8 +57,7 @@ class SynchronousCompositorFactoryImpl : public SynchronousCompositorFactory {
void CompositorInitializedHardwareDraw();
void CompositorReleasedHardwareDraw();
- scoped_refptr<cc::ContextProvider>
- CreateOnscreenContextProviderForCompositorThread();
+ scoped_refptr<cc::ContextProvider> CreateContextProviderForCompositor();
private:
bool CanCreateMainThreadContext();
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 06be5be5696..d3c6b830b70 100644
--- a/chromium/content/browser/android/in_process/synchronous_compositor_impl.cc
+++ b/chromium/content/browser/android/in_process/synchronous_compositor_impl.cc
@@ -4,13 +4,18 @@
#include "content/browser/android/in_process/synchronous_compositor_impl.h"
+#include "base/auto_reset.h"
+#include "base/bind.h"
#include "base/lazy_instance.h"
#include "base/message_loop/message_loop.h"
#include "cc/input/input_handler.h"
+#include "content/browser/android/in_process/synchronous_compositor_external_begin_frame_source.h"
#include "content/browser/android/in_process/synchronous_compositor_factory_impl.h"
+#include "content/browser/android/in_process/synchronous_compositor_registry.h"
#include "content/browser/android/in_process/synchronous_input_event_filter.h"
#include "content/browser/renderer_host/render_widget_host_view_android.h"
#include "content/common/input/did_overscroll_params.h"
+#include "content/common/input_messages.h"
#include "content/public/browser/android/synchronous_compositor_client.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h"
@@ -65,22 +70,42 @@ SynchronousCompositorImpl* SynchronousCompositorImpl::FromRoutingID(
SynchronousCompositorImpl::SynchronousCompositorImpl(WebContents* contents)
: compositor_client_(NULL),
output_surface_(NULL),
+ begin_frame_source_(nullptr),
contents_(contents),
+ routing_id_(contents->GetRoutingID()),
input_handler_(NULL),
+ is_active_(false),
+ renderer_needs_begin_frames_(false),
weak_ptr_factory_(this) {
DCHECK(contents);
+ DCHECK_NE(routing_id_, MSG_ROUTING_NONE);
}
SynchronousCompositorImpl::~SynchronousCompositorImpl() {
- if (compositor_client_)
- compositor_client_->DidDestroyCompositor(this);
- SetInputHandler(NULL);
+ DCHECK(!output_surface_);
+ DCHECK(!begin_frame_source_);
+ DCHECK(!input_handler_);
}
void SynchronousCompositorImpl::SetClient(
SynchronousCompositorClient* compositor_client) {
DCHECK(CalledOnValidThread());
+ DCHECK_IMPLIES(compositor_client, !compositor_client_);
+ DCHECK_IMPLIES(!compositor_client, compositor_client_);
+
+ if (!compositor_client) {
+ SynchronousCompositorRegistry::GetInstance()->UnregisterCompositor(
+ routing_id_, this);
+ }
+
compositor_client_ = compositor_client;
+
+ // SetClient is essentially the constructor and destructor of
+ // SynchronousCompositorImpl.
+ if (compositor_client_) {
+ SynchronousCompositorRegistry::GetInstance()->RegisterCompositor(
+ routing_id_, this);
+ }
}
// static
@@ -94,25 +119,45 @@ void SynchronousCompositor::SetRecordFullDocument(bool record_full_document) {
g_factory.Get().SetRecordFullDocument(record_full_document);
}
-bool SynchronousCompositorImpl::InitializeHwDraw() {
- DCHECK(CalledOnValidThread());
- DCHECK(output_surface_);
+void SynchronousCompositorImpl::DidInitializeRendererObjects(
+ SynchronousCompositorOutputSurface* output_surface,
+ SynchronousCompositorExternalBeginFrameSource* begin_frame_source,
+ cc::InputHandler* input_handler) {
+ DCHECK(!output_surface_);
+ DCHECK(!begin_frame_source_);
+ DCHECK(output_surface);
+ DCHECK(begin_frame_source);
+ DCHECK(compositor_client_);
+ DCHECK(input_handler);
- scoped_refptr<cc::ContextProvider> onscreen_context =
- g_factory.Get().CreateOnscreenContextProviderForCompositorThread();
+ output_surface_ = output_surface;
+ begin_frame_source_ = begin_frame_source;
- bool success = output_surface_->InitializeHwDraw(onscreen_context);
+ begin_frame_source_->SetCompositor(this);
+ output_surface_->SetCompositor(this);
- if (success)
- g_factory.Get().CompositorInitializedHardwareDraw();
- return success;
+ output_surface_->SetTreeActivationCallback(
+ base::Bind(&SynchronousCompositorImpl::DidActivatePendingTree,
+ weak_ptr_factory_.GetWeakPtr()));
+
+ OnNeedsBeginFramesChange(begin_frame_source_->NeedsBeginFrames());
+
+ compositor_client_->DidInitializeCompositor(this);
+
+ SetInputHandler(input_handler);
}
-void SynchronousCompositorImpl::ReleaseHwDraw() {
- DCHECK(CalledOnValidThread());
+void SynchronousCompositorImpl::DidDestroyRendererObjects() {
DCHECK(output_surface_);
- output_surface_->ReleaseHwDraw();
- g_factory.Get().CompositorReleasedHardwareDraw();
+ DCHECK(begin_frame_source_);
+ DCHECK(compositor_client_);
+
+ begin_frame_source_->SetCompositor(nullptr);
+ output_surface_->SetCompositor(nullptr);
+ SetInputHandler(nullptr);
+ compositor_client_->DidDestroyCompositor(this);
+ output_surface_ = nullptr;
+ begin_frame_source_ = nullptr;
}
scoped_ptr<cc::CompositorFrame> SynchronousCompositorImpl::DemandDrawHw(
@@ -124,6 +169,8 @@ scoped_ptr<cc::CompositorFrame> SynchronousCompositorImpl::DemandDrawHw(
const gfx::Transform& transform_for_tile_priority) {
DCHECK(CalledOnValidThread());
DCHECK(output_surface_);
+ DCHECK(compositor_client_);
+ DCHECK(begin_frame_source_);
scoped_ptr<cc::CompositorFrame> frame =
output_surface_->DemandDrawHw(surface_size,
@@ -132,6 +179,7 @@ scoped_ptr<cc::CompositorFrame> SynchronousCompositorImpl::DemandDrawHw(
clip,
viewport_rect_for_tile_priority,
transform_for_tile_priority);
+
if (frame.get())
UpdateFrameMetaData(frame->metadata);
@@ -147,10 +195,15 @@ void SynchronousCompositorImpl::ReturnResources(
bool SynchronousCompositorImpl::DemandDrawSw(SkCanvas* canvas) {
DCHECK(CalledOnValidThread());
DCHECK(output_surface_);
+ DCHECK(compositor_client_);
+ DCHECK(begin_frame_source_);
+
+ scoped_ptr<cc::CompositorFrame> frame =
+ output_surface_->DemandDrawSw(canvas);
- scoped_ptr<cc::CompositorFrame> frame = output_surface_->DemandDrawSw(canvas);
if (frame.get())
UpdateFrameMetaData(frame->metadata);
+
return !!frame.get();
}
@@ -167,7 +220,20 @@ void SynchronousCompositorImpl::SetMemoryPolicy(size_t bytes_limit) {
DCHECK(CalledOnValidThread());
DCHECK(output_surface_);
+ size_t current_bytes_limit = output_surface_->GetMemoryPolicy();
output_surface_->SetMemoryPolicy(bytes_limit);
+
+ if (bytes_limit && !current_bytes_limit) {
+ g_factory.Get().CompositorInitializedHardwareDraw();
+ } else if (!bytes_limit && current_bytes_limit) {
+ g_factory.Get().CompositorReleasedHardwareDraw();
+ }
+}
+
+void SynchronousCompositorImpl::PostInvalidate() {
+ DCHECK(CalledOnValidThread());
+ DCHECK(compositor_client_);
+ compositor_client_->PostInvalidate();
}
void SynchronousCompositorImpl::DidChangeRootLayerScrollOffset() {
@@ -175,26 +241,29 @@ void SynchronousCompositorImpl::DidChangeRootLayerScrollOffset() {
input_handler_->OnRootLayerDelegatedScrollOffsetChanged();
}
-void SynchronousCompositorImpl::DidBindOutputSurface(
- SynchronousCompositorOutputSurface* output_surface) {
- DCHECK(CalledOnValidThread());
- output_surface_ = output_surface;
- if (compositor_client_)
- compositor_client_->DidInitializeCompositor(this);
+void SynchronousCompositorImpl::SetIsActive(bool is_active) {
+ TRACE_EVENT1("cc", "SynchronousCompositorImpl::SetIsActive", "is_active",
+ is_active);
+ is_active_ = is_active;
+ UpdateNeedsBeginFrames();
}
-void SynchronousCompositorImpl::DidDestroySynchronousOutputSurface(
- SynchronousCompositorOutputSurface* output_surface) {
- DCHECK(CalledOnValidThread());
+void SynchronousCompositorImpl::OnNeedsBeginFramesChange(
+ bool needs_begin_frames) {
+ renderer_needs_begin_frames_ = needs_begin_frames;
+ UpdateNeedsBeginFrames();
+}
- // Allow for transient hand-over when two output surfaces may refer to
- // a single delegate.
- if (output_surface_ == output_surface) {
- output_surface_ = NULL;
- if (compositor_client_)
- compositor_client_->DidDestroyCompositor(this);
- compositor_client_ = NULL;
- }
+void SynchronousCompositorImpl::BeginFrame(const cc::BeginFrameArgs& args) {
+ if (begin_frame_source_)
+ begin_frame_source_->BeginFrame(args);
+}
+
+void SynchronousCompositorImpl::UpdateNeedsBeginFrames() {
+ RenderWidgetHostViewAndroid* rwhv = static_cast<RenderWidgetHostViewAndroid*>(
+ contents_->GetRenderWidgetHostView());
+ if (rwhv)
+ rwhv->OnSetNeedsBeginFrames(is_active_ && renderer_needs_begin_frames_);
}
void SynchronousCompositorImpl::SetInputHandler(
@@ -212,24 +281,18 @@ void SynchronousCompositorImpl::SetInputHandler(
void SynchronousCompositorImpl::DidOverscroll(
const DidOverscrollParams& params) {
- if (compositor_client_) {
- compositor_client_->DidOverscroll(params.accumulated_overscroll,
- params.latest_overscroll_delta,
- params.current_fling_velocity);
- }
+ DCHECK(compositor_client_);
+ compositor_client_->DidOverscroll(params.accumulated_overscroll,
+ params.latest_overscroll_delta,
+ params.current_fling_velocity);
}
void SynchronousCompositorImpl::DidStopFlinging() {
- RenderWidgetHostViewAndroid* rwhv = static_cast<RenderWidgetHostViewAndroid*>(
- contents_->GetRenderWidgetHostView());
- if (rwhv)
- rwhv->DidStopFlinging();
-}
-
-void SynchronousCompositorImpl::SetContinuousInvalidate(bool enable) {
- DCHECK(CalledOnValidThread());
- if (compositor_client_)
- compositor_client_->SetContinuousInvalidate(enable);
+ // It's important that the fling-end notification follow the same path as it
+ // takes on other platforms (using an IPC). This ensures consistent
+ // bookkeeping at all stages of the input pipeline.
+ contents_->GetRenderProcessHost()->OnMessageReceived(
+ InputHostMsg_DidStopFlinging(routing_id_));
}
InputEventAckState SynchronousCompositorImpl::HandleInputEvent(
@@ -251,26 +314,24 @@ void SynchronousCompositorImpl::DeliverMessages() {
}
void SynchronousCompositorImpl::DidActivatePendingTree() {
- if (compositor_client_)
- compositor_client_->DidUpdateContent();
+ DCHECK(compositor_client_);
+ compositor_client_->DidUpdateContent();
+ DeliverMessages();
}
gfx::ScrollOffset SynchronousCompositorImpl::GetTotalScrollOffset() {
DCHECK(CalledOnValidThread());
- if (compositor_client_) {
- // TODO(miletus): Make GetTotalRootLayerScrollOffset return
- // ScrollOffset. crbug.com/414283.
- return gfx::ScrollOffset(
- compositor_client_->GetTotalRootLayerScrollOffset());
- }
- return gfx::ScrollOffset();
+ DCHECK(compositor_client_);
+ // TODO(miletus): Make GetTotalRootLayerScrollOffset return
+ // ScrollOffset. crbug.com/414283.
+ return gfx::ScrollOffset(
+ compositor_client_->GetTotalRootLayerScrollOffset());
}
bool SynchronousCompositorImpl::IsExternalFlingActive() const {
DCHECK(CalledOnValidThread());
- if (compositor_client_)
- return compositor_client_->IsExternalFlingActive();
- return false;
+ DCHECK(compositor_client_);
+ return compositor_client_->IsExternalFlingActive();
}
void SynchronousCompositorImpl::UpdateRootLayerState(
@@ -281,8 +342,7 @@ void SynchronousCompositorImpl::UpdateRootLayerState(
float min_page_scale_factor,
float max_page_scale_factor) {
DCHECK(CalledOnValidThread());
- if (!compositor_client_)
- return;
+ DCHECK(compositor_client_);
// TODO(miletus): Pass in ScrollOffset. crbug.com/414283.
compositor_client_->UpdateRootLayerState(
@@ -309,10 +369,10 @@ void SynchronousCompositor::SetClientForWebContents(
g_factory.Get(); // Ensure it's initialized.
SynchronousCompositorImpl::CreateForWebContents(contents);
}
- if (SynchronousCompositorImpl* instance =
- SynchronousCompositorImpl::FromWebContents(contents)) {
- instance->SetClient(client);
- }
+ SynchronousCompositorImpl* instance =
+ SynchronousCompositorImpl::FromWebContents(contents);
+ DCHECK(instance);
+ instance->SetClient(client);
}
} // namespace content
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 9b92cef3781..48bdd5b48e7 100644
--- a/chromium/content/browser/android/in_process/synchronous_compositor_impl.h
+++ b/chromium/content/browser/android/in_process/synchronous_compositor_impl.h
@@ -18,6 +18,7 @@
#include "ipc/ipc_message.h"
namespace cc {
+struct BeginFrameArgs;
class InputHandler;
}
@@ -27,6 +28,7 @@ class WebInputEvent;
namespace content {
class InputHandlerManager;
+class SynchronousCompositorExternalBeginFrameSource;
struct DidOverscrollParams;
// The purpose of this class is to act as the intermediary between the various
@@ -37,7 +39,6 @@ struct DidOverscrollParams;
class SynchronousCompositorImpl
: public cc::LayerScrollOffsetDelegate,
public SynchronousCompositor,
- public SynchronousCompositorOutputSurfaceDelegate,
public WebContentsUserData<SynchronousCompositorImpl> {
public:
// When used from browser code, use both |process_id| and |routing_id|.
@@ -48,60 +49,71 @@ class SynchronousCompositorImpl
InputEventAckState HandleInputEvent(const blink::WebInputEvent& input_event);
+ // Called by SynchronousCompositorRegistry.
+ void DidInitializeRendererObjects(
+ SynchronousCompositorOutputSurface* output_surface,
+ SynchronousCompositorExternalBeginFrameSource* begin_frame_source,
+ cc::InputHandler* input_handler);
+ void DidDestroyRendererObjects();
+
+ // Called by SynchronousCompositorExternalBeginFrameSource.
+ void OnNeedsBeginFramesChange(bool needs_begin_frames);
+
+ // Called by SynchronousCompositorOutputSurface.
+ void PostInvalidate();
+
+ // Called by RenderWidgetHostViewAndroid.
+ void BeginFrame(const cc::BeginFrameArgs& args);
+
// SynchronousCompositor
- virtual void SetClient(SynchronousCompositorClient* compositor_client)
- override;
- virtual bool InitializeHwDraw() override;
- virtual void ReleaseHwDraw() override;
- virtual scoped_ptr<cc::CompositorFrame> DemandDrawHw(
+ 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) override;
- virtual bool DemandDrawSw(SkCanvas* canvas) override;
- virtual void ReturnResources(
- 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;
- virtual void DidDestroySynchronousOutputSurface(
- SynchronousCompositorOutputSurface* output_surface) override;
- virtual void SetContinuousInvalidate(bool enable) override;
- virtual void DidActivatePendingTree() override;
+ bool DemandDrawSw(SkCanvas* canvas) override;
+ void ReturnResources(const cc::CompositorFrameAck& frame_ack) override;
+ void SetMemoryPolicy(size_t bytes_limit) override;
+ void DidChangeRootLayerScrollOffset() override;
+ void SetIsActive(bool is_active) override;
// LayerScrollOffsetDelegate
- 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;
+ gfx::ScrollOffset GetTotalScrollOffset() override;
+ 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;
+ bool IsExternalFlingActive() const override;
- void SetInputHandler(cc::InputHandler* input_handler);
void DidOverscroll(const DidOverscrollParams& params);
void DidStopFlinging();
private:
- explicit SynchronousCompositorImpl(WebContents* contents);
- virtual ~SynchronousCompositorImpl();
friend class WebContentsUserData<SynchronousCompositorImpl>;
+ friend class SynchronousCompositor;
+ explicit SynchronousCompositorImpl(WebContents* contents);
+ ~SynchronousCompositorImpl() override;
+ void SetClient(SynchronousCompositorClient* compositor_client);
void UpdateFrameMetaData(const cc::CompositorFrameMetadata& frame_info);
+ void DidActivatePendingTree();
void DeliverMessages();
bool CalledOnValidThread() const;
+ void UpdateNeedsBeginFrames();
+ void SetInputHandler(cc::InputHandler* input_handler);
SynchronousCompositorClient* compositor_client_;
SynchronousCompositorOutputSurface* output_surface_;
+ SynchronousCompositorExternalBeginFrameSource* begin_frame_source_;
WebContents* contents_;
+ const int routing_id_;
cc::InputHandler* input_handler_;
+ bool is_active_;
+ bool renderer_needs_begin_frames_;
base::WeakPtrFactory<SynchronousCompositorImpl> weak_ptr_factory_;
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 1c87cc34dac..95d82804247 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
@@ -6,19 +6,21 @@
#include "base/auto_reset.h"
#include "base/logging.h"
-#include "cc/output/begin_frame_args.h"
#include "cc/output/compositor_frame.h"
#include "cc/output/context_provider.h"
#include "cc/output/output_surface_client.h"
#include "cc/output/software_output_device.h"
+#include "content/browser/android/in_process/synchronous_compositor_external_begin_frame_source.h"
#include "content/browser/android/in_process/synchronous_compositor_impl.h"
+#include "content/browser/android/in_process/synchronous_compositor_registry.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/context_support.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"
-#include "ui/gfx/rect_conversions.h"
+#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/skia_util.h"
#include "ui/gfx/transform.h"
@@ -29,13 +31,6 @@ 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);
- if (delegate)
- delegate->DidActivatePendingTree();
-}
-
} // namespace
class SynchronousCompositorOutputSurface::SoftwareDevice
@@ -44,11 +39,10 @@ class SynchronousCompositorOutputSurface::SoftwareDevice
SoftwareDevice(SynchronousCompositorOutputSurface* surface)
: surface_(surface) {
}
- virtual void Resize(const gfx::Size& pixel_size,
- float scale_factor) override {
+ void Resize(const gfx::Size& pixel_size, float scale_factor) override {
// Intentional no-op: canvas size is controlled by the embedder.
}
- virtual SkCanvas* BeginPaint(const gfx::Rect& damage_rect) override {
+ SkCanvas* BeginPaint(const gfx::Rect& damage_rect) override {
if (!surface_->current_sw_canvas_) {
NOTREACHED() << "BeginPaint with no canvas set";
return &null_canvas_;
@@ -57,11 +51,7 @@ class SynchronousCompositorOutputSurface::SoftwareDevice
<< "Mutliple calls to BeginPaint per frame";
return surface_->current_sw_canvas_;
}
- virtual void EndPaint(cc::SoftwareFrameData* frame_data) override {
- }
- virtual void CopyToPixels(const gfx::Rect& rect, void* pixels) override {
- NOTIMPLEMENTED();
- }
+ void EndPaint(cc::SoftwareFrameData* frame_data) override {}
private:
SynchronousCompositorOutputSurface* surface_;
@@ -71,34 +61,33 @@ class SynchronousCompositorOutputSurface::SoftwareDevice
};
SynchronousCompositorOutputSurface::SynchronousCompositorOutputSurface(
+ const scoped_refptr<cc::ContextProvider>& context_provider,
+ const scoped_refptr<cc::ContextProvider>& worker_context_provider,
int routing_id,
scoped_refptr<FrameSwapMessageQueue> frame_swap_message_queue)
: cc::OutputSurface(
+ context_provider,
+ worker_context_provider,
scoped_ptr<cc::SoftwareOutputDevice>(new SoftwareDevice(this))),
routing_id_(routing_id),
- needs_begin_frame_(false),
- invoking_composite_(false),
- current_sw_canvas_(NULL),
+ registered_(false),
+ current_sw_canvas_(nullptr),
memory_policy_(0),
- 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;
capabilities_.delegated_rendering = true;
capabilities_.max_frames_pending = 1;
- // Cannot call out to GetDelegate() here as the output surface is not
- // constructed on the correct thread.
-
memory_policy_.priority_cutoff_when_visible =
gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE;
}
SynchronousCompositorOutputSurface::~SynchronousCompositorOutputSurface() {
DCHECK(CalledOnValidThread());
- SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate();
- if (delegate)
- delegate->DidDestroySynchronousOutputSurface(this);
+ if (registered_) {
+ SynchronousCompositorRegistry::GetInstance()->UnregisterOutputSurface(
+ routing_id_, this);
+ }
}
bool SynchronousCompositorOutputSurface::BindToClient(
@@ -107,31 +96,26 @@ bool SynchronousCompositorOutputSurface::BindToClient(
if (!cc::OutputSurface::BindToClient(surface_client))
return false;
- output_surface_client_ = surface_client;
- output_surface_client_->SetTreeActivationCallback(
- base::Bind(&DidActivatePendingTree, routing_id_));
- output_surface_client_->SetMemoryPolicy(memory_policy_);
+ client_->SetMemoryPolicy(memory_policy_);
- SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate();
- if (delegate)
- delegate->DidBindOutputSurface(this);
+ SynchronousCompositorRegistry::GetInstance()->RegisterOutputSurface(
+ routing_id_, this);
+ registered_ = true;
return true;
}
+void SynchronousCompositorOutputSurface::SetCompositor(
+ SynchronousCompositorImpl* compositor) {
+ DCHECK(CalledOnValidThread());
+ compositor_ = compositor;
+}
+
void SynchronousCompositorOutputSurface::Reshape(
const gfx::Size& size, float scale_factor) {
// Intentional no-op: surface size is controlled by the embedder.
}
-void SynchronousCompositorOutputSurface::SetNeedsBeginFrame(bool enable) {
- DCHECK(CalledOnValidThread());
- needs_begin_frame_ = enable;
- SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate();
- if (delegate && !invoking_composite_)
- delegate->SetContinuousInvalidate(needs_begin_frame_);
-}
-
void SynchronousCompositorOutputSurface::SwapBuffers(
cc::CompositorFrame* frame) {
DCHECK(CalledOnValidThread());
@@ -142,6 +126,11 @@ void SynchronousCompositorOutputSurface::SwapBuffers(
client_->DidSwapBuffers();
}
+void SynchronousCompositorOutputSurface::Invalidate() {
+ DCHECK(CalledOnValidThread());
+ compositor_->PostInvalidate();
+}
+
namespace {
void AdjustTransform(gfx::Transform* transform, gfx::Rect viewport) {
// CC's draw origin starts at the viewport.
@@ -149,20 +138,6 @@ void AdjustTransform(gfx::Transform* transform, gfx::Rect viewport) {
}
} // namespace
-bool SynchronousCompositorOutputSurface::InitializeHwDraw(
- scoped_refptr<cc::ContextProvider> onscreen_context_provider) {
- DCHECK(CalledOnValidThread());
- DCHECK(HasClient());
- DCHECK(!context_provider_.get());
-
- return InitializeAndSetContext3d(onscreen_context_provider);
-}
-
-void SynchronousCompositorOutputSurface::ReleaseHwDraw() {
- DCHECK(CalledOnValidThread());
- cc::OutputSurface::ReleaseGL();
-}
-
scoped_ptr<cc::CompositorFrame>
SynchronousCompositorOutputSurface::DemandDrawHw(
gfx::Size surface_size,
@@ -191,6 +166,7 @@ SynchronousCompositorOutputSurface::DemandDrawSw(SkCanvas* canvas) {
DCHECK(CalledOnValidThread());
DCHECK(canvas);
DCHECK(!current_sw_canvas_);
+
base::AutoReset<SkCanvas*> canvas_resetter(&current_sw_canvas_, canvas);
SkIRect canvas_clip;
@@ -223,9 +199,7 @@ void SynchronousCompositorOutputSurface::InvokeComposite(
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);
@@ -236,7 +210,8 @@ void SynchronousCompositorOutputSurface::InvokeComposite(
transform_for_tile_priority,
!hardware_draw);
SetNeedsRedrawRect(gfx::Rect(viewport.size()));
- client_->BeginFrame(cc::BeginFrameArgs::CreateForSynchronousCompositor());
+
+ client_->OnDraw();
// After software draws (which might move the viewport arbitrarily), restore
// the previous hardware viewport to allow CC's tile manager to prioritize
@@ -260,10 +235,6 @@ void SynchronousCompositorOutputSurface::InvokeComposite(
if (frame_holder_.get())
client_->DidSwapBuffersComplete();
-
- SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate();
- if (delegate)
- delegate->SetContinuousInvalidate(needs_begin_frame_);
}
void SynchronousCompositorOutputSurface::ReturnResources(
@@ -273,11 +244,28 @@ void SynchronousCompositorOutputSurface::ReturnResources(
void SynchronousCompositorOutputSurface::SetMemoryPolicy(size_t bytes_limit) {
DCHECK(CalledOnValidThread());
+ bool became_zero = memory_policy_.bytes_limit_when_visible && !bytes_limit;
+ bool became_non_zero =
+ !memory_policy_.bytes_limit_when_visible && bytes_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_);
+ if (client_)
+ client_->SetMemoryPolicy(memory_policy_);
+
+ if (became_zero) {
+ // This is small hack to drop context resources without destroying it
+ // when this compositor is put into the background.
+ context_provider()->ContextSupport()->SetSurfaceVisible(false);
+ } else if (became_non_zero) {
+ context_provider()->ContextSupport()->SetSurfaceVisible(true);
+ }
+}
+
+void SynchronousCompositorOutputSurface::SetTreeActivationCallback(
+ const base::Closure& callback) {
+ DCHECK(client_);
+ client_->SetTreeActivationCallback(callback);
}
void SynchronousCompositorOutputSurface::GetMessagesToDeliver(
@@ -295,9 +283,4 @@ bool SynchronousCompositorOutputSurface::CalledOnValidThread() const {
return BrowserThread::CurrentlyOn(BrowserThread::UI);
}
-SynchronousCompositorOutputSurfaceDelegate*
-SynchronousCompositorOutputSurface::GetDelegate() {
- return SynchronousCompositorImpl::FromRoutingID(routing_id_);
-}
-
} // namespace content
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 d01d88b6b36..414695230c1 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
@@ -8,6 +8,7 @@
#include <vector>
#include "base/basictypes.h"
+#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
@@ -31,49 +32,37 @@ namespace content {
class FrameSwapMessageQueue;
class SynchronousCompositorClient;
+class SynchronousCompositorImpl;
class SynchronousCompositorOutputSurface;
class WebGraphicsContext3DCommandBufferImpl;
-class SynchronousCompositorOutputSurfaceDelegate {
- public:
- virtual void DidBindOutputSurface(
- SynchronousCompositorOutputSurface* output_surface) = 0;
- virtual void DidDestroySynchronousOutputSurface(
- SynchronousCompositorOutputSurface* output_surface) = 0;
- virtual void SetContinuousInvalidate(bool enable) = 0;
- virtual void DidActivatePendingTree() = 0;
-
- protected:
- SynchronousCompositorOutputSurfaceDelegate() {}
- virtual ~SynchronousCompositorOutputSurfaceDelegate() {}
-};
-
// Specialization of the output surface that adapts it to implement the
// content::SynchronousCompositor public API. This class effects an "inversion
// of control" - enabling drawing to be orchestrated by the embedding
// layer, instead of driven by the compositor internals - hence it holds two
// 'client' pointers (|client_| in the OutputSurface baseclass and
-// GetDelegate()) which represent the consumers of the two roles in plays.
+// |delegate_|) which represent the consumers of the two roles in plays.
// This class can be created only on the main thread, but then becomes pinned
// to a fixed thread when BindToClient is called.
class SynchronousCompositorOutputSurface
: NON_EXPORTED_BASE(public cc::OutputSurface) {
public:
- explicit SynchronousCompositorOutputSurface(
+ SynchronousCompositorOutputSurface(
+ const scoped_refptr<cc::ContextProvider>& context_provider,
+ const scoped_refptr<cc::ContextProvider>& worker_context_provider,
int routing_id,
scoped_refptr<FrameSwapMessageQueue> frame_swap_message_queue);
- virtual ~SynchronousCompositorOutputSurface();
+ ~SynchronousCompositorOutputSurface() override;
+
+ void SetCompositor(SynchronousCompositorImpl* compositor);
// OutputSurface.
- 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;
+ bool BindToClient(cc::OutputSurfaceClient* surface_client) override;
+ void Reshape(const gfx::Size& size, float scale_factor) override;
+ void SwapBuffers(cc::CompositorFrame* frame) override;
+ void Invalidate() 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,
@@ -84,8 +73,13 @@ class SynchronousCompositorOutputSurface
void ReturnResources(const cc::CompositorFrameAck& frame_ack);
scoped_ptr<cc::CompositorFrame> DemandDrawSw(SkCanvas* canvas);
void SetMemoryPolicy(size_t bytes_limit);
+ void SetTreeActivationCallback(const base::Closure& callback);
void GetMessagesToDeliver(ScopedVector<IPC::Message>* messages);
+ size_t GetMemoryPolicy() const {
+ return memory_policy_.bytes_limit_when_visible;
+ }
+
private:
class SoftwareDevice;
friend class SoftwareDevice;
@@ -97,11 +91,12 @@ class SynchronousCompositorOutputSurface
gfx::Transform transform_for_tile_priority,
bool hardware_draw);
bool CalledOnValidThread() const;
- SynchronousCompositorOutputSurfaceDelegate* GetDelegate();
- int routing_id_;
- bool needs_begin_frame_;
- bool invoking_composite_;
+ const int routing_id_;
+ bool registered_;
+
+ // Not owned.
+ SynchronousCompositorImpl* compositor_;
gfx::Transform cached_hw_transform_;
gfx::Rect cached_hw_viewport_;
@@ -114,7 +109,6 @@ class SynchronousCompositorOutputSurface
cc::ManagedMemoryPolicy memory_policy_;
- cc::OutputSurfaceClient* output_surface_client_;
scoped_ptr<cc::CompositorFrame> frame_holder_;
scoped_refptr<FrameSwapMessageQueue> frame_swap_message_queue_;
diff --git a/chromium/content/browser/android/in_process/synchronous_compositor_registry.cc b/chromium/content/browser/android/in_process/synchronous_compositor_registry.cc
new file mode 100644
index 00000000000..2b8bded260f
--- /dev/null
+++ b/chromium/content/browser/android/in_process/synchronous_compositor_registry.cc
@@ -0,0 +1,171 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/android/in_process/synchronous_compositor_registry.h"
+
+#include "content/browser/android/in_process/synchronous_compositor_impl.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace content {
+
+namespace {
+base::LazyInstance<SynchronousCompositorRegistry> g_compositor_registry =
+ LAZY_INSTANCE_INITIALIZER;
+}
+
+// static
+SynchronousCompositorRegistry* SynchronousCompositorRegistry::GetInstance() {
+ return g_compositor_registry.Pointer();
+}
+
+SynchronousCompositorRegistry::SynchronousCompositorRegistry() {
+ DCHECK(CalledOnValidThread());
+}
+
+SynchronousCompositorRegistry::~SynchronousCompositorRegistry() {
+ DCHECK(CalledOnValidThread());
+}
+
+void SynchronousCompositorRegistry::RegisterCompositor(
+ int routing_id,
+ SynchronousCompositorImpl* compositor) {
+ DCHECK(CalledOnValidThread());
+ DCHECK(compositor);
+ Entry& entry = entry_map_[routing_id];
+ DCHECK(!entry.compositor);
+ entry.compositor = compositor;
+ CheckIsReady(routing_id);
+}
+
+void SynchronousCompositorRegistry::UnregisterCompositor(
+ int routing_id,
+ SynchronousCompositorImpl* compositor) {
+ DCHECK(CalledOnValidThread());
+ DCHECK(compositor);
+ DCHECK(entry_map_.find(routing_id) != entry_map_.end());
+ Entry& entry = entry_map_[routing_id];
+ DCHECK_EQ(compositor, entry.compositor);
+
+ if (entry.IsReady())
+ UnregisterObjects(routing_id);
+ entry.compositor = nullptr;
+ RemoveEntryIfNeeded(routing_id);
+}
+
+void SynchronousCompositorRegistry::RegisterBeginFrameSource(
+ int routing_id,
+ SynchronousCompositorExternalBeginFrameSource* begin_frame_source) {
+ DCHECK(CalledOnValidThread());
+ DCHECK(begin_frame_source);
+ Entry& entry = entry_map_[routing_id];
+ DCHECK(!entry.begin_frame_source);
+ entry.begin_frame_source = begin_frame_source;
+ CheckIsReady(routing_id);
+}
+
+void SynchronousCompositorRegistry::UnregisterBeginFrameSource(
+ int routing_id,
+ SynchronousCompositorExternalBeginFrameSource* begin_frame_source) {
+ DCHECK(CalledOnValidThread());
+ DCHECK(begin_frame_source);
+ DCHECK(entry_map_.find(routing_id) != entry_map_.end());
+ Entry& entry = entry_map_[routing_id];
+ DCHECK_EQ(begin_frame_source, entry.begin_frame_source);
+
+ if (entry.IsReady())
+ UnregisterObjects(routing_id);
+ entry.begin_frame_source = nullptr;
+ RemoveEntryIfNeeded(routing_id);
+}
+
+void SynchronousCompositorRegistry::RegisterOutputSurface(
+ int routing_id,
+ SynchronousCompositorOutputSurface* output_surface) {
+ DCHECK(CalledOnValidThread());
+ DCHECK(output_surface);
+ Entry& entry = entry_map_[routing_id];
+ DCHECK(!entry.output_surface);
+ entry.output_surface = output_surface;
+ CheckIsReady(routing_id);
+}
+
+void SynchronousCompositorRegistry::UnregisterOutputSurface(
+ int routing_id,
+ SynchronousCompositorOutputSurface* output_surface) {
+ DCHECK(CalledOnValidThread());
+ DCHECK(output_surface);
+ DCHECK(entry_map_.find(routing_id) != entry_map_.end());
+ Entry& entry = entry_map_[routing_id];
+ DCHECK_EQ(output_surface, entry.output_surface);
+
+ if (entry.IsReady())
+ UnregisterObjects(routing_id);
+ entry.output_surface = nullptr;
+ RemoveEntryIfNeeded(routing_id);
+}
+
+void SynchronousCompositorRegistry::RegisterInputHandler(
+ int routing_id,
+ cc::InputHandler* input_handler) {
+ DCHECK(CalledOnValidThread());
+ DCHECK(input_handler);
+ Entry& entry = entry_map_[routing_id];
+ DCHECK(!entry.input_handler);
+ entry.input_handler = input_handler;
+ CheckIsReady(routing_id);
+}
+
+void SynchronousCompositorRegistry::UnregisterInputHandler(int routing_id) {
+ DCHECK(CalledOnValidThread());
+ DCHECK(entry_map_.find(routing_id) != entry_map_.end());
+ Entry& entry = entry_map_[routing_id];
+
+ if (entry.IsReady())
+ UnregisterObjects(routing_id);
+ entry.input_handler = nullptr;
+ RemoveEntryIfNeeded(routing_id);
+}
+
+void SynchronousCompositorRegistry::CheckIsReady(int routing_id) {
+ DCHECK(entry_map_.find(routing_id) != entry_map_.end());
+ Entry& entry = entry_map_[routing_id];
+ if (entry.IsReady()) {
+ entry.compositor->DidInitializeRendererObjects(entry.output_surface,
+ entry.begin_frame_source,
+ entry.input_handler);
+ }
+}
+
+void SynchronousCompositorRegistry::UnregisterObjects(int routing_id) {
+ DCHECK(entry_map_.find(routing_id) != entry_map_.end());
+ Entry& entry = entry_map_[routing_id];
+ DCHECK(entry.IsReady());
+ entry.compositor->DidDestroyRendererObjects();
+}
+
+void SynchronousCompositorRegistry::RemoveEntryIfNeeded(int routing_id) {
+ DCHECK(entry_map_.find(routing_id) != entry_map_.end());
+ Entry& entry = entry_map_[routing_id];
+ if (!entry.compositor && !entry.begin_frame_source && !entry.output_surface &&
+ !entry.input_handler) {
+ entry_map_.erase(routing_id);
+ }
+}
+
+bool SynchronousCompositorRegistry::CalledOnValidThread() const {
+ return BrowserThread::CurrentlyOn(BrowserThread::UI);
+}
+
+SynchronousCompositorRegistry::Entry::Entry()
+ : compositor(nullptr),
+ begin_frame_source(nullptr),
+ output_surface(nullptr),
+ input_handler(nullptr) {
+}
+
+bool SynchronousCompositorRegistry::Entry::IsReady() {
+ return compositor && begin_frame_source && output_surface && input_handler;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/android/in_process/synchronous_compositor_registry.h b/chromium/content/browser/android/in_process/synchronous_compositor_registry.h
new file mode 100644
index 00000000000..5dfdc7e8db8
--- /dev/null
+++ b/chromium/content/browser/android/in_process/synchronous_compositor_registry.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_ANDROID_IN_PROCESS_SYNCHRONOUS_COMPOSITOR_REGISTRY_H_
+#define CONTENT_BROWSER_ANDROID_IN_PROCESS_SYNCHRONOUS_COMPOSITOR_REGISTRY_H_
+
+#include "base/containers/hash_tables.h"
+#include "base/lazy_instance.h"
+
+namespace cc {
+class InputHandler;
+}
+
+namespace content {
+
+class SynchronousCompositorExternalBeginFrameSource;
+class SynchronousCompositorImpl;
+class SynchronousCompositorOutputSurface;
+
+class SynchronousCompositorRegistry {
+ public:
+ static SynchronousCompositorRegistry* GetInstance();
+
+ void RegisterCompositor(int routing_id,
+ SynchronousCompositorImpl* compositor);
+ void UnregisterCompositor(int routing_id,
+ SynchronousCompositorImpl* compositor);
+ void RegisterBeginFrameSource(
+ int routing_id,
+ SynchronousCompositorExternalBeginFrameSource* begin_frame_source);
+ void UnregisterBeginFrameSource(
+ int routing_id,
+ SynchronousCompositorExternalBeginFrameSource* begin_frame_source);
+ void RegisterOutputSurface(
+ int routing_id,
+ SynchronousCompositorOutputSurface* output_surface);
+ void UnregisterOutputSurface(
+ int routing_id,
+ SynchronousCompositorOutputSurface* output_surface);
+ void RegisterInputHandler(
+ int routing_id,
+ cc::InputHandler* input_handler);
+ void UnregisterInputHandler(int routing_id);
+
+ private:
+ friend struct base::DefaultLazyInstanceTraits<SynchronousCompositorRegistry>;
+ SynchronousCompositorRegistry();
+ ~SynchronousCompositorRegistry();
+
+ struct Entry {
+ SynchronousCompositorImpl* compositor;
+ SynchronousCompositorExternalBeginFrameSource* begin_frame_source;
+ SynchronousCompositorOutputSurface* output_surface;
+ cc::InputHandler* input_handler;
+
+ Entry();
+ bool IsReady();
+ };
+
+ using EntryMap = base::hash_map<int, Entry>;
+
+ void CheckIsReady(int routing_id);
+ void UnregisterObjects(int routing_id);
+ void RemoveEntryIfNeeded(int routing_id);
+ bool CalledOnValidThread() const;
+
+ EntryMap entry_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(SynchronousCompositorRegistry);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_ANDROID_IN_PROCESS_SYNCHRONOUS_COMPOSITOR_REGISTRY_H_
diff --git a/chromium/content/browser/android/in_process/synchronous_input_event_filter.cc b/chromium/content/browser/android/in_process/synchronous_input_event_filter.cc
index 2122a90f36b..3a03c0d3ce3 100644
--- a/chromium/content/browser/android/in_process/synchronous_input_event_filter.cc
+++ b/chromium/content/browser/android/in_process/synchronous_input_event_filter.cc
@@ -7,6 +7,7 @@
#include "base/callback.h"
#include "cc/input/input_handler.h"
#include "content/browser/android/in_process/synchronous_compositor_impl.h"
+#include "content/browser/android/in_process/synchronous_compositor_registry.h"
#include "content/public/browser/browser_thread.h"
#include "ui/events/latency_info.h"
@@ -41,28 +42,22 @@ void SynchronousInputEventFilter::SetBoundHandler(const Handler& handler) {
void SynchronousInputEventFilter::SetBoundHandlerOnUIThread(
const Handler& handler) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
handler_ = handler;
}
void SynchronousInputEventFilter::DidAddInputHandler(
int routing_id,
cc::InputHandler* input_handler) {
- // The SynchronusCompositorImpl can be NULL if the WebContents that it's
- // bound to has already been deleted.
- SynchronousCompositorImpl* compositor =
- SynchronousCompositorImpl::FromRoutingID(routing_id);
- if (compositor)
- compositor->SetInputHandler(input_handler);
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ SynchronousCompositorRegistry::GetInstance()->RegisterInputHandler(
+ routing_id, input_handler);
}
void SynchronousInputEventFilter::DidRemoveInputHandler(int routing_id) {
- // The SynchronusCompositorImpl can be NULL if the WebContents that it's
- // bound to has already been deleted.
- SynchronousCompositorImpl* compositor =
- SynchronousCompositorImpl::FromRoutingID(routing_id);
- if (compositor)
- compositor->SetInputHandler(NULL);
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ SynchronousCompositorRegistry::GetInstance()->UnregisterInputHandler(
+ routing_id);
}
void SynchronousInputEventFilter::DidOverscroll(
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 33200e8068e..607b9a99438 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
@@ -10,7 +10,7 @@
#include "base/compiler_specific.h"
#include "content/common/input/input_event_ack_state.h"
#include "content/renderer/input/input_handler_manager_client.h"
-#include "ui/gfx/vector2d_f.h"
+#include "ui/gfx/geometry/vector2d_f.h"
namespace blink {
class WebInputEvent;
@@ -26,19 +26,19 @@ namespace content {
class SynchronousInputEventFilter : public InputHandlerManagerClient {
public:
SynchronousInputEventFilter();
- virtual ~SynchronousInputEventFilter();
+ ~SynchronousInputEventFilter() override;
InputEventAckState HandleInputEvent(int routing_id,
const blink::WebInputEvent& input_event);
// InputHandlerManagerClient implementation.
- 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;
- virtual void DidOverscroll(int routing_id,
- const DidOverscrollParams& params) override;
- virtual void DidStopFlinging(int routing_id) override;
+ void SetBoundHandler(const Handler& handler) override;
+ void DidAddInputHandler(int routing_id,
+ cc::InputHandler* input_handler) override;
+ void DidRemoveInputHandler(int routing_id) override;
+ void DidOverscroll(int routing_id,
+ const DidOverscrollParams& params) override;
+ 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 5121be161f5..bd28d381c9d 100644
--- a/chromium/content/browser/android/interstitial_page_delegate_android.h
+++ b/chromium/content/browser/android/interstitial_page_delegate_android.h
@@ -26,7 +26,7 @@ class InterstitialPageDelegateAndroid : public InterstitialPageDelegate {
InterstitialPageDelegateAndroid(JNIEnv* env,
jobject obj,
const std::string& html_content);
- virtual ~InterstitialPageDelegateAndroid();
+ ~InterstitialPageDelegateAndroid() override;
void set_interstitial_page(InterstitialPage* page) { page_ = page; }
@@ -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;
+ std::string GetHTMLContents() override;
+ void OnProceed() override;
+ void OnDontProceed() override;
+ void CommandReceived(const std::string& command) override;
static bool RegisterInterstitialPageDelegateAndroid(JNIEnv* env);
diff --git a/chromium/content/browser/android/java/gin_java_bound_object.cc b/chromium/content/browser/android/java/gin_java_bound_object.cc
index 99c8b5d14e3..527fcef83bd 100644
--- a/chromium/content/browser/android/java/gin_java_bound_object.cc
+++ b/chromium/content/browser/android/java/gin_java_bound_object.cc
@@ -42,8 +42,8 @@ GinJavaBoundObject* GinJavaBoundObject::CreateNamed(
GinJavaBoundObject* GinJavaBoundObject::CreateTransient(
const JavaObjectWeakGlobalRef& ref,
const base::android::JavaRef<jclass>& safe_annotation_clazz,
- RenderFrameHost* holder) {
- std::set<RenderFrameHost*> holders;
+ int32 holder) {
+ std::set<int32> holders;
holders.insert(holder);
return new GinJavaBoundObject(ref, safe_annotation_clazz, holders);
}
@@ -61,7 +61,7 @@ GinJavaBoundObject::GinJavaBoundObject(
GinJavaBoundObject::GinJavaBoundObject(
const JavaObjectWeakGlobalRef& ref,
const base::android::JavaRef<jclass>& safe_annotation_clazz,
- const std::set<RenderFrameHost*> holders)
+ const std::set<int32>& holders)
: ref_(ref),
names_count_(0),
holders_(holders),
diff --git a/chromium/content/browser/android/java/gin_java_bound_object.h b/chromium/content/browser/android/java/gin_java_bound_object.h
index ce1d403e7f6..72fa7c6f8e1 100644
--- a/chromium/content/browser/android/java/gin_java_bound_object.h
+++ b/chromium/content/browser/android/java/gin_java_bound_object.h
@@ -10,26 +10,17 @@
#include "base/android/jni_weak_ref.h"
#include "base/android/scoped_java_ref.h"
-#include "base/id_map.h"
#include "base/memory/linked_ptr.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
#include "base/values.h"
#include "content/browser/android/java/java_method.h"
namespace content {
-class RenderFrameHost;
-
class GinJavaBoundObject
: public base::RefCountedThreadSafe<GinJavaBoundObject> {
public:
- // Using scoped_refptr<> as a value type is somewhat not IDMap had been
- // designed for (it returns T* from lookups, so we have to de-ref it), but on
- // the other hand, this allows us to manage lifetime of GinJavaBoundObject
- // automatically.
- typedef IDMap<scoped_refptr<GinJavaBoundObject>, IDMapOwnPointer> ObjectMap;
- typedef ObjectMap::KeyType ObjectID;
+ typedef int32 ObjectID;
static GinJavaBoundObject* CreateNamed(
const JavaObjectWeakGlobalRef& ref,
@@ -37,8 +28,9 @@ class GinJavaBoundObject
static GinJavaBoundObject* CreateTransient(
const JavaObjectWeakGlobalRef& ref,
const base::android::JavaRef<jclass>& safe_annotation_clazz,
- RenderFrameHost* holder);
+ int32 holder);
+ // The following methods can be called on any thread.
JavaObjectWeakGlobalRef& GetWeakRef() { return ref_; }
base::android::ScopedJavaLocalRef<jobject> GetLocalRef(JNIEnv* env) {
return ref_.get(env);
@@ -49,8 +41,8 @@ class GinJavaBoundObject
void RemoveName() { --names_count_; }
bool HasHolders() { return !holders_.empty(); }
- void AddHolder(RenderFrameHost* holder) { holders_.insert(holder); }
- void RemoveHolder(RenderFrameHost* holder) { holders_.erase(holder); }
+ void AddHolder(int32 holder) { holders_.insert(holder); }
+ void RemoveHolder(int32 holder) { holders_.erase(holder); }
// The following methods are called on the background thread.
std::set<std::string> GetMethodNames();
@@ -70,7 +62,7 @@ class GinJavaBoundObject
GinJavaBoundObject(
const JavaObjectWeakGlobalRef& ref,
const base::android::JavaRef<jclass>& safe_annotation_clazz,
- const std::set<RenderFrameHost*> holders);
+ const std::set<int32>& holders);
~GinJavaBoundObject();
// The following methods are called on the background thread.
@@ -81,7 +73,7 @@ class GinJavaBoundObject
// An object must be kept in retained_object_set_ either if it has
// names or if it has a non-empty holders set.
int names_count_;
- std::set<RenderFrameHost*> holders_;
+ std::set<int32> holders_;
// The following fields are accessed on the background thread.
typedef std::multimap<std::string, linked_ptr<JavaMethod> > JavaMethodMap;
diff --git a/chromium/content/browser/android/java/gin_java_bound_object_delegate.h b/chromium/content/browser/android/java/gin_java_bound_object_delegate.h
index 49ff4bbca4f..cdee8a61c6c 100644
--- a/chromium/content/browser/android/java/gin_java_bound_object_delegate.h
+++ b/chromium/content/browser/android/java/gin_java_bound_object_delegate.h
@@ -15,17 +15,15 @@ class GinJavaBoundObjectDelegate
: public GinJavaMethodInvocationHelper::ObjectDelegate {
public:
GinJavaBoundObjectDelegate(scoped_refptr<GinJavaBoundObject> object);
- virtual ~GinJavaBoundObjectDelegate();
+ ~GinJavaBoundObjectDelegate() override;
- virtual base::android::ScopedJavaLocalRef<jobject> GetLocalRef(
+ base::android::ScopedJavaLocalRef<jobject> GetLocalRef(JNIEnv* env) override;
+ base::android::ScopedJavaLocalRef<jclass> GetLocalClassRef(
JNIEnv* env) override;
- virtual base::android::ScopedJavaLocalRef<jclass> GetLocalClassRef(
- JNIEnv* env) override;
- virtual const JavaMethod* FindMethod(const std::string& method_name,
- size_t num_parameters) override;
- virtual bool IsObjectGetClassMethod(const JavaMethod* method) override;
- virtual const base::android::JavaRef<jclass>& GetSafeAnnotationClass()
- override;
+ const JavaMethod* FindMethod(const std::string& method_name,
+ size_t num_parameters) override;
+ bool IsObjectGetClassMethod(const JavaMethod* method) override;
+ const base::android::JavaRef<jclass>& GetSafeAnnotationClass() override;
private:
scoped_refptr<GinJavaBoundObject> object_;
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
index c8fb2fd9899..fc4c55ef8fa 100644
--- a/chromium/content/browser/android/java/gin_java_bridge_dispatcher_host.cc
+++ b/chromium/content/browser/android/java/gin_java_bridge_dispatcher_host.cc
@@ -7,7 +7,9 @@
#include "base/android/java_handler_thread.h"
#include "base/android/jni_android.h"
#include "base/android/scoped_java_ref.h"
+#include "base/atomic_sequence_num.h"
#include "base/lazy_instance.h"
+#include "base/pickle.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task_runner_util.h"
@@ -18,6 +20,7 @@
#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/render_process_host.h"
#include "content/public/browser/web_contents.h"
#include "ipc/ipc_message_utils.h"
@@ -35,32 +38,64 @@ class JavaBridgeThread : public base::android::JavaHandlerThread {
JavaBridgeThread() : base::android::JavaHandlerThread("JavaBridge") {
Start();
}
- virtual ~JavaBridgeThread() {
- Stop();
- }
+ ~JavaBridgeThread() override { Stop(); }
+ static bool CurrentlyOn();
};
base::LazyInstance<JavaBridgeThread> g_background_thread =
LAZY_INSTANCE_INITIALIZER;
+// static
+bool JavaBridgeThread::CurrentlyOn() {
+ return base::MessageLoop::current() ==
+ g_background_thread.Get().message_loop();
+}
+
+// Object IDs are globally unique, so we can figure out the right
+// GinJavaBridgeDispatcherHost when dispatching messages on the background
+// thread.
+base::StaticAtomicSequenceNumber g_next_object_id;
+
} // namespace
GinJavaBridgeDispatcherHost::GinJavaBridgeDispatcherHost(
WebContents* web_contents,
jobject retained_object_set)
: WebContentsObserver(web_contents),
+ BrowserMessageFilter(GinJavaBridgeMsgStart),
+ browser_filter_added_(false),
retained_object_set_(base::android::AttachCurrentThread(),
retained_object_set),
- allow_object_contents_inspection_(true) {
+ allow_object_contents_inspection_(true),
+ current_routing_id_(MSG_ROUTING_NONE) {
DCHECK(retained_object_set);
}
GinJavaBridgeDispatcherHost::~GinJavaBridgeDispatcherHost() {
- DCHECK(pending_replies_.empty());
+}
+
+// GinJavaBridgeDispatcherHost gets created earlier than RenderProcessHost
+// is initialized. So we postpone installing the message filter until we know
+// that the RPH is in a good shape. Currently this means that we are calling
+// this function from any UI thread function that is about to communicate
+// with the renderer.
+// TODO(mnaganov): Redesign, so we only have a single filter for all hosts.
+void GinJavaBridgeDispatcherHost::AddBrowserFilterIfNeeded() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ // Transient objects can only appear after named objects were added. Thus,
+ // we can wait until we have one, to avoid installing unnecessary filters.
+ if (!browser_filter_added_ &&
+ web_contents()->GetRenderProcessHost()->GetChannel() &&
+ !named_objects_.empty()) {
+ web_contents()->GetRenderProcessHost()->AddFilter(this);
+ browser_filter_added_ = true;
+ }
}
void GinJavaBridgeDispatcherHost::RenderFrameCreated(
RenderFrameHost* render_frame_host) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ AddBrowserFilterIfNeeded();
for (NamedObjectMap::const_iterator iter = named_objects_.begin();
iter != named_objects_.end();
++iter) {
@@ -72,46 +107,52 @@ void GinJavaBridgeDispatcherHost::RenderFrameCreated(
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);
+ AddBrowserFilterIfNeeded();
+ base::AutoLock locker(objects_lock_);
+ auto iter = objects_.begin();
+ while (iter != objects_.end()) {
+ JavaObjectWeakGlobalRef ref =
+ RemoveHolderAndAdvanceLocked(render_frame_host->GetRoutingID(), &iter);
+ if (!ref.is_empty()) {
+ RemoveFromRetainedObjectSetLocked(ref);
+ }
}
- 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) {
+ int32 holder) {
+ // Can be called on any thread. Calls come from the UI thread via
+ // AddNamedObject, and from the background thread, when injected Java
+ // object's method returns a Java object.
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)));
+ scoped_refptr<GinJavaBoundObject> new_object =
+ is_named ? GinJavaBoundObject::CreateNamed(ref, safe_annotation_clazz)
+ : GinJavaBoundObject::CreateTransient(ref, safe_annotation_clazz,
+ holder);
+ // Note that we are abusing the fact that StaticAtomicSequenceNumber
+ // uses Atomic32 as a counter, so it is guaranteed that it will not
+ // overflow our int32 IDs. IDs start from 1.
+ GinJavaBoundObject::ObjectID object_id = g_next_object_id.GetNext() + 1;
+ {
+ base::AutoLock locker(objects_lock_);
+ objects_[object_id] = new_object;
}
-#if DCHECK_IS_ON
+#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
+#endif // DCHECK_IS_ON()
base::android::ScopedJavaLocalRef<jobject> retained_object_set =
retained_object_set_.get(env);
if (!retained_object_set.is_null()) {
+ base::AutoLock locker(objects_lock_);
JNI_Java_HashSet_add(env, retained_object_set, object);
}
return object_id;
@@ -120,13 +161,14 @@ GinJavaBoundObject::ObjectID GinJavaBridgeDispatcherHost::AddObject(
bool GinJavaBridgeDispatcherHost::FindObjectId(
const base::android::JavaRef<jobject>& object,
GinJavaBoundObject::ObjectID* object_id) {
+ // Can be called on any thread.
JNIEnv* env = base::android::AttachCurrentThread();
- for (GinJavaBoundObject::ObjectMap::iterator it(&objects_); !it.IsAtEnd();
- it.Advance()) {
+ base::AutoLock locker(objects_lock_);
+ for (const auto& pair : objects_) {
if (env->IsSameObject(
object.obj(),
- it.GetCurrentValue()->get()->GetLocalRef(env).obj())) {
- *object_id = it.GetCurrentKey();
+ pair.second->GetLocalRef(env).obj())) {
+ *object_id = pair.first;
return true;
}
}
@@ -135,37 +177,44 @@ bool GinJavaBridgeDispatcherHost::FindObjectId(
JavaObjectWeakGlobalRef GinJavaBridgeDispatcherHost::GetObjectWeakRef(
GinJavaBoundObject::ObjectID object_id) {
- scoped_refptr<GinJavaBoundObject>* result = objects_.Lookup(object_id);
- scoped_refptr<GinJavaBoundObject> object(result ? *result : NULL);
+ scoped_refptr<GinJavaBoundObject> object = FindObject(object_id);
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;
+JavaObjectWeakGlobalRef
+GinJavaBridgeDispatcherHost::RemoveHolderAndAdvanceLocked(
+ int32 holder,
+ ObjectMap::iterator* iter_ptr) {
+ objects_lock_.AssertAcquired();
+ JavaObjectWeakGlobalRef result;
+ scoped_refptr<GinJavaBoundObject> object((*iter_ptr)->second);
+ bool object_erased = false;
+ if (!object->IsNamed()) {
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());
+ result = object->GetWeakRef();
+ objects_.erase((*iter_ptr)++);
+ object_erased = true;
}
}
+ if (!object_erased) {
+ ++(*iter_ptr);
+ }
+ return result;
+}
+
+void GinJavaBridgeDispatcherHost::RemoveFromRetainedObjectSetLocked(
+ const JavaObjectWeakGlobalRef& ref) {
+ objects_lock_.AssertAcquired();
+ 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, ref.get(env));
+ }
}
void GinJavaBridgeDispatcherHost::AddNamedObject(
@@ -185,12 +234,14 @@ void GinJavaBridgeDispatcherHost::AddNamedObject(
RemoveNamedObject(iter->first);
}
if (existing_object) {
- (*objects_.Lookup(object_id))->AddName();
+ base::AutoLock locker(objects_lock_);
+ objects_[object_id]->AddName();
} else {
- object_id = AddObject(object, safe_annotation_clazz, true, NULL);
+ object_id = AddObject(object, safe_annotation_clazz, true, 0);
}
named_objects_[name] = object_id;
+ AddBrowserFilterIfNeeded();
web_contents()->SendToAllFrames(
new GinJavaBridgeMsg_AddNamedObject(MSG_ROUTING_NONE, name, object_id));
}
@@ -206,9 +257,11 @@ void GinJavaBridgeDispatcherHost::RemoveNamedObject(
// |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));
+ {
+ base::AutoLock locker(objects_lock_);
+ objects_[iter->second]->RemoveName();
+ }
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
@@ -220,6 +273,14 @@ void GinJavaBridgeDispatcherHost::RemoveNamedObject(
}
void GinJavaBridgeDispatcherHost::SetAllowObjectContentsInspection(bool allow) {
+ if (!JavaBridgeThread::CurrentlyOn()) {
+ g_background_thread.Get().message_loop()->task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &GinJavaBridgeDispatcherHost::SetAllowObjectContentsInspection,
+ this, allow));
+ return;
+ }
allow_object_contents_inspection_ = allow;
}
@@ -228,337 +289,203 @@ void GinJavaBridgeDispatcherHost::DocumentAvailableInMainFrame() {
// 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.
+ AddBrowserFilterIfNeeded();
JNIEnv* env = base::android::AttachCurrentThread();
base::android::ScopedJavaLocalRef<jobject> retained_object_set =
retained_object_set_.get(env);
+ base::AutoLock locker(objects_lock_);
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()) {
+ auto iter = objects_.begin();
+ while (iter != objects_.end()) {
+ if (iter->second->IsNamed()) {
if (!retained_object_set.is_null()) {
JNI_Java_HashSet_add(
- env, retained_object_set, object->GetLocalRef(env));
+ env, retained_object_set, iter->second->GetLocalRef(env));
}
+ ++iter;
} else {
- objects_.Remove(it.GetCurrentKey());
+ objects_.erase(iter++);
}
}
}
-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);
+base::TaskRunner* GinJavaBridgeDispatcherHost::OverrideTaskRunnerForMessage(
+ const IPC::Message& message) {
+ GinJavaBoundObject::ObjectID object_id = 0;
+ // TODO(mnaganov): It's very sad that we have a BrowserMessageFilter per
+ // WebView instance. We should redesign to have a filter per RPH.
+ // Check, if the object ID in the message is known to this host. If not,
+ // this is a message for some other host. As all our IPC messages from the
+ // renderer start with object ID, we just fetch it directly from the
+ // message, considering sync and async messages separately.
+ switch (message.type()) {
+ case GinJavaBridgeHostMsg_GetMethods::ID:
+ case GinJavaBridgeHostMsg_HasMethod::ID:
+ case GinJavaBridgeHostMsg_InvokeMethod::ID: {
+ DCHECK(message.is_sync());
+ PickleIterator message_reader =
+ IPC::SyncMessage::GetDataIterator(&message);
+ if (!IPC::ReadParam(&message, &message_reader, &object_id))
+ return NULL;
+ break;
+ }
+ case GinJavaBridgeHostMsg_ObjectWrapperDeleted::ID: {
+ DCHECK(!message.is_sync());
+ PickleIterator message_reader(message);
+ if (!IPC::ReadParam(&message, &message_reader, &object_id))
+ return NULL;
+ break;
+ }
+ default:
+ NOTREACHED();
+ return NULL;
}
- virtual bool Send(IPC::Message* msg) override {
- NOTREACHED();
- return false;
+ {
+ base::AutoLock locker(objects_lock_);
+ if (objects_.find(object_id) != objects_.end()) {
+ return g_background_thread.Get().message_loop()->task_runner().get();
+ }
}
- private:
- GinJavaBridgeDispatcherHost* gjbdh_;
- RenderFrameHost* render_frame_host_;
-};
-
+ return NULL;
}
bool GinJavaBridgeDispatcherHost::OnMessageReceived(
- const IPC::Message& message,
- RenderFrameHost* render_frame_host) {
- DCHECK(render_frame_host);
+ const IPC::Message& message) {
+ // We can get here As WebContentsObserver also has OnMessageReceived,
+ // or because we have not provided a task runner in
+ // OverrideTaskRunnerForMessage. In either case, just bail out.
+ if (!JavaBridgeThread::CurrentlyOn())
+ return false;
+ SetCurrentRoutingID(message.routing_id());
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_BEGIN_MESSAGE_MAP(GinJavaBridgeDispatcherHost, message)
+ IPC_MESSAGE_HANDLER(GinJavaBridgeHostMsg_GetMethods, OnGetMethods)
+ IPC_MESSAGE_HANDLER(GinJavaBridgeHostMsg_HasMethod, OnHasMethod)
+ IPC_MESSAGE_HANDLER(GinJavaBridgeHostMsg_InvokeMethod, OnInvokeMethod)
IPC_MESSAGE_HANDLER(GinJavaBridgeHostMsg_ObjectWrapperDeleted,
OnObjectWrapperDeleted)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
+ SetCurrentRoutingID(MSG_ROUTING_NONE);
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;
+void GinJavaBridgeDispatcherHost::OnDestruct() const {
+ if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ delete this;
+ } else {
+ BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, this);
}
+}
- private:
- friend class base::RefCounted<IsValidRenderFrameHostHelper>;
-
- ~IsValidRenderFrameHostHelper() {}
-
- RenderFrameHost* rfh_to_match_;
- bool rfh_found_;
-
- DISALLOW_COPY_AND_ASSIGN(IsValidRenderFrameHostHelper);
-};
+int GinJavaBridgeDispatcherHost::GetCurrentRoutingID() const {
+ DCHECK(JavaBridgeThread::CurrentlyOn());
+ return current_routing_id_;
+}
-} // namespace
+void GinJavaBridgeDispatcherHost::SetCurrentRoutingID(int32 routing_id) {
+ DCHECK(JavaBridgeThread::CurrentlyOn());
+ current_routing_id_ = routing_id;
+}
-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();
+scoped_refptr<GinJavaBoundObject> GinJavaBridgeDispatcherHost::FindObject(
+ GinJavaBoundObject::ObjectID object_id) {
+ // Can be called on any thread.
+ base::AutoLock locker(objects_lock_);
+ auto iter = objects_.find(object_id);
+ if (iter != objects_.end())
+ return iter->second;
+ return NULL;
}
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);
+ std::set<std::string>* returned_method_names) {
+ DCHECK(JavaBridgeThread::CurrentlyOn());
+ if (!allow_object_contents_inspection_)
return;
- }
- scoped_refptr<GinJavaBoundObject> object(*objects_.Lookup(object_id));
- if (!object.get()) {
+ scoped_refptr<GinJavaBoundObject> object = FindObject(object_id);
+ if (object.get()) {
+ *returned_method_names = object->GetMethodNames();
+ } else {
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()) {
+ bool* result) {
+ DCHECK(JavaBridgeThread::CurrentlyOn());
+ scoped_refptr<GinJavaBoundObject> object = FindObject(object_id);
+ if (object.get()) {
+ *result = object->HasMethod(method_name);
+ } else {
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));
+ base::ListValue* wrapped_result,
+ content::GinJavaBridgeError* error_code) {
+ DCHECK(JavaBridgeThread::CurrentlyOn());
+ DCHECK(GetCurrentRoutingID() != MSG_ROUTING_NONE);
+ scoped_refptr<GinJavaBoundObject> object = FindObject(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);
+ wrapped_result->Append(base::Value::CreateNullValue());
+ *error_code = kGinJavaBridgeUnknownObjectId;
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) {
+ result->Invoke();
+ *error_code = result->GetInvocationError();
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()) {
+ scoped_ptr<base::ListValue> result_copy(
+ result->GetPrimitiveResult().DeepCopy());
+ wrapped_result->Swap(result_copy.get());
+ } else 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);
+ base::AutoLock locker(objects_lock_);
+ objects_[returned_object_id]->AddHolder(GetCurrentRoutingID());
} else {
returned_object_id = AddObject(result->GetObjectResult(),
result->GetSafeAnnotationClass(),
false,
- render_frame_host);
+ GetCurrentRoutingID());
}
- wrapped_result.Append(
+ wrapped_result->Append(
GinJavaBridgeValue::CreateObjectIDValue(
returned_object_id).release());
} else {
- wrapped_result.Append(base::Value::CreateNullValue());
+ 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;
+ DCHECK(JavaBridgeThread::CurrentlyOn());
+ DCHECK(GetCurrentRoutingID() != MSG_ROUTING_NONE);
+ base::AutoLock locker(objects_lock_);
+ auto iter = objects_.find(object_id);
+ if (iter == objects_.end())
+ return;
+ JavaObjectWeakGlobalRef ref =
+ RemoveHolderAndAdvanceLocked(GetCurrentRoutingID(), &iter);
+ if (!ref.is_empty()) {
+ RemoveFromRetainedObjectSetLocked(ref);
}
-
- 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
index c57ba260f1e..56fddeed5f1 100644
--- a/chromium/content/browser/android/java/gin_java_bridge_dispatcher_host.h
+++ b/chromium/content/browser/android/java/gin_java_bridge_dispatcher_host.h
@@ -12,8 +12,10 @@
#include "base/android/scoped_java_ref.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
+#include "base/synchronization/lock.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/browser_message_filter.h"
#include "content/public/browser/web_contents_observer.h"
namespace base {
@@ -31,14 +33,13 @@ namespace content {
// 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 WebContentsObserver,
+ public BrowserMessageFilter,
public GinJavaMethodInvocationHelper::DispatcherDelegate {
public:
GinJavaBridgeDispatcherHost(WebContents* web_contents,
jobject retained_object_set);
- virtual ~GinJavaBridgeDispatcherHost();
void AddNamedObject(
const std::string& name,
@@ -48,56 +49,68 @@ class GinJavaBridgeDispatcherHost
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;
+ void RenderFrameCreated(RenderFrameHost* render_frame_host) override;
+ void RenderFrameDeleted(RenderFrameHost* render_frame_host) override;
+ void DocumentAvailableInMainFrame() override;
+
+ // BrowserMessageFilter
+ using BrowserMessageFilter::Send;
+ void OnDestruct() const override;
+ bool OnMessageReceived(const IPC::Message& message) override;
+ base::TaskRunner* OverrideTaskRunnerForMessage(
+ const IPC::Message& message) override;
// GinJavaMethodInvocationHelper::DispatcherDelegate
- virtual JavaObjectWeakGlobalRef GetObjectWeakRef(
+ 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);
+ friend class BrowserThread;
+ friend class base::DeleteHelper<GinJavaBridgeDispatcherHost>;
+
+ typedef std::map<GinJavaBoundObject::ObjectID,
+ scoped_refptr<GinJavaBoundObject>> ObjectMap;
+
+ ~GinJavaBridgeDispatcherHost() override;
+
+ void AddBrowserFilterIfNeeded();
+
+ // Run on any thread.
GinJavaBoundObject::ObjectID AddObject(
const base::android::JavaRef<jobject>& object,
const base::android::JavaRef<jclass>& safe_annotation_clazz,
bool is_named,
- RenderFrameHost* holder);
+ int32 holder);
+ scoped_refptr<GinJavaBoundObject> FindObject(
+ GinJavaBoundObject::ObjectID object_id);
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);
+ void RemoveFromRetainedObjectSetLocked(const JavaObjectWeakGlobalRef& ref);
+ JavaObjectWeakGlobalRef RemoveHolderAndAdvanceLocked(
+ int32 holder,
+ ObjectMap::iterator* iter_ptr);
+
+ // Run on the background thread.
+ void OnGetMethods(GinJavaBoundObject::ObjectID object_id,
+ std::set<std::string>* returned_method_names);
+ void OnHasMethod(GinJavaBoundObject::ObjectID object_id,
+ const std::string& method_name,
+ bool* result);
+ void OnInvokeMethod(GinJavaBoundObject::ObjectID object_id,
+ const std::string& method_name,
+ const base::ListValue& arguments,
+ base::ListValue* result,
+ content::GinJavaBridgeError* error_code);
+ void OnObjectWrapperDeleted(GinJavaBoundObject::ObjectID object_id);
+ int GetCurrentRoutingID() const;
+ void SetCurrentRoutingID(int routing_id);
+
+ bool browser_filter_added_;
+
+ typedef std::map<std::string, GinJavaBoundObject::ObjectID> NamedObjectMap;
+ NamedObjectMap named_objects_;
+
+ // The following objects are used on both threads, so locking must be used.
// Every time a GinJavaBoundObject backed by a real Java object is
// created/destroyed, we insert/remove a strong ref to that Java object into
@@ -106,17 +119,15 @@ class GinJavaBridgeDispatcherHost
// 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_;
+ // Note that retained_object_set_ does not need to be consistent
+ // with objects_.
+ ObjectMap objects_;
+ base::Lock objects_lock_;
- // 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_;
+ // The following objects are only used on the background thread.
+ bool allow_object_contents_inspection_;
+ // The routing id of the RenderFrameHost whose request we are processing.
+ int32 current_routing_id_;
DISALLOW_COPY_AND_ASSIGN(GinJavaBridgeDispatcherHost);
};
diff --git a/chromium/content/browser/android/java/gin_java_method_invocation_helper.cc b/chromium/content/browser/android/java/gin_java_method_invocation_helper.cc
index ae1c798fe52..93ab2e66228 100644
--- a/chromium/content/browser/android/java/gin_java_method_invocation_helper.cc
+++ b/chromium/content/browser/android/java/gin_java_method_invocation_helper.cc
@@ -6,10 +6,11 @@
#include <unistd.h>
+#include <cmath>
+
#include "base/android/event_log.h"
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
-#include "base/float_util.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"
@@ -256,7 +257,7 @@ void GinJavaMethodInvocationHelper::InvokeMethod(jobject object,
float result = object
? env->CallFloatMethodA(object, id, parameters)
: env->CallStaticFloatMethodA(clazz, id, parameters);
- if (base::IsFinite(result)) {
+ if (std::isfinite(result)) {
result_wrapper.AppendDouble(result);
} else {
result_wrapper.Append(
@@ -268,7 +269,7 @@ void GinJavaMethodInvocationHelper::InvokeMethod(jobject object,
double result = object
? env->CallDoubleMethodA(object, id, parameters)
: env->CallStaticDoubleMethodA(clazz, id, parameters);
- if (base::IsFinite(result)) {
+ if (std::isfinite(result)) {
result_wrapper.AppendDouble(result);
} else {
result_wrapper.Append(
diff --git a/chromium/content/browser/android/java/gin_java_method_invocation_helper.h b/chromium/content/browser/android/java/gin_java_method_invocation_helper.h
index 014e3113194..f7bdd57747f 100644
--- a/chromium/content/browser/android/java/gin_java_method_invocation_helper.h
+++ b/chromium/content/browser/android/java/gin_java_method_invocation_helper.h
@@ -20,13 +20,10 @@ namespace content {
class JavaMethod;
-// Instances of this class are created and initialized on the UI thread, do
-// their work on the background thread, and then again examined on the UI
-// thread. They don't work on both threads simultaneously, though.
+// Instances of this class are created and used on the background thread.
class CONTENT_EXPORT GinJavaMethodInvocationHelper
: public base::RefCountedThreadSafe<GinJavaMethodInvocationHelper> {
public:
- // DispatcherDelegate is used on the UI thread
class DispatcherDelegate {
public:
DispatcherDelegate() {}
@@ -38,7 +35,6 @@ class CONTENT_EXPORT GinJavaMethodInvocationHelper
DISALLOW_COPY_AND_ASSIGN(DispatcherDelegate);
};
- // ObjectDelegate is used in the background thread
class ObjectDelegate {
public:
ObjectDelegate() {}
@@ -61,10 +57,8 @@ class CONTENT_EXPORT GinJavaMethodInvocationHelper
const base::ListValue& arguments);
void Init(DispatcherDelegate* dispatcher);
- // Called on the background thread
void Invoke();
- // Called on the UI thread
bool HoldsPrimitiveResult();
const base::ListValue& GetPrimitiveResult();
const base::android::JavaRef<jobject>& GetObjectResult();
@@ -75,7 +69,6 @@ class CONTENT_EXPORT GinJavaMethodInvocationHelper
friend class base::RefCountedThreadSafe<GinJavaMethodInvocationHelper>;
~GinJavaMethodInvocationHelper();
- // Called on the UI thread
void BuildObjectRefsFromListValue(DispatcherDelegate* dispatcher,
const base::Value* list_value);
void BuildObjectRefsFromDictionaryValue(DispatcherDelegate* dispatcher,
@@ -84,7 +77,6 @@ class CONTENT_EXPORT GinJavaMethodInvocationHelper
bool AppendObjectRef(DispatcherDelegate* dispatcher,
const base::Value* raw_value);
- // Called on the background thread.
void InvokeMethod(jobject object,
jclass clazz,
const JavaType& return_type,
diff --git a/chromium/content/browser/android/java/gin_java_method_invocation_helper_unittest.cc b/chromium/content/browser/android/java/gin_java_method_invocation_helper_unittest.cc
index ccd508355bb..fcda3cda934 100644
--- a/chromium/content/browser/android/java/gin_java_method_invocation_helper_unittest.cc
+++ b/chromium/content/browser/android/java/gin_java_method_invocation_helper_unittest.cc
@@ -18,29 +18,27 @@ class NullObjectDelegate
public:
NullObjectDelegate() {}
- virtual ~NullObjectDelegate() {}
+ ~NullObjectDelegate() override {}
- virtual base::android::ScopedJavaLocalRef<jobject> GetLocalRef(
- JNIEnv* env) override {
+ base::android::ScopedJavaLocalRef<jobject> GetLocalRef(JNIEnv* env) override {
return base::android::ScopedJavaLocalRef<jobject>();
}
- virtual base::android::ScopedJavaLocalRef<jclass> GetLocalClassRef(
+ base::android::ScopedJavaLocalRef<jclass> GetLocalClassRef(
JNIEnv* env) override {
return base::android::ScopedJavaLocalRef<jclass>();
}
- virtual const JavaMethod* FindMethod(const std::string& method_name,
- size_t num_parameters) override {
+ const JavaMethod* FindMethod(const std::string& method_name,
+ size_t num_parameters) override {
return NULL;
}
- virtual bool IsObjectGetClassMethod(const JavaMethod* method) override {
+ bool IsObjectGetClassMethod(const JavaMethod* method) override {
return false;
}
- virtual const base::android::JavaRef<jclass>& GetSafeAnnotationClass()
- override {
+ const base::android::JavaRef<jclass>& GetSafeAnnotationClass() override {
return safe_annotation_class_;
}
@@ -55,9 +53,9 @@ class NullDispatcherDelegate
public:
NullDispatcherDelegate() {}
- virtual ~NullDispatcherDelegate() {}
+ ~NullDispatcherDelegate() override {}
- virtual JavaObjectWeakGlobalRef GetObjectWeakRef(
+ JavaObjectWeakGlobalRef GetObjectWeakRef(
GinJavaBoundObject::ObjectID object_id) override {
return JavaObjectWeakGlobalRef();
}
@@ -77,9 +75,9 @@ class CountingDispatcherDelegate
public:
CountingDispatcherDelegate() {}
- virtual ~CountingDispatcherDelegate() {}
+ ~CountingDispatcherDelegate() override {}
- virtual JavaObjectWeakGlobalRef GetObjectWeakRef(
+ JavaObjectWeakGlobalRef GetObjectWeakRef(
GinJavaBoundObject::ObjectID object_id) override {
counters_[object_id]++;
return JavaObjectWeakGlobalRef();
@@ -176,16 +174,15 @@ class ObjectIsGoneObjectDelegate : public NullObjectDelegate {
method_.reset(new JavaMethod(method_obj));
}
- virtual ~ObjectIsGoneObjectDelegate() {}
+ ~ObjectIsGoneObjectDelegate() override {}
- virtual base::android::ScopedJavaLocalRef<jobject> GetLocalRef(
- JNIEnv* env) override {
+ 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 {
+ const JavaMethod* FindMethod(const std::string& method_name,
+ size_t num_parameters) override {
return method_.get();
}
@@ -230,16 +227,15 @@ class MethodNotFoundObjectDelegate : public NullObjectDelegate {
public:
MethodNotFoundObjectDelegate() : find_method_called_(false) {}
- virtual ~MethodNotFoundObjectDelegate() {}
+ ~MethodNotFoundObjectDelegate() override {}
- virtual base::android::ScopedJavaLocalRef<jobject> GetLocalRef(
- JNIEnv* env) override {
+ base::android::ScopedJavaLocalRef<jobject> GetLocalRef(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 {
+ const JavaMethod* FindMethod(const std::string& method_name,
+ size_t num_parameters) override {
find_method_called_ = true;
return NULL;
}
@@ -282,15 +278,15 @@ class GetClassObjectDelegate : public MethodNotFoundObjectDelegate {
public:
GetClassObjectDelegate() : get_class_called_(false) {}
- virtual ~GetClassObjectDelegate() {}
+ ~GetClassObjectDelegate() override {}
- virtual const JavaMethod* FindMethod(const std::string& method_name,
- size_t num_parameters) override {
+ const JavaMethod* FindMethod(const std::string& method_name,
+ size_t num_parameters) override {
find_method_called_ = true;
return kFakeGetClass;
}
- virtual bool IsObjectGetClassMethod(const JavaMethod* method) override {
+ bool IsObjectGetClassMethod(const JavaMethod* method) override {
get_class_called_ = true;
return kFakeGetClass == method;
}
diff --git a/chromium/content/browser/android/java/gin_java_script_to_java_types_coercion.cc b/chromium/content/browser/android/java/gin_java_script_to_java_types_coercion.cc
index cb4e51776b4..84b2070366a 100644
--- a/chromium/content/browser/android/java/gin_java_script_to_java_types_coercion.cc
+++ b/chromium/content/browser/android/java/gin_java_script_to_java_types_coercion.cc
@@ -460,7 +460,7 @@ jobject CoerceJavaScriptListToArray(JNIEnv* env,
if (!result) {
return NULL;
}
- scoped_ptr<base::Value> null_value(base::Value::CreateNullValue());
+ scoped_ptr<base::Value> null_value = base::Value::CreateNullValue();
for (jsize i = 0; i < length; ++i) {
const base::Value* value_element = null_value.get();
list_value->Get(i, &value_element);
@@ -531,7 +531,7 @@ jobject CoerceJavaScriptDictionaryToArray(JNIEnv* env,
if (!result) {
return NULL;
}
- scoped_ptr<base::Value> null_value(base::Value::CreateNullValue());
+ scoped_ptr<base::Value> null_value = base::Value::CreateNullValue();
for (jsize i = 0; i < length; ++i) {
const std::string key(base::IntToString(i));
const base::Value* value_element = null_value.get();
diff --git a/chromium/content/browser/android/load_url_params.cc b/chromium/content/browser/android/load_url_params.cc
index d276622f55a..67802ea0cfb 100644
--- a/chromium/content/browser/android/load_url_params.cc
+++ b/chromium/content/browser/android/load_url_params.cc
@@ -12,29 +12,10 @@
#include "jni/LoadUrlParams_jni.h"
#include "url/gurl.h"
-namespace {
-
-using content::NavigationController;
-
-void RegisterConstants(JNIEnv* env) {
- Java_LoadUrlParams_initializeConstants(env,
- NavigationController::LOAD_TYPE_DEFAULT,
- NavigationController::LOAD_TYPE_BROWSER_INITIATED_HTTP_POST,
- NavigationController::LOAD_TYPE_DATA,
- NavigationController::UA_OVERRIDE_INHERIT,
- NavigationController::UA_OVERRIDE_FALSE,
- NavigationController::UA_OVERRIDE_TRUE);
-}
-
-} // namespace
-
namespace content {
bool RegisterLoadUrlParams(JNIEnv* env) {
- if (!RegisterNativesImpl(env))
- return false;
- RegisterConstants(env);
- return true;
+ return RegisterNativesImpl(env);
}
jboolean IsDataScheme(JNIEnv* env, jclass clazz, jstring jurl) {
diff --git a/chromium/content/browser/android/media_players_observer.cc b/chromium/content/browser/android/media_players_observer.cc
new file mode 100644
index 00000000000..c2771307571
--- /dev/null
+++ b/chromium/content/browser/android/media_players_observer.cc
@@ -0,0 +1,59 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/android/media_players_observer.h"
+
+#include <climits>
+
+#include "base/logging.h"
+#include "content/public/browser/web_contents.h"
+
+namespace content {
+
+MediaPlayersObserver::MediaPlayersObserver(WebContents* web_contents)
+ : AudioStateProvider(web_contents) {
+}
+
+MediaPlayersObserver::~MediaPlayersObserver() {}
+
+bool MediaPlayersObserver::IsAudioStateAvailable() const {
+ return true;
+}
+
+// This audio state provider does not have a monitor
+AudioStreamMonitor* MediaPlayersObserver::audio_stream_monitor() {
+ return nullptr;
+}
+
+void MediaPlayersObserver::OnAudibleStateChanged(RenderFrameHost* rfh,
+ int player_id,
+ bool is_audible) {
+ audio_status_map_[Key(rfh, player_id)] = is_audible;
+ UpdateStatusAndNotify();
+}
+
+void MediaPlayersObserver::RemovePlayer(RenderFrameHost* rfh, int player_id) {
+ audio_status_map_.erase(Key(rfh, player_id));
+ UpdateStatusAndNotify();
+}
+
+void MediaPlayersObserver::RenderFrameDeleted(RenderFrameHost* rfh) {
+ StatusMap::iterator begin = audio_status_map_.lower_bound(Key(rfh, 0));
+ StatusMap::iterator end = audio_status_map_.upper_bound(Key(rfh, INT_MAX));
+ audio_status_map_.erase(begin, end);
+ UpdateStatusAndNotify();
+}
+
+void MediaPlayersObserver::UpdateStatusAndNotify() {
+ for (const auto& player_status : audio_status_map_) {
+ if (player_status.second) {
+ Notify(true); // at least one player is making noise
+ return;
+ }
+ }
+
+ Notify(false);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/android/media_players_observer.h b/chromium/content/browser/android/media_players_observer.h
new file mode 100644
index 00000000000..b01a3bf916a
--- /dev/null
+++ b/chromium/content/browser/android/media_players_observer.h
@@ -0,0 +1,51 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_ANDROID_MEDIA_PLAYERS_OBSERVER_H_
+#define CONTENT_BROWSER_ANDROID_MEDIA_PLAYERS_OBSERVER_H_
+
+#include <map>
+
+#include "base/macros.h"
+#include "content/browser/media/audio_state_provider.h"
+
+namespace content {
+
+class RenderFrameHost;
+
+// On Android the MediaPlayerAndroid objects report
+// the audible state to us.
+class MediaPlayersObserver : public AudioStateProvider {
+ public:
+ explicit MediaPlayersObserver(WebContents* web_contents);
+ ~MediaPlayersObserver() override;
+
+ bool IsAudioStateAvailable() const override;
+
+ // This audio state provider does not have a monitor,
+ // the method returns nullptr.
+ AudioStreamMonitor* audio_stream_monitor() override;
+
+ // These methods constitute the observer pattern, should
+ // be called when corresponding event happens. They will notify
+ // WebContents whenever its audible state as a whole changes.
+ void OnAudibleStateChanged(RenderFrameHost* rfh, int player_id,
+ bool is_audible);
+ void RemovePlayer(RenderFrameHost* rfh, int player_id);
+ void RenderFrameDeleted(RenderFrameHost* rfh);
+
+ private:
+ void UpdateStatusAndNotify();
+
+ // Audible status per player ID and frame
+ typedef std::pair<RenderFrameHost*, int> Key;
+ typedef std::map<Key, bool> StatusMap;
+ StatusMap audio_status_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(MediaPlayersObserver);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_ANDROID_MEDIA_PLAYERS_OBSERVER_H_
diff --git a/chromium/content/browser/android/overscroll_controller_android.cc b/chromium/content/browser/android/overscroll_controller_android.cc
new file mode 100644
index 00000000000..d73cd22247c
--- /dev/null
+++ b/chromium/content/browser/android/overscroll_controller_android.cc
@@ -0,0 +1,294 @@
+// Copyright 2014 The Chromium Authors. 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/overscroll_controller_android.h"
+
+#include "base/android/build_info.h"
+#include "base/command_line.h"
+#include "cc/layers/layer.h"
+#include "cc/output/compositor_frame_metadata.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/web_contents/web_contents_impl.h"
+#include "content/common/input/did_overscroll_params.h"
+#include "content/public/browser/navigation_controller.h"
+#include "content/public/browser/user_metrics.h"
+#include "content/public/common/content_switches.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
+#include "ui/android/resources/resource_manager.h"
+#include "ui/android/window_android.h"
+#include "ui/android/window_android_compositor.h"
+#include "ui/base/l10n/l10n_util_android.h"
+
+namespace content {
+namespace {
+
+// Used for conditional creation of EdgeEffect types for the overscroll glow.
+const int kAndroidLSDKVersion = 21;
+
+// If the glow effect alpha is greater than this value, the refresh effect will
+// be suppressed. This value was experimentally determined to provide a
+// reasonable balance between avoiding accidental refresh activation and
+// minimizing the wait required to refresh after the glow has been triggered.
+const float kMinGlowAlphaToDisableRefreshOnL = 0.085f;
+
+bool IsAndroidLOrNewer() {
+ static bool android_l_or_newer =
+ base::android::BuildInfo::GetInstance()->sdk_int() >= kAndroidLSDKVersion;
+ return android_l_or_newer;
+}
+
+// Suppressing refresh detection when the glow is still animating prevents
+// visual confusion and accidental activation after repeated scrolls.
+float MinGlowAlphaToDisableRefresh() {
+ // Only the L effect is guaranteed to be both sufficiently brief and prominent
+ // to provide a meaningful "wait" signal. The refresh effect on previous
+ // Android releases can be quite faint, depending on the OEM-supplied
+ // overscroll resources, and lasts nearly twice as long.
+ if (IsAndroidLOrNewer())
+ return kMinGlowAlphaToDisableRefreshOnL;
+
+ // Any value greater than 1 effectively prevents the glow effect from ever
+ // suppressing the refresh effect.
+ return 1.01f;
+}
+
+scoped_ptr<EdgeEffectBase> CreateGlowEdgeEffect(
+ ui::ResourceManager* resource_manager,
+ float dpi_scale) {
+ DCHECK(resource_manager);
+ if (IsAndroidLOrNewer())
+ return scoped_ptr<EdgeEffectBase>(new EdgeEffectL(resource_manager));
+
+ return scoped_ptr<EdgeEffectBase>(
+ new EdgeEffect(resource_manager, dpi_scale));
+}
+
+scoped_ptr<OverscrollGlow> CreateGlowEffect(OverscrollGlowClient* client,
+ float dpi_scale) {
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableOverscrollEdgeEffect)) {
+ return nullptr;
+ }
+
+ return make_scoped_ptr(new OverscrollGlow(client));
+}
+
+scoped_ptr<OverscrollRefresh> CreateRefreshEffect(
+ OverscrollRefreshHandler* handler) {
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisablePullToRefreshEffect)) {
+ return nullptr;
+ }
+
+ return make_scoped_ptr(new OverscrollRefresh(handler));
+}
+
+} // namespace
+
+OverscrollControllerAndroid::OverscrollControllerAndroid(
+ ContentViewCoreImpl* content_view_core)
+ : compositor_(content_view_core->GetWindowAndroid()->GetCompositor()),
+ dpi_scale_(content_view_core->GetDpiScale()),
+ enabled_(true),
+ glow_effect_(CreateGlowEffect(this, dpi_scale_)),
+ refresh_effect_(CreateRefreshEffect(content_view_core)),
+ is_fullscreen_(false) {
+ DCHECK(compositor_);
+ // Fullscreen state is only relevant for the refresh effect.
+ if (refresh_effect_) {
+ WebContentsImpl* web_contents =
+ static_cast<WebContentsImpl*>(content_view_core->GetWebContents());
+ is_fullscreen_ = web_contents->IsFullscreenForCurrentTab();
+ Observe(web_contents);
+ }
+}
+
+OverscrollControllerAndroid::~OverscrollControllerAndroid() {
+}
+
+bool OverscrollControllerAndroid::WillHandleGestureEvent(
+ const blink::WebGestureEvent& event) {
+ if (!enabled_)
+ return false;
+
+ if (!refresh_effect_)
+ return false;
+
+ // Suppress refresh detection for fullscreen HTML5 scenarios, e.g., video.
+ if (is_fullscreen_)
+ return false;
+
+ // Suppress refresh detection if the glow effect is still prominent.
+ if (glow_effect_ && glow_effect_->IsActive()) {
+ if (glow_effect_->GetVisibleAlpha() > MinGlowAlphaToDisableRefresh())
+ return false;
+ }
+
+ bool handled = false;
+ switch (event.type) {
+ case blink::WebInputEvent::GestureScrollBegin:
+ refresh_effect_->OnScrollBegin();
+ break;
+
+ case blink::WebInputEvent::GestureScrollUpdate: {
+ gfx::Vector2dF scroll_delta(event.data.scrollUpdate.deltaX,
+ event.data.scrollUpdate.deltaY);
+ scroll_delta.Scale(dpi_scale_);
+ handled = refresh_effect_->WillHandleScrollUpdate(scroll_delta);
+ } break;
+
+ case blink::WebInputEvent::GestureScrollEnd:
+ refresh_effect_->OnScrollEnd(gfx::Vector2dF());
+ break;
+
+ case blink::WebInputEvent::GestureFlingStart: {
+ if (refresh_effect_->IsActive()) {
+ gfx::Vector2dF scroll_velocity(event.data.flingStart.velocityX,
+ event.data.flingStart.velocityY);
+ scroll_velocity.Scale(dpi_scale_);
+ refresh_effect_->OnScrollEnd(scroll_velocity);
+ // TODO(jdduke): Figure out a cleaner way of suppressing a fling.
+ // It's important that the any downstream code sees a scroll-ending
+ // event (in this case GestureFlingStart) if it has seen a scroll begin.
+ // Thus, we cannot simply consume the fling. Changing the event type to
+ // a GestureScrollEnd might work in practice, but could lead to
+ // unexpected results. For now, simply truncate the fling velocity, but
+ // not to zero as downstream code may not expect a zero-velocity fling.
+ blink::WebGestureEvent& modified_event =
+ const_cast<blink::WebGestureEvent&>(event);
+ modified_event.data.flingStart.velocityX = .01f;
+ modified_event.data.flingStart.velocityY = .01f;
+ }
+ } break;
+
+ case blink::WebInputEvent::GesturePinchBegin:
+ refresh_effect_->ReleaseWithoutActivation();
+ break;
+
+ default:
+ break;
+ }
+
+ return handled;
+}
+
+void OverscrollControllerAndroid::OnGestureEventAck(
+ const blink::WebGestureEvent& event,
+ InputEventAckState ack_result) {
+ if (!enabled_)
+ return;
+
+ // 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) {
+ OnOverscrolled(DidOverscrollParams());
+ }
+
+ if (event.type == blink::WebInputEvent::GestureScrollUpdate &&
+ refresh_effect_) {
+ // The effect should only be allowed if both the causal touch events go
+ // unconsumed and the generated scroll events go unconsumed.
+ bool consumed = ack_result == INPUT_EVENT_ACK_STATE_CONSUMED ||
+ event.data.scrollUpdate.previousUpdateInSequencePrevented;
+ refresh_effect_->OnScrollUpdateAck(consumed);
+ }
+}
+
+void OverscrollControllerAndroid::OnOverscrolled(
+ const DidOverscrollParams& params) {
+ if (!enabled_)
+ return;
+
+ if (refresh_effect_ && (refresh_effect_->IsActive() ||
+ refresh_effect_->IsAwaitingScrollUpdateAck())) {
+ // An active (or potentially active) refresh effect should always pre-empt
+ // the passive glow effect.
+ return;
+ }
+
+ if (glow_effect_ &&
+ glow_effect_->OnOverscrolled(
+ base::TimeTicks::Now(),
+ gfx::ScaleVector2d(params.accumulated_overscroll, dpi_scale_),
+ gfx::ScaleVector2d(params.latest_overscroll_delta, dpi_scale_),
+ gfx::ScaleVector2d(params.current_fling_velocity, dpi_scale_),
+ gfx::ScaleVector2d(
+ params.causal_event_viewport_point.OffsetFromOrigin(),
+ dpi_scale_))) {
+ SetNeedsAnimate();
+ }
+}
+
+bool OverscrollControllerAndroid::Animate(base::TimeTicks current_time,
+ cc::Layer* parent_layer) {
+ DCHECK(parent_layer);
+ if (!enabled_)
+ return false;
+
+ return glow_effect_->Animate(current_time, parent_layer);
+}
+
+void OverscrollControllerAndroid::OnFrameMetadataUpdated(
+ const cc::CompositorFrameMetadata& frame_metadata) {
+ if (!refresh_effect_ && !glow_effect_)
+ return;
+
+ const float scale_factor =
+ frame_metadata.page_scale_factor * frame_metadata.device_scale_factor;
+ gfx::SizeF viewport_size =
+ gfx::ScaleSize(frame_metadata.scrollable_viewport_size, scale_factor);
+ gfx::SizeF content_size =
+ gfx::ScaleSize(frame_metadata.root_layer_size, scale_factor);
+ gfx::Vector2dF content_scroll_offset =
+ gfx::ScaleVector2d(frame_metadata.root_scroll_offset, scale_factor);
+
+ if (refresh_effect_) {
+ refresh_effect_->OnFrameUpdated(content_scroll_offset,
+ frame_metadata.root_overflow_y_hidden);
+ }
+
+ if (glow_effect_) {
+ glow_effect_->OnFrameUpdated(viewport_size, content_size,
+ content_scroll_offset);
+ }
+}
+
+void OverscrollControllerAndroid::Enable() {
+ enabled_ = true;
+}
+
+void OverscrollControllerAndroid::Disable() {
+ if (!enabled_)
+ return;
+ enabled_ = false;
+ if (!enabled_) {
+ if (refresh_effect_)
+ refresh_effect_->Reset();
+ if (glow_effect_)
+ glow_effect_->Reset();
+ }
+}
+
+void OverscrollControllerAndroid::DidToggleFullscreenModeForTab(
+ bool entered_fullscreen) {
+ DCHECK(refresh_effect_);
+ if (is_fullscreen_ == entered_fullscreen)
+ return;
+ is_fullscreen_ = entered_fullscreen;
+ if (is_fullscreen_)
+ refresh_effect_->ReleaseWithoutActivation();
+}
+
+scoped_ptr<EdgeEffectBase> OverscrollControllerAndroid::CreateEdgeEffect() {
+ return CreateGlowEdgeEffect(&compositor_->GetResourceManager(), dpi_scale_);
+}
+
+void OverscrollControllerAndroid::SetNeedsAnimate() {
+ compositor_->SetNeedsAnimate();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/android/overscroll_controller_android.h b/chromium/content/browser/android/overscroll_controller_android.h
new file mode 100644
index 00000000000..128b803eca2
--- /dev/null
+++ b/chromium/content/browser/android/overscroll_controller_android.h
@@ -0,0 +1,91 @@
+// Copyright 2014 The Chromium Authors. 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_OVERSCROLL_CONTROLLER_ANDROID_H_
+#define CONTENT_BROWSER_ANDROID_OVERSCROLL_CONTROLLER_ANDROID_H_
+
+#include "base/time/time.h"
+#include "content/browser/android/overscroll_glow.h"
+#include "content/browser/android/overscroll_refresh.h"
+#include "content/common/input/input_event_ack_state.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "ui/gfx/geometry/vector2d_f.h"
+
+namespace blink {
+class WebGestureEvent;
+}
+
+namespace cc {
+class CompositorFrameMetadata;
+class Layer;
+}
+
+namespace ui {
+class WindowAndroidCompositor;
+}
+
+namespace content {
+
+class ContentViewCoreImpl;
+struct DidOverscrollParams;
+
+// Glue class for handling all inputs into Android-specific overscroll effects,
+// both the passive overscroll glow and the active overscroll pull-to-refresh.
+// Note that all input coordinates (both for events and overscroll) are in DIPs.
+class OverscrollControllerAndroid : public OverscrollGlowClient,
+ public WebContentsObserver {
+ public:
+ explicit OverscrollControllerAndroid(ContentViewCoreImpl* content_view_core);
+ ~OverscrollControllerAndroid() override;
+
+ // Returns true if |event| is consumed by an overscroll effect, in which
+ // case it should cease propagation.
+ bool WillHandleGestureEvent(const blink::WebGestureEvent& event);
+
+ // To be called upon receipt of a gesture event ack.
+ void OnGestureEventAck(const blink::WebGestureEvent& event,
+ InputEventAckState ack_result);
+
+ // To be called upon receipt of an overscroll event.
+ void OnOverscrolled(const DidOverscrollParams& overscroll_params);
+
+ // Returns true if the effect still needs animation ticks.
+ // Note: The effect will detach itself when no further animation is required.
+ bool Animate(base::TimeTicks current_time, cc::Layer* parent_layer);
+
+ // To be called whenever the content frame has been updated.
+ void OnFrameMetadataUpdated(const cc::CompositorFrameMetadata& metadata);
+
+ // Toggle activity of any overscroll effects. When disabled, events will be
+ // ignored until the controller is re-enabled.
+ void Enable();
+ void Disable();
+
+ private:
+ // WebContentsObserver implementation.
+ void DidToggleFullscreenModeForTab(bool entered_fullscreen) override;
+
+ // OverscrollGlowClient implementation.
+ scoped_ptr<EdgeEffectBase> CreateEdgeEffect() override;
+
+ void SetNeedsAnimate();
+
+ ui::WindowAndroidCompositor* const compositor_;
+ const float dpi_scale_;
+
+ bool enabled_;
+
+ // TODO(jdduke): Factor out a common API from the two overscroll effects.
+ scoped_ptr<OverscrollGlow> glow_effect_;
+ scoped_ptr<OverscrollRefresh> refresh_effect_;
+
+ // For fullscreen HTML5 scenarios, the refresh effect will be disabled.
+ bool is_fullscreen_;
+
+ DISALLOW_COPY_AND_ASSIGN(OverscrollControllerAndroid);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_ANDROID_OVERSCROLL_CONTROLLER_ANDROID_H_
diff --git a/chromium/content/browser/android/overscroll_glow.cc b/chromium/content/browser/android/overscroll_glow.cc
index 6df795a2db2..6842becafa3 100644
--- a/chromium/content/browser/android/overscroll_glow.cc
+++ b/chromium/content/browser/android/overscroll_glow.cc
@@ -75,56 +75,58 @@ gfx::SizeF ComputeSize(OverscrollGlow::Edge edge,
} // namespace
-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(OverscrollGlowClient* client)
+ : client_(client), edge_offsets_(), initialized_(false) {
+ DCHECK(client);
}
OverscrollGlow::~OverscrollGlow() {
Detach();
}
-void OverscrollGlow::Enable() {
- enabled_ = true;
+void OverscrollGlow::Reset() {
+ if (!initialized_)
+ return;
+ Detach();
+ for (size_t i = 0; i < EDGE_COUNT; ++i)
+ edge_effects_[i]->Finish();
}
-void OverscrollGlow::Disable() {
- if (!enabled_)
- return;
- enabled_ = false;
- if (!enabled_ && initialized_) {
- Detach();
- for (size_t i = 0; i < EDGE_COUNT; ++i)
- edge_effects_[i]->Finish();
+bool OverscrollGlow::IsActive() const {
+ if (!initialized_)
+ return false;
+ for (size_t i = 0; i < EDGE_COUNT; ++i) {
+ if (!edge_effects_[i]->IsFinished())
+ return true;
}
+ return false;
}
-bool OverscrollGlow::OnOverscrolled(cc::Layer* overscrolling_layer,
- base::TimeTicks current_time,
- gfx::Vector2dF accumulated_overscroll,
- gfx::Vector2dF overscroll_delta,
- gfx::Vector2dF velocity,
- gfx::Vector2dF displacement) {
- DCHECK(overscrolling_layer);
-
- if (!enabled_)
- return false;
+float OverscrollGlow::GetVisibleAlpha() const {
+ float max_alpha = 0;
+ for (size_t i = 0; i < EDGE_COUNT; ++i) {
+ if (!edge_effects_[i]->IsFinished())
+ max_alpha = std::max(max_alpha, edge_effects_[i]->GetAlpha());
+ }
+ return std::min(max_alpha, 1.f);
+}
+bool OverscrollGlow::OnOverscrolled(base::TimeTicks current_time,
+ const gfx::Vector2dF& accumulated_overscroll,
+ gfx::Vector2dF overscroll_delta,
+ gfx::Vector2dF velocity,
+ const gfx::Vector2dF& displacement) {
// The size of the glow determines the relative effect of the inputs; an
// empty-sized effect is effectively disabled.
- if (display_params_.size.IsEmpty())
+ if (viewport_size_.IsEmpty())
return false;
// Ignore sufficiently small values that won't meaningfuly affect animation.
overscroll_delta = ZeroSmallComponents(overscroll_delta);
if (overscroll_delta.IsZero()) {
- if (initialized_) {
+ if (initialized_)
Release(current_time);
- UpdateLayerAttachment(overscrolling_layer);
- }
- return NeedsAnimate();
+ return CheckNeedsAnimate();
}
if (!InitializeIfNecessary())
@@ -142,45 +144,53 @@ bool OverscrollGlow::OnOverscrolled(cc::Layer* overscrolling_layer,
else
Pull(current_time, overscroll_delta, displacement);
- UpdateLayerAttachment(overscrolling_layer);
- return NeedsAnimate();
+ return CheckNeedsAnimate();
}
-bool OverscrollGlow::Animate(base::TimeTicks current_time) {
- if (!NeedsAnimate()) {
- Detach();
+bool OverscrollGlow::Animate(base::TimeTicks current_time,
+ cc::Layer* parent_layer) {
+ DCHECK(parent_layer);
+ if (!CheckNeedsAnimate())
return false;
- }
+
+ UpdateLayerAttachment(parent_layer);
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(
- ComputeSize(edge, display_params_.size),
- ComputeTransform(
- edge, display_params_.size, display_params_.edge_offsets[i]));
+ ComputeSize(edge, viewport_size_),
+ ComputeTransform(edge, viewport_size_, edge_offsets_[i]));
}
}
- if (!NeedsAnimate()) {
- Detach();
- return false;
- }
-
- return true;
+ return CheckNeedsAnimate();
}
-void OverscrollGlow::UpdateDisplayParameters(const DisplayParameters& params) {
- display_params_ = params;
+void OverscrollGlow::OnFrameUpdated(
+ const gfx::SizeF& viewport_size,
+ const gfx::SizeF& content_size,
+ const gfx::Vector2dF& content_scroll_offset) {
+ viewport_size_ = viewport_size;
+ edge_offsets_[OverscrollGlow::EDGE_TOP] = -content_scroll_offset.y();
+ edge_offsets_[OverscrollGlow::EDGE_LEFT] = -content_scroll_offset.x();
+ edge_offsets_[OverscrollGlow::EDGE_BOTTOM] = content_size.height() -
+ content_scroll_offset.y() -
+ viewport_size.height();
+ edge_offsets_[OverscrollGlow::EDGE_RIGHT] =
+ content_size.width() - content_scroll_offset.x() - viewport_size.width();
}
-bool OverscrollGlow::NeedsAnimate() const {
- if (!enabled_ || !initialized_)
+bool OverscrollGlow::CheckNeedsAnimate() {
+ if (!initialized_) {
+ Detach();
return false;
- for (size_t i = 0; i < EDGE_COUNT; ++i) {
- if (!edge_effects_[i]->IsFinished())
- return true;
}
+
+ if (IsActive())
+ return true;
+
+ Detach();
return false;
}
@@ -189,10 +199,8 @@ void OverscrollGlow::UpdateLayerAttachment(cc::Layer* parent) {
if (!root_layer_.get())
return;
- if (!NeedsAnimate()) {
- Detach();
+ if (!CheckNeedsAnimate())
return;
- }
if (root_layer_->parent() != parent)
parent->AddChild(root_layer_);
@@ -207,14 +215,13 @@ void OverscrollGlow::Detach() {
}
bool OverscrollGlow::InitializeIfNecessary() {
- DCHECK(enabled_);
if (initialized_)
return true;
DCHECK(!root_layer_.get());
root_layer_ = cc::Layer::Create();
for (size_t i = 0; i < EDGE_COUNT; ++i) {
- edge_effects_[i] = edge_effect_provider_.Run();
+ edge_effects_[i] = client_->CreateEdgeEffect();
DCHECK(edge_effects_[i]);
}
@@ -225,10 +232,11 @@ bool OverscrollGlow::InitializeIfNecessary() {
void OverscrollGlow::Pull(base::TimeTicks current_time,
const gfx::Vector2dF& overscroll_delta,
const gfx::Vector2dF& overscroll_location) {
- DCHECK(enabled_ && initialized_);
+ DCHECK(initialized_);
DCHECK(!overscroll_delta.IsZero());
- const float inv_width = 1.f / display_params_.size.width();
- const float inv_height = 1.f / display_params_.size.height();
+ DCHECK(!viewport_size_.IsEmpty());
+ const float inv_width = 1.f / viewport_size_.width();
+ const float inv_height = 1.f / viewport_size_.height();
gfx::Vector2dF overscroll_pull =
gfx::ScaleVector2d(overscroll_delta, inv_width, inv_height);
@@ -264,7 +272,7 @@ void OverscrollGlow::Absorb(base::TimeTicks current_time,
const gfx::Vector2dF& velocity,
bool x_overscroll_started,
bool y_overscroll_started) {
- DCHECK(enabled_ && initialized_);
+ DCHECK(initialized_);
DCHECK(!velocity.IsZero());
// Only trigger on initial overscroll at a non-zero velocity
@@ -295,8 +303,4 @@ EdgeEffectBase* OverscrollGlow::GetOppositeEdge(int edge_index) {
return edge_effects_[(edge_index + 2) % EDGE_COUNT].get();
}
-OverscrollGlow::DisplayParameters::DisplayParameters() {
- edge_offsets[0] = edge_offsets[1] = edge_offsets[2] = edge_offsets[3] = 0.f;
-}
-
} // namespace content
diff --git a/chromium/content/browser/android/overscroll_glow.h b/chromium/content/browser/android/overscroll_glow.h
index 878d39aec12..8fae95c4b86 100644
--- a/chromium/content/browser/android/overscroll_glow.h
+++ b/chromium/content/browser/android/overscroll_glow.h
@@ -5,12 +5,11 @@
#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 "ui/gfx/size_f.h"
-#include "ui/gfx/vector2d_f.h"
+#include "ui/gfx/geometry/size_f.h"
+#include "ui/gfx/geometry/vector2d_f.h"
namespace cc {
class Layer;
@@ -20,6 +19,15 @@ namespace content {
class EdgeEffectBase;
+// Provides lazy, customized EdgeEffect creation.
+class OverscrollGlowClient {
+ public:
+ virtual ~OverscrollGlowClient() {}
+
+ // Called lazily, after the initial overscrolling event.
+ virtual scoped_ptr<EdgeEffectBase> CreateEdgeEffect() = 0;
+};
+
/* |OverscrollGlow| mirrors its Android counterpart, OverscrollGlow.java.
* Conscious tradeoffs were made to align this as closely as possible with the
* original Android Java version.
@@ -28,54 +36,49 @@ class OverscrollGlow {
public:
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);
-
+ // |client| 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(OverscrollGlowClient* client);
~OverscrollGlow();
- // Enable the effect. If the effect was previously disabled, it will remain
- // dormant until subsequent calls to |OnOverscrolled()|.
- void Enable();
-
- // Deactivate and detach the effect. Subsequent calls to |OnOverscrolled()| or
- // |Animate()| will have no effect.
- void Disable();
-
- // Effect layers will be attached to |overscrolling_layer| if necessary.
+ // Called when the root content layer overscrolls.
// |accumulated_overscroll| and |overscroll_delta| are in device pixels, while
// |velocity| is in device pixels / second.
// Returns true if the effect still needs animation ticks.
- bool OnOverscrolled(cc::Layer* overscrolling_layer,
- base::TimeTicks current_time,
- gfx::Vector2dF accumulated_overscroll,
+ bool OnOverscrolled(base::TimeTicks current_time,
+ const gfx::Vector2dF& accumulated_overscroll,
gfx::Vector2dF overscroll_delta,
gfx::Vector2dF velocity,
- gfx::Vector2dF overscroll_location);
+ const gfx::Vector2dF& overscroll_location);
- // Returns true if the effect still needs animation ticks.
+ // Returns true if the effect still needs animation ticks, with effect layers
+ // attached to |parent_layer| if necessary.
// Note: The effect will detach itself when no further animation is required.
- bool Animate(base::TimeTicks current_time);
+ bool Animate(base::TimeTicks current_time, cc::Layer* parent_layer);
// Update the effect according to the most recent display parameters,
// Note: All dimensions are in device pixels.
- struct DisplayParameters {
- DisplayParameters();
- gfx::SizeF size;
- float edge_offsets[EDGE_COUNT];
- };
- void UpdateDisplayParameters(const DisplayParameters& params);
+ void OnFrameUpdated(const gfx::SizeF& viewport_size,
+ const gfx::SizeF& content_size,
+ const gfx::Vector2dF& content_scroll_offset);
+
+ // Reset the effect to its inactive state, clearing any active effects.
+ void Reset();
+
+ // Whether the effect is active, either being pulled or receding.
+ bool IsActive() const;
+
+ // The maximum alpha value (in the range [0,1]) of any animated edge layers.
+ // If the effect is inactive, this will be 0.
+ float GetVisibleAlpha() const;
private:
enum Axis { AXIS_X, AXIS_Y };
- // Returns whether the effect is initialized.
+ // Returns whether the effect has been properly initialized.
bool InitializeIfNecessary();
- bool NeedsAnimate() const;
+ bool CheckNeedsAnimate();
void UpdateLayerAttachment(cc::Layer* parent);
void Detach();
void Pull(base::TimeTicks current_time,
@@ -89,11 +92,11 @@ class OverscrollGlow {
EdgeEffectBase* GetOppositeEdge(int edge_index);
- EdgeEffectProvider edge_effect_provider_;
+ OverscrollGlowClient* const client_;
scoped_ptr<EdgeEffectBase> edge_effects_[EDGE_COUNT];
- DisplayParameters display_params_;
- bool enabled_;
+ gfx::SizeF viewport_size_;
+ float edge_offsets_[EDGE_COUNT];
bool initialized_;
scoped_refptr<cc::Layer> root_layer_;
@@ -103,4 +106,4 @@ class OverscrollGlow {
} // namespace content
-#endif // CONTENT_BROWSER_ANDROID_SCROLL_GLOW_H_
+#endif // CONTENT_BROWSER_ANDROID_OVERSCROLL_GLOW_H_
diff --git a/chromium/content/browser/android/overscroll_refresh.cc b/chromium/content/browser/android/overscroll_refresh.cc
new file mode 100644
index 00000000000..c2a1453bc17
--- /dev/null
+++ b/chromium/content/browser/android/overscroll_refresh.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/android/overscroll_refresh.h"
+
+#include "base/logging.h"
+
+namespace content {
+namespace {
+
+// Experimentally determined constant used to allow activation even if touch
+// release results in a small upward fling (quite common during a slow scroll).
+const float kMinFlingVelocityForActivation = -500.f;
+
+} // namespace
+
+OverscrollRefresh::OverscrollRefresh(OverscrollRefreshHandler* handler)
+ : scrolled_to_top_(true),
+ overflow_y_hidden_(false),
+ scroll_consumption_state_(DISABLED),
+ handler_(handler) {
+ DCHECK(handler);
+}
+
+OverscrollRefresh::~OverscrollRefresh() {
+}
+
+void OverscrollRefresh::Reset() {
+ scroll_consumption_state_ = DISABLED;
+ handler_->PullReset();
+}
+
+void OverscrollRefresh::OnScrollBegin() {
+ ReleaseWithoutActivation();
+ if (scrolled_to_top_ && !overflow_y_hidden_)
+ scroll_consumption_state_ = AWAITING_SCROLL_UPDATE_ACK;
+}
+
+void OverscrollRefresh::OnScrollEnd(const gfx::Vector2dF& scroll_velocity) {
+ bool allow_activation = scroll_velocity.y() > kMinFlingVelocityForActivation;
+ Release(allow_activation);
+}
+
+void OverscrollRefresh::OnScrollUpdateAck(bool was_consumed) {
+ if (scroll_consumption_state_ != AWAITING_SCROLL_UPDATE_ACK)
+ return;
+
+ if (was_consumed) {
+ scroll_consumption_state_ = DISABLED;
+ return;
+ }
+
+ scroll_consumption_state_ = handler_->PullStart() ? ENABLED : DISABLED;
+}
+
+bool OverscrollRefresh::WillHandleScrollUpdate(
+ const gfx::Vector2dF& scroll_delta) {
+ switch (scroll_consumption_state_) {
+ case DISABLED:
+ return false;
+
+ case AWAITING_SCROLL_UPDATE_ACK:
+ // If the initial scroll motion is downward, never allow activation.
+ if (scroll_delta.y() <= 0)
+ scroll_consumption_state_ = DISABLED;
+ return false;
+
+ case ENABLED:
+ handler_->PullUpdate(scroll_delta.y());
+ return true;
+ }
+
+ NOTREACHED() << "Invalid overscroll state: " << scroll_consumption_state_;
+ return false;
+}
+
+void OverscrollRefresh::ReleaseWithoutActivation() {
+ bool allow_activation = false;
+ Release(allow_activation);
+}
+
+bool OverscrollRefresh::IsActive() const {
+ return scroll_consumption_state_ == ENABLED;
+}
+
+bool OverscrollRefresh::IsAwaitingScrollUpdateAck() const {
+ return scroll_consumption_state_ == AWAITING_SCROLL_UPDATE_ACK;
+}
+
+void OverscrollRefresh::OnFrameUpdated(
+ const gfx::Vector2dF& content_scroll_offset,
+ bool root_overflow_y_hidden) {
+ scrolled_to_top_ = content_scroll_offset.y() == 0;
+ overflow_y_hidden_ = root_overflow_y_hidden;
+}
+
+void OverscrollRefresh::Release(bool allow_refresh) {
+ if (scroll_consumption_state_ == ENABLED)
+ handler_->PullRelease(allow_refresh);
+ scroll_consumption_state_ = DISABLED;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/android/overscroll_refresh.h b/chromium/content/browser/android/overscroll_refresh.h
new file mode 100644
index 00000000000..43ed0833258
--- /dev/null
+++ b/chromium/content/browser/android/overscroll_refresh.h
@@ -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.
+
+#ifndef CONTENT_BROWSER_ANDROID_OVERSCROLL_REFRESH_H_
+#define CONTENT_BROWSER_ANDROID_OVERSCROLL_REFRESH_H_
+
+#include "base/macros.h"
+#include "content/common/content_export.h"
+#include "ui/gfx/geometry/size_f.h"
+#include "ui/gfx/geometry/vector2d_f.h"
+
+namespace content {
+
+class CONTENT_EXPORT OverscrollRefreshHandler {
+ public:
+ // Signals the start of an overscrolling pull. Returns whether the handler
+ // will consume the overscroll gesture, in which case it will receive the
+ // remaining pull updates.
+ virtual bool PullStart() = 0;
+
+ // Signals a pull update, where |delta| is in device pixels.
+ virtual void PullUpdate(float delta) = 0;
+
+ // Signals the release of the pull, and whether the release is allowed to
+ // trigger the refresh action.
+ virtual void PullRelease(bool allow_refresh) = 0;
+
+ // Reset the active pull state.
+ virtual void PullReset() = 0;
+
+ protected:
+ virtual ~OverscrollRefreshHandler() {}
+};
+
+// Simple pull-to-refresh styled effect. Listens to scroll events, conditionally
+// activating when:
+// 1) The scroll begins when the page's root layer 1) has no vertical scroll
+// offset and 2) lacks the overflow-y:hidden property.
+// 2) The page doesn't consume the initial scroll events.
+// 3) The initial scroll direction is upward.
+// The actuall pull response, animation and action are delegated to the
+// provided refresh handler.
+class CONTENT_EXPORT OverscrollRefresh {
+ public:
+ // Minmum number of overscrolling pull events required to activate the effect.
+ // Useful for avoiding accidental triggering when a scroll janks (is delayed),
+ // capping the impulse per event.
+ enum { kMinPullsToActivate = 3 };
+
+ explicit OverscrollRefresh(OverscrollRefreshHandler* handler);
+ ~OverscrollRefresh();
+
+ // Scroll event stream listening methods.
+ void OnScrollBegin();
+ // Returns whether the refresh was activated.
+ void OnScrollEnd(const gfx::Vector2dF& velocity);
+
+ // Scroll ack listener. The effect will only be activated if the initial
+ // updates go unconsumed.
+ void OnScrollUpdateAck(bool was_consumed);
+
+ // Returns true if the effect has consumed the |scroll_delta|.
+ bool WillHandleScrollUpdate(const gfx::Vector2dF& scroll_delta);
+
+ // Release the effect (if active), preventing any associated refresh action.
+ void ReleaseWithoutActivation();
+
+ // Notify the effect of the latest scroll offset and overflow properties.
+ // The effect will be disabled when the offset is non-zero or overflow is
+ // hidden. Note: All dimensions are in device pixels.
+ void OnFrameUpdated(const gfx::Vector2dF& content_scroll_offset,
+ bool root_overflow_y_hidden);
+
+ // Reset the effect to its inactive state, immediately detaching and
+ // disabling any active effects.
+ void Reset();
+
+ // Returns true if the refresh effect is either being manipulated or animated.
+ bool IsActive() const;
+
+ // Returns true if the effect is waiting for an unconsumed scroll to start.
+ bool IsAwaitingScrollUpdateAck() const;
+
+ private:
+ void Release(bool allow_refresh);
+
+ bool scrolled_to_top_;
+ bool overflow_y_hidden_;
+
+ enum ScrollConsumptionState {
+ DISABLED,
+ AWAITING_SCROLL_UPDATE_ACK,
+ ENABLED,
+ } scroll_consumption_state_;
+
+ OverscrollRefreshHandler* const handler_;
+
+ DISALLOW_COPY_AND_ASSIGN(OverscrollRefresh);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_ANDROID_OVERSCROLL_REFRESH_H_
diff --git a/chromium/content/browser/android/overscroll_refresh_unittest.cc b/chromium/content/browser/android/overscroll_refresh_unittest.cc
new file mode 100644
index 00000000000..70ed0dbd510
--- /dev/null
+++ b/chromium/content/browser/android/overscroll_refresh_unittest.cc
@@ -0,0 +1,241 @@
+// Copyright 2014 The Chromium Authors. 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/layers/layer.h"
+#include "content/browser/android/overscroll_refresh.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+class OverscrollRefreshTest : public OverscrollRefreshHandler,
+ public testing::Test {
+ public:
+ OverscrollRefreshTest() {}
+
+ // OverscrollRefreshHandler implementation.
+ bool PullStart() override {
+ started_ = true;
+ return true;
+ }
+
+ void PullUpdate(float delta) override { delta_ += delta; }
+
+ void PullRelease(bool allow_refresh) override {
+ released_ = true;
+ refresh_allowed_ = allow_refresh;
+ }
+
+ void PullReset() override { reset_ = true; }
+
+ bool GetAndResetPullStarted() {
+ bool result = started_;
+ started_ = false;
+ return result;
+ }
+
+ float GetAndResetPullDelta() {
+ float result = delta_;
+ delta_ = 0;
+ return result;
+ }
+
+ bool GetAndResetPullReleased() {
+ bool result = released_;
+ released_ = false;
+ return result;
+ }
+
+ bool GetAndResetRefreshAllowed() {
+ bool result = refresh_allowed_;
+ refresh_allowed_ = false;
+ return result;
+ }
+
+ bool GetAndResetPullReset() {
+ bool result = reset_;
+ reset_ = false;
+ return result;
+ }
+
+ private:
+ float delta_ = 0;
+ bool started_ = false;
+ bool released_ = false;
+ bool reset_ = false;
+ bool refresh_allowed_ = false;
+};
+
+TEST_F(OverscrollRefreshTest, Basic) {
+ OverscrollRefresh effect(this);
+
+ EXPECT_FALSE(effect.IsActive());
+ EXPECT_FALSE(effect.IsAwaitingScrollUpdateAck());
+
+ effect.OnScrollBegin();
+ EXPECT_FALSE(effect.IsActive());
+ EXPECT_TRUE(effect.IsAwaitingScrollUpdateAck());
+
+ // The initial scroll should not be consumed, as it should first be offered
+ // to content.
+ gfx::Vector2dF scroll_up(0, 10);
+ EXPECT_FALSE(effect.WillHandleScrollUpdate(scroll_up));
+ EXPECT_FALSE(effect.IsActive());
+ EXPECT_TRUE(effect.IsAwaitingScrollUpdateAck());
+
+ // The unconsumed, overscrolling scroll will trigger the effect.
+ effect.OnScrollUpdateAck(false);
+ EXPECT_TRUE(effect.IsActive());
+ EXPECT_FALSE(effect.IsAwaitingScrollUpdateAck());
+ EXPECT_TRUE(GetAndResetPullStarted());
+
+ // Further scrolls will be consumed.
+ EXPECT_TRUE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 50)));
+ EXPECT_EQ(50.f, GetAndResetPullDelta());
+ EXPECT_TRUE(effect.IsActive());
+
+ // Even scrolls in the down direction should be consumed.
+ EXPECT_TRUE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, -50)));
+ EXPECT_EQ(-50.f, GetAndResetPullDelta());
+ EXPECT_TRUE(effect.IsActive());
+
+ // Ending the scroll while beyond the threshold should trigger a refresh.
+ gfx::Vector2dF zero_velocity;
+ EXPECT_FALSE(GetAndResetPullReleased());
+ effect.OnScrollEnd(zero_velocity);
+ EXPECT_FALSE(effect.IsActive());
+ EXPECT_TRUE(GetAndResetPullReleased());
+ EXPECT_TRUE(GetAndResetRefreshAllowed());
+}
+
+TEST_F(OverscrollRefreshTest, NotTriggeredIfInitialYOffsetIsNotZero) {
+ OverscrollRefresh effect(this);
+
+ // A positive y scroll offset at the start of scroll will prevent activation,
+ // even if the subsequent scroll overscrolls upward.
+ gfx::Vector2dF nonzero_offset(0, 10);
+ bool overflow_y_hidden = false;
+ effect.OnFrameUpdated(nonzero_offset, overflow_y_hidden);
+ effect.OnScrollBegin();
+
+ effect.OnFrameUpdated(gfx::Vector2dF(), overflow_y_hidden);
+ ASSERT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 10)));
+ EXPECT_FALSE(effect.IsActive());
+ EXPECT_FALSE(effect.IsAwaitingScrollUpdateAck());
+ effect.OnScrollUpdateAck(false);
+ EXPECT_FALSE(effect.IsActive());
+ EXPECT_FALSE(effect.IsAwaitingScrollUpdateAck());
+ EXPECT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 500)));
+ effect.OnScrollEnd(gfx::Vector2dF());
+ EXPECT_FALSE(GetAndResetPullStarted());
+ EXPECT_FALSE(GetAndResetPullReleased());
+}
+
+TEST_F(OverscrollRefreshTest, NotTriggeredIfOverflowYHidden) {
+ OverscrollRefresh effect(this);
+
+ // overflow-y:hidden at the start of scroll will prevent activation.
+ gfx::Vector2dF zero_offset;
+ bool overflow_y_hidden = true;
+ effect.OnFrameUpdated(zero_offset, overflow_y_hidden);
+ effect.OnScrollBegin();
+
+ ASSERT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 10)));
+ EXPECT_FALSE(effect.IsActive());
+ EXPECT_FALSE(effect.IsAwaitingScrollUpdateAck());
+ effect.OnScrollUpdateAck(false);
+ EXPECT_FALSE(effect.IsActive());
+ EXPECT_FALSE(effect.IsAwaitingScrollUpdateAck());
+ EXPECT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 500)));
+ effect.OnScrollEnd(gfx::Vector2dF());
+ EXPECT_FALSE(GetAndResetPullStarted());
+ EXPECT_FALSE(GetAndResetPullReleased());
+}
+
+TEST_F(OverscrollRefreshTest, NotTriggeredIfInitialScrollDownward) {
+ OverscrollRefresh effect(this);
+ effect.OnScrollBegin();
+
+ // A downward initial scroll will prevent activation, even if the subsequent
+ // scroll overscrolls upward.
+ ASSERT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, -10)));
+ EXPECT_FALSE(effect.IsActive());
+ EXPECT_FALSE(effect.IsAwaitingScrollUpdateAck());
+
+ effect.OnScrollUpdateAck(false);
+ EXPECT_FALSE(effect.IsActive());
+ EXPECT_FALSE(effect.IsAwaitingScrollUpdateAck());
+ EXPECT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 500)));
+ effect.OnScrollEnd(gfx::Vector2dF());
+ EXPECT_FALSE(GetAndResetPullReleased());
+}
+
+TEST_F(OverscrollRefreshTest, NotTriggeredIfInitialScrollOrTouchConsumed) {
+ OverscrollRefresh effect(this);
+ effect.OnScrollBegin();
+ ASSERT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 10)));
+ ASSERT_TRUE(effect.IsAwaitingScrollUpdateAck());
+
+ // Consumption of the initial touchmove or scroll should prevent future
+ // activation.
+ effect.OnScrollUpdateAck(true);
+ EXPECT_FALSE(effect.IsActive());
+ EXPECT_FALSE(effect.IsAwaitingScrollUpdateAck());
+ EXPECT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 500)));
+ effect.OnScrollUpdateAck(false);
+ EXPECT_FALSE(effect.IsActive());
+ EXPECT_FALSE(effect.IsAwaitingScrollUpdateAck());
+ EXPECT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 500)));
+ effect.OnScrollEnd(gfx::Vector2dF());
+ EXPECT_FALSE(GetAndResetPullStarted());
+ EXPECT_FALSE(GetAndResetPullReleased());
+}
+
+TEST_F(OverscrollRefreshTest, NotTriggeredIfFlungDownward) {
+ OverscrollRefresh effect(this);
+ effect.OnScrollBegin();
+ ASSERT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 10)));
+ ASSERT_TRUE(effect.IsAwaitingScrollUpdateAck());
+ effect.OnScrollUpdateAck(false);
+ ASSERT_TRUE(effect.IsActive());
+ EXPECT_TRUE(GetAndResetPullStarted());
+
+ // Terminating the pull with a down-directed fling should prevent triggering.
+ effect.OnScrollEnd(gfx::Vector2dF(0, -1000));
+ EXPECT_TRUE(GetAndResetPullReleased());
+ EXPECT_FALSE(GetAndResetRefreshAllowed());
+}
+
+TEST_F(OverscrollRefreshTest, NotTriggeredIfReleasedWithoutActivation) {
+ OverscrollRefresh effect(this);
+ effect.OnScrollBegin();
+ ASSERT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 10)));
+ ASSERT_TRUE(effect.IsAwaitingScrollUpdateAck());
+ effect.OnScrollUpdateAck(false);
+ ASSERT_TRUE(effect.IsActive());
+ EXPECT_TRUE(GetAndResetPullStarted());
+
+ // An early release should prevent the refresh action from firing.
+ effect.ReleaseWithoutActivation();
+ effect.OnScrollEnd(gfx::Vector2dF());
+ EXPECT_TRUE(GetAndResetPullReleased());
+ EXPECT_FALSE(GetAndResetRefreshAllowed());
+}
+
+TEST_F(OverscrollRefreshTest, NotTriggeredIfReset) {
+ OverscrollRefresh effect(this);
+ effect.OnScrollBegin();
+ ASSERT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 10)));
+ ASSERT_TRUE(effect.IsAwaitingScrollUpdateAck());
+ effect.OnScrollUpdateAck(false);
+ ASSERT_TRUE(effect.IsActive());
+ EXPECT_TRUE(GetAndResetPullStarted());
+
+ // An early reset should prevent the refresh action from firing.
+ effect.Reset();
+ EXPECT_TRUE(GetAndResetPullReset());
+ effect.OnScrollEnd(gfx::Vector2dF());
+ EXPECT_FALSE(GetAndResetPullReleased());
+}
+
+} // namespace content
diff --git a/chromium/content/browser/android/popup_touch_handle_drawable.cc b/chromium/content/browser/android/popup_touch_handle_drawable.cc
index 8a7cf845f70..aef23f8fb0f 100644
--- a/chromium/content/browser/android/popup_touch_handle_drawable.cc
+++ b/chromium/content/browser/android/popup_touch_handle_drawable.cc
@@ -30,30 +30,17 @@ void PopupTouchHandleDrawable::SetEnabled(bool enabled) {
}
void PopupTouchHandleDrawable::SetOrientation(
- TouchHandleOrientation orientation) {
+ ui::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.";
- };
+ Java_PopupTouchHandleDrawable_setOrientation(env, obj,
+ static_cast<int>(orientation));
}
void PopupTouchHandleDrawable::SetAlpha(float alpha) {
JNIEnv* env = base::android::AttachCurrentThread();
- Java_PopupTouchHandleDrawable_setOpacity(env, drawable_.obj(), alpha);
+ bool visible = alpha > 0;
+ Java_PopupTouchHandleDrawable_setVisible(env, drawable_.obj(), visible);
}
void PopupTouchHandleDrawable::SetFocus(const gfx::PointF& position) {
@@ -63,20 +50,14 @@ void PopupTouchHandleDrawable::SetFocus(const gfx::PointF& position) {
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_);
+gfx::RectF PopupTouchHandleDrawable::GetVisibleBounds() const {
JNIEnv* env = base::android::AttachCurrentThread();
- return Java_PopupTouchHandleDrawable_intersectsWith(env,
- drawable_.obj(),
- rect_pix.x(),
- rect_pix.y(),
- rect_pix.width(),
- rect_pix.height());
+ gfx::RectF unscaled_rect(
+ Java_PopupTouchHandleDrawable_getPositionX(env, drawable_.obj()),
+ Java_PopupTouchHandleDrawable_getPositionY(env, drawable_.obj()),
+ Java_PopupTouchHandleDrawable_getVisibleWidth(env, drawable_.obj()),
+ Java_PopupTouchHandleDrawable_getVisibleHeight(env, drawable_.obj()));
+ return gfx::ScaleRect(unscaled_rect, 1.f / dpi_scale_);
}
// static
diff --git a/chromium/content/browser/android/popup_touch_handle_drawable.h b/chromium/content/browser/android/popup_touch_handle_drawable.h
index 0e1a8ea4d1c..5b5c334e8a5 100644
--- a/chromium/content/browser/android/popup_touch_handle_drawable.h
+++ b/chromium/content/browser/android/popup_touch_handle_drawable.h
@@ -5,26 +5,25 @@
#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 "ui/touch_selection/touch_handle.h"
#include "base/android/jni_android.h"
namespace content {
// Touch handle drawable backed by an Android PopupWindow.
-class PopupTouchHandleDrawable : public TouchHandleDrawable {
+class PopupTouchHandleDrawable : public ui::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;
+ ~PopupTouchHandleDrawable() override;
+
+ // ui::TouchHandleDrawable implementation.
+ void SetEnabled(bool enabled) override;
+ void SetOrientation(ui::TouchHandleOrientation orientation) override;
+ void SetAlpha(float alpha) override;
+ void SetFocus(const gfx::PointF& position) override;
+ gfx::RectF GetVisibleBounds() const override;
static bool RegisterPopupTouchHandleDrawable(JNIEnv* env);
diff --git a/chromium/content/browser/android/system_ui_resource_manager_impl.cc b/chromium/content/browser/android/system_ui_resource_manager_impl.cc
deleted file mode 100644
index 57ef6f2055d..00000000000
--- a/chromium/content/browser/android/system_ui_resource_manager_impl.cc
+++ /dev/null
@@ -1,178 +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/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
deleted file mode 100644
index 54b2bd39d95..00000000000
--- a/chromium/content/browser/android/system_ui_resource_manager_impl.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_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
deleted file mode 100644
index 5ab07fc3aa1..00000000000
--- a/chromium/content/browser/android/system_ui_resource_manager_impl_unittest.cc
+++ /dev/null
@@ -1,169 +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 "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 4c40bb74297..6953a0de5f8 100644
--- a/chromium/content/browser/android/tracing_controller_android.cc
+++ b/chromium/content/browser/android/tracing_controller_android.cc
@@ -6,9 +6,9 @@
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
-#include "base/debug/trace_event.h"
#include "base/json/json_writer.h"
#include "base/logging.h"
+#include "base/trace_event/trace_event.h"
#include "content/public/browser/tracing_controller.h"
#include "jni/TracingControllerAndroid_jni.h"
@@ -35,7 +35,7 @@ bool TracingControllerAndroid::StartTracing(JNIEnv* env,
jstring jtraceoptions) {
std::string categories =
base::android::ConvertJavaStringToUTF8(env, jcategories);
- base::debug::TraceOptions trace_options;
+ base::trace_event::TraceOptions trace_options;
trace_options.SetFromString(
base::android::ConvertJavaStringToUTF8(env, jtraceoptions));
@@ -43,7 +43,7 @@ bool TracingControllerAndroid::StartTracing(JNIEnv* env,
LOG(WARNING) << "Logging performance trace to file";
return TracingController::GetInstance()->EnableRecording(
- base::debug::CategoryFilter(categories),
+ base::trace_event::CategoryFilter(categories),
trace_options,
TracingController::EnableRecordingDoneCallback());
}
@@ -105,8 +105,10 @@ void TracingControllerAndroid::OnKnownCategoriesReceived(
}
static jstring GetDefaultCategories(JNIEnv* env, jobject obj) {
- return base::android::ConvertUTF8ToJavaString(env,
- base::debug::CategoryFilter::kDefaultCategoryFilterString).Release();
+ return base::android::ConvertUTF8ToJavaString(
+ env,
+ base::trace_event::CategoryFilter::kDefaultCategoryFilterString)
+ .Release();
}
bool RegisterTracingControllerAndroid(JNIEnv* env) {
diff --git a/chromium/content/browser/android/ui_resource_provider_impl.cc b/chromium/content/browser/android/ui_resource_provider_impl.cc
deleted file mode 100644
index cd45d7cc634..00000000000
--- a/chromium/content/browser/android/ui_resource_provider_impl.cc
+++ /dev/null
@@ -1,72 +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/android/ui_resource_provider_impl.h"
-
-#include "cc/resources/ui_resource_client.h"
-#include "cc/trees/layer_tree_host.h"
-#include "content/public/browser/android/ui_resource_client_android.h"
-
-namespace content {
-
-UIResourceProviderImpl::UIResourceProviderImpl()
- : system_ui_resource_manager_(this), host_(NULL),
- supports_etc1_npot_(false) {
-
-}
-
-UIResourceProviderImpl::~UIResourceProviderImpl() {
- SetLayerTreeHost(NULL);
-}
-
-void UIResourceProviderImpl::SetLayerTreeHost(cc::LayerTreeHost* host) {
- if (host_ == host)
- return;
- host_ = host;
- UIResourcesAreInvalid();
-}
-
-void UIResourceProviderImpl::UIResourcesAreInvalid() {
- 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();
- }
-}
-
-cc::UIResourceId UIResourceProviderImpl::CreateUIResource(
- UIResourceClientAndroid* client) {
- if (!host_)
- return 0;
- cc::UIResourceId id = host_->CreateUIResource(client);
- DCHECK(ui_resource_client_map_.find(id) == ui_resource_client_map_.end());
-
- ui_resource_client_map_[id] = client;
- return id;
-}
-
-void UIResourceProviderImpl::DeleteUIResource(cc::UIResourceId ui_resource_id) {
- UIResourceClientMap::iterator iter =
- ui_resource_client_map_.find(ui_resource_id);
- DCHECK(iter != ui_resource_client_map_.end());
-
- ui_resource_client_map_.erase(iter);
-
- if (!host_)
- return;
- 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
deleted file mode 100644
index 1c29a3ed117..00000000000
--- a/chromium/content/browser/android/ui_resource_provider_impl.h
+++ /dev/null
@@ -1,55 +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_ANDROID_UI_RESOURCE_PROVIDER_IMPL_H_
-#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 {
-class LayerTreeHost;
-}
-
-namespace content {
-
-class UIResourceClientAndroid;
-
-class UIResourceProviderImpl : public UIResourceProvider {
- public:
- UIResourceProviderImpl();
-
- virtual ~UIResourceProviderImpl();
-
- void SetLayerTreeHost(cc::LayerTreeHost* host);
-
- void UIResourcesAreInvalid();
-
- virtual cc::UIResourceId CreateUIResource(
- UIResourceClientAndroid* client) 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);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_ANDROID_UI_RESOURCE_PROVIDER_IMPL_H_
diff --git a/chromium/content/browser/android/url_request_content_job.cc b/chromium/content/browser/android/url_request_content_job.cc
new file mode 100644
index 00000000000..0ba13e0df50
--- /dev/null
+++ b/chromium/content/browser/android/url_request_content_job.cc
@@ -0,0 +1,228 @@
+// 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/android/url_request_content_job.h"
+
+#include "base/android/content_uri_utils.h"
+#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/task_runner.h"
+#include "net/base/file_stream.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/http/http_util.h"
+#include "net/url_request/url_request_error_job.h"
+#include "url/gurl.h"
+
+namespace content {
+
+// TODO(qinmin): Refactor this class to reuse the common code in
+// url_request_file_job.cc.
+URLRequestContentJob::ContentMetaInfo::ContentMetaInfo()
+ : content_exists(false),
+ content_size(0) {
+}
+
+URLRequestContentJob::URLRequestContentJob(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate,
+ const base::FilePath& content_path,
+ const scoped_refptr<base::TaskRunner>& content_task_runner)
+ : net::URLRequestJob(request, network_delegate),
+ content_path_(content_path),
+ stream_(new net::FileStream(content_task_runner)),
+ content_task_runner_(content_task_runner),
+ remaining_bytes_(0),
+ io_pending_(false),
+ weak_ptr_factory_(this) {}
+
+void URLRequestContentJob::Start() {
+ ContentMetaInfo* meta_info = new ContentMetaInfo();
+ content_task_runner_->PostTaskAndReply(
+ FROM_HERE,
+ base::Bind(&URLRequestContentJob::FetchMetaInfo, content_path_,
+ base::Unretained(meta_info)),
+ base::Bind(&URLRequestContentJob::DidFetchMetaInfo,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::Owned(meta_info)));
+}
+
+void URLRequestContentJob::Kill() {
+ stream_.reset();
+ weak_ptr_factory_.InvalidateWeakPtrs();
+
+ net::URLRequestJob::Kill();
+}
+
+bool URLRequestContentJob::ReadRawData(net::IOBuffer* dest,
+ int dest_size,
+ int* bytes_read) {
+ DCHECK_GT(dest_size, 0);
+ DCHECK(bytes_read);
+ DCHECK_GE(remaining_bytes_, 0);
+
+ if (remaining_bytes_ < dest_size)
+ dest_size = static_cast<int>(remaining_bytes_);
+
+ // If we should copy zero bytes because |remaining_bytes_| is zero, short
+ // circuit here.
+ if (!dest_size) {
+ *bytes_read = 0;
+ return true;
+ }
+
+ int rv = stream_->Read(dest,
+ dest_size,
+ base::Bind(&URLRequestContentJob::DidRead,
+ weak_ptr_factory_.GetWeakPtr(),
+ make_scoped_refptr(dest)));
+ if (rv >= 0) {
+ // Data is immediately available.
+ *bytes_read = rv;
+ remaining_bytes_ -= rv;
+ DCHECK_GE(remaining_bytes_, 0);
+ return true;
+ }
+
+ // Otherwise, a read error occured. We may just need to wait...
+ if (rv == net::ERR_IO_PENDING) {
+ io_pending_ = true;
+ SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
+ } else {
+ NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, rv));
+ }
+ return false;
+}
+
+bool URLRequestContentJob::IsRedirectResponse(GURL* location,
+ int* http_status_code) {
+ return false;
+}
+
+bool URLRequestContentJob::GetMimeType(std::string* mime_type) const {
+ DCHECK(request_);
+ if (!meta_info_.mime_type.empty()) {
+ *mime_type = meta_info_.mime_type;
+ return true;
+ }
+ return false;
+}
+
+void URLRequestContentJob::SetExtraRequestHeaders(
+ const net::HttpRequestHeaders& headers) {
+ std::string range_header;
+ if (!headers.GetHeader(net::HttpRequestHeaders::kRange, &range_header))
+ return;
+
+ // We only care about "Range" header here.
+ std::vector<net::HttpByteRange> ranges;
+ if (net::HttpUtil::ParseRangeHeader(range_header, &ranges)) {
+ if (ranges.size() == 1) {
+ byte_range_ = ranges[0];
+ } else {
+ // We don't support multiple range requests.
+ NotifyDone(net::URLRequestStatus(
+ net::URLRequestStatus::FAILED,
+ net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
+ }
+ }
+}
+
+URLRequestContentJob::~URLRequestContentJob() {}
+
+void URLRequestContentJob::FetchMetaInfo(const base::FilePath& content_path,
+ ContentMetaInfo* meta_info) {
+ base::File::Info file_info;
+ meta_info->content_exists = base::GetFileInfo(content_path, &file_info);
+ if (meta_info->content_exists) {
+ meta_info->content_size = file_info.size;
+ meta_info->mime_type = base::GetContentUriMimeType(content_path);
+ }
+}
+
+void URLRequestContentJob::DidFetchMetaInfo(const ContentMetaInfo* meta_info) {
+ meta_info_ = *meta_info;
+
+ if (!meta_info_.content_exists) {
+ DidOpen(net::ERR_FILE_NOT_FOUND);
+ return;
+ }
+
+ int flags = base::File::FLAG_OPEN |
+ base::File::FLAG_READ |
+ base::File::FLAG_ASYNC;
+ int rv = stream_->Open(content_path_, flags,
+ base::Bind(&URLRequestContentJob::DidOpen,
+ weak_ptr_factory_.GetWeakPtr()));
+ if (rv != net::ERR_IO_PENDING)
+ DidOpen(rv);
+}
+
+void URLRequestContentJob::DidOpen(int result) {
+ if (result != net::OK) {
+ NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
+ return;
+ }
+
+ if (!byte_range_.ComputeBounds(meta_info_.content_size)) {
+ NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
+ net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
+ return;
+ }
+
+ remaining_bytes_ = byte_range_.last_byte_position() -
+ byte_range_.first_byte_position() + 1;
+ DCHECK_GE(remaining_bytes_, 0);
+
+ if (remaining_bytes_ > 0 && byte_range_.first_byte_position() != 0) {
+ int rv = stream_->Seek(base::File::FROM_BEGIN,
+ byte_range_.first_byte_position(),
+ base::Bind(&URLRequestContentJob::DidSeek,
+ weak_ptr_factory_.GetWeakPtr()));
+ if (rv != net::ERR_IO_PENDING) {
+ // stream_->Seek() failed, so pass an intentionally erroneous value
+ // into DidSeek().
+ DidSeek(-1);
+ }
+ } else {
+ // We didn't need to call stream_->Seek() at all, so we pass to DidSeek()
+ // the value that would mean seek success. This way we skip the code
+ // handling seek failure.
+ DidSeek(byte_range_.first_byte_position());
+ }
+}
+
+void URLRequestContentJob::DidSeek(int64 result) {
+ if (result != byte_range_.first_byte_position()) {
+ NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
+ net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
+ return;
+ }
+
+ set_expected_content_size(remaining_bytes_);
+ NotifyHeadersComplete();
+}
+
+void URLRequestContentJob::DidRead(
+ scoped_refptr<net::IOBuffer> buf, int result) {
+ if (result > 0) {
+ SetStatus(net::URLRequestStatus()); // Clear the IO_PENDING status
+ remaining_bytes_ -= result;
+ DCHECK_GE(remaining_bytes_, 0);
+ }
+
+ DCHECK(io_pending_);
+ io_pending_ = false;
+
+ if (result == 0) {
+ NotifyDone(net::URLRequestStatus());
+ } else if (result < 0) {
+ NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
+ }
+
+ NotifyReadComplete(result);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/android/url_request_content_job.h b/chromium/content/browser/android/url_request_content_job.h
new file mode 100644
index 00000000000..5d3d9336acc
--- /dev/null
+++ b/chromium/content/browser/android/url_request_content_job.h
@@ -0,0 +1,103 @@
+// 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_ANDROID_URL_REQUEST_CONTENT_JOB_H_
+#define CONTENT_BROWSER_ANDROID_URL_REQUEST_CONTENT_JOB_H_
+
+#include <string>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "content/common/content_export.h"
+#include "net/http/http_byte_range.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_job.h"
+
+namespace base {
+class TaskRunner;
+}
+
+namespace file_util {
+struct FileInfo;
+}
+
+namespace net {
+class FileStream;
+}
+
+namespace content {
+
+// A request job that handles reading content URIs
+class CONTENT_EXPORT URLRequestContentJob : public net::URLRequestJob {
+ public:
+ URLRequestContentJob(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate,
+ const base::FilePath& content_path,
+ const scoped_refptr<base::TaskRunner>& content_task_runner);
+
+ // net::URLRequestJob:
+ void Start() override;
+ void Kill() override;
+ bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read) override;
+ bool IsRedirectResponse(GURL* location, int* http_status_code) override;
+ bool GetMimeType(std::string* mime_type) const override;
+ void SetExtraRequestHeaders(const net::HttpRequestHeaders& headers) override;
+
+ protected:
+ ~URLRequestContentJob() override;
+
+ private:
+ // Meta information about the content URI. It's used as a member in the
+ // URLRequestContentJob and also passed between threads because disk access is
+ // necessary to obtain it.
+ struct ContentMetaInfo {
+ ContentMetaInfo();
+ // Flag showing whether the content URI exists.
+ bool content_exists;
+ // Size of the content URI.
+ int64 content_size;
+ // Mime type associated with the content URI.
+ std::string mime_type;
+ };
+
+ // Fetches content URI info on a background thread.
+ static void FetchMetaInfo(const base::FilePath& content_path,
+ ContentMetaInfo* meta_info);
+
+ // Callback after fetching content URI info on a background thread.
+ void DidFetchMetaInfo(const ContentMetaInfo* meta_info);
+
+ // Callback after opening content URI on a background thread.
+ void DidOpen(int result);
+
+ // Callback after seeking to the beginning of |byte_range_| in the content URI
+ // on a background thread.
+ void DidSeek(int64 result);
+
+ // Callback after data is asynchronously read from the content URI into |buf|.
+ void DidRead(scoped_refptr<net::IOBuffer> buf, int result);
+
+ // The full path of the content URI.
+ base::FilePath content_path_;
+
+ scoped_ptr<net::FileStream> stream_;
+ ContentMetaInfo meta_info_;
+ const scoped_refptr<base::TaskRunner> content_task_runner_;
+
+ net::HttpByteRange byte_range_;
+ int64 remaining_bytes_;
+
+ bool io_pending_;
+
+ base::WeakPtrFactory<URLRequestContentJob> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(URLRequestContentJob);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_ANDROID_URL_REQUEST_CONTENT_JOB_H_
diff --git a/chromium/content/browser/android/url_request_content_job_unittest.cc b/chromium/content/browser/android/url_request_content_job_unittest.cc
new file mode 100644
index 00000000000..028a864968a
--- /dev/null
+++ b/chromium/content/browser/android/url_request_content_job_unittest.cc
@@ -0,0 +1,198 @@
+// Copyright 2014 The Chromium Authors. 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/url_request_content_job.h"
+
+#include <algorithm>
+
+#include "base/files/file_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/run_loop.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/test_file_util.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+
+namespace content {
+
+namespace {
+
+// A URLRequestJobFactory that will return URLRequestContentJobWithCallbacks
+// instances for content:// scheme URLs.
+class CallbacksJobFactory : public net::URLRequestJobFactory {
+ public:
+ class JobObserver {
+ public:
+ virtual void OnJobCreated(URLRequestContentJob* job) = 0;
+ };
+
+ CallbacksJobFactory(const base::FilePath& path, JobObserver* observer)
+ : path_(path), observer_(observer) {
+ }
+
+ ~CallbacksJobFactory() override {}
+
+ net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
+ const std::string& scheme,
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) const override {
+ URLRequestContentJob* job =
+ new URLRequestContentJob(
+ request,
+ network_delegate,
+ path_,
+ const_cast<base::MessageLoop*>(&message_loop_)->task_runner());
+ observer_->OnJobCreated(job);
+ return job;
+ }
+
+ 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 == "content";
+ }
+
+ bool IsHandledURL(const GURL& url) const override {
+ return IsHandledProtocol(url.scheme());
+ }
+
+ bool IsSafeRedirectTarget(const GURL& location) const override {
+ return false;
+ }
+
+ private:
+ base::MessageLoop message_loop_;
+ base::FilePath path_;
+ JobObserver* observer_;
+};
+
+class JobObserverImpl : public CallbacksJobFactory::JobObserver {
+ public:
+ void OnJobCreated(URLRequestContentJob* job) override {
+ jobs_.push_back(job);
+ }
+
+ typedef std::vector<scoped_refptr<URLRequestContentJob> > JobList;
+
+ const JobList& jobs() { return jobs_; }
+
+ protected:
+ JobList jobs_;
+};
+
+// A simple holder for start/end used in http range requests.
+struct Range {
+ int start;
+ int end;
+
+ explicit Range(int start, int end) {
+ this->start = start;
+ this->end = end;
+ }
+};
+
+// A superclass for tests of the OnSeekComplete / OnReadComplete functions of
+// URLRequestContentJob.
+class URLRequestContentJobTest : public testing::Test {
+ public:
+ URLRequestContentJobTest();
+
+ protected:
+ // This inserts an image file into the android MediaStore and retrieves the
+ // content URI. Then creates and runs a URLRequestContentJob to get the
+ // contents out of it. If a Range is provided, this function will add the
+ // appropriate Range http header to the request and verify the bytes
+ // retrieved.
+ void RunRequest(const Range* range);
+
+ JobObserverImpl observer_;
+ net::TestURLRequestContext context_;
+ net::TestDelegate delegate_;
+};
+
+URLRequestContentJobTest::URLRequestContentJobTest() {}
+
+void URLRequestContentJobTest::RunRequest(const Range* range) {
+ base::FilePath test_dir;
+ PathService::Get(base::DIR_SOURCE_ROOT, &test_dir);
+ test_dir = test_dir.AppendASCII("content");
+ test_dir = test_dir.AppendASCII("test");
+ test_dir = test_dir.AppendASCII("data");
+ test_dir = test_dir.AppendASCII("android");
+ ASSERT_TRUE(base::PathExists(test_dir));
+ base::FilePath image_file = test_dir.Append(FILE_PATH_LITERAL("red.png"));
+
+ // Insert the image into MediaStore. MediaStore will do some conversions, and
+ // return the content URI.
+ base::FilePath path = base::InsertImageIntoMediaStore(image_file);
+ EXPECT_TRUE(path.IsContentUri());
+ EXPECT_TRUE(base::PathExists(path));
+ int64 file_size;
+ EXPECT_TRUE(base::GetFileSize(path, &file_size));
+ EXPECT_LT(0, file_size);
+ CallbacksJobFactory factory(path, &observer_);
+ context_.set_job_factory(&factory);
+
+ scoped_ptr<net::URLRequest> request(context_.CreateRequest(
+ GURL(path.value()), net::DEFAULT_PRIORITY, &delegate_));
+ int expected_length = file_size;
+ if (range) {
+ ASSERT_GE(range->start, 0);
+ ASSERT_GE(range->end, 0);
+ ASSERT_LE(range->start, range->end);
+ std::string range_value =
+ base::StringPrintf("bytes=%d-%d", range->start, range->end);
+ request->SetExtraRequestHeaderByName(
+ net::HttpRequestHeaders::kRange, range_value, true /*overwrite*/);
+ if (range->start <= file_size)
+ expected_length =
+ std::min(range->end, (int) (file_size - 1)) - range->start + 1;
+ else
+ expected_length = 0;
+ }
+ request->Start();
+
+ base::RunLoop loop;
+ loop.Run();
+
+ EXPECT_FALSE(delegate_.request_failed());
+ ASSERT_EQ(observer_.jobs().size(), 1u);
+ EXPECT_EQ(delegate_.bytes_received(), expected_length);
+}
+
+TEST_F(URLRequestContentJobTest, ContentURIWithoutRange) {
+ RunRequest(NULL);
+}
+
+TEST_F(URLRequestContentJobTest, ContentURIWithSmallRange) {
+ Range range(1, 10);
+ RunRequest(&range);
+}
+
+TEST_F(URLRequestContentJobTest, ContentURIWithLargeRange) {
+ Range range(1, 100000);
+ RunRequest(&range);
+}
+
+TEST_F(URLRequestContentJobTest, ContentURIWithZeroRange) {
+ Range range(0, 0);
+ RunRequest(&range);
+}
+
+} // namespace
+
+} // namespace content
diff --git a/chromium/content/browser/android/web_contents_observer_android.cc b/chromium/content/browser/android/web_contents_observer_android.cc
deleted file mode 100644
index acadf8d85a3..00000000000
--- a/chromium/content/browser/android/web_contents_observer_android.cc
+++ /dev/null
@@ -1,325 +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/web_contents_observer_android.h"
-
-#include <string>
-
-#include <jni.h>
-
-#include "base/android/jni_android.h"
-#include "base/android/jni_string.h"
-#include "base/android/scoped_java_ref.h"
-#include "content/browser/renderer_host/render_widget_host_impl.h"
-#include "content/browser/web_contents/web_contents_impl.h"
-#include "content/public/browser/navigation_details.h"
-#include "content/public/browser/navigation_entry.h"
-#include "jni/WebContentsObserver_jni.h"
-
-using base::android::AttachCurrentThread;
-using base::android::ScopedJavaLocalRef;
-using base::android::ConvertUTF8ToJavaString;
-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,
- WebContents* web_contents)
- : WebContentsObserver(web_contents),
- weak_java_observer_(env, obj){
-}
-
-WebContentsObserverAndroid::~WebContentsObserverAndroid() {
-}
-
-jlong Init(JNIEnv* env, jobject obj, jobject java_web_contents) {
- WebContents* web_contents =
- WebContents::FromJavaWebContents(java_web_contents);
- CHECK(web_contents);
-
- WebContentsObserverAndroid* native_observer = new WebContentsObserverAndroid(
- env, obj, web_contents);
- return reinterpret_cast<intptr_t>(native_observer);
-}
-
-void WebContentsObserverAndroid::Destroy(JNIEnv* env, jobject obj) {
- delete this;
-}
-
-void WebContentsObserverAndroid::WebContentsDestroyed() {
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
- if (obj.is_null()) {
- delete this;
- } else {
- // The java side will destroy |this|
- Java_WebContentsObserver_detachFromWebContents(env, obj.obj());
- }
-}
-
-void WebContentsObserverAndroid::RenderProcessGone(
- base::TerminationStatus termination_status) {
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
- if (obj.is_null())
- return;
- jboolean was_oom_protected =
- termination_status == base::TERMINATION_STATUS_OOM_PROTECTED;
- Java_WebContentsObserver_renderProcessGone(
- env, obj.obj(), was_oom_protected);
-}
-
-void WebContentsObserverAndroid::DidStartLoading(
- RenderViewHost* render_view_host) {
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
- if (obj.is_null())
- return;
- ScopedJavaLocalRef<jstring> jstring_url(ConvertUTF8ToJavaString(
- env, web_contents()->GetVisibleURL().spec()));
- Java_WebContentsObserver_didStartLoading(
- env, obj.obj(), jstring_url.obj());
-}
-
-void WebContentsObserverAndroid::DidStopLoading(
- RenderViewHost* render_view_host) {
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
- if (obj.is_null())
- return;
- ScopedJavaLocalRef<jstring> jstring_url(ConvertUTF8ToJavaString(
- env, web_contents()->GetLastCommittedURL().spec()));
- Java_WebContentsObserver_didStopLoading(
- env, obj.obj(), jstring_url.obj());
-}
-
-void WebContentsObserverAndroid::DidFailProvisionalLoad(
- RenderFrameHost* render_frame_host,
- const GURL& validated_url,
- int error_code,
- const base::string16& error_description) {
- DidFailLoadInternal(true,
- !render_frame_host->GetParent(),
- error_code,
- error_description,
- validated_url);
-}
-
-void WebContentsObserverAndroid::DidFailLoad(
- RenderFrameHost* render_frame_host,
- const GURL& validated_url,
- int error_code,
- const base::string16& error_description) {
- DidFailLoadInternal(false,
- !render_frame_host->GetParent(),
- error_code,
- error_description,
- validated_url);
-}
-
-void WebContentsObserverAndroid::DidNavigateMainFrame(
- const LoadCommittedDetails& details,
- const FrameNavigateParams& params) {
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
- if (obj.is_null())
- return;
- ScopedJavaLocalRef<jstring> jstring_url(
- ConvertUTF8ToJavaString(env, params.url.spec()));
- ScopedJavaLocalRef<jstring> jstring_base_url(
- ConvertUTF8ToJavaString(env, params.base_url.spec()));
-
- // See http://crbug.com/251330 for why it's determined this way.
- url::Replacements<char> replacements;
- replacements.ClearRef();
- bool urls_same_ignoring_fragment =
- params.url.ReplaceComponents(replacements) ==
- details.previous_url.ReplaceComponents(replacements);
-
- // is_fragment_navigation is indicative of the intent of this variable.
- // However, there isn't sufficient information here to determine whether this
- // is actually a fragment navigation, or a history API navigation to a URL
- // 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_WebContentsObserver_didNavigateMainFrame(
- env, obj.obj(), jstring_url.obj(), jstring_base_url.obj(),
- 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();
- ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
- if (obj.is_null())
- return;
- ScopedJavaLocalRef<jstring> jstring_url(
- ConvertUTF8ToJavaString(env, params.url.spec()));
- ScopedJavaLocalRef<jstring> jstring_base_url(
- ConvertUTF8ToJavaString(env, params.base_url.spec()));
- jboolean jboolean_is_reload = ui::PageTransitionCoreTypeIs(
- params.transition, ui::PAGE_TRANSITION_RELOAD);
-
- Java_WebContentsObserver_didNavigateAnyFrame(
- env, obj.obj(), jstring_url.obj(), jstring_base_url.obj(),
- jboolean_is_reload);
-}
-
-void WebContentsObserverAndroid::DidStartProvisionalLoadForFrame(
- 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()));
- // 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(
- 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_WebContentsObserver_didCommitProvisionalLoadForFrame(
- env,
- obj.obj(),
- render_frame_host->GetRoutingID(),
- !render_frame_host->GetParent(),
- jstring_url.obj(),
- transition_type);
-}
-
-void WebContentsObserverAndroid::DidFinishLoad(
- RenderFrameHost* render_frame_host,
- const GURL& validated_url) {
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
- if (obj.is_null())
- return;
-
- std::string url_string = validated_url.spec();
- NavigationEntry* entry =
- web_contents()->GetController().GetLastCommittedEntry();
- // Note that GetBaseURLForDataURL is only used by the Android WebView.
- if (entry && !entry->GetBaseURLForDataURL().is_empty())
- url_string = entry->GetBaseURLForDataURL().possibly_invalid_spec();
-
- ScopedJavaLocalRef<jstring> jstring_url(
- ConvertUTF8ToJavaString(env, url_string));
- Java_WebContentsObserver_didFinishLoad(
- env,
- obj.obj(),
- render_frame_host->GetRoutingID(),
- jstring_url.obj(),
- !render_frame_host->GetParent());
-}
-
-void WebContentsObserverAndroid::DocumentLoadedInFrame(
- RenderFrameHost* render_frame_host) {
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
- if (obj.is_null())
- return;
- Java_WebContentsObserver_documentLoadedInFrame(
- env, obj.obj(), render_frame_host->GetRoutingID());
-}
-
-void WebContentsObserverAndroid::NavigationEntryCommitted(
- const LoadCommittedDetails& load_details) {
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
- if (obj.is_null())
- return;
- Java_WebContentsObserver_navigationEntryCommitted(env, obj.obj());
-}
-
-void WebContentsObserverAndroid::DidAttachInterstitialPage() {
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
- if (obj.is_null())
- return;
- Java_WebContentsObserver_didAttachInterstitialPage(env, obj.obj());
-}
-
-void WebContentsObserverAndroid::DidDetachInterstitialPage() {
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
- if (obj.is_null())
- return;
- Java_WebContentsObserver_didDetachInterstitialPage(env, obj.obj());
-}
-
-void WebContentsObserverAndroid::DidChangeThemeColor(SkColor color) {
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
- if (obj.is_null())
- return;
- Java_WebContentsObserver_didChangeThemeColor(env, obj.obj(), color);
-}
-
-void WebContentsObserverAndroid::DidFailLoadInternal(
- bool is_provisional_load,
- bool is_main_frame,
- int error_code,
- const base::string16& description,
- const GURL& url) {
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
- if (obj.is_null())
- return;
- ScopedJavaLocalRef<jstring> jstring_error_description(
- ConvertUTF16ToJavaString(env, description));
- ScopedJavaLocalRef<jstring> jstring_url(
- ConvertUTF8ToJavaString(env, url.spec()));
-
- Java_WebContentsObserver_didFailLoad(
- env, obj.obj(),
- is_provisional_load,
- is_main_frame,
- error_code,
- jstring_error_description.obj(), jstring_url.obj());
-}
-
-void WebContentsObserverAndroid::DidFirstVisuallyNonEmptyPaint() {
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
- if (obj.is_null())
- return;
- Java_WebContentsObserver_didFirstVisuallyNonEmptyPaint(
- env, obj.obj());
-}
-
-bool RegisterWebContentsObserverAndroid(JNIEnv* env) {
- return RegisterNativesImpl(env);
-}
-} // namespace content
diff --git a/chromium/content/browser/android/web_contents_observer_android.h b/chromium/content/browser/android/web_contents_observer_android.h
deleted file mode 100644
index 429290321ff..00000000000
--- a/chromium/content/browser/android/web_contents_observer_android.h
+++ /dev/null
@@ -1,88 +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_WEB_CONTENTS_OBSERVER_ANDROID_H_
-#define CONTENT_BROWSER_ANDROID_WEB_CONTENTS_OBSERVER_ANDROID_H_
-
-#include <jni.h>
-
-#include "base/android/jni_weak_ref.h"
-#include "base/basictypes.h"
-#include "base/process/kill.h"
-#include "content/browser/web_contents/web_contents_impl.h"
-#include "content/public/browser/web_contents_observer.h"
-#include "content/public/common/frame_navigate_params.h"
-#include "url/gurl.h"
-
-namespace content {
-
-class RenderViewHost;
-class WebContents;
-
-// Extends WebContentsObserver for providing a public Java API for some of the
-// the calls it receives.
-class WebContentsObserverAndroid : public WebContentsObserver {
- public:
- WebContentsObserverAndroid(JNIEnv* env,
- jobject obj,
- WebContents* web_contents);
- virtual ~WebContentsObserverAndroid();
-
- void Destroy(JNIEnv* env, jobject obj);
-
- 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;
- virtual void DidFailProvisionalLoad(
- RenderFrameHost* render_frame_host,
- const GURL& validated_url,
- int error_code,
- const base::string16& error_description) override;
- virtual void DidFailLoad(RenderFrameHost* render_frame_host,
- const GURL& validated_url,
- int error_code,
- const base::string16& error_description) override;
- virtual void DidNavigateMainFrame(const LoadCommittedDetails& details,
- 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(
- RenderFrameHost* render_frame_host,
- const GURL& validated_url,
- bool is_error_page,
- bool is_iframe_srcdoc) override;
- virtual void DidCommitProvisionalLoadForFrame(
- RenderFrameHost* render_frame_host,
- const GURL& url,
- 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;
-
- void DidFailLoadInternal(bool is_provisional_load,
- bool is_main_frame,
- int error_code,
- const base::string16& description,
- const GURL& url);
-
- JavaObjectWeakGlobalRef weak_java_observer_;
-
- DISALLOW_COPY_AND_ASSIGN(WebContentsObserverAndroid);
-};
-
-bool RegisterWebContentsObserverAndroid(JNIEnv* env);
-} // namespace content
-
-#endif // CONTENT_BROWSER_ANDROID_WEB_CONTENTS_OBSERVER_ANDROID_H_
diff --git a/chromium/content/browser/android/web_contents_observer_proxy.cc b/chromium/content/browser/android/web_contents_observer_proxy.cc
new file mode 100644
index 00000000000..f81e4f2e283
--- /dev/null
+++ b/chromium/content/browser/android/web_contents_observer_proxy.cc
@@ -0,0 +1,290 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/android/web_contents_observer_proxy.h"
+
+#include <string>
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/android/scoped_java_ref.h"
+#include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/browser/navigation_details.h"
+#include "content/public/browser/navigation_entry.h"
+#include "jni/WebContentsObserverProxy_jni.h"
+
+using base::android::AttachCurrentThread;
+using base::android::ScopedJavaLocalRef;
+using base::android::ConvertUTF8ToJavaString;
+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).
+WebContentsObserverProxy::WebContentsObserverProxy(JNIEnv* env,
+ jobject obj,
+ WebContents* web_contents)
+ : WebContentsObserver(web_contents) {
+ DCHECK(obj);
+ java_observer_.Reset(env, obj);
+}
+
+WebContentsObserverProxy::~WebContentsObserverProxy() {
+}
+
+jlong Init(JNIEnv* env, jobject obj, jobject java_web_contents) {
+ WebContents* web_contents =
+ WebContents::FromJavaWebContents(java_web_contents);
+ CHECK(web_contents);
+
+ WebContentsObserverProxy* native_observer =
+ new WebContentsObserverProxy(env, obj, web_contents);
+ return reinterpret_cast<intptr_t>(native_observer);
+}
+
+void WebContentsObserverProxy::Destroy(JNIEnv* env, jobject obj) {
+ delete this;
+}
+
+void WebContentsObserverProxy::WebContentsDestroyed() {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj(java_observer_);
+ // The java side will destroy |this|
+ Java_WebContentsObserverProxy_destroy(env, obj.obj());
+}
+
+void WebContentsObserverProxy::RenderViewReady() {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj(java_observer_);
+ Java_WebContentsObserverProxy_renderViewReady(env, obj.obj());
+}
+
+void WebContentsObserverProxy::RenderProcessGone(
+ base::TerminationStatus termination_status) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj(java_observer_);
+ jboolean was_oom_protected =
+ termination_status == base::TERMINATION_STATUS_OOM_PROTECTED;
+ Java_WebContentsObserverProxy_renderProcessGone(env, obj.obj(),
+ was_oom_protected);
+}
+
+void WebContentsObserverProxy::DidStartLoading() {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj(java_observer_);
+ ScopedJavaLocalRef<jstring> jstring_url(
+ ConvertUTF8ToJavaString(env, web_contents()->GetVisibleURL().spec()));
+ Java_WebContentsObserverProxy_didStartLoading(env, obj.obj(),
+ jstring_url.obj());
+}
+
+void WebContentsObserverProxy::DidStopLoading() {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj(java_observer_);
+ ScopedJavaLocalRef<jstring> jstring_url(ConvertUTF8ToJavaString(
+ env, web_contents()->GetLastCommittedURL().spec()));
+ Java_WebContentsObserverProxy_didStopLoading(env, obj.obj(),
+ jstring_url.obj());
+}
+
+void WebContentsObserverProxy::DidFailProvisionalLoad(
+ RenderFrameHost* render_frame_host,
+ const GURL& validated_url,
+ int error_code,
+ const base::string16& error_description) {
+ DidFailLoadInternal(true, !render_frame_host->GetParent(), error_code,
+ error_description, validated_url);
+}
+
+void WebContentsObserverProxy::DidFailLoad(
+ RenderFrameHost* render_frame_host,
+ const GURL& validated_url,
+ int error_code,
+ const base::string16& error_description) {
+ DidFailLoadInternal(false, !render_frame_host->GetParent(), error_code,
+ error_description, validated_url);
+}
+
+void WebContentsObserverProxy::DidNavigateMainFrame(
+ const LoadCommittedDetails& details,
+ const FrameNavigateParams& params) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj(java_observer_);
+ ScopedJavaLocalRef<jstring> jstring_url(
+ ConvertUTF8ToJavaString(env, params.url.spec()));
+ ScopedJavaLocalRef<jstring> jstring_base_url(
+ ConvertUTF8ToJavaString(env, params.base_url.spec()));
+
+ // See http://crbug.com/251330 for why it's determined this way.
+ url::Replacements<char> replacements;
+ replacements.ClearRef();
+ bool urls_same_ignoring_fragment =
+ params.url.ReplaceComponents(replacements) ==
+ details.previous_url.ReplaceComponents(replacements);
+
+ // is_fragment_navigation is indicative of the intent of this variable.
+ // However, there isn't sufficient information here to determine whether this
+ // is actually a fragment navigation, or a history API navigation to a URL
+ // 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_WebContentsObserverProxy_didNavigateMainFrame(
+ env, obj.obj(), jstring_url.obj(), jstring_base_url.obj(),
+ details.is_navigation_to_different_page(), is_fragment_navigation,
+ details.http_status_code);
+}
+
+void WebContentsObserverProxy::DidNavigateAnyFrame(
+ RenderFrameHost* render_frame_host,
+ const LoadCommittedDetails& details,
+ const FrameNavigateParams& params) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj(java_observer_);
+ ScopedJavaLocalRef<jstring> jstring_url(
+ ConvertUTF8ToJavaString(env, params.url.spec()));
+ ScopedJavaLocalRef<jstring> jstring_base_url(
+ ConvertUTF8ToJavaString(env, params.base_url.spec()));
+ jboolean jboolean_is_reload = ui::PageTransitionCoreTypeIs(
+ params.transition, ui::PAGE_TRANSITION_RELOAD);
+
+ Java_WebContentsObserverProxy_didNavigateAnyFrame(
+ env, obj.obj(), jstring_url.obj(), jstring_base_url.obj(),
+ jboolean_is_reload);
+}
+
+void WebContentsObserverProxy::DocumentAvailableInMainFrame() {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj(java_observer_);
+ Java_WebContentsObserverProxy_documentAvailableInMainFrame(env, obj.obj());
+}
+
+void WebContentsObserverProxy::DidStartProvisionalLoadForFrame(
+ RenderFrameHost* render_frame_host,
+ const GURL& validated_url,
+ bool is_error_page,
+ bool is_iframe_srcdoc) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj(java_observer_);
+ ScopedJavaLocalRef<jstring> jstring_url(
+ ConvertUTF8ToJavaString(env, validated_url.spec()));
+ // 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_WebContentsObserverProxy_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 WebContentsObserverProxy::DidCommitProvisionalLoadForFrame(
+ RenderFrameHost* render_frame_host,
+ const GURL& url,
+ ui::PageTransition transition_type) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj(java_observer_);
+ ScopedJavaLocalRef<jstring> jstring_url(
+ ConvertUTF8ToJavaString(env, url.spec()));
+ Java_WebContentsObserverProxy_didCommitProvisionalLoadForFrame(
+ env, obj.obj(), render_frame_host->GetRoutingID(),
+ !render_frame_host->GetParent(), jstring_url.obj(), transition_type);
+}
+
+void WebContentsObserverProxy::DidFinishLoad(RenderFrameHost* render_frame_host,
+ const GURL& validated_url) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj(java_observer_);
+
+ std::string url_string = validated_url.spec();
+ NavigationEntry* entry =
+ web_contents()->GetController().GetLastCommittedEntry();
+ // Note that GetBaseURLForDataURL is only used by the Android WebView.
+ if (entry && !entry->GetBaseURLForDataURL().is_empty())
+ url_string = entry->GetBaseURLForDataURL().possibly_invalid_spec();
+
+ ScopedJavaLocalRef<jstring> jstring_url(
+ ConvertUTF8ToJavaString(env, url_string));
+ Java_WebContentsObserverProxy_didFinishLoad(
+ env, obj.obj(), render_frame_host->GetRoutingID(), jstring_url.obj(),
+ !render_frame_host->GetParent());
+}
+
+void WebContentsObserverProxy::DocumentLoadedInFrame(
+ RenderFrameHost* render_frame_host) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj(java_observer_);
+ Java_WebContentsObserverProxy_documentLoadedInFrame(
+ env, obj.obj(), render_frame_host->GetRoutingID());
+}
+
+void WebContentsObserverProxy::NavigationEntryCommitted(
+ const LoadCommittedDetails& load_details) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj(java_observer_);
+ Java_WebContentsObserverProxy_navigationEntryCommitted(env, obj.obj());
+}
+
+void WebContentsObserverProxy::DidAttachInterstitialPage() {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj(java_observer_);
+ Java_WebContentsObserverProxy_didAttachInterstitialPage(env, obj.obj());
+}
+
+void WebContentsObserverProxy::DidDetachInterstitialPage() {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj(java_observer_);
+ Java_WebContentsObserverProxy_didDetachInterstitialPage(env, obj.obj());
+}
+
+void WebContentsObserverProxy::DidChangeThemeColor(SkColor color) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj(java_observer_);
+ Java_WebContentsObserverProxy_didChangeThemeColor(env, obj.obj(), color);
+}
+
+void WebContentsObserverProxy::DidFailLoadInternal(
+ bool is_provisional_load,
+ bool is_main_frame,
+ int error_code,
+ const base::string16& description,
+ const GURL& url) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj(java_observer_);
+ ScopedJavaLocalRef<jstring> jstring_error_description(
+ ConvertUTF16ToJavaString(env, description));
+ ScopedJavaLocalRef<jstring> jstring_url(
+ ConvertUTF8ToJavaString(env, url.spec()));
+
+ Java_WebContentsObserverProxy_didFailLoad(
+ env, obj.obj(), is_provisional_load, is_main_frame, error_code,
+ jstring_error_description.obj(), jstring_url.obj());
+}
+
+void WebContentsObserverProxy::DidFirstVisuallyNonEmptyPaint() {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj(java_observer_);
+ Java_WebContentsObserverProxy_didFirstVisuallyNonEmptyPaint(env, obj.obj());
+}
+
+void WebContentsObserverProxy::DidStartNavigationToPendingEntry(
+ const GURL& url,
+ NavigationController::ReloadType reload_type) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj(java_observer_);
+ ScopedJavaLocalRef<jstring> jstring_url(
+ ConvertUTF8ToJavaString(env, url.spec()));
+
+ Java_WebContentsObserverProxy_didStartNavigationToPendingEntry(
+ env, obj.obj(), jstring_url.obj());
+}
+
+bool RegisterWebContentsObserverProxy(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+} // namespace content
diff --git a/chromium/content/browser/android/web_contents_observer_proxy.h b/chromium/content/browser/android/web_contents_observer_proxy.h
new file mode 100644
index 00000000000..0f21400a4ae
--- /dev/null
+++ b/chromium/content/browser/android/web_contents_observer_proxy.h
@@ -0,0 +1,87 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_ANDROID_WEB_CONTENTS_OBSERVER_PROXY_H_
+#define CONTENT_BROWSER_ANDROID_WEB_CONTENTS_OBSERVER_PROXY_H_
+
+#include <jni.h>
+
+#include "base/android/jni_weak_ref.h"
+#include "base/basictypes.h"
+#include "base/process/kill.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/common/frame_navigate_params.h"
+#include "url/gurl.h"
+
+namespace content {
+
+class RenderViewHost;
+class WebContents;
+
+// Extends WebContentsObserver for providing a public Java API for some of the
+// the calls it receives.
+class WebContentsObserverProxy : public WebContentsObserver {
+ public:
+ WebContentsObserverProxy(JNIEnv* env, jobject obj, WebContents* web_contents);
+ ~WebContentsObserverProxy() override;
+
+ void Destroy(JNIEnv* env, jobject obj);
+
+ private:
+ void RenderViewReady() override;
+ void RenderProcessGone(base::TerminationStatus termination_status) override;
+ void DidStartLoading() override;
+ void DidStopLoading() override;
+ void DidFailProvisionalLoad(RenderFrameHost* render_frame_host,
+ const GURL& validated_url,
+ int error_code,
+ const base::string16& error_description) override;
+ void DidFailLoad(RenderFrameHost* render_frame_host,
+ const GURL& validated_url,
+ int error_code,
+ const base::string16& error_description) override;
+ void DidNavigateMainFrame(const LoadCommittedDetails& details,
+ const FrameNavigateParams& params) override;
+ void DidNavigateAnyFrame(RenderFrameHost* render_frame_host,
+ const LoadCommittedDetails& details,
+ const FrameNavigateParams& params) override;
+ void DocumentAvailableInMainFrame() override;
+ void DidFirstVisuallyNonEmptyPaint() override;
+ void DidStartProvisionalLoadForFrame(RenderFrameHost* render_frame_host,
+ const GURL& validated_url,
+ bool is_error_page,
+ bool is_iframe_srcdoc) override;
+ void DidCommitProvisionalLoadForFrame(
+ RenderFrameHost* render_frame_host,
+ const GURL& url,
+ ui::PageTransition transition_type) override;
+ void DidFinishLoad(RenderFrameHost* render_frame_host,
+ const GURL& validated_url) override;
+ void DocumentLoadedInFrame(RenderFrameHost* render_frame_host) override;
+ void NavigationEntryCommitted(
+ const LoadCommittedDetails& load_details) override;
+ void WebContentsDestroyed() override;
+ void DidAttachInterstitialPage() override;
+ void DidDetachInterstitialPage() override;
+ void DidChangeThemeColor(SkColor color) override;
+ void DidStartNavigationToPendingEntry(
+ const GURL& url,
+ NavigationController::ReloadType reload_type) override;
+
+ void DidFailLoadInternal(bool is_provisional_load,
+ bool is_main_frame,
+ int error_code,
+ const base::string16& description,
+ const GURL& url);
+
+ base::android::ScopedJavaGlobalRef<jobject> java_observer_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebContentsObserverProxy);
+};
+
+bool RegisterWebContentsObserverProxy(JNIEnv* env);
+} // namespace content
+
+#endif // CONTENT_BROWSER_ANDROID_WEB_CONTENTS_OBSERVER_PROXY_H_
diff --git a/chromium/content/browser/appcache/appcache_database.cc b/chromium/content/browser/appcache/appcache_database.cc
index 3e502813a1b..985173be166 100644
--- a/chromium/content/browser/appcache/appcache_database.cc
+++ b/chromium/content/browser/appcache/appcache_database.cc
@@ -210,6 +210,7 @@ AppCacheDatabase::AppCacheDatabase(const base::FilePath& path)
}
AppCacheDatabase::~AppCacheDatabase() {
+ CommitLazyLastAccessTimes();
}
void AppCacheDatabase::Disable() {
@@ -392,7 +393,7 @@ bool AppCacheDatabase::FindGroupForCache(int64 cache_id, GroupRecord* record) {
return true;
}
-bool AppCacheDatabase::UpdateGroupLastAccessTime(
+bool AppCacheDatabase::UpdateLastAccessTime(
int64 group_id, base::Time time) {
if (!LazyOpen(true))
return false;
@@ -404,7 +405,30 @@ bool AppCacheDatabase::UpdateGroupLastAccessTime(
statement.BindInt64(0, time.ToInternalValue());
statement.BindInt64(1, group_id);
- return statement.Run() && db_->GetLastChangeCount();
+ return statement.Run();
+}
+
+bool AppCacheDatabase::LazyUpdateLastAccessTime(
+ int64 group_id, base::Time time) {
+ if (!LazyOpen(true))
+ return false;
+ lazy_last_access_times_[group_id] = time;
+ return true;
+}
+
+bool AppCacheDatabase::CommitLazyLastAccessTimes() {
+ if (lazy_last_access_times_.empty())
+ return true;
+ if (!LazyOpen(false))
+ return false;
+
+ sql::Transaction transaction(db_.get());
+ if (!transaction.Begin())
+ return false;
+ for (const auto& pair : lazy_last_access_times_)
+ UpdateLastAccessTime(pair.first, pair.second);
+ lazy_last_access_times_.clear();
+ return transaction.Commit();
}
bool AppCacheDatabase::InsertGroup(const GroupRecord* record) {
@@ -924,8 +948,14 @@ void AppCacheDatabase::ReadGroupRecord(
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));
+
+ const auto found = lazy_last_access_times_.find(record->group_id);
+ if (found != lazy_last_access_times_.end()) {
+ record->last_access_time = found->second;
+ } else {
+ record->last_access_time =
+ base::Time::FromInternalValue(statement.ColumnInt64(4));
+ }
}
void AppCacheDatabase::ReadCacheRecord(
diff --git a/chromium/content/browser/appcache/appcache_database.h b/chromium/content/browser/appcache/appcache_database.h
index ee1c52d8be3..ccfd891abbb 100644
--- a/chromium/content/browser/appcache/appcache_database.h
+++ b/chromium/content/browser/appcache/appcache_database.h
@@ -116,8 +116,11 @@ class CONTENT_EXPORT AppCacheDatabase {
bool FindGroupsForOrigin(
const GURL& origin, std::vector<GroupRecord>* records);
bool FindGroupForCache(int64 cache_id, GroupRecord* record);
- bool UpdateGroupLastAccessTime(
+ bool UpdateLastAccessTime(
int64 group_id, base::Time last_access_time);
+ bool LazyUpdateLastAccessTime(
+ int64 group_id, base::Time last_access_time);
+ bool CommitLazyLastAccessTimes(); // The destructor calls this too.
bool InsertGroup(const GroupRecord* record);
bool DeleteGroup(int64 group_id);
@@ -220,6 +223,7 @@ class CONTENT_EXPORT AppCacheDatabase {
base::FilePath db_file_path_;
scoped_ptr<sql::Connection> db_;
scoped_ptr<sql::MetaTable> meta_table_;
+ std::map<int64, base::Time> lazy_last_access_times_;
bool is_disabled_;
bool is_recreating_;
bool was_corruption_detected_;
diff --git a/chromium/content/browser/appcache/appcache_disk_cache.cc b/chromium/content/browser/appcache/appcache_disk_cache.cc
index 382ed45fed2..46f406eb699 100644
--- a/chromium/content/browser/appcache/appcache_disk_cache.cc
+++ b/chromium/content/browser/appcache/appcache_disk_cache.cc
@@ -8,6 +8,7 @@
#include "base/bind_helpers.h"
#include "base/files/file_path.h"
#include "base/logging.h"
+#include "base/memory/ref_counted.h"
#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
@@ -114,70 +115,91 @@ class AppCacheDiskCache::EntryImpl : public Entry {
// 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 {
+class AppCacheDiskCache::ActiveCall
+ : public base::RefCounted<AppCacheDiskCache::ActiveCall> {
public:
- explicit ActiveCall(AppCacheDiskCache* owner)
- : entry_(NULL),
- owner_(owner),
- entry_ptr_(NULL) {
+ static int CreateEntry(const base::WeakPtr<AppCacheDiskCache>& owner,
+ int64 key, Entry** entry,
+ const net::CompletionCallback& callback) {
+ scoped_refptr<ActiveCall> active_call(
+ new ActiveCall(owner, entry, callback));
+ int rv = owner->disk_cache()->CreateEntry(
+ base::Int64ToString(key), &active_call->entry_ptr_,
+ base::Bind(&ActiveCall::OnAsyncCompletion, active_call));
+ return active_call->HandleImmediateReturnValue(rv);
}
- 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);
+ static int OpenEntry(const base::WeakPtr<AppCacheDiskCache>& owner,
+ int64 key, Entry** entry,
+ const net::CompletionCallback& callback) {
+ scoped_refptr<ActiveCall> active_call(
+ new ActiveCall(owner, entry, callback));
+ int rv = owner->disk_cache()->OpenEntry(
+ base::Int64ToString(key), &active_call->entry_ptr_,
+ base::Bind(&ActiveCall::OnAsyncCompletion, active_call));
+ return active_call->HandleImmediateReturnValue(rv);
}
- 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(
+ static int DoomEntry(const base::WeakPtr<AppCacheDiskCache>& owner,
+ int64 key, const net::CompletionCallback& callback) {
+ scoped_refptr<ActiveCall> active_call(
+ new ActiveCall(owner, nullptr, callback));
+ int rv = owner->disk_cache()->DoomEntry(
base::Int64ToString(key),
- base::Bind(&ActiveCall::OnAsyncCompletion, base::Unretained(this)));
- return HandleImmediateReturnValue(rv, NULL, callback);
+ base::Bind(&ActiveCall::OnAsyncCompletion, active_call));
+ return active_call->HandleImmediateReturnValue(rv);
}
private:
- int HandleImmediateReturnValue(int rv, Entry** entry,
- const net::CompletionCallback& callback) {
+ friend class base::RefCounted<AppCacheDiskCache::ActiveCall>;
+
+ ActiveCall(const base::WeakPtr<AppCacheDiskCache>& owner,
+ Entry** entry,
+ const net::CompletionCallback& callback)
+ : owner_(owner),
+ entry_(entry),
+ callback_(callback),
+ entry_ptr_(nullptr) {
+ DCHECK(owner_);
+ }
+
+ ~ActiveCall() {}
+
+ int HandleImmediateReturnValue(int rv) {
if (rv == net::ERR_IO_PENDING) {
// OnAsyncCompletion will be called later.
- callback_ = callback;
- entry_ = entry;
- owner_->AddActiveCall(this);
- return net::ERR_IO_PENDING;
+ return rv;
+ }
+
+ if (rv == net::OK && entry_) {
+ DCHECK(entry_ptr_);
+ *entry_ = new EntryImpl(entry_ptr_, owner_.get());
}
- 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_);
+ if (rv == net::OK && entry_) {
+ DCHECK(entry_ptr_);
+ if (owner_) {
+ *entry_ = new EntryImpl(entry_ptr_, owner_.get());
+ } else {
+ entry_ptr_->Close();
+ rv = net::ERR_ABORTED;
+ }
+ }
callback_.Run(rv);
- callback_.Reset();
- delete this;
}
+ base::WeakPtr<AppCacheDiskCache> owner_;
Entry** entry_;
net::CompletionCallback callback_;
- AppCacheDiskCache* owner_;
disk_cache::Entry* entry_ptr_;
};
AppCacheDiskCache::AppCacheDiskCache()
- : is_disabled_(false) {
+ : is_disabled_(false),
+ weak_factory_(this) {
}
AppCacheDiskCache::~AppCacheDiskCache() {
@@ -225,7 +247,6 @@ void AppCacheDiskCache::Disable() {
}
open_entries_.clear();
disk_cache_.reset();
- STLDeleteElements(&active_calls_);
}
int AppCacheDiskCache::CreateEntry(int64 key, Entry** entry,
@@ -243,7 +264,8 @@ int AppCacheDiskCache::CreateEntry(int64 key, Entry** entry,
if (!disk_cache_)
return net::ERR_FAILED;
- return (new ActiveCall(this))->CreateEntry(key, entry, callback);
+ return ActiveCall::CreateEntry(
+ weak_factory_.GetWeakPtr(), key, entry, callback);
}
int AppCacheDiskCache::OpenEntry(int64 key, Entry** entry,
@@ -261,7 +283,8 @@ int AppCacheDiskCache::OpenEntry(int64 key, Entry** entry,
if (!disk_cache_)
return net::ERR_FAILED;
- return (new ActiveCall(this))->OpenEntry(key, entry, callback);
+ return ActiveCall::OpenEntry(
+ weak_factory_.GetWeakPtr(), key, entry, callback);
}
int AppCacheDiskCache::DoomEntry(int64 key,
@@ -278,7 +301,7 @@ int AppCacheDiskCache::DoomEntry(int64 key,
if (!disk_cache_)
return net::ERR_FAILED;
- return (new ActiveCall(this))->DoomEntry(key, callback);
+ return ActiveCall::DoomEntry(weak_factory_.GetWeakPtr(), key, callback);
}
AppCacheDiskCache::PendingCall::PendingCall()
diff --git a/chromium/content/browser/appcache/appcache_disk_cache.h b/chromium/content/browser/appcache/appcache_disk_cache.h
index 8995e83cf71..d4a7723423f 100644
--- a/chromium/content/browser/appcache/appcache_disk_cache.h
+++ b/chromium/content/browser/appcache/appcache_disk_cache.h
@@ -96,8 +96,6 @@ class CONTENT_EXPORT AppCacheDiskCache
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); }
@@ -105,9 +103,10 @@ class CONTENT_EXPORT AppCacheDiskCache
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_;
+
+ base::WeakPtrFactory<AppCacheDiskCache> weak_factory_;
};
} // namespace content
diff --git a/chromium/content/browser/appcache/appcache_entry.h b/chromium/content/browser/appcache/appcache_entry.h
index 5c4fffd2ff5..7aaf42581ea 100644
--- a/chromium/content/browser/appcache/appcache_entry.h
+++ b/chromium/content/browser/appcache/appcache_entry.h
@@ -64,4 +64,4 @@ class AppCacheEntry {
} // namespace content
-#endif // WEBKIT_APPCACHE_APPCACHE_RESOURCE_H_
+#endif // CONTENT_BROWSER_APPCACHE_APPCACHE_ENTRY_H_
diff --git a/chromium/content/browser/appcache/appcache_group.cc b/chromium/content/browser/appcache/appcache_group.cc
index 7ebd2890ba4..ce6d873638b 100644
--- a/chromium/content/browser/appcache/appcache_group.cc
+++ b/chromium/content/browser/appcache/appcache_group.cc
@@ -219,7 +219,9 @@ void AppCacheGroup::RunQueuedUpdates() {
}
}
-bool AppCacheGroup::FindObserver(UpdateObserver* find_me,
+// static
+bool AppCacheGroup::FindObserver(
+ const UpdateObserver* find_me,
const ObserverList<UpdateObserver>& observer_list) {
return observer_list.HasObserver(find_me);
}
diff --git a/chromium/content/browser/appcache/appcache_group.h b/chromium/content/browser/appcache/appcache_group.h
index 3c54cfec5a2..1a2df75203a 100644
--- a/chromium/content/browser/appcache/appcache_group.h
+++ b/chromium/content/browser/appcache/appcache_group.h
@@ -122,8 +122,8 @@ class CONTENT_EXPORT AppCacheGroup
// 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);
+ static bool FindObserver(const UpdateObserver* find_me,
+ const ObserverList<UpdateObserver>& observer_list);
void ScheduleUpdateRestart(int delay_ms);
void HostDestructionImminent(AppCacheHost* host);
diff --git a/chromium/content/browser/appcache/appcache_host.cc b/chromium/content/browser/appcache/appcache_host.cc
index 52213a3a14e..4ec19ffe624 100644
--- a/chromium/content/browser/appcache/appcache_host.cc
+++ b/chromium/content/browser/appcache/appcache_host.cc
@@ -291,11 +291,13 @@ AppCacheHost* AppCacheHost::GetParentAppCacheHost() const {
AppCacheRequestHandler* AppCacheHost::CreateRequestHandler(
net::URLRequest* request,
- ResourceType resource_type) {
+ ResourceType resource_type,
+ bool should_reset_appcache) {
if (is_for_dedicated_worker()) {
AppCacheHost* parent_host = GetParentAppCacheHost();
if (parent_host)
- return parent_host->CreateRequestHandler(request, resource_type);
+ return parent_host->CreateRequestHandler(
+ request, resource_type, should_reset_appcache);
return NULL;
}
@@ -303,12 +305,14 @@ AppCacheRequestHandler* AppCacheHost::CreateRequestHandler(
// 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);
+ return new AppCacheRequestHandler(
+ this, resource_type, should_reset_appcache);
}
if ((associated_cache() && associated_cache()->is_complete()) ||
is_selection_pending()) {
- return new AppCacheRequestHandler(this, resource_type);
+ return new AppCacheRequestHandler(
+ this, resource_type, should_reset_appcache);
}
return NULL;
}
diff --git a/chromium/content/browser/appcache/appcache_host.h b/chromium/content/browser/appcache/appcache_host.h
index 9f014fbb471..7525ea2f7b8 100644
--- a/chromium/content/browser/appcache/appcache_host.h
+++ b/chromium/content/browser/appcache/appcache_host.h
@@ -111,7 +111,8 @@ class CONTENT_EXPORT AppCacheHost
// May return NULL if the request isn't subject to retrieval from an appache.
AppCacheRequestHandler* CreateRequestHandler(
net::URLRequest* request,
- ResourceType resource_type);
+ ResourceType resource_type,
+ bool should_reset_appcache);
// Support for devtools inspecting appcache resources.
void GetResourceList(std::vector<AppCacheResourceInfo>* resource_infos);
diff --git a/chromium/content/browser/appcache/appcache_interceptor.cc b/chromium/content/browser/appcache/appcache_interceptor.cc
index adc6d2c6979..4ca2c6998e7 100644
--- a/chromium/content/browser/appcache/appcache_interceptor.cc
+++ b/chromium/content/browser/appcache/appcache_interceptor.cc
@@ -10,49 +10,21 @@
#include "content/browser/appcache/appcache_service_impl.h"
#include "content/browser/appcache/appcache_url_request_job.h"
#include "content/common/appcache_interfaces.h"
+#include "net/url_request/url_request.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();
-}
+static int kHandlerKey; // Value is not used.
-// static
-scoped_ptr<net::URLRequestInterceptor>
-AppCacheInterceptor::CreateStartInterceptor() {
- return scoped_ptr<net::URLRequestInterceptor>(
- new StartInterceptor);
-}
+namespace content {
void AppCacheInterceptor::SetHandler(net::URLRequest* request,
AppCacheRequestHandler* handler) {
- request->SetUserData(GetInstance(), handler); // request takes ownership
+ request->SetUserData(&kHandlerKey, handler); // request takes ownership
}
AppCacheRequestHandler* AppCacheInterceptor::GetHandler(
net::URLRequest* request) {
return static_cast<AppCacheRequestHandler*>(
- request->GetUserData(GetInstance()));
+ request->GetUserData(&kHandlerKey));
}
void AppCacheInterceptor::SetExtraRequestInfo(
@@ -60,7 +32,8 @@ void AppCacheInterceptor::SetExtraRequestInfo(
AppCacheServiceImpl* service,
int process_id,
int host_id,
- ResourceType resource_type) {
+ ResourceType resource_type,
+ bool should_reset_appcache) {
if (!service || (host_id == kAppCacheNoHostId))
return;
@@ -76,7 +49,7 @@ void AppCacheInterceptor::SetExtraRequestInfo(
// Create a handler for this request and associate it with the request.
AppCacheRequestHandler* handler =
- host->CreateRequestHandler(request, resource_type);
+ host->CreateRequestHandler(request, resource_type, should_reset_appcache);
if (handler)
SetHandler(request, handler);
}
@@ -112,24 +85,33 @@ void AppCacheInterceptor::CompleteCrossSiteTransfer(
new_host_id);
}
+void AppCacheInterceptor::MaybeCompleteCrossSiteTransferInOldProcess(
+ net::URLRequest* request,
+ int process_id) {
+ AppCacheRequestHandler* handler = GetHandler(request);
+ if (!handler)
+ return;
+ handler->MaybeCompleteCrossSiteTransferInOldProcess(process_id);
+}
+
AppCacheInterceptor::AppCacheInterceptor() {
- net::URLRequest::Deprecated::RegisterRequestInterceptor(this);
}
AppCacheInterceptor::~AppCacheInterceptor() {
- net::URLRequest::Deprecated::UnregisterRequestInterceptor(this);
}
-net::URLRequestJob* AppCacheInterceptor::MaybeIntercept(
- net::URLRequest* request, net::NetworkDelegate* network_delegate) {
- // Intentionally empty, handled by class StartInterceptor.
- return NULL;
+net::URLRequestJob* AppCacheInterceptor::MaybeInterceptRequest(
+ net::URLRequest* request, net::NetworkDelegate* network_delegate) const {
+ AppCacheRequestHandler* handler = GetHandler(request);
+ if (!handler)
+ return NULL;
+ return handler->MaybeLoadResource(request, network_delegate);
}
net::URLRequestJob* AppCacheInterceptor::MaybeInterceptRedirect(
net::URLRequest* request,
net::NetworkDelegate* network_delegate,
- const GURL& location) {
+ const GURL& location) const {
AppCacheRequestHandler* handler = GetHandler(request);
if (!handler)
return NULL;
@@ -138,7 +120,7 @@ net::URLRequestJob* AppCacheInterceptor::MaybeInterceptRedirect(
}
net::URLRequestJob* AppCacheInterceptor::MaybeInterceptResponse(
- net::URLRequest* request, net::NetworkDelegate* network_delegate) {
+ net::URLRequest* request, net::NetworkDelegate* network_delegate) const {
AppCacheRequestHandler* handler = GetHandler(request);
if (!handler)
return NULL;
diff --git a/chromium/content/browser/appcache/appcache_interceptor.h b/chromium/content/browser/appcache/appcache_interceptor.h
index 049fd7a5732..be8110daabb 100644
--- a/chromium/content/browser/appcache/appcache_interceptor.h
+++ b/chromium/content/browser/appcache/appcache_interceptor.h
@@ -5,12 +5,16 @@
#ifndef CONTENT_BROWSER_APPCACHE_APPCACHE_INTERCEPTOR_H_
#define CONTENT_BROWSER_APPCACHE_APPCACHE_INTERCEPTOR_H_
-#include "base/memory/singleton.h"
+#include "base/basictypes.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"
+
+class GURL;
+
+namespace net {
+class URLRequest;
+}
namespace content {
class AppCacheRequestHandler;
@@ -18,21 +22,15 @@ class AppCacheServiceImpl;
// An interceptor to hijack requests and potentially service them out of
// the appcache.
-class CONTENT_EXPORT AppCacheInterceptor
- : public net::URLRequest::Interceptor {
+class CONTENT_EXPORT AppCacheInterceptor : public net::URLRequestInterceptor {
public:
- // Registers a singleton instance with the net library.
- // Should be called early in the IO thread prior to initiating requests.
- static void EnsureRegistered() {
- CHECK(GetInstance());
- }
-
// Must be called to make a request eligible for retrieval from an appcache.
static void SetExtraRequestInfo(net::URLRequest* request,
AppCacheServiceImpl* service,
int process_id,
int host_id,
- ResourceType resource_type);
+ ResourceType resource_type,
+ bool should_reset_appcache);
// May be called after response headers are complete to retrieve extra
// info about the response.
@@ -46,37 +44,27 @@ class CONTENT_EXPORT AppCacheInterceptor
static void CompleteCrossSiteTransfer(net::URLRequest* request,
int new_process_id,
int new_host_id);
+ static void MaybeCompleteCrossSiteTransferInOldProcess(
+ net::URLRequest* request,
+ int old_process_id);
- 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();
+ AppCacheInterceptor();
+ ~AppCacheInterceptor() override;
protected:
- // Override from net::URLRequest::Interceptor:
- net::URLRequestJob* MaybeIntercept(
+ // Override from net::URLRequestInterceptor:
+ net::URLRequestJob* MaybeInterceptRequest(
net::URLRequest* request,
- net::NetworkDelegate* network_delegate) override;
+ net::NetworkDelegate* network_delegate) const override;
net::URLRequestJob* MaybeInterceptResponse(
net::URLRequest* request,
- net::NetworkDelegate* network_delegate) override;
+ net::NetworkDelegate* network_delegate) const override;
net::URLRequestJob* MaybeInterceptRedirect(
net::URLRequest* request,
net::NetworkDelegate* network_delegate,
- const GURL& location) override;
+ const GURL& location) const override;
private:
- friend struct DefaultSingletonTraits<AppCacheInterceptor>;
- class StartInterceptor;
-
- AppCacheInterceptor();
- ~AppCacheInterceptor() override;
-
static void SetHandler(net::URLRequest* request,
AppCacheRequestHandler* handler);
static AppCacheRequestHandler* GetHandler(net::URLRequest* request);
diff --git a/chromium/content/browser/appcache/appcache_manifest_parser.cc b/chromium/content/browser/appcache/appcache_manifest_parser.cc
index 99f5e87f379..bf936c23ebc 100644
--- a/chromium/content/browser/appcache/appcache_manifest_parser.cc
+++ b/chromium/content/browser/appcache/appcache_manifest_parser.cc
@@ -100,10 +100,7 @@ bool ParseManifest(const GURL& manifest_url, const char* data, int length,
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);
+ base::UTF8ToWide(data, length, &data_string);
const wchar_t* p = data_string.c_str();
const wchar_t* end = p + data_string.length();
diff --git a/chromium/content/browser/appcache/appcache_request_handler.cc b/chromium/content/browser/appcache/appcache_request_handler.cc
index a21337c1111..bcfbe35cfb0 100644
--- a/chromium/content/browser/appcache/appcache_request_handler.cc
+++ b/chromium/content/browser/appcache/appcache_request_handler.cc
@@ -15,15 +15,19 @@
namespace content {
AppCacheRequestHandler::AppCacheRequestHandler(AppCacheHost* host,
- ResourceType resource_type)
+ ResourceType resource_type,
+ bool should_reset_appcache)
: host_(host),
resource_type_(resource_type),
+ should_reset_appcache_(should_reset_appcache),
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) {
+ maybe_load_resource_executed_(false),
+ old_process_id_(0),
+ old_host_id_(kAppCacheNoHostId) {
DCHECK(host_);
host_->AddObserver(this);
}
@@ -183,6 +187,8 @@ void AppCacheRequestHandler::PrepareForCrossSiteTransfer(int old_process_id) {
if (!host_)
return;
AppCacheBackendImpl* backend = host_->service()->GetBackend(old_process_id);
+ old_process_id_ = old_process_id;
+ old_host_id_ = host_->host_id();
host_for_cross_site_transfer_ = backend->TransferHostOut(host_->host_id());
DCHECK_EQ(host_, host_for_cross_site_transfer_.get());
}
@@ -196,6 +202,15 @@ void AppCacheRequestHandler::CompleteCrossSiteTransfer(
backend->TransferHostIn(new_host_id, host_for_cross_site_transfer_.Pass());
}
+void AppCacheRequestHandler::MaybeCompleteCrossSiteTransferInOldProcess(
+ int old_process_id) {
+ if (!host_ || !host_for_cross_site_transfer_.get() ||
+ old_process_id != old_process_id_) {
+ return;
+ }
+ CompleteCrossSiteTransfer(old_process_id_, old_host_id_);
+}
+
void AppCacheRequestHandler::OnDestructionImminent(AppCacheHost* host) {
storage()->CancelDelegateCallbacks(this);
host_ = NULL; // no need to RemoveObserver, the host is being deleted
@@ -292,6 +307,13 @@ void AppCacheRequestHandler::OnMainResponseFound(
return;
}
+ if (should_reset_appcache_ && !manifest_url.is_empty()) {
+ host_->service()->DeleteAppCacheGroup(
+ manifest_url, net::CompletionCallback());
+ 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
diff --git a/chromium/content/browser/appcache/appcache_request_handler.h b/chromium/content/browser/appcache/appcache_request_handler.h
index cf0297b35dd..81acd85d0d3 100644
--- a/chromium/content/browser/appcache/appcache_request_handler.h
+++ b/chromium/content/browser/appcache/appcache_request_handler.h
@@ -49,6 +49,7 @@ class CONTENT_EXPORT AppCacheRequestHandler
// Methods to support cross site navigations.
void PrepareForCrossSiteTransfer(int old_process_id);
void CompleteCrossSiteTransfer(int new_process_id, int new_host_id);
+ void MaybeCompleteCrossSiteTransferInOldProcess(int old_process_id);
static bool IsMainResourceType(ResourceType type) {
return IsResourceTypeFrame(type) ||
@@ -59,7 +60,8 @@ class CONTENT_EXPORT AppCacheRequestHandler
friend class AppCacheHost;
// Callers should use AppCacheHost::CreateRequestHandler.
- AppCacheRequestHandler(AppCacheHost* host, ResourceType resource_type);
+ AppCacheRequestHandler(AppCacheHost* host, ResourceType resource_type,
+ bool should_reset_appcache);
// AppCacheHost::Observer override
void OnDestructionImminent(AppCacheHost* host) override;
@@ -113,6 +115,9 @@ class CONTENT_EXPORT AppCacheRequestHandler
// Frame vs subresource vs sharedworker loads are somewhat different.
ResourceType resource_type_;
+ // True if corresponding AppCache group should be resetted before load.
+ bool should_reset_appcache_;
+
// Subresource requests wait until after cache selection completes.
bool is_waiting_for_cache_selection_;
@@ -141,6 +146,8 @@ class CONTENT_EXPORT AppCacheRequestHandler
// 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_;
+ int old_process_id_;
+ int old_host_id_;
friend class content::AppCacheRequestHandlerTest;
DISALLOW_COPY_AND_ASSIGN(AppCacheRequestHandler);
diff --git a/chromium/content/browser/appcache/appcache_request_handler_unittest.cc b/chromium/content/browser/appcache/appcache_request_handler_unittest.cc
index 9543f7e65d7..f05fed29544 100644
--- a/chromium/content/browser/appcache/appcache_request_handler_unittest.cc
+++ b/chromium/content/browser/appcache/appcache_request_handler_unittest.cc
@@ -254,9 +254,10 @@ class AppCacheRequestHandlerTest : public testing::Test {
base::Unretained(this)));
request_ = empty_context_.CreateRequest(
- GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
+ GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
handler_.reset(host_->CreateRequestHandler(request_.get(),
- RESOURCE_TYPE_MAIN_FRAME));
+ RESOURCE_TYPE_MAIN_FRAME,
+ false));
EXPECT_TRUE(handler_.get());
job_ = handler_->MaybeLoadResource(request_.get(),
@@ -302,9 +303,10 @@ class AppCacheRequestHandlerTest : public testing::Test {
base::Unretained(this)));
request_ = empty_context_.CreateRequest(
- GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
+ GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
handler_.reset(host_->CreateRequestHandler(request_.get(),
- RESOURCE_TYPE_MAIN_FRAME));
+ RESOURCE_TYPE_MAIN_FRAME,
+ false));
EXPECT_TRUE(handler_.get());
mock_storage()->SimulateFindMainResource(
@@ -351,9 +353,10 @@ class AppCacheRequestHandlerTest : public testing::Test {
base::Unretained(this)));
request_ = empty_context_.CreateRequest(
- GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
+ GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
handler_.reset(host_->CreateRequestHandler(request_.get(),
- RESOURCE_TYPE_MAIN_FRAME));
+ RESOURCE_TYPE_MAIN_FRAME,
+ false));
EXPECT_TRUE(handler_.get());
mock_storage()->SimulateFindMainResource(
@@ -433,9 +436,10 @@ class AppCacheRequestHandlerTest : public testing::Test {
request_ = empty_context_.CreateRequest(
GURL("http://blah/fallback-override"), net::DEFAULT_PRIORITY,
- &delegate_, NULL);
+ &delegate_);
handler_.reset(host_->CreateRequestHandler(request_.get(),
- RESOURCE_TYPE_MAIN_FRAME));
+ RESOURCE_TYPE_MAIN_FRAME,
+ false));
EXPECT_TRUE(handler_.get());
mock_storage()->SimulateFindMainResource(
@@ -486,9 +490,10 @@ class AppCacheRequestHandlerTest : public testing::Test {
void SubResource_Miss_WithNoCacheSelected() {
request_ = empty_context_.CreateRequest(
- GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
+ GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
handler_.reset(host_->CreateRequestHandler(request_.get(),
- RESOURCE_TYPE_SUB_RESOURCE));
+ RESOURCE_TYPE_SUB_RESOURCE,
+ false));
// We avoid creating handler when possible, sub-resource requests are not
// subject to retrieval from an appcache when there's no associated cache.
@@ -505,9 +510,10 @@ class AppCacheRequestHandlerTest : public testing::Test {
host_->AssociateCompleteCache(MakeNewCache());
request_ = empty_context_.CreateRequest(
- GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
+ GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
handler_.reset(host_->CreateRequestHandler(request_.get(),
- RESOURCE_TYPE_SUB_RESOURCE));
+ RESOURCE_TYPE_SUB_RESOURCE,
+ false));
EXPECT_TRUE(handler_.get());
job_ = handler_->MaybeLoadResource(request_.get(),
@@ -537,9 +543,10 @@ class AppCacheRequestHandlerTest : public testing::Test {
host_->set_preferred_manifest_url(cache->owning_group()->manifest_url());
request_ = empty_context_.CreateRequest(
- GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
+ GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
handler_.reset(host_->CreateRequestHandler(request_.get(),
- RESOURCE_TYPE_SUB_RESOURCE));
+ RESOURCE_TYPE_SUB_RESOURCE,
+ false));
EXPECT_TRUE(handler_.get());
job_ = handler_->MaybeLoadResource(request_.get(),
request_->context()->network_delegate());
@@ -572,9 +579,10 @@ class AppCacheRequestHandlerTest : public testing::Test {
AppCacheEntry(AppCacheEntry::EXPLICIT, 1), AppCacheEntry(), false);
request_ = empty_context_.CreateRequest(
- GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
+ GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
handler_.reset(host_->CreateRequestHandler(request_.get(),
- RESOURCE_TYPE_SUB_RESOURCE));
+ RESOURCE_TYPE_SUB_RESOURCE,
+ false));
EXPECT_TRUE(handler_.get());
job_ = handler_->MaybeLoadResource(request_.get(),
request_->context()->network_delegate());
@@ -605,9 +613,10 @@ class AppCacheRequestHandlerTest : public testing::Test {
AppCacheEntry(), AppCacheEntry(AppCacheEntry::EXPLICIT, 1), false);
request_ = empty_context_.CreateRequest(
- GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
+ GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
handler_.reset(host_->CreateRequestHandler(request_.get(),
- RESOURCE_TYPE_SUB_RESOURCE));
+ RESOURCE_TYPE_SUB_RESOURCE,
+ false));
EXPECT_TRUE(handler_.get());
job_ = handler_->MaybeLoadResource(request_.get(),
request_->context()->network_delegate());
@@ -639,9 +648,10 @@ class AppCacheRequestHandlerTest : public testing::Test {
AppCacheEntry(), AppCacheEntry(AppCacheEntry::EXPLICIT, 1), false);
request_ = empty_context_.CreateRequest(
- GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
+ GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
handler_.reset(host_->CreateRequestHandler(request_.get(),
- RESOURCE_TYPE_SUB_RESOURCE));
+ RESOURCE_TYPE_SUB_RESOURCE,
+ false));
EXPECT_TRUE(handler_.get());
job_ = handler_->MaybeLoadResource(request_.get(),
request_->context()->network_delegate());
@@ -674,9 +684,10 @@ class AppCacheRequestHandlerTest : public testing::Test {
AppCacheEntry(), AppCacheEntry(), true);
request_ = empty_context_.CreateRequest(
- GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
+ GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
handler_.reset(host_->CreateRequestHandler(request_.get(),
- RESOURCE_TYPE_SUB_RESOURCE));
+ RESOURCE_TYPE_SUB_RESOURCE,
+ false));
EXPECT_TRUE(handler_.get());
job_ = handler_->MaybeLoadResource(request_.get(),
request_->context()->network_delegate());
@@ -704,9 +715,10 @@ class AppCacheRequestHandlerTest : public testing::Test {
AppCacheEntry(AppCacheEntry::EXPLICIT, 1), AppCacheEntry(), false);
request_ = empty_context_.CreateRequest(
- GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
+ GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
handler_.reset(host_->CreateRequestHandler(request_.get(),
- RESOURCE_TYPE_SUB_RESOURCE));
+ RESOURCE_TYPE_SUB_RESOURCE,
+ false));
EXPECT_TRUE(handler_.get());
backend_impl_->UnregisterHost(1);
@@ -731,9 +743,10 @@ class AppCacheRequestHandlerTest : public testing::Test {
host_->pending_selected_cache_id_ = 1;
request_ = empty_context_.CreateRequest(
- GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
+ GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
handler_.reset(host_->CreateRequestHandler(request_.get(),
- RESOURCE_TYPE_SUB_RESOURCE));
+ RESOURCE_TYPE_SUB_RESOURCE,
+ false));
EXPECT_TRUE(handler_.get());
job_ = handler_->MaybeLoadResource(request_.get(),
@@ -764,9 +777,10 @@ class AppCacheRequestHandlerTest : public testing::Test {
host_->pending_selected_cache_id_ = 1;
request_ = empty_context_.CreateRequest(
- GURL("ftp://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
+ GURL("ftp://blah/"), net::DEFAULT_PRIORITY, &delegate_);
handler_.reset(host_->CreateRequestHandler(request_.get(),
- RESOURCE_TYPE_SUB_RESOURCE));
+ RESOURCE_TYPE_SUB_RESOURCE,
+ false));
EXPECT_TRUE(handler_.get()); // we could redirect to http (conceivably)
EXPECT_FALSE(handler_->MaybeLoadResource(
@@ -785,9 +799,10 @@ class AppCacheRequestHandlerTest : public testing::Test {
void CanceledRequest() {
request_ = empty_context_.CreateRequest(
- GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
+ GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
handler_.reset(host_->CreateRequestHandler(request_.get(),
- RESOURCE_TYPE_MAIN_FRAME));
+ RESOURCE_TYPE_MAIN_FRAME,
+ false));
EXPECT_TRUE(handler_.get());
job_ = handler_->MaybeLoadResource(request_.get(),
@@ -822,7 +837,7 @@ class AppCacheRequestHandlerTest : public testing::Test {
RESOURCE_TYPE_WORKER));
request_ = empty_context_.CreateRequest(
- GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
+ GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
const int kParentHostId = host_->host_id();
const int kWorkerHostId = 2;
@@ -833,7 +848,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(), RESOURCE_TYPE_SHARED_WORKER));
+ request_.get(), RESOURCE_TYPE_SHARED_WORKER, false));
EXPECT_TRUE(handler_.get());
// Verify that the handler is associated with the parent host.
EXPECT_EQ(host_, handler_->host_);
@@ -846,7 +861,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(), RESOURCE_TYPE_SHARED_WORKER));
+ request_.get(), RESOURCE_TYPE_SHARED_WORKER, false));
EXPECT_FALSE(handler_.get());
TestFinished();
@@ -860,9 +875,10 @@ class AppCacheRequestHandlerTest : public testing::Test {
base::Unretained(this)));
request_ = empty_context_.CreateRequest(
- GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
+ GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
handler_.reset(host_->CreateRequestHandler(request_.get(),
- RESOURCE_TYPE_MAIN_FRAME));
+ RESOURCE_TYPE_MAIN_FRAME,
+ false));
EXPECT_TRUE(handler_.get());
mock_policy_->can_load_return_value_ = false;
diff --git a/chromium/content/browser/appcache/appcache_response.cc b/chromium/content/browser/appcache/appcache_response.cc
index 0d8b5b4039d..8b7c2188233 100644
--- a/chromium/content/browser/appcache/appcache_response.cc
+++ b/chromium/content/browser/appcache/appcache_response.cc
@@ -10,6 +10,7 @@
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "base/pickle.h"
+#include "base/profiler/scoped_tracker.h"
#include "base/strings/string_util.h"
#include "content/browser/appcache/appcache_storage.h"
#include "net/base/completion_callback.h"
@@ -21,10 +22,7 @@ namespace content {
namespace {
// Disk cache entry data indices.
-enum {
- kResponseInfoIndex,
- kResponseContentIndex
-};
+enum { kResponseInfoIndex, kResponseContentIndex, kResponseMetadataIndex };
// An IOBuffer that wraps a pickle's data. Ownership of the
// pickle is transfered to the WrappedPickleIOBuffer object.
@@ -129,19 +127,60 @@ void AppCacheResponseIO::WriteRaw(int index, int offset,
}
void AppCacheResponseIO::OnRawIOComplete(int result) {
+ // TODO(rtenneti): Remove ScopedTracker below once crbug.com/422516 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "422516 AppCacheResponseIO::OnRawIOComplete"));
+
DCHECK_NE(net::ERR_IO_PENDING, result);
OnIOComplete(result);
}
+void AppCacheResponseIO::OpenEntryIfNeeded() {
+ 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(&AppCacheResponseIO::OpenEntryCallback,
+ weak_factory_.GetWeakPtr(), base::Owned(entry_ptr));
+ rv = disk_cache_->OpenEntry(response_id_, entry_ptr, open_callback_);
+ }
+
+ if (rv != net::ERR_IO_PENDING)
+ OpenEntryCallback(entry_ptr, rv);
+}
+
+void AppCacheResponseIO::OpenEntryCallback(
+ 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();
+ }
+ OnOpenEntryComplete();
+}
+
// AppCacheResponseReader ----------------------------------------------
AppCacheResponseReader::AppCacheResponseReader(
- int64 response_id, int64 group_id, AppCacheDiskCacheInterface* disk_cache)
+ 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),
+ reading_metadata_size_(0),
weak_factory_(this) {
}
@@ -159,15 +198,10 @@ void AppCacheResponseReader::ReadInfo(HttpResponseInfoIOBuffer* info_buf,
info_buffer_ = info_buf;
callback_ = callback; // cleared on completion
- OpenEntryIfNeededAndContinue();
+ OpenEntryIfNeeded();
}
void AppCacheResponseReader::ContinueReadInfo() {
- if (!entry_) {
- ScheduleIOCompletionCallback(net::ERR_CACHE_MISS);
- return;
- }
-
int size = entry_->GetSize(kResponseInfoIndex);
if (size <= 0) {
ScheduleIOCompletionCallback(net::ERR_CACHE_MISS);
@@ -190,15 +224,10 @@ void AppCacheResponseReader::ReadData(net::IOBuffer* buf, int buf_len,
buffer_ = buf;
buffer_len_ = buf_len;
callback_ = callback; // cleared on completion
- OpenEntryIfNeededAndContinue();
+ OpenEntryIfNeeded();
}
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_);
@@ -218,7 +247,11 @@ void AppCacheResponseReader::SetReadRange(int offset, int length) {
void AppCacheResponseReader::OnIOComplete(int result) {
if (result >= 0) {
- if (info_buffer_.get()) {
+ if (reading_metadata_size_) {
+ DCHECK(reading_metadata_size_ == result);
+ DCHECK(info_buffer_->http_info->metadata);
+ reading_metadata_size_ = 0;
+ } else 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);
@@ -235,6 +268,16 @@ void AppCacheResponseReader::OnIOComplete(int result) {
DCHECK(entry_);
info_buffer_->response_data_size =
entry_->GetSize(kResponseContentIndex);
+
+ int64 metadata_size = entry_->GetSize(kResponseMetadataIndex);
+ if (metadata_size > 0) {
+ reading_metadata_size_ = metadata_size;
+ info_buffer_->http_info->metadata =
+ new net::IOBufferWithSize(metadata_size);
+ ReadRaw(kResponseMetadataIndex, 0,
+ info_buffer_->http_info->metadata.get(), metadata_size);
+ return;
+ }
} else {
read_position_ += result;
}
@@ -242,37 +285,11 @@ void AppCacheResponseReader::OnIOComplete(int 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();
+void AppCacheResponseReader::OnOpenEntryComplete() {
+ if (!entry_) {
+ ScheduleIOCompletionCallback(net::ERR_CACHE_MISS);
+ return;
}
-
if (info_buffer_.get())
ContinueReadInfo();
else
@@ -420,4 +437,47 @@ void AppCacheResponseWriter::OnCreateEntryComplete(
ContinueWriteData();
}
+// AppCacheResponseMetadataWriter ----------------------------------------------
+
+AppCacheResponseMetadataWriter::AppCacheResponseMetadataWriter(
+ int64 response_id,
+ int64 group_id,
+ AppCacheDiskCacheInterface* disk_cache)
+ : AppCacheResponseIO(response_id, group_id, disk_cache),
+ write_amount_(0),
+ weak_factory_(this) {
+}
+
+AppCacheResponseMetadataWriter::~AppCacheResponseMetadataWriter() {
+}
+
+void AppCacheResponseMetadataWriter::WriteMetadata(
+ net::IOBuffer* buf,
+ int buf_len,
+ const net::CompletionCallback& callback) {
+ DCHECK(!callback.is_null());
+ DCHECK(!IsIOPending());
+ DCHECK(buf);
+ DCHECK(buf_len >= 0);
+ DCHECK(!buffer_.get());
+
+ buffer_ = buf;
+ write_amount_ = buf_len;
+ callback_ = callback; // cleared on completion
+ OpenEntryIfNeeded();
+}
+
+void AppCacheResponseMetadataWriter::OnOpenEntryComplete() {
+ if (!entry_) {
+ ScheduleIOCompletionCallback(net::ERR_FAILED);
+ return;
+ }
+ WriteRaw(kResponseMetadataIndex, 0, buffer_.get(), write_amount_);
+}
+
+void AppCacheResponseMetadataWriter::OnIOComplete(int result) {
+ DCHECK(result < 0 || write_amount_ == result);
+ InvokeUserCompletionCallback(result);
+}
+
} // namespace content
diff --git a/chromium/content/browser/appcache/appcache_response.h b/chromium/content/browser/appcache/appcache_response.h
index 4b7a32c6767..8d6c79060bd 100644
--- a/chromium/content/browser/appcache/appcache_response.h
+++ b/chromium/content/browser/appcache/appcache_response.h
@@ -106,12 +106,14 @@ class CONTENT_EXPORT AppCacheResponseIO {
AppCacheDiskCacheInterface* disk_cache);
virtual void OnIOComplete(int result) = 0;
+ virtual void OnOpenEntryComplete() {}
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);
+ void OpenEntryIfNeeded();
const int64 response_id_;
const int64 group_id_;
@@ -121,10 +123,12 @@ class CONTENT_EXPORT AppCacheResponseIO {
scoped_refptr<net::IOBuffer> buffer_;
int buffer_len_;
net::CompletionCallback callback_;
+ net::CompletionCallback open_callback_;
base::WeakPtrFactory<AppCacheResponseIO> weak_factory_;
private:
void OnRawIOComplete(int result);
+ void OpenEntryCallback(AppCacheDiskCacheInterface::Entry** entry, int rv);
};
// Reads existing response data from storage. If the object is deleted
@@ -178,15 +182,14 @@ class CONTENT_EXPORT AppCacheResponseReader
AppCacheDiskCacheInterface* disk_cache);
void OnIOComplete(int result) override;
+ void OnOpenEntryComplete() 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_;
+ int reading_metadata_size_;
base::WeakPtrFactory<AppCacheResponseReader> weak_factory_;
};
@@ -257,6 +260,47 @@ class CONTENT_EXPORT AppCacheResponseWriter
base::WeakPtrFactory<AppCacheResponseWriter> weak_factory_;
};
+// Writes metadata of the existing response 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 AppCacheResponseMetadataWriter
+ : public AppCacheResponseIO {
+ public:
+ ~AppCacheResponseMetadataWriter() override;
+
+ // Writes metadata 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 WriteMetadata operation in
+ // progress.
+ void WriteMetadata(net::IOBuffer* buf,
+ int buf_len,
+ const net::CompletionCallback& callback);
+
+ // Returns true if there is a write pending.
+ bool IsWritePending() { return IsIOPending(); }
+
+ protected:
+ friend class AppCacheStorageImpl;
+ friend class content::MockAppCacheStorage;
+ // Should only be constructed by the storage class and derivatives.
+ AppCacheResponseMetadataWriter(int64 response_id,
+ int64 group_id,
+ AppCacheDiskCacheInterface* disk_cache);
+
+ private:
+ void OnIOComplete(int result) override;
+ void OnOpenEntryComplete() override;
+
+ int write_amount_;
+ base::WeakPtrFactory<AppCacheResponseMetadataWriter> 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 815e69789c8..5f91f92fbd2 100644
--- a/chromium/content/browser/appcache/appcache_response_unittest.cc
+++ b/chromium/content/browser/appcache/appcache_response_unittest.cc
@@ -191,6 +191,16 @@ class AppCacheResponseTest : public testing::Test {
base::Unretained(this)));
}
+ void WriteResponseMetadata(scoped_refptr<IOBuffer> io_buffer, int buf_len) {
+ EXPECT_FALSE(metadata_writer_->IsWritePending());
+ write_buffer_ = io_buffer;
+ expected_write_result_ = buf_len;
+ metadata_writer_->WriteMetadata(
+ write_buffer_.get(), buf_len,
+ base::Bind(&AppCacheResponseTest::OnMetadataWriteComplete,
+ base::Unretained(this)));
+ }
+
void ReadResponseBody(scoped_refptr<IOBuffer> io_buffer, int buf_len) {
EXPECT_FALSE(reader_->IsReadPending());
read_buffer_ = io_buffer;
@@ -220,6 +230,12 @@ class AppCacheResponseTest : public testing::Test {
ScheduleNextTask();
}
+ void OnMetadataWriteComplete(int result) {
+ EXPECT_FALSE(metadata_writer_->IsWritePending());
+ EXPECT_EQ(expected_write_result_, result);
+ ScheduleNextTask();
+ }
+
void OnReadInfoComplete(int result) {
EXPECT_FALSE(reader_->IsReadPending());
EXPECT_EQ(expected_read_result_, result);
@@ -373,6 +389,87 @@ class AppCacheResponseTest : public testing::Test {
TestFinished();
}
+ // Metadata -------------------------------------------------
+ void Metadata() {
+ // This tests involves multiple async steps.
+ // 1. Write a response headers and body to storage
+ // a. headers
+ // b. body
+ // 2. Write metadata "Metadata First" using AppCacheResponseMetadataWriter.
+ // 3. Check metadata was written.
+ // 4. Write metadata "Second".
+ // 5. Check metadata was written and was truncated .
+ // 6. Write metadata "".
+ // 7. Check metadata was deleted.
+
+ // Push tasks in reverse order.
+ PushNextTask(base::Bind(&AppCacheResponseTest::Metadata_VerifyMetadata,
+ base::Unretained(this), ""));
+ PushNextTask(base::Bind(&AppCacheResponseTest::Metadata_LoadResponseInfo,
+ base::Unretained(this)));
+ PushNextTask(base::Bind(&AppCacheResponseTest::Metadata_WriteMetadata,
+ base::Unretained(this), ""));
+ PushNextTask(base::Bind(&AppCacheResponseTest::Metadata_VerifyMetadata,
+ base::Unretained(this), "Second"));
+ PushNextTask(base::Bind(&AppCacheResponseTest::Metadata_LoadResponseInfo,
+ base::Unretained(this)));
+ PushNextTask(base::Bind(&AppCacheResponseTest::Metadata_WriteMetadata,
+ base::Unretained(this), "Second"));
+ PushNextTask(base::Bind(&AppCacheResponseTest::Metadata_VerifyMetadata,
+ base::Unretained(this), "Metadata First"));
+ PushNextTask(base::Bind(&AppCacheResponseTest::Metadata_LoadResponseInfo,
+ base::Unretained(this)));
+ PushNextTask(base::Bind(&AppCacheResponseTest::Metadata_WriteMetadata,
+ base::Unretained(this), "Metadata First"));
+ PushNextTask(base::Bind(&AppCacheResponseTest::Metadata_ResetWriter,
+ base::Unretained(this)));
+ writer_.reset(service_->storage()->CreateResponseWriter(GURL(), 0));
+ written_response_id_ = writer_->response_id();
+ WriteBasicResponse();
+ }
+
+ void Metadata_ResetWriter() {
+ writer_.reset();
+ ScheduleNextTask();
+ }
+
+ void Metadata_WriteMetadata(const char* metadata) {
+ metadata_writer_.reset(service_->storage()->CreateResponseMetadataWriter(
+ 0, written_response_id_));
+ scoped_refptr<IOBuffer> buffer(new WrappedIOBuffer(metadata));
+ WriteResponseMetadata(buffer.get(), strlen(metadata));
+ }
+
+ void Metadata_LoadResponseInfo() {
+ metadata_writer_.reset();
+ storage_delegate_.reset(new MockStorageDelegate(this));
+ service_->storage()->LoadResponseInfo(GURL(), 0, written_response_id_,
+ storage_delegate_.get());
+ }
+
+ void Metadata_VerifyMetadata(const char* metadata) {
+ EXPECT_EQ(written_response_id_, storage_delegate_->loaded_info_id_);
+ EXPECT_TRUE(storage_delegate_->loaded_info_.get());
+ const net::HttpResponseInfo* read_head =
+ storage_delegate_->loaded_info_->http_response_info();
+ EXPECT_TRUE(read_head);
+ const int metadata_size = strlen(metadata);
+ if (metadata_size) {
+ EXPECT_TRUE(read_head->metadata.get());
+ EXPECT_EQ(metadata_size, read_head->metadata->size());
+ EXPECT_EQ(0,
+ memcmp(metadata, read_head->metadata->data(), metadata_size));
+ } else {
+ EXPECT_FALSE(read_head->metadata.get());
+ }
+ EXPECT_TRUE(CompareHttpResponseInfos(
+ write_info_buffer_->http_info.get(),
+ storage_delegate_->loaded_info_->http_response_info()));
+ EXPECT_EQ(basic_response_size(),
+ storage_delegate_->loaded_info_->response_data_size());
+ ScheduleNextTask();
+ }
+
// AmountWritten ----------------------------------------------------
void AmountWritten() {
@@ -667,6 +764,7 @@ class AppCacheResponseTest : public testing::Test {
int64 written_response_id_;
scoped_ptr<AppCacheResponseWriter> writer_;
+ scoped_ptr<AppCacheResponseMetadataWriter> metadata_writer_;
scoped_refptr<HttpResponseInfoIOBuffer> write_info_buffer_;
scoped_refptr<IOBuffer> write_buffer_;
int expected_write_result_;
@@ -692,6 +790,10 @@ TEST_F(AppCacheResponseTest, LoadResponseInfo_Hit) {
RunTestOnIOThread(&AppCacheResponseTest::LoadResponseInfo_Hit);
}
+TEST_F(AppCacheResponseTest, Metadata) {
+ RunTestOnIOThread(&AppCacheResponseTest::Metadata);
+}
+
TEST_F(AppCacheResponseTest, AmountWritten) {
RunTestOnIOThread(&AppCacheResponseTest::AmountWritten);
}
diff --git a/chromium/content/browser/appcache/appcache_storage.h b/chromium/content/browser/appcache/appcache_storage.h
index edc059b9381..854b0d1da47 100644
--- a/chromium/content/browser/appcache/appcache_storage.h
+++ b/chromium/content/browser/appcache/appcache_storage.h
@@ -26,6 +26,7 @@ class AppCache;
class AppCacheEntry;
class AppCacheGroup;
class AppCacheQuotaClientTest;
+class AppCacheResponseMetadataWriter;
class AppCacheResponseReader;
class AppCacheResponseTest;
class AppCacheResponseWriter;
@@ -169,6 +170,11 @@ class CONTENT_EXPORT AppCacheStorage {
virtual AppCacheResponseWriter* CreateResponseWriter(
const GURL& manifest_url, int64 group_id) = 0;
+ // Creates a metadata writer to write metadata of response to storage.
+ virtual AppCacheResponseMetadataWriter* CreateResponseMetadataWriter(
+ int64 group_id,
+ int64 response_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.
diff --git a/chromium/content/browser/appcache/appcache_storage_impl.cc b/chromium/content/browser/appcache/appcache_storage_impl.cc
index 5df1d3ebdd1..3653488f188 100644
--- a/chromium/content/browser/appcache/appcache_storage_impl.cc
+++ b/chromium/content/browser/appcache/appcache_storage_impl.cc
@@ -14,6 +14,7 @@
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
+#include "base/profiler/scoped_tracker.h"
#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
@@ -285,6 +286,8 @@ class AppCacheStorageImpl::InitTask : public DatabaseTask {
};
void AppCacheStorageImpl::InitTask::Run() {
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION("AppCacheStorageImpl::InitTask"));
// If there is no sql database, ensure there is no disk cache either.
if (!db_file_path_.empty() &&
!base::PathExists(db_file_path_) &&
@@ -512,14 +515,16 @@ class AppCacheStorageImpl::CacheLoadTask : public StoreOrLoadTask {
};
void AppCacheStorageImpl::CacheLoadTask::Run() {
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION("AppCacheStorageImpl::CacheLoadTask"));
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());
+ database_->LazyUpdateLastAccessTime(group_record_.group_id,
+ base::Time::Now());
}
void AppCacheStorageImpl::CacheLoadTask::RunCompleted() {
@@ -527,6 +532,7 @@ void AppCacheStorageImpl::CacheLoadTask::RunCompleted() {
scoped_refptr<AppCache> cache;
scoped_refptr<AppCacheGroup> group;
if (success_ && !storage_->is_disabled()) {
+ storage_->LazilyCommitLastAccessTimes();
DCHECK(cache_record_.cache_id == cache_id_);
CreateCacheAndGroupFromRecords(&cache, &group);
}
@@ -554,14 +560,16 @@ class AppCacheStorageImpl::GroupLoadTask : public StoreOrLoadTask {
};
void AppCacheStorageImpl::GroupLoadTask::Run() {
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION("AppCacheStorageImpl::GroupLoadTask"));
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());
+ database_->LazyUpdateLastAccessTime(group_record_.group_id,
+ base::Time::Now());
}
void AppCacheStorageImpl::GroupLoadTask::RunCompleted() {
@@ -570,6 +578,7 @@ void AppCacheStorageImpl::GroupLoadTask::RunCompleted() {
scoped_refptr<AppCache> cache;
if (!storage_->is_disabled()) {
if (success_) {
+ storage_->LazilyCommitLastAccessTimes();
DCHECK(group_record_.manifest_url == manifest_url_);
CreateCacheAndGroupFromRecords(&cache, &group);
} else {
@@ -690,8 +699,8 @@ void AppCacheStorageImpl::StoreGroupAndCacheTask::Run() {
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());
+ database_->UpdateLastAccessTime(group_record_.group_id,
+ base::Time::Now());
AppCacheDatabase::CacheRecord cache;
if (database_->FindCacheForGroup(group_record_.group_id, &cache)) {
@@ -931,6 +940,9 @@ class AppCacheStorageImpl::FindMainResponseTask : public DatabaseTask {
};
void AppCacheStorageImpl::FindMainResponseTask::Run() {
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "AppCacheStorageImpl::FindMainResponseTask"));
// NOTE: The heuristics around choosing amoungst multiple candidates
// is underspecified, and just plain not fully understood. This needs
// to be refined.
@@ -1286,12 +1298,12 @@ void AppCacheStorageImpl::DeleteDeletableResponseIdsTask::Run() {
database_->DeleteDeletableResponseIds(response_ids_);
}
-// UpdateGroupLastAccessTimeTask -------
+// LazyUpdateLastAccessTimeTask -------
-class AppCacheStorageImpl::UpdateGroupLastAccessTimeTask
+class AppCacheStorageImpl::LazyUpdateLastAccessTimeTask
: public DatabaseTask {
public:
- UpdateGroupLastAccessTimeTask(
+ LazyUpdateLastAccessTimeTask(
AppCacheStorageImpl* storage, AppCacheGroup* group, base::Time time)
: DatabaseTask(storage), group_id_(group->group_id()),
last_access_time_(time) {
@@ -1300,19 +1312,46 @@ class AppCacheStorageImpl::UpdateGroupLastAccessTimeTask
// DatabaseTask:
void Run() override;
+ void RunCompleted() override;
protected:
- ~UpdateGroupLastAccessTimeTask() override {}
+ ~LazyUpdateLastAccessTimeTask() override {}
private:
int64 group_id_;
base::Time last_access_time_;
};
-void AppCacheStorageImpl::UpdateGroupLastAccessTimeTask::Run() {
- database_->UpdateGroupLastAccessTime(group_id_, last_access_time_);
+void AppCacheStorageImpl::LazyUpdateLastAccessTimeTask::Run() {
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "AppCacheStorageImpl::LazyUpdateLastAccessTimeTask"));
+ database_->LazyUpdateLastAccessTime(group_id_, last_access_time_);
+}
+
+void AppCacheStorageImpl::LazyUpdateLastAccessTimeTask::RunCompleted() {
+ storage_->LazilyCommitLastAccessTimes();
}
+// CommitLastAccessTimesTask -------
+
+class AppCacheStorageImpl::CommitLastAccessTimesTask
+ : public DatabaseTask {
+ public:
+ CommitLastAccessTimesTask(AppCacheStorageImpl* storage)
+ : DatabaseTask(storage) {}
+
+ // DatabaseTask:
+ void Run() override {
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "AppCacheStorageImpl::CommitLastAccessTimesTask"));
+ database_->CommitLazyLastAccessTimes();
+ }
+
+ protected:
+ ~CommitLastAccessTimesTask() override {}
+};
// AppCacheStorageImpl ---------------------------------------------------
@@ -1400,7 +1439,7 @@ void AppCacheStorageImpl::LoadCache(int64 id, Delegate* delegate) {
delegate->OnCacheLoaded(cache, id);
if (cache->owning_group()) {
scoped_refptr<DatabaseTask> update_task(
- new UpdateGroupLastAccessTimeTask(
+ new LazyUpdateLastAccessTimeTask(
this, cache->owning_group(), base::Time::Now()));
update_task->Schedule();
}
@@ -1429,7 +1468,7 @@ void AppCacheStorageImpl::LoadOrCreateGroup(
if (group) {
delegate->OnGroupLoaded(group, manifest_url);
scoped_refptr<DatabaseTask> update_task(
- new UpdateGroupLastAccessTimeTask(
+ new LazyUpdateLastAccessTimeTask(
this, group, base::Time::Now()));
update_task->Schedule();
return;
@@ -1643,6 +1682,13 @@ AppCacheResponseWriter* AppCacheStorageImpl::CreateResponseWriter(
return new AppCacheResponseWriter(NewResponseId(), group_id, disk_cache());
}
+AppCacheResponseMetadataWriter*
+AppCacheStorageImpl::CreateResponseMetadataWriter(int64 group_id,
+ int64 response_id) {
+ return new AppCacheResponseMetadataWriter(response_id, group_id,
+ disk_cache());
+}
+
void AppCacheStorageImpl::DoomResponses(
const GURL& manifest_url, const std::vector<int64>& response_ids) {
if (response_ids.empty())
@@ -1691,12 +1737,12 @@ void AppCacheStorageImpl::StartDeletingResponses(
void AppCacheStorageImpl::ScheduleDeleteOneResponse() {
DCHECK(!is_response_deletion_scheduled_);
- const base::TimeDelta kDelay = base::TimeDelta::FromMilliseconds(10);
+ const base::TimeDelta kBriefDelay = base::TimeDelta::FromMilliseconds(10);
base::MessageLoop::current()->PostDelayedTask(
FROM_HERE,
base::Bind(&AppCacheStorageImpl::DeleteOneResponse,
weak_factory_.GetWeakPtr()),
- kDelay);
+ kBriefDelay);
is_response_deletion_scheduled_ = true;
}
@@ -1863,4 +1909,22 @@ void AppCacheStorageImpl::CallScheduleReinitialize() {
// note: 'this' may be deleted at this point.
}
+void AppCacheStorageImpl::LazilyCommitLastAccessTimes() {
+ if (lazy_commit_timer_.IsRunning())
+ return;
+ const base::TimeDelta kDelay = base::TimeDelta::FromMinutes(5);
+ lazy_commit_timer_.Start(
+ FROM_HERE, kDelay,
+ base::Bind(&AppCacheStorageImpl::OnLazyCommitTimer,
+ weak_factory_.GetWeakPtr()));
+}
+
+void AppCacheStorageImpl::OnLazyCommitTimer() {
+ lazy_commit_timer_.Stop();
+ if (is_disabled())
+ return;
+ scoped_refptr<DatabaseTask> task(new CommitLastAccessTimesTask(this));
+ task->Schedule();
+}
+
} // namespace content
diff --git a/chromium/content/browser/appcache/appcache_storage_impl.h b/chromium/content/browser/appcache/appcache_storage_impl.h
index ca6d76b314b..4a8ebcc3f5b 100644
--- a/chromium/content/browser/appcache/appcache_storage_impl.h
+++ b/chromium/content/browser/appcache/appcache_storage_impl.h
@@ -15,6 +15,7 @@
#include "base/files/file_path.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
+#include "base/timer/timer.h"
#include "content/browser/appcache/appcache_database.h"
#include "content/browser/appcache/appcache_disk_cache.h"
#include "content/browser/appcache/appcache_storage.h"
@@ -64,6 +65,9 @@ class AppCacheStorageImpl : public AppCacheStorage {
int64 response_id) override;
AppCacheResponseWriter* CreateResponseWriter(const GURL& manifest_url,
int64 group_id) override;
+ AppCacheResponseMetadataWriter* CreateResponseMetadataWriter(
+ int64 group_id,
+ int64 response_id) override;
void DoomResponses(const GURL& manifest_url,
const std::vector<int64>& response_ids) override;
void DeleteResponses(const GURL& manifest_url,
@@ -87,7 +91,8 @@ class AppCacheStorageImpl : public AppCacheStorage {
class GetDeletableResponseIdsTask;
class InsertDeletableResponseIdsTask;
class DeleteDeletableResponseIdsTask;
- class UpdateGroupLastAccessTimeTask;
+ class LazyUpdateLastAccessTimeTask;
+ class CommitLastAccessTimesTask;
typedef std::deque<DatabaseTask*> DatabaseTaskQueue;
typedef std::map<int64, CacheLoadTask*> PendingCacheLoads;
@@ -111,12 +116,13 @@ class AppCacheStorageImpl : public AppCacheStorage {
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();
+ void LazilyCommitLastAccessTimes();
+ void OnLazyCommitTimer();
// Sometimes we can respond without having to query the database.
bool FindResponseForMainRequestInGroup(
@@ -168,6 +174,7 @@ class AppCacheStorageImpl : public AppCacheStorage {
bool is_disabled_;
scoped_ptr<AppCacheDiskCache> disk_cache_;
+ base::OneShotTimer<AppCacheStorageImpl> lazy_commit_timer_;
// Used to short-circuit certain operations without having to schedule
// any tasks on the background database thread.
diff --git a/chromium/content/browser/appcache/appcache_storage_impl_unittest.cc b/chromium/content/browser/appcache/appcache_storage_impl_unittest.cc
index 330d9aba390..37c295dbb43 100644
--- a/chromium/content/browser/appcache/appcache_storage_impl_unittest.cc
+++ b/chromium/content/browser/appcache/appcache_storage_impl_unittest.cc
@@ -163,11 +163,10 @@ class IOThread : public base::Thread {
factory->SetProtocolHandler(
"http",
new MockHttpServerJobFactory(
- AppCacheInterceptor::CreateStartInterceptor()));
+ make_scoped_ptr(new AppCacheInterceptor())));
job_factory_ = factory.Pass();
request_context_.reset(new net::TestURLRequestContext());
request_context_->set_job_factory(job_factory_.get());
- AppCacheInterceptor::EnsureRegistered();
}
void CleanUp() override {
@@ -1772,11 +1771,12 @@ class AppCacheStorageImplTest : public testing::Test {
AppCacheHost* host2 = backend_->GetHost(2);
GURL manifest_url = MockHttpServer::GetMockUrl("manifest");
request_ = service()->request_context()->CreateRequest(
- manifest_url, net::DEFAULT_PRIORITY, NULL, NULL);
+ manifest_url, net::DEFAULT_PRIORITY, NULL);
AppCacheInterceptor::SetExtraRequestInfo(
request_.get(), service_.get(),
backend_->process_id(), host2->host_id(),
- RESOURCE_TYPE_MAIN_FRAME);
+ RESOURCE_TYPE_MAIN_FRAME,
+ false);
request_->Start();
}
diff --git a/chromium/content/browser/appcache/appcache_update_job.cc b/chromium/content/browser/appcache/appcache_update_job.cc
index af47342e97c..708b42c32a2 100644
--- a/chromium/content/browser/appcache/appcache_update_job.cc
+++ b/chromium/content/browser/appcache/appcache_update_job.cc
@@ -7,12 +7,12 @@
#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 "base/thread_task_runner_handle.h"
#include "content/browser/appcache/appcache_group.h"
#include "content/browser/appcache/appcache_histograms.h"
-#include "net/base/host_port_pair.h"
+#include "content/public/browser/browser_thread.h"
#include "net/base/io_buffer.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
@@ -21,15 +21,6 @@
#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;
@@ -133,7 +124,7 @@ AppCacheUpdateJob::URLFetcher::URLFetcher(const GURL& url,
retry_503_attempts_(0),
buffer_(new net::IOBuffer(kBufferSize)),
request_(job->service_->request_context()
- ->CreateRequest(url, net::DEFAULT_PRIORITY, this, NULL)),
+ ->CreateRequest(url, net::DEFAULT_PRIORITY, this)),
result_(UPDATE_OK),
redirect_response_code_(-1) {}
@@ -142,8 +133,6 @@ 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();
@@ -154,16 +143,6 @@ void AppCacheUpdateJob::URLFetcher::OnReceivedRedirect(
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();
@@ -190,7 +169,7 @@ void AppCacheUpdateJob::URLFetcher::OnResponseStarted(
return;
}
- if (url_.SchemeIsSecure()) {
+ if (url_.SchemeIsCryptographic()) {
// 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.
@@ -199,7 +178,12 @@ void AppCacheUpdateJob::URLFetcher::OnResponseStarted(
// 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) ||
+ const net::HttpNetworkSession::Params* session_params =
+ request->context()->GetNetworkSessionParams();
+ bool ignore_cert_errors = session_params &&
+ session_params->ignore_certificate_errors;
+ if ((net::IsCertStatusError(request->ssl_info().cert_status) &&
+ !ignore_cert_errors) ||
(url_.GetOrigin() != job_->manifest_url_.GetOrigin() &&
request->response_headers()->
HasHeaderValue("cache-control", "no-store"))) {
@@ -360,7 +344,7 @@ bool AppCacheUpdateJob::URLFetcher::MaybeRetryRequest() {
++retry_503_attempts_;
result_ = UPDATE_OK;
request_ = job_->service_->request_context()->CreateRequest(
- url_, net::DEFAULT_PRIORITY, this, NULL);
+ url_, net::DEFAULT_PRIORITY, this);
Start();
return true;
}
@@ -377,7 +361,8 @@ AppCacheUpdateJob::AppCacheUpdateJob(AppCacheServiceImpl* service,
manifest_fetcher_(NULL),
manifest_has_valid_mime_type_(false),
stored_state_(UNSTORED),
- storage_(service->storage()) {
+ storage_(service->storage()),
+ weak_factory_(this) {
service_->AddObserver(this);
}
@@ -457,7 +442,10 @@ void AppCacheUpdateJob::StartUpdate(AppCacheHost* host,
is_new_pending_master_entry);
}
- FetchManifest(true);
+ BrowserThread::PostAfterStartupTask(
+ FROM_HERE, base::ThreadTaskRunnerHandle::Get(),
+ base::Bind(&AppCacheUpdateJob::FetchManifest, weak_factory_.GetWeakPtr(),
+ true));
}
AppCacheResponseWriter* AppCacheUpdateJob::CreateResponseWriter() {
diff --git a/chromium/content/browser/appcache/appcache_update_job.h b/chromium/content/browser/appcache/appcache_update_job.h
index 4d2d896ea74..8dfd153ac32 100644
--- a/chromium/content/browser/appcache/appcache_update_job.h
+++ b/chromium/content/browser/appcache/appcache_update_job.h
@@ -13,6 +13,7 @@
#include "base/gtest_prod_util.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "content/browser/appcache/appcache.h"
#include "content/browser/appcache/appcache_host.h"
@@ -335,6 +336,7 @@ class CONTENT_EXPORT AppCacheUpdateJob
StoredState stored_state_;
AppCacheStorage* storage_;
+ base::WeakPtrFactory<AppCacheUpdateJob> weak_factory_;
FRIEND_TEST_ALL_PREFIXES(content::AppCacheGroupTest, QueueUpdate);
diff --git a/chromium/content/browser/appcache/appcache_update_job_unittest.cc b/chromium/content/browser/appcache/appcache_update_job_unittest.cc
index 4955a71d780..b69af526d3b 100644
--- a/chromium/content/browser/appcache/appcache_update_job_unittest.cc
+++ b/chromium/content/browser/appcache/appcache_update_job_unittest.cc
@@ -724,9 +724,6 @@ class AppCacheUpdateJobTest : public testing::Test,
MockFrontend* frontend = MakeMockFrontend();
AppCacheHost* host = MakeHost(1, frontend);
update->StartUpdate(host, GURL());
- EXPECT_TRUE(update->manifest_fetcher_ != NULL);
-
- update->manifest_fetcher_->request()->CancelWithError(-100);
// Set up checks for when update job finishes.
do_checks_after_update_finished_ = true;
@@ -757,9 +754,6 @@ class AppCacheUpdateJobTest : public testing::Test,
host2->AssociateCompleteCache(cache);
update->StartUpdate(NULL, GURL());
- EXPECT_TRUE(update->manifest_fetcher_ != NULL);
-
- update->manifest_fetcher_->request()->CancelWithError(-100);
// Set up checks for when update job finishes.
do_checks_after_update_finished_ = true;
@@ -794,7 +788,6 @@ class AppCacheUpdateJobTest : public testing::Test,
MockFrontend* frontend = MakeMockFrontend();
AppCacheHost* host = MakeHost(1, frontend);
update->StartUpdate(host, GURL());
- EXPECT_TRUE(update->manifest_fetcher_ != NULL);
// Set up checks for when update job finishes.
do_checks_after_update_finished_ = true;
@@ -826,7 +819,6 @@ class AppCacheUpdateJobTest : public testing::Test,
frontend->SetVerifyProgressEvents(true);
update->StartUpdate(NULL, GURL());
- EXPECT_TRUE(update->manifest_fetcher_ != NULL);
// Set up checks for when update job finishes.
do_checks_after_update_finished_ = true;
@@ -864,7 +856,6 @@ class AppCacheUpdateJobTest : public testing::Test,
host2->AssociateCompleteCache(cache);
update->StartUpdate(NULL, GURL());
- EXPECT_TRUE(update->manifest_fetcher_ != NULL);
// Set up checks for when update job finishes.
do_checks_after_update_finished_ = true;
@@ -895,7 +886,6 @@ class AppCacheUpdateJobTest : public testing::Test,
MockFrontend* frontend = MakeMockFrontend();
AppCacheHost* host = MakeHost(1, frontend);
update->StartUpdate(host, GURL());
- EXPECT_TRUE(update->manifest_fetcher_ != NULL);
// Set up checks for when update job finishes.
do_checks_after_update_finished_ = true;
@@ -921,7 +911,6 @@ class AppCacheUpdateJobTest : public testing::Test,
MockFrontend* frontend = MakeMockFrontend();
AppCacheHost* host = MakeHost(1, frontend);
update->StartUpdate(host, GURL());
- EXPECT_TRUE(update->manifest_fetcher_ != NULL);
// Set up checks for when update job finishes.
do_checks_after_update_finished_ = true;
@@ -953,7 +942,6 @@ class AppCacheUpdateJobTest : public testing::Test,
host2->AssociateCompleteCache(cache);
update->StartUpdate(NULL, GURL());
- EXPECT_TRUE(update->manifest_fetcher_ != NULL);
// Set up checks for when update job finishes.
do_checks_after_update_finished_ = true;
@@ -1040,7 +1028,6 @@ class AppCacheUpdateJobTest : public testing::Test,
host->AssociateCompleteCache(cache);
update->StartUpdate(NULL, GURL());
- EXPECT_TRUE(update->manifest_fetcher_ != NULL);
// Set up checks for when update job finishes.
do_checks_after_update_finished_ = true;
@@ -1061,7 +1048,6 @@ class AppCacheUpdateJobTest : public testing::Test,
AppCacheUpdateJob* update = group_->update_job_;
update->StartUpdate(NULL, GURL());
- EXPECT_TRUE(update->manifest_fetcher_ != NULL);
WaitForUpdateToFinish();
}
@@ -1391,7 +1377,6 @@ class AppCacheUpdateJobTest : public testing::Test,
AppCacheEntry(AppCacheEntry::MASTER, 111));
update->StartUpdate(NULL, GURL());
- EXPECT_TRUE(update->manifest_fetcher_ != NULL);
// Set up checks for when update job finishes.
do_checks_after_update_finished_ = true;
@@ -1431,7 +1416,6 @@ class AppCacheUpdateJobTest : public testing::Test,
MockFrontend* frontend = MakeMockFrontend();
AppCacheHost* host = MakeHost(1, frontend);
update->StartUpdate(host, GURL());
- EXPECT_TRUE(update->manifest_fetcher_ != NULL);
// Set up checks for when update job finishes.
do_checks_after_update_finished_ = true;
@@ -1465,7 +1449,6 @@ class AppCacheUpdateJobTest : public testing::Test,
host2->AssociateCompleteCache(cache);
update->StartUpdate(NULL, GURL());
- EXPECT_TRUE(update->manifest_fetcher_ != NULL);
// Set up checks for when update job finishes.
do_checks_after_update_finished_ = true;
@@ -1533,7 +1516,6 @@ class AppCacheUpdateJobTest : public testing::Test,
MakeAppCacheResponseInfo(kManifestUrl, 555, kRawHeaders);
update->StartUpdate(NULL, GURL());
- EXPECT_TRUE(update->manifest_fetcher_ != NULL);
// Set up checks for when update job finishes.
do_checks_after_update_finished_ = true;
@@ -1602,7 +1584,6 @@ class AppCacheUpdateJobTest : public testing::Test,
frontend1->SetVerifyProgressEvents(true);
update->StartUpdate(NULL, GURL());
- EXPECT_TRUE(update->manifest_fetcher_ != NULL);
// Set up checks for when update job finishes.
do_checks_after_update_finished_ = true;
@@ -1642,7 +1623,6 @@ class AppCacheUpdateJobTest : public testing::Test,
frontend->SetVerifyProgressEvents(true);
update->StartUpdate(host, GURL());
- EXPECT_TRUE(update->manifest_fetcher_ != NULL);
// Set up checks for when update job finishes.
do_checks_after_update_finished_ = true;
@@ -1681,7 +1661,6 @@ class AppCacheUpdateJobTest : public testing::Test,
MockFrontend* frontend = MakeMockFrontend();
AppCacheHost* host = MakeHost(1, frontend);
update->StartUpdate(host, GURL());
- EXPECT_TRUE(update->manifest_fetcher_ != NULL);
// Set up checks for when update job finishes.
do_checks_after_update_finished_ = true;
@@ -1715,7 +1694,6 @@ class AppCacheUpdateJobTest : public testing::Test,
MockFrontend* frontend = MakeMockFrontend();
AppCacheHost* host = MakeHost(1, frontend);
update->StartUpdate(host, GURL());
- EXPECT_TRUE(update->manifest_fetcher_ != NULL);
// Set up checks for when update job finishes.
do_checks_after_update_finished_ = true;
@@ -1750,7 +1728,6 @@ class AppCacheUpdateJobTest : public testing::Test,
MockFrontend* frontend = MakeMockFrontend();
AppCacheHost* host = MakeHost(1, frontend);
update->StartUpdate(host, GURL());
- EXPECT_TRUE(update->manifest_fetcher_ != NULL);
// Set up checks for when update job finishes.
do_checks_after_update_finished_ = true;
@@ -1784,7 +1761,6 @@ class AppCacheUpdateJobTest : public testing::Test,
MockFrontend* frontend = MakeMockFrontend();
AppCacheHost* host = MakeHost(1, frontend);
update->StartUpdate(host, GURL());
- EXPECT_TRUE(update->manifest_fetcher_ != NULL);
// Set up checks for when update job finishes.
do_checks_after_update_finished_ = true;
@@ -1817,7 +1793,6 @@ class AppCacheUpdateJobTest : public testing::Test,
MockFrontend* frontend = MakeMockFrontend();
AppCacheHost* host = MakeHost(1, frontend);
update->StartUpdate(host, GURL());
- EXPECT_TRUE(update->manifest_fetcher_ != NULL);
// Set up checks for when update job finishes.
do_checks_after_update_finished_ = true;
@@ -1978,7 +1953,6 @@ class AppCacheUpdateJobTest : public testing::Test,
host2->AssociateCompleteCache(cache);
update->StartUpdate(NULL, GURL());
- EXPECT_TRUE(update->manifest_fetcher_ != NULL);
// Set up checks for when update job finishes.
do_checks_after_update_finished_ = true;
@@ -2008,9 +1982,6 @@ class AppCacheUpdateJobTest : public testing::Test,
AppCacheHost* host = MakeHost(1, frontend);
host->new_master_entry_url_ = GURL("http://failme/blah");
update->StartUpdate(host, host->new_master_entry_url_);
- EXPECT_TRUE(update->manifest_fetcher_ != NULL);
-
- update->manifest_fetcher_->request()->CancelWithError(-100);
// Set up checks for when update job finishes.
do_checks_after_update_finished_ = true;
@@ -2037,7 +2008,6 @@ class AppCacheUpdateJobTest : public testing::Test,
AppCacheHost* host = MakeHost(1, frontend);
host->new_master_entry_url_ = MockHttpServer::GetMockUrl("files/blah");
update->StartUpdate(host, host->new_master_entry_url_);
- EXPECT_TRUE(update->manifest_fetcher_ != NULL);
// Set up checks for when update job finishes.
do_checks_after_update_finished_ = true;
@@ -2067,7 +2037,6 @@ class AppCacheUpdateJobTest : public testing::Test,
host->new_master_entry_url_ = MockHttpServer::GetMockUrl("files/blah");
update->StartUpdate(host, host->new_master_entry_url_);
- EXPECT_TRUE(update->manifest_fetcher_ != NULL);
// Set up checks for when update job finishes.
do_checks_after_update_finished_ = true;
@@ -2097,7 +2066,6 @@ class AppCacheUpdateJobTest : public testing::Test,
MockHttpServer::GetMockUrl("files/explicit1");
update->StartUpdate(host, host->new_master_entry_url_);
- EXPECT_TRUE(update->manifest_fetcher_ != NULL);
// Set up checks for when update job finishes.
do_checks_after_update_finished_ = true;
@@ -2386,7 +2354,6 @@ class AppCacheUpdateJobTest : public testing::Test,
host1->new_master_entry_url_ =
MockHttpServer::GetMockUrl("files/explicit2");
update->StartUpdate(host1, host1->new_master_entry_url_);
- EXPECT_TRUE(update->manifest_fetcher_ != NULL);
// Set up additional updates to be started while update is in progress.
MockFrontend* frontend2 = MakeMockFrontend();
@@ -2484,7 +2451,6 @@ class AppCacheUpdateJobTest : public testing::Test,
host2->new_master_entry_url_ =
MockHttpServer::GetMockUrl("files/nosuchfile");
update->StartUpdate(host2, host2->new_master_entry_url_);
- EXPECT_TRUE(update->manifest_fetcher_ != NULL);
// Set up additional updates to be started while update is in progress.
MockFrontend* frontend3 = MakeMockFrontend();
diff --git a/chromium/content/browser/appcache/appcache_url_request_job.cc b/chromium/content/browser/appcache/appcache_url_request_job.cc
index b12a5b6db5f..9bf70e7c242 100644
--- a/chromium/content/browser/appcache/appcache_url_request_job.cc
+++ b/chromium/content/browser/appcache/appcache_url_request_job.cc
@@ -20,10 +20,10 @@
#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/log/net_log.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_status.h"
@@ -134,8 +134,8 @@ void AppCacheURLRequestJob::BeginDelivery() {
}
void AppCacheURLRequestJob::BeginExecutableHandlerDelivery() {
- DCHECK(CommandLine::ForCurrentProcess()->
- HasSwitch(kEnableExecutableHandlers));
+ DCHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
+ kEnableExecutableHandlers));
if (!storage_->service()->handler_factory()) {
BeginErrorDelivery("missing handler factory");
return;
diff --git a/chromium/content/browser/appcache/appcache_url_request_job.h b/chromium/content/browser/appcache/appcache_url_request_job.h
index 580b86a58a2..be30a5fa3c3 100644
--- a/chromium/content/browser/appcache/appcache_url_request_job.h
+++ b/chromium/content/browser/appcache/appcache_url_request_job.h
@@ -172,4 +172,4 @@ class CONTENT_EXPORT AppCacheURLRequestJob
} // namespace content
-#endif // CONTENT_BROWSER_APPCACHE_APPCACHE_REQUEST_HANDLER_H_
+#endif // CONTENT_BROWSER_APPCACHE_APPCACHE_URL_REQUEST_JOB_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 8acc71c7c9c..bd5ff7a6bca 100644
--- a/chromium/content/browser/appcache/appcache_url_request_job_unittest.cc
+++ b/chromium/content/browser/appcache/appcache_url_request_job_unittest.cc
@@ -430,7 +430,7 @@ class AppCacheURLRequestJobTest : public testing::Test {
void Basic() {
AppCacheStorage* storage = service_->storage();
scoped_ptr<net::URLRequest> request(empty_context_->CreateRequest(
- GURL("http://blah/"), net::DEFAULT_PRIORITY, NULL, NULL));
+ GURL("http://blah/"), net::DEFAULT_PRIORITY, NULL));
scoped_refptr<AppCacheURLRequestJob> job;
// Create an instance and see that it looks as expected.
@@ -453,7 +453,7 @@ class AppCacheURLRequestJobTest : public testing::Test {
void DeliveryOrders() {
AppCacheStorage* storage = service_->storage();
scoped_ptr<net::URLRequest> request(empty_context_->CreateRequest(
- GURL("http://blah/"), net::DEFAULT_PRIORITY, NULL, NULL));
+ GURL("http://blah/"), net::DEFAULT_PRIORITY, NULL));
scoped_refptr<AppCacheURLRequestJob> job;
// Create an instance, give it a delivery order and see that
@@ -499,8 +499,7 @@ class AppCacheURLRequestJobTest : public testing::Test {
AppCacheStorage* storage = service_->storage();
request_ = empty_context_->CreateRequest(GURL("http://blah/"),
net::DEFAULT_PRIORITY,
- url_request_delegate_.get(),
- NULL);
+ url_request_delegate_.get());
// Setup to create an AppCacheURLRequestJob with orders to deliver
// a network response.
@@ -536,8 +535,7 @@ class AppCacheURLRequestJobTest : public testing::Test {
AppCacheStorage* storage = service_->storage();
request_ = empty_context_->CreateRequest(GURL("http://blah/"),
net::DEFAULT_PRIORITY,
- url_request_delegate_.get(),
- NULL);
+ url_request_delegate_.get());
// Setup to create an AppCacheURLRequestJob with orders to deliver
// a network response.
@@ -588,8 +586,7 @@ class AppCacheURLRequestJobTest : public testing::Test {
AppCacheStorage* storage = service_->storage();
request_ = empty_context_->CreateRequest(GURL("http://blah/"),
net::DEFAULT_PRIORITY,
- url_request_delegate_.get(),
- NULL);
+ url_request_delegate_.get());
// Setup to create an AppCacheURLRequestJob with orders to deliver
// a network response.
@@ -703,8 +700,7 @@ class AppCacheURLRequestJobTest : public testing::Test {
AppCacheStorage* storage = service_->storage();
request_ = empty_context_->CreateRequest(GURL("http://blah/"),
net::DEFAULT_PRIORITY,
- url_request_delegate_.get(),
- NULL);
+ url_request_delegate_.get());
// Request a range, the 3 middle chars out of 'Hello'
net::HttpRequestHeaders extra_headers;
diff --git a/chromium/content/browser/appcache/chrome_appcache_service.cc b/chromium/content/browser/appcache/chrome_appcache_service.cc
index e4dbf7e00a1..11d107ce5a3 100644
--- a/chromium/content/browser/appcache/chrome_appcache_service.cc
+++ b/chromium/content/browser/appcache/chrome_appcache_service.cc
@@ -5,6 +5,7 @@
#include "content/browser/appcache/chrome_appcache_service.h"
#include "base/files/file_path.h"
+#include "base/profiler/scoped_tracker.h"
#include "content/browser/appcache/appcache_storage_impl.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
@@ -25,7 +26,11 @@ void ChromeAppCacheService::InitializeOnIOThread(
ResourceContext* resource_context,
net::URLRequestContextGetter* request_context_getter,
scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ // TODO(pkasting): Remove ScopedTracker below once crbug.com/477117 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "477117 ChromeAppCacheService::InitializeOnIOThread"));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
cache_path_ = cache_path;
resource_context_ = resource_context;
@@ -51,7 +56,7 @@ void ChromeAppCacheService::InitializeOnIOThread(
bool ChromeAppCacheService::CanLoadAppCache(const GURL& manifest_url,
const GURL& first_party) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
// We don't prompt for read access.
return GetContentClient()->browser()->AllowAppCache(
manifest_url, first_party, resource_context_);
@@ -59,7 +64,7 @@ bool ChromeAppCacheService::CanLoadAppCache(const GURL& manifest_url,
bool ChromeAppCacheService::CanCreateAppCache(
const GURL& manifest_url, const GURL& first_party) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
return GetContentClient()->browser()->AllowAppCache(
manifest_url, first_party, resource_context_);
}
diff --git a/chromium/content/browser/appcache/mock_appcache_storage.cc b/chromium/content/browser/appcache/mock_appcache_storage.cc
index 91630f7d351..2a337a0e4a2 100644
--- a/chromium/content/browser/appcache/mock_appcache_storage.cc
+++ b/chromium/content/browser/appcache/mock_appcache_storage.cc
@@ -165,6 +165,13 @@ AppCacheResponseWriter* MockAppCacheStorage::CreateResponseWriter(
return new AppCacheResponseWriter(NewResponseId(), group_id, disk_cache());
}
+AppCacheResponseMetadataWriter*
+MockAppCacheStorage::CreateResponseMetadataWriter(int64 group_id,
+ int64 response_id) {
+ return new AppCacheResponseMetadataWriter(response_id, group_id,
+ disk_cache());
+}
+
void MockAppCacheStorage::DoomResponses(
const GURL& manifest_url, const std::vector<int64>& response_ids) {
DeleteResponses(manifest_url, response_ids);
diff --git a/chromium/content/browser/appcache/mock_appcache_storage.h b/chromium/content/browser/appcache/mock_appcache_storage.h
index a6ece438ef1..7803ff7cc5a 100644
--- a/chromium/content/browser/appcache/mock_appcache_storage.h
+++ b/chromium/content/browser/appcache/mock_appcache_storage.h
@@ -72,6 +72,9 @@ class MockAppCacheStorage : public AppCacheStorage {
int64 response_id) override;
AppCacheResponseWriter* CreateResponseWriter(const GURL& manifest_url,
int64 group_id) override;
+ AppCacheResponseMetadataWriter* CreateResponseMetadataWriter(
+ int64 group_id,
+ int64 response_id) override;
void DoomResponses(const GURL& manifest_url,
const std::vector<int64>& response_ids) override;
void DeleteResponses(const GURL& manifest_url,
diff --git a/chromium/content/browser/appcache/view_appcache_internals_job.cc b/chromium/content/browser/appcache/view_appcache_internals_job.cc
index 5e793bbb760..84912b733d4 100644
--- a/chromium/content/browser/appcache/view_appcache_internals_job.cc
+++ b/chromium/content/browser/appcache/view_appcache_internals_job.cc
@@ -13,7 +13,6 @@
#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"
@@ -358,10 +357,6 @@ class MainPageJob : public BaseInternalsJob {
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");
@@ -483,10 +478,6 @@ class ViewAppCacheJob : public BaseInternalsJob,
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();
@@ -562,10 +553,6 @@ class ViewEntryJob : public BaseInternalsJob,
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();
diff --git a/chromium/content/browser/background_sync/BUILD.gn b/chromium/content/browser/background_sync/BUILD.gn
new file mode 100644
index 00000000000..55aeded7a53
--- /dev/null
+++ b/chromium/content/browser/background_sync/BUILD.gn
@@ -0,0 +1,11 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/protobuf/proto_library.gni")
+
+proto_library("background_sync_proto") {
+ sources = [
+ "background_sync.proto",
+ ]
+}
diff --git a/chromium/content/browser/background_sync/OWNERS b/chromium/content/browser/background_sync/OWNERS
new file mode 100644
index 00000000000..1e6deee91b7
--- /dev/null
+++ b/chromium/content/browser/background_sync/OWNERS
@@ -0,0 +1 @@
+jkarlin@chromium.org
diff --git a/chromium/content/browser/background_sync/PRESUBMIT.py b/chromium/content/browser/background_sync/PRESUBMIT.py
new file mode 100644
index 00000000000..192a8c4aa39
--- /dev/null
+++ b/chromium/content/browser/background_sync/PRESUBMIT.py
@@ -0,0 +1,12 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Top-level presubmit script for src/content/browser/background_sync/
+
+See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
+for more details about the presubmit API built into depot_tools.
+"""
+
+def CheckChangeOnUpload(input_api, output_api):
+ return input_api.canned_checks.CheckPatchFormatted(input_api, output_api)
diff --git a/chromium/content/browser/background_sync/background_sync.proto b/chromium/content/browser/background_sync/background_sync.proto
new file mode 100644
index 00000000000..eb9b4ad229b
--- /dev/null
+++ b/chromium/content/browser/background_sync/background_sync.proto
@@ -0,0 +1,47 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package content;
+
+enum SyncNetworkState {
+ NETWORK_STATE_ANY = 0;
+ NETWORK_STATE_AVOID_CELLULAR = 1;
+ NETWORK_STATE_ONLINE = 2;
+}
+
+enum SyncPowerState {
+ POWER_STATE_AUTO = 0;
+ POWER_STATE_AVOID_DRAINING = 1;
+}
+
+enum SyncPeriodicity {
+ SYNC_PERIODIC = 0;
+ SYNC_ONE_SHOT = 1;
+}
+
+enum SyncState {
+ SYNC_STATE_PENDING = 0;
+ SYNC_STATE_FIRING = 1;
+ SYNC_STATE_FAILED = 2;
+}
+
+message BackgroundSyncRegistrationProto {
+ required int64 id = 1;
+ required string tag = 2;
+ required SyncPeriodicity periodicity = 3;
+ required int64 min_period = 4;
+ required SyncNetworkState network_state = 5;
+ required SyncPowerState power_state = 6;
+ required SyncState sync_state = 7;
+}
+
+message BackgroundSyncRegistrationsProto {
+ repeated BackgroundSyncRegistrationProto registration = 1;
+ required int64 next_registration_id = 2;
+ required string origin = 3;
+} \ No newline at end of file
diff --git a/chromium/content/browser/background_sync/background_sync_context_impl.cc b/chromium/content/browser/background_sync/background_sync_context_impl.cc
new file mode 100644
index 00000000000..31ad2a0a99c
--- /dev/null
+++ b/chromium/content/browser/background_sync/background_sync_context_impl.cc
@@ -0,0 +1,60 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/background_sync/background_sync_context_impl.h"
+
+#include "base/bind.h"
+#include "content/browser/background_sync/background_sync_manager.h"
+#include "content/browser/service_worker/service_worker_context_wrapper.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace content {
+
+BackgroundSyncContextImpl::BackgroundSyncContextImpl() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+}
+
+BackgroundSyncContextImpl::~BackgroundSyncContextImpl() {
+}
+
+void BackgroundSyncContextImpl::Init(
+ const scoped_refptr<ServiceWorkerContextWrapper>& context) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&BackgroundSyncContextImpl::CreateBackgroundSyncManager, this,
+ context));
+}
+
+void BackgroundSyncContextImpl::Shutdown() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&BackgroundSyncContextImpl::ShutdownOnIO, this));
+}
+
+BackgroundSyncManager* BackgroundSyncContextImpl::background_sync_manager()
+ const {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ return background_sync_manager_.get();
+}
+
+void BackgroundSyncContextImpl::CreateBackgroundSyncManager(
+ const scoped_refptr<ServiceWorkerContextWrapper>& context) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(!background_sync_manager_);
+
+ background_sync_manager_ = BackgroundSyncManager::Create(context);
+}
+
+void BackgroundSyncContextImpl::ShutdownOnIO() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ background_sync_manager_.reset();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/background_sync/background_sync_context_impl.h b/chromium/content/browser/background_sync/background_sync_context_impl.h
new file mode 100644
index 00000000000..4cf34902698
--- /dev/null
+++ b/chromium/content/browser/background_sync/background_sync_context_impl.h
@@ -0,0 +1,53 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_BACKGROUND_SYNC_BACKGROUND_SYNC_CONTEXT_IMPL_H_
+#define CONTENT_BROWSER_BACKGROUND_SYNC_BACKGROUND_SYNC_CONTEXT_IMPL_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/common/content_export.h"
+
+namespace content {
+
+class BackgroundSyncManager;
+class ServiceWorkerContextWrapper;
+
+// One instance of this exists per StoragePartition, and services multiple
+// child processes/origins. Most logic is delegated to the owned
+// BackgroundSyncManager instance, which is only accessed on the IO
+// thread.
+// TODO(jkarlin): Make a public/ BackgroundSyncContext.
+class CONTENT_EXPORT BackgroundSyncContextImpl
+ : public base::RefCountedThreadSafe<BackgroundSyncContextImpl> {
+ public:
+ BackgroundSyncContextImpl();
+
+ // Init and Shutdown are for use on the UI thread when the profile,
+ // storagepartition is being setup and torn down.
+ void Init(const scoped_refptr<ServiceWorkerContextWrapper>& context);
+ void Shutdown();
+
+ // Only callable on the IO thread.
+ BackgroundSyncManager* background_sync_manager() const;
+
+ private:
+ friend class base::RefCountedThreadSafe<BackgroundSyncContextImpl>;
+
+ ~BackgroundSyncContextImpl();
+
+ void CreateBackgroundSyncManager(
+ const scoped_refptr<ServiceWorkerContextWrapper>& context);
+
+ void ShutdownOnIO();
+
+ // Only accessed on the IO thread.
+ scoped_ptr<BackgroundSyncManager> background_sync_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(BackgroundSyncContextImpl);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_BACKGROUND_SYNC_BACKGROUND_SYNC_CONTEXT_IMPL_H_
diff --git a/chromium/content/browser/background_sync/background_sync_manager.cc b/chromium/content/browser/background_sync/background_sync_manager.cc
new file mode 100644
index 00000000000..dd4f2f86cb0
--- /dev/null
+++ b/chromium/content/browser/background_sync/background_sync_manager.cc
@@ -0,0 +1,881 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/background_sync/background_sync_manager.h"
+
+#include "base/barrier_closure.h"
+#include "base/bind.h"
+#include "content/browser/background_sync/background_sync_network_observer.h"
+#include "content/browser/service_worker/service_worker_context_wrapper.h"
+#include "content/browser/service_worker/service_worker_storage.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace {
+const char kBackgroundSyncUserDataKey[] = "BackgroundSyncUserData";
+}
+
+namespace content {
+
+const BackgroundSyncManager::BackgroundSyncRegistration::RegistrationId
+ BackgroundSyncManager::BackgroundSyncRegistration::kInvalidRegistrationId =
+ -1;
+
+const BackgroundSyncManager::BackgroundSyncRegistration::RegistrationId
+ BackgroundSyncManager::BackgroundSyncRegistration::kInitialId = 0;
+
+BackgroundSyncManager::BackgroundSyncRegistrations::
+ BackgroundSyncRegistrations()
+ : next_id(BackgroundSyncRegistration::kInitialId) {
+}
+
+BackgroundSyncManager::BackgroundSyncRegistrations::
+ ~BackgroundSyncRegistrations() {
+}
+
+// static
+scoped_ptr<BackgroundSyncManager> BackgroundSyncManager::Create(
+ const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ BackgroundSyncManager* sync_manager =
+ new BackgroundSyncManager(service_worker_context);
+ sync_manager->Init();
+ return make_scoped_ptr(sync_manager);
+}
+
+BackgroundSyncManager::~BackgroundSyncManager() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ service_worker_context_->RemoveObserver(this);
+}
+
+BackgroundSyncManager::RegistrationKey::RegistrationKey(
+ const BackgroundSyncRegistration& registration)
+ : RegistrationKey(registration.tag, registration.periodicity) {
+}
+
+BackgroundSyncManager::RegistrationKey::RegistrationKey(
+ const std::string& tag,
+ SyncPeriodicity periodicity)
+ : value_(periodicity == SYNC_ONE_SHOT ? "o_" + tag : "p_" + tag) {
+}
+
+void BackgroundSyncManager::Register(
+ int64 sw_registration_id,
+ const BackgroundSyncRegistration& sync_registration,
+ const StatusAndRegistrationCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK_EQ(BackgroundSyncRegistration::kInvalidRegistrationId,
+ sync_registration.id);
+
+ if (disabled_) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
+ return;
+ }
+
+ op_scheduler_.ScheduleOperation(base::Bind(
+ &BackgroundSyncManager::RegisterImpl, weak_ptr_factory_.GetWeakPtr(),
+ sw_registration_id, sync_registration,
+ MakeStatusAndRegistrationCompletion(callback)));
+}
+
+void BackgroundSyncManager::Unregister(
+ int64 sw_registration_id,
+ const std::string& sync_registration_tag,
+ SyncPeriodicity periodicity,
+ BackgroundSyncRegistration::RegistrationId sync_registration_id,
+ const StatusCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (disabled_) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE));
+ return;
+ }
+
+ RegistrationKey registration_key(sync_registration_tag, periodicity);
+
+ op_scheduler_.ScheduleOperation(base::Bind(
+ &BackgroundSyncManager::UnregisterImpl, weak_ptr_factory_.GetWeakPtr(),
+ sw_registration_id, registration_key, sync_registration_id,
+ MakeStatusCompletion(callback)));
+}
+
+void BackgroundSyncManager::GetRegistration(
+ int64 sw_registration_id,
+ const std::string& sync_registration_tag,
+ SyncPeriodicity periodicity,
+ const StatusAndRegistrationCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (disabled_) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
+ return;
+ }
+
+ RegistrationKey registration_key(sync_registration_tag, periodicity);
+
+ op_scheduler_.ScheduleOperation(base::Bind(
+ &BackgroundSyncManager::GetRegistrationImpl,
+ weak_ptr_factory_.GetWeakPtr(), sw_registration_id, registration_key,
+ MakeStatusAndRegistrationCompletion(callback)));
+}
+
+void BackgroundSyncManager::GetRegistrations(
+ int64 sw_registration_id,
+ SyncPeriodicity periodicity,
+ const StatusAndRegistrationsCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (disabled_) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE,
+ std::vector<BackgroundSyncRegistration>()));
+ return;
+ }
+
+ op_scheduler_.ScheduleOperation(
+ base::Bind(&BackgroundSyncManager::GetRegistrationsImpl,
+ weak_ptr_factory_.GetWeakPtr(), sw_registration_id,
+ periodicity, MakeStatusAndRegistrationsCompletion(callback)));
+}
+
+void BackgroundSyncManager::OnRegistrationDeleted(int64 registration_id,
+ const GURL& pattern) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ // Operations already in the queue will either fail when they write to storage
+ // or return stale results based on registrations loaded in memory. This is
+ // inconsequential since the service worker is gone.
+ op_scheduler_.ScheduleOperation(base::Bind(
+ &BackgroundSyncManager::OnRegistrationDeletedImpl,
+ weak_ptr_factory_.GetWeakPtr(), registration_id, MakeEmptyCompletion()));
+}
+
+void BackgroundSyncManager::OnStorageWiped() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ // Operations already in the queue will either fail when they write to storage
+ // or return stale results based on registrations loaded in memory. This is
+ // inconsequential since the service workers are gone.
+ op_scheduler_.ScheduleOperation(
+ base::Bind(&BackgroundSyncManager::OnStorageWipedImpl,
+ weak_ptr_factory_.GetWeakPtr(), MakeEmptyCompletion()));
+}
+
+BackgroundSyncManager::BackgroundSyncManager(
+ const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context)
+ : service_worker_context_(service_worker_context),
+ disabled_(false),
+ weak_ptr_factory_(this) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ service_worker_context_->AddObserver(this);
+
+ network_observer_.reset(new BackgroundSyncNetworkObserver(
+ base::Bind(&BackgroundSyncManager::OnNetworkChanged,
+ weak_ptr_factory_.GetWeakPtr())));
+}
+
+void BackgroundSyncManager::Init() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(!op_scheduler_.ScheduledOperations());
+ DCHECK(!disabled_);
+
+ op_scheduler_.ScheduleOperation(base::Bind(&BackgroundSyncManager::InitImpl,
+ weak_ptr_factory_.GetWeakPtr(),
+ MakeEmptyCompletion()));
+}
+
+void BackgroundSyncManager::InitImpl(const base::Closure& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (disabled_) {
+ base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
+ return;
+ }
+
+ GetDataFromBackend(
+ kBackgroundSyncUserDataKey,
+ base::Bind(&BackgroundSyncManager::InitDidGetDataFromBackend,
+ weak_ptr_factory_.GetWeakPtr(), callback));
+}
+
+void BackgroundSyncManager::InitDidGetDataFromBackend(
+ const base::Closure& callback,
+ const std::vector<std::pair<int64, std::string>>& user_data,
+ ServiceWorkerStatusCode status) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (status != SERVICE_WORKER_OK && status != SERVICE_WORKER_ERROR_NOT_FOUND) {
+ LOG(ERROR) << "BackgroundSync failed to init due to backend failure.";
+ DisableAndClearManager(base::Bind(callback));
+ return;
+ }
+
+ bool corruption_detected = false;
+ for (const std::pair<int64, std::string>& data : user_data) {
+ BackgroundSyncRegistrationsProto registrations_proto;
+ if (registrations_proto.ParseFromString(data.second)) {
+ BackgroundSyncRegistrations* registrations =
+ &sw_to_registrations_map_[data.first];
+ registrations->next_id = registrations_proto.next_registration_id();
+ registrations->origin = GURL(registrations_proto.origin());
+
+ for (int i = 0, max = registrations_proto.registration_size(); i < max;
+ ++i) {
+ const BackgroundSyncRegistrationProto& registration_proto =
+ registrations_proto.registration(i);
+
+ if (registration_proto.id() >= registrations->next_id) {
+ corruption_detected = true;
+ break;
+ }
+
+ RegistrationKey registration_key(registration_proto.tag(),
+ registration_proto.periodicity());
+ BackgroundSyncRegistration* registration =
+ &registrations->registration_map[registration_key];
+
+ registration->id = registration_proto.id();
+ registration->tag = registration_proto.tag();
+ registration->periodicity = registration_proto.periodicity();
+ registration->min_period = registration_proto.min_period();
+ registration->network_state = registration_proto.network_state();
+ registration->power_state = registration_proto.power_state();
+ registration->sync_state = registration_proto.sync_state();
+ if (registration->sync_state == SYNC_STATE_FIRING) {
+ // If the browser (or worker) closed while firing the event, consider
+ // it pending again>
+ registration->sync_state = SYNC_STATE_PENDING;
+ }
+ }
+ }
+
+ if (corruption_detected)
+ break;
+ }
+
+ if (corruption_detected) {
+ LOG(ERROR) << "Corruption detected in background sync backend";
+ DisableAndClearManager(base::Bind(callback));
+ return;
+ }
+
+ FireReadyEvents();
+
+ base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
+}
+
+void BackgroundSyncManager::RegisterImpl(
+ int64 sw_registration_id,
+ const BackgroundSyncRegistration& sync_registration,
+ const StatusAndRegistrationCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (disabled_) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
+ return;
+ }
+
+ const BackgroundSyncRegistration* existing_registration = LookupRegistration(
+ sw_registration_id, RegistrationKey(sync_registration));
+ if (existing_registration &&
+ existing_registration->Equals(sync_registration)) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(callback, ERROR_TYPE_OK, *existing_registration));
+ return;
+ }
+
+ BackgroundSyncRegistration new_registration = sync_registration;
+ BackgroundSyncRegistrations* registrations =
+ &sw_to_registrations_map_[sw_registration_id];
+ new_registration.id = registrations->next_id++;
+
+ ServiceWorkerRegistration* sw_registration =
+ service_worker_context_->GetLiveRegistration(sw_registration_id);
+ if (!sw_registration || !sw_registration->active_version()) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(callback, ERROR_TYPE_NO_SERVICE_WORKER,
+ BackgroundSyncRegistration()));
+ return;
+ }
+
+ AddRegistrationToMap(sw_registration_id,
+ sw_registration->pattern().GetOrigin(),
+ new_registration);
+
+ StoreRegistrations(
+ sw_registration_id,
+ base::Bind(&BackgroundSyncManager::RegisterDidStore,
+ weak_ptr_factory_.GetWeakPtr(), sw_registration_id,
+ new_registration, callback));
+}
+
+void BackgroundSyncManager::DisableAndClearManager(
+ const base::Closure& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (disabled_) {
+ base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
+ return;
+ }
+
+ disabled_ = true;
+ sw_to_registrations_map_.clear();
+
+ // Delete all backend entries. The memory representation of registered syncs
+ // may be out of sync with storage (e.g., due to corruption detection on
+ // loading from storage), so reload the registrations from storage again.
+ GetDataFromBackend(
+ kBackgroundSyncUserDataKey,
+ base::Bind(&BackgroundSyncManager::DisableAndClearDidGetRegistrations,
+ weak_ptr_factory_.GetWeakPtr(), callback));
+}
+
+void BackgroundSyncManager::DisableAndClearDidGetRegistrations(
+ const base::Closure& callback,
+ const std::vector<std::pair<int64, std::string>>& user_data,
+ ServiceWorkerStatusCode status) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (status != SERVICE_WORKER_OK || user_data.empty()) {
+ base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
+ return;
+ }
+
+ base::Closure barrier_closure =
+ base::BarrierClosure(user_data.size(), base::Bind(callback));
+
+ for (const auto& sw_id_and_regs : user_data) {
+ service_worker_context_->ClearRegistrationUserData(
+ sw_id_and_regs.first, kBackgroundSyncUserDataKey,
+ base::Bind(&BackgroundSyncManager::DisableAndClearManagerClearedOne,
+ weak_ptr_factory_.GetWeakPtr(), barrier_closure));
+ }
+}
+
+void BackgroundSyncManager::DisableAndClearManagerClearedOne(
+ const base::Closure& barrier_closure,
+ ServiceWorkerStatusCode status) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ // The status doesn't matter at this point, there is nothing else to be done.
+ base::MessageLoop::current()->PostTask(FROM_HERE,
+ base::Bind(barrier_closure));
+}
+
+BackgroundSyncManager::BackgroundSyncRegistration*
+BackgroundSyncManager::LookupRegistration(
+ int64 sw_registration_id,
+ const RegistrationKey& registration_key) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ SWIdToRegistrationsMap::iterator it =
+ sw_to_registrations_map_.find(sw_registration_id);
+ if (it == sw_to_registrations_map_.end())
+ return nullptr;
+
+ BackgroundSyncRegistrations& registrations = it->second;
+ DCHECK_LE(BackgroundSyncRegistration::kInitialId, registrations.next_id);
+ DCHECK(!registrations.origin.is_empty());
+
+ auto key_and_registration_iter =
+ registrations.registration_map.find(registration_key);
+ if (key_and_registration_iter == registrations.registration_map.end())
+ return nullptr;
+
+ return &key_and_registration_iter->second;
+}
+
+void BackgroundSyncManager::StoreRegistrations(
+ int64 sw_registration_id,
+ const ServiceWorkerStorage::StatusCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ // Serialize the data.
+ const BackgroundSyncRegistrations& registrations =
+ sw_to_registrations_map_[sw_registration_id];
+ BackgroundSyncRegistrationsProto registrations_proto;
+ registrations_proto.set_next_registration_id(registrations.next_id);
+ registrations_proto.set_origin(registrations.origin.spec());
+
+ for (const auto& key_and_registration : registrations.registration_map) {
+ const BackgroundSyncRegistration& registration =
+ key_and_registration.second;
+ BackgroundSyncRegistrationProto* registration_proto =
+ registrations_proto.add_registration();
+ registration_proto->set_id(registration.id);
+ registration_proto->set_tag(registration.tag);
+ registration_proto->set_periodicity(registration.periodicity);
+ registration_proto->set_min_period(registration.min_period);
+ registration_proto->set_network_state(registration.network_state);
+ registration_proto->set_power_state(registration.power_state);
+ registration_proto->set_sync_state(registration.sync_state);
+ }
+ std::string serialized;
+ bool success = registrations_proto.SerializeToString(&serialized);
+ DCHECK(success);
+
+ StoreDataInBackend(sw_registration_id, registrations.origin,
+ kBackgroundSyncUserDataKey, serialized, callback);
+}
+
+void BackgroundSyncManager::RegisterDidStore(
+ int64 sw_registration_id,
+ const BackgroundSyncRegistration& new_registration,
+ const StatusAndRegistrationCallback& callback,
+ ServiceWorkerStatusCode status) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (status == SERVICE_WORKER_ERROR_NOT_FOUND) {
+ // The registration is gone.
+ sw_to_registrations_map_.erase(sw_registration_id);
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
+ return;
+ }
+
+ if (status != SERVICE_WORKER_OK) {
+ LOG(ERROR) << "BackgroundSync failed to store registration due to backend "
+ "failure.";
+ DisableAndClearManager(
+ base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
+ return;
+ }
+
+ FireReadyEvents();
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(callback, ERROR_TYPE_OK, new_registration));
+}
+
+void BackgroundSyncManager::RemoveRegistrationFromMap(
+ int64 sw_registration_id,
+ const RegistrationKey& registration_key) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(LookupRegistration(sw_registration_id, registration_key));
+
+ BackgroundSyncRegistrations* registrations =
+ &sw_to_registrations_map_[sw_registration_id];
+
+ registrations->registration_map.erase(registration_key);
+}
+
+void BackgroundSyncManager::AddRegistrationToMap(
+ int64 sw_registration_id,
+ const GURL& origin,
+ const BackgroundSyncRegistration& sync_registration) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK_NE(BackgroundSyncRegistration::kInvalidRegistrationId,
+ sw_registration_id);
+
+ BackgroundSyncRegistrations* registrations =
+ &sw_to_registrations_map_[sw_registration_id];
+ registrations->origin = origin;
+
+ RegistrationKey registration_key(sync_registration);
+ registrations->registration_map[registration_key] = sync_registration;
+}
+
+void BackgroundSyncManager::StoreDataInBackend(
+ int64 sw_registration_id,
+ const GURL& origin,
+ const std::string& backend_key,
+ const std::string& data,
+ const ServiceWorkerStorage::StatusCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ service_worker_context_->StoreRegistrationUserData(
+ sw_registration_id, origin, backend_key, data, callback);
+}
+
+void BackgroundSyncManager::GetDataFromBackend(
+ const std::string& backend_key,
+ const ServiceWorkerStorage::GetUserDataForAllRegistrationsCallback&
+ callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ service_worker_context_->GetUserDataForAllRegistrations(backend_key,
+ callback);
+}
+
+void BackgroundSyncManager::FireOneShotSync(
+ const scoped_refptr<ServiceWorkerVersion>& active_version,
+ const ServiceWorkerVersion::StatusCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ active_version->DispatchSyncEvent(callback);
+}
+
+void BackgroundSyncManager::UnregisterImpl(
+ int64 sw_registration_id,
+ const RegistrationKey& registration_key,
+ BackgroundSyncRegistration::RegistrationId sync_registration_id,
+ const StatusCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (disabled_) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE));
+ return;
+ }
+
+ const BackgroundSyncRegistration* existing_registration =
+ LookupRegistration(sw_registration_id, registration_key);
+ if (!existing_registration ||
+ existing_registration->id != sync_registration_id) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(callback, ERROR_TYPE_NOT_FOUND));
+ return;
+ }
+
+ RemoveRegistrationFromMap(sw_registration_id, registration_key);
+
+ StoreRegistrations(
+ sw_registration_id,
+ base::Bind(&BackgroundSyncManager::UnregisterDidStore,
+ weak_ptr_factory_.GetWeakPtr(), sw_registration_id, callback));
+}
+
+void BackgroundSyncManager::UnregisterDidStore(
+ int64 sw_registration_id,
+ const StatusCallback& callback,
+ ServiceWorkerStatusCode status) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (status == SERVICE_WORKER_ERROR_NOT_FOUND) {
+ // ServiceWorker was unregistered.
+ sw_to_registrations_map_.erase(sw_registration_id);
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE));
+ return;
+ }
+
+ if (status != SERVICE_WORKER_OK) {
+ LOG(ERROR) << "BackgroundSync failed to unregister due to backend failure.";
+ DisableAndClearManager(base::Bind(callback, ERROR_TYPE_STORAGE));
+ return;
+ }
+
+ base::MessageLoop::current()->PostTask(FROM_HERE,
+ base::Bind(callback, ERROR_TYPE_OK));
+}
+
+void BackgroundSyncManager::GetRegistrationImpl(
+ int64 sw_registration_id,
+ const RegistrationKey& registration_key,
+ const StatusAndRegistrationCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (disabled_) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
+ return;
+ }
+
+ const BackgroundSyncRegistration* out_registration =
+ LookupRegistration(sw_registration_id, registration_key);
+ if (!out_registration) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(callback, ERROR_TYPE_NOT_FOUND,
+ BackgroundSyncRegistration()));
+ return;
+ }
+
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(callback, ERROR_TYPE_OK, *out_registration));
+}
+
+void BackgroundSyncManager::GetRegistrationsImpl(
+ int64 sw_registration_id,
+ SyncPeriodicity periodicity,
+ const StatusAndRegistrationsCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ std::vector<BackgroundSyncRegistration> out_registrations;
+
+ if (disabled_) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE, out_registrations));
+ return;
+ }
+
+ SWIdToRegistrationsMap::iterator it =
+ sw_to_registrations_map_.find(sw_registration_id);
+
+ if (it != sw_to_registrations_map_.end()) {
+ const BackgroundSyncRegistrations& registrations = it->second;
+ for (const auto& tag_and_registration : registrations.registration_map) {
+ const BackgroundSyncRegistration& registration =
+ tag_and_registration.second;
+ if (registration.periodicity == periodicity)
+ out_registrations.push_back(registration);
+ }
+ }
+
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(callback, ERROR_TYPE_OK, out_registrations));
+}
+
+bool BackgroundSyncManager::IsRegistrationReadyToFire(
+ const BackgroundSyncRegistration& registration) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ // TODO(jkarlin): Add support for firing periodic registrations.
+ if (registration.periodicity == SYNC_PERIODIC)
+ return false;
+
+ if (registration.sync_state != SYNC_STATE_PENDING)
+ return false;
+
+ DCHECK_EQ(SYNC_ONE_SHOT, registration.periodicity);
+
+ return network_observer_->NetworkSufficient(registration.network_state);
+}
+
+void BackgroundSyncManager::FireReadyEvents() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (disabled_)
+ return;
+
+ op_scheduler_.ScheduleOperation(
+ base::Bind(&BackgroundSyncManager::FireReadyEventsImpl,
+ weak_ptr_factory_.GetWeakPtr(), MakeEmptyCompletion()));
+}
+
+void BackgroundSyncManager::FireReadyEventsImpl(const base::Closure& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (disabled_) {
+ base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
+ return;
+ }
+
+ // Find the registrations that are ready to run.
+ std::vector<std::pair<int64, RegistrationKey>> sw_id_and_keys_to_fire;
+
+ for (auto& sw_id_and_registrations : sw_to_registrations_map_) {
+ const int64 service_worker_id = sw_id_and_registrations.first;
+ for (auto& key_and_registration :
+ sw_id_and_registrations.second.registration_map) {
+ BackgroundSyncRegistration* registration = &key_and_registration.second;
+ if (IsRegistrationReadyToFire(*registration)) {
+ sw_id_and_keys_to_fire.push_back(
+ std::make_pair(service_worker_id, key_and_registration.first));
+ // The state change is not saved to persistent storage because
+ // if the sync event is killed mid-sync then it should return to
+ // SYNC_STATE_PENDING.
+ registration->sync_state = SYNC_STATE_FIRING;
+ }
+ }
+ }
+
+ // Fire the sync event of the ready registrations and run |callback| once
+ // they're all done.
+ base::Closure barrier_closure =
+ base::BarrierClosure(sw_id_and_keys_to_fire.size(), base::Bind(callback));
+
+ for (const auto& sw_id_and_key : sw_id_and_keys_to_fire) {
+ int64 service_worker_id = sw_id_and_key.first;
+ const BackgroundSyncRegistration* registration =
+ LookupRegistration(service_worker_id, sw_id_and_key.second);
+
+ service_worker_context_->FindRegistrationForId(
+ service_worker_id, sw_to_registrations_map_[service_worker_id].origin,
+ base::Bind(&BackgroundSyncManager::FireReadyEventsDidFindRegistration,
+ weak_ptr_factory_.GetWeakPtr(), sw_id_and_key.second,
+ registration->id, barrier_closure));
+ }
+}
+
+void BackgroundSyncManager::FireReadyEventsDidFindRegistration(
+ const RegistrationKey& registration_key,
+ BackgroundSyncRegistration::RegistrationId registration_id,
+ const base::Closure& callback,
+ ServiceWorkerStatusCode service_worker_status,
+ const scoped_refptr<ServiceWorkerRegistration>&
+ service_worker_registration) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (service_worker_status != SERVICE_WORKER_OK) {
+ base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
+ return;
+ }
+
+ FireOneShotSync(
+ service_worker_registration->active_version(),
+ base::Bind(&BackgroundSyncManager::EventComplete,
+ weak_ptr_factory_.GetWeakPtr(), service_worker_registration,
+ service_worker_registration->id(), registration_key,
+ registration_id));
+
+ base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
+}
+
+// |service_worker_registration| is just to keep the registration alive
+// while the event is firing.
+void BackgroundSyncManager::EventComplete(
+ const scoped_refptr<ServiceWorkerRegistration>& service_worker_registration,
+ int64 service_worker_id,
+ const RegistrationKey& key,
+ BackgroundSyncRegistration::RegistrationId sync_registration_id,
+ ServiceWorkerStatusCode status_code) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (disabled_)
+ return;
+
+ op_scheduler_.ScheduleOperation(
+ base::Bind(&BackgroundSyncManager::EventCompleteImpl,
+ weak_ptr_factory_.GetWeakPtr(), service_worker_id, key,
+ sync_registration_id, status_code, MakeEmptyCompletion()));
+}
+
+void BackgroundSyncManager::EventCompleteImpl(
+ int64 service_worker_id,
+ const RegistrationKey& key,
+ BackgroundSyncRegistration::RegistrationId sync_registration_id,
+ ServiceWorkerStatusCode status_code,
+ const base::Closure& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (disabled_) {
+ base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
+ return;
+ }
+
+ BackgroundSyncRegistration* registration =
+ LookupRegistration(service_worker_id, key);
+ if (!registration || registration->id != sync_registration_id) {
+ base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
+ return;
+ }
+
+ if (registration->periodicity == SYNC_ONE_SHOT) {
+ if (status_code != SERVICE_WORKER_OK) {
+ // TODO(jkarlin) Fire the sync event on the next page load controlled by
+ // this registration. (crbug.com/479665)
+ registration->sync_state = SYNC_STATE_FAILED;
+ } else {
+ registration = nullptr;
+ RemoveRegistrationFromMap(service_worker_id, key);
+ }
+ } else {
+ // TODO(jkarlin): Add support for running periodic syncs. (crbug.com/479674)
+ NOTREACHED();
+ }
+
+ StoreRegistrations(
+ service_worker_id,
+ base::Bind(&BackgroundSyncManager::EventCompleteDidStore,
+ weak_ptr_factory_.GetWeakPtr(), service_worker_id, callback));
+}
+
+void BackgroundSyncManager::EventCompleteDidStore(
+ int64 service_worker_id,
+ const base::Closure& callback,
+ ServiceWorkerStatusCode status_code) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (status_code == SERVICE_WORKER_ERROR_NOT_FOUND) {
+ // The registration is gone.
+ sw_to_registrations_map_.erase(service_worker_id);
+ base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
+ return;
+ }
+
+ if (status_code != SERVICE_WORKER_OK) {
+ LOG(ERROR) << "BackgroundSync failed to store registration due to backend "
+ "failure.";
+ DisableAndClearManager(base::Bind(callback));
+ return;
+ }
+
+ base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
+}
+
+void BackgroundSyncManager::OnRegistrationDeletedImpl(
+ int64 registration_id,
+ const base::Closure& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ // The backend (ServiceWorkerStorage) will delete the data, so just delete the
+ // memory representation here.
+ sw_to_registrations_map_.erase(registration_id);
+ base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
+}
+
+void BackgroundSyncManager::OnStorageWipedImpl(const base::Closure& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ sw_to_registrations_map_.clear();
+ disabled_ = false;
+ InitImpl(callback);
+}
+
+void BackgroundSyncManager::OnNetworkChanged() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ FireReadyEvents();
+}
+
+template <typename CallbackT, typename... Params>
+void BackgroundSyncManager::CompleteOperationCallback(const CallbackT& callback,
+ Params... parameters) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ callback.Run(parameters...);
+ op_scheduler_.CompleteOperationAndRunNext();
+}
+
+base::Closure BackgroundSyncManager::MakeEmptyCompletion() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ return base::Bind(
+ &BackgroundSyncManager::CompleteOperationCallback<base::Closure>,
+ weak_ptr_factory_.GetWeakPtr(), base::Bind(base::DoNothing));
+}
+
+BackgroundSyncManager::StatusAndRegistrationCallback
+BackgroundSyncManager::MakeStatusAndRegistrationCompletion(
+ const StatusAndRegistrationCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ return base::Bind(&BackgroundSyncManager::CompleteOperationCallback<
+ StatusAndRegistrationCallback, ErrorType,
+ const BackgroundSyncRegistration&>,
+ weak_ptr_factory_.GetWeakPtr(), callback);
+}
+
+BackgroundSyncManager::StatusAndRegistrationsCallback
+BackgroundSyncManager::MakeStatusAndRegistrationsCompletion(
+ const StatusAndRegistrationsCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ return base::Bind(&BackgroundSyncManager::CompleteOperationCallback<
+ StatusAndRegistrationsCallback, ErrorType,
+ const std::vector<BackgroundSyncRegistration>&>,
+ weak_ptr_factory_.GetWeakPtr(), callback);
+}
+
+BackgroundSyncManager::StatusCallback
+BackgroundSyncManager::MakeStatusCompletion(const StatusCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ return base::Bind(
+ &BackgroundSyncManager::CompleteOperationCallback<StatusCallback,
+ ErrorType>,
+ weak_ptr_factory_.GetWeakPtr(), callback);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/background_sync/background_sync_manager.h b/chromium/content/browser/background_sync/background_sync_manager.h
new file mode 100644
index 00000000000..f9c8960fdff
--- /dev/null
+++ b/chromium/content/browser/background_sync/background_sync_manager.h
@@ -0,0 +1,317 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_BACKGROUND_SYNC_BACKGROUND_SYNC_MANAGER_H_
+#define CONTENT_BROWSER_BACKGROUND_SYNC_BACKGROUND_SYNC_MANAGER_H_
+
+#include <map>
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "content/browser/background_sync/background_sync.pb.h"
+#include "content/browser/cache_storage/cache_storage_scheduler.h"
+#include "content/browser/service_worker/service_worker_context_observer.h"
+#include "content/browser/service_worker/service_worker_storage.h"
+#include "content/common/content_export.h"
+#include "content/common/service_worker/service_worker_status_code.h"
+#include "url/gurl.h"
+
+namespace content {
+
+class BackgroundSyncNetworkObserver;
+class ServiceWorkerContextWrapper;
+
+// BackgroundSyncManager manages and stores the set of background sync
+// registrations across all registered service workers for a profile.
+// Registrations are stored along with their associated Service Worker
+// registration in ServiceWorkerStorage. If the ServiceWorker is unregistered,
+// the sync registrations are removed. This class expects to be run on the IO
+// thread. The asynchronous methods are executed sequentially.
+
+// TODO(jkarlin): Check permissions when registering, scheduling, and firing
+// background sync. In the meantime, --enable-service-worker-sync is required to
+// fire a sync event.
+// TODO(jkarlin): Unregister syncs when permission is revoked.
+// TODO(jkarlin): Create a background sync scheduler to actually run the
+// registered events.
+// TODO(jkarlin): Keep the browser alive if "Let Google Chrome Run in the
+// Background" is true and a sync is registered.
+class CONTENT_EXPORT BackgroundSyncManager
+ : NON_EXPORTED_BASE(public ServiceWorkerContextObserver) {
+ public:
+ enum ErrorType {
+ ERROR_TYPE_OK = 0,
+ ERROR_TYPE_STORAGE,
+ ERROR_TYPE_NOT_FOUND,
+ ERROR_TYPE_NO_SERVICE_WORKER
+ };
+
+ // TODO(jkarlin): Remove this and use the struct from IPC messages once it
+ // lands.
+ struct CONTENT_EXPORT BackgroundSyncRegistration {
+ using RegistrationId = int64;
+ static const RegistrationId kInvalidRegistrationId;
+ static const RegistrationId kInitialId;
+ BackgroundSyncRegistration() {}
+
+ bool Equals(const BackgroundSyncRegistration& other) const {
+ return this->tag == other.tag && this->periodicity == other.periodicity &&
+ this->min_period == other.min_period &&
+ network_state == other.network_state &&
+ power_state == other.power_state;
+ }
+
+ // Registrations options from the specification
+ std::string tag;
+ int64 min_period = 0;
+ SyncNetworkState network_state = NETWORK_STATE_ONLINE;
+ SyncPowerState power_state = POWER_STATE_AVOID_DRAINING;
+
+ // Implementation specific members
+ RegistrationId id = kInvalidRegistrationId;
+ SyncPeriodicity periodicity = SYNC_ONE_SHOT;
+ SyncState sync_state = SYNC_STATE_PENDING;
+ };
+
+ using StatusCallback = base::Callback<void(ErrorType)>;
+ using StatusAndRegistrationCallback =
+ base::Callback<void(ErrorType, const BackgroundSyncRegistration&)>;
+ using StatusAndRegistrationsCallback =
+ base::Callback<void(ErrorType,
+ const std::vector<BackgroundSyncRegistration>&)>;
+
+ static scoped_ptr<BackgroundSyncManager> Create(
+ const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context);
+ ~BackgroundSyncManager() override;
+
+ // Stores the given background sync registration and adds it to the scheduling
+ // queue. It will overwrite an existing registration with the same tag and
+ // periodicity unless they're identical (save for the id). Calls |callback|
+ // with ErrorTypeOK and the accepted registration on success. The accepted
+ // registration will have a unique id. It may also have altered parameters if
+ // the user or UA chose different parameters than those supplied.
+ void Register(int64 sw_registration_id,
+ const BackgroundSyncRegistration& sync_registration,
+ const StatusAndRegistrationCallback& callback);
+
+ // Removes the background sync with tag |sync_registration_tag|, periodicity
+ // |periodicity|, and id |sync_registration_id|. Calls |callback| with
+ // ErrorTypeNotFound if no match is found. Calls |callback| with ErrorTypeOK
+ // on success.
+ void Unregister(
+ int64 sw_registration_id,
+ const std::string& sync_registration_tag,
+ SyncPeriodicity periodicity,
+ BackgroundSyncRegistration::RegistrationId sync_registration_id,
+ const StatusCallback& callback);
+
+ // Finds the background sync registration associated with
+ // |sw_registration_id| with periodicity |periodicity|. Calls
+ // |callback| with ErrorTypeNotFound if it doesn't exist. Calls |callback|
+ // with ErrorTypeOK on success.
+ void GetRegistration(int64 sw_registration_id,
+ const std::string& sync_registration_tag,
+ SyncPeriodicity periodicity,
+ const StatusAndRegistrationCallback& callback);
+
+ void GetRegistrations(int64 sw_registration_id,
+ SyncPeriodicity periodicity,
+ const StatusAndRegistrationsCallback& callback);
+
+ // ServiceWorkerContextObserver overrides.
+ void OnRegistrationDeleted(int64 registration_id,
+ const GURL& pattern) override;
+ void OnStorageWiped() override;
+
+ protected:
+ explicit BackgroundSyncManager(
+ const scoped_refptr<ServiceWorkerContextWrapper>& context);
+
+ // Init must be called before any public member function. Only call it once.
+ void Init();
+
+ // The following methods are virtual for testing.
+ virtual void StoreDataInBackend(
+ int64 sw_registration_id,
+ const GURL& origin,
+ const std::string& backend_key,
+ const std::string& data,
+ const ServiceWorkerStorage::StatusCallback& callback);
+ virtual void GetDataFromBackend(
+ const std::string& backend_key,
+ const ServiceWorkerStorage::GetUserDataForAllRegistrationsCallback&
+ callback);
+ virtual void FireOneShotSync(
+ const scoped_refptr<ServiceWorkerVersion>& active_version,
+ const ServiceWorkerVersion::StatusCallback& callback);
+
+ private:
+ class RegistrationKey {
+ public:
+ explicit RegistrationKey(const BackgroundSyncRegistration& registration);
+ RegistrationKey(const std::string& tag, SyncPeriodicity periodicity);
+ RegistrationKey(const RegistrationKey& other) = default;
+ RegistrationKey& operator=(const RegistrationKey& other) = default;
+
+ bool operator<(const RegistrationKey& rhs) const {
+ return value_ < rhs.value_;
+ }
+
+ private:
+ std::string value_;
+ };
+
+ struct BackgroundSyncRegistrations {
+ using RegistrationMap =
+ std::map<RegistrationKey, BackgroundSyncRegistration>;
+
+ BackgroundSyncRegistrations();
+ ~BackgroundSyncRegistrations();
+
+ RegistrationMap registration_map;
+ BackgroundSyncRegistration::RegistrationId next_id;
+ GURL origin;
+ };
+
+ using PermissionStatusCallback = base::Callback<void(bool)>;
+ using SWIdToRegistrationsMap = std::map<int64, BackgroundSyncRegistrations>;
+
+ // Disable the manager. Already queued operations will abort once they start
+ // to run (in their impl methods). Future operations will not queue. Any
+ // registrations are cleared from memory and the backend (if it's still
+ // functioning). The manager will reenable itself once it receives the
+ // OnStorageWiped message or on browser restart.
+ void DisableAndClearManager(const base::Closure& callback);
+ void DisableAndClearDidGetRegistrations(
+ const base::Closure& callback,
+ const std::vector<std::pair<int64, std::string>>& user_data,
+ ServiceWorkerStatusCode status);
+ void DisableAndClearManagerClearedOne(const base::Closure& barrier_closure,
+ ServiceWorkerStatusCode status);
+
+ // Returns the existing registration in |existing_registration| if it is not
+ // null.
+ BackgroundSyncRegistration* LookupRegistration(
+ int64 sw_registration_id,
+ const RegistrationKey& registration_key);
+
+ // Store all registrations for a given |sw_registration_id|.
+ void StoreRegistrations(int64 sw_registration_id,
+ const ServiceWorkerStorage::StatusCallback& callback);
+
+ // Removes the registration if it is in the map.
+ void RemoveRegistrationFromMap(int64 sw_registration_id,
+ const RegistrationKey& registration_key);
+
+ void AddRegistrationToMap(
+ int64 sw_registration_id,
+ const GURL& origin,
+ const BackgroundSyncRegistration& sync_registration);
+
+ void InitImpl(const base::Closure& callback);
+ void InitDidGetDataFromBackend(
+ const base::Closure& callback,
+ const std::vector<std::pair<int64, std::string>>& user_data,
+ ServiceWorkerStatusCode status);
+
+ // Register callbacks
+ void RegisterImpl(int64 sw_registration_id,
+ const BackgroundSyncRegistration& sync_registration,
+ const StatusAndRegistrationCallback& callback);
+ void RegisterDidStore(int64 sw_registration_id,
+ const BackgroundSyncRegistration& sync_registration,
+ const StatusAndRegistrationCallback& callback,
+ ServiceWorkerStatusCode status);
+
+ // Unregister callbacks
+ void UnregisterImpl(
+ int64 sw_registration_id,
+ const RegistrationKey& registration_key,
+ BackgroundSyncRegistration::RegistrationId sync_registration_id,
+ const StatusCallback& callback);
+ void UnregisterDidStore(
+ int64 sw_registration_id,
+ const StatusCallback& callback,
+ ServiceWorkerStatusCode status);
+
+ // GetRegistration callbacks
+ void GetRegistrationImpl(int64 sw_registration_id,
+ const RegistrationKey& registration_key,
+ const StatusAndRegistrationCallback& callback);
+
+ // GetRegistrations callbacks
+ void GetRegistrationsImpl(int64 sw_registration_id,
+ SyncPeriodicity periodicity,
+ const StatusAndRegistrationsCallback& callback);
+
+ bool IsRegistrationReadyToFire(
+ const BackgroundSyncRegistration& registration);
+
+ // FireReadyEvents and callbacks
+ void FireReadyEvents();
+ void FireReadyEventsImpl(const base::Closure& callback);
+ void FireReadyEventsDidFindRegistration(
+ const RegistrationKey& registration_key,
+ BackgroundSyncRegistration::RegistrationId registration_id,
+ const base::Closure& callback,
+ ServiceWorkerStatusCode service_worker_status,
+ const scoped_refptr<ServiceWorkerRegistration>&
+ service_worker_registration);
+
+ // Called when a sync event has completed.
+ void EventComplete(
+ const scoped_refptr<ServiceWorkerRegistration>&
+ service_worker_registration,
+ int64 service_worker_id,
+ const RegistrationKey& key,
+ BackgroundSyncRegistration::RegistrationId sync_registration_id,
+ ServiceWorkerStatusCode status_code);
+ void EventCompleteImpl(
+ int64 service_worker_id,
+ const RegistrationKey& key,
+ BackgroundSyncRegistration::RegistrationId sync_registration_id,
+ ServiceWorkerStatusCode status_code,
+ const base::Closure& callback);
+ void EventCompleteDidStore(int64 service_worker_id,
+ const base::Closure& callback,
+ ServiceWorkerStatusCode status_code);
+
+ // OnRegistrationDeleted callbacks
+ void OnRegistrationDeletedImpl(int64 registration_id,
+ const base::Closure& callback);
+
+ // OnStorageWiped callbacks
+ void OnStorageWipedImpl(const base::Closure& callback);
+
+ void OnNetworkChanged();
+
+ // Operation Scheduling callback and convenience functions.
+ template <typename CallbackT, typename... Params>
+ void CompleteOperationCallback(const CallbackT& callback,
+ Params... parameters);
+ base::Closure MakeEmptyCompletion();
+ StatusAndRegistrationCallback MakeStatusAndRegistrationCompletion(
+ const StatusAndRegistrationCallback& callback);
+ StatusAndRegistrationsCallback MakeStatusAndRegistrationsCompletion(
+ const StatusAndRegistrationsCallback& callback);
+ BackgroundSyncManager::StatusCallback MakeStatusCompletion(
+ const StatusCallback& callback);
+
+ SWIdToRegistrationsMap sw_to_registrations_map_;
+ CacheStorageScheduler op_scheduler_;
+ scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_;
+ bool disabled_;
+
+ scoped_ptr<BackgroundSyncNetworkObserver> network_observer_;
+
+ base::WeakPtrFactory<BackgroundSyncManager> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(BackgroundSyncManager);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_BACKGROUND_SYNC_BACKGROUND_SYNC_MANAGER_H_
diff --git a/chromium/content/browser/background_sync/background_sync_manager_unittest.cc b/chromium/content/browser/background_sync/background_sync_manager_unittest.cc
new file mode 100644
index 00000000000..8c9861c6d9c
--- /dev/null
+++ b/chromium/content/browser/background_sync/background_sync_manager_unittest.cc
@@ -0,0 +1,1161 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/background_sync/background_sync_manager.h"
+
+#include "base/files/scoped_temp_dir.h"
+#include "base/logging.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/embedded_worker_test_helper.h"
+#include "content/browser/service_worker/service_worker_context_core.h"
+#include "content/browser/service_worker/service_worker_context_wrapper.h"
+#include "content/browser/service_worker/service_worker_storage.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "net/base/network_change_notifier.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+namespace {
+
+const char kPattern1[] = "https://example.com/a";
+const char kPattern2[] = "https://example.com/b";
+const char kScript1[] = "https://example.com/a/script.js";
+const char kScript2[] = "https://example.com/b/script.js";
+const int kRenderProcessId = 99;
+
+void RegisterServiceWorkerCallback(bool* called,
+ int64* store_registration_id,
+ ServiceWorkerStatusCode status,
+ const std::string& status_message,
+ int64 registration_id) {
+ EXPECT_EQ(SERVICE_WORKER_OK, status) << ServiceWorkerStatusToString(status);
+ *called = true;
+ *store_registration_id = registration_id;
+}
+
+void FindServiceWorkerRegistrationCallback(
+ scoped_refptr<ServiceWorkerRegistration>* out_registration,
+ ServiceWorkerStatusCode status,
+ const scoped_refptr<ServiceWorkerRegistration>& registration) {
+ EXPECT_EQ(SERVICE_WORKER_OK, status) << ServiceWorkerStatusToString(status);
+ *out_registration = registration;
+}
+
+void UnregisterServiceWorkerCallback(bool* called,
+ ServiceWorkerStatusCode code) {
+ EXPECT_EQ(SERVICE_WORKER_OK, code);
+ *called = true;
+}
+
+void OneShotSuccessfulCallback(
+ int* count,
+ const scoped_refptr<ServiceWorkerVersion>& active_version,
+ const ServiceWorkerVersion::StatusCallback& callback) {
+ *count += 1;
+ callback.Run(SERVICE_WORKER_OK);
+}
+
+void OneShotFailedCallback(
+ int* count,
+ const scoped_refptr<ServiceWorkerVersion>& active_version,
+ const ServiceWorkerVersion::StatusCallback& callback) {
+ *count += 1;
+ callback.Run(SERVICE_WORKER_ERROR_FAILED);
+}
+
+void OneShotDelayedCallback(
+ int* count,
+ ServiceWorkerVersion::StatusCallback* out_callback,
+ const scoped_refptr<ServiceWorkerVersion>& active_version,
+ const ServiceWorkerVersion::StatusCallback& callback) {
+ *count += 1;
+ *out_callback = callback;
+}
+
+} // namespace
+
+// A BackgroundSyncManager that can simulate delaying and corrupting the backend
+// storage and service worker onsync events.
+class TestBackgroundSyncManager : public BackgroundSyncManager {
+ public:
+ using OneShotCallback =
+ base::Callback<void(const scoped_refptr<ServiceWorkerVersion>&,
+ const ServiceWorkerVersion::StatusCallback&)>;
+
+ explicit TestBackgroundSyncManager(
+ const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context)
+ : BackgroundSyncManager(service_worker_context) {}
+
+ void DoInit() { Init(); }
+
+ void StoreDataInBackendContinue(
+ int64 sw_registration_id,
+ const GURL& origin,
+ const std::string& key,
+ const std::string& data,
+ const ServiceWorkerStorage::StatusCallback& callback) {
+ BackgroundSyncManager::StoreDataInBackend(sw_registration_id, origin, key,
+ data, callback);
+ }
+
+ void GetDataFromBackendContinue(
+ const std::string& key,
+ const ServiceWorkerStorage::GetUserDataForAllRegistrationsCallback&
+ callback) {
+ BackgroundSyncManager::GetDataFromBackend(key, callback);
+ }
+
+ void Continue() {
+ continuation_.Run();
+ continuation_.Reset();
+ }
+
+ void set_corrupt_backend(bool corrupt_backend) {
+ corrupt_backend_ = corrupt_backend;
+ }
+ void set_delay_backend(bool delay_backend) { delay_backend_ = delay_backend; }
+ void set_one_shot_callback(const OneShotCallback& callback) {
+ one_shot_callback_ = callback;
+ }
+
+ protected:
+ void StoreDataInBackend(
+ int64 sw_registration_id,
+ const GURL& origin,
+ const std::string& key,
+ const std::string& data,
+ const ServiceWorkerStorage::StatusCallback& callback) override {
+ EXPECT_TRUE(continuation_.is_null());
+ if (corrupt_backend_) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(callback, SERVICE_WORKER_ERROR_FAILED));
+ return;
+ }
+ continuation_ =
+ base::Bind(&TestBackgroundSyncManager::StoreDataInBackendContinue,
+ base::Unretained(this), sw_registration_id, origin, key,
+ data, callback);
+ if (delay_backend_)
+ return;
+
+ Continue();
+ }
+
+ void GetDataFromBackend(
+ const std::string& key,
+ const ServiceWorkerStorage::GetUserDataForAllRegistrationsCallback&
+ callback) override {
+ EXPECT_TRUE(continuation_.is_null());
+ if (corrupt_backend_) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(callback, std::vector<std::pair<int64, std::string>>(),
+ SERVICE_WORKER_ERROR_FAILED));
+ return;
+ }
+ continuation_ =
+ base::Bind(&TestBackgroundSyncManager::GetDataFromBackendContinue,
+ base::Unretained(this), key, callback);
+ if (delay_backend_)
+ return;
+
+ Continue();
+ }
+
+ void FireOneShotSync(
+ const scoped_refptr<ServiceWorkerVersion>& active_version,
+ const ServiceWorkerVersion::StatusCallback& callback) override {
+ if (one_shot_callback_.is_null()) {
+ BackgroundSyncManager::FireOneShotSync(active_version, callback);
+ } else {
+ one_shot_callback_.Run(active_version, callback);
+ }
+ }
+
+ private:
+ bool corrupt_backend_ = false;
+ bool delay_backend_ = false;
+ base::Closure continuation_;
+ OneShotCallback one_shot_callback_;
+};
+
+class BackgroundSyncManagerTest : public testing::Test {
+ public:
+ BackgroundSyncManagerTest()
+ : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP),
+ network_change_notifier_(net::NetworkChangeNotifier::CreateMock()),
+ test_background_sync_manager_(nullptr),
+ sync_reg_1_(BackgroundSyncManager::BackgroundSyncRegistration()),
+ sync_reg_2_(BackgroundSyncManager::BackgroundSyncRegistration()),
+ callback_error_(BackgroundSyncManager::ERROR_TYPE_OK),
+ callback_sw_status_code_(SERVICE_WORKER_OK),
+ sync_events_called_(0) {
+ sync_reg_1_.tag = "foo";
+ sync_reg_1_.periodicity = SYNC_ONE_SHOT;
+ sync_reg_1_.network_state = NETWORK_STATE_ONLINE;
+ sync_reg_1_.power_state = POWER_STATE_AUTO;
+
+ sync_reg_2_.tag = "bar";
+ sync_reg_2_.periodicity = SYNC_ONE_SHOT;
+ sync_reg_2_.network_state = NETWORK_STATE_ONLINE;
+ sync_reg_2_.power_state = POWER_STATE_AUTO;
+ }
+
+ void SetUp() override {
+ SetNetwork(net::NetworkChangeNotifier::CONNECTION_WIFI);
+
+ helper_.reset(
+ new EmbeddedWorkerTestHelper(base::FilePath(), kRenderProcessId));
+
+ background_sync_manager_ =
+ BackgroundSyncManager::Create(helper_->context_wrapper());
+
+ // Wait for storage to finish initializing before registering service
+ // workers.
+ base::RunLoop().RunUntilIdle();
+ RegisterServiceWorkers();
+ }
+
+ void RegisterServiceWorkers() {
+ bool called_1 = false;
+ bool called_2 = false;
+ helper_->context()->RegisterServiceWorker(
+ GURL(kPattern1), GURL(kScript1), NULL,
+ base::Bind(&RegisterServiceWorkerCallback, &called_1,
+ &sw_registration_id_1_));
+
+ helper_->context()->RegisterServiceWorker(
+ GURL(kPattern2), GURL(kScript2), NULL,
+ base::Bind(&RegisterServiceWorkerCallback, &called_2,
+ &sw_registration_id_2_));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(called_1);
+ EXPECT_TRUE(called_2);
+
+ // Hang onto the registrations as they need to be "live" when
+ // calling BackgroundSyncMasnager::Register.
+ helper_->context_wrapper()->FindRegistrationForId(
+ sw_registration_id_1_, GURL(kPattern1).GetOrigin(),
+ base::Bind(FindServiceWorkerRegistrationCallback, &sw_registration_1_));
+
+ helper_->context_wrapper()->FindRegistrationForId(
+ sw_registration_id_2_, GURL(kPattern1).GetOrigin(),
+ base::Bind(FindServiceWorkerRegistrationCallback, &sw_registration_2_));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(sw_registration_1_);
+ EXPECT_TRUE(sw_registration_2_);
+ }
+
+ void SetNetwork(net::NetworkChangeNotifier::ConnectionType connection_type) {
+ net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
+ connection_type);
+ base::RunLoop().RunUntilIdle();
+ }
+
+ void StatusAndRegistrationCallback(
+ bool* was_called,
+ BackgroundSyncManager::ErrorType error,
+ const BackgroundSyncManager::BackgroundSyncRegistration& registration) {
+ *was_called = true;
+ callback_error_ = error;
+ callback_registration_ = registration;
+ }
+
+ void StatusAndRegistrationsCallback(
+ bool* was_called,
+ BackgroundSyncManager::ErrorType error,
+ const std::vector<BackgroundSyncManager::BackgroundSyncRegistration>&
+ registrations) {
+ *was_called = true;
+ callback_error_ = error;
+ callback_registrations_ = registrations;
+ }
+
+ void StatusCallback(bool* was_called,
+ BackgroundSyncManager::ErrorType error) {
+ *was_called = true;
+ callback_error_ = error;
+ }
+
+ protected:
+ void UseTestBackgroundSyncManager() {
+ test_background_sync_manager_ =
+ new TestBackgroundSyncManager(helper_->context_wrapper());
+ test_background_sync_manager_->DoInit();
+ background_sync_manager_.reset(test_background_sync_manager_);
+ }
+
+ bool Register(const BackgroundSyncManager::BackgroundSyncRegistration&
+ sync_registration) {
+ return RegisterWithServiceWorkerId(sw_registration_id_1_,
+ sync_registration);
+ }
+
+ bool RegisterWithServiceWorkerId(
+ int64 sw_registration_id,
+ const BackgroundSyncManager::BackgroundSyncRegistration&
+ sync_registration) {
+ bool was_called = false;
+ background_sync_manager_->Register(
+ sw_registration_id, sync_registration,
+ base::Bind(&BackgroundSyncManagerTest::StatusAndRegistrationCallback,
+ base::Unretained(this), &was_called));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(was_called);
+ return callback_error_ == BackgroundSyncManager::ERROR_TYPE_OK;
+ }
+
+ bool Unregister(const BackgroundSyncManager::BackgroundSyncRegistration&
+ sync_registration) {
+ return UnregisterWithServiceWorkerId(sw_registration_id_1_,
+ sync_registration);
+ }
+
+ bool UnregisterWithServiceWorkerId(
+ int64 sw_registration_id,
+ const BackgroundSyncManager::BackgroundSyncRegistration&
+ sync_registration) {
+ bool was_called = false;
+ background_sync_manager_->Unregister(
+ sw_registration_id, sync_registration.tag,
+ sync_registration.periodicity, sync_registration.id,
+ base::Bind(&BackgroundSyncManagerTest::StatusCallback,
+ base::Unretained(this), &was_called));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(was_called);
+ return callback_error_ == BackgroundSyncManager::ERROR_TYPE_OK;
+ }
+
+ bool GetRegistration(const BackgroundSyncManager::BackgroundSyncRegistration&
+ sync_registration) {
+ return GetRegistrationWithServiceWorkerId(sw_registration_id_1_,
+ sync_registration);
+ }
+
+ bool GetRegistrationWithServiceWorkerId(
+ int64 sw_registration_id,
+ const BackgroundSyncManager::BackgroundSyncRegistration&
+ sync_registration) {
+ bool was_called = false;
+ background_sync_manager_->GetRegistration(
+ sw_registration_id, sync_registration.tag,
+ sync_registration.periodicity,
+ base::Bind(&BackgroundSyncManagerTest::StatusAndRegistrationCallback,
+ base::Unretained(this), &was_called));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(was_called);
+
+ if (callback_error_ == BackgroundSyncManager::ERROR_TYPE_OK) {
+ EXPECT_STREQ(sync_registration.tag.c_str(),
+ callback_registration_.tag.c_str());
+ }
+
+ return callback_error_ == BackgroundSyncManager::ERROR_TYPE_OK;
+ }
+
+ bool GetRegistrations(SyncPeriodicity periodicity) {
+ return GetRegistrationWithServiceWorkerId(sw_registration_id_1_,
+ periodicity);
+ }
+
+ bool GetRegistrationWithServiceWorkerId(int64 sw_registration_id,
+ SyncPeriodicity periodicity) {
+ bool was_called = false;
+ background_sync_manager_->GetRegistrations(
+ sw_registration_id, periodicity,
+ base::Bind(&BackgroundSyncManagerTest::StatusAndRegistrationsCallback,
+ base::Unretained(this), &was_called));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(was_called);
+
+ return callback_error_ == BackgroundSyncManager::ERROR_TYPE_OK;
+ }
+
+ void StorageRegistrationCallback(ServiceWorkerStatusCode result) {
+ callback_sw_status_code_ = result;
+ }
+
+ void UnregisterServiceWorker(uint64 sw_registration_id) {
+ bool called = false;
+ helper_->context()->UnregisterServiceWorker(
+ PatternForSWId(sw_registration_id),
+ base::Bind(&UnregisterServiceWorkerCallback, &called));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(called);
+ }
+
+ GURL PatternForSWId(int64 sw_id) {
+ EXPECT_TRUE(sw_id == sw_registration_id_1_ ||
+ sw_id == sw_registration_id_2_);
+ return sw_id == sw_registration_id_1_ ? GURL(kPattern1) : GURL(kPattern2);
+ }
+
+ void InitSyncEventTest() {
+ UseTestBackgroundSyncManager();
+ test_background_sync_manager_->set_one_shot_callback(
+ base::Bind(OneShotSuccessfulCallback, &sync_events_called_));
+ base::RunLoop().RunUntilIdle();
+ }
+
+ void InitFailedSyncEventTest() {
+ UseTestBackgroundSyncManager();
+ test_background_sync_manager_->set_one_shot_callback(
+ base::Bind(OneShotFailedCallback, &sync_events_called_));
+ base::RunLoop().RunUntilIdle();
+ }
+
+ void InitDelayedSyncEventTest() {
+ UseTestBackgroundSyncManager();
+ test_background_sync_manager_->set_one_shot_callback(base::Bind(
+ OneShotDelayedCallback, &sync_events_called_, &sync_fired_callback_));
+ base::RunLoop().RunUntilIdle();
+ }
+
+ void RegisterAndVerifySyncEventDelayed(
+ const BackgroundSyncManager::BackgroundSyncRegistration&
+ sync_registration) {
+ int sync_events_called = sync_events_called_;
+ EXPECT_TRUE(sync_fired_callback_.is_null());
+
+ EXPECT_TRUE(Register(sync_registration));
+
+ EXPECT_EQ(sync_events_called + 1, sync_events_called_);
+ EXPECT_TRUE(GetRegistration(sync_reg_1_));
+ EXPECT_FALSE(sync_fired_callback_.is_null());
+ }
+
+ TestBrowserThreadBundle browser_thread_bundle_;
+ scoped_ptr<net::NetworkChangeNotifier> network_change_notifier_;
+ scoped_ptr<EmbeddedWorkerTestHelper> helper_;
+ scoped_ptr<BackgroundSyncManager> background_sync_manager_;
+ TestBackgroundSyncManager* test_background_sync_manager_;
+
+ int64 sw_registration_id_1_;
+ int64 sw_registration_id_2_;
+ scoped_refptr<ServiceWorkerRegistration> sw_registration_1_;
+ scoped_refptr<ServiceWorkerRegistration> sw_registration_2_;
+
+ BackgroundSyncManager::BackgroundSyncRegistration sync_reg_1_;
+ BackgroundSyncManager::BackgroundSyncRegistration sync_reg_2_;
+
+ // Callback values.
+ BackgroundSyncManager::ErrorType callback_error_;
+ BackgroundSyncManager::BackgroundSyncRegistration callback_registration_;
+ std::vector<BackgroundSyncManager::BackgroundSyncRegistration>
+ callback_registrations_;
+ ServiceWorkerStatusCode callback_sw_status_code_;
+ int sync_events_called_;
+ ServiceWorkerVersion::StatusCallback sync_fired_callback_;
+};
+
+TEST_F(BackgroundSyncManagerTest, Register) {
+ EXPECT_TRUE(Register(sync_reg_1_));
+}
+
+TEST_F(BackgroundSyncManagerTest, RegistractionIntact) {
+ EXPECT_TRUE(Register(sync_reg_1_));
+ EXPECT_STREQ(sync_reg_1_.tag.c_str(), callback_registration_.tag.c_str());
+ EXPECT_NE(
+ BackgroundSyncManager::BackgroundSyncRegistration::kInvalidRegistrationId,
+ callback_registration_.id);
+}
+
+TEST_F(BackgroundSyncManagerTest, RegisterWithoutLiveSWRegistration) {
+ sw_registration_1_ = nullptr;
+ EXPECT_FALSE(Register(sync_reg_1_));
+ EXPECT_EQ(BackgroundSyncManager::ERROR_TYPE_NO_SERVICE_WORKER,
+ callback_error_);
+}
+
+TEST_F(BackgroundSyncManagerTest, RegisterWithoutActiveSWRegistration) {
+ sw_registration_1_->UnsetVersion(sw_registration_1_->active_version());
+ EXPECT_FALSE(Register(sync_reg_1_));
+ EXPECT_EQ(BackgroundSyncManager::ERROR_TYPE_NO_SERVICE_WORKER,
+ callback_error_);
+}
+
+TEST_F(BackgroundSyncManagerTest, RegisterExistingKeepsId) {
+ EXPECT_TRUE(Register(sync_reg_1_));
+ BackgroundSyncManager::BackgroundSyncRegistration first_registration =
+ callback_registration_;
+ EXPECT_TRUE(Register(sync_reg_1_));
+ EXPECT_TRUE(callback_registration_.Equals(first_registration));
+ EXPECT_EQ(first_registration.id, callback_registration_.id);
+}
+
+TEST_F(BackgroundSyncManagerTest, RegisterOverwrites) {
+ EXPECT_TRUE(Register(sync_reg_1_));
+ BackgroundSyncManager::BackgroundSyncRegistration first_registration =
+ callback_registration_;
+
+ sync_reg_1_.min_period = 100;
+ EXPECT_TRUE(Register(sync_reg_1_));
+ EXPECT_LT(first_registration.id, callback_registration_.id);
+ EXPECT_FALSE(callback_registration_.Equals(first_registration));
+}
+
+TEST_F(BackgroundSyncManagerTest, RegisterOverlappingPeriodicAndOneShotTags) {
+ // Registrations with the same tags but different periodicities should not
+ // collide.
+ sync_reg_1_.tag = "";
+ sync_reg_2_.tag = "";
+ sync_reg_1_.periodicity = SYNC_PERIODIC;
+ sync_reg_2_.periodicity = SYNC_ONE_SHOT;
+ EXPECT_TRUE(Register(sync_reg_1_));
+ EXPECT_TRUE(Register(sync_reg_2_));
+ EXPECT_TRUE(GetRegistration(sync_reg_1_));
+ EXPECT_EQ(SYNC_PERIODIC, callback_registration_.periodicity);
+ EXPECT_TRUE(GetRegistration(sync_reg_2_));
+ EXPECT_EQ(SYNC_ONE_SHOT, callback_registration_.periodicity);
+}
+
+TEST_F(BackgroundSyncManagerTest, RegisterBadBackend) {
+ UseTestBackgroundSyncManager();
+ test_background_sync_manager_->set_corrupt_backend(true);
+ EXPECT_FALSE(Register(sync_reg_1_));
+ test_background_sync_manager_->set_corrupt_backend(false);
+ EXPECT_FALSE(Register(sync_reg_1_));
+ EXPECT_FALSE(GetRegistration(sync_reg_1_));
+}
+
+TEST_F(BackgroundSyncManagerTest, TwoRegistrations) {
+ EXPECT_TRUE(Register(sync_reg_1_));
+ EXPECT_TRUE(Register(sync_reg_2_));
+}
+
+TEST_F(BackgroundSyncManagerTest, GetRegistrationNonExisting) {
+ EXPECT_FALSE(GetRegistration(sync_reg_1_));
+}
+
+TEST_F(BackgroundSyncManagerTest, GetRegistrationExisting) {
+ EXPECT_TRUE(Register(sync_reg_1_));
+ EXPECT_TRUE(GetRegistration(sync_reg_1_));
+ EXPECT_FALSE(GetRegistration(sync_reg_2_));
+}
+
+TEST_F(BackgroundSyncManagerTest, GetRegistrationBadBackend) {
+ UseTestBackgroundSyncManager();
+ EXPECT_TRUE(Register(sync_reg_1_));
+ test_background_sync_manager_->set_corrupt_backend(true);
+ EXPECT_TRUE(GetRegistration(sync_reg_1_));
+ EXPECT_FALSE(Register(sync_reg_2_));
+ // Registration should have discovered the bad backend and disabled the
+ // BackgroundSyncManager.
+ EXPECT_FALSE(GetRegistration(sync_reg_1_));
+ test_background_sync_manager_->set_corrupt_backend(false);
+ EXPECT_FALSE(GetRegistration(sync_reg_1_));
+}
+
+TEST_F(BackgroundSyncManagerTest, GetRegistrationsZero) {
+ EXPECT_TRUE(GetRegistrations(SYNC_ONE_SHOT));
+ EXPECT_EQ(0u, callback_registrations_.size());
+}
+
+TEST_F(BackgroundSyncManagerTest, GetRegistrationsOne) {
+ EXPECT_TRUE(Register(sync_reg_1_));
+ EXPECT_TRUE(GetRegistrations(sync_reg_1_.periodicity));
+
+ EXPECT_EQ(1u, callback_registrations_.size());
+ sync_reg_1_.Equals(callback_registrations_[0]);
+}
+
+TEST_F(BackgroundSyncManagerTest, GetRegistrationsTwo) {
+ EXPECT_EQ(sync_reg_1_.periodicity, sync_reg_2_.periodicity);
+
+ EXPECT_TRUE(Register(sync_reg_1_));
+ EXPECT_TRUE(Register(sync_reg_2_));
+ EXPECT_TRUE(GetRegistrations(sync_reg_1_.periodicity));
+
+ EXPECT_EQ(2u, callback_registrations_.size());
+ sync_reg_1_.Equals(callback_registrations_[0]);
+ sync_reg_2_.Equals(callback_registrations_[1]);
+}
+
+TEST_F(BackgroundSyncManagerTest, GetRegistrationsPeriodicity) {
+ sync_reg_1_.periodicity = SYNC_ONE_SHOT;
+ sync_reg_2_.periodicity = SYNC_PERIODIC;
+ EXPECT_TRUE(Register(sync_reg_1_));
+ EXPECT_TRUE(Register(sync_reg_2_));
+
+ EXPECT_TRUE(GetRegistrations(SYNC_ONE_SHOT));
+ EXPECT_EQ(1u, callback_registrations_.size());
+ sync_reg_1_.Equals(callback_registrations_[0]);
+
+ EXPECT_TRUE(GetRegistrations(SYNC_PERIODIC));
+ EXPECT_EQ(1u, callback_registrations_.size());
+ sync_reg_2_.Equals(callback_registrations_[0]);
+}
+
+TEST_F(BackgroundSyncManagerTest, GetRegistrationsBadBackend) {
+ UseTestBackgroundSyncManager();
+ EXPECT_TRUE(Register(sync_reg_1_));
+ test_background_sync_manager_->set_corrupt_backend(true);
+ EXPECT_TRUE(GetRegistrations(sync_reg_1_.periodicity));
+ EXPECT_FALSE(Register(sync_reg_2_));
+ // Registration should have discovered the bad backend and disabled the
+ // BackgroundSyncManager.
+ EXPECT_FALSE(GetRegistrations(sync_reg_1_.periodicity));
+ test_background_sync_manager_->set_corrupt_backend(false);
+ EXPECT_FALSE(GetRegistrations(sync_reg_1_.periodicity));
+}
+
+TEST_F(BackgroundSyncManagerTest, Unregister) {
+ EXPECT_TRUE(Register(sync_reg_1_));
+ EXPECT_TRUE(Unregister(callback_registration_));
+ EXPECT_FALSE(GetRegistration(sync_reg_1_));
+}
+
+TEST_F(BackgroundSyncManagerTest, UnregisterWrongId) {
+ EXPECT_TRUE(Register(sync_reg_1_));
+ callback_registration_.id += 1;
+ EXPECT_FALSE(Unregister(callback_registration_));
+}
+
+TEST_F(BackgroundSyncManagerTest, Reregister) {
+ EXPECT_TRUE(Register(sync_reg_1_));
+ EXPECT_TRUE(Unregister(callback_registration_));
+ EXPECT_TRUE(Register(sync_reg_1_));
+}
+
+TEST_F(BackgroundSyncManagerTest, UnregisterNonExisting) {
+ EXPECT_FALSE(Unregister(sync_reg_1_));
+ EXPECT_EQ(BackgroundSyncManager::ERROR_TYPE_NOT_FOUND, callback_error_);
+}
+
+TEST_F(BackgroundSyncManagerTest, UnregisterSecond) {
+ EXPECT_TRUE(Register(sync_reg_1_));
+ EXPECT_TRUE(Register(sync_reg_2_));
+ EXPECT_TRUE(Unregister(callback_registration_));
+ EXPECT_TRUE(GetRegistration(sync_reg_1_));
+ EXPECT_TRUE(Register(sync_reg_2_));
+}
+
+TEST_F(BackgroundSyncManagerTest, UnregisterBadBackend) {
+ UseTestBackgroundSyncManager();
+ sync_reg_1_.min_period += 1;
+ EXPECT_TRUE(Register(sync_reg_1_));
+ EXPECT_TRUE(Register(sync_reg_2_));
+ test_background_sync_manager_->set_corrupt_backend(true);
+ EXPECT_FALSE(Unregister(callback_registration_));
+ // Unregister should have discovered the bad backend and disabled the
+ // BackgroundSyncManager.
+ test_background_sync_manager_->set_corrupt_backend(false);
+ EXPECT_FALSE(GetRegistration(sync_reg_1_));
+ EXPECT_FALSE(GetRegistration(sync_reg_2_));
+}
+
+TEST_F(BackgroundSyncManagerTest, RegistrationIncreasesId) {
+ EXPECT_TRUE(Register(sync_reg_1_));
+ BackgroundSyncManager::BackgroundSyncRegistration registered_sync =
+ callback_registration_;
+ BackgroundSyncManager::BackgroundSyncRegistration::RegistrationId cur_id =
+ callback_registration_.id;
+
+ EXPECT_TRUE(GetRegistration(sync_reg_1_));
+ EXPECT_TRUE(Register(sync_reg_2_));
+ EXPECT_LT(cur_id, callback_registration_.id);
+ cur_id = callback_registration_.id;
+
+ EXPECT_TRUE(Unregister(registered_sync));
+ EXPECT_TRUE(Register(sync_reg_1_));
+ EXPECT_LT(cur_id, callback_registration_.id);
+}
+
+TEST_F(BackgroundSyncManagerTest, RebootRecovery) {
+ EXPECT_TRUE(Register(sync_reg_1_));
+
+ background_sync_manager_ =
+ BackgroundSyncManager::Create(helper_->context_wrapper());
+
+ EXPECT_TRUE(GetRegistration(sync_reg_1_));
+ EXPECT_FALSE(GetRegistration(sync_reg_2_));
+}
+
+TEST_F(BackgroundSyncManagerTest, RebootRecoveryTwoServiceWorkers) {
+ EXPECT_TRUE(RegisterWithServiceWorkerId(sw_registration_id_1_, sync_reg_1_));
+ EXPECT_TRUE(RegisterWithServiceWorkerId(sw_registration_id_2_, sync_reg_2_));
+
+ background_sync_manager_ =
+ BackgroundSyncManager::Create(helper_->context_wrapper());
+
+ EXPECT_TRUE(
+ GetRegistrationWithServiceWorkerId(sw_registration_id_1_, sync_reg_1_));
+ EXPECT_FALSE(
+ GetRegistrationWithServiceWorkerId(sw_registration_id_1_, sync_reg_2_));
+ EXPECT_FALSE(
+ GetRegistrationWithServiceWorkerId(sw_registration_id_2_, sync_reg_1_));
+ EXPECT_TRUE(
+ GetRegistrationWithServiceWorkerId(sw_registration_id_2_, sync_reg_2_));
+
+ EXPECT_TRUE(
+ GetRegistrationWithServiceWorkerId(sw_registration_id_1_, sync_reg_1_));
+ EXPECT_TRUE(
+ GetRegistrationWithServiceWorkerId(sw_registration_id_2_, sync_reg_2_));
+
+ EXPECT_TRUE(RegisterWithServiceWorkerId(sw_registration_id_1_, sync_reg_2_));
+ EXPECT_TRUE(RegisterWithServiceWorkerId(sw_registration_id_2_, sync_reg_1_));
+}
+
+TEST_F(BackgroundSyncManagerTest, InitWithBadBackend) {
+ TestBackgroundSyncManager* manager =
+ new TestBackgroundSyncManager(helper_->context_wrapper());
+ background_sync_manager_.reset(manager);
+ manager->set_corrupt_backend(true);
+ manager->DoInit();
+
+ EXPECT_FALSE(Register(sync_reg_1_));
+ EXPECT_FALSE(GetRegistration(sync_reg_1_));
+}
+
+TEST_F(BackgroundSyncManagerTest, SequentialOperations) {
+ // Schedule Init and all of the operations on a delayed backend. Verify that
+ // the operations complete sequentially.
+ TestBackgroundSyncManager* manager =
+ new TestBackgroundSyncManager(helper_->context_wrapper());
+ background_sync_manager_.reset(manager);
+ manager->set_delay_backend(true);
+ manager->DoInit();
+
+ const int64 kExpectedInitialId =
+ BackgroundSyncManager::BackgroundSyncRegistration::kInitialId;
+
+ bool register_called = false;
+ bool unregister_called = false;
+ bool get_registration_called = false;
+ manager->Register(
+ sw_registration_id_1_, sync_reg_1_,
+ base::Bind(&BackgroundSyncManagerTest::StatusAndRegistrationCallback,
+ base::Unretained(this), &register_called));
+ manager->Unregister(sw_registration_id_1_, sync_reg_1_.tag,
+ sync_reg_1_.periodicity, kExpectedInitialId,
+ base::Bind(&BackgroundSyncManagerTest::StatusCallback,
+ base::Unretained(this), &unregister_called));
+ manager->GetRegistration(
+ sw_registration_id_1_, sync_reg_1_.tag, sync_reg_1_.periodicity,
+ base::Bind(&BackgroundSyncManagerTest::StatusAndRegistrationCallback,
+ base::Unretained(this), &get_registration_called));
+
+ base::RunLoop().RunUntilIdle();
+ // Init should be blocked while loading from the backend.
+ EXPECT_FALSE(register_called);
+ EXPECT_FALSE(unregister_called);
+ EXPECT_FALSE(get_registration_called);
+
+ manager->Continue();
+ base::RunLoop().RunUntilIdle();
+ // Register should be blocked while storing to the backend.
+ EXPECT_FALSE(register_called);
+ EXPECT_FALSE(unregister_called);
+ EXPECT_FALSE(get_registration_called);
+
+ manager->Continue();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(register_called);
+ EXPECT_EQ(kExpectedInitialId, callback_registration_.id);
+ EXPECT_EQ(BackgroundSyncManager::ERROR_TYPE_OK, callback_error_);
+ // Unregister should be blocked while storing to the backend.
+ EXPECT_FALSE(unregister_called);
+ EXPECT_FALSE(get_registration_called);
+
+ manager->Continue();
+ base::RunLoop().RunUntilIdle();
+ // Unregister should be done and since GetRegistration doesn't require the
+ // backend it should be done too.
+ EXPECT_EQ(BackgroundSyncManager::ERROR_TYPE_NOT_FOUND, callback_error_);
+ EXPECT_TRUE(unregister_called);
+ EXPECT_TRUE(get_registration_called);
+}
+
+TEST_F(BackgroundSyncManagerTest, UnregisterServiceWorker) {
+ EXPECT_TRUE(Register(sync_reg_1_));
+ UnregisterServiceWorker(sw_registration_id_1_);
+ EXPECT_FALSE(GetRegistration(sync_reg_1_));
+}
+
+TEST_F(BackgroundSyncManagerTest,
+ UnregisterServiceWorkerDuringSyncRegistration) {
+ TestBackgroundSyncManager* manager =
+ new TestBackgroundSyncManager(helper_->context_wrapper());
+ background_sync_manager_.reset(manager);
+ manager->DoInit();
+
+ EXPECT_TRUE(Register(sync_reg_1_));
+
+ manager->set_delay_backend(true);
+ bool callback_called = false;
+ manager->Register(
+ sw_registration_id_1_, sync_reg_2_,
+ base::Bind(&BackgroundSyncManagerTest::StatusAndRegistrationCallback,
+ base::Unretained(this), &callback_called));
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(callback_called);
+ UnregisterServiceWorker(sw_registration_id_1_);
+
+ manager->Continue();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(callback_called);
+ EXPECT_EQ(BackgroundSyncManager::ERROR_TYPE_STORAGE, callback_error_);
+
+ manager->set_delay_backend(false);
+ EXPECT_FALSE(GetRegistration(sync_reg_1_));
+}
+
+TEST_F(BackgroundSyncManagerTest, DeleteAndStartOverServiceWorkerContext) {
+ EXPECT_TRUE(Register(sync_reg_1_));
+ helper_->context()->ScheduleDeleteAndStartOver();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(GetRegistration(sync_reg_1_));
+}
+
+TEST_F(BackgroundSyncManagerTest, DisabledManagerWorksAfterBrowserRestart) {
+ TestBackgroundSyncManager* manager =
+ new TestBackgroundSyncManager(helper_->context_wrapper());
+ background_sync_manager_.reset(manager);
+ manager->DoInit();
+ EXPECT_TRUE(Register(sync_reg_1_));
+ manager->set_corrupt_backend(true);
+ EXPECT_FALSE(Register(sync_reg_2_));
+
+ // The manager is now disabled and not accepting new requests until browser
+ // restart or notification that the storage has been wiped.
+ manager->set_corrupt_backend(false);
+ EXPECT_FALSE(GetRegistration(sync_reg_1_));
+ EXPECT_FALSE(Register(sync_reg_2_));
+
+ // Simulate restarting the browser by creating a new BackgroundSyncManager.
+ background_sync_manager_.reset(
+ new TestBackgroundSyncManager(helper_->context_wrapper()));
+ EXPECT_FALSE(GetRegistration(sync_reg_1_));
+ EXPECT_TRUE(Register(sync_reg_1_));
+}
+
+TEST_F(BackgroundSyncManagerTest, DisabledManagerWorksAfterDeleteAndStartOver) {
+ TestBackgroundSyncManager* manager =
+ new TestBackgroundSyncManager(helper_->context_wrapper());
+ background_sync_manager_.reset(manager);
+ manager->DoInit();
+ EXPECT_TRUE(Register(sync_reg_1_));
+ manager->set_corrupt_backend(true);
+ EXPECT_FALSE(Register(sync_reg_2_));
+
+ // The manager is now disabled and not accepting new requests until browser
+ // restart or notification that the storage has been wiped.
+ manager->set_corrupt_backend(false);
+ helper_->context()->ScheduleDeleteAndStartOver();
+ base::RunLoop().RunUntilIdle();
+
+ RegisterServiceWorkers();
+
+ EXPECT_TRUE(Register(sync_reg_2_));
+ EXPECT_FALSE(GetRegistration(sync_reg_1_));
+ EXPECT_TRUE(GetRegistration(sync_reg_2_));
+}
+
+TEST_F(BackgroundSyncManagerTest, RegistrationEqualsId) {
+ BackgroundSyncManager::BackgroundSyncRegistration reg_1;
+ BackgroundSyncManager::BackgroundSyncRegistration reg_2;
+
+ EXPECT_TRUE(reg_1.Equals(reg_2));
+ reg_2.id = reg_1.id + 1;
+ EXPECT_TRUE(reg_1.Equals(reg_2));
+}
+
+TEST_F(BackgroundSyncManagerTest, RegistrationEqualsTag) {
+ BackgroundSyncManager::BackgroundSyncRegistration reg_1;
+ BackgroundSyncManager::BackgroundSyncRegistration reg_2;
+ EXPECT_TRUE(reg_1.Equals(reg_2));
+ reg_2.tag = "bar";
+ EXPECT_FALSE(reg_1.Equals(reg_2));
+}
+
+TEST_F(BackgroundSyncManagerTest, RegistrationEqualsPeriodicity) {
+ BackgroundSyncManager::BackgroundSyncRegistration reg_1;
+ BackgroundSyncManager::BackgroundSyncRegistration reg_2;
+ EXPECT_TRUE(reg_1.Equals(reg_2));
+ reg_1.periodicity = SYNC_PERIODIC;
+ reg_2.periodicity = SYNC_ONE_SHOT;
+ EXPECT_FALSE(reg_1.Equals(reg_2));
+}
+
+TEST_F(BackgroundSyncManagerTest, RegistrationEqualsMinPeriod) {
+ BackgroundSyncManager::BackgroundSyncRegistration reg_1;
+ BackgroundSyncManager::BackgroundSyncRegistration reg_2;
+ EXPECT_TRUE(reg_1.Equals(reg_2));
+ reg_2.min_period = reg_1.min_period + 1;
+ EXPECT_FALSE(reg_1.Equals(reg_2));
+}
+
+TEST_F(BackgroundSyncManagerTest, RegistrationEqualsNetworkState) {
+ BackgroundSyncManager::BackgroundSyncRegistration reg_1;
+ BackgroundSyncManager::BackgroundSyncRegistration reg_2;
+ EXPECT_TRUE(reg_1.Equals(reg_2));
+ reg_1.network_state = NETWORK_STATE_ANY;
+ reg_2.network_state = NETWORK_STATE_ONLINE;
+ EXPECT_FALSE(reg_1.Equals(reg_2));
+}
+
+TEST_F(BackgroundSyncManagerTest, RegistrationEqualsPowerState) {
+ BackgroundSyncManager::BackgroundSyncRegistration reg_1;
+ BackgroundSyncManager::BackgroundSyncRegistration reg_2;
+ EXPECT_TRUE(reg_1.Equals(reg_2));
+ reg_1.power_state = POWER_STATE_AUTO;
+ reg_2.power_state = POWER_STATE_AVOID_DRAINING;
+ EXPECT_FALSE(reg_1.Equals(reg_2));
+}
+
+TEST_F(BackgroundSyncManagerTest, StoreAndRetrievePreservesValues) {
+ BackgroundSyncManager::BackgroundSyncRegistration reg_1;
+ // Set non-default values for each field.
+ reg_1.tag = "foo";
+ EXPECT_NE(SYNC_PERIODIC, reg_1.periodicity);
+ reg_1.periodicity = SYNC_PERIODIC;
+ reg_1.min_period += 1;
+ EXPECT_NE(NETWORK_STATE_ANY, reg_1.network_state);
+ reg_1.network_state = NETWORK_STATE_ANY;
+ EXPECT_NE(POWER_STATE_AUTO, reg_1.power_state);
+ reg_1.power_state = POWER_STATE_AUTO;
+
+ // Store the registration.
+ EXPECT_TRUE(Register(reg_1));
+
+ // Simulate restarting the sync manager, forcing the next read to come from
+ // disk.
+ UseTestBackgroundSyncManager();
+
+ EXPECT_TRUE(GetRegistration(reg_1));
+ EXPECT_TRUE(reg_1.Equals(callback_registration_));
+}
+
+TEST_F(BackgroundSyncManagerTest, EmptyTagSupported) {
+ sync_reg_1_.tag = "a";
+ EXPECT_TRUE(Register(sync_reg_1_));
+ EXPECT_TRUE(GetRegistration(sync_reg_1_));
+ EXPECT_TRUE(sync_reg_1_.Equals(callback_registration_));
+ EXPECT_TRUE(Unregister(callback_registration_));
+ EXPECT_FALSE(GetRegistration(sync_reg_1_));
+}
+
+TEST_F(BackgroundSyncManagerTest, OverlappingPeriodicAndOneShotTags) {
+ // Registrations with the same tags but different periodicities should not
+ // collide.
+ sync_reg_1_.tag = "";
+ sync_reg_2_.tag = "";
+ sync_reg_1_.periodicity = SYNC_PERIODIC;
+ sync_reg_2_.periodicity = SYNC_ONE_SHOT;
+
+ EXPECT_TRUE(Register(sync_reg_1_));
+ EXPECT_TRUE(Register(sync_reg_2_));
+
+ EXPECT_TRUE(GetRegistration(sync_reg_1_));
+ EXPECT_EQ(SYNC_PERIODIC, callback_registration_.periodicity);
+ EXPECT_TRUE(GetRegistration(sync_reg_2_));
+ EXPECT_EQ(SYNC_ONE_SHOT, callback_registration_.periodicity);
+
+ EXPECT_TRUE(GetRegistration(sync_reg_1_));
+ EXPECT_TRUE(Unregister(callback_registration_));
+ EXPECT_FALSE(GetRegistration(sync_reg_1_));
+ EXPECT_TRUE(GetRegistration(sync_reg_2_));
+ EXPECT_EQ(SYNC_ONE_SHOT, callback_registration_.periodicity);
+
+ EXPECT_TRUE(Unregister(callback_registration_));
+ EXPECT_FALSE(GetRegistration(sync_reg_2_));
+}
+
+TEST_F(BackgroundSyncManagerTest, OneShotFiresOnRegistration) {
+ InitSyncEventTest();
+
+ EXPECT_TRUE(Register(sync_reg_1_));
+ EXPECT_EQ(1, sync_events_called_);
+ EXPECT_FALSE(GetRegistration(sync_reg_1_));
+}
+
+TEST_F(BackgroundSyncManagerTest, OneShotFiresOnNetworkChange) {
+ InitSyncEventTest();
+
+ SetNetwork(net::NetworkChangeNotifier::CONNECTION_NONE);
+ EXPECT_TRUE(Register(sync_reg_1_));
+ EXPECT_EQ(0, sync_events_called_);
+ EXPECT_TRUE(GetRegistration(sync_reg_1_));
+
+ SetNetwork(net::NetworkChangeNotifier::CONNECTION_WIFI);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(1, sync_events_called_);
+ EXPECT_FALSE(GetRegistration(sync_reg_1_));
+}
+
+TEST_F(BackgroundSyncManagerTest, MultipleOneShotsFireOnNetworkChange) {
+ InitSyncEventTest();
+
+ SetNetwork(net::NetworkChangeNotifier::CONNECTION_NONE);
+ EXPECT_TRUE(Register(sync_reg_1_));
+ EXPECT_TRUE(Register(sync_reg_2_));
+ EXPECT_EQ(0, sync_events_called_);
+ EXPECT_TRUE(GetRegistration(sync_reg_1_));
+ EXPECT_TRUE(GetRegistration(sync_reg_2_));
+
+ SetNetwork(net::NetworkChangeNotifier::CONNECTION_WIFI);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(2, sync_events_called_);
+ EXPECT_FALSE(GetRegistration(sync_reg_1_));
+ EXPECT_FALSE(GetRegistration(sync_reg_2_));
+}
+
+TEST_F(BackgroundSyncManagerTest, OneShotFiresOnManagerRestart) {
+ InitSyncEventTest();
+
+ // Initially the event won't run because there is no network.
+ SetNetwork(net::NetworkChangeNotifier::CONNECTION_NONE);
+ EXPECT_TRUE(Register(sync_reg_1_));
+ EXPECT_EQ(0, sync_events_called_);
+ EXPECT_TRUE(GetRegistration(sync_reg_1_));
+
+ // Simulate closing the browser.
+ background_sync_manager_.reset();
+
+ // The next time the manager is started, the network is good.
+ SetNetwork(net::NetworkChangeNotifier::CONNECTION_WIFI);
+ InitSyncEventTest();
+
+ // The event should have fired.
+ EXPECT_EQ(1, sync_events_called_);
+ EXPECT_FALSE(GetRegistration(sync_reg_1_));
+}
+
+TEST_F(BackgroundSyncManagerTest, FailedOneShotStillExists) {
+ InitFailedSyncEventTest();
+
+ EXPECT_TRUE(Register(sync_reg_1_));
+ EXPECT_EQ(1, sync_events_called_);
+ EXPECT_TRUE(GetRegistration(sync_reg_1_));
+
+ // The failed one-shot should stay registered but not fire until the
+ // ServiceWorker is reloaded with an active client. Therefore, changing the
+ // network should not cause the event to run again.
+ SetNetwork(net::NetworkChangeNotifier::CONNECTION_2G);
+ EXPECT_EQ(1, sync_events_called_);
+ EXPECT_TRUE(GetRegistration(sync_reg_1_));
+}
+
+TEST_F(BackgroundSyncManagerTest, DelayOneShotMidSync) {
+ InitDelayedSyncEventTest();
+
+ RegisterAndVerifySyncEventDelayed(sync_reg_1_);
+
+ // Finish firing the event and verify that the registration is removed.
+ sync_fired_callback_.Run(SERVICE_WORKER_OK);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(1, sync_events_called_);
+ EXPECT_FALSE(GetRegistration(sync_reg_1_));
+}
+
+TEST_F(BackgroundSyncManagerTest, OverwriteRegistrationMidSync) {
+ InitDelayedSyncEventTest();
+
+ sync_reg_1_.network_state = NETWORK_STATE_ANY;
+ SetNetwork(net::NetworkChangeNotifier::CONNECTION_NONE);
+
+ RegisterAndVerifySyncEventDelayed(sync_reg_1_);
+
+ // Don't delay the next sync.
+ test_background_sync_manager_->set_one_shot_callback(
+ base::Bind(OneShotSuccessfulCallback, &sync_events_called_));
+
+ // Register a different sync event with the same tag, overwriting the first.
+ sync_reg_1_.network_state = NETWORK_STATE_ONLINE;
+ EXPECT_TRUE(Register(sync_reg_1_));
+
+ // The new sync event won't run as the network requirements aren't met.
+ EXPECT_EQ(1, sync_events_called_);
+ EXPECT_TRUE(GetRegistration(sync_reg_1_));
+
+ // Finish the first event, note that the second is still registered.
+ sync_fired_callback_.Run(SERVICE_WORKER_OK);
+ EXPECT_EQ(1, sync_events_called_);
+ EXPECT_TRUE(GetRegistration(sync_reg_1_));
+
+ // Change the network and the second should run.
+ SetNetwork(net::NetworkChangeNotifier::CONNECTION_WIFI);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(2, sync_events_called_);
+ EXPECT_FALSE(GetRegistration(sync_reg_1_));
+}
+
+TEST_F(BackgroundSyncManagerTest, ReregisterOneShotMidSync) {
+ InitDelayedSyncEventTest();
+
+ RegisterAndVerifySyncEventDelayed(sync_reg_1_);
+
+ // Register the same sync, but don't delay it. It shouldn't run as it's
+ // already firing.
+ test_background_sync_manager_->set_one_shot_callback(
+ base::Bind(OneShotSuccessfulCallback, &sync_events_called_));
+ EXPECT_TRUE(Register(sync_reg_1_));
+ EXPECT_EQ(1, sync_events_called_);
+ EXPECT_TRUE(GetRegistration(sync_reg_1_));
+
+ // Finish the original event, note that the second never runs.
+ sync_fired_callback_.Run(SERVICE_WORKER_OK);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(1, sync_events_called_);
+ EXPECT_FALSE(GetRegistration(sync_reg_1_));
+}
+
+TEST_F(BackgroundSyncManagerTest, UnregisterOneShotMidSync) {
+ InitDelayedSyncEventTest();
+
+ RegisterAndVerifySyncEventDelayed(sync_reg_1_);
+
+ EXPECT_TRUE(Unregister(callback_registration_));
+ EXPECT_FALSE(GetRegistration(sync_reg_1_));
+
+ sync_fired_callback_.Run(SERVICE_WORKER_OK);
+ EXPECT_FALSE(GetRegistration(sync_reg_1_));
+}
+
+TEST_F(BackgroundSyncManagerTest, BadBackendMidSync) {
+ InitDelayedSyncEventTest();
+
+ RegisterAndVerifySyncEventDelayed(sync_reg_1_);
+
+ test_background_sync_manager_->set_corrupt_backend(true);
+ sync_fired_callback_.Run(SERVICE_WORKER_OK);
+ base::RunLoop().RunUntilIdle();
+
+ // The backend should now be disabled because it couldn't unregister the
+ // one-shot.
+ EXPECT_FALSE(Register(sync_reg_2_));
+ EXPECT_FALSE(RegisterWithServiceWorkerId(sw_registration_id_2_, sync_reg_2_));
+}
+
+TEST_F(BackgroundSyncManagerTest, UnregisterServiceWorkerMidSync) {
+ InitDelayedSyncEventTest();
+
+ RegisterAndVerifySyncEventDelayed(sync_reg_1_);
+ UnregisterServiceWorker(sw_registration_id_1_);
+
+ sync_fired_callback_.Run(SERVICE_WORKER_OK);
+
+ // The backend isn't disabled, but the first service worker registration is
+ // gone.
+ EXPECT_FALSE(GetRegistration(sync_reg_1_));
+ EXPECT_FALSE(Register(sync_reg_1_));
+ EXPECT_TRUE(RegisterWithServiceWorkerId(sw_registration_id_2_, sync_reg_1_));
+}
+
+TEST_F(BackgroundSyncManagerTest, KillManagerMidSync) {
+ InitDelayedSyncEventTest();
+
+ RegisterAndVerifySyncEventDelayed(sync_reg_1_);
+
+ // Create a new manager which should fire the sync again on init.
+ InitSyncEventTest();
+ EXPECT_FALSE(GetRegistration(sync_reg_1_));
+ EXPECT_EQ(2, sync_events_called_);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/background_sync/background_sync_network_observer.cc b/chromium/content/browser/background_sync/background_sync_network_observer.cc
new file mode 100644
index 00000000000..fafb1e68a1f
--- /dev/null
+++ b/chromium/content/browser/background_sync/background_sync_network_observer.cc
@@ -0,0 +1,64 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/background_sync/background_sync_network_observer.h"
+
+#include "content/public/browser/browser_thread.h"
+
+namespace content {
+
+BackgroundSyncNetworkObserver::BackgroundSyncNetworkObserver(
+ const base::Closure& network_changed_callback)
+ : connection_type_(net::NetworkChangeNotifier::GetConnectionType()),
+ network_changed_callback_(network_changed_callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
+}
+
+BackgroundSyncNetworkObserver::~BackgroundSyncNetworkObserver() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
+}
+
+bool BackgroundSyncNetworkObserver::NetworkSufficient(
+ SyncNetworkState network_state) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ switch (network_state) {
+ case NETWORK_STATE_ANY:
+ return true;
+ case NETWORK_STATE_AVOID_CELLULAR:
+ // Note that this returns true for CONNECTION_UNKNOWN to avoid never
+ // firing.
+ return connection_type_ != net::NetworkChangeNotifier::CONNECTION_NONE &&
+ !net::NetworkChangeNotifier::IsConnectionCellular(
+ connection_type_);
+ case NETWORK_STATE_ONLINE:
+ return connection_type_ != net::NetworkChangeNotifier::CONNECTION_NONE;
+ }
+
+ NOTREACHED();
+ return false;
+}
+
+void BackgroundSyncNetworkObserver::NotifyNetworkChanged() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ base::MessageLoop::current()->PostTask(FROM_HERE, network_changed_callback_);
+}
+
+void BackgroundSyncNetworkObserver::OnNetworkChanged(
+ net::NetworkChangeNotifier::ConnectionType connection_type) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (connection_type == connection_type_)
+ return;
+
+ connection_type_ = connection_type;
+ NotifyNetworkChanged();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/background_sync/background_sync_network_observer.h b/chromium/content/browser/background_sync/background_sync_network_observer.h
new file mode 100644
index 00000000000..7c81f738a92
--- /dev/null
+++ b/chromium/content/browser/background_sync/background_sync_network_observer.h
@@ -0,0 +1,45 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_BACKGROUND_SYNC_BACKGROUND_SYNC_NETWORK_OBSERVER_H_
+#define CONTENT_BROWSER_BACKGROUND_SYNC_BACKGROUND_SYNC_NETWORK_OBSERVER_H_
+
+#include "base/bind.h"
+#include "content/browser/background_sync/background_sync.pb.h"
+#include "content/common/content_export.h"
+#include "net/base/network_change_notifier.h"
+
+namespace content {
+
+class CONTENT_EXPORT BackgroundSyncNetworkObserver
+ : net::NetworkChangeNotifier::NetworkChangeObserver {
+ public:
+ // Creates a BackgroundSyncNetworkObserver. |network_changed_callback| is
+ // called when the network connection changes asynchronously via PostMessage.
+ BackgroundSyncNetworkObserver(const base::Closure& network_changed_callback);
+
+ ~BackgroundSyncNetworkObserver() override;
+
+ // Returns true if the state of the network meets the needs of
+ // |network_state|.
+ bool NetworkSufficient(SyncNetworkState network_state);
+
+ private:
+ void NotifyNetworkChanged();
+
+ // NetworkChangeObserver overrides
+ void OnNetworkChanged(
+ net::NetworkChangeNotifier::ConnectionType connection_type) override;
+
+ net::NetworkChangeNotifier::ConnectionType connection_type_;
+
+ // The callback to run when the network changes.
+ base::Closure network_changed_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(BackgroundSyncNetworkObserver);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_BACKGROUND_SYNC_BACKGROUND_SYNC_NETWORK_OBSERVER_H_
diff --git a/chromium/content/browser/background_sync/background_sync_network_observer_unittest.cc b/chromium/content/browser/background_sync/background_sync_network_observer_unittest.cc
new file mode 100644
index 00000000000..eb97bedb93d
--- /dev/null
+++ b/chromium/content/browser/background_sync/background_sync_network_observer_unittest.cc
@@ -0,0 +1,108 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/background_sync/background_sync_network_observer.h"
+
+#include "base/run_loop.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "net/base/network_change_notifier.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+class BackgroundSyncNetworkObserverTest : public testing::Test {
+ protected:
+ BackgroundSyncNetworkObserverTest()
+ : network_change_notifier(net::NetworkChangeNotifier::CreateMock()),
+ network_observer_(new BackgroundSyncNetworkObserver(
+ base::Bind(&BackgroundSyncNetworkObserverTest::OnNetworkChanged,
+ base::Unretained(this)))),
+ network_changed_count_(0) {}
+
+ void SetNetwork(net::NetworkChangeNotifier::ConnectionType connection_type) {
+ net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
+ connection_type);
+ base::RunLoop().RunUntilIdle();
+ }
+
+ void OnNetworkChanged() { network_changed_count_++; }
+
+ TestBrowserThreadBundle browser_thread_bundle_;
+
+ scoped_ptr<net::NetworkChangeNotifier> network_change_notifier;
+ scoped_ptr<BackgroundSyncNetworkObserver> network_observer_;
+ int network_changed_count_;
+};
+
+TEST_F(BackgroundSyncNetworkObserverTest, NetworkChangeInvokesCallback) {
+ SetNetwork(net::NetworkChangeNotifier::CONNECTION_NONE);
+ network_changed_count_ = 0;
+
+ SetNetwork(net::NetworkChangeNotifier::CONNECTION_WIFI);
+ EXPECT_EQ(1, network_changed_count_);
+ SetNetwork(net::NetworkChangeNotifier::CONNECTION_3G);
+ EXPECT_EQ(2, network_changed_count_);
+ SetNetwork(net::NetworkChangeNotifier::CONNECTION_UNKNOWN);
+ EXPECT_EQ(3, network_changed_count_);
+ SetNetwork(net::NetworkChangeNotifier::CONNECTION_NONE);
+ EXPECT_EQ(4, network_changed_count_);
+ SetNetwork(net::NetworkChangeNotifier::CONNECTION_NONE);
+ EXPECT_EQ(4, network_changed_count_);
+}
+
+TEST_F(BackgroundSyncNetworkObserverTest, NetworkSufficientAnyNetwork) {
+ SetNetwork(net::NetworkChangeNotifier::CONNECTION_WIFI);
+ EXPECT_TRUE(network_observer_->NetworkSufficient(NETWORK_STATE_ANY));
+
+ SetNetwork(net::NetworkChangeNotifier::CONNECTION_3G);
+ EXPECT_TRUE(network_observer_->NetworkSufficient(NETWORK_STATE_ANY));
+
+ SetNetwork(net::NetworkChangeNotifier::CONNECTION_UNKNOWN);
+ EXPECT_TRUE(network_observer_->NetworkSufficient(NETWORK_STATE_ANY));
+
+ SetNetwork(net::NetworkChangeNotifier::CONNECTION_NONE);
+ EXPECT_TRUE(network_observer_->NetworkSufficient(NETWORK_STATE_ANY));
+}
+
+TEST_F(BackgroundSyncNetworkObserverTest, NetworkSufficientAvoidCellular) {
+ SetNetwork(net::NetworkChangeNotifier::CONNECTION_WIFI);
+ EXPECT_TRUE(
+ network_observer_->NetworkSufficient(NETWORK_STATE_AVOID_CELLULAR));
+
+ SetNetwork(net::NetworkChangeNotifier::CONNECTION_UNKNOWN);
+ EXPECT_TRUE(
+ network_observer_->NetworkSufficient(NETWORK_STATE_AVOID_CELLULAR));
+
+ SetNetwork(net::NetworkChangeNotifier::CONNECTION_2G);
+ EXPECT_FALSE(
+ network_observer_->NetworkSufficient(NETWORK_STATE_AVOID_CELLULAR));
+
+ SetNetwork(net::NetworkChangeNotifier::CONNECTION_3G);
+ EXPECT_FALSE(
+ network_observer_->NetworkSufficient(NETWORK_STATE_AVOID_CELLULAR));
+
+ SetNetwork(net::NetworkChangeNotifier::CONNECTION_4G);
+ EXPECT_FALSE(
+ network_observer_->NetworkSufficient(NETWORK_STATE_AVOID_CELLULAR));
+
+ SetNetwork(net::NetworkChangeNotifier::CONNECTION_NONE);
+ EXPECT_FALSE(
+ network_observer_->NetworkSufficient(NETWORK_STATE_AVOID_CELLULAR));
+}
+
+TEST_F(BackgroundSyncNetworkObserverTest, ConditionsMetOnline) {
+ SetNetwork(net::NetworkChangeNotifier::CONNECTION_WIFI);
+ EXPECT_TRUE(network_observer_->NetworkSufficient(NETWORK_STATE_ONLINE));
+
+ SetNetwork(net::NetworkChangeNotifier::CONNECTION_3G);
+ EXPECT_TRUE(network_observer_->NetworkSufficient(NETWORK_STATE_ONLINE));
+
+ SetNetwork(net::NetworkChangeNotifier::CONNECTION_UNKNOWN);
+ EXPECT_TRUE(network_observer_->NetworkSufficient(NETWORK_STATE_ONLINE));
+
+ SetNetwork(net::NetworkChangeNotifier::CONNECTION_NONE);
+ EXPECT_FALSE(network_observer_->NetworkSufficient(NETWORK_STATE_ONLINE));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/background_sync/background_sync_proto.gyp b/chromium/content/browser/background_sync/background_sync_proto.gyp
new file mode 100644
index 00000000000..2d5c1e75e38
--- /dev/null
+++ b/chromium/content/browser/background_sync/background_sync_proto.gyp
@@ -0,0 +1,17 @@
+{
+ 'targets': [
+ {
+ # GN version: //content/browser/background_sync:background_sync_proto
+ 'target_name': 'background_sync_proto',
+ 'type': 'static_library',
+ 'sources': [
+ 'background_sync.proto',
+ ],
+ 'variables': {
+ 'proto_in_dir': '.',
+ 'proto_out_dir': 'content/browser/background_sync',
+ },
+ 'includes': [ '../../../build/protoc.gypi' ]
+ },
+ ],
+}
diff --git a/chromium/content/browser/bad_message.cc b/chromium/content/browser/bad_message.cc
new file mode 100644
index 00000000000..cc41b00bd82
--- /dev/null
+++ b/chromium/content/browser/bad_message.cc
@@ -0,0 +1,22 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/bad_message.h"
+
+#include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
+#include "content/public/browser/render_process_host.h"
+
+namespace content {
+namespace bad_message {
+
+void ReceivedBadMessage(RenderProcessHost* host, BadMessageReason reason) {
+ LOG(ERROR) << "Terminating renderer for bad IPC message, reason " << reason;
+ UMA_HISTOGRAM_ENUMERATION("Stability.BadMessageTerminated.Content", reason,
+ BAD_MESSAGE_MAX);
+ host->ShutdownForBadMessage();
+}
+
+} // namespace bad_message
+} // namespace content
diff --git a/chromium/content/browser/bad_message.h b/chromium/content/browser/bad_message.h
new file mode 100644
index 00000000000..337014d9a58
--- /dev/null
+++ b/chromium/content/browser/bad_message.h
@@ -0,0 +1,57 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_BAD_MESSAGE_H_
+#define CONTENT_BROWSER_BAD_MESSAGE_H_
+
+namespace content {
+class RenderProcessHost;
+
+namespace bad_message {
+
+// The browser process often chooses to terminate a renderer if it receives
+// a bad IPC message. The reasons are tracked for metrics.
+//
+// Content embedders should implement their own bad message statistics but
+// should use similar histogram names to make analysis easier.
+//
+// NOTE: Do not remove or reorder elements in this list. Add new entries at the
+// end. Items may be renamed but do not change the values. We rely on the enum
+// values in histograms. Also update histograms.xml with any new values.
+enum BadMessageReason {
+ NC_IN_PAGE_NAVIGATION = 0,
+ RFH_CAN_COMMIT_URL_BLOCKED = 1,
+ RFH_CAN_ACCESS_FILES_OF_PAGE_STATE = 2,
+ RFH_SANDBOX_FLAGS = 3,
+ RFH_NO_PROXY_TO_PARENT = 4,
+ RPH_DESERIALIZATION_FAILED = 5,
+ RVH_CAN_ACCESS_FILES_OF_PAGE_STATE = 6,
+ RVH_FILE_CHOOSER_PATH = 7,
+ RWH_SYNTHETIC_GESTURE = 8,
+ RWH_FOCUS = 9,
+ RWH_BLUR = 10,
+ RWH_SHARED_BITMAP = 11,
+ RWH_BAD_ACK_MESSAGE = 12,
+ RWHVA_SHARED_MEMORY = 13,
+ SERVICE_WORKER_BAD_URL = 14,
+ WC_INVALID_FRAME_SOURCE = 15,
+ RWHVM_UNEXPECTED_FRAME_TYPE = 16,
+ RFPH_DETACH = 17,
+ DFH_BAD_EMBEDDER_MESSAGE = 18,
+ NC_AUTO_SUBFRAME = 19,
+ // Please add new elements here. The naming convention is abbreviated class
+ // name (e.g. RenderFrameHost becomes RFH) plus a unique description of the
+ // reason.
+ BAD_MESSAGE_MAX
+};
+
+// Called when the browser receives a bad IPC message from a renderer process.
+// Logs the event, records a histogram metric for the |reason|, and terminates
+// the process for |host|.
+void ReceivedBadMessage(RenderProcessHost* host, BadMessageReason reason);
+
+} // namespace bad_message
+} // namespace content
+
+#endif // CONTENT_BROWSER_BAD_MESSAGE_H_
diff --git a/chromium/content/browser/battery_status/OWNERS b/chromium/content/browser/battery_status/OWNERS
new file mode 100644
index 00000000000..67aeaacd028
--- /dev/null
+++ b/chromium/content/browser/battery_status/OWNERS
@@ -0,0 +1,2 @@
+timvolodine@chromium.org
+ppi@chromium.org
diff --git a/chromium/content/browser/battery_status/battery_monitor_impl_browsertest.cc b/chromium/content/browser/battery_status/battery_monitor_impl_browsertest.cc
new file mode 100644
index 00000000000..51fe83db8e1
--- /dev/null
+++ b/chromium/content/browser/battery_status/battery_monitor_impl_browsertest.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 "base/thread_task_runner_handle.h"
+#include "content/public/browser/web_contents.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 "device/battery/battery_status_manager.h"
+#include "device/battery/battery_status_service.h"
+
+// These tests run against the default implementation of the BatteryMonitor
+// service, with a dummy BatteryManager set as a source of the battery
+// information. They can be run only on platforms that use the default service
+// implementation, ie. on the platforms where BatteryStatusService is used.
+
+namespace content {
+
+namespace {
+
+class FakeBatteryManager : public device::BatteryStatusManager {
+ public:
+ explicit FakeBatteryManager(
+ const device::BatteryStatusService::BatteryUpdateCallback& callback)
+ : callback_(callback), battery_status_available_(true), started_(false) {}
+ ~FakeBatteryManager() override {}
+
+ // Methods from BatteryStatusManager.
+ bool StartListeningBatteryChange() override {
+ started_ = true;
+ if (battery_status_available_)
+ InvokeUpdateCallback();
+ return battery_status_available_;
+ }
+
+ void StopListeningBatteryChange() override {}
+
+ void InvokeUpdateCallback() {
+ // Invoke asynchronously to mimic the OS-specific battery managers.
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(callback_, status_));
+ }
+
+ void set_battery_status(const device::BatteryStatus& status) {
+ status_ = status;
+ }
+
+ void set_battery_status_available(bool value) {
+ battery_status_available_ = value;
+ }
+
+ bool started() { return started_; }
+
+ private:
+ device::BatteryStatusService::BatteryUpdateCallback callback_;
+ bool battery_status_available_;
+ bool started_;
+ device::BatteryStatus status_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeBatteryManager);
+};
+
+class BatteryMonitorImplTest : public ContentBrowserTest {
+ public:
+ BatteryMonitorImplTest() : battery_manager_(NULL), battery_service_(NULL) {}
+
+ 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();
+
+ battery_service_->SetBatteryManagerForTesting(battery_manager.Pass());
+ }
+
+ void TearDown() override {
+ battery_service_->SetBatteryManagerForTesting(
+ scoped_ptr<device::BatteryStatusManager>());
+ battery_manager_ = NULL;
+ }
+
+ FakeBatteryManager* battery_manager() { return battery_manager_; }
+
+ private:
+ FakeBatteryManager* battery_manager_;
+ device::BatteryStatusService* battery_service_;
+
+ DISALLOW_COPY_AND_ASSIGN(BatteryMonitorImplTest);
+};
+
+IN_PROC_BROWSER_TEST_F(BatteryMonitorImplTest, BatteryManagerDefaultValues) {
+ // Set the fake battery manager to return false on start. From JavaScript
+ // request a promise for the battery status information and once it resolves
+ // check the default values and navigate to #pass.
+ battery_manager()->set_battery_status_available(false);
+ GURL test_url =
+ GetTestUrl("battery_status", "battery_status_default_test.html");
+ NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 2);
+ EXPECT_EQ("pass", shell()->web_contents()->GetLastCommittedURL().ref());
+ EXPECT_TRUE(battery_manager()->started());
+}
+
+IN_PROC_BROWSER_TEST_F(BatteryMonitorImplTest, 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.
+ device::BatteryStatus status;
+ status.charging = true;
+ status.charging_time = 100;
+ status.discharging_time = std::numeric_limits<double>::infinity();
+ status.level = 0.5;
+ battery_manager()->set_battery_status(status);
+
+ GURL test_url = GetTestUrl("battery_status",
+ "battery_status_promise_resolution_test.html");
+ NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 2);
+ EXPECT_EQ("pass", shell()->web_contents()->GetLastCommittedURL().ref());
+ EXPECT_TRUE(battery_manager()->started());
+}
+
+IN_PROC_BROWSER_TEST_F(BatteryMonitorImplTest,
+ BatteryManagerWithEventListener) {
+ // Set the fake battery manager to return default battery status values.
+ // From JavaScript request a promise for the battery status information.
+ // 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.
+ device::BatteryStatus status;
+ battery_manager()->set_battery_status(status);
+
+ TestNavigationObserver same_tab_observer(shell()->web_contents(), 2);
+ GURL test_url =
+ GetTestUrl("battery_status", "battery_status_event_listener_test.html");
+ shell()->LoadURL(test_url);
+ same_tab_observer.Wait();
+ EXPECT_EQ("resolved", shell()->web_contents()->GetLastCommittedURL().ref());
+
+ TestNavigationObserver same_tab_observer2(shell()->web_contents(), 1);
+ status.level = 0.6;
+ battery_manager()->set_battery_status(status);
+ battery_manager()->InvokeUpdateCallback();
+ same_tab_observer2.Wait();
+ EXPECT_EQ("pass", shell()->web_contents()->GetLastCommittedURL().ref());
+ EXPECT_TRUE(battery_manager()->started());
+}
+
+} // namespace
+
+} // namespace content
diff --git a/chromium/content/browser/battery_status/battery_monitor_integration_browsertest.cc b/chromium/content/browser/battery_status/battery_monitor_integration_browsertest.cc
new file mode 100644
index 00000000000..541d76938dc
--- /dev/null
+++ b/chromium/content/browser/battery_status/battery_monitor_integration_browsertest.cc
@@ -0,0 +1,177 @@
+// Copyright 2014 The Chromium Authors. 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_list.h"
+#include "base/lazy_instance.h"
+#include "base/thread_task_runner_handle.h"
+#include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/content_client.h"
+#include "content/public/common/service_registry.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/browser/shell_content_browser_client.h"
+#include "device/battery/battery_monitor.mojom.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h"
+
+// These tests run against a dummy implementation of the BatteryMonitor service.
+// That is, they verify that the service implementation is correctly exposed to
+// the renderer, whatever the implementation is.
+
+namespace content {
+
+namespace {
+
+typedef base::CallbackList<void(const device::BatteryStatus&)>
+ BatteryUpdateCallbackList;
+typedef BatteryUpdateCallbackList::Subscription BatteryUpdateSubscription;
+
+// Global battery state used in the tests.
+device::BatteryStatus g_battery_status;
+// Global list of test battery monitors to notify when |g_battery_status|
+// changes.
+base::LazyInstance<BatteryUpdateCallbackList> g_callback_list =
+ LAZY_INSTANCE_INITIALIZER;
+
+// Updates the global battery state and notifies existing test monitors.
+void UpdateBattery(const device::BatteryStatus& battery_status) {
+ g_battery_status = battery_status;
+ g_callback_list.Get().Notify(battery_status);
+}
+
+class FakeBatteryMonitor : public device::BatteryMonitor {
+ public:
+ static void Create(mojo::InterfaceRequest<BatteryMonitor> request) {
+ new FakeBatteryMonitor(request.Pass());
+ }
+
+ private:
+ typedef mojo::Callback<void(device::BatteryStatusPtr)> BatteryStatusCallback;
+
+ FakeBatteryMonitor(mojo::InterfaceRequest<BatteryMonitor> request)
+ : binding_(this, request.Pass()) {
+ }
+ ~FakeBatteryMonitor() override {}
+
+ void QueryNextStatus(const BatteryStatusCallback& callback) override {
+ // We don't expect overlapped calls to QueryNextStatus.
+ DCHECK(callback_.is_null());
+
+ callback_ = callback;
+
+ if (!subscription_) {
+ subscription_ =
+ g_callback_list.Get().Add(base::Bind(&FakeBatteryMonitor::DidChange,
+ base::Unretained(this)));
+ // Report initial value.
+ DidChange(g_battery_status);
+ }
+ }
+
+ void DidChange(const device::BatteryStatus& battery_status) {
+ if (!callback_.is_null()) {
+ callback_.Run(battery_status.Clone());
+ callback_.reset();
+ }
+ }
+
+ scoped_ptr<BatteryUpdateSubscription> subscription_;
+ mojo::StrongBinding<BatteryMonitor> binding_;
+ BatteryStatusCallback callback_;
+};
+
+// Overrides the default service implementation with the test implementation
+// declared above.
+class TestContentBrowserClient : public ContentBrowserClient {
+ public:
+ void OverrideRenderProcessMojoServices(ServiceRegistry* registry) override {
+ registry->AddService(base::Bind(&FakeBatteryMonitor::Create));
+ }
+
+#if defined(OS_ANDROID)
+ void GetAdditionalMappedFilesForChildProcess(
+ const base::CommandLine& command_line,
+ int child_process_id,
+ FileDescriptorInfo* mappings) override {
+ ShellContentBrowserClient::Get()->GetAdditionalMappedFilesForChildProcess(
+ command_line, child_process_id, mappings);
+ }
+#endif // defined(OS_ANDROID)
+};
+
+class BatteryMonitorIntegrationTest : public ContentBrowserTest {
+ public:
+ BatteryMonitorIntegrationTest() {}
+
+ void SetUpOnMainThread() override {
+ old_client_ = SetBrowserClientForTesting(&test_client_);
+ }
+
+ void TearDownOnMainThread() override {
+ SetBrowserClientForTesting(old_client_);
+ }
+
+ private:
+ TestContentBrowserClient test_client_;
+ ContentBrowserClient* old_client_;
+
+ DISALLOW_COPY_AND_ASSIGN(BatteryMonitorIntegrationTest);
+};
+
+IN_PROC_BROWSER_TEST_F(BatteryMonitorIntegrationTest, DefaultValues) {
+ // From JavaScript request a promise for the battery status information and
+ // once it resolves check the default values and navigate to #pass.
+ UpdateBattery(device::BatteryStatus());
+ GURL test_url =
+ GetTestUrl("battery_status", "battery_status_default_test.html");
+ NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 2);
+ EXPECT_EQ("pass", shell()->web_contents()->GetLastCommittedURL().ref());
+}
+
+IN_PROC_BROWSER_TEST_F(BatteryMonitorIntegrationTest, ResolvePromise) {
+ // Set the fake battery monitor 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.
+ device::BatteryStatus status;
+ status.charging = true;
+ status.charging_time = 100;
+ status.discharging_time = std::numeric_limits<double>::infinity();
+ status.level = 0.5;
+ UpdateBattery(status);
+
+ GURL test_url = GetTestUrl("battery_status",
+ "battery_status_promise_resolution_test.html");
+ NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 2);
+ EXPECT_EQ("pass", shell()->web_contents()->GetLastCommittedURL().ref());
+}
+
+IN_PROC_BROWSER_TEST_F(BatteryMonitorIntegrationTest, EventListener) {
+ // Set the fake battery monitor to return default battery status values.
+ // From JavaScript request a promise for the battery status information.
+ // 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.
+ device::BatteryStatus status;
+ UpdateBattery(status);
+
+ TestNavigationObserver same_tab_observer(shell()->web_contents(), 2);
+ GURL test_url =
+ GetTestUrl("battery_status", "battery_status_event_listener_test.html");
+ shell()->LoadURL(test_url);
+ same_tab_observer.Wait();
+ EXPECT_EQ("resolved", shell()->web_contents()->GetLastCommittedURL().ref());
+
+ TestNavigationObserver same_tab_observer2(shell()->web_contents(), 1);
+ status.level = 0.6;
+ UpdateBattery(status);
+ same_tab_observer2.Wait();
+ EXPECT_EQ("pass", shell()->web_contents()->GetLastCommittedURL().ref());
+}
+
+} // namespace
+
+} // namespace content
diff --git a/chromium/content/browser/battery_status/battery_status_browsertest.cc b/chromium/content/browser/battery_status/battery_status_browsertest.cc
deleted file mode 100644
index 7da7f86d082..00000000000
--- a/chromium/content/browser/battery_status/battery_status_browsertest.cc
+++ /dev/null
@@ -1,167 +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 "base/command_line.h"
-#include "base/synchronization/waitable_event.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"
-#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 "device/battery/battery_status_manager.h"
-#include "device/battery/battery_status_service.h"
-
-namespace content {
-
-namespace {
-
-class FakeBatteryManager : public device::BatteryStatusManager {
- public:
- explicit FakeBatteryManager(
- const device::BatteryStatusService::BatteryUpdateCallback& callback)
- : callback_(callback), battery_status_available_(true), started_(false) {}
- ~FakeBatteryManager() override {}
-
- // Methods from BatteryStatusManager.
- bool StartListeningBatteryChange() override {
- started_ = true;
- if (battery_status_available_)
- InvokeUpdateCallback();
- return battery_status_available_;
- }
-
- void StopListeningBatteryChange() override {}
-
- void InvokeUpdateCallback() {
- // Invoke asynchronously to mimic the OS-specific battery managers.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::Bind(callback_, status_));
- }
-
- void set_battery_status(const device::BatteryStatus& status) {
- status_ = status;
- }
-
- void set_battery_status_available(bool value) {
- battery_status_available_ = value;
- }
-
- bool started() {
- return started_;
- }
-
- private:
- device::BatteryStatusService::BatteryUpdateCallback callback_;
- bool battery_status_available_;
- bool started_;
- device::BatteryStatus status_;
-
- DISALLOW_COPY_AND_ASSIGN(FakeBatteryManager);
-};
-
-class BatteryStatusBrowserTest : public ContentBrowserTest {
- public:
- BatteryStatusBrowserTest()
- : battery_manager_(NULL),
- battery_service_(NULL) {
- }
-
- void SetUpCommandLine(CommandLine* command_line) override {
- command_line->AppendSwitch(
- switches::kEnableExperimentalWebPlatformFeatures);
- }
-
- 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();
-
- battery_service_->SetBatteryManagerForTesting(
- battery_manager.Pass());
- }
-
- void TearDown() override {
- battery_service_->SetBatteryManagerForTesting(
- scoped_ptr<device::BatteryStatusManager>());
- battery_manager_ = NULL;
- }
-
- FakeBatteryManager* battery_manager() {
- return battery_manager_;
- }
-
- private:
- FakeBatteryManager* battery_manager_;
- device::BatteryStatusService* battery_service_;
-
- DISALLOW_COPY_AND_ASSIGN(BatteryStatusBrowserTest);
-};
-
-IN_PROC_BROWSER_TEST_F(BatteryStatusBrowserTest, BatteryManagerDefaultValues) {
- // Set the fake battery manager to return false on start. From JavaScript
- // request a promise for the battery status information and once it resolves
- // check the default values and navigate to #pass.
- battery_manager()->set_battery_status_available(false);
- GURL test_url = GetTestUrl(
- "battery_status", "battery_status_default_test.html");
- NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 2);
- EXPECT_EQ("pass", shell()->web_contents()->GetLastCommittedURL().ref());
- EXPECT_TRUE(battery_manager()->started());
-}
-
-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.
- device::BatteryStatus status;
- status.charging = true;
- status.charging_time = 100;
- status.discharging_time = std::numeric_limits<double>::infinity();
- status.level = 0.5;
- battery_manager()->set_battery_status(status);
-
- GURL test_url = GetTestUrl(
- "battery_status", "battery_status_promise_resolution_test.html");
- NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 2);
- EXPECT_EQ("pass", shell()->web_contents()->GetLastCommittedURL().ref());
- EXPECT_TRUE(battery_manager()->started());
-}
-
-IN_PROC_BROWSER_TEST_F(BatteryStatusBrowserTest,
- BatteryManagerWithEventListener) {
- // Set the fake battery manager to return default battery status values.
- // From JavaScript request a promise for the battery status information.
- // 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.
- device::BatteryStatus status;
- battery_manager()->set_battery_status(status);
-
- TestNavigationObserver same_tab_observer(shell()->web_contents(), 2);
- GURL test_url = GetTestUrl(
- "battery_status", "battery_status_event_listener_test.html");
- shell()->LoadURL(test_url);
- same_tab_observer.Wait();
- EXPECT_EQ("resolved", shell()->web_contents()->GetLastCommittedURL().ref());
-
- TestNavigationObserver same_tab_observer2(shell()->web_contents(), 1);
- status.level = 0.6;
- battery_manager()->set_battery_status(status);
- battery_manager()->InvokeUpdateCallback();
- same_tab_observer2.Wait();
- EXPECT_EQ("pass", shell()->web_contents()->GetLastCommittedURL().ref());
- EXPECT_TRUE(battery_manager()->started());
-}
-
-} // namespace
-
-} // 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
deleted file mode 100644
index efe94303c4e..00000000000
--- a/chromium/content/browser/battery_status/battery_status_message_filter.h
+++ /dev/null
@@ -1,36 +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_MESSAGE_FILTER_H_
-#define CONTENT_BROWSER_BATTERY_STATUS_BATTERY_STATUS_MESSAGE_FILTER_H_
-
-#include "content/browser/battery_status/battery_status_service.h"
-#include "content/public/browser/browser_message_filter.h"
-
-namespace content {
-
-class BatteryStatusMessageFilter : public BrowserMessageFilter {
- public:
- BatteryStatusMessageFilter();
-
- // BrowserMessageFilter implementation.
- bool OnMessageReceived(const IPC::Message& message) override;
-
- private:
- ~BatteryStatusMessageFilter() override;
-
- void OnBatteryStatusStart();
- void OnBatteryStatusStop();
- void SendBatteryChange(const blink::WebBatteryStatus& status);
-
- BatteryStatusService::BatteryUpdateCallback callback_;
- scoped_ptr<BatteryStatusService::BatteryUpdateSubscription> subscription_;
- bool is_started_;
-
- DISALLOW_COPY_AND_ASSIGN(BatteryStatusMessageFilter);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_BATTERY_STATUS_BATTERY_STATUS_MESSAGE_FILTER_H_
diff --git a/chromium/content/browser/bluetooth/DEPS b/chromium/content/browser/bluetooth/DEPS
new file mode 100644
index 00000000000..78c99702126
--- /dev/null
+++ b/chromium/content/browser/bluetooth/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+device/bluetooth",
+]
diff --git a/chromium/content/browser/bluetooth/OWNERS b/chromium/content/browser/bluetooth/OWNERS
new file mode 100644
index 00000000000..673aeda7145
--- /dev/null
+++ b/chromium/content/browser/bluetooth/OWNERS
@@ -0,0 +1 @@
+scheib@chromium.org
diff --git a/chromium/content/browser/bluetooth/PRESUBMIT.py b/chromium/content/browser/bluetooth/PRESUBMIT.py
new file mode 100644
index 00000000000..3f9babedbd6
--- /dev/null
+++ b/chromium/content/browser/bluetooth/PRESUBMIT.py
@@ -0,0 +1,14 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Presubmit script.
+
+See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
+for more details about the presubmit API built into depot_tools.
+"""
+
+def CheckChangeOnUpload(input_api, output_api):
+ results = []
+ results += input_api.canned_checks.CheckPatchFormatted(input_api, output_api)
+ return results
diff --git a/chromium/content/browser/bluetooth/bluetooth_dispatcher_host.cc b/chromium/content/browser/bluetooth/bluetooth_dispatcher_host.cc
new file mode 100644
index 00000000000..b440cdb5c9e
--- /dev/null
+++ b/chromium/content/browser/bluetooth/bluetooth_dispatcher_host.cc
@@ -0,0 +1,221 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/bluetooth/bluetooth_dispatcher_host.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "content/common/bluetooth/bluetooth_messages.h"
+#include "device/bluetooth/bluetooth_adapter.h"
+#include "device/bluetooth/bluetooth_adapter_factory.h"
+#include "device/bluetooth/bluetooth_device.h"
+#include "device/bluetooth/bluetooth_discovery_session.h"
+
+using device::BluetoothAdapter;
+using device::BluetoothAdapterFactory;
+
+namespace content {
+
+const uint32 kUnspecifiedDeviceClass =
+ 0x1F00; // bluetooth.org/en-us/specification/assigned-numbers/baseband
+const int kScanTime = 5; // 5 seconds of scan time
+
+BluetoothDispatcherHost::BluetoothDispatcherHost()
+ : BrowserMessageFilter(BluetoothMsgStart),
+ bluetooth_mock_data_set_(MockData::NOT_MOCKING),
+ bluetooth_request_device_reject_type_(BluetoothError::NOT_FOUND),
+ weak_ptr_factory_(this) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (BluetoothAdapterFactory::IsBluetoothAdapterAvailable())
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothDispatcherHost::set_adapter,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void BluetoothDispatcherHost::OnDestruct() const {
+ // See class comment: UI Thread Note.
+ BrowserThread::DeleteOnUIThread::Destruct(this);
+}
+
+void BluetoothDispatcherHost::OverrideThreadForMessage(
+ const IPC::Message& message,
+ content::BrowserThread::ID* thread) {
+ // See class comment: UI Thread Note.
+ *thread = BrowserThread::UI;
+}
+
+bool BluetoothDispatcherHost::OnMessageReceived(const IPC::Message& message) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(BluetoothDispatcherHost, message)
+ IPC_MESSAGE_HANDLER(BluetoothHostMsg_RequestDevice, OnRequestDevice)
+ IPC_MESSAGE_HANDLER(BluetoothHostMsg_ConnectGATT, OnConnectGATT)
+ IPC_MESSAGE_HANDLER(BluetoothHostMsg_SetBluetoothMockDataSetForTesting,
+ OnSetBluetoothMockDataSetForTesting)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+BluetoothDispatcherHost::~BluetoothDispatcherHost() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ // Clear adapter, releasing observer references.
+ set_adapter(scoped_refptr<device::BluetoothAdapter>());
+}
+
+void BluetoothDispatcherHost::set_adapter(
+ scoped_refptr<device::BluetoothAdapter> adapter) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (adapter_.get())
+ adapter_->RemoveObserver(this);
+ adapter_ = adapter;
+ if (adapter_.get())
+ adapter_->AddObserver(this);
+}
+
+void BluetoothDispatcherHost::OnRequestDevice(int thread_id, int request_id) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ // TODO(scheib) Extend this very simple mock implementation by using
+ // device/bluetooth/test mock adapter and related classes.
+ switch (bluetooth_mock_data_set_) {
+ case MockData::NOT_MOCKING: {
+ // TODO(scheib): Filter devices by services: crbug.com/440594
+ // TODO(scheib): Device selection UI: crbug.com/436280
+ // TODO(scheib): Utilize BluetoothAdapter::Observer::DeviceAdded/Removed.
+ BluetoothAdapter::DeviceList devices;
+
+ if (adapter_.get()) {
+ adapter_->StartDiscoverySession(
+ base::Bind(&BluetoothDispatcherHost::OnDiscoverySessionStarted,
+ weak_ptr_factory_.GetWeakPtr(), thread_id, request_id),
+ base::Bind(&BluetoothDispatcherHost::OnDiscoverySessionStartedError,
+ weak_ptr_factory_.GetWeakPtr(), thread_id, request_id));
+ } else {
+ DLOG(WARNING) << "No BluetoothAdapter. Can't serve requestDevice.";
+ Send(new BluetoothMsg_RequestDeviceError(thread_id, request_id,
+ BluetoothError::NOT_FOUND));
+ }
+ return;
+ }
+ case MockData::REJECT: {
+ Send(new BluetoothMsg_RequestDeviceError(
+ thread_id, request_id, bluetooth_request_device_reject_type_));
+ return;
+ }
+ case MockData::RESOLVE: {
+ std::vector<std::string> uuids;
+ uuids.push_back("00001800-0000-1000-8000-00805f9b34fb");
+ uuids.push_back("00001801-0000-1000-8000-00805f9b34fb");
+ content::BluetoothDevice device_ipc(
+ "Empty Mock Device instanceID", // instance_id
+ base::UTF8ToUTF16("Empty Mock Device name"), // name
+ kUnspecifiedDeviceClass, // device_class
+ device::BluetoothDevice::VENDOR_ID_BLUETOOTH, // vendor_id_source
+ 0xFFFF, // vendor_id
+ 1, // product_id
+ 2, // product_version
+ true, // paired
+ uuids); // uuids
+ Send(new BluetoothMsg_RequestDeviceSuccess(thread_id, request_id,
+ device_ipc));
+ return;
+ }
+ }
+ NOTREACHED();
+}
+
+void BluetoothDispatcherHost::OnConnectGATT(
+ int thread_id,
+ int request_id,
+ const std::string& device_instance_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ // TODO(ortuno): Add actual implementation of connectGATT. This needs to be
+ // done after the "allowed devices map" is implemented.
+ Send(new BluetoothMsg_ConnectGATTSuccess(thread_id, request_id,
+ device_instance_id));
+}
+
+void BluetoothDispatcherHost::OnSetBluetoothMockDataSetForTesting(
+ const std::string& name) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (name == "RejectRequestDevice_NotFoundError") {
+ bluetooth_mock_data_set_ = MockData::REJECT;
+ bluetooth_request_device_reject_type_ = BluetoothError::NOT_FOUND;
+ } else if (name == "RejectRequestDevice_SecurityError") {
+ bluetooth_mock_data_set_ = MockData::REJECT;
+ bluetooth_request_device_reject_type_ = BluetoothError::SECURITY;
+ } else if (name == "ResolveRequestDevice_Empty" || // TODO(scheib): Remove.
+ name == "Single Empty Device") {
+ bluetooth_mock_data_set_ = MockData::RESOLVE;
+ } else {
+ bluetooth_mock_data_set_ = MockData::NOT_MOCKING;
+ }
+}
+
+void BluetoothDispatcherHost::OnDiscoverySessionStarted(
+ int thread_id,
+ int request_id,
+ scoped_ptr<device::BluetoothDiscoverySession> discovery_session) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ BrowserThread::PostDelayedTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&BluetoothDispatcherHost::StopDiscoverySession,
+ weak_ptr_factory_.GetWeakPtr(), thread_id, request_id,
+ base::Passed(&discovery_session)),
+ base::TimeDelta::FromSeconds(kScanTime));
+}
+
+void BluetoothDispatcherHost::OnDiscoverySessionStartedError(int thread_id,
+ int request_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DLOG(WARNING) << "BluetoothDispatcherHost::OnDiscoverySessionStartedError";
+ Send(new BluetoothMsg_RequestDeviceError(thread_id, request_id,
+ BluetoothError::NOT_FOUND));
+}
+
+void BluetoothDispatcherHost::StopDiscoverySession(
+ int thread_id,
+ int request_id,
+ scoped_ptr<device::BluetoothDiscoverySession> discovery_session) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ discovery_session->Stop(
+ base::Bind(&BluetoothDispatcherHost::OnDiscoverySessionStopped,
+ weak_ptr_factory_.GetWeakPtr(), thread_id, request_id),
+ base::Bind(&BluetoothDispatcherHost::OnDiscoverySessionStoppedError,
+ weak_ptr_factory_.GetWeakPtr(), thread_id, request_id));
+}
+
+void BluetoothDispatcherHost::OnDiscoverySessionStopped(int thread_id,
+ int request_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ BluetoothAdapter::DeviceList devices = adapter_->GetDevices();
+ if (devices.begin() == devices.end()) {
+ Send(new BluetoothMsg_RequestDeviceError(thread_id, request_id,
+ BluetoothError::NOT_FOUND));
+ } else {
+ device::BluetoothDevice* device = *devices.begin();
+ content::BluetoothDevice device_ipc(
+ device->GetAddress(), // instance_id
+ device->GetName(), // name
+ device->GetBluetoothClass(), // device_class
+ device->GetVendorIDSource(), // vendor_id_source
+ device->GetVendorID(), // vendor_id
+ device->GetProductID(), // product_id
+ device->GetDeviceID(), // product_version
+ device->IsPaired(), // paired
+ content::BluetoothDevice::UUIDsFromBluetoothUUIDs(
+ device->GetUUIDs())); // uuids
+ Send(new BluetoothMsg_RequestDeviceSuccess(thread_id, request_id,
+ device_ipc));
+ }
+}
+
+void BluetoothDispatcherHost::OnDiscoverySessionStoppedError(int thread_id,
+ int request_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DLOG(WARNING) << "BluetoothDispatcherHost::OnDiscoverySessionStoppedError";
+ Send(new BluetoothMsg_RequestDeviceError(thread_id, request_id,
+ BluetoothError::NOT_FOUND));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/bluetooth/bluetooth_dispatcher_host.h b/chromium/content/browser/bluetooth/bluetooth_dispatcher_host.h
new file mode 100644
index 00000000000..1cc27c594d5
--- /dev/null
+++ b/chromium/content/browser/bluetooth/bluetooth_dispatcher_host.h
@@ -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.
+
+#ifndef CONTENT_BROWSER_BLUETOOTH_BLUETOOTH_DISPATCHER_HOST_H_
+#define CONTENT_BROWSER_BLUETOOTH_BLUETOOTH_DISPATCHER_HOST_H_
+
+#include "base/basictypes.h"
+#include "base/memory/weak_ptr.h"
+#include "content/common/bluetooth/bluetooth_error.h"
+#include "content/public/browser/browser_message_filter.h"
+#include "device/bluetooth/bluetooth_adapter.h"
+
+namespace content {
+
+// Dispatches and sends bluetooth related messages sent to/from a child
+// process BluetoothDispatcher from/to the main browser process.
+//
+// Intended to be instantiated by the RenderProcessHost and installed as
+// a filter on the channel. BrowserMessageFilter is refcounted and typically
+// lives as long as it is installed on a channel.
+//
+// UI Thread Note:
+// BluetoothDispatcherHost is constructed, operates, and destroyed on the UI
+// thread because BluetoothAdapter and related objects live there.
+class BluetoothDispatcherHost final
+ : public BrowserMessageFilter,
+ public device::BluetoothAdapter::Observer {
+ public:
+ BluetoothDispatcherHost();
+ // BrowserMessageFilter:
+ void OnDestruct() const override;
+ void OverrideThreadForMessage(const IPC::Message& message,
+ BrowserThread::ID* thread) override;
+ bool OnMessageReceived(const IPC::Message& message) override;
+
+ protected:
+ ~BluetoothDispatcherHost() override;
+
+ private:
+ friend class base::DeleteHelper<BluetoothDispatcherHost>;
+ friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>;
+
+ // Set |adapter_| to a BluetoothAdapter instance and register observers,
+ // releasing references to previous |adapter_|.
+ void set_adapter(scoped_refptr<device::BluetoothAdapter> adapter);
+
+ // IPC Handlers, see definitions in bluetooth_messages.h.
+ void OnRequestDevice(int thread_id, int request_id);
+ void OnConnectGATT(int thread_id, int request_id,
+ const std::string& device_instance_id);
+ void OnSetBluetoothMockDataSetForTesting(const std::string& name);
+
+ // Callbacks for BluetoothAdapter::StartDiscoverySession.
+ void OnDiscoverySessionStarted(
+ int thread_id,
+ int request_id,
+ scoped_ptr<device::BluetoothDiscoverySession> discovery_session);
+ void OnDiscoverySessionStartedError(int thread_id, int request_id);
+
+ // Stop in progress discovery session.
+ void StopDiscoverySession(
+ int thread_id,
+ int request_id,
+ scoped_ptr<device::BluetoothDiscoverySession> discovery_session);
+
+ // Callbacks for BluetoothDiscoverySession::Stop.
+ void OnDiscoverySessionStopped(int thread_id, int request_id);
+ void OnDiscoverySessionStoppedError(int thread_id, int request_id);
+
+ // A BluetoothAdapter instance representing an adapter of the system.
+ scoped_refptr<device::BluetoothAdapter> adapter_;
+
+ enum class MockData { NOT_MOCKING, REJECT, RESOLVE };
+ MockData bluetooth_mock_data_set_;
+ BluetoothError bluetooth_request_device_reject_type_;
+
+ // Must be last member, see base/memory/weak_ptr.h documentation
+ base::WeakPtrFactory<BluetoothDispatcherHost> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothDispatcherHost);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_BLUETOOTH_BLUETOOTH_DISPATCHER_HOST_H_
diff --git a/chromium/content/browser/bootstrap_sandbox_mac.cc b/chromium/content/browser/bootstrap_sandbox_mac.cc
index 2361563b197..c4662ada4f4 100644
--- a/chromium/content/browser/bootstrap_sandbox_mac.cc
+++ b/chromium/content/browser/bootstrap_sandbox_mac.cc
@@ -31,7 +31,9 @@ class BootstrapSandboxPolicy : public BrowserChildProcessObserver {
// BrowserChildProcessObserver:
void BrowserChildProcessHostDisconnected(
const ChildProcessData& data) override;
- void BrowserChildProcessCrashed(const ChildProcessData& data) override;
+ void BrowserChildProcessCrashed(
+ const ChildProcessData& data,
+ int exit_code) override;
private:
friend struct DefaultSingletonTraits<BootstrapSandboxPolicy>;
@@ -53,7 +55,8 @@ void BootstrapSandboxPolicy::BrowserChildProcessHostDisconnected(
}
void BootstrapSandboxPolicy::BrowserChildProcessCrashed(
- const ChildProcessData& data) {
+ const ChildProcessData& data,
+ int exit_code) {
sandbox()->ChildDied(data.handle);
}
diff --git a/chromium/content/browser/browser.gni b/chromium/content/browser/browser.gni
index b7e8d7f1d52..925b71af3f5 100644
--- a/chromium/content/browser/browser.gni
+++ b/chromium/content/browser/browser.gni
@@ -6,10 +6,11 @@
# cached, which is a performance optimization that allows us to share the
# results of parsing the .gypi file between the public and private BUILD.gn
# files. It also saves us from duplicating this exec_script call.
-content_browser_gypi_values = exec_script(
- "//build/gypi_to_gn.py",
- [ rebase_path("../content_browser.gypi"),
- "--replace=<(SHARED_INTERMEDIATE_DIR)=$root_gen_dir" ],
- "scope",
- [ "../content_browser.gypi" ])
-
+content_browser_gypi_values =
+ exec_script("//build/gypi_to_gn.py",
+ [
+ rebase_path("../content_browser.gypi"),
+ "--replace=<(SHARED_INTERMEDIATE_DIR)=$root_gen_dir",
+ ],
+ "scope",
+ [ "../content_browser.gypi" ])
diff --git a/chromium/content/browser/browser_child_process_host_impl.cc b/chromium/content/browser/browser_child_process_host_impl.cc
index b22ee21aae6..156c21b961f 100644
--- a/chromium/content/browser/browser_child_process_host_impl.cc
+++ b/chromium/content/browser/browser_child_process_host_impl.cc
@@ -7,10 +7,12 @@
#include "base/base_switches.h"
#include "base/bind.h"
#include "base/command_line.h"
+#include "base/debug/dump_without_crashing.h"
#include "base/files/file_path.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
+#include "base/profiler/scoped_tracker.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/synchronization/waitable_event.h"
@@ -51,15 +53,15 @@ void NotifyProcessHostDisconnected(const ChildProcessData& data) {
BrowserChildProcessHostDisconnected(data));
}
-void NotifyProcessCrashed(const ChildProcessData& data) {
+void NotifyProcessCrashed(const ChildProcessData& data, int exit_code) {
FOR_EACH_OBSERVER(BrowserChildProcessObserver, g_observers.Get(),
- BrowserChildProcessCrashed(data));
+ BrowserChildProcessCrashed(data, exit_code));
}
} // namespace
BrowserChildProcessHost* BrowserChildProcessHost::Create(
- int process_type,
+ content::ProcessType process_type,
BrowserChildProcessHostDelegate* delegate) {
return new BrowserChildProcessHostImpl(process_type, delegate);
}
@@ -79,7 +81,7 @@ BrowserChildProcessHostImpl::BrowserChildProcessList*
// static
void BrowserChildProcessHostImpl::AddObserver(
BrowserChildProcessObserver* observer) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
g_observers.Get().AddObserver(observer);
}
@@ -91,7 +93,7 @@ void BrowserChildProcessHostImpl::RemoveObserver(
}
BrowserChildProcessHostImpl::BrowserChildProcessHostImpl(
- int process_type,
+ content::ProcessType process_type,
BrowserChildProcessHostDelegate* delegate)
: data_(process_type),
delegate_(delegate),
@@ -115,7 +117,7 @@ BrowserChildProcessHostImpl::~BrowserChildProcessHostImpl() {
// static
void BrowserChildProcessHostImpl::TerminateAll() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
// Make a copy since the BrowserChildProcessHost dtor mutates the original
// list.
BrowserChildProcessList copy = g_child_process_list.Get();
@@ -127,8 +129,9 @@ void BrowserChildProcessHostImpl::TerminateAll() {
void BrowserChildProcessHostImpl::Launch(
SandboxedProcessLauncherDelegate* delegate,
- base::CommandLine* cmd_line) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ base::CommandLine* cmd_line,
+ bool terminate_on_shutdown) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
GetContentClient()->browser()->AppendExtraCommandLineSwitches(
cmd_line, data_.id);
@@ -151,40 +154,41 @@ void BrowserChildProcessHostImpl::Launch(
delegate,
cmd_line,
data_.id,
- this));
+ this,
+ terminate_on_shutdown));
}
const ChildProcessData& BrowserChildProcessHostImpl::GetData() const {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
return data_;
}
ChildProcessHost* BrowserChildProcessHostImpl::GetHost() const {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
return child_process_host_.get();
}
-base::ProcessHandle BrowserChildProcessHostImpl::GetHandle() const {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+const base::Process& BrowserChildProcessHostImpl::GetProcess() const {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(child_process_.get())
<< "Requesting a child process handle before launching.";
DCHECK(child_process_->GetProcess().IsValid())
<< "Requesting a child process handle before launch has completed OK.";
- return child_process_->GetProcess().Handle();
+ return child_process_->GetProcess();
}
void BrowserChildProcessHostImpl::SetName(const base::string16& name) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
data_.name = name;
}
void BrowserChildProcessHostImpl::SetHandle(base::ProcessHandle handle) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
data_.handle = handle;
}
void BrowserChildProcessHostImpl::ForceShutdown() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
g_child_process_list.Get().remove(this);
child_process_host_->ForceShutdown();
}
@@ -193,19 +197,13 @@ void BrowserChildProcessHostImpl::SetBackgrounded(bool backgrounded) {
child_process_->SetProcessBackgrounded(backgrounded);
}
-void BrowserChildProcessHostImpl::SetTerminateChildOnShutdown(
- bool terminate_on_shutdown) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- child_process_->SetTerminateChildOnShutdown(terminate_on_shutdown);
-}
-
void BrowserChildProcessHostImpl::AddFilter(BrowserMessageFilter* filter) {
child_process_host_->AddFilter(filter->GetFilter());
}
void BrowserChildProcessHostImpl::NotifyProcessInstanceCreated(
const ChildProcessData& data) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
FOR_EACH_OBSERVER(BrowserChildProcessObserver, g_observers.Get(),
BrowserChildProcessInstanceCreated(data));
}
@@ -218,7 +216,7 @@ void BrowserChildProcessHostImpl::HistogramBadMessageTerminated(
base::TerminationStatus BrowserChildProcessHostImpl::GetTerminationStatus(
bool known_dead, int* exit_code) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!child_process_) // If the delegate doesn't use Launch() helper.
return base::GetTerminationStatus(data_.handle, exit_code);
return child_process_->GetChildTerminationStatus(known_dead,
@@ -237,7 +235,7 @@ void BrowserChildProcessHostImpl::OnChannelConnected(int32 peer_pid) {
early_exit_watcher_.StopWatching();
#endif
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(&NotifyProcessHostConnected, data_));
@@ -251,11 +249,18 @@ void BrowserChildProcessHostImpl::OnChannelError() {
void BrowserChildProcessHostImpl::OnBadMessageReceived(
const IPC::Message& message) {
HistogramBadMessageTerminated(data_.process_type);
- if (CommandLine::ForCurrentProcess()->HasSwitch(
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableKillAfterBadIPC)) {
return;
}
- base::KillProcess(GetHandle(), RESULT_CODE_KILLED_BAD_MESSAGE, false);
+ LOG(ERROR) << "Terminating child process for bad IPC message of type "
+ << message.type();
+
+ // Create a memory dump. This will contain enough stack frames to work out
+ // what the bad message was.
+ base::debug::DumpWithoutCrashing();
+
+ child_process_->GetProcess().Terminate(RESULT_CODE_KILLED_BAD_MESSAGE, false);
}
bool BrowserChildProcessHostImpl::CanShutdown() {
@@ -263,7 +268,7 @@ bool BrowserChildProcessHostImpl::CanShutdown() {
}
void BrowserChildProcessHostImpl::OnChildDisconnected() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(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.
@@ -277,8 +282,9 @@ void BrowserChildProcessHostImpl::OnChildDisconnected() {
case base::TERMINATION_STATUS_PROCESS_CRASHED:
case base::TERMINATION_STATUS_ABNORMAL_TERMINATION: {
delegate_->OnProcessCrashed(exit_code);
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(&NotifyProcessCrashed, data_));
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&NotifyProcessCrashed, data_, exit_code));
UMA_HISTOGRAM_ENUMERATION("ChildProcess.Crashed2",
data_.process_type,
PROCESS_TYPE_MAX);
@@ -319,6 +325,11 @@ void BrowserChildProcessHostImpl::OnProcessLaunchFailed() {
}
void BrowserChildProcessHostImpl::OnProcessLaunched() {
+ // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "465841 BrowserChildProcessHostImpl::OnProcessLaunched"));
const base::Process& process = child_process_->GetProcess();
DCHECK(process.IsValid());
diff --git a/chromium/content/browser/browser_child_process_host_impl.h b/chromium/content/browser/browser_child_process_host_impl.h
index 4490b99e142..08e1b360a11 100644
--- a/chromium/content/browser/browser_child_process_host_impl.h
+++ b/chromium/content/browser/browser_child_process_host_impl.h
@@ -42,9 +42,8 @@ class CONTENT_EXPORT BrowserChildProcessHostImpl
#endif
public ChildProcessLauncher::Client {
public:
- BrowserChildProcessHostImpl(
- int process_type,
- BrowserChildProcessHostDelegate* delegate);
+ BrowserChildProcessHostImpl(content::ProcessType process_type,
+ BrowserChildProcessHostDelegate* delegate);
~BrowserChildProcessHostImpl() override;
// Terminates all child processes and deletes each BrowserChildProcessHost
@@ -54,7 +53,8 @@ class CONTENT_EXPORT BrowserChildProcessHostImpl
// BrowserChildProcessHost implementation:
bool Send(IPC::Message* message) override;
void Launch(SandboxedProcessLauncherDelegate* delegate,
- base::CommandLine* cmd_line) override;
+ base::CommandLine* cmd_line,
+ bool terminate_on_shutdown) override;
const ChildProcessData& GetData() const override;
ChildProcessHost* GetHost() const override;
base::TerminationStatus GetTerminationStatus(bool known_dead,
@@ -65,7 +65,7 @@ class CONTENT_EXPORT BrowserChildProcessHostImpl
// ChildProcessHostDelegate implementation:
bool CanShutdown() override;
void OnChildDisconnected() override;
- base::ProcessHandle GetHandle() const override;
+ const base::Process& GetProcess() const override;
bool OnMessageReceived(const IPC::Message& message) override;
void OnChannelConnected(int32 peer_pid) override;
void OnChannelError() override;
@@ -77,10 +77,6 @@ class CONTENT_EXPORT BrowserChildProcessHostImpl
// Callers can reduce the BrowserChildProcess' priority.
void SetBackgrounded(bool backgrounded);
- // Controls whether the child process should be terminated on browser
- // shutdown. Default is to always terminate.
- void SetTerminateChildOnShutdown(bool terminate_on_shutdown);
-
// Adds an IPC message filter.
void AddFilter(BrowserMessageFilter* filter);
diff --git a/chromium/content/browser/browser_context.cc b/chromium/content/browser/browser_context.cc
index 76188331198..a7394834cc2 100644
--- a/chromium/content/browser/browser_context.cc
+++ b/chromium/content/browser/browser_context.cc
@@ -113,7 +113,7 @@ void BrowserContext::GarbageCollectStoragePartitions(
DownloadManager* BrowserContext::GetDownloadManager(
BrowserContext* context) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!context->GetUserData(kDownloadManagerKeyName)) {
ResourceDispatcherHostImpl* rdh = ResourceDispatcherHostImpl::Get();
DCHECK(rdh);
@@ -206,10 +206,11 @@ StoragePartition* BrowserContext::GetDefaultStoragePartition(
return GetStoragePartition(browser_context, NULL);
}
+// static
void BrowserContext::CreateMemoryBackedBlob(BrowserContext* browser_context,
const char* data, size_t length,
const BlobCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
ChromeBlobStorageContext* blob_context =
ChromeBlobStorageContext::GetFor(browser_context);
@@ -221,13 +222,33 @@ void BrowserContext::CreateMemoryBackedBlob(BrowserContext* browser_context,
}
// static
+void BrowserContext::CreateFileBackedBlob(
+ BrowserContext* browser_context,
+ const base::FilePath& path,
+ int64_t offset,
+ int64_t size,
+ const base::Time& expected_modification_time,
+ const BlobCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ ChromeBlobStorageContext* blob_context =
+ ChromeBlobStorageContext::GetFor(browser_context);
+ BrowserThread::PostTaskAndReplyWithResult(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&ChromeBlobStorageContext::CreateFileBackedBlob,
+ make_scoped_refptr(blob_context), path, offset, size,
+ expected_modification_time),
+ 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));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
PushMessagingRouter::DeliverMessage(
browser_context, origin, service_worker_registration_id, data, callback);
}
diff --git a/chromium/content/browser/browser_ipc_logging.cc b/chromium/content/browser/browser_ipc_logging.cc
index 20a56f6f6d5..7e7f05e1b70 100644
--- a/chromium/content/browser/browser_ipc_logging.cc
+++ b/chromium/content/browser/browser_ipc_logging.cc
@@ -16,7 +16,7 @@ namespace content {
#if defined(IPC_MESSAGE_LOG_ENABLED)
void EnableIPCLoggingForChildProcesses(bool enabled) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
BrowserChildProcessHostIterator i; // default constr references a singleton
while (!i.Done()) {
diff --git a/chromium/content/browser/browser_main.cc b/chromium/content/browser/browser_main.cc
index 640ccee5ac7..4c114b43613 100644
--- a/chromium/content/browser/browser_main.cc
+++ b/chromium/content/browser/browser_main.cc
@@ -4,7 +4,7 @@
#include "content/browser/browser_main.h"
-#include "base/debug/trace_event.h"
+#include "base/trace_event/trace_event.h"
#include "content/common/content_constants_internal.h"
#include "content/public/browser/browser_main_runner.h"
@@ -13,8 +13,8 @@ namespace content {
// Main routine for running as the Browser process.
int BrowserMain(const MainFunctionParams& parameters) {
TRACE_EVENT_BEGIN_ETW("BrowserMain", 0, "");
- base::debug::TraceLog::GetInstance()->SetProcessName("Browser");
- base::debug::TraceLog::GetInstance()->SetProcessSortIndex(
+ base::trace_event::TraceLog::GetInstance()->SetProcessName("Browser");
+ base::trace_event::TraceLog::GetInstance()->SetProcessSortIndex(
kTraceEventBrowserProcessSortIndex);
scoped_ptr<BrowserMainRunner> main_runner(BrowserMainRunner::Create());
diff --git a/chromium/content/browser/browser_main_loop.cc b/chromium/content/browser/browser_main_loop.cc
index c7dd81bcf36..456bc14ece3 100644
--- a/chromium/content/browser/browser_main_loop.cc
+++ b/chromium/content/browser/browser_main_loop.cc
@@ -6,8 +6,8 @@
#include "base/bind.h"
#include "base/command_line.h"
-#include "base/debug/trace_event.h"
#include "base/logging.h"
+#include "base/memory/memory_pressure_monitor.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
@@ -15,17 +15,23 @@
#include "base/power_monitor/power_monitor.h"
#include "base/power_monitor/power_monitor_device_source.h"
#include "base/process/process_metrics.h"
+#include "base/profiler/scoped_profile.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
#include "base/system_monitor/system_monitor.h"
#include "base/thread_task_runner_handle.h"
#include "base/threading/thread_restrictions.h"
#include "base/timer/hi_res_timer_manager.h"
+#include "base/trace_event/memory_dump_manager.h"
+#include "base/trace_event/trace_event.h"
#include "content/browser/browser_thread_impl.h"
#include "content/browser/device_sensors/device_inertial_sensor_service.h"
+#include "content/browser/dom_storage/dom_storage_area.h"
#include "content/browser/download/save_file_manager.h"
#include "content/browser/gamepad/gamepad_service.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_process_host.h"
@@ -40,6 +46,9 @@
#include "content/browser/time_zone_monitor.h"
#include "content/browser/webui/content_web_ui_controller_factory.h"
#include "content/browser/webui/url_data_manager.h"
+#include "content/common/content_switches_internal.h"
+#include "content/common/host_discardable_shared_memory_manager.h"
+#include "content/common/host_shared_bitmap_manager.h"
#include "content/public/browser/browser_main_parts.h"
#include "content/public/browser/browser_shutdown.h"
#include "content/public/browser/content_browser_client.h"
@@ -82,9 +91,15 @@
#include "ui/gl/gl_surface.h"
#endif
+#if defined(OS_MACOSX)
+#include "media/base/mac/avfoundation_glue.h"
+#endif
+
#if defined(OS_MACOSX) && !defined(OS_IOS)
+#include "base/mac/memory_pressure_monitor.h"
#include "content/browser/bootstrap_sandbox_mac.h"
#include "content/browser/cocoa/system_hotkey_helper_mac.h"
+#include "content/browser/compositor/browser_compositor_view_mac.h"
#include "content/browser/theme_helper_mac.h"
#endif
@@ -93,12 +108,18 @@
#include <commctrl.h>
#include <shellapi.h>
+#include "base/win/memory_pressure_monitor.h"
#include "content/browser/system_message_window_win.h"
#include "content/common/sandbox_win.h"
#include "net/base/winsock_init.h"
#include "ui/base/l10n/l10n_util_win.h"
#endif
+#if defined(OS_CHROMEOS)
+#include "base/chromeos/memory_pressure_monitor.h"
+#include "chromeos/chromeos_switches.h"
+#endif
+
#if defined(USE_GLIB)
#include <glib-object.h>
#endif
@@ -112,7 +133,7 @@
#if defined(OS_POSIX) && !defined(OS_MACOSX)
#include "content/browser/renderer_host/render_sandbox_host_linux.h"
#include "content/browser/zygote_host/zygote_host_impl_linux.h"
-#include "sandbox/linux/suid/client/setuid_sandbox_client.h"
+#include "sandbox/linux/suid/client/setuid_sandbox_host.h"
#endif
#if defined(ENABLE_PLUGINS)
@@ -141,20 +162,20 @@ void SetupSandbox(const base::CommandLine& parsed_command_line) {
TRACE_EVENT0("startup", "SetupSandbox");
base::FilePath sandbox_binary;
- scoped_ptr<sandbox::SetuidSandboxClient> setuid_sandbox_client(
- sandbox::SetuidSandboxClient::Create());
+ scoped_ptr<sandbox::SetuidSandboxHost> setuid_sandbox_host(
+ sandbox::SetuidSandboxHost::Create());
const bool want_setuid_sandbox =
!parsed_command_line.HasSwitch(switches::kNoSandbox) &&
!parsed_command_line.HasSwitch(switches::kDisableSetuidSandbox) &&
- !setuid_sandbox_client->IsDisabledViaEnvironment();
+ !setuid_sandbox_host->IsDisabledViaEnvironment();
static const char no_suid_error[] =
"Running without the SUID sandbox! See "
"https://code.google.com/p/chromium/wiki/LinuxSUIDSandboxDevelopment "
"for more information on developing with the sandbox on.";
if (want_setuid_sandbox) {
- sandbox_binary = setuid_sandbox_client->GetSandboxBinaryPath();
+ sandbox_binary = setuid_sandbox_host->GetSandboxBinaryPath();
if (sandbox_binary.empty()) {
// This needs to be fatal. Talk to security@chromium.org if you feel
// otherwise.
@@ -231,16 +252,6 @@ void OnStoppedStartupTracing(const base::FilePath& trace_file) {
VLOG(0) << "Completed startup tracing to " << trace_file.value();
}
-#if defined(USE_AURA)
-bool ShouldInitializeBrowserGpuChannelAndTransportSurface() {
- return true;
-}
-#elif defined(OS_MACOSX) && !defined(OS_IOS)
-bool ShouldInitializeBrowserGpuChannelAndTransportSurface() {
- return IsDelegatedRendererEnabled();
-}
-#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.
@@ -248,33 +259,47 @@ MSVC_DISABLE_OPTIMIZE()
MSVC_PUSH_DISABLE_WARNING(4748)
NOINLINE void ResetThread_DB(scoped_ptr<BrowserProcessSubThread> thread) {
+ volatile int inhibit_comdat = __LINE__;
+ ALLOW_UNUSED_LOCAL(inhibit_comdat);
thread.reset();
}
NOINLINE void ResetThread_FILE(scoped_ptr<BrowserProcessSubThread> thread) {
+ volatile int inhibit_comdat = __LINE__;
+ ALLOW_UNUSED_LOCAL(inhibit_comdat);
thread.reset();
}
NOINLINE void ResetThread_FILE_USER_BLOCKING(
scoped_ptr<BrowserProcessSubThread> thread) {
+ volatile int inhibit_comdat = __LINE__;
+ ALLOW_UNUSED_LOCAL(inhibit_comdat);
thread.reset();
}
NOINLINE void ResetThread_PROCESS_LAUNCHER(
scoped_ptr<BrowserProcessSubThread> thread) {
+ volatile int inhibit_comdat = __LINE__;
+ ALLOW_UNUSED_LOCAL(inhibit_comdat);
thread.reset();
}
NOINLINE void ResetThread_CACHE(scoped_ptr<BrowserProcessSubThread> thread) {
+ volatile int inhibit_comdat = __LINE__;
+ ALLOW_UNUSED_LOCAL(inhibit_comdat);
thread.reset();
}
NOINLINE void ResetThread_IO(scoped_ptr<BrowserProcessSubThread> thread) {
+ volatile int inhibit_comdat = __LINE__;
+ ALLOW_UNUSED_LOCAL(inhibit_comdat);
thread.reset();
}
#if !defined(OS_IOS)
NOINLINE void ResetThread_IndexedDb(scoped_ptr<base::Thread> thread) {
+ volatile int inhibit_comdat = __LINE__;
+ ALLOW_UNUSED_LOCAL(inhibit_comdat);
thread.reset();
}
#endif
@@ -282,6 +307,34 @@ NOINLINE void ResetThread_IndexedDb(scoped_ptr<base::Thread> thread) {
MSVC_POP_WARNING()
MSVC_ENABLE_OPTIMIZE();
+#if defined(OS_WIN)
+// Creates a memory pressure monitor using automatic thresholds, or those
+// specified on the command-line. Ownership is passed to the caller.
+base::win::MemoryPressureMonitor* CreateWinMemoryPressureMonitor(
+ const base::CommandLine& parsed_command_line) {
+ std::vector<std::string> thresholds;
+ base::SplitString(
+ parsed_command_line.GetSwitchValueASCII(
+ switches::kMemoryPressureThresholdsMb),
+ ',',
+ &thresholds);
+
+ int moderate_threshold_mb = 0;
+ int critical_threshold_mb = 0;
+ if (thresholds.size() == 2 &&
+ base::StringToInt(thresholds[0], &moderate_threshold_mb) &&
+ base::StringToInt(thresholds[1], &critical_threshold_mb) &&
+ moderate_threshold_mb >= critical_threshold_mb &&
+ critical_threshold_mb >= 0) {
+ return new base::win::MemoryPressureMonitor(moderate_threshold_mb,
+ critical_threshold_mb);
+ }
+
+ // In absence of valid switches use the automatic defaults.
+ return new base::win::MemoryPressureMonitor();
+}
+#endif // defined(OS_WIN)
+
} // namespace
// The currently-running BrowserMainLoop. There can be one or zero.
@@ -341,7 +394,7 @@ class BrowserMainLoop::MemoryObserver : public base::MessageLoop::TaskObserver {
// BrowserMainLoop construction / destruction =============================
BrowserMainLoop* BrowserMainLoop::GetInstance() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
return g_current_browser_main_loop;
}
@@ -368,6 +421,8 @@ BrowserMainLoop::~BrowserMainLoop() {
void BrowserMainLoop::Init() {
TRACE_EVENT0("startup", "BrowserMainLoop::Init");
+ TRACK_SCOPED_REGION("Startup", "BrowserMainLoop::Init");
+
parts_.reset(
GetContentClient()->browser()->CreateBrowserMainParts(parameters_));
}
@@ -376,6 +431,7 @@ void BrowserMainLoop::Init() {
void BrowserMainLoop::EarlyInitialization() {
TRACE_EVENT0("startup", "BrowserMainLoop::EarlyInitialization");
+ TRACK_SCOPED_REGION("Startup", "BrowserMainLoop::EarlyInitialization");
#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
// No thread should be created before this call, as SetupSandbox()
@@ -384,8 +440,7 @@ void BrowserMainLoop::EarlyInitialization() {
#endif
#if defined(USE_X11)
- if (parsed_command_line_.HasSwitch(switches::kSingleProcess) ||
- parsed_command_line_.HasSwitch(switches::kInProcessGPU)) {
+ if (UsingInProcessGpu()) {
if (!gfx::InitializeThreadedX11()) {
LOG(ERROR) << "Failed to put Xlib into threaded mode.";
}
@@ -440,12 +495,27 @@ void BrowserMainLoop::EarlyInitialization() {
}
#endif // !defined(OS_IOS)
+ if (parsed_command_line_.HasSwitch(switches::kEnableNativeGpuMemoryBuffers)) {
+ BrowserGpuChannelHostFactory::EnableGpuMemoryBufferFactoryUsage(
+ gfx::GpuMemoryBuffer::MAP);
+ }
+
+#if defined(USE_OZONE)
+ BrowserGpuChannelHostFactory::EnableGpuMemoryBufferFactoryUsage(
+ gfx::GpuMemoryBuffer::SCANOUT);
+#endif
+
+ base::DiscardableMemoryAllocator::SetInstance(
+ HostDiscardableSharedMemoryManager::current());
+
if (parts_)
parts_->PostEarlyInitialization();
}
void BrowserMainLoop::MainMessageLoopStart() {
TRACE_EVENT0("startup", "BrowserMainLoop::MainMessageLoopStart");
+ TRACK_SCOPED_REGION("Startup", "BrowserMainLoop::MainMessageLoopStart");
+
if (parts_) {
TRACE_EVENT0("startup",
"BrowserMainLoop::MainMessageLoopStart:PreMainMessageLoopStart");
@@ -492,15 +562,6 @@ void BrowserMainLoop::MainMessageLoopStart() {
media::InitializeCPUSpecificMediaFeatures();
}
{
- TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:AudioMan");
- audio_manager_.reset(media::AudioManager::Create(
- MediaInternals::GetInstance()));
- }
- {
- TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:MidiManager");
- midi_manager_.reset(media::MidiManager::Create());
- }
- {
TRACE_EVENT0("startup",
"BrowserMainLoop::Subsystem:ContentWebUIController");
WebUIControllerFactory::RegisterFactory(
@@ -513,8 +574,9 @@ void BrowserMainLoop::MainMessageLoopStart() {
}
{
- system_stats_monitor_.reset(new base::debug::TraceEventSystemStatsMonitor(
- base::ThreadTaskRunnerHandle::Get()));
+ system_stats_monitor_.reset(
+ new base::trace_event::TraceEventSystemStatsMonitor(
+ base::ThreadTaskRunnerHandle::Get()));
}
#endif // !defined(OS_IOS)
@@ -541,7 +603,8 @@ void BrowserMainLoop::MainMessageLoopStart() {
SurfaceTextureManager::InitInstance(new BrowserSurfaceTextureManager);
}
- {
+ if (!parsed_command_line_.HasSwitch(
+ switches::kDisableScreenOrientationLock)) {
TRACE_EVENT0("startup",
"BrowserMainLoop::Subsystem:ScreenOrientationProvider");
screen_orientation_delegate_.reset(
@@ -556,11 +619,23 @@ void BrowserMainLoop::MainMessageLoopStart() {
base::MessageLoop::current()->AddTaskObserver(memory_observer_.get());
}
+ if (parsed_command_line_.HasSwitch(
+ switches::kEnableAggressiveDOMStorageFlushing)) {
+ TRACE_EVENT0("startup",
+ "BrowserMainLoop::Subsystem:EnableAggressiveCommitDelay");
+ DOMStorageArea::EnableAggressiveCommitDelay();
+ }
+
+ base::trace_event::MemoryDumpManager::GetInstance()->Initialize();
+
+ // Enable the dump providers.
+ base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
+ HostSharedBitmapManager::current());
+
#if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED)
- trace_memory_controller_.reset(new base::debug::TraceMemoryController(
+ trace_memory_controller_.reset(new base::trace_event::TraceMemoryController(
base::MessageLoop::current()->message_loop_proxy(),
- ::HeapProfilerWithPseudoStackStart,
- ::HeapProfilerStop,
+ ::HeapProfilerWithPseudoStackStart, ::HeapProfilerStop,
::GetHeapProfile));
#endif
}
@@ -569,9 +644,25 @@ int BrowserMainLoop::PreCreateThreads() {
if (parts_) {
TRACE_EVENT0("startup",
"BrowserMainLoop::CreateThreads:PreCreateThreads");
+ TRACK_SCOPED_REGION("Startup", "BrowserMainLoop::PreCreateThreads");
+
result_code_ = parts_->PreCreateThreads();
}
+ // TODO(chrisha): Abstract away this construction mess to a helper function,
+ // once MemoryPressureMonitor is made a concrete class.
+#if defined(OS_CHROMEOS)
+ if (chromeos::switches::MemoryPressureHandlingEnabled()) {
+ memory_pressure_monitor_.reset(new base::chromeos::MemoryPressureMonitor(
+ chromeos::switches::GetMemoryPressureThresholds()));
+ }
+#elif defined(OS_MACOSX) && !defined(OS_IOS)
+ memory_pressure_monitor_.reset(new base::mac::MemoryPressureMonitor());
+#elif defined(OS_WIN)
+ memory_pressure_monitor_.reset(CreateWinMemoryPressureMonitor(
+ parsed_command_line_));
+#endif
+
#if defined(ENABLE_PLUGINS)
// Prior to any processing happening on the io thread, we create the
// plugin service as it is predominantly used from the io thread,
@@ -583,17 +674,47 @@ int BrowserMainLoop::PreCreateThreads() {
}
#endif
+#if defined(OS_MACOSX)
+ {
+ // Initialize AVFoundation if supported, for audio and video.
+ TRACE_EVENT0("startup",
+ "BrowserMainLoop::CreateThreads:InitializeAVFoundation");
+ AVFoundationGlue::InitializeAVFoundation();
+ }
+#endif
+
+ // Need to initialize in-process GpuDataManager before creating threads.
+ // It's unsafe to append the gpu command line switches to the global
+ // CommandLine::ForCurrentProcess object after threads are created.
+ if (UsingInProcessGpu()) {
+ bool initialize_gpu_data_manager = true;
+#if defined(OS_ANDROID)
+ if (!gfx::GLSurface::InitializeOneOff()) {
+ // Single-process Android WebView supports no gpu.
+ LOG(ERROR) << "GLSurface::InitializeOneOff failed";
+ initialize_gpu_data_manager = false;
+ }
+#endif
+
+ // Initialize the GpuDataManager before we set up the MessageLoops because
+ // otherwise we'll trigger the assertion about doing IO on the UI thread.
+ if (initialize_gpu_data_manager)
+ GpuDataManagerImpl::GetInstance()->Initialize();
+ }
+
#if !defined(OS_IOS) && (!defined(GOOGLE_CHROME_BUILD) || defined(OS_ANDROID))
// Single-process is an unsupported and not fully tested mode, so
// don't enable it for official Chrome builds (except on Android).
if (parsed_command_line_.HasSwitch(switches::kSingleProcess))
RenderProcessHost::SetRunRendererInProcess(true);
#endif
+
return result_code_;
}
void BrowserMainLoop::CreateStartupTasks() {
TRACE_EVENT0("startup", "BrowserMainLoop::CreateStartupTasks");
+ TRACK_SCOPED_REGION("Startup", "BrowserMainLoop::CreateStartupTasks");
// First time through, we really want to create all the tasks
if (!startup_task_runner_.get()) {
@@ -644,6 +765,7 @@ void BrowserMainLoop::CreateStartupTasks() {
int BrowserMainLoop::CreateThreads() {
TRACE_EVENT0("startup", "BrowserMainLoop::CreateThreads");
+ TRACK_SCOPED_REGION("Startup", "BrowserMainLoop::CreateThreads");
base::Thread::Options io_message_loop_options;
io_message_loop_options.message_loop_type = base::MessageLoop::TYPE_IO;
@@ -740,6 +862,9 @@ int BrowserMainLoop::PreMainMessageLoopRun() {
if (parts_) {
TRACE_EVENT0("startup",
"BrowserMainLoop::CreateThreads:PreMainMessageLoopRun");
+ TRACK_SCOPED_REGION(
+ "Startup", "BrowserMainLoop::PreMainMessageLoopRun");
+
parts_->PreMainMessageLoopRun();
}
@@ -808,8 +933,14 @@ void BrowserMainLoop::ShutdownThreadsAndCleanUp() {
resource_dispatcher_host_.get()->Shutdown();
}
+ memory_pressure_monitor_.reset();
+
+#if defined(OS_MACOSX)
+ BrowserCompositorMac::DisableRecyclingForShutdown();
+#endif
+
#if defined(USE_AURA) || defined(OS_MACOSX)
- if (ShouldInitializeBrowserGpuChannelAndTransportSurface()) {
+ {
TRACE_EVENT0("shutdown",
"BrowserMainLoop::Subsystem:ImageTransportFactory");
ImageTransportFactory::Terminate();
@@ -976,60 +1107,83 @@ int BrowserMainLoop::BrowserThreadsStarted() {
indexed_db_thread_->Start();
#endif
-#if defined(OS_ANDROID)
- // Up the priority of anything that touches with display tasks
- // (this thread is UI thread, and io_thread_ is for IPCs).
- io_thread_->SetPriority(base::kThreadPriority_Display);
- base::PlatformThread::SetThreadPriority(
- base::PlatformThread::CurrentHandle(),
- base::kThreadPriority_Display);
-#endif
-
#if !defined(OS_IOS)
HistogramSynchronizer::GetInstance();
- bool initialize_gpu_data_manager = true;
+
+ // GpuDataManager for in-process initialized in PreCreateThreads.
+ bool initialize_gpu_data_manager = !UsingInProcessGpu();
#if defined(OS_ANDROID)
- // On Android, GLSurface::InitializeOneOff() must be called before initalizing
- // the GpuDataManagerImpl as it uses the GL bindings. crbug.com/326295
- if (!gfx::GLSurface::InitializeOneOff()) {
- LOG(ERROR) << "GLSurface::InitializeOneOff failed";
- initialize_gpu_data_manager = false;
+ // Up the priority of anything that touches with display tasks
+ // (this thread is UI thread, and io_thread_ is for IPCs).
+ io_thread_->SetPriority(base::ThreadPriority::DISPLAY);
+ base::PlatformThread::SetThreadPriority(base::PlatformThread::CurrentHandle(),
+ base::ThreadPriority::DISPLAY);
+
+ // On Android, GLSurface::InitializeOneOff() must be called before
+ // initalizing the GpuDataManagerImpl as it uses the GL bindings.
+ // TODO(sievers): Shouldn't need to init full bindings to determine GL
+ // version/vendor strings. crbug.com/326295
+ if (initialize_gpu_data_manager) {
+ // Note InitializeOneOff is not safe either for in-process gpu after
+ // creating threads, since it may race with the gpu thread.
+ if (!gfx::GLSurface::InitializeOneOff()) {
+ LOG(FATAL) << "GLSurface::InitializeOneOff failed";
+ }
}
#endif
- // Initialize the GpuDataManager before we set up the MessageLoops because
- // otherwise we'll trigger the assertion about doing IO on the UI thread.
if (initialize_gpu_data_manager)
GpuDataManagerImpl::GetInstance()->Initialize();
bool always_uses_gpu = true;
bool established_gpu_channel = false;
#if defined(USE_AURA) || defined(OS_MACOSX)
- if (ShouldInitializeBrowserGpuChannelAndTransportSurface()) {
- established_gpu_channel = true;
- if (!GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor()) {
- established_gpu_channel = always_uses_gpu = false;
- }
- BrowserGpuChannelHostFactory::Initialize(established_gpu_channel);
- ImageTransportFactory::Initialize();
+ established_gpu_channel = true;
+ if (!GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor() ||
+ parsed_command_line_.HasSwitch(switches::kDisableGpuEarlyInit)) {
+ established_gpu_channel = always_uses_gpu = false;
+ }
+ BrowserGpuChannelHostFactory::Initialize(established_gpu_channel);
+ ImageTransportFactory::Initialize();
#if defined(USE_AURA)
- if (aura::Env::GetInstance()) {
- aura::Env::GetInstance()->set_context_factory(GetContextFactory());
- }
-#endif
+ if (aura::Env::GetInstance()) {
+ aura::Env::GetInstance()->set_context_factory(GetContextFactory());
}
+#endif
#elif defined(OS_ANDROID)
- established_gpu_channel = true;
+ // TODO(crbug.com/439322): This should be set to |true|.
+ established_gpu_channel = false;
BrowserGpuChannelHostFactory::Initialize(established_gpu_channel);
#endif
+ // Enable the GpuMemoryBuffer dump provider with IO thread affinity. Note that
+ // unregistration happens on the IO thread (See
+ // BrowserProcessSubThread::IOThreadPreCleanUp).
+ base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
+ BrowserGpuMemoryBufferManager::current(), io_thread_->task_runner());
+
+ {
+ TRACE_EVENT0("startup", "BrowserThreadsStarted::Subsystem:AudioMan");
+ audio_manager_.reset(media::AudioManager::CreateWithHangTimer(
+ MediaInternals::GetInstance(), io_thread_->task_runner()));
+ }
+
+ {
+ TRACE_EVENT0("startup", "BrowserThreadsStarted::Subsystem:MidiManager");
+ midi_manager_.reset(media::midi::MidiManager::Create());
+ }
+
#if defined(OS_LINUX) && defined(USE_UDEV)
device_monitor_linux_.reset(new DeviceMonitorLinux());
#elif defined(OS_MACOSX)
device_monitor_mac_.reset(new DeviceMonitorMac());
#endif
+#if defined(OS_WIN)
+ UMA_HISTOGRAM_BOOLEAN("Windows.Win32kRendererLockdown",
+ IsWin32kRendererLockdownEnabled());
+#endif
// RDH needs the IO thread to be created
{
TRACE_EVENT0("startup",
@@ -1083,8 +1237,7 @@ int BrowserMainLoop::BrowserThreadsStarted() {
if (GpuDataManagerImpl::GetInstance()->GpuAccessAllowed(NULL) &&
!established_gpu_channel &&
always_uses_gpu &&
- !parsed_command_line_.HasSwitch(switches::kSingleProcess) &&
- !parsed_command_line_.HasSwitch(switches::kInProcessGPU)) {
+ !UsingInProcessGpu()) {
TRACE_EVENT_INSTANT0("gpu", "Post task to launch GPU process",
TRACE_EVENT_SCOPE_THREAD);
BrowserThread::PostTask(
@@ -1109,8 +1262,15 @@ int BrowserMainLoop::BrowserThreadsStarted() {
return result_code_;
}
+bool BrowserMainLoop::UsingInProcessGpu() const {
+ return parsed_command_line_.HasSwitch(switches::kSingleProcess) ||
+ parsed_command_line_.HasSwitch(switches::kInProcessGPU);
+}
+
bool BrowserMainLoop::InitializeToolkit() {
TRACE_EVENT0("startup", "BrowserMainLoop::InitializeToolkit");
+ TRACK_SCOPED_REGION("Startup", "BrowserMainLoop::InitializeToolkit");
+
// TODO(evan): this function is rather subtle, due to the variety
// of intersecting ifdefs we have. To keep it easy to follow, there
// are no #else branches on any #ifs.
diff --git a/chromium/content/browser/browser_main_loop.h b/chromium/content/browser/browser_main_loop.h
index 188aa3209d3..27bc664bd72 100644
--- a/chromium/content/browser/browser_main_loop.h
+++ b/chromium/content/browser/browser_main_loop.h
@@ -20,16 +20,19 @@ class HighResolutionTimerManager;
class MessageLoop;
class PowerMonitor;
class SystemMonitor;
-namespace debug {
+class MemoryPressureMonitor;
+namespace trace_event {
class TraceMemoryController;
class TraceEventSystemStatsMonitor;
-} // namespace debug
+} // namespace trace_event
} // namespace base
namespace media {
class AudioManager;
-class MidiManager;
class UserInputMonitor;
+namespace midi {
+class MidiManager;
+} // namespace midi
} // namespace media
namespace net {
@@ -99,7 +102,7 @@ class CONTENT_EXPORT BrowserMainLoop {
media::UserInputMonitor* user_input_monitor() const {
return user_input_monitor_.get();
}
- media::MidiManager* midi_manager() const { return midi_manager_.get(); }
+ media::midi::MidiManager* midi_manager() const { return midi_manager_.get(); }
base::Thread* indexed_db_thread() const { return indexed_db_thread_.get(); }
bool is_tracing_startup() const { return is_tracing_startup_; }
@@ -141,6 +144,9 @@ class CONTENT_EXPORT BrowserMainLoop {
void InitStartupTracing(const base::CommandLine& command_line);
void EndStartupTracing();
+ bool UsingInProcessGpu() const;
+ void InitializeGpuDataManager();
+
// Members initialized on construction ---------------------------------------
const MainFunctionParams& parameters_;
const base::CommandLine& parsed_command_line_;
@@ -157,7 +163,7 @@ class CONTENT_EXPORT BrowserMainLoop {
// user_input_monitor_ has to outlive audio_manager_, so declared first.
scoped_ptr<media::UserInputMonitor> user_input_monitor_;
scoped_ptr<media::AudioManager> audio_manager_;
- scoped_ptr<media::MidiManager> midi_manager_;
+ scoped_ptr<media::midi::MidiManager> midi_manager_;
scoped_ptr<MediaStreamManager> media_stream_manager_;
// Per-process listener for online state changes.
scoped_ptr<BrowserOnlineStateObserver> online_state_observer_;
@@ -172,6 +178,11 @@ class CONTENT_EXPORT BrowserMainLoop {
// Android implementation of ScreenOrientationDelegate
scoped_ptr<ScreenOrientationDelegate> screen_orientation_delegate_;
#endif
+
+ // Memory pressure monitor. Created in PreCreateThreads and torn down in
+ // ShutdownThreadsAndCleanUp.
+ scoped_ptr<base::MemoryPressureMonitor> memory_pressure_monitor_;
+
// The startup task runner is created by CreateStartupTasks()
scoped_ptr<StartupTaskRunner> startup_task_runner_;
@@ -197,8 +208,9 @@ class CONTENT_EXPORT BrowserMainLoop {
scoped_ptr<BrowserProcessSubThread> io_thread_;
scoped_ptr<base::Thread> indexed_db_thread_;
scoped_ptr<MemoryObserver> memory_observer_;
- scoped_ptr<base::debug::TraceMemoryController> trace_memory_controller_;
- scoped_ptr<base::debug::TraceEventSystemStatsMonitor> system_stats_monitor_;
+ scoped_ptr<base::trace_event::TraceMemoryController> trace_memory_controller_;
+ scoped_ptr<base::trace_event::TraceEventSystemStatsMonitor>
+ system_stats_monitor_;
bool is_tracing_startup_;
base::FilePath startup_trace_file_;
diff --git a/chromium/content/browser/browser_main_runner.cc b/chromium/content/browser/browser_main_runner.cc
index 4a74b6eb5f8..f98ece33520 100644
--- a/chromium/content/browser/browser_main_runner.cc
+++ b/chromium/content/browser/browser_main_runner.cc
@@ -4,14 +4,16 @@
#include "content/public/browser/browser_main_runner.h"
-#include "base/allocator/allocator_shim.h"
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/debug/leak_annotations.h"
-#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/metrics/statistics_recorder.h"
+#include "base/profiler/scoped_profile.h"
+#include "base/profiler/scoped_tracker.h"
+#include "base/trace_event/trace_event.h"
+#include "base/tracked_objects.h"
#include "content/browser/browser_main_loop.h"
#include "content/browser/browser_shutdown_profile_dumper.h"
#include "content/browser/notification_service_impl.h"
@@ -20,16 +22,11 @@
#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
@@ -117,34 +114,6 @@ void InstallSha256LegacyHooks() {
#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
@@ -160,7 +129,13 @@ class BrowserMainRunnerImpl : public BrowserMainRunner {
}
int Initialize(const MainFunctionParams& parameters) override {
+ // TODO(vadimt, yiyaoliu): Remove all tracked_objects references below once
+ // crbug.com/453640 is fixed.
+ tracked_objects::ThreadData::InitializeThreadContext("CrBrowserMain");
+ TRACK_SCOPED_REGION(
+ "Startup", "BrowserMainRunnerImpl::Initialize");
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
// another application to start the browser. If this happens then we must
@@ -198,7 +173,7 @@ class BrowserMainRunnerImpl : public BrowserMainRunner {
// on Windows 8 Metro mode.
ole_initializer_.reset(new ui::ScopedOleInitializer);
// Enable DirectWrite font rendering if needed.
- MaybeEnableDirectWriteFontRendering();
+ gfx::win::MaybeInitializeDirectWrite();
#endif // OS_WIN
main_loop_.reset(new BrowserMainLoop(parameters));
@@ -217,14 +192,6 @@ class BrowserMainRunnerImpl : public BrowserMainRunner {
// are NOT deleted. If you need something to run during WM_ENDSESSION add it
// to browser_shutdown::Shutdown or BrowserProcess::EndSession.
-#if defined(OS_WIN) && !defined(NO_TCMALLOC)
- // When linking shared libraries, NO_TCMALLOC is defined, and dynamic
- // allocator selection is not supported.
-
- // Make this call before going multithreaded, or spawning any
- // subprocesses.
- base::allocator::SetupSubprocessAllocator();
-#endif
ui::InitializeInputMethod();
}
main_loop_->CreateStartupTasks();
@@ -293,7 +260,8 @@ class BrowserMainRunnerImpl : public BrowserMainRunner {
// Forcefully terminates the RunLoop inside MessagePumpForUI, ensuring
// proper shutdown for content_browsertests. Shutdown() is not used by
// the actual browser.
- base::MessageLoop::current()->QuitNow();
+ if (base::MessageLoop::current()->is_running())
+ base::MessageLoop::current()->QuitNow();
#endif
main_loop_.reset(NULL);
diff --git a/chromium/content/browser/browser_plugin/browser_plugin_embedder.cc b/chromium/content/browser/browser_plugin/browser_plugin_embedder.cc
index cb471594ac8..e563df0cac8 100644
--- a/chromium/content/browser/browser_plugin/browser_plugin_embedder.cc
+++ b/chromium/content/browser/browser_plugin/browser_plugin_embedder.cc
@@ -4,24 +4,15 @@
#include "content/browser/browser_plugin/browser_plugin_embedder.h"
-#include "base/values.h"
#include "content/browser/browser_plugin/browser_plugin_guest.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#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/drag_messages.h"
-#include "content/common/gpu/gpu_messages.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_plugin_guest_manager.h"
-#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/native_web_keyboard_event.h"
#include "content/public/browser/render_view_host.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/url_constants.h"
-#include "net/base/escape.h"
#include "third_party/WebKit/public/web/WebFindOptions.h"
#include "ui/events/keycodes/keyboard_codes.h"
@@ -42,8 +33,9 @@ BrowserPluginEmbedder* BrowserPluginEmbedder::Create(
return new BrowserPluginEmbedder(web_contents);
}
-void BrowserPluginEmbedder::DragEnteredGuest(BrowserPluginGuest* guest) {
+bool BrowserPluginEmbedder::DragEnteredGuest(BrowserPluginGuest* guest) {
guest_dragging_over_ = guest->AsWeakPtr();
+ return guest_started_drag_.get() == guest;
}
void BrowserPluginEmbedder::DragLeftGuest(BrowserPluginGuest* guest) {
@@ -54,18 +46,46 @@ void BrowserPluginEmbedder::DragLeftGuest(BrowserPluginGuest* guest) {
}
}
+// static
+bool BrowserPluginEmbedder::NotifyScreenInfoChanged(
+ WebContents* guest_web_contents) {
+ if (guest_web_contents->GetRenderViewHost()) {
+ auto render_widget_host =
+ RenderWidgetHostImpl::From(guest_web_contents->GetRenderViewHost());
+ render_widget_host->NotifyScreenInfoChanged();
+ }
+
+ // Returns false to iterate over all guests.
+ return false;
+}
+
+void BrowserPluginEmbedder::ScreenInfoChanged() {
+ GetBrowserPluginGuestManager()->ForEachGuest(web_contents(), base::Bind(
+ &BrowserPluginEmbedder::NotifyScreenInfoChanged));
+}
+
+// static
+bool BrowserPluginEmbedder::CancelDialogs(WebContents* guest_web_contents) {
+ static_cast<WebContentsImpl*>(guest_web_contents)
+ ->CancelActiveAndPendingDialogs();
+
+ // Returns false to iterate over all guests.
+ return false;
+}
+
+void BrowserPluginEmbedder::CancelGuestDialogs() {
+ GetBrowserPluginGuestManager()->ForEachGuest(
+ web_contents(), base::Bind(&BrowserPluginEmbedder::CancelDialogs));
+}
+
void BrowserPluginEmbedder::StartDrag(BrowserPluginGuest* guest) {
guest_started_drag_ = guest->AsWeakPtr();
guest_drag_ending_ = false;
}
-WebContentsImpl* BrowserPluginEmbedder::GetWebContents() const {
- return static_cast<WebContentsImpl*>(web_contents());
-}
-
BrowserPluginGuestManager*
BrowserPluginEmbedder::GetBrowserPluginGuestManager() const {
- return GetWebContents()->GetBrowserContext()->GetGuestManager();
+ return web_contents()->GetBrowserContext()->GetGuestManager();
}
void BrowserPluginEmbedder::ClearGuestDragStateIfApplicable() {
@@ -82,6 +102,7 @@ void BrowserPluginEmbedder::ClearGuestDragStateIfApplicable() {
}
}
+// static
bool BrowserPluginEmbedder::DidSendScreenRectsCallback(
WebContents* guest_web_contents) {
static_cast<RenderViewHostImpl*>(
@@ -92,14 +113,20 @@ bool BrowserPluginEmbedder::DidSendScreenRectsCallback(
void BrowserPluginEmbedder::DidSendScreenRects() {
GetBrowserPluginGuestManager()->ForEachGuest(
- GetWebContents(), base::Bind(
- &BrowserPluginEmbedder::DidSendScreenRectsCallback,
- base::Unretained(this)));
+ web_contents(),
+ base::Bind(&BrowserPluginEmbedder::DidSendScreenRectsCallback));
}
bool BrowserPluginEmbedder::OnMessageReceived(const IPC::Message& message) {
+ return OnMessageReceived(message, nullptr);
+}
+
+bool BrowserPluginEmbedder::OnMessageReceived(
+ const IPC::Message& message,
+ RenderFrameHost* render_frame_host) {
bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(BrowserPluginEmbedder, message)
+ IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(BrowserPluginEmbedder, message,
+ render_frame_host)
IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_Attach, OnAttach)
IPC_MESSAGE_HANDLER_GENERIC(DragHostMsg_UpdateDragCursor,
OnUpdateDragCursor(&handled));
@@ -124,26 +151,31 @@ void BrowserPluginEmbedder::SystemDragEnded() {
// 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_)
- guest_started_drag_->EndSystemDrag();
+ guest_started_drag_->EmbedderSystemDragEnded();
+
guest_dragging_over_.reset();
ClearGuestDragStateIfApplicable();
}
void BrowserPluginEmbedder::OnUpdateDragCursor(bool* handled) {
- *handled = (guest_dragging_over_.get() != NULL);
+ *handled = !!guest_dragging_over_;
}
void BrowserPluginEmbedder::OnAttach(
+ RenderFrameHost* render_frame_host,
int browser_plugin_instance_id,
const BrowserPluginHostMsg_Attach_Params& params) {
WebContents* guest_web_contents =
GetBrowserPluginGuestManager()->GetGuestByInstanceID(
- GetWebContents(), browser_plugin_instance_id);
+ render_frame_host->GetProcess()->GetID(),
+ 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);
+ guest->Attach(browser_plugin_instance_id,
+ static_cast<WebContentsImpl*>(web_contents()),
+ params);
}
bool BrowserPluginEmbedder::HandleKeyboardEvent(
@@ -155,26 +187,22 @@ bool BrowserPluginEmbedder::HandleKeyboardEvent(
bool event_consumed = false;
GetBrowserPluginGuestManager()->ForEachGuest(
- GetWebContents(),
+ web_contents(),
base::Bind(&BrowserPluginEmbedder::UnlockMouseIfNecessaryCallback,
- base::Unretained(this),
&event_consumed));
return event_consumed;
}
-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),
- request_id,
- search_text,
- options));
+BrowserPluginGuest* BrowserPluginEmbedder::GetFullPageGuest() {
+ WebContentsImpl* guest_contents = static_cast<WebContentsImpl*>(
+ GetBrowserPluginGuestManager()->GetFullPageGuest(web_contents()));
+ if (!guest_contents)
+ return nullptr;
+ return guest_contents->GetBrowserPluginGuest();
}
+// static
bool BrowserPluginEmbedder::UnlockMouseIfNecessaryCallback(bool* mouse_unlocked,
WebContents* guest) {
*mouse_unlocked |= static_cast<WebContentsImpl*>(guest)
@@ -186,17 +214,4 @@ bool BrowserPluginEmbedder::UnlockMouseIfNecessaryCallback(bool* mouse_unlocked,
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 7ea98f7773a..842d3ee1b03 100644
--- a/chromium/content/browser/browser_plugin/browser_plugin_embedder.h
+++ b/chromium/content/browser/browser_plugin/browser_plugin_embedder.h
@@ -14,27 +14,18 @@
#ifndef CONTENT_BROWSER_BROWSER_PLUGIN_BROWSER_PLUGIN_EMBEDDER_H_
#define CONTENT_BROWSER_BROWSER_PLUGIN_BROWSER_PLUGIN_EMBEDDER_H_
-#include <map>
-
#include "base/memory/weak_ptr.h"
-#include "base/values.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "third_party/WebKit/public/web/WebDragOperation.h"
struct BrowserPluginHostMsg_Attach_Params;
-struct BrowserPluginHostMsg_ResizeGuest_Params;
-
-namespace gfx {
-class Point;
-}
namespace content {
class BrowserPluginGuest;
class BrowserPluginGuestManager;
class RenderWidgetHostImpl;
-class WebContentsImpl;
struct NativeWebKeyboardEvent;
class CONTENT_EXPORT BrowserPluginEmbedder : public WebContentsObserver {
@@ -43,24 +34,33 @@ class CONTENT_EXPORT BrowserPluginEmbedder : public WebContentsObserver {
static BrowserPluginEmbedder* Create(WebContentsImpl* web_contents);
- // Returns this embedder's WebContentsImpl.
- WebContentsImpl* GetWebContents() const;
-
// Called when embedder's |rwh| has sent screen rects to renderer.
void DidSendScreenRects();
// WebContentsObserver implementation.
bool OnMessageReceived(const IPC::Message& message) override;
+ bool OnMessageReceived(const IPC::Message& message,
+ RenderFrameHost* render_frame_host) override;
+ // Sends a 'dragend' message to the guest that started the drag.
void DragSourceEndedAt(int client_x, int client_y, int screen_x,
int screen_y, blink::WebDragOperation operation);
- void OnUpdateDragCursor(bool* handled);
-
- void DragEnteredGuest(BrowserPluginGuest* guest);
+ // Indicates that a drag operation has entered into the bounds of a given
+ // |guest|. Returns whether the |guest| also started the operation.
+ bool DragEnteredGuest(BrowserPluginGuest* guest);
+ // Indicates that a drag operation has left the bounds of a given |guest|.
void DragLeftGuest(BrowserPluginGuest* guest);
+ // Called when the screen info has changed.
+ void ScreenInfoChanged();
+
+ // Closes modal dialogs in all of the guests.
+ void CancelGuestDialogs();
+
+ // Called by WebContentsViewGuest when a drag operation is started within
+ // |guest|. This |guest| will be signaled at the end of the drag operation.
void StartDrag(BrowserPluginGuest* guest);
// Sends EndSystemDrag message to the guest that initiated the last drag/drop
@@ -70,11 +70,10 @@ class CONTENT_EXPORT BrowserPluginEmbedder : public WebContentsObserver {
// 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);
+ // Returns the "full page" guest if there is one. That is, if there is a
+ // single BrowserPlugin in the embedder which takes up the full page, then it
+ // is returned.
+ BrowserPluginGuest* GetFullPageGuest();
private:
explicit BrowserPluginEmbedder(WebContentsImpl* web_contents);
@@ -83,21 +82,23 @@ class CONTENT_EXPORT BrowserPluginEmbedder : public WebContentsObserver {
void ClearGuestDragStateIfApplicable();
- bool DidSendScreenRectsCallback(WebContents* guest_web_contents);
+ static bool DidSendScreenRectsCallback(WebContents* guest_web_contents);
+
+ // Notifies a guest that the embedder's screen info has changed.
+ static bool NotifyScreenInfoChanged(WebContents* guest_web_contents);
- bool UnlockMouseIfNecessaryCallback(bool* mouse_unlocked, WebContents* guest);
+ // Closes modal dialogs in |guest_web_contents|.
+ static bool CancelDialogs(WebContents* guest_web_contents);
- bool FindInGuest(int request_id,
- const base::string16& search_text,
- const blink::WebFindOptions& options,
- WebContents* guest);
+ static bool UnlockMouseIfNecessaryCallback(bool* mouse_unlocked,
+ WebContents* guest);
// Message handlers.
- void OnAttach(int instance_id,
+
+ void OnAttach(RenderFrameHost* render_frame_host,
+ int instance_id,
const BrowserPluginHostMsg_Attach_Params& params);
- void OnPluginAtPositionResponse(int instance_id,
- int request_id,
- const gfx::Point& position);
+ void OnUpdateDragCursor(bool* handled);
// Used to correctly update the cursor when dragging over a guest, and to
// handle a race condition when dropping onto the guest that started the drag
diff --git a/chromium/content/browser/browser_plugin/browser_plugin_guest.cc b/chromium/content/browser/browser_plugin/browser_plugin_guest.cc
index c2db313eedd..3f6173a2ca5 100644
--- a/chromium/content/browser/browser_plugin/browser_plugin_guest.cc
+++ b/chromium/content/browser/browser_plugin/browser_plugin_guest.cc
@@ -31,6 +31,7 @@
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_plugin_guest_manager.h"
#include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/guest_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/user_metrics.h"
#include "content/public/browser/web_contents_observer.h"
@@ -43,15 +44,15 @@
namespace content {
-class BrowserPluginGuest::EmbedderWebContentsObserver
+class BrowserPluginGuest::EmbedderVisibilityObserver
: public WebContentsObserver {
public:
- explicit EmbedderWebContentsObserver(BrowserPluginGuest* guest)
+ explicit EmbedderVisibilityObserver(BrowserPluginGuest* guest)
: WebContentsObserver(guest->embedder_web_contents()),
browser_plugin_guest_(guest) {
}
- ~EmbedderWebContentsObserver() override {}
+ ~EmbedderVisibilityObserver() override {}
// WebContentsObserver implementation.
void WasShown() override {
@@ -65,16 +66,16 @@ class BrowserPluginGuest::EmbedderWebContentsObserver
private:
BrowserPluginGuest* browser_plugin_guest_;
- DISALLOW_COPY_AND_ASSIGN(EmbedderWebContentsObserver);
+ DISALLOW_COPY_AND_ASSIGN(EmbedderVisibilityObserver);
};
BrowserPluginGuest::BrowserPluginGuest(bool has_render_view,
WebContentsImpl* web_contents,
BrowserPluginGuestDelegate* delegate)
: WebContentsObserver(web_contents),
- embedder_web_contents_(NULL),
+ owner_web_contents_(nullptr),
+ attached_(false),
browser_plugin_instance_id_(browser_plugin::kInstanceIDNone),
- guest_device_scale_factor_(1.0f),
focused_(false),
mouse_locked_(false),
pending_lock_request_(false),
@@ -83,35 +84,94 @@ BrowserPluginGuest::BrowserPluginGuest(bool has_render_view,
is_full_page_plugin_(false),
has_render_view_(has_render_view),
is_in_destruction_(false),
+ initialized_(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),
guest_proxy_routing_id_(MSG_ROUTING_NONE),
+ last_drag_status_(blink::WebDragStatusUnknown),
+ seen_embedder_system_drag_ended_(false),
+ seen_embedder_drag_source_ended_at_(false),
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()));
+ delegate->SetGuestHost(this);
+}
+
+int BrowserPluginGuest::GetGuestProxyRoutingID() {
+ if (guest_proxy_routing_id_ != MSG_ROUTING_NONE)
+ return guest_proxy_routing_id_;
+
+ // Create a swapped out RenderView for the guest in the embedder renderer
+ // 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.
+ //
+ // TODO(fsamuel): Make sure this works for transferring guests across
+ // owners in different processes. We probably need to clear the
+ // |guest_proxy_routing_id_| and perform any necessary cleanup on Detach
+ // to enable this.
+ SiteInstance* owner_site_instance = owner_web_contents_->GetSiteInstance();
+ guest_proxy_routing_id_ =
+ GetWebContents()->CreateSwappedOutRenderView(owner_site_instance);
+
+ return guest_proxy_routing_id_;
+}
+
+int BrowserPluginGuest::LoadURLWithParams(
+ const NavigationController::LoadURLParams& load_params) {
+ GetWebContents()->GetController().LoadURLWithParams(load_params);
+ return GetGuestProxyRoutingID();
+}
+
+void BrowserPluginGuest::SizeContents(const gfx::Size& new_size) {
+ GetWebContents()->GetView()->SizeContents(new_size);
}
void BrowserPluginGuest::WillDestroy() {
is_in_destruction_ = true;
- embedder_web_contents_ = NULL;
+ owner_web_contents_ = nullptr;
+ attached_ = false;
+}
+
+void BrowserPluginGuest::Init() {
+ if (initialized_)
+ return;
+ initialized_ = true;
+
+ // TODO(fsamuel): Initiailization prior to attachment should be behind a
+ // command line flag once we introduce experimental guest types that rely on
+ // this functionality.
+ if (!delegate_->CanRunInDetachedState())
+ return;
+
+ WebContentsImpl* owner_web_contents = static_cast<WebContentsImpl*>(
+ delegate_->GetOwnerWebContents());
+ owner_web_contents->CreateBrowserPluginEmbedderIfNecessary();
+ InitInternal(BrowserPluginHostMsg_Attach_Params(), owner_web_contents);
}
base::WeakPtr<BrowserPluginGuest> BrowserPluginGuest::AsWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
-void BrowserPluginGuest::SetFocus(RenderWidgetHost* rwh, bool focused) {
+void BrowserPluginGuest::SetFocus(RenderWidgetHost* rwh,
+ bool focused,
+ blink::WebFocusType focus_type) {
focused_ = focused;
if (!rwh)
return;
+ if ((focus_type == blink::WebFocusTypeForward) ||
+ (focus_type == blink::WebFocusTypeBackward)) {
+ static_cast<RenderViewHostImpl*>(RenderViewHost::From(rwh))->
+ SetInitialFocus(focus_type == blink::WebFocusTypeBackward);
+ }
rwh->Send(new InputMsg_SetFocus(rwh->GetRoutingID(), focused));
if (!focused && mouse_locked_)
OnUnlockMouse();
@@ -119,10 +179,7 @@ void BrowserPluginGuest::SetFocus(RenderWidgetHost* rwh, bool focused) {
// 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_);
- }
+ SendTextInputTypeChangedToView(rwhv);
}
void BrowserPluginGuest::SetTooltipText(const base::string16& tooltip_text) {
@@ -153,8 +210,8 @@ bool BrowserPluginGuest::OnMessageReceivedFromEmbedder(
const IPC::Message& message) {
RenderWidgetHostViewGuest* rwhv = static_cast<RenderWidgetHostViewGuest*>(
web_contents()->GetRenderWidgetHostView());
- if (rwhv &&
- rwhv->OnMessageReceivedFromEmbedder(
+ // Until the guest is attached, it should not be handling input events.
+ if (attached() && rwhv && rwhv->OnMessageReceivedFromEmbedder(
message,
static_cast<RenderViewHostImpl*>(
embedder_web_contents()->GetRenderViewHost()))) {
@@ -165,6 +222,7 @@ bool BrowserPluginGuest::OnMessageReceivedFromEmbedder(
IPC_BEGIN_MESSAGE_MAP(BrowserPluginGuest, message)
IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_CompositorFrameSwappedACK,
OnCompositorFrameSwappedACK)
+ IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_Detach, OnDetach)
IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_DragStatusUpdate,
OnDragStatusUpdate)
IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ExecuteEditCommand,
@@ -178,7 +236,6 @@ bool BrowserPluginGuest::OnMessageReceivedFromEmbedder(
IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_LockMouse_ACK, OnLockMouseAck)
IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ReclaimCompositorResources,
OnReclaimCompositorResources)
- IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ResizeGuest, OnResizeGuest)
IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent,
OnSetEditCommandsForNextKeyEvent)
IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetFocus, OnSetFocus)
@@ -190,26 +247,31 @@ bool BrowserPluginGuest::OnMessageReceivedFromEmbedder(
return handled;
}
-void BrowserPluginGuest::Initialize(
- int browser_plugin_instance_id,
+void BrowserPluginGuest::InitInternal(
const BrowserPluginHostMsg_Attach_Params& params,
- WebContentsImpl* embedder_web_contents) {
- browser_plugin_instance_id_ = browser_plugin_instance_id;
+ WebContentsImpl* owner_web_contents) {
focused_ = params.focused;
+ OnSetFocus(browser_plugin::kInstanceIDNone,
+ focused_,
+ blink::WebFocusTypeNone);
+
guest_visible_ = params.visible;
+ UpdateVisibility();
+
is_full_page_plugin_ = params.is_full_page_plugin;
- guest_window_rect_ = gfx::Rect(params.origin,
- params.resize_guest_params.view_size);
+ guest_window_rect_ = params.view_rect;
- WebContentsViewGuest* new_view =
- static_cast<WebContentsViewGuest*>(GetWebContents()->GetView());
- if (attached())
- new_view->OnGuestDetached(embedder_web_contents_->GetView());
+ if (owner_web_contents_ != owner_web_contents) {
+ WebContentsViewGuest* new_view =
+ static_cast<WebContentsViewGuest*>(GetWebContents()->GetView());
+ if (owner_web_contents_)
+ new_view->OnGuestDetached(owner_web_contents_->GetView());
- // Once a BrowserPluginGuest has an embedder WebContents, it's considered to
- // be attached.
- embedder_web_contents_ = embedder_web_contents;
- new_view->OnGuestAttached(embedder_web_contents->GetView());
+ // Once a BrowserPluginGuest has an embedder WebContents, it's considered to
+ // be attached.
+ owner_web_contents_ = owner_web_contents;
+ new_view->OnGuestAttached(owner_web_contents_->GetView());
+ }
RendererPreferences* renderer_prefs =
GetWebContents()->GetMutableRendererPrefs();
@@ -220,7 +282,7 @@ void BrowserPluginGuest::Initialize(
// For GTK and Aura this is necessary to get proper renderer configuration
// values for caret blinking interval, colors related to selection and
// focus.
- *renderer_prefs = *embedder_web_contents_->GetMutableRendererPrefs();
+ *renderer_prefs = *owner_web_contents_->GetMutableRendererPrefs();
renderer_prefs->user_agent_override = guest_user_agent_override;
// We would like the guest to report changes to frame names so that we can
@@ -233,9 +295,14 @@ void BrowserPluginGuest::Initialize(
// Disable "client blocked" error page for browser plugin.
renderer_prefs->disable_client_blocked_error_page = true;
- embedder_web_contents_observer_.reset(new EmbedderWebContentsObserver(this));
+ embedder_visibility_observer_.reset(new EmbedderVisibilityObserver(this));
+
+ DCHECK(GetWebContents()->GetRenderViewHost());
- OnResizeGuest(browser_plugin_instance_id_, params.resize_guest_params);
+ // Initialize the device scale factor by calling |NotifyScreenInfoChanged|.
+ auto render_widget_host =
+ RenderWidgetHostImpl::From(GetWebContents()->GetRenderViewHost());
+ render_widget_host->NotifyScreenInfoChanged();
// TODO(chrishtr): this code is wrong. The navigate_on_drag_drop field will
// be reset again the next time preferences are updated.
@@ -243,18 +310,6 @@ void BrowserPluginGuest::Initialize(
GetWebContents()->GetRenderViewHost()->GetWebkitPreferences();
prefs.navigate_on_drag_drop = false;
GetWebContents()->GetRenderViewHost()->UpdateWebkitPreferences(prefs);
-
- // Enable input method for guest if it's enabled for the embedder.
- if (static_cast<RenderViewHostImpl*>(
- embedder_web_contents_->GetRenderViewHost())->input_method_active()) {
- RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
- GetWebContents()->GetRenderViewHost());
- guest_rvh->SetInputMethodActive(true);
- }
-
- // Inform the embedder of the guest's attachment.
- SendMessageToEmbedder(
- new BrowserPluginMsg_Attach_ACK(browser_plugin_instance_id_));
}
BrowserPluginGuest::~BrowserPluginGuest() {
@@ -265,7 +320,7 @@ BrowserPluginGuest* BrowserPluginGuest::Create(
WebContentsImpl* web_contents,
BrowserPluginGuestDelegate* delegate) {
return new BrowserPluginGuest(
- web_contents->opener() != NULL, web_contents, delegate);
+ web_contents->opener() != nullptr, web_contents, delegate);
}
// static
@@ -280,10 +335,10 @@ bool BrowserPluginGuest::IsGuest(RenderViewHostImpl* render_view_host) {
render_view_host)));
}
-RenderWidgetHostView* BrowserPluginGuest::GetEmbedderRenderWidgetHostView() {
- if (!attached())
- return NULL;
- return embedder_web_contents_->GetRenderWidgetHostView();
+RenderWidgetHostView* BrowserPluginGuest::GetOwnerRenderWidgetHostView() {
+ if (!owner_web_contents_)
+ return nullptr;
+ return owner_web_contents_->GetRenderWidgetHostView();
}
void BrowserPluginGuest::UpdateVisibility() {
@@ -317,18 +372,19 @@ void BrowserPluginGuest::SwapCompositorFrame(
1.0f / frame->metadata.device_scale_factor)));
if (last_seen_view_size_ != view_size) {
- delegate_->GuestSizeChanged(last_seen_view_size_, view_size);
+ delegate_->GuestSizeChanged(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;
+ last_pending_frame_.reset(new FrameMsg_CompositorFrameSwapped_Params());
+ frame->AssignTo(&last_pending_frame_->frame);
+ last_pending_frame_->output_surface_id = output_surface_id;
+ last_pending_frame_->producing_route_id = host_routing_id;
+ last_pending_frame_->producing_host_id = host_process_id;
+
SendMessageToEmbedder(
new BrowserPluginMsg_CompositorFrameSwapped(
- browser_plugin_instance_id(), guest_params));
+ browser_plugin_instance_id(), *last_pending_frame_));
}
void BrowserPluginGuest::SetContentsOpaque(bool opaque) {
@@ -340,8 +396,11 @@ void BrowserPluginGuest::SetContentsOpaque(bool 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_);
+ return delegate_->Find(request_id, search_text, options);
+}
+
+bool BrowserPluginGuest::StopFinding(StopFindAction action) {
+ return delegate_->StopFinding(action);
}
WebContentsImpl* BrowserPluginGuest::GetWebContents() const {
@@ -373,20 +432,52 @@ void BrowserPluginGuest::SendMessageToEmbedder(IPC::Message* msg) {
pending_messages_.push_back(linked_ptr<IPC::Message>(msg));
return;
}
- msg->set_routing_id(embedder_web_contents_->GetRoutingID());
- embedder_web_contents_->Send(msg);
+ owner_web_contents_->Send(msg);
}
void BrowserPluginGuest::DragSourceEndedAt(int client_x, int client_y,
int screen_x, int screen_y, blink::WebDragOperation operation) {
web_contents()->GetRenderViewHost()->DragSourceEndedAt(client_x, client_y,
screen_x, screen_y, operation);
+ seen_embedder_drag_source_ended_at_ = true;
+ EndSystemDragIfApplicable();
}
-void BrowserPluginGuest::EndSystemDrag() {
- RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
- GetWebContents()->GetRenderViewHost());
- guest_rvh->DragSourceSystemDragEnded();
+void BrowserPluginGuest::EndSystemDragIfApplicable() {
+ // Ideally we'd want either WebDragStatusDrop or WebDragStatusLeave...
+ // Call guest RVH->DragSourceSystemDragEnded() correctly on the guest where
+ // the drag was initiated. Calling DragSourceSystemDragEnded() correctly
+ // means we call it in all cases and also make sure we only call it once.
+ // This ensures that the input state of the guest stays correct, otherwise
+ // it will go stale and won't accept any further input events.
+ //
+ // The strategy used here to call DragSourceSystemDragEnded() on the RVH
+ // is when the following conditions are met:
+ // a. Embedder has seen SystemDragEnded()
+ // b. Embedder has seen DragSourceEndedAt()
+ // c. The guest has seen some drag status update other than
+ // WebDragStatusUnknown. Note that this step should ideally be done
+ // differently: The guest has seen at least one of
+ // {WebDragStatusOver, WebDragStatusDrop}. However, if a user drags
+ // a source quickly outside of <webview> bounds, then the
+ // BrowserPluginGuest never sees any of these drag status updates,
+ // there we just check whether we've seen any drag status update or
+ // not.
+ if (last_drag_status_ != blink::WebDragStatusOver &&
+ seen_embedder_drag_source_ended_at_ && seen_embedder_system_drag_ended_) {
+ RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
+ GetWebContents()->GetRenderViewHost());
+ guest_rvh->DragSourceSystemDragEnded();
+ last_drag_status_ = blink::WebDragStatusUnknown;
+ seen_embedder_system_drag_ended_ = false;
+ seen_embedder_drag_source_ended_at_ = false;
+ dragged_url_ = GURL();
+ }
+}
+
+void BrowserPluginGuest::EmbedderSystemDragEnded() {
+ seen_embedder_system_drag_ended_ = true;
+ EndSystemDragIfApplicable();
}
void BrowserPluginGuest::SendQueuedMessages() {
@@ -400,6 +491,35 @@ void BrowserPluginGuest::SendQueuedMessages() {
}
}
+void BrowserPluginGuest::SendTextInputTypeChangedToView(
+ RenderWidgetHostViewBase* guest_rwhv) {
+ if (!guest_rwhv)
+ return;
+
+ if (!owner_web_contents_) {
+ // If we were showing an interstitial, then we can end up here during
+ // embedder shutdown or when the embedder navigates to a different page.
+ // The call stack is roughly:
+ // BrowserPluginGuest::SetFocus()
+ // content::InterstitialPageImpl::Hide()
+ // content::InterstitialPageImpl::DontProceed().
+ //
+ // TODO(lazyboy): Write a WebUI test once http://crbug.com/463674 is fixed.
+ return;
+ }
+
+ guest_rwhv->TextInputTypeChanged(last_text_input_type_, last_input_mode_,
+ last_can_compose_inline_, last_input_flags_);
+ // Enable input method for guest if it's enabled for the embedder.
+ if (!static_cast<RenderViewHostImpl*>(
+ owner_web_contents_->GetRenderViewHost())->input_method_active()) {
+ return;
+ }
+ RenderViewHostImpl* guest_rvh =
+ static_cast<RenderViewHostImpl*>(GetWebContents()->GetRenderViewHost());
+ guest_rvh->SetInputMethodActive(true);
+}
+
void BrowserPluginGuest::DidCommitProvisionalLoadForFrame(
RenderFrameHost* render_frame_host,
const GURL& url,
@@ -414,7 +534,7 @@ void BrowserPluginGuest::RenderViewReady() {
Send(new InputMsg_SetFocus(routing_id(), focused_));
UpdateVisibility();
- RenderWidgetHostImpl::From(rvh)->set_hung_renderer_delay_ms(
+ RenderWidgetHostImpl::From(rvh)->set_hung_renderer_delay(
base::TimeDelta::FromMilliseconds(kHungRendererDelayMs));
}
@@ -440,26 +560,8 @@ void BrowserPluginGuest::RenderProcessGone(base::TerminationStatus status) {
// static
bool BrowserPluginGuest::ShouldForwardToBrowserPluginGuest(
const IPC::Message& message) {
- switch (message.type()) {
- case BrowserPluginHostMsg_CompositorFrameSwappedACK::ID:
- case BrowserPluginHostMsg_DragStatusUpdate::ID:
- case BrowserPluginHostMsg_ExecuteEditCommand::ID:
- case BrowserPluginHostMsg_ExtendSelectionAndDelete::ID:
- case BrowserPluginHostMsg_HandleInputEvent::ID:
- case BrowserPluginHostMsg_ImeConfirmComposition::ID:
- case BrowserPluginHostMsg_ImeSetComposition::ID:
- case BrowserPluginHostMsg_LockMouse_ACK::ID:
- case BrowserPluginHostMsg_ReclaimCompositorResources::ID:
- case BrowserPluginHostMsg_ResizeGuest::ID:
- case BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent::ID:
- case BrowserPluginHostMsg_SetFocus::ID:
- case BrowserPluginHostMsg_SetVisibility::ID:
- case BrowserPluginHostMsg_UnlockMouse_ACK::ID:
- case BrowserPluginHostMsg_UpdateGeometry::ID:
- return true;
- default:
- return false;
- }
+ return (message.type() != BrowserPluginHostMsg_Attach::ID) &&
+ (IPC_MESSAGE_CLASS(message) == BrowserPluginMsgStart);
}
bool BrowserPluginGuest::OnMessageReceived(const IPC::Message& message) {
@@ -514,8 +616,36 @@ void BrowserPluginGuest::Attach(
int browser_plugin_instance_id,
WebContentsImpl* embedder_web_contents,
const BrowserPluginHostMsg_Attach_Params& params) {
- delegate_->WillAttach(embedder_web_contents, browser_plugin_instance_id);
+ browser_plugin_instance_id_ = browser_plugin_instance_id;
+ // If a guest is detaching from one container and attaching to another
+ // container, then late arriving ACKs may be lost if the mapping from
+ // |browser_plugin_instance_id| to |guest_instance_id| changes. Thus we
+ // ensure that we always get new frames on attachment by ACKing the pending
+ // frame if it's still waiting on the ACK.
+ if (last_pending_frame_) {
+ cc::CompositorFrameAck ack;
+ RenderWidgetHostImpl::SendSwapCompositorFrameAck(
+ last_pending_frame_->producing_route_id,
+ last_pending_frame_->output_surface_id,
+ last_pending_frame_->producing_host_id,
+ ack);
+ last_pending_frame_.reset();
+ }
+ // The guest is owned by the embedder. Attach is queued up so we cannot
+ // change embedders before attach completes. If the embedder goes away,
+ // so does the guest and so we will never call WillAttachComplete because
+ // we have a weak ptr.
+ delegate_->WillAttach(embedder_web_contents, browser_plugin_instance_id,
+ params.is_full_page_plugin,
+ base::Bind(&BrowserPluginGuest::OnWillAttachComplete,
+ weak_ptr_factory_.GetWeakPtr(),
+ embedder_web_contents, params));
+}
+
+void BrowserPluginGuest::OnWillAttachComplete(
+ WebContentsImpl* embedder_web_contents,
+ const BrowserPluginHostMsg_Attach_Params& params) {
// 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.
@@ -531,25 +661,23 @@ void BrowserPluginGuest::Attach(
}
}
- Initialize(browser_plugin_instance_id, params, embedder_web_contents);
+ InitInternal(params, embedder_web_contents);
+ attached_ = true;
SendQueuedMessages();
- // 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_);
+ delegate_->DidAttach(GetGuestProxyRoutingID());
has_render_view_ = true;
+ // Enable input method for guest if it's enabled for the embedder.
+ if (static_cast<RenderViewHostImpl*>(
+ owner_web_contents_->GetRenderViewHost())->input_method_active()) {
+ RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
+ GetWebContents()->GetRenderViewHost());
+ guest_rvh->SetInputMethodActive(true);
+ }
+
RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Attached"));
}
@@ -560,6 +688,18 @@ void BrowserPluginGuest::OnCompositorFrameSwappedACK(
params.output_surface_id,
params.producing_host_id,
params.ack);
+ last_pending_frame_.reset();
+}
+
+void BrowserPluginGuest::OnDetach(int browser_plugin_instance_id) {
+ if (!attached())
+ return;
+
+ // This tells BrowserPluginGuest to queue up all IPCs to BrowserPlugin until
+ // it's attached again.
+ attached_ = false;
+
+ delegate_->DidDetach();
}
void BrowserPluginGuest::OnDragStatusUpdate(int browser_plugin_instance_id,
@@ -568,31 +708,44 @@ void BrowserPluginGuest::OnDragStatusUpdate(int browser_plugin_instance_id,
blink::WebDragOperationsMask mask,
const gfx::Point& location) {
RenderViewHost* host = GetWebContents()->GetRenderViewHost();
+ auto embedder = owner_web_contents_->GetBrowserPluginEmbedder();
switch (drag_status) {
case blink::WebDragStatusEnter:
- embedder_web_contents_->GetBrowserPluginEmbedder()->DragEnteredGuest(
- this);
+ // Only track the URL being dragged over the guest if the link isn't
+ // coming from the guest.
+ if (!embedder->DragEnteredGuest(this))
+ dragged_url_ = drop_data.url;
host->DragTargetDragEnter(drop_data, location, location, mask, 0);
break;
case blink::WebDragStatusOver:
host->DragTargetDragOver(location, location, mask, 0);
break;
case blink::WebDragStatusLeave:
- embedder_web_contents_->GetBrowserPluginEmbedder()->DragLeftGuest(this);
+ embedder->DragLeftGuest(this);
host->DragTargetDragLeave();
break;
case blink::WebDragStatusDrop:
host->DragTargetDrop(location, location, 0);
- EndSystemDrag();
+ if (dragged_url_.is_valid()) {
+ delegate_->DidDropLink(dragged_url_);
+ dragged_url_ = GURL();
+ }
break;
case blink::WebDragStatusUnknown:
NOTREACHED();
}
+ last_drag_status_ = drag_status;
+ EndSystemDragIfApplicable();
}
void BrowserPluginGuest::OnExecuteEditCommand(int browser_plugin_instance_id,
const std::string& name) {
- Send(new InputMsg_ExecuteEditCommand(routing_id(), name, std::string()));
+ RenderFrameHost* focused_frame = web_contents()->GetFocusedFrame();
+ if (!focused_frame)
+ return;
+
+ focused_frame->Send(new InputMsg_ExecuteNoValueEditCommand(
+ focused_frame->GetRoutingID(), name));
}
void BrowserPluginGuest::OnImeSetComposition(
@@ -662,37 +815,12 @@ void BrowserPluginGuest::OnLockMouseAck(int browser_plugin_instance_id,
mouse_locked_ = true;
}
-void BrowserPluginGuest::OnResizeGuest(
- int browser_plugin_instance_id,
- const BrowserPluginHostMsg_ResizeGuest_Params& params) {
- // If we are setting the size for the first time before navigating then
- // BrowserPluginGuest does not yet have a RenderViewHost.
- if (guest_device_scale_factor_ != params.scale_factor &&
- GetWebContents()->GetRenderViewHost()) {
- RenderWidgetHostImpl* render_widget_host =
- RenderWidgetHostImpl::From(GetWebContents()->GetRenderViewHost());
- guest_device_scale_factor_ = params.scale_factor;
- render_widget_host->NotifyScreenInfoChanged();
- }
-
- 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.
- 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 browser_plugin_instance_id,
- bool focused) {
+ bool focused,
+ blink::WebFocusType focus_type) {
RenderWidgetHostView* rwhv = web_contents()->GetRenderWidgetHostView();
- RenderWidgetHost* rwh = rwhv ? rwhv->GetRenderWidgetHost() : NULL;
- SetFocus(rwh, focused);
+ RenderWidgetHost* rwh = rwhv ? rwhv->GetRenderWidgetHost() : nullptr;
+ SetFocus(rwh, focused, focus_type);
}
void BrowserPluginGuest::OnSetEditCommandsForNextKeyEvent(
@@ -749,7 +877,7 @@ void BrowserPluginGuest::OnShowPopup(
gfx::Rect translated_bounds(params.bounds);
translated_bounds.Offset(guest_window_rect_.OffsetFromOrigin());
BrowserPluginPopupMenuHelper popup_menu_helper(
- embedder_web_contents_->GetRenderViewHost(), render_frame_host);
+ owner_web_contents_->GetRenderViewHost(), render_frame_host);
popup_menu_helper.ShowPopupMenu(translated_bounds,
params.item_height,
params.item_font_size,
@@ -761,8 +889,8 @@ void BrowserPluginGuest::OnShowPopup(
#endif
void BrowserPluginGuest::OnShowWidget(int route_id,
- const gfx::Rect& initial_pos) {
- GetWebContents()->ShowCreatedWidget(route_id, initial_pos);
+ const gfx::Rect& initial_rect) {
+ GetWebContents()->ShowCreatedWidget(route_id, initial_rect);
}
void BrowserPluginGuest::OnTakeFocus(bool reverse) {
@@ -780,9 +908,9 @@ void BrowserPluginGuest::OnTextInputTypeChanged(ui::TextInputType type,
last_input_flags_ = flags;
last_can_compose_inline_ = can_compose_inline;
- static_cast<RenderWidgetHostViewBase*>(
- web_contents()->GetRenderWidgetHostView())->TextInputTypeChanged(
- type, input_mode, can_compose_inline, flags);
+ SendTextInputTypeChangedToView(
+ static_cast<RenderWidgetHostViewBase*>(
+ web_contents()->GetRenderWidgetHostView()));
}
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 cb1ba7eef8e..86278b98694 100644
--- a/chromium/content/browser/browser_plugin/browser_plugin_guest.h
+++ b/chromium/content/browser/browser_plugin/browser_plugin_guest.h
@@ -28,28 +28,27 @@
#include "content/common/edit_command.h"
#include "content/common/input/input_event_ack_state.h"
#include "content/public/browser/browser_plugin_guest_delegate.h"
+#include "content/public/browser/guest_host.h"
+#include "content/public/browser/readback_types.h"
#include "content/public/browser/web_contents_observer.h"
+#include "third_party/WebKit/public/platform/WebFocusType.h"
#include "third_party/WebKit/public/web/WebCompositionUnderline.h"
#include "third_party/WebKit/public/web/WebDragOperation.h"
#include "third_party/WebKit/public/web/WebDragStatus.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
#include "ui/base/ime/text_input_mode.h"
#include "ui/base/ime/text_input_type.h"
-#include "ui/gfx/rect.h"
+#include "ui/gfx/geometry/rect.h"
-class SkBitmap;
struct BrowserPluginHostMsg_Attach_Params;
-struct BrowserPluginHostMsg_ResizeGuest_Params;
struct FrameHostMsg_CompositorFrameSwappedACK_Params;
struct FrameHostMsg_ReclaimCompositorResources_Params;
+struct FrameMsg_CompositorFrameSwapped_Params;
+
#if defined(OS_MACOSX)
struct FrameHostMsg_ShowPopup_Params;
#endif
-namespace blink {
-class WebInputEvent;
-} // namespace blink
-
namespace cc {
class CompositorFrame;
} // namespace cc
@@ -64,6 +63,7 @@ class BrowserPluginGuestManager;
class RenderViewHostImpl;
class RenderWidgetHost;
class RenderWidgetHostView;
+class RenderWidgetHostViewBase;
class SiteInstance;
struct DropData;
@@ -77,7 +77,8 @@ struct DropData;
// A BrowserPluginGuest can also create a new unattached guest via
// CreateNewWindow. The newly created guest will live in the same partition,
// which means it can share storage and can script this guest.
-class CONTENT_EXPORT BrowserPluginGuest : public WebContentsObserver {
+class CONTENT_EXPORT BrowserPluginGuest : public GuestHost,
+ public WebContentsObserver {
public:
~BrowserPluginGuest() override;
@@ -97,11 +98,21 @@ class CONTENT_EXPORT BrowserPluginGuest : public WebContentsObserver {
// Returns whether the given RenderviewHost is a BrowserPlugin guest.
static bool IsGuest(RenderViewHostImpl* render_view_host);
+ // BrowserPluginGuest::Init is called after the associated guest WebContents
+ // initializes. If this guest cannot navigate without being attached to a
+ // container, then this call is a no-op. For guest types that can be
+ // navigated, this call adds the associated RenderWdigetHostViewGuest to the
+ // view hierachy and sets up the appropriate RendererPreferences so that this
+ // guest can navigate and resize offscreen.
+ void Init();
+
// Returns a WeakPtr to this BrowserPluginGuest.
base::WeakPtr<BrowserPluginGuest> AsWeakPtr();
// Sets the focus state of the current RenderWidgetHostView.
- void SetFocus(RenderWidgetHost* rwh, bool focused);
+ void SetFocus(RenderWidgetHost* rwh,
+ bool focused,
+ blink::WebFocusType focus_type);
// Sets the tooltip text.
void SetTooltipText(const base::string16& tooltip_text);
@@ -121,6 +132,10 @@ class CONTENT_EXPORT BrowserPluginGuest : public WebContentsObserver {
WebContentsImpl* CreateNewGuestWindow(
const WebContents::CreateParams& params);
+ // Creates, if necessary, and returns the routing ID of a proxy for the guest
+ // in the owner's renderer process.
+ int GetGuestProxyRoutingID();
+
// Returns the identifier that uniquely identifies a browser plugin guest
// within an embedder.
int browser_plugin_instance_id() const { return browser_plugin_instance_id_; }
@@ -128,12 +143,12 @@ class CONTENT_EXPORT BrowserPluginGuest : public WebContentsObserver {
bool OnMessageReceivedFromEmbedder(const IPC::Message& message);
WebContentsImpl* embedder_web_contents() const {
- return embedder_web_contents_;
+ return attached_ ? owner_web_contents_ : nullptr;
}
// Returns the embedder's RenderWidgetHostView if it is available.
- // Returns NULL otherwise.
- RenderWidgetHostView* GetEmbedderRenderWidgetHostView();
+ // Returns nullptr otherwise.
+ RenderWidgetHostView* GetOwnerRenderWidgetHostView();
bool focused() const { return focused_; }
bool visible() const { return guest_visible_; }
@@ -155,17 +170,23 @@ class CONTENT_EXPORT BrowserPluginGuest : public WebContentsObserver {
bool OnMessageReceived(const IPC::Message& message,
RenderFrameHost* render_frame_host) override;
+ // GuestHost implementation.
+ int LoadURLWithParams(
+ const NavigationController::LoadURLParams& load_params) override;
+ void SizeContents(const gfx::Size& new_size) override;
+ void WillDestroy() override;
+
// Exposes the protected web_contents() from WebContentsObserver.
WebContentsImpl* GetWebContents() const;
gfx::Point GetScreenCoordinates(const gfx::Point& relative_position) const;
- // Helper to send messages to embedder. This methods fills the message with
- // the correct routing id.
+ // Helper to send messages to embedder. If this guest is not yet attached,
+ // then IPCs will be queued until attachment.
void SendMessageToEmbedder(IPC::Message* msg);
// Returns whether the guest is attached to an embedder.
- bool attached() const { return embedder_web_contents_ != NULL; }
+ bool attached() const { return attached_; }
// Attaches this BrowserPluginGuest to the provided |embedder_web_contents|
// and initializes the guest with the provided |params|. Attaching a guest
@@ -183,7 +204,8 @@ class CONTENT_EXPORT BrowserPluginGuest : public WebContentsObserver {
int screen_y, blink::WebDragOperation operation);
// Called when the drag started by this guest ends at an OS-level.
- void EndSystemDrag();
+ void EmbedderSystemDragEnded();
+ void EndSystemDragIfApplicable();
void RespondToPermissionRequest(int request_id,
bool should_allow,
@@ -203,9 +225,10 @@ class CONTENT_EXPORT BrowserPluginGuest : public WebContentsObserver {
bool Find(int request_id,
const base::string16& search_text,
const blink::WebFindOptions& options);
+ bool StopFinding(StopFindAction action);
private:
- class EmbedderWebContentsObserver;
+ class EmbedderVisibilityObserver;
// BrowserPluginGuest is a WebContentsObserver of |web_contents| and
// |web_contents| has to stay valid for the lifetime of BrowserPluginGuest.
@@ -213,11 +236,8 @@ class CONTENT_EXPORT BrowserPluginGuest : public WebContentsObserver {
WebContentsImpl* web_contents,
BrowserPluginGuestDelegate* delegate);
- void WillDestroy();
-
- void Initialize(int browser_plugin_instance_id,
- const BrowserPluginHostMsg_Attach_Params& params,
- WebContentsImpl* embedder_web_contents);
+ void InitInternal(const BrowserPluginHostMsg_Attach_Params& params,
+ WebContentsImpl* owner_web_contents);
bool InAutoSizeBounds(const gfx::Size& size) const;
@@ -225,7 +245,7 @@ class CONTENT_EXPORT BrowserPluginGuest : public WebContentsObserver {
void OnCompositorFrameSwappedACK(
int instance_id,
const FrameHostMsg_CompositorFrameSwappedACK_Params& params);
-
+ void OnDetach(int instance_id);
// Handles drag events from the embedder.
// When dragging, the drag events go to the embedder first, and if the drag
// happens on the browser plugin, then the plugin sends a corresponding
@@ -250,9 +270,9 @@ class CONTENT_EXPORT BrowserPluginGuest : public WebContentsObserver {
bool privileged);
void OnLockMouseAck(int instance_id, bool succeeded);
// Resizes the guest's web contents.
- void OnResizeGuest(
- int instance_id, const BrowserPluginHostMsg_ResizeGuest_Params& params);
- void OnSetFocus(int instance_id, bool focused);
+ void OnSetFocus(int instance_id,
+ bool focused,
+ blink::WebFocusType focus_type);
// Sets the name of the guest so that other guests in the same partition can
// access it.
void OnSetName(int instance_id, const std::string& name);
@@ -313,24 +333,32 @@ class CONTENT_EXPORT BrowserPluginGuest : public WebContentsObserver {
void OnShowPopup(RenderFrameHost* render_frame_host,
const FrameHostMsg_ShowPopup_Params& params);
#endif
- void OnShowWidget(int route_id, const gfx::Rect& initial_pos);
+ void OnShowWidget(int route_id, const gfx::Rect& initial_rect);
void OnTakeFocus(bool reverse);
void OnUpdateFrameName(int frame_id,
bool is_top_level,
const std::string& name);
+ // Called when WillAttach is complete.
+ void OnWillAttachComplete(WebContentsImpl* embedder_web_contents,
+ const BrowserPluginHostMsg_Attach_Params& params);
+
// Forwards all messages from the |pending_messages_| queue to the embedder.
void SendQueuedMessages();
+ void SendTextInputTypeChangedToView(RenderWidgetHostViewBase* guest_rwhv);
+
// The last tooltip that was set with SetTooltipText().
base::string16 current_tooltip_text_;
- scoped_ptr<EmbedderWebContentsObserver> embedder_web_contents_observer_;
- WebContentsImpl* embedder_web_contents_;
+ scoped_ptr<EmbedderVisibilityObserver> embedder_visibility_observer_;
+ WebContentsImpl* owner_web_contents_;
+
+ // Indicates whether this guest has been attached to a container.
+ bool attached_;
// 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_;
bool focused_;
bool mouse_locked_;
@@ -349,11 +377,13 @@ class CONTENT_EXPORT BrowserPluginGuest : public WebContentsObserver {
// Last seen size of guest contents (by SwapCompositorFrame).
gfx::Size last_seen_view_size_;
- // Last seen size of BrowserPlugin (by OnResizeGuest).
- gfx::Size last_seen_browser_plugin_size_;
bool is_in_destruction_;
+ // BrowserPluginGuest::Init can only be called once. This flag allows it to
+ // exit early if it's already been called.
+ bool initialized_;
+
// Text input type states.
ui::TextInputType last_text_input_type_;
ui::TextInputMode last_input_mode_;
@@ -363,6 +393,24 @@ class CONTENT_EXPORT BrowserPluginGuest : public WebContentsObserver {
// The is the routing ID for a swapped out RenderView for the guest
// WebContents in the embedder's process.
int guest_proxy_routing_id_;
+ // Last seen state of drag status update.
+ blink::WebDragStatus last_drag_status_;
+ // Whether or not our embedder has seen a SystemDragEnded() call.
+ bool seen_embedder_system_drag_ended_;
+ // Whether or not our embedder has seen a DragSourceEndedAt() call.
+ bool seen_embedder_drag_source_ended_at_;
+
+ // Indicates the URL dragged into the guest if any.
+ GURL dragged_url_;
+
+ // Guests generate frames and send a CompositorFrameSwapped (CFS) message
+ // indicating the next frame is ready to be positioned and composited.
+ // Subsequent frames are not generated until the IPC is ACKed. We would like
+ // to ensure that the guest generates frames on attachment so we directly ACK
+ // an unACKed CFS. ACKs could get lost between the time a guest is detached
+ // from a container and the time it is attached elsewhere. This mitigates this
+ // race by ensuring the guest is ACKed on attachment.
+ scoped_ptr<FrameMsg_CompositorFrameSwapped_Params> last_pending_frame_;
// This is a queue of messages that are destined to be sent to the embedder
// once the guest is attached to a particular embedder.
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 c39476d2fbc..c04114dc7be 100644
--- a/chromium/content/browser/browser_plugin/browser_plugin_message_filter.cc
+++ b/chromium/content/browser/browser_plugin/browser_plugin_message_filter.cc
@@ -24,7 +24,7 @@ BrowserPluginMessageFilter::BrowserPluginMessageFilter(int render_process_id)
}
BrowserPluginMessageFilter::~BrowserPluginMessageFilter() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
}
bool BrowserPluginMessageFilter::OnMessageReceived(
@@ -33,8 +33,8 @@ bool BrowserPluginMessageFilter::OnMessageReceived(
// a BrowserPluginGuestManager.
if (BrowserPluginGuest::ShouldForwardToBrowserPluginGuest(message)) {
ForwardMessageToGuest(message);
- // We always swallow messages destined for BrowserPluginGuestManager because
- // we're on the UI thread and fallback code is expected to be run on the IO
+ // We always swallow messages destined for BrowserPluginGuest because we're
+ // on the UI thread and fallback code is expected to be run on the IO
// thread.
return true;
}
@@ -53,24 +53,28 @@ void BrowserPluginMessageFilter::OverrideThreadForMessage(
void BrowserPluginMessageFilter::ForwardMessageToGuest(
const IPC::Message& message) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- RenderViewHost* rvh = RenderViewHost::FromID(render_process_id_,
- message.routing_id());
- if (!rvh)
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ auto rph = RenderProcessHost::FromID(render_process_id_);
+ if (!rph)
return;
- WebContents* embedder_web_contents = WebContents::FromRenderViewHost(rvh);
-
- int browser_plugin_instance_id = 0;
+ int browser_plugin_instance_id = browser_plugin::kInstanceIDNone;
// All allowed messages must have instance_id as their first parameter.
PickleIterator iter(message);
bool success = iter.ReadInt(&browser_plugin_instance_id);
DCHECK(success);
+
+ // BrowserPlugin cannot create guests, it only serves as a container for
+ // guests. Thus, we should not be getting BrowserPlugin messages without
+ // an already created GuestManager.
+ BrowserPluginGuestManager* manager =
+ rph->GetBrowserContext()->GetGuestManager();
+ if (!manager)
+ return;
+
WebContents* guest_web_contents =
- embedder_web_contents->GetBrowserContext()
- ->GetGuestManager()
- ->GetGuestByInstanceID(embedder_web_contents,
- browser_plugin_instance_id);
+ manager->GetGuestByInstanceID(render_process_id_,
+ browser_plugin_instance_id);
if (!guest_web_contents)
return;
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 672f6de51b6..9c89f8170d8 100644
--- a/chromium/content/browser/browser_plugin/browser_plugin_message_filter.h
+++ b/chromium/content/browser/browser_plugin/browser_plugin_message_filter.h
@@ -7,17 +7,13 @@
#include "content/public/browser/browser_message_filter.h"
-struct FrameHostMsg_BuffersSwappedACK_Params;
-
namespace content {
-class BrowserContext;
-
// This class filters out incoming IPC messages for the guest renderer process
// on the IPC thread before other message filters handle them.
class BrowserPluginMessageFilter : public BrowserMessageFilter {
public:
- BrowserPluginMessageFilter(int render_process_id);
+ explicit BrowserPluginMessageFilter(int render_process_id);
// BrowserMessageFilter implementation.
void OverrideThreadForMessage(const IPC::Message& message,
@@ -33,7 +29,7 @@ class BrowserPluginMessageFilter : public BrowserMessageFilter {
void ForwardMessageToGuest(const IPC::Message& message);
- int render_process_id_;
+ const int render_process_id_;
DISALLOW_COPY_AND_ASSIGN(BrowserPluginMessageFilter);
};
diff --git a/chromium/content/browser/browser_process_sub_thread.cc b/chromium/content/browser/browser_process_sub_thread.cc
index 9a5b78a9edb..b1904e10971 100644
--- a/chromium/content/browser/browser_process_sub_thread.cc
+++ b/chromium/content/browser/browser_process_sub_thread.cc
@@ -6,8 +6,10 @@
#include "base/debug/leak_tracker.h"
#include "base/threading/thread_restrictions.h"
+#include "base/trace_event/memory_dump_manager.h"
#include "build/build_config.h"
#include "content/browser/browser_child_process_host_impl.h"
+#include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
#include "content/browser/notification_service_impl.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_request.h"
@@ -70,6 +72,10 @@ void BrowserProcessSubThread::IOThreadPreCleanUp() {
// IO thread only resources they are referencing.
BrowserChildProcessHostImpl::TerminateAll();
#endif // !defined(OS_IOS)
+
+ // Unregister GpuMemoryBuffer dump provider before IO thread is shut down.
+ base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
+ BrowserGpuMemoryBufferManager::current());
}
} // namespace content
diff --git a/chromium/content/browser/browser_shutdown_profile_dumper.cc b/chromium/content/browser/browser_shutdown_profile_dumper.cc
index c2533a09604..6c4d8c8c14a 100644
--- a/chromium/content/browser/browser_shutdown_profile_dumper.cc
+++ b/chromium/content/browser/browser_shutdown_profile_dumper.cc
@@ -6,14 +6,14 @@
#include "base/base_switches.h"
#include "base/command_line.h"
-#include "base/debug/trace_event.h"
-#include "base/debug/trace_event_impl.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"
#include "base/threading/thread_restrictions.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_impl.h"
#include "content/public/common/content_switches.h"
namespace content {
@@ -29,14 +29,20 @@ BrowserShutdownProfileDumper::~BrowserShutdownProfileDumper() {
WriteTracesToDisc();
}
+static float GetTraceBufferPercentFull() {
+ base::trace_event::TraceLogStatus status =
+ base::trace_event::TraceLog::GetInstance()->GetStatus();
+ return 100 * static_cast<float>(static_cast<double>(status.event_count) /
+ status.event_capacity);
+}
+
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
// that caused the problem.
- DVLOG(1) << "Flushing shutdown traces to disc. The buffer is %" <<
- base::debug::TraceLog::GetInstance()->GetBufferPercentFull() <<
- " full.";
+ DVLOG(1) << "Flushing shutdown traces to disc. The buffer is "
+ << GetTraceBufferPercentFull() << "% full.";
DCHECK(!dump_file_);
dump_file_ = base::OpenFile(dump_file_name_, "w+");
if (!IsFileValid()) {
@@ -66,8 +72,8 @@ void BrowserShutdownProfileDumper::WriteTracesToDisc() {
void BrowserShutdownProfileDumper::EndTraceAndFlush(
base::WaitableEvent* flush_complete_event) {
- base::debug::TraceLog::GetInstance()->SetDisabled();
- base::debug::TraceLog::GetInstance()->Flush(
+ base::trace_event::TraceLog::GetInstance()->SetDisabled();
+ base::trace_event::TraceLog::GetInstance()->Flush(
base::Bind(&BrowserShutdownProfileDumper::WriteTraceDataCollected,
base::Unretained(this),
base::Unretained(flush_complete_event)));
diff --git a/chromium/content/browser/browser_side_navigation_browsertest.cc b/chromium/content/browser/browser_side_navigation_browsertest.cc
new file mode 100644
index 00000000000..61c002b90a0
--- /dev/null
+++ b/chromium/content/browser/browser_side_navigation_browsertest.cc
@@ -0,0 +1,188 @@
+// Copyright 2014 The Chromium Authors. 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 "base/command_line.h"
+#include "base/strings/stringprintf.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/public/test/content_browser_test_utils.h"
+#include "content/public/test/test_navigation_observer.h"
+#include "content/shell/browser/shell.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/url_request/url_request_failed_job.h"
+#include "url/gurl.h"
+
+namespace content {
+
+class BrowserSideNavigationBrowserTest : public ContentBrowserTest {
+ public:
+ BrowserSideNavigationBrowserTest() {}
+
+ protected:
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ command_line->AppendSwitch(switches::kEnableBrowserSideNavigation);
+ }
+
+ void SetUpOnMainThread() override {
+ host_resolver()->AddRule("*", "127.0.0.1");
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+ }
+};
+
+// Ensure that browser initiated basic navigations work with browser side
+// navigation.
+IN_PROC_BROWSER_TEST_F(BrowserSideNavigationBrowserTest,
+ BrowserInitiatedNavigations) {
+ // Perform a navigation with no live renderer.
+ {
+ TestNavigationObserver observer(shell()->web_contents());
+ GURL url(embedded_test_server()->GetURL("/title1.html"));
+ NavigateToURL(shell(), url);
+ EXPECT_EQ(url, observer.last_navigation_url());
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ }
+
+ RenderFrameHost* initial_rfh =
+ static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()->root()->current_frame_host();
+
+ // Perform a same site navigation.
+ {
+ TestNavigationObserver observer(shell()->web_contents());
+ GURL url(embedded_test_server()->GetURL("/title2.html"));
+ NavigateToURL(shell(), url);
+ EXPECT_EQ(url, observer.last_navigation_url());
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ }
+
+ // The RenderFrameHost should not have changed.
+ EXPECT_EQ(initial_rfh, static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()->root()->current_frame_host());
+
+ // Perform a cross-site navigation.
+ {
+ TestNavigationObserver observer(shell()->web_contents());
+ GURL url = embedded_test_server()->GetURL("foo.com", "/title3.html");
+ NavigateToURL(shell(), url);
+ EXPECT_EQ(url, observer.last_navigation_url());
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ }
+
+ // The RenderFrameHost should have changed.
+ EXPECT_NE(initial_rfh, static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()->root()->current_frame_host());
+}
+
+// Ensure that renderer initiated same-site navigations work with browser side
+// navigation.
+IN_PROC_BROWSER_TEST_F(BrowserSideNavigationBrowserTest,
+ RendererInitiatedSameSiteNavigation) {
+ // Perform a navigation with no live renderer.
+ {
+ TestNavigationObserver observer(shell()->web_contents());
+ GURL url(embedded_test_server()->GetURL("/simple_links.html"));
+ NavigateToURL(shell(), url);
+ EXPECT_EQ(url, observer.last_navigation_url());
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ }
+
+ RenderFrameHost* initial_rfh =
+ static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()->root()->current_frame_host();
+
+ // Simulate clicking on a same-site link.
+ {
+ TestNavigationObserver observer(shell()->web_contents());
+ GURL url(embedded_test_server()->GetURL("/title2.html"));
+ bool success = false;
+ EXPECT_TRUE(ExecuteScriptAndExtractBool(
+ shell()->web_contents(),
+ "window.domAutomationController.send(clickSameSiteLink());", &success));
+ EXPECT_TRUE(success);
+ EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+ EXPECT_EQ(url, observer.last_navigation_url());
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ }
+
+ // The RenderFrameHost should not have changed.
+ EXPECT_EQ(initial_rfh, static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()->root()->current_frame_host());
+}
+
+// Ensure that renderer initiated cross-site navigations work with browser side
+// navigation.
+IN_PROC_BROWSER_TEST_F(BrowserSideNavigationBrowserTest,
+ RendererInitiatedCrossSiteNavigation) {
+ // Perform a navigation with no live renderer.
+ {
+ TestNavigationObserver observer(shell()->web_contents());
+ GURL url(embedded_test_server()->GetURL("/simple_links.html"));
+ NavigateToURL(shell(), url);
+ EXPECT_EQ(url, observer.last_navigation_url());
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ }
+
+ RenderFrameHost* initial_rfh =
+ static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()->root()->current_frame_host();
+
+ // Simulate clicking on a cross-site link.
+ {
+ TestNavigationObserver observer(shell()->web_contents());
+ const char kReplacePortNumber[] =
+ "window.domAutomationController.send(setPortNumber(%d));";
+ uint16 port_number = embedded_test_server()->port();
+ GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
+ bool success = false;
+ EXPECT_TRUE(ExecuteScriptAndExtractBool(
+ shell()->web_contents(),
+ base::StringPrintf(kReplacePortNumber, port_number),
+ &success));
+ success = false;
+ EXPECT_TRUE(ExecuteScriptAndExtractBool(
+ shell()->web_contents(),
+ "window.domAutomationController.send(clickCrossSiteLink());",
+ &success));
+ EXPECT_TRUE(success);
+ EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+ EXPECT_EQ(url, observer.last_navigation_url());
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ }
+
+ // The RenderFrameHost should not have changed.
+ EXPECT_EQ(initial_rfh, static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()->root()->current_frame_host());
+}
+
+// Ensure that browser side navigation handles navigation failures.
+IN_PROC_BROWSER_TEST_F(BrowserSideNavigationBrowserTest, FailedNavigation) {
+ // Perform a navigation with no live renderer.
+ {
+ TestNavigationObserver observer(shell()->web_contents());
+ GURL url(embedded_test_server()->GetURL("/title1.html"));
+ NavigateToURL(shell(), url);
+ EXPECT_EQ(url, observer.last_navigation_url());
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ }
+
+ // Now navigate to an unreachable url.
+ {
+ TestNavigationObserver observer(shell()->web_contents());
+ GURL error_url(
+ net::URLRequestFailedJob::GetMockHttpUrl(net::ERR_CONNECTION_RESET));
+ net::URLRequestFailedJob::AddUrlHandler();
+ NavigateToURL(shell(), error_url);
+ EXPECT_EQ(error_url, observer.last_navigation_url());
+ NavigationEntry* entry =
+ shell()->web_contents()->GetController().GetLastCommittedEntry();
+ EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
+ }
+}
+
+} // namespace content
diff --git a/chromium/content/browser/browser_thread_impl.cc b/chromium/content/browser/browser_thread_impl.cc
index 33bfeb951e5..78e3836dade 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 "content/public/browser/content_browser_client.h"
#include "net/disk_cache/simple/simple_backend_impl.h"
#if defined(OS_ANDROID)
@@ -365,6 +366,15 @@ bool BrowserThread::PostBlockingPoolSequencedTask(
}
// static
+void BrowserThread::PostAfterStartupTask(
+ const tracked_objects::Location& from_here,
+ const scoped_refptr<base::TaskRunner>& task_runner,
+ const base::Closure& task) {
+ GetContentClient()->browser()->PostAfterStartupTask(from_here, task_runner,
+ task);
+}
+
+// static
base::SequencedWorkerPool* BrowserThread::GetBlockingPool() {
return g_globals.Get().blocking_pool.get();
}
@@ -405,12 +415,11 @@ static const char* GetThreadName(BrowserThread::ID thread) {
// static
std::string BrowserThread::GetDCheckCurrentlyOnErrorMessage(ID expected) {
- const std::string& message_loop_name =
- base::MessageLoop::current()->thread_name();
+ const base::MessageLoop* message_loop = base::MessageLoop::current();
ID actual_browser_thread;
const char* actual_name = "Unknown Thread";
- if (!message_loop_name.empty()) {
- actual_name = message_loop_name.c_str();
+ if (message_loop && !message_loop->thread_name().empty()) {
+ actual_name = message_loop->thread_name().c_str();
} else if (GetCurrentThreadIdentifier(&actual_browser_thread)) {
actual_name = GetThreadName(actual_browser_thread);
}
diff --git a/chromium/content/browser/browser_url_handler_impl.cc b/chromium/content/browser/browser_url_handler_impl.cc
index 7ea7ff787b9..63ddf4924b8 100644
--- a/chromium/content/browser/browser_url_handler_impl.cc
+++ b/chromium/content/browser/browser_url_handler_impl.cc
@@ -88,7 +88,8 @@ BrowserURLHandlerImpl* BrowserURLHandlerImpl::GetInstance() {
return Singleton<BrowserURLHandlerImpl>::get();
}
-BrowserURLHandlerImpl::BrowserURLHandlerImpl() {
+BrowserURLHandlerImpl::BrowserURLHandlerImpl() :
+ fixup_handler_(nullptr) {
AddHandlerPair(&DebugURLHandler, BrowserURLHandlerImpl::null_handler());
GetContentClient()->browser()->BrowserURLHandlerCreated(this);
@@ -100,6 +101,11 @@ BrowserURLHandlerImpl::BrowserURLHandlerImpl() {
BrowserURLHandlerImpl::~BrowserURLHandlerImpl() {
}
+void BrowserURLHandlerImpl::SetFixupHandler(URLHandler handler) {
+ DCHECK(fixup_handler_ == nullptr);
+ fixup_handler_ = handler;
+}
+
void BrowserURLHandlerImpl::AddHandlerPair(URLHandler handler,
URLHandler reverse_handler) {
url_handlers_.push_back(HandlerPair(handler, reverse_handler));
@@ -118,6 +124,13 @@ void BrowserURLHandlerImpl::RewriteURLIfNecessary(
}
}
+void BrowserURLHandlerImpl::FixupURLBeforeRewrite(
+ GURL* url,
+ BrowserContext* browser_context) {
+ if (fixup_handler_)
+ fixup_handler_(url, browser_context);
+}
+
bool BrowserURLHandlerImpl::ReverseURLRewrite(
GURL* url, const GURL& original, BrowserContext* browser_context) {
for (size_t i = 0; i < url_handlers_.size(); ++i) {
diff --git a/chromium/content/browser/browser_url_handler_impl.h b/chromium/content/browser/browser_url_handler_impl.h
index 240554b7681..4084418abc2 100644
--- a/chromium/content/browser/browser_url_handler_impl.h
+++ b/chromium/content/browser/browser_url_handler_impl.h
@@ -26,9 +26,13 @@ class CONTENT_EXPORT BrowserURLHandlerImpl : public BrowserURLHandler {
void RewriteURLIfNecessary(GURL* url,
BrowserContext* browser_context,
bool* reverse_on_redirect) override;
+ void SetFixupHandler(URLHandler handler) override;
// Add the specified handler pair to the list of URL handlers.
void AddHandlerPair(URLHandler handler, URLHandler reverse_handler) override;
+ // Fixes up the URL before rewriting occurs.
+ void FixupURLBeforeRewrite(GURL* url, BrowserContext* browser_context);
+
// Reverses the rewriting that was done for |original| using the new |url|.
bool ReverseURLRewrite(GURL* url, const GURL& original,
BrowserContext* browser_context);
@@ -39,6 +43,9 @@ class CONTENT_EXPORT BrowserURLHandlerImpl : public BrowserURLHandler {
~BrowserURLHandlerImpl() override;
friend struct DefaultSingletonTraits<BrowserURLHandlerImpl>;
+ // A URLHandler to run in a preliminary phase, before rewriting is done.
+ URLHandler fixup_handler_;
+
// The list of known URLHandlers, optionally with reverse-rewriters.
typedef std::pair<URLHandler, URLHandler> HandlerPair;
std::vector<HandlerPair> url_handlers_;
diff --git a/chromium/content/browser/cache_storage/BUILD.gn b/chromium/content/browser/cache_storage/BUILD.gn
new file mode 100644
index 00000000000..7b33ea105f1
--- /dev/null
+++ b/chromium/content/browser/cache_storage/BUILD.gn
@@ -0,0 +1,11 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/protobuf/proto_library.gni")
+
+proto_library("cache_storage_proto") {
+ sources = [
+ "cache_storage.proto",
+ ]
+}
diff --git a/chromium/content/browser/cache_storage/OWNERS b/chromium/content/browser/cache_storage/OWNERS
new file mode 100644
index 00000000000..2db987d718b
--- /dev/null
+++ b/chromium/content/browser/cache_storage/OWNERS
@@ -0,0 +1,4 @@
+michaeln@chromium.org
+nhiroki@chromium.org
+jkarlin@chromium.org
+jsbell@chromium.org
diff --git a/chromium/content/browser/cache_storage/PRESUBMIT.py b/chromium/content/browser/cache_storage/PRESUBMIT.py
new file mode 100644
index 00000000000..fdfe05452a7
--- /dev/null
+++ b/chromium/content/browser/cache_storage/PRESUBMIT.py
@@ -0,0 +1,14 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Presubmit script for cache_storage.
+
+See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
+for more details about the presubmit API built into depot_tools.
+"""
+
+def CheckChangeOnUpload(input_api, output_api):
+ results = []
+ results += input_api.canned_checks.CheckPatchFormatted(input_api, output_api)
+ return results
diff --git a/chromium/content/browser/cache_storage/cache_storage.cc b/chromium/content/browser/cache_storage/cache_storage.cc
new file mode 100644
index 00000000000..a6a32b9893d
--- /dev/null
+++ b/chromium/content/browser/cache_storage/cache_storage.cc
@@ -0,0 +1,860 @@
+// Copyright 2014 The Chromium Authors. 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/cache_storage/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/metrics/histogram_macros.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/cache_storage/cache_storage.pb.h"
+#include "content/browser/cache_storage/cache_storage_cache.h"
+#include "content/browser/cache_storage/cache_storage_scheduler.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<CacheStorageCache>& cache,
+ const base::Closure& barrier_closure) {
+ barrier_closure.Run();
+}
+
+} // namespace
+
+const char CacheStorage::kIndexFileName[] = "index.txt";
+
+// Handles the loading and clean up of CacheStorageCache objects. The
+// callback of every public method is guaranteed to be called.
+class CacheStorage::CacheLoader {
+ public:
+ typedef base::Callback<void(const scoped_refptr<CacheStorageCache>&)>
+ CacheCallback;
+ typedef base::Callback<void(bool)> BoolCallback;
+ typedef base::Callback<void(scoped_ptr<std::vector<std::string>>)>
+ StringVectorCallback;
+
+ CacheLoader(
+ base::SequencedTaskRunner* cache_task_runner,
+ 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 CacheStorageCache with the given name. It does not attempt to
+ // load the backend, that happens lazily when the cache is used.
+ virtual scoped_refptr<CacheStorageCache> CreateCache(
+ 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 CacheStorage::MemoryLoader : public CacheStorage::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<CacheStorageCache> CreateCache(
+ const std::string& cache_name) override {
+ return CacheStorageCache::CreateMemoryCache(
+ origin_, request_context_, quota_manager_proxy_, blob_context_);
+ }
+
+ void CreateCache(const std::string& cache_name,
+ const CacheCallback& callback) override {
+ scoped_refptr<CacheStorageCache> cache = CreateCache(cache_name);
+ cache_refs_.insert(std::make_pair(cache_name, cache));
+ callback.Run(cache);
+ }
+
+ 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<CacheStorageCache>> CacheRefMap;
+ ~MemoryLoader() override {}
+
+ // Keep a reference to each cache to ensure that it's not freed before the
+ // client calls CacheStorage::Delete or the CacheStorage is
+ // freed.
+ CacheRefMap cache_refs_;
+};
+
+class CacheStorage::SimpleCacheLoader : public CacheStorage::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<CacheStorageCache> CreateCache(
+ const std::string& cache_name) override {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ return CacheStorageCache::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<CacheStorageCache>());
+ return;
+ }
+
+ callback.Run(loader->CreateCache(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)
+
+ CacheStorageIndex index;
+ index.set_origin(origin_.spec());
+
+ for (size_t i = 0u, max = cache_names.size(); i < max; ++i) {
+ CacheStorageIndex::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(CacheStorage::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(CacheStorage::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);
+
+ CacheStorageIndex index;
+ if (index.ParseFromString(serialized)) {
+ for (int i = 0, max = index.cache_size(); i < max; ++i) {
+ const CacheStorageIndex::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_;
+};
+
+CacheStorage::CacheStorage(
+ 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),
+ initializing_(false),
+ scheduler_(new CacheStorageScheduler()),
+ 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));
+}
+
+CacheStorage::~CacheStorage() {
+}
+
+void CacheStorage::OpenCache(const std::string& cache_name,
+ const CacheAndErrorCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (!initialized_)
+ LazyInit();
+
+ CacheAndErrorCallback pending_callback =
+ base::Bind(&CacheStorage::PendingCacheAndErrorCallback,
+ weak_factory_.GetWeakPtr(), callback);
+ scheduler_->ScheduleOperation(base::Bind(&CacheStorage::OpenCacheImpl,
+ weak_factory_.GetWeakPtr(),
+ cache_name, pending_callback));
+}
+
+void CacheStorage::HasCache(const std::string& cache_name,
+ const BoolAndErrorCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (!initialized_)
+ LazyInit();
+
+ BoolAndErrorCallback pending_callback =
+ base::Bind(&CacheStorage::PendingBoolAndErrorCallback,
+ weak_factory_.GetWeakPtr(), callback);
+ scheduler_->ScheduleOperation(base::Bind(&CacheStorage::HasCacheImpl,
+ weak_factory_.GetWeakPtr(),
+ cache_name, pending_callback));
+}
+
+void CacheStorage::DeleteCache(const std::string& cache_name,
+ const BoolAndErrorCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (!initialized_)
+ LazyInit();
+
+ BoolAndErrorCallback pending_callback =
+ base::Bind(&CacheStorage::PendingBoolAndErrorCallback,
+ weak_factory_.GetWeakPtr(), callback);
+ scheduler_->ScheduleOperation(base::Bind(&CacheStorage::DeleteCacheImpl,
+ weak_factory_.GetWeakPtr(),
+ cache_name, pending_callback));
+}
+
+void CacheStorage::EnumerateCaches(const StringsAndErrorCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (!initialized_)
+ LazyInit();
+
+ StringsAndErrorCallback pending_callback =
+ base::Bind(&CacheStorage::PendingStringsAndErrorCallback,
+ weak_factory_.GetWeakPtr(), callback);
+ scheduler_->ScheduleOperation(base::Bind(&CacheStorage::EnumerateCachesImpl,
+ weak_factory_.GetWeakPtr(),
+ pending_callback));
+}
+
+void CacheStorage::MatchCache(
+ const std::string& cache_name,
+ scoped_ptr<ServiceWorkerFetchRequest> request,
+ const CacheStorageCache::ResponseCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (!initialized_)
+ LazyInit();
+
+ CacheStorageCache::ResponseCallback pending_callback =
+ base::Bind(&CacheStorage::PendingResponseCallback,
+ weak_factory_.GetWeakPtr(), callback);
+ scheduler_->ScheduleOperation(
+ base::Bind(&CacheStorage::MatchCacheImpl, weak_factory_.GetWeakPtr(),
+ cache_name, base::Passed(request.Pass()), pending_callback));
+}
+
+void CacheStorage::MatchAllCaches(
+ scoped_ptr<ServiceWorkerFetchRequest> request,
+ const CacheStorageCache::ResponseCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (!initialized_)
+ LazyInit();
+
+ CacheStorageCache::ResponseCallback pending_callback =
+ base::Bind(&CacheStorage::PendingResponseCallback,
+ weak_factory_.GetWeakPtr(), callback);
+ scheduler_->ScheduleOperation(
+ base::Bind(&CacheStorage::MatchAllCachesImpl, weak_factory_.GetWeakPtr(),
+ base::Passed(request.Pass()), pending_callback));
+}
+
+void CacheStorage::CloseAllCaches(const base::Closure& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (!initialized_) {
+ callback.Run();
+ return;
+ }
+
+ base::Closure pending_callback = base::Bind(
+ &CacheStorage::PendingClosure, weak_factory_.GetWeakPtr(), callback);
+ scheduler_->ScheduleOperation(base::Bind(&CacheStorage::CloseAllCachesImpl,
+ weak_factory_.GetWeakPtr(),
+ pending_callback));
+}
+
+int64 CacheStorage::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;
+}
+
+void CacheStorage::StartAsyncOperationForTesting() {
+ scheduler_->ScheduleOperation(base::Bind(&base::DoNothing));
+}
+
+void CacheStorage::CompleteAsyncOperationForTesting() {
+ scheduler_->CompleteOperationAndRunNext();
+}
+
+// Init is run lazily so that it is called on the proper MessageLoop.
+void CacheStorage::LazyInit() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(!initialized_);
+
+ if (initializing_)
+ return;
+
+ DCHECK(!scheduler_->ScheduledOperations());
+
+ initializing_ = true;
+ scheduler_->ScheduleOperation(
+ base::Bind(&CacheStorage::LazyInitImpl, weak_factory_.GetWeakPtr()));
+}
+
+void CacheStorage::LazyInitImpl() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(!initialized_);
+ DCHECK(initializing_);
+
+ // 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(&CacheStorage::LazyInitDidLoadIndex,
+ weak_factory_.GetWeakPtr()));
+}
+
+void CacheStorage::LazyInitDidLoadIndex(
+ 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<CacheStorageCache>()));
+ ordered_cache_names_.push_back(indexed_cache_names->at(i));
+ }
+
+ initializing_ = false;
+ initialized_ = true;
+
+ scheduler_->CompleteOperationAndRunNext();
+}
+
+void CacheStorage::OpenCacheImpl(const std::string& cache_name,
+ const CacheAndErrorCallback& callback) {
+ scoped_refptr<CacheStorageCache> cache = GetLoadedCache(cache_name);
+ if (cache.get()) {
+ callback.Run(cache, CACHE_STORAGE_OK);
+ return;
+ }
+
+ cache_loader_->CreateCache(
+ cache_name, base::Bind(&CacheStorage::CreateCacheDidCreateCache,
+ weak_factory_.GetWeakPtr(), cache_name, callback));
+}
+
+void CacheStorage::CreateCacheDidCreateCache(
+ const std::string& cache_name,
+ const CacheAndErrorCallback& callback,
+ const scoped_refptr<CacheStorageCache>& cache) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ UMA_HISTOGRAM_BOOLEAN("ServiceWorkerCache.CreateCacheStorageResult",
+ cache != nullptr);
+
+ if (!cache.get()) {
+ callback.Run(scoped_refptr<CacheStorageCache>(),
+ CACHE_STORAGE_ERROR_STORAGE);
+ 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(&CacheStorage::CreateCacheDidWriteIndex,
+ weak_factory_.GetWeakPtr(), callback, cache));
+}
+
+void CacheStorage::CreateCacheDidWriteIndex(
+ const CacheAndErrorCallback& callback,
+ const scoped_refptr<CacheStorageCache>& cache,
+ bool success) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(cache.get());
+
+ // TODO(jkarlin): Handle !success.
+
+ callback.Run(cache, CACHE_STORAGE_OK);
+}
+
+void CacheStorage::HasCacheImpl(const std::string& cache_name,
+ const BoolAndErrorCallback& callback) {
+ bool has_cache = cache_map_.find(cache_name) != cache_map_.end();
+
+ callback.Run(has_cache, CACHE_STORAGE_OK);
+}
+
+void CacheStorage::DeleteCacheImpl(const std::string& cache_name,
+ const BoolAndErrorCallback& callback) {
+ CacheMap::iterator it = cache_map_.find(cache_name);
+ if (it == cache_map_.end()) {
+ callback.Run(false, CACHE_STORAGE_ERROR_NOT_FOUND);
+ return;
+ }
+
+ base::WeakPtr<CacheStorageCache> 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(&CacheStorage::DeleteCacheDidClose, weak_factory_.GetWeakPtr(),
+ cache_name, callback, ordered_cache_names_,
+ make_scoped_refptr(cache.get()));
+
+ if (cache) {
+ cache->Close(closure);
+ return;
+ }
+
+ closure.Run();
+}
+
+void CacheStorage::DeleteCacheDidClose(
+ const std::string& cache_name,
+ const BoolAndErrorCallback& callback,
+ const StringVector& ordered_cache_names,
+ const scoped_refptr<CacheStorageCache>& cache /* might be null */) {
+ cache_loader_->WriteIndex(
+ ordered_cache_names,
+ base::Bind(&CacheStorage::DeleteCacheDidWriteIndex,
+ weak_factory_.GetWeakPtr(), cache_name, callback));
+}
+
+void CacheStorage::DeleteCacheDidWriteIndex(
+ const std::string& cache_name,
+ const BoolAndErrorCallback& callback,
+ bool success) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ cache_loader_->CleanUpDeletedCache(
+ cache_name, base::Bind(&CacheStorage::DeleteCacheDidCleanUp,
+ weak_factory_.GetWeakPtr(), callback));
+}
+
+void CacheStorage::DeleteCacheDidCleanUp(const BoolAndErrorCallback& callback,
+ bool success) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ callback.Run(true, CACHE_STORAGE_OK);
+}
+
+void CacheStorage::EnumerateCachesImpl(
+ const StringsAndErrorCallback& callback) {
+ callback.Run(ordered_cache_names_, CACHE_STORAGE_OK);
+}
+
+void CacheStorage::MatchCacheImpl(
+ const std::string& cache_name,
+ scoped_ptr<ServiceWorkerFetchRequest> request,
+ const CacheStorageCache::ResponseCallback& callback) {
+ scoped_refptr<CacheStorageCache> cache = GetLoadedCache(cache_name);
+
+ if (!cache.get()) {
+ callback.Run(CACHE_STORAGE_ERROR_NOT_FOUND,
+ scoped_ptr<ServiceWorkerResponse>(),
+ scoped_ptr<storage::BlobDataHandle>());
+ return;
+ }
+
+ // Pass the cache along to the callback to keep the cache open until match is
+ // done.
+ cache->Match(request.Pass(),
+ base::Bind(&CacheStorage::MatchCacheDidMatch,
+ weak_factory_.GetWeakPtr(), cache, callback));
+}
+
+void CacheStorage::MatchCacheDidMatch(
+ const scoped_refptr<CacheStorageCache>& cache,
+ const CacheStorageCache::ResponseCallback& callback,
+ CacheStorageError error,
+ scoped_ptr<ServiceWorkerResponse> response,
+ scoped_ptr<storage::BlobDataHandle> handle) {
+ callback.Run(error, response.Pass(), handle.Pass());
+}
+
+void CacheStorage::MatchAllCachesImpl(
+ scoped_ptr<ServiceWorkerFetchRequest> request,
+ const CacheStorageCache::ResponseCallback& callback) {
+ scoped_ptr<CacheStorageCache::ResponseCallback> callback_copy(
+ new CacheStorageCache::ResponseCallback(callback));
+
+ CacheStorageCache::ResponseCallback* callback_ptr = callback_copy.get();
+ base::Closure barrier_closure =
+ base::BarrierClosure(ordered_cache_names_.size(),
+ base::Bind(&CacheStorage::MatchAllCachesDidMatchAll,
+ weak_factory_.GetWeakPtr(),
+ base::Passed(callback_copy.Pass())));
+
+ for (const std::string& cache_name : ordered_cache_names_) {
+ scoped_refptr<CacheStorageCache> cache = GetLoadedCache(cache_name);
+ DCHECK(cache.get());
+
+ cache->Match(make_scoped_ptr(new ServiceWorkerFetchRequest(*request)),
+ base::Bind(&CacheStorage::MatchAllCachesDidMatch,
+ weak_factory_.GetWeakPtr(), cache, barrier_closure,
+ callback_ptr));
+ }
+}
+
+void CacheStorage::MatchAllCachesDidMatch(
+ scoped_refptr<CacheStorageCache> cache,
+ const base::Closure& barrier_closure,
+ CacheStorageCache::ResponseCallback* callback,
+ CacheStorageError error,
+ scoped_ptr<ServiceWorkerResponse> response,
+ scoped_ptr<storage::BlobDataHandle> handle) {
+ if (callback->is_null() || error == CACHE_STORAGE_ERROR_NOT_FOUND) {
+ barrier_closure.Run();
+ return;
+ }
+ callback->Run(error, response.Pass(), handle.Pass());
+ callback->Reset(); // Only call the callback once.
+
+ barrier_closure.Run();
+}
+
+void CacheStorage::MatchAllCachesDidMatchAll(
+ scoped_ptr<CacheStorageCache::ResponseCallback> callback) {
+ if (!callback->is_null()) {
+ callback->Run(CACHE_STORAGE_ERROR_NOT_FOUND,
+ scoped_ptr<ServiceWorkerResponse>(),
+ scoped_ptr<storage::BlobDataHandle>());
+ }
+}
+
+scoped_refptr<CacheStorageCache> CacheStorage::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<CacheStorageCache>();
+
+ base::WeakPtr<CacheStorageCache> cache = map_iter->second;
+
+ if (!cache) {
+ scoped_refptr<CacheStorageCache> new_cache =
+ cache_loader_->CreateCache(cache_name);
+ map_iter->second = new_cache->AsWeakPtr();
+ return new_cache;
+ }
+
+ return make_scoped_refptr(cache.get());
+}
+
+void CacheStorage::CloseAllCachesImpl(const base::Closure& callback) {
+ int live_cache_count = 0;
+ for (const auto& key_value : cache_map_) {
+ if (key_value.second)
+ live_cache_count += 1;
+ }
+
+ 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();
+}
+
+void CacheStorage::PendingClosure(const base::Closure& callback) {
+ base::WeakPtr<CacheStorage> cache_storage = weak_factory_.GetWeakPtr();
+
+ callback.Run();
+ if (cache_storage)
+ scheduler_->CompleteOperationAndRunNext();
+}
+
+void CacheStorage::PendingBoolAndErrorCallback(
+ const BoolAndErrorCallback& callback,
+ bool found,
+ CacheStorageError error) {
+ base::WeakPtr<CacheStorage> cache_storage = weak_factory_.GetWeakPtr();
+
+ callback.Run(found, error);
+ if (cache_storage)
+ scheduler_->CompleteOperationAndRunNext();
+}
+
+void CacheStorage::PendingCacheAndErrorCallback(
+ const CacheAndErrorCallback& callback,
+ const scoped_refptr<CacheStorageCache>& cache,
+ CacheStorageError error) {
+ base::WeakPtr<CacheStorage> cache_storage = weak_factory_.GetWeakPtr();
+
+ callback.Run(cache, error);
+ if (cache_storage)
+ scheduler_->CompleteOperationAndRunNext();
+}
+
+void CacheStorage::PendingStringsAndErrorCallback(
+ const StringsAndErrorCallback& callback,
+ const StringVector& strings,
+ CacheStorageError error) {
+ base::WeakPtr<CacheStorage> cache_storage = weak_factory_.GetWeakPtr();
+
+ callback.Run(strings, error);
+ if (cache_storage)
+ scheduler_->CompleteOperationAndRunNext();
+}
+
+void CacheStorage::PendingResponseCallback(
+ const CacheStorageCache::ResponseCallback& callback,
+ CacheStorageError error,
+ scoped_ptr<ServiceWorkerResponse> response,
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle) {
+ base::WeakPtr<CacheStorage> cache_storage = weak_factory_.GetWeakPtr();
+
+ callback.Run(error, response.Pass(), blob_data_handle.Pass());
+ if (cache_storage)
+ scheduler_->CompleteOperationAndRunNext();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/cache_storage/cache_storage.h b/chromium/content/browser/cache_storage/cache_storage.h
new file mode 100644
index 00000000000..261eebd134c
--- /dev/null
+++ b/chromium/content/browser/cache_storage/cache_storage.h
@@ -0,0 +1,226 @@
+// Copyright 2014 The Chromium Authors. 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_CACHE_STORAGE_CACHE_STORAGE_H_
+#define CONTENT_BROWSER_CACHE_STORAGE_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/cache_storage/cache_storage_cache.h"
+
+namespace base {
+class SequencedTaskRunner;
+}
+
+namespace net {
+class URLRequestContext;
+}
+
+namespace storage {
+class BlobStorageContext;
+}
+
+namespace content {
+class CacheStorageScheduler;
+
+// TODO(jkarlin): Constrain the total bytes used per origin.
+
+// CacheStorage holds the set of caches for a given origin. It is
+// owned by the CacheStorageManager. This class expects to be run
+// on the IO thread. The asynchronous methods are executed serially.
+class CONTENT_EXPORT CacheStorage {
+ public:
+ typedef std::vector<std::string> StringVector;
+ typedef base::Callback<void(bool, CacheStorageError)> BoolAndErrorCallback;
+ typedef base::Callback<void(const scoped_refptr<CacheStorageCache>&,
+ CacheStorageError)> CacheAndErrorCallback;
+ typedef base::Callback<void(const StringVector&, CacheStorageError)>
+ StringsAndErrorCallback;
+
+ static const char kIndexFileName[];
+
+ CacheStorage(
+ 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 ~CacheStorage();
+
+ // 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);
+
+ // Calls match on the cache with the given |cache_name|.
+ void MatchCache(const std::string& cache_name,
+ scoped_ptr<ServiceWorkerFetchRequest> request,
+ const CacheStorageCache::ResponseCallback& callback);
+
+ // Calls match on all of the caches in parallel, calling |callback| with the
+ // first response found. Note that if multiple caches have the same
+ // request/response then it is not defined which cache's response will be
+ // returned. If no response is found then |callback| is called with
+ // CACHE_STORAGE_ERROR_NOT_FOUND.
+ void MatchAllCaches(scoped_ptr<ServiceWorkerFetchRequest> request,
+ const CacheStorageCache::ResponseCallback& callback);
+
+ // Calls close on each cache and runs the callback after all of them have
+ // closed.
+ void CloseAllCaches(const base::Closure& callback);
+
+ // The size of all of the origin's contents in memory. Returns 0 if the cache
+ // backend is not a memory backend. Runs synchronously.
+ int64 MemoryBackedSize() const;
+
+ // The functions below are for tests to verify that the operations run
+ // serially.
+ void StartAsyncOperationForTesting();
+ void CompleteAsyncOperationForTesting();
+
+ private:
+ class MemoryLoader;
+ class SimpleCacheLoader;
+ class CacheLoader;
+
+ typedef std::map<std::string, base::WeakPtr<CacheStorageCache>> CacheMap;
+
+ // Return a CacheStorageCache for the given name if the name is known. If the
+ // CacheStorageCache has been deleted, creates a new one.
+ scoped_refptr<CacheStorageCache> GetLoadedCache(
+ const std::string& cache_name);
+
+ // Initializer and its callback are below.
+ void LazyInit();
+ void LazyInitImpl();
+ void LazyInitDidLoadIndex(
+ scoped_ptr<std::vector<std::string>> indexed_cache_names);
+
+ // The Open and CreateCache callbacks are below.
+ void OpenCacheImpl(const std::string& cache_name,
+ const CacheAndErrorCallback& callback);
+ void CreateCacheDidCreateCache(const std::string& cache_name,
+ const CacheAndErrorCallback& callback,
+ const scoped_refptr<CacheStorageCache>& cache);
+ void CreateCacheDidWriteIndex(const CacheAndErrorCallback& callback,
+ const scoped_refptr<CacheStorageCache>& cache,
+ bool success);
+
+ // The HasCache callbacks are below.
+ void HasCacheImpl(const std::string& cache_name,
+ const BoolAndErrorCallback& callback);
+
+ // The DeleteCache callbacks are below.
+ void DeleteCacheImpl(const std::string& cache_name,
+ const BoolAndErrorCallback& callback);
+
+ void DeleteCacheDidClose(const std::string& cache_name,
+ const BoolAndErrorCallback& callback,
+ const StringVector& ordered_cache_names,
+ const scoped_refptr<CacheStorageCache>& cache);
+ void DeleteCacheDidWriteIndex(const std::string& cache_name,
+ const BoolAndErrorCallback& callback,
+ bool success);
+ void DeleteCacheDidCleanUp(const BoolAndErrorCallback& callback,
+ bool success);
+
+ // The EnumerateCache callbacks are below.
+ void EnumerateCachesImpl(const StringsAndErrorCallback& callback);
+
+ // The MatchCache callbacks are below.
+ void MatchCacheImpl(const std::string& cache_name,
+ scoped_ptr<ServiceWorkerFetchRequest> request,
+ const CacheStorageCache::ResponseCallback& callback);
+ void MatchCacheDidMatch(const scoped_refptr<CacheStorageCache>& cache,
+ const CacheStorageCache::ResponseCallback& callback,
+ CacheStorageError error,
+ scoped_ptr<ServiceWorkerResponse> response,
+ scoped_ptr<storage::BlobDataHandle> handle);
+
+ // The MatchAllCaches callbacks are below.
+ void MatchAllCachesImpl(scoped_ptr<ServiceWorkerFetchRequest> request,
+ const CacheStorageCache::ResponseCallback& callback);
+ void MatchAllCachesDidMatch(scoped_refptr<CacheStorageCache> cache,
+ const base::Closure& barrier_closure,
+ CacheStorageCache::ResponseCallback* callback,
+ CacheStorageError error,
+ scoped_ptr<ServiceWorkerResponse> response,
+ scoped_ptr<storage::BlobDataHandle> handle);
+ void MatchAllCachesDidMatchAll(
+ scoped_ptr<CacheStorageCache::ResponseCallback> callback);
+
+ // The CloseAllCaches callbacks are below.
+ void CloseAllCachesImpl(const base::Closure& callback);
+
+ void PendingClosure(const base::Closure& callback);
+ void PendingBoolAndErrorCallback(const BoolAndErrorCallback& callback,
+ bool found,
+ CacheStorageError error);
+ void PendingCacheAndErrorCallback(
+ const CacheAndErrorCallback& callback,
+ const scoped_refptr<CacheStorageCache>& cache,
+ CacheStorageError error);
+ void PendingStringsAndErrorCallback(const StringsAndErrorCallback& callback,
+ const StringVector& strings,
+ CacheStorageError error);
+ void PendingResponseCallback(
+ const CacheStorageCache::ResponseCallback& callback,
+ CacheStorageError error,
+ scoped_ptr<ServiceWorkerResponse> response,
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle);
+
+ // Whether or not we've loaded the list of cache names into memory.
+ bool initialized_;
+ bool initializing_;
+
+ // The pending operation scheduler.
+ scoped_ptr<CacheStorageScheduler> scheduler_;
+
+ // The map of cache names to CacheStorageCache 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<CacheStorage> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(CacheStorage);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_CACHE_STORAGE_CACHE_STORAGE_H_
diff --git a/chromium/content/browser/cache_storage/cache_storage.proto b/chromium/content/browser/cache_storage/cache_storage.proto
new file mode 100644
index 00000000000..560bcf13f46
--- /dev/null
+++ b/chromium/content/browser/cache_storage/cache_storage.proto
@@ -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.
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package content;
+
+message CacheStorageIndex {
+ message Cache { required string name = 1; }
+ repeated Cache cache = 1;
+ optional string origin = 2;
+}
+
+message CacheHeaderMap {
+ required string name = 1;
+ required string value = 2;
+}
+
+message CacheRequest {
+ required string method = 1;
+ repeated CacheHeaderMap headers = 2;
+}
+
+message CacheResponse {
+ 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 CacheHeaderMap headers = 4;
+ optional string url = 5;
+}
+
+message CacheMetadata {
+ required CacheRequest request = 1;
+ required CacheResponse response = 2;
+}
diff --git a/chromium/content/browser/cache_storage/cache_storage_cache.cc b/chromium/content/browser/cache_storage/cache_storage_cache.cc
new file mode 100644
index 00000000000..43737590ee9
--- /dev/null
+++ b/chromium/content/browser/cache_storage/cache_storage_cache.cc
@@ -0,0 +1,1275 @@
+// Copyright 2014 The Chromium Authors. 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/cache_storage/cache_storage_cache.h"
+
+#include <string>
+
+#include "base/barrier_closure.h"
+#include "base/files/file_path.h"
+#include "base/guid.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/strings/string_util.h"
+#include "content/browser/cache_storage/cache_storage.pb.h"
+#include "content/browser/cache_storage/cache_storage_scheduler.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/common/referrer.h"
+#include "net/base/completion_callback.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_builder.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 base::Callback<void(disk_cache::ScopedEntryPtr, bool)>
+ EntryBoolCallback;
+typedef base::Callback<void(scoped_ptr<CacheMetadata>)> MetadataCallback;
+
+enum EntryIndex { INDEX_HEADERS = 0, INDEX_RESPONSE_BODY };
+
+// The maximum size of an individual cache. Ultimately cache size is controlled
+// per-origin.
+const int kMaxCacheBytes = 512 * 1024 * 1024;
+
+// Buffer size for cache and blob reading/writing.
+const int kBufferSize = 1024 * 512;
+
+void NotReachedCompletionCallback(int rv) {
+ NOTREACHED();
+}
+
+blink::WebServiceWorkerResponseType ProtoResponseTypeToWebResponseType(
+ CacheResponse::ResponseType response_type) {
+ switch (response_type) {
+ case CacheResponse::BASIC_TYPE:
+ return blink::WebServiceWorkerResponseTypeBasic;
+ case CacheResponse::CORS_TYPE:
+ return blink::WebServiceWorkerResponseTypeCORS;
+ case CacheResponse::DEFAULT_TYPE:
+ return blink::WebServiceWorkerResponseTypeDefault;
+ case CacheResponse::ERROR_TYPE:
+ return blink::WebServiceWorkerResponseTypeError;
+ case CacheResponse::OPAQUE_TYPE:
+ return blink::WebServiceWorkerResponseTypeOpaque;
+ }
+ NOTREACHED();
+ return blink::WebServiceWorkerResponseTypeOpaque;
+}
+
+CacheResponse::ResponseType WebResponseTypeToProtoResponseType(
+ blink::WebServiceWorkerResponseType response_type) {
+ switch (response_type) {
+ case blink::WebServiceWorkerResponseTypeBasic:
+ return CacheResponse::BASIC_TYPE;
+ case blink::WebServiceWorkerResponseTypeCORS:
+ return CacheResponse::CORS_TYPE;
+ case blink::WebServiceWorkerResponseTypeDefault:
+ return CacheResponse::DEFAULT_TYPE;
+ case blink::WebServiceWorkerResponseTypeError:
+ return CacheResponse::ERROR_TYPE;
+ case blink::WebServiceWorkerResponseTypeOpaque:
+ return CacheResponse::OPAQUE_TYPE;
+ }
+ NOTREACHED();
+ return CacheResponse::OPAQUE_TYPE;
+}
+
+// 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);
+
+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 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<CacheMetadata>());
+ return;
+ }
+
+ scoped_ptr<CacheMetadata> metadata(new CacheMetadata());
+
+ if (!metadata->ParseFromArray(buffer->data(), buffer->size())) {
+ callback.Run(scoped_ptr<CacheMetadata>());
+ return;
+ }
+
+ callback.Run(metadata.Pass());
+}
+
+} // namespace
+
+// Streams data from a blob and writes it to a given disk_cache::Entry.
+class CacheStorageCache::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 CacheStorageCache::Keys callbacks.
+struct CacheStorageCache::KeysContext {
+ explicit KeysContext(const CacheStorageCache::RequestsCallback& callback)
+ : original_callback(callback),
+ out_keys(new CacheStorageCache::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.
+ CacheStorageCache::RequestsCallback original_callback;
+
+ // The vector of open entries in the backend.
+ Entries entries;
+
+ // The output of the Keys function.
+ scoped_ptr<CacheStorageCache::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);
+};
+
+struct CacheStorageCache::MatchContext {
+ MatchContext(scoped_ptr<ServiceWorkerFetchRequest> request,
+ const CacheStorageCache::ResponseCallback& callback,
+ base::WeakPtr<storage::BlobStorageContext> blob_storage_context)
+ : request(request.Pass()),
+ original_callback(callback),
+ blob_storage_context(blob_storage_context),
+ entry(nullptr),
+ total_bytes_read(0) {}
+
+ ~MatchContext() {
+ if (entry)
+ entry->Close();
+ }
+
+ // Input
+ scoped_ptr<ServiceWorkerFetchRequest> request;
+ CacheStorageCache::ResponseCallback original_callback;
+ base::WeakPtr<storage::BlobStorageContext> blob_storage_context;
+ disk_cache::Entry* entry;
+
+ // Output
+ scoped_ptr<ServiceWorkerResponse> response;
+ scoped_ptr<storage::BlobDataBuilder> blob_data;
+
+ // For reading the cache entry data into a blob.
+ scoped_refptr<net::IOBufferWithSize> response_body_buffer;
+ size_t total_bytes_read;
+
+ DISALLOW_COPY_AND_ASSIGN(MatchContext);
+};
+
+// The state needed to pass between CacheStorageCache::Put callbacks.
+struct CacheStorageCache::PutContext {
+ PutContext(
+ const GURL& origin,
+ scoped_ptr<ServiceWorkerFetchRequest> request,
+ scoped_ptr<ServiceWorkerResponse> response,
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle,
+ const CacheStorageCache::ErrorCallback& callback,
+ 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),
+ 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;
+ CacheStorageCache::ErrorCallback callback;
+ 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;
+
+ DISALLOW_COPY_AND_ASSIGN(PutContext);
+};
+
+// static
+scoped_refptr<CacheStorageCache> CacheStorageCache::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 CacheStorageCache(origin, base::FilePath(), request_context,
+ quota_manager_proxy, blob_context));
+}
+
+// static
+scoped_refptr<CacheStorageCache> CacheStorageCache::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 CacheStorageCache(
+ origin, path, request_context, quota_manager_proxy, blob_context));
+}
+
+CacheStorageCache::~CacheStorageCache() {
+}
+
+base::WeakPtr<CacheStorageCache> CacheStorageCache::AsWeakPtr() {
+ return weak_ptr_factory_.GetWeakPtr();
+}
+
+void CacheStorageCache::Match(scoped_ptr<ServiceWorkerFetchRequest> request,
+ const ResponseCallback& callback) {
+ switch (backend_state_) {
+ case BACKEND_UNINITIALIZED:
+ InitBackend();
+ break;
+ case BACKEND_CLOSED:
+ callback.Run(CACHE_STORAGE_ERROR_STORAGE,
+ scoped_ptr<ServiceWorkerResponse>(),
+ scoped_ptr<storage::BlobDataHandle>());
+ return;
+ case BACKEND_OPEN:
+ DCHECK(backend_);
+ break;
+ }
+
+ ResponseCallback pending_callback =
+ base::Bind(&CacheStorageCache::PendingResponseCallback,
+ weak_ptr_factory_.GetWeakPtr(), callback);
+ scheduler_->ScheduleOperation(
+ base::Bind(&CacheStorageCache::MatchImpl, weak_ptr_factory_.GetWeakPtr(),
+ base::Passed(request.Pass()), pending_callback));
+}
+
+void CacheStorageCache::BatchOperation(
+ const std::vector<CacheStorageBatchOperation>& operations,
+ const ErrorCallback& callback) {
+ switch (backend_state_) {
+ case BACKEND_UNINITIALIZED:
+ InitBackend();
+ break;
+ case BACKEND_CLOSED:
+ callback.Run(CACHE_STORAGE_ERROR_STORAGE);
+ return;
+ case BACKEND_OPEN:
+ DCHECK(backend_);
+ break;
+ }
+
+ scoped_ptr<ErrorCallback> callback_copy(new ErrorCallback(callback));
+ ErrorCallback* callback_ptr = callback_copy.get();
+ base::Closure barrier_closure = base::BarrierClosure(
+ operations.size(), base::Bind(&CacheStorageCache::BatchDidAllOperations,
+ this, base::Passed(callback_copy.Pass())));
+ ErrorCallback completion_callback =
+ base::Bind(&CacheStorageCache::BatchDidOneOperation, this,
+ barrier_closure, callback_ptr);
+
+ for (const auto& operation : operations) {
+ switch (operation.operation_type) {
+ case CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT:
+ Put(operation, completion_callback);
+ break;
+ case CACHE_STORAGE_CACHE_OPERATION_TYPE_DELETE:
+ DCHECK_EQ(1u, operations.size());
+ Delete(operation, completion_callback);
+ break;
+ case CACHE_STORAGE_CACHE_OPERATION_TYPE_UNDEFINED:
+ NOTREACHED();
+ // TODO(nhiroki): This should return "TypeError".
+ // http://crbug.com/425505
+ completion_callback.Run(CACHE_STORAGE_ERROR_STORAGE);
+ break;
+ }
+ }
+}
+
+void CacheStorageCache::BatchDidOneOperation(
+ const base::Closure& barrier_closure,
+ ErrorCallback* callback,
+ CacheStorageError error) {
+ if (callback->is_null() || error == CACHE_STORAGE_OK) {
+ barrier_closure.Run();
+ return;
+ }
+ callback->Run(error);
+ callback->Reset(); // Only call the callback once.
+
+ barrier_closure.Run();
+}
+
+void CacheStorageCache::BatchDidAllOperations(
+ scoped_ptr<ErrorCallback> callback) {
+ if (callback->is_null())
+ return;
+ callback->Run(CACHE_STORAGE_OK);
+}
+
+void CacheStorageCache::Keys(const RequestsCallback& callback) {
+ switch (backend_state_) {
+ case BACKEND_UNINITIALIZED:
+ InitBackend();
+ break;
+ case BACKEND_CLOSED:
+ callback.Run(CACHE_STORAGE_ERROR_STORAGE, scoped_ptr<Requests>());
+ return;
+ case BACKEND_OPEN:
+ DCHECK(backend_);
+ break;
+ }
+
+ RequestsCallback pending_callback =
+ base::Bind(&CacheStorageCache::PendingRequestsCallback,
+ weak_ptr_factory_.GetWeakPtr(), callback);
+ scheduler_->ScheduleOperation(base::Bind(&CacheStorageCache::KeysImpl,
+ weak_ptr_factory_.GetWeakPtr(),
+ pending_callback));
+}
+
+void CacheStorageCache::Close(const base::Closure& callback) {
+ DCHECK(backend_state_ != BACKEND_CLOSED)
+ << "Don't call CacheStorageCache::Close() twice.";
+
+ base::Closure pending_callback =
+ base::Bind(&CacheStorageCache::PendingClosure,
+ weak_ptr_factory_.GetWeakPtr(), callback);
+
+ scheduler_->ScheduleOperation(base::Bind(&CacheStorageCache::CloseImpl,
+ weak_ptr_factory_.GetWeakPtr(),
+ pending_callback));
+}
+
+int64 CacheStorageCache::MemoryBackedSize() const {
+ if (backend_state_ != BACKEND_OPEN || !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;
+}
+
+CacheStorageCache::CacheStorageCache(
+ 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),
+ backend_state_(BACKEND_UNINITIALIZED),
+ scheduler_(new CacheStorageScheduler()),
+ initializing_(false),
+ memory_only_(path.empty()),
+ weak_ptr_factory_(this) {
+}
+
+void CacheStorageCache::MatchImpl(scoped_ptr<ServiceWorkerFetchRequest> request,
+ const ResponseCallback& callback) {
+ DCHECK(backend_state_ != BACKEND_UNINITIALIZED);
+ if (backend_state_ != BACKEND_OPEN) {
+ callback.Run(CACHE_STORAGE_ERROR_STORAGE,
+ scoped_ptr<ServiceWorkerResponse>(),
+ scoped_ptr<storage::BlobDataHandle>());
+ return;
+ }
+
+ scoped_ptr<MatchContext> match_context(
+ new MatchContext(request.Pass(), callback, blob_storage_context_));
+
+ disk_cache::Entry** entry_ptr = &match_context->entry;
+ ServiceWorkerFetchRequest* request_ptr = match_context->request.get();
+
+ net::CompletionCallback open_entry_callback = base::Bind(
+ &CacheStorageCache::MatchDidOpenEntry, weak_ptr_factory_.GetWeakPtr(),
+ base::Passed(match_context.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 CacheStorageCache::MatchDidOpenEntry(
+ scoped_ptr<MatchContext> match_context,
+ int rv) {
+ if (rv != net::OK) {
+ match_context->original_callback.Run(CACHE_STORAGE_ERROR_NOT_FOUND,
+ scoped_ptr<ServiceWorkerResponse>(),
+ scoped_ptr<storage::BlobDataHandle>());
+ return;
+ }
+
+ // Copy the entry pointer before passing it in base::Bind.
+ disk_cache::Entry* tmp_entry_ptr = match_context->entry;
+ DCHECK(tmp_entry_ptr);
+
+ MetadataCallback headers_callback = base::Bind(
+ &CacheStorageCache::MatchDidReadMetadata, weak_ptr_factory_.GetWeakPtr(),
+ base::Passed(match_context.Pass()));
+
+ ReadMetadata(tmp_entry_ptr, headers_callback);
+}
+
+void CacheStorageCache::MatchDidReadMetadata(
+ scoped_ptr<MatchContext> match_context,
+ scoped_ptr<CacheMetadata> metadata) {
+ if (!metadata) {
+ match_context->original_callback.Run(CACHE_STORAGE_ERROR_STORAGE,
+ scoped_ptr<ServiceWorkerResponse>(),
+ scoped_ptr<storage::BlobDataHandle>());
+ return;
+ }
+
+ match_context->response.reset(new ServiceWorkerResponse(
+ match_context->request->url, metadata->response().status_code(),
+ metadata->response().status_text(),
+ ProtoResponseTypeToWebResponseType(metadata->response().response_type()),
+ ServiceWorkerHeaderMap(), "", 0, GURL()));
+
+ ServiceWorkerResponse* response = match_context->response.get();
+
+ if (metadata->response().has_url())
+ response->url = GURL(metadata->response().url());
+
+ for (int i = 0; i < metadata->response().headers_size(); ++i) {
+ const CacheHeaderMap header = metadata->response().headers(i);
+ DCHECK(header.name().find('\0') == std::string::npos);
+ DCHECK(header.value().find('\0') == std::string::npos);
+ 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 CacheHeaderMap header = metadata->request().headers(i);
+ DCHECK(header.name().find('\0') == std::string::npos);
+ DCHECK(header.value().find('\0') == std::string::npos);
+ cached_request_headers[header.name()] = header.value();
+ }
+
+ if (!VaryMatches(match_context->request->headers, cached_request_headers,
+ response->headers)) {
+ match_context->original_callback.Run(CACHE_STORAGE_ERROR_NOT_FOUND,
+ scoped_ptr<ServiceWorkerResponse>(),
+ scoped_ptr<storage::BlobDataHandle>());
+ return;
+ }
+
+ if (match_context->entry->GetDataSize(INDEX_RESPONSE_BODY) == 0) {
+ match_context->original_callback.Run(CACHE_STORAGE_OK,
+ match_context->response.Pass(),
+ scoped_ptr<storage::BlobDataHandle>());
+ return;
+ }
+
+ // Stream the response body into a blob.
+ if (!match_context->blob_storage_context) {
+ match_context->original_callback.Run(CACHE_STORAGE_ERROR_STORAGE,
+ scoped_ptr<ServiceWorkerResponse>(),
+ scoped_ptr<storage::BlobDataHandle>());
+ return;
+ }
+
+ response->blob_uuid = base::GenerateGUID();
+
+ match_context->blob_data.reset(
+ new storage::BlobDataBuilder(response->blob_uuid));
+ match_context->response_body_buffer = new net::IOBufferWithSize(kBufferSize);
+
+ disk_cache::Entry* tmp_entry_ptr = match_context->entry;
+ net::IOBufferWithSize* response_body_buffer =
+ match_context->response_body_buffer.get();
+
+ net::CompletionCallback read_callback = base::Bind(
+ &CacheStorageCache::MatchDidReadResponseBodyData,
+ weak_ptr_factory_.GetWeakPtr(), base::Passed(match_context.Pass()));
+
+ int read_rv =
+ tmp_entry_ptr->ReadData(INDEX_RESPONSE_BODY, 0, response_body_buffer,
+ response_body_buffer->size(), read_callback);
+
+ if (read_rv != net::ERR_IO_PENDING)
+ read_callback.Run(read_rv);
+}
+
+void CacheStorageCache::MatchDidReadResponseBodyData(
+ scoped_ptr<MatchContext> match_context,
+ int rv) {
+ if (rv < 0) {
+ match_context->original_callback.Run(CACHE_STORAGE_ERROR_STORAGE,
+ scoped_ptr<ServiceWorkerResponse>(),
+ scoped_ptr<storage::BlobDataHandle>());
+ return;
+ }
+
+ if (rv == 0) {
+ match_context->response->blob_uuid = match_context->blob_data->uuid();
+ match_context->response->blob_size = match_context->total_bytes_read;
+ MatchDoneWithBody(match_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.
+ match_context->blob_data->AppendData(
+ match_context->response_body_buffer->data(), rv);
+ match_context->total_bytes_read += rv;
+ int total_bytes_read = match_context->total_bytes_read;
+
+ // Grab some pointers before passing match_context in bind.
+ net::IOBufferWithSize* buffer = match_context->response_body_buffer.get();
+ disk_cache::Entry* tmp_entry_ptr = match_context->entry;
+
+ net::CompletionCallback read_callback = base::Bind(
+ &CacheStorageCache::MatchDidReadResponseBodyData,
+ weak_ptr_factory_.GetWeakPtr(), base::Passed(match_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 CacheStorageCache::MatchDoneWithBody(
+ scoped_ptr<MatchContext> match_context) {
+ if (!match_context->blob_storage_context) {
+ match_context->original_callback.Run(CACHE_STORAGE_ERROR_STORAGE,
+ scoped_ptr<ServiceWorkerResponse>(),
+ scoped_ptr<storage::BlobDataHandle>());
+ return;
+ }
+
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle(
+ match_context->blob_storage_context->AddFinishedBlob(
+ match_context->blob_data.get()));
+
+ match_context->original_callback.Run(CACHE_STORAGE_OK,
+ match_context->response.Pass(),
+ blob_data_handle.Pass());
+}
+
+void CacheStorageCache::Put(const CacheStorageBatchOperation& operation,
+ const ErrorCallback& callback) {
+ DCHECK(BACKEND_OPEN == backend_state_ || initializing_);
+ DCHECK_EQ(CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT, operation.operation_type);
+
+ scoped_ptr<ServiceWorkerFetchRequest> request(new ServiceWorkerFetchRequest(
+ operation.request.url, operation.request.method,
+ operation.request.headers, operation.request.referrer,
+ operation.request.is_reload));
+
+ // We don't support streaming for cache.
+ DCHECK(operation.response.stream_url.is_empty());
+ scoped_ptr<ServiceWorkerResponse> 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, operation.response.stream_url));
+
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle;
+
+ if (!response->blob_uuid.empty()) {
+ if (!blob_storage_context_) {
+ callback.Run(CACHE_STORAGE_ERROR_STORAGE);
+ return;
+ }
+ blob_data_handle =
+ blob_storage_context_->GetBlobDataFromUUID(response->blob_uuid);
+ if (!blob_data_handle) {
+ callback.Run(CACHE_STORAGE_ERROR_STORAGE);
+ return;
+ }
+ }
+
+ ErrorCallback pending_callback =
+ base::Bind(&CacheStorageCache::PendingErrorCallback,
+ weak_ptr_factory_.GetWeakPtr(), callback);
+
+ scoped_ptr<PutContext> put_context(new PutContext(
+ origin_, request.Pass(), response.Pass(), blob_data_handle.Pass(),
+ pending_callback, request_context_, quota_manager_proxy_));
+
+ scheduler_->ScheduleOperation(base::Bind(&CacheStorageCache::PutImpl,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::Passed(put_context.Pass())));
+}
+
+void CacheStorageCache::PutImpl(scoped_ptr<PutContext> put_context) {
+ DCHECK(backend_state_ != BACKEND_UNINITIALIZED);
+ if (backend_state_ != BACKEND_OPEN) {
+ put_context->callback.Run(CACHE_STORAGE_ERROR_STORAGE);
+ return;
+ }
+
+ scoped_ptr<ServiceWorkerFetchRequest> request_copy(
+ new ServiceWorkerFetchRequest(*put_context->request));
+
+ DeleteImpl(request_copy.Pass(), base::Bind(&CacheStorageCache::PutDidDelete,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::Passed(put_context.Pass())));
+}
+
+void CacheStorageCache::PutDidDelete(scoped_ptr<PutContext> put_context,
+ CacheStorageError delete_error) {
+ if (backend_state_ != BACKEND_OPEN) {
+ put_context->callback.Run(CACHE_STORAGE_ERROR_STORAGE);
+ return;
+ }
+
+ disk_cache::Entry** entry_ptr = &put_context->cache_entry;
+ ServiceWorkerFetchRequest* request_ptr = put_context->request.get();
+ disk_cache::Backend* backend_ptr = backend_.get();
+
+ net::CompletionCallback create_entry_callback = base::Bind(
+ &CacheStorageCache::PutDidCreateEntry, weak_ptr_factory_.GetWeakPtr(),
+ 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);
+}
+
+void CacheStorageCache::PutDidCreateEntry(scoped_ptr<PutContext> put_context,
+ int rv) {
+ if (rv != net::OK) {
+ put_context->callback.Run(CACHE_STORAGE_ERROR_EXISTS);
+ return;
+ }
+
+ DCHECK(put_context->cache_entry);
+
+ CacheMetadata metadata;
+ CacheRequest* 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) {
+ DCHECK(it->first.find('\0') == std::string::npos);
+ DCHECK(it->second.find('\0') == std::string::npos);
+ CacheHeaderMap* header_map = request_metadata->add_headers();
+ header_map->set_name(it->first);
+ header_map->set_value(it->second);
+ }
+
+ CacheResponse* 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) {
+ DCHECK(it->first.find('\0') == std::string::npos);
+ DCHECK(it->second.find('\0') == std::string::npos);
+ CacheHeaderMap* 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(CACHE_STORAGE_ERROR_STORAGE);
+ 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(
+ &CacheStorageCache::PutDidWriteHeaders, weak_ptr_factory_.GetWeakPtr(),
+ 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);
+}
+
+void CacheStorageCache::PutDidWriteHeaders(scoped_ptr<PutContext> put_context,
+ int expected_bytes,
+ int rv) {
+ if (rv != expected_bytes) {
+ put_context->cache_entry->Doom();
+ put_context->callback.Run(CACHE_STORAGE_ERROR_STORAGE);
+ 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(CACHE_STORAGE_OK);
+ 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(&CacheStorageCache::PutDidWriteBlobToCache,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::Passed(put_context.Pass()),
+ base::Passed(reader.Pass())));
+}
+
+void CacheStorageCache::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(CACHE_STORAGE_ERROR_STORAGE);
+ 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(CACHE_STORAGE_OK);
+}
+
+void CacheStorageCache::Delete(const CacheStorageBatchOperation& operation,
+ const ErrorCallback& callback) {
+ DCHECK(BACKEND_OPEN == backend_state_ || initializing_);
+ DCHECK_EQ(CACHE_STORAGE_CACHE_OPERATION_TYPE_DELETE,
+ operation.operation_type);
+
+ scoped_ptr<ServiceWorkerFetchRequest> request(new ServiceWorkerFetchRequest(
+ operation.request.url, operation.request.method,
+ operation.request.headers, operation.request.referrer,
+ operation.request.is_reload));
+
+ ErrorCallback pending_callback =
+ base::Bind(&CacheStorageCache::PendingErrorCallback,
+ weak_ptr_factory_.GetWeakPtr(), callback);
+ scheduler_->ScheduleOperation(
+ base::Bind(&CacheStorageCache::DeleteImpl, weak_ptr_factory_.GetWeakPtr(),
+ base::Passed(request.Pass()), pending_callback));
+}
+
+void CacheStorageCache::DeleteImpl(
+ scoped_ptr<ServiceWorkerFetchRequest> request,
+ const ErrorCallback& callback) {
+ DCHECK(backend_state_ != BACKEND_UNINITIALIZED);
+ if (backend_state_ != BACKEND_OPEN) {
+ callback.Run(CACHE_STORAGE_ERROR_STORAGE);
+ 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(
+ &CacheStorageCache::DeleteDidOpenEntry, weak_ptr_factory_.GetWeakPtr(),
+ origin_, base::Passed(request.Pass()), 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 CacheStorageCache::DeleteDidOpenEntry(
+ const GURL& origin,
+ scoped_ptr<ServiceWorkerFetchRequest> request,
+ const CacheStorageCache::ErrorCallback& callback,
+ scoped_ptr<disk_cache::Entry*> entry_ptr,
+ const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
+ int rv) {
+ if (rv != net::OK) {
+ callback.Run(CACHE_STORAGE_ERROR_NOT_FOUND);
+ return;
+ }
+
+ DCHECK(entry_ptr);
+ disk_cache::ScopedEntryPtr entry(*entry_ptr);
+
+ if (quota_manager_proxy.get()) {
+ quota_manager_proxy->NotifyStorageModified(
+ storage::QuotaClient::kServiceWorkerCache, origin,
+ storage::kStorageTypeTemporary,
+ -1 * (entry->GetDataSize(INDEX_HEADERS) +
+ entry->GetDataSize(INDEX_RESPONSE_BODY)));
+ }
+
+ entry->Doom();
+ callback.Run(CACHE_STORAGE_OK);
+}
+
+void CacheStorageCache::KeysImpl(const RequestsCallback& callback) {
+ DCHECK(backend_state_ != BACKEND_UNINITIALIZED);
+ if (backend_state_ != BACKEND_OPEN) {
+ callback.Run(CACHE_STORAGE_ERROR_STORAGE, 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(callback));
+
+ 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(
+ &CacheStorageCache::KeysDidOpenNextEntry, weak_ptr_factory_.GetWeakPtr(),
+ 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 CacheStorageCache::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;
+ }
+
+ if (rv < 0) {
+ keys_context->original_callback.Run(CACHE_STORAGE_ERROR_STORAGE,
+ scoped_ptr<Requests>());
+ return;
+ }
+
+ if (backend_state_ != BACKEND_OPEN) {
+ keys_context->original_callback.Run(CACHE_STORAGE_ERROR_NOT_FOUND,
+ 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(
+ &CacheStorageCache::KeysDidOpenNextEntry, weak_ptr_factory_.GetWeakPtr(),
+ base::Passed(keys_context.Pass()));
+
+ rv = iterator.OpenNextEntry(enumerated_entry, open_entry_callback);
+
+ if (rv != net::ERR_IO_PENDING)
+ open_entry_callback.Run(rv);
+}
+
+void CacheStorageCache::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(CACHE_STORAGE_OK,
+ keys_context->out_keys.Pass());
+ return;
+ }
+
+ ReadMetadata(*iter, base::Bind(&CacheStorageCache::KeysDidReadMetadata,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::Passed(keys_context.Pass()), iter));
+}
+
+void CacheStorageCache::KeysDidReadMetadata(
+ scoped_ptr<KeysContext> keys_context,
+ const Entries::iterator& iter,
+ scoped_ptr<CacheMetadata> metadata) {
+ disk_cache::Entry* entry = *iter;
+
+ if (metadata) {
+ keys_context->out_keys->push_back(ServiceWorkerFetchRequest(
+ GURL(entry->GetKey()), metadata->request().method(),
+ ServiceWorkerHeaderMap(), Referrer(), false));
+
+ ServiceWorkerHeaderMap& req_headers =
+ keys_context->out_keys->back().headers;
+
+ for (int i = 0; i < metadata->request().headers_size(); ++i) {
+ const CacheHeaderMap header = metadata->request().headers(i);
+ DCHECK(header.name().find('\0') == std::string::npos);
+ DCHECK(header.value().find('\0') == std::string::npos);
+ req_headers.insert(std::make_pair(header.name(), header.value()));
+ }
+ } else {
+ entry->Doom();
+ }
+
+ KeysProcessNextEntry(keys_context.Pass(), iter + 1);
+}
+
+void CacheStorageCache::CloseImpl(const base::Closure& callback) {
+ DCHECK(backend_state_ != BACKEND_CLOSED);
+
+ backend_state_ = BACKEND_CLOSED;
+ backend_.reset();
+ callback.Run();
+}
+
+void CacheStorageCache::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(&CacheStorageCache::CreateBackendDidCreate,
+ weak_ptr_factory_.GetWeakPtr(), callback,
+ base::Passed(backend_ptr.Pass()));
+
+ // 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 CacheStorageCache::CreateBackendDidCreate(
+ const CacheStorageCache::ErrorCallback& callback,
+ scoped_ptr<ScopedBackendPtr> backend_ptr,
+ int rv) {
+ if (rv != net::OK) {
+ callback.Run(CACHE_STORAGE_ERROR_STORAGE);
+ return;
+ }
+
+ backend_ = backend_ptr->Pass();
+ callback.Run(CACHE_STORAGE_OK);
+}
+
+void CacheStorageCache::InitBackend() {
+ DCHECK(backend_state_ == BACKEND_UNINITIALIZED);
+
+ if (initializing_)
+ return;
+
+ DCHECK(!scheduler_->ScheduledOperations());
+ initializing_ = true;
+
+ scheduler_->ScheduleOperation(base::Bind(
+ &CacheStorageCache::CreateBackend, weak_ptr_factory_.GetWeakPtr(),
+ base::Bind(&CacheStorageCache::InitDone,
+ weak_ptr_factory_.GetWeakPtr())));
+}
+
+void CacheStorageCache::InitDone(CacheStorageError error) {
+ initializing_ = false;
+ backend_state_ = (error == CACHE_STORAGE_OK && backend_ &&
+ backend_state_ == BACKEND_UNINITIALIZED)
+ ? BACKEND_OPEN
+ : BACKEND_CLOSED;
+
+ UMA_HISTOGRAM_ENUMERATION("ServiceWorkerCache.InitBackendResult", error,
+ CACHE_STORAGE_ERROR_LAST + 1);
+
+ scheduler_->CompleteOperationAndRunNext();
+}
+
+void CacheStorageCache::PendingClosure(const base::Closure& callback) {
+ base::WeakPtr<CacheStorageCache> cache = weak_ptr_factory_.GetWeakPtr();
+
+ callback.Run();
+ if (cache)
+ scheduler_->CompleteOperationAndRunNext();
+}
+
+void CacheStorageCache::PendingErrorCallback(const ErrorCallback& callback,
+ CacheStorageError error) {
+ base::WeakPtr<CacheStorageCache> cache = weak_ptr_factory_.GetWeakPtr();
+
+ callback.Run(error);
+ if (cache)
+ scheduler_->CompleteOperationAndRunNext();
+}
+
+void CacheStorageCache::PendingResponseCallback(
+ const ResponseCallback& callback,
+ CacheStorageError error,
+ scoped_ptr<ServiceWorkerResponse> response,
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle) {
+ base::WeakPtr<CacheStorageCache> cache = weak_ptr_factory_.GetWeakPtr();
+
+ callback.Run(error, response.Pass(), blob_data_handle.Pass());
+ if (cache)
+ scheduler_->CompleteOperationAndRunNext();
+}
+
+void CacheStorageCache::PendingRequestsCallback(
+ const RequestsCallback& callback,
+ CacheStorageError error,
+ scoped_ptr<Requests> requests) {
+ base::WeakPtr<CacheStorageCache> cache = weak_ptr_factory_.GetWeakPtr();
+
+ callback.Run(error, requests.Pass());
+ if (cache)
+ scheduler_->CompleteOperationAndRunNext();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/cache_storage/cache_storage_cache.h b/chromium/content/browser/cache_storage/cache_storage_cache.h
new file mode 100644
index 00000000000..8e682eafe7e
--- /dev/null
+++ b/chromium/content/browser/cache_storage/cache_storage_cache.h
@@ -0,0 +1,226 @@
+// Copyright 2014 The Chromium Authors. 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_CACHE_STORAGE_CACHE_STORAGE_CACHE_H_
+#define CONTENT_BROWSER_CACHE_STORAGE_CACHE_STORAGE_CACHE_H_
+
+#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/common/cache_storage/cache_storage_types.h"
+#include "content/common/service_worker/service_worker_types.h"
+#include "net/disk_cache/disk_cache.h"
+
+namespace net {
+class URLRequestContext;
+class IOBufferWithSize;
+}
+
+namespace storage {
+class BlobDataHandle;
+class BlobStorageContext;
+class QuotaManagerProxy;
+}
+
+namespace content {
+
+class CacheMetadata;
+class CacheStorageScheduler;
+class TestCacheStorageCache;
+
+// Represents a ServiceWorker Cache as seen in
+// https://slightlyoff.github.io/ServiceWorker/spec/service_worker/
+// The asynchronous methods are executed serially. Callbacks to the
+// public functions will be called so long as the cache object lives.
+class CONTENT_EXPORT CacheStorageCache
+ : public base::RefCounted<CacheStorageCache> {
+ public:
+ using ErrorCallback = base::Callback<void(CacheStorageError)>;
+ using ResponseCallback =
+ base::Callback<void(CacheStorageError,
+ scoped_ptr<ServiceWorkerResponse>,
+ scoped_ptr<storage::BlobDataHandle>)>;
+ using Requests = std::vector<ServiceWorkerFetchRequest>;
+ using RequestsCallback =
+ base::Callback<void(CacheStorageError, scoped_ptr<Requests>)>;
+
+ static scoped_refptr<CacheStorageCache> 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<CacheStorageCache> 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 ERROR_TYPE_NOT_FOUND if not found.
+ void Match(scoped_ptr<ServiceWorkerFetchRequest> request,
+ const ResponseCallback& callback);
+
+ // Runs given batch operations. This corresponds to the Batch Cache Operations
+ // algorithm in the spec.
+ //
+ // |operations| cannot mix PUT and DELETE operations and cannot contain
+ // multiple DELETE operations.
+ //
+ // In the case of the PUT operation, puts request and response objects in the
+ // cache and returns OK when all operations are successfully completed.
+ // In the case of the DELETE operation, returns ERROR_NOT_FOUND if a specified
+ // entry is not found. Otherwise deletes it and returns OK.
+ //
+ // TODO(nhiroki): This function should run all operations atomically.
+ // http://crbug.com/486637
+ void BatchOperation(const std::vector<CacheStorageBatchOperation>& operations,
+ const ErrorCallback& callback);
+ void BatchDidOneOperation(const base::Closure& barrier_closure,
+ ErrorCallback* callback,
+ CacheStorageError error);
+ void BatchDidAllOperations(scoped_ptr<ErrorCallback> callback);
+
+ // TODO(jkarlin): Have keys take an optional ServiceWorkerFetchRequest.
+ // Returns CACHE_STORAGE_OK and a vector of requests if there are no errors.
+ void Keys(const RequestsCallback& callback);
+
+ // Closes the backend. Future operations that require the backend
+ // will exit early. Close should only be called once per CacheStorageCache.
+ void Close(const base::Closure& callback);
+
+ // The size of the cache contents in memory. Returns 0 if the cache backend is
+ // not a memory cache backend.
+ int64 MemoryBackedSize() const;
+
+ base::WeakPtr<CacheStorageCache> AsWeakPtr();
+
+ private:
+ friend class base::RefCounted<CacheStorageCache>;
+ friend class TestCacheStorageCache;
+
+ class BlobReader;
+ struct KeysContext;
+ struct MatchContext;
+ struct PutContext;
+
+ // The backend progresses from uninitialized, to open, to closed, and cannot
+ // reverse direction. The open step may be skipped.
+ enum BackendState {
+ BACKEND_UNINITIALIZED, // No backend, create backend on first operation.
+ BACKEND_OPEN, // Backend can be used.
+ BACKEND_CLOSED // Backend cannot be used. All ops should fail.
+ };
+
+ using Entries = std::vector<disk_cache::Entry*>;
+ using ScopedBackendPtr = scoped_ptr<disk_cache::Backend>;
+
+ CacheStorageCache(
+ 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);
+
+ // Async operations in progress will cancel and not run their callbacks.
+ virtual ~CacheStorageCache();
+
+ // Match callbacks
+ void MatchImpl(scoped_ptr<ServiceWorkerFetchRequest> request,
+ const ResponseCallback& callback);
+ void MatchDidOpenEntry(scoped_ptr<MatchContext> match_context, int rv);
+ void MatchDidReadMetadata(scoped_ptr<MatchContext> match_context,
+ scoped_ptr<CacheMetadata> headers);
+ void MatchDidReadResponseBodyData(scoped_ptr<MatchContext> match_context,
+ int rv);
+ void MatchDoneWithBody(scoped_ptr<MatchContext> match_context);
+
+ // 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 OK on
+ // success.
+ void Put(const CacheStorageBatchOperation& operation,
+ const ErrorCallback& callback);
+ void PutImpl(scoped_ptr<PutContext> put_context);
+ void PutDidDelete(scoped_ptr<PutContext> put_context,
+ CacheStorageError delete_error);
+ void PutDidCreateEntry(scoped_ptr<PutContext> put_context, int rv);
+ void PutDidWriteHeaders(scoped_ptr<PutContext> put_context,
+ int expected_bytes,
+ int rv);
+ void PutDidWriteBlobToCache(scoped_ptr<PutContext> put_context,
+ scoped_ptr<BlobReader> blob_reader,
+ disk_cache::ScopedEntryPtr entry,
+ bool success);
+
+ // Returns ERROR_NOT_FOUND if not found. Otherwise deletes and returns OK.
+ void Delete(const CacheStorageBatchOperation& operation,
+ const ErrorCallback& callback);
+ void DeleteImpl(scoped_ptr<ServiceWorkerFetchRequest> request,
+ const ErrorCallback& callback);
+ void DeleteDidOpenEntry(
+ const GURL& origin,
+ scoped_ptr<ServiceWorkerFetchRequest> request,
+ const CacheStorageCache::ErrorCallback& callback,
+ scoped_ptr<disk_cache::Entry*> entryptr,
+ const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
+ int rv);
+
+ // Keys callbacks.
+ void KeysImpl(const RequestsCallback& callback);
+ void KeysDidOpenNextEntry(scoped_ptr<KeysContext> keys_context, int rv);
+ void KeysProcessNextEntry(scoped_ptr<KeysContext> keys_context,
+ const Entries::iterator& iter);
+ void KeysDidReadMetadata(scoped_ptr<KeysContext> keys_context,
+ const Entries::iterator& iter,
+ scoped_ptr<CacheMetadata> metadata);
+
+ void CloseImpl(const base::Closure& callback);
+
+ // 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 CreateBackendDidCreate(const CacheStorageCache::ErrorCallback& callback,
+ scoped_ptr<ScopedBackendPtr> backend_ptr,
+ int rv);
+
+ void InitBackend();
+ void InitDone(CacheStorageError error);
+
+ void PendingClosure(const base::Closure& callback);
+ void PendingErrorCallback(const ErrorCallback& callback,
+ CacheStorageError error);
+ void PendingResponseCallback(
+ const ResponseCallback& callback,
+ CacheStorageError error,
+ scoped_ptr<ServiceWorkerResponse> response,
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle);
+ void PendingRequestsCallback(const RequestsCallback& callback,
+ CacheStorageError error,
+ scoped_ptr<Requests> requests);
+
+ // Be sure to check |backend_state_| 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_;
+ BackendState backend_state_;
+ scoped_ptr<CacheStorageScheduler> scheduler_;
+ bool initializing_;
+
+ // Whether or not to store data in disk or memory.
+ bool memory_only_;
+
+ base::WeakPtrFactory<CacheStorageCache> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(CacheStorageCache);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_CACHE_STORAGE_CACHE_STORAGE_CACHE_H_
diff --git a/chromium/content/browser/cache_storage/cache_storage_cache_unittest.cc b/chromium/content/browser/cache_storage/cache_storage_cache_unittest.cc
new file mode 100644
index 00000000000..57350d2cc27
--- /dev/null
+++ b/chromium/content/browser/cache_storage/cache_storage_cache_unittest.cc
@@ -0,0 +1,871 @@
+// Copyright 2014 The Chromium Authors. 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/cache_storage/cache_storage_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 "base/strings/string_split.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/cache_storage/cache_storage_types.h"
+#include "content/common/service_worker/service_worker_types.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/common/referrer.h"
+#include "content/public/test/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_builder.h"
+#include "storage/browser/blob/blob_data_handle.h"
+#include "storage/browser/blob/blob_data_snapshot.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 "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());
+}
+
+// A disk_cache::Backend wrapper that can delay operations.
+class DelayableBackend : public disk_cache::Backend {
+ public:
+ DelayableBackend(scoped_ptr<disk_cache::Backend> backend)
+ : backend_(backend.Pass()), delay_open_(false) {}
+
+ // disk_cache::Backend overrides
+ net::CacheType GetCacheType() const override {
+ return backend_->GetCacheType();
+ }
+ int32 GetEntryCount() const override { return backend_->GetEntryCount(); }
+ int OpenEntry(const std::string& key,
+ disk_cache::Entry** entry,
+ const CompletionCallback& callback) override {
+ if (delay_open_) {
+ open_entry_callback_ =
+ base::Bind(&DelayableBackend::OpenEntryDelayedImpl,
+ base::Unretained(this), key, entry, callback);
+ return net::ERR_IO_PENDING;
+ }
+
+ return backend_->OpenEntry(key, entry, callback);
+ }
+ int CreateEntry(const std::string& key,
+ disk_cache::Entry** entry,
+ const CompletionCallback& callback) override {
+ return backend_->CreateEntry(key, entry, callback);
+ }
+ int DoomEntry(const std::string& key,
+ const CompletionCallback& callback) override {
+ return backend_->DoomEntry(key, callback);
+ }
+ int DoomAllEntries(const CompletionCallback& callback) override {
+ return backend_->DoomAllEntries(callback);
+ }
+ int DoomEntriesBetween(base::Time initial_time,
+ base::Time end_time,
+ const CompletionCallback& callback) override {
+ return backend_->DoomEntriesBetween(initial_time, end_time, callback);
+ }
+ int DoomEntriesSince(base::Time initial_time,
+ const CompletionCallback& callback) override {
+ return backend_->DoomEntriesSince(initial_time, callback);
+ }
+ scoped_ptr<Iterator> CreateIterator() override {
+ return backend_->CreateIterator();
+ }
+ void GetStats(base::StringPairs* stats) override {
+ return backend_->GetStats(stats);
+ }
+ void OnExternalCacheHit(const std::string& key) override {
+ return backend_->OnExternalCacheHit(key);
+ }
+
+ // Call to continue a delayed open.
+ void OpenEntryContinue() {
+ EXPECT_FALSE(open_entry_callback_.is_null());
+ open_entry_callback_.Run();
+ }
+
+ void set_delay_open(bool value) { delay_open_ = value; }
+
+ private:
+ void OpenEntryDelayedImpl(const std::string& key,
+ disk_cache::Entry** entry,
+ const CompletionCallback& callback) {
+ int rv = backend_->OpenEntry(key, entry, callback);
+ if (rv != net::ERR_IO_PENDING)
+ callback.Run(rv);
+ }
+
+ scoped_ptr<disk_cache::Backend> backend_;
+ bool delay_open_;
+ base::Closure open_entry_callback_;
+};
+
+} // namespace
+
+// A CacheStorageCache that can optionally delay during backend creation.
+class TestCacheStorageCache : public CacheStorageCache {
+ public:
+ TestCacheStorageCache(
+ 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)
+ : CacheStorageCache(origin,
+ path,
+ request_context,
+ quota_manager_proxy,
+ blob_context),
+ delay_backend_creation_(false) {}
+
+ void CreateBackend(const ErrorCallback& callback) override {
+ backend_creation_callback_ = callback;
+ if (delay_backend_creation_)
+ return;
+ ContinueCreateBackend();
+ }
+
+ void ContinueCreateBackend() {
+ CacheStorageCache::CreateBackend(backend_creation_callback_);
+ }
+
+ void set_delay_backend_creation(bool delay) {
+ delay_backend_creation_ = delay;
+ }
+
+ // Swap the existing backend with a delayable one. The backend must have been
+ // created before calling this.
+ DelayableBackend* UseDelayableBackend() {
+ EXPECT_TRUE(backend_);
+ DelayableBackend* delayable_backend = new DelayableBackend(backend_.Pass());
+ backend_.reset(delayable_backend);
+ return delayable_backend;
+ }
+
+ private:
+ ~TestCacheStorageCache() override {}
+
+ bool delay_backend_creation_;
+ ErrorCallback backend_creation_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestCacheStorageCache);
+};
+
+class CacheStorageCacheTest : public testing::Test {
+ public:
+ CacheStorageCacheTest()
+ : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP),
+ callback_error_(CACHE_STORAGE_OK),
+ 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 TestCacheStorageCache(
+ 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, Referrer(), false);
+ no_body_request_ =
+ ServiceWorkerFetchRequest(GURL("http://example.com/no_body.html"),
+ "GET", headers, Referrer(), false);
+
+ std::string expected_response;
+ for (int i = 0; i < 100; ++i)
+ expected_blob_data_ += kTestData;
+
+ scoped_ptr<storage::BlobDataBuilder> blob_data(
+ new storage::BlobDataBuilder("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(), GURL());
+
+ no_body_response_ = ServiceWorkerResponse(
+ GURL("http://example.com/no_body.html"), 200, "OK",
+ blink::WebServiceWorkerResponseTypeDefault, headers, "", 0, GURL());
+ }
+
+ scoped_ptr<ServiceWorkerFetchRequest> CopyFetchRequest(
+ const ServiceWorkerFetchRequest& request) {
+ return make_scoped_ptr(new ServiceWorkerFetchRequest(
+ request.url, request.method, request.headers, request.referrer,
+ request.is_reload));
+ }
+
+ CacheStorageError BatchOperation(
+ const std::vector<CacheStorageBatchOperation>& operations) {
+ scoped_ptr<base::RunLoop> loop(new base::RunLoop());
+
+ cache_->BatchOperation(
+ operations,
+ base::Bind(&CacheStorageCacheTest::ErrorTypeCallback,
+ 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_;
+ }
+
+ bool Put(const ServiceWorkerFetchRequest& request,
+ const ServiceWorkerResponse& response) {
+ CacheStorageBatchOperation operation;
+ operation.operation_type = CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT;
+ operation.request = request;
+ operation.response = response;
+
+ CacheStorageError error =
+ BatchOperation(std::vector<CacheStorageBatchOperation>(1, operation));
+ return error == CACHE_STORAGE_OK;
+ }
+
+ bool Match(const ServiceWorkerFetchRequest& request) {
+ scoped_ptr<base::RunLoop> loop(new base::RunLoop());
+
+ cache_->Match(
+ CopyFetchRequest(request),
+ base::Bind(&CacheStorageCacheTest::ResponseAndErrorCallback,
+ base::Unretained(this), base::Unretained(loop.get())));
+ loop->Run();
+
+ return callback_error_ == CACHE_STORAGE_OK;
+ }
+
+ bool Delete(const ServiceWorkerFetchRequest& request) {
+ CacheStorageBatchOperation operation;
+ operation.operation_type = CACHE_STORAGE_CACHE_OPERATION_TYPE_DELETE;
+ operation.request = request;
+
+ CacheStorageError error =
+ BatchOperation(std::vector<CacheStorageBatchOperation>(1, operation));
+ return error == CACHE_STORAGE_OK;
+ }
+
+ bool Keys() {
+ scoped_ptr<base::RunLoop> loop(new base::RunLoop());
+
+ cache_->Keys(base::Bind(&CacheStorageCacheTest::RequestsCallback,
+ base::Unretained(this),
+ base::Unretained(loop.get())));
+ loop->Run();
+
+ return callback_error_ == CACHE_STORAGE_OK;
+ }
+
+ bool Close() {
+ scoped_ptr<base::RunLoop> loop(new base::RunLoop());
+
+ cache_->Close(base::Bind(&CacheStorageCacheTest::CloseCallback,
+ base::Unretained(this),
+ base::Unretained(loop.get())));
+ loop->Run();
+ return callback_closed_;
+ }
+
+ void RequestsCallback(base::RunLoop* run_loop,
+ CacheStorageError error,
+ scoped_ptr<CacheStorageCache::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, CacheStorageError error) {
+ callback_error_ = error;
+ if (run_loop)
+ run_loop->Quit();
+ }
+
+ void SequenceCallback(int sequence,
+ int* sequence_out,
+ base::RunLoop* run_loop,
+ CacheStorageError error) {
+ *sequence_out = sequence;
+ callback_error_ = error;
+ if (run_loop)
+ run_loop->Quit();
+ }
+
+ void ResponseAndErrorCallback(
+ base::RunLoop* run_loop,
+ CacheStorageError error,
+ scoped_ptr<ServiceWorkerResponse> response,
+ scoped_ptr<storage::BlobDataHandle> body_handle) {
+ callback_error_ = error;
+ callback_response_ = response.Pass();
+ callback_response_data_.reset();
+ if (error == CACHE_STORAGE_OK && !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) {
+ scoped_ptr<storage::BlobDataSnapshot> data = blob_handle->CreateSnapshot();
+ const auto& items = data->items();
+ for (const auto& item : items) {
+ output->append(item->bytes(), item->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<TestCacheStorageCache> 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_;
+
+ CacheStorageError callback_error_;
+ scoped_ptr<ServiceWorkerResponse> callback_response_;
+ scoped_ptr<storage::BlobDataHandle> callback_response_data_;
+ std::vector<std::string> callback_strings_;
+ bool callback_closed_;
+};
+
+class CacheStorageCacheTestP : public CacheStorageCacheTest,
+ public testing::WithParamInterface<bool> {
+ bool MemoryOnly() override { return !GetParam(); }
+};
+
+class CacheStorageCacheMemoryOnlyTest
+ : public CacheStorageCacheTest,
+ public testing::WithParamInterface<bool> {
+ bool MemoryOnly() override { return true; }
+};
+
+TEST_P(CacheStorageCacheTestP, PutNoBody) {
+ EXPECT_TRUE(Put(no_body_request_, no_body_response_));
+}
+
+TEST_P(CacheStorageCacheTestP, PutBody) {
+ EXPECT_TRUE(Put(body_request_, body_response_));
+}
+
+TEST_P(CacheStorageCacheTestP, PutBody_Multiple) {
+ CacheStorageBatchOperation operation1;
+ operation1.operation_type = CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT;
+ operation1.request = body_request_;
+ operation1.request.url = GURL("http://example.com/1");
+ operation1.response = body_response_;
+ operation1.response.url = GURL("http://example.com/1");
+
+ CacheStorageBatchOperation operation2;
+ operation2.operation_type = CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT;
+ operation2.request = body_request_;
+ operation2.request.url = GURL("http://example.com/2");
+ operation2.response = body_response_;
+ operation2.response.url = GURL("http://example.com/2");
+
+ CacheStorageBatchOperation operation3;
+ operation3.operation_type = CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT;
+ operation3.request = body_request_;
+ operation3.request.url = GURL("http://example.com/3");
+ operation3.response = body_response_;
+ operation3.response.url = GURL("http://example.com/3");
+
+ std::vector<CacheStorageBatchOperation> operations;
+ operations.push_back(operation1);
+ operations.push_back(operation2);
+ operations.push_back(operation3);
+
+ EXPECT_EQ(CACHE_STORAGE_OK, BatchOperation(operations));
+ EXPECT_TRUE(Match(operation1.request));
+ EXPECT_TRUE(Match(operation2.request));
+ EXPECT_TRUE(Match(operation3.request));
+}
+
+// TODO(nhiroki): Add a test for the case where one of PUT operations fails.
+// Currently there is no handy way to fail only one operation in a batch.
+// This could be easily achieved after adding some security checks in the
+// browser side (http://crbug.com/425505).
+
+TEST_P(CacheStorageCacheTestP, 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(CacheStorageCacheTestP, 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(CacheStorageCacheTest, PutBodyDropBlobRef) {
+ CacheStorageBatchOperation operation;
+ operation.operation_type = CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT;
+ operation.request = body_request_;
+ operation.response = body_response_;
+
+ scoped_ptr<base::RunLoop> loop(new base::RunLoop());
+ cache_->BatchOperation(
+ std::vector<CacheStorageBatchOperation>(1, operation),
+ base::Bind(&CacheStorageCacheTestP::ErrorTypeCallback,
+ 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(CACHE_STORAGE_OK, callback_error_);
+}
+
+TEST_P(CacheStorageCacheTestP, 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(CacheStorageCacheTestP, PutReplcaceInBatch) {
+ CacheStorageBatchOperation operation1;
+ operation1.operation_type = CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT;
+ operation1.request = body_request_;
+ operation1.response = no_body_response_;
+
+ CacheStorageBatchOperation operation2;
+ operation2.operation_type = CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT;
+ operation2.request = body_request_;
+ operation2.response = body_response_;
+
+ std::vector<CacheStorageBatchOperation> operations;
+ operations.push_back(operation1);
+ operations.push_back(operation2);
+
+ EXPECT_EQ(CACHE_STORAGE_OK, BatchOperation(operations));
+
+ // |operation2| should win.
+ EXPECT_TRUE(Match(operation2.request));
+ EXPECT_TRUE(callback_response_data_);
+}
+
+TEST_P(CacheStorageCacheTestP, 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(CacheStorageCacheTestP, 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(CacheStorageCacheTestP, 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(CacheStorageCacheTestP, 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(CacheStorageCacheTestP, 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(CacheStorageCacheTestP, 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(CacheStorageCacheTestP, 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(CacheStorageCacheTestP, VaryStar) {
+ body_response_.headers["vary"] = "*";
+ EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_FALSE(Match(body_request_));
+}
+
+TEST_P(CacheStorageCacheTestP, EmptyKeys) {
+ EXPECT_TRUE(Keys());
+ EXPECT_EQ(0u, callback_strings_.size());
+}
+
+TEST_P(CacheStorageCacheTestP, 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(CacheStorageCacheTestP, 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(CacheStorageCacheTestP, 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(CacheStorageCacheTestP, 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(CacheStorageCacheTestP, 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(CacheStorageCacheTestP, 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(CacheStorageCacheTestP, 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(CacheStorageCacheTest, CaselessServiceWorkerResponseHeaders) {
+ // CacheStorageCache 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, GURL());
+ response.headers["content-type"] = "foo";
+ response.headers["Content-Type"] = "bar";
+ EXPECT_EQ("bar", response.headers["content-type"]);
+}
+
+TEST_F(CacheStorageCacheTest, CaselessServiceWorkerFetchRequestHeaders) {
+ // CacheStorageCache depends on ServiceWorkerFetchRequest having caseless
+ // headers so that it can quickly lookup vary headers.
+ ServiceWorkerFetchRequest request(GURL("http://www.example.com"), "GET",
+ ServiceWorkerHeaderMap(), Referrer(),
+ false);
+ request.headers["content-type"] = "foo";
+ request.headers["Content-Type"] = "bar";
+ EXPECT_EQ("bar", request.headers["content-type"]);
+}
+
+TEST_P(CacheStorageCacheTestP, 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(CacheStorageCacheMemoryOnlyTest, 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(CacheStorageCacheTest, MemoryBackedSizePersistent) {
+ EXPECT_EQ(0, cache_->MemoryBackedSize());
+ EXPECT_TRUE(Put(no_body_request_, no_body_response_));
+ EXPECT_EQ(0, cache_->MemoryBackedSize());
+}
+
+TEST_P(CacheStorageCacheTestP, OpsFailOnClosedBackendNeverCreated) {
+ cache_->set_delay_backend_creation(
+ true); // Will hang the test if a backend is created.
+ EXPECT_TRUE(Close());
+ VerifyAllOpsFail();
+}
+
+TEST_P(CacheStorageCacheTestP, OpsFailOnClosedBackend) {
+ // Create the backend and put something in it.
+ EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Close());
+ VerifyAllOpsFail();
+}
+
+TEST_P(CacheStorageCacheTestP, VerifySerialScheduling) {
+ // Start two operations, the first one is delayed but the second isn't. The
+ // second should wait for the first.
+ EXPECT_TRUE(Keys()); // Opens the backend.
+ DelayableBackend* delayable_backend = cache_->UseDelayableBackend();
+ delayable_backend->set_delay_open(true);
+
+ int sequence_out = -1;
+
+ CacheStorageBatchOperation operation1;
+ operation1.operation_type = CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT;
+ operation1.request = body_request_;
+ operation1.response = body_response_;
+
+ scoped_ptr<base::RunLoop> close_loop1(new base::RunLoop());
+ cache_->BatchOperation(
+ std::vector<CacheStorageBatchOperation>(1, operation1),
+ base::Bind(&CacheStorageCacheTest::SequenceCallback,
+ base::Unretained(this), 1, &sequence_out, close_loop1.get()));
+
+ // Blocks on opening the cache entry.
+ base::RunLoop().RunUntilIdle();
+
+ CacheStorageBatchOperation operation2;
+ operation2.operation_type = CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT;
+ operation2.request = body_request_;
+ operation2.response = body_response_;
+
+ delayable_backend->set_delay_open(false);
+ scoped_ptr<base::RunLoop> close_loop2(new base::RunLoop());
+ cache_->BatchOperation(
+ std::vector<CacheStorageBatchOperation>(1, operation2),
+ base::Bind(&CacheStorageCacheTest::SequenceCallback,
+ base::Unretained(this), 2, &sequence_out, close_loop2.get()));
+
+ // The second put operation should wait for the first to complete.
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(callback_response_);
+
+ delayable_backend->OpenEntryContinue();
+ close_loop1->Run();
+ EXPECT_EQ(1, sequence_out);
+ close_loop2->Run();
+ EXPECT_EQ(2, sequence_out);
+}
+
+INSTANTIATE_TEST_CASE_P(CacheStorageCacheTest,
+ CacheStorageCacheTestP,
+ ::testing::Values(false, true));
+
+} // namespace content
diff --git a/chromium/content/browser/cache_storage/cache_storage_context_impl.cc b/chromium/content/browser/cache_storage/cache_storage_context_impl.cc
new file mode 100644
index 00000000000..7e43070909d
--- /dev/null
+++ b/chromium/content/browser/cache_storage/cache_storage_context_impl.cc
@@ -0,0 +1,104 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/cache_storage/cache_storage_context_impl.h"
+
+#include "base/bind.h"
+#include "base/files/file_path.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "content/browser/cache_storage/cache_storage_manager.h"
+#include "content/browser/fileapi/chrome_blob_storage_context.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_thread.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 {
+
+CacheStorageContextImpl::CacheStorageContextImpl(
+ BrowserContext* browser_context) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+}
+
+CacheStorageContextImpl::~CacheStorageContextImpl() {
+}
+
+void CacheStorageContextImpl::Init(
+ const base::FilePath& user_data_directory,
+ storage::QuotaManagerProxy* quota_manager_proxy,
+ storage::SpecialStoragePolicy* special_storage_policy) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ is_incognito_ = user_data_directory.empty();
+ base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool();
+ scoped_refptr<base::SequencedTaskRunner> cache_task_runner =
+ pool->GetSequencedTaskRunnerWithShutdownBehavior(
+ BrowserThread::GetBlockingPool()->GetSequenceToken(),
+ base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
+
+ // This thread-hopping antipattern is needed here for some unit tests, where
+ // browser threads are collapsed the quota manager is initialized before the
+ // posted task can register the quota client.
+ // TODO: Fix the tests to let the quota manager initialize normally.
+ if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
+ CreateCacheStorageManager(user_data_directory, cache_task_runner,
+ quota_manager_proxy, special_storage_policy);
+ return;
+ }
+
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&CacheStorageContextImpl::CreateCacheStorageManager, this,
+ user_data_directory, cache_task_runner,
+ make_scoped_refptr(quota_manager_proxy),
+ make_scoped_refptr(special_storage_policy)));
+}
+
+void CacheStorageContextImpl::Shutdown() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&CacheStorageContextImpl::ShutdownOnIO, this));
+}
+
+CacheStorageManager* CacheStorageContextImpl::cache_manager() const {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ return cache_manager_.get();
+}
+
+void CacheStorageContextImpl::SetBlobParametersForCache(
+ net::URLRequestContextGetter* request_context,
+ ChromeBlobStorageContext* blob_storage_context) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (cache_manager_ && request_context && blob_storage_context) {
+ cache_manager_->SetBlobParametersForCache(
+ request_context->GetURLRequestContext(),
+ blob_storage_context->context()->AsWeakPtr());
+ }
+}
+
+void CacheStorageContextImpl::CreateCacheStorageManager(
+ const base::FilePath& user_data_directory,
+ const scoped_refptr<base::SequencedTaskRunner>& cache_task_runner,
+ storage::QuotaManagerProxy* quota_manager_proxy,
+ storage::SpecialStoragePolicy* special_storage_policy) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ DCHECK(!cache_manager_);
+ cache_manager_ =
+ CacheStorageManager::Create(user_data_directory, cache_task_runner.get(),
+ make_scoped_refptr(quota_manager_proxy));
+}
+
+void CacheStorageContextImpl::ShutdownOnIO() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ cache_manager_.reset();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/cache_storage/cache_storage_context_impl.h b/chromium/content/browser/cache_storage/cache_storage_context_impl.h
new file mode 100644
index 00000000000..2944a409087
--- /dev/null
+++ b/chromium/content/browser/cache_storage/cache_storage_context_impl.h
@@ -0,0 +1,87 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_CACHE_STORAGE_CACHE_STORAGE_CONTEXT_IMPL_H_
+#define CONTENT_BROWSER_CACHE_STORAGE_CACHE_STORAGE_CONTEXT_IMPL_H_
+
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/common/content_export.h"
+
+namespace base {
+class FilePath;
+class SequencedTaskRunner;
+}
+
+namespace net {
+class URLRequestContextGetter;
+}
+
+namespace storage {
+class QuotaManagerProxy;
+class SpecialStoragePolicy;
+}
+
+namespace content {
+
+class BrowserContext;
+class ChromeBlobStorageContext;
+class CacheStorageManager;
+
+// One instance of this exists per StoragePartition, and services multiple
+// child processes/origins. Most logic is delegated to the owned
+// CacheStorageManager instance, which is only accessed on the IO
+// thread.
+// TODO(jsbell): Derive from a public CacheStorageContext. crbug.com/466371
+class CONTENT_EXPORT CacheStorageContextImpl
+ : public base::RefCountedThreadSafe<CacheStorageContextImpl> {
+ public:
+ explicit CacheStorageContextImpl(BrowserContext* browser_context);
+
+ // Init and Shutdown are for use on the UI thread when the profile,
+ // storagepartition is being setup and torn down.
+ void Init(const base::FilePath& user_data_directory,
+ storage::QuotaManagerProxy* quota_manager_proxy,
+ storage::SpecialStoragePolicy* special_storage_policy);
+ void Shutdown();
+
+ // Only callable on the IO thread.
+ CacheStorageManager* cache_manager() const;
+
+ 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 CacheStorageCache operations.
+ // It must be called on the IO thread. If either parameter is NULL the
+ // function immediately returns without forwarding to the
+ // CacheStorageManager.
+ void SetBlobParametersForCache(
+ net::URLRequestContextGetter* request_context,
+ ChromeBlobStorageContext* blob_storage_context);
+
+ private:
+ friend class base::RefCountedThreadSafe<CacheStorageContextImpl>;
+
+ ~CacheStorageContextImpl();
+
+ void CreateCacheStorageManager(
+ const base::FilePath& user_data_directory,
+ const scoped_refptr<base::SequencedTaskRunner>& cache_task_runner,
+ storage::QuotaManagerProxy* quota_manager_proxy,
+ storage::SpecialStoragePolicy* special_storage_policy);
+
+ void ShutdownOnIO();
+
+ // Initialized in Init(); true if the user data directory is empty.
+ bool is_incognito_ = false;
+
+ // Only accessed on the IO thread.
+ scoped_ptr<CacheStorageManager> cache_manager_;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_CACHE_STORAGE_CACHE_STORAGE_CONTEXT_IMPL_H_
diff --git a/chromium/content/browser/cache_storage/cache_storage_dispatcher_host.cc b/chromium/content/browser/cache_storage/cache_storage_dispatcher_host.cc
new file mode 100644
index 00000000000..f8630f6ce7b
--- /dev/null
+++ b/chromium/content/browser/cache_storage/cache_storage_dispatcher_host.cc
@@ -0,0 +1,433 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/cache_storage/cache_storage_dispatcher_host.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/trace_event/trace_event.h"
+#include "content/browser/cache_storage/cache_storage_cache.h"
+#include "content/browser/cache_storage/cache_storage_context_impl.h"
+#include "content/browser/cache_storage/cache_storage_manager.h"
+#include "content/common/cache_storage/cache_storage_messages.h"
+#include "content/public/browser/content_browser_client.h"
+#include "storage/browser/blob/blob_data_handle.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerCacheError.h"
+
+namespace content {
+
+namespace {
+
+const uint32 kFilteredMessageClasses[] = {CacheStorageMsgStart};
+
+blink::WebServiceWorkerCacheError ToWebServiceWorkerCacheError(
+ CacheStorageError err) {
+ switch (err) {
+ case CACHE_STORAGE_OK:
+ NOTREACHED();
+ return blink::WebServiceWorkerCacheErrorNotImplemented;
+ case CACHE_STORAGE_ERROR_EXISTS:
+ return blink::WebServiceWorkerCacheErrorExists;
+ case CACHE_STORAGE_ERROR_STORAGE:
+ // TODO(nhiroki): Add WebServiceWorkerCacheError equivalent to
+ // CACHE_STORAGE_ERROR_STORAGE.
+ return blink::WebServiceWorkerCacheErrorNotFound;
+ case CACHE_STORAGE_ERROR_NOT_FOUND:
+ return blink::WebServiceWorkerCacheErrorNotFound;
+ }
+ NOTREACHED();
+ return blink::WebServiceWorkerCacheErrorNotImplemented;
+}
+
+} // namespace
+
+CacheStorageDispatcherHost::CacheStorageDispatcherHost()
+ : BrowserMessageFilter(kFilteredMessageClasses,
+ arraysize(kFilteredMessageClasses)) {
+}
+
+CacheStorageDispatcherHost::~CacheStorageDispatcherHost() {
+}
+
+void CacheStorageDispatcherHost::Init(CacheStorageContextImpl* context) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&CacheStorageDispatcherHost::CreateCacheListener, this,
+ make_scoped_refptr(context)));
+}
+
+void CacheStorageDispatcherHost::OnDestruct() const {
+ BrowserThread::DeleteOnIOThread::Destruct(this);
+}
+
+bool CacheStorageDispatcherHost::OnMessageReceived(
+ const IPC::Message& message) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(CacheStorageDispatcherHost, message)
+ IPC_MESSAGE_HANDLER(CacheStorageHostMsg_CacheStorageHas, OnCacheStorageHas)
+ IPC_MESSAGE_HANDLER(CacheStorageHostMsg_CacheStorageOpen, OnCacheStorageOpen)
+ IPC_MESSAGE_HANDLER(CacheStorageHostMsg_CacheStorageDelete,
+ OnCacheStorageDelete)
+ IPC_MESSAGE_HANDLER(CacheStorageHostMsg_CacheStorageKeys, OnCacheStorageKeys)
+ IPC_MESSAGE_HANDLER(CacheStorageHostMsg_CacheStorageMatch,
+ OnCacheStorageMatch)
+ IPC_MESSAGE_HANDLER(CacheStorageHostMsg_CacheMatch, OnCacheMatch)
+ IPC_MESSAGE_HANDLER(CacheStorageHostMsg_CacheMatchAll, OnCacheMatchAll)
+ IPC_MESSAGE_HANDLER(CacheStorageHostMsg_CacheKeys, OnCacheKeys)
+ IPC_MESSAGE_HANDLER(CacheStorageHostMsg_CacheBatch, OnCacheBatch)
+ IPC_MESSAGE_HANDLER(CacheStorageHostMsg_CacheClosed, OnCacheClosed)
+ IPC_MESSAGE_HANDLER(CacheStorageHostMsg_BlobDataHandled, OnBlobDataHandled)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+
+ if (!handled)
+ BadMessageReceived();
+ return handled;
+}
+
+void CacheStorageDispatcherHost::CreateCacheListener(
+ CacheStorageContextImpl* context) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ context_ = context;
+}
+
+void CacheStorageDispatcherHost::OnCacheStorageHas(
+ int thread_id,
+ int request_id,
+ const GURL& origin,
+ const base::string16& cache_name) {
+ TRACE_EVENT0("CacheStorage", "CacheStorageDispatcherHost::OnCacheStorageHas");
+ context_->cache_manager()->HasCache(
+ origin, base::UTF16ToUTF8(cache_name),
+ base::Bind(&CacheStorageDispatcherHost::OnCacheStorageHasCallback, this,
+ thread_id, request_id));
+}
+
+void CacheStorageDispatcherHost::OnCacheStorageOpen(
+ int thread_id,
+ int request_id,
+ const GURL& origin,
+ const base::string16& cache_name) {
+ TRACE_EVENT0("CacheStorage",
+ "CacheStorageDispatcherHost::OnCacheStorageOpen");
+ context_->cache_manager()->OpenCache(
+ origin, base::UTF16ToUTF8(cache_name),
+ base::Bind(&CacheStorageDispatcherHost::OnCacheStorageOpenCallback, this,
+ thread_id, request_id));
+}
+
+void CacheStorageDispatcherHost::OnCacheStorageDelete(
+ int thread_id,
+ int request_id,
+ const GURL& origin,
+ const base::string16& cache_name) {
+ TRACE_EVENT0("CacheStorage",
+ "CacheStorageDispatcherHost::OnCacheStorageDelete");
+ context_->cache_manager()->DeleteCache(
+ origin, base::UTF16ToUTF8(cache_name),
+ base::Bind(&CacheStorageDispatcherHost::OnCacheStorageDeleteCallback,
+ this, thread_id, request_id));
+}
+
+void CacheStorageDispatcherHost::OnCacheStorageKeys(int thread_id,
+ int request_id,
+ const GURL& origin) {
+ TRACE_EVENT0("CacheStorage",
+ "CacheStorageDispatcherHost::OnCacheStorageKeys");
+ context_->cache_manager()->EnumerateCaches(
+ origin,
+ base::Bind(&CacheStorageDispatcherHost::OnCacheStorageKeysCallback, this,
+ thread_id, request_id));
+}
+
+void CacheStorageDispatcherHost::OnCacheStorageMatch(
+ int thread_id,
+ int request_id,
+ const GURL& origin,
+ const ServiceWorkerFetchRequest& request,
+ const CacheStorageCacheQueryParams& match_params) {
+ TRACE_EVENT0("CacheStorage",
+ "CacheStorageDispatcherHost::OnCacheStorageMatch");
+
+ scoped_ptr<ServiceWorkerFetchRequest> scoped_request(
+ new ServiceWorkerFetchRequest(request.url, request.method,
+ request.headers, request.referrer,
+ request.is_reload));
+
+ if (match_params.cache_name.empty()) {
+ context_->cache_manager()->MatchAllCaches(
+ origin, scoped_request.Pass(),
+ base::Bind(&CacheStorageDispatcherHost::OnCacheStorageMatchCallback,
+ this, thread_id, request_id));
+ return;
+ }
+ context_->cache_manager()->MatchCache(
+ origin, base::UTF16ToUTF8(match_params.cache_name), scoped_request.Pass(),
+ base::Bind(&CacheStorageDispatcherHost::OnCacheStorageMatchCallback, this,
+ thread_id, request_id));
+}
+
+void CacheStorageDispatcherHost::OnCacheMatch(
+ int thread_id,
+ int request_id,
+ int cache_id,
+ const ServiceWorkerFetchRequest& request,
+ const CacheStorageCacheQueryParams& match_params) {
+ IDToCacheMap::iterator it = id_to_cache_map_.find(cache_id);
+ if (it == id_to_cache_map_.end()) {
+ Send(new CacheStorageMsg_CacheMatchError(
+ thread_id, request_id, blink::WebServiceWorkerCacheErrorNotFound));
+ return;
+ }
+
+ scoped_refptr<CacheStorageCache> 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(&CacheStorageDispatcherHost::OnCacheMatchCallback,
+ this, thread_id, request_id, cache));
+}
+
+void CacheStorageDispatcherHost::OnCacheMatchAll(
+ int thread_id,
+ int request_id,
+ int cache_id,
+ const ServiceWorkerFetchRequest& request,
+ const CacheStorageCacheQueryParams& match_params) {
+ // TODO(gavinp,jkarlin): Implement this method.
+ Send(new CacheStorageMsg_CacheMatchAllError(
+ thread_id, request_id, blink::WebServiceWorkerCacheErrorNotImplemented));
+}
+
+void CacheStorageDispatcherHost::OnCacheKeys(
+ int thread_id,
+ int request_id,
+ int cache_id,
+ const ServiceWorkerFetchRequest& request,
+ const CacheStorageCacheQueryParams& match_params) {
+ IDToCacheMap::iterator it = id_to_cache_map_.find(cache_id);
+ if (it == id_to_cache_map_.end()) {
+ Send(new CacheStorageMsg_CacheKeysError(
+ thread_id, request_id, blink::WebServiceWorkerCacheErrorNotFound));
+ return;
+ }
+
+ scoped_refptr<CacheStorageCache> cache = it->second;
+
+ cache->Keys(base::Bind(&CacheStorageDispatcherHost::OnCacheKeysCallback, this,
+ thread_id, request_id, cache));
+}
+
+void CacheStorageDispatcherHost::OnCacheBatch(
+ int thread_id,
+ int request_id,
+ int cache_id,
+ const std::vector<CacheStorageBatchOperation>& operations) {
+ if (operations.size() != 1u) {
+ Send(new CacheStorageMsg_CacheBatchError(
+ thread_id, request_id,
+ blink::WebServiceWorkerCacheErrorNotImplemented));
+ return;
+ }
+
+ IDToCacheMap::iterator it = id_to_cache_map_.find(cache_id);
+ if (it == id_to_cache_map_.end()) {
+ Send(new CacheStorageMsg_CacheBatchError(
+ thread_id, request_id, blink::WebServiceWorkerCacheErrorNotFound));
+ return;
+ }
+ scoped_refptr<CacheStorageCache> cache = it->second;
+ cache->BatchOperation(
+ operations, base::Bind(&CacheStorageDispatcherHost::OnCacheBatchCallback,
+ this, thread_id, request_id, cache));
+}
+
+void CacheStorageDispatcherHost::OnCacheClosed(int cache_id) {
+ DropCacheReference(cache_id);
+}
+
+void CacheStorageDispatcherHost::OnBlobDataHandled(const std::string& uuid) {
+ DropBlobDataHandle(uuid);
+}
+
+void CacheStorageDispatcherHost::OnCacheStorageHasCallback(
+ int thread_id,
+ int request_id,
+ bool has_cache,
+ CacheStorageError error) {
+ if (error != CACHE_STORAGE_OK) {
+ Send(new CacheStorageMsg_CacheStorageHasError(
+ thread_id, request_id, ToWebServiceWorkerCacheError(error)));
+ return;
+ }
+ if (!has_cache) {
+ Send(new CacheStorageMsg_CacheStorageHasError(
+ thread_id, request_id, blink::WebServiceWorkerCacheErrorNotFound));
+ return;
+ }
+ Send(new CacheStorageMsg_CacheStorageHasSuccess(thread_id, request_id));
+}
+
+void CacheStorageDispatcherHost::OnCacheStorageOpenCallback(
+ int thread_id,
+ int request_id,
+ const scoped_refptr<CacheStorageCache>& cache,
+ CacheStorageError error) {
+ if (error != CACHE_STORAGE_OK) {
+ Send(new CacheStorageMsg_CacheStorageOpenError(
+ thread_id, request_id, ToWebServiceWorkerCacheError(error)));
+ return;
+ }
+ CacheID cache_id = StoreCacheReference(cache);
+ Send(new CacheStorageMsg_CacheStorageOpenSuccess(thread_id, request_id,
+ cache_id));
+}
+
+void CacheStorageDispatcherHost::OnCacheStorageDeleteCallback(
+ int thread_id,
+ int request_id,
+ bool deleted,
+ CacheStorageError error) {
+ if (!deleted || error != CACHE_STORAGE_OK) {
+ Send(new CacheStorageMsg_CacheStorageDeleteError(
+ thread_id, request_id, ToWebServiceWorkerCacheError(error)));
+ return;
+ }
+ Send(new CacheStorageMsg_CacheStorageDeleteSuccess(thread_id, request_id));
+}
+
+void CacheStorageDispatcherHost::OnCacheStorageKeysCallback(
+ int thread_id,
+ int request_id,
+ const std::vector<std::string>& strings,
+ CacheStorageError error) {
+ if (error != CACHE_STORAGE_OK) {
+ Send(new CacheStorageMsg_CacheStorageKeysError(
+ thread_id, 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(new CacheStorageMsg_CacheStorageKeysSuccess(thread_id, request_id,
+ string16s));
+}
+
+void CacheStorageDispatcherHost::OnCacheStorageMatchCallback(
+ int thread_id,
+ int request_id,
+ CacheStorageError error,
+ scoped_ptr<ServiceWorkerResponse> response,
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle) {
+ if (error != CACHE_STORAGE_OK) {
+ Send(new CacheStorageMsg_CacheStorageMatchError(
+ thread_id, request_id, ToWebServiceWorkerCacheError(error)));
+ return;
+ }
+
+ if (blob_data_handle)
+ StoreBlobDataHandle(blob_data_handle.Pass());
+
+ Send(new CacheStorageMsg_CacheStorageMatchSuccess(thread_id, request_id,
+ *response));
+}
+
+void CacheStorageDispatcherHost::OnCacheMatchCallback(
+ int thread_id,
+ int request_id,
+ const scoped_refptr<CacheStorageCache>& cache,
+ CacheStorageError error,
+ scoped_ptr<ServiceWorkerResponse> response,
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle) {
+ if (error != CACHE_STORAGE_OK) {
+ Send(new CacheStorageMsg_CacheMatchError(
+ thread_id, request_id, ToWebServiceWorkerCacheError(error)));
+ return;
+ }
+
+ if (blob_data_handle)
+ StoreBlobDataHandle(blob_data_handle.Pass());
+
+ Send(new CacheStorageMsg_CacheMatchSuccess(thread_id, request_id, *response));
+}
+
+void CacheStorageDispatcherHost::OnCacheKeysCallback(
+ int thread_id,
+ int request_id,
+ const scoped_refptr<CacheStorageCache>& cache,
+ CacheStorageError error,
+ scoped_ptr<CacheStorageCache::Requests> requests) {
+ if (error != CACHE_STORAGE_OK) {
+ Send(new CacheStorageMsg_CacheKeysError(
+ thread_id, request_id, ToWebServiceWorkerCacheError(error)));
+ return;
+ }
+
+ CacheStorageCache::Requests out;
+
+ for (CacheStorageCache::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(new CacheStorageMsg_CacheKeysSuccess(thread_id, request_id, out));
+}
+
+void CacheStorageDispatcherHost::OnCacheBatchCallback(
+ int thread_id,
+ int request_id,
+ const scoped_refptr<CacheStorageCache>& cache,
+ CacheStorageError error) {
+ if (error != CACHE_STORAGE_OK) {
+ Send(new CacheStorageMsg_CacheBatchError(
+ thread_id, request_id, ToWebServiceWorkerCacheError(error)));
+ return;
+ }
+
+ Send(new CacheStorageMsg_CacheBatchSuccess(thread_id, request_id));
+}
+
+CacheStorageDispatcherHost::CacheID
+CacheStorageDispatcherHost::StoreCacheReference(
+ const scoped_refptr<CacheStorageCache>& cache) {
+ int cache_id = next_cache_id_++;
+ id_to_cache_map_[cache_id] = cache;
+ return cache_id;
+}
+
+void CacheStorageDispatcherHost::DropCacheReference(CacheID cache_id) {
+ id_to_cache_map_.erase(cache_id);
+}
+
+void CacheStorageDispatcherHost::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 CacheStorageDispatcherHost::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/cache_storage/cache_storage_dispatcher_host.h b/chromium/content/browser/cache_storage/cache_storage_dispatcher_host.h
new file mode 100644
index 00000000000..8691a9cfde9
--- /dev/null
+++ b/chromium/content/browser/cache_storage/cache_storage_dispatcher_host.h
@@ -0,0 +1,155 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_CACHE_STORAGE_CACHE_STORAGE_DISPATCHER_HOST_H_
+#define CONTENT_BROWSER_CACHE_STORAGE_CACHE_STORAGE_DISPATCHER_HOST_H_
+
+#include <list>
+
+#include "content/browser/cache_storage/cache_storage.h"
+#include "content/public/browser/browser_message_filter.h"
+
+namespace content {
+
+class CacheStorageContextImpl;
+
+// Handles Cache Storage related messages sent to the browser process from
+// child processes. One host instance exists per child process. All
+// messages are processed on the IO thread.
+class CONTENT_EXPORT CacheStorageDispatcherHost : public BrowserMessageFilter {
+ public:
+ CacheStorageDispatcherHost();
+
+ // Runs on UI thread.
+ void Init(CacheStorageContextImpl* context);
+
+ // BrowserMessageFilter implementation
+ void OnDestruct() const override;
+ bool OnMessageReceived(const IPC::Message& message) override;
+
+ private:
+ // Friends to allow OnDestruct() delegation
+ friend class BrowserThread;
+ friend class base::DeleteHelper<CacheStorageDispatcherHost>;
+
+ typedef int32_t CacheID; // TODO(jkarlin): Bump to 64 bit.
+ typedef std::map<CacheID, scoped_refptr<CacheStorageCache>> IDToCacheMap;
+ typedef std::map<std::string, std::list<storage::BlobDataHandle>>
+ UUIDToBlobDataHandleList;
+
+ ~CacheStorageDispatcherHost() override;
+
+ // Called by Init() on IO thread.
+ void CreateCacheListener(CacheStorageContextImpl* context);
+
+ // The message receiver functions for the CacheStorage API:
+ void OnCacheStorageHas(int thread_id,
+ int request_id,
+ const GURL& origin,
+ const base::string16& cache_name);
+ void OnCacheStorageOpen(int thread_id,
+ int request_id,
+ const GURL& origin,
+ const base::string16& cache_name);
+ void OnCacheStorageDelete(int thread_id,
+ int request_id,
+ const GURL& origin,
+ const base::string16& cache_name);
+ void OnCacheStorageKeys(int thread_id, int request_id, const GURL& origin);
+ void OnCacheStorageMatch(int thread_id,
+ int request_id,
+ const GURL& origin,
+ const ServiceWorkerFetchRequest& request,
+ const CacheStorageCacheQueryParams& match_params);
+
+ // The message receiver functions for the Cache API:
+ void OnCacheMatch(int thread_id,
+ int request_id,
+ int cache_id,
+ const ServiceWorkerFetchRequest& request,
+ const CacheStorageCacheQueryParams& match_params);
+ void OnCacheKeys(int thread_id,
+ int request_id,
+ int cache_id,
+ const ServiceWorkerFetchRequest& request,
+ const CacheStorageCacheQueryParams& match_params);
+ void OnCacheBatch(int thread_id,
+ int request_id,
+ int cache_id,
+ const std::vector<CacheStorageBatchOperation>& operations);
+ void OnCacheClosed(int cache_id);
+ void OnBlobDataHandled(const std::string& uuid);
+
+ // CacheStorageManager callbacks
+ void OnCacheStorageHasCallback(int thread_id,
+ int request_id,
+ bool has_cache,
+ CacheStorageError error);
+ void OnCacheStorageOpenCallback(int thread_id,
+ int request_id,
+ const scoped_refptr<CacheStorageCache>& cache,
+ CacheStorageError error);
+ void OnCacheStorageDeleteCallback(int thread_id,
+ int request_id,
+ bool deleted,
+ CacheStorageError error);
+ void OnCacheStorageKeysCallback(int thread_id,
+ int request_id,
+ const std::vector<std::string>& strings,
+ CacheStorageError error);
+ void OnCacheStorageMatchCallback(
+ int thread_id,
+ int request_id,
+ CacheStorageError error,
+ scoped_ptr<ServiceWorkerResponse> response,
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle);
+
+ // Cache callbacks.
+ void OnCacheMatchCallback(
+ int thread_id,
+ int request_id,
+ const scoped_refptr<CacheStorageCache>& cache,
+ CacheStorageError error,
+ scoped_ptr<ServiceWorkerResponse> response,
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle);
+ void OnCacheMatchAll(int thread_id,
+ int request_id,
+ int cache_id,
+ const ServiceWorkerFetchRequest& request,
+ const CacheStorageCacheQueryParams& match_params);
+ void OnCacheKeysCallback(int thread_id,
+ int request_id,
+ const scoped_refptr<CacheStorageCache>& cache,
+ CacheStorageError error,
+ scoped_ptr<CacheStorageCache::Requests> requests);
+ void OnCacheBatchCallback(int thread_id,
+ int request_id,
+ const scoped_refptr<CacheStorageCache>& cache,
+ CacheStorageError error);
+
+ // Hangs onto a scoped_refptr for the cache if it isn't already doing so.
+ // Returns a unique cache_id. Call DropCacheReference when the client is done
+ // with this cache.
+ CacheID StoreCacheReference(const scoped_refptr<CacheStorageCache>& cache);
+ 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);
+
+ IDToCacheMap id_to_cache_map_;
+ CacheID next_cache_id_ = 0;
+
+ UUIDToBlobDataHandleList blob_handle_store_;
+
+ scoped_refptr<CacheStorageContextImpl> context_;
+
+ DISALLOW_COPY_AND_ASSIGN(CacheStorageDispatcherHost);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_CACHE_STORAGE_CACHE_STORAGE_DISPATCHER_HOST_H_
diff --git a/chromium/content/browser/cache_storage/cache_storage_manager.cc b/chromium/content/browser/cache_storage/cache_storage_manager.cc
new file mode 100644
index 00000000000..9b56c07954c
--- /dev/null
+++ b/chromium/content/browser/cache_storage/cache_storage_manager.cc
@@ -0,0 +1,364 @@
+// Copyright 2014 The Chromium Authors. 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/cache_storage/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/cache_storage/cache_storage.h"
+#include "content/browser/cache_storage/cache_storage.pb.h"
+#include "content/browser/cache_storage/cache_storage_quota_client.h"
+#include "content/browser/service_worker/service_worker_context_core.h"
+#include "content/public/browser/browser_thread.h"
+#include "net/base/net_util.h"
+#include "storage/browser/quota/quota_manager_proxy.h"
+#include "storage/common/database/database_identifier.h"
+#include "storage/common/quota/quota_status_code.h"
+#include "url/gurl.h"
+
+namespace content {
+
+namespace {
+
+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(CacheStorage::kIndexFileName),
+ &protobuf);
+
+ CacheStorageIndex 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<CacheStorageManager> CacheStorageManager::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 CacheStorageManager(root_path, cache_task_runner,
+ quota_manager_proxy));
+}
+
+// static
+scoped_ptr<CacheStorageManager> CacheStorageManager::Create(
+ CacheStorageManager* old_manager) {
+ scoped_ptr<CacheStorageManager> manager(new CacheStorageManager(
+ 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();
+}
+
+CacheStorageManager::~CacheStorageManager() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ for (CacheStorageMap::iterator it = cache_storage_map_.begin();
+ it != cache_storage_map_.end(); ++it) {
+ delete it->second;
+ }
+}
+
+void CacheStorageManager::OpenCache(
+ const GURL& origin,
+ const std::string& cache_name,
+ const CacheStorage::CacheAndErrorCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ CacheStorage* cache_storage = FindOrCreateCacheStorage(origin);
+
+ cache_storage->OpenCache(cache_name, callback);
+}
+
+void CacheStorageManager::HasCache(
+ const GURL& origin,
+ const std::string& cache_name,
+ const CacheStorage::BoolAndErrorCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ CacheStorage* cache_storage = FindOrCreateCacheStorage(origin);
+ cache_storage->HasCache(cache_name, callback);
+}
+
+void CacheStorageManager::DeleteCache(
+ const GURL& origin,
+ const std::string& cache_name,
+ const CacheStorage::BoolAndErrorCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ CacheStorage* cache_storage = FindOrCreateCacheStorage(origin);
+ cache_storage->DeleteCache(cache_name, callback);
+}
+
+void CacheStorageManager::EnumerateCaches(
+ const GURL& origin,
+ const CacheStorage::StringsAndErrorCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ CacheStorage* cache_storage = FindOrCreateCacheStorage(origin);
+
+ cache_storage->EnumerateCaches(callback);
+}
+
+void CacheStorageManager::MatchCache(
+ const GURL& origin,
+ const std::string& cache_name,
+ scoped_ptr<ServiceWorkerFetchRequest> request,
+ const CacheStorageCache::ResponseCallback& callback) {
+ CacheStorage* cache_storage = FindOrCreateCacheStorage(origin);
+
+ cache_storage->MatchCache(cache_name, request.Pass(), callback);
+}
+
+void CacheStorageManager::MatchAllCaches(
+ const GURL& origin,
+ scoped_ptr<ServiceWorkerFetchRequest> request,
+ const CacheStorageCache::ResponseCallback& callback) {
+ CacheStorage* cache_storage = FindOrCreateCacheStorage(origin);
+
+ cache_storage->MatchAllCaches(request.Pass(), callback);
+}
+
+void CacheStorageManager::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 CacheStorageManager::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;
+ }
+
+ MigrateOrigin(origin_url);
+ PostTaskAndReplyWithResult(
+ cache_task_runner_.get(), FROM_HERE,
+ base::Bind(base::ComputeDirectorySize,
+ ConstructOriginPath(root_path_, origin_url)),
+ base::Bind(callback));
+}
+
+void CacheStorageManager::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 CacheStorageManager::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 CacheStorageManager::DeleteOriginData(
+ const GURL& origin,
+ const storage::QuotaClient::DeletionCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ CacheStorage* cache_storage = FindOrCreateCacheStorage(origin);
+ cache_storage_map_.erase(origin);
+ cache_storage->CloseAllCaches(
+ base::Bind(&CacheStorageManager::DeleteOriginDidClose, origin, callback,
+ base::Passed(make_scoped_ptr(cache_storage)),
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+// static
+void CacheStorageManager::DeleteOriginDidClose(
+ const GURL& origin,
+ const storage::QuotaClient::DeletionCallback& callback,
+ scoped_ptr<CacheStorage> cache_storage,
+ base::WeakPtr<CacheStorageManager> 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;
+ }
+
+ cache_manager->MigrateOrigin(origin);
+ PostTaskAndReplyWithResult(
+ cache_manager->cache_task_runner_.get(), FROM_HERE,
+ base::Bind(&DeleteDir,
+ ConstructOriginPath(cache_manager->root_path_, origin)),
+ base::Bind(&DeleteOriginDidDeleteDir, callback));
+}
+
+CacheStorageManager::CacheStorageManager(
+ const base::FilePath& path,
+ const scoped_refptr<base::SequencedTaskRunner>& cache_task_runner,
+ const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy)
+ : 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 CacheStorageQuotaClient(weak_ptr_factory_.GetWeakPtr()));
+ }
+}
+
+CacheStorage* CacheStorageManager::FindOrCreateCacheStorage(
+ const GURL& origin) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(request_context_);
+ CacheStorageMap::const_iterator it = cache_storage_map_.find(origin);
+ if (it == cache_storage_map_.end()) {
+ MigrateOrigin(origin);
+ CacheStorage* cache_storage = new CacheStorage(
+ 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;
+}
+
+// static
+base::FilePath CacheStorageManager::ConstructLegacyOriginPath(
+ const base::FilePath& root_path,
+ const GURL& origin) {
+ const std::string origin_hash = base::SHA1HashString(origin.spec());
+ const std::string origin_hash_hex = base::StringToLowerASCII(
+ base::HexEncode(origin_hash.c_str(), origin_hash.length()));
+ return root_path.AppendASCII(origin_hash_hex);
+}
+
+// static
+base::FilePath CacheStorageManager::ConstructOriginPath(
+ const base::FilePath& root_path,
+ const GURL& origin) {
+ const std::string identifier = storage::GetIdentifierFromOrigin(origin);
+ const std::string origin_hash = base::SHA1HashString(identifier);
+ const std::string origin_hash_hex = base::StringToLowerASCII(
+ base::HexEncode(origin_hash.c_str(), origin_hash.length()));
+ return root_path.AppendASCII(origin_hash_hex);
+}
+
+// Migrate from old origin-based path to storage identifier-based path.
+// TODO(jsbell); Remove after a few releases.
+void CacheStorageManager::MigrateOrigin(const GURL& origin) {
+ if (IsMemoryBacked())
+ return;
+ base::FilePath old_path = ConstructLegacyOriginPath(root_path_, origin);
+ base::FilePath new_path = ConstructOriginPath(root_path_, origin);
+ cache_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&MigrateOriginOnTaskRunner, old_path, new_path));
+}
+
+// static
+void CacheStorageManager::MigrateOriginOnTaskRunner(
+ const base::FilePath& old_path,
+ const base::FilePath& new_path) {
+ if (base::PathExists(old_path)) {
+ if (!base::PathExists(new_path))
+ base::Move(old_path, new_path);
+ base::DeleteFile(old_path, /*recursive*/ true);
+ }
+}
+
+} // namespace content
diff --git a/chromium/content/browser/cache_storage/cache_storage_manager.h b/chromium/content/browser/cache_storage/cache_storage_manager.h
new file mode 100644
index 00000000000..b9eeda696a0
--- /dev/null
+++ b/chromium/content/browser/cache_storage/cache_storage_manager.h
@@ -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.
+
+#ifndef CONTENT_BROWSER_CACHE_STORAGE_CACHE_STORAGE_MANAGER_H_
+#define CONTENT_BROWSER_CACHE_STORAGE_CACHE_STORAGE_MANAGER_H_
+
+#include <map>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/files/file_path.h"
+#include "base/gtest_prod_util.h"
+#include "content/browser/cache_storage/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 CacheStorageQuotaClient;
+
+// Keeps track of a CacheStorage per origin. There is one
+// CacheStorageManager per ServiceWorkerContextCore.
+// TODO(jkarlin): Remove CacheStorage from memory once they're no
+// longer in active use.
+class CONTENT_EXPORT CacheStorageManager {
+ public:
+ static scoped_ptr<CacheStorageManager> Create(
+ const base::FilePath& path,
+ const scoped_refptr<base::SequencedTaskRunner>& cache_task_runner,
+ const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy);
+
+ static scoped_ptr<CacheStorageManager> Create(
+ CacheStorageManager* old_manager);
+
+ virtual ~CacheStorageManager();
+
+ // Methods to support the CacheStorage spec. These methods call the
+ // corresponding CacheStorage method on the appropriate thread.
+ void OpenCache(const GURL& origin,
+ const std::string& cache_name,
+ const CacheStorage::CacheAndErrorCallback& callback);
+ void HasCache(const GURL& origin,
+ const std::string& cache_name,
+ const CacheStorage::BoolAndErrorCallback& callback);
+ void DeleteCache(const GURL& origin,
+ const std::string& cache_name,
+ const CacheStorage::BoolAndErrorCallback& callback);
+ void EnumerateCaches(const GURL& origin,
+ const CacheStorage::StringsAndErrorCallback& callback);
+ void MatchCache(const GURL& origin,
+ const std::string& cache_name,
+ scoped_ptr<ServiceWorkerFetchRequest> request,
+ const CacheStorageCache::ResponseCallback& callback);
+ void MatchAllCaches(const GURL& origin,
+ scoped_ptr<ServiceWorkerFetchRequest> request,
+ const CacheStorageCache::ResponseCallback& callback);
+
+ // 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<CacheStorageManager> AsWeakPtr() {
+ return weak_ptr_factory_.GetWeakPtr();
+ }
+
+ private:
+ friend class CacheStorageQuotaClient;
+ friend class CacheStorageManagerTest;
+ friend class CacheStorageMigrationTest;
+
+ typedef std::map<GURL, CacheStorage*> CacheStorageMap;
+
+ CacheStorageManager(
+ const base::FilePath& path,
+ const scoped_refptr<base::SequencedTaskRunner>& cache_task_runner,
+ const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy);
+
+ // The returned CacheStorage* is owned by this manager.
+ CacheStorage* FindOrCreateCacheStorage(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<CacheStorage> cache_storage,
+ base::WeakPtr<CacheStorageManager> 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(); }
+
+ // Map a origin to the path. Exposed for testing.
+ static base::FilePath ConstructLegacyOriginPath(
+ const base::FilePath& root_path,
+ const GURL& origin);
+ // Map a database identifier (computed from an origin) to the path. Exposed
+ // for testing.
+ static base::FilePath ConstructOriginPath(const base::FilePath& root_path,
+ const GURL& origin);
+
+ // Migrate from old origin-based path to storage identifier-based path.
+ // TODO(jsbell); Remove method and all calls after a few releases.
+ void MigrateOrigin(const GURL& origin);
+ static void MigrateOriginOnTaskRunner(const base::FilePath& old_path,
+ const base::FilePath& new_path);
+
+ 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_|.
+ CacheStorageMap cache_storage_map_;
+
+ net::URLRequestContext* request_context_;
+ base::WeakPtr<storage::BlobStorageContext> blob_context_;
+
+ base::WeakPtrFactory<CacheStorageManager> weak_ptr_factory_;
+ DISALLOW_COPY_AND_ASSIGN(CacheStorageManager);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_CACHE_STORAGE_CACHE_STORAGE_MANAGER_H_
diff --git a/chromium/content/browser/cache_storage/cache_storage_manager_unittest.cc b/chromium/content/browser/cache_storage/cache_storage_manager_unittest.cc
new file mode 100644
index 00000000000..4fb7e7fb4a8
--- /dev/null
+++ b/chromium/content/browser/cache_storage/cache_storage_manager_unittest.cc
@@ -0,0 +1,800 @@
+// Copyright 2014 The Chromium Authors. 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/cache_storage/cache_storage_manager.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"
+#include "base/stl_util.h"
+#include "content/browser/cache_storage/cache_storage_quota_client.h"
+#include "content/browser/fileapi/chrome_blob_storage_context.h"
+#include "content/browser/quota/mock_quota_manager_proxy.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 CacheStorageManagerTest : public testing::Test {
+ public:
+ CacheStorageManagerTest()
+ : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP),
+ callback_bool_(false),
+ callback_error_(CACHE_STORAGE_OK),
+ 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_ = CacheStorageManager::Create(
+ base::FilePath(), base::MessageLoopProxy::current(),
+ quota_manager_proxy_);
+ } else {
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ cache_manager_ = CacheStorageManager::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,
+ CacheStorageError error) {
+ callback_bool_ = value;
+ callback_error_ = error;
+ run_loop->Quit();
+ }
+
+ void CacheAndErrorCallback(base::RunLoop* run_loop,
+ const scoped_refptr<CacheStorageCache>& cache,
+ CacheStorageError error) {
+ callback_cache_ = cache;
+ callback_error_ = error;
+ run_loop->Quit();
+ }
+
+ void StringsAndErrorCallback(base::RunLoop* run_loop,
+ const std::vector<std::string>& strings,
+ CacheStorageError error) {
+ callback_strings_ = strings;
+ callback_error_ = error;
+ run_loop->Quit();
+ }
+
+ void CachePutCallback(base::RunLoop* run_loop, CacheStorageError error) {
+ callback_error_ = error;
+ run_loop->Quit();
+ }
+
+ void CacheMatchCallback(
+ base::RunLoop* run_loop,
+ CacheStorageError error,
+ scoped_ptr<ServiceWorkerResponse> response,
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle) {
+ callback_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(&CacheStorageManagerTest::CacheAndErrorCallback,
+ base::Unretained(this), base::Unretained(loop.get())));
+ loop->Run();
+
+ bool error = callback_error_ != CACHE_STORAGE_OK;
+ 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(&CacheStorageManagerTest::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(&CacheStorageManagerTest::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(&CacheStorageManagerTest::StringsAndErrorCallback,
+ base::Unretained(this), base::Unretained(loop.get())));
+ loop->Run();
+
+ return callback_error_ == CACHE_STORAGE_OK;
+ }
+
+ bool StorageMatch(const GURL& origin,
+ const std::string& cache_name,
+ const GURL& url) {
+ scoped_ptr<ServiceWorkerFetchRequest> request(
+ new ServiceWorkerFetchRequest());
+ request->url = url;
+ scoped_ptr<base::RunLoop> loop(new base::RunLoop());
+ cache_manager_->MatchCache(
+ origin, cache_name, request.Pass(),
+ base::Bind(&CacheStorageManagerTest::CacheMatchCallback,
+ base::Unretained(this), base::Unretained(loop.get())));
+ loop->Run();
+
+ return callback_error_ == CACHE_STORAGE_OK;
+ }
+
+ bool StorageMatchAll(const GURL& origin, const GURL& url) {
+ scoped_ptr<ServiceWorkerFetchRequest> request(
+ new ServiceWorkerFetchRequest());
+ request->url = url;
+ scoped_ptr<base::RunLoop> loop(new base::RunLoop());
+ cache_manager_->MatchAllCaches(
+ origin, request.Pass(),
+ base::Bind(&CacheStorageManagerTest::CacheMatchCallback,
+ base::Unretained(this), base::Unretained(loop.get())));
+ loop->Run();
+
+ return callback_error_ == CACHE_STORAGE_OK;
+ }
+
+ bool CachePut(const scoped_refptr<CacheStorageCache>& cache,
+ const GURL& url) {
+ ServiceWorkerFetchRequest request;
+ ServiceWorkerResponse response;
+ request.url = url;
+ response.url = url;
+
+ CacheStorageBatchOperation operation;
+ operation.operation_type = CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT;
+ operation.request = request;
+ operation.response = response;
+
+ scoped_ptr<base::RunLoop> loop(new base::RunLoop());
+ cache->BatchOperation(
+ std::vector<CacheStorageBatchOperation>(1, operation),
+ base::Bind(&CacheStorageManagerTest::CachePutCallback,
+ base::Unretained(this), base::Unretained(loop.get())));
+ loop->Run();
+
+ return callback_error_ == CACHE_STORAGE_OK;
+ }
+
+ bool CacheMatch(const scoped_refptr<CacheStorageCache>& 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(&CacheStorageManagerTest::CacheMatchCallback,
+ base::Unretained(this), base::Unretained(loop.get())));
+ loop->Run();
+
+ return callback_error_ == CACHE_STORAGE_OK;
+ }
+
+ CacheStorage* CacheStorageForOrigin(const GURL& origin) {
+ return cache_manager_->FindOrCreateCacheStorage(origin);
+ }
+
+ protected:
+ TestBrowserContext browser_context_;
+ TestBrowserThreadBundle browser_thread_bundle_;
+
+ base::ScopedTempDir temp_dir_;
+ scoped_refptr<MockQuotaManagerProxy> quota_manager_proxy_;
+ scoped_ptr<CacheStorageManager> cache_manager_;
+
+ scoped_refptr<CacheStorageCache> callback_cache_;
+ int callback_bool_;
+ CacheStorageError callback_error_;
+ scoped_ptr<ServiceWorkerResponse> callback_cache_response_;
+ std::vector<std::string> callback_strings_;
+
+ const GURL origin1_;
+ const GURL origin2_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CacheStorageManagerTest);
+};
+
+class CacheStorageManagerMemoryOnlyTest : public CacheStorageManagerTest {
+ bool MemoryOnly() override { return true; }
+};
+
+class CacheStorageManagerTestP : public CacheStorageManagerTest,
+ public testing::WithParamInterface<bool> {
+ bool MemoryOnly() override { return !GetParam(); }
+};
+
+TEST_F(CacheStorageManagerTest, TestsRunOnIOThread) {
+ EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
+}
+
+TEST_P(CacheStorageManagerTestP, OpenCache) {
+ EXPECT_TRUE(Open(origin1_, "foo"));
+}
+
+TEST_P(CacheStorageManagerTestP, OpenTwoCaches) {
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ EXPECT_TRUE(Open(origin1_, "bar"));
+}
+
+TEST_P(CacheStorageManagerTestP, CachePointersDiffer) {
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ scoped_refptr<CacheStorageCache> cache = callback_cache_;
+ EXPECT_TRUE(Open(origin1_, "bar"));
+ EXPECT_NE(callback_cache_.get(), cache.get());
+}
+
+TEST_P(CacheStorageManagerTestP, Open2CachesSameNameDiffOrigins) {
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ scoped_refptr<CacheStorageCache> cache = callback_cache_;
+ EXPECT_TRUE(Open(origin2_, "foo"));
+ EXPECT_NE(cache.get(), callback_cache_.get());
+}
+
+TEST_P(CacheStorageManagerTestP, OpenExistingCache) {
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ scoped_refptr<CacheStorageCache> cache = callback_cache_;
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ EXPECT_EQ(callback_cache_.get(), cache.get());
+}
+
+TEST_P(CacheStorageManagerTestP, HasCache) {
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ EXPECT_TRUE(Has(origin1_, "foo"));
+ EXPECT_TRUE(callback_bool_);
+}
+
+TEST_P(CacheStorageManagerTestP, HasNonExistent) {
+ EXPECT_FALSE(Has(origin1_, "foo"));
+}
+
+TEST_P(CacheStorageManagerTestP, DeleteCache) {
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ EXPECT_TRUE(Delete(origin1_, "foo"));
+ EXPECT_FALSE(Has(origin1_, "foo"));
+}
+
+TEST_P(CacheStorageManagerTestP, DeleteTwice) {
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ EXPECT_TRUE(Delete(origin1_, "foo"));
+ EXPECT_FALSE(Delete(origin1_, "foo"));
+ EXPECT_EQ(CACHE_STORAGE_ERROR_NOT_FOUND, callback_error_);
+}
+
+TEST_P(CacheStorageManagerTestP, EmptyKeys) {
+ EXPECT_TRUE(Keys(origin1_));
+ EXPECT_TRUE(callback_strings_.empty());
+}
+
+TEST_P(CacheStorageManagerTestP, 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(CacheStorageManagerTestP, 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(CacheStorageManagerTestP, StorageMatchEntryExists) {
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ EXPECT_TRUE(CachePut(callback_cache_, GURL("http://example.com/foo")));
+ EXPECT_TRUE(StorageMatch(origin1_, "foo", GURL("http://example.com/foo")));
+}
+
+TEST_P(CacheStorageManagerTestP, StorageMatchNoEntry) {
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ EXPECT_TRUE(CachePut(callback_cache_, GURL("http://example.com/foo")));
+ EXPECT_FALSE(StorageMatch(origin1_, "foo", GURL("http://example.com/bar")));
+ EXPECT_EQ(CACHE_STORAGE_ERROR_NOT_FOUND, callback_error_);
+}
+
+TEST_P(CacheStorageManagerTestP, StorageMatchNoCache) {
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ EXPECT_TRUE(CachePut(callback_cache_, GURL("http://example.com/foo")));
+ EXPECT_FALSE(StorageMatch(origin1_, "bar", GURL("http://example.com/foo")));
+ EXPECT_EQ(CACHE_STORAGE_ERROR_NOT_FOUND, callback_error_);
+}
+
+TEST_P(CacheStorageManagerTestP, StorageMatchAllEntryExists) {
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ EXPECT_TRUE(CachePut(callback_cache_, GURL("http://example.com/foo")));
+ EXPECT_TRUE(StorageMatchAll(origin1_, GURL("http://example.com/foo")));
+}
+
+TEST_P(CacheStorageManagerTestP, StorageMatchAllNoEntry) {
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ EXPECT_TRUE(CachePut(callback_cache_, GURL("http://example.com/foo")));
+ EXPECT_FALSE(StorageMatchAll(origin1_, GURL("http://example.com/bar")));
+ EXPECT_EQ(CACHE_STORAGE_ERROR_NOT_FOUND, callback_error_);
+}
+
+TEST_P(CacheStorageManagerTestP, StorageMatchAllNoCaches) {
+ EXPECT_FALSE(StorageMatchAll(origin1_, GURL("http://example.com/foo")));
+ EXPECT_EQ(CACHE_STORAGE_ERROR_NOT_FOUND, callback_error_);
+}
+
+TEST_P(CacheStorageManagerTestP, StorageMatchAllEntryExistsTwice) {
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ EXPECT_TRUE(CachePut(callback_cache_, GURL("http://example.com/foo")));
+ EXPECT_TRUE(Open(origin1_, "bar"));
+ EXPECT_TRUE(CachePut(callback_cache_, GURL("http://example.com/foo")));
+
+ EXPECT_TRUE(StorageMatchAll(origin1_, GURL("http://example.com/foo")));
+}
+
+TEST_P(CacheStorageManagerTestP, StorageMatchInOneOfMany) {
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ EXPECT_TRUE(Open(origin1_, "bar"));
+ EXPECT_TRUE(CachePut(callback_cache_, GURL("http://example.com/foo")));
+ EXPECT_TRUE(Open(origin1_, "baz"));
+
+ EXPECT_TRUE(StorageMatchAll(origin1_, GURL("http://example.com/foo")));
+}
+
+TEST_P(CacheStorageManagerTestP, Chinese) {
+ EXPECT_TRUE(Open(origin1_, "你好"));
+ scoped_refptr<CacheStorageCache> 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(CacheStorageManagerTest, EmptyKey) {
+ EXPECT_TRUE(Open(origin1_, ""));
+ scoped_refptr<CacheStorageCache> 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(CacheStorageManagerTest, 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_ = CacheStorageManager::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(CacheStorageManagerMemoryOnlyTest, DataLostWhenMemoryOnly) {
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ EXPECT_TRUE(Open(origin2_, "baz"));
+ quota_manager_proxy_->SimulateQuotaManagerDestroyed();
+ cache_manager_ = CacheStorageManager::Create(cache_manager_.get());
+ EXPECT_TRUE(Keys(origin1_));
+ EXPECT_EQ(0u, callback_strings_.size());
+}
+
+TEST_F(CacheStorageManagerTest, 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(CacheStorageManagerTest, 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
+// CacheStorageCache
+// it should be deleted.
+TEST_F(CacheStorageManagerTest, DropReference) {
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ base::WeakPtr<CacheStorageCache> 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(CacheStorageManagerMemoryOnlyTest, MemoryLosesReferenceOnlyAfterDelete) {
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ base::WeakPtr<CacheStorageCache> cache = callback_cache_->AsWeakPtr();
+ callback_cache_ = NULL;
+ EXPECT_TRUE(cache);
+ EXPECT_TRUE(Delete(origin1_, "foo"));
+ EXPECT_FALSE(cache);
+}
+
+TEST_P(CacheStorageManagerTestP, DeleteBeforeRelease) {
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ EXPECT_TRUE(Delete(origin1_, "foo"));
+ EXPECT_TRUE(callback_cache_->AsWeakPtr());
+}
+
+TEST_P(CacheStorageManagerTestP, OpenRunsSerially) {
+ EXPECT_FALSE(Delete(origin1_, "tmp")); // Init storage.
+ CacheStorage* cache_storage = CacheStorageForOrigin(origin1_);
+ cache_storage->StartAsyncOperationForTesting();
+
+ scoped_ptr<base::RunLoop> open_loop(new base::RunLoop());
+ cache_manager_->OpenCache(
+ origin1_, "foo",
+ base::Bind(&CacheStorageManagerTest::CacheAndErrorCallback,
+ base::Unretained(this), base::Unretained(open_loop.get())));
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(callback_cache_);
+
+ cache_storage->CompleteAsyncOperationForTesting();
+ open_loop->Run();
+ EXPECT_TRUE(callback_cache_);
+}
+
+TEST_F(CacheStorageManagerMemoryOnlyTest, MemoryBackedSize) {
+ CacheStorage* cache_storage = CacheStorageForOrigin(origin1_);
+ EXPECT_EQ(0, cache_storage->MemoryBackedSize());
+
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ scoped_refptr<CacheStorageCache> foo_cache = callback_cache_;
+ EXPECT_TRUE(Open(origin1_, "bar"));
+ scoped_refptr<CacheStorageCache> 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(CacheStorageManagerTest, MemoryBackedSizePersistent) {
+ CacheStorage* cache_storage = CacheStorageForOrigin(origin1_);
+ EXPECT_EQ(0, cache_storage->MemoryBackedSize());
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ EXPECT_TRUE(CachePut(callback_cache_, GURL("http://example.com/foo")));
+ EXPECT_EQ(0, cache_storage->MemoryBackedSize());
+}
+
+class CacheStorageMigrationTest : public CacheStorageManagerTest {
+ protected:
+ CacheStorageMigrationTest() : cache1_("foo"), cache2_("bar") {}
+
+ void SetUp() override {
+ CacheStorageManagerTest::SetUp();
+
+ // Populate a cache, then move it to the "legacy" location
+ // so that tests can verify the results of migration.
+ legacy_path_ = CacheStorageManager::ConstructLegacyOriginPath(
+ cache_manager_->root_path(), origin1_);
+ new_path_ = CacheStorageManager::ConstructOriginPath(
+ cache_manager_->root_path(), origin1_);
+
+ ASSERT_FALSE(base::DirectoryExists(legacy_path_));
+ ASSERT_FALSE(base::DirectoryExists(new_path_));
+ ASSERT_TRUE(Open(origin1_, cache1_));
+ ASSERT_TRUE(Open(origin1_, cache2_));
+ callback_cache_ = nullptr;
+ ASSERT_FALSE(base::DirectoryExists(legacy_path_));
+ ASSERT_TRUE(base::DirectoryExists(new_path_));
+
+ quota_manager_proxy_->SimulateQuotaManagerDestroyed();
+ cache_manager_ = CacheStorageManager::Create(cache_manager_.get());
+
+ ASSERT_TRUE(base::Move(new_path_, legacy_path_));
+ ASSERT_TRUE(base::DirectoryExists(legacy_path_));
+ ASSERT_FALSE(base::DirectoryExists(new_path_));
+ }
+
+ int64 GetOriginUsage(const GURL& origin) {
+ scoped_ptr<base::RunLoop> loop(new base::RunLoop());
+ cache_manager_->GetOriginUsage(
+ origin,
+ base::Bind(&CacheStorageMigrationTest::UsageCallback,
+ base::Unretained(this), base::Unretained(loop.get())));
+ loop->Run();
+ return callback_usage_;
+ }
+
+ void UsageCallback(base::RunLoop* run_loop, int64 usage) {
+ callback_usage_ = usage;
+ run_loop->Quit();
+ }
+
+ base::FilePath legacy_path_;
+ base::FilePath new_path_;
+
+ const std::string cache1_;
+ const std::string cache2_;
+
+ int64 callback_usage_;
+
+ DISALLOW_COPY_AND_ASSIGN(CacheStorageMigrationTest);
+};
+
+TEST_F(CacheStorageMigrationTest, OpenCache) {
+ EXPECT_TRUE(Open(origin1_, cache1_));
+ EXPECT_FALSE(base::DirectoryExists(legacy_path_));
+ EXPECT_TRUE(base::DirectoryExists(new_path_));
+
+ EXPECT_TRUE(Keys(origin1_));
+ std::vector<std::string> expected_keys;
+ expected_keys.push_back(cache1_);
+ expected_keys.push_back(cache2_);
+ EXPECT_EQ(expected_keys, callback_strings_);
+}
+
+TEST_F(CacheStorageMigrationTest, DeleteCache) {
+ EXPECT_TRUE(Delete(origin1_, cache1_));
+ EXPECT_FALSE(base::DirectoryExists(legacy_path_));
+ EXPECT_TRUE(base::DirectoryExists(new_path_));
+
+ EXPECT_TRUE(Keys(origin1_));
+ std::vector<std::string> expected_keys;
+ expected_keys.push_back(cache2_);
+ EXPECT_EQ(expected_keys, callback_strings_);
+}
+
+TEST_F(CacheStorageMigrationTest, GetOriginUsage) {
+ EXPECT_GT(GetOriginUsage(origin1_), 0);
+ EXPECT_FALSE(base::DirectoryExists(legacy_path_));
+ EXPECT_TRUE(base::DirectoryExists(new_path_));
+}
+
+TEST_F(CacheStorageMigrationTest, MoveFailure) {
+ // Revert the migration.
+ ASSERT_TRUE(base::Move(legacy_path_, new_path_));
+ ASSERT_FALSE(base::DirectoryExists(legacy_path_));
+ ASSERT_TRUE(base::DirectoryExists(new_path_));
+
+ // Make a dummy legacy directory.
+ ASSERT_TRUE(base::CreateDirectory(legacy_path_));
+
+ // Ensure that migration doesn't stomp existing new directory,
+ // but does clean up old directory.
+ EXPECT_TRUE(Open(origin1_, cache1_));
+ EXPECT_FALSE(base::DirectoryExists(legacy_path_));
+ EXPECT_TRUE(base::DirectoryExists(new_path_));
+
+ EXPECT_TRUE(Keys(origin1_));
+ std::vector<std::string> expected_keys;
+ expected_keys.push_back(cache1_);
+ expected_keys.push_back(cache2_);
+ EXPECT_EQ(expected_keys, callback_strings_);
+}
+
+class CacheStorageQuotaClientTest : public CacheStorageManagerTest {
+ protected:
+ CacheStorageQuotaClientTest() {}
+
+ void SetUp() override {
+ CacheStorageManagerTest::SetUp();
+ quota_client_.reset(
+ new CacheStorageQuotaClient(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(&CacheStorageQuotaClientTest::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(&CacheStorageQuotaClientTest::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(&CacheStorageQuotaClientTest::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(&CacheStorageQuotaClientTest::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<CacheStorageQuotaClient> quota_client_;
+
+ storage::QuotaStatusCode callback_status_;
+ int64 callback_usage_;
+ std::set<GURL> callback_origins_;
+
+ DISALLOW_COPY_AND_ASSIGN(CacheStorageQuotaClientTest);
+};
+
+class CacheStorageQuotaClientTestP : public CacheStorageQuotaClientTest,
+ public testing::WithParamInterface<bool> {
+ bool MemoryOnly() override { return !GetParam(); }
+};
+
+TEST_P(CacheStorageQuotaClientTestP, QuotaID) {
+ EXPECT_EQ(storage::QuotaClient::kServiceWorkerCache, quota_client_->id());
+}
+
+TEST_P(CacheStorageQuotaClientTestP, QuotaGetOriginUsage) {
+ EXPECT_EQ(0, QuotaGetOriginUsage(origin1_));
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ EXPECT_TRUE(CachePut(callback_cache_, GURL("http://example.com/foo")));
+ EXPECT_LT(0, QuotaGetOriginUsage(origin1_));
+}
+
+TEST_P(CacheStorageQuotaClientTestP, 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(CacheStorageQuotaClientTestP, 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(CacheStorageQuotaClientTestP, 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(CacheStorageQuotaClientTestP, QuotaDeleteEmptyOrigin) {
+ EXPECT_TRUE(QuotaDeleteOriginData(origin1_));
+}
+
+TEST_P(CacheStorageQuotaClientTestP, 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(CacheStorageManagerTests,
+ CacheStorageManagerTestP,
+ ::testing::Values(false, true));
+
+INSTANTIATE_TEST_CASE_P(CacheStorageQuotaClientTests,
+ CacheStorageQuotaClientTestP,
+ ::testing::Values(false, true));
+
+} // namespace content
diff --git a/chromium/content/browser/cache_storage/cache_storage_proto.gyp b/chromium/content/browser/cache_storage/cache_storage_proto.gyp
new file mode 100644
index 00000000000..cdbce159968
--- /dev/null
+++ b/chromium/content/browser/cache_storage/cache_storage_proto.gyp
@@ -0,0 +1,17 @@
+{
+ 'targets': [
+ {
+ # GN version: //content/browser/cache_storage:cache_storage_proto
+ 'target_name': 'cache_storage_proto',
+ 'type': 'static_library',
+ 'sources': [
+ 'cache_storage.proto',
+ ],
+ 'variables': {
+ 'proto_in_dir': '.',
+ 'proto_out_dir': 'content/browser/cache_storage',
+ },
+ 'includes': [ '../../../build/protoc.gypi' ]
+ },
+ ],
+}
diff --git a/chromium/content/browser/cache_storage/cache_storage_quota_client.cc b/chromium/content/browser/cache_storage/cache_storage_quota_client.cc
new file mode 100644
index 00000000000..9d6ceca4d61
--- /dev/null
+++ b/chromium/content/browser/cache_storage/cache_storage_quota_client.cc
@@ -0,0 +1,95 @@
+// Copyright 2014 The Chromium Authors. 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/cache_storage/cache_storage_quota_client.h"
+
+#include "content/browser/cache_storage/cache_storage_manager.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace content {
+
+CacheStorageQuotaClient::CacheStorageQuotaClient(
+ base::WeakPtr<CacheStorageManager> cache_manager)
+ : cache_manager_(cache_manager) {
+}
+
+CacheStorageQuotaClient::~CacheStorageQuotaClient() {
+}
+
+storage::QuotaClient::ID CacheStorageQuotaClient::id() const {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ return kServiceWorkerCache;
+}
+
+void CacheStorageQuotaClient::OnQuotaManagerDestroyed() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ delete this;
+}
+
+void CacheStorageQuotaClient::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 CacheStorageQuotaClient::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 CacheStorageQuotaClient::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 CacheStorageQuotaClient::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 CacheStorageQuotaClient::DoesSupport(storage::StorageType type) const {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ return type == storage::kStorageTypeTemporary;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/cache_storage/cache_storage_quota_client.h b/chromium/content/browser/cache_storage/cache_storage_quota_client.h
new file mode 100644
index 00000000000..94df1d9f1a4
--- /dev/null
+++ b/chromium/content/browser/cache_storage/cache_storage_quota_client.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_CACHE_STORAGE_CACHE_STORAGE_QUOTA_CLIENT_H_
+#define CONTENT_BROWSER_CACHE_STORAGE_CACHE_STORAGE_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 CacheStorageManager;
+
+// CacheStorageQuotaClient is owned by the QuotaManager. There is one per
+// CacheStorageManager, and therefore one per
+// ServiceWorkerContextCore.
+class CONTENT_EXPORT CacheStorageQuotaClient : public storage::QuotaClient {
+ public:
+ explicit CacheStorageQuotaClient(
+ base::WeakPtr<CacheStorageManager> cache_manager);
+ ~CacheStorageQuotaClient() 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<CacheStorageManager> cache_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(CacheStorageQuotaClient);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_CACHE_STORAGE_CACHE_STORAGE_QUOTA_CLIENT_H_
diff --git a/chromium/content/browser/cache_storage/cache_storage_scheduler.cc b/chromium/content/browser/cache_storage/cache_storage_scheduler.cc
new file mode 100644
index 00000000000..33447b93787
--- /dev/null
+++ b/chromium/content/browser/cache_storage/cache_storage_scheduler.cc
@@ -0,0 +1,47 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/cache_storage/cache_storage_scheduler.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop_proxy.h"
+
+namespace content {
+
+CacheStorageScheduler::CacheStorageScheduler() : operation_running_(false) {
+}
+
+CacheStorageScheduler::~CacheStorageScheduler() {
+}
+
+void CacheStorageScheduler::ScheduleOperation(const base::Closure& closure) {
+ pending_operations_.push_back(closure);
+ RunOperationIfIdle();
+}
+
+void CacheStorageScheduler::CompleteOperationAndRunNext() {
+ DCHECK(operation_running_);
+ operation_running_ = false;
+ RunOperationIfIdle();
+}
+
+bool CacheStorageScheduler::ScheduledOperations() const {
+ return operation_running_ || !pending_operations_.empty();
+}
+
+void CacheStorageScheduler::RunOperationIfIdle() {
+ if (!operation_running_ && !pending_operations_.empty()) {
+ operation_running_ = true;
+ // TODO(jkarlin): Run multiple operations in parallel where allowed.
+ base::Closure closure = pending_operations_.front();
+ pending_operations_.pop_front();
+ base::MessageLoopProxy::current()->PostTask(FROM_HERE, base::Bind(closure));
+ }
+}
+
+} // namespace content
diff --git a/chromium/content/browser/cache_storage/cache_storage_scheduler.h b/chromium/content/browser/cache_storage/cache_storage_scheduler.h
new file mode 100644
index 00000000000..dec6cbe7295
--- /dev/null
+++ b/chromium/content/browser/cache_storage/cache_storage_scheduler.h
@@ -0,0 +1,51 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_CACHE_STORAGE_CACHE_STORAGE_SCHEDULER_H_
+#define CONTENT_BROWSER_CACHE_STORAGE_CACHE_STORAGE_SCHEDULER_H_
+
+#include <list>
+
+#include "base/callback.h"
+#include "content/common/content_export.h"
+
+namespace content {
+
+// TODO(jkarlin): Support readers and writers so operations can run in parallel.
+// TODO(jkarlin): Support operation identification so that ops can be checked in
+// DCHECKs.
+
+// CacheStorageScheduler runs the scheduled callbacks sequentially. Add an
+// operation by calling ScheduleOperation() with your callback. Once your
+// operation is done be sure to call CompleteOperationAndRunNext() to schedule
+// the next operation.
+class CONTENT_EXPORT CacheStorageScheduler {
+ public:
+ CacheStorageScheduler();
+ virtual ~CacheStorageScheduler();
+
+ // Adds the operation to the tail of the queue and starts it if the scheduler
+ // is idle.
+ void ScheduleOperation(const base::Closure& closure);
+
+ // Call this after each operation completes. It cleans up the current
+ // operation and starts the next.
+ void CompleteOperationAndRunNext();
+
+ // Returns true if there are any running or pending operations.
+ bool ScheduledOperations() const;
+
+ private:
+ void RunOperationIfIdle();
+
+ // The list of operations waiting on initialization.
+ std::list<base::Closure> pending_operations_;
+ bool operation_running_;
+
+ DISALLOW_COPY_AND_ASSIGN(CacheStorageScheduler);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_CACHE_STORAGE_CACHE_STORAGE_SCHEDULER_H_
diff --git a/chromium/content/browser/cache_storage/cache_storage_scheduler_unittest.cc b/chromium/content/browser/cache_storage/cache_storage_scheduler_unittest.cc
new file mode 100644
index 00000000000..b04e8e7321f
--- /dev/null
+++ b/chromium/content/browser/cache_storage/cache_storage_scheduler_unittest.cc
@@ -0,0 +1,81 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/cache_storage/cache_storage_scheduler.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/run_loop.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+namespace {
+
+class TestTask {
+ public:
+ TestTask(CacheStorageScheduler* scheduler)
+ : scheduler_(scheduler), callback_count_(0) {}
+
+ virtual void Run() { callback_count_++; }
+ void Done() { scheduler_->CompleteOperationAndRunNext(); }
+
+ int callback_count() const { return callback_count_; }
+
+ protected:
+ CacheStorageScheduler* scheduler_;
+ int callback_count_;
+};
+
+} // namespace
+
+class CacheStorageSchedulerTest : public testing::Test {
+ protected:
+ CacheStorageSchedulerTest()
+ : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP),
+ task1_(TestTask(&scheduler_)),
+ task2_(TestTask(&scheduler_)) {}
+
+ TestBrowserThreadBundle browser_thread_bundle_;
+ CacheStorageScheduler scheduler_;
+ TestTask task1_;
+ TestTask task2_;
+};
+
+TEST_F(CacheStorageSchedulerTest, ScheduleOne) {
+ scheduler_.ScheduleOperation(
+ base::Bind(&TestTask::Run, base::Unretained(&task1_)));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(1, task1_.callback_count());
+}
+
+TEST_F(CacheStorageSchedulerTest, ScheduleTwo) {
+ scheduler_.ScheduleOperation(
+ base::Bind(&TestTask::Run, base::Unretained(&task1_)));
+ scheduler_.ScheduleOperation(
+ base::Bind(&TestTask::Run, base::Unretained(&task2_)));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(1, task1_.callback_count());
+ EXPECT_EQ(0, task2_.callback_count());
+
+ task1_.Done();
+ EXPECT_TRUE(scheduler_.ScheduledOperations());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(1, task1_.callback_count());
+ EXPECT_EQ(1, task2_.callback_count());
+}
+
+TEST_F(CacheStorageSchedulerTest, ScheduledOperations) {
+ scheduler_.ScheduleOperation(
+ base::Bind(&TestTask::Run, base::Unretained(&task1_)));
+ EXPECT_TRUE(scheduler_.ScheduledOperations());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(1, task1_.callback_count());
+ EXPECT_TRUE(scheduler_.ScheduledOperations());
+ task1_.Done();
+ EXPECT_FALSE(scheduler_.ScheduledOperations());
+}
+
+} // namespace content
diff --git a/chromium/content/browser/child_process_launcher.cc b/chromium/content/browser/child_process_launcher.cc
index e47bebc3bdf..23cf832e665 100644
--- a/chromium/content/browser/child_process_launcher.cc
+++ b/chromium/content/browser/child_process_launcher.cc
@@ -1,22 +1,19 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 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/child_process_launcher.h"
-#include <utility> // For std::pair.
-
#include "base/bind.h"
#include "base/command_line.h"
#include "base/files/file_util.h"
-#include "base/files/scoped_file.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/metrics/histogram.h"
#include "base/process/process.h"
+#include "base/profiler/scoped_tracker.h"
#include "base/synchronization/lock.h"
#include "base/threading/thread.h"
-#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/common/content_descriptors.h"
#include "content/public/common/content_switches.h"
@@ -43,470 +40,453 @@
#endif
#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 {
-// Having the functionality of ChildProcessLauncher be in an internal
-// ref counted object allows us to automatically terminate the process when the
-// parent class destructs, while still holding on to state that we need.
-class ChildProcessLauncher::Context
- : public base::RefCountedThreadSafe<ChildProcessLauncher::Context> {
- public:
- Context()
- : client_(NULL),
- client_thread_id_(BrowserThread::UI),
- termination_status_(base::TERMINATION_STATUS_NORMAL_TERMINATION),
- exit_code_(RESULT_CODE_NORMAL_EXIT),
- starting_(true),
- // TODO(earthdok): Re-enable on CrOS http://crbug.com/360622
-#if (defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \
- defined(THREAD_SANITIZER)) && !defined(OS_CHROMEOS)
- terminate_child_on_shutdown_(false)
-#else
- terminate_child_on_shutdown_(true)
-#endif
-#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
- , zygote_(false)
-#endif
- {
- }
-
- void Launch(SandboxedProcessLauncherDelegate* delegate,
- base::CommandLine* cmd_line,
- int child_process_id,
- Client* client) {
- client_ = client;
-
- CHECK(BrowserThread::GetCurrentThreadIdentifier(&client_thread_id_));
+namespace {
+typedef base::Callback<void(bool,
#if defined(OS_ANDROID)
- // 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_.reset(delegate->TakeIpcFd().release());
+ base::ScopedFD,
#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::Process)> NotifyCallback;
+
+void RecordHistogramsOnLauncherThread(base::TimeDelta launch_time) {
+ DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
+ // Log the launch time, separating out the first one (which will likely be
+ // slower due to the rest of the browser initializing at the same time).
+ static bool done_first_launch = false;
+ if (done_first_launch) {
+ UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time);
+ } else {
+ UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time);
+ done_first_launch = true;
}
+}
#if defined(OS_ANDROID)
- static void OnChildProcessStarted(
- // |this_object| is NOT thread safe. Only use it to post a task back.
- scoped_refptr<Context> this_object,
- BrowserThread::ID client_thread_id,
- const base::TimeTicks begin_launch_time,
- base::ProcessHandle handle) {
- RecordHistograms(begin_launch_time);
- 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(base::Process(handle));
- } else {
- BrowserThread::PostTask(
- client_thread_id, FROM_HERE,
- base::Bind(
- &ChildProcessLauncher::Context::Notify,
- this_object,
- base::Passed(base::Process(handle))));
- }
- }
-#endif
-
- void ResetClient() {
- // No need for locking as this function gets called on the same thread that
- // client_ would be used.
- CHECK(BrowserThread::CurrentlyOn(client_thread_id_));
- client_ = NULL;
- }
-
- void set_terminate_child_on_shutdown(bool terminate_on_shutdown) {
- 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();
+// TODO(sievers): Remove this by defining better what happens on what
+// thread in the corresponding Java code.
+void OnChildProcessStartedAndroid(const NotifyCallback& callback,
+ BrowserThread::ID client_thread_id,
+ const base::TimeTicks begin_launch_time,
+ base::ScopedFD ipcfd,
+ base::ProcessHandle handle) {
+ // This can be called on the launcher thread or UI thread.
+ base::TimeDelta launch_time = base::TimeTicks::Now() - begin_launch_time;
+ BrowserThread::PostTask(
+ BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
+ base::Bind(&RecordHistogramsOnLauncherThread, launch_time));
+
+ base::Closure callback_on_client_thread(
+ base::Bind(callback, false, base::Passed(&ipcfd),
+ base::Passed(base::Process(handle))));
+ if (BrowserThread::CurrentlyOn(client_thread_id)) {
+ callback_on_client_thread.Run();
+ } else {
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;
-
- ~Context() {
- Terminate();
- }
-
- static void RecordHistograms(const base::TimeTicks begin_launch_time) {
- base::TimeDelta launch_time = base::TimeTicks::Now() - begin_launch_time;
- if (BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER)) {
- RecordLaunchHistograms(launch_time);
- } else {
- BrowserThread::PostTask(
- BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
- base::Bind(&ChildProcessLauncher::Context::RecordLaunchHistograms,
- launch_time));
- }
- }
-
- static void RecordLaunchHistograms(const base::TimeDelta launch_time) {
- // Log the launch time, separating out the first one (which will likely be
- // slower due to the rest of the browser initializing at the same time).
- static bool done_first_launch = false;
- if (done_first_launch) {
- UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time);
- } else {
- UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time);
- done_first_launch = true;
- }
- }
+ client_thread_id, FROM_HERE, callback_on_client_thread);
+ }
+}
+#endif
- static void LaunchInternal(
- // |this_object| is NOT thread safe. Only use it to post a task back.
- scoped_refptr<Context> this_object,
- BrowserThread::ID client_thread_id,
- int child_process_id,
- SandboxedProcessLauncherDelegate* delegate,
- base::CommandLine* cmd_line) {
- scoped_ptr<SandboxedProcessLauncherDelegate> delegate_deleter(delegate);
+void LaunchOnLauncherThread(const NotifyCallback& callback,
+ BrowserThread::ID client_thread_id,
+ int child_process_id,
+ SandboxedProcessLauncherDelegate* delegate,
+#if defined(OS_ANDROID)
+ base::ScopedFD ipcfd,
+#endif
+ base::CommandLine* cmd_line) {
+ DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
+ scoped_ptr<SandboxedProcessLauncherDelegate> delegate_deleter(delegate);
#if defined(OS_WIN)
- bool launch_elevated = delegate->ShouldLaunchElevated();
-#elif defined(OS_ANDROID)
- // Uses |ipcfd_| instead of |ipcfd| on Android.
+ bool use_zygote = false;
+ bool launch_elevated = delegate->ShouldLaunchElevated();
#elif defined(OS_MACOSX)
- base::EnvironmentMap env = delegate->GetEnvironment();
- base::ScopedFD ipcfd = delegate->TakeIpcFd();
-#elif defined(OS_POSIX)
- bool use_zygote = delegate->ShouldUseZygote();
- base::EnvironmentMap env = delegate->GetEnvironment();
- base::ScopedFD ipcfd = delegate->TakeIpcFd();
+ bool use_zygote = false;
+ base::EnvironmentMap env = delegate->GetEnvironment();
+ base::ScopedFD ipcfd = delegate->TakeIpcFd();
+#elif defined(OS_POSIX) && !defined(OS_ANDROID)
+ bool use_zygote = delegate->ShouldUseZygote();
+ base::EnvironmentMap env = delegate->GetEnvironment();
+ base::ScopedFD ipcfd = delegate->TakeIpcFd();
#endif
- scoped_ptr<base::CommandLine> cmd_line_deleter(cmd_line);
- base::TimeTicks begin_launch_time = base::TimeTicks::Now();
+ scoped_ptr<base::CommandLine> cmd_line_deleter(cmd_line);
+ base::TimeTicks begin_launch_time = base::TimeTicks::Now();
+ base::Process process;
#if defined(OS_WIN)
- base::ProcessHandle handle = base::kNullProcessHandle;
- if (launch_elevated) {
- base::LaunchOptions options;
- options.start_hidden = true;
- base::LaunchElevatedProcess(*cmd_line, options, &handle);
- } else {
- handle = StartSandboxedProcess(delegate, cmd_line);
- }
+ if (launch_elevated) {
+ base::LaunchOptions options;
+ options.start_hidden = true;
+ process = base::LaunchElevatedProcess(*cmd_line, options);
+ } else {
+ process = StartSandboxedProcess(delegate, cmd_line);
+ }
#elif defined(OS_POSIX)
- std::string process_type =
- cmd_line->GetSwitchValueASCII(switches::kProcessType);
- scoped_ptr<FileDescriptorInfo> files_to_register(
- FileDescriptorInfoImpl::Create());
+ std::string process_type =
+ cmd_line->GetSwitchValueASCII(switches::kProcessType);
+ scoped_ptr<FileDescriptorInfo> files_to_register(
+ FileDescriptorInfoImpl::Create());
#if defined(OS_ANDROID)
- files_to_register->Share(kPrimaryIPCChannel, this_object->ipcfd_.get());
+ files_to_register->Share(kPrimaryIPCChannel, ipcfd.get());
#else
- files_to_register->Transfer(kPrimaryIPCChannel, ipcfd.Pass());
+ files_to_register->Transfer(kPrimaryIPCChannel, ipcfd.Pass());
#endif
- base::StatsTable* stats_table = base::StatsTable::current();
- if (stats_table &&
- base::SharedMemory::IsHandleValid(
- stats_table->GetSharedMemoryHandle())) {
- base::FileDescriptor fd = stats_table->GetSharedMemoryHandle();
- DCHECK(!fd.auto_close);
- files_to_register->Share(kStatsTableSharedMemFd, fd.fd);
- }
#endif
#if defined(OS_ANDROID)
- // Android WebView runs in single process, ensure that we never get here
- // when running in single process mode.
- CHECK(!cmd_line->HasSwitch(switches::kSingleProcess));
-
- GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess(
- *cmd_line, child_process_id, files_to_register.get());
-
- StartChildProcess(
- cmd_line->argv(),
- child_process_id,
- files_to_register.Pass(),
- base::Bind(&ChildProcessLauncher::Context::OnChildProcessStarted,
- this_object,
- client_thread_id,
- begin_launch_time));
+ // Android WebView runs in single process, ensure that we never get here
+ // when running in single process mode.
+ CHECK(!cmd_line->HasSwitch(switches::kSingleProcess));
+
+ GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess(
+ *cmd_line, child_process_id, files_to_register.get());
+
+ StartChildProcess(
+ cmd_line->argv(), child_process_id, files_to_register.Pass(),
+ base::Bind(&OnChildProcessStartedAndroid, callback, client_thread_id,
+ begin_launch_time, base::Passed(&ipcfd)));
#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.
+ // We need to close the client end of the IPC channel to reliably detect
+ // child termination.
#if !defined(OS_MACOSX)
- 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.Pass(), process_type);
- } else
- // Fall through to the normal posix case below when we're not zygoting.
+ GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess(
+ *cmd_line, child_process_id, files_to_register.get());
+ if (use_zygote) {
+ base::ProcessHandle handle = ZygoteHostImpl::GetInstance()->ForkRequest(
+ cmd_line->argv(), files_to_register.Pass(), process_type);
+ process = base::Process(handle);
+ } 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 =
- files_to_register->GetMappingWithIDAdjustment(
- base::GlobalDescriptors::kBaseDescriptor);
+ {
+ // Convert FD mapping to FileHandleMappingVector
+ base::FileHandleMappingVector fds_to_map =
+ files_to_register->GetMappingWithIDAdjustment(
+ base::GlobalDescriptors::kBaseDescriptor);
#if !defined(OS_MACOSX)
- if (process_type == switches::kRendererProcess) {
- const int sandbox_fd =
- RenderSandboxHostLinux::GetInstance()->GetRendererSocket();
- fds_to_map.push_back(std::make_pair(
- sandbox_fd,
- GetSandboxFD()));
- }
+ if (process_type == switches::kRendererProcess) {
+ const int sandbox_fd =
+ RenderSandboxHostLinux::GetInstance()->GetRendererSocket();
+ fds_to_map.push_back(std::make_pair(
+ sandbox_fd,
+ GetSandboxFD()));
+ }
#endif // defined(OS_MACOSX)
- // Actually launch the app.
- base::LaunchOptions options;
- options.environ = env;
- options.fds_to_remap = &fds_to_map;
+ // Actually launch the app.
+ base::LaunchOptions options;
+ options.environ = env;
+ options.fds_to_remap = &fds_to_map;
#if defined(OS_MACOSX)
- // Hold the MachBroker lock for the duration of LaunchProcess. The child
- // will send its task port to the parent almost immediately after startup.
- // The Mach message will be delivered to the parent, but updating the
- // record of the launch will wait until after the placeholder PID is
- // inserted below. This ensures that while the child process may send its
- // port to the parent prior to the parent leaving LaunchProcess, the
- // order in which the record in MachBroker is updated is correct.
- MachBroker* broker = MachBroker::GetInstance();
- broker->GetLock().Acquire();
-
- // Make sure the MachBroker is running, and inform it to expect a
- // check-in from the new process.
- broker->EnsureRunning();
-
- const int bootstrap_sandbox_policy = delegate->GetSandboxType();
- if (ShouldEnableBootstrapSandbox() &&
- bootstrap_sandbox_policy != SANDBOX_TYPE_INVALID) {
- options.replacement_bootstrap_name =
- GetBootstrapSandbox()->server_bootstrap_name();
- GetBootstrapSandbox()->PrepareToForkWithPolicy(
- bootstrap_sandbox_policy);
- }
+ // Hold the MachBroker lock for the duration of LaunchProcess. The child
+ // will send its task port to the parent almost immediately after startup.
+ // The Mach message will be delivered to the parent, but updating the
+ // record of the launch will wait until after the placeholder PID is
+ // inserted below. This ensures that while the child process may send its
+ // port to the parent prior to the parent leaving LaunchProcess, the
+ // order in which the record in MachBroker is updated is correct.
+ MachBroker* broker = MachBroker::GetInstance();
+ broker->GetLock().Acquire();
+
+ // Make sure the MachBroker is running, and inform it to expect a
+ // check-in from the new process.
+ broker->EnsureRunning();
+
+ const int bootstrap_sandbox_policy = delegate->GetSandboxType();
+ if (ShouldEnableBootstrapSandbox() &&
+ bootstrap_sandbox_policy != SANDBOX_TYPE_INVALID) {
+ options.replacement_bootstrap_name =
+ GetBootstrapSandbox()->server_bootstrap_name();
+ GetBootstrapSandbox()->PrepareToForkWithPolicy(
+ bootstrap_sandbox_policy);
+ }
#endif // defined(OS_MACOSX)
- bool launched = base::LaunchProcess(*cmd_line, options, &handle);
- if (!launched)
- handle = base::kNullProcessHandle;
+ process = base::LaunchProcess(*cmd_line, options);
#if defined(OS_MACOSX)
- if (ShouldEnableBootstrapSandbox() &&
- bootstrap_sandbox_policy != SANDBOX_TYPE_INVALID) {
- GetBootstrapSandbox()->FinishedFork(handle);
- }
+ if (ShouldEnableBootstrapSandbox() &&
+ bootstrap_sandbox_policy != SANDBOX_TYPE_INVALID) {
+ GetBootstrapSandbox()->FinishedFork(process.Handle());
+ }
- if (launched)
- broker->AddPlaceholderForPid(handle);
+ if (process.IsValid())
+ broker->AddPlaceholderForPid(process.Pid(), child_process_id);
- // After updating the broker, release the lock and let the child's
- // messasge be processed on the broker's thread.
- broker->GetLock().Release();
+ // After updating the broker, release the lock and let the child's
+ // messasge be processed on the broker's thread.
+ broker->GetLock().Release();
#endif // defined(OS_MACOSX)
- }
+ }
#endif // else defined(OS_POSIX)
#if !defined(OS_ANDROID)
- if (handle)
- RecordHistograms(begin_launch_time);
- BrowserThread::PostTask(
- client_thread_id, FROM_HERE,
- base::Bind(
- &Context::Notify,
- this_object.get(),
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
- use_zygote,
-#endif
- base::Passed(base::Process(handle))));
-#endif // !defined(OS_ANDROID)
- }
-
- void Notify(
-#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
- bool zygote,
-#endif
- base::Process process) {
-#if defined(OS_ANDROID)
- // Finally close the ipcfd
- base::ScopedFD ipcfd_closer = ipcfd_.Pass();
-#endif
- starting_ = false;
- 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 (process_.IsValid()) {
- client_->OnProcessLaunched();
- } else {
- client_->OnProcessLaunchFailed();
- }
- } else {
- Terminate();
- }
- }
-
- void Terminate() {
- if (!process_.IsValid())
- return;
-
- if (!terminate_child_on_shutdown_)
- return;
-
- // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So
- // don't this on the UI/IO threads.
- BrowserThread::PostTask(
- BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
- base::Bind(
- &Context::TerminateInternal,
-#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
- zygote_,
-#endif
- base::Passed(&process_)));
- }
-
- static void SetProcessBackgroundedInternal(base::Process process,
- bool background) {
- process.SetProcessBackgrounded(background);
-#if defined(OS_ANDROID)
- SetChildProcessInForeground(process.Handle(), !background);
-#endif
+ if (process.IsValid()) {
+ RecordHistogramsOnLauncherThread(base::TimeTicks::Now() -
+ begin_launch_time);
}
+ BrowserThread::PostTask(client_thread_id, FROM_HERE,
+ base::Bind(callback,
+ use_zygote,
+ base::Passed(&process)));
+#endif // !defined(OS_ANDROID)
+}
- static void TerminateInternal(
-#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
- bool zygote,
-#endif
- base::Process process) {
+void TerminateOnLauncherThread(bool zygote, base::Process process) {
+ DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
#if defined(OS_ANDROID)
- VLOG(1) << "ChromeProcess: Stopping process with handle "
- << process.Handle();
- StopChildProcess(process.Handle());
+ VLOG(1) << "ChromeProcess: Stopping process with handle "
+ << process.Handle();
+ StopChildProcess(process.Handle());
#else
- // 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);
- // On POSIX, we must additionally reap the child.
+ // 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, false);
+ // On POSIX, we must additionally reap the child.
#if defined(OS_POSIX)
#if !defined(OS_MACOSX)
- if (zygote) {
- // If the renderer was created via a zygote, we have to proxy the reaping
- // through the zygote process.
- ZygoteHostImpl::GetInstance()->EnsureProcessTerminated(process.Handle());
- } else
+ if (zygote) {
+ // If the renderer was created via a zygote, we have to proxy the reaping
+ // through the zygote process.
+ ZygoteHostImpl::GetInstance()->EnsureProcessTerminated(process.Handle());
+ } else
#endif // !OS_MACOSX
- {
- base::EnsureProcessTerminated(process.Handle());
- }
+ base::EnsureProcessTerminated(process.Pass());
#endif // OS_POSIX
#endif // defined(OS_ANDROID)
- }
+}
- Client* client_;
- BrowserThread::ID client_thread_id_;
- base::Process process_;
- base::TerminationStatus termination_status_;
- int exit_code_;
- bool starting_;
- // Controls whether the child process should be terminated on browser
- // shutdown. Default behavior is to terminate the child.
- bool terminate_child_on_shutdown_;
+void SetProcessBackgroundedOnLauncherThread(base::Process process,
+ bool background) {
+ DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
+#if defined(OS_MACOSX)
+ MachBroker* broker = MachBroker::GetInstance();
+ mach_port_t task_port = broker->TaskForPid(process.Pid());
+ if (task_port != TASK_NULL) {
+ process.SetProcessBackgrounded(task_port, background);
+ }
+#else
+ process.SetProcessBackgrounded(background);
+#endif // defined(OS_MACOSX)
#if defined(OS_ANDROID)
- // The fd to close after creating the process.
- base::ScopedFD ipcfd_;
-#elif defined(OS_POSIX) && !defined(OS_MACOSX)
- bool zygote_;
+ SetChildProcessInForeground(process.Handle(), !background);
#endif
-};
+}
+} // anonymous namespace
ChildProcessLauncher::ChildProcessLauncher(
SandboxedProcessLauncherDelegate* delegate,
base::CommandLine* cmd_line,
int child_process_id,
- Client* client) {
- context_ = new Context();
- context_->Launch(
- delegate,
- cmd_line,
- child_process_id,
- client);
+ Client* client,
+ bool terminate_on_shutdown)
+ : client_(client),
+ termination_status_(base::TERMINATION_STATUS_NORMAL_TERMINATION),
+ exit_code_(RESULT_CODE_NORMAL_EXIT),
+ zygote_(false),
+ starting_(true),
+#if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \
+ defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \
+ defined(UNDEFINED_SANITIZER)
+ terminate_child_on_shutdown_(false),
+#else
+ terminate_child_on_shutdown_(terminate_on_shutdown),
+#endif
+ weak_factory_(this) {
+ DCHECK(CalledOnValidThread());
+ CHECK(BrowserThread::GetCurrentThreadIdentifier(&client_thread_id_));
+ Launch(delegate, cmd_line, child_process_id);
}
ChildProcessLauncher::~ChildProcessLauncher() {
- context_->ResetClient();
+ DCHECK(CalledOnValidThread());
+ if (process_.IsValid() && terminate_child_on_shutdown_) {
+ // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So
+ // don't this on the UI/IO threads.
+ BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
+ base::Bind(&TerminateOnLauncherThread, zygote_,
+ base::Passed(&process_)));
+ }
}
-bool ChildProcessLauncher::IsStarting() {
- return context_->starting_;
-}
+void ChildProcessLauncher::Launch(
+ SandboxedProcessLauncherDelegate* delegate,
+ base::CommandLine* cmd_line,
+ int child_process_id) {
+ DCHECK(CalledOnValidThread());
-const base::Process& ChildProcessLauncher::GetProcess() const {
- DCHECK(!context_->starting_);
- return context_->process_;
+#if defined(OS_ANDROID)
+ // Android only supports renderer, sandboxed utility and gpu.
+ std::string process_type =
+ cmd_line->GetSwitchValueASCII(switches::kProcessType);
+ CHECK(process_type == switches::kGpuProcess ||
+ process_type == switches::kRendererProcess ||
+ process_type == switches::kUtilityProcess)
+ << "Unsupported process type: " << process_type;
+
+ // Non-sandboxed utility or renderer process are currently not supported.
+ DCHECK(process_type == switches::kGpuProcess ||
+ !cmd_line->HasSwitch(switches::kNoSandbox));
+
+ // 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.
+ base::ScopedFD ipcfd(delegate->TakeIpcFd().release());
+#endif
+ NotifyCallback reply_callback(base::Bind(&ChildProcessLauncher::DidLaunch,
+ weak_factory_.GetWeakPtr(),
+ terminate_child_on_shutdown_));
+ BrowserThread::PostTask(
+ BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
+ base::Bind(&LaunchOnLauncherThread, reply_callback, client_thread_id_,
+ child_process_id, delegate,
+#if defined(OS_ANDROID)
+ base::Passed(&ipcfd),
+#endif
+ cmd_line));
}
-base::TerminationStatus ChildProcessLauncher::GetChildTerminationStatus(
- bool known_dead,
- int* exit_code) {
- if (!context_->process_.IsValid()) {
- // Process is already gone, so return the cached termination status.
- if (exit_code)
- *exit_code = context_->exit_code_;
- return context_->termination_status_;
- }
+void ChildProcessLauncher::UpdateTerminationStatus(bool known_dead) {
+ DCHECK(CalledOnValidThread());
#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
- if (context_->zygote_) {
- context_->termination_status_ = ZygoteHostImpl::GetInstance()->
- GetTerminationStatus(context_->process_.Handle(), known_dead,
- &context_->exit_code_);
+ if (zygote_) {
+ termination_status_ = ZygoteHostImpl::GetInstance()->
+ GetTerminationStatus(process_.Handle(), known_dead, &exit_code_);
} else if (known_dead) {
- context_->termination_status_ =
- base::GetKnownDeadTerminationStatus(context_->process_.Handle(),
- &context_->exit_code_);
+ termination_status_ =
+ base::GetKnownDeadTerminationStatus(process_.Handle(), &exit_code_);
} else {
#elif defined(OS_MACOSX)
if (known_dead) {
- context_->termination_status_ =
- base::GetKnownDeadTerminationStatus(context_->process_.Handle(),
- &context_->exit_code_);
+ termination_status_ =
+ base::GetKnownDeadTerminationStatus(process_.Handle(), &exit_code_);
} else {
#elif defined(OS_ANDROID)
- if (IsChildProcessOomProtected(context_->process_.Handle())) {
- context_->termination_status_ = base::TERMINATION_STATUS_OOM_PROTECTED;
+ if (IsChildProcessOomProtected(process_.Handle())) {
+ termination_status_ = base::TERMINATION_STATUS_OOM_PROTECTED;
} else {
#else
{
#endif
- context_->GetTerminationStatus();
+ termination_status_ =
+ base::GetTerminationStatus(process_.Handle(), &exit_code_);
}
+}
+void ChildProcessLauncher::SetProcessBackgrounded(bool background) {
+ DCHECK(CalledOnValidThread());
+ base::Process to_pass = process_.Duplicate();
+ BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
+ base::Bind(&SetProcessBackgroundedOnLauncherThread,
+ base::Passed(&to_pass), background));
+}
+
+void ChildProcessLauncher::DidLaunch(
+ base::WeakPtr<ChildProcessLauncher> instance,
+ bool terminate_on_shutdown,
+ bool zygote,
+#if defined(OS_ANDROID)
+ base::ScopedFD ipcfd,
+#endif
+ base::Process process) {
+ if (!process.IsValid())
+ LOG(ERROR) << "Failed to launch child process";
+
+ // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile1(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "465841 ChildProcessLauncher::Context::Notify::Start"));
+
+ if (instance.get()) {
+ instance->Notify(zygote,
+#if defined(OS_ANDROID)
+ ipcfd.Pass(),
+#endif
+ process.Pass());
+ } else {
+ // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile4(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "465841 ChildProcessLauncher::Context::Notify::ProcessTerminate"));
+ if (process.IsValid() && terminate_on_shutdown) {
+ // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So
+ // don't this on the UI/IO threads.
+ BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
+ base::Bind(&TerminateOnLauncherThread, zygote,
+ base::Passed(&process)));
+ }
+ }
+}
+
+void ChildProcessLauncher::Notify(
+ bool zygote,
+#if defined(OS_ANDROID)
+ base::ScopedFD ipcfd,
+#endif
+ base::Process process) {
+ DCHECK(CalledOnValidThread());
+ starting_ = false;
+ process_ = process.Pass();
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
+ zygote_ = zygote;
+#endif
+ if (process_.IsValid()) {
+ // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile2(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "465841 ChildProcessLauncher::Context::Notify::ProcessLaunched"));
+ client_->OnProcessLaunched();
+ } else {
+ // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile3(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "465841 ChildProcessLauncher::Context::Notify::ProcessFailed"));
+ client_->OnProcessLaunchFailed();
+ }
+}
+
+bool ChildProcessLauncher::IsStarting() {
+ // TODO(crbug.com/469248): This fails in some tests.
+ // DCHECK(CalledOnValidThread());
+ return starting_;
+}
+
+const base::Process& ChildProcessLauncher::GetProcess() const {
+ // TODO(crbug.com/469248): This fails in some tests.
+ // DCHECK(CalledOnValidThread());
+ return process_;
+}
+
+base::TerminationStatus ChildProcessLauncher::GetChildTerminationStatus(
+ bool known_dead,
+ int* exit_code) {
+ DCHECK(CalledOnValidThread());
+ if (!process_.IsValid()) {
+ // Process is already gone, so return the cached termination status.
+ if (exit_code)
+ *exit_code = exit_code_;
+ return termination_status_;
+ }
+
+ UpdateTerminationStatus(known_dead);
if (exit_code)
- *exit_code = context_->exit_code_;
+ *exit_code = exit_code_;
// POSIX: If the process crashed, then the kernel closed the socket
// for it and so the child has already died by the time we get
@@ -514,20 +494,17 @@ base::TerminationStatus ChildProcessLauncher::GetChildTerminationStatus(
// it'll reap the process. However, if GetTerminationStatus didn't
// reap the child (because it was still running), we'll need to
// Terminate via ProcessWatcher. So we can't close the handle here.
- if (context_->termination_status_ != base::TERMINATION_STATUS_STILL_RUNNING)
- context_->process_.Close();
+ if (termination_status_ != base::TERMINATION_STATUS_STILL_RUNNING)
+ process_.Close();
- return context_->termination_status_;
+ return termination_status_;
}
-void ChildProcessLauncher::SetProcessBackgrounded(bool background) {
- context_->SetProcessBackgrounded(background);
-}
-
-void ChildProcessLauncher::SetTerminateChildOnShutdown(
- bool terminate_on_shutdown) {
- if (context_.get())
- context_->set_terminate_child_on_shutdown(terminate_on_shutdown);
+ChildProcessLauncher::Client* ChildProcessLauncher::ReplaceClientForTest(
+ Client* client) {
+ Client* ret = client_;
+ client_ = client;
+ return ret;
}
} // namespace content
diff --git a/chromium/content/browser/child_process_launcher.h b/chromium/content/browser/child_process_launcher.h
index de890a92e40..2d647f40877 100644
--- a/chromium/content/browser/child_process_launcher.h
+++ b/chromium/content/browser/child_process_launcher.h
@@ -6,11 +6,14 @@
#define CONTENT_BROWSER_CHILD_PROCESS_LAUNCHER_H_
#include "base/basictypes.h"
-#include "base/memory/ref_counted.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/weak_ptr.h"
#include "base/process/kill.h"
#include "base/process/launch.h"
#include "base/process/process.h"
+#include "base/threading/non_thread_safe.h"
#include "content/common/content_export.h"
+#include "content/public/browser/browser_thread.h"
namespace base {
class CommandLine;
@@ -22,7 +25,7 @@ class SandboxedProcessLauncherDelegate;
// Launches a process asynchronously and notifies the client of the process
// handle when it's available. It's used to avoid blocking the calling thread
// on the OS since often it can take > 100 ms to create the process.
-class CONTENT_EXPORT ChildProcessLauncher {
+class CONTENT_EXPORT ChildProcessLauncher : public base::NonThreadSafe {
public:
class CONTENT_EXPORT Client {
public:
@@ -45,7 +48,8 @@ class CONTENT_EXPORT ChildProcessLauncher {
SandboxedProcessLauncherDelegate* delegate,
base::CommandLine* cmd_line,
int child_process_id,
- Client* client);
+ Client* client,
+ bool terminate_on_shutdown = true);
~ChildProcessLauncher();
// True if the process is being launched and so the handle isn't available.
@@ -72,14 +76,49 @@ class CONTENT_EXPORT ChildProcessLauncher {
// this after the process has started.
void SetProcessBackgrounded(bool background);
- // Controls whether the child process should be terminated on browser
- // shutdown.
- void SetTerminateChildOnShutdown(bool terminate_on_shutdown);
+ // Replaces the ChildProcessLauncher::Client for testing purposes. Returns the
+ // previous client.
+ Client* ReplaceClientForTest(Client* client);
private:
- class Context;
+ // Posts a task to the launcher thread to do the actual work.
+ void Launch(SandboxedProcessLauncherDelegate* delegate,
+ base::CommandLine* cmd_line,
+ int child_process_id);
+
+ void UpdateTerminationStatus(bool known_dead);
+
+ // This is always called on the client thread after an attempt
+ // to launch the child process on the launcher thread.
+ // It makes sure we always perform the necessary cleanup if the
+ // client went away.
+ static void DidLaunch(base::WeakPtr<ChildProcessLauncher> instance,
+ bool terminate_on_shutdown,
+ bool zygote,
+#if defined(OS_ANDROID)
+ base::ScopedFD ipcfd,
+#endif
+ base::Process process);
+
+ // Notifies the client about the result of the operation.
+ void Notify(bool zygote,
+#if defined(OS_ANDROID)
+ base::ScopedFD ipcfd,
+#endif
+ base::Process process);
+
+ Client* client_;
+ BrowserThread::ID client_thread_id_;
+ base::Process process_;
+ base::TerminationStatus termination_status_;
+ int exit_code_;
+ bool zygote_;
+ bool starting_;
+ // Controls whether the child process should be terminated on browser
+ // shutdown. Default behavior is to terminate the child.
+ const bool terminate_child_on_shutdown_;
- scoped_refptr<Context> context_;
+ base::WeakPtrFactory<ChildProcessLauncher> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ChildProcessLauncher);
};
diff --git a/chromium/content/browser/child_process_launcher_browsertest.cc b/chromium/content/browser/child_process_launcher_browsertest.cc
index fe3fa1da32b..9ef655c6fc6 100644
--- a/chromium/content/browser/child_process_launcher_browsertest.cc
+++ b/chromium/content/browser/child_process_launcher_browsertest.cc
@@ -3,13 +3,41 @@
// found in the LICENSE file.
#include "base/command_line.h"
+#include "content/browser/child_process_launcher.h"
+#include "content/browser/renderer_host/render_process_host_impl.h"
+#include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/web_contents.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"
+#include "content/public/test/test_navigation_observer.h"
+#include "content/shell/browser/shell.h"
+
+namespace {
+
+class MockChildProcessLauncherClient
+ : public content::ChildProcessLauncher::Client {
+ public:
+ MockChildProcessLauncherClient()
+ : client_(nullptr), simulate_failure_(false) {}
+
+ void OnProcessLaunched() override {
+ if (simulate_failure_)
+ client_->OnProcessLaunchFailed();
+ else
+ client_->OnProcessLaunched();
+ };
+ void OnProcessLaunchFailed() override { client_->OnProcessLaunchFailed(); };
+
+ content::ChildProcessLauncher::Client* client_;
+ bool simulate_failure_;
+};
+
+}
namespace content {
-typedef ContentBrowserTest ChildProcessLauncherBrowserTest;
+class ChildProcessLauncherBrowserTest : public ContentBrowserTest {};
class StatsTableBrowserTest : public ChildProcessLauncherBrowserTest {
public:
@@ -22,4 +50,44 @@ IN_PROC_BROWSER_TEST_F(StatsTableBrowserTest, StartWithStatTable) {
NavigateToURL(shell(), GURL("about:blank"));
}
+IN_PROC_BROWSER_TEST_F(ChildProcessLauncherBrowserTest, ChildSpawnFail) {
+ GURL url("about:blank");
+ Shell* window = shell();
+ MockChildProcessLauncherClient* client(nullptr);
+
+ // Navigate once and simulate a process failing to spawn.
+ TestNavigationObserver nav_observer1(window->web_contents(), 1);
+ client = new MockChildProcessLauncherClient;
+ window->LoadURL(url);
+ client->client_ = static_cast<RenderProcessHostImpl*>(
+ window->web_contents()->GetRenderProcessHost())
+ ->child_process_launcher_->ReplaceClientForTest(client);
+ client->simulate_failure_ = true;
+ nav_observer1.Wait();
+ delete client;
+ NavigationEntry* last_entry =
+ shell()->web_contents()->GetController().GetLastCommittedEntry();
+ // Make sure we didn't navigate.
+ CHECK(!last_entry);
+
+ // Navigate again and let the process spawn correctly.
+ TestNavigationObserver nav_observer2(window->web_contents(), 1);
+ window->LoadURL(url);
+ nav_observer2.Wait();
+ last_entry = shell()->web_contents()->GetController().GetLastCommittedEntry();
+ // Make sure that we navigated to the proper URL.
+ CHECK(last_entry && last_entry->GetPageType() == PAGE_TYPE_NORMAL);
+ CHECK(shell()->web_contents()->GetLastCommittedURL() == url);
+
+ // Navigate again, using the same renderer.
+ url = GURL("data:text/html,dataurl");
+ TestNavigationObserver nav_observer3(window->web_contents(), 1);
+ window->LoadURL(url);
+ nav_observer3.Wait();
+ last_entry = shell()->web_contents()->GetController().GetLastCommittedEntry();
+ // Make sure that we navigated to the proper URL.
+ CHECK(last_entry && last_entry->GetPageType() == PAGE_TYPE_NORMAL);
+ CHECK(shell()->web_contents()->GetLastCommittedURL() == url);
+}
+
} // 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 b509a494706..c1e3c3959e9 100644
--- a/chromium/content/browser/child_process_security_policy_browsertest.cc
+++ b/chromium/content/browser/child_process_security_policy_browsertest.cc
@@ -48,8 +48,7 @@ IN_PROC_BROWSER_TEST_F(ChildProcessSecurityPolicyInProcessBrowserTest, NoLeak) {
1U);
WebContents* web_contents = shell()->web_contents();
- base::KillProcess(web_contents->GetRenderProcessHost()->GetHandle(),
- RESULT_CODE_KILLED, true);
+ web_contents->GetRenderProcessHost()->Shutdown(RESULT_CODE_KILLED, true);
web_contents->GetController().Reload(true);
EXPECT_EQ(
diff --git a/chromium/content/browser/child_process_security_policy_impl.h b/chromium/content/browser/child_process_security_policy_impl.h
index dcc1b887fab..db673c1bdaf 100644
--- a/chromium/content/browser/child_process_security_policy_impl.h
+++ b/chromium/content/browser/child_process_security_policy_impl.h
@@ -73,6 +73,7 @@ class CONTENT_EXPORT ChildProcessSecurityPolicyImpl
bool CanDeleteFromFileSystem(int child_id,
const std::string& filesystem_id) override;
bool HasWebUIBindings(int child_id) override;
+ void GrantSendMidiSysExMessage(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
@@ -119,9 +120,6 @@ class CONTENT_EXPORT ChildProcessSecurityPolicyImpl
// Revoke read raw cookies permission.
void RevokeReadRawCookies(int child_id);
- // Grants permission to send system exclusive message to any MIDI devices.
- void GrantSendMidiSysExMessage(int child_id);
-
// Before servicing a child process's request for a URL, the browser should
// call this method to determine whether the process has the capability to
// request the URL.
diff --git a/chromium/content/browser/cocoa/system_hotkey_helper_mac.mm b/chromium/content/browser/cocoa/system_hotkey_helper_mac.mm
index 68c52820ef3..7e79572a1a2 100644
--- a/chromium/content/browser/cocoa/system_hotkey_helper_mac.mm
+++ b/chromium/content/browser/cocoa/system_hotkey_helper_mac.mm
@@ -45,7 +45,7 @@ SystemHotkeyHelperMac::~SystemHotkeyHelperMac() {
}
void SystemHotkeyHelperMac::LoadSystemHotkeys() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
std::string library_path(base::mac::GetUserLibraryPath().value());
NSString* expanded_file_path =
@@ -67,7 +67,7 @@ void SystemHotkeyHelperMac::LoadSystemHotkeys() {
}
void SystemHotkeyHelperMac::FileDidLoad(NSDictionary* dictionary) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
bool success = map()->ParseDictionary(dictionary);
UMA_HISTOGRAM_BOOLEAN("OSX.SystemHotkeyMap.LoadSuccess", success);
diff --git a/chromium/content/browser/cocoa/system_hotkey_map_unittest.mm b/chromium/content/browser/cocoa/system_hotkey_map_unittest.mm
index 6b2652fb426..37638d472ac 100644
--- a/chromium/content/browser/cocoa/system_hotkey_map_unittest.mm
+++ b/chromium/content/browser/cocoa/system_hotkey_map_unittest.mm
@@ -56,7 +56,7 @@ class SystemHotkeyMapTest : public ::testing::Test {
++count_;
}
- virtual void SetUp() override {
+ 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_
@@ -64,7 +64,7 @@ class SystemHotkeyMapTest : public ::testing::Test {
count_ = 100;
}
- virtual void TearDown() override {
+ void TearDown() override {
system_hotkey_dictionary_.reset();
system_hotkey_inner_dictionary_.reset();
}
diff --git a/chromium/content/browser/compositor/DEPS b/chromium/content/browser/compositor/DEPS
new file mode 100644
index 00000000000..1701f72a861
--- /dev/null
+++ b/chromium/content/browser/compositor/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+ui/platform_window",
+]
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
deleted file mode 100644
index b342035ed5f..00000000000
--- a/chromium/content/browser/compositor/browser_compositor_ca_layer_tree_mac.h
+++ /dev/null
@@ -1,136 +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_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
deleted file mode 100644
index 3abee8cd763..00000000000
--- a/chromium/content/browser/compositor/browser_compositor_ca_layer_tree_mac.mm
+++ /dev/null
@@ -1,406 +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/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 0c650ca9f3e..2038725bc86 100644
--- a/chromium/content/browser/compositor/browser_compositor_output_surface.cc
+++ b/chromium/content/browser/compositor/browser_compositor_output_surface.cc
@@ -7,63 +7,52 @@
#include "base/bind.h"
#include "base/location.h"
#include "base/strings/string_number_conversions.h"
+#include "content/browser/compositor/browser_compositor_overlay_candidate_validator.h"
#include "content/browser/compositor/reflector_impl.h"
#include "content/common/gpu/client/context_provider_command_buffer.h"
namespace content {
BrowserCompositorOutputSurface::BrowserCompositorOutputSurface(
- const scoped_refptr<ContextProviderCommandBuffer>& context_provider,
- int surface_id,
- IDMap<BrowserCompositorOutputSurface>* output_surface_map,
- const scoped_refptr<ui::CompositorVSyncManager>& vsync_manager)
+ const scoped_refptr<cc::ContextProvider>& context_provider,
+ const scoped_refptr<ui::CompositorVSyncManager>& vsync_manager,
+ scoped_ptr<BrowserCompositorOverlayCandidateValidator>
+ overlay_candidate_validator)
: OutputSurface(context_provider),
- surface_id_(surface_id),
- output_surface_map_(output_surface_map),
- vsync_manager_(vsync_manager) {
+ vsync_manager_(vsync_manager),
+ reflector_(nullptr) {
+ overlay_candidate_validator_ = overlay_candidate_validator.Pass();
Initialize();
}
BrowserCompositorOutputSurface::BrowserCompositorOutputSurface(
scoped_ptr<cc::SoftwareOutputDevice> software_device,
- int surface_id,
- IDMap<BrowserCompositorOutputSurface>* output_surface_map,
const scoped_refptr<ui::CompositorVSyncManager>& vsync_manager)
: OutputSurface(software_device.Pass()),
- surface_id_(surface_id),
- output_surface_map_(output_surface_map),
- vsync_manager_(vsync_manager) {
+ vsync_manager_(vsync_manager),
+ reflector_(nullptr) {
Initialize();
}
BrowserCompositorOutputSurface::~BrowserCompositorOutputSurface() {
- DCHECK(CalledOnValidThread());
- if (reflector_.get())
+ if (reflector_)
reflector_->DetachFromOutputSurface();
- DCHECK(!reflector_.get());
+ DCHECK(!reflector_);
if (!HasClient())
return;
- output_surface_map_->Remove(surface_id_);
vsync_manager_->RemoveObserver(this);
}
void BrowserCompositorOutputSurface::Initialize() {
capabilities_.max_frames_pending = 1;
capabilities_.adjust_deadline_for_parent = false;
-
- DetachFromThread();
}
bool BrowserCompositorOutputSurface::BindToClient(
cc::OutputSurfaceClient* client) {
- DCHECK(CalledOnValidThread());
-
if (!OutputSurface::BindToClient(client))
return false;
-
- output_surface_map_->AddWithID(this, surface_id_);
- if (reflector_.get())
- reflector_->OnSourceSurfaceReady(this);
+ // Don't want vsync notifications until there is a client.
vsync_manager_->AddObserver(this);
return true;
}
@@ -71,7 +60,6 @@ bool BrowserCompositorOutputSurface::BindToClient(
void BrowserCompositorOutputSurface::OnUpdateVSyncParameters(
base::TimeTicks timebase,
base::TimeDelta interval) {
- DCHECK(CalledOnValidThread());
DCHECK(HasClient());
CommitVSyncParameters(timebase, interval);
}
@@ -79,13 +67,32 @@ void BrowserCompositorOutputSurface::OnUpdateVSyncParameters(
void BrowserCompositorOutputSurface::OnUpdateVSyncParametersFromGpu(
base::TimeTicks timebase,
base::TimeDelta interval) {
- DCHECK(CalledOnValidThread());
DCHECK(HasClient());
vsync_manager_->UpdateVSyncParameters(timebase, interval);
}
void BrowserCompositorOutputSurface::SetReflector(ReflectorImpl* reflector) {
+ // Software mirroring is done by doing a GL copy out of the framebuffer - if
+ // we have overlays then that data will be missing.
+ if (overlay_candidate_validator_) {
+ overlay_candidate_validator_->SetSoftwareMirrorMode(reflector != nullptr);
+ }
reflector_ = reflector;
+
+ OnReflectorChanged();
+}
+
+void BrowserCompositorOutputSurface::OnReflectorChanged() {
+}
+
+base::Closure
+BrowserCompositorOutputSurface::CreateCompositionStartedCallback() {
+ return base::Closure();
+}
+
+cc::OverlayCandidateValidator*
+BrowserCompositorOutputSurface::GetOverlayCandidateValidator() const {
+ return overlay_candidate_validator_.get();
}
} // 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 dd538769e76..5c4f30828bf 100644
--- a/chromium/content/browser/compositor/browser_compositor_output_surface.h
+++ b/chromium/content/browser/compositor/browser_compositor_output_surface.h
@@ -5,7 +5,6 @@
#ifndef CONTENT_BROWSER_COMPOSITOR_BROWSER_COMPOSITOR_OUTPUT_SURFACE_H_
#define CONTENT_BROWSER_COMPOSITOR_BROWSER_COMPOSITOR_OUTPUT_SURFACE_H_
-#include "base/id_map.h"
#include "base/threading/non_thread_safe.h"
#include "cc/output/output_surface.h"
#include "content/common/content_export.h"
@@ -16,19 +15,20 @@ class SoftwareOutputDevice;
}
namespace content {
+class BrowserCompositorOverlayCandidateValidator;
class ContextProviderCommandBuffer;
class ReflectorImpl;
class WebGraphicsContext3DCommandBufferImpl;
class CONTENT_EXPORT BrowserCompositorOutputSurface
: public cc::OutputSurface,
- public ui::CompositorVSyncManager::Observer,
- public base::NonThreadSafe {
+ public ui::CompositorVSyncManager::Observer {
public:
~BrowserCompositorOutputSurface() override;
// cc::OutputSurface implementation.
bool BindToClient(cc::OutputSurfaceClient* client) override;
+ cc::OverlayCandidateValidator* GetOverlayCandidateValidator() const override;
// ui::CompositorOutputSurface::Observer implementation.
void OnUpdateVSyncParameters(base::TimeTicks timebase,
@@ -39,34 +39,41 @@ class CONTENT_EXPORT BrowserCompositorOutputSurface
void SetReflector(ReflectorImpl* reflector);
+ // Called when |reflector_| was updated.
+ virtual void OnReflectorChanged();
+
+ // Returns a callback that will be called when all mirroring
+ // compositors have started composition.
+ virtual base::Closure CreateCompositionStartedCallback();
+
#if defined(OS_MACOSX)
virtual void OnSurfaceDisplayed() = 0;
+ virtual void SetSurfaceSuspendedForRecycle(bool suspended) = 0;
+ virtual bool SurfaceShouldNotShowFramesAfterSuspendForRecycle() const = 0;
#endif
protected:
// Constructor used by the accelerated implementation.
BrowserCompositorOutputSurface(
- const scoped_refptr<ContextProviderCommandBuffer>& context,
- int surface_id,
- IDMap<BrowserCompositorOutputSurface>* output_surface_map,
- const scoped_refptr<ui::CompositorVSyncManager>& vsync_manager);
+ const scoped_refptr<cc::ContextProvider>& context,
+ const scoped_refptr<ui::CompositorVSyncManager>& vsync_manager,
+ scoped_ptr<BrowserCompositorOverlayCandidateValidator>
+ overlay_candidate_validator);
// Constructor used by the software implementation.
BrowserCompositorOutputSurface(
scoped_ptr<cc::SoftwareOutputDevice> software_device,
- int surface_id,
- IDMap<BrowserCompositorOutputSurface>* output_surface_map,
const scoped_refptr<ui::CompositorVSyncManager>& vsync_manager);
- int surface_id_;
- IDMap<BrowserCompositorOutputSurface>* output_surface_map_;
-
scoped_refptr<ui::CompositorVSyncManager> vsync_manager_;
- scoped_refptr<ReflectorImpl> reflector_;
+ ReflectorImpl* reflector_;
private:
void Initialize();
+ scoped_ptr<BrowserCompositorOverlayCandidateValidator>
+ overlay_candidate_validator_;
+
DISALLOW_COPY_AND_ASSIGN(BrowserCompositorOutputSurface);
};
diff --git a/chromium/content/browser/compositor/browser_compositor_output_surface_proxy.cc b/chromium/content/browser/compositor/browser_compositor_output_surface_proxy.cc
deleted file mode 100644
index 27fe55a7ea9..00000000000
--- a/chromium/content/browser/compositor/browser_compositor_output_surface_proxy.cc
+++ /dev/null
@@ -1,58 +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/browser_compositor_output_surface_proxy.h"
-
-#include "base/bind.h"
-#include "content/browser/compositor/browser_compositor_output_surface.h"
-#include "content/browser/gpu/browser_gpu_channel_host_factory.h"
-#include "content/common/gpu/gpu_messages.h"
-
-namespace content {
-
-BrowserCompositorOutputSurfaceProxy::BrowserCompositorOutputSurfaceProxy(
- IDMap<BrowserCompositorOutputSurface>* surface_map)
- : surface_map_(surface_map),
- connected_to_gpu_process_host_id_(0) {}
-
-BrowserCompositorOutputSurfaceProxy::~BrowserCompositorOutputSurfaceProxy() {}
-
-void BrowserCompositorOutputSurfaceProxy::ConnectToGpuProcessHost(
- base::SingleThreadTaskRunner* compositor_thread_task_runner) {
- BrowserGpuChannelHostFactory* factory =
- BrowserGpuChannelHostFactory::instance();
-
- int gpu_process_host_id = factory->GpuProcessHostId();
- if (connected_to_gpu_process_host_id_ == gpu_process_host_id)
- return;
-
- const uint32 kMessagesToFilter[] = { GpuHostMsg_UpdateVSyncParameters::ID };
- factory->SetHandlerForControlMessages(
- kMessagesToFilter,
- arraysize(kMessagesToFilter),
- base::Bind(&BrowserCompositorOutputSurfaceProxy::
- OnMessageReceivedOnCompositorThread,
- this),
- compositor_thread_task_runner);
- connected_to_gpu_process_host_id_ = gpu_process_host_id;
-}
-
-void BrowserCompositorOutputSurfaceProxy::OnMessageReceivedOnCompositorThread(
- const IPC::Message& message) {
- IPC_BEGIN_MESSAGE_MAP(BrowserCompositorOutputSurfaceProxy, message)
- IPC_MESSAGE_HANDLER(GpuHostMsg_UpdateVSyncParameters,
- OnUpdateVSyncParametersOnCompositorThread);
- IPC_END_MESSAGE_MAP()
-}
-
-void
-BrowserCompositorOutputSurfaceProxy::OnUpdateVSyncParametersOnCompositorThread(
- int surface_id,
- base::TimeTicks timebase,
- base::TimeDelta interval) {
- BrowserCompositorOutputSurface* surface = surface_map_->Lookup(surface_id);
- if (surface)
- surface->OnUpdateVSyncParametersFromGpu(timebase, interval);
-}
-} // namespace content
diff --git a/chromium/content/browser/compositor/browser_compositor_output_surface_proxy.h b/chromium/content/browser/compositor/browser_compositor_output_surface_proxy.h
deleted file mode 100644
index 644516ea665..00000000000
--- a/chromium/content/browser/compositor/browser_compositor_output_surface_proxy.h
+++ /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.
-
-#ifndef CONTENT_BROWSER_COMPOSITOR_BROWSER_COMPOSITOR_OUTPUT_SURFACE_PROXY_H_
-#define CONTENT_BROWSER_COMPOSITOR_BROWSER_COMPOSITOR_OUTPUT_SURFACE_PROXY_H_
-
-#include "base/id_map.h"
-#include "base/memory/ref_counted.h"
-#include "base/time/time.h"
-#include "content/common/content_export.h"
-
-namespace base { class SingleThreadTaskRunner; }
-
-namespace IPC { class Message; }
-
-namespace content {
-class BrowserCompositorOutputSurface;
-
-// Directs vsync updates to the appropriate BrowserCompositorOutputSurface.
-class CONTENT_EXPORT BrowserCompositorOutputSurfaceProxy
- : public base::RefCountedThreadSafe<BrowserCompositorOutputSurfaceProxy> {
- public:
- BrowserCompositorOutputSurfaceProxy(
- IDMap<BrowserCompositorOutputSurface>* surface_map);
-
- // Call this before each OutputSurface is created to ensure that the
- // proxy is connected to the current host.
- void ConnectToGpuProcessHost(
- base::SingleThreadTaskRunner* compositor_thread_task_runner);
-
- private:
- friend class base::RefCountedThreadSafe<BrowserCompositorOutputSurfaceProxy>;
- friend class SoftwareBrowserCompositorOutputSurface;
- ~BrowserCompositorOutputSurfaceProxy();
-
- void OnMessageReceivedOnCompositorThread(const IPC::Message& message);
-
- void OnUpdateVSyncParametersOnCompositorThread(int surface_id,
- base::TimeTicks timebase,
- base::TimeDelta interval);
-
- IDMap<BrowserCompositorOutputSurface>* surface_map_;
- int connected_to_gpu_process_host_id_;
-
- DISALLOW_COPY_AND_ASSIGN(BrowserCompositorOutputSurfaceProxy);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_COMPOSITOR_BROWSER_COMPOSITOR_OUTPUT_SURFACE_PROXY_H_
diff --git a/chromium/content/browser/compositor/browser_compositor_overlay_candidate_validator.h b/chromium/content/browser/compositor/browser_compositor_overlay_candidate_validator.h
new file mode 100644
index 00000000000..0c62e2bb14d
--- /dev/null
+++ b/chromium/content/browser/compositor/browser_compositor_overlay_candidate_validator.h
@@ -0,0 +1,28 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_COMPOSITOR_BROWSER_COMPOSITOR_OVERLAY_CANDIDATE_VALIDATOR_H_
+#define CONTENT_BROWSER_COMPOSITOR_BROWSER_COMPOSITOR_OVERLAY_CANDIDATE_VALIDATOR_H_
+
+#include "cc/output/overlay_candidate_validator.h"
+
+#include "content/common/content_export.h"
+
+namespace content {
+
+class CONTENT_EXPORT BrowserCompositorOverlayCandidateValidator
+ : public cc::OverlayCandidateValidator {
+ public:
+ BrowserCompositorOverlayCandidateValidator() {}
+ ~BrowserCompositorOverlayCandidateValidator() override {}
+
+ virtual void SetSoftwareMirrorMode(bool enabled) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BrowserCompositorOverlayCandidateValidator);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_COMPOSITOR_BROWSER_COMPOSITOR_OVERLAY_CANDIDATE_VALIDATOR_H_
diff --git a/chromium/content/browser/compositor/browser_compositor_overlay_candidate_validator_ozone.cc b/chromium/content/browser/compositor/browser_compositor_overlay_candidate_validator_ozone.cc
new file mode 100644
index 00000000000..a646ac97be4
--- /dev/null
+++ b/chromium/content/browser/compositor/browser_compositor_overlay_candidate_validator_ozone.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/compositor/browser_compositor_overlay_candidate_validator_ozone.h"
+
+#include "ui/ozone/public/overlay_candidates_ozone.h"
+
+namespace content {
+
+static ui::SurfaceFactoryOzone::BufferFormat GetOzoneFormat(
+ cc::ResourceFormat overlay_format) {
+ switch (overlay_format) {
+ // TODO(dshwang): overlay video still uses RGBA_8888.
+ case cc::RGBA_8888:
+ case cc::BGRA_8888:
+ return ui::SurfaceFactoryOzone::BGRA_8888;
+ case cc::RGBA_4444:
+ case cc::ALPHA_8:
+ case cc::LUMINANCE_8:
+ case cc::RGB_565:
+ case cc::ETC1:
+ case cc::RED_8:
+ break;
+ }
+ NOTREACHED();
+ return ui::SurfaceFactoryOzone::UNKNOWN;
+}
+
+BrowserCompositorOverlayCandidateValidatorOzone::
+ BrowserCompositorOverlayCandidateValidatorOzone(
+ gfx::AcceleratedWidget widget,
+ ui::OverlayCandidatesOzone* overlay_candidates)
+ : widget_(widget),
+ overlay_candidates_(overlay_candidates),
+ software_mirror_active_(false) {
+}
+
+BrowserCompositorOverlayCandidateValidatorOzone::
+ ~BrowserCompositorOverlayCandidateValidatorOzone() {
+}
+
+void BrowserCompositorOverlayCandidateValidatorOzone::CheckOverlaySupport(
+ cc::OverlayCandidateList* surfaces) {
+ // SW mirroring copies out of the framebuffer, so we can't remove any
+ // quads for overlaying, otherwise the output is incorrect.
+ if (software_mirror_active_)
+ return;
+
+ DCHECK_GE(2U, surfaces->size());
+ ui::OverlayCandidatesOzone::OverlaySurfaceCandidateList ozone_surface_list;
+ ozone_surface_list.resize(surfaces->size());
+
+ for (size_t i = 0; i < surfaces->size(); i++) {
+ ozone_surface_list.at(i).transform = surfaces->at(i).transform;
+ ozone_surface_list.at(i).format = GetOzoneFormat(surfaces->at(i).format);
+ ozone_surface_list.at(i).display_rect = surfaces->at(i).display_rect;
+ ozone_surface_list.at(i).crop_rect = surfaces->at(i).uv_rect;
+ ozone_surface_list.at(i).plane_z_order = surfaces->at(i).plane_z_order;
+ }
+
+ overlay_candidates_->CheckOverlaySupport(&ozone_surface_list);
+ DCHECK_EQ(surfaces->size(), ozone_surface_list.size());
+
+ for (size_t i = 0; i < surfaces->size(); i++) {
+ surfaces->at(i).overlay_handled = ozone_surface_list.at(i).overlay_handled;
+ surfaces->at(i).display_rect = ozone_surface_list.at(i).display_rect;
+ }
+}
+
+void BrowserCompositorOverlayCandidateValidatorOzone::SetSoftwareMirrorMode(
+ bool enabled) {
+ software_mirror_active_ = enabled;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/compositor/browser_compositor_overlay_candidate_validator_ozone.h b/chromium/content/browser/compositor/browser_compositor_overlay_candidate_validator_ozone.h
new file mode 100644
index 00000000000..744d864d82f
--- /dev/null
+++ b/chromium/content/browser/compositor/browser_compositor_overlay_candidate_validator_ozone.h
@@ -0,0 +1,41 @@
+// Copyright 2014 The Chromium Authors. 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_OVERLAY_CANDIDATE_VALIDATOR_OZONE_H_
+#define CONTENT_BROWSER_COMPOSITOR_OVERLAY_CANDIDATE_VALIDATOR_OZONE_H_
+
+#include "content/browser/compositor/browser_compositor_overlay_candidate_validator.h"
+#include "ui/gfx/native_widget_types.h"
+
+namespace ui {
+class OverlayCandidatesOzone;
+}
+
+namespace content {
+
+class CONTENT_EXPORT BrowserCompositorOverlayCandidateValidatorOzone
+ : public BrowserCompositorOverlayCandidateValidator {
+ public:
+ BrowserCompositorOverlayCandidateValidatorOzone(
+ gfx::AcceleratedWidget widget,
+ ui::OverlayCandidatesOzone* overlay_candidates);
+ ~BrowserCompositorOverlayCandidateValidatorOzone() override;
+
+ // cc::OverlayCandidateValidator implementation.
+ void CheckOverlaySupport(cc::OverlayCandidateList* surfaces) override;
+
+ // BrowserCompositorOverlayCandidateValidator implementation.
+ void SetSoftwareMirrorMode(bool enabled) override;
+
+ private:
+ gfx::AcceleratedWidget widget_;
+ ui::OverlayCandidatesOzone* overlay_candidates_;
+ bool software_mirror_active_;
+
+ DISALLOW_COPY_AND_ASSIGN(BrowserCompositorOverlayCandidateValidatorOzone);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_COMPOSITOR_OVERLAY_CANDIDATE_VALIDATOR_OZONE_H_
diff --git a/chromium/content/browser/compositor/browser_compositor_view_mac.h b/chromium/content/browser/compositor/browser_compositor_view_mac.h
index 619aef55edd..28b824eedc9 100644
--- a/chromium/content/browser/compositor/browser_compositor_view_mac.h
+++ b/chromium/content/browser/compositor/browser_compositor_view_mac.h
@@ -5,85 +5,71 @@
#ifndef CONTENT_BROWSER_COMPOSITOR_BROWSER_COMPOSITOR_VIEW_MAC_H_
#define CONTENT_BROWSER_COMPOSITOR_BROWSER_COMPOSITOR_VIEW_MAC_H_
-#include <vector>
-
-#include "cc/output/software_frame_data.h"
-#include "skia/ext/platform_canvas.h"
+#include "ui/accelerated_widget_mac/accelerated_widget_mac.h"
#include "ui/compositor/compositor.h"
-#include "ui/events/latency_info.h"
-#include "ui/gfx/geometry/size.h"
+#include "ui/compositor/compositor_observer.h"
namespace content {
-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 {
+// A ui::Compositor and a gfx::AcceleratedWidget (and helper) that it draws
+// into. This structure is used to efficiently recycle these structures across
+// tabs (because creating a new ui::Compositor for each tab would be expensive
+// in terms of time and resources).
+class BrowserCompositorMac : public ui::CompositorObserver {
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;
-};
+ virtual ~BrowserCompositorMac();
-// 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();
+ // Create a compositor, or recycle a preexisting one.
+ static scoped_ptr<BrowserCompositorMac> Create();
+
+ // Delete a compositor, or allow it to be recycled.
+ static void Recycle(scoped_ptr<BrowserCompositorMac> compositor);
+
+ // Indicate that the recyclable compositor should be destroyed, and no future
+ // compositors should be recycled.
+ static void DisableRecyclingForShutdown();
+
+ ui::Compositor* compositor() { return &compositor_; }
+ ui::AcceleratedWidgetMac* accelerated_widget_mac() {
+ return accelerated_widget_mac_.get();
+ }
+
+ // Suspend will prevent the compositor from producing new frames. This should
+ // be called to avoid creating spurious frames while changing state.
+ // Compositors are created as suspended.
+ void Suspend();
+ void Unsuspend();
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_;
+ BrowserCompositorMac();
+
+ // ui::CompositorObserver implementation:
+ void OnCompositingDidCommit(ui::Compositor* compositor) override;
+ void OnCompositingStarted(ui::Compositor* compositor,
+ base::TimeTicks start_time) override {}
+ void OnCompositingEnded(ui::Compositor* compositor) override {}
+ void OnCompositingAborted(ui::Compositor* compositor) override {}
+ void OnCompositingLockStateChanged(ui::Compositor* compositor) override {}
+ void OnCompositingShuttingDown(ui::Compositor* compositor) override {}
+
+ scoped_ptr<ui::AcceleratedWidgetMac> accelerated_widget_mac_;
+ ui::Compositor compositor_;
+ scoped_refptr<ui::CompositorLock> compositor_suspended_lock_;
+
+ DISALLOW_COPY_AND_ASSIGN(BrowserCompositorMac);
};
-// A class to keep around whenever a BrowserCompositorViewMac may be created.
+// A class to keep around whenever a BrowserCompositorMac 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 {
+// next BrowserCompositorMac to be created will be be created quickly.
+class BrowserCompositorMacPlaceholder {
public:
- BrowserCompositorViewPlaceholderMac();
- ~BrowserCompositorViewPlaceholderMac();
+ BrowserCompositorMacPlaceholder();
+ ~BrowserCompositorMacPlaceholder();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BrowserCompositorMacPlaceholder);
};
} // namespace content
diff --git a/chromium/content/browser/compositor/browser_compositor_view_mac.mm b/chromium/content/browser/compositor/browser_compositor_view_mac.mm
index b38edce89ae..472c17fab83 100644
--- a/chromium/content/browser/compositor/browser_compositor_view_mac.mm
+++ b/chromium/content/browser/compositor/browser_compositor_view_mac.mm
@@ -4,95 +4,120 @@
#include "content/browser/compositor/browser_compositor_view_mac.h"
-#include "base/debug/trace_event.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"
+#include "base/trace_event/trace_event.h"
+#include "content/browser/compositor/image_transport_factory.h"
+#include "content/browser/gpu/gpu_data_manager_impl.h"
+#include "content/browser/renderer_host/render_widget_resize_helper.h"
+#include "content/public/browser/context_factory.h"
+#include "gpu/config/gpu_driver_bug_workaround_type.h"
+#include "ui/accelerated_widget_mac/accelerated_widget_mac.h"
////////////////////////////////////////////////////////////////////////////////
-// BrowserCompositorViewMac
+// BrowserCompositorMac
namespace content {
+
namespace {
+// Set when no browser compositors should remain alive.
+bool g_has_shut_down = false;
+
// 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.
+// the BrowserCompositorMac being held on to for recycling,
+// |g_recyclable_browser_compositor|, 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;
+// A spare BrowserCompositorMac kept around for recycling.
+base::LazyInstance<scoped_ptr<BrowserCompositorMac>>
+ g_recyclable_browser_compositor;
+
+bool WidgetNeedsGLFinishWorkaround() {
+ return GpuDataManagerImpl::GetInstance()->IsDriverBugWorkaroundActive(
+ gpu::FORCE_GL_FINISH_AFTER_COMPOSITING);
+}
} // 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);
+BrowserCompositorMac::BrowserCompositorMac()
+ : accelerated_widget_mac_(
+ new ui::AcceleratedWidgetMac(WidgetNeedsGLFinishWorkaround())),
+ compositor_(
+ accelerated_widget_mac_->accelerated_widget(),
+ content::GetContextFactory(),
+ RenderWidgetResizeHelper::Get()->task_runner()) {
+ compositor_.SetLocksWillTimeOut(false);
+ Suspend();
+ compositor_.AddObserver(this);
}
-BrowserCompositorViewMac::~BrowserCompositorViewMac() {
- // Make this BrowserCompositorCALayerTreeMac recyclable for future instances.
- ca_layer_tree_->ResetView();
- g_recyclable_ca_layer_tree.Get() = ca_layer_tree_.Pass();
+BrowserCompositorMac::~BrowserCompositorMac() {
+ compositor_.RemoveObserver(this);
+}
- // 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();
+void BrowserCompositorMac::Suspend() {
+ compositor_suspended_lock_ = compositor_.GetCompositorLock();
}
-ui::Compositor* BrowserCompositorViewMac::GetCompositor() const {
- DCHECK(ca_layer_tree_);
- return ca_layer_tree_->compositor();
+void BrowserCompositorMac::Unsuspend() {
+ compositor_suspended_lock_ = nullptr;
}
-bool BrowserCompositorViewMac::HasFrameOfSize(
- const gfx::Size& dip_size) const {
- if (ca_layer_tree_)
- return ca_layer_tree_->HasFrameOfSize(dip_size);
- return false;
+void BrowserCompositorMac::OnCompositingDidCommit(
+ ui::Compositor* compositor_that_did_commit) {
+ DCHECK_EQ(compositor_that_did_commit, compositor());
+ content::ImageTransportFactory::GetInstance()
+ ->SetCompositorSuspendedForRecycle(compositor(), false);
}
-void BrowserCompositorViewMac::BeginPumpingFrames() {
- if (ca_layer_tree_)
- ca_layer_tree_->BeginPumpingFrames();
+// static
+scoped_ptr<BrowserCompositorMac> BrowserCompositorMac::Create() {
+ if (g_recyclable_browser_compositor.Get())
+ return g_recyclable_browser_compositor.Get().Pass();
+ return scoped_ptr<BrowserCompositorMac>(new BrowserCompositorMac).Pass();
+}
+
+// static
+void BrowserCompositorMac::Recycle(
+ scoped_ptr<BrowserCompositorMac> compositor) {
+ DCHECK(compositor);
+ content::ImageTransportFactory::GetInstance()
+ ->SetCompositorSuspendedForRecycle(compositor->compositor(), true);
+
+ // It is an error to have a browser compositor continue to exist after
+ // shutdown.
+ CHECK(!g_has_shut_down);
+
+ // Make this BrowserCompositorMac recyclable for future instances.
+ g_recyclable_browser_compositor.Get().swap(compositor);
+
+ // If there are no placeholders allocated, destroy the recyclable
+ // BrowserCompositorMac that we just populated.
+ if (!g_placeholder_count)
+ g_recyclable_browser_compositor.Get().reset();
}
-void BrowserCompositorViewMac::EndPumpingFrames() {
- if (ca_layer_tree_)
- ca_layer_tree_->EndPumpingFrames();
+// static
+void BrowserCompositorMac::DisableRecyclingForShutdown() {
+ g_has_shut_down = true;
+ g_recyclable_browser_compositor.Get().reset();
}
////////////////////////////////////////////////////////////////////////////////
-// BrowserCompositorViewPlaceholderMac
+// BrowserCompositorMacPlaceholder
-BrowserCompositorViewPlaceholderMac::BrowserCompositorViewPlaceholderMac() {
+BrowserCompositorMacPlaceholder::BrowserCompositorMacPlaceholder() {
g_placeholder_count += 1;
}
-BrowserCompositorViewPlaceholderMac::~BrowserCompositorViewPlaceholderMac() {
+BrowserCompositorMacPlaceholder::~BrowserCompositorMacPlaceholder() {
DCHECK_GT(g_placeholder_count, 0u);
g_placeholder_count -= 1;
// If there are no placeholders allocated, destroy the recyclable
- // BrowserCompositorCALayerTreeMac.
+ // BrowserCompositorMac.
if (!g_placeholder_count)
- g_recyclable_ca_layer_tree.Get().reset();
+ g_recyclable_browser_compositor.Get().reset();
}
} // namespace content
diff --git a/chromium/content/browser/compositor/buffer_queue.cc b/chromium/content/browser/compositor/buffer_queue.cc
index ebb01658ccb..ed055826c39 100644
--- a/chromium/content/browser/compositor/buffer_queue.cc
+++ b/chromium/content/browser/compositor/buffer_queue.cc
@@ -5,23 +5,31 @@
#include "content/browser/compositor/buffer_queue.h"
#include "content/browser/compositor/image_transport_factory.h"
+#include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
#include "content/common/gpu/client/context_provider_command_buffer.h"
#include "content/common/gpu/client/gl_helper.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/gles2_interface.h"
+#include "gpu/command_buffer/service/image_factory.h"
#include "third_party/skia/include/core/SkRect.h"
#include "third_party/skia/include/core/SkRegion.h"
+#include "ui/gfx/gpu_memory_buffer.h"
namespace content {
-BufferQueue::BufferQueue(scoped_refptr<cc::ContextProvider> context_provider,
- unsigned int internalformat,
- GLHelper* gl_helper)
+BufferQueue::BufferQueue(
+ scoped_refptr<cc::ContextProvider> context_provider,
+ unsigned int internalformat,
+ GLHelper* gl_helper,
+ BrowserGpuMemoryBufferManager* gpu_memory_buffer_manager,
+ int surface_id)
: context_provider_(context_provider),
fbo_(0),
allocated_count_(0),
internalformat_(internalformat),
- gl_helper_(gl_helper) {
+ gl_helper_(gl_helper),
+ gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
+ surface_id_(surface_id) {
}
BufferQueue::~BufferQueue() {
@@ -32,10 +40,9 @@ BufferQueue::~BufferQueue() {
gl->DeleteFramebuffers(1, &fbo_);
}
-bool BufferQueue::Initialize() {
+void BufferQueue::Initialize() {
gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
gl->GenFramebuffers(1, &fbo_);
- return fbo_ != 0;
}
void BufferQueue::BindFramebuffer() {
@@ -70,8 +77,10 @@ void BufferQueue::CopyBufferDamage(int texture,
}
void BufferQueue::UpdateBufferDamage(const gfx::Rect& damage) {
+ displayed_surface_.damage.Union(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();
@@ -82,10 +91,12 @@ void BufferQueue::UpdateBufferDamage(const gfx::Rect& 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,
+ DCHECK(!in_flight_surfaces_.empty() || displayed_surface_.texture);
+ unsigned int texture_id = !in_flight_surfaces_.empty()
+ ? in_flight_surfaces_.back().texture
+ : displayed_surface_.texture;
+
+ CopyBufferDamage(current_surface_.texture, texture_id, damage,
current_surface_.damage);
}
UpdateBufferDamage(damage);
@@ -93,6 +104,9 @@ void BufferQueue::SwapBuffers(const gfx::Rect& damage) {
in_flight_surfaces_.push_back(current_surface_);
current_surface_.texture = 0;
current_surface_.image = 0;
+ // Some things reset the framebuffer (CopySubBufferDamage, some GLRenderer
+ // paths), so ensure we restore it here.
+ context_provider_->ContextGL()->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
}
void BufferQueue::Reshape(const gfx::Size& size, float scale_factor) {
@@ -111,20 +125,26 @@ void BufferQueue::Reshape(const gfx::Size& size, float scale_factor) {
}
void BufferQueue::PageFlipComplete() {
- if (in_flight_surfaces_.size() > 1) {
- available_surfaces_.push_back(in_flight_surfaces_.front());
- in_flight_surfaces_.pop_front();
- }
+ DCHECK(!in_flight_surfaces_.empty());
+
+ if (displayed_surface_.texture)
+ available_surfaces_.push_back(displayed_surface_);
+
+ displayed_surface_ = in_flight_surfaces_.front();
+ in_flight_surfaces_.pop_front();
}
void BufferQueue::FreeAllSurfaces() {
+ FreeSurface(&displayed_surface_);
FreeSurface(&current_surface_);
- while (!in_flight_surfaces_.empty()) {
- FreeSurface(&in_flight_surfaces_.front());
- in_flight_surfaces_.pop_front();
- }
+ // This is intentionally not emptied since the swap buffers acks are still
+ // expected to arrive.
+ for (auto& surface : in_flight_surfaces_)
+ FreeSurface(&surface);
+
for (size_t i = 0; i < available_surfaces_.size(); i++)
FreeSurface(&available_surfaces_[i]);
+
available_surfaces_.clear();
}
@@ -157,11 +177,20 @@ BufferQueue::AllocatedSurface BufferQueue::GetNextSurface() {
// 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);
+ scoped_ptr<gfx::GpuMemoryBuffer> buffer(
+ gpu_memory_buffer_manager_->AllocateGpuMemoryBufferForScanout(
+ size_, gpu::ImageFactory::ImageFormatToGpuMemoryBufferFormat(
+ internalformat_),
+ surface_id_));
+ if (!buffer) {
+ gl->DeleteTextures(1, &texture);
+ DLOG(ERROR) << "Failed to allocate GPU memory buffer";
+ return AllocatedSurface();
+ }
+
+ unsigned int id = gl->CreateImageCHROMIUM(
+ buffer->AsClientBuffer(), size_.width(), size_.height(), internalformat_);
+
if (!id) {
LOG(ERROR) << "Failed to allocate backing image surface";
gl->DeleteTextures(1, &texture);
diff --git a/chromium/content/browser/compositor/buffer_queue.h b/chromium/content/browser/compositor/buffer_queue.h
index dca9c38c0d4..e2bc0c9c77c 100644
--- a/chromium/content/browser/compositor/buffer_queue.h
+++ b/chromium/content/browser/compositor/buffer_queue.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CONTENT_BROWSER_COMPOSITOR_BUFFERED_OUTPUT_SURFACE_H_
-#define CONTENT_BROWSER_COMPOSITOR_BUFFERED_OUTPUT_SURFACE_H_
+#ifndef CONTENT_BROWSER_COMPOSITOR_BUFFER_QUEUE_H_
+#define CONTENT_BROWSER_COMPOSITOR_BUFFER_QUEUE_H_
#include <queue>
#include <vector>
@@ -11,8 +11,8 @@
#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"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
namespace cc {
class ContextProvider;
@@ -20,6 +20,7 @@ class ContextProvider;
namespace content {
+class BrowserGpuMemoryBufferManager;
class GLHelper;
// Provides a surface that manages its own buffers, backed by GpuMemoryBuffers
@@ -30,17 +31,20 @@ class CONTENT_EXPORT BufferQueue {
public:
BufferQueue(scoped_refptr<cc::ContextProvider> context_provider,
unsigned int internalformat,
- GLHelper* gl_helper);
+ GLHelper* gl_helper,
+ BrowserGpuMemoryBufferManager* gpu_memory_buffer_manager,
+ int surface_id);
virtual ~BufferQueue();
- bool Initialize();
+ void 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; }
+ unsigned int current_texture_id() const { return current_surface_.texture; }
+ unsigned int fbo() const { return fbo_; }
private:
friend class BufferQueueTest;
@@ -78,13 +82,16 @@ class CONTENT_EXPORT BufferQueue {
size_t allocated_count_;
unsigned int internalformat_;
AllocatedSurface current_surface_; // This surface is currently bound.
+ AllocatedSurface displayed_surface_; // The surface currently on the screen.
std::vector<AllocatedSurface> available_surfaces_; // These are free for use.
std::deque<AllocatedSurface> in_flight_surfaces_;
GLHelper* gl_helper_;
+ BrowserGpuMemoryBufferManager* gpu_memory_buffer_manager_;
+ int surface_id_;
DISALLOW_COPY_AND_ASSIGN(BufferQueue);
};
} // namespace content
-#endif // CONTENT_BROWSER_COMPOSITOR_BUFFERED_OUTPUT_SURFACE_H_
+#endif // CONTENT_BROWSER_COMPOSITOR_BUFFER_QUEUE_H_
diff --git a/chromium/content/browser/compositor/buffer_queue_unittest.cc b/chromium/content/browser/compositor/buffer_queue_unittest.cc
index 1a2c4feeddc..ccc46373e4d 100644
--- a/chromium/content/browser/compositor/buffer_queue_unittest.cc
+++ b/chromium/content/browser/compositor/buffer_queue_unittest.cc
@@ -8,6 +8,8 @@
#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 "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
+#include "content/common/gpu/client/gl_helper.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -19,11 +21,48 @@ using ::testing::Ne;
using ::testing::Return;
namespace content {
+
+class StubGpuMemoryBufferImpl : public gfx::GpuMemoryBuffer {
+ public:
+ StubGpuMemoryBufferImpl() {}
+
+ // Overridden from gfx::GpuMemoryBuffer:
+ bool Map(void** data) override { return false; }
+ void Unmap() override {}
+ bool IsMapped() const override { return false; }
+ Format GetFormat() const override { return gfx::GpuMemoryBuffer::RGBX_8888; }
+ void GetStride(int* stride) const override {}
+ gfx::GpuMemoryBufferHandle GetHandle() const override {
+ return gfx::GpuMemoryBufferHandle();
+ }
+ ClientBuffer AsClientBuffer() override {
+ return reinterpret_cast<ClientBuffer>(this);
+ }
+};
+
+class StubBrowserGpuMemoryBufferManager : public BrowserGpuMemoryBufferManager {
+ public:
+ StubBrowserGpuMemoryBufferManager()
+ : BrowserGpuMemoryBufferManager(nullptr, 1) {}
+
+ scoped_ptr<gfx::GpuMemoryBuffer> AllocateGpuMemoryBufferForScanout(
+ const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
+ int32 surface_id) override {
+ return make_scoped_ptr<gfx::GpuMemoryBuffer>(new StubGpuMemoryBufferImpl);
+ }
+};
+
class MockBufferQueue : public BufferQueue {
public:
MockBufferQueue(scoped_refptr<cc::ContextProvider> context_provider,
+ BrowserGpuMemoryBufferManager* gpu_memory_buffer_manager,
unsigned int internalformat)
- : BufferQueue(context_provider, internalformat, nullptr) {}
+ : BufferQueue(context_provider,
+ internalformat,
+ nullptr,
+ gpu_memory_buffer_manager,
+ 1) {}
MOCK_METHOD4(CopyBufferDamage,
void(int, int, const gfx::Rect&, const gfx::Rect&));
};
@@ -36,7 +75,9 @@ class BufferQueueTest : public ::testing::Test {
scoped_refptr<cc::TestContextProvider> context_provider =
cc::TestContextProvider::Create(cc::TestWebGraphicsContext3D::Create());
context_provider->BindToCurrentThread();
- output_surface_.reset(new MockBufferQueue(context_provider, GL_RGBA));
+ gpu_memory_buffer_manager_.reset(new StubBrowserGpuMemoryBufferManager);
+ output_surface_.reset(new MockBufferQueue(
+ context_provider, gpu_memory_buffer_manager_.get(), GL_RGBA));
output_surface_->Initialize();
}
@@ -48,6 +89,9 @@ class BufferQueueTest : public ::testing::Test {
return output_surface_->in_flight_surfaces_;
}
+ const BufferQueue::AllocatedSurface& displayed_frame() {
+ return output_surface_->displayed_surface_;
+ }
const BufferQueue::AllocatedSurface& last_frame() {
return output_surface_->in_flight_surfaces_.back();
}
@@ -57,7 +101,8 @@ class BufferQueueTest : public ::testing::Test {
const gfx::Size size() { return output_surface_->size_; }
int CountBuffers() {
- int n = available_surfaces().size() + in_flight_surfaces().size();
+ int n = available_surfaces().size() + in_flight_surfaces().size() +
+ (displayed_frame().texture ? 1 : 0);
if (current_surface())
n++;
return n;
@@ -67,6 +112,7 @@ class BufferQueueTest : public ::testing::Test {
void CheckUnique() {
std::set<unsigned> buffers;
EXPECT_TRUE(InsertUnique(&buffers, current_surface()));
+ EXPECT_TRUE(InsertUnique(&buffers, displayed_frame().image));
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 =
@@ -102,6 +148,7 @@ class BufferQueueTest : public ::testing::Test {
return true;
}
+ scoped_ptr<BrowserGpuMemoryBufferManager> gpu_memory_buffer_manager_;
scoped_ptr<MockBufferQueue> output_surface_;
bool doublebuffering_;
bool first_frame_;
@@ -119,29 +166,33 @@ class MockedContext : public cc::TestWebGraphicsContext3D {
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_METHOD4(createImageCHROMIUM,
+ GLuint(ClientBuffer, GLsizei, GLsizei, GLenum));
MOCK_METHOD1(destroyImageCHROMIUM, void(GLuint));
MOCK_METHOD5(framebufferTexture2D,
void(GLenum, GLenum, GLenum, GLuint, GLint));
};
-scoped_ptr<BufferQueue> CreateOutputSurfaceWithMock(MockedContext** context) {
+scoped_ptr<BufferQueue> CreateOutputSurfaceWithMock(
+ MockedContext** context,
+ BrowserGpuMemoryBufferManager* gpu_memory_buffer_manager) {
*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));
+ scoped_ptr<BufferQueue> buffer_queue(new BufferQueue(
+ context_provider, GL_RGBA, nullptr, gpu_memory_buffer_manager, 1));
buffer_queue->Initialize();
return buffer_queue.Pass();
}
TEST(BufferQueueStandaloneTest, FboInitialization) {
MockedContext* context;
+ scoped_ptr<BrowserGpuMemoryBufferManager> gpu_memory_buffer_manager(
+ new StubBrowserGpuMemoryBufferManager);
scoped_ptr<BufferQueue> output_surface =
- CreateOutputSurfaceWithMock(&context);
+ CreateOutputSurfaceWithMock(&context, gpu_memory_buffer_manager.get());
EXPECT_CALL(*context, bindFramebuffer(GL_FRAMEBUFFER, Ne(0U)));
ON_CALL(*context, framebufferTexture2D(_, _, _, _, _))
@@ -152,14 +203,15 @@ TEST(BufferQueueStandaloneTest, FboInitialization) {
TEST(BufferQueueStandaloneTest, FboBinding) {
MockedContext* context;
+ scoped_ptr<BrowserGpuMemoryBufferManager> gpu_memory_buffer_manager(
+ new StubBrowserGpuMemoryBufferManager);
scoped_ptr<BufferQueue> output_surface =
- CreateOutputSurfaceWithMock(&context);
+ CreateOutputSurfaceWithMock(&context, gpu_memory_buffer_manager.get());
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));
+ EXPECT_CALL(*context, createImageCHROMIUM(_, 0, 0, GL_RGBA))
+ .WillOnce(Return(1));
Expectation fb =
EXPECT_CALL(*context, bindFramebuffer(GL_FRAMEBUFFER, Ne(0U)));
Expectation tex = EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, Ne(0U)));
@@ -175,8 +227,37 @@ TEST(BufferQueueStandaloneTest, FboBinding) {
output_surface->BindFramebuffer();
}
+TEST(BufferQueueStandaloneTest, CheckBoundFramebuffer) {
+ scoped_ptr<BrowserGpuMemoryBufferManager> gpu_memory_buffer_manager;
+ scoped_ptr<BufferQueue> output_surface;
+ scoped_refptr<cc::TestContextProvider> context_provider =
+ cc::TestContextProvider::Create(cc::TestWebGraphicsContext3D::Create());
+ context_provider->BindToCurrentThread();
+ gpu_memory_buffer_manager.reset(new StubBrowserGpuMemoryBufferManager);
+
+ scoped_ptr<GLHelper> gl_helper;
+ gl_helper.reset(new GLHelper(context_provider->ContextGL(),
+ context_provider->ContextSupport()));
+
+ output_surface.reset(new BufferQueue(context_provider, GL_RGBA,
+ gl_helper.get(),
+ gpu_memory_buffer_manager.get(), 1));
+ output_surface->Initialize();
+ output_surface->Reshape(screen_size, 1.0f);
+ // Trigger a sub-buffer copy to exercise all paths.
+ output_surface->BindFramebuffer();
+ output_surface->SwapBuffers(screen_rect);
+ output_surface->PageFlipComplete();
+ output_surface->BindFramebuffer();
+ output_surface->SwapBuffers(small_damage);
+
+ int current_fbo = 0;
+ context_provider->ContextGL()->GetIntegerv(GL_FRAMEBUFFER_BINDING,
+ &current_fbo);
+ EXPECT_EQ(static_cast<int>(output_surface->fbo()), current_fbo);
+}
+
TEST_F(BufferQueueTest, PartialSwapReuse) {
- // Check that
output_surface_->Reshape(screen_size, 1.0f);
ASSERT_TRUE(doublebuffering_);
EXPECT_CALL(*output_surface_,
@@ -236,22 +317,27 @@ TEST_F(BufferQueueTest, CheckDoubleBuffering) {
output_surface_->BindFramebuffer();
EXPECT_EQ(1, CountBuffers());
EXPECT_NE(0U, current_surface());
+ EXPECT_FALSE(displayed_frame().texture);
SwapBuffers();
EXPECT_EQ(1U, in_flight_surfaces().size());
output_surface_->PageFlipComplete();
- EXPECT_EQ(1U, in_flight_surfaces().size());
+ EXPECT_EQ(0U, in_flight_surfaces().size());
+ EXPECT_TRUE(displayed_frame().texture);
output_surface_->BindFramebuffer();
EXPECT_EQ(2, CountBuffers());
CheckUnique();
EXPECT_NE(0U, current_surface());
- EXPECT_EQ(1U, in_flight_surfaces().size());
+ EXPECT_EQ(0U, in_flight_surfaces().size());
+ EXPECT_TRUE(displayed_frame().texture);
SwapBuffers();
CheckUnique();
- EXPECT_EQ(2U, in_flight_surfaces().size());
+ EXPECT_EQ(1U, in_flight_surfaces().size());
+ EXPECT_TRUE(displayed_frame().texture);
output_surface_->PageFlipComplete();
CheckUnique();
- EXPECT_EQ(1U, in_flight_surfaces().size());
+ EXPECT_EQ(0U, in_flight_surfaces().size());
EXPECT_EQ(1U, available_surfaces().size());
+ EXPECT_TRUE(displayed_frame().texture);
output_surface_->BindFramebuffer();
EXPECT_EQ(2, CountBuffers());
CheckUnique();
@@ -263,6 +349,7 @@ TEST_F(BufferQueueTest, CheckTripleBuffering) {
// This bit is the same sequence tested in the doublebuffering case.
output_surface_->BindFramebuffer();
+ EXPECT_FALSE(displayed_frame().texture);
SwapBuffers();
output_surface_->PageFlipComplete();
output_surface_->BindFramebuffer();
@@ -270,19 +357,87 @@ TEST_F(BufferQueueTest, CheckTripleBuffering) {
EXPECT_EQ(2, CountBuffers());
CheckUnique();
- EXPECT_EQ(2U, in_flight_surfaces().size());
+ EXPECT_EQ(1U, in_flight_surfaces().size());
+ EXPECT_TRUE(displayed_frame().texture);
output_surface_->BindFramebuffer();
EXPECT_EQ(3, CountBuffers());
CheckUnique();
EXPECT_NE(0U, current_surface());
- EXPECT_EQ(2U, in_flight_surfaces().size());
+ EXPECT_EQ(1U, in_flight_surfaces().size());
+ EXPECT_TRUE(displayed_frame().texture);
output_surface_->PageFlipComplete();
EXPECT_EQ(3, CountBuffers());
CheckUnique();
EXPECT_NE(0U, current_surface());
- EXPECT_EQ(1U, in_flight_surfaces().size());
+ EXPECT_EQ(0U, in_flight_surfaces().size());
+ EXPECT_TRUE(displayed_frame().texture);
EXPECT_EQ(1U, available_surfaces().size());
}
+TEST_F(BufferQueueTest, CheckCorrectBufferOrdering) {
+ const size_t kSwapCount = 3;
+ for (size_t i = 0; i < kSwapCount; ++i) {
+ output_surface_->BindFramebuffer();
+ SwapBuffers();
+ }
+
+ EXPECT_EQ(kSwapCount, in_flight_surfaces().size());
+ for (size_t i = 0; i < kSwapCount; ++i) {
+ unsigned int next_texture_id = in_flight_surfaces().front().texture;
+ output_surface_->PageFlipComplete();
+ EXPECT_EQ(displayed_frame().texture, next_texture_id);
+ }
+}
+
+TEST_F(BufferQueueTest, ReshapeWithInFlightSurfaces) {
+ const size_t kSwapCount = 3;
+ for (size_t i = 0; i < kSwapCount; ++i) {
+ output_surface_->BindFramebuffer();
+ SwapBuffers();
+ }
+
+ output_surface_->Reshape(gfx::Size(10, 20), 1.0f);
+ EXPECT_EQ(3u, in_flight_surfaces().size());
+
+ for (size_t i = 0; i < kSwapCount; ++i) {
+ output_surface_->PageFlipComplete();
+ EXPECT_EQ(0u, displayed_frame().texture);
+ }
+
+ // The dummy surfacess left should be discarded.
+ EXPECT_EQ(0u, available_surfaces().size());
+}
+
+TEST_F(BufferQueueTest, SwapAfterReshape) {
+ const size_t kSwapCount = 3;
+ for (size_t i = 0; i < kSwapCount; ++i) {
+ output_surface_->BindFramebuffer();
+ SwapBuffers();
+ }
+
+ output_surface_->Reshape(gfx::Size(10, 20), 1.0f);
+
+ for (size_t i = 0; i < kSwapCount; ++i) {
+ output_surface_->BindFramebuffer();
+ SwapBuffers();
+ }
+
+ EXPECT_EQ(2 * kSwapCount, in_flight_surfaces().size());
+
+ for (size_t i = 0; i < kSwapCount; ++i) {
+ output_surface_->PageFlipComplete();
+ EXPECT_EQ(0u, displayed_frame().texture);
+ }
+
+ CheckUnique();
+
+ for (size_t i = 0; i < kSwapCount; ++i) {
+ unsigned int next_texture_id = in_flight_surfaces().front().texture;
+ output_surface_->PageFlipComplete();
+ EXPECT_EQ(displayed_frame().texture, next_texture_id);
+ EXPECT_NE(0u, displayed_frame().texture);
+ }
+}
+
} // namespace
} // namespace content
diff --git a/chromium/content/browser/compositor/delegated_frame_host.cc b/chromium/content/browser/compositor/delegated_frame_host.cc
index 5dbaed130f5..2faa1a7e520 100644
--- a/chromium/content/browser/compositor/delegated_frame_host.cc
+++ b/chromium/content/browser/compositor/delegated_frame_host.cc
@@ -26,6 +26,7 @@
#include "third_party/skia/include/core/SkPaint.h"
#include "third_party/skia/include/effects/SkLumaColorFilter.h"
#include "ui/gfx/frame_time.h"
+#include "ui/gfx/geometry/dip_util.h"
namespace content {
@@ -52,39 +53,21 @@ void RequireCallback(cc::SurfaceManager* manager,
} // namespace
////////////////////////////////////////////////////////////////////////////////
-// DelegatedFrameHostClient
-
-bool DelegatedFrameHostClient::ShouldCreateResizeLock() {
- // On Windows and Linux, holding pointer moves will not help throttling
- // resizes.
- // TODO(piman): on Windows we need to block (nested message loop?) the
- // WM_SIZE event. On Linux we need to throttle at the WM level using
- // _NET_WM_SYNC_REQUEST.
- // TODO(ccameron): Mac browser window resizing is incompletely implemented.
-#if !defined(OS_CHROMEOS)
- return false;
-#else
- return GetDelegatedFrameHost()->ShouldCreateResizeLock();
-#endif
-}
-
-void DelegatedFrameHostClient::RequestCopyOfOutput(
- scoped_ptr<cc::CopyOutputRequest> request) {
- GetDelegatedFrameHost()->RequestCopyOfOutput(request.Pass());
-}
-
-////////////////////////////////////////////////////////////////////////////////
// DelegatedFrameHost
DelegatedFrameHost::DelegatedFrameHost(DelegatedFrameHostClient* client)
: client_(client),
+ compositor_(nullptr),
use_surfaces_(UseSurfacesEnabled()),
last_output_surface_id_(0),
pending_delegated_ack_count_(0),
skipped_frames_(false),
+ current_scale_factor_(1.f),
can_lock_compositor_(YES_CAN_LOCK),
delegated_frame_evictor_(new DelegatedFrameEvictor(this)) {
- ImageTransportFactory::GetInstance()->AddObserver(this);
+ ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
+ factory->AddObserver(this);
+ id_allocator_ = factory->GetContextFactory()->CreateSurfaceIdAllocator();
}
void DelegatedFrameHost::WasShown(const ui::LatencyInfo& latency_info) {
@@ -92,14 +75,12 @@ void DelegatedFrameHost::WasShown(const ui::LatencyInfo& latency_info) {
if (surface_id_.is_null() && !frame_provider_.get() &&
!released_front_lock_.get()) {
- ui::Compositor* compositor = client_->GetCompositor();
- if (compositor)
- released_front_lock_ = compositor->GetCompositorLock();
+ if (compositor_)
+ released_front_lock_ = compositor_->GetCompositorLock();
}
- ui::Compositor* compositor = client_->GetCompositor();
- if (compositor) {
- compositor->SetLatencyInfo(latency_info);
+ if (compositor_) {
+ compositor_->SetLatencyInfo(latency_info);
}
}
@@ -113,14 +94,9 @@ void DelegatedFrameHost::WasHidden() {
}
void DelegatedFrameHost::MaybeCreateResizeLock() {
- if (!client_->ShouldCreateResizeLock())
+ if (!ShouldCreateResizeLock())
return;
- DCHECK(client_->GetCompositor());
-
- // Listen to changes in the compositor lock state.
- ui::Compositor* compositor = client_->GetCompositor();
- if (!compositor->HasObserver(this))
- compositor->AddObserver(this);
+ DCHECK(compositor_);
bool defer_compositor_lock =
can_lock_compositor_ == NO_PENDING_RENDERER_FRAME ||
@@ -129,57 +105,49 @@ void DelegatedFrameHost::MaybeCreateResizeLock() {
if (can_lock_compositor_ == YES_CAN_LOCK)
can_lock_compositor_ = YES_DID_LOCK;
- resize_lock_ = client_->CreateResizeLock(defer_compositor_lock);
+ resize_lock_ =
+ client_->DelegatedFrameHostCreateResizeLock(defer_compositor_lock);
}
bool DelegatedFrameHost::ShouldCreateResizeLock() {
- RenderWidgetHostImpl* host = client_->GetHost();
-
- if (resize_lock_)
+ if (!client_->DelegatedFrameCanCreateResizeLock())
return false;
- if (host->should_auto_resize())
+ if (resize_lock_)
return false;
- gfx::Size desired_size = client_->DesiredFrameSize();
+ gfx::Size desired_size = client_->DelegatedFrameHostDesiredSizeInDIP();
if (desired_size == current_frame_size_in_dip_ || desired_size.IsEmpty())
return false;
- ui::Compositor* compositor = client_->GetCompositor();
- if (!compositor)
+ if (!compositor_)
return false;
return true;
}
-void DelegatedFrameHost::RequestCopyOfOutput(
- scoped_ptr<cc::CopyOutputRequest> request) {
- client_->GetLayer()->RequestCopyOfOutput(request.Pass());
-}
-
void DelegatedFrameHost::CopyFromCompositingSurface(
const gfx::Rect& src_subrect,
const gfx::Size& output_size,
- CopyFromCompositingSurfaceCallback& callback,
- const SkColorType color_type) {
+ ReadbackRequestCallback& callback,
+ const SkColorType preferred_color_type) {
// Only ARGB888 and RGB565 supported as of now.
- bool format_support = ((color_type == kAlpha_8_SkColorType) ||
- (color_type == kRGB_565_SkColorType) ||
- (color_type == kN32_SkColorType));
+ bool format_support = ((preferred_color_type == kAlpha_8_SkColorType) ||
+ (preferred_color_type == kRGB_565_SkColorType) ||
+ (preferred_color_type == kN32_SkColorType));
DCHECK(format_support);
if (!CanCopyToBitmap()) {
- callback.Run(false, SkBitmap());
+ callback.Run(SkBitmap(), content::READBACK_SURFACE_UNAVAILABLE);
return;
}
scoped_ptr<cc::CopyOutputRequest> request =
- cc::CopyOutputRequest::CreateRequest(base::Bind(
- &DelegatedFrameHost::CopyFromCompositingSurfaceHasResult,
- output_size,
- color_type,
- callback));
- request->set_area(src_subrect);
- client_->RequestCopyOfOutput(request.Pass());
+ cc::CopyOutputRequest::CreateRequest(
+ base::Bind(&DelegatedFrameHost::CopyFromCompositingSurfaceHasResult,
+ output_size, preferred_color_type, callback));
+ if (!src_subrect.IsEmpty())
+ request->set_area(src_subrect);
+ RequestCopyOfOutput(request.Pass());
}
void DelegatedFrameHost::CopyFromCompositingSurfaceToVideoFrame(
@@ -191,44 +159,26 @@ void DelegatedFrameHost::CopyFromCompositingSurfaceToVideoFrame(
return;
}
- // Try get a texture to reuse.
- scoped_refptr<OwnedMailbox> subscriber_texture;
- if (frame_subscriber_) {
- if (!idle_frame_subscriber_textures_.empty()) {
- subscriber_texture = idle_frame_subscriber_textures_.back();
- idle_frame_subscriber_textures_.pop_back();
- } else if (GLHelper* helper =
- ImageTransportFactory::GetInstance()->GetGLHelper()) {
- subscriber_texture = new OwnedMailbox(helper);
- }
- }
-
scoped_ptr<cc::CopyOutputRequest> request =
cc::CopyOutputRequest::CreateRequest(base::Bind(
&DelegatedFrameHost::
CopyFromCompositingSurfaceHasResultForVideo,
AsWeakPtr(), // For caching the ReadbackYUVInterface on this class.
- subscriber_texture,
+ nullptr,
target,
callback));
request->set_area(src_subrect);
- if (subscriber_texture.get()) {
- request->SetTextureMailbox(
- cc::TextureMailbox(subscriber_texture->mailbox(),
- subscriber_texture->target(),
- subscriber_texture->sync_point()));
- }
- client_->RequestCopyOfOutput(request.Pass());
+ RequestCopyOfOutput(request.Pass());
}
bool DelegatedFrameHost::CanCopyToBitmap() const {
- return client_->GetCompositor() &&
- client_->GetLayer()->has_external_content();
+ return compositor_ &&
+ client_->DelegatedFrameHostGetLayer()->has_external_content();
}
bool DelegatedFrameHost::CanCopyToVideoFrame() const {
- return client_->GetCompositor() &&
- client_->GetLayer()->has_external_content();
+ return compositor_ &&
+ client_->DelegatedFrameHostGetLayer()->has_external_content();
}
bool DelegatedFrameHost::CanSubscribeFrame() const {
@@ -245,6 +195,13 @@ void DelegatedFrameHost::EndFrameSubscription() {
frame_subscriber_.reset();
}
+uint32_t DelegatedFrameHost::GetSurfaceIdNamespace() {
+ if (!use_surfaces_)
+ return 0;
+
+ return id_allocator_->id_namespace();
+}
+
bool DelegatedFrameHost::ShouldSkipFrame(gfx::Size size_in_dip) const {
// Should skip a frame only when another frame from the renderer is guaranteed
// to replace it. Otherwise may cause hangs when the renderer is waiting for
@@ -258,8 +215,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())
+ if (client_->DelegatedFrameHostDesiredSizeInDIP() !=
+ current_frame_size_in_dip_ &&
+ !client_->DelegatedFrameHostIsVisible())
EvictDelegatedFrame();
MaybeCreateResizeLock();
}
@@ -268,7 +226,7 @@ gfx::Size DelegatedFrameHost::GetRequestedRendererSize() const {
if (resize_lock_)
return resize_lock_->expected_size();
else
- return client_->DesiredFrameSize();
+ return client_->DelegatedFrameHostDesiredSizeInDIP();
}
void DelegatedFrameHost::CheckResizeLock() {
@@ -280,11 +238,6 @@ void DelegatedFrameHost::CheckResizeLock() {
// the release of the lock until we've kicked a frame with the new texture, to
// avoid resizing the UI before we have a chance to draw a "good" frame.
resize_lock_->UnlockCompositor();
- ui::Compositor* compositor = client_->GetCompositor();
- if (compositor) {
- if (!compositor->HasObserver(this))
- compositor->AddObserver(this);
- }
}
void DelegatedFrameHost::DidReceiveFrameFromRenderer(
@@ -303,13 +256,42 @@ void DelegatedFrameHost::DidReceiveFrameFromRenderer(
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));
+ if (!frame_subscriber()->ShouldCaptureFrame(damage_rect, present_time,
+ &frame, &callback))
+ return;
+
+ // Get a texture to re-use; else, create a new one.
+ scoped_refptr<OwnedMailbox> subscriber_texture;
+ if (!idle_frame_subscriber_textures_.empty()) {
+ subscriber_texture = idle_frame_subscriber_textures_.back();
+ idle_frame_subscriber_textures_.pop_back();
+ } else if (GLHelper* helper =
+ ImageTransportFactory::GetInstance()->GetGLHelper()) {
+ subscriber_texture = new OwnedMailbox(helper);
}
+
+ scoped_ptr<cc::CopyOutputRequest> request =
+ cc::CopyOutputRequest::CreateRequest(base::Bind(
+ &DelegatedFrameHost::CopyFromCompositingSurfaceHasResultForVideo,
+ AsWeakPtr(),
+ subscriber_texture,
+ frame,
+ base::Bind(callback, present_time)));
+ // Setting the source in this copy request asks that the layer abort any prior
+ // uncommitted copy requests made on behalf of the same frame subscriber.
+ // This will not affect any of the copy requests spawned elsewhere from
+ // DelegatedFrameHost (e.g., a call to CopyFromCompositingSurface() for
+ // screenshots) since those copy requests do not specify |frame_subscriber()|
+ // as a source.
+ request->set_source(frame_subscriber());
+ request->set_area(gfx::Rect(current_frame_size_in_dip_));
+ if (subscriber_texture.get()) {
+ request->SetTextureMailbox(
+ cc::TextureMailbox(subscriber_texture->mailbox(),
+ subscriber_texture->target(),
+ subscriber_texture->sync_point()));
+ }
+ RequestCopyOfOutput(request.Pass());
}
void DelegatedFrameHost::SwapDelegatedFrame(
@@ -317,19 +299,18 @@ void DelegatedFrameHost::SwapDelegatedFrame(
scoped_ptr<cc::DelegatedFrameData> frame_data,
float frame_device_scale_factor,
const std::vector<ui::LatencyInfo>& latency_info) {
- RenderWidgetHostImpl* host = client_->GetHost();
DCHECK(!frame_data->render_pass_list.empty());
cc::RenderPass* root_pass = frame_data->render_pass_list.back();
gfx::Size frame_size = root_pass->output_rect.size();
gfx::Size frame_size_in_dip =
- ConvertSizeToDIP(frame_device_scale_factor, frame_size);
+ gfx::ConvertSizeToDIP(frame_device_scale_factor, frame_size);
gfx::Rect damage_rect = gfx::ToEnclosingRect(root_pass->damage_rect);
damage_rect.Intersect(gfx::Rect(frame_size));
gfx::Rect damage_rect_in_dip =
- ConvertRectToDIP(frame_device_scale_factor, damage_rect);
+ gfx::ConvertRectToDIP(frame_device_scale_factor, damage_rect);
if (ShouldSkipFrame(frame_size_in_dip)) {
cc::CompositorFrameAck ack;
@@ -339,9 +320,7 @@ void DelegatedFrameHost::SwapDelegatedFrame(
skipped_latency_info_list_.insert(skipped_latency_info_list_.end(),
latency_info.begin(), latency_info.end());
- RenderWidgetHostImpl::SendSwapCompositorFrameAck(
- host->GetRoutingID(), output_surface_id,
- host->GetProcess()->GetID(), ack);
+ client_->DelegatedFrameHostSendCompositorSwapAck(output_surface_id, ack);
skipped_frames_ = true;
return;
}
@@ -382,7 +361,9 @@ void DelegatedFrameHost::SwapDelegatedFrame(
}
last_output_surface_id_ = output_surface_id;
}
- ui::Compositor* compositor = client_->GetCompositor();
+ bool immediate_ack = !compositor_;
+ pending_delegated_ack_count_++;
+
if (frame_size.IsEmpty()) {
DCHECK(frame_data->resource_list.empty());
EvictDelegatedFrame();
@@ -391,8 +372,6 @@ void DelegatedFrameHost::SwapDelegatedFrame(
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));
}
@@ -401,14 +380,15 @@ void DelegatedFrameHost::SwapDelegatedFrame(
if (!surface_id_.is_null())
surface_factory_->Destroy(surface_id_);
surface_id_ = id_allocator_->GenerateId();
- surface_factory_->Create(surface_id_, frame_size);
+ surface_factory_->Create(surface_id_);
// manager must outlive compositors using it.
- client_->GetLayer()->SetShowSurface(
+ client_->DelegatedFrameHostGetLayer()->SetShowSurface(
surface_id_,
base::Bind(&SatisfyCallback, base::Unretained(manager)),
base::Bind(&RequireCallback, base::Unretained(manager)), frame_size,
- frame_size_in_dip);
+ frame_device_scale_factor, frame_size_in_dip);
current_surface_size_ = frame_size;
+ current_scale_factor_ = frame_device_scale_factor;
}
scoped_ptr<cc::CompositorFrame> compositor_frame =
make_scoped_ptr(new cc::CompositorFrame());
@@ -420,11 +400,14 @@ void DelegatedFrameHost::SwapDelegatedFrame(
latency_info.begin(),
latency_info.end());
- base::Closure ack_callback;
- if (compositor) {
- ack_callback = base::Bind(&DelegatedFrameHost::SendDelegatedFrameAck,
- AsWeakPtr(),
- output_surface_id);
+ gfx::Size desired_size = client_->DelegatedFrameHostDesiredSizeInDIP();
+ if (desired_size != frame_size_in_dip && !desired_size.IsEmpty())
+ immediate_ack = true;
+
+ cc::SurfaceFactory::DrawCallback ack_callback;
+ if (compositor_ && !immediate_ack) {
+ ack_callback = base::Bind(&DelegatedFrameHost::SurfaceDrawn,
+ AsWeakPtr(), output_surface_id);
}
surface_factory_->SubmitFrame(
surface_id_, compositor_frame.Pass(), ack_callback);
@@ -443,8 +426,8 @@ void DelegatedFrameHost::SwapDelegatedFrame(
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);
+ client_->DelegatedFrameHostGetLayer()->SetShowDelegatedContent(
+ frame_provider_.get(), frame_size_in_dip);
} else {
frame_provider_->SetFrameData(frame_data.Pass());
}
@@ -455,50 +438,50 @@ void DelegatedFrameHost::SwapDelegatedFrame(
CheckResizeLock();
if (!damage_rect_in_dip.IsEmpty())
- client_->GetLayer()->OnDelegatedFrameDamage(damage_rect_in_dip);
+ client_->DelegatedFrameHostGetLayer()->OnDelegatedFrameDamage(
+ damage_rect_in_dip);
- pending_delegated_ack_count_++;
-
- if (!compositor) {
+ if (immediate_ack) {
SendDelegatedFrameAck(output_surface_id);
} else if (!use_surfaces_) {
std::vector<ui::LatencyInfo>::const_iterator it;
for (it = latency_info.begin(); it != latency_info.end(); ++it)
- compositor->SetLatencyInfo(*it);
+ compositor_->SetLatencyInfo(*it);
// If we've previously skipped any latency infos add them.
for (it = skipped_latency_info_list_.begin();
it != skipped_latency_info_list_.end();
++it)
- compositor->SetLatencyInfo(*it);
+ compositor_->SetLatencyInfo(*it);
skipped_latency_info_list_.clear();
AddOnCommitCallbackAndDisableLocks(
base::Bind(&DelegatedFrameHost::SendDelegatedFrameAck,
- AsWeakPtr(),
- output_surface_id));
+ AsWeakPtr(), output_surface_id));
} else {
AddOnCommitCallbackAndDisableLocks(base::Closure());
}
DidReceiveFrameFromRenderer(damage_rect);
if (frame_provider_.get() || !surface_id_.is_null())
- delegated_frame_evictor_->SwappedFrame(!host->is_hidden());
+ delegated_frame_evictor_->SwappedFrame(
+ client_->DelegatedFrameHostIsVisible());
// Note: the frame may have been evicted immediately.
}
void DelegatedFrameHost::SendDelegatedFrameAck(uint32 output_surface_id) {
- RenderWidgetHostImpl* host = client_->GetHost();
cc::CompositorFrameAck ack;
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,
- host->GetProcess()->GetID(),
- ack);
+ client_->DelegatedFrameHostSendCompositorSwapAck(output_surface_id, ack);
DCHECK_GT(pending_delegated_ack_count_, 0);
pending_delegated_ack_count_--;
}
+void DelegatedFrameHost::SurfaceDrawn(uint32 output_surface_id,
+ cc::SurfaceDrawStatus drawn) {
+ SendDelegatedFrameAck(output_surface_id);
+}
+
void DelegatedFrameHost::UnusedResourcesAreAvailable() {
if (pending_delegated_ack_count_)
return;
@@ -508,8 +491,6 @@ void DelegatedFrameHost::UnusedResourcesAreAvailable() {
void DelegatedFrameHost::SendReturnedDelegatedResources(
uint32 output_surface_id) {
- RenderWidgetHostImpl* host = client_->GetHost();
-
cc::CompositorFrameAck ack;
if (!surface_returned_resources_.empty()) {
ack.resources.swap(surface_returned_resources_);
@@ -519,11 +500,8 @@ void DelegatedFrameHost::SendReturnedDelegatedResources(
}
DCHECK(!ack.resources.empty());
- RenderWidgetHostImpl::SendReclaimCompositorResources(
- host->GetRoutingID(),
- output_surface_id,
- host->GetProcess()->GetID(),
- ack);
+ client_->DelegatedFrameHostSendReclaimCompositorResources(output_surface_id,
+ ack);
}
void DelegatedFrameHost::ReturnResources(
@@ -538,7 +516,7 @@ void DelegatedFrameHost::ReturnResources(
}
void DelegatedFrameHost::EvictDelegatedFrame() {
- client_->GetLayer()->SetShowSolidColorContent();
+ client_->DelegatedFrameHostGetLayer()->SetShowSolidColorContent();
frame_provider_ = NULL;
if (!surface_id_.is_null()) {
surface_factory_->Destroy(surface_id_);
@@ -551,16 +529,22 @@ void DelegatedFrameHost::EvictDelegatedFrame() {
void DelegatedFrameHost::CopyFromCompositingSurfaceHasResult(
const gfx::Size& dst_size_in_pixel,
const SkColorType color_type,
- const base::Callback<void(bool, const SkBitmap&)>& callback,
+ ReadbackRequestCallback& callback,
scoped_ptr<cc::CopyOutputResult> result) {
if (result->IsEmpty() || result->size().IsEmpty()) {
- callback.Run(false, SkBitmap());
+ callback.Run(SkBitmap(), content::READBACK_FAILED);
return;
}
+ gfx::Size output_size_in_pixel;
+ if (dst_size_in_pixel.IsEmpty())
+ output_size_in_pixel = result->size();
+ else
+ output_size_in_pixel = dst_size_in_pixel;
+
if (result->HasTexture()) {
// GPU-accelerated path
- PrepareTextureCopyOutputResult(dst_size_in_pixel, color_type,
+ PrepareTextureCopyOutputResult(output_size_in_pixel, color_type,
callback,
result.Pass());
return;
@@ -568,12 +552,12 @@ void DelegatedFrameHost::CopyFromCompositingSurfaceHasResult(
DCHECK(result->HasBitmap());
// Software path
- PrepareBitmapCopyOutputResult(dst_size_in_pixel, color_type, callback,
+ PrepareBitmapCopyOutputResult(output_size_in_pixel, color_type, callback,
result.Pass());
}
static void CopyFromCompositingSurfaceFinished(
- const base::Callback<void(bool, const SkBitmap&)>& callback,
+ ReadbackRequestCallback& callback,
scoped_ptr<cc::SingleReleaseCallback> release_callback,
scoped_ptr<SkBitmap> bitmap,
scoped_ptr<SkAutoLockPixels> bitmap_pixels_lock,
@@ -583,33 +567,37 @@ static void CopyFromCompositingSurfaceFinished(
uint32 sync_point = 0;
if (result) {
GLHelper* gl_helper = ImageTransportFactory::GetInstance()->GetGLHelper();
- sync_point = gl_helper->InsertSyncPoint();
+ if (gl_helper)
+ sync_point = gl_helper->InsertSyncPoint();
}
bool lost_resource = sync_point == 0;
release_callback->Run(sync_point, lost_resource);
- callback.Run(result, *bitmap);
+ callback.Run(*bitmap,
+ result ? content::READBACK_SUCCESS : content::READBACK_FAILED);
}
// static
void DelegatedFrameHost::PrepareTextureCopyOutputResult(
const gfx::Size& dst_size_in_pixel,
const SkColorType color_type,
- const base::Callback<void(bool, const SkBitmap&)>& callback,
+ ReadbackRequestCallback& callback,
scoped_ptr<cc::CopyOutputResult> result) {
DCHECK(result->HasTexture());
base::ScopedClosureRunner scoped_callback_runner(
- base::Bind(callback, false, SkBitmap()));
+ base::Bind(callback, SkBitmap(), content::READBACK_FAILED));
- // TODO(sikugu): We should be able to validate the format here using
+ // TODO(siva.gunturi): We should be able to validate the format here using
// GLHelper::IsReadbackConfigSupported before we processs the result.
- // See crbug.com/415682.
+ // See crbug.com/415682 and crbug.com/415131.
scoped_ptr<SkBitmap> bitmap(new SkBitmap);
- if (!bitmap->tryAllocPixels(SkImageInfo::Make(dst_size_in_pixel.width(),
- dst_size_in_pixel.height(),
- color_type,
- kOpaque_SkAlphaType)))
+ if (!bitmap->tryAllocPixels(SkImageInfo::Make(
+ dst_size_in_pixel.width(), dst_size_in_pixel.height(), color_type,
+ kOpaque_SkAlphaType))) {
+ scoped_callback_runner.Reset(base::Bind(
+ callback, SkBitmap(), content::READBACK_BITMAP_ALLOCATION_FAILURE));
return;
+ }
ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
GLHelper* gl_helper = factory->GetGLHelper();
@@ -640,19 +628,19 @@ void DelegatedFrameHost::PrepareTextureCopyOutputResult(
base::Passed(&release_callback),
base::Passed(&bitmap),
base::Passed(&bitmap_pixels_lock)),
- GLHelper::SCALER_QUALITY_FAST);
+ GLHelper::SCALER_QUALITY_GOOD);
}
// static
void DelegatedFrameHost::PrepareBitmapCopyOutputResult(
const gfx::Size& dst_size_in_pixel,
- const SkColorType color_type,
- const base::Callback<void(bool, const SkBitmap&)>& callback,
+ const SkColorType preferred_color_type,
+ ReadbackRequestCallback& callback,
scoped_ptr<cc::CopyOutputResult> result) {
+ SkColorType color_type = preferred_color_type;
if (color_type != kN32_SkColorType && color_type != kAlpha_8_SkColorType) {
- NOTIMPLEMENTED();
- callback.Run(false, SkBitmap());
- return;
+ // Switch back to default colortype if format not supported.
+ color_type = kN32_SkColorType;
}
DCHECK(result->HasBitmap());
scoped_ptr<SkBitmap> source = result->TakeBitmap();
@@ -670,7 +658,7 @@ void DelegatedFrameHost::PrepareBitmapCopyOutputResult(
}
if (color_type == kN32_SkColorType) {
DCHECK_EQ(scaled_bitmap.colorType(), kN32_SkColorType);
- callback.Run(true, scaled_bitmap);
+ callback.Run(scaled_bitmap, READBACK_SUCCESS);
return;
}
DCHECK_EQ(color_type, kAlpha_8_SkColorType);
@@ -682,7 +670,7 @@ void DelegatedFrameHost::PrepareBitmapCopyOutputResult(
bool success = grayscale_bitmap.tryAllocPixels(
SkImageInfo::MakeA8(scaled_bitmap.width(), scaled_bitmap.height()));
if (!success) {
- callback.Run(false, SkBitmap());
+ callback.Run(SkBitmap(), content::READBACK_BITMAP_ALLOCATION_FAILURE);
return;
}
SkCanvas canvas(grayscale_bitmap);
@@ -691,7 +679,7 @@ void DelegatedFrameHost::PrepareBitmapCopyOutputResult(
skia::AdoptRef(SkLumaColorFilter::Create());
paint.setColorFilter(filter.get());
canvas.drawBitmap(scaled_bitmap, SkIntToScalar(0), SkIntToScalar(0), &paint);
- callback.Run(true, grayscale_bitmap);
+ callback.Run(grayscale_bitmap, READBACK_SUCCESS);
}
// static
@@ -756,11 +744,10 @@ void DelegatedFrameHost::CopyFromCompositingSurfaceHasResultForVideo(
// coordinates and sizes even because we letterbox in YUV space
// (see CopyRGBToVideoFrame). They need to be even for the UV samples to
// line up correctly.
- // The video frame's coded_size() and the result's size() are both physical
+ // The video frame's visible_rect() and the result's size() are both physical
// pixels.
- gfx::Rect region_in_frame =
- media::ComputeLetterboxRegion(gfx::Rect(video_frame->coded_size()),
- result->size());
+ gfx::Rect region_in_frame = media::ComputeLetterboxRegion(
+ video_frame->visible_rect(), result->size());
region_in_frame = gfx::Rect(region_in_frame.x() & ~1,
region_in_frame.y() & ~1,
region_in_frame.width() & ~1,
@@ -773,8 +760,7 @@ void DelegatedFrameHost::CopyFromCompositingSurfaceHasResultForVideo(
scoped_ptr<SkBitmap> bitmap = result->TakeBitmap();
// Scale the bitmap to the required size, if necessary.
SkBitmap scaled_bitmap;
- if (result->size().width() != region_in_frame.width() ||
- result->size().height() != region_in_frame.height()) {
+ if (result->size() != region_in_frame.size()) {
skia::ImageOperations::ResizeMethod method =
skia::ImageOperations::RESIZE_GOOD;
scaled_bitmap = skia::ImageOperations::Resize(*bitmap.get(), method,
@@ -839,8 +825,7 @@ void DelegatedFrameHost::CopyFromCompositingSurfaceHasResultForVideo(
gl_helper->CreateReadbackPipelineYUV(quality,
result_rect.size(),
result_rect,
- video_frame->coded_size(),
- region_in_frame,
+ region_in_frame.size(),
true,
true));
yuv_readback_pipeline = dfh->yuv_readback_pipeline_.get();
@@ -857,6 +842,7 @@ void DelegatedFrameHost::CopyFromCompositingSurfaceHasResultForVideo(
yuv_readback_pipeline->ReadbackYUV(texture_mailbox.mailbox(),
texture_mailbox.sync_point(),
video_frame.get(),
+ region_in_frame.origin(),
finished_callback);
}
@@ -865,7 +851,6 @@ void DelegatedFrameHost::CopyFromCompositingSurfaceHasResultForVideo(
void DelegatedFrameHost::OnCompositingDidCommit(
ui::Compositor* compositor) {
- RenderWidgetHostImpl* host = client_->GetHost();
if (can_lock_compositor_ == NO_PENDING_COMMIT) {
can_lock_compositor_ = YES_CAN_LOCK;
if (resize_lock_.get() && resize_lock_->GrabDeferredLock())
@@ -875,7 +860,7 @@ void DelegatedFrameHost::OnCompositingDidCommit(
if (resize_lock_ &&
resize_lock_->expected_size() == current_frame_size_in_dip_) {
resize_lock_.reset();
- host->WasResized();
+ client_->DelegatedFrameHostResizeLockWasReleased();
// We may have had a resize while we had the lock (e.g. if the lock expired,
// or if the UI still gave us some resizes), so make sure we grab a new lock
// if necessary.
@@ -904,33 +889,38 @@ void DelegatedFrameHost::OnCompositingLockStateChanged(
}
}
+void DelegatedFrameHost::OnCompositingShuttingDown(ui::Compositor* compositor) {
+ DCHECK_EQ(compositor, compositor_);
+ ResetCompositor();
+ DCHECK(!compositor_);
+}
+
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);
+ if (client_->DelegatedFrameHostIsVisible())
+ client_->DelegatedFrameHostUpdateVSyncParameters(timebase, interval);
}
////////////////////////////////////////////////////////////////////////////////
-// RenderWidgetHostViewAura, ImageTransportFactoryObserver implementation:
+// DelegatedFrameHost, ImageTransportFactoryObserver implementation:
void DelegatedFrameHost::OnLostResources() {
- RenderWidgetHostImpl* host = client_->GetHost();
if (frame_provider_.get() || !surface_id_.is_null())
EvictDelegatedFrame();
idle_frame_subscriber_textures_.clear();
yuv_readback_pipeline_.reset();
- host->ScheduleComposite();
+ client_->DelegatedFrameHostOnLostCompositorResources();
}
////////////////////////////////////////////////////////////////////////////////
// DelegatedFrameHost, private:
DelegatedFrameHost::~DelegatedFrameHost() {
+ DCHECK(!compositor_);
ImageTransportFactory::GetInstance()->RemoveObserver(this);
if (!surface_id_.is_null())
@@ -952,38 +942,39 @@ void DelegatedFrameHost::RunOnCommitCallbacks() {
void DelegatedFrameHost::AddOnCommitCallbackAndDisableLocks(
const base::Closure& callback) {
- ui::Compositor* compositor = client_->GetCompositor();
- DCHECK(compositor);
-
- if (!compositor->HasObserver(this))
- compositor->AddObserver(this);
+ DCHECK(compositor_);
can_lock_compositor_ = NO_PENDING_COMMIT;
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_.get());
- vsync_manager_ = compositor->vsync_manager();
- vsync_manager_->AddObserver(this);
- }
+void DelegatedFrameHost::SetCompositor(ui::Compositor* compositor) {
+ DCHECK(!compositor_);
+ if (!compositor)
+ return;
+ compositor_ = compositor;
+ compositor_->AddObserver(this);
+ DCHECK(!vsync_manager_.get());
+ vsync_manager_ = compositor_->vsync_manager();
+ vsync_manager_->AddObserver(this);
}
-void DelegatedFrameHost::RemovingFromWindow() {
+void DelegatedFrameHost::ResetCompositor() {
+ if (!compositor_)
+ return;
RunOnCommitCallbacks();
- resize_lock_.reset();
- client_->GetHost()->WasResized();
- ui::Compositor* compositor = client_->GetCompositor();
- if (compositor && compositor->HasObserver(this))
- compositor->RemoveObserver(this);
-
+ if (resize_lock_) {
+ resize_lock_.reset();
+ client_->DelegatedFrameHostResizeLockWasReleased();
+ }
+ if (compositor_->HasObserver(this))
+ compositor_->RemoveObserver(this);
if (vsync_manager_.get()) {
vsync_manager_->RemoveObserver(this);
vsync_manager_ = NULL;
}
+ compositor_ = nullptr;
}
void DelegatedFrameHost::LockResources() {
@@ -991,6 +982,14 @@ void DelegatedFrameHost::LockResources() {
delegated_frame_evictor_->LockFrame();
}
+void DelegatedFrameHost::RequestCopyOfOutput(
+ scoped_ptr<cc::CopyOutputRequest> request) {
+ if (!request_copy_of_output_callback_for_testing_.is_null())
+ request_copy_of_output_callback_for_testing_.Run(request.Pass());
+ else
+ client_->DelegatedFrameHostGetLayer()->RequestCopyOfOutput(request.Pass());
+}
+
void DelegatedFrameHost::UnlockResources() {
DCHECK(frame_provider_.get() || !surface_id_.is_null());
delegated_frame_evictor_->UnlockFrame();
@@ -1014,7 +1013,8 @@ void DelegatedFrameHost::OnLayerRecreated(ui::Layer* old_layer,
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_);
+ current_surface_size_, current_scale_factor_,
+ current_frame_size_in_dip_);
}
}
diff --git a/chromium/content/browser/compositor/delegated_frame_host.h b/chromium/content/browser/compositor/delegated_frame_host.h
index a789ef6e1f0..abb9b082887 100644
--- a/chromium/content/browser/compositor/delegated_frame_host.h
+++ b/chromium/content/browser/compositor/delegated_frame_host.h
@@ -21,10 +21,11 @@
#include "ui/compositor/compositor_vsync_manager.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_owner_delegate.h"
-#include "ui/gfx/rect_conversions.h"
+#include "ui/gfx/geometry/rect_conversions.h"
namespace cc {
class SurfaceFactory;
+enum class SurfaceDrawStatus;
}
namespace media {
@@ -44,26 +45,26 @@ class ResizeLock;
// display them.
class CONTENT_EXPORT DelegatedFrameHostClient {
public:
- virtual ui::Compositor* GetCompositor() const = 0;
- virtual ui::Layer* GetLayer() = 0;
- virtual RenderWidgetHostImpl* GetHost() = 0;
- virtual bool IsVisible() = 0;
- virtual scoped_ptr<ResizeLock> CreateResizeLock(
+ virtual ui::Layer* DelegatedFrameHostGetLayer() const = 0;
+ virtual bool DelegatedFrameHostIsVisible() const = 0;
+ virtual gfx::Size DelegatedFrameHostDesiredSizeInDIP() const = 0;
+
+ virtual bool DelegatedFrameCanCreateResizeLock() const = 0;
+ virtual scoped_ptr<ResizeLock> DelegatedFrameHostCreateResizeLock(
bool defer_compositor_lock) = 0;
- virtual gfx::Size DesiredFrameSize() = 0;
-
- // TODO(ccameron): It is likely that at least one of these two functions is
- // redundant. Find which one, and delete it.
- virtual float CurrentDeviceScaleFactor() = 0;
- virtual gfx::Size ConvertViewSizeToPixel(const gfx::Size& size) = 0;
-
- // These are to be overridden for testing only.
- // TODO(ccameron): This is convoluted. Make the tests that need to override
- // these functions test DelegatedFrameHost directly (rather than do it
- // through RenderWidgetHostViewAura).
- virtual DelegatedFrameHost* GetDelegatedFrameHost() const = 0;
- virtual bool ShouldCreateResizeLock();
- virtual void RequestCopyOfOutput(scoped_ptr<cc::CopyOutputRequest> request);
+ virtual void DelegatedFrameHostResizeLockWasReleased() = 0;
+
+ virtual void DelegatedFrameHostSendCompositorSwapAck(
+ int output_surface_id,
+ const cc::CompositorFrameAck& ack) = 0;
+ virtual void DelegatedFrameHostSendReclaimCompositorResources(
+ int output_surface_id,
+ const cc::CompositorFrameAck& ack) = 0;
+ virtual void DelegatedFrameHostOnLostCompositorResources() = 0;
+
+ virtual void DelegatedFrameHostUpdateVSyncParameters(
+ const base::TimeTicks& timebase,
+ const base::TimeDelta& interval) = 0;
};
// The DelegatedFrameHost is used to host all of the RenderWidgetHostView state
@@ -83,6 +84,34 @@ class CONTENT_EXPORT DelegatedFrameHost
DelegatedFrameHost(DelegatedFrameHostClient* client);
~DelegatedFrameHost() override;
+ // ui::CompositorObserver implementation.
+ void OnCompositingDidCommit(ui::Compositor* compositor) override;
+ void OnCompositingStarted(ui::Compositor* compositor,
+ base::TimeTicks start_time) override;
+ void OnCompositingEnded(ui::Compositor* compositor) override;
+ void OnCompositingAborted(ui::Compositor* compositor) override;
+ void OnCompositingLockStateChanged(ui::Compositor* compositor) override;
+ void OnCompositingShuttingDown(ui::Compositor* compositor) override;
+
+ // ui::CompositorVSyncManager::Observer implementation.
+ void OnUpdateVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval) override;
+
+ // ui::LayerOwnerObserver implementation.
+ void OnLayerRecreated(ui::Layer* old_layer, ui::Layer* new_layer) override;
+
+ // ImageTransportFactoryObserver implementation.
+ void OnLostResources() override;
+
+ // DelegatedFrameEvictorClient implementation.
+ void EvictDelegatedFrame() override;
+
+ // cc::DelegatedFrameProviderClient implementation.
+ void UnusedResourcesAreAvailable() override;
+
+ // cc::SurfaceFactoryClient implementation.
+ void ReturnResources(const cc::ReturnedResourceArray& resources) override;
+
bool CanCopyToBitmap() const;
// Public interface exposed to RenderWidgetHostView.
@@ -96,12 +125,14 @@ class CONTENT_EXPORT DelegatedFrameHost
void WasResized();
bool HasSavedFrame();
gfx::Size GetRequestedRendererSize() const;
- void AddedToWindow();
- void RemovingFromWindow();
+ void SetCompositor(ui::Compositor* compositor);
+ void ResetCompositor();
+ // Note: |src_subset| is specified in DIP dimensions while |output_size|
+ // expects pixels.
void CopyFromCompositingSurface(const gfx::Rect& src_subrect,
const gfx::Size& output_size,
- CopyFromCompositingSurfaceCallback& callback,
- const SkColorType color_type);
+ ReadbackRequestCallback& callback,
+ const SkColorType preferred_color_type);
void CopyFromCompositingSurfaceToVideoFrame(
const gfx::Rect& src_subrect,
const scoped_refptr<media::VideoFrame>& target,
@@ -112,6 +143,7 @@ class CONTENT_EXPORT DelegatedFrameHost
scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber);
void EndFrameSubscription();
bool HasFrameSubscriber() const { return frame_subscriber_; }
+ uint32_t GetSurfaceIdNamespace();
// Exposed for tests.
cc::DelegatedFrameProvider* FrameProviderForTesting() const {
@@ -121,10 +153,13 @@ class CONTENT_EXPORT DelegatedFrameHost
void OnCompositingDidCommitForTesting(ui::Compositor* compositor) {
OnCompositingDidCommit(compositor);
}
- bool ShouldCreateResizeLockForTesting() { return ShouldCreateResizeLock(); }
bool ReleasedFrontLockActiveForTesting() const {
return !!released_front_lock_.get();
}
+ void SetRequestCopyOfOutputCallbackForTesting(
+ const base::Callback<void(scoped_ptr<cc::CopyOutputRequest>)>& callback) {
+ request_copy_of_output_callback_for_testing_ = callback;
+ }
private:
friend class DelegatedFrameHostClient;
@@ -139,28 +174,9 @@ class CONTENT_EXPORT DelegatedFrameHost
return frame_subscriber_.get();
}
bool ShouldCreateResizeLock();
- void RequestCopyOfOutput(scoped_ptr<cc::CopyOutputRequest> request);
-
void LockResources();
void UnlockResources();
-
- // Overridden from ui::CompositorObserver:
- void OnCompositingDidCommit(ui::Compositor* compositor) override;
- void OnCompositingStarted(ui::Compositor* compositor,
- base::TimeTicks start_time) override;
- void OnCompositingEnded(ui::Compositor* compositor) override;
- void OnCompositingAborted(ui::Compositor* compositor) override;
- void OnCompositingLockStateChanged(ui::Compositor* compositor) override;
-
- // Overridden from ui::CompositorVSyncManager::Observer:
- void OnUpdateVSyncParameters(base::TimeTicks timebase,
- base::TimeDelta interval) override;
-
- // Overridden from ui::LayerOwnerObserver:
- void OnLayerRecreated(ui::Layer* old_layer, ui::Layer* new_layer) override;
-
- // Overridden from ImageTransportFactoryObserver:
- void OnLostResources() override;
+ void RequestCopyOfOutput(scoped_ptr<cc::CopyOutputRequest> request);
bool ShouldSkipFrame(gfx::Size size_in_dip) const;
@@ -182,17 +198,17 @@ class CONTENT_EXPORT DelegatedFrameHost
static void CopyFromCompositingSurfaceHasResult(
const gfx::Size& dst_size_in_pixel,
const SkColorType color_type,
- const base::Callback<void(bool, const SkBitmap&)>& callback,
+ ReadbackRequestCallback& callback,
scoped_ptr<cc::CopyOutputResult> result);
static void PrepareTextureCopyOutputResult(
const gfx::Size& dst_size_in_pixel,
const SkColorType color_type,
- const base::Callback<void(bool, const SkBitmap&)>& callback,
+ ReadbackRequestCallback& callback,
scoped_ptr<cc::CopyOutputResult> result);
static void PrepareBitmapCopyOutputResult(
const gfx::Size& dst_size_in_pixel,
const SkColorType color_type,
- const base::Callback<void(bool, const SkBitmap&)>& callback,
+ ReadbackRequestCallback& callback,
scoped_ptr<cc::CopyOutputResult> result);
static void CopyFromCompositingSurfaceHasResultForVideo(
base::WeakPtr<DelegatedFrameHost> rwhva,
@@ -212,20 +228,15 @@ class CONTENT_EXPORT DelegatedFrameHost
uint32 sync_point);
void SendDelegatedFrameAck(uint32 output_surface_id);
+ void SurfaceDrawn(uint32 output_surface_id, cc::SurfaceDrawStatus drawn);
void SendReturnedDelegatedResources(uint32 output_surface_id);
- // DelegatedFrameEvictorClient implementation.
- void EvictDelegatedFrame() override;
-
- // cc::DelegatedFrameProviderClient implementation.
- void UnusedResourcesAreAvailable() override;
-
- // cc::SurfaceFactoryClient implementation.
- void ReturnResources(const cc::ReturnedResourceArray& resources) override;
-
+ // Called to consult the current |frame_subscriber_|, to determine and maybe
+ // initiate a copy-into-video-frame request.
void DidReceiveFrameFromRenderer(const gfx::Rect& damage_rect);
- DelegatedFrameHostClient* client_;
+ DelegatedFrameHostClient* const client_;
+ ui::Compositor* compositor_;
// True if this renders into a Surface, false if it renders into a delegated
// layer.
@@ -268,6 +279,7 @@ class CONTENT_EXPORT DelegatedFrameHost
scoped_ptr<cc::SurfaceFactory> surface_factory_;
cc::SurfaceId surface_id_;
gfx::Size current_surface_size_;
+ float current_scale_factor_;
cc::ReturnedResourceArray surface_returned_resources_;
// This lock is the one waiting for a frame of the right size to come back
@@ -301,6 +313,11 @@ class CONTENT_EXPORT DelegatedFrameHost
scoped_ptr<RenderWidgetHostViewFrameSubscriber> frame_subscriber_;
std::vector<scoped_refptr<OwnedMailbox> > idle_frame_subscriber_textures_;
+ // Callback used to pass the output request to the layer or to a function
+ // specified by a test.
+ base::Callback<void(scoped_ptr<cc::CopyOutputRequest>)>
+ request_copy_of_output_callback_for_testing_;
+
// YUV readback pipeline.
scoped_ptr<content::ReadbackYUVInterface>
yuv_readback_pipeline_;
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 e68c5c8fd20..273f40bf91e 100644
--- a/chromium/content/browser/compositor/gpu_browser_compositor_output_surface.cc
+++ b/chromium/content/browser/compositor/gpu_browser_compositor_output_surface.cc
@@ -6,29 +6,32 @@
#include "cc/output/compositor_frame.h"
#include "cc/output/output_surface_client.h"
+#include "content/browser/compositor/browser_compositor_overlay_candidate_validator.h"
#include "content/browser/compositor/reflector_impl.h"
+#include "content/browser/compositor/reflector_texture.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 {
GpuBrowserCompositorOutputSurface::GpuBrowserCompositorOutputSurface(
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)
+ scoped_ptr<BrowserCompositorOverlayCandidateValidator>
+ overlay_candidate_validator)
: BrowserCompositorOutputSurface(context,
- surface_id,
- output_surface_map,
- vsync_manager),
+ vsync_manager,
+ overlay_candidate_validator.Pass()),
+#if defined(OS_MACOSX)
+ should_show_frames_state_(SHOULD_SHOW_FRAMES),
+#endif
swap_buffers_completion_callback_(
base::Bind(&GpuBrowserCompositorOutputSurface::OnSwapBuffersCompleted,
- base::Unretained(this))) {
- overlay_candidate_validator_ = overlay_candidate_validator.Pass();
+ base::Unretained(this))),
+ update_vsync_parameters_callback_(base::Bind(
+ &BrowserCompositorOutputSurface::OnUpdateVSyncParametersFromGpu,
+ base::Unretained(this))) {
}
GpuBrowserCompositorOutputSurface::~GpuBrowserCompositorOutputSurface() {}
@@ -51,21 +54,36 @@ bool GpuBrowserCompositorOutputSurface::BindToClient(
GetCommandBufferProxy()->SetSwapBuffersCompletionCallback(
swap_buffers_completion_callback_.callback());
+ GetCommandBufferProxy()->SetUpdateVSyncParametersCallback(
+ update_vsync_parameters_callback_.callback());
return true;
}
+void GpuBrowserCompositorOutputSurface::OnReflectorChanged() {
+ if (!reflector_) {
+ reflector_texture_.reset();
+ } else {
+ reflector_texture_.reset(new ReflectorTexture(context_provider()));
+ reflector_->OnSourceTextureMailboxUpdated(reflector_texture_->mailbox());
+ }
+}
+
void GpuBrowserCompositorOutputSurface::SwapBuffers(
cc::CompositorFrame* frame) {
DCHECK(frame->gl_frame_data);
GetCommandBufferProxy()->SetLatencyInfo(frame->metadata.latency_info);
- if (reflector_.get()) {
+ if (reflector_) {
if (frame->gl_frame_data->sub_buffer_rect ==
- gfx::Rect(frame->gl_frame_data->size))
- reflector_->OnSwapBuffers();
- else
- reflector_->OnPostSubBuffer(frame->gl_frame_data->sub_buffer_rect);
+ gfx::Rect(frame->gl_frame_data->size)) {
+ reflector_texture_->CopyTextureFullImage(SurfaceSize());
+ reflector_->OnSourceSwapBuffers();
+ } else {
+ const gfx::Rect& rect = frame->gl_frame_data->sub_buffer_rect;
+ reflector_texture_->CopyTextureSubImage(rect);
+ reflector_->OnSourcePostSubBuffer(rect);
+ }
}
if (frame->gl_frame_data->sub_buffer_rect ==
@@ -77,6 +95,13 @@ void GpuBrowserCompositorOutputSurface::SwapBuffers(
}
client_->DidSwapBuffers();
+
+#if defined(OS_MACOSX)
+ if (should_show_frames_state_ ==
+ SHOULD_NOT_SHOW_FRAMES_NO_SWAP_AFTER_SUSPENDED) {
+ should_show_frames_state_ = SHOULD_SHOW_FRAMES;
+ }
+#endif
}
void GpuBrowserCompositorOutputSurface::OnSwapBuffersCompleted(
@@ -86,14 +111,7 @@ void GpuBrowserCompositorOutputSurface::OnSwapBuffersCompleted(
// 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));
- }
+ RenderWidgetHostImpl::CompositorFrameDrawn(latency_info);
OnSwapBuffersComplete();
#endif
}
@@ -102,6 +120,36 @@ void GpuBrowserCompositorOutputSurface::OnSwapBuffersCompleted(
void GpuBrowserCompositorOutputSurface::OnSurfaceDisplayed() {
cc::OutputSurface::OnSwapBuffersComplete();
}
+
+void GpuBrowserCompositorOutputSurface::SetSurfaceSuspendedForRecycle(
+ bool suspended) {
+ if (suspended) {
+ // It may be that there are frames in-flight from the GPU process back to
+ // the browser. Make sure that these frames are not displayed by ignoring
+ // them in GpuProcessHostUIShim, until the browser issues a SwapBuffers for
+ // the new content.
+ should_show_frames_state_ = SHOULD_NOT_SHOW_FRAMES_SUSPENDED;
+ } else {
+ // Discard the backbuffer before drawing the new frame. This is necessary
+ // only when using a ImageTransportSurfaceFBO with a
+ // CALayerStorageProvider. Discarding the backbuffer results in the next
+ // frame using a new CALayer and CAContext, which guarantees that the
+ // browser will not flash stale content when adding the remote CALayer to
+ // the NSView hierarchy (it could flash stale content because the system
+ // window server is not synchronized with any signals we control or
+ // observe).
+ if (should_show_frames_state_ == SHOULD_NOT_SHOW_FRAMES_SUSPENDED) {
+ DiscardBackbuffer();
+ should_show_frames_state_ =
+ SHOULD_NOT_SHOW_FRAMES_NO_SWAP_AFTER_SUSPENDED;
+ }
+ }
+}
+
+bool GpuBrowserCompositorOutputSurface::
+ SurfaceShouldNotShowFramesAfterSuspendForRecycle() const {
+ return should_show_frames_state_ != SHOULD_SHOW_FRAMES;
+}
#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 c558b56c04b..125985844d6 100644
--- a/chromium/content/browser/compositor/gpu_browser_compositor_output_surface.h
+++ b/chromium/content/browser/compositor/gpu_browser_compositor_output_surface.h
@@ -12,12 +12,10 @@ namespace ui {
class CompositorVSyncManager;
}
-namespace cc {
-class OverlayCandidateValidator;
-}
-
namespace content {
class CommandBufferProxyImpl;
+class BrowserCompositorOverlayCandidateValidator;
+class ReflectorTexture;
// Adapts a WebGraphicsContext3DCommandBufferImpl into a
// cc::OutputSurface that also handles vsync parameter updates
@@ -27,20 +25,36 @@ class GpuBrowserCompositorOutputSurface
public:
GpuBrowserCompositorOutputSurface(
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);
+ scoped_ptr<BrowserCompositorOverlayCandidateValidator>
+ overlay_candidate_validator);
~GpuBrowserCompositorOutputSurface() override;
protected:
+ // BrowserCompositorOutputSurface:
+ void OnReflectorChanged() override;
+
// cc::OutputSurface implementation.
void SwapBuffers(cc::CompositorFrame* frame) override;
bool BindToClient(cc::OutputSurfaceClient* client) override;
#if defined(OS_MACOSX)
void OnSurfaceDisplayed() override;
+ void SetSurfaceSuspendedForRecycle(bool suspended) override;
+ bool SurfaceShouldNotShowFramesAfterSuspendForRecycle() const override;
+ enum ShouldShowFramesState {
+ // Frames that come from the GPU process should appear on-screen.
+ SHOULD_SHOW_FRAMES,
+ // The compositor has been suspended. Any frames that come from the GPU
+ // process are for the pre-suspend content and should not be displayed.
+ SHOULD_NOT_SHOW_FRAMES_SUSPENDED,
+ // The compositor has been un-suspended, but has not yet issued a swap
+ // since being un-suspended, so any frames that come from the GPU process
+ // are for pre-suspend content and should not be displayed.
+ SHOULD_NOT_SHOW_FRAMES_NO_SWAP_AFTER_SUSPENDED,
+ };
+ ShouldShowFramesState should_show_frames_state_;
#endif
CommandBufferProxyImpl* GetCommandBufferProxy();
@@ -48,6 +62,11 @@ class GpuBrowserCompositorOutputSurface
base::CancelableCallback<void(const std::vector<ui::LatencyInfo>&)>
swap_buffers_completion_callback_;
+ base::CancelableCallback<void(base::TimeTicks timebase,
+ base::TimeDelta interval)>
+ update_vsync_parameters_callback_;
+
+ scoped_ptr<ReflectorTexture> reflector_texture_;
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 24e721f4201..95c3f1d13ec 100644
--- a/chromium/content/browser/compositor/gpu_process_transport_factory.cc
+++ b/chromium/content/browser/compositor/gpu_process_transport_factory.cc
@@ -11,18 +11,22 @@
#include "base/location.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram.h"
+#include "base/profiler/scoped_tracker.h"
+#include "base/threading/simple_thread.h"
#include "base/threading/thread.h"
#include "cc/output/compositor_frame.h"
#include "cc/output/output_surface.h"
+#include "cc/raster/task_graph_runner.h"
+#include "cc/surfaces/onscreen_display_client.h"
+#include "cc/surfaces/surface_display_output_surface.h"
#include "cc/surfaces/surface_manager.h"
#include "content/browser/compositor/browser_compositor_output_surface.h"
-#include "content/browser/compositor/browser_compositor_output_surface_proxy.h"
+#include "content/browser/compositor/browser_compositor_overlay_candidate_validator.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/offscreen_browser_compositor_output_surface.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"
@@ -43,14 +47,15 @@
#include "ui/compositor/compositor.h"
#include "ui/compositor/compositor_constants.h"
#include "ui/compositor/compositor_switches.h"
+#include "ui/gfx/geometry/size.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/size.h"
#if defined(OS_WIN)
#include "content/browser/compositor/software_output_device_win.h"
#elif defined(USE_OZONE)
-#include "content/browser/compositor/overlay_candidate_validator_ozone.h"
+#include "content/browser/compositor/browser_compositor_overlay_candidate_validator_ozone.h"
#include "content/browser/compositor/software_output_device_ozone.h"
+#include "ui/ozone/public/ozone_switches.h"
#include "ui/ozone/public/surface_factory_ozone.h"
#elif defined(USE_X11)
#include "content/browser/compositor/software_output_device_x11.h"
@@ -61,31 +66,51 @@
using cc::ContextProvider;
using gpu::gles2::GLES2Interface;
+static const int kNumRetriesBeforeSoftwareFallback = 4;
+
namespace content {
+namespace {
+
+class RasterThread : public base::SimpleThread {
+ public:
+ RasterThread(cc::TaskGraphRunner* task_graph_runner)
+ : base::SimpleThread("CompositorTileWorker1"),
+ task_graph_runner_(task_graph_runner) {}
+
+ // Overridden from base::SimpleThread:
+ void Run() override { task_graph_runner_->Run(); }
+
+ private:
+ cc::TaskGraphRunner* task_graph_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(RasterThread);
+};
+
+} // namespace
struct GpuProcessTransportFactory::PerCompositorData {
int surface_id;
- scoped_refptr<ReflectorImpl> reflector;
- scoped_ptr<OnscreenDisplayClient> display_client;
+ BrowserCompositorOutputSurface* surface;
+ ReflectorImpl* reflector;
+ scoped_ptr<cc::OnscreenDisplayClient> display_client;
+
+ PerCompositorData() : surface_id(0), surface(nullptr), reflector(nullptr) {}
};
GpuProcessTransportFactory::GpuProcessTransportFactory()
: next_surface_id_namespace_(1u),
+ task_graph_runner_(new cc::TaskGraphRunner),
callback_factory_(this) {
- output_surface_proxy_ = new BrowserCompositorOutputSurfaceProxy(
- &output_surface_map_);
-#if defined(OS_CHROMEOS)
- bool use_thread = !base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kUIDisableThreadedCompositing);
-#else
- bool use_thread = false;
-#endif
- if (use_thread) {
- compositor_thread_.reset(new base::Thread("Browser Compositor"));
- compositor_thread_->Start();
- }
if (UseSurfacesEnabled())
surface_manager_ = make_scoped_ptr(new cc::SurfaceManager);
+
+ if (ui::IsUIImplSidePaintingEnabled()) {
+ raster_thread_.reset(new RasterThread(task_graph_runner_.get()));
+ raster_thread_->Start();
+ }
+#if defined(OS_WIN)
+ software_backing_.reset(new OutputDeviceBacking);
+#endif
}
GpuProcessTransportFactory::~GpuProcessTransportFactory() {
@@ -93,6 +118,10 @@ GpuProcessTransportFactory::~GpuProcessTransportFactory() {
// Make sure the lost context callback doesn't try to run during destruction.
callback_factory_.InvalidateWeakPtrs();
+
+ task_graph_runner_->Shutdown();
+ if (raster_thread_)
+ raster_thread_->Join();
}
scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
@@ -104,11 +133,12 @@ GpuProcessTransportFactory::CreateOffscreenCommandBufferContext() {
return CreateContextCommon(gpu_channel_host, 0);
}
-scoped_ptr<cc::SoftwareOutputDevice> CreateSoftwareOutputDevice(
+scoped_ptr<cc::SoftwareOutputDevice>
+GpuProcessTransportFactory::CreateSoftwareOutputDevice(
ui::Compositor* compositor) {
#if defined(OS_WIN)
- return scoped_ptr<cc::SoftwareOutputDevice>(new SoftwareOutputDeviceWin(
- compositor));
+ return scoped_ptr<cc::SoftwareOutputDevice>(
+ new SoftwareOutputDeviceWin(software_backing_.get(), compositor));
#elif defined(USE_OZONE)
return scoped_ptr<cc::SoftwareOutputDevice>(new SoftwareOutputDeviceOzone(
compositor));
@@ -124,191 +154,216 @@ scoped_ptr<cc::SoftwareOutputDevice> CreateSoftwareOutputDevice(
#endif
}
-scoped_ptr<cc::OverlayCandidateValidator> CreateOverlayCandidateValidator(
- gfx::AcceleratedWidget widget) {
+scoped_ptr<BrowserCompositorOverlayCandidateValidator>
+CreateOverlayCandidateValidator(gfx::AcceleratedWidget widget) {
#if defined(USE_OZONE)
ui::OverlayCandidatesOzone* overlay_candidates =
ui::SurfaceFactoryOzone::GetInstance()->GetOverlayCandidates(widget);
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (overlay_candidates &&
- base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableHardwareOverlays)) {
- return scoped_ptr<cc::OverlayCandidateValidator>(
- new OverlayCandidateValidatorOzone(widget, overlay_candidates));
+ (command_line->HasSwitch(switches::kEnableHardwareOverlays) ||
+ command_line->HasSwitch(switches::kOzoneTestSingleOverlaySupport))) {
+ return scoped_ptr<BrowserCompositorOverlayCandidateValidator>(
+ new BrowserCompositorOverlayCandidateValidatorOzone(
+ widget, overlay_candidates));
}
#endif
- return scoped_ptr<cc::OverlayCandidateValidator>();
+ return scoped_ptr<BrowserCompositorOverlayCandidateValidator>();
+}
+
+static bool ShouldCreateGpuOutputSurface(ui::Compositor* compositor) {
+#if defined(OS_CHROMEOS)
+ // Software fallback does not happen on Chrome OS.
+ return true;
+#endif
+
+#if defined(OS_WIN)
+ if (::GetProp(compositor->widget(), kForceSoftwareCompositor) &&
+ ::RemoveProp(compositor->widget(), kForceSoftwareCompositor))
+ return false;
+#endif
+
+ return GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor();
}
void GpuProcessTransportFactory::CreateOutputSurface(
- base::WeakPtr<ui::Compositor> compositor,
- bool software_fallback) {
+ base::WeakPtr<ui::Compositor> compositor) {
DCHECK(!!compositor);
PerCompositorData* data = per_compositor_data_[compositor.get()];
- if (!data)
+ if (!data) {
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/466870
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile1(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "466870 GpuProcessTransportFactory::CreateOutputSurface1"));
data = CreatePerCompositorData(compositor.get());
-
- bool create_software_renderer = software_fallback;
-#if defined(OS_CHROMEOS)
- // Software fallback does not happen on Chrome OS.
- create_software_renderer = false;
-#elif defined(OS_WIN)
- if (::GetProp(compositor->widget(), kForceSoftwareCompositor)) {
- if (::RemoveProp(compositor->widget(), kForceSoftwareCompositor))
- create_software_renderer = true;
+ } else {
+ // TODO(piman): Use GpuSurfaceTracker to map ids to surfaces instead of an
+ // output_surface_map_ here.
+ output_surface_map_.Remove(data->surface_id);
+ data->surface = nullptr;
}
-#endif
- if (!GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor())
- create_software_renderer = true;
- if (!create_software_renderer) {
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/466870
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile2(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "466870 GpuProcessTransportFactory::CreateOutputSurface2"));
+
+ bool create_gpu_output_surface =
+ ShouldCreateGpuOutputSurface(compositor.get());
+ if (create_gpu_output_surface) {
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/466870
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile3(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "466870 GpuProcessTransportFactory::CreateOutputSurface3"));
+
CauseForGpuLaunch cause =
CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE;
BrowserGpuChannelHostFactory::instance()->EstablishGpuChannel(
- cause,
- base::Bind(&GpuProcessTransportFactory::EstablishedGpuChannel,
- callback_factory_.GetWeakPtr(),
- compositor,
- create_software_renderer));
+ cause, base::Bind(&GpuProcessTransportFactory::EstablishedGpuChannel,
+ callback_factory_.GetWeakPtr(), compositor,
+ create_gpu_output_surface, 0));
} else {
- EstablishedGpuChannel(compositor, create_software_renderer);
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/466870
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile4(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "466870 GpuProcessTransportFactory::CreateOutputSurface4"));
+
+ EstablishedGpuChannel(compositor, create_gpu_output_surface, 0);
}
}
void GpuProcessTransportFactory::EstablishedGpuChannel(
base::WeakPtr<ui::Compositor> compositor,
- bool create_software_renderer) {
+ bool create_gpu_output_surface,
+ int num_attempts) {
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(gpu_channel_host,
- data->surface_id),
- "Compositor");
- }
- UMA_HISTOGRAM_BOOLEAN("Aura.CreatedGpuBrowserCompositor",
- !!context_provider.get());
+ if (num_attempts > kNumRetriesBeforeSoftwareFallback) {
+#if defined(OS_CHROMEOS)
+ LOG(FATAL) << "Unable to create a UI graphics context, and cannot use "
+ << "software compositing on ChromeOS.";
+#endif
+ create_gpu_output_surface = false;
+ }
- 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();
+ scoped_refptr<ContextProviderCommandBuffer> context_provider;
+ if (create_gpu_output_surface) {
+ scoped_refptr<GpuChannelHost> gpu_channel_host =
+ BrowserGpuChannelHostFactory::instance()->GetGpuChannel();
+ if (gpu_channel_host.get()) {
+ context_provider = ContextProviderCommandBuffer::Create(
+ GpuProcessTransportFactory::CreateContextCommon(gpu_channel_host,
+ data->surface_id),
+ BROWSER_COMPOSITOR_ONSCREEN_CONTEXT);
+ if (context_provider && !context_provider->BindToCurrentThread())
+ context_provider = nullptr;
+ }
- // Here we know the GpuProcessHost has been set up, because we created a
- // context.
- output_surface_proxy_->ConnectToGpuProcessHost(
- compositor_thread_task_runner.get());
+ UMA_HISTOGRAM_BOOLEAN("Aura.CreatedGpuBrowserCompositor",
+ !!context_provider.get());
+
+ if (!context_provider) {
+ // Try again.
+ CauseForGpuLaunch cause =
+ CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE;
+ BrowserGpuChannelHostFactory::instance()->EstablishGpuChannel(
+ cause, base::Bind(&GpuProcessTransportFactory::EstablishedGpuChannel,
+ callback_factory_.GetWeakPtr(), compositor,
+ create_gpu_output_surface, num_attempts + 1));
+ return;
+ }
}
- 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> display_surface;
- if (!context_provider.get()) {
- display_surface =
- make_scoped_ptr(new SoftwareBrowserCompositorOutputSurface(
- output_surface_proxy_,
- 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(),
+ scoped_ptr<BrowserCompositorOutputSurface> surface;
+ if (!create_gpu_output_surface) {
+ surface = make_scoped_ptr(new SoftwareBrowserCompositorOutputSurface(
+ CreateSoftwareOutputDevice(compositor.get()),
+ compositor->vsync_manager()));
+ } else {
+ DCHECK(context_provider);
+ if (!data->surface_id) {
+ surface = make_scoped_ptr(new OffscreenBrowserCompositorOutputSurface(
+ context_provider, compositor->vsync_manager(),
+ scoped_ptr<BrowserCompositorOverlayCandidateValidator>()));
+ } else
+#if defined(USE_OZONE)
+ if (ui::SurfaceFactoryOzone::GetInstance()
+ ->CanShowPrimaryPlaneAsOverlay()) {
+ surface =
+ make_scoped_ptr(new GpuSurfacelessBrowserCompositorOutputSurface(
+ context_provider, data->surface_id, compositor->vsync_manager(),
+ CreateOverlayCandidateValidator(compositor->widget()), GL_RGB,
+ BrowserGpuMemoryBufferManager::current()));
+ } else
+#endif
+ {
+ surface = make_scoped_ptr(new GpuBrowserCompositorOutputSurface(
+ context_provider, compositor->vsync_manager(),
CreateOverlayCandidateValidator(compositor->widget())));
}
- scoped_ptr<OnscreenDisplayClient> display_client(new OnscreenDisplayClient(
- display_surface.Pass(), manager, compositor->task_runner()));
-
- scoped_ptr<SurfaceDisplayOutputSurface> output_surface(
- new SurfaceDisplayOutputSurface(
- 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();
- compositor->SetOutputSurface(output_surface.Pass());
- return;
}
- if (!context_provider.get()) {
- if (compositor_thread_.get()) {
- LOG(FATAL) << "Failed to create UI context, but can't use software"
- " compositing with browser threaded compositing. Aborting.";
- }
+ // TODO(piman): Use GpuSurfaceTracker to map ids to surfaces instead of an
+ // output_surface_map_ here.
+ output_surface_map_.AddWithID(surface.get(), data->surface_id);
+ data->surface = surface.get();
+ if (data->reflector)
+ data->reflector->OnSourceSurfaceReady(data->surface);
- scoped_ptr<SoftwareBrowserCompositorOutputSurface> surface(
- new SoftwareBrowserCompositorOutputSurface(
- output_surface_proxy_,
- CreateSoftwareOutputDevice(compositor.get()),
- data->surface_id,
- &output_surface_map_,
- compositor->vsync_manager()));
+ if (!UseSurfacesEnabled()) {
compositor->SetOutputSurface(surface.Pass());
return;
}
- 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())));
-
- if (data->reflector.get())
- data->reflector->ReattachToOutputSurfaceFromMainThread(surface.get());
-
- compositor->SetOutputSurface(surface.Pass());
+ // This gets a bit confusing. Here we have a ContextProvider in the |surface|
+ // configured to render directly to this widget. We need to make an
+ // OnscreenDisplayClient associated with that context, then return a
+ // SurfaceDisplayOutputSurface set up to draw to the display's surface.
+ cc::SurfaceManager* manager = surface_manager_.get();
+ scoped_ptr<cc::OnscreenDisplayClient> display_client(
+ new cc::OnscreenDisplayClient(
+ surface.Pass(), manager, HostSharedBitmapManager::current(),
+ BrowserGpuMemoryBufferManager::current(),
+ compositor->GetRendererSettings(), compositor->task_runner()));
+
+ scoped_ptr<cc::SurfaceDisplayOutputSurface> output_surface(
+ new cc::SurfaceDisplayOutputSurface(
+ manager, compositor->surface_id_allocator(), context_provider));
+ display_client->set_surface_output_surface(output_surface.get());
+ output_surface->set_display_client(display_client.get());
+ display_client->display()->Resize(compositor->size());
+ data->display_client = display_client.Pass();
+ compositor->SetOutputSurface(output_surface.Pass());
}
-scoped_refptr<ui::Reflector> GpuProcessTransportFactory::CreateReflector(
- ui::Compositor* source,
- ui::Layer* target) {
- PerCompositorData* data = per_compositor_data_[source];
- DCHECK(data);
-
- data->reflector = new ReflectorImpl(source,
- target,
- &output_surface_map_,
- GetCompositorMessageLoop(),
- data->surface_id);
- return data->reflector;
+scoped_ptr<ui::Reflector> GpuProcessTransportFactory::CreateReflector(
+ ui::Compositor* source_compositor,
+ ui::Layer* target_layer) {
+ PerCompositorData* source_data = per_compositor_data_[source_compositor];
+ DCHECK(source_data);
+
+ scoped_ptr<ReflectorImpl> reflector(
+ new ReflectorImpl(source_compositor, target_layer));
+ source_data->reflector = reflector.get();
+ if (BrowserCompositorOutputSurface* source_surface = source_data->surface)
+ reflector->OnSourceSurfaceReady(source_surface);
+ return reflector.Pass();
}
-void GpuProcessTransportFactory::RemoveReflector(
- scoped_refptr<ui::Reflector> reflector) {
- ReflectorImpl* reflector_impl =
- static_cast<ReflectorImpl*>(reflector.get());
+void GpuProcessTransportFactory::RemoveReflector(ui::Reflector* reflector) {
+ ReflectorImpl* reflector_impl = static_cast<ReflectorImpl*>(reflector);
PerCompositorData* data =
per_compositor_data_[reflector_impl->mirrored_compositor()];
DCHECK(data);
data->reflector->Shutdown();
- data->reflector = NULL;
+ data->reflector = nullptr;
}
void GpuProcessTransportFactory::RemoveCompositor(ui::Compositor* compositor) {
@@ -317,7 +372,12 @@ void GpuProcessTransportFactory::RemoveCompositor(ui::Compositor* compositor) {
return;
PerCompositorData* data = it->second;
DCHECK(data);
- GpuSurfaceTracker::Get()->RemoveSurface(data->surface_id);
+ // TODO(piman): Use GpuSurfaceTracker to map ids to surfaces instead of an
+ // output_surface_map_ here.
+ if (data->surface)
+ output_surface_map_.Remove(data->surface_id);
+ if (data->surface_id)
+ GpuSurfaceTracker::Get()->RemoveSurface(data->surface_id);
delete data;
per_compositor_data_.erase(it);
if (per_compositor_data_.empty()) {
@@ -341,6 +401,10 @@ void GpuProcessTransportFactory::RemoveCompositor(ui::Compositor* compositor) {
bool GpuProcessTransportFactory::DoesCreateTestContexts() { return false; }
+uint32 GpuProcessTransportFactory::GetImageTextureTarget() {
+ return BrowserGpuChannelHostFactory::GetImageTextureTarget();
+}
+
cc::SharedBitmapManager* GpuProcessTransportFactory::GetSharedBitmapManager() {
return HostSharedBitmapManager::current();
}
@@ -350,14 +414,12 @@ GpuProcessTransportFactory::GetGpuMemoryBufferManager() {
return BrowserGpuMemoryBufferManager::current();
}
-ui::ContextFactory* GpuProcessTransportFactory::GetContextFactory() {
- return this;
+cc::TaskGraphRunner* GpuProcessTransportFactory::GetTaskGraphRunner() {
+ return task_graph_runner_.get();
}
-base::MessageLoopProxy* GpuProcessTransportFactory::GetCompositorMessageLoop() {
- if (!compositor_thread_)
- return NULL;
- return compositor_thread_->message_loop_proxy().get();
+ui::ContextFactory* GpuProcessTransportFactory::GetContextFactory() {
+ return this;
}
gfx::GLSurfaceHandle GpuProcessTransportFactory::GetSharedSurfaceHandle() {
@@ -374,6 +436,17 @@ GpuProcessTransportFactory::CreateSurfaceIdAllocator() {
new cc::SurfaceIdAllocator(next_surface_id_namespace_++));
}
+void GpuProcessTransportFactory::ResizeDisplay(ui::Compositor* compositor,
+ const gfx::Size& size) {
+ PerCompositorDataMap::iterator it = per_compositor_data_.find(compositor);
+ if (it == per_compositor_data_.end())
+ return;
+ PerCompositorData* data = it->second;
+ DCHECK(data);
+ if (data->display_client)
+ data->display_client->display()->Resize(size);
+}
+
cc::SurfaceManager* GpuProcessTransportFactory::GetSurfaceManager() {
return surface_manager_.get();
}
@@ -406,6 +479,29 @@ void GpuProcessTransportFactory::OnSurfaceDisplayed(int surface_id) {
if (surface)
surface->OnSurfaceDisplayed();
}
+
+void GpuProcessTransportFactory::SetCompositorSuspendedForRecycle(
+ ui::Compositor* compositor,
+ bool suspended) {
+ PerCompositorDataMap::iterator it = per_compositor_data_.find(compositor);
+ if (it == per_compositor_data_.end())
+ return;
+ PerCompositorData* data = it->second;
+ DCHECK(data);
+ BrowserCompositorOutputSurface* surface =
+ output_surface_map_.Lookup(data->surface_id);
+ if (surface)
+ surface->SetSurfaceSuspendedForRecycle(suspended);
+}
+
+bool GpuProcessTransportFactory::
+ SurfaceShouldNotShowFramesAfterSuspendForRecycle(int surface_id) const {
+ BrowserCompositorOutputSurface* surface =
+ output_surface_map_.Lookup(surface_id);
+ if (surface)
+ return surface->SurfaceShouldNotShowFramesAfterSuspendForRecycle();
+ return false;
+}
#endif
scoped_refptr<cc::ContextProvider>
@@ -419,7 +515,7 @@ GpuProcessTransportFactory::SharedMainThreadContextProvider() {
// context so that skia and gl_helper don't step on each other.
shared_main_thread_contexts_ = ContextProviderCommandBuffer::Create(
GpuProcessTransportFactory::CreateOffscreenCommandBufferContext(),
- "Offscreen-MainThread");
+ BROWSER_OFFSCREEN_MAINTHREAD_CONTEXT);
if (shared_main_thread_contexts_.get()) {
shared_main_thread_contexts_->SetLostContextCallback(
@@ -441,10 +537,13 @@ GpuProcessTransportFactory::CreatePerCompositorData(
GpuSurfaceTracker* tracker = GpuSurfaceTracker::Get();
PerCompositorData* data = new PerCompositorData;
- data->surface_id = tracker->AddSurfaceForNativeWidget(widget);
- tracker->SetSurfaceHandle(
- data->surface_id,
- gfx::GLSurfaceHandle(widget, gfx::NATIVE_DIRECT));
+ if (compositor->widget() == gfx::kNullAcceleratedWidget) {
+ data->surface_id = 0;
+ } else {
+ data->surface_id = tracker->AddSurfaceForNativeWidget(widget);
+ tracker->SetSurfaceHandle(data->surface_id,
+ gfx::GLSurfaceHandle(widget, gfx::NATIVE_DIRECT));
+ }
per_compositor_data_[compositor] = data;
diff --git a/chromium/content/browser/compositor/gpu_process_transport_factory.h b/chromium/content/browser/compositor/gpu_process_transport_factory.h
index 25cfbc0c53a..171c030f4e5 100644
--- a/chromium/content/browser/compositor/gpu_process_transport_factory.h
+++ b/chromium/content/browser/compositor/gpu_process_transport_factory.h
@@ -17,18 +17,20 @@
#include "ui/compositor/compositor.h"
namespace base {
+class SimpleThread;
class Thread;
}
namespace cc {
+class SoftwareOutputDevice;
class SurfaceManager;
}
namespace content {
class BrowserCompositorOutputSurface;
-class BrowserCompositorOutputSurfaceProxy;
class CompositorSwapClient;
class ContextProviderCommandBuffer;
+class OutputDeviceBacking;
class ReflectorImpl;
class WebGraphicsContext3DCommandBufferImpl;
@@ -44,18 +46,20 @@ class GpuProcessTransportFactory
CreateOffscreenCommandBufferContext();
// ui::ContextFactory implementation.
- 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 CreateOutputSurface(base::WeakPtr<ui::Compositor> compositor) override;
+ scoped_ptr<ui::Reflector> CreateReflector(ui::Compositor* source,
+ ui::Layer* target) override;
+ void RemoveReflector(ui::Reflector* reflector) override;
void RemoveCompositor(ui::Compositor* compositor) override;
scoped_refptr<cc::ContextProvider> SharedMainThreadContextProvider() override;
bool DoesCreateTestContexts() override;
+ uint32 GetImageTextureTarget() override;
cc::SharedBitmapManager* GetSharedBitmapManager() override;
gpu::GpuMemoryBufferManager* GetGpuMemoryBufferManager() override;
- base::MessageLoopProxy* GetCompositorMessageLoop() override;
+ cc::TaskGraphRunner* GetTaskGraphRunner() override;
scoped_ptr<cc::SurfaceIdAllocator> CreateSurfaceIdAllocator() override;
+ void ResizeDisplay(ui::Compositor* compositor,
+ const gfx::Size& size) override;
// ImageTransportFactory implementation.
ui::ContextFactory* GetContextFactory() override;
@@ -66,14 +70,21 @@ class GpuProcessTransportFactory
void RemoveObserver(ImageTransportFactoryObserver* observer) override;
#if defined(OS_MACOSX)
void OnSurfaceDisplayed(int surface_id) override;
+ void SetCompositorSuspendedForRecycle(ui::Compositor* compositor,
+ bool suspended) override;
+ bool SurfaceShouldNotShowFramesAfterSuspendForRecycle(
+ int surface_id) const override;
#endif
private:
struct PerCompositorData;
PerCompositorData* CreatePerCompositorData(ui::Compositor* compositor);
+ scoped_ptr<cc::SoftwareOutputDevice> CreateSoftwareOutputDevice(
+ ui::Compositor* compositor);
void EstablishedGpuChannel(base::WeakPtr<ui::Compositor> compositor,
- bool create_software_renderer);
+ bool create_gpu_output_surface,
+ int num_attempts);
scoped_ptr<WebGraphicsContext3DCommandBufferImpl> CreateContextCommon(
scoped_refptr<GpuChannelHost> gpu_channel_host,
int surface_id);
@@ -82,20 +93,23 @@ class GpuProcessTransportFactory
void OnLostMainThreadSharedContext();
typedef std::map<ui::Compositor*, PerCompositorData*> PerCompositorDataMap;
- scoped_ptr<base::Thread> compositor_thread_;
PerCompositorDataMap per_compositor_data_;
scoped_refptr<ContextProviderCommandBuffer> shared_main_thread_contexts_;
scoped_ptr<GLHelper> gl_helper_;
ObserverList<ImageTransportFactoryObserver> observer_list_;
scoped_ptr<cc::SurfaceManager> surface_manager_;
uint32_t next_surface_id_namespace_;
+ scoped_ptr<cc::TaskGraphRunner> task_graph_runner_;
+ scoped_ptr<base::SimpleThread> raster_thread_;
+
+#if defined(OS_WIN)
+ scoped_ptr<OutputDeviceBacking> software_backing_;
+#endif
// The contents of this map and its methods may only be used on the compositor
// thread.
IDMap<BrowserCompositorOutputSurface> output_surface_map_;
- 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
index c3d9cbbc056..ff77fa94664 100644
--- a/chromium/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc
+++ b/chromium/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc
@@ -5,6 +5,7 @@
#include "content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h"
#include "cc/output/compositor_frame.h"
+#include "content/browser/compositor/browser_compositor_overlay_candidate_validator.h"
#include "content/browser/compositor/buffer_queue.h"
#include "content/browser/compositor/reflector_impl.h"
#include "content/browser/gpu/gpu_surface_tracker.h"
@@ -19,20 +20,33 @@ 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,
+ scoped_ptr<BrowserCompositorOverlayCandidateValidator>
+ overlay_candidate_validator,
unsigned internalformat,
- bool use_own_gl_helper)
+ BrowserGpuMemoryBufferManager* gpu_memory_buffer_manager)
: GpuBrowserCompositorOutputSurface(context,
- surface_id,
- output_surface_map,
vsync_manager,
overlay_candidate_validator.Pass()),
internalformat_(internalformat),
- use_own_gl_helper_(use_own_gl_helper) {
+ gpu_memory_buffer_manager_(gpu_memory_buffer_manager) {
capabilities_.uses_default_gl_framebuffer = false;
capabilities_.flipped_output_surface = true;
+ // Set |max_frames_pending| to 2 for surfaceless, which aligns scheduling
+ // more closely with the previous surfaced behavior.
+ // With a surface, swap buffer ack used to return early, before actually
+ // presenting the back buffer, enabling the browser compositor to run ahead.
+ // Surfaceless implementation acks at the time of actual buffer swap, which
+ // shifts the start of the new frame forward relative to the old
+ // implementation.
+ capabilities_.max_frames_pending = 2;
+
+ gl_helper_.reset(new GLHelper(context_provider_->ContextGL(),
+ context_provider_->ContextSupport()));
+ output_surface_.reset(
+ new BufferQueue(context_provider_, internalformat_, gl_helper_.get(),
+ gpu_memory_buffer_manager_, surface_id));
+ output_surface_->Initialize();
}
GpuSurfacelessBrowserCompositorOutputSurface::
@@ -80,21 +94,4 @@ void GpuSurfacelessBrowserCompositorOutputSurface::Reshape(
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
index e95ab7a5223..7f634dd2be5 100644
--- a/chromium/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h
+++ b/chromium/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h
@@ -9,6 +9,7 @@
namespace content {
+class BrowserGpuMemoryBufferManager;
class BufferQueue;
class GLHelper;
@@ -18,11 +19,11 @@ class 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,
+ scoped_ptr<BrowserCompositorOverlayCandidateValidator>
+ overlay_candidate_validator,
unsigned internalformat,
- bool use_own_gl_helper);
+ BrowserGpuMemoryBufferManager* gpu_memory_buffer_manager);
~GpuSurfacelessBrowserCompositorOutputSurface() override;
private:
@@ -31,12 +32,11 @@ class GpuSurfacelessBrowserCompositorOutputSurface
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_;
+ BrowserGpuMemoryBufferManager* gpu_memory_buffer_manager_;
};
} // namespace content
diff --git a/chromium/content/browser/compositor/image_transport_factory.h b/chromium/content/browser/compositor/image_transport_factory.h
index 4b5dec10629..e9aa0390023 100644
--- a/chromium/content/browser/compositor/image_transport_factory.h
+++ b/chromium/content/browser/compositor/image_transport_factory.h
@@ -22,6 +22,7 @@ class Size;
}
namespace ui {
+class Compositor;
class ContextFactory;
class Texture;
}
@@ -84,6 +85,18 @@ class CONTENT_EXPORT ImageTransportFactory {
#if defined(OS_MACOSX)
virtual void OnSurfaceDisplayed(int surface_id) = 0;
+ // Called with |suspended| as true when the ui::Compositor has been
+ // disconnected from an NSView and may be attached to another one. Called
+ // with |suspended| as false after the ui::Compositor has been connected to
+ // a new NSView and the first commit targeted at the new NSView has
+ // completed. This ensures that content and frames intended for the old
+ // NSView will not flash in the new NSView.
+ virtual void SetCompositorSuspendedForRecycle(ui::Compositor* compositor,
+ bool suspended) = 0;
+ // Used by GpuProcessHostUIShim to determine if a frame should not be
+ // displayed because it is targetted to an NSView that has been disconnected.
+ virtual bool SurfaceShouldNotShowFramesAfterSuspendForRecycle(
+ int surface_id) const = 0;
#endif
};
diff --git a/chromium/content/browser/compositor/io_surface_context_mac.h b/chromium/content/browser/compositor/io_surface_context_mac.h
deleted file mode 100644
index 4e5802a0175..00000000000
--- a/chromium/content/browser/compositor/io_surface_context_mac.h
+++ /dev/null
@@ -1,72 +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_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
deleted file mode 100644
index 82c81b1a949..00000000000
--- a/chromium/content/browser/compositor/io_surface_context_mac.mm
+++ /dev/null
@@ -1,121 +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/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
deleted file mode 100644
index 5a218e8f665..00000000000
--- a/chromium/content/browser/compositor/io_surface_layer_mac.h
+++ /dev/null
@@ -1,161 +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_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
deleted file mode 100644
index d09f24c4902..00000000000
--- a/chromium/content/browser/compositor/io_surface_layer_mac.mm
+++ /dev/null
@@ -1,302 +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/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
deleted file mode 100644
index 595c91232dc..00000000000
--- a/chromium/content/browser/compositor/io_surface_texture_mac.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_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
deleted file mode 100644
index dea6b287682..00000000000
--- a/chromium/content/browser/compositor/io_surface_texture_mac.mm
+++ /dev/null
@@ -1,297 +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/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/offscreen_browser_compositor_output_surface.cc b/chromium/content/browser/compositor/offscreen_browser_compositor_output_surface.cc
new file mode 100644
index 00000000000..36f6aa9e24c
--- /dev/null
+++ b/chromium/content/browser/compositor/offscreen_browser_compositor_output_surface.cc
@@ -0,0 +1,152 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/compositor/offscreen_browser_compositor_output_surface.h"
+
+#include "base/logging.h"
+#include "cc/output/compositor_frame.h"
+#include "cc/output/compositor_frame_ack.h"
+#include "cc/output/gl_frame_data.h"
+#include "cc/output/output_surface_client.h"
+#include "cc/resources/resource_provider.h"
+#include "content/browser/compositor/browser_compositor_overlay_candidate_validator.h"
+#include "content/browser/compositor/reflector_impl.h"
+#include "content/browser/compositor/reflector_texture.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"
+#include "third_party/khronos/GLES2/gl2.h"
+#include "third_party/khronos/GLES2/gl2ext.h"
+
+using cc::CompositorFrame;
+using cc::GLFrameData;
+using cc::ResourceProvider;
+using gpu::gles2::GLES2Interface;
+
+namespace content {
+
+OffscreenBrowserCompositorOutputSurface::
+ OffscreenBrowserCompositorOutputSurface(
+ const scoped_refptr<ContextProviderCommandBuffer>& context,
+ const scoped_refptr<ui::CompositorVSyncManager>& vsync_manager,
+ scoped_ptr<BrowserCompositorOverlayCandidateValidator>
+ overlay_candidate_validator)
+ : BrowserCompositorOutputSurface(context,
+ vsync_manager,
+ overlay_candidate_validator.Pass()),
+ fbo_(0),
+ is_backbuffer_discarded_(false),
+ weak_ptr_factory_(this) {
+ capabilities_.max_frames_pending = 1;
+ capabilities_.uses_default_gl_framebuffer = false;
+}
+
+OffscreenBrowserCompositorOutputSurface::
+ ~OffscreenBrowserCompositorOutputSurface() {
+ DiscardBackbuffer();
+}
+
+void OffscreenBrowserCompositorOutputSurface::EnsureBackbuffer() {
+ is_backbuffer_discarded_ = false;
+
+ if (!reflector_texture_.get()) {
+ reflector_texture_.reset(new ReflectorTexture(context_provider()));
+
+ GLES2Interface* gl = context_provider_->ContextGL();
+ cc::ResourceFormat format = cc::RGBA_8888;
+ gl->BindTexture(GL_TEXTURE_2D, reflector_texture_->texture_id());
+ gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ gl->TexImage2D(GL_TEXTURE_2D, 0, GLInternalFormat(format),
+ surface_size_.width(), surface_size_.height(), 0,
+ GLDataFormat(format), GLDataType(format), nullptr);
+ if (!fbo_)
+ gl->GenFramebuffers(1, &fbo_);
+
+ gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
+ gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D, reflector_texture_->texture_id(),
+ 0);
+ reflector_->OnSourceTextureMailboxUpdated(
+ reflector_texture_->mailbox());
+ }
+}
+
+void OffscreenBrowserCompositorOutputSurface::DiscardBackbuffer() {
+ is_backbuffer_discarded_ = true;
+
+ GLES2Interface* gl = context_provider_->ContextGL();
+
+ if (reflector_texture_) {
+ reflector_texture_.reset();
+ if (reflector_)
+ reflector_->OnSourceTextureMailboxUpdated(nullptr);
+ }
+
+ if (fbo_) {
+ gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
+ gl->DeleteFramebuffers(1, &fbo_);
+ fbo_ = 0;
+ }
+}
+
+void OffscreenBrowserCompositorOutputSurface::Reshape(const gfx::Size& size,
+ float scale_factor) {
+ if (size == surface_size_)
+ return;
+
+ surface_size_ = size;
+ device_scale_factor_ = scale_factor;
+ DiscardBackbuffer();
+ EnsureBackbuffer();
+}
+
+void OffscreenBrowserCompositorOutputSurface::BindFramebuffer() {
+ bool need_to_bind = !!reflector_texture_.get();
+ EnsureBackbuffer();
+ DCHECK(reflector_texture_.get());
+
+ if (need_to_bind) {
+ GLES2Interface* gl = context_provider_->ContextGL();
+ gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
+ }
+}
+
+void OffscreenBrowserCompositorOutputSurface::SwapBuffers(
+ cc::CompositorFrame* frame) {
+ if (reflector_) {
+ if (frame->gl_frame_data->sub_buffer_rect ==
+ gfx::Rect(frame->gl_frame_data->size))
+ reflector_->OnSourceSwapBuffers();
+ else
+ reflector_->OnSourcePostSubBuffer(frame->gl_frame_data->sub_buffer_rect);
+ }
+
+ client_->DidSwapBuffers();
+}
+
+void OffscreenBrowserCompositorOutputSurface::OnReflectorChanged() {
+ if (reflector_)
+ EnsureBackbuffer();
+}
+
+base::Closure
+OffscreenBrowserCompositorOutputSurface::CreateCompositionStartedCallback() {
+ return base::Bind(&OutputSurface::OnSwapBuffersComplete,
+ weak_ptr_factory_.GetWeakPtr());
+}
+
+#if defined(OS_MACOSX)
+
+bool OffscreenBrowserCompositorOutputSurface::
+SurfaceShouldNotShowFramesAfterSuspendForRecycle() const {
+ return true;
+}
+
+#endif
+
+} // namespace content
diff --git a/chromium/content/browser/compositor/offscreen_browser_compositor_output_surface.h b/chromium/content/browser/compositor/offscreen_browser_compositor_output_surface.h
new file mode 100644
index 00000000000..67fc2247c7e
--- /dev/null
+++ b/chromium/content/browser/compositor/offscreen_browser_compositor_output_surface.h
@@ -0,0 +1,62 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_COMPOSITOR_OFFSCREEN_BROWSER_COMPOSITOR_OUTPUT_SURFACE_H_
+#define CONTENT_BROWSER_COMPOSITOR_OFFSCREEN_BROWSER_COMPOSITOR_OUTPUT_SURFACE_H_
+
+#include "base/cancelable_callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "content/browser/compositor/browser_compositor_output_surface.h"
+
+namespace ui {
+class CompositorVSyncManager;
+}
+
+namespace content {
+class CommandBufferProxyImpl;
+class ReflectorTexture;
+
+class OffscreenBrowserCompositorOutputSurface
+ : public BrowserCompositorOutputSurface {
+ public:
+ OffscreenBrowserCompositorOutputSurface(
+ const scoped_refptr<ContextProviderCommandBuffer>& context,
+ const scoped_refptr<ui::CompositorVSyncManager>& vsync_manager,
+ scoped_ptr<BrowserCompositorOverlayCandidateValidator>
+ overlay_candidate_validator);
+
+ ~OffscreenBrowserCompositorOutputSurface() override;
+
+ protected:
+ // cc::OutputSurface:
+ void EnsureBackbuffer() override;
+ void DiscardBackbuffer() override;
+ void Reshape(const gfx::Size& size, float scale_factor) override;
+ void BindFramebuffer() override;
+ void SwapBuffers(cc::CompositorFrame* frame) override;
+
+ // BrowserCompositorOutputSurface
+ void OnReflectorChanged() override;
+ base::Closure CreateCompositionStartedCallback() override;
+#if defined(OS_MACOSX)
+ void OnSurfaceDisplayed() override {};
+ void SetSurfaceSuspendedForRecycle(bool suspended) override {};
+ bool SurfaceShouldNotShowFramesAfterSuspendForRecycle() const override;
+#endif
+
+ uint32 fbo_;
+ bool is_backbuffer_discarded_;
+ scoped_ptr<ReflectorTexture> reflector_texture_;
+
+ base::WeakPtrFactory<OffscreenBrowserCompositorOutputSurface>
+ weak_ptr_factory_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(OffscreenBrowserCompositorOutputSurface);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_COMPOSITOR_OFFSCREEN_BROWSER_COMPOSITOR_OUTPUT_SURFACE_H_
diff --git a/chromium/content/browser/compositor/onscreen_display_client.cc b/chromium/content/browser/compositor/onscreen_display_client.cc
deleted file mode 100644
index 6e2241d6cb1..00000000000
--- a/chromium/content/browser/compositor/onscreen_display_client.cc
+++ /dev/null
@@ -1,96 +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/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(
- 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() {
-}
-
-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
deleted file mode 100644
index 206f79a322c..00000000000
--- a/chromium/content/browser/compositor/onscreen_display_client.h
+++ /dev/null
@@ -1,70 +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_ONSCREEN_DISPLAY_CLIENT_H_
-#define CONTENT_BROWSER_COMPOSITOR_ONSCREEN_DISPLAY_CLIENT_H_
-
-#include "cc/surfaces/display_client.h"
-
-#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 {
-class ContextProvider;
-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(
- scoped_ptr<cc::OutputSurface> output_surface,
- cc::SurfaceManager* manager,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner);
- ~OnscreenDisplayClient() override;
-
- bool Initialize();
- cc::Display* display() { return display_.get(); }
- void set_surface_output_surface(SurfaceDisplayOutputSurface* surface) {
- surface_display_output_surface_ = surface;
- }
-
- // cc::DisplayClient implementation.
- 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:
- 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);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_COMPOSITOR_ONSCREEN_DISPLAY_CLIENT_H_
diff --git a/chromium/content/browser/compositor/overlay_candidate_validator_ozone.cc b/chromium/content/browser/compositor/overlay_candidate_validator_ozone.cc
deleted file mode 100644
index a92dc1011de..00000000000
--- a/chromium/content/browser/compositor/overlay_candidate_validator_ozone.cc
+++ /dev/null
@@ -1,58 +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/overlay_candidate_validator_ozone.h"
-
-#include "ui/ozone/public/overlay_candidates_ozone.h"
-
-namespace content {
-
-static ui::SurfaceFactoryOzone::BufferFormat GetOzoneFormat(
- cc::ResourceFormat overlay_format) {
- switch (overlay_format) {
- case cc::RGBA_8888:
- 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:
- break;
- }
- NOTREACHED();
- return ui::SurfaceFactoryOzone::UNKNOWN;
-}
-
-OverlayCandidateValidatorOzone::OverlayCandidateValidatorOzone(
- gfx::AcceleratedWidget widget,
- ui::OverlayCandidatesOzone* overlay_candidates)
- : widget_(widget), overlay_candidates_(overlay_candidates) {
-}
-
-OverlayCandidateValidatorOzone::~OverlayCandidateValidatorOzone() {}
-
-void OverlayCandidateValidatorOzone::CheckOverlaySupport(
- cc::OverlayCandidateList* surfaces) {
- DCHECK_GE(2U, surfaces->size());
- ui::OverlayCandidatesOzone::OverlaySurfaceCandidateList ozone_surface_list;
- ozone_surface_list.resize(surfaces->size());
-
- for (size_t i = 0; i < surfaces->size(); i++) {
- ozone_surface_list.at(i).transform = surfaces->at(i).transform;
- ozone_surface_list.at(i).format = GetOzoneFormat(surfaces->at(i).format);
- ozone_surface_list.at(i).display_rect = surfaces->at(i).display_rect;
- ozone_surface_list.at(i).crop_rect = surfaces->at(i).uv_rect;
- ozone_surface_list.at(i).plane_z_order = surfaces->at(i).plane_z_order;
- }
-
- overlay_candidates_->CheckOverlaySupport(&ozone_surface_list);
- DCHECK_EQ(surfaces->size(), ozone_surface_list.size());
-
- for (size_t i = 0; i < surfaces->size(); i++) {
- surfaces->at(i).overlay_handled = ozone_surface_list.at(i).overlay_handled;
- }
-}
-
-} // namespace content
diff --git a/chromium/content/browser/compositor/overlay_candidate_validator_ozone.h b/chromium/content/browser/compositor/overlay_candidate_validator_ozone.h
deleted file mode 100644
index 0e81d53e7c0..00000000000
--- a/chromium/content/browser/compositor/overlay_candidate_validator_ozone.h
+++ /dev/null
@@ -1,39 +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_OVERLAY_CANDIDATE_VALIDATOR_OZONE_H_
-#define CONTENT_BROWSER_COMPOSITOR_OVERLAY_CANDIDATE_VALIDATOR_OZONE_H_
-
-#include "cc/output/overlay_candidate_validator.h"
-
-#include "content/common/content_export.h"
-#include "ui/gfx/native_widget_types.h"
-
-namespace ui {
-class OverlayCandidatesOzone;
-}
-
-namespace content {
-
-class CONTENT_EXPORT OverlayCandidateValidatorOzone
- : public cc::OverlayCandidateValidator {
- public:
- OverlayCandidateValidatorOzone(
- gfx::AcceleratedWidget widget,
- ui::OverlayCandidatesOzone* overlay_candidates);
- virtual ~OverlayCandidateValidatorOzone();
-
- // cc::OverlayCandidateValidator implementation.
- virtual void CheckOverlaySupport(cc::OverlayCandidateList* surfaces) override;
-
- private:
- gfx::AcceleratedWidget widget_;
- ui::OverlayCandidatesOzone* overlay_candidates_;
-
- DISALLOW_COPY_AND_ASSIGN(OverlayCandidateValidatorOzone);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_COMPOSITOR_OVERLAY_CANDIDATE_VALIDATOR_OZONE_H_
diff --git a/chromium/content/browser/compositor/reflector_impl.cc b/chromium/content/browser/compositor/reflector_impl.cc
index ac3bdda748e..dcc0dc2bbe6 100644
--- a/chromium/content/browser/compositor/reflector_impl.cc
+++ b/chromium/content/browser/compositor/reflector_impl.cc
@@ -8,164 +8,165 @@
#include "base/location.h"
#include "content/browser/compositor/browser_compositor_output_surface.h"
#include "content/browser/compositor/owned_mailbox.h"
-#include "content/common/gpu/client/gl_helper.h"
+//#include "content/common/gpu/client/gl_helper.h"
#include "ui/compositor/layer.h"
namespace content {
-ReflectorImpl::ReflectorImpl(
- ui::Compositor* mirrored_compositor,
- ui::Layer* mirroring_layer,
- IDMap<BrowserCompositorOutputSurface>* output_surface_map,
- base::MessageLoopProxy* compositor_thread_loop,
- int surface_id)
- : impl_unsafe_(output_surface_map),
- main_unsafe_(mirrored_compositor, mirroring_layer),
- impl_message_loop_(compositor_thread_loop),
- main_message_loop_(base::MessageLoopProxy::current()),
- surface_id_(surface_id) {
- GLHelper* helper = ImageTransportFactory::GetInstance()->GetGLHelper();
- MainThreadData& main = GetMain();
- main.mailbox = new OwnedMailbox(helper);
- impl_message_loop_->PostTask(
- FROM_HERE,
- base::Bind(
- &ReflectorImpl::InitOnImplThread, this, main.mailbox->holder()));
-}
-
-ReflectorImpl::MainThreadData::MainThreadData(
- ui::Compositor* mirrored_compositor,
- ui::Layer* mirroring_layer)
- : needs_set_mailbox(true),
- mirrored_compositor(mirrored_compositor),
- mirroring_layer(mirroring_layer) {}
+struct ReflectorImpl::LayerData {
+ LayerData(ui::Layer* layer) : layer(layer) {}
-ReflectorImpl::MainThreadData::~MainThreadData() {}
+ ui::Layer* layer;
+ bool needs_set_mailbox = false;
+};
-ReflectorImpl::ImplThreadData::ImplThreadData(
- IDMap<BrowserCompositorOutputSurface>* output_surface_map)
- : output_surface_map(output_surface_map),
- output_surface(NULL),
- texture_id(0) {}
+ReflectorImpl::ReflectorImpl(ui::Compositor* mirrored_compositor,
+ ui::Layer* mirroring_layer)
+ : mirrored_compositor_(mirrored_compositor),
+ flip_texture_(false),
+ composition_count_(0),
+ output_surface_(nullptr) {
+ if (mirroring_layer)
+ AddMirroringLayer(mirroring_layer);
+}
-ReflectorImpl::ImplThreadData::~ImplThreadData() {}
+ReflectorImpl::~ReflectorImpl() {
+}
-ReflectorImpl::ImplThreadData& ReflectorImpl::GetImpl() {
- DCHECK(impl_message_loop_->BelongsToCurrentThread());
- return impl_unsafe_;
+void ReflectorImpl::Shutdown() {
+ if (output_surface_)
+ DetachFromOutputSurface();
+ // Prevent the ReflectorImpl from picking up a new output surface.
+ mirroring_layers_.clear();
}
-ReflectorImpl::MainThreadData& ReflectorImpl::GetMain() {
- DCHECK(main_message_loop_->BelongsToCurrentThread());
- return main_unsafe_;
+void ReflectorImpl::DetachFromOutputSurface() {
+ DCHECK(output_surface_);
+ output_surface_->SetReflector(nullptr);
+ DCHECK(mailbox_.get());
+ mailbox_ = nullptr;
+ output_surface_ = nullptr;
+ for (LayerData* layer_data : mirroring_layers_)
+ layer_data->layer->SetShowSolidColorContent();
}
-void ReflectorImpl::InitOnImplThread(const gpu::MailboxHolder& mailbox_holder) {
- ImplThreadData& impl = GetImpl();
- // Ignore if the reflector was shutdown before
- // initialized, or it's already initialized.
- if (!impl.output_surface_map || impl.gl_helper.get())
- return;
+void ReflectorImpl::OnSourceSurfaceReady(
+ BrowserCompositorOutputSurface* output_surface) {
+ if (mirroring_layers_.empty())
+ return; // Was already Shutdown().
+ if (output_surface == output_surface_)
+ return; // Is already attached.
+ if (output_surface_)
+ DetachFromOutputSurface();
- impl.mailbox_holder = mailbox_holder;
+ output_surface_ = output_surface;
- BrowserCompositorOutputSurface* source_surface =
- impl.output_surface_map->Lookup(surface_id_);
- // Skip if the source surface isn't ready yet. This will be
- // initialized when the source surface becomes ready.
- if (!source_surface)
- return;
+ composition_started_callback_ =
+ output_surface_->CreateCompositionStartedCallback();
- AttachToOutputSurfaceOnImplThread(impl.mailbox_holder, source_surface);
-}
+ flip_texture_ = !output_surface->capabilities().flipped_output_surface;
-void ReflectorImpl::OnSourceSurfaceReady(
- BrowserCompositorOutputSurface* source_surface) {
- ImplThreadData& impl = GetImpl();
- AttachToOutputSurfaceOnImplThread(impl.mailbox_holder, source_surface);
+ output_surface_->SetReflector(this);
}
-void ReflectorImpl::Shutdown() {
- MainThreadData& main = GetMain();
- main.mailbox = NULL;
- main.mirroring_layer->SetShowSolidColorContent();
- main.mirroring_layer = NULL;
- impl_message_loop_->PostTask(
- FROM_HERE, base::Bind(&ReflectorImpl::ShutdownOnImplThread, this));
+void ReflectorImpl::OnMirroringCompositorResized() {
+ for (LayerData* layer_data : mirroring_layers_)
+ layer_data->layer->SchedulePaint(layer_data->layer->bounds());
}
-void ReflectorImpl::DetachFromOutputSurface() {
- ImplThreadData& impl = GetImpl();
- DCHECK(impl.output_surface);
- impl.output_surface->SetReflector(NULL);
- DCHECK(impl.texture_id);
- impl.gl_helper->DeleteTexture(impl.texture_id);
- impl.texture_id = 0;
- impl.gl_helper.reset();
- impl.output_surface = NULL;
+void ReflectorImpl::AddMirroringLayer(ui::Layer* layer) {
+ DCHECK(layer->GetCompositor());
+ DCHECK(mirroring_layers_.end() == FindLayerData(layer));
+
+ LayerData* layer_data = new LayerData(layer);
+ if (mailbox_)
+ layer_data->needs_set_mailbox = true;
+ mirroring_layers_.push_back(layer_data);
+ mirrored_compositor_->ScheduleFullRedraw();
+
+ layer->GetCompositor()->AddObserver(this);
}
-void ReflectorImpl::ShutdownOnImplThread() {
- ImplThreadData& impl = GetImpl();
- if (impl.output_surface)
+void ReflectorImpl::RemoveMirroringLayer(ui::Layer* layer) {
+ DCHECK(layer->GetCompositor());
+
+ ScopedVector<LayerData>::iterator iter = FindLayerData(layer);
+ DCHECK(iter != mirroring_layers_.end());
+ (*iter)->layer->SetShowSolidColorContent();
+ mirroring_layers_.erase(iter);
+
+ layer->GetCompositor()->RemoveObserver(this);
+ composition_count_--;
+ if (composition_count_ == 0 && !composition_started_callback_.is_null())
+ composition_started_callback_.Run();
+
+ if (mirroring_layers_.empty() && output_surface_)
DetachFromOutputSurface();
- impl.output_surface_map = NULL;
- // The instance must be deleted on main thread.
- main_message_loop_->PostTask(FROM_HERE,
- base::Bind(&ReflectorImpl::DeleteOnMainThread,
- scoped_refptr<ReflectorImpl>(this)));
}
-void ReflectorImpl::ReattachToOutputSurfaceFromMainThread(
- BrowserCompositorOutputSurface* output_surface) {
- MainThreadData& main = GetMain();
- GLHelper* helper = ImageTransportFactory::GetInstance()->GetGLHelper();
- main.mailbox = new OwnedMailbox(helper);
- main.needs_set_mailbox = true;
- main.mirroring_layer->SetShowSolidColorContent();
- impl_message_loop_->PostTask(
- FROM_HERE,
- base::Bind(&ReflectorImpl::AttachToOutputSurfaceOnImplThread,
- this,
- main.mailbox->holder(),
- output_surface));
+void ReflectorImpl::OnCompositingStarted(ui::Compositor* compositor,
+ base::TimeTicks start_time) {
+ if (composition_count_ > 0 && --composition_count_ == 0 &&
+ !composition_started_callback_.is_null()) {
+ composition_started_callback_.Run();
+ }
}
-void ReflectorImpl::OnMirroringCompositorResized() {
- MainThreadData& main = GetMain();
- main.mirroring_layer->SchedulePaint(main.mirroring_layer->bounds());
-}
+void ReflectorImpl::OnSourceTextureMailboxUpdated(
+ scoped_refptr<OwnedMailbox> mailbox) {
+ mailbox_ = mailbox;
+ if (mailbox_.get()) {
+ for (LayerData* layer_data : mirroring_layers_)
+ layer_data->needs_set_mailbox = true;
-void ReflectorImpl::OnSwapBuffers() {
- ImplThreadData& impl = GetImpl();
- gfx::Size size = impl.output_surface->SurfaceSize();
- if (impl.texture_id) {
- impl.gl_helper->CopyTextureFullImage(impl.texture_id, size);
- impl.gl_helper->Flush();
+ // The texture doesn't have the data. Request full redraw on mirrored
+ // compositor so that the full content will be copied to mirroring
+ // compositor. This full redraw should land us in OnSourceSwapBuffers() to
+ // resize the texture appropriately.
+ mirrored_compositor_->ScheduleFullRedraw();
}
- main_message_loop_->PostTask(
- FROM_HERE,
- base::Bind(
- &ReflectorImpl::FullRedrawOnMainThread, this->AsWeakPtr(), size));
}
-void ReflectorImpl::OnPostSubBuffer(gfx::Rect rect) {
- ImplThreadData& impl = GetImpl();
- if (impl.texture_id) {
- impl.gl_helper->CopyTextureSubImage(impl.texture_id, rect);
- impl.gl_helper->Flush();
+void ReflectorImpl::OnSourceSwapBuffers() {
+ if (mirroring_layers_.empty()) {
+ if (!composition_started_callback_.is_null())
+ composition_started_callback_.Run();
+ return;
}
- main_message_loop_->PostTask(
- FROM_HERE,
- base::Bind(&ReflectorImpl::UpdateSubBufferOnMainThread,
- this->AsWeakPtr(),
- impl.output_surface->SurfaceSize(),
- rect));
+
+ // Should be attached to the source output surface already.
+ DCHECK(mailbox_.get());
+
+ gfx::Size size = output_surface_->SurfaceSize();
+
+ // Request full redraw on mirroring compositor.
+ for (LayerData* layer_data : mirroring_layers_)
+ UpdateTexture(layer_data, size, layer_data->layer->bounds());
+ composition_count_ = mirroring_layers_.size();
}
-ReflectorImpl::~ReflectorImpl() {
- // Make sure the reflector is deleted on main thread.
- DCHECK_EQ(main_message_loop_.get(), base::MessageLoopProxy::current().get());
+void ReflectorImpl::OnSourcePostSubBuffer(const gfx::Rect& rect) {
+ if (mirroring_layers_.empty()) {
+ if (!composition_started_callback_.is_null())
+ composition_started_callback_.Run();
+ return;
+ }
+
+ // Should be attached to the source output surface already.
+ DCHECK(mailbox_.get());
+
+ gfx::Size size = output_surface_->SurfaceSize();
+
+ int y = rect.y();
+ // Flip the coordinates to compositor's one.
+ if (flip_texture_)
+ y = size.height() - rect.y() - rect.height();
+ gfx::Rect mirroring_rect(rect.x(), y, rect.width(), rect.height());
+
+ // Request redraw of the dirty portion in mirroring compositor.
+ for (LayerData* layer_data : mirroring_layers_)
+ UpdateTexture(layer_data, size, mirroring_rect);
+ composition_count_ = mirroring_layers_.size();
}
static void ReleaseMailbox(scoped_refptr<OwnedMailbox> mailbox,
@@ -174,72 +175,29 @@ static void ReleaseMailbox(scoped_refptr<OwnedMailbox> mailbox,
mailbox->UpdateSyncPoint(sync_point);
}
-void ReflectorImpl::AttachToOutputSurfaceOnImplThread(
- const gpu::MailboxHolder& mailbox_holder,
- BrowserCompositorOutputSurface* output_surface) {
- ImplThreadData& impl = GetImpl();
- if (output_surface == impl.output_surface)
- return;
- if (impl.output_surface)
- DetachFromOutputSurface();
- impl.output_surface = output_surface;
- output_surface->context_provider()->BindToCurrentThread();
- impl.gl_helper.reset(
- new GLHelper(output_surface->context_provider()->ContextGL(),
- output_surface->context_provider()->ContextSupport()));
- impl.texture_id = impl.gl_helper->ConsumeMailboxToTexture(
- mailbox_holder.mailbox, mailbox_holder.sync_point);
- impl.gl_helper->ResizeTexture(impl.texture_id, output_surface->SurfaceSize());
- impl.gl_helper->Flush();
- output_surface->SetReflector(this);
- // The texture doesn't have the data, so invokes full redraw now.
- main_message_loop_->PostTask(
- FROM_HERE,
- base::Bind(&ReflectorImpl::FullRedrawContentOnMainThread,
- scoped_refptr<ReflectorImpl>(this)));
+ScopedVector<ReflectorImpl::LayerData>::iterator ReflectorImpl::FindLayerData(
+ ui::Layer* layer) {
+ return std::find_if(mirroring_layers_.begin(), mirroring_layers_.end(),
+ [layer](const LayerData* layer_data) {
+ return layer_data->layer == layer;
+ });
}
-void ReflectorImpl::UpdateTextureSizeOnMainThread(gfx::Size size) {
- MainThreadData& main = GetMain();
- if (!main.mirroring_layer || !main.mailbox.get() ||
- main.mailbox->mailbox().IsZero())
- return;
- if (main.needs_set_mailbox) {
- main.mirroring_layer->SetTextureMailbox(
- cc::TextureMailbox(main.mailbox->holder()),
- cc::SingleReleaseCallback::Create(
- base::Bind(ReleaseMailbox, main.mailbox)),
- size);
- main.needs_set_mailbox = false;
+void ReflectorImpl::UpdateTexture(ReflectorImpl::LayerData* layer_data,
+ const gfx::Size& source_size,
+ const gfx::Rect& redraw_rect) {
+ if (layer_data->needs_set_mailbox) {
+ layer_data->layer->SetTextureMailbox(
+ cc::TextureMailbox(mailbox_->holder()),
+ cc::SingleReleaseCallback::Create(base::Bind(ReleaseMailbox, mailbox_)),
+ source_size);
+ layer_data->needs_set_mailbox = false;
} else {
- main.mirroring_layer->SetTextureSize(size);
+ layer_data->layer->SetTextureSize(source_size);
}
- main.mirroring_layer->SetBounds(gfx::Rect(size));
-}
-
-void ReflectorImpl::FullRedrawOnMainThread(gfx::Size size) {
- MainThreadData& main = GetMain();
- if (!main.mirroring_layer)
- return;
- UpdateTextureSizeOnMainThread(size);
- main.mirroring_layer->SchedulePaint(main.mirroring_layer->bounds());
-}
-
-void ReflectorImpl::UpdateSubBufferOnMainThread(gfx::Size size,
- gfx::Rect rect) {
- MainThreadData& main = GetMain();
- if (!main.mirroring_layer)
- return;
- UpdateTextureSizeOnMainThread(size);
- // Flip the coordinates to compositor's one.
- int y = size.height() - rect.y() - rect.height();
- gfx::Rect new_rect(rect.x(), y, rect.width(), rect.height());
- main.mirroring_layer->SchedulePaint(new_rect);
-}
-
-void ReflectorImpl::FullRedrawContentOnMainThread() {
- MainThreadData& main = GetMain();
- main.mirrored_compositor->ScheduleFullRedraw();
+ layer_data->layer->SetBounds(gfx::Rect(source_size));
+ layer_data->layer->SetTextureFlipped(flip_texture_);
+ layer_data->layer->SchedulePaint(redraw_rect);
}
} // namespace content
diff --git a/chromium/content/browser/compositor/reflector_impl.h b/chromium/content/browser/compositor/reflector_impl.h
index f771fe46c33..957dfc305fa 100644
--- a/chromium/content/browser/compositor/reflector_impl.h
+++ b/chromium/content/browser/compositor/reflector_impl.h
@@ -5,14 +5,18 @@
#ifndef CONTENT_BROWSER_COMPOSITOR_REFLECTOR_IMPL_H_
#define CONTENT_BROWSER_COMPOSITOR_REFLECTOR_IMPL_H_
+#include "base/callback.h"
#include "base/id_map.h"
#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
#include "base/memory/weak_ptr.h"
#include "base/synchronization/lock.h"
#include "content/browser/compositor/image_transport_factory.h"
+#include "content/common/content_export.h"
#include "gpu/command_buffer/common/mailbox_holder.h"
+#include "ui/compositor/compositor_observer.h"
#include "ui/compositor/reflector.h"
-#include "ui/gfx/size.h"
+#include "ui/gfx/geometry/size.h"
namespace base { class MessageLoopProxy; }
@@ -30,109 +34,67 @@ class BrowserCompositorOutputSurface;
// A reflector implementation that copies the framebuffer content
// to the texture, then draw it onto the mirroring compositor.
-class ReflectorImpl : public base::SupportsWeakPtr<ReflectorImpl>,
- public ui::Reflector {
+class CONTENT_EXPORT ReflectorImpl
+ : public base::SupportsWeakPtr<ReflectorImpl>,
+ public ui::Reflector,
+ public ui::CompositorObserver {
public:
- ReflectorImpl(
- ui::Compositor* mirrored_compositor,
- ui::Layer* mirroring_layer,
- IDMap<BrowserCompositorOutputSurface>* output_surface_map,
- base::MessageLoopProxy* compositor_thread_loop,
- int surface_id);
-
- ui::Compositor* mirrored_compositor() {
- return GetMain().mirrored_compositor;
- }
-
- void InitOnImplThread(const gpu::MailboxHolder& mailbox_holder);
+ ReflectorImpl(ui::Compositor* mirrored_compositor,
+ ui::Layer* mirroring_layer);
+ ~ReflectorImpl() override;
+
+ ui::Compositor* mirrored_compositor() { return mirrored_compositor_; }
+
void Shutdown();
- void ShutdownOnImplThread();
- // Post a task to attach the reflector to the output surface onto ImplThread.
- void ReattachToOutputSurfaceFromMainThread(
- BrowserCompositorOutputSurface* surface);
+ void DetachFromOutputSurface();
- // ui::Reflector implementation.
+ // ui::Reflector:
void OnMirroringCompositorResized() override;
+ void AddMirroringLayer(ui::Layer* layer) override;
+ void RemoveMirroringLayer(ui::Layer* layer) override;
+
+ // ui::CompositorObserver:
+ void OnCompositingDidCommit(ui::Compositor* compositor) override {}
+ void OnCompositingStarted(ui::Compositor* compositor,
+ base::TimeTicks start_time) override;
+ void OnCompositingEnded(ui::Compositor* compositor) override {}
+ void OnCompositingAborted(ui::Compositor* compositor) override {}
+ void OnCompositingLockStateChanged(ui::Compositor* compositor) override {}
+ void OnCompositingShuttingDown(ui::Compositor* compositor) override {}
// Called in |BrowserCompositorOutputSurface::SwapBuffers| to copy
- // the full screen image to the |texture_id_|. This must be called
- // on ImplThread.
- void OnSwapBuffers();
+ // the full screen image to the |mailbox_| texture.
+ void OnSourceSwapBuffers();
// Called in |BrowserCompositorOutputSurface::PostSubBuffer| copy
- // the sub image given by |rect| to the texture.This must be called
- // on ImplThread.
- void OnPostSubBuffer(gfx::Rect rect);
-
- // Create a shared texture that will be used to copy the content of
- // mirrored compositor to the mirroring compositor. This should
- // be posted to the main thread when the output is attached in
- // impl thread.
- void CreateSharedTextureOnMainThread(gfx::Size size);
-
- // Called when the source surface is bound and available. This must
- // be called on ImplThread.
+ // the sub image given by |rect| to the |mailbox_| texture.
+ void OnSourcePostSubBuffer(const gfx::Rect& rect);
+
+ // Called when the source surface is bound and available.
void OnSourceSurfaceReady(BrowserCompositorOutputSurface* surface);
- void DetachFromOutputSurface();
+ // Called when the mailbox which has the source surface's texture
+ // is updated.
+ void OnSourceTextureMailboxUpdated(scoped_refptr<OwnedMailbox> mailbox);
private:
- struct MainThreadData {
- MainThreadData(ui::Compositor* mirrored_compositor,
- ui::Layer* mirroring_layer);
- ~MainThreadData();
- scoped_refptr<OwnedMailbox> mailbox;
- bool needs_set_mailbox;
- ui::Compositor* mirrored_compositor;
- ui::Layer* mirroring_layer;
- };
-
- struct ImplThreadData {
- explicit ImplThreadData(
- IDMap<BrowserCompositorOutputSurface>* output_surface_map);
- ~ImplThreadData();
- IDMap<BrowserCompositorOutputSurface>* output_surface_map;
- BrowserCompositorOutputSurface* output_surface;
- scoped_ptr<GLHelper> gl_helper;
- unsigned texture_id;
- gpu::MailboxHolder mailbox_holder;
- };
-
- ~ReflectorImpl() override;
-
- void AttachToOutputSurfaceOnImplThread(
- const gpu::MailboxHolder& mailbox_holder,
- BrowserCompositorOutputSurface* surface);
-
- void UpdateTextureSizeOnMainThread(gfx::Size size);
-
- // Request full redraw on mirroring compositor.
- void FullRedrawOnMainThread(gfx::Size size);
-
- void UpdateSubBufferOnMainThread(gfx::Size size, gfx::Rect rect);
-
- // Request full redraw on mirrored compositor so that
- // the full content will be copied to mirroring compositor.
- void FullRedrawContentOnMainThread();
-
- // This exists just to hold a reference to a ReflectorImpl in a post task,
- // so the ReflectorImpl gets deleted when the function returns.
- static void DeleteOnMainThread(scoped_refptr<ReflectorImpl> reflector) {}
-
- MainThreadData& GetMain();
- ImplThreadData& GetImpl();
-
- // Must be accessed only on ImplThread, through GetImpl().
- ImplThreadData impl_unsafe_;
-
- // Must be accessed only on MainThread, through GetMain().
- MainThreadData main_unsafe_;
-
- // Can be accessed on both.
- scoped_refptr<base::MessageLoopProxy> impl_message_loop_;
- scoped_refptr<base::MessageLoopProxy> main_message_loop_;
- int surface_id_;
+ struct LayerData;
+
+ ScopedVector<ReflectorImpl::LayerData>::iterator FindLayerData(
+ ui::Layer* layer);
+ void UpdateTexture(LayerData* layer_data,
+ const gfx::Size& size,
+ const gfx::Rect& redraw_rect);
+
+ ui::Compositor* mirrored_compositor_;
+ ScopedVector<LayerData> mirroring_layers_;
+
+ scoped_refptr<OwnedMailbox> mailbox_;
+ bool flip_texture_;
+ int composition_count_;
+ BrowserCompositorOutputSurface* output_surface_;
+ base::Closure composition_started_callback_;
};
} // namespace content
diff --git a/chromium/content/browser/compositor/reflector_impl_unittest.cc b/chromium/content/browser/compositor/reflector_impl_unittest.cc
new file mode 100644
index 00000000000..9960484789c
--- /dev/null
+++ b/chromium/content/browser/compositor/reflector_impl_unittest.cc
@@ -0,0 +1,222 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "cc/test/fake_output_surface_client.h"
+#include "cc/test/test_context_provider.h"
+#include "cc/test/test_web_graphics_context_3d.h"
+#include "content/browser/compositor/browser_compositor_output_surface.h"
+#include "content/browser/compositor/browser_compositor_overlay_candidate_validator.h"
+#include "content/browser/compositor/reflector_impl.h"
+#include "content/browser/compositor/reflector_texture.h"
+#include "content/browser/compositor/test/no_transport_image_transport_factory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/compositor/compositor.h"
+#include "ui/compositor/layer.h"
+#include "ui/compositor/test/context_factories_for_test.h"
+
+#if defined(USE_OZONE)
+#include "content/browser/compositor/browser_compositor_overlay_candidate_validator_ozone.h"
+#include "ui/ozone/public/overlay_candidates_ozone.h"
+#endif // defined(USE_OZONE)
+
+namespace content {
+namespace {
+class FakeTaskRunner : public base::SingleThreadTaskRunner {
+ public:
+ FakeTaskRunner() {}
+
+ bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
+ const base::Closure& task,
+ base::TimeDelta delay) override {
+ return true;
+ }
+ bool PostDelayedTask(const tracked_objects::Location& from_here,
+ const base::Closure& task,
+ base::TimeDelta delay) override {
+ return true;
+ }
+ bool RunsTasksOnCurrentThread() const override { return true; }
+
+ protected:
+ ~FakeTaskRunner() override {}
+};
+
+#if defined(USE_OZONE)
+class TestOverlayCandidatesOzone : public ui::OverlayCandidatesOzone {
+ public:
+ TestOverlayCandidatesOzone() {}
+ ~TestOverlayCandidatesOzone() override {}
+
+ void CheckOverlaySupport(OverlaySurfaceCandidateList* surfaces) override {
+ (*surfaces)[0].overlay_handled = true;
+ }
+};
+#endif // defined(USE_OZONE)
+
+scoped_ptr<BrowserCompositorOverlayCandidateValidator>
+CreateTestValidatorOzone() {
+#if defined(USE_OZONE)
+ return scoped_ptr<BrowserCompositorOverlayCandidateValidator>(
+ new BrowserCompositorOverlayCandidateValidatorOzone(
+ 0, new TestOverlayCandidatesOzone()));
+#else
+ return nullptr;
+#endif // defined(USE_OZONE)
+}
+
+class TestOutputSurface : public BrowserCompositorOutputSurface {
+ public:
+ TestOutputSurface(
+ const scoped_refptr<cc::ContextProvider>& context_provider,
+ const scoped_refptr<ui::CompositorVSyncManager>& vsync_manager)
+ : BrowserCompositorOutputSurface(context_provider,
+ vsync_manager,
+ CreateTestValidatorOzone().Pass()) {}
+
+ void SetFlip(bool flip) { capabilities_.flipped_output_surface = flip; }
+
+ void SwapBuffers(cc::CompositorFrame* frame) override {}
+
+ void OnReflectorChanged() override {
+ if (!reflector_) {
+ reflector_texture_.reset();
+ } else {
+ reflector_texture_.reset(new ReflectorTexture(context_provider()));
+ reflector_->OnSourceTextureMailboxUpdated(reflector_texture_->mailbox());
+ }
+ }
+
+#if defined(OS_MACOSX)
+ void OnSurfaceDisplayed() override {}
+ void SetSurfaceSuspendedForRecycle(bool suspended) override {}
+ bool SurfaceShouldNotShowFramesAfterSuspendForRecycle() const override {
+ return false;
+ }
+#endif
+
+ gfx::Size SurfaceSize() const override { return gfx::Size(256, 256); }
+
+ private:
+ scoped_ptr<ReflectorTexture> reflector_texture_;
+};
+
+const gfx::Rect kSubRect(0, 0, 64, 64);
+
+} // namespace
+
+class ReflectorImplTest : public testing::Test {
+ public:
+ void SetUp() override {
+ bool enable_pixel_output = false;
+ ui::ContextFactory* context_factory =
+ ui::InitializeContextFactoryForTests(enable_pixel_output);
+ ImageTransportFactory::InitializeForUnitTests(
+ scoped_ptr<ImageTransportFactory>(
+ new NoTransportImageTransportFactory));
+ message_loop_.reset(new base::MessageLoop());
+ proxy_ = message_loop_->message_loop_proxy();
+ compositor_task_runner_ = new FakeTaskRunner();
+ compositor_.reset(new ui::Compositor(gfx::kNullAcceleratedWidget,
+ context_factory,
+ compositor_task_runner_.get()));
+ context_provider_ = cc::TestContextProvider::Create(
+ cc::TestWebGraphicsContext3D::Create().Pass());
+ output_surface_ =
+ scoped_ptr<TestOutputSurface>(
+ new TestOutputSurface(context_provider_,
+ compositor_->vsync_manager())).Pass();
+ CHECK(output_surface_->BindToClient(&output_surface_client_));
+
+ root_layer_.reset(new ui::Layer(ui::LAYER_SOLID_COLOR));
+ compositor_->SetRootLayer(root_layer_.get());
+ mirroring_layer_.reset(new ui::Layer(ui::LAYER_SOLID_COLOR));
+ compositor_->root_layer()->Add(mirroring_layer_.get());
+ gfx::Size size = output_surface_->SurfaceSize();
+ mirroring_layer_->SetBounds(gfx::Rect(size.width(), size.height()));
+ }
+
+ void SetUpReflector() {
+ reflector_ = make_scoped_ptr(
+ new ReflectorImpl(compositor_.get(), mirroring_layer_.get()));
+ reflector_->OnSourceSurfaceReady(output_surface_.get());
+ }
+
+ void TearDown() override {
+ if (reflector_)
+ reflector_->RemoveMirroringLayer(mirroring_layer_.get());
+ cc::TextureMailbox mailbox;
+ scoped_ptr<cc::SingleReleaseCallback> release;
+ if (mirroring_layer_->PrepareTextureMailbox(&mailbox, &release, false)) {
+ release->Run(0, false);
+ }
+ compositor_.reset();
+ ui::TerminateContextFactoryForTests();
+ ImageTransportFactory::Terminate();
+ }
+
+ void UpdateTexture() { reflector_->OnSourcePostSubBuffer(kSubRect); }
+
+ protected:
+ scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_;
+ scoped_refptr<cc::ContextProvider> context_provider_;
+ cc::FakeOutputSurfaceClient output_surface_client_;
+ scoped_ptr<base::MessageLoop> message_loop_;
+ scoped_refptr<base::MessageLoopProxy> proxy_;
+ scoped_ptr<ui::Compositor> compositor_;
+ scoped_ptr<ui::Layer> root_layer_;
+ scoped_ptr<ui::Layer> mirroring_layer_;
+ scoped_ptr<ReflectorImpl> reflector_;
+ scoped_ptr<TestOutputSurface> output_surface_;
+};
+
+namespace {
+TEST_F(ReflectorImplTest, CheckNormalOutputSurface) {
+ output_surface_->SetFlip(false);
+ SetUpReflector();
+ UpdateTexture();
+ EXPECT_TRUE(mirroring_layer_->TextureFlipped());
+ gfx::Rect expected_rect =
+ kSubRect + gfx::Vector2d(0, output_surface_->SurfaceSize().height()) -
+ gfx::Vector2d(0, kSubRect.height());
+ EXPECT_EQ(expected_rect, mirroring_layer_->damaged_region());
+}
+
+TEST_F(ReflectorImplTest, CheckInvertedOutputSurface) {
+ output_surface_->SetFlip(true);
+ SetUpReflector();
+ UpdateTexture();
+ EXPECT_FALSE(mirroring_layer_->TextureFlipped());
+ EXPECT_EQ(kSubRect, mirroring_layer_->damaged_region());
+}
+
+#if defined(USE_OZONE)
+TEST_F(ReflectorImplTest, CheckOverlayNoReflector) {
+ cc::OverlayCandidateList list;
+ cc::OverlayCandidate plane_1, plane_2;
+ plane_1.plane_z_order = 0;
+ plane_2.plane_z_order = 1;
+ list.push_back(plane_1);
+ list.push_back(plane_2);
+ output_surface_->GetOverlayCandidateValidator()->CheckOverlaySupport(&list);
+ EXPECT_TRUE(list[0].overlay_handled);
+}
+
+TEST_F(ReflectorImplTest, CheckOverlaySWMirroring) {
+ SetUpReflector();
+ cc::OverlayCandidateList list;
+ cc::OverlayCandidate plane_1, plane_2;
+ plane_1.plane_z_order = 0;
+ plane_2.plane_z_order = 1;
+ list.push_back(plane_1);
+ list.push_back(plane_2);
+ output_surface_->GetOverlayCandidateValidator()->CheckOverlaySupport(&list);
+ EXPECT_FALSE(list[0].overlay_handled);
+}
+#endif // defined(USE_OZONE)
+
+} // namespace
+} // namespace content
diff --git a/chromium/content/browser/compositor/reflector_texture.cc b/chromium/content/browser/compositor/reflector_texture.cc
new file mode 100644
index 00000000000..ed6a3bd86db
--- /dev/null
+++ b/chromium/content/browser/compositor/reflector_texture.cc
@@ -0,0 +1,48 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/compositor/reflector_texture.h"
+
+#include "content/browser/compositor/owned_mailbox.h"
+#include "content/common/gpu/client/context_provider_command_buffer.h"
+#include "content/common/gpu/client/gl_helper.h"
+#include "gpu/command_buffer/client/context_support.h"
+#include "gpu/command_buffer/client/gles2_interface.h"
+
+namespace content {
+
+ReflectorTexture::ReflectorTexture(cc::ContextProvider* context_provider)
+ : texture_id_(0) {
+ GLHelper* shared_helper =
+ ImageTransportFactory::GetInstance()->GetGLHelper();
+ mailbox_ = new OwnedMailbox(shared_helper);
+ gpu::gles2::GLES2Interface* gl = context_provider->ContextGL();
+
+ gl_helper_.reset(new GLHelper(gl, context_provider->ContextSupport()));
+
+ texture_id_ = gl_helper_->ConsumeMailboxToTexture(
+ mailbox_->mailbox(), mailbox_->sync_point());
+}
+
+ReflectorTexture::~ReflectorTexture() {
+ gl_helper_->DeleteTexture(texture_id_);
+}
+
+void ReflectorTexture::CopyTextureFullImage(const gfx::Size& size) {
+ gl_helper_->CopyTextureFullImage(texture_id_, size);
+ // Insert a barrier to make the copy show up in the mirroring compositor's
+ // mailbox. Since the the compositor contexts and the
+ // ImageTransportFactory's
+ // GLHelper are all on the same GPU channel, this is sufficient instead of
+ // plumbing through a sync point.
+ gl_helper_->InsertOrderingBarrier();
+}
+
+void ReflectorTexture::CopyTextureSubImage(const gfx::Rect& rect) {
+ gl_helper_->CopyTextureSubImage(texture_id_, rect);
+ // Insert a barrier for the same reason above.
+ gl_helper_->InsertOrderingBarrier();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/compositor/reflector_texture.h b/chromium/content/browser/compositor/reflector_texture.h
new file mode 100644
index 00000000000..cacabd39c15
--- /dev/null
+++ b/chromium/content/browser/compositor/reflector_texture.h
@@ -0,0 +1,47 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_COMPOSITOR_REFLECTOR_TEXTURE_H_
+#define CONTENT_BROWSER_COMPOSITOR_REFLECTOR_TEXTURE_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/browser/compositor/owned_mailbox.h"
+#include "content/common/content_export.h"
+
+namespace cc {
+class ContextProvider;
+}
+
+namespace gfx {
+class Rect;
+class Size;
+}
+
+namespace content {
+class GLHelper;
+
+// Create and manages texture mailbox to be used by Reflector.
+class CONTENT_EXPORT ReflectorTexture {
+ public:
+ explicit ReflectorTexture(cc::ContextProvider* provider);
+ ~ReflectorTexture();
+
+ void CopyTextureFullImage(const gfx::Size& size);
+ void CopyTextureSubImage(const gfx::Rect& size);
+
+ uint32 texture_id() const { return texture_id_; }
+ scoped_refptr<OwnedMailbox> mailbox() { return mailbox_; }
+
+ private:
+ scoped_refptr<OwnedMailbox> mailbox_;
+ scoped_ptr<GLHelper> gl_helper_;
+ uint32 texture_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(ReflectorTexture);
+};
+
+} // namespace content
+
+#endif
diff --git a/chromium/content/browser/compositor/resize_lock.h b/chromium/content/browser/compositor/resize_lock.h
index 07acff33cf1..306a19d39f1 100644
--- a/chromium/content/browser/compositor/resize_lock.h
+++ b/chromium/content/browser/compositor/resize_lock.h
@@ -7,7 +7,7 @@
#include "base/basictypes.h"
#include "content/common/content_export.h"
-#include "ui/gfx/size.h"
+#include "ui/gfx/geometry/size.h"
namespace content {
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 98c707f6611..c2b70d40c94 100644
--- a/chromium/content/browser/compositor/software_browser_compositor_output_surface.cc
+++ b/chromium/content/browser/compositor/software_browser_compositor_output_surface.cc
@@ -10,7 +10,6 @@
#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"
#include "ui/events/latency_info.h"
#include "ui/gfx/vsync_provider.h"
@@ -18,25 +17,26 @@
namespace content {
SoftwareBrowserCompositorOutputSurface::SoftwareBrowserCompositorOutputSurface(
- scoped_refptr<BrowserCompositorOutputSurfaceProxy> surface_proxy,
scoped_ptr<cc::SoftwareOutputDevice> software_device,
- int surface_id,
- IDMap<BrowserCompositorOutputSurface>* output_surface_map,
const scoped_refptr<ui::CompositorVSyncManager>& vsync_manager)
: BrowserCompositorOutputSurface(software_device.Pass(),
- surface_id,
- output_surface_map,
vsync_manager),
- output_surface_proxy_(surface_proxy) {}
+ weak_factory_(this) {
+}
SoftwareBrowserCompositorOutputSurface::
- ~SoftwareBrowserCompositorOutputSurface() {}
+ ~SoftwareBrowserCompositorOutputSurface() {
+}
void SoftwareBrowserCompositorOutputSurface::SwapBuffers(
cc::CompositorFrame* frame) {
- for (size_t i = 0; i < frame->metadata.latency_info.size(); i++) {
- frame->metadata.latency_info[i].AddLatencyNumber(
- ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0);
+ base::TimeTicks swap_time = base::TimeTicks::Now();
+ for (auto& latency : frame->metadata.latency_info) {
+ latency.AddLatencyNumberWithTimestamp(
+ ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, 0, swap_time, 1);
+ latency.AddLatencyNumberWithTimestamp(
+ ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0,
+ swap_time, 1);
}
base::MessageLoop::current()->PostTask(
FROM_HERE,
@@ -46,11 +46,9 @@ void SoftwareBrowserCompositorOutputSurface::SwapBuffers(
gfx::VSyncProvider* vsync_provider = software_device()->GetVSyncProvider();
if (vsync_provider) {
- vsync_provider->GetVSyncParameters(
- base::Bind(&BrowserCompositorOutputSurfaceProxy::
- OnUpdateVSyncParametersOnCompositorThread,
- output_surface_proxy_,
- surface_id_));
+ vsync_provider->GetVSyncParameters(base::Bind(
+ &BrowserCompositorOutputSurface::OnUpdateVSyncParametersFromGpu,
+ weak_factory_.GetWeakPtr()));
}
PostSwapBuffersComplete();
client_->DidSwapBuffers();
@@ -61,6 +59,15 @@ void SoftwareBrowserCompositorOutputSurface::OnSurfaceDisplayed() {
// See GpuBrowserCompositorOutputSurface for when and how this is used.
NOTREACHED() << "Not expected for software surfaces.";
}
+
+void SoftwareBrowserCompositorOutputSurface::SetSurfaceSuspendedForRecycle(
+ bool suspended) {
+}
+
+bool SoftwareBrowserCompositorOutputSurface::
+ SurfaceShouldNotShowFramesAfterSuspendForRecycle() const {
+ return false;
+}
#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 1df9b366edd..68776ca7aa6 100644
--- a/chromium/content/browser/compositor/software_browser_compositor_output_surface.h
+++ b/chromium/content/browser/compositor/software_browser_compositor_output_surface.h
@@ -19,16 +19,11 @@ class CompositorVSyncManager;
namespace content {
-class BrowserCompositorOutputSurfaceProxy;
-
class CONTENT_EXPORT SoftwareBrowserCompositorOutputSurface
: public BrowserCompositorOutputSurface {
public:
SoftwareBrowserCompositorOutputSurface(
- scoped_refptr<BrowserCompositorOutputSurfaceProxy> surface_proxy,
scoped_ptr<cc::SoftwareOutputDevice> software_device,
- int surface_id,
- IDMap<BrowserCompositorOutputSurface>* output_surface_map,
const scoped_refptr<ui::CompositorVSyncManager>& vsync_manager);
~SoftwareBrowserCompositorOutputSurface() override;
@@ -38,11 +33,11 @@ class CONTENT_EXPORT SoftwareBrowserCompositorOutputSurface
#if defined(OS_MACOSX)
void OnSurfaceDisplayed() override;
+ void SetSurfaceSuspendedForRecycle(bool suspended) override;
+ bool SurfaceShouldNotShowFramesAfterSuspendForRecycle() const override;
#endif
- // On the software path we need to explicitly call the proxy to update the
- // VSync parameters.
- scoped_refptr<BrowserCompositorOutputSurfaceProxy> output_surface_proxy_;
+ base::WeakPtrFactory<SoftwareBrowserCompositorOutputSurface> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(SoftwareBrowserCompositorOutputSurface);
};
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 904fca2d2f4..68534f0cacd 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
@@ -5,7 +5,6 @@
#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"
#include "ui/compositor/compositor.h"
@@ -72,9 +71,6 @@ class SoftwareBrowserCompositorOutputSurfaceTest : public testing::Test {
scoped_ptr<base::MessageLoop> message_loop_;
scoped_ptr<ui::Compositor> compositor_;
- IDMap<content::BrowserCompositorOutputSurface> surface_map_;
- scoped_refptr<content::BrowserCompositorOutputSurfaceProxy> surface_proxy_;
-
DISALLOW_COPY_AND_ASSIGN(SoftwareBrowserCompositorOutputSurfaceTest);
};
@@ -96,17 +92,11 @@ void SoftwareBrowserCompositorOutputSurfaceTest::SetUp() {
compositor_.reset(new ui::Compositor(gfx::kNullAcceleratedWidget,
context_factory,
base::MessageLoopProxy::current()));
- surface_proxy_ =
- new content::BrowserCompositorOutputSurfaceProxy(&surface_map_);
}
void SoftwareBrowserCompositorOutputSurfaceTest::TearDown() {
output_surface_.reset();
compositor_.reset();
-
- EXPECT_TRUE(surface_map_.IsEmpty());
-
- surface_map_.Clear();
ui::TerminateContextFactoryForTests();
}
@@ -115,10 +105,7 @@ SoftwareBrowserCompositorOutputSurfaceTest::CreateSurface(
scoped_ptr<cc::SoftwareOutputDevice> device) {
return scoped_ptr<content::BrowserCompositorOutputSurface>(
new content::SoftwareBrowserCompositorOutputSurface(
- surface_proxy_,
device.Pass(),
- 1,
- &surface_map_,
compositor_->vsync_manager()));
}
diff --git a/chromium/content/browser/compositor/software_layer_mac.h b/chromium/content/browser/compositor/software_layer_mac.h
deleted file mode 100644
index 687070e500e..00000000000
--- a/chromium/content/browser/compositor/software_layer_mac.h
+++ /dev/null
@@ -1,22 +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_RENDERER_HOST_SOFTWARE_LAYER_MAC_H_
-#define CONTENT_BROWSER_RENDERER_HOST_SOFTWARE_LAYER_MAC_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include "ui/gfx/geometry/size.h"
-
-@interface SoftwareLayer : CALayer
-- (id)init;
-
-- (void)setContentsToData:(const void *)data
- withRowBytes:(size_t)rowBytes
- withPixelSize:(gfx::Size)pixelSize
- withScaleFactor:(float)scaleFactor;
-@end
-
-
-#endif // CONTENT_BROWSER_RENDERER_HOST_SOFTWARE_LAYER_MAC_H_
diff --git a/chromium/content/browser/compositor/software_layer_mac.mm b/chromium/content/browser/compositor/software_layer_mac.mm
deleted file mode 100644
index eb2f03c2547..00000000000
--- a/chromium/content/browser/compositor/software_layer_mac.mm
+++ /dev/null
@@ -1,68 +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/software_layer_mac.h"
-
-#include "base/debug/trace_event.h"
-#include "base/mac/mac_util.h"
-#include "base/mac/scoped_cftyperef.h"
-#include "base/mac/sdk_forward_declarations.h"
-#include "ui/base/cocoa/animation_utils.h"
-
-@implementation SoftwareLayer
-
-- (id)init {
- if (self = [super init]) {
- [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];
- }
- return self;
-}
-
-- (void)setContentsToData:(const void *)data
- withRowBytes:(size_t)rowBytes
- withPixelSize:(gfx::Size)pixelSize
- withScaleFactor:(float)scaleFactor {
- TRACE_EVENT0("browser", "-[SoftwareLayer setContentsToData]");
-
- // Disable animating the contents change or the scale factor change.
- ScopedCAActionDisabler disabler;
-
- // Set the contents of the software CALayer to be a CGImage with the provided
- // pixel data. Make a copy of the data before backing the image with them,
- // because the same buffer will be reused for the next frame.
- base::ScopedCFTypeRef<CFDataRef> dataCopy(
- CFDataCreate(NULL,
- static_cast<const UInt8 *>(data),
- rowBytes * pixelSize.height()));
- base::ScopedCFTypeRef<CGDataProviderRef> dataProvider(
- CGDataProviderCreateWithCFData(dataCopy));
- base::ScopedCFTypeRef<CGImageRef> image(
- CGImageCreate(pixelSize.width(),
- pixelSize.height(),
- 8,
- 32,
- rowBytes,
- base::mac::GetSystemColorSpace(),
- kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,
- dataProvider,
- NULL,
- 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))] &&
- [self respondsToSelector:(@selector(setContentsScale:))] &&
- [self contentsScale] != scaleFactor) {
- [self setContentsScale:scaleFactor];
- }
-}
-
-@end
diff --git a/chromium/content/browser/compositor/software_output_device_mac.mm b/chromium/content/browser/compositor/software_output_device_mac.mm
index 6fc3aefb0ec..70ca4b411b4 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_ca_layer_tree_mac.h"
+#include "ui/accelerated_widget_mac/accelerated_widget_mac.h"
#include "ui/compositor/compositor.h"
namespace content {
@@ -20,8 +20,8 @@ SoftwareOutputDeviceMac::~SoftwareOutputDeviceMac() {
void SoftwareOutputDeviceMac::EndPaint(cc::SoftwareFrameData* frame_data) {
SoftwareOutputDevice::EndPaint(frame_data);
- BrowserCompositorCALayerTreeMacGotSoftwareFrame(
- compositor_->widget(), frame_data, scale_factor_, canvas_.get());
+ ui::AcceleratedWidgetMacGotSoftwareFrame(
+ compositor_->widget(), scale_factor_, surface_->getCanvas());
}
} // 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 62d8bce3347..98c111d5cc8 100644
--- a/chromium/content/browser/compositor/software_output_device_ozone.cc
+++ b/chromium/content/browser/compositor/software_output_device_ozone.cc
@@ -43,7 +43,7 @@ SkCanvas* SoftwareOutputDeviceOzone::BeginPaint(const gfx::Rect& damage_rect) {
DCHECK(gfx::Rect(viewport_pixel_size_).Contains(damage_rect));
// Get canvas for next frame.
- canvas_ = surface_ozone_->GetCanvas();
+ surface_ = surface_ozone_->GetSurface();
return SoftwareOutputDevice::BeginPaint(damage_rect);
}
diff --git a/chromium/content/browser/compositor/software_output_device_ozone.h b/chromium/content/browser/compositor/software_output_device_ozone.h
index ef947e16c44..ed0120d5f2d 100644
--- a/chromium/content/browser/compositor/software_output_device_ozone.h
+++ b/chromium/content/browser/compositor/software_output_device_ozone.h
@@ -23,12 +23,12 @@ class CONTENT_EXPORT SoftwareOutputDeviceOzone
: public cc::SoftwareOutputDevice {
public:
explicit SoftwareOutputDeviceOzone(ui::Compositor* compositor);
- virtual ~SoftwareOutputDeviceOzone();
+ ~SoftwareOutputDeviceOzone() override;
- virtual void Resize(const gfx::Size& viewport_pixel_size,
+ 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;
+ SkCanvas* BeginPaint(const gfx::Rect& damage_rect) override;
+ 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 8b720055d8f..a19465b35af 100644
--- a/chromium/content/browser/compositor/software_output_device_ozone_unittest.cc
+++ b/chromium/content/browser/compositor/software_output_device_ozone_unittest.cc
@@ -11,56 +11,41 @@
#include "third_party/skia/include/core/SkSurface.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/test/context_factories_for_test.h"
-#include "ui/gfx/size.h"
+#include "ui/gfx/geometry/size.h"
#include "ui/gfx/skia_util.h"
#include "ui/gfx/vsync_provider.h"
#include "ui/gl/gl_implementation.h"
-#include "ui/ozone/public/surface_factory_ozone.h"
+#include "ui/ozone/public/ozone_platform.h"
#include "ui/ozone/public/surface_ozone_canvas.h"
+#include "ui/platform_window/platform_window.h"
+#include "ui/platform_window/platform_window_delegate.h"
namespace {
-class MockSurfaceOzone : public ui::SurfaceOzoneCanvas {
+class TestPlatformWindowDelegate : public ui::PlatformWindowDelegate {
public:
- MockSurfaceOzone() {}
- virtual ~MockSurfaceOzone() {}
-
- // ui::SurfaceOzoneCanvas overrides:
- 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 {
- return skia::SharePtr(surface_->getCanvas());
- }
- virtual void PresentCanvas(const gfx::Rect& damage) override {}
- virtual scoped_ptr<gfx::VSyncProvider> CreateVSyncProvider() override {
- return scoped_ptr<gfx::VSyncProvider>();
+ TestPlatformWindowDelegate() : widget_(gfx::kNullAcceleratedWidget) {}
+ ~TestPlatformWindowDelegate() override {}
+
+ gfx::AcceleratedWidget GetAcceleratedWidget() const { return widget_; }
+
+ // ui::PlatformWindowDelegate:
+ void OnBoundsChanged(const gfx::Rect& new_bounds) override {}
+ void OnDamageRect(const gfx::Rect& damaged_region) override {}
+ void DispatchEvent(ui::Event* event) override {}
+ void OnCloseRequest() override {}
+ void OnClosed() override {}
+ void OnWindowStateChanged(ui::PlatformWindowState new_state) override {}
+ void OnLostCapture() override {}
+ void OnAcceleratedWidgetAvailable(gfx::AcceleratedWidget widget) override {
+ widget_ = widget;
}
+ void OnActivationChanged(bool active) override {}
private:
- skia::RefPtr<SkSurface> surface_;
-
- DISALLOW_COPY_AND_ASSIGN(MockSurfaceOzone);
-};
-
-class MockSurfaceFactoryOzone : public ui::SurfaceFactoryOzone {
- public:
- MockSurfaceFactoryOzone() {}
- virtual ~MockSurfaceFactoryOzone() {}
-
- virtual bool LoadEGLGLES2Bindings(
- AddGLLibraryCallback add_gl_library,
- SetGLGetProcAddressProcCallback set_gl_get_proc_address) override {
- return false;
- }
- virtual scoped_ptr<ui::SurfaceOzoneCanvas> CreateCanvasForWidget(
- gfx::AcceleratedWidget widget) override {
- return make_scoped_ptr<ui::SurfaceOzoneCanvas>(new MockSurfaceOzone());
- }
+ gfx::AcceleratedWidget widget_;
- private:
- DISALLOW_COPY_AND_ASSIGN(MockSurfaceFactoryOzone);
+ DISALLOW_COPY_AND_ASSIGN(TestPlatformWindowDelegate);
};
} // namespace
@@ -68,10 +53,10 @@ class MockSurfaceFactoryOzone : public ui::SurfaceFactoryOzone {
class SoftwareOutputDeviceOzoneTest : public testing::Test {
public:
SoftwareOutputDeviceOzoneTest();
- virtual ~SoftwareOutputDeviceOzoneTest();
+ ~SoftwareOutputDeviceOzoneTest() override;
- virtual void SetUp() override;
- virtual void TearDown() override;
+ void SetUp() override;
+ void TearDown() override;
protected:
scoped_ptr<content::SoftwareOutputDeviceOzone> output_device_;
@@ -80,7 +65,8 @@ class SoftwareOutputDeviceOzoneTest : public testing::Test {
private:
scoped_ptr<ui::Compositor> compositor_;
scoped_ptr<base::MessageLoop> message_loop_;
- scoped_ptr<ui::SurfaceFactoryOzone> surface_factory_;
+ TestPlatformWindowDelegate window_delegate_;
+ scoped_ptr<ui::PlatformWindow> window_;
DISALLOW_COPY_AND_ASSIGN(SoftwareOutputDeviceOzoneTest);
};
@@ -97,14 +83,12 @@ void SoftwareOutputDeviceOzoneTest::SetUp() {
ui::ContextFactory* context_factory =
ui::InitializeContextFactoryForTests(enable_pixel_output_);
- surface_factory_.reset(new MockSurfaceFactoryOzone());
-
const gfx::Size size(500, 400);
- const gfx::AcceleratedWidget kTestAcceleratedWidget = 1;
- compositor_.reset(
- new ui::Compositor(kTestAcceleratedWidget,
- context_factory,
- base::MessageLoopProxy::current()));
+ window_ = ui::OzonePlatform::GetInstance()->CreatePlatformWindow(
+ &window_delegate_, gfx::Rect(size));
+ compositor_.reset(new ui::Compositor(window_delegate_.GetAcceleratedWidget(),
+ context_factory,
+ base::MessageLoopProxy::current()));
compositor_->SetScaleAndSize(1.0f, size);
output_device_.reset(new content::SoftwareOutputDeviceOzone(
@@ -115,14 +99,14 @@ void SoftwareOutputDeviceOzoneTest::SetUp() {
void SoftwareOutputDeviceOzoneTest::TearDown() {
output_device_.reset();
compositor_.reset();
- surface_factory_.reset();
+ window_.reset();
ui::TerminateContextFactoryForTests();
}
class SoftwareOutputDeviceOzonePixelTest
: public SoftwareOutputDeviceOzoneTest {
protected:
- virtual void SetUp() override;
+ void SetUp() override;
};
void SoftwareOutputDeviceOzonePixelTest::SetUp() {
@@ -152,41 +136,3 @@ TEST_F(SoftwareOutputDeviceOzoneTest, CheckCorrectResizeBehavior) {
}
-TEST_F(SoftwareOutputDeviceOzonePixelTest, CheckCopyToBitmap) {
- const int width = 6;
- const int height = 4;
- const gfx::Rect area(width, height);
- output_device_->Resize(area.size(), 1.f);
- SkCanvas* canvas = output_device_->BeginPaint(area);
-
- // Clear the background to black.
- canvas->drawColor(SK_ColorBLACK);
-
- cc::SoftwareFrameData frame;
- output_device_->EndPaint(&frame);
-
- // Draw a white rectangle.
- gfx::Rect damage(area.width() / 2, area.height() / 2);
- canvas = output_device_->BeginPaint(damage);
- canvas->clipRect(gfx::RectToSkRect(damage), SkRegion::kReplace_Op);
-
- canvas->drawColor(SK_ColorWHITE);
-
- output_device_->EndPaint(&frame);
-
- SkPMColor pixels[width * height];
- output_device_->CopyToPixels(area, pixels);
-
- // Check that the copied bitmap contains the same pixel values as what we
- // painted.
- const SkPMColor white = SkPreMultiplyColor(SK_ColorWHITE);
- const SkPMColor black = SkPreMultiplyColor(SK_ColorBLACK);
- for (int i = 0; i < area.height(); ++i) {
- for (int j = 0; j < area.width(); ++j) {
- if (j < damage.width() && i < damage.height())
- EXPECT_EQ(white, pixels[i * area.width() + j]);
- else
- EXPECT_EQ(black, pixels[i * area.width() + j]);
- }
- }
-}
diff --git a/chromium/content/browser/compositor/software_output_device_win.cc b/chromium/content/browser/compositor/software_output_device_win.cc
index 1a6b5f64b40..35d14b1ac30 100644
--- a/chromium/content/browser/compositor/software_output_device_win.cc
+++ b/chromium/content/browser/compositor/software_output_device_win.cc
@@ -4,34 +4,98 @@
#include "content/browser/compositor/software_output_device_win.h"
+#include "base/memory/shared_memory.h"
#include "content/public/browser/browser_thread.h"
+#include "skia/ext/platform_canvas.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkDevice.h"
#include "ui/compositor/compositor.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/canvas_skia_paint.h"
#include "ui/gfx/gdi_util.h"
#include "ui/gfx/skia_util.h"
namespace content {
-SoftwareOutputDeviceWin::SoftwareOutputDeviceWin(ui::Compositor* compositor)
+OutputDeviceBacking::OutputDeviceBacking() : created_byte_size_(0) {
+}
+
+OutputDeviceBacking::~OutputDeviceBacking() {
+ DCHECK(devices_.empty());
+}
+
+void OutputDeviceBacking::Resized() {
+ size_t new_size = GetMaxByteSize();
+ if (new_size == created_byte_size_)
+ return;
+ for (SoftwareOutputDeviceWin* device : devices_) {
+ device->ReleaseContents();
+ }
+ backing_.reset();
+ created_byte_size_ = 0;
+}
+
+void OutputDeviceBacking::RegisterOutputDevice(
+ SoftwareOutputDeviceWin* device) {
+ devices_.push_back(device);
+}
+
+void OutputDeviceBacking::UnregisterOutputDevice(
+ SoftwareOutputDeviceWin* device) {
+ auto it = std::find(devices_.begin(), devices_.end(), device);
+ DCHECK(it != devices_.end());
+ devices_.erase(it);
+ Resized();
+}
+
+base::SharedMemory* OutputDeviceBacking::GetSharedMemory() {
+ if (backing_)
+ return backing_.get();
+ created_byte_size_ = GetMaxByteSize();
+
+ backing_.reset(new base::SharedMemory);
+ CHECK(backing_->CreateAnonymous(created_byte_size_));
+ return backing_.get();
+}
+
+size_t OutputDeviceBacking::GetMaxByteSize() {
+ // Minimum byte size is 1 because creating a 0-byte-long SharedMemory fails.
+ size_t max_size = 1;
+ for (const SoftwareOutputDeviceWin* device : devices_) {
+ max_size = std::max(
+ max_size,
+ static_cast<size_t>(device->viewport_pixel_size().GetArea() * 4));
+ }
+ return max_size;
+}
+
+SoftwareOutputDeviceWin::SoftwareOutputDeviceWin(OutputDeviceBacking* backing,
+ ui::Compositor* compositor)
: hwnd_(compositor->widget()),
- is_hwnd_composited_(false) {
- // TODO(skaslev) Remove this when crbug.com/180702 is fixed.
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ is_hwnd_composited_(false),
+ backing_(backing),
+ in_paint_(false) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
LONG style = GetWindowLong(hwnd_, GWL_EXSTYLE);
is_hwnd_composited_ = !!(style & WS_EX_COMPOSITED);
+ // Layered windows must be completely updated every time, so they can't
+ // share contents with other windows.
+ if (is_hwnd_composited_)
+ backing_ = nullptr;
+ if (backing_)
+ backing_->RegisterOutputDevice(this);
}
SoftwareOutputDeviceWin::~SoftwareOutputDeviceWin() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DCHECK(!in_paint_);
+ if (backing_)
+ backing_->UnregisterOutputDevice(this);
}
void SoftwareOutputDeviceWin::Resize(const gfx::Size& viewport_pixel_size,
float scale_factor) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DCHECK(!in_paint_);
scale_factor_ = scale_factor;
@@ -39,29 +103,35 @@ void SoftwareOutputDeviceWin::Resize(const gfx::Size& viewport_pixel_size,
return;
viewport_pixel_size_ = viewport_pixel_size;
- contents_.reset(new gfx::Canvas(viewport_pixel_size, 1.0f, true));
- memset(&bitmap_info_, 0, sizeof(bitmap_info_));
- gfx::CreateBitmapHeader(viewport_pixel_size_.width(),
- viewport_pixel_size_.height(),
- &bitmap_info_.bmiHeader);
+ if (backing_)
+ backing_->Resized();
+ contents_.clear();
}
SkCanvas* SoftwareOutputDeviceWin::BeginPaint(const gfx::Rect& damage_rect) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(contents_);
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DCHECK(!in_paint_);
+ if (!contents_) {
+ HANDLE shared_section = NULL;
+ if (backing_)
+ shared_section = backing_->GetSharedMemory()->handle();
+ contents_ = skia::AdoptRef(skia::CreatePlatformCanvas(
+ viewport_pixel_size_.width(), viewport_pixel_size_.height(), true,
+ shared_section, skia::CRASH_ON_FAILURE));
+ }
damage_rect_ = damage_rect;
- return contents_ ? contents_->sk_canvas() : NULL;
+ in_paint_ = true;
+ return contents_.get();
}
void SoftwareOutputDeviceWin::EndPaint(cc::SoftwareFrameData* frame_data) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(contents_);
DCHECK(frame_data);
+ DCHECK(in_paint_);
- if (!contents_)
- return;
-
+ in_paint_ = false;
SoftwareOutputDevice::EndPaint(frame_data);
gfx::Rect rect = damage_rect_;
@@ -69,8 +139,6 @@ void SoftwareOutputDeviceWin::EndPaint(cc::SoftwareFrameData* frame_data) {
if (rect.IsEmpty())
return;
- SkCanvas* canvas = contents_->sk_canvas();
- DCHECK(canvas);
if (is_hwnd_composited_) {
RECT wr;
GetWindowRect(hwnd_, &wr);
@@ -84,24 +152,23 @@ void SoftwareOutputDeviceWin::EndPaint(cc::SoftwareFrameData* frame_data) {
style |= WS_EX_LAYERED;
SetWindowLong(hwnd_, GWL_EXSTYLE, style);
- HDC dib_dc = skia::BeginPlatformPaint(canvas);
+ HDC dib_dc = skia::BeginPlatformPaint(contents_.get());
::UpdateLayeredWindow(hwnd_, NULL, &position, &size, dib_dc, &zero,
RGB(0xFF, 0xFF, 0xFF), &blend, ULW_ALPHA);
- skia::EndPlatformPaint(canvas);
+ skia::EndPlatformPaint(contents_.get());
} else {
HDC hdc = ::GetDC(hwnd_);
RECT src_rect = rect.ToRECT();
- skia::DrawToNativeContext(canvas, hdc, rect.x(), rect.y(), &src_rect);
+ skia::DrawToNativeContext(contents_.get(), hdc, rect.x(), rect.y(),
+ &src_rect);
::ReleaseDC(hwnd_, hdc);
}
}
-void SoftwareOutputDeviceWin::CopyToPixels(const gfx::Rect& rect,
- void* pixels) {
- DCHECK(contents_);
- SkImageInfo info = SkImageInfo::MakeN32Premul(rect.width(), rect.height());
- contents_->sk_canvas()->readPixels(
- info, pixels, info.minRowBytes(), rect.x(), rect.y());
+void SoftwareOutputDeviceWin::ReleaseContents() {
+ DCHECK(!contents_ || contents_->unique());
+ DCHECK(!in_paint_);
+ contents_.clear();
}
} // namespace content
diff --git a/chromium/content/browser/compositor/software_output_device_win.h b/chromium/content/browser/compositor/software_output_device_win.h
index 85873fb12b6..8b7fc160dc3 100644
--- a/chromium/content/browser/compositor/software_output_device_win.h
+++ b/chromium/content/browser/compositor/software_output_device_win.h
@@ -5,13 +5,15 @@
#ifndef CONTENT_BROWSER_COMPOSITOR_SOFTWARE_OUTPUT_DEVICE_WIN_H_
#define CONTENT_BROWSER_COMPOSITOR_SOFTWARE_OUTPUT_DEVICE_WIN_H_
+#include <vector>
+
#include "base/memory/scoped_ptr.h"
#include "cc/output/software_output_device.h"
#include <windows.h>
-namespace gfx {
-class Canvas;
+namespace base {
+class SharedMemory;
}
namespace ui {
@@ -19,23 +21,48 @@ class Compositor;
}
namespace content {
+class SoftwareOutputDeviceWin;
+
+class OutputDeviceBacking {
+ public:
+ OutputDeviceBacking();
+ ~OutputDeviceBacking();
+
+ void Resized();
+ void RegisterOutputDevice(SoftwareOutputDeviceWin* device);
+ void UnregisterOutputDevice(SoftwareOutputDeviceWin* device);
+ base::SharedMemory* GetSharedMemory();
+
+ private:
+ size_t GetMaxByteSize();
+
+ std::vector<SoftwareOutputDeviceWin*> devices_;
+ scoped_ptr<base::SharedMemory> backing_;
+ size_t created_byte_size_;
+
+ DISALLOW_COPY_AND_ASSIGN(OutputDeviceBacking);
+};
class SoftwareOutputDeviceWin : public cc::SoftwareOutputDevice {
public:
- explicit SoftwareOutputDeviceWin(ui::Compositor* compositor);
- virtual ~SoftwareOutputDeviceWin();
+ SoftwareOutputDeviceWin(OutputDeviceBacking* backing,
+ ui::Compositor* compositor);
+ ~SoftwareOutputDeviceWin() override;
+
+ void Resize(const gfx::Size& viewport_pixel_size,
+ float scale_factor) override;
+ SkCanvas* BeginPaint(const gfx::Rect& damage_rect) override;
+ void EndPaint(cc::SoftwareFrameData* frame_data) override;
- 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;
+ gfx::Size viewport_pixel_size() const { return viewport_pixel_size_; }
+ void ReleaseContents();
private:
HWND hwnd_;
- BITMAPINFO bitmap_info_;
- scoped_ptr<gfx::Canvas> contents_;
+ skia::RefPtr<SkCanvas> contents_;
bool is_hwnd_composited_;
+ OutputDeviceBacking* backing_;
+ bool in_paint_;
DISALLOW_COPY_AND_ASSIGN(SoftwareOutputDeviceWin);
};
diff --git a/chromium/content/browser/compositor/software_output_device_x11.cc b/chromium/content/browser/compositor/software_output_device_x11.cc
index ebaefd7550e..6570c41082d 100644
--- a/chromium/content/browser/compositor/software_output_device_x11.cc
+++ b/chromium/content/browser/compositor/software_output_device_x11.cc
@@ -20,7 +20,7 @@ namespace content {
SoftwareOutputDeviceX11::SoftwareOutputDeviceX11(ui::Compositor* compositor)
: compositor_(compositor), display_(gfx::GetXDisplay()), gc_(NULL) {
// TODO(skaslev) Remove this when crbug.com/180702 is fixed.
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
gc_ = XCreateGC(display_, compositor_->widget(), 0, NULL);
if (!XGetWindowAttributes(display_, compositor_->widget(), &attributes_)) {
@@ -31,17 +31,17 @@ SoftwareOutputDeviceX11::SoftwareOutputDeviceX11(ui::Compositor* compositor)
}
SoftwareOutputDeviceX11::~SoftwareOutputDeviceX11() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
XFreeGC(display_, gc_);
}
void SoftwareOutputDeviceX11::EndPaint(cc::SoftwareFrameData* frame_data) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(canvas_);
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DCHECK(surface_);
DCHECK(frame_data);
- if (!canvas_)
+ if (!surface_)
return;
SoftwareOutputDevice::EndPaint(frame_data);
@@ -64,7 +64,7 @@ void SoftwareOutputDeviceX11::EndPaint(cc::SoftwareFrameData* frame_data) {
SkImageInfo info;
size_t rowBytes;
- const void* addr = canvas_->peekPixels(&info, &rowBytes);
+ const void* addr = surface_->peekPixels(&info, &rowBytes);
image.width = viewport_pixel_size_.width();
image.height = viewport_pixel_size_.height();
image.depth = 32;
@@ -118,7 +118,7 @@ void SoftwareOutputDeviceX11::EndPaint(cc::SoftwareFrameData* frame_data) {
// TODO(jbauman): Switch to XShmPutImage since it's async.
SkImageInfo info;
size_t rowBytes;
- const void* addr = canvas_->peekPixels(&info, &rowBytes);
+ const void* addr = surface_->peekPixels(&info, &rowBytes);
gfx::PutARGBImage(display_,
attributes_.visual,
attributes_.depth,
diff --git a/chromium/content/browser/compositor/surface_display_output_surface.cc b/chromium/content/browser/compositor/surface_display_output_surface.cc
deleted file mode 100644
index d3971dadbaa..00000000000
--- a/chromium/content/browser/compositor/surface_display_output_surface.cc
+++ /dev/null
@@ -1,90 +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/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::SurfaceManager* surface_manager,
- cc::SurfaceIdAllocator* allocator,
- const scoped_refptr<cc::ContextProvider>& context_provider)
- : cc::OutputSurface(context_provider,
- scoped_ptr<cc::SoftwareOutputDevice>()),
- 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();
- 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());
- 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();
-}
-
-} // namespace content
diff --git a/chromium/content/browser/compositor/surface_display_output_surface.h b/chromium/content/browser/compositor/surface_display_output_surface.h
deleted file mode 100644
index 698b9f5553c..00000000000
--- a/chromium/content/browser/compositor/surface_display_output_surface.h
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_COMPOSITOR_SURFACE_DISPLAY_OUTPUT_SURFACE_H_
-#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;
-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,
- public cc::SurfaceFactoryClient {
- public:
- // The underlying cc::Display and cc::SurfaceManager must outlive this class.
- SurfaceDisplayOutputSurface(
- cc::SurfaceManager* surface_manager,
- cc::SurfaceIdAllocator* allocator,
- const scoped_refptr<cc::ContextProvider>& context_provider);
- ~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.
- void SwapBuffers(cc::CompositorFrame* frame) override;
- bool BindToClient(cc::OutputSurfaceClient* client) override;
-
- // cc::SurfaceFactoryClient implementation.
- void ReturnResources(const cc::ReturnedResourceArray& resources) override;
-
- private:
- 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);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_COMPOSITOR_SURFACE_DISPLAY_OUTPUT_SURFACE_H_
diff --git a/chromium/content/browser/cross_site_transfer_browsertest.cc b/chromium/content/browser/cross_site_transfer_browsertest.cc
index f611030bf9a..6b54a514609 100644
--- a/chromium/content/browser/cross_site_transfer_browsertest.cc
+++ b/chromium/content/browser/cross_site_transfer_browsertest.cc
@@ -19,6 +19,7 @@
#include "content/shell/browser/shell_resource_dispatcher_host_delegate.h"
#include "net/base/escape.h"
#include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_status.h"
#include "url/gurl.h"
@@ -177,6 +178,9 @@ class CrossSiteTransferTest : public ContentBrowserTest {
base::Bind(
&CrossSiteTransferTest::InjectResourceDisptcherHostDelegate,
base::Unretained(this)));
+ host_resolver()->AddRule("*", "127.0.0.1");
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+ content::SetupCrossSiteRedirector(embedded_test_server());
}
void TearDownOnMainThread() override {
@@ -204,19 +208,19 @@ class CrossSiteTransferTest : public ContentBrowserTest {
load_observer.Wait();
}
- void SetUpCommandLine(CommandLine* command_line) override {
+ void SetUpCommandLine(base::CommandLine* command_line) override {
// Use --site-per-process to force process swaps for cross-site transfers.
command_line->AppendSwitch(switches::kSitePerProcess);
}
void InjectResourceDisptcherHostDelegate() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
old_delegate_ = ResourceDispatcherHostImpl::Get()->delegate();
ResourceDispatcherHostImpl::Get()->SetDelegate(&tracking_delegate_);
}
void RestoreResourceDisptcherHostDelegate() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
ResourceDispatcherHostImpl::Get()->SetDelegate(old_delegate_);
old_delegate_ = NULL;
}
@@ -248,16 +252,9 @@ IN_PROC_BROWSER_TEST_F(CrossSiteTransferTest,
MAYBE_ReplaceEntryCrossProcessThenTransfer) {
const NavigationController& controller =
shell()->web_contents()->GetController();
- host_resolver()->AddRule("*", "127.0.0.1");
- ASSERT_TRUE(test_server()->Start());
-
- // These must all stay in scope with replace_host.
- GURL::Replacements replace_host;
- std::string a_com("A.com");
- std::string b_com("B.com");
// Navigate to a starting URL, so there is a history entry to replace.
- GURL url1 = test_server()->GetURL("files/site_isolation/blank.html?1");
+ GURL url1 = embedded_test_server()->GetURL("/site_isolation/blank.html?1");
NavigateToURL(shell(), url1);
// Force all future navigations to transfer. Note that this includes same-site
@@ -269,9 +266,8 @@ IN_PROC_BROWSER_TEST_F(CrossSiteTransferTest,
// cross-site, so the renderer will send it to the browser via OpenURL to give
// to a new process. It will then be transferred into yet another process due
// to the call above.
- GURL url2 = test_server()->GetURL("files/site_isolation/blank.html?2");
- replace_host.SetHostStr(a_com);
- url2 = url2.ReplaceComponents(replace_host);
+ GURL url2 =
+ embedded_test_server()->GetURL("A.com", "/site_isolation/blank.html?2");
// Used to make sure the request for url2 succeeds, and there was only one of
// them.
tracking_delegate().SetTrackedURL(url2);
@@ -288,9 +284,8 @@ IN_PROC_BROWSER_TEST_F(CrossSiteTransferTest,
// Now navigate as before to a page on B.com, but normally (without
// replacement). This will still perform a double process-swap as above, via
// OpenURL and then transfer.
- GURL url3 = test_server()->GetURL("files/site_isolation/blank.html?3");
- replace_host.SetHostStr(b_com);
- url3 = url3.ReplaceComponents(replace_host);
+ GURL url3 =
+ embedded_test_server()->GetURL("B.com", "/site_isolation/blank.html?3");
// Used to make sure the request for url3 succeeds, and there was only one of
// them.
tracking_delegate().SetTrackedURL(url3);
@@ -316,10 +311,9 @@ IN_PROC_BROWSER_TEST_F(CrossSiteTransferTest,
ReplaceEntryInProcessThenTranfers) {
const NavigationController& controller =
shell()->web_contents()->GetController();
- ASSERT_TRUE(test_server()->Start());
// Navigate to a starting URL, so there is a history entry to replace.
- GURL url = test_server()->GetURL("files/site_isolation/blank.html?1");
+ GURL url = embedded_test_server()->GetURL("/site_isolation/blank.html?1");
NavigateToURL(shell(), url);
// Force all future navigations to transfer. Note that this includes same-site
@@ -330,7 +324,7 @@ IN_PROC_BROWSER_TEST_F(CrossSiteTransferTest,
// Navigate in-process with entry replacement. It will then be transferred
// into a new one due to the call above.
- GURL url2 = test_server()->GetURL("files/site_isolation/blank.html?2");
+ GURL url2 = embedded_test_server()->GetURL("/site_isolation/blank.html?2");
NavigateToURLContentInitiated(shell(), url2, true, true);
// There should be one history entry. url2 should have replaced url1.
@@ -340,7 +334,7 @@ IN_PROC_BROWSER_TEST_F(CrossSiteTransferTest,
EXPECT_EQ(url2, controller.GetEntryAtIndex(0)->GetURL());
// Now navigate as before, but without replacement.
- GURL url3 = test_server()->GetURL("files/site_isolation/blank.html?3");
+ GURL url3 = embedded_test_server()->GetURL("/site_isolation/blank.html?3");
NavigateToURLContentInitiated(shell(), url3, false, true);
// There should be two history entries. url2 should have replaced url1. url2
@@ -358,16 +352,9 @@ IN_PROC_BROWSER_TEST_F(CrossSiteTransferTest,
MAYBE_ReplaceEntryCrossProcessTwice) {
const NavigationController& controller =
shell()->web_contents()->GetController();
- host_resolver()->AddRule("*", "127.0.0.1");
- ASSERT_TRUE(test_server()->Start());
-
- // These must all stay in scope with replace_host.
- GURL::Replacements replace_host;
- std::string a_com("A.com");
- std::string b_com("B.com");
// Navigate to a starting URL, so there is a history entry to replace.
- GURL url1 = test_server()->GetURL("files/site_isolation/blank.html?1");
+ GURL url1 = embedded_test_server()->GetURL("/site_isolation/blank.html?1");
NavigateToURL(shell(), url1);
// Navigate to a page on A.com which redirects to B.com with entry
@@ -375,13 +362,11 @@ IN_PROC_BROWSER_TEST_F(CrossSiteTransferTest,
// and second in response to the server redirect to B.com. The second swap is
// also renderer-initiated via OpenURL because decidePolicyForNavigation is
// currently applied on redirects.
- GURL url2b = test_server()->GetURL("files/site_isolation/blank.html?2");
- replace_host.SetHostStr(b_com);
- url2b = url2b.ReplaceComponents(replace_host);
- GURL url2a = test_server()->GetURL(
- "server-redirect?" + net::EscapeQueryParamValue(url2b.spec(), false));
- replace_host.SetHostStr(a_com);
- url2a = url2a.ReplaceComponents(replace_host);
+ GURL::Replacements replace_host;
+ GURL url2b =
+ embedded_test_server()->GetURL("B.com", "/site_isolation/blank.html?2");
+ GURL url2a = embedded_test_server()->GetURL(
+ "A.com", "/cross-site/" + url2b.host() + url2b.PathForRequest());
NavigateToURLContentInitiated(shell(), url2a, true, true);
// There should be one history entry. url2b should have replaced url1.
@@ -391,13 +376,10 @@ IN_PROC_BROWSER_TEST_F(CrossSiteTransferTest,
EXPECT_EQ(url2b, controller.GetEntryAtIndex(0)->GetURL());
// Now repeat without replacement.
- GURL url3b = test_server()->GetURL("files/site_isolation/blank.html?3");
- replace_host.SetHostStr(b_com);
- url3b = url3b.ReplaceComponents(replace_host);
- GURL url3a = test_server()->GetURL(
- "server-redirect?" + net::EscapeQueryParamValue(url3b.spec(), false));
- replace_host.SetHostStr(a_com);
- url3a = url3a.ReplaceComponents(replace_host);
+ GURL url3b =
+ embedded_test_server()->GetURL("B.com", "/site_isolation/blank.html?3");
+ GURL url3a = embedded_test_server()->GetURL(
+ "A.com", "/cross-site/" + url3b.host() + url3b.PathForRequest());
NavigateToURLContentInitiated(shell(), url3a, false, true);
// There should be two history entries. url2b should have replaced url1. url2b
@@ -414,16 +396,9 @@ IN_PROC_BROWSER_TEST_F(CrossSiteTransferTest,
IN_PROC_BROWSER_TEST_F(CrossSiteTransferTest, NoLeakOnCrossSiteCancel) {
const NavigationController& controller =
shell()->web_contents()->GetController();
- host_resolver()->AddRule("*", "127.0.0.1");
- ASSERT_TRUE(test_server()->Start());
-
- // These must all stay in scope with replace_host.
- GURL::Replacements replace_host;
- std::string a_com("A.com");
- std::string b_com("B.com");
// Navigate to a starting URL, so there is a history entry to replace.
- GURL url1 = test_server()->GetURL("files/site_isolation/blank.html?1");
+ GURL url1 = embedded_test_server()->GetURL("/site_isolation/blank.html?1");
NavigateToURL(shell(), url1);
// Force all future navigations to transfer.
@@ -437,9 +412,8 @@ IN_PROC_BROWSER_TEST_F(CrossSiteTransferTest, NoLeakOnCrossSiteCancel) {
// cross-site, so the renderer will send it to the browser via OpenURL to give
// to a new process. It will then be transferred into yet another process due
// to the call above.
- GURL url2 = test_server()->GetURL("files/site_isolation/blank.html?2");
- replace_host.SetHostStr(a_com);
- url2 = url2.ReplaceComponents(replace_host);
+ GURL url2 =
+ embedded_test_server()->GetURL("A.com", "/site_isolation/blank.html?2");
// Used to make sure the second request is cancelled, and there is only one
// request for url2.
tracking_delegate().SetTrackedURL(url2);
diff --git a/chromium/content/browser/device_monitor_mac.mm b/chromium/content/browser/device_monitor_mac.mm
index f33c09752ea..c3c713c5714 100644
--- a/chromium/content/browser/device_monitor_mac.mm
+++ b/chromium/content/browser/device_monitor_mac.mm
@@ -12,6 +12,7 @@
#include "base/logging.h"
#include "base/mac/bind_objc_block.h"
#include "base/mac/scoped_nsobject.h"
+#include "base/profiler/scoped_tracker.h"
#include "base/threading/thread_checker.h"
#include "content/public/browser/browser_thread.h"
#import "media/base/mac/avfoundation_glue.h"
@@ -282,12 +283,12 @@ class SuspendObserverDelegate :
SuspendObserverDelegate::SuspendObserverDelegate(DeviceMonitorMacImpl* monitor)
: avfoundation_monitor_impl_(monitor) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
}
void SuspendObserverDelegate::StartObserver(
const scoped_refptr<base::SingleThreadTaskRunner>& device_thread) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
base::Closure on_device_changed_callback =
base::Bind(&SuspendObserverDelegate::OnDeviceChanged,
@@ -307,7 +308,7 @@ void SuspendObserverDelegate::StartObserver(
void SuspendObserverDelegate::OnDeviceChanged(
const scoped_refptr<base::SingleThreadTaskRunner>& device_thread) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
// Enumerate the devices in Device thread and post the consolidation of the
// new devices and the old ones to be done on UI thread. The devices array
// is retained in |device_thread| and released in DoOnDeviceChanged().
@@ -319,17 +320,17 @@ void SuspendObserverDelegate::OnDeviceChanged(
}
void SuspendObserverDelegate::ResetDeviceMonitor() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
avfoundation_monitor_impl_ = NULL;
[suspend_observer_ clearOnDeviceChangedCallback];
}
SuspendObserverDelegate::~SuspendObserverDelegate() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
}
void SuspendObserverDelegate::DoStartObserver(NSArray* devices) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
base::scoped_nsobject<NSArray> auto_release(devices);
for (CrAVCaptureDevice* device in devices) {
base::scoped_nsobject<CrAVCaptureDevice> device_ptr([device retain]);
@@ -338,7 +339,7 @@ void SuspendObserverDelegate::DoStartObserver(NSArray* devices) {
}
void SuspendObserverDelegate::DoOnDeviceChanged(NSArray* devices) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
base::scoped_nsobject<NSArray> auto_release(devices);
std::vector<DeviceInfo> snapshot_devices;
for (CrAVCaptureDevice* device in devices) {
@@ -360,7 +361,11 @@ void SuspendObserverDelegate::DoOnDeviceChanged(NSArray* devices) {
snapshot_devices.push_back(DeviceInfo([[device uniqueID] UTF8String],
device_type));
}
-
+ // Make sure no references are held to |devices| when
+ // ConsolidateDevicesListAndNotify is called since the VideoCaptureManager
+ // and AudioCaptureManagers also enumerates the available devices but on
+ // another thread.
+ auto_release.reset();
// |avfoundation_monitor_impl_| might have been NULLed asynchronously before
// arriving at this line.
if (avfoundation_monitor_impl_) {
@@ -399,7 +404,7 @@ AVFoundationMonitorImpl::AVFoundationMonitorImpl(
: DeviceMonitorMacImpl(monitor),
device_task_runner_(device_task_runner),
suspend_observer_delegate_(new SuspendObserverDelegate(this)) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
device_arrival_ =
[nc addObserverForName:AVFoundationGlue::
@@ -419,7 +424,7 @@ AVFoundationMonitorImpl::AVFoundationMonitorImpl(
}
AVFoundationMonitorImpl::~AVFoundationMonitorImpl() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
suspend_observer_delegate_->ResetDeviceMonitor();
NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
[nc removeObserver:device_arrival_];
@@ -427,7 +432,7 @@ AVFoundationMonitorImpl::~AVFoundationMonitorImpl() {
}
void AVFoundationMonitorImpl::OnDeviceChanged() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
suspend_observer_delegate_->OnDeviceChanged(device_task_runner_);
}
@@ -436,7 +441,7 @@ void AVFoundationMonitorImpl::OnDeviceChanged() {
@implementation CrAVFoundationDeviceObserver
- (id)initWithOnChangedCallback:(const base::Closure&)callback {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if ((self = [super init])) {
DCHECK(!callback.is_null());
onDeviceChangedCallback_ = callback;
@@ -445,7 +450,7 @@ void AVFoundationMonitorImpl::OnDeviceChanged() {
}
- (void)dealloc {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
std::set<base::scoped_nsobject<CrAVCaptureDevice> >::iterator it =
monitoredDevices_.begin();
while (it != monitoredDevices_.end())
@@ -454,7 +459,7 @@ void AVFoundationMonitorImpl::OnDeviceChanged() {
}
- (void)startObserving:(base::scoped_nsobject<CrAVCaptureDevice>)device {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(device != nil);
// Skip this device if there are already observers connected to it.
if (std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device) !=
@@ -473,7 +478,7 @@ void AVFoundationMonitorImpl::OnDeviceChanged() {
}
- (void)stopObserving:(CrAVCaptureDevice*)device {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(device != nil);
std::set<base::scoped_nsobject<CrAVCaptureDevice> >::iterator found =
@@ -484,12 +489,12 @@ void AVFoundationMonitorImpl::OnDeviceChanged() {
}
- (void)clearOnDeviceChangedCallback {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
onDeviceChangedCallback_.Reset();
}
- (void)removeObservers:(CrAVCaptureDevice*)device {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
// Check sanity of |device| via its -observationInfo. http://crbug.com/371271.
if ([device observationInfo]) {
[device removeObserver:self
@@ -503,7 +508,7 @@ void AVFoundationMonitorImpl::OnDeviceChanged() {
ofObject:(id)object
change:(NSDictionary*)change
context:(void*)context {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if ([keyPath isEqual:@"suspended"])
onDeviceChangedCallback_.Run();
if ([keyPath isEqual:@"connected"])
@@ -527,10 +532,20 @@ void DeviceMonitorMac::StartMonitoring(
const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner) {
DCHECK(thread_checker_.CalledOnValidThread());
if (AVFoundationGlue::IsAVFoundationSupported()) {
+ // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/458404
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "458404 DeviceMonitorMac::StartMonitoring::AVFoundation"));
DVLOG(1) << "Monitoring via AVFoundation";
device_monitor_impl_.reset(new AVFoundationMonitorImpl(this,
device_task_runner));
} else {
+ // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/458404
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "458404 DeviceMonitorMac::StartMonitoring::QTKit"));
DVLOG(1) << "Monitoring via QTKit";
device_monitor_impl_.reset(new QTKitMonitorImpl(this));
}
diff --git a/chromium/content/browser/device_monitor_udev.cc b/chromium/content/browser/device_monitor_udev.cc
index ddfe053eae2..82529e17908 100644
--- a/chromium/content/browser/device_monitor_udev.cc
+++ b/chromium/content/browser/device_monitor_udev.cc
@@ -6,13 +6,12 @@
#include "content/browser/device_monitor_udev.h"
-#include <libudev.h>
-
#include <string>
#include "base/system_monitor/system_monitor.h"
#include "content/browser/udev_linux.h"
#include "content/public/browser/browser_thread.h"
+#include "device/udev_linux/udev.h"
namespace {
@@ -46,7 +45,7 @@ DeviceMonitorLinux::~DeviceMonitorLinux() {
}
void DeviceMonitorLinux::Initialize() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
// We want to be notified of IO message loop destruction to delete |udev_|.
base::MessageLoop::current()->AddDestructionObserver(this);
@@ -67,12 +66,12 @@ void DeviceMonitorLinux::WillDestroyCurrentMessageLoop() {
}
void DeviceMonitorLinux::OnDevicesChanged(udev_device* device) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(device);
base::SystemMonitor::DeviceType device_type =
base::SystemMonitor::DEVTYPE_UNKNOWN;
- std::string subsystem(udev_device_get_subsystem(device));
+ std::string subsystem(device::udev_device_get_subsystem(device));
for (size_t i = 0; i < arraysize(kSubsystemMap); ++i) {
if (subsystem == kSubsystemMap[i].subsystem) {
device_type = kSubsystemMap[i].device_type;
diff --git a/chromium/content/browser/device_sensors/ambient_light_mac.cc b/chromium/content/browser/device_sensors/ambient_light_mac.cc
new file mode 100644
index 00000000000..187f6a0697d
--- /dev/null
+++ b/chromium/content/browser/device_sensors/ambient_light_mac.cc
@@ -0,0 +1,78 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is based on http://osxbook.com/book/bonus/chapter10/light/
+
+#include "content/browser/device_sensors/ambient_light_mac.h"
+
+#include "base/mac/scoped_cftyperef.h"
+#include "base/mac/scoped_ioobject.h"
+
+namespace content {
+
+namespace {
+enum LmuFunctionIndex {
+ kGetSensorReadingID = 0, // getSensorReading(int *, int *)
+ kGetLEDBrightnessID = 1, // getLEDBrightness(int, int *)
+ kSetLEDBrightnessID = 2, // setLEDBrightness(int, int, int *)
+ kSetLEDFadeID = 3, // setLEDFade(int, int, int, int *)
+};
+} // namespace
+
+// static
+scoped_ptr<AmbientLightSensor> AmbientLightSensor::Create() {
+ scoped_ptr<AmbientLightSensor> light_sensor(new AmbientLightSensor);
+ return light_sensor->Init() ? light_sensor.Pass() : nullptr;
+}
+
+AmbientLightSensor::~AmbientLightSensor() {
+ if (!io_connection_)
+ IOServiceClose(io_connection_);
+}
+
+AmbientLightSensor::AmbientLightSensor() : io_connection_(IO_OBJECT_NULL) {
+}
+
+bool AmbientLightSensor::Init() {
+ // Tested and verified by riju that the following call works on
+ // MacBookPro9,1 : Macbook Pro 15" (Mid 2012 model)
+ // MacBookPro10,1 : Macbook Pro 15" (Retina Display, Early 2013 model).
+ // MacBookPro10,2 : Macbook Pro 13" (Retina Display, Early 2013 model).
+ // MacBookAir5,2 : Macbook Air 13" (Mid 2012 model) (by François Beaufort).
+ // MacBookAir6,2 : Macbook Air 13" (Mid 2013 model).
+ // Testing plans : please download the code and follow the comments :-
+ // https://gist.github.com/riju/74af8c81a665e412d122/
+ // and add an entry here about the model and the status returned by the code.
+
+ // Look up a registered IOService object whose class is AppleLMUController.
+ base::mac::ScopedIOObject<io_service_t> service_object(
+ IOServiceGetMatchingService(kIOMasterPortDefault,
+ IOServiceMatching("AppleLMUController")));
+
+ // Return early if the ambient light sensor is not present.
+ if (!service_object)
+ return false;
+
+ // Create a connection to the IOService object.
+ kern_return_t kr =
+ IOServiceOpen(service_object, mach_task_self(), 0, &io_connection_);
+
+ // IOServiceOpen error.
+ if (kr != KERN_SUCCESS || io_connection_ == IO_OBJECT_NULL)
+ return false;
+
+ uint64_t lux_values[2];
+ return ReadSensorValue(lux_values);
+}
+
+bool AmbientLightSensor::ReadSensorValue(uint64_t lux_values[2]) {
+ uint32_t scalar_output_count = 2;
+ kern_return_t kr = IOConnectCallMethod(
+ io_connection_, LmuFunctionIndex::kGetSensorReadingID, nullptr, 0,
+ nullptr, 0, lux_values, &scalar_output_count, nullptr, 0);
+
+ return kr == KERN_SUCCESS;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/device_sensors/ambient_light_mac.h b/chromium/content/browser/device_sensors/ambient_light_mac.h
new file mode 100644
index 00000000000..8d34e165b80
--- /dev/null
+++ b/chromium/content/browser/device_sensors/ambient_light_mac.h
@@ -0,0 +1,40 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_DEVICE_SENSORS_AMBIENT_LIGHT_MAC_H_
+#define CONTENT_BROWSER_DEVICE_SENSORS_AMBIENT_LIGHT_MAC_H_
+
+#include <IOKit/IOKitLib.h>
+
+#include "base/memory/scoped_ptr.h"
+
+namespace content {
+
+// Provides an interface to retrieve ambient light data from MacBooks.
+class AmbientLightSensor {
+ public:
+ // Create AmbientLightSensor object, return NULL if no valid is sensor found.
+ static scoped_ptr<AmbientLightSensor> Create();
+
+ ~AmbientLightSensor();
+
+ // Retrieve lux values from Ambient Light Sensor.
+ bool ReadSensorValue(uint64_t lux_value[2]);
+
+ private:
+ AmbientLightSensor();
+
+ // Probe the local hardware looking for Ambient Light sensor and
+ // initialize an I/O connection to it.
+ bool Init();
+
+ // IOKit connection to the local sensor.
+ io_connect_t io_connection_;
+
+ DISALLOW_COPY_AND_ASSIGN(AmbientLightSensor);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_DEVICE_SENSORS_AMBIENT_LIGHT_MAC_H_
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 e42f45f9528..ea56b003fd7 100644
--- a/chromium/content/browser/device_sensors/data_fetcher_shared_memory.h
+++ b/chromium/content/browser/device_sensors/data_fetcher_shared_memory.h
@@ -22,6 +22,12 @@ class SuddenMotionSensor;
namespace content {
+#if defined(OS_CHROMEOS)
+class SensorManagerChromeOS;
+#elif defined(OS_MACOSX)
+class AmbientLightSensor;
+#endif
+
class CONTENT_EXPORT DataFetcherSharedMemory
: public DataFetcherSharedMemoryBase {
@@ -29,6 +35,10 @@ class CONTENT_EXPORT DataFetcherSharedMemory
DataFetcherSharedMemory();
~DataFetcherSharedMemory() override;
+#if defined(OS_ANDROID)
+ void Shutdown() override;
+#endif
+
private:
bool Start(ConsumerType consumer_type, void* buffer) override;
bool Stop(ConsumerType consumer_type) override;
@@ -38,17 +48,22 @@ class CONTENT_EXPORT DataFetcherSharedMemory
DeviceOrientationHardwareBuffer* orientation_buffer_;
DeviceLightHardwareBuffer* light_buffer_;
#endif
-#if defined(OS_MACOSX)
+
+#if defined(OS_CHROMEOS)
+ scoped_ptr<SensorManagerChromeOS> sensor_manager_;
+#elif defined(OS_MACOSX)
void Fetch(unsigned consumer_bitmask) override;
FetcherType GetType() const override;
+ scoped_ptr<AmbientLightSensor> ambient_light_sensor_;
scoped_ptr<SuddenMotionSensor> sudden_motion_sensor_;
#elif defined(OS_WIN)
class SensorEventSink;
class SensorEventSinkMotion;
class SensorEventSinkOrientation;
+ class SensorEventSinkLight;
- virtual FetcherType GetType() const override;
+ FetcherType GetType() const override;
bool RegisterForSensor(REFSENSOR_TYPE_ID sensor_type, ISensor** sensor,
scoped_refptr<SensorEventSink> event_sink);
@@ -58,6 +73,7 @@ class CONTENT_EXPORT DataFetcherSharedMemory
base::win::ScopedComPtr<ISensor> sensor_inclinometer_;
base::win::ScopedComPtr<ISensor> sensor_accelerometer_;
base::win::ScopedComPtr<ISensor> sensor_gyrometer_;
+ base::win::ScopedComPtr<ISensor> sensor_light_;
#endif
DISALLOW_COPY_AND_ASSIGN(DataFetcherSharedMemory);
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 477be76585a..e2676a14d72 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
@@ -56,4 +56,9 @@ bool DataFetcherSharedMemory::Stop(ConsumerType consumer_type) {
return false;
}
+void DataFetcherSharedMemory::Shutdown() {
+ DataFetcherSharedMemoryBase::Shutdown();
+ SensorManagerAndroid::GetInstance()->Shutdown();
+}
+
} // namespace content
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 d997537c059..f2b2d40c643 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
@@ -17,7 +17,7 @@ namespace content {
namespace {
-static size_t GetConsumerSharedMemoryBufferSize(ConsumerType consumer_type) {
+size_t GetConsumerSharedMemoryBufferSize(ConsumerType consumer_type) {
switch (consumer_type) {
case CONSUMER_TYPE_MOTION:
return sizeof(DeviceMotionHardwareBuffer);
@@ -165,7 +165,7 @@ bool DataFetcherSharedMemoryBase::StopFetchingDeviceData(
return true;
}
-void DataFetcherSharedMemoryBase::StopFetchingAllDeviceData() {
+void DataFetcherSharedMemoryBase::Shutdown() {
StopFetchingDeviceData(CONSUMER_TYPE_MOTION);
StopFetchingDeviceData(CONSUMER_TYPE_ORIENTATION);
StopFetchingDeviceData(CONSUMER_TYPE_LIGHT);
@@ -218,7 +218,7 @@ base::SharedMemory* DataFetcherSharedMemoryBase::GetSharedMemory(
size_t buffer_size = GetConsumerSharedMemoryBufferSize(consumer_type);
if (buffer_size == 0)
- return NULL;
+ return nullptr;
scoped_ptr<base::SharedMemory> new_shared_mem(new base::SharedMemory);
if (new_shared_mem->CreateAndMapAnonymous(buffer_size)) {
@@ -230,18 +230,18 @@ base::SharedMemory* DataFetcherSharedMemoryBase::GetSharedMemory(
}
}
LOG(ERROR) << "Failed to initialize shared memory";
- return NULL;
+ return nullptr;
}
void* DataFetcherSharedMemoryBase::GetSharedMemoryBuffer(
ConsumerType consumer_type) {
if (base::SharedMemory* shared_memory = GetSharedMemory(consumer_type))
return shared_memory->memory();
- return NULL;
+ return nullptr;
}
base::MessageLoop* DataFetcherSharedMemoryBase::GetPollingMessageLoop() const {
- return polling_thread_ ? polling_thread_->message_loop() : NULL;
+ return polling_thread_ ? polling_thread_->message_loop() : nullptr;
}
bool DataFetcherSharedMemoryBase::IsPollingTimerRunningForTesting() const {
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 fc1f031d499..c13c37800aa 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
@@ -33,7 +33,7 @@ class CONTENT_EXPORT DataFetcherSharedMemoryBase {
// Should be called before destruction to make sure all active
// sensors are unregistered.
- void StopFetchingAllDeviceData();
+ virtual void Shutdown();
// Returns the shared memory handle of the device sensor data
// duplicated into the given process. This method should only be
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 aa1a9a93153..e13cd8986c6 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
@@ -29,9 +29,9 @@ class FakeDataFetcher : public DataFetcherSharedMemoryBase {
updated_light_(false, false),
updated_motion_(false, false),
updated_orientation_(false, false),
- light_buffer_(NULL),
- motion_buffer_(NULL),
- orientation_buffer_(NULL) {}
+ light_buffer_(nullptr),
+ motion_buffer_(nullptr),
+ orientation_buffer_(nullptr) {}
~FakeDataFetcher() override {}
bool Init(ConsumerType consumer_type, void* buffer) {
diff --git a/chromium/content/browser/device_sensors/data_fetcher_shared_memory_chromeos.cc b/chromium/content/browser/device_sensors/data_fetcher_shared_memory_chromeos.cc
new file mode 100644
index 00000000000..76349d2a37d
--- /dev/null
+++ b/chromium/content/browser/device_sensors/data_fetcher_shared_memory_chromeos.cc
@@ -0,0 +1,53 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/device_sensors/data_fetcher_shared_memory.h"
+
+#include "content/browser/device_sensors/sensor_manager_chromeos.h"
+
+namespace content {
+
+DataFetcherSharedMemory::DataFetcherSharedMemory() {
+}
+
+DataFetcherSharedMemory::~DataFetcherSharedMemory() {
+}
+
+bool DataFetcherSharedMemory::Start(ConsumerType consumer_type, void* buffer) {
+ DCHECK(buffer);
+ if (!sensor_manager_)
+ sensor_manager_.reset(new SensorManagerChromeOS);
+
+ switch (consumer_type) {
+ case CONSUMER_TYPE_MOTION:
+ sensor_manager_->StartFetchingDeviceMotionData(
+ static_cast<DeviceMotionHardwareBuffer*>(buffer));
+ return true;
+ case CONSUMER_TYPE_ORIENTATION:
+ sensor_manager_->StartFetchingDeviceOrientationData(
+ static_cast<DeviceOrientationHardwareBuffer*>(buffer));
+ return true;
+ case CONSUMER_TYPE_LIGHT:
+ NOTIMPLEMENTED();
+ return false;
+ }
+ NOTREACHED();
+ return false;
+}
+
+bool DataFetcherSharedMemory::Stop(ConsumerType consumer_type) {
+ switch (consumer_type) {
+ case CONSUMER_TYPE_MOTION:
+ return sensor_manager_->StopFetchingDeviceMotionData();
+ case CONSUMER_TYPE_ORIENTATION:
+ return sensor_manager_->StopFetchingDeviceOrientationData();
+ case CONSUMER_TYPE_LIGHT:
+ NOTIMPLEMENTED();
+ return false;
+ }
+ NOTREACHED();
+ return false;
+}
+
+} // namespace content
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 5294e8ee5db..9b3a60babe8 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
@@ -2,14 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "data_fetcher_shared_memory.h"
+#include "content/browser/device_sensors/data_fetcher_shared_memory.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
namespace {
-static bool SetMotionBuffer(content::DeviceMotionHardwareBuffer* buffer,
+bool SetMotionBuffer(content::DeviceMotionHardwareBuffer* buffer,
bool enabled) {
if (!buffer)
return false;
@@ -19,7 +19,7 @@ static bool SetMotionBuffer(content::DeviceMotionHardwareBuffer* buffer,
return true;
}
-static bool SetOrientationBuffer(
+bool SetOrientationBuffer(
content::DeviceOrientationHardwareBuffer* buffer, bool enabled) {
if (!buffer)
return false;
@@ -29,7 +29,7 @@ static bool SetOrientationBuffer(
return true;
}
-static bool SetLightBuffer(content::DeviceLightHardwareBuffer* buffer,
+bool SetLightBuffer(content::DeviceLightHardwareBuffer* buffer,
double lux) {
if (!buffer)
return false;
@@ -44,7 +44,9 @@ static bool SetLightBuffer(content::DeviceLightHardwareBuffer* buffer,
namespace content {
DataFetcherSharedMemory::DataFetcherSharedMemory()
- : motion_buffer_(NULL), orientation_buffer_(NULL), light_buffer_(NULL) {
+ : motion_buffer_(nullptr),
+ orientation_buffer_(nullptr),
+ light_buffer_(nullptr) {
}
DataFetcherSharedMemory::~DataFetcherSharedMemory() {
diff --git a/chromium/content/browser/device_sensors/data_fetcher_shared_memory_mac.cc b/chromium/content/browser/device_sensors/data_fetcher_shared_memory_mac.cc
index 7f4934dd342..4a1644ffb68 100644
--- a/chromium/content/browser/device_sensors/data_fetcher_shared_memory_mac.cc
+++ b/chromium/content/browser/device_sensors/data_fetcher_shared_memory_mac.cc
@@ -2,18 +2,58 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "data_fetcher_shared_memory.h"
+#include "content/browser/device_sensors/data_fetcher_shared_memory.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
+#include "content/browser/device_sensors/ambient_light_mac.h"
#include "third_party/sudden_motion_sensor/sudden_motion_sensor_mac.h"
namespace {
const double kMeanGravity = 9.80665;
+double LMUvalueToLux(uint64_t raw_value) {
+ // Conversion formula from regression.
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=793728
+ // Let x = raw_value, then
+ // lux = -2.978303814*(10^-27)*x^4 + 2.635687683*(10^-19)*x^3 -
+ // 3.459747434*(10^-12)*x^2 + 3.905829689*(10^-5)*x - 0.1932594532
+
+ static const long double k4 = pow(10.L, -7);
+ static const long double k3 = pow(10.L, -4);
+ static const long double k2 = pow(10.L, -2);
+ static const long double k1 = pow(10.L, 5);
+ long double scaled_value = raw_value / k1;
+
+ long double lux_value =
+ (-3 * k4 * pow(scaled_value, 4)) + (2.6 * k3 * pow(scaled_value, 3)) +
+ (-3.4 * k2 * pow(scaled_value, 2)) + (3.9 * scaled_value) - 0.19;
+
+ double lux = ceil(static_cast<double>(lux_value));
+ return lux > 0 ? lux : 0;
+}
+
+void FetchLight(content::AmbientLightSensor* sensor,
+ content::DeviceLightHardwareBuffer* buffer) {
+ DCHECK(sensor);
+ DCHECK(buffer);
+ // Macbook pro has 2 lux values, left and right, we take the average.
+ // The raw sensor values are converted to lux using LMUvalueToLux(raw_value)
+ // similar to how it is done in Firefox.
+ uint64_t lux_value[2];
+ if (!sensor->ReadSensorValue(lux_value))
+ return;
+ uint64_t mean = (lux_value[0] + lux_value[1]) / 2;
+ double lux = LMUvalueToLux(mean);
+ buffer->seqlock.WriteBegin();
+ buffer->data.value = lux;
+ buffer->seqlock.WriteEnd();
+}
+
void FetchMotion(SuddenMotionSensor* sensor,
content::DeviceMotionHardwareBuffer* buffer) {
+ DCHECK(sensor);
DCHECK(buffer);
float axis_value[3];
@@ -33,6 +73,7 @@ void FetchMotion(SuddenMotionSensor* sensor,
void FetchOrientation(SuddenMotionSensor* sensor,
content::DeviceOrientationHardwareBuffer* buffer) {
+ DCHECK(sensor);
DCHECK(buffer);
// Retrieve per-axis calibrated values.
@@ -99,14 +140,16 @@ DataFetcherSharedMemory::~DataFetcherSharedMemory() {
void DataFetcherSharedMemory::Fetch(unsigned consumer_bitmask) {
DCHECK(base::MessageLoop::current() == GetPollingMessageLoop());
- DCHECK(sudden_motion_sensor_);
DCHECK(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)
FetchOrientation(sudden_motion_sensor_.get(), orientation_buffer_);
if (consumer_bitmask & CONSUMER_TYPE_MOTION)
FetchMotion(sudden_motion_sensor_.get(), motion_buffer_);
+ if (consumer_bitmask & CONSUMER_TYPE_LIGHT)
+ FetchLight(ambient_light_sensor_.get(), light_buffer_);
}
DataFetcherSharedMemory::FetcherType DataFetcherSharedMemory::GetType() const {
@@ -117,12 +160,13 @@ bool DataFetcherSharedMemory::Start(ConsumerType consumer_type, void* buffer) {
DCHECK(base::MessageLoop::current() == GetPollingMessageLoop());
DCHECK(buffer);
- if (!sudden_motion_sensor_)
- sudden_motion_sensor_.reset(SuddenMotionSensor::Create());
- bool sudden_motion_sensor_available = sudden_motion_sensor_.get() != NULL;
-
switch (consumer_type) {
- case CONSUMER_TYPE_MOTION:
+ case CONSUMER_TYPE_MOTION: {
+ if (!sudden_motion_sensor_)
+ sudden_motion_sensor_.reset(SuddenMotionSensor::Create());
+ bool sudden_motion_sensor_available =
+ sudden_motion_sensor_.get() != nullptr;
+
motion_buffer_ = static_cast<DeviceMotionHardwareBuffer*>(buffer);
UMA_HISTOGRAM_BOOLEAN("InertialSensor.MotionMacAvailable",
sudden_motion_sensor_available);
@@ -133,7 +177,13 @@ bool DataFetcherSharedMemory::Start(ConsumerType consumer_type, void* buffer) {
motion_buffer_->seqlock.WriteEnd();
}
return sudden_motion_sensor_available;
- case CONSUMER_TYPE_ORIENTATION:
+ }
+ case CONSUMER_TYPE_ORIENTATION: {
+ if (!sudden_motion_sensor_)
+ sudden_motion_sensor_.reset(SuddenMotionSensor::Create());
+ bool sudden_motion_sensor_available =
+ sudden_motion_sensor_.get() != nullptr;
+
orientation_buffer_ =
static_cast<DeviceOrientationHardwareBuffer*>(buffer);
UMA_HISTOGRAM_BOOLEAN("InertialSensor.OrientationMacAvailable",
@@ -151,6 +201,21 @@ bool DataFetcherSharedMemory::Start(ConsumerType consumer_type, void* buffer) {
orientation_buffer_->seqlock.WriteEnd();
}
return sudden_motion_sensor_available;
+ }
+ case CONSUMER_TYPE_LIGHT: {
+ if (!ambient_light_sensor_)
+ ambient_light_sensor_ = AmbientLightSensor::Create();
+ bool ambient_light_sensor_available =
+ ambient_light_sensor_.get() != nullptr;
+
+ light_buffer_ = static_cast<DeviceLightHardwareBuffer*>(buffer);
+ if (!ambient_light_sensor_available) {
+ light_buffer_->seqlock.WriteBegin();
+ light_buffer_->data.value = std::numeric_limits<double>::infinity();
+ light_buffer_->seqlock.WriteEnd();
+ }
+ return ambient_light_sensor_available;
+ }
default:
NOTREACHED();
}
@@ -166,7 +231,7 @@ bool DataFetcherSharedMemory::Stop(ConsumerType consumer_type) {
motion_buffer_->seqlock.WriteBegin();
motion_buffer_->data.allAvailableSensorsAreActive = false;
motion_buffer_->seqlock.WriteEnd();
- motion_buffer_ = NULL;
+ motion_buffer_ = nullptr;
}
return true;
case CONSUMER_TYPE_ORIENTATION:
@@ -174,7 +239,15 @@ bool DataFetcherSharedMemory::Stop(ConsumerType consumer_type) {
orientation_buffer_->seqlock.WriteBegin();
orientation_buffer_->data.allAvailableSensorsAreActive = false;
orientation_buffer_->seqlock.WriteEnd();
- orientation_buffer_ = NULL;
+ orientation_buffer_ = nullptr;
+ }
+ return true;
+ case CONSUMER_TYPE_LIGHT:
+ if (light_buffer_) {
+ light_buffer_->seqlock.WriteBegin();
+ light_buffer_->data.value = -1;
+ light_buffer_->seqlock.WriteEnd();
+ light_buffer_ = nullptr;
}
return true;
default:
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 c537e032551..6bb79cb6d67 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
@@ -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 "data_fetcher_shared_memory.h"
+#include "content/browser/device_sensors/data_fetcher_shared_memory.h"
#include <GuidDef.h>
#include <InitGuid.h>
@@ -18,6 +18,13 @@ namespace {
const double kMeanGravity = 9.80665;
+void SetLightBuffer(content::DeviceLightHardwareBuffer* buffer, double lux) {
+ DCHECK(buffer);
+ buffer->seqlock.WriteBegin();
+ buffer->data.value = lux;
+ buffer->seqlock.WriteEnd();
+}
+
} // namespace
@@ -27,18 +34,18 @@ class DataFetcherSharedMemory::SensorEventSink
: public ISensorEvents, public base::win::IUnknownImpl {
public:
SensorEventSink() {}
- virtual ~SensorEventSink() {}
+ ~SensorEventSink() override {}
// IUnknown interface
- virtual ULONG STDMETHODCALLTYPE AddRef() override {
+ ULONG STDMETHODCALLTYPE AddRef() override {
return IUnknownImpl::AddRef();
}
- virtual ULONG STDMETHODCALLTYPE Release() override {
+ ULONG STDMETHODCALLTYPE Release() override {
return IUnknownImpl::Release();
}
- virtual STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override {
+ STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override {
if (riid == __uuidof(ISensorEvents)) {
*ppv = static_cast<ISensorEvents*>(this);
AddRef();
@@ -64,12 +71,12 @@ class DataFetcherSharedMemory::SensorEventSink
STDMETHODIMP OnDataUpdated(ISensor* sensor,
ISensorDataReport* new_data) override {
- if (NULL == new_data || NULL == sensor)
+ if (nullptr == new_data || nullptr == sensor)
return E_INVALIDARG;
return UpdateSharedMemoryBuffer(sensor, new_data) ? S_OK : E_FAIL;
}
-protected:
+ protected:
virtual bool UpdateSharedMemoryBuffer(
ISensor* sensor, ISensorDataReport* new_data) = 0;
@@ -98,10 +105,10 @@ class DataFetcherSharedMemory::SensorEventSinkOrientation
public:
explicit SensorEventSinkOrientation(
DeviceOrientationHardwareBuffer* const buffer) : buffer_(buffer) {}
- virtual ~SensorEventSinkOrientation() {}
+ ~SensorEventSinkOrientation() override {}
-protected:
- virtual bool UpdateSharedMemoryBuffer(
+ protected:
+ bool UpdateSharedMemoryBuffer(
ISensor* sensor, ISensorDataReport* new_data) override {
double alpha, beta, gamma;
bool has_alpha, has_beta, has_gamma;
@@ -141,10 +148,10 @@ class DataFetcherSharedMemory::SensorEventSinkMotion
public:
explicit SensorEventSinkMotion(DeviceMotionHardwareBuffer* const buffer)
: buffer_(buffer) {}
- virtual ~SensorEventSinkMotion() {}
+ ~SensorEventSinkMotion() override {}
protected:
- virtual bool UpdateSharedMemoryBuffer(
+ bool UpdateSharedMemoryBuffer(
ISensor* sensor, ISensorDataReport* new_data) override {
SENSOR_TYPE_ID sensor_type = GUID_NULL;
@@ -216,16 +223,47 @@ class DataFetcherSharedMemory::SensorEventSinkMotion
return true;
}
- private:
- DeviceMotionHardwareBuffer* const buffer_;
+ private:
+ DeviceMotionHardwareBuffer* const buffer_;
+
+ DISALLOW_COPY_AND_ASSIGN(SensorEventSinkMotion);
+};
+
+class DataFetcherSharedMemory::SensorEventSinkLight
+ : public DataFetcherSharedMemory::SensorEventSink {
+ public:
+ explicit SensorEventSinkLight(DeviceLightHardwareBuffer* const buffer)
+ : buffer_(buffer) {}
+ ~SensorEventSinkLight() override {}
+
+ protected:
+ bool UpdateSharedMemoryBuffer(ISensor* sensor,
+ ISensorDataReport* new_data) override {
+ double lux;
+ bool has_lux;
+
+ GetSensorValue(SENSOR_DATA_TYPE_LIGHT_LEVEL_LUX, new_data, &lux, &has_lux);
+
+ if(!has_lux) {
+ // Could not get lux value.
+ return false;
+ }
- DISALLOW_COPY_AND_ASSIGN(SensorEventSinkMotion);
- };
+ SetLightBuffer(buffer_, lux);
+ return true;
+ }
+
+ private:
+ DeviceLightHardwareBuffer* const buffer_;
+
+ DISALLOW_COPY_AND_ASSIGN(SensorEventSinkLight);
+};
DataFetcherSharedMemory::DataFetcherSharedMemory()
- : motion_buffer_(NULL),
- orientation_buffer_(NULL) {
+ : motion_buffer_(nullptr),
+ orientation_buffer_(nullptr),
+ light_buffer_(nullptr) {
}
DataFetcherSharedMemory::~DataFetcherSharedMemory() {
@@ -279,6 +317,22 @@ bool DataFetcherSharedMemory::Start(ConsumerType consumer_type, void* buffer) {
SetBufferAvailableState(consumer_type, true);
}
break;
+ case CONSUMER_TYPE_LIGHT:
+ {
+ light_buffer_ = static_cast<DeviceLightHardwareBuffer*>(buffer);
+ scoped_refptr<SensorEventSink> sink(
+ new SensorEventSinkLight(light_buffer_));
+ bool sensor_light_available = RegisterForSensor(
+ SENSOR_TYPE_AMBIENT_LIGHT, sensor_light_.Receive(), sink);
+ if (sensor_light_available) {
+ SetLightBuffer(light_buffer_, -1);
+ return true;
+ }
+
+ // if no sensors are available, fire an Infinity event.
+ SetLightBuffer(light_buffer_, std::numeric_limits<double>::infinity());
+ }
+ break;
default:
NOTREACHED();
}
@@ -287,13 +341,18 @@ bool DataFetcherSharedMemory::Start(ConsumerType consumer_type, void* buffer) {
bool DataFetcherSharedMemory::Stop(ConsumerType consumer_type) {
DisableSensors(consumer_type);
- SetBufferAvailableState(consumer_type, false);
switch (consumer_type) {
case CONSUMER_TYPE_ORIENTATION:
- orientation_buffer_ = NULL;
+ SetBufferAvailableState(consumer_type, false);
+ orientation_buffer_ = nullptr;
return true;
case CONSUMER_TYPE_MOTION:
- motion_buffer_ = NULL;
+ SetBufferAvailableState(consumer_type, false);
+ motion_buffer_ = nullptr;
+ return true;
+ case CONSUMER_TYPE_LIGHT:
+ SetLightBuffer(light_buffer_, -1);
+ light_buffer_ = nullptr;
return true;
default:
NOTREACHED();
@@ -310,14 +369,14 @@ bool DataFetcherSharedMemory::RegisterForSensor(
base::win::ScopedComPtr<ISensorManager> sensor_manager;
HRESULT hr = sensor_manager.CreateInstance(CLSID_SensorManager);
- if (FAILED(hr) || !sensor_manager)
+ if (FAILED(hr) || !sensor_manager.get())
return false;
base::win::ScopedComPtr<ISensorCollection> sensor_collection;
hr = sensor_manager->GetSensorsByType(
sensor_type, sensor_collection.Receive());
- if (FAILED(hr) || !sensor_collection)
+ if (FAILED(hr) || !sensor_collection.get())
return false;
ULONG count = 0;
@@ -342,10 +401,10 @@ bool DataFetcherSharedMemory::RegisterForSensor(
base::win::ScopedComPtr<ISensorEvents> sensor_events;
hr = event_sink->QueryInterface(
__uuidof(ISensorEvents), sensor_events.ReceiveVoid());
- if (FAILED(hr) || !sensor_events)
+ if (FAILED(hr) || !sensor_events.get())
return false;
- hr = (*sensor)->SetEventSink(sensor_events);
+ hr = (*sensor)->SetEventSink(sensor_events.get());
if (FAILED(hr))
return false;
@@ -355,21 +414,27 @@ bool DataFetcherSharedMemory::RegisterForSensor(
void DataFetcherSharedMemory::DisableSensors(ConsumerType consumer_type) {
switch(consumer_type) {
case CONSUMER_TYPE_ORIENTATION:
- if (sensor_inclinometer_) {
- sensor_inclinometer_->SetEventSink(NULL);
+ if (sensor_inclinometer_.get()) {
+ sensor_inclinometer_->SetEventSink(nullptr);
sensor_inclinometer_.Release();
}
break;
case CONSUMER_TYPE_MOTION:
- if (sensor_accelerometer_) {
- sensor_accelerometer_->SetEventSink(NULL);
+ if (sensor_accelerometer_.get()) {
+ sensor_accelerometer_->SetEventSink(nullptr);
sensor_accelerometer_.Release();
}
- if (sensor_gyrometer_) {
- sensor_gyrometer_->SetEventSink(NULL);
+ if (sensor_gyrometer_.get()) {
+ sensor_gyrometer_->SetEventSink(nullptr);
sensor_gyrometer_.Release();
}
break;
+ case CONSUMER_TYPE_LIGHT:
+ if (sensor_light_.get()) {
+ sensor_light_->SetEventSink(nullptr);
+ sensor_light_.Release();
+ }
+ break;
default:
NOTREACHED();
}
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 3380d8a2e74..665b0122708 100644
--- a/chromium/content/browser/device_sensors/device_inertial_sensor_browsertest.cc
+++ b/chromium/content/browser/device_sensors/device_inertial_sensor_browsertest.cc
@@ -178,9 +178,7 @@ class FakeDataFetcher : public DataFetcherSharedMemory {
class DeviceInertialSensorBrowserTest : public ContentBrowserTest {
public:
DeviceInertialSensorBrowserTest()
- : fetcher_(NULL),
- io_loop_finished_event_(false, false) {
- }
+ : fetcher_(nullptr), io_loop_finished_event_(false, false) {}
void SetUpOnMainThread() override {
BrowserThread::PostTask(
@@ -202,9 +200,9 @@ class DeviceInertialSensorBrowserTest : public ContentBrowserTest {
}
void WaitForAlertDialogAndQuitAfterDelay(base::TimeDelta delay) {
- ShellJavaScriptDialogManager* dialog_manager=
+ ShellJavaScriptDialogManager* dialog_manager =
static_cast<ShellJavaScriptDialogManager*>(
- shell()->GetJavaScriptDialogManager());
+ shell()->GetJavaScriptDialogManager(shell()->web_contents()));
scoped_refptr<MessageLoopRunner> runner = new MessageLoopRunner();
dialog_manager->set_dialog_request_callback(
@@ -213,6 +211,13 @@ class DeviceInertialSensorBrowserTest : public ContentBrowserTest {
runner->Run();
}
+ void EnableExperimentalFeatures() {
+ // TODO(riju): remove when the DeviceLight feature goes stable.
+ base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
+ if (!cmd_line->HasSwitch(switches::kEnableExperimentalWebPlatformFeatures))
+ cmd_line->AppendSwitch(switches::kEnableExperimentalWebPlatformFeatures);
+ }
+
FakeDataFetcher* fetcher_;
private:
@@ -235,15 +240,8 @@ 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.
+ EnableExperimentalFeatures();
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());
@@ -263,92 +261,72 @@ 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.
+ LightOneOffInfintyTest) {
+ // The test page registers an event handler for light events and expects
+ // to get an event with value equal to infinity, because no sensor data can
+ // be provided.
+ EnableExperimentalFeatures();
fetcher_->SetSensorDataAvailable(false);
+ GURL test_url = GetTestUrl("device_sensors",
+ "device_light_infinity_test.html");
+ NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 2);
- // 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));
-
+ EXPECT_EQ("pass", shell()->web_contents()->GetLastCommittedURL().ref());
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
-#else
-#define MAYBE_OrientationNullTestWithAlert OrientationNullTestWithAlert
-#endif
-IN_PROC_BROWSER_TEST_F(DeviceInertialSensorBrowserTest,
- MAYBE_OrientationNullTestWithAlert) {
- // The test page will register an event handler for orientation events,
- // expects to get an event with null values. The test raises a modal alert
- // dialog with a delay to test that the one-off null-event still propagates
- // to window after the alert is dismissed and the callback is invoked which
- // navigates to #pass.
+IN_PROC_BROWSER_TEST_F(DeviceInertialSensorBrowserTest, OrientationNullTest) {
+ // The test page registers an event handler for orientation events and
+ // expects to get an event with null values, because no sensor data can be
+ // provided.
fetcher_->SetSensorDataAvailable(false);
- TestNavigationObserver same_tab_observer(shell()->web_contents(), 2);
-
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
- // delay, crbug.com/360044.
- WaitForAlertDialogAndQuitAfterDelay(base::TimeDelta::FromMilliseconds(1000));
+ "device_orientation_null_test.html");
+ NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 2);
+ EXPECT_EQ("pass", shell()->web_contents()->GetLastCommittedURL().ref());
fetcher_->started_orientation_.Wait();
fetcher_->stopped_orientation_.Wait();
- same_tab_observer.Wait();
+}
+
+IN_PROC_BROWSER_TEST_F(DeviceInertialSensorBrowserTest, MotionNullTest) {
+ // The test page registers an event handler for motion events and
+ // expects to get an event with null values, because no sensor data can be
+ // provided.
+ fetcher_->SetSensorDataAvailable(false);
+ GURL test_url = GetTestUrl("device_sensors",
+ "device_motion_null_test.html");
+ NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 2);
+
EXPECT_EQ("pass", shell()->web_contents()->GetLastCommittedURL().ref());
+ fetcher_->started_motion_.Wait();
+ fetcher_->stopped_motion_.Wait();
}
-// Flaking in the android try bot. See http://crbug.com/360578.
-#if defined(OS_ANDROID) || defined(OS_WIN)
-#define MAYBE_MotionNullTestWithAlert DISABLED_MotionNullTestWithAlert
-#else
-#define MAYBE_MotionNullTestWithAlert MotionNullTestWithAlert
-#endif
IN_PROC_BROWSER_TEST_F(DeviceInertialSensorBrowserTest,
- MAYBE_MotionNullTestWithAlert) {
- // The test page will register an event handler for motion events,
- // expects to get an event with null values. The test raises a modal alert
- // dialog with a delay to test that the one-off null-event still propagates
- // to window after the alert is dismissed and the callback is invoked which
- // navigates to #pass.
+ DISABLED_NullTestWithAlert) {
+ // The test page registers an event handlers for motion/orientation events
+ // and expects to get events with null values. The test raises a modal alert
+ // dialog with a delay to test that the one-off null-events still propagate
+ // to window after the alert is dismissed and the callbacks are invoked which
+ // eventually navigate to #pass.
fetcher_->SetSensorDataAvailable(false);
TestNavigationObserver same_tab_observer(shell()->web_contents(), 2);
- GURL test_url =
- GetTestUrl("device_sensors", "device_motion_null_test_with_alert.html");
+ GURL test_url = GetTestUrl("device_sensors",
+ "device_sensors_null_test_with_alert.html");
shell()->LoadURL(test_url);
// TODO(timvolodine): investigate if it is possible to test this without
// delay, crbug.com/360044.
- WaitForAlertDialogAndQuitAfterDelay(base::TimeDelta::FromMilliseconds(1000));
+ WaitForAlertDialogAndQuitAfterDelay(base::TimeDelta::FromMilliseconds(500));
fetcher_->started_motion_.Wait();
fetcher_->stopped_motion_.Wait();
+ fetcher_->started_orientation_.Wait();
+ fetcher_->stopped_orientation_.Wait();
same_tab_observer.Wait();
EXPECT_EQ("pass", shell()->web_contents()->GetLastCommittedURL().ref());
}
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 840ce254bc1..37952475532 100644
--- a/chromium/content/browser/device_sensors/device_inertial_sensor_service.cc
+++ b/chromium/content/browser/device_sensors/device_inertial_sensor_service.cc
@@ -94,7 +94,7 @@ DeviceInertialSensorService::GetSharedMemoryHandleForProcess(
void DeviceInertialSensorService::Shutdown() {
if (data_fetcher_) {
- data_fetcher_->StopFetchingAllDeviceData();
+ data_fetcher_->Shutdown();
data_fetcher_.reset();
}
is_shutdown_ = true;
@@ -103,7 +103,7 @@ void DeviceInertialSensorService::Shutdown() {
void DeviceInertialSensorService::SetDataFetcherForTesting(
DataFetcherSharedMemory* test_data_fetcher) {
if (data_fetcher_)
- data_fetcher_->StopFetchingAllDeviceData();
+ data_fetcher_->Shutdown();
data_fetcher_.reset(test_data_fetcher);
}
diff --git a/chromium/content/browser/device_sensors/device_light_message_filter.cc b/chromium/content/browser/device_sensors/device_light_message_filter.cc
index 751b6f11ce3..797b3eade2c 100644
--- a/chromium/content/browser/device_sensors/device_light_message_filter.cc
+++ b/chromium/content/browser/device_sensors/device_light_message_filter.cc
@@ -14,7 +14,7 @@ DeviceLightMessageFilter::DeviceLightMessageFilter()
}
DeviceLightMessageFilter::~DeviceLightMessageFilter() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (is_started_) {
DeviceInertialSensorService::GetInstance()->RemoveConsumer(
CONSUMER_TYPE_LIGHT);
diff --git a/chromium/content/browser/device_sensors/device_motion_message_filter.cc b/chromium/content/browser/device_sensors/device_motion_message_filter.cc
index 2994c383f15..f874ea493a4 100644
--- a/chromium/content/browser/device_sensors/device_motion_message_filter.cc
+++ b/chromium/content/browser/device_sensors/device_motion_message_filter.cc
@@ -15,7 +15,7 @@ DeviceMotionMessageFilter::DeviceMotionMessageFilter()
}
DeviceMotionMessageFilter::~DeviceMotionMessageFilter() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (is_started_)
DeviceInertialSensorService::GetInstance()->RemoveConsumer(
CONSUMER_TYPE_MOTION);
diff --git a/chromium/content/browser/device_sensors/device_orientation_message_filter.cc b/chromium/content/browser/device_sensors/device_orientation_message_filter.cc
index 402aa67a40f..63a9d6230f4 100644
--- a/chromium/content/browser/device_sensors/device_orientation_message_filter.cc
+++ b/chromium/content/browser/device_sensors/device_orientation_message_filter.cc
@@ -15,7 +15,7 @@ DeviceOrientationMessageFilter::DeviceOrientationMessageFilter()
}
DeviceOrientationMessageFilter::~DeviceOrientationMessageFilter() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (is_started_)
DeviceInertialSensorService::GetInstance()->RemoveConsumer(
CONSUMER_TYPE_ORIENTATION);
diff --git a/chromium/content/browser/device_sensors/sensor_manager_android.cc b/chromium/content/browser/device_sensors/sensor_manager_android.cc
index 11de85ae68c..f63e45a91ff 100644
--- a/chromium/content/browser/device_sensors/sensor_manager_android.cc
+++ b/chromium/content/browser/device_sensors/sensor_manager_android.cc
@@ -7,32 +7,44 @@
#include <string.h>
#include "base/android/jni_android.h"
+#include "base/bind.h"
#include "base/memory/singleton.h"
#include "base/metrics/histogram.h"
#include "content/browser/device_sensors/inertial_sensor_consts.h"
+#include "content/public/browser/browser_thread.h"
#include "jni/DeviceSensors_jni.h"
using base::android::AttachCurrentThread;
namespace {
-static void updateRotationVectorHistogram(bool value) {
- UMA_HISTOGRAM_BOOLEAN("InertialSensor.RotationVectorAndroidAvailable", value);
+enum OrientationSensorType {
+ NOT_AVAILABLE = 0,
+ ROTATION_VECTOR = 1,
+ ACCELEROMETER_MAGNETIC = 2,
+ ORIENTATION_SENSOR_MAX = 3,
+};
+
+void UpdateDeviceOrientationHistogram(OrientationSensorType type) {
+ UMA_HISTOGRAM_ENUMERATION("InertialSensor.DeviceOrientationSensorAndroid",
+ type,
+ ORIENTATION_SENSOR_MAX);
}
-}
+} // namespace
namespace content {
SensorManagerAndroid::SensorManagerAndroid()
: number_active_device_motion_sensors_(0),
- device_light_buffer_(NULL),
- device_motion_buffer_(NULL),
- device_orientation_buffer_(NULL),
+ device_light_buffer_(nullptr),
+ device_motion_buffer_(nullptr),
+ device_orientation_buffer_(nullptr),
is_light_buffer_ready_(false),
is_motion_buffer_ready_(false),
is_orientation_buffer_ready_(false),
- is_using_backup_sensors_for_orientation_(false) {
+ is_using_backup_sensors_for_orientation_(false),
+ is_shutdown_(false) {
memset(received_motion_data_, 0, sizeof(received_motion_data_));
device_sensors_.Reset(Java_DeviceSensors_getInstance(
AttachCurrentThread(), base::android::GetApplicationContext()));
@@ -68,7 +80,8 @@ void SensorManagerAndroid::GotOrientation(
if (!is_orientation_buffer_ready_) {
SetOrientationBufferReadyStatus(true);
- updateRotationVectorHistogram(!is_using_backup_sensors_for_orientation_);
+ UpdateDeviceOrientationHistogram(is_using_backup_sensors_for_orientation_
+ ? ACCELEROMETER_MAGNETIC : ROTATION_VECTOR);
}
}
@@ -186,7 +199,25 @@ bool SensorManagerAndroid::isUsingBackupSensorsForOrientation() {
bool SensorManagerAndroid::StartFetchingDeviceLightData(
DeviceLightHardwareBuffer* buffer) {
+ if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ StartFetchingLightDataOnUI(buffer);
+ } else {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&SensorManagerAndroid::StartFetchingLightDataOnUI,
+ base::Unretained(this),
+ buffer));
+ }
+ return true;
+}
+
+void SensorManagerAndroid::StartFetchingLightDataOnUI(
+ DeviceLightHardwareBuffer* buffer) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(buffer);
+ if (is_shutdown_)
+ return;
+
{
base::AutoLock autolock(light_buffer_lock_);
device_light_buffer_ = buffer;
@@ -197,16 +228,31 @@ bool SensorManagerAndroid::StartFetchingDeviceLightData(
base::AutoLock autolock(light_buffer_lock_);
SetLightBufferValue(std::numeric_limits<double>::infinity());
}
- return success;
}
void SensorManagerAndroid::StopFetchingDeviceLightData() {
+ if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ StopFetchingLightDataOnUI();
+ return;
+ }
+
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&SensorManagerAndroid::StopFetchingLightDataOnUI,
+ base::Unretained(this)));
+}
+
+void SensorManagerAndroid::StopFetchingLightDataOnUI() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (is_shutdown_)
+ return;
+
Stop(kTypeLight);
{
base::AutoLock autolock(light_buffer_lock_);
if (device_light_buffer_) {
SetLightBufferValue(-1);
- device_light_buffer_ = NULL;
+ device_light_buffer_ = nullptr;
}
}
}
@@ -216,17 +262,36 @@ void SensorManagerAndroid::SetLightBufferValue(double lux) {
device_light_buffer_->data.value = lux;
device_light_buffer_->seqlock.WriteEnd();
}
+
// --- Device Motion
bool SensorManagerAndroid::StartFetchingDeviceMotionData(
DeviceMotionHardwareBuffer* buffer) {
+ if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ StartFetchingMotionDataOnUI(buffer);
+ } else {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&SensorManagerAndroid::StartFetchingMotionDataOnUI,
+ base::Unretained(this),
+ buffer));
+ }
+ return true;
+}
+
+void SensorManagerAndroid::StartFetchingMotionDataOnUI(
+ DeviceMotionHardwareBuffer* buffer) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(buffer);
+ if (is_shutdown_)
+ return;
+
{
base::AutoLock autolock(motion_buffer_lock_);
device_motion_buffer_ = buffer;
ClearInternalMotionBuffers();
}
- bool success = Start(kTypeMotion);
+ Start(kTypeMotion);
// If no motion data can ever be provided, the number of active device motion
// sensors will be zero. In that case flag the shared memory buffer
@@ -236,16 +301,31 @@ bool SensorManagerAndroid::StartFetchingDeviceMotionData(
base::AutoLock autolock(motion_buffer_lock_);
CheckMotionBufferReadyToRead();
}
- return success;
}
void SensorManagerAndroid::StopFetchingDeviceMotionData() {
+ if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ StopFetchingMotionDataOnUI();
+ return;
+ }
+
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&SensorManagerAndroid::StopFetchingMotionDataOnUI,
+ base::Unretained(this)));
+}
+
+void SensorManagerAndroid::StopFetchingMotionDataOnUI() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (is_shutdown_)
+ return;
+
Stop(kTypeMotion);
{
base::AutoLock autolock(motion_buffer_lock_);
if (device_motion_buffer_) {
ClearInternalMotionBuffers();
- device_motion_buffer_ = NULL;
+ device_motion_buffer_ = nullptr;
}
}
}
@@ -298,7 +378,25 @@ void SensorManagerAndroid::SetOrientationBufferReadyStatus(bool ready) {
bool SensorManagerAndroid::StartFetchingDeviceOrientationData(
DeviceOrientationHardwareBuffer* buffer) {
+ if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ StartFetchingOrientationDataOnUI(buffer);
+ } else {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&SensorManagerAndroid::StartFetchingOrientationDataOnUI,
+ base::Unretained(this),
+ buffer));
+ }
+ return true;
+}
+
+void SensorManagerAndroid::StartFetchingOrientationDataOnUI(
+ DeviceOrientationHardwareBuffer* buffer) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(buffer);
+ if (is_shutdown_)
+ return;
+
{
base::AutoLock autolock(orientation_buffer_lock_);
device_orientation_buffer_ = buffer;
@@ -312,24 +410,44 @@ bool SensorManagerAndroid::StartFetchingDeviceOrientationData(
SetOrientationBufferReadyStatus(!success);
}
- if (!success)
- updateRotationVectorHistogram(false);
- else
+ if (!success) {
+ UpdateDeviceOrientationHistogram(NOT_AVAILABLE);
+ } else {
is_using_backup_sensors_for_orientation_ =
isUsingBackupSensorsForOrientation();
-
- return success;
+ }
}
void SensorManagerAndroid::StopFetchingDeviceOrientationData() {
+ if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ StopFetchingOrientationDataOnUI();
+ return;
+ }
+
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&SensorManagerAndroid::StopFetchingOrientationDataOnUI,
+ base::Unretained(this)));
+}
+
+void SensorManagerAndroid::StopFetchingOrientationDataOnUI() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (is_shutdown_)
+ return;
+
Stop(kTypeOrientation);
{
base::AutoLock autolock(orientation_buffer_lock_);
if (device_orientation_buffer_) {
SetOrientationBufferReadyStatus(false);
- device_orientation_buffer_ = NULL;
+ device_orientation_buffer_ = nullptr;
}
}
}
+void SensorManagerAndroid::Shutdown() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ is_shutdown_ = true;
+}
+
} // namespace content
diff --git a/chromium/content/browser/device_sensors/sensor_manager_android.h b/chromium/content/browser/device_sensors/sensor_manager_android.h
index 714b8ec0416..535efa1c1c9 100644
--- a/chromium/content/browser/device_sensors/sensor_manager_android.h
+++ b/chromium/content/browser/device_sensors/sensor_manager_android.h
@@ -52,6 +52,8 @@ class CONTENT_EXPORT SensorManagerAndroid {
DeviceOrientationHardwareBuffer* buffer);
void StopFetchingDeviceOrientationData();
+ void Shutdown();
+
protected:
enum EventType {
// These constants should match DEVICE_ORIENTATION, DEVICE_MOTION and
@@ -69,6 +71,16 @@ class CONTENT_EXPORT SensorManagerAndroid {
virtual void Stop(EventType event_type);
virtual int GetNumberActiveDeviceMotionSensors();
+ void StartFetchingLightDataOnUI(DeviceLightHardwareBuffer* buffer);
+ void StopFetchingLightDataOnUI();
+
+ void StartFetchingMotionDataOnUI(DeviceMotionHardwareBuffer* buffer);
+ void StopFetchingMotionDataOnUI();
+
+ void StartFetchingOrientationDataOnUI(
+ DeviceOrientationHardwareBuffer* buffer);
+ void StopFetchingOrientationDataOnUI();
+
private:
friend struct DefaultSingletonTraits<SensorManagerAndroid>;
@@ -104,6 +116,7 @@ class CONTENT_EXPORT SensorManagerAndroid {
base::Lock orientation_buffer_lock_;
bool is_using_backup_sensors_for_orientation_;
+ bool is_shutdown_;
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 b5f0c5fb933..39f86e1d17f 100644
--- a/chromium/content/browser/device_sensors/sensor_manager_android_unittest.cc
+++ b/chromium/content/browser/device_sensors/sensor_manager_android_unittest.cc
@@ -8,6 +8,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "content/browser/device_sensors/inertial_sensor_consts.h"
+#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
@@ -16,10 +17,10 @@ namespace {
class FakeSensorManagerAndroid : public SensorManagerAndroid {
public:
- FakeSensorManagerAndroid() { }
- virtual ~FakeSensorManagerAndroid() { }
+ FakeSensorManagerAndroid() {}
+ ~FakeSensorManagerAndroid() override {}
- virtual int GetNumberActiveDeviceMotionSensors() override {
+ int GetNumberActiveDeviceMotionSensors() override {
return number_active_sensors_;
}
@@ -28,12 +29,8 @@ class FakeSensorManagerAndroid : public SensorManagerAndroid {
}
protected:
- virtual bool Start(EventType event_type) override {
- return true;
- }
-
- virtual void Stop(EventType event_type) override {
- }
+ bool Start(EventType event_type) override { return true; }
+ void Stop(EventType event_type) override {}
private:
int number_active_sensors_;
@@ -50,6 +47,7 @@ class AndroidSensorManagerTest : public testing::Test {
scoped_ptr<DeviceLightHardwareBuffer> light_buffer_;
scoped_ptr<DeviceMotionHardwareBuffer> motion_buffer_;
scoped_ptr<DeviceOrientationHardwareBuffer> orientation_buffer_;
+ content::TestBrowserThreadBundle thread_bundle_;
};
TEST_F(AndroidSensorManagerTest, ThreeDeviceMotionSensorsActive) {
diff --git a/chromium/content/browser/device_sensors/sensor_manager_chromeos.cc b/chromium/content/browser/device_sensors/sensor_manager_chromeos.cc
new file mode 100644
index 00000000000..36bdadd81fe
--- /dev/null
+++ b/chromium/content/browser/device_sensors/sensor_manager_chromeos.cc
@@ -0,0 +1,173 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/device_sensors/sensor_manager_chromeos.h"
+
+#include <math.h>
+
+#include "chromeos/accelerometer/accelerometer_reader.h"
+#include "chromeos/accelerometer/accelerometer_types.h"
+#include "content/browser/device_sensors/inertial_sensor_consts.h"
+#include "ui/gfx/geometry/vector3d_f.h"
+
+namespace {
+// Conversion ratio from radians to degrees.
+const double kRad2deg = 180.0 / M_PI;
+}
+
+namespace content {
+
+SensorManagerChromeOS::SensorManagerChromeOS()
+ : motion_buffer_(nullptr), orientation_buffer_(nullptr) {
+}
+
+SensorManagerChromeOS::~SensorManagerChromeOS() {
+}
+
+void SensorManagerChromeOS::StartFetchingDeviceMotionData(
+ DeviceMotionHardwareBuffer* buffer) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(!motion_buffer_);
+ motion_buffer_ = buffer;
+
+ motion_buffer_->seqlock.WriteBegin();
+ // The interval between updates is the longer of the rate set on the buffer,
+ // and the rate at which AccelerometerReader polls the sensor.
+ motion_buffer_->data.interval =
+ std::max(kInertialSensorIntervalMicroseconds / 1000,
+ chromeos::AccelerometerReader::kDelayBetweenReadsMs);
+ motion_buffer_->seqlock.WriteEnd();
+
+ if (!orientation_buffer_)
+ StartObservingAccelerometer();
+}
+
+bool SensorManagerChromeOS::StopFetchingDeviceMotionData() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (!motion_buffer_)
+ return false;
+
+ // Make sure to indicate that the sensor data is no longer available.
+ motion_buffer_->seqlock.WriteBegin();
+ motion_buffer_->data.allAvailableSensorsAreActive = false;
+ motion_buffer_->seqlock.WriteEnd();
+
+ motion_buffer_ = nullptr;
+
+ if (!orientation_buffer_)
+ StopObservingAccelerometer();
+ return true;
+}
+
+void SensorManagerChromeOS::StartFetchingDeviceOrientationData(
+ DeviceOrientationHardwareBuffer* buffer) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(!orientation_buffer_);
+ orientation_buffer_ = buffer;
+
+ // No compass information, so we cannot provide absolute orientation.
+ orientation_buffer_->seqlock.WriteBegin();
+ orientation_buffer_->data.absolute = false;
+ orientation_buffer_->data.hasAbsolute = true;
+ orientation_buffer_->seqlock.WriteEnd();
+
+ if (!motion_buffer_)
+ StartObservingAccelerometer();
+}
+
+bool SensorManagerChromeOS::StopFetchingDeviceOrientationData() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (!orientation_buffer_)
+ return false;
+ // Make sure to indicate that the sensor data is no longer available.
+ orientation_buffer_->seqlock.WriteBegin();
+ orientation_buffer_->data.allAvailableSensorsAreActive = false;
+ orientation_buffer_->seqlock.WriteEnd();
+ orientation_buffer_ = nullptr;
+
+ if (!motion_buffer_)
+ StopObservingAccelerometer();
+ return true;
+}
+
+void SensorManagerChromeOS::OnAccelerometerUpdated(
+ scoped_refptr<const chromeos::AccelerometerUpdate> update) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ chromeos::AccelerometerSource source;
+ if (update->has(chromeos::ACCELEROMETER_SOURCE_SCREEN))
+ source = chromeos::ACCELEROMETER_SOURCE_SCREEN;
+ else if (update->has(chromeos::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD))
+ source = chromeos::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD;
+ else
+ return;
+
+ double x = update->get(source).x;
+ double y = update->get(source).y;
+ double z = update->get(source).z;
+
+ GenerateMotionEvent(x, y, z);
+ GenerateOrientationEvent(x, y, z);
+}
+
+void SensorManagerChromeOS::StartObservingAccelerometer() {
+ chromeos::AccelerometerReader::GetInstance()->AddObserver(this);
+}
+
+void SensorManagerChromeOS::StopObservingAccelerometer() {
+ chromeos::AccelerometerReader::GetInstance()->RemoveObserver(this);
+}
+
+void SensorManagerChromeOS::GenerateMotionEvent(double x, double y, double z) {
+ if (!motion_buffer_)
+ return;
+
+ motion_buffer_->seqlock.WriteBegin();
+ motion_buffer_->data.accelerationIncludingGravityX = x;
+ motion_buffer_->data.hasAccelerationIncludingGravityX = true;
+ motion_buffer_->data.accelerationIncludingGravityY = y;
+ motion_buffer_->data.hasAccelerationIncludingGravityY = true;
+ motion_buffer_->data.accelerationIncludingGravityZ = z;
+ motion_buffer_->data.hasAccelerationIncludingGravityZ = true;
+ motion_buffer_->data.allAvailableSensorsAreActive = true;
+ motion_buffer_->seqlock.WriteEnd();
+}
+
+void SensorManagerChromeOS::GenerateOrientationEvent(double x,
+ double y,
+ double z) {
+ if (!orientation_buffer_)
+ return;
+
+ // Create a unit vector for trigonometry
+ // TODO(jonross): Stop reversing signs for vector components once
+ // accelerometer values have been fixed. crbug.com/431391
+ // Ternaries are to remove -0.0f which gives incorrect trigonometrical
+ // results.
+ gfx::Vector3dF data(x, y ? -y : 0.0f, z ? -z : 0.0f);
+ data.Scale(1.0f / data.Length());
+
+ // Transform accelerometer to W3C angles, using the Z-X-Y Eulerangles matrix.
+ // x = sin(gamma)
+ // y = -cos(gamma) * sin(beta)
+ // z = cos(beta) * cos(gamma)
+ // With only accelerometer alpha cannot be provided.
+ double beta = kRad2deg * atan2(data.y(), data.z());
+ double gamma = kRad2deg * asin(data.x());
+
+ // Convert beta and gamma to fit the intervals in the specification. Beta is
+ // [-180, 180) and gamma is [-90, 90).
+ if (beta >= 180.0f)
+ beta = -180.0f;
+ if (gamma >= 90.0f)
+ gamma = -90.0f;
+ orientation_buffer_->seqlock.WriteBegin();
+ orientation_buffer_->data.beta = beta;
+ orientation_buffer_->data.hasBeta = true;
+ orientation_buffer_->data.gamma = gamma;
+ orientation_buffer_->data.hasGamma = true;
+ orientation_buffer_->data.allAvailableSensorsAreActive = true;
+ orientation_buffer_->seqlock.WriteEnd();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/device_sensors/sensor_manager_chromeos.h b/chromium/content/browser/device_sensors/sensor_manager_chromeos.h
new file mode 100644
index 00000000000..74c4acecbc7
--- /dev/null
+++ b/chromium/content/browser/device_sensors/sensor_manager_chromeos.h
@@ -0,0 +1,69 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_DEVICE_SENSORS_SENSOR_MANAGER_CHROMEOS_H_
+#define CONTENT_BROWSER_DEVICE_SENSORS_SENSOR_MANAGER_CHROMEOS_H_
+
+#include "base/macros.h"
+#include "base/threading/thread_checker.h"
+#include "chromeos/accelerometer/accelerometer_reader.h"
+#include "chromeos/accelerometer/accelerometer_types.h"
+#include "content/common/content_export.h"
+#include "content/common/device_sensors/device_motion_hardware_buffer.h"
+#include "content/common/device_sensors/device_orientation_hardware_buffer.h"
+
+namespace content {
+
+// Observes Chrome OS accelerometer sensors, and provides updated device
+// orientation information.
+class CONTENT_EXPORT SensorManagerChromeOS
+ : public chromeos::AccelerometerReader::Observer {
+ public:
+ SensorManagerChromeOS();
+ ~SensorManagerChromeOS() override;
+
+ // Begins monitoring of motion events, the shared memory of |buffer| will be
+ // updated upon subsequent events.
+ void StartFetchingDeviceMotionData(DeviceMotionHardwareBuffer* buffer);
+
+ // Stops monitoring motion events. Returns true if there is an active
+ // |motion_buffer_| and fetching stops. Otherwise returns false.
+ bool StopFetchingDeviceMotionData();
+
+ // Begins monitoring of orientation events, the shared memory of |buffer| will
+ // be updated upon subsequent events.
+ void StartFetchingDeviceOrientationData(
+ DeviceOrientationHardwareBuffer* buffer);
+
+ // Stops monitoring orientation events. Returns true if there is an active
+ // |orientation_buffer_| and fetching stops. Otherwise returns false.
+ bool StopFetchingDeviceOrientationData();
+
+ // chromeos::AccelerometerReader::Observer:
+ void OnAccelerometerUpdated(
+ scoped_refptr<const chromeos::AccelerometerUpdate> update) override;
+
+ protected:
+ // Begins/ends the observation of accelerometer events.
+ virtual void StartObservingAccelerometer();
+ virtual void StopObservingAccelerometer();
+
+ private:
+ // Updates |motion_buffer_| or |orientation_buffer_| accordingly.
+ void GenerateMotionEvent(double x, double y, double z);
+ void GenerateOrientationEvent(double x, double y, double z);
+
+ // Shared memory to update.
+ DeviceMotionHardwareBuffer* motion_buffer_;
+ DeviceOrientationHardwareBuffer* orientation_buffer_;
+
+ // Verify all work is done on the same thread.
+ base::ThreadChecker thread_checker_;
+
+ DISALLOW_COPY_AND_ASSIGN(SensorManagerChromeOS);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_DEVICE_SENSORS_SENSOR_MANAGER_CHROMEOS_H_
diff --git a/chromium/content/browser/device_sensors/sensor_manager_chromeos_unittest.cc b/chromium/content/browser/device_sensors/sensor_manager_chromeos_unittest.cc
new file mode 100644
index 00000000000..610a47682d9
--- /dev/null
+++ b/chromium/content/browser/device_sensors/sensor_manager_chromeos_unittest.cc
@@ -0,0 +1,228 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/device_sensors/sensor_manager_chromeos.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "chromeos/accelerometer/accelerometer_types.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"
+
+namespace {
+
+const double kMeanGravity = 9.80665;
+
+// Isolated content::SensorManagerChromeOS from the active
+// chromeos::AccelerometerReader. This allows for direct control over which
+// accelerometer events are provided to the sensor manager.
+class TestSensorManagerChromeOS : public content::SensorManagerChromeOS {
+ public:
+ TestSensorManagerChromeOS() {}
+ ~TestSensorManagerChromeOS() override {};
+
+ protected:
+ void StartObservingAccelerometer() override {}
+ void StopObservingAccelerometer() override {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestSensorManagerChromeOS);
+};
+
+} // namespace
+
+namespace content {
+
+class SensorManagerChromeOSTest : public testing::Test {
+ public:
+ SensorManagerChromeOSTest() {
+ motion_buffer_.reset(new DeviceMotionHardwareBuffer);
+ orientation_buffer_.reset(new DeviceOrientationHardwareBuffer);
+ }
+
+ ~SensorManagerChromeOSTest() override {}
+
+ void OnAccelerationIncludingGravity(double x, double y, double z) {
+ scoped_refptr<chromeos::AccelerometerUpdate> update(
+ new chromeos::AccelerometerUpdate());
+ update->Set(chromeos::ACCELEROMETER_SOURCE_SCREEN, x, y, z);
+ sensor_manager_->OnAccelerometerUpdated(update);
+ }
+
+ DeviceMotionHardwareBuffer* motion_buffer() { return motion_buffer_.get(); }
+
+ DeviceOrientationHardwareBuffer* orientation_buffer() {
+ return orientation_buffer_.get();
+ }
+
+ SensorManagerChromeOS* sensor_manager() { return sensor_manager_.get(); }
+
+ // testing::Test:
+ void SetUp() override {
+ testing::Test::SetUp();
+ sensor_manager_.reset(new TestSensorManagerChromeOS);
+ sensor_manager_->StartFetchingDeviceMotionData(motion_buffer_.get());
+ sensor_manager_->StartFetchingDeviceOrientationData(
+ orientation_buffer_.get());
+ }
+
+ void TearDown() override {
+ sensor_manager_->StopFetchingDeviceMotionData();
+ sensor_manager_->StopFetchingDeviceOrientationData();
+ testing::Test::TearDown();
+ }
+
+ private:
+ scoped_ptr<TestSensorManagerChromeOS> sensor_manager_;
+ scoped_ptr<DeviceMotionHardwareBuffer> motion_buffer_;
+ scoped_ptr<DeviceOrientationHardwareBuffer> orientation_buffer_;
+
+ DISALLOW_COPY_AND_ASSIGN(SensorManagerChromeOSTest);
+};
+
+// Tests that starting to process motion data will update the associated buffer.
+TEST_F(SensorManagerChromeOSTest, MotionBuffer) {
+ DeviceMotionHardwareBuffer* buffer = motion_buffer();
+ EXPECT_FLOAT_EQ(100.0f, buffer->data.interval);
+ EXPECT_FALSE(buffer->data.hasAccelerationIncludingGravityX);
+ EXPECT_FALSE(buffer->data.hasAccelerationIncludingGravityY);
+ EXPECT_FALSE(buffer->data.hasAccelerationIncludingGravityZ);
+ EXPECT_FALSE(buffer->data.hasAccelerationX);
+ EXPECT_FALSE(buffer->data.hasAccelerationY);
+ EXPECT_FALSE(buffer->data.hasAccelerationZ);
+ EXPECT_FALSE(buffer->data.hasRotationRateAlpha);
+ EXPECT_FALSE(buffer->data.hasRotationRateBeta);
+ EXPECT_FALSE(buffer->data.hasRotationRateGamma);
+
+ OnAccelerationIncludingGravity(0.0f, 0.0f, 1.0f);
+ EXPECT_TRUE(buffer->data.hasAccelerationIncludingGravityX);
+ EXPECT_TRUE(buffer->data.hasAccelerationIncludingGravityY);
+ EXPECT_TRUE(buffer->data.hasAccelerationIncludingGravityZ);
+ EXPECT_FALSE(buffer->data.hasAccelerationX);
+ EXPECT_FALSE(buffer->data.hasAccelerationY);
+ EXPECT_FALSE(buffer->data.hasAccelerationZ);
+ EXPECT_FALSE(buffer->data.hasRotationRateAlpha);
+ EXPECT_FALSE(buffer->data.hasRotationRateBeta);
+ EXPECT_FALSE(buffer->data.hasRotationRateGamma);
+ EXPECT_TRUE(buffer->data.allAvailableSensorsAreActive);
+
+ sensor_manager()->StopFetchingDeviceMotionData();
+ EXPECT_FALSE(buffer->data.allAvailableSensorsAreActive);
+}
+
+// Tests that starting to process orientation data will update the associated
+// buffer.
+TEST_F(SensorManagerChromeOSTest, OrientationBuffer) {
+ DeviceOrientationHardwareBuffer* buffer = orientation_buffer();
+ EXPECT_TRUE(buffer->data.hasAbsolute);
+ EXPECT_FALSE(buffer->data.hasAlpha);
+ EXPECT_FALSE(buffer->data.hasBeta);
+ EXPECT_FALSE(buffer->data.hasGamma);
+ EXPECT_FALSE(buffer->data.allAvailableSensorsAreActive);
+
+ OnAccelerationIncludingGravity(0.0f, 0.0f, 1.0f);
+ EXPECT_FLOAT_EQ(0.0f, buffer->data.alpha);
+ EXPECT_FALSE(buffer->data.hasAlpha);
+ EXPECT_TRUE(buffer->data.hasBeta);
+ EXPECT_TRUE(buffer->data.hasGamma);
+ EXPECT_TRUE(buffer->data.allAvailableSensorsAreActive);
+
+ sensor_manager()->StopFetchingDeviceOrientationData();
+ EXPECT_FALSE(buffer->data.allAvailableSensorsAreActive);
+}
+
+// Tests a device resting flat.
+TEST_F(SensorManagerChromeOSTest, NeutralOrientation) {
+ OnAccelerationIncludingGravity(0.0f, 0.0f, -kMeanGravity);
+
+ DeviceMotionHardwareBuffer* motion = motion_buffer();
+ EXPECT_FLOAT_EQ(0.0f, motion->data.accelerationIncludingGravityX);
+ EXPECT_FLOAT_EQ(0.0f, motion->data.accelerationIncludingGravityY);
+ EXPECT_FLOAT_EQ(-kMeanGravity, motion->data.accelerationIncludingGravityZ);
+
+ DeviceOrientationHardwareBuffer* orientation = orientation_buffer();
+ EXPECT_FLOAT_EQ(0.0f, orientation->data.beta);
+ EXPECT_FLOAT_EQ(0.0f, orientation->data.gamma);
+}
+
+// Tests an upside-down device, such that the W3C boundary [-180,180) causes the
+// beta value to become negative.
+TEST_F(SensorManagerChromeOSTest, UpsideDown) {
+ OnAccelerationIncludingGravity(0.0f, 0.0f, kMeanGravity);
+
+ DeviceMotionHardwareBuffer* motion = motion_buffer();
+ EXPECT_FLOAT_EQ(0.0f, motion->data.accelerationIncludingGravityX);
+ EXPECT_FLOAT_EQ(0.0f, motion->data.accelerationIncludingGravityY);
+ EXPECT_FLOAT_EQ(kMeanGravity, motion->data.accelerationIncludingGravityZ);
+
+ DeviceOrientationHardwareBuffer* orientation = orientation_buffer();
+ EXPECT_FLOAT_EQ(-180.0f, orientation->data.beta);
+ EXPECT_FLOAT_EQ(0.0f, orientation->data.gamma);
+}
+
+// Tests for positive beta value before the device is completely upside-down
+TEST_F(SensorManagerChromeOSTest, BeforeUpsideDownBoundary) {
+ OnAccelerationIncludingGravity(0.0f, -kMeanGravity / 2.0f,
+ kMeanGravity / 2.0f);
+
+ DeviceMotionHardwareBuffer* motion = motion_buffer();
+ EXPECT_FLOAT_EQ(0.0f, motion->data.accelerationIncludingGravityX);
+ EXPECT_FLOAT_EQ(-kMeanGravity / 2.0f,
+ motion->data.accelerationIncludingGravityY);
+ EXPECT_FLOAT_EQ(kMeanGravity / 2.0f,
+ motion->data.accelerationIncludingGravityZ);
+
+ DeviceOrientationHardwareBuffer* orientation = orientation_buffer();
+ EXPECT_FLOAT_EQ(135.0f, orientation->data.beta);
+ EXPECT_FLOAT_EQ(0.0f, orientation->data.gamma);
+}
+
+// Tests a device lying on its left-edge.
+TEST_F(SensorManagerChromeOSTest, LeftEdge) {
+ OnAccelerationIncludingGravity(-kMeanGravity, 0.0f, 0.0f);
+
+ DeviceMotionHardwareBuffer* motion = motion_buffer();
+ EXPECT_FLOAT_EQ(-kMeanGravity, motion->data.accelerationIncludingGravityX);
+ EXPECT_FLOAT_EQ(0.0f, motion->data.accelerationIncludingGravityY);
+ EXPECT_FLOAT_EQ(0.0f, motion->data.accelerationIncludingGravityZ);
+
+ DeviceOrientationHardwareBuffer* orientation = orientation_buffer();
+ EXPECT_FLOAT_EQ(0.0f, orientation->data.beta);
+ EXPECT_FLOAT_EQ(-90.0f, orientation->data.gamma);
+}
+
+// Tests a device lying on its right-edge, such that the W3C boundary [-90,90)
+// causes the gamma value to become negative.
+TEST_F(SensorManagerChromeOSTest, RightEdge) {
+ OnAccelerationIncludingGravity(kMeanGravity, 0.0f, 0.0f);
+
+ DeviceMotionHardwareBuffer* motion = motion_buffer();
+ EXPECT_FLOAT_EQ(kMeanGravity, motion->data.accelerationIncludingGravityX);
+ EXPECT_FLOAT_EQ(0.0f, motion->data.accelerationIncludingGravityY);
+ EXPECT_FLOAT_EQ(0.0f, motion->data.accelerationIncludingGravityZ);
+
+ DeviceOrientationHardwareBuffer* orientation = orientation_buffer();
+ EXPECT_FLOAT_EQ(0.0f, orientation->data.beta);
+ EXPECT_FLOAT_EQ(-90.0f, orientation->data.gamma);
+}
+
+// Tests for positive gamma value before the device is completely on its right
+// side.
+TEST_F(SensorManagerChromeOSTest, BeforeRightEdgeBoundary) {
+ OnAccelerationIncludingGravity(kMeanGravity / 2.0f, 0.0f,
+ -kMeanGravity / 2.0f);
+
+ DeviceMotionHardwareBuffer* motion = motion_buffer();
+ EXPECT_FLOAT_EQ(kMeanGravity / 2.0f,
+ motion->data.accelerationIncludingGravityX);
+ EXPECT_FLOAT_EQ(0.0f, motion->data.accelerationIncludingGravityY);
+ EXPECT_FLOAT_EQ(-kMeanGravity / 2.0f,
+ motion->data.accelerationIncludingGravityZ);
+
+ DeviceOrientationHardwareBuffer* orientation = orientation_buffer();
+ EXPECT_FLOAT_EQ(0.0f, orientation->data.beta);
+ EXPECT_FLOAT_EQ(45.0f, orientation->data.gamma);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/devtools/BUILD.gn b/chromium/content/browser/devtools/BUILD.gn
index 75777316dcd..e65cfe7da9d 100644
--- a/chromium/content/browser/devtools/BUILD.gn
+++ b/chromium/content/browser/devtools/BUILD.gn
@@ -8,8 +8,6 @@ import("//tools/grit/grit_rule.gni")
group("resources") {
deps = [
":devtools_resources",
- ":devtools_protocol_constants",
- ":devtools_protocol_handler",
]
}
@@ -19,7 +17,7 @@ grit("devtools_resources") {
# 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"
+ output_dir = "$root_gen_dir/blink"
outputs = [
"grit/devtools_resources.h",
"devtools_resources.pak",
@@ -27,9 +25,8 @@ grit("devtools_resources") {
"grit/devtools_resources_map.h",
]
- defines = [
- "SHARED_INTERMEDIATE_DIR=" + rebase_path(root_gen_dir, root_build_dir),
- ]
+ defines =
+ [ "SHARED_INTERMEDIATE_DIR=" + rebase_path(root_gen_dir, root_build_dir) ]
deps = [
# This is the action that generates out .grd input file.
@@ -37,51 +34,24 @@ grit("devtools_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"
- inputs = [ blink_protocol, browser_protocol ]
-
- outputs = [
- "$target_gen_dir/devtools_protocol_constants.cc",
- "$target_gen_dir/devtools_protocol_constants.h",
- ]
-
- args = [ "content" ] + rebase_path(outputs, root_build_dir) + [
- rebase_path(blink_protocol, root_build_dir),
- rebase_path(browser_protocol, root_build_dir),
- ]
-}
-
action("gen_devtools_protocol_handler") {
- visibility = [ ":devtools_protocol_handler" ]
+ visibility = [ "//content/browser" ]
script = "//content/browser/devtools/protocol/" +
- "devtools_protocol_handler_generator.py"
+ "devtools_protocol_handler_generator.py"
blink_protocol = "//third_party/WebKit/Source/devtools/protocol.json"
- inputs = [ blink_protocol ]
+ browser_protocol = "browser_protocol.json"
+ inputs = [
+ blink_protocol,
+ browser_protocol,
+ ]
outputs = [
- "$target_gen_dir/protocol/devtools_protocol_handler_impl.cc",
- "$target_gen_dir/protocol/devtools_protocol_handler_impl.h",
+ "$target_gen_dir/protocol/devtools_protocol_dispatcher.cc",
+ "$target_gen_dir/protocol/devtools_protocol_dispatcher.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")
+ args =
+ rebase_path(inputs, root_build_dir) + rebase_path(outputs, root_build_dir)
}
diff --git a/chromium/content/browser/devtools/OWNERS b/chromium/content/browser/devtools/OWNERS
index 88a3d57bb91..d403771bf40 100644
--- a/chromium/content/browser/devtools/OWNERS
+++ b/chromium/content/browser/devtools/OWNERS
@@ -1,4 +1,3 @@
dgozman@chromium.org
pfeldman@chromium.org
-vsevik@chromium.org
yurys@chromium.org
diff --git a/chromium/content/browser/devtools/browser_devtools_agent_host.cc b/chromium/content/browser/devtools/browser_devtools_agent_host.cc
new file mode 100644
index 00000000000..03fb0e2ecc3
--- /dev/null
+++ b/chromium/content/browser/devtools/browser_devtools_agent_host.cc
@@ -0,0 +1,65 @@
+// Copyright 2014 The Chromium Authors. 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/browser_devtools_agent_host.h"
+
+#include "base/bind.h"
+#include "content/browser/devtools/protocol/devtools_protocol_handler.h"
+#include "content/browser/devtools/protocol/system_info_handler.h"
+#include "content/browser/devtools/protocol/tethering_handler.h"
+#include "content/browser/devtools/protocol/tracing_handler.h"
+
+namespace content {
+
+scoped_refptr<DevToolsAgentHost> DevToolsAgentHost::CreateForBrowser(
+ scoped_refptr<base::MessageLoopProxy> tethering_message_loop,
+ const CreateServerSocketCallback& socket_callback) {
+ return new BrowserDevToolsAgentHost(tethering_message_loop, socket_callback);
+}
+
+BrowserDevToolsAgentHost::BrowserDevToolsAgentHost(
+ scoped_refptr<base::MessageLoopProxy> tethering_message_loop,
+ const CreateServerSocketCallback& socket_callback)
+ : system_info_handler_(new devtools::system_info::SystemInfoHandler()),
+ tethering_handler_(new devtools::tethering::TetheringHandler(
+ socket_callback, tethering_message_loop)),
+ tracing_handler_(new devtools::tracing::TracingHandler(
+ devtools::tracing::TracingHandler::Browser)) {
+ set_handle_all_protocol_commands();
+ DevToolsProtocolDispatcher* dispatcher = protocol_handler_->dispatcher();
+ dispatcher->SetSystemInfoHandler(system_info_handler_.get());
+ dispatcher->SetTetheringHandler(tethering_handler_.get());
+ dispatcher->SetTracingHandler(tracing_handler_.get());
+}
+
+BrowserDevToolsAgentHost::~BrowserDevToolsAgentHost() {
+}
+
+void BrowserDevToolsAgentHost::Attach() {
+}
+
+void BrowserDevToolsAgentHost::Detach() {
+}
+
+DevToolsAgentHost::Type BrowserDevToolsAgentHost::GetType() {
+ return TYPE_BROWSER;
+}
+
+std::string BrowserDevToolsAgentHost::GetTitle() {
+ return "";
+}
+
+GURL BrowserDevToolsAgentHost::GetURL() {
+ return GURL();
+}
+
+bool BrowserDevToolsAgentHost::Activate() {
+ return false;
+}
+
+bool BrowserDevToolsAgentHost::Close() {
+ return false;
+}
+
+} // content
diff --git a/chromium/content/browser/devtools/browser_devtools_agent_host.h b/chromium/content/browser/devtools/browser_devtools_agent_host.h
new file mode 100644
index 00000000000..b4fbb7de1ee
--- /dev/null
+++ b/chromium/content/browser/devtools/browser_devtools_agent_host.h
@@ -0,0 +1,44 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_DEVTOOLS_BROWSER_DEVTOOLS_AGENT_HOST_H_
+#define CONTENT_BROWSER_DEVTOOLS_BROWSER_DEVTOOLS_AGENT_HOST_H_
+
+#include "content/browser/devtools/devtools_agent_host_impl.h"
+
+namespace content {
+
+namespace devtools {
+namespace system_info { class SystemInfoHandler; }
+namespace tethering { class TetheringHandler; }
+namespace tracing { class TracingHandler; }
+} // namespace devtools
+
+class BrowserDevToolsAgentHost : public DevToolsAgentHostImpl {
+ private:
+ friend class DevToolsAgentHost;
+ BrowserDevToolsAgentHost(
+ scoped_refptr<base::MessageLoopProxy> tethering_message_loop,
+ const CreateServerSocketCallback& socket_callback);
+ ~BrowserDevToolsAgentHost() override;
+
+ // DevToolsAgentHostImpl implementation.
+ void Attach() override;
+ void Detach() override;
+
+ // DevToolsAgentHost implementation.
+ Type GetType() override;
+ std::string GetTitle() override;
+ GURL GetURL() override;
+ bool Activate() override;
+ bool Close() override;
+
+ scoped_ptr<devtools::system_info::SystemInfoHandler> system_info_handler_;
+ scoped_ptr<devtools::tethering::TetheringHandler> tethering_handler_;
+ scoped_ptr<devtools::tracing::TracingHandler> tracing_handler_;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_DEVTOOLS_BROWSER_DEVTOOLS_AGENT_HOST_H_
diff --git a/chromium/content/browser/devtools/browser_protocol.json b/chromium/content/browser/devtools/browser_protocol.json
index f4b67407d2e..1152ca79833 100644
--- a/chromium/content/browser/devtools/browser_protocol.json
+++ b/chromium/content/browser/devtools/browser_protocol.json
@@ -26,23 +26,17 @@
{ "name": "driverBugWorkarounds", "type": "array", "items": { "type": "string" }, "description": "An optional array of GPU driver bug workarounds." }
],
"description": "Provides information about the GPU(s) on the system."
- },
- {
- "id": "SystemInfo",
- "type": "object",
- "properties": [
- { "name": "gpu", "$ref": "GPUInfo", "description": "Information about the GPUs on the system." },
- { "name": "modelName", "type": "string", "description": "A platform-dependent description of the model of the machine. On Mac OS, this is, for example, 'MacBookPro 10.1'. Will be the empty string if not supported." }
- ],
- "description": "Provides information about the system."
}
],
"commands": [
{
"name": "getInfo",
+ "async": true,
"description": "Returns information about the system.",
"returns": [
- { "name": "info", "$ref": "SystemInfo", "description": "Information about the system." }
+ { "name": "gpu", "$ref": "GPUInfo", "description": "Information about the GPUs on the system." },
+ { "name": "modelName", "type": "string", "description": "A platform-dependent description of the model of the machine. On Mac OS, this is, for example, 'MacBookPro'. Will be the empty string if not supported." },
+ { "name": "modelVersion", "type": "string", "description": "A platform-dependent description of the version of the machine. On Mac OS, this is, for example, '10.1'. Will be the empty string if not supported." }
],
"handlers": ["browser"]
}
@@ -55,17 +49,19 @@
"commands": [
{
"name": "bind",
+ "async": true,
"description": "Request browser port binding.",
"parameters": [
- { "name": "port", "type": "number", "description": "Port number to bind." }
+ { "name": "port", "type": "integer", "description": "Port number to bind." }
],
"handlers": ["browser"]
},
{
"name": "unbind",
+ "async": true,
"description": "Request browser port unbinding.",
"parameters": [
- { "name": "port", "type": "number", "description": "Port number to unbind." }
+ { "name": "port", "type": "integer", "description": "Port number to unbind." }
],
"handlers": ["browser"]
}
@@ -75,7 +71,7 @@
"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": "port", "type": "integer", "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
index a67eca87890..9aaaf25b9cd 100644
--- a/chromium/content/browser/devtools/devtools.gyp
+++ b/chromium/content/browser/devtools/devtools.gyp
@@ -12,12 +12,14 @@
'action_name': 'devtools_protocol_handler',
'variables': {
'blink_protocol': '../../../third_party/WebKit/Source/devtools/protocol.json',
+ 'browser_protocol': 'browser_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',
+ 'output_cc': '<(SHARED_INTERMEDIATE_DIR)/content/browser/devtools/protocol/devtools_protocol_dispatcher.cc',
+ 'output_h': '<(SHARED_INTERMEDIATE_DIR)/content/browser/devtools/protocol/devtools_protocol_dispatcher.h',
},
'inputs': [
'<(blink_protocol)',
+ '<(browser_protocol)',
'<(generator)',
],
'outputs': [
@@ -28,10 +30,11 @@
'python',
'<(generator)',
'<(blink_protocol)',
+ '<(browser_protocol)',
'<(output_cc)',
'<(output_h)',
],
- 'message': 'Generating DevTools protocol browser-side handlers from <(blink_protocol)'
+ 'message': 'Generating DevTools protocol browser-side handlers from <(blink_protocol) and <(browser_protocol)'
},
],
'direct_dependent_settings': {
diff --git a/chromium/content/browser/devtools/devtools_agent_host_impl.cc b/chromium/content/browser/devtools/devtools_agent_host_impl.cc
index b7f9b24b59f..cba575ea0ef 100644
--- a/chromium/content/browser/devtools/devtools_agent_host_impl.cc
+++ b/chromium/content/browser/devtools/devtools_agent_host_impl.cc
@@ -9,10 +9,16 @@
#include "base/basictypes.h"
#include "base/guid.h"
+#include "base/json/json_writer.h"
#include "base/lazy_instance.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/browser/devtools/protocol/devtools_protocol_handler.h"
+#include "content/browser/devtools/render_frame_devtools_agent_host.h"
+#include "content/browser/devtools/service_worker_devtools_agent_host.h"
+#include "content/browser/devtools/service_worker_devtools_manager.h"
+#include "content/browser/devtools/shared_worker_devtools_agent_host.h"
+#include "content/browser/devtools/shared_worker_devtools_manager.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/devtools_manager_delegate.h"
@@ -29,27 +35,60 @@ base::LazyInstance<AgentStateCallbacks>::Leaky g_callbacks =
} // namespace
// static
+std::string DevToolsAgentHost::GetProtocolVersion() {
+ return std::string(devtools::kProtocolVersion);
+}
+
+// static
+bool DevToolsAgentHost::IsSupportedProtocolVersion(const std::string& version) {
+ return devtools::IsSupportedProtocolVersion(version);
+}
+
+// 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));
- }
+ List result;
+ SharedWorkerDevToolsAgentHost::List shared_list;
+ SharedWorkerDevToolsManager::GetInstance()->AddAllAgentHosts(&shared_list);
+ for (const auto& host : shared_list)
+ result.push_back(host);
+
+ ServiceWorkerDevToolsAgentHost::List service_list;
+ ServiceWorkerDevToolsManager::GetInstance()->AddAllAgentHosts(&service_list);
+ for (const auto& host : service_list)
+ result.push_back(host);
+
+ RenderFrameDevToolsAgentHost::AddAllAgentHosts(&result);
return result;
}
+// Called on the UI thread.
+// static
+scoped_refptr<DevToolsAgentHost> DevToolsAgentHost::GetForWorker(
+ int worker_process_id,
+ int worker_route_id) {
+ if (scoped_refptr<DevToolsAgentHost> host =
+ SharedWorkerDevToolsManager::GetInstance()
+ ->GetDevToolsAgentHostForWorker(worker_process_id,
+ worker_route_id)) {
+ return host;
+ }
+ return ServiceWorkerDevToolsManager::GetInstance()
+ ->GetDevToolsAgentHostForWorker(worker_process_id, worker_route_id);
+}
+
DevToolsAgentHostImpl::DevToolsAgentHostImpl()
- : id_(base::GenerateGUID()),
- client_(NULL) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ : protocol_handler_(new DevToolsProtocolHandler(
+ base::Bind(&DevToolsAgentHostImpl::SendMessageToClient,
+ base::Unretained(this)))),
+ id_(base::GenerateGUID()),
+ client_(NULL),
+ handle_all_commands_(false) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
g_instances.Get()[id_] = this;
}
DevToolsAgentHostImpl::~DevToolsAgentHostImpl() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
g_instances.Get().erase(g_instances.Get().find(id_));
}
@@ -78,7 +117,6 @@ void DevToolsAgentHostImpl::AttachClient(DevToolsAgentHostClient* client) {
}
client_ = client;
Attach();
- DevToolsManager::GetInstance()->AgentHostChanged(this);
}
void DevToolsAgentHostImpl::DetachClient() {
@@ -88,7 +126,6 @@ void DevToolsAgentHostImpl::DetachClient() {
scoped_refptr<DevToolsAgentHostImpl> protect(this);
client_ = NULL;
Detach();
- DevToolsManager::GetInstance()->AgentHostChanged(this);
}
bool DevToolsAgentHostImpl::IsAttached() {
@@ -102,6 +139,10 @@ std::string DevToolsAgentHostImpl::GetId() {
return id_;
}
+BrowserContext* DevToolsAgentHostImpl::GetBrowserContext() {
+ return nullptr;
+}
+
WebContents* DevToolsAgentHostImpl::GetWebContents() {
return NULL;
}
@@ -112,10 +153,6 @@ void DevToolsAgentHostImpl::DisconnectWebContents() {
void DevToolsAgentHostImpl::ConnectWebContents(WebContents* wc) {
}
-bool DevToolsAgentHostImpl::IsWorker() const {
- return false;
-}
-
void DevToolsAgentHostImpl::HostClosed() {
if (!client_)
return;
@@ -125,7 +162,6 @@ void DevToolsAgentHostImpl::HostClosed() {
DevToolsAgentHostClient* client = client_;
client_ = NULL;
client->AgentHostClosed(this, false);
- DevToolsManager::GetInstance()->AgentHostChanged(this);
}
void DevToolsAgentHostImpl::SendMessageToClient(const std::string& message) {
@@ -151,7 +187,6 @@ void DevToolsAgentHost::DetachAllClients() {
agent_host->client_ = NULL;
client->AgentHostClosed(agent_host, true);
agent_host->Detach();
- DevToolsManager::GetInstance()->AgentHostChanged(protect);
}
}
}
@@ -180,6 +215,7 @@ void DevToolsAgentHostImpl::NotifyCallbacks(
DevToolsAgentHostImpl* agent_host, bool attached) {
AgentStateCallbacks copy(g_callbacks.Get());
DevToolsManager* manager = DevToolsManager::GetInstance();
+ manager->AgentHostStateChanged(agent_host, attached);
if (manager->delegate())
manager->delegate()->DevToolsAgentStateChanged(agent_host, attached);
for (AgentStateCallbacks::iterator it = copy.begin(); it != copy.end(); ++it)
@@ -192,4 +228,30 @@ void DevToolsAgentHostImpl::Inspect(BrowserContext* browser_context) {
manager->delegate()->Inspect(browser_context, this);
}
+bool DevToolsAgentHostImpl::DispatchProtocolMessage(
+ const std::string& message) {
+ scoped_ptr<base::DictionaryValue> command =
+ protocol_handler_->ParseCommand(message);
+ if (!command)
+ return true;
+
+ DevToolsManagerDelegate* delegate =
+ DevToolsManager::GetInstance()->delegate();
+ if (delegate) {
+ scoped_ptr<base::DictionaryValue> response(
+ delegate->HandleCommand(this, command.get()));
+ if (response) {
+ std::string json_response;
+ base::JSONWriter::Write(response.get(), &json_response);
+ SendMessageToClient(json_response);
+ return true;
+ }
+ }
+
+ if (!handle_all_commands_)
+ return protocol_handler_->HandleOptionalCommand(command.Pass());
+ protocol_handler_->HandleCommand(command.Pass());
+ return true;
+}
+
} // 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 694590acf1c..698bfe90a16 100644
--- a/chromium/content/browser/devtools/devtools_agent_host_impl.h
+++ b/chromium/content/browser/devtools/devtools_agent_host_impl.h
@@ -18,13 +18,11 @@ class Message;
namespace content {
class BrowserContext;
+class DevToolsProtocolHandler;
// Describes interface for managing devtools agents from the browser process.
class CONTENT_EXPORT DevToolsAgentHostImpl : public DevToolsAgentHost {
public:
- // 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;
@@ -32,7 +30,7 @@ class CONTENT_EXPORT DevToolsAgentHostImpl : public DevToolsAgentHost {
virtual void Detach() = 0;
// Sends a message to the agent.
- virtual void DispatchProtocolMessage(const std::string& message) = 0;
+ bool DispatchProtocolMessage(const std::string& message) override;
// Opens the inspector for this host.
void Inspect(BrowserContext* browser_context);
@@ -43,15 +41,18 @@ class CONTENT_EXPORT DevToolsAgentHostImpl : public DevToolsAgentHost {
bool IsAttached() override;
void InspectElement(int x, int y) override;
std::string GetId() override;
+ BrowserContext* GetBrowserContext() override;
WebContents* GetWebContents() override;
void DisconnectWebContents() override;
void ConnectWebContents(WebContents* wc) override;
- bool IsWorker() const override;
protected:
DevToolsAgentHostImpl();
~DevToolsAgentHostImpl() override;
+ scoped_ptr<DevToolsProtocolHandler> protocol_handler_;
+
+ void set_handle_all_protocol_commands() { handle_all_commands_ = true; }
void HostClosed();
void SendMessageToClient(const std::string& message);
static void NotifyCallbacks(DevToolsAgentHostImpl* agent_host, bool attached);
@@ -61,6 +62,7 @@ class CONTENT_EXPORT DevToolsAgentHostImpl : public DevToolsAgentHost {
const std::string id_;
DevToolsAgentHostClient* client_;
+ bool handle_all_commands_;
};
} // namespace content
diff --git a/chromium/content/browser/devtools/devtools_frame_trace_recorder.cc b/chromium/content/browser/devtools/devtools_frame_trace_recorder.cc
new file mode 100644
index 00000000000..0626bfa8fdb
--- /dev/null
+++ b/chromium/content/browser/devtools/devtools_frame_trace_recorder.cc
@@ -0,0 +1,141 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/devtools/devtools_frame_trace_recorder.h"
+
+#include <string>
+#include <vector>
+
+#include "base/atomicops.h"
+#include "base/base64.h"
+#include "base/bind.h"
+#include "base/memory/ref_counted.h"
+#include "base/trace_event/trace_event_impl.h"
+#include "cc/output/compositor_frame_metadata.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
+#include "content/browser/renderer_host/render_widget_host_view_base.h"
+#include "content/public/browser/readback_types.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/codec/png_codec.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/geometry/size_conversions.h"
+
+namespace content {
+
+namespace {
+
+static base::subtle::Atomic32 frame_data_count = 0;
+static int kMaximumFrameDataCount = 150;
+static size_t kFrameAreaLimit = 256000;
+
+} // namespace
+
+class DevToolsFrameTraceRecorderData
+ : public base::trace_event::ConvertableToTraceFormat {
+ public:
+ DevToolsFrameTraceRecorderData(const cc::CompositorFrameMetadata& metadata)
+ : metadata_(metadata),
+ weak_factory_(this) {
+ }
+
+ base::WeakPtr<DevToolsFrameTraceRecorderData> GetWeakPtr() {
+ return weak_factory_.GetWeakPtr();
+ }
+
+ void FrameCaptured(const SkBitmap& bitmap, ReadbackResponse response) {
+ if (response != READBACK_SUCCESS)
+ return;
+ int current_frame_count = base::subtle::NoBarrier_Load(&frame_data_count);
+ if (current_frame_count >= kMaximumFrameDataCount)
+ return;
+ frame_ = bitmap;
+ if (!frame_.drawsNothing())
+ base::subtle::NoBarrier_AtomicIncrement(&frame_data_count, 1);
+ }
+
+ void CaptureFrame(RenderFrameHostImpl* host) {
+ RenderWidgetHostViewBase* view =
+ static_cast<RenderWidgetHostViewBase*>(host->GetView());
+ if (!view)
+ return;
+ int current_frame_count = base::subtle::NoBarrier_Load(&frame_data_count);
+ if (current_frame_count >= kMaximumFrameDataCount)
+ return;
+ float scale = metadata_.page_scale_factor;
+ float area = metadata_.scrollable_viewport_size.GetArea();
+ if (area * scale * scale > kFrameAreaLimit)
+ scale = sqrt(kFrameAreaLimit / area);
+ gfx::Size snapshot_size(gfx::ToRoundedSize(gfx::ScaleSize(
+ metadata_.scrollable_viewport_size, scale)));
+ view->CopyFromCompositingSurface(gfx::Rect(), snapshot_size,
+ base::Bind(
+ &DevToolsFrameTraceRecorderData::FrameCaptured,
+ GetWeakPtr()),
+ kN32_SkColorType);
+ }
+
+ void AppendAsTraceFormat(std::string* out) const override {
+ out->append("\"");
+ std::vector<unsigned char> data;
+ SkAutoLockPixels lock_image(frame_);
+ bool encoded = gfx::PNGCodec::Encode(
+ reinterpret_cast<unsigned char*>(frame_.getAddr32(0, 0)),
+ gfx::PNGCodec::FORMAT_SkBitmap,
+ gfx::Size(frame_.width(), frame_.height()),
+ frame_.width() * frame_.bytesPerPixel(),
+ false, std::vector<gfx::PNGCodec::Comment>(), &data);
+ if (encoded) {
+ std::string encoded_data;
+ base::Base64Encode(
+ base::StringPiece(reinterpret_cast<char*>(&data[0]), data.size()),
+ &encoded_data);
+ out->append(encoded_data);
+ }
+ out->append("\"");
+ }
+
+ private:
+ ~DevToolsFrameTraceRecorderData() override {
+ if (!frame_.drawsNothing())
+ base::subtle::NoBarrier_AtomicIncrement(&frame_data_count, -1);
+ }
+
+ cc::CompositorFrameMetadata metadata_;
+ SkBitmap frame_;
+ base::WeakPtrFactory<DevToolsFrameTraceRecorderData> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(DevToolsFrameTraceRecorderData);
+};
+
+DevToolsFrameTraceRecorder::DevToolsFrameTraceRecorder() { }
+
+DevToolsFrameTraceRecorder::~DevToolsFrameTraceRecorder() { }
+
+void DevToolsFrameTraceRecorder::OnSwapCompositorFrame(
+ RenderFrameHostImpl* host,
+ const cc::CompositorFrameMetadata& frame_metadata) {
+ if (!host)
+ return;
+
+ bool enabled;
+ TRACE_EVENT_CATEGORY_GROUP_ENABLED(
+ TRACE_DISABLED_BY_DEFAULT("devtools.screenshot"), &enabled);
+ if (!enabled)
+ return;
+
+ if (last_event_data_.get())
+ last_event_data_->CaptureFrame(host);
+
+ scoped_refptr<DevToolsFrameTraceRecorderData> data(
+ new DevToolsFrameTraceRecorderData(frame_metadata));
+ last_event_data_ = data->GetWeakPtr();
+ TRACE_EVENT_INSTANT1(
+ TRACE_DISABLED_BY_DEFAULT("devtools.screenshot"),
+ "CaptureFrame",
+ TRACE_EVENT_SCOPE_THREAD,
+ "data",
+ scoped_refptr<base::trace_event::ConvertableToTraceFormat>(data));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/devtools/devtools_frame_trace_recorder.h b/chromium/content/browser/devtools/devtools_frame_trace_recorder.h
new file mode 100644
index 00000000000..88c4311b852
--- /dev/null
+++ b/chromium/content/browser/devtools/devtools_frame_trace_recorder.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_FRAME_TRACE_RECORDER_H_
+#define CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_FRAME_TRACE_RECORDER_H_
+
+#include "base/compiler_specific.h"
+#include "base/memory/weak_ptr.h"
+
+namespace cc {
+class CompositorFrameMetadata;
+}
+
+namespace content {
+
+class DevToolsFrameTraceRecorderData;
+class RenderFrameHostImpl;
+
+class DevToolsFrameTraceRecorder {
+ public:
+ DevToolsFrameTraceRecorder();
+ ~DevToolsFrameTraceRecorder();
+
+ void OnSwapCompositorFrame(
+ RenderFrameHostImpl* host,
+ const cc::CompositorFrameMetadata& frame_metadata);
+
+ private:
+ base::WeakPtr<DevToolsFrameTraceRecorderData> last_event_data_;
+ DISALLOW_COPY_AND_ASSIGN(DevToolsFrameTraceRecorder);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_FRAME_TRACE_RECORDER_H_
diff --git a/chromium/content/browser/devtools/devtools_frontend_host_impl.cc b/chromium/content/browser/devtools/devtools_frontend_host_impl.cc
index a73e88cb50a..712a9c9329c 100644
--- a/chromium/content/browser/devtools/devtools_frontend_host_impl.cc
+++ b/chromium/content/browser/devtools/devtools_frontend_host_impl.cc
@@ -4,34 +4,58 @@
#include "content/browser/devtools/devtools_frontend_host_impl.h"
+#include "content/browser/bad_message.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/render_frame_host.h"
#include "content/public/browser/web_contents.h"
+#include "content/public/common/content_client.h"
+#include "grit/devtools_resources_map.h"
namespace content {
// static
DevToolsFrontendHost* DevToolsFrontendHost::Create(
- RenderViewHost* frontend_rvh,
+ RenderFrameHost* frontend_main_frame,
DevToolsFrontendHost::Delegate* delegate) {
- return new DevToolsFrontendHostImpl(frontend_rvh, delegate);
+ return new DevToolsFrontendHostImpl(frontend_main_frame, delegate);
+}
+
+// static
+base::StringPiece DevToolsFrontendHost::GetFrontendResource(
+ const std::string& path) {
+ for (size_t i = 0; i < kDevtoolsResourcesSize; ++i) {
+ if (path == kDevtoolsResources[i].name) {
+ return GetContentClient()->GetDataResource(
+ kDevtoolsResources[i].value, ui::SCALE_FACTOR_NONE);
+ }
+ }
+ return std::string();
}
DevToolsFrontendHostImpl::DevToolsFrontendHostImpl(
- RenderViewHost* frontend_rvh,
+ RenderFrameHost* frontend_main_frame,
DevToolsFrontendHost::Delegate* delegate)
- : WebContentsObserver(WebContents::FromRenderViewHost(frontend_rvh)),
+ : WebContentsObserver(
+ WebContents::FromRenderFrameHost(frontend_main_frame)),
delegate_(delegate) {
- frontend_rvh->Send(new DevToolsMsg_SetupDevToolsClient(
- frontend_rvh->GetRoutingID()));
+ frontend_main_frame->Send(
+ new DevToolsMsg_SetupDevToolsClient(frontend_main_frame->GetRoutingID()));
}
DevToolsFrontendHostImpl::~DevToolsFrontendHostImpl() {
}
+void DevToolsFrontendHostImpl::BadMessageRecieved() {
+ bad_message::ReceivedBadMessage(web_contents()->GetRenderProcessHost(),
+ bad_message::DFH_BAD_EMBEDDER_MESSAGE);
+}
+
bool DevToolsFrontendHostImpl::OnMessageReceived(
- const IPC::Message& message) {
+ const IPC::Message& message,
+ RenderFrameHost* render_frame_host) {
+ if (render_frame_host != web_contents()->GetMainFrame())
+ return false;
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(DevToolsFrontendHostImpl, message)
IPC_MESSAGE_HANDLER(DevToolsAgentMsg_DispatchOnInspectorBackend,
diff --git a/chromium/content/browser/devtools/devtools_frontend_host_impl.h b/chromium/content/browser/devtools/devtools_frontend_host_impl.h
index 98b907497a1..148bc2f6e73 100644
--- a/chromium/content/browser/devtools/devtools_frontend_host_impl.h
+++ b/chromium/content/browser/devtools/devtools_frontend_host_impl.h
@@ -13,13 +13,16 @@ namespace content {
class DevToolsFrontendHostImpl : public DevToolsFrontendHost,
public WebContentsObserver {
public:
- DevToolsFrontendHostImpl(RenderViewHost* frontend_rvh,
+ DevToolsFrontendHostImpl(RenderFrameHost* frontend_main_frame,
DevToolsFrontendHost::Delegate* delegate);
~DevToolsFrontendHostImpl() override;
+ void BadMessageRecieved() override;
+
private:
// WebContentsObserver overrides.
- bool OnMessageReceived(const IPC::Message& message) override;
+ bool OnMessageReceived(const IPC::Message& message,
+ RenderFrameHost* render_frame_host) override;
void OnDispatchOnInspectorBackend(const std::string& message);
void OnDispatchOnEmbedder(const std::string& message);
diff --git a/chromium/content/browser/devtools/devtools_http_handler_impl.cc b/chromium/content/browser/devtools/devtools_http_handler_impl.cc
deleted file mode 100644
index e7b7fb9b99e..00000000000
--- a/chromium/content/browser/devtools/devtools_http_handler_impl.cc
+++ /dev/null
@@ -1,989 +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_http_handler_impl.h"
-
-#include <algorithm>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/compiler_specific.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"
-#include "base/stl_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/threading/thread.h"
-#include "base/values.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/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_http_handler_delegate.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 "grit/devtools_resources_map.h"
-#include "net/base/escape.h"
-#include "net/base/io_buffer.h"
-#include "net/base/ip_endpoint.h"
-#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"
-#endif
-
-namespace content {
-
-namespace {
-
-const base::FilePath::CharType kDevToolsActivePortFileName[] =
- FILE_PATH_LITERAL("DevToolsActivePort");
-
-const char kDevToolsHandlerThreadName[] = "Chrome_DevToolsHandlerThread";
-
-const char kThumbUrlPrefix[] = "/thumb/";
-const char kPageUrlPrefix[] = "/devtools/page/";
-
-const char kTargetIdField[] = "id";
-const char kTargetParentIdField[] = "parentId";
-const char kTargetTypeField[] = "type";
-const char kTargetTitleField[] = "title";
-const char kTargetDescriptionField[] = "description";
-const char kTargetUrlField[] = "url";
-const char kTargetThumbnailUrlField[] = "thumbnailUrl";
-const char kTargetFaviconUrlField[] = "faviconUrl";
-const char kTargetWebSocketDebuggerUrlField[] = "webSocketDebuggerUrl";
-const char kTargetDevtoolsFrontendUrlField[] = "devtoolsFrontendUrl";
-
-// 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:
- DevToolsAgentHostClientImpl(base::MessageLoop* message_loop,
- net::HttpServer* server,
- int connection_id,
- DevToolsAgentHost* agent_host)
- : message_loop_(message_loop),
- server_(server),
- connection_id_(connection_id),
- agent_host_(agent_host) {
- agent_host_->AttachClient(this);
- }
-
- ~DevToolsAgentHostClientImpl() override {
- if (agent_host_.get())
- agent_host_->DetachClient();
- }
-
- 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,
- 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,
- base::Unretained(server_),
- connection_id_,
- response));
-
- message_loop_->PostTask(
- FROM_HERE,
- base::Bind(&net::HttpServer::Close,
- base::Unretained(server_),
- connection_id_));
- }
-
- 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,
- base::Unretained(server_),
- connection_id_,
- message));
- }
-
- void OnMessage(const std::string& message) {
- if (agent_host_.get())
- agent_host_->DispatchProtocolMessage(message);
- }
-
- private:
- base::MessageLoop* const message_loop_;
- net::HttpServer* const server_;
- const int connection_id_;
- scoped_refptr<DevToolsAgentHost> agent_host_;
-};
-
-static bool TimeComparator(const DevToolsTarget* target1,
- const DevToolsTarget* target2) {
- return target1->GetLastActivityTime() > target2->GetLastActivityTime();
-}
-
-} // 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) {
- return devtools::IsSupportedProtocolVersion(version);
-}
-
-// static
-int DevToolsHttpHandler::GetFrontendResourceId(const std::string& name) {
- for (size_t i = 0; i < kDevtoolsResourcesSize; ++i) {
- if (name == kDevtoolsResources[i].name)
- return kDevtoolsResources[i].value;
- }
- return -1;
-}
-
-// static
-DevToolsHttpHandler* DevToolsHttpHandler::Start(
- 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(server_socket_factory.Pass(),
- frontend_url,
- delegate,
- active_port_output_directory);
- http_handler->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.
- DCHECK(server_.get() == NULL);
- DCHECK(thread_.get() == NULL);
- STLDeleteValues(&target_map_);
-}
-
-void DevToolsHttpHandlerImpl::Start() {
- if (thread_)
- return;
- thread_.reset(new base::Thread(kDevToolsHandlerThreadName));
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- base::Bind(&DevToolsHttpHandlerImpl::StartHandlerThread, this));
-}
-
-// Runs on FILE thread.
-void DevToolsHttpHandlerImpl::StartHandlerThread() {
- base::Thread::Options options;
- options.message_loop_type = base::MessageLoop::TYPE_IO;
- if (!thread_->StartWithOptions(options)) {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&DevToolsHttpHandlerImpl::ResetHandlerThread, this));
- return;
- }
-
- thread_->message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&DevToolsHttpHandlerImpl::Init, this));
-}
-
-void DevToolsHttpHandlerImpl::ResetHandlerThread() {
- thread_.reset();
- server_ip_address_.reset();
-}
-
-void DevToolsHttpHandlerImpl::ResetHandlerThreadAndRelease() {
- ResetHandlerThread();
- Release();
-}
-
-void DevToolsHttpHandlerImpl::Stop() {
- if (!thread_)
- return;
- BrowserThread::PostTaskAndReply(
- BrowserThread::FILE, FROM_HERE,
- base::Bind(&DevToolsHttpHandlerImpl::StopHandlerThread, this),
- 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() {
- if (!server_ip_address_)
- return GURL();
- return GURL(std::string("http://") + server_ip_address_->ToString() + frontend_url_);
-}
-
-static std::string PathWithoutParams(const std::string& path) {
- size_t query_position = path.find("?");
- if (query_position != std::string::npos)
- return path.substr(0, query_position);
- return path;
-}
-
-static std::string GetMimeType(const std::string& filename) {
- if (EndsWith(filename, ".html", false)) {
- return "text/html";
- } else if (EndsWith(filename, ".css", false)) {
- return "text/css";
- } else if (EndsWith(filename, ".js", false)) {
- return "application/javascript";
- } else if (EndsWith(filename, ".png", false)) {
- return "image/png";
- } else if (EndsWith(filename, ".gif", false)) {
- return "image/gif";
- } else if (EndsWith(filename, ".json", false)) {
- return "application/json";
- }
- LOG(ERROR) << "GetMimeType doesn't know mime type for: "
- << filename
- << " text/plain will be returned";
- NOTREACHED();
- return "text/plain";
-}
-
-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,
- FROM_HERE,
- base::Bind(&DevToolsHttpHandlerImpl::OnJsonRequestUI,
- this,
- connection_id,
- info));
- return;
- }
-
- if (info.path.find(kThumbUrlPrefix) == 0) {
- // Thumbnail request.
- const std::string target_id = info.path.substr(strlen(kThumbUrlPrefix));
- DevToolsTarget* target = GetTarget(target_id);
- GURL page_url;
- if (target)
- page_url = target->GetURL();
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(&DevToolsHttpHandlerImpl::OnThumbnailRequestUI,
- this,
- connection_id,
- page_url));
- return;
- }
-
- if (info.path == "" || info.path == "/") {
- // Discovery page request.
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(&DevToolsHttpHandlerImpl::OnDiscoveryPageRequestUI,
- this,
- connection_id));
- return;
- }
-
- if (info.path.find("/devtools/") != 0) {
- server_->Send404(connection_id);
- return;
- }
-
- std::string filename = PathWithoutParams(info.path.substr(10));
- std::string mime_type = GetMimeType(filename);
-
- base::FilePath frontend_dir = delegate_->GetDebugFrontendDir();
- if (!frontend_dir.empty()) {
- base::FilePath path = frontend_dir.AppendASCII(filename);
- std::string data;
- base::ReadFileToString(path, &data);
- server_->Send200(connection_id, data, mime_type);
- return;
- }
- if (delegate_->BundlesFrontendResources()) {
- int resource_id = DevToolsHttpHandler::GetFrontendResourceId(filename);
- if (resource_id != -1) {
- base::StringPiece data = GetContentClient()->GetDataResource(
- resource_id, ui::SCALE_FACTOR_NONE);
- server_->Send200(connection_id, data.as_string(), mime_type);
- return;
- }
- }
- server_->Send404(connection_id);
-}
-
-void DevToolsHttpHandlerImpl::OnWebSocketRequest(
- int connection_id,
- const net::HttpServerRequestInfo& request) {
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(
- &DevToolsHttpHandlerImpl::OnWebSocketRequestUI,
- this,
- connection_id,
- request));
-}
-
-void DevToolsHttpHandlerImpl::OnWebSocketMessage(
- int connection_id,
- const std::string& data) {
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(
- &DevToolsHttpHandlerImpl::OnWebSocketMessageUI,
- this,
- connection_id,
- data));
-}
-
-void DevToolsHttpHandlerImpl::OnClose(int connection_id) {
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(
- &DevToolsHttpHandlerImpl::OnCloseUI,
- this,
- connection_id));
-}
-
-std::string DevToolsHttpHandlerImpl::GetFrontendURLInternal(
- const std::string id,
- const std::string& host) {
- return base::StringPrintf(
- "%s%sws=%s%s%s",
- frontend_url_.c_str(),
- frontend_url_.find("?") == std::string::npos ? "?" : "&",
- host.c_str(),
- kPageUrlPrefix,
- id.c_str());
-}
-
-static bool ParseJsonPath(
- const std::string& path,
- std::string* command,
- std::string* target_id) {
-
- // Fall back to list in case of empty query.
- if (path.empty()) {
- *command = "list";
- return true;
- }
-
- if (path.find("/") != 0) {
- // Malformed command.
- return false;
- }
- *command = path.substr(1);
-
- size_t separator_pos = command->find("/");
- if (separator_pos != std::string::npos) {
- *target_id = command->substr(separator_pos + 1);
- *command = command->substr(0, separator_pos);
- }
- return true;
-}
-
-void DevToolsHttpHandlerImpl::OnJsonRequestUI(
- int connection_id,
- const net::HttpServerRequestInfo& info) {
- // Trim /json
- std::string path = info.path.substr(5);
-
- // Trim fragment and query
- std::string query;
- size_t query_pos = path.find("?");
- if (query_pos != std::string::npos) {
- query = path.substr(query_pos + 1);
- path = path.substr(0, query_pos);
- }
-
- size_t fragment_pos = path.find("#");
- if (fragment_pos != std::string::npos)
- path = path.substr(0, fragment_pos);
-
- std::string command;
- std::string target_id;
- if (!ParseJsonPath(path, &command, &target_id)) {
- SendJson(connection_id,
- net::HTTP_NOT_FOUND,
- NULL,
- "Malformed query: " + info.path);
- return;
- }
-
- if (command == "version") {
- base::DictionaryValue version;
- version.SetString("Protocol-Version", devtools::kProtocolVersion);
- version.SetString("WebKit-Version", GetWebKitVersion());
- version.SetString("Browser", GetContentClient()->GetProduct());
- version.SetString("User-Agent", GetContentClient()->GetUserAgent());
-#if defined(OS_ANDROID)
- version.SetString("Android-Package",
- base::android::BuildInfo::GetInstance()->package_name());
-#endif
- SendJson(connection_id, net::HTTP_OK, &version, std::string());
- return;
- }
-
- if (command == "list") {
- std::string host = info.headers["host"];
- AddRef(); // Balanced in OnTargetListReceived.
- 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;
- }
-
- if (command == "new") {
- GURL url(net::UnescapeURLComponent(
- query, net::UnescapeRule::URL_SPECIAL_CHARS));
- if (!url.is_valid())
- url = GURL(url::kAboutBlankURL);
- 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,
- NULL,
- "Could not create new page");
- return;
- }
- std::string host = info.headers["host"];
- scoped_ptr<base::DictionaryValue> dictionary(
- SerializeTarget(*target.get(), host));
- SendJson(connection_id, net::HTTP_OK, dictionary.get(), std::string());
- const std::string target_id = target->GetId();
- target_map_[target_id] = target.release();
- return;
- }
-
- if (command == "activate" || command == "close") {
- DevToolsTarget* target = GetTarget(target_id);
- if (!target) {
- SendJson(connection_id,
- net::HTTP_NOT_FOUND,
- NULL,
- "No such target id: " + target_id);
- return;
- }
-
- if (command == "activate") {
- if (target->Activate()) {
- SendJson(connection_id, net::HTTP_OK, NULL, "Target activated");
- } else {
- SendJson(connection_id,
- net::HTTP_INTERNAL_SERVER_ERROR,
- NULL,
- "Could not activate target id: " + target_id);
- }
- return;
- }
-
- if (command == "close") {
- if (target->Close()) {
- SendJson(connection_id, net::HTTP_OK, NULL, "Target is closing");
- } else {
- SendJson(connection_id,
- net::HTTP_INTERNAL_SERVER_ERROR,
- NULL,
- "Could not close target id: " + target_id);
- }
- return;
- }
- }
- SendJson(connection_id,
- net::HTTP_NOT_FOUND,
- NULL,
- "Unknown command: " + command);
- return;
-}
-
-void DevToolsHttpHandlerImpl::OnTargetListReceived(
- int connection_id,
- const std::string& host,
- 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 (DevToolsManagerDelegate::TargetList::const_iterator it =
- sorted_targets.begin(); it != sorted_targets.end(); ++it) {
- DevToolsTarget* target = *it;
- target_map_[target->GetId()] = target;
- list_value.Append(SerializeTarget(*target, host));
- }
- SendJson(connection_id, net::HTTP_OK, &list_value, std::string());
- Release(); // Balanced in OnJsonRequestUI.
-}
-
-DevToolsTarget* DevToolsHttpHandlerImpl::GetTarget(const std::string& id) {
- TargetMap::const_iterator it = target_map_.find(id);
- if (it == target_map_.end())
- return NULL;
- return it->second;
-}
-
-void DevToolsHttpHandlerImpl::OnThumbnailRequestUI(
- int connection_id, const GURL& 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
- Send404(connection_id);
-}
-
-void DevToolsHttpHandlerImpl::OnDiscoveryPageRequestUI(int connection_id) {
- std::string response = delegate_->GetDiscoveryPageHTML();
- Send200(connection_id, response, "text/html; charset=UTF-8");
-}
-
-void DevToolsHttpHandlerImpl::OnWebSocketRequestUI(
- int connection_id,
- const net::HttpServerRequestInfo& request) {
- 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);
- return;
- }
-
- std::string page_id = request.path.substr(strlen(kPageUrlPrefix));
- DevToolsTarget* target = GetTarget(page_id);
- scoped_refptr<DevToolsAgentHost> agent =
- target ? target->GetAgentHost() : NULL;
- if (!agent.get()) {
- Send500(connection_id, "No such target id: " + page_id);
- return;
- }
-
- if (agent->IsAttached()) {
- Send500(connection_id,
- "Target with given id is being inspected: " + page_id);
- return;
- }
-
- 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);
-}
-
-void DevToolsHttpHandlerImpl::OnWebSocketMessageUI(
- int connection_id,
- const std::string& data) {
- 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;
-
- DevToolsAgentHostClientImpl* client =
- static_cast<DevToolsAgentHostClientImpl*>(it->second);
- client->OnMessage(data);
-}
-
-void DevToolsHttpHandlerImpl::OnCloseUI(int 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(
- scoped_ptr<ServerSocketFactory> server_socket_factory,
- const std::string& frontend_url,
- DevToolsHttpHandlerDelegate* delegate,
- const base::FilePath& active_port_output_directory)
- : frontend_url_(frontend_url),
- 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";
-
- // Balanced in ResetHandlerThreadAndRelease().
- AddRef();
-}
-
-// Runs on the handler thread
-void DevToolsHttpHandlerImpl::Init() {
- 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_.reset();
-}
-
-// Runs on FILE thread to make sure that it is serialized against
-// {Start|Stop}HandlerThread and to allow calling pthread_join.
-void DevToolsHttpHandlerImpl::StopHandlerThread() {
- if (!thread_->message_loop())
- return;
- thread_->message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&DevToolsHttpHandlerImpl::Teardown, this));
- // Thread::Stop joins the thread.
- thread_->Stop();
-}
-
-void DevToolsHttpHandlerImpl::WriteActivePortToUserProfile() {
- DCHECK(!active_port_output_directory_.empty());
- net::IPEndPoint endpoint;
- int err;
- if ((err = server_->GetLocalAddress(&endpoint)) != net::OK) {
- LOG(ERROR) << "Error " << err << " getting local address";
- return;
- }
-
- // Write this port to a well-known file in the profile directory
- // so Telemetry can pick it up.
- base::FilePath path = active_port_output_directory_.Append(
- kDevToolsActivePortFileName);
- std::string port_string = base::IntToString(endpoint.port());
- if (base::WriteFile(path, port_string.c_str(), port_string.length()) < 0) {
- LOG(ERROR) << "Error writing DevTools active port to file";
- }
-}
-
-void DevToolsHttpHandlerImpl::SendJson(int connection_id,
- net::HttpStatusCode status_code,
- base::Value* value,
- const std::string& message) {
- if (!thread_)
- return;
-
- // Serialize value and message.
- std::string json_value;
- if (value) {
- base::JSONWriter::WriteWithOptions(value,
- base::JSONWriter::OPTIONS_PRETTY_PRINT,
- &json_value);
- }
- std::string json_message;
- scoped_ptr<base::Value> message_object(new base::StringValue(message));
- base::JSONWriter::Write(message_object.get(), &json_message);
-
- net::HttpServerResponseInfo response(status_code);
- response.SetBody(json_value + message, "application/json; charset=UTF-8");
-
- thread_->message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&net::HttpServer::SendResponse,
- base::Unretained(server_.get()),
- connection_id,
- response));
-}
-
-void DevToolsHttpHandlerImpl::Send200(int connection_id,
- const std::string& data,
- const std::string& mime_type) {
- if (!thread_)
- return;
- thread_->message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&net::HttpServer::Send200,
- base::Unretained(server_.get()),
- connection_id,
- data,
- mime_type));
-}
-
-void DevToolsHttpHandlerImpl::Send404(int connection_id) {
- if (!thread_)
- return;
- thread_->message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&net::HttpServer::Send404,
- base::Unretained(server_.get()),
- connection_id));
-}
-
-void DevToolsHttpHandlerImpl::Send500(int connection_id,
- const std::string& message) {
- if (!thread_)
- return;
- thread_->message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&net::HttpServer::Send500,
- base::Unretained(server_.get()),
- connection_id,
- message));
-}
-
-void DevToolsHttpHandlerImpl::AcceptWebSocket(
- int connection_id,
- const net::HttpServerRequestInfo& request) {
- if (!thread_)
- return;
- thread_->message_loop()->PostTask(
- FROM_HERE,
- 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(
- const DevToolsTarget& target,
- const std::string& host) {
- base::DictionaryValue* dictionary = new base::DictionaryValue;
-
- std::string id = target.GetId();
- dictionary->SetString(kTargetIdField, id);
- std::string parent_id = target.GetParentId();
- if (!parent_id.empty())
- dictionary->SetString(kTargetParentIdField, parent_id);
- dictionary->SetString(kTargetTypeField, target.GetType());
- dictionary->SetString(kTargetTitleField,
- net::EscapeForHTML(target.GetTitle()));
- dictionary->SetString(kTargetDescriptionField, target.GetDescription());
-
- GURL url = target.GetURL();
- dictionary->SetString(kTargetUrlField, url.spec());
-
- GURL favicon_url = target.GetFaviconURL();
- if (favicon_url.is_valid())
- dictionary->SetString(kTargetFaviconUrlField, favicon_url.spec());
-
- DevToolsManagerDelegate* manager_delegate =
- DevToolsManager::GetInstance()->delegate();
- if (manager_delegate &&
- !manager_delegate->GetPageThumbnailData(url).empty()) {
- dictionary->SetString(kTargetThumbnailUrlField,
- std::string(kThumbUrlPrefix) + id);
- }
-
- if (!target.IsAttached()) {
- dictionary->SetString(kTargetWebSocketDebuggerUrlField,
- base::StringPrintf("ws://%s%s%s",
- host.c_str(),
- kPageUrlPrefix,
- id.c_str()));
- std::string devtools_frontend_url = GetFrontendURLInternal(
- id.c_str(),
- host);
- dictionary->SetString(
- kTargetDevtoolsFrontendUrlField, devtools_frontend_url);
- }
-
- return dictionary;
-}
-
-} // namespace content
diff --git a/chromium/content/browser/devtools/devtools_http_handler_impl.h b/chromium/content/browser/devtools/devtools_http_handler_impl.h
deleted file mode 100644
index 5750dede955..00000000000
--- a/chromium/content/browser/devtools/devtools_http_handler_impl.h
+++ /dev/null
@@ -1,138 +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_HTTP_HANDLER_IMPL_H_
-#define CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_HTTP_HANDLER_IMPL_H_
-
-#include <map>
-#include <set>
-#include <string>
-#include <vector>
-
-#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"
-
-namespace base {
-class DictionaryValue;
-class ListValue;
-class Thread;
-class Value;
-}
-
-namespace net {
-class ServerSocketFactory;
-class URLRequestContextGetter;
-}
-
-namespace content {
-
-class DevToolsHttpHandlerImpl
- : public DevToolsHttpHandler,
- public base::RefCountedThreadSafe<DevToolsHttpHandlerImpl>,
- public net::HttpServer::Delegate {
- private:
- friend class base::RefCountedThreadSafe<DevToolsHttpHandlerImpl>;
- friend class DevToolsHttpHandler;
-
- class BrowserTarget;
-
- DevToolsHttpHandlerImpl(scoped_ptr<ServerSocketFactory> server_socket_factory,
- const std::string& frontend_url,
- DevToolsHttpHandlerDelegate* delegate,
- const base::FilePath& active_port_output_directory);
- ~DevToolsHttpHandlerImpl() override;
- void Start();
-
- // DevToolsHttpHandler implementation.
- void Stop() override;
- GURL GetFrontendURL() override;
-
- // net::HttpServer::Delegate implementation.
- 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);
- void OnThumbnailRequestUI(int connection_id, const GURL& page_url);
- void OnDiscoveryPageRequestUI(int connection_id);
-
- void OnWebSocketRequestUI(int connection_id,
- const net::HttpServerRequestInfo& info);
- void OnWebSocketMessageUI(int connection_id, const std::string& data);
- void OnCloseUI(int connection_id);
-
- void ResetHandlerThread();
- void ResetHandlerThreadAndRelease();
-
- void OnTargetListReceived(
- int connection_id,
- const std::string& host,
- const DevToolsManagerDelegate::TargetList& targets);
-
- void OnHttpServerInitialized(const net::IPEndPoint& ip_address);
-
- DevToolsTarget* GetTarget(const std::string& id);
-
- void Init();
- void Teardown();
-
- void StartHandlerThread();
- void StopHandlerThread();
- void StopWithoutRelease();
-
- void WriteActivePortToUserProfile();
-
- void SendJson(int connection_id,
- net::HttpStatusCode status_code,
- base::Value* value,
- const std::string& message);
- void Send200(int connection_id,
- const std::string& data,
- const std::string& mime_type);
- void Send404(int connection_id);
- void Send500(int connection_id,
- const std::string& message);
- void AcceptWebSocket(int connection_id,
- const net::HttpServerRequestInfo& request);
-
- // Returns the front end url without the host at the beginning.
- std::string GetFrontendURLInternal(const std::string target_id,
- const std::string& host);
-
- base::DictionaryValue* SerializeTarget(const DevToolsTarget& target,
- const std::string& host);
-
- // The thread used by the devtools handler to run server socket.
- scoped_ptr<base::Thread> thread_;
-
- std::string frontend_url_;
- 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, BrowserTarget*> BrowserTargets;
- BrowserTargets browser_targets_;
- DISALLOW_COPY_AND_ASSIGN(DevToolsHttpHandlerImpl);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_HTTP_HANDLER_IMPL_H_
diff --git a/chromium/content/browser/devtools/devtools_http_handler_unittest.cc b/chromium/content/browser/devtools/devtools_http_handler_unittest.cc
deleted file mode 100644
index 28630ead75a..00000000000
--- a/chromium/content/browser/devtools/devtools_http_handler_unittest.cc
+++ /dev/null
@@ -1,165 +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 "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 "base/strings/string_number_conversions.h"
-#include "content/browser/browser_thread_impl.h"
-#include "content/public/browser/devtools_http_handler.h"
-#include "content/public/browser/devtools_http_handler_delegate.h"
-#include "content/public/browser/devtools_target.h"
-#include "net/base/ip_endpoint.h"
-#include "net/base/net_errors.h"
-#include "net/socket/server_socket.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace content {
-namespace {
-
-const int kDummyPort = 4321;
-const base::FilePath::CharType kDevToolsActivePortFileName[] =
- FILE_PATH_LITERAL("DevToolsActivePort");
-
-class DummyServerSocket : public net::ServerSocket {
- public:
- 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 DummyServerSocketFactory
- : public DevToolsHttpHandler::ServerSocketFactory {
- public:
- 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_);
- }
-
- private:
- scoped_ptr<net::ServerSocket> Create() const override {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE, quit_closure_1_);
- return scoped_ptr<net::ServerSocket>(new DummyServerSocket());
- }
-
- base::Closure quit_closure_1_;
- base::Closure quit_closure_2_;
-};
-
-class DummyDelegate : public DevToolsHttpHandlerDelegate {
- public:
- 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>();
- }
-};
-
-}
-
-class DevToolsHttpHandlerTest : public testing::Test {
- public:
- DevToolsHttpHandlerTest()
- : ui_thread_(BrowserThread::UI, &message_loop_) {
- }
-
- protected:
- void SetUp() override {
- file_thread_.reset(new BrowserThreadImpl(BrowserThread::FILE));
- file_thread_->Start();
- }
-
- void TearDown() override { file_thread_->Stop(); }
-
- private:
- base::MessageLoopForIO message_loop_;
- BrowserThreadImpl ui_thread_;
- scoped_ptr<BrowserThreadImpl> file_thread_;
-};
-
-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(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();
- devtools_http_handler_->Stop();
- // Make sure the handler actually stops.
- run_loop_2.Run();
-}
-
-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(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();
- devtools_http_handler_->Stop();
- // Make sure the handler actually stops.
- run_loop_2.Run();
-
- // Now make sure the DevToolsActivePort was written into the
- // temporary directory and its contents are as expected.
- base::FilePath active_port_file = temp_dir.path().Append(
- kDevToolsActivePortFileName);
- EXPECT_TRUE(base::PathExists(active_port_file));
- std::string file_contents;
- EXPECT_TRUE(base::ReadFileToString(active_port_file, &file_contents));
- int port = 0;
- EXPECT_TRUE(base::StringToInt(file_contents, &port));
- EXPECT_EQ(kDummyPort, port);
-}
-
-} // namespace content
diff --git a/chromium/content/browser/devtools/devtools_manager.cc b/chromium/content/browser/devtools/devtools_manager.cc
index f405185a24d..1fa19d88d93 100644
--- a/chromium/content/browser/devtools/devtools_manager.cc
+++ b/chromium/content/browser/devtools/devtools_manager.cc
@@ -10,16 +10,9 @@
#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();
@@ -27,104 +20,32 @@ DevToolsManager* DevToolsManager::GetInstance() {
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))) {
+ attached_hosts_count_(0) {
}
DevToolsManager::~DevToolsManager() {
- DCHECK(!attached_hosts_.size());
- update_target_list_callback_.Cancel();
+ DCHECK(!attached_hosts_count_);
}
-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()) {
+void DevToolsManager::AgentHostStateChanged(
+ DevToolsAgentHostImpl* agent_host, bool attached) {
+ if (attached) {
+ if (!attached_hosts_count_) {
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()) {
+ ++attached_hosts_count_;
+ } else {
+ --attached_hosts_count_;
+ if (!attached_hosts_count_) {
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
index 979424f1c66..3e29a7a2c06 100644
--- a/chromium/content/browser/devtools/devtools_manager.h
+++ b/chromium/content/browser/devtools/devtools_manager.h
@@ -5,40 +5,20 @@
#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;
+class DevToolsAgentHostImpl;
// This class is a singleton that manage global DevTools state for the whole
// browser.
+// TODO(dgozman): remove this class entirely.
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();
@@ -48,29 +28,13 @@ class CONTENT_EXPORT 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);
+ void AgentHostStateChanged(DevToolsAgentHostImpl* agent_host, bool attached);
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_;
+ int attached_hosts_count_;
DISALLOW_COPY_AND_ASSIGN(DevToolsManager);
};
diff --git a/chromium/content/browser/devtools/devtools_manager_unittest.cc b/chromium/content/browser/devtools/devtools_manager_unittest.cc
index 988ffb752fb..cd632c1aeca 100644
--- a/chromium/content/browser/devtools/devtools_manager_unittest.cc
+++ b/chromium/content/browser/devtools/devtools_manager_unittest.cc
@@ -6,8 +6,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/time/time.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/devtools/shared_worker_devtools_manager.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"
@@ -16,7 +15,6 @@
#include "content/public/browser/devtools_agent_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"
@@ -96,125 +94,17 @@ 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) {}
+ DevToolsManagerTest() {}
protected:
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) {
@@ -234,8 +124,10 @@ TEST_F(DevToolsManagerTest, OpenAndManuallyCloseDevToolsClientHost) {
}
TEST_F(DevToolsManagerTest, NoUnresponsiveDialogInInspectedContents) {
+ const GURL url("http://www.google.com");
+ contents()->NavigateAndCommit(url);
TestRenderViewHost* inspected_rvh = test_rvh();
- inspected_rvh->set_render_view_created(true);
+ EXPECT_TRUE(inspected_rvh->IsRenderViewLive());
EXPECT_FALSE(contents()->GetDelegate());
TestWebContentsDelegate delegate;
contents()->SetDelegate(&delegate);
@@ -275,9 +167,11 @@ TEST_F(DevToolsManagerTest, ReattachOnCancelPendingNavigation) {
const GURL url("http://www.google.com");
controller().LoadURL(
url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- contents()->TestDidNavigate(
- contents()->GetMainFrame(), 1, url, ui::PAGE_TRANSITION_TYPED);
- EXPECT_FALSE(contents()->cross_navigation_pending());
+ int pending_id = controller().GetPendingEntry()->GetUniqueID();
+ contents()->GetMainFrame()->PrepareForCommit();
+ contents()->TestDidNavigate(contents()->GetMainFrame(), 1, pending_id, true,
+ url, ui::PAGE_TRANSITION_TYPED);
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
TestDevToolsClientHost client_host;
client_host.InspectAgentHost(
@@ -287,16 +181,19 @@ TEST_F(DevToolsManagerTest, ReattachOnCancelPendingNavigation) {
const GURL url2("http://www.yahoo.com");
controller().LoadURL(
url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- EXPECT_TRUE(contents()->cross_navigation_pending());
+ contents()->GetMainFrame()->PrepareForCommit();
+ EXPECT_TRUE(contents()->CrossProcessNavigationPending());
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(), ui::PAGE_TRANSITION_TYPED, std::string());
- contents()->TestDidNavigate(
- contents()->GetMainFrame(), 1, url, ui::PAGE_TRANSITION_TYPED);
- EXPECT_FALSE(contents()->cross_navigation_pending());
+ pending_id = controller().GetPendingEntry()->GetUniqueID();
+ contents()->GetMainFrame()->PrepareForCommit();
+ contents()->TestDidNavigate(contents()->GetMainFrame(), 1, pending_id, false,
+ url, ui::PAGE_TRANSITION_TYPED);
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
EXPECT_EQ(client_host.agent_host(),
DevToolsAgentHost::GetOrCreateFor(web_contents()).get());
client_host.Close();
@@ -351,110 +248,4 @@ TEST_F(DevToolsManagerTest, TestExternalProxy) {
client_host.Close();
}
-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.cc b/chromium/content/browser/devtools/devtools_netlog_observer.cc
index 27ce58ae49b..f20ef34b9a0 100644
--- a/chromium/content/browser/devtools/devtools_netlog_observer.cc
+++ b/chromium/content/browser/devtools/devtools_netlog_observer.cc
@@ -46,7 +46,7 @@ void DevToolsNetLogObserver::OnAddEntry(const net::NetLog::Entry& entry) {
void DevToolsNetLogObserver::OnAddURLRequestEntry(
const net::NetLog::Entry& entry) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
bool is_begin = entry.phase() == net::NetLog::PHASE_BEGIN;
bool is_end = entry.phase() == net::NetLog::PHASE_END;
@@ -106,7 +106,7 @@ void DevToolsNetLogObserver::OnAddURLRequestEntry(
info->request_headers_text = request_line + request_headers.ToString();
break;
}
- case net::NetLog::TYPE_HTTP_TRANSACTION_SPDY_SEND_REQUEST_HEADERS: {
+ case net::NetLog::TYPE_HTTP_TRANSACTION_HTTP2_SEND_REQUEST_HEADERS: {
scoped_ptr<base::Value> event_params(entry.ParametersToValue());
net::SpdyHeaderBlock request_headers;
@@ -169,24 +169,25 @@ void DevToolsNetLogObserver::Attach() {
net::NetLog* net_log = GetContentClient()->browser()->GetNetLog();
if (net_log) {
instance_ = new DevToolsNetLogObserver();
- net_log->AddThreadSafeObserver(instance_, net::NetLog::LOG_ALL_BUT_BYTES);
+ net_log->DeprecatedAddObserver(
+ instance_, net::NetLogCaptureMode::IncludeCookiesAndCredentials());
}
}
void DevToolsNetLogObserver::Detach() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (instance_) {
// Safest not to do this in the destructor to maintain thread safety across
// refactorings.
- instance_->net_log()->RemoveThreadSafeObserver(instance_);
+ instance_->net_log()->DeprecatedRemoveObserver(instance_);
delete instance_;
instance_ = NULL;
}
}
DevToolsNetLogObserver* DevToolsNetLogObserver::GetInstance() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
return instance_;
}
diff --git a/chromium/content/browser/devtools/devtools_netlog_observer.h b/chromium/content/browser/devtools/devtools_netlog_observer.h
index 2155f06a11f..da58589b301 100644
--- a/chromium/content/browser/devtools/devtools_netlog_observer.h
+++ b/chromium/content/browser/devtools/devtools_netlog_observer.h
@@ -8,7 +8,7 @@
#include "base/containers/hash_tables.h"
#include "base/memory/ref_counted.h"
#include "content/public/common/resource_devtools_info.h"
-#include "net/base/net_log.h"
+#include "net/log/net_log.h"
namespace net {
class URLRequest;
diff --git a/chromium/content/browser/devtools/devtools_protocol.cc b/chromium/content/browser/devtools/devtools_protocol.cc
deleted file mode 100644
index e3d531489d5..00000000000
--- a/chromium/content/browser/devtools/devtools_protocol.cc
+++ /dev/null
@@ -1,331 +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/devtools_protocol.h"
-
-#include "base/json/json_reader.h"
-#include "base/json/json_writer.h"
-#include "base/strings/stringprintf.h"
-
-namespace content {
-
-namespace {
-
-const char kIdParam[] = "id";
-const char kMethodParam[] = "method";
-const char kParamsParam[] = "params";
-const char kResultParam[] = "result";
-const char kErrorParam[] = "error";
-const char kErrorCodeParam[] = "code";
-const char kErrorMessageParam[] = "message";
-const int kNoId = -1;
-
-// JSON RPC 2.0 spec: http://www.jsonrpc.org/specification#error_object
-enum Error {
- kErrorParseError = -32700,
- kErrorInvalidRequest = -32600,
- kErrorNoSuchMethod = -32601,
- kErrorInvalidParams = -32602,
- kErrorInternalError = -32603,
- kErrorServerError = -32000
-};
-
-} // namespace
-
-using base::Value;
-
-DevToolsProtocol::Message::~Message() {
-}
-
-DevToolsProtocol::Message::Message(const std::string& method,
- base::DictionaryValue* params)
- : method_(method),
- params_(params) {
- size_t pos = method.find(".");
- if (pos != std::string::npos && pos > 0)
- domain_ = method.substr(0, pos);
-}
-
-DevToolsProtocol::Command::~Command() {
-}
-
-std::string DevToolsProtocol::Command::Serialize() {
- base::DictionaryValue command;
- command.SetInteger(kIdParam, id_);
- command.SetString(kMethodParam, method_);
- if (params_)
- command.Set(kParamsParam, params_->DeepCopy());
-
- std::string json_command;
- base::JSONWriter::Write(&command, &json_command);
- return json_command;
-}
-
-scoped_refptr<DevToolsProtocol::Response>
-DevToolsProtocol::Command::SuccessResponse(base::DictionaryValue* result) {
- return new DevToolsProtocol::Response(id_, result);
-}
-
-scoped_refptr<DevToolsProtocol::Response>
-DevToolsProtocol::Command::InternalErrorResponse(const std::string& message) {
- return new DevToolsProtocol::Response(id_, kErrorInternalError, message);
-}
-
-scoped_refptr<DevToolsProtocol::Response>
-DevToolsProtocol::Command::InvalidParamResponse(const std::string& param) {
- std::string message =
- base::StringPrintf("Missing or invalid '%s' parameter", param.c_str());
- return new DevToolsProtocol::Response(id_, kErrorInvalidParams, message);
-}
-
-scoped_refptr<DevToolsProtocol::Response>
-DevToolsProtocol::Command::NoSuchMethodErrorResponse() {
- return new Response(id_, kErrorNoSuchMethod, "No such method");
-}
-
-scoped_refptr<DevToolsProtocol::Response>
-DevToolsProtocol::Command::ServerErrorResponse(const std::string& message) {
- return new Response(id_, kErrorServerError, message);
-}
-
-scoped_refptr<DevToolsProtocol::Response>
-DevToolsProtocol::Command::AsyncResponsePromise() {
- scoped_refptr<DevToolsProtocol::Response> promise =
- new DevToolsProtocol::Response(0, NULL);
- promise->is_async_promise_ = true;
- return promise;
-}
-
-DevToolsProtocol::Command::Command(int id,
- const std::string& method,
- base::DictionaryValue* params)
- : Message(method, params),
- id_(id) {
-}
-
-DevToolsProtocol::Response::~Response() {
-}
-
-std::string DevToolsProtocol::Response::Serialize() {
- base::DictionaryValue response;
-
- if (id_ != kNoId)
- response.SetInteger(kIdParam, id_);
-
- if (error_code_) {
- base::DictionaryValue* error_object = new base::DictionaryValue();
- response.Set(kErrorParam, error_object);
- 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
- response.Set(kResultParam, new base::DictionaryValue());
- }
-
- std::string json_response;
- base::JSONWriter::Write(&response, &json_response);
- return json_response;
-}
-
-DevToolsProtocol::Response::Response(int id, base::DictionaryValue* result)
- : id_(id),
- result_(result),
- error_code_(0),
- is_async_promise_(false) {
-}
-
-DevToolsProtocol::Response::Response(int id,
- int error_code,
- const std::string& error_message)
- : id_(id),
- error_code_(error_code),
- error_message_(error_message),
- is_async_promise_(false) {
-}
-
-DevToolsProtocol::Notification::Notification(const std::string& method,
- base::DictionaryValue* params)
- : Message(method, params) {
-}
-
-DevToolsProtocol::Notification::~Notification() {
-}
-
-std::string DevToolsProtocol::Notification::Serialize() {
- base::DictionaryValue notification;
- notification.SetString(kMethodParam, method_);
- if (params_)
- notification.Set(kParamsParam, params_->DeepCopy());
-
- std::string json_notification;
- base::JSONWriter::Write(&notification, &json_notification);
- return json_notification;
-}
-
-DevToolsProtocol::Handler::~Handler() {
-}
-
-scoped_refptr<DevToolsProtocol::Response>
-DevToolsProtocol::Handler::HandleCommand(
- scoped_refptr<DevToolsProtocol::Command> command) {
- CommandHandlers::iterator it = command_handlers_.find(command->method());
- if (it == command_handlers_.end())
- return NULL;
- return (it->second).Run(command);
-}
-
-void DevToolsProtocol::Handler::SetNotifier(const Notifier& notifier) {
- notifier_ = notifier;
-}
-
-DevToolsProtocol::Handler::Handler() {
-}
-
-void DevToolsProtocol::Handler::RegisterCommandHandler(
- const std::string& command,
- const CommandHandler& handler) {
- command_handlers_[command] = handler;
-}
-
-void DevToolsProtocol::Handler::SendNotification(
- const std::string& method,
- base::DictionaryValue* params) {
- scoped_refptr<DevToolsProtocol::Notification> notification =
- new DevToolsProtocol::Notification(method, params);
- SendRawMessage(notification->Serialize());
-}
-
-void DevToolsProtocol::Handler::SendAsyncResponse(
- scoped_refptr<DevToolsProtocol::Response> response) {
- SendRawMessage(response->Serialize());
-}
-
-void DevToolsProtocol::Handler::SendRawMessage(const std::string& message) {
- if (!notifier_.is_null())
- notifier_.Run(message);
-}
-
-static bool ParseMethod(base::DictionaryValue* command,
- std::string* method) {
- if (!command->GetString(kMethodParam, method))
- return false;
- size_t pos = method->find(".");
- if (pos == std::string::npos || pos == 0)
- return false;
- return true;
-}
-
-// static
-scoped_refptr<DevToolsProtocol::Command> DevToolsProtocol::ParseCommand(
- const std::string& json,
- std::string* error_response) {
- scoped_ptr<base::DictionaryValue> command_dict(
- ParseMessage(json, error_response));
- return ParseCommand(command_dict.get(), error_response);
-}
-
-// static
-scoped_refptr<DevToolsProtocol::Command> DevToolsProtocol::ParseCommand(
- base::DictionaryValue* command_dict,
- std::string* error_response) {
- if (!command_dict)
- return NULL;
-
- int id;
- std::string method;
- bool ok = command_dict->GetInteger(kIdParam, &id) && id >= 0;
- ok = ok && ParseMethod(command_dict, &method);
- if (!ok) {
- scoped_refptr<Response> response =
- new Response(kNoId, kErrorInvalidRequest, "No such method");
- *error_response = response->Serialize();
- return NULL;
- }
-
- base::DictionaryValue* params = NULL;
- command_dict->GetDictionary(kParamsParam, &params);
- return new Command(id, method, params ? params->DeepCopy() : NULL);
-}
-
-// static
-scoped_refptr<DevToolsProtocol::Command>
-DevToolsProtocol::CreateCommand(
- int id,
- const std::string& method,
- base::DictionaryValue* params) {
- return new Command(id, method, params);
-}
-
-//static
-scoped_refptr<DevToolsProtocol::Response>
-DevToolsProtocol::ParseResponse(
- base::DictionaryValue* response_dict) {
- int id;
- if (!response_dict->GetInteger(kIdParam, &id))
- id = kNoId;
-
- const base::DictionaryValue* error_dict;
- if (response_dict->GetDictionary(kErrorParam, &error_dict)) {
- int error_code = kErrorInternalError;
- response_dict->GetInteger(kErrorCodeParam, &error_code);
- std::string error_message;
- response_dict->GetString(kErrorMessageParam, &error_message);
- return new Response(id, error_code, error_message);
- }
-
- const base::DictionaryValue* result = NULL;
- response_dict->GetDictionary(kResultParam, &result);
- return new Response(id, result ? result->DeepCopy() : NULL);
-}
-
-// static
-scoped_refptr<DevToolsProtocol::Notification>
-DevToolsProtocol::ParseNotification(const std::string& json) {
- scoped_ptr<base::DictionaryValue> dict(ParseMessage(json, NULL));
- if (!dict)
- return NULL;
-
- std::string method;
- bool ok = ParseMethod(dict.get(), &method);
- if (!ok)
- return NULL;
-
- base::DictionaryValue* params = NULL;
- dict->GetDictionary(kParamsParam, &params);
- return new Notification(method, params ? params->DeepCopy() : NULL);
-}
-
-//static
-scoped_refptr<DevToolsProtocol::Notification>
-DevToolsProtocol::CreateNotification(
- const std::string& method,
- base::DictionaryValue* params) {
- return new Notification(method, params);
-}
-
-// static
-base::DictionaryValue* DevToolsProtocol::ParseMessage(
- const std::string& json,
- std::string* error_response) {
- int parse_error_code;
- std::string error_message;
- scoped_ptr<base::Value> message(
- base::JSONReader::ReadAndReturnError(
- json, 0, &parse_error_code, &error_message));
-
- if (!message || !message->IsType(base::Value::TYPE_DICTIONARY)) {
- scoped_refptr<Response> response =
- new Response(0, kErrorParseError, error_message);
- if (error_response)
- *error_response = response->Serialize();
- return NULL;
- }
-
- return static_cast<base::DictionaryValue*>(message.release());
-}
-
-} // namespace content
diff --git a/chromium/content/browser/devtools/devtools_protocol.h b/chromium/content/browser/devtools/devtools_protocol.h
deleted file mode 100644
index 50dc8a649dc..00000000000
--- a/chromium/content/browser/devtools/devtools_protocol.h
+++ /dev/null
@@ -1,195 +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_DEVTOOLS_PROTOCOL_H_
-#define CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_PROTOCOL_H_
-
-#include <map>
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/callback.h"
-#include "base/compiler_specific.h"
-#include "base/memory/ref_counted.h"
-#include "base/values.h"
-#include "content/common/content_export.h"
-
-namespace content {
-
-// Utility classes for processing DevTools remote debugging messages.
-// https://developers.google.com/chrome-developer-tools/docs/debugger-protocol
-class DevToolsProtocol {
- public:
- typedef base::Callback<void(const std::string& message)> Notifier;
-
- class Response;
-
- class Message : public base::RefCountedThreadSafe<Message> {
- public:
- std::string domain() { return domain_; }
- std::string method() { return method_; }
- base::DictionaryValue* params() { return params_.get(); }
- virtual std::string Serialize() = 0;
-
- protected:
- friend class base::RefCountedThreadSafe<Message>;
- virtual ~Message();
- Message(const std::string& method,
- base::DictionaryValue* params);
-
- std::string domain_;
- std::string method_;
- scoped_ptr<base::DictionaryValue> params_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Message);
- };
-
- class Command : public Message {
- public:
- int id() { return id_; }
-
- std::string Serialize() override;
-
- // Creates success response. Takes ownership of |result|.
- scoped_refptr<Response> SuccessResponse(base::DictionaryValue* result);
-
- // Creates error response.
- scoped_refptr<Response> InternalErrorResponse(const std::string& message);
-
- // Creates error response.
- scoped_refptr<Response> InvalidParamResponse(const std::string& param);
-
- // Creates error response.
- scoped_refptr<Response> NoSuchMethodErrorResponse();
-
- // Creates error response.
- scoped_refptr<Response> ServerErrorResponse(const std::string& message);
-
- // Creates async response promise.
- scoped_refptr<Response> AsyncResponsePromise();
-
- protected:
- ~Command() override;
-
- private:
- friend class DevToolsProtocol;
- Command(int id, const std::string& method,
- base::DictionaryValue* params);
-
- int id_;
-
- DISALLOW_COPY_AND_ASSIGN(Command);
- };
-
- class Response : public base::RefCountedThreadSafe<Response> {
- public:
- std::string Serialize();
-
- bool is_async_promise() { return is_async_promise_; }
-
- private:
- friend class base::RefCountedThreadSafe<Response>;
- friend class Command;
- friend class DevToolsProtocol;
- virtual ~Response();
-
- Response(int id, base::DictionaryValue* result);
- Response(int id, int error_code, const std::string& error_message);
-
- int id_;
- scoped_ptr<base::DictionaryValue> result_;
- int error_code_;
- std::string error_message_;
- bool is_async_promise_;
-
- DISALLOW_COPY_AND_ASSIGN(Response);
- };
-
- class Notification : public Message {
- public:
- std::string Serialize() override;
-
- private:
- friend class DevToolsProtocol;
- friend class DevToolsProtocolClient;
- ~Notification() override;
-
- // Takes ownership of |params|.
- Notification(const std::string& method,
- base::DictionaryValue* params);
-
- DISALLOW_COPY_AND_ASSIGN(Notification);
- };
-
- class CONTENT_EXPORT Handler {
- public:
- typedef base::Callback<scoped_refptr<DevToolsProtocol::Response>(
- scoped_refptr<DevToolsProtocol::Command> command)> CommandHandler;
-
- virtual ~Handler();
-
- virtual scoped_refptr<DevToolsProtocol::Response> HandleCommand(
- scoped_refptr<DevToolsProtocol::Command> command);
-
- void SetNotifier(const Notifier& notifier);
-
- protected:
- Handler();
-
- void RegisterCommandHandler(const std::string& command,
- const CommandHandler& handler);
-
- // Sends notification to the client. Takes ownership of |params|.
- void SendNotification(const std::string& method,
- base::DictionaryValue* params);
-
- void SendAsyncResponse(scoped_refptr<DevToolsProtocol::Response> response);
-
- // Sends message to client, the caller is presumed to properly
- // format the message.
- void SendRawMessage(const std::string& message);
-
- private:
- typedef std::map<std::string, CommandHandler> CommandHandlers;
-
- Notifier notifier_;
- CommandHandlers command_handlers_;
-
- DISALLOW_COPY_AND_ASSIGN(Handler);
- };
-
- CONTENT_EXPORT static base::DictionaryValue* ParseMessage(
- const std::string& json,
- std::string* error_response);
-
- CONTENT_EXPORT static scoped_refptr<Command> ParseCommand(
- const std::string& json,
- std::string* error_response);
-
- CONTENT_EXPORT static scoped_refptr<Command> ParseCommand(
- base::DictionaryValue* command_dict,
- std::string* error_response);
-
- CONTENT_EXPORT static scoped_refptr<Command> CreateCommand(
- int id,
- const std::string& method,
- base::DictionaryValue* params);
-
- CONTENT_EXPORT static scoped_refptr<Response> ParseResponse(
- base::DictionaryValue* response_dict);
-
- static scoped_refptr<Notification> ParseNotification(
- const std::string& json);
-
- static scoped_refptr<Notification> CreateNotification(
- const std::string& method, base::DictionaryValue* params);
-
- DevToolsProtocol() {}
- ~DevToolsProtocol() {}
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_PROTOCOL_H_
diff --git a/chromium/content/browser/devtools/devtools_resources.gyp b/chromium/content/browser/devtools/devtools_resources.gyp
index 72ae7060549..bd35d426b25 100644
--- a/chromium/content/browser/devtools/devtools_resources.gyp
+++ b/chromium/content/browser/devtools/devtools_resources.gyp
@@ -11,7 +11,7 @@
'../../../third_party/WebKit/public/blink_devtools.gyp:blink_generate_devtools_grd',
],
'variables': {
- 'grit_out_dir': '<(SHARED_INTERMEDIATE_DIR)/webkit',
+ 'grit_out_dir': '<(SHARED_INTERMEDIATE_DIR)/blink',
},
'actions': [
{
@@ -23,6 +23,21 @@
'grit_cmd': ['python', '../../../tools/grit/grit.py'],
'grit_grd_file': '<(SHARED_INTERMEDIATE_DIR)/devtools/devtools_resources.grd',
'grit_rc_header_format%': '',
+
+ 'conditions': [
+ # These scripts can skip writing generated files if they are
+ # identical to the already existing files, which avoids further
+ # build steps, like recompilation. However, a dependency (earlier
+ # build step) having a newer timestamp than an output (later
+ # build step) confuses some build systems, so only use this on
+ # ninja, which explicitly supports this use case (gyp turns all
+ # actions into ninja restat rules).
+ ['"<(GENERATOR)"=="ninja"', {
+ 'write_only_new': '1',
+ }, {
+ 'write_only_new': '0',
+ }],
+ ],
},
'inputs': [
'<(grit_grd_file)',
@@ -38,39 +53,12 @@
'-i', '<(grit_grd_file)', 'build',
'-f', '<(DEPTH)/tools/gritsettings/resource_ids',
'-o', '<(grit_out_dir)',
+ '--write-only-new=<(write_only_new)',
'-D', 'SHARED_INTERMEDIATE_DIR=<(SHARED_INTERMEDIATE_DIR)',
'<@(grit_defines)',
'<@(grit_rc_header_format)'],
'message': 'Generating resources from <(grit_grd_file)',
},
- {
- 'action_name': 'devtools_protocol_constants',
- 'variables': {
- 'blink_protocol': '../../../third_party/WebKit/Source/devtools/protocol.json',
- 'browser_protocol': 'browser_protocol.json',
- 'generator': '../../public/browser/devtools_protocol_constants_generator.py',
- 'package': 'content'
- },
- 'inputs': [
- '<(blink_protocol)',
- '<(browser_protocol)',
- '<(generator)',
- ],
- 'outputs': [
- '<(SHARED_INTERMEDIATE_DIR)/<(package)/browser/devtools/devtools_protocol_constants.cc',
- '<(SHARED_INTERMEDIATE_DIR)/<(package)/browser/devtools/devtools_protocol_constants.h'
- ],
- 'action':[
- 'python',
- '<(generator)',
- '<(package)',
- '<(SHARED_INTERMEDIATE_DIR)/<(package)/browser/devtools/devtools_protocol_constants.cc',
- '<(SHARED_INTERMEDIATE_DIR)/<(package)/browser/devtools/devtools_protocol_constants.h',
- '<(blink_protocol)',
- '<(browser_protocol)',
- ],
- 'message': 'Generating DevTools protocol constants from <(blink_protocol)'
- }
],
'direct_dependent_settings': {
'include_dirs': [
diff --git a/chromium/content/browser/devtools/devtools_system_info_handler.cc b/chromium/content/browser/devtools/devtools_system_info_handler.cc
deleted file mode 100644
index 15261b3e466..00000000000
--- a/chromium/content/browser/devtools/devtools_system_info_handler.cc
+++ /dev/null
@@ -1,130 +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/devtools/devtools_system_info_handler.h"
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/values.h"
-#include "content/browser/devtools/devtools_protocol_constants.h"
-#include "content/browser/gpu/compositor_util.h"
-#include "content/browser/gpu/gpu_data_manager_impl.h"
-#include "gpu/config/gpu_info.h"
-
-namespace content {
-
-namespace {
-
-const char kAuxAttributes[] = "auxAttributes";
-const char kDeviceId[] = "deviceId";
-const char kDeviceString[] = "deviceString";
-const char kDevices[] = "devices";
-const char kDriverBugWorkarounds[] = "driverBugWorkarounds";
-const char kFeatureStatus[] = "featureStatus";
-const char kGPU[] = "gpu";
-const char kModelName[] = "modelName";
-const char kModelVersion[] = "modelVersion";
-const char kVendorId[] = "vendorId";
-const char kVendorString[] = "vendorString";
-
-class AuxGPUInfoEnumerator : public gpu::GPUInfo::Enumerator {
- public:
- AuxGPUInfoEnumerator(base::DictionaryValue* dictionary)
- : dictionary_(dictionary),
- in_aux_attributes_(false) { }
-
- void AddInt64(const char* name, int64 value) override {
- if (in_aux_attributes_)
- dictionary_->SetDouble(name, value);
- }
-
- void AddInt(const char* name, int value) override {
- if (in_aux_attributes_)
- dictionary_->SetInteger(name, value);
- }
-
- void AddString(const char* name, const std::string& value) override {
- if (in_aux_attributes_)
- dictionary_->SetString(name, value);
- }
-
- void AddBool(const char* name, bool value) override {
- if (in_aux_attributes_)
- dictionary_->SetBoolean(name, value);
- }
-
- void AddTimeDeltaInSecondsF(const char* name,
- const base::TimeDelta& value) override {
- if (in_aux_attributes_)
- dictionary_->SetDouble(name, value.InSecondsF());
- }
-
- void BeginGPUDevice() override {}
-
- void EndGPUDevice() override {}
-
- void BeginVideoEncodeAcceleratorSupportedProfile() override {}
-
- void EndVideoEncodeAcceleratorSupportedProfile() override {}
-
- void BeginAuxAttributes() override { in_aux_attributes_ = true; }
-
- void EndAuxAttributes() override { in_aux_attributes_ = false; }
-
- private:
- base::DictionaryValue* dictionary_;
- bool in_aux_attributes_;
-};
-
-base::DictionaryValue* GPUDeviceToDictionary(
- const gpu::GPUInfo::GPUDevice& device) {
- base::DictionaryValue* result = new base::DictionaryValue;
- result->SetInteger(kVendorId, device.vendor_id);
- result->SetInteger(kDeviceId, device.device_id);
- result->SetString(kVendorString, device.vendor_string);
- result->SetString(kDeviceString, device.device_string);
- return result;
-}
-
-} // namespace
-
-DevToolsSystemInfoHandler::DevToolsSystemInfoHandler() {
- RegisterCommandHandler(devtools::SystemInfo::getInfo::kName,
- base::Bind(&DevToolsSystemInfoHandler::OnGetInfo,
- base::Unretained(this)));
-}
-
-DevToolsSystemInfoHandler::~DevToolsSystemInfoHandler() {
-}
-
-scoped_refptr<DevToolsProtocol::Response>
-DevToolsSystemInfoHandler::OnGetInfo(
- scoped_refptr<DevToolsProtocol::Command> command) {
- gpu::GPUInfo gpu_info = GpuDataManagerImpl::GetInstance()->GetGPUInfo();
- base::DictionaryValue* gpu_dict = new base::DictionaryValue;
-
- base::ListValue* devices = new base::ListValue;
- devices->Append(GPUDeviceToDictionary(gpu_info.gpu));
- for (size_t ii = 0; ii < gpu_info.secondary_gpus.size(); ++ii) {
- devices->Append(GPUDeviceToDictionary(gpu_info.secondary_gpus[ii]));
- }
- gpu_dict->Set(kDevices, devices);
-
- base::DictionaryValue* aux_attributes = new base::DictionaryValue;
- AuxGPUInfoEnumerator enumerator(aux_attributes);
- gpu_info.EnumerateFields(&enumerator);
- gpu_dict->Set(kAuxAttributes, aux_attributes);
-
- gpu_dict->Set(kFeatureStatus, GetFeatureStatus());
-
- gpu_dict->Set(kDriverBugWorkarounds, GetDriverBugWorkarounds());
-
- base::DictionaryValue* system_dict = new base::DictionaryValue;
- system_dict->SetString(kModelName, gpu_info.machine_model_name);
- system_dict->SetString(kModelVersion, gpu_info.machine_model_version);
- system_dict->Set(kGPU, gpu_dict);
- return command->SuccessResponse(system_dict);
-}
-
-} // namespace content
diff --git a/chromium/content/browser/devtools/devtools_system_info_handler.h b/chromium/content/browser/devtools/devtools_system_info_handler.h
deleted file mode 100644
index 6217f7aef1c..00000000000
--- a/chromium/content/browser/devtools/devtools_system_info_handler.h
+++ /dev/null
@@ -1,28 +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_DEVTOOLS_DEVTOOLS_SYSTEM_INFO_HANDLER_H_
-#define CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_SYSTEM_INFO_HANDLER_H_
-
-#include "content/browser/devtools/devtools_protocol.h"
-
-namespace content {
-
-// This class provides information to DevTools about the system it's running on.
-class DevToolsSystemInfoHandler
- : public DevToolsProtocol::Handler {
- public:
- DevToolsSystemInfoHandler();
- ~DevToolsSystemInfoHandler() override;
-
- private:
- scoped_refptr<DevToolsProtocol::Response> OnGetInfo(
- scoped_refptr<DevToolsProtocol::Command> command);
-
- DISALLOW_COPY_AND_ASSIGN(DevToolsSystemInfoHandler);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_SYSTEM_INFO_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
deleted file mode 100644
index dede4d93d8a..00000000000
--- a/chromium/content/browser/devtools/embedded_worker_devtools_agent_host.cc
+++ /dev/null
@@ -1,232 +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/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
deleted file mode 100644
index cb0e45f3369..00000000000
--- a/chromium/content/browser/devtools/embedded_worker_devtools_agent_host.h
+++ /dev/null
@@ -1,84 +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_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
deleted file mode 100644
index be0bbbf9bc2..00000000000
--- a/chromium/content/browser/devtools/embedded_worker_devtools_manager.cc
+++ /dev/null
@@ -1,207 +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/embedded_worker_devtools_manager.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"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/render_process_host.h"
-#include "content/public/browser/worker_service.h"
-#include "ipc/ipc_listener.h"
-
-namespace content {
-
-// 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);
-}
-
-EmbeddedWorkerDevToolsManager::ServiceWorkerIdentifier::ServiceWorkerIdentifier(
- 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)
- : context_(other.context_),
- context_weak_(other.context_weak_),
- version_id_(other.version_id_),
- url_(other.url_) {
-}
-
-EmbeddedWorkerDevToolsManager::
-ServiceWorkerIdentifier::~ServiceWorkerIdentifier() {
-}
-
-bool EmbeddedWorkerDevToolsManager::ServiceWorkerIdentifier::Matches(
- const ServiceWorkerIdentifier& other) const {
- return context_ == other.context_ && version_id_ == other.version_id_;
-}
-
-const ServiceWorkerContextCore*
-EmbeddedWorkerDevToolsManager::ServiceWorkerIdentifier::context() const {
- return context_;
-}
-
-base::WeakPtr<ServiceWorkerContextCore>
-EmbeddedWorkerDevToolsManager::ServiceWorkerIdentifier::context_weak() const {
- return context_weak_;
-}
-
-int64
-EmbeddedWorkerDevToolsManager::ServiceWorkerIdentifier::version_id() const {
- return version_id_;
-}
-
-GURL EmbeddedWorkerDevToolsManager::ServiceWorkerIdentifier::url() const {
- return url_;
-}
-
-// static
-EmbeddedWorkerDevToolsManager* EmbeddedWorkerDevToolsManager::GetInstance() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- return Singleton<EmbeddedWorkerDevToolsManager>::get();
-}
-
-DevToolsAgentHostImpl*
-EmbeddedWorkerDevToolsManager::GetDevToolsAgentHostForWorker(
- int worker_process_id,
- int worker_route_id) {
- AgentHostMap::iterator it = workers_.find(
- WorkerId(worker_process_id, worker_route_id));
- return it == workers_.end() ? NULL : it->second;
-}
-
-EmbeddedWorkerDevToolsManager::EmbeddedWorkerDevToolsManager()
- : debug_service_worker_on_start_(false) {
-}
-
-EmbeddedWorkerDevToolsManager::~EmbeddedWorkerDevToolsManager() {
-}
-
-bool EmbeddedWorkerDevToolsManager::SharedWorkerCreated(
- int worker_process_id,
- int worker_route_id,
- const SharedWorkerInstance& instance) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- const WorkerId id(worker_process_id, worker_route_id);
- AgentHostMap::iterator it = FindExistingSharedWorkerAgentHost(instance);
- if (it == workers_.end()) {
- workers_[id] = new EmbeddedWorkerDevToolsAgentHost(id, instance);
- DevToolsManager::GetInstance()->AgentHostChanged(workers_[id]);
- return false;
- }
- WorkerRestarted(id, it);
- return true;
-}
-
-bool EmbeddedWorkerDevToolsManager::ServiceWorkerCreated(
- int worker_process_id,
- int worker_route_id,
- const ServiceWorkerIdentifier& service_worker_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- const WorkerId id(worker_process_id, worker_route_id);
- AgentHostMap::iterator it =
- FindExistingServiceWorkerAgentHost(service_worker_id);
- if (it == workers_.end()) {
- workers_[id] = new EmbeddedWorkerDevToolsAgentHost(
- id, service_worker_id, debug_service_worker_on_start_);
- DevToolsManager::GetInstance()->AgentHostChanged(workers_[id]);
- return debug_service_worker_on_start_;
- }
- WorkerRestarted(id, it);
- return true;
-}
-
-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);
- AgentHostMap::iterator it = workers_.find(id);
- DCHECK(it != workers_.end());
- scoped_refptr<EmbeddedWorkerDevToolsAgentHost> agent_host(it->second);
- agent_host->WorkerDestroyed();
- DevToolsManager::GetInstance()->AgentHostChanged(agent_host);
-}
-
-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);
- AgentHostMap::iterator it = workers_.find(id);
- DCHECK(it != workers_.end());
- it->second->WorkerReadyForInspection();
-}
-
-void EmbeddedWorkerDevToolsManager::RemoveInspectedWorkerData(WorkerId id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- workers_.erase(id);
-}
-
-EmbeddedWorkerDevToolsManager::AgentHostMap::iterator
-EmbeddedWorkerDevToolsManager::FindExistingSharedWorkerAgentHost(
- const SharedWorkerInstance& instance) {
- AgentHostMap::iterator it = workers_.begin();
- for (; it != workers_.end(); ++it) {
- if (it->second->Matches(instance))
- break;
- }
- return it;
-}
-
-EmbeddedWorkerDevToolsManager::AgentHostMap::iterator
-EmbeddedWorkerDevToolsManager::FindExistingServiceWorkerAgentHost(
- const ServiceWorkerIdentifier& service_worker_id) {
- AgentHostMap::iterator it = workers_.begin();
- for (; it != workers_.end(); ++it) {
- if (it->second->Matches(service_worker_id))
- break;
- }
- return it;
-}
-
-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 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() {
- workers_.clear();
-}
-
-} // namespace content
diff --git a/chromium/content/browser/devtools/embedded_worker_devtools_manager.h b/chromium/content/browser/devtools/embedded_worker_devtools_manager.h
deleted file mode 100644
index 7103877be11..00000000000
--- a/chromium/content/browser/devtools/embedded_worker_devtools_manager.h
+++ /dev/null
@@ -1,119 +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_EMBEDDED_WORKER_DEVTOOLS_MANAGER_H_
-#define CONTENT_BROWSER_DEVTOOLS_EMBEDDED_WORKER_DEVTOOLS_MANAGER_H_
-
-#include <map>
-
-#include "base/basictypes.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"
-
-namespace content {
-
-class DevToolsAgentHost;
-class DevToolsAgentHostImpl;
-class EmbeddedWorkerDevToolsAgentHost;
-class ServiceWorkerContextCore;
-
-// EmbeddedWorkerDevToolsManager is used instead of WorkerDevToolsManager when
-// "enable-embedded-shared-worker" flag is set.
-// This class lives on UI thread.
-class CONTENT_EXPORT EmbeddedWorkerDevToolsManager {
- public:
- typedef std::pair<int, int> WorkerId;
-
- class ServiceWorkerIdentifier {
- public:
- 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 context_;
- const base::WeakPtr<ServiceWorkerContextCore> context_weak_;
- const int64 version_id_;
- const GURL url_;
- };
-
- // Returns the EmbeddedWorkerDevToolsManager singleton.
- static EmbeddedWorkerDevToolsManager* GetInstance();
-
- DevToolsAgentHostImpl* GetDevToolsAgentHostForWorker(int worker_process_id,
- int worker_route_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.
- bool SharedWorkerCreated(int worker_process_id,
- int worker_route_id,
- const SharedWorkerInstance& instance);
- // Returns true when the worker must be paused on start because a DevTool
- // window for the same former ServiceWorkerIdentifier is still opened or
- // debug-on-start is enabled in chrome://serviceworker-internals.
- bool ServiceWorkerCreated(int worker_process_id,
- int worker_route_id,
- const ServiceWorkerIdentifier& service_worker_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) {
- debug_service_worker_on_start_ = debug_on_start;
- }
- bool debug_service_worker_on_start() const {
- return debug_service_worker_on_start_;
- }
-
- private:
- friend struct DefaultSingletonTraits<EmbeddedWorkerDevToolsManager>;
- friend class EmbeddedWorkerDevToolsAgentHost;
- friend class EmbeddedWorkerDevToolsManagerTest;
- FRIEND_TEST_ALL_PREFIXES(EmbeddedWorkerDevToolsManagerTest, BasicTest);
- FRIEND_TEST_ALL_PREFIXES(EmbeddedWorkerDevToolsManagerTest, AttachTest);
-
- typedef std::map<WorkerId, EmbeddedWorkerDevToolsAgentHost*> AgentHostMap;
-
- EmbeddedWorkerDevToolsManager();
- virtual ~EmbeddedWorkerDevToolsManager();
-
- void RemoveInspectedWorkerData(WorkerId id);
-
- AgentHostMap::iterator FindExistingSharedWorkerAgentHost(
- const SharedWorkerInstance& instance);
- AgentHostMap::iterator FindExistingServiceWorkerAgentHost(
- const ServiceWorkerIdentifier& service_worker_id);
-
- void WorkerRestarted(const WorkerId& id, const AgentHostMap::iterator& it);
-
- // Resets to its initial state as if newly created.
- void ResetForTesting();
-
- AgentHostMap workers_;
-
- bool debug_service_worker_on_start_;
-
- DISALLOW_COPY_AND_ASSIGN(EmbeddedWorkerDevToolsManager);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_DEVTOOLS_EMBEDDED_WORKER_DEVTOOLS_MANAGER_H_
diff --git a/chromium/content/browser/devtools/embedded_worker_devtools_manager_unittest.cc b/chromium/content/browser/devtools/embedded_worker_devtools_manager_unittest.cc
deleted file mode 100644
index 35a0b301ac2..00000000000
--- a/chromium/content/browser/devtools/embedded_worker_devtools_manager_unittest.cc
+++ /dev/null
@@ -1,298 +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/embedded_worker_devtools_manager.h"
-
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "content/browser/browser_thread_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/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 DevToolsAgentHostClient {
- public:
- TestDevToolsClientHost() {}
- ~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()),
- partition_(
- new WorkerStoragePartition(browser_context_->GetRequestContext(),
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL)),
- partition_id_(*partition_.get()) {}
-
- protected:
- void SetUp() override {
- manager_ = EmbeddedWorkerDevToolsManager::GetInstance();
- }
- void TearDown() override {
- EmbeddedWorkerDevToolsManager::GetInstance()->ResetForTesting();
- }
-
- void CheckWorkerState(int worker_process_id,
- int worker_route_id,
- WorkerState state) {
- const EmbeddedWorkerDevToolsManager::WorkerId id(worker_process_id,
- worker_route_id);
- EmbeddedWorkerDevToolsManager::AgentHostMap::iterator it =
- manager_->workers_.find(id);
- EXPECT_TRUE(manager_->workers_.end() != it);
- EXPECT_EQ(state, it->second->state_);
- }
-
- void CheckWorkerNotExist(int worker_process_id, int worker_route_id) {
- const EmbeddedWorkerDevToolsManager::WorkerId id(worker_process_id,
- worker_route_id);
- EXPECT_TRUE(manager_->workers_.end() == manager_->workers_.find(id));
- }
-
- void CheckWorkerCount(size_t size) {
- EXPECT_EQ(size, manager_->workers_.size());
- }
-
- base::MessageLoopForIO message_loop_;
- BrowserThreadImpl ui_thread_;
- scoped_ptr<TestBrowserContext> browser_context_;
- scoped_ptr<WorkerStoragePartition> partition_;
- const WorkerStoragePartitionId partition_id_;
- EmbeddedWorkerDevToolsManager* manager_;
-};
-
-TEST_F(EmbeddedWorkerDevToolsManagerTest, BasicTest) {
- scoped_refptr<DevToolsAgentHostImpl> agent_host;
-
- SharedWorkerInstance instance1(GURL("http://example.com/w.js"),
- base::string16(),
- base::string16(),
- blink::WebContentSecurityPolicyTypeReport,
- browser_context_->GetResourceContext(),
- partition_id_);
-
- agent_host = manager_->GetDevToolsAgentHostForWorker(1, 1);
- EXPECT_FALSE(agent_host.get());
-
- // Created -> Started -> Destroyed
- CheckWorkerNotExist(1, 1);
- manager_->SharedWorkerCreated(1, 1, instance1);
- 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, WorkerState::WORKER_UNINSPECTED);
- agent_host = manager_->GetDevToolsAgentHostForWorker(1, 2);
- EXPECT_TRUE(agent_host.get());
- CheckWorkerState(1, 2, WorkerState::WORKER_UNINSPECTED);
- EXPECT_EQ(agent_host.get(), manager_->GetDevToolsAgentHostForWorker(1, 2));
- manager_->WorkerReadyForInspection(1, 2);
- CheckWorkerState(1, 2, WorkerState::WORKER_UNINSPECTED);
- manager_->WorkerDestroyed(1, 2);
- 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, 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, WorkerState::WORKER_UNINSPECTED);
- manager_->WorkerDestroyed(1, 3);
- 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, WorkerState::WORKER_UNINSPECTED);
- manager_->WorkerDestroyed(1, 4);
- CheckWorkerNotExist(1, 4);
-
- // Created -> GetDevToolsAgentHost -> Destroyed
- CheckWorkerNotExist(1, 5);
- manager_->SharedWorkerCreated(1, 5, instance1);
- CheckWorkerState(1, 5, WorkerState::WORKER_UNINSPECTED);
- agent_host = manager_->GetDevToolsAgentHostForWorker(1, 5);
- EXPECT_TRUE(agent_host.get());
- CheckWorkerState(1, 5, WorkerState::WORKER_UNINSPECTED);
- manager_->WorkerDestroyed(1, 5);
- 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, WorkerState::WORKER_UNINSPECTED);
- agent_host = manager_->GetDevToolsAgentHostForWorker(1, 6);
- EXPECT_TRUE(agent_host.get());
- CheckWorkerState(1, 6, WorkerState::WORKER_UNINSPECTED);
- agent_host = NULL;
- manager_->WorkerDestroyed(1, 6);
- CheckWorkerNotExist(1, 6);
-}
-
-TEST_F(EmbeddedWorkerDevToolsManagerTest, AttachTest) {
- scoped_refptr<DevToolsAgentHostImpl> agent_host1;
- scoped_refptr<DevToolsAgentHostImpl> agent_host2;
-
- SharedWorkerInstance instance1(GURL("http://example.com/w1.js"),
- base::string16(),
- base::string16(),
- blink::WebContentSecurityPolicyTypeReport,
- browser_context_->GetResourceContext(),
- partition_id_);
- SharedWorkerInstance instance2(GURL("http://example.com/w2.js"),
- base::string16(),
- base::string16(),
- blink::WebContentSecurityPolicyTypeReport,
- browser_context_->GetResourceContext(),
- partition_id_);
-
- // Created -> GetDevToolsAgentHost -> Register -> Started -> Destroyed
- scoped_ptr<TestDevToolsClientHost> client_host1(new TestDevToolsClientHost());
- CheckWorkerNotExist(2, 1);
- manager_->SharedWorkerCreated(2, 1, instance1);
- CheckWorkerState(2, 1, WorkerState::WORKER_UNINSPECTED);
- agent_host1 = manager_->GetDevToolsAgentHostForWorker(2, 1);
- EXPECT_TRUE(agent_host1.get());
- CheckWorkerState(2, 1, WorkerState::WORKER_UNINSPECTED);
- EXPECT_EQ(agent_host1.get(), manager_->GetDevToolsAgentHostForWorker(2, 1));
- 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, 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, 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, WorkerState::WORKER_UNINSPECTED);
- client_host2->InspectAgentHost(agent_host2.get());
- CheckWorkerState(2, 2, WorkerState::WORKER_INSPECTED);
- manager_->WorkerDestroyed(2, 2);
- CheckWorkerState(2, 2, WorkerState::WORKER_TERMINATED);
- EXPECT_EQ(agent_host2.get(), manager_->GetDevToolsAgentHostForWorker(2, 2));
-
- // Re-created -> Started -> ClientHostClosing -> Destroyed
- CheckWorkerState(2, 1, WorkerState::WORKER_TERMINATED);
- manager_->SharedWorkerCreated(2, 3, instance1);
- CheckWorkerNotExist(2, 1);
- CheckWorkerState(2, 3, WorkerState::WORKER_PAUSED_FOR_REATTACH);
- EXPECT_EQ(agent_host1.get(), manager_->GetDevToolsAgentHostForWorker(2, 3));
- manager_->WorkerReadyForInspection(2, 3);
- CheckWorkerState(2, 3, WorkerState::WORKER_INSPECTED);
- client_host1->InspectAgentHost(NULL);
- manager_->WorkerDestroyed(2, 3);
- CheckWorkerState(2, 3, WorkerState::WORKER_TERMINATED);
- agent_host1 = NULL;
- CheckWorkerNotExist(2, 3);
-
- // Re-created -> Destroyed
- CheckWorkerState(2, 2, WorkerState::WORKER_TERMINATED);
- manager_->SharedWorkerCreated(2, 4, instance2);
- CheckWorkerNotExist(2, 2);
- CheckWorkerState(2, 4, WorkerState::WORKER_PAUSED_FOR_REATTACH);
- EXPECT_EQ(agent_host2.get(), manager_->GetDevToolsAgentHostForWorker(2, 4));
- manager_->WorkerDestroyed(2, 4);
- CheckWorkerNotExist(2, 2);
- CheckWorkerState(2, 4, WorkerState::WORKER_TERMINATED);
-
- // Re-created -> ClientHostClosing -> Destroyed
- manager_->SharedWorkerCreated(2, 5, instance2);
- CheckWorkerNotExist(2, 2);
- CheckWorkerState(2, 5, WorkerState::WORKER_PAUSED_FOR_REATTACH);
- EXPECT_EQ(agent_host2.get(), manager_->GetDevToolsAgentHostForWorker(2, 5));
- client_host2->InspectAgentHost(NULL);
- CheckWorkerCount(1);
- agent_host2 = NULL;
- CheckWorkerCount(1);
- manager_->WorkerDestroyed(2, 5);
- 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 4d3e4fff0b0..9f3f204b776 100644
--- a/chromium/content/browser/devtools/forwarding_agent_host.cc
+++ b/chromium/content/browser/devtools/forwarding_agent_host.cc
@@ -4,6 +4,9 @@
#include "content/browser/devtools/forwarding_agent_host.h"
+#include "base/bind.h"
+#include "content/browser/devtools/protocol/inspector_handler.h"
+
namespace content {
ForwardingAgentHost::ForwardingAgentHost(
@@ -19,20 +22,29 @@ void ForwardingAgentHost::DispatchOnClientHost(const std::string& message) {
}
void ForwardingAgentHost::ConnectionClosed() {
- HostClosed();
+ devtools::inspector::Client inspector(
+ base::Bind(&ForwardingAgentHost::DispatchOnClientHost,
+ base::Unretained(this)));
+ inspector.Detached(devtools::inspector::DetachedParams::Create()
+ ->set_reason("Connection lost."));
+ delegate_.reset();
}
void ForwardingAgentHost::Attach() {
- delegate_->Attach(this);
+ if (delegate_)
+ delegate_->Attach(this);
}
void ForwardingAgentHost::Detach() {
- delegate_->Detach();
+ if (delegate_)
+ delegate_->Detach();
}
-void ForwardingAgentHost::DispatchProtocolMessage(
+bool ForwardingAgentHost::DispatchProtocolMessage(
const std::string& message) {
- delegate_->SendMessageToBackend(message);
+ if (delegate_)
+ delegate_->SendMessageToBackend(message);
+ return true;
}
DevToolsAgentHost::Type ForwardingAgentHost::GetType() {
diff --git a/chromium/content/browser/devtools/forwarding_agent_host.h b/chromium/content/browser/devtools/forwarding_agent_host.h
index 7f9bcec5ff9..2b6ccce3050 100644
--- a/chromium/content/browser/devtools/forwarding_agent_host.h
+++ b/chromium/content/browser/devtools/forwarding_agent_host.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_DEVTOOLS_FORWARDING_AGENT_HOST_H
-#define CONTENT_BROWSER_DEVTOOLS_FORWARDING_AGENT_HOST_H
+#ifndef CONTENT_BROWSER_DEVTOOLS_FORWARDING_AGENT_HOST_H_
+#define CONTENT_BROWSER_DEVTOOLS_FORWARDING_AGENT_HOST_H_
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
@@ -29,7 +29,7 @@ class ForwardingAgentHost
// DevToolsAgentHostImpl implementation.
void Attach() override;
void Detach() override;
- void DispatchProtocolMessage(const std::string& message) override;
+ bool DispatchProtocolMessage(const std::string& message) override;
// DevToolsAgentHost implementation
Type GetType() override;
@@ -43,4 +43,4 @@ class ForwardingAgentHost
} // namespace content
-#endif // CONTENT_BROWSER_DEVTOOLS_FORWARDING_AGENT_HOST_H
+#endif // CONTENT_BROWSER_DEVTOOLS_FORWARDING_AGENT_HOST_H_
diff --git a/chromium/content/browser/devtools/ipc_devtools_agent_host.cc b/chromium/content/browser/devtools/ipc_devtools_agent_host.cc
index 9218d5809bb..dc3eebe8b1d 100644
--- a/chromium/content/browser/devtools/ipc_devtools_agent_host.cc
+++ b/chromium/content/browser/devtools/ipc_devtools_agent_host.cc
@@ -4,13 +4,11 @@
#include "content/browser/devtools/ipc_devtools_agent_host.h"
-#include "content/common/devtools_messages.h"
-
namespace content {
void IPCDevToolsAgentHost::Attach() {
SendMessageToAgent(new DevToolsAgentMsg_Attach(MSG_ROUTING_NONE, GetId()));
- OnClientAttached();
+ OnClientAttached(false);
}
void IPCDevToolsAgentHost::Detach() {
@@ -18,10 +16,14 @@ void IPCDevToolsAgentHost::Detach() {
OnClientDetached();
}
-void IPCDevToolsAgentHost::DispatchProtocolMessage(
+bool IPCDevToolsAgentHost::DispatchProtocolMessage(
const std::string& message) {
+ if (DevToolsAgentHostImpl::DispatchProtocolMessage(message))
+ return true;
+
SendMessageToAgent(new DevToolsAgentMsg_DispatchOnInspectorBackend(
MSG_ROUTING_NONE, message));
+ return true;
}
void IPCDevToolsAgentHost::InspectElement(int x, int y) {
@@ -36,31 +38,35 @@ IPCDevToolsAgentHost::IPCDevToolsAgentHost()
IPCDevToolsAgentHost::~IPCDevToolsAgentHost() {
}
-void IPCDevToolsAgentHost::Reattach(const std::string& saved_agent_state) {
+void IPCDevToolsAgentHost::Reattach() {
SendMessageToAgent(new DevToolsAgentMsg_Reattach(
- MSG_ROUTING_NONE, GetId(), saved_agent_state));
- OnClientAttached();
+ MSG_ROUTING_NONE, GetId(), state_cookie_));
+ OnClientAttached(true);
}
void IPCDevToolsAgentHost::ProcessChunkedMessageFromAgent(
- const std::string& message, uint32 total_size) {
- if (total_size && total_size == message.length()) {
- DCHECK(message_buffer_size_ == 0);
- SendMessageToClient(message);
+ const DevToolsMessageChunk& chunk) {
+ if (chunk.is_last && !chunk.post_state.empty())
+ state_cookie_ = chunk.post_state;
+
+ if (chunk.is_first && chunk.is_last) {
+ CHECK(message_buffer_size_ == 0);
+ SendMessageToClient(chunk.data);
return;
}
- if (total_size) {
- DCHECK(message_buffer_size_ == 0);
+ if (chunk.is_first) {
message_buffer_ = std::string();
- message_buffer_.reserve(total_size);
- message_buffer_size_ = total_size;
+ message_buffer_.reserve(chunk.message_size);
+ message_buffer_size_ = chunk.message_size;
}
- message_buffer_.append(message);
+ CHECK(message_buffer_.size() + chunk.data.size() <=
+ message_buffer_size_);
+ message_buffer_.append(chunk.data);
- if (message_buffer_.size() >= message_buffer_size_) {
- DCHECK(message_buffer_.size() == message_buffer_size_);
+ if (chunk.is_last) {
+ CHECK(message_buffer_.size() == message_buffer_size_);
SendMessageToClient(message_buffer_);
message_buffer_ = std::string();
message_buffer_size_ = 0;
diff --git a/chromium/content/browser/devtools/ipc_devtools_agent_host.h b/chromium/content/browser/devtools/ipc_devtools_agent_host.h
index a952588f758..1f910784d82 100644
--- a/chromium/content/browser/devtools/ipc_devtools_agent_host.h
+++ b/chromium/content/browser/devtools/ipc_devtools_agent_host.h
@@ -6,6 +6,7 @@
#define CONTENT_BROWSER_DEVTOOLS_IPC_DEVTOOLS_AGENT_HOST_H_
#include "content/browser/devtools/devtools_agent_host_impl.h"
+#include "content/common/devtools_messages.h"
namespace IPC {
class Message;
@@ -18,24 +19,24 @@ class CONTENT_EXPORT IPCDevToolsAgentHost : public DevToolsAgentHostImpl {
// DevToolsAgentHostImpl implementation.
void Attach() override;
void Detach() override;
- void DispatchProtocolMessage(const std::string& message) override;
+ bool DispatchProtocolMessage(const std::string& message) override;
void InspectElement(int x, int y) override;
protected:
IPCDevToolsAgentHost();
~IPCDevToolsAgentHost() override;
- void Reattach(const std::string& saved_agent_state);
- void ProcessChunkedMessageFromAgent(const std::string& message,
- uint32 total_size);
+ void Reattach();
+ void ProcessChunkedMessageFromAgent(const DevToolsMessageChunk& chunk);
virtual void SendMessageToAgent(IPC::Message* msg) = 0;
- virtual void OnClientAttached() = 0;
+ virtual void OnClientAttached(bool reattached) = 0;
virtual void OnClientDetached() = 0;
private:
std::string message_buffer_;
uint32 message_buffer_size_;
+ std::string state_cookie_;
};
} // namespace content
diff --git a/chromium/content/browser/devtools/protocol/color_picker.cc b/chromium/content/browser/devtools/protocol/color_picker.cc
index dec4f3103b3..23d79a6dc98 100644
--- a/chromium/content/browser/devtools/protocol/color_picker.cc
+++ b/chromium/content/browser/devtools/protocol/color_picker.cc
@@ -12,7 +12,7 @@
#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"
+#include "ui/gfx/geometry/size_conversions.h"
namespace content {
namespace devtools {
@@ -33,11 +33,11 @@ ColorPicker::ColorPicker(ColorPickedCallback callback)
ColorPicker::~ColorPicker() {
}
-void ColorPicker::SetRenderViewHost(RenderViewHostImpl* host) {
+void ColorPicker::SetRenderWidgetHost(RenderWidgetHostImpl* host) {
if (host_ == host)
return;
- if (host_)
+ if (enabled_ && host_)
host_->RemoveMouseEventCallback(mouse_event_callback_);
ResetFrame();
host_ = host;
@@ -95,11 +95,12 @@ void ColorPicker::ResetFrame() {
last_cursor_y_ = -1;
}
-void ColorPicker::FrameUpdated(bool succeeded, const SkBitmap& bitmap) {
+void ColorPicker::FrameUpdated(const SkBitmap& bitmap,
+ ReadbackResponse response) {
if (!enabled_)
return;
- if (succeeded) {
+ if (response == READBACK_SUCCESS) {
frame_ = bitmap;
UpdateCursor();
}
@@ -165,11 +166,14 @@ void ColorPicker::UpdateCursor() {
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);
+ SkBitmap result;
+ result.allocN32Pixels(kCursorSize * device_scale_factor,
+ kCursorSize * device_scale_factor);
+ result.eraseARGB(0, 0, 0, 0);
+
+ SkCanvas canvas(result);
+ canvas.scale(device_scale_factor, device_scale_factor);
+ canvas.translate(0.5f, 0.5f);
SkPaint paint;
@@ -180,22 +184,22 @@ void ColorPicker::UpdateCursor() {
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);
+ 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);
+ canvas.drawCircle(kHotspotOffset, kHotspotOffset, kHotspotRadius, paint);
}
// Clip circle for magnified projection.
@@ -203,7 +207,7 @@ void ColorPicker::UpdateCursor() {
SkPath clip_path;
clip_path.addOval(SkRect::MakeXYWH(padding, padding, kDiameter, kDiameter));
clip_path.close();
- canvas->clipPath(clip_path, SkRegion::kIntersect_Op, true);
+ canvas.clipPath(clip_path, SkRegion::kIntersect_Op, true);
// Project pixels.
int pixel_count = kDiameter / kPixelSize;
@@ -211,17 +215,17 @@ void ColorPicker::UpdateCursor() {
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);
+ 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);
+ 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.
@@ -230,18 +234,13 @@ void ColorPicker::UpdateCursor() {
kPixelSize, kPixelSize);
paint.setColor(SK_ColorRED);
paint.setStyle(SkPaint::kStroke_Style);
- canvas->drawRect(pixel, paint);
+ 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);
+ canvas.drawCircle(kCursorSize / 2, kCursorSize / 2, kDiameter / 2, paint);
WebCursor cursor;
WebCursor::CursorInfo cursor_info;
diff --git a/chromium/content/browser/devtools/protocol/color_picker.h b/chromium/content/browser/devtools/protocol/color_picker.h
index e59a35137fd..e4de5257516 100644
--- a/chromium/content/browser/devtools/protocol/color_picker.h
+++ b/chromium/content/browser/devtools/protocol/color_picker.h
@@ -15,7 +15,7 @@ class WebMouseEvent;
namespace content {
-class RenderViewHostImpl;
+class RenderWidgetHostImpl;
namespace devtools {
namespace page {
@@ -27,14 +27,14 @@ class ColorPicker {
explicit ColorPicker(ColorPickedCallback callback);
virtual ~ColorPicker();
- void SetRenderViewHost(RenderViewHostImpl* host);
+ void SetRenderWidgetHost(RenderWidgetHostImpl* host);
void SetEnabled(bool enabled);
void OnSwapCompositorFrame();
private:
void UpdateFrame();
void ResetFrame();
- void FrameUpdated(bool succeeded, const SkBitmap& bitmap);
+ void FrameUpdated(const SkBitmap&, ReadbackResponse);
bool HandleMouseEvent(const blink::WebMouseEvent& event);
void UpdateCursor();
@@ -44,7 +44,7 @@ class ColorPicker {
int last_cursor_x_;
int last_cursor_y_;
RenderWidgetHost::MouseEventCallback mouse_event_callback_;
- RenderViewHostImpl* host_;
+ RenderWidgetHostImpl* host_;
base::WeakPtrFactory<ColorPicker> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ColorPicker);
diff --git a/chromium/content/browser/devtools/protocol/devtools_protocol_browsertest.cc b/chromium/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
new file mode 100644
index 00000000000..cbae68203b9
--- /dev/null
+++ b/chromium/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
@@ -0,0 +1,264 @@
+// 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/base64.h"
+#include "base/command_line.h"
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/values.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 {
+
+namespace {
+
+const char kIdParam[] = "id";
+const char kMethodParam[] = "method";
+const char kParamsParam[] = "params";
+
+}
+
+class DevToolsProtocolTest : public ContentBrowserTest,
+ public DevToolsAgentHostClient {
+ protected:
+ void SendCommand(const std::string& method,
+ scoped_ptr<base::DictionaryValue> params) {
+ base::DictionaryValue command;
+ command.SetInteger(kIdParam, 1);
+ command.SetString(kMethodParam, method);
+ if (params)
+ command.Set(kParamsParam, params.release());
+
+ std::string json_command;
+ base::JSONWriter::Write(&command, &json_command);
+ agent_host_->DispatchProtocolMessage(json_command);
+ base::MessageLoop::current()->Run();
+ }
+
+ bool HasValue(const std::string& path) {
+ base::Value* value = 0;
+ return result_->Get(path, &value);
+ }
+
+ bool HasListItem(const std::string& path_to_list,
+ const std::string& name,
+ const std::string& value) {
+ base::ListValue* list;
+ if (!result_->GetList(path_to_list, &list))
+ return false;
+
+ for (size_t i = 0; i != list->GetSize(); i++) {
+ base::DictionaryValue* item;
+ if (!list->GetDictionary(i, &item))
+ return false;
+ std::string id;
+ if (!item->GetString(name, &id))
+ return false;
+ if (id == value)
+ return true;
+ }
+ return false;
+ }
+
+ void SetUpOnMainThread() override {
+ agent_host_ = DevToolsAgentHost::GetOrCreateFor(shell()->web_contents());
+ agent_host_->AttachClient(this);
+ }
+
+ void TearDownOnMainThread() override {
+ agent_host_->DetachClient();
+ agent_host_ = NULL;
+ }
+
+ scoped_ptr<base::DictionaryValue> result_;
+ scoped_refptr<DevToolsAgentHost> agent_host_;
+
+ private:
+ 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;
+ 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);
+ }
+};
+
+class CaptureScreenshotTest : public DevToolsProtocolTest {
+ 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", nullptr);
+ 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);
+}
+
+class SyntheticGestureTest : public DevToolsProtocolTest {
+#if !defined(OS_ANDROID)
+ protected:
+ void SetUpOnMainThread() override {
+ DevToolsProtocolTest::SetUpOnMainThread();
+
+ scoped_ptr<base::DictionaryValue> params(new base::DictionaryValue());
+ params->SetInteger("width", 384);
+ params->SetInteger("height", 640);
+ params->SetDouble("deviceScaleFactor", 2.0);
+ params->SetBoolean("mobile", true);
+ params->SetBoolean("fitWindow", false);
+ params->SetBoolean("textAutosizing", true);
+ SendCommand("Page.setDeviceMetricsOverride", params.Pass());
+
+ params.reset(new base::DictionaryValue());
+ params->SetBoolean("enabled", true);
+ params->SetString("configuration", "mobile");
+ SendCommand("Page.setTouchEmulationEnabled", params.Pass());
+ }
+#endif
+};
+
+#if defined(OS_ANDROID)
+// crbug.com/469947
+#define MAYBE_SynthesizePinchGesture DISABLED_SynthesizePinchGesture
+#else
+// crbug.com/460128
+#define MAYBE_SynthesizePinchGesture DISABLED_SynthesizePinchGesture
+#endif
+IN_PROC_BROWSER_TEST_F(SyntheticGestureTest, MAYBE_SynthesizePinchGesture) {
+ GURL test_url = GetTestUrl("devtools", "synthetic_gesture_tests.html");
+ NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 1);
+
+ int old_width;
+ ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
+ shell()->web_contents(),
+ "domAutomationController.send(window.innerWidth)", &old_width));
+
+ int old_height;
+ ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
+ shell()->web_contents(),
+ "domAutomationController.send(window.innerHeight)", &old_height));
+
+ scoped_ptr<base::DictionaryValue> params(new base::DictionaryValue());
+ params->SetInteger("x", old_width / 2);
+ params->SetInteger("y", old_height / 2);
+ params->SetDouble("scaleFactor", 2.0);
+ SendCommand("Input.synthesizePinchGesture", params.Pass());
+
+ int new_width;
+ ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
+ shell()->web_contents(),
+ "domAutomationController.send(window.innerWidth)", &new_width));
+ ASSERT_DOUBLE_EQ(2.0, static_cast<double>(old_width) / new_width);
+
+ int new_height;
+ ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
+ shell()->web_contents(),
+ "domAutomationController.send(window.innerHeight)", &new_height));
+ ASSERT_DOUBLE_EQ(2.0, static_cast<double>(old_height) / new_height);
+}
+
+#if defined(OS_ANDROID)
+#define MAYBE_SynthesizeScrollGesture SynthesizeScrollGesture
+#else
+// crbug.com/460128
+#define MAYBE_SynthesizeScrollGesture DISABLED_SynthesizeScrollGesture
+#endif
+IN_PROC_BROWSER_TEST_F(SyntheticGestureTest, MAYBE_SynthesizeScrollGesture) {
+ GURL test_url = GetTestUrl("devtools", "synthetic_gesture_tests.html");
+ NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 1);
+
+ int scroll_top;
+ ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
+ shell()->web_contents(),
+ "domAutomationController.send(document.body.scrollTop)", &scroll_top));
+ ASSERT_EQ(0, scroll_top);
+
+ scoped_ptr<base::DictionaryValue> params(new base::DictionaryValue());
+ params->SetInteger("x", 0);
+ params->SetInteger("y", 0);
+ params->SetInteger("xDistance", 0);
+ params->SetInteger("yDistance", -100);
+ SendCommand("Input.synthesizeScrollGesture", params.Pass());
+
+ ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
+ shell()->web_contents(),
+ "domAutomationController.send(document.body.scrollTop)", &scroll_top));
+ ASSERT_EQ(100, scroll_top);
+}
+
+#if defined(OS_ANDROID)
+#define MAYBE_SynthesizeTapGesture SynthesizeTapGesture
+#else
+// crbug.com/460128
+#define MAYBE_SynthesizeTapGesture DISABLED_SynthesizeTapGesture
+#endif
+IN_PROC_BROWSER_TEST_F(SyntheticGestureTest, MAYBE_SynthesizeTapGesture) {
+ GURL test_url = GetTestUrl("devtools", "synthetic_gesture_tests.html");
+ NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 1);
+
+ int scroll_top;
+ ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
+ shell()->web_contents(),
+ "domAutomationController.send(document.body.scrollTop)", &scroll_top));
+ ASSERT_EQ(0, scroll_top);
+
+ scoped_ptr<base::DictionaryValue> params(new base::DictionaryValue());
+ params->SetInteger("x", 16);
+ params->SetInteger("y", 16);
+ params->SetString("gestureSourceType", "touch");
+ SendCommand("Input.synthesizeTapGesture", params.Pass());
+
+ // The link that we just tapped should take us to the bottom of the page. The
+ // new value of |document.body.scrollTop| will depend on the screen dimensions
+ // of the device that we're testing on, but in any case it should be greater
+ // than 0.
+ ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
+ shell()->web_contents(),
+ "domAutomationController.send(document.body.scrollTop)", &scroll_top));
+ ASSERT_GT(scroll_top, 0);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/devtools/protocol/devtools_protocol_client.cc b/chromium/content/browser/devtools/protocol/devtools_protocol_client.cc
index a34189e0efc..4658b083114 100644
--- a/chromium/content/browser/devtools/protocol/devtools_protocol_client.cc
+++ b/chromium/content/browser/devtools/protocol/devtools_protocol_client.cc
@@ -4,8 +4,34 @@
#include "content/browser/devtools/protocol/devtools_protocol_client.h"
+#include "base/json/json_writer.h"
+#include "base/strings/stringprintf.h"
+
namespace content {
+namespace {
+
+const char kIdParam[] = "id";
+const char kMethodParam[] = "method";
+const char kParamsParam[] = "params";
+const char kResultParam[] = "result";
+const char kErrorParam[] = "error";
+const char kErrorCodeParam[] = "code";
+const char kErrorMessageParam[] = "message";
+
+// Special values.
+const int kStatusOk = -1;
+const int kStatusFallThrough = -2;
+// JSON RPC 2.0 spec: http://www.jsonrpc.org/specification#error_object
+const int kStatusInvalidParams = -32602;
+const int kStatusInternalError = -32603;
+const int kStatusServerError = -32000;
+
+} // namespace
+
+// static
+const DevToolsCommandId DevToolsProtocolClient::kNoId = -1;
+
DevToolsProtocolClient::DevToolsProtocolClient(
const RawMessageCallback& raw_message_callback)
: raw_message_callback_(raw_message_callback) {
@@ -14,76 +40,85 @@ DevToolsProtocolClient::DevToolsProtocolClient(
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::SendRawMessage(const std::string& message) {
+ raw_message_callback_.Run(message);
}
-void DevToolsProtocolClient::SendAsyncResponse(
- scoped_refptr<DevToolsProtocol::Response> response) {
- SendRawMessage(response->Serialize());
+void DevToolsProtocolClient::SendMessage(const base::DictionaryValue& message) {
+ std::string json_message;
+ base::JSONWriter::Write(&message, &json_message);
+ SendRawMessage(json_message);
}
-void DevToolsProtocolClient::SendRawMessage(const std::string& message) {
- raw_message_callback_.Run(message);
-}
+void DevToolsProtocolClient::SendNotification(
+ const std::string& method,
+ scoped_ptr<base::DictionaryValue> params) {
+ base::DictionaryValue notification;
+ notification.SetString(kMethodParam, method);
+ if (params)
+ notification.Set(kParamsParam, params.release());
-void DevToolsProtocolClient::SendInvalidParamsResponse(
- scoped_refptr<DevToolsProtocol::Command> command,
- const std::string& message) {
- SendAsyncResponse(command->InvalidParamResponse(message));
+ SendMessage(notification);
}
-void DevToolsProtocolClient::SendInternalErrorResponse(
- scoped_refptr<DevToolsProtocol::Command> command,
- const std::string& message) {
- SendAsyncResponse(command->InternalErrorResponse(message));
+void DevToolsProtocolClient::SendSuccess(
+ DevToolsCommandId command_id,
+ scoped_ptr<base::DictionaryValue> params) {
+ base::DictionaryValue response;
+ response.SetInteger(kIdParam, command_id);
+
+ response.Set(kResultParam,
+ params ? params.release() : new base::DictionaryValue());
+
+ SendMessage(response);
}
-void DevToolsProtocolClient::SendServerErrorResponse(
- scoped_refptr<DevToolsProtocol::Command> command,
- const std::string& message) {
- SendAsyncResponse(command->ServerErrorResponse(message));
+bool DevToolsProtocolClient::SendError(DevToolsCommandId command_id,
+ const Response& response) {
+ if (response.status() == kStatusOk ||
+ response.status() == kStatusFallThrough) {
+ return false;
+ }
+ base::DictionaryValue dict;
+ if (command_id == kNoId)
+ dict.Set(kIdParam, base::Value::CreateNullValue());
+ else
+ dict.SetInteger(kIdParam, command_id);
+
+ base::DictionaryValue* error_object = new base::DictionaryValue();
+ error_object->SetInteger(kErrorCodeParam, response.status());
+ if (!response.message().empty())
+ error_object->SetString(kErrorMessageParam, response.message());
+
+ dict.Set(kErrorParam, error_object);
+ SendMessage(dict);
+ return true;
}
typedef DevToolsProtocolClient::Response Response;
Response Response::FallThrough() {
- Response response;
- response.status_ = ResponseStatus::RESPONSE_STATUS_FALLTHROUGH;
- return response;
+ return Response(kStatusFallThrough);
}
Response Response::OK() {
- Response response;
- response.status_ = ResponseStatus::RESPONSE_STATUS_OK;
- return response;
+ return Response(kStatusOk);
}
-Response Response::InvalidParams(const std::string& message) {
- Response response;
- response.status_ = ResponseStatus::RESPONSE_STATUS_INVALID_PARAMS;
- response.message_ = message;
- return response;
+Response Response::InvalidParams(const std::string& param) {
+ return Response(kStatusInvalidParams,
+ base::StringPrintf("Missing or invalid '%s' parameter", param.c_str()));
}
Response Response::InternalError(const std::string& message) {
- Response response;
- response.status_ = ResponseStatus::RESPONSE_STATUS_INTERNAL_ERROR;
- response.message_ = message;
- return response;
+ return Response(kStatusInternalError, message);
}
Response Response::ServerError(const std::string& message) {
- Response response;
- response.status_ = ResponseStatus::RESPONSE_STATUS_SERVER_ERROR;
- response.message_ = message;
- return response;
+ return Response(kStatusServerError, message);
}
-DevToolsProtocolClient::ResponseStatus Response::status() const {
+int Response::status() const {
return status_;
}
@@ -91,7 +126,17 @@ const std::string& Response::message() const {
return message_;
}
-Response::Response() {
+bool Response::IsFallThrough() const {
+ return status_ == kStatusFallThrough;
+}
+
+Response::Response(int status)
+ : status_(status) {
+}
+
+Response::Response(int status, const std::string& message)
+ : status_(status),
+ message_(message) {
}
} // namespace content
diff --git a/chromium/content/browser/devtools/protocol/devtools_protocol_client.h b/chromium/content/browser/devtools/protocol/devtools_protocol_client.h
index 620a7c14995..9297187f21c 100644
--- a/chromium/content/browser/devtools/protocol/devtools_protocol_client.h
+++ b/chromium/content/browser/devtools/protocol/devtools_protocol_client.h
@@ -5,68 +5,67 @@
#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"
+#include "base/callback.h"
+#include "base/values.h"
namespace content {
+using DevToolsCommandId = int;
+class DevToolsProtocolHandler;
+class DevToolsProtocolDispatcher;
+
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,
- };
+ static const DevToolsCommandId kNoId;
struct Response {
public:
static Response FallThrough();
static Response OK();
- static Response InvalidParams(const std::string& message);
+ static Response InvalidParams(const std::string& param);
static Response InternalError(const std::string& message);
static Response ServerError(const std::string& message);
- ResponseStatus status() const;
+ int status() const;
const std::string& message() const;
+ bool IsFallThrough() const;
+
private:
- Response();
+ friend class DevToolsProtocolHandler;
+
+ explicit Response(int status);
+ Response(int status, const std::string& message);
- ResponseStatus status_;
+ int 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);
+ bool SendError(DevToolsCommandId command_id,
+ const Response& response);
// 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);
-
+ explicit DevToolsProtocolClient(
+ const RawMessageCallback& raw_message_callback);
virtual ~DevToolsProtocolClient();
+ protected:
+ void SendSuccess(DevToolsCommandId command_id,
+ scoped_ptr<base::DictionaryValue> params);
void SendNotification(const std::string& method,
- base::DictionaryValue* params);
-
- void SendAsyncResponse(scoped_refptr<DevToolsProtocol::Response> response);
+ scoped_ptr<base::DictionaryValue> params);
private:
- RawMessageCallback raw_message_callback_;
+ friend class DevToolsProtocolDispatcher;
+
+ void SendMessage(const base::DictionaryValue& message);
+ RawMessageCallback raw_message_callback_;
DISALLOW_COPY_AND_ASSIGN(DevToolsProtocolClient);
};
diff --git a/chromium/content/browser/devtools/protocol/devtools_protocol_handler.cc b/chromium/content/browser/devtools/protocol/devtools_protocol_handler.cc
new file mode 100644
index 00000000000..28412195702
--- /dev/null
+++ b/chromium/content/browser/devtools/protocol/devtools_protocol_handler.cc
@@ -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.
+
+#include "content/browser/devtools/protocol/devtools_protocol_handler.h"
+
+#include "base/bind.h"
+#include "base/json/json_reader.h"
+
+namespace content {
+
+namespace {
+
+const char kIdParam[] = "id";
+const char kMethodParam[] = "method";
+const char kParamsParam[] = "params";
+
+// JSON RPC 2.0 spec: http://www.jsonrpc.org/specification#error_object
+const int kStatusParseError = -32700;
+const int kStatusInvalidRequest = -32600;
+const int kStatusNoSuchMethod = -32601;
+
+scoped_ptr<base::DictionaryValue> TakeDictionary(base::DictionaryValue* dict,
+ const std::string& key) {
+ scoped_ptr<base::Value> value;
+ dict->Remove(key, &value);
+ base::DictionaryValue* result = nullptr;
+ if (value)
+ value.release()->GetAsDictionary(&result);
+ return make_scoped_ptr(result);
+}
+
+} // namespace
+
+DevToolsProtocolHandler::DevToolsProtocolHandler(const Notifier& notifier)
+ : client_(notifier),
+ dispatcher_(notifier) {
+}
+
+DevToolsProtocolHandler::~DevToolsProtocolHandler() {
+}
+
+scoped_ptr<base::DictionaryValue>
+DevToolsProtocolHandler::ParseCommand(const std::string& message) {
+ scoped_ptr<base::Value> value(base::JSONReader::Read(message));
+ if (!value || !value->IsType(base::Value::TYPE_DICTIONARY)) {
+ client_.SendError(DevToolsProtocolClient::kNoId,
+ Response(kStatusParseError,
+ "Message must be in JSON format"));
+ return nullptr;
+ }
+
+ scoped_ptr<base::DictionaryValue> command =
+ make_scoped_ptr(static_cast<base::DictionaryValue*>(value.release()));
+ int id = DevToolsProtocolClient::kNoId;
+ bool ok = command->GetInteger(kIdParam, &id) && id >= 0;
+ if (!ok) {
+ client_.SendError(id, Response(kStatusInvalidRequest,
+ "The type of 'id' property must be number"));
+ return nullptr;
+ }
+
+ std::string method;
+ ok = command->GetString(kMethodParam, &method);
+ if (!ok) {
+ client_.SendError(id,
+ Response(kStatusInvalidRequest,
+ "The type of 'method' property must be string"));
+ return nullptr;
+ }
+
+ return command;
+}
+
+void DevToolsProtocolHandler::HandleCommand(
+ scoped_ptr<base::DictionaryValue> command) {
+ int id = DevToolsProtocolClient::kNoId;
+ std::string method;
+ command->GetInteger(kIdParam, &id);
+ command->GetString(kMethodParam, &method);
+ DevToolsProtocolDispatcher::CommandHandler command_handler(
+ dispatcher_.FindCommandHandler(method));
+ if (command_handler.is_null()) {
+ client_.SendError(id, Response(kStatusNoSuchMethod, "No such method"));
+ return;
+ }
+ bool result =
+ command_handler.Run(id, TakeDictionary(command.get(), kParamsParam));
+ DCHECK(result);
+}
+
+bool DevToolsProtocolHandler::HandleOptionalCommand(
+ scoped_ptr<base::DictionaryValue> command) {
+ int id = DevToolsProtocolClient::kNoId;
+ std::string method;
+ command->GetInteger(kIdParam, &id);
+ command->GetString(kMethodParam, &method);
+ DevToolsProtocolDispatcher::CommandHandler command_handler(
+ dispatcher_.FindCommandHandler(method));
+ if (!command_handler.is_null())
+ return command_handler.Run(id, TakeDictionary(command.get(), kParamsParam));
+ return false;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/devtools/protocol/devtools_protocol_handler.h b/chromium/content/browser/devtools/protocol/devtools_protocol_handler.h
new file mode 100644
index 00000000000..70bd1f796e5
--- /dev/null
+++ b/chromium/content/browser/devtools/protocol/devtools_protocol_handler.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_PROTOCOL_DEVTOOLS_PROTOCOL_HANDLER_H_
+#define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_DEVTOOLS_PROTOCOL_HANDLER_H_
+
+#include "content/browser/devtools/protocol/devtools_protocol_dispatcher.h"
+
+namespace content {
+
+class DevToolsProtocolHandler {
+ public:
+ using Response = DevToolsProtocolClient::Response;
+ using Notifier = base::Callback<void(const std::string& message)>;
+
+ explicit DevToolsProtocolHandler(const Notifier& notifier);
+ virtual ~DevToolsProtocolHandler();
+
+ scoped_ptr<base::DictionaryValue> ParseCommand(const std::string& message);
+ void HandleCommand(scoped_ptr<base::DictionaryValue> command);
+ bool HandleOptionalCommand(scoped_ptr<base::DictionaryValue> command);
+
+ DevToolsProtocolDispatcher* dispatcher() { return &dispatcher_; }
+
+ private:
+ DevToolsProtocolClient client_;
+ DevToolsProtocolDispatcher dispatcher_;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_DEVTOOLS_PROTOCOL_DEVTOOLS_PROTOCOL_HANDLER_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
index dd165faec5f..cc2aa130b68 100755
--- a/chromium/content/browser/devtools/protocol/devtools_protocol_handler_generator.py
+++ b/chromium/content/browser/devtools/protocol/devtools_protocol_handler_generator.py
@@ -7,9 +7,10 @@ import sys
import string
import json
-input_json_path = sys.argv[1]
-output_cc_path = sys.argv[2]
-output_h_path = sys.argv[3]
+blink_protocol_path = sys.argv[1]
+browser_protocol_path = sys.argv[2]
+output_cc_path = sys.argv[3]
+output_h_path = sys.argv[4]
header = """\
// Copyright 2014 The Chromium Authors. All rights reserved.
@@ -19,48 +20,86 @@ header = """\
// 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
+// third_party/WebKit/Source/devtools/protocol.json and
+// content/browser/devtools/browser_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_
+#ifndef CONTENT_BROWSER_DEVTOOLS_PROTOCOL_DEVTOOLS_PROTOCOL_DISPATCHER_H_
+#define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_DEVTOOLS_PROTOCOL_DISPATCHER_H_
-#include "content/browser/devtools/devtools_protocol.h"
#include "content/browser/devtools/protocol/devtools_protocol_client.h"
namespace content {
-class DevToolsProtocolHandlerImpl;
+class DevToolsProtocolDispatcher;
namespace devtools {
+extern const char kProtocolVersion[];
+
+bool IsSupportedProtocolVersion(const std::string& version);
+
+template<typename T>
+base::Value* CreateValue(const T& param) {
+ return new base::FundamentalValue(param);
+}
+
+template<class T>
+base::Value* CreateValue(scoped_ptr<T>& param) {
+ return param.release();
+}
+
+template<class T>
+base::Value* CreateValue(scoped_refptr<T> param) {
+ return param->ToValue().release();
+}
+
+template<typename T>
+base::Value* CreateValue(const std::vector<T> param) {
+ base::ListValue* result = new base::ListValue();
+ for (auto& item : param) {
+ result->Append(CreateValue(item));
+ }
+ return result;
+}
+
+template<>
+base::Value* CreateValue(const std::string& param);
+
${types}\
} // namespace devtools
-class DevToolsProtocolHandlerImpl : public DevToolsProtocol::Handler {
+class DevToolsProtocolDispatcher {
public:
- typedef DevToolsProtocolClient::Response Response;
- typedef DevToolsProtocolClient::ResponseStatus ResponseStatus;
+ using Notifier = DevToolsProtocolClient::RawMessageCallback;
+ using CommandHandler =
+ base::Callback<bool(int, scoped_ptr<base::DictionaryValue>)>;
+
+ explicit DevToolsProtocolDispatcher(const Notifier& notifier);
+ ~DevToolsProtocolDispatcher();
- DevToolsProtocolHandlerImpl();
- virtual ~DevToolsProtocolHandlerImpl();
+ CommandHandler FindCommandHandler(const std::string& method);
${setters}\
private:
-${friends}\
+ using Response = DevToolsProtocolClient::Response;
+ using CommandHandlers = std::map<std::string, CommandHandler>;
${methods}\
+ Notifier notifier_;
+ DevToolsProtocolClient client_;
+ CommandHandlers command_handlers_;
${fields}\
};
} // namespace content
-#endif // CONTENT_BROWSER_DEVTOOLS_PROTOCOL_DEVTOOLS_PROTOCOL_HANDLER_IMPL_H_
+#endif // CONTENT_BROWSER_DEVTOOLS_PROTOCOL_DEVTOOLS_PROTOCOL_DISPATCHER_H_
""")
tmpl_typedef = string.Template("""\
@@ -71,30 +110,77 @@ typedef ${param_type} ${declared_name};
tmpl_struct = string.Template("""\
namespace ${domain} {
-struct ${declared_name} {
+template<int MASK>
+struct ${declared_name}Builder
+ : base::RefCounted<${declared_name}Builder<MASK>> {
public:
- ${declared_name}();
+ enum {
+ kAllSet = 0,
+${fields_enum}\
+ };
${methods}\
+ static scoped_refptr<${declared_name}Builder<kNoneSet>> Create() {
+ return new ${declared_name}Builder<kNoneSet>();
+ }
+
+ scoped_ptr<base::DictionaryValue> ToValue() {
+ static_assert(MASK == kAllSet, "required properties missing");
+ return make_scoped_ptr(dict_->DeepCopy());
+ }
+
private:
- friend class ::content::DevToolsProtocolHandlerImpl;
+ friend struct ${declared_name}Builder<0>;
-${fields}\
+ ${declared_name}Builder() : dict_(new base::DictionaryValue()) {
+ }
+
+ template<class T> T* ThisAs() {
+ static_assert(sizeof(*this) == sizeof(T), "cannot cast");
+ return reinterpret_cast<T*>(this);
+ }
+
+ scoped_ptr<base::DictionaryValue> dict_;
};
+
+typedef ${declared_name}Builder<0> ${declared_name};
+
} // namespace ${domain}
""")
-tmpl_struct_setter = string.Template("""\
- void set_${param}(${pass_type} ${param});
+tmpl_builder_setter_req = string.Template("""\
+ scoped_refptr<${declared_name}Builder<MASK & ~k${Param}>>
+ set_${param}(${pass_type} ${param}) {
+ static_assert(MASK & k${Param}, "already set");
+ dict_->Set("${proto_param}", CreateValue(${param}));
+ return ThisAs<${declared_name}Builder<MASK & ~k${Param}>>();
+ }
+""")
+
+tmpl_builder_setter_opt = string.Template("""\
+ scoped_refptr<${declared_name}Builder<MASK>>
+ set_${param}(${pass_type} ${param}) {
+ dict_->Set("${proto_param}", CreateValue(${param}));
+ return this;
+ }
""")
-tmpl_struct_field = string.Template("""\
- ${param_type} ${param}_;
- bool has_${param}_;
+tmpl_builder_enum = string.Template("""\
+ k${Param} = 1 << ${ordinal},
""")
-tmpl_enum = string.Template("""\
+tmpl_builder_none_set = string.Template("""\
+ kNoneSet = ${all_fields}
+""")
+
+tmpl_named_enum = string.Template("""\
+namespace ${domain} {
+${values}\
+} // namespace ${domain}
+""")
+
+tmpl_inline_enum = string.Template("""\
namespace ${domain} {
namespace ${subdomain} {
${values}\
@@ -103,11 +189,11 @@ ${values}\
""")
tmpl_enum_value = string.Template("""\
-extern const char k${Param}${Value}[];
+extern const char k${Enum}${Value}[];
""")
tmpl_enum_value_def = string.Template("""\
-const char k${Param}${Value}[] = "${value}";
+const char k${Enum}${Value}[] = "${value}";
""")
tmpl_handler = string.Template("""\
@@ -120,8 +206,8 @@ tmpl_client = string.Template("""\
namespace ${domain} {
class Client : public DevToolsProtocolClient {
public:
- Client(const RawMessageCallback& raw_message_callback);
- virtual ~Client();
+ explicit Client(const RawMessageCallback& raw_message_callback);
+ ~Client() override;
${methods}\
};
@@ -130,13 +216,13 @@ ${methods}\
tmpl_event = string.Template("""\
void ${Command}(
- const ${Command}Params& params);
+ scoped_refptr<${Command}Params> params);
""")
tmpl_response = string.Template("""\
void Send${Command}Response(
- scoped_refptr<DevToolsProtocol::Command> command,
- const ${Command}Response& params);
+ DevToolsCommandId command_id,
+ scoped_refptr<${Command}Response> params);
""")
tmpl_setter = string.Template("""\
@@ -144,19 +230,10 @@ tmpl_setter = string.Template("""\
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);
+ bool On${Domain}${Command}(
+ DevToolsCommandId command_id,
+ scoped_ptr<base::DictionaryValue> params);
""")
tmpl_field = string.Template("""\
@@ -165,53 +242,50 @@ tmpl_field = string.Template("""\
template_cc = string.Template(header + """\
-#include "content/browser/devtools/protocol/devtools_protocol_handler_impl.h"
+#include "content/browser/devtools/protocol/devtools_protocol_handler.h"
#include "base/bind.h"
+#include "base/strings/string_number_conversions.h"
${includes}\
namespace content {
-DevToolsProtocolHandlerImpl::DevToolsProtocolHandlerImpl()
- : ${fields_init} {
+DevToolsProtocolDispatcher::DevToolsProtocolDispatcher(
+ const Notifier& notifier)
+ : notifier_(notifier),
+ client_(notifier),
+ ${fields_init} {
}
-DevToolsProtocolHandlerImpl::~DevToolsProtocolHandlerImpl() {
+DevToolsProtocolDispatcher::~DevToolsProtocolDispatcher() {
}
-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;
+DevToolsProtocolDispatcher::CommandHandler
+DevToolsProtocolDispatcher::FindCommandHandler(const std::string& method) {
+ CommandHandlers::iterator it = command_handlers_.find(method);
+ return it == command_handlers_.end() ? CommandHandler() : it->second;
}
-} // namespace
-
${methods}\
namespace devtools {
+const char kProtocolVersion[] = "${major}.${minor}";
+
+bool IsSupportedProtocolVersion(const std::string& version) {
+ std::vector<std::string> tokens;
+ Tokenize(version, ".", &tokens);
+ int major, minor;
+ return tokens.size() == 2 &&
+ base::StringToInt(tokens[0], &major) && major == ${major} &&
+ base::StringToInt(tokens[1], &minor) && minor <= ${minor};
+}
+
+template<>
+base::Value* CreateValue(const std::string& param) {
+ return new base::StringValue(param);
+}
+
${types}\
} // namespace devtools
@@ -223,10 +297,10 @@ tmpl_include = string.Template("""\
#include "content/browser/devtools/protocol/${domain}_handler.h"
""")
-tmpl_field_init = string.Template("${domain}_handler_(NULL)")
+tmpl_field_init = string.Template("${domain}_handler_(nullptr)")
tmpl_setter_impl = string.Template("""\
-void DevToolsProtocolHandlerImpl::Set${Domain}Handler(
+void DevToolsProtocolDispatcher::Set${Domain}Handler(
devtools::${domain}::${Domain}Handler* ${domain}_handler) {
DCHECK(!${domain}_handler_);
${domain}_handler_ = ${domain}_handler;
@@ -235,71 +309,79 @@ ${initializations}\
""")
tmpl_register = string.Template("""\
- RegisterCommandHandler(
- "${Domain}.${command}",
+ command_handlers_["${Domain}.${command}"] =
base::Bind(
- &DevToolsProtocolHandlerImpl::On${Domain}${Command},
- base::Unretained(this)));
+ &DevToolsProtocolDispatcher::On${TargetDomain}${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)))));
+ new devtools::${domain}::Client(notifier_)));
""")
tmpl_callback_impl = string.Template("""\
-scoped_refptr<DevToolsProtocol::Response>
-DevToolsProtocolHandlerImpl::On${Domain}${Command}(
- scoped_refptr<DevToolsProtocol::Command> command) {
+bool DevToolsProtocolDispatcher::On${Domain}${Command}(
+ DevToolsCommandId command_id,
+ scoped_ptr<base::DictionaryValue> params) {
${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();
+ scoped_ptr<base::DictionaryValue> protocol_response;
+ if (client_.SendError(command_id, response))
+ return true;
+ if (response.IsFallThrough())
+ return false;
+ scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue());
${wrap}\
- return command->SuccessResponse(dict);
+ client_.SendSuccess(command_id, result.Pass());
+ return true;
}
""")
+tmpl_wrap = string.Template("""\
+ result->Set("${proto_param}", devtools::CreateValue(out_${param}));
+""")
+
tmpl_callback_async_impl = string.Template("""\
-scoped_refptr<DevToolsProtocol::Response>
-DevToolsProtocolHandlerImpl::On${Domain}${Command}(
- scoped_refptr<DevToolsProtocol::Command> command) {
+bool DevToolsProtocolDispatcher::On${Domain}${Command}(
+ DevToolsCommandId command_id,
+ scoped_ptr<base::DictionaryValue> params) {
${prep}\
- return ${domain}_handler_->${Command}(${args});
+ Response response = ${domain}_handler_->${Command}(${args});
+ if (client_.SendError(command_id, response))
+ return true;
+ return !response.IsFallThrough();
}
""")
-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}");
+ ${raw_type} in_${param}${init};
+ if (!params || !params->Get${Type}("${proto_param}", &in_${param})) {
+ client_.SendError(command_id, Response::InvalidParams("${proto_param}"));
+ return true;
+ }
""")
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};
+ base::ListValue* list_${param} = nullptr;
+ if (!params || !params->GetList("${proto_param}", &list_${param})) {
+ client_.SendError(command_id, Response::InvalidParams("${proto_param}"));
+ return true;
+ }
+ std::vector<${item_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);
+ ${item_raw_type} item;
+ if (!(*it)->GetAs${ItemType}(&item)) {
+ client_.SendError(command_id, Response::InvalidParams("${proto_param}"));
+ return true;
+ }
+ in_${param}.push_back(${item_pass});
}
""")
tmpl_prep_opt = string.Template("""\
- ${param_type} in_${param}${init};
+ ${raw_type} in_${param}${init};
bool ${param}_found = params && params->Get${Type}(
"${proto_param}",
&in_${param});
@@ -309,48 +391,15 @@ 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_arg_name = string.Template("in_${param}")
-tmpl_struct_impl = string.Template("""\
-namespace ${domain} {
+tmpl_arg_req = string.Template("${param_pass}")
-${declared_name}::${declared_name}()${fields} {
-}
-
-${methods}\
-
-} // namespace ${domain}
-""")
-
-tmpl_struct_field_init = string.Template("has_${param}_(false)")
+tmpl_arg_opt = string.Template(
+ "${param}_found ? ${param_pass} : nullptr")
-tmpl_struct_setter_impl = string.Template("""\
-void ${declared_name}::set_${param}(
- ${pass_type} ${param}) {
- ${param}_ = ${param};
- has_${param}_ = true;
-}
-""")
+tmpl_object_pass = string.Template(
+ "make_scoped_ptr<base::DictionaryValue>(${name}->DeepCopy())")
tmpl_client_impl = string.Template("""\
namespace ${domain} {
@@ -369,68 +418,25 @@ ${methods}\
tmpl_event_impl = string.Template("""\
void Client::${Command}(
- const ${Command}Params& params) {
+ scoped_refptr<${Command}Params> params) {
SendNotification("${Domain}.${command}",
- DevToolsProtocolHandlerImpl::ToValue(params));
+ params->ToValue().Pass());
}
""")
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)));
+ DevToolsCommandId command_id,
+ scoped_refptr<${Command}Response> params) {
+ SendSuccess(command_id, params->ToValue().Pass());
}
""")
-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):
@@ -443,61 +449,74 @@ def Uncamelcase(s):
return result
types = {}
-json_api = json.loads(open(input_json_path, "r").read())
+blink_protocol = json.loads(open(blink_protocol_path, "r").read())
+browser_protocol = json.loads(open(browser_protocol_path, "r").read())
type_decls = []
type_impls = []
handler_methods = []
handler_method_impls = []
+domain_maps = []
+redirects = {}
+
+all_domains = blink_protocol["domains"] + browser_protocol["domains"]
-for json_domain in json_api["domains"]:
+for json_domain in all_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 = []
+ fields_enum = []
+ enum_items = []
+ req_fields_num = 0
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"]
+ prop_map["Param"] = Capitalize(json_prop["name"])
+ prop_map["subdomain"] = Uncamelcase(prop_map["declared_name"])
+ del prop_map["declared_name"]
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))
+ methods.append(tmpl_builder_setter_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"])
-
+ methods.append(tmpl_builder_setter_req.substitute(prop_map))
+ enum_items.append("k%s" % prop_map["Param"]);
+ fields_enum.append(tmpl_builder_enum.substitute(prop_map,
+ ordinal = req_fields_num))
+ req_fields_num += 1
+
+ all_fields = "kAllSet"
+ if len(enum_items) > 0:
+ all_fields = " | ".join(enum_items)
+ fields_enum.append(tmpl_builder_none_set.substitute(mapping,
+ all_fields = all_fields))
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)))
+ methods = "\n".join(methods),
+ fields_enum = "".join(fields_enum)))
+
+def DeclareEnum(json, mapping):
+ values = []
+ value_defs = []
+ tmpl_enum = tmpl_inline_enum
+ if "declared_name" in mapping:
+ mapping["Enum"] = mapping["declared_name"]
+ tmpl_enum = tmpl_named_enum
+ else:
+ mapping["Enum"] = 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)))
def ResolveRef(json, mapping):
dot_pos = json["$ref"].find(".")
@@ -510,52 +529,59 @@ def ResolveRef(json, mapping):
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["domain"] = Uncamelcase(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 not "___type_declared" in json_type:
+ json_type["___type_declared"] = True;
if (json_type.get("type") == "object") and ("properties" in json_type):
DeclareStruct(json_type["properties"], mapping)
else:
+ if ("enum" in json_type):
+ DeclareEnum(json_type, mapping)
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)
+ if items_map["Type"] == "List":
+ # TODO(dgozman) Implement this.
+ raise Exception("Nested arrays are not implemented")
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["storage_type"] = "std::vector<%s>" % items_map["storage_type"]
+ mapping["raw_type"] = mapping["storage_type"]
mapping["prep_req"] = tmpl_prep_req_list.substitute(mapping,
- item_type = items_map["param_type"],
+ item_type = items_map["storage_type"],
item_init = items_map["init"],
+ item_raw_type = items_map["raw_type"],
+ item_pass = items_map["pass_template"].substitute(name="item", opt=""),
ItemType = items_map["Type"])
- # TODO(vkuzkokov) mapping["append"]: template for array of arrays.
+ mapping["arg_out"] = "&out_%s" % mapping["param"]
def ResolveObject(json, mapping):
mapping["Type"] = "Dictionary"
+ mapping["storage_type"] = "scoped_ptr<base::DictionaryValue>"
+ mapping["raw_type"] = "base::DictionaryValue*"
+ mapping["pass_template"] = tmpl_object_pass
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)
+ mapping["param_type"] = ("scoped_refptr<%s>" %
+ 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)
+ else:
+ mapping["param_type"] = ("scoped_refptr<%s>" %
+ tmpl_typename.substitute(mapping))
mapping["pass_type"] = mapping["param_type"]
+ mapping["arg_out"] = "&out_%s" % mapping["param"]
+ else:
+ mapping["param_type"] = "base::DictionaryValue"
+ mapping["pass_type"] = "scoped_ptr<base::DictionaryValue>"
+ mapping["arg_out"] = "out_%s.get()" % mapping["param"]
+ mapping["prep_req"] = tmpl_prep_req.substitute(mapping)
def ResolvePrimitive(json, mapping):
jsonrpc_type = json["type"]
@@ -575,34 +601,22 @@ def ResolvePrimitive(json, mapping):
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:
+ if "enum" in json and not "declared_name" in mapping:
+ if not "subdomain" in mapping:
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)))
+ DeclareEnum(json, mapping)
else:
raise Exception("Unknown type: %s" % json_type)
- mapping["wrap"] = tmpl_wrap.substitute(mapping)
- mapping["append"] = tmpl_append.substitute(mapping)
+ mapping["storage_type"] = mapping["param_type"]
+ mapping["raw_type"] = mapping["param_type"]
mapping["prep_req"] = tmpl_prep_req.substitute(mapping)
if jsonrpc_type != "string":
mapping["pass_type"] = mapping["param_type"]
+ mapping["arg_out"] = "&out_%s" % mapping["param"]
def ResolveType(json, mapping):
mapping["init"] = ""
+ mapping["pass_template"] = string.Template("${opt}${name}")
if "$ref" in json:
ResolveRef(json, mapping)
elif "type" in json:
@@ -618,16 +632,15 @@ def ResolveType(json, mapping):
(mapping["Domain"], mapping["command"], mapping["proto_param"]))
setters = []
-friends = []
fields = []
includes = []
fields_init = []
-for json_domain in json_api["domains"]:
+for json_domain in all_domains:
domain_map = {}
domain_map["Domain"] = json_domain["domain"]
- domain_map["domain"] = Decapitalize(json_domain["domain"])
+ domain_map["domain"] = Uncamelcase(json_domain["domain"])
initializations = []
client_methods = []
@@ -646,6 +659,15 @@ for json_domain in json_api["domains"]:
command_map["command"] = json_command["name"]
command_map["Command"] = Capitalize(json_command["name"])
+ if "redirect" in json_command:
+ redirect_domain = json_command["redirect"]
+ if not (redirect_domain in redirects):
+ redirects[redirect_domain] = []
+ command_map["TargetDomain"] = redirect_domain
+ redirects[redirect_domain].append(tmpl_register.substitute(command_map))
+ continue
+
+ command_map["TargetDomain"] = command_map["Domain"]
prep = []
args = []
@@ -654,22 +676,26 @@ for json_domain in json_api["domains"]:
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"]:
+ if param_map["Type"] in ["List"]:
# 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")
+ "Optional array parameters are not implemented")
prep.append(tmpl_prep_opt.substitute(param_map))
- args.append(tmpl_arg_opt.substitute(param_map))
+ param_pass = param_map["pass_template"].substitute(
+ name=tmpl_arg_name.substitute(param_map),
+ opt="&")
+ args.append(
+ tmpl_arg_opt.substitute(param_map, param_pass=param_pass))
else:
prep.append(param_map["prep_req"])
- args.append(tmpl_arg_req.substitute(param_map))
+ param_pass = param_map["pass_template"].substitute(
+ name=tmpl_arg_name.substitute(param_map),
+ opt="")
+ args.append(
+ tmpl_arg_req.substitute(param_map, param_pass=param_pass))
if json_command.get("async"):
domain_needs_client = True
@@ -681,7 +707,7 @@ for json_domain in json_api["domains"]:
# 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")
+ args.insert(0, "command_id")
handler_method_impls.append(
tmpl_callback_async_impl.substitute(command_map,
prep = "".join(prep),
@@ -695,18 +721,13 @@ for json_domain in json_api["domains"]:
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.append(param_map["arg_out"])
+ wrap.append(tmpl_wrap.substitute(param_map))
args_str = ""
if len(args) > 0:
args_str = "\n " + ",\n ".join(args)
@@ -749,13 +770,17 @@ for json_domain in json_api["domains"]:
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)))
+ domain_map["initializations"] = "".join(initializations)
+ domain_maps.append(domain_map)
+for domain_map in domain_maps:
+ domain = domain_map["Domain"]
+ if domain in redirects:
+ domain_map["initializations"] += "".join(redirects[domain])
+ handler_method_impls.append(tmpl_setter_impl.substitute(domain_map))
output_h_file = open(output_h_path, "w")
output_cc_file = open(output_cc_path, "w")
@@ -763,12 +788,13 @@ 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({},
+ major = blink_protocol["version"]["major"],
+ minor = blink_protocol["version"]["minor"],
includes = "".join(sorted(includes)),
fields_init = ",\n ".join(fields_init),
methods = "\n".join(handler_method_impls),
diff --git a/chromium/content/browser/devtools/protocol/dom_handler.cc b/chromium/content/browser/devtools/protocol/dom_handler.cc
index 9ddf4092b52..0022c2ec800 100644
--- a/chromium/content/browser/devtools/protocol/dom_handler.cc
+++ b/chromium/content/browser/devtools/protocol/dom_handler.cc
@@ -6,7 +6,7 @@
#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"
+#include "content/browser/frame_host/render_frame_host_impl.h"
namespace content {
namespace devtools {
@@ -20,7 +20,7 @@ DOMHandler::DOMHandler() : host_(nullptr) {
DOMHandler::~DOMHandler() {
}
-void DOMHandler::SetRenderViewHost(RenderViewHostImpl* host) {
+void DOMHandler::SetRenderFrameHost(RenderFrameHostImpl* host) {
host_ = host;
}
diff --git a/chromium/content/browser/devtools/protocol/dom_handler.h b/chromium/content/browser/devtools/protocol/dom_handler.h
index d2b20e24e0c..ff3ad39ca48 100644
--- a/chromium/content/browser/devtools/protocol/dom_handler.h
+++ b/chromium/content/browser/devtools/protocol/dom_handler.h
@@ -5,11 +5,11 @@
#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"
+#include "content/browser/devtools/protocol/devtools_protocol_handler.h"
namespace content {
-class RenderViewHostImpl;
+class RenderFrameHostImpl;
namespace devtools {
namespace dom {
@@ -21,13 +21,13 @@ class DOMHandler {
DOMHandler();
virtual ~DOMHandler();
- void SetRenderViewHost(RenderViewHostImpl* host);
+ void SetRenderFrameHost(RenderFrameHostImpl* host);
Response SetFileInputFiles(NodeId node_id,
const std::vector<std::string>& files);
private:
- RenderViewHostImpl* host_;
+ RenderFrameHostImpl* host_;
DISALLOW_COPY_AND_ASSIGN(DOMHandler);
};
diff --git a/chromium/content/browser/devtools/protocol/emulation_handler.cc b/chromium/content/browser/devtools/protocol/emulation_handler.cc
new file mode 100644
index 00000000000..84e6a2a488f
--- /dev/null
+++ b/chromium/content/browser/devtools/protocol/emulation_handler.cc
@@ -0,0 +1,215 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/devtools/protocol/emulation_handler.h"
+
+#include "base/strings/string_number_conversions.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
+#include "content/browser/geolocation/geolocation_service_context.h"
+#include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/common/view_messages.h"
+#include "content/public/common/url_constants.h"
+
+namespace content {
+namespace devtools {
+namespace emulation {
+
+using Response = DevToolsProtocolClient::Response;
+
+namespace {
+
+ui::GestureProviderConfigType TouchEmulationConfigurationToType(
+ const std::string& protocol_value) {
+ ui::GestureProviderConfigType result =
+ ui::GestureProviderConfigType::CURRENT_PLATFORM;
+ if (protocol_value ==
+ set_touch_emulation_enabled::kConfigurationMobile) {
+ result = ui::GestureProviderConfigType::GENERIC_MOBILE;
+ }
+ if (protocol_value ==
+ set_touch_emulation_enabled::kConfigurationDesktop) {
+ result = ui::GestureProviderConfigType::GENERIC_DESKTOP;
+ }
+ return result;
+}
+
+} // namespace
+
+EmulationHandler::EmulationHandler(page::PageHandler* page_handler)
+ : touch_emulation_enabled_(false),
+ device_emulation_enabled_(false),
+ page_handler_(page_handler),
+ host_(nullptr)
+{
+ page_handler->SetScreencastListener(this);
+}
+
+EmulationHandler::~EmulationHandler() {
+}
+
+void EmulationHandler::ScreencastEnabledChanged() {
+ UpdateTouchEventEmulationState();
+}
+
+void EmulationHandler::SetRenderFrameHost(RenderFrameHostImpl* host) {
+ if (host_ == host)
+ return;
+
+ host_ = host;
+ UpdateTouchEventEmulationState();
+ UpdateDeviceEmulationState();
+}
+
+void EmulationHandler::Detached() {
+ touch_emulation_enabled_ = false;
+ device_emulation_enabled_ = false;
+ UpdateTouchEventEmulationState();
+ UpdateDeviceEmulationState();
+}
+
+Response EmulationHandler::SetGeolocationOverride(
+ double* latitude, double* longitude, double* accuracy) {
+ if (!GetWebContents())
+ return Response::InternalError("Could not connect to view");
+
+ GeolocationServiceContext* geolocation_context =
+ GetWebContents()->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 EmulationHandler::ClearGeolocationOverride() {
+ if (!GetWebContents())
+ return Response::InternalError("Could not connect to view");
+
+ GeolocationServiceContext* geolocation_context =
+ GetWebContents()->GetGeolocationServiceContext();
+ geolocation_context->ClearOverride();
+ return Response::OK();
+}
+
+Response EmulationHandler::SetTouchEmulationEnabled(
+ bool enabled, const std::string* configuration) {
+ touch_emulation_enabled_ = enabled;
+ touch_emulation_configuration_ =
+ configuration ? *configuration : std::string();
+ UpdateTouchEventEmulationState();
+ return Response::FallThrough();
+}
+
+Response EmulationHandler::CanEmulate(bool* result) {
+#if defined(OS_ANDROID)
+ *result = false;
+#else
+ *result = true;
+ if (WebContentsImpl* web_contents = GetWebContents())
+ *result &= !web_contents->GetVisibleURL().SchemeIs(kChromeDevToolsScheme);
+#endif // defined(OS_ANDROID)
+ return Response::OK();
+}
+
+Response EmulationHandler::SetDeviceMetricsOverride(
+ int width, int height, double device_scale_factor, bool mobile,
+ bool fit_window, const double* optional_scale,
+ const double* optional_offset_x, const double* optional_offset_y) {
+ const static int max_size = 10000000;
+ const static double max_scale = 10;
+
+ if (!host_)
+ return Response::InternalError("Could not connect to view");
+
+ if (width < 0 || height < 0 || width > max_size || height > max_size) {
+ return Response::InvalidParams(
+ "Width and height values must be positive, not greater than " +
+ base::IntToString(max_size));
+ }
+
+ if (device_scale_factor < 0)
+ return Response::InvalidParams("deviceScaleFactor must be non-negative");
+
+ if (optional_scale && (*optional_scale <= 0 || *optional_scale > max_scale)) {
+ return Response::InvalidParams(
+ "scale must be positive, not greater than " +
+ base::IntToString(max_scale));
+ }
+
+ blink::WebDeviceEmulationParams params;
+ params.screenPosition = mobile ? blink::WebDeviceEmulationParams::Mobile :
+ blink::WebDeviceEmulationParams::Desktop;
+ params.deviceScaleFactor = device_scale_factor;
+ params.viewSize = blink::WebSize(width, height);
+ params.fitToView = fit_window;
+ params.scale = optional_scale ? *optional_scale : 1;
+ params.offset = blink::WebFloatPoint(
+ optional_offset_x ? *optional_offset_x : 0.f,
+ optional_offset_y ? *optional_offset_y : 0.f);
+
+ if (device_emulation_enabled_ && params == device_emulation_params_)
+ return Response::OK();
+
+ device_emulation_enabled_ = true;
+ device_emulation_params_ = params;
+ UpdateDeviceEmulationState();
+ return Response::OK();
+}
+
+Response EmulationHandler::ClearDeviceMetricsOverride() {
+ if (!device_emulation_enabled_)
+ return Response::OK();
+
+ device_emulation_enabled_ = false;
+ UpdateDeviceEmulationState();
+ return Response::OK();
+}
+
+WebContentsImpl* EmulationHandler::GetWebContents() {
+ return host_ ?
+ static_cast<WebContentsImpl*>(WebContents::FromRenderFrameHost(host_)) :
+ nullptr;
+}
+
+void EmulationHandler::UpdateTouchEventEmulationState() {
+ RenderWidgetHostImpl* widget_host =
+ host_ ? host_->GetRenderWidgetHost() : nullptr;
+ if (!widget_host)
+ return;
+ bool enabled = touch_emulation_enabled_ ||
+ page_handler_->screencast_enabled();
+ ui::GestureProviderConfigType config_type =
+ TouchEmulationConfigurationToType(touch_emulation_configuration_);
+ widget_host->SetTouchEventEmulationEnabled(enabled, config_type);
+ if (GetWebContents())
+ GetWebContents()->SetForceDisableOverscrollContent(enabled);
+}
+
+void EmulationHandler::UpdateDeviceEmulationState() {
+ RenderWidgetHostImpl* widget_host =
+ host_ ? host_->GetRenderWidgetHost() : nullptr;
+ if (!widget_host)
+ return;
+ if (device_emulation_enabled_) {
+ widget_host->Send(new ViewMsg_EnableDeviceEmulation(
+ widget_host->GetRoutingID(), device_emulation_params_));
+ } else {
+ widget_host->Send(new ViewMsg_DisableDeviceEmulation(
+ widget_host->GetRoutingID()));
+ }
+}
+
+} // namespace emulation
+} // namespace devtools
+} // namespace content
diff --git a/chromium/content/browser/devtools/protocol/emulation_handler.h b/chromium/content/browser/devtools/protocol/emulation_handler.h
new file mode 100644
index 00000000000..5303663c107
--- /dev/null
+++ b/chromium/content/browser/devtools/protocol/emulation_handler.h
@@ -0,0 +1,76 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_DEVTOOLS_PROTOCOL_EMULATION_HANDLER_H_
+#define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_EMULATION_HANDLER_H_
+
+#include "content/browser/devtools/protocol/devtools_protocol_handler.h"
+#include "content/browser/devtools/protocol/page_handler.h"
+#include "third_party/WebKit/public/web/WebDeviceEmulationParams.h"
+
+namespace content {
+
+class RenderFrameHostImpl;
+class WebContentsImpl;
+
+namespace devtools {
+
+namespace page { class PageHandler; }
+
+namespace emulation {
+
+class EmulationHandler : public page::PageHandler::ScreencastListener {
+ public:
+ using Response = DevToolsProtocolClient::Response;
+
+ explicit EmulationHandler(page::PageHandler* page_handler);
+ ~EmulationHandler() override;
+
+ // page::PageHandler::ScreencastListener implementation.
+ void ScreencastEnabledChanged() override;
+
+ void SetRenderFrameHost(RenderFrameHostImpl* host);
+ void Detached();
+
+ Response SetGeolocationOverride(double* latitude,
+ double* longitude,
+ double* accuracy);
+ Response ClearGeolocationOverride();
+
+ Response SetTouchEmulationEnabled(bool enabled,
+ const std::string* configuration);
+
+ Response CanEmulate(bool* result);
+ Response SetDeviceMetricsOverride(int width,
+ int height,
+ double device_scale_factor,
+ bool mobile,
+ bool fit_window,
+ const double* optional_scale,
+ const double* optional_offset_x,
+ const double* optional_offset_y);
+ Response ClearDeviceMetricsOverride();
+
+ private:
+ WebContentsImpl* GetWebContents();
+ void UpdateTouchEventEmulationState();
+ void UpdateDeviceEmulationState();
+
+ bool touch_emulation_enabled_;
+ std::string touch_emulation_configuration_;
+
+ bool device_emulation_enabled_;
+ blink::WebDeviceEmulationParams device_emulation_params_;
+
+ page::PageHandler* page_handler_;
+ RenderFrameHostImpl* host_;
+
+ DISALLOW_COPY_AND_ASSIGN(EmulationHandler);
+};
+
+} // namespace emulation
+} // namespace devtools
+} // namespace content
+
+#endif // CONTENT_BROWSER_DEVTOOLS_PROTOCOL_EMULATION_HANDLER_H_
diff --git a/chromium/content/browser/devtools/protocol/input_handler.cc b/chromium/content/browser/devtools/protocol/input_handler.cc
index 05cff6195a1..55a3c743469 100644
--- a/chromium/content/browser/devtools/protocol/input_handler.cc
+++ b/chromium/content/browser/devtools/protocol/input_handler.cc
@@ -5,26 +5,246 @@
#include "content/browser/devtools/protocol/input_handler.h"
#include "base/strings/stringprintf.h"
-#include "content/browser/renderer_host/render_view_host_impl.h"
+#include "base/strings/utf_string_conversions.h"
+#include "cc/output/compositor_frame_metadata.h"
+#include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "content/common/input/synthetic_pinch_gesture_params.h"
+#include "content/common/input/synthetic_smooth_scroll_gesture_params.h"
+#include "content/common/input/synthetic_tap_gesture_params.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
+#include "ui/events/keycodes/dom/keycode_converter.h"
+#include "ui/gfx/geometry/point.h"
namespace content {
namespace devtools {
namespace input {
+namespace {
+
+gfx::Point CssPixelsToPoint(int x, int y, float page_scale_factor) {
+ return gfx::Point(x * page_scale_factor, y * page_scale_factor);
+}
+
+gfx::Vector2d CssPixelsToVector2d(int x, int y, float page_scale_factor) {
+ return gfx::Vector2d(x * page_scale_factor, y * page_scale_factor);
+}
+
+bool StringToGestureSourceType(const std::string& in,
+ SyntheticGestureParams::GestureSourceType& out) {
+ if (in == kGestureSourceTypeDefault) {
+ out = SyntheticGestureParams::GestureSourceType::DEFAULT_INPUT;
+ return true;
+ } else if (in == kGestureSourceTypeTouch) {
+ out = SyntheticGestureParams::GestureSourceType::TOUCH_INPUT;
+ return true;
+ } else if (in == kGestureSourceTypeMouse) {
+ out = SyntheticGestureParams::GestureSourceType::MOUSE_INPUT;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+}
+
typedef DevToolsProtocolClient::Response Response;
+namespace {
+
+void SetEventModifiers(blink::WebInputEvent* event, const int* modifiers) {
+ if (!modifiers)
+ return;
+ 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;
+}
+
+void SetEventTimestamp(blink::WebInputEvent* event, const double* timestamp) {
+ event->timeStampSeconds =
+ timestamp ? *timestamp : base::Time::Now().ToDoubleT();
+}
+
+bool SetKeyboardEventText(blink::WebUChar* to, const std::string* from) {
+ if (!from)
+ return true;
+
+ base::string16 text16 = base::UTF8ToUTF16(*from);
+ if (text16.size() > blink::WebKeyboardEvent::textLengthCap)
+ return false;
+
+ for (size_t i = 0; i < text16.size(); ++i)
+ to[i] = text16[i];
+ return true;
+}
+
+bool SetMouseEventButton(blink::WebMouseEvent* event,
+ const std::string* button) {
+ if (!button)
+ return true;
+
+ if (*button == dispatch_mouse_event::kButtonNone) {
+ event->button = blink::WebMouseEvent::ButtonNone;
+ } else if (*button == dispatch_mouse_event::kButtonLeft) {
+ event->button = blink::WebMouseEvent::ButtonLeft;
+ event->modifiers |= blink::WebInputEvent::LeftButtonDown;
+ } else if (*button == dispatch_mouse_event::kButtonMiddle) {
+ event->button = blink::WebMouseEvent::ButtonMiddle;
+ event->modifiers |= blink::WebInputEvent::MiddleButtonDown;
+ } else if (*button == dispatch_mouse_event::kButtonRight) {
+ event->button = blink::WebMouseEvent::ButtonRight;
+ event->modifiers |= blink::WebInputEvent::RightButtonDown;
+ } else {
+ return false;
+ }
+ return true;
+}
+
+bool SetMouseEventType(blink::WebMouseEvent* event, const std::string& type) {
+ if (type == dispatch_mouse_event::kTypeMousePressed) {
+ event->type = blink::WebInputEvent::MouseDown;
+ } else if (type == dispatch_mouse_event::kTypeMouseReleased) {
+ event->type = blink::WebInputEvent::MouseUp;
+ } else if (type == dispatch_mouse_event::kTypeMouseMoved) {
+ event->type = blink::WebInputEvent::MouseMove;
+ } else {
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
InputHandler::InputHandler()
- : host_(NULL) {
+ : host_(NULL),
+ page_scale_factor_(1.0),
+ weak_factory_(this) {
}
InputHandler::~InputHandler() {
}
-void InputHandler::SetRenderViewHost(RenderViewHostImpl* host) {
+void InputHandler::SetRenderWidgetHost(RenderWidgetHostImpl* host) {
host_ = host;
}
+void InputHandler::SetClient(scoped_ptr<Client> client) {
+ client_.swap(client);
+}
+
+void InputHandler::OnSwapCompositorFrame(
+ const cc::CompositorFrameMetadata& frame_metadata) {
+ page_scale_factor_ = frame_metadata.page_scale_factor;
+ scrollable_viewport_size_ = frame_metadata.scrollable_viewport_size;
+}
+
+Response InputHandler::DispatchKeyEvent(
+ const std::string& type,
+ const int* modifiers,
+ const double* timestamp,
+ const std::string* text,
+ const std::string* unmodified_text,
+ const std::string* key_identifier,
+ const std::string* code,
+ const int* windows_virtual_key_code,
+ const int* native_virtual_key_code,
+ const bool* auto_repeat,
+ const bool* is_keypad,
+ const bool* is_system_key) {
+ NativeWebKeyboardEvent event;
+
+ if (type == dispatch_key_event::kTypeKeyDown) {
+ event.type = blink::WebInputEvent::KeyDown;
+ } else if (type == dispatch_key_event::kTypeKeyUp) {
+ event.type = blink::WebInputEvent::KeyUp;
+ } else if (type == dispatch_key_event::kTypeChar) {
+ event.type = blink::WebInputEvent::Char;
+ } else if (type == dispatch_key_event::kTypeRawKeyDown) {
+ event.type = blink::WebInputEvent::RawKeyDown;
+ } else {
+ return Response::InvalidParams(
+ base::StringPrintf("Unexpected event type '%s'", type.c_str()));
+ }
+
+ SetEventModifiers(&event, modifiers);
+ SetEventTimestamp(&event, timestamp);
+ if (!SetKeyboardEventText(event.text, text))
+ return Response::InvalidParams("Invalid 'text' parameter");
+ if (!SetKeyboardEventText(event.unmodifiedText, unmodified_text))
+ return Response::InvalidParams("Invalid 'unmodifiedText' parameter");
+
+ if (key_identifier) {
+ if (key_identifier->size() >
+ blink::WebKeyboardEvent::keyIdentifierLengthCap) {
+ return Response::InvalidParams("Invalid 'keyIdentifier' parameter");
+ }
+ for (size_t i = 0; i < key_identifier->size(); ++i)
+ event.keyIdentifier[i] = (*key_identifier)[i];
+ }
+
+ if (code) {
+ event.domCode = static_cast<int>(
+ ui::KeycodeConverter::CodeStringToDomCode(code->c_str()));
+ }
+
+ if (windows_virtual_key_code)
+ event.windowsKeyCode = *windows_virtual_key_code;
+ if (native_virtual_key_code)
+ event.nativeKeyCode = *native_virtual_key_code;
+ if (auto_repeat && *auto_repeat)
+ event.modifiers |= blink::WebInputEvent::IsAutoRepeat;
+ if (is_keypad && *is_keypad)
+ event.modifiers |= blink::WebInputEvent::IsKeyPad;
+ if (is_system_key)
+ event.isSystemKey = *is_system_key;
+
+ if (!host_)
+ return Response::ServerError("Could not connect to view");
+
+ host_->Focus();
+ host_->ForwardKeyboardEvent(event);
+ return Response::OK();
+}
+
+Response InputHandler::DispatchMouseEvent(
+ const std::string& type,
+ int x,
+ int y,
+ const int* modifiers,
+ const double* timestamp,
+ const std::string* button,
+ const int* click_count) {
+ blink::WebMouseEvent event;
+
+ if (!SetMouseEventType(&event, type)) {
+ return Response::InvalidParams(
+ base::StringPrintf("Unexpected event type '%s'", type.c_str()));
+ }
+ SetEventModifiers(&event, modifiers);
+ SetEventTimestamp(&event, timestamp);
+ if (!SetMouseEventButton(&event, button))
+ return Response::InvalidParams("Invalid mouse button");
+
+ event.x = x;
+ event.y = y;
+ event.windowX = x;
+ event.windowY = y;
+ event.globalX = x;
+ event.globalY = y;
+ event.clickCount = click_count ? *click_count : 0;
+
+ if (!host_)
+ return Response::ServerError("Could not connect to view");
+
+ host_->Focus();
+ host_->ForwardMouseEvent(event);
+ return Response::OK();
+}
+
Response InputHandler::EmulateTouchFromMouseEvent(const std::string& type,
int x,
int y,
@@ -38,13 +258,7 @@ Response InputHandler::EmulateTouchFromMouseEvent(const std::string& type,
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 (type == emulate_touch_from_mouse_event::kTypeMouseWheel) {
if (!delta_x || !delta_y) {
return Response::InvalidParams(
"'deltaX' and 'deltaY' are expected for mouseWheel event");
@@ -53,48 +267,23 @@ Response InputHandler::EmulateTouchFromMouseEvent(const std::string& type,
wheel_event.deltaY = static_cast<float>(*delta_y);
event = &wheel_event;
event->type = blink::WebInputEvent::MouseWheel;
- } else {
+ } else if (!SetMouseEventType(event, type)) {
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;
- }
+ SetEventModifiers(event, modifiers);
+ SetEventTimestamp(event, &timestamp);
+ if (!SetMouseEventButton(event, &button))
+ return Response::InvalidParams("Invalid mouse button");
- 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()));
- }
+ event->clickCount = click_count ? *click_count : 0;
if (!host_)
return Response::ServerError("Could not connect to view");
@@ -106,6 +295,170 @@ Response InputHandler::EmulateTouchFromMouseEvent(const std::string& type,
return Response::OK();
}
+Response InputHandler::SynthesizePinchGesture(
+ DevToolsCommandId command_id,
+ int x,
+ int y,
+ double scale_factor,
+ const int* relative_speed,
+ const std::string* gesture_source_type) {
+ if (!host_)
+ return Response::ServerError("Could not connect to view");
+
+ SyntheticPinchGestureParams gesture_params;
+ const int kDefaultRelativeSpeed = 800;
+
+ gesture_params.scale_factor = scale_factor;
+ gesture_params.anchor = CssPixelsToPoint(x, y, page_scale_factor_);
+ gesture_params.relative_pointer_speed_in_pixels_s =
+ relative_speed ? *relative_speed : kDefaultRelativeSpeed;
+
+ if (!StringToGestureSourceType(
+ gesture_source_type ? *gesture_source_type : kGestureSourceTypeDefault,
+ gesture_params.gesture_source_type)) {
+ return Response::InvalidParams("gestureSourceType");
+ }
+
+ host_->QueueSyntheticGesture(
+ SyntheticGesture::Create(gesture_params),
+ base::Bind(&InputHandler::SendSynthesizePinchGestureResponse,
+ weak_factory_.GetWeakPtr(), command_id));
+
+ return Response::OK();
+}
+
+Response InputHandler::SynthesizeScrollGesture(
+ DevToolsCommandId command_id,
+ int x,
+ int y,
+ const int* x_distance,
+ const int* y_distance,
+ const int* x_overscroll,
+ const int* y_overscroll,
+ const bool* prevent_fling,
+ const int* speed,
+ const std::string* gesture_source_type) {
+ if (!host_)
+ return Response::ServerError("Could not connect to view");
+
+ SyntheticSmoothScrollGestureParams gesture_params;
+ const bool kDefaultPreventFling = true;
+ const int kDefaultSpeed = 800;
+
+ gesture_params.anchor = CssPixelsToPoint(x, y, page_scale_factor_);
+ gesture_params.prevent_fling =
+ prevent_fling ? *prevent_fling : kDefaultPreventFling;
+ gesture_params.speed_in_pixels_s = speed ? *speed : kDefaultSpeed;
+
+ if (x_distance || y_distance) {
+ gesture_params.distances.push_back(
+ CssPixelsToVector2d(x_distance ? *x_distance : 0,
+ y_distance ? *y_distance : 0,
+ page_scale_factor_));
+ }
+
+ if (x_overscroll || y_overscroll) {
+ gesture_params.distances.push_back(
+ CssPixelsToVector2d(x_overscroll ? -*x_overscroll : 0,
+ y_overscroll ? -*y_overscroll : 0,
+ page_scale_factor_));
+ }
+
+ if (!StringToGestureSourceType(
+ gesture_source_type ? *gesture_source_type : kGestureSourceTypeDefault,
+ gesture_params.gesture_source_type)) {
+ return Response::InvalidParams("gestureSourceType");
+ }
+
+ host_->QueueSyntheticGesture(
+ SyntheticGesture::Create(gesture_params),
+ base::Bind(&InputHandler::SendSynthesizeScrollGestureResponse,
+ weak_factory_.GetWeakPtr(), command_id));
+
+ return Response::OK();
+}
+
+Response InputHandler::SynthesizeTapGesture(
+ DevToolsCommandId command_id,
+ int x,
+ int y,
+ const int* duration,
+ const int* tap_count,
+ const std::string* gesture_source_type) {
+ if (!host_)
+ return Response::ServerError("Could not connect to view");
+
+ SyntheticTapGestureParams gesture_params;
+ const int kDefaultDuration = 50;
+ const int kDefaultTapCount = 1;
+
+ gesture_params.position = CssPixelsToPoint(x, y, page_scale_factor_);
+ gesture_params.duration_ms = duration ? *duration : kDefaultDuration;
+
+ if (!StringToGestureSourceType(
+ gesture_source_type ? *gesture_source_type : kGestureSourceTypeDefault,
+ gesture_params.gesture_source_type)) {
+ return Response::InvalidParams("gestureSourceType");
+ }
+
+ if (!tap_count)
+ tap_count = &kDefaultTapCount;
+
+ for (int i = 0; i < *tap_count; i++) {
+ // If we're doing more than one tap, don't send the response to the client
+ // until we've completed the last tap.
+ bool is_last_tap = i == *tap_count - 1;
+ host_->QueueSyntheticGesture(
+ SyntheticGesture::Create(gesture_params),
+ base::Bind(&InputHandler::SendSynthesizeTapGestureResponse,
+ weak_factory_.GetWeakPtr(), command_id, is_last_tap));
+ }
+
+ return Response::OK();
+}
+
+void InputHandler::SendSynthesizePinchGestureResponse(
+ DevToolsCommandId command_id,
+ SyntheticGesture::Result result) {
+ if (result == SyntheticGesture::Result::GESTURE_FINISHED) {
+ client_->SendSynthesizePinchGestureResponse(
+ command_id, SynthesizePinchGestureResponse::Create());
+ } else {
+ client_->SendError(command_id,
+ Response::InternalError(base::StringPrintf(
+ "Synthetic pinch failed, result was %d", result)));
+ }
+}
+
+void InputHandler::SendSynthesizeScrollGestureResponse(
+ DevToolsCommandId command_id,
+ SyntheticGesture::Result result) {
+ if (result == SyntheticGesture::Result::GESTURE_FINISHED) {
+ client_->SendSynthesizeScrollGestureResponse(
+ command_id, SynthesizeScrollGestureResponse::Create());
+ } else {
+ client_->SendError(command_id,
+ Response::InternalError(base::StringPrintf(
+ "Synthetic scroll failed, result was %d", result)));
+ }
+}
+
+void InputHandler::SendSynthesizeTapGestureResponse(
+ DevToolsCommandId command_id,
+ bool send_success,
+ SyntheticGesture::Result result) {
+ if (result == SyntheticGesture::Result::GESTURE_FINISHED) {
+ if (send_success) {
+ client_->SendSynthesizeTapGestureResponse(
+ command_id, SynthesizeTapGestureResponse::Create());
+ }
+ } else {
+ client_->SendError(command_id,
+ Response::InternalError(base::StringPrintf(
+ "Synthetic tap failed, result was %d", result)));
+ }
+}
+
} // 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
index 1a85b2a48c8..22a1ad70ddf 100644
--- a/chromium/content/browser/devtools/protocol/input_handler.h
+++ b/chromium/content/browser/devtools/protocol/input_handler.h
@@ -5,11 +5,22 @@
#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"
+#include "base/memory/weak_ptr.h"
+#include "content/browser/devtools/protocol/devtools_protocol_handler.h"
+#include "content/browser/renderer_host/input/synthetic_gesture.h"
+#include "ui/gfx/geometry/size_f.h"
+
+namespace cc {
+class CompositorFrameMetadata;
+}
+
+namespace gfx {
+class Point;
+}
namespace content {
-class RenderViewHostImpl;
+class RenderWidgetHostImpl;
namespace devtools {
namespace input {
@@ -21,7 +32,30 @@ class InputHandler {
InputHandler();
virtual ~InputHandler();
- void SetRenderViewHost(RenderViewHostImpl* host);
+ void SetRenderWidgetHost(RenderWidgetHostImpl* host);
+ void SetClient(scoped_ptr<Client> client);
+ void OnSwapCompositorFrame(const cc::CompositorFrameMetadata& frame_metadata);
+
+ Response DispatchKeyEvent(const std::string& type,
+ const int* modifiers,
+ const double* timestamp,
+ const std::string* text,
+ const std::string* unmodified_text,
+ const std::string* key_identifier,
+ const std::string* code,
+ const int* windows_virtual_key_code,
+ const int* native_virtual_key_code,
+ const bool* auto_repeat,
+ const bool* is_keypad,
+ const bool* is_system_key);
+
+ Response DispatchMouseEvent(const std::string& type,
+ int x,
+ int y,
+ const int* modifiers,
+ const double* timestamp,
+ const std::string* button,
+ const int* click_count);
Response EmulateTouchFromMouseEvent(const std::string& type,
int x,
@@ -33,13 +67,52 @@ class InputHandler {
int* modifiers,
int* click_count);
+ Response SynthesizePinchGesture(DevToolsCommandId command_id,
+ int x,
+ int y,
+ double scale_factor,
+ const int* relative_speed,
+ const std::string* gesture_source_type);
+
+ Response SynthesizeScrollGesture(DevToolsCommandId command_id,
+ int x,
+ int y,
+ const int* x_distance,
+ const int* y_distance,
+ const int* x_overscroll,
+ const int* y_overscroll,
+ const bool* prevent_fling,
+ const int* speed,
+ const std::string* gesture_source_type);
+
+ Response SynthesizeTapGesture(DevToolsCommandId command_id,
+ int x,
+ int y,
+ const int* duration,
+ const int* tap_count,
+ const std::string* gesture_source_type);
+
private:
- RenderViewHostImpl* host_;
+ void SendSynthesizePinchGestureResponse(DevToolsCommandId command_id,
+ SyntheticGesture::Result result);
+
+ void SendSynthesizeScrollGestureResponse(DevToolsCommandId command_id,
+ SyntheticGesture::Result result);
+
+ void SendSynthesizeTapGestureResponse(DevToolsCommandId command_id,
+ bool send_success,
+ SyntheticGesture::Result result);
+
+ RenderWidgetHostImpl* host_;
+ scoped_ptr<Client> client_;
+ float page_scale_factor_;
+ gfx::SizeF scrollable_viewport_size_;
+ base::WeakPtrFactory<InputHandler> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(InputHandler);
};
-} // namespace inpue
+} // namespace input
} // namespace devtools
} // namespace content
diff --git a/chromium/content/browser/devtools/protocol/inspector_handler.cc b/chromium/content/browser/devtools/protocol/inspector_handler.cc
index 4dbbd045449..8378e5a1e2a 100644
--- a/chromium/content/browser/devtools/protocol/inspector_handler.cc
+++ b/chromium/content/browser/devtools/protocol/inspector_handler.cc
@@ -18,6 +18,10 @@ void InspectorHandler::SetClient(scoped_ptr<Client> client) {
client_.swap(client);
}
+void InspectorHandler::TargetCrashed() {
+ client_->TargetCrashed(TargetCrashedParams::Create());
+}
+
} // 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
index d6b449e8d11..4045e2975f2 100644
--- a/chromium/content/browser/devtools/protocol/inspector_handler.h
+++ b/chromium/content/browser/devtools/protocol/inspector_handler.h
@@ -5,7 +5,7 @@
#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"
+#include "content/browser/devtools/protocol/devtools_protocol_handler.h"
namespace content {
namespace devtools {
@@ -18,6 +18,8 @@ class InspectorHandler {
void SetClient(scoped_ptr<Client> client);
+ void TargetCrashed();
+
private:
scoped_ptr<Client> client_;
diff --git a/chromium/content/browser/devtools/protocol/network_handler.cc b/chromium/content/browser/devtools/protocol/network_handler.cc
index d5b8f77a867..55e9826b962 100644
--- a/chromium/content/browser/devtools/protocol/network_handler.cc
+++ b/chromium/content/browser/devtools/protocol/network_handler.cc
@@ -4,25 +4,198 @@
#include "content/browser/devtools/protocol/network_handler.h"
+#include "base/containers/hash_tables.h"
+#include "base/strings/stringprintf.h"
+#include "content/browser/frame_host/frame_tree_node.h"
+#include "content/browser/frame_host/render_frame_host_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/browser/resource_context.h"
+#include "content/public/browser/site_instance.h"
#include "content/public/common/content_client.h"
+#include "net/cookies/cookie_store.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_context_getter.h"
namespace content {
namespace devtools {
namespace network {
+using CookieListCallback = net::CookieStore::GetCookieListCallback;
+
+namespace {
+
+net::URLRequestContext* GetRequestContextOnIO(
+ ResourceContext* resource_context,
+ net::URLRequestContextGetter* context_getter,
+ const GURL& url) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ net::URLRequestContext* context =
+ GetContentClient()->browser()->OverrideRequestContextForURL(
+ url, resource_context);
+ if (!context)
+ context = context_getter->GetURLRequestContext();
+ return context;
+}
+
+void GotCookiesForURLOnIO(
+ const CookieListCallback& callback,
+ const net::CookieList& cookie_list) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(callback, cookie_list));
+}
+
+void GetCookiesForURLOnIO(
+ ResourceContext* resource_context,
+ net::URLRequestContextGetter* context_getter,
+ const GURL& url,
+ const CookieListCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ net::URLRequestContext* request_context =
+ GetRequestContextOnIO(resource_context, context_getter, url);
+ request_context->cookie_store()->GetAllCookiesForURLAsync(
+ url, base::Bind(&GotCookiesForURLOnIO, callback));
+}
+
+void GetCookiesForURLOnUI(
+ ResourceContext* resource_context,
+ net::URLRequestContextGetter* context_getter,
+ const GURL& url,
+ const CookieListCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&GetCookiesForURLOnIO,
+ base::Unretained(resource_context),
+ base::Unretained(context_getter),
+ url,
+ callback));
+}
+
+void DeletedCookieOnIO(const base::Closure& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ callback);
+}
+
+void DeleteCookieOnIO(
+ ResourceContext* resource_context,
+ net::URLRequestContextGetter* context_getter,
+ const GURL& url,
+ const std::string& cookie_name,
+ const base::Closure& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ net::URLRequestContext* request_context =
+ GetRequestContextOnIO(resource_context, context_getter, url);
+ request_context->cookie_store()->DeleteCookieAsync(
+ url, cookie_name, base::Bind(&DeletedCookieOnIO, callback));
+}
+
+void DeleteCookieOnUI(
+ ResourceContext* resource_context,
+ net::URLRequestContextGetter* context_getter,
+ const GURL& url,
+ const std::string& cookie_name,
+ const base::Closure& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&DeleteCookieOnIO,
+ base::Unretained(resource_context),
+ base::Unretained(context_getter),
+ url,
+ cookie_name,
+ callback));
+}
+
+class GetCookiesCommand {
+ public:
+ explicit GetCookiesCommand(
+ RenderFrameHostImpl* frame_host,
+ const CookieListCallback& callback)
+ : callback_(callback),
+ request_count_(0) {
+ CookieListCallback got_cookies_callback = base::Bind(
+ &GetCookiesCommand::GotCookiesForURL, base::Unretained(this));
+ BrowserContext* browser_context =
+ frame_host->GetSiteInstance()->GetBrowserContext();
+
+ std::queue<FrameTreeNode*> queue;
+ queue.push(frame_host->frame_tree_node());
+ while (!queue.empty()) {
+ FrameTreeNode* node = queue.front();
+ queue.pop();
+
+ // Only traverse nodes with the same local root.
+ if (node->current_frame_host()->IsCrossProcessSubframe())
+ continue;
+ int process_id = node->current_frame_host()->GetProcess()->GetID();
+ ++request_count_;
+ GetCookiesForURLOnUI(
+ browser_context->GetResourceContext(),
+ browser_context->GetRequestContextForRenderProcess(process_id),
+ node->current_url(),
+ got_cookies_callback);
+
+ for (size_t i = 0; i < node->child_count(); ++i)
+ queue.push(node->child_at(i));
+ }
+ }
+
+ private:
+ void GotCookiesForURL(const net::CookieList& cookie_list) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ for (const net::CanonicalCookie& cookie : cookie_list) {
+ std::string key = base::StringPrintf(
+ "%s::%s::%s::%d",
+ cookie.Name().c_str(),
+ cookie.Domain().c_str(),
+ cookie.Path().c_str(),
+ cookie.IsSecure());
+ cookies_[key] = cookie;
+ }
+ --request_count_;
+ if (!request_count_) {
+ net::CookieList list;
+ list.reserve(cookies_.size());
+ for (const auto& pair : cookies_)
+ list.push_back(pair.second);
+ callback_.Run(list);
+ delete this;
+ }
+ }
+
+ CookieListCallback callback_;
+ int request_count_;
+ base::hash_map<std::string, net::CanonicalCookie> cookies_;
+};
+
+} // namespace
+
typedef DevToolsProtocolClient::Response Response;
-NetworkHandler::NetworkHandler() : host_(nullptr) {
+NetworkHandler::NetworkHandler() : host_(nullptr), weak_factory_(this) {
}
NetworkHandler::~NetworkHandler() {
}
-void NetworkHandler::SetRenderViewHost(RenderViewHost* host) {
+void NetworkHandler::SetRenderFrameHost(RenderFrameHostImpl* host) {
host_ = host;
}
+void NetworkHandler::SetClient(scoped_ptr<Client> client) {
+ client_.swap(client);
+}
+
Response NetworkHandler::ClearBrowserCache() {
if (host_)
GetContentClient()->browser()->ClearCache(host_);
@@ -35,6 +208,64 @@ Response NetworkHandler::ClearBrowserCookies() {
return Response::OK();
}
+Response NetworkHandler::GetCookies(DevToolsCommandId command_id) {
+ if (!host_)
+ return Response::InternalError("Could not connect to view");
+ new GetCookiesCommand(
+ host_,
+ base::Bind(&NetworkHandler::SendGetCookiesResponse,
+ weak_factory_.GetWeakPtr(),
+ command_id));
+ return Response::OK();
+}
+
+void NetworkHandler::SendGetCookiesResponse(
+ DevToolsCommandId command_id,
+ const net::CookieList& cookie_list) {
+ std::vector<scoped_refptr<Cookie>> cookies;
+ for (size_t i = 0; i < cookie_list.size(); ++i) {
+ const net::CanonicalCookie& cookie = cookie_list[i];
+ cookies.push_back(Cookie::Create()
+ ->set_name(cookie.Name())
+ ->set_value(cookie.Value())
+ ->set_domain(cookie.Domain())
+ ->set_path(cookie.Path())
+ ->set_expires(cookie.ExpiryDate().ToDoubleT() * 1000)
+ ->set_size(cookie.Name().length() + cookie.Value().length())
+ ->set_http_only(cookie.IsHttpOnly())
+ ->set_secure(cookie.IsSecure())
+ ->set_session(!cookie.IsPersistent()));
+ }
+ client_->SendGetCookiesResponse(command_id,
+ GetCookiesResponse::Create()->set_cookies(cookies));
+}
+
+Response NetworkHandler::DeleteCookie(
+ DevToolsCommandId command_id,
+ const std::string& cookie_name,
+ const std::string& url) {
+ if (!host_)
+ return Response::InternalError("Could not connect to view");
+ BrowserContext* browser_context =
+ host_->GetSiteInstance()->GetBrowserContext();
+ int process_id = host_->GetProcess()->GetID();
+ DeleteCookieOnUI(
+ browser_context->GetResourceContext(),
+ browser_context->GetRequestContextForRenderProcess(process_id),
+ GURL(url),
+ cookie_name,
+ base::Bind(&NetworkHandler::SendDeleteCookieResponse,
+ weak_factory_.GetWeakPtr(),
+ command_id));
+ return Response::OK();
+}
+
+void NetworkHandler::SendDeleteCookieResponse(DevToolsCommandId command_id) {
+ client_->SendDeleteCookieResponse(command_id,
+ DeleteCookieResponse::Create());
+}
+
+
Response NetworkHandler::CanEmulateNetworkConditions(bool* result) {
*result = false;
return Response::OK();
diff --git a/chromium/content/browser/devtools/protocol/network_handler.h b/chromium/content/browser/devtools/protocol/network_handler.h
index c045a86f2de..b54a0cb46b3 100644
--- a/chromium/content/browser/devtools/protocol/network_handler.h
+++ b/chromium/content/browser/devtools/protocol/network_handler.h
@@ -5,11 +5,13 @@
#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"
+#include "base/memory/weak_ptr.h"
+#include "content/browser/devtools/protocol/devtools_protocol_handler.h"
+#include "net/cookies/canonical_cookie.h"
namespace content {
-class RenderViewHost;
+class RenderFrameHostImpl;
namespace devtools {
namespace network {
@@ -21,19 +23,31 @@ class NetworkHandler {
NetworkHandler();
virtual ~NetworkHandler();
- void SetRenderViewHost(RenderViewHost* host);
+ void SetRenderFrameHost(RenderFrameHostImpl* host);
+ void SetClient(scoped_ptr<Client> client);
Response ClearBrowserCache();
Response ClearBrowserCookies();
- Response CanEmulateNetworkConditions(bool* result);
+ Response GetCookies(DevToolsCommandId command_id);
+ Response DeleteCookie(DevToolsCommandId command_id,
+ const std::string& cookie_name,
+ const std::string& url);
+ Response CanEmulateNetworkConditions(bool* result);
Response EmulateNetworkConditions(bool offline,
double latency,
double download_throughput,
double upload_throughput);
private:
- RenderViewHost* host_;
+ void SendGetCookiesResponse(
+ DevToolsCommandId command_id,
+ const net::CookieList& cookie_list);
+ void SendDeleteCookieResponse(DevToolsCommandId command_id);
+
+ RenderFrameHostImpl* host_;
+ scoped_ptr<Client> client_;
+ base::WeakPtrFactory<NetworkHandler> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(NetworkHandler);
};
diff --git a/chromium/content/browser/devtools/protocol/page_handler.cc b/chromium/content/browser/devtools/protocol/page_handler.cc
index b336d8cb6c8..cc69f7d2a29 100644
--- a/chromium/content/browser/devtools/protocol/page_handler.cc
+++ b/chromium/content/browser/devtools/protocol/page_handler.cc
@@ -10,10 +10,9 @@
#include "base/bind.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/threading/worker_pool.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_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"
@@ -21,17 +20,17 @@
#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/notification_service.h"
+#include "content/public/browser/notification_types.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/gfx/geometry/size_conversions.h"
#include "ui/snapshot/snapshot.h"
#include "url/gurl.h"
@@ -44,25 +43,44 @@ namespace {
static const char kPng[] = "png";
static const char kJpeg[] = "jpeg";
static int kDefaultScreenshotQuality = 80;
-static int kFrameRateThresholdMs = 100;
+static int kFrameRetryDelayMs = 100;
static int kCaptureRetryLimit = 2;
+static int kMaxScreencastFramesInFlight = 2;
-void QueryUsageAndQuotaCompletedOnIOThread(
- const UsageAndQuotaQuery::Callback& callback,
- scoped_ptr<QueryUsageAndQuotaResponse> response) {
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(callback, base::Passed(&response)));
-}
+std::string EncodeScreencastFrame(const SkBitmap& bitmap,
+ const std::string& format,
+ int quality) {
+ 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();
+
+ std::string base_64_data;
+ base::Base64Encode(
+ base::StringPiece(reinterpret_cast<char*>(&data[0]), data.size()),
+ &base_64_data);
-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));
+ return base_64_data;
}
} // namespace
@@ -71,29 +89,48 @@ 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),
+ has_compositor_frame_metadata_(false),
+ screencast_frame_sent_(0),
+ screencast_frame_acked_(0),
+ processing_screencast_frame_(false),
color_picker_(new ColorPicker(base::Bind(
&PageHandler::OnColorPicked, base::Unretained(this)))),
host_(nullptr),
+ screencast_listener_(nullptr),
weak_factory_(this) {
}
PageHandler::~PageHandler() {
}
-void PageHandler::SetRenderViewHost(RenderViewHostImpl* host) {
+void PageHandler::SetRenderFrameHost(RenderFrameHostImpl* host) {
if (host_ == host)
return;
- color_picker_->SetRenderViewHost(host);
+ RenderWidgetHostImpl* widget_host =
+ host_ ? host_->GetRenderWidgetHost() : nullptr;
+ if (widget_host) {
+ registrar_.Remove(
+ this,
+ content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
+ content::Source<RenderWidgetHost>(widget_host));
+ }
+
host_ = host;
- UpdateTouchEventEmulationState();
+ widget_host = host_ ? host_->GetRenderWidgetHost() : nullptr;
+ color_picker_->SetRenderWidgetHost(widget_host);
+
+ if (widget_host) {
+ registrar_.Add(
+ this,
+ content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
+ content::Source<RenderWidgetHost>(widget_host));
+ }
}
void PageHandler::SetClient(scoped_ptr<Client> client) {
@@ -106,32 +143,40 @@ void PageHandler::Detached() {
void PageHandler::OnSwapCompositorFrame(
const cc::CompositorFrameMetadata& frame_metadata) {
- last_compositor_frame_metadata_ = frame_metadata;
- has_last_compositor_frame_metadata_ = true;
+ last_compositor_frame_metadata_ = has_compositor_frame_metadata_ ?
+ next_compositor_frame_metadata_ : frame_metadata;
+ next_compositor_frame_metadata_ = frame_metadata;
+ has_compositor_frame_metadata_ = true;
if (screencast_enabled_)
InnerSwapCompositorFrame();
color_picker_->OnSwapCompositorFrame();
}
-void PageHandler::OnVisibilityChanged(bool visible) {
+void PageHandler::Observe(int type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
if (!screencast_enabled_)
return;
+ DCHECK(type == content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED);
+ bool visible = *Details<bool>(details).ptr();
NotifyScreencastVisibility(visible);
}
void PageHandler::DidAttachInterstitialPage() {
if (!enabled_)
return;
- InterstitialShownParams params;
- client_->InterstitialShown(params);
+ client_->InterstitialShown(InterstitialShownParams::Create());
}
void PageHandler::DidDetachInterstitialPage() {
if (!enabled_)
return;
- InterstitialHiddenParams params;
- client_->InterstitialHidden(params);
+ client_->InterstitialHidden(InterstitialHiddenParams::Create());
+}
+
+void PageHandler::SetScreencastListener(ScreencastListener* listener) {
+ screencast_listener_ = listener;
}
Response PageHandler::Enable() {
@@ -141,22 +186,19 @@ Response PageHandler::Enable() {
Response PageHandler::Disable() {
enabled_ = false;
- touch_emulation_enabled_ = false;
screencast_enabled_ = false;
- UpdateTouchEventEmulationState();
color_picker_->SetEnabled(false);
+ if (screencast_listener_)
+ screencast_listener_->ScreencastEnabledChanged();
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_);
+ WebContentsImpl* web_contents = GetWebContents();
if (!web_contents)
- return Response::InternalError("No WebContents to reload");
+ return Response::InternalError("Could not connect to view");
// Handle in browser only if it is crashed.
if (!web_contents->IsCrashed())
@@ -172,48 +214,37 @@ Response PageHandler::Navigate(const std::string& 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_);
+ WebContentsImpl* web_contents = GetWebContents();
if (!web_contents)
- return Response::InternalError("No WebContents to navigate");
+ return Response::InternalError("Could not connect to view");
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_);
+Response PageHandler::GetNavigationHistory(int* current_index,
+ NavigationEntries* entries) {
+ WebContentsImpl* web_contents = GetWebContents();
if (!web_contents)
- return Response::InternalError("No WebContents to navigate");
+ return Response::InternalError("Could not connect to view");
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);
+ entries->push_back(NavigationEntry::Create()
+ ->set_id(controller.GetEntryAtIndex(i)->GetUniqueID())
+ ->set_url(controller.GetEntryAtIndex(i)->GetURL().spec())
+ ->set_title(
+ base::UTF16ToUTF8(controller.GetEntryAtIndex(i)->GetTitle())));
}
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_);
+ WebContentsImpl* web_contents = GetWebContents();
if (!web_contents)
- return Response::InternalError("No WebContents to navigate");
+ return Response::InternalError("Could not connect to view");
NavigationController& controller = web_contents->GetController();
for (int i = 0; i != controller.GetEntryCount(); ++i) {
@@ -226,74 +257,14 @@ Response PageHandler::NavigateToHistoryEntry(int entry_id) {
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_)
+Response PageHandler::CaptureScreenshot(DevToolsCommandId command_id) {
+ if (!host_ || !host_->GetRenderWidgetHost())
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(
+ host_->GetRenderWidgetHost()->GetSnapshotFromBrowser(
base::Bind(&PageHandler::ScreenshotCaptured,
- weak_factory_.GetWeakPtr(), command));
- return command->AsyncResponsePromise();
+ weak_factory_.GetWeakPtr(), command_id));
+ return Response::OK();
}
Response PageHandler::CanScreencast(bool* result) {
@@ -305,28 +276,13 @@ Response PageHandler::CanScreencast(bool* result) {
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_)
+ RenderWidgetHostImpl* widget_host =
+ host_ ? host_->GetRenderWidgetHost() : nullptr;
+ if (!widget_host)
return Response::InternalError("Could not connect to view");
screencast_enabled_ = true;
@@ -337,40 +293,45 @@ Response PageHandler::StartScreencast(const std::string* format,
screencast_max_width_ = max_width ? *max_width : -1;
screencast_max_height_ = max_height ? *max_height : -1;
- UpdateTouchEventEmulationState();
- bool visible = !host_->is_hidden();
+ bool visible = !widget_host->is_hidden();
NotifyScreencastVisibility(visible);
if (visible) {
- if (has_last_compositor_frame_metadata_)
+ if (has_compositor_frame_metadata_) {
InnerSwapCompositorFrame();
- else
- host_->Send(new ViewMsg_ForceRedraw(host_->GetRoutingID(), 0));
+ } else {
+ widget_host->Send(
+ new ViewMsg_ForceRedraw(widget_host->GetRoutingID(), 0));
+ }
}
+ if (screencast_listener_)
+ screencast_listener_->ScreencastEnabledChanged();
return Response::FallThrough();
}
Response PageHandler::StopScreencast() {
- last_frame_time_ = base::TimeTicks();
screencast_enabled_ = false;
- UpdateTouchEventEmulationState();
+ if (screencast_listener_)
+ screencast_listener_->ScreencastEnabledChanged();
return Response::FallThrough();
}
+Response PageHandler::ScreencastFrameAck(int frame_number) {
+ screencast_frame_acked_ = frame_number;
+ return Response::OK();
+}
+
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_);
+ WebContentsImpl* web_contents = GetWebContents();
if (!web_contents)
- return Response::InternalError("No JavaScript dialog to handle");
+ return Response::InternalError("Could not connect to view");
JavaScriptDialogManager* manager =
- web_contents->GetDelegate()->GetJavaScriptDialogManager();
+ web_contents->GetDelegate()->GetJavaScriptDialogManager(web_contents);
if (manager && manager->HandleJavaScriptDialog(
web_contents, accept, prompt_text ? &prompt_override : nullptr)) {
return Response::OK();
@@ -379,26 +340,9 @@ Response PageHandler::HandleJavaScriptDialog(bool accept,
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::QueryUsageAndQuota(DevToolsCommandId command_id,
+ const std::string& security_origin) {
+ return Response::OK();
}
Response PageHandler::SetColorPickerEnabled(bool enabled) {
@@ -409,37 +353,28 @@ Response PageHandler::SetColorPickerEnabled(bool 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);
+WebContentsImpl* PageHandler::GetWebContents() {
+ return host_ ?
+ static_cast<WebContentsImpl*>(WebContents::FromRenderFrameHost(host_)) :
+ nullptr;
}
void PageHandler::NotifyScreencastVisibility(bool visible) {
if (visible)
capture_retry_count_ = kCaptureRetryLimit;
- ScreencastVisibilityChangedParams params;
- params.set_visible(visible);
- client_->ScreencastVisibilityChanged(params);
+ client_->ScreencastVisibilityChanged(
+ ScreencastVisibilityChangedParams::Create()->set_visible(visible));
}
void PageHandler::InnerSwapCompositorFrame() {
- if ((base::TimeTicks::Now() - last_frame_time_).InMilliseconds() <
- kFrameRateThresholdMs) {
+ if (screencast_frame_sent_ - screencast_frame_acked_ >
+ kMaxScreencastFramesInFlight || processing_screencast_frame_) {
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.
@@ -471,115 +406,81 @@ void PageHandler::InnerSwapCompositorFrame() {
gfx::ScaleSize(viewport_size_dip, scale)));
if (snapshot_size_dip.width() > 0 && snapshot_size_dip.height() > 0) {
+ processing_screencast_frame_ = true;
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) {
+ const SkBitmap& bitmap,
+ ReadbackResponse response) {
+ if (response != READBACK_SUCCESS) {
+ processing_screencast_frame_ = false;
if (capture_retry_count_) {
--capture_retry_count_;
base::MessageLoop::current()->PostDelayedTask(
FROM_HERE,
base::Bind(&PageHandler::InnerSwapCompositorFrame,
weak_factory_.GetWeakPtr()),
- base::TimeDelta::FromMilliseconds(kFrameRateThresholdMs));
+ base::TimeDelta::FromMilliseconds(kFrameRetryDelayMs));
}
return;
}
+ base::PostTaskAndReplyWithResult(
+ base::WorkerPool::GetTaskRunner(true).get(),
+ FROM_HERE,
+ base::Bind(&EncodeScreencastFrame,
+ bitmap, screencast_format_, screencast_quality_),
+ base::Bind(&PageHandler::ScreencastFrameEncoded,
+ weak_factory_.GetWeakPtr(), metadata, base::Time::Now()));
+}
- 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);
+void PageHandler::ScreencastFrameEncoded(
+ const cc::CompositorFrameMetadata& metadata,
+ const base::Time& timestamp,
+ const std::string& data) {
+ processing_screencast_frame_ = false;
- 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);
- }
+ if (metadata.device_scale_factor == 0 || !host_ || data.empty())
+ return;
- ScreencastFrameParams params;
- params.set_data(base_64_data);
- params.set_metadata(param_metadata);
- client_->ScreencastFrame(params);
-}
+ RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
+ host_->GetView());
+ if (!view)
+ return;
-void PageHandler::ScreenshotCaptured(
- scoped_refptr<DevToolsProtocol::Command> command,
- const unsigned char* png_data,
- size_t png_size) {
+ gfx::SizeF screen_size_dip = gfx::ScaleSize(
+ view->GetPhysicalBackingSize(), 1 / metadata.device_scale_factor);
+ scoped_refptr<ScreencastFrameMetadata> param_metadata =
+ ScreencastFrameMetadata::Create()
+ ->set_page_scale_factor(metadata.page_scale_factor)
+ ->set_offset_top(metadata.location_bar_content_translation.y())
+ ->set_device_width(screen_size_dip.width())
+ ->set_device_height(screen_size_dip.height())
+ ->set_scroll_offset_x(metadata.root_scroll_offset.x())
+ ->set_scroll_offset_y(metadata.root_scroll_offset.y())
+ ->set_timestamp(timestamp.ToDoubleT());
+ client_->ScreencastFrame(ScreencastFrameParams::Create()
+ ->set_data(data)
+ ->set_metadata(param_metadata)
+ ->set_frame_number(++screencast_frame_sent_));
+}
+
+void PageHandler::ScreenshotCaptured(DevToolsCommandId command_id,
+ const unsigned char* png_data,
+ size_t png_size) {
if (!png_data || !png_size) {
- client_->SendInternalErrorResponse(command,
- "Unable to capture screenshot");
+ client_->SendError(command_id,
+ Response::InternalError("Unable to capture screenshot"));
return;
}
@@ -588,26 +489,14 @@ void PageHandler::ScreenshotCaptured(
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);
+ client_->SendCaptureScreenshotResponse(command_id,
+ CaptureScreenshotResponse::Create()->set_data(base_64_data));
}
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);
+ scoped_refptr<dom::RGBA> color =
+ dom::RGBA::Create()->set_r(r)->set_g(g)->set_b(b)->set_a(a);
+ client_->ColorPicked(ColorPickedParams::Create()->set_color(color));
}
} // namespace page
diff --git a/chromium/content/browser/devtools/protocol/page_handler.h b/chromium/content/browser/devtools/protocol/page_handler.h
index 913655d7b06..fff0cda58ec 100644
--- a/chromium/content/browser/devtools/protocol/page_handler.h
+++ b/chromium/content/browser/devtools/protocol/page_handler.h
@@ -10,104 +10,101 @@
#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"
+#include "content/browser/devtools/protocol/devtools_protocol_handler.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/readback_types.h"
class SkBitmap;
namespace content {
-class RenderViewHostImpl;
+class RenderFrameHostImpl;
+class WebContentsImpl;
namespace devtools {
namespace page {
class ColorPicker;
-class PageHandler {
+class PageHandler : public NotificationObserver {
public:
typedef DevToolsProtocolClient::Response Response;
+ class ScreencastListener {
+ public:
+ virtual ~ScreencastListener() { }
+ virtual void ScreencastEnabledChanged() = 0;
+ };
+
PageHandler();
- virtual ~PageHandler();
+ ~PageHandler() override;
- void SetRenderViewHost(RenderViewHostImpl* host);
+ void SetRenderFrameHost(RenderFrameHostImpl* host);
void SetClient(scoped_ptr<Client> client);
void Detached();
void OnSwapCompositorFrame(const cc::CompositorFrameMetadata& frame_metadata);
- void OnVisibilityChanged(bool visible);
void DidAttachInterstitialPage();
void DidDetachInterstitialPage();
+ void SetScreencastListener(ScreencastListener* listener);
+ bool screencast_enabled() const { return enabled_ && screencast_enabled_; }
Response Enable();
Response Disable();
Response Reload(const bool* ignoreCache,
const std::string* script_to_evaluate_on_load,
- const std::string* script_preprocessor);
+ const std::string* script_preprocessor = NULL);
Response Navigate(const std::string& url, FrameId* frame_id);
+ using NavigationEntries = std::vector<scoped_refptr<NavigationEntry>>;
Response GetNavigationHistory(int* current_index,
- std::vector<NavigationEntry>* entries);
+ NavigationEntries* 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 CaptureScreenshot(DevToolsCommandId command_id);
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 ScreencastFrameAck(int frame_number);
+
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 QueryUsageAndQuota(DevToolsCommandId command_id,
+ const std::string& security_origin);
Response SetColorPickerEnabled(bool enabled);
private:
- void UpdateTouchEventEmulationState();
-
+ WebContentsImpl* GetWebContents();
void NotifyScreencastVisibility(bool visible);
void InnerSwapCompositorFrame();
- void ScreencastFrameCaptured(
- const std::string& format,
- int quality,
- const cc::CompositorFrameMetadata& metadata,
- bool success,
- const SkBitmap& bitmap);
+ void ScreencastFrameCaptured(const cc::CompositorFrameMetadata& metadata,
+ const SkBitmap& bitmap,
+ ReadbackResponse response);
+ void ScreencastFrameEncoded(const cc::CompositorFrameMetadata& metadata,
+ const base::Time& timestamp,
+ const std::string& data);
void ScreenshotCaptured(
- scoped_refptr<DevToolsProtocol::Command> command,
+ DevToolsCommandId command_id,
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);
+ // NotificationObserver overrides.
+ void Observe(int type,
+ const NotificationSource& source,
+ const NotificationDetails& details) override;
bool enabled_;
- bool touch_emulation_enabled_;
- std::string touch_emulation_configuration_;
bool screencast_enabled_;
std::string screencast_format_;
@@ -115,14 +112,19 @@ class PageHandler {
int screencast_max_width_;
int screencast_max_height_;
int capture_retry_count_;
- bool has_last_compositor_frame_metadata_;
+ bool has_compositor_frame_metadata_;
+ cc::CompositorFrameMetadata next_compositor_frame_metadata_;
cc::CompositorFrameMetadata last_compositor_frame_metadata_;
- base::TimeTicks last_frame_time_;
+ int screencast_frame_sent_;
+ int screencast_frame_acked_;
+ bool processing_screencast_frame_;
scoped_ptr<ColorPicker> color_picker_;
- RenderViewHostImpl* host_;
+ RenderFrameHostImpl* host_;
scoped_ptr<Client> client_;
+ ScreencastListener* screencast_listener_;
+ NotificationRegistrar registrar_;
base::WeakPtrFactory<PageHandler> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(PageHandler);
diff --git a/chromium/content/browser/devtools/protocol/power_handler.cc b/chromium/content/browser/devtools/protocol/power_handler.cc
index c121ac3cf2d..c88097b86d7 100644
--- a/chromium/content/browser/devtools/protocol/power_handler.cc
+++ b/chromium/content/browser/devtools/protocol/power_handler.cc
@@ -25,21 +25,19 @@ void PowerHandler::SetClient(scoped_ptr<Client> client) {
}
void PowerHandler::OnPowerEvent(const PowerEventVector& events) {
- std::vector<PowerEvent> event_list;
+ std::vector<scoped_refptr<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);
+ double timestamp = event.time.ToInternalValue() /
+ static_cast<double>(base::Time::kMicrosecondsPerMillisecond);
+ event_list.push_back(PowerEvent::Create()
+ ->set_type(kPowerTypeNames[event.type])
+ ->set_timestamp(timestamp)
+ ->set_value(event.value));
}
- DataAvailableParams params;
- params.set_value(event_list);
- client_->DataAvailable(params);
+ client_->DataAvailable(DataAvailableParams::Create()->set_value(event_list));
}
void PowerHandler::Detached() {
diff --git a/chromium/content/browser/devtools/protocol/power_handler.h b/chromium/content/browser/devtools/protocol/power_handler.h
index f0892c70c3f..cd7e8da9302 100644
--- a/chromium/content/browser/devtools/protocol/power_handler.h
+++ b/chromium/content/browser/devtools/protocol/power_handler.h
@@ -5,7 +5,7 @@
#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/devtools/protocol/devtools_protocol_handler.h"
#include "content/browser/power_profiler/power_profiler_observer.h"
namespace content {
diff --git a/chromium/content/browser/devtools/protocol/service_worker_handler.cc b/chromium/content/browser/devtools/protocol/service_worker_handler.cc
new file mode 100644
index 00000000000..907d8a5f343
--- /dev/null
+++ b/chromium/content/browser/devtools/protocol/service_worker_handler.cc
@@ -0,0 +1,526 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/devtools/protocol/service_worker_handler.h"
+
+#include "base/bind.h"
+#include "base/containers/scoped_ptr_hash_map.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/browser/devtools/service_worker_devtools_agent_host.h"
+#include "content/browser/devtools/service_worker_devtools_manager.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/service_worker/service_worker_context_watcher.h"
+#include "content/browser/service_worker/service_worker_context_wrapper.h"
+#include "content/browser/service_worker/service_worker_version.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/devtools_agent_host.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/storage_partition.h"
+#include "content/public/common/push_messaging_status.h"
+#include "url/gurl.h"
+
+// Windows headers will redefine SendMessage.
+#ifdef SendMessage
+#undef SendMessage
+#endif
+
+namespace content {
+namespace devtools {
+namespace service_worker {
+
+using Response = DevToolsProtocolClient::Response;
+
+namespace {
+
+void ResultNoOp(bool success) {
+}
+void StatusNoOp(ServiceWorkerStatusCode status) {
+}
+void PushDeliveryNoOp(PushDeliveryStatus status) {
+}
+
+const std::string GetVersionRunningStatusString(
+ content::ServiceWorkerVersion::RunningStatus running_status) {
+ switch (running_status) {
+ case content::ServiceWorkerVersion::STOPPED:
+ return kServiceWorkerVersionRunningStatusStopped;
+ case content::ServiceWorkerVersion::STARTING:
+ return kServiceWorkerVersionRunningStatusStarting;
+ case content::ServiceWorkerVersion::RUNNING:
+ return kServiceWorkerVersionRunningStatusRunning;
+ case content::ServiceWorkerVersion::STOPPING:
+ return kServiceWorkerVersionRunningStatusStopping;
+ }
+ return "";
+}
+
+const std::string GetVersionStatusString(
+ content::ServiceWorkerVersion::Status status) {
+ switch (status) {
+ case content::ServiceWorkerVersion::NEW:
+ return kServiceWorkerVersionStatusNew;
+ case content::ServiceWorkerVersion::INSTALLING:
+ return kServiceWorkerVersionStatusInstalling;
+ case content::ServiceWorkerVersion::INSTALLED:
+ return kServiceWorkerVersionStatusInstalled;
+ case content::ServiceWorkerVersion::ACTIVATING:
+ return kServiceWorkerVersionStatusActivating;
+ case content::ServiceWorkerVersion::ACTIVATED:
+ return kServiceWorkerVersionStatusActivated;
+ case content::ServiceWorkerVersion::REDUNDANT:
+ return kServiceWorkerVersionStatusRedundant;
+ }
+ return "";
+}
+
+scoped_refptr<ServiceWorkerVersion> CreateVersionDictionaryValue(
+ const ServiceWorkerVersionInfo& version_info) {
+ scoped_refptr<ServiceWorkerVersion> version(
+ ServiceWorkerVersion::Create()
+ ->set_version_id(base::Int64ToString(version_info.version_id))
+ ->set_registration_id(
+ base::Int64ToString(version_info.registration_id))
+ ->set_script_url(version_info.script_url.spec())
+ ->set_running_status(
+ GetVersionRunningStatusString(version_info.running_status))
+ ->set_status(GetVersionStatusString(version_info.status))
+ ->set_script_last_modified(
+ version_info.script_last_modified.ToDoubleT())
+ ->set_script_response_time(
+ version_info.script_response_time.ToDoubleT()));
+ return version;
+}
+
+scoped_refptr<ServiceWorkerRegistration> CreateRegistrationDictionaryValue(
+ const ServiceWorkerRegistrationInfo& registration_info) {
+ scoped_refptr<ServiceWorkerRegistration> registration(
+ ServiceWorkerRegistration::Create()
+ ->set_registration_id(
+ base::Int64ToString(registration_info.registration_id))
+ ->set_scope_url(registration_info.pattern.spec())
+ ->set_is_deleted(registration_info.delete_flag ==
+ ServiceWorkerRegistrationInfo::IS_DELETED));
+ return registration;
+}
+
+scoped_refptr<ServiceWorkerDevToolsAgentHost> GetMatchingServiceWorker(
+ const ServiceWorkerDevToolsAgentHost::List& agent_hosts,
+ const GURL& url) {
+ scoped_refptr<ServiceWorkerDevToolsAgentHost> best_host;
+ std::string best_scope;
+ for (auto host : agent_hosts) {
+ if (host->GetURL().host() != url.host())
+ continue;
+ std::string path = host->GetURL().path();
+ std::string file = host->GetURL().ExtractFileName();
+ std::string scope = path.substr(0, path.length() - file.length());
+ if (scope.length() > best_scope.length()) {
+ best_host = host;
+ best_scope = scope;
+ }
+ }
+ return best_host;
+}
+
+ServiceWorkerDevToolsAgentHost::Map GetMatchingServiceWorkers(
+ BrowserContext* browser_context,
+ const std::set<GURL>& urls) {
+ ServiceWorkerDevToolsAgentHost::Map result;
+ if (!browser_context)
+ return result;
+ ServiceWorkerDevToolsAgentHost::List agent_hosts;
+ ServiceWorkerDevToolsManager::GetInstance()
+ ->AddAllAgentHostsForBrowserContext(browser_context, &agent_hosts);
+ for (const GURL& url : urls) {
+ scoped_refptr<ServiceWorkerDevToolsAgentHost> host =
+ GetMatchingServiceWorker(agent_hosts, url);
+ if (host)
+ result[host->GetId()] = host;
+ }
+ return result;
+}
+
+bool CollectURLs(std::set<GURL>* urls, FrameTreeNode* tree_node) {
+ urls->insert(tree_node->current_url());
+ return false;
+}
+
+void StopServiceWorkerOnIO(scoped_refptr<ServiceWorkerContextWrapper> context,
+ int64 version_id) {
+ if (content::ServiceWorkerVersion* version =
+ context->GetLiveVersion(version_id)) {
+ version->StopWorker(base::Bind(&StatusNoOp));
+ }
+}
+
+void GetDevToolsRouteInfoOnIO(
+ scoped_refptr<ServiceWorkerContextWrapper> context,
+ int64 version_id,
+ const base::Callback<void(int, int)>& callback) {
+ if (content::ServiceWorkerVersion* version =
+ context->GetLiveVersion(version_id)) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(
+ callback, version->embedded_worker()->process_id(),
+ version->embedded_worker()->worker_devtools_agent_route_id()));
+ }
+}
+
+Response CreateContextErrorResponse() {
+ return Response::InternalError("Could not connect to the context");
+}
+
+Response CreateInvalidVersionIdErrorResponse() {
+ return Response::InternalError("Invalid version ID");
+}
+
+} // namespace
+
+ServiceWorkerHandler::ServiceWorkerHandler()
+ : enabled_(false), weak_factory_(this) {
+}
+
+ServiceWorkerHandler::~ServiceWorkerHandler() {
+ Disable();
+}
+
+void ServiceWorkerHandler::SetRenderFrameHost(
+ RenderFrameHostImpl* render_frame_host) {
+ render_frame_host_ = render_frame_host;
+ // Do not call UpdateHosts yet, wait for load to commit.
+ if (!render_frame_host) {
+ context_ = nullptr;
+ return;
+ }
+ StoragePartition* partition = BrowserContext::GetStoragePartition(
+ render_frame_host->GetProcess()->GetBrowserContext(),
+ render_frame_host->GetSiteInstance());
+ DCHECK(partition);
+ context_ = static_cast<ServiceWorkerContextWrapper*>(
+ partition->GetServiceWorkerContext());
+}
+
+void ServiceWorkerHandler::SetClient(scoped_ptr<Client> client) {
+ client_.swap(client);
+}
+
+void ServiceWorkerHandler::UpdateHosts() {
+ if (!enabled_)
+ return;
+
+ urls_.clear();
+ BrowserContext* browser_context = nullptr;
+ if (render_frame_host_) {
+ render_frame_host_->frame_tree_node()->frame_tree()->ForEach(
+ base::Bind(&CollectURLs, &urls_));
+ browser_context = render_frame_host_->GetProcess()->GetBrowserContext();
+ }
+
+ ServiceWorkerDevToolsAgentHost::Map old_hosts = attached_hosts_;
+ ServiceWorkerDevToolsAgentHost::Map new_hosts =
+ GetMatchingServiceWorkers(browser_context, urls_);
+
+ for (auto pair : old_hosts) {
+ if (new_hosts.find(pair.first) == new_hosts.end())
+ ReportWorkerTerminated(pair.second.get());
+ }
+
+ for (auto pair : new_hosts) {
+ if (old_hosts.find(pair.first) == old_hosts.end())
+ ReportWorkerCreated(pair.second.get());
+ }
+}
+
+void ServiceWorkerHandler::Detached() {
+ Disable();
+}
+
+Response ServiceWorkerHandler::Enable() {
+ if (enabled_)
+ return Response::OK();
+ if (!context_)
+ return Response::InternalError("Could not connect to the context");
+ enabled_ = true;
+
+ ServiceWorkerDevToolsManager::GetInstance()->AddObserver(this);
+
+ client_->DebugOnStartUpdated(
+ DebugOnStartUpdatedParams::Create()->set_debug_on_start(
+ ServiceWorkerDevToolsManager::GetInstance()
+ ->debug_service_worker_on_start()));
+
+ context_watcher_ = new ServiceWorkerContextWatcher(
+ context_, base::Bind(&ServiceWorkerHandler::OnWorkerRegistrationUpdated,
+ weak_factory_.GetWeakPtr()),
+ base::Bind(&ServiceWorkerHandler::OnWorkerVersionUpdated,
+ weak_factory_.GetWeakPtr()),
+ base::Bind(&ServiceWorkerHandler::OnErrorReported,
+ weak_factory_.GetWeakPtr()));
+ context_watcher_->Start();
+
+ UpdateHosts();
+ return Response::OK();
+}
+
+Response ServiceWorkerHandler::Disable() {
+ if (!enabled_)
+ return Response::OK();
+ enabled_ = false;
+
+ ServiceWorkerDevToolsManager::GetInstance()->RemoveObserver(this);
+ for (const auto& pair : attached_hosts_)
+ pair.second->DetachClient();
+ attached_hosts_.clear();
+ DCHECK(context_watcher_);
+ context_watcher_->Stop();
+ context_watcher_ = nullptr;
+ return Response::OK();
+}
+
+Response ServiceWorkerHandler::SendMessage(
+ const std::string& worker_id,
+ const std::string& message) {
+ auto it = attached_hosts_.find(worker_id);
+ if (it == attached_hosts_.end())
+ return Response::InternalError("Not connected to the worker");
+ it->second->DispatchProtocolMessage(message);
+ return Response::OK();
+}
+
+Response ServiceWorkerHandler::Stop(
+ const std::string& worker_id) {
+ auto it = attached_hosts_.find(worker_id);
+ if (it == attached_hosts_.end())
+ return Response::InternalError("Not connected to the worker");
+ it->second->UnregisterWorker();
+ return Response::OK();
+}
+
+Response ServiceWorkerHandler::Unregister(const std::string& scope_url) {
+ if (!enabled_)
+ return Response::OK();
+ if (!context_)
+ return CreateContextErrorResponse();
+ context_->UnregisterServiceWorker(GURL(scope_url), base::Bind(&ResultNoOp));
+ return Response::OK();
+}
+
+Response ServiceWorkerHandler::StartWorker(const std::string& scope_url) {
+ if (!enabled_)
+ return Response::OK();
+ if (!context_)
+ return CreateContextErrorResponse();
+ context_->StartServiceWorker(GURL(scope_url), base::Bind(&StatusNoOp));
+ return Response::OK();
+}
+
+Response ServiceWorkerHandler::StopWorker(const std::string& version_id) {
+ if (!enabled_)
+ return Response::OK();
+ if (!context_)
+ return CreateContextErrorResponse();
+ int64 id = 0;
+ if (!base::StringToInt64(version_id, &id))
+ return CreateInvalidVersionIdErrorResponse();
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(&StopServiceWorkerOnIO, context_, id));
+ return Response::OK();
+}
+
+Response ServiceWorkerHandler::UpdateRegistration(
+ const std::string& scope_url) {
+ if (!enabled_)
+ return Response::OK();
+ if (!context_)
+ return CreateContextErrorResponse();
+ context_->UpdateRegistration(GURL(scope_url));
+ return Response::OK();
+}
+
+Response ServiceWorkerHandler::InspectWorker(const std::string& version_id) {
+ if (!enabled_)
+ return Response::OK();
+ if (!context_)
+ return CreateContextErrorResponse();
+
+ int64 id = 0;
+ if (!base::StringToInt64(version_id, &id))
+ return CreateInvalidVersionIdErrorResponse();
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&GetDevToolsRouteInfoOnIO, context_, id,
+ base::Bind(&ServiceWorkerHandler::OpenNewDevToolsWindow,
+ weak_factory_.GetWeakPtr())));
+ return Response::OK();
+}
+
+Response ServiceWorkerHandler::SkipWaiting(const std::string& version_id) {
+ if (!enabled_)
+ return Response::OK();
+ if (!context_)
+ return CreateContextErrorResponse();
+
+ int64 id = 0;
+ if (!base::StringToInt64(version_id, &id))
+ return CreateInvalidVersionIdErrorResponse();
+ context_->SimulateSkipWaiting(id);
+ return Response::OK();
+}
+
+Response ServiceWorkerHandler::SetDebugOnStart(bool debug_on_start) {
+ ServiceWorkerDevToolsManager::GetInstance()
+ ->set_debug_service_worker_on_start(debug_on_start);
+ return Response::OK();
+}
+
+Response ServiceWorkerHandler::DeliverPushMessage(
+ const std::string& origin,
+ const std::string& registration_id,
+ const std::string& data) {
+ if (!enabled_)
+ return Response::OK();
+ if (!render_frame_host_)
+ return CreateContextErrorResponse();
+ int64 id = 0;
+ if (!base::StringToInt64(registration_id, &id))
+ return CreateInvalidVersionIdErrorResponse();
+ BrowserContext::DeliverPushMessage(
+ render_frame_host_->GetProcess()->GetBrowserContext(), GURL(origin), id,
+ data, base::Bind(&PushDeliveryNoOp));
+ return Response::OK();
+}
+
+void ServiceWorkerHandler::OpenNewDevToolsWindow(int process_id,
+ int devtools_agent_route_id) {
+ scoped_refptr<DevToolsAgentHostImpl> agent_host(
+ ServiceWorkerDevToolsManager::GetInstance()
+ ->GetDevToolsAgentHostForWorker(process_id, devtools_agent_route_id));
+ if (!agent_host.get())
+ return;
+ agent_host->Inspect(render_frame_host_->GetProcess()->GetBrowserContext());
+}
+
+void ServiceWorkerHandler::OnWorkerRegistrationUpdated(
+ const std::vector<ServiceWorkerRegistrationInfo>& registrations) {
+ std::vector<scoped_refptr<ServiceWorkerRegistration>> registration_values;
+ for (const auto& registration : registrations) {
+ registration_values.push_back(
+ CreateRegistrationDictionaryValue(registration));
+ }
+ client_->WorkerRegistrationUpdated(
+ WorkerRegistrationUpdatedParams::Create()->set_registrations(
+ registration_values));
+}
+
+void ServiceWorkerHandler::OnWorkerVersionUpdated(
+ const std::vector<ServiceWorkerVersionInfo>& versions) {
+ std::vector<scoped_refptr<ServiceWorkerVersion>> version_values;
+ for (const auto& version : versions) {
+ version_values.push_back(CreateVersionDictionaryValue(version));
+ }
+ client_->WorkerVersionUpdated(
+ WorkerVersionUpdatedParams::Create()->set_versions(version_values));
+}
+
+void ServiceWorkerHandler::OnErrorReported(
+ int64 registration_id,
+ int64 version_id,
+ const ServiceWorkerContextObserver::ErrorInfo& info) {
+ client_->WorkerErrorReported(
+ WorkerErrorReportedParams::Create()->set_error_message(
+ ServiceWorkerErrorMessage::Create()
+ ->set_error_message(base::UTF16ToUTF8(info.error_message))
+ ->set_registration_id(base::Int64ToString(registration_id))
+ ->set_version_id(base::Int64ToString(version_id))
+ ->set_source_url(info.source_url.spec())
+ ->set_line_number(info.line_number)
+ ->set_column_number(info.column_number)));
+}
+
+void ServiceWorkerHandler::DispatchProtocolMessage(
+ DevToolsAgentHost* host,
+ const std::string& message) {
+
+ auto it = attached_hosts_.find(host->GetId());
+ if (it == attached_hosts_.end())
+ return; // Already disconnected.
+
+ client_->DispatchMessage(
+ DispatchMessageParams::Create()->
+ set_worker_id(host->GetId())->
+ set_message(message));
+}
+
+void ServiceWorkerHandler::AgentHostClosed(
+ DevToolsAgentHost* host,
+ bool replaced_with_another_client) {
+ client_->WorkerTerminated(WorkerTerminatedParams::Create()->
+ set_worker_id(host->GetId()));
+ attached_hosts_.erase(host->GetId());
+}
+
+void ServiceWorkerHandler::WorkerCreated(
+ ServiceWorkerDevToolsAgentHost* host) {
+ BrowserContext* browser_context = nullptr;
+ if (render_frame_host_)
+ browser_context = render_frame_host_->GetProcess()->GetBrowserContext();
+
+ auto hosts = GetMatchingServiceWorkers(browser_context, urls_);
+ if (hosts.find(host->GetId()) != hosts.end() && !host->IsAttached() &&
+ !host->IsPausedForDebugOnStart())
+ host->PauseForDebugOnStart();
+}
+
+void ServiceWorkerHandler::WorkerReadyForInspection(
+ ServiceWorkerDevToolsAgentHost* host) {
+ if (ServiceWorkerDevToolsManager::GetInstance()
+ ->debug_service_worker_on_start()) {
+ // When debug_service_worker_on_start is true, a new DevTools window will
+ // be opend in ServiceWorkerDevToolsManager::WorkerReadyForInspection.
+ return;
+ }
+ UpdateHosts();
+}
+
+void ServiceWorkerHandler::WorkerDestroyed(
+ ServiceWorkerDevToolsAgentHost* host) {
+ UpdateHosts();
+}
+
+void ServiceWorkerHandler::DebugOnStartUpdated(bool debug_on_start) {
+ client_->DebugOnStartUpdated(
+ DebugOnStartUpdatedParams::Create()->set_debug_on_start(debug_on_start));
+}
+
+void ServiceWorkerHandler::ReportWorkerCreated(
+ ServiceWorkerDevToolsAgentHost* host) {
+ if (host->IsAttached())
+ return;
+ attached_hosts_[host->GetId()] = host;
+ host->AttachClient(this);
+ client_->WorkerCreated(WorkerCreatedParams::Create()->
+ set_worker_id(host->GetId())->
+ set_url(host->GetURL().spec()));
+}
+
+void ServiceWorkerHandler::ReportWorkerTerminated(
+ ServiceWorkerDevToolsAgentHost* host) {
+ auto it = attached_hosts_.find(host->GetId());
+ if (it == attached_hosts_.end())
+ return;
+ host->DetachClient();
+ client_->WorkerTerminated(WorkerTerminatedParams::Create()->
+ set_worker_id(host->GetId()));
+ attached_hosts_.erase(it);
+}
+
+} // namespace service_worker
+} // namespace devtools
+} // namespace content
diff --git a/chromium/content/browser/devtools/protocol/service_worker_handler.h b/chromium/content/browser/devtools/protocol/service_worker_handler.h
new file mode 100644
index 00000000000..e277871afcc
--- /dev/null
+++ b/chromium/content/browser/devtools/protocol/service_worker_handler.h
@@ -0,0 +1,106 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_DEVTOOLS_PROTOCOL_SERVICE_WORKER_HANDLER_H_
+#define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_SERVICE_WORKER_HANDLER_H_
+
+#include <set>
+
+#include "base/memory/weak_ptr.h"
+#include "content/browser/devtools/protocol/devtools_protocol_handler.h"
+#include "content/browser/devtools/service_worker_devtools_agent_host.h"
+#include "content/browser/devtools/service_worker_devtools_manager.h"
+#include "content/browser/service_worker/service_worker_context_observer.h"
+#include "content/browser/service_worker/service_worker_info.h"
+#include "content/public/browser/devtools_agent_host.h"
+#include "content/public/browser/devtools_agent_host_client.h"
+
+// Windows headers will redefine SendMessage.
+#ifdef SendMessage
+#undef SendMessage
+#endif
+
+namespace content {
+
+class RenderFrameHostImpl;
+class ServiceWorkerContextWatcher;
+class ServiceWorkerContextWrapper;
+
+namespace devtools {
+namespace service_worker {
+
+class ServiceWorkerHandler : public DevToolsAgentHostClient,
+ public ServiceWorkerDevToolsManager::Observer {
+ public:
+ typedef DevToolsProtocolClient::Response Response;
+
+ ServiceWorkerHandler();
+ ~ServiceWorkerHandler() override;
+
+ void SetRenderFrameHost(RenderFrameHostImpl* render_frame_host);
+ void SetClient(scoped_ptr<Client> client);
+ void UpdateHosts();
+ void Detached();
+
+ // Protocol 'service worker' domain implementation.
+ Response Enable();
+ Response Disable();
+ Response SendMessage(const std::string& worker_id,
+ const std::string& message);
+ Response Stop(const std::string& worker_id);
+ Response Unregister(const std::string& scope_url);
+ Response StartWorker(const std::string& scope_url);
+ Response StopWorker(const std::string& version_id);
+ Response UpdateRegistration(const std::string& scope_url);
+ Response InspectWorker(const std::string& version_id);
+ Response SkipWaiting(const std::string& version_id);
+ Response SetDebugOnStart(bool debug_on_start);
+ Response DeliverPushMessage(const std::string& origin,
+ const std::string& registration_id,
+ const std::string& data);
+
+ // WorkerDevToolsManager::Observer implementation.
+ void WorkerCreated(ServiceWorkerDevToolsAgentHost* host) override;
+ void WorkerReadyForInspection(ServiceWorkerDevToolsAgentHost* host) override;
+ void WorkerDestroyed(ServiceWorkerDevToolsAgentHost* host) override;
+ void DebugOnStartUpdated(bool debug_on_start) override;
+
+ private:
+ // DevToolsAgentHostClient overrides.
+ void DispatchProtocolMessage(DevToolsAgentHost* agent_host,
+ const std::string& message) override;
+ void AgentHostClosed(DevToolsAgentHost* agent_host,
+ bool replaced_with_another_client) override;
+
+ void ReportWorkerCreated(ServiceWorkerDevToolsAgentHost* host);
+ void ReportWorkerTerminated(ServiceWorkerDevToolsAgentHost* host);
+
+ void OnWorkerRegistrationUpdated(
+ const std::vector<ServiceWorkerRegistrationInfo>& registrations);
+ void OnWorkerVersionUpdated(
+ const std::vector<ServiceWorkerVersionInfo>& registrations);
+ void OnErrorReported(int64 registration_id,
+ int64 version_id,
+ const ServiceWorkerContextObserver::ErrorInfo& info);
+
+ void OpenNewDevToolsWindow(int process_id, int devtools_agent_route_id);
+
+ scoped_refptr<ServiceWorkerContextWrapper> context_;
+ scoped_ptr<Client> client_;
+ ServiceWorkerDevToolsAgentHost::Map attached_hosts_;
+ bool enabled_;
+ std::set<GURL> urls_;
+ scoped_refptr<ServiceWorkerContextWatcher> context_watcher_;
+ RenderFrameHostImpl* render_frame_host_;
+
+ base::WeakPtrFactory<ServiceWorkerHandler> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ServiceWorkerHandler);
+};
+
+} // namespace service_worker
+} // namespace devtools
+} // namespace content
+
+#endif // CONTENT_BROWSER_DEVTOOLS_PROTOCOL_SERVICE_WORKER_HANDLER_H_
diff --git a/chromium/content/browser/devtools/protocol/system_info_handler.cc b/chromium/content/browser/devtools/protocol/system_info_handler.cc
new file mode 100644
index 00000000000..aa32e58e928
--- /dev/null
+++ b/chromium/content/browser/devtools/protocol/system_info_handler.cc
@@ -0,0 +1,233 @@
+// Copyright 2014 The Chromium Authors. 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/system_info_handler.h"
+
+#include "base/bind.h"
+#include "content/browser/gpu/compositor_util.h"
+#include "content/public/browser/gpu_data_manager.h"
+#include "gpu/config/gpu_info.h"
+
+namespace content {
+namespace devtools {
+namespace system_info {
+
+namespace {
+
+using Response = DevToolsProtocolClient::Response;
+
+// Give the GPU process a few seconds to provide GPU info.
+const int kGPUInfoWatchdogTimeoutMs = 5000;
+
+class AuxGPUInfoEnumerator : public gpu::GPUInfo::Enumerator {
+ public:
+ AuxGPUInfoEnumerator(base::DictionaryValue* dictionary)
+ : dictionary_(dictionary),
+ in_aux_attributes_(false) { }
+
+ void AddInt64(const char* name, int64 value) override {
+ if (in_aux_attributes_)
+ dictionary_->SetDouble(name, value);
+ }
+
+ void AddInt(const char* name, int value) override {
+ if (in_aux_attributes_)
+ dictionary_->SetInteger(name, value);
+ }
+
+ void AddString(const char* name, const std::string& value) override {
+ if (in_aux_attributes_)
+ dictionary_->SetString(name, value);
+ }
+
+ void AddBool(const char* name, bool value) override {
+ if (in_aux_attributes_)
+ dictionary_->SetBoolean(name, value);
+ }
+
+ void AddTimeDeltaInSecondsF(const char* name,
+ const base::TimeDelta& value) override {
+ if (in_aux_attributes_)
+ dictionary_->SetDouble(name, value.InSecondsF());
+ }
+
+ void BeginGPUDevice() override {}
+
+ void EndGPUDevice() override {}
+
+ void BeginVideoDecodeAcceleratorSupportedProfile() override {}
+
+ void EndVideoDecodeAcceleratorSupportedProfile() override {}
+
+ void BeginVideoEncodeAcceleratorSupportedProfile() override {}
+
+ void EndVideoEncodeAcceleratorSupportedProfile() override {}
+
+ void BeginAuxAttributes() override {
+ in_aux_attributes_ = true;
+ }
+
+ void EndAuxAttributes() override {
+ in_aux_attributes_ = false;
+ }
+
+ private:
+ base::DictionaryValue* dictionary_;
+ bool in_aux_attributes_;
+};
+
+scoped_refptr<GPUDevice> GPUDeviceToProtocol(
+ const gpu::GPUInfo::GPUDevice& device) {
+ return GPUDevice::Create()->set_vendor_id(device.vendor_id)
+ ->set_device_id(device.device_id)
+ ->set_vendor_string(device.vendor_string)
+ ->set_device_string(device.device_string);
+}
+
+} // namespace
+
+class SystemInfoHandlerGpuObserver : public content::GpuDataManagerObserver {
+ public:
+ SystemInfoHandlerGpuObserver(base::WeakPtr<SystemInfoHandler> handler,
+ DevToolsCommandId command_id)
+ : handler_(handler),
+ command_id_(command_id),
+ observer_id_(++next_observer_id_)
+ {
+ if (handler_) {
+ handler_->AddActiveObserverId(observer_id_);
+ }
+ }
+
+ void OnGpuInfoUpdate() override {
+ UnregisterAndSendResponse();
+ }
+
+ void OnGpuProcessCrashed(base::TerminationStatus exit_code) override {
+ UnregisterAndSendResponse();
+ }
+
+ void UnregisterAndSendResponse() {
+ GpuDataManager::GetInstance()->RemoveObserver(this);
+ if (handler_.get()) {
+ if (handler_->RemoveActiveObserverId(observer_id_)) {
+ handler_->SendGetInfoResponse(command_id_);
+ }
+ }
+ delete this;
+ }
+
+ int GetObserverId() {
+ return observer_id_;
+ }
+
+ private:
+ base::WeakPtr<SystemInfoHandler> handler_;
+ DevToolsCommandId command_id_;
+ int observer_id_;
+
+ static int next_observer_id_;
+};
+
+int SystemInfoHandlerGpuObserver::next_observer_id_ = 0;
+
+SystemInfoHandler::SystemInfoHandler()
+ : weak_factory_(this) {
+}
+
+SystemInfoHandler::~SystemInfoHandler() {
+}
+
+void SystemInfoHandler::SetClient(scoped_ptr<Client> client) {
+ client_.swap(client);
+}
+
+Response SystemInfoHandler::GetInfo(DevToolsCommandId command_id) {
+ std::string reason;
+ if (!GpuDataManager::GetInstance()->GpuAccessAllowed(&reason) ||
+ GpuDataManager::GetInstance()->IsEssentialGpuInfoAvailable()) {
+ // The GpuDataManager already has all of the information needed to make
+ // GPU-based blacklisting decisions. Post a task to give it to the
+ // client asynchronously.
+ //
+ // Waiting for complete GPU info in the if-test above seems to
+ // frequently hit internal timeouts in the launching of the unsandboxed
+ // GPU process in debug builds on Windows.
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&SystemInfoHandler::SendGetInfoResponse,
+ weak_factory_.GetWeakPtr(),
+ command_id));
+ } else {
+ // We will be able to get more information from the GpuDataManager.
+ // Register a transient observer with it to call us back when the
+ // information is available.
+ SystemInfoHandlerGpuObserver* observer = new SystemInfoHandlerGpuObserver(
+ weak_factory_.GetWeakPtr(), command_id);
+ BrowserThread::PostDelayedTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&SystemInfoHandler::ObserverWatchdogCallback,
+ weak_factory_.GetWeakPtr(),
+ observer->GetObserverId(),
+ command_id),
+ base::TimeDelta::FromMilliseconds(kGPUInfoWatchdogTimeoutMs));
+ GpuDataManager::GetInstance()->AddObserver(observer);
+ // There's no other method available to request just essential GPU info.
+ GpuDataManager::GetInstance()->RequestCompleteGpuInfoIfNeeded();
+ }
+
+ return Response::OK();
+}
+
+void SystemInfoHandler::SendGetInfoResponse(DevToolsCommandId command_id) {
+ gpu::GPUInfo gpu_info = GpuDataManager::GetInstance()->GetGPUInfo();
+ std::vector<scoped_refptr<GPUDevice>> devices;
+ devices.push_back(GPUDeviceToProtocol(gpu_info.gpu));
+ for (const auto& device : gpu_info.secondary_gpus)
+ devices.push_back(GPUDeviceToProtocol(device));
+
+ scoped_ptr<base::DictionaryValue> aux_attributes(new base::DictionaryValue);
+ AuxGPUInfoEnumerator enumerator(aux_attributes.get());
+ gpu_info.EnumerateFields(&enumerator);
+
+ scoped_refptr<GPUInfo> gpu = GPUInfo::Create()
+ ->set_devices(devices)
+ ->set_aux_attributes(aux_attributes.Pass())
+ ->set_feature_status(make_scoped_ptr(GetFeatureStatus()))
+ ->set_driver_bug_workarounds(GetDriverBugWorkarounds());
+
+ client_->SendGetInfoResponse(
+ command_id,
+ GetInfoResponse::Create()->set_gpu(gpu)
+ ->set_model_name(gpu_info.machine_model_name)
+ ->set_model_version(gpu_info.machine_model_version));
+}
+
+void SystemInfoHandler::AddActiveObserverId(int observer_id) {
+ base::AutoLock auto_lock(lock_);
+ active_observers_.insert(observer_id);
+}
+
+bool SystemInfoHandler::RemoveActiveObserverId(int observer_id) {
+ base::AutoLock auto_lock(lock_);
+ int num_removed = active_observers_.erase(observer_id);
+ return (num_removed != 0);
+}
+
+void SystemInfoHandler::ObserverWatchdogCallback(int observer_id,
+ DevToolsCommandId command_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (RemoveActiveObserverId(observer_id)) {
+ SendGetInfoResponse(command_id);
+ // For the time being we want to know about this event in the test logs.
+ LOG(ERROR) << "SystemInfoHandler: request for GPU info timed out!"
+ << " Most recent info sent.";
+ }
+}
+
+} // namespace system_info
+} // namespace devtools
+} // namespace content
diff --git a/chromium/content/browser/devtools/protocol/system_info_handler.h b/chromium/content/browser/devtools/protocol/system_info_handler.h
new file mode 100644
index 00000000000..485bdab4dd7
--- /dev/null
+++ b/chromium/content/browser/devtools/protocol/system_info_handler.h
@@ -0,0 +1,59 @@
+// Copyright 2014 The Chromium Authors. 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_SYSTEM_INFO_HANDLER_H_
+#define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_SYSTEM_INFO_HANDLER_H_
+
+#include <set>
+
+#include "content/browser/devtools/protocol/devtools_protocol_handler.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/gpu_data_manager_observer.h"
+
+namespace content {
+namespace devtools {
+namespace system_info {
+
+class SystemInfoHandler {
+ public:
+ using Response = DevToolsProtocolClient::Response;
+
+ SystemInfoHandler();
+ ~SystemInfoHandler();
+
+ void SetClient(scoped_ptr<Client> client);
+
+ Response GetInfo(DevToolsCommandId command_id);
+
+ private:
+ friend class SystemInfoHandlerGpuObserver;
+
+ void SendGetInfoResponse(DevToolsCommandId command_id);
+
+ // Bookkeeping for the active GpuObservers.
+ void AddActiveObserverId(int observer_id);
+ bool RemoveActiveObserverId(int observer_id);
+ void ObserverWatchdogCallback(int observer_id, DevToolsCommandId command_id);
+
+ // For robustness, we have to guarantee a response to getInfo requests.
+ // It's very unlikely that the requests will time out. The
+ // GpuDataManager's threading model is not well defined (see comments in
+ // gpu_data_manager_impl.h) and it is very difficult to correctly clean
+ // up its observers. For the moment, especially since these classes are
+ // only used in tests, we leak a little bit of memory if we don't get a
+ // callback from the GpuDataManager in time.
+ mutable base::Lock lock_;
+ std::set<int> active_observers_;
+
+ scoped_ptr<Client> client_;
+ base::WeakPtrFactory<SystemInfoHandler> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(SystemInfoHandler);
+};
+
+} // namespace system_info
+} // namespace devtools
+} // namespace content
+
+#endif // CONTENT_BROWSER_DEVTOOLS_PROTOCOL_SYSTEM_INFO_HANDLER_H_
diff --git a/chromium/content/browser/devtools/protocol/tethering_handler.cc b/chromium/content/browser/devtools/protocol/tethering_handler.cc
new file mode 100644
index 00000000000..b8b3e3f70b2
--- /dev/null
+++ b/chromium/content/browser/devtools/protocol/tethering_handler.cc
@@ -0,0 +1,407 @@
+// Copyright 2014 The Chromium Authors. 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/tethering_handler.h"
+
+#include "content/public/browser/browser_thread.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/socket/server_socket.h"
+#include "net/socket/stream_socket.h"
+#include "net/socket/tcp_server_socket.h"
+
+namespace content {
+namespace devtools {
+namespace tethering {
+
+namespace {
+
+const char kLocalhost[] = "127.0.0.1";
+
+const int kListenBacklog = 5;
+const int kBufferSize = 16 * 1024;
+
+const int kMinTetheringPort = 1024;
+const int kMaxTetheringPort = 32767;
+
+using Response = DevToolsProtocolClient::Response;
+using CreateServerSocketCallback =
+ base::Callback<scoped_ptr<net::ServerSocket>(std::string*)>;
+
+class SocketPump {
+ public:
+ SocketPump(net::StreamSocket* client_socket)
+ : client_socket_(client_socket),
+ pending_writes_(0),
+ pending_destruction_(false) {
+ }
+
+ std::string Init(const CreateServerSocketCallback& socket_callback) {
+ std::string channel_name;
+ server_socket_ = socket_callback.Run(&channel_name);
+ if (!server_socket_.get() || channel_name.empty())
+ SelfDestruct();
+
+ int result = server_socket_->Accept(
+ &accepted_socket_,
+ base::Bind(&SocketPump::OnAccepted, base::Unretained(this)));
+ if (result != net::ERR_IO_PENDING)
+ OnAccepted(result);
+ return channel_name;
+ }
+
+ private:
+ void OnAccepted(int result) {
+ if (result < 0) {
+ SelfDestruct();
+ return;
+ }
+
+ ++pending_writes_; // avoid SelfDestruct in first Pump
+ Pump(client_socket_.get(), accepted_socket_.get());
+ --pending_writes_;
+ if (pending_destruction_) {
+ SelfDestruct();
+ } else {
+ Pump(accepted_socket_.get(), client_socket_.get());
+ }
+ }
+
+ void Pump(net::StreamSocket* from, net::StreamSocket* to) {
+ scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kBufferSize);
+ int result = from->Read(
+ buffer.get(),
+ kBufferSize,
+ base::Bind(
+ &SocketPump::OnRead, base::Unretained(this), from, to, buffer));
+ if (result != net::ERR_IO_PENDING)
+ OnRead(from, to, buffer, result);
+ }
+
+ void OnRead(net::StreamSocket* from,
+ net::StreamSocket* to,
+ scoped_refptr<net::IOBuffer> buffer,
+ int result) {
+ if (result <= 0) {
+ SelfDestruct();
+ return;
+ }
+
+ int total = result;
+ scoped_refptr<net::DrainableIOBuffer> drainable =
+ new net::DrainableIOBuffer(buffer.get(), total);
+
+ ++pending_writes_;
+ result = to->Write(drainable.get(),
+ total,
+ base::Bind(&SocketPump::OnWritten,
+ base::Unretained(this),
+ drainable,
+ from,
+ to));
+ if (result != net::ERR_IO_PENDING)
+ OnWritten(drainable, from, to, result);
+ }
+
+ void OnWritten(scoped_refptr<net::DrainableIOBuffer> drainable,
+ net::StreamSocket* from,
+ net::StreamSocket* to,
+ int result) {
+ --pending_writes_;
+ if (result < 0) {
+ SelfDestruct();
+ return;
+ }
+
+ drainable->DidConsume(result);
+ if (drainable->BytesRemaining() > 0) {
+ ++pending_writes_;
+ result = to->Write(drainable.get(),
+ drainable->BytesRemaining(),
+ base::Bind(&SocketPump::OnWritten,
+ base::Unretained(this),
+ drainable,
+ from,
+ to));
+ if (result != net::ERR_IO_PENDING)
+ OnWritten(drainable, from, to, result);
+ return;
+ }
+
+ if (pending_destruction_) {
+ SelfDestruct();
+ return;
+ }
+ Pump(from, to);
+ }
+
+ void SelfDestruct() {
+ if (pending_writes_ > 0) {
+ pending_destruction_ = true;
+ return;
+ }
+ delete this;
+ }
+
+
+ private:
+ scoped_ptr<net::StreamSocket> client_socket_;
+ scoped_ptr<net::ServerSocket> server_socket_;
+ scoped_ptr<net::StreamSocket> accepted_socket_;
+ int pending_writes_;
+ bool pending_destruction_;
+};
+
+class BoundSocket {
+ public:
+ typedef base::Callback<void(uint16, const std::string&)> AcceptedCallback;
+
+ BoundSocket(AcceptedCallback accepted_callback,
+ const CreateServerSocketCallback& socket_callback)
+ : accepted_callback_(accepted_callback),
+ socket_callback_(socket_callback),
+ socket_(new net::TCPServerSocket(NULL, net::NetLog::Source())),
+ port_(0) {
+ }
+
+ virtual ~BoundSocket() {
+ }
+
+ bool Listen(uint16 port) {
+ port_ = port;
+ net::IPAddressNumber ip_number;
+ if (!net::ParseIPLiteralToNumber(kLocalhost, &ip_number))
+ return false;
+
+ net::IPEndPoint end_point(ip_number, port);
+ int result = socket_->Listen(end_point, kListenBacklog);
+ if (result < 0)
+ return false;
+
+ net::IPEndPoint local_address;
+ result = socket_->GetLocalAddress(&local_address);
+ if (result < 0)
+ return false;
+
+ DoAccept();
+ return true;
+ }
+
+ private:
+ typedef std::map<net::IPEndPoint, net::StreamSocket*> AcceptedSocketsMap;
+
+ void DoAccept() {
+ while (true) {
+ int result = socket_->Accept(
+ &accept_socket_,
+ base::Bind(&BoundSocket::OnAccepted, base::Unretained(this)));
+ if (result == net::ERR_IO_PENDING)
+ break;
+ else
+ HandleAcceptResult(result);
+ }
+ }
+
+ void OnAccepted(int result) {
+ HandleAcceptResult(result);
+ if (result == net::OK)
+ DoAccept();
+ }
+
+ void HandleAcceptResult(int result) {
+ if (result != net::OK)
+ return;
+
+ SocketPump* pump = new SocketPump(accept_socket_.release());
+ std::string name = pump->Init(socket_callback_);
+ if (!name.empty())
+ accepted_callback_.Run(port_, name);
+ }
+
+ AcceptedCallback accepted_callback_;
+ CreateServerSocketCallback socket_callback_;
+ scoped_ptr<net::ServerSocket> socket_;
+ scoped_ptr<net::StreamSocket> accept_socket_;
+ uint16 port_;
+};
+
+} // namespace
+
+// TetheringHandler::TetheringImpl -------------------------------------------
+
+class TetheringHandler::TetheringImpl {
+ public:
+ TetheringImpl(
+ base::WeakPtr<TetheringHandler> handler,
+ const CreateServerSocketCallback& socket_callback);
+ ~TetheringImpl();
+
+ void Bind(DevToolsCommandId command_id, uint16 port);
+ void Unbind(DevToolsCommandId command_id, uint16 port);
+ void Accepted(uint16 port, const std::string& name);
+
+ private:
+ void SendInternalError(DevToolsCommandId command_id,
+ const std::string& message);
+
+ base::WeakPtr<TetheringHandler> handler_;
+ CreateServerSocketCallback socket_callback_;
+
+ typedef std::map<uint16, BoundSocket*> BoundSockets;
+ BoundSockets bound_sockets_;
+};
+
+TetheringHandler::TetheringImpl::TetheringImpl(
+ base::WeakPtr<TetheringHandler> handler,
+ const CreateServerSocketCallback& socket_callback)
+ : handler_(handler),
+ socket_callback_(socket_callback) {
+}
+
+TetheringHandler::TetheringImpl::~TetheringImpl() {
+ STLDeleteValues(&bound_sockets_);
+}
+
+void TetheringHandler::TetheringImpl::Bind(
+ DevToolsCommandId command_id, uint16 port) {
+ if (bound_sockets_.find(port) != bound_sockets_.end()) {
+ SendInternalError(command_id, "Port already bound");
+ return;
+ }
+
+ BoundSocket::AcceptedCallback callback = base::Bind(
+ &TetheringHandler::TetheringImpl::Accepted, base::Unretained(this));
+ scoped_ptr<BoundSocket> bound_socket(
+ new BoundSocket(callback, socket_callback_));
+ if (!bound_socket->Listen(port)) {
+ SendInternalError(command_id, "Could not bind port");
+ return;
+ }
+
+ bound_sockets_[port] = bound_socket.release();
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&TetheringHandler::SendBindSuccess, handler_, command_id));
+}
+
+void TetheringHandler::TetheringImpl::Unbind(
+ DevToolsCommandId command_id, uint16 port) {
+
+ BoundSockets::iterator it = bound_sockets_.find(port);
+ if (it == bound_sockets_.end()) {
+ SendInternalError(command_id, "Port is not bound");
+ return;
+ }
+
+ delete it->second;
+ bound_sockets_.erase(it);
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&TetheringHandler::SendUnbindSuccess, handler_, command_id));
+}
+
+void TetheringHandler::TetheringImpl::Accepted(
+ uint16 port, const std::string& name) {
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&TetheringHandler::Accepted, handler_, port, name));
+}
+
+void TetheringHandler::TetheringImpl::SendInternalError(
+ DevToolsCommandId command_id,
+ const std::string& message) {
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&TetheringHandler::SendInternalError, handler_,
+ command_id, message));
+}
+
+
+// TetheringHandler ----------------------------------------------------------
+
+// static
+TetheringHandler::TetheringImpl* TetheringHandler::impl_ = nullptr;
+
+TetheringHandler::TetheringHandler(
+ const CreateServerSocketCallback& socket_callback,
+ scoped_refptr<base::MessageLoopProxy> message_loop_proxy)
+ : socket_callback_(socket_callback),
+ message_loop_proxy_(message_loop_proxy),
+ is_active_(false),
+ weak_factory_(this) {
+}
+
+TetheringHandler::~TetheringHandler() {
+ if (is_active_) {
+ message_loop_proxy_->DeleteSoon(FROM_HERE, impl_);
+ impl_ = nullptr;
+ }
+}
+
+void TetheringHandler::SetClient(scoped_ptr<Client> client) {
+ client_.swap(client);
+}
+
+void TetheringHandler::Accepted(uint16 port, const std::string& name) {
+ client_->Accepted(AcceptedParams::Create()->set_port(port)
+ ->set_connection_id(name));
+}
+
+bool TetheringHandler::Activate() {
+ if (is_active_)
+ return true;
+ if (impl_)
+ return false;
+ is_active_ = true;
+ impl_ = new TetheringImpl(weak_factory_.GetWeakPtr(), socket_callback_);
+ return true;
+}
+
+Response TetheringHandler::Bind(DevToolsCommandId command_id, int port) {
+ if (port < kMinTetheringPort || port > kMaxTetheringPort)
+ return Response::InvalidParams("port");
+
+ if (!Activate())
+ return Response::ServerError("Tethering is used by another connection");
+
+ DCHECK(impl_);
+ message_loop_proxy_->PostTask(
+ FROM_HERE,
+ base::Bind(&TetheringImpl::Bind, base::Unretained(impl_),
+ command_id, port));
+ return Response::OK();
+}
+
+Response TetheringHandler::Unbind(DevToolsCommandId command_id, int port) {
+ if (!Activate())
+ return Response::ServerError("Tethering is used by another connection");
+
+ DCHECK(impl_);
+ message_loop_proxy_->PostTask(
+ FROM_HERE,
+ base::Bind(&TetheringImpl::Unbind, base::Unretained(impl_),
+ command_id, port));
+ return Response::OK();
+}
+
+void TetheringHandler::SendBindSuccess(DevToolsCommandId command_id) {
+ client_->SendBindResponse(command_id, BindResponse::Create());
+}
+
+void TetheringHandler::SendUnbindSuccess(DevToolsCommandId command_id) {
+ client_->SendUnbindResponse(command_id, UnbindResponse::Create());
+}
+
+void TetheringHandler::SendInternalError(DevToolsCommandId command_id,
+ const std::string& message) {
+ client_->SendError(command_id, Response::InternalError(message));
+}
+
+} // namespace tethering
+} // namespace devtools
+} // namespace content
diff --git a/chromium/content/browser/devtools/protocol/tethering_handler.h b/chromium/content/browser/devtools/protocol/tethering_handler.h
new file mode 100644
index 00000000000..04bf6906d0f
--- /dev/null
+++ b/chromium/content/browser/devtools/protocol/tethering_handler.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_DEVTOOLS_PROTOCOL_TETHERING_HANDLER_H_
+#define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_TETHERING_HANDLER_H_
+
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "content/browser/devtools/protocol/devtools_protocol_handler.h"
+
+namespace net {
+class ServerSocket;
+}
+
+namespace content {
+namespace devtools {
+namespace tethering {
+
+// This class implements reversed tethering handler.
+class TetheringHandler {
+ public:
+ using Response = DevToolsProtocolClient::Response;
+ using CreateServerSocketCallback =
+ base::Callback<scoped_ptr<net::ServerSocket>(std::string*)>;
+
+ TetheringHandler(const CreateServerSocketCallback& socket_callback,
+ scoped_refptr<base::MessageLoopProxy> message_loop_proxy);
+ ~TetheringHandler();
+
+ void SetClient(scoped_ptr<Client> client);
+
+ Response Bind(DevToolsCommandId command_id, int port);
+ Response Unbind(DevToolsCommandId command_id, int port);
+
+ private:
+ class TetheringImpl;
+
+ void Accepted(uint16 port, const std::string& name);
+ bool Activate();
+
+ void SendBindSuccess(DevToolsCommandId command_id);
+ void SendUnbindSuccess(DevToolsCommandId command_id);
+ void SendInternalError(DevToolsCommandId command_id,
+ const std::string& message);
+
+ scoped_ptr<Client> client_;
+ CreateServerSocketCallback socket_callback_;
+ scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
+ bool is_active_;
+ base::WeakPtrFactory<TetheringHandler> weak_factory_;
+
+ static TetheringImpl* impl_;
+
+ DISALLOW_COPY_AND_ASSIGN(TetheringHandler);
+};
+
+} // namespace tethering
+} // namespace devtools
+} // namespace content
+
+#endif // CONTENT_BROWSER_DEVTOOLS_PROTOCOL_TETHERING_HANDLER_H_
diff --git a/chromium/content/browser/devtools/protocol/tracing_handler.cc b/chromium/content/browser/devtools/protocol/tracing_handler.cc
index 7515da87b74..a4319b9efd0 100644
--- a/chromium/content/browser/devtools/protocol/tracing_handler.cc
+++ b/chromium/content/browser/devtools/protocol/tracing_handler.cc
@@ -7,11 +7,11 @@
#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"
+#include "base/trace_event/trace_event_impl.h"
namespace content {
namespace devtools {
@@ -80,21 +80,20 @@ void TracingHandler::OnTraceDataCollected(const std::string& trace_fragment) {
}
void TracingHandler::OnTraceComplete() {
- TracingCompleteParams params;
- client_->TracingComplete(params);
+ client_->TracingComplete(TracingCompleteParams::Create());
}
-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) {
+Response TracingHandler::Start(DevToolsCommandId command_id,
+ const std::string* categories,
+ const std::string* options_str,
+ const double* buffer_usage_reporting_interval) {
if (is_recording_)
- return command->InternalErrorResponse("Tracing is already started");
- is_recording_ = true;
+ return Response::InternalError("Tracing is already started");
- base::debug::TraceOptions options = TraceOptionsFromString(options_str);
- base::debug::CategoryFilter filter(categories ? *categories : std::string());
+ is_recording_ = true;
+ base::trace_event::TraceOptions options = TraceOptionsFromString(options_str);
+ base::trace_event::CategoryFilter filter(categories ? *categories
+ : std::string());
if (buffer_usage_reporting_interval)
SetupTimer(*buffer_usage_reporting_interval);
@@ -105,7 +104,7 @@ scoped_refptr<DevToolsProtocol::Response> TracingHandler::Start(
filter,
options,
TracingController::EnableRecordingDoneCallback());
- return nullptr;
+ return Response::FallThrough();
}
TracingController::GetInstance()->EnableRecording(
@@ -113,55 +112,55 @@ scoped_refptr<DevToolsProtocol::Response> TracingHandler::Start(
options,
base::Bind(&TracingHandler::OnRecordingEnabled,
weak_factory_.GetWeakPtr(),
- command));
- return command->AsyncResponsePromise();
+ command_id));
+ return Response::OK();
}
-scoped_refptr<DevToolsProtocol::Response> TracingHandler::End(
- scoped_refptr<DevToolsProtocol::Command> command) {
+Response TracingHandler::End(DevToolsCommandId command_id) {
if (!is_recording_)
- return command->InternalErrorResponse("Tracing is not started");
+ return Response::InternalError("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);
+ return target_ == Renderer ? Response::FallThrough() : Response::OK();
}
-scoped_refptr<DevToolsProtocol::Response> TracingHandler::GetCategories(
- scoped_refptr<DevToolsProtocol::Command> command) {
+Response TracingHandler::GetCategories(DevToolsCommandId command_id) {
TracingController::GetInstance()->GetCategories(
base::Bind(&TracingHandler::OnCategoriesReceived,
weak_factory_.GetWeakPtr(),
- command));
- return command->AsyncResponsePromise();
+ command_id));
+ return Response::OK();
}
-void TracingHandler::OnRecordingEnabled(
- scoped_refptr<DevToolsProtocol::Command> command) {
- StartResponse response;
- client_->SendStartResponse(command, response);
+void TracingHandler::OnRecordingEnabled(DevToolsCommandId command_id) {
+ client_->SendStartResponse(command_id, StartResponse::Create());
}
-void TracingHandler::OnBufferUsage(float usage) {
- BufferUsageParams params;
- params.set_value(usage);
- client_->BufferUsage(params);
+void TracingHandler::OnBufferUsage(float percent_full,
+ size_t approximate_event_count) {
+ // TODO(crbug426117): remove set_value once all clients have switched to
+ // the new interface of the event.
+ client_->BufferUsage(BufferUsageParams::Create()
+ ->set_value(percent_full)
+ ->set_percent_full(percent_full)
+ ->set_event_count(approximate_event_count));
}
void TracingHandler::OnCategoriesReceived(
- scoped_refptr<DevToolsProtocol::Command> command,
+ DevToolsCommandId command_id,
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);
+ std::vector<std::string> categories;
+ for (const std::string& category : category_set)
+ categories.push_back(category);
+ client_->SendGetCategoriesResponse(command_id,
+ GetCategoriesResponse::Create()->set_categories(categories));
}
-base::debug::TraceOptions TracingHandler::TraceOptionsFromString(
+base::trace_event::TraceOptions TracingHandler::TraceOptionsFromString(
const std::string* options) {
- base::debug::TraceOptions ret;
+ base::trace_event::TraceOptions ret;
if (!options)
return ret;
@@ -171,11 +170,11 @@ base::debug::TraceOptions TracingHandler::TraceOptionsFromString(
base::SplitString(*options, ',', &split);
for (iter = split.begin(); iter != split.end(); ++iter) {
if (*iter == kRecordUntilFull) {
- ret.record_mode = base::debug::RECORD_UNTIL_FULL;
+ ret.record_mode = base::trace_event::RECORD_UNTIL_FULL;
} else if (*iter == kRecordContinuously) {
- ret.record_mode = base::debug::RECORD_CONTINUOUSLY;
+ ret.record_mode = base::trace_event::RECORD_CONTINUOUSLY;
} else if (*iter == kRecordAsMuchAsPossible) {
- ret.record_mode = base::debug::RECORD_AS_MUCH_AS_POSSIBLE;
+ ret.record_mode = base::trace_event::RECORD_AS_MUCH_AS_POSSIBLE;
} else if (*iter == kEnableSampling) {
ret.enable_sampling = true;
}
@@ -192,13 +191,11 @@ void TracingHandler::SetupTimer(double usage_reporting_interval) {
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())),
+ FROM_HERE, interval,
+ base::Bind(base::IgnoreResult(&TracingController::GetTraceBufferUsage),
+ base::Unretained(TracingController::GetInstance()),
+ base::Bind(&TracingHandler::OnBufferUsage,
+ weak_factory_.GetWeakPtr())),
true));
buffer_usage_poll_timer_->Reset();
}
diff --git a/chromium/content/browser/devtools/protocol/tracing_handler.h b/chromium/content/browser/devtools/protocol/tracing_handler.h
index b20e5854a3b..1afd6b39fcf 100644
--- a/chromium/content/browser/devtools/protocol/tracing_handler.h
+++ b/chromium/content/browser/devtools/protocol/tracing_handler.h
@@ -8,9 +8,9 @@
#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 "base/trace_event/trace_event.h"
+#include "content/browser/devtools/protocol/devtools_protocol_handler.h"
#include "content/public/browser/tracing_controller.h"
namespace base {
@@ -36,25 +36,22 @@ class TracingHandler {
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);
+ Response Start(DevToolsCommandId command_id,
+ const std::string* categories,
+ const std::string* options,
+ const double* buffer_usage_reporting_interval);
+ Response End(DevToolsCommandId command_id);
+ Response GetCategories(DevToolsCommandId command);
private:
- void OnRecordingEnabled(scoped_refptr<DevToolsProtocol::Command> command);
- void OnBufferUsage(float usage);
+ void OnRecordingEnabled(DevToolsCommandId command_id);
+ void OnBufferUsage(float percent_full, size_t approximate_event_count);
- void OnCategoriesReceived(scoped_refptr<DevToolsProtocol::Command> command,
+ void OnCategoriesReceived(DevToolsCommandId command_id,
const std::set<std::string>& category_set);
- base::debug::TraceOptions TraceOptionsFromString(const std::string* options);
+ base::trace_event::TraceOptions TraceOptionsFromString(
+ const std::string* options);
void SetupTimer(double usage_reporting_interval);
diff --git a/chromium/content/browser/devtools/protocol/usage_and_quota_query.cc b/chromium/content/browser/devtools/protocol/usage_and_quota_query.cc
deleted file mode 100644
index 2936fe1e079..00000000000
--- a/chromium/content/browser/devtools/protocol/usage_and_quota_query.cc
+++ /dev/null
@@ -1,136 +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/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
deleted file mode 100644
index ffbf7010a18..00000000000
--- a/chromium/content/browser/devtools/protocol/usage_and_quota_query.h
+++ /dev/null
@@ -1,55 +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_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
deleted file mode 100644
index fd8fc09a253..00000000000
--- a/chromium/content/browser/devtools/protocol/worker_handler.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/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
deleted file mode 100644
index 1c1faafed2b..00000000000
--- a/chromium/content/browser/devtools/protocol/worker_handler.h
+++ /dev/null
@@ -1,35 +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_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_frame_devtools_agent_host.cc b/chromium/content/browser/devtools/render_frame_devtools_agent_host.cc
new file mode 100644
index 00000000000..6f40d6fae6a
--- /dev/null
+++ b/chromium/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -0,0 +1,535 @@
+// 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/render_frame_devtools_agent_host.h"
+
+#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_frame_trace_recorder.h"
+#include "content/browser/devtools/protocol/devtools_protocol_handler.h"
+#include "content/browser/devtools/protocol/dom_handler.h"
+#include "content/browser/devtools/protocol/emulation_handler.h"
+#include "content/browser/devtools/protocol/input_handler.h"
+#include "content/browser/devtools/protocol/inspector_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/service_worker_handler.h"
+#include "content/browser/devtools/protocol/tracing_handler.h"
+#include "content/browser/frame_host/render_frame_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/site_instance_impl.h"
+#include "content/browser/web_contents/web_contents_impl.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/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"
+#include "content/public/browser/render_widget_host_view.h"
+#endif
+
+namespace content {
+
+typedef std::vector<RenderFrameDevToolsAgentHost*> Instances;
+
+namespace {
+base::LazyInstance<Instances>::Leaky g_instances = LAZY_INSTANCE_INITIALIZER;
+
+static RenderFrameDevToolsAgentHost* FindAgentHost(RenderFrameHost* host) {
+ if (g_instances == NULL)
+ return NULL;
+ for (Instances::iterator it = g_instances.Get().begin();
+ it != g_instances.Get().end(); ++it) {
+ if ((*it)->HasRenderFrameHost(host))
+ return *it;
+ }
+ return NULL;
+}
+
+// Returns RenderFrameDevToolsAgentHost attached to any of RenderFrameHost
+// instances associated with |web_contents|
+static RenderFrameDevToolsAgentHost* FindAgentHost(WebContents* web_contents) {
+ if (g_instances == NULL)
+ return NULL;
+ for (Instances::iterator it = g_instances.Get().begin();
+ it != g_instances.Get().end(); ++it) {
+ if ((*it)->GetWebContents() == web_contents)
+ return *it;
+ }
+ return NULL;
+}
+
+bool ShouldCreateDevToolsFor(RenderFrameHost* rfh) {
+ return rfh->IsCrossProcessSubframe() || !rfh->GetParent();
+}
+
+} // namespace
+
+scoped_refptr<DevToolsAgentHost>
+DevToolsAgentHost::GetOrCreateFor(WebContents* web_contents) {
+ RenderFrameDevToolsAgentHost* result = FindAgentHost(web_contents);
+ if (!result)
+ result = new RenderFrameDevToolsAgentHost(web_contents->GetMainFrame());
+ return result;
+}
+
+// static
+scoped_refptr<DevToolsAgentHost> RenderFrameDevToolsAgentHost::GetOrCreateFor(
+ RenderFrameHost* host) {
+ RenderFrameDevToolsAgentHost* result = FindAgentHost(host);
+ if (!result)
+ result = new RenderFrameDevToolsAgentHost(host);
+ return result;
+}
+
+// static
+void RenderFrameDevToolsAgentHost::AppendAgentHostForFrameIfApplicable(
+ DevToolsAgentHost::List* result,
+ RenderFrameHost* host) {
+ RenderFrameHostImpl* rfh = static_cast<RenderFrameHostImpl*>(host);
+ if (!rfh->IsRenderFrameLive())
+ return;
+ if (ShouldCreateDevToolsFor(rfh))
+ result->push_back(RenderFrameDevToolsAgentHost::GetOrCreateFor(rfh));
+}
+
+// static
+bool DevToolsAgentHost::HasFor(WebContents* web_contents) {
+ return FindAgentHost(web_contents) != NULL;
+}
+
+// static
+bool DevToolsAgentHost::IsDebuggerAttached(WebContents* web_contents) {
+ RenderFrameDevToolsAgentHost* agent_host = FindAgentHost(web_contents);
+ return agent_host && agent_host->IsAttached();
+}
+
+//static
+void RenderFrameDevToolsAgentHost::AddAllAgentHosts(
+ DevToolsAgentHost::List* result) {
+ base::Callback<void(RenderFrameHost*)> callback = base::Bind(
+ RenderFrameDevToolsAgentHost::AppendAgentHostForFrameIfApplicable,
+ base::Unretained(result));
+ for (const auto& wc : WebContentsImpl::GetAllWebContents())
+ wc->ForEachFrame(callback);
+}
+
+// static
+void RenderFrameDevToolsAgentHost::OnCancelPendingNavigation(
+ RenderFrameHost* pending,
+ RenderFrameHost* current) {
+ RenderFrameDevToolsAgentHost* agent_host = FindAgentHost(pending);
+ if (!agent_host)
+ return;
+ agent_host->ReattachToRenderFrameHost(current);
+}
+
+RenderFrameDevToolsAgentHost::RenderFrameDevToolsAgentHost(RenderFrameHost* rfh)
+ : render_frame_host_(NULL),
+ dom_handler_(new devtools::dom::DOMHandler()),
+ input_handler_(new devtools::input::InputHandler()),
+ inspector_handler_(new devtools::inspector::InspectorHandler()),
+ network_handler_(new devtools::network::NetworkHandler()),
+ page_handler_(nullptr),
+ power_handler_(new devtools::power::PowerHandler()),
+ service_worker_handler_(
+ new devtools::service_worker::ServiceWorkerHandler()),
+ tracing_handler_(new devtools::tracing::TracingHandler(
+ devtools::tracing::TracingHandler::Renderer)),
+ emulation_handler_(nullptr),
+ frame_trace_recorder_(nullptr),
+ reattaching_(false) {
+ DevToolsProtocolDispatcher* dispatcher = protocol_handler_->dispatcher();
+ dispatcher->SetDOMHandler(dom_handler_.get());
+ dispatcher->SetInputHandler(input_handler_.get());
+ dispatcher->SetInspectorHandler(inspector_handler_.get());
+ dispatcher->SetNetworkHandler(network_handler_.get());
+ dispatcher->SetPowerHandler(power_handler_.get());
+ dispatcher->SetServiceWorkerHandler(service_worker_handler_.get());
+ dispatcher->SetTracingHandler(tracing_handler_.get());
+
+ if (!rfh->GetParent()) {
+ page_handler_.reset(new devtools::page::PageHandler());
+ emulation_handler_.reset(
+ new devtools::emulation::EmulationHandler(page_handler_.get()));
+ dispatcher->SetPageHandler(page_handler_.get());
+ dispatcher->SetEmulationHandler(emulation_handler_.get());
+ }
+
+ SetRenderFrameHost(rfh);
+ g_instances.Get().push_back(this);
+ AddRef(); // Balanced in RenderFrameHostDestroyed.
+}
+
+BrowserContext* RenderFrameDevToolsAgentHost::GetBrowserContext() {
+ WebContents* contents = web_contents();
+ return contents ? contents->GetBrowserContext() : nullptr;
+}
+
+WebContents* RenderFrameDevToolsAgentHost::GetWebContents() {
+ return web_contents();
+}
+
+void RenderFrameDevToolsAgentHost::SendMessageToAgent(IPC::Message* msg) {
+ if (!render_frame_host_)
+ return;
+ msg->set_routing_id(render_frame_host_->GetRoutingID());
+ render_frame_host_->Send(msg);
+}
+
+void RenderFrameDevToolsAgentHost::OnClientAttached(bool reattached) {
+ if (!render_frame_host_)
+ return;
+
+ InnerOnClientAttached();
+
+ // TODO(kaznacheev): Move this call back to DevToolsManager when
+ // extensions::ProcessManager no longer relies on this notification.
+ if (!reattaching_)
+ DevToolsAgentHostImpl::NotifyCallbacks(this, true);
+}
+
+void RenderFrameDevToolsAgentHost::InnerOnClientAttached() {
+ ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadRawCookies(
+ render_frame_host_->GetProcess()->GetID());
+
+#if defined(OS_ANDROID)
+ power_save_blocker_.reset(static_cast<PowerSaveBlockerImpl*>(
+ PowerSaveBlocker::Create(
+ PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
+ PowerSaveBlocker::kReasonOther, "DevTools").release()));
+ power_save_blocker_->InitDisplaySleepBlocker(
+ WebContents::FromRenderFrameHost(render_frame_host_));
+#endif
+
+ frame_trace_recorder_.reset(new DevToolsFrameTraceRecorder());
+}
+
+void RenderFrameDevToolsAgentHost::OnClientDetached() {
+#if defined(OS_ANDROID)
+ power_save_blocker_.reset();
+#endif
+ if (emulation_handler_)
+ emulation_handler_->Detached();
+ if (page_handler_)
+ page_handler_->Detached();
+ power_handler_->Detached();
+ service_worker_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 RenderFrameDevToolsAgentHost::ClientDetachedFromRenderer() {
+ if (!render_frame_host_)
+ return;
+
+ InnerClientDetachedFromRenderer();
+}
+
+void RenderFrameDevToolsAgentHost::InnerClientDetachedFromRenderer() {
+ bool process_has_agents = false;
+ RenderProcessHost* render_process_host = render_frame_host_->GetProcess();
+ for (Instances::iterator it = g_instances.Get().begin();
+ it != g_instances.Get().end(); ++it) {
+ if (*it == this || !(*it)->IsAttached())
+ continue;
+ RenderFrameHost* rfh = (*it)->render_frame_host_;
+ if (rfh && rfh->GetProcess() == render_process_host)
+ process_has_agents = true;
+ }
+
+ // We are the last to disconnect from the renderer -> revoke permissions.
+ if (!process_has_agents) {
+ ChildProcessSecurityPolicyImpl::GetInstance()->RevokeReadRawCookies(
+ render_process_host->GetID());
+ }
+ frame_trace_recorder_.reset();
+}
+
+RenderFrameDevToolsAgentHost::~RenderFrameDevToolsAgentHost() {
+ Instances::iterator it = std::find(g_instances.Get().begin(),
+ g_instances.Get().end(),
+ this);
+ if (it != g_instances.Get().end())
+ g_instances.Get().erase(it);
+}
+
+// TODO(creis): Consider removing this in favor of RenderFrameHostChanged.
+void RenderFrameDevToolsAgentHost::AboutToNavigateRenderFrame(
+ RenderFrameHost* old_host,
+ RenderFrameHost* new_host) {
+ if (render_frame_host_ != old_host)
+ return;
+
+ // TODO(creis): This will need to be updated for --site-per-process, since
+ // RenderViewHost is going away and navigations could happen in any frame.
+ if (render_frame_host_ == new_host) {
+ RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
+ render_frame_host_->GetRenderViewHost());
+ if (rvh->render_view_termination_status() ==
+ base::TERMINATION_STATUS_STILL_RUNNING)
+ return;
+ }
+ ReattachToRenderFrameHost(new_host);
+}
+
+void RenderFrameDevToolsAgentHost::RenderFrameHostChanged(
+ RenderFrameHost* old_host,
+ RenderFrameHost* new_host) {
+ if (old_host == render_frame_host_ && new_host != render_frame_host_) {
+ // AboutToNavigateRenderFrame was not called for renderer-initiated
+ // navigation.
+ ReattachToRenderFrameHost(new_host);
+ }
+}
+
+void
+RenderFrameDevToolsAgentHost::ReattachToRenderFrameHost(RenderFrameHost* rfh) {
+ if (!ShouldCreateDevToolsFor(rfh)) {
+ DestroyOnRenderFrameGone();
+ // |this| may be deleted at this point.
+ return;
+ }
+
+ DCHECK(!reattaching_);
+ reattaching_ = true;
+ DisconnectRenderFrameHost();
+ ConnectRenderFrameHost(rfh);
+ reattaching_ = false;
+}
+
+void RenderFrameDevToolsAgentHost::FrameDeleted(RenderFrameHost* rfh) {
+ if (rfh != render_frame_host_)
+ return;
+ DestroyOnRenderFrameGone();
+ // |this| may be deleted at this point.
+}
+
+void RenderFrameDevToolsAgentHost::DestroyOnRenderFrameGone() {
+ DCHECK(render_frame_host_);
+ scoped_refptr<RenderFrameDevToolsAgentHost> protect(this);
+ if (IsAttached())
+ OnClientDetached();
+ HostClosed();
+ ClearRenderFrameHost();
+ Release();
+}
+
+void RenderFrameDevToolsAgentHost::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:
+#if defined(OS_ANDROID)
+ case base::TERMINATION_STATUS_OOM_PROTECTED:
+#endif
+ RenderFrameCrashed();
+ break;
+ default:
+ break;
+ }
+}
+
+bool RenderFrameDevToolsAgentHost::OnMessageReceived(
+ const IPC::Message& message) {
+ if (!render_frame_host_)
+ return false;
+ if (message.type() == ViewHostMsg_SwapCompositorFrame::ID)
+ OnSwapCompositorFrame(message);
+ return false;
+}
+
+bool RenderFrameDevToolsAgentHost::OnMessageReceived(
+ const IPC::Message& message,
+ RenderFrameHost* render_frame_host) {
+ if (!render_frame_host_ || render_frame_host != render_frame_host_)
+ return false;
+
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(RenderFrameDevToolsAgentHost, message)
+ IPC_MESSAGE_HANDLER(DevToolsClientMsg_DispatchOnInspectorFrontend,
+ OnDispatchOnInspectorFrontend)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void RenderFrameDevToolsAgentHost::DidAttachInterstitialPage() {
+ if (page_handler_)
+ page_handler_->DidAttachInterstitialPage();
+
+ if (!render_frame_host_)
+ return;
+ // The rvh set in AboutToNavigateRenderFrame turned out to be interstitial.
+ // Connect back to the real one.
+ WebContents* web_contents =
+ WebContents::FromRenderFrameHost(render_frame_host_);
+ if (!web_contents)
+ return;
+ DisconnectRenderFrameHost();
+ ConnectRenderFrameHost(web_contents->GetMainFrame());
+}
+
+void RenderFrameDevToolsAgentHost::DidDetachInterstitialPage() {
+ if (page_handler_)
+ page_handler_->DidDetachInterstitialPage();
+}
+
+void RenderFrameDevToolsAgentHost::DidCommitProvisionalLoadForFrame(
+ RenderFrameHost* render_frame_host,
+ const GURL& url,
+ ui::PageTransition transition_type) {
+ service_worker_handler_->UpdateHosts();
+}
+
+void RenderFrameDevToolsAgentHost::SetRenderFrameHost(RenderFrameHost* rfh) {
+ DCHECK(ShouldCreateDevToolsFor(rfh));
+ DCHECK(!render_frame_host_);
+ render_frame_host_ = static_cast<RenderFrameHostImpl*>(rfh);
+ DCHECK(render_frame_host_);
+
+ WebContentsObserver::Observe(WebContents::FromRenderFrameHost(rfh));
+ dom_handler_->SetRenderFrameHost(render_frame_host_);
+ input_handler_->SetRenderWidgetHost(
+ render_frame_host_->GetRenderWidgetHost());
+ network_handler_->SetRenderFrameHost(render_frame_host_);
+ service_worker_handler_->SetRenderFrameHost(render_frame_host_);
+
+ if (emulation_handler_)
+ emulation_handler_->SetRenderFrameHost(render_frame_host_);
+ if (page_handler_)
+ page_handler_->SetRenderFrameHost(render_frame_host_);
+}
+
+void RenderFrameDevToolsAgentHost::ClearRenderFrameHost() {
+ DCHECK(render_frame_host_);
+ render_frame_host_ = nullptr;
+ dom_handler_->SetRenderFrameHost(nullptr);
+ if (emulation_handler_)
+ emulation_handler_->SetRenderFrameHost(nullptr);
+ input_handler_->SetRenderWidgetHost(nullptr);
+ network_handler_->SetRenderFrameHost(nullptr);
+ if (page_handler_)
+ page_handler_->SetRenderFrameHost(nullptr);
+ service_worker_handler_->SetRenderFrameHost(nullptr);
+}
+
+void RenderFrameDevToolsAgentHost::DisconnectWebContents() {
+ DisconnectRenderFrameHost();
+}
+
+void RenderFrameDevToolsAgentHost::ConnectWebContents(WebContents* wc) {
+ ConnectRenderFrameHost(wc->GetMainFrame());
+}
+
+DevToolsAgentHost::Type RenderFrameDevToolsAgentHost::GetType() {
+ return IsChildFrame() ? TYPE_FRAME : TYPE_WEB_CONTENTS;
+}
+
+std::string RenderFrameDevToolsAgentHost::GetTitle() {
+ if (IsChildFrame())
+ return GetURL().spec();
+ if (WebContents* web_contents = GetWebContents())
+ return base::UTF16ToUTF8(web_contents->GetTitle());
+ return "";
+}
+
+GURL RenderFrameDevToolsAgentHost::GetURL() {
+ WebContents* web_contents = GetWebContents();
+ if (web_contents && !IsChildFrame())
+ return web_contents->GetVisibleURL();
+ return render_frame_host_ ?
+ render_frame_host_->GetLastCommittedURL() : GURL();
+}
+
+bool RenderFrameDevToolsAgentHost::Activate() {
+ if (render_frame_host_) {
+ render_frame_host_->GetRenderViewHost()->GetDelegate()->Activate();
+ return true;
+ }
+ return false;
+}
+
+bool RenderFrameDevToolsAgentHost::Close() {
+ if (web_contents()) {
+ web_contents()->ClosePage();
+ return true;
+ }
+ return false;
+}
+
+void RenderFrameDevToolsAgentHost::ConnectRenderFrameHost(
+ RenderFrameHost* rfh) {
+ SetRenderFrameHost(rfh);
+ if (IsAttached())
+ Reattach();
+}
+
+void RenderFrameDevToolsAgentHost::DisconnectRenderFrameHost() {
+ ClientDetachedFromRenderer();
+ ClearRenderFrameHost();
+}
+
+void RenderFrameDevToolsAgentHost::RenderFrameCrashed() {
+ inspector_handler_->TargetCrashed();
+}
+
+void RenderFrameDevToolsAgentHost::OnSwapCompositorFrame(
+ const IPC::Message& message) {
+ ViewHostMsg_SwapCompositorFrame::Param param;
+ if (!ViewHostMsg_SwapCompositorFrame::Read(&message, &param))
+ return;
+ if (page_handler_)
+ page_handler_->OnSwapCompositorFrame(get<1>(param).metadata);
+ if (input_handler_)
+ input_handler_->OnSwapCompositorFrame(get<1>(param).metadata);
+ if (frame_trace_recorder_) {
+ frame_trace_recorder_->OnSwapCompositorFrame(
+ render_frame_host_, get<1>(param).metadata);
+ }
+}
+
+void RenderFrameDevToolsAgentHost::SynchronousSwapCompositorFrame(
+ const cc::CompositorFrameMetadata& frame_metadata) {
+ if (!render_frame_host_)
+ return;
+ if (page_handler_)
+ page_handler_->OnSwapCompositorFrame(frame_metadata);
+ if (input_handler_)
+ input_handler_->OnSwapCompositorFrame(frame_metadata);
+ if (frame_trace_recorder_) {
+ frame_trace_recorder_->OnSwapCompositorFrame(
+ render_frame_host_, frame_metadata);
+ }
+}
+
+bool RenderFrameDevToolsAgentHost::HasRenderFrameHost(
+ RenderFrameHost* host) {
+ return host == render_frame_host_;
+}
+
+void RenderFrameDevToolsAgentHost::OnDispatchOnInspectorFrontend(
+ const DevToolsMessageChunk& message) {
+ if (!IsAttached() || !render_frame_host_)
+ return;
+ ProcessChunkedMessageFromAgent(message);
+}
+
+bool RenderFrameDevToolsAgentHost::IsChildFrame() {
+ return render_frame_host_ && render_frame_host_->GetParent();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/devtools/render_frame_devtools_agent_host.h b/chromium/content/browser/devtools/render_frame_devtools_agent_host.h
new file mode 100644
index 00000000000..a77cdbe2063
--- /dev/null
+++ b/chromium/content/browser/devtools/render_frame_devtools_agent_host.h
@@ -0,0 +1,144 @@
+// 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_RENDER_FRAME_DEVTOOLS_AGENT_HOST_H_
+#define CONTENT_BROWSER_DEVTOOLS_RENDER_FRAME_DEVTOOLS_AGENT_HOST_H_
+
+#include <map>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/browser/devtools/ipc_devtools_agent_host.h"
+#include "content/common/content_export.h"
+#include "content/public/browser/web_contents_observer.h"
+
+namespace cc {
+class CompositorFrameMetadata;
+}
+
+namespace content {
+
+class BrowserContext;
+class DevToolsFrameTraceRecorder;
+class RenderFrameHost;
+class RenderFrameHostImpl;
+
+#if defined(OS_ANDROID)
+class PowerSaveBlockerImpl;
+#endif
+
+namespace devtools {
+namespace dom { class DOMHandler; }
+namespace emulation { class EmulationHandler; }
+namespace input { class InputHandler; }
+namespace inspector { class InspectorHandler; }
+namespace network { class NetworkHandler; }
+namespace page { class PageHandler; }
+namespace power { class PowerHandler; }
+namespace service_worker { class ServiceWorkerHandler; }
+namespace tracing { class TracingHandler; }
+}
+
+class CONTENT_EXPORT RenderFrameDevToolsAgentHost
+ : public IPCDevToolsAgentHost,
+ private WebContentsObserver {
+ public:
+ static void AddAllAgentHosts(DevToolsAgentHost::List* result);
+
+ static void OnCancelPendingNavigation(RenderFrameHost* pending,
+ RenderFrameHost* current);
+
+ void SynchronousSwapCompositorFrame(
+ const cc::CompositorFrameMetadata& frame_metadata);
+
+ bool HasRenderFrameHost(RenderFrameHost* host);
+
+ // DevTooolsAgentHost overrides.
+ void DisconnectWebContents() override;
+ void ConnectWebContents(WebContents* web_contents) override;
+ BrowserContext* GetBrowserContext() override;
+ WebContents* GetWebContents() override;
+ Type GetType() override;
+ std::string GetTitle() override;
+ GURL GetURL() override;
+ bool Activate() override;
+ bool Close() override;
+
+ private:
+ friend class DevToolsAgentHost;
+ explicit RenderFrameDevToolsAgentHost(RenderFrameHost*);
+ ~RenderFrameDevToolsAgentHost() override;
+
+ static scoped_refptr<DevToolsAgentHost> GetOrCreateFor(RenderFrameHost* host);
+ static void AppendAgentHostForFrameIfApplicable(
+ DevToolsAgentHost::List* result,
+ RenderFrameHost* host);
+
+ // IPCDevToolsAgentHost overrides.
+ void SendMessageToAgent(IPC::Message* msg) override;
+ void OnClientAttached(bool reattached) override;
+ void OnClientDetached() override;
+
+ // WebContentsObserver overrides.
+ void AboutToNavigateRenderFrame(RenderFrameHost* old_host,
+ RenderFrameHost* new_host) override;
+ void RenderFrameHostChanged(RenderFrameHost* old_host,
+ RenderFrameHost* new_host) override;
+ void FrameDeleted(RenderFrameHost* rfh) 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 DidCommitProvisionalLoadForFrame(
+ RenderFrameHost* render_frame_host,
+ const GURL& url,
+ ui::PageTransition transition_type) override;
+
+ void DisconnectRenderFrameHost();
+ void ConnectRenderFrameHost(RenderFrameHost* rvh);
+ void ReattachToRenderFrameHost(RenderFrameHost* rvh);
+
+ void SetRenderFrameHost(RenderFrameHost* rvh);
+ void ClearRenderFrameHost();
+
+ void RenderFrameCrashed();
+ void OnSwapCompositorFrame(const IPC::Message& message);
+ bool OnSetTouchEventEmulationEnabled(const IPC::Message& message);
+
+ void OnDispatchOnInspectorFrontend(const DevToolsMessageChunk& message);
+
+ void ClientDetachedFromRenderer();
+
+ void InnerOnClientAttached();
+ void InnerClientDetachedFromRenderer();
+
+ bool IsChildFrame();
+ void DestroyOnRenderFrameGone();
+
+ RenderFrameHostImpl* render_frame_host_;
+ scoped_ptr<devtools::dom::DOMHandler> dom_handler_;
+ scoped_ptr<devtools::input::InputHandler> input_handler_;
+ scoped_ptr<devtools::inspector::InspectorHandler> inspector_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::service_worker::ServiceWorkerHandler>
+ service_worker_handler_;
+ scoped_ptr<devtools::tracing::TracingHandler> tracing_handler_;
+ scoped_ptr<devtools::emulation::EmulationHandler> emulation_handler_;
+ scoped_ptr<DevToolsFrameTraceRecorder> frame_trace_recorder_;
+#if defined(OS_ANDROID)
+ scoped_ptr<PowerSaveBlockerImpl> power_save_blocker_;
+#endif
+ bool reattaching_;
+
+ DISALLOW_COPY_AND_ASSIGN(RenderFrameDevToolsAgentHost);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_DEVTOOLS_RENDER_FRAME_DEVTOOLS_AGENT_HOST_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
deleted file mode 100644
index 5115ba21e45..00000000000
--- a/chromium/content/browser/devtools/render_view_devtools_agent_host.cc
+++ /dev/null
@@ -1,514 +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/render_view_devtools_agent_host.h"
-
-#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.h"
-#include "content/browser/devtools/devtools_protocol.h"
-#include "content/browser/devtools/devtools_protocol_constants.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"
-#include "content/browser/web_contents/web_contents_impl.h"
-#include "content/common/devtools_messages.h"
-#include "content/common/view_messages.h"
-#include "content/public/browser/content_browser_client.h"
-#include "content/public/browser/devtools_manager_delegate.h"
-#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"
-#include "content/public/browser/render_widget_host_view.h"
-#endif
-
-namespace content {
-
-typedef std::vector<RenderViewDevToolsAgentHost*> Instances;
-
-namespace {
-base::LazyInstance<Instances>::Leaky g_instances = LAZY_INSTANCE_INITIALIZER;
-
-//Returns RenderViewDevToolsAgentHost attached to any of RenderViewHost
-//instances associated with |web_contents|
-static RenderViewDevToolsAgentHost* FindAgentHost(WebContents* web_contents) {
- if (g_instances == NULL)
- return NULL;
- for (Instances::iterator it = g_instances.Get().begin();
- it != g_instances.Get().end(); ++it) {
- if ((*it)->GetWebContents() == web_contents)
- return *it;
- }
- return NULL;
-}
-
-} // namespace
-
-scoped_refptr<DevToolsAgentHost>
-DevToolsAgentHost::GetOrCreateFor(WebContents* web_contents) {
- RenderViewDevToolsAgentHost* result = FindAgentHost(web_contents);
- if (!result)
- result = new RenderViewDevToolsAgentHost(web_contents->GetRenderViewHost());
- return result;
-}
-
-// static
-bool DevToolsAgentHost::HasFor(WebContents* web_contents) {
- return FindAgentHost(web_contents) != NULL;
-}
-
-// static
-bool DevToolsAgentHost::IsDebuggerAttached(WebContents* web_contents) {
- RenderViewDevToolsAgentHost* agent_host = FindAgentHost(web_contents);
- return agent_host && agent_host->IsAttached();
-}
-
-//static
-std::vector<WebContents*> DevToolsAgentHostImpl::GetInspectableWebContents() {
- std::set<WebContents*> set;
- scoped_ptr<RenderWidgetHostIterator> widgets(
- RenderWidgetHost::GetRenderWidgetHosts());
- while (RenderWidgetHost* widget = widgets->GetNextHost()) {
- // Ignore processes that don't have a connection, such as crashed contents.
- if (!widget->GetProcess()->HasConnection())
- continue;
- if (!widget->IsRenderView())
- continue;
-
- RenderViewHost* rvh = RenderViewHost::From(widget);
- WebContents* web_contents = WebContents::FromRenderViewHost(rvh);
- if (web_contents)
- set.insert(web_contents);
- }
- std::vector<WebContents*> result(set.size());
- std::copy(set.begin(), set.end(), result.begin());
- return result;
-}
-
-// static
-void RenderViewDevToolsAgentHost::OnCancelPendingNavigation(
- RenderViewHost* pending,
- RenderViewHost* current) {
- WebContents* web_contents = WebContents::FromRenderViewHost(pending);
- RenderViewDevToolsAgentHost* agent_host = FindAgentHost(web_contents);
- if (!agent_host)
- return;
- agent_host->DisconnectRenderViewHost();
- agent_host->ConnectRenderViewHost(current);
-}
-
-RenderViewDevToolsAgentHost::RenderViewDevToolsAgentHost(RenderViewHost* rvh)
- : render_view_host_(NULL),
- 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::DispatchOnInspectorFrontend,
- base::Unretained(this)));
- handler_impl_->SetNotifier(notifier);
- g_instances.Get().push_back(this);
- AddRef(); // Balanced in RenderViewHostDestroyed.
- DevToolsManager::GetInstance()->AgentHostChanged(this);
-}
-
-WebContents* RenderViewDevToolsAgentHost::GetWebContents() {
- return web_contents();
-}
-
-void RenderViewDevToolsAgentHost::DispatchProtocolMessage(
- const std::string& message) {
- std::string error_message;
-
- scoped_ptr<base::DictionaryValue> message_dict(
- DevToolsProtocol::ParseMessage(message, &error_message));
- scoped_refptr<DevToolsProtocol::Command> command =
- DevToolsProtocol::ParseCommand(message_dict.get(), &error_message);
-
- if (command.get()) {
- scoped_refptr<DevToolsProtocol::Response> overridden_response;
-
- DevToolsManagerDelegate* delegate =
- DevToolsManager::GetInstance()->delegate();
- if (delegate) {
- scoped_ptr<base::DictionaryValue> overridden_response_value(
- delegate->HandleCommand(this, message_dict.get()));
- if (overridden_response_value)
- overridden_response = DevToolsProtocol::ParseResponse(
- overridden_response_value.get());
- }
- if (!overridden_response.get())
- overridden_response = handler_impl_->HandleCommand(command);
- if (overridden_response.get()) {
- if (!overridden_response->is_async_promise())
- DispatchOnInspectorFrontend(overridden_response->Serialize());
- return;
- }
- }
-
- IPCDevToolsAgentHost::DispatchProtocolMessage(message);
-}
-
-void RenderViewDevToolsAgentHost::SendMessageToAgent(IPC::Message* msg) {
- if (!render_view_host_)
- return;
- msg->set_routing_id(render_view_host_->GetRoutingID());
- render_view_host_->Send(msg);
-}
-
-void RenderViewDevToolsAgentHost::OnClientAttached() {
- if (!render_view_host_)
- return;
-
- InnerOnClientAttached();
-
- // TODO(kaznacheev): Move this call back to DevToolsManager when
- // extensions::ProcessManager no longer relies on this notification.
- if (!reattaching_)
- DevToolsAgentHostImpl::NotifyCallbacks(this, true);
-}
-
-void RenderViewDevToolsAgentHost::InnerOnClientAttached() {
- ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadRawCookies(
- render_view_host_->GetProcess()->GetID());
-
-#if defined(OS_ANDROID)
- power_save_blocker_.reset(
- static_cast<PowerSaveBlockerImpl*>(
- PowerSaveBlocker::Create(
- PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
- "DevTools").release()));
- if (render_view_host_->GetView()) {
- power_save_blocker_.get()->
- InitDisplaySleepBlocker(render_view_host_->GetView()->GetNativeView());
- }
-#endif
-}
-
-void RenderViewDevToolsAgentHost::OnClientDetached() {
-#if defined(OS_ANDROID)
- power_save_blocker_.reset();
-#endif
- 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() {
- if (!render_view_host_)
- return;
-
- InnerClientDetachedFromRenderer();
-}
-
-void RenderViewDevToolsAgentHost::InnerClientDetachedFromRenderer() {
- bool process_has_agents = false;
- RenderProcessHost* render_process_host = render_view_host_->GetProcess();
- for (Instances::iterator it = g_instances.Get().begin();
- it != g_instances.Get().end(); ++it) {
- if (*it == this || !(*it)->IsAttached())
- continue;
- RenderViewHost* rvh = (*it)->render_view_host_;
- if (rvh && rvh->GetProcess() == render_process_host)
- process_has_agents = true;
- }
-
- // We are the last to disconnect from the renderer -> revoke permissions.
- if (!process_has_agents) {
- ChildProcessSecurityPolicyImpl::GetInstance()->RevokeReadRawCookies(
- render_process_host->GetID());
- }
-}
-
-RenderViewDevToolsAgentHost::~RenderViewDevToolsAgentHost() {
- Instances::iterator it = std::find(g_instances.Get().begin(),
- g_instances.Get().end(),
- this);
- if (it != g_instances.Get().end())
- g_instances.Get().erase(it);
-}
-
-void RenderViewDevToolsAgentHost::AboutToNavigateRenderView(
- RenderViewHost* dest_rvh) {
- if (!render_view_host_)
- return;
-
- if (render_view_host_ == dest_rvh &&
- render_view_host_->render_view_termination_status() ==
- base::TERMINATION_STATUS_STILL_RUNNING)
- return;
- ReattachToRenderViewHost(dest_rvh);
-}
-
-void RenderViewDevToolsAgentHost::RenderViewHostChanged(
- RenderViewHost* old_host,
- RenderViewHost* new_host) {
- if (new_host != render_view_host_) {
- // AboutToNavigateRenderView was not called for renderer-initiated
- // navigation.
- ReattachToRenderViewHost(new_host);
- }
-}
-
-void
-RenderViewDevToolsAgentHost::ReattachToRenderViewHost(RenderViewHost* rvh) {
- DCHECK(!reattaching_);
- reattaching_ = true;
- DisconnectRenderViewHost();
- ConnectRenderViewHost(rvh);
- reattaching_ = false;
-}
-
-void RenderViewDevToolsAgentHost::RenderViewDeleted(RenderViewHost* rvh) {
- if (rvh != render_view_host_)
- return;
-
- DCHECK(render_view_host_);
- scoped_refptr<RenderViewDevToolsAgentHost> protect(this);
- HostClosed();
- ClearRenderViewHost();
- DevToolsManager::GetInstance()->AgentHostChanged(this);
- Release();
-}
-
-void RenderViewDevToolsAgentHost::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:
-#if defined(OS_ANDROID)
- case base::TERMINATION_STATUS_OOM_PROTECTED:
-#endif
- RenderViewCrashed();
- break;
- default:
- break;
- }
-}
-
-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.
- // Connect back to the real one.
- WebContents* web_contents =
- WebContents::FromRenderViewHost(render_view_host_);
- if (!web_contents)
- return;
- DisconnectRenderViewHost();
- 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();
- page_handler_->OnVisibilityChanged(visible);
- }
-}
-
-void RenderViewDevToolsAgentHost::SetRenderViewHost(RenderViewHost* rvh) {
- DCHECK(!render_view_host_);
- 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,
- content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
- content::Source<RenderWidgetHost>(render_view_host_));
-}
-
-void RenderViewDevToolsAgentHost::ClearRenderViewHost() {
- DCHECK(render_view_host_);
- registrar_.Remove(
- this,
- content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
- content::Source<RenderWidgetHost>(render_view_host_));
- 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) {
- SetRenderViewHost(rvh);
- if (IsAttached())
- Reattach(state_);
-}
-
-void RenderViewDevToolsAgentHost::DisconnectRenderViewHost() {
- ClientDetachedFromRenderer();
- ClearRenderViewHost();
-}
-
-void RenderViewDevToolsAgentHost::RenderViewCrashed() {
- scoped_refptr<DevToolsProtocol::Notification> notification =
- DevToolsProtocol::CreateNotification(
- devtools::Inspector::targetCrashed::kName, NULL);
- SendMessageToClient(notification->Serialize());
-}
-
-bool RenderViewDevToolsAgentHost::DispatchIPCMessage(
- const IPC::Message& msg) {
- if (!render_view_host_)
- return false;
-
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(RenderViewDevToolsAgentHost, msg)
- IPC_MESSAGE_HANDLER(DevToolsClientMsg_DispatchOnInspectorFrontend,
- OnDispatchOnInspectorFrontend)
- IPC_MESSAGE_HANDLER(DevToolsHostMsg_SaveAgentRuntimeState,
- OnSaveAgentRuntimeState)
- IPC_MESSAGE_HANDLER_GENERIC(ViewHostMsg_SwapCompositorFrame,
- handled = false; OnSwapCompositorFrame(msg))
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-void RenderViewDevToolsAgentHost::OnSwapCompositorFrame(
- const IPC::Message& message) {
- ViewHostMsg_SwapCompositorFrame::Param param;
- if (!ViewHostMsg_SwapCompositorFrame::Read(&message, &param))
- return;
- page_handler_->OnSwapCompositorFrame(param.b.metadata);
-}
-
-void RenderViewDevToolsAgentHost::SynchronousSwapCompositorFrame(
- const cc::CompositorFrameMetadata& frame_metadata) {
- if (!render_view_host_)
- return;
- page_handler_->OnSwapCompositorFrame(frame_metadata);
-}
-
-void RenderViewDevToolsAgentHost::OnSaveAgentRuntimeState(
- const std::string& state) {
- if (!render_view_host_)
- return;
- state_ = state;
-}
-
-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 (!IsAttached() || !render_view_host_)
- return;
- 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
deleted file mode 100644
index 204d87e8544..00000000000
--- a/chromium/content/browser/devtools/render_view_devtools_agent_host.h
+++ /dev/null
@@ -1,138 +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_RENDER_VIEW_DEVTOOLS_AGENT_HOST_H_
-#define CONTENT_BROWSER_DEVTOOLS_RENDER_VIEW_DEVTOOLS_AGENT_HOST_H_
-
-#include <map>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
-#include "content/browser/devtools/ipc_devtools_agent_host.h"
-#include "content/common/content_export.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
-#include "content/public/browser/web_contents_observer.h"
-
-namespace cc {
-class CompositorFrameMetadata;
-}
-
-namespace content {
-
-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,
- public NotificationObserver {
- public:
- static void OnCancelPendingNavigation(RenderViewHost* pending,
- RenderViewHost* current);
-
- RenderViewDevToolsAgentHost(RenderViewHost*);
-
- 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;
- ~RenderViewDevToolsAgentHost() override;
-
- // IPCDevToolsAgentHost overrides.
- void DispatchProtocolMessage(const std::string& message) override;
- void SendMessageToAgent(IPC::Message* msg) override;
- void OnClientAttached() override;
- void OnClientDetached() override;
-
- // WebContentsObserver overrides.
- 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:
- 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);
-
- void SetRenderViewHost(RenderViewHost* rvh);
- void ClearRenderViewHost();
-
- void RenderViewCrashed();
- void OnSwapCompositorFrame(const IPC::Message& message);
- bool OnSetTouchEventEmulationEnabled(const IPC::Message& message);
-
- void OnDispatchOnInspectorFrontend(const std::string& message,
- uint32 total_size);
- void DispatchOnInspectorFrontend(const std::string& message);
- void OnSaveAgentRuntimeState(const std::string& state);
-
- void ClientDetachedFromRenderer();
-
- void InnerOnClientAttached();
- void InnerClientDetachedFromRenderer();
-
- 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
- std::string state_;
- NotificationRegistrar registrar_;
- bool reattaching_;
-
- DISALLOW_COPY_AND_ASSIGN(RenderViewDevToolsAgentHost);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_DEVTOOLS_RENDER_VIEW_DEVTOOLS_AGENT_HOST_H_
diff --git a/chromium/content/browser/devtools/renderer_overrides_handler_browsertest.cc b/chromium/content/browser/devtools/renderer_overrides_handler_browsertest.cc
deleted file mode 100644
index fd02c091234..00000000000
--- a/chromium/content/browser/devtools/renderer_overrides_handler_browsertest.cc
+++ /dev/null
@@ -1,137 +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/base64.h"
-#include "base/command_line.h"
-#include "base/json/json_reader.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/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,
- public DevToolsAgentHostClient {
- protected:
- void SendCommand(const std::string& method,
- base::DictionaryValue* params) {
- agent_host_->DispatchProtocolMessage(
- DevToolsProtocol::CreateCommand(1, method, params)->Serialize());
- base::MessageLoop::current()->Run();
- }
-
- bool HasValue(const std::string& path) {
- base::Value* value = 0;
- return result_->Get(path, &value);
- }
-
- bool HasListItem(const std::string& path_to_list,
- const std::string& name,
- const std::string& value) {
- base::ListValue* list;
- if (!result_->GetList(path_to_list, &list))
- return false;
-
- for (size_t i = 0; i != list->GetSize(); i++) {
- base::DictionaryValue* item;
- if (!list->GetDictionary(i, &item))
- return false;
- std::string id;
- if (!item->GetString(name, &id))
- return false;
- if (id == value)
- return true;
- }
- return false;
- }
-
- scoped_ptr<base::DictionaryValue> result_;
- scoped_refptr<DevToolsAgentHost> agent_host_;
-
- private:
- void SetUpOnMainThread() override {
- agent_host_ = DevToolsAgentHost::GetOrCreateFor(shell()->web_contents());
- agent_host_->AttachClient(this);
- }
-
- void TearDownOnMainThread() override {
- agent_host_->DetachClient();
- agent_host_ = NULL;
- }
-
- 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;
- 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");
- SendCommand("Page.queryUsageAndQuota", params);
-
- EXPECT_TRUE(HasValue("quota.persistent"));
- EXPECT_TRUE(HasValue("quota.temporary"));
- EXPECT_TRUE(HasListItem("usage.temporary", "id", "appcache"));
- EXPECT_TRUE(HasListItem("usage.temporary", "id", "database"));
- EXPECT_TRUE(HasListItem("usage.temporary", "id", "indexeddatabase"));
- EXPECT_TRUE(HasListItem("usage.temporary", "id", "filesystem"));
- 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/service_worker_devtools_agent_host.cc b/chromium/content/browser/devtools/service_worker_devtools_agent_host.cc
new file mode 100644
index 00000000000..5a36ba17ce8
--- /dev/null
+++ b/chromium/content/browser/devtools/service_worker_devtools_agent_host.cc
@@ -0,0 +1,123 @@
+// Copyright 2014 The Chromium Authors. 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/service_worker_devtools_agent_host.h"
+
+#include "base/strings/stringprintf.h"
+#include "content/browser/devtools/service_worker_devtools_manager.h"
+#include "content/browser/service_worker/service_worker_context_core.h"
+#include "content/browser/service_worker/service_worker_version.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_process_host.h"
+
+namespace content {
+
+namespace {
+
+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));
+ }
+}
+
+void UnregisterServiceWorkerOnIO(
+ 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));
+ context->UnregisterServiceWorker(
+ version->scope(), base::Bind(&StatusNoOp));
+ }
+ }
+}
+
+void SetDevToolsAttachedOnIO(
+ base::WeakPtr<ServiceWorkerContextCore> context_weak,
+ int64 version_id,
+ bool attached) {
+ if (ServiceWorkerContextCore* context = context_weak.get()) {
+ if (ServiceWorkerVersion* version = context->GetLiveVersion(version_id))
+ version->SetDevToolsAttached(attached);
+ }
+}
+
+} // namespace
+
+ServiceWorkerDevToolsAgentHost::ServiceWorkerDevToolsAgentHost(
+ WorkerId worker_id,
+ const ServiceWorkerIdentifier& service_worker)
+ : WorkerDevToolsAgentHost(worker_id),
+ service_worker_(new ServiceWorkerIdentifier(service_worker)) {
+}
+
+DevToolsAgentHost::Type ServiceWorkerDevToolsAgentHost::GetType() {
+ return TYPE_SERVICE_WORKER;
+}
+
+std::string ServiceWorkerDevToolsAgentHost::GetTitle() {
+ if (RenderProcessHost* host = RenderProcessHost::FromID(worker_id().first)) {
+ return base::StringPrintf("Worker pid:%d",
+ base::GetProcId(host->GetHandle()));
+ }
+ return "";
+}
+
+GURL ServiceWorkerDevToolsAgentHost::GetURL() {
+ return service_worker_->url();
+}
+
+bool ServiceWorkerDevToolsAgentHost::Activate() {
+ return false;
+}
+
+bool ServiceWorkerDevToolsAgentHost::Close() {
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(&TerminateServiceWorkerOnIO,
+ service_worker_->context_weak(),
+ service_worker_->version_id()));
+ return true;
+}
+
+void ServiceWorkerDevToolsAgentHost::UnregisterWorker() {
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(&UnregisterServiceWorkerOnIO,
+ service_worker_->context_weak(),
+ service_worker_->version_id()));
+}
+
+void ServiceWorkerDevToolsAgentHost::OnClientAttached(bool reattached) {
+ WorkerDevToolsAgentHost::OnClientAttached(reattached);
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(&SetDevToolsAttachedOnIO,
+ service_worker_->context_weak(),
+ service_worker_->version_id(),
+ true));
+}
+
+void ServiceWorkerDevToolsAgentHost::OnClientDetached() {
+ WorkerDevToolsAgentHost::OnClientDetached();
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(&SetDevToolsAttachedOnIO,
+ service_worker_->context_weak(),
+ service_worker_->version_id(),
+ false));
+}
+
+bool ServiceWorkerDevToolsAgentHost::Matches(
+ const ServiceWorkerIdentifier& other) {
+ return service_worker_->Matches(other);
+}
+
+ServiceWorkerDevToolsAgentHost::~ServiceWorkerDevToolsAgentHost() {
+ ServiceWorkerDevToolsManager::GetInstance()->RemoveInspectedWorkerData(
+ worker_id());
+}
+
+} // namespace content
diff --git a/chromium/content/browser/devtools/service_worker_devtools_agent_host.h b/chromium/content/browser/devtools/service_worker_devtools_agent_host.h
new file mode 100644
index 00000000000..b0535ccfc7f
--- /dev/null
+++ b/chromium/content/browser/devtools/service_worker_devtools_agent_host.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_DEVTOOLS_SERVICE_WORKER_DEVTOOLS_AGENT_HOST_H_
+#define CONTENT_BROWSER_DEVTOOLS_SERVICE_WORKER_DEVTOOLS_AGENT_HOST_H_
+
+#include <map>
+
+#include "content/browser/devtools/service_worker_devtools_manager.h"
+#include "content/browser/devtools/worker_devtools_agent_host.h"
+
+namespace content {
+
+class ServiceWorkerDevToolsAgentHost : public WorkerDevToolsAgentHost {
+ public:
+ using List = std::vector<scoped_refptr<ServiceWorkerDevToolsAgentHost>>;
+ using Map = std::map<std::string,
+ scoped_refptr<ServiceWorkerDevToolsAgentHost>>;
+ using ServiceWorkerIdentifier =
+ ServiceWorkerDevToolsManager::ServiceWorkerIdentifier;
+
+ ServiceWorkerDevToolsAgentHost(WorkerId worker_id,
+ const ServiceWorkerIdentifier& service_worker);
+
+ void UnregisterWorker();
+
+ // DevToolsAgentHost override.
+ Type GetType() override;
+ std::string GetTitle() override;
+ GURL GetURL() override;
+ bool Activate() override;
+ bool Close() override;
+
+ // IPCDevToolsAgentHost override.
+ void OnClientAttached(bool reattached) override;
+ void OnClientDetached() override;
+
+ bool Matches(const ServiceWorkerIdentifier& other);
+
+ private:
+ ~ServiceWorkerDevToolsAgentHost() override;
+ scoped_ptr<ServiceWorkerIdentifier> service_worker_;
+
+ DISALLOW_COPY_AND_ASSIGN(ServiceWorkerDevToolsAgentHost);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_DEVTOOLS_SERVICE_WORKER_DEVTOOLS_AGENT_HOST_H_
diff --git a/chromium/content/browser/devtools/service_worker_devtools_manager.cc b/chromium/content/browser/devtools/service_worker_devtools_manager.cc
new file mode 100644
index 00000000000..c02ab6e2568
--- /dev/null
+++ b/chromium/content/browser/devtools/service_worker_devtools_manager.cc
@@ -0,0 +1,185 @@
+// Copyright 2014 The Chromium Authors. 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/service_worker_devtools_manager.h"
+
+#include "content/browser/devtools/ipc_devtools_agent_host.h"
+#include "content/browser/devtools/service_worker_devtools_agent_host.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/worker_service.h"
+#include "ipc/ipc_listener.h"
+
+namespace content {
+
+ServiceWorkerDevToolsManager::ServiceWorkerIdentifier::ServiceWorkerIdentifier(
+ 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) {
+}
+
+ServiceWorkerDevToolsManager::ServiceWorkerIdentifier::ServiceWorkerIdentifier(
+ const ServiceWorkerIdentifier& other)
+ : context_(other.context_),
+ context_weak_(other.context_weak_),
+ version_id_(other.version_id_),
+ url_(other.url_) {
+}
+
+ServiceWorkerDevToolsManager::
+ServiceWorkerIdentifier::~ServiceWorkerIdentifier() {
+}
+
+bool ServiceWorkerDevToolsManager::ServiceWorkerIdentifier::Matches(
+ const ServiceWorkerIdentifier& other) const {
+ return context_ == other.context_ && version_id_ == other.version_id_;
+}
+
+// static
+ServiceWorkerDevToolsManager* ServiceWorkerDevToolsManager::GetInstance() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ return Singleton<ServiceWorkerDevToolsManager>::get();
+}
+
+DevToolsAgentHostImpl*
+ServiceWorkerDevToolsManager::GetDevToolsAgentHostForWorker(
+ int worker_process_id,
+ int worker_route_id) {
+ AgentHostMap::iterator it = workers_.find(
+ WorkerId(worker_process_id, worker_route_id));
+ return it == workers_.end() ? NULL : it->second;
+}
+
+void ServiceWorkerDevToolsManager::AddAllAgentHosts(
+ ServiceWorkerDevToolsAgentHost::List* result) {
+ for (auto& worker : workers_) {
+ if (!worker.second->IsTerminated())
+ result->push_back(worker.second);
+ }
+}
+
+void ServiceWorkerDevToolsManager::AddAllAgentHostsForBrowserContext(
+ BrowserContext* browser_context,
+ ServiceWorkerDevToolsAgentHost::List* result) {
+ for (auto& worker : workers_) {
+ if (!worker.second->IsTerminated() &&
+ worker.second->GetBrowserContext() == browser_context) {
+ result->push_back(worker.second);
+ }
+ }
+}
+
+bool ServiceWorkerDevToolsManager::WorkerCreated(
+ int worker_process_id,
+ int worker_route_id,
+ const ServiceWorkerIdentifier& service_worker_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ const WorkerId id(worker_process_id, worker_route_id);
+ AgentHostMap::iterator it = FindExistingWorkerAgentHost(service_worker_id);
+ if (it == workers_.end()) {
+ scoped_refptr<ServiceWorkerDevToolsAgentHost> host =
+ new ServiceWorkerDevToolsAgentHost(
+ id, service_worker_id);
+ workers_[id] = host.get();
+ FOR_EACH_OBSERVER(Observer, observer_list_, WorkerCreated(host.get()));
+ if (debug_service_worker_on_start_)
+ host->PauseForDebugOnStart();
+ return host->IsPausedForDebugOnStart();
+ }
+
+ // Worker was restarted.
+ ServiceWorkerDevToolsAgentHost* agent_host = it->second;
+ agent_host->WorkerRestarted(id);
+ workers_.erase(it);
+ workers_[id] = agent_host;
+
+ return agent_host->IsAttached();
+}
+
+void ServiceWorkerDevToolsManager::WorkerReadyForInspection(
+ int worker_process_id,
+ int worker_route_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ const WorkerId id(worker_process_id, worker_route_id);
+ AgentHostMap::iterator it = workers_.find(id);
+ DCHECK(it != workers_.end());
+ scoped_refptr<ServiceWorkerDevToolsAgentHost> host = it->second;
+ host->WorkerReadyForInspection();
+ FOR_EACH_OBSERVER(Observer, observer_list_,
+ WorkerReadyForInspection(host.get()));
+
+ // Then bring up UI for the ones not picked by other clients.
+ if (host->IsPausedForDebugOnStart() && !host->IsAttached()) {
+ host->Inspect(RenderProcessHost::FromID(worker_process_id)->
+ GetBrowserContext());
+ }
+}
+
+void ServiceWorkerDevToolsManager::WorkerStopIgnored(int worker_process_id,
+ int worker_route_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ // TODO(pfeldman): Show a console message to tell the user that UA didn't
+ // terminate the worker because devtools is attached.
+}
+
+void ServiceWorkerDevToolsManager::WorkerDestroyed(int worker_process_id,
+ int worker_route_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ const WorkerId id(worker_process_id, worker_route_id);
+ AgentHostMap::iterator it = workers_.find(id);
+ DCHECK(it != workers_.end());
+ scoped_refptr<WorkerDevToolsAgentHost> agent_host(it->second);
+ agent_host->WorkerDestroyed();
+ FOR_EACH_OBSERVER(Observer, observer_list_, WorkerDestroyed(it->second));
+}
+
+void ServiceWorkerDevToolsManager::RemoveInspectedWorkerData(WorkerId id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ workers_.erase(id);
+}
+
+void ServiceWorkerDevToolsManager::AddObserver(Observer* observer) {
+ observer_list_.AddObserver(observer);
+}
+
+void ServiceWorkerDevToolsManager::RemoveObserver(Observer* observer) {
+ observer_list_.RemoveObserver(observer);
+}
+
+void ServiceWorkerDevToolsManager::set_debug_service_worker_on_start(
+ bool debug_on_start) {
+ debug_service_worker_on_start_ = debug_on_start;
+ FOR_EACH_OBSERVER(Observer, observer_list_,
+ DebugOnStartUpdated(debug_on_start));
+}
+
+ServiceWorkerDevToolsManager::ServiceWorkerDevToolsManager()
+ : debug_service_worker_on_start_(false) {
+}
+
+ServiceWorkerDevToolsManager::~ServiceWorkerDevToolsManager() {
+}
+
+ServiceWorkerDevToolsManager::AgentHostMap::iterator
+ServiceWorkerDevToolsManager::FindExistingWorkerAgentHost(
+ const ServiceWorkerIdentifier& service_worker_id) {
+ AgentHostMap::iterator it = workers_.begin();
+ for (; it != workers_.end(); ++it) {
+ if (static_cast<ServiceWorkerDevToolsAgentHost*>(
+ it->second)->Matches(service_worker_id))
+ break;
+ }
+ return it;
+}
+
+void ServiceWorkerDevToolsManager::ResetForTesting() {
+ workers_.clear();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/devtools/service_worker_devtools_manager.h b/chromium/content/browser/devtools/service_worker_devtools_manager.h
new file mode 100644
index 00000000000..8815fefe331
--- /dev/null
+++ b/chromium/content/browser/devtools/service_worker_devtools_manager.h
@@ -0,0 +1,122 @@
+// Copyright 2014 The Chromium Authors. 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_SERVICE_WORKER_DEVTOOLS_MANAGER_H_
+#define CONTENT_BROWSER_DEVTOOLS_SERVICE_WORKER_DEVTOOLS_MANAGER_H_
+
+#include <map>
+
+#include "base/basictypes.h"
+#include "base/memory/singleton.h"
+#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "content/public/browser/devtools_agent_host.h"
+
+namespace content {
+
+class BrowserContext;
+class DevToolsAgentHostImpl;
+class ServiceWorkerDevToolsAgentHost;
+class ServiceWorkerContextCore;
+
+// Manages WorkerDevToolsAgentHost's for Service Workers.
+// This class lives on UI thread.
+class CONTENT_EXPORT ServiceWorkerDevToolsManager {
+ public:
+ using WorkerId = std::pair<int, int>;
+ using AgentList = std::vector<scoped_refptr<ServiceWorkerDevToolsAgentHost>>;
+
+ class Observer {
+ public:
+ virtual void WorkerCreated(ServiceWorkerDevToolsAgentHost* host) {}
+ virtual void WorkerReadyForInspection(
+ ServiceWorkerDevToolsAgentHost* host) {}
+ virtual void WorkerDestroyed(ServiceWorkerDevToolsAgentHost* host) {}
+ virtual void DebugOnStartUpdated(bool debug_on_start) {}
+
+ protected:
+ virtual ~Observer() {}
+ };
+
+ class ServiceWorkerIdentifier {
+ public:
+ 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 { return context_; }
+ base::WeakPtr<ServiceWorkerContextCore> context_weak() const {
+ return context_weak_;
+ }
+ int64 version_id() const { return version_id_; }
+ GURL url() const { return url_; }
+
+ private:
+ const ServiceWorkerContextCore* const context_;
+ const base::WeakPtr<ServiceWorkerContextCore> context_weak_;
+ const int64 version_id_;
+ const GURL url_;
+ };
+
+ // Returns the ServiceWorkerDevToolsManager singleton.
+ static ServiceWorkerDevToolsManager* GetInstance();
+
+ DevToolsAgentHostImpl* GetDevToolsAgentHostForWorker(int worker_process_id,
+ int worker_route_id);
+ void AddAllAgentHosts(
+ std::vector<scoped_refptr<ServiceWorkerDevToolsAgentHost>>* result);
+ void AddAllAgentHostsForBrowserContext(
+ BrowserContext* browser_context,
+ std::vector<scoped_refptr<ServiceWorkerDevToolsAgentHost>>* result);
+
+ // Returns true when the worker must be paused on start because a DevTool
+ // window for the same former ServiceWorkerIdentifier is still opened or
+ // debug-on-start is enabled in chrome://serviceworker-internals.
+ bool WorkerCreated(int worker_process_id,
+ int worker_route_id,
+ const ServiceWorkerIdentifier& service_worker_id);
+ void WorkerReadyForInspection(int worker_process_id, int worker_route_id);
+ void WorkerStopIgnored(int worker_process_id, int worker_route_id);
+ void WorkerDestroyed(int worker_process_id, int worker_route_id);
+ void RemoveInspectedWorkerData(WorkerId id);
+
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+
+ void set_debug_service_worker_on_start(bool debug_on_start);
+ bool debug_service_worker_on_start() const {
+ return debug_service_worker_on_start_;
+ }
+
+ private:
+ friend struct DefaultSingletonTraits<ServiceWorkerDevToolsManager>;
+ friend class ServiceWorkerDevToolsAgentHost;
+
+ using AgentHostMap = std::map<WorkerId, ServiceWorkerDevToolsAgentHost*>;
+
+ ServiceWorkerDevToolsManager();
+ ~ServiceWorkerDevToolsManager();
+
+ AgentHostMap::iterator FindExistingWorkerAgentHost(
+ const ServiceWorkerIdentifier& service_worker_id);
+
+ // Resets to its initial state as if newly created.
+ void ResetForTesting();
+
+ ObserverList<Observer> observer_list_;
+ AgentHostMap workers_;
+ bool debug_service_worker_on_start_;
+
+ DISALLOW_COPY_AND_ASSIGN(ServiceWorkerDevToolsManager);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_DEVTOOLS_SERVICE_WORKER_DEVTOOLS_MANAGER_H_
diff --git a/chromium/content/browser/devtools/shared_worker_devtools_agent_host.cc b/chromium/content/browser/devtools/shared_worker_devtools_agent_host.cc
new file mode 100644
index 00000000000..b823ea7af3e
--- /dev/null
+++ b/chromium/content/browser/devtools/shared_worker_devtools_agent_host.cc
@@ -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 "content/browser/devtools/shared_worker_devtools_agent_host.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "content/browser/devtools/shared_worker_devtools_manager.h"
+#include "content/browser/shared_worker/shared_worker_instance.h"
+#include "content/browser/shared_worker/shared_worker_service_impl.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace content {
+
+namespace {
+
+void TerminateSharedWorkerOnIO(
+ WorkerDevToolsAgentHost::WorkerId worker_id) {
+ SharedWorkerServiceImpl::GetInstance()->TerminateWorker(
+ worker_id.first, worker_id.second);
+}
+
+} // namespace
+
+SharedWorkerDevToolsAgentHost::SharedWorkerDevToolsAgentHost(
+ WorkerId worker_id,
+ const SharedWorkerInstance& shared_worker)
+ : WorkerDevToolsAgentHost(worker_id),
+ shared_worker_(new SharedWorkerInstance(shared_worker)) {
+}
+
+DevToolsAgentHost::Type SharedWorkerDevToolsAgentHost::GetType() {
+ return TYPE_SHARED_WORKER;
+}
+
+std::string SharedWorkerDevToolsAgentHost::GetTitle() {
+ return base::UTF16ToUTF8(shared_worker_->name());
+}
+
+GURL SharedWorkerDevToolsAgentHost::GetURL() {
+ return shared_worker_->url();
+}
+
+bool SharedWorkerDevToolsAgentHost::Activate() {
+ return false;
+}
+
+bool SharedWorkerDevToolsAgentHost::Close() {
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(&TerminateSharedWorkerOnIO, worker_id()));
+ return true;
+}
+
+bool SharedWorkerDevToolsAgentHost::Matches(
+ const SharedWorkerInstance& other) {
+ return shared_worker_->Matches(other);
+}
+
+SharedWorkerDevToolsAgentHost::~SharedWorkerDevToolsAgentHost() {
+ SharedWorkerDevToolsManager::GetInstance()->RemoveInspectedWorkerData(
+ worker_id());
+}
+
+} // namespace content
diff --git a/chromium/content/browser/devtools/shared_worker_devtools_agent_host.h b/chromium/content/browser/devtools/shared_worker_devtools_agent_host.h
new file mode 100644
index 00000000000..21f8a38de4a
--- /dev/null
+++ b/chromium/content/browser/devtools/shared_worker_devtools_agent_host.h
@@ -0,0 +1,41 @@
+// Copyright 2014 The Chromium Authors. 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_SHARED_WORKER_DEVTOOLS_AGENT_HOST_H_
+#define CONTENT_BROWSER_DEVTOOLS_SHARED_WORKER_DEVTOOLS_AGENT_HOST_H_
+
+#include "content/browser/devtools/worker_devtools_agent_host.h"
+
+namespace content {
+
+class SharedWorkerInstance;
+
+class SharedWorkerDevToolsAgentHost : public WorkerDevToolsAgentHost {
+ public:
+ using List = std::vector<scoped_refptr<SharedWorkerDevToolsAgentHost>>;
+
+ SharedWorkerDevToolsAgentHost(WorkerId worker_id,
+ const SharedWorkerInstance& shared_worker);
+
+ // DevToolsAgentHost override.
+ Type GetType() override;
+ std::string GetTitle() override;
+ GURL GetURL() override;
+ bool Activate() override;
+ bool Close() override;
+
+ bool Matches(const SharedWorkerInstance& other);
+
+ private:
+ friend class SharedWorkerDevToolsManagerTest;
+
+ ~SharedWorkerDevToolsAgentHost() override;
+ scoped_ptr<SharedWorkerInstance> shared_worker_;
+
+ DISALLOW_COPY_AND_ASSIGN(SharedWorkerDevToolsAgentHost);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_DEVTOOLS_SHARED_WORKER_DEVTOOLS_AGENT_HOST_H_
diff --git a/chromium/content/browser/devtools/shared_worker_devtools_manager.cc b/chromium/content/browser/devtools/shared_worker_devtools_manager.cc
new file mode 100644
index 00000000000..3490e803be7
--- /dev/null
+++ b/chromium/content/browser/devtools/shared_worker_devtools_manager.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/devtools/shared_worker_devtools_manager.h"
+
+#include "content/browser/devtools/shared_worker_devtools_agent_host.h"
+#include "content/browser/shared_worker/shared_worker_instance.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace content {
+
+// static
+SharedWorkerDevToolsManager* SharedWorkerDevToolsManager::GetInstance() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ return Singleton<SharedWorkerDevToolsManager>::get();
+}
+
+DevToolsAgentHostImpl*
+SharedWorkerDevToolsManager::GetDevToolsAgentHostForWorker(
+ int worker_process_id,
+ int worker_route_id) {
+ AgentHostMap::iterator it = workers_.find(
+ WorkerId(worker_process_id, worker_route_id));
+ return it == workers_.end() ? NULL : it->second;
+}
+
+void SharedWorkerDevToolsManager::AddAllAgentHosts(
+ SharedWorkerDevToolsAgentHost::List* result) {
+ for (auto& worker : workers_) {
+ if (!worker.second->IsTerminated())
+ result->push_back(worker.second);
+ }
+}
+
+bool SharedWorkerDevToolsManager::WorkerCreated(
+ int worker_process_id,
+ int worker_route_id,
+ const SharedWorkerInstance& instance) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ const WorkerId id(worker_process_id, worker_route_id);
+ AgentHostMap::iterator it =
+ FindExistingWorkerAgentHost(instance);
+ if (it == workers_.end()) {
+ workers_[id] = new SharedWorkerDevToolsAgentHost(id, instance);
+ return false;
+ }
+
+ // Worker restarted.
+ SharedWorkerDevToolsAgentHost* agent_host = it->second;
+ agent_host->WorkerRestarted(id);
+ workers_.erase(it);
+ workers_[id] = agent_host;
+ return true;
+}
+
+void SharedWorkerDevToolsManager::WorkerReadyForInspection(
+ int worker_process_id,
+ int worker_route_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ const WorkerId id(worker_process_id, worker_route_id);
+ AgentHostMap::iterator it = workers_.find(id);
+ DCHECK(it != workers_.end());
+ it->second->WorkerReadyForInspection();
+}
+
+void SharedWorkerDevToolsManager::WorkerDestroyed(
+ int worker_process_id,
+ int worker_route_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ const WorkerId id(worker_process_id, worker_route_id);
+ AgentHostMap::iterator it = workers_.find(id);
+ DCHECK(it != workers_.end());
+ scoped_refptr<SharedWorkerDevToolsAgentHost> agent_host(it->second);
+ agent_host->WorkerDestroyed();
+}
+
+void SharedWorkerDevToolsManager::RemoveInspectedWorkerData(WorkerId id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ workers_.erase(id);
+}
+SharedWorkerDevToolsManager::SharedWorkerDevToolsManager() {
+}
+
+SharedWorkerDevToolsManager::~SharedWorkerDevToolsManager() {
+}
+
+SharedWorkerDevToolsManager::AgentHostMap::iterator
+SharedWorkerDevToolsManager::FindExistingWorkerAgentHost(
+ const SharedWorkerInstance& instance) {
+ AgentHostMap::iterator it = workers_.begin();
+ for (; it != workers_.end(); ++it) {
+ if (it->second->Matches(instance))
+ break;
+ }
+ return it;
+}
+
+void SharedWorkerDevToolsManager::ResetForTesting() {
+ workers_.clear();
+}
+
+
+} // namespace content
diff --git a/chromium/content/browser/devtools/shared_worker_devtools_manager.h b/chromium/content/browser/devtools/shared_worker_devtools_manager.h
new file mode 100644
index 00000000000..6a2a828f9bf
--- /dev/null
+++ b/chromium/content/browser/devtools/shared_worker_devtools_manager.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_DEVTOOLS_SHARED_WORKER_DEVTOOLS_MANAGER_H_
+#define CONTENT_BROWSER_DEVTOOLS_SHARED_WORKER_DEVTOOLS_MANAGER_H_
+
+#include <map>
+
+#include "base/basictypes.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/singleton.h"
+#include "content/public/browser/devtools_agent_host.h"
+
+namespace content {
+
+class DevToolsAgentHostImpl;
+class SharedWorkerDevToolsAgentHost;
+class SharedWorkerInstance;
+
+// Manages WorkerDevToolsAgentHost's for Shared Workers.
+// This class lives on UI thread.
+class CONTENT_EXPORT SharedWorkerDevToolsManager {
+ public:
+ using WorkerId = std::pair<int, int>;
+
+ // Returns the SharedWorkerDevToolsManager singleton.
+ static SharedWorkerDevToolsManager* GetInstance();
+
+ DevToolsAgentHostImpl* GetDevToolsAgentHostForWorker(int worker_process_id,
+ int worker_route_id);
+ void AddAllAgentHosts(
+ std::vector<scoped_refptr<SharedWorkerDevToolsAgentHost>>* result);
+
+ // Returns true when the worker must be paused on start because a DevTool
+ // window for the same former SharedWorkerInstance is still opened.
+ bool WorkerCreated(int worker_process_id,
+ int worker_route_id,
+ const SharedWorkerInstance& instance);
+ void WorkerReadyForInspection(int worker_process_id, int worker_route_id);
+ void WorkerDestroyed(int worker_process_id, int worker_route_id);
+ void RemoveInspectedWorkerData(WorkerId id);
+
+ private:
+ friend struct DefaultSingletonTraits<SharedWorkerDevToolsManager>;
+ friend class SharedWorkerDevToolsAgentHost;
+ friend class SharedWorkerDevToolsManagerTest;
+ FRIEND_TEST_ALL_PREFIXES(SharedWorkerDevToolsManagerTest, BasicTest);
+ FRIEND_TEST_ALL_PREFIXES(SharedWorkerDevToolsManagerTest, AttachTest);
+
+ using AgentHostMap = std::map<WorkerId, SharedWorkerDevToolsAgentHost*>;
+
+ SharedWorkerDevToolsManager();
+ ~SharedWorkerDevToolsManager();
+
+ AgentHostMap::iterator FindExistingWorkerAgentHost(
+ const SharedWorkerInstance& instance);
+
+ // Resets to its initial state as if newly created.
+ void ResetForTesting();
+
+ AgentHostMap workers_;
+ DISALLOW_COPY_AND_ASSIGN(SharedWorkerDevToolsManager);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_DEVTOOLS_SHARED_WORKER_DEVTOOLS_MANAGER_H_
diff --git a/chromium/content/browser/devtools/shared_worker_devtools_manager_unittest.cc b/chromium/content/browser/devtools/shared_worker_devtools_manager_unittest.cc
new file mode 100644
index 00000000000..b56c07bab3e
--- /dev/null
+++ b/chromium/content/browser/devtools/shared_worker_devtools_manager_unittest.cc
@@ -0,0 +1,298 @@
+// Copyright 2014 The Chromium Authors. 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/shared_worker_devtools_manager.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "content/browser/browser_thread_impl.h"
+#include "content/browser/devtools/devtools_agent_host_impl.h"
+#include "content/browser/devtools/shared_worker_devtools_agent_host.h"
+#include "content/browser/shared_worker/shared_worker_instance.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 DevToolsAgentHostClient {
+ public:
+ TestDevToolsClientHost() {}
+ ~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);
+};
+} // namespace
+
+class SharedWorkerDevToolsManagerTest : public testing::Test {
+ public:
+ typedef SharedWorkerDevToolsAgentHost::WorkerState WorkerState;
+
+ SharedWorkerDevToolsManagerTest()
+ : ui_thread_(BrowserThread::UI, &message_loop_),
+ browser_context_(new TestBrowserContext()),
+ partition_(
+ new WorkerStoragePartition(browser_context_->GetRequestContext(),
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL)),
+ partition_id_(*partition_.get()) {}
+
+ protected:
+ void SetUp() override {
+ manager_ = SharedWorkerDevToolsManager::GetInstance();
+ }
+ void TearDown() override {
+ SharedWorkerDevToolsManager::GetInstance()->ResetForTesting();
+ }
+
+ void CheckWorkerState(int worker_process_id,
+ int worker_route_id,
+ WorkerState state) {
+ const SharedWorkerDevToolsManager::WorkerId id(worker_process_id,
+ worker_route_id);
+ SharedWorkerDevToolsManager::AgentHostMap::iterator it =
+ manager_->workers_.find(id);
+ EXPECT_TRUE(manager_->workers_.end() != it);
+ EXPECT_EQ(state, it->second->state_);
+ }
+
+ void CheckWorkerNotExist(int worker_process_id, int worker_route_id) {
+ const SharedWorkerDevToolsManager::WorkerId id(worker_process_id,
+ worker_route_id);
+ EXPECT_TRUE(manager_->workers_.end() == manager_->workers_.find(id));
+ }
+
+ void CheckWorkerCount(size_t size) {
+ EXPECT_EQ(size, manager_->workers_.size());
+ }
+
+ base::MessageLoopForIO message_loop_;
+ BrowserThreadImpl ui_thread_;
+ scoped_ptr<TestBrowserContext> browser_context_;
+ scoped_ptr<WorkerStoragePartition> partition_;
+ const WorkerStoragePartitionId partition_id_;
+ SharedWorkerDevToolsManager* manager_;
+};
+
+TEST_F(SharedWorkerDevToolsManagerTest, BasicTest) {
+ scoped_refptr<DevToolsAgentHostImpl> agent_host;
+
+ SharedWorkerInstance instance1(GURL("http://example.com/w.js"),
+ base::string16(),
+ base::string16(),
+ blink::WebContentSecurityPolicyTypeReport,
+ browser_context_->GetResourceContext(),
+ partition_id_);
+
+ agent_host = manager_->GetDevToolsAgentHostForWorker(1, 1);
+ EXPECT_FALSE(agent_host.get());
+
+ // Created -> Started -> Destroyed
+ CheckWorkerNotExist(1, 1);
+ manager_->WorkerCreated(1, 1, instance1);
+ 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_->WorkerCreated(1, 2, instance1);
+ CheckWorkerState(1, 2, WorkerState::WORKER_UNINSPECTED);
+ agent_host = manager_->GetDevToolsAgentHostForWorker(1, 2);
+ EXPECT_TRUE(agent_host.get());
+ CheckWorkerState(1, 2, WorkerState::WORKER_UNINSPECTED);
+ EXPECT_EQ(agent_host.get(), manager_->GetDevToolsAgentHostForWorker(1, 2));
+ manager_->WorkerReadyForInspection(1, 2);
+ CheckWorkerState(1, 2, WorkerState::WORKER_UNINSPECTED);
+ manager_->WorkerDestroyed(1, 2);
+ CheckWorkerState(1, 2, WorkerState::WORKER_TERMINATED);
+ agent_host = NULL;
+ CheckWorkerNotExist(1, 2);
+
+ // Created -> Started -> GetDevToolsAgentHost -> Destroyed
+ CheckWorkerNotExist(1, 3);
+ manager_->WorkerCreated(1, 3, instance1);
+ 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, WorkerState::WORKER_UNINSPECTED);
+ manager_->WorkerDestroyed(1, 3);
+ CheckWorkerState(1, 3, WorkerState::WORKER_TERMINATED);
+ agent_host = NULL;
+ CheckWorkerNotExist(1, 3);
+
+ // Created -> Destroyed
+ CheckWorkerNotExist(1, 4);
+ manager_->WorkerCreated(1, 4, instance1);
+ CheckWorkerState(1, 4, WorkerState::WORKER_UNINSPECTED);
+ manager_->WorkerDestroyed(1, 4);
+ CheckWorkerNotExist(1, 4);
+
+ // Created -> GetDevToolsAgentHost -> Destroyed
+ CheckWorkerNotExist(1, 5);
+ manager_->WorkerCreated(1, 5, instance1);
+ CheckWorkerState(1, 5, WorkerState::WORKER_UNINSPECTED);
+ agent_host = manager_->GetDevToolsAgentHostForWorker(1, 5);
+ EXPECT_TRUE(agent_host.get());
+ CheckWorkerState(1, 5, WorkerState::WORKER_UNINSPECTED);
+ manager_->WorkerDestroyed(1, 5);
+ CheckWorkerState(1, 5, WorkerState::WORKER_TERMINATED);
+ agent_host = NULL;
+ CheckWorkerNotExist(1, 5);
+
+ // Created -> GetDevToolsAgentHost -> Free agent_host -> Destroyed
+ CheckWorkerNotExist(1, 6);
+ manager_->WorkerCreated(1, 6, instance1);
+ CheckWorkerState(1, 6, WorkerState::WORKER_UNINSPECTED);
+ agent_host = manager_->GetDevToolsAgentHostForWorker(1, 6);
+ EXPECT_TRUE(agent_host.get());
+ CheckWorkerState(1, 6, WorkerState::WORKER_UNINSPECTED);
+ agent_host = NULL;
+ manager_->WorkerDestroyed(1, 6);
+ CheckWorkerNotExist(1, 6);
+}
+
+TEST_F(SharedWorkerDevToolsManagerTest, AttachTest) {
+ scoped_refptr<DevToolsAgentHostImpl> agent_host1;
+ scoped_refptr<DevToolsAgentHostImpl> agent_host2;
+
+ SharedWorkerInstance instance1(GURL("http://example.com/w1.js"),
+ base::string16(),
+ base::string16(),
+ blink::WebContentSecurityPolicyTypeReport,
+ browser_context_->GetResourceContext(),
+ partition_id_);
+ SharedWorkerInstance instance2(GURL("http://example.com/w2.js"),
+ base::string16(),
+ base::string16(),
+ blink::WebContentSecurityPolicyTypeReport,
+ browser_context_->GetResourceContext(),
+ partition_id_);
+
+ // Created -> GetDevToolsAgentHost -> Register -> Started -> Destroyed
+ scoped_ptr<TestDevToolsClientHost> client_host1(new TestDevToolsClientHost());
+ CheckWorkerNotExist(2, 1);
+ manager_->WorkerCreated(2, 1, instance1);
+ CheckWorkerState(2, 1, WorkerState::WORKER_UNINSPECTED);
+ agent_host1 = manager_->GetDevToolsAgentHostForWorker(2, 1);
+ EXPECT_TRUE(agent_host1.get());
+ CheckWorkerState(2, 1, WorkerState::WORKER_UNINSPECTED);
+ EXPECT_EQ(agent_host1.get(), manager_->GetDevToolsAgentHostForWorker(2, 1));
+ 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, 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_->WorkerCreated(2, 2, instance2);
+ 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, WorkerState::WORKER_UNINSPECTED);
+ client_host2->InspectAgentHost(agent_host2.get());
+ CheckWorkerState(2, 2, WorkerState::WORKER_INSPECTED);
+ manager_->WorkerDestroyed(2, 2);
+ CheckWorkerState(2, 2, WorkerState::WORKER_TERMINATED);
+ EXPECT_EQ(agent_host2.get(), manager_->GetDevToolsAgentHostForWorker(2, 2));
+
+ // Re-created -> Started -> ClientHostClosing -> Destroyed
+ CheckWorkerState(2, 1, WorkerState::WORKER_TERMINATED);
+ manager_->WorkerCreated(2, 3, instance1);
+ CheckWorkerNotExist(2, 1);
+ CheckWorkerState(2, 3, WorkerState::WORKER_PAUSED_FOR_REATTACH);
+ EXPECT_EQ(agent_host1.get(), manager_->GetDevToolsAgentHostForWorker(2, 3));
+ manager_->WorkerReadyForInspection(2, 3);
+ CheckWorkerState(2, 3, WorkerState::WORKER_INSPECTED);
+ client_host1->InspectAgentHost(NULL);
+ manager_->WorkerDestroyed(2, 3);
+ CheckWorkerState(2, 3, WorkerState::WORKER_TERMINATED);
+ agent_host1 = NULL;
+ CheckWorkerNotExist(2, 3);
+
+ // Re-created -> Destroyed
+ CheckWorkerState(2, 2, WorkerState::WORKER_TERMINATED);
+ manager_->WorkerCreated(2, 4, instance2);
+ CheckWorkerNotExist(2, 2);
+ CheckWorkerState(2, 4, WorkerState::WORKER_PAUSED_FOR_REATTACH);
+ EXPECT_EQ(agent_host2.get(), manager_->GetDevToolsAgentHostForWorker(2, 4));
+ manager_->WorkerDestroyed(2, 4);
+ CheckWorkerNotExist(2, 2);
+ CheckWorkerState(2, 4, WorkerState::WORKER_TERMINATED);
+
+ // Re-created -> ClientHostClosing -> Destroyed
+ manager_->WorkerCreated(2, 5, instance2);
+ CheckWorkerNotExist(2, 2);
+ CheckWorkerState(2, 5, WorkerState::WORKER_PAUSED_FOR_REATTACH);
+ EXPECT_EQ(agent_host2.get(), manager_->GetDevToolsAgentHostForWorker(2, 5));
+ client_host2->InspectAgentHost(NULL);
+ CheckWorkerCount(1);
+ agent_host2 = NULL;
+ CheckWorkerCount(1);
+ manager_->WorkerDestroyed(2, 5);
+ CheckWorkerCount(0);
+}
+
+TEST_F(SharedWorkerDevToolsManagerTest, 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_->WorkerCreated(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_->WorkerCreated(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/site_per_process_devtools_browsertest.cc b/chromium/content/browser/devtools/site_per_process_devtools_browsertest.cc
new file mode 100644
index 00000000000..1ec78c603c5
--- /dev/null
+++ b/chromium/content/browser/devtools/site_per_process_devtools_browsertest.cc
@@ -0,0 +1,111 @@
+// 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/frame_tree.h"
+#include "content/browser/site_per_process_browsertest.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/browser/devtools_agent_host.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 "net/dns/mock_host_resolver.h"
+
+namespace content {
+
+class SitePerProcessDevToolsBrowserTest
+ : public SitePerProcessBrowserTest {
+ public:
+ SitePerProcessDevToolsBrowserTest() {}
+};
+
+class TestClient: public DevToolsAgentHostClient {
+ public:
+ TestClient() : closed_(false) {}
+ ~TestClient() override {}
+
+ bool closed() { return closed_; }
+
+ void DispatchProtocolMessage(
+ DevToolsAgentHost* agent_host,
+ const std::string& message) override {
+ }
+
+ void AgentHostClosed(
+ DevToolsAgentHost* agent_host,
+ bool replaced_with_another_client) override {
+ closed_ = true;
+ }
+
+ private:
+ bool closed_;
+};
+
+// Fails on Android, http://crbug.com/464993.
+#if defined(OS_ANDROID)
+#define MAYBE_CrossSiteIframeAgentHost DISABLED_CrossSiteIframeAgentHost
+#else
+#define MAYBE_CrossSiteIframeAgentHost CrossSiteIframeAgentHost
+#endif
+IN_PROC_BROWSER_TEST_F(SitePerProcessDevToolsBrowserTest,
+ MAYBE_CrossSiteIframeAgentHost) {
+ DevToolsAgentHost::List list;
+ 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();
+
+ list = DevToolsAgentHost::GetOrCreateAll();
+ EXPECT_EQ(1U, list.size());
+ EXPECT_EQ(DevToolsAgentHost::TYPE_WEB_CONTENTS, list[0]->GetType());
+ EXPECT_EQ(main_url.spec(), list[0]->GetURL().spec());
+
+ // 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);
+
+ list = DevToolsAgentHost::GetOrCreateAll();
+ EXPECT_EQ(1U, list.size());
+ EXPECT_EQ(DevToolsAgentHost::TYPE_WEB_CONTENTS, list[0]->GetType());
+ EXPECT_EQ(main_url.spec(), list[0]->GetURL().spec());
+
+ // Load cross-site page into iframe.
+ GURL::Replacements replace_host;
+ 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);
+
+ list = DevToolsAgentHost::GetOrCreateAll();
+ EXPECT_EQ(2U, list.size());
+ EXPECT_EQ(DevToolsAgentHost::TYPE_WEB_CONTENTS, list[0]->GetType());
+ EXPECT_EQ(main_url.spec(), list[0]->GetURL().spec());
+ EXPECT_EQ(DevToolsAgentHost::TYPE_FRAME, list[1]->GetType());
+ EXPECT_EQ(cross_site_url.spec(), list[1]->GetURL().spec());
+
+ // Attaching to child frame.
+ scoped_refptr<DevToolsAgentHost> child_host = list[1];
+ TestClient client;
+ child_host->AttachClient(&client);
+
+ // Load back same-site page into iframe.
+ NavigateFrameToURL(root->child_at(0), http_url);
+
+ list = DevToolsAgentHost::GetOrCreateAll();
+ EXPECT_EQ(1U, list.size());
+ EXPECT_EQ(DevToolsAgentHost::TYPE_WEB_CONTENTS, list[0]->GetType());
+ EXPECT_EQ(main_url.spec(), list[0]->GetURL().spec());
+ EXPECT_TRUE(client.closed());
+ child_host->DetachClient();
+ child_host = nullptr;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/devtools/tethering_handler.cc b/chromium/content/browser/devtools/tethering_handler.cc
deleted file mode 100644
index e0c083dd8ea..00000000000
--- a/chromium/content/browser/devtools/tethering_handler.cc
+++ /dev/null
@@ -1,441 +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/tethering_handler.h"
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/stl_util.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/devtools_http_handler_delegate.h"
-#include "net/base/io_buffer.h"
-#include "net/base/ip_endpoint.h"
-#include "net/base/net_errors.h"
-#include "net/base/net_log.h"
-#include "net/socket/stream_listen_socket.h"
-#include "net/socket/stream_socket.h"
-#include "net/socket/tcp_server_socket.h"
-
-namespace content {
-
-namespace {
-
-const char kLocalhost[] = "127.0.0.1";
-
-const int kListenBacklog = 5;
-const int kBufferSize = 16 * 1024;
-
-const int kMinTetheringPort = 1024;
-const int kMaxTetheringPort = 32767;
-
-class SocketPump : public net::StreamListenSocket::Delegate {
- public:
- SocketPump(DevToolsHttpHandlerDelegate* delegate,
- net::StreamSocket* client_socket)
- : client_socket_(client_socket),
- delegate_(delegate),
- wire_buffer_size_(0),
- pending_destruction_(false) {
- }
-
- std::string Init() {
- std::string channel_name;
- server_socket_ = delegate_->CreateSocketForTethering(this, &channel_name);
- if (!server_socket_.get() || channel_name.empty())
- SelfDestruct();
- return channel_name;
- }
-
- ~SocketPump() override {}
-
- private:
- void DidAccept(net::StreamListenSocket* server,
- scoped_ptr<net::StreamListenSocket> socket) override {
- if (accepted_socket_.get())
- return;
-
- buffer_ = new net::IOBuffer(kBufferSize);
- wire_buffer_ = new net::GrowableIOBuffer();
- wire_buffer_->SetCapacity(kBufferSize);
-
- accepted_socket_ = socket.Pass();
- int result = client_socket_->Read(
- buffer_.get(),
- kBufferSize,
- base::Bind(&SocketPump::OnClientRead, base::Unretained(this)));
- if (result != net::ERR_IO_PENDING)
- OnClientRead(result);
- }
-
- 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_)
- wire_buffer_->SetCapacity(wire_buffer_->capacity() * 2);
- memcpy(wire_buffer_->StartOfBuffer() + old_size, data, len);
- if (old_size != wire_buffer_->offset())
- return;
- OnClientWrite(0);
- }
-
- void DidClose(net::StreamListenSocket* socket) override { SelfDestruct(); }
-
- void OnClientRead(int result) {
- if (result <= 0) {
- SelfDestruct();
- return;
- }
-
- accepted_socket_->Send(buffer_->data(), result);
- result = client_socket_->Read(
- buffer_.get(),
- kBufferSize,
- base::Bind(&SocketPump::OnClientRead, base::Unretained(this)));
- if (result != net::ERR_IO_PENDING)
- OnClientRead(result);
- }
-
- void OnClientWrite(int result) {
- if (result < 0) {
- SelfDestruct();
- return;
- }
-
- wire_buffer_->set_offset(wire_buffer_->offset() + result);
-
- int remaining = wire_buffer_size_ - wire_buffer_->offset();
- if (remaining == 0) {
- if (pending_destruction_)
- SelfDestruct();
- return;
- }
-
-
- if (remaining > kBufferSize)
- remaining = kBufferSize;
-
- scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(remaining);
- memcpy(buffer->data(), wire_buffer_->data(), remaining);
- result = client_socket_->Write(
- buffer.get(),
- remaining,
- base::Bind(&SocketPump::OnClientWrite, base::Unretained(this)));
-
- // Shrink buffer
- int offset = wire_buffer_->offset();
- if (offset > kBufferSize) {
- memcpy(wire_buffer_->StartOfBuffer(), wire_buffer_->data(),
- wire_buffer_size_ - offset);
- wire_buffer_size_ -= offset;
- wire_buffer_->set_offset(0);
- }
-
- if (result != net::ERR_IO_PENDING)
- OnClientWrite(result);
- return;
- }
-
- void SelfDestruct() {
- if (wire_buffer_.get() && wire_buffer_->offset() != wire_buffer_size_) {
- pending_destruction_ = true;
- return;
- }
- delete this;
- }
-
- private:
- scoped_ptr<net::StreamSocket> client_socket_;
- scoped_ptr<net::StreamListenSocket> server_socket_;
- scoped_ptr<net::StreamListenSocket> accepted_socket_;
- scoped_refptr<net::IOBuffer> buffer_;
- scoped_refptr<net::GrowableIOBuffer> wire_buffer_;
- DevToolsHttpHandlerDelegate* delegate_;
- int wire_buffer_size_;
- bool pending_destruction_;
-};
-
-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 BoundSocket {
- public:
- typedef base::Callback<void(int, const std::string&)> AcceptedCallback;
-
- BoundSocket(AcceptedCallback accepted_callback,
- DevToolsHttpHandlerDelegate* delegate)
- : accepted_callback_(accepted_callback),
- delegate_(delegate),
- socket_(new net::TCPServerSocket(NULL, net::NetLog::Source())),
- port_(0) {
- }
-
- virtual ~BoundSocket() {
- }
-
- bool Listen(int port) {
- port_ = port;
- net::IPAddressNumber ip_number;
- if (!net::ParseIPLiteralToNumber(kLocalhost, &ip_number))
- return false;
-
- net::IPEndPoint end_point(ip_number, port);
- int result = socket_->Listen(end_point, kListenBacklog);
- if (result < 0)
- return false;
-
- net::IPEndPoint local_address;
- result = socket_->GetLocalAddress(&local_address);
- if (result < 0)
- return false;
-
- DoAccept();
- return true;
- }
-
- private:
- typedef std::map<net::IPEndPoint, net::StreamSocket*> AcceptedSocketsMap;
-
- void DoAccept() {
- while (true) {
- int result = socket_->Accept(
- &accept_socket_,
- base::Bind(&BoundSocket::OnAccepted, base::Unretained(this)));
- if (result == net::ERR_IO_PENDING)
- break;
- else
- HandleAcceptResult(result);
- }
- }
-
- void OnAccepted(int result) {
- HandleAcceptResult(result);
- if (result == net::OK)
- DoAccept();
- }
-
- void HandleAcceptResult(int result) {
- if (result != net::OK)
- return;
-
- SocketPump* pump = new SocketPump(delegate_, accept_socket_.release());
- std::string name = pump->Init();
- if (!name.empty())
- accepted_callback_.Run(port_, name);
- }
-
- AcceptedCallback accepted_callback_;
- DevToolsHttpHandlerDelegate* delegate_;
- scoped_ptr<net::ServerSocket> socket_;
- scoped_ptr<net::StreamSocket> accept_socket_;
- int port_;
-};
-
-} // 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(devtools::Tethering::unbind::kName,
- base::Bind(&TetheringHandler::OnUnbind,
- base::Unretained(this)));
-}
-
-TetheringHandler::~TetheringHandler() {
- 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(devtools::Tethering::accepted::kParamPort, port);
- params->SetString(devtools::Tethering::accepted::kParamConnectionId, name);
- SendNotification(devtools::Tethering::accepted::kName, params);
-}
-
-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) {
- const std::string& portParamName = devtools::Tethering::bind::kParamPort;
- int port = GetPort(command, portParamName);
- if (port == 0)
- return command->InvalidParamResponse(portParamName);
-
- 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) {
- const std::string& portParamName = devtools::Tethering::unbind::kParamPort;
- int port = GetPort(command, portParamName);
- if (port == 0)
- return command->InvalidParamResponse(portParamName);
-
- 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();
-}
-
-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
deleted file mode 100644
index d6e56b592fd..00000000000
--- a/chromium/content/browser/devtools/tethering_handler.h
+++ /dev/null
@@ -1,53 +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_TETHERING_HANDLER_H_
-#define CONTENT_BROWSER_DEVTOOLS_TETHERING_HANDLER_H_
-
-#include <map>
-
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "content/browser/devtools/devtools_protocol.h"
-
-namespace content {
-
-class DevToolsHttpHandlerDelegate;
-
-// This class implements reversed tethering handler.
-class TetheringHandler : public DevToolsProtocol::Handler {
- public:
- TetheringHandler(DevToolsHttpHandlerDelegate* delegate,
- scoped_refptr<base::MessageLoopProxy> message_loop_proxy);
- ~TetheringHandler() override;
-
- private:
- class TetheringImpl;
-
- void Accepted(int port, const std::string& name);
- bool Activate();
-
- scoped_refptr<DevToolsProtocol::Response> OnBind(
- scoped_refptr<DevToolsProtocol::Command> command);
- scoped_refptr<DevToolsProtocol::Response> OnUnbind(
- scoped_refptr<DevToolsProtocol::Command> command);
-
- 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);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_DEVTOOLS_TETHERING_HANDLER_H_
diff --git a/chromium/content/browser/devtools/worker_devtools_agent_host.cc b/chromium/content/browser/devtools/worker_devtools_agent_host.cc
new file mode 100644
index 00000000000..a0c1fc63128
--- /dev/null
+++ b/chromium/content/browser/devtools/worker_devtools_agent_host.cc
@@ -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.
+
+#include "content/browser/devtools/worker_devtools_agent_host.h"
+
+#include "content/browser/devtools/ipc_devtools_agent_host.h"
+#include "content/browser/devtools/protocol/devtools_protocol_handler.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_process_host.h"
+
+namespace content {
+
+BrowserContext* WorkerDevToolsAgentHost::GetBrowserContext() {
+ RenderProcessHost* rph = RenderProcessHost::FromID(worker_id_.first);
+ return rph ? rph->GetBrowserContext() : nullptr;
+}
+
+void WorkerDevToolsAgentHost::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 WorkerDevToolsAgentHost::Attach() {
+ if (state_ != WORKER_INSPECTED) {
+ state_ = WORKER_INSPECTED;
+ AttachToWorker();
+ }
+ IPCDevToolsAgentHost::Attach();
+}
+
+void WorkerDevToolsAgentHost::OnClientAttached(bool reattached) {
+ if (!reattached)
+ DevToolsAgentHostImpl::NotifyCallbacks(this, true);
+}
+
+void WorkerDevToolsAgentHost::OnClientDetached() {
+ if (state_ == WORKER_INSPECTED) {
+ state_ = WORKER_UNINSPECTED;
+ DetachFromWorker();
+ } else if (state_ == WORKER_PAUSED_FOR_REATTACH) {
+ state_ = WORKER_UNINSPECTED;
+ }
+ DevToolsAgentHostImpl::NotifyCallbacks(this, false);
+}
+
+bool WorkerDevToolsAgentHost::OnMessageReceived(
+ const IPC::Message& msg) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(WorkerDevToolsAgentHost, msg)
+ IPC_MESSAGE_HANDLER(DevToolsClientMsg_DispatchOnInspectorFrontend,
+ OnDispatchOnInspectorFrontend)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void WorkerDevToolsAgentHost::PauseForDebugOnStart() {
+ DCHECK(state_ == WORKER_UNINSPECTED);
+ state_ = WORKER_PAUSED_FOR_DEBUG_ON_START;
+}
+
+bool WorkerDevToolsAgentHost::IsPausedForDebugOnStart() {
+ return state_ == WORKER_PAUSED_FOR_DEBUG_ON_START;
+}
+
+void WorkerDevToolsAgentHost::WorkerReadyForInspection() {
+ if (state_ == WORKER_PAUSED_FOR_REATTACH) {
+ DCHECK(IsAttached());
+ state_ = WORKER_INSPECTED;
+ AttachToWorker();
+ Reattach();
+ }
+}
+
+void WorkerDevToolsAgentHost::WorkerRestarted(WorkerId worker_id) {
+ DCHECK_EQ(WORKER_TERMINATED, state_);
+ state_ = IsAttached() ? WORKER_PAUSED_FOR_REATTACH : WORKER_UNINSPECTED;
+ worker_id_ = worker_id;
+ WorkerCreated();
+}
+
+void WorkerDevToolsAgentHost::WorkerDestroyed() {
+ DCHECK_NE(WORKER_TERMINATED, state_);
+ if (state_ == WORKER_INSPECTED) {
+ DCHECK(IsAttached());
+ // Client host is debugging this worker agent host.
+ base::Callback<void(const std::string&)> raw_message_callback(
+ base::Bind(&WorkerDevToolsAgentHost::SendMessageToClient,
+ base::Unretained(this)));
+ devtools::inspector::Client inspector(raw_message_callback);
+ inspector.TargetCrashed(
+ devtools::inspector::TargetCrashedParams::Create());
+ DetachFromWorker();
+ }
+ state_ = WORKER_TERMINATED;
+ Release(); // Balanced in WorkerCreated().
+}
+
+bool WorkerDevToolsAgentHost::IsTerminated() {
+ return state_ == WORKER_TERMINATED;
+}
+
+WorkerDevToolsAgentHost::WorkerDevToolsAgentHost(
+ WorkerId worker_id)
+ : state_(WORKER_UNINSPECTED),
+ worker_id_(worker_id) {
+ WorkerCreated();
+}
+
+WorkerDevToolsAgentHost::~WorkerDevToolsAgentHost() {
+ DCHECK_EQ(WORKER_TERMINATED, state_);
+}
+
+void WorkerDevToolsAgentHost::AttachToWorker() {
+ if (RenderProcessHost* host = RenderProcessHost::FromID(worker_id_.first))
+ host->AddRoute(worker_id_.second, this);
+}
+
+void WorkerDevToolsAgentHost::DetachFromWorker() {
+ if (RenderProcessHost* host = RenderProcessHost::FromID(worker_id_.first))
+ host->RemoveRoute(worker_id_.second);
+}
+
+void WorkerDevToolsAgentHost::WorkerCreated() {
+ AddRef(); // Balanced in WorkerDestroyed()
+}
+
+void WorkerDevToolsAgentHost::OnDispatchOnInspectorFrontend(
+ const DevToolsMessageChunk& message) {
+ if (!IsAttached())
+ return;
+
+ ProcessChunkedMessageFromAgent(message);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/devtools/worker_devtools_agent_host.h b/chromium/content/browser/devtools/worker_devtools_agent_host.h
new file mode 100644
index 00000000000..30fee5a6211
--- /dev/null
+++ b/chromium/content/browser/devtools/worker_devtools_agent_host.h
@@ -0,0 +1,70 @@
+// Copyright 2014 The Chromium Authors. 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_AGENT_HOST_H_
+#define CONTENT_BROWSER_DEVTOOLS_WORKER_DEVTOOLS_AGENT_HOST_H_
+
+#include "content/browser/devtools/ipc_devtools_agent_host.h"
+#include "ipc/ipc_listener.h"
+
+namespace content {
+
+class BrowserContext;
+class SharedWorkerInstance;
+
+class WorkerDevToolsAgentHost : public IPCDevToolsAgentHost,
+ public IPC::Listener {
+ public:
+ typedef std::pair<int, int> WorkerId;
+
+ // DevToolsAgentHost override.
+ BrowserContext* GetBrowserContext() override;
+
+ // IPCDevToolsAgentHost implementation.
+ void SendMessageToAgent(IPC::Message* message) override;
+ void Attach() override;
+ void OnClientAttached(bool reattached) override;
+ void OnClientDetached() override;
+
+ // IPC::Listener implementation.
+ bool OnMessageReceived(const IPC::Message& msg) override;
+
+ void PauseForDebugOnStart();
+ bool IsPausedForDebugOnStart();
+
+ void WorkerReadyForInspection();
+ void WorkerRestarted(WorkerId worker_id);
+ void WorkerDestroyed();
+ bool IsTerminated();
+
+ protected:
+ WorkerDevToolsAgentHost(WorkerId worker_id);
+ ~WorkerDevToolsAgentHost() 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 DevToolsMessageChunk& message);
+
+ const WorkerId& worker_id() const { return worker_id_; }
+
+ private:
+ friend class SharedWorkerDevToolsManagerTest;
+
+ WorkerState state_;
+ WorkerId worker_id_;
+ DISALLOW_COPY_AND_ASSIGN(WorkerDevToolsAgentHost);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_DEVTOOLS_WORKER_DEVTOOLS_AGENT_HOST_H_
diff --git a/chromium/content/browser/dom_storage/dom_storage_area.cc b/chromium/content/browser/dom_storage/dom_storage_area.cc
index 90a55a0ed8b..e76f5c94d5e 100644
--- a/chromium/content/browser/dom_storage/dom_storage_area.cc
+++ b/chromium/content/browser/dom_storage/dom_storage_area.cc
@@ -4,10 +4,13 @@
#include "content/browser/dom_storage/dom_storage_area.h"
+#include <algorithm>
+
#include "base/bind.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
+#include "base/process/process_info.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "content/browser/dom_storage/dom_storage_namespace.h"
@@ -17,6 +20,7 @@
#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 "content/public/browser/browser_thread.h"
#include "storage/browser/database/database_util.h"
#include "storage/common/database/database_identifier.h"
#include "storage/common/fileapi/file_system_util.h"
@@ -25,13 +29,46 @@ using storage::DatabaseUtil;
namespace content {
-static const int kCommitTimerSeconds = 1;
+namespace {
+
+// Delay for a moment after a value is set in anticipation
+// of other values being set, so changes are batched.
+const int kCommitDefaultDelaySecs = 5;
+
+// To avoid excessive IO we apply limits to the amount of data being written
+// and the frequency of writes. The specific values used are somewhat arbitrary.
+const int kMaxBytesPerHour = kPerStorageAreaQuota;
+const int kMaxCommitsPerHour = 60;
+
+} // namespace
+
+bool DOMStorageArea::s_aggressive_flushing_enabled_ = false;
-DOMStorageArea::CommitBatch::CommitBatch()
- : clear_all_first(false) {
+DOMStorageArea::RateLimiter::RateLimiter(size_t desired_rate,
+ base::TimeDelta time_quantum)
+ : rate_(desired_rate), samples_(0), time_quantum_(time_quantum) {
+ DCHECK_GT(desired_rate, 0ul);
+}
+
+base::TimeDelta DOMStorageArea::RateLimiter::ComputeTimeNeeded() const {
+ return time_quantum_ * (samples_ / rate_);
+}
+
+base::TimeDelta DOMStorageArea::RateLimiter::ComputeDelayNeeded(
+ const base::TimeDelta elapsed_time) const {
+ base::TimeDelta time_needed = ComputeTimeNeeded();
+ if (time_needed > elapsed_time)
+ return time_needed - elapsed_time;
+ return base::TimeDelta();
+}
+
+DOMStorageArea::CommitBatch::CommitBatch() : clear_all_first(false) {
}
DOMStorageArea::CommitBatch::~CommitBatch() {}
+size_t DOMStorageArea::CommitBatch::GetDataSize() const {
+ return DOMStorageMap::CountBytes(changed_values);
+}
// static
const base::FilePath::CharType DOMStorageArea::kDatabaseFileExtension[] =
@@ -55,17 +92,25 @@ GURL DOMStorageArea::OriginFromDatabaseFileName(const base::FilePath& name) {
return storage::GetOriginFromIdentifier(origin_id);
}
-DOMStorageArea::DOMStorageArea(
- const GURL& origin, const base::FilePath& directory,
- DOMStorageTaskRunner* task_runner)
- : namespace_id_(kLocalStorageNamespaceId), origin_(origin),
+void DOMStorageArea::EnableAggressiveCommitDelay() {
+ s_aggressive_flushing_enabled_ = true;
+}
+
+DOMStorageArea::DOMStorageArea(const GURL& origin,
+ const base::FilePath& directory,
+ DOMStorageTaskRunner* task_runner)
+ : namespace_id_(kLocalStorageNamespaceId),
+ origin_(origin),
directory_(directory),
task_runner_(task_runner),
map_(new DOMStorageMap(kPerStorageAreaQuota +
kPerStorageAreaOverQuotaAllowance)),
is_initial_import_done_(true),
is_shutdown_(false),
- commit_batches_in_flight_(0) {
+ commit_batches_in_flight_(0),
+ start_time_(base::TimeTicks::Now()),
+ data_rate_limiter_(kMaxBytesPerHour, base::TimeDelta::FromHours(1)),
+ commit_rate_limiter_(kMaxCommitsPerHour, base::TimeDelta::FromHours(1)) {
if (!directory.empty()) {
base::FilePath path = directory.Append(DatabaseFileNameFromOrigin(origin_));
backing_.reset(new LocalStorageDatabaseAdapter(path));
@@ -73,12 +118,11 @@ DOMStorageArea::DOMStorageArea(
}
}
-DOMStorageArea::DOMStorageArea(
- int64 namespace_id,
- const std::string& persistent_namespace_id,
- const GURL& origin,
- SessionStorageDatabase* session_storage_backing,
- DOMStorageTaskRunner* task_runner)
+DOMStorageArea::DOMStorageArea(int64 namespace_id,
+ const std::string& persistent_namespace_id,
+ const GURL& origin,
+ SessionStorageDatabase* session_storage_backing,
+ DOMStorageTaskRunner* task_runner)
: namespace_id_(namespace_id),
persistent_namespace_id_(persistent_namespace_id),
origin_(origin),
@@ -88,7 +132,10 @@ DOMStorageArea::DOMStorageArea(
session_storage_backing_(session_storage_backing),
is_initial_import_done_(true),
is_shutdown_(false),
- commit_batches_in_flight_(0) {
+ commit_batches_in_flight_(0),
+ start_time_(base::TimeTicks::Now()),
+ data_rate_limiter_(kMaxBytesPerHour, base::TimeDelta::FromHours(1)),
+ commit_rate_limiter_(kMaxCommitsPerHour, base::TimeDelta::FromHours(1)) {
DCHECK(namespace_id != kLocalStorageNamespaceId);
if (session_storage_backing) {
backing_.reset(new SessionStorageDatabaseAdapter(
@@ -137,7 +184,8 @@ bool DOMStorageArea::SetItem(const base::string16& key,
if (!map_->HasOneRef())
map_ = map_->DeepCopy();
bool success = map_->SetItem(key, value, old_value);
- if (success && backing_) {
+ if (success && backing_ &&
+ (old_value->is_null() || old_value->string() != value)) {
CommitBatch* commit_batch = CreateCommitBatchIfNeeded();
commit_batch->changed_values[key] = base::NullableString16(value, false);
}
@@ -212,19 +260,21 @@ DOMStorageArea* DOMStorageArea::ShallowCopy(
copy->is_initial_import_done_ = true;
// All the uncommitted changes to this area need to happen before the actual
- // shallow copy is made (scheduled by the upper layer). Another OnCommitTimer
- // call might be in the event queue at this point, but it's handled gracefully
- // when it fires.
+ // shallow copy is made (scheduled by the upper layer sometime after return).
if (commit_batch_)
- OnCommitTimer();
+ ScheduleImmediateCommit();
return copy;
}
bool DOMStorageArea::HasUncommittedChanges() const {
- DCHECK(!is_shutdown_);
return commit_batch_.get() || commit_batches_in_flight_;
}
+void DOMStorageArea::ScheduleImmediateCommit() {
+ DCHECK(HasUncommittedChanges());
+ PostCommitTask();
+}
+
void DOMStorageArea::DeleteOrigin() {
DCHECK(!is_shutdown_);
// This function shouldn't be called for sessionStorage.
@@ -321,31 +371,62 @@ DOMStorageArea::CommitBatch* DOMStorageArea::CreateCommitBatchIfNeeded() {
DCHECK(!is_shutdown_);
if (!commit_batch_) {
commit_batch_.reset(new CommitBatch());
-
- // Start a timer to commit any changes that accrue in the batch, but only if
- // no commits are currently in flight. In that case the timer will be
- // started after the commits have happened.
- if (!commit_batches_in_flight_) {
- task_runner_->PostDelayedTask(
- FROM_HERE,
- base::Bind(&DOMStorageArea::OnCommitTimer, this),
- base::TimeDelta::FromSeconds(kCommitTimerSeconds));
- }
+ BrowserThread::PostAfterStartupTask(
+ FROM_HERE, task_runner_,
+ base::Bind(&DOMStorageArea::StartCommitTimer, this));
}
return commit_batch_.get();
}
+void DOMStorageArea::StartCommitTimer() {
+ if (is_shutdown_ || !commit_batch_)
+ return;
+
+ // Start a timer to commit any changes that accrue in the batch, but only if
+ // no commits are currently in flight. In that case the timer will be
+ // started after the commits have happened.
+ if (commit_batches_in_flight_)
+ return;
+
+ task_runner_->PostDelayedTask(
+ FROM_HERE, base::Bind(&DOMStorageArea::OnCommitTimer, this),
+ ComputeCommitDelay());
+}
+
+base::TimeDelta DOMStorageArea::ComputeCommitDelay() const {
+ if (s_aggressive_flushing_enabled_)
+ return base::TimeDelta::FromSeconds(1);
+
+ base::TimeDelta elapsed_time = base::TimeTicks::Now() - start_time_;
+ base::TimeDelta delay = std::max(
+ base::TimeDelta::FromSeconds(kCommitDefaultDelaySecs),
+ std::max(commit_rate_limiter_.ComputeDelayNeeded(elapsed_time),
+ data_rate_limiter_.ComputeDelayNeeded(elapsed_time)));
+ UMA_HISTOGRAM_LONG_TIMES("LocalStorage.CommitDelay", delay);
+ return delay;
+}
+
void DOMStorageArea::OnCommitTimer() {
if (is_shutdown_)
return;
- DCHECK(backing_.get());
-
- // It's possible that there is nothing to commit, since a shallow copy occured
- // before the timer fired.
+ // It's possible that there is nothing to commit if an immediate
+ // commit occured after the timer was scheduled but before it fired.
if (!commit_batch_)
return;
+ PostCommitTask();
+}
+
+void DOMStorageArea::PostCommitTask() {
+ if (is_shutdown_ || !commit_batch_)
+ return;
+
+ DCHECK(backing_.get());
+
+ commit_rate_limiter_.add_samples(1);
+ data_rate_limiter_.add_samples(commit_batch_->GetDataSize());
+
// This method executes on the primary sequence, we schedule
// a task for immediate execution on the commit sequence.
DCHECK(task_runner_->IsRunningOnPrimarySequence());
@@ -362,7 +443,7 @@ void DOMStorageArea::CommitChanges(const CommitBatch* commit_batch) {
// This method executes on the commit sequence.
DCHECK(task_runner_->IsRunningOnCommitSequence());
backing_->CommitChanges(commit_batch->clear_all_first,
- commit_batch->changed_values);
+ commit_batch->changed_values);
// TODO(michaeln): what if CommitChanges returns false (e.g., we're trying to
// commit to a DB which is in an inconsistent state?)
task_runner_->PostTask(
@@ -379,9 +460,8 @@ void DOMStorageArea::OnCommitComplete() {
if (commit_batch_.get() && !commit_batches_in_flight_) {
// More changes have accrued, restart the timer.
task_runner_->PostDelayedTask(
- FROM_HERE,
- base::Bind(&DOMStorageArea::OnCommitTimer, this),
- base::TimeDelta::FromSeconds(kCommitTimerSeconds));
+ FROM_HERE, base::Bind(&DOMStorageArea::OnCommitTimer, this),
+ ComputeCommitDelay());
}
}
diff --git a/chromium/content/browser/dom_storage/dom_storage_area.h b/chromium/content/browser/dom_storage/dom_storage_area.h
index ca28be1aa14..dd0df52bdc2 100644
--- a/chromium/content/browser/dom_storage/dom_storage_area.h
+++ b/chromium/content/browser/dom_storage/dom_storage_area.h
@@ -5,6 +5,8 @@
#ifndef CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_AREA_H_
#define CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_AREA_H_
+#include <string>
+
#include "base/files/file_path.h"
#include "base/gtest_prod_util.h"
#include "base/memory/ref_counted.h"
@@ -33,6 +35,12 @@ class CONTENT_EXPORT DOMStorageArea
static base::FilePath DatabaseFileNameFromOrigin(const GURL& origin);
static GURL OriginFromDatabaseFileName(const base::FilePath& file_name);
+ // Commence aggressive flushing. This should be called early in the startup -
+ // before any localStorage writing. Currently scheduled writes will not be
+ // rescheduled and will be flushed at the scheduled time after which
+ // aggressive flushing will commence.
+ static void EnableAggressiveCommitDelay();
+
// Local storage. Backed on disk if directory is nonempty.
DOMStorageArea(const GURL& origin,
const base::FilePath& directory,
@@ -65,6 +73,7 @@ class CONTENT_EXPORT DOMStorageArea
const std::string& destination_persistent_namespace_id);
bool HasUncommittedChanges() const;
+ void ScheduleImmediateCommit();
// Similar to Clear() but more optimized for just deleting
// without raising events.
@@ -92,14 +101,42 @@ class CONTENT_EXPORT DOMStorageArea
FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, CommitChangesAtShutdown);
FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, DeleteOrigin);
FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, PurgeMemory);
+ FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, RateLimiter);
FRIEND_TEST_ALL_PREFIXES(DOMStorageContextImplTest, PersistentIds);
friend class base::RefCountedThreadSafe<DOMStorageArea>;
+ // Used to rate limit commits.
+ class CONTENT_EXPORT RateLimiter {
+ public:
+ RateLimiter(size_t desired_rate, base::TimeDelta time_quantum);
+
+ void add_samples(size_t samples) {
+ samples_ += samples;
+ }
+
+ // Computes the total time needed to process the total samples seen
+ // at the desired rate.
+ base::TimeDelta ComputeTimeNeeded() const;
+
+ // Given the elapsed time since the start of the rate limiting session,
+ // computes the delay needed to mimic having processed the total samples
+ // seen at the desired rate.
+ base::TimeDelta ComputeDelayNeeded(
+ const base::TimeDelta elapsed_time) const;
+
+ private:
+ float rate_;
+ float samples_;
+ base::TimeDelta time_quantum_;
+ };
+
struct CommitBatch {
bool clear_all_first;
DOMStorageValuesMap changed_values;
+
CommitBatch();
~CommitBatch();
+ size_t GetDataSize() const;
};
~DOMStorageArea();
@@ -113,12 +150,17 @@ class CONTENT_EXPORT DOMStorageArea
// disk on the commit sequence, and to call back on the primary
// task sequence when complete.
CommitBatch* CreateCommitBatchIfNeeded();
+ void StartCommitTimer();
void OnCommitTimer();
+ void PostCommitTask();
void CommitChanges(const CommitBatch* commit_batch);
void OnCommitComplete();
+ base::TimeDelta ComputeCommitDelay() const;
void ShutdownInCommitSequence();
+ static bool s_aggressive_flushing_enabled_;
+
int64 namespace_id_;
std::string persistent_namespace_id_;
GURL origin_;
@@ -131,6 +173,11 @@ class CONTENT_EXPORT DOMStorageArea
bool is_shutdown_;
scoped_ptr<CommitBatch> commit_batch_;
int commit_batches_in_flight_;
+ base::TimeTicks start_time_;
+ RateLimiter data_rate_limiter_;
+ RateLimiter commit_rate_limiter_;
+
+ DISALLOW_COPY_AND_ASSIGN(DOMStorageArea);
};
} // namespace content
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 c074cc0709b..aa5653da319 100644
--- a/chromium/content/browser/dom_storage/dom_storage_area_unittest.cc
+++ b/chromium/content/browser/dom_storage/dom_storage_area_unittest.cc
@@ -6,8 +6,8 @@
#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"
#include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
#include "base/threading/sequenced_worker_pool.h"
#include "base/time/time.h"
#include "content/browser/dom_storage/dom_storage_area.h"
@@ -16,6 +16,7 @@
#include "content/browser/dom_storage/dom_storage_task_runner.h"
#include "content/browser/dom_storage/local_storage_database_adapter.h"
#include "content/common/dom_storage/dom_storage_types.h"
+#include "content/public/browser/browser_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::ASCIIToUTF16;
@@ -39,7 +40,20 @@ class DOMStorageAreaTest : public testing::Test {
const base::string16 kValue2;
// Method used in the CommitTasks test case.
- void InjectedCommitSequencingTask(DOMStorageArea* area) {
+ void InjectedCommitSequencingTask1(
+ const scoped_refptr<DOMStorageArea>& area) {
+ // At this point the StartCommitTimer task has run and
+ // the OnCommitTimer task is queued. We want to inject after
+ // that.
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&DOMStorageAreaTest::InjectedCommitSequencingTask2,
+ base::Unretained(this),
+ area));
+ }
+
+ void InjectedCommitSequencingTask2(
+ const scoped_refptr<DOMStorageArea>& area) {
// At this point the OnCommitTimer has run.
// Verify that it put a commit in flight.
EXPECT_EQ(1, area->commit_batches_in_flight_);
@@ -261,13 +275,14 @@ TEST_F(DOMStorageAreaTest, CommitTasks) {
// those will also get committed.
EXPECT_TRUE(area->SetItem(kKey, kValue, &old_value));
EXPECT_TRUE(area->HasUncommittedChanges());
- // At this point the OnCommitTimer task has been posted. We inject
- // another task in the queue that will execute after the timer task,
- // but before the CommitChanges task. From within our injected task,
- // we'll make an additional SetItem() call.
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&DOMStorageAreaTest::InjectedCommitSequencingTask,
+ // At this point the StartCommitTimer task has been posted to the after
+ // startup task queue. We inject another task in the queue that will
+ // execute when the CommitChanges task is inflight. From within our
+ // injected task, we'll make an additional SetItem() call and verify
+ // that a new commit batch is created for that additional change.
+ BrowserThread::PostAfterStartupTask(
+ FROM_HERE, base::ThreadTaskRunnerHandle::Get(),
+ base::Bind(&DOMStorageAreaTest::InjectedCommitSequencingTask1,
base::Unretained(this),
area));
base::MessageLoop::current()->RunUntilIdle();
@@ -472,4 +487,51 @@ TEST_F(DOMStorageAreaTest, DatabaseFileNames) {
base::FilePath().AppendASCII(".extensiononly")));
}
+TEST_F(DOMStorageAreaTest, RateLimiter) {
+ // Limit to 1000 samples per second
+ DOMStorageArea::RateLimiter rate_limiter(
+ 1000, base::TimeDelta::FromSeconds(1));
+
+ // No samples have been added so no time/delay should be needed.
+ EXPECT_EQ(base::TimeDelta(),
+ rate_limiter.ComputeTimeNeeded());
+ EXPECT_EQ(base::TimeDelta(),
+ rate_limiter.ComputeDelayNeeded(base::TimeDelta()));
+ EXPECT_EQ(base::TimeDelta(),
+ rate_limiter.ComputeDelayNeeded(base::TimeDelta::FromDays(1)));
+
+ // Add a seconds worth of samples.
+ rate_limiter.add_samples(1000);
+ EXPECT_EQ(base::TimeDelta::FromSeconds(1),
+ rate_limiter.ComputeTimeNeeded());
+ EXPECT_EQ(base::TimeDelta::FromSeconds(1),
+ rate_limiter.ComputeDelayNeeded(base::TimeDelta()));
+ EXPECT_EQ(base::TimeDelta(),
+ rate_limiter.ComputeDelayNeeded(base::TimeDelta::FromSeconds(1)));
+ EXPECT_EQ(base::TimeDelta::FromMilliseconds(250),
+ rate_limiter.ComputeDelayNeeded(
+ base::TimeDelta::FromMilliseconds(750)));
+ EXPECT_EQ(base::TimeDelta(),
+ rate_limiter.ComputeDelayNeeded(
+ base::TimeDelta::FromDays(1)));
+
+ // And another half seconds worth.
+ rate_limiter.add_samples(500);
+ EXPECT_EQ(base::TimeDelta::FromMilliseconds(1500),
+ rate_limiter.ComputeTimeNeeded());
+ EXPECT_EQ(base::TimeDelta::FromMilliseconds(1500),
+ rate_limiter.ComputeDelayNeeded(base::TimeDelta()));
+ EXPECT_EQ(base::TimeDelta::FromMilliseconds(500),
+ rate_limiter.ComputeDelayNeeded(base::TimeDelta::FromSeconds(1)));
+ EXPECT_EQ(base::TimeDelta::FromMilliseconds(750),
+ rate_limiter.ComputeDelayNeeded(
+ base::TimeDelta::FromMilliseconds(750)));
+ EXPECT_EQ(base::TimeDelta(),
+ rate_limiter.ComputeDelayNeeded(
+ base::TimeDelta::FromMilliseconds(1500)));
+ EXPECT_EQ(base::TimeDelta(),
+ rate_limiter.ComputeDelayNeeded(
+ base::TimeDelta::FromDays(1)));
+}
+
} // namespace content
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 d8e7ac50411..cef7b573dd0 100644
--- a/chromium/content/browser/dom_storage/dom_storage_context_impl.cc
+++ b/chromium/content/browser/dom_storage/dom_storage_context_impl.cc
@@ -4,6 +4,8 @@
#include "content/browser/dom_storage/dom_storage_context_impl.h"
+#include <stdlib.h>
+
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/files/file_enumerator.h"
@@ -26,6 +28,10 @@ namespace content {
static const int kSessionStoraceScavengingSeconds = 60;
+// Offset the session storage namespace ids generated by different contexts
+// to help identify when an id from one is mistakenly used in another.
+static int g_session_id_offset_sequence = 1;
+
DOMStorageContextImpl::DOMStorageContextImpl(
const base::FilePath& localstorage_directory,
const base::FilePath& sessionstorage_directory,
@@ -34,6 +40,7 @@ DOMStorageContextImpl::DOMStorageContextImpl(
: localstorage_directory_(localstorage_directory),
sessionstorage_directory_(sessionstorage_directory),
task_runner_(task_runner),
+ session_id_offset_(abs((g_session_id_offset_sequence++ % 10)) * 1000),
is_shutdown_(false),
force_keep_session_state_(false),
special_storage_policy_(special_storage_policy),
@@ -160,6 +167,11 @@ void DOMStorageContextImpl::DeleteSessionStorage(
NotifyAreaCleared(area, usage_info.origin);
}
+void DOMStorageContextImpl::Flush() {
+ for (auto& entry : namespaces_)
+ entry.second->Flush();
+}
+
void DOMStorageContextImpl::Shutdown() {
is_shutdown_ = true;
StorageNamespaceMap::const_iterator it = namespaces_.begin();
@@ -227,14 +239,8 @@ void DOMStorageContextImpl::NotifyAreaCleared(
OnDOMStorageAreaCleared(area, page_url));
}
-void DOMStorageContextImpl::NotifyAliasSessionMerged(
- int64 namespace_id,
- DOMStorageNamespace* old_alias_master_namespace) {
- FOR_EACH_OBSERVER(
- EventObserver, event_observers_,
- OnDOMSessionStorageReset(namespace_id));
- if (old_alias_master_namespace)
- MaybeShutdownSessionNamespace(old_alias_master_namespace);
+int64 DOMStorageContextImpl::AllocateSessionId() {
+ return session_id_sequence_.GetNext() + session_id_offset_;
}
std::string DOMStorageContextImpl::AllocatePersistentSessionId() {
@@ -261,36 +267,11 @@ void DOMStorageContextImpl::DeleteSessionNamespace(
int64 namespace_id, bool should_persist_data) {
DCHECK_NE(kLocalStorageNamespaceId, namespace_id);
StorageNamespaceMap::const_iterator it = namespaces_.find(namespace_id);
- if (it == namespaces_.end() ||
- it->second->ready_for_deletion_pending_aliases()) {
- return;
- }
- it->second->set_ready_for_deletion_pending_aliases(true);
- DOMStorageNamespace* alias_master = it->second->alias_master_namespace();
- if (alias_master) {
- DCHECK(it->second->num_aliases() == 0);
- DCHECK(alias_master->alias_master_namespace() == NULL);
- if (should_persist_data)
- alias_master->set_must_persist_at_shutdown(true);
- if (it->second->DecrementMasterAliasCount())
- MaybeShutdownSessionNamespace(alias_master);
- namespaces_.erase(namespace_id);
- } else {
- if (should_persist_data)
- it->second->set_must_persist_at_shutdown(true);
- MaybeShutdownSessionNamespace(it->second.get());
- }
-}
-
-void DOMStorageContextImpl::MaybeShutdownSessionNamespace(
- DOMStorageNamespace* ns) {
- if (ns->num_aliases() > 0 || !ns->ready_for_deletion_pending_aliases())
+ if (it == namespaces_.end())
return;
- DCHECK_EQ(ns->num_aliases(), 0);
- DCHECK(ns->alias_master_namespace() == NULL);
- std::string persistent_namespace_id = ns->persistent_namespace_id();
+ std::string persistent_namespace_id = it->second->persistent_namespace_id();
if (session_storage_database_.get()) {
- if (!ns->must_persist_at_shutdown()) {
+ if (!should_persist_data) {
task_runner_->PostShutdownBlockingTask(
FROM_HERE,
DOMStorageTaskRunner::COMMIT_SEQUENCE,
@@ -300,7 +281,7 @@ void DOMStorageContextImpl::MaybeShutdownSessionNamespace(
persistent_namespace_id));
} else {
// Ensure that the data gets committed before we shut down.
- ns->Shutdown();
+ it->second->Shutdown();
if (!scavenging_started_) {
// Protect the persistent namespace ID from scavenging.
protected_persistent_session_ids_.insert(persistent_namespace_id);
@@ -308,7 +289,7 @@ void DOMStorageContextImpl::MaybeShutdownSessionNamespace(
}
}
persistent_namespace_id_to_namespace_id_.erase(persistent_namespace_id);
- namespaces_.erase(ns->namespace_id());
+ namespaces_.erase(namespace_id);
}
void DOMStorageContextImpl::CloneSessionNamespace(
@@ -325,21 +306,6 @@ void DOMStorageContextImpl::CloneSessionNamespace(
CreateSessionNamespace(new_id, new_persistent_id);
}
-void DOMStorageContextImpl::CreateAliasSessionNamespace(
- int64 existing_id, int64 new_id,
- const std::string& persistent_id) {
- if (is_shutdown_)
- return;
- DCHECK_NE(kLocalStorageNamespaceId, existing_id);
- DCHECK_NE(kLocalStorageNamespaceId, new_id);
- StorageNamespaceMap::iterator found = namespaces_.find(existing_id);
- if (found != namespaces_.end()) {
- namespaces_[new_id] = found->second->CreateAlias(new_id);
- } else {
- CreateSessionNamespace(new_id, persistent_id);
- }
-}
-
void DOMStorageContextImpl::ClearSessionOnlyOrigins() {
if (!localstorage_directory_.empty()) {
std::vector<LocalStorageUsageInfo> infos;
@@ -458,39 +424,4 @@ void DOMStorageContextImpl::DeleteNextUnusedNamespaceInCommitSequence() {
}
}
-void DOMStorageContextImpl::AddTransactionLogProcessId(int64 namespace_id,
- int process_id) {
- DCHECK_NE(kLocalStorageNamespaceId, namespace_id);
- StorageNamespaceMap::const_iterator it = namespaces_.find(namespace_id);
- if (it == namespaces_.end())
- return;
- it->second->AddTransactionLogProcessId(process_id);
-}
-
-void DOMStorageContextImpl::RemoveTransactionLogProcessId(int64 namespace_id,
- int process_id) {
- DCHECK_NE(kLocalStorageNamespaceId, namespace_id);
- StorageNamespaceMap::const_iterator it = namespaces_.find(namespace_id);
- if (it == namespaces_.end())
- return;
- it->second->RemoveTransactionLogProcessId(process_id);
-}
-
-SessionStorageNamespace::MergeResult
-DOMStorageContextImpl::MergeSessionStorage(
- int64 namespace1_id, bool actually_merge, int process_id,
- int64 namespace2_id) {
- DCHECK_NE(kLocalStorageNamespaceId, namespace1_id);
- DCHECK_NE(kLocalStorageNamespaceId, namespace2_id);
- StorageNamespaceMap::const_iterator it = namespaces_.find(namespace1_id);
- if (it == namespaces_.end())
- return SessionStorageNamespace::MERGE_RESULT_NAMESPACE_NOT_FOUND;
- 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.get();
- return ns1->Merge(actually_merge, process_id, ns2, this);
-}
-
} // namespace content
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 bd1acbfba22..f71ab6a9d72 100644
--- a/chromium/content/browser/dom_storage/dom_storage_context_impl.h
+++ b/chromium/content/browser/dom_storage/dom_storage_context_impl.h
@@ -7,6 +7,7 @@
#include <map>
#include <set>
+#include <string>
#include <vector>
#include "base/atomic_sequence_num.h"
@@ -16,9 +17,7 @@
#include "base/memory/ref_counted.h"
#include "base/observer_list.h"
#include "base/time/time.h"
-#include "content/browser/dom_storage/dom_storage_namespace.h"
#include "content/common/content_export.h"
-#include "content/public/browser/session_storage_namespace.h"
#include "url/gurl.h"
namespace base {
@@ -34,17 +33,18 @@ class SpecialStoragePolicy;
namespace content {
class DOMStorageArea;
+class DOMStorageNamespace;
class DOMStorageSession;
class DOMStorageTaskRunner;
class SessionStorageDatabase;
struct LocalStorageUsageInfo;
struct SessionStorageUsageInfo;
-// The Context is the root of an object containment hierachy for
+// The Context is the root of an object containment hierarchy for
// Namespaces and Areas related to the owning profile.
// One instance is allocated in the main process for each profile,
// instance methods should be called serially in the background as
-// determined by the task_runner. Specifcally not on chrome's non-blocking
+// determined by the task_runner. Specifically not on chrome's non-blocking
// IO thread since these methods can result in blocking file io.
//
// In general terms, the DOMStorage object relationships are...
@@ -81,9 +81,6 @@ class CONTENT_EXPORT DOMStorageContextImpl
virtual void OnDOMStorageAreaCleared(
const DOMStorageArea* area,
const GURL& page_url) = 0;
- // Indicates that cached values of the DOM Storage provided must be
- // cleared and retrieved again.
- virtual void OnDOMSessionStorageReset(int64 namespace_id) = 0;
protected:
virtual ~EventObserver() {}
@@ -132,10 +129,13 @@ class CONTENT_EXPORT DOMStorageContextImpl
// this method has been called.
void Shutdown();
+ // Initiate the process of flushing (writing - not sync'ing) any unwritten
+ // data managed by this instance. Flushing will start "soon".
+ void Flush();
+
// Methods to add, remove, and notify EventObservers.
void AddEventObserver(EventObserver* observer);
void RemoveEventObserver(EventObserver* observer);
-
void NotifyItemSet(
const DOMStorageArea* area,
const base::string16& key,
@@ -150,15 +150,9 @@ class CONTENT_EXPORT DOMStorageContextImpl
void NotifyAreaCleared(
const DOMStorageArea* area,
const GURL& page_url);
- void NotifyAliasSessionMerged(
- int64 namespace_id,
- DOMStorageNamespace* old_alias_master_namespace);
// May be called on any thread.
- int64 AllocateSessionId() {
- return session_id_sequence_.GetNext();
- }
-
+ int64 AllocateSessionId();
std::string AllocatePersistentSessionId();
// Must be called on the background thread.
@@ -167,8 +161,6 @@ class CONTENT_EXPORT DOMStorageContextImpl
void DeleteSessionNamespace(int64 namespace_id, bool should_persist_data);
void CloneSessionNamespace(int64 existing_id, int64 new_id,
const std::string& new_persistent_id);
- void CreateAliasSessionNamespace(int64 existing_id, int64 new_id,
- const std::string& persistent_id);
// Starts backing sessionStorage on disk. This function must be called right
// after DOMStorageContextImpl is created, before it's used.
@@ -179,13 +171,6 @@ class CONTENT_EXPORT DOMStorageContextImpl
// unclean exit.
void StartScavengingUnusedSessionStorage();
- void AddTransactionLogProcessId(int64 namespace_id, int process_id);
- void RemoveTransactionLogProcessId(int64 namespace_id, int process_id);
-
- SessionStorageNamespace::MergeResult MergeSessionStorage(
- int64 namespace1_id, bool actually_merge, int process_id,
- int64 namespace2_id);
-
private:
friend class DOMStorageContextImplTest;
FRIEND_TEST_ALL_PREFIXES(DOMStorageContextImplTest, Basics);
@@ -193,12 +178,10 @@ class CONTENT_EXPORT DOMStorageContextImpl
typedef std::map<int64, scoped_refptr<DOMStorageNamespace> >
StorageNamespaceMap;
- virtual ~DOMStorageContextImpl();
+ ~DOMStorageContextImpl();
void ClearSessionOnlyOrigins();
- void MaybeShutdownSessionNamespace(DOMStorageNamespace* ns);
-
// For scavenging unused sessionStorages.
void FindUnusedNamespaces();
void FindUnusedNamespacesInCommitSequence(
@@ -226,7 +209,10 @@ class CONTENT_EXPORT DOMStorageContextImpl
// We use a 32 bit identifier for per tab storage sessions.
// At a tab per second, this range is large enough for 68 years.
+ // The offset is to more quickly detect the error condition where
+ // an id related to one context is mistakenly used in another.
base::AtomicSequenceNumber session_id_sequence_;
+ const int session_id_offset_;
bool is_shutdown_;
bool force_keep_session_state_;
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 f3744ab157b..9ea46028b6f 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
@@ -15,7 +15,6 @@
#include "content/browser/dom_storage/dom_storage_namespace.h"
#include "content/browser/dom_storage/dom_storage_task_runner.h"
#include "content/public/browser/local_storage_usage_info.h"
-#include "content/public/browser/session_storage_namespace.h"
#include "content/public/browser/session_storage_usage_info.h"
#include "content/public/test/mock_special_storage_policy.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -64,6 +63,8 @@ class DOMStorageContextImplTest : public testing::Test {
EXPECT_EQ(origin, infos[0].origin);
}
+ int session_id_offset() { return context_->session_id_offset_; }
+
protected:
base::MessageLoop message_loop_;
base::ScopedTempDir temp_dir_;
@@ -81,7 +82,7 @@ TEST_F(DOMStorageContextImplTest, Basics) {
EXPECT_EQ(base::FilePath(), context_->sessionstorage_directory());
EXPECT_EQ(storage_policy_.get(), context_->special_storage_policy_.get());
context_->DeleteLocalStorage(GURL("http://chromium.org/"));
- const int kFirstSessionStorageNamespaceId = 1;
+ const int kFirstSessionStorageNamespaceId = 1 + session_id_offset();
EXPECT_TRUE(context_->GetStorageNamespace(kLocalStorageNamespaceId));
EXPECT_FALSE(context_->GetStorageNamespace(kFirstSessionStorageNamespaceId));
EXPECT_EQ(kFirstSessionStorageNamespaceId, context_->AllocateSessionId());
@@ -163,7 +164,7 @@ TEST_F(DOMStorageContextImplTest, SetForceKeepSessionState) {
}
TEST_F(DOMStorageContextImplTest, PersistentIds) {
- const int kFirstSessionStorageNamespaceId = 1;
+ const int kFirstSessionStorageNamespaceId = 1 + session_id_offset();
const std::string kPersistentId = "persistent";
context_->CreateSessionNamespace(kFirstSessionStorageNamespaceId,
kPersistentId);
@@ -176,7 +177,7 @@ TEST_F(DOMStorageContextImplTest, PersistentIds) {
EXPECT_EQ(kPersistentId, area->persistent_namespace_id_);
// Verify that the persistent IDs are handled correctly when cloning.
- const int kClonedSessionStorageNamespaceId = 2;
+ const int kClonedSessionStorageNamespaceId = 2 + session_id_offset();
const std::string kClonedPersistentId = "cloned";
context_->CloneSessionNamespace(kFirstSessionStorageNamespaceId,
kClonedSessionStorageNamespaceId,
@@ -201,7 +202,7 @@ TEST_F(DOMStorageContextImplTest, DeleteSessionStorage) {
ASSERT_EQ(temp_dir_.path(), context_->sessionstorage_directory());
// Write data.
- const int kSessionStorageNamespaceId = 1;
+ const int kSessionStorageNamespaceId = 1 + session_id_offset();
const std::string kPersistentId = "persistent";
context_->CreateSessionNamespace(kSessionStorageNamespaceId,
kPersistentId);
@@ -260,115 +261,4 @@ TEST_F(DOMStorageContextImplTest, DeleteSessionStorage) {
base::MessageLoop::current()->RunUntilIdle();
}
-TEST_F(DOMStorageContextImplTest, SessionStorageAlias) {
- const int kFirstSessionStorageNamespaceId = 1;
- const std::string kPersistentId = "persistent";
- context_->CreateSessionNamespace(kFirstSessionStorageNamespaceId,
- kPersistentId);
- DOMStorageNamespace* dom_namespace1 =
- context_->GetStorageNamespace(kFirstSessionStorageNamespaceId);
- ASSERT_TRUE(dom_namespace1);
- DOMStorageArea* area1 = dom_namespace1->OpenStorageArea(kOrigin);
- base::NullableString16 old_value;
- area1->SetItem(kKey, kValue, &old_value);
- EXPECT_TRUE(old_value.is_null());
- base::NullableString16 read_value = area1->GetItem(kKey);
- EXPECT_TRUE(!read_value.is_null() && read_value.string() == kValue);
-
- // Create an alias.
- const int kAliasSessionStorageNamespaceId = 2;
- context_->CreateAliasSessionNamespace(kFirstSessionStorageNamespaceId,
- kAliasSessionStorageNamespaceId,
- kPersistentId);
- DOMStorageNamespace* dom_namespace2 =
- context_->GetStorageNamespace(kAliasSessionStorageNamespaceId);
- ASSERT_TRUE(dom_namespace2);
- ASSERT_TRUE(dom_namespace2->alias_master_namespace() == dom_namespace1);
-
- // Verify that read values are identical.
- DOMStorageArea* area2 = dom_namespace2->OpenStorageArea(kOrigin);
- read_value = area2->GetItem(kKey);
- EXPECT_TRUE(!read_value.is_null() && read_value.string() == kValue);
-
- // Verify that writes are reflected in both namespaces.
- const base::string16 kValue2(ASCIIToUTF16("value2"));
- area2->SetItem(kKey, kValue2, &old_value);
- read_value = area1->GetItem(kKey);
- EXPECT_TRUE(!read_value.is_null() && read_value.string() == kValue2);
- dom_namespace1->CloseStorageArea(area1);
- dom_namespace2->CloseStorageArea(area2);
-
- // When creating an alias of an alias, ensure that the master relationship
- // is collapsed.
- const int kAlias2SessionStorageNamespaceId = 3;
- context_->CreateAliasSessionNamespace(kAliasSessionStorageNamespaceId,
- kAlias2SessionStorageNamespaceId,
- kPersistentId);
- DOMStorageNamespace* dom_namespace3 =
- context_->GetStorageNamespace(kAlias2SessionStorageNamespaceId);
- ASSERT_TRUE(dom_namespace3);
- ASSERT_TRUE(dom_namespace3->alias_master_namespace() == dom_namespace1);
-}
-
-TEST_F(DOMStorageContextImplTest, SessionStorageMerge) {
- // Create a target namespace that we will merge into.
- const int kTargetSessionStorageNamespaceId = 1;
- const std::string kTargetPersistentId = "persistent";
- context_->CreateSessionNamespace(kTargetSessionStorageNamespaceId,
- kTargetPersistentId);
- DOMStorageNamespace* target_ns =
- context_->GetStorageNamespace(kTargetSessionStorageNamespaceId);
- ASSERT_TRUE(target_ns);
- DOMStorageArea* target_ns_area = target_ns->OpenStorageArea(kOrigin);
- base::NullableString16 old_value;
- const base::string16 kKey2(ASCIIToUTF16("key2"));
- const base::string16 kKey2Value(ASCIIToUTF16("key2value"));
- target_ns_area->SetItem(kKey, kValue, &old_value);
- target_ns_area->SetItem(kKey2, kKey2Value, &old_value);
-
- // Create a source namespace & its alias.
- const int kSourceSessionStorageNamespaceId = 2;
- const int kAliasSessionStorageNamespaceId = 3;
- const std::string kSourcePersistentId = "persistent_source";
- context_->CreateSessionNamespace(kSourceSessionStorageNamespaceId,
- kSourcePersistentId);
- context_->CreateAliasSessionNamespace(kSourceSessionStorageNamespaceId,
- kAliasSessionStorageNamespaceId,
- kSourcePersistentId);
- DOMStorageNamespace* alias_ns =
- context_->GetStorageNamespace(kAliasSessionStorageNamespaceId);
- ASSERT_TRUE(alias_ns);
-
- // Create a transaction log that can't be merged.
- const int kPid1 = 10;
- ASSERT_FALSE(alias_ns->IsLoggingRenderer(kPid1));
- alias_ns->AddTransactionLogProcessId(kPid1);
- ASSERT_TRUE(alias_ns->IsLoggingRenderer(kPid1));
- const base::string16 kValue2(ASCIIToUTF16("value2"));
- DOMStorageNamespace::TransactionRecord txn;
- txn.origin = kOrigin;
- txn.key = kKey;
- txn.value = base::NullableString16(kValue2, false);
- txn.transaction_type = DOMStorageNamespace::TRANSACTION_READ;
- alias_ns->AddTransaction(kPid1, txn);
- ASSERT_TRUE(alias_ns->Merge(false, kPid1, target_ns, NULL) ==
- SessionStorageNamespace::MERGE_RESULT_NOT_MERGEABLE);
-
- // Create a transaction log that can be merged.
- const int kPid2 = 20;
- alias_ns->AddTransactionLogProcessId(kPid2);
- txn.transaction_type = DOMStorageNamespace::TRANSACTION_WRITE;
- alias_ns->AddTransaction(kPid2, txn);
- ASSERT_TRUE(alias_ns->Merge(true, kPid2, target_ns, NULL) ==
- SessionStorageNamespace::MERGE_RESULT_MERGEABLE);
-
- // Verify that the merge was successful.
- ASSERT_TRUE(alias_ns->alias_master_namespace() == target_ns);
- base::NullableString16 read_value = target_ns_area->GetItem(kKey);
- EXPECT_TRUE(!read_value.is_null() && read_value.string() == kValue2);
- DOMStorageArea* alias_ns_area = alias_ns->OpenStorageArea(kOrigin);
- read_value = alias_ns_area->GetItem(kKey2);
- EXPECT_TRUE(!read_value.is_null() && read_value.string() == kKey2Value);
-}
-
} // namespace content
diff --git a/chromium/content/browser/dom_storage/dom_storage_context_wrapper.cc b/chromium/content/browser/dom_storage/dom_storage_context_wrapper.cc
index d483d9b57a7..fef44e8eff3 100644
--- a/chromium/content/browser/dom_storage/dom_storage_context_wrapper.cc
+++ b/chromium/content/browser/dom_storage/dom_storage_context_wrapper.cc
@@ -4,6 +4,9 @@
#include "content/browser/dom_storage/dom_storage_context_wrapper.h"
+#include <string>
+#include <vector>
+
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/files/file_path.h"
@@ -162,4 +165,11 @@ void DOMStorageContextWrapper::Shutdown() {
base::Bind(&DOMStorageContextImpl::Shutdown, context_));
}
+void DOMStorageContextWrapper::Flush() {
+ DCHECK(context_.get());
+ context_->task_runner()->PostShutdownBlockingTask(
+ FROM_HERE, DOMStorageTaskRunner::PRIMARY_SEQUENCE,
+ base::Bind(&DOMStorageContextImpl::Flush, context_));
+}
+
} // namespace content
diff --git a/chromium/content/browser/dom_storage/dom_storage_context_wrapper.h b/chromium/content/browser/dom_storage/dom_storage_context_wrapper.h
index efd50914890..6ef2abf84f0 100644
--- a/chromium/content/browser/dom_storage/dom_storage_context_wrapper.h
+++ b/chromium/content/browser/dom_storage/dom_storage_context_wrapper.h
@@ -5,6 +5,8 @@
#ifndef CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_CONTEXT_WRAPPER_H_
#define CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_CONTEXT_WRAPPER_H_
+#include <string>
+
#include "base/memory/ref_counted.h"
#include "content/common/content_export.h"
#include "content/public/browser/dom_storage_context.h"
@@ -53,6 +55,8 @@ class CONTENT_EXPORT DOMStorageContextWrapper :
// Called when the BrowserContext/Profile is going away.
void Shutdown();
+ void Flush();
+
private:
friend class DOMStorageMessageFilter; // for access to context()
friend class SessionStorageNamespaceImpl; // ditto
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 20b714c039b..caea649f970 100644
--- a/chromium/content/browser/dom_storage/dom_storage_database_unittest.cc
+++ b/chromium/content/browser/dom_storage/dom_storage_database_unittest.cc
@@ -13,7 +13,6 @@
#include "sql/statement.h"
#include "sql/test/scoped_error_ignorer.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/sqlite/sqlite3.h"
using base::ASCIIToUTF16;
@@ -349,7 +348,15 @@ TEST(DOMStorageDatabaseTest, TestCanOpenFileThatIsNotADatabase) {
{
sql::ScopedErrorIgnorer ignore_errors;
- ignore_errors.IgnoreError(SQLITE_IOERR_SHORT_READ);
+
+ // Earlier versions of Chromium compiled against SQLite 3.6.7.3, which
+ // returned SQLITE_IOERR_SHORT_READ in this case. Some platforms may still
+ // compile against an earlier SQLite via USE_SYSTEM_SQLITE.
+ if (ignore_errors.SQLiteLibVersionNumber() < 3008005) {
+ ignore_errors.IgnoreError(SQLITE_IOERR_SHORT_READ);
+ } else {
+ ignore_errors.IgnoreError(SQLITE_NOTADB);
+ }
// Try and open the file. As it's not a database, we should end up deleting
// it and creating a new, valid file, so everything should actually
diff --git a/chromium/content/browser/dom_storage/dom_storage_host.cc b/chromium/content/browser/dom_storage/dom_storage_host.cc
index 556f76d5c0f..14d288d8653 100644
--- a/chromium/content/browser/dom_storage/dom_storage_host.cc
+++ b/chromium/content/browser/dom_storage/dom_storage_host.cc
@@ -12,10 +12,8 @@
namespace content {
-DOMStorageHost::DOMStorageHost(DOMStorageContextImpl* context,
- int render_process_id)
- : context_(context),
- render_process_id_(render_process_id) {
+DOMStorageHost::DOMStorageHost(DOMStorageContextImpl* context)
+ : context_(context) {
}
DOMStorageHost::~DOMStorageHost() {
@@ -49,7 +47,7 @@ void DOMStorageHost::CloseStorageArea(int connection_id) {
}
bool DOMStorageHost::ExtractAreaValues(
- int connection_id, DOMStorageValuesMap* map, bool* send_log_get_messages) {
+ int connection_id, DOMStorageValuesMap* map) {
map->clear();
DOMStorageArea* area = GetOpenArea(connection_id);
if (!area)
@@ -64,10 +62,6 @@ bool DOMStorageHost::ExtractAreaValues(
}
}
area->ExtractValues(map);
- *send_log_get_messages = false;
- DOMStorageNamespace* ns = GetNamespace(connection_id);
- DCHECK(ns);
- *send_log_get_messages = ns->IsLoggingRenderer(render_process_id_);
return true;
}
@@ -105,24 +99,9 @@ bool DOMStorageHost::SetAreaItem(
return false;
if (old_value->is_null() || old_value->string() != value)
context_->NotifyItemSet(area, key, value, *old_value, page_url);
- MaybeLogTransaction(connection_id,
- DOMStorageNamespace::TRANSACTION_WRITE,
- area->origin(), page_url, key,
- base::NullableString16(value, false));
return true;
}
-void DOMStorageHost::LogGetAreaItem(
- int connection_id, const base::string16& key,
- const base::NullableString16& value) {
- DOMStorageArea* area = GetOpenArea(connection_id);
- if (!area)
- return;
- MaybeLogTransaction(connection_id,
- DOMStorageNamespace::TRANSACTION_READ,
- area->origin(), GURL(), key, value);
-}
-
bool DOMStorageHost::RemoveAreaItem(
int connection_id, const base::string16& key, const GURL& page_url,
base::string16* old_value) {
@@ -132,9 +111,6 @@ bool DOMStorageHost::RemoveAreaItem(
if (!area->RemoveItem(key, old_value))
return false;
context_->NotifyItemRemoved(area, key, *old_value, page_url);
- MaybeLogTransaction(connection_id,
- DOMStorageNamespace::TRANSACTION_REMOVE,
- area->origin(), page_url, key, base::NullableString16());
return true;
}
@@ -145,40 +121,21 @@ bool DOMStorageHost::ClearArea(int connection_id, const GURL& page_url) {
if (!area->Clear())
return false;
context_->NotifyAreaCleared(area, page_url);
- MaybeLogTransaction(connection_id,
- DOMStorageNamespace::TRANSACTION_CLEAR,
- area->origin(), page_url, base::string16(),
- base::NullableString16());
return true;
}
bool DOMStorageHost::HasAreaOpen(
- int64 namespace_id, const GURL& origin, int64* alias_namespace_id) const {
+ int namespace_id, const GURL& origin) const {
AreaMap::const_iterator it = connections_.begin();
for (; it != connections_.end(); ++it) {
- if (namespace_id == it->second.area_->namespace_id() &&
+ if (namespace_id == it->second.namespace_->namespace_id() &&
origin == it->second.area_->origin()) {
- *alias_namespace_id = it->second.namespace_->namespace_id();
return true;
}
}
return false;
}
-bool DOMStorageHost::ResetOpenAreasForNamespace(int64 namespace_id) {
- bool result = false;
- AreaMap::iterator it = connections_.begin();
- for (; it != connections_.end(); ++it) {
- if (namespace_id == it->second.namespace_->namespace_id()) {
- GURL origin = it->second.area_->origin();
- it->second.namespace_->CloseStorageArea(it->second.area_.get());
- it->second.area_ = it->second.namespace_->OpenStorageArea(origin);
- result = true;
- }
- }
- return result;
-}
-
DOMStorageArea* DOMStorageHost::GetOpenArea(int connection_id) {
AreaMap::iterator found = connections_.find(connection_id);
if (found == connections_.end())
@@ -193,26 +150,6 @@ DOMStorageNamespace* DOMStorageHost::GetNamespace(int connection_id) {
return found->second.namespace_.get();
}
-void DOMStorageHost::MaybeLogTransaction(
- int connection_id,
- DOMStorageNamespace::LogType transaction_type,
- const GURL& origin,
- const GURL& page_url,
- const base::string16& key,
- const base::NullableString16& value) {
- DOMStorageNamespace* ns = GetNamespace(connection_id);
- DCHECK(ns);
- if (!ns->IsLoggingRenderer(render_process_id_))
- return;
- DOMStorageNamespace::TransactionRecord transaction;
- transaction.transaction_type = transaction_type;
- transaction.origin = origin;
- transaction.page_url = page_url;
- transaction.key = key;
- transaction.value = value;
- ns->AddTransaction(render_process_id_, transaction);
-}
-
// NamespaceAndArea
DOMStorageHost::NamespaceAndArea::NamespaceAndArea() {}
diff --git a/chromium/content/browser/dom_storage/dom_storage_host.h b/chromium/content/browser/dom_storage/dom_storage_host.h
index 10d59198f23..a6289076f87 100644
--- a/chromium/content/browser/dom_storage/dom_storage_host.h
+++ b/chromium/content/browser/dom_storage/dom_storage_host.h
@@ -10,7 +10,6 @@
#include "base/memory/ref_counted.h"
#include "base/strings/nullable_string16.h"
#include "base/strings/string16.h"
-#include "content/browser/dom_storage/dom_storage_namespace.h"
#include "content/common/content_export.h"
#include "content/common/dom_storage/dom_storage_types.h"
@@ -30,14 +29,13 @@ class DOMStorageArea;
// See class comments for DOMStorageContextImpl for a larger overview.
class CONTENT_EXPORT DOMStorageHost {
public:
- DOMStorageHost(DOMStorageContextImpl* context, int render_process_id);
+ explicit DOMStorageHost(DOMStorageContextImpl* context);
~DOMStorageHost();
bool OpenStorageArea(int connection_id, int namespace_id,
const GURL& origin);
void CloseStorageArea(int connection_id);
- bool ExtractAreaValues(int connection_id, DOMStorageValuesMap* map,
- bool* send_log_get_messages);
+ bool ExtractAreaValues(int connection_id, DOMStorageValuesMap* map);
unsigned GetAreaLength(int connection_id);
base::NullableString16 GetAreaKey(int connection_id, unsigned index);
base::NullableString16 GetAreaItem(int connection_id,
@@ -45,17 +43,11 @@ class CONTENT_EXPORT DOMStorageHost {
bool SetAreaItem(int connection_id, const base::string16& key,
const base::string16& value, const GURL& page_url,
base::NullableString16* old_value);
- void LogGetAreaItem(int connection_id, const base::string16& key,
- const base::NullableString16& value);
bool RemoveAreaItem(int connection_id, const base::string16& key,
const GURL& page_url,
base::string16* old_value);
bool ClearArea(int connection_id, const GURL& page_url);
- bool HasAreaOpen(int64 namespace_id, const GURL& origin,
- int64* alias_namespace_id) const;
- // Resets all open areas for the namespace provided. Returns true
- // iff there were any areas to reset.
- bool ResetOpenAreasForNamespace(int64 namespace_id);
+ bool HasAreaOpen(int namespace_id, const GURL& origin) const;
private:
// Struct to hold references needed for areas that are open
@@ -70,17 +62,9 @@ class CONTENT_EXPORT DOMStorageHost {
DOMStorageArea* GetOpenArea(int connection_id);
DOMStorageNamespace* GetNamespace(int connection_id);
- void MaybeLogTransaction(
- int connection_id,
- DOMStorageNamespace::LogType transaction_type,
- const GURL& origin,
- const GURL& page_url,
- const base::string16& key,
- const base::NullableString16& value);
scoped_refptr<DOMStorageContextImpl> context_;
AreaMap connections_;
- int render_process_id_;
DISALLOW_COPY_AND_ASSIGN(DOMStorageHost);
};
diff --git a/chromium/content/browser/dom_storage/dom_storage_message_filter.cc b/chromium/content/browser/dom_storage/dom_storage_message_filter.cc
index 91d72d32762..ca3bcc5ac3b 100644
--- a/chromium/content/browser/dom_storage/dom_storage_message_filter.cc
+++ b/chromium/content/browser/dom_storage/dom_storage_message_filter.cc
@@ -21,10 +21,8 @@
namespace content {
DOMStorageMessageFilter::DOMStorageMessageFilter(
- int render_process_id,
DOMStorageContextWrapper* context)
: BrowserMessageFilter(DOMStorageMsgStart),
- render_process_id_(render_process_id),
context_(context->context()),
connection_dispatching_message_for_(0) {
}
@@ -35,7 +33,7 @@ DOMStorageMessageFilter::~DOMStorageMessageFilter() {
void DOMStorageMessageFilter::InitializeInSequence() {
DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
- host_.reset(new DOMStorageHost(context_.get(), render_process_id_));
+ host_.reset(new DOMStorageHost(context_.get()));
context_->AddEventObserver(this);
}
@@ -80,7 +78,6 @@ bool DOMStorageMessageFilter::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(DOMStorageHostMsg_CloseStorageArea, OnCloseStorageArea)
IPC_MESSAGE_HANDLER(DOMStorageHostMsg_LoadStorageArea, OnLoadStorageArea)
IPC_MESSAGE_HANDLER(DOMStorageHostMsg_SetItem, OnSetItem)
- IPC_MESSAGE_HANDLER(DOMStorageHostMsg_LogGetItem, OnLogGetItem)
IPC_MESSAGE_HANDLER(DOMStorageHostMsg_RemoveItem, OnRemoveItem)
IPC_MESSAGE_HANDLER(DOMStorageHostMsg_Clear, OnClear)
IPC_MESSAGE_HANDLER(DOMStorageHostMsg_FlushMessages, OnFlushMessages)
@@ -105,10 +102,9 @@ void DOMStorageMessageFilter::OnCloseStorageArea(int connection_id) {
}
void DOMStorageMessageFilter::OnLoadStorageArea(int connection_id,
- DOMStorageValuesMap* map,
- bool* send_log_get_messages) {
+ DOMStorageValuesMap* map) {
DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
- if (!host_->ExtractAreaValues(connection_id, map, send_log_get_messages)) {
+ if (!host_->ExtractAreaValues(connection_id, map)) {
RecordAction(base::UserMetricsAction("BadMessageTerminate_DSMF_2"));
BadMessageReceived();
}
@@ -128,13 +124,6 @@ void DOMStorageMessageFilter::OnSetItem(
Send(new DOMStorageMsg_AsyncOperationComplete(success));
}
-void DOMStorageMessageFilter::OnLogGetItem(
- int connection_id, const base::string16& key,
- const base::NullableString16& value) {
- DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
- host_->LogGetAreaItem(connection_id, key, value);
-}
-
void DOMStorageMessageFilter::OnRemoveItem(
int connection_id, const base::string16& key,
const GURL& page_url) {
@@ -193,11 +182,6 @@ void DOMStorageMessageFilter::OnDOMStorageAreaCleared(
base::NullableString16());
}
-void DOMStorageMessageFilter::OnDOMSessionStorageReset(int64 namespace_id) {
- if (host_->ResetOpenAreasForNamespace(namespace_id))
- Send(new DOMStorageMsg_ResetCachedValues(namespace_id));
-}
-
void DOMStorageMessageFilter::SendDOMStorageEvent(
const DOMStorageArea* area,
const GURL& page_url,
@@ -207,10 +191,8 @@ void DOMStorageMessageFilter::SendDOMStorageEvent(
DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
// Only send mutation events to processes which have the area open.
bool originated_in_process = connection_dispatching_message_for_ != 0;
- int64 alias_namespace_id = area->namespace_id();
- if (host_->HasAreaOpen(area->namespace_id(), area->origin(),
- &alias_namespace_id) ||
- originated_in_process) {
+ if (originated_in_process ||
+ host_->HasAreaOpen(area->namespace_id(), area->origin())) {
DOMStorageMsg_Event_Params params;
params.origin = area->origin();
params.page_url = page_url;
@@ -218,7 +200,7 @@ void DOMStorageMessageFilter::SendDOMStorageEvent(
params.key = key;
params.new_value = new_value;
params.old_value = old_value;
- params.namespace_id = alias_namespace_id;
+ params.namespace_id = area->namespace_id();
Send(new DOMStorageMsg_Event(params));
}
}
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 d93acfd06f6..8ac75233007 100644
--- a/chromium/content/browser/dom_storage/dom_storage_message_filter.h
+++ b/chromium/content/browser/dom_storage/dom_storage_message_filter.h
@@ -30,8 +30,7 @@ class DOMStorageMessageFilter
: public BrowserMessageFilter,
public DOMStorageContextImpl::EventObserver {
public:
- explicit DOMStorageMessageFilter(int render_process_id,
- DOMStorageContextWrapper* context);
+ explicit DOMStorageMessageFilter(DOMStorageContextWrapper* context);
private:
~DOMStorageMessageFilter() override;
@@ -50,12 +49,9 @@ class DOMStorageMessageFilter
void OnOpenStorageArea(int connection_id, int64 namespace_id,
const GURL& origin);
void OnCloseStorageArea(int connection_id);
- void OnLoadStorageArea(int connection_id, DOMStorageValuesMap* map,
- bool* send_log_get_messages);
+ void OnLoadStorageArea(int connection_id, DOMStorageValuesMap* map);
void OnSetItem(int connection_id, const base::string16& key,
const base::string16& value, const GURL& page_url);
- void OnLogGetItem(int connection_id, const base::string16& key,
- const base::NullableString16& value);
void OnRemoveItem(int connection_id, const base::string16& key,
const GURL& page_url);
void OnClear(int connection_id, const GURL& page_url);
@@ -74,7 +70,6 @@ class DOMStorageMessageFilter
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,
@@ -83,7 +78,6 @@ class DOMStorageMessageFilter
const base::NullableString16& new_value,
const base::NullableString16& old_value);
- int render_process_id_;
scoped_refptr<DOMStorageContextImpl> context_;
scoped_ptr<DOMStorageHost> host_;
int connection_dispatching_message_for_;
diff --git a/chromium/content/browser/dom_storage/dom_storage_namespace.cc b/chromium/content/browser/dom_storage/dom_storage_namespace.cc
index fb76b6764ed..f554ac58814 100644
--- a/chromium/content/browser/dom_storage/dom_storage_namespace.cc
+++ b/chromium/content/browser/dom_storage/dom_storage_namespace.cc
@@ -4,40 +4,23 @@
#include "content/browser/dom_storage/dom_storage_namespace.h"
-#include <set>
-#include <utility>
-
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/location.h"
#include "base/logging.h"
-#include "base/stl_util.h"
#include "content/browser/dom_storage/dom_storage_area.h"
-#include "content/browser/dom_storage/dom_storage_context_impl.h"
#include "content/browser/dom_storage/dom_storage_task_runner.h"
#include "content/browser/dom_storage/session_storage_database.h"
#include "content/common/dom_storage/dom_storage_types.h"
-#include "content/public/common/child_process_host.h"
namespace content {
-namespace {
-
-static const unsigned int kMaxTransactionLogEntries = 8 * 1024;
-
-} // namespace
-
DOMStorageNamespace::DOMStorageNamespace(
const base::FilePath& directory,
DOMStorageTaskRunner* task_runner)
: namespace_id_(kLocalStorageNamespaceId),
directory_(directory),
- task_runner_(task_runner),
- num_aliases_(0),
- old_master_for_close_area_(NULL),
- master_alias_count_decremented_(false),
- ready_for_deletion_pending_aliases_(false),
- must_persist_at_shutdown_(false) {
+ task_runner_(task_runner) {
}
DOMStorageNamespace::DOMStorageNamespace(
@@ -48,23 +31,14 @@ DOMStorageNamespace::DOMStorageNamespace(
: namespace_id_(namespace_id),
persistent_namespace_id_(persistent_namespace_id),
task_runner_(task_runner),
- session_storage_database_(session_storage_database),
- num_aliases_(0),
- old_master_for_close_area_(NULL),
- master_alias_count_decremented_(false),
- ready_for_deletion_pending_aliases_(false),
- must_persist_at_shutdown_(false) {
+ session_storage_database_(session_storage_database) {
DCHECK_NE(kLocalStorageNamespaceId, namespace_id);
}
DOMStorageNamespace::~DOMStorageNamespace() {
- STLDeleteValues(&transactions_);
- DecrementMasterAliasCount();
}
DOMStorageArea* DOMStorageNamespace::OpenStorageArea(const GURL& origin) {
- if (alias_master_namespace_.get())
- return alias_master_namespace_->OpenStorageArea(origin);
if (AreaHolder* holder = GetAreaHolder(origin)) {
++(holder->open_count_);
return holder->area_.get();
@@ -83,14 +57,6 @@ DOMStorageArea* DOMStorageNamespace::OpenStorageArea(const GURL& origin) {
void DOMStorageNamespace::CloseStorageArea(DOMStorageArea* area) {
AreaHolder* holder = GetAreaHolder(area->origin());
- if (alias_master_namespace_.get()) {
- DCHECK(!holder);
- if (old_master_for_close_area_)
- old_master_for_close_area_->CloseStorageArea(area);
- else
- alias_master_namespace_->CloseStorageArea(area);
- return;
- }
DCHECK(holder);
DCHECK_EQ(holder->area_.get(), area);
--(holder->open_count_);
@@ -99,8 +65,6 @@ void DOMStorageNamespace::CloseStorageArea(DOMStorageArea* area) {
}
DOMStorageArea* DOMStorageNamespace::GetOpenStorageArea(const GURL& origin) {
- if (alias_master_namespace_.get())
- return alias_master_namespace_->GetOpenStorageArea(origin);
AreaHolder* holder = GetAreaHolder(origin);
if (holder && holder->open_count_)
return holder->area_.get();
@@ -110,10 +74,6 @@ DOMStorageArea* DOMStorageNamespace::GetOpenStorageArea(const GURL& origin) {
DOMStorageNamespace* DOMStorageNamespace::Clone(
int64 clone_namespace_id,
const std::string& clone_persistent_namespace_id) {
- if (alias_master_namespace_.get()) {
- return alias_master_namespace_->Clone(clone_namespace_id,
- clone_persistent_namespace_id);
- }
DCHECK_NE(kLocalStorageNamespaceId, namespace_id_);
DCHECK_NE(kLocalStorageNamespaceId, clone_namespace_id);
DOMStorageNamespace* clone = new DOMStorageNamespace(
@@ -138,34 +98,8 @@ DOMStorageNamespace* DOMStorageNamespace::Clone(
return clone;
}
-DOMStorageNamespace* DOMStorageNamespace::CreateAlias(
- int64 alias_namespace_id) {
- // Creates an alias of the current DOMStorageNamespace.
- // The alias will have a reference to this namespace (called the master),
- // and all operations will be redirected to the master (in particular,
- // the alias will never open any areas of its own, but always redirect
- // to the master). Accordingly, an alias will also never undergo the shutdown
- // procedure which initiates persisting to disk, since there is never any data
- // of its own to persist to disk. DOMStorageContextImpl is the place where
- // shutdowns are initiated, but only for non-alias DOMStorageNamespaces.
- DCHECK_NE(kLocalStorageNamespaceId, namespace_id_);
- DCHECK_NE(kLocalStorageNamespaceId, alias_namespace_id);
- DOMStorageNamespace* alias = new DOMStorageNamespace(
- alias_namespace_id, persistent_namespace_id_,
- session_storage_database_.get(), task_runner_.get());
- 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;
- }
- alias->alias_master_namespace_->num_aliases_++;
- return alias;
-}
-
void DOMStorageNamespace::DeleteLocalStorageOrigin(const GURL& origin) {
DCHECK(!session_storage_database_.get());
- DCHECK(!alias_master_namespace_.get());
AreaHolder* holder = GetAreaHolder(origin);
if (holder) {
holder->area_->DeleteOrigin();
@@ -179,34 +113,33 @@ void DOMStorageNamespace::DeleteLocalStorageOrigin(const GURL& origin) {
}
void DOMStorageNamespace::DeleteSessionStorageOrigin(const GURL& origin) {
- if (alias_master_namespace_.get()) {
- alias_master_namespace_->DeleteSessionStorageOrigin(origin);
- return;
- }
DOMStorageArea* area = OpenStorageArea(origin);
area->FastClear();
CloseStorageArea(area);
}
void DOMStorageNamespace::PurgeMemory(PurgeOption option) {
- if (alias_master_namespace_.get()) {
- alias_master_namespace_->PurgeMemory(option);
- return;
- }
if (directory_.empty())
return; // We can't purge w/o backing on disk.
AreaMap::iterator it = areas_.begin();
while (it != areas_.end()) {
- // Leave it alone if changes are pending
- if (it->second.area_->HasUncommittedChanges()) {
+ const AreaHolder& holder = it->second;
+
+ // We can't purge if there are changes pending.
+ if (holder.area_->HasUncommittedChanges()) {
+ if (holder.open_count_ == 0) {
+ // Schedule an immediate commit so the next time we're asked to purge,
+ // we can drop it from memory.
+ holder.area_->ScheduleImmediateCommit();
+ }
++it;
continue;
}
// If not in use, we can shut it down and remove
// it from our collection entirely.
- if (it->second.open_count_ == 0) {
- it->second.area_->Shutdown();
+ if (holder.open_count_ == 0) {
+ holder.area_->Shutdown();
areas_.erase(it++);
continue;
}
@@ -214,7 +147,7 @@ void DOMStorageNamespace::PurgeMemory(PurgeOption option) {
if (option == PURGE_AGGRESSIVE) {
// If aggressive is true, we clear caches and such
// for opened areas.
- it->second.area_->PurgeMemory();
+ holder.area_->PurgeMemory();
}
++it;
@@ -227,9 +160,15 @@ void DOMStorageNamespace::Shutdown() {
it->second.area_->Shutdown();
}
+void DOMStorageNamespace::Flush() {
+ for (auto& entry : areas_) {
+ if (!entry.second.area_->HasUncommittedChanges())
+ continue;
+ entry.second.area_->ScheduleImmediateCommit();
+ }
+}
+
unsigned int DOMStorageNamespace::CountInMemoryAreas() const {
- 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) {
if (it->second.area_->IsLoadedInMemory())
@@ -246,187 +185,6 @@ DOMStorageNamespace::GetAreaHolder(const GURL& origin) {
return &(found->second);
}
-void DOMStorageNamespace::AddTransactionLogProcessId(int process_id) {
- DCHECK(process_id != ChildProcessHost::kInvalidUniqueID);
- DCHECK(transactions_.count(process_id) == 0);
- TransactionData* transaction_data = new TransactionData;
- transactions_[process_id] = transaction_data;
-}
-
-void DOMStorageNamespace::RemoveTransactionLogProcessId(int process_id) {
- DCHECK(process_id != ChildProcessHost::kInvalidUniqueID);
- DCHECK(transactions_.count(process_id) == 1);
- delete transactions_[process_id];
- transactions_.erase(process_id);
-}
-
-SessionStorageNamespace::MergeResult DOMStorageNamespace::Merge(
- bool actually_merge,
- int process_id,
- DOMStorageNamespace* other,
- DOMStorageContextImpl* context) {
- if (!alias_master_namespace())
- return SessionStorageNamespace::MERGE_RESULT_NAMESPACE_NOT_ALIAS;
- if (transactions_.count(process_id) < 1)
- return SessionStorageNamespace::MERGE_RESULT_NOT_LOGGING;
- TransactionData* data = transactions_[process_id];
- if (data->max_log_size_exceeded)
- return SessionStorageNamespace::MERGE_RESULT_TOO_MANY_TRANSACTIONS;
- if (data->log.size() < 1) {
- if (actually_merge)
- SwitchToNewAliasMaster(other, context);
- return SessionStorageNamespace::MERGE_RESULT_NO_TRANSACTIONS;
- }
-
- // skip_areas and skip_keys store areas and (area, key) pairs, respectively,
- // that have already been handled previously. Any further modifications to
- // them will not change the result of the hypothetical merge.
- std::set<GURL> skip_areas;
- typedef std::pair<GURL, base::string16> OriginKey;
- std::set<OriginKey> skip_keys;
- // Indicates whether we could still merge the namespaces preserving all
- // individual transactions.
- for (unsigned int i = 0; i < data->log.size(); i++) {
- TransactionRecord& transaction = data->log[i];
- if (transaction.transaction_type == TRANSACTION_CLEAR) {
- skip_areas.insert(transaction.origin);
- continue;
- }
- if (skip_areas.find(transaction.origin) != skip_areas.end())
- continue;
- if (skip_keys.find(OriginKey(transaction.origin, transaction.key))
- != skip_keys.end()) {
- continue;
- }
- if (transaction.transaction_type == TRANSACTION_REMOVE ||
- transaction.transaction_type == TRANSACTION_WRITE) {
- skip_keys.insert(OriginKey(transaction.origin, transaction.key));
- continue;
- }
- if (transaction.transaction_type == TRANSACTION_READ) {
- DOMStorageArea* area = other->OpenStorageArea(transaction.origin);
- base::NullableString16 other_value = area->GetItem(transaction.key);
- other->CloseStorageArea(area);
- if (transaction.value != other_value)
- return SessionStorageNamespace::MERGE_RESULT_NOT_MERGEABLE;
- continue;
- }
- NOTREACHED();
- }
- if (!actually_merge)
- return SessionStorageNamespace::MERGE_RESULT_MERGEABLE;
-
- // Actually perform the merge.
-
- for (unsigned int i = 0; i < data->log.size(); i++) {
- TransactionRecord& transaction = data->log[i];
- if (transaction.transaction_type == TRANSACTION_READ)
- continue;
- DOMStorageArea* area = other->OpenStorageArea(transaction.origin);
- if (transaction.transaction_type == TRANSACTION_CLEAR) {
- area->Clear();
- if (context)
- context->NotifyAreaCleared(area, transaction.page_url);
- }
- if (transaction.transaction_type == TRANSACTION_REMOVE) {
- base::string16 old_value;
- area->RemoveItem(transaction.key, &old_value);
- if (context) {
- context->NotifyItemRemoved(area, transaction.key, old_value,
- transaction.page_url);
- }
- }
- if (transaction.transaction_type == TRANSACTION_WRITE) {
- base::NullableString16 old_value;
- area->SetItem(transaction.key, base::string16(transaction.value.string()),
- &old_value);
- if (context) {
- context->NotifyItemSet(area, transaction.key,transaction.value.string(),
- old_value, transaction.page_url);
- }
- }
- other->CloseStorageArea(area);
- }
-
- SwitchToNewAliasMaster(other, context);
- return SessionStorageNamespace::MERGE_RESULT_MERGEABLE;
-}
-
-bool DOMStorageNamespace::IsLoggingRenderer(int process_id) {
- DCHECK(process_id != ChildProcessHost::kInvalidUniqueID);
- if (transactions_.count(process_id) < 1)
- return false;
- return !transactions_[process_id]->max_log_size_exceeded;
-}
-
-void DOMStorageNamespace::AddTransaction(
- int process_id, const TransactionRecord& transaction) {
- if (!IsLoggingRenderer(process_id))
- return;
- TransactionData* transaction_data = transactions_[process_id];
- DCHECK(transaction_data);
- if (transaction_data->max_log_size_exceeded)
- return;
- transaction_data->log.push_back(transaction);
- if (transaction_data->log.size() > kMaxTransactionLogEntries) {
- transaction_data->max_log_size_exceeded = true;
- transaction_data->log.clear();
- }
-}
-
-bool DOMStorageNamespace::DecrementMasterAliasCount() {
- if (!alias_master_namespace_.get() || master_alias_count_decremented_)
- return false;
- DCHECK_GT(alias_master_namespace_->num_aliases_, 0);
- alias_master_namespace_->num_aliases_--;
- master_alias_count_decremented_ = true;
- return (alias_master_namespace_->num_aliases_ == 0);
-}
-
-void DOMStorageNamespace::SwitchToNewAliasMaster(
- DOMStorageNamespace* new_master,
- DOMStorageContextImpl* context) {
- DCHECK(alias_master_namespace());
- scoped_refptr<DOMStorageNamespace> old_master = alias_master_namespace();
- if (new_master->alias_master_namespace())
- new_master = new_master->alias_master_namespace();
- DCHECK(!new_master->alias_master_namespace());
- DCHECK(old_master.get() != this);
- DCHECK(old_master.get() != new_master);
- DecrementMasterAliasCount();
- alias_master_namespace_ = new_master;
- alias_master_namespace_->num_aliases_++;
- master_alias_count_decremented_ = false;
- // There are three things that we need to clean up:
- // -- the old master may ready for shutdown, if its last alias has disappeared
- // -- The dom_storage hosts need to close and reopen their areas, so that
- // they point to the correct new areas.
- // -- The renderers will need to reset their local caches.
- // All three of these things are accomplished with the following call below.
- // |context| will be NULL in unit tests, which is when this will
- // not apply, of course.
- // During this call, open areas will be closed & reopened, so that they now
- // come from the correct new master. Therefore, we must send close operations
- // to the old master.
- old_master_for_close_area_ = old_master.get();
- if (context)
- context->NotifyAliasSessionMerged(namespace_id(), old_master.get());
- old_master_for_close_area_ = NULL;
-}
-
-DOMStorageNamespace::TransactionData::TransactionData()
- : max_log_size_exceeded(false) {
-}
-
-DOMStorageNamespace::TransactionData::~TransactionData() {
-}
-
-DOMStorageNamespace::TransactionRecord::TransactionRecord() {
-}
-
-DOMStorageNamespace::TransactionRecord::~TransactionRecord() {
-}
-
// AreaHolder
DOMStorageNamespace::AreaHolder::AreaHolder()
diff --git a/chromium/content/browser/dom_storage/dom_storage_namespace.h b/chromium/content/browser/dom_storage/dom_storage_namespace.h
index 5d18882834d..48f449a615d 100644
--- a/chromium/content/browser/dom_storage/dom_storage_namespace.h
+++ b/chromium/content/browser/dom_storage/dom_storage_namespace.h
@@ -6,20 +6,17 @@
#define CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_NAMESPACE_H_
#include <map>
-#include <vector>
+#include <string>
#include "base/basictypes.h"
#include "base/files/file_path.h"
#include "base/memory/ref_counted.h"
-#include "base/strings/nullable_string16.h"
#include "content/common/content_export.h"
-#include "content/public/browser/session_storage_namespace.h"
#include "url/gurl.h"
namespace content {
class DOMStorageArea;
-class DOMStorageContextImpl;
class DOMStorageTaskRunner;
class SessionStorageDatabase;
@@ -70,61 +67,14 @@ class CONTENT_EXPORT DOMStorageNamespace
DOMStorageNamespace* Clone(int64 clone_namespace_id,
const std::string& clone_persistent_namespace_id);
- // Creates an alias of |this| namespace.
- // Should only be called for session storage namespaces.
- DOMStorageNamespace* CreateAlias(int64 alias_namespace_id);
-
void DeleteLocalStorageOrigin(const GURL& origin);
void DeleteSessionStorageOrigin(const GURL& origin);
void PurgeMemory(PurgeOption purge);
void Shutdown();
+ void Flush();
unsigned int CountInMemoryAreas() const;
- void AddTransactionLogProcessId(int process_id);
- void RemoveTransactionLogProcessId(int process_id);
- SessionStorageNamespace::MergeResult Merge(
- bool actually_merge,
- int process_id,
- DOMStorageNamespace* other,
- DOMStorageContextImpl* context);
- DOMStorageNamespace* alias_master_namespace() {
- return alias_master_namespace_.get();
- }
- int num_aliases() const { return num_aliases_; }
- bool ready_for_deletion_pending_aliases() const {
- return ready_for_deletion_pending_aliases_; }
- void set_ready_for_deletion_pending_aliases(bool value) {
- ready_for_deletion_pending_aliases_ = value;
- }
- bool must_persist_at_shutdown() const { return must_persist_at_shutdown_; }
- void set_must_persist_at_shutdown(bool value) {
- must_persist_at_shutdown_ = value;
- }
-
- enum LogType {
- TRANSACTION_READ,
- TRANSACTION_WRITE,
- TRANSACTION_REMOVE,
- TRANSACTION_CLEAR
- };
-
- struct CONTENT_EXPORT TransactionRecord {
- LogType transaction_type;
- GURL origin;
- GURL page_url;
- base::string16 key;
- base::NullableString16 value;
- TransactionRecord();
- ~TransactionRecord();
- };
-
- void AddTransaction(int process_id, const TransactionRecord& transaction);
- bool IsLoggingRenderer(int process_id);
- // Decrements the count of aliases owned by the master, and returns true
- // if the new count is 0.
- bool DecrementMasterAliasCount();
-
private:
friend class base::RefCountedThreadSafe<DOMStorageNamespace>;
@@ -139,43 +89,17 @@ class CONTENT_EXPORT DOMStorageNamespace
};
typedef std::map<GURL, AreaHolder> AreaMap;
- struct TransactionData {
- bool max_log_size_exceeded;
- std::vector<TransactionRecord> log;
- TransactionData();
- ~TransactionData();
- };
-
~DOMStorageNamespace();
// Returns a pointer to the area holder in our map or NULL.
AreaHolder* GetAreaHolder(const GURL& origin);
- // Switches the current alias DOM storage namespace to a new alias master.
- void SwitchToNewAliasMaster(DOMStorageNamespace* new_master,
- DOMStorageContextImpl* context);
-
int64 namespace_id_;
std::string persistent_namespace_id_;
base::FilePath directory_;
AreaMap areas_;
scoped_refptr<DOMStorageTaskRunner> task_runner_;
scoped_refptr<SessionStorageDatabase> session_storage_database_;
- std::map<int, TransactionData*> transactions_;
- int num_aliases_;
- scoped_refptr<DOMStorageNamespace> alias_master_namespace_;
- DOMStorageNamespace* old_master_for_close_area_;
- // Indicates whether we have already decremented |num_aliases_| for this
- // namespace in its alias master. We may only decrement it once, and around
- // deletion, this instance will stick around a bit longer until its refcount
- // drops to 0. Therefore, we want to make sure we don't decrement the master's
- // alias count a second time.
- bool master_alias_count_decremented_;
- // This indicates, for an alias master, that the master itself is ready
- // for deletion, but there are aliases outstanding that we have to wait for
- // before we can start cleaning up the master.
- bool ready_for_deletion_pending_aliases_;
- bool must_persist_at_shutdown_;
};
} // namespace content
diff --git a/chromium/content/browser/dom_storage/dom_storage_session.cc b/chromium/content/browser/dom_storage/dom_storage_session.cc
index c3b7a9e3046..7706ec85064 100644
--- a/chromium/content/browser/dom_storage/dom_storage_session.cc
+++ b/chromium/content/browser/dom_storage/dom_storage_session.cc
@@ -7,33 +7,12 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/logging.h"
-#include "base/single_thread_task_runner.h"
-#include "base/thread_task_runner_handle.h"
#include "base/tracked_objects.h"
#include "content/browser/dom_storage/dom_storage_context_impl.h"
#include "content/browser/dom_storage/dom_storage_task_runner.h"
namespace content {
-namespace {
-
-void PostMergeTaskResult(
- const SessionStorageNamespace::MergeResultCallback& callback,
- SessionStorageNamespace::MergeResult result) {
- callback.Run(result);
-}
-
-void RunMergeTaskAndPostResult(
- const base::Callback<SessionStorageNamespace::MergeResult(void)>& task,
- scoped_refptr<base::SingleThreadTaskRunner> result_loop,
- const SessionStorageNamespace::MergeResultCallback& callback) {
- SessionStorageNamespace::MergeResult result = task.Run();
- result_loop->PostTask(
- FROM_HERE, base::Bind(&PostMergeTaskResult, callback, result));
-}
-
-} // namespace
-
DOMStorageSession::DOMStorageSession(DOMStorageContextImpl* context)
: context_(context),
namespace_id_(context->AllocateSessionId()),
@@ -57,22 +36,6 @@ DOMStorageSession::DOMStorageSession(DOMStorageContextImpl* context,
context_, namespace_id_, persistent_namespace_id_));
}
-DOMStorageSession::DOMStorageSession(
- DOMStorageSession* master_dom_storage_session)
- : context_(master_dom_storage_session->context_),
- namespace_id_(master_dom_storage_session->context_->AllocateSessionId()),
- persistent_namespace_id_(
- master_dom_storage_session->persistent_namespace_id()),
- should_persist_(false) {
- context_->task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&DOMStorageContextImpl::CreateAliasSessionNamespace,
- context_,
- master_dom_storage_session->namespace_id(),
- namespace_id_,
- persistent_namespace_id_));
-}
-
void DOMStorageSession::SetShouldPersist(bool should_persist) {
should_persist_ = should_persist;
}
@@ -118,54 +81,4 @@ DOMStorageSession::~DOMStorageSession() {
context_, namespace_id_, should_persist_));
}
-void DOMStorageSession::AddTransactionLogProcessId(int process_id) {
- context_->task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&DOMStorageContextImpl::AddTransactionLogProcessId,
- context_, namespace_id_, process_id));
-}
-
-void DOMStorageSession::RemoveTransactionLogProcessId(int process_id) {
- context_->task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&DOMStorageContextImpl::RemoveTransactionLogProcessId,
- context_, namespace_id_, process_id));
-}
-
-void DOMStorageSession::Merge(
- bool actually_merge,
- int process_id,
- DOMStorageSession* other,
- const SessionStorageNamespace::MergeResultCallback& callback) {
- scoped_refptr<base::SingleThreadTaskRunner> current_loop(
- base::ThreadTaskRunnerHandle::Get());
- SessionStorageNamespace::MergeResultCallback cb =
- base::Bind(&DOMStorageSession::ProcessMergeResult,
- this,
- actually_merge,
- callback,
- other->persistent_namespace_id());
- context_->task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&RunMergeTaskAndPostResult,
- base::Bind(&DOMStorageContextImpl::MergeSessionStorage,
- context_, namespace_id_, actually_merge, process_id,
- other->namespace_id_),
- current_loop,
- cb));
-}
-
-void DOMStorageSession::ProcessMergeResult(
- bool actually_merge,
- const SessionStorageNamespace::MergeResultCallback& callback,
- const std::string& new_persistent_namespace_id,
- SessionStorageNamespace::MergeResult result) {
- if (actually_merge &&
- (result == SessionStorageNamespace::MERGE_RESULT_MERGEABLE ||
- result == SessionStorageNamespace::MERGE_RESULT_NO_TRANSACTIONS)) {
- persistent_namespace_id_ = new_persistent_namespace_id;
- }
- callback.Run(result);
-}
-
} // namespace content
diff --git a/chromium/content/browser/dom_storage/dom_storage_session.h b/chromium/content/browser/dom_storage/dom_storage_session.h
index 5e126216c60..62c6d97252c 100644
--- a/chromium/content/browser/dom_storage/dom_storage_session.h
+++ b/chromium/content/browser/dom_storage/dom_storage_session.h
@@ -9,7 +9,6 @@
#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
-#include "content/browser/dom_storage/session_storage_namespace_impl.h"
#include "content/common/content_export.h"
namespace content {
@@ -31,10 +30,6 @@ class CONTENT_EXPORT DOMStorageSession
DOMStorageSession(DOMStorageContextImpl* context,
const std::string& persistent_namespace_id);
- // Constructs a |DOMStorageSession| as an alias of
- // |master_dom_storage_session|. Allocates a new non-persistent ID.
- explicit DOMStorageSession(DOMStorageSession* master_dom_storage_session);
-
int64 namespace_id() const { return namespace_id_; }
const std::string& persistent_namespace_id() const {
return persistent_namespace_id_;
@@ -49,13 +44,6 @@ class CONTENT_EXPORT DOMStorageSession
static DOMStorageSession* CloneFrom(DOMStorageContextImpl* context,
int64 namepace_id_to_clone);
- void AddTransactionLogProcessId(int process_id);
- void RemoveTransactionLogProcessId(int process_id);
- void Merge(bool actually_merge,
- int process_id,
- DOMStorageSession* other,
- const SessionStorageNamespace::MergeResultCallback& callback);
-
private:
friend class base::RefCountedThreadSafe<DOMStorageSession>;
@@ -64,12 +52,6 @@ class CONTENT_EXPORT DOMStorageSession
const std::string& persistent_namespace_id);
~DOMStorageSession();
- void ProcessMergeResult(
- bool actually_merge,
- const SessionStorageNamespace::MergeResultCallback& callback,
- const std::string& new_persistent_namespace_id,
- SessionStorageNamespace::MergeResult result);
-
scoped_refptr<DOMStorageContextImpl> context_;
int64 namespace_id_;
std::string persistent_namespace_id_;
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 a2000a08c14..1d4485c9bd8 100644
--- a/chromium/content/browser/dom_storage/dom_storage_task_runner.h
+++ b/chromium/content/browser/dom_storage/dom_storage_task_runner.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_DOM_STORAGE_DOM_STORAGE_TASK_RUNNER_
-#define CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_TASK_RUNNER_
+#ifndef CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_TASK_RUNNER_H_
+#define CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_TASK_RUNNER_H_
#include "base/memory/ref_counted.h"
#include "base/sequenced_task_runner.h"
@@ -36,10 +36,9 @@ class CONTENT_EXPORT DOMStorageTaskRunner
// The PostTask() and PostDelayedTask() methods defined by TaskRunner
// post shutdown-blocking tasks on the primary sequence.
- virtual bool PostDelayedTask(
- const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta delay) = 0;
+ bool PostDelayedTask(const tracked_objects::Location& from_here,
+ const base::Closure& task,
+ base::TimeDelta delay) override = 0;
// Posts a shutdown blocking task to |sequence_id|.
virtual bool PostShutdownBlockingTask(
@@ -128,4 +127,4 @@ class CONTENT_EXPORT MockDOMStorageTaskRunner :
} // namespace content
-#endif // CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_TASK_RUNNER_
+#endif // CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_TASK_RUNNER_H_
diff --git a/chromium/content/browser/dom_storage/session_storage_database.cc b/chromium/content/browser/dom_storage/session_storage_database.cc
index 6e47a1fdf1c..62d643031de 100644
--- a/chromium/content/browser/dom_storage/session_storage_database.cc
+++ b/chromium/content/browser/dom_storage/session_storage_database.cc
@@ -10,6 +10,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
+#include "third_party/leveldatabase/env_chromium.h"
#include "third_party/leveldatabase/src/include/leveldb/db.h"
#include "third_party/leveldatabase/src/include/leveldb/iterator.h"
#include "third_party/leveldatabase/src/include/leveldb/options.h"
@@ -236,9 +237,14 @@ bool SessionStorageDatabase::DeleteArea(const std::string& namespace_id,
}
bool SessionStorageDatabase::DeleteNamespace(const std::string& namespace_id) {
- if (!LazyOpen(false)) {
- // No need to create the database if it doesn't exist.
- return true;
+ {
+ // The caller should have called other methods to open the DB before this
+ // function. Otherwise, DB stores nothing interesting related to the
+ // specified namespace.
+ // Do nothing if the DB is not open (or we know it has failed already),
+ base::AutoLock auto_lock(db_lock_);
+ if (!IsOpen() || db_error_ || is_inconsistent_)
+ return false;
}
DBOperation operation(this);
// Itereate through the areas in the namespace.
@@ -376,6 +382,7 @@ leveldb::Status SessionStorageDatabase::TryToOpen(leveldb::DB** db) {
// situation gracefully by creating the database now.
options.max_open_files = 0; // Use minimum.
options.create_if_missing = true;
+ options.reuse_logs = leveldb_env::kDefaultLogReuseOptionValue;
#if defined(OS_WIN)
return leveldb::DB::Open(options, base::WideToUTF8(file_path_.value()), db);
#elif defined(OS_POSIX)
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 ee861b2fbf0..a1f7f2dd7f7 100644
--- a/chromium/content/browser/dom_storage/session_storage_namespace_impl.cc
+++ b/chromium/content/browser/dom_storage/session_storage_namespace_impl.cc
@@ -25,13 +25,6 @@ SessionStorageNamespaceImpl::SessionStorageNamespaceImpl(
: session_(new DOMStorageSession(context->context(), persistent_id)) {
}
-SessionStorageNamespaceImpl::SessionStorageNamespaceImpl(
- SessionStorageNamespaceImpl* master_session_storage_namespace)
- : session_(new DOMStorageSession(
- master_session_storage_namespace->session_.get())) {
-}
-
-
int64 SessionStorageNamespaceImpl::id() const {
return session_->namespace_id();
}
@@ -65,32 +58,4 @@ SessionStorageNamespaceImpl::SessionStorageNamespaceImpl(
SessionStorageNamespaceImpl::~SessionStorageNamespaceImpl() {
}
-void SessionStorageNamespaceImpl::AddTransactionLogProcessId(int process_id) {
- session_->AddTransactionLogProcessId(process_id);
-}
-
-void SessionStorageNamespaceImpl::RemoveTransactionLogProcessId(
- int process_id) {
- session_->RemoveTransactionLogProcessId(process_id);
-}
-
-void SessionStorageNamespaceImpl::Merge(
- bool actually_merge,
- int process_id,
- SessionStorageNamespace* other,
- const MergeResultCallback& callback) {
- SessionStorageNamespaceImpl* other_impl =
- static_cast<SessionStorageNamespaceImpl*>(other);
- session_->Merge(
- actually_merge, process_id, other_impl->session_.get(), callback);
-}
-
-bool SessionStorageNamespaceImpl::IsAliasOf(SessionStorageNamespace* other) {
- return persistent_id() == other->persistent_id();
-}
-
-SessionStorageNamespace* SessionStorageNamespaceImpl::CreateAlias() {
- return new SessionStorageNamespaceImpl(this);
-}
-
} // namespace content
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 025ee8729da..83a9866241e 100644
--- a/chromium/content/browser/dom_storage/session_storage_namespace_impl.h
+++ b/chromium/content/browser/dom_storage/session_storage_namespace_impl.h
@@ -34,11 +34,6 @@ class SessionStorageNamespaceImpl
SessionStorageNamespaceImpl(DOMStorageContextWrapper* context,
const std::string& persistent_id);
- // Creates an alias of |master_session_storage_namespace|. This will allocate
- // a new non-persistent ID.
- explicit SessionStorageNamespaceImpl(
- SessionStorageNamespaceImpl* master_session_storage_namespace);
-
// SessionStorageNamespace implementation.
int64 id() const override;
const std::string& persistent_id() const override;
@@ -48,15 +43,6 @@ class SessionStorageNamespaceImpl
SessionStorageNamespaceImpl* Clone();
bool IsFromContext(DOMStorageContextWrapper* context);
- 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);
~SessionStorageNamespaceImpl() override;
diff --git a/chromium/content/browser/download/base_file.cc b/chromium/content/browser/download/base_file.cc
index 5bca7831a44..62ffe57fea2 100644
--- a/chromium/content/browser/download/base_file.cc
+++ b/chromium/content/browser/download/base_file.cc
@@ -55,7 +55,7 @@ BaseFile::BaseFile(const base::FilePath& full_path,
}
BaseFile::~BaseFile() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
if (detached_)
Close();
else
@@ -64,7 +64,7 @@ BaseFile::~BaseFile() {
DownloadInterruptReason BaseFile::Initialize(
const base::FilePath& default_directory) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
DCHECK(!detached_);
if (full_path_.empty()) {
@@ -90,7 +90,7 @@ DownloadInterruptReason BaseFile::Initialize(
DownloadInterruptReason BaseFile::AppendDataToFile(const char* data,
size_t data_len) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
DCHECK(!detached_);
// NOTE(benwells): The above DCHECK won't be present in release builds,
@@ -137,7 +137,7 @@ DownloadInterruptReason BaseFile::AppendDataToFile(const char* data,
}
DownloadInterruptReason BaseFile::Rename(const base::FilePath& new_path) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
DownloadInterruptReason rename_result = DOWNLOAD_INTERRUPT_REASON_NONE;
// If the new path is same as the old one, there is no need to perform the
@@ -179,7 +179,7 @@ void BaseFile::Detach() {
}
void BaseFile::Cancel() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
DCHECK(!detached_);
bound_net_log_.AddEvent(net::NetLog::TYPE_CANCELLED);
@@ -195,7 +195,7 @@ void BaseFile::Cancel() {
}
void BaseFile::Finish() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
if (calculate_hash_)
secure_hash_->Finish(sha256_hash_, crypto::kSHA256Length);
@@ -251,7 +251,7 @@ std::string BaseFile::DebugString() const {
}
DownloadInterruptReason BaseFile::Open() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
DCHECK(!detached_);
DCHECK(!full_path_.empty());
@@ -297,7 +297,7 @@ DownloadInterruptReason BaseFile::Open() {
}
void BaseFile::Close() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
bound_net_log_.AddEvent(net::NetLog::TYPE_DOWNLOAD_FILE_CLOSED);
diff --git a/chromium/content/browser/download/base_file.h b/chromium/content/browser/download/base_file.h
index 037aecca3b5..9016755ebc6 100644
--- a/chromium/content/browser/download/base_file.h
+++ b/chromium/content/browser/download/base_file.h
@@ -18,7 +18,7 @@
#include "content/public/browser/download_interrupt_reasons.h"
#include "crypto/sha2.h"
#include "net/base/net_errors.h"
-#include "net/base/net_log.h"
+#include "net/log/net_log.h"
#include "url/gurl.h"
namespace crypto {
diff --git a/chromium/content/browser/download/base_file_linux.cc b/chromium/content/browser/download/base_file_linux.cc
index ee8d1fa8587..721cd602694 100644
--- a/chromium/content/browser/download/base_file_linux.cc
+++ b/chromium/content/browser/download/base_file_linux.cc
@@ -10,7 +10,7 @@
namespace content {
DownloadInterruptReason BaseFile::AnnotateWithSourceInformation() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
DCHECK(!detached_);
AddOriginMetadataToFile(full_path_, source_url_, referrer_url_);
diff --git a/chromium/content/browser/download/base_file_mac.cc b/chromium/content/browser/download/base_file_mac.cc
index 21e6b556abb..f3edf12d094 100644
--- a/chromium/content/browser/download/base_file_mac.cc
+++ b/chromium/content/browser/download/base_file_mac.cc
@@ -10,7 +10,7 @@
namespace content {
DownloadInterruptReason BaseFile::AnnotateWithSourceInformation() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
DCHECK(!detached_);
AddQuarantineMetadataToFile(full_path_, source_url_, referrer_url_);
diff --git a/chromium/content/browser/download/base_file_win.cc b/chromium/content/browser/download/base_file_win.cc
index fec1454d57b..6e836c76d57 100644
--- a/chromium/content/browser/download/base_file_win.cc
+++ b/chromium/content/browser/download/base_file_win.cc
@@ -353,7 +353,7 @@ DownloadInterruptReason BaseFile::MoveFileAndAdjustPermissions(
}
DownloadInterruptReason BaseFile::AnnotateWithSourceInformation() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
DCHECK(!detached_);
bound_net_log_.BeginEvent(net::NetLog::TYPE_DOWNLOAD_FILE_ANNOTATED);
diff --git a/chromium/content/browser/download/download_browsertest.cc b/chromium/content/browser/download/download_browsertest.cc
index a011fc90015..f0ffbe31406 100644
--- a/chromium/content/browser/download/download_browsertest.cc
+++ b/chromium/content/browser/download/download_browsertest.cc
@@ -34,12 +34,12 @@
#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_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 "net/test/url_request/url_request_slow_download_job.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
@@ -173,9 +173,9 @@ class DownloadFileWithDelayFactory : public DownloadFileFactory {
void WaitForSomeCallback();
private:
- base::WeakPtrFactory<DownloadFileWithDelayFactory> weak_ptr_factory_;
std::vector<base::Closure> rename_callbacks_;
bool waiting_;
+ base::WeakPtrFactory<DownloadFileWithDelayFactory> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(DownloadFileWithDelayFactory);
};
@@ -201,7 +201,7 @@ DownloadFileWithDelay::~DownloadFileWithDelay() {}
void DownloadFileWithDelay::RenameAndUniquify(
const base::FilePath& full_path,
const RenameCompletionCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
DownloadFileImpl::RenameAndUniquify(
full_path, base::Bind(DownloadFileWithDelay::RenameCallbackWrapper,
owner_, callback));
@@ -209,7 +209,7 @@ void DownloadFileWithDelay::RenameAndUniquify(
void DownloadFileWithDelay::RenameAndAnnotate(
const base::FilePath& full_path, const RenameCompletionCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
DownloadFileImpl::RenameAndAnnotate(
full_path, base::Bind(DownloadFileWithDelay::RenameCallbackWrapper,
owner_, callback));
@@ -221,15 +221,16 @@ void DownloadFileWithDelay::RenameCallbackWrapper(
const RenameCompletionCallback& original_callback,
DownloadInterruptReason reason,
const base::FilePath& path) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!factory)
return;
factory->AddRenameCallback(base::Bind(original_callback, reason, path));
}
DownloadFileWithDelayFactory::DownloadFileWithDelayFactory()
- : weak_ptr_factory_(this),
- waiting_(false) {}
+ : waiting_(false),
+ weak_ptr_factory_(this) {}
+
DownloadFileWithDelayFactory::~DownloadFileWithDelayFactory() {}
DownloadFile* DownloadFileWithDelayFactory::CreateFile(
@@ -241,10 +242,9 @@ DownloadFile* DownloadFileWithDelayFactory::CreateFile(
scoped_ptr<ByteStreamReader> stream,
const net::BoundNetLog& bound_net_log,
base::WeakPtr<DownloadDestinationObserver> observer) {
- scoped_ptr<PowerSaveBlocker> psb(
- PowerSaveBlocker::Create(
- PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
- "Download in progress"));
+ scoped_ptr<PowerSaveBlocker> psb(PowerSaveBlocker::Create(
+ PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
+ PowerSaveBlocker::kReasonOther, "Download in progress"));
return new DownloadFileWithDelay(
save_info.Pass(), default_download_directory, url, referrer_url,
calculate_hash, stream.Pass(), bound_net_log,
@@ -252,7 +252,7 @@ DownloadFile* DownloadFileWithDelayFactory::CreateFile(
}
void DownloadFileWithDelayFactory::AddRenameCallback(base::Closure callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
rename_callbacks_.push_back(callback);
if (waiting_)
base::MessageLoopForUI::current()->Quit();
@@ -260,12 +260,12 @@ void DownloadFileWithDelayFactory::AddRenameCallback(base::Closure callback) {
void DownloadFileWithDelayFactory::GetAllRenameCallbacks(
std::vector<base::Closure>* results) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
results->swap(rename_callbacks_);
}
void DownloadFileWithDelayFactory::WaitForSomeCallback() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (rename_callbacks_.empty()) {
waiting_ = true;
@@ -291,18 +291,18 @@ class CountingDownloadFile : public DownloadFileImpl {
stream.Pass(), bound_net_log, observer) {}
~CountingDownloadFile() override {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
active_files_--;
}
void Initialize(const InitializeCallback& callback) override {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
active_files_++;
return DownloadFileImpl::Initialize(callback);
}
static void GetNumberActiveFiles(int* result) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
*result = active_files_;
}
@@ -341,10 +341,9 @@ class CountingDownloadFileFactory : public DownloadFileFactory {
scoped_ptr<ByteStreamReader> stream,
const net::BoundNetLog& bound_net_log,
base::WeakPtr<DownloadDestinationObserver> observer) override {
- scoped_ptr<PowerSaveBlocker> psb(
- PowerSaveBlocker::Create(
- PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
- "Download in progress"));
+ scoped_ptr<PowerSaveBlocker> psb(PowerSaveBlocker::Create(
+ PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
+ PowerSaveBlocker::kReasonOther, "Download in progress"));
return new CountingDownloadFile(
save_info.Pass(), default_downloads_directory, url, referrer_url,
calculate_hash, stream.Pass(), bound_net_log,
@@ -471,7 +470,7 @@ class DownloadCreateObserver : DownloadManager::Observer {
}
DownloadItem* WaitForFinished() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!item_) {
waiting_ = true;
RunMessageLoop();
@@ -582,14 +581,12 @@ class DownloadContentTest : public ContentBrowserTest {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
- base::Bind(&URLRequestSlowDownloadJob::AddUrlHandler));
+ base::Bind(&net::URLRequestSlowDownloadJob::AddUrlHandler));
base::FilePath mock_base(GetTestFilePath("download", ""));
BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
+ BrowserThread::IO, FROM_HERE,
base::Bind(
- &net::URLRequestMockHTTPJob::AddUrlHandler,
- mock_base,
+ &net::URLRequestMockHTTPJob::AddUrlHandlers, mock_base,
make_scoped_refptr(content::BrowserThread::GetBlockingPool())));
}
@@ -746,7 +743,7 @@ class DownloadContentTest : public ContentBrowserTest {
private:
static void EnsureNoPendingDownloadJobsOnIO(bool* result) {
- if (URLRequestSlowDownloadJob::NumberOutstandingRequests())
+ if (net::URLRequestSlowDownloadJob::NumberOutstandingRequests())
*result = false;
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE, base::MessageLoop::QuitClosure());
@@ -764,7 +761,7 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest, DownloadCancelled) {
// we're in the expected state.
scoped_ptr<DownloadCreateObserver> observer(
CreateInProgressWaiter(shell(), 1));
- NavigateToURL(shell(), GURL(URLRequestSlowDownloadJob::kUnknownSizeUrl));
+ NavigateToURL(shell(), GURL(net::URLRequestSlowDownloadJob::kUnknownSizeUrl));
observer->WaitForFinished();
std::vector<DownloadItem*> downloads;
@@ -791,7 +788,7 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest, MultiDownload) {
// we're in the expected state.
scoped_ptr<DownloadCreateObserver> observer1(
CreateInProgressWaiter(shell(), 1));
- NavigateToURL(shell(), GURL(URLRequestSlowDownloadJob::kUnknownSizeUrl));
+ NavigateToURL(shell(), GURL(net::URLRequestSlowDownloadJob::kUnknownSizeUrl));
observer1->WaitForFinished();
std::vector<DownloadItem*> downloads;
@@ -818,7 +815,8 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest, MultiDownload) {
// Allow the first request to finish.
scoped_ptr<DownloadTestObserver> observer2(CreateWaiter(shell(), 1));
- NavigateToURL(shell(), GURL(URLRequestSlowDownloadJob::kFinishDownloadUrl));
+ NavigateToURL(shell(),
+ GURL(net::URLRequestSlowDownloadJob::kFinishDownloadUrl));
observer2->WaitForFinished(); // Wait for the third request.
EXPECT_EQ(1u, observer2->NumDownloadsSeenInState(DownloadItem::COMPLETE));
@@ -830,8 +828,8 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest, MultiDownload) {
// |file1| should be full of '*'s, and |file2| should be the same as the
// source file.
base::FilePath file1(download1->GetTargetFilePath());
- size_t file_size1 = URLRequestSlowDownloadJob::kFirstDownloadSize +
- URLRequestSlowDownloadJob::kSecondDownloadSize;
+ size_t file_size1 = net::URLRequestSlowDownloadJob::kFirstDownloadSize +
+ net::URLRequestSlowDownloadJob::kSecondDownloadSize;
std::string expected_contents(file_size1, '*');
ASSERT_TRUE(VerifyFile(file1, expected_contents, file_size1));
@@ -854,6 +852,7 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest, DownloadOctetStream) {
plugin_info.name = base::ASCIIToUTF16(kTestPluginName);
plugin_info.mime_types.push_back(
WebPluginMimeType(kTestMimeType, kTestFileType, ""));
+ plugin_info.type = WebPluginInfo::PLUGIN_TYPE_PEPPER_IN_PROCESS;
PluginServiceImpl::GetInstance()->RegisterInternalPlugin(plugin_info, false);
// The following is served with a Content-Type of application/octet-stream.
@@ -970,7 +969,7 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest, ShutdownInProgress) {
// Create a download that won't complete.
scoped_ptr<DownloadCreateObserver> observer(
CreateInProgressWaiter(shell(), 1));
- NavigateToURL(shell(), GURL(URLRequestSlowDownloadJob::kUnknownSizeUrl));
+ NavigateToURL(shell(), GURL(net::URLRequestSlowDownloadJob::kUnknownSizeUrl));
observer->WaitForFinished();
// Get the item.
diff --git a/chromium/content/browser/download/download_create_info.h b/chromium/content/browser/download/download_create_info.h
index cbf87119aa2..7bf03ab1d2a 100644
--- a/chromium/content/browser/download/download_create_info.h
+++ b/chromium/content/browser/download/download_create_info.h
@@ -15,7 +15,7 @@
#include "content/browser/download/download_request_handle.h"
#include "content/common/content_export.h"
#include "content/public/browser/download_save_info.h"
-#include "net/base/net_log.h"
+#include "net/log/net_log.h"
#include "ui/base/page_transition_types.h"
#include "url/gurl.h"
diff --git a/chromium/content/browser/download/download_file_impl.cc b/chromium/content/browser/download/download_file_impl.cc
index 91b25dac35b..b15354d1069 100644
--- a/chromium/content/browser/download/download_file_impl.cc
+++ b/chromium/content/browser/download/download_file_impl.cc
@@ -59,12 +59,12 @@ DownloadFileImpl::DownloadFileImpl(
}
DownloadFileImpl::~DownloadFileImpl() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
--number_active_objects_;
}
void DownloadFileImpl::Initialize(const InitializeCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
update_timer_.reset(new base::RepeatingTimer<DownloadFileImpl>());
DownloadInterruptReason result =
@@ -95,7 +95,7 @@ void DownloadFileImpl::Initialize(const InitializeCallback& callback) {
DownloadInterruptReason DownloadFileImpl::AppendDataToFile(
const char* data, size_t data_len) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
if (!update_timer_->IsRunning()) {
update_timer_->Start(FROM_HERE,
@@ -144,7 +144,7 @@ void DownloadFileImpl::RenameWithRetryInternal(
int retries_left,
base::TimeTicks time_of_first_failure,
const RenameCompletionCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
base::FilePath new_path(full_path);
@@ -337,7 +337,7 @@ void DownloadFileImpl::StreamActive() {
&DownloadDestinationObserver::DestinationCompleted,
observer_, hash));
}
- if (bound_net_log_.IsLogging()) {
+ if (bound_net_log_.IsCapturing()) {
bound_net_log_.AddEvent(
net::NetLog::TYPE_DOWNLOAD_STREAM_DRAINED,
base::Bind(&FileStreamDrainedNetLogCallback, total_incoming_data_size,
diff --git a/chromium/content/browser/download/download_file_impl.h b/chromium/content/browser/download/download_file_impl.h
index 9ff3f8583db..8d192c2e3a9 100644
--- a/chromium/content/browser/download/download_file_impl.h
+++ b/chromium/content/browser/download/download_file_impl.h
@@ -16,7 +16,7 @@
#include "content/browser/download/base_file.h"
#include "content/browser/download/rate_estimator.h"
#include "content/public/browser/download_save_info.h"
-#include "net/base/net_log.h"
+#include "net/log/net_log.h"
namespace content {
class ByteStreamReader;
diff --git a/chromium/content/browser/download/download_item_impl.cc b/chromium/content/browser/download/download_item_impl.cc
index f681486cdcb..599bc0d5ab7 100644
--- a/chromium/content/browser/download/download_item_impl.cc
+++ b/chromium/content/browser/download/download_item_impl.cc
@@ -58,7 +58,7 @@ namespace content {
namespace {
bool DeleteDownloadedFile(const base::FilePath& path) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
// Make sure we only delete files.
if (base::DirectoryExists(path))
@@ -70,7 +70,7 @@ void DeleteDownloadedFileDone(
base::WeakPtr<DownloadItemImpl> item,
const base::Callback<void(bool)>& callback,
bool success) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (success && item.get())
item->OnDownloadedFileRemoved();
callback.Run(success);
@@ -81,14 +81,14 @@ void DeleteDownloadedFileDone(
// at the end of the function.
static base::FilePath DownloadFileDetach(
scoped_ptr<DownloadFile> download_file) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
base::FilePath full_path = download_file->FullPath();
download_file->Detach();
return full_path;
}
static void DownloadFileCancel(scoped_ptr<DownloadFile> download_file) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
download_file->Cancel();
}
@@ -272,7 +272,7 @@ DownloadItemImpl::DownloadItemImpl(
}
DownloadItemImpl::~DownloadItemImpl() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
// Should always have been nuked before now, at worst in
// DownloadManager shutdown.
@@ -284,29 +284,29 @@ DownloadItemImpl::~DownloadItemImpl() {
}
void DownloadItemImpl::AddObserver(Observer* observer) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
observers_.AddObserver(observer);
}
void DownloadItemImpl::RemoveObserver(Observer* observer) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
observers_.RemoveObserver(observer);
}
void DownloadItemImpl::UpdateObservers() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
FOR_EACH_OBSERVER(Observer, observers_, OnDownloadUpdated(this));
}
void DownloadItemImpl::ValidateDangerousDownload() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(!IsDone());
DCHECK(IsDangerous());
- VLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
+ DVLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
if (IsDone() || !IsDangerous())
return;
@@ -327,8 +327,8 @@ void DownloadItemImpl::ValidateDangerousDownload() {
void DownloadItemImpl::StealDangerousDownload(
const AcquireFileCallback& callback) {
- VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true);
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DVLOG(20) << __FUNCTION__ << "() download = " << DebugString(true);
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(IsDangerous());
if (download_file_) {
BrowserThread::PostTaskAndReplyWithResult(
@@ -345,7 +345,7 @@ void DownloadItemImpl::StealDangerousDownload(
}
void DownloadItemImpl::Pause() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
// Ignore irrelevant states.
if (state_ != IN_PROGRESS_INTERNAL || is_paused_)
@@ -357,7 +357,7 @@ void DownloadItemImpl::Pause() {
}
void DownloadItemImpl::Resume() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
switch (state_) {
case IN_PROGRESS_INTERNAL:
if (!is_paused_)
@@ -384,9 +384,9 @@ void DownloadItemImpl::Resume() {
}
void DownloadItemImpl::Cancel(bool user_cancel) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
- VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true);
+ DVLOG(20) << __FUNCTION__ << "() download = " << DebugString(true);
if (state_ != IN_PROGRESS_INTERNAL &&
state_ != INTERRUPTED_INTERNAL &&
state_ != RESUMING_INTERNAL) {
@@ -434,8 +434,8 @@ void DownloadItemImpl::Cancel(bool user_cancel) {
}
void DownloadItemImpl::Remove() {
- VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true);
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DVLOG(20) << __FUNCTION__ << "() download = " << DebugString(true);
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
delegate_->AssertStateConsistent(this);
Cancel(true);
@@ -447,7 +447,7 @@ void DownloadItemImpl::Remove() {
}
void DownloadItemImpl::OpenDownload() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!IsDone()) {
// We don't honor the open_when_complete_ flag for temporary
@@ -472,7 +472,7 @@ void DownloadItemImpl::OpenDownload() {
}
void DownloadItemImpl::ShowDownloadInShell() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
delegate_->ShowDownloadInShell(this);
}
@@ -641,7 +641,7 @@ bool DownloadItemImpl::GetFileExternallyRemoved() const {
}
void DownloadItemImpl::DeleteFile(const base::Callback<void(bool)>& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (GetState() != DownloadItem::COMPLETE) {
// Pass a null WeakPtr so it doesn't call OnDownloadedFileRemoved.
BrowserThread::PostTask(
@@ -666,8 +666,8 @@ void DownloadItemImpl::DeleteFile(const base::Callback<void(bool)>& callback) {
}
bool DownloadItemImpl::IsDangerous() const {
-#if defined(OS_WIN)
- // TODO(noelutz): At this point only the windows views UI supports
+#if defined(OS_WIN) || defined(OS_MACOSX)
+ // TODO(noelutz): At this point only the windows views and OSX UI supports
// warnings based on dangerous content.
return (danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE ||
danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_URL ||
@@ -779,10 +779,10 @@ WebContents* DownloadItemImpl::GetWebContents() const {
}
void DownloadItemImpl::OnContentCheckCompleted(DownloadDangerType danger_type) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(AllDataSaved());
- VLOG(20) << __FUNCTION__ << " danger_type=" << danger_type
- << " download=" << DebugString(true);
+ DVLOG(20) << __FUNCTION__ << " danger_type=" << danger_type
+ << " download=" << DebugString(true);
SetDangerType(danger_type);
UpdateObservers();
}
@@ -864,7 +864,7 @@ std::string DownloadItemImpl::DebugString(bool verbose) const {
}
DownloadItemImpl::ResumeMode DownloadItemImpl::GetResumeMode() const {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
// We can't continue without a handle on the intermediate file.
// We also can't continue if we don't have some verifier to make sure
// we're getting the same file.
@@ -938,7 +938,7 @@ DownloadItemImpl::ResumeMode DownloadItemImpl::GetResumeMode() const {
void DownloadItemImpl::MergeOriginInfoOnResume(
const DownloadCreateInfo& new_create_info) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK_EQ(RESUMING_INTERNAL, state_);
DCHECK(!new_create_info.url_chain.empty());
@@ -986,7 +986,7 @@ void DownloadItemImpl::NotifyRemoved() {
void DownloadItemImpl::OnDownloadedFileRemoved() {
file_externally_removed_ = true;
- VLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
+ DVLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
UpdateObservers();
}
@@ -1004,12 +1004,12 @@ void DownloadItemImpl::SetTotalBytes(int64 total_bytes) {
}
void DownloadItemImpl::OnAllDataSaved(const std::string& final_hash) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK_EQ(IN_PROGRESS_INTERNAL, state_);
DCHECK(!all_data_saved_);
all_data_saved_ = true;
- VLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
+ DVLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
// Store final hash and null out intermediate serialized hash state.
hash_ = final_hash;
@@ -1019,7 +1019,7 @@ void DownloadItemImpl::OnAllDataSaved(const std::string& final_hash) {
}
void DownloadItemImpl::MarkAsComplete() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(all_data_saved_);
end_time_ = base::Time::Now();
@@ -1029,9 +1029,10 @@ void DownloadItemImpl::MarkAsComplete() {
void DownloadItemImpl::DestinationUpdate(int64 bytes_so_far,
int64 bytes_per_sec,
const std::string& hash_state) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- VLOG(20) << __FUNCTION__ << " so_far=" << bytes_so_far
- << " per_sec=" << bytes_per_sec << " download=" << DebugString(true);
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DVLOG(20) << __FUNCTION__ << " so_far=" << bytes_so_far
+ << " per_sec=" << bytes_per_sec << " download="
+ << DebugString(true);
if (GetState() != IN_PROGRESS) {
// Ignore if we're no longer in-progress. This can happen if we race a
@@ -1054,7 +1055,7 @@ void DownloadItemImpl::DestinationUpdate(int64 bytes_so_far,
if (received_bytes_ > total_bytes_)
total_bytes_ = 0;
- if (bound_net_log_.IsLogging()) {
+ if (bound_net_log_.IsCapturing()) {
bound_net_log_.AddEvent(
net::NetLog::TYPE_DOWNLOAD_ITEM_UPDATED,
net::NetLog::Int64Callback("bytes_so_far", received_bytes_));
@@ -1074,7 +1075,7 @@ void DownloadItemImpl::DestinationError(DownloadInterruptReason reason) {
}
void DownloadItemImpl::DestinationCompleted(const std::string& final_hash) {
- VLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
+ DVLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
if (GetState() != IN_PROGRESS)
return;
OnAllDataSaved(final_hash);
@@ -1085,7 +1086,7 @@ void DownloadItemImpl::DestinationCompleted(const std::string& final_hash) {
void DownloadItemImpl::Init(bool active,
DownloadType download_type) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (active)
RecordDownloadCount(START_COUNT);
@@ -1105,8 +1106,8 @@ void DownloadItemImpl::Init(bool active,
file_name = GetURL().ExtractFileName();
}
- base::Callback<base::Value*(net::NetLog::LogLevel)> active_data = base::Bind(
- &ItemActivatedNetLogCallback, this, download_type, &file_name);
+ net::NetLog::ParametersCallback active_data =
+ base::Bind(&ItemActivatedNetLogCallback, this, download_type, &file_name);
if (active) {
bound_net_log_.BeginEvent(
net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE, active_data);
@@ -1115,14 +1116,14 @@ void DownloadItemImpl::Init(bool active,
net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE, active_data);
}
- VLOG(20) << __FUNCTION__ << "() " << DebugString(true);
+ DVLOG(20) << __FUNCTION__ << "() " << DebugString(true);
}
// We're starting the download.
void DownloadItemImpl::Start(
scoped_ptr<DownloadFile> file,
scoped_ptr<DownloadRequestHandleInterface> req_handle) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(!download_file_.get());
DCHECK(file.get());
DCHECK(req_handle.get());
@@ -1151,7 +1152,7 @@ void DownloadItemImpl::Start(
void DownloadItemImpl::OnDownloadFileInitialized(
DownloadInterruptReason result) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (result != DOWNLOAD_INTERRUPT_REASON_NONE) {
Interrupt(result);
// TODO(rdsmith/asanka): Arguably we should show this in the UI, but
@@ -1177,7 +1178,7 @@ void DownloadItemImpl::OnDownloadTargetDetermined(
TargetDisposition disposition,
DownloadDangerType danger_type,
const base::FilePath& intermediate_path) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
// If the |target_path| is empty, then we consider this download to be
// canceled.
@@ -1194,8 +1195,8 @@ void DownloadItemImpl::OnDownloadTargetDetermined(
// name determination complete" semantics, we need to make sure that the
// error is kept completely invisible until that point.
- VLOG(20) << __FUNCTION__ << " " << target_path.value() << " " << disposition
- << " " << danger_type << " " << DebugString(true);
+ DVLOG(20) << __FUNCTION__ << " " << target_path.value() << " " << disposition
+ << " " << danger_type << " " << DebugString(true);
target_path_ = target_path;
target_disposition_ = disposition;
@@ -1240,8 +1241,8 @@ void DownloadItemImpl::OnDownloadTargetDetermined(
void DownloadItemImpl::OnDownloadRenamedToIntermediateName(
DownloadInterruptReason reason,
const base::FilePath& full_path) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- VLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DVLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
if (DOWNLOAD_INTERRUPT_REASON_NONE != destination_error_) {
// Process destination error. If both |reason| and |destination_error_|
@@ -1274,7 +1275,7 @@ void DownloadItemImpl::OnDownloadRenamedToIntermediateName(
// downloads. SavePackage always uses its own Finish() to mark downloads
// complete.
void DownloadItemImpl::MaybeCompleteDownload() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(!is_save_package_download_);
if (!IsDownloadReadyForCompletion(
@@ -1298,13 +1299,13 @@ void DownloadItemImpl::MaybeCompleteDownload() {
// Called by MaybeCompleteDownload() when it has determined that the download
// is ready for completion.
void DownloadItemImpl::OnDownloadCompleting() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (state_ != IN_PROGRESS_INTERNAL)
return;
- VLOG(20) << __FUNCTION__ << "()"
- << " " << DebugString(true);
+ DVLOG(20) << __FUNCTION__ << "()"
+ << " " << DebugString(true);
DCHECK(!GetTargetFilePath().empty());
DCHECK(!IsDangerous());
@@ -1335,7 +1336,7 @@ void DownloadItemImpl::OnDownloadCompleting() {
void DownloadItemImpl::OnDownloadRenamedToFinalName(
DownloadInterruptReason reason,
const base::FilePath& full_path) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(!is_save_package_download_);
// If a cancel or interrupt hit, we'll cancel the DownloadFile, which
@@ -1344,9 +1345,9 @@ void DownloadItemImpl::OnDownloadRenamedToFinalName(
if (state_ != IN_PROGRESS_INTERNAL)
return;
- VLOG(20) << __FUNCTION__ << "()"
- << " full_path = \"" << full_path.value() << "\""
- << " " << DebugString(false);
+ DVLOG(20) << __FUNCTION__ << "()"
+ << " full_path = \"" << full_path.value() << "\""
+ << " " << DebugString(false);
if (DOWNLOAD_INTERRUPT_REASON_NONE != reason) {
Interrupt(reason);
@@ -1386,16 +1387,16 @@ void DownloadItemImpl::OnDownloadRenamedToFinalName(
}
void DownloadItemImpl::DelayedDownloadOpened(bool auto_opened) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
auto_opened_ = auto_opened;
Completed();
}
void DownloadItemImpl::Completed() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
- VLOG(20) << __FUNCTION__ << "() " << DebugString(false);
+ DVLOG(20) << __FUNCTION__ << "() " << DebugString(false);
DCHECK(all_data_saved_);
end_time_ = base::Time::Now();
@@ -1438,7 +1439,7 @@ void DownloadItemImpl::OnResumeRequestStarted(
// An error occurred somewhere.
void DownloadItemImpl::Interrupt(DownloadInterruptReason reason) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK_NE(DOWNLOAD_INTERRUPT_REASON_NONE, reason);
// Somewhat counter-intuitively, it is possible for us to receive an
@@ -1498,7 +1499,7 @@ void DownloadItemImpl::Interrupt(DownloadInterruptReason reason) {
}
void DownloadItemImpl::ReleaseDownloadFile(bool destroy_file) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (destroy_file) {
BrowserThread::PostTask(
@@ -1559,7 +1560,7 @@ bool DownloadItemImpl::IsDownloadReadyForCompletion(
void DownloadItemImpl::TransitionTo(DownloadInternalState new_state,
ShouldUpdateObservers notify_action) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (state_ == new_state)
return;
@@ -1602,9 +1603,9 @@ void DownloadItemImpl::TransitionTo(DownloadInternalState new_state,
break;
}
- VLOG(20) << " " << __FUNCTION__ << "()" << " this = " << DebugString(true)
- << " " << InternalToExternalState(old_state)
- << " " << InternalToExternalState(state_);
+ DVLOG(20) << " " << __FUNCTION__ << "()" << " this = " << DebugString(true)
+ << " " << InternalToExternalState(old_state)
+ << " " << InternalToExternalState(state_);
bool is_done = (state_ != IN_PROGRESS_INTERNAL &&
state_ != COMPLETING_INTERNAL);
@@ -1649,10 +1650,10 @@ void DownloadItemImpl::SetDangerType(DownloadDangerType danger_type) {
}
void DownloadItemImpl::SetFullPath(const base::FilePath& new_path) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- VLOG(20) << __FUNCTION__ << "()"
- << " new_path = \"" << new_path.value() << "\""
- << " " << DebugString(true);
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DVLOG(20) << __FUNCTION__ << "()"
+ << " new_path = \"" << new_path.value() << "\""
+ << " " << DebugString(true);
DCHECK(!new_path.empty());
bound_net_log_.AddEvent(
@@ -1664,7 +1665,7 @@ void DownloadItemImpl::SetFullPath(const base::FilePath& new_path) {
void DownloadItemImpl::AutoResumeIfValid() {
DVLOG(20) << __FUNCTION__ << "() " << DebugString(true);
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
ResumeMode mode = GetResumeMode();
if (mode != RESUME_MODE_IMMEDIATE_RESTART &&
@@ -1678,7 +1679,7 @@ void DownloadItemImpl::AutoResumeIfValid() {
}
void DownloadItemImpl::ResumeInterruptedDownload() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
// If the flag for downloads resumption isn't enabled, ignore
// this request.
diff --git a/chromium/content/browser/download/download_item_impl.h b/chromium/content/browser/download/download_item_impl.h
index b6394f7469d..50b3dbd0f1a 100644
--- a/chromium/content/browser/download/download_item_impl.h
+++ b/chromium/content/browser/download/download_item_impl.h
@@ -20,7 +20,7 @@
#include "content/public/browser/download_destination_observer.h"
#include "content/public/browser/download_interrupt_reasons.h"
#include "content/public/browser/download_item.h"
-#include "net/base/net_log.h"
+#include "net/log/net_log.h"
#include "url/gurl.h"
namespace content {
diff --git a/chromium/content/browser/download/download_item_impl_unittest.cc b/chromium/content/browser/download/download_item_impl_unittest.cc
index acbc55e2ef8..786d9031104 100644
--- a/chromium/content/browser/download/download_item_impl_unittest.cc
+++ b/chromium/content/browser/download/download_item_impl_unittest.cc
@@ -53,7 +53,7 @@ class MockDelegate : public DownloadItemImplDelegate {
MOCK_METHOD1(ShouldOpenFileBasedOnExtension, bool(const base::FilePath&));
MOCK_METHOD1(CheckForFileRemoval, void(DownloadItemImpl*));
- virtual void ResumeInterruptedDownload(
+ void ResumeInterruptedDownload(
scoped_ptr<DownloadUrlParameters> params, uint32 id) override {
MockResumeInterruptedDownload(params.get(), id);
}
@@ -207,7 +207,6 @@ class DownloadItemTest : public testing::Test {
virtual void TearDown() {
ui_thread_.DeprecatedGetThreadObject()->message_loop()->RunUntilIdle();
STLDeleteElements(&allocated_downloads_);
- allocated_downloads_.clear();
}
// This class keeps ownership of the created download item; it will
diff --git a/chromium/content/browser/download/download_manager_impl.cc b/chromium/content/browser/download/download_manager_impl.cc
index 30296cb82e7..ce39612f65f 100644
--- a/chromium/content/browser/download/download_manager_impl.cc
+++ b/chromium/content/browser/download/download_manager_impl.cc
@@ -50,14 +50,13 @@ namespace {
void BeginDownload(scoped_ptr<DownloadUrlParameters> params,
uint32 download_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
// ResourceDispatcherHost{Base} is-not-a URLRequest::Delegate, and
// DownloadUrlParameters can-not include resource_dispatcher_host_impl.h, so
// we must down cast. RDHI is the only subclass of RDH as of 2012 May 4.
scoped_ptr<net::URLRequest> request(
params->resource_context()->GetRequestContext()->CreateRequest(
- params->url(), net::DEFAULT_PRIORITY, NULL, NULL));
- request->SetLoadFlags(request->load_flags() | params->load_flags());
+ params->url(), net::DEFAULT_PRIORITY, NULL));
request->set_method(params->method());
if (!params->post_body().empty()) {
const std::string& body = params->post_body();
@@ -129,6 +128,7 @@ void BeginDownload(scoped_ptr<DownloadUrlParameters> params,
params->render_process_host_id(),
params->render_view_host_routing_id(),
params->prefer_cache(),
+ params->do_not_prompt_for_login(),
save_info.Pass(),
download_id,
params->callback());
@@ -249,7 +249,7 @@ DownloadManagerImpl::~DownloadManagerImpl() {
DownloadItemImpl* DownloadManagerImpl::CreateActiveItem(
uint32 id, const DownloadCreateInfo& info) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(!ContainsKey(downloads_, id));
net::BoundNetLog bound_net_log =
net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD);
@@ -260,7 +260,7 @@ DownloadItemImpl* DownloadManagerImpl::CreateActiveItem(
}
void DownloadManagerImpl::GetNextId(const DownloadIdCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (delegate_) {
delegate_->GetNextId(callback);
return;
@@ -325,8 +325,8 @@ DownloadManagerDelegate* DownloadManagerImpl::GetDelegate() const {
}
void DownloadManagerImpl::Shutdown() {
- VLOG(20) << __FUNCTION__ << "()"
- << " shutdown_needed_ = " << shutdown_needed_;
+ DVLOG(20) << __FUNCTION__ << "()"
+ << " shutdown_needed_ = " << shutdown_needed_;
if (!shutdown_needed_)
return;
shutdown_needed_ = false;
@@ -345,7 +345,6 @@ void DownloadManagerImpl::Shutdown() {
download->Cancel(false);
}
STLDeleteValues(&downloads_);
- downloads_.clear();
// We'll have nothing more to report to the observers after this point.
observers_.Clear();
@@ -359,7 +358,7 @@ void DownloadManagerImpl::StartDownload(
scoped_ptr<DownloadCreateInfo> info,
scoped_ptr<ByteStreamReader> stream,
const DownloadUrlParameters::OnStartedCallback& on_started) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(info);
uint32 download_id = info->download_id;
const bool new_download = (download_id == content::DownloadItem::kInvalidId);
@@ -383,7 +382,7 @@ void DownloadManagerImpl::StartDownloadWithId(
const DownloadUrlParameters::OnStartedCallback& on_started,
bool new_download,
uint32 id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK_NE(content::DownloadItem::kInvalidId, id);
DownloadItemImpl* download = NULL;
if (new_download) {
@@ -446,7 +445,7 @@ void DownloadManagerImpl::StartDownloadWithId(
}
void DownloadManagerImpl::CheckForHistoryFilesRemoval() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
for (DownloadMap::iterator it = downloads_.begin();
it != downloads_.end(); ++it) {
DownloadItemImpl* item = it->second;
@@ -455,7 +454,7 @@ void DownloadManagerImpl::CheckForHistoryFilesRemoval() {
}
void DownloadManagerImpl::CheckForFileRemoval(DownloadItemImpl* download_item) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if ((download_item->GetState() == DownloadItem::COMPLETE) &&
!download_item->GetFileExternallyRemoved() &&
delegate_) {
@@ -468,7 +467,7 @@ void DownloadManagerImpl::CheckForFileRemoval(DownloadItemImpl* download_item) {
void DownloadManagerImpl::OnFileExistenceChecked(uint32 download_id,
bool result) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!result) { // File does not exist.
if (ContainsKey(downloads_, download_id))
downloads_[download_id]->OnDownloadedFileRemoved();
@@ -485,7 +484,7 @@ void DownloadManagerImpl::CreateSavePackageDownloadItem(
const std::string& mime_type,
scoped_ptr<DownloadRequestHandleInterface> request_handle,
const DownloadItemImplCreated& item_created) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
GetNextId(base::Bind(
&DownloadManagerImpl::CreateSavePackageDownloadItemWithId,
weak_factory_.GetWeakPtr(),
@@ -503,7 +502,7 @@ void DownloadManagerImpl::CreateSavePackageDownloadItemWithId(
scoped_ptr<DownloadRequestHandleInterface> request_handle,
const DownloadItemImplCreated& item_created,
uint32 id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK_NE(content::DownloadItem::kInvalidId, id);
DCHECK(!ContainsKey(downloads_, id));
net::BoundNetLog bound_net_log =
@@ -662,7 +661,7 @@ DownloadItem* DownloadManagerImpl::CreateDownloadItem(
net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD));
downloads_[id] = item;
FOR_EACH_OBSERVER(Observer, observers_, OnDownloadCreated(this, item));
- VLOG(20) << __FUNCTION__ << "() download = " << item->DebugString(true);
+ DVLOG(20) << __FUNCTION__ << "() download = " << item->DebugString(true);
return item;
}
diff --git a/chromium/content/browser/download/download_manager_impl_unittest.cc b/chromium/content/browser/download/download_manager_impl_unittest.cc
index 0c5eb523966..52adff4010e 100644
--- a/chromium/content/browser/download/download_manager_impl_unittest.cc
+++ b/chromium/content/browser/download/download_manager_impl_unittest.cc
@@ -28,11 +28,12 @@
#include "content/public/browser/download_interrupt_reasons.h"
#include "content/public/browser/download_item.h"
#include "content/public/browser/download_manager_delegate.h"
+#include "content/public/browser/zoom_level_delegate.h"
#include "content/public/test/mock_download_item.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_browser_thread.h"
-#include "net/base/net_log.h"
#include "net/base/net_util.h"
+#include "net/log/net_log.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gmock_mutant.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -109,9 +110,8 @@ class MockDownloadItemImpl : public DownloadItemImpl {
MOCK_METHOD0(MarkAsComplete, void());
MOCK_METHOD1(OnAllDataSaved, void(const std::string&));
MOCK_METHOD0(OnDownloadedFileRemoved, void());
- virtual void Start(
- scoped_ptr<DownloadFile> download_file,
- scoped_ptr<DownloadRequestHandleInterface> req_handle) override {
+ void Start(scoped_ptr<DownloadFile> download_file,
+ scoped_ptr<DownloadRequestHandleInterface> req_handle) override {
MockStart(download_file.get(), req_handle.get());
}
@@ -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 {
+ std::string DebugString(bool verbose) const override {
return std::string();
}
};
@@ -401,6 +401,8 @@ class MockBrowserContext : public BrowserContext {
~MockBrowserContext() {}
MOCK_CONST_METHOD0(GetPath, base::FilePath());
+ MOCK_METHOD1(CreateZoomLevelDelegateMock,
+ ZoomLevelDelegate*(const base::FilePath&));
MOCK_CONST_METHOD0(IsOffTheRecord, bool());
MOCK_METHOD0(GetRequestContext, net::URLRequestContextGetter*());
MOCK_METHOD1(GetRequestContextForRenderProcess,
@@ -418,6 +420,12 @@ class MockBrowserContext : public BrowserContext {
MOCK_METHOD0(GetSpecialStoragePolicy, storage::SpecialStoragePolicy*());
MOCK_METHOD0(GetPushMessagingService, PushMessagingService*());
MOCK_METHOD0(GetSSLHostStateDelegate, SSLHostStateDelegate*());
+ MOCK_METHOD0(GetPermissionManager, PermissionManager*());
+
+ scoped_ptr<ZoomLevelDelegate> CreateZoomLevelDelegate(
+ const base::FilePath& path) override {
+ return scoped_ptr<ZoomLevelDelegate>(CreateZoomLevelDelegateMock(path));
+ }
};
class MockDownloadManagerObserver : public DownloadManager::Observer {
diff --git a/chromium/content/browser/download/download_net_log_parameters.cc b/chromium/content/browser/download/download_net_log_parameters.cc
index 36e7e1e2210..8d04ae1d1fe 100644
--- a/chromium/content/browser/download/download_net_log_parameters.cc
+++ b/chromium/content/browser/download/download_net_log_parameters.cc
@@ -34,18 +34,17 @@ static const char* download_danger_names[] = {
"POTENTIALLY_UNWANTED"
};
-COMPILE_ASSERT(arraysize(download_type_names) == SRC_SAVE_PAGE_AS + 1,
- download_type_enum_has_changed);
-COMPILE_ASSERT(arraysize(download_danger_names) == DOWNLOAD_DANGER_TYPE_MAX,
- download_danger_enum_has_changed);
+static_assert(arraysize(download_type_names) == SRC_SAVE_PAGE_AS + 1,
+ "download type enum has changed");
+static_assert(arraysize(download_danger_names) == DOWNLOAD_DANGER_TYPE_MAX,
+ "download danger enum has changed");
} // namespace
-base::Value* ItemActivatedNetLogCallback(
- const DownloadItem* download_item,
- DownloadType download_type,
- const std::string* file_name,
- net::NetLog::LogLevel log_level) {
+base::Value* ItemActivatedNetLogCallback(const DownloadItem* download_item,
+ DownloadType download_type,
+ const std::string* file_name,
+ net::NetLogCaptureMode capture_mode) {
base::DictionaryValue* dict = new base::DictionaryValue();
dict->SetString("type", download_type_names[download_type]);
@@ -62,9 +61,8 @@ base::Value* ItemActivatedNetLogCallback(
return dict;
}
-base::Value* ItemCheckedNetLogCallback(
- DownloadDangerType danger_type,
- net::NetLog::LogLevel log_level) {
+base::Value* ItemCheckedNetLogCallback(DownloadDangerType danger_type,
+ net::NetLogCaptureMode capture_mode) {
base::DictionaryValue* dict = new base::DictionaryValue();
dict->SetString("danger_type", download_danger_names[danger_type]);
@@ -74,7 +72,7 @@ base::Value* ItemCheckedNetLogCallback(
base::Value* ItemRenamedNetLogCallback(const base::FilePath* old_filename,
const base::FilePath* new_filename,
- net::NetLog::LogLevel log_level) {
+ net::NetLogCaptureMode capture_mode) {
base::DictionaryValue* dict = new base::DictionaryValue();
dict->SetString("old_filename", old_filename->AsUTF8Unsafe());
@@ -83,10 +81,11 @@ base::Value* ItemRenamedNetLogCallback(const base::FilePath* old_filename,
return dict;
}
-base::Value* ItemInterruptedNetLogCallback(DownloadInterruptReason reason,
- int64 bytes_so_far,
- const std::string* hash_state,
- net::NetLog::LogLevel log_level) {
+base::Value* ItemInterruptedNetLogCallback(
+ DownloadInterruptReason reason,
+ int64 bytes_so_far,
+ const std::string* hash_state,
+ net::NetLogCaptureMode capture_mode) {
base::DictionaryValue* dict = new base::DictionaryValue();
dict->SetString("interrupt_reason", DownloadInterruptReasonToString(reason));
@@ -101,7 +100,7 @@ base::Value* ItemResumingNetLogCallback(bool user_initiated,
DownloadInterruptReason reason,
int64 bytes_so_far,
const std::string* hash_state,
- net::NetLog::LogLevel log_level) {
+ net::NetLogCaptureMode capture_mode) {
base::DictionaryValue* dict = new base::DictionaryValue();
dict->SetString("user_initiated", user_initiated ? "true" : "false");
@@ -115,7 +114,7 @@ base::Value* ItemResumingNetLogCallback(bool user_initiated,
base::Value* ItemCompletingNetLogCallback(int64 bytes_so_far,
const std::string* final_hash,
- net::NetLog::LogLevel log_level) {
+ net::NetLogCaptureMode capture_mode) {
base::DictionaryValue* dict = new base::DictionaryValue();
dict->SetString("bytes_so_far", base::Int64ToString(bytes_so_far));
@@ -126,7 +125,7 @@ base::Value* ItemCompletingNetLogCallback(int64 bytes_so_far,
}
base::Value* ItemFinishedNetLogCallback(bool auto_opened,
- net::NetLog::LogLevel log_level) {
+ net::NetLogCaptureMode capture_mode) {
base::DictionaryValue* dict = new base::DictionaryValue();
dict->SetString("auto_opened", auto_opened ? "yes" : "no");
@@ -136,7 +135,7 @@ base::Value* ItemFinishedNetLogCallback(bool auto_opened,
base::Value* ItemCanceledNetLogCallback(int64 bytes_so_far,
const std::string* hash_state,
- net::NetLog::LogLevel log_level) {
+ net::NetLogCaptureMode capture_mode) {
base::DictionaryValue* dict = new base::DictionaryValue();
dict->SetString("bytes_so_far", base::Int64ToString(bytes_so_far));
@@ -148,7 +147,7 @@ base::Value* ItemCanceledNetLogCallback(int64 bytes_so_far,
base::Value* FileOpenedNetLogCallback(const base::FilePath* file_name,
int64 start_offset,
- net::NetLog::LogLevel log_level) {
+ net::NetLogCaptureMode capture_mode) {
base::DictionaryValue* dict = new base::DictionaryValue();
dict->SetString("file_name", file_name->AsUTF8Unsafe());
@@ -157,9 +156,10 @@ base::Value* FileOpenedNetLogCallback(const base::FilePath* file_name,
return dict;
}
-base::Value* FileStreamDrainedNetLogCallback(size_t stream_size,
- size_t num_buffers,
- net::NetLog::LogLevel log_level) {
+base::Value* FileStreamDrainedNetLogCallback(
+ size_t stream_size,
+ size_t num_buffers,
+ net::NetLogCaptureMode capture_mode) {
base::DictionaryValue* dict = new base::DictionaryValue();
dict->SetInteger("stream_size", static_cast<int>(stream_size));
@@ -170,7 +170,7 @@ base::Value* FileStreamDrainedNetLogCallback(size_t stream_size,
base::Value* FileRenamedNetLogCallback(const base::FilePath* old_filename,
const base::FilePath* new_filename,
- net::NetLog::LogLevel log_level) {
+ net::NetLogCaptureMode capture_mode) {
base::DictionaryValue* dict = new base::DictionaryValue();
dict->SetString("old_filename", old_filename->AsUTF8Unsafe());
@@ -181,7 +181,7 @@ base::Value* FileRenamedNetLogCallback(const base::FilePath* old_filename,
base::Value* FileErrorNetLogCallback(const char* operation,
net::Error net_error,
- net::NetLog::LogLevel log_level) {
+ net::NetLogCaptureMode capture_mode) {
base::DictionaryValue* dict = new base::DictionaryValue();
dict->SetString("operation", operation);
@@ -190,10 +190,11 @@ base::Value* FileErrorNetLogCallback(const char* operation,
return dict;
}
-base::Value* FileInterruptedNetLogCallback(const char* operation,
- int os_error,
- DownloadInterruptReason reason,
- net::NetLog::LogLevel log_level) {
+base::Value* FileInterruptedNetLogCallback(
+ const char* operation,
+ int os_error,
+ DownloadInterruptReason reason,
+ net::NetLogCaptureMode capture_mode) {
base::DictionaryValue* dict = new base::DictionaryValue();
dict->SetString("operation", operation);
diff --git a/chromium/content/browser/download/download_net_log_parameters.h b/chromium/content/browser/download/download_net_log_parameters.h
index 1c12b8d1767..de0c9578a5b 100644
--- a/chromium/content/browser/download/download_net_log_parameters.h
+++ b/chromium/content/browser/download/download_net_log_parameters.h
@@ -9,7 +9,7 @@
#include "content/public/browser/download_item.h"
#include "net/base/net_errors.h"
-#include "net/base/net_log.h"
+#include "net/log/net_log.h"
class GURL;
@@ -26,74 +26,73 @@ enum DownloadType {
};
// Returns NetLog parameters when a DownloadItem is activated.
-base::Value* ItemActivatedNetLogCallback(
- const DownloadItem* download_item,
- DownloadType download_type,
- const std::string* file_name,
- net::NetLog::LogLevel log_level);
+base::Value* ItemActivatedNetLogCallback(const DownloadItem* download_item,
+ DownloadType download_type,
+ const std::string* file_name,
+ net::NetLogCaptureMode capture_mode);
// Returns NetLog parameters when a DownloadItem is checked for danger.
-base::Value* ItemCheckedNetLogCallback(
- DownloadDangerType danger_type,
- net::NetLog::LogLevel log_level);
+base::Value* ItemCheckedNetLogCallback(DownloadDangerType danger_type,
+ net::NetLogCaptureMode capture_mode);
// Returns NetLog parameters when a DownloadItem is renamed.
base::Value* ItemRenamedNetLogCallback(const base::FilePath* old_filename,
const base::FilePath* new_filename,
- net::NetLog::LogLevel log_level);
+ net::NetLogCaptureMode capture_mode);
// Returns NetLog parameters when a DownloadItem is interrupted.
base::Value* ItemInterruptedNetLogCallback(DownloadInterruptReason reason,
int64 bytes_so_far,
const std::string* hash_state,
- net::NetLog::LogLevel log_level);
+ net::NetLogCaptureMode capture_mode);
// Returns NetLog parameters when a DownloadItem is resumed.
base::Value* ItemResumingNetLogCallback(bool user_initiated,
DownloadInterruptReason reason,
int64 bytes_so_far,
const std::string* hash_state,
- net::NetLog::LogLevel log_level);
+ net::NetLogCaptureMode capture_mode);
// Returns NetLog parameters when a DownloadItem is completing.
base::Value* ItemCompletingNetLogCallback(int64 bytes_so_far,
const std::string* final_hash,
- net::NetLog::LogLevel log_level);
+ net::NetLogCaptureMode capture_mode);
// Returns NetLog parameters when a DownloadItem is finished.
base::Value* ItemFinishedNetLogCallback(bool auto_opened,
- net::NetLog::LogLevel log_level);
+ net::NetLogCaptureMode capture_mode);
// Returns NetLog parameters when a DownloadItem is canceled.
base::Value* ItemCanceledNetLogCallback(int64 bytes_so_far,
const std::string* hash_state,
- net::NetLog::LogLevel log_level);
+ net::NetLogCaptureMode capture_mode);
// Returns NetLog parameters when a DownloadFile is opened.
base::Value* FileOpenedNetLogCallback(const base::FilePath* file_name,
int64 start_offset,
- net::NetLog::LogLevel log_level);
+ net::NetLogCaptureMode capture_mode);
// Returns NetLog parameters when a DownloadFile is opened.
-base::Value* FileStreamDrainedNetLogCallback(size_t stream_size,
- size_t num_buffers,
- net::NetLog::LogLevel log_level);
+base::Value* FileStreamDrainedNetLogCallback(
+ size_t stream_size,
+ size_t num_buffers,
+ net::NetLogCaptureMode capture_mode);
// Returns NetLog parameters when a DownloadFile is renamed.
base::Value* FileRenamedNetLogCallback(const base::FilePath* old_filename,
const base::FilePath* new_filename,
- net::NetLog::LogLevel log_level);
+ net::NetLogCaptureMode capture_mode);
// Returns NetLog parameters when a File has an error.
base::Value* FileErrorNetLogCallback(const char* operation,
net::Error net_error,
- net::NetLog::LogLevel log_level);
+ net::NetLogCaptureMode capture_mode);
// Returns NetLog parameters for a download interruption.
base::Value* FileInterruptedNetLogCallback(const char* operation,
int os_error,
DownloadInterruptReason reason,
- net::NetLog::LogLevel log_level);
+ net::NetLogCaptureMode capture_mode);
} // namespace content
diff --git a/chromium/content/browser/download/download_resource_handler.cc b/chromium/content/browser/download/download_resource_handler.cc
index f2fb2a5b267..045c0f0e17e 100644
--- a/chromium/content/browser/download/download_resource_handler.cc
+++ b/chromium/content/browser/download/download_resource_handler.cc
@@ -10,7 +10,6 @@
#include "base/logging.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/metrics/histogram.h"
-#include "base/metrics/stats_counters.h"
#include "base/strings/stringprintf.h"
#include "content/browser/byte_stream.h"
#include "content/browser/download/download_create_info.h"
@@ -47,7 +46,7 @@ void CallStartedCBOnUIThread(
const DownloadUrlParameters::OnStartedCallback& started_cb,
DownloadItem* item,
DownloadInterruptReason interrupt_reason) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (started_cb.is_null())
return;
@@ -58,10 +57,10 @@ void CallStartedCBOnUIThread(
// DownloadResourceHandler members from the UI thread.
static void StartOnUIThread(
scoped_ptr<DownloadCreateInfo> info,
- DownloadResourceHandler::DownloadTabInfo* tab_info,
+ scoped_ptr<DownloadResourceHandler::DownloadTabInfo> tab_info,
scoped_ptr<ByteStreamReader> stream,
const DownloadUrlParameters::OnStartedCallback& started_cb) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DownloadManager* download_manager = info->request_handle.GetDownloadManager();
if (!download_manager) {
@@ -85,7 +84,7 @@ static void StartOnUIThread(
void InitializeDownloadTabInfoOnUIThread(
const DownloadRequestHandle& request_handle,
DownloadResourceHandler::DownloadTabInfo* tab_info) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
WebContents* web_contents = request_handle.GetWebContents();
if (web_contents) {
@@ -97,6 +96,9 @@ void InitializeDownloadTabInfoOnUIThread(
}
}
+void DeleteOnUIThread(
+ scoped_ptr<DownloadResourceHandler::DownloadTabInfo> tab_info) {}
+
} // namespace
const int DownloadResourceHandler::kDownloadByteStreamSize = 100 * 1024;
@@ -110,6 +112,7 @@ DownloadResourceHandler::DownloadResourceHandler(
download_id_(id),
started_cb_(started_cb),
save_info_(save_info.Pass()),
+ tab_info_(new DownloadTabInfo()),
last_buffer_size_(0),
bytes_read_(0),
pause_count_(0),
@@ -117,10 +120,12 @@ DownloadResourceHandler::DownloadResourceHandler(
on_response_started_called_(false) {
RecordDownloadCount(UNTHROTTLED_COUNT);
- // Do UI thread initialization asap after DownloadResourceHandler creation
- // since the tab could be navigated before StartOnUIThread gets called.
+ // Do UI thread initialization for tab_info_ asap after
+ // DownloadResourceHandler creation since the tab could be navigated
+ // before StartOnUIThread gets called. This is safe because deletion
+ // will occur via PostTask() as well, which will serialized behind this
+ // PostTask()
const ResourceRequestInfoImpl* request_info = GetRequestInfo();
- tab_info_ = new DownloadTabInfo();
BrowserThread::PostTask(
BrowserThread::UI,
FROM_HERE,
@@ -129,10 +134,10 @@ DownloadResourceHandler::DownloadResourceHandler(
request_info->GetChildID(),
request_info->GetRouteID(),
request_info->GetRequestID()),
- tab_info_));
+ tab_info_.get()));
power_save_blocker_ = PowerSaveBlocker::Create(
PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
- "Download in progress");
+ PowerSaveBlocker::kReasonOther, "Download in progress");
}
bool DownloadResourceHandler::OnUploadProgress(uint64 position,
@@ -151,12 +156,12 @@ bool DownloadResourceHandler::OnRequestRedirected(
bool DownloadResourceHandler::OnResponseStarted(
ResourceResponse* response,
bool* defer) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
// There can be only one (call)
DCHECK(!on_response_started_called_);
on_response_started_called_ = true;
- VLOG(20) << __FUNCTION__ << "()" << DebugString();
+ DVLOG(20) << __FUNCTION__ << "()" << DebugString();
download_start_time_ = base::TimeTicks::Now();
// If it's a download, we don't want to poison the cache with it.
@@ -244,14 +249,12 @@ bool DownloadResourceHandler::OnResponseStarted(
BrowserThread::UI, FROM_HERE,
base::Bind(&StartOnUIThread,
base::Passed(&info),
- base::Owned(tab_info_),
+ base::Passed(&tab_info_),
base::Passed(&stream_reader),
// Pass to StartOnUIThread so that variable
// access is always on IO thread but function
// is called on UI thread.
started_cb_));
- // Now owned by the task that was just posted.
- tab_info_ = NULL;
// Guaranteed to be called in StartOnUIThread
started_cb_.Reset();
@@ -261,7 +264,7 @@ bool DownloadResourceHandler::OnResponseStarted(
void DownloadResourceHandler::CallStartedCB(
DownloadItem* item,
DownloadInterruptReason interrupt_reason) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (started_cb_.is_null())
return;
BrowserThread::PostTask(
@@ -286,7 +289,7 @@ bool DownloadResourceHandler::OnBeforeNetworkStart(const GURL& url,
bool DownloadResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf,
int* buf_size,
int min_size) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(buf && buf_size);
DCHECK(!read_buffer_.get());
@@ -299,7 +302,7 @@ bool DownloadResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf,
// Pass the buffer to the download file writer.
bool DownloadResourceHandler::OnReadCompleted(int bytes_read, bool* defer) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(read_buffer_.get());
base::TimeTicks now(base::TimeTicks::Now());
@@ -341,12 +344,12 @@ void DownloadResourceHandler::OnResponseCompleted(
const net::URLRequestStatus& status,
const std::string& security_info,
bool* defer) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
int response_code = status.is_success() ? request()->GetResponseCode() : 0;
- VLOG(20) << __FUNCTION__ << "()" << DebugString()
- << " status.status() = " << status.status()
- << " status.error() = " << status.error()
- << " response_code = " << response_code;
+ DVLOG(20) << __FUNCTION__ << "()" << DebugString()
+ << " status.status() = " << status.status()
+ << " status.error() = " << status.error()
+ << " response_code = " << response_code;
net::Error error_code = net::OK;
if (status.status() == net::URLRequestStatus::FAILED ||
@@ -464,13 +467,13 @@ void DownloadResourceHandler::OnDataDownloaded(int bytes_downloaded) {
}
void DownloadResourceHandler::PauseRequest() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
++pause_count_;
}
void DownloadResourceHandler::ResumeRequest() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK_LT(0, pause_count_);
--pause_count_;
@@ -490,7 +493,7 @@ void DownloadResourceHandler::ResumeRequest() {
}
void DownloadResourceHandler::CancelRequest() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
const ResourceRequestInfo* info = GetRequestInfo();
ResourceDispatcherHostImpl::Get()->CancelRequest(
@@ -518,7 +521,7 @@ std::string DownloadResourceHandler::DebugString() const {
}
DownloadResourceHandler::~DownloadResourceHandler() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
// This won't do anything if the callback was called before.
// If it goes through, it will likely be because OnWillStart() returned
@@ -531,8 +534,11 @@ DownloadResourceHandler::~DownloadResourceHandler() {
// tab_info_ must be destroyed on UI thread, since
// InitializeDownloadTabInfoOnUIThread might still be using it.
- if (tab_info_)
- BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, tab_info_);
+ if (tab_info_.get()) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&DeleteOnUIThread, base::Passed(&tab_info_)));
+ }
UMA_HISTOGRAM_TIMES("SB2.DownloadDuration",
base::TimeTicks::Now() - download_start_time_);
diff --git a/chromium/content/browser/download/download_resource_handler.h b/chromium/content/browser/download/download_resource_handler.h
index 89587831496..93bb0cf7916 100644
--- a/chromium/content/browser/download/download_resource_handler.h
+++ b/chromium/content/browser/download/download_resource_handler.h
@@ -102,7 +102,9 @@ class CONTENT_EXPORT DownloadResourceHandler
// thread before StartOnUIThread is called.
// Created on IO thread, but only accessed on UI thread. |tab_info_| holds
// the pointer until we pass it off to StartOnUIThread or DeleteSoon.
- DownloadTabInfo* tab_info_;
+ // Marked as a scoped_ptr<> to indicate ownership of the structure, but
+ // deletion must occur on the IO thread.
+ scoped_ptr<DownloadTabInfo> tab_info_;
// Data flow
scoped_refptr<net::IOBuffer> read_buffer_; // From URLRequest.
diff --git a/chromium/content/browser/download/download_stats.cc b/chromium/content/browser/download/download_stats.cc
index d88eef2c4e2..f8b92bead61 100644
--- a/chromium/content/browser/download/download_stats.cc
+++ b/chromium/content/browser/download/download_stats.cc
@@ -31,7 +31,7 @@ enum ContentDispositionCountTypes {
// number of downloads is measured by UNTHROTTLED_COUNT.
CONTENT_DISPOSITION_HEADER_PRESENT = 0,
- // At least one of 'name', 'filename' or 'filenae*' attributes were valid and
+ // Either 'filename' or 'filename*' attributes were valid and
// yielded a non-empty filename.
CONTENT_DISPOSITION_IS_VALID,
@@ -39,15 +39,16 @@ enum ContentDispositionCountTypes {
// net::HttpContentDisposition::ParseResult.
CONTENT_DISPOSITION_HAS_DISPOSITION_TYPE,
CONTENT_DISPOSITION_HAS_UNKNOWN_TYPE,
- CONTENT_DISPOSITION_HAS_NAME,
+
+ CONTENT_DISPOSITION_HAS_NAME, // Obsolete; kept for UMA compatiblity.
+
CONTENT_DISPOSITION_HAS_FILENAME,
CONTENT_DISPOSITION_HAS_EXT_FILENAME,
CONTENT_DISPOSITION_HAS_NON_ASCII_STRINGS,
CONTENT_DISPOSITION_HAS_PERCENT_ENCODED_STRINGS,
CONTENT_DISPOSITION_HAS_RFC2047_ENCODED_STRINGS,
- // Only have the 'name' attribute is present.
- CONTENT_DISPOSITION_HAS_NAME_ONLY,
+ CONTENT_DISPOSITION_HAS_NAME_ONLY, // Obsolete; kept for UMA compatiblity.
CONTENT_DISPOSITION_LAST_ENTRY
};
@@ -505,9 +506,6 @@ void RecordDownloadContentDisposition(
CONTENT_DISPOSITION_HAS_UNKNOWN_TYPE, result,
net::HttpContentDisposition::HAS_UNKNOWN_DISPOSITION_TYPE);
RecordContentDispositionCountFlag(
- CONTENT_DISPOSITION_HAS_NAME, result,
- net::HttpContentDisposition::HAS_NAME);
- RecordContentDispositionCountFlag(
CONTENT_DISPOSITION_HAS_FILENAME, result,
net::HttpContentDisposition::HAS_FILENAME);
RecordContentDispositionCountFlag(
@@ -522,13 +520,6 @@ void RecordDownloadContentDisposition(
RecordContentDispositionCountFlag(
CONTENT_DISPOSITION_HAS_RFC2047_ENCODED_STRINGS, result,
net::HttpContentDisposition::HAS_RFC2047_ENCODED_STRINGS);
-
- RecordContentDispositionCount(
- CONTENT_DISPOSITION_HAS_NAME_ONLY,
- (result & (net::HttpContentDisposition::HAS_NAME |
- net::HttpContentDisposition::HAS_FILENAME |
- net::HttpContentDisposition::HAS_EXT_FILENAME)) ==
- net::HttpContentDisposition::HAS_NAME);
}
void RecordFileThreadReceiveBuffers(size_t num_buffers) {
diff --git a/chromium/content/browser/download/drag_download_file.cc b/chromium/content/browser/download/drag_download_file.cc
index ca68740a257..13950a1e2aa 100644
--- a/chromium/content/browser/download/drag_download_file.cc
+++ b/chromium/content/browser/download/drag_download_file.cc
@@ -55,7 +55,7 @@ class DragDownloadFile::DragDownloadFileUI : public DownloadItem::Observer {
void InitiateDownload(base::File file,
const base::FilePath& file_path) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DownloadManager* download_manager =
BrowserContext::GetDownloadManager(web_contents_->GetBrowserContext());
@@ -72,26 +72,26 @@ class DragDownloadFile::DragDownloadFileUI : public DownloadItem::Observer {
}
void Cancel() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (download_item_)
download_item_->Cancel(true);
}
void Delete() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
delete this;
}
private:
~DragDownloadFileUI() override {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (download_item_)
download_item_->RemoveObserver(this);
}
void OnDownloadStarted(DownloadItem* item,
DownloadInterruptReason interrupt_reason) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!item) {
DCHECK_NE(DOWNLOAD_INTERRUPT_REASON_NONE, interrupt_reason);
on_completed_loop_->PostTask(FROM_HERE, base::Bind(on_completed_, false));
@@ -104,7 +104,7 @@ class DragDownloadFile::DragDownloadFileUI : public DownloadItem::Observer {
// DownloadItem::Observer:
void OnDownloadUpdated(DownloadItem* item) override {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK_EQ(download_item_, item);
DownloadItem::DownloadState state = download_item_->GetState();
if (state == DownloadItem::COMPLETE ||
@@ -122,7 +122,7 @@ class DragDownloadFile::DragDownloadFileUI : public DownloadItem::Observer {
}
void OnDownloadDestroyed(DownloadItem* item) override {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK_EQ(download_item_, item);
if (!on_completed_.is_null()) {
const bool is_complete =
@@ -236,7 +236,7 @@ void DragDownloadFile::CheckThread() {
#if defined(OS_WIN)
DCHECK(drag_message_loop_ == base::MessageLoop::current());
#else
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
#endif
}
diff --git a/chromium/content/browser/download/drag_download_file_browsertest.cc b/chromium/content/browser/download/drag_download_file_browsertest.cc
index 0b1de7d6fcd..e6a85159b57 100644
--- a/chromium/content/browser/download/drag_download_file_browsertest.cc
+++ b/chromium/content/browser/download/drag_download_file_browsertest.cc
@@ -22,7 +22,6 @@
#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_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"
@@ -74,11 +73,9 @@ class DragDownloadFileTest : public ContentBrowserTest {
void SetUpServer() {
base::FilePath mock_base(GetTestFilePath("download", ""));
BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
+ BrowserThread::IO, FROM_HERE,
base::Bind(
- &net::URLRequestMockHTTPJob::AddUrlHandler,
- mock_base,
+ &net::URLRequestMockHTTPJob::AddUrlHandlers, mock_base,
make_scoped_refptr(content::BrowserThread::GetBlockingPool())));
}
diff --git a/chromium/content/browser/download/file_metadata_mac.mm b/chromium/content/browser/download/file_metadata_mac.mm
index 9dc504fcc49..f4ae3c97509 100644
--- a/chromium/content/browser/download/file_metadata_mac.mm
+++ b/chromium/content/browser/download/file_metadata_mac.mm
@@ -9,6 +9,7 @@
#include "base/files/file_path.h"
#include "base/logging.h"
+#include "base/mac/foundation_util.h"
#include "base/mac/mac_logging.h"
#include "base/mac/mac_util.h"
#include "base/mac/scoped_cftyperef.h"
diff --git a/chromium/content/browser/download/file_metadata_unittest_linux.cc b/chromium/content/browser/download/file_metadata_unittest_linux.cc
index ab7eb3c8044..d3a6ea4c69e 100644
--- a/chromium/content/browser/download/file_metadata_unittest_linux.cc
+++ b/chromium/content/browser/download/file_metadata_unittest_linux.cc
@@ -57,8 +57,8 @@ class FileMetadataLinuxTest : public testing::Test {
"user.test", "test", 4, 0);
is_xattr_supported_ = (!result) || (errno != ENOTSUP);
if (!is_xattr_supported_) {
- VLOG(0) << "Test will be skipped because extended attributes are not "
- << "supported on this OS/file system.";
+ DVLOG(0) << "Test will be skipped because extended attributes are not "
+ << "supported on this OS/file system.";
}
}
diff --git a/chromium/content/browser/download/mhtml_generation_manager.cc b/chromium/content/browser/download/mhtml_generation_manager.cc
index d02d509996a..4ace9875816 100644
--- a/chromium/content/browser/download/mhtml_generation_manager.cc
+++ b/chromium/content/browser/download/mhtml_generation_manager.cc
@@ -98,7 +98,7 @@ MHTMLGenerationManager::~MHTMLGenerationManager() {
void MHTMLGenerationManager::SaveMHTML(WebContents* web_contents,
const base::FilePath& file,
const GenerateMHTMLCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
int job_id = NewJob(web_contents, callback);
@@ -113,7 +113,7 @@ void MHTMLGenerationManager::StreamMHTML(
WebContents* web_contents,
base::File browser_file,
const GenerateMHTMLCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
int job_id = NewJob(web_contents, callback);
@@ -134,7 +134,7 @@ void MHTMLGenerationManager::MHTMLGenerated(int job_id, int64 mhtml_data_size) {
void MHTMLGenerationManager::CreateFile(
int job_id, const base::FilePath& file_path,
base::ProcessHandle renderer_process) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
base::File browser_file(
file_path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
if (!browser_file.IsValid()) {
@@ -160,7 +160,7 @@ void MHTMLGenerationManager::FileAvailable(
int job_id,
base::File browser_file,
IPC::PlatformFileForTransit renderer_file) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!browser_file.IsValid()) {
LOG(ERROR) << "Failed to create file";
JobFinished(job_id, -1);
@@ -189,7 +189,7 @@ void MHTMLGenerationManager::FileAvailable(
}
void MHTMLGenerationManager::JobFinished(int job_id, int64 file_size) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
IDToJobMap::iterator iter = id_to_job_.find(job_id);
if (iter == id_to_job_.end()) {
NOTREACHED();
@@ -208,7 +208,7 @@ void MHTMLGenerationManager::JobFinished(int job_id, int64 file_size) {
}
void MHTMLGenerationManager::CloseFile(base::File file) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
file.Close();
}
@@ -224,7 +224,7 @@ int MHTMLGenerationManager::NewJob(WebContents* web_contents,
}
void MHTMLGenerationManager::RenderProcessExited(Job* job) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
for (IDToJobMap::iterator it = id_to_job_.begin(); it != id_to_job_.end();
++it) {
if (it->second == job) {
diff --git a/chromium/content/browser/download/save_file.cc b/chromium/content/browser/download/save_file.cc
index 4404fc866d7..a5c7488242f 100644
--- a/chromium/content/browser/download/save_file.cc
+++ b/chromium/content/browser/download/save_file.cc
@@ -23,14 +23,14 @@ SaveFile::SaveFile(const SaveFileCreateInfo* info, bool calculate_hash)
base::File(),
net::BoundNetLog()),
info_(info) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
DCHECK(info);
DCHECK(info->path.empty());
}
SaveFile::~SaveFile() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
}
DownloadInterruptReason SaveFile::Initialize() {
diff --git a/chromium/content/browser/download/save_file_manager.cc b/chromium/content/browser/download/save_file_manager.cc
index e9c03f484ff..e7e74c2aad6 100644
--- a/chromium/content/browser/download/save_file_manager.cc
+++ b/chromium/content/browser/download/save_file_manager.cc
@@ -43,7 +43,7 @@ void SaveFileManager::Shutdown() {
// Stop file thread operations.
void SaveFileManager::OnShutdown() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
STLDeleteValues(&save_file_map_);
}
@@ -59,14 +59,14 @@ SaveFile* SaveFileManager::LookupSaveFile(int save_id) {
// file a request from the file thread to the IO thread to generate a
// unique save ID.
int SaveFileManager::GetNextId() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
return next_id_++;
}
void SaveFileManager::RegisterStartingRequest(const GURL& save_url,
SavePackage* save_package) {
// Make sure it runs in the UI thread.
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
int contents_id = save_package->contents_id();
// Register this starting request.
@@ -80,7 +80,7 @@ void SaveFileManager::RegisterStartingRequest(const GURL& save_url,
SavePackage* SaveFileManager::UnregisterStartingRequest(
const GURL& save_url, int contents_id) {
// Make sure it runs in UI thread.
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
ContentsToStartingRequestsMap::iterator it =
contents_starting_requests_.find(contents_id);
@@ -104,7 +104,7 @@ SavePackage* SaveFileManager::UnregisterStartingRequest(
// Look up a SavePackage according to a save id.
SavePackage* SaveFileManager::LookupPackage(int save_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
SavePackageMap::iterator it = packages_.find(save_id);
if (it != packages_.end())
return it->second;
@@ -121,7 +121,7 @@ void SaveFileManager::SaveURL(
const base::FilePath& file_full_path,
ResourceContext* context,
SavePackage* save_package) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
// Register a saving job.
RegisterStartingRequest(url, save_package);
@@ -159,7 +159,7 @@ void SaveFileManager::SaveURL(
void SaveFileManager::RemoveSaveFile(int save_id, const GURL& save_url,
SavePackage* package) {
DCHECK(package);
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
// A save page job (SavePackage) can only have one manager,
// so remove it if it exists.
if (save_id == -1) {
@@ -191,7 +191,7 @@ SavePackage* SaveFileManager::GetSavePackageFromRenderIds(
void SaveFileManager::DeleteDirectoryOrFile(const base::FilePath& full_path,
bool is_dir) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
BrowserThread::PostTask(
BrowserThread::FILE, FROM_HERE,
base::Bind(&SaveFileManager::OnDeleteDirectoryOrFile,
@@ -212,7 +212,7 @@ void SaveFileManager::SendCancelRequest(int save_id) {
// to create a SaveFile which will hold and finally destroy |info|. It will
// then passes |info| to the UI thread for reporting saving status.
void SaveFileManager::StartSave(SaveFileCreateInfo* info) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
DCHECK(info);
// No need to calculate hash.
SaveFile* save_file = new SaveFile(info, false);
@@ -236,7 +236,7 @@ void SaveFileManager::StartSave(SaveFileCreateInfo* info) {
void SaveFileManager::UpdateSaveProgress(int save_id,
net::IOBuffer* data,
int data_len) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
SaveFile* save_file = LookupSaveFile(save_id);
if (save_file) {
DCHECK(save_file->InProgress());
@@ -263,11 +263,11 @@ void SaveFileManager::SaveFinished(int save_id,
const GURL& save_url,
int render_process_id,
bool is_success) {
- VLOG(20) << " " << __FUNCTION__ << "()"
- << " save_id = " << save_id
- << " save_url = \"" << save_url.spec() << "\""
- << " is_success = " << is_success;
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DVLOG(20) << " " << __FUNCTION__ << "()"
+ << " save_id = " << save_id
+ << " save_url = \"" << save_url.spec() << "\""
+ << " is_success = " << is_success;
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
SaveFileMap::iterator it = save_file_map_.find(save_id);
if (it != save_file_map_.end()) {
SaveFile* save_file = it->second;
@@ -278,8 +278,8 @@ void SaveFileManager::SaveFinished(int save_id,
// TODO(rdsmith): Fix this logic and put the DCHECK below back in.
// DCHECK(save_file->InProgress());
- VLOG(20) << " " << __FUNCTION__ << "()"
- << " save_file = " << save_file->DebugString();
+ DVLOG(20) << " " << __FUNCTION__ << "()"
+ << " save_file = " << save_file->DebugString();
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&SaveFileManager::OnSaveFinished, this, save_id,
@@ -300,7 +300,7 @@ void SaveFileManager::SaveFinished(int save_id,
// Notifications sent from the file thread and run on the UI thread.
void SaveFileManager::OnStartSave(const SaveFileCreateInfo* info) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
SavePackage* save_package =
GetSavePackageFromRenderIds(info->render_process_id,
info->render_view_id);
@@ -334,7 +334,7 @@ void SaveFileManager::OnStartSave(const SaveFileCreateInfo* info) {
void SaveFileManager::OnUpdateSaveProgress(int save_id, int64 bytes_so_far,
bool write_success) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
SavePackage* package = LookupPackage(save_id);
if (package)
package->UpdateSaveProgress(save_id, bytes_so_far, write_success);
@@ -345,14 +345,14 @@ void SaveFileManager::OnUpdateSaveProgress(int save_id, int64 bytes_so_far,
void SaveFileManager::OnSaveFinished(int save_id,
int64 bytes_so_far,
bool is_success) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
SavePackage* package = LookupPackage(save_id);
if (package)
package->SaveFinished(save_id, bytes_so_far, is_success);
}
void SaveFileManager::OnErrorFinished(const GURL& save_url, int contents_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
SavePackage* save_package = UnregisterStartingRequest(save_url, contents_id);
if (save_package)
save_package->SaveFailed(save_url);
@@ -366,7 +366,7 @@ void SaveFileManager::OnSaveURL(
int render_process_host_id,
int render_view_id,
ResourceContext* context) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
ResourceDispatcherHostImpl::Get()->BeginSaveFile(url,
referrer,
render_process_host_id,
@@ -376,7 +376,7 @@ void SaveFileManager::OnSaveURL(
void SaveFileManager::OnRequireSaveJobFromOtherSource(
SaveFileCreateInfo* info) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK_EQ(info->save_id, -1);
// Generate a unique save id.
info->save_id = GetNextId();
@@ -388,7 +388,7 @@ void SaveFileManager::OnRequireSaveJobFromOtherSource(
void SaveFileManager::ExecuteCancelSaveRequest(int render_process_id,
int request_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
ResourceDispatcherHostImpl::Get()->CancelRequest(
render_process_id, request_id);
}
@@ -401,7 +401,7 @@ void SaveFileManager::ExecuteCancelSaveRequest(int render_process_id,
// sent from the UI thread, the saving job may have already completed and
// won't exist in our map.
void SaveFileManager::CancelSave(int save_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
SaveFileMap::iterator it = save_file_map_.find(save_id);
if (it != save_file_map_.end()) {
SaveFile* save_file = it->second;
@@ -436,7 +436,7 @@ void SaveFileManager::CancelSave(int save_id) {
void SaveFileManager::SaveLocalFile(const GURL& original_file_url,
int save_id,
int render_process_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
SaveFile* save_file = LookupSaveFile(save_id);
if (!save_file)
return;
@@ -466,7 +466,7 @@ void SaveFileManager::SaveLocalFile(const GURL& original_file_url,
void SaveFileManager::OnDeleteDirectoryOrFile(const base::FilePath& full_path,
bool is_dir) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
DCHECK(!full_path.empty());
base::DeleteFile(full_path, is_dir);
@@ -478,7 +478,7 @@ void SaveFileManager::RenameAllFiles(
int render_process_id,
int render_view_id,
int save_package_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
if (!resource_dir.empty() && !base::PathExists(resource_dir))
base::CreateDirectory(resource_dir);
@@ -504,7 +504,7 @@ void SaveFileManager::RenameAllFiles(
void SaveFileManager::OnFinishSavePageJob(int render_process_id,
int render_view_id,
int save_package_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
SavePackage* save_package =
GetSavePackageFromRenderIds(render_process_id, render_view_id);
@@ -515,7 +515,7 @@ void SaveFileManager::OnFinishSavePageJob(int render_process_id,
void SaveFileManager::RemoveSavedFileFromFileMap(
const SaveIDList& save_ids) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
for (SaveIDList::const_iterator i = save_ids.begin();
i != save_ids.end(); ++i) {
diff --git a/chromium/content/browser/download/save_package.cc b/chromium/content/browser/download/save_package.cc
index 486cb1057d1..b8799399aaf 100644
--- a/chromium/content/browser/download/save_package.cc
+++ b/chromium/content/browser/download/save_package.cc
@@ -255,7 +255,7 @@ GURL SavePackage::GetUrlToBeSaved() {
// different (like having "view-source:" on the front).
NavigationEntry* visible_entry =
web_contents()->GetController().GetVisibleEntry();
- return visible_entry->GetURL();
+ return visible_entry ? visible_entry->GetURL() : GURL::EmptyGURL();
}
void SavePackage::Cancel(bool user_action) {
@@ -291,7 +291,7 @@ void SavePackage::InternalInit() {
bool SavePackage::Init(
const SavePackageDownloadCreatedCallback& download_created_callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
// Set proper running state.
if (wait_state_ != INITIALIZE)
return false;
@@ -322,7 +322,7 @@ bool SavePackage::Init(
void SavePackage::InitWithDownloadItem(
const SavePackageDownloadCreatedCallback& download_created_callback,
DownloadItemImpl* item) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(item);
download_ = item;
download_->AddObserver(this);
@@ -1071,9 +1071,9 @@ void SavePackage::OnReceivedSerializedHtmlData(const GURL& frame_url,
if (flag == WebPageSerializerClient::AllFramesAreFinished) {
for (SaveUrlItemMap::iterator it = in_progress_items_.begin();
it != in_progress_items_.end(); ++it) {
- VLOG(20) << " " << __FUNCTION__ << "()"
- << " save_id = " << it->second->save_id()
- << " url = \"" << it->second->url().spec() << "\"";
+ DVLOG(20) << " " << __FUNCTION__ << "()"
+ << " save_id = " << it->second->save_id()
+ << " url = \"" << it->second->url().spec() << "\"";
BrowserThread::PostTask(
BrowserThread::FILE, FROM_HERE,
base::Bind(&SaveFileManager::SaveFinished,
@@ -1123,9 +1123,9 @@ void SavePackage::OnReceivedSerializedHtmlData(const GURL& frame_url,
// Current frame is completed saving, call finish in file thread.
if (flag == WebPageSerializerClient::CurrentFrameIsFinished) {
- VLOG(20) << " " << __FUNCTION__ << "()"
- << " save_id = " << save_item->save_id()
- << " url = \"" << save_item->url().spec() << "\"";
+ DVLOG(20) << " " << __FUNCTION__ << "()"
+ << " save_id = " << save_item->save_id()
+ << " url = \"" << save_item->url().spec() << "\"";
BrowserThread::PostTask(
BrowserThread::FILE, FROM_HERE,
base::Bind(&SaveFileManager::SaveFinished,
@@ -1242,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();
- base::i18n::ReplaceIllegalCharactersInPath(&file_name, ' ');
+ base::i18n::ReplaceIllegalCharactersInPath(&file_name, '_');
return base::FilePath(file_name);
}
diff --git a/chromium/content/browser/download/save_package_unittest.cc b/chromium/content/browser/download/save_package_unittest.cc
index c0dcbf0a7eb..c6c862c4e75 100644
--- a/chromium/content/browser/download/save_package_unittest.cc
+++ b/chromium/content/browser/download/save_package_unittest.cc
@@ -382,7 +382,7 @@ static const struct SuggestedSaveNameTestCase {
// A URL-like title that does not match the title is respected in full.
{ "http://foo.com",
base::ASCIIToUTF16("http://www.foo.com/path/title.txt"),
- FPL("http www.foo.com path title.txt"),
+ FPL("http___www.foo.com_path_title.txt"),
false
},
};
diff --git a/chromium/content/browser/file_descriptor_info_impl.cc b/chromium/content/browser/file_descriptor_info_impl.cc
index c1f055bc76d..45ce54246ec 100644
--- a/chromium/content/browser/file_descriptor_info_impl.cc
+++ b/chromium/content/browser/file_descriptor_info_impl.cc
@@ -47,6 +47,27 @@ bool FileDescriptorInfoImpl::HasID(int id) const {
return false;
}
+bool FileDescriptorInfoImpl::OwnsFD(base::PlatformFile file) const {
+ return owned_descriptors_.end() !=
+ std::find_if(
+ owned_descriptors_.begin(), owned_descriptors_.end(),
+ [file](const base::ScopedFD* fd) { return fd->get() == file; });
+}
+
+base::ScopedFD FileDescriptorInfoImpl::ReleaseFD(base::PlatformFile file) {
+ DCHECK(OwnsFD(file));
+
+ base::ScopedFD fd;
+ auto found = std::find_if(
+ owned_descriptors_.begin(), owned_descriptors_.end(),
+ [file](const base::ScopedFD* fd) { return fd->get() == file; });
+
+ (*found)->swap(fd);
+ owned_descriptors_.erase(found);
+
+ return fd.Pass();
+}
+
void FileDescriptorInfoImpl::AddToMapping(int id, base::PlatformFile fd) {
DCHECK(!HasID(id));
mapping_.push_back(std::make_pair(fd, id));
diff --git a/chromium/content/browser/file_descriptor_info_impl.h b/chromium/content/browser/file_descriptor_info_impl.h
index 78d746e22d4..40db9593244 100644
--- a/chromium/content/browser/file_descriptor_info_impl.h
+++ b/chromium/content/browser/file_descriptor_info_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_PUBLIC_BROWSER_FILE_DESCRIPTOR_INFO_IMPL_H_
-#define CONTENT_PUBLIC_BROWSER_FILE_DESCRIPTOR_INFO_IMPL_H_
+#ifndef CONTENT_BROWSER_FILE_DESCRIPTOR_INFO_IMPL_H_
+#define CONTENT_BROWSER_FILE_DESCRIPTOR_INFO_IMPL_H_
#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
@@ -25,6 +25,8 @@ class FileDescriptorInfoImpl : public FileDescriptorInfo {
base::PlatformFile GetFDAt(size_t i) const override;
int GetIDAt(size_t i) const override;
size_t GetMappingSize() const override;
+ bool OwnsFD(base::PlatformFile file) const override;
+ base::ScopedFD ReleaseFD(base::PlatformFile file) override;
private:
FileDescriptorInfoImpl();
@@ -36,4 +38,4 @@ class FileDescriptorInfoImpl : public FileDescriptorInfo {
};
}
-#endif // CONTENT_PUBLIC_BROWSER_FILE_DESCRIPTOR_INFO_IMPL_H_
+#endif // CONTENT_BROWSER_FILE_DESCRIPTOR_INFO_IMPL_H_
diff --git a/chromium/content/browser/fileapi/blob_storage_context_unittest.cc b/chromium/content/browser/fileapi/blob_storage_context_unittest.cc
index 6ac1832894c..29270b7dea9 100644
--- a/chromium/content/browser/fileapi/blob_storage_context_unittest.cc
+++ b/chromium/content/browser/fileapi/blob_storage_context_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 "storage/browser/blob/blob_storage_context.h"
+
+#include <limits>
+#include <string>
+
#include "base/files/file_path.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
@@ -9,23 +14,31 @@
#include "base/run_loop.h"
#include "base/time/time.h"
#include "content/browser/fileapi/blob_storage_host.h"
+#include "storage/browser/blob/blob_data_builder.h"
#include "storage/browser/blob/blob_data_handle.h"
-#include "storage/browser/blob/blob_storage_context.h"
+#include "storage/browser/blob/blob_data_item.h"
+#include "storage/browser/blob/blob_data_snapshot.h"
#include "testing/gtest/include/gtest/gtest.h"
+using storage::BlobDataBuilder;
using storage::BlobDataHandle;
+using storage::BlobDataItem;
+using storage::BlobDataSnapshot;
+using storage::BlobStorageContext;
+using storage::DataElement;
namespace content {
-
namespace {
+
void SetupBasicBlob(BlobStorageHost* host, const std::string& id) {
EXPECT_TRUE(host->StartBuildingBlob(id));
- BlobData::Item item;
+ DataElement item;
item.SetToBytes("1", 1);
EXPECT_TRUE(host->AppendBlobDataItem(id, item));
EXPECT_TRUE(host->FinishBuildingBlob(id, "text/plain"));
EXPECT_FALSE(host->StartBuildingBlob(id));
}
+
} // namespace
TEST(BlobStorageContextTest, IncrementDecrementRef) {
@@ -42,10 +55,7 @@ TEST(BlobStorageContextTest, IncrementDecrementRef) {
blob_data_handle = context.GetBlobDataFromUUID(kId);
EXPECT_TRUE(blob_data_handle);
blob_data_handle.reset();
- { // Clean up for ASAN
- base::RunLoop run_loop;
- run_loop.RunUntilIdle();
- }
+ base::RunLoop().RunUntilIdle();
// Make sure its still there after inc/dec.
EXPECT_TRUE(host.IncrementBlobRefCount(kId));
@@ -53,10 +63,7 @@ TEST(BlobStorageContextTest, IncrementDecrementRef) {
blob_data_handle = context.GetBlobDataFromUUID(kId);
EXPECT_TRUE(blob_data_handle);
blob_data_handle.reset();
- { // Clean up for ASAN
- base::RunLoop run_loop;
- run_loop.RunUntilIdle();
- }
+ base::RunLoop().RunUntilIdle();
// Make sure it goes away in the end.
EXPECT_TRUE(host.DecrementBlobRefCount(kId));
@@ -66,6 +73,22 @@ TEST(BlobStorageContextTest, IncrementDecrementRef) {
EXPECT_FALSE(host.IncrementBlobRefCount(kId));
}
+TEST(BlobStorageContextTest, CancelBuildingBlob) {
+ BlobStorageContext context;
+ BlobStorageHost host(&context);
+ base::MessageLoop fake_io_message_loop;
+
+ // Build up a basic blob.
+ const std::string kId("id");
+ EXPECT_TRUE(host.StartBuildingBlob(kId));
+ DataElement item;
+ item.SetToBytes("1", 1);
+ EXPECT_TRUE(host.AppendBlobDataItem(kId, item));
+ EXPECT_TRUE(host.CancelBuildingBlob(kId));
+ EXPECT_FALSE(host.FinishBuildingBlob(kId, "text/plain"));
+ EXPECT_TRUE(host.StartBuildingBlob(kId));
+}
+
TEST(BlobStorageContextTest, BlobDataHandle) {
BlobStorageContext context;
BlobStorageHost host(&context);
@@ -91,14 +114,154 @@ TEST(BlobStorageContextTest, BlobDataHandle) {
// Should disappear after dropping both handles.
blob_data_handle.reset();
another_handle.reset();
- { // Clean up for ASAN
- base::RunLoop run_loop;
- run_loop.RunUntilIdle();
- }
+ base::RunLoop().RunUntilIdle();
+
blob_data_handle = context.GetBlobDataFromUUID(kId);
EXPECT_FALSE(blob_data_handle);
}
+TEST(BlobStorageContextTest, MemoryUsage) {
+ const std::string kId1("id1");
+ const std::string kId2("id2");
+
+ base::MessageLoop fake_io_message_loop;
+
+ BlobDataBuilder builder1(kId1);
+ BlobDataBuilder builder2(kId2);
+ builder1.AppendData("Data1Data2");
+ builder2.AppendBlob(kId1);
+ builder2.AppendBlob(kId1);
+ builder2.AppendBlob(kId1);
+ builder2.AppendBlob(kId1);
+ builder2.AppendBlob(kId1);
+ builder2.AppendBlob(kId1);
+ builder2.AppendBlob(kId1);
+
+ BlobStorageContext context;
+ EXPECT_EQ(0lu, context.memory_usage());
+
+ scoped_ptr<BlobDataHandle> blob_data_handle =
+ context.AddFinishedBlob(&builder1);
+ EXPECT_EQ(10lu, context.memory_usage());
+ scoped_ptr<BlobDataHandle> blob_data_handle2 =
+ context.AddFinishedBlob(&builder2);
+ EXPECT_EQ(10lu, context.memory_usage());
+
+ blob_data_handle.reset();
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(10lu, context.memory_usage());
+ blob_data_handle2.reset();
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(0lu, context.memory_usage());
+}
+
+TEST(BlobStorageContextTest, AddFinishedBlob) {
+ const std::string kId1("id1");
+ const std::string kId2("id12");
+ const std::string kId2Prime("id2.prime");
+ const std::string kId3("id3");
+ const std::string kId3Prime("id3.prime");
+
+ base::MessageLoop fake_io_message_loop;
+
+ BlobDataBuilder builder1(kId1);
+ BlobDataBuilder builder2(kId2);
+ BlobDataBuilder canonicalized_blob_data2(kId2Prime);
+ builder1.AppendData("Data1Data2");
+ builder2.AppendBlob(kId1, 5, 5);
+ builder2.AppendData(" is the best");
+ canonicalized_blob_data2.AppendData("Data2");
+ canonicalized_blob_data2.AppendData(" is the best");
+
+ BlobStorageContext context;
+
+ scoped_ptr<BlobDataHandle> blob_data_handle =
+ context.AddFinishedBlob(&builder1);
+ scoped_ptr<BlobDataHandle> blob_data_handle2 =
+ context.AddFinishedBlob(&builder2);
+
+ ASSERT_TRUE(blob_data_handle);
+ ASSERT_TRUE(blob_data_handle2);
+ scoped_ptr<BlobDataSnapshot> data1 = blob_data_handle->CreateSnapshot();
+ scoped_ptr<BlobDataSnapshot> data2 = blob_data_handle2->CreateSnapshot();
+ EXPECT_EQ(*data1, builder1);
+ EXPECT_EQ(*data2, canonicalized_blob_data2);
+ blob_data_handle.reset();
+ data2.reset();
+
+ base::RunLoop().RunUntilIdle();
+
+ blob_data_handle = context.GetBlobDataFromUUID(kId1);
+ EXPECT_FALSE(blob_data_handle);
+ EXPECT_TRUE(blob_data_handle2);
+ data2 = blob_data_handle2->CreateSnapshot();
+ EXPECT_EQ(*data2, canonicalized_blob_data2);
+
+ // Test shared elements stick around.
+ BlobDataBuilder builder3(kId3);
+ builder3.AppendBlob(kId2);
+ builder3.AppendBlob(kId2);
+ scoped_ptr<BlobDataHandle> blob_data_handle3 =
+ context.AddFinishedBlob(&builder3);
+ blob_data_handle2.reset();
+ base::RunLoop().RunUntilIdle();
+
+ blob_data_handle2 = context.GetBlobDataFromUUID(kId2);
+ EXPECT_FALSE(blob_data_handle2);
+ EXPECT_TRUE(blob_data_handle3);
+ scoped_ptr<BlobDataSnapshot> data3 = blob_data_handle3->CreateSnapshot();
+
+ BlobDataBuilder canonicalized_blob_data3(kId3Prime);
+ canonicalized_blob_data3.AppendData("Data2");
+ canonicalized_blob_data3.AppendData(" is the best");
+ canonicalized_blob_data3.AppendData("Data2");
+ canonicalized_blob_data3.AppendData(" is the best");
+ EXPECT_EQ(*data3, canonicalized_blob_data3);
+
+ blob_data_handle.reset();
+ blob_data_handle2.reset();
+ blob_data_handle3.reset();
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST(BlobStorageContextTest, AddFinishedBlob_LargeOffset) {
+ // A value which does not fit in a 4-byte data type. Used to confirm that
+ // large values are supported on 32-bit Chromium builds. Regression test for:
+ // crbug.com/458122.
+ const uint64_t kLargeSize = std::numeric_limits<uint64_t>::max();
+
+ const uint64_t kBlobLength = 5;
+ const std::string kId1("id1");
+ const std::string kId2("id2");
+ base::MessageLoop fake_io_message_loop;
+
+ BlobDataBuilder builder1(kId1);
+ builder1.AppendFileSystemFile(GURL(), 0, kLargeSize, base::Time::Now());
+
+ BlobDataBuilder builder2(kId2);
+ builder2.AppendBlob(kId1, kLargeSize - kBlobLength, kBlobLength);
+
+ BlobStorageContext context;
+ scoped_ptr<BlobDataHandle> blob_data_handle1 =
+ context.AddFinishedBlob(&builder1);
+ scoped_ptr<BlobDataHandle> blob_data_handle2 =
+ context.AddFinishedBlob(&builder2);
+
+ ASSERT_TRUE(blob_data_handle1);
+ ASSERT_TRUE(blob_data_handle2);
+ scoped_ptr<BlobDataSnapshot> data = blob_data_handle2->CreateSnapshot();
+ ASSERT_EQ(1u, data->items().size());
+ const scoped_refptr<BlobDataItem> item = data->items()[0];
+ EXPECT_EQ(kLargeSize - kBlobLength, item->offset());
+ EXPECT_EQ(kBlobLength, item->length());
+
+ blob_data_handle1.reset();
+ blob_data_handle2.reset();
+ base::RunLoop().RunUntilIdle();
+}
+
TEST(BlobStorageContextTest, CompoundBlobs) {
const std::string kId1("id1");
const std::string kId2("id2");
@@ -111,45 +274,46 @@ TEST(BlobStorageContextTest, CompoundBlobs) {
base::Time::FromString("Tue, 15 Nov 1994, 12:45:26 GMT", &time1);
base::Time::FromString("Mon, 14 Nov 1994, 11:30:49 GMT", &time2);
- scoped_refptr<BlobData> blob_data1(new BlobData(kId1));
- blob_data1->AppendData("Data1");
- blob_data1->AppendData("Data2");
- blob_data1->AppendFile(base::FilePath(FILE_PATH_LITERAL("File1.txt")),
- 10, 1024, time1);
-
- scoped_refptr<BlobData> blob_data2(new BlobData(kId2));
- blob_data2->AppendData("Data3");
- blob_data2->AppendBlob(kId1, 8, 100);
- blob_data2->AppendFile(base::FilePath(FILE_PATH_LITERAL("File2.txt")),
- 0, 20, time2);
-
- scoped_refptr<BlobData> canonicalized_blob_data2(new BlobData(kId2Prime));
- canonicalized_blob_data2->AppendData("Data3");
- canonicalized_blob_data2->AppendData("a2___", 2);
- canonicalized_blob_data2->AppendFile(
- base::FilePath(FILE_PATH_LITERAL("File1.txt")),
- 10, 98, time1);
- canonicalized_blob_data2->AppendFile(
+ BlobDataBuilder blob_data1(kId1);
+ blob_data1.AppendData("Data1");
+ blob_data1.AppendData("Data2");
+ blob_data1.AppendFile(base::FilePath(FILE_PATH_LITERAL("File1.txt")), 10,
+ 1024, time1);
+
+ BlobDataBuilder blob_data2(kId2);
+ blob_data2.AppendData("Data3");
+ blob_data2.AppendBlob(kId1, 8, 100);
+ blob_data2.AppendFile(base::FilePath(FILE_PATH_LITERAL("File2.txt")), 0, 20,
+ time2);
+
+ BlobDataBuilder canonicalized_blob_data2(kId2Prime);
+ canonicalized_blob_data2.AppendData("Data3");
+ canonicalized_blob_data2.AppendData("a2___", 2);
+ canonicalized_blob_data2.AppendFile(
+ base::FilePath(FILE_PATH_LITERAL("File1.txt")), 10, 98, time1);
+ canonicalized_blob_data2.AppendFile(
base::FilePath(FILE_PATH_LITERAL("File2.txt")), 0, 20, time2);
BlobStorageContext context;
scoped_ptr<BlobDataHandle> blob_data_handle;
// Test a blob referring to only data and a file.
- blob_data_handle = context.AddFinishedBlob(blob_data1.get());
- ASSERT_TRUE(blob_data_handle.get());
- EXPECT_TRUE(*(blob_data_handle->data()) == *blob_data1.get());
+ blob_data_handle = context.AddFinishedBlob(&blob_data1);
+
+ ASSERT_TRUE(blob_data_handle);
+ scoped_ptr<BlobDataSnapshot> data = blob_data_handle->CreateSnapshot();
+ ASSERT_TRUE(blob_data_handle);
+ EXPECT_EQ(*data, blob_data1);
// Test a blob composed in part with another blob.
- blob_data_handle = context.AddFinishedBlob(blob_data2.get());
- ASSERT_TRUE(blob_data_handle.get());
- EXPECT_TRUE(*(blob_data_handle->data()) == *canonicalized_blob_data2.get());
+ blob_data_handle = context.AddFinishedBlob(&blob_data2);
+ data = blob_data_handle->CreateSnapshot();
+ ASSERT_TRUE(blob_data_handle);
+ ASSERT_TRUE(data);
+ EXPECT_EQ(*data, canonicalized_blob_data2);
blob_data_handle.reset();
- { // Clean up for ASAN
- base::RunLoop run_loop;
- run_loop.RunUntilIdle();
- }
+ base::RunLoop().RunUntilIdle();
}
TEST(BlobStorageContextTest, PublicBlobUrls) {
@@ -167,12 +331,10 @@ TEST(BlobStorageContextTest, PublicBlobUrls) {
scoped_ptr<BlobDataHandle> blob_data_handle =
context.GetBlobDataFromPublicURL(kUrl);
ASSERT_TRUE(blob_data_handle.get());
- EXPECT_EQ(kId, blob_data_handle->data()->uuid());
+ EXPECT_EQ(kId, blob_data_handle->uuid());
+ scoped_ptr<BlobDataSnapshot> data = blob_data_handle->CreateSnapshot();
blob_data_handle.reset();
- { // Clean up for ASAN
- base::RunLoop run_loop;
- run_loop.RunUntilIdle();
- }
+ base::RunLoop().RunUntilIdle();
// The url registration should keep the blob alive even after
// explicit references are dropped.
@@ -180,10 +342,7 @@ TEST(BlobStorageContextTest, PublicBlobUrls) {
blob_data_handle = context.GetBlobDataFromPublicURL(kUrl);
EXPECT_TRUE(blob_data_handle);
blob_data_handle.reset();
- { // Clean up for ASAN
- base::RunLoop run_loop;
- run_loop.RunUntilIdle();
- }
+ base::RunLoop().RunUntilIdle();
// Finally get rid of the url registration and the blob.
EXPECT_TRUE(host.RevokePublicBlobURL(kUrl));
@@ -222,7 +381,7 @@ TEST(BlobStorageContextTest, EarlyContextDeletion) {
const std::string kId("id");
GURL kUrl("blob:id");
EXPECT_FALSE(host.StartBuildingBlob(kId));
- BlobData::Item item;
+ DataElement item;
item.SetToBytes("1", 1);
EXPECT_FALSE(host.AppendBlobDataItem(kId, item));
EXPECT_FALSE(host.FinishBuildingBlob(kId, "text/plain"));
diff --git a/chromium/content/browser/fileapi/blob_storage_host.cc b/chromium/content/browser/fileapi/blob_storage_host.cc
index 87e675ce5d1..faf81010dd3 100644
--- a/chromium/content/browser/fileapi/blob_storage_host.cc
+++ b/chromium/content/browser/fileapi/blob_storage_host.cc
@@ -6,12 +6,10 @@
#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"
using storage::BlobStorageContext;
-using storage::BlobData;
namespace content {
@@ -42,7 +40,8 @@ bool BlobStorageHost::StartBuildingBlob(const std::string& uuid) {
}
bool BlobStorageHost::AppendBlobDataItem(
- const std::string& uuid, const BlobData::Item& data_item) {
+ const std::string& uuid,
+ const storage::DataElement& data_item) {
if (!context_.get() || !IsBeingBuiltInHost(uuid))
return false;
context_->AppendBlobDataItem(uuid, data_item);
diff --git a/chromium/content/browser/fileapi/blob_storage_host.h b/chromium/content/browser/fileapi/blob_storage_host.h
index 3544f398b7d..dc277ae5acc 100644
--- a/chromium/content/browser/fileapi/blob_storage_host.h
+++ b/chromium/content/browser/fileapi/blob_storage_host.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_FILEAPI_STORAGE_HOST_H_
-#define CONTENT_BROWSER_FILEAPI_STORAGE_HOST_H_
+#ifndef CONTENT_BROWSER_FILEAPI_BLOB_STORAGE_HOST_H_
+#define CONTENT_BROWSER_FILEAPI_BLOB_STORAGE_HOST_H_
#include <map>
#include <set>
@@ -12,7 +12,7 @@
#include "base/compiler_specific.h"
#include "base/memory/weak_ptr.h"
#include "content/common/content_export.h"
-#include "storage/common/blob/blob_data.h"
+#include "storage/common/data_element.h"
class GURL;
@@ -22,9 +22,6 @@ class BlobStorageHost;
class BlobStorageContext;
}
-using storage::BlobStorageContext;
-using storage::BlobData;
-
namespace content {
// This class handles the logistics of blob storage for a single child process.
@@ -34,7 +31,7 @@ namespace content {
// only be used on the IO thread.
class CONTENT_EXPORT BlobStorageHost {
public:
- explicit BlobStorageHost(BlobStorageContext* context);
+ explicit BlobStorageHost(storage::BlobStorageContext* context);
~BlobStorageHost();
// Methods to support the IPC message protocol.
@@ -42,7 +39,8 @@ class CONTENT_EXPORT BlobStorageHost {
// like a non-existent or pre-existent uuid or url.
bool StartBuildingBlob(const std::string& uuid) WARN_UNUSED_RESULT;
bool AppendBlobDataItem(const std::string& uuid,
- const BlobData::Item& data_item) WARN_UNUSED_RESULT;
+ const storage::DataElement& data_item)
+ WARN_UNUSED_RESULT;
bool CancelBuildingBlob(const std::string& uuid) WARN_UNUSED_RESULT;
bool FinishBuildingBlob(const std::string& uuid,
const std::string& type) WARN_UNUSED_RESULT;
@@ -66,11 +64,11 @@ class CONTENT_EXPORT BlobStorageHost {
// The set of public blob urls coined by this consumer.
std::set<GURL> public_blob_urls_;
- base::WeakPtr<BlobStorageContext> context_;
+ base::WeakPtr<storage::BlobStorageContext> context_;
DISALLOW_COPY_AND_ASSIGN(BlobStorageHost);
};
} // namespace content
-#endif // CONTENT_BROWSER_FILEAPI_STORAGE_HOST_H_
+#endif // CONTENT_BROWSER_FILEAPI_BLOB_STORAGE_HOST_H_
diff --git a/chromium/content/browser/fileapi/blob_url_request_job_unittest.cc b/chromium/content/browser/fileapi/blob_url_request_job_unittest.cc
index 79824772be6..ed90f1d6048 100644
--- a/chromium/content/browser/fileapi/blob_url_request_job_unittest.cc
+++ b/chromium/content/browser/fileapi/blob_url_request_job_unittest.cc
@@ -22,14 +22,18 @@
#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_data_builder.h"
+#include "storage/browser/blob/blob_data_handle.h"
+#include "storage/browser/blob/blob_data_snapshot.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_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"
-using storage::BlobData;
+using storage::BlobDataSnapshot;
+using storage::BlobDataBuilder;
using storage::BlobURLRequestJob;
namespace content {
@@ -64,9 +68,8 @@ class BlobURLRequestJobTest : public testing::Test {
net::URLRequestJob* MaybeCreateJob(
net::URLRequest* request,
net::NetworkDelegate* network_delegate) const override {
- return new BlobURLRequestJob(request,
- network_delegate,
- test_->blob_data_.get(),
+ return new BlobURLRequestJob(request, network_delegate,
+ test_->GetSnapshotFromBuilder(),
test_->file_system_context_.get(),
base::MessageLoopProxy::current().get());
}
@@ -76,8 +79,7 @@ class BlobURLRequestJobTest : public testing::Test {
};
BlobURLRequestJobTest()
- : blob_data_(new BlobData()),
- expected_status_code_(0) {}
+ : blob_data_(new BlobDataBuilder("uuid")), expected_status_code_(0) {}
void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
@@ -103,7 +105,12 @@ class BlobURLRequestJobTest : public testing::Test {
url_request_context_.set_job_factory(&url_request_job_factory_);
}
- void TearDown() override {}
+ void TearDown() override {
+ blob_handle_.reset();
+ // Clean up for ASAN
+ base::RunLoop run_loop;
+ run_loop.RunUntilIdle();
+ }
void SetUpFileSystem() {
// Prepare file system.
@@ -183,7 +190,7 @@ class BlobURLRequestJobTest : public testing::Test {
void TestRequest(const std::string& method,
const net::HttpRequestHeaders& extra_headers) {
request_ = url_request_context_.CreateRequest(
- GURL("blob:blah"), net::DEFAULT_PRIORITY, &url_request_delegate_, NULL);
+ GURL("blob:blah"), net::DEFAULT_PRIORITY, &url_request_delegate_);
request_->set_method(method);
if (!extra_headers.IsEmpty())
request_->SetExtraRequestHeaders(extra_headers);
@@ -215,14 +222,21 @@ class BlobURLRequestJobTest : public testing::Test {
*expected_result += std::string(kTestFileSystemFileData2 + 6, 7);
}
+ scoped_ptr<BlobDataSnapshot> GetSnapshotFromBuilder() {
+ if (!blob_handle_) {
+ blob_handle_ = blob_context_.AddFinishedBlob(blob_data_.get()).Pass();
+ }
+ return blob_handle_->CreateSnapshot().Pass();
+ }
+
// This only works if all the Blob items have a definite pre-computed length.
// Otherwise, this will fail a CHECK.
- int64 GetTotalBlobLength() const {
+ int64 GetTotalBlobLength() {
int64 total = 0;
- const std::vector<BlobData::Item>& items = blob_data_->items();
- for (std::vector<BlobData::Item>::const_iterator it = items.begin();
- it != items.end(); ++it) {
- int64 length = base::checked_cast<int64>(it->length());
+ scoped_ptr<BlobDataSnapshot> data = GetSnapshotFromBuilder();
+ const auto& items = data->items();
+ for (const auto& item : items) {
+ int64 length = base::checked_cast<int64>(item->length());
CHECK(length <= kint64max - total);
total += length;
}
@@ -243,7 +257,11 @@ class BlobURLRequestJobTest : public testing::Test {
base::MessageLoopForIO message_loop_;
scoped_refptr<storage::FileSystemContext> file_system_context_;
- scoped_refptr<BlobData> blob_data_;
+
+ storage::BlobStorageContext blob_context_;
+ scoped_ptr<storage::BlobDataHandle> blob_handle_;
+ scoped_ptr<BlobDataBuilder> blob_data_;
+ scoped_ptr<BlobDataSnapshot> blob_data_snapshot_;
net::URLRequestJobFactoryImpl url_request_job_factory_;
net::URLRequestContext url_request_context_;
MockURLRequestDelegate url_request_delegate_;
@@ -328,6 +346,13 @@ TEST_F(BlobURLRequestJobTest, TestGetNonExistentFileSystemFileRequest) {
TestErrorRequest(404);
}
+TEST_F(BlobURLRequestJobTest, TestGetInvalidFileSystemFileRequest) {
+ SetUpFileSystem();
+ GURL invalid_file;
+ blob_data_->AppendFileSystemFile(invalid_file, 0, kuint64max, base::Time());
+ TestErrorRequest(500);
+}
+
TEST_F(BlobURLRequestJobTest, TestGetChangedFileSystemFileRequest) {
SetUpFileSystem();
base::Time old_time =
diff --git a/chromium/content/browser/fileapi/browser_file_system_helper.cc b/chromium/content/browser/fileapi/browser_file_system_helper.cc
index b3221612116..4ab06e61754 100644
--- a/chromium/content/browser/fileapi/browser_file_system_helper.cc
+++ b/chromium/content/browser/fileapi/browser_file_system_helper.cc
@@ -39,7 +39,7 @@ FileSystemOptions CreateBrowserFileSystemOptions(bool is_incognito) {
std::vector<std::string> additional_allowed_schemes;
GetContentClient()->browser()->GetAdditionalAllowedSchemesForFileSystem(
&additional_allowed_schemes);
- if (CommandLine::ForCurrentProcess()->HasSwitch(
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kAllowFileAccessFromFiles)) {
additional_allowed_schemes.push_back(url::kFileScheme);
}
diff --git a/chromium/content/browser/fileapi/chrome_blob_storage_context.cc b/chromium/content/browser/fileapi/chrome_blob_storage_context.cc
index f085242f689..5e2c4c83d1d 100644
--- a/chromium/content/browser/fileapi/chrome_blob_storage_context.cc
+++ b/chromium/content/browser/fileapi/chrome_blob_storage_context.cc
@@ -9,6 +9,7 @@
#include "content/public/browser/blob_handle.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
+#include "storage/browser/blob/blob_data_builder.h"
#include "storage/browser/blob/blob_data_handle.h"
#include "storage/browser/blob/blob_storage_context.h"
@@ -24,8 +25,7 @@ const char kBlobStorageContextKeyName[] = "content_blob_storage_context";
class BlobHandleImpl : public BlobHandle {
public:
explicit BlobHandleImpl(scoped_ptr<storage::BlobDataHandle> handle)
- : handle_(handle.Pass()) {
- }
+ : handle_(handle.Pass()) {}
~BlobHandleImpl() override {}
@@ -60,20 +60,41 @@ ChromeBlobStorageContext* ChromeBlobStorageContext::GetFor(
}
void ChromeBlobStorageContext::InitializeOnIOThread() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
context_.reset(new BlobStorageContext());
}
scoped_ptr<BlobHandle> ChromeBlobStorageContext::CreateMemoryBackedBlob(
const char* data, size_t length) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ std::string uuid(base::GenerateGUID());
+ storage::BlobDataBuilder blob_data_builder(uuid);
+ blob_data_builder.AppendData(data, length);
+
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle =
+ context_->AddFinishedBlob(&blob_data_builder);
+ if (!blob_data_handle)
+ return scoped_ptr<BlobHandle>();
+
+ scoped_ptr<BlobHandle> blob_handle(
+ new BlobHandleImpl(blob_data_handle.Pass()));
+ return blob_handle.Pass();
+}
+
+scoped_ptr<BlobHandle> ChromeBlobStorageContext::CreateFileBackedBlob(
+ const base::FilePath& path,
+ int64_t offset,
+ int64_t size,
+ const base::Time& expected_modification_time) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
std::string uuid(base::GenerateGUID());
- scoped_refptr<storage::BlobData> blob_data = new storage::BlobData(uuid);
- blob_data->AppendData(data, length);
+ storage::BlobDataBuilder blob_data_builder(uuid);
+ blob_data_builder.AppendFile(path, offset, size, expected_modification_time);
scoped_ptr<storage::BlobDataHandle> blob_data_handle =
- context_->AddFinishedBlob(blob_data.get());
+ context_->AddFinishedBlob(&blob_data_builder);
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 8d8a5f226b4..0c565459a2c 100644
--- a/chromium/content/browser/fileapi/chrome_blob_storage_context.h
+++ b/chromium/content/browser/fileapi/chrome_blob_storage_context.h
@@ -10,6 +10,11 @@
#include "base/sequenced_task_runner_helpers.h"
#include "content/common/content_export.h"
+namespace base {
+class FilePath;
+class Time;
+}
+
namespace storage {
class BlobStorageContext;
}
@@ -43,6 +48,13 @@ class CONTENT_EXPORT ChromeBlobStorageContext
scoped_ptr<BlobHandle> CreateMemoryBackedBlob(const char* data,
size_t length);
+ // Returns a NULL scoped_ptr on failure.
+ scoped_ptr<BlobHandle> CreateFileBackedBlob(
+ const base::FilePath& path,
+ int64_t offset,
+ int64_t size,
+ const base::Time& expected_modification_time);
+
protected:
virtual ~ChromeBlobStorageContext();
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 ea2ba898940..f9b8d1506f4 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,13 +11,13 @@
#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/blob/shareable_file_reference.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"
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 a50d4a054a6..451353d1cd9 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
@@ -18,15 +18,16 @@
#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_reader.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_mount_option.h"
#include "storage/common/fileapi/file_system_util.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -740,7 +741,7 @@ TEST(LocalFileSystemCopyOrMoveOperationTest, StreamCopyHelper) {
std::vector<int64> progress;
CopyOrMoveOperationDelegate::StreamCopyHelper helper(
reader.Pass(), writer.Pass(),
- false, // don't need flush
+ storage::FlushPolicy::NO_FLUSH_ON_COMPLETION,
10, // buffer size
base::Bind(&RecordFileProgressCallback, base::Unretained(&progress)),
base::TimeDelta()); // For testing, we need all the progress.
@@ -796,7 +797,7 @@ TEST(LocalFileSystemCopyOrMoveOperationTest, StreamCopyHelperWithFlush) {
std::vector<int64> progress;
CopyOrMoveOperationDelegate::StreamCopyHelper helper(
reader.Pass(), writer.Pass(),
- true, // need flush
+ storage::FlushPolicy::NO_FLUSH_ON_COMPLETION,
10, // buffer size
base::Bind(&RecordFileProgressCallback, base::Unretained(&progress)),
base::TimeDelta()); // For testing, we need all the progress.
@@ -847,7 +848,7 @@ TEST(LocalFileSystemCopyOrMoveOperationTest, StreamCopyHelper_Cancel) {
std::vector<int64> progress;
CopyOrMoveOperationDelegate::StreamCopyHelper helper(
reader.Pass(), writer.Pass(),
- false, // need_flush
+ storage::FlushPolicy::NO_FLUSH_ON_COMPLETION,
10, // buffer size
base::Bind(&RecordFileProgressCallback, base::Unretained(&progress)),
base::TimeDelta()); // For testing, we need all the progress.
diff --git a/chromium/content/browser/fileapi/external_mount_points_unittest.cc b/chromium/content/browser/fileapi/external_mount_points_unittest.cc
index 447eb7348a7..02103da2a94 100644
--- a/chromium/content/browser/fileapi/external_mount_points_unittest.cc
+++ b/chromium/content/browser/fileapi/external_mount_points_unittest.cc
@@ -8,6 +8,7 @@
#include "base/files/file_path.h"
#include "storage/browser/fileapi/file_system_url.h"
+#include "storage/common/fileapi/file_system_mount_option.h"
#include "testing/gtest/include/gtest/gtest.h"
#define FPL FILE_PATH_LITERAL
@@ -472,14 +473,13 @@ TEST(ExternalMountPointsTest, MountOption) {
storage::ExternalMountPoints::CreateRefCounted());
mount_points->RegisterFileSystem(
- "nosync",
- storage::kFileSystemTypeNativeLocal,
- storage::FileSystemMountOption(storage::COPY_SYNC_OPTION_NO_SYNC),
+ "nosync", storage::kFileSystemTypeNativeLocal,
+ storage::FileSystemMountOption(
+ storage::FlushPolicy::NO_FLUSH_ON_COMPLETION),
base::FilePath(DRIVE FPL("/nosync")));
mount_points->RegisterFileSystem(
- "sync",
- storage::kFileSystemTypeNativeLocal,
- storage::FileSystemMountOption(storage::COPY_SYNC_OPTION_SYNC),
+ "sync", storage::kFileSystemTypeNativeLocal,
+ storage::FileSystemMountOption(storage::FlushPolicy::FLUSH_ON_COMPLETION),
base::FilePath(DRIVE FPL("/sync")));
std::string name;
@@ -490,11 +490,12 @@ TEST(ExternalMountPointsTest, MountOption) {
EXPECT_TRUE(mount_points->CrackVirtualPath(
base::FilePath(FPL("nosync/file")), &name, &type, &cracked_id, &path,
&option));
- EXPECT_EQ(storage::COPY_SYNC_OPTION_NO_SYNC, option.copy_sync_option());
+ EXPECT_EQ(storage::FlushPolicy::NO_FLUSH_ON_COMPLETION,
+ option.flush_policy());
EXPECT_TRUE(mount_points->CrackVirtualPath(
base::FilePath(FPL("sync/file")), &name, &type, &cracked_id, &path,
&option));
- EXPECT_EQ(storage::COPY_SYNC_OPTION_SYNC, option.copy_sync_option());
+ EXPECT_EQ(storage::FlushPolicy::FLUSH_ON_COMPLETION, option.flush_policy());
}
} // namespace content
diff --git a/chromium/content/browser/fileapi/file_system_browsertest.cc b/chromium/content/browser/fileapi/file_system_browsertest.cc
index 804f04e9fd9..79e9f3cb05f 100644
--- a/chromium/content/browser/fileapi/file_system_browsertest.cc
+++ b/chromium/content/browser/fileapi/file_system_browsertest.cc
@@ -69,7 +69,7 @@ class FileSystemBrowserTestWithLowQuota : public FileSystemBrowserTest {
qm));
return;
}
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
qm->SetTemporaryGlobalOverrideQuota(bytes, storage::QuotaCallback());
// Don't return until the quota has been set.
scoped_refptr<base::ThreadTestHelper> helper(new base::ThreadTestHelper(
diff --git a/chromium/content/browser/fileapi/file_system_context_unittest.cc b/chromium/content/browser/fileapi/file_system_context_unittest.cc
index 454a8f385e6..c071c4b4d53 100644
--- a/chromium/content/browser/fileapi/file_system_context_unittest.cc
+++ b/chromium/content/browser/fileapi/file_system_context_unittest.cc
@@ -366,6 +366,27 @@ TEST_F(FileSystemContextTest, CanServeURLRequest) {
IsolatedContext::GetInstance()->RevokeFileSystem(isolated_fs_id);
}
+// Ensures that a backend exists for each common isolated file system type.
+// See http://crbug.com/447027
+TEST_F(FileSystemContextTest, IsolatedFileSystemsTypesHandled) {
+ // This does not provide any "additional" file system handlers. In particular,
+ // on Chrome OS it does not provide chromeos::FileSystemBackend.
+ scoped_refptr<FileSystemContext> file_system_context(
+ CreateFileSystemContextForTest(nullptr));
+
+ // Isolated file system types are handled.
+ EXPECT_TRUE(file_system_context->GetFileSystemBackend(
+ storage::kFileSystemTypeIsolated));
+ EXPECT_TRUE(file_system_context->GetFileSystemBackend(
+ storage::kFileSystemTypeDragged));
+ EXPECT_TRUE(file_system_context->GetFileSystemBackend(
+ storage::kFileSystemTypeForTransientFile));
+ EXPECT_TRUE(file_system_context->GetFileSystemBackend(
+ storage::kFileSystemTypeNativeLocal));
+ EXPECT_TRUE(file_system_context->GetFileSystemBackend(
+ storage::kFileSystemTypeNativeForPlatformApp));
+}
+
} // namespace
} // namespace content
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 e496954c229..ff913ecaa18 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
@@ -177,7 +177,7 @@ class FileSystemDirURLRequestJobTest : public testing::Test {
empty_context_.set_job_factory(job_factory_.get());
request_ = empty_context_.CreateRequest(
- url, net::DEFAULT_PRIORITY, delegate_.get(), NULL);
+ url, net::DEFAULT_PRIORITY, delegate_.get());
request_->Start();
ASSERT_TRUE(request_->is_pending()); // verify that we're starting async
if (run_to_completion)
@@ -318,7 +318,7 @@ TEST_F(FileSystemDirURLRequestJobTest, DirectoryListing) {
std::istringstream in(delegate_->data_received());
std::string line;
- EXPECT_TRUE(!!std::getline(in, line));
+ EXPECT_TRUE(std::getline(in, line));
#if defined(OS_WIN)
EXPECT_EQ("<script>start(\"foo\\\\bar\");</script>", line);
@@ -326,10 +326,10 @@ TEST_F(FileSystemDirURLRequestJobTest, DirectoryListing) {
EXPECT_EQ("<script>start(\"/foo/bar\");</script>", line);
#endif
- EXPECT_TRUE(!!std::getline(in, line));
+ EXPECT_TRUE(std::getline(in, line));
VerifyListingEntry(line, "hoge", "hoge", false, 10);
- EXPECT_TRUE(!!std::getline(in, line));
+ EXPECT_TRUE(std::getline(in, line));
VerifyListingEntry(line, "baz", "baz", true, 0);
EXPECT_FALSE(!!std::getline(in, line));
}
@@ -378,7 +378,7 @@ TEST_F(FileSystemDirURLRequestJobTest, Incognito) {
std::istringstream in(delegate_->data_received());
std::string line;
- EXPECT_TRUE(!!std::getline(in, line));
+ EXPECT_TRUE(std::getline(in, line));
EXPECT_FALSE(!!std::getline(in, line));
TestRequestWithContext(CreateFileSystemURL("foo"),
@@ -405,7 +405,7 @@ TEST_F(FileSystemDirURLRequestJobTest, AutoMountDirectoryListing) {
std::istringstream in(delegate_->data_received());
std::string line;
- EXPECT_TRUE(!!std::getline(in, line)); // |line| contains the temp dir path.
+ EXPECT_TRUE(std::getline(in, line)); // |line| contains the temp dir path.
// Result order is not guaranteed, so sort the results.
std::vector<std::string> listing_entries;
@@ -450,5 +450,5 @@ TEST_F(FileSystemDirURLRequestJobTest, AutoMountNoHandler) {
kValidExternalMountPoint));
}
-} // namespace (anonymous)
+} // namespace
} // namespace content
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 23a8c2d679b..6f84204a4ac 100644
--- a/chromium/content/browser/fileapi/file_system_operation_impl_unittest.cc
+++ b/chromium/content/browser/fileapi/file_system_operation_impl_unittest.cc
@@ -18,6 +18,7 @@
#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/blob/shareable_file_reference.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"
@@ -25,7 +26,6 @@
#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"
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 9d3c181fdce..ca324ae4653 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
@@ -25,7 +25,6 @@
#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"
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 12ba010a318..075ba2130ff 100644
--- a/chromium/content/browser/fileapi/file_system_operation_runner_unittest.cc
+++ b/chromium/content/browser/fileapi/file_system_operation_runner_unittest.cc
@@ -5,8 +5,17 @@
#include "base/basictypes.h"
#include "base/files/file_path.h"
#include "base/files/scoped_temp_dir.h"
+#include "base/memory/scoped_vector.h"
#include "base/run_loop.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/thread_restrictions.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/test/mock_special_storage_policy.h"
+#include "content/public/test/test_browser_thread_bundle.h"
#include "content/public/test/test_file_system_context.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/file_system_context.h"
#include "storage/browser/fileapi/file_system_operation_runner.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -18,6 +27,8 @@ using storage::FileSystemURL;
namespace content {
+namespace {
+
void GetStatus(bool* done,
base::File::Error *status_out,
base::File::Error status) {
@@ -37,6 +48,10 @@ void GetCancelStatus(bool* operation_done,
*status_out = status;
}
+void DidOpenFile(base::File file, const base::Closure& on_close_callback) {}
+
+} // namespace
+
class FileSystemOperationRunnerTest : public testing::Test {
protected:
FileSystemOperationRunnerTest() {}
@@ -45,12 +60,11 @@ class FileSystemOperationRunnerTest : public testing::Test {
void SetUp() override {
ASSERT_TRUE(base_.CreateUniqueTempDir());
base::FilePath base_dir = base_.path();
- file_system_context_ =
- CreateFileSystemContextForTesting(NULL, base_dir);
+ file_system_context_ = CreateFileSystemContextForTesting(nullptr, base_dir);
}
void TearDown() override {
- file_system_context_ = NULL;
+ file_system_context_ = nullptr;
base::RunLoop().RunUntilIdle();
}
@@ -164,4 +178,73 @@ TEST_F(FileSystemOperationRunnerTest, CancelWithInvalidId) {
ASSERT_EQ(base::File::FILE_ERROR_INVALID_OPERATION, cancel_status);
}
+class MultiThreadFileSystemOperationRunnerTest : public testing::Test {
+ public:
+ MultiThreadFileSystemOperationRunnerTest()
+ : thread_bundle_(
+ content::TestBrowserThreadBundle::REAL_FILE_THREAD |
+ content::TestBrowserThreadBundle::IO_MAINLOOP) {}
+
+ void SetUp() override {
+ ASSERT_TRUE(base_.CreateUniqueTempDir());
+
+ base::FilePath base_dir = base_.path();
+ ScopedVector<storage::FileSystemBackend> additional_providers;
+ file_system_context_ = new FileSystemContext(
+ base::ThreadTaskRunnerHandle::Get().get(),
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE).get(),
+ storage::ExternalMountPoints::CreateRefCounted().get(),
+ make_scoped_refptr(new MockSpecialStoragePolicy()).get(),
+ nullptr,
+ additional_providers.Pass(),
+ std::vector<storage::URLRequestAutoMountHandler>(),
+ base_dir,
+ CreateAllowFileAccessOptions());
+
+ // Disallow IO on the main loop.
+ base::ThreadRestrictions::SetIOAllowed(false);
+ }
+
+ void TearDown() override {
+ base::ThreadRestrictions::SetIOAllowed(true);
+ file_system_context_ = nullptr;
+ }
+
+ FileSystemURL URL(const std::string& path) {
+ return file_system_context_->CreateCrackedFileSystemURL(
+ GURL("http://example.com"),
+ storage::kFileSystemTypeTemporary,
+ base::FilePath::FromUTF8Unsafe(path));
+ }
+
+ FileSystemOperationRunner* operation_runner() {
+ return file_system_context_->operation_runner();
+ }
+
+ private:
+ content::TestBrowserThreadBundle thread_bundle_;
+ base::ScopedTempDir base_;
+ scoped_refptr<FileSystemContext> file_system_context_;
+
+ DISALLOW_COPY_AND_ASSIGN(MultiThreadFileSystemOperationRunnerTest);
+};
+
+TEST_F(MultiThreadFileSystemOperationRunnerTest, OpenAndShutdown) {
+ // Call OpenFile and immediately shutdown the runner.
+ operation_runner()->OpenFile(
+ URL("foo"),
+ base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE,
+ base::Bind(&DidOpenFile));
+ operation_runner()->Shutdown();
+
+ // Wait until the task posted on FILE thread is done.
+ base::RunLoop run_loop;
+ BrowserThread::PostTaskAndReply(
+ BrowserThread::FILE, FROM_HERE,
+ base::Bind(&base::DoNothing),
+ run_loop.QuitClosure());
+ run_loop.Run();
+ // This should finish without thread assertion failure on debug build.
+}
+
} // namespace content
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 747c6626d6e..5ab33e1b923 100644
--- a/chromium/content/browser/fileapi/file_system_quota_client_unittest.cc
+++ b/chromium/content/browser/fileapi/file_system_quota_client_unittest.cc
@@ -40,9 +40,9 @@ const storage::StorageType kPersistent = storage::kStorageTypePersistent;
class FileSystemQuotaClientTest : public testing::Test {
public:
FileSystemQuotaClientTest()
- : weak_factory_(this),
- additional_callback_count_(0),
- deletion_status_(storage::kQuotaStatusUnknown) {}
+ : additional_callback_count_(0),
+ deletion_status_(storage::kQuotaStatusUnknown),
+ weak_factory_(this) {}
void SetUp() override {
ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
@@ -230,11 +230,11 @@ class FileSystemQuotaClientTest : public testing::Test {
base::ScopedTempDir data_dir_;
base::MessageLoop message_loop_;
scoped_refptr<storage::FileSystemContext> file_system_context_;
- base::WeakPtrFactory<FileSystemQuotaClientTest> weak_factory_;
int64 usage_;
int additional_callback_count_;
std::set<GURL> origins_;
storage::QuotaStatusCode deletion_status_;
+ base::WeakPtrFactory<FileSystemQuotaClientTest> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(FileSystemQuotaClientTest);
};
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 4dcba3baac6..5e932f2b370 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
@@ -193,7 +193,7 @@ class FileSystemURLRequestJobTest : public testing::Test {
empty_context_.set_job_factory(job_factory_.get());
request_ = empty_context_.CreateRequest(
- url, net::DEFAULT_PRIORITY, delegate_.get(), NULL);
+ url, net::DEFAULT_PRIORITY, delegate_.get());
if (headers)
request_->SetExtraRequestHeaders(*headers);
@@ -251,7 +251,6 @@ class FileSystemURLRequestJobTest : public testing::Test {
base::ScopedTempDir temp_dir_;
scoped_refptr<storage::FileSystemContext> file_system_context_;
- base::WeakPtrFactory<FileSystemURLRequestJobTest> weak_factory_;
net::URLRequestContext empty_context_;
scoped_ptr<FileSystemURLRequestJobFactory> job_factory_;
@@ -259,6 +258,8 @@ class FileSystemURLRequestJobTest : public testing::Test {
// NOTE: order matters, request must die before delegate
scoped_ptr<net::TestDelegate> delegate_;
scoped_ptr<net::URLRequest> request_;
+
+ base::WeakPtrFactory<FileSystemURLRequestJobTest> weak_factory_;
};
namespace {
diff --git a/chromium/content/browser/fileapi/file_writer_delegate_unittest.cc b/chromium/content/browser/fileapi/file_writer_delegate_unittest.cc
index d907843695a..1aacaccd2bb 100644
--- a/chromium/content/browser/fileapi/file_writer_delegate_unittest.cc
+++ b/chromium/content/browser/fileapi/file_writer_delegate_unittest.cc
@@ -24,6 +24,7 @@
#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 "storage/common/fileapi/file_system_mount_option.h"
#include "testing/platform_test.h"
#include "url/gurl.h"
@@ -124,7 +125,7 @@ class FileWriterDelegateTest : public PlatformTest {
*file_system_context_->GetUpdateObservers(kFileSystemType));
writer->set_default_quota(allowed_growth);
return new FileWriterDelegate(scoped_ptr<storage::FileStreamWriter>(writer),
- FileWriterDelegate::FLUSH_ON_COMPLETION);
+ storage::FlushPolicy::FLUSH_ON_COMPLETION);
}
FileWriterDelegate::DelegateWriteCallback GetWriteCallback(Result* result) {
@@ -140,7 +141,7 @@ class FileWriterDelegateTest : public PlatformTest {
file_writer_delegate_.reset(
CreateWriterDelegate(test_file_path, offset, allowed_growth));
request_ = empty_context_.CreateRequest(
- blob_url, net::DEFAULT_PRIORITY, file_writer_delegate_.get(), NULL);
+ blob_url, net::DEFAULT_PRIORITY, file_writer_delegate_.get());
}
// This should be alive until the very end of this instance.
@@ -368,7 +369,7 @@ TEST_F(FileWriterDelegateTest, WriteSuccessWithoutQuotaLimitConcurrent) {
// Credate another FileWriterDelegate for concurrent write.
file_writer_delegate2.reset(CreateWriterDelegate("test2", 0, kint64max));
request2 = empty_context_.CreateRequest(
- kBlobURL2, net::DEFAULT_PRIORITY, file_writer_delegate2.get(), NULL);
+ kBlobURL2, net::DEFAULT_PRIORITY, file_writer_delegate2.get());
Result result, result2;
ASSERT_EQ(0, usage());
diff --git a/chromium/content/browser/fileapi/fileapi_message_filter.cc b/chromium/content/browser/fileapi/fileapi_message_filter.cc
index 3fe4199272a..ca67e188207 100644
--- a/chromium/content/browser/fileapi/fileapi_message_filter.cc
+++ b/chromium/content/browser/fileapi/fileapi_message_filter.cc
@@ -27,13 +27,14 @@
#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_data_builder.h"
#include "storage/browser/blob/blob_storage_context.h"
+#include "storage/browser/blob/shareable_file_reference.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/data_element.h"
#include "storage/common/fileapi/directory_entry.h"
#include "storage/common/fileapi/file_system_info.h"
#include "storage/common/fileapi/file_system_types.h"
@@ -44,7 +45,7 @@ using storage::FileSystemFileUtil;
using storage::FileSystemBackend;
using storage::FileSystemOperation;
using storage::FileSystemURL;
-using storage::BlobData;
+using storage::BlobDataBuilder;
using storage::BlobStorageContext;
namespace content {
@@ -105,7 +106,7 @@ FileAPIMessageFilter::FileAPIMessageFilter(
}
void FileAPIMessageFilter::OnChannelConnected(int32 peer_pid) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (request_context_getter_.get()) {
DCHECK(!request_context_);
@@ -121,7 +122,7 @@ void FileAPIMessageFilter::OnChannelConnected(int32 peer_pid) {
}
void FileAPIMessageFilter::OnChannelClosing() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
// Unregister all the blob and stream URLs that are previously registered in
// this process.
@@ -185,6 +186,7 @@ bool FileAPIMessageFilter::OnMessageReceived(const IPC::Message& message) {
OnAppendBlobDataItemToStream)
IPC_MESSAGE_HANDLER(StreamHostMsg_SyncAppendSharedMemory,
OnAppendSharedMemoryToStream)
+ IPC_MESSAGE_HANDLER(StreamHostMsg_Flush, OnFlushStream)
IPC_MESSAGE_HANDLER(StreamHostMsg_FinishBuilding, OnFinishBuildingStream)
IPC_MESSAGE_HANDLER(StreamHostMsg_AbortBuilding, OnAbortBuildingStream)
IPC_MESSAGE_HANDLER(StreamHostMsg_Clone, OnCloneStream)
@@ -204,7 +206,7 @@ void FileAPIMessageFilter::BadMessageReceived() {
void FileAPIMessageFilter::OnOpenFileSystem(int request_id,
const GURL& origin_url,
storage::FileSystemType type) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (type == storage::kFileSystemTypeTemporary) {
RecordAction(base::UserMetricsAction("OpenFileSystemTemporary"));
} else if (type == storage::kFileSystemTypePersistent) {
@@ -219,7 +221,7 @@ void FileAPIMessageFilter::OnOpenFileSystem(int request_id,
void FileAPIMessageFilter::OnResolveURL(
int request_id,
const GURL& filesystem_url) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
FileSystemURL url(context_->CrackURL(filesystem_url));
if (!ValidateFileSystemURL(request_id, url))
return;
@@ -236,14 +238,14 @@ void FileAPIMessageFilter::OnResolveURL(
void FileAPIMessageFilter::OnDeleteFileSystem(int request_id,
const GURL& origin_url,
storage::FileSystemType type) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
context_->DeleteFileSystem(origin_url, type, base::Bind(
&FileAPIMessageFilter::DidDeleteFileSystem, this, request_id));
}
void FileAPIMessageFilter::OnMove(
int request_id, const GURL& src_path, const GURL& dest_path) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
FileSystemURL src_url(context_->CrackURL(src_path));
FileSystemURL dest_url(context_->CrackURL(dest_path));
if (!ValidateFileSystemURL(request_id, src_url) ||
@@ -267,7 +269,7 @@ void FileAPIMessageFilter::OnMove(
void FileAPIMessageFilter::OnCopy(
int request_id, const GURL& src_path, const GURL& dest_path) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
FileSystemURL src_url(context_->CrackURL(src_path));
FileSystemURL dest_url(context_->CrackURL(dest_path));
if (!ValidateFileSystemURL(request_id, src_url) ||
@@ -291,7 +293,7 @@ void FileAPIMessageFilter::OnCopy(
void FileAPIMessageFilter::OnRemove(
int request_id, const GURL& path, bool recursive) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
FileSystemURL url(context_->CrackURL(path));
if (!ValidateFileSystemURL(request_id, url))
return;
@@ -308,7 +310,7 @@ void FileAPIMessageFilter::OnRemove(
void FileAPIMessageFilter::OnReadMetadata(
int request_id, const GURL& path) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
FileSystemURL url(context_->CrackURL(path));
if (!ValidateFileSystemURL(request_id, url))
return;
@@ -325,7 +327,7 @@ void FileAPIMessageFilter::OnReadMetadata(
void FileAPIMessageFilter::OnCreate(
int request_id, const GURL& path, bool exclusive,
bool is_directory, bool recursive) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
FileSystemURL url(context_->CrackURL(path));
if (!ValidateFileSystemURL(request_id, url))
return;
@@ -348,7 +350,7 @@ void FileAPIMessageFilter::OnCreate(
void FileAPIMessageFilter::OnExists(
int request_id, const GURL& path, bool is_directory) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
FileSystemURL url(context_->CrackURL(path));
if (!ValidateFileSystemURL(request_id, url))
return;
@@ -371,7 +373,7 @@ void FileAPIMessageFilter::OnExists(
void FileAPIMessageFilter::OnReadDirectory(
int request_id, const GURL& path) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
FileSystemURL url(context_->CrackURL(path));
if (!ValidateFileSystemURL(request_id, url))
return;
@@ -391,7 +393,7 @@ void FileAPIMessageFilter::OnWrite(
const GURL& path,
const std::string& blob_uuid,
int64 offset) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!request_context_) {
// We can't write w/o a request context, trying to do so will crash.
NOTREACHED();
@@ -438,7 +440,7 @@ void FileAPIMessageFilter::OnTouchFile(
const GURL& path,
const base::Time& last_access_time,
const base::Time& last_modified_time) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
FileSystemURL url(context_->CrackURL(path));
if (!ValidateFileSystemURL(request_id, url))
return;
@@ -456,7 +458,7 @@ void FileAPIMessageFilter::OnTouchFile(
void FileAPIMessageFilter::OnCancel(
int request_id,
int request_id_to_cancel) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
OperationsMap::iterator found = operations_.find(request_id_to_cancel);
if (found != operations_.end()) {
@@ -479,7 +481,7 @@ void FileAPIMessageFilter::OnSyncGetPlatformPath(
void FileAPIMessageFilter::OnCreateSnapshotFile(
int request_id, const GURL& path) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
FileSystemURL url(context_->CrackURL(path));
// Make sure if this file can be read by the renderer as this is
@@ -508,19 +510,20 @@ void FileAPIMessageFilter::OnCreateSnapshotFile(
}
void FileAPIMessageFilter::OnDidReceiveSnapshotFile(int request_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
in_transit_snapshot_files_.erase(request_id);
}
void FileAPIMessageFilter::OnStartBuildingBlob(const std::string& uuid) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
ignore_result(blob_storage_host_->StartBuildingBlob(uuid));
}
void FileAPIMessageFilter::OnAppendBlobDataItemToBlob(
- const std::string& uuid, const BlobData::Item& item) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- if (item.type() == BlobData::Item::TYPE_FILE_FILESYSTEM) {
+ const std::string& uuid,
+ const storage::DataElement& item) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (item.type() == storage::DataElement::TYPE_FILE_FILESYSTEM) {
FileSystemURL filesystem_url(context_->CrackURL(item.filesystem_url()));
if (!FileSystemURLIsValid(context_, filesystem_url) ||
!security_policy_->CanReadFileSystemFile(process_id_, filesystem_url)) {
@@ -528,7 +531,7 @@ void FileAPIMessageFilter::OnAppendBlobDataItemToBlob(
return;
}
}
- if (item.type() == BlobData::Item::TYPE_FILE &&
+ if (item.type() == storage::DataElement::TYPE_FILE &&
!security_policy_->CanReadFile(process_id_, item.path())) {
ignore_result(blob_storage_host_->CancelBuildingBlob(uuid));
return;
@@ -559,7 +562,7 @@ void FileAPIMessageFilter::OnAppendSharedMemoryToBlob(
return;
}
- BlobData::Item item;
+ storage::DataElement item;
item.SetToSharedBytes(static_cast<char*>(shared_memory.memory()),
buffer_size);
ignore_result(blob_storage_host_->AppendBlobDataItem(uuid, item));
@@ -567,35 +570,35 @@ void FileAPIMessageFilter::OnAppendSharedMemoryToBlob(
void FileAPIMessageFilter::OnFinishBuildingBlob(
const std::string& uuid, const std::string& content_type) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
ignore_result(blob_storage_host_->FinishBuildingBlob(uuid, content_type));
// TODO(michaeln): check return values once blink has migrated, crbug/174200
}
void FileAPIMessageFilter::OnIncrementBlobRefCount(const std::string& uuid) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
ignore_result(blob_storage_host_->IncrementBlobRefCount(uuid));
}
void FileAPIMessageFilter::OnDecrementBlobRefCount(const std::string& uuid) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
ignore_result(blob_storage_host_->DecrementBlobRefCount(uuid));
}
void FileAPIMessageFilter::OnRegisterPublicBlobURL(
const GURL& public_url, const std::string& uuid) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
ignore_result(blob_storage_host_->RegisterPublicBlobURL(public_url, uuid));
}
void FileAPIMessageFilter::OnRevokePublicBlobURL(const GURL& public_url) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
ignore_result(blob_storage_host_->RevokePublicBlobURL(public_url));
}
void FileAPIMessageFilter::OnStartBuildingStream(
const GURL& url, const std::string& content_type) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
// Only an internal Blob URL is expected here. See the BlobURL of the Blink.
if (!StartsWithASCII(
url.path(), "blobinternal%3A///", true /* case_sensitive */)) {
@@ -612,8 +615,9 @@ void FileAPIMessageFilter::OnStartBuildingStream(
}
void FileAPIMessageFilter::OnAppendBlobDataItemToStream(
- const GURL& url, const BlobData::Item& item) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ const GURL& url,
+ const storage::DataElement& item) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
scoped_refptr<Stream> stream(GetStreamForURL(url));
// Stream instances may be deleted on error. Just abort if there's no Stream
@@ -622,7 +626,7 @@ void FileAPIMessageFilter::OnAppendBlobDataItemToStream(
return;
// Data for stream is delivered as TYPE_BYTES item.
- if (item.type() != BlobData::Item::TYPE_BYTES) {
+ if (item.type() != storage::DataElement::TYPE_BYTES) {
BadMessageReceived();
return;
}
@@ -653,15 +657,22 @@ void FileAPIMessageFilter::OnAppendSharedMemoryToStream(
stream->AddData(static_cast<char*>(shared_memory.memory()), buffer_size);
}
+void FileAPIMessageFilter::OnFlushStream(const GURL& url) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ scoped_refptr<Stream> stream(GetStreamForURL(url));
+ if (stream.get())
+ stream->Flush();
+}
+
void FileAPIMessageFilter::OnFinishBuildingStream(const GURL& url) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
scoped_refptr<Stream> stream(GetStreamForURL(url));
if (stream.get())
stream->Finalize();
}
void FileAPIMessageFilter::OnAbortBuildingStream(const GURL& url) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
scoped_refptr<Stream> stream(GetStreamForURL(url));
if (stream.get())
stream->Abort();
@@ -669,7 +680,7 @@ void FileAPIMessageFilter::OnAbortBuildingStream(const GURL& url) {
void FileAPIMessageFilter::OnCloneStream(
const GURL& url, const GURL& src_url) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(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).get())
@@ -680,7 +691,7 @@ void FileAPIMessageFilter::OnCloneStream(
}
void FileAPIMessageFilter::OnRemoveStream(const GURL& url) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!GetStreamForURL(url).get())
return;
@@ -758,7 +769,7 @@ void FileAPIMessageFilter::DidOpenFileSystem(int request_id,
const GURL& root,
const std::string& filesystem_name,
base::File::Error result) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (result == base::File::FILE_OK) {
DCHECK(root.is_valid());
Send(new FileSystemMsg_DidOpenFileSystem(
@@ -775,7 +786,7 @@ void FileAPIMessageFilter::DidResolveURL(
const storage::FileSystemInfo& info,
const base::FilePath& file_path,
storage::FileSystemContext::ResolvedEntryType type) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (result == base::File::FILE_OK &&
type == storage::FileSystemContext::RESOLVED_ENTRY_NOT_FOUND)
result = base::File::FILE_ERROR_NOT_FOUND;
@@ -811,7 +822,7 @@ void FileAPIMessageFilter::DidCreateSnapshot(
const base::File::Info& info,
const base::FilePath& platform_path,
const scoped_refptr<storage::ShareableFileReference>& /* unused */) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
operations_.erase(request_id);
if (result != base::File::FILE_OK) {
diff --git a/chromium/content/browser/fileapi/fileapi_message_filter.h b/chromium/content/browser/fileapi/fileapi_message_filter.h
index 297213d722d..805778b4b59 100644
--- a/chromium/content/browser/fileapi/fileapi_message_filter.h
+++ b/chromium/content/browser/fileapi/fileapi_message_filter.h
@@ -20,7 +20,6 @@
#include "content/public/browser/browser_message_filter.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"
@@ -49,6 +48,7 @@ class BlobStorageHost;
namespace storage {
class ShareableFileReference;
+class DataElement;
}
namespace content {
@@ -130,7 +130,7 @@ class CONTENT_EXPORT FileAPIMessageFilter : public BrowserMessageFilter {
void OnStartBuildingBlob(const std::string& uuid);
void OnAppendBlobDataItemToBlob(const std::string& uuid,
- const storage::BlobData::Item& item);
+ const storage::DataElement& item);
void OnAppendSharedMemoryToBlob(const std::string& uuid,
base::SharedMemoryHandle handle,
size_t buffer_size);
@@ -151,9 +151,10 @@ 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 storage::BlobData::Item& item);
+ const storage::DataElement& item);
void OnAppendSharedMemoryToStream(
const GURL& url, base::SharedMemoryHandle handle, size_t buffer_size);
+ void OnFlushStream(const GURL& url);
void OnFinishBuildingStream(const GURL& url);
void OnAbortBuildingStream(const GURL& url);
void OnCloneStream(const GURL& url, const GURL& src_url);
diff --git a/chromium/content/browser/fileapi/fileapi_message_filter_unittest.cc b/chromium/content/browser/fileapi/fileapi_message_filter_unittest.cc
index b3a66595420..58f555e10fb 100644
--- a/chromium/content/browser/fileapi/fileapi_message_filter_unittest.cc
+++ b/chromium/content/browser/fileapi/fileapi_message_filter_unittest.cc
@@ -25,7 +25,7 @@
#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 "storage/common/data_element.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
@@ -197,7 +197,7 @@ TEST_F(FileAPIMessageFilterTest, BuildNonEmptyStream) {
StreamHostMsg_StartBuilding start_message(kUrl, kFakeContentType);
EXPECT_TRUE(filter_->OnMessageReceived(start_message));
- storage::BlobData::Item item;
+ storage::DataElement item;
const std::string kFakeData = "foobarbaz";
item.SetToBytes(kFakeData.data(), kFakeData.size());
StreamHostMsg_AppendBlobDataItem append_message(kUrl, item);
@@ -232,11 +232,11 @@ TEST_F(FileAPIMessageFilterTest, BuildStreamWithSharedMemory) {
EXPECT_EQ(NULL, stream_registry->GetStream(kUrl).get());
- // For win, we need to set valid PID to the filter.
+ // For win, we need to set valid process to the filter.
// 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::GetCurrentProcId());
+ filter_->set_peer_process_for_testing(base::Process::Current());
StreamHostMsg_StartBuilding start_message(kUrl, kFakeContentType);
EXPECT_TRUE(filter_->OnMessageReceived(start_message));
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 461aa606c6c..5e17165d6b5 100644
--- a/chromium/content/browser/fileapi/local_file_stream_reader_unittest.cc
+++ b/chromium/content/browser/fileapi/local_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 "storage/browser/blob/local_file_stream_reader.h"
+#include "storage/browser/fileapi/local_file_stream_reader.h"
#include <string>
diff --git a/chromium/content/browser/fileapi/mock_file_change_observer.h b/chromium/content/browser/fileapi/mock_file_change_observer.h
index 3465a7a1f5d..92c24e1bc80 100644
--- a/chromium/content/browser/fileapi/mock_file_change_observer.h
+++ b/chromium/content/browser/fileapi/mock_file_change_observer.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef WEBKIT_BROWSER_FILEAPI_MOCK_FILE_CHANGE_OBSERVER_H_
-#define WEBKIT_BROWSER_FILEAPI_MOCK_FILE_CHANGE_OBSERVER_H_
+#ifndef CONTENT_BROWSER_FILEAPI_MOCK_FILE_CHANGE_OBSERVER_H_
+#define CONTENT_BROWSER_FILEAPI_MOCK_FILE_CHANGE_OBSERVER_H_
#include "base/basictypes.h"
#include "base/compiler_specific.h"
@@ -100,4 +100,4 @@ class MockFileChangeObserver : public FileChangeObserver {
} // namespace storage
-#endif // WEBKIT_BROWSER_FILEAPI_MOCK_FILE_CHANGE_OBSERVER_H_
+#endif // CONTENT_BROWSER_FILEAPI_MOCK_FILE_CHANGE_OBSERVER_H_
diff --git a/chromium/content/browser/fileapi/mock_file_update_observer.h b/chromium/content/browser/fileapi/mock_file_update_observer.h
index 78aef9fae25..64bd85e46c6 100644
--- a/chromium/content/browser/fileapi/mock_file_update_observer.h
+++ b/chromium/content/browser/fileapi/mock_file_update_observer.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef WEBKIT_BROWSER_FILEAPI_MOCK_FILE_UPDATE_OBSERVER_H_
-#define WEBKIT_BROWSER_FILEAPI_MOCK_FILE_UPDATE_OBSERVER_H_
+#ifndef CONTENT_BROWSER_FILEAPI_MOCK_FILE_UPDATE_OBSERVER_H_
+#define CONTENT_BROWSER_FILEAPI_MOCK_FILE_UPDATE_OBSERVER_H_
#include <map>
@@ -47,4 +47,4 @@ class MockFileUpdateObserver : public FileUpdateObserver {
} // namespace storage
-#endif // WEBKIT_BROWSER_FILEAPI_MOCK_FILE_UPDATE_OBSERVER_H_
+#endif // CONTENT_BROWSER_FILEAPI_MOCK_FILE_UPDATE_OBSERVER_H_
diff --git a/chromium/content/browser/fileapi/mock_url_request_delegate.cc b/chromium/content/browser/fileapi/mock_url_request_delegate.cc
index 97e09f0df6f..455b4586d18 100644
--- a/chromium/content/browser/fileapi/mock_url_request_delegate.cc
+++ b/chromium/content/browser/fileapi/mock_url_request_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 "mock_url_request_delegate.h"
+#include "content/browser/fileapi/mock_url_request_delegate.h"
#include "base/run_loop.h"
#include "net/base/io_buffer.h"
diff --git a/chromium/content/browser/fileapi/mock_url_request_delegate.h b/chromium/content/browser/fileapi/mock_url_request_delegate.h
index a628f6ea5a4..d52d1bb309b 100644
--- a/chromium/content/browser/fileapi/mock_url_request_delegate.h
+++ b/chromium/content/browser/fileapi/mock_url_request_delegate.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_FILEAPI_MOCK_URL_REQUEST_DELEGATE_H
-#define CONTENT_BROWSER_FILEAPI_MOCK_URL_REQUEST_DELEGATE_H
+#ifndef CONTENT_BROWSER_FILEAPI_MOCK_URL_REQUEST_DELEGATE_H_
+#define CONTENT_BROWSER_FILEAPI_MOCK_URL_REQUEST_DELEGATE_H_
#include "net/url_request/url_request.h"
@@ -34,4 +34,4 @@ class MockURLRequestDelegate : public net::URLRequest::Delegate {
} // namespace content
-#endif // CONTENT_BROWSER_FILEAPI_MOCK_URL_REQUEST_DELEGATE_H
+#endif // CONTENT_BROWSER_FILEAPI_MOCK_URL_REQUEST_DELEGATE_H_
diff --git a/chromium/content/browser/fileapi/obfuscated_file_util_unittest.cc b/chromium/content/browser/fileapi/obfuscated_file_util_unittest.cc
index cef39901405..7abaf7e8958 100644
--- a/chromium/content/browser/fileapi/obfuscated_file_util_unittest.cc
+++ b/chromium/content/browser/fileapi/obfuscated_file_util_unittest.cc
@@ -146,10 +146,10 @@ class ObfuscatedFileUtilTest : public testing::Test {
ObfuscatedFileUtilTest()
: origin_(GURL("http://www.example.com")),
type_(storage::kFileSystemTypeTemporary),
- weak_factory_(this),
sandbox_file_system_(origin_, type_),
quota_status_(storage::kQuotaStatusUnknown),
- usage_(-1) {}
+ usage_(-1),
+ weak_factory_(this) {}
void SetUp() override {
ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
@@ -802,12 +802,12 @@ class ObfuscatedFileUtilTest : public testing::Test {
scoped_refptr<FileSystemContext> file_system_context_;
GURL origin_;
storage::FileSystemType type_;
- base::WeakPtrFactory<ObfuscatedFileUtilTest> weak_factory_;
SandboxFileSystemTestHelper sandbox_file_system_;
storage::QuotaStatusCode quota_status_;
int64 usage_;
storage::MockFileChangeObserver change_observer_;
storage::ChangeObserverList change_observers_;
+ base::WeakPtrFactory<ObfuscatedFileUtilTest> weak_factory_;
private:
DISALLOW_COPY_AND_ASSIGN(ObfuscatedFileUtilTest);
diff --git a/chromium/content/browser/fileapi/transient_file_util_unittest.cc b/chromium/content/browser/fileapi/transient_file_util_unittest.cc
index faf20caa4c5..2ed8b746495 100644
--- a/chromium/content/browser/fileapi/transient_file_util_unittest.cc
+++ b/chromium/content/browser/fileapi/transient_file_util_unittest.cc
@@ -9,11 +9,11 @@
#include "base/memory/scoped_ptr.h"
#include "base/run_loop.h"
#include "content/public/test/test_file_system_context.h"
+#include "storage/browser/blob/scoped_file.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"
using storage::FileSystemURL;
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 a6a99ca0c75..3cf45fe418c 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
@@ -10,7 +10,7 @@
#include "base/bind.h"
#include "base/numerics/safe_conversions.h"
#include "net/base/net_errors.h"
-#include "storage/browser/blob/file_stream_reader.h"
+#include "storage/browser/fileapi/file_stream_reader.h"
#include "storage/browser/fileapi/file_system_context.h"
#include "storage/browser/fileapi/file_system_url.h"
diff --git a/chromium/content/browser/frame_host/DEPS b/chromium/content/browser/frame_host/DEPS
index 09569cb1402..ebd27f06278 100644
--- a/chromium/content/browser/frame_host/DEPS
+++ b/chromium/content/browser/frame_host/DEPS
@@ -1,4 +1,5 @@
include_rules = [
+ "+content/public/renderer/isolated_world_ids.h",
# The frame_host files should only call upwards in the layering via the
# delegate interfaces.
"-content/browser/web_contents",
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 43efd017fe1..b9f66ac7599 100644
--- a/chromium/content/browser/frame_host/cross_process_frame_connector.cc
+++ b/chromium/content/browser/frame_host/cross_process_frame_connector.cc
@@ -141,7 +141,8 @@ void CrossProcessFrameConnector::OnForwardInputEvent(
void CrossProcessFrameConnector::SetDeviceScaleFactor(float scale_factor) {
device_scale_factor_ = scale_factor;
- if (view_) {
+ // The RenderWidgetHost is null in unit tests.
+ if (view_ && view_->GetRenderWidgetHost()) {
RenderWidgetHostImpl* child_widget =
RenderWidgetHostImpl::From(view_->GetRenderWidgetHost());
child_widget->NotifyScreenInfoChanged();
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 dffeba2675d..c52c9913d81 100644
--- a/chromium/content/browser/frame_host/cross_process_frame_connector.h
+++ b/chromium/content/browser/frame_host/cross_process_frame_connector.h
@@ -6,7 +6,7 @@
#define CONTENT_BROWSER_FRAME_HOST_CROSS_PROCESS_FRAME_CONNECTOR_H_
#include "cc/output/compositor_frame.h"
-#include "ui/gfx/rect.h"
+#include "ui/gfx/geometry/rect.h"
namespace blink {
class WebInputEvent;
diff --git a/chromium/content/browser/frame_host/cross_site_transferring_request.cc b/chromium/content/browser/frame_host/cross_site_transferring_request.cc
index 6d3ac2c0d08..1a34fe72158 100644
--- a/chromium/content/browser/frame_host/cross_site_transferring_request.cc
+++ b/chromium/content/browser/frame_host/cross_site_transferring_request.cc
@@ -14,7 +14,7 @@ namespace content {
namespace {
void CancelRequestOnIOThread(GlobalRequestID global_request_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
ResourceDispatcherHostImpl::Get()->CancelTransferringNavigation(
global_request_id);
diff --git a/chromium/content/browser/frame_host/debug_urls.cc b/chromium/content/browser/frame_host/debug_urls.cc
index 0b2ca863388..3f6769bac1f 100644
--- a/chromium/content/browser/frame_host/debug_urls.cc
+++ b/chromium/content/browser/frame_host/debug_urls.cc
@@ -4,12 +4,18 @@
#include "content/browser/frame_host/debug_urls.h"
+#if defined(SYZYASAN)
+#include <windows.h>
+#endif
+
#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 "base/synchronization/waitable_event.h"
+#include "base/threading/thread_restrictions.h"
#include "cc/base/switches.h"
#include "content/browser/gpu/gpu_process_host_ui_shim.h"
#include "content/public/browser/browser_thread.h"
@@ -36,6 +42,12 @@ const char kAsanCorruptHeapBlock[] = "/browser-corrupt-heap-block";
const char kAsanCorruptHeap[] = "/browser-corrupt-heap";
#endif
+#if defined(KASKO)
+// Define the Kasko debug URLs.
+const char kKaskoCrashDomain[] = "kasko";
+const char kKaskoSendReport[] = "/send-report";
+#endif
+
void HandlePpapiFlashDebugURL(const GURL& url) {
#if defined(ENABLE_PLUGINS)
bool crash = url == GURL(kChromeUIPpapiFlashCrashURL);
@@ -53,6 +65,35 @@ void HandlePpapiFlashDebugURL(const GURL& url) {
#endif
}
+bool IsKaskoDebugURL(const GURL& url) {
+#if defined(KASKO)
+ return (url.is_valid() && url.SchemeIs(kChromeUIScheme) &&
+ url.DomainIs(kKaskoCrashDomain, sizeof(kKaskoCrashDomain) - 1) &&
+ url.path() == kKaskoSendReport);
+#else
+ return false;
+#endif
+}
+
+void HandleKaskoDebugURL() {
+#if defined(KASKO)
+ // Signature of an enhanced crash reporting function.
+ typedef void(__cdecl * ReportCrashWithProtobufPtr)(EXCEPTION_POINTERS*,
+ const char*);
+
+ HMODULE exe_hmodule = ::GetModuleHandle(NULL);
+ ReportCrashWithProtobufPtr report_crash_with_protobuf =
+ reinterpret_cast<ReportCrashWithProtobufPtr>(
+ ::GetProcAddress(exe_hmodule, "ReportCrashWithProtobuf"));
+ if (report_crash_with_protobuf)
+ report_crash_with_protobuf(NULL, "Invoked from debug url.");
+ else
+ NOTREACHED();
+#else
+ NOTIMPLEMENTED();
+#endif
+}
+
bool IsAsanDebugURL(const GURL& url) {
#if defined(SYZYASAN)
if (!base::debug::IsBinaryInstrumented())
@@ -110,6 +151,11 @@ bool HandleAsanDebugURL(const GURL& url) {
} // namespace
+class ScopedAllowWaitForDebugURL {
+ private:
+ base::ThreadRestrictions::ScopedAllowWait wait;
+};
+
bool HandleDebugURL(const GURL& url, ui::PageTransition transition) {
// Ensure that the user explicitly navigated to this URL, unless
// kEnableGpuBenchmarking is enabled by Telemetry.
@@ -125,12 +171,23 @@ bool HandleDebugURL(const GURL& url, ui::PageTransition transition) {
if (IsAsanDebugURL(url))
return HandleAsanDebugURL(url);
+ if (IsKaskoDebugURL(url)) {
+ HandleKaskoDebugURL();
+ return true;
+ }
+
if (url == GURL(kChromeUIBrowserCrashURL)) {
// Induce an intentional crash in the browser process.
CHECK(false);
return true;
}
+ if (url == GURL(kChromeUIBrowserUIHang)) {
+ ScopedAllowWaitForDebugURL allow_wait;
+ base::WaitableEvent(false, false).Wait();
+ return true;
+ }
+
if (url == GURL(kChromeUIGpuCleanURL)) {
GpuProcessHostUIShim* shim = GpuProcessHostUIShim::GetOneInstance();
if (shim)
diff --git a/chromium/content/browser/frame_host/frame_accessibility.cc b/chromium/content/browser/frame_host/frame_accessibility.cc
index aa2c32667bf..b0461670d6d 100644
--- a/chromium/content/browser/frame_host/frame_accessibility.cc
+++ b/chromium/content/browser/frame_host/frame_accessibility.cc
@@ -18,7 +18,7 @@ FrameAccessibility* FrameAccessibility::GetInstance() {
}
FrameAccessibility::ChildFrameMapping::ChildFrameMapping()
- : parent_frame_host(NULL),
+ : parent_frame_host(nullptr),
accessibility_node_id(0),
child_frame_tree_node_id(0),
browser_plugin_instance_id(0) {}
@@ -30,7 +30,7 @@ FrameAccessibility::~FrameAccessibility() {}
void FrameAccessibility::AddChildFrame(
RenderFrameHostImpl* parent_frame_host,
int accessibility_node_id,
- int64 child_frame_tree_node_id) {
+ int child_frame_tree_node_id) {
for (std::vector<ChildFrameMapping>::iterator iter = mappings_.begin();
iter != mappings_.end();
++iter) {
@@ -105,31 +105,50 @@ RenderFrameHostImpl* FrameAccessibility::GetChild(
}
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();
+ return GetRFHIFromFrameTreeNodeId(
+ parent_frame_host, iter->child_frame_tree_node_id);
}
if (iter->browser_plugin_instance_id) {
RenderFrameHost* guest =
parent_frame_host->delegate()->GetGuestByInstanceID(
+ iter->parent_frame_host,
iter->browser_plugin_instance_id);
if (guest)
return static_cast<RenderFrameHostImpl*>(guest);
}
}
- return NULL;
+ return nullptr;
+}
+
+void FrameAccessibility::GetAllChildFrames(
+ RenderFrameHostImpl* parent_frame_host,
+ std::vector<RenderFrameHostImpl*>* child_frame_hosts) {
+ CHECK(child_frame_hosts);
+
+ for (std::vector<ChildFrameMapping>::iterator iter = mappings_.begin();
+ iter != mappings_.end();
+ ++iter) {
+ if (iter->parent_frame_host != parent_frame_host)
+ continue;
+
+ if (iter->child_frame_tree_node_id) {
+ RenderFrameHostImpl* child_frame_host = GetRFHIFromFrameTreeNodeId(
+ parent_frame_host, iter->child_frame_tree_node_id);
+ if (child_frame_host)
+ child_frame_hosts->push_back(child_frame_host);
+ }
+
+ if (iter->browser_plugin_instance_id) {
+ RenderFrameHost* guest =
+ parent_frame_host->delegate()->GetGuestByInstanceID(
+ iter->parent_frame_host,
+ iter->browser_plugin_instance_id);
+ if (guest)
+ child_frame_hosts->push_back(static_cast<RenderFrameHostImpl*>(guest));
+ }
+ }
}
bool FrameAccessibility::GetParent(
@@ -141,12 +160,18 @@ bool FrameAccessibility::GetParent(
++iter) {
if (iter->child_frame_tree_node_id) {
FrameTreeNode* child_node =
- FrameTree::GloballyFindByID(iter->child_frame_tree_node_id);
+ FrameTreeNode::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()) {
+ // Assert that the child node is a descendant of the parent frame in
+ // the frame tree. It may not be a direct descendant because the
+ // parent frame's accessibility tree may span multiple frames from the
+ // same origin.
+ FrameTreeNode* parent_node = iter->parent_frame_host->frame_tree_node();
+ FrameTreeNode* child_node_ancestor = child_node->parent();
+ while (child_node_ancestor && child_node_ancestor != parent_node)
+ child_node_ancestor = child_node_ancestor->parent();
+ if (child_node_ancestor != parent_node) {
NOTREACHED();
return false;
}
@@ -162,6 +187,7 @@ bool FrameAccessibility::GetParent(
if (iter->browser_plugin_instance_id) {
RenderFrameHost* guest =
iter->parent_frame_host->delegate()->GetGuestByInstanceID(
+ iter->parent_frame_host,
iter->browser_plugin_instance_id);
if (guest == child_frame_host) {
if (out_parent_frame_host)
@@ -176,4 +202,28 @@ bool FrameAccessibility::GetParent(
return false;
}
+RenderFrameHostImpl* FrameAccessibility::GetRFHIFromFrameTreeNodeId(
+ RenderFrameHostImpl* parent_frame_host,
+ int child_frame_tree_node_id) {
+ FrameTreeNode* child_node =
+ FrameTreeNode::GloballyFindByID(child_frame_tree_node_id);
+ if (!child_node)
+ return nullptr;
+
+ // Assert that the child node is a descendant of the parent frame in
+ // the frame tree. It may not be a direct descendant because the
+ // parent frame's accessibility tree may span multiple frames from the
+ // same origin.
+ FrameTreeNode* parent_node = parent_frame_host->frame_tree_node();
+ FrameTreeNode* child_node_ancestor = child_node->parent();
+ while (child_node_ancestor && child_node_ancestor != parent_node)
+ child_node_ancestor = child_node_ancestor->parent();
+ if (child_node_ancestor != parent_node) {
+ NOTREACHED();
+ return nullptr;
+ }
+
+ return child_node->current_frame_host();
+}
+
} // namespace content
diff --git a/chromium/content/browser/frame_host/frame_accessibility.h b/chromium/content/browser/frame_host/frame_accessibility.h
index 253ba19b054..d97a5c014e1 100644
--- a/chromium/content/browser/frame_host/frame_accessibility.h
+++ b/chromium/content/browser/frame_host/frame_accessibility.h
@@ -27,7 +27,7 @@ class CONTENT_EXPORT FrameAccessibility {
// frame tree.
void AddChildFrame(RenderFrameHostImpl* parent_frame_host,
int accessibility_node_id,
- int64 child_frame_tree_node_id);
+ int 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
@@ -48,6 +48,13 @@ class CONTENT_EXPORT FrameAccessibility {
RenderFrameHostImpl* GetChild(RenderFrameHostImpl* parent_frame_host,
int accessibility_node_id);
+ // Given a parent RenderFrameHostImpl and an accessibility node id, look up
+ // all child frames or guest frames that were previously associated with this
+ // frame, and populate |child_frame_hosts| with all of them that resolve
+ // to a valid RenderFrameHostImpl.
+ void GetAllChildFrames(RenderFrameHostImpl* parent_frame_host,
+ std::vector<RenderFrameHostImpl*>* child_frame_hosts);
+
// 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,
@@ -60,12 +67,32 @@ class CONTENT_EXPORT FrameAccessibility {
FrameAccessibility();
virtual ~FrameAccessibility();
+ RenderFrameHostImpl* GetRFHIFromFrameTreeNodeId(
+ RenderFrameHostImpl* parent_frame_host,
+ int child_frame_tree_node_id);
+
+ // This structure stores the parent-child relationship between an
+ // accessibility node in a parent frame and its child frame, where the
+ // child frame may be an iframe or the main frame of a guest browser
+ // plugin. It allows the accessibility code to walk both down and up
+ // the "composed" accessibility tree.
struct ChildFrameMapping {
ChildFrameMapping();
+ // The parent frame host. Required.
RenderFrameHostImpl* parent_frame_host;
+
+ // The id of the accessibility node that's the host of the child frame,
+ // for example the accessibility node for the <iframe> element or the
+ // <embed> element.
int accessibility_node_id;
- int64 child_frame_tree_node_id;
+
+ // If the child frame is an iframe, this is the iframe's FrameTreeNode id,
+ // otherwise 0.
+ int child_frame_tree_node_id;
+
+ // If the child frame is a browser plugin, this is its instance id,
+ // otherwise 0.
int browser_plugin_instance_id;
};
diff --git a/chromium/content/browser/frame_host/frame_navigation_entry.cc b/chromium/content/browser/frame_host/frame_navigation_entry.cc
new file mode 100644
index 00000000000..02af2af9ce9
--- /dev/null
+++ b/chromium/content/browser/frame_host/frame_navigation_entry.cc
@@ -0,0 +1,40 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/frame_host/frame_navigation_entry.h"
+
+namespace content {
+
+FrameNavigationEntry::FrameNavigationEntry(int64 frame_tree_node_id)
+ : frame_tree_node_id_(frame_tree_node_id) {
+}
+
+FrameNavigationEntry::FrameNavigationEntry(int64 frame_tree_node_id,
+ SiteInstanceImpl* site_instance,
+ const GURL& url,
+ const Referrer& referrer)
+ : frame_tree_node_id_(frame_tree_node_id),
+ site_instance_(site_instance),
+ url_(url),
+ referrer_(referrer) {
+}
+
+FrameNavigationEntry::~FrameNavigationEntry() {
+}
+
+FrameNavigationEntry* FrameNavigationEntry::Clone() const {
+ FrameNavigationEntry* copy = new FrameNavigationEntry(frame_tree_node_id_);
+ copy->UpdateEntry(site_instance_.get(), url_, referrer_);
+ return copy;
+}
+
+void FrameNavigationEntry::UpdateEntry(SiteInstanceImpl* site_instance,
+ const GURL& url,
+ const Referrer& referrer) {
+ site_instance_ = site_instance;
+ url_ = url;
+ referrer_ = referrer;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/frame_host/frame_navigation_entry.h b/chromium/content/browser/frame_host/frame_navigation_entry.h
new file mode 100644
index 00000000000..15d224ca188
--- /dev/null
+++ b/chromium/content/browser/frame_host/frame_navigation_entry.h
@@ -0,0 +1,91 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_FRAME_HOST_FRAME_NAVIGATION_ENTRY_H_
+#define CONTENT_BROWSER_FRAME_HOST_FRAME_NAVIGATION_ENTRY_H_
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "content/browser/site_instance_impl.h"
+#include "content/public/common/referrer.h"
+
+namespace content {
+
+// Represents a session history item for a particular frame.
+//
+// This class is refcounted and can be shared across multiple NavigationEntries.
+// For now, it is owned by a single NavigationEntry and only tracks the main
+// frame.
+//
+// TODO(creis): In --site-per-process, fill in a tree of FrameNavigationEntries
+// in each NavigationEntry, one per frame. FrameNavigationEntries may be shared
+// across NavigationEntries if the frame hasn't changed.
+class CONTENT_EXPORT FrameNavigationEntry
+ : public base::RefCounted<FrameNavigationEntry> {
+ public:
+ // TODO(creis): We should not use FTN IDs here, since they will change if you
+ // leave a page and come back later. We should evaluate whether Blink's
+ // frame sequence numbers or unique names would work instead, similar to
+ // HistoryNode.
+ explicit FrameNavigationEntry(int64 frame_tree_node_id);
+ FrameNavigationEntry(int64 frame_tree_node_id,
+ SiteInstanceImpl* site_instance,
+ const GURL& url,
+ const Referrer& referrer);
+
+ // Creates a copy of this FrameNavigationEntry that can be modified
+ // independently from the original.
+ FrameNavigationEntry* Clone() const;
+
+ // Updates all the members of this entry.
+ void UpdateEntry(SiteInstanceImpl* site_instance,
+ const GURL& url,
+ const Referrer& referrer);
+
+ // The ID of the FrameTreeNode this entry is for. -1 for the main frame,
+ // since we don't always know the FrameTreeNode ID when creating the overall
+ // NavigationEntry.
+ // TODO(creis): Replace with frame sequence number or unique name.
+ int64 frame_tree_node_id() const { return frame_tree_node_id_; }
+
+ // The SiteInstance responsible for rendering this frame. All frames sharing
+ // a SiteInstance must live in the same process. This is a refcounted pointer
+ // that keeps the SiteInstance (not necessarily the process) alive as long as
+ // this object remains in the session history.
+ void set_site_instance(SiteInstanceImpl* site_instance) {
+ site_instance_ = site_instance;
+ }
+ SiteInstanceImpl* site_instance() const { return site_instance_.get(); }
+
+ // The actual URL loaded in the frame. This is in contrast to the virtual
+ // URL, which is shown to the user.
+ void set_url(const GURL& url) { url_ = url; }
+ const GURL& url() const { return url_; }
+
+ // The referring URL. Can be empty.
+ void set_referrer(const Referrer& referrer) { referrer_ = referrer; }
+ const Referrer& referrer() const { return referrer_; }
+
+ private:
+ friend class base::RefCounted<FrameNavigationEntry>;
+ virtual ~FrameNavigationEntry();
+
+ // WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+ // For all new fields, update |Clone|.
+ // TODO(creis): These fields have implications for session restore. This is
+ // currently managed by NavigationEntry, but the logic will move here.
+ // WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+
+ // See the accessors above for descriptions.
+ int64 frame_tree_node_id_;
+ scoped_refptr<SiteInstanceImpl> site_instance_;
+ GURL url_;
+ Referrer referrer_;
+
+ DISALLOW_COPY_AND_ASSIGN(FrameNavigationEntry);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_FRAME_HOST_FRAME_NAVIGATION_ENTRY_H_
diff --git a/chromium/content/browser/frame_host/frame_tree.cc b/chromium/content/browser/frame_host/frame_tree.cc
index b1ccf6f9c79..798a849daf4 100644
--- a/chromium/content/browser/frame_host/frame_tree.cc
+++ b/chromium/content/browser/frame_host/frame_tree.cc
@@ -17,22 +17,14 @@
#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| whithin a specific FrameTree.
-bool FrameTreeNodeForId(int64 frame_tree_node_id,
+// corresponding to |frame_tree_node_id| within a specific FrameTree.
+bool FrameTreeNodeForId(int frame_tree_node_id,
FrameTreeNode** out_node,
FrameTreeNode* node) {
if (node->frame_tree_node_id() == frame_tree_node_id) {
@@ -43,15 +35,15 @@ bool FrameTreeNodeForId(int64 frame_tree_node_id,
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()) {
- // 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();
+// Used with FrameTree::ForEach() to search for the FrameTreeNode with the given
+// |name| within a specific FrameTree.
+bool FrameTreeNodeForName(const std::string& name,
+ FrameTreeNode** out_node,
+ FrameTreeNode* node) {
+ if (node->frame_name() == name) {
+ *out_node = node;
+ // Terminate iteration once the node has been found.
+ return false;
}
return true;
}
@@ -67,6 +59,38 @@ bool CreateProxyForSiteInstance(const scoped_refptr<SiteInstance>& instance,
return true;
}
+// Helper function used with FrameTree::ForEach() for retrieving the total
+// loading progress and number of frames in a frame tree.
+bool CollectLoadProgress(double* progress,
+ int* frame_count,
+ FrameTreeNode* node) {
+ // Ignore the current frame if it has not started loading.
+ if (!node->has_started_loading())
+ return true;
+
+ // Collect progress.
+ *progress += node->loading_progress();
+ (*frame_count)++;
+ return true;
+}
+
+// Helper function used with FrameTree::ForEach() to reset the load progress.
+bool ResetNodeLoadProgress(FrameTreeNode* node) {
+ node->reset_loading_progress();
+ return true;
+}
+
+// Helper function used with FrameTree::ForEach() to check if at least one of
+// the nodes is loading.
+bool IsNodeLoading(bool* is_loading, FrameTreeNode* node) {
+ if (node->IsLoading()) {
+ // There is at least one node loading, so abort traversal.
+ *is_loading = true;
+ return false;
+ }
+ return true;
+}
+
} // namespace
FrameTree::FrameTree(Navigator* navigator,
@@ -84,33 +108,22 @@ FrameTree::FrameTree(Navigator* navigator,
render_view_delegate,
render_widget_delegate,
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);
+ std::string(),
+ SandboxFlags::NONE)),
+ focused_frame_tree_node_id_(-1),
+ load_progress_(0.0) {
}
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) {
- FrameTreeNode* node = NULL;
+FrameTreeNode* FrameTree::FindByID(int frame_tree_node_id) {
+ FrameTreeNode* node = nullptr;
ForEach(base::Bind(&FrameTreeNodeForId, frame_tree_node_id, &node));
return node;
}
-FrameTreeNode* FrameTree::FindByRoutingID(int routing_id, int process_id) {
+FrameTreeNode* FrameTree::FindByRoutingID(int process_id, int routing_id) {
RenderFrameHostImpl* render_frame_host =
RenderFrameHostImpl::FromID(process_id, routing_id);
if (render_frame_host) {
@@ -127,12 +140,21 @@ FrameTreeNode* FrameTree::FindByRoutingID(int routing_id, int process_id) {
return result;
}
- return NULL;
+ return nullptr;
+}
+
+FrameTreeNode* FrameTree::FindByName(const std::string& name) {
+ if (name.empty())
+ return root_.get();
+
+ FrameTreeNode* node = nullptr;
+ ForEach(base::Bind(&FrameTreeNodeForName, name, &node));
+ return node;
}
void FrameTree::ForEach(
const base::Callback<bool(FrameTreeNode*)>& on_node) const {
- ForEach(on_node, NULL);
+ ForEach(on_node, nullptr);
}
void FrameTree::ForEach(
@@ -158,21 +180,20 @@ void FrameTree::ForEach(
RenderFrameHostImpl* FrameTree::AddFrame(FrameTreeNode* parent,
int process_id,
int new_routing_id,
- const std::string& frame_name) {
+ const std::string& frame_name,
+ SandboxFlags sandbox_flags) {
// 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.
+ // We return nullptr if this is not the case, which can happen in a race if an
+ // old RFH sends a CreateChildFrame message as we're swapping to a new RFH.
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);
+ render_widget_delegate_, manager_delegate_, frame_name, sandbox_flags));
FrameTreeNode* node_ptr = node.get();
// AddChild is what creates the RenderFrameHost.
parent->AddChild(node.Pass(), process_id, new_routing_id);
@@ -186,12 +207,6 @@ void FrameTree::RemoveFrame(FrameTreeNode* child) {
return;
}
- // 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);
- }
- g_frame_tree_node_id_map.Get().erase(child->frame_tree_node_id());
parent->RemoveChild(child);
}
@@ -205,11 +220,12 @@ void FrameTree::CreateProxiesForSiteInstance(
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);
+ root()->render_manager()->CreateRenderFrame(
+ site_instance, nullptr, MSG_ROUTING_NONE,
+ CREATE_RF_SWAPPED_OUT | CREATE_RF_HIDDEN, nullptr);
+ } else {
+ root()->render_manager()->EnsureRenderViewInitialized(
+ source, render_view_host, site_instance);
}
}
@@ -221,21 +237,6 @@ void FrameTree::CreateProxiesForSiteInstance(
ForEach(base::Bind(&CreateProxyForSiteInstance, instance), source);
}
-void FrameTree::ResetForMainFrameSwap() {
- root_->ResetForNewProcess();
- focused_frame_tree_node_id_ = -1;
-}
-
-void FrameTree::RenderProcessGone(RenderViewHost* render_view_host) {
- // Walk the full tree looking for nodes that may be affected. Once a frame
- // crashes, all of its child FrameTreeNodes go away.
- // Note that the helper function may call ResetForNewProcess on a node, which
- // clears its children before we iterate over them. That's ok, because
- // ForEach does not add a node's children to the queue until after visiting
- // the node itself.
- ForEach(base::Bind(&ResetNodesForNewProcess, render_view_host));
-}
-
RenderFrameHostImpl* FrameTree::GetMainFrame() const {
return root_->current_frame_host();
}
@@ -293,16 +294,14 @@ RenderViewHostImpl* FrameTree::CreateRenderViewHost(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.
if (iter == render_view_host_map_.end())
- return NULL;
+ return nullptr;
return iter->second;
}
void FrameTree::RegisterRenderFrameHost(
RenderFrameHostImpl* render_frame_host) {
- SiteInstance* site_instance =
- render_frame_host->render_view_host()->GetSiteInstance();
+ SiteInstance* site_instance = render_frame_host->GetSiteInstance();
RenderViewHostMap::iterator iter =
render_view_host_map_.find(site_instance->GetId());
CHECK(iter != render_view_host_map_.end());
@@ -312,8 +311,7 @@ void FrameTree::RegisterRenderFrameHost(
void FrameTree::UnregisterRenderFrameHost(
RenderFrameHostImpl* render_frame_host) {
- SiteInstance* site_instance =
- render_frame_host->render_view_host()->GetSiteInstance();
+ SiteInstance* site_instance = render_frame_host->GetSiteInstance();
int32 site_instance_id = site_instance->GetId();
RenderViewHostMap::iterator iter =
render_view_host_map_.find(site_instance_id);
@@ -355,4 +353,46 @@ void FrameTree::UnregisterRenderFrameHost(
}
}
+void FrameTree::FrameRemoved(FrameTreeNode* frame) {
+ if (frame->frame_tree_node_id() == focused_frame_tree_node_id_)
+ focused_frame_tree_node_id_ = -1;
+
+ // No notification for the root frame.
+ if (!frame->parent()) {
+ CHECK_EQ(frame, root_.get());
+ return;
+ }
+
+ // Notify observers of the frame removal.
+ if (!on_frame_removed_.is_null())
+ on_frame_removed_.Run(frame->current_frame_host());
+}
+
+void FrameTree::UpdateLoadProgress() {
+ double progress = 0.0;
+ int frame_count = 0;
+
+ ForEach(base::Bind(&CollectLoadProgress, &progress, &frame_count));
+ if (frame_count != 0)
+ progress /= frame_count;
+
+ if (progress <= load_progress_)
+ return;
+ load_progress_ = progress;
+
+ // Notify the WebContents.
+ root_->navigator()->GetDelegate()->DidChangeLoadProgress();
+}
+
+void FrameTree::ResetLoadProgress() {
+ ForEach(base::Bind(&ResetNodeLoadProgress));
+ load_progress_ = 0.0;
+}
+
+bool FrameTree::IsLoading() {
+ bool is_loading = false;
+ ForEach(base::Bind(&IsNodeLoading, &is_loading));
+ return is_loading;
+}
+
} // namespace content
diff --git a/chromium/content/browser/frame_host/frame_tree.h b/chromium/content/browser/frame_host/frame_tree.h
index b312265fe4e..c853dd5b391 100644
--- a/chromium/content/browser/frame_host/frame_tree.h
+++ b/chromium/content/browser/frame_host/frame_tree.h
@@ -50,17 +50,20 @@ 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| if it is part
// of this FrameTree.
- FrameTreeNode* FindByID(int64 frame_tree_node_id);
+ FrameTreeNode* FindByID(int frame_tree_node_id);
// Returns the FrameTreeNode with the given renderer-specific |routing_id|.
- FrameTreeNode* FindByRoutingID(int routing_id, int process_id);
+ FrameTreeNode* FindByRoutingID(int process_id, int routing_id);
+
+ // Returns the first frame in this tree with the given |name|, or the main
+ // frame if |name| is empty.
+ // Note that this does NOT support pseudo-names like _self, _top, and _blank,
+ // nor searching other FrameTrees (unlike blink::WebView::findFrameByName).
+ FrameTreeNode* FindByName(const std::string& name);
// Executes |on_node| on each node in the frame tree. If |on_node| returns
// false, terminates the iteration immediately. Returning false is useful
@@ -70,10 +73,15 @@ class CONTENT_EXPORT FrameTree {
void ForEach(const base::Callback<bool(FrameTreeNode*)>& on_node) const;
// Frame tree manipulation routines.
+ // |process_id| is required to disambiguate |new_routing_id|, and it must
+ // match the process of the |parent| node. Otherwise this method returns
+ // nullptr. Passing MSG_ROUTING_NONE for |new_routing_id| will allocate a new
+ // routing ID for the new frame.
RenderFrameHostImpl* AddFrame(FrameTreeNode* parent,
int process_id,
int new_routing_id,
- const std::string& frame_name);
+ const std::string& frame_name,
+ SandboxFlags sandbox_flags);
void RemoveFrame(FrameTreeNode* child);
// This method walks the entire frame tree and creates a RenderFrameProxyHost
@@ -84,20 +92,6 @@ class CONTENT_EXPORT FrameTree {
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
- // support bookkeeping for top-level navigations.
- // TODO(creis): Look into how we can remove the need for this method.
- void ResetForMainFrameSwap();
-
- // Update the frame tree after a process exits. Any nodes currently using the
- // given |render_view_host| will lose all their children.
- // TODO(creis): This should take a RenderProcessHost once RenderFrameHost
- // knows its process. Until then, we would just be asking the RenderViewHost
- // for its process, so we'll skip that step.
- void RenderProcessGone(RenderViewHost* render_view_host);
-
// Convenience accessor for the main frame's RenderFrameHostImpl.
RenderFrameHostImpl* GetMainFrame() const;
@@ -132,7 +126,24 @@ class CONTENT_EXPORT FrameTree {
void RegisterRenderFrameHost(RenderFrameHostImpl* render_frame_host);
void UnregisterRenderFrameHost(RenderFrameHostImpl* render_frame_host);
+ // This is only meant to be called by FrameTreeNode. Triggers calling
+ // the listener installed by SetFrameRemoveListener.
+ void FrameRemoved(FrameTreeNode* frame);
+
+ // Updates the overall load progress and notifies the WebContents.
+ void UpdateLoadProgress();
+
+ // Returns this FrameTree's total load progress.
+ double load_progress() { return load_progress_; }
+
+ // Resets the load progress on all nodes in this FrameTree.
+ void ResetLoadProgress();
+
+ // Returns true if at least one of the nodes in this FrameTree is loading.
+ bool IsLoading();
+
private:
+ FRIEND_TEST_ALL_PREFIXES(RenderFrameHostImplBrowserTest, RemoveFocusedFrame);
typedef base::hash_map<int, RenderViewHostImpl*> RenderViewHostMap;
typedef std::multimap<int, RenderViewHostImpl*> RenderViewHostMultiMap;
@@ -167,10 +178,13 @@ class CONTENT_EXPORT FrameTree {
scoped_ptr<FrameTreeNode> root_;
- int64 focused_frame_tree_node_id_;
+ int focused_frame_tree_node_id_;
base::Callback<void(RenderFrameHost*)> on_frame_removed_;
+ // Overall load progress.
+ double load_progress_;
+
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 9f16066cd38..15e72e7e0e7 100644
--- a/chromium/content/browser/frame_host/frame_tree_browsertest.cc
+++ b/chromium/content/browser/frame_host/frame_tree_browsertest.cc
@@ -19,6 +19,12 @@
#include "content/shell/browser/shell.h"
#include "content/test/content_browser_test_utils_internal.h"
#include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+
+// For fine-grained suppression on flaky tests.
+#if defined(OS_WIN)
+#include "base/win/windows_version.h"
+#endif
namespace content {
@@ -26,20 +32,19 @@ class FrameTreeBrowserTest : public ContentBrowserTest {
public:
FrameTreeBrowserTest() {}
+ void SetUpOnMainThread() override {
+ host_resolver()->AddRule("*", "127.0.0.1");
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+ SetupCrossSiteRedirector(embedded_test_server());
+ }
+
private:
DISALLOW_COPY_AND_ASSIGN(FrameTreeBrowserTest);
};
// Ensures FrameTree correctly reflects page structure during navigations.
IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, FrameTreeShape) {
- host_resolver()->AddRule("*", "127.0.0.1");
- ASSERT_TRUE(test_server()->Start());
-
- GURL base_url = test_server()->GetURL("files/site_isolation/");
- GURL::Replacements replace_host;
- std::string host_str("A.com"); // Must stay in scope with replace_host.
- replace_host.SetHostStr(host_str);
- base_url = base_url.ReplaceComponents(replace_host);
+ GURL base_url = embedded_test_server()->GetURL("A.com", "/site_isolation/");
// Load doc without iframes. Verify FrameTree just has root.
// Frame tree:
@@ -68,9 +73,8 @@ IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, FrameTreeShape) {
// TODO(ajwong): Talk with nasko and merge this functionality with
// FrameTreeShape.
IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, FrameTreeShape2) {
- ASSERT_TRUE(test_server()->Start());
NavigateToURL(shell(),
- test_server()->GetURL("files/frame_tree/top.html"));
+ embedded_test_server()->GetURL("/frame_tree/top.html"));
WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
FrameTreeNode* root = wc->GetFrameTree()->root();
@@ -91,7 +95,7 @@ IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, FrameTreeShape2) {
// Navigate to about:blank, which should leave only the root node of the frame
// tree in the browser process.
- NavigateToURL(shell(), test_server()->GetURL("files/title1.html"));
+ NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
root = wc->GetFrameTree()->root();
EXPECT_EQ(0UL, root->child_count());
@@ -101,9 +105,8 @@ IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, FrameTreeShape2) {
// Test that we can navigate away if the previous renderer doesn't clean up its
// child frames.
IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, FrameTreeAfterCrash) {
- ASSERT_TRUE(test_server()->Start());
NavigateToURL(shell(),
- test_server()->GetURL("files/frame_tree/top.html"));
+ embedded_test_server()->GetURL("/frame_tree/top.html"));
// Ensure the view and frame are live.
RenderViewHost* rvh = shell()->web_contents()->GetRenderViewHost();
@@ -129,7 +132,7 @@ IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, FrameTreeAfterCrash) {
EXPECT_FALSE(rfh->IsRenderFrameLive());
// Navigate to a new URL.
- GURL url(test_server()->GetURL("files/title1.html"));
+ GURL url(embedded_test_server()->GetURL("/title1.html"));
NavigateToURL(shell(), url);
EXPECT_EQ(0UL, root->child_count());
EXPECT_EQ(url, root->current_url());
@@ -141,18 +144,22 @@ IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, FrameTreeAfterCrash) {
// Test that we can navigate away if the previous renderer doesn't clean up its
// child frames.
-IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, NavigateWithLeftoverFrames) {
- host_resolver()->AddRule("*", "127.0.0.1");
- ASSERT_TRUE(test_server()->Start());
-
- GURL base_url = test_server()->GetURL("files/site_isolation/");
- GURL::Replacements replace_host;
- std::string host_str("A.com"); // Must stay in scope with replace_host.
- replace_host.SetHostStr(host_str);
- base_url = base_url.ReplaceComponents(replace_host);
+// Flaky on Mac. http://crbug.com/452018
+#if defined(OS_MACOSX)
+#define MAYBE_NavigateWithLeftoverFrames DISABLED_NavigateWithLeftoverFrames
+#else
+#define MAYBE_NavigateWithLeftoverFrames NavigateWithLeftoverFrames
+#endif
+IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, MAYBE_NavigateWithLeftoverFrames) {
+#if defined(OS_WIN)
+ // Flaky on XP bot http://crbug.com/468713
+ if (base::win::GetVersion() <= base::win::VERSION_XP)
+ return;
+#endif
+ GURL base_url = embedded_test_server()->GetURL("A.com", "/site_isolation/");
NavigateToURL(shell(),
- test_server()->GetURL("files/frame_tree/top.html"));
+ embedded_test_server()->GetURL("/frame_tree/top.html"));
// Hang the renderer so that it doesn't send any FrameDetached messages.
// (This navigation will never complete, so don't wait for it.)
@@ -175,9 +182,7 @@ IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, NavigateWithLeftoverFrames) {
// 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"));
+ GURL main_url(embedded_test_server()->GetURL("/frame_tree/top.html"));
NavigateToURL(shell(), main_url);
// It is safe to obtain the root frame tree node here, as it doesn't change.
@@ -191,7 +196,7 @@ IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, 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"));
+ GURL http_url(embedded_test_server()->GetURL("/title1.html"));
NavigateFrameToURL(root->child_at(0), http_url);
EXPECT_TRUE(
root->current_frame_host()->render_view_host()->IsRenderViewLive());
@@ -199,6 +204,83 @@ IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, IsRenderFrameLive) {
EXPECT_TRUE(root->child_at(0)->current_frame_host()->IsRenderFrameLive());
}
+// Ensure that origins are correctly set on navigations.
+IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, OriginSetOnNavigation) {
+ GURL main_url(embedded_test_server()->GetURL("/frame_tree/top.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ // It is safe to obtain the root frame tree node here, as it doesn't change.
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()->root();
+
+ // Extra '/' is added because the replicated origin is serialized in RFC 6454
+ // format, which dictates no trailing '/', whereas GURL::GetOrigin does put a
+ // '/' at the end.
+ EXPECT_EQ(root->current_replication_state().origin.string() + '/',
+ main_url.GetOrigin().spec());
+
+ GURL frame_url(embedded_test_server()->GetURL("/title1.html"));
+ NavigateFrameToURL(root->child_at(0), frame_url);
+
+ EXPECT_EQ(
+ root->child_at(0)->current_replication_state().origin.string() + '/',
+ frame_url.GetOrigin().spec());
+
+ GURL data_url("data:text/html,foo");
+ EXPECT_TRUE(NavigateToURL(shell(), data_url));
+
+ // Navigating to a data URL should set a unique origin. This is represented
+ // as "null" per RFC 6454.
+ EXPECT_EQ(root->current_replication_state().origin.string(), "null");
+
+ // Re-navigating to a normal URL should update the origin.
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+ EXPECT_EQ(root->current_replication_state().origin.string() + '/',
+ main_url.GetOrigin().spec());
+}
+
+// Ensure that sandbox flags are correctly set when child frames are created.
+IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, SandboxFlagsSetForChildFrames) {
+ GURL main_url(embedded_test_server()->GetURL("/sandboxed_frames.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ // It is safe to obtain the root frame tree node here, as it doesn't change.
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()->root();
+
+ // Verify that sandbox flags are set properly for all FrameTreeNodes.
+ // First frame is completely sandboxed; second frame uses "allow-scripts",
+ // which resets both SandboxFlags::Scripts and
+ // SandboxFlags::AutomaticFeatures bits per blink::parseSandboxPolicy(), and
+ // third frame has "allow-scripts allow-same-origin".
+ EXPECT_EQ(root->current_replication_state().sandbox_flags,
+ SandboxFlags::NONE);
+ EXPECT_EQ(root->child_at(0)->current_replication_state().sandbox_flags,
+ SandboxFlags::ALL);
+ EXPECT_EQ(root->child_at(1)->current_replication_state().sandbox_flags,
+ SandboxFlags::ALL & ~SandboxFlags::SCRIPTS &
+ ~SandboxFlags::AUTOMATIC_FEATURES);
+ EXPECT_EQ(root->child_at(2)->current_replication_state().sandbox_flags,
+ SandboxFlags::ALL & ~SandboxFlags::SCRIPTS &
+ ~SandboxFlags::AUTOMATIC_FEATURES & ~SandboxFlags::ORIGIN);
+
+ // Sandboxed frames should set a unique origin unless they have the
+ // "allow-same-origin" directive.
+ EXPECT_EQ(root->child_at(0)->current_replication_state().origin.string(),
+ "null");
+ EXPECT_EQ(root->child_at(1)->current_replication_state().origin.string(),
+ "null");
+ EXPECT_EQ(
+ root->child_at(2)->current_replication_state().origin.string() + "/",
+ main_url.GetOrigin().spec());
+
+ // Navigating to a different URL should not clear sandbox flags.
+ GURL frame_url(embedded_test_server()->GetURL("/title1.html"));
+ NavigateFrameToURL(root->child_at(0), frame_url);
+ EXPECT_EQ(root->child_at(0)->current_replication_state().sandbox_flags,
+ SandboxFlags::ALL);
+}
+
class CrossProcessFrameTreeBrowserTest : public ContentBrowserTest {
public:
CrossProcessFrameTreeBrowserTest() {}
@@ -207,6 +289,12 @@ class CrossProcessFrameTreeBrowserTest : public ContentBrowserTest {
command_line->AppendSwitch(switches::kSitePerProcess);
}
+ void SetUpOnMainThread() override {
+ host_resolver()->AddRule("*", "127.0.0.1");
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+ SetupCrossSiteRedirector(embedded_test_server());
+ }
+
private:
DISALLOW_COPY_AND_ASSIGN(CrossProcessFrameTreeBrowserTest);
};
@@ -219,9 +307,7 @@ class CrossProcessFrameTreeBrowserTest : public ContentBrowserTest {
#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"));
+ 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.
@@ -233,17 +319,12 @@ IN_PROC_BROWSER_TEST_F(CrossProcessFrameTreeBrowserTest,
EXPECT_FALSE(root->render_manager()->GetRenderFrameProxyHost(root_instance));
// Load same-site page into iframe.
- GURL http_url(test_server()->GetURL("files/title1.html"));
+ GURL http_url(embedded_test_server()->GetURL("/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);
+ GURL cross_site_url(
+ embedded_test_server()->GetURL("foo.com", "/title2.html"));
NavigateFrameToURL(root->child_at(0), cross_site_url);
// Ensure that we have created a new process for the subframe.
@@ -277,4 +358,50 @@ IN_PROC_BROWSER_TEST_F(CrossProcessFrameTreeBrowserTest,
EXPECT_TRUE(root->child_at(0)->current_frame_host()->IsRenderFrameLive());
}
+IN_PROC_BROWSER_TEST_F(CrossProcessFrameTreeBrowserTest,
+ OriginSetOnCrossProcessNavigations) {
+ GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ // It is safe to obtain the root frame tree node here, as it doesn't change.
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()->root();
+
+ EXPECT_EQ(root->current_replication_state().origin.string() + '/',
+ main_url.GetOrigin().spec());
+
+ // First frame is an about:blank frame. Check that its origin is correctly
+ // inherited from the parent.
+ EXPECT_EQ(
+ root->child_at(0)->current_replication_state().origin.string() + '/',
+ main_url.GetOrigin().spec());
+
+ // Second frame loads a same-site page. Its origin should also be the same
+ // as the parent.
+ EXPECT_EQ(
+ root->child_at(1)->current_replication_state().origin.string() + '/',
+ main_url.GetOrigin().spec());
+
+ // Load cross-site page into the first frame.
+ GURL cross_site_url(
+ embedded_test_server()->GetURL("foo.com", "/title2.html"));
+ NavigateFrameToURL(root->child_at(0), cross_site_url);
+
+ EXPECT_EQ(
+ root->child_at(0)->current_replication_state().origin.string() + '/',
+ cross_site_url.GetOrigin().spec());
+
+ // The root's origin shouldn't have changed.
+ EXPECT_EQ(root->current_replication_state().origin.string() + '/',
+ main_url.GetOrigin().spec());
+
+ GURL data_url("data:text/html,foo");
+ NavigateFrameToURL(root->child_at(1), data_url);
+
+ // Navigating to a data URL should set a unique origin. This is represented
+ // as "null" per RFC 6454.
+ EXPECT_EQ(root->child_at(1)->current_replication_state().origin.string(),
+ "null");
+}
+
} // 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 41be622302e..b87af213161 100644
--- a/chromium/content/browser/frame_host/frame_tree_node.cc
+++ b/chromium/content/browser/frame_host/frame_tree_node.cc
@@ -7,16 +7,45 @@
#include <queue>
#include "base/command_line.h"
+#include "base/profiler/scoped_tracker.h"
#include "base/stl_util.h"
#include "content/browser/frame_host/frame_tree.h"
+#include "content/browser/frame_host/navigation_request.h"
#include "content/browser/frame_host/navigator.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
+#include "content/public/browser/browser_thread.h"
#include "content/public/common/content_switches.h"
namespace content {
-int64 FrameTreeNode::next_frame_tree_node_id_ = 1;
+namespace {
+
+// This is a global map between frame_tree_node_ids and pointers to
+// FrameTreeNodes.
+typedef base::hash_map<int, FrameTreeNode*> FrameTreeNodeIDMap;
+
+base::LazyInstance<FrameTreeNodeIDMap> g_frame_tree_node_id_map =
+ LAZY_INSTANCE_INITIALIZER;
+
+// These values indicate the loading progress status. The minimum progress
+// value matches what Blink's ProgressTracker has traditionally used for a
+// minimum progress value.
+const double kLoadingProgressNotStarted = 0.0;
+const double kLoadingProgressMinimum = 0.1;
+const double kLoadingProgressDone = 1.0;
+
+} // namespace
+
+int FrameTreeNode::next_frame_tree_node_id_ = 1;
+
+// static
+FrameTreeNode* FrameTreeNode::GloballyFindByID(int frame_tree_node_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ FrameTreeNodeIDMap* nodes = g_frame_tree_node_id_map.Pointer();
+ FrameTreeNodeIDMap::iterator it = nodes->find(frame_tree_node_id);
+ return it == nodes->end() ? nullptr : it->second;
+}
FrameTreeNode::FrameTreeNode(FrameTree* frame_tree,
Navigator* navigator,
@@ -24,7 +53,8 @@ FrameTreeNode::FrameTreeNode(FrameTree* frame_tree,
RenderViewHostDelegate* render_view_delegate,
RenderWidgetHostDelegate* render_widget_delegate,
RenderFrameHostManager::Delegate* manager_delegate,
- const std::string& name)
+ const std::string& name,
+ SandboxFlags sandbox_flags)
: frame_tree_(frame_tree),
navigator_(navigator),
render_manager_(this,
@@ -33,14 +63,22 @@ FrameTreeNode::FrameTreeNode(FrameTree* frame_tree,
render_widget_delegate,
manager_delegate),
frame_tree_node_id_(next_frame_tree_node_id_++),
- frame_name_(name),
- parent_(NULL) {}
+ parent_(NULL),
+ replication_state_(name, sandbox_flags),
+ // Effective sandbox flags also need to be set, since initial sandbox
+ // flags should apply to the initial empty document in the frame.
+ effective_sandbox_flags_(sandbox_flags),
+ loading_progress_(kLoadingProgressNotStarted) {
+ std::pair<FrameTreeNodeIDMap::iterator, bool> result =
+ g_frame_tree_node_id_map.Get().insert(
+ std::make_pair(frame_tree_node_id_, this));
+ CHECK(result.second);
+}
FrameTreeNode::~FrameTreeNode() {
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableBrowserSideNavigation)) {
- navigator_->CancelNavigation(this);
- }
+ frame_tree_->FrameRemoved(this);
+
+ g_frame_tree_node_id_map.Get().erase(frame_tree_node_id_);
}
bool FrameTreeNode::IsMainFrame() const {
@@ -62,12 +100,20 @@ void FrameTreeNode::AddChild(scoped_ptr<FrameTreeNode> child,
render_manager_.current_host()->GetRoutingID(),
frame_routing_id);
child->set_parent(this);
+
+ // Other renderer processes in this BrowsingInstance may need to find out
+ // about the new frame. Create a proxy for the child frame in all
+ // SiteInstances that have a proxy for the frame's parent, since all frames
+ // in a frame tree should have the same set of proxies.
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess))
+ render_manager_.CreateProxiesForChildFrame(child.get());
+
children_.push_back(child.release());
}
void FrameTreeNode::RemoveChild(FrameTreeNode* child) {
std::vector<FrameTreeNode*>::iterator iter;
-
for (iter = children_.begin(); iter != children_.end(); ++iter) {
if ((*iter) == child)
break;
@@ -78,7 +124,6 @@ void FrameTreeNode::RemoveChild(FrameTreeNode* child) {
// observers are notified of its deletion.
scoped_ptr<FrameTreeNode> node_to_delete(*iter);
children_.weak_erase(iter);
- node_to_delete->set_parent(NULL);
node_to_delete.reset();
}
}
@@ -86,9 +131,6 @@ 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.
@@ -96,4 +138,171 @@ void FrameTreeNode::ResetForNewProcess() {
old_children.clear(); // May notify observers.
}
+void FrameTreeNode::SetCurrentOrigin(const url::Origin& origin) {
+ if (!origin.IsSameAs(replication_state_.origin))
+ render_manager_.OnDidUpdateOrigin(origin);
+ replication_state_.origin = origin;
+}
+
+void FrameTreeNode::SetFrameName(const std::string& name) {
+ if (name != replication_state_.name)
+ render_manager_.OnDidUpdateName(name);
+ replication_state_.name = name;
+}
+
+bool FrameTreeNode::IsDescendantOf(FrameTreeNode* other) const {
+ if (!other || !other->child_count())
+ return false;
+
+ for (FrameTreeNode* node = parent(); node; node = node->parent()) {
+ if (node == other)
+ return true;
+ }
+
+ return false;
+}
+
+FrameTreeNode* FrameTreeNode::PreviousSibling() const {
+ if (!parent_)
+ return nullptr;
+
+ for (size_t i = 0; i < parent_->child_count(); ++i) {
+ if (parent_->child_at(i) == this)
+ return (i == 0) ? nullptr : parent_->child_at(i - 1);
+ }
+
+ NOTREACHED() << "FrameTreeNode not found in its parent's children.";
+ return nullptr;
+}
+
+bool FrameTreeNode::IsLoading() const {
+ RenderFrameHostImpl* current_frame_host =
+ render_manager_.current_frame_host();
+ RenderFrameHostImpl* pending_frame_host =
+ render_manager_.pending_frame_host();
+
+ DCHECK(current_frame_host);
+
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation)) {
+ if (navigation_request_)
+ return true;
+ } else {
+ if (pending_frame_host && pending_frame_host->is_loading())
+ return true;
+ }
+ return current_frame_host->is_loading();
+}
+
+bool FrameTreeNode::CommitPendingSandboxFlags() {
+ bool did_change_flags =
+ effective_sandbox_flags_ != replication_state_.sandbox_flags;
+ effective_sandbox_flags_ = replication_state_.sandbox_flags;
+ return did_change_flags;
+}
+
+void FrameTreeNode::SetNavigationRequest(
+ scoped_ptr<NavigationRequest> navigation_request) {
+ CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation));
+ ResetNavigationRequest(false);
+
+ // Force the throbber to start to keep it in sync with what is happening in
+ // the UI. Blink doesn't send throb notifications for JavaScript URLs, so it
+ // is not done here either.
+ if (!navigation_request->common_params().url.SchemeIs(
+ url::kJavaScriptScheme)) {
+ // TODO(fdegans): Check if this is a same-document navigation and set the
+ // proper argument.
+ DidStartLoading(true);
+ }
+
+ navigation_request_ = navigation_request.Pass();
+}
+
+void FrameTreeNode::ResetNavigationRequest(bool is_commit) {
+ CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation));
+ if (!navigation_request_)
+ return;
+ navigation_request_.reset();
+
+ // During commit, the clean up of a speculative RenderFrameHost is done in
+ // RenderFrameHostManager::DidNavigateFrame. The load is also still being
+ // tracked.
+ if (is_commit)
+ return;
+
+ // If the reset corresponds to a cancelation, the RenderFrameHostManager
+ // should clean up any speculative RenderFrameHost it created for the
+ // navigation.
+ DidStopLoading();
+ render_manager_.CleanUpNavigation();
+}
+
+bool FrameTreeNode::has_started_loading() const {
+ return loading_progress_ != kLoadingProgressNotStarted;
+}
+
+void FrameTreeNode::reset_loading_progress() {
+ loading_progress_ = kLoadingProgressNotStarted;
+}
+
+void FrameTreeNode::DidStartLoading(bool to_different_document) {
+ // Any main frame load to a new document should reset the load progress since
+ // it will replace the current page and any frames. The WebContents will
+ // be notified when DidChangeLoadProgress is called.
+ if (to_different_document && IsMainFrame())
+ frame_tree_->ResetLoadProgress();
+
+ // Notify the WebContents.
+ if (!frame_tree_->IsLoading())
+ navigator()->GetDelegate()->DidStartLoading(this, to_different_document);
+
+ // Set initial load progress and update overall progress. This will notify
+ // the WebContents of the load progress change.
+ DidChangeLoadProgress(kLoadingProgressMinimum);
+
+ // Notify the RenderFrameHostManager of the event.
+ render_manager()->OnDidStartLoading();
+}
+
+void FrameTreeNode::DidStopLoading() {
+ // TODO(erikchen): Remove ScopedTracker below once crbug.com/465796 is fixed.
+ tracked_objects::ScopedTracker tracking_profile1(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "465796 FrameTreeNode::DidStopLoading::Start"));
+
+ // Set final load progress and update overall progress. This will notify
+ // the WebContents of the load progress change.
+ DidChangeLoadProgress(kLoadingProgressDone);
+
+ // TODO(erikchen): Remove ScopedTracker below once crbug.com/465796 is fixed.
+ tracked_objects::ScopedTracker tracking_profile2(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "465796 FrameTreeNode::DidStopLoading::WCIDidStopLoading"));
+
+ // Notify the WebContents.
+ if (!frame_tree_->IsLoading())
+ navigator()->GetDelegate()->DidStopLoading();
+
+ // TODO(erikchen): Remove ScopedTracker below once crbug.com/465796 is fixed.
+ tracked_objects::ScopedTracker tracking_profile3(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "465796 FrameTreeNode::DidStopLoading::RFHMDidStopLoading"));
+
+ // Notify the RenderFrameHostManager of the event.
+ render_manager()->OnDidStopLoading();
+
+ // TODO(erikchen): Remove ScopedTracker below once crbug.com/465796 is fixed.
+ tracked_objects::ScopedTracker tracking_profile4(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "465796 FrameTreeNode::DidStopLoading::End"));
+}
+
+void FrameTreeNode::DidChangeLoadProgress(double load_progress) {
+ loading_progress_ = load_progress;
+ frame_tree_->UpdateLoadProgress();
+}
+
} // namespace content
diff --git a/chromium/content/browser/frame_host/frame_tree_node.h b/chromium/content/browser/frame_host/frame_tree_node.h
index 5974fd29bf5..4e985592823 100644
--- a/chromium/content/browser/frame_host/frame_tree_node.h
+++ b/chromium/content/browser/frame_host/frame_tree_node.h
@@ -14,11 +14,14 @@
#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/frame_host/render_frame_host_manager.h"
#include "content/common/content_export.h"
+#include "content/common/frame_replication_state.h"
#include "url/gurl.h"
+#include "url/origin.h"
namespace content {
class FrameTree;
+class NavigationRequest;
class Navigator;
class RenderFrameHostImpl;
@@ -28,6 +31,9 @@ class RenderFrameHostImpl;
// are frame-specific (as opposed to page-specific).
class CONTENT_EXPORT FrameTreeNode {
public:
+ // Returns the FrameTreeNode with the given global |frame_tree_node_id|,
+ // regardless of which FrameTree it is in.
+ static FrameTreeNode* GloballyFindByID(int frame_tree_node_id);
FrameTreeNode(FrameTree* frame_tree,
Navigator* navigator,
@@ -35,7 +41,8 @@ class CONTENT_EXPORT FrameTreeNode {
RenderViewHostDelegate* render_view_delegate,
RenderWidgetHostDelegate* render_widget_delegate,
RenderFrameHostManager::Delegate* manager_delegate,
- const std::string& name);
+ const std::string& name,
+ SandboxFlags sandbox_flags);
~FrameTreeNode();
@@ -61,12 +68,12 @@ class CONTENT_EXPORT FrameTreeNode {
return &render_manager_;
}
- int64 frame_tree_node_id() const {
+ int frame_tree_node_id() const {
return frame_tree_node_id_;
}
const std::string& frame_name() const {
- return frame_name_;
+ return replication_state_.name;
}
size_t child_count() const {
@@ -87,15 +94,85 @@ class CONTENT_EXPORT FrameTreeNode {
current_url_ = url;
}
+ // Set the current origin and notify proxies about the update.
+ void SetCurrentOrigin(const url::Origin& origin);
+
+ // Set the current name and notify proxies about the update.
+ void SetFrameName(const std::string& name);
+
+ SandboxFlags effective_sandbox_flags() { return effective_sandbox_flags_; }
+
+ void set_sandbox_flags(SandboxFlags sandbox_flags) {
+ replication_state_.sandbox_flags = sandbox_flags;
+ }
+
+ // Transfer any pending sandbox flags into |effective_sandbox_flags_|, and
+ // return true if the sandbox flags were changed.
+ bool CommitPendingSandboxFlags();
+
+ bool HasSameOrigin(const FrameTreeNode& node) const {
+ return replication_state_.origin.IsSameAs(node.replication_state_.origin);
+ }
+
+ const FrameReplicationState& current_replication_state() const {
+ return replication_state_;
+ }
+
RenderFrameHostImpl* current_frame_host() const {
return render_manager_.current_frame_host();
}
+ bool IsDescendantOf(FrameTreeNode* other) const;
+
+ // Return the node immediately preceding this node in its parent's
+ // |children_|, or nullptr if there is no such node.
+ FrameTreeNode* PreviousSibling() const;
+
+ // Returns true if this node is in a loading state.
+ bool IsLoading() const;
+
+ // Returns this node's loading progress.
+ double loading_progress() const { return loading_progress_; }
+
+ NavigationRequest* navigation_request() { return navigation_request_.get(); }
+
+ // PlzNavigate
+ // Takes ownership of |navigation_request| and makes it the current
+ // NavigationRequest of this frame. This corresponds to the start of a new
+ // navigation. If there was an ongoing navigation request before calling this
+ // function, it is canceled. |navigation_request| should not be null.
+ void SetNavigationRequest(scoped_ptr<NavigationRequest> navigation_request);
+
+ // PlzNavigate
+ // Resets the current navigation request. |is_commit| is true if the reset is
+ // due to the commit of the navigation.
+ void ResetNavigationRequest(bool is_commit);
+
+ // Returns true if this node is in a state where the loading progress is being
+ // tracked.
+ bool has_started_loading() const;
+
+ // Resets this node's loading progress.
+ void reset_loading_progress();
+
+ // A RenderFrameHost in this node started loading.
+ // |to_different_document| will be true unless the load is a fragment
+ // navigation, or triggered by history.pushState/replaceState.
+ void DidStartLoading(bool to_different_document);
+
+ // A RenderFrameHost in this node stopped loading.
+ void DidStopLoading();
+
+ // The load progress for a RenderFrameHost in this node was updated to
+ // |load_progress|. This will notify the FrameTree which will in turn notify
+ // the WebContents.
+ void DidChangeLoadProgress(double load_progress);
+
private:
void set_parent(FrameTreeNode* parent) { parent_ = parent; }
// The next available browser-global FrameTreeNode ID.
- static int64 next_frame_tree_node_id_;
+ static int next_frame_tree_node_id_;
// The FrameTree that owns us.
FrameTree* frame_tree_; // not owned.
@@ -106,17 +183,13 @@ class CONTENT_EXPORT FrameTreeNode {
// Manages creation and swapping of RenderFrameHosts for this frame. This
// must be declared before |children_| so that it gets deleted after them.
- // That's currently necessary so that RenderFrameHostImpl's destructor can
+ // That's currently necessary so that RenderFrameHostImpl's destructor can
// call GetProcess.
RenderFrameHostManager render_manager_;
// A browser-global identifier for the frame in the page, which stays stable
// even if the frame does a cross-process navigation.
- const int64 frame_tree_node_id_;
-
- // The assigned name of the frame. This name can be empty, unlike the unique
- // name generated internally in the DOM tree.
- std::string frame_name_;
+ const int frame_tree_node_id_;
// The parent node of this frame. NULL if this node is the root or if it has
// not yet been attached to the frame tree.
@@ -131,6 +204,28 @@ class CONTENT_EXPORT FrameTreeNode {
// NavigationController.
GURL current_url_;
+ // Track information that needs to be replicated to processes that have
+ // proxies for this frame.
+ FrameReplicationState replication_state_;
+
+ // Track the effective sandbox flags for this frame. When a parent frame
+ // dynamically updates sandbox flags for a child frame, the child's updated
+ // sandbox flags are stored in replication_state_.sandbox_flags. However, the
+ // update only takes effect on the next frame navigation, so the effective
+ // sandbox flags are tracked separately here. When enforcing sandbox flags
+ // directives in the browser process, |effective_sandbox_flags_| should be
+ // used. |effective_sandbox_flags_| is updated with any pending sandbox
+ // flags when a navigation for this frame commits.
+ SandboxFlags effective_sandbox_flags_;
+
+ // Used to track this node's loading progress (from 0 to 1).
+ double loading_progress_;
+
+ // PlzNavigate
+ // Owns an ongoing NavigationRequest until it is ready to commit. It will then
+ // be reset and a RenderFrameHost will be responsible for the navigation.
+ scoped_ptr<NavigationRequest> navigation_request_;
+
DISALLOW_COPY_AND_ASSIGN(FrameTreeNode);
};
diff --git a/chromium/content/browser/frame_host/frame_tree_unittest.cc b/chromium/content/browser/frame_host/frame_tree_unittest.cc
index bb705c7f881..96f6b4d9466 100644
--- a/chromium/content/browser/frame_host/frame_tree_unittest.cc
+++ b/chromium/content/browser/frame_host/frame_tree_unittest.cc
@@ -11,7 +11,7 @@
#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
-#include "content/common/view_messages.h"
+#include "content/common/frame_messages.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/test/mock_render_process_host.h"
#include "content/public/test/test_browser_context.h"
@@ -29,6 +29,9 @@ namespace {
void AppendTreeNodeState(FrameTreeNode* node, std::string* result) {
result->append(
base::Int64ToString(node->current_frame_host()->GetRoutingID()));
+ if (!node->current_frame_host()->IsRenderFrameLive())
+ result->append("*"); // Asterisk next to dead frames.
+
if (!node->frame_name().empty()) {
result->append(" '");
result->append(node->frame_name());
@@ -70,8 +73,8 @@ class TreeWalkingWebContentsLogger : public WebContentsObserver {
void RenderFrameHostChanged(RenderFrameHost* old_host,
RenderFrameHost* new_host) override {
if (old_host)
- LogWhatHappened("RenderFrameChanged(old)", old_host);
- LogWhatHappened("RenderFrameChanged(new)", new_host);
+ LogWhatHappened("RenderFrameHostChanged(old)", old_host);
+ LogWhatHappened("RenderFrameHostChanged(new)", new_host);
}
void RenderFrameDeleted(RenderFrameHost* render_frame_host) override {
@@ -118,7 +121,13 @@ class FrameTreeTest : public RenderViewHostImplTestHarness {
// Exercise tree manipulation routines.
// - Add a series of nodes and verify tree structure.
// - Remove a series of nodes and verify tree structure.
-TEST_F(FrameTreeTest, Shape) {
+//
+// TODO(nick): http://crbug.com/444722 Disabled temporarily because of a bad
+// interaction with the WebContentsObserverConsistencyChecker -- calling
+// AddFrame directly causes the RFH to not be announced. We either need to
+// rewrite this test, or be consistent in the layer at which we announce render
+// frame creation.
+TEST_F(FrameTreeTest, DISABLED_Shape) {
// Use the FrameTree of the WebContents so that it has all the delegates it
// needs. We may want to consider a test version of this.
FrameTree* frame_tree = contents()->GetFrameTree();
@@ -131,13 +140,19 @@ TEST_F(FrameTreeTest, Shape) {
ASSERT_EQ("1: []", GetTreeState(frame_tree));
// Simulate attaching a series of frames to build the frame tree.
- 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), 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());
+ frame_tree->AddFrame(root, process_id, 14, std::string(),
+ SandboxFlags::NONE);
+ frame_tree->AddFrame(root, process_id, 15, std::string(),
+ SandboxFlags::NONE);
+ frame_tree->AddFrame(root, process_id, 16, std::string(),
+ SandboxFlags::NONE);
+
+ frame_tree->AddFrame(root->child_at(0), process_id, 244, std::string(),
+ SandboxFlags::NONE);
+ frame_tree->AddFrame(root->child_at(1), process_id, 255, no_children_node,
+ SandboxFlags::NONE);
+ frame_tree->AddFrame(root->child_at(0), process_id, 245, std::string(),
+ SandboxFlags::NONE);
ASSERT_EQ("1: [14: [244: [], 245: []], "
"15: [255 'no children node': []], "
@@ -145,19 +160,26 @@ TEST_F(FrameTreeTest, Shape) {
GetTreeState(frame_tree));
FrameTreeNode* child_16 = root->child_at(2);
- 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());
+ frame_tree->AddFrame(child_16, process_id, 264, std::string(),
+ SandboxFlags::NONE);
+ frame_tree->AddFrame(child_16, process_id, 265, std::string(),
+ SandboxFlags::NONE);
+ frame_tree->AddFrame(child_16, process_id, 266, std::string(),
+ SandboxFlags::NONE);
+ frame_tree->AddFrame(child_16, process_id, 267, deep_subtree,
+ SandboxFlags::NONE);
+ frame_tree->AddFrame(child_16, process_id, 268, std::string(),
+ SandboxFlags::NONE);
FrameTreeNode* child_267 = child_16->child_at(3);
- 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, process_id, 365, std::string(),
+ SandboxFlags::NONE);
+ frame_tree->AddFrame(child_267->child_at(0), process_id, 455, std::string(),
+ SandboxFlags::NONE);
frame_tree->AddFrame(child_267->child_at(0)->child_at(0), process_id, 555,
- std::string());
+ std::string(), SandboxFlags::NONE);
frame_tree->AddFrame(child_267->child_at(0)->child_at(0)->child_at(0),
- process_id, 655, std::string());
+ process_id, 655, std::string(), SandboxFlags::NONE);
// Now that's it's fully built, verify the tree structure is as expected.
ASSERT_EQ("1: [14: [244: [], 245: []], "
@@ -192,20 +214,94 @@ TEST_F(FrameTreeTest, Shape) {
GetTreeState(frame_tree));
}
+// Ensure frames can be found by frame_tree_node_id, routing ID, or name.
+TEST_F(FrameTreeTest, FindFrames) {
+ // Add a few child frames to the main frame.
+ FrameTree* frame_tree = contents()->GetFrameTree();
+ FrameTreeNode* root = frame_tree->root();
+ main_test_rfh()->OnCreateChildFrame(22, "child0", SandboxFlags::NONE);
+ main_test_rfh()->OnCreateChildFrame(23, "child1", SandboxFlags::NONE);
+ main_test_rfh()->OnCreateChildFrame(24, std::string(), SandboxFlags::NONE);
+ FrameTreeNode* child0 = root->child_at(0);
+ FrameTreeNode* child1 = root->child_at(1);
+ FrameTreeNode* child2 = root->child_at(2);
+
+ // Add one grandchild frame.
+ child1->current_frame_host()->OnCreateChildFrame(33, "grandchild",
+ SandboxFlags::NONE);
+ FrameTreeNode* grandchild = child1->child_at(0);
+
+ // Ensure they can be found by FTN id.
+ EXPECT_EQ(root, frame_tree->FindByID(root->frame_tree_node_id()));
+ EXPECT_EQ(child0, frame_tree->FindByID(child0->frame_tree_node_id()));
+ EXPECT_EQ(child1, frame_tree->FindByID(child1->frame_tree_node_id()));
+ EXPECT_EQ(child2, frame_tree->FindByID(child2->frame_tree_node_id()));
+ EXPECT_EQ(grandchild, frame_tree->FindByID(grandchild->frame_tree_node_id()));
+ EXPECT_EQ(nullptr, frame_tree->FindByID(-1));
+
+ // Ensure they can be found by routing id.
+ int process_id = main_test_rfh()->GetProcess()->GetID();
+ EXPECT_EQ(root, frame_tree->FindByRoutingID(process_id,
+ main_test_rfh()->GetRoutingID()));
+ EXPECT_EQ(child0, frame_tree->FindByRoutingID(process_id, 22));
+ EXPECT_EQ(child1, frame_tree->FindByRoutingID(process_id, 23));
+ EXPECT_EQ(child2, frame_tree->FindByRoutingID(process_id, 24));
+ EXPECT_EQ(grandchild, frame_tree->FindByRoutingID(process_id, 33));
+ EXPECT_EQ(nullptr, frame_tree->FindByRoutingID(process_id, 37));
+
+ // Ensure they can be found by name, if they have one.
+ EXPECT_EQ(root, frame_tree->FindByName(std::string()));
+ EXPECT_EQ(child0, frame_tree->FindByName("child0"));
+ EXPECT_EQ(child1, frame_tree->FindByName("child1"));
+ EXPECT_EQ(grandchild, frame_tree->FindByName("grandchild"));
+ EXPECT_EQ(nullptr, frame_tree->FindByName("no such frame"));
+}
+
+// Check that PreviousSibling() is retrieved correctly.
+TEST_F(FrameTreeTest, PreviousSibling) {
+ // Add a few child frames to the main frame.
+ FrameTree* frame_tree = contents()->GetFrameTree();
+ FrameTreeNode* root = frame_tree->root();
+ main_test_rfh()->OnCreateChildFrame(22, "child0", SandboxFlags::NONE);
+ main_test_rfh()->OnCreateChildFrame(23, "child1", SandboxFlags::NONE);
+ main_test_rfh()->OnCreateChildFrame(24, "child2", SandboxFlags::NONE);
+ FrameTreeNode* child0 = root->child_at(0);
+ FrameTreeNode* child1 = root->child_at(1);
+ FrameTreeNode* child2 = root->child_at(2);
+
+ // Add one grandchild frame.
+ child1->current_frame_host()->OnCreateChildFrame(33, "grandchild",
+ SandboxFlags::NONE);
+ FrameTreeNode* grandchild = child1->child_at(0);
+
+ EXPECT_EQ(nullptr, root->PreviousSibling());
+ EXPECT_EQ(nullptr, child0->PreviousSibling());
+ EXPECT_EQ(child0, child1->PreviousSibling());
+ EXPECT_EQ(child1, child2->PreviousSibling());
+ EXPECT_EQ(nullptr, grandchild->PreviousSibling());
+}
+
// Do some simple manipulations of the frame tree, making sure that
// WebContentsObservers see a consistent view of the tree as we go.
TEST_F(FrameTreeTest, ObserverWalksTreeDuringFrameCreation) {
TreeWalkingWebContentsLogger activity(contents());
+ contents()->NavigateAndCommit(GURL("http://www.google.com"));
+ EXPECT_EQ("", activity.GetLog());
+
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());
- main_test_rfh()->OnCreateChildFrame(18, std::string());
- EXPECT_EQ("RenderFrameCreated(18) -> 1: [14: [], 18: []]", activity.GetLog());
+ main_test_rfh()->OnCreateChildFrame(14, std::string(), SandboxFlags::NONE);
+ EXPECT_EQ(
+ "RenderFrameHostChanged(new)(14) -> 1: []\n"
+ "RenderFrameCreated(14) -> 1: [14: []]",
+ activity.GetLog());
+ main_test_rfh()->OnCreateChildFrame(18, std::string(), SandboxFlags::NONE);
+ EXPECT_EQ(
+ "RenderFrameHostChanged(new)(18) -> 1: [14: []]\n"
+ "RenderFrameCreated(18) -> 1: [14: [], 18: []]",
+ activity.GetLog());
frame_tree->RemoveFrame(root->child_at(0));
EXPECT_EQ("RenderFrameDeleted(14) -> 1: [18: []]", activity.GetLog());
frame_tree->RemoveFrame(root->child_at(0));
@@ -216,25 +312,34 @@ TEST_F(FrameTreeTest, ObserverWalksTreeDuringFrameCreation) {
// recovery from a render process crash.
TEST_F(FrameTreeTest, ObserverWalksTreeAfterCrash) {
TreeWalkingWebContentsLogger activity(contents());
+ contents()->NavigateAndCommit(GURL("http://www.google.com"));
+ EXPECT_EQ("", activity.GetLog());
- main_test_rfh()->OnCreateChildFrame(22, std::string());
- EXPECT_EQ("RenderFrameCreated(22) -> 1: [22: []]", activity.GetLog());
- main_test_rfh()->OnCreateChildFrame(23, std::string());
- EXPECT_EQ("RenderFrameCreated(23) -> 1: [22: [], 23: []]", activity.GetLog());
+ main_test_rfh()->OnCreateChildFrame(22, std::string(), SandboxFlags::NONE);
+ EXPECT_EQ(
+ "RenderFrameHostChanged(new)(22) -> 1: []\n"
+ "RenderFrameCreated(22) -> 1: [22: []]",
+ activity.GetLog());
+ main_test_rfh()->OnCreateChildFrame(23, std::string(), SandboxFlags::NONE);
+ EXPECT_EQ(
+ "RenderFrameHostChanged(new)(23) -> 1: [22: []]\n"
+ "RenderFrameCreated(23) -> 1: [22: [], 23: []]",
+ activity.GetLog());
// Crash the renderer
- test_rvh()->OnMessageReceived(ViewHostMsg_RenderProcessGone(
- 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
+ main_test_rfh()->GetProcess()->SimulateCrash();
EXPECT_EQ(
- "RenderFrameDeleted(22) -> 1: []\n"
- "RenderFrameDeleted(23) -> 1: []\n"
- "RenderProcessGone -> 1: []",
+ "RenderFrameDeleted(23) -> 1: [22: [], 23*: []]\n"
+ "RenderFrameDeleted(22) -> 1: [22*: [], 23*: []]\n"
+ "RenderFrameDeleted(1) -> 1: []\n" // TODO(nick): Should be "1*:"
+ "RenderProcessGone -> 1*: []",
activity.GetLog());
}
// 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) {
+ contents()->NavigateAndCommit(GURL("http://www.google.com"));
FrameTree* frame_tree = contents()->GetFrameTree();
FrameTreeNode* root = frame_tree->root();
int process_id = root->current_frame_host()->GetProcess()->GetID();
@@ -242,8 +347,39 @@ TEST_F(FrameTreeTest, FailAddFrameWithWrongProcessId) {
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_FALSE(frame_tree->AddFrame(root, process_id + 1, 1, std::string(),
+ SandboxFlags::NONE));
ASSERT_EQ("1: []", GetTreeState(frame_tree));
}
+// Ensure that frames removed while a process has crashed are not preserved in
+// the global map of id->frame.
+TEST_F(FrameTreeTest, ProcessCrashClearsGlobalMap) {
+ // Add a couple child frames to the main frame.
+ FrameTreeNode* root = contents()->GetFrameTree()->root();
+
+ main_test_rfh()->OnCreateChildFrame(22, std::string(), SandboxFlags::NONE);
+ main_test_rfh()->OnCreateChildFrame(23, std::string(), SandboxFlags::NONE);
+
+ // Add one grandchild frame.
+ RenderFrameHostImpl* child1_rfh = root->child_at(0)->current_frame_host();
+ child1_rfh->OnCreateChildFrame(33, std::string(), SandboxFlags::NONE);
+
+ // Ensure they can be found by id.
+ int id1 = root->child_at(0)->frame_tree_node_id();
+ int id2 = root->child_at(1)->frame_tree_node_id();
+ int id3 = root->child_at(0)->child_at(0)->frame_tree_node_id();
+ EXPECT_TRUE(FrameTreeNode::GloballyFindByID(id1));
+ EXPECT_TRUE(FrameTreeNode::GloballyFindByID(id2));
+ EXPECT_TRUE(FrameTreeNode::GloballyFindByID(id3));
+
+ // Crash the renderer.
+ main_test_rfh()->GetProcess()->SimulateCrash();
+
+ // Ensure they cannot be found by id after the process has crashed.
+ EXPECT_FALSE(FrameTreeNode::GloballyFindByID(id1));
+ EXPECT_FALSE(FrameTreeNode::GloballyFindByID(id2));
+ EXPECT_FALSE(FrameTreeNode::GloballyFindByID(id3));
+}
+
} // 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 72fd2043faf..455ac74ebe6 100644
--- a/chromium/content/browser/frame_host/interstitial_page_impl.cc
+++ b/chromium/content/browser/frame_host/interstitial_page_impl.cc
@@ -245,7 +245,6 @@ void InterstitialPageImpl::Show() {
DCHECK(!render_view_host_);
render_view_host_ = CreateRenderViewHost();
- render_view_host_->AttachToFrameTree();
CreateWebContentsView();
std::string data_url = "data:text/html;charset=utf-8," +
@@ -295,11 +294,11 @@ void InterstitialPageImpl::Hide() {
base::Bind(&InterstitialPageImpl::Shutdown,
weak_ptr_factory_.GetWeakPtr()));
render_view_host_ = NULL;
- frame_tree_.ResetForMainFrameSwap();
+ frame_tree_.root()->ResetForNewProcess();
controller_->delegate()->DetachInterstitialPage();
// Let's revert to the original title if necessary.
NavigationEntry* entry = controller_->GetVisibleEntry();
- if (!new_navigation_ && should_revert_web_contents_title_) {
+ if (entry && !new_navigation_ && should_revert_web_contents_title_) {
entry->SetTitle(original_web_contents_title_);
controller_->delegate()->NotifyNavigationStateChanged(
INVALIDATE_TYPE_TITLE);
@@ -395,15 +394,12 @@ void InterstitialPageImpl::UpdateTitle(
DCHECK(render_view_host == render_view_host_);
NavigationEntry* entry = controller_->GetVisibleEntry();
if (!entry) {
- // Crash reports from the field indicate this can be NULL.
- // This is unexpected as InterstitialPages constructed with the
- // new_navigation flag set to true create a transient navigation entry
- // (that is returned as the active entry). And the only case so far of
- // interstitial created with that flag set to false is with the
- // SafeBrowsingBlockingPage, when the resource triggering the interstitial
- // is a sub-resource, meaning the main page has already been loaded and a
- // navigation entry should have been created.
- NOTREACHED();
+ // There may be no visible entry if no URL has committed (e.g., after
+ // window.open("")). InterstitialPages with the new_navigation flag create
+ // a transient NavigationEntry and thus have a visible entry. However,
+ // interstitials can still be created when there is no visible entry. For
+ // example, the opener window may inject content into the initial blank
+ // page, which might trigger a SafeBrowsingBlockingPage.
return;
}
@@ -486,8 +482,7 @@ void InterstitialPageImpl::DidNavigate(
// as complete. Without this, navigating in a UI test to a URL that triggers
// an interstitial would hang.
web_contents_was_loading_ = controller_->delegate()->IsLoading();
- controller_->delegate()->SetIsLoading(
- controller_->delegate()->GetRenderViewHost(), false, true, NULL);
+ controller_->delegate()->SetIsLoading(false, true, NULL);
}
RendererPreferences InterstitialPageImpl::GetRendererPrefs(
@@ -496,13 +491,6 @@ RendererPreferences InterstitialPageImpl::GetRendererPrefs(
return renderer_preferences_;
}
-WebPreferences InterstitialPageImpl::ComputeWebkitPrefs() {
- if (!enabled())
- return WebPreferences();
-
- return render_view_host_->ComputeWebkitPrefs(url_);
-}
-
void InterstitialPageImpl::RenderWidgetDeleted(
RenderWidgetHostImpl* render_widget_host) {
// TODO(creis): Remove this method once we verify the shutdown path is sane.
@@ -601,8 +589,7 @@ void InterstitialPageImpl::Proceed() {
// Resumes the throbber, if applicable.
if (web_contents_was_loading_)
- controller_->delegate()->SetIsLoading(
- controller_->delegate()->GetRenderViewHost(), true, true, NULL);
+ controller_->delegate()->SetIsLoading(true, true, NULL);
// If this is a new navigation, the old page is going away, so we cancel any
// blocked requests for it. If it is not a new navigation, then it means the
@@ -704,15 +691,9 @@ RenderWidgetHostView* InterstitialPageImpl::GetView() {
return render_view_host_->GetView();
}
-RenderViewHost* InterstitialPageImpl::GetRenderViewHostForTesting() const {
- return render_view_host_;
-}
-
-#if defined(OS_ANDROID)
-RenderViewHost* InterstitialPageImpl::GetRenderViewHost() const {
- return render_view_host_;
+RenderFrameHost* InterstitialPageImpl::GetMainFrame() const {
+ return render_view_host_->GetMainFrame();
}
-#endif
InterstitialPageDelegate* InterstitialPageImpl::GetDelegateForTesting() {
return delegate_.get();
@@ -749,13 +730,13 @@ void InterstitialPageImpl::CreateNewFullscreenWidget(int render_process_id,
void InterstitialPageImpl::ShowCreatedWindow(int route_id,
WindowOpenDisposition disposition,
- const gfx::Rect& initial_pos,
+ const gfx::Rect& initial_rect,
bool user_gesture) {
NOTREACHED() << "InterstitialPage does not support showing popups yet.";
}
void InterstitialPageImpl::ShowCreatedWidget(int route_id,
- const gfx::Rect& initial_pos) {
+ const gfx::Rect& initial_rect) {
NOTREACHED() << "InterstitialPage does not support showing drop-downs yet.";
}
@@ -797,8 +778,7 @@ void InterstitialPageImpl::OnNavigatingAwayOrTabClosing() {
void InterstitialPageImpl::TakeActionOnResourceDispatcher(
ResourceRequestAction action) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)) <<
- "TakeActionOnResourceDispatcher should be called on the main thread.";
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (action == CANCEL || action == RESUME) {
if (resource_dispatcher_host_notified_)
@@ -883,8 +863,8 @@ void InterstitialPageImpl::InterstitialPageRVHDelegateView::UpdateDragCursor(
void InterstitialPageImpl::InterstitialPageRVHDelegateView::GotFocus() {
WebContents* web_contents = interstitial_page_->web_contents();
- if (web_contents && web_contents->GetDelegate())
- web_contents->GetDelegate()->WebContentsFocused(web_contents);
+ if (web_contents)
+ static_cast<WebContentsImpl*>(web_contents)->NotifyWebContentsFocused();
}
void InterstitialPageImpl::InterstitialPageRVHDelegateView::TakeFocus(
diff --git a/chromium/content/browser/frame_host/interstitial_page_impl.h b/chromium/content/browser/frame_host/interstitial_page_impl.h
index 9f6ce8445aa..a509c1b69da 100644
--- a/chromium/content/browser/frame_host/interstitial_page_impl.h
+++ b/chromium/content/browser/frame_host/interstitial_page_impl.h
@@ -61,7 +61,7 @@ class CONTENT_EXPORT InterstitialPageImpl
void Hide() override;
void DontProceed() override;
void Proceed() override;
- RenderViewHost* GetRenderViewHostForTesting() const override;
+ RenderFrameHost* GetMainFrame() const override;
InterstitialPageDelegate* GetDelegateForTesting() override;
void DontCreateViewForTesting() override;
void SetSize(const gfx::Size& size) override;
@@ -84,12 +84,6 @@ class CONTENT_EXPORT InterstitialPageImpl
}
bool reload_on_dont_proceed() const { return reload_on_dont_proceed_; }
-#if defined(OS_ANDROID)
- // Android shares a single platform window for all tabs, so we need to expose
- // the RenderViewHost to properly route gestures to the interstitial.
- RenderViewHost* GetRenderViewHost() const;
-#endif
-
// TODO(nasko): This should move to InterstitialPageNavigatorImpl, but in
// the meantime make it public, so it can be called directly.
void DidNavigate(
@@ -122,7 +116,6 @@ class CONTENT_EXPORT InterstitialPageImpl
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,
@@ -136,9 +129,9 @@ class CONTENT_EXPORT InterstitialPageImpl
void CreateNewFullscreenWidget(int render_process_id, int route_id) override;
void ShowCreatedWindow(int route_id,
WindowOpenDisposition disposition,
- const gfx::Rect& initial_pos,
+ const gfx::Rect& initial_rect,
bool user_gesture) override;
- void ShowCreatedWidget(int route_id, const gfx::Rect& initial_pos) override;
+ void ShowCreatedWidget(int route_id, const gfx::Rect& initial_rect) override;
void ShowCreatedFullscreenWidget(int route_id) override;
SessionStorageNamespace* GetSessionStorageNamespace(
@@ -152,7 +145,7 @@ class CONTENT_EXPORT InterstitialPageImpl
bool* is_keyboard_shortcut) override;
void HandleKeyboardEvent(const NativeWebKeyboardEvent& event) override;
#if defined(OS_WIN)
- virtual gfx::NativeViewAccessible GetParentNativeViewAccessible() override;
+ gfx::NativeViewAccessible GetParentNativeViewAccessible() override;
#endif
bool enabled() const { return enabled_; }
diff --git a/chromium/content/browser/frame_host/interstitial_page_navigator_impl.cc b/chromium/content/browser/frame_host/interstitial_page_navigator_impl.cc
index fc45950742d..8b1a3a6865f 100644
--- a/chromium/content/browser/frame_host/interstitial_page_navigator_impl.cc
+++ b/chromium/content/browser/frame_host/interstitial_page_navigator_impl.cc
@@ -17,6 +17,10 @@ InterstitialPageNavigatorImpl::InterstitialPageNavigatorImpl(
: interstitial_(interstitial),
controller_(navigation_controller) {}
+NavigatorDelegate* InterstitialPageNavigatorImpl::GetDelegate() {
+ return interstitial_;
+}
+
NavigationController* InterstitialPageNavigatorImpl::GetController() {
return controller_;
}
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 2f9661440c0..8a8621912af 100644
--- a/chromium/content/browser/frame_host/interstitial_page_navigator_impl.h
+++ b/chromium/content/browser/frame_host/interstitial_page_navigator_impl.h
@@ -22,6 +22,7 @@ class CONTENT_EXPORT InterstitialPageNavigatorImpl : public Navigator {
InterstitialPageImpl* interstitial,
NavigationControllerImpl* navigation_controller);
+ NavigatorDelegate* GetDelegate() override;
NavigationController* GetController() override;
void DidNavigate(RenderFrameHostImpl* render_frame_host,
const FrameHostMsg_DidCommitProvisionalLoad_Params&
diff --git a/chromium/content/browser/frame_host/navigation_controller_android.cc b/chromium/content/browser/frame_host/navigation_controller_android.cc
index 52ef78ee5d1..686403eb651 100644
--- a/chromium/content/browser/frame_host/navigation_controller_android.cc
+++ b/chromium/content/browser/frame_host/navigation_controller_android.cc
@@ -49,7 +49,8 @@ static base::android::ScopedJavaLocalRef<jobject> CreateJavaNavigationEntry(
j_virtual_url.obj(),
j_original_url.obj(),
j_title.obj(),
- j_bitmap.obj());
+ j_bitmap.obj(),
+ entry->GetTransitionType());
}
static void AddNavigationEntryToHistory(JNIEnv* env,
@@ -118,6 +119,11 @@ void NavigationControllerAndroid::GoToOffset(JNIEnv* env,
navigation_controller_->GoToOffset(offset);
}
+jboolean NavigationControllerAndroid::IsInitialNavigation(JNIEnv* env,
+ jobject obj) {
+ return navigation_controller_->IsInitialNavigation();
+}
+
void NavigationControllerAndroid::LoadIfNecessary(JNIEnv* env, jobject obj) {
navigation_controller_->LoadIfNecessary();
}
@@ -301,6 +307,18 @@ void NavigationControllerAndroid::SetUseDesktopUserAgent(
}
base::android::ScopedJavaLocalRef<jobject>
+NavigationControllerAndroid::GetEntryAtIndex(JNIEnv* env,
+ jobject obj,
+ int index) {
+ if (index < 0 || index >= navigation_controller_->GetEntryCount())
+ return base::android::ScopedJavaLocalRef<jobject>();
+
+ content::NavigationEntry* entry =
+ navigation_controller_->GetEntryAtIndex(index);
+ return CreateJavaNavigationEntry(env, entry, index);
+}
+
+base::android::ScopedJavaLocalRef<jobject>
NavigationControllerAndroid::GetPendingEntry(JNIEnv* env, jobject obj) {
content::NavigationEntry* entry = navigation_controller_->GetPendingEntry();
@@ -322,4 +340,35 @@ jboolean NavigationControllerAndroid::RemoveEntryAtIndex(JNIEnv* env,
return navigation_controller_->RemoveEntryAtIndex(index);
}
+jboolean NavigationControllerAndroid::CanCopyStateOver(JNIEnv* env,
+ jobject obj) {
+ return navigation_controller_->GetEntryCount() == 0 &&
+ !navigation_controller_->GetPendingEntry();
+}
+
+jboolean NavigationControllerAndroid::CanPruneAllButLastCommitted(JNIEnv* env,
+ jobject obj) {
+ return navigation_controller_->CanPruneAllButLastCommitted();
+}
+
+void NavigationControllerAndroid::CopyStateFrom(
+ JNIEnv* env,
+ jobject obj,
+ jlong source_navigation_controller_android) {
+ navigation_controller_->CopyStateFrom(
+ *(reinterpret_cast<NavigationControllerAndroid*>(
+ source_navigation_controller_android)->navigation_controller_));
+}
+
+void NavigationControllerAndroid::CopyStateFromAndPrune(
+ JNIEnv* env,
+ jobject obj,
+ jlong source_navigation_controller_android,
+ jboolean replace_entry) {
+ navigation_controller_->CopyStateFromAndPrune(
+ reinterpret_cast<NavigationControllerAndroid*>(
+ source_navigation_controller_android)->navigation_controller_,
+ replace_entry);
+}
+
} // 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 9b9a8c67062..0d67d1c13c2 100644
--- a/chromium/content/browser/frame_host/navigation_controller_android.h
+++ b/chromium/content/browser/frame_host/navigation_controller_android.h
@@ -39,6 +39,7 @@ class CONTENT_EXPORT NavigationControllerAndroid {
void GoBack(JNIEnv* env, jobject obj);
void GoForward(JNIEnv* env, jobject obj);
void GoToOffset(JNIEnv* env, jobject obj, jint offset);
+ jboolean IsInitialNavigation(JNIEnv* env, jobject obj);
void LoadIfNecessary(JNIEnv* env, jobject obj);
void ContinuePendingReload(JNIEnv* env, jobject obj);
void Reload(JNIEnv* env, jobject obj, jboolean check_for_repost);
@@ -66,6 +67,9 @@ class CONTENT_EXPORT NavigationControllerAndroid {
jobject /* obj */,
jboolean state,
jboolean reload_on_state_change);
+ base::android::ScopedJavaLocalRef<jobject> GetEntryAtIndex(JNIEnv* env,
+ jobject obj,
+ int index);
base::android::ScopedJavaLocalRef<jobject> GetPendingEntry(JNIEnv* env,
jobject /* obj */);
int GetNavigationHistory(JNIEnv* env, jobject obj, jobject history);
@@ -79,6 +83,15 @@ class CONTENT_EXPORT NavigationControllerAndroid {
void ClearHistory(JNIEnv* env, jobject obj);
int GetLastCommittedEntryIndex(JNIEnv* env, jobject obj);
jboolean RemoveEntryAtIndex(JNIEnv* env, jobject obj, jint index);
+ jboolean CanCopyStateOver(JNIEnv* env, jobject obj);
+ jboolean CanPruneAllButLastCommitted(JNIEnv* env, jobject obj);
+ void CopyStateFrom(JNIEnv* env,
+ jobject obj,
+ jlong source_native_navigation_controller_android);
+ void CopyStateFromAndPrune(JNIEnv* env,
+ jobject obj,
+ jlong source_native_navigation_controller_android,
+ jboolean replace_entry);
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 52567ef3c62..9789689033f 100644
--- a/chromium/content/browser/frame_host/navigation_controller_delegate.h
+++ b/chromium/content/browser/frame_host/navigation_controller_delegate.h
@@ -15,6 +15,7 @@ namespace content {
struct LoadCommittedDetails;
struct LoadNotificationDetails;
struct NativeWebKeyboardEvent;
+class FrameTree;
class InterstitialPage;
class InterstitialPageImpl;
class RenderFrameHost;
@@ -46,15 +47,14 @@ class NavigationControllerDelegate {
// Methods from WebContentsImpl that NavigationControllerImpl needs to
// call.
+ virtual FrameTree* GetFrameTree() = 0;
virtual void NotifyBeforeFormRepostWarningShow() = 0;
virtual void NotifyNavigationEntryCommitted(
const LoadCommittedDetails& load_details) = 0;
virtual bool NavigateToPendingEntry(
NavigationController::ReloadType reload_type) = 0;
- virtual void SetHistoryLengthAndPrune(
- const SiteInstance* site_instance,
- int merge_history_length,
- int32 minimum_page_id) = 0;
+ virtual void SetHistoryOffsetAndLength(int history_offset,
+ int history_length) = 0;
virtual void CopyMaxPageIDsFrom(WebContents* web_contents) = 0;
virtual void UpdateMaxPageID(int32 page_id) = 0;
virtual void UpdateMaxPageIDForSiteInstance(SiteInstance* site_instance,
@@ -73,8 +73,7 @@ class NavigationControllerDelegate {
virtual void AttachInterstitialPage(
InterstitialPageImpl* interstitial_page) = 0;
virtual void DetachInterstitialPage() = 0;
- virtual void SetIsLoading(RenderViewHost* render_view_host,
- bool is_loading,
+ virtual void SetIsLoading(bool is_loading,
bool to_different_document,
LoadNotificationDetails* details) = 0;
};
diff --git a/chromium/content/browser/frame_host/navigation_controller_impl.cc b/chromium/content/browser/frame_host/navigation_controller_impl.cc
index 4be5a3ce4a0..8339b73051b 100644
--- a/chromium/content/browser/frame_host/navigation_controller_impl.cc
+++ b/chromium/content/browser/frame_host/navigation_controller_impl.cc
@@ -6,14 +6,16 @@
#include "base/bind.h"
#include "base/command_line.h"
-#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/strings/string_number_conversions.h" // Temporary
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
#include "cc/base/switches.h"
+#include "components/mime_util/mime_util.h"
+#include "content/browser/bad_message.h"
#include "content/browser/browser_url_handler_impl.h"
#include "content/browser/dom_storage/dom_storage_context_wrapper.h"
#include "content/browser/dom_storage/session_storage_namespace_impl.h"
@@ -37,6 +39,7 @@
#include "content/public/browser/user_metrics.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_constants.h"
+#include "content/public/common/content_switches.h"
#include "net/base/escape.h"
#include "net/base/mime_util.h"
#include "net/base/net_util.h"
@@ -129,9 +132,13 @@ bool AreURLsInPageNavigation(const GURL& existing_url,
// 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();
+ !prefs.web_security_enabled ||
+ (prefs.allow_universal_access_from_file_urls &&
+ existing_url.SchemeIs(url::kFileScheme));
+ if (!is_same_origin && renderer_says_in_page) {
+ bad_message::ReceivedBadMessage(rfh->GetProcess(),
+ bad_message::NC_IN_PAGE_NAVIGATION);
+ }
return is_same_origin && renderer_says_in_page;
}
@@ -163,11 +170,17 @@ NavigationEntry* NavigationController::CreateNavigationEntry(
bool is_renderer_initiated,
const std::string& extra_headers,
BrowserContext* browser_context) {
+ // Fix up the given URL before letting it be rewritten, so that any minor
+ // cleanup (e.g., removing leading dots) will not lead to a virtual URL.
+ GURL dest_url(url);
+ BrowserURLHandlerImpl::GetInstance()->FixupURLBeforeRewrite(&dest_url,
+ browser_context);
+
// Allow the browser URL handler to rewrite the URL. This will, for example,
// remove "view-source:" from the beginning of the URL to get the URL that
// will actually be loaded. This real URL won't be shown to the user, just
// used internally.
- GURL loaded_url(url);
+ GURL loaded_url(dest_url);
bool reverse_on_redirect = false;
BrowserURLHandlerImpl::GetInstance()->RewriteURLIfNecessary(
&loaded_url, browser_context, &reverse_on_redirect);
@@ -181,8 +194,8 @@ NavigationEntry* NavigationController::CreateNavigationEntry(
base::string16(),
transition,
is_renderer_initiated);
- entry->SetVirtualURL(url);
- entry->set_user_typed_url(url);
+ entry->SetVirtualURL(dest_url);
+ entry->set_user_typed_url(dest_url);
entry->set_update_virtual_url_with_url(reverse_on_redirect);
entry->set_extra_headers(extra_headers);
return entry;
@@ -214,6 +227,8 @@ NavigationControllerImpl::NavigationControllerImpl(
BrowserContext* browser_context)
: browser_context_(browser_context),
pending_entry_(NULL),
+ failed_pending_entry_id_(0),
+ failed_pending_entry_should_replace_(false),
last_committed_entry_index_(-1),
pending_entry_index_(-1),
transient_entry_index_(-1),
@@ -282,8 +297,7 @@ void NavigationControllerImpl::ReloadInternal(bool check_for_repost,
if (transient_entry_index_ != -1) {
// If an interstitial is showing, treat a reload as a navigation to the
// transient entry's URL.
- NavigationEntryImpl* transient_entry =
- NavigationEntryImpl::FromNavigationEntry(GetTransientEntry());
+ NavigationEntryImpl* transient_entry = GetTransientEntry();
if (!transient_entry)
return;
LoadURL(transient_entry->GetURL(),
@@ -307,8 +321,7 @@ void NavigationControllerImpl::ReloadInternal(bool check_for_repost,
DiscardNonCommittedEntriesInternal();
current_index = GetCurrentEntryIndex();
if (current_index != -1) {
- entry = NavigationEntryImpl::FromNavigationEntry(
- GetEntryAtIndex(current_index));
+ entry = GetEntryAtIndex(current_index);
}
}
@@ -424,7 +437,7 @@ void NavigationControllerImpl::SetPendingEntry(NavigationEntryImpl* entry) {
Details<NavigationEntry>(entry));
}
-NavigationEntry* NavigationControllerImpl::GetActiveEntry() const {
+NavigationEntryImpl* NavigationControllerImpl::GetActiveEntry() const {
if (transient_entry_index_ != -1)
return entries_[transient_entry_index_].get();
if (pending_entry_)
@@ -432,7 +445,7 @@ NavigationEntry* NavigationControllerImpl::GetActiveEntry() const {
return GetLastCommittedEntry();
}
-NavigationEntry* NavigationControllerImpl::GetVisibleEntry() const {
+NavigationEntryImpl* NavigationControllerImpl::GetVisibleEntry() const {
if (transient_entry_index_ != -1)
return entries_[transient_entry_index_].get();
// The pending entry is safe to return for new (non-history), browser-
@@ -446,7 +459,7 @@ NavigationEntry* NavigationControllerImpl::GetVisibleEntry() const {
bool safe_to_show_pending =
pending_entry_ &&
// Require a new navigation.
- pending_entry_->GetPageID() == -1 &&
+ pending_entry_index_ == -1 &&
// Require either browser-initiated or an unmodified new tab.
(!pending_entry_->is_renderer_initiated() || IsUnmodifiedBlankTab());
@@ -455,7 +468,7 @@ NavigationEntry* NavigationControllerImpl::GetVisibleEntry() const {
// can script the new tab before it commits.
if (!safe_to_show_pending &&
pending_entry_ &&
- pending_entry_->GetPageID() != -1 &&
+ pending_entry_index_ != -1 &&
IsInitialNavigation() &&
!pending_entry_->is_renderer_initiated())
safe_to_show_pending = true;
@@ -473,7 +486,7 @@ int NavigationControllerImpl::GetCurrentEntryIndex() const {
return last_committed_entry_index_;
}
-NavigationEntry* NavigationControllerImpl::GetLastCommittedEntry() const {
+NavigationEntryImpl* NavigationControllerImpl::GetLastCommittedEntry() const {
if (last_committed_entry_index_ == -1)
return NULL;
return entries_[last_committed_entry_index_].get();
@@ -481,7 +494,8 @@ NavigationEntry* NavigationControllerImpl::GetLastCommittedEntry() const {
bool NavigationControllerImpl::CanViewSource() const {
const std::string& mime_type = delegate_->GetContentsMimeType();
- bool is_viewable_mime_type = net::IsSupportedNonImageMimeType(mime_type) &&
+ bool is_viewable_mime_type =
+ mime_util::IsSupportedNonImageMimeType(mime_type) &&
!net::IsSupportedMediaMimeType(mime_type);
NavigationEntry* visible_entry = GetVisibleEntry();
return visible_entry && !visible_entry->IsViewSourceMode() &&
@@ -497,12 +511,12 @@ int NavigationControllerImpl::GetEntryCount() const {
return static_cast<int>(entries_.size());
}
-NavigationEntry* NavigationControllerImpl::GetEntryAtIndex(
+NavigationEntryImpl* NavigationControllerImpl::GetEntryAtIndex(
int index) const {
return entries_.at(index).get();
}
-NavigationEntry* NavigationControllerImpl::GetEntryAtOffset(
+NavigationEntryImpl* NavigationControllerImpl::GetEntryAtOffset(
int offset) const {
int index = GetIndexForOffset(offset);
if (index < 0 || index >= GetEntryCount())
@@ -655,7 +669,7 @@ void NavigationControllerImpl::LoadURLWithParams(const LoadURLParams& params) {
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(
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
cc::switches::kEnableGpuBenchmarking))
return;
}
@@ -719,17 +733,35 @@ void NavigationControllerImpl::LoadURLWithParams(const LoadURLParams& params) {
params.is_renderer_initiated,
params.extra_headers,
browser_context_));
+ if (!params.frame_name.empty()) {
+ // This is only used for navigating subframes in tests.
+ FrameTreeNode* named_frame =
+ delegate_->GetFrameTree()->FindByName(params.frame_name);
+ if (named_frame)
+ entry->set_frame_tree_node_id(named_frame->frame_tree_node_id());
+ }
if (params.frame_tree_node_id != -1)
entry->set_frame_tree_node_id(params.frame_tree_node_id);
+ entry->set_source_site_instance(
+ static_cast<SiteInstanceImpl*>(params.source_site_instance.get()));
if (params.redirect_chain.size() > 0)
entry->SetRedirectChain(params.redirect_chain);
- if (params.should_replace_current_entry)
+ // Don't allow an entry replacement if there is no entry to replace.
+ // http://crbug.com/457149
+ if (params.should_replace_current_entry && entries_.size() > 0)
entry->set_should_replace_entry(true);
entry->set_should_clear_history_list(params.should_clear_history_list);
entry->SetIsOverridingUserAgent(override);
entry->set_transferred_global_request_id(
params.transferred_global_request_id);
- entry->SetFrameToNavigate(params.frame_name);
+
+#if defined(OS_ANDROID)
+ if (params.intent_received_timestamp > 0) {
+ entry->set_intent_received_timestamp(
+ base::TimeTicks() +
+ base::TimeDelta::FromMilliseconds(params.intent_received_timestamp));
+ }
+#endif
switch (params.load_type) {
case LOAD_TYPE_DEFAULT:
@@ -753,7 +785,7 @@ void NavigationControllerImpl::LoadURLWithParams(const LoadURLParams& params) {
}
bool NavigationControllerImpl::RendererDidNavigate(
- RenderFrameHost* rfh,
+ RenderFrameHostImpl* rfh,
const FrameHostMsg_DidCommitProvisionalLoad_Params& params,
LoadCommittedDetails* details) {
is_initial_navigation_ = false;
@@ -774,14 +806,37 @@ bool NavigationControllerImpl::RendererDidNavigate(
// If we are doing a cross-site reload, we need to replace the existing
// navigation entry, not add another entry to the history. This has the side
- // effect of removing forward browsing history, if such existed.
- // Or if we are doing a cross-site redirect navigation,
- // we will do a similar thing.
- details->did_replace_entry =
- pending_entry_ && pending_entry_->should_replace_entry();
+ // effect of removing forward browsing history, if such existed. Or if we are
+ // doing a cross-site redirect navigation, we will do a similar thing.
+ //
+ // If this is an error load, we may have already removed the pending entry
+ // when we got the notice of the load failure. If so, look at the copy of the
+ // pending parameters that were saved.
+ if (params.url_is_unreachable && failed_pending_entry_id_ != 0) {
+ details->did_replace_entry = failed_pending_entry_should_replace_;
+ } else {
+ details->did_replace_entry = pending_entry_ &&
+ pending_entry_->should_replace_entry();
+ }
// Do navigation-type specific actions. These will make and commit an entry.
details->type = ClassifyNavigation(rfh, params);
+#if DCHECK_IS_ON()
+ // For site-per-process, both ClassifyNavigation methods get it wrong (see
+ // http://crbug.com/464014) so don't worry about a mismatch if that's the
+ // case.
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess)) {
+ NavigationType new_type = ClassifyNavigationWithoutPageID(rfh, params);
+ // There's constant disagreements over SAME_PAGE between the two classifiers
+ // so ignore disagreements if that's the case. Otherwise, enforce agreement.
+ // TODO(avi): Work this out.
+ if (details->type != NAVIGATION_TYPE_SAME_PAGE &&
+ new_type != NAVIGATION_TYPE_SAME_PAGE) {
+ DCHECK_EQ(details->type, new_type);
+ }
+ }
+#endif // DCHECK_IS_ON()
// is_in_page must be computed before the entry gets committed.
details->is_in_page = AreURLsInPageNavigation(rfh->GetLastCommittedURL(),
@@ -838,8 +893,7 @@ bool NavigationControllerImpl::RendererDidNavigate(
// All committed entries should have nonempty content state so WebKit doesn't
// get confused when we go back to them (see the function for details).
DCHECK(params.page_state.IsValid());
- NavigationEntryImpl* active_entry =
- NavigationEntryImpl::FromNavigationEntry(GetLastCommittedEntry());
+ NavigationEntryImpl* active_entry = GetLastCommittedEntry();
active_entry->SetTimestamp(timestamp);
active_entry->SetHttpStatusCode(params.http_status_code);
active_entry->SetPageState(params.page_state);
@@ -865,8 +919,7 @@ bool NavigationControllerImpl::RendererDidNavigate(
// Remember the bindings the renderer process has at this point, so that
// we do not grant this entry additional bindings if we come back to it.
- active_entry->SetBindings(
- static_cast<RenderFrameHostImpl*>(rfh)->GetEnabledBindings());
+ active_entry->SetBindings(rfh->GetEnabledBindings());
// Now prep the rest of the details for the notification and broadcast.
details->entry = active_entry;
@@ -880,15 +933,15 @@ bool NavigationControllerImpl::RendererDidNavigate(
}
NavigationType NavigationControllerImpl::ClassifyNavigation(
- RenderFrameHost* rfh,
+ RenderFrameHostImpl* 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.
+ // 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 and in particular http://crbug.com/464014). 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;
@@ -977,8 +1030,7 @@ NavigationType NavigationControllerImpl::ClassifyNavigation(
temp.append(",");
}
GURL url(temp);
- static_cast<RenderFrameHostImpl*>(rfh)->render_view_host()->Send(
- new ViewMsg_TempCrashWithData(url));
+ rfh->render_view_host()->Send(new ViewMsg_TempCrashWithData(url));
return NAVIGATION_TYPE_NAV_IGNORE;
}
NavigationEntryImpl* existing_entry = entries_[existing_entry_index].get();
@@ -996,15 +1048,31 @@ NavigationType NavigationControllerImpl::ClassifyNavigation(
!pending_entry_->is_renderer_initiated() &&
existing_entry != pending_entry_ &&
pending_entry_->GetPageID() == -1 &&
- existing_entry == GetLastCommittedEntry()) {
- // In this case, we have a pending entry for a URL but WebCore didn't do a
- // new navigation. This happens when you press enter in the URL bar to
- // reload. We will create a pending entry, but WebKit will convert it to
- // a reload since it's the same page and not create a new entry for it
- // (the user doesn't want to have a new back/forward entry when they do
- // this). If this matches the last committed entry, we want to just ignore
- // the pending entry and go back to where we were (the "existing entry").
- return NAVIGATION_TYPE_SAME_PAGE;
+ existing_entry == GetLastCommittedEntry() &&
+ !params.was_within_same_page) {
+ // In order to prevent unrelated pending entries from interfering with
+ // this classification, make sure that the URL committed matches the URLs
+ // of both the existing entry and the pending entry. There might have been
+ // a redirection, though, so allow both the existing and pending entries
+ // to match either the final URL that committed, or the original one
+ // before redirection.
+ GURL original_url;
+ if (params.redirects.size())
+ original_url = params.redirects[0];
+
+ if ((params.url == existing_entry->GetURL() ||
+ original_url == existing_entry->GetURL()) &&
+ (params.url == pending_entry_->GetURL() ||
+ original_url == pending_entry_->GetURL())) {
+ // In this case, we have a pending entry for a URL but Blink didn't do a
+ // new navigation. This happens when you press enter in the URL bar to
+ // reload. We will create a pending entry, but Blink will convert it to a
+ // reload since it's the same page and not create a new entry for it (the
+ // user doesn't want to have a new back/forward entry when they do this).
+ // If this matches the last committed entry, we want to just ignore the
+ // pending entry and go back to where we were (the "existing entry").
+ return NAVIGATION_TYPE_SAME_PAGE;
+ }
}
// Any toplevel navigations with the same base (minus the reference fragment)
@@ -1022,8 +1090,123 @@ NavigationType NavigationControllerImpl::ClassifyNavigation(
return NAVIGATION_TYPE_EXISTING_PAGE;
}
+NavigationType NavigationControllerImpl::ClassifyNavigationWithoutPageID(
+ RenderFrameHostImpl* rfh,
+ const FrameHostMsg_DidCommitProvisionalLoad_Params& params) const {
+ if (params.did_create_new_entry) {
+ // A new entry. We may or may not have a pending entry for the page, and
+ // this may or may not be the main frame.
+ if (ui::PageTransitionIsMainFrame(params.transition)) {
+ // TODO(avi): I want to use |if (!rfh->GetParent())| here but lots of unit
+ // tests fake auto subframe commits by sending the main frame a
+ // PAGE_TRANSITION_AUTO_SUBFRAME transition. Fix those, and adjust here.
+ return NAVIGATION_TYPE_NEW_PAGE;
+ }
+
+ // When this is a new subframe navigation, we should have a committed page
+ // in which it's a subframe. This may not be the case when an iframe is
+ // navigated on a popup navigated to about:blank (the iframe would be
+ // written into the popup by script on the main page). For these cases,
+ // there isn't any navigation stuff we can do, so just ignore it.
+ if (!GetLastCommittedEntry())
+ return NAVIGATION_TYPE_NAV_IGNORE;
+
+ // Valid subframe navigation.
+ return NAVIGATION_TYPE_NEW_SUBFRAME;
+ }
+
+ // We only clear the session history when navigating to a new page.
+ DCHECK(!params.history_list_was_cleared);
+
+ if (!ui::PageTransitionIsMainFrame(params.transition)) {
+ // All manual subframes would be did_create_new_entry and handled above, so
+ // we know this is auto.
+ if (GetLastCommittedEntry()) {
+ return NAVIGATION_TYPE_AUTO_SUBFRAME;
+ } else {
+ // We ignore subframes created in non-committed pages; we'd appreciate if
+ // people stopped doing that.
+ return NAVIGATION_TYPE_NAV_IGNORE;
+ }
+ }
+
+ if (params.nav_entry_id == 0) {
+ // This is a renderer-initiated navigation (nav_entry_id == 0), but didn't
+ // create a new page.
+
+ // Just like above in the did_create_new_entry case, it's possible to
+ // scribble onto an uncommitted page. Again, there isn't any navigation
+ // stuff that we can do, so ignore it here as well.
+ if (!GetLastCommittedEntry())
+ return NAVIGATION_TYPE_NAV_IGNORE;
+
+ if (params.was_within_same_page) {
+ // This is history.replaceState(), which is renderer-initiated yet within
+ // the same page.
+ return NAVIGATION_TYPE_IN_PAGE;
+ } else {
+ // This is history.reload() or a client-side redirect.
+ return NAVIGATION_TYPE_EXISTING_PAGE;
+ }
+ }
+
+ if (pending_entry_ && pending_entry_index_ == -1 &&
+ pending_entry_->GetUniqueID() == params.nav_entry_id) {
+ // In this case, we have a pending entry for a load of a new URL but Blink
+ // didn't do a new navigation (params.did_create_new_entry). This happens
+ // when you press enter in the URL bar to reload. We will create a pending
+ // entry, but Blink will convert it to a reload since it's the same page and
+ // not create a new entry for it (the user doesn't want to have a new
+ // back/forward entry when they do this). Therefore we want to just ignore
+ // the pending entry and go back to where we were (the "existing entry").
+ return NAVIGATION_TYPE_SAME_PAGE;
+ }
+
+ if (params.intended_as_new_entry) {
+ // This was intended to be a navigation to a new entry but the pending entry
+ // got cleared in the meanwhile. Classify as EXISTING_PAGE because we may or
+ // may not have a pending entry.
+ return NAVIGATION_TYPE_EXISTING_PAGE;
+ }
+
+ if (params.url_is_unreachable && failed_pending_entry_id_ != 0 &&
+ params.nav_entry_id == failed_pending_entry_id_) {
+ // If the renderer was going to a new pending entry that got cleared because
+ // of an error, this is the case of the user trying to retry a failed load
+ // by pressing return. Classify as EXISTING_PAGE because we probably don't
+ // have a pending entry.
+ return NAVIGATION_TYPE_EXISTING_PAGE;
+ }
+
+ // Now we know that the notification is for an existing page. Find that entry.
+ int existing_entry_index = GetEntryIndexWithUniqueID(params.nav_entry_id);
+ if (existing_entry_index == -1) {
+ // The page was not found. It could have been pruned because of the limit on
+ // back/forward entries (not likely since we'll usually tell it to navigate
+ // to such entries). It could also mean that the renderer is smoking crack.
+ // TODO(avi): Crash the renderer like we do in the old ClassifyNavigation?
+ NOTREACHED() << "Could not find nav entry with id " << params.nav_entry_id;
+ return NAVIGATION_TYPE_NAV_IGNORE;
+ }
+
+ // Any top-level navigations with the same base (minus the reference fragment)
+ // are in-page navigations. (We weeded out subframe navigations above.) Most
+ // of the time this doesn't matter since Blink doesn't tell us about subframe
+ // navigations that don't actually navigate, but it can happen when there is
+ // an encoding override (it always sends a navigation request).
+ NavigationEntryImpl* existing_entry = entries_[existing_entry_index].get();
+ if (AreURLsInPageNavigation(existing_entry->GetURL(), params.url,
+ params.was_within_same_page, rfh)) {
+ return NAVIGATION_TYPE_IN_PAGE;
+ }
+
+ // Since we weeded out "new" navigations above, we know this is an existing
+ // (back/forward) navigation.
+ return NAVIGATION_TYPE_EXISTING_PAGE;
+}
+
void NavigationControllerImpl::RendererDidNavigateToNewPage(
- RenderFrameHost* rfh,
+ RenderFrameHostImpl* rfh,
const FrameHostMsg_DidCommitProvisionalLoad_Params& params,
bool replace_entry) {
NavigationEntryImpl* new_entry;
@@ -1034,12 +1217,8 @@ void NavigationControllerImpl::RendererDidNavigateToNewPage(
if (pending_entry_ &&
(!pending_entry_->site_instance() ||
pending_entry_->site_instance() == rfh->GetSiteInstance())) {
- new_entry = new NavigationEntryImpl(*pending_entry_);
+ new_entry = pending_entry_->Clone();
- // Don't use the page type from the pending entry. Some interstitial page
- // may have set the type to interstitial. Once we commit, however, the page
- // type must always be normal.
- new_entry->set_page_type(PAGE_TYPE_NORMAL);
update_virtual_url = new_entry->update_virtual_url_with_url();
} else {
new_entry = new NavigationEntryImpl;
@@ -1060,8 +1239,11 @@ void NavigationControllerImpl::RendererDidNavigateToNewPage(
update_virtual_url = needs_update;
}
- if (params.url_is_unreachable)
- new_entry->set_page_type(PAGE_TYPE_ERROR);
+ // Don't use the page type from the pending entry. Some interstitial page
+ // may have set the type to interstitial. Once we commit, however, the page
+ // type must always be normal or error.
+ new_entry->set_page_type(params.url_is_unreachable ? PAGE_TYPE_ERROR
+ : PAGE_TYPE_NORMAL);
new_entry->SetURL(params.url);
if (update_virtual_url)
UpdateVirtualURLToURL(new_entry, params.url);
@@ -1097,7 +1279,7 @@ void NavigationControllerImpl::RendererDidNavigateToNewPage(
}
void NavigationControllerImpl::RendererDidNavigateToExistingPage(
- RenderFrameHost* rfh,
+ RenderFrameHostImpl* rfh,
const FrameHostMsg_DidCommitProvisionalLoad_Params& params) {
// We should only get here for main frame navigations.
DCHECK(ui::PageTransitionIsMainFrame(params.transition));
@@ -1112,6 +1294,8 @@ void NavigationControllerImpl::RendererDidNavigateToExistingPage(
NavigationEntryImpl* entry = entries_[entry_index].get();
// The URL may have changed due to redirects.
+ entry->set_page_type(params.url_is_unreachable ? PAGE_TYPE_ERROR
+ : PAGE_TYPE_NORMAL);
entry->SetURL(params.url);
entry->SetReferrer(params.referrer);
if (entry->update_virtual_url_with_url())
@@ -1150,7 +1334,7 @@ void NavigationControllerImpl::RendererDidNavigateToExistingPage(
}
void NavigationControllerImpl::RendererDidNavigateToSamePage(
- RenderFrameHost* rfh,
+ RenderFrameHostImpl* rfh,
const FrameHostMsg_DidCommitProvisionalLoad_Params& params) {
// This mode implies we have a pending entry that's the same as an existing
// entry for this page ID. This entry is guaranteed to exist by
@@ -1164,6 +1348,8 @@ void NavigationControllerImpl::RendererDidNavigateToSamePage(
existing_entry->set_unique_id(pending_entry_->GetUniqueID());
// The URL may have changed due to redirects.
+ existing_entry->set_page_type(params.url_is_unreachable ? PAGE_TYPE_ERROR
+ : PAGE_TYPE_NORMAL);
if (existing_entry->update_virtual_url_with_url())
UpdateVirtualURLToURL(existing_entry, params.url);
existing_entry->SetURL(params.url);
@@ -1177,7 +1363,7 @@ void NavigationControllerImpl::RendererDidNavigateToSamePage(
}
void NavigationControllerImpl::RendererDidNavigateInPage(
- RenderFrameHost* rfh,
+ RenderFrameHostImpl* rfh,
const FrameHostMsg_DidCommitProvisionalLoad_Params& params,
bool* did_replace_entry) {
DCHECK(ui::PageTransitionIsMainFrame(params.transition)) <<
@@ -1190,6 +1376,8 @@ void NavigationControllerImpl::RendererDidNavigateInPage(
// entry and it will be the same page as the new navigation (minus the
// reference fragments, of course). We'll update the URL of the existing
// entry without pruning the forward history.
+ existing_entry->set_page_type(params.url_is_unreachable ? PAGE_TYPE_ERROR
+ : PAGE_TYPE_NORMAL);
existing_entry->SetURL(params.url);
if (existing_entry->update_virtual_url_with_url())
UpdateVirtualURLToURL(existing_entry, params.url);
@@ -1209,11 +1397,26 @@ void NavigationControllerImpl::RendererDidNavigateInPage(
}
void NavigationControllerImpl::RendererDidNavigateNewSubframe(
- RenderFrameHost* rfh,
+ RenderFrameHostImpl* rfh,
const FrameHostMsg_DidCommitProvisionalLoad_Params& params) {
- if (ui::PageTransitionCoreTypeIs(params.transition,
- ui::PAGE_TRANSITION_AUTO_SUBFRAME)) {
- // This is not user-initiated. Ignore.
+ if (!ui::PageTransitionCoreTypeIs(params.transition,
+ ui::PAGE_TRANSITION_MANUAL_SUBFRAME)) {
+ // There was a comment here that said, "This is not user-initiated. Ignore."
+ // But this makes no sense; non-user-initiated navigations should be
+ // determined to be of type NAVIGATION_TYPE_AUTO_SUBFRAME and sent to
+ // RendererDidNavigateAutoSubframe below.
+ //
+ // This if clause dates back to https://codereview.chromium.org/115919 and
+ // the handling of immediate redirects. TODO(avi): Is this still valid? I'm
+ // pretty sure that's there's nothing left of that code and that we should
+ // take this out.
+ //
+ // Except for cross-process iframes; this doesn't work yet for them.
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess)) {
+ NOTREACHED();
+ }
+
DiscardNonCommittedEntriesInternal();
return;
}
@@ -1224,15 +1427,17 @@ void NavigationControllerImpl::RendererDidNavigateNewSubframe(
// band with the actual navigations.
DCHECK(GetLastCommittedEntry()) << "ClassifyNavigation should guarantee "
<< "that a last committed entry exists.";
- NavigationEntryImpl* new_entry = new NavigationEntryImpl(
- *NavigationEntryImpl::FromNavigationEntry(GetLastCommittedEntry()));
+ NavigationEntryImpl* new_entry = GetLastCommittedEntry()->Clone();
new_entry->SetPageID(params.page_id);
InsertOrReplaceEntry(new_entry, false);
}
bool NavigationControllerImpl::RendererDidNavigateAutoSubframe(
- RenderFrameHost* rfh,
+ RenderFrameHostImpl* rfh,
const FrameHostMsg_DidCommitProvisionalLoad_Params& params) {
+ DCHECK(ui::PageTransitionCoreTypeIs(params.transition,
+ ui::PAGE_TRANSITION_AUTO_SUBFRAME));
+
// We're guaranteed to have a previously committed entry, and we now need to
// handle navigation inside of a subframe in it without creating a new entry.
DCHECK(GetLastCommittedEntry());
@@ -1251,11 +1456,32 @@ bool NavigationControllerImpl::RendererDidNavigateAutoSubframe(
// Update the current navigation entry in case we're going back/forward.
if (entry_index != last_committed_entry_index_) {
+ // Make sure that a subframe commit isn't changing the main frame's origin.
+ // Otherwise the renderer process may be confused, leading to a URL spoof.
+ // We can't check the path since that may change (https://crbug.com/373041).
+ if (GetLastCommittedEntry()->GetURL().GetOrigin() !=
+ GetEntryAtIndex(entry_index)->GetURL().GetOrigin()) {
+ // TODO(creis): This is unexpectedly being encountered in practice. If
+ // you encounter this in practice, please post details to
+ // https://crbug.com/486916. Once that's resolved, we'll change this to
+ // kill the renderer process with bad_message::NC_AUTO_SUBFRAME.
+ NOTREACHED() << "Unexpected main frame origin change on AUTO_SUBFRAME.";
+ }
last_committed_entry_index_ = entry_index;
DiscardNonCommittedEntriesInternal();
return true;
}
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess)) {
+ // This may be a "new auto" case where we add a new FrameNavigationEntry, or
+ // it may be a "history auto" case where we update an existing one.
+ NavigationEntryImpl* last_committed = GetLastCommittedEntry();
+ last_committed->AddOrUpdateFrameEntry(rfh->frame_tree_node(),
+ rfh->GetSiteInstance(), params.url,
+ params.referrer);
+ }
+
// We do not need to discard the pending entry in this case, since we will
// not generate commit notifications for this auto-subframe navigation.
return false;
@@ -1317,19 +1543,8 @@ void NavigationControllerImpl::CopyStateFromAndPrune(
NavigationControllerImpl* source =
static_cast<NavigationControllerImpl*>(temp);
- // The SiteInstance and page_id of the last committed entry needs to be
- // remembered at this point, in case there is only one committed entry
- // and it is pruned. We use a scoped_refptr to ensure the SiteInstance
- // can't be freed during this time period.
- NavigationEntryImpl* last_committed =
- NavigationEntryImpl::FromNavigationEntry(GetLastCommittedEntry());
- scoped_refptr<SiteInstance> site_instance(
- last_committed->site_instance());
- int32 minimum_page_id = last_committed->GetPageID();
- int32 max_page_id =
- delegate_->GetMaxPageIDForSiteInstance(site_instance.get());
-
- // Remove all the entries leaving the active entry.
+
+ // Remove all the entries leaving the last committed entry.
PruneAllButLastCommittedInternal();
// We now have one entry, possibly with a new pending entry. Ensure that
@@ -1339,7 +1554,7 @@ void NavigationControllerImpl::CopyStateFromAndPrune(
source->PruneOldestEntryIfFull();
// Insert the entries from source. Don't use source->GetCurrentEntryIndex as
- // we don't want to copy over the transient entry. Ignore any pending entry,
+ // we don't want to copy over the transient entry. Ignore any pending entry,
// since it has not committed in source.
int max_source_index = source->last_committed_entry_index_;
if (max_source_index == -1)
@@ -1358,22 +1573,19 @@ void NavigationControllerImpl::CopyStateFromAndPrune(
// Adjust indices such that the last entry and pending are at the end now.
last_committed_entry_index_ = GetEntryCount() - 1;
- delegate_->SetHistoryLengthAndPrune(site_instance.get(),
- max_source_index,
- minimum_page_id);
+ delegate_->SetHistoryOffsetAndLength(last_committed_entry_index_,
+ GetEntryCount());
- // Copy the max page id map from the old tab to the new tab. This ensures
- // that new and existing navigations in the tab's current SiteInstances
- // are identified properly.
+ // Copy the max page id map from the old tab to the new tab. This ensures that
+ // new and existing navigations in the tab's current SiteInstances are
+ // identified properly.
+ NavigationEntryImpl* last_committed = GetLastCommittedEntry();
+ int32 site_max_page_id =
+ delegate_->GetMaxPageIDForSiteInstance(last_committed->site_instance());
delegate_->CopyMaxPageIDsFrom(source->delegate()->GetWebContents());
+ delegate_->UpdateMaxPageIDForSiteInstance(last_committed->site_instance(),
+ site_max_page_id);
max_restored_page_id_ = source->max_restored_page_id_;
-
- // If there is a last committed entry, be sure to include it in the new
- // max page ID map.
- if (max_page_id > -1) {
- delegate_->UpdateMaxPageIDForSiteInstance(site_instance.get(),
- max_page_id);
- }
}
bool NavigationControllerImpl::CanPruneAllButLastCommitted() {
@@ -1400,18 +1612,11 @@ bool NavigationControllerImpl::CanPruneAllButLastCommitted() {
void NavigationControllerImpl::PruneAllButLastCommitted() {
PruneAllButLastCommittedInternal();
- // We should still have a last committed entry.
- DCHECK_NE(-1, last_committed_entry_index_);
+ DCHECK_EQ(0, last_committed_entry_index_);
+ DCHECK_EQ(1, GetEntryCount());
- // We pass 0 instead of GetEntryCount() for the history_length parameter of
- // SetHistoryLengthAndPrune, because it will create history_length additional
- // history entries.
- // TODO(jochen): This API is confusing and we should clean it up.
- // http://crbug.com/178491
- NavigationEntryImpl* entry =
- NavigationEntryImpl::FromNavigationEntry(GetVisibleEntry());
- delegate_->SetHistoryLengthAndPrune(
- entry->site_instance(), 0, entry->GetPageID());
+ delegate_->SetHistoryOffsetAndLength(last_committed_entry_index_,
+ GetEntryCount());
}
void NavigationControllerImpl::PruneAllButLastCommittedInternal() {
@@ -1509,6 +1714,11 @@ bool NavigationControllerImpl::NeedsReload() const {
void NavigationControllerImpl::SetNeedsReload() {
needs_reload_ = true;
+
+ if (last_committed_entry_index_ != -1) {
+ entries_[last_committed_entry_index_]->SetTransitionType(
+ ui::PAGE_TRANSITION_RELOAD);
+ }
}
void NavigationControllerImpl::RemoveEntryAtIndexInternal(int index) {
@@ -1533,7 +1743,7 @@ void NavigationControllerImpl::DiscardNonCommittedEntries() {
}
}
-NavigationEntry* NavigationControllerImpl::GetPendingEntry() const {
+NavigationEntryImpl* NavigationControllerImpl::GetPendingEntry() const {
return pending_entry_;
}
@@ -1556,6 +1766,7 @@ void NavigationControllerImpl::InsertOrReplaceEntry(NavigationEntryImpl* entry,
DiscardNonCommittedEntriesInternal();
int current_size = static_cast<int>(entries_.size());
+ DCHECK_IMPLIES(replace, current_size > 0);
if (current_size > 0) {
// Prune any entries which are in front of the current entry.
@@ -1720,17 +1931,25 @@ void NavigationControllerImpl::FinishRestore(int selected_index,
}
void NavigationControllerImpl::DiscardNonCommittedEntriesInternal() {
- DiscardPendingEntry();
+ DiscardPendingEntry(false);
DiscardTransientEntry();
}
-void NavigationControllerImpl::DiscardPendingEntry() {
+void NavigationControllerImpl::DiscardPendingEntry(bool was_failure) {
// It is not safe to call DiscardPendingEntry while NavigateToEntry is in
// progress, since this will cause a use-after-free. (We only allow this
// when the tab is being destroyed for shutdown, since it won't return to
// NavigateToEntry in that case.) http://crbug.com/347742.
CHECK(!in_navigate_to_pending_entry_ || delegate_->IsBeingDestroyed());
+ if (was_failure && pending_entry_) {
+ failed_pending_entry_id_ = pending_entry_->GetUniqueID();
+ failed_pending_entry_should_replace_ =
+ pending_entry_->should_replace_entry();
+ } else {
+ failed_pending_entry_id_ = 0;
+ }
+
if (pending_entry_index_ == -1)
delete pending_entry_;
pending_entry_ = NULL;
@@ -1756,7 +1975,16 @@ int NavigationControllerImpl::GetEntryIndexWithPageID(
return -1;
}
-NavigationEntry* NavigationControllerImpl::GetTransientEntry() const {
+int NavigationControllerImpl::GetEntryIndexWithUniqueID(
+ int nav_entry_id) const {
+ for (int i = static_cast<int>(entries_.size()) - 1; i >= 0; --i) {
+ if (entries_[i]->GetUniqueID() == nav_entry_id)
+ return i;
+ }
+ return -1;
+}
+
+NavigationEntryImpl* NavigationControllerImpl::GetTransientEntry() const {
if (transient_entry_index_ == -1)
return NULL;
return entries_[transient_entry_index_].get();
@@ -1781,12 +2009,14 @@ void NavigationControllerImpl::InsertEntriesFrom(
DCHECK_LE(max_index, source.GetEntryCount());
size_t insert_index = 0;
for (int i = 0; i < max_index; i++) {
- // When cloning a tab, copy all entries except interstitial pages
- if (source.entries_[i].get()->GetPageType() !=
- PAGE_TYPE_INTERSTITIAL) {
+ // When cloning a tab, copy all entries except interstitial pages.
+ if (source.entries_[i].get()->GetPageType() != PAGE_TYPE_INTERSTITIAL) {
+ // TODO(creis): Once we start sharing FrameNavigationEntries between
+ // NavigationEntries, it will not be safe to share them with another tab.
+ // Must have a version of Clone that recreates them.
entries_.insert(entries_.begin() + insert_index++,
linked_ptr<NavigationEntryImpl>(
- new NavigationEntryImpl(*source.entries_[i])));
+ source.entries_[i]->Clone()));
}
}
}
diff --git a/chromium/content/browser/frame_host/navigation_controller_impl.h b/chromium/content/browser/frame_host/navigation_controller_impl.h
index a646646f35f..8546940148e 100644
--- a/chromium/content/browser/frame_host/navigation_controller_impl.h
+++ b/chromium/content/browser/frame_host/navigation_controller_impl.h
@@ -12,6 +12,7 @@
#include "base/time/time.h"
#include "build/build_config.h"
#include "content/browser/frame_host/navigation_controller_delegate.h"
+#include "content/browser/frame_host/navigation_entry_impl.h"
#include "content/browser/ssl/ssl_manager.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_type.h"
@@ -19,8 +20,7 @@
struct FrameHostMsg_DidCommitProvisionalLoad_Params;
namespace content {
-class NavigationEntryImpl;
-class RenderViewHost;
+class RenderFrameHostImpl;
class NavigationEntryScreenshotManager;
class SiteInstance;
struct LoadCommittedDetails;
@@ -40,19 +40,19 @@ class CONTENT_EXPORT NavigationControllerImpl
void Restore(int selected_navigation,
RestoreType type,
std::vector<NavigationEntry*>* entries) override;
- NavigationEntry* GetActiveEntry() const override;
- NavigationEntry* GetVisibleEntry() const override;
+ NavigationEntryImpl* GetActiveEntry() const override;
+ NavigationEntryImpl* GetVisibleEntry() const override;
int GetCurrentEntryIndex() const override;
- NavigationEntry* GetLastCommittedEntry() const override;
+ NavigationEntryImpl* 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;
+ NavigationEntryImpl* GetEntryAtIndex(int index) const override;
+ NavigationEntryImpl* GetEntryAtOffset(int offset) const override;
void DiscardNonCommittedEntries() override;
- NavigationEntry* GetPendingEntry() const override;
+ NavigationEntryImpl* GetPendingEntry() const override;
int GetPendingEntryIndex() const override;
- NavigationEntry* GetTransientEntry() const override;
+ NavigationEntryImpl* GetTransientEntry() const override;
void SetTransientEntry(NavigationEntry* entry) override;
void LoadURL(const GURL& url,
const Referrer& referrer,
@@ -107,6 +107,9 @@ class CONTENT_EXPORT NavigationControllerImpl
int GetEntryIndexWithPageID(SiteInstance* instance,
int32 page_id) const;
+ // Return the index of the entry with the given unique id, or -1 if not found.
+ int GetEntryIndexWithUniqueID(int nav_entry_id) const;
+
// Return the entry with the corresponding instance and page_id, or NULL if
// not found.
NavigationEntryImpl* GetEntryWithPageID(
@@ -134,7 +137,7 @@ class CONTENT_EXPORT NavigationControllerImpl
// In the case that nothing has changed, the details structure is undefined
// and it will return false.
bool RendererDidNavigate(
- RenderFrameHost* rfh,
+ RenderFrameHostImpl* rfh,
const FrameHostMsg_DidCommitProvisionalLoad_Params& params,
LoadCommittedDetails* details);
@@ -199,8 +202,9 @@ class CONTENT_EXPORT NavigationControllerImpl
// that.
void SetScreenshotManager(NavigationEntryScreenshotManager* manager);
- // Discards only the pending entry.
- void DiscardPendingEntry();
+ // Discards only the pending entry. |was_failure| should be set if the pending
+ // entry is being discarded because it failed to load.
+ void DiscardPendingEntry(bool was_failure);
private:
friend class RestoreHelper;
@@ -228,7 +232,13 @@ class CONTENT_EXPORT NavigationControllerImpl
// Classifies the given renderer navigation (see the NavigationType enum).
NavigationType ClassifyNavigation(
- RenderFrameHost* rfh,
+ RenderFrameHostImpl* rfh,
+ const FrameHostMsg_DidCommitProvisionalLoad_Params& params) const;
+ // This does the same as above (hopefully), but does so without any use of
+ // deprecated page id values. Once it bakes and is verified to behave the
+ // same, it will replace it. http://crbug.com/369661
+ NavigationType ClassifyNavigationWithoutPageID(
+ RenderFrameHostImpl* rfh,
const FrameHostMsg_DidCommitProvisionalLoad_Params& params) const;
// Causes the controller to load the specified entry. The function assumes
@@ -249,24 +259,24 @@ class CONTENT_EXPORT NavigationControllerImpl
// whether the last entry has been replaced or not.
// See LoadCommittedDetails.did_replace_entry.
void RendererDidNavigateToNewPage(
- RenderFrameHost* rfh,
+ RenderFrameHostImpl* rfh,
const FrameHostMsg_DidCommitProvisionalLoad_Params& params,
bool replace_entry);
void RendererDidNavigateToExistingPage(
- RenderFrameHost* rfh,
+ RenderFrameHostImpl* rfh,
const FrameHostMsg_DidCommitProvisionalLoad_Params& params);
void RendererDidNavigateToSamePage(
- RenderFrameHost* rfh,
+ RenderFrameHostImpl* rfh,
const FrameHostMsg_DidCommitProvisionalLoad_Params& params);
void RendererDidNavigateInPage(
- RenderFrameHost* rfh,
+ RenderFrameHostImpl* rfh,
const FrameHostMsg_DidCommitProvisionalLoad_Params& params,
bool* did_replace_entry);
void RendererDidNavigateNewSubframe(
- RenderFrameHost* rfh,
+ RenderFrameHostImpl* rfh,
const FrameHostMsg_DidCommitProvisionalLoad_Params& params);
bool RendererDidNavigateAutoSubframe(
- RenderFrameHost* rfh,
+ RenderFrameHostImpl* rfh,
const FrameHostMsg_DidCommitProvisionalLoad_Params& params);
// Helper function for code shared between Reload() and ReloadIgnoringCache().
@@ -345,11 +355,23 @@ class CONTENT_EXPORT NavigationControllerImpl
// the memory management.
NavigationEntryImpl* pending_entry_;
- // currently visible entry
+ // If a new entry fails loading, details about it are temporarily held here
+ // until the error page is shown. These variables are only valid if
+ // |failed_pending_entry_id_| is not 0.
+ //
+ // TODO(avi): We need a better way to handle the connection between failed
+ // loads and the subsequent load of the error page. This current approach has
+ // issues: 1. This might hang around longer than we'd like if there is no
+ // error page loaded, and 2. This doesn't work very well for frames.
+ // http://crbug.com/474261
+ int failed_pending_entry_id_;
+ bool failed_pending_entry_should_replace_;
+
+ // The index of the currently visible entry.
int last_committed_entry_index_;
- // index of pending entry if it is in entries_, or -1 if pending_entry_ is a
- // new entry (created by LoadURL).
+ // The index of the pending entry if it is in entries_, or -1 if
+ // pending_entry_ is a new entry (created by LoadURL).
int pending_entry_index_;
// The index for the entry that is shown until a navigation occurs. This is
diff --git a/chromium/content/browser/frame_host/navigation_controller_impl_browsertest.cc b/chromium/content/browser/frame_host/navigation_controller_impl_browsertest.cc
index 20c00ee3edf..6cc541ef01a 100644
--- a/chromium/content/browser/frame_host/navigation_controller_impl_browsertest.cc
+++ b/chromium/content/browser/frame_host/navigation_controller_impl_browsertest.cc
@@ -3,16 +3,42 @@
// found in the LICENSE file.
#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/strings/stringprintf.h"
+#include "content/browser/frame_host/frame_navigation_entry.h"
+#include "content/browser/frame_host/frame_tree.h"
#include "content/browser/frame_host/navigation_controller_impl.h"
#include "content/browser/frame_host/navigation_entry_impl.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/resource_controller.h"
+#include "content/public/browser/resource_dispatcher_host.h"
+#include "content/public/browser/resource_dispatcher_host_delegate.h"
+#include "content/public/browser/resource_throttle.h"
#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/common/bindings_policy.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/common/url_constants.h"
+#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
+#include "content/public/test/test_navigation_observer.h"
+#include "content/public/test/test_utils.h"
#include "content/shell/browser/shell.h"
+#include "content/test/content_browser_test_utils_internal.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/url_request/url_request_failed_job.h"
namespace content {
class NavigationControllerBrowserTest : public ContentBrowserTest {
+ protected:
+ void SetUpOnMainThread() override {
+ host_resolver()->AddRule("*", "127.0.0.1");
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+ }
};
IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, LoadDataWithBaseURL) {
@@ -22,7 +48,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, LoadDataWithBaseURL) {
const NavigationController& controller =
shell()->web_contents()->GetController();
- // load data. Blocks until it is done.
+ // Load data. Blocks until it is done.
content::LoadDataWithBaseURL(shell(), history_url, data, base_url);
// We should use history_url instead of the base_url as the original url of
@@ -30,5 +56,1363 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, LoadDataWithBaseURL) {
// paths in the data, or enforcing same origin policy.
EXPECT_EQ(controller.GetVisibleEntry()->GetOriginalRequestURL(), history_url);
}
-} // namespace content
+// The renderer uses the position in the history list as a clue to whether a
+// navigation is stale. In the case where the entry limit is reached and the
+// history list is pruned, make sure that there is no mismatch that would cause
+// it to start incorrectly rejecting navigations as stale. See
+// http://crbug.com/89798.
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+ DontIgnoreBackAfterNavEntryLimit) {
+ NavigationController& controller =
+ shell()->web_contents()->GetController();
+
+ const int kMaxEntryCount =
+ static_cast<int>(NavigationControllerImpl::max_entry_count());
+
+ // Load up to the max count, all entries should be there.
+ for (int url_index = 0; url_index < kMaxEntryCount; ++url_index) {
+ GURL url(base::StringPrintf("data:text/html,page%d", url_index));
+ EXPECT_TRUE(NavigateToURL(shell(), url));
+ }
+
+ EXPECT_EQ(controller.GetEntryCount(), kMaxEntryCount);
+
+ // Navigate twice more more.
+ for (int url_index = kMaxEntryCount;
+ url_index < kMaxEntryCount + 2; ++url_index) {
+ GURL url(base::StringPrintf("data:text/html,page%d", url_index));
+ EXPECT_TRUE(NavigateToURL(shell(), url));
+ }
+
+ // We expect page0 and page1 to be gone.
+ EXPECT_EQ(kMaxEntryCount, controller.GetEntryCount());
+ EXPECT_EQ(GURL("data:text/html,page2"),
+ controller.GetEntryAtIndex(0)->GetURL());
+
+ // Now try to go back. This should not hang.
+ ASSERT_TRUE(controller.CanGoBack());
+ controller.GoBack();
+ EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+
+ // This should have successfully gone back.
+ EXPECT_EQ(GURL(base::StringPrintf("data:text/html,page%d", kMaxEntryCount)),
+ controller.GetLastCommittedEntry()->GetURL());
+}
+
+namespace {
+
+int RendererHistoryLength(Shell* shell) {
+ int value = 0;
+ EXPECT_TRUE(ExecuteScriptAndExtractInt(
+ shell->web_contents(),
+ "domAutomationController.send(history.length)",
+ &value));
+ return value;
+}
+
+// Similar to the ones from content_browser_test_utils.
+bool NavigateToURLAndReplace(Shell* shell, const GURL& url) {
+ WebContents* web_contents = shell->web_contents();
+ WaitForLoadStop(web_contents);
+ TestNavigationObserver same_tab_observer(web_contents, 1);
+ NavigationController::LoadURLParams params(url);
+ params.should_replace_current_entry = true;
+ web_contents->GetController().LoadURLWithParams(params);
+ web_contents->Focus();
+ same_tab_observer.Wait();
+ if (!IsLastCommittedEntryOfPageType(web_contents, PAGE_TYPE_NORMAL))
+ return false;
+ return web_contents->GetLastCommittedURL() == url;
+}
+
+} // namespace
+
+// When loading a new page to replace an old page in the history list, make sure
+// that the browser and renderer agree, and that both get it right.
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+ CorrectLengthWithCurrentItemReplacement) {
+ NavigationController& controller =
+ shell()->web_contents()->GetController();
+
+ EXPECT_TRUE(NavigateToURL(shell(), GURL("data:text/html,page1")));
+ EXPECT_EQ(1, controller.GetEntryCount());
+ EXPECT_EQ(1, RendererHistoryLength(shell()));
+
+ EXPECT_TRUE(NavigateToURLAndReplace(shell(), GURL("data:text/html,page2")));
+ EXPECT_EQ(1, controller.GetEntryCount());
+ EXPECT_EQ(1, RendererHistoryLength(shell()));
+
+ // Note that there's no way to access the renderer's notion of the history
+ // offset via JavaScript. Checking just the history length, though, is enough;
+ // if the replacement failed, there would be a new history entry and thus an
+ // incorrect length.
+}
+
+// When spawning a new page from a WebUI page, make sure that the browser and
+// renderer agree about the length of the history list, and that both get it
+// right.
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+ CorrectLengthWithNewTabNavigatingFromWebUI) {
+ GURL web_ui_page(std::string(kChromeUIScheme) + "://" +
+ std::string(kChromeUIGpuHost));
+ EXPECT_TRUE(NavigateToURL(shell(), web_ui_page));
+ EXPECT_EQ(BINDINGS_POLICY_WEB_UI,
+ shell()->web_contents()->GetRenderViewHost()->GetEnabledBindings());
+
+ ShellAddedObserver observer;
+ std::string page_url = embedded_test_server()->GetURL(
+ "/navigation_controller/simple_page_1.html").spec();
+ EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
+ "window.open('" + page_url + "', '_blank')"));
+ Shell* shell2 = observer.GetShell();
+ EXPECT_TRUE(WaitForLoadStop(shell2->web_contents()));
+
+ EXPECT_EQ(1, shell2->web_contents()->GetController().GetEntryCount());
+ EXPECT_EQ(1, RendererHistoryLength(shell2));
+
+ // Again, as above, there's no way to access the renderer's notion of the
+ // history offset via JavaScript. Checking just the history length, again,
+ // will have to suffice.
+}
+
+namespace {
+
+class NoNavigationsObserver : public WebContentsObserver {
+ public:
+ // Observes navigation for the specified |web_contents|.
+ explicit NoNavigationsObserver(WebContents* web_contents)
+ : WebContentsObserver(web_contents) {}
+
+ private:
+ void DidNavigateAnyFrame(RenderFrameHost* render_frame_host,
+ const LoadCommittedDetails& details,
+ const FrameNavigateParams& params) override {
+ FAIL() << "No navigations should occur";
+ }
+};
+
+} // namespace
+
+// Some pages create a popup, then write an iframe into it. This causes a
+// subframe navigation without having any committed entry. Such navigations
+// just get thrown on the ground, but we shouldn't crash.
+//
+// This test actually hits NAVIGATION_TYPE_NAV_IGNORE three times. Two of them,
+// the initial window.open() and the iframe creation, don't try to create
+// navigation entries, and the third, the new navigation, tries to.
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, SubframeOnEmptyPage) {
+ NavigateToURL(shell(), GURL(url::kAboutBlankURL));
+ EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+
+ FrameTreeNode* root =
+ static_cast<WebContentsImpl*>(shell()->web_contents())->
+ GetFrameTree()->root();
+
+ // Pop open a new window.
+ ShellAddedObserver new_shell_observer;
+ std::string script = "window.open()";
+ EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
+ Shell* new_shell = new_shell_observer.GetShell();
+ ASSERT_NE(new_shell->web_contents(), shell()->web_contents());
+ FrameTreeNode* new_root =
+ static_cast<WebContentsImpl*>(new_shell->web_contents())->
+ GetFrameTree()->root();
+
+ // Make a new iframe in it.
+ NoNavigationsObserver observer(new_shell->web_contents());
+ script = "var iframe = document.createElement('iframe');"
+ "iframe.src = 'data:text/html,<p>some page</p>';"
+ "document.body.appendChild(iframe);";
+ EXPECT_TRUE(content::ExecuteScript(new_root->current_frame_host(), script));
+ // The success check is of the last-committed entry, and there is none.
+ WaitForLoadStopWithoutSuccessCheck(new_shell->web_contents());
+
+ ASSERT_EQ(1U, new_root->child_count());
+ ASSERT_NE(nullptr, new_root->child_at(0));
+
+ // Navigate it.
+ GURL frame_url = embedded_test_server()->GetURL(
+ "/navigation_controller/simple_page_2.html");
+ script = "location.assign('" + frame_url.spec() + "')";
+ EXPECT_TRUE(content::ExecuteScript(
+ new_root->child_at(0)->current_frame_host(), script));
+
+ // Success is not crashing, and not navigating.
+ EXPECT_EQ(nullptr,
+ new_shell->web_contents()->GetController().GetLastCommittedEntry());
+}
+
+namespace {
+
+class FrameNavigateParamsCapturer : public WebContentsObserver {
+ public:
+ // Observes navigation for the specified |node|.
+ explicit FrameNavigateParamsCapturer(FrameTreeNode* node)
+ : WebContentsObserver(
+ node->current_frame_host()->delegate()->GetAsWebContents()),
+ frame_tree_node_id_(node->frame_tree_node_id()),
+ navigations_remaining_(1),
+ wait_for_load_(true),
+ message_loop_runner_(new MessageLoopRunner) {}
+
+ void set_navigations_remaining(int count) {
+ navigations_remaining_ = count;
+ }
+
+ void set_wait_for_load(bool ignore) {
+ wait_for_load_ = ignore;
+ }
+
+ void Wait() {
+ message_loop_runner_->Run();
+ }
+
+ const FrameNavigateParams& params() const {
+ EXPECT_EQ(1U, params_.size());
+ return params_[0];
+ }
+
+ const std::vector<FrameNavigateParams>& all_params() const {
+ return params_;
+ }
+
+ const LoadCommittedDetails& details() const {
+ EXPECT_EQ(1U, details_.size());
+ return details_[0];
+ }
+
+ const std::vector<LoadCommittedDetails>& all_details() const {
+ return details_;
+ }
+
+ private:
+ void DidNavigateAnyFrame(RenderFrameHost* render_frame_host,
+ const LoadCommittedDetails& details,
+ const FrameNavigateParams& params) override {
+ RenderFrameHostImpl* rfh =
+ static_cast<RenderFrameHostImpl*>(render_frame_host);
+ if (rfh->frame_tree_node()->frame_tree_node_id() != frame_tree_node_id_)
+ return;
+
+ --navigations_remaining_;
+ params_.push_back(params);
+ details_.push_back(details);
+ if (!navigations_remaining_ &&
+ (!web_contents()->IsLoading() || !wait_for_load_))
+ message_loop_runner_->Quit();
+ }
+
+ void DidStopLoading() override {
+ if (!navigations_remaining_)
+ message_loop_runner_->Quit();
+ }
+
+ // The id of the FrameTreeNode whose navigations to observe.
+ int frame_tree_node_id_;
+
+ // How many navigations remain to capture.
+ int navigations_remaining_;
+
+ // Whether to also wait for the load to complete.
+ bool wait_for_load_;
+
+ // The params of the navigations.
+ std::vector<FrameNavigateParams> params_;
+
+ // The details of the navigations.
+ std::vector<LoadCommittedDetails> details_;
+
+ // The MessageLoopRunner used to spin the message loop.
+ scoped_refptr<MessageLoopRunner> message_loop_runner_;
+};
+
+class LoadCommittedCapturer : public WebContentsObserver {
+ public:
+ // Observes the load commit for the specified |node|.
+ explicit LoadCommittedCapturer(FrameTreeNode* node)
+ : WebContentsObserver(
+ node->current_frame_host()->delegate()->GetAsWebContents()),
+ frame_tree_node_id_(node->frame_tree_node_id()),
+ message_loop_runner_(new MessageLoopRunner) {}
+
+ // Observes the load commit for the next created frame in the specified
+ // |web_contents|.
+ explicit LoadCommittedCapturer(WebContents* web_contents)
+ : WebContentsObserver(web_contents),
+ frame_tree_node_id_(0),
+ message_loop_runner_(new MessageLoopRunner) {}
+
+ void Wait() {
+ message_loop_runner_->Run();
+ }
+
+ ui::PageTransition transition_type() const {
+ return transition_type_;
+ }
+
+ private:
+ void RenderFrameCreated(RenderFrameHost* render_frame_host) override {
+ // If this object was created with a specified tree frame node, there
+ // shouldn't be any frames being created.
+ DCHECK_EQ(0, frame_tree_node_id_);
+ RenderFrameHostImpl* rfh =
+ static_cast<RenderFrameHostImpl*>(render_frame_host);
+ frame_tree_node_id_ = rfh->frame_tree_node()->frame_tree_node_id();
+ }
+
+ void DidCommitProvisionalLoadForFrame(
+ RenderFrameHost* render_frame_host,
+ const GURL& url,
+ ui::PageTransition transition_type) override {
+ DCHECK_NE(0, frame_tree_node_id_);
+ RenderFrameHostImpl* rfh =
+ static_cast<RenderFrameHostImpl*>(render_frame_host);
+ if (rfh->frame_tree_node()->frame_tree_node_id() != frame_tree_node_id_)
+ return;
+
+ transition_type_ = transition_type;
+ if (!web_contents()->IsLoading())
+ message_loop_runner_->Quit();
+ }
+
+ void DidStopLoading() override { message_loop_runner_->Quit(); }
+
+ // The id of the FrameTreeNode whose navigations to observe.
+ int frame_tree_node_id_;
+
+ // The transition_type of the last navigation.
+ ui::PageTransition transition_type_;
+
+ // The MessageLoopRunner used to spin the message loop.
+ scoped_refptr<MessageLoopRunner> message_loop_runner_;
+};
+
+} // namespace
+
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+ ErrorPageReplacement) {
+ NavigationController& controller = shell()->web_contents()->GetController();
+ GURL error_url(
+ net::URLRequestFailedJob::GetMockHttpUrl(net::ERR_CONNECTION_RESET));
+ net::URLRequestFailedJob::AddUrlHandler();
+
+ NavigateToURL(shell(), GURL(url::kAboutBlankURL));
+ EXPECT_EQ(1, controller.GetEntryCount());
+
+ FrameTreeNode* root =
+ static_cast<WebContentsImpl*>(shell()->web_contents())->
+ GetFrameTree()->root();
+
+ // Navigate to a page that fails to load. It must result in an error page, the
+ // NEW_PAGE navigation type, and an addition to the history list.
+ {
+ FrameNavigateParamsCapturer capturer(root);
+ NavigateFrameToURL(root, error_url);
+ capturer.Wait();
+ EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.details().type);
+ NavigationEntry* entry = controller.GetLastCommittedEntry();
+ EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
+ EXPECT_EQ(2, controller.GetEntryCount());
+ }
+
+ // Navigate again to the page that fails to load. It must result in an error
+ // page, the EXISTING_PAGE navigation type, and no addition to the history
+ // list. We do not use SAME_PAGE here; that case only differs in that it
+ // clears the pending entry, and there is no pending entry after a load
+ // failure.
+ {
+ FrameNavigateParamsCapturer capturer(root);
+ NavigateFrameToURL(root, error_url);
+ capturer.Wait();
+ EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.details().type);
+ NavigationEntry* entry = controller.GetLastCommittedEntry();
+ EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
+ EXPECT_EQ(2, controller.GetEntryCount());
+ }
+
+ // Make a new entry ...
+ NavigateToURL(shell(), GURL(url::kAboutBlankURL));
+ EXPECT_EQ(3, controller.GetEntryCount());
+
+ // ... and replace it with a failed load. (Note that when you set the
+ // should_replace_current_entry flag, the navigation is classified as NEW_PAGE
+ // because that is a classification of the renderer's behavior, and the flag
+ // is a browser-side flag.)
+ {
+ FrameNavigateParamsCapturer capturer(root);
+ NavigateToURLAndReplace(shell(), error_url);
+ capturer.Wait();
+ EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.details().type);
+ NavigationEntry* entry = controller.GetLastCommittedEntry();
+ EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
+ EXPECT_EQ(3, controller.GetEntryCount());
+ }
+
+ // Make a new web ui page to force a process swap ...
+ GURL web_ui_page(std::string(kChromeUIScheme) + "://" +
+ std::string(kChromeUIGpuHost));
+ NavigateToURL(shell(), web_ui_page);
+ EXPECT_EQ(4, controller.GetEntryCount());
+
+ // ... and replace it with a failed load. (It is NEW_PAGE for the reason noted
+ // above.)
+ {
+ FrameNavigateParamsCapturer capturer(root);
+ NavigateToURLAndReplace(shell(), error_url);
+ capturer.Wait();
+ EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.details().type);
+ NavigationEntry* entry = controller.GetLastCommittedEntry();
+ EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
+ EXPECT_EQ(4, controller.GetEntryCount());
+ }
+}
+
+// Various tests for navigation type classifications. TODO(avi): It's rather
+// bogus that the same info is in two different enums; http://crbug.com/453555.
+
+// Verify that navigations for NAVIGATION_TYPE_NEW_PAGE are correctly
+// classified.
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+ NavigationTypeClassification_NewPage) {
+ NavigateToURL(shell(), GURL(url::kAboutBlankURL));
+
+ FrameTreeNode* root =
+ static_cast<WebContentsImpl*>(shell()->web_contents())->
+ GetFrameTree()->root();
+
+ {
+ // Simple load.
+ FrameNavigateParamsCapturer capturer(root);
+ GURL frame_url(embedded_test_server()->GetURL(
+ "/navigation_controller/page_with_links.html"));
+ NavigateFrameToURL(root, frame_url);
+ capturer.Wait();
+ // TODO(avi,creis): Why is this (and quite a few others below) a "link"
+ // transition? Lots of these transitions should be cleaned up.
+ EXPECT_EQ(ui::PAGE_TRANSITION_LINK, capturer.params().transition);
+ EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.details().type);
+ }
+
+ {
+ // Load via a fragment link click.
+ FrameNavigateParamsCapturer capturer(root);
+ std::string script = "document.getElementById('fraglink').click()";
+ EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
+ capturer.Wait();
+ EXPECT_EQ(ui::PAGE_TRANSITION_LINK, capturer.params().transition);
+ EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.details().type);
+ }
+
+ {
+ // Load via link click.
+ FrameNavigateParamsCapturer capturer(root);
+ std::string script = "document.getElementById('thelink').click()";
+ EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
+ capturer.Wait();
+ EXPECT_EQ(ui::PAGE_TRANSITION_LINK, capturer.params().transition);
+ EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.details().type);
+ }
+
+ {
+ // location.assign().
+ FrameNavigateParamsCapturer capturer(root);
+ GURL frame_url(embedded_test_server()->GetURL(
+ "/navigation_controller/simple_page_2.html"));
+ std::string script = "location.assign('" + frame_url.spec() + "')";
+ EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
+ capturer.Wait();
+ EXPECT_EQ(ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_CLIENT_REDIRECT,
+ capturer.params().transition);
+ EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.details().type);
+ }
+
+ {
+ // history.pushState().
+ FrameNavigateParamsCapturer capturer(root);
+ std::string script =
+ "history.pushState({}, 'page 1', 'simple_page_1.html')";
+ EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
+ capturer.Wait();
+ EXPECT_EQ(ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_CLIENT_REDIRECT,
+ capturer.params().transition);
+ EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.details().type);
+ }
+}
+
+// Verify that navigations for NAVIGATION_TYPE_EXISTING_PAGE are correctly
+// classified.
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+ NavigationTypeClassification_ExistingPage) {
+ GURL url1(embedded_test_server()->GetURL(
+ "/navigation_controller/simple_page_1.html"));
+ NavigateToURL(shell(), url1);
+ GURL url2(embedded_test_server()->GetURL(
+ "/navigation_controller/simple_page_2.html"));
+ NavigateToURL(shell(), url2);
+
+ FrameTreeNode* root =
+ static_cast<WebContentsImpl*>(shell()->web_contents())->
+ GetFrameTree()->root();
+
+ {
+ // Back from the browser side.
+ FrameNavigateParamsCapturer capturer(root);
+ shell()->web_contents()->GetController().GoBack();
+ capturer.Wait();
+ EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
+ | ui::PAGE_TRANSITION_FORWARD_BACK
+ | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR,
+ capturer.params().transition);
+ EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.details().type);
+ }
+
+ {
+ // Forward from the browser side.
+ FrameNavigateParamsCapturer capturer(root);
+ shell()->web_contents()->GetController().GoForward();
+ capturer.Wait();
+ EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
+ | ui::PAGE_TRANSITION_FORWARD_BACK
+ | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR,
+ capturer.params().transition);
+ EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.details().type);
+ }
+
+ {
+ // Back from the renderer side.
+ FrameNavigateParamsCapturer capturer(root);
+ EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(),
+ "history.back()"));
+ capturer.Wait();
+ EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
+ | ui::PAGE_TRANSITION_FORWARD_BACK
+ | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR,
+ capturer.params().transition);
+ EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.details().type);
+ }
+
+ {
+ // Forward from the renderer side.
+ FrameNavigateParamsCapturer capturer(root);
+ EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(),
+ "history.forward()"));
+ capturer.Wait();
+ EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
+ | ui::PAGE_TRANSITION_FORWARD_BACK
+ | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR,
+ capturer.params().transition);
+ EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.details().type);
+ }
+
+ {
+ // Back from the renderer side via history.go().
+ FrameNavigateParamsCapturer capturer(root);
+ EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(),
+ "history.go(-1)"));
+ capturer.Wait();
+ EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
+ | ui::PAGE_TRANSITION_FORWARD_BACK
+ | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR,
+ capturer.params().transition);
+ EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.details().type);
+ }
+
+ {
+ // Forward from the renderer side via history.go().
+ FrameNavigateParamsCapturer capturer(root);
+ EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(),
+ "history.go(1)"));
+ capturer.Wait();
+ EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
+ | ui::PAGE_TRANSITION_FORWARD_BACK
+ | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR,
+ capturer.params().transition);
+ EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.details().type);
+ }
+
+ {
+ // Reload from the browser side.
+ FrameNavigateParamsCapturer capturer(root);
+ shell()->web_contents()->GetController().Reload(false);
+ capturer.Wait();
+ EXPECT_EQ(ui::PAGE_TRANSITION_RELOAD, capturer.params().transition);
+ EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.details().type);
+ }
+
+ {
+ // Reload from the renderer side.
+ FrameNavigateParamsCapturer capturer(root);
+ EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(),
+ "location.reload()"));
+ capturer.Wait();
+ EXPECT_EQ(ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_CLIENT_REDIRECT,
+ capturer.params().transition);
+ EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.details().type);
+ }
+
+ {
+ // location.replace().
+ FrameNavigateParamsCapturer capturer(root);
+ GURL frame_url(embedded_test_server()->GetURL(
+ "/navigation_controller/simple_page_1.html"));
+ std::string script = "location.replace('" + frame_url.spec() + "')";
+ EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
+ capturer.Wait();
+ EXPECT_EQ(ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_CLIENT_REDIRECT,
+ capturer.params().transition);
+ EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.details().type);
+ }
+}
+
+// Verify that navigations for NAVIGATION_TYPE_SAME_PAGE are correctly
+// classified.
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+ NavigationTypeClassification_SamePage) {
+ GURL url1(embedded_test_server()->GetURL(
+ "/navigation_controller/simple_page_1.html"));
+ NavigateToURL(shell(), url1);
+
+ FrameTreeNode* root =
+ static_cast<WebContentsImpl*>(shell()->web_contents())->
+ GetFrameTree()->root();
+
+ {
+ // Simple load.
+ FrameNavigateParamsCapturer capturer(root);
+ GURL frame_url(embedded_test_server()->GetURL(
+ "/navigation_controller/simple_page_1.html"));
+ NavigateFrameToURL(root, frame_url);
+ capturer.Wait();
+ EXPECT_EQ(ui::PAGE_TRANSITION_LINK, capturer.params().transition);
+ EXPECT_EQ(NAVIGATION_TYPE_SAME_PAGE, capturer.details().type);
+ }
+}
+
+// Verify that navigations for NAVIGATION_TYPE_IN_PAGE are correctly
+// classified.
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+ NavigationTypeClassification_InPage) {
+ GURL url1(embedded_test_server()->GetURL(
+ "/navigation_controller/simple_page_1.html"));
+ NavigateToURL(shell(), url1);
+
+ FrameTreeNode* root =
+ static_cast<WebContentsImpl*>(shell()->web_contents())->
+ GetFrameTree()->root();
+
+ {
+ // history.replaceState().
+ FrameNavigateParamsCapturer capturer(root);
+ std::string script =
+ "history.replaceState({}, 'page 1', 'simple_page_2.html')";
+ EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
+ capturer.Wait();
+ EXPECT_EQ(ui::PAGE_TRANSITION_LINK, capturer.params().transition);
+ EXPECT_EQ(NAVIGATION_TYPE_IN_PAGE, capturer.details().type);
+ }
+
+ // Back and forward across a fragment navigation.
+
+ GURL url2(embedded_test_server()->GetURL(
+ "/navigation_controller/page_with_links.html"));
+ NavigateToURL(shell(), url2);
+ std::string script = "document.getElementById('fraglink').click()";
+ EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
+ EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+
+ {
+ // Back.
+ FrameNavigateParamsCapturer capturer(root);
+ shell()->web_contents()->GetController().GoBack();
+ capturer.Wait();
+ EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
+ | ui::PAGE_TRANSITION_FORWARD_BACK
+ | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR,
+ capturer.params().transition);
+ EXPECT_EQ(NAVIGATION_TYPE_IN_PAGE, capturer.details().type);
+ }
+
+ {
+ // Forward.
+ FrameNavigateParamsCapturer capturer(root);
+ shell()->web_contents()->GetController().GoForward();
+ capturer.Wait();
+ EXPECT_EQ(ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_FORWARD_BACK,
+ capturer.params().transition);
+ EXPECT_EQ(NAVIGATION_TYPE_IN_PAGE, capturer.details().type);
+ }
+
+ // Back and forward across a pushState-created navigation.
+
+ NavigateToURL(shell(), url1);
+ script = "history.pushState({}, 'page 2', 'simple_page_2.html')";
+ EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
+ EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+
+ {
+ // Back.
+ FrameNavigateParamsCapturer capturer(root);
+ shell()->web_contents()->GetController().GoBack();
+ capturer.Wait();
+ EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
+ | ui::PAGE_TRANSITION_FORWARD_BACK
+ | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR,
+ capturer.params().transition);
+ EXPECT_EQ(NAVIGATION_TYPE_IN_PAGE, capturer.details().type);
+ }
+
+ {
+ // Forward.
+ FrameNavigateParamsCapturer capturer(root);
+ shell()->web_contents()->GetController().GoForward();
+ capturer.Wait();
+ EXPECT_EQ(ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_FORWARD_BACK,
+ capturer.params().transition);
+ EXPECT_EQ(NAVIGATION_TYPE_IN_PAGE, capturer.details().type);
+ }
+}
+
+// Verify that navigations for NAVIGATION_TYPE_NEW_SUBFRAME and
+// NAVIGATION_TYPE_AUTO_SUBFRAME are properly classified.
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+ NavigationTypeClassification_NewAndAutoSubframe) {
+ GURL main_url(embedded_test_server()->GetURL(
+ "/navigation_controller/page_with_iframe.html"));
+ NavigateToURL(shell(), main_url);
+
+ // It is safe to obtain the root frame tree node here, as it doesn't change.
+ FrameTreeNode* root =
+ static_cast<WebContentsImpl*>(shell()->web_contents())->
+ GetFrameTree()->root();
+
+ ASSERT_EQ(1U, root->child_count());
+ ASSERT_NE(nullptr, root->child_at(0));
+
+ {
+ // Simple load.
+ FrameNavigateParamsCapturer capturer(root->child_at(0));
+ GURL frame_url(embedded_test_server()->GetURL(
+ "/navigation_controller/simple_page_1.html"));
+ NavigateFrameToURL(root->child_at(0), frame_url);
+ capturer.Wait();
+ EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME,
+ capturer.params().transition);
+ EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.details().type);
+ }
+
+ {
+ // Back.
+ FrameNavigateParamsCapturer capturer(root->child_at(0));
+ shell()->web_contents()->GetController().GoBack();
+ capturer.Wait();
+ EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.params().transition);
+ EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.details().type);
+ }
+
+ {
+ // Forward.
+ FrameNavigateParamsCapturer capturer(root->child_at(0));
+ shell()->web_contents()->GetController().GoForward();
+ capturer.Wait();
+ EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.params().transition);
+ EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.details().type);
+ }
+
+ {
+ // Simple load.
+ FrameNavigateParamsCapturer capturer(root->child_at(0));
+ GURL frame_url(embedded_test_server()->GetURL(
+ "/navigation_controller/page_with_links.html"));
+ NavigateFrameToURL(root->child_at(0), frame_url);
+ capturer.Wait();
+ EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME,
+ capturer.params().transition);
+ EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.details().type);
+ }
+
+ {
+ // Load via a fragment link click.
+ FrameNavigateParamsCapturer capturer(root->child_at(0));
+ std::string script = "document.getElementById('fraglink').click()";
+ EXPECT_TRUE(content::ExecuteScript(root->child_at(0)->current_frame_host(),
+ script));
+ capturer.Wait();
+ EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME,
+ capturer.params().transition);
+ EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.details().type);
+ }
+
+ {
+ // location.assign().
+ FrameNavigateParamsCapturer capturer(root->child_at(0));
+ GURL frame_url(embedded_test_server()->GetURL(
+ "/navigation_controller/simple_page_1.html"));
+ std::string script = "location.assign('" + frame_url.spec() + "')";
+ EXPECT_TRUE(content::ExecuteScript(root->child_at(0)->current_frame_host(),
+ script));
+ capturer.Wait();
+ EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME,
+ capturer.params().transition);
+ EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.details().type);
+ }
+
+ {
+ // location.replace().
+ LoadCommittedCapturer capturer(root->child_at(0));
+ GURL frame_url(embedded_test_server()->GetURL(
+ "/navigation_controller/simple_page_2.html"));
+ std::string script = "location.replace('" + frame_url.spec() + "')";
+ EXPECT_TRUE(content::ExecuteScript(root->child_at(0)->current_frame_host(),
+ script));
+ capturer.Wait();
+ EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type());
+ }
+
+ {
+ // history.pushState().
+ FrameNavigateParamsCapturer capturer(root->child_at(0));
+ std::string script =
+ "history.pushState({}, 'page 1', 'simple_page_1.html')";
+ EXPECT_TRUE(content::ExecuteScript(root->child_at(0)->current_frame_host(),
+ script));
+ capturer.Wait();
+ EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME,
+ capturer.params().transition);
+ EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.details().type);
+ }
+
+ {
+ // history.replaceState().
+ LoadCommittedCapturer capturer(root->child_at(0));
+ std::string script =
+ "history.replaceState({}, 'page 2', 'simple_page_2.html')";
+ EXPECT_TRUE(content::ExecuteScript(root->child_at(0)->current_frame_host(),
+ script));
+ capturer.Wait();
+ EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type());
+ }
+
+ {
+ // Reload.
+ LoadCommittedCapturer capturer(root->child_at(0));
+ EXPECT_TRUE(content::ExecuteScript(root->child_at(0)->current_frame_host(),
+ "location.reload()"));
+ capturer.Wait();
+ EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type());
+ }
+
+ {
+ // Create an iframe.
+ LoadCommittedCapturer capturer(shell()->web_contents());
+ GURL frame_url(embedded_test_server()->GetURL(
+ "/navigation_controller/simple_page_1.html"));
+ std::string script = "var iframe = document.createElement('iframe');"
+ "iframe.src = '" + frame_url.spec() + "';"
+ "document.body.appendChild(iframe);";
+ EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
+ capturer.Wait();
+ EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type());
+ }
+}
+
+// Verify that navigations caused by client-side redirects are correctly
+// classified.
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+ NavigationTypeClassification_ClientSideRedirect) {
+ NavigateToURL(shell(), GURL(url::kAboutBlankURL));
+ EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+
+ FrameTreeNode* root =
+ static_cast<WebContentsImpl*>(shell()->web_contents())->
+ GetFrameTree()->root();
+
+ {
+ // Load the redirecting page.
+ FrameNavigateParamsCapturer capturer(root);
+ capturer.set_navigations_remaining(2);
+ GURL frame_url(embedded_test_server()->GetURL(
+ "/navigation_controller/client_redirect.html"));
+ NavigateFrameToURL(root, frame_url);
+ capturer.Wait();
+
+ std::vector<FrameNavigateParams> params = capturer.all_params();
+ std::vector<LoadCommittedDetails> details = capturer.all_details();
+ ASSERT_EQ(2U, params.size());
+ ASSERT_EQ(2U, details.size());
+ EXPECT_EQ(ui::PAGE_TRANSITION_LINK, params[0].transition);
+ EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, details[0].type);
+ EXPECT_EQ(ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_CLIENT_REDIRECT,
+ params[1].transition);
+ EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, details[1].type);
+ }
+}
+
+// Verify the tree of FrameNavigationEntries after NAVIGATION_TYPE_AUTO_SUBFRAME
+// commits.
+// TODO(creis): Test cross-site iframes.
+// TODO(creis): Test updating entries for history auto subframe navigations.
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+ FrameNavigationEntry_AutoSubframe) {
+ GURL main_url(embedded_test_server()->GetURL(
+ "/navigation_controller/simple_page_1.html"));
+ NavigateToURL(shell(), main_url);
+ const NavigationControllerImpl& controller =
+ static_cast<const NavigationControllerImpl&>(
+ shell()->web_contents()->GetController());
+ FrameTreeNode* root =
+ static_cast<WebContentsImpl*>(shell()->web_contents())->
+ GetFrameTree()->root();
+
+ // Create an iframe.
+ GURL frame_url(embedded_test_server()->GetURL(
+ "/navigation_controller/simple_page_2.html"));
+ {
+ LoadCommittedCapturer capturer(shell()->web_contents());
+ std::string script = "var iframe = document.createElement('iframe');"
+ "iframe.src = '" + frame_url.spec() + "';"
+ "document.body.appendChild(iframe);";
+ EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
+ capturer.Wait();
+ EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type());
+ }
+
+ // Check last committed NavigationEntry.
+ EXPECT_EQ(1, controller.GetEntryCount());
+ NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
+ EXPECT_EQ(main_url, entry->GetURL());
+ FrameNavigationEntry* root_entry = entry->root_node()->frame_entry.get();
+ EXPECT_EQ(main_url, root_entry->url());
+
+ // Verify subframe entries if we're in --site-per-process mode.
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess)) {
+ // The entry should now have a subframe FrameNavigationEntry.
+ ASSERT_EQ(1U, entry->root_node()->children.size());
+ FrameNavigationEntry* frame_entry =
+ entry->root_node()->children[0]->frame_entry.get();
+ EXPECT_EQ(frame_url, frame_entry->url());
+ } else {
+ // There are no subframe FrameNavigationEntries by default.
+ EXPECT_EQ(0U, entry->root_node()->children.size());
+ }
+
+ // Create a second iframe.
+ {
+ LoadCommittedCapturer capturer(shell()->web_contents());
+ std::string script = "var iframe = document.createElement('iframe');"
+ "iframe.src = '" + frame_url.spec() + "';"
+ "document.body.appendChild(iframe);";
+ EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
+ capturer.Wait();
+ EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type());
+ }
+
+ // The last committed NavigationEntry shouldn't have changed.
+ EXPECT_EQ(1, controller.GetEntryCount());
+ entry = controller.GetLastCommittedEntry();
+ EXPECT_EQ(main_url, entry->GetURL());
+ root_entry = entry->root_node()->frame_entry.get();
+ EXPECT_EQ(main_url, root_entry->url());
+
+ // Verify subframe entries if we're in --site-per-process mode.
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess)) {
+ // The entry should now have 2 subframe FrameNavigationEntries.
+ ASSERT_EQ(2U, entry->root_node()->children.size());
+ FrameNavigationEntry* frame_entry =
+ entry->root_node()->children[1]->frame_entry.get();
+ EXPECT_EQ(frame_url, frame_entry->url());
+ } else {
+ // There are no subframe FrameNavigationEntries by default.
+ EXPECT_EQ(0U, entry->root_node()->children.size());
+ }
+
+ // Create a nested iframe in the second subframe.
+ {
+ LoadCommittedCapturer capturer(shell()->web_contents());
+ std::string script = "var iframe = document.createElement('iframe');"
+ "iframe.src = '" + frame_url.spec() + "';"
+ "document.body.appendChild(iframe);";
+ EXPECT_TRUE(content::ExecuteScript(root->child_at(1)->current_frame_host(),
+ script));
+ capturer.Wait();
+ EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type());
+ }
+
+ // The last committed NavigationEntry shouldn't have changed.
+ EXPECT_EQ(1, controller.GetEntryCount());
+ entry = controller.GetLastCommittedEntry();
+ EXPECT_EQ(main_url, entry->GetURL());
+ root_entry = entry->root_node()->frame_entry.get();
+ EXPECT_EQ(main_url, root_entry->url());
+
+ // Verify subframe entries if we're in --site-per-process mode.
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess)) {
+ // The entry should now have 2 subframe FrameNavigationEntries.
+ ASSERT_EQ(2U, entry->root_node()->children.size());
+ ASSERT_EQ(1U, entry->root_node()->children[1]->children.size());
+ FrameNavigationEntry* frame_entry =
+ entry->root_node()->children[1]->children[0]->frame_entry.get();
+ EXPECT_EQ(frame_url, frame_entry->url());
+ } else {
+ // There are no subframe FrameNavigationEntries by default.
+ EXPECT_EQ(0U, entry->root_node()->children.size());
+ }
+}
+
+namespace {
+
+class HttpThrottle : public ResourceThrottle {
+ public:
+ // ResourceThrottle
+ void WillStartRequest(bool* defer) override {
+ *defer = true;
+ }
+
+ const char* GetNameForLogging() const override {
+ return "HttpThrottle";
+ }
+};
+
+class StallDelegate : public ResourceDispatcherHostDelegate {
+ // ResourceDispatcherHostDelegate
+ void RequestBeginning(
+ net::URLRequest* request,
+ content::ResourceContext* resource_context,
+ content::AppCacheService* appcache_service,
+ ResourceType resource_type,
+ ScopedVector<content::ResourceThrottle>* throttles) override {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ throttles->push_back(new HttpThrottle);
+ }
+};
+
+// Loads |start_url|, then loads |stalled_url| which stalls. While the page is
+// stalled, an in-page navigation happens. Make sure that all the navigations
+// are properly classified.
+void DoReplaceStateWhilePending(Shell* shell,
+ const GURL& start_url,
+ const GURL& stalled_url,
+ const std::string& replace_state_filename) {
+ NavigationControllerImpl& controller =
+ static_cast<NavigationControllerImpl&>(
+ shell->web_contents()->GetController());
+
+ FrameTreeNode* root =
+ static_cast<WebContentsImpl*>(shell->web_contents())->
+ GetFrameTree()->root();
+
+ // Start with one page.
+ EXPECT_TRUE(NavigateToURL(shell, start_url));
+
+ // Have the user decide to go to a different page which is very slow.
+ StallDelegate stall_delegate;
+ ResourceDispatcherHost::Get()->SetDelegate(&stall_delegate);
+ controller.LoadURL(
+ stalled_url, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
+
+ // That should be the pending entry.
+ NavigationEntryImpl* entry = controller.GetPendingEntry();
+ ASSERT_NE(nullptr, entry);
+ EXPECT_EQ(stalled_url, entry->GetURL());
+
+ {
+ // Now the existing page uses history.replaceState().
+ FrameNavigateParamsCapturer capturer(root);
+ capturer.set_wait_for_load(false);
+ std::string script =
+ "history.replaceState({}, '', '" + replace_state_filename + "')";
+ EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
+ capturer.Wait();
+
+ // The fact that there was a pending entry shouldn't interfere with the
+ // classification.
+ EXPECT_EQ(NAVIGATION_TYPE_IN_PAGE, capturer.details().type);
+ }
+
+ ResourceDispatcherHost::Get()->SetDelegate(nullptr);
+}
+
+} // namespace
+
+IN_PROC_BROWSER_TEST_F(
+ NavigationControllerBrowserTest,
+ NavigationTypeClassification_On1InPageToXWhile2Pending) {
+ GURL url1(embedded_test_server()->GetURL(
+ "/navigation_controller/simple_page_1.html"));
+ GURL url2(embedded_test_server()->GetURL(
+ "/navigation_controller/simple_page_2.html"));
+ DoReplaceStateWhilePending(shell(), url1, url2, "x");
+}
+
+IN_PROC_BROWSER_TEST_F(
+ NavigationControllerBrowserTest,
+ NavigationTypeClassification_On1InPageTo2While2Pending) {
+ GURL url1(embedded_test_server()->GetURL(
+ "/navigation_controller/simple_page_1.html"));
+ GURL url2(embedded_test_server()->GetURL(
+ "/navigation_controller/simple_page_2.html"));
+ DoReplaceStateWhilePending(shell(), url1, url2, "simple_page_2.html");
+}
+
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+ NavigationTypeClassification_On1InPageToXWhile1Pending) {
+ GURL url(embedded_test_server()->GetURL(
+ "/navigation_controller/simple_page_1.html"));
+ DoReplaceStateWhilePending(shell(), url, url, "x");
+}
+
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+ NavigationTypeClassification_On1InPageTo1While1Pending) {
+ GURL url(embedded_test_server()->GetURL(
+ "/navigation_controller/simple_page_1.html"));
+ DoReplaceStateWhilePending(shell(), url, url, "simple_page_1.html");
+}
+
+// Ensure the renderer process does not get confused about the current entry
+// due to subframes and replaced entries. See https://crbug.com/480201.
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+ PreventSpoofFromSubframeAndReplace) {
+ // Start at an initial URL.
+ GURL url1(embedded_test_server()->GetURL(
+ "/navigation_controller/simple_page_1.html"));
+ NavigateToURL(shell(), url1);
+
+ // Now go to a page with a real iframe.
+ GURL url2(embedded_test_server()->GetURL(
+ "/navigation_controller/page_with_data_iframe.html"));
+ NavigateToURL(shell(), url2);
+
+ // It is safe to obtain the root frame tree node here, as it doesn't change.
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+ ASSERT_EQ(1U, root->child_count());
+ ASSERT_NE(nullptr, root->child_at(0));
+
+ {
+ // Navigate in the iframe.
+ FrameNavigateParamsCapturer capturer(root->child_at(0));
+ GURL frame_url(embedded_test_server()->GetURL(
+ "/navigation_controller/simple_page_2.html"));
+ NavigateFrameToURL(root->child_at(0), frame_url);
+ capturer.Wait();
+ EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.details().type);
+ }
+
+ {
+ // Go back in the iframe.
+ TestNavigationObserver back_load_observer(shell()->web_contents());
+ shell()->web_contents()->GetController().GoBack();
+ back_load_observer.Wait();
+ }
+
+ {
+ // Go forward in the iframe.
+ TestNavigationObserver forward_load_observer(shell()->web_contents());
+ shell()->web_contents()->GetController().GoForward();
+ forward_load_observer.Wait();
+ }
+
+ GURL url3(embedded_test_server()->GetURL(
+ "/navigation_controller/page_with_iframe.html"));
+ {
+ // location.replace() to cause an inert commit.
+ TestNavigationObserver replace_load_observer(shell()->web_contents());
+ std::string script = "location.replace('" + url3.spec() + "')";
+ EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
+ replace_load_observer.Wait();
+ }
+
+ {
+ // Go back to url2.
+ TestNavigationObserver back_load_observer(shell()->web_contents());
+ shell()->web_contents()->GetController().GoBack();
+ back_load_observer.Wait();
+
+ // Make sure the URL is correct for both the entry and the main frame, and
+ // that the process hasn't been killed for showing a spoof.
+ EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
+ EXPECT_EQ(url2, shell()->web_contents()->GetLastCommittedURL());
+ EXPECT_EQ(url2, root->current_url());
+ }
+
+ {
+ // Go back to reset main frame entirely.
+ TestNavigationObserver back_load_observer(shell()->web_contents());
+ shell()->web_contents()->GetController().GoBack();
+ back_load_observer.Wait();
+ EXPECT_EQ(url1, shell()->web_contents()->GetLastCommittedURL());
+ EXPECT_EQ(url1, root->current_url());
+ }
+
+ {
+ // Go forward.
+ TestNavigationObserver back_load_observer(shell()->web_contents());
+ shell()->web_contents()->GetController().GoForward();
+ back_load_observer.Wait();
+ EXPECT_EQ(url2, shell()->web_contents()->GetLastCommittedURL());
+ EXPECT_EQ(url2, root->current_url());
+ }
+
+ {
+ // Go forward to the replaced URL.
+ TestNavigationObserver forward_load_observer(shell()->web_contents());
+ shell()->web_contents()->GetController().GoForward();
+ forward_load_observer.Wait();
+
+ // Make sure the URL is correct for both the entry and the main frame, and
+ // that the process hasn't been killed for showing a spoof.
+ EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
+ EXPECT_EQ(url3, shell()->web_contents()->GetLastCommittedURL());
+ EXPECT_EQ(url3, root->current_url());
+ }
+}
+
+// Ensure the renderer process does not get killed if the main frame URL's path
+// changes when going back in a subframe, since this is currently possible after
+// a replaceState in the main frame (thanks to https://crbug.com/373041).
+// See https:///crbug.com/486916.
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+ SubframeBackFromReplaceState) {
+ // Start at a page with a real iframe.
+ GURL url1(embedded_test_server()->GetURL(
+ "/navigation_controller/page_with_data_iframe.html"));
+ NavigateToURL(shell(), url1);
+
+ // It is safe to obtain the root frame tree node here, as it doesn't change.
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+ ASSERT_EQ(1U, root->child_count());
+ ASSERT_NE(nullptr, root->child_at(0));
+
+ {
+ // Navigate in the iframe.
+ FrameNavigateParamsCapturer capturer(root->child_at(0));
+ GURL frame_url(embedded_test_server()->GetURL(
+ "/navigation_controller/simple_page_2.html"));
+ NavigateFrameToURL(root->child_at(0), frame_url);
+ capturer.Wait();
+ EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.details().type);
+ }
+
+ {
+ // history.replaceState().
+ FrameNavigateParamsCapturer capturer(root);
+ std::string script =
+ "history.replaceState({}, 'replaced', 'replaced')";
+ EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
+ capturer.Wait();
+ }
+
+ {
+ // Go back in the iframe.
+ TestNavigationObserver back_load_observer(shell()->web_contents());
+ shell()->web_contents()->GetController().GoBack();
+ back_load_observer.Wait();
+ }
+
+ // For now, we expect the main frame's URL to revert. This won't happen once
+ // https://crbug.com/373041 is fixed.
+ EXPECT_EQ(url1, shell()->web_contents()->GetLastCommittedURL());
+
+ // Make sure the renderer process has not been killed.
+ EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
+}
+
+namespace {
+
+class FailureWatcher : public WebContentsObserver {
+ public:
+ // Observes failure for the specified |node|.
+ explicit FailureWatcher(FrameTreeNode* node)
+ : WebContentsObserver(
+ node->current_frame_host()->delegate()->GetAsWebContents()),
+ frame_tree_node_id_(node->frame_tree_node_id()),
+ message_loop_runner_(new MessageLoopRunner) {}
+
+ void Wait() {
+ message_loop_runner_->Run();
+ }
+
+ private:
+ void DidFailLoad(RenderFrameHost* render_frame_host,
+ const GURL& validated_url,
+ int error_code,
+ const base::string16& error_description) override {
+ RenderFrameHostImpl* rfh =
+ static_cast<RenderFrameHostImpl*>(render_frame_host);
+ if (rfh->frame_tree_node()->frame_tree_node_id() != frame_tree_node_id_)
+ return;
+
+ message_loop_runner_->Quit();
+ }
+
+ void DidFailProvisionalLoad(
+ RenderFrameHost* render_frame_host,
+ const GURL& validated_url,
+ int error_code,
+ const base::string16& error_description) override {
+ RenderFrameHostImpl* rfh =
+ static_cast<RenderFrameHostImpl*>(render_frame_host);
+ if (rfh->frame_tree_node()->frame_tree_node_id() != frame_tree_node_id_)
+ return;
+
+ message_loop_runner_->Quit();
+ }
+
+ // The id of the FrameTreeNode whose navigations to observe.
+ int frame_tree_node_id_;
+
+ // The MessageLoopRunner used to spin the message loop.
+ scoped_refptr<MessageLoopRunner> message_loop_runner_;
+};
+
+} // namespace
+
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+ StopCausesFailureDespiteJavaScriptURL) {
+ NavigationControllerImpl& controller =
+ static_cast<NavigationControllerImpl&>(
+ shell()->web_contents()->GetController());
+
+ FrameTreeNode* root =
+ static_cast<WebContentsImpl*>(shell()->web_contents())->
+ GetFrameTree()->root();
+
+ // Start with a normal page.
+ GURL url1(embedded_test_server()->GetURL(
+ "/navigation_controller/simple_page_1.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), url1));
+
+ // Have the user decide to go to a different page which is very slow.
+ StallDelegate stall_delegate;
+ ResourceDispatcherHost::Get()->SetDelegate(&stall_delegate);
+ GURL url2(embedded_test_server()->GetURL(
+ "/navigation_controller/simple_page_2.html"));
+ controller.LoadURL(url2, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
+
+ // That should be the pending entry.
+ NavigationEntryImpl* entry = controller.GetPendingEntry();
+ ASSERT_NE(nullptr, entry);
+ EXPECT_EQ(url2, entry->GetURL());
+
+ // Loading a JavaScript URL shouldn't affect the ability to stop.
+ {
+ FailureWatcher watcher(root);
+ GURL js("javascript:(function(){})()");
+ controller.LoadURL(js, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
+ // This LoadURL ends up purging the pending entry, which is why this is
+ // tricky.
+ EXPECT_EQ(nullptr, controller.GetPendingEntry());
+ shell()->web_contents()->Stop();
+ watcher.Wait();
+ }
+
+ ResourceDispatcherHost::Get()->SetDelegate(nullptr);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/frame_host/navigation_controller_impl_unittest.cc b/chromium/content/browser/frame_host/navigation_controller_impl_unittest.cc
index ae7ad90f1e4..cd10a01267c 100644
--- a/chromium/content/browser/frame_host/navigation_controller_impl_unittest.cc
+++ b/chromium/content/browser/frame_host/navigation_controller_impl_unittest.cc
@@ -4,6 +4,7 @@
#include "base/basictypes.h"
#include "base/bind.h"
+#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/stl_util.h"
@@ -11,10 +12,13 @@
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "content/browser/frame_host/cross_site_transferring_request.h"
+#include "content/browser/frame_host/frame_navigation_entry.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_entry_screenshot_manager.h"
+#include "content/browser/frame_host/navigation_request.h"
#include "content/browser/frame_host/navigator.h"
+#include "content/browser/frame_host/navigator_impl.h"
#include "content/browser/site_instance_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/common/frame_messages.h"
@@ -25,7 +29,9 @@
#include "content/public/browser/render_view_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/common/page_state.h"
+#include "content/public/common/page_type.h"
#include "content/public/common/url_constants.h"
#include "content/public/test/mock_render_process_host.h"
#include "content/public/test/test_notification_tracker.h"
@@ -81,7 +87,7 @@ class MockScreenshotManager : public content::NavigationEntryScreenshotManager {
1, 1, kAlpha_8_SkColorType, kPremul_SkAlphaType));
bitmap.eraseARGB(0, 0, 0, 0);
encoding_screenshot_in_progress_ = true;
- OnScreenshotTaken(entry->GetUniqueID(), true, bitmap);
+ OnScreenshotTaken(entry->GetUniqueID(), bitmap, content::READBACK_SUCCESS);
WaitUntilScreenshotIsReady();
}
@@ -211,6 +217,33 @@ class NavigationControllerTest
return static_cast<NavigationControllerImpl&>(controller());
}
+ bool HasNavigationRequest() {
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation)) {
+ return contents()->GetFrameTree()->root()->navigation_request() !=
+ nullptr;
+ }
+ return process()->sink().GetFirstMessageMatching(FrameMsg_Navigate::ID)
+ != nullptr;
+ }
+
+ const GURL GetLastNavigationURL() {
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation)) {
+ NavigationRequest* navigation_request =
+ contents()->GetFrameTree()->root()->navigation_request();
+ CHECK(navigation_request);
+ return navigation_request->common_params().url;
+ }
+ const IPC::Message* message =
+ process()->sink().GetFirstMessageMatching(FrameMsg_Navigate::ID);
+ CHECK(message);
+ Tuple<CommonNavigationParams, StartNavigationParams,
+ RequestNavigationParams> nav_params;
+ FrameMsg_Navigate::Read(message, &nav_params);
+ return get<0>(nav_params).url;
+ }
+
protected:
GURL navigated_url_;
size_t navigation_entry_committed_counter_;
@@ -224,10 +257,6 @@ void RegisterForAllNavNotifications(TestNotificationTracker* tracker,
Source<NavigationController>(controller));
}
-SiteInstance* GetSiteInstanceFromEntry(NavigationEntry* entry) {
- return NavigationEntryImpl::FromNavigationEntry(entry)->site_instance();
-}
-
class TestWebContentsDelegate : public WebContentsDelegate {
public:
explicit TestWebContentsDelegate() :
@@ -243,7 +272,7 @@ class TestWebContentsDelegate : public WebContentsDelegate {
}
// Keep track of whether the tab has notified us of a navigation state change.
- void NavigationStateChanged(const WebContents* source,
+ void NavigationStateChanged(WebContents* source,
InvalidateTypes changed_flags) override {
navigation_state_change_count_++;
}
@@ -286,7 +315,9 @@ TEST_F(NavigationControllerTest, GoToOffset) {
urls[i] = GURL(base::StringPrintf("http://www.a.com/%d", i));
}
- main_test_rfh()->SendNavigate(0, urls[0]);
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(urls[0], true);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(0, 0, true, urls[0]);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
EXPECT_EQ(urls[0], controller.GetVisibleEntry()->GetVirtualURL());
@@ -295,7 +326,9 @@ TEST_F(NavigationControllerTest, GoToOffset) {
EXPECT_FALSE(controller.CanGoToOffset(1));
for (int i = 1; i <= 4; ++i) {
- main_test_rfh()->SendNavigate(i, urls[i]);
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(urls[i], true);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(i, 0, true, urls[i]);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
EXPECT_EQ(urls[i], controller.GetVisibleEntry()->GetVirtualURL());
@@ -327,10 +360,12 @@ TEST_F(NavigationControllerTest, GoToOffset) {
for (int test = 0; test < NUM_TESTS; ++test) {
int offset = test_offsets[test];
controller.GoToOffset(offset);
+ int entry_id = controller.GetPendingEntry()->GetUniqueID();
url_index += offset;
// Check that the GoToOffset will land on the expected page.
EXPECT_EQ(urls[url_index], controller.GetPendingEntry()->GetVirtualURL());
- main_test_rfh()->SendNavigate(url_index, urls[url_index]);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(url_index, entry_id, false, urls[url_index]);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
// Check that we can go to any valid offset into the history.
@@ -352,6 +387,7 @@ TEST_F(NavigationControllerTest, LoadURL) {
controller.LoadURL(
url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ int entry_id = controller.GetPendingEntry()->GetUniqueID();
// Creating a pending notification should not have issued any of the
// notifications we're listening for.
EXPECT_EQ(0U, notifications.size());
@@ -374,7 +410,8 @@ TEST_F(NavigationControllerTest, LoadURL) {
// We should have gotten no notifications from the preceeding checks.
EXPECT_EQ(0U, notifications.size());
- main_test_rfh()->SendNavigate(0, url1);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(0, entry_id, true, url1);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -388,8 +425,7 @@ TEST_F(NavigationControllerTest, LoadURL) {
EXPECT_FALSE(controller.CanGoBack());
EXPECT_FALSE(controller.CanGoForward());
EXPECT_EQ(contents()->GetMaxPageID(), 0);
- EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
- controller.GetLastCommittedEntry())->bindings());
+ EXPECT_EQ(0, controller.GetLastCommittedEntry()->bindings());
// The timestamp should have been set.
EXPECT_FALSE(controller.GetVisibleEntry()->GetTimestamp().is_null());
@@ -397,6 +433,7 @@ TEST_F(NavigationControllerTest, LoadURL) {
// Load another...
controller.LoadURL(
url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ entry_id = controller.GetPendingEntry()->GetUniqueID();
// The load should now be pending.
EXPECT_EQ(controller.GetEntryCount(), 1);
@@ -414,8 +451,8 @@ TEST_F(NavigationControllerTest, LoadURL) {
// Simulate the beforeunload ack for the cross-site transition, and then the
// commit.
- main_test_rfh()->SendBeforeUnloadACK(true);
- contents()->GetPendingMainFrame()->SendNavigate(1, url2);
+ main_test_rfh()->PrepareForCommit();
+ contents()->GetPendingMainFrame()->SendNavigate(1, entry_id, true, url2);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -455,19 +492,22 @@ TEST_F(NavigationControllerTest, LoadURLSameTime) {
controller.LoadURL(
url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ int entry_id = controller.GetPendingEntry()->GetUniqueID();
- main_test_rfh()->SendNavigate(0, url1);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(0, entry_id, true, url1);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
// Load another...
controller.LoadURL(
url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ entry_id = controller.GetPendingEntry()->GetUniqueID();
// Simulate the beforeunload ack for the cross-site transition, and then the
// commit.
- main_test_rfh()->SendBeforeUnloadACK(true);
- main_test_rfh()->SendNavigate(1, url2);
+ main_test_rfh()->PrepareForCommit();
+ contents()->GetPendingMainFrame()->SendNavigate(1, entry_id, true, url2);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -522,9 +562,7 @@ TEST_F(NavigationControllerTest, LoadURLWithParams) {
load_params.transferred_global_request_id = GlobalRequestID(2, 3);
controller.LoadURLWithParams(load_params);
- NavigationEntryImpl* entry =
- NavigationEntryImpl::FromNavigationEntry(
- controller.GetPendingEntry());
+ NavigationEntryImpl* entry = controller.GetPendingEntry();
// The timestamp should not have been set yet.
ASSERT_TRUE(entry);
@@ -544,9 +582,7 @@ TEST_F(NavigationControllerTest, LoadURLWithExtraParams_Data) {
load_params.override_user_agent = NavigationController::UA_OVERRIDE_FALSE;
controller.LoadURLWithParams(load_params);
- NavigationEntryImpl* entry =
- NavigationEntryImpl::FromNavigationEntry(
- controller.GetPendingEntry());
+ NavigationEntryImpl* entry = controller.GetPendingEntry();
CheckNavigationEntryMatchLoadParams(load_params, entry);
}
@@ -570,9 +606,7 @@ TEST_F(NavigationControllerTest, LoadURLWithExtraParams_HttpPost) {
load_params.browser_initiated_post_data = data.get();
controller.LoadURLWithParams(load_params);
- NavigationEntryImpl* entry =
- NavigationEntryImpl::FromNavigationEntry(
- controller.GetPendingEntry());
+ NavigationEntryImpl* entry = controller.GetPendingEntry();
CheckNavigationEntryMatchLoadParams(load_params, entry);
}
@@ -590,8 +624,11 @@ TEST_F(NavigationControllerTest, LoadURL_SamePage) {
controller.LoadURL(
url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ int entry_id = controller.GetPendingEntry()->GetUniqueID();
EXPECT_EQ(0U, notifications.size());
- main_test_rfh()->SendNavigate(0, url1);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigateWithTransition(
+ 0, entry_id, true, url1, ui::PAGE_TRANSITION_TYPED);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -601,8 +638,11 @@ TEST_F(NavigationControllerTest, LoadURL_SamePage) {
controller.LoadURL(
url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ entry_id = controller.GetPendingEntry()->GetUniqueID();
EXPECT_EQ(0U, notifications.size());
- main_test_rfh()->SendNavigate(0, url1);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigateWithTransition(
+ 0, entry_id, false, url1, ui::PAGE_TRANSITION_TYPED);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -636,11 +676,14 @@ TEST_F(NavigationControllerTest, LoadURL_SamePage_DifferentMethod) {
url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = 0;
+ params.nav_entry_id = controller.GetPendingEntry()->GetUniqueID();
+ params.did_create_new_entry = true;
params.url = url1;
params.transition = ui::PAGE_TRANSITION_TYPED;
params.is_post = true;
params.post_id = 123;
params.page_state = PageState::CreateForTesting(url1, false, 0, 0);
+ main_test_rfh()->PrepareForCommit();
main_test_rfh()->SendNavigateWithParams(&params);
// The post data should be visible.
@@ -651,7 +694,10 @@ TEST_F(NavigationControllerTest, LoadURL_SamePage_DifferentMethod) {
controller.LoadURL(
url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- main_test_rfh()->SendNavigate(0, url1);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigateWithTransition(
+ 0, controller.GetPendingEntry()->GetUniqueID(),
+ false, url1, ui::PAGE_TRANSITION_TYPED);
// We should not have produced a new session history entry.
ASSERT_EQ(controller.GetVisibleEntry(), entry);
@@ -672,8 +718,10 @@ TEST_F(NavigationControllerTest, LoadURL_Discarded) {
controller.LoadURL(
url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ int entry_id = controller.GetPendingEntry()->GetUniqueID();
EXPECT_EQ(0U, notifications.size());
- main_test_rfh()->SendNavigate(0, url1);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(0, entry_id, true, url1);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -711,15 +759,17 @@ TEST_F(NavigationControllerTest, LoadURL_NoPending) {
const GURL kExistingURL1("http://eh");
controller.LoadURL(
kExistingURL1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- main_test_rfh()->SendNavigate(0, kExistingURL1);
+ int entry_id = controller.GetPendingEntry()->GetUniqueID();
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(0, entry_id, true, kExistingURL1);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
// Do a new navigation without making a pending one.
const GURL kNewURL("http://see");
- main_test_rfh()->SendNavigate(99, kNewURL);
+ main_test_rfh()->NavigateAndCommitRendererInitiated(99, true, kNewURL);
- // There should no longer be any pending entry, and the third navigation we
+ // There should no longer be any pending entry, and the second navigation we
// just made should be committed.
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -741,7 +791,9 @@ TEST_F(NavigationControllerTest, LoadURL_NewPending) {
const GURL kExistingURL1("http://eh");
controller.LoadURL(
kExistingURL1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- main_test_rfh()->SendNavigate(0, kExistingURL1);
+ int entry_id = controller.GetPendingEntry()->GetUniqueID();
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(0, entry_id, true, kExistingURL1);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -751,10 +803,14 @@ TEST_F(NavigationControllerTest, LoadURL_NewPending) {
kExistingURL2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
EXPECT_EQ(0U, notifications.size());
- // After the beforeunload but before it commits, do a new navigation.
- main_test_rfh()->SendBeforeUnloadACK(true);
+ // After the beforeunload but before it commits...
+ main_test_rfh()->PrepareForCommit();
+
+ // ... Do a new navigation.
const GURL kNewURL("http://see");
- contents()->GetPendingMainFrame()->SendNavigate(3, kNewURL);
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(kNewURL, true);
+ main_test_rfh()->PrepareForCommit();
+ contents()->GetMainFrame()->SendNavigate(3, 0, true, kNewURL);
// There should no longer be any pending entry, and the third navigation we
// just made should be committed.
@@ -777,14 +833,18 @@ TEST_F(NavigationControllerTest, LoadURL_ExistingPending) {
const GURL kExistingURL1("http://foo/eh");
controller.LoadURL(
kExistingURL1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- main_test_rfh()->SendNavigate(0, kExistingURL1);
+ int entry_id = controller.GetPendingEntry()->GetUniqueID();
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(0, entry_id, true, kExistingURL1);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
const GURL kExistingURL2("http://foo/bee");
controller.LoadURL(
kExistingURL2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- main_test_rfh()->SendNavigate(1, kExistingURL2);
+ entry_id = controller.GetPendingEntry()->GetUniqueID();
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(1, entry_id, true, kExistingURL2);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -797,10 +857,11 @@ TEST_F(NavigationControllerTest, LoadURL_ExistingPending) {
// Before that commits, do a new navigation.
const GURL kNewURL("http://foo/see");
- LoadCommittedDetails details;
- main_test_rfh()->SendNavigate(3, kNewURL);
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(kNewURL, true);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(3, 0, true, kNewURL);
- // There should no longer be any pending entry, and the third navigation we
+ // There should no longer be any pending entry, and the new navigation we
// just made should be committed.
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -821,9 +882,11 @@ TEST_F(NavigationControllerTest, LoadURL_PrivilegedPending) {
const GURL kExistingURL1("http://privileged");
controller.LoadURL(
kExistingURL1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ int entry_id = controller.GetPendingEntry()->GetUniqueID();
// Pretend it has bindings so we can tell if we incorrectly copy it.
main_test_rfh()->GetRenderViewHost()->AllowBindings(2);
- main_test_rfh()->SendNavigate(0, kExistingURL1);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(0, entry_id, true, kExistingURL1);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -831,9 +894,10 @@ TEST_F(NavigationControllerTest, LoadURL_PrivilegedPending) {
const GURL kExistingURL2("http://foo/eh");
controller.LoadURL(
kExistingURL2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- main_test_rfh()->SendBeforeUnloadACK(true);
+ entry_id = controller.GetPendingEntry()->GetUniqueID();
+ main_test_rfh()->PrepareForCommit();
TestRenderFrameHost* foo_rfh = contents()->GetPendingMainFrame();
- foo_rfh->SendNavigate(1, kExistingURL2);
+ foo_rfh->SendNavigate(1, entry_id, true, kExistingURL2);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -844,23 +908,22 @@ TEST_F(NavigationControllerTest, LoadURL_PrivilegedPending) {
EXPECT_EQ(0U, notifications.size());
EXPECT_EQ(0, controller.GetPendingEntryIndex());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
- EXPECT_EQ(2, NavigationEntryImpl::FromNavigationEntry(
- controller.GetPendingEntry())->bindings());
+ EXPECT_EQ(2, controller.GetPendingEntry()->bindings());
// Before that commits, do a new navigation.
const GURL kNewURL("http://foo/bee");
- LoadCommittedDetails details;
- foo_rfh->SendNavigate(3, kNewURL);
+ foo_rfh->SendRendererInitiatedNavigationRequest(kNewURL, true);
+ foo_rfh->PrepareForCommit();
+ foo_rfh->SendNavigate(3, 0, true, kNewURL);
- // There should no longer be any pending entry, and the third navigation we
+ // There should no longer be any pending entry, and the new navigation we
// just made should be committed.
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
EXPECT_EQ(-1, controller.GetPendingEntryIndex());
EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(kNewURL, controller.GetVisibleEntry()->GetURL());
- EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
- controller.GetLastCommittedEntry())->bindings());
+ EXPECT_EQ(0, controller.GetLastCommittedEntry()->bindings());
}
// Tests navigating to an existing URL when there is a pending new navigation.
@@ -875,18 +938,26 @@ TEST_F(NavigationControllerTest, LoadURL_BackPreemptsPending) {
const GURL kExistingURL1("http://foo/eh");
controller.LoadURL(
kExistingURL1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- main_test_rfh()->SendNavigate(0, kExistingURL1);
+ int entry_id = controller.GetPendingEntry()->GetUniqueID();
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(0, entry_id, true, kExistingURL1);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
const GURL kExistingURL2("http://foo/bee");
controller.LoadURL(
kExistingURL2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- main_test_rfh()->SendNavigate(1, kExistingURL2);
+ entry_id = controller.GetPendingEntry()->GetUniqueID();
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(1, entry_id, true, kExistingURL2);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
- // Now make a pending new navigation.
+ // A back navigation comes in from the renderer...
+ controller.GoToOffset(-1);
+ entry_id = controller.GetPendingEntry()->GetUniqueID();
+
+ // ...while the user tries to navigate to a new page...
const GURL kNewURL("http://foo/see");
controller.LoadURL(
kNewURL, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
@@ -894,11 +965,12 @@ TEST_F(NavigationControllerTest, LoadURL_BackPreemptsPending) {
EXPECT_EQ(-1, controller.GetPendingEntryIndex());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
- // Before that commits, a back navigation from the renderer commits.
- main_test_rfh()->SendNavigate(0, kExistingURL1);
+ // ...and the back navigation commits.
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(0, entry_id, false, kExistingURL1);
- // There should no longer be any pending entry, and the back navigation we
- // just made should be committed.
+ // There should no longer be any pending entry, and the back navigation should
+ // be committed.
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
EXPECT_EQ(-1, controller.GetPendingEntryIndex());
@@ -933,15 +1005,22 @@ TEST_F(NavigationControllerTest, LoadURL_IgnorePreemptsPending) {
EXPECT_EQ(1, delegate->navigation_state_change_count());
// Before that commits, a document.write and location.reload can cause the
- // renderer to send a FrameNavigate with page_id -1.
- main_test_rfh()->SendNavigate(-1, kExistingURL);
+ // renderer to send a FrameNavigate with page_id -1 and nav_entry_id 0.
+ // PlzNavigate: this will stop the old navigation and start a new one.
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(kExistingURL, true);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(-1, 0, false, kExistingURL);
// This should clear the pending entry and notify of a navigation state
// change, so that we do not keep displaying kNewURL.
EXPECT_EQ(-1, controller.GetPendingEntryIndex());
EXPECT_FALSE(controller.GetPendingEntry());
EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex());
- EXPECT_EQ(2, delegate->navigation_state_change_count());
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation))
+ EXPECT_EQ(4, delegate->navigation_state_change_count());
+ else
+ EXPECT_EQ(2, delegate->navigation_state_change_count());
contents()->SetDelegate(NULL);
}
@@ -963,6 +1042,7 @@ TEST_F(NavigationControllerTest, LoadURL_AbortDoesntCancelPending) {
const GURL kNewURL("http://eh");
controller.LoadURL(
kNewURL, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ main_test_rfh()->PrepareForCommit();
EXPECT_EQ(0U, notifications.size());
EXPECT_EQ(-1, controller.GetPendingEntryIndex());
EXPECT_TRUE(controller.GetPendingEntry());
@@ -1009,7 +1089,9 @@ TEST_F(NavigationControllerTest, LoadURL_RedirectAbortDoesntShowPendingURL) {
const GURL kExistingURL("http://foo/eh");
controller.LoadURL(kExistingURL, content::Referrer(),
ui::PAGE_TRANSITION_TYPED, std::string());
- main_test_rfh()->SendNavigate(1, kExistingURL);
+ int entry_id = controller.GetPendingEntry()->GetUniqueID();
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(1, entry_id, true, kExistingURL);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -1080,16 +1162,17 @@ TEST_F(NavigationControllerTest, LoadURL_WithBindings) {
controller.LoadURL(
url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
EXPECT_EQ(NavigationEntryImpl::kInvalidBindings,
- NavigationEntryImpl::FromNavigationEntry(
- controller.GetPendingEntry())->bindings());
+ controller.GetPendingEntry()->bindings());
+ int entry1_id = controller.GetPendingEntry()->GetUniqueID();
// Commit.
TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
- orig_rfh->SendNavigate(0, url1);
+ orig_rfh->PrepareForCommit();
+ orig_rfh->SendNavigate(0, entry1_id, true, url1);
EXPECT_EQ(controller.GetEntryCount(), 1);
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
- EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
- controller.GetLastCommittedEntry())->bindings());
+ EXPECT_EQ(0, controller.GetLastCommittedEntry()->bindings());
+ entry1_id = controller.GetLastCommittedEntry()->GetUniqueID();
// Manually increase the number of active frames in the SiteInstance
// that orig_rfh belongs to, to prevent it from being destroyed when
@@ -1102,25 +1185,24 @@ TEST_F(NavigationControllerTest, LoadURL_WithBindings) {
// privileged url.
controller.LoadURL(
url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- orig_rfh->SendBeforeUnloadACK(true);
+ int entry_id = controller.GetPendingEntry()->GetUniqueID();
+ orig_rfh->PrepareForCommit();
TestRenderFrameHost* new_rfh = contents()->GetPendingMainFrame();
new_rfh->GetRenderViewHost()->AllowBindings(1);
- new_rfh->SendNavigate(1, url2);
+ new_rfh->SendNavigate(1, entry_id, true, url2);
// The second load should be committed, and bindings should be remembered.
EXPECT_EQ(controller.GetEntryCount(), 2);
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
EXPECT_TRUE(controller.CanGoBack());
- EXPECT_EQ(1, NavigationEntryImpl::FromNavigationEntry(
- controller.GetLastCommittedEntry())->bindings());
+ EXPECT_EQ(1, controller.GetLastCommittedEntry()->bindings());
// Going back, the first entry should still appear unprivileged.
controller.GoBack();
- new_rfh->SendBeforeUnloadACK(true);
- orig_rfh->SendNavigate(0, url1);
+ new_rfh->PrepareForCommit();
+ orig_rfh->SendNavigate(0, entry1_id, false, url1);
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
- EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
- controller.GetLastCommittedEntry())->bindings());
+ EXPECT_EQ(0, controller.GetLastCommittedEntry()->bindings());
}
TEST_F(NavigationControllerTest, Reload) {
@@ -1132,12 +1214,16 @@ TEST_F(NavigationControllerTest, Reload) {
controller.LoadURL(
url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ int entry_id = controller.GetPendingEntry()->GetUniqueID();
EXPECT_EQ(0U, notifications.size());
- main_test_rfh()->SendNavigate(0, url1);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(0, entry_id, true, url1);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
ASSERT_TRUE(controller.GetVisibleEntry());
controller.GetVisibleEntry()->SetTitle(base::ASCIIToUTF16("Title"));
+ entry_id = controller.GetLastCommittedEntry()->GetUniqueID();
+
controller.Reload(true);
EXPECT_EQ(0U, notifications.size());
@@ -1157,7 +1243,8 @@ TEST_F(NavigationControllerTest, Reload) {
// See http://crbug.com/96041.
EXPECT_TRUE(controller.GetVisibleEntry()->GetTitle().empty());
- main_test_rfh()->SendNavigate(0, url1);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(0, entry_id, false, url1);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -1186,14 +1273,18 @@ TEST_F(NavigationControllerTest, Reload_GeneratesNewPage) {
controller.LoadURL(
url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- main_test_rfh()->SendNavigate(0, url1);
+ int entry_id = controller.GetPendingEntry()->GetUniqueID();
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(0, entry_id, true, url1);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
+ entry_id = controller.GetLastCommittedEntry()->GetUniqueID();
controller.Reload(true);
EXPECT_EQ(0U, notifications.size());
- main_test_rfh()->SendNavigate(1, url2);
+ main_test_rfh()->PrepareForCommitWithServerRedirect(url2);
+ main_test_rfh()->SendNavigate(1, entry_id, true, url2);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -1216,12 +1307,13 @@ TEST_F(NavigationControllerTest, ReloadWithGuest) {
const GURL url1("http://foo1");
controller.LoadURL(
url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- main_test_rfh()->SendNavigate(0, url1);
+ int entry_id = controller.GetPendingEntry()->GetUniqueID();
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(0, entry_id, true, url1);
ASSERT_TRUE(controller.GetVisibleEntry());
// Make the entry believe its RenderProcessHost is a guest.
- NavigationEntryImpl* entry1 =
- NavigationEntryImpl::FromNavigationEntry(controller.GetVisibleEntry());
+ NavigationEntryImpl* entry1 = controller.GetVisibleEntry();
reinterpret_cast<MockRenderProcessHost*>(
entry1->site_instance()->GetProcess())->set_is_isolated_guest(true);
@@ -1234,8 +1326,7 @@ TEST_F(NavigationControllerTest, ReloadWithGuest) {
EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
EXPECT_EQ(controller.GetPendingEntryIndex(), 0);
- NavigationEntryImpl* entry2 =
- NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry());
+ NavigationEntryImpl* entry2 = controller.GetPendingEntry();
EXPECT_EQ(entry1, entry2);
}
@@ -1251,11 +1342,14 @@ TEST_F(NavigationControllerTest, ReloadOriginalRequestURL) {
// Load up the original URL, but get redirected.
controller.LoadURL(
original_url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ int entry_id = controller.GetPendingEntry()->GetUniqueID();
EXPECT_EQ(0U, notifications.size());
- main_test_rfh()->SendNavigateWithOriginalRequestURL(
- 0, final_url, original_url);
+ main_test_rfh()->PrepareForCommitWithServerRedirect(final_url);
+ main_test_rfh()->SendNavigateWithOriginalRequestURL(0, entry_id, true,
+ final_url, original_url);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
+ entry_id = controller.GetLastCommittedEntry()->GetUniqueID();
// The NavigationEntry should save both the original URL and the final
// redirected URL.
@@ -1284,7 +1378,8 @@ TEST_F(NavigationControllerTest, ReloadOriginalRequestURL) {
EXPECT_TRUE(controller.GetVisibleEntry()->GetTitle().empty());
// Send that the navigation has proceeded; say it got redirected again.
- main_test_rfh()->SendNavigate(0, final_url);
+ main_test_rfh()->PrepareForCommitWithServerRedirect(final_url);
+ main_test_rfh()->SendNavigate(0, entry_id, false, final_url);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -1304,9 +1399,21 @@ TEST_F(NavigationControllerTest, ReloadOriginalRequestURL) {
// commit.
TEST_F(NavigationControllerTest, ResetEntryValuesAfterCommit) {
NavigationControllerImpl& controller = controller_impl();
- const GURL url1("http://foo1");
+
+ // The value of "should replace entry" will be tested, but it's an error to
+ // specify it when there are no entries. Create a simple entry to be replaced.
+ const GURL url0("http://foo/0");
+ controller.LoadURL(
+ url0, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ int entry_id = controller.GetPendingEntry()->GetUniqueID();
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(0, entry_id, true, url0);
+
+ // Set up the pending entry.
+ const GURL url1("http://foo/1");
controller.LoadURL(
url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ entry_id = controller.GetPendingEntry()->GetUniqueID();
// Set up some sample values.
const unsigned char* raw_data =
@@ -1316,12 +1423,9 @@ TEST_F(NavigationControllerTest, ResetEntryValuesAfterCommit) {
scoped_refptr<base::RefCountedBytes> post_data =
base::RefCountedBytes::TakeVector(&post_data_vector);
GlobalRequestID transfer_id(3, 4);
- std::vector<GURL> redirects;
- redirects.push_back(GURL("http://foo2"));
// Set non-persisted values on the pending entry.
- NavigationEntryImpl* pending_entry =
- NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry());
+ NavigationEntryImpl* pending_entry = controller.GetPendingEntry();
pending_entry->SetBrowserInitiatedPostData(post_data.get());
pending_entry->set_is_renderer_initiated(true);
pending_entry->set_transferred_global_request_id(transfer_id);
@@ -1333,13 +1437,13 @@ TEST_F(NavigationControllerTest, ResetEntryValuesAfterCommit) {
EXPECT_TRUE(pending_entry->should_replace_entry());
EXPECT_TRUE(pending_entry->should_clear_history_list());
- main_test_rfh()->SendNavigate(0, url1);
+ // Fake a commit response.
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(1, entry_id, true, url1);
// Certain values that are only used for pending entries get reset after
// commit.
- NavigationEntryImpl* committed_entry =
- NavigationEntryImpl::FromNavigationEntry(
- controller.GetLastCommittedEntry());
+ NavigationEntryImpl* committed_entry = controller.GetLastCommittedEntry();
EXPECT_FALSE(committed_entry->GetBrowserInitiatedPostData());
EXPECT_FALSE(committed_entry->is_renderer_initiated());
EXPECT_EQ(GlobalRequestID(-1, -1),
@@ -1352,27 +1456,28 @@ TEST_F(NavigationControllerTest, ResetEntryValuesAfterCommit) {
TEST_F(NavigationControllerTest, RedirectsAreNotResetByCommit) {
NavigationControllerImpl& controller = controller_impl();
const GURL url1("http://foo1");
+ const GURL url2("http://foo2");
controller.LoadURL(
url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ int entry_id = controller.GetPendingEntry()->GetUniqueID();
// Set up some redirect values.
std::vector<GURL> redirects;
- redirects.push_back(GURL("http://foo2"));
+ redirects.push_back(url2);
// Set redirects on the pending entry.
- NavigationEntryImpl* pending_entry =
- NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry());
+ NavigationEntryImpl* pending_entry = controller.GetPendingEntry();
pending_entry->SetRedirectChain(redirects);
EXPECT_EQ(1U, pending_entry->GetRedirectChain().size());
- EXPECT_EQ(GURL("http://foo2"), pending_entry->GetRedirectChain()[0]);
+ EXPECT_EQ(url2, pending_entry->GetRedirectChain()[0]);
// Normal navigation will preserve redirects in the committed entry.
- main_test_rfh()->SendNavigateWithRedirects(0, url1, redirects);
- NavigationEntryImpl* committed_entry =
- NavigationEntryImpl::FromNavigationEntry(
- controller.GetLastCommittedEntry());
+ main_test_rfh()->PrepareForCommitWithServerRedirect(url2);
+ main_test_rfh()->SendNavigateWithRedirects(0, entry_id, true, url1,
+ redirects);
+ NavigationEntryImpl* committed_entry = controller.GetLastCommittedEntry();
ASSERT_EQ(1U, committed_entry->GetRedirectChain().size());
- EXPECT_EQ(GURL("http://foo2"), committed_entry->GetRedirectChain()[0]);
+ EXPECT_EQ(url2, committed_entry->GetRedirectChain()[0]);
}
// Tests what happens when we navigate back successfully
@@ -1382,16 +1487,17 @@ TEST_F(NavigationControllerTest, Back) {
RegisterForAllNavNotifications(&notifications, &controller);
const GURL url1("http://foo1");
- main_test_rfh()->SendNavigate(0, url1);
+ main_test_rfh()->NavigateAndCommitRendererInitiated(0, true, url1);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
const GURL url2("http://foo2");
- main_test_rfh()->SendNavigate(1, url2);
+ main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url2);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
controller.GoBack();
+ int entry_id = controller.GetPendingEntry()->GetUniqueID();
EXPECT_EQ(0U, notifications.size());
// We should now have a pending navigation to go back.
@@ -1404,14 +1510,14 @@ TEST_F(NavigationControllerTest, Back) {
EXPECT_FALSE(controller.CanGoToOffset(-1));
EXPECT_TRUE(controller.CanGoForward());
EXPECT_TRUE(controller.CanGoToOffset(1));
- EXPECT_FALSE(controller.CanGoToOffset(2)); // Cannot go foward 2 steps.
+ EXPECT_FALSE(controller.CanGoToOffset(2)); // Cannot go forward 2 steps.
// Timestamp for entry 1 should be on or after that of entry 0.
EXPECT_FALSE(controller.GetEntryAtIndex(0)->GetTimestamp().is_null());
EXPECT_GE(controller.GetEntryAtIndex(1)->GetTimestamp(),
controller.GetEntryAtIndex(0)->GetTimestamp());
- main_test_rfh()->SendNavigate(0, url2);
+ main_test_rfh()->SendNavigate(0, entry_id, false, url2);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -1445,13 +1551,18 @@ TEST_F(NavigationControllerTest, Back_GeneratesNewPage) {
controller.LoadURL(
url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- main_test_rfh()->SendNavigate(0, url1);
+ int entry1_id = controller.GetPendingEntry()->GetUniqueID();
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(0, entry1_id, true, url1);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
+ entry1_id = controller.GetLastCommittedEntry()->GetUniqueID();
controller.LoadURL(
url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- main_test_rfh()->SendNavigate(1, url2);
+ int entry_id = controller.GetPendingEntry()->GetUniqueID();
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(1, entry_id, true, url2);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -1467,7 +1578,8 @@ TEST_F(NavigationControllerTest, Back_GeneratesNewPage) {
EXPECT_FALSE(controller.CanGoBack());
EXPECT_TRUE(controller.CanGoForward());
- main_test_rfh()->SendNavigate(2, url3);
+ main_test_rfh()->PrepareForCommitWithServerRedirect(url3);
+ main_test_rfh()->SendNavigate(2, entry1_id, true, url3);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -1493,12 +1605,12 @@ TEST_F(NavigationControllerTest, Back_NewPending) {
const GURL kUrl3("http://foo3");
// First navigate two places so we have some back history.
- main_test_rfh()->SendNavigate(0, kUrl1);
+ main_test_rfh()->NavigateAndCommitRendererInitiated(0, true, kUrl1);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
// controller.LoadURL(kUrl2, ui::PAGE_TRANSITION_TYPED);
- main_test_rfh()->SendNavigate(1, kUrl2);
+ main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, kUrl2);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -1524,18 +1636,27 @@ TEST_F(NavigationControllerTest, Back_OtherBackPending) {
const GURL kUrl3("http://foo/3");
// First navigate three places so we have some back history.
- main_test_rfh()->SendNavigate(0, kUrl1);
- main_test_rfh()->SendNavigate(1, kUrl2);
- main_test_rfh()->SendNavigate(2, kUrl3);
-
- // With nothing pending, say we get a navigation to the second entry.
- main_test_rfh()->SendNavigate(1, kUrl2);
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl1, true);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(0, 0, true, kUrl1);
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl2, true);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(1, 0, true, kUrl2);
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl3, true);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(2, 0, true, kUrl3);
+
+ // With nothing pending, say we get a renderer back navigation request to the
+ // second entry.
+ controller.GoToOffset(-1);
+ int entry_id = controller.GetPendingEntry()->GetUniqueID();
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(1, entry_id, false, kUrl2);
// We know all the entries have the same site instance, so we can just grab
// a random one for looking up other entries.
SiteInstance* site_instance =
- NavigationEntryImpl::FromNavigationEntry(
- controller.GetLastCommittedEntry())->site_instance();
+ controller.GetLastCommittedEntry()->site_instance();
// That second URL should be the last committed and it should have gotten the
// new title.
@@ -1545,16 +1666,21 @@ TEST_F(NavigationControllerTest, Back_OtherBackPending) {
// Now go forward to the last item again and say it was committed.
controller.GoForward();
- main_test_rfh()->SendNavigate(2, kUrl3);
+ entry_id = controller.GetPendingEntry()->GetUniqueID();
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(2, entry_id, false, kUrl3);
// Now start going back one to the second page. It will be pending.
controller.GoBack();
EXPECT_EQ(1, controller.GetPendingEntryIndex());
EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
- // Not synthesize a totally new back event to the first page. This will not
- // match the pending one.
- main_test_rfh()->SendNavigate(0, kUrl1);
+ // Now have the renderer request a navigation back to the first page. This
+ // will not match the pending one.
+ controller.GoToOffset(-2);
+ entry_id = controller.GetPendingEntry()->GetUniqueID();
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(0, entry_id, false, kUrl1);
// The committed navigation should clear the pending entry.
EXPECT_EQ(-1, controller.GetPendingEntryIndex());
@@ -1573,16 +1699,23 @@ TEST_F(NavigationControllerTest, Forward) {
const GURL url1("http://foo1");
const GURL url2("http://foo2");
- main_test_rfh()->SendNavigate(0, url1);
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(url1, true);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(0, 0, true, url1);
+ NavigationEntry* entry1 = controller.GetLastCommittedEntry();
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
- main_test_rfh()->SendNavigate(1, url2);
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(url2, true);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(1, 0, true, url2);
+ NavigationEntry* entry2 = controller.GetLastCommittedEntry();
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
controller.GoBack();
- main_test_rfh()->SendNavigate(0, url1);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(0, entry1->GetUniqueID(), false, url1);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -1606,7 +1739,8 @@ TEST_F(NavigationControllerTest, Forward) {
EXPECT_GE(controller.GetEntryAtIndex(0)->GetTimestamp(),
controller.GetEntryAtIndex(1)->GetTimestamp());
- main_test_rfh()->SendNavigate(1, url2);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(1, entry2->GetUniqueID(), false, url2);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -1638,15 +1772,22 @@ TEST_F(NavigationControllerTest, Forward_GeneratesNewPage) {
const GURL url2("http://foo2");
const GURL url3("http://foo3");
- main_test_rfh()->SendNavigate(0, url1);
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(url1, true);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(0, 0, true, url1);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
+ NavigationEntry* entry1 = controller.GetLastCommittedEntry();
navigation_entry_committed_counter_ = 0;
- main_test_rfh()->SendNavigate(1, url2);
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(url2, true);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(1, 0, true, url2);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
+ NavigationEntry* entry2 = controller.GetLastCommittedEntry();
navigation_entry_committed_counter_ = 0;
controller.GoBack();
- main_test_rfh()->SendNavigate(0, url1);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(0, entry1->GetUniqueID(), false, url1);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -1662,7 +1803,8 @@ TEST_F(NavigationControllerTest, Forward_GeneratesNewPage) {
EXPECT_TRUE(controller.CanGoBack());
EXPECT_FALSE(controller.CanGoForward());
- main_test_rfh()->SendNavigate(2, url3);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(2, entry2->GetUniqueID(), true, url3);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
EXPECT_TRUE(notifications.Check1AndReset(NOTIFICATION_NAV_LIST_PRUNED));
@@ -1676,7 +1818,7 @@ TEST_F(NavigationControllerTest, Forward_GeneratesNewPage) {
EXPECT_FALSE(controller.CanGoForward());
}
-// Two consequent navigation for the same URL entered in should be considered
+// Two consecutive navigations for the same URL entered in should be considered
// as SAME_PAGE navigation even when we are redirected to some other page.
TEST_F(NavigationControllerTest, Redirect) {
NavigationControllerImpl& controller = controller_impl();
@@ -1686,25 +1828,17 @@ TEST_F(NavigationControllerTest, Redirect) {
const GURL url1("http://foo1");
const GURL url2("http://foo2"); // Redirection target
- // First request
+ // First request.
controller.LoadURL(
url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ int entry_id = controller.GetPendingEntry()->GetUniqueID();
EXPECT_EQ(0U, notifications.size());
- main_test_rfh()->SendNavigate(0, url2);
- EXPECT_EQ(1U, navigation_entry_committed_counter_);
- navigation_entry_committed_counter_ = 0;
-
- // Second request
- controller.LoadURL(
- url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
-
- EXPECT_TRUE(controller.GetPendingEntry());
- EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
- EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = 0;
+ params.nav_entry_id = entry_id;
+ params.did_create_new_entry = true;
params.url = url2;
params.transition = ui::PAGE_TRANSITION_SERVER_REDIRECT;
params.redirects.push_back(GURL("http://foo1"));
@@ -1716,6 +1850,23 @@ TEST_F(NavigationControllerTest, Redirect) {
LoadCommittedDetails details;
+ EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
+ &details));
+ EXPECT_EQ(1U, navigation_entry_committed_counter_);
+ navigation_entry_committed_counter_ = 0;
+
+ // Second request.
+ controller.LoadURL(
+ url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ entry_id = controller.GetPendingEntry()->GetUniqueID();
+
+ EXPECT_TRUE(controller.GetPendingEntry());
+ EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
+ EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
+
+ params.nav_entry_id = entry_id;
+ params.did_create_new_entry = false;
+
EXPECT_EQ(0U, notifications.size());
EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
&details));
@@ -1745,37 +1896,47 @@ TEST_F(NavigationControllerTest, PostThenRedirect) {
const GURL url1("http://foo1");
const GURL url2("http://foo2"); // Redirection target
- // First request as POST
+ // First request as POST.
controller.LoadURL(
url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ int entry_id = controller.GetPendingEntry()->GetUniqueID();
controller.GetVisibleEntry()->SetHasPostData(true);
EXPECT_EQ(0U, notifications.size());
- main_test_rfh()->SendNavigate(0, url2);
- EXPECT_EQ(1U, navigation_entry_committed_counter_);
- navigation_entry_committed_counter_ = 0;
-
- // Second request
- controller.LoadURL(
- url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
-
- EXPECT_TRUE(controller.GetPendingEntry());
- EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
- EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = 0;
+ params.nav_entry_id = entry_id;
+ params.did_create_new_entry = true;
params.url = url2;
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;
params.gesture = NavigationGestureAuto;
- params.is_post = false;
+ params.is_post = true;
params.page_state = PageState::CreateFromURL(url2);
LoadCommittedDetails details;
+ EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
+ &details));
+ EXPECT_EQ(1U, navigation_entry_committed_counter_);
+ navigation_entry_committed_counter_ = 0;
+
+ // Second request.
+ controller.LoadURL(
+ url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ entry_id = controller.GetPendingEntry()->GetUniqueID();
+
+ EXPECT_TRUE(controller.GetPendingEntry());
+ EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
+ EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
+
+ params.nav_entry_id = entry_id;
+ params.did_create_new_entry = false;
+ params.is_post = false;
+
EXPECT_EQ(0U, notifications.size());
EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
&details));
@@ -1807,6 +1968,7 @@ TEST_F(NavigationControllerTest, ImmediateRedirect) {
// First request
controller.LoadURL(
url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ int entry_id = controller.GetPendingEntry()->GetUniqueID();
EXPECT_TRUE(controller.GetPendingEntry());
EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
@@ -1814,6 +1976,8 @@ TEST_F(NavigationControllerTest, ImmediateRedirect) {
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = 0;
+ params.nav_entry_id = entry_id;
+ params.did_create_new_entry = true;
params.url = url2;
params.transition = ui::PAGE_TRANSITION_SERVER_REDIRECT;
params.redirects.push_back(GURL("http://foo1"));
@@ -1843,6 +2007,59 @@ TEST_F(NavigationControllerTest, ImmediateRedirect) {
EXPECT_FALSE(controller.CanGoForward());
}
+// If something is pumping the event loop in the browser process and is loading
+// pages rapidly one after the other, there can be a race with two closely-
+// spaced load requests. Once the first load request is sent, will the renderer
+// be fast enough to get the load committed, send a DidCommitProvisionalLoad
+// IPC, and have the browser process handle that IPC before the caller makes
+// another load request, replacing the pending entry of the first request?
+//
+// This test is about what happens in such a race when that pending entry
+// replacement happens. If it happens, and the first load had the same URL as
+// the page before it, we must make sure that the replacement of the pending
+// entry correctly turns a SAME_PAGE classification into an EXISTING_PAGE one.
+//
+// (This is a unit test rather than a browser test because it's not currently
+// possible to force this sequence of events with a browser test.)
+TEST_F(NavigationControllerTest,
+ NavigationTypeClassification_ExistingPageRace) {
+ NavigationControllerImpl& controller = controller_impl();
+ const GURL url1("http://foo1");
+ const GURL url2("http://foo2");
+
+ // Start with a loaded page.
+ main_test_rfh()->NavigateAndCommitRendererInitiated(0, true, url1);
+ EXPECT_EQ(nullptr, controller_impl().GetPendingEntry());
+
+ // Start a load of the same page again.
+ controller.LoadURL(
+ url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ int entry_id1 = controller.GetPendingEntry()->GetUniqueID();
+
+ // Immediately start loading a different page...
+ controller.LoadURL(
+ url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ int entry_id2 = controller.GetPendingEntry()->GetUniqueID();
+ EXPECT_NE(entry_id1, entry_id2);
+
+ // ... and now the renderer sends a commit for the first navigation.
+ FrameHostMsg_DidCommitProvisionalLoad_Params params;
+ params.page_id = 0;
+ params.nav_entry_id = entry_id1;
+ params.intended_as_new_entry = true;
+ params.did_create_new_entry = false;
+ params.url = url1;
+ params.transition = ui::PAGE_TRANSITION_TYPED;
+ params.page_state = PageState::CreateFromURL(url1);
+
+ LoadCommittedDetails details;
+
+ main_test_rfh()->PrepareForCommit();
+ EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
+ &details));
+ EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, details.type);
+}
+
// Tests navigation via link click within a subframe. A new navigation entry
// should be created.
TEST_F(NavigationControllerTest, NewSubframe) {
@@ -1851,13 +2068,15 @@ TEST_F(NavigationControllerTest, NewSubframe) {
RegisterForAllNavNotifications(&notifications, &controller);
const GURL url1("http://foo1");
- main_test_rfh()->SendNavigate(0, url1);
+ main_test_rfh()->NavigateAndCommitRendererInitiated(0, true, url1);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
const GURL url2("http://foo2");
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = 1;
+ params.nav_entry_id = 0;
+ params.did_create_new_entry = true;
params.url = url2;
params.transition = ui::PAGE_TRANSITION_MANUAL_SUBFRAME;
params.should_update_history = false;
@@ -1883,61 +2102,158 @@ TEST_F(NavigationControllerTest, NewSubframe) {
EXPECT_EQ(params.page_id, details.entry->GetPageID());
}
-// Some pages create a popup, then write an iframe into it. This causes a
-// subframe navigation without having any committed entry. Such navigations
-// just get thrown on the ground, but we shouldn't crash.
-TEST_F(NavigationControllerTest, SubframeOnEmptyPage) {
- NavigationControllerImpl& controller = controller_impl();
- TestNotificationTracker notifications;
- RegisterForAllNavNotifications(&notifications, &controller);
-
- // Navigation controller currently has no entries.
- const GURL url("http://foo2");
- FrameHostMsg_DidCommitProvisionalLoad_Params params;
- params.page_id = 1;
- params.url = url;
- params.transition = ui::PAGE_TRANSITION_AUTO_SUBFRAME;
- params.should_update_history = false;
- params.gesture = NavigationGestureAuto;
- params.is_post = false;
- params.page_state = PageState::CreateFromURL(url);
-
- LoadCommittedDetails details;
- EXPECT_FALSE(controller.RendererDidNavigate(main_test_rfh(), params,
- &details));
- EXPECT_EQ(0U, notifications.size());
-}
-
// Auto subframes are ones the page loads automatically like ads. They should
// not create new navigation entries.
+// TODO(creis): Test updating entries for history auto subframe navigations.
TEST_F(NavigationControllerTest, AutoSubframe) {
NavigationControllerImpl& controller = controller_impl();
TestNotificationTracker notifications;
RegisterForAllNavNotifications(&notifications, &controller);
- const GURL url1("http://foo1");
- main_test_rfh()->SendNavigate(0, url1);
+ const GURL url1("http://foo/1");
+ main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
- const GURL url2("http://foo2");
- FrameHostMsg_DidCommitProvisionalLoad_Params params;
- params.page_id = 0;
- params.url = url2;
- params.transition = ui::PAGE_TRANSITION_AUTO_SUBFRAME;
- params.should_update_history = false;
- params.gesture = NavigationGestureUser;
- params.is_post = false;
- params.page_state = PageState::CreateFromURL(url2);
+ // Add a subframe and navigate it.
+ main_test_rfh()->OnCreateChildFrame(MSG_ROUTING_NONE, std::string(),
+ SandboxFlags::NONE);
+ RenderFrameHostImpl* subframe =
+ contents()->GetFrameTree()->root()->child_at(0)->current_frame_host();
+ const GURL url2("http://foo/2");
+ {
+ FrameHostMsg_DidCommitProvisionalLoad_Params params;
+ params.page_id = 1;
+ params.nav_entry_id = 0;
+ params.did_create_new_entry = false;
+ params.url = url2;
+ params.transition = ui::PAGE_TRANSITION_AUTO_SUBFRAME;
+ params.should_update_history = false;
+ params.gesture = NavigationGestureUser;
+ params.is_post = false;
+ params.page_state = PageState::CreateFromURL(url2);
- // Navigating should do nothing.
- LoadCommittedDetails details;
- EXPECT_FALSE(controller.RendererDidNavigate(main_test_rfh(), params,
- &details));
- EXPECT_EQ(0U, notifications.size());
+ // Navigating should do nothing.
+ LoadCommittedDetails details;
+ EXPECT_FALSE(controller.RendererDidNavigate(subframe, params, &details));
+ EXPECT_EQ(0U, notifications.size());
+ }
// There should still be only one entry.
EXPECT_EQ(1, controller.GetEntryCount());
+ NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
+ EXPECT_EQ(url1, entry->GetURL());
+ EXPECT_EQ(1, entry->GetPageID());
+ FrameNavigationEntry* root_entry = entry->root_node()->frame_entry.get();
+ EXPECT_EQ(url1, root_entry->url());
+
+ // Verify subframe entries if we're in --site-per-process mode.
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess)) {
+ // The entry should now have a subframe FrameNavigationEntry.
+ ASSERT_EQ(1U, entry->root_node()->children.size());
+ FrameNavigationEntry* frame_entry =
+ entry->root_node()->children[0]->frame_entry.get();
+ EXPECT_EQ(url2, frame_entry->url());
+ } else {
+ // There are no subframe FrameNavigationEntries by default.
+ EXPECT_EQ(0U, entry->root_node()->children.size());
+ }
+
+ // Add a second subframe and navigate.
+ main_test_rfh()->OnCreateChildFrame(MSG_ROUTING_NONE, std::string(),
+ SandboxFlags::NONE);
+ RenderFrameHostImpl* subframe2 =
+ contents()->GetFrameTree()->root()->child_at(1)->current_frame_host();
+ const GURL url3("http://foo/3");
+ {
+ FrameHostMsg_DidCommitProvisionalLoad_Params params;
+ params.page_id = 1;
+ params.nav_entry_id = 0;
+ params.did_create_new_entry = false;
+ params.url = url3;
+ params.transition = ui::PAGE_TRANSITION_AUTO_SUBFRAME;
+ params.should_update_history = false;
+ params.gesture = NavigationGestureUser;
+ params.is_post = false;
+ params.page_state = PageState::CreateFromURL(url3);
+
+ // Navigating should do nothing.
+ LoadCommittedDetails details;
+ EXPECT_FALSE(controller.RendererDidNavigate(subframe2, params, &details));
+ EXPECT_EQ(0U, notifications.size());
+ }
+
+ // There should still be only one entry, mostly unchanged.
+ EXPECT_EQ(1, controller.GetEntryCount());
+ EXPECT_EQ(entry, controller.GetLastCommittedEntry());
+ EXPECT_EQ(url1, entry->GetURL());
+ EXPECT_EQ(1, entry->GetPageID());
+ EXPECT_EQ(root_entry, entry->root_node()->frame_entry.get());
+ EXPECT_EQ(url1, root_entry->url());
+
+ // Verify subframe entries if we're in --site-per-process mode.
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess)) {
+ // The entry should now have 2 subframe FrameNavigationEntries.
+ ASSERT_EQ(2U, entry->root_node()->children.size());
+ FrameNavigationEntry* new_frame_entry =
+ entry->root_node()->children[1]->frame_entry.get();
+ EXPECT_EQ(url3, new_frame_entry->url());
+ } else {
+ // There are no subframe FrameNavigationEntries by default.
+ EXPECT_EQ(0U, entry->root_node()->children.size());
+ }
+
+ // Add a nested subframe and navigate.
+ subframe->OnCreateChildFrame(MSG_ROUTING_NONE, std::string(),
+ SandboxFlags::NONE);
+ RenderFrameHostImpl* subframe3 = contents()
+ ->GetFrameTree()
+ ->root()
+ ->child_at(0)
+ ->child_at(0)
+ ->current_frame_host();
+ const GURL url4("http://foo/4");
+ {
+ FrameHostMsg_DidCommitProvisionalLoad_Params params;
+ params.page_id = 1;
+ params.nav_entry_id = 0;
+ params.did_create_new_entry = false;
+ params.url = url4;
+ params.transition = ui::PAGE_TRANSITION_AUTO_SUBFRAME;
+ params.should_update_history = false;
+ params.gesture = NavigationGestureUser;
+ params.is_post = false;
+ params.page_state = PageState::CreateFromURL(url4);
+
+ // Navigating should do nothing.
+ LoadCommittedDetails details;
+ EXPECT_FALSE(controller.RendererDidNavigate(subframe3, params, &details));
+ EXPECT_EQ(0U, notifications.size());
+ }
+
+ // There should still be only one entry, mostly unchanged.
+ EXPECT_EQ(1, controller.GetEntryCount());
+ EXPECT_EQ(entry, controller.GetLastCommittedEntry());
+ EXPECT_EQ(url1, entry->GetURL());
+ EXPECT_EQ(1, entry->GetPageID());
+ EXPECT_EQ(root_entry, entry->root_node()->frame_entry.get());
+ EXPECT_EQ(url1, root_entry->url());
+
+ // Verify subframe entries if we're in --site-per-process mode.
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess)) {
+ // The entry should now have a nested FrameNavigationEntry.
+ EXPECT_EQ(2U, entry->root_node()->children.size());
+ ASSERT_EQ(1U, entry->root_node()->children[0]->children.size());
+ FrameNavigationEntry* new_frame_entry =
+ entry->root_node()->children[0]->children[0]->frame_entry.get();
+ EXPECT_EQ(url4, new_frame_entry->url());
+ } else {
+ // There are no subframe FrameNavigationEntries by default.
+ EXPECT_EQ(0U, entry->root_node()->children.size());
+ }
}
// Tests navigation and then going back to a subframe navigation.
@@ -1948,14 +2264,17 @@ TEST_F(NavigationControllerTest, BackSubframe) {
// Main page.
const GURL url1("http://foo1");
- main_test_rfh()->SendNavigate(0, url1);
+ main_test_rfh()->NavigateAndCommitRendererInitiated(0, true, url1);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
+ NavigationEntry* entry1 = controller.GetLastCommittedEntry();
navigation_entry_committed_counter_ = 0;
// First manual subframe navigation.
const GURL url2("http://foo2");
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = 1;
+ params.nav_entry_id = 0;
+ params.did_create_new_entry = true;
params.url = url2;
params.transition = ui::PAGE_TRANSITION_MANUAL_SUBFRAME;
params.should_update_history = false;
@@ -1967,6 +2286,7 @@ TEST_F(NavigationControllerTest, BackSubframe) {
LoadCommittedDetails details;
EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
&details));
+ NavigationEntry* entry2 = controller.GetLastCommittedEntry();
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
EXPECT_EQ(2, controller.GetEntryCount());
@@ -1974,7 +2294,10 @@ TEST_F(NavigationControllerTest, BackSubframe) {
// Second manual subframe navigation should also make a new entry.
const GURL url3("http://foo3");
params.page_id = 2;
+ params.nav_entry_id = 0;
+ params.did_create_new_entry = true;
params.url = url3;
+ params.transition = ui::PAGE_TRANSITION_MANUAL_SUBFRAME;
EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
&details));
EXPECT_EQ(1U, navigation_entry_committed_counter_);
@@ -1984,8 +2307,11 @@ TEST_F(NavigationControllerTest, BackSubframe) {
// Go back one.
controller.GoBack();
- params.url = url2;
params.page_id = 1;
+ params.nav_entry_id = entry2->GetUniqueID();
+ params.did_create_new_entry = false;
+ params.url = url2;
+ params.transition = ui::PAGE_TRANSITION_AUTO_SUBFRAME;
EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
&details));
EXPECT_EQ(1U, navigation_entry_committed_counter_);
@@ -1997,8 +2323,11 @@ TEST_F(NavigationControllerTest, BackSubframe) {
// Go back one more.
controller.GoBack();
- params.url = url1;
params.page_id = 0;
+ params.nav_entry_id = entry1->GetUniqueID();
+ params.did_create_new_entry = false;
+ params.url = url1;
+ params.transition = ui::PAGE_TRANSITION_AUTO_SUBFRAME;
EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
&details));
EXPECT_EQ(1U, navigation_entry_committed_counter_);
@@ -2017,15 +2346,15 @@ TEST_F(NavigationControllerTest, LinkClick) {
const GURL url1("http://foo1");
const GURL url2("http://foo2");
- main_test_rfh()->SendNavigate(0, url1);
+ main_test_rfh()->NavigateAndCommitRendererInitiated(0, true, url1);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
- main_test_rfh()->SendNavigate(1, url2);
+ main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url2);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
- // Should not have produced a new session history entry.
+ // Should have produced a new session history entry.
EXPECT_EQ(controller.GetEntryCount(), 2);
EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
@@ -2042,7 +2371,7 @@ TEST_F(NavigationControllerTest, InPage) {
// Main page.
const GURL url1("http://foo");
- main_test_rfh()->SendNavigate(0, url1);
+ main_test_rfh()->NavigateAndCommitRendererInitiated(0, true, url1);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -2050,6 +2379,8 @@ TEST_F(NavigationControllerTest, InPage) {
// hint provided in the params.
FrameHostMsg_DidCommitProvisionalLoad_Params self_params;
self_params.page_id = 0;
+ self_params.nav_entry_id = 0;
+ self_params.did_create_new_entry = false;
self_params.url = url1;
self_params.transition = ui::PAGE_TRANSITION_LINK;
self_params.should_update_history = false;
@@ -2061,6 +2392,7 @@ TEST_F(NavigationControllerTest, InPage) {
LoadCommittedDetails details;
EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), self_params,
&details));
+ NavigationEntry* entry1 = controller.GetLastCommittedEntry();
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
EXPECT_TRUE(details.is_in_page);
@@ -2071,6 +2403,8 @@ TEST_F(NavigationControllerTest, InPage) {
const GURL url2("http://foo#a");
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = 1;
+ params.nav_entry_id = 0;
+ params.did_create_new_entry = true;
params.url = url2;
params.transition = ui::PAGE_TRANSITION_LINK;
params.should_update_history = false;
@@ -2082,6 +2416,7 @@ TEST_F(NavigationControllerTest, InPage) {
// This should generate a new entry.
EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
&details));
+ NavigationEntry* entry2 = controller.GetLastCommittedEntry();
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
EXPECT_TRUE(details.is_in_page);
@@ -2093,6 +2428,8 @@ TEST_F(NavigationControllerTest, InPage) {
controller.GoBack();
back_params.url = url1;
back_params.page_id = 0;
+ back_params.nav_entry_id = entry1->GetUniqueID();
+ back_params.did_create_new_entry = false;
EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), back_params,
&details));
EXPECT_EQ(1U, navigation_entry_committed_counter_);
@@ -2102,11 +2439,13 @@ TEST_F(NavigationControllerTest, InPage) {
EXPECT_EQ(0, controller.GetCurrentEntryIndex());
EXPECT_EQ(back_params.url, controller.GetVisibleEntry()->GetURL());
- // Go forward
+ // Go forward.
FrameHostMsg_DidCommitProvisionalLoad_Params forward_params(params);
controller.GoForward();
forward_params.url = url2;
forward_params.page_id = 1;
+ forward_params.nav_entry_id = entry2->GetUniqueID();
+ forward_params.did_create_new_entry = false;
EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), forward_params,
&details));
EXPECT_EQ(1U, navigation_entry_committed_counter_);
@@ -2133,6 +2472,8 @@ TEST_F(NavigationControllerTest, InPage) {
// Finally, navigate to an unrelated URL to make sure in_page is not sticky.
const GURL url3("http://bar");
params.page_id = 2;
+ params.nav_entry_id = 0;
+ params.did_create_new_entry = true;
params.url = url3;
navigation_entry_committed_counter_ = 0;
EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
@@ -2151,7 +2492,7 @@ TEST_F(NavigationControllerTest, InPage_Replace) {
// Main page.
const GURL url1("http://foo");
- main_test_rfh()->SendNavigate(0, url1);
+ main_test_rfh()->NavigateAndCommitRendererInitiated(0, true, url1);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -2159,6 +2500,8 @@ TEST_F(NavigationControllerTest, InPage_Replace) {
const GURL url2("http://foo#a");
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = 0; // Same page_id
+ params.nav_entry_id = 0;
+ params.did_create_new_entry = false;
params.url = url2;
params.transition = ui::PAGE_TRANSITION_LINK;
params.should_update_history = false;
@@ -2192,7 +2535,7 @@ TEST_F(NavigationControllerTest, ClientRedirectAfterInPageNavigation) {
// Load an initial page.
{
const GURL url("http://foo/");
- main_test_rfh()->SendNavigate(0, url);
+ main_test_rfh()->NavigateAndCommitRendererInitiated(0, true, url);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
}
@@ -2200,7 +2543,7 @@ TEST_F(NavigationControllerTest, ClientRedirectAfterInPageNavigation) {
// Navigate to a new page.
{
const GURL url("http://foo2/");
- main_test_rfh()->SendNavigate(1, url);
+ main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
}
@@ -2210,6 +2553,8 @@ TEST_F(NavigationControllerTest, ClientRedirectAfterInPageNavigation) {
const GURL url("http://foo2/#a");
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = 1; // Same page_id
+ params.nav_entry_id = 0;
+ params.did_create_new_entry = false;
params.url = url;
params.transition = ui::PAGE_TRANSITION_LINK;
params.redirects.push_back(url);
@@ -2235,6 +2580,8 @@ TEST_F(NavigationControllerTest, ClientRedirectAfterInPageNavigation) {
const GURL url("http://foo3/");
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = 2; // New page_id
+ params.nav_entry_id = 0;
+ params.did_create_new_entry = true;
params.url = url;
params.transition = ui::PAGE_TRANSITION_CLIENT_REDIRECT;
params.redirects.push_back(GURL("http://foo2/#a"));
@@ -2258,7 +2605,9 @@ TEST_F(NavigationControllerTest, ClientRedirectAfterInPageNavigation) {
{
const GURL url("http://foo2/");
controller.GoBack();
- main_test_rfh()->SendNavigate(1, url);
+ int entry_id = controller.GetPendingEntry()->GetUniqueID();
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(1, entry_id, false, url);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
EXPECT_EQ(url, controller.GetVisibleEntry()->GetURL());
@@ -2271,9 +2620,13 @@ TEST_F(NavigationControllerTest, PushStateWithoutPreviousEntry)
FrameHostMsg_DidCommitProvisionalLoad_Params params;
GURL url("http://foo");
params.page_id = 1;
+ params.nav_entry_id = 0;
+ params.did_create_new_entry = true;
params.url = url;
params.page_state = PageState::CreateFromURL(url);
params.was_within_same_page = true;
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(url, false);
+ main_test_rfh()->PrepareForCommit();
contents()->GetMainFrame()->SendNavigateWithParams(&params);
// We pass if we don't crash.
}
@@ -2323,7 +2676,9 @@ TEST_F(NavigationControllerTest, EnforceMaxNavigationCount) {
GURL url(base::StringPrintf("http://www.a.com/%d", url_index));
controller.LoadURL(
url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- main_test_rfh()->SendNavigate(url_index, url);
+ int entry_id = controller.GetPendingEntry()->GetUniqueID();
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(url_index, entry_id, true, url);
}
EXPECT_EQ(controller.GetEntryCount(), kMaxEntryCount);
@@ -2335,7 +2690,9 @@ TEST_F(NavigationControllerTest, EnforceMaxNavigationCount) {
GURL url(base::StringPrintf("http://www.a.com/%d", url_index));
controller.LoadURL(
url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- main_test_rfh()->SendNavigate(url_index, url);
+ int entry_id = controller.GetPendingEntry()->GetUniqueID();
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(url_index, entry_id, true, url);
url_index++;
// We should have got a pruned navigation.
@@ -2346,19 +2703,21 @@ TEST_F(NavigationControllerTest, EnforceMaxNavigationCount) {
// We expect http://www.a.com/0 to be gone.
EXPECT_EQ(controller.GetEntryCount(), kMaxEntryCount);
EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(),
- GURL("http:////www.a.com/1"));
+ GURL("http://www.a.com/1"));
// More navigations.
for (int i = 0; i < 3; i++) {
- url = GURL(base::StringPrintf("http:////www.a.com/%d", url_index));
+ url = GURL(base::StringPrintf("http://www.a.com/%d", url_index));
controller.LoadURL(
url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- main_test_rfh()->SendNavigate(url_index, url);
+ int entry_id = controller.GetPendingEntry()->GetUniqueID();
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(url_index, entry_id, true, url);
url_index++;
}
EXPECT_EQ(controller.GetEntryCount(), kMaxEntryCount);
EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(),
- GURL("http:////www.a.com/4"));
+ GURL("http://www.a.com/4"));
NavigationControllerImpl::set_max_entry_count_for_testing(original_count);
}
@@ -2392,10 +2751,8 @@ TEST_F(NavigationControllerTest, RestoreNavigate) {
// and no SiteInstance.
ASSERT_EQ(1, our_controller.GetEntryCount());
EXPECT_EQ(NavigationEntryImpl::RESTORE_LAST_SESSION_EXITED_CLEANLY,
- NavigationEntryImpl::FromNavigationEntry(
- our_controller.GetEntryAtIndex(0))->restore_type());
- EXPECT_FALSE(NavigationEntryImpl::FromNavigationEntry(
- our_controller.GetEntryAtIndex(0))->site_instance());
+ our_controller.GetEntryAtIndex(0)->restore_type());
+ EXPECT_FALSE(our_controller.GetEntryAtIndex(0)->site_instance());
// After navigating, we should have one entry, and it should be "pending".
// It should now have a SiteInstance and no restore_type.
@@ -2405,10 +2762,8 @@ TEST_F(NavigationControllerTest, RestoreNavigate) {
our_controller.GetPendingEntry());
EXPECT_EQ(0, our_controller.GetEntryAtIndex(0)->GetPageID());
EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE,
- NavigationEntryImpl::FromNavigationEntry
- (our_controller.GetEntryAtIndex(0))->restore_type());
- EXPECT_TRUE(NavigationEntryImpl::FromNavigationEntry(
- our_controller.GetEntryAtIndex(0))->site_instance());
+ our_controller.GetEntryAtIndex(0)->restore_type());
+ EXPECT_TRUE(our_controller.GetEntryAtIndex(0)->site_instance());
// Timestamp should remain the same before the navigation finishes.
EXPECT_EQ(timestamp, our_controller.GetEntryAtIndex(0)->GetTimestamp());
@@ -2416,6 +2771,8 @@ TEST_F(NavigationControllerTest, RestoreNavigate) {
// Say we navigated to that entry.
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = 0;
+ params.nav_entry_id = our_controller.GetPendingEntry()->GetUniqueID();
+ params.did_create_new_entry = false;
params.url = url;
params.transition = ui::PAGE_TRANSITION_LINK;
params.should_update_history = false;
@@ -2432,13 +2789,11 @@ TEST_F(NavigationControllerTest, RestoreNavigate) {
EXPECT_EQ(1, our_controller.GetEntryCount());
EXPECT_EQ(0, our_controller.GetLastCommittedEntryIndex());
EXPECT_FALSE(our_controller.GetPendingEntry());
- EXPECT_EQ(url,
- NavigationEntryImpl::FromNavigationEntry(
- our_controller.GetLastCommittedEntry())->site_instance()->
- GetSiteURL());
+ EXPECT_EQ(
+ url,
+ our_controller.GetLastCommittedEntry()->site_instance()->GetSiteURL());
EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE,
- NavigationEntryImpl::FromNavigationEntry(
- our_controller.GetEntryAtIndex(0))->restore_type());
+ our_controller.GetEntryAtIndex(0)->restore_type());
// Timestamp should have been updated.
EXPECT_GE(our_controller.GetEntryAtIndex(0)->GetTimestamp(), timestamp);
@@ -2466,11 +2821,10 @@ TEST_F(NavigationControllerTest, RestoreNavigateAfterFailure) {
// Before navigating to the restored entry, it should have a restore_type
// and no SiteInstance.
+ entry = our_controller.GetEntryAtIndex(0);
EXPECT_EQ(NavigationEntryImpl::RESTORE_LAST_SESSION_EXITED_CLEANLY,
- NavigationEntryImpl::FromNavigationEntry(
- our_controller.GetEntryAtIndex(0))->restore_type());
- EXPECT_FALSE(NavigationEntryImpl::FromNavigationEntry(
- our_controller.GetEntryAtIndex(0))->site_instance());
+ our_controller.GetEntryAtIndex(0)->restore_type());
+ EXPECT_FALSE(our_controller.GetEntryAtIndex(0)->site_instance());
// After navigating, we should have one entry, and it should be "pending".
// It should now have a SiteInstance and no restore_type.
@@ -2480,10 +2834,8 @@ TEST_F(NavigationControllerTest, RestoreNavigateAfterFailure) {
our_controller.GetPendingEntry());
EXPECT_EQ(0, our_controller.GetEntryAtIndex(0)->GetPageID());
EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE,
- NavigationEntryImpl::FromNavigationEntry(
- our_controller.GetEntryAtIndex(0))->restore_type());
- EXPECT_TRUE(NavigationEntryImpl::FromNavigationEntry(
- our_controller.GetEntryAtIndex(0))->site_instance());
+ our_controller.GetEntryAtIndex(0)->restore_type());
+ EXPECT_TRUE(our_controller.GetEntryAtIndex(0)->site_instance());
// This pending navigation may have caused a different navigation to fail,
// which causes the pending entry to be cleared.
@@ -2499,6 +2851,8 @@ TEST_F(NavigationControllerTest, RestoreNavigateAfterFailure) {
// Now the pending restored entry commits.
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = 0;
+ params.nav_entry_id = entry->GetUniqueID();
+ params.did_create_new_entry = false;
params.url = url;
params.transition = ui::PAGE_TRANSITION_LINK;
params.should_update_history = false;
@@ -2513,13 +2867,11 @@ TEST_F(NavigationControllerTest, RestoreNavigateAfterFailure) {
EXPECT_EQ(1, our_controller.GetEntryCount());
EXPECT_EQ(0, our_controller.GetLastCommittedEntryIndex());
EXPECT_FALSE(our_controller.GetPendingEntry());
- EXPECT_EQ(url,
- NavigationEntryImpl::FromNavigationEntry(
- our_controller.GetLastCommittedEntry())->site_instance()->
- GetSiteURL());
+ EXPECT_EQ(
+ url,
+ our_controller.GetLastCommittedEntry()->site_instance()->GetSiteURL());
EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE,
- NavigationEntryImpl::FromNavigationEntry(
- our_controller.GetEntryAtIndex(0))->restore_type());
+ our_controller.GetEntryAtIndex(0)->restore_type());
}
// Make sure that the page type and stuff is correct after an interstitial.
@@ -2529,18 +2881,21 @@ TEST_F(NavigationControllerTest, Interstitial) {
const GURL url1("http://foo");
controller.LoadURL(
url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- main_test_rfh()->SendNavigate(0, url1);
+ int entry_id = controller.GetPendingEntry()->GetUniqueID();
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(0, entry_id, true, url1);
// Now navigate somewhere with an interstitial.
const GURL url2("http://bar");
- controller.LoadURL(
- url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
- set_page_type(PAGE_TYPE_INTERSTITIAL);
+ controller.LoadURL(url2, Referrer(), ui::PAGE_TRANSITION_TYPED,
+ std::string());
+ entry_id = controller.GetPendingEntry()->GetUniqueID();
+ controller.GetPendingEntry()->set_page_type(PAGE_TYPE_INTERSTITIAL);
// At this point the interstitial will be displayed and the load will still
// be pending. If the user continues, the load will commit.
- main_test_rfh()->SendNavigate(1, url2);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(1, entry_id, true, url2);
// The page should be a normal page again.
EXPECT_EQ(url2, controller.GetLastCommittedEntry()->GetURL());
@@ -2560,19 +2915,29 @@ TEST_F(NavigationControllerTest, RemoveEntry) {
controller.LoadURL(
url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- main_test_rfh()->SendNavigate(0, url1);
+ int entry_id = controller.GetPendingEntry()->GetUniqueID();
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(0, entry_id, true, url1);
controller.LoadURL(
url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- main_test_rfh()->SendNavigate(1, url2);
+ entry_id = controller.GetPendingEntry()->GetUniqueID();
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(1, entry_id, true, url2);
controller.LoadURL(
url3, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- main_test_rfh()->SendNavigate(2, url3);
+ entry_id = controller.GetPendingEntry()->GetUniqueID();
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(2, entry_id, true, url3);
controller.LoadURL(
url4, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- main_test_rfh()->SendNavigate(3, url4);
+ entry_id = controller.GetPendingEntry()->GetUniqueID();
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(3, entry_id, true, url4);
controller.LoadURL(
url5, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- main_test_rfh()->SendNavigate(4, url5);
+ entry_id = controller.GetPendingEntry()->GetUniqueID();
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(4, entry_id, true, url5);
// Try to remove the last entry. Will fail because it is the current entry.
EXPECT_FALSE(controller.RemoveEntryAtIndex(controller.GetEntryCount() - 1));
@@ -2582,11 +2947,13 @@ TEST_F(NavigationControllerTest, RemoveEntry) {
// Go back, but don't commit yet. Check that we can't delete the current
// and pending entries.
controller.GoBack();
+ entry_id = controller.GetPendingEntry()->GetUniqueID();
EXPECT_FALSE(controller.RemoveEntryAtIndex(controller.GetEntryCount() - 1));
EXPECT_FALSE(controller.RemoveEntryAtIndex(controller.GetEntryCount() - 2));
// Now commit and delete the last entry.
- main_test_rfh()->SendNavigate(3, url4);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(3, entry_id, false, url4);
EXPECT_TRUE(controller.RemoveEntryAtIndex(controller.GetEntryCount() - 1));
EXPECT_EQ(4, controller.GetEntryCount());
EXPECT_EQ(3, controller.GetLastCommittedEntryIndex());
@@ -2616,17 +2983,24 @@ TEST_F(NavigationControllerTest, RemoveEntryWithPending) {
controller.LoadURL(
url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- main_test_rfh()->SendNavigate(0, url1);
+ int entry_id = controller.GetPendingEntry()->GetUniqueID();
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(0, entry_id, true, url1);
controller.LoadURL(
url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- main_test_rfh()->SendNavigate(1, url2);
+ entry_id = controller.GetPendingEntry()->GetUniqueID();
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(1, entry_id, true, url2);
controller.LoadURL(
url3, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- main_test_rfh()->SendNavigate(2, url3);
+ entry_id = controller.GetPendingEntry()->GetUniqueID();
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(2, entry_id, true, url3);
// Go back, but don't commit yet. Check that we can't delete the current
// and pending entries.
controller.GoBack();
+ entry_id = controller.GetPendingEntry()->GetUniqueID();
EXPECT_FALSE(controller.RemoveEntryAtIndex(2));
EXPECT_FALSE(controller.RemoveEntryAtIndex(1));
@@ -2640,7 +3014,8 @@ TEST_F(NavigationControllerTest, RemoveEntryWithPending) {
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
// Now commit and ensure we land on the right entry.
- main_test_rfh()->SendNavigate(1, url2);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(1, entry_id, false, url2);
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
EXPECT_FALSE(controller.GetPendingEntry());
@@ -2662,10 +3037,14 @@ TEST_F(NavigationControllerTest, TransientEntry) {
controller.LoadURL(
url0, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- main_test_rfh()->SendNavigate(0, url0);
+ int entry_id = controller.GetPendingEntry()->GetUniqueID();
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(0, entry_id, true, url0);
controller.LoadURL(
url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- main_test_rfh()->SendNavigate(1, url1);
+ entry_id = controller.GetPendingEntry()->GetUniqueID();
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(1, entry_id, true, url1);
notifications.Reset();
@@ -2691,7 +3070,9 @@ TEST_F(NavigationControllerTest, TransientEntry) {
// Navigate.
controller.LoadURL(
url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- main_test_rfh()->SendNavigate(2, url2);
+ entry_id = controller.GetPendingEntry()->GetUniqueID();
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(2, entry_id, true, url2);
// We should have navigated, transient entry should be gone.
EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL());
@@ -2702,7 +3083,9 @@ TEST_F(NavigationControllerTest, TransientEntry) {
transient_entry->SetURL(transient_url);
controller.SetTransientEntry(transient_entry);
EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
- main_test_rfh()->SendNavigate(3, url3);
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(url3, true);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(3, 0, true, url3);
// Transient entry should be gone.
EXPECT_EQ(url3, controller.GetVisibleEntry()->GetURL());
EXPECT_EQ(controller.GetEntryCount(), 4);
@@ -2710,11 +3093,13 @@ TEST_F(NavigationControllerTest, TransientEntry) {
// Initiate a navigation, add a transient then commit navigation.
controller.LoadURL(
url4, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ entry_id = controller.GetPendingEntry()->GetUniqueID();
transient_entry = new NavigationEntryImpl;
transient_entry->SetURL(transient_url);
controller.SetTransientEntry(transient_entry);
EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
- main_test_rfh()->SendNavigate(4, url4);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(4, entry_id, true, url4);
EXPECT_EQ(url4, controller.GetVisibleEntry()->GetURL());
EXPECT_EQ(controller.GetEntryCount(), 5);
@@ -2729,7 +3114,12 @@ TEST_F(NavigationControllerTest, TransientEntry) {
// Transient entry should be gone.
EXPECT_EQ(url4, controller.GetVisibleEntry()->GetURL());
EXPECT_EQ(controller.GetEntryCount(), 5);
- main_test_rfh()->SendNavigate(3, url3);
+
+ // Suppose the page requested a history navigation backward.
+ controller.GoToOffset(-1);
+ entry_id = controller.GetPendingEntry()->GetUniqueID();
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(3, entry_id, false, url3);
// Add a transient and go to an entry before the current one.
transient_entry = new NavigationEntryImpl;
@@ -2737,12 +3127,14 @@ TEST_F(NavigationControllerTest, TransientEntry) {
controller.SetTransientEntry(transient_entry);
EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
controller.GoToIndex(1);
+ entry_id = controller.GetPendingEntry()->GetUniqueID();
// The navigation should have been initiated, transient entry should be gone.
EXPECT_FALSE(controller.GetTransientEntry());
EXPECT_EQ(url1, controller.GetPendingEntry()->GetURL());
// Visible entry does not update for history navigations until commit.
EXPECT_EQ(url3, controller.GetVisibleEntry()->GetURL());
- main_test_rfh()->SendNavigate(1, url1);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(1, entry_id, false, url1);
EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
// Add a transient and go to an entry after the current one.
@@ -2751,12 +3143,14 @@ TEST_F(NavigationControllerTest, TransientEntry) {
controller.SetTransientEntry(transient_entry);
EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
controller.GoToIndex(3);
+ entry_id = controller.GetPendingEntry()->GetUniqueID();
// The navigation should have been initiated, transient entry should be gone.
// Because of the transient entry that is removed, going to index 3 makes us
// land on url2 (which is visible after the commit).
EXPECT_EQ(url2, controller.GetPendingEntry()->GetURL());
EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
- main_test_rfh()->SendNavigate(2, url2);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(2, entry_id, false, url2);
EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL());
// Add a transient and go forward.
@@ -2766,11 +3160,13 @@ TEST_F(NavigationControllerTest, TransientEntry) {
EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
EXPECT_TRUE(controller.CanGoForward());
controller.GoForward();
+ entry_id = controller.GetPendingEntry()->GetUniqueID();
// We should have navigated, transient entry should be gone.
EXPECT_FALSE(controller.GetTransientEntry());
EXPECT_EQ(url3, controller.GetPendingEntry()->GetURL());
EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL());
- main_test_rfh()->SendNavigate(3, url3);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(3, entry_id, false, url3);
EXPECT_EQ(url3, controller.GetVisibleEntry()->GetURL());
// Add a transient and do an in-page navigation, replacing the current entry.
@@ -2778,7 +3174,10 @@ TEST_F(NavigationControllerTest, TransientEntry) {
transient_entry->SetURL(transient_url);
controller.SetTransientEntry(transient_entry);
EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
- main_test_rfh()->SendNavigate(3, url3_ref);
+
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(url3_ref, false);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(3, 0, false, url3_ref);
// Transient entry should be gone.
EXPECT_FALSE(controller.GetTransientEntry());
EXPECT_EQ(url3_ref, controller.GetVisibleEntry()->GetURL());
@@ -2802,7 +3201,9 @@ TEST_F(NavigationControllerTest, ReloadTransient) {
// Load |url0|, and start a pending navigation to |url1|.
controller.LoadURL(
url0, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- main_test_rfh()->SendNavigate(0, url0);
+ int entry_id = controller.GetPendingEntry()->GetUniqueID();
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(0, entry_id, true, url0);
controller.LoadURL(
url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
@@ -2817,6 +3218,7 @@ TEST_F(NavigationControllerTest, ReloadTransient) {
// the transient entry for |transient_url|, and start a navigation to
// |transient_url|.
controller.Reload(true);
+ entry_id = controller.GetPendingEntry()->GetUniqueID();
EXPECT_FALSE(controller.GetTransientEntry());
EXPECT_TRUE(controller.GetPendingEntry());
EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
@@ -2824,7 +3226,8 @@ TEST_F(NavigationControllerTest, ReloadTransient) {
EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url0);
// Load of |transient_url| completes.
- main_test_rfh()->SendNavigate(1, transient_url);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(1, entry_id, true, transient_url);
ASSERT_EQ(controller.GetEntryCount(), 2);
EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url0);
EXPECT_EQ(controller.GetEntryAtIndex(1)->GetURL(), transient_url);
@@ -2853,17 +3256,17 @@ TEST_F(NavigationControllerTest, RendererInitiatedPendingEntries) {
EXPECT_EQ(url1_fixed, controller.GetPendingEntry()->GetURL());
EXPECT_EQ(url1, controller.GetPendingEntry()->GetVirtualURL());
- EXPECT_TRUE(
- NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
- is_renderer_initiated());
+ EXPECT_TRUE(controller.GetPendingEntry()->is_renderer_initiated());
// If the user clicks another link, we should replace the pending entry.
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(url2, false);
+ main_test_rfh()->PrepareForCommit();
navigator->DidStartProvisionalLoad(main_test_rfh(), url2, false);
EXPECT_EQ(url2, controller.GetPendingEntry()->GetURL());
EXPECT_EQ(url2, controller.GetPendingEntry()->GetVirtualURL());
// Once it commits, the URL and virtual URL should reflect the actual page.
- main_test_rfh()->SendNavigate(0, url2);
+ main_test_rfh()->SendNavigate(0, 0, true, url2);
EXPECT_EQ(url2, controller.GetLastCommittedEntry()->GetURL());
EXPECT_EQ(url2, controller.GetLastCommittedEntry()->GetVirtualURL());
@@ -2877,16 +3280,13 @@ TEST_F(NavigationControllerTest, RendererInitiatedPendingEntries) {
// We should remember if the pending entry will replace the current one.
// http://crbug.com/308444.
navigator->DidStartProvisionalLoad(main_test_rfh(), url1, false);
- NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
- set_should_replace_entry(true);
+ controller.GetPendingEntry()->set_should_replace_entry(true);
+
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(url2, false);
+ main_test_rfh()->PrepareForCommit();
navigator->DidStartProvisionalLoad(main_test_rfh(), url2, false);
- EXPECT_TRUE(
- NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
- should_replace_entry());
- // TODO(nasko): Until OnNavigate is moved to RenderFrameHost, we need
- // to go through the RenderViewHost. The TestRenderViewHost routes navigations
- // to the main frame.
- main_test_rfh()->SendNavigate(0, url2);
+ EXPECT_TRUE(controller.GetPendingEntry()->should_replace_entry());
+ main_test_rfh()->SendNavigate(0, 0, false, url2);
EXPECT_EQ(url2, controller.GetLastCommittedEntry()->GetURL());
}
@@ -2905,29 +3305,29 @@ TEST_F(NavigationControllerTest, DontShowRendererURLUntilCommit) {
// should update before commit.
controller.LoadURL(
url0, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ int entry_id = controller.GetPendingEntry()->GetUniqueID();
EXPECT_EQ(url0, controller.GetPendingEntry()->GetURL());
EXPECT_EQ(url0, controller.GetVisibleEntry()->GetURL());
- main_test_rfh()->SendNavigate(0, url0);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(0, entry_id, true, url0);
// For link clicks (renderer-initiated navigations), the pending entry should
// update before commit but the visible should not.
NavigationController::LoadURLParams load_url_params(url1);
load_url_params.is_renderer_initiated = true;
controller.LoadURLWithParams(load_url_params);
+ entry_id = controller.GetPendingEntry()->GetUniqueID();
EXPECT_EQ(url0, controller.GetVisibleEntry()->GetURL());
EXPECT_EQ(url1, controller.GetPendingEntry()->GetURL());
- EXPECT_TRUE(
- NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
- is_renderer_initiated());
+ EXPECT_TRUE(controller.GetPendingEntry()->is_renderer_initiated());
// After commit, both visible should be updated, there should be no pending
// entry, and we should no longer treat the entry as renderer-initiated.
- main_test_rfh()->SendNavigate(1, url1);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(1, entry_id, true, url1);
EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
EXPECT_FALSE(controller.GetPendingEntry());
- EXPECT_FALSE(
- NavigationEntryImpl::FromNavigationEntry(
- controller.GetLastCommittedEntry())->is_renderer_initiated());
+ EXPECT_FALSE(controller.GetLastCommittedEntry()->is_renderer_initiated());
notifications.Reset();
}
@@ -2952,9 +3352,7 @@ TEST_F(NavigationControllerTest, ShowRendererURLInNewTabUntilModified) {
controller.LoadURLWithParams(load_url_params);
EXPECT_EQ(url, controller.GetVisibleEntry()->GetURL());
EXPECT_EQ(url, controller.GetPendingEntry()->GetURL());
- EXPECT_TRUE(
- NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
- is_renderer_initiated());
+ EXPECT_TRUE(controller.GetPendingEntry()->is_renderer_initiated());
EXPECT_TRUE(controller.IsInitialNavigation());
EXPECT_FALSE(contents()->HasAccessedInitialDocument());
@@ -2992,9 +3390,7 @@ TEST_F(NavigationControllerTest, ShowBrowserURLAfterFailUntilModified) {
controller.LoadURLWithParams(load_url_params);
EXPECT_EQ(url, controller.GetVisibleEntry()->GetURL());
EXPECT_EQ(url, controller.GetPendingEntry()->GetURL());
- EXPECT_FALSE(
- NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
- is_renderer_initiated());
+ EXPECT_FALSE(controller.GetPendingEntry()->is_renderer_initiated());
EXPECT_TRUE(controller.IsInitialNavigation());
EXPECT_FALSE(contents()->HasAccessedInitialDocument());
@@ -3010,7 +3406,7 @@ TEST_F(NavigationControllerTest, ShowBrowserURLAfterFailUntilModified) {
params.showing_repost_interstitial = false;
main_test_rfh()->OnMessageReceived(
FrameHostMsg_DidFailProvisionalLoadWithError(0, params));
- contents()->SetIsLoading(test_rvh(), false, true, NULL);
+ contents()->SetIsLoading(false, true, NULL);
EXPECT_EQ(url, controller.GetVisibleEntry()->GetURL());
// If something else later modifies the contents of the about:blank page, then
@@ -3043,9 +3439,7 @@ TEST_F(NavigationControllerTest, ShowRendererURLAfterFailUntilModified) {
controller.LoadURLWithParams(load_url_params);
EXPECT_EQ(url, controller.GetVisibleEntry()->GetURL());
EXPECT_EQ(url, controller.GetPendingEntry()->GetURL());
- EXPECT_TRUE(
- NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
- is_renderer_initiated());
+ EXPECT_TRUE(controller.GetPendingEntry()->is_renderer_initiated());
EXPECT_TRUE(controller.IsInitialNavigation());
EXPECT_FALSE(contents()->HasAccessedInitialDocument());
@@ -3088,15 +3482,15 @@ TEST_F(NavigationControllerTest, DontShowRendererURLInNewTabAfterCommit) {
load_url_params.transition_type = ui::PAGE_TRANSITION_LINK;
load_url_params.is_renderer_initiated = true;
controller.LoadURLWithParams(load_url_params);
+ int entry_id = controller.GetPendingEntry()->GetUniqueID();
EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
- EXPECT_TRUE(
- NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
- is_renderer_initiated());
+ EXPECT_TRUE(controller.GetPendingEntry()->is_renderer_initiated());
EXPECT_TRUE(controller.IsInitialNavigation());
EXPECT_FALSE(contents()->HasAccessedInitialDocument());
// Simulate a commit and then starting a new pending navigation.
- main_test_rfh()->SendNavigate(0, url1);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(0, entry_id, true, url1);
NavigationController::LoadURLParams load_url2_params(url2);
load_url2_params.transition_type = ui::PAGE_TRANSITION_LINK;
load_url2_params.is_renderer_initiated = true;
@@ -3126,16 +3520,15 @@ TEST_F(NavigationControllerTest, IsInPageNavigation) {
// 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);
+ main_test_rfh()->NavigateAndCommitRendererInitiated(0, true, blank_url);
EXPECT_TRUE(controller.IsURLInPageNavigation(url, true,
main_test_rfh()));
// Navigate to URL with no refs.
- main_test_rfh()->SendNavigate(0, url);
+ main_test_rfh()->NavigateAndCommitRendererInitiated(0, false, url);
// Reloading the page is not an in-page navigation.
- EXPECT_FALSE(controller.IsURLInPageNavigation(url, false,
- main_test_rfh()));
+ EXPECT_FALSE(controller.IsURLInPageNavigation(url, false, main_test_rfh()));
const GURL other_url("http://www.google.com/add.html");
EXPECT_FALSE(controller.IsURLInPageNavigation(other_url, false,
main_test_rfh()));
@@ -3144,7 +3537,7 @@ TEST_F(NavigationControllerTest, IsInPageNavigation) {
main_test_rfh()));
// Navigate to URL with refs.
- main_test_rfh()->SendNavigate(1, url_with_ref);
+ main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url_with_ref);
// Reloading the page is not an in-page navigation.
EXPECT_FALSE(controller.IsURLInPageNavigation(url_with_ref, false,
@@ -3172,15 +3565,40 @@ TEST_F(NavigationControllerTest, IsInPageNavigation) {
EXPECT_TRUE(controller.IsURLInPageNavigation(other_url, true,
main_test_rfh()));
- // Don't believe the renderer if it claims a cross-origin navigation is
- // in-page.
+ // Test allow_universal_access_from_file_urls flag.
const GURL different_origin_url("http://www.example.com");
- MockRenderProcessHost* rph =
- static_cast<MockRenderProcessHost*>(main_test_rfh()->GetProcess());
+ MockRenderProcessHost* rph = main_test_rfh()->GetProcess();
+ WebPreferences prefs = test_rvh()->GetWebkitPreferences();
+ prefs.allow_universal_access_from_file_urls = true;
+ test_rvh()->UpdateWebkitPreferences(prefs);
+ prefs = test_rvh()->GetWebkitPreferences();
+ EXPECT_TRUE(prefs.allow_universal_access_from_file_urls);
+ // Allow in page navigation if existing URL is file scheme.
+ const GURL file_url("file:///foo/index.html");
+ main_test_rfh()->NavigateAndCommitRendererInitiated(0, false, file_url);
+ EXPECT_EQ(0, rph->bad_msg_count());
+ EXPECT_TRUE(controller.IsURLInPageNavigation(different_origin_url, true,
+ main_test_rfh()));
EXPECT_EQ(0, rph->bad_msg_count());
+ // Don't honor allow_universal_access_from_file_urls if existing URL is
+ // not file scheme.
+ main_test_rfh()->NavigateAndCommitRendererInitiated(0, false, url);
EXPECT_FALSE(controller.IsURLInPageNavigation(different_origin_url, true,
main_test_rfh()));
EXPECT_EQ(1, rph->bad_msg_count());
+
+ // Remove allow_universal_access_from_file_urls flag.
+ prefs.allow_universal_access_from_file_urls = false;
+ test_rvh()->UpdateWebkitPreferences(prefs);
+ prefs = test_rvh()->GetWebkitPreferences();
+ EXPECT_FALSE(prefs.allow_universal_access_from_file_urls);
+
+ // Don't believe the renderer if it claims a cross-origin navigation is
+ // in-page.
+ EXPECT_EQ(1, rph->bad_msg_count());
+ EXPECT_FALSE(controller.IsURLInPageNavigation(different_origin_url, true,
+ main_test_rfh()));
+ EXPECT_EQ(2, rph->bad_msg_count());
}
// Some pages can have subframes with the same base URL (minus the reference) as
@@ -3191,25 +3609,30 @@ TEST_F(NavigationControllerTest, SameSubframe) {
NavigationControllerImpl& controller = controller_impl();
// Navigate the main frame.
const GURL url("http://www.google.com/");
- main_test_rfh()->SendNavigate(0, url);
+ main_test_rfh()->NavigateAndCommitRendererInitiated(0, true, url);
// We should be at the first navigation entry.
EXPECT_EQ(controller.GetEntryCount(), 1);
EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
- // Navigate a subframe that would normally count as in-page.
- const GURL subframe("http://www.google.com/#");
+ // Add and navigate a subframe that would normally count as in-page.
+ main_test_rfh()->OnCreateChildFrame(MSG_ROUTING_NONE, std::string(),
+ SandboxFlags::NONE);
+ RenderFrameHostImpl* subframe =
+ contents()->GetFrameTree()->root()->child_at(0)->current_frame_host();
+ const GURL subframe_url("http://www.google.com/#");
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = 0;
- params.url = subframe;
+ params.nav_entry_id = 0;
+ params.did_create_new_entry = false;
+ params.url = subframe_url;
params.transition = ui::PAGE_TRANSITION_AUTO_SUBFRAME;
params.should_update_history = false;
params.gesture = NavigationGestureAuto;
params.is_post = false;
- params.page_state = PageState::CreateFromURL(subframe);
+ params.page_state = PageState::CreateFromURL(subframe_url);
LoadCommittedDetails details;
- EXPECT_FALSE(controller.RendererDidNavigate(main_test_rfh(), params,
- &details));
+ EXPECT_FALSE(controller.RendererDidNavigate(subframe, params, &details));
// Nothing should have changed.
EXPECT_EQ(controller.GetEntryCount(), 1);
@@ -3288,15 +3711,44 @@ TEST_F(NavigationControllerTest, LazyReload) {
const GURL url("http://foo");
NavigateAndCommit(url);
ASSERT_FALSE(controller.NeedsReload());
+ EXPECT_NE(ui::PAGE_TRANSITION_RELOAD,
+ controller.GetLastCommittedEntry()->GetTransitionType());
// Request a reload to happen when the controller becomes active (e.g. after
// the renderer gets killed in background on Android).
controller.SetNeedsReload();
ASSERT_TRUE(controller.NeedsReload());
+ EXPECT_EQ(ui::PAGE_TRANSITION_RELOAD,
+ controller.GetLastCommittedEntry()->GetTransitionType());
// Set the controller as active, triggering the requested reload.
controller.SetActive(true);
ASSERT_FALSE(controller.NeedsReload());
+ EXPECT_EQ(ui::PAGE_TRANSITION_RELOAD,
+ controller.GetPendingEntry()->GetTransitionType());
+}
+
+// Test requesting and triggering a lazy reload without any committed entry.
+TEST_F(NavigationControllerTest, LazyReloadWithoutCommittedEntry) {
+ NavigationControllerImpl& controller = controller_impl();
+ const GURL url("http://foo");
+ controller.LoadURL(url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ ASSERT_FALSE(controller.NeedsReload());
+ EXPECT_EQ(ui::PAGE_TRANSITION_TYPED,
+ controller.GetPendingEntry()->GetTransitionType());
+
+ // Request a reload to happen when the controller becomes active (e.g. after
+ // the renderer gets killed in background on Android).
+ controller.SetNeedsReload();
+ ASSERT_TRUE(controller.NeedsReload());
+ EXPECT_EQ(ui::PAGE_TRANSITION_TYPED,
+ controller.GetPendingEntry()->GetTransitionType());
+
+ // Set the controller as active, triggering the requested reload.
+ controller.SetActive(true);
+ ASSERT_FALSE(controller.NeedsReload());
+ EXPECT_EQ(ui::PAGE_TRANSITION_TYPED,
+ controller.GetPendingEntry()->GetTransitionType());
}
// Tests a subframe navigation while a toplevel navigation is pending.
@@ -3314,9 +3766,15 @@ TEST_F(NavigationControllerTest, SubframeWhilePending) {
// Send a subframe update from the first page, as if one had just
// automatically loaded. Auto subframes don't increment the page ID.
+ main_test_rfh()->OnCreateChildFrame(MSG_ROUTING_NONE, std::string(),
+ SandboxFlags::NONE);
+ RenderFrameHostImpl* subframe =
+ contents()->GetFrameTree()->root()->child_at(0)->current_frame_host();
const GURL url1_sub("http://foo/subframe");
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = controller.GetLastCommittedEntry()->GetPageID();
+ params.nav_entry_id = 0;
+ params.did_create_new_entry = false;
params.url = url1_sub;
params.transition = ui::PAGE_TRANSITION_AUTO_SUBFRAME;
params.should_update_history = false;
@@ -3326,8 +3784,7 @@ TEST_F(NavigationControllerTest, SubframeWhilePending) {
LoadCommittedDetails details;
// This should return false meaning that nothing was actually updated.
- EXPECT_FALSE(controller.RendererDidNavigate(main_test_rfh(), params,
- &details));
+ EXPECT_FALSE(controller.RendererDidNavigate(subframe, params, &details));
// The notification should have updated the last committed one, and not
// the pending load.
@@ -3367,7 +3824,7 @@ TEST_F(NavigationControllerTest, CopyStateFrom) {
// The max page ID map should be copied over and updated with the max page ID
// from the current tab.
SiteInstance* instance1 =
- GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0));
+ other_controller.GetEntryAtIndex(0)->site_instance();
EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
// Ensure the SessionStorageNamespaceMaps are the same size and have
@@ -3402,10 +3859,8 @@ TEST_F(NavigationControllerTest, CopyStateFromAndPrune) {
NavigateAndCommit(url2);
// First two entries should have the same SiteInstance.
- SiteInstance* instance1 =
- GetSiteInstanceFromEntry(controller.GetEntryAtIndex(0));
- SiteInstance* instance2 =
- GetSiteInstanceFromEntry(controller.GetEntryAtIndex(1));
+ SiteInstance* instance1 = controller.GetEntryAtIndex(0)->site_instance();
+ SiteInstance* instance2 = controller.GetEntryAtIndex(1)->site_instance();
EXPECT_EQ(instance1, instance2);
EXPECT_EQ(0, controller.GetEntryAtIndex(0)->GetPageID());
EXPECT_EQ(1, controller.GetEntryAtIndex(1)->GetPageID());
@@ -3415,9 +3870,7 @@ TEST_F(NavigationControllerTest, CopyStateFromAndPrune) {
static_cast<TestWebContents*>(CreateTestWebContents()));
NavigationControllerImpl& other_controller = other_contents->GetController();
other_contents->NavigateAndCommit(url3);
- other_contents->ExpectSetHistoryLengthAndPrune(
- GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 2,
- other_controller.GetEntryAtIndex(0)->GetPageID());
+ other_contents->ExpectSetHistoryOffsetAndLength(2, 3);
other_controller.CopyStateFromAndPrune(&controller, false);
// other_controller should now contain the 3 urls: url1, url2 and url3.
@@ -3436,7 +3889,7 @@ TEST_F(NavigationControllerTest, CopyStateFromAndPrune) {
// A new SiteInstance in a different BrowsingInstance should be used for the
// new tab.
SiteInstance* instance3 =
- GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(2));
+ other_controller.GetEntryAtIndex(2)->site_instance();
EXPECT_NE(instance3, instance1);
EXPECT_FALSE(instance3->IsRelatedSiteInstance(instance1));
@@ -3463,9 +3916,7 @@ TEST_F(NavigationControllerTest, CopyStateFromAndPrune2) {
static_cast<TestWebContents*>(CreateTestWebContents()));
NavigationControllerImpl& other_controller = other_contents->GetController();
other_contents->NavigateAndCommit(url3);
- other_contents->ExpectSetHistoryLengthAndPrune(
- GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 1,
- other_controller.GetEntryAtIndex(0)->GetPageID());
+ other_contents->ExpectSetHistoryOffsetAndLength(1, 2);
other_controller.CopyStateFromAndPrune(&controller, false);
// other_controller should now contain: url1, url3
@@ -3480,7 +3931,7 @@ TEST_F(NavigationControllerTest, CopyStateFromAndPrune2) {
// The max page ID map should be copied over and updated with the max page ID
// from the current tab.
SiteInstance* instance1 =
- GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(1));
+ other_controller.GetEntryAtIndex(1)->site_instance();
EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
}
@@ -3501,9 +3952,7 @@ TEST_F(NavigationControllerTest, CopyStateFromAndPrune3) {
NavigationControllerImpl& other_controller = other_contents->GetController();
other_contents->NavigateAndCommit(url3);
other_contents->NavigateAndCommit(url4);
- other_contents->ExpectSetHistoryLengthAndPrune(
- GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(1)), 2,
- other_controller.GetEntryAtIndex(0)->GetPageID());
+ other_contents->ExpectSetHistoryOffsetAndLength(2, 3);
other_controller.CopyStateFromAndPrune(&controller, false);
// other_controller should now contain: url1, url2, url4
@@ -3518,7 +3967,7 @@ TEST_F(NavigationControllerTest, CopyStateFromAndPrune3) {
// The max page ID map should be copied over and updated with the max page ID
// from the current tab.
SiteInstance* instance1 =
- GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(2));
+ other_controller.GetEntryAtIndex(2)->site_instance();
EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
}
@@ -3541,9 +3990,7 @@ TEST_F(NavigationControllerTest, CopyStateFromAndPruneNotLast) {
other_contents->NavigateAndCommit(url4);
other_controller.GoBack();
other_contents->CommitPendingNavigation();
- other_contents->ExpectSetHistoryLengthAndPrune(
- GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 2,
- other_controller.GetEntryAtIndex(0)->GetPageID());
+ other_contents->ExpectSetHistoryOffsetAndLength(2, 3);
other_controller.CopyStateFromAndPrune(&controller, false);
// other_controller should now contain: url1, url2, url3
@@ -3558,7 +4005,7 @@ TEST_F(NavigationControllerTest, CopyStateFromAndPruneNotLast) {
// The max page ID map should be copied over and updated with the max page ID
// from the current tab.
SiteInstance* instance1 =
- GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(2));
+ other_controller.GetEntryAtIndex(2)->site_instance();
EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
}
@@ -3582,9 +4029,7 @@ TEST_F(NavigationControllerTest, CopyStateFromAndPruneTargetPending) {
other_contents->NavigateAndCommit(url3);
other_controller.LoadURL(
url4, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- other_contents->ExpectSetHistoryLengthAndPrune(
- GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 1,
- other_controller.GetEntryAtIndex(0)->GetPageID());
+ other_contents->ExpectSetHistoryOffsetAndLength(1, 2);
other_controller.CopyStateFromAndPrune(&controller, false);
// other_controller should now contain url1, url3, and a pending entry
@@ -3603,7 +4048,7 @@ TEST_F(NavigationControllerTest, CopyStateFromAndPruneTargetPending) {
// The max page ID map should be copied over and updated with the max page ID
// from the current tab.
SiteInstance* instance1 =
- GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0));
+ other_controller.GetEntryAtIndex(0)->site_instance();
EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
}
@@ -3626,12 +4071,10 @@ TEST_F(NavigationControllerTest, CopyStateFromAndPruneTargetPending2) {
// Simulate a client redirect, which has the same page ID as entry 2a.
other_controller.LoadURL(
url2b, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
- other_controller.GetPendingEntry()->SetPageID(
- other_controller.GetLastCommittedEntry()->GetPageID());
+ NavigationEntry* entry = other_controller.GetPendingEntry();
+ entry->SetPageID(other_controller.GetLastCommittedEntry()->GetPageID());
- other_contents->ExpectSetHistoryLengthAndPrune(
- GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 1,
- other_controller.GetEntryAtIndex(0)->GetPageID());
+ other_contents->ExpectSetHistoryOffsetAndLength(1, 2);
other_controller.CopyStateFromAndPrune(&controller, false);
// other_controller should now contain url1, url2a, and a pending entry
@@ -3648,12 +4091,14 @@ TEST_F(NavigationControllerTest, CopyStateFromAndPruneTargetPending2) {
EXPECT_EQ(url2b, other_controller.GetPendingEntry()->GetURL());
// Let the pending entry commit.
- other_contents->CommitPendingNavigation();
+ other_contents->TestDidNavigate(other_contents->GetMainFrame(),
+ entry->GetPageID(), 0, false, url2b,
+ ui::PAGE_TRANSITION_LINK);
// The max page ID map should be copied over and updated with the max page ID
// from the current tab.
SiteInstance* instance1 =
- GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(1));
+ other_controller.GetEntryAtIndex(1)->site_instance();
EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
}
@@ -3673,9 +4118,7 @@ TEST_F(NavigationControllerTest, CopyStateFromAndPruneSourcePending) {
static_cast<TestWebContents*>(CreateTestWebContents()));
NavigationControllerImpl& other_controller = other_contents->GetController();
other_contents->NavigateAndCommit(url3);
- other_contents->ExpectSetHistoryLengthAndPrune(
- GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 2,
- other_controller.GetEntryAtIndex(0)->GetPageID());
+ other_contents->ExpectSetHistoryOffsetAndLength(2, 3);
other_controller.CopyStateFromAndPrune(&controller, false);
// other_controller should now contain: url1, url2, url3
@@ -3691,7 +4134,7 @@ TEST_F(NavigationControllerTest, CopyStateFromAndPruneSourcePending) {
// The max page ID map should be copied over and updated with the max page ID
// from the current tab.
SiteInstance* instance1 =
- GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(2));
+ other_controller.GetEntryAtIndex(2)->site_instance();
EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
}
@@ -3720,9 +4163,7 @@ TEST_F(NavigationControllerTest, CopyStateFromAndPruneMaxEntries) {
static_cast<TestWebContents*>(CreateTestWebContents()));
NavigationControllerImpl& other_controller = other_contents->GetController();
other_contents->NavigateAndCommit(url4);
- other_contents->ExpectSetHistoryLengthAndPrune(
- GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 2,
- other_controller.GetEntryAtIndex(0)->GetPageID());
+ other_contents->ExpectSetHistoryOffsetAndLength(2, 3);
other_controller.CopyStateFromAndPrune(&controller, false);
// We should have received a pruned notification.
@@ -3758,10 +4199,8 @@ TEST_F(NavigationControllerTest, CopyStateFromAndPruneReplaceEntry) {
NavigateAndCommit(url2);
// First two entries should have the same SiteInstance.
- SiteInstance* instance1 =
- GetSiteInstanceFromEntry(controller.GetEntryAtIndex(0));
- SiteInstance* instance2 =
- GetSiteInstanceFromEntry(controller.GetEntryAtIndex(1));
+ SiteInstance* instance1 = controller.GetEntryAtIndex(0)->site_instance();
+ SiteInstance* instance2 = controller.GetEntryAtIndex(1)->site_instance();
EXPECT_EQ(instance1, instance2);
EXPECT_EQ(0, controller.GetEntryAtIndex(0)->GetPageID());
EXPECT_EQ(1, controller.GetEntryAtIndex(1)->GetPageID());
@@ -3771,9 +4210,7 @@ TEST_F(NavigationControllerTest, CopyStateFromAndPruneReplaceEntry) {
static_cast<TestWebContents*>(CreateTestWebContents()));
NavigationControllerImpl& other_controller = other_contents->GetController();
other_contents->NavigateAndCommit(url3);
- other_contents->ExpectSetHistoryLengthAndPrune(
- GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 1,
- other_controller.GetEntryAtIndex(0)->GetPageID());
+ other_contents->ExpectSetHistoryOffsetAndLength(1, 2);
other_controller.CopyStateFromAndPrune(&controller, true);
// other_controller should now contain the 2 urls: url1 and url3.
@@ -3790,7 +4227,7 @@ TEST_F(NavigationControllerTest, CopyStateFromAndPruneReplaceEntry) {
// A new SiteInstance in a different BrowsingInstance should be used for the
// new tab.
SiteInstance* instance3 =
- GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(1));
+ other_controller.GetEntryAtIndex(1)->site_instance();
EXPECT_NE(instance3, instance1);
EXPECT_FALSE(instance3->IsRelatedSiteInstance(instance1));
@@ -3825,9 +4262,7 @@ TEST_F(NavigationControllerTest, CopyStateFromAndPruneMaxEntriesReplaceEntry) {
static_cast<TestWebContents*>(CreateTestWebContents()));
NavigationControllerImpl& other_controller = other_contents->GetController();
other_contents->NavigateAndCommit(url4);
- other_contents->ExpectSetHistoryLengthAndPrune(
- GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 2,
- other_controller.GetEntryAtIndex(0)->GetPageID());
+ other_contents->ExpectSetHistoryOffsetAndLength(2, 3);
other_controller.CopyStateFromAndPrune(&controller, true);
// We should have received no pruned notification.
@@ -3882,9 +4317,7 @@ TEST_F(NavigationControllerTest, CopyRestoredStateAndNavigate) {
// Load a page, then copy state from |source_contents|.
NavigateAndCommit(kInitialUrl);
- contents()->ExpectSetHistoryLengthAndPrune(
- GetSiteInstanceFromEntry(controller_impl().GetEntryAtIndex(0)), 2,
- controller_impl().GetEntryAtIndex(0)->GetPageID());
+ contents()->ExpectSetHistoryOffsetAndLength(2, 3);
controller_impl().CopyStateFromAndPrune(&source_controller, false);
ASSERT_EQ(3, controller_impl().GetEntryCount());
@@ -3917,6 +4350,7 @@ TEST_F(NavigationControllerTest, HistoryNavigate) {
NavigateAndCommit(url3);
controller.GoBack();
contents()->CommitPendingNavigation();
+ process()->sink().ClearMessages();
// Simulate the page calling history.back(). It should create a pending entry.
contents()->OnGoToEntryAtOffset(-1);
@@ -3925,12 +4359,9 @@ TEST_F(NavigationControllerTest, HistoryNavigate) {
// it unloaded, simulate that.
contents()->ProceedWithCrossSiteNavigation();
// Also make sure we told the page to navigate.
- const IPC::Message* message =
- process()->sink().GetFirstMessageMatching(FrameMsg_Navigate::ID);
- ASSERT_TRUE(message != NULL);
- Tuple1<FrameMsg_Navigate_Params> nav_params;
- FrameMsg_Navigate::Read(message, &nav_params);
- EXPECT_EQ(url1, nav_params.a.common_params.url);
+ GURL nav_url = GetLastNavigationURL();
+ EXPECT_EQ(url1, nav_url);
+ contents()->CommitPendingNavigation();
process()->sink().ClearMessages();
// Now test history.forward()
@@ -3939,10 +4370,9 @@ TEST_F(NavigationControllerTest, HistoryNavigate) {
// The actual cross-navigation is suspended until the current RVH tells us
// it unloaded, simulate that.
contents()->ProceedWithCrossSiteNavigation();
- message = process()->sink().GetFirstMessageMatching(FrameMsg_Navigate::ID);
- ASSERT_TRUE(message != NULL);
- FrameMsg_Navigate::Read(message, &nav_params);
- EXPECT_EQ(url3, nav_params.a.common_params.url);
+ nav_url = GetLastNavigationURL();
+ EXPECT_EQ(url3, nav_url);
+ contents()->CommitPendingNavigation();
process()->sink().ClearMessages();
controller.DiscardNonCommittedEntries();
@@ -3950,8 +4380,7 @@ TEST_F(NavigationControllerTest, HistoryNavigate) {
// Make sure an extravagant history.go() doesn't break.
contents()->OnGoToEntryAtOffset(120); // Out of bounds.
EXPECT_EQ(-1, controller.GetPendingEntryIndex());
- message = process()->sink().GetFirstMessageMatching(FrameMsg_Navigate::ID);
- EXPECT_TRUE(message == NULL);
+ EXPECT_FALSE(HasNavigationRequest());
}
// Test call to PruneAllButLastCommitted for the only entry.
@@ -3960,9 +4389,7 @@ TEST_F(NavigationControllerTest, PruneAllButLastCommittedForSingle) {
const GURL url1("http://foo1");
NavigateAndCommit(url1);
- contents()->ExpectSetHistoryLengthAndPrune(
- GetSiteInstanceFromEntry(controller.GetEntryAtIndex(0)), 0,
- controller.GetEntryAtIndex(0)->GetPageID());
+ contents()->ExpectSetHistoryOffsetAndLength(0, 1);
controller.PruneAllButLastCommitted();
@@ -3984,9 +4411,7 @@ TEST_F(NavigationControllerTest, PruneAllButLastCommittedForFirst) {
controller.GoBack();
contents()->CommitPendingNavigation();
- contents()->ExpectSetHistoryLengthAndPrune(
- GetSiteInstanceFromEntry(controller.GetEntryAtIndex(0)), 0,
- controller.GetEntryAtIndex(0)->GetPageID());
+ contents()->ExpectSetHistoryOffsetAndLength(0, 1);
controller.PruneAllButLastCommitted();
@@ -4007,9 +4432,7 @@ TEST_F(NavigationControllerTest, PruneAllButLastCommittedForIntermediate) {
controller.GoBack();
contents()->CommitPendingNavigation();
- contents()->ExpectSetHistoryLengthAndPrune(
- GetSiteInstanceFromEntry(controller.GetEntryAtIndex(1)), 0,
- controller.GetEntryAtIndex(1)->GetPageID());
+ contents()->ExpectSetHistoryOffsetAndLength(0, 1);
controller.PruneAllButLastCommitted();
@@ -4031,11 +4454,11 @@ TEST_F(NavigationControllerTest, PruneAllButLastCommittedForPendingNotInList) {
// Create a pending entry that is not in the entry list.
controller.LoadURL(
url3, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ int entry_id = controller.GetPendingEntry()->GetUniqueID();
EXPECT_TRUE(controller.GetPendingEntry());
EXPECT_EQ(2, controller.GetEntryCount());
- contents()->ExpectSetHistoryLengthAndPrune(
- NULL, 0, controller.GetPendingEntry()->GetPageID());
+ contents()->ExpectSetHistoryOffsetAndLength(0, 1);
controller.PruneAllButLastCommitted();
// We should only have the last committed and pending entries at this point,
@@ -4047,7 +4470,8 @@ TEST_F(NavigationControllerTest, PruneAllButLastCommittedForPendingNotInList) {
EXPECT_EQ(1, controller.GetEntryCount());
// Try to commit the pending entry.
- main_test_rfh()->SendNavigate(2, url3);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigate(2, entry_id, true, url3);
EXPECT_EQ(-1, controller.GetPendingEntryIndex());
EXPECT_FALSE(controller.GetPendingEntry());
EXPECT_EQ(2, controller.GetEntryCount());
@@ -4089,7 +4513,7 @@ TEST_F(NavigationControllerTest, IsInitialNavigation) {
// After commit, it stays false.
const GURL url1("http://foo1");
- main_test_rfh()->SendNavigate(0, url1);
+ main_test_rfh()->NavigateAndCommitRendererInitiated(0, true, url1);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
EXPECT_FALSE(controller.IsInitialNavigation());
@@ -4112,7 +4536,8 @@ TEST_F(NavigationControllerTest, ClearFaviconOnRedirect) {
TestNotificationTracker notifications;
RegisterForAllNavNotifications(&notifications, &controller);
- main_test_rfh()->SendNavigate(0, kPageWithFavicon);
+ main_test_rfh()->NavigateAndCommitRendererInitiated(
+ 0, true, kPageWithFavicon);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -4127,10 +4552,14 @@ TEST_F(NavigationControllerTest, ClearFaviconOnRedirect) {
favicon_status.valid = true;
EXPECT_FALSE(DoImagesMatch(kDefaultFavicon, entry->GetFavicon().image));
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(kPageWithoutFavicon,
+ false);
+ main_test_rfh()->PrepareForCommit();
main_test_rfh()->SendNavigateWithTransition(
- 0, // same page ID.
- kPageWithoutFavicon,
- ui::PAGE_TRANSITION_CLIENT_REDIRECT);
+ 0, // same page ID.
+ 0, // nav_entry_id
+ false, // no new entry
+ kPageWithoutFavicon, ui::PAGE_TRANSITION_CLIENT_REDIRECT);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -4152,7 +4581,7 @@ TEST_F(NavigationControllerTest, BackNavigationDoesNotClearFavicon) {
TestNotificationTracker notifications;
RegisterForAllNavNotifications(&notifications, &controller);
- main_test_rfh()->SendNavigate(0, kUrl1);
+ main_test_rfh()->NavigateAndCommitRendererInitiated(0, true, kUrl1);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -4166,12 +4595,13 @@ TEST_F(NavigationControllerTest, BackNavigationDoesNotClearFavicon) {
favicon_status.valid = true;
// Navigate to another page and go back to the original page.
- main_test_rfh()->SendNavigate(1, kUrl2);
+ main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, kUrl2);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl1, false);
+ main_test_rfh()->PrepareForCommit();
main_test_rfh()->SendNavigateWithTransition(
- 0,
- kUrl1,
+ 0, controller.GetEntryAtIndex(0)->GetUniqueID(), false, kUrl1,
ui::PAGE_TRANSITION_FORWARD_BACK);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -4206,28 +4636,24 @@ TEST_F(NavigationControllerTest, MAYBE_PurgeScreenshot) {
new MockScreenshotManager(&controller);
controller.SetScreenshotManager(screenshot_manager);
for (int i = 0; i < controller.GetEntryCount(); ++i) {
- entry = NavigationEntryImpl::FromNavigationEntry(
- controller.GetEntryAtIndex(i));
+ entry = controller.GetEntryAtIndex(i);
screenshot_manager->TakeScreenshotFor(entry);
EXPECT_TRUE(entry->screenshot().get());
}
NavigateAndCommit(GURL("https://foo/"));
EXPECT_EQ(13, controller.GetEntryCount());
- entry = NavigationEntryImpl::FromNavigationEntry(
- controller.GetEntryAtIndex(11));
+ entry = controller.GetEntryAtIndex(11);
screenshot_manager->TakeScreenshotFor(entry);
for (int i = 0; i < 2; ++i) {
- entry = NavigationEntryImpl::FromNavigationEntry(
- controller.GetEntryAtIndex(i));
+ entry = controller.GetEntryAtIndex(i);
EXPECT_FALSE(entry->screenshot().get()) << "Screenshot " << i
<< " not purged";
}
for (int i = 2; i < controller.GetEntryCount() - 1; ++i) {
- entry = NavigationEntryImpl::FromNavigationEntry(
- controller.GetEntryAtIndex(i));
+ entry = controller.GetEntryAtIndex(i);
EXPECT_TRUE(entry->screenshot().get()) << "Screenshot not found for " << i;
}
@@ -4236,14 +4662,12 @@ TEST_F(NavigationControllerTest, MAYBE_PurgeScreenshot) {
contents()->CommitPendingNavigation();
EXPECT_EQ(5, controller.GetCurrentEntryIndex());
for (int i = 0; i < controller.GetEntryCount() - 1; ++i) {
- entry = NavigationEntryImpl::FromNavigationEntry(
- controller.GetEntryAtIndex(i));
+ entry = controller.GetEntryAtIndex(i);
screenshot_manager->TakeScreenshotFor(entry);
}
for (int i = 10; i <= 12; ++i) {
- entry = NavigationEntryImpl::FromNavigationEntry(
- controller.GetEntryAtIndex(i));
+ entry = controller.GetEntryAtIndex(i);
EXPECT_FALSE(entry->screenshot().get()) << "Screenshot " << i
<< " not purged";
screenshot_manager->TakeScreenshotFor(entry);
@@ -4254,14 +4678,12 @@ TEST_F(NavigationControllerTest, MAYBE_PurgeScreenshot) {
contents()->CommitPendingNavigation();
EXPECT_EQ(7, controller.GetCurrentEntryIndex());
for (int i = 0; i < controller.GetEntryCount() - 1; ++i) {
- entry = NavigationEntryImpl::FromNavigationEntry(
- controller.GetEntryAtIndex(i));
+ entry = controller.GetEntryAtIndex(i);
screenshot_manager->TakeScreenshotFor(entry);
}
for (int i = 0; i < 2; ++i) {
- entry = NavigationEntryImpl::FromNavigationEntry(
- controller.GetEntryAtIndex(i));
+ entry = controller.GetEntryAtIndex(i);
EXPECT_FALSE(entry->screenshot().get()) << "Screenshot " << i
<< " not purged";
}
@@ -4272,8 +4694,7 @@ TEST_F(NavigationControllerTest, MAYBE_PurgeScreenshot) {
controller.ClearAllScreenshots();
EXPECT_EQ(0, screenshot_manager->GetScreenshotCount());
for (int i = 0; i < controller.GetEntryCount(); ++i) {
- entry = NavigationEntryImpl::FromNavigationEntry(
- controller.GetEntryAtIndex(i));
+ entry = controller.GetEntryAtIndex(i);
EXPECT_FALSE(entry->screenshot().get()) << "Screenshot " << i
<< " not cleared";
}
@@ -4281,7 +4702,8 @@ TEST_F(NavigationControllerTest, MAYBE_PurgeScreenshot) {
TEST_F(NavigationControllerTest, PushStateUpdatesTitleAndFavicon) {
// Navigate.
- contents()->GetMainFrame()->SendNavigate(1, GURL("http://foo"));
+ main_test_rfh()->NavigateAndCommitRendererInitiated(
+ 1, true, GURL("http://foo"));
// Set title and favicon.
base::string16 title(base::ASCIIToUTF16("Title"));
@@ -4293,12 +4715,16 @@ TEST_F(NavigationControllerTest, PushStateUpdatesTitleAndFavicon) {
// history.pushState() is called.
FrameHostMsg_DidCommitProvisionalLoad_Params params;
- GURL url("http://foo#foo");
+ GURL kUrl2("http://foo#foo");
params.page_id = 2;
- params.url = url;
- params.page_state = PageState::CreateFromURL(url);
+ params.nav_entry_id = 0;
+ params.did_create_new_entry = true;
+ params.url = kUrl2;
+ params.page_state = PageState::CreateFromURL(kUrl2);
params.was_within_same_page = true;
- contents()->GetMainFrame()->SendNavigateWithParams(&params);
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl2, false);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigateWithParams(&params);
// The title should immediately be visible on the new NavigationEntry.
base::string16 new_title =
@@ -4337,13 +4763,16 @@ TEST_F(NavigationControllerTest, ClearHistoryList) {
// Verify that the pending entry correctly indicates that the session history
// should be cleared.
- NavigationEntryImpl* entry =
- NavigationEntryImpl::FromNavigationEntry(
- controller.GetPendingEntry());
+ NavigationEntryImpl* entry = controller.GetPendingEntry();
ASSERT_TRUE(entry);
EXPECT_TRUE(entry->should_clear_history_list());
- // Assume that the RF correctly cleared its history and commit the navigation.
+ // Assume that the RenderFrame correctly cleared its history and commit the
+ // navigation.
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation)) {
+ contents()->GetMainFrame()->SendBeforeUnloadACK(true);
+ }
contents()->GetPendingMainFrame()->
set_simulate_history_list_was_cleared(true);
contents()->CommitPendingNavigation();
@@ -4368,6 +4797,8 @@ TEST_F(NavigationControllerTest, PostThenReplaceStateThenReload) {
GURL url("http://foo");
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = 1;
+ params.nav_entry_id = 0;
+ params.did_create_new_entry = true;
params.url = url;
params.transition = ui::PAGE_TRANSITION_FORM_SUBMIT;
params.gesture = NavigationGestureUser;
@@ -4375,11 +4806,15 @@ TEST_F(NavigationControllerTest, PostThenReplaceStateThenReload) {
params.was_within_same_page = false;
params.is_post = true;
params.post_id = 2;
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(url, false);
+ main_test_rfh()->PrepareForCommit();
contents()->GetMainFrame()->SendNavigateWithParams(&params);
// history.replaceState() is called.
GURL replace_url("http://foo#foo");
params.page_id = 1;
+ params.nav_entry_id = 0;
+ params.did_create_new_entry = false;
params.url = replace_url;
params.transition = ui::PAGE_TRANSITION_LINK;
params.gesture = NavigationGestureUser;
@@ -4387,6 +4822,8 @@ TEST_F(NavigationControllerTest, PostThenReplaceStateThenReload) {
params.was_within_same_page = true;
params.is_post = false;
params.post_id = -1;
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(replace_url, false);
+ main_test_rfh()->PrepareForCommit();
contents()->GetMainFrame()->SendNavigateWithParams(&params);
// Now reload. replaceState overrides the POST, so we should not show a
@@ -4395,4 +4832,66 @@ TEST_F(NavigationControllerTest, PostThenReplaceStateThenReload) {
EXPECT_EQ(0, delegate->repost_form_warning_count());
}
+TEST_F(NavigationControllerTest, UnreachableURLGivesErrorPage) {
+ GURL url("http://foo");
+ FrameHostMsg_DidCommitProvisionalLoad_Params params;
+ params.page_id = 1;
+ params.nav_entry_id = 0;
+ params.did_create_new_entry = true;
+ params.url = url;
+ params.transition = ui::PAGE_TRANSITION_LINK;
+ params.gesture = NavigationGestureUser;
+ params.page_state = PageState::CreateFromURL(url);
+ params.was_within_same_page = false;
+ params.is_post = true;
+ params.post_id = 2;
+ params.url_is_unreachable = true;
+
+ // Navigate to new page.
+ {
+ LoadCommittedDetails details;
+ controller_impl().RendererDidNavigate(main_test_rfh(), params, &details);
+ EXPECT_EQ(PAGE_TYPE_ERROR,
+ controller_impl().GetLastCommittedEntry()->GetPageType());
+ EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, details.type);
+ }
+
+ // Navigate to existing page.
+ {
+ params.did_create_new_entry = false;
+ LoadCommittedDetails details;
+ controller_impl().RendererDidNavigate(main_test_rfh(), params, &details);
+ EXPECT_EQ(PAGE_TYPE_ERROR,
+ controller_impl().GetLastCommittedEntry()->GetPageType());
+ EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, details.type);
+ }
+
+ // Navigate to same page.
+ // Note: The call to LoadURL() creates a pending entry in order to trigger the
+ // same-page transition.
+ controller_impl().LoadURL(
+ url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ params.nav_entry_id = controller_impl().GetPendingEntry()->GetUniqueID();
+ params.transition = ui::PAGE_TRANSITION_TYPED;
+ {
+ LoadCommittedDetails details;
+ controller_impl().RendererDidNavigate(main_test_rfh(), params, &details);
+ EXPECT_EQ(PAGE_TYPE_ERROR,
+ controller_impl().GetLastCommittedEntry()->GetPageType());
+ EXPECT_EQ(NAVIGATION_TYPE_SAME_PAGE, details.type);
+ }
+
+ // Navigate in page.
+ params.url = GURL("http://foo#foo");
+ params.transition = ui::PAGE_TRANSITION_LINK;
+ params.was_within_same_page = true;
+ {
+ LoadCommittedDetails details;
+ controller_impl().RendererDidNavigate(main_test_rfh(), params, &details);
+ EXPECT_EQ(PAGE_TYPE_ERROR,
+ controller_impl().GetLastCommittedEntry()->GetPageType());
+ EXPECT_EQ(NAVIGATION_TYPE_IN_PAGE, details.type);
+ }
+}
+
} // namespace content
diff --git a/chromium/content/browser/frame_host/navigation_entry_impl.cc b/chromium/content/browser/frame_host/navigation_entry_impl.cc
index 7105608f774..c2b7675519e 100644
--- a/chromium/content/browser/frame_host/navigation_entry_impl.cc
+++ b/chromium/content/browser/frame_host/navigation_entry_impl.cc
@@ -4,9 +4,12 @@
#include "content/browser/frame_host/navigation_entry_impl.h"
+#include <queue>
+
#include "base/metrics/histogram.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "content/common/navigation_params.h"
#include "content/public/common/content_constants.h"
#include "content/public/common/url_constants.h"
#include "net/base/net_util.h"
@@ -23,12 +26,24 @@ namespace content {
int NavigationEntryImpl::kInvalidBindings = -1;
-NavigationEntry* NavigationEntry::Create() {
- return new NavigationEntryImpl();
+NavigationEntryImpl::TreeNode::TreeNode(FrameNavigationEntry* frame_entry)
+ : frame_entry(frame_entry) {
}
-NavigationEntry* NavigationEntry::Create(const NavigationEntry& copy) {
- return new NavigationEntryImpl(static_cast<const NavigationEntryImpl&>(copy));
+NavigationEntryImpl::TreeNode::~TreeNode() {
+}
+
+NavigationEntryImpl::TreeNode* NavigationEntryImpl::TreeNode::Clone() const {
+ // Clone the tree using a copy of the FrameNavigationEntry, without sharing.
+ NavigationEntryImpl::TreeNode* copy =
+ new NavigationEntryImpl::TreeNode(frame_entry->Clone());
+
+ // TODO(creis): Clone children once we add them.
+ return copy;
+}
+
+NavigationEntry* NavigationEntry::Create() {
+ return new NavigationEntryImpl();
}
NavigationEntryImpl* NavigationEntryImpl::FromNavigationEntry(
@@ -37,23 +52,8 @@ NavigationEntryImpl* NavigationEntryImpl::FromNavigationEntry(
}
NavigationEntryImpl::NavigationEntryImpl()
- : unique_id_(GetUniqueIDInConstructor()),
- site_instance_(NULL),
- bindings_(kInvalidBindings),
- page_type_(PAGE_TYPE_NORMAL),
- update_virtual_url_with_url_(false),
- page_id_(-1),
- transition_type_(ui::PAGE_TRANSITION_LINK),
- has_post_data_(false),
- post_id_(-1),
- restore_type_(RESTORE_NONE),
- is_overriding_user_agent_(false),
- http_status_code_(0),
- is_renderer_initiated_(false),
- should_replace_entry_(false),
- should_clear_history_list_(false),
- can_load_local_resources_(false),
- frame_tree_node_id_(-1) {
+ : NavigationEntryImpl(nullptr, -1, GURL(), Referrer(), base::string16(),
+ ui::PAGE_TRANSITION_LINK, false) {
}
NavigationEntryImpl::NavigationEntryImpl(SiteInstanceImpl* instance,
@@ -63,12 +63,11 @@ NavigationEntryImpl::NavigationEntryImpl(SiteInstanceImpl* instance,
const base::string16& title,
ui::PageTransition transition_type,
bool is_renderer_initiated)
- : unique_id_(GetUniqueIDInConstructor()),
- site_instance_(instance),
+ : frame_tree_(
+ new TreeNode(new FrameNavigationEntry(-1, instance, url, referrer))),
+ unique_id_(GetUniqueIDInConstructor()),
bindings_(kInvalidBindings),
page_type_(PAGE_TYPE_NORMAL),
- url_(url),
- referrer_(referrer),
update_virtual_url_with_url_(false),
title_(title),
page_id_(page_id),
@@ -97,12 +96,12 @@ PageType NavigationEntryImpl::GetPageType() const {
}
void NavigationEntryImpl::SetURL(const GURL& url) {
- url_ = url;
+ frame_tree_->frame_entry->set_url(url);
cached_display_title_.clear();
}
const GURL& NavigationEntryImpl::GetURL() const {
- return url_;
+ return frame_tree_->frame_entry->url();
}
void NavigationEntryImpl::SetBaseURLForDataURL(const GURL& url) {
@@ -114,20 +113,20 @@ const GURL& NavigationEntryImpl::GetBaseURLForDataURL() const {
}
void NavigationEntryImpl::SetReferrer(const Referrer& referrer) {
- referrer_ = referrer;
+ frame_tree_->frame_entry->set_referrer(referrer);
}
const Referrer& NavigationEntryImpl::GetReferrer() const {
- return referrer_;
+ return frame_tree_->frame_entry->referrer();
}
void NavigationEntryImpl::SetVirtualURL(const GURL& url) {
- virtual_url_ = (url == url_) ? GURL() : url;
+ virtual_url_ = (url == GetURL()) ? GURL() : url;
cached_display_title_.clear();
}
const GURL& NavigationEntryImpl::GetVirtualURL() const {
- return virtual_url_.is_empty() ? url_ : virtual_url_;
+ return virtual_url_.is_empty() ? GetURL() : virtual_url_;
}
void NavigationEntryImpl::SetTitle(const base::string16& title) {
@@ -156,7 +155,13 @@ int32 NavigationEntryImpl::GetPageID() const {
}
void NavigationEntryImpl::set_site_instance(SiteInstanceImpl* site_instance) {
- site_instance_ = site_instance;
+ // TODO(creis): Update all callers and remove this method.
+ frame_tree_->frame_entry->set_site_instance(site_instance);
+}
+
+void NavigationEntryImpl::set_source_site_instance(
+ SiteInstanceImpl* source_site_instance) {
+ source_site_instance_ = source_site_instance;
}
void NavigationEntryImpl::SetBindings(int bindings) {
@@ -182,12 +187,12 @@ const base::string16& NavigationEntryImpl::GetTitleForDisplay(
base::string16 title;
if (!virtual_url_.is_empty()) {
title = net::FormatUrl(virtual_url_, languages);
- } else if (!url_.is_empty()) {
- title = net::FormatUrl(url_, languages);
+ } else if (!GetURL().is_empty()) {
+ title = net::FormatUrl(GetURL(), languages);
}
// For file:// URLs use the filename as the title, not the full path.
- if (url_.SchemeIsFile()) {
+ if (GetURL().SchemeIsFile()) {
base::string16::size_type slashpos = title.rfind('/');
if (slashpos != base::string16::npos)
title = title.substr(slashpos + 1);
@@ -310,14 +315,6 @@ bool NavigationEntryImpl::GetCanLoadLocalResources() const {
return can_load_local_resources_;
}
-void NavigationEntryImpl::SetFrameToNavigate(const std::string& frame_name) {
- frame_to_navigate_ = frame_name;
-}
-
-const std::string& NavigationEntryImpl::GetFrameToNavigate() const {
- return frame_to_navigate_;
-}
-
void NavigationEntryImpl::SetExtraData(const std::string& key,
const base::string16& data) {
extra_data_[key] = data;
@@ -337,16 +334,188 @@ void NavigationEntryImpl::ClearExtraData(const std::string& key) {
extra_data_.erase(key);
}
+NavigationEntryImpl* NavigationEntryImpl::Clone() const {
+ NavigationEntryImpl* copy = new NavigationEntryImpl();
+
+ // TODO(creis): Only share the same FrameNavigationEntries if cloning within
+ // the same tab.
+ copy->frame_tree_.reset(frame_tree_->Clone());
+
+ // Copy all state over, unless cleared in ResetForCommit.
+ copy->unique_id_ = unique_id_;
+ copy->bindings_ = bindings_;
+ copy->page_type_ = page_type_;
+ copy->virtual_url_ = virtual_url_;
+ copy->update_virtual_url_with_url_ = update_virtual_url_with_url_;
+ copy->title_ = title_;
+ copy->favicon_ = favicon_;
+ copy->page_state_ = page_state_;
+ copy->page_id_ = page_id_;
+ copy->ssl_ = ssl_;
+ copy->transition_type_ = transition_type_;
+ copy->user_typed_url_ = user_typed_url_;
+ copy->has_post_data_ = has_post_data_;
+ copy->post_id_ = post_id_;
+ copy->restore_type_ = restore_type_;
+ copy->original_request_url_ = original_request_url_;
+ copy->is_overriding_user_agent_ = is_overriding_user_agent_;
+ copy->timestamp_ = timestamp_;
+ copy->http_status_code_ = http_status_code_;
+ // ResetForCommit: browser_initiated_post_data_
+ copy->screenshot_ = screenshot_;
+ copy->extra_headers_ = extra_headers_;
+ // ResetForCommit: source_site_instance_
+ copy->base_url_for_data_url_ = base_url_for_data_url_;
+ // ResetForCommit: is_renderer_initiated_
+ copy->cached_display_title_ = cached_display_title_;
+ // ResetForCommit: transferred_global_request_id_
+ // ResetForCommit: should_replace_entry_
+ copy->redirect_chain_ = redirect_chain_;
+ // ResetForCommit: should_clear_history_list_
+ // ResetForCommit: frame_tree_node_id_
+ // ResetForCommit: intent_received_timestamp_
+ copy->extra_data_ = extra_data_;
+
+ return copy;
+}
+
+CommonNavigationParams NavigationEntryImpl::ConstructCommonNavigationParams(
+ FrameMsg_Navigate_Type::Value navigation_type) const {
+ FrameMsg_UILoadMetricsReportType::Value report_type =
+ FrameMsg_UILoadMetricsReportType::NO_REPORT;
+ base::TimeTicks ui_timestamp = base::TimeTicks();
+#if defined(OS_ANDROID)
+ if (!intent_received_timestamp().is_null())
+ report_type = FrameMsg_UILoadMetricsReportType::REPORT_INTENT;
+ ui_timestamp = intent_received_timestamp();
+#endif
+
+ return CommonNavigationParams(
+ GetURL(), GetReferrer(), GetTransitionType(), navigation_type,
+ !IsViewSourceMode(), ui_timestamp, report_type, GetBaseURLForDataURL(),
+ GetHistoryURLForDataURL());
+}
+
+StartNavigationParams NavigationEntryImpl::ConstructStartNavigationParams()
+ const {
+ std::vector<unsigned char> browser_initiated_post_data;
+ if (GetBrowserInitiatedPostData()) {
+ browser_initiated_post_data.assign(
+ GetBrowserInitiatedPostData()->front(),
+ GetBrowserInitiatedPostData()->front() +
+ GetBrowserInitiatedPostData()->size());
+ }
+
+ return StartNavigationParams(
+ GetHasPostData(), extra_headers(), browser_initiated_post_data,
+ should_replace_entry(), transferred_global_request_id().child_id,
+ transferred_global_request_id().request_id);
+}
+
+RequestNavigationParams NavigationEntryImpl::ConstructRequestNavigationParams(
+ base::TimeTicks navigation_start,
+ bool intended_as_new_entry,
+ int pending_history_list_offset,
+ int current_history_list_offset,
+ int current_history_list_length) const {
+ // Set the redirect chain to the navigation's redirects, unless returning to a
+ // completed navigation (whose previous redirects don't apply).
+ std::vector<GURL> redirects;
+ if (ui::PageTransitionIsNewNavigation(GetTransitionType())) {
+ redirects = GetRedirectChain();
+ }
+
+ int pending_offset_to_send = pending_history_list_offset;
+ int current_offset_to_send = current_history_list_offset;
+ int current_length_to_send = current_history_list_length;
+ if (should_clear_history_list()) {
+ // Set the history list related parameters to the same values a
+ // NavigationController would return before its first navigation. This will
+ // fully clear the RenderView's view of the session history.
+ pending_offset_to_send = -1;
+ current_offset_to_send = -1;
+ current_length_to_send = 0;
+ }
+ return RequestNavigationParams(
+ GetIsOverridingUserAgent(), navigation_start, redirects,
+ GetCanLoadLocalResources(), base::Time::Now(), GetPageState(),
+ GetPageID(), GetUniqueID(), intended_as_new_entry, pending_offset_to_send,
+ current_offset_to_send, current_length_to_send,
+ should_clear_history_list());
+}
+
void NavigationEntryImpl::ResetForCommit() {
// Any state that only matters when a navigation entry is pending should be
// cleared here.
- SetBrowserInitiatedPostData(NULL);
+ // TODO(creis): This state should be moved to NavigationRequest once
+ // PlzNavigate is enabled.
+ SetBrowserInitiatedPostData(nullptr);
+ set_source_site_instance(nullptr);
set_is_renderer_initiated(false);
set_transferred_global_request_id(GlobalRequestID());
set_should_replace_entry(false);
set_should_clear_history_list(false);
set_frame_tree_node_id(-1);
+
+#if defined(OS_ANDROID)
+ // Reset the time stamp so that the metrics are not reported if this entry is
+ // loaded again in the future.
+ set_intent_received_timestamp(base::TimeTicks());
+#endif
+}
+
+void NavigationEntryImpl::AddOrUpdateFrameEntry(FrameTreeNode* frame_tree_node,
+ SiteInstanceImpl* site_instance,
+ const GURL& url,
+ const Referrer& referrer) {
+ // We should already have a TreeNode for the parent node by the time this node
+ // commits. Find it first.
+ DCHECK(frame_tree_node->parent());
+ int parent_ftn_id = frame_tree_node->parent()->frame_tree_node_id();
+ bool found = false;
+ NavigationEntryImpl::TreeNode* parent_node = nullptr;
+ std::queue<NavigationEntryImpl::TreeNode*> work_queue;
+ work_queue.push(root_node());
+ while (!found && !work_queue.empty()) {
+ parent_node = work_queue.front();
+ work_queue.pop();
+ // The root FNE will have an ID of -1, so check for that as well.
+ if (parent_node->frame_entry->frame_tree_node_id() == parent_ftn_id ||
+ (parent_node->frame_entry->frame_tree_node_id() == -1 &&
+ parent_node == root_node() &&
+ frame_tree_node->parent()->IsMainFrame())) {
+ found = true;
+ break;
+ }
+ // Enqueue any children and keep looking.
+ for (auto& child : parent_node->children)
+ work_queue.push(child);
+ }
+ if (!found) {
+ // The renderer should not send a commit for a subframe before its parent.
+ // TODO(creis): This can currently happen because we don't yet clone the
+ // FrameNavigationEntry tree on manual subframe navigations. Once that's
+ // added, we should kill the renderer if we get here.
+ return;
+ }
+
+ // Now check whether we have a TreeNode for the node itself.
+ int frame_tree_node_id = frame_tree_node->frame_tree_node_id();
+ for (TreeNode* child : parent_node->children) {
+ if (child->frame_entry->frame_tree_node_id() == frame_tree_node_id) {
+ // Update the existing FrameNavigationEntry.
+ child->frame_entry->UpdateEntry(site_instance, url, referrer);
+ return;
+ }
+ }
+
+ // No entry exists yet, so create a new one. Unordered list, since we expect
+ // to look up entries by frame sequence number or unique name.
+ FrameNavigationEntry* frame_entry = new FrameNavigationEntry(
+ frame_tree_node_id, site_instance, url, referrer);
+ parent_node->children.push_back(
+ new NavigationEntryImpl::TreeNode(frame_entry));
}
void NavigationEntryImpl::SetScreenshotPNGData(
@@ -356,4 +525,8 @@ void NavigationEntryImpl::SetScreenshotPNGData(
UMA_HISTOGRAM_MEMORY_KB("Overscroll.ScreenshotSize", screenshot_->size());
}
+GURL NavigationEntryImpl::GetHistoryURLForDataURL() const {
+ return GetBaseURLForDataURL().is_empty() ? GURL() : GetVirtualURL();
+}
+
} // namespace content
diff --git a/chromium/content/browser/frame_host/navigation_entry_impl.h b/chromium/content/browser/frame_host/navigation_entry_impl.h
index 37de18213cb..8c3fbb5226c 100644
--- a/chromium/content/browser/frame_host/navigation_entry_impl.h
+++ b/chromium/content/browser/frame_host/navigation_entry_impl.h
@@ -7,7 +7,12 @@
#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_vector.h"
+#include "base/time/time.h"
+#include "content/browser/frame_host/frame_navigation_entry.h"
+#include "content/browser/frame_host/frame_tree_node.h"
#include "content/browser/site_instance_impl.h"
+#include "content/common/frame_message_enums.h"
#include "content/public/browser/favicon_status.h"
#include "content/public/browser/global_request_id.h"
#include "content/public/browser/navigation_entry.h"
@@ -15,10 +20,35 @@
#include "content/public/common/ssl_status.h"
namespace content {
+struct CommonNavigationParams;
+struct RequestNavigationParams;
+struct StartNavigationParams;
class CONTENT_EXPORT NavigationEntryImpl
: public NON_EXPORTED_BASE(NavigationEntry) {
public:
+ // Represents a tree of FrameNavigationEntries that make up this joint session
+ // history item. The tree currently only tracks the main frame.
+ // TODO(creis): Populate the tree with subframe entries in --site-per-process.
+ struct TreeNode {
+ TreeNode(FrameNavigationEntry* frame_entry);
+ ~TreeNode();
+
+ // Returns a deep copy of the tree with copies of each node's
+ // FrameNavigationEntries. We do not yet share FrameNavigationEntries
+ // across trees.
+ // TODO(creis): For --site-per-process, share FrameNavigationEntries between
+ // NavigationEntries of the same tab.
+ TreeNode* Clone() const;
+
+ // Ref counted pointer that keeps the FrameNavigationEntry alive as long as
+ // it is needed by this node's NavigationEntry.
+ scoped_refptr<FrameNavigationEntry> frame_entry;
+
+ // List of child TreeNodes, which will be deleted when this node is.
+ ScopedVector<TreeNode> children;
+ };
+
static NavigationEntryImpl* FromNavigationEntry(NavigationEntry* entry);
// The value of bindings() before it is set during commit.
@@ -75,8 +105,6 @@ class CONTENT_EXPORT NavigationEntryImpl
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,
@@ -88,23 +116,69 @@ class CONTENT_EXPORT NavigationEntryImpl
const std::vector<GURL>& GetRedirectChain() const override;
bool IsRestored() const override;
+ // Creates a copy of this NavigationEntryImpl that can be modified
+ // independently from the original. Does not copy any value that would be
+ // cleared in ResetForCommit.
+ // TODO(creis): Once we start sharing FrameNavigationEntries between
+ // NavigationEntryImpls, we will need to support two versions of Clone: one
+ // that shares the existing FrameNavigationEntries (for use within the same
+ // tab) and one that draws them from a different pool (for use in a new tab).
+ NavigationEntryImpl* Clone() const;
+
+ // Helper functions to construct NavigationParameters for a navigation to this
+ // NavigationEntry.
+ CommonNavigationParams ConstructCommonNavigationParams(
+ FrameMsg_Navigate_Type::Value navigation_type) const;
+ StartNavigationParams ConstructStartNavigationParams() const;
+ RequestNavigationParams ConstructRequestNavigationParams(
+ base::TimeTicks navigation_start,
+ bool intended_as_new_entry,
+ int pending_offset_to_send,
+ int current_offset_to_send,
+ int current_length_to_send) const;
+
// Once a navigation entry is committed, we should no longer track several
// pieces of non-persisted state, as documented on the members below.
void ResetForCommit();
+ // Exposes the tree of FrameNavigationEntries that make up this joint session
+ // history item.
+ // In default Chrome, this tree only has a root node with an unshared
+ // FrameNavigationEntry. Subframes are only added to the tree if the
+ // --site-per-process flag is passed.
+ TreeNode* root_node() const {
+ return frame_tree_.get();
+ }
+
+ // Finds the TreeNode associated with |frame_tree_node_id| to add or update
+ // its FrameNavigationEntry. A new FrameNavigationEntry is added if none
+ // exists, or else the existing one (which might be shared with other
+ // NavigationEntries) is updated with the given parameters.
+ void AddOrUpdateFrameEntry(FrameTreeNode* frame_tree_node,
+ SiteInstanceImpl* site_instance,
+ const GURL& url,
+ const Referrer& referrer);
+
void set_unique_id(int unique_id) {
unique_id_ = unique_id;
}
- // The SiteInstance tells us how to share sub-processes. This is a reference
- // counted pointer to a shared site instance.
+ // The SiteInstance represents which pages must share processes. This is a
+ // reference counted pointer to a shared SiteInstance.
//
// Note that the SiteInstance should usually not be changed after it is set,
// but this may happen if the NavigationEntry was cloned and needs to use a
// different SiteInstance.
void set_site_instance(SiteInstanceImpl* site_instance);
SiteInstanceImpl* site_instance() const {
- return site_instance_.get();
+ return frame_tree_->frame_entry->site_instance();
+ }
+
+ // The |source_site_instance| is used to identify the SiteInstance of the
+ // frame that initiated the navigation.
+ void set_source_site_instance(SiteInstanceImpl* source_site_instance);
+ SiteInstanceImpl* source_site_instance() const {
+ return source_site_instance_.get();
}
// Remember the set of bindings granted to this NavigationEntry at the time
@@ -209,29 +283,47 @@ class CONTENT_EXPORT NavigationEntryImpl
// Indicates which FrameTreeNode to navigate. Currently only used if the
// --site-per-process flag is passed.
- int64 frame_tree_node_id() const {
+ int frame_tree_node_id() const {
return frame_tree_node_id_;
}
- void set_frame_tree_node_id(int64 frame_tree_node_id) {
+ void set_frame_tree_node_id(int frame_tree_node_id) {
frame_tree_node_id_ = frame_tree_node_id;
}
+ // Returns the history URL for a data URL to use in Blink.
+ GURL GetHistoryURLForDataURL() const;
+
+#if defined(OS_ANDROID)
+ base::TimeTicks intent_received_timestamp() const {
+ return intent_received_timestamp_;
+ }
+
+ void set_intent_received_timestamp(
+ const base::TimeTicks intent_received_timestamp) {
+ intent_received_timestamp_ = intent_received_timestamp;
+ }
+#endif
+
private:
// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
// Session/Tab restore save portions of this class so that it can be recreated
// later. If you add a new field that needs to be persisted you'll have to
// update SessionService/TabRestoreService and Android WebView
// state_serializer.cc appropriately.
+ // For all new fields, update |Clone| and possibly |ResetForCommit|.
// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+ // Tree of FrameNavigationEntries, one for each frame on the page.
+ // TODO(creis): Once FrameNavigationEntries can be shared across multiple
+ // NavigationEntries, we will need to update Session/Tab restore. For now,
+ // each NavigationEntry's tree has its own unshared FrameNavigationEntries.
+ scoped_ptr<TreeNode> frame_tree_;
+
// See the accessors above for descriptions.
int unique_id_;
- scoped_refptr<SiteInstanceImpl> site_instance_;
// TODO(creis): Persist bindings_. http://crbug.com/173672.
int bindings_;
PageType page_type_;
- GURL url_;
- Referrer referrer_;
GURL virtual_url_;
bool update_virtual_url_with_url_;
base::string16 title_;
@@ -268,6 +360,9 @@ class CONTENT_EXPORT NavigationEntryImpl
// This member is not persisted with session restore.
std::string extra_headers_;
+ // This member is cleared in |ResetForCommit| and not persisted.
+ scoped_refptr<SiteInstanceImpl> source_site_instance_;
+
// Used for specifying base URL for pages loaded via data URLs. Only used and
// persisted by Android WebView.
GURL base_url_for_data_url_;
@@ -320,23 +415,25 @@ class CONTENT_EXPORT NavigationEntryImpl
// value is not needed after the entry commits and is not persisted.
bool can_load_local_resources_;
- // If not empty, the name of the frame to navigate. This field is not
- // persisted, because it is currently only used in tests.
- std::string frame_to_navigate_;
-
// If not -1, this indicates which FrameTreeNode to navigate. This field is
// not persisted because it is experimental and only used when the
// --site-per-process flag is passed. It is cleared in |ResetForCommit|
// because we only use it while the navigation is pending.
// TODO(creis): Move this to FrameNavigationEntry.
- int64 frame_tree_node_id_;
+ int frame_tree_node_id_;
+
+#if defined(OS_ANDROID)
+ // The time at which Chrome received the Android Intent that triggered this
+ // URL load operation. Reset at commit and not persisted.
+ base::TimeTicks intent_received_timestamp_;
+#endif
// Used to store extra data to support browser features. This member is not
// persisted, unless specific data is taken out/put back in at save/restore
// time (see TabNavigation for an example of this).
std::map<std::string, base::string16> extra_data_;
- // Copy and assignment is explicitly allowed for this class.
+ DISALLOW_COPY_AND_ASSIGN(NavigationEntryImpl);
};
} // namespace content
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 663386a1316..3aec3587251 100644
--- a/chromium/content/browser/frame_host/navigation_entry_impl_unittest.cc
+++ b/chromium/content/browser/frame_host/navigation_entry_impl_unittest.cc
@@ -207,10 +207,27 @@ TEST_F(NavigationEntryTest, NavigationEntryAccessors) {
entry2_->SetBrowserInitiatedPostData(post_data.get());
EXPECT_EQ(post_data->front(),
entry2_->GetBrowserInitiatedPostData()->front());
+}
+
+// Test basic Clone behavior.
+TEST_F(NavigationEntryTest, NavigationEntryClone) {
+ // Set some additional values.
+ entry2_->SetTransitionType(ui::PAGE_TRANSITION_RELOAD);
+ entry2_->set_should_replace_entry(true);
+
+ scoped_ptr<NavigationEntryImpl> clone(entry2_->Clone());
+
+ // Value from FrameNavigationEntry.
+ EXPECT_EQ(entry2_->site_instance(), clone->site_instance());
+
+ // Value from constructor.
+ EXPECT_EQ(entry2_->GetTitle(), clone->GetTitle());
+
+ // Value set after constructor.
+ EXPECT_EQ(entry2_->GetTransitionType(), clone->GetTransitionType());
- // Frame to navigate.
- EXPECT_TRUE(entry1_->GetFrameToNavigate().empty());
- EXPECT_TRUE(entry2_->GetFrameToNavigate().empty());
+ // Value not copied due to ResetForCommit.
+ EXPECT_NE(entry2_->should_replace_entry(), clone->should_replace_entry());
}
// Test timestamps.
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 162cfb79043..121898b07c0 100644
--- a/chromium/content/browser/frame_host/navigation_entry_screenshot_manager.cc
+++ b/chromium/content/browser/frame_host/navigation_entry_screenshot_manager.cc
@@ -78,8 +78,7 @@ void NavigationEntryScreenshotManager::TakeScreenshot() {
if (!overscroll_enabled)
return;
- NavigationEntryImpl* entry =
- NavigationEntryImpl::FromNavigationEntry(owner_->GetLastCommittedEntry());
+ NavigationEntryImpl* entry = owner_->GetLastCommittedEntry();
if (!entry)
return;
@@ -109,8 +108,7 @@ void NavigationEntryScreenshotManager::TakeScreenshot() {
void NavigationEntryScreenshotManager::ClearAllScreenshots() {
int count = owner_->GetEntryCount();
for (int i = 0; i < count; ++i) {
- ClearScreenshot(NavigationEntryImpl::FromNavigationEntry(
- owner_->GetEntryAtIndex(i)));
+ ClearScreenshot(owner_->GetEntryAtIndex(i));
}
DCHECK_EQ(GetScreenshotCount(), 0);
}
@@ -135,15 +133,16 @@ void NavigationEntryScreenshotManager::SetMinScreenshotIntervalMS(
min_screenshot_interval_ms_ = interval_ms;
}
-void NavigationEntryScreenshotManager::OnScreenshotTaken(int unique_id,
- bool success,
- const SkBitmap& bitmap) {
+void NavigationEntryScreenshotManager::OnScreenshotTaken(
+ int unique_id,
+ const SkBitmap& bitmap,
+ ReadbackResponse response) {
NavigationEntryImpl* entry = NULL;
int entry_count = owner_->GetEntryCount();
for (int i = 0; i < entry_count; ++i) {
- NavigationEntry* iter = owner_->GetEntryAtIndex(i);
+ NavigationEntryImpl* iter = owner_->GetEntryAtIndex(i);
if (iter->GetUniqueID() == unique_id) {
- entry = NavigationEntryImpl::FromNavigationEntry(iter);
+ entry = iter;
break;
}
}
@@ -153,7 +152,7 @@ void NavigationEntryScreenshotManager::OnScreenshotTaken(int unique_id,
return;
}
- if (!success || bitmap.empty() || bitmap.isNull()) {
+ if ((response != READBACK_SUCCESS) || bitmap.empty() || bitmap.isNull()) {
if (!ClearScreenshot(entry))
OnScreenshotSet(entry);
return;
@@ -172,8 +171,7 @@ int NavigationEntryScreenshotManager::GetScreenshotCount() const {
int screenshot_count = 0;
int entry_count = owner_->GetEntryCount();
for (int i = 0; i < entry_count; ++i) {
- NavigationEntryImpl* entry =
- NavigationEntryImpl::FromNavigationEntry(owner_->GetEntryAtIndex(i));
+ NavigationEntryImpl* entry = owner_->GetEntryAtIndex(i);
if (entry->screenshot().get())
screenshot_count++;
}
@@ -186,9 +184,9 @@ void NavigationEntryScreenshotManager::OnScreenshotEncodeComplete(
NavigationEntryImpl* entry = NULL;
int entry_count = owner_->GetEntryCount();
for (int i = 0; i < entry_count; ++i) {
- NavigationEntry* iter = owner_->GetEntryAtIndex(i);
+ NavigationEntryImpl* iter = owner_->GetEntryAtIndex(i);
if (iter->GetUniqueID() == unique_id) {
- entry = NavigationEntryImpl::FromNavigationEntry(iter);
+ entry = iter;
break;
}
}
@@ -223,8 +221,7 @@ void NavigationEntryScreenshotManager::PurgeScreenshotsIfNecessary() {
const int current = owner_->GetCurrentEntryIndex();
const int num_entries = owner_->GetEntryCount();
int available_slots = kMaxScreenshots;
- if (NavigationEntryImpl::FromNavigationEntry(owner_->GetEntryAtIndex(current))
- ->screenshot().get()) {
+ if (owner_->GetEntryAtIndex(current)->screenshot().get()) {
--available_slots;
}
@@ -241,16 +238,14 @@ void NavigationEntryScreenshotManager::PurgeScreenshotsIfNecessary() {
int forward = current + 1;
while (available_slots > 0 && (back >= 0 || forward < num_entries)) {
if (back >= 0) {
- NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
- owner_->GetEntryAtIndex(back));
+ NavigationEntryImpl* entry = owner_->GetEntryAtIndex(back);
if (entry->screenshot().get())
--available_slots;
--back;
}
if (available_slots > 0 && forward < num_entries) {
- NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
- owner_->GetEntryAtIndex(forward));
+ NavigationEntryImpl* entry = owner_->GetEntryAtIndex(forward);
if (entry->screenshot().get())
--available_slots;
++forward;
@@ -260,16 +255,14 @@ void NavigationEntryScreenshotManager::PurgeScreenshotsIfNecessary() {
// Purge any screenshot at |back| or lower indices, and |forward| or higher
// indices.
while (screenshot_count > kMaxScreenshots && back >= 0) {
- NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
- owner_->GetEntryAtIndex(back));
+ NavigationEntryImpl* entry = owner_->GetEntryAtIndex(back);
if (ClearScreenshot(entry))
--screenshot_count;
--back;
}
while (screenshot_count > kMaxScreenshots && forward < num_entries) {
- NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
- owner_->GetEntryAtIndex(forward));
+ NavigationEntryImpl* entry = owner_->GetEntryAtIndex(forward);
if (ClearScreenshot(entry))
--screenshot_count;
++forward;
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 21c78f18e62..df85f560867 100644
--- a/chromium/content/browser/frame_host/navigation_entry_screenshot_manager.h
+++ b/chromium/content/browser/frame_host/navigation_entry_screenshot_manager.h
@@ -9,6 +9,7 @@
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "content/common/content_export.h"
+#include "content/public/browser/readback_types.h"
class SkBitmap;
@@ -50,8 +51,8 @@ class CONTENT_EXPORT NavigationEntryScreenshotManager {
// The callback invoked when taking the screenshot of the page is complete.
// This sets the screenshot on the navigation entry.
void OnScreenshotTaken(int unique_id,
- bool success,
- const SkBitmap& bitmap);
+ const SkBitmap& bitmap,
+ ReadbackResponse response);
// Returns the number of entries with screenshots.
int GetScreenshotCount() const;
diff --git a/chromium/content/browser/frame_host/navigation_request.cc b/chromium/content/browser/frame_host/navigation_request.cc
index 57f5479727c..cd443ded992 100644
--- a/chromium/content/browser/frame_host/navigation_request.cc
+++ b/chromium/content/browser/frame_host/navigation_request.cc
@@ -4,37 +4,181 @@
#include "content/browser/frame_host/navigation_request.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_request_info.h"
#include "content/browser/frame_host/navigator.h"
#include "content/browser/loader/navigation_url_loader.h"
+#include "content/browser/site_instance_impl.h"
#include "content/common/resource_request_body.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/stream_handle.h"
+#include "content/public/common/content_client.h"
+#include "net/base/load_flags.h"
+#include "net/http/http_request_headers.h"
#include "net/url_request/redirect_info.h"
namespace content {
+namespace {
+
+// 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;
+}
+
+} // namespace
+
+// static
+bool NavigationRequest::ShouldMakeNetworkRequest(const GURL& url) {
+ // Data urls should not make network requests.
+ // TODO(clamy): same document navigations should not make network requests.
+ return !url.SchemeIs(url::kDataScheme);
+}
+
+// static
+scoped_ptr<NavigationRequest> NavigationRequest::CreateBrowserInitiated(
+ FrameTreeNode* frame_tree_node,
+ const NavigationEntryImpl& entry,
+ FrameMsg_Navigate_Type::Value navigation_type,
+ base::TimeTicks navigation_start,
+ NavigationControllerImpl* controller) {
+ std::string method = entry.GetHasPostData() ? "POST" : "GET";
+
+ // Copy existing headers and add necessary headers that may not be present
+ // in the RequestNavigationParams.
+ net::HttpRequestHeaders headers;
+ headers.AddHeadersFromString(entry.extra_headers());
+ headers.SetHeaderIfMissing(net::HttpRequestHeaders::kUserAgent,
+ GetContentClient()->GetUserAgent());
+ // TODO(clamy): match what blink is doing with accept headers.
+ headers.SetHeaderIfMissing("Accept", "*/*");
+
+ // Fill POST data from the browser in the request body.
+ scoped_refptr<ResourceRequestBody> request_body;
+ if (entry.GetHasPostData()) {
+ request_body = new ResourceRequestBody();
+ request_body->AppendBytes(
+ reinterpret_cast<const char *>(
+ entry.GetBrowserInitiatedPostData()->front()),
+ entry.GetBrowserInitiatedPostData()->size());
+ }
+
+ scoped_ptr<NavigationRequest> navigation_request(new NavigationRequest(
+ frame_tree_node, entry.ConstructCommonNavigationParams(navigation_type),
+ BeginNavigationParams(method, headers.ToString(),
+ LoadFlagFromNavigationType(navigation_type), false),
+ entry.ConstructRequestNavigationParams(
+ navigation_start,
+ controller->GetPendingEntryIndex() == -1,
+ controller->GetIndexOfEntry(&entry),
+ controller->GetLastCommittedEntryIndex(),
+ controller->GetEntryCount()),
+ request_body, true, &entry));
+ return navigation_request.Pass();
+}
+
+// static
+scoped_ptr<NavigationRequest> NavigationRequest::CreateRendererInitiated(
+ FrameTreeNode* frame_tree_node,
+ const CommonNavigationParams& common_params,
+ const BeginNavigationParams& begin_params,
+ scoped_refptr<ResourceRequestBody> body,
+ int current_history_list_offset,
+ int current_history_list_length) {
+ // TODO(clamy): Check if some PageState should be provided here.
+ // TODO(clamy): See how we should handle override of the user agent when the
+ // navigation may start in a renderer and commit in another one.
+ // TODO(clamy): See if the navigation start time should be measured in the
+ // renderer and sent to the browser instead of being measured here.
+ // TODO(clamy): The pending history list offset should be properly set.
+ RequestNavigationParams request_params;
+ request_params.current_history_list_offset = current_history_list_offset;
+ request_params.current_history_list_length = current_history_list_length;
+ scoped_ptr<NavigationRequest> navigation_request(
+ new NavigationRequest(frame_tree_node, common_params, begin_params,
+ request_params, body, false, nullptr));
+ return navigation_request.Pass();
+}
+
NavigationRequest::NavigationRequest(
FrameTreeNode* frame_tree_node,
const CommonNavigationParams& common_params,
- const CommitNavigationParams& commit_params)
+ const BeginNavigationParams& begin_params,
+ const RequestNavigationParams& request_params,
+ scoped_refptr<ResourceRequestBody> body,
+ bool browser_initiated,
+ const NavigationEntryImpl* entry)
: frame_tree_node_(frame_tree_node),
common_params_(common_params),
- commit_params_(commit_params) {
+ begin_params_(begin_params),
+ request_params_(request_params),
+ browser_initiated_(browser_initiated),
+ state_(NOT_STARTED),
+ restore_type_(NavigationEntryImpl::RESTORE_NONE),
+ is_view_source_(false),
+ bindings_(NavigationEntryImpl::kInvalidBindings) {
+ if (entry) {
+ source_site_instance_ = entry->source_site_instance();
+ dest_site_instance_ = entry->site_instance();
+ restore_type_ = entry->restore_type();
+ is_view_source_ = entry->IsViewSourceMode();
+ bindings_ = entry->bindings();
+ }
+
+ const GURL& first_party_for_cookies =
+ frame_tree_node->IsMainFrame()
+ ? common_params.url
+ : frame_tree_node->frame_tree()->root()->current_url();
+ bool parent_is_main_frame = !frame_tree_node->parent() ?
+ false : frame_tree_node->parent()->IsMainFrame();
+ info_.reset(new NavigationRequestInfo(
+ common_params, begin_params, first_party_for_cookies,
+ frame_tree_node->IsMainFrame(), parent_is_main_frame, body));
}
NavigationRequest::~NavigationRequest() {
}
-void NavigationRequest::BeginNavigation(
- scoped_ptr<NavigationRequestInfo> info,
- scoped_refptr<ResourceRequestBody> request_body) {
+bool NavigationRequest::BeginNavigation() {
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);
+ DCHECK(state_ == NOT_STARTED || state_ == WAITING_FOR_RENDERER_RESPONSE);
+ state_ = STARTED;
+
+ if (ShouldMakeNetworkRequest(common_params_.url)) {
+ loader_ = NavigationURLLoader::Create(
+ frame_tree_node_->navigator()->GetController()->GetBrowserContext(),
+ frame_tree_node_->frame_tree_node_id(), info_.Pass(), this);
+ return true;
+ }
+
+ // There is no need to make a network request for this navigation, so commit
+ // it immediately.
+ state_ = RESPONSE_STARTED;
+ frame_tree_node_->navigator()->CommitNavigation(
+ frame_tree_node_, nullptr, scoped_ptr<StreamHandle>());
+ return false;
// TODO(davidben): Fire (and add as necessary) observer methods such as
// DidStartProvisionalLoadForFrame for the navigation.
@@ -55,13 +199,23 @@ void NavigationRequest::OnRequestRedirected(
void NavigationRequest::OnResponseStarted(
const scoped_refptr<ResourceResponse>& response,
scoped_ptr<StreamHandle> body) {
+ DCHECK(state_ == STARTED);
+ state_ = RESPONSE_STARTED;
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();
+void NavigationRequest::OnRequestFailed(bool has_stale_copy_in_cache,
+ int net_error) {
+ DCHECK(state_ == STARTED);
+ state_ = FAILED;
+ frame_tree_node_->navigator()->FailedNavigation(
+ frame_tree_node_, has_stale_copy_in_cache, net_error);
+}
+
+void NavigationRequest::OnRequestStarted(base::TimeTicks timestamp) {
+ frame_tree_node_->navigator()->LogResourceRequestTime(timestamp,
+ common_params_.url);
}
} // namespace content
diff --git a/chromium/content/browser/frame_host/navigation_request.h b/chromium/content/browser/frame_host/navigation_request.h
index eb537211374..ce5c5468b10 100644
--- a/chromium/content/browser/frame_host/navigation_request.h
+++ b/chromium/content/browser/frame_host/navigation_request.h
@@ -8,15 +8,19 @@
#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+#include "content/browser/frame_host/navigation_entry_impl.h"
#include "content/browser/loader/navigation_url_loader_delegate.h"
#include "content/common/content_export.h"
+#include "content/common/frame_message_enums.h"
#include "content/common/navigation_params.h"
namespace content {
class FrameTreeNode;
+class NavigationControllerImpl;
class NavigationURLLoader;
class ResourceRequestBody;
+class SiteInstanceImpl;
struct NavigationRequestInfo;
// PlzNavigate
@@ -27,32 +31,111 @@ struct NavigationRequestInfo;
// 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);
+ // Keeps track of the various stages of a NavigationRequest.
+ enum NavigationState {
+ // Initial state.
+ NOT_STARTED = 0,
+
+ // Waiting for a BeginNavigation IPC from the renderer in a
+ // browser-initiated navigation. If there is no live renderer when the
+ // request is created, this stage is skipped.
+ WAITING_FOR_RENDERER_RESPONSE,
+
+ // The request was sent to the IO thread.
+ STARTED,
+
+ // The response started on the IO thread and is ready to be committed. This
+ // is one of the two final states for the request.
+ RESPONSE_STARTED,
+
+ // The request failed on the IO thread and an error page should be
+ // displayed. This is one of the two final states for the request.
+ FAILED,
+ };
+
+ // Helper function to determine if the navigation request to |url| should be
+ // sent to the network stack.
+ static bool ShouldMakeNetworkRequest(const GURL& url);
+
+ // Creates a request for a browser-intiated navigation.
+ static scoped_ptr<NavigationRequest> CreateBrowserInitiated(
+ FrameTreeNode* frame_tree_node,
+ const NavigationEntryImpl& entry,
+ FrameMsg_Navigate_Type::Value navigation_type,
+ base::TimeTicks navigation_start,
+ NavigationControllerImpl* controller);
+
+ // Creates a request for a renderer-intiated navigation.
+ // Note: |body| is sent to the IO thread when calling BeginNavigation, and
+ // should no longer be manipulated afterwards on the UI thread.
+ static scoped_ptr<NavigationRequest> CreateRendererInitiated(
+ FrameTreeNode* frame_tree_node,
+ const CommonNavigationParams& common_params,
+ const BeginNavigationParams& begin_params,
+ scoped_refptr<ResourceRequestBody> body,
+ int current_history_list_offset,
+ int current_history_list_length);
~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);
+ // Called on the UI thread by the Navigator to start the navigation. Returns
+ // whether a request was made on the IO thread.
+ // TODO(clamy): see if ResourceRequestBody could be un-refcounted to avoid
+ // threading subtleties.
+ bool BeginNavigation();
+
+ const CommonNavigationParams& common_params() const { return common_params_; }
- CommonNavigationParams& common_params() { return common_params_; }
+ const BeginNavigationParams& begin_params() const { return begin_params_; }
- const CommitNavigationParams& commit_params() const { return commit_params_; }
+ const RequestNavigationParams& request_params() const {
+ return request_params_;
+ }
NavigationURLLoader* loader_for_testing() const { return loader_.get(); }
+ NavigationState state() const { return state_; }
+
+ SiteInstanceImpl* source_site_instance() const {
+ return source_site_instance_.get();
+ }
+
+ SiteInstanceImpl* dest_site_instance() const {
+ return dest_site_instance_.get();
+ }
+
+ NavigationEntryImpl::RestoreType restore_type() const {
+ return restore_type_;
+ };
+
+ bool is_view_source() const { return is_view_source_; };
+
+ int bindings() const { return bindings_; };
+
+ bool browser_initiated() const { return browser_initiated_ ; }
+
+ void SetWaitingForRendererResponse() {
+ DCHECK(state_ == NOT_STARTED);
+ state_ = WAITING_FOR_RENDERER_RESPONSE;
+ }
+
private:
+ NavigationRequest(FrameTreeNode* frame_tree_node,
+ const CommonNavigationParams& common_params,
+ const BeginNavigationParams& begin_params,
+ const RequestNavigationParams& request_params,
+ scoped_refptr<ResourceRequestBody> body,
+ bool browser_initiated,
+ const NavigationEntryImpl* navitation_entry);
+
// 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;
+ void OnRequestFailed(bool has_stale_copy_in_cache, int net_error) override;
+ void OnRequestStarted(base::TimeTicks timestamp) override;
FrameTreeNode* frame_tree_node_;
@@ -62,10 +145,28 @@ class CONTENT_EXPORT NavigationRequest : public NavigationURLLoaderDelegate {
// will be set to the final navigation url, obtained after following all
// redirects.
CommonNavigationParams common_params_;
- const CommitNavigationParams commit_params_;
+ const BeginNavigationParams begin_params_;
+ const RequestNavigationParams request_params_;
+ const bool browser_initiated_;
+
+ NavigationState state_;
+
+
+ // The parameters to send to the IO thread. |loader_| takes ownership of
+ // |info_| after calling BeginNavigation.
+ scoped_ptr<NavigationRequestInfo> info_;
scoped_ptr<NavigationURLLoader> loader_;
+ // These next items are used in browser-initiated navigations to store
+ // information from the NavigationEntryImpl that is required after request
+ // creation time.
+ scoped_refptr<SiteInstanceImpl> source_site_instance_;
+ scoped_refptr<SiteInstanceImpl> dest_site_instance_;
+ NavigationEntryImpl::RestoreType restore_type_;
+ bool is_view_source_;
+ int bindings_;
+
DISALLOW_COPY_AND_ASSIGN(NavigationRequest);
};
diff --git a/chromium/content/browser/frame_host/navigation_request_info.cc b/chromium/content/browser/frame_host/navigation_request_info.cc
index 91568ad36df..76b98c36d5f 100644
--- a/chromium/content/browser/frame_host/navigation_request_info.cc
+++ b/chromium/content/browser/frame_host/navigation_request_info.cc
@@ -4,15 +4,23 @@
#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) {
+ const CommonNavigationParams& common_params,
+ const BeginNavigationParams& begin_params,
+ const GURL& first_party_for_cookies,
+ bool is_main_frame,
+ bool parent_is_main_frame,
+ scoped_refptr<ResourceRequestBody> request_body)
+ : common_params(common_params),
+ begin_params(begin_params),
+ first_party_for_cookies(first_party_for_cookies),
+ is_main_frame(is_main_frame),
+ parent_is_main_frame(parent_is_main_frame),
+ request_body(request_body) {
}
+NavigationRequestInfo::~NavigationRequestInfo() {}
+
} // namespace content
diff --git a/chromium/content/browser/frame_host/navigation_request_info.h b/chromium/content/browser/frame_host/navigation_request_info.h
index 70bb78729dd..2721c3d73ad 100644
--- a/chromium/content/browser/frame_host/navigation_request_info.h
+++ b/chromium/content/browser/frame_host/navigation_request_info.h
@@ -8,31 +8,39 @@
#include <string>
#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
#include "content/common/content_export.h"
-#include "content/common/frame_messages.h"
+#include "content/common/navigation_params.h"
+#include "content/common/resource_request_body.h"
#include "content/public/common/referrer.h"
#include "url/gurl.h"
namespace content {
+class ResourceRequestBody;
// 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);
+ NavigationRequestInfo(const CommonNavigationParams& common_params,
+ const BeginNavigationParams& params,
+ const GURL& first_party_for_cookies,
+ bool is_main_frame,
+ bool parent_is_main_frame,
+ scoped_refptr<ResourceRequestBody> request_body);
+ ~NavigationRequestInfo();
- const FrameHostMsg_BeginNavigation_Params navigation_params;
-
- // ---------------------------------------------------------------------------
- // The following parameters should be filled in by RenderFrameHostManager
- // before the navigation request is sent to the ResourceDispatcherHost.
+ const CommonNavigationParams common_params;
+ const BeginNavigationParams begin_params;
// 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;
+ const GURL first_party_for_cookies;
+
+ const bool is_main_frame;
+ const bool parent_is_main_frame;
+
+ scoped_refptr<ResourceRequestBody> request_body;
};
} // namespace content
diff --git a/chromium/content/browser/frame_host/navigator.cc b/chromium/content/browser/frame_host/navigator.cc
index 3f5d6cb5f99..1ca9dfc5e39 100644
--- a/chromium/content/browser/frame_host/navigator.cc
+++ b/chromium/content/browser/frame_host/navigator.cc
@@ -5,16 +5,21 @@
#include "content/browser/frame_host/navigator.h"
#include "base/time/time.h"
+#include "content/common/resource_request_body.h"
#include "content/public/browser/stream_handle.h"
namespace content {
+NavigatorDelegate* Navigator::GetDelegate() {
+ return nullptr;
+}
+
NavigationController* Navigator::GetController() {
return NULL;
}
bool Navigator::NavigateToPendingEntry(
- RenderFrameHostImpl* render_frame_host,
+ FrameTreeNode* frame_tree_node,
NavigationController::ReloadType reload_type) {
return false;
}
@@ -23,9 +28,20 @@ base::TimeTicks Navigator::GetCurrentLoadStart() {
return base::TimeTicks::Now();
}
+void Navigator::OnBeginNavigation(
+ FrameTreeNode* frame_tree_node,
+ const CommonNavigationParams& common_params,
+ const BeginNavigationParams& begin_params,
+ scoped_refptr<ResourceRequestBody> body) {
+}
+
void Navigator::CommitNavigation(FrameTreeNode* frame_tree_node,
ResourceResponse* response,
scoped_ptr<StreamHandle> body) {
}
+bool Navigator::IsWaitingForBeforeUnloadACK(FrameTreeNode* frame_tree_node) {
+ return false;
+}
+
} // namespace content
diff --git a/chromium/content/browser/frame_host/navigator.h b/chromium/content/browser/frame_host/navigator.h
index 5063faf20e5..8771dd26496 100644
--- a/chromium/content/browser/frame_host/navigator.h
+++ b/chromium/content/browser/frame_host/navigator.h
@@ -7,6 +7,7 @@
#include "base/memory/ref_counted.h"
#include "base/time/time.h"
+#include "content/browser/frame_host/navigator_delegate.h"
#include "content/common/content_export.h"
#include "content/public/browser/navigation_controller.h"
#include "ui/base/window_open_disposition.h"
@@ -26,9 +27,10 @@ class FrameTreeNode;
class NavigationControllerImpl;
class NavigationEntryImpl;
class NavigationRequest;
-class NavigatorDelegate;
class RenderFrameHostImpl;
+class ResourceRequestBody;
class StreamHandle;
+struct BeginNavigationParams;
struct CommonNavigationParams;
struct ResourceResponse;
@@ -41,6 +43,9 @@ struct ResourceResponse;
// from WebContentsImpl to this interface.
class CONTENT_EXPORT Navigator : public base::RefCounted<Navigator> {
public:
+ // Returns the delegate of this Navigator.
+ virtual NavigatorDelegate* GetDelegate();
+
// Returns the NavigationController associated with this Navigator.
virtual NavigationController* GetController();
@@ -83,10 +88,9 @@ class CONTENT_EXPORT Navigator : public base::RefCounted<Navigator> {
// NavigationController know about each other. This will be possible once
// initialization of Navigator and NavigationController is properly done.
virtual bool NavigateToPendingEntry(
- RenderFrameHostImpl* render_frame_host,
+ FrameTreeNode* frame_tree_node,
NavigationController::ReloadType reload_type);
-
// Navigation requests -------------------------------------------------------
virtual base::TimeTicks GetCurrentLoadStart();
@@ -95,6 +99,7 @@ class CONTENT_EXPORT Navigator : public base::RefCounted<Navigator> {
// specified |disposition|.
virtual void RequestOpenURL(RenderFrameHostImpl* render_frame_host,
const GURL& url,
+ SiteInstance* source_site_instance,
const Referrer& referrer,
WindowOpenDisposition disposition,
bool should_replace_current_entry,
@@ -106,6 +111,7 @@ class CONTENT_EXPORT Navigator : public base::RefCounted<Navigator> {
virtual void RequestTransferURL(
RenderFrameHostImpl* render_frame_host,
const GURL& url,
+ SiteInstance* source_site_instance,
const std::vector<GURL>& redirect_chain,
const Referrer& referrer,
ui::PageTransition page_transition,
@@ -114,15 +120,22 @@ class CONTENT_EXPORT Navigator : public base::RefCounted<Navigator> {
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).
+ // PlzNavigate
+ // Called after receiving a BeforeUnloadACK IPC from the renderer. If
+ // |frame_tree_node| has a NavigationRequest waiting for the renderer
+ // response, then the request is either started or canceled, depending on the
+ // value of |proceed|.
+ virtual void OnBeforeUnloadACK(FrameTreeNode* frame_tree_node,
+ bool proceed) {}
+
+ // PlzNavigate
+ // Used to start a new renderer-initiated navigation, following a
+ // BeginNavigation IPC from the renderer.
virtual void OnBeginNavigation(
FrameTreeNode* frame_tree_node,
- const FrameHostMsg_BeginNavigation_Params& params,
- const CommonNavigationParams& common_params) {}
+ const CommonNavigationParams& common_params,
+ const BeginNavigationParams& begin_params,
+ scoped_refptr<ResourceRequestBody> body);
// PlzNavigate
// Signal |render_frame_host| that a navigation is ready to commit (the
@@ -132,12 +145,25 @@ class CONTENT_EXPORT Navigator : public base::RefCounted<Navigator> {
scoped_ptr<StreamHandle> body);
// PlzNavigate
+ // Called when a NavigationRequest for |frame_tree_node| failed. An
+ // appropriate RenderFrameHost should be selected and asked to show an error
+ // page. |has_stale_copy_in_cache| is true if there is a stale copy of the
+ // unreachable page in cache.
+ virtual void FailedNavigation(FrameTreeNode* frame_tree_node,
+ bool has_stale_copy_in_cache,
+ int error_code) {}
+
+ // 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.
+ // Called when the network stack started handling the navigation request
+ // so that the |timestamp| when it happened can be recorded into an histogram.
+ // The |url| is used to verify we're tracking the correct navigation.
+ // TODO(carlosk): once PlzNavigate is the only navigation implementation
+ // remove the URL parameter and rename this method to better suit its naming
+ // conventions.
virtual void LogResourceRequestTime(
base::TimeTicks timestamp, const GURL& url) {};
@@ -147,6 +173,11 @@ class CONTENT_EXPORT Navigator : public base::RefCounted<Navigator> {
const base::TimeTicks& renderer_before_unload_start_time,
const base::TimeTicks& renderer_before_unload_end_time) {}
+ // PlzNavigate
+ // Returns whether there is an ongoing navigation waiting for the BeforeUnload
+ // event to execute in the renderer process.
+ virtual bool IsWaitingForBeforeUnloadACK(FrameTreeNode* frame_tree_node);
+
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 80ed2135223..75df9c412db 100644
--- a/chromium/content/browser/frame_host/navigator_delegate.h
+++ b/chromium/content/browser/frame_host/navigator_delegate.h
@@ -17,6 +17,7 @@ struct FrameHostMsg_DidFailProvisionalLoadWithError_Params;
namespace content {
+class FrameTreeNode;
class RenderFrameHostImpl;
struct LoadCommittedDetails;
struct OpenURLParams;
@@ -64,6 +65,7 @@ class CONTENT_EXPORT NavigatorDelegate {
// not provided since it may be invalid/changed after being committed. The
// NavigationController's last committed entry is for this navigation.
virtual void DidNavigateMainFramePostCommit(
+ RenderFrameHostImpl* render_frame_host,
const LoadCommittedDetails& details,
const FrameHostMsg_DidCommitProvisionalLoad_Params& params) {}
virtual void DidNavigateAnyFramePostCommit(
@@ -81,12 +83,12 @@ class CONTENT_EXPORT NavigatorDelegate {
// Notifies the Navigator embedder that it is beginning to navigate a frame.
virtual void AboutToNavigateRenderFrame(
- RenderFrameHostImpl* render_frame_host) {}
+ RenderFrameHostImpl* old_host,
+ RenderFrameHostImpl* new_host) {}
- // Notifies the Navigator embedder that a navigation to pending
+ // Notifies the Navigator embedder that a navigation to the pending
// NavigationEntry has started in the browser process.
virtual void DidStartNavigationToPendingEntry(
- RenderFrameHostImpl* render_frame_host,
const GURL& url,
NavigationController::ReloadType reload_type) {}
@@ -98,6 +100,20 @@ class CONTENT_EXPORT NavigatorDelegate {
// Returns whether URLs for aborted browser-initiated navigations should be
// preserved in the omnibox. Defaults to false.
virtual bool ShouldPreserveAbortedURLs();
+
+ // A RenderFrameHost in the specified |frame_tree_node| started loading a new
+ // document. This correponds to Blink's notion of the throbber starting.
+ // |to_different_document| will be true unless the load is a fragment
+ // navigation, or triggered by history.pushState/replaceState.
+ virtual void DidStartLoading(FrameTreeNode* frame_tree_node,
+ bool to_different_document) {}
+
+ // A document stopped loading. This corresponds to Blink's notion of the
+ // throbber stopping.
+ virtual void DidStopLoading() {}
+
+ // The load progress was changed.
+ virtual void DidChangeLoadProgress() {}
};
} // namspace content
diff --git a/chromium/content/browser/frame_host/navigator_impl.cc b/chromium/content/browser/frame_host/navigator_impl.cc
index e3b56215d4d..52ed3c0d4a2 100644
--- a/chromium/content/browser/frame_host/navigator_impl.cc
+++ b/chromium/content/browser/frame_host/navigator_impl.cc
@@ -19,6 +19,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/navigation_params.h"
#include "content/common/view_messages.h"
#include "content/public/browser/browser_context.h"
@@ -37,8 +38,7 @@
#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"
+#include "net/base/net_errors.h"
namespace content {
@@ -70,50 +70,6 @@ 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))
@@ -122,62 +78,6 @@ RenderFrameHostManager* GetRenderManager(RenderFrameHostImpl* rfh) {
return rfh->frame_tree_node()->frame_tree()->root()->render_manager();
}
-void MakeNavigateParams(const NavigationEntryImpl& entry,
- 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();
- 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
- // fully clear the RenderView's view of the session history.
- params->pending_history_list_offset = -1;
- params->current_history_list_offset = -1;
- params->current_history_list_length = 0;
- } else {
- params->pending_history_list_offset = controller->GetIndexOfEntry(&entry);
- params->current_history_list_offset =
- controller->GetLastCommittedEntryIndex();
- params->current_history_list_length = controller->GetEntryCount();
- }
- // Set the redirect chain to the navigation's redirects, unless we are
- // returning to a completed navigation (whose previous redirects don't apply).
- if (ui::PageTransitionIsNewNavigation(params->common_params.transition)) {
- params->redirects = entry.GetRedirectChain();
- } else {
- params->redirects.clear();
- }
-
- params->can_load_local_resources = entry.GetCanLoadLocalResources();
- params->frame_to_navigate = entry.GetFrameToNavigate();
-}
-
} // namespace
struct NavigatorImpl::NavigationMetricsData {
@@ -207,6 +107,10 @@ NavigatorImpl::NavigatorImpl(
NavigatorImpl::~NavigatorImpl() {}
+NavigatorDelegate* NavigatorImpl::GetDelegate() {
+ return delegate_;
+}
+
NavigationController* NavigatorImpl::GetController() {
return controller_;
}
@@ -222,8 +126,7 @@ void NavigatorImpl::DidStartProvisionalLoad(
render_process_host->FilterURL(false, &validated_url);
bool is_main_frame = render_frame_host->frame_tree_node()->IsMainFrame();
- NavigationEntryImpl* pending_entry =
- NavigationEntryImpl::FromNavigationEntry(controller_->GetPendingEntry());
+ NavigationEntryImpl* pending_entry = controller_->GetPendingEntry();
if (is_main_frame) {
// If there is no browser-initiated pending entry for this navigation and it
// is not for the error URL, create a pending entry using the current
@@ -240,9 +143,7 @@ void NavigatorImpl::DidStartProvisionalLoad(
true /* is_renderer_initiated */,
std::string(),
controller_->GetBrowserContext()));
- entry->set_site_instance(
- static_cast<SiteInstanceImpl*>(
- render_frame_host->render_view_host()->GetSiteInstance()));
+ entry->set_site_instance(render_frame_host->GetSiteInstance());
// TODO(creis): If there's a pending entry already, find a safe way to
// update it instead of replacing it and copying over things like this.
if (pending_entry) {
@@ -331,7 +232,7 @@ void NavigatorImpl::DidFailProvisionalLoadWithError(
delegate_->ShouldPreserveAbortedURLs();
if (controller_->GetPendingEntry() != controller_->GetVisibleEntry() ||
!should_preserve_entry) {
- controller_->DiscardPendingEntry();
+ controller_->DiscardPendingEntry(true);
// Also force the UI to refresh.
controller_->delegate()->NotifyNavigationStateChanged(INVALIDATE_TYPE_URL);
@@ -354,7 +255,7 @@ void NavigatorImpl::DidFailLoadWithError(
}
bool NavigatorImpl::NavigateToEntry(
- RenderFrameHostImpl* render_frame_host,
+ FrameTreeNode* frame_tree_node,
const NavigationEntryImpl& entry,
NavigationController::ReloadType reload_type) {
TRACE_EVENT0("browser,navigation", "NavigatorImpl::NavigateToEntry");
@@ -373,18 +274,20 @@ bool NavigatorImpl::NavigateToEntry(
// 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();
+ RenderFrameHostManager* manager = frame_tree_node->render_manager();
// PlzNavigate: the RenderFrameHosts are no longer asked to navigate.
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableBrowserSideNavigation)) {
+ if (base::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);
+ RequestNavigation(frame_tree_node, entry, reload_type, navigation_start);
+
+ // Notify observers about navigation.
+ if (delegate_)
+ delegate_->DidStartNavigationToPendingEntry(entry.GetURL(), reload_type);
+
+ return true;
}
RenderFrameHostImpl* dest_render_frame_host = manager->Navigate(entry);
@@ -400,33 +303,40 @@ bool NavigatorImpl::NavigateToEntry(
dest_render_frame_host, entry.GetURL());
// Notify observers that we will navigate in this RenderFrame.
- if (delegate_)
- delegate_->AboutToNavigateRenderFrame(dest_render_frame_host);
-
- // 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);
+ if (delegate_) {
+ delegate_->AboutToNavigateRenderFrame(frame_tree_node->current_frame_host(),
+ dest_render_frame_host);
+ }
// Navigate in the desired RenderFrameHost.
// We can skip this step in the rare case that this is a transfer navigation
// which began in the chosen RenderFrameHost, since the request has already
// been issued. In that case, simply resume the response.
bool is_transfer_to_same =
- navigate_params.transferred_request_child_id != -1 &&
- navigate_params.transferred_request_child_id ==
+ entry.transferred_global_request_id().child_id != -1 &&
+ entry.transferred_global_request_id().child_id ==
dest_render_frame_host->GetProcess()->GetID();
if (!is_transfer_to_same) {
navigation_data_.reset(new NavigationMetricsData(
navigation_start, entry.GetURL(), entry.restore_type()));
- dest_render_frame_host->Navigate(navigate_params);
+ // Create the navigation parameters.
+ // TODO(vitalybuka): Move this before AboutToNavigateRenderFrame once
+ // http://crbug.com/408684 is fixed.
+ FrameMsg_Navigate_Type::Value navigation_type =
+ GetNavigationType(controller_->GetBrowserContext(), entry, reload_type);
+ dest_render_frame_host->Navigate(
+ entry.ConstructCommonNavigationParams(navigation_type),
+ entry.ConstructStartNavigationParams(),
+ entry.ConstructRequestNavigationParams(
+ navigation_start,
+ controller_->GetPendingEntryIndex() == -1,
+ controller_->GetIndexOfEntry(&entry),
+ controller_->GetLastCommittedEntryIndex(),
+ controller_->GetEntryCount()));
} else {
// No need to navigate again. Just resume the deferred request.
dest_render_frame_host->GetProcess()->ResumeDeferredNavigation(
- GlobalRequestID(navigate_params.transferred_request_child_id,
- navigate_params.transferred_request_request_id));
+ entry.transferred_global_request_id());
}
// Make sure no code called via RFH::Navigate clears the pending entry.
@@ -443,22 +353,17 @@ bool NavigatorImpl::NavigateToEntry(
}
// Notify observers about navigation.
- if (delegate_) {
- delegate_->DidStartNavigationToPendingEntry(dest_render_frame_host,
- entry.GetURL(),
- reload_type);
- }
+ if (delegate_)
+ delegate_->DidStartNavigationToPendingEntry(entry.GetURL(), reload_type);
return true;
}
bool NavigatorImpl::NavigateToPendingEntry(
- RenderFrameHostImpl* render_frame_host,
+ FrameTreeNode* frame_tree_node,
NavigationController::ReloadType reload_type) {
- return NavigateToEntry(
- render_frame_host,
- *NavigationEntryImpl::FromNavigationEntry(controller_->GetPendingEntry()),
- reload_type);
+ return NavigateToEntry(frame_tree_node, *controller_->GetPendingEntry(),
+ reload_type);
}
void NavigatorImpl::DidNavigate(
@@ -467,10 +372,9 @@ void NavigatorImpl::DidNavigate(
// 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());
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation)) {
+ render_frame_host->frame_tree_node()->ResetNavigationRequest(true);
}
FrameHostMsg_DidCommitProvisionalLoad_Params params(input_params);
@@ -478,21 +382,6 @@ void NavigatorImpl::DidNavigate(
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,
- // cross-process subframe navigations happen in a renderer's main frame.
- // Correct the transition type here if we know it is for a subframe.
- NavigationEntryImpl* pending_entry =
- NavigationEntryImpl::FromNavigationEntry(
- controller_->GetPendingEntry());
- if (!render_frame_host->frame_tree_node()->IsMainFrame() &&
- pending_entry &&
- pending_entry->frame_tree_node_id() ==
- render_frame_host->frame_tree_node()->frame_tree_node_id()) {
- params.transition = ui::PAGE_TRANSITION_AUTO_SUBFRAME;
- }
- }
-
if (ui::PageTransitionIsMainFrame(params.transition)) {
if (delegate_) {
// When overscroll navigation gesture is enabled, a screenshot of the page
@@ -517,22 +406,31 @@ void NavigatorImpl::DidNavigate(
}
if (!use_site_per_process)
- frame_tree->root()->render_manager()->DidNavigateFrame(render_frame_host);
+ frame_tree->root()->render_manager()->DidNavigateFrame(
+ render_frame_host, params.gesture == NavigationGestureUser);
}
+ // Save the origin of the new page. Do this before calling
+ // DidNavigateFrame(), because the origin needs to be included in the SwapOut
+ // message, which is sent inside DidNavigateFrame(). SwapOut needs the
+ // origin because it creates a RenderFrameProxy that needs this to initialize
+ // its security context. This origin will also be sent to RenderFrameProxies
+ // created via ViewMsg_New and FrameMsg_NewFrameProxy.
+ render_frame_host->frame_tree_node()->SetCurrentOrigin(params.origin);
+
// When using --site-per-process, we notify the RFHM for all navigations,
// not just main frame navigations.
if (use_site_per_process) {
FrameTreeNode* frame = render_frame_host->frame_tree_node();
- frame->render_manager()->DidNavigateFrame(render_frame_host);
+ frame->render_manager()->DidNavigateFrame(
+ render_frame_host, params.gesture == NavigationGestureUser);
}
// Update the site of the SiteInstance if it doesn't have one yet, unless
// assigning a site is not necessary for this URL. In that case, the
// SiteInstance can still be considered unused until a navigation to a real
// page.
- SiteInstanceImpl* site_instance =
- static_cast<SiteInstanceImpl*>(render_frame_host->GetSiteInstance());
+ SiteInstanceImpl* site_instance = render_frame_host->GetSiteInstance();
if (!site_instance->HasSite() &&
ShouldAssignSiteForURL(params.url)) {
site_instance->SetSite(params.url);
@@ -597,8 +495,10 @@ void NavigatorImpl::DidNavigate(
// Run post-commit tasks.
if (delegate_) {
- if (details.is_main_frame)
- delegate_->DidNavigateMainFramePostCommit(details, params);
+ if (details.is_main_frame) {
+ delegate_->DidNavigateMainFramePostCommit(render_frame_host,
+ details, params);
+ }
delegate_->DidNavigateAnyFramePostCommit(
render_frame_host, details, params);
@@ -616,13 +516,13 @@ bool NavigatorImpl::ShouldAssignSiteForURL(const GURL& url) {
return GetContentClient()->browser()->ShouldAssignSiteForURL(url);
}
-void NavigatorImpl::RequestOpenURL(
- RenderFrameHostImpl* render_frame_host,
- const GURL& url,
- const Referrer& referrer,
- WindowOpenDisposition disposition,
- bool should_replace_current_entry,
- bool user_gesture) {
+void NavigatorImpl::RequestOpenURL(RenderFrameHostImpl* render_frame_host,
+ const GURL& url,
+ SiteInstance* source_site_instance,
+ const Referrer& referrer,
+ WindowOpenDisposition disposition,
+ bool should_replace_current_entry,
+ bool user_gesture) {
SiteInstance* current_site_instance =
GetRenderManager(render_frame_host)->current_frame_host()->
GetSiteInstance();
@@ -640,20 +540,16 @@ 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,
- ui::PAGE_TRANSITION_LINK,
- disposition,
- GlobalRequestID(),
- should_replace_current_entry,
- user_gesture);
+ RequestTransferURL(render_frame_host, url, source_site_instance,
+ redirect_chain, referrer, ui::PAGE_TRANSITION_LINK,
+ disposition, GlobalRequestID(),
+ should_replace_current_entry, user_gesture);
}
void NavigatorImpl::RequestTransferURL(
RenderFrameHostImpl* render_frame_host,
const GURL& url,
+ SiteInstance* source_site_instance,
const std::vector<GURL>& redirect_chain,
const Referrer& referrer,
ui::PageTransition page_transition,
@@ -670,15 +566,23 @@ void NavigatorImpl::RequestTransferURL(
dest_url = GURL(url::kAboutBlankURL);
}
- int64 frame_tree_node_id = -1;
+ int frame_tree_node_id = -1;
+
+ // Send the navigation to the current FrameTreeNode if it's destined for a
+ // subframe in the current tab. We'll assume it's for the main frame
+ // (possibly of a new or different WebContents) otherwise.
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kSitePerProcess)) {
+ switches::kSitePerProcess) &&
+ disposition == CURRENT_TAB &&
+ render_frame_host->GetParent()) {
frame_tree_node_id =
render_frame_host->frame_tree_node()->frame_tree_node_id();
}
+
OpenURLParams params(
dest_url, referrer, frame_tree_node_id, disposition, page_transition,
true /* is_renderer_initiated */);
+ params.source_site_instance = source_site_instance;
if (redirect_chain.size() > 0)
params.redirect_chain = redirect_chain;
params.transferred_global_request_id = transferred_global_request_id;
@@ -711,77 +615,158 @@ void NavigatorImpl::RequestTransferURL(
}
// PlzNavigate
+void NavigatorImpl::OnBeforeUnloadACK(FrameTreeNode* frame_tree_node,
+ bool proceed) {
+ CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation));
+ DCHECK(frame_tree_node);
+
+ NavigationRequest* navigation_request = frame_tree_node->navigation_request();
+
+ // The NavigationRequest may have been canceled while the renderer was
+ // executing the BeforeUnload event.
+ if (!navigation_request)
+ return;
+
+ DCHECK_EQ(NavigationRequest::WAITING_FOR_RENDERER_RESPONSE,
+ navigation_request->state());
+
+ if (proceed)
+ BeginNavigation(frame_tree_node);
+ else
+ CancelNavigation(frame_tree_node);
+}
+
+// PlzNavigate
void NavigatorImpl::OnBeginNavigation(
FrameTreeNode* frame_tree_node,
- const FrameHostMsg_BeginNavigation_Params& params,
- const CommonNavigationParams& common_params) {
- CHECK(CommandLine::ForCurrentProcess()->HasSwitch(
+ const CommonNavigationParams& common_params,
+ const BeginNavigationParams& begin_params,
+ scoped_refptr<ResourceRequestBody> body) {
+ // This is a renderer-initiated navigation.
+ CHECK(base::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;
+ NavigationRequest* ongoing_navigation_request =
+ frame_tree_node->navigation_request();
- scoped_ptr<NavigationRequestInfo> info(new NavigationRequestInfo(params));
+ // The renderer-initiated navigation request is ignored iff a) there is an
+ // ongoing request b) which is browser or user-initiated and c) the renderer
+ // request is not user-initiated.
+ if (ongoing_navigation_request &&
+ (ongoing_navigation_request->browser_initiated() ||
+ ongoing_navigation_request->begin_params().has_user_gesture) &&
+ !begin_params.has_user_gesture) {
+ return;
+ }
- 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();
+ // In all other cases the current navigation, if any, is canceled and a new
+ // NavigationRequest is created for the node.
+ scoped_ptr<NavigationRequest> navigation_request =
+ NavigationRequest::CreateRendererInitiated(
+ frame_tree_node, common_params, begin_params, body,
+ controller_->GetLastCommittedEntryIndex(),
+ controller_->GetEntryCount());
+ frame_tree_node->SetNavigationRequest(navigation_request.Pass());
- // TODO(clamy): Inform the RenderFrameHostManager that a navigation is about
- // to begin, so that it can speculatively spawn a new renderer if needed.
+ if (frame_tree_node->IsMainFrame())
+ navigation_data_.reset();
- navigation_request->BeginNavigation(info.Pass(), params.request_body);
+ BeginNavigation(frame_tree_node);
}
// PlzNavigate
void NavigatorImpl::CommitNavigation(FrameTreeNode* frame_tree_node,
ResourceResponse* response,
scoped_ptr<StreamHandle> body) {
- CHECK(CommandLine::ForCurrentProcess()->HasSwitch(
+ CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableBrowserSideNavigation));
+ NavigationRequest* navigation_request = frame_tree_node->navigation_request();
+ DCHECK(navigation_request);
+ DCHECK(response ||
+ !NavigationRequest::ShouldMakeNetworkRequest(
+ navigation_request->common_params().url));
+
// HTTP 204 (No Content) and HTTP 205 (Reset Content) responses should not
// commit; they leave the frame showing the previous page.
- if (response->head.headers.get() &&
+ if (response && 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);
+ *navigation_request);
+
+ // The renderer can exit view source mode when any error or cancellation
+ // happen. When reusing the same renderer, overwrite to recover the mode.
+ if (navigation_request->is_view_source() &&
+ render_frame_host ==
+ frame_tree_node->render_manager()->current_frame_host()) {
+ DCHECK(!render_frame_host->GetParent());
+ render_frame_host->render_view_host()->Send(
+ new ViewMsg_EnableViewSourceMode(
+ render_frame_host->render_view_host()->GetRoutingID()));
+ }
+
CheckWebUIRendererDoesNotDisplayNormalURL(
render_frame_host, navigation_request->common_params().url);
render_frame_host->CommitNavigation(response, body.Pass(),
navigation_request->common_params(),
- navigation_request->commit_params());
+ navigation_request->request_params());
+}
+
+// PlzNavigate
+void NavigatorImpl::FailedNavigation(FrameTreeNode* frame_tree_node,
+ bool has_stale_copy_in_cache,
+ int error_code) {
+ CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation));
+
+ NavigationRequest* navigation_request = frame_tree_node->navigation_request();
+ DCHECK(navigation_request);
+
+ // If the request was canceled by the user do not show an error page.
+ if (error_code == net::ERR_ABORTED) {
+ frame_tree_node->ResetNavigationRequest(false);
+ return;
+ }
+
+ // Select an appropriate renderer to show the error page.
+ RenderFrameHostImpl* render_frame_host =
+ frame_tree_node->render_manager()->GetFrameHostForNavigation(
+ *navigation_request);
+ CheckWebUIRendererDoesNotDisplayNormalURL(
+ render_frame_host, navigation_request->common_params().url);
+
+ render_frame_host->FailedNavigation(navigation_request->common_params(),
+ navigation_request->request_params(),
+ has_stale_copy_in_cache, error_code);
}
// PlzNavigate
void NavigatorImpl::CancelNavigation(FrameTreeNode* frame_tree_node) {
- CHECK(CommandLine::ForCurrentProcess()->HasSwitch(
+ CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableBrowserSideNavigation));
- navigation_request_map_.erase(frame_tree_node->frame_tree_node_id());
+ frame_tree_node->ResetNavigationRequest(false);
+ if (frame_tree_node->IsMainFrame())
+ navigation_data_.reset();
+}
+
+bool NavigatorImpl::IsWaitingForBeforeUnloadACK(
+ FrameTreeNode* frame_tree_node) {
+ CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation));
+ NavigationRequest* request = frame_tree_node->navigation_request();
+ if (!request)
+ return false;
+ return request->state() == NavigationRequest::WAITING_FOR_RENDERER_RESPONSE;
}
void NavigatorImpl::LogResourceRequestTime(
@@ -823,50 +808,44 @@ void NavigatorImpl::CheckWebUIRendererDoesNotDisplayNormalURL(
}
// PlzNavigate
-bool NavigatorImpl::RequestNavigation(
+void NavigatorImpl::RequestNavigation(
FrameTreeNode* frame_tree_node,
const NavigationEntryImpl& entry,
NavigationController::ReloadType reload_type,
base::TimeTicks navigation_start) {
- CHECK(CommandLine::ForCurrentProcess()->HasSwitch(
+ CHECK(base::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;
- }
+ scoped_ptr<NavigationRequest> navigation_request =
+ NavigationRequest::CreateBrowserInitiated(frame_tree_node, entry,
+ navigation_type,
+ navigation_start, controller_);
+ frame_tree_node->SetNavigationRequest(navigation_request.Pass());
+
+ // Have the current renderer execute its beforeUnload event if needed. If it
+ // is not needed (eg. the renderer is not live), BeginNavigation should get
+ // called.
+ frame_tree_node->navigation_request()->SetWaitingForRendererResponse();
+ frame_tree_node->current_frame_host()->DispatchBeforeUnload(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::BeginNavigation(FrameTreeNode* frame_tree_node) {
+ NavigationRequest* navigation_request = frame_tree_node->navigation_request();
+
+ // A browser-initiated navigation could have been cancelled while it was
+ // waiting for the BeforeUnload event to execute.
+ if (!navigation_request)
+ return;
+
+ // Start the request.
+ if (navigation_request->BeginNavigation()) {
+ // If the request was sent to the IO thread, notify the
+ // RenderFrameHostManager so it can speculatively create a RenderFrameHost
+ // (and potentially a new renderer process) in parallel.
+ frame_tree_node->render_manager()->BeginNavigation(*navigation_request);
+ }
}
void NavigatorImpl::RecordNavigationMetrics(
@@ -879,6 +858,7 @@ void NavigatorImpl::RecordNavigationMetrics(
RecordAction(base::UserMetricsAction("FrameLoad"));
if (!details.is_main_frame || !navigation_data_ ||
+ navigation_data_->url_job_start_time_.is_null() ||
navigation_data_->url_ != params.original_request_url) {
return;
}
diff --git a/chromium/content/browser/frame_host/navigator_impl.h b/chromium/content/browser/frame_host/navigator_impl.h
index e142b3fd1ff..7dd2a0284fb 100644
--- a/chromium/content/browser/frame_host/navigator_impl.h
+++ b/chromium/content/browser/frame_host/navigator_impl.h
@@ -9,14 +9,12 @@
#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 {
@@ -36,6 +34,7 @@ class CONTENT_EXPORT NavigatorImpl : public Navigator {
NavigatorDelegate* delegate);
// Navigator implementation.
+ NavigatorDelegate* GetDelegate() override;
NavigationController* GetController() override;
void DidStartProvisionalLoad(RenderFrameHostImpl* render_frame_host,
const GURL& url,
@@ -52,16 +51,18 @@ class CONTENT_EXPORT NavigatorImpl : public Navigator {
const FrameHostMsg_DidCommitProvisionalLoad_Params&
input_params) override;
bool NavigateToPendingEntry(
- RenderFrameHostImpl* render_frame_host,
+ FrameTreeNode* frame_tree_node,
NavigationController::ReloadType reload_type) override;
void RequestOpenURL(RenderFrameHostImpl* render_frame_host,
const GURL& url,
+ SiteInstance* source_site_instance,
const Referrer& referrer,
WindowOpenDisposition disposition,
bool should_replace_current_entry,
bool user_gesture) override;
void RequestTransferURL(RenderFrameHostImpl* render_frame_host,
const GURL& url,
+ SiteInstance* source_site_instance,
const std::vector<GURL>& redirect_chain,
const Referrer& referrer,
ui::PageTransition page_transition,
@@ -69,30 +70,36 @@ class CONTENT_EXPORT NavigatorImpl : public Navigator {
const GlobalRequestID& transferred_global_request_id,
bool should_replace_current_entry,
bool user_gesture) override;
+ void OnBeforeUnloadACK(FrameTreeNode* frame_tree_node, bool proceed) override;
void OnBeginNavigation(FrameTreeNode* frame_tree_node,
- const FrameHostMsg_BeginNavigation_Params& params,
- const CommonNavigationParams& common_params) override;
+ const CommonNavigationParams& common_params,
+ const BeginNavigationParams& begin_params,
+ scoped_refptr<ResourceRequestBody> body) override;
void CommitNavigation(FrameTreeNode* frame_tree_node,
ResourceResponse* response,
scoped_ptr<StreamHandle> body) override;
+ void FailedNavigation(FrameTreeNode* frame_tree_node,
+ bool has_stale_copy_in_cache,
+ int error_code) override;
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;
+ bool IsWaitingForBeforeUnloadACK(FrameTreeNode* frame_tree_node) override;
private:
// Holds data used to track browser side navigation metrics.
struct NavigationMetricsData;
- friend class NavigatorTest;
+ friend class NavigatorTestWithBrowserSideNavigation;
~NavigatorImpl() override;
// Navigates to the given entry, which must be the pending entry. Private
// because all callers should use NavigateToPendingEntry.
bool NavigateToEntry(
- RenderFrameHostImpl* render_frame_host,
+ FrameTreeNode* frame_tree_node,
const NavigationEntryImpl& entry,
NavigationController::ReloadType reload_type);
@@ -102,14 +109,18 @@ class CONTENT_EXPORT NavigatorImpl : public Navigator {
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,
+ // PlzNavigate: if needed, sends a BeforeUnload IPC to the renderer to ask it
+ // to execute the beforeUnload event. Otherwise, the navigation request will
+ // be started.
+ void RequestNavigation(FrameTreeNode* frame_tree_node,
const NavigationEntryImpl& entry,
NavigationController::ReloadType reload_type,
base::TimeTicks navigation_start);
+ // PlzNavigate: sends the NavigationRequest for |frame_tree_node| to the
+ // network stack so that it can start.
+ void BeginNavigation(FrameTreeNode* frame_tree_node);
+
void RecordNavigationMetrics(
const LoadCommittedDetails& details,
const FrameHostMsg_DidCommitProvisionalLoad_Params& params,
@@ -127,11 +138,6 @@ class CONTENT_EXPORT NavigatorImpl : public Navigator {
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
index 37a0f243d6d..8dc64af604f 100644
--- a/chromium/content/browser/frame_host/navigator_impl_unittest.cc
+++ b/chromium/content/browser/frame_host/navigator_impl_unittest.cc
@@ -3,10 +3,7 @@
// 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"
@@ -15,17 +12,17 @@
#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/frame_messages.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/public/test/mock_render_process_host.h"
+#include "content/test/browser_side_navigation_test_utils.h"
+#include "content/test/test_navigation_url_loader.h"
#include "content/test/test_render_frame_host.h"
#include "content/test/test_web_contents.h"
#include "net/base/load_flags.h"
@@ -36,236 +33,339 @@
namespace content {
-namespace {
-
-class TestNavigationURLLoader
- : public NavigationURLLoader,
- public base::SupportsWeakPtr<TestNavigationURLLoader> {
+class NavigatorTestWithBrowserSideNavigation
+ : public RenderViewHostImplTestHarness {
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) {
- }
+ // Re-defines the private RenderFrameHostManager::SiteInstanceDescriptor here
+ // to allow access to it from tests.
+ typedef RenderFrameHostManager::SiteInstanceDescriptor SiteInstanceDescriptor;
- // NavigationURLLoader implementation.
- void FollowRedirect() override { redirect_count_++; }
+ void SetUp() override {
+ EnableBrowserSideNavigation();
+ RenderViewHostImplTestHarness::SetUp();
+ }
- const CommonNavigationParams& common_params() const { return common_params_; }
- NavigationRequestInfo* request_info() const { return request_info_.get(); }
+ TestNavigationURLLoader* GetLoaderForNavigationRequest(
+ NavigationRequest* request) const {
+ return static_cast<TestNavigationURLLoader*>(request->loader_for_testing());
+ }
- void CallOnRequestRedirected(
- const net::RedirectInfo& redirect_info,
- const scoped_refptr<ResourceResponse>& response) {
- delegate_->OnRequestRedirected(redirect_info, response);
+ // Requests a navigation of the specified FrameTreeNode to the specified URL;
+ // returns the unique ID of the pending NavigationEntry.
+ int RequestNavigation(FrameTreeNode* node, const GURL& url) {
+ return RequestNavigationWithParameters(node, url, Referrer(),
+ ui::PAGE_TRANSITION_LINK);
}
- void CallOnResponseStarted(
- const scoped_refptr<ResourceResponse>& response,
- scoped_ptr<StreamHandle> body) {
- delegate_->OnResponseStarted(response, body.Pass());
+ // Requests a navigation of the specified FrameTreeNode to the specified URL,
+ // using other specified parameters; returns the unique ID of the pending
+ // NavigationEntry.
+ int RequestNavigationWithParameters(
+ FrameTreeNode* node,
+ const GURL& url,
+ const Referrer& referrer,
+ ui::PageTransition transition_type) {
+ NavigationController::LoadURLParams load_params(url);
+ load_params.frame_tree_node_id = node->frame_tree_node_id();
+ load_params.referrer = referrer;
+ load_params.transition_type = transition_type;
+
+ controller().LoadURLWithParams(load_params);
+ return controller().GetPendingEntry()->GetUniqueID();
}
- int redirect_count() { return redirect_count_; }
+ TestRenderFrameHost* GetSpeculativeRenderFrameHost(FrameTreeNode* node) {
+ return static_cast<TestRenderFrameHost*>(
+ node->render_manager()->speculative_render_frame_host_.get());
+ }
- private:
- CommonNavigationParams common_params_;
- scoped_ptr<NavigationRequestInfo> request_info_;
- NavigationURLLoaderDelegate* delegate_;
- int redirect_count_;
-};
+ // Checks if this RenderFrameHost sent a single FrameMsg_CommitNavigation
+ // since the last clearing of the sink.
+ // Note: caller must invoke ClearMessages on the sink at some point before
+ // the tracked commit happens to clear up commit messages from previous
+ // navigations.
+ bool DidRenderFrameHostRequestCommit(TestRenderFrameHost* rfh) {
+ const FrameMsg_CommitNavigation* commit_message =
+ static_cast<const FrameMsg_CommitNavigation*>(
+ rfh->GetProcess()->sink().GetUniqueMessageMatching(
+ FrameMsg_CommitNavigation::ID));
+ return commit_message &&
+ rfh->GetRoutingID() == commit_message->routing_id();
+ }
-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));
+ SiteInstance* ConvertToSiteInstance(RenderFrameHostManager* rfhm,
+ const SiteInstanceDescriptor& descriptor,
+ SiteInstance* candidate_instance) {
+ return rfhm->ConvertToSiteInstance(descriptor, candidate_instance);
}
};
-} // namespace
+// PlzNavigate: Test a complete browser-initiated navigation starting with a
+// non-live renderer.
+TEST_F(NavigatorTestWithBrowserSideNavigation,
+ SimpleBrowserInitiatedNavigationFromNonLiveRenderer) {
+ const GURL kUrl("http://chromium.org/");
-class NavigatorTest : public RenderViewHostImplTestHarness {
- public:
- NavigatorTest() : stream_registry_(new StreamRegistry) {}
+ EXPECT_FALSE(main_test_rfh()->IsRenderFrameLive());
- void SetUp() override {
- RenderViewHostImplTestHarness::SetUp();
- loader_factory_.reset(new TestNavigationURLLoaderFactory);
- NavigationURLLoader::SetFactoryForTesting(loader_factory_.get());
- }
+ // Start a browser-initiated navigation.
+ int32 site_instance_id = main_test_rfh()->GetSiteInstance()->GetId();
+ FrameTreeNode* node = main_test_rfh()->frame_tree_node();
+ int entry_id = RequestNavigation(node, kUrl);
+ NavigationRequest* request = node->navigation_request();
+ ASSERT_TRUE(request);
+ EXPECT_EQ(kUrl, request->common_params().url);
+ EXPECT_TRUE(request->browser_initiated());
+
+ // As there's no live renderer the navigation should not wait for a
+ // beforeUnload ACK from the renderer and start right away.
+ EXPECT_EQ(NavigationRequest::STARTED, request->state());
+ ASSERT_TRUE(GetLoaderForNavigationRequest(request));
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
+ EXPECT_FALSE(node->render_manager()->pending_frame_host());
- void TearDown() override {
- NavigationURLLoader::SetFactoryForTesting(nullptr);
- loader_factory_.reset();
- RenderViewHostImplTestHarness::TearDown();
- }
+ // Have the current RenderFrameHost commit the navigation.
+ scoped_refptr<ResourceResponse> response(new ResourceResponse);
+ GetLoaderForNavigationRequest(request)
+ ->CallOnResponseStarted(response, MakeEmptyStream());
+ EXPECT_TRUE(DidRenderFrameHostRequestCommit(main_test_rfh()));
+ EXPECT_EQ(NavigationRequest::RESPONSE_STARTED, request->state());
+
+ // Commit the navigation.
+ main_test_rfh()->SendNavigate(0, entry_id, true, kUrl);
+ EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, main_test_rfh()->rfh_state());
+ EXPECT_EQ(SiteInstanceImpl::GetSiteForURL(browser_context(), kUrl),
+ main_test_rfh()->GetSiteInstance()->GetSiteURL());
+ EXPECT_EQ(kUrl, contents()->GetLastCommittedURL());
+ EXPECT_FALSE(node->navigation_request());
+ EXPECT_FALSE(node->render_manager()->pending_frame_host());
- 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());
- }
+ // The main RenderFrameHost should not have been changed, and the renderer
+ // should have been initialized.
+ EXPECT_EQ(site_instance_id, main_test_rfh()->GetSiteInstance()->GetId());
+ EXPECT_TRUE(main_test_rfh()->IsRenderFrameLive());
- TestNavigationURLLoader* GetLoaderForNavigationRequest(
- NavigationRequest* request) const {
- return static_cast<TestNavigationURLLoader*>(request->loader_for_testing());
- }
+ // After a navigation is finished no speculative RenderFrameHost should
+ // exist.
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
- void EnableBrowserSideNavigation() {
- CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kEnableBrowserSideNavigation);
- }
+ // With PlzNavigate enabled a pending RenderFrameHost should never exist.
+ EXPECT_FALSE(node->render_manager()->pending_frame_host());
+}
- void SendRequestNavigation(FrameTreeNode* node,
- const GURL& url) {
- SendRequestNavigationWithParameters(
- node, url, Referrer(), ui::PAGE_TRANSITION_LINK,
- NavigationController::NO_RELOAD);
- }
+// PlzNavigate: Test a complete renderer-initiated same-site navigation.
+TEST_F(NavigatorTestWithBrowserSideNavigation,
+ SimpleRendererInitiatedSameSiteNavigation) {
+ const GURL kUrl1("http://www.chromium.org/");
+ const GURL kUrl2("http://www.chromium.org/Home");
- 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());
- }
+ contents()->NavigateAndCommit(kUrl1);
+ EXPECT_TRUE(main_test_rfh()->IsRenderFrameLive());
- 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();
- }
+ // Start a renderer-initiated non-user-initiated navigation.
+ process()->sink().ClearMessages();
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl2, false);
+ FrameTreeNode* node = main_test_rfh()->frame_tree_node();
+ NavigationRequest* request = node->navigation_request();
+ ASSERT_TRUE(request);
+
+ // The navigation is immediately started as there's no need to wait for
+ // beforeUnload to be executed.
+ EXPECT_EQ(NavigationRequest::STARTED, request->state());
+ EXPECT_FALSE(request->begin_params().has_user_gesture);
+ EXPECT_EQ(kUrl2, request->common_params().url);
+ EXPECT_FALSE(request->browser_initiated());
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
+
+ // Have the current RenderFrameHost commit the navigation.
+ scoped_refptr<ResourceResponse> response(new ResourceResponse);
+ GetLoaderForNavigationRequest(request)
+ ->CallOnResponseStarted(response, MakeEmptyStream());
+ EXPECT_TRUE(DidRenderFrameHostRequestCommit(main_test_rfh()));
+ EXPECT_EQ(NavigationRequest::RESPONSE_STARTED, request->state());
+
+ // Commit the navigation.
+ main_test_rfh()->SendNavigate(1, 0, true, kUrl2);
+ EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, main_test_rfh()->rfh_state());
+ EXPECT_EQ(SiteInstanceImpl::GetSiteForURL(browser_context(), kUrl2),
+ main_test_rfh()->GetSiteInstance()->GetSiteURL());
+ EXPECT_EQ(kUrl2, contents()->GetLastCommittedURL());
+ EXPECT_FALSE(node->navigation_request());
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
+ EXPECT_FALSE(node->render_manager()->pending_frame_host());
+}
- private:
- scoped_ptr<StreamRegistry> stream_registry_;
- scoped_ptr<TestNavigationURLLoaderFactory> loader_factory_;
-};
+// PlzNavigate: Test a complete renderer-initiated navigation that should be
+// cross-site but does not result in a SiteInstance swap because its
+// renderer-initiated.
+TEST_F(NavigatorTestWithBrowserSideNavigation,
+ SimpleRendererInitiatedCrossSiteNavigation) {
+ const GURL kUrl1("http://www.chromium.org/");
+ const GURL kUrl2("http://www.google.com");
+
+ contents()->NavigateAndCommit(kUrl1);
+ EXPECT_TRUE(main_test_rfh()->IsRenderFrameLive());
+ int32 site_instance_id_1 = main_test_rfh()->GetSiteInstance()->GetId();
+
+ // Start a renderer-initiated non-user-initiated navigation.
+ process()->sink().ClearMessages();
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl2, false);
+ FrameTreeNode* node = main_test_rfh()->frame_tree_node();
+ NavigationRequest* request = node->navigation_request();
+ ASSERT_TRUE(request);
+
+ // The navigation is immediately started as there's no need to wait for
+ // beforeUnload to be executed.
+ EXPECT_EQ(NavigationRequest::STARTED, request->state());
+ EXPECT_FALSE(request->begin_params().has_user_gesture);
+ EXPECT_EQ(kUrl2, request->common_params().url);
+ EXPECT_FALSE(request->browser_initiated());
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
+
+ // Have the current RenderFrameHost commit the navigation.
+ scoped_refptr<ResourceResponse> response(new ResourceResponse);
+ GetLoaderForNavigationRequest(request)
+ ->CallOnResponseStarted(response, MakeEmptyStream());
+ EXPECT_TRUE(DidRenderFrameHostRequestCommit(main_test_rfh()));
+ EXPECT_EQ(NavigationRequest::RESPONSE_STARTED, request->state());
+
+ // Commit the navigation.
+ main_test_rfh()->SendNavigate(1, 0, true, kUrl2);
+ EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, main_test_rfh()->rfh_state());
+ EXPECT_EQ(kUrl2, contents()->GetLastCommittedURL());
+ EXPECT_FALSE(node->navigation_request());
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
+ EXPECT_FALSE(node->render_manager()->pending_frame_host());
+
+ // The SiteInstance did not change.
+ EXPECT_EQ(site_instance_id_1, main_test_rfh()->GetSiteInstance()->GetId());
+}
+
+// PlzNavigate: Test that a beforeUnload denial cancels the navigation.
+TEST_F(NavigatorTestWithBrowserSideNavigation,
+ BeforeUnloadDenialCancelNavigation) {
+ const GURL kUrl1("http://www.google.com/");
+ const GURL kUrl2("http://www.chromium.org/");
+
+ contents()->NavigateAndCommit(kUrl1);
+
+ // Start a new navigation.
+ FrameTreeNode* node = main_test_rfh()->frame_tree_node();
+ RequestNavigation(node, kUrl2);
+ NavigationRequest* request = node->navigation_request();
+ ASSERT_TRUE(request);
+ EXPECT_TRUE(request->browser_initiated());
+ EXPECT_EQ(NavigationRequest::WAITING_FOR_RENDERER_RESPONSE, request->state());
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
+
+ // Simulate a beforeUnload denial.
+ main_test_rfh()->SendBeforeUnloadACK(false);
+ EXPECT_FALSE(node->navigation_request());
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
+}
// 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) {
+// RequestNavigation.
+TEST_F(NavigatorTestWithBrowserSideNavigation, BeginNavigation) {
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* root_node = contents()->GetFrameTree()->root();
+ TestRenderFrameHost* subframe_rfh = main_test_rfh()->AppendChild("Child");
+ ASSERT_TRUE(subframe_rfh);
+ // Start a navigation at the subframe.
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);
+ RequestNavigation(subframe_node, kUrl2);
+ NavigationRequest* subframe_request = subframe_node->navigation_request();
TestNavigationURLLoader* subframe_loader =
GetLoaderForNavigationRequest(subframe_request);
+
+ // Subframe navigations should start right away as they don't have to request
+ // beforeUnload to run at the renderer.
ASSERT_TRUE(subframe_request);
+ ASSERT_TRUE(subframe_loader);
+ EXPECT_EQ(NavigationRequest::STARTED, subframe_request->state());
EXPECT_EQ(kUrl2, subframe_request->common_params().url);
- EXPECT_EQ(kUrl2, subframe_loader->common_params().url);
+ EXPECT_EQ(kUrl2, subframe_loader->request_info()->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);
+ EXPECT_TRUE(subframe_request->browser_initiated());
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(root_node));
+
+ // Subframe navigations should never create a speculative RenderFrameHost,
+ // unless site-per-process is enabled. In that case, as the subframe
+ // navigation is to a different site and is still ongoing, it should have one.
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess)) {
+ EXPECT_TRUE(GetSpeculativeRenderFrameHost(subframe_node));
+ } else {
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(subframe_node));
+ }
+
+ // Now start a navigation at the root node.
+ RequestNavigation(root_node, kUrl3);
+ NavigationRequest* main_request = root_node->navigation_request();
+ ASSERT_TRUE(main_request);
+ EXPECT_EQ(NavigationRequest::WAITING_FOR_RENDERER_RESPONSE,
+ main_request->state());
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(root_node));
- SendRequestNavigation(root, kUrl3);
- // Simulate a BeginNavigation IPC on the main frame.
- contents()->GetMainFrame()->SendBeginNavigationWithURL(kUrl3);
- NavigationRequest* main_request = GetNavigationRequestForFrameTreeNode(root);
+ // Simulate a BeforeUnloadACK IPC on the main frame.
+ main_test_rfh()->SendBeforeUnloadACK(true);
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()->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);
+ EXPECT_TRUE(main_request->browser_initiated());
+ // BeforeUnloadACK was received from the renderer so the navigation should
+ // have started.
+ EXPECT_EQ(NavigationRequest::STARTED, main_request->state());
+
+ // Main frame navigation to a different site should use a speculative
+ // RenderFrameHost.
+ EXPECT_TRUE(GetSpeculativeRenderFrameHost(root_node));
+
+ // As the main frame hasn't yet committed the subframe still exists. Thus, the
+ // above situation regarding subframe navigations is valid here.
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess)) {
+ EXPECT_TRUE(GetSpeculativeRenderFrameHost(subframe_node));
+ } else {
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(subframe_node));
+ }
}
-// 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) {
+// PlzNavigate: Test that committing an HTTP 204 or HTTP 205 response cancels
+// the navigation.
+TEST_F(NavigatorTestWithBrowserSideNavigation, NoContent) {
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);
+ process()->sink().ClearMessages();
+ RequestNavigation(node, kUrl2);
+ main_test_rfh()->SendBeforeUnloadACK(true);
+
+ NavigationRequest* main_request = node->navigation_request();
ASSERT_TRUE(main_request);
+ // Navigations to a different site do create a speculative RenderFrameHost.
+ EXPECT_TRUE(GetSpeculativeRenderFrameHost(node));
+
// Commit an HTTP 204 response.
scoped_refptr<ResourceResponse> response(new ResourceResponse);
const char kNoContentHeaders[] = "HTTP/1.1 204 No Content\0\0";
@@ -274,17 +374,23 @@ TEST_F(NavigatorTest, BrowserSideNavigationNoContent) {
GetLoaderForNavigationRequest(main_request)->CallOnResponseStarted(
response, MakeEmptyStream());
- // There should be no pending RenderFrameHost; the navigation was aborted.
- EXPECT_FALSE(GetNavigationRequestForFrameTreeNode(node));
+ // There should be no pending nor speculative RenderFrameHost; the navigation
+ // was aborted.
+ EXPECT_FALSE(DidRenderFrameHostRequestCommit(main_test_rfh()));
+ EXPECT_FALSE(node->navigation_request());
EXPECT_FALSE(node->render_manager()->pending_frame_host());
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
// 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);
+ process()->sink().ClearMessages();
+ RequestNavigation(node, kUrl2);
+ main_test_rfh()->SendBeforeUnloadACK(true);
+
+ main_request = node->navigation_request();
ASSERT_TRUE(main_request);
+ EXPECT_TRUE(GetSpeculativeRenderFrameHost(node));
// Commit an HTTP 205 response.
response = new ResourceResponse;
@@ -294,187 +400,736 @@ TEST_F(NavigatorTest, BrowserSideNavigationNoContent) {
GetLoaderForNavigationRequest(main_request)->CallOnResponseStarted(
response, MakeEmptyStream());
- // There should be no pending RenderFrameHost; the navigation was aborted.
- EXPECT_FALSE(GetNavigationRequestForFrameTreeNode(node));
+ // There should be no pending nor speculative RenderFrameHost; the navigation
+ // was aborted.
+ EXPECT_FALSE(DidRenderFrameHostRequestCommit(main_test_rfh()));
+ EXPECT_FALSE(node->navigation_request());
EXPECT_FALSE(node->render_manager()->pending_frame_host());
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
}
// PlzNavigate: Test that a new RenderFrameHost is created when doing a cross
// site navigation.
-TEST_F(NavigatorTest, BrowserSideNavigationCrossSiteNavigation) {
+TEST_F(NavigatorTestWithBrowserSideNavigation, CrossSiteNavigation) {
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());
+ RenderFrameHostImpl* initial_rfh = main_test_rfh();
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);
+ process()->sink().ClearMessages();
+ int entry_id = RequestNavigation(node, kUrl2);
+ NavigationRequest* main_request = node->navigation_request();
ASSERT_TRUE(main_request);
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
+
+ // Receive the beforeUnload ACK.
+ main_test_rfh()->SendBeforeUnloadACK(true);
+ EXPECT_TRUE(GetSpeculativeRenderFrameHost(node));
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
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());
+ TestRenderFrameHost* speculative_rfh = GetSpeculativeRenderFrameHost(node);
+ ASSERT_TRUE(speculative_rfh);
+ EXPECT_TRUE(DidRenderFrameHostRequestCommit(speculative_rfh));
+ EXPECT_FALSE(DidRenderFrameHostRequestCommit(main_test_rfh()));
+ EXPECT_TRUE(contents()->CrossProcessNavigationPending());
+
+ speculative_rfh->SendNavigate(0, entry_id, true, kUrl2);
+
+ RenderFrameHostImpl* final_rfh = main_test_rfh();
+ EXPECT_EQ(speculative_rfh, final_rfh);
+ EXPECT_NE(initial_rfh, final_rfh);
+ EXPECT_TRUE(final_rfh->IsRenderFrameLive());
+ EXPECT_TRUE(final_rfh->render_view_host()->IsRenderViewLive());
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
}
-// PlzNavigate: Test that redirects are followed.
-TEST_F(NavigatorTest, BrowserSideNavigationRedirectCrossSite) {
+// PlzNavigate: Test that redirects are followed and the speculative
+// RenderFrameHost logic behaves as expected.
+TEST_F(NavigatorTestWithBrowserSideNavigation, RedirectCrossSite) {
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);
+ process()->sink().ClearMessages();
+ int entry_id = RequestNavigation(node, kUrl1);
+ main_test_rfh()->SendBeforeUnloadACK(true);
+ NavigationRequest* main_request = node->navigation_request();
ASSERT_TRUE(main_request);
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
// 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);
+ GetLoaderForNavigationRequest(main_request)->SimulateServerRedirect(kUrl2);
// The redirect should have been followed.
EXPECT_EQ(1, GetLoaderForNavigationRequest(main_request)->redirect_count());
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
- // Then it commits.
- response = new ResourceResponse;
+ // Have the RenderFrameHost commit the navigation.
+ 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());
+ TestRenderFrameHost* final_speculative_rfh =
+ GetSpeculativeRenderFrameHost(node);
+ EXPECT_TRUE(final_speculative_rfh);
+ EXPECT_TRUE(DidRenderFrameHostRequestCommit(final_speculative_rfh));
+
+ // Commit the navigation.
+ final_speculative_rfh->SendNavigate(0, entry_id, true, kUrl2);
+ RenderFrameHostImpl* final_rfh = main_test_rfh();
+ ASSERT_TRUE(final_rfh);
+ EXPECT_NE(rfh, final_rfh);
+ EXPECT_EQ(final_speculative_rfh, final_rfh);
+ EXPECT_TRUE(final_rfh->IsRenderFrameLive());
+ EXPECT_TRUE(final_rfh->render_view_host()->IsRenderViewLive());
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
}
-// PlzNavigate: Test that a navigation is cancelled if another request has been
-// issued in the meantime.
-TEST_F(NavigatorTest, BrowserSideNavigationReplacePendingNavigation) {
+// PlzNavigate: Test that a navigation is canceled if another browser-initiated
+// request has been issued in the meantime. Also confirms that the speculative
+// RenderFrameHost is correctly updated in the process.
+TEST_F(NavigatorTestWithBrowserSideNavigation,
+ BrowserInitiatedNavigationCancel) {
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 kUrl1_site = SiteInstance::GetSiteForURL(browser_context(), kUrl1);
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);
+ process()->sink().ClearMessages();
+ RequestNavigation(node, kUrl1);
+ main_test_rfh()->SendBeforeUnloadACK(true);
+ NavigationRequest* request1 = node->navigation_request();
ASSERT_TRUE(request1);
EXPECT_EQ(kUrl1, request1->common_params().url);
+ EXPECT_TRUE(request1->browser_initiated());
base::WeakPtr<TestNavigationURLLoader> loader1 =
GetLoaderForNavigationRequest(request1)->AsWeakPtr();
+ EXPECT_TRUE(loader1);
+
+ // Confirm a speculative RenderFrameHost was created.
+ TestRenderFrameHost* speculative_rfh = GetSpeculativeRenderFrameHost(node);
+ ASSERT_TRUE(speculative_rfh);
+ int32 site_instance_id_1 = speculative_rfh->GetSiteInstance()->GetId();
+ EXPECT_EQ(kUrl1_site, speculative_rfh->GetSiteInstance()->GetSiteURL());
// 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);
+ int entry_id = RequestNavigation(node, kUrl2);
+ main_test_rfh()->SendBeforeUnloadACK(true);
+ NavigationRequest* request2 = node->navigation_request();
ASSERT_TRUE(request2);
EXPECT_EQ(kUrl2, request2->common_params().url);
+ EXPECT_TRUE(request2->browser_initiated());
// Confirm that the first loader got destroyed.
EXPECT_FALSE(loader1);
- // Confirm that the commit corresponds to the new request.
+ // Confirm that a new speculative RenderFrameHost was created.
+ speculative_rfh = GetSpeculativeRenderFrameHost(node);
+ ASSERT_TRUE(speculative_rfh);
+ int32 site_instance_id_2 = speculative_rfh->GetSiteInstance()->GetId();
+ EXPECT_NE(site_instance_id_1, site_instance_id_2);
+
+ // Have the RenderFrameHost commit the navigation.
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());
+ EXPECT_TRUE(DidRenderFrameHostRequestCommit(speculative_rfh));
+ EXPECT_FALSE(DidRenderFrameHostRequestCommit(main_test_rfh()));
+
+ // Commit the navigation.
+ speculative_rfh->SendNavigate(0, entry_id, true, kUrl2);
+
+ // Confirm that the commit corresponds to the new request.
+ ASSERT_TRUE(main_test_rfh());
+ EXPECT_EQ(kUrl2_site, main_test_rfh()->GetSiteInstance()->GetSiteURL());
+ EXPECT_EQ(kUrl2, contents()->GetLastCommittedURL());
+
+ // Confirm that the committed RenderFrameHost is the latest speculative one.
+ EXPECT_EQ(site_instance_id_2, main_test_rfh()->GetSiteInstance()->GetId());
+}
+
+// PlzNavigate: Test that a browser-initiated navigation is canceled if a
+// renderer-initiated user-initiated request has been issued in the meantime.
+TEST_F(NavigatorTestWithBrowserSideNavigation,
+ RendererUserInitiatedNavigationCancel) {
+ const GURL kUrl0("http://www.wikipedia.org/");
+ const GURL kUrl1("http://www.chromium.org/");
+ const GURL kUrl2("http://www.google.com/");
+
+ // Initialization.
+ contents()->NavigateAndCommit(kUrl0);
+ FrameTreeNode* node = main_test_rfh()->frame_tree_node();
+
+ // Start a browser-initiated navigation to the 1st URL and receive its
+ // beforeUnload ACK.
+ process()->sink().ClearMessages();
+ RequestNavigation(node, kUrl1);
+ main_test_rfh()->SendBeforeUnloadACK(true);
+ NavigationRequest* request1 = node->navigation_request();
+ ASSERT_TRUE(request1);
+ EXPECT_EQ(kUrl1, request1->common_params().url);
+ EXPECT_TRUE(request1->browser_initiated());
+ base::WeakPtr<TestNavigationURLLoader> loader1 =
+ GetLoaderForNavigationRequest(request1)->AsWeakPtr();
+ EXPECT_TRUE(loader1);
+
+ // Confirm that a speculative RenderFrameHost was created.
+ ASSERT_TRUE(GetSpeculativeRenderFrameHost(node));
+
+ // Now receive a renderer-initiated user-initiated request. It should replace
+ // the current NavigationRequest.
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl2, true);
+ NavigationRequest* request2 = node->navigation_request();
+ ASSERT_TRUE(request2);
+ EXPECT_EQ(kUrl2, request2->common_params().url);
+ EXPECT_FALSE(request2->browser_initiated());
+ EXPECT_TRUE(request2->begin_params().has_user_gesture);
+
+ // Confirm that the first loader got destroyed.
+ EXPECT_FALSE(loader1);
+
+ // Confirm that the speculative RenderFrameHost was destroyed.
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
+
+ // Have the RenderFrameHost commit the navigation.
+ scoped_refptr<ResourceResponse> response(new ResourceResponse);
+ GetLoaderForNavigationRequest(request2)
+ ->CallOnResponseStarted(response, MakeEmptyStream());
+ EXPECT_TRUE(DidRenderFrameHostRequestCommit(main_test_rfh()));
+
+ // Commit the navigation.
+ main_test_rfh()->SendNavigate(1, 0, true, kUrl2);
+
+ // Confirm that the commit corresponds to the new request.
+ ASSERT_TRUE(main_test_rfh());
+ EXPECT_EQ(kUrl2, contents()->GetLastCommittedURL());
}
-// 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/");
+// PlzNavigate: Test that a renderer-initiated user-initiated navigation is NOT
+// canceled if a renderer-initiated non-user-initiated request is issued in the
+// meantime.
+TEST_F(NavigatorTestWithBrowserSideNavigation,
+ RendererNonUserInitiatedNavigationDoesntCancelRendererUserInitiated) {
+ const GURL kUrl0("http://www.wikipedia.org/");
const GURL kUrl1("http://www.chromium.org/");
- base::HistogramTester histo_tester;
+ const GURL kUrl2("http://www.google.com/");
- // Performs a "normal" non-PlzNavigate navigation
+ // Initialization.
contents()->NavigateAndCommit(kUrl0);
- histo_tester.ExpectTotalCount("Navigation.TimeToCommit", 1);
+ FrameTreeNode* node = main_test_rfh()->frame_tree_node();
- // 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);
+ // Start a renderer-initiated user-initiated navigation to the 1st URL.
+ process()->sink().ClearMessages();
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl1, true);
+ NavigationRequest* request1 = node->navigation_request();
+ ASSERT_TRUE(request1);
+ EXPECT_EQ(kUrl1, request1->common_params().url);
+ EXPECT_FALSE(request1->browser_initiated());
+ EXPECT_TRUE(request1->begin_params().has_user_gesture);
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
+
+ // Now receive a renderer-initiated non-user-initiated request. Nothing should
+ // change.
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl2, false);
+ NavigationRequest* request2 = node->navigation_request();
+ ASSERT_TRUE(request2);
+ EXPECT_EQ(request1, request2);
+ EXPECT_EQ(kUrl1, request2->common_params().url);
+ EXPECT_FALSE(request2->browser_initiated());
+ EXPECT_TRUE(request2->begin_params().has_user_gesture);
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
- // Performs a PlzNavigate navigation
- EnableBrowserSideNavigation();
- contents()->NavigateAndCommit(kUrl1);
- histo_tester.ExpectTotalCount("Navigation.TimeToCommit", 2);
+ // Have the RenderFrameHost commit the navigation.
+ scoped_refptr<ResourceResponse> response(new ResourceResponse);
+ GetLoaderForNavigationRequest(request2)
+ ->CallOnResponseStarted(response, MakeEmptyStream());
+ EXPECT_TRUE(DidRenderFrameHostRequestCommit(main_test_rfh()));
+
+ // Commit the navigation.
+ main_test_rfh()->SendNavigate(1, 0, true, kUrl1);
+ EXPECT_EQ(kUrl1, contents()->GetLastCommittedURL());
+}
+
+// PlzNavigate: Test that a browser-initiated navigation is NOT canceled if a
+// renderer-initiated non-user-initiated request is issued in the meantime.
+TEST_F(NavigatorTestWithBrowserSideNavigation,
+ RendererNonUserInitiatedNavigationDoesntCancelBrowserInitiated) {
+ const GURL kUrl0("http://www.wikipedia.org/");
+ const GURL kUrl1("http://www.chromium.org/");
+ const GURL kUrl2("http://www.google.com/");
+
+ // Initialization.
+ contents()->NavigateAndCommit(kUrl0);
+ FrameTreeNode* node = main_test_rfh()->frame_tree_node();
+
+ // Start a browser-initiated navigation to the 1st URL.
+ process()->sink().ClearMessages();
+ int entry_id = RequestNavigation(node, kUrl1);
+ NavigationRequest* request1 = node->navigation_request();
+ ASSERT_TRUE(request1);
+ EXPECT_EQ(kUrl1, request1->common_params().url);
+ EXPECT_TRUE(request1->browser_initiated());
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
+
+ // Now receive a renderer-initiated non-user-initiated request. Nothing should
+ // change.
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl2, false);
+ NavigationRequest* request2 = node->navigation_request();
+ ASSERT_TRUE(request2);
+ EXPECT_EQ(request1, request2);
+ EXPECT_EQ(kUrl1, request2->common_params().url);
+ EXPECT_TRUE(request2->browser_initiated());
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
+
+ // Now receive the beforeUnload ACK from the still ongoing navigation.
+ main_test_rfh()->SendBeforeUnloadACK(true);
+ TestRenderFrameHost* speculative_rfh = GetSpeculativeRenderFrameHost(node);
+ ASSERT_TRUE(speculative_rfh);
+
+ // Have the RenderFrameHost commit the navigation.
+ scoped_refptr<ResourceResponse> response(new ResourceResponse);
+ GetLoaderForNavigationRequest(request2)
+ ->CallOnResponseStarted(response, MakeEmptyStream());
+ EXPECT_TRUE(DidRenderFrameHostRequestCommit(speculative_rfh));
+ EXPECT_FALSE(DidRenderFrameHostRequestCommit(main_test_rfh()));
+
+ // Commit the navigation.
+ speculative_rfh->SendNavigate(0, entry_id, true, kUrl1);
+ EXPECT_EQ(kUrl1, contents()->GetLastCommittedURL());
+}
+
+// PlzNavigate: Test that a renderer-initiated non-user-initiated navigation is
+// canceled if a another similar request is issued in the meantime.
+TEST_F(NavigatorTestWithBrowserSideNavigation,
+ RendererNonUserInitiatedNavigationCancelSimilarNavigation) {
+ const GURL kUrl0("http://www.wikipedia.org/");
+ const GURL kUrl1("http://www.chromium.org/");
+ const GURL kUrl2("http://www.google.com/");
+
+ // Initialization.
+ contents()->NavigateAndCommit(kUrl0);
+ FrameTreeNode* node = main_test_rfh()->frame_tree_node();
+ int32 site_instance_id_0 = main_test_rfh()->GetSiteInstance()->GetId();
+
+ // Start a renderer-initiated non-user-initiated navigation to the 1st URL.
+ process()->sink().ClearMessages();
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl1, false);
+ NavigationRequest* request1 = node->navigation_request();
+ ASSERT_TRUE(request1);
+ EXPECT_EQ(kUrl1, request1->common_params().url);
+ EXPECT_FALSE(request1->browser_initiated());
+ EXPECT_FALSE(request1->begin_params().has_user_gesture);
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
+ base::WeakPtr<TestNavigationURLLoader> loader1 =
+ GetLoaderForNavigationRequest(request1)->AsWeakPtr();
+ EXPECT_TRUE(loader1);
+
+ // Now receive a 2nd similar request that should replace the current one.
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl2, false);
+ NavigationRequest* request2 = node->navigation_request();
+ EXPECT_EQ(kUrl2, request2->common_params().url);
+ EXPECT_FALSE(request2->browser_initiated());
+ EXPECT_FALSE(request2->begin_params().has_user_gesture);
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
+
+ // Confirm that the first loader got destroyed.
+ EXPECT_FALSE(loader1);
+
+ // Have the RenderFrameHost commit the navigation.
+ scoped_refptr<ResourceResponse> response(new ResourceResponse);
+ GetLoaderForNavigationRequest(request2)
+ ->CallOnResponseStarted(response, MakeEmptyStream());
+ EXPECT_TRUE(DidRenderFrameHostRequestCommit(main_test_rfh()));
+
+ // Commit the navigation.
+ main_test_rfh()->SendNavigate(1, 0, true, kUrl2);
+ EXPECT_EQ(kUrl2, contents()->GetLastCommittedURL());
+
+ // The SiteInstance did not change.
+ EXPECT_EQ(site_instance_id_0, main_test_rfh()->GetSiteInstance()->GetId());
}
// PlzNavigate: Test that a reload navigation is properly signaled to the
-// renderer when the navigation can commit.
-TEST_F(NavigatorTest, BrowserSideNavigationReload) {
+// RenderFrame when the navigation can commit. A speculative RenderFrameHost
+// should not be created at any step.
+TEST_F(NavigatorTestWithBrowserSideNavigation, Reload) {
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);
+ controller().Reload(false);
+ int entry_id = controller().GetPendingEntry()->GetUniqueID();
// A NavigationRequest should have been generated.
- NavigationRequest* main_request =
- GetNavigationRequestForFrameTreeNode(node);
+ NavigationRequest* main_request = node->navigation_request();
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);
+ main_test_rfh()->PrepareForCommit();
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
+
+ main_test_rfh()->SendNavigate(0, entry_id, false, kUrl);
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
// Now do a shift+reload.
- SendRequestNavigationWithParameters(
- node, kUrl, Referrer(), ui::PAGE_TRANSITION_LINK,
- NavigationController::RELOAD_IGNORING_CACHE);
- contents()->GetMainFrame()->SendBeginNavigationWithURL(kUrl);
+ controller().ReloadIgnoringCache(false);
// A NavigationRequest should have been generated.
- main_request = GetNavigationRequestForFrameTreeNode(node);
+ main_request = node->navigation_request();
ASSERT_TRUE(main_request != NULL);
EXPECT_EQ(FrameMsg_Navigate_Type::RELOAD_IGNORING_CACHE,
main_request->common_params().navigation_type);
+ main_test_rfh()->PrepareForCommit();
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
+}
+
+// PlzNavigate: Confirm that a speculative RenderFrameHost is used when
+// navigating from one site to another.
+TEST_F(NavigatorTestWithBrowserSideNavigation,
+ SpeculativeRendererWorksBaseCase) {
+ // Navigate to an initial site.
+ const GURL kUrlInit("http://wikipedia.org/");
+ contents()->NavigateAndCommit(kUrlInit);
+ FrameTreeNode* node = main_test_rfh()->frame_tree_node();
+
+ // Begin navigating to another site.
+ const GURL kUrl("http://google.com/");
+ process()->sink().ClearMessages();
+ int entry_id = RequestNavigation(node, kUrl);
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
+
+ // Receive the beforeUnload ACK.
+ main_test_rfh()->SendBeforeUnloadACK(true);
+ TestRenderFrameHost* speculative_rfh = GetSpeculativeRenderFrameHost(node);
+ ASSERT_TRUE(speculative_rfh);
+ EXPECT_NE(speculative_rfh, main_test_rfh());
+ EXPECT_EQ(SiteInstanceImpl::GetSiteForURL(browser_context(), kUrl),
+ speculative_rfh->GetSiteInstance()->GetSiteURL());
+ EXPECT_FALSE(node->render_manager()->pending_frame_host());
+ int32 site_instance_id = speculative_rfh->GetSiteInstance()->GetId();
+
+ // Ask Navigator to commit the navigation by simulating a call to
+ // OnResponseStarted.
+ scoped_refptr<ResourceResponse> response(new ResourceResponse);
+ GetLoaderForNavigationRequest(node->navigation_request())
+ ->CallOnResponseStarted(response, MakeEmptyStream());
+ speculative_rfh = GetSpeculativeRenderFrameHost(node);
+ ASSERT_TRUE(speculative_rfh);
+ EXPECT_TRUE(DidRenderFrameHostRequestCommit(speculative_rfh));
+ EXPECT_EQ(site_instance_id, speculative_rfh->GetSiteInstance()->GetId());
+ EXPECT_FALSE(node->render_manager()->pending_frame_host());
+
+ // Invoke OnDidCommitProvisionalLoad.
+ speculative_rfh->SendNavigate(0, entry_id, true, kUrl);
+ EXPECT_EQ(site_instance_id, main_test_rfh()->GetSiteInstance()->GetId());
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
+ EXPECT_FALSE(node->render_manager()->pending_frame_host());
+}
+
+// PlzNavigate: Confirm that a speculative RenderFrameHost is thrown away when
+// the final URL's site differs from the initial one due to redirects.
+TEST_F(NavigatorTestWithBrowserSideNavigation,
+ SpeculativeRendererDiscardedAfterRedirectToAnotherSite) {
+ // Navigate to an initial site.
+ const GURL kUrlInit("http://wikipedia.org/");
+ contents()->NavigateAndCommit(kUrlInit);
+ FrameTreeNode* node = main_test_rfh()->frame_tree_node();
+ int32 init_site_instance_id = main_test_rfh()->GetSiteInstance()->GetId();
+
+ // Begin navigating to another site.
+ const GURL kUrl("http://google.com/");
+ process()->sink().ClearMessages();
+ int entry_id = RequestNavigation(node, kUrl);
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
+
+ // Receive the beforeUnload ACK.
+ main_test_rfh()->SendBeforeUnloadACK(true);
+ TestRenderFrameHost* speculative_rfh = GetSpeculativeRenderFrameHost(node);
+ int32 site_instance_id = speculative_rfh->GetSiteInstance()->GetId();
+ EXPECT_NE(init_site_instance_id, site_instance_id);
+ EXPECT_EQ(init_site_instance_id, main_test_rfh()->GetSiteInstance()->GetId());
+ ASSERT_TRUE(speculative_rfh);
+ EXPECT_NE(speculative_rfh, main_test_rfh());
+ EXPECT_EQ(SiteInstanceImpl::GetSiteForURL(browser_context(), kUrl),
+ speculative_rfh->GetSiteInstance()->GetSiteURL());
+
+ // It then redirects to yet another site.
+ NavigationRequest* main_request = node->navigation_request();
+ ASSERT_TRUE(main_request);
+ const GURL kUrlRedirect("https://www.google.com/");
+ GetLoaderForNavigationRequest(main_request)
+ ->SimulateServerRedirect(kUrlRedirect);
+ EXPECT_EQ(init_site_instance_id, main_test_rfh()->GetSiteInstance()->GetId());
+ speculative_rfh = GetSpeculativeRenderFrameHost(node);
+ ASSERT_TRUE(speculative_rfh);
+
+ // For now, ensure that the speculative RenderFrameHost does not change after
+ // the redirect.
+ // TODO(carlosk): once the speculative RenderFrameHost updates with redirects
+ // this next check will be changed to verify that it actually happens.
+ EXPECT_EQ(site_instance_id, speculative_rfh->GetSiteInstance()->GetId());
+
+ // Commit the navigation with Navigator by simulating the call to
+ // OnResponseStarted.
+ scoped_refptr<ResourceResponse> response(new ResourceResponse);
+ GetLoaderForNavigationRequest(main_request)
+ ->CallOnResponseStarted(response, MakeEmptyStream());
+ speculative_rfh = GetSpeculativeRenderFrameHost(node);
+ EXPECT_TRUE(DidRenderFrameHostRequestCommit(speculative_rfh));
+ EXPECT_EQ(init_site_instance_id, main_test_rfh()->GetSiteInstance()->GetId());
+
+ // Once commit happens the speculative RenderFrameHost is updated to match the
+ // known final SiteInstance.
+ ASSERT_TRUE(speculative_rfh);
+ EXPECT_EQ(SiteInstanceImpl::GetSiteForURL(browser_context(), kUrlRedirect),
+ speculative_rfh->GetSiteInstance()->GetSiteURL());
+ int32 redirect_site_instance_id = speculative_rfh->GetSiteInstance()->GetId();
+ EXPECT_NE(init_site_instance_id, redirect_site_instance_id);
+ EXPECT_NE(site_instance_id, redirect_site_instance_id);
+
+ // Invoke OnDidCommitProvisionalLoad.
+ speculative_rfh->SendNavigate(0, entry_id, true, kUrlRedirect);
+
+ // Check that the speculative RenderFrameHost was swapped in.
+ EXPECT_EQ(redirect_site_instance_id,
+ main_test_rfh()->GetSiteInstance()->GetId());
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
+}
+
+// PlzNavigate: Verify that a previously swapped out RenderFrameHost is
+// correctly reused when spawning a speculative RenderFrameHost in a navigation
+// using the same SiteInstance.
+TEST_F(NavigatorTestWithBrowserSideNavigation,
+ SpeculativeRendererReuseSwappedOutRFH) {
+ // Navigate to an initial site.
+ const GURL kUrl1("http://wikipedia.org/");
+ contents()->NavigateAndCommit(kUrl1);
+ TestRenderFrameHost* rfh1 = main_test_rfh();
+ FrameTreeNode* node = rfh1->frame_tree_node();
+ RenderFrameHostManager* rfhm = node->render_manager();
+
+ // Increment active frame count to cause the RenderFrameHost to be swapped out
+ // (instead of immediately destroyed).
+ rfh1->GetSiteInstance()->increment_active_frame_count();
+
+ // Navigate to another site to swap out the initial RenderFrameHost.
+ const GURL kUrl2("http://chromium.org/");
+ contents()->NavigateAndCommit(kUrl2);
+ ASSERT_NE(rfh1, main_test_rfh());
+ EXPECT_NE(RenderFrameHostImpl::STATE_DEFAULT, rfh1->rfh_state());
+ EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, main_test_rfh()->rfh_state());
+ EXPECT_TRUE(rfhm->IsOnSwappedOutList(rfh1));
+
+ // Now go back to the initial site so that the swapped out RenderFrameHost
+ // should be reused.
+ process()->sink().ClearMessages();
+ rfh1->GetProcess()->sink().ClearMessages();
+ int entry_id = RequestNavigation(node, kUrl1);
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
+
+ main_test_rfh()->SendBeforeUnloadACK(true);
+ EXPECT_EQ(rfh1, GetSpeculativeRenderFrameHost(node));
+ EXPECT_NE(RenderFrameHostImpl::STATE_DEFAULT,
+ GetSpeculativeRenderFrameHost(node)->rfh_state());
+
+ scoped_refptr<ResourceResponse> response(new ResourceResponse);
+ GetLoaderForNavigationRequest(node->navigation_request())
+ ->CallOnResponseStarted(response, MakeEmptyStream());
+ EXPECT_EQ(rfh1, GetSpeculativeRenderFrameHost(node));
+ EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT,
+ GetSpeculativeRenderFrameHost(node)->rfh_state());
+ EXPECT_TRUE(DidRenderFrameHostRequestCommit(rfh1));
+ EXPECT_FALSE(DidRenderFrameHostRequestCommit(main_test_rfh()));
+
+ rfh1->SendNavigate(1, entry_id, true, kUrl1);
+ EXPECT_EQ(rfh1, main_test_rfh());
+ EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, rfh1->rfh_state());
+ EXPECT_FALSE(rfhm->IsOnSwappedOutList(rfh1));
+}
+
+// PlzNavigate: Verify that data urls are properly handled.
+TEST_F(NavigatorTestWithBrowserSideNavigation, DataUrls) {
+ const GURL kUrl1("http://wikipedia.org/");
+ const GURL kUrl2("data:text/html,test");
+
+ // Navigate to an initial site.
+ contents()->NavigateAndCommit(kUrl1);
+ FrameTreeNode* node = main_test_rfh()->frame_tree_node();
+
+ // Navigate to a data url.
+ int entry_id = RequestNavigation(node, kUrl2);
+ NavigationRequest* navigation_request = node->navigation_request();
+ ASSERT_TRUE(navigation_request);
+ EXPECT_EQ(NavigationRequest::WAITING_FOR_RENDERER_RESPONSE,
+ navigation_request->state());
+ main_test_rfh()->SendBeforeUnloadACK(true);
+
+ // The request should not have been sent to the IO thread but committed
+ // immediately.
+ EXPECT_EQ(NavigationRequest::RESPONSE_STARTED,
+ navigation_request->state());
+ EXPECT_FALSE(navigation_request->loader_for_testing());
+ TestRenderFrameHost* speculative_rfh = GetSpeculativeRenderFrameHost(node);
+ ASSERT_TRUE(speculative_rfh);
+ speculative_rfh->SendNavigate(0, entry_id, true, kUrl2);
+ EXPECT_EQ(main_test_rfh(), speculative_rfh);
+
+ // Go back to the initial site.
+ contents()->NavigateAndCommit(kUrl1);
+
+ // Do a renderer-initiated navigation to a data url. The request should not be
+ // sent to the IO thread, nor committed.
+ TestRenderFrameHost* main_rfh = main_test_rfh();
+ main_rfh->SendRendererInitiatedNavigationRequest(kUrl2, true);
+ navigation_request = node->navigation_request();
+ ASSERT_TRUE(navigation_request);
+ EXPECT_EQ(NavigationRequest::RESPONSE_STARTED,
+ navigation_request->state());
+ EXPECT_FALSE(navigation_request->loader_for_testing());
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
+}
+
+// Tests several cases for converting SiteInstanceDescriptors into
+// SiteInstances:
+// 1) Pointer to the current SiteInstance.
+// 2) Pointer to an unrelated SiteInstance.
+// 3) Same-site URL, related.
+// 4) Cross-site URL, related.
+// 5) Same-site URL, unrelated (with and without candidate SiteInstances).
+// 6) Cross-site URL, unrelated (with candidate SiteInstance).
+TEST_F(NavigatorTestWithBrowserSideNavigation,
+ SiteInstanceDescriptionConversion) {
+ // Navigate to set a current SiteInstance on the RenderFrameHost.
+ GURL kUrl1("http://a.com");
+ contents()->NavigateAndCommit(kUrl1);
+ SiteInstance* current_instance = main_test_rfh()->GetSiteInstance();
+ ASSERT_TRUE(current_instance);
+
+ // 1) Convert a descriptor pointing to the current instance.
+ RenderFrameHostManager* rfhm =
+ main_test_rfh()->frame_tree_node()->render_manager();
+ {
+ SiteInstanceDescriptor descriptor(current_instance);
+ SiteInstance* converted_instance =
+ ConvertToSiteInstance(rfhm, descriptor, nullptr);
+ EXPECT_EQ(current_instance, converted_instance);
+ }
+
+ // 2) Convert a descriptor pointing an instance unrelated to the current one,
+ // with a different site.
+ GURL kUrl2("http://b.com");
+ scoped_refptr<SiteInstance> unrelated_instance(
+ SiteInstance::CreateForURL(browser_context(), kUrl2));
+ EXPECT_FALSE(
+ current_instance->IsRelatedSiteInstance(unrelated_instance.get()));
+ {
+ SiteInstanceDescriptor descriptor(unrelated_instance.get());
+ SiteInstance* converted_instance =
+ ConvertToSiteInstance(rfhm, descriptor, nullptr);
+ EXPECT_EQ(unrelated_instance.get(), converted_instance);
+ }
+
+ // 3) Convert a descriptor of a related instance with the same site as the
+ // current one.
+ GURL kUrlSameSiteAs1("http://www.a.com/foo");
+ {
+ SiteInstanceDescriptor descriptor(browser_context(), kUrlSameSiteAs1, true);
+ SiteInstance* converted_instance =
+ ConvertToSiteInstance(rfhm, descriptor, nullptr);
+ EXPECT_EQ(current_instance, converted_instance);
+ }
+
+ // 4) Convert a descriptor of a related instance with a site different from
+ // the current one.
+ GURL kUrlSameSiteAs2("http://www.b.com/foo");
+ scoped_refptr<SiteInstance> related_instance;
+ {
+ SiteInstanceDescriptor descriptor(browser_context(), kUrlSameSiteAs2, true);
+ related_instance = ConvertToSiteInstance(rfhm, descriptor, nullptr);
+ // Should return a new instance, related to the current, set to the new site
+ // URL.
+ EXPECT_TRUE(
+ current_instance->IsRelatedSiteInstance(related_instance.get()));
+ EXPECT_NE(current_instance, related_instance.get());
+ EXPECT_NE(unrelated_instance.get(), related_instance.get());
+ EXPECT_EQ(SiteInstance::GetSiteForURL(browser_context(), kUrlSameSiteAs2),
+ related_instance->GetSiteURL());
+ }
+
+ // 5) Convert a descriptor of an unrelated instance with the same site as the
+ // current one, several times, with and without candidate sites.
+ {
+ SiteInstanceDescriptor descriptor(browser_context(), kUrlSameSiteAs1,
+ false);
+ scoped_refptr<SiteInstance> converted_instance_1 =
+ ConvertToSiteInstance(rfhm, descriptor, nullptr);
+ // Should return a new instance, unrelated to the current one, set to the
+ // provided site URL.
+ EXPECT_FALSE(
+ current_instance->IsRelatedSiteInstance(converted_instance_1.get()));
+ EXPECT_NE(current_instance, converted_instance_1.get());
+ EXPECT_NE(unrelated_instance.get(), converted_instance_1.get());
+ EXPECT_EQ(SiteInstance::GetSiteForURL(browser_context(), kUrlSameSiteAs1),
+ converted_instance_1->GetSiteURL());
+
+ // Does the same but this time using unrelated_instance as a candidate,
+ // which has a different site.
+ scoped_refptr<SiteInstance> converted_instance_2 =
+ ConvertToSiteInstance(rfhm, descriptor, unrelated_instance.get());
+ // Should return yet another new instance, unrelated to the current one, set
+ // to the same site URL.
+ EXPECT_FALSE(
+ current_instance->IsRelatedSiteInstance(converted_instance_2.get()));
+ EXPECT_NE(current_instance, converted_instance_2.get());
+ EXPECT_NE(unrelated_instance.get(), converted_instance_2.get());
+ EXPECT_NE(converted_instance_1.get(), converted_instance_2.get());
+ EXPECT_EQ(SiteInstance::GetSiteForURL(browser_context(), kUrlSameSiteAs1),
+ converted_instance_2->GetSiteURL());
+
+ // Converts once more but with |converted_instance_1| as a candidate.
+ SiteInstance* converted_instance_3 =
+ ConvertToSiteInstance(rfhm, descriptor, converted_instance_1.get());
+ // Should return |converted_instance_1| because its site matches and it is
+ // unrelated to the current SiteInstance.
+ EXPECT_EQ(converted_instance_1.get(), converted_instance_3);
+ }
+
+ // 6) Convert a descriptor of an unrelated instance with the same site of
+ // related_instance and using it as a candidate.
+ {
+ SiteInstanceDescriptor descriptor(browser_context(), kUrlSameSiteAs2,
+ false);
+ scoped_refptr<SiteInstance> converted_instance_1 =
+ ConvertToSiteInstance(rfhm, descriptor, related_instance.get());
+ // Should return a new instance, unrelated to the current, set to the
+ // provided site URL.
+ EXPECT_FALSE(
+ current_instance->IsRelatedSiteInstance(converted_instance_1.get()));
+ EXPECT_NE(related_instance.get(), converted_instance_1.get());
+ EXPECT_NE(unrelated_instance.get(), converted_instance_1.get());
+ EXPECT_EQ(SiteInstance::GetSiteForURL(browser_context(), kUrlSameSiteAs2),
+ converted_instance_1->GetSiteURL());
+
+ SiteInstance* converted_instance_2 =
+ ConvertToSiteInstance(rfhm, descriptor, unrelated_instance.get());
+ // Should return |unrelated_instance| because its site matches and it is
+ // unrelated to the current SiteInstance.
+ EXPECT_EQ(unrelated_instance.get(), converted_instance_2);
+ }
}
} // namespace content
diff --git a/chromium/content/browser/frame_host/popup_menu_helper_mac.h b/chromium/content/browser/frame_host/popup_menu_helper_mac.h
index e92aa10340f..5575d89483c 100644
--- a/chromium/content/browser/frame_host/popup_menu_helper_mac.h
+++ b/chromium/content/browser/frame_host/popup_menu_helper_mac.h
@@ -11,7 +11,7 @@
#include "content/common/content_export.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
-#include "ui/gfx/rect.h"
+#include "ui/gfx/geometry/rect.h"
#ifdef __OBJC__
@class WebMenuRunner;
diff --git a/chromium/content/browser/frame_host/popup_menu_helper_mac.mm b/chromium/content/browser/frame_host/popup_menu_helper_mac.mm
index eac8f7c3b7a..1ab1917d713 100644
--- a/chromium/content/browser/frame_host/popup_menu_helper_mac.mm
+++ b/chromium/content/browser/frame_host/popup_menu_helper_mac.mm
@@ -13,6 +13,7 @@
#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"
+#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/notification_types.h"
#import "ui/base/cocoa/base_view.h"
@@ -32,6 +33,9 @@ PopupMenuHelper::PopupMenuHelper(RenderFrameHost* render_frame_host)
notification_registrar_.Add(
this, NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED,
Source<RenderWidgetHost>(render_frame_host->GetRenderViewHost()));
+ notification_registrar_.Add(
+ this, NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
+ Source<RenderWidgetHost>(render_frame_host->GetRenderViewHost()));
}
void PopupMenuHelper::ShowPopupMenu(
@@ -119,10 +123,20 @@ RenderWidgetHostViewMac* PopupMenuHelper::GetRenderWidgetHostView() const {
void PopupMenuHelper::Observe(int type,
const NotificationSource& source,
const NotificationDetails& details) {
- DCHECK(type == NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED);
DCHECK_EQ(Source<RenderWidgetHost>(source).ptr(),
render_frame_host_->GetRenderViewHost());
- render_frame_host_ = NULL;
+ switch (type) {
+ case NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED: {
+ render_frame_host_ = NULL;
+ break;
+ }
+ case NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED: {
+ bool is_visible = *Details<bool>(details).ptr();
+ if (!is_visible)
+ Hide();
+ break;
+ }
+ }
}
} // 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 a83715dece8..ff4aba61ac6 100644
--- a/chromium/content/browser/frame_host/render_frame_host_delegate.cc
+++ b/chromium/content/browser/frame_host/render_frame_host_delegate.cc
@@ -7,6 +7,7 @@
#include "base/callback.h"
#include "base/strings/string16.h"
#include "content/browser/frame_host/render_frame_host_delegate.h"
+#include "ipc/ipc_message.h"
#include "ui/gfx/native_widget_types.h"
#include "url/gurl.h"
@@ -59,6 +60,7 @@ AccessibilityMode RenderFrameHostDelegate::GetAccessibilityMode() const {
}
RenderFrameHost* RenderFrameHostDelegate::GetGuestByInstanceID(
+ RenderFrameHost* render_frame_host,
int browser_plugin_instance_id) {
return NULL;
}
@@ -68,6 +70,17 @@ RenderFrameHostDelegate::GetGeolocationServiceContext() {
return NULL;
}
+bool RenderFrameHostDelegate::ShouldRouteMessageEvent(
+ RenderFrameHost* target_rfh,
+ SiteInstance* source_site_instance) const {
+ return false;
+}
+
+int RenderFrameHostDelegate::EnsureOpenerRenderViewsExist(
+ RenderFrameHost* source_rfh) {
+ return MSG_ROUTING_NONE;
+}
+
#if defined(OS_WIN)
gfx::NativeViewAccessible
RenderFrameHostDelegate::GetParentNativeViewAccessible() {
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 6c22d94abf2..708e1c92d12 100644
--- a/chromium/content/browser/frame_host/render_frame_host_delegate.h
+++ b/chromium/content/browser/frame_host/render_frame_host_delegate.h
@@ -11,6 +11,7 @@
#include "base/i18n/rtl.h"
#include "content/common/content_export.h"
#include "content/common/frame_message_enums.h"
+#include "content/public/browser/site_instance.h"
#include "content/public/common/javascript_message_type.h"
#include "content/public/common/media_stream_request.h"
#include "net/http/http_response_headers.h"
@@ -57,13 +58,6 @@ class CONTENT_EXPORT RenderFrameHostDelegate {
// Informs the delegate whenever a RenderFrameHost is deleted.
virtual void RenderFrameDeleted(RenderFrameHost* render_frame_host) {}
- // The top-level RenderFrame began loading a new page. This corresponds to
- // Blink's notion of the throbber starting.
- // |to_different_document| will be true unless the load is a fragment
- // navigation, or triggered by history.pushState/replaceState.
- virtual void DidStartLoading(RenderFrameHost* render_frame_host,
- bool to_different_document) {}
-
// The RenderFrameHost has been swapped out.
virtual void SwappedOut(RenderFrameHost* render_frame_host) {}
@@ -100,6 +94,10 @@ class CONTENT_EXPORT RenderFrameHostDelegate {
// is no longer safe to display a pending URL without risking a URL spoof.
virtual void DidAccessInitialDocument() {}
+ // The frame changed its window.name property.
+ virtual void DidChangeName(RenderFrameHost* render_frame_host,
+ const std::string& name) {}
+
// The frame set its opener to null, disowning it for the lifetime of the
// window. Only called for the top-level frame.
virtual void DidDisownOpener(RenderFrameHost* render_frame_host) {}
@@ -144,13 +142,42 @@ class CONTENT_EXPORT RenderFrameHostDelegate {
virtual void AccessibilityEventReceived(
const std::vector<AXEventNotificationDetails>& details) {}
- // Find a guest RenderFrameHost by its browser plugin instance id.
+ // Find a guest RenderFrameHost by its parent |render_frame_host| and
+ // |browser_plugin_instance_id|.
virtual RenderFrameHost* GetGuestByInstanceID(
+ RenderFrameHost* render_frame_host,
int browser_plugin_instance_id);
// Gets the GeolocationServiceContext associated with this delegate.
virtual GeolocationServiceContext* GetGeolocationServiceContext();
+ // Notification that the frame wants to go into fullscreen mode.
+ // |origin| represents the origin of the frame that requests fullscreen.
+ virtual void EnterFullscreenMode(const GURL& origin) {}
+
+ // Notification that the frame wants to go out of fullscreen mode.
+ virtual void ExitFullscreenMode() {}
+
+ // Let the delegate decide whether postMessage should be delivered to
+ // |target_rfh| from a source frame in the given SiteInstance. This defaults
+ // to false and overrides the RenderFrameHost's decision if true.
+ virtual bool ShouldRouteMessageEvent(
+ RenderFrameHost* target_rfh,
+ SiteInstance* source_site_instance) const;
+
+ // Ensure that |source_rfh| has swapped-out RenderViews and proxies for
+ // itself and for each frame on its opener chain in the current frame's
+ // SiteInstance. Returns the routing ID of the swapped-out RenderView
+ // corresponding to |source_rfh|.
+ //
+ // TODO(alexmos): This method will be removed once opener tracking and
+ // CreateOpenerRenderViews moves out of WebContents and into lower layers, as
+ // part of https://crbug.com/225940. Currently, this method temporarily
+ // supports cross-process postMessage in non-site-per-process mode, where we
+ // need to create any missing proxies for the message's source frame and its
+ // opener chain on demand.
+ virtual int EnsureOpenerRenderViewsExist(RenderFrameHost* source_rfh);
+
#if defined(OS_WIN)
// Returns the frame's parent's NativeViewAccessible.
virtual gfx::NativeViewAccessible GetParentNativeViewAccessible();
diff --git a/chromium/content/browser/frame_host/render_frame_host_factory.cc b/chromium/content/browser/frame_host/render_frame_host_factory.cc
index 4262c1c7eb2..412073aa8bb 100644
--- a/chromium/content/browser/frame_host/render_frame_host_factory.cc
+++ b/chromium/content/browser/frame_host/render_frame_host_factory.cc
@@ -15,23 +15,22 @@ RenderFrameHostFactory* RenderFrameHostFactory::factory_ = NULL;
// static
scoped_ptr<RenderFrameHostImpl> RenderFrameHostFactory::Create(
+ SiteInstance* site_instance,
RenderViewHostImpl* render_view_host,
RenderFrameHostDelegate* delegate,
+ RenderWidgetHostDelegate* rwh_delegate,
FrameTree* frame_tree,
FrameTreeNode* frame_tree_node,
int routing_id,
- bool is_swapped_out) {
+ int flags) {
if (factory_) {
- return factory_->CreateRenderFrameHost(render_view_host,
- delegate,
- frame_tree,
- frame_tree_node,
- routing_id,
- is_swapped_out).Pass();
+ return factory_->CreateRenderFrameHost(site_instance, render_view_host,
+ delegate, rwh_delegate, frame_tree,
+ frame_tree_node, routing_id, flags);
}
return make_scoped_ptr(new RenderFrameHostImpl(
- render_view_host, delegate, frame_tree, frame_tree_node, routing_id,
- is_swapped_out));
+ site_instance, render_view_host, delegate, rwh_delegate, frame_tree,
+ frame_tree_node, routing_id, flags));
}
// static
diff --git a/chromium/content/browser/frame_host/render_frame_host_factory.h b/chromium/content/browser/frame_host/render_frame_host_factory.h
index ce8433d0882..07b8ffb7024 100644
--- a/chromium/content/browser/frame_host/render_frame_host_factory.h
+++ b/chromium/content/browser/frame_host/render_frame_host_factory.h
@@ -16,6 +16,8 @@ class FrameTreeNode;
class RenderFrameHostDelegate;
class RenderFrameHostImpl;
class RenderViewHostImpl;
+class RenderWidgetHostDelegate;
+class SiteInstance;
// A factory for creating RenderFrameHosts. There is a global factory function
// that can be installed for the purposes of testing to provide a specialized
@@ -25,12 +27,14 @@ class CONTENT_EXPORT RenderFrameHostFactory {
// Creates a new RenderFrameHostImpl using the currently registered factory,
// or a regular RenderFrameHostImpl if no factory is registered.
static scoped_ptr<RenderFrameHostImpl> Create(
+ SiteInstance* site_instance,
RenderViewHostImpl* render_view_host,
RenderFrameHostDelegate* delegate,
+ RenderWidgetHostDelegate* rwh_delegate,
FrameTree* frame_tree,
FrameTreeNode* frame_tree_node,
int routing_id,
- bool is_swapped_out);
+ int flags);
// Returns true if there is currently a globally-registered factory.
static bool has_factory() { return !!factory_; }
@@ -42,12 +46,14 @@ class CONTENT_EXPORT RenderFrameHostFactory {
// You can derive from this class and specify an implementation for this
// function to create an alternate kind of RenderFrameHostImpl for testing.
virtual scoped_ptr<RenderFrameHostImpl> CreateRenderFrameHost(
+ SiteInstance* site_instance,
RenderViewHostImpl* render_view_host,
RenderFrameHostDelegate* delegate,
+ RenderWidgetHostDelegate* rwh_delegate,
FrameTree* frame_tree,
FrameTreeNode* frame_tree_node,
int routing_id,
- bool is_swapped_out) = 0;
+ int flags) = 0;
// Registers a factory to be called when new RenderFrameHostImpls are created.
// We have only one global factory, so there must be no factory registered
diff --git a/chromium/content/browser/frame_host/render_frame_host_impl.cc b/chromium/content/browser/frame_host/render_frame_host_impl.cc
index b7941077c5e..9929fa143cb 100644
--- a/chromium/content/browser/frame_host/render_frame_host_impl.cc
+++ b/chromium/content/browser/frame_host/render_frame_host_impl.cc
@@ -9,22 +9,28 @@
#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/process/kill.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/bad_message.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/navigation_request.h"
#include "content/browser/frame_host/navigator.h"
+#include "content/browser/frame_host/navigator_impl.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/permissions/permission_service_context.h"
+#include "content/browser/permissions/permission_service_impl.h"
+#include "content/browser/presentation/presentation_service_impl.h"
#include "content/browser/renderer_host/input/input_router.h"
#include "content/browser/renderer_host/input/timeout_monitor.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
@@ -35,13 +41,10 @@
#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"
@@ -50,7 +53,8 @@
#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/permission_manager.h"
+#include "content/public/browser/permission_type.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"
@@ -59,13 +63,24 @@
#include "content/public/common/content_switches.h"
#include "content/public/common/url_constants.h"
#include "content/public/common/url_utils.h"
+#include "content/public/renderer/isolated_world_ids.h"
#include "ui/accessibility/ax_tree.h"
+#include "ui/accessibility/ax_tree_update.h"
#include "url/gurl.h"
+#if defined(OS_ANDROID)
+#include "content/browser/mojo/service_registrar_android.h"
+#endif
+
#if defined(OS_MACOSX)
#include "content/browser/frame_host/popup_menu_helper_mac.h"
#endif
+#if defined(ENABLE_MEDIA_MOJO_RENDERER)
+#include "media/mojo/interfaces/media_renderer.mojom.h"
+#include "media/mojo/services/mojo_renderer_service.h"
+#endif
+
using base::TimeDelta;
namespace content {
@@ -75,6 +90,9 @@ namespace {
// The next value to use for the accessibility reset token.
int g_next_accessibility_reset_token = 1;
+// The next value to use for the javascript callback id.
+int g_next_javascript_callback_id = 1;
+
// The (process id, routing id) pair that identifies one RenderFrame.
typedef std::pair<int32, int32> RenderFrameHostID;
typedef base::hash_map<RenderFrameHostID, RenderFrameHostImpl*>
@@ -82,54 +100,6 @@ typedef base::hash_map<RenderFrameHostID, RenderFrameHostImpl*>
base::LazyInstance<RoutingIDFrameMap> g_routing_id_frame_map =
LAZY_INSTANCE_INITIALIZER;
-class DesktopNotificationDelegateImpl : public DesktopNotificationDelegate {
- public:
- DesktopNotificationDelegateImpl(RenderFrameHost* render_frame_host,
- int notification_id)
- : render_process_id_(render_frame_host->GetProcess()->GetID()),
- render_frame_id_(render_frame_host->GetRoutingID()),
- notification_id_(notification_id) {}
-
- ~DesktopNotificationDelegateImpl() override {}
-
- void NotificationDisplayed() override {
- RenderFrameHost* rfh =
- RenderFrameHost::FromID(render_process_id_, render_frame_id_);
- if (!rfh)
- return;
-
- rfh->Send(new DesktopNotificationMsg_PostDisplay(
- rfh->GetRoutingID(), notification_id_));
- }
-
- void NotificationClosed(bool by_user) override {
- RenderFrameHost* rfh =
- RenderFrameHost::FromID(render_process_id_, render_frame_id_);
- if (!rfh)
- return;
-
- rfh->Send(new DesktopNotificationMsg_PostClose(
- rfh->GetRoutingID(), notification_id_, by_user));
- static_cast<RenderFrameHostImpl*>(rfh)->NotificationClosed(
- notification_id_);
- }
-
- void NotificationClick() override {
- RenderFrameHost* rfh =
- RenderFrameHost::FromID(render_process_id_, render_frame_id_);
- if (!rfh)
- return;
-
- rfh->Send(new DesktopNotificationMsg_PostClick(
- rfh->GetRoutingID(), notification_id_));
- }
-
- private:
- int render_process_id_;
- int render_frame_id_;
- int notification_id_;
-};
-
// Translate a WebKit text direction into a base::i18n one.
base::i18n::TextDirection WebTextDirectionToChromeTextDirection(
blink::WebTextDirection dir) {
@@ -160,34 +130,43 @@ RenderFrameHost* RenderFrameHost::FromID(int render_process_id,
// static
RenderFrameHostImpl* RenderFrameHostImpl::FromID(int process_id,
int routing_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
RoutingIDFrameMap* frames = g_routing_id_frame_map.Pointer();
RoutingIDFrameMap::iterator it = frames->find(
RenderFrameHostID(process_id, routing_id));
return it == frames->end() ? NULL : it->second;
}
-RenderFrameHostImpl::RenderFrameHostImpl(RenderViewHostImpl* render_view_host,
+RenderFrameHostImpl::RenderFrameHostImpl(SiteInstance* site_instance,
+ RenderViewHostImpl* render_view_host,
RenderFrameHostDelegate* delegate,
+ RenderWidgetHostDelegate* rwh_delegate,
FrameTree* frame_tree,
FrameTreeNode* frame_tree_node,
int routing_id,
- bool is_swapped_out)
+ int flags)
: render_view_host_(render_view_host),
delegate_(delegate),
+ site_instance_(static_cast<SiteInstanceImpl*>(site_instance)),
+ process_(site_instance->GetProcess()),
cross_process_frame_connector_(NULL),
render_frame_proxy_host_(NULL),
frame_tree_(frame_tree),
frame_tree_node_(frame_tree_node),
+ render_widget_host_(nullptr),
routing_id_(routing_id),
render_frame_created_(false),
navigations_suspended_(false),
is_waiting_for_beforeunload_ack_(false),
- unload_ack_is_for_cross_site_transition_(false),
+ unload_ack_is_for_navigation_(false),
+ is_loading_(false),
+ pending_commit_(false),
accessibility_reset_token_(0),
accessibility_reset_count_(0),
no_create_browser_accessibility_manager_for_testing_(false),
weak_ptr_factory_(this) {
+ bool is_swapped_out = !!(flags & CREATE_RF_SWAPPED_OUT);
+ bool hidden = !!(flags & CREATE_RF_HIDDEN);
frame_tree_->RegisterRenderFrameHost(this);
GetProcess()->AddRoute(routing_id_, this);
g_routing_id_frame_map.Get().insert(std::make_pair(
@@ -204,6 +183,12 @@ RenderFrameHostImpl::RenderFrameHostImpl(RenderViewHostImpl* render_view_host,
SetUpMojoIfNeeded();
swapout_event_monitor_timeout_.reset(new TimeoutMonitor(base::Bind(
&RenderFrameHostImpl::OnSwappedOut, weak_ptr_factory_.GetWeakPtr())));
+
+ if (flags & CREATE_RF_NEEDS_RENDER_WIDGET_HOST) {
+ render_widget_host_ = new RenderWidgetHostImpl(rwh_delegate, GetProcess(),
+ MSG_ROUTING_NONE, hidden);
+ render_widget_host_->set_owned_by_render_frame_host(true);
+ }
}
RenderFrameHostImpl::~RenderFrameHostImpl() {
@@ -211,7 +196,7 @@ RenderFrameHostImpl::~RenderFrameHostImpl() {
g_routing_id_frame_map.Get().erase(
RenderFrameHostID(GetProcess()->GetID(), routing_id_));
- if (delegate_)
+ if (delegate_ && render_frame_created_)
delegate_->RenderFrameDeleted(this);
FrameAccessibility::GetInstance()->OnRenderFrameHostDestroyed(this);
@@ -224,6 +209,19 @@ RenderFrameHostImpl::~RenderFrameHostImpl() {
// 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);
+
+ // NULL out the swapout timer; in crash dumps this member will be null only if
+ // the dtor has run.
+ swapout_event_monitor_timeout_.reset();
+
+ for (const auto& iter: visual_state_callbacks_) {
+ iter.second.Run(false);
+ }
+
+ if (render_widget_host_) {
+ // Shutdown causes the RenderWidgetHost to delete itself.
+ render_widget_host_->Shutdown();
+ }
}
int RenderFrameHostImpl::GetRoutingID() {
@@ -231,13 +229,11 @@ int RenderFrameHostImpl::GetRoutingID() {
}
SiteInstanceImpl* RenderFrameHostImpl::GetSiteInstance() {
- return render_view_host_->GetSiteInstance();
+ return site_instance_.get();
}
RenderProcessHost* RenderFrameHostImpl::GetProcess() {
- // TODO(nasko): This should return its own process, once we have working
- // cross-process navigation for subframes.
- return render_view_host_->GetProcess();
+ return process_;
}
RenderFrameHost* RenderFrameHostImpl::GetParent() {
@@ -280,19 +276,35 @@ void RenderFrameHostImpl::ExecuteJavaScript(
void RenderFrameHostImpl::ExecuteJavaScript(
const base::string16& javascript,
const JavaScriptResultCallback& callback) {
- static int next_id = 1;
- int key = next_id++;
+ int key = g_next_javascript_callback_id++;
Send(new FrameMsg_JavaScriptExecuteRequest(routing_id_,
javascript,
key, true));
javascript_callbacks_.insert(std::make_pair(key, callback));
}
-void RenderFrameHostImpl::ExecuteJavaScriptForTests(
+void RenderFrameHostImpl::ExecuteJavaScriptWithUserGestureForTests(
const base::string16& javascript) {
Send(new FrameMsg_JavaScriptExecuteRequestForTests(routing_id_,
javascript,
- 0, false));
+ 0, false, true));
+}
+
+void RenderFrameHostImpl::ExecuteJavaScriptInIsolatedWorld(
+ const base::string16& javascript,
+ const JavaScriptResultCallback& callback,
+ int world_id) {
+ if (world_id <= ISOLATED_WORLD_ID_GLOBAL ||
+ world_id > ISOLATED_WORLD_ID_MAX) {
+ // Return if the world_id is not valid.
+ NOTREACHED();
+ return;
+ }
+
+ int key = g_next_javascript_callback_id++;
+ Send(new FrameMsg_JavaScriptExecuteRequestInIsolatedWorld(
+ routing_id_, javascript, key, true, world_id));
+ javascript_callbacks_.insert(std::make_pair(key, callback));
}
RenderViewHost* RenderFrameHostImpl::GetRenderViewHost() {
@@ -303,20 +315,24 @@ ServiceRegistry* RenderFrameHostImpl::GetServiceRegistry() {
return service_registry_.get();
}
+blink::WebPageVisibilityState RenderFrameHostImpl::GetVisibilityState() {
+ // TODO(mlamouri,kenrb): call GetRenderWidgetHost() directly when it stops
+ // returning nullptr in some cases. See https://crbug.com/455245.
+ blink::WebPageVisibilityState visibility_state =
+ RenderWidgetHostImpl::From(GetView()->GetRenderWidgetHost())->is_hidden()
+ ? blink::WebPageVisibilityStateHidden
+ : blink::WebPageVisibilityStateVisible;
+ GetContentClient()->browser()->OverridePageVisibilityState(this,
+ &visibility_state);
+ return visibility_state;
+}
+
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));
}
- // 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);
- }
-
return GetProcess()->Send(message);
}
@@ -360,6 +376,7 @@ bool RenderFrameHostImpl::OnMessageReceived(const IPC::Message &msg) {
OnDidFailLoadWithError)
IPC_MESSAGE_HANDLER_GENERIC(FrameHostMsg_DidCommitProvisionalLoad,
OnDidCommitProvisionalLoad(msg))
+ IPC_MESSAGE_HANDLER(FrameHostMsg_DidDropNavigation, OnDidDropNavigation)
IPC_MESSAGE_HANDLER(FrameHostMsg_OpenURL, OnOpenURL)
IPC_MESSAGE_HANDLER(FrameHostMsg_DocumentOnLoadCompleted,
OnDocumentOnLoadCompleted)
@@ -368,6 +385,8 @@ bool RenderFrameHostImpl::OnMessageReceived(const IPC::Message &msg) {
IPC_MESSAGE_HANDLER(FrameHostMsg_ContextMenu, OnContextMenu)
IPC_MESSAGE_HANDLER(FrameHostMsg_JavaScriptExecuteResponse,
OnJavaScriptExecuteResponse)
+ IPC_MESSAGE_HANDLER(FrameHostMsg_VisualStateResponse,
+ OnVisualStateResponse)
IPC_MESSAGE_HANDLER_DELAY_REPLY(FrameHostMsg_RunJavaScriptMessage,
OnRunJavaScriptMessage)
IPC_MESSAGE_HANDLER_DELAY_REPLY(FrameHostMsg_RunBeforeUnloadConfirm,
@@ -375,17 +394,15 @@ bool RenderFrameHostImpl::OnMessageReceived(const IPC::Message &msg) {
IPC_MESSAGE_HANDLER(FrameHostMsg_DidAccessInitialDocument,
OnDidAccessInitialDocument)
IPC_MESSAGE_HANDLER(FrameHostMsg_DidDisownOpener, OnDidDisownOpener)
+ IPC_MESSAGE_HANDLER(FrameHostMsg_DidChangeName, OnDidChangeName)
IPC_MESSAGE_HANDLER(FrameHostMsg_DidAssignPageId, OnDidAssignPageId)
+ IPC_MESSAGE_HANDLER(FrameHostMsg_DidChangeSandboxFlags,
+ OnDidChangeSandboxFlags)
IPC_MESSAGE_HANDLER(FrameHostMsg_UpdateTitle, OnUpdateTitle)
IPC_MESSAGE_HANDLER(FrameHostMsg_UpdateEncoding, OnUpdateEncoding)
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_DispatchLoad, OnDispatchLoad)
IPC_MESSAGE_HANDLER(FrameHostMsg_TextSurroundingSelectionResponse,
OnTextSurroundingSelectionResponse)
IPC_MESSAGE_HANDLER(AccessibilityHostMsg_Events, OnAccessibilityEvents)
@@ -393,8 +410,16 @@ bool RenderFrameHostImpl::OnMessageReceived(const IPC::Message &msg) {
OnAccessibilityLocationChanges)
IPC_MESSAGE_HANDLER(AccessibilityHostMsg_FindInPageResult,
OnAccessibilityFindInPageResult)
- IPC_MESSAGE_HANDLER(PushMessagingHostMsg_RequestPermission,
- OnRequestPushPermission)
+ IPC_MESSAGE_HANDLER(AccessibilityHostMsg_SnapshotResponse,
+ OnAccessibilitySnapshotResponse)
+ IPC_MESSAGE_HANDLER(FrameHostMsg_ToggleFullscreen, OnToggleFullscreen)
+ // The following message is synthetic and doesn't come from RenderFrame, but
+ // from RenderProcessHost.
+ IPC_MESSAGE_HANDLER(FrameHostMsg_RenderProcessGone, OnRenderProcessGone)
+ IPC_MESSAGE_HANDLER(FrameHostMsg_DidStartLoading, OnDidStartLoading)
+ IPC_MESSAGE_HANDLER(FrameHostMsg_DidStopLoading, OnDidStopLoading)
+ IPC_MESSAGE_HANDLER(FrameHostMsg_DidChangeLoadProgress,
+ OnDidChangeLoadProgress)
#if defined(OS_MACOSX) || defined(OS_ANDROID)
IPC_MESSAGE_HANDLER(FrameHostMsg_ShowPopup, OnShowPopup)
IPC_MESSAGE_HANDLER(FrameHostMsg_HidePopup, OnHidePopup)
@@ -512,23 +537,27 @@ BrowserAccessibilityManager* RenderFrameHostImpl::AccessibilityGetChildFrame(
int accessibility_node_id) {
RenderFrameHostImpl* child_frame =
FrameAccessibility::GetInstance()->GetChild(this, accessibility_node_id);
- if (!child_frame)
- return NULL;
+ if (!child_frame || IsSameSiteInstance(child_frame))
+ return nullptr;
- // 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;
+ return child_frame->GetOrCreateBrowserAccessibilityManager();
+}
- // 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;
- }
+void RenderFrameHostImpl::AccessibilityGetAllChildFrames(
+ std::vector<BrowserAccessibilityManager*>* child_frames) {
+ std::vector<RenderFrameHostImpl*> child_frame_hosts;
+ FrameAccessibility::GetInstance()->GetAllChildFrames(
+ this, &child_frame_hosts);
+ for (size_t i = 0; i < child_frame_hosts.size(); ++i) {
+ RenderFrameHostImpl* child_frame_host = child_frame_hosts[i];
+ if (!child_frame_host || IsSameSiteInstance(child_frame_host))
+ continue;
- return child_frame->GetOrCreateBrowserAccessibilityManager();
+ BrowserAccessibilityManager* manager =
+ child_frame_host->GetOrCreateBrowserAccessibilityManager();
+ if (manager)
+ child_frames->push_back(manager);
+ }
}
BrowserAccessibility* RenderFrameHostImpl::AccessibilityGetParentFrame() {
@@ -556,6 +585,7 @@ BrowserAccessibility* RenderFrameHostImpl::AccessibilityGetParentFrame() {
}
bool RenderFrameHostImpl::CreateRenderFrame(int parent_routing_id,
+ int previous_sibling_routing_id,
int proxy_routing_id) {
TRACE_EVENT0("navigation", "RenderFrameHostImpl::CreateRenderFrame");
DCHECK(!IsRenderFrameLive()) << "Creating frame twice";
@@ -569,13 +599,48 @@ bool RenderFrameHostImpl::CreateRenderFrame(int parent_routing_id,
DCHECK(GetProcess()->HasConnection());
- Send(new FrameMsg_NewFrame(routing_id_, parent_routing_id, proxy_routing_id));
+ FrameMsg_NewFrame_Params params;
+ params.routing_id = routing_id_;
+ params.parent_routing_id = parent_routing_id;
+ params.proxy_routing_id = proxy_routing_id;
+ params.previous_sibling_routing_id = previous_sibling_routing_id;
+ params.replication_state = frame_tree_node()->current_replication_state();
+
+ if (render_widget_host_) {
+ params.widget_params.routing_id = render_widget_host_->GetRoutingID();
+ params.widget_params.surface_id = render_widget_host_->surface_id();
+ params.widget_params.hidden = render_widget_host_->is_hidden();
+ } else {
+ // MSG_ROUTING_NONE will prevent a new RenderWidget from being created in
+ // the renderer process.
+ params.widget_params.routing_id = MSG_ROUTING_NONE;
+ params.widget_params.surface_id = 0;
+ params.widget_params.hidden = true;
+ }
+
+ Send(new FrameMsg_NewFrame(params));
+
+ // The RenderWidgetHost takes ownership of its view. It is tied to the
+ // lifetime of the current RenderProcessHost for this RenderFrameHost.
+ if (render_widget_host_) {
+ RenderWidgetHostView* rwhv =
+ new RenderWidgetHostViewChildFrame(render_widget_host_);
+ rwhv->Hide();
+ }
+
+ if (proxy_routing_id != MSG_ROUTING_NONE) {
+ RenderFrameProxyHost* proxy = RenderFrameProxyHost::FromID(
+ GetProcess()->GetID(), proxy_routing_id);
+ // We have also created a RenderFrameProxy in FrameMsg_NewFrame above, so
+ // remember that.
+ proxy->set_render_frame_proxy_created(true);
+ }
// 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);
+ SetRenderFrameCreated(true);
return true;
}
@@ -594,6 +659,23 @@ bool RenderFrameHostImpl::IsRenderFrameLive() {
return is_live;
}
+void RenderFrameHostImpl::SetRenderFrameCreated(bool created) {
+ bool was_created = render_frame_created_;
+ render_frame_created_ = created;
+
+ // If the current status is different than the new status, the delegate
+ // needs to be notified.
+ if (delegate_ && (created != was_created)) {
+ if (created)
+ delegate_->RenderFrameCreated(this);
+ else
+ delegate_->RenderFrameDeleted(this);
+ }
+
+ if (created && render_widget_host_)
+ render_widget_host_->InitForFrame();
+}
+
void RenderFrameHostImpl::Init() {
GetProcess()->ResumeRequestsForView(routing_id_);
}
@@ -607,17 +689,26 @@ void RenderFrameHostImpl::OnAddMessageToConsole(
return;
// Pass through log level only on WebUI pages to limit console spew.
- int32 resolved_level =
- HasWebUIScheme(delegate_->GetMainFrameLastCommittedURL()) ? level : 0;
-
- if (resolved_level >= ::logging::GetMinLogLevel()) {
- logging::LogMessage("CONSOLE", line_no, resolved_level).stream() << "\"" <<
- message << "\", source: " << source_id << " (" << line_no << ")";
+ const bool is_web_ui =
+ HasWebUIScheme(delegate_->GetMainFrameLastCommittedURL());
+ const int32 resolved_level = is_web_ui ? level : ::logging::LOG_INFO;
+
+ // LogMessages can be persisted so this shouldn't be logged in incognito mode.
+ // This rule is not applied to WebUI pages, because source code of WebUI is a
+ // part of Chrome source code, and we want to treat messages from WebUI the
+ // same way as we treat log messages from native code.
+ if (::logging::GetMinLogLevel() <= resolved_level &&
+ (is_web_ui ||
+ !GetSiteInstance()->GetBrowserContext()->IsOffTheRecord())) {
+ logging::LogMessage("CONSOLE", line_no, resolved_level).stream()
+ << "\"" << message << "\", source: " << source_id << " (" << line_no
+ << ")";
}
}
void RenderFrameHostImpl::OnCreateChildFrame(int new_routing_id,
- const std::string& frame_name) {
+ const std::string& frame_name,
+ SandboxFlags sandbox_flags) {
// 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.
@@ -625,17 +716,15 @@ void RenderFrameHostImpl::OnCreateChildFrame(int new_routing_id,
if (rfh_state_ != RenderFrameHostImpl::STATE_DEFAULT)
return;
- RenderFrameHostImpl* new_frame = frame_tree_->AddFrame(
- frame_tree_node_, GetProcess()->GetID(), new_routing_id, frame_name);
+ RenderFrameHostImpl* new_frame =
+ frame_tree_->AddFrame(frame_tree_node_, GetProcess()->GetID(),
+ new_routing_id, frame_name, sandbox_flags);
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);
+ new_frame->SetRenderFrameCreated(true);
}
void RenderFrameHostImpl::OnDetach() {
@@ -646,19 +735,24 @@ void RenderFrameHostImpl::OnFrameFocused() {
frame_tree_->SetFocusedFrame(frame_tree_node_);
}
-void RenderFrameHostImpl::OnOpenURL(
- const FrameHostMsg_OpenURL_Params& params) {
- 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);
+void RenderFrameHostImpl::OnOpenURL(const FrameHostMsg_OpenURL_Params& params) {
+ OpenURL(params, GetSiteInstance());
}
-void RenderFrameHostImpl::OnDocumentOnLoadCompleted() {
+void RenderFrameHostImpl::OnDocumentOnLoadCompleted(
+ FrameMsg_UILoadMetricsReportType::Value report_type,
+ base::TimeTicks ui_timestamp) {
+ if (report_type == FrameMsg_UILoadMetricsReportType::REPORT_LINK) {
+ UMA_HISTOGRAM_CUSTOM_TIMES("Navigation.UI_OnLoadComplete.Link",
+ base::TimeTicks::Now() - ui_timestamp,
+ base::TimeDelta::FromMilliseconds(10),
+ base::TimeDelta::FromMinutes(10), 100);
+ } else if (report_type == FrameMsg_UILoadMetricsReportType::REPORT_INTENT) {
+ UMA_HISTOGRAM_CUSTOM_TIMES("Navigation.UI_OnLoadComplete.Intent",
+ base::TimeTicks::Now() - ui_timestamp,
+ base::TimeDelta::FromMilliseconds(10),
+ base::TimeDelta::FromMinutes(10), 100);
+ }
// This message is only sent for top-level frames. TODO(avi): when frame tree
// mirroring works correctly, add a check here to enforce it.
delegate_->DocumentOnLoadCompleted(this);
@@ -713,7 +807,7 @@ void RenderFrameHostImpl::OnDidCommitProvisionalLoad(const IPC::Message& msg) {
// old page will soon be stopped. Instead, treat this as a beforeunload ack
// to allow the pending navigation to continue.
if (is_waiting_for_beforeunload_ack_ &&
- unload_ack_is_for_cross_site_transition_ &&
+ unload_ack_is_for_navigation_ &&
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());
@@ -728,6 +822,22 @@ void RenderFrameHostImpl::OnDidCommitProvisionalLoad(const IPC::Message& msg) {
if (IsWaitingForUnloadACK())
return;
+ if (validated_params.report_type ==
+ FrameMsg_UILoadMetricsReportType::REPORT_LINK) {
+ UMA_HISTOGRAM_CUSTOM_TIMES(
+ "Navigation.UI_OnCommitProvisionalLoad.Link",
+ base::TimeTicks::Now() - validated_params.ui_timestamp,
+ base::TimeDelta::FromMilliseconds(10), base::TimeDelta::FromMinutes(10),
+ 100);
+ } else if (validated_params.report_type ==
+ FrameMsg_UILoadMetricsReportType::REPORT_INTENT) {
+ UMA_HISTOGRAM_CUSTOM_TIMES(
+ "Navigation.UI_OnCommitProvisionalLoad.Intent",
+ base::TimeTicks::Now() - validated_params.ui_timestamp,
+ base::TimeDelta::FromMilliseconds(10), base::TimeDelta::FromMinutes(10),
+ 100);
+ }
+
RenderProcessHost* process = GetProcess();
// Attempts to commit certain off-limits URL should be caught more strictly
@@ -736,9 +846,9 @@ void RenderFrameHostImpl::OnDidCommitProvisionalLoad(const IPC::Message& msg) {
if (!CanCommitURL(validated_params.url)) {
VLOG(1) << "Blocked URL " << validated_params.url.spec();
validated_params.url = GURL(url::kAboutBlankURL);
- RecordAction(base::UserMetricsAction("CanCommitURL_BlockedAndKilled"));
// Kills the process.
- process->ReceivedBadMessage();
+ bad_message::ReceivedBadMessage(process,
+ bad_message::RFH_CAN_COMMIT_URL_BLOCKED);
}
// Without this check, an evil renderer can trick the browser into creating
@@ -760,16 +870,51 @@ void RenderFrameHostImpl::OnDidCommitProvisionalLoad(const IPC::Message& msg) {
// filenames it can't access in a future session restore.
if (!render_view_host_->CanAccessFilesOfPageState(
validated_params.page_state)) {
- GetProcess()->ReceivedBadMessage();
+ bad_message::ReceivedBadMessage(
+ GetProcess(), bad_message::RFH_CAN_ACCESS_FILES_OF_PAGE_STATE);
return;
}
accessibility_reset_count_ = 0;
frame_tree_node()->navigator()->DidNavigate(this, validated_params);
+
+ // PlzNavigate
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation)) {
+ pending_commit_ = false;
+ }
+}
+
+void RenderFrameHostImpl::OnDidDropNavigation() {
+ // At the end of Navigate(), the FrameTreeNode's DidStartLoading is called to
+ // force the spinner to start, even if the renderer didn't yet begin the load.
+ // If it turns out that the renderer dropped the navigation, the spinner needs
+ // to be turned off.
+ frame_tree_node_->DidStopLoading();
}
RenderWidgetHostImpl* RenderFrameHostImpl::GetRenderWidgetHost() {
- return static_cast<RenderWidgetHostImpl*>(render_view_host_);
+ if (render_widget_host_)
+ return render_widget_host_;
+
+ // TODO(kenrb): When RenderViewHost no longer inherits RenderWidgetHost,
+ // we can remove this fallback. Currently it is only used for the main
+ // frame.
+ if (!GetParent())
+ return static_cast<RenderWidgetHostImpl*>(render_view_host_);
+
+ return nullptr;
+}
+
+RenderWidgetHostView* RenderFrameHostImpl::GetView() {
+ RenderFrameHostImpl* frame = this;
+ while (frame) {
+ if (frame->render_widget_host_)
+ return frame->render_widget_host_->GetView();
+ frame = static_cast<RenderFrameHostImpl*>(frame->GetParent());
+ }
+
+ return render_view_host_->GetView();
}
int RenderFrameHostImpl::GetEnabledBindings() {
@@ -801,7 +946,9 @@ void RenderFrameHostImpl::OnDeferredAfterResponseStarted(
delegate_->DidDeferAfterResponseStarted(transition_data);
}
-void RenderFrameHostImpl::SwapOut(RenderFrameProxyHost* proxy) {
+void RenderFrameHostImpl::SwapOut(
+ RenderFrameProxyHost* proxy,
+ bool is_loading) {
// 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
@@ -821,13 +968,17 @@ void RenderFrameHostImpl::SwapOut(RenderFrameProxyHost* proxy) {
// There may be no proxy if there are no active views in the process.
int proxy_routing_id = MSG_ROUTING_NONE;
+ FrameReplicationState replication_state;
if (proxy) {
set_render_frame_proxy_host(proxy);
proxy_routing_id = proxy->GetRoutingID();
+ replication_state = proxy->frame_tree_node()->current_replication_state();
}
- if (IsRenderFrameLive())
- Send(new FrameMsg_SwapOut(routing_id_, proxy_routing_id));
+ if (IsRenderFrameLive()) {
+ Send(new FrameMsg_SwapOut(routing_id_, proxy_routing_id, is_loading,
+ replication_state));
+ }
if (!GetParent())
delegate_->SwappedOut(this);
@@ -840,8 +991,6 @@ void RenderFrameHostImpl::OnBeforeUnloadACK(
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 OnDidCommitProvisionalLoad, in which case we
// can ignore this message.
@@ -903,17 +1052,36 @@ void RenderFrameHostImpl::OnBeforeUnloadACK(
}
// Resets beforeunload waiting state.
is_waiting_for_beforeunload_ack_ = false;
+ render_view_host_->decrement_in_flight_event_count();
+ render_view_host_->StopHangMonitorTimeout();
send_before_unload_start_time_ = base::TimeTicks();
- frame_tree_node_->render_manager()->OnBeforeUnloadACK(
- unload_ack_is_for_cross_site_transition_, proceed,
- before_unload_end_time);
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation)) {
+ // TODO(clamy): see if before_unload_end_time should be transmitted to the
+ // Navigator.
+ frame_tree_node_->navigator()->OnBeforeUnloadACK(
+ frame_tree_node_, proceed);
+ } else {
+ frame_tree_node_->render_manager()->OnBeforeUnloadACK(
+ unload_ack_is_for_navigation_, proceed,
+ before_unload_end_time);
+ }
// If canceled, notify the delegate to cancel its pending navigation entry.
if (!proceed)
render_view_host_->GetDelegate()->DidCancelLoading();
}
+bool RenderFrameHostImpl::IsWaitingForBeforeUnloadACK() const {
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation)) {
+ return is_waiting_for_beforeunload_ack_;
+ }
+ return frame_tree_node_->navigator()->IsWaitingForBeforeUnloadACK(
+ frame_tree_node_);
+}
+
bool RenderFrameHostImpl::IsWaitingForUnloadACK() const {
return render_view_host_->is_waiting_for_close_ack_ ||
rfh_state_ == STATE_PENDING_SWAP_OUT;
@@ -923,6 +1091,49 @@ void RenderFrameHostImpl::OnSwapOutACK() {
OnSwappedOut();
}
+void RenderFrameHostImpl::OnRenderProcessGone(int status, int exit_code) {
+ if (frame_tree_node_->IsMainFrame()) {
+ // Keep the termination status so we can get at it later when we
+ // need to know why it died.
+ render_view_host_->render_view_termination_status_ =
+ static_cast<base::TerminationStatus>(status);
+ }
+
+ // Reset frame tree state associated with this process. This must happen
+ // before RenderViewTerminated because observers expect the subframes of any
+ // affected frames to be cleared first.
+ // Note: When a RenderFrameHost is swapped out there is a different one
+ // which is the current host. In this case, the FrameTreeNode state must
+ // not be reset.
+ if (!is_swapped_out())
+ frame_tree_node_->ResetForNewProcess();
+
+ // Reset state for the current RenderFrameHost once the FrameTreeNode has been
+ // reset.
+ SetRenderFrameCreated(false);
+ InvalidateMojoConnection();
+
+ // Execute any pending AX tree snapshot callbacks with an empty response,
+ // since we're never going to get a response from this renderer.
+ for (const auto& iter : ax_tree_snapshot_callbacks_)
+ iter.second.Run(ui::AXTreeUpdate());
+ ax_tree_snapshot_callbacks_.clear();
+
+ if (frame_tree_node_->IsMainFrame()) {
+ // RenderViewHost/RenderWidgetHost needs to reset some stuff.
+ render_view_host_->RendererExited(
+ render_view_host_->render_view_termination_status_, exit_code);
+
+ render_view_host_->delegate_->RenderViewTerminated(
+ render_view_host_, static_cast<base::TerminationStatus>(status),
+ exit_code);
+ }
+
+ // Note: don't add any more code at this point in the function because
+ // |this| may be deleted. Any additional cleanup should happen before
+ // the last block of code here.
+}
+
void RenderFrameHostImpl::OnSwappedOut() {
// Ignore spurious swap out ack.
if (rfh_state_ != STATE_PENDING_SWAP_OUT)
@@ -975,6 +1186,16 @@ void RenderFrameHostImpl::OnJavaScriptExecuteResponse(
}
}
+void RenderFrameHostImpl::OnVisualStateResponse(uint64 id) {
+ auto it = visual_state_callbacks_.find(id);
+ if (it != visual_state_callbacks_.end()) {
+ it->second.Run(true);
+ visual_state_callbacks_.erase(it);
+ } else {
+ NOTREACHED() << "Received script response for unknown request";
+ }
+}
+
void RenderFrameHostImpl::OnRunJavaScriptMessage(
const base::string16& message,
const base::string16& default_prompt,
@@ -1001,51 +1222,6 @@ void RenderFrameHostImpl::OnRunBeforeUnloadConfirm(
delegate_->RunBeforeUnloadConfirm(this, message, is_reload, reply_msg);
}
-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,
- 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))
- return;
-
- cancel_notification_callbacks_[notification_id].Run();
- cancel_notification_callbacks_.erase(notification_id);
-}
-
void RenderFrameHostImpl::OnTextSurroundingSelectionResponse(
const base::string16& content,
size_t start_offset,
@@ -1064,12 +1240,48 @@ void RenderFrameHostImpl::OnDidDisownOpener() {
delegate_->DidDisownOpener(this);
}
+void RenderFrameHostImpl::OnDidChangeName(const std::string& name) {
+ frame_tree_node()->SetFrameName(name);
+ delegate_->DidChangeName(this, name);
+}
+
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::OnDidChangeSandboxFlags(int32 frame_routing_id,
+ SandboxFlags flags) {
+ FrameTree* frame_tree = frame_tree_node()->frame_tree();
+ FrameTreeNode* child =
+ frame_tree->FindByRoutingID(GetProcess()->GetID(), frame_routing_id);
+ if (!child)
+ return;
+
+ // Ensure that a frame can only update sandbox flags for its immediate
+ // children. If this is not the case, the renderer is considered malicious
+ // and is killed.
+ if (child->parent() != frame_tree_node()) {
+ bad_message::ReceivedBadMessage(GetProcess(),
+ bad_message::RFH_SANDBOX_FLAGS);
+ return;
+ }
+
+ child->set_sandbox_flags(flags);
+
+ // Notify the RenderFrame if it lives in a different process from its
+ // parent. The frame's proxies in other processes also need to learn about
+ // the updated sandbox flags, but these notifications are sent later in
+ // RenderFrameHostManager::CommitPendingSandboxFlags(), when the frame
+ // navigates and the new sandbox flags take effect.
+ RenderFrameHost* child_rfh = child->current_frame_host();
+ if (child_rfh->GetSiteInstance() != GetSiteInstance()) {
+ child_rfh->Send(
+ new FrameMsg_DidUpdateSandboxFlags(child_rfh->GetRoutingID(), flags));
+ }
+}
+
void RenderFrameHostImpl::OnUpdateTitle(
const base::string16& title,
blink::WebTextDirection title_direction) {
@@ -1092,12 +1304,29 @@ void RenderFrameHostImpl::OnUpdateEncoding(const std::string& encoding_name) {
}
void RenderFrameHostImpl::OnBeginNavigation(
- const FrameHostMsg_BeginNavigation_Params& params,
- const CommonNavigationParams& common_params) {
- CHECK(CommandLine::ForCurrentProcess()->HasSwitch(
+ const CommonNavigationParams& common_params,
+ const BeginNavigationParams& begin_params,
+ scoped_refptr<ResourceRequestBody> body) {
+ CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableBrowserSideNavigation));
frame_tree_node()->navigator()->OnBeginNavigation(
- frame_tree_node(), params, common_params);
+ frame_tree_node(), common_params, begin_params, body);
+}
+
+void RenderFrameHostImpl::OnDispatchLoad() {
+ CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess));
+ // Only frames with an out-of-process parent frame should be sending this
+ // message.
+ RenderFrameProxyHost* proxy =
+ frame_tree_node()->render_manager()->GetProxyToParent();
+ if (!proxy) {
+ bad_message::ReceivedBadMessage(GetProcess(),
+ bad_message::RFH_NO_PROXY_TO_PARENT);
+ return;
+ }
+
+ proxy->Send(new FrameMsg_DispatchLoad(proxy->GetRoutingID()));
}
void RenderFrameHostImpl::OnAccessibilityEvents(
@@ -1217,20 +1446,66 @@ void RenderFrameHostImpl::OnAccessibilityFindInPageResult(
}
}
-void RenderFrameHostImpl::OnRequestPushPermission(int request_id,
- bool user_gesture) {
- if (!delegate()->GetAsWebContents())
+void RenderFrameHostImpl::OnAccessibilitySnapshotResponse(
+ int callback_id,
+ const ui::AXTreeUpdate& snapshot) {
+ const auto& it = ax_tree_snapshot_callbacks_.find(callback_id);
+ if (it != ax_tree_snapshot_callbacks_.end()) {
+ it->second.Run(snapshot);
+ ax_tree_snapshot_callbacks_.erase(it);
+ } else {
+ NOTREACHED() << "Received AX tree snapshot response for unknown id";
+ }
+}
+
+void RenderFrameHostImpl::OnToggleFullscreen(bool enter_fullscreen) {
+ if (enter_fullscreen)
+ delegate_->EnterFullscreenMode(GetLastCommittedURL().GetOrigin());
+ else
+ delegate_->ExitFullscreenMode();
+
+ // The previous call might change the fullscreen state. We need to make sure
+ // the renderer is aware of that, which is done via the resize message.
+ render_view_host_->WasResized();
+}
+
+void RenderFrameHostImpl::OnDidStartLoading(bool to_different_document) {
+ // Any main frame load to a new document should reset the load since it will
+ // replace the current page and any frames.
+ if (to_different_document && !GetParent())
+ is_loading_ = false;
+
+ // This method should never be called when the frame is loading.
+ // Unfortunately, it can happen if a history navigation happens during a
+ // BeforeUnload or Unload event.
+ // TODO(fdegans): Change this to a DCHECK after LoadEventProgress has been
+ // refactored in Blink. See crbug.com/466089
+ if (is_loading_) {
+ LOG(WARNING) << "OnDidStartLoading was called twice.";
+ return;
+ }
+
+ frame_tree_node_->DidStartLoading(to_different_document);
+ is_loading_ = true;
+}
+
+void RenderFrameHostImpl::OnDidStopLoading() {
+ // This method should never be called when the frame is not loading.
+ // Unfortunately, it can happen if a history navigation happens during a
+ // BeforeUnload or Unload event.
+ // TODO(fdegans): Change this to a DCHECK after LoadEventProgress has been
+ // refactored in Blink. See crbug.com/466089
+ if (!is_loading_) {
+ LOG(WARNING) << "OnDidStopLoading was called twice.";
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));
+ is_loading_ = false;
+ frame_tree_node_->DidStopLoading();
+}
+
+void RenderFrameHostImpl::OnDidChangeLoadProgress(double load_progress) {
+ frame_tree_node_->DidChangeLoadProgress(load_progress);
}
#if defined(OS_MACOSX) || defined(OS_ANDROID)
@@ -1258,6 +1533,14 @@ void RenderFrameHostImpl::OnHidePopup() {
}
#endif
+#if defined(ENABLE_MEDIA_MOJO_RENDERER)
+static void CreateMediaRendererService(
+ mojo::InterfaceRequest<mojo::MediaRenderer> request) {
+ media::MojoRendererService* service = new media::MojoRendererService();
+ mojo::BindToRequest(service, &request);
+}
+#endif
+
void RenderFrameHostImpl::RegisterMojoServices() {
GeolocationServiceContext* geolocation_service_context =
delegate_ ? delegate_->GetGeolocationServiceContext() : NULL;
@@ -1271,6 +1554,25 @@ void RenderFrameHostImpl::RegisterMojoServices() {
base::Bind(&RenderFrameHostImpl::DidUseGeolocationPermission,
base::Unretained(this))));
}
+
+ if (!permission_service_context_)
+ permission_service_context_.reset(new PermissionServiceContext(this));
+
+ GetServiceRegistry()->AddService<PermissionService>(
+ base::Bind(&PermissionServiceContext::CreateService,
+ base::Unretained(permission_service_context_.get())));
+
+ GetServiceRegistry()->AddService<presentation::PresentationService>(
+ base::Bind(&PresentationServiceImpl::CreateMojoService,
+ base::Unretained(this)));
+
+#if defined(ENABLE_MEDIA_MOJO_RENDERER)
+ GetServiceRegistry()->AddService<mojo::MediaRenderer>(
+ base::Bind(&CreateMediaRendererService));
+#endif
+
+ GetContentClient()->browser()->OverrideRenderFrameMojoServices(
+ GetServiceRegistry(), this);
}
void RenderFrameHostImpl::SetState(RenderFrameHostImplState rfh_state) {
@@ -1301,7 +1603,11 @@ void RenderFrameHostImpl::SetState(RenderFrameHostImplState rfh_state) {
rfh_state == STATE_SWAPPED_OUT ||
rfh_state_ == STATE_DEFAULT ||
rfh_state_ == STATE_SWAPPED_OUT) {
- is_waiting_for_beforeunload_ack_ = false;
+ if (is_waiting_for_beforeunload_ack_) {
+ is_waiting_for_beforeunload_ack_ = false;
+ render_view_host_->decrement_in_flight_event_count();
+ render_view_host_->StopHangMonitorTimeout();
+ }
send_before_unload_start_time_ = base::TimeTicks();
render_view_host_->is_waiting_for_close_ack_ = false;
}
@@ -1317,21 +1623,13 @@ bool RenderFrameHostImpl::CanCommitURL(const GURL& url) {
return GetContentClient()->browser()->CanCommitURL(GetProcess(), url);
}
-void RenderFrameHostImpl::Navigate(const FrameMsg_Navigate_Params& params) {
+void RenderFrameHostImpl::Navigate(
+ const CommonNavigationParams& common_params,
+ const StartNavigationParams& start_params,
+ const RequestNavigationParams& request_params) {
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.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.
- ChildProcessSecurityPolicyImpl::GetInstance()->GrantRequestURL(
- GetProcess()->GetID(), params.base_url_for_data_url);
- }
- }
+
+ UpdatePermissionsForNavigation(common_params, request_params);
// Only send the message if we aren't suspended at the start of a cross-site
// request.
@@ -1341,58 +1639,70 @@ void RenderFrameHostImpl::Navigate(const FrameMsg_Navigate_Params& params) {
// second navigation occurs, RenderFrameHostManager will cancel this pending
// RFH and create a new pending RFH.
DCHECK(!suspended_nav_params_.get());
- suspended_nav_params_.reset(new FrameMsg_Navigate_Params(params));
+ suspended_nav_params_.reset(
+ new NavigationParams(common_params, start_params, request_params));
} else {
// Get back to a clean state, in case we start a new navigation without
// completing a RFH swap or unload handler.
SetState(RenderFrameHostImpl::STATE_DEFAULT);
- Send(new FrameMsg_Navigate(routing_id_, params));
+ Send(new FrameMsg_Navigate(routing_id_, common_params, start_params,
+ request_params));
}
- // Force the throbber to start. We do this because Blink's "started
- // loading" message will be received asynchronously from the UI of the
- // browser. But we want to keep the throbber in sync with what's happening
- // in the UI. For example, we want to start throbbing immediately when the
- // user naivgates even if the renderer is delayed. There is also an issue
- // with the throbber starting because the WebUI (which controls whether the
- // favicon is displayed) happens synchronously. If the start loading
- // messages was asynchronous, then the default favicon would flash in.
+ // Force the throbber to start. This is done because Blink's "started loading"
+ // message will be received asynchronously from the UI of the browser. But the
+ // throbber needs to be kept in sync with what's happening in the UI. For
+ // example, the throbber will start immediately when the user navigates even
+ // if the renderer is delayed. There is also an issue with the throbber
+ // starting because the WebUI (which controls whether the favicon is
+ // displayed) happens synchronously. If the start loading messages was
+ // asynchronous, then the default favicon would flash in.
//
- // Blink doesn't send throb notifications for JavaScript URLs, so we
- // don't want to either.
- if (!params.common_params.url.SchemeIs(url::kJavaScriptScheme))
- delegate_->DidStartLoading(this, true);
+ // Blink doesn't send throb notifications for JavaScript URLs, so it is not
+ // done here either.
+ if (!common_params.url.SchemeIs(url::kJavaScriptScheme))
+ frame_tree_node_->DidStartLoading(true);
}
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;
- Navigate(params);
+ CommonNavigationParams common_params(
+ url, Referrer(), ui::PAGE_TRANSITION_LINK, FrameMsg_Navigate_Type::NORMAL,
+ true, base::TimeTicks::Now(), FrameMsg_UILoadMetricsReportType::NO_REPORT,
+ GURL(), GURL());
+ Navigate(common_params, StartNavigationParams(), RequestNavigationParams());
}
-void RenderFrameHostImpl::OpenURL(const FrameHostMsg_OpenURL_Params& params) {
- OnOpenURL(params);
+void RenderFrameHostImpl::OpenURL(const FrameHostMsg_OpenURL_Params& params,
+ SiteInstance* source_site_instance) {
+ GURL validated_url(params.url);
+ GetProcess()->FilterURL(false, &validated_url);
+
+ TRACE_EVENT1("navigation", "RenderFrameHostImpl::OpenURL", "url",
+ validated_url.possibly_invalid_spec());
+ frame_tree_node_->navigator()->RequestOpenURL(
+ this, validated_url, source_site_instance, params.referrer,
+ params.disposition, params.should_replace_current_entry,
+ params.user_gesture);
}
void RenderFrameHostImpl::Stop() {
Send(new FrameMsg_Stop(routing_id_));
}
-void RenderFrameHostImpl::DispatchBeforeUnload(bool for_cross_site_transition) {
+void RenderFrameHostImpl::DispatchBeforeUnload(bool for_navigation) {
// 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.
- frame_tree_node_->render_manager()->OnBeforeUnloadACK(
- for_cross_site_transition, true, base::TimeTicks::Now());
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation)) {
+ frame_tree_node_->navigator()->OnBeforeUnloadACK(
+ frame_tree_node_, true);
+ } else {
+ frame_tree_node_->render_manager()->OnBeforeUnloadACK(
+ for_navigation, true, base::TimeTicks::Now());
+ }
return;
}
TRACE_EVENT_ASYNC_BEGIN0(
@@ -1408,13 +1718,13 @@ void RenderFrameHostImpl::DispatchBeforeUnload(bool for_cross_site_transition) {
// (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.
- unload_ack_is_for_cross_site_transition_ =
- unload_ack_is_for_cross_site_transition_ && for_cross_site_transition;
+ unload_ack_is_for_navigation_ =
+ unload_ack_is_for_navigation_ && for_navigation;
} else {
// Start the hang monitor in case the renderer hangs in the beforeunload
// handler.
is_waiting_for_beforeunload_ack_ = true;
- unload_ack_is_for_cross_site_transition_ = for_cross_site_transition;
+ unload_ack_is_for_navigation_ = for_navigation;
// 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();
@@ -1447,9 +1757,10 @@ void RenderFrameHostImpl::JavaScriptDialogClosed(
// leave the current page. In this case, use the regular timeout value used
// during the (before)unload handling.
if (is_waiting) {
- render_view_host_->StartHangMonitorTimeout(TimeDelta::FromMilliseconds(
- success ? RenderViewHostImpl::kUnloadTimeoutMS
- : render_view_host_->hung_renderer_delay_ms_));
+ render_view_host_->StartHangMonitorTimeout(
+ success
+ ? TimeDelta::FromMilliseconds(RenderViewHostImpl::kUnloadTimeoutMS)
+ : render_view_host_->hung_renderer_delay_);
}
FrameHostMsg_RunJavaScriptMessage::WriteReplyParams(reply_msg,
@@ -1466,28 +1777,45 @@ void RenderFrameHostImpl::JavaScriptDialogClosed(
render_view_host_->delegate_->RendererUnresponsive(render_view_host_);
}
-void RenderFrameHostImpl::NotificationClosed(int notification_id) {
- cancel_notification_callbacks_.erase(notification_id);
-}
-
// 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));
+ const RequestNavigationParams& request_params) {
+ DCHECK((response && body.get()) ||
+ !NavigationRequest::ShouldMakeNetworkRequest(common_params.url));
+ UpdatePermissionsForNavigation(common_params, request_params);
+
+ // Get back to a clean state, in case we start a new navigation without
+ // completing a RFH swap or unload handler.
+ SetState(RenderFrameHostImpl::STATE_DEFAULT);
+
+ const GURL body_url = body.get() ? body->GetURL() : GURL();
+ const ResourceResponseHead head = response ?
+ response->head : ResourceResponseHead();
+ Send(new FrameMsg_CommitNavigation(routing_id_, head, body_url, common_params,
+ request_params));
// TODO(clamy): Check if we should start the throbber for non javascript urls
// here.
// TODO(clamy): Release the stream handle once the renderer has finished
// reading it.
stream_handle_ = body.Pass();
+ pending_commit_ = true;
+}
+
+void RenderFrameHostImpl::FailedNavigation(
+ const CommonNavigationParams& common_params,
+ const RequestNavigationParams& request_params,
+ bool has_stale_copy_in_cache,
+ int error_code) {
+ // Get back to a clean state, in case a new navigation started without
+ // completing a RFH swap or unload handler.
+ SetState(RenderFrameHostImpl::STATE_DEFAULT);
+
+ Send(new FrameMsg_FailedNavigation(routing_id_, common_params, request_params,
+ has_stale_copy_in_cache, error_code));
}
void RenderFrameHostImpl::SetUpMojoIfNeeded() {
@@ -1501,15 +1829,20 @@ void RenderFrameHostImpl::SetUpMojoIfNeeded() {
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());
+
+ mojo::ServiceProviderPtr exposed_services;
+ service_registry_->Bind(GetProxy(&exposed_services));
+
+ mojo::ServiceProviderPtr services;
+ setup->ExchangeServiceProviders(routing_id_, GetProxy(&services),
+ exposed_services.Pass());
+ service_registry_->BindRemoteServiceProvider(services.Pass());
#if defined(OS_ANDROID)
service_registry_android_.reset(
new ServiceRegistryAndroid(service_registry_.get()));
+ ServiceRegistrarAndroid::RegisterFrameHostServices(
+ service_registry_android_.get());
#endif
}
@@ -1523,20 +1856,14 @@ void RenderFrameHostImpl::InvalidateMojoConnection() {
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));
+bool RenderFrameHostImpl::IsFocused() {
+ // TODO(mlamouri,kenrb): call GetRenderWidgetHost() directly when it stops
+ // returning nullptr in some cases. See https://crbug.com/455245.
+ return RenderWidgetHostImpl::From(
+ GetView()->GetRenderWidgetHost())->is_focused() &&
+ frame_tree_->GetFocusedFrame() &&
+ (frame_tree_->GetFocusedFrame() == frame_tree_node() ||
+ frame_tree_->GetFocusedFrame()->IsDescendantOf(frame_tree_node()));
}
void RenderFrameHostImpl::UpdateCrossProcessIframeAccessibility(
@@ -1550,6 +1877,7 @@ void RenderFrameHostImpl::UpdateCrossProcessIframeAccessibility(
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());
@@ -1569,15 +1897,37 @@ void RenderFrameHostImpl::UpdateGuestFrameAccessibility(
}
}
+bool RenderFrameHostImpl::IsSameSiteInstance(
+ RenderFrameHostImpl* other_render_frame_host) {
+ // As a sanity check, make sure the frame belongs to the same BrowserContext.
+ CHECK_EQ(GetSiteInstance()->GetBrowserContext(),
+ other_render_frame_host->GetSiteInstance()->GetBrowserContext());
+ return GetSiteInstance() == other_render_frame_host->GetSiteInstance();
+}
+
void RenderFrameHostImpl::SetAccessibilityMode(AccessibilityMode mode) {
Send(new FrameMsg_SetAccessibilityMode(routing_id_, mode));
}
+void RenderFrameHostImpl::RequestAXTreeSnapshot(
+ AXTreeSnapshotCallback callback) {
+ static int next_id = 1;
+ int callback_id = next_id++;
+ Send(new AccessibilityMsg_SnapshotTree(routing_id_, callback_id));
+ ax_tree_snapshot_callbacks_.insert(std::make_pair(callback_id, callback));
+}
+
void RenderFrameHostImpl::SetAccessibilityCallbackForTesting(
const base::Callback<void(ui::AXEvent, int)>& callback) {
accessibility_testing_callback_ = callback;
}
+void RenderFrameHostImpl::SetTextTrackSettings(
+ const FrameMsg_TextTrackSettings_Params& params) {
+ DCHECK(!GetParent());
+ Send(new FrameMsg_SetTextTrackSettings(routing_id_, params));
+}
+
const ui::AXTree* RenderFrameHostImpl::GetAXTreeForTesting() {
return ax_tree_for_testing_.get();
}
@@ -1610,6 +1960,14 @@ void RenderFrameHostImpl::ActivateFindInPageResultForAccessibility(
}
}
+void RenderFrameHostImpl::InsertVisualStateCallback(
+ const VisualStateCallback& callback) {
+ static uint64 next_id = 1;
+ uint64 key = next_id++;
+ Send(new FrameMsg_VisualStateRequest(routing_id_, key));
+ visual_state_callbacks_.insert(std::make_pair(key, callback));
+}
+
#if defined(OS_WIN)
void RenderFrameHostImpl::SetParentNativeViewAccessible(
@@ -1682,9 +2040,12 @@ void RenderFrameHostImpl::SetNavigationsSuspended(
SetState(RenderFrameHostImpl::STATE_DEFAULT);
DCHECK(!proceed_time.is_null());
- suspended_nav_params_->commit_params.browser_navigation_start =
+ suspended_nav_params_->request_params.browser_navigation_start =
proceed_time;
- Send(new FrameMsg_Navigate(routing_id_, *suspended_nav_params_));
+ Send(new FrameMsg_Navigate(routing_id_,
+ suspended_nav_params_->common_params,
+ suspended_nav_params_->start_params,
+ suspended_nav_params_->request_params));
suspended_nav_params_.reset();
}
}
@@ -1700,12 +2061,42 @@ void RenderFrameHostImpl::CancelSuspendedNavigations() {
}
void RenderFrameHostImpl::DidUseGeolocationPermission() {
- RenderFrameHost* top_frame = frame_tree_node()->frame_tree()->GetMainFrame();
- GetContentClient()->browser()->RegisterPermissionUsage(
- PERMISSION_GEOLOCATION,
- delegate_->GetAsWebContents(),
+ PermissionManager* permission_manager =
+ GetSiteInstance()->GetBrowserContext()->GetPermissionManager();
+ if (!permission_manager)
+ return;
+
+ permission_manager->RegisterPermissionUsage(
+ PermissionType::GEOLOCATION,
GetLastCommittedURL().GetOrigin(),
- top_frame->GetLastCommittedURL().GetOrigin());
+ frame_tree_node()->frame_tree()->GetMainFrame()
+ ->GetLastCommittedURL().GetOrigin());
+}
+
+void RenderFrameHostImpl::UpdatePermissionsForNavigation(
+ const CommonNavigationParams& common_params,
+ const RequestNavigationParams& request_params) {
+ // 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(), common_params.url);
+ if (common_params.url.SchemeIs(url::kDataScheme) &&
+ common_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.
+ ChildProcessSecurityPolicyImpl::GetInstance()->GrantRequestURL(
+ GetProcess()->GetID(), common_params.base_url_for_data_url);
+ }
+ }
+
+ // We may be returning to an existing NavigationEntry that had been granted
+ // file access. If this is a different process, we will need to grant the
+ // access again. The files listed in the page state are validated when they
+ // are received from the renderer to prevent abuse.
+ if (request_params.page_state.IsValid()) {
+ render_view_host_->GrantFileAccessFromPageState(request_params.page_state);
+ }
}
} // 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 b1c470312f4..8af7d7a6911 100644
--- a/chromium/content/browser/frame_host/render_frame_host_impl.h
+++ b/chromium/content/browser/frame_host/render_frame_host_impl.h
@@ -18,7 +18,10 @@
#include "content/browser/site_instance_impl.h"
#include "content/common/accessibility_mode_enums.h"
#include "content/common/content_export.h"
+#include "content/common/frame_message_enums.h"
+#include "content/common/frame_replication_state.h"
#include "content/common/mojo/service_registry_impl.h"
+#include "content/common/navigation_params.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/common/javascript_message_type.h"
#include "net/http/http_response_headers.h"
@@ -36,8 +39,7 @@ struct AccessibilityHostMsg_FindInPageResultParams;
struct AccessibilityHostMsg_LocationChangeParams;
struct FrameHostMsg_DidFailProvisionalLoadWithError_Params;
struct FrameHostMsg_OpenURL_Params;
-struct FrameHostMsg_BeginNavigation_Params;
-struct FrameMsg_Navigate_Params;
+struct FrameMsg_TextTrackSettings_Params;
#if defined(OS_MACOSX) || defined(OS_ANDROID)
struct FrameHostMsg_ShowPopup_Params;
#endif
@@ -53,26 +55,45 @@ class CrossProcessFrameConnector;
class CrossSiteTransferringRequest;
class FrameTree;
class FrameTreeNode;
+class PermissionServiceContext;
class RenderFrameHostDelegate;
class RenderFrameProxyHost;
class RenderProcessHost;
class RenderViewHostImpl;
+class RenderWidgetHostDelegate;
class RenderWidgetHostImpl;
+class RenderWidgetHostView;
+class ResourceRequestBody;
class StreamHandle;
class TimeoutMonitor;
-struct CommitNavigationParams;
-struct CommonNavigationParams;
struct ContextMenuParams;
struct GlobalRequestID;
struct Referrer;
struct ResourceResponse;
-struct ShowDesktopNotificationHostMsgParams;
struct TransitionLayerData;
+// Flag arguments for RenderFrameHost creation.
+enum CreateRenderFrameFlags {
+ // The RFH will be initially placed on the swapped out hosts list.
+ CREATE_RF_SWAPPED_OUT = 1 << 0,
+ // The new RenderFrame is being created for a navigation of the
+ // top-level frame.
+ CREATE_RF_FOR_MAIN_FRAME_NAVIGATION = 1 << 1,
+ // The RenderFrame is initially hidden.
+ CREATE_RF_HIDDEN = 1 << 2,
+ // The RenderFrameHost will have a new RenderWidgetHost created and
+ // attached to it. This is used when the RenderFrameHost is in a different
+ // process from its parent frame.
+ CREATE_RF_NEEDS_RENDER_WIDGET_HOST = 1 << 3
+};
+
class CONTENT_EXPORT RenderFrameHostImpl
: public RenderFrameHost,
public BrowserAccessibilityDelegate {
public:
+ typedef base::Callback<void(const ui::AXTreeUpdate&)>
+ AXTreeSnapshotCallback;
+
// Keeps track of the state of the RenderFrameHostImpl, particularly with
// respect to swap out.
enum RenderFrameHostImplState {
@@ -114,10 +135,18 @@ class CONTENT_EXPORT RenderFrameHostImpl
void ExecuteJavaScript(const base::string16& javascript) override;
void ExecuteJavaScript(const base::string16& javascript,
const JavaScriptResultCallback& callback) override;
- void ExecuteJavaScriptForTests(const base::string16& javascript) override;
+ void ExecuteJavaScriptWithUserGestureForTests(
+ const base::string16& javascript) override;
+ void ExecuteJavaScriptInIsolatedWorld(
+ const base::string16& javascript,
+ const JavaScriptResultCallback& callback,
+ int world_id) override;
+ void ActivateFindInPageResultForAccessibility(int request_id) override;
RenderViewHost* GetRenderViewHost() override;
ServiceRegistry* GetServiceRegistry() override;
- void ActivateFindInPageResultForAccessibility(int request_id) override;
+ blink::WebPageVisibilityState GetVisibilityState() override;
+ void InsertVisualStateCallback(
+ const VisualStateCallback& callback) override;
// IPC::Sender
bool Send(IPC::Message* msg) override;
@@ -149,11 +178,15 @@ class CONTENT_EXPORT RenderFrameHostImpl
gfx::NativeViewAccessible AccessibilityGetNativeViewAccessible() override;
BrowserAccessibilityManager* AccessibilityGetChildFrame(
int accessibility_node_id) override;
+ void AccessibilityGetAllChildFrames(
+ std::vector<BrowserAccessibilityManager*>* child_frames) 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);
+ bool CreateRenderFrame(int parent_routing_id,
+ int previous_sibling_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.
@@ -162,9 +195,7 @@ class CONTENT_EXPORT RenderFrameHostImpl
// 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;
- }
+ void SetRenderFrameCreated(bool created);
// Called for renderer-created windows to resume requests from this frame,
// after they are blocked in RenderWidgetHelper::CreateNewWindow.
@@ -172,15 +203,28 @@ class CONTENT_EXPORT RenderFrameHostImpl
int routing_id() const { return routing_id_; }
void OnCreateChildFrame(int new_routing_id,
- const std::string& frame_name);
+ const std::string& frame_name,
+ SandboxFlags sandbox_flags);
RenderViewHostImpl* render_view_host() { return render_view_host_; }
RenderFrameHostDelegate* delegate() { return delegate_; }
FrameTreeNode* frame_tree_node() { return frame_tree_node_; }
- // TODO(nasko): The RenderWidgetHost will be owned by RenderFrameHost in
- // the future, so update this accessor to return the right pointer.
+
+ // Returns this RenderFrameHost's loading state. This method is only used by
+ // FrameTreeNode. The proper way to check whether a frame is loading is to
+ // call FrameTreeNode::IsLoading.
+ bool is_loading() const { return is_loading_; }
+
+ // This returns the RenderFrameHost's owned RenderWidgetHost if it has one,
+ // or else it returns nullptr.
+ // If the RenderFrameHost is the page's main frame, this returns instead a
+ // pointer to the RenderViewHost (which inherits RenderWidgetHost).
RenderWidgetHostImpl* GetRenderWidgetHost();
+ // This returns the RenderWidgetHostView that can be used to control
+ // focus and visibility for this frame.
+ RenderWidgetHostView* GetView();
+
// This function is called when this is a swapped out RenderFrameHost that
// lives in the same process as the parent frame. The
// |cross_process_frame_connector| allows the non-swapped-out
@@ -223,15 +267,17 @@ class CONTENT_EXPORT RenderFrameHostImpl
// Tells the renderer that this RenderFrame is being swapped out for one in a
// 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);
-
- bool is_waiting_for_beforeunload_ack() const {
- return is_waiting_for_beforeunload_ack_;
- }
+ // RenderFrameProxy to replace the RenderFrame and set it to |is_loading|
+ // state. 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, bool is_loading);
+
+ // Whether an ongoing navigation is waiting for a BeforeUnload ACK from the
+ // RenderFrame. Currently this only happens in cross-site navigations.
+ // PlzNavigate: this happens in every browser-initiated navigation that is not
+ // same-page.
+ bool IsWaitingForBeforeUnloadACK() const;
// Whether the RFH is waiting for an unload ACK from the renderer.
bool IsWaitingForUnloadACK() const;
@@ -254,15 +300,21 @@ class CONTENT_EXPORT RenderFrameHostImpl
// 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.
- void Navigate(const FrameMsg_Navigate_Params& params);
+ void Navigate(const CommonNavigationParams& common_params,
+ const StartNavigationParams& start_params,
+ const RequestNavigationParams& request_params);
// 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);
+ // Treat this prospective navigation as though it originated from the frame.
+ // Used, e.g., for a navigation request that originated from a RemoteFrame.
+ // |source_site_instance| is the SiteInstance of the frame that initiated the
+ // navigation.
+ // TODO(creis): Remove this method and have RenderFrameProxyHost call
+ // RequestOpenURL with its FrameTreeNode.
+ void OpenURL(const FrameHostMsg_OpenURL_Params& params,
+ SiteInstance* source_site_instance);
// Stop the load in progress.
void Stop();
@@ -291,10 +343,11 @@ class CONTENT_EXPORT RenderFrameHostImpl
// 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
+ // Runs the beforeunload handler for this frame. |for_navigation| 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);
+ // PlzNavigate: this call happens on all browser-initiated navigations.
+ void DispatchBeforeUnload(bool for_navigation);
// Set the frame's opener to null in the renderer process in response to an
// action in another renderer process.
@@ -311,9 +364,6 @@ class CONTENT_EXPORT RenderFrameHostImpl
const base::string16& user_input,
bool dialog_was_suppressed);
- // 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();
@@ -321,6 +371,10 @@ class CONTENT_EXPORT RenderFrameHostImpl
// Send a message to the renderer process to change the accessibility mode.
void SetAccessibilityMode(AccessibilityMode AccessibilityMode);
+ // Request a one-time snapshot of the accessibility tree without changing
+ // the accessibility mode.
+ void RequestAXTreeSnapshot(AXTreeSnapshotCallback callback);
+
// 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
@@ -328,6 +382,9 @@ class CONTENT_EXPORT RenderFrameHostImpl
void SetAccessibilityCallbackForTesting(
const base::Callback<void(ui::AXEvent, int)>& callback);
+ // Send a message to the render process to change text track style settings.
+ void SetTextTrackSettings(const FrameMsg_TextTrackSettings_Params& params);
+
// Returns a snapshot of the accessibility tree received from the
// renderer as of the last time an accessibility notification was
// received.
@@ -365,7 +422,15 @@ class CONTENT_EXPORT RenderFrameHostImpl
void CommitNavigation(ResourceResponse* response,
scoped_ptr<StreamHandle> body,
const CommonNavigationParams& common_params,
- const CommitNavigationParams& commit_params);
+ const RequestNavigationParams& request_params);
+
+ // PlzNavigate
+ // Indicates that a navigation failed and that this RenderFrame should display
+ // an error page.
+ void FailedNavigation(const CommonNavigationParams& common_params,
+ const RequestNavigationParams& request_params,
+ bool has_stale_copy_in_cache,
+ int error_code);
// Sets up the Mojo connection between this instance and its associated render
// frame if it has not yet been set up.
@@ -375,18 +440,26 @@ class CONTENT_EXPORT RenderFrameHostImpl
// this instance and its associated render frame.
void InvalidateMojoConnection();
+ // Returns whether the frame is focused. A frame is considered focused when it
+ // is the parent chain of the focused frame within the frame tree. In
+ // addition, its associated RenderWidgetHost has to be focused.
+ bool IsFocused();
+
protected:
friend class RenderFrameHostFactory;
+ // |flags| is a combination of CreateRenderFrameFlags.
// TODO(nasko): Remove dependency on RenderViewHost here. RenderProcessHost
// should be the abstraction needed here, but we need RenderViewHost to pass
// into WebContentsObserver::FrameDetached for now.
- RenderFrameHostImpl(RenderViewHostImpl* render_view_host,
+ RenderFrameHostImpl(SiteInstance* site_instance,
+ RenderViewHostImpl* render_view_host,
RenderFrameHostDelegate* delegate,
+ RenderWidgetHostDelegate* rwh_delegate,
FrameTree* frame_tree,
FrameTreeNode* frame_tree_node,
int routing_id,
- bool is_swapped_out);
+ int flags);
private:
friend class TestRenderFrameHost;
@@ -402,7 +475,9 @@ class CONTENT_EXPORT RenderFrameHostImpl
void OnDetach();
void OnFrameFocused();
void OnOpenURL(const FrameHostMsg_OpenURL_Params& params);
- void OnDocumentOnLoadCompleted();
+ void OnDocumentOnLoadCompleted(
+ FrameMsg_UILoadMetricsReportType::Value report_type,
+ base::TimeTicks ui_timestamp);
void OnDidStartProvisionalLoadForFrame(const GURL& url,
bool is_transition_navigation);
void OnDidFailProvisionalLoadWithError(
@@ -412,13 +487,16 @@ class CONTENT_EXPORT RenderFrameHostImpl
int error_code,
const base::string16& error_description);
void OnDidCommitProvisionalLoad(const IPC::Message& msg);
+ void OnDidDropNavigation();
void OnBeforeUnloadACK(
bool proceed,
const base::TimeTicks& renderer_before_unload_start_time,
const base::TimeTicks& renderer_before_unload_end_time);
void OnSwapOutACK();
+ void OnRenderProcessGone(int status, int error_code);
void OnContextMenu(const ContextMenuParams& params);
void OnJavaScriptExecuteResponse(int id, const base::ListValue& result);
+ void OnVisualStateResponse(uint64 id);
void OnRunJavaScriptMessage(const base::string16& message,
const base::string16& default_prompt,
const GURL& frame_url,
@@ -428,23 +506,21 @@ class CONTENT_EXPORT RenderFrameHostImpl
const base::string16& message,
bool is_reload,
IPC::Message* reply_msg);
- void OnRequestPlatformNotificationPermission(const GURL& origin,
- int request_id);
- void OnShowDesktopNotification(
- int notification_id,
- const ShowDesktopNotificationHostMsgParams& params);
- void OnCancelDesktopNotification(int notification_id);
void OnTextSurroundingSelectionResponse(const base::string16& content,
size_t start_offset,
size_t end_offset);
void OnDidAccessInitialDocument();
void OnDidDisownOpener();
+ void OnDidChangeName(const std::string& name);
void OnDidAssignPageId(int32 page_id);
+ void OnDidChangeSandboxFlags(int32 frame_routing_id, SandboxFlags flags);
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 OnBeginNavigation(const CommonNavigationParams& common_params,
+ const BeginNavigationParams& begin_params,
+ scoped_refptr<ResourceRequestBody> body);
+ void OnDispatchLoad();
void OnAccessibilityEvents(
const std::vector<AccessibilityHostMsg_EventParams>& params,
int reset_token);
@@ -452,7 +528,12 @@ class CONTENT_EXPORT RenderFrameHostImpl
const std::vector<AccessibilityHostMsg_LocationChangeParams>& params);
void OnAccessibilityFindInPageResult(
const AccessibilityHostMsg_FindInPageResultParams& params);
- void OnRequestPushPermission(int request_id, bool user_gesture);
+ void OnAccessibilitySnapshotResponse(int callback_id,
+ const ui::AXTreeUpdate& snapshot);
+ void OnToggleFullscreen(bool enter_fullscreen);
+ void OnDidStartLoading(bool to_different_document);
+ void OnDidStopLoading();
+ void OnDidChangeLoadProgress(double load_progress);
#if defined(OS_MACOSX) || defined(OS_ANDROID)
void OnShowPopup(const FrameHostMsg_ShowPopup_Params& params);
@@ -471,10 +552,6 @@ class CONTENT_EXPORT RenderFrameHostImpl
// it will be used to kill processes that commit unauthorized URLs.
bool CanCommitURL(const GURL& url);
- 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.
@@ -487,9 +564,18 @@ class CONTENT_EXPORT RenderFrameHostImpl
void UpdateGuestFrameAccessibility(
const std::map<int32, int>& node_to_browser_plugin_instance_id_map);
+ // Asserts that the given RenderFrameHostImpl is part of the same browser
+ // context (and crashes if not), then returns whether the given frame is
+ // part of the same site instance.
+ bool IsSameSiteInstance(RenderFrameHostImpl* other_render_frame_host);
+
// Informs the content client that geolocation permissions were used.
void DidUseGeolocationPermission();
+ void UpdatePermissionsForNavigation(
+ const CommonNavigationParams& common_params,
+ const RequestNavigationParams& request_params);
+
// For now, RenderFrameHosts indirectly keep RenderViewHosts alive via a
// refcount that calls Shutdown when it reaches zero. This allows each
// RenderFrameHostManager to just care about RenderFrameHosts, while ensuring
@@ -500,6 +586,17 @@ class CONTENT_EXPORT RenderFrameHostImpl
RenderFrameHostDelegate* delegate_;
+ // The SiteInstance associated with this RenderFrameHost. All content drawn
+ // in this RenderFrameHost is part of this SiteInstance. Cannot change over
+ // time.
+ scoped_refptr<SiteInstanceImpl> site_instance_;
+
+ // The renderer process this RenderFrameHost is associated with. It is
+ // equivalent to the result of site_instance_->GetProcess(), but that
+ // method has the side effect of creating the process if it doesn't exist.
+ // Cache a pointer to avoid unnecessary process creation.
+ RenderProcessHost* process_;
+
// |cross_process_frame_connector_| passes messages from an out-of-process
// child frame to the parent process for compositing.
//
@@ -529,9 +626,15 @@ class CONTENT_EXPORT RenderFrameHostImpl
// The mapping of pending JavaScript calls created by
// ExecuteJavaScript and their corresponding callbacks.
std::map<int, JavaScriptResultCallback> javascript_callbacks_;
+ std::map<uint64, VisualStateCallback> visual_state_callbacks_;
- // Map from notification_id to a callback to cancel them.
- std::map<int, base::Closure> cancel_notification_callbacks_;
+ // RenderFrameHosts that need management of the rendering and input events
+ // for their frame subtrees require RenderWidgetHosts. This typically
+ // means frames that are rendered in different processes from their parent
+ // frames.
+ // TODO(kenrb): Later this will also be used on the top-level frame, when
+ // RenderFrameHost owns its RenderViewHost.
+ RenderWidgetHostImpl* render_widget_host_;
int routing_id_;
@@ -549,12 +652,13 @@ class CONTENT_EXPORT RenderFrameHostImpl
// 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_;
+ // Holds the parameters for a suspended navigation. This can only happen 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.
+ // PlzNavigate: unused as navigations are never suspended.
+ scoped_ptr<NavigationParams> suspended_nav_params_;
// When the last BeforeUnload message was sent.
base::TimeTicks send_before_unload_start_time_;
@@ -571,8 +675,19 @@ class CONTENT_EXPORT RenderFrameHostImpl
// 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_;
+ // the case of a navigation ( = true). Currently only cross-site navigations
+ // require a beforeUnload/unload ACK.
+ // PlzNavigate: all navigations require a beforeUnload ACK.
+ bool unload_ack_is_for_navigation_;
+
+ // Indicates whether this RenderFrameHost is in the process of loading a
+ // document or not.
+ bool is_loading_;
+
+ // PlzNavigate
+ // Used to track whether a commit is expected in this frame. Only used in
+ // tests.
+ bool pending_commit_;
// 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
@@ -597,6 +712,10 @@ class CONTENT_EXPORT RenderFrameHostImpl
// we don't keep trying to reset forever.
int accessibility_reset_count_;
+ // The mapping from callback id to corresponding callback for pending
+ // accessibility tree snapshot calls created by RequestAXTreeSnapshot.
+ std::map<int, AXTreeSnapshotCallback> ax_tree_snapshot_callbacks_;
+
// Callback when an event is received, for testing.
base::Callback<void(ui::AXEvent, int)> accessibility_testing_callback_;
// The most recently received accessibility tree - for testing only.
@@ -609,6 +728,9 @@ class CONTENT_EXPORT RenderFrameHostImpl
// response once it has started.
scoped_ptr<StreamHandle> stream_handle_;
+ // Context shared for each PermissionService instance created for this RFH.
+ scoped_ptr<PermissionServiceContext> permission_service_context_;
+
// NOTE: This must be the last member.
base::WeakPtrFactory<RenderFrameHostImpl> weak_ptr_factory_;
diff --git a/chromium/content/browser/frame_host/render_frame_host_impl_browsertest.cc b/chromium/content/browser/frame_host/render_frame_host_impl_browsertest.cc
new file mode 100644
index 00000000000..33826a07558
--- /dev/null
+++ b/chromium/content/browser/frame_host/render_frame_host_impl_browsertest.cc
@@ -0,0 +1,192 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/frame_host/render_frame_host_impl.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/content_client.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/test_content_browser_client.h"
+
+namespace content {
+
+namespace {
+
+RenderFrameHostImpl* ToRFHI(RenderFrameHost* render_frame_host) {
+ return static_cast<RenderFrameHostImpl*>(render_frame_host);
+}
+
+// Implementation of ContentBrowserClient that overrides
+// OverridePageVisibilityState() and allows consumers to set a value.
+class PrerenderTestContentBrowserClient : public TestContentBrowserClient {
+ public:
+ PrerenderTestContentBrowserClient()
+ : override_enabled_(false),
+ visibility_override_(blink::WebPageVisibilityStateVisible)
+ {}
+ ~PrerenderTestContentBrowserClient() override {}
+
+ void EnableVisibilityOverride(
+ blink::WebPageVisibilityState visibility_override) {
+ override_enabled_ = true;
+ visibility_override_ = visibility_override;
+ }
+
+ void OverridePageVisibilityState(
+ RenderFrameHost* render_frame_host,
+ blink::WebPageVisibilityState* visibility_state) override {
+ if (override_enabled_)
+ *visibility_state = visibility_override_;
+ }
+
+ private:
+ bool override_enabled_;
+ blink::WebPageVisibilityState visibility_override_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrerenderTestContentBrowserClient);
+};
+
+} // anonymous namespace
+
+using RenderFrameHostImplBrowserTest = ContentBrowserTest;
+
+// Test that when creating a new window, the main frame is correctly focused.
+// flaky http://crbug.com/452631
+IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest,
+ DISABLED_IsFocused_AtLoad) {
+ EXPECT_TRUE(
+ NavigateToURL(shell(), GetTestUrl("render_frame_host", "focus.html")));
+
+ // The main frame should be focused.
+ WebContents* web_contents = shell()->web_contents();
+ EXPECT_TRUE(ToRFHI(web_contents->GetMainFrame())->IsFocused());
+}
+
+// Test that if the content changes the focused frame, it is correctly exposed.
+// Disabled to to flaky failures: crbug.com/452631
+IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest,
+ DISABLED_IsFocused_Change) {
+ EXPECT_TRUE(
+ NavigateToURL(shell(), GetTestUrl("render_frame_host", "focus.html")));
+
+ WebContents* web_contents = shell()->web_contents();
+
+ std::string frames[2] = { "frame1", "frame2" };
+ for (const std::string& frame : frames) {
+ ExecuteScriptAndGetValue(
+ web_contents->GetMainFrame(), "focus" + frame + "()");
+
+ // The main frame is not the focused frame in the frame tree but the main
+ // frame is focused per RFHI rules because one of its descendant is focused.
+ EXPECT_NE(web_contents->GetMainFrame(), web_contents->GetFocusedFrame());
+ EXPECT_TRUE(ToRFHI(web_contents->GetFocusedFrame())->IsFocused());
+ EXPECT_TRUE(ToRFHI(web_contents->GetMainFrame())->IsFocused());
+ EXPECT_EQ(frame, web_contents->GetFocusedFrame()->GetFrameName());
+ }
+}
+
+// Tests focus behavior when the focused frame is removed from the frame tree.
+IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest, RemoveFocusedFrame) {
+ EXPECT_TRUE(
+ NavigateToURL(shell(), GetTestUrl("render_frame_host", "focus.html")));
+
+ WebContentsImpl* web_contents =
+ static_cast<WebContentsImpl*>(shell()->web_contents());
+
+ ExecuteScriptAndGetValue(web_contents->GetMainFrame(), "focusframe4()");
+
+ // TODO(nick,mlamouri): Add calls to RFHI::IsFocused here once they're not
+ // flaky. See http://crbug.com/452631, http://crbug.com/464033, etc.
+ EXPECT_NE(web_contents->GetMainFrame(), web_contents->GetFocusedFrame());
+ EXPECT_EQ("frame4", web_contents->GetFocusedFrame()->GetFrameName());
+ EXPECT_EQ("frame3",
+ web_contents->GetFocusedFrame()->GetParent()->GetFrameName());
+ EXPECT_NE(-1, web_contents->GetFrameTree()->focused_frame_tree_node_id_);
+
+ ExecuteScriptAndGetValue(web_contents->GetMainFrame(), "detachframe(3)");
+ EXPECT_EQ(nullptr, web_contents->GetFocusedFrame());
+ EXPECT_EQ(-1, web_contents->GetFrameTree()->focused_frame_tree_node_id_);
+
+ ExecuteScriptAndGetValue(web_contents->GetMainFrame(), "focusframe2()");
+ EXPECT_NE(nullptr, web_contents->GetFocusedFrame());
+ EXPECT_NE(web_contents->GetMainFrame(), web_contents->GetFocusedFrame());
+ EXPECT_NE(-1, web_contents->GetFrameTree()->focused_frame_tree_node_id_);
+
+ ExecuteScriptAndGetValue(web_contents->GetMainFrame(), "detachframe(2)");
+ EXPECT_EQ(nullptr, web_contents->GetFocusedFrame());
+ EXPECT_EQ(-1, web_contents->GetFrameTree()->focused_frame_tree_node_id_);
+}
+
+// Test that even if the frame is focused in the frame tree but its
+// RenderWidgetHost is not focused, it is not considered as focused.
+// flaky http://crbug.com/452631
+IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest,
+ DISABLED_IsFocused_Widget) {
+ EXPECT_TRUE(
+ NavigateToURL(shell(), GetTestUrl("render_frame_host", "focus.html")));
+ WebContents* web_contents = shell()->web_contents();
+
+ // A second window is created and navigated. It takes the focus.
+ Shell* new_shell = CreateBrowser();
+ EXPECT_TRUE(
+ NavigateToURL(new_shell, GetTestUrl("render_frame_host", "focus.html")));
+ EXPECT_TRUE(ToRFHI(new_shell->web_contents()->GetMainFrame())->IsFocused());
+
+ // The first opened window is no longer focused. The main frame is still the
+ // focused frame in the frame tree but as far as RFH is concerned, the frame
+ // is not focused.
+ EXPECT_EQ(web_contents->GetMainFrame(), web_contents->GetFocusedFrame());
+
+#if defined(OS_MACOSX)
+ EXPECT_TRUE(ToRFHI(web_contents->GetMainFrame())->IsFocused());
+#else
+ EXPECT_FALSE(ToRFHI(web_contents->GetMainFrame())->IsFocused());
+#endif
+}
+
+// Test that a frame is visible/hidden depending on its WebContents visibility
+// state.
+// Flaky on Mac. http://crbug.com/467670
+#if defined(OS_MACOSX)
+#define MAYBE_GetVisibilityState_Basic DISABLED_GetVisibilityState_Basic
+#else
+#define MAYBE_GetVisibilityState_Basic GetVisibilityState_Basic
+#endif
+IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest,
+ MAYBE_GetVisibilityState_Basic) {
+ EXPECT_TRUE(NavigateToURL(shell(), GURL("data:text/html,foo")));
+ WebContents* web_contents = shell()->web_contents();
+
+ EXPECT_EQ(blink::WebPageVisibilityStateVisible,
+ web_contents->GetMainFrame()->GetVisibilityState());
+
+ web_contents->WasHidden();
+ EXPECT_EQ(blink::WebPageVisibilityStateHidden,
+ web_contents->GetMainFrame()->GetVisibilityState());
+}
+
+// Test that a frame visibility can be overridden by the ContentBrowserClient.
+IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest,
+ GetVisibilityState_Override) {
+ EXPECT_TRUE(NavigateToURL(shell(), GURL("data:text/html,foo")));
+ WebContents* web_contents = shell()->web_contents();
+
+ PrerenderTestContentBrowserClient new_client;
+ ContentBrowserClient* old_client = SetBrowserClientForTesting(&new_client);
+
+ EXPECT_EQ(blink::WebPageVisibilityStateVisible,
+ web_contents->GetMainFrame()->GetVisibilityState());
+
+ new_client.EnableVisibilityOverride(blink::WebPageVisibilityStatePrerender);
+ EXPECT_EQ(blink::WebPageVisibilityStatePrerender,
+ web_contents->GetMainFrame()->GetVisibilityState());
+
+ SetBrowserClientForTesting(old_client);
+}
+
+} // namespace content
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 49b9495e32d..46428b9297b 100644
--- a/chromium/content/browser/frame_host/render_frame_host_manager.cc
+++ b/chromium/content/browser/frame_host/render_frame_host_manager.cc
@@ -7,16 +7,17 @@
#include <utility>
#include "base/command_line.h"
-#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/stl_util.h"
+#include "base/trace_event/trace_event.h"
#include "content/browser/child_process_security_policy_impl.h"
-#include "content/browser/devtools/render_view_devtools_agent_host.h"
+#include "content/browser/devtools/render_frame_devtools_agent_host.h"
#include "content/browser/frame_host/cross_site_transferring_request.h"
#include "content/browser/frame_host/debug_urls.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/frame_host/navigation_request.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"
@@ -56,24 +57,41 @@ RenderFrameHostManager::RenderFrameHostManager(
Delegate* delegate)
: frame_tree_node_(frame_tree_node),
delegate_(delegate),
- cross_navigation_pending_(false),
render_frame_delegate_(render_frame_delegate),
render_view_delegate_(render_view_delegate),
render_widget_delegate_(render_widget_delegate),
- interstitial_page_(NULL),
+ interstitial_page_(nullptr),
+ should_reuse_web_ui_(false),
weak_factory_(this) {
DCHECK(frame_tree_node_);
}
RenderFrameHostManager::~RenderFrameHostManager() {
- if (pending_render_frame_host_)
- CancelPending();
+ if (pending_render_frame_host_) {
+ scoped_ptr<RenderFrameHostImpl> relic = UnsetPendingRenderFrameHost();
+ ShutdownProxiesIfLastActiveFrameInSiteInstance(relic.get());
+ }
- // We should always have a current RenderFrameHost except in some tests.
- SetRenderFrameHost(scoped_ptr<RenderFrameHostImpl>());
+ if (speculative_render_frame_host_) {
+ scoped_ptr<RenderFrameHostImpl> relic = UnsetSpeculativeRenderFrameHost();
+ ShutdownProxiesIfLastActiveFrameInSiteInstance(relic.get());
+ }
+
+ ShutdownProxiesIfLastActiveFrameInSiteInstance(render_frame_host_.get());
- // Delete any swapped out RenderFrameHosts.
+ // Delete any RenderFrameProxyHosts and swapped out RenderFrameHosts.
+ // It is important to delete those prior to deleting the current
+ // RenderFrameHost, since the CrossProcessFrameConnector (owned by
+ // RenderFrameProxyHost) points to the RenderWidgetHostView associated with
+ // the current RenderFrameHost and uses it during its destructor.
STLDeleteValues(&proxy_hosts_);
+
+ // Release the WebUI prior to resetting the current RenderFrameHost, as the
+ // WebUI accesses the RenderFrameHost during cleanup.
+ web_ui_.reset();
+
+ // We should always have a current RenderFrameHost except in some tests.
+ SetRenderFrameHost(scoped_ptr<RenderFrameHostImpl>());
}
void RenderFrameHostManager::Init(BrowserContext* browser_context,
@@ -86,11 +104,17 @@ void RenderFrameHostManager::Init(BrowserContext* browser_context,
if (!site_instance)
site_instance = SiteInstance::Create(browser_context);
- SetRenderFrameHost(CreateRenderFrameHost(site_instance,
- view_routing_id,
- frame_routing_id,
- false,
- delegate_->IsHidden()));
+ int flags = delegate_->IsHidden() ? CREATE_RF_HIDDEN : 0;
+ SetRenderFrameHost(CreateRenderFrameHost(site_instance, view_routing_id,
+ frame_routing_id, flags));
+
+ // Notify the delegate of the creation of the current RenderFrameHost.
+ // Do this only for subframes, as the main frame case is taken care of by
+ // WebContentsImpl::Init.
+ if (!frame_tree_node_->IsMainFrame()) {
+ delegate_->NotifySwappedFromRenderManager(
+ nullptr, render_frame_host_.get(), false);
+ }
// Keep track of renderer processes as they start to shut down or are
// crashed/killed.
@@ -115,9 +139,9 @@ RenderViewHostImpl* RenderFrameHostManager::pending_render_view_host() const {
RenderWidgetHostView* RenderFrameHostManager::GetRenderWidgetHostView() const {
if (interstitial_page_)
return interstitial_page_->GetView();
- if (!render_frame_host_)
- return NULL;
- return render_frame_host_->render_view_host()->GetView();
+ if (render_frame_host_)
+ return render_frame_host_->GetView();
+ return nullptr;
}
RenderFrameProxyHost* RenderFrameHostManager::GetProxyToParent() {
@@ -136,23 +160,25 @@ RenderFrameProxyHost* RenderFrameHostManager::GetProxyToParent() {
return iter->second;
}
-void RenderFrameHostManager::SetPendingWebUI(const GURL& url,
- int bindings) {
- pending_web_ui_.reset(
- delegate_->CreateWebUIForRenderManager(url));
+void RenderFrameHostManager::SetPendingWebUI(const GURL& url, int bindings) {
+ pending_web_ui_ = CreateWebUI(url, bindings);
pending_and_current_web_ui_.reset();
+}
+
+scoped_ptr<WebUIImpl> RenderFrameHostManager::CreateWebUI(const GURL& url,
+ int bindings) {
+ scoped_ptr<WebUIImpl> new_web_ui(delegate_->CreateWebUIForRenderManager(url));
// If we have assigned (zero or more) bindings to this NavigationEntry in the
// past, make sure we're not granting it different bindings than it had
// before. If so, note it and don't give it any bindings, to avoid a
// potential privilege escalation.
- if (pending_web_ui_.get() &&
- bindings != NavigationEntryImpl::kInvalidBindings &&
- pending_web_ui_->GetBindings() != bindings) {
- RecordAction(
- base::UserMetricsAction("ProcessSwapBindingsMismatch_RVHM"));
- pending_web_ui_.reset();
+ if (new_web_ui && bindings != NavigationEntryImpl::kInvalidBindings &&
+ new_web_ui->GetBindings() != bindings) {
+ RecordAction(base::UserMetricsAction("ProcessSwapBindingsMismatch_RVHM"));
+ return nullptr;
}
+ return new_web_ui.Pass();
}
RenderFrameHostImpl* RenderFrameHostManager::Navigate(
@@ -161,12 +187,10 @@ RenderFrameHostImpl* 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.GetURL(),
- entry.site_instance(),
+ entry.GetURL(), entry.source_site_instance(), entry.site_instance(),
entry.GetTransitionType(),
entry.restore_type() != NavigationEntryImpl::RESTORE_NONE,
- entry.IsViewSourceMode(),
- entry.transferred_global_request_id(),
+ 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.
@@ -207,14 +231,18 @@ RenderFrameHostImpl* RenderFrameHostManager::Navigate(
// Now that we've created a new renderer, be sure to hide it if it isn't
// our primary one. Otherwise, we might crash if we try to call Show()
// on it later.
- 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();
+ if (dest_render_frame_host != render_frame_host_) {
+ if (dest_render_frame_host->GetView())
+ dest_render_frame_host->GetView()->Hide();
} else {
- // Notify here as we won't be calling CommitPending (which does the
- // notify).
- delegate_->NotifySwappedFromRenderManager(
- NULL, render_frame_host_.get(), frame_tree_node_->IsMainFrame());
+ // TODO(nasko): This is a very ugly hack. The Chrome extensions process
+ // manager still uses NotificationService and expects to see a
+ // RenderViewHost changed notification after WebContents and
+ // RenderFrameHostManager are completely initialized. This should be
+ // removed once the process manager moves away from NotificationService.
+ // See https://crbug.com/462682.
+ delegate_->NotifyMainFrameSwappedFromRenderManager(
+ nullptr, render_frame_host_->render_view_host());
}
}
@@ -233,9 +261,10 @@ RenderFrameHostImpl* RenderFrameHostManager::Navigate(
void RenderFrameHostManager::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_) {
+ // If we are navigating cross-process, we should stop the pending renderers.
+ // This will lead to a DidFailProvisionalLoad, which will properly destroy
+ // them.
+ if (pending_render_frame_host_) {
pending_render_frame_host_->Send(new FrameMsg_Stop(
pending_render_frame_host_->GetRoutingID()));
}
@@ -253,7 +282,7 @@ bool RenderFrameHostManager::ShouldCloseTabOnUnresponsiveRenderer() {
// 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_ ||
+ if (!pending_render_frame_host_ ||
render_frame_host_->render_view_host()->is_waiting_for_close_ack())
return true;
@@ -266,9 +295,9 @@ bool RenderFrameHostManager::ShouldCloseTabOnUnresponsiveRenderer() {
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
+ // cross-process navigation, proceed with the navigation. (This assumes that
// the pending RenderFrameHost is still responsive.)
- if (render_frame_host_->is_waiting_for_beforeunload_ack()) {
+ if (render_frame_host_->IsWaitingForBeforeUnloadACK()) {
// 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
@@ -288,12 +317,14 @@ void RenderFrameHostManager::OnBeforeUnloadACK(
bool proceed,
const base::TimeTicks& proceed_time) {
if (for_cross_site_transition) {
- // Ignore if we're not in a cross-site navigation.
- if (!cross_navigation_pending_)
+ DCHECK(!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation));
+ // Ignore if we're not in a cross-process navigation.
+ if (!pending_render_frame_host_)
return;
if (proceed) {
- // Ok to unload the current page, so proceed with the cross-site
+ // Ok to unload the current page, so proceed with the cross-process
// navigation. Note that if navigations are not currently suspended, it
// might be because the renderer was deemed unresponsive and this call was
// already made by ShouldCloseTabOnUnresponsiveRenderer. In that case, it
@@ -306,10 +337,9 @@ void RenderFrameHostManager::OnBeforeUnloadACK(
} else {
// Current page says to cancel.
CancelPending();
- cross_navigation_pending_ = false;
}
} else {
- // Non-cross site transition means closing the entire tab.
+ // Non-cross-process transition means closing the entire tab.
bool proceed_to_fire_unload;
delegate_->BeforeUnloadFiredFromRenderManager(proceed, proceed_time,
&proceed_to_fire_unload);
@@ -320,10 +350,16 @@ void RenderFrameHostManager::OnBeforeUnloadACK(
// close in the current RFH, we'll lose the tab close.
if (pending_render_frame_host_) {
CancelPending();
- cross_navigation_pending_ = false;
}
- // This is not a cross-site navigation, the tab is being closed.
+ // PlzNavigate: clean up the speculative RenderFrameHost if there is one.
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation) &&
+ speculative_render_frame_host_) {
+ CleanUpNavigation();
+ }
+
+ // This is not a cross-process navigation; the tab is being closed.
render_frame_host_->render_view_host()->ClosePage();
}
}
@@ -340,7 +376,7 @@ void RenderFrameHostManager::OnCrossSiteResponse(
// 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());
+ CHECK(cross_site_transferring_request);
// 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
@@ -378,15 +414,9 @@ void RenderFrameHostManager::OnCrossSiteResponse(
// 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);
+ pending_render_frame_host, transfer_url, nullptr, 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.
@@ -396,13 +426,13 @@ void RenderFrameHostManager::OnCrossSiteResponse(
void RenderFrameHostManager::OnDeferredAfterResponseStarted(
const GlobalRequestID& global_request_id,
RenderFrameHostImpl* pending_render_frame_host) {
- DCHECK(!response_started_id_.get());
+ DCHECK(!response_started_id_);
response_started_id_.reset(new GlobalRequestID(global_request_id));
}
void RenderFrameHostManager::ResumeResponseDeferredAtStart() {
- DCHECK(response_started_id_.get());
+ DCHECK(response_started_id_);
RenderProcessHostImpl* process =
static_cast<RenderProcessHostImpl*>(render_frame_host_->GetProcess());
@@ -418,28 +448,47 @@ void RenderFrameHostManager::ClearNavigationTransitionData() {
}
void RenderFrameHostManager::DidNavigateFrame(
- RenderFrameHostImpl* render_frame_host) {
- if (!cross_navigation_pending_) {
- DCHECK(!pending_render_frame_host_);
+ RenderFrameHostImpl* render_frame_host,
+ bool was_caused_by_user_gesture) {
+ CommitPendingIfNecessary(render_frame_host, was_caused_by_user_gesture);
+
+ // Make sure any dynamic changes to this frame's sandbox flags that were made
+ // prior to navigation take effect.
+ CommitPendingSandboxFlags();
+}
+
+void RenderFrameHostManager::CommitPendingIfNecessary(
+ RenderFrameHostImpl* render_frame_host,
+ bool was_caused_by_user_gesture) {
+ if (!pending_render_frame_host_ && !speculative_render_frame_host_) {
+ DCHECK_IMPLIES(should_reuse_web_ui_, web_ui_);
// We should only hear this from our current renderer.
DCHECK_EQ(render_frame_host_, render_frame_host);
// Even when there is no pending RVH, there may be a pending Web UI.
- if (pending_web_ui())
+ if (pending_web_ui() || speculative_web_ui_)
CommitPending();
return;
}
- if (render_frame_host == pending_render_frame_host_) {
- // The pending cross-site navigation completed, so show the renderer.
+ if (render_frame_host == pending_render_frame_host_ ||
+ render_frame_host == speculative_render_frame_host_) {
+ // The pending cross-process navigation completed, so show the renderer.
CommitPending();
- cross_navigation_pending_ = false;
} else if (render_frame_host == render_frame_host_) {
- // A navigation in the original page has taken place. Cancel the pending
- // one.
- CancelPending();
- cross_navigation_pending_ = false;
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation)) {
+ CleanUpNavigation();
+ } else {
+ if (was_caused_by_user_gesture) {
+ // A navigation in the original page has taken place. Cancel the
+ // pending one. Only do it for user gesture originated navigations to
+ // prevent page doing any shenanigans to prevent user from navigating.
+ // See https://code.google.com/p/chromium/issues/detail?id=75195
+ CancelPending();
+ }
+ }
} else {
// No one else should be sending us DidNavigate in this state.
DCHECK(false);
@@ -467,17 +516,49 @@ void RenderFrameHostManager::DidDisownOpener(
}
}
+void RenderFrameHostManager::CommitPendingSandboxFlags() {
+ // Return early if there were no pending sandbox flags updates.
+ if (!frame_tree_node_->CommitPendingSandboxFlags())
+ return;
+
+ // Sandbox flags updates can only happen when the frame has a parent.
+ CHECK(frame_tree_node_->parent());
+
+ // Notify all of the frame's proxies about updated sandbox flags, excluding
+ // the parent process since it already knows the latest flags.
+ SiteInstance* parent_site_instance =
+ frame_tree_node_->parent()->current_frame_host()->GetSiteInstance();
+ for (const auto& pair : proxy_hosts_) {
+ if (pair.second->GetSiteInstance() != parent_site_instance) {
+ pair.second->Send(new FrameMsg_DidUpdateSandboxFlags(
+ pair.second->GetRoutingID(),
+ frame_tree_node_->current_replication_state().sandbox_flags));
+ }
+ }
+}
+
void RenderFrameHostManager::RendererProcessClosing(
RenderProcessHost* render_process_host) {
// Remove any swapped out RVHs from this process, so that we don't try to
// swap them back in while the process is exiting. Start by finding them,
// since there could be more than one.
std::list<int> ids_to_remove;
+ // Do not remove proxies in the dead process that still have active frame
+ // count though, we just reset them to be uninitialized.
+ std::list<int> ids_to_keep;
for (RenderFrameProxyHostMap::iterator iter = proxy_hosts_.begin();
iter != proxy_hosts_.end();
++iter) {
- if (iter->second->GetProcess() == render_process_host)
+ RenderFrameProxyHost* proxy = iter->second;
+ if (proxy->GetProcess() != render_process_host)
+ continue;
+
+ if (static_cast<SiteInstanceImpl*>(proxy->GetSiteInstance())
+ ->active_frame_count() >= 1U) {
+ ids_to_keep.push_back(iter->first);
+ } else {
ids_to_remove.push_back(iter->first);
+ }
}
// Now delete them.
@@ -486,6 +567,14 @@ void RenderFrameHostManager::RendererProcessClosing(
proxy_hosts_.erase(ids_to_remove.back());
ids_to_remove.pop_back();
}
+
+ while (!ids_to_keep.empty()) {
+ frame_tree_node_->frame_tree()->ForEach(
+ base::Bind(
+ &RenderFrameHostManager::ResetProxiesInSiteInstance,
+ ids_to_keep.back()));
+ ids_to_keep.pop_back();
+ }
}
void RenderFrameHostManager::SwapOutOldFrame(
@@ -509,7 +598,7 @@ void RenderFrameHostManager::SwapOutOldFrame(
int32 old_site_instance_id =
old_render_frame_host->GetSiteInstance()->GetId();
if (!old_render_frame_host->IsRenderFrameLive()) {
- ShutdownRenderFrameProxyHostsInSiteInstance(old_site_instance_id);
+ ShutdownProxiesIfLastActiveFrameInSiteInstance(old_render_frame_host.get());
return;
}
@@ -519,14 +608,13 @@ void RenderFrameHostManager::SwapOutOldFrame(
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
+ // Clear out any proxies from this SiteInstance, in case this was the
// last one keeping other proxies alive.
- ShutdownRenderFrameProxyHostsInSiteInstance(old_site_instance_id);
+ ShutdownProxiesIfLastActiveFrameInSiteInstance(old_render_frame_host.get());
+ // Tell the old RenderFrameHost to swap out, with no proxy to replace it.
+ old_render_frame_host->SwapOut(NULL, true);
+ MoveToPendingDeleteHosts(old_render_frame_host.Pass());
return;
}
@@ -539,10 +627,14 @@ void RenderFrameHostManager::SwapOutOldFrame(
<< "Inserting a duplicate item.";
// Tell the old RenderFrameHost to swap out and be replaced by the proxy.
- old_render_frame_host->SwapOut(proxy);
+ old_render_frame_host->SwapOut(proxy, true);
+
+ // SwapOut creates a RenderFrameProxy, so set the proxy to be initialized.
+ proxy->set_render_frame_proxy_created(true);
bool is_main_frame = frame_tree_node_->IsMainFrame();
- if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess) &&
+ if (base::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.
@@ -559,6 +651,37 @@ void RenderFrameHostManager::SwapOutOldFrame(
}
}
+void RenderFrameHostManager::DiscardUnusedFrame(
+ scoped_ptr<RenderFrameHostImpl> render_frame_host) {
+ // TODO(carlosk): this code is very similar to what can be found in
+ // SwapOutOldFrame and we should see that these are unified at some point.
+
+ // 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 = render_frame_host->GetSiteInstance();
+ if (site_instance->HasSite() && site_instance->active_frame_count() > 1) {
+ // Any currently suspended navigations are no longer needed.
+ render_frame_host->CancelSuspendedNavigations();
+
+ CHECK(!GetRenderFrameProxyHost(site_instance));
+ RenderFrameProxyHost* proxy =
+ new RenderFrameProxyHost(site_instance, frame_tree_node_);
+ proxy_hosts_[site_instance->GetId()] = proxy;
+
+ // Check if the RenderFrameHost is already swapped out, to avoid swapping it
+ // out again.
+ if (!render_frame_host->is_swapped_out())
+ render_frame_host->SwapOut(proxy, false);
+
+ if (frame_tree_node_->IsMainFrame())
+ proxy->TakeFrameHostOwnership(render_frame_host.Pass());
+ } else {
+ // We won't be coming back, so delete this one.
+ ShutdownProxiesIfLastActiveFrameInSiteInstance(render_frame_host.get());
+ render_frame_host.reset();
+ }
+}
+
void RenderFrameHostManager::MoveToPendingDeleteHosts(
scoped_ptr<RenderFrameHostImpl> render_frame_host) {
// |render_frame_host| will be deleted when its SwapOut ACK is received, or
@@ -595,35 +718,186 @@ void RenderFrameHostManager::ResetProxyHosts() {
}
// PlzNavigate
+void RenderFrameHostManager::BeginNavigation(const NavigationRequest& request) {
+ CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation));
+ // Clean up any state in case there's an ongoing navigation.
+ // TODO(carlosk): remove this cleanup here once we properly cancel ongoing
+ // navigations.
+ CleanUpNavigation();
+
+ RenderFrameHostImpl* dest_rfh = GetFrameHostForNavigation(request);
+ DCHECK(dest_rfh);
+}
+
+// PlzNavigate
RenderFrameHostImpl* RenderFrameHostManager::GetFrameHostForNavigation(
- const GURL& url,
- ui::PageTransition transition) {
- CHECK(CommandLine::ForCurrentProcess()->HasSwitch(
+ const NavigationRequest& request) {
+ CHECK(base::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);
+ SiteInstance* current_site_instance = render_frame_host_->GetSiteInstance();
+
+ SiteInstance* candidate_site_instance =
+ speculative_render_frame_host_
+ ? speculative_render_frame_host_->GetSiteInstance()
+ : nullptr;
+
+ scoped_refptr<SiteInstance> dest_site_instance = GetSiteInstanceForNavigation(
+ request.common_params().url, request.source_site_instance(),
+ request.dest_site_instance(), candidate_site_instance,
+ request.common_params().transition,
+ request.restore_type() != NavigationEntryImpl::RESTORE_NONE,
+ request.is_view_source());
+
+ // The appropriate RenderFrameHost to commit the navigation.
+ RenderFrameHostImpl* navigation_rfh = nullptr;
+
+ // Renderer-initiated navigations that may require a SiteInstance swap are
+ // sent to the browser via the OpenURL IPC and are afterwards treated as
+ // browser-initiated navigations. NavigationRequests marked as
+ // renderer-initiated are created by receiving a BeginNavigation IPC, and will
+ // then proceed in the same renderer that sent the IPC due to the condition
+ // below.
+ // TODO(carlosk): Once there is support for cross-process scripting check for
+ // non-browser-initiated navigations should be removed (see crbug.com/440266).
+ if (current_site_instance == dest_site_instance.get() ||
+ !request.browser_initiated() ||
+ (!frame_tree_node_->IsMainFrame() &&
+ !base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess))) {
+ // Reuse the current RFH if its SiteInstance matches the the navigation's
+ // or if this is a subframe navigation. We only swap RFHs for subframes when
+ // --site-per-process is enabled.
+ CleanUpNavigation();
+ navigation_rfh = render_frame_host_.get();
+
+ // As SiteInstances are the same, check if the WebUI should be reused.
+ const NavigationEntry* current_navigation_entry =
+ delegate_->GetLastCommittedNavigationEntryForRenderManager();
+ should_reuse_web_ui_ = ShouldReuseWebUI(current_navigation_entry,
+ request.common_params().url);
+ if (!should_reuse_web_ui_) {
+ speculative_web_ui_ = CreateWebUI(request.common_params().url,
+ request.bindings());
+ // Make sure the current RenderViewHost has the right bindings.
+ if (speculative_web_ui() &&
+ !render_frame_host_->GetProcess()->IsIsolatedGuest()) {
+ render_frame_host_->render_view_host()->AllowBindings(
+ speculative_web_ui()->GetBindings());
+ }
+ }
+ } else {
+ // If the SiteInstance for the final URL doesn't match the one from the
+ // speculatively created RenderFrameHost, create a new RenderFrameHost using
+ // this new SiteInstance.
+ if (!speculative_render_frame_host_ ||
+ speculative_render_frame_host_->GetSiteInstance() !=
+ dest_site_instance.get()) {
+ CleanUpNavigation();
+ bool success = CreateSpeculativeRenderFrameHost(
+ request.common_params().url, current_site_instance,
+ dest_site_instance.get(), request.bindings());
+ DCHECK(success);
+ }
+ DCHECK(speculative_render_frame_host_);
+ navigation_rfh = speculative_render_frame_host_.get();
- // 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()) {
+ // Check if our current RFH is live.
+ if (!render_frame_host_->IsRenderFrameLive()) {
+ // 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 navigation to
+ // complete. Just switch to the speculative RFH now and go back to normal.
+ // (Note that we don't care about on{before}unload handlers if the current
+ // RFH isn't live.)
+ CommitPending();
+ }
+ }
+ DCHECK(navigation_rfh &&
+ (navigation_rfh == render_frame_host_.get() ||
+ navigation_rfh == speculative_render_frame_host_.get()));
+
+ // If the RenderFrame that needs to navigate is not live (its process was just
+ // created or has crashed), initialize it.
+ if (!navigation_rfh->IsRenderFrameLive()) {
// 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;
+ navigation_rfh->GetSiteInstance());
+ if (!InitRenderView(navigation_rfh->render_view_host(), opener_route_id,
+ MSG_ROUTING_NONE, frame_tree_node_->IsMainFrame())) {
+ return nullptr;
}
+
+ if (navigation_rfh == render_frame_host_) {
+ // TODO(nasko): This is a very ugly hack. The Chrome extensions process
+ // manager still uses NotificationService and expects to see a
+ // RenderViewHost changed notification after WebContents and
+ // RenderFrameHostManager are completely initialized. This should be
+ // removed once the process manager moves away from NotificationService.
+ // See https://crbug.com/462682.
+ delegate_->NotifyMainFrameSwappedFromRenderManager(
+ nullptr, render_frame_host_->render_view_host());
+ }
+ }
+
+ return navigation_rfh;
+}
+
+// PlzNavigate
+void RenderFrameHostManager::CleanUpNavigation() {
+ CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation));
+ speculative_web_ui_.reset();
+ should_reuse_web_ui_ = false;
+ if (speculative_render_frame_host_)
+ DiscardUnusedFrame(UnsetSpeculativeRenderFrameHost());
+}
+
+// PlzNavigate
+scoped_ptr<RenderFrameHostImpl>
+RenderFrameHostManager::UnsetSpeculativeRenderFrameHost() {
+ CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation));
+ speculative_render_frame_host_->GetProcess()->RemovePendingView();
+ return speculative_render_frame_host_.Pass();
+}
+
+void RenderFrameHostManager::OnDidStartLoading() {
+ for (const auto& pair : proxy_hosts_) {
+ pair.second->Send(
+ new FrameMsg_DidStartLoading(pair.second->GetRoutingID()));
+ }
+}
+
+void RenderFrameHostManager::OnDidStopLoading() {
+ for (const auto& pair : proxy_hosts_) {
+ pair.second->Send(new FrameMsg_DidStopLoading(pair.second->GetRoutingID()));
+ }
+}
+
+void RenderFrameHostManager::OnDidUpdateName(const std::string& name) {
+ // The window.name message may be sent outside of --site-per-process when
+ // report_frame_name_changes renderer preference is set (used by
+ // WebView). Don't send the update to proxies in those cases.
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess))
+ return;
+
+ for (const auto& pair : proxy_hosts_) {
+ pair.second->Send(
+ new FrameMsg_DidUpdateName(pair.second->GetRoutingID(), name));
+ }
+}
+
+void RenderFrameHostManager::OnDidUpdateOrigin(const url::Origin& origin) {
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess))
+ return;
+
+ for (const auto& pair : proxy_hosts_) {
+ pair.second->Send(
+ new FrameMsg_DidUpdateOrigin(pair.second->GetRoutingID(), origin));
}
- return render_frame_host;
}
void RenderFrameHostManager::Observe(
@@ -642,6 +916,15 @@ void RenderFrameHostManager::Observe(
}
}
+RenderFrameHostManager::SiteInstanceDescriptor::SiteInstanceDescriptor(
+ BrowserContext* browser_context,
+ GURL dest_url,
+ bool related_to_current)
+ : existing_site_instance(nullptr),
+ new_is_related_to_current(related_to_current) {
+ new_site_url = SiteInstance::GetSiteForURL(browser_context, dest_url);
+}
+
// static
bool RenderFrameHostManager::ClearProxiesInSiteInstance(
int32 site_instance_id,
@@ -654,6 +937,7 @@ bool RenderFrameHostManager::ClearProxiesInSiteInstance(
// 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() &&
proxy->render_frame_host()->rfh_state() ==
RenderFrameHostImpl::STATE_PENDING_SWAP_OUT) {
scoped_ptr<RenderFrameHostImpl> swapped_out_rfh =
@@ -667,14 +951,32 @@ bool RenderFrameHostManager::ClearProxiesInSiteInstance(
return true;
}
+// static.
+bool RenderFrameHostManager::ResetProxiesInSiteInstance(int32 site_instance_id,
+ FrameTreeNode* node) {
+ RenderFrameProxyHostMap::iterator iter =
+ node->render_manager()->proxy_hosts_.find(site_instance_id);
+ if (iter != node->render_manager()->proxy_hosts_.end())
+ iter->second->set_render_frame_proxy_created(false);
+
+ return true;
+}
+
bool RenderFrameHostManager::ShouldTransitionCrossSite() {
+ // True for --site-per-process, which overrides both kSingleProcess and
+ // kProcessPerTab.
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess))
+ return true;
+
// False in the single-process mode, as it makes RVHs to accumulate
// in swapped_out_hosts_.
// True if we are using process-per-site-instance (default) or
// process-per-site (kProcessPerSite).
- return
- !CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess) &&
- !CommandLine::ForCurrentProcess()->HasSwitch(switches::kProcessPerTab);
+ return !base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSingleProcess) &&
+ !base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kProcessPerTab);
}
bool RenderFrameHostManager::ShouldSwapBrowsingInstancesForNavigation(
@@ -745,7 +1047,7 @@ bool RenderFrameHostManager::ShouldReuseWebUI(
const GURL& new_url) const {
NavigationControllerImpl& controller =
delegate_->GetControllerForRenderManager();
- return current_entry && web_ui_.get() &&
+ return current_entry && web_ui_ &&
(WebUIControllerFactoryRegistry::GetInstance()->GetWebUIType(
controller.GetBrowserContext(), current_entry->GetURL()) ==
WebUIControllerFactoryRegistry::GetInstance()->GetWebUIType(
@@ -754,12 +1056,13 @@ bool RenderFrameHostManager::ShouldReuseWebUI(
SiteInstance* RenderFrameHostManager::GetSiteInstanceForNavigation(
const GURL& dest_url,
+ SiteInstance* source_instance,
SiteInstance* dest_instance,
- ui::PageTransition dest_transition,
+ SiteInstance* candidate_instance,
+ ui::PageTransition 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))
@@ -787,33 +1090,38 @@ SiteInstance* RenderFrameHostManager::GetSiteInstanceForNavigation(
dest_instance,
SiteInstanceImpl::GetEffectiveURL(browser_context, dest_url),
dest_is_view_source_mode);
+ SiteInstanceDescriptor new_instance_descriptor =
+ SiteInstanceDescriptor(current_instance);
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.
+ new_instance_descriptor = DetermineSiteInstanceForURL(
+ dest_url, source_instance, current_instance, dest_instance, transition,
+ dest_is_restore, dest_is_view_source_mode, force_swap);
+ }
+
+ SiteInstance* new_instance =
+ ConvertToSiteInstance(new_instance_descriptor, candidate_instance);
+
+ // If |force_swap| is true, we must use a different SiteInstance than the
+ // current one. If we didn't, we would have two RenderFrameHosts in the same
+ // SiteInstance and the same frame, resulting in page_id conflicts for their
+ // NavigationEntries.
if (force_swap)
CHECK_NE(new_instance, current_instance);
return new_instance;
}
-SiteInstance* RenderFrameHostManager::GetSiteInstanceForURL(
+RenderFrameHostManager::SiteInstanceDescriptor
+RenderFrameHostManager::DetermineSiteInstanceForURL(
const GURL& dest_url,
+ SiteInstance* source_instance,
+ SiteInstance* current_instance,
SiteInstance* dest_instance,
- ui::PageTransition dest_transition,
+ ui::PageTransition transition,
bool dest_is_restore,
bool dest_is_view_source_mode,
- SiteInstance* current_instance,
bool force_browsing_instance_swap) {
+ SiteInstanceImpl* current_instance_impl =
+ static_cast<SiteInstanceImpl*>(current_instance);
NavigationControllerImpl& controller =
delegate_->GetControllerForRenderManager();
BrowserContext* browser_context = controller.GetBrowserContext();
@@ -825,13 +1133,13 @@ SiteInstance* RenderFrameHostManager::GetSiteInstanceForURL(
CHECK(!dest_instance->IsRelatedSiteInstance(
render_frame_host_->GetSiteInstance()));
}
- return dest_instance;
+ return SiteInstanceDescriptor(dest_instance);
}
// If a swap is required, we need to force the SiteInstance AND
// BrowsingInstance to be different ones, using CreateForURL.
if (force_browsing_instance_swap)
- return SiteInstance::CreateForURL(browser_context, dest_url);
+ return SiteInstanceDescriptor(browser_context, dest_url, false);
// (UGLY) HEURISTIC, process-per-site only:
//
@@ -843,20 +1151,17 @@ SiteInstance* RenderFrameHostManager::GetSiteInstanceForURL(
// NOTE: This can be removed once we have a way to transition between
// RenderViews in response to a link click.
//
- if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kProcessPerSite) &&
- ui::PageTransitionCoreTypeIs(
- dest_transition, ui::PAGE_TRANSITION_GENERATED)) {
- return current_instance;
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kProcessPerSite) &&
+ ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_GENERATED)) {
+ return SiteInstanceDescriptor(current_instance_impl);
}
- SiteInstanceImpl* current_site_instance =
- static_cast<SiteInstanceImpl*>(current_instance);
-
// If we haven't used our SiteInstance (and thus RVH) yet, then we can use it
// for this entry. We won't commit the SiteInstance to this site until the
// navigation commits (in DidNavigate), unless the navigation entry was
// restored or it's a Web UI as described below.
- if (!current_site_instance->HasSite()) {
+ if (!current_instance_impl->HasSite()) {
// If we've already created a SiteInstance for our destination, we don't
// want to use this unused SiteInstance; use the existing one. (We don't
// do this check if the current_instance has a site, because for now, we
@@ -871,30 +1176,30 @@ SiteInstance* RenderFrameHostManager::GetSiteInstanceForURL(
bool use_process_per_site =
RenderProcessHost::ShouldUseProcessPerSite(browser_context, dest_url) &&
RenderProcessHostImpl::GetProcessHostForSite(browser_context, dest_url);
- if (current_site_instance->HasRelatedSiteInstance(dest_url) ||
+ if (current_instance_impl->HasRelatedSiteInstance(dest_url) ||
use_process_per_site) {
- return current_site_instance->GetRelatedSiteInstance(dest_url);
+ return SiteInstanceDescriptor(browser_context, dest_url, true);
}
// For extensions, Web UI URLs (such as the new tab page), and apps we do
- // not want to use the current_instance if it has no site, since it will
- // have a RenderProcessHost of PRIV_NORMAL. Create a new SiteInstance for
- // this URL instead (with the correct process type).
- if (current_site_instance->HasWrongProcessForURL(dest_url))
- return current_site_instance->GetRelatedSiteInstance(dest_url);
+ // not want to use the |current_instance_impl| if it has no site, since it
+ // will have a RenderProcessHost of PRIV_NORMAL. Create a new SiteInstance
+ // for this URL instead (with the correct process type).
+ if (current_instance_impl->HasWrongProcessForURL(dest_url))
+ return SiteInstanceDescriptor(browser_context, dest_url, true);
// View-source URLs must use a new SiteInstance and BrowsingInstance.
// TODO(nasko): This is the same condition as later in the function. This
// should be taken into account when refactoring this method as part of
// http://crbug.com/123007.
if (dest_is_view_source_mode)
- return SiteInstance::CreateForURL(browser_context, dest_url);
+ return SiteInstanceDescriptor(browser_context, dest_url, false);
// If we are navigating from a blank SiteInstance to a WebUI, make sure we
// create a new SiteInstance.
if (WebUIControllerFactoryRegistry::GetInstance()->UseWebUIForURL(
browser_context, dest_url)) {
- return SiteInstance::CreateForURL(browser_context, dest_url);
+ return SiteInstanceDescriptor(browser_context, dest_url, false);
}
// Normally the "site" on the SiteInstance is set lazily when the load
@@ -913,19 +1218,19 @@ SiteInstance* RenderFrameHostManager::GetSiteInstanceForURL(
// See http://crbug.com/386542.
if (dest_is_restore &&
GetContentClient()->browser()->ShouldAssignSiteForURL(dest_url)) {
- current_site_instance->SetSite(dest_url);
+ current_instance_impl->SetSite(dest_url);
}
- return current_site_instance;
+ return SiteInstanceDescriptor(current_instance_impl);
}
- // Otherwise, only create a new SiteInstance for a cross-site navigation.
+ // Otherwise, only create a new SiteInstance for a cross-process navigation.
// TODO(creis): Once we intercept links and script-based navigations, we
// will be able to enforce that all entries in a SiteInstance actually have
// the same site, and it will be safe to compare the URL against the
// SiteInstance's site, as follows:
- // const GURL& current_url = current_instance->site();
+ // const GURL& current_url = current_instance_impl->site();
// For now, though, we're in a hybrid model where you only switch
// SiteInstances if you type in a cross-site URL. This means we have to
// compare the entry's URL to the last committed entry's URL.
@@ -944,17 +1249,26 @@ SiteInstance* RenderFrameHostManager::GetSiteInstanceForURL(
if (current_entry &&
current_entry->IsViewSourceMode() != dest_is_view_source_mode &&
!IsRendererDebugURL(dest_url)) {
- return SiteInstance::CreateForURL(browser_context, dest_url);
+ return SiteInstanceDescriptor(browser_context, dest_url, false);
+ }
+
+ // Use the source SiteInstance in case of data URLs or about:blank pages,
+ // because the content is then controlled and/or scriptable by the source
+ // SiteInstance.
+ GURL about_blank(url::kAboutBlankURL);
+ if (source_instance &&
+ (dest_url == about_blank || dest_url.scheme() == url::kDataScheme)) {
+ return SiteInstanceDescriptor(source_instance);
}
// Use the current SiteInstance for same site navigations, as long as the
// process type is correct. (The URL may have been installed as an app since
// the last time we visited it.)
const GURL& current_url =
- GetCurrentURLForSiteInstance(current_instance, current_entry);
+ GetCurrentURLForSiteInstance(current_instance_impl, current_entry);
if (SiteInstance::IsSameWebSite(browser_context, current_url, dest_url) &&
- !current_site_instance->HasWrongProcessForURL(dest_url)) {
- return current_instance;
+ !current_instance_impl->HasWrongProcessForURL(dest_url)) {
+ return SiteInstanceDescriptor(current_instance_impl);
}
// Start the new renderer in a new SiteInstance, but in the current
@@ -962,7 +1276,36 @@ SiteInstance* RenderFrameHostManager::GetSiteInstanceForURL(
// SiteInstance to a RenderViewHost (if it is different than our current
// SiteInstance), so that it is ref counted. This will happen in
// CreateRenderView.
- return current_instance->GetRelatedSiteInstance(dest_url);
+ return SiteInstanceDescriptor(browser_context, dest_url, true);
+}
+
+SiteInstance* RenderFrameHostManager::ConvertToSiteInstance(
+ const SiteInstanceDescriptor& descriptor,
+ SiteInstance* candidate_instance) {
+ SiteInstance* current_instance = render_frame_host_->GetSiteInstance();
+
+ // Note: If the |candidate_instance| matches the descriptor, it will already
+ // be set to |descriptor.existing_site_instance|.
+ if (descriptor.existing_site_instance)
+ return descriptor.existing_site_instance;
+
+ // Note: If the |candidate_instance| matches the descriptor,
+ // GetRelatedSiteInstance will return it.
+ if (descriptor.new_is_related_to_current)
+ return current_instance->GetRelatedSiteInstance(descriptor.new_site_url);
+
+ // At this point we know an unrelated site instance must be returned. First
+ // check if the candidate matches.
+ if (candidate_instance &&
+ !current_instance->IsRelatedSiteInstance(candidate_instance) &&
+ candidate_instance->GetSiteURL() == descriptor.new_site_url) {
+ return candidate_instance;
+ }
+
+ // Otherwise return a newly created one.
+ return SiteInstance::CreateForURL(
+ delegate_->GetControllerForRenderManager().GetBrowserContext(),
+ descriptor.new_site_url);
}
const GURL& RenderFrameHostManager::GetCurrentURLForSiteInstance(
@@ -974,7 +1317,8 @@ const GURL& RenderFrameHostManager::GetCurrentURLForSiteInstance(
// 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))
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess))
return frame_tree_node_->current_url();
// If there is no last non-interstitial entry (and current_instance already
@@ -992,48 +1336,80 @@ const GURL& RenderFrameHostManager::GetCurrentURLForSiteInstance(
return current_instance->GetSiteURL();
}
-void RenderFrameHostManager::CreateRenderFrameHostForNewSiteInstance(
+void RenderFrameHostManager::CreatePendingRenderFrameHost(
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 create_render_frame_flags = 0;
+ if (is_main_frame)
+ create_render_frame_flags |= CREATE_RF_FOR_MAIN_FRAME_NAVIGATION;
+
+ if (delegate_->IsHidden())
+ create_render_frame_flags |= CREATE_RF_HIDDEN;
+
+ if (pending_render_frame_host_)
+ CancelPending();
+
+ // The process for the new SiteInstance may (if we're sharing a process with
+ // another host that already initialized it) or may not (we have our own
+ // process or the existing process crashed) have been initialized. Calling
+ // Init multiple times will be ignored, so this is safe.
+ if (!new_instance->GetProcess()->Init())
+ return;
+
+ int opener_route_id = CreateOpenerRenderViewsIfNeeded(
+ old_instance, new_instance, &create_render_frame_flags);
+
+ // Create a non-swapped-out RFH with the given opener.
+ pending_render_frame_host_ =
+ CreateRenderFrame(new_instance, pending_web_ui(), opener_route_id,
+ create_render_frame_flags, nullptr);
+}
+
+int RenderFrameHostManager::CreateOpenerRenderViewsIfNeeded(
+ SiteInstance* old_instance,
+ SiteInstance* new_instance,
+ int* create_render_frame_flags) {
int opener_route_id = MSG_ROUTING_NONE;
+ // Only create opener proxies if they are in the same BrowsingInstance.
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;
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess)) {
+ // Ensure that the frame tree has RenderFrameProxyHosts for the new
+ // SiteInstance in all nodes except the current one. We do this for all
+ // frames in the tree, whether they are in the same BrowsingInstance or not.
+ // We will still check whether two frames are in the same BrowsingInstance
+ // before we allow them to interact (e.g., postMessage).
+ frame_tree_node_->frame_tree()->CreateProxiesForSiteInstance(
+ frame_tree_node_, new_instance);
+ // RenderFrames in different processes from their parent RenderFrames
+ // in the frame tree require RenderWidgets for rendering and processing
+ // input events.
+ if (frame_tree_node_->parent() &&
+ frame_tree_node_->parent()->current_frame_host()->GetSiteInstance() !=
+ new_instance)
+ *create_render_frame_flags |= CREATE_RF_NEEDS_RENDER_WIDGET_HOST;
}
+ return opener_route_id;
}
scoped_ptr<RenderFrameHostImpl> RenderFrameHostManager::CreateRenderFrameHost(
SiteInstance* site_instance,
int view_routing_id,
int frame_routing_id,
- bool swapped_out,
- bool hidden) {
+ int flags) {
if (frame_routing_id == MSG_ROUTING_NONE)
frame_routing_id = site_instance->GetProcess()->GetNextRoutingID();
+ bool swapped_out = !!(flags & CREATE_RF_SWAPPED_OUT);
+ bool hidden = !!(flags & CREATE_RF_HIDDEN);
+
// Create a RVH for main frames, or find the existing one for subframes.
FrameTree* frame_tree = frame_tree_node_->frame_tree();
- RenderViewHostImpl* render_view_host = NULL;
+ RenderViewHostImpl* render_view_host = nullptr;
if (frame_tree_node_->IsMainFrame()) {
render_view_host = frame_tree->CreateRenderViewHost(
site_instance, view_routing_id, frame_routing_id, swapped_out, hidden);
@@ -1044,45 +1420,88 @@ scoped_ptr<RenderFrameHostImpl> RenderFrameHostManager::CreateRenderFrameHost(
}
// TODO(creis): Pass hidden to RFH.
- scoped_ptr<RenderFrameHostImpl> render_frame_host =
- make_scoped_ptr(RenderFrameHostFactory::Create(render_view_host,
- render_frame_delegate_,
- frame_tree,
- frame_tree_node_,
- frame_routing_id,
- swapped_out).release());
+ scoped_ptr<RenderFrameHostImpl> render_frame_host = make_scoped_ptr(
+ RenderFrameHostFactory::Create(
+ site_instance, render_view_host, render_frame_delegate_,
+ render_widget_delegate_, frame_tree, frame_tree_node_,
+ frame_routing_id, flags).release());
return render_frame_host.Pass();
}
-int RenderFrameHostManager::CreateRenderFrame(SiteInstance* instance,
- int opener_route_id,
- bool swapped_out,
- bool for_main_frame_navigation,
- bool hidden) {
+// PlzNavigate
+bool RenderFrameHostManager::CreateSpeculativeRenderFrameHost(
+ const GURL& url,
+ SiteInstance* old_instance,
+ SiteInstance* new_instance,
+ int bindings) {
+ CHECK(new_instance);
+ CHECK_NE(old_instance, new_instance);
+ CHECK(!should_reuse_web_ui_);
+
+ // Note: |speculative_web_ui_| must be initialized before starting the
+ // |speculative_render_frame_host_| creation steps otherwise the WebUI
+ // won't be properly initialized.
+ speculative_web_ui_ = CreateWebUI(url, bindings);
+
+ // The process for the new SiteInstance may (if we're sharing a process with
+ // another host that already initialized it) or may not (we have our own
+ // process or the existing process crashed) have been initialized. Calling
+ // Init multiple times will be ignored, so this is safe.
+ if (!new_instance->GetProcess()->Init())
+ return false;
+
+ int create_render_frame_flags = 0;
+ int opener_route_id =
+ CreateOpenerRenderViewsIfNeeded(old_instance, new_instance,
+ &create_render_frame_flags);
+
+ if (frame_tree_node_->IsMainFrame())
+ create_render_frame_flags |= CREATE_RF_FOR_MAIN_FRAME_NAVIGATION;
+ if (delegate_->IsHidden())
+ create_render_frame_flags |= CREATE_RF_HIDDEN;
+ speculative_render_frame_host_ =
+ CreateRenderFrame(new_instance, speculative_web_ui_.get(),
+ opener_route_id, create_render_frame_flags, nullptr);
+
+ if (!speculative_render_frame_host_) {
+ speculative_web_ui_.reset();
+ return false;
+ }
+ return true;
+}
+
+scoped_ptr<RenderFrameHostImpl> RenderFrameHostManager::CreateRenderFrame(
+ SiteInstance* instance,
+ WebUIImpl* web_ui,
+ int opener_route_id,
+ int flags,
+ int* view_routing_id_ptr) {
+ bool swapped_out = !!(flags & CREATE_RF_SWAPPED_OUT);
CHECK(instance);
- DCHECK(!swapped_out || hidden); // Swapped out views should always be hidden.
+ // Swapped out views should always be hidden.
+ DCHECK(!swapped_out || (flags & CREATE_RF_HIDDEN));
- // TODO(nasko): Remove the following CHECK once cross-site navigation no
+ // TODO(nasko): Remove the following CHECK once cross-process navigation no
// longer relies on swapped out RFH for the top-level frame.
- if (!frame_tree_node_->IsMainFrame()) {
+ 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;
+ bool success = true;
+ if (view_routing_id_ptr)
+ *view_routing_id_ptr = MSG_ROUTING_NONE;
- // We are creating a pending or swapped out RFH here. We should never create
- // it in the same SiteInstance as our current RFH.
+ // We are creating a pending, speculative or swapped out RFH here. We should
+ // never create it in the same SiteInstance as our current RFH.
CHECK_NE(render_frame_host_->GetSiteInstance(), instance);
// Check if we've already created an RFH for this SiteInstance. If so, try
// to re-use the existing one, which has already been initialized. We'll
// remove it from the list of proxy hosts below if it will be active.
RenderFrameProxyHost* proxy = GetRenderFrameProxyHost(instance);
-
if (proxy && proxy->render_frame_host()) {
- routing_id = proxy->GetRenderViewHost()->GetRoutingID();
+ if (view_routing_id_ptr)
+ *view_routing_id_ptr = proxy->GetRenderViewHost()->GetRoutingID();
// Delete the existing RenderFrameProxyHost, but reuse the RenderFrameHost.
// Prevent the process from exiting while we're trying to use it.
if (!swapped_out) {
@@ -1096,20 +1515,20 @@ int RenderFrameHostManager::CreateRenderFrame(SiteInstance* instance,
// gets a RenderViewHost in the SiteInstance of its opener WebContents.
// If not used in the first navigation, this RVH is swapped out and is not
// granted bindings, so we may need to grant them when swapping it in.
- if (pending_web_ui() &&
- !new_render_frame_host->GetProcess()->IsIsolatedGuest()) {
- int required_bindings = pending_web_ui()->GetBindings();
- RenderViewHost* rvh = new_render_frame_host->render_view_host();
- if ((rvh->GetEnabledBindings() & required_bindings) !=
- required_bindings) {
- rvh->AllowBindings(required_bindings);
+ if (web_ui && !new_render_frame_host->GetProcess()->IsIsolatedGuest()) {
+ int required_bindings = web_ui->GetBindings();
+ RenderViewHost* render_view_host =
+ new_render_frame_host->render_view_host();
+ if ((render_view_host->GetEnabledBindings() & required_bindings) !=
+ required_bindings) {
+ render_view_host->AllowBindings(required_bindings);
}
}
}
} else {
// Create a new RenderFrameHost if we don't find an existing one.
- new_render_frame_host = CreateRenderFrameHost(
- instance, MSG_ROUTING_NONE, MSG_ROUTING_NONE, swapped_out, hidden);
+ new_render_frame_host = CreateRenderFrameHost(instance, MSG_ROUTING_NONE,
+ MSG_ROUTING_NONE, flags);
RenderViewHostImpl* render_view_host =
new_render_frame_host->render_view_host();
int proxy_routing_id = MSG_ROUTING_NONE;
@@ -1123,39 +1542,42 @@ int RenderFrameHostManager::CreateRenderFrame(SiteInstance* instance,
new_render_frame_host->GetSiteInstance(), frame_tree_node_);
proxy_hosts_[instance->GetId()] = proxy;
proxy_routing_id = proxy->GetRoutingID();
- if (frame_tree_node_->IsMainFrame())
- proxy->TakeFrameHostOwnership(new_render_frame_host.Pass());
+ proxy->TakeFrameHostOwnership(new_render_frame_host.Pass());
}
- bool success = InitRenderView(render_view_host,
- opener_route_id,
- proxy_routing_id,
- for_main_frame_navigation);
+ success =
+ InitRenderView(render_view_host, opener_route_id, proxy_routing_id,
+ !!(flags & CREATE_RF_FOR_MAIN_FRAME_NAVIGATION));
if (success) {
+ // Remember that InitRenderView also created the RenderFrameProxy.
+ if (swapped_out)
+ proxy->set_render_frame_proxy_created(true);
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();
+ // Only the RenderViewHost for the top-level RenderFrameHost has a
+ // RenderWidgetHostView; RenderWidgetHosts for out-of-process iframes
+ // will be created later and hidden.
+ if (render_view_host->GetView())
+ 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());
+ DCHECK(new_render_frame_host);
success = InitRenderFrame(new_render_frame_host.get());
}
- } else if (!swapped_out && pending_render_frame_host_) {
- CancelPending();
}
- routing_id = render_view_host->GetRoutingID();
- frame_to_announce = new_render_frame_host.get();
- }
- // Use this as our new pending RFH if it isn't swapped out.
- if (!swapped_out)
- pending_render_frame_host_ = new_render_frame_host.Pass();
-
- // If a brand new RFH was created, announce it to observers.
- if (frame_to_announce)
- render_frame_delegate_->RenderFrameCreated(frame_to_announce);
+ if (success) {
+ if (view_routing_id_ptr)
+ *view_routing_id_ptr = render_view_host->GetRoutingID();
+ }
+ }
- return routing_id;
+ // Returns the new RFH if it isn't swapped out.
+ if (success && !swapped_out) {
+ DCHECK(new_render_frame_host->GetSiteInstance() == instance);
+ return new_render_frame_host.Pass();
+ }
+ return nullptr;
}
int RenderFrameHostManager::CreateRenderFrameProxy(SiteInstance* instance) {
@@ -1165,15 +1587,42 @@ int RenderFrameHostManager::CreateRenderFrameProxy(SiteInstance* instance) {
CHECK_NE(instance, render_frame_host_->GetSiteInstance());
RenderFrameProxyHost* proxy = GetRenderFrameProxyHost(instance);
- if (proxy)
+ if (proxy && proxy->is_render_frame_proxy_live())
return proxy->GetRoutingID();
- proxy = new RenderFrameProxyHost(instance, frame_tree_node_);
- proxy_hosts_[instance->GetId()] = proxy;
+ if (!proxy) {
+ proxy = new RenderFrameProxyHost(instance, frame_tree_node_);
+ proxy_hosts_[instance->GetId()] = proxy;
+ }
proxy->InitRenderFrameProxy();
return proxy->GetRoutingID();
}
+void RenderFrameHostManager::CreateProxiesForChildFrame(FrameTreeNode* child) {
+ for (const auto& pair : proxy_hosts_) {
+ child->render_manager()->CreateRenderFrameProxy(
+ pair.second->GetSiteInstance());
+ }
+}
+
+void RenderFrameHostManager::EnsureRenderViewInitialized(
+ FrameTreeNode* source,
+ RenderViewHostImpl* render_view_host,
+ SiteInstance* instance) {
+ DCHECK(frame_tree_node_->IsMainFrame());
+
+ if (render_view_host->IsRenderViewLive())
+ return;
+
+ // Recreate the opener chain.
+ int opener_route_id =
+ delegate_->CreateOpenerRenderViewsForRenderManager(instance);
+ RenderFrameProxyHost* proxy = GetRenderFrameProxyHost(instance);
+ InitRenderView(render_view_host, opener_route_id, proxy->GetRoutingID(),
+ source->IsMainFrame());
+ proxy->set_render_frame_proxy_created(true);
+}
+
bool RenderFrameHostManager::InitRenderView(
RenderViewHostImpl* render_view_host,
int opener_route_id,
@@ -1183,11 +1632,19 @@ bool RenderFrameHostManager::InitRenderView(
if (render_view_host->IsRenderViewLive())
return true;
- // If the pending navigation is to a WebUI and the RenderView is not in a
+ // If the ongoing navigation is to a WebUI and the RenderView is not in a
// guest process, tell the RenderViewHost about any bindings it will need
// enabled.
- if (pending_web_ui() && !render_view_host->GetProcess()->IsIsolatedGuest()) {
- render_view_host->AllowBindings(pending_web_ui()->GetBindings());
+ WebUIImpl* dest_web_ui = nullptr;
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation)) {
+ dest_web_ui =
+ should_reuse_web_ui_ ? web_ui_.get() : speculative_web_ui_.get();
+ } else {
+ dest_web_ui = pending_web_ui();
+ }
+ if (dest_web_ui && !render_view_host->GetProcess()->IsIsolatedGuest()) {
+ render_view_host->AllowBindings(dest_web_ui->GetBindings());
} else {
// Ensure that we don't create an unprivileged RenderView in a WebUI-enabled
// process unless it's swapped out.
@@ -1209,12 +1666,28 @@ bool RenderFrameHostManager::InitRenderFrame(
return true;
int parent_routing_id = MSG_ROUTING_NONE;
+ int previous_sibling_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);
}
+
+ // At this point, all RenderFrameProxies for sibling frames have already been
+ // created, including any proxies that come after this frame. To preserve
+ // correct order for indexed window access (e.g., window.frames[1]), pass the
+ // previous sibling frame so that this frame is correctly inserted into the
+ // frame tree on the renderer side.
+ FrameTreeNode* previous_sibling = frame_tree_node_->PreviousSibling();
+ if (previous_sibling) {
+ previous_sibling_routing_id =
+ previous_sibling->render_manager()->GetRoutingIdForSiteInstance(
+ render_frame_host->GetSiteInstance());
+ CHECK_NE(previous_sibling_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.
@@ -1227,10 +1700,12 @@ bool RenderFrameHostManager::InitRenderFrame(
if (existing_proxy) {
proxy_routing_id = existing_proxy->GetRoutingID();
CHECK_NE(proxy_routing_id, MSG_ROUTING_NONE);
+ if (!existing_proxy->is_render_frame_proxy_live())
+ existing_proxy->InitRenderFrameProxy();
}
- return delegate_->CreateRenderFrameForRenderManager(render_frame_host,
- parent_routing_id,
- proxy_routing_id);
+ return delegate_->CreateRenderFrameForRenderManager(
+ render_frame_host, parent_routing_id, previous_sibling_routing_id,
+ proxy_routing_id);
}
int RenderFrameHostManager::GetRoutingIdForSiteInstance(
@@ -1249,6 +1724,9 @@ int RenderFrameHostManager::GetRoutingIdForSiteInstance(
void RenderFrameHostManager::CommitPending() {
TRACE_EVENT1("navigation", "RenderFrameHostManager::CommitPending",
"FrameTreeNode id", frame_tree_node_->frame_tree_node_id());
+ bool browser_side_navigation =
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation);
// 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
@@ -1258,20 +1736,29 @@ void RenderFrameHostManager::CommitPending() {
// 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.
- DCHECK(!(pending_web_ui_.get() && pending_and_current_web_ui_.get()));
- if (pending_web_ui_) {
- web_ui_.reset(pending_web_ui_.release());
- } else if (!pending_and_current_web_ui_.get()) {
- web_ui_.reset();
+ DCHECK(!(pending_web_ui_ && pending_and_current_web_ui_));
+ if (pending_web_ui_ || speculative_web_ui_) {
+ DCHECK(!should_reuse_web_ui_);
+ web_ui_.reset(browser_side_navigation ? speculative_web_ui_.release()
+ : pending_web_ui_.release());
+ } else if (pending_and_current_web_ui_ || should_reuse_web_ui_) {
+ if (browser_side_navigation) {
+ DCHECK(web_ui_);
+ should_reuse_web_ui_ = false;
+ } else {
+ DCHECK_EQ(pending_and_current_web_ui_.get(), web_ui_.get());
+ pending_and_current_web_ui_.reset();
+ }
} else {
- DCHECK_EQ(pending_and_current_web_ui_.get(), web_ui_.get());
- pending_and_current_web_ui_.reset();
+ web_ui_.reset();
}
+ DCHECK(!speculative_web_ui_);
+ DCHECK(!should_reuse_web_ui_);
- // It's possible for the pending_render_frame_host_ to be NULL when we aren't
- // crossing process boundaries. If so, we just needed to handle the Web UI
- // committing above and we're done.
- if (!pending_render_frame_host_) {
+ // It's possible for the pending_render_frame_host_ to be nullptr when we
+ // aren't crossing process boundaries. If so, we just needed to handle the Web
+ // UI committing above and we're done.
+ if (!pending_render_frame_host_ && !speculative_render_frame_host_) {
if (will_focus_location_bar)
delegate_->SetFocusToLocationBar(false);
return;
@@ -1280,26 +1767,36 @@ void RenderFrameHostManager::CommitPending() {
// Remember if the page was focused so we can focus the new renderer in
// that case.
bool focus_render_view = !will_focus_location_bar &&
- render_frame_host_->render_view_host()->GetView() &&
- render_frame_host_->render_view_host()->GetView()->HasFocus();
+ render_frame_host_->GetView() &&
+ render_frame_host_->GetView()->HasFocus();
bool is_main_frame = frame_tree_node_->IsMainFrame();
- // Swap in the pending frame and make it active. Also ensure the FrameTree
- // stays in sync.
- scoped_ptr<RenderFrameHostImpl> old_render_frame_host =
- SetRenderFrameHost(pending_render_frame_host_.Pass());
- if (is_main_frame)
- render_frame_host_->render_view_host()->AttachToFrameTree();
+ // Swap in the pending or speculative frame and make it active. Also ensure
+ // the FrameTree stays in sync.
+ scoped_ptr<RenderFrameHostImpl> old_render_frame_host;
+ if (!browser_side_navigation) {
+ DCHECK(!speculative_render_frame_host_);
+ old_render_frame_host =
+ SetRenderFrameHost(pending_render_frame_host_.Pass());
+ } else {
+ // PlzNavigate
+ DCHECK(speculative_render_frame_host_);
+ old_render_frame_host =
+ SetRenderFrameHost(speculative_render_frame_host_.Pass());
+ }
+
+ // Remove the children of the old frame from the tree.
+ frame_tree_node_->ResetForNewProcess();
// The process will no longer try to exit, so we can decrement the count.
render_frame_host_->GetProcess()->RemovePendingView();
// Show the new view (or a sad tab) if necessary.
- bool new_rfh_has_view = !!render_frame_host_->render_view_host()->GetView();
+ bool new_rfh_has_view = !!render_frame_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();
+ render_frame_host_->GetView()->Show();
}
if (!new_rfh_has_view) {
// If the view is gone, then this RenderViewHost died while it was hidden.
@@ -1322,9 +1819,8 @@ void RenderFrameHostManager::CommitPending() {
if (will_focus_location_bar) {
delegate_->SetFocusToLocationBar(false);
- } else if (focus_render_view &&
- render_frame_host_->render_view_host()->GetView()) {
- render_frame_host_->render_view_host()->GetView()->Focus();
+ } else if (focus_render_view && render_frame_host_->GetView()) {
+ render_frame_host_->GetView()->Focus();
}
// Notify that we've swapped RenderFrameHosts. We do this before shutting down
@@ -1340,19 +1836,9 @@ void RenderFrameHostManager::CommitPending() {
// the proxy.
SwapOutOldFrame(old_render_frame_host.Pass());
- if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess) &&
+ if (base::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());
- }
-
// Since the new RenderFrameHost is now committed, there must be no proxies
// for its SiteInstance. Delete any existing ones.
RenderFrameProxyHostMap::iterator iter =
@@ -1361,6 +1847,17 @@ void RenderFrameHostManager::CommitPending() {
delete iter->second;
proxy_hosts_.erase(iter);
}
+
+ // 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. If this navigation causes
+ // an out-of-process frame to return to the same process as its parent, the
+ // proxy would have been removed from proxy_hosts_ above.
+ // 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_->GetView());
}
// After all is done, there must never be a proxy in the list which has the
@@ -1369,9 +1866,21 @@ void RenderFrameHostManager::CommitPending() {
proxy_hosts_.end());
}
-void RenderFrameHostManager::ShutdownRenderFrameProxyHostsInSiteInstance(
- int32 site_instance_id) {
- // First remove any swapped out RFH for this SiteInstance from our own list.
+void RenderFrameHostManager::ShutdownProxiesIfLastActiveFrameInSiteInstance(
+ RenderFrameHostImpl* render_frame_host) {
+ if (!render_frame_host)
+ return;
+ if (!RenderFrameHostImpl::IsRFHStateActive(render_frame_host->rfh_state()))
+ return;
+ if (render_frame_host->GetSiteInstance()->active_frame_count() > 1U)
+ return;
+
+ // After |render_frame_host| goes away, there will be no active frames left in
+ // its SiteInstance, so we can delete all proxies created in that SiteInstance
+ // on behalf of frames anywhere in the BrowsingInstance.
+ int32 site_instance_id = render_frame_host->GetSiteInstance()->GetId();
+
+ // First remove any proxies for this SiteInstance from our own list.
ClearProxiesInSiteInstance(site_instance_id, frame_tree_node_);
// Use the safe RenderWidgetHost iterator for now to find all RenderViewHosts
@@ -1398,28 +1907,29 @@ void RenderFrameHostManager::ShutdownRenderFrameProxyHostsInSiteInstance(
}
RenderFrameHostImpl* RenderFrameHostManager::UpdateStateForNavigate(
- const GURL& url,
- SiteInstance* instance,
+ const GURL& dest_url,
+ SiteInstance* source_instance,
+ SiteInstance* dest_instance,
ui::PageTransition transition,
- bool is_restore,
- bool is_view_source_mode,
+ bool dest_is_restore,
+ bool dest_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_) {
- if (pending_render_frame_host_)
- CancelPending();
- cross_navigation_pending_ = false;
- }
+ if (pending_render_frame_host_)
+ CancelPending();
SiteInstance* current_instance = render_frame_host_->GetSiteInstance();
scoped_refptr<SiteInstance> new_instance = GetSiteInstanceForNavigation(
- url, instance, transition, is_restore, is_view_source_mode);
+ dest_url, source_instance, dest_instance, nullptr, transition,
+ dest_is_restore, dest_is_view_source_mode);
const NavigationEntry* current_entry =
delegate_->GetLastCommittedNavigationEntryForRenderManager();
+ DCHECK(!pending_render_frame_host_);
+
if (new_instance.get() != current_instance) {
TRACE_EVENT_INSTANT2(
"navigation",
@@ -1429,53 +1939,37 @@ RenderFrameHostImpl* RenderFrameHostManager::UpdateStateForNavigate(
"new_instance id", new_instance->GetId());
// New SiteInstance: create a pending RFH to navigate.
- DCHECK(!cross_navigation_pending_);
-
- // This will possibly create (set to NULL) a Web UI object for the pending
- // page. We'll use this later to give the page special access. This must
- // happen before the new renderer is created below so it will get bindings.
- // 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(url, bindings);
- CreateRenderFrameHostForNewSiteInstance(
- current_instance, new_instance.get(), frame_tree_node_->IsMainFrame());
- if (!pending_render_frame_host_.get()) {
- return NULL;
- }
+
+ // This will possibly create (set to nullptr) a Web UI object for the
+ // pending page. We'll use this later to give the page special access. This
+ // must happen before the new renderer is created below so it will get
+ // bindings. 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(dest_url, bindings);
+ CreatePendingRenderFrameHost(current_instance, new_instance.get(),
+ frame_tree_node_->IsMainFrame());
+ if (!pending_render_frame_host_)
+ return nullptr;
// Check if our current RFH is live before we set up a transition.
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
- // navigate. Just switch to the pending RFH now and go back to non
- // cross-navigating (Note that we don't care about on{before}unload
- // handlers if the current RFH isn't live.)
- CommitPending();
- return render_frame_host_.get();
- } else {
- NOTREACHED();
- return render_frame_host_.get();
- }
+ // 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
+ // navigate. Just switch to the pending RFH now and go back to normal.
+ // (Note that we don't care about on{before}unload handlers if the current
+ // RFH isn't live.)
+ CommitPending();
+ return render_frame_host_.get();
}
- // Otherwise, it's safe to treat this as a pending cross-site transition.
+ // Otherwise, it's safe to treat this as a pending cross-process 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();
- }
+ DCHECK(pending_render_frame_host_);
// 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
+ // Suspend the new render view (i.e., don't let it send the cross-process
// 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.
@@ -1506,7 +2000,6 @@ RenderFrameHostImpl* RenderFrameHostManager::UpdateStateForNavigate(
}
// Otherwise the same SiteInstance can be used. Navigate render_frame_host_.
- DCHECK(!cross_navigation_pending_);
// 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
@@ -1515,11 +2008,11 @@ RenderFrameHostImpl* RenderFrameHostManager::UpdateStateForNavigate(
// delete the proxy.
DeleteRenderFrameProxyHost(new_instance.get());
- if (ShouldReuseWebUI(current_entry, url)) {
+ if (ShouldReuseWebUI(current_entry, dest_url)) {
pending_web_ui_.reset();
pending_and_current_web_ui_ = web_ui_->AsWeakPtr();
} else {
- SetPendingWebUI(url, bindings);
+ SetPendingWebUI(dest_url, bindings);
// Make sure the new RenderViewHost has the right bindings.
if (pending_web_ui() &&
!render_frame_host_->GetProcess()->IsIsolatedGuest()) {
@@ -1535,7 +2028,7 @@ RenderFrameHostImpl* RenderFrameHostManager::UpdateStateForNavigate(
// The renderer can exit view source mode when any error or cancellation
// happen. We must overwrite to recover the mode.
- if (is_view_source_mode) {
+ if (dest_is_view_source_mode) {
render_frame_host_->render_view_host()->Send(
new ViewMsg_EnableViewSourceMode(
render_frame_host_->render_view_host()->GetRoutingID()));
@@ -1547,37 +2040,25 @@ RenderFrameHostImpl* RenderFrameHostManager::UpdateStateForNavigate(
void RenderFrameHostManager::CancelPending() {
TRACE_EVENT1("navigation", "RenderFrameHostManager::CancelPending",
"FrameTreeNode id", frame_tree_node_->frame_tree_node_id());
+ DiscardUnusedFrame(UnsetPendingRenderFrameHost());
+}
+
+scoped_ptr<RenderFrameHostImpl>
+RenderFrameHostManager::UnsetPendingRenderFrameHost() {
scoped_ptr<RenderFrameHostImpl> pending_render_frame_host =
pending_render_frame_host_.Pass();
- RenderViewDevToolsAgentHost::OnCancelPendingNavigation(
- pending_render_frame_host->render_view_host(),
- render_frame_host_->render_view_host());
+ RenderFrameDevToolsAgentHost::OnCancelPendingNavigation(
+ pending_render_frame_host.get(),
+ render_frame_host_.get());
// We no longer need to prevent the process from exiting.
pending_render_frame_host->GetProcess()->RemovePendingView();
- // 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 =
- pending_render_frame_host->GetSiteInstance();
- if (site_instance->active_frame_count() > 1) {
- // Any currently suspended navigations are no longer needed.
- 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);
- 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();
- }
-
pending_web_ui_.reset();
pending_and_current_web_ui_.reset();
+
+ return pending_render_frame_host.Pass();
}
scoped_ptr<RenderFrameHostImpl> RenderFrameHostManager::SetRenderFrameHost(
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 7394628bcbf..1c77b3eb3f4 100644
--- a/chromium/content/browser/frame_host/render_frame_host_manager.h
+++ b/chromium/content/browser/frame_host/render_frame_host_manager.h
@@ -19,21 +19,21 @@
#include "content/public/browser/notification_registrar.h"
#include "content/public/common/referrer.h"
#include "ui/base/page_transition_types.h"
-
-struct FrameMsg_Navigate_Params;
+#include "url/origin.h"
namespace content {
class BrowserContext;
class CrossProcessFrameConnector;
class CrossSiteTransferringRequest;
-class InterstitialPageImpl;
class FrameTreeNode;
+class InterstitialPageImpl;
class NavigationControllerImpl;
class NavigationEntry;
class NavigationEntryImpl;
+class NavigationRequest;
+class NavigatorTestWithBrowserSideNavigation;
class RenderFrameHost;
class RenderFrameHostDelegate;
-class RenderFrameHost;
class RenderFrameHostImpl;
class RenderFrameHostManagerTest;
class RenderFrameProxyHost;
@@ -43,6 +43,7 @@ class RenderWidgetHostDelegate;
class RenderWidgetHostView;
class TestWebContents;
class WebUIImpl;
+struct CommonNavigationParams;
// Manages RenderFrameHosts for a FrameTreeNode. It maintains a
// current_frame_host() which is the content currently visible to the user. When
@@ -124,6 +125,7 @@ class CONTENT_EXPORT RenderFrameHostManager : public NotificationObserver {
virtual bool CreateRenderFrameForRenderManager(
RenderFrameHost* render_frame_host,
int parent_routing_id,
+ int previous_sibling_routing_id,
int proxy_routing_id) = 0;
virtual void BeforeUnloadFiredFromRenderManager(
bool proceed, const base::TimeTicks& proceed_time,
@@ -135,6 +137,11 @@ class CONTENT_EXPORT RenderFrameHostManager : public NotificationObserver {
virtual void NotifySwappedFromRenderManager(RenderFrameHost* old_host,
RenderFrameHost* new_host,
bool is_main_frame) = 0;
+ // TODO(nasko): This should be removed once extensions no longer use
+ // NotificationService. See https://crbug.com/462682.
+ virtual void NotifyMainFrameSwappedFromRenderManager(
+ RenderViewHost* old_host,
+ RenderViewHost* new_host) = 0;
virtual NavigationControllerImpl&
GetControllerForRenderManager() = 0;
@@ -148,7 +155,8 @@ class CONTENT_EXPORT RenderFrameHostManager : public NotificationObserver {
// Creates a WebUI object for the given URL if one applies. Ownership of the
// returned pointer will be passed to the caller. If no WebUI applies,
// returns NULL.
- virtual WebUIImpl* CreateWebUIForRenderManager(const GURL& url) = 0;
+ virtual scoped_ptr<WebUIImpl> CreateWebUIForRenderManager(
+ const GURL& url) = 0;
// Returns the navigation entry of the current navigation, or NULL if there
// is none.
@@ -231,9 +239,12 @@ class CONTENT_EXPORT RenderFrameHostManager : public NotificationObserver {
pending_and_current_web_ui_.get();
}
- // Sets the pending Web UI for the pending navigation, ensuring that the
- // bindings are appropriate compared to |bindings|.
- void SetPendingWebUI(const GURL& url, int bindings);
+ // PlzNavigate
+ // Returns the speculative WebUI for the navigation (a newly created one or
+ // the current one if it should be reused). If none is set returns nullptr.
+ WebUIImpl* speculative_web_ui() const {
+ return should_reuse_web_ui_ ? web_ui_.get() : speculative_web_ui_.get();
+ }
// 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
@@ -292,24 +303,39 @@ class CONTENT_EXPORT RenderFrameHostManager : public NotificationObserver {
void ClearNavigationTransitionData();
// Called when a renderer's frame navigates.
- void DidNavigateFrame(RenderFrameHostImpl* render_frame_host);
+ void DidNavigateFrame(RenderFrameHostImpl* render_frame_host,
+ bool was_caused_by_user_gesture);
// Called when a renderer sets its opener to null.
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.
- // 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);
+ // Sets the pending Web UI for the pending navigation, ensuring that the
+ // bindings are appropriate compared to |bindings|.
+ void SetPendingWebUI(const GURL& url, int bindings);
+
+ // Creates and initializes a RenderFrameHost. The |web_ui| is an optional
+ // input parameter used to double check bindings when swapping back in a
+ // previously existing RenderFrameHost. If |flags| has the
+ // CREATE_RF_SWAPPED_OUT bit set from the CreateRenderFrameFlags enum, it will
+ // initially be placed on the swapped out hosts list. If |view_routing_id_ptr|
+ // is not nullptr it will be set to the routing id of the view associated with
+ // the frame.
+ scoped_ptr<RenderFrameHostImpl> CreateRenderFrame(SiteInstance* instance,
+ WebUIImpl* web_ui,
+ int opener_route_id,
+ int flags,
+ int* view_routing_id_ptr);
// Helper method to create and initialize a RenderFrameProxyHost and return
// its routing id.
int CreateRenderFrameProxy(SiteInstance* instance);
+ // Creates proxies for a new child frame at FrameTreeNode |child| in all
+ // SiteInstances for which the current frame has proxies. This method is
+ // called on the parent of a new child frame before the child leaves the
+ // SiteInstance.
+ void CreateProxiesForChildFrame(FrameTreeNode* child);
+
// 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
@@ -362,22 +388,83 @@ class CONTENT_EXPORT RenderFrameHostManager : public NotificationObserver {
// 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);
+ // PlzNavigate
+ // Notifies the RFHM that a navigation has begun so that it can speculatively
+ // create a new RenderFrameHost (and potentially a new process) if needed.
+ void BeginNavigation(const NavigationRequest& request);
+
+ // PlzNavigate
+ // Called (possibly several times) during a navigation to select or create an
+ // appropriate RenderFrameHost for the provided URL. The returned pointer will
+ // be for the current or the speculative RenderFrameHost and the instance is
+ // owned by this manager.
+ RenderFrameHostImpl* GetFrameHostForNavigation(
+ const NavigationRequest& request);
+
+ // PlzNavigate
+ // Clean up any state for any ongoing navigation.
+ void CleanUpNavigation();
+
+ // PlzNavigate
+ // Clears the speculative members, returning the RenderFrameHost to the caller
+ // for disposal.
+ scoped_ptr<RenderFrameHostImpl> UnsetSpeculativeRenderFrameHost();
+
+ // Notification methods to tell this RenderFrameHostManager that the frame it
+ // is responsible for has started or stopped loading a document.
+ void OnDidStartLoading();
+ void OnDidStopLoading();
+
+ // Send updated frame name to all frame proxies when the frame changes its
+ // window.name property.
+ void OnDidUpdateName(const std::string& name);
+
+ // Send updated origin to all frame proxies when the frame navigates to a new
+ // origin.
+ void OnDidUpdateOrigin(const url::Origin& origin);
+
+ void EnsureRenderViewInitialized(FrameTreeNode* source,
+ RenderViewHostImpl* render_view_host,
+ SiteInstance* instance);
private:
+ friend class FrameTreeVisualizer;
+ friend class NavigatorTestWithBrowserSideNavigation;
friend class RenderFrameHostManagerTest;
friend class TestWebContents;
- FRIEND_TEST_ALL_PREFIXES(CrossProcessFrameTreeBrowserTest,
- CreateCrossProcessSubframeProxies);
+ // Stores information regarding a SiteInstance targeted at a specific URL to
+ // allow for comparisons without having to actually create new instances. It
+ // can point to an existing one or store the details needed to create a new
+ // one.
+ struct CONTENT_EXPORT SiteInstanceDescriptor {
+ explicit SiteInstanceDescriptor(content::SiteInstance* site_instance)
+ : existing_site_instance(site_instance),
+ new_is_related_to_current(false) {}
+
+ SiteInstanceDescriptor(BrowserContext* browser_context,
+ GURL dest_url,
+ bool related_to_current);
+
+ // Set with an existing SiteInstance to be reused.
+ content::SiteInstance* existing_site_instance;
+
+ // In case |existing_site_instance| is null, specify a new site URL.
+ GURL new_site_url;
+
+ // In case |existing_site_instance| is null, specify if the new site should
+ // be created in a new BrowsingInstance or not.
+ bool new_is_related_to_current;
+ };
// Used with FrameTree::ForEach to erase RenderFrameProxyHosts from a
// FrameTreeNode's RenderFrameHostManager.
static bool ClearProxiesInSiteInstance(int32 site_instance_id,
FrameTreeNode* node);
+ // Used with FrameTree::ForEach to reset initialized state of
+ // RenderFrameProxyHosts from a FrameTreeNode's RenderFrameHostManager.
+ static bool ResetProxiesInSiteInstance(int32 site_instance_id,
+ FrameTreeNode* node);
// Returns whether this tab should transition to a new renderer for
// cross-site URLs. Enabled unless we see the --process-per-tab command line
@@ -404,6 +491,10 @@ class CONTENT_EXPORT RenderFrameHostManager : public NotificationObserver {
const GURL& new_effective_url,
bool new_is_view_source_mode) const;
+ // Creates a new Web UI, ensuring that the bindings are appropriate compared
+ // to |bindings|.
+ scoped_ptr<WebUIImpl> CreateWebUI(const GURL& url, int bindings);
+
// Returns true if it is safe to reuse the current WebUI when navigating from
// |current_entry| to |new_url|.
bool ShouldReuseWebUI(
@@ -411,46 +502,80 @@ class CONTENT_EXPORT RenderFrameHostManager : public NotificationObserver {
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 |dest_url|,
- // possibly reusing the current SiteInstance. If --process-per-tab is used,
- // this is only called when ShouldSwapBrowsingInstancesForNavigation returns
- // true. |dest_instance| will be used if it is not null.
+ SiteInstance* GetSiteInstanceForNavigation(const GURL& dest_url,
+ SiteInstance* source_instance,
+ SiteInstance* dest_instance,
+ SiteInstance* candidate_instance,
+ ui::PageTransition transition,
+ bool dest_is_restore,
+ bool dest_is_view_source_mode);
+
+ // Returns a descriptor of the appropriate SiteInstance object for the given
+ // |dest_url|, possibly reusing the current, source or destination
+ // SiteInstance. The actual SiteInstance can then be obtained calling
+ // ConvertToSiteInstance with the descriptor.
+ //
+ // |source_instance| is the SiteInstance of the frame that initiated the
+ // navigation. |current_instance| is the SiteInstance of the frame that is
+ // currently navigating. |dest_instance| is a predetermined SiteInstance that
+ // will be used if not null.
+ // For example, if you have a parent frame A, which has a child frame B, and
+ // A is trying to change the src attribute of B, this will cause a navigation
+ // where the source SiteInstance is A and B is the current SiteInstance.
+ //
// This is a helper function for GetSiteInstanceForNavigation.
- SiteInstance* GetSiteInstanceForURL(
+ SiteInstanceDescriptor DetermineSiteInstanceForURL(
const GURL& dest_url,
+ SiteInstance* source_instance,
+ SiteInstance* current_instance,
SiteInstance* dest_instance,
- ui::PageTransition dest_transition,
+ ui::PageTransition transition,
bool dest_is_restore,
bool dest_is_view_source_mode,
- SiteInstance* current_instance,
bool force_browsing_instance_swap);
+ // Converts a SiteInstanceDescriptor to the actual SiteInstance it describes.
+ // If a |candidate_instance| is provided (is not nullptr) and it matches the
+ // description, it is returned as is.
+ SiteInstance* ConvertToSiteInstance(const SiteInstanceDescriptor& descriptor,
+ SiteInstance* candidate_instance);
+
// 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 new RenderFrameHostImpl for the |new_instance| and assign it to
+ // |pending_render_frame_host_| while respecting the opener route if needed
+ // and stores it in pending_render_frame_host_.
+ void CreatePendingRenderFrameHost(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). Returns the opener
+ // route ID to be used for the new RenderView to be created.
+ // |create_render_frame_flags| allows the method to set additional flags.
+ int CreateOpenerRenderViewsIfNeeded(SiteInstance* old_instance,
+ SiteInstance* new_instance,
+ int* create_render_frame_flags);
// Creates a RenderFrameHost and corresponding RenderViewHost if necessary.
scoped_ptr<RenderFrameHostImpl> CreateRenderFrameHost(SiteInstance* instance,
int view_routing_id,
int frame_routing_id,
- bool swapped_out,
- bool hidden);
+ int flags);
+
+ // PlzNavigate
+ // Creates and initializes a speculative RenderFrameHost and/or WebUI for an
+ // ongoing navigation. They might be destroyed and re-created later if the
+ // navigation is redirected to a different SiteInstance.
+ bool CreateSpeculativeRenderFrameHost(const GURL& url,
+ SiteInstance* old_instance,
+ SiteInstance* new_instance,
+ int bindings);
// Sets up the necessary state for a new RenderViewHost with the given opener,
// if necessary. It creates a RenderFrameProxy in the target renderer process
@@ -471,37 +596,58 @@ class CONTENT_EXPORT RenderFrameHostManager : public NotificationObserver {
// 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.
+ // If PlzNavigate is enabled the method will set the speculative (not pending)
+ // RenderFrameHost to be the active one.
void CommitPending();
+ // Helper to call CommitPending() in all necessary cases.
+ void CommitPendingIfNecessary(RenderFrameHostImpl* render_frame_host,
+ bool was_caused_by_user_gesture);
+
+ // Commits any pending sandbox flag updates when the renderer's frame
+ // navigates.
+ void CommitPendingSandboxFlags();
+
// 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);
+ // Discards a RenderFrameHost that was never made active (for active ones
+ // SwapOutOldFrame is used instead).
+ void DiscardUnusedFrame(scoped_ptr<RenderFrameHostImpl> 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);
+ // If |render_frame_host| is the last remaining active frame in its
+ // SiteInstance, this will shutdown all the RenderFrameProxyHosts in the
+ // SiteInstance. This is appropriate if |render_frame_host| is about to be
+ // destroyed.
+ void ShutdownProxiesIfLastActiveFrameInSiteInstance(
+ RenderFrameHostImpl* render_frame_host);
- // Helper method to terminate the pending RenderViewHost.
+ // Helper method to terminate the pending RenderFrameHost. The frame may be
+ // deleted immediately, or it may be kept around in hopes of later reuse.
void CancelPending();
+ // Clears pending_render_frame_host_, returning it to the caller for disposal.
+ scoped_ptr<RenderFrameHostImpl> UnsetPendingRenderFrameHost();
+
// Helper method to set the active RenderFrameHost. Returns the old
// RenderFrameHost and updates counts.
scoped_ptr<RenderFrameHostImpl> SetRenderFrameHost(
scoped_ptr<RenderFrameHostImpl> render_frame_host);
RenderFrameHostImpl* UpdateStateForNavigate(
- const GURL& url,
- SiteInstance* instance,
+ const GURL& dest_url,
+ SiteInstance* source_instance,
+ SiteInstance* dest_instance,
ui::PageTransition transition,
- bool is_restore,
- bool is_view_source_mode,
+ bool dest_is_restore,
+ bool dest_is_view_source_mode,
const GlobalRequestID& transferred_request_id,
int bindings);
@@ -519,11 +665,6 @@ class CONTENT_EXPORT RenderFrameHostManager : public NotificationObserver {
// Our delegate, not owned by us. Guaranteed non-NULL.
Delegate* delegate_;
- // Whether a navigation requiring different RenderFrameHosts is pending. This
- // is either for cross-site requests or when required for the process type
- // (like WebUI).
- bool cross_navigation_pending_;
-
// Implemented by the owner of this class. These delegates are installed into
// all the RenderFrameHosts that we create.
RenderFrameHostDelegate* render_frame_delegate_;
@@ -548,6 +689,7 @@ class CONTENT_EXPORT RenderFrameHostManager : public NotificationObserver {
// transitioning between two Web UI pages: the RFH won't be swapped, so the
// pending pointer will be unused, but there will be a pending Web UI
// associated with the navigation.
+ // Note: This is not used in PlzNavigate.
scoped_ptr<RenderFrameHostImpl> pending_render_frame_host_;
// If a pending request needs to be transferred to another process, this
@@ -563,6 +705,7 @@ class CONTENT_EXPORT RenderFrameHostManager : public NotificationObserver {
// page. The scoped_ptr is used if pending_web_ui_ != web_ui_, the WeakPtr is
// used for when they reference the same object. If either is non-NULL, the
// other should be NULL.
+ // Note: These are not used in PlzNavigate.
scoped_ptr<WebUIImpl> pending_web_ui_;
base::WeakPtr<WebUIImpl> pending_and_current_web_ui_;
@@ -582,6 +725,23 @@ class CONTENT_EXPORT RenderFrameHostManager : public NotificationObserver {
NotificationRegistrar registrar_;
+ // PlzNavigate
+ // These members store a speculative RenderFrameHost and WebUI. They are
+ // created early in a navigation so a renderer process can be started in
+ // parallel, if needed. This is purely a performance optimization and is not
+ // required for correct behavior. The created RenderFrameHost might be
+ // discarded later on if the final URL's SiteInstance isn't compatible with
+ // what was used to create it.
+ // Note: PlzNavigate only uses speculative RenderFrameHost and WebUI, not
+ // the pending ones.
+ scoped_ptr<RenderFrameHostImpl> speculative_render_frame_host_;
+ scoped_ptr<WebUIImpl> speculative_web_ui_;
+
+ // PlzNavigate
+ // If true at navigation commit time the current WebUI will be kept instead of
+ // creating a new one.
+ bool should_reuse_web_ui_;
+
base::WeakPtrFactory<RenderFrameHostManager> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(RenderFrameHostManager);
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 fcfbd2c585c..9de16f8e9c0 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,6 +7,7 @@
#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"
@@ -22,6 +23,9 @@
#include "content/public/browser/web_contents_observer.h"
#include "content/public/common/bindings_policy.h"
#include "content/public/common/content_switches.h"
+#include "content/public/common/file_chooser_file_info.h"
+#include "content/public/common/file_chooser_params.h"
+#include "content/public/common/page_state.h"
#include "content/public/common/url_constants.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
@@ -128,9 +132,7 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, NoScriptAccessAfterSwapOut) {
new_shell->web_contents()->GetLastCommittedURL().path());
// Should have the same SiteInstance.
- scoped_refptr<SiteInstance> blank_site_instance(
- new_shell->web_contents()->GetSiteInstance());
- EXPECT_EQ(orig_site_instance, blank_site_instance);
+ EXPECT_EQ(orig_site_instance, new_shell->web_contents()->GetSiteInstance());
// We should have access to the opened window's location.
success = false;
@@ -153,6 +155,29 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, NoScriptAccessAfterSwapOut) {
"window.domAutomationController.send(testScriptAccessToWindow());",
&success));
EXPECT_FALSE(success);
+
+ // We now navigate the window to an about:blank page.
+ success = false;
+ EXPECT_TRUE(ExecuteScriptAndExtractBool(
+ shell()->web_contents(),
+ "window.domAutomationController.send(clickBlankTargetedLink());",
+ &success));
+ EXPECT_TRUE(success);
+
+ // Wait for the navigation in the new window to finish.
+ WaitForLoadStop(new_shell->web_contents());
+ GURL blank_url(url::kAboutBlankURL);
+ EXPECT_EQ(blank_url,
+ new_shell->web_contents()->GetLastCommittedURL());
+ EXPECT_EQ(orig_site_instance, new_shell->web_contents()->GetSiteInstance());
+
+ // We should have access to the opened window's location.
+ success = false;
+ EXPECT_TRUE(ExecuteScriptAndExtractBool(
+ shell()->web_contents(),
+ "window.domAutomationController.send(testScriptAccessToWindow());",
+ &success));
+ EXPECT_TRUE(success);
}
// Test for crbug.com/24447. Following a cross-site link with rel=noreferrer
@@ -264,7 +289,7 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
"files/click-noreferrer-links.html",
foo_host_port_,
&replacement_path));
- NavigateToURL(shell(), test_server()->GetURL(replacement_path));
+ EXPECT_TRUE(NavigateToURL(shell(), test_server()->GetURL(replacement_path)));
// Get the original SiteInstance for later comparison.
scoped_refptr<SiteInstance> orig_site_instance(
@@ -284,7 +309,7 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
Shell* new_shell = new_shell_observer.GetShell();
// Wait for the cross-site transition in the new tab to finish.
- WaitForLoadStop(new_shell->web_contents());
+ EXPECT_TRUE(WaitForLoadStop(new_shell->web_contents()));
EXPECT_EQ("/files/title2.html",
new_shell->web_contents()->GetLastCommittedURL().path());
@@ -809,6 +834,50 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
EXPECT_EQ(orig_site_instance, revisit_site_instance);
}
+// Test that subframes do not crash when sending a postMessage to the top frame
+// from an unload handler while the top frame is being swapped out as part of
+// navigating cross-process. https://crbug.com/475651.
+IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
+ PostMessageFromSubframeUnloadHandler) {
+ StartServer();
+
+ GURL frame_url(test_server()->GetURL("files/post_message.html"));
+ GURL main_url("data:text/html,<iframe name='foo' src='" + frame_url.spec() +
+ "'></iframe>");
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ // Get the original SiteInstance for later comparison.
+ scoped_refptr<SiteInstance> orig_site_instance(
+ shell()->web_contents()->GetSiteInstance());
+ EXPECT_NE(nullptr, orig_site_instance.get());
+
+ // It is safe to obtain the root frame tree node here, as it doesn't change.
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+ ASSERT_EQ(1U, root->child_count());
+ EXPECT_EQ(frame_url, root->child_at(0)->current_url());
+
+ // Register an unload handler that sends a postMessage to the top frame.
+ EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(),
+ "registerUnload();"));
+
+ // Navigate the top frame cross-site. This will cause the top frame to be
+ // swapped out and run unload handlers, and the original renderer process
+ // should then terminate since it's not rendering any other frames.
+ RenderProcessHostWatcher exit_observer(
+ root->current_frame_host()->GetProcess(),
+ RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
+ EXPECT_TRUE(NavigateToURL(shell(), GetCrossSiteURL("files/title1.html")));
+ scoped_refptr<SiteInstance> new_site_instance(
+ shell()->web_contents()->GetSiteInstance());
+ EXPECT_NE(orig_site_instance, new_site_instance);
+
+ // Ensure that the original renderer process exited cleanly without crashing.
+ exit_observer.Wait();
+ EXPECT_EQ(true, exit_observer.did_exit_normally());
+}
+
// Test that opening a new window in the same SiteInstance and then navigating
// both windows to a different SiteInstance allows the first process to exit.
// See http://crbug.com/126333.
@@ -883,7 +952,8 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ClickLinkAfter204Error) {
EXPECT_TRUE(orig_site_instance.get() != NULL);
// Load a cross-site page that fails with a 204 error.
- NavigateToURL(shell(), GetCrossSiteURL("nocontent"));
+ EXPECT_TRUE(NavigateToURLAndExpectNoCommit(shell(),
+ GetCrossSiteURL("nocontent")));
// We should still be looking at the normal page. Because we started from a
// blank new tab, the typed URL will still be visible until the user clears it
@@ -1324,7 +1394,8 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, RendererDebugURLsDontSwap) {
RenderProcessHostWatcher crash_observer(
shell()->web_contents(),
RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
- NavigateToURL(shell(), GURL(kChromeUICrashURL));
+ EXPECT_TRUE(
+ NavigateToURLAndExpectNoCommit(shell(), GURL(kChromeUICrashURL)));
crash_observer.Wait();
}
@@ -1345,7 +1416,8 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
RenderProcessHostWatcher crash_observer(
shell()->web_contents(),
RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
- NavigateToURL(shell(), GURL(kChromeUICrashURL));
+ EXPECT_TRUE(
+ NavigateToURLAndExpectNoCommit(shell(), GURL(kChromeUICrashURL)));
crash_observer.Wait();
// Load the crash URL again but don't wait for any action. If it is not
@@ -1356,12 +1428,12 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
// We postpone the initial navigation of the tab using an empty GURL, so that
// we can add a watcher for crashes.
Shell* shell2 = Shell::CreateNewWindow(
- shell()->web_contents()->GetBrowserContext(), GURL(), NULL,
- MSG_ROUTING_NONE, gfx::Size());
+ shell()->web_contents()->GetBrowserContext(), GURL(), NULL, gfx::Size());
RenderProcessHostWatcher crash_observer2(
shell2->web_contents(),
RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
- NavigateToURL(shell2, GURL(kChromeUIKillURL));
+ EXPECT_TRUE(
+ NavigateToURLAndExpectNoCommit(shell2, GURL(kChromeUIKillURL)));
crash_observer2.Wait();
}
@@ -1401,7 +1473,7 @@ class RFHMProcessPerTabTest : public RenderFrameHostManagerTest {
public:
RFHMProcessPerTabTest() {}
- void SetUpCommandLine(CommandLine* command_line) override {
+ void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitch(switches::kProcessPerTab);
}
};
@@ -1490,7 +1562,8 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, WebUIGetsBindings) {
// in between WebUI and regular page.
IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
ForceSwapAfterWebUIBindings) {
- CommandLine::ForCurrentProcess()->AppendSwitch(switches::kProcessPerTab);
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kProcessPerTab);
ASSERT_TRUE(test_server()->Start());
const GURL web_ui_url(std::string(kChromeUIScheme) + "://" +
@@ -1507,4 +1580,146 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
shell()->web_contents()->GetRenderProcessHost()->GetID()));
}
+class FileChooserDelegate : public WebContentsDelegate {
+ public:
+ FileChooserDelegate(const base::FilePath& file)
+ : file_(file), file_chosen_(false) {}
+
+ void RunFileChooser(WebContents* web_contents,
+ const FileChooserParams& params) override {
+ // Send the selected file to the renderer process.
+ FileChooserFileInfo file_info;
+ file_info.file_path = file_;
+ std::vector<FileChooserFileInfo> files;
+ files.push_back(file_info);
+ web_contents->GetRenderViewHost()->FilesSelectedInChooser(
+ files, FileChooserParams::Open);
+
+ file_chosen_ = true;
+ }
+
+ bool file_chosen() { return file_chosen_; }
+
+ private:
+ base::FilePath file_;
+ bool file_chosen_;
+};
+
+// Test for http://crbug.com/262948.
+// Flaky on Mac. http://crbug.com/452018
+#if defined(OS_MACOSX)
+#define MAYBE_RestoreFileAccessForHistoryNavigation \
+ DISABLED_RestoreFileAccessForHistoryNavigation
+#else
+#define MAYBE_RestoreFileAccessForHistoryNavigation \
+ RestoreFileAccessForHistoryNavigation
+#endif
+IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
+ MAYBE_RestoreFileAccessForHistoryNavigation) {
+ StartServer();
+ base::FilePath file;
+ EXPECT_TRUE(PathService::Get(base::DIR_TEMP, &file));
+ file = file.AppendASCII("bar");
+
+ // Navigate to url and get it to reference a file in its PageState.
+ GURL url1(test_server()->GetURL("files/file_input.html"));
+ NavigateToURL(shell(), url1);
+ int process_id = shell()->web_contents()->GetRenderProcessHost()->GetID();
+ scoped_ptr<FileChooserDelegate> delegate(new FileChooserDelegate(file));
+ shell()->web_contents()->SetDelegate(delegate.get());
+ EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
+ "document.getElementById('fileinput').click();"));
+ EXPECT_TRUE(delegate->file_chosen());
+ EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
+ process_id, file));
+
+ // Navigate to a different process without access to the file, and wait for
+ // the old process to exit.
+ RenderProcessHostWatcher exit_observer(
+ shell()->web_contents()->GetRenderProcessHost(),
+ RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
+ NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
+ exit_observer.Wait();
+ EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
+ shell()->web_contents()->GetRenderProcessHost()->GetID(), file));
+
+ // Ensure that the file ended up in the PageState of the previous entry.
+ NavigationEntry* prev_entry =
+ shell()->web_contents()->GetController().GetEntryAtIndex(0);
+ EXPECT_EQ(url1, prev_entry->GetURL());
+ const std::vector<base::FilePath>& files =
+ prev_entry->GetPageState().GetReferencedFiles();
+ ASSERT_EQ(1U, files.size());
+ EXPECT_EQ(file, files.at(0));
+
+ // Go back, ending up in a different RenderProcessHost than before.
+ TestNavigationObserver back_nav_load_observer(shell()->web_contents());
+ shell()->web_contents()->GetController().GoBack();
+ back_nav_load_observer.Wait();
+ EXPECT_NE(process_id,
+ shell()->web_contents()->GetRenderProcessHost()->GetID());
+
+ // Ensure that the file access still exists in the new process ID.
+ EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
+ shell()->web_contents()->GetRenderProcessHost()->GetID(), file));
+
+ // Navigate to a same site page to trigger a PageState update and ensure the
+ // renderer is not killed.
+ EXPECT_TRUE(
+ NavigateToURL(shell(), test_server()->GetURL("files/title2.html")));
+}
+
+// Test for http://crbug.com/441966.
+IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
+ RestoreSubframeFileAccessForHistoryNavigation) {
+ StartServer();
+ base::FilePath file;
+ EXPECT_TRUE(PathService::Get(base::DIR_TEMP, &file));
+ file = file.AppendASCII("bar");
+
+ // Navigate to url and get it to reference a file in its PageState.
+ GURL url1(test_server()->GetURL("files/file_input_subframe.html"));
+ NavigateToURL(shell(), url1);
+ WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
+ FrameTreeNode* root = wc->GetFrameTree()->root();
+ int process_id = shell()->web_contents()->GetRenderProcessHost()->GetID();
+ scoped_ptr<FileChooserDelegate> delegate(new FileChooserDelegate(file));
+ shell()->web_contents()->SetDelegate(delegate.get());
+ EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(),
+ "document.getElementById('fileinput').click();"));
+ EXPECT_TRUE(delegate->file_chosen());
+ EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
+ process_id, file));
+
+ // Navigate to a different process without access to the file, and wait for
+ // the old process to exit.
+ RenderProcessHostWatcher exit_observer(
+ shell()->web_contents()->GetRenderProcessHost(),
+ RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
+ NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
+ exit_observer.Wait();
+ EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
+ shell()->web_contents()->GetRenderProcessHost()->GetID(), file));
+
+ // Ensure that the file ended up in the PageState of the previous entry.
+ NavigationEntry* prev_entry =
+ shell()->web_contents()->GetController().GetEntryAtIndex(0);
+ EXPECT_EQ(url1, prev_entry->GetURL());
+ const std::vector<base::FilePath>& files =
+ prev_entry->GetPageState().GetReferencedFiles();
+ ASSERT_EQ(1U, files.size());
+ EXPECT_EQ(file, files.at(0));
+
+ // Go back, ending up in a different RenderProcessHost than before.
+ TestNavigationObserver back_nav_load_observer(shell()->web_contents());
+ shell()->web_contents()->GetController().GoBack();
+ back_nav_load_observer.Wait();
+ EXPECT_NE(process_id,
+ shell()->web_contents()->GetRenderProcessHost()->GetID());
+
+ // Ensure that the file access still exists in the new process ID.
+ EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
+ shell()->web_contents()->GetRenderProcessHost()->GetID(), file));
+}
+
} // 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 11c3c8a2704..ec75f5b95fe 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
@@ -10,6 +10,7 @@
#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/navigation_request.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"
@@ -201,6 +202,31 @@ class RenderFrameHostDeletedObserver : public WebContentsObserver {
DISALLOW_COPY_AND_ASSIGN(RenderFrameHostDeletedObserver);
};
+// This WebContents observer keep track of its RVH change.
+class RenderViewHostChangedObserver : public WebContentsObserver {
+ public:
+ RenderViewHostChangedObserver(WebContents* web_contents)
+ : WebContentsObserver(web_contents), host_changed_(false) {}
+
+ // WebContentsObserver.
+ void RenderViewHostChanged(RenderViewHost* old_host,
+ RenderViewHost* new_host) override {
+ host_changed_ = true;
+ }
+
+ bool DidHostChange() {
+ bool host_changed = host_changed_;
+ Reset();
+ return host_changed;
+ }
+
+ void Reset() { host_changed_ = false; }
+
+ private:
+ bool host_changed_;
+ DISALLOW_COPY_AND_ASSIGN(RenderViewHostChangedObserver);
+};
+
// 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
@@ -237,74 +263,16 @@ class PluginFaviconMessageObserver : public WebContentsObserver {
DISALLOW_COPY_AND_ASSIGN(PluginFaviconMessageObserver);
};
-// Ensures that RenderFrameDeleted and RenderFrameCreated are called in a
-// consistent manner.
-class FrameLifetimeConsistencyChecker : public WebContentsObserver {
- public:
- explicit FrameLifetimeConsistencyChecker(WebContentsImpl* web_contents)
- : WebContentsObserver(web_contents) {
- RenderViewCreated(web_contents->GetRenderViewHost());
- RenderFrameCreated(web_contents->GetMainFrame());
- }
-
- 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());
- bool was_live_already = !live_routes_.insert(routing_pair).second;
- bool was_used_before = deleted_routes_.count(routing_pair) != 0;
-
- if (was_live_already) {
- FAIL() << "RenderFrameCreated called more than once for routing pair: "
- << Format(render_frame_host);
- } else if (was_used_before) {
- FAIL() << "RenderFrameCreated called for routing pair "
- << Format(render_frame_host) << " that was previously deleted.";
- }
- }
-
- 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());
- bool was_live = live_routes_.erase(routing_pair);
- bool was_dead_already = !deleted_routes_.insert(routing_pair).second;
-
- if (was_dead_already) {
- FAIL() << "RenderFrameDeleted called more than once for routing pair "
- << Format(render_frame_host);
- } else if (!was_live) {
- FAIL() << "RenderFrameDeleted called for routing pair "
- << Format(render_frame_host)
- << " for which RenderFrameCreated was never called";
- }
- }
-
- private:
- std::string Format(RenderFrameHost* render_frame_host) {
- return base::StringPrintf(
- "(%d, %d -> %s )",
- render_frame_host->GetProcess()->GetID(),
- render_frame_host->GetRoutingID(),
- render_frame_host->GetSiteInstance()->GetSiteURL().spec().c_str());
- }
- std::set<std::pair<int, int> > live_routes_;
- std::set<std::pair<int, int> > deleted_routes_;
-};
-
} // namespace
-class RenderFrameHostManagerTest
- : public RenderViewHostImplTestHarness {
+class RenderFrameHostManagerTest : public RenderViewHostImplTestHarness {
public:
void SetUp() override {
RenderViewHostImplTestHarness::SetUp();
WebUIControllerFactory::RegisterFactory(&factory_);
- lifetime_checker_.reset(new FrameLifetimeConsistencyChecker(contents()));
}
void TearDown() override {
- lifetime_checker_.reset();
RenderViewHostImplTestHarness::TearDown();
WebUIControllerFactory::UnregisterFactoryForTesting(&factory_);
}
@@ -319,17 +287,24 @@ class RenderFrameHostManagerTest
// for us.
controller().LoadURL(
url, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
+ int entry_id = controller().GetPendingEntry()->GetUniqueID();
+
+ // Simulate the BeforeUnload_ACK that is received from the current renderer
+ // for a cross-site navigation.
+ // PlzNavigate: it is necessary to call PrepareForCommit before getting the
+ // main and the pending frame because when we are trying to navigate to a
+ // WebUI from a new tab, a RenderFrameHost is created to display it that is
+ // committed immediately (since it is a new tab). Therefore the main frame
+ // is replaced without a pending frame being created, and we don't get the
+ // right values for the RFH to navigate: we try to use the old one that has
+ // been deleted in the meantime.
+ contents()->GetMainFrame()->PrepareForCommit();
+
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_rfh != active_rfh) {
- old_rfh->SendBeforeUnloadACK(true);
- EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, old_rfh->rfh_state());
- }
+ EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, old_rfh->rfh_state());
// Commit the navigation with a new page ID.
int32 max_page_id = contents()->GetMaxPageIDForSiteInstance(
@@ -339,7 +314,7 @@ class RenderFrameHostManagerTest
// state is being checked.
RenderFrameHostDeletedObserver rfh_observer(old_rfh);
RenderViewHostDeletedObserver rvh_observer(old_rfh->GetRenderViewHost());
- active_rfh->SendNavigate(max_page_id + 1, url);
+ active_rfh->SendNavigate(max_page_id + 1, entry_id, true, url);
// Make sure that we start to run the unload handler at the time of commit.
bool expecting_rfh_shutdown = false;
@@ -402,7 +377,9 @@ class RenderFrameHostManagerTest
// Navigate to a cross-site URL.
contents()->GetController().LoadURL(
kDestUrl, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
- EXPECT_TRUE(contents()->cross_navigation_pending());
+ int entry_id = contents()->GetController().GetPendingEntry()->GetUniqueID();
+ contents()->GetMainFrame()->PrepareForCommit();
+ EXPECT_TRUE(contents()->CrossProcessNavigationPending());
// Manually increase the number of active frames in the
// SiteInstance that ntp_rfh belongs to, to prevent it from being
@@ -416,16 +393,47 @@ class RenderFrameHostManagerTest
// BeforeUnload finishes.
ntp_rfh->SendBeforeUnloadACK(true);
- dest_rfh->SendNavigate(101, kDestUrl);
+ dest_rfh->SendNavigate(101, entry_id, true, kDestUrl);
ntp_rfh->OnSwappedOut();
EXPECT_TRUE(ntp_rfh->is_swapped_out());
return ntp_rfh;
}
+ // Returns the RenderFrameHost that should be used in the navigation to
+ // |entry|.
+ RenderFrameHostImpl* NavigateToEntry(
+ RenderFrameHostManager* manager,
+ const NavigationEntryImpl& entry) {
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation)) {
+ scoped_ptr<NavigationRequest> navigation_request =
+ NavigationRequest::CreateBrowserInitiated(
+ manager->frame_tree_node_, entry, FrameMsg_Navigate_Type::NORMAL,
+ base::TimeTicks::Now(),
+ static_cast<NavigationControllerImpl*>(&controller()));
+ TestRenderFrameHost* frame_host = static_cast<TestRenderFrameHost*>(
+ manager->GetFrameHostForNavigation(*navigation_request));
+ CHECK(frame_host);
+ frame_host->set_pending_commit(true);
+ return frame_host;
+ }
+ return manager->Navigate(entry);
+ }
+
+ // Returns the pending RenderFrameHost.
+ // PlzNavigate: returns the speculative RenderFrameHost.
+ RenderFrameHostImpl* GetPendingFrameHost(
+ RenderFrameHostManager* manager) {
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation)) {
+ return manager->speculative_render_frame_host_.get();
+ }
+ return manager->pending_frame_host();
+ }
+
private:
RenderFrameHostManagerTestWebUIControllerFactory factory_;
- scoped_ptr<FrameLifetimeConsistencyChecker> lifetime_checker_;
};
// Tests that when you navigate from a chrome:// url to another page, and
@@ -454,20 +462,23 @@ TEST_F(RenderFrameHostManagerTest, NewTabPageProcesses) {
// we use the committed one.
contents2->GetController().LoadURL(
kChromeUrl, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
+ int entry_id = contents2->GetController().GetPendingEntry()->GetUniqueID();
+ contents2->GetMainFrame()->PrepareForCommit();
TestRenderFrameHost* ntp_rfh2 = contents2->GetMainFrame();
- EXPECT_FALSE(contents2->cross_navigation_pending());
- ntp_rfh2->SendNavigate(100, kChromeUrl);
+ EXPECT_FALSE(contents2->CrossProcessNavigationPending());
+ ntp_rfh2->SendNavigate(100, entry_id, true, kChromeUrl);
// The second one is the opposite, creating a cross-site transition and
// requiring a beforeunload ack.
contents2->GetController().LoadURL(
kDestUrl, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
- EXPECT_TRUE(contents2->cross_navigation_pending());
+ entry_id = contents2->GetController().GetPendingEntry()->GetUniqueID();
+ contents2->GetMainFrame()->PrepareForCommit();
+ EXPECT_TRUE(contents2->CrossProcessNavigationPending());
TestRenderFrameHost* dest_rfh2 = contents2->GetPendingMainFrame();
ASSERT_TRUE(dest_rfh2);
- ntp_rfh2->SendBeforeUnloadACK(true);
- dest_rfh2->SendNavigate(101, kDestUrl);
+ dest_rfh2->SendNavigate(101, entry_id, true, kDestUrl);
// The two RFH's should be different in every way.
EXPECT_NE(contents()->GetMainFrame()->GetProcess(), dest_rfh2->GetProcess());
@@ -483,8 +494,10 @@ TEST_F(RenderFrameHostManagerTest, NewTabPageProcesses) {
contents2->GetController().LoadURL(
kChromeUrl, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
- dest_rfh2->SendBeforeUnloadACK(true);
- contents2->GetPendingMainFrame()->SendNavigate(102, kChromeUrl);
+ entry_id = contents2->GetController().GetPendingEntry()->GetUniqueID();
+ contents2->GetMainFrame()->PrepareForCommit();
+ contents2->GetPendingMainFrame()->SendNavigate(102, entry_id, true,
+ kChromeUrl);
EXPECT_NE(contents()->GetMainFrame()->GetSiteInstance(),
contents2->GetMainFrame()->GetSiteInstance());
@@ -507,7 +520,6 @@ TEST_F(RenderFrameHostManagerTest, FilterMessagesWhileSwappedOut) {
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_rfh->GetRenderViewHost()->OnMessageReceived(
@@ -520,7 +532,6 @@ TEST_F(RenderFrameHostManagerTest, FilterMessagesWhileSwappedOut) {
// site.
ntp_rfh->GetSiteInstance()->increment_active_frame_count();
-
// Navigate to a cross-site URL.
NavigateActiveAndCommit(kDestUrl);
TestRenderFrameHost* dest_rfh = contents()->GetMainFrame();
@@ -528,7 +539,6 @@ TEST_F(RenderFrameHostManagerTest, FilterMessagesWhileSwappedOut) {
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(
@@ -567,8 +577,7 @@ TEST_F(RenderFrameHostManagerTest, FilterMessagesWhileSwappedOut) {
// 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_rfh->GetProcess());
+ MockRenderProcessHost* ntp_process_host = ntp_rfh->GetProcess();
ntp_process_host->sink().ClearMessages();
const base::string16 msg = base::ASCIIToUTF16("Message");
bool result = false;
@@ -590,6 +599,63 @@ TEST_F(RenderFrameHostManagerTest, FilterMessagesWhileSwappedOut) {
EXPECT_TRUE(ntp_process_host->sink().GetUniqueMessageMatching(IPC_REPLY_ID));
}
+// Test that the ViewHostMsg_UpdateFaviconURL IPC message is ignored if the
+// renderer is in the STATE_PENDING_SWAP_OUT_STATE. The favicon code assumes
+// that it only gets ViewHostMsg_UpdateFaviconURL messages for the most recently
+// committed navigation for each WebContentsImpl.
+TEST_F(RenderFrameHostManagerTest, UpdateFaviconURLWhilePendingSwapOut) {
+ const GURL kChromeURL("chrome://foo");
+ const GURL kDestUrl("http://www.google.com/");
+ std::vector<FaviconURL> icons;
+
+ // Navigate our first tab to a chrome url and then to the destination.
+ NavigateActiveAndCommit(kChromeURL);
+ TestRenderFrameHost* rfh1 = contents()->GetMainFrame();
+
+ // Send an update favicon message and make sure it works.
+ {
+ PluginFaviconMessageObserver observer(contents());
+ EXPECT_TRUE(rfh1->GetRenderViewHost()->OnMessageReceived(
+ ViewHostMsg_UpdateFaviconURL(
+ rfh1->GetRenderViewHost()->GetRoutingID(), icons)));
+ EXPECT_TRUE(observer.favicon_received());
+ }
+
+ // Create one more frame in the same SiteInstance where |rfh1| exists so that
+ // it doesn't get deleted on navigation to another site.
+ rfh1->GetSiteInstance()->increment_active_frame_count();
+
+ // Navigate to a cross-site URL and commit the new page.
+ controller().LoadURL(
+ kDestUrl, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
+ int entry_id = controller().GetPendingEntry()->GetUniqueID();
+ contents()->GetMainFrame()->PrepareForCommit();
+ TestRenderFrameHost* rfh2 = contents()->GetPendingMainFrame();
+ contents()->TestDidNavigate(rfh2, 1, entry_id, true, kDestUrl,
+ ui::PAGE_TRANSITION_TYPED);
+ EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, rfh2->rfh_state());
+ EXPECT_EQ(RenderFrameHostImpl::STATE_PENDING_SWAP_OUT, rfh1->rfh_state());
+
+ // The new RVH should be able to update its favicons.
+ {
+ PluginFaviconMessageObserver observer(contents());
+ EXPECT_TRUE(rfh2->GetRenderViewHost()->OnMessageReceived(
+ ViewHostMsg_UpdateFaviconURL(rfh2->GetRenderViewHost()->GetRoutingID(),
+ icons)));
+ EXPECT_TRUE(observer.favicon_received());
+ }
+
+ // The old renderer, being slow, now updates its favicons. The message should
+ // be ignored.
+ {
+ PluginFaviconMessageObserver observer(contents());
+ EXPECT_TRUE(rfh1->GetRenderViewHost()->OnMessageReceived(
+ ViewHostMsg_UpdateFaviconURL(rfh1->GetRenderViewHost()->GetRoutingID(),
+ icons)));
+ EXPECT_FALSE(observer.favicon_received());
+ }
+}
+
// 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
@@ -604,7 +670,8 @@ TEST_F(RenderFrameHostManagerTest, DropCreateChildFrameWhileSwappedOut) {
{
RenderFrameHostCreatedObserver observer(contents());
initial_rfh->OnCreateChildFrame(
- initial_rfh->GetProcess()->GetNextRoutingID(), std::string());
+ initial_rfh->GetProcess()->GetNextRoutingID(), std::string(),
+ SandboxFlags::NONE);
EXPECT_TRUE(observer.created());
}
@@ -626,7 +693,8 @@ TEST_F(RenderFrameHostManagerTest, DropCreateChildFrameWhileSwappedOut) {
// to create child frames.
RenderFrameHostCreatedObserver observer(contents());
initial_rfh->OnCreateChildFrame(
- initial_rfh->GetProcess()->GetNextRoutingID(), std::string());
+ initial_rfh->GetProcess()->GetNextRoutingID(), std::string(),
+ SandboxFlags::NONE);
EXPECT_FALSE(observer.created());
}
}
@@ -638,8 +706,7 @@ TEST_F(RenderFrameHostManagerTest, WhiteListSwapCompositorFrame) {
swapped_out_rfh->GetRenderViewHost()->GetView());
EXPECT_FALSE(swapped_out_rwhv->did_swap_compositor_frame());
- MockRenderProcessHost* process_host =
- static_cast<MockRenderProcessHost*>(swapped_out_rfh->GetProcess());
+ MockRenderProcessHost* process_host = swapped_out_rfh->GetProcess();
process_host->sink().ClearMessages();
cc::CompositorFrame frame;
@@ -801,33 +868,40 @@ TEST_F(RenderFrameHostManagerTest,
// EnableViewSourceMode message is sent on every navigation regardless
// RenderView is being newly created or reused.
TEST_F(RenderFrameHostManagerTest, AlwaysSendEnableViewSourceMode) {
- const GURL kChromeUrl("chrome://foo");
- const GURL kUrl("view-source:http://foo");
+ const GURL kChromeUrl("chrome://foo/");
+ const GURL kUrl("http://foo/");
+ const GURL kViewSourceUrl("view-source:http://foo/");
// We have to navigate to some page at first since without this, the first
// navigation will reuse the SiteInstance created by Init(), and the second
// one will create a new SiteInstance. Because current_instance and
// new_instance will be different, a new RenderViewHost will be created for
// the second navigation. We have to avoid this in order to exercise the
- // target code patch.
+ // target code path.
NavigateActiveAndCommit(kChromeUrl);
- // Navigate.
+ // Navigate. Note that "view source" URLs are implemented by putting the RFH
+ // into a view-source mode and then navigating to the inner URL, so that's why
+ // the bare URL is what's committed and returned by the last committed entry's
+ // GetURL() call.
controller().LoadURL(
- kUrl, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ kViewSourceUrl, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ int entry_id = controller().GetPendingEntry()->GetUniqueID();
+
// Simulate response from RenderFrame for DispatchBeforeUnload.
- base::TimeTicks now = base::TimeTicks::Now();
- contents()->GetMainFrame()->OnMessageReceived(FrameHostMsg_BeforeUnload_ACK(
- contents()->GetMainFrame()->GetRoutingID(), true, now, now));
+ contents()->GetMainFrame()->PrepareForCommit();
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());
+ contents()->GetPendingMainFrame()->SendNavigate(new_id, entry_id, true, kUrl);
+
+ EXPECT_EQ(1, controller().GetLastCommittedEntryIndex());
+ NavigationEntry* last_committed = controller().GetLastCommittedEntry();
+ ASSERT_NE(nullptr, last_committed);
+ EXPECT_EQ(kUrl, last_committed->GetURL());
+ EXPECT_EQ(kViewSourceUrl, last_committed->GetVirtualURL());
EXPECT_FALSE(controller().GetPendingEntry());
// Because we're using TestWebContents and TestRenderViewHost in this
// unittest, no one calls WebContentsImpl::RenderViewCreated(). So, we see no
@@ -835,16 +909,23 @@ TEST_F(RenderFrameHostManagerTest, AlwaysSendEnableViewSourceMode) {
// Clear queued messages before load.
process()->sink().ClearMessages();
+
// Navigate, again.
controller().LoadURL(
- kUrl, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ kViewSourceUrl, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ entry_id = controller().GetPendingEntry()->GetUniqueID();
+ contents()->GetMainFrame()->PrepareForCommit();
+
// The same RenderViewHost should be reused.
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_EQ(last_rfh, contents()->GetMainFrame());
+
+ // The renderer sends a commit.
+ contents()->GetMainFrame()->SendNavigateWithTransition(
+ new_id, entry_id, false, kUrl, ui::PAGE_TRANSITION_TYPED);
+ EXPECT_EQ(1, controller().GetLastCommittedEntryIndex());
EXPECT_FALSE(controller().GetPendingEntry());
+
// New message should be sent out to make sure to enter view-source mode.
EXPECT_TRUE(process()->sink().GetUniqueMessageMatching(
ViewMsg_EnableViewSourceMode::ID));
@@ -876,14 +957,11 @@ TEST_F(RenderFrameHostManagerTest, Init) {
// Tests the Navigate function. We navigate three sites consecutively and check
// how the pending/committed RenderViewHost are modified.
TEST_F(RenderFrameHostManagerTest, Navigate) {
- 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()));
+ RenderViewHostChangedObserver change_observer(web_contents.get());
RenderFrameHostManager* manager = web_contents->GetRenderManagerForTesting();
RenderFrameHostImpl* host = NULL;
@@ -894,15 +972,15 @@ TEST_F(RenderFrameHostManagerTest, Navigate) {
NULL /* instance */, -1 /* page_id */, kUrl1, Referrer(),
base::string16() /* title */, ui::PAGE_TRANSITION_TYPED,
false /* is_renderer_init */);
- host = manager->Navigate(entry1);
+ host = NavigateToEntry(manager, entry1);
// The RenderFrameHost created in Init will be reused.
EXPECT_TRUE(host == manager->current_frame_host());
- EXPECT_FALSE(manager->pending_frame_host());
+ EXPECT_FALSE(GetPendingFrameHost(manager));
// Commit.
- manager->DidNavigateFrame(host);
- // Commit to SiteInstance should be delayed until RenderView commit.
+ manager->DidNavigateFrame(host, true);
+ // Commit to SiteInstance should be delayed until RenderFrame commit.
EXPECT_TRUE(host == manager->current_frame_host());
ASSERT_TRUE(host);
EXPECT_FALSE(host->GetSiteInstance()->HasSite());
@@ -915,14 +993,14 @@ TEST_F(RenderFrameHostManagerTest, Navigate) {
Referrer(kUrl1, blink::WebReferrerPolicyDefault),
base::string16() /* title */, ui::PAGE_TRANSITION_LINK,
true /* is_renderer_init */);
- host = manager->Navigate(entry2);
+ host = NavigateToEntry(manager, entry2);
// The RenderFrameHost created in Init will be reused.
EXPECT_TRUE(host == manager->current_frame_host());
- EXPECT_FALSE(manager->pending_frame_host());
+ EXPECT_FALSE(GetPendingFrameHost(manager));
// Commit.
- manager->DidNavigateFrame(host);
+ manager->DidNavigateFrame(host, true);
EXPECT_TRUE(host == manager->current_frame_host());
ASSERT_TRUE(host);
EXPECT_TRUE(host->GetSiteInstance()->HasSite());
@@ -934,25 +1012,24 @@ TEST_F(RenderFrameHostManagerTest, Navigate) {
Referrer(kUrl2, blink::WebReferrerPolicyDefault),
base::string16() /* title */, ui::PAGE_TRANSITION_LINK,
false /* is_renderer_init */);
- host = manager->Navigate(entry3);
+ host = NavigateToEntry(manager, entry3);
// A new RenderFrameHost should be created.
- EXPECT_TRUE(manager->pending_frame_host());
- ASSERT_EQ(host, manager->pending_frame_host());
+ EXPECT_TRUE(GetPendingFrameHost(manager));
+ ASSERT_EQ(host, GetPendingFrameHost(manager));
- notifications.Reset();
+ change_observer.Reset();
// Commit.
- manager->DidNavigateFrame(manager->pending_frame_host());
+ manager->DidNavigateFrame(GetPendingFrameHost(manager), true);
EXPECT_TRUE(host == manager->current_frame_host());
ASSERT_TRUE(host);
EXPECT_TRUE(host->GetSiteInstance()->HasSite());
// Check the pending RenderFrameHost has been committed.
- EXPECT_FALSE(manager->pending_frame_host());
+ EXPECT_FALSE(GetPendingFrameHost(manager));
- // We should observe a notification.
- EXPECT_TRUE(
- notifications.Check1AndReset(NOTIFICATION_RENDER_VIEW_HOST_CHANGED));
+ // We should observe RVH changed event.
+ EXPECT_TRUE(change_observer.DidHostChange());
}
// Tests WebUI creation.
@@ -963,24 +1040,28 @@ TEST_F(RenderFrameHostManagerTest, WebUI) {
scoped_ptr<TestWebContents> web_contents(
TestWebContents::Create(browser_context(), instance));
RenderFrameHostManager* manager = web_contents->GetRenderManagerForTesting();
+ RenderFrameHostImpl* initial_rfh = manager->current_frame_host();
EXPECT_FALSE(manager->current_host()->IsRenderViewLive());
+ EXPECT_FALSE(manager->web_ui());
+ EXPECT_TRUE(initial_rfh);
const GURL kUrl("chrome://foo");
NavigationEntryImpl entry(NULL /* instance */, -1 /* page_id */, kUrl,
Referrer(), base::string16() /* title */,
ui::PAGE_TRANSITION_TYPED,
false /* is_renderer_init */);
- RenderFrameHostImpl* host = manager->Navigate(entry);
+ RenderFrameHostImpl* host = NavigateToEntry(manager, entry);
// We commit the pending RenderFrameHost immediately because the previous
// RenderFrameHost was not live. We test a case where it is live in
// WebUIInNewTab.
EXPECT_TRUE(host);
+ EXPECT_NE(initial_rfh, host);
EXPECT_EQ(host, manager->current_frame_host());
- EXPECT_FALSE(manager->pending_frame_host());
+ EXPECT_FALSE(GetPendingFrameHost(manager));
- // It's important that the site instance get set on the Web UI page as soon
+ // It's important that the SiteInstance get set on the Web UI page as soon
// 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.
@@ -989,11 +1070,16 @@ TEST_F(RenderFrameHostManagerTest, WebUI) {
// The Web UI is committed immediately because the RenderViewHost has not been
// used yet. UpdateStateForNavigate() took the short cut path.
- EXPECT_FALSE(manager->pending_web_ui());
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation)) {
+ EXPECT_FALSE(manager->speculative_web_ui());
+ } else {
+ EXPECT_FALSE(manager->pending_web_ui());
+ }
EXPECT_TRUE(manager->web_ui());
// Commit.
- manager->DidNavigateFrame(host);
+ manager->DidNavigateFrame(host, true);
EXPECT_TRUE(
host->render_view_host()->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
}
@@ -1021,17 +1107,17 @@ TEST_F(RenderFrameHostManagerTest, WebUIInNewTab) {
Referrer(), base::string16() /* title */,
ui::PAGE_TRANSITION_TYPED,
false /* is_renderer_init */);
- RenderFrameHostImpl* host1 = manager1->Navigate(entry1);
+ RenderFrameHostImpl* host1 = NavigateToEntry(manager1, entry1);
// We should have a pending navigation to the WebUI RenderViewHost.
// It should already have bindings.
- EXPECT_EQ(host1, manager1->pending_frame_host());
+ EXPECT_EQ(host1, GetPendingFrameHost(manager1));
EXPECT_NE(host1, manager1->current_frame_host());
EXPECT_TRUE(
host1->render_view_host()->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
// Commit and ensure we still have bindings.
- manager1->DidNavigateFrame(host1);
+ manager1->DidNavigateFrame(host1, true);
SiteInstance* webui_instance = host1->GetSiteInstance();
EXPECT_EQ(host1, manager1->current_frame_host());
EXPECT_TRUE(
@@ -1046,25 +1132,69 @@ TEST_F(RenderFrameHostManagerTest, WebUIInNewTab) {
// RenderWidgetHost::Init when opening a new tab from a link.
manager2->current_host()->CreateRenderView(
base::string16(), -1, MSG_ROUTING_NONE, -1, false);
+ EXPECT_TRUE(manager2->current_host()->IsRenderViewLive());
const GURL kUrl2("chrome://foo/bar");
NavigationEntryImpl entry2(NULL /* instance */, -1 /* page_id */, kUrl2,
Referrer(), base::string16() /* title */,
ui::PAGE_TRANSITION_LINK,
true /* is_renderer_init */);
- RenderFrameHostImpl* host2 = manager2->Navigate(entry2);
+ RenderFrameHostImpl* host2 = NavigateToEntry(manager2, entry2);
// No cross-process transition happens because we are already in the right
// SiteInstance. We should grant bindings immediately.
EXPECT_EQ(host2, manager2->current_frame_host());
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation)) {
+ EXPECT_TRUE(manager2->speculative_web_ui());
+ } else {
+ EXPECT_TRUE(manager2->pending_web_ui());
+ }
EXPECT_TRUE(
host2->render_view_host()->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
- manager2->DidNavigateFrame(host2);
+ manager2->DidNavigateFrame(host2, true);
+}
+
+// Tests that a WebUI is correctly reused between chrome:// pages.
+TEST_F(RenderFrameHostManagerTest, WebUIWasReused) {
+ set_should_create_webui(true);
+
+ // Navigate to a WebUI page.
+ const GURL kUrl1("chrome://foo");
+ contents()->NavigateAndCommit(kUrl1);
+ RenderFrameHostManager* manager =
+ main_test_rfh()->frame_tree_node()->render_manager();
+ WebUIImpl* web_ui = manager->web_ui();
+ EXPECT_TRUE(web_ui);
+
+ // Navigate to another WebUI page which should be same-site and keep the
+ // current WebUI.
+ const GURL kUrl2("chrome://foo/bar");
+ contents()->NavigateAndCommit(kUrl2);
+ EXPECT_EQ(web_ui, manager->web_ui());
+}
+
+// Tests that a WebUI is correctly cleaned up when navigating from a chrome://
+// page to a non-chrome:// page.
+TEST_F(RenderFrameHostManagerTest, WebUIWasCleared) {
+ set_should_create_webui(true);
+
+ // Navigate to a WebUI page.
+ const GURL kUrl1("chrome://foo");
+ contents()->NavigateAndCommit(kUrl1);
+ EXPECT_TRUE(main_test_rfh()->frame_tree_node()->render_manager()->web_ui());
+
+ // Navigate to a non-WebUI page.
+ const GURL kUrl2("http://www.google.com");
+ contents()->NavigateAndCommit(kUrl2);
+ EXPECT_FALSE(main_test_rfh()->frame_tree_node()->render_manager()->web_ui());
}
// Tests that we don't end up in an inconsistent state if a page does a back and
// then reload. http://crbug.com/51680
+// Also tests that only user-gesture navigations can interrupt cross-process
+// navigations. http://crbug.com/75195
TEST_F(RenderFrameHostManagerTest, PageDoesBackAndReload) {
const GURL kUrl1("http://www.google.com/");
const GURL kUrl2("http://www.evil-site.com/");
@@ -1079,6 +1209,7 @@ TEST_F(RenderFrameHostManagerTest, PageDoesBackAndReload) {
// Now let's simulate the evil page calling history.back().
contents()->OnGoToEntryAtOffset(-1);
+ contents()->GetMainFrame()->PrepareForCommit();
// 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.
@@ -1088,7 +1219,9 @@ TEST_F(RenderFrameHostManagerTest, PageDoesBackAndReload) {
// Before that RFH has committed, the evil page reloads itself.
FrameHostMsg_DidCommitProvisionalLoad_Params params;
- params.page_id = 1;
+ params.page_id = 0;
+ params.nav_entry_id = 0;
+ params.did_create_new_entry = false;
params.url = kUrl2;
params.transition = ui::PAGE_TRANSITION_CLIENT_REDIRECT;
params.should_update_history = false;
@@ -1100,8 +1233,30 @@ TEST_F(RenderFrameHostManagerTest, PageDoesBackAndReload) {
contents()->GetFrameTree()->root()->navigator()->DidNavigate(evil_rfh,
params);
- // That should have cancelled the pending RFH, and the evil RFH should be the
- // current one.
+ // That should NOT have cancelled the pending RFH, because the reload did
+ // not have a user gesture. Thus, the pending back navigation will still
+ // eventually commit.
+ EXPECT_TRUE(contents()->GetRenderManagerForTesting()->
+ pending_render_view_host() != NULL);
+ 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);
+ NavigationEntry* entry = contents()->GetController().GetVisibleEntry();
+ ASSERT_TRUE(entry != NULL);
+ EXPECT_EQ(kUrl2, entry->GetURL());
+
+ // Now do the same but as a user gesture.
+ params.gesture = NavigationGestureUser;
+ contents()->GetFrameTree()->root()->navigator()->DidNavigate(evil_rfh,
+ params);
+
+ // User navigation should have cancelled the pending RFH.
EXPECT_TRUE(contents()->GetRenderManagerForTesting()->
pending_render_view_host() == NULL);
EXPECT_TRUE(contents()->GetRenderManagerForTesting()->pending_frame_host() ==
@@ -1113,7 +1268,7 @@ TEST_F(RenderFrameHostManagerTest, PageDoesBackAndReload) {
// Also we should not have a pending navigation entry.
EXPECT_TRUE(contents()->GetController().GetPendingEntry() == NULL);
- NavigationEntry* entry = contents()->GetController().GetVisibleEntry();
+ entry = contents()->GetController().GetVisibleEntry();
ASSERT_TRUE(entry != NULL);
EXPECT_EQ(kUrl2, entry->GetURL());
}
@@ -1140,21 +1295,23 @@ TEST_F(RenderFrameHostManagerTest, NavigateAfterMissingSwapOutACK) {
// happen, but we have seen it when going back quickly across many entries
// (http://crbug.com/93427).
contents()->GetController().GoBack();
- EXPECT_TRUE(rfh2->is_waiting_for_beforeunload_ack());
- contents()->ProceedWithCrossSiteNavigation();
- EXPECT_FALSE(rfh2->is_waiting_for_beforeunload_ack());
+ EXPECT_TRUE(rfh2->IsWaitingForBeforeUnloadACK());
+ contents()->GetMainFrame()->PrepareForCommit();
+ EXPECT_FALSE(rfh2->IsWaitingForBeforeUnloadACK());
// The back navigation commits.
const NavigationEntry* entry1 = contents()->GetController().GetPendingEntry();
- rfh1->SendNavigate(entry1->GetPageID(), entry1->GetURL());
+ rfh1->SendNavigate(entry1->GetPageID(), entry1->GetUniqueID(), false,
+ 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();
+ contents()->GetMainFrame()->PrepareForCommit();
const NavigationEntry* entry2 = contents()->GetController().GetPendingEntry();
- rfh2->SendNavigate(entry2->GetPageID(), entry2->GetURL());
+ rfh2->SendNavigate(entry2->GetPageID(), entry2->GetUniqueID(), false,
+ 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());
@@ -1323,7 +1480,7 @@ TEST_F(RenderFrameHostManagerTest, DisownOpenerDuringNavigation) {
// Start a back navigation so that rfh1 becomes the pending RFH.
contents()->GetController().GoBack();
- contents()->ProceedWithCrossSiteNavigation();
+ contents()->GetMainFrame()->PrepareForCommit();
// Disown the opener from rfh2.
rfh2->DidDisownOpener();
@@ -1333,7 +1490,8 @@ TEST_F(RenderFrameHostManagerTest, DisownOpenerDuringNavigation) {
// The back navigation commits.
const NavigationEntry* entry1 = contents()->GetController().GetPendingEntry();
- rfh1->SendNavigate(entry1->GetPageID(), entry1->GetURL());
+ rfh1->SendNavigate(entry1->GetPageID(), entry1->GetUniqueID(), false,
+ entry1->GetURL());
// Ensure the opener is still cleared.
EXPECT_FALSE(contents()->HasOpener());
@@ -1364,9 +1522,10 @@ TEST_F(RenderFrameHostManagerTest, DisownOpenerAfterNavigation) {
// Commit a back navigation before the DidDisownOpener message arrives.
// rfh1 will be kept alive because of the opener tab.
contents()->GetController().GoBack();
- contents()->ProceedWithCrossSiteNavigation();
+ contents()->GetMainFrame()->PrepareForCommit();
const NavigationEntry* entry1 = contents()->GetController().GetPendingEntry();
- rfh1->SendNavigate(entry1->GetPageID(), entry1->GetURL());
+ rfh1->SendNavigate(entry1->GetPageID(), entry1->GetUniqueID(), false,
+ entry1->GetURL());
// Disown the opener from rfh2.
rfh2->DidDisownOpener();
@@ -1381,11 +1540,11 @@ TEST_F(RenderFrameHostManagerTest, CleanUpSwappedOutRVHOnProcessCrash) {
// Navigate to an initial URL.
contents()->NavigateAndCommit(kUrl1);
- TestRenderViewHost* rvh1 = test_rvh();
+ TestRenderFrameHost* rfh1 = contents()->GetMainFrame();
// Create a new tab as an opener for the main tab.
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());
@@ -1397,33 +1556,33 @@ TEST_F(RenderFrameHostManagerTest, CleanUpSwappedOutRVHOnProcessCrash) {
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(
- rvh1->GetSiteInstance()));
+ EXPECT_FALSE(
+ opener1_manager->GetSwappedOutRenderViewHost(rfh1->GetSiteInstance()));
opener1->NavigateAndCommit(kUrl2);
- EXPECT_TRUE(opener1_manager->GetSwappedOutRenderViewHost(
- rvh1->GetSiteInstance()));
+ EXPECT_TRUE(
+ opener1_manager->GetSwappedOutRenderViewHost(rfh1->GetSiteInstance()));
// Fake a process crash.
- RenderProcessHost::RendererClosedDetails details(
- rvh1->GetProcess()->GetHandle(),
- base::TERMINATION_STATUS_PROCESS_CRASHED,
- 0);
- NotificationService::current()->Notify(
- NOTIFICATION_RENDERER_PROCESS_CLOSED,
- Source<RenderProcessHost>(rvh1->GetProcess()),
- Details<RenderProcessHost::RendererClosedDetails>(&details));
- rvh1->set_render_view_created(false);
-
- // Ensure that the swapped out RenderViewHost has been deleted.
- EXPECT_FALSE(opener1_manager->GetSwappedOutRenderViewHost(
- rvh1->GetSiteInstance()));
+ rfh1->GetProcess()->SimulateCrash();
+
+ // Ensure that the RenderFrameProxyHost stays around and the RenderFrameProxy
+ // is deleted.
+ RenderFrameProxyHost* render_frame_proxy_host =
+ opener1_manager->GetRenderFrameProxyHost(rfh1->GetSiteInstance());
+ EXPECT_TRUE(render_frame_proxy_host);
+ EXPECT_FALSE(render_frame_proxy_host->is_render_frame_proxy_live());
+
+ // Expect the swapped out RVH to exist.
+ EXPECT_TRUE(
+ opener1_manager->GetSwappedOutRenderViewHost(rfh1->GetSiteInstance()));
// Reload the initial tab. This should recreate the opener's swapped out RVH
// in the original SiteInstance.
contents()->GetController().Reload(true);
+ contents()->GetMainFrame()->PrepareForCommit();
EXPECT_EQ(opener1_manager->GetSwappedOutRenderViewHost(
- rvh1->GetSiteInstance())->GetRoutingID(),
- test_rvh()->opener_route_id());
+ rfh1->GetSiteInstance())->GetRoutingID(),
+ contents()->GetMainFrame()->GetRenderViewHost()->opener_route_id());
}
// Test that RenderViewHosts created for WebUI navigations are properly
@@ -1474,8 +1633,6 @@ TEST_F(RenderFrameHostManagerTest, EnableWebUIWithSwappedOutOpener) {
// Test that we reuse the same guest SiteInstance if we navigate across sites.
TEST_F(RenderFrameHostManagerTest, NoSwapOnGuestNavigations) {
- TestNotificationTracker notifications;
-
GURL guest_url(std::string(kGuestScheme).append("://abc123"));
SiteInstance* instance =
SiteInstance::CreateForURL(browser_context(), guest_url);
@@ -1492,7 +1649,7 @@ TEST_F(RenderFrameHostManagerTest, NoSwapOnGuestNavigations) {
NULL /* instance */, -1 /* page_id */, kUrl1, Referrer(),
base::string16() /* title */, ui::PAGE_TRANSITION_TYPED,
false /* is_renderer_init */);
- host = manager->Navigate(entry1);
+ host = NavigateToEntry(manager, entry1);
// The RenderFrameHost created in Init will be reused.
EXPECT_TRUE(host == manager->current_frame_host());
@@ -1500,8 +1657,8 @@ TEST_F(RenderFrameHostManagerTest, NoSwapOnGuestNavigations) {
EXPECT_EQ(manager->current_frame_host()->GetSiteInstance(), instance);
// Commit.
- manager->DidNavigateFrame(host);
- // Commit to SiteInstance should be delayed until RenderView commit.
+ manager->DidNavigateFrame(host, true);
+ // Commit to SiteInstance should be delayed until RenderFrame commit.
EXPECT_EQ(host, manager->current_frame_host());
ASSERT_TRUE(host);
EXPECT_TRUE(host->GetSiteInstance()->HasSite());
@@ -1514,14 +1671,14 @@ TEST_F(RenderFrameHostManagerTest, NoSwapOnGuestNavigations) {
Referrer(kUrl1, blink::WebReferrerPolicyDefault),
base::string16() /* title */, ui::PAGE_TRANSITION_LINK,
true /* is_renderer_init */);
- host = manager->Navigate(entry2);
+ host = NavigateToEntry(manager, entry2);
// The RenderFrameHost created in Init will be reused.
EXPECT_EQ(host, manager->current_frame_host());
EXPECT_FALSE(manager->pending_frame_host());
// Commit.
- manager->DidNavigateFrame(host);
+ manager->DidNavigateFrame(host, true);
EXPECT_EQ(host, manager->current_frame_host());
ASSERT_TRUE(host);
EXPECT_EQ(host->GetSiteInstance(), instance);
@@ -1537,9 +1694,8 @@ TEST_F(RenderFrameHostManagerTest, NavigateWithEarlyClose) {
BeforeUnloadFiredWebContentsDelegate delegate;
scoped_ptr<TestWebContents> web_contents(
TestWebContents::Create(browser_context(), instance));
+ RenderViewHostChangedObserver change_observer(web_contents.get());
web_contents->SetDelegate(&delegate);
- notifications.ListenFor(NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
- Source<WebContents>(web_contents.get()));
RenderFrameHostManager* manager = web_contents->GetRenderManagerForTesting();
@@ -1549,19 +1705,17 @@ TEST_F(RenderFrameHostManagerTest, NavigateWithEarlyClose) {
Referrer(), base::string16() /* title */,
ui::PAGE_TRANSITION_TYPED,
false /* is_renderer_init */);
- RenderFrameHostImpl* host = manager->Navigate(entry1);
+ RenderFrameHostImpl* host = NavigateToEntry(manager, entry1);
// The RenderFrameHost created in Init will be reused.
EXPECT_EQ(host, manager->current_frame_host());
- EXPECT_FALSE(manager->pending_frame_host());
+ EXPECT_FALSE(GetPendingFrameHost(manager));
- // We should observe a notification.
- EXPECT_TRUE(
- notifications.Check1AndReset(NOTIFICATION_RENDER_VIEW_HOST_CHANGED));
- notifications.Reset();
+ // We should observe RVH changed event.
+ EXPECT_TRUE(change_observer.DidHostChange());
// Commit.
- manager->DidNavigateFrame(host);
+ manager->DidNavigateFrame(host, true);
// Commit to SiteInstance should be delayed until RenderFrame commits.
EXPECT_EQ(host, manager->current_frame_host());
@@ -1574,15 +1728,15 @@ TEST_F(RenderFrameHostManagerTest, NavigateWithEarlyClose) {
NULL /* instance */, -1 /* page_id */, kUrl2, Referrer(),
base::string16() /* title */, ui::PAGE_TRANSITION_TYPED,
false /* is_renderer_init */);
- RenderFrameHostImpl* host2 = manager->Navigate(entry2);
+ RenderFrameHostImpl* host2 = NavigateToEntry(manager, entry2);
// A new RenderFrameHost should be created.
- ASSERT_EQ(host2, manager->pending_frame_host());
+ ASSERT_EQ(host2, GetPendingFrameHost(manager));
EXPECT_NE(host2, host);
EXPECT_EQ(host, manager->current_frame_host());
EXPECT_FALSE(manager->current_frame_host()->is_swapped_out());
- EXPECT_EQ(host2, manager->pending_frame_host());
+ EXPECT_EQ(host2, GetPendingFrameHost(manager));
// 3) Close the tab. -------------------------
notifications.ListenFor(NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED,
@@ -1591,7 +1745,7 @@ TEST_F(RenderFrameHostManagerTest, NavigateWithEarlyClose) {
EXPECT_TRUE(
notifications.Check1AndReset(NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED));
- EXPECT_FALSE(manager->pending_frame_host());
+ EXPECT_FALSE(GetPendingFrameHost(manager));
EXPECT_EQ(host, manager->current_frame_host());
}
@@ -1613,7 +1767,11 @@ TEST_F(RenderFrameHostManagerTest, CloseWithPendingWhileUnresponsive) {
// Start a navigation to a new site.
controller().LoadURL(
kUrl2, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
- EXPECT_TRUE(contents()->cross_navigation_pending());
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation)) {
+ rfh1->PrepareForCommit();
+ }
+ EXPECT_TRUE(contents()->CrossProcessNavigationPending());
// Simulate the unresponsiveness timer. The tab should close.
contents()->RendererUnresponsive(rfh1->render_view_host());
@@ -1636,22 +1794,22 @@ TEST_F(RenderFrameHostManagerTest, DeleteFrameAfterSwapOutACK) {
// Navigate to new site, simulating onbeforeunload approval.
controller().LoadURL(
kUrl2, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
- base::TimeTicks now = base::TimeTicks::Now();
- contents()->GetMainFrame()->OnMessageReceived(
- FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
- EXPECT_TRUE(contents()->cross_navigation_pending());
+ int entry_id = controller().GetPendingEntry()->GetUniqueID();
+ contents()->GetMainFrame()->PrepareForCommit();
+ EXPECT_TRUE(contents()->CrossProcessNavigationPending());
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_TRUE(contents()->CrossProcessNavigationPending());
EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, rfh1->rfh_state());
// The new page commits.
- contents()->TestDidNavigate(rfh2, 1, kUrl2, ui::PAGE_TRANSITION_TYPED);
- EXPECT_FALSE(contents()->cross_navigation_pending());
+ contents()->TestDidNavigate(rfh2, 1, entry_id, true, kUrl2,
+ ui::PAGE_TRANSITION_TYPED);
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
EXPECT_EQ(rfh2, contents()->GetMainFrame());
EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL);
EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, rfh2->rfh_state());
@@ -1686,16 +1844,16 @@ TEST_F(RenderFrameHostManagerTest, SwapOutFrameAfterSwapOutACK) {
// Navigate to new site, simulating onbeforeunload approval.
controller().LoadURL(
kUrl2, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
- base::TimeTicks now = base::TimeTicks::Now();
- contents()->GetMainFrame()->OnMessageReceived(
- FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
- EXPECT_TRUE(contents()->cross_navigation_pending());
+ int entry_id = controller().GetPendingEntry()->GetUniqueID();
+ contents()->GetMainFrame()->PrepareForCommit();
+ EXPECT_TRUE(contents()->CrossProcessNavigationPending());
EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, rfh1->rfh_state());
TestRenderFrameHost* rfh2 = contents()->GetPendingMainFrame();
// The new page commits.
- contents()->TestDidNavigate(rfh2, 1, kUrl2, ui::PAGE_TRANSITION_TYPED);
- EXPECT_FALSE(contents()->cross_navigation_pending());
+ contents()->TestDidNavigate(rfh2, 1, entry_id, true, kUrl2,
+ ui::PAGE_TRANSITION_TYPED);
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
EXPECT_EQ(rfh2, contents()->GetMainFrame());
EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL);
EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, rfh2->rfh_state());
@@ -1731,15 +1889,15 @@ TEST_F(RenderFrameHostManagerTest,
// Navigate to new site, simulating onbeforeunload approval.
controller().LoadURL(
kUrl2, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
- base::TimeTicks now = base::TimeTicks::Now();
- rfh1->OnMessageReceived(
- FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
- EXPECT_TRUE(contents()->cross_navigation_pending());
+ int entry_id = controller().GetPendingEntry()->GetUniqueID();
+ rfh1->PrepareForCommit();
+ EXPECT_TRUE(contents()->CrossProcessNavigationPending());
TestRenderFrameHost* rfh2 = contents()->GetPendingMainFrame();
// The new page commits.
- contents()->TestDidNavigate(rfh2, 1, kUrl2, ui::PAGE_TRANSITION_TYPED);
- EXPECT_FALSE(contents()->cross_navigation_pending());
+ contents()->TestDidNavigate(rfh2, 1, entry_id, true, kUrl2,
+ ui::PAGE_TRANSITION_TYPED);
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
EXPECT_EQ(rfh2, contents()->GetMainFrame());
EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL);
EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, rfh2->rfh_state());
@@ -1778,7 +1936,7 @@ TEST_F(RenderFrameHostManagerTest,
// Cancel the navigation by simulating a declined beforeunload dialog.
contents()->GetMainFrame()->OnMessageReceived(
FrameHostMsg_BeforeUnload_ACK(0, false, now, now));
- EXPECT_FALSE(contents()->cross_navigation_pending());
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
// Since the pending RFH is the only one for the new SiteInstance, it should
// be deleted.
@@ -1795,13 +1953,199 @@ TEST_F(RenderFrameHostManagerTest,
// Increment the number of active frames in the new SiteInstance, which will
// cause the pending RFH to be swapped out instead of deleted.
- pending_rfh->GetSiteInstance()->increment_active_frame_count();
+ pending_rfh->GetSiteInstance()->increment_active_frame_count();
contents()->GetMainFrame()->OnMessageReceived(
FrameHostMsg_BeforeUnload_ACK(0, false, now, now));
- EXPECT_FALSE(contents()->cross_navigation_pending());
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
EXPECT_FALSE(rfh_deleted_observer.deleted());
}
}
+// Test that a pending RenderFrameHost in a non-root frame tree node is properly
+// deleted when the node is detached. Motivated by http://crbug.com/441357 and
+// http://crbug.com/444955.
+TEST_F(RenderFrameHostManagerTest, DetachPendingChild) {
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kSitePerProcess);
+
+ const GURL kUrlA("http://www.google.com/");
+ const GURL kUrlB("http://webkit.org/");
+
+ // Create a page with two child frames.
+ contents()->NavigateAndCommit(kUrlA);
+ contents()->GetMainFrame()->OnCreateChildFrame(
+ contents()->GetMainFrame()->GetProcess()->GetNextRoutingID(),
+ std::string("frame_name"), SandboxFlags::NONE);
+ contents()->GetMainFrame()->OnCreateChildFrame(
+ contents()->GetMainFrame()->GetProcess()->GetNextRoutingID(),
+ std::string("frame_name"), SandboxFlags::NONE);
+ RenderFrameHostManager* root_manager =
+ contents()->GetFrameTree()->root()->render_manager();
+ RenderFrameHostManager* iframe1 =
+ contents()->GetFrameTree()->root()->child_at(0)->render_manager();
+ RenderFrameHostManager* iframe2 =
+ contents()->GetFrameTree()->root()->child_at(1)->render_manager();
+
+ // 1) The first navigation.
+ NavigationEntryImpl entryA(NULL /* instance */, -1 /* page_id */, kUrlA,
+ Referrer(), base::string16() /* title */,
+ ui::PAGE_TRANSITION_TYPED,
+ false /* is_renderer_init */);
+ RenderFrameHostImpl* host1 = NavigateToEntry(iframe1, entryA);
+
+ // The RenderFrameHost created in Init will be reused.
+ EXPECT_TRUE(host1 == iframe1->current_frame_host());
+ EXPECT_FALSE(GetPendingFrameHost(iframe1));
+
+ // Commit.
+ iframe1->DidNavigateFrame(host1, true);
+ // Commit to SiteInstance should be delayed until RenderFrame commit.
+ EXPECT_TRUE(host1 == iframe1->current_frame_host());
+ ASSERT_TRUE(host1);
+ EXPECT_TRUE(host1->GetSiteInstance()->HasSite());
+
+ // 2) Cross-site navigate both frames to next site.
+ NavigationEntryImpl entryB(NULL /* instance */, -1 /* page_id */, kUrlB,
+ Referrer(kUrlA, blink::WebReferrerPolicyDefault),
+ base::string16() /* title */,
+ ui::PAGE_TRANSITION_LINK,
+ false /* is_renderer_init */);
+ host1 = NavigateToEntry(iframe1, entryB);
+ RenderFrameHostImpl* host2 = NavigateToEntry(iframe2, entryB);
+
+ // A new, pending RenderFrameHost should be created in each FrameTreeNode.
+ EXPECT_TRUE(GetPendingFrameHost(iframe1));
+ EXPECT_TRUE(GetPendingFrameHost(iframe2));
+ EXPECT_EQ(host1, GetPendingFrameHost(iframe1));
+ EXPECT_EQ(host2, GetPendingFrameHost(iframe2));
+ EXPECT_TRUE(RenderFrameHostImpl::IsRFHStateActive(
+ GetPendingFrameHost(iframe1)->rfh_state()));
+ EXPECT_TRUE(RenderFrameHostImpl::IsRFHStateActive(
+ GetPendingFrameHost(iframe2)->rfh_state()));
+ EXPECT_NE(GetPendingFrameHost(iframe1), GetPendingFrameHost(iframe2));
+ EXPECT_EQ(GetPendingFrameHost(iframe1)->GetSiteInstance(),
+ GetPendingFrameHost(iframe2)->GetSiteInstance());
+ EXPECT_NE(iframe1->current_frame_host(), GetPendingFrameHost(iframe1));
+ EXPECT_NE(iframe2->current_frame_host(), GetPendingFrameHost(iframe2));
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending())
+ << "There should be no top-level pending navigation.";
+
+ RenderFrameHostDeletedObserver delete_watcher1(GetPendingFrameHost(iframe1));
+ RenderFrameHostDeletedObserver delete_watcher2(GetPendingFrameHost(iframe2));
+ EXPECT_FALSE(delete_watcher1.deleted());
+ EXPECT_FALSE(delete_watcher2.deleted());
+
+ // Keep the SiteInstance alive for testing.
+ scoped_refptr<SiteInstanceImpl> site_instance =
+ GetPendingFrameHost(iframe1)->GetSiteInstance();
+ EXPECT_TRUE(site_instance->HasSite());
+ EXPECT_NE(site_instance, contents()->GetSiteInstance());
+ EXPECT_EQ(2U, site_instance->active_frame_count());
+
+ // Proxies should exist.
+ EXPECT_NE(nullptr,
+ root_manager->GetRenderFrameProxyHost(site_instance.get()));
+ EXPECT_NE(nullptr,
+ iframe1->GetRenderFrameProxyHost(site_instance.get()));
+ EXPECT_NE(nullptr,
+ iframe2->GetRenderFrameProxyHost(site_instance.get()));
+
+ // Detach the first child FrameTreeNode. This should kill the pending host but
+ // not yet destroy proxies in |site_instance| since the other child remains.
+ iframe1->current_frame_host()->OnMessageReceived(
+ FrameHostMsg_Detach(iframe1->current_frame_host()->GetRoutingID()));
+ iframe1 = NULL; // Was just destroyed.
+
+ EXPECT_TRUE(delete_watcher1.deleted());
+ EXPECT_FALSE(delete_watcher2.deleted());
+ EXPECT_EQ(1U, site_instance->active_frame_count());
+
+ // Proxies should still exist.
+ EXPECT_NE(nullptr,
+ root_manager->GetRenderFrameProxyHost(site_instance.get()));
+ EXPECT_NE(nullptr,
+ iframe2->GetRenderFrameProxyHost(site_instance.get()));
+
+ // Detach the second child FrameTreeNode. This should trigger cleanup of
+ // RenderFrameProxyHosts in |site_instance|.
+ iframe2->current_frame_host()->OnMessageReceived(
+ FrameHostMsg_Detach(iframe2->current_frame_host()->GetRoutingID()));
+ iframe2 = NULL; // Was just destroyed.
+
+ EXPECT_TRUE(delete_watcher1.deleted());
+ EXPECT_TRUE(delete_watcher2.deleted());
+
+ EXPECT_EQ(0U, site_instance->active_frame_count());
+ EXPECT_EQ(nullptr,
+ root_manager->GetRenderFrameProxyHost(site_instance.get()))
+ << "Proxies should have been cleaned up";
+ EXPECT_TRUE(site_instance->HasOneRef())
+ << "This SiteInstance should be destroyable now.";
+}
+
+// Two tabs in the same process crash. The first tab is reloaded, and the second
+// tab navigates away without reloading. The second tab's navigation shouldn't
+// mess with the first tab's content. Motivated by http://crbug.com/473714.
+TEST_F(RenderFrameHostManagerTest, TwoTabsCrashOneReloadsOneLeaves) {
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kSitePerProcess);
+
+ const GURL kUrl1("http://www.google.com/");
+ const GURL kUrl2("http://webkit.org/");
+ const GURL kUrl3("http://whatwg.org/");
+
+ // |contents1| and |contents2| navigate to the same page and then crash.
+ TestWebContents* contents1 = contents();
+ scoped_ptr<TestWebContents> contents2(
+ TestWebContents::Create(browser_context(), contents1->GetSiteInstance()));
+ contents1->NavigateAndCommit(kUrl1);
+ contents2->NavigateAndCommit(kUrl1);
+ MockRenderProcessHost* rph = contents1->GetMainFrame()->GetProcess();
+ EXPECT_EQ(rph, contents2->GetMainFrame()->GetProcess());
+ rph->SimulateCrash();
+ EXPECT_FALSE(contents1->GetMainFrame()->IsRenderFrameLive());
+ EXPECT_FALSE(contents2->GetMainFrame()->IsRenderFrameLive());
+ EXPECT_EQ(contents1->GetSiteInstance(), contents2->GetSiteInstance());
+
+ // Reload |contents1|.
+ contents1->NavigateAndCommit(kUrl1);
+ EXPECT_TRUE(contents1->GetMainFrame()->IsRenderFrameLive());
+ EXPECT_FALSE(contents2->GetMainFrame()->IsRenderFrameLive());
+ EXPECT_EQ(contents1->GetSiteInstance(), contents2->GetSiteInstance());
+
+ // |contents1| creates an out of process iframe.
+ contents1->GetMainFrame()->OnCreateChildFrame(
+ contents1->GetMainFrame()->GetProcess()->GetNextRoutingID(),
+ std::string("frame_name"), SandboxFlags::NONE);
+ RenderFrameHostManager* iframe =
+ contents()->GetFrameTree()->root()->child_at(0)->render_manager();
+ NavigationEntryImpl entry(NULL /* instance */, -1 /* page_id */, kUrl2,
+ Referrer(kUrl1, blink::WebReferrerPolicyDefault),
+ base::string16() /* title */,
+ ui::PAGE_TRANSITION_LINK,
+ false /* is_renderer_init */);
+ RenderFrameHostImpl* cross_site = NavigateToEntry(iframe, entry);
+ iframe->DidNavigateFrame(cross_site, true);
+
+ // A proxy to the iframe should now exist in the SiteInstance of the main
+ // frames.
+ EXPECT_NE(cross_site->GetSiteInstance(), contents1->GetSiteInstance());
+ EXPECT_NE(nullptr,
+ iframe->GetRenderFrameProxyHost(contents1->GetSiteInstance()));
+ EXPECT_NE(nullptr,
+ iframe->GetRenderFrameProxyHost(contents2->GetSiteInstance()));
+
+ // Navigate |contents2| away from the sad tab (and thus away from the
+ // SiteInstance of |contents1|). This should not destroy the proxies needed by
+ // |contents1| -- that was http://crbug.com/473714.
+ EXPECT_FALSE(contents2->GetMainFrame()->IsRenderFrameLive());
+ contents2->NavigateAndCommit(kUrl3);
+ EXPECT_TRUE(contents2->GetMainFrame()->IsRenderFrameLive());
+ EXPECT_NE(nullptr,
+ iframe->GetRenderFrameProxyHost(contents1->GetSiteInstance()));
+ EXPECT_EQ(nullptr,
+ iframe->GetRenderFrameProxyHost(contents2->GetSiteInstance()));
+}
+
} // namespace content
diff --git a/chromium/content/browser/frame_host/render_frame_message_filter.cc b/chromium/content/browser/frame_host/render_frame_message_filter.cc
index 8e414307b40..8fb9310683e 100644
--- a/chromium/content/browser/frame_host/render_frame_message_filter.cc
+++ b/chromium/content/browser/frame_host/render_frame_message_filter.cc
@@ -16,14 +16,17 @@ namespace {
void CreateChildFrameOnUI(int process_id,
int parent_routing_id,
const std::string& frame_name,
+ SandboxFlags sandbox_flags,
int new_routing_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
RenderFrameHostImpl* render_frame_host =
RenderFrameHostImpl::FromID(process_id, parent_routing_id);
// Handles the RenderFrameHost being deleted on the UI thread while
// processing a subframe creation message.
- if (render_frame_host)
- render_frame_host->OnCreateChildFrame(new_routing_id, frame_name);
+ if (render_frame_host) {
+ render_frame_host->OnCreateChildFrame(new_routing_id, frame_name,
+ sandbox_flags);
+ }
}
} // namespace
@@ -49,15 +52,15 @@ bool RenderFrameMessageFilter::OnMessageReceived(const IPC::Message& message) {
return handled;
}
-void RenderFrameMessageFilter::OnCreateChildFrame(
- int parent_routing_id,
- const std::string& frame_name,
- int* new_routing_id) {
+void RenderFrameMessageFilter::OnCreateChildFrame(int parent_routing_id,
+ const std::string& frame_name,
+ SandboxFlags sandbox_flags,
+ int* new_routing_id) {
*new_routing_id = render_widget_helper_->GetNextRoutingID();
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
- base::Bind(&CreateChildFrameOnUI, render_process_id_,
- parent_routing_id, frame_name, *new_routing_id));
+ base::Bind(&CreateChildFrameOnUI, render_process_id_, parent_routing_id,
+ frame_name, sandbox_flags, *new_routing_id));
}
} // namespace content
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 0de54b10e83..7380245c083 100644
--- a/chromium/content/browser/frame_host/render_frame_message_filter.h
+++ b/chromium/content/browser/frame_host/render_frame_message_filter.h
@@ -5,6 +5,7 @@
#ifndef CONTENT_BROWSER_FRAME_HOST_RENDER_FRAME_MESSAGE_FILTER_H_
#define CONTENT_BROWSER_FRAME_HOST_RENDER_FRAME_MESSAGE_FILTER_H_
+#include "content/common/frame_replication_state.h"
#include "content/public/browser/browser_message_filter.h"
namespace content {
@@ -28,6 +29,7 @@ class RenderFrameMessageFilter : public BrowserMessageFilter {
void OnCreateChildFrame(int parent_routing_id,
const std::string& frame_name,
+ SandboxFlags sandbox_flags,
int* new_render_frame_id);
const int render_process_id_;
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 3db9edf613d..6d41f873516 100644
--- a/chromium/content/browser/frame_host/render_frame_proxy_host.cc
+++ b/chromium/content/browser/frame_host/render_frame_proxy_host.cc
@@ -5,11 +5,14 @@
#include "content/browser/frame_host/render_frame_proxy_host.h"
#include "base/lazy_instance.h"
+#include "content/browser/bad_message.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_delegate.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/message_port_message_filter.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"
@@ -33,7 +36,7 @@ base::LazyInstance<RoutingIDFrameProxyMap> g_routing_id_frame_proxy_map =
// static
RenderFrameProxyHost* RenderFrameProxyHost::FromID(int process_id,
int routing_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
RoutingIDFrameProxyMap* frames = g_routing_id_frame_proxy_map.Pointer();
RoutingIDFrameProxyMap::iterator it = frames->find(
RenderFrameProxyHostID(process_id, routing_id));
@@ -44,7 +47,9 @@ 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) {
+ process_(site_instance->GetProcess()),
+ frame_tree_node_(frame_tree_node),
+ render_frame_proxy_created_(false) {
GetProcess()->AddRoute(routing_id_, this);
CHECK(g_routing_id_frame_proxy_map.Get().insert(
std::make_pair(
@@ -94,6 +99,7 @@ RenderViewHostImpl* RenderFrameProxyHost::GetRenderViewHost() {
void RenderFrameProxyHost::TakeFrameHostOwnership(
scoped_ptr<RenderFrameHostImpl> render_frame_host) {
+ CHECK(render_frame_host_ == nullptr);
render_frame_host_ = render_frame_host.Pass();
render_frame_host_->set_render_frame_proxy_host(this);
}
@@ -104,14 +110,6 @@ scoped_ptr<RenderFrameHostImpl> RenderFrameProxyHost::PassFrameHostOwnership() {
}
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.
-
- // 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);
}
@@ -120,34 +118,43 @@ bool RenderFrameProxyHost::OnMessageReceived(const IPC::Message& msg) {
cross_process_frame_connector_->OnMessageReceived(msg))
return true;
- // TODO(nasko): This can be removed once we don't have a swapped out state on
- // RenderFrameHosts. See https://crbug.com/357747.
- if (render_frame_host_.get())
- return render_frame_host_->OnMessageReceived(msg);
-
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(RenderFrameProxyHost, msg)
+ IPC_MESSAGE_HANDLER(FrameHostMsg_Detach, OnDetach)
IPC_MESSAGE_HANDLER(FrameHostMsg_OpenURL, OnOpenURL)
+ IPC_MESSAGE_HANDLER(FrameHostMsg_RouteMessageEvent, OnRouteMessageEvent)
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(!render_frame_proxy_created_);
- DCHECK(GetProcess()->HasConnection());
+ // It is possible to reach this when the process is dead (in particular, when
+ // creating proxies from CreateProxiesForChildFrame). In that case, don't
+ // create the proxy. The process shouldn't be resurrected just to create
+ // RenderFrameProxies; it should be restored only if it needs to host a
+ // RenderFrame. When that happens, the process will be reinitialized, and
+ // all necessary proxies, including any of the ones we skipped here, will be
+ // created by CreateProxiesForSiteInstance. See https://crbug.com/476846
+ if (!GetProcess()->HasConnection())
+ return false;
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());
+ // It is safe to use GetRenderFrameProxyHost to get the parent proxy, since
+ // new child frames always start out as local frames, so a new proxy should
+ // never have a RenderFrameHost as a parent.
+ RenderFrameProxyHost* parent_proxy =
+ frame_tree_node_->parent()->render_manager()->GetRenderFrameProxyHost(
+ site_instance_.get());
+ CHECK(parent_proxy);
+ // When this is called, the parent RenderFrameProxy should already exist.
+ // The FrameNew_NewFrameProxy will crash on the renderer side if there's no
+ // parent proxy.
+ CHECK(parent_proxy->is_render_frame_proxy_live());
+ parent_routing_id = parent_proxy->GetRoutingID();
CHECK_NE(parent_routing_id, MSG_ROUTING_NONE);
}
@@ -155,8 +162,11 @@ bool RenderFrameProxyHost::InitRenderFrameProxy() {
parent_routing_id,
frame_tree_node_->frame_tree()
->GetRenderViewHost(site_instance_.get())
- ->GetRoutingID()));
+ ->GetRoutingID(),
+ frame_tree_node_
+ ->current_replication_state()));
+ render_frame_proxy_created_ = true;
return true;
}
@@ -164,9 +174,104 @@ void RenderFrameProxyHost::DisownOpener() {
Send(new FrameMsg_DisownOpener(GetRoutingID()));
}
+void RenderFrameProxyHost::OnDetach() {
+ // This message should only be received for subframes. Note that we can't
+ // restrict it to just the current SiteInstances of the ancestors of this
+ // frame, because another frame in the tree may be able to detach this frame
+ // by navigating its parent.
+ if (frame_tree_node_->IsMainFrame()) {
+ bad_message::ReceivedBadMessage(GetProcess(), bad_message::RFPH_DETACH);
+ return;
+ }
+ frame_tree_node_->frame_tree()->RemoveFrame(frame_tree_node_);
+}
+
void RenderFrameProxyHost::OnOpenURL(
const FrameHostMsg_OpenURL_Params& params) {
- frame_tree_node_->current_frame_host()->OpenURL(params);
+ // TODO(creis): Verify that we are in the same BrowsingInstance as the current
+ // RenderFrameHost. See NavigatorImpl::RequestOpenURL.
+ frame_tree_node_->current_frame_host()->OpenURL(params, site_instance_.get());
+}
+
+void RenderFrameProxyHost::OnRouteMessageEvent(
+ const FrameMsg_PostMessage_Params& params) {
+ RenderFrameHostImpl* target_rfh = frame_tree_node()->current_frame_host();
+
+ // Only deliver the message if the request came from a RenderFrameHost in the
+ // same BrowsingInstance or if this WebContents is dedicated to a browser
+ // plugin guest.
+ //
+ // TODO(alexmos, lazyboy): The check for browser plugin guest currently
+ // requires going through the delegate. It should be refactored and
+ // performed here once OOPIF support in <webview> is further along.
+ SiteInstance* target_site_instance = target_rfh->GetSiteInstance();
+ if (!target_site_instance->IsRelatedSiteInstance(GetSiteInstance()) &&
+ !target_rfh->delegate()->ShouldRouteMessageEvent(target_rfh,
+ GetSiteInstance()))
+ return;
+
+ FrameMsg_PostMessage_Params new_params(params);
+
+ // If there is a source_routing_id, translate it to the routing ID of the
+ // equivalent RenderFrameProxyHost in the target process.
+ if (new_params.source_routing_id != MSG_ROUTING_NONE) {
+ RenderFrameHostImpl* source_rfh = RenderFrameHostImpl::FromID(
+ GetProcess()->GetID(), new_params.source_routing_id);
+ if (!source_rfh) {
+ new_params.source_routing_id = MSG_ROUTING_NONE;
+ } else {
+ // Ensure that we have a swapped-out RVH and proxy for the source frame.
+ // If it doesn't exist, create it on demand and also create its opener
+ // chain, since those will also be accessible to the target page.
+ //
+ // TODO(alexmos): This currently only works for top-level frames and
+ // won't create the right proxy if the message source is a subframe on a
+ // cross-process tab. This will be cleaned up as part of moving opener
+ // tracking to FrameTreeNode (https://crbug.com/225940). For now, if the
+ // message is sent from a subframe on a cross-process tab, set the source
+ // routing ID to the main frame of the source tab, which matches legacy
+ // postMessage behavior prior to --site-per-process.
+ int source_view_routing_id =
+ target_rfh->delegate()->EnsureOpenerRenderViewsExist(source_rfh);
+
+ RenderFrameProxyHost* source_proxy_in_target_site_instance =
+ source_rfh->frame_tree_node()
+ ->render_manager()
+ ->GetRenderFrameProxyHost(target_rfh->GetSiteInstance());
+ if (source_proxy_in_target_site_instance) {
+ new_params.source_routing_id =
+ source_proxy_in_target_site_instance->GetRoutingID();
+ } else if (source_view_routing_id != MSG_ROUTING_NONE) {
+ RenderViewHostImpl* source_rvh = RenderViewHostImpl::FromID(
+ target_rfh->GetProcess()->GetID(), source_view_routing_id);
+ CHECK(source_rvh);
+ new_params.source_routing_id = source_rvh->main_frame_routing_id();
+ } else {
+ new_params.source_routing_id = MSG_ROUTING_NONE;
+ }
+ }
+ }
+
+ if (!params.message_ports.empty()) {
+ // Updating the message port information has to be done in the IO thread;
+ // MessagePortMessageFilter::RouteMessageEventWithMessagePorts will send
+ // FrameMsg_PostMessageEvent after it's done. Note that a trivial solution
+ // would've been to post a task on the IO thread to do the IO-thread-bound
+ // work, and make that post a task back to WebContentsImpl in the UI
+ // thread. But we cannot do that, since there's nothing to guarantee that
+ // WebContentsImpl stays alive during the round trip.
+ scoped_refptr<MessagePortMessageFilter> message_port_message_filter(
+ static_cast<RenderProcessHostImpl*>(target_rfh->GetProcess())
+ ->message_port_message_filter());
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&MessagePortMessageFilter::RouteMessageEventWithMessagePorts,
+ message_port_message_filter, target_rfh->GetRoutingID(),
+ new_params));
+ } else {
+ target_rfh->Send(
+ new FrameMsg_PostMessageEvent(target_rfh->GetRoutingID(), new_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 ed3235ca98b..9594f75010a 100644
--- a/chromium/content/browser/frame_host/render_frame_proxy_host.h
+++ b/chromium/content/browser/frame_host/render_frame_proxy_host.h
@@ -11,6 +11,8 @@
#include "ipc/ipc_listener.h"
#include "ipc/ipc_sender.h"
+struct FrameMsg_PostMessage_Params;
+
namespace content {
class CrossProcessFrameConnector;
@@ -62,7 +64,7 @@ class RenderFrameProxyHost
~RenderFrameProxyHost() override;
RenderProcessHost* GetProcess() {
- return site_instance_->GetProcess();
+ return process_;
}
// Initializes the object and creates the RenderFrameProxy in the process
@@ -106,9 +108,18 @@ class RenderFrameProxyHost
// action in another renderer process.
void DisownOpener();
+ void set_render_frame_proxy_created(bool created) {
+ render_frame_proxy_created_ = created;
+ }
+
+ // Returns if the RenderFrameProxy for this host is alive.
+ bool is_render_frame_proxy_live() { return render_frame_proxy_created_; }
+
private:
// IPC Message handlers.
+ void OnDetach();
void OnOpenURL(const FrameHostMsg_OpenURL_Params& params);
+ void OnRouteMessageEvent(const FrameMsg_PostMessage_Params& params);
// This RenderFrameProxyHost's routing id.
int routing_id_;
@@ -116,9 +127,18 @@ class RenderFrameProxyHost
// The SiteInstance this proxy is associated with.
scoped_refptr<SiteInstance> site_instance_;
+ // The renderer process this RenderFrameHostProxy is associated with. It is
+ // equivalent to the result of site_instance_->GetProcess(), but that
+ // method has the side effect of creating the process if it doesn't exist.
+ // Cache a pointer to avoid unnecessary process creation.
+ RenderProcessHost* process_;
+
// The node in the frame tree where this proxy is located.
FrameTreeNode* frame_tree_node_;
+ // True if we have a live RenderFrameProxy for this host.
+ bool render_frame_proxy_created_;
+
// When a RenderFrameHost is in a different process from its parent in the
// frame tree, this class connects its associated RenderWidgetHostView
// to this RenderFrameProxyHost, which corresponds to the same frame in the
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 ab1bff89c81..b8fdb0193d5 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
@@ -53,11 +53,15 @@ bool RenderWidgetHostViewChildFrame::IsSurfaceAvailableForCopy() const {
}
void RenderWidgetHostViewChildFrame::Show() {
- WasShown();
+ if (!host_->is_hidden())
+ return;
+ host_->WasShown(ui::LatencyInfo());
}
void RenderWidgetHostViewChildFrame::Hide() {
- WasHidden();
+ if (host_->is_hidden())
+ return;
+ host_->WasHidden();
}
bool RenderWidgetHostViewChildFrame::IsShowing() {
@@ -103,7 +107,7 @@ gfx::Size RenderWidgetHostViewChildFrame::GetPhysicalBackingSize() const {
void RenderWidgetHostViewChildFrame::InitAsPopup(
RenderWidgetHostView* parent_host_view,
- const gfx::Rect& pos) {
+ const gfx::Rect& bounds) {
NOTREACHED();
}
@@ -116,33 +120,16 @@ void RenderWidgetHostViewChildFrame::ImeCancelComposition() {
NOTREACHED();
}
-#if defined(OS_MACOSX) || defined(USE_AURA) || defined(OS_ANDROID)
void RenderWidgetHostViewChildFrame::ImeCompositionRangeChanged(
const gfx::Range& range,
const std::vector<gfx::Rect>& character_bounds) {
NOTREACHED();
}
-#endif
-
-void RenderWidgetHostViewChildFrame::WasShown() {
- if (!host_->is_hidden())
- return;
- host_->WasShown(ui::LatencyInfo());
-}
-
-void RenderWidgetHostViewChildFrame::WasHidden() {
- if (host_->is_hidden())
- return;
- host_->WasHidden();
-}
void RenderWidgetHostViewChildFrame::MovePluginWindows(
const std::vector<WebPluginGeometry>& moves) {
}
-void RenderWidgetHostViewChildFrame::Blur() {
-}
-
void RenderWidgetHostViewChildFrame::UpdateCursor(const WebCursor& cursor) {
}
@@ -155,7 +142,7 @@ void RenderWidgetHostViewChildFrame::TextInputTypeChanged(
ui::TextInputMode input_mode,
bool can_compose_inline,
int flags) {
- NOTREACHED();
+ // TODO(kenrb): Implement.
}
void RenderWidgetHostViewChildFrame::RenderProcessGone(
@@ -235,6 +222,12 @@ bool RenderWidgetHostViewChildFrame::LockMouse() {
void RenderWidgetHostViewChildFrame::UnlockMouse() {
}
+uint32_t RenderWidgetHostViewChildFrame::GetSurfaceIdNamespace() {
+ // TODO(kenrb): Create SurfaceFactory here when RWHVChildFrame
+ // gets compositor surface support.
+ return 0;
+}
+
#if defined(OS_MACOSX)
void RenderWidgetHostViewChildFrame::SetActive(bool active) {
}
@@ -271,9 +264,9 @@ bool RenderWidgetHostViewChildFrame::PostProcessEventForPluginIme(
void RenderWidgetHostViewChildFrame::CopyFromCompositingSurface(
const gfx::Rect& src_subrect,
const gfx::Size& /* dst_size */,
- CopyFromCompositingSurfaceCallback& callback,
- const SkColorType color_type) {
- callback.Run(false, SkBitmap());
+ ReadbackRequestCallback& callback,
+ const SkColorType preferred_color_type) {
+ callback.Run(SkBitmap(), READBACK_FAILED);
}
void RenderWidgetHostViewChildFrame::CopyFromCompositingSurfaceToVideoFrame(
@@ -308,10 +301,6 @@ gfx::NativeViewId RenderWidgetHostViewChildFrame::GetParentForWindowlessPlugin()
}
#endif // defined(OS_WIN)
-SkColorType RenderWidgetHostViewChildFrame::PreferredReadbackFormat() {
- return kN32_SkColorType;
-}
-
BrowserAccessibilityManager*
RenderWidgetHostViewChildFrame::CreateBrowserAccessibilityManager(
BrowserAccessibilityDelegate* delegate) {
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 b2895f9f7df..6513033172f 100644
--- a/chromium/content/browser/frame_host/render_widget_host_view_child_frame.h
+++ b/chromium/content/browser/frame_host/render_widget_host_view_child_frame.h
@@ -8,8 +8,9 @@
#include "base/memory/scoped_ptr.h"
#include "content/browser/renderer_host/render_widget_host_view_base.h"
#include "content/common/content_export.h"
+#include "content/public/browser/readback_types.h"
+#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/rect.h"
namespace content {
class CrossProcessFrameConnector;
@@ -56,12 +57,9 @@ class CONTENT_EXPORT RenderWidgetHostViewChildFrame
// RenderWidgetHostViewBase implementation.
void InitAsPopup(RenderWidgetHostView* parent_host_view,
- const gfx::Rect& pos) override;
+ const gfx::Rect& bounds) 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,
@@ -69,11 +67,9 @@ class CONTENT_EXPORT RenderWidgetHostViewChildFrame
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;
-#endif
void RenderProcessGone(base::TerminationStatus status,
int error_code) override;
void Destroy() override;
@@ -86,8 +82,8 @@ class CONTENT_EXPORT RenderWidgetHostViewChildFrame
void CopyFromCompositingSurface(
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
- const base::Callback<void(bool, const SkBitmap&)>& callback,
- const SkColorType color_type) override;
+ ReadbackRequestCallback& callback,
+ const SkColorType preferred_color_type) override;
void CopyFromCompositingSurfaceToVideoFrame(
const gfx::Rect& src_subrect,
const scoped_refptr<media::VideoFrame>& target,
@@ -105,6 +101,7 @@ class CONTENT_EXPORT RenderWidgetHostViewChildFrame
#endif // defined(USE_AURA)
bool LockMouse() override;
void UnlockMouse() override;
+ uint32_t GetSurfaceIdNamespace() override;
#if defined(OS_MACOSX)
// RenderWidgetHostView implementation.
@@ -124,20 +121,18 @@ class CONTENT_EXPORT RenderWidgetHostViewChildFrame
// RenderWidgetHostViewBase implementation.
#if defined(OS_ANDROID)
- virtual void LockCompositingSurface() override;
- virtual void UnlockCompositingSurface() override;
+ void LockCompositingSurface() override;
+ void UnlockCompositingSurface() override;
#endif // defined(OS_ANDROID)
#if defined(OS_WIN)
- virtual void SetParentNativeViewAccessible(
+ void SetParentNativeViewAccessible(
gfx::NativeViewAccessible accessible_parent) override;
- virtual gfx::NativeViewId GetParentForWindowlessPlugin() const override;
+ gfx::NativeViewId GetParentForWindowlessPlugin() const override;
#endif
BrowserAccessibilityManager* CreateBrowserAccessibilityManager(
BrowserAccessibilityDelegate* delegate) override;
- SkColorType PreferredReadbackFormat() override;
-
protected:
friend class RenderWidgetHostView;
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 7d731ff90fd..aafa97939bf 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
@@ -69,12 +69,6 @@ TEST_F(RenderWidgetHostViewChildFrameTest, VisibilityTest) {
view_->Hide();
ASSERT_FALSE(view_->IsShowing());
-
- view_->WasShown();
- ASSERT_TRUE(view_->IsShowing());
-
- view_->WasHidden();
- ASSERT_FALSE(view_->IsShowing());
}
} // namespace content
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 708f8bf0364..6ae03772cec 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
@@ -76,7 +76,7 @@ bool RenderWidgetHostViewGuest::OnMessageReceivedFromEmbedder(
return handled;
}
-void RenderWidgetHostViewGuest::WasShown() {
+void RenderWidgetHostViewGuest::Show() {
// If the WebContents associated with us showed an interstitial page in the
// beginning, the teardown path might call WasShown() while |host_| is in
// the process of destruction. Avoid calling WasShown below in this case.
@@ -95,7 +95,7 @@ void RenderWidgetHostViewGuest::WasShown() {
host_->WasShown(ui::LatencyInfo());
}
-void RenderWidgetHostViewGuest::WasHidden() {
+void RenderWidgetHostViewGuest::Hide() {
// |guest_| is NULL during test.
if ((guest_ && guest_->is_in_destruction()) || host_->is_hidden())
return;
@@ -116,7 +116,7 @@ void RenderWidgetHostViewGuest::Focus() {
// InterstitialPages are not WebContents, and so BrowserPluginGuest does not
// have direct access to the interstitial page's RenderWidgetHost.
if (guest_)
- guest_->SetFocus(host_, true);
+ guest_->SetFocus(host_, true, blink::WebFocusTypeNone);
}
bool RenderWidgetHostViewGuest::HasFocus() const {
@@ -141,12 +141,12 @@ 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))
+ if (!gesture_recognizer_->ProcessTouchEventPreDispatch(*iter, this))
continue;
scoped_ptr<ui::GestureRecognizer::Gestures> gestures;
- gestures.reset(gesture_recognizer_->ProcessTouchEventPostDispatch(
- *(*iter), result, this));
+ gestures.reset(gesture_recognizer_->AckSyncTouchEvent(
+ (*iter)->unique_event_id(), result, this));
ProcessGestures(gestures.get());
}
}
@@ -156,7 +156,7 @@ gfx::Rect RenderWidgetHostViewGuest::GetViewBounds() const {
if (!guest_)
return gfx::Rect();
- RenderWidgetHostViewBase* rwhv = GetGuestRenderWidgetHostView();
+ RenderWidgetHostViewBase* rwhv = GetOwnerRenderWidgetHostView();
gfx::Rect embedder_bounds;
if (rwhv)
embedder_bounds = rwhv->GetViewBounds();
@@ -167,7 +167,11 @@ gfx::Rect RenderWidgetHostViewGuest::GetViewBounds() const {
void RenderWidgetHostViewGuest::RenderProcessGone(
base::TerminationStatus status,
int error_code) {
- platform_view_->RenderProcessGone(status, error_code);
+ // The |platform_view_| gets destroyed before we get here if this view
+ // is for an InterstitialPage.
+ if (platform_view_)
+ platform_view_->RenderProcessGone(status, error_code);
+
// Destroy the guest view instance only, so we don't end up calling
// platform_view_->Destroy().
DestroyGuestView();
@@ -209,6 +213,12 @@ void RenderWidgetHostViewGuest::OnSwapCompositorFrame(
}
bool RenderWidgetHostViewGuest::OnMessageReceived(const IPC::Message& msg) {
+ if (!platform_view_) {
+ // In theory, we can get here if there's a delay between DestroyGuestView()
+ // being called and when our destructor is invoked.
+ return false;
+ }
+
return platform_view_->OnMessageReceived(msg);
}
@@ -218,7 +228,7 @@ void RenderWidgetHostViewGuest::InitAsChild(
}
void RenderWidgetHostViewGuest::InitAsPopup(
- RenderWidgetHostView* parent_host_view, const gfx::Rect& pos) {
+ RenderWidgetHostView* parent_host_view, const gfx::Rect& bounds) {
// This should never get called.
NOTREACHED();
}
@@ -233,7 +243,7 @@ gfx::NativeView RenderWidgetHostViewGuest::GetNativeView() const {
if (!guest_)
return gfx::NativeView();
- RenderWidgetHostView* rwhv = guest_->GetEmbedderRenderWidgetHostView();
+ RenderWidgetHostView* rwhv = guest_->GetOwnerRenderWidgetHostView();
if (!rwhv)
return gfx::NativeView();
return rwhv->GetNativeView();
@@ -243,7 +253,7 @@ gfx::NativeViewId RenderWidgetHostViewGuest::GetNativeViewId() const {
if (!guest_)
return static_cast<gfx::NativeViewId>(NULL);
- RenderWidgetHostView* rwhv = guest_->GetEmbedderRenderWidgetHostView();
+ RenderWidgetHostView* rwhv = guest_->GetOwnerRenderWidgetHostView();
if (!rwhv)
return static_cast<gfx::NativeViewId>(NULL);
return rwhv->GetNativeViewId();
@@ -253,7 +263,7 @@ gfx::NativeViewAccessible RenderWidgetHostViewGuest::GetNativeViewAccessible() {
if (!guest_)
return gfx::NativeViewAccessible();
- RenderWidgetHostView* rwhv = guest_->GetEmbedderRenderWidgetHostView();
+ RenderWidgetHostView* rwhv = guest_->GetOwnerRenderWidgetHostView();
if (!rwhv)
return gfx::NativeViewAccessible();
return rwhv->GetNativeViewAccessible();
@@ -289,7 +299,7 @@ void RenderWidgetHostViewGuest::TextInputTypeChanged(
if (!guest_)
return;
- RenderWidgetHostViewBase* rwhv = GetGuestRenderWidgetHostView();
+ RenderWidgetHostViewBase* rwhv = GetOwnerRenderWidgetHostView();
if (!rwhv)
return;
// Forward the information to embedding RWHV.
@@ -300,7 +310,7 @@ void RenderWidgetHostViewGuest::ImeCancelComposition() {
if (!guest_)
return;
- RenderWidgetHostViewBase* rwhv = GetGuestRenderWidgetHostView();
+ RenderWidgetHostViewBase* rwhv = GetOwnerRenderWidgetHostView();
if (!rwhv)
return;
// Forward the information to embedding RWHV.
@@ -314,7 +324,7 @@ void RenderWidgetHostViewGuest::ImeCompositionRangeChanged(
if (!guest_)
return;
- RenderWidgetHostViewBase* rwhv = GetGuestRenderWidgetHostView();
+ RenderWidgetHostViewBase* rwhv = GetOwnerRenderWidgetHostView();
if (!rwhv)
return;
std::vector<gfx::Rect> guest_character_bounds;
@@ -339,7 +349,7 @@ void RenderWidgetHostViewGuest::SelectionBoundsChanged(
if (!guest_)
return;
- RenderWidgetHostViewBase* rwhv = GetGuestRenderWidgetHostView();
+ RenderWidgetHostViewBase* rwhv = GetOwnerRenderWidgetHostView();
if (!rwhv)
return;
ViewHostMsg_SelectionBounds_Params guest_params(params);
@@ -374,7 +384,7 @@ void RenderWidgetHostViewGuest::UnlockMouse() {
void RenderWidgetHostViewGuest::GetScreenInfo(blink::WebScreenInfo* results) {
if (!guest_)
return;
- RenderWidgetHostViewBase* embedder_view = GetGuestRenderWidgetHostView();
+ RenderWidgetHostViewBase* embedder_view = GetOwnerRenderWidgetHostView();
if (embedder_view)
embedder_view->GetScreenInfo(results);
}
@@ -398,7 +408,7 @@ void RenderWidgetHostViewGuest::ShowDefinitionForSelection() {
gfx::Point origin;
gfx::Rect guest_bounds = GetViewBounds();
- RenderWidgetHostView* rwhv = guest_->GetEmbedderRenderWidgetHostView();
+ RenderWidgetHostView* rwhv = guest_->GetOwnerRenderWidgetHostView();
gfx::Rect embedder_bounds;
if (rwhv)
embedder_bounds = rwhv->GetViewBounds();
@@ -542,14 +552,10 @@ void RenderWidgetHostViewGuest::ProcessGestures(
}
}
-SkColorType RenderWidgetHostViewGuest::PreferredReadbackFormat() {
- return kN32_SkColorType;
-}
-
RenderWidgetHostViewBase*
-RenderWidgetHostViewGuest::GetGuestRenderWidgetHostView() const {
+RenderWidgetHostViewGuest::GetOwnerRenderWidgetHostView() const {
return static_cast<RenderWidgetHostViewBase*>(
- guest_->GetEmbedderRenderWidgetHostView());
+ guest_->GetOwnerRenderWidgetHostView());
}
void RenderWidgetHostViewGuest::OnHandleInputEvent(
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 2ebd4e66845..1f9651f4bfc 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
@@ -14,9 +14,9 @@
#include "ui/events/event.h"
#include "ui/events/gestures/gesture_recognizer.h"
#include "ui/events/gestures/gesture_types.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/vector2d_f.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/vector2d_f.h"
namespace content {
class BrowserPluginGuest;
@@ -55,6 +55,8 @@ class CONTENT_EXPORT RenderWidgetHostViewGuest
void SetBounds(const gfx::Rect& rect) override;
void Focus() override;
bool HasFocus() const override;
+ void Show() override;
+ void Hide() override;
gfx::NativeView GetNativeView() const override;
gfx::NativeViewId GetNativeViewId() const override;
gfx::NativeViewAccessible GetNativeViewAccessible() override;
@@ -65,10 +67,8 @@ class CONTENT_EXPORT RenderWidgetHostViewGuest
// RenderWidgetHostViewBase implementation.
void InitAsPopup(RenderWidgetHostView* parent_host_view,
- const gfx::Rect& pos) override;
+ const gfx::Rect& bounds) 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;
@@ -124,14 +124,14 @@ class CONTENT_EXPORT RenderWidgetHostViewGuest
#endif // defined(OS_ANDROID) || defined(TOOLKIT_VIEWS)
#if defined(OS_ANDROID)
- virtual void LockCompositingSurface() override;
- virtual void UnlockCompositingSurface() override;
+ void LockCompositingSurface() override;
+ void UnlockCompositingSurface() override;
#endif // defined(OS_ANDROID)
#if defined(OS_WIN)
- virtual void SetParentNativeViewAccessible(
+ void SetParentNativeViewAccessible(
gfx::NativeViewAccessible accessible_parent) override;
- virtual gfx::NativeViewId GetParentForWindowlessPlugin() const override;
+ gfx::NativeViewId GetParentForWindowlessPlugin() const override;
#endif
// Overridden from ui::GestureEventHelper.
@@ -139,8 +139,6 @@ class CONTENT_EXPORT RenderWidgetHostViewGuest
void DispatchGestureEvent(ui::GestureEvent* event) override;
void DispatchCancelTouchEvent(ui::TouchEvent* event) override;
- SkColorType PreferredReadbackFormat() override;
-
protected:
friend class RenderWidgetHostView;
@@ -154,7 +152,7 @@ class CONTENT_EXPORT RenderWidgetHostViewGuest
// Process all of the given gestures (passes them on to renderer)
void ProcessGestures(ui::GestureRecognizer::Gestures* gestures);
- RenderWidgetHostViewBase* GetGuestRenderWidgetHostView() const;
+ RenderWidgetHostViewBase* GetOwnerRenderWidgetHostView() const;
void OnHandleInputEvent(RenderWidgetHostImpl* embedder,
int browser_plugin_instance_id,
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 968dc8abc07..114c46c2be5 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
@@ -71,12 +71,6 @@ TEST_F(RenderWidgetHostViewGuestTest, VisibilityTest) {
view_->Hide();
ASSERT_FALSE(view_->IsShowing());
-
- view_->WasShown();
- ASSERT_TRUE(view_->IsShowing());
-
- view_->WasHidden();
- ASSERT_FALSE(view_->IsShowing());
}
} // namespace content
diff --git a/chromium/content/browser/gamepad/gamepad_consumer.h b/chromium/content/browser/gamepad/gamepad_consumer.h
index 3d07452fd1c..1ef5c48038c 100644
--- a/chromium/content/browser/gamepad/gamepad_consumer.h
+++ b/chromium/content/browser/gamepad/gamepad_consumer.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_GAMEPAD_GAMEPAD_CONSUMER_H
-#define CONTENT_BROWSER_GAMEPAD_GAMEPAD_CONSUMER_H
+#ifndef CONTENT_BROWSER_GAMEPAD_GAMEPAD_CONSUMER_H_
+#define CONTENT_BROWSER_GAMEPAD_GAMEPAD_CONSUMER_H_
#include "base/basictypes.h"
#include "content/common/content_export.h"
@@ -26,4 +26,4 @@ class CONTENT_EXPORT GamepadConsumer {
} // namespace content
-#endif // CONTENT_BROWSER_GAMEPAD_GAMEPAD_CONSUMER_H
+#endif // CONTENT_BROWSER_GAMEPAD_GAMEPAD_CONSUMER_H_
diff --git a/chromium/content/browser/gamepad/gamepad_platform_data_fetcher.h b/chromium/content/browser/gamepad/gamepad_platform_data_fetcher.h
index 9cb4cd11ed7..04aab03e265 100644
--- a/chromium/content/browser/gamepad/gamepad_platform_data_fetcher.h
+++ b/chromium/content/browser/gamepad/gamepad_platform_data_fetcher.h
@@ -46,8 +46,8 @@ class GamepadDataFetcherEmpty : public GamepadDataFetcher {
public:
GamepadDataFetcherEmpty();
- virtual void GetGamepadData(blink::WebGamepads* pads,
- bool devices_changed_hint) override;
+ void GetGamepadData(blink::WebGamepads* pads,
+ bool devices_changed_hint) override;
private:
DISALLOW_COPY_AND_ASSIGN(GamepadDataFetcherEmpty);
diff --git a/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_android.cc b/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_android.cc
index a8673fa3252..8668dbc70e5 100644
--- a/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_android.cc
+++ b/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_android.cc
@@ -7,10 +7,10 @@
#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
-#include "base/debug/trace_event.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/trace_event/trace_event.h"
#include "jni/GamepadList_jni.h"
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 989a467a291..4acdfb3b0ad 100644
--- a/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_android.h
+++ b/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_android.h
@@ -21,12 +21,12 @@ namespace content {
class GamepadPlatformDataFetcherAndroid : public GamepadDataFetcher {
public:
GamepadPlatformDataFetcherAndroid();
- virtual ~GamepadPlatformDataFetcherAndroid();
+ ~GamepadPlatformDataFetcherAndroid() override;
- virtual void PauseHint(bool paused) override;
+ void PauseHint(bool paused) override;
- virtual void GetGamepadData(blink::WebGamepads* pads,
- bool devices_changed_hint) override;
+ void GetGamepadData(blink::WebGamepads* pads,
+ 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 e99a5e15904..26f2913a877 100644
--- a/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_linux.cc
+++ b/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_linux.cc
@@ -5,20 +5,19 @@
#include "content/browser/gamepad/gamepad_platform_data_fetcher_linux.h"
#include <fcntl.h>
-#include <libudev.h>
#include <linux/joystick.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
-#include "base/debug/trace_event.h"
#include "base/message_loop/message_loop.h"
#include "base/posix/eintr_wrapper.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 "base/trace_event/trace_event.h"
#include "content/browser/udev_linux.h"
#include "device/udev_linux/scoped_udev.h"
@@ -35,10 +34,10 @@ void CloseFileDescriptorIfValid(int fd) {
}
bool IsGamepad(udev_device* dev, int* index, std::string* path) {
- if (!udev_device_get_property_value(dev, "ID_INPUT_JOYSTICK"))
+ if (!device::udev_device_get_property_value(dev, "ID_INPUT_JOYSTICK"))
return false;
- const char* node_path = udev_device_get_devnode(dev);
+ const char* node_path = device::udev_device_get_devnode(dev);
if (!node_path)
return false;
@@ -126,7 +125,7 @@ void GamepadPlatformDataFetcherLinux::RefreshDevice(udev_device* dev) {
// joystick device. In order to get the information about the physical
// 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 = device::udev_device_get_parent_with_subsystem_devtype(
dev, kInputSubsystem, NULL);
if (!dev) {
// Unable to get device information, don't use this device.
@@ -142,32 +141,36 @@ void GamepadPlatformDataFetcherLinux::RefreshDevice(udev_device* dev) {
return;
}
- const char* vendor_id = udev_device_get_sysattr_value(dev, "id/vendor");
- const char* product_id = udev_device_get_sysattr_value(dev, "id/product");
+ const char* vendor_id =
+ device::udev_device_get_sysattr_value(dev, "id/vendor");
+ const char* product_id =
+ device::udev_device_get_sysattr_value(dev, "id/product");
mapper = GetGamepadStandardMappingFunction(vendor_id, product_id);
// Driver returns utf-8 strings here, so combine in utf-8 first and
// convert to WebUChar later once we've picked an id string.
- const char* name = udev_device_get_sysattr_value(dev, "name");
+ const char* name = device::udev_device_get_sysattr_value(dev, "name");
std::string name_string = base::StringPrintf("%s", name);
// In many cases the information the input subsystem contains isn't
// 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 =
+ device::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");
+ device::udev_device_get_sysattr_value(usb_dev, "idVendor");
const char* usb_product_id =
- udev_device_get_sysattr_value(usb_dev, "idProduct");
+ device::udev_device_get_sysattr_value(usb_dev, "idProduct");
if (strcmp(vendor_id, usb_vendor_id) == 0 &&
strcmp(product_id, usb_product_id) == 0) {
const char* manufacturer =
- udev_device_get_sysattr_value(usb_dev, "manufacturer");
- const char* product = udev_device_get_sysattr_value(usb_dev, "product");
+ device::udev_device_get_sysattr_value(usb_dev, "manufacturer");
+ const char* product =
+ device::udev_device_get_sysattr_value(usb_dev, "product");
// Replace the previous name string with one containing the better
// information, again driver returns utf-8 strings here so combine
@@ -205,25 +208,26 @@ void GamepadPlatformDataFetcherLinux::RefreshDevice(udev_device* dev) {
void GamepadPlatformDataFetcherLinux::EnumerateDevices() {
device::ScopedUdevEnumeratePtr enumerate(
- udev_enumerate_new(udev_->udev_handle()));
+ device::udev_enumerate_new(udev_->udev_handle()));
if (!enumerate)
return;
- int ret =
- udev_enumerate_add_match_subsystem(enumerate.get(), kInputSubsystem);
+ int ret = device::udev_enumerate_add_match_subsystem(enumerate.get(),
+ kInputSubsystem);
if (ret != 0)
return;
- ret = udev_enumerate_scan_devices(enumerate.get());
+ ret = device::udev_enumerate_scan_devices(enumerate.get());
if (ret != 0)
return;
- udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate.get());
+ udev_list_entry* devices =
+ device::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)) {
+ dev_list_entry = device::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);
+ const char* path = device::udev_list_entry_get_name(dev_list_entry);
device::ScopedUdevDevicePtr dev(
- udev_device_new_from_syspath(udev_->udev_handle(), path));
+ device::udev_device_new_from_syspath(udev_->udev_handle(), path));
if (!dev)
continue;
RefreshDevice(dev.get());
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 77c024e9369..e7c7c75d6a9 100644
--- a/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_mac.h
+++ b/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_mac.h
@@ -59,7 +59,7 @@ class GamepadPlatformDataFetcherMac : public GamepadDataFetcher,
size_t GetSlotForXboxDevice(XboxController* device);
void DeviceAdd(IOHIDDeviceRef device);
- void AddButtonsAndAxes(NSArray* elements, size_t slot);
+ bool AddButtonsAndAxes(NSArray* elements, size_t slot);
void DeviceRemove(IOHIDDeviceRef device);
void ValueChanged(IOHIDValueRef value);
diff --git a/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_mac.mm b/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_mac.mm
index fc457cdfb55..28c3c5ddf58 100644
--- a/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_mac.mm
+++ b/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_mac.mm
@@ -155,7 +155,7 @@ void GamepadPlatformDataFetcherMac::ValueChangedCallback(void* context,
InstanceFromContext(context)->ValueChanged(ref);
}
-void GamepadPlatformDataFetcherMac::AddButtonsAndAxes(NSArray* elements,
+bool GamepadPlatformDataFetcherMac::AddButtonsAndAxes(NSArray* elements,
size_t slot) {
WebGamepad& pad = data_.items[slot];
AssociatedData& associated = associated_[slot];
@@ -224,6 +224,8 @@ void GamepadPlatformDataFetcherMac::AddButtonsAndAxes(NSArray* elements,
break;
}
}
+
+ return (pad.axesLength > 0 || pad.buttonsLength > 0);
}
size_t GamepadPlatformDataFetcherMac::GetEmptySlot() {
@@ -281,6 +283,9 @@ void GamepadPlatformDataFetcherMac::DeviceAdd(IOHIDDeviceRef device) {
if (slot == WebGamepads::itemsLengthCap)
return;
+ // Clear some state that may have been left behind by previous gamepads
+ memset(&associated_[slot], 0, sizeof(AssociatedData));
+
NSNumber* vendor_id = CFToNSCast(CFCastStrict<CFNumberRef>(
IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVendorIDKey))));
NSNumber* product_id = CFToNSCast(CFCastStrict<CFNumberRef>(
@@ -318,7 +323,9 @@ void GamepadPlatformDataFetcherMac::DeviceAdd(IOHIDDeviceRef device) {
base::ScopedCFTypeRef<CFArrayRef> elements(
IOHIDDeviceCopyMatchingElements(device, NULL, kIOHIDOptionsTypeNone));
- AddButtonsAndAxes(CFToNSCast(elements), slot);
+
+ if (!AddButtonsAndAxes(CFToNSCast(elements), slot))
+ return;
associated_[slot].hid.device_ref = device;
data_.items[slot].connected = true;
diff --git a/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_win.cc b/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_win.cc
index c344e7e79d5..aca009605ed 100644
--- a/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_win.cc
+++ b/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_win.cc
@@ -4,8 +4,8 @@
#include "content/browser/gamepad/gamepad_platform_data_fetcher_win.h"
-#include "base/debug/trace_event.h"
#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event.h"
#include "base/win/windows_version.h"
#include "content/common/gamepad_hardware_buffer.h"
#include "content/common/gamepad_messages.h"
@@ -114,7 +114,6 @@ void GamepadPlatformDataFetcherWin::EnumerateDevices(
pad_state_[pad_index].status = XINPUT_CONNECTED;
pad_state_[pad_index].xinput_index = i;
pad_state_[pad_index].mapper = NULL;
- pads->length++;
}
}
@@ -123,6 +122,8 @@ void GamepadPlatformDataFetcherWin::EnumerateDevices(
raw_input_fetcher_->EnumerateDevices();
for (size_t i = 0; i < raw_inputs.size(); ++i) {
RawGamepadInfo* gamepad = raw_inputs[i];
+ if (gamepad->buttons_length == 0 && gamepad->axes_length == 0)
+ continue;
if (HasRawInputGamepad(gamepad->handle))
continue;
int pad_index = FirstAvailableGamepadId();
@@ -148,7 +149,6 @@ void GamepadPlatformDataFetcherWin::EnumerateDevices(
else
pad.mapping[0] = 0;
- pads->length++;
}
}
}
@@ -174,6 +174,7 @@ void GamepadPlatformDataFetcherWin::GetGamepadData(WebGamepads* pads,
if (devices_changed_hint)
EnumerateDevices(pads);
+ pads->length = 0;
for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) {
// We rely on device_changed and GetCapabilities to tell us that
// something's been connected, but we will mark as disconnected if
@@ -185,6 +186,9 @@ void GamepadPlatformDataFetcherWin::GetGamepadData(WebGamepads* pads,
GetXInputPadData(i, &pads->items[i]);
else if (pad_state_[i].status == RAWINPUT_CONNECTED)
GetRawInputPadData(i, &pads->items[i]);
+
+ if (pads->items[i].connected)
+ pads->length++;
}
}
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 d5cf220702c..33dab0ca2e6 100644
--- a/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_win.h
+++ b/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_win.h
@@ -32,10 +32,10 @@ namespace content {
class GamepadPlatformDataFetcherWin : public GamepadDataFetcher {
public:
GamepadPlatformDataFetcherWin();
- virtual ~GamepadPlatformDataFetcherWin();
- virtual void GetGamepadData(blink::WebGamepads* pads,
- bool devices_changed_hint) override;
- virtual void PauseHint(bool paused) override;
+ ~GamepadPlatformDataFetcherWin() override;
+ void GetGamepadData(blink::WebGamepads* pads,
+ bool devices_changed_hint) override;
+ 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 caa4cc82c66..e16339cbc96 100644
--- a/chromium/content/browser/gamepad/gamepad_provider.cc
+++ b/chromium/content/browser/gamepad/gamepad_provider.cc
@@ -10,6 +10,7 @@
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "base/message_loop/message_loop_proxy.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
#include "base/threading/thread.h"
#include "base/threading/thread_restrictions.h"
#include "content/browser/gamepad/gamepad_data_fetcher.h"
@@ -170,34 +171,34 @@ bool GamepadProvider::PadState::Match(const WebGamepad& pad) const {
return connected_ == pad.connected &&
axes_length_ == pad.axesLength &&
buttons_length_ == pad.buttonsLength &&
- memcmp(id_, pad.id, arraysize(id_)) == 0 &&
- memcmp(mapping_, pad.mapping, arraysize(mapping_)) == 0;
+ memcmp(id_, pad.id, sizeof(id_)) == 0 &&
+ memcmp(mapping_, pad.mapping, sizeof(mapping_)) == 0;
}
void GamepadProvider::PadState::SetPad(const WebGamepad& pad) {
connected_ = pad.connected;
axes_length_ = pad.axesLength;
buttons_length_ = pad.buttonsLength;
- memcpy(id_, pad.id, arraysize(id_));
- memcpy(mapping_, pad.mapping, arraysize(mapping_));
+ memcpy(id_, pad.id, sizeof(id_));
+ memcpy(mapping_, pad.mapping, sizeof(mapping_));
}
void GamepadProvider::PadState::SetDisconnected() {
connected_ = false;
axes_length_ = 0;
buttons_length_ = 0;
- memset(id_, 0, arraysize(id_));
- memset(mapping_, 0, arraysize(mapping_));
+ memset(id_, 0, sizeof(id_));
+ memset(mapping_, 0, sizeof(mapping_));
}
void GamepadProvider::PadState::AsWebGamepad(WebGamepad* pad) {
pad->connected = connected_;
pad->axesLength = axes_length_;
pad->buttonsLength = buttons_length_;
- memcpy(pad->id, id_, arraysize(id_));
- memcpy(pad->mapping, mapping_, arraysize(mapping_));
- memset(pad->axes, 0, arraysize(pad->axes));
- memset(pad->buttons, 0, arraysize(pad->buttons));
+ memcpy(pad->id, id_, sizeof(id_));
+ memcpy(pad->mapping, mapping_, sizeof(mapping_));
+ memset(pad->axes, 0, sizeof(pad->axes));
+ memset(pad->buttons, 0, sizeof(pad->buttons));
}
void GamepadProvider::DoPoll() {
diff --git a/chromium/content/browser/gamepad/gamepad_provider_unittest.cc b/chromium/content/browser/gamepad/gamepad_provider_unittest.cc
index e4f6571da27..eaea2c69f45 100644
--- a/chromium/content/browser/gamepad/gamepad_provider_unittest.cc
+++ b/chromium/content/browser/gamepad/gamepad_provider_unittest.cc
@@ -21,8 +21,8 @@ using blink::WebGamepads;
class UserGestureListener {
public:
UserGestureListener()
- : weak_factory_(this),
- has_user_gesture_(false) {
+ : has_user_gesture_(false),
+ weak_factory_(this) {
}
base::Closure GetClosure() {
@@ -37,8 +37,8 @@ class UserGestureListener {
has_user_gesture_ = true;
}
- base::WeakPtrFactory<UserGestureListener> weak_factory_;
bool has_user_gesture_;
+ base::WeakPtrFactory<UserGestureListener> weak_factory_;
};
// Main test fixture
diff --git a/chromium/content/browser/gamepad/gamepad_service.h b/chromium/content/browser/gamepad/gamepad_service.h
index 726558936af..345a83c55d0 100644
--- a/chromium/content/browser/gamepad/gamepad_service.h
+++ b/chromium/content/browser/gamepad/gamepad_service.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_GAMEPAD_GAMEPAD_SERVICE_H
-#define CONTENT_BROWSER_GAMEPAD_GAMEPAD_SERVICE_H
+#ifndef CONTENT_BROWSER_GAMEPAD_GAMEPAD_SERVICE_H_
+#define CONTENT_BROWSER_GAMEPAD_GAMEPAD_SERVICE_H_
#include <set>
diff --git a/chromium/content/browser/gamepad/gamepad_standard_mappings_linux.cc b/chromium/content/browser/gamepad/gamepad_standard_mappings_linux.cc
index a0852420c6a..48b59ac5a90 100644
--- a/chromium/content/browser/gamepad/gamepad_standard_mappings_linux.cc
+++ b/chromium/content/browser/gamepad/gamepad_standard_mappings_linux.cc
@@ -108,6 +108,26 @@ void MapperDualshock4(const blink::WebGamepad& input,
mapped->axesLength = AXIS_INDEX_COUNT;
}
+void MapperIBuffalo(const blink::WebGamepad& input, blink::WebGamepad* mapped) {
+ *mapped = input;
+ mapped->buttons[BUTTON_INDEX_PRIMARY] = input.buttons[1];
+ mapped->buttons[BUTTON_INDEX_SECONDARY] = input.buttons[0];
+ mapped->buttons[BUTTON_INDEX_TERTIARY] = input.buttons[3];
+ mapped->buttons[BUTTON_INDEX_QUATERNARY] = input.buttons[2];
+ mapped->buttons[BUTTON_INDEX_BACK_SELECT] = input.buttons[6];
+ mapped->buttons[BUTTON_INDEX_START] = 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[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]);
+ mapped->buttonsLength = BUTTON_INDEX_COUNT - 1; /* no meta */
+ mapped->axesLength = 2;
+}
+
+
void MapperXGEAR(const blink::WebGamepad& input, blink::WebGamepad* mapped) {
*mapped = input;
mapped->buttons[BUTTON_INDEX_PRIMARY] = input.buttons[2];
@@ -186,6 +206,25 @@ void MapperADT1(const blink::WebGamepad& input, blink::WebGamepad* mapped) {
mapped->axesLength = AXIS_INDEX_COUNT;
}
+void MapperNvShield(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] = input.buttons[7];
+ mapped->buttons[BUTTON_INDEX_LEFT_THUMBSTICK] = input.buttons[8];
+ mapped->buttons[BUTTON_INDEX_RIGHT_THUMBSTICK] = input.buttons[9];
+ 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;
@@ -202,12 +241,14 @@ struct MappingData {
{"046d", "c21f", MapperXInputStyleGamepad}, // Logitech F710
{"054c", "0268", MapperPlaystationSixAxis}, // Playstation SIXAXIS
{"054c", "05c4", MapperDualshock4}, // Playstation Dualshock 4
+ {"0583", "2060", MapperIBuffalo}, // iBuffalo Classic
{"0925", "0005", MapperLakeviewResearch}, // SmartJoy PLUS Adapter
{"0925", "8866", MapperLakeviewResearch}, // WiseGroup MP-8866
+ {"0955", "7210", MapperNvShield}, // Nvidia Shield gamepad
{"0e8f", "0003", MapperXGEAR}, // XFXforce XGEAR PS2 Controller
+ {"18d1", "2c40", MapperADT1}, // ADT-1 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 ebb08eda640..4377bd2af11 100644
--- a/chromium/content/browser/gamepad/gamepad_standard_mappings_mac.mm
+++ b/chromium/content/browser/gamepad/gamepad_standard_mappings_mac.mm
@@ -48,7 +48,7 @@ void MapperPlaystationSixAxis(const blink::WebGamepad& input,
mapped->buttons[BUTTON_INDEX_LEFT_THUMBSTICK] = input.buttons[1];
mapped->buttons[BUTTON_INDEX_RIGHT_THUMBSTICK] = input.buttons[2];
- // The SixAxis Dpad is pressure sensative
+ // The SixAxis Dpad is pressure sensitive.
mapped->buttons[BUTTON_INDEX_DPAD_UP] =
ButtonFromButtonAndAxis(input.buttons[4], input.axes[10]);
mapped->buttons[BUTTON_INDEX_DPAD_DOWN] =
@@ -94,6 +94,25 @@ void MapperDualshock4(const blink::WebGamepad& input,
mapped->axesLength = AXIS_INDEX_COUNT;
}
+void MapperIBuffalo(const blink::WebGamepad& input, blink::WebGamepad* mapped) {
+ *mapped = input;
+ mapped->buttons[BUTTON_INDEX_PRIMARY] = input.buttons[1];
+ mapped->buttons[BUTTON_INDEX_SECONDARY] = input.buttons[0];
+ mapped->buttons[BUTTON_INDEX_TERTIARY] = input.buttons[3];
+ mapped->buttons[BUTTON_INDEX_QUATERNARY] = input.buttons[2];
+ mapped->buttons[BUTTON_INDEX_BACK_SELECT] = input.buttons[6];
+ mapped->buttons[BUTTON_INDEX_START] = 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[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]);
+ mapped->buttonsLength = BUTTON_INDEX_COUNT - 1; /* no meta */
+ mapped->axesLength = 2;
+}
+
void MapperDirectInputStyle(const blink::WebGamepad& input,
blink::WebGamepad* mapped) {
*mapped = input;
@@ -242,22 +261,23 @@ 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)
- {"18d1", "2c40", MapperADT1}, // ADT-1 Controller
+ // 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
+ {"0583", "2060", MapperIBuffalo}, // iBuffalo Classic
+ {"0925", "0005", MapperSmartJoyPLUS}, // SmartJoy PLUS Adapter
+ {"0e8f", "0003", MapperXGEAR}, // XFXforce XGEAR PS2 Controller
+ {"18d1", "2c40", MapperADT1}, // ADT-1 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)
};
} // namespace
diff --git a/chromium/content/browser/gamepad/gamepad_standard_mappings_win.cc b/chromium/content/browser/gamepad/gamepad_standard_mappings_win.cc
index 93c18517453..c03fe4fbf70 100644
--- a/chromium/content/browser/gamepad/gamepad_standard_mappings_win.cc
+++ b/chromium/content/browser/gamepad/gamepad_standard_mappings_win.cc
@@ -74,6 +74,25 @@ void MapperDualshock4(const blink::WebGamepad& input,
mapped->axesLength = AXIS_INDEX_COUNT;
}
+void MapperIBuffalo(const blink::WebGamepad& input, blink::WebGamepad* mapped) {
+ *mapped = input;
+ mapped->buttons[BUTTON_INDEX_PRIMARY] = input.buttons[1];
+ mapped->buttons[BUTTON_INDEX_SECONDARY] = input.buttons[0];
+ mapped->buttons[BUTTON_INDEX_TERTIARY] = input.buttons[3];
+ mapped->buttons[BUTTON_INDEX_QUATERNARY] = input.buttons[2];
+ mapped->buttons[BUTTON_INDEX_BACK_SELECT] = input.buttons[6];
+ mapped->buttons[BUTTON_INDEX_START] = 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[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]);
+ mapped->buttonsLength = BUTTON_INDEX_COUNT - 1; /* no meta */
+ mapped->axesLength = 2;
+}
+
void MapperOnLiveWireless(const blink::WebGamepad& input,
blink::WebGamepad* mapped) {
*mapped = input;
@@ -120,18 +139,42 @@ void MapperADT1(const blink::WebGamepad& input, blink::WebGamepad* mapped) {
mapped->axesLength = AXIS_INDEX_COUNT;
}
+void MapperNvShield(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] = 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[8];
+ 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 {
const char* const vendor_id;
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)
- {"18d1", "2c40", MapperADT1}, // ADT-1 Controller
+ // http://www.linux-usb.org/usb.ids
+ {"0079", "0011", Mapper2Axes8Keys}, // 2Axes 8Keys Game Pad
+ {"046d", "c216", MapperLogitechDualAction}, // Logitech DualAction
+ {"054c", "05c4", MapperDualshock4}, // Playstation Dualshock 4
+ {"0583", "2060", MapperIBuffalo}, // iBuffalo Classic
+ {"0955", "7210", MapperNvShield}, // Nvidia Shield gamepad
+ {"18d1", "2c40", MapperADT1}, // ADT-1 Controller
+ {"2378", "1008", MapperOnLiveWireless}, // OnLive Controller (Bluetooth)
+ {"2378", "100a", MapperOnLiveWireless}, // OnLive Controller (Wired)
};
} // namespace
diff --git a/chromium/content/browser/gamepad/raw_input_data_fetcher_win.cc b/chromium/content/browser/gamepad/raw_input_data_fetcher_win.cc
index 05748216b27..8b3b34fb006 100644
--- a/chromium/content/browser/gamepad/raw_input_data_fetcher_win.cc
+++ b/chromium/content/browser/gamepad/raw_input_data_fetcher_win.cc
@@ -4,7 +4,7 @@
#include "content/browser/gamepad/raw_input_data_fetcher_win.h"
-#include "base/debug/trace_event.h"
+#include "base/trace_event/trace_event.h"
#include "content/common/gamepad_hardware_buffer.h"
#include "content/common/gamepad_messages.h"
@@ -18,6 +18,10 @@ float NormalizeAxis(long value, long min, long max) {
return (2.f * (value - min) / static_cast<float>(max - min)) - 1.f;
}
+unsigned long GetBitmask(unsigned short bits) {
+ return (1 << bits) - 1;
+}
+
// From the HID Usage Tables specification.
USHORT DeviceUsages[] = {
0x04, // Joysticks
@@ -28,15 +32,23 @@ USHORT DeviceUsages[] = {
const uint32_t kAxisMinimumUsageNumber = 0x30;
const uint32_t kGameControlsUsagePage = 0x05;
-} // namespace
+} // namespace
+
+RawGamepadInfo::RawGamepadInfo() {
+}
+
+RawGamepadInfo::~RawGamepadInfo() {
+}
RawInputDataFetcher::RawInputDataFetcher()
- : hid_dll_(base::FilePath(FILE_PATH_LITERAL("hid.dll")))
- , rawinput_available_(GetHidDllFunctions())
- , filter_xinput_(true)
- , events_monitored_(false) {}
+ : hid_dll_(base::FilePath(FILE_PATH_LITERAL("hid.dll"))),
+ rawinput_available_(GetHidDllFunctions()),
+ filter_xinput_(true),
+ events_monitored_(false) {
+}
RawInputDataFetcher::~RawInputDataFetcher() {
+ ClearControllers();
DCHECK(!window_);
DCHECK(!events_monitored_);
}
@@ -52,7 +64,7 @@ RAWINPUTDEVICE* RawInputDataFetcher::GetRawInputDevices(DWORD flags) {
devices[i].dwFlags = flags;
devices[i].usUsagePage = 1;
devices[i].usUsage = DeviceUsages[i];
- devices[i].hwndTarget = window_->hwnd();
+ devices[i].hwndTarget = (flags & RIDEV_REMOVE) ? 0 : window_->hwnd();
}
return devices.release();
}
@@ -103,7 +115,6 @@ void RawInputDataFetcher::StopMonitor() {
events_monitored_ = false;
window_.reset();
- ClearControllers();
// Stop observing message loop destruction if no event is being monitored.
base::MessageLoop::current()->RemoveDestructionObserver(this);
@@ -303,6 +314,7 @@ RawGamepadInfo* RawInputDataFetcher::ParseGamepadInfo(HANDLE hDevice) {
gamepad_info->axes[axis_index].caps = axes_caps[i];
gamepad_info->axes[axis_index].value = 0;
gamepad_info->axes[axis_index].active = true;
+ gamepad_info->axes[axis_index].bitmask = GetBitmask(axes_caps[i].BitSize);
gamepad_info->axes_length =
std::max(gamepad_info->axes_length, axis_index + 1);
} else {
@@ -326,6 +338,8 @@ RawGamepadInfo* RawInputDataFetcher::ParseGamepadInfo(HANDLE hDevice) {
gamepad_info->axes[next_index].caps = axes_caps[i];
gamepad_info->axes[next_index].value = 0;
gamepad_info->axes[next_index].active = true;
+ gamepad_info->axes[next_index].bitmask = GetBitmask(
+ axes_caps[i].BitSize);
gamepad_info->axes_length =
std::max(gamepad_info->axes_length, next_index + 1);
}
@@ -397,7 +411,7 @@ void RawInputDataFetcher::UpdateGamepad(
input->data.hid.dwSizeHid);
if (status == HIDP_STATUS_SUCCESS) {
axis->value = NormalizeAxis(scaled_axis_value,
- axis->caps.LogicalMin, axis->caps.LogicalMax);
+ axis->caps.PhysicalMin, axis->caps.PhysicalMax);
}
} else {
status = hidp_get_usage_value_(HidP_Input, axis->caps.UsagePage, 0,
@@ -406,8 +420,9 @@ void RawInputDataFetcher::UpdateGamepad(
reinterpret_cast<PCHAR>(input->data.hid.bRawData),
input->data.hid.dwSizeHid);
if (status == HIDP_STATUS_SUCCESS) {
- axis->value = NormalizeAxis(axis_value,
- axis->caps.LogicalMin, axis->caps.LogicalMax);
+ axis->value = NormalizeAxis(axis_value & axis->bitmask,
+ axis->caps.LogicalMin & axis->bitmask,
+ axis->caps.LogicalMax & axis->bitmask);
}
}
}
@@ -446,9 +461,9 @@ LRESULT RawInputDataFetcher::OnInput(HRAWINPUT input_handle) {
}
bool RawInputDataFetcher::HandleMessage(UINT message,
- WPARAM wparam,
- LPARAM lparam,
- LRESULT* result) {
+ WPARAM wparam,
+ LPARAM lparam,
+ LRESULT* result) {
switch (message) {
case WM_INPUT:
*result = OnInput(reinterpret_cast<HRAWINPUT>(lparam));
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 16908c11646..3de85df7326 100644
--- a/chromium/content/browser/gamepad/raw_input_data_fetcher_win.h
+++ b/chromium/content/browser/gamepad/raw_input_data_fetcher_win.h
@@ -31,9 +31,13 @@ struct RawGamepadAxis {
HIDP_VALUE_CAPS caps;
float value;
bool active;
+ unsigned long bitmask;
};
struct RawGamepadInfo {
+ RawGamepadInfo();
+ ~RawGamepadInfo();
+
HANDLE handle;
scoped_ptr<uint8[]> ppd_buffer;
PHIDP_PREPARSED_DATA preparsed_data;
@@ -56,10 +60,10 @@ class RawInputDataFetcher
public base::MessageLoop::DestructionObserver {
public:
explicit RawInputDataFetcher();
- ~RawInputDataFetcher();
+ ~RawInputDataFetcher() override;
// DestructionObserver overrides.
- virtual void WillDestroyCurrentMessageLoop() override;
+ void WillDestroyCurrentMessageLoop() override;
bool Available() { return rawinput_available_; }
void StartMonitor();
diff --git a/chromium/content/browser/gamepad/xbox_data_fetcher_mac.cc b/chromium/content/browser/gamepad/xbox_data_fetcher_mac.cc
index 0626f94212c..163f96cb3ac 100644
--- a/chromium/content/browser/gamepad/xbox_data_fetcher_mac.cc
+++ b/chromium/content/browser/gamepad/xbox_data_fetcher_mac.cc
@@ -113,8 +113,8 @@ struct XboxOneButtonData {
};
#pragma pack(pop)
-COMPILE_ASSERT(sizeof(Xbox360ButtonData) == 18, xbox_button_data_wrong_size);
-COMPILE_ASSERT(sizeof(XboxOneButtonData) == 14, xbox_button_data_wrong_size);
+static_assert(sizeof(Xbox360ButtonData) == 18, "xbox button data wrong size");
+static_assert(sizeof(XboxOneButtonData) == 14, "xbox button data wrong size");
// From MSDN:
// http://msdn.microsoft.com/en-us/library/windows/desktop/ee417001(v=vs.85).aspx#dead_zone
diff --git a/chromium/content/browser/geofencing/geofencing_dispatcher_host.cc b/chromium/content/browser/geofencing/geofencing_dispatcher_host.cc
index 5cae1136bc9..4b8c865a2c1 100644
--- a/chromium/content/browser/geofencing/geofencing_dispatcher_host.cc
+++ b/chromium/content/browser/geofencing/geofencing_dispatcher_host.cc
@@ -32,6 +32,10 @@ bool GeofencingDispatcherHost::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(GeofencingHostMsg_UnregisterRegion, OnUnregisterRegion)
IPC_MESSAGE_HANDLER(GeofencingHostMsg_GetRegisteredRegions,
OnGetRegisteredRegions)
+ IPC_MESSAGE_FORWARD(GeofencingHostMsg_SetMockProvider, manager_.get(),
+ GeofencingManager::SetMockProvider)
+ IPC_MESSAGE_FORWARD(GeofencingHostMsg_SetMockPosition, manager_.get(),
+ GeofencingManager::SetMockPosition)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
diff --git a/chromium/content/browser/geofencing/geofencing_dispatcher_host.h b/chromium/content/browser/geofencing/geofencing_dispatcher_host.h
index 40ed3a8487b..ea4b6a1e66e 100644
--- a/chromium/content/browser/geofencing/geofencing_dispatcher_host.h
+++ b/chromium/content/browser/geofencing/geofencing_dispatcher_host.h
@@ -5,7 +5,7 @@
#ifndef CONTENT_BROWSER_GEOFENCING_GEOFENCING_DISPATCHER_HOST_H_
#define CONTENT_BROWSER_GEOFENCING_GEOFENCING_DISPATCHER_HOST_H_
-#include "content/common/geofencing_status.h"
+#include "content/common/geofencing_types.h"
#include "content/public/browser/browser_message_filter.h"
namespace blink {
diff --git a/chromium/content/browser/geofencing/geofencing_manager.cc b/chromium/content/browser/geofencing/geofencing_manager.cc
index 6899c73067a..d44605771f8 100644
--- a/chromium/content/browser/geofencing/geofencing_manager.cc
+++ b/chromium/content/browser/geofencing/geofencing_manager.cc
@@ -8,6 +8,7 @@
#include "base/callback.h"
#include "content/browser/geofencing/geofencing_service.h"
+#include "content/browser/geofencing/mock_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"
@@ -82,18 +83,20 @@ void GeofencingManager::Shutdown() {
void GeofencingManager::InitOnIO() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- service_ = GeofencingServiceImpl::GetInstance();
+ service_worker_context_->AddObserver(this);
+ if (!service_)
+ service_ = GeofencingServiceImpl::GetInstance();
}
void GeofencingManager::ShutdownOnIO() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ service_worker_context_->RemoveObserver(this);
// 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_) {
+ for (const auto& registration : registrations_by_id_)
service_->UnregisterRegion(registration.first);
- }
}
void GeofencingManager::RegisterRegion(
@@ -105,21 +108,18 @@ void GeofencingManager::RegisterRegion(
// 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();
+ // Look up service worker.
+ ServiceWorkerRegistration* service_worker_registration =
+ service_worker_context_->GetLiveRegistration(
+ service_worker_registration_id);
+ if (!service_worker_registration) {
+ callback.Run(GEOFENCING_STATUS_OPERATION_FAILED_NO_SERVICE_WORKER);
+ return;
}
+ GURL service_worker_origin =
+ service_worker_registration->pattern().GetOrigin();
+
if (!service_->IsServiceAvailable()) {
callback.Run(GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE);
return;
@@ -132,11 +132,8 @@ void GeofencingManager::RegisterRegion(
return;
}
- AddRegistration(service_worker_registration_id,
- service_worker_origin,
- region_id,
- region,
- callback,
+ AddRegistration(service_worker_registration_id, service_worker_origin,
+ region_id, region, callback,
service_->RegisterRegion(region, this));
}
@@ -147,16 +144,13 @@ void GeofencingManager::UnregisterRegion(int64 service_worker_registration_id,
// 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;
- }
+ // Look up service worker.
+ ServiceWorkerRegistration* service_worker_registration =
+ service_worker_context_->GetLiveRegistration(
+ service_worker_registration_id);
+ if (!service_worker_registration) {
+ callback.Run(GEOFENCING_STATUS_OPERATION_FAILED_NO_SERVICE_WORKER);
+ return;
}
if (!service_->IsServiceAvailable()) {
@@ -189,15 +183,12 @@ GeofencingStatus GeofencingManager::GetRegisteredRegions(
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;
- }
+ // Look up service worker.
+ ServiceWorkerRegistration* service_worker_registration =
+ service_worker_context_->GetLiveRegistration(
+ service_worker_registration_id);
+ if (!service_worker_registration) {
+ return GEOFENCING_STATUS_OPERATION_FAILED_NO_SERVICE_WORKER;
}
if (!service_->IsServiceAvailable()) {
@@ -217,6 +208,44 @@ GeofencingStatus GeofencingManager::GetRegisteredRegions(
return GEOFENCING_STATUS_OK;
}
+void GeofencingManager::SetMockProvider(GeofencingMockState mock_state) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ // TODO(mek): It would be nice if enabling the mock geofencing service
+ // wouldn't completely delete all existing registrations but instead just
+ // somehow keep them around but inactive.
+ // For now mocking is only used in layout tests, so just clearing all
+ // registrations works good enough.
+ for (const auto& registration : registrations_by_id_)
+ service_->UnregisterRegion(registration.first);
+ registrations_by_id_.clear();
+ registrations_.clear();
+
+ // Then set or reset the mock service for the service worker.
+ if (mock_state == GeofencingMockState::NONE) {
+ service_ = GeofencingServiceImpl::GetInstance();
+ mock_service_.reset();
+ } else {
+ mock_service_.reset(new MockGeofencingService(
+ mock_state != GeofencingMockState::SERVICE_UNAVAILABLE));
+ service_ = mock_service_.get();
+ }
+}
+
+void GeofencingManager::SetMockPosition(double latitude, double longitude) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (!mock_service_)
+ return;
+ mock_service_->SetMockPosition(latitude, longitude);
+}
+
+void GeofencingManager::OnRegistrationDeleted(
+ int64 service_worker_registration_id,
+ const GURL& pattern) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ CleanUpForServiceWorker(service_worker_registration_id);
+}
+
void GeofencingManager::RegistrationFinished(int64 geofencing_registration_id,
GeofencingStatus status) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -300,6 +329,23 @@ void GeofencingManager::ClearRegistration(Registration* registration) {
registrations_.erase(registrations_iterator);
}
+void GeofencingManager::CleanUpForServiceWorker(
+ int64 service_worker_registration_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ ServiceWorkerRegistrationsMap::iterator registrations_iterator =
+ registrations_.find(service_worker_registration_id);
+ if (registrations_iterator == registrations_.end())
+ return;
+
+ for (const auto& registration : registrations_iterator->second) {
+ int geofencing_registration_id =
+ registration.second.geofencing_registration_id;
+ service_->UnregisterRegion(geofencing_registration_id);
+ registrations_by_id_.erase(geofencing_registration_id);
+ }
+ registrations_.erase(service_worker_registration_id);
+}
+
void GeofencingManager::DispatchGeofencingEvent(
blink::WebGeofencingEventType event_type,
int64 geofencing_registration_id) {
@@ -312,7 +358,7 @@ void GeofencingManager::DispatchGeofencingEvent(
return;
}
- service_worker_context_->context()->storage()->FindRegistrationForId(
+ service_worker_context_->FindRegistrationForId(
registration->service_worker_registration_id,
registration->service_worker_origin,
base::Bind(&GeofencingManager::DeliverGeofencingEvent,
diff --git a/chromium/content/browser/geofencing/geofencing_manager.h b/chromium/content/browser/geofencing/geofencing_manager.h
index 29c52e4830b..6954d7bd39b 100644
--- a/chromium/content/browser/geofencing/geofencing_manager.h
+++ b/chromium/content/browser/geofencing/geofencing_manager.h
@@ -14,9 +14,10 @@
#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_context_observer.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/geofencing_types.h"
#include "content/common/service_worker/service_worker_status_code.h"
template <typename T>
@@ -30,6 +31,7 @@ struct WebCircularGeofencingRegion;
namespace content {
class GeofencingService;
+class MockGeofencingService;
class ServiceWorkerContextWrapper;
class ServiceWorkerRegistration;
@@ -41,10 +43,9 @@ class ServiceWorkerRegistration;
// 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),
+ NON_EXPORTED_BASE(public ServiceWorkerContextObserver),
public base::RefCountedThreadSafe<GeofencingManager> {
public:
typedef base::Callback<void(GeofencingStatus)> StatusCallback;
@@ -89,6 +90,14 @@ class CONTENT_EXPORT GeofencingManager
int64 service_worker_registration_id,
std::map<std::string, blink::WebCircularGeofencingRegion>* result);
+ // Enables or disables mock geofencing service.
+ void SetMockProvider(GeofencingMockState mock_state);
+
+ // Set the mock geofencing position.
+ // TODO(mek): Unify this mock position with the devtools exposed geolocation
+ // mock position (http://crbug.com/440902).
+ void SetMockPosition(double latitude, double longitude);
+
void SetServiceForTesting(GeofencingService* service) {
service_ = service;
}
@@ -104,6 +113,10 @@ class CONTENT_EXPORT GeofencingManager
void InitOnIO();
void ShutdownOnIO();
+ // ServiceWorkerContextObserver implementation.
+ void OnRegistrationDeleted(int64 service_worker_registration_id,
+ const GURL& pattern) override;
+
// GeofencingRegistrationDelegate implementation.
void RegistrationFinished(int64 geofencing_registration_id,
GeofencingStatus status) override;
@@ -132,6 +145,10 @@ class CONTENT_EXPORT GeofencingManager
// Clears a registration.
void ClearRegistration(Registration* registration);
+ // Unregisters and clears all registrations associated with a specific
+ // service worker.
+ void CleanUpForServiceWorker(int64 service_worker_registration_id);
+
// 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
@@ -169,6 +186,7 @@ class CONTENT_EXPORT GeofencingManager
RegistrationIdRegistrationMap registrations_by_id_;
GeofencingService* service_;
+ scoped_ptr<MockGeofencingService> mock_service_;
scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_;
DISALLOW_COPY_AND_ASSIGN(GeofencingManager);
diff --git a/chromium/content/browser/geofencing/geofencing_manager_unittest.cc b/chromium/content/browser/geofencing/geofencing_manager_unittest.cc
index cf64b9faa04..16cf1bbe895 100644
--- a/chromium/content/browser/geofencing/geofencing_manager_unittest.cc
+++ b/chromium/content/browser/geofencing/geofencing_manager_unittest.cc
@@ -6,6 +6,7 @@
#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/embedded_worker_test_helper.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"
@@ -18,9 +19,8 @@ typedef std::map<std::string, WebCircularGeofencingRegion> RegionMap;
namespace {
+static const int kRenderProcessId = 99;
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;
@@ -36,11 +36,21 @@ namespace content {
class TestGeofencingService : public GeofencingService {
public:
- MOCK_METHOD0(IsServiceAvailable, bool());
+ TestGeofencingService() : is_available_(false) {}
+
+ bool IsServiceAvailable() override { return is_available_; }
+
+ void SetIsServiceAvailable(bool is_available) {
+ is_available_ = is_available;
+ }
+
MOCK_METHOD2(RegisterRegion,
int64(const WebCircularGeofencingRegion& region,
GeofencingRegistrationDelegate* delegate));
MOCK_METHOD1(UnregisterRegion, void(int64 geofencing_registration_id));
+
+ private:
+ bool is_available_;
};
ACTION_P(SaveDelegate, delegate) {
@@ -78,6 +88,31 @@ class StatusCatcher {
scoped_refptr<MessageLoopRunner> runner_;
};
+void SaveResponseCallback(bool* called,
+ int64* store_registration_id,
+ ServiceWorkerStatusCode status,
+ const std::string& status_message,
+ int64 registration_id) {
+ EXPECT_EQ(SERVICE_WORKER_OK, status) << ServiceWorkerStatusToString(status);
+ *called = true;
+ *store_registration_id = registration_id;
+}
+
+ServiceWorkerContextCore::RegistrationCallback MakeRegisteredCallback(
+ bool* called,
+ int64* store_registration_id) {
+ return base::Bind(&SaveResponseCallback, called, store_registration_id);
+}
+
+void CallCompletedCallback(bool* called, ServiceWorkerStatusCode) {
+ *called = true;
+}
+
+ServiceWorkerContextCore::UnregistrationCallback MakeUnregisteredCallback(
+ bool* called) {
+ return base::Bind(&CallCompletedCallback, called);
+}
+
class GeofencingManagerTest : public testing::Test {
public:
GeofencingManagerTest() : service_(nullptr) {
@@ -88,22 +123,58 @@ class GeofencingManagerTest : public testing::Test {
}
void SetUp() override {
+ helper_.reset(
+ new EmbeddedWorkerTestHelper(base::FilePath(), kRenderProcessId));
service_ = new TestGeofencingService();
- ON_CALL(*service_, IsServiceAvailable())
- .WillByDefault(testing::Return(false));
- manager_ = new GeofencingManager(nullptr /* ServiceWorkerContextWrapper */);
+ manager_ = new GeofencingManager(helper_->context_wrapper());
manager_->SetServiceForTesting(service_);
+ manager_->Init();
+
+ worker1_ = RegisterServiceWorker("1");
+ worker2_ = RegisterServiceWorker("2");
}
void TearDown() override {
+ worker1_ = nullptr;
+ worker2_ = nullptr;
manager_ = nullptr;
delete service_;
service_ = nullptr;
+ helper_.reset();
}
- void SetHasProviderForTests() {
- ON_CALL(*service_, IsServiceAvailable())
- .WillByDefault(testing::Return(true));
+ void SetHasProviderForTests() { service_->SetIsServiceAvailable(true); }
+
+ scoped_refptr<ServiceWorkerRegistration> RegisterServiceWorker(
+ const std::string& name) {
+ GURL pattern("http://www.example.com/" + name);
+ GURL script_url("http://www.example.com/service_worker.js");
+ int64 registration_id = kInvalidServiceWorkerRegistrationId;
+ bool called = false;
+ helper_->context()->RegisterServiceWorker(
+ pattern, script_url, nullptr,
+ MakeRegisteredCallback(&called, &registration_id));
+
+ EXPECT_FALSE(called);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(called);
+ scoped_refptr<ServiceWorkerRegistration> worker(
+ new ServiceWorkerRegistration(pattern, registration_id,
+ helper_->context()->AsWeakPtr()));
+ // ServiceWorkerRegistration posts a notification task on construction.
+ base::RunLoop().RunUntilIdle();
+ return worker;
+ }
+
+ void UnregisterServiceWorker(
+ const scoped_refptr<ServiceWorkerRegistration>& registration) {
+ bool called = false;
+ helper_->context()->UnregisterServiceWorker(
+ registration->pattern(), MakeUnregisteredCallback(&called));
+
+ EXPECT_FALSE(called);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(called);
}
GeofencingStatus RegisterRegionSync(
@@ -174,101 +245,86 @@ class GeofencingManagerTest : public testing::Test {
protected:
TestBrowserThreadBundle threads_;
+ scoped_ptr<EmbeddedWorkerTestHelper> helper_;
TestGeofencingService* service_;
scoped_refptr<GeofencingManager> manager_;
WebCircularGeofencingRegion test_region_;
RegionMap expected_regions_;
+
+ scoped_refptr<ServiceWorkerRegistration> worker1_;
+ scoped_refptr<ServiceWorkerRegistration> worker2_;
};
TEST_F(GeofencingManagerTest, RegisterRegion_NoService) {
EXPECT_EQ(GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE,
- RegisterRegionSync(
- kTestServiceWorkerRegistrationId, kTestRegionId, test_region_));
+ RegisterRegionSync(worker1_->id(), kTestRegionId, test_region_));
}
TEST_F(GeofencingManagerTest, UnregisterRegion_NoService) {
EXPECT_EQ(GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE,
- UnregisterRegionSync(
- kTestServiceWorkerRegistrationId, kTestRegionId, false));
+ UnregisterRegionSync(worker1_->id(), kTestRegionId, false));
}
TEST_F(GeofencingManagerTest, GetRegisteredRegions_NoService) {
RegionMap regions;
EXPECT_EQ(GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE,
- manager_->GetRegisteredRegions(kTestServiceWorkerRegistrationId,
- &regions));
+ manager_->GetRegisteredRegions(worker1_->id(), &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));
+ EXPECT_EQ(GEOFENCING_STATUS_ERROR,
+ RegisterRegionSyncWithServiceResult(worker1_->id(), 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_);
+ EXPECT_EQ(GEOFENCING_STATUS_OK,
+ RegisterRegionSyncWithServiceResult(
+ worker1_->id(), kTestRegionId, test_region_,
+ GEOFENCING_STATUS_OK, kTestGeofencingRegistrationId));
+ VerifyRegions(worker1_->id(), 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_);
+ EXPECT_EQ(GEOFENCING_STATUS_OK,
+ RegisterRegionSyncWithServiceResult(
+ worker1_->id(), kTestRegionId, test_region_,
+ GEOFENCING_STATUS_OK, kTestGeofencingRegistrationId));
+ VerifyRegions(worker1_->id(), 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_);
+ RegisterRegionSync(worker1_->id(), kTestRegionId, region2));
+ VerifyRegions(worker1_->id(), expected_regions_);
}
TEST_F(GeofencingManagerTest, UnregisterRegion_NotRegistered) {
SetHasProviderForTests();
EXPECT_EQ(GEOFENCING_STATUS_UNREGISTRATION_FAILED_NOT_REGISTERED,
- UnregisterRegionSync(
- kTestServiceWorkerRegistrationId, kTestRegionId, false));
+ UnregisterRegionSync(worker1_->id(), 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,
+ RegisterRegionSyncWithServiceResult(
+ worker1_->id(), kTestRegionId, test_region_,
+ GEOFENCING_STATUS_OK, kTestGeofencingRegistrationId));
EXPECT_EQ(GEOFENCING_STATUS_OK,
- UnregisterRegionSync(kTestServiceWorkerRegistrationId,
- kTestRegionId,
- true,
+ UnregisterRegionSync(worker1_->id(), kTestRegionId, true,
kTestGeofencingRegistrationId));
- VerifyRegions(kTestServiceWorkerRegistrationId, RegionMap());
+ VerifyRegions(worker1_->id(), RegionMap());
}
TEST_F(GeofencingManagerTest, GetRegisteredRegions_RegistrationInProgress) {
@@ -282,22 +338,20 @@ TEST_F(GeofencingManagerTest, GetRegisteredRegions_RegistrationInProgress) {
.WillOnce(testing::DoAll(SaveDelegate(&delegate),
testing::Return(kTestGeofencingRegistrationId)));
manager_->RegisterRegion(
- kTestServiceWorkerRegistrationId,
- kTestRegionId,
- test_region_,
+ worker1_->id(), 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());
+ VerifyRegions(worker1_->id(), 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_);
+ VerifyRegions(worker1_->id(), expected_regions_);
}
TEST_F(GeofencingManagerTest, UnregisterRegion_RegistrationInProgress) {
@@ -311,9 +365,7 @@ TEST_F(GeofencingManagerTest, UnregisterRegion_RegistrationInProgress) {
.WillOnce(testing::DoAll(SaveDelegate(&delegate),
testing::Return(kTestGeofencingRegistrationId)));
manager_->RegisterRegion(
- kTestServiceWorkerRegistrationId,
- kTestRegionId,
- test_region_,
+ worker1_->id(), kTestRegionId, test_region_,
base::Bind(&StatusCatcher::Done, base::Unretained(&result)));
// At this point the manager should have tried registering the region with
@@ -322,88 +374,68 @@ TEST_F(GeofencingManagerTest, UnregisterRegion_RegistrationInProgress) {
EXPECT_NE(delegate, nullptr);
EXPECT_EQ(GEOFENCING_STATUS_UNREGISTRATION_FAILED_NOT_REGISTERED,
- UnregisterRegionSync(
- kTestServiceWorkerRegistrationId, kTestRegionId, false));
+ UnregisterRegionSync(worker1_->id(), kTestRegionId, false));
}
TEST_F(GeofencingManagerTest, GetRegisteredRegions_NoRegions) {
SetHasProviderForTests();
- VerifyRegions(kTestServiceWorkerRegistrationId, RegionMap());
+ VerifyRegions(worker1_->id(), 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_);
+ EXPECT_EQ(GEOFENCING_STATUS_OK,
+ RegisterRegionSyncWithServiceResult(
+ worker1_->id(), kTestRegionId, test_region_,
+ GEOFENCING_STATUS_OK, kTestGeofencingRegistrationId));
+
+ VerifyRegions(worker1_->id(), expected_regions_);
+ VerifyRegions(worker2_->id(), RegionMap());
+
+ EXPECT_EQ(GEOFENCING_STATUS_OK,
+ RegisterRegionSyncWithServiceResult(
+ worker2_->id(), kTestRegionId, test_region_,
+ GEOFENCING_STATUS_OK, kTestGeofencingRegistrationId2));
+
+ VerifyRegions(worker1_->id(), expected_regions_);
+ VerifyRegions(worker2_->id(), 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,
+ RegisterRegionSyncWithServiceResult(
+ worker1_->id(), kTestRegionId, test_region_,
+ GEOFENCING_STATUS_OK, kTestGeofencingRegistrationId));
+ EXPECT_EQ(GEOFENCING_STATUS_OK,
+ RegisterRegionSyncWithServiceResult(
+ worker2_->id(), kTestRegionId, test_region_,
+ GEOFENCING_STATUS_OK, kTestGeofencingRegistrationId2));
EXPECT_EQ(GEOFENCING_STATUS_OK,
- UnregisterRegionSync(kTestServiceWorkerRegistrationId,
- kTestRegionId,
- true,
+ UnregisterRegionSync(worker1_->id(), kTestRegionId, true,
kTestGeofencingRegistrationId));
- VerifyRegions(kTestServiceWorkerRegistrationId, RegionMap());
- VerifyRegions(kTestServiceWorkerRegistrationId2, expected_regions_);
+ VerifyRegions(worker1_->id(), RegionMap());
+ VerifyRegions(worker2_->id(), expected_regions_);
EXPECT_EQ(GEOFENCING_STATUS_OK,
- UnregisterRegionSync(kTestServiceWorkerRegistrationId2,
- kTestRegionId,
- true,
+ UnregisterRegionSync(worker2_->id(), kTestRegionId, true,
kTestGeofencingRegistrationId2));
- VerifyRegions(kTestServiceWorkerRegistrationId, RegionMap());
- VerifyRegions(kTestServiceWorkerRegistrationId2, RegionMap());
+ VerifyRegions(worker1_->id(), RegionMap());
+ VerifyRegions(worker2_->id(), 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_EQ(GEOFENCING_STATUS_OK,
+ RegisterRegionSyncWithServiceResult(
+ worker1_->id(), kTestRegionId, test_region_,
+ GEOFENCING_STATUS_OK, kTestGeofencingRegistrationId));
EXPECT_CALL(*service_, UnregisterRegion(kTestGeofencingRegistrationId))
.WillOnce(QuitRunner(runner));
@@ -411,4 +443,75 @@ TEST_F(GeofencingManagerTest, ShutdownCleansRegistrations) {
runner->Run();
}
+TEST_F(GeofencingManagerTest, OnRegistrationDeleted) {
+ SetHasProviderForTests();
+
+ EXPECT_EQ(GEOFENCING_STATUS_OK,
+ RegisterRegionSyncWithServiceResult(
+ worker1_->id(), kTestRegionId, test_region_,
+ GEOFENCING_STATUS_OK, kTestGeofencingRegistrationId));
+ EXPECT_EQ(GEOFENCING_STATUS_OK,
+ RegisterRegionSyncWithServiceResult(
+ worker2_->id(), kTestRegionId, test_region_,
+ GEOFENCING_STATUS_OK, kTestGeofencingRegistrationId2));
+
+ EXPECT_CALL(*service_, UnregisterRegion(kTestGeofencingRegistrationId));
+ UnregisterServiceWorker(worker1_);
+ VerifyRegions(worker1_->id(), RegionMap());
+ VerifyRegions(worker2_->id(), expected_regions_);
+
+ EXPECT_CALL(*service_, UnregisterRegion(kTestGeofencingRegistrationId2));
+ UnregisterServiceWorker(worker2_);
+ VerifyRegions(worker1_->id(), RegionMap());
+ VerifyRegions(worker2_->id(), RegionMap());
+}
+
+TEST_F(GeofencingManagerTest, RegisterRegion_MockedNoService) {
+ manager_->SetMockProvider(GeofencingMockState::SERVICE_UNAVAILABLE);
+
+ EXPECT_EQ(GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE,
+ RegisterRegionSync(worker1_->id(), kTestRegionId, test_region_));
+}
+
+TEST_F(GeofencingManagerTest, UnregisterRegion_MockedNoService) {
+ manager_->SetMockProvider(GeofencingMockState::SERVICE_UNAVAILABLE);
+
+ EXPECT_EQ(GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE,
+ UnregisterRegionSync(worker1_->id(), kTestRegionId, false));
+}
+
+TEST_F(GeofencingManagerTest, GetRegisteredRegions_MockedNoService) {
+ manager_->SetMockProvider(GeofencingMockState::SERVICE_UNAVAILABLE);
+
+ RegionMap regions;
+ EXPECT_EQ(GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE,
+ manager_->GetRegisteredRegions(worker1_->id(), &regions));
+ EXPECT_TRUE(regions.empty());
+}
+
+TEST_F(GeofencingManagerTest, RegisterRegion_MockedService) {
+ manager_->SetMockProvider(GeofencingMockState::SERVICE_AVAILABLE);
+
+ // Make sure real service doesn't get called.
+ EXPECT_CALL(*service_, RegisterRegion(testing::_, testing::_)).Times(0);
+
+ EXPECT_EQ(GEOFENCING_STATUS_OK,
+ RegisterRegionSync(worker1_->id(), kTestRegionId, test_region_));
+ VerifyRegions(worker1_->id(), expected_regions_);
+}
+
+TEST_F(GeofencingManagerTest, SetMockProviderClearsRegistrations) {
+ SetHasProviderForTests();
+ EXPECT_EQ(GEOFENCING_STATUS_OK,
+ RegisterRegionSyncWithServiceResult(
+ worker1_->id(), kTestRegionId, test_region_,
+ GEOFENCING_STATUS_OK, kTestGeofencingRegistrationId));
+ VerifyRegions(worker1_->id(), expected_regions_);
+
+ EXPECT_CALL(*service_, UnregisterRegion(kTestGeofencingRegistrationId));
+
+ manager_->SetMockProvider(GeofencingMockState::SERVICE_AVAILABLE);
+ VerifyRegions(worker1_->id(), RegionMap());
+}
+
} // namespace content
diff --git a/chromium/content/browser/geofencing/geofencing_provider.h b/chromium/content/browser/geofencing/geofencing_provider.h
index dec96b5270b..ea2c207ef0e 100644
--- a/chromium/content/browser/geofencing/geofencing_provider.h
+++ b/chromium/content/browser/geofencing/geofencing_provider.h
@@ -7,7 +7,7 @@
#include "base/basictypes.h"
#include "base/callback_forward.h"
-#include "content/common/geofencing_status.h"
+#include "content/common/geofencing_types.h"
namespace blink {
struct WebCircularGeofencingRegion;
diff --git a/chromium/content/browser/geofencing/geofencing_registration_delegate.h b/chromium/content/browser/geofencing/geofencing_registration_delegate.h
index ead0ec8eed0..10d6cea6077 100644
--- a/chromium/content/browser/geofencing/geofencing_registration_delegate.h
+++ b/chromium/content/browser/geofencing/geofencing_registration_delegate.h
@@ -6,7 +6,7 @@
#define CONTENT_BROWSER_GEOFENCING_GEOFENCING_REGISTRATION_DELEGATE_H_
#include "base/basictypes.h"
-#include "content/common/geofencing_status.h"
+#include "content/common/geofencing_types.h"
namespace content {
diff --git a/chromium/content/browser/geofencing/geofencing_service.h b/chromium/content/browser/geofencing/geofencing_service.h
index dc3d832ffdf..894b81696fd 100644
--- a/chromium/content/browser/geofencing/geofencing_service.h
+++ b/chromium/content/browser/geofencing/geofencing_service.h
@@ -10,7 +10,7 @@
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "content/common/content_export.h"
-#include "content/common/geofencing_status.h"
+#include "content/common/geofencing_types.h"
template <typename T>
struct DefaultSingletonTraits;
diff --git a/chromium/content/browser/geofencing/mock_geofencing_service.cc b/chromium/content/browser/geofencing/mock_geofencing_service.cc
new file mode 100644
index 00000000000..e53b8c72f55
--- /dev/null
+++ b/chromium/content/browser/geofencing/mock_geofencing_service.cc
@@ -0,0 +1,123 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// 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/geofencing/mock_geofencing_service.h"
+
+#include <cmath>
+
+#include "base/bind.h"
+#include "base/message_loop/message_loop.h"
+#include "content/browser/geofencing/geofencing_registration_delegate.h"
+#include "third_party/WebKit/public/platform/WebCircularGeofencingRegion.h"
+
+namespace content {
+
+namespace {
+
+void RegisterRegionResult(GeofencingRegistrationDelegate* delegate,
+ int64 geofencing_registration_id,
+ GeofencingStatus status) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&GeofencingRegistrationDelegate::RegistrationFinished,
+ base::Unretained(delegate), geofencing_registration_id,
+ status));
+}
+
+double DegreesToRadians(float degrees) {
+ return (M_PI * degrees) / 180.f;
+}
+
+double Haversin(double theta) {
+ double temp = sin(theta / 2);
+ return temp * temp;
+}
+
+// Calculates the distance in meters between two points with coordinates in
+// degrees.
+double Distance(double lat1, double long1, double lat2, double long2) {
+ double R = 6371000; // radius of earth in meters
+ double phi1 = DegreesToRadians(lat1);
+ double phi2 = DegreesToRadians(lat2);
+ double dphi = DegreesToRadians(lat2 - lat1);
+ double dlambda = DegreesToRadians(long2 - long1);
+ double haversine = Haversin(dphi) + cos(phi1) * cos(phi2) * Haversin(dlambda);
+ return 2 * R * asin(sqrt(haversine));
+}
+
+// Returns true iff the provided coordinate is inside the region.
+bool PositionInRegion(double latitude,
+ double longitude,
+ const blink::WebCircularGeofencingRegion& region) {
+ return Distance(latitude, longitude, region.latitude, region.longitude) <=
+ region.radius;
+}
+}
+
+struct MockGeofencingService::Registration {
+ blink::WebCircularGeofencingRegion region;
+ GeofencingRegistrationDelegate* delegate;
+ // True iff the last event emitted for this region was a RegionEntered event.
+ bool is_inside;
+};
+
+MockGeofencingService::MockGeofencingService(bool service_available)
+ : available_(service_available),
+ next_id_(0),
+ has_position_(false),
+ last_latitude_(0),
+ last_longitude_(0) {
+}
+
+MockGeofencingService::~MockGeofencingService() {
+}
+
+void MockGeofencingService::SetMockPosition(double latitude, double longitude) {
+ has_position_ = true;
+ last_latitude_ = latitude;
+ last_longitude_ = longitude;
+ for (auto& registration : registrations_) {
+ bool is_inside =
+ PositionInRegion(latitude, longitude, registration.second.region);
+ if (is_inside != registration.second.is_inside) {
+ if (is_inside)
+ registration.second.delegate->RegionEntered(registration.first);
+ else
+ registration.second.delegate->RegionExited(registration.first);
+ }
+ registration.second.is_inside = is_inside;
+ }
+}
+
+bool MockGeofencingService::IsServiceAvailable() {
+ return available_;
+}
+
+int64 MockGeofencingService::RegisterRegion(
+ const blink::WebCircularGeofencingRegion& region,
+ GeofencingRegistrationDelegate* delegate) {
+ int64 id = next_id_++;
+ Registration& registration = registrations_[id];
+ registration.region = region;
+ registration.delegate = delegate;
+ registration.is_inside =
+ has_position_ &&
+ PositionInRegion(last_latitude_, last_longitude_, region);
+ RegisterRegionResult(delegate, id, GEOFENCING_STATUS_OK);
+ if (registration.is_inside) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(&GeofencingRegistrationDelegate::RegionEntered,
+ base::Unretained(delegate), id));
+ }
+ return id;
+}
+
+void MockGeofencingService::UnregisterRegion(int64 geofencing_registration_id) {
+ registrations_.erase(geofencing_registration_id);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/geofencing/mock_geofencing_service.h b/chromium/content/browser/geofencing/mock_geofencing_service.h
new file mode 100644
index 00000000000..4634b26395d
--- /dev/null
+++ b/chromium/content/browser/geofencing/mock_geofencing_service.h
@@ -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.
+
+#ifndef CONTENT_BROWSER_GEOFENCING_MOCK_GEOFENCING_SERVICE_H_
+#define CONTENT_BROWSER_GEOFENCING_MOCK_GEOFENCING_SERVICE_H_
+
+#include <map>
+
+#include "content/browser/geofencing/geofencing_service.h"
+
+namespace content {
+
+// This class implements a geofencing service that doesn't rely on any
+// underlying platform implementation. Instead whenever SetMockPosition is
+// called this class will compare the provided position with all currently
+// registered regions, and emit corresponding geofencing events.
+//
+// If an instance is created with |service_available| set to false, the mock
+// will behave as if the platform does not support geofencing.
+class MockGeofencingService : public GeofencingService {
+ public:
+ MockGeofencingService(bool service_available);
+ ~MockGeofencingService() override;
+
+ void SetMockPosition(double latitude, double longitude);
+
+ // GeofencingService implementation.
+ bool IsServiceAvailable() override;
+ int64 RegisterRegion(const blink::WebCircularGeofencingRegion& region,
+ GeofencingRegistrationDelegate* delegate) override;
+ void UnregisterRegion(int64 geofencing_registration_id) override;
+
+ private:
+ struct Registration;
+
+ bool available_;
+ std::map<int64, Registration> registrations_;
+ int64 next_id_;
+ bool has_position_;
+ double last_latitude_;
+ double last_longitude_;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_GEOFENCING_MOCK_GEOFENCING_SERVICE_H_
diff --git a/chromium/content/browser/geolocation/empty_wifi_data_provider.h b/chromium/content/browser/geolocation/empty_wifi_data_provider.h
index 4397e19b547..4ab138454c2 100644
--- a/chromium/content/browser/geolocation/empty_wifi_data_provider.h
+++ b/chromium/content/browser/geolocation/empty_wifi_data_provider.h
@@ -16,12 +16,12 @@ class EmptyWifiDataProvider : public WifiDataProvider {
EmptyWifiDataProvider();
// WifiDataProvider implementation
- virtual void StartDataProvider() override { }
- virtual void StopDataProvider() override { }
- virtual bool GetData(WifiData* data) override;
+ void StartDataProvider() override { }
+ void StopDataProvider() override { }
+ bool GetData(WifiData* data) override;
private:
- virtual ~EmptyWifiDataProvider();
+ ~EmptyWifiDataProvider() override;
DISALLOW_COPY_AND_ASSIGN(EmptyWifiDataProvider);
};
diff --git a/chromium/content/browser/geolocation/geolocation_dispatcher_host.cc b/chromium/content/browser/geolocation/geolocation_dispatcher_host.cc
deleted file mode 100644
index 9dfec900ea2..00000000000
--- a/chromium/content/browser/geolocation/geolocation_dispatcher_host.cc
+++ /dev/null
@@ -1,144 +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/geolocation/geolocation_dispatcher_host.h"
-
-#include <utility>
-
-#include "base/bind.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/web_contents/web_contents_impl.h"
-#include "content/public/browser/content_browser_client.h"
-#include "content/common/geolocation_messages.h"
-
-namespace content {
-
-GeolocationDispatcherHost::PendingPermission::PendingPermission(
- int render_frame_id,
- int render_process_id,
- int bridge_id,
- const GURL& origin)
- : render_frame_id(render_frame_id),
- render_process_id(render_process_id),
- bridge_id(bridge_id),
- origin(origin) {
-}
-
-GeolocationDispatcherHost::PendingPermission::~PendingPermission() {
-}
-
-GeolocationDispatcherHost::GeolocationDispatcherHost(
- WebContents* web_contents)
- : WebContentsObserver(web_contents),
- weak_factory_(this) {
- // This is initialized by WebContentsImpl. Do not add any non-trivial
- // initialization here, defer to OnStartUpdating which is triggered whenever
- // a javascript geolocation object is actually initialized.
-}
-
-GeolocationDispatcherHost::~GeolocationDispatcherHost() {
-}
-
-void GeolocationDispatcherHost::RenderFrameDeleted(
- RenderFrameHost* render_frame_host) {
- CancelPermissionRequestsForFrame(render_frame_host);
-}
-
-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(
- const IPC::Message& msg, RenderFrameHost* render_frame_host) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(GeolocationDispatcherHost, msg,
- render_frame_host)
- IPC_MESSAGE_HANDLER(GeolocationHostMsg_RequestPermission,
- OnRequestPermission)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-void GeolocationDispatcherHost::OnRequestPermission(
- RenderFrameHost* render_frame_host,
- int bridge_id,
- 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, requesting_origin);
- pending_permissions_.push_back(pending_permission);
-
- GetContentClient()->browser()->RequestPermission(
- content::PERMISSION_GEOLOCATION,
- web_contents(),
- bridge_id,
- requesting_origin,
- user_gesture,
- base::Bind(&GeolocationDispatcherHost::SendGeolocationPermissionResponse,
- weak_factory_.GetWeakPtr(),
- render_process_id,
- render_frame_id,
- bridge_id));
-}
-
-void GeolocationDispatcherHost::SendGeolocationPermissionResponse(
- int render_process_id,
- int render_frame_id,
- int bridge_id,
- bool allowed) {
- 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) {
- RenderFrameHost* render_frame_host =
- RenderFrameHost::FromID(render_process_id, render_frame_id);
- if (render_frame_host) {
- render_frame_host->Send(new GeolocationMsg_PermissionSet(
- render_frame_id, bridge_id, allowed));
- }
-
- if (allowed) {
- GeolocationProviderImpl::GetInstance()->
- UserDidOptIntoLocationServices();
- }
-
- pending_permissions_.erase(pending_permissions_.begin() + i);
- return;
- }
- }
-
- 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
deleted file mode 100644
index 6359de10cce..00000000000
--- a/chromium/content/browser/geolocation/geolocation_dispatcher_host.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_GEOLOCATION_GEOLOCATION_DISPATCHER_HOST_H_
-#define CONTENT_BROWSER_GEOLOCATION_GEOLOCATION_DISPATCHER_HOST_H_
-
-#include <map>
-#include <vector>
-
-#include "base/callback_forward.h"
-#include "base/memory/weak_ptr.h"
-#include "content/public/browser/web_contents_observer.h"
-
-class GURL;
-
-namespace content {
-
-// 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);
- ~GeolocationDispatcherHost() override;
-
- private:
- // WebContentsObserver
- 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_origin,
- bool user_gesture);
-
- void SendGeolocationPermissionResponse(int render_process_id,
- int render_frame_id,
- int bridge_id,
- bool allowed);
-
- // 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,
- const GURL& origin);
- ~PendingPermission();
- int render_frame_id;
- int render_process_id;
- int bridge_id;
- GURL origin;
- };
- std::vector<PendingPermission> pending_permissions_;
-
- base::WeakPtrFactory<GeolocationDispatcherHost> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(GeolocationDispatcherHost);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_GEOLOCATION_GEOLOCATION_DISPATCHER_HOST_H_
diff --git a/chromium/content/browser/geolocation/geolocation_provider_impl.cc b/chromium/content/browser/geolocation/geolocation_provider_impl.cc
index 626a52afa4f..7375d578665 100644
--- a/chromium/content/browser/geolocation/geolocation_provider_impl.cc
+++ b/chromium/content/browser/geolocation/geolocation_provider_impl.cc
@@ -23,7 +23,7 @@ GeolocationProvider* GeolocationProvider::GetInstance() {
scoped_ptr<GeolocationProvider::Subscription>
GeolocationProviderImpl::AddLocationUpdateCallback(
const LocationUpdateCallback& callback, bool use_high_accuracy) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
scoped_ptr<GeolocationProvider::Subscription> subscription;
if (use_high_accuracy) {
subscription = high_accuracy_callbacks_.Add(callback);
@@ -41,7 +41,7 @@ GeolocationProviderImpl::AddLocationUpdateCallback(
}
void GeolocationProviderImpl::UserDidOptIntoLocationServices() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
bool was_permission_granted = user_did_opt_into_location_services_;
user_did_opt_into_location_services_ = true;
if (IsRunning() && !was_permission_granted)
@@ -50,7 +50,7 @@ void GeolocationProviderImpl::UserDidOptIntoLocationServices() {
void GeolocationProviderImpl::OverrideLocationForTesting(
const Geoposition& position) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
ignore_location_updates_ = true;
NotifyClients(position);
}
@@ -67,7 +67,7 @@ void GeolocationProviderImpl::OnLocationUpdate(const Geoposition& position) {
}
GeolocationProviderImpl* GeolocationProviderImpl::GetInstance() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
return Singleton<GeolocationProviderImpl>::get();
}
@@ -76,7 +76,7 @@ GeolocationProviderImpl::GeolocationProviderImpl()
user_did_opt_into_location_services_(false),
ignore_location_updates_(false),
arbitrator_(NULL) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
high_accuracy_callbacks_.set_removal_callback(
base::Bind(&GeolocationProviderImpl::OnClientsChanged,
base::Unretained(this)));
@@ -95,7 +95,7 @@ bool GeolocationProviderImpl::OnGeolocationThread() const {
}
void GeolocationProviderImpl::OnClientsChanged() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
base::Closure task;
if (high_accuracy_callbacks_.empty() && low_accuracy_callbacks_.empty()) {
DCHECK(IsRunning());
@@ -151,7 +151,7 @@ void GeolocationProviderImpl::InformProvidersPermissionGranted() {
}
void GeolocationProviderImpl::NotifyClients(const Geoposition& position) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(position.Validate() ||
position.error_code != Geoposition::ERROR_CODE_NONE);
position_ = position;
diff --git a/chromium/content/browser/geolocation/geolocation_provider_impl_unittest.cc b/chromium/content/browser/geolocation/geolocation_provider_impl_unittest.cc
index f201f48e842..685818b8279 100644
--- a/chromium/content/browser/geolocation/geolocation_provider_impl_unittest.cc
+++ b/chromium/content/browser/geolocation/geolocation_provider_impl_unittest.cc
@@ -78,8 +78,8 @@ class GeopositionEqMatcher
explicit GeopositionEqMatcher(const Geoposition& expected)
: expected_(expected) {}
- virtual bool MatchAndExplain(const Geoposition& actual,
- MatchResultListener* listener) const override {
+ bool MatchAndExplain(const Geoposition& actual,
+ 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 {
+ void DescribeTo(::std::ostream* os) const override {
*os << "which matches the expected position";
}
- virtual void DescribeNegationTo(::std::ostream* os) const override {
+ void DescribeNegationTo(::std::ostream* os) const override {
*os << "which does not match the expected position";
}
diff --git a/chromium/content/browser/geolocation/geolocation_service_impl.cc b/chromium/content/browser/geolocation/geolocation_service_impl.cc
index 4c855f27046..8b5bf229243 100644
--- a/chromium/content/browser/geolocation/geolocation_service_impl.cc
+++ b/chromium/content/browser/geolocation/geolocation_service_impl.cc
@@ -63,11 +63,21 @@ GeolocationServiceImpl::GeolocationServiceImpl(
const base::Closure& update_callback)
: context_(context),
update_callback_(update_callback),
- high_accuracy_(false) {
+ high_accuracy_(false),
+ has_position_to_report_(false) {
DCHECK(context_);
}
GeolocationServiceImpl::~GeolocationServiceImpl() {
+ // Make sure to respond to any pending callback even without a valid position.
+ if (!position_callback_.is_null()) {
+ if (!current_position_.valid) {
+ current_position_.error_code = MojoGeoposition::ErrorCode(
+ GEOPOSITION_ERROR_CODE_POSITION_UNAVAILABLE);
+ current_position_.error_message = mojo::String("");
+ }
+ ReportCurrentPosition();
+ }
}
void GeolocationServiceImpl::PauseUpdates() {
@@ -105,6 +115,20 @@ void GeolocationServiceImpl::SetHighAccuracy(bool high_accuracy) {
StartListeningForUpdates();
}
+void GeolocationServiceImpl::QueryNextPosition(
+ const PositionCallback& callback) {
+ if (!position_callback_.is_null()) {
+ DVLOG(1) << "Overlapped call to QueryNextPosition!";
+ OnConnectionError(); // Simulate a connection error.
+ return;
+ }
+
+ position_callback_ = callback;
+
+ if (has_position_to_report_)
+ ReportCurrentPosition();
+}
+
void GeolocationServiceImpl::SetOverride(const Geoposition& position) {
position_override_ = position;
if (!position_override_.Validate()) {
@@ -135,21 +159,31 @@ void GeolocationServiceImpl::OnLocationUpdate(const Geoposition& position) {
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());
+
+ current_position_.valid = position.Validate();
+ current_position_.latitude = position.latitude;
+ current_position_.longitude = position.longitude;
+ current_position_.altitude = position.altitude;
+ current_position_.accuracy = position.accuracy;
+ current_position_.altitude_accuracy = position.altitude_accuracy;
+ current_position_.heading = position.heading;
+ current_position_.speed = position.speed;
+ current_position_.timestamp = position.timestamp.ToDoubleT();
+ current_position_.error_code =
+ MojoGeoposition::ErrorCode(position.error_code);
+ current_position_.error_message = position.error_message;
+
+ has_position_to_report_ = true;
+
+ if (!position_callback_.is_null())
+ ReportCurrentPosition();
+}
+
+void GeolocationServiceImpl::ReportCurrentPosition() {
+ position_callback_.Run(current_position_.Clone());
+ position_callback_.reset();
+ has_position_to_report_ = false;
}
} // namespace content
diff --git a/chromium/content/browser/geolocation/geolocation_service_impl.h b/chromium/content/browser/geolocation/geolocation_service_impl.h
index 172e4e196c8..9887b2f2b4a 100644
--- a/chromium/content/browser/geolocation/geolocation_service_impl.h
+++ b/chromium/content/browser/geolocation/geolocation_service_impl.h
@@ -5,6 +5,7 @@
#include "base/memory/scoped_ptr.h"
#include "content/browser/geolocation/geolocation_provider_impl.h"
#include "content/common/geolocation_service.mojom.h"
+#include "content/public/common/mojo_geoposition.mojom.h"
#ifndef CONTENT_BROWSER_GEOLOCATION_GEOLOCATION_SERVICE_IMPL_H_
#define CONTENT_BROWSER_GEOLOCATION_GEOLOCATION_SERVICE_IMPL_H_
@@ -17,8 +18,9 @@ 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.
+ // |context| must outlive this object. |update_callback| will be called when
+ // location updates are sent, allowing the client to know when the service
+ // is being used.
GeolocationServiceImpl(GeolocationServiceContext* context,
const base::Closure& update_callback);
~GeolocationServiceImpl() override;
@@ -35,27 +37,41 @@ class GeolocationServiceImpl : public mojo::InterfaceImpl<GeolocationService> {
void ClearOverride();
private:
+ typedef mojo::Callback<void(MojoGeopositionPtr)> PositionCallback;
+
// GeolocationService:
void SetHighAccuracy(bool high_accuracy) override;
+ void QueryNextPosition(const PositionCallback& callback) override;
// mojo::InterfaceImpl:
void OnConnectionError() override;
void OnLocationUpdate(const Geoposition& position);
+ void ReportCurrentPosition();
// Owns this object.
GeolocationServiceContext* context_;
scoped_ptr<GeolocationProvider::Subscription> geolocation_subscription_;
+
+ // Callback that allows the instantiator of this class to be notified on
+ // position updates.
base::Closure update_callback_;
+ // The callback passed to QueryNextPosition.
+ PositionCallback position_callback_;
+
// Valid iff SetOverride() has been called and ClearOverride() has not
// subsequently been called.
Geoposition position_override_;
+ MojoGeoposition current_position_;
+
// Whether this instance is currently observing location updates with high
// accuracy.
bool high_accuracy_;
+ bool has_position_to_report_;
+
DISALLOW_COPY_AND_ASSIGN(GeolocationServiceImpl);
};
diff --git a/chromium/content/browser/geolocation/location_arbitrator.h b/chromium/content/browser/geolocation/location_arbitrator.h
index d2cd191c798..feb42e519dc 100644
--- a/chromium/content/browser/geolocation/location_arbitrator.h
+++ b/chromium/content/browser/geolocation/location_arbitrator.h
@@ -34,4 +34,4 @@ public:
} // namespace content
-#endif // CONTENT_BROWSER_GEOLOCATION_LOCATION_ARBITRATOR_IMPL_H_
+#endif // CONTENT_BROWSER_GEOLOCATION_LOCATION_ARBITRATOR_H_
diff --git a/chromium/content/browser/geolocation/location_arbitrator_impl.cc b/chromium/content/browser/geolocation/location_arbitrator_impl.cc
index ef20a0ce468..20d9a5127db 100644
--- a/chromium/content/browser/geolocation/location_arbitrator_impl.cc
+++ b/chromium/content/browser/geolocation/location_arbitrator_impl.cc
@@ -53,12 +53,23 @@ void LocationArbitratorImpl::OnPermissionGranted() {
}
void LocationArbitratorImpl::StartProviders(bool use_high_accuracy) {
+ // GetAccessTokenStore() will return NULL for embedders not implementing
+ // the AccessTokenStore class, so we report an error to avoid JavaScript
+ // requests of location to wait eternally for a reply.
+ AccessTokenStore* access_token_store = GetAccessTokenStore();
+ if (!access_token_store) {
+ Geoposition position;
+ position.error_code = Geoposition::ERROR_CODE_PERMISSION_DENIED;
+ arbitrator_update_callback_.Run(position);
+ return;
+ }
+
// Stash options as OnAccessTokenStoresLoaded has not yet been called.
is_running_ = true;
use_high_accuracy_ = use_high_accuracy;
if (providers_.empty()) {
DCHECK(DefaultNetworkProviderURL().is_valid());
- GetAccessTokenStore()->LoadAccessTokens(
+ access_token_store->LoadAccessTokens(
base::Bind(&LocationArbitratorImpl::OnAccessTokenStoresLoaded,
base::Unretained(this)));
} else {
diff --git a/chromium/content/browser/geolocation/location_provider_android.h b/chromium/content/browser/geolocation/location_provider_android.h
index e24f67cb980..9e0ad5f8395 100644
--- a/chromium/content/browser/geolocation/location_provider_android.h
+++ b/chromium/content/browser/geolocation/location_provider_android.h
@@ -17,17 +17,17 @@ struct Geoposition;
class LocationProviderAndroid : public LocationProviderBase {
public:
LocationProviderAndroid();
- virtual ~LocationProviderAndroid();
+ ~LocationProviderAndroid() override;
// Called by the AndroidLocationApiAdapter.
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;
+ bool StartProvider(bool high_accuracy) override;
+ void StopProvider() override;
+ void GetPosition(Geoposition* position) override;
+ void RequestRefresh() override;
+ 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 1e3f4430da0..b0ca80e119f 100644
--- a/chromium/content/browser/geolocation/location_provider_base.h
+++ b/chromium/content/browser/geolocation/location_provider_base.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_GEOLOCATION_LOCATION_PROVIDER_H_
-#define CONTENT_BROWSER_GEOLOCATION_LOCATION_PROVIDER_H_
+#ifndef CONTENT_BROWSER_GEOLOCATION_LOCATION_PROVIDER_BASE_H_
+#define CONTENT_BROWSER_GEOLOCATION_LOCATION_PROVIDER_BASE_H_
#include "content/common/content_export.h"
#include "content/public/browser/location_provider.h"
@@ -32,4 +32,4 @@ class CONTENT_EXPORT LocationProviderBase
} // namespace content
-#endif // CONTENT_BROWSER_GEOLOCATION_LOCATION_PROVIDER_H_
+#endif // CONTENT_BROWSER_GEOLOCATION_LOCATION_PROVIDER_BASE_H_
diff --git a/chromium/content/browser/geolocation/mock_location_arbitrator.h b/chromium/content/browser/geolocation/mock_location_arbitrator.h
index 620bcc88662..efdb8b1cf9d 100644
--- a/chromium/content/browser/geolocation/mock_location_arbitrator.h
+++ b/chromium/content/browser/geolocation/mock_location_arbitrator.h
@@ -34,4 +34,4 @@ class MockLocationArbitrator : public LocationArbitrator {
} // namespace content
-#endif // CONTENT_BROWSER_GEOLOCATION_MOCK_LOCATION_ARBITRATOR_H_
+#endif // CONTENT_BROWSER_GEOLOCATION_MOCK_LOCATION_ARBITRATOR_H_
diff --git a/chromium/content/browser/geolocation/network_location_request.cc b/chromium/content/browser/geolocation/network_location_request.cc
index 84ba5b05edc..253e321bb54 100644
--- a/chromium/content/browser/geolocation/network_location_request.cc
+++ b/chromium/content/browser/geolocation/network_location_request.cc
@@ -123,8 +123,8 @@ bool NetworkLocationRequest::MakeRequest(const base::string16& access_token,
wifi_data_timestamp_ = timestamp;
GURL request_url = FormRequestURL(url_);
- url_fetcher_.reset(net::URLFetcher::Create(
- url_fetcher_id_for_tests, request_url, net::URLFetcher::POST, this));
+ url_fetcher_ = net::URLFetcher::Create(url_fetcher_id_for_tests, request_url,
+ net::URLFetcher::POST, this);
url_fetcher_->SetRequestContext(url_context_.get());
std::string upload_data;
FormUploadData(wifi_data, timestamp, access_token, &upload_data);
diff --git a/chromium/content/browser/geolocation/wifi_data_provider_chromeos.cc b/chromium/content/browser/geolocation/wifi_data_provider_chromeos.cc
index 2b5c218c24b..18d84bad109 100644
--- a/chromium/content/browser/geolocation/wifi_data_provider_chromeos.cc
+++ b/chromium/content/browser/geolocation/wifi_data_provider_chromeos.cc
@@ -24,7 +24,8 @@ const int kNoWifiPollingIntervalMilliseconds = 20 * 1000; // 20s
} // namespace
-WifiDataProviderChromeOs::WifiDataProviderChromeOs() : started_(false) {
+WifiDataProviderChromeOs::WifiDataProviderChromeOs()
+ : started_(false), is_first_scan_complete_(false) {
}
WifiDataProviderChromeOs::~WifiDataProviderChromeOs() {
diff --git a/chromium/content/browser/geolocation/wifi_data_provider_chromeos.h b/chromium/content/browser/geolocation/wifi_data_provider_chromeos.h
index db56ea7da09..0e8bc93fd21 100644
--- a/chromium/content/browser/geolocation/wifi_data_provider_chromeos.h
+++ b/chromium/content/browser/geolocation/wifi_data_provider_chromeos.h
@@ -16,13 +16,13 @@ class CONTENT_EXPORT WifiDataProviderChromeOs : public WifiDataProvider {
WifiDataProviderChromeOs();
// WifiDataProvider
- virtual void StartDataProvider() override;
- virtual void StopDataProvider() override;
- virtual bool GetData(WifiData* data) override;
+ void StartDataProvider() override;
+ void StopDataProvider() override;
+ bool GetData(WifiData* data) override;
private:
friend class GeolocationChromeOsWifiDataProviderTest;
- virtual ~WifiDataProviderChromeOs();
+ ~WifiDataProviderChromeOs() override;
// UI thread
void DoWifiScanTaskOnUIThread(); // The polling task
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 eb0442194cb..38c1ea3b555 100644
--- a/chromium/content/browser/geolocation/wifi_data_provider_chromeos_unittest.cc
+++ b/chromium/content/browser/geolocation/wifi_data_provider_chromeos_unittest.cc
@@ -19,7 +19,7 @@ class GeolocationChromeOsWifiDataProviderTest : public testing::Test {
GeolocationChromeOsWifiDataProviderTest() {
}
- virtual void SetUp() override {
+ void SetUp() override {
chromeos::DBusThreadManager::Initialize();
chromeos::NetworkHandler::Initialize();
manager_client_ =
@@ -29,7 +29,7 @@ class GeolocationChromeOsWifiDataProviderTest : public testing::Test {
message_loop_.RunUntilIdle();
}
- virtual void TearDown() override {
+ void TearDown() override {
provider_ = NULL;
chromeos::NetworkHandler::Shutdown();
chromeos::DBusThreadManager::Shutdown();
diff --git a/chromium/content/browser/geolocation/wifi_data_provider_win.cc b/chromium/content/browser/geolocation/wifi_data_provider_win.cc
index 66c07c01848..4d950ec12fc 100644
--- a/chromium/content/browser/geolocation/wifi_data_provider_win.cc
+++ b/chromium/content/browser/geolocation/wifi_data_provider_win.cc
@@ -87,12 +87,12 @@ typedef DWORD (WINAPI* WlanCloseHandleFunction)(HANDLE hClientHandle,
// Local classes and functions
class WindowsWlanApi : public WifiDataProviderCommon::WlanApiInterface {
public:
- virtual ~WindowsWlanApi();
+ ~WindowsWlanApi() override;
// Factory function. Will return NULL if this API is unavailable.
static WindowsWlanApi* Create();
// WlanApiInterface
- virtual bool GetAccessPointData(WifiData::AccessPointDataSet* data);
+ bool GetAccessPointData(WifiData::AccessPointDataSet* data) override;
private:
// Takes ownership of the library handle.
@@ -120,11 +120,11 @@ class WindowsWlanApi : public WifiDataProviderCommon::WlanApiInterface {
class WindowsNdisApi : public WifiDataProviderCommon::WlanApiInterface {
public:
- virtual ~WindowsNdisApi();
+ ~WindowsNdisApi() override;
static WindowsNdisApi* Create();
// WlanApiInterface
- virtual bool GetAccessPointData(WifiData::AccessPointDataSet* data);
+ bool GetAccessPointData(WifiData::AccessPointDataSet* data) override;
private:
static bool GetInterfacesNDIS(
diff --git a/chromium/content/browser/geolocation/wifi_data_provider_win.h b/chromium/content/browser/geolocation/wifi_data_provider_win.h
index d67798d5711..49ed704a38c 100644
--- a/chromium/content/browser/geolocation/wifi_data_provider_win.h
+++ b/chromium/content/browser/geolocation/wifi_data_provider_win.h
@@ -15,11 +15,11 @@ class CONTENT_EXPORT WifiDataProviderWin : public WifiDataProviderCommon {
WifiDataProviderWin();
private:
- virtual ~WifiDataProviderWin();
+ ~WifiDataProviderWin() override;
// WifiDataProviderCommon
- virtual WlanApiInterface* NewWlanApi();
- virtual WifiPollingPolicy* NewPollingPolicy();
+ WlanApiInterface* NewWlanApi() override;
+ WifiPollingPolicy* NewPollingPolicy() override;
DISALLOW_COPY_AND_ASSIGN(WifiDataProviderWin);
};
diff --git a/chromium/content/browser/geolocation/wifi_polling_policy.h b/chromium/content/browser/geolocation/wifi_polling_policy.h
index c1df4d267ac..f597e837e7e 100644
--- a/chromium/content/browser/geolocation/wifi_polling_policy.h
+++ b/chromium/content/browser/geolocation/wifi_polling_policy.h
@@ -32,7 +32,7 @@ class GenericWifiPollingPolicy : public WifiPollingPolicy {
public:
GenericWifiPollingPolicy() : polling_interval_(DEFAULT_INTERVAL) {}
// WifiPollingPolicy
- virtual void UpdatePollingInterval(bool scan_results_differ) {
+ void UpdatePollingInterval(bool scan_results_differ) override {
if (scan_results_differ) {
polling_interval_ = DEFAULT_INTERVAL;
} else if (polling_interval_ == DEFAULT_INTERVAL) {
@@ -43,8 +43,8 @@ class GenericWifiPollingPolicy : public WifiPollingPolicy {
polling_interval_ = TWO_NO_CHANGE_INTERVAL;
}
}
- virtual int PollingInterval() { return polling_interval_; }
- virtual int NoWifiInterval() { return NO_WIFI_INTERVAL; }
+ int PollingInterval() override { return polling_interval_; }
+ int NoWifiInterval() override { return NO_WIFI_INTERVAL; }
private:
int polling_interval_;
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 032c597c664..205542cdc81 100644
--- a/chromium/content/browser/gpu/browser_gpu_channel_host_factory.cc
+++ b/chromium/content/browser/gpu/browser_gpu_channel_host_factory.cc
@@ -4,26 +4,46 @@
#include "content/browser/gpu/browser_gpu_channel_host_factory.h"
+#include <set>
+
#include "base/bind.h"
-#include "base/debug/trace_event.h"
+#include "base/profiler/scoped_tracker.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread_restrictions.h"
-#include "base/tracked_objects.h"
+#include "base/trace_event/trace_event.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/gpu_memory_buffer_factory.h"
#include "content/common/gpu/gpu_messages.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/gpu_data_manager.h"
#include "content/public/common/content_client.h"
+#include "gpu/GLES2/gl2extchromium.h"
#include "ipc/ipc_channel_handle.h"
#include "ipc/ipc_forwarding_message_filter.h"
#include "ipc/message_filter.h"
+#if defined(OS_MACOSX)
+#include "content/common/gpu/gpu_memory_buffer_factory_io_surface.h"
+#endif
+
+#if defined(OS_ANDROID)
+#include "content/common/gpu/gpu_memory_buffer_factory_surface_texture.h"
+#endif
+
+#if defined(USE_OZONE)
+#include "content/common/gpu/gpu_memory_buffer_factory_ozone_native_buffer.h"
+#endif
+
namespace content {
+namespace {
+
+base::LazyInstance<std::set<gfx::GpuMemoryBuffer::Usage>>
+ g_enabled_gpu_memory_buffer_usages;
+}
BrowserGpuChannelHostFactory* BrowserGpuChannelHostFactory::instance_ = NULL;
@@ -106,6 +126,11 @@ BrowserGpuChannelHostFactory::EstablishRequest::EstablishRequest(
}
void BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO() {
+ // TODO(pkasting): Remove ScopedTracker below once crbug.com/477117 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "477117 "
+ "BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO"));
GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
if (!host) {
host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
@@ -175,12 +200,10 @@ 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();
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/125248 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "125248 BrowserGpuChannelHostFactory::EstablishRequest::Wait"));
// 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
@@ -190,8 +213,6 @@ void BrowserGpuChannelHostFactory::EstablishRequest::Wait() {
"BrowserGpuChannelHostFactory::EstablishGpuChannelSync");
base::ThreadRestrictions::ScopedAllowWait allow_wait;
event_.Wait();
-
- stopwatch.Stop();
}
FinishOnMain();
}
@@ -220,13 +241,51 @@ void BrowserGpuChannelHostFactory::Terminate() {
instance_ = NULL;
}
+// static
+void BrowserGpuChannelHostFactory::EnableGpuMemoryBufferFactoryUsage(
+ gfx::GpuMemoryBuffer::Usage usage) {
+ g_enabled_gpu_memory_buffer_usages.Get().insert(usage);
+}
+
+// static
+bool BrowserGpuChannelHostFactory::IsGpuMemoryBufferFactoryUsageEnabled(
+ gfx::GpuMemoryBuffer::Usage usage) {
+ return g_enabled_gpu_memory_buffer_usages.Get().count(usage) != 0;
+}
+
+// static
+uint32 BrowserGpuChannelHostFactory::GetImageTextureTarget() {
+ if (!IsGpuMemoryBufferFactoryUsageEnabled(gfx::GpuMemoryBuffer::MAP))
+ return GL_TEXTURE_2D;
+
+ std::vector<gfx::GpuMemoryBufferType> supported_types;
+ GpuMemoryBufferFactory::GetSupportedTypes(&supported_types);
+ DCHECK(!supported_types.empty());
+
+ // The GPU service will always use the preferred type.
+ gfx::GpuMemoryBufferType type = supported_types[0];
+
+ switch (type) {
+ case gfx::SURFACE_TEXTURE_BUFFER:
+ case gfx::OZONE_NATIVE_BUFFER:
+ // GPU memory buffers that are shared with the GL using EGLImages require
+ // TEXTURE_EXTERNAL_OES.
+ return GL_TEXTURE_EXTERNAL_OES;
+ case gfx::IO_SURFACE_BUFFER:
+ // IOSurface backed images require GL_TEXTURE_RECTANGLE_ARB.
+ return GL_TEXTURE_RECTANGLE_ARB;
+ default:
+ return GL_TEXTURE_2D;
+ }
+}
+
BrowserGpuChannelHostFactory::BrowserGpuChannelHostFactory()
: gpu_client_id_(ChildProcessHostImpl::GenerateChildProcessUniqueId()),
shutdown_event_(new base::WaitableEvent(true, false)),
- gpu_memory_buffer_factory_host_(new GpuMemoryBufferFactoryHostImpl),
gpu_memory_buffer_manager_(
- new BrowserGpuMemoryBufferManager(gpu_client_id_)),
- gpu_host_id_(0) {
+ new BrowserGpuMemoryBufferManager(this, gpu_client_id_)),
+ gpu_host_id_(0),
+ next_create_gpu_memory_buffer_request_id_(0) {
}
BrowserGpuChannelHostFactory::~BrowserGpuChannelHostFactory() {
@@ -236,18 +295,18 @@ BrowserGpuChannelHostFactory::~BrowserGpuChannelHostFactory() {
for (size_t n = 0; n < established_callbacks_.size(); n++)
established_callbacks_[n].Run();
shutdown_event_->Signal();
+ if (gpu_channel_) {
+ gpu_channel_->DestroyChannel();
+ gpu_channel_ = NULL;
+ }
}
bool BrowserGpuChannelHostFactory::IsMainThread() {
return BrowserThread::CurrentlyOn(BrowserThread::UI);
}
-base::MessageLoop* BrowserGpuChannelHostFactory::GetMainLoop() {
- return BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::UI);
-}
-
-scoped_refptr<base::MessageLoopProxy>
-BrowserGpuChannelHostFactory::GetIOLoopProxy() {
+scoped_refptr<base::SingleThreadTaskRunner>
+BrowserGpuChannelHostFactory::GetIOThreadTaskRunner() {
return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
}
@@ -294,12 +353,15 @@ CreateCommandBufferResult BrowserGpuChannelHostFactory::CreateViewCommandBuffer(
const GPUCreateCommandBufferConfig& init_params,
int32 route_id) {
CreateRequest request(route_id);
- GetIOLoopProxy()->PostTask(FROM_HERE, base::Bind(
- &BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO,
- base::Unretained(this),
- &request,
- surface_id,
- init_params));
+ GetIOThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO,
+ base::Unretained(this), &request, surface_id, init_params));
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/125248 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "125248 BrowserGpuChannelHostFactory::CreateViewCommandBuffer"));
+
// We're blocking the UI thread, which is generally undesirable.
// In this case we need to wait for this before we can show any UI /anyway/,
// so it won't cause additional jank.
@@ -311,6 +373,10 @@ CreateCommandBufferResult BrowserGpuChannelHostFactory::CreateViewCommandBuffer(
return request.result;
}
+// Blocking the UI thread to open a GPU channel is not supported on Android.
+// (Opening the initial channel to a child process involves handling a reply
+// task on the UI thread first, so we cannot block here.)
+#if !defined(OS_ANDROID)
GpuChannelHost* BrowserGpuChannelHostFactory::EstablishGpuChannelSync(
CauseForGpuLaunch cause_for_gpu_launch) {
EstablishGpuChannel(cause_for_gpu_launch, base::Closure());
@@ -320,6 +386,7 @@ GpuChannelHost* BrowserGpuChannelHostFactory::EstablishGpuChannelSync(
return gpu_channel_.get();
}
+#endif
void BrowserGpuChannelHostFactory::EstablishGpuChannel(
CauseForGpuLaunch cause_for_gpu_launch,
@@ -327,6 +394,7 @@ void BrowserGpuChannelHostFactory::EstablishGpuChannel(
if (gpu_channel_.get() && gpu_channel_->IsLost()) {
DCHECK(!pending_request_.get());
// Recreate the channel if it has been lost.
+ gpu_channel_->DestroyChannel();
gpu_channel_ = NULL;
}
@@ -357,6 +425,11 @@ void BrowserGpuChannelHostFactory::GpuChannelEstablished() {
if (pending_request_->channel_handle().name.empty()) {
DCHECK(!gpu_channel_.get());
} else {
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/466866
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile1(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "466866 BrowserGpuChannelHostFactory::GpuChannelEstablished1"));
GetContentClient()->SetGpuInfo(pending_request_->gpu_info());
gpu_channel_ =
GpuChannelHost::Create(this,
@@ -366,9 +439,14 @@ void BrowserGpuChannelHostFactory::GpuChannelEstablished() {
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;
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/466866 is
+ // fixed.
+ tracked_objects::ScopedTracker tracking_profile2(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "466866 BrowserGpuChannelHostFactory::GpuChannelEstablished2"));
+
for (size_t n = 0; n < established_callbacks_.size(); n++)
established_callbacks_[n].Run();
@@ -379,34 +457,111 @@ void BrowserGpuChannelHostFactory::GpuChannelEstablished() {
void BrowserGpuChannelHostFactory::AddFilterOnIO(
int host_id,
scoped_refptr<IPC::MessageFilter> filter) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
GpuProcessHost* host = GpuProcessHost::FromID(host_id);
if (host)
host->AddFilter(filter.get());
}
-void BrowserGpuChannelHostFactory::SetHandlerForControlMessages(
- const uint32* message_ids,
- size_t num_messages,
- const base::Callback<void(const IPC::Message&)>& handler,
- base::TaskRunner* target_task_runner) {
- DCHECK(gpu_host_id_)
- << "Do not call"
- << " BrowserGpuChannelHostFactory::SetHandlerForControlMessages()"
- << " until the GpuProcessHost has been set up.";
+bool BrowserGpuChannelHostFactory::IsGpuMemoryBufferConfigurationSupported(
+ gfx::GpuMemoryBuffer::Format format,
+ gfx::GpuMemoryBuffer::Usage usage) {
+ // Return early if usage is not enabled.
+ if (!IsGpuMemoryBufferFactoryUsageEnabled(usage))
+ return false;
+
+ // Preferred type is always used by factory.
+ std::vector<gfx::GpuMemoryBufferType> supported_types;
+ GpuMemoryBufferFactory::GetSupportedTypes(&supported_types);
+ DCHECK(!supported_types.empty());
+ switch (supported_types[0]) {
+ case gfx::SHARED_MEMORY_BUFFER:
+ // Shared memory buffers must be created in-process.
+ return false;
+#if defined(OS_MACOSX)
+ case gfx::IO_SURFACE_BUFFER:
+ return GpuMemoryBufferFactoryIOSurface::
+ IsGpuMemoryBufferConfigurationSupported(format, usage);
+#endif
+#if defined(OS_ANDROID)
+ case gfx::SURFACE_TEXTURE_BUFFER:
+ return GpuMemoryBufferFactorySurfaceTexture::
+ IsGpuMemoryBufferConfigurationSupported(format, usage);
+#endif
+#if defined(USE_OZONE)
+ case gfx::OZONE_NATIVE_BUFFER:
+ return GpuMemoryBufferFactoryOzoneNativeBuffer::
+ IsGpuMemoryBufferConfigurationSupported(format, usage);
+#endif
+ default:
+ NOTREACHED();
+ return false;
+ }
+}
+
+void BrowserGpuChannelHostFactory::CreateGpuMemoryBuffer(
+ gfx::GpuMemoryBufferId id,
+ const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
+ gfx::GpuMemoryBuffer::Usage usage,
+ int client_id,
+ int32 surface_id,
+ const CreateGpuMemoryBufferCallback& callback) {
+ DCHECK_CURRENTLY_ON(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;
- scoped_refptr<IPC::ForwardingMessageFilter> filter =
- new IPC::ForwardingMessageFilter(message_ids,
- num_messages,
- target_task_runner);
- filter->AddRoute(MSG_ROUTING_CONTROL, handler);
+ host->CreateGpuMemoryBuffer(
+ id, size, format, usage, client_id, surface_id,
+ base::Bind(&BrowserGpuChannelHostFactory::OnGpuMemoryBufferCreated,
+ base::Unretained(this), request_id));
+}
- GetIOLoopProxy()->PostTask(
+void BrowserGpuChannelHostFactory::DestroyGpuMemoryBuffer(
+ gfx::GpuMemoryBufferId id,
+ int client_id,
+ int32 sync_point) {
+ BrowserThread::PostTask(
+ BrowserThread::IO,
FROM_HERE,
- base::Bind(&BrowserGpuChannelHostFactory::AddFilterOnIO,
- gpu_host_id_,
- filter));
+ base::Bind(&BrowserGpuChannelHostFactory::DestroyGpuMemoryBufferOnIO,
+ base::Unretained(this),
+ id,
+ client_id,
+ sync_point));
+}
+
+void BrowserGpuChannelHostFactory::DestroyGpuMemoryBufferOnIO(
+ gfx::GpuMemoryBufferId id,
+ int client_id,
+ int32 sync_point) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
+ if (!host)
+ return;
+
+ host->DestroyGpuMemoryBuffer(id, client_id, sync_point);
+}
+
+void BrowserGpuChannelHostFactory::OnGpuMemoryBufferCreated(
+ uint32 request_id,
+ const gfx::GpuMemoryBufferHandle& handle) {
+ DCHECK_CURRENTLY_ON(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/browser_gpu_channel_host_factory.h b/chromium/content/browser/gpu/browser_gpu_channel_host_factory.h
index 4bc0b413153..b4df563fc02 100644
--- a/chromium/content/browser/gpu/browser_gpu_channel_host_factory.h
+++ b/chromium/content/browser/gpu/browser_gpu_channel_host_factory.h
@@ -5,45 +5,62 @@
#ifndef CONTENT_BROWSER_GPU_BROWSER_GPU_CHANNEL_HOST_FACTORY_H_
#define CONTENT_BROWSER_GPU_BROWSER_GPU_CHANNEL_HOST_FACTORY_H_
+#include <map>
#include <vector>
#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 GpuChannelHostFactory,
+ public GpuMemoryBufferFactoryHost {
public:
static void Initialize(bool establish_gpu_channel);
static void Terminate();
static BrowserGpuChannelHostFactory* instance() { return instance_; }
- // GpuChannelHostFactory implementation.
+ static void EnableGpuMemoryBufferFactoryUsage(
+ gfx::GpuMemoryBuffer::Usage usage);
+ static bool IsGpuMemoryBufferFactoryUsageEnabled(
+ gfx::GpuMemoryBuffer::Usage usage);
+ static uint32 GetImageTextureTarget();
+
+ // Overridden from GpuChannelHostFactory:
bool IsMainThread() override;
- base::MessageLoop* GetMainLoop() override;
- scoped_refptr<base::MessageLoopProxy> GetIOLoopProxy() override;
+ scoped_refptr<base::SingleThreadTaskRunner> GetIOThreadTaskRunner() override;
scoped_ptr<base::SharedMemory> AllocateSharedMemory(size_t size) override;
CreateCommandBufferResult CreateViewCommandBuffer(
int32 surface_id,
const GPUCreateCommandBufferConfig& init_params,
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
- // GpuProcessHostId().
- virtual void SetHandlerForControlMessages(
- const uint32* message_ids,
- size_t num_messages,
- const base::Callback<void(const IPC::Message&)>& handler,
- base::TaskRunner* target_task_runner);
+ // Overridden from GpuMemoryBufferFactoryHost:
+ bool IsGpuMemoryBufferConfigurationSupported(
+ gfx::GpuMemoryBuffer::Format format,
+ gfx::GpuMemoryBuffer::Usage usage) override;
+ void CreateGpuMemoryBuffer(
+ gfx::GpuMemoryBufferId id,
+ const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
+ gfx::GpuMemoryBuffer::Usage usage,
+ int client_id,
+ int32 surface_id,
+ const CreateGpuMemoryBufferCallback& callback) override;
+ void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
+ int client_id,
+ int32 sync_point) override;
+
int GpuProcessHostId() { return gpu_host_id_; }
+#if !defined(OS_ANDROID)
GpuChannelHost* EstablishGpuChannelSync(
CauseForGpuLaunch cause_for_gpu_launch);
+#endif
void EstablishGpuChannel(CauseForGpuLaunch cause_for_gpu_launch,
const base::Closure& callback);
GpuChannelHost* GetGpuChannel();
@@ -68,15 +85,23 @@ class CONTENT_EXPORT BrowserGpuChannelHostFactory
CreateCommandBufferResult result);
static void AddFilterOnIO(int gpu_host_id,
scoped_refptr<IPC::MessageFilter> filter);
+ void DestroyGpuMemoryBufferOnIO(gfx::GpuMemoryBufferId id,
+ int client_id,
+ int32 sync_point);
+ void OnGpuMemoryBufferCreated(uint32 request_id,
+ const gfx::GpuMemoryBufferHandle& handle);
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_;
diff --git a/chromium/content/browser/gpu/browser_gpu_memory_buffer_manager.cc b/chromium/content/browser/gpu/browser_gpu_memory_buffer_manager.cc
index b5bcebc05ea..70184a0f48a 100644
--- a/chromium/content/browser/gpu/browser_gpu_memory_buffer_manager.cc
+++ b/chromium/content/browser/gpu/browser_gpu_memory_buffer_manager.cc
@@ -6,11 +6,14 @@
#include "base/atomic_sequence_num.h"
#include "base/bind.h"
-#include "base/debug/trace_event.h"
-#include "base/lazy_instance.h"
+#include "base/strings/stringprintf.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread_restrictions.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/trace_event.h"
+#include "content/common/gpu/client/gpu_memory_buffer_factory_host.h"
#include "content/common/gpu/client/gpu_memory_buffer_impl.h"
+#include "content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h"
#include "content/public/browser/browser_thread.h"
namespace content {
@@ -21,29 +24,38 @@ BrowserGpuMemoryBufferManager* g_gpu_memory_buffer_manager = nullptr;
// Global atomic to generate gpu memory buffer unique IDs.
base::StaticAtomicSequenceNumber g_next_gpu_memory_buffer_id;
+const char kMemoryAllocatorName[] = "gpumemorybuffer";
+
} // namespace
struct BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferRequest {
AllocateGpuMemoryBufferRequest(const gfx::Size& size,
gfx::GpuMemoryBuffer::Format format,
gfx::GpuMemoryBuffer::Usage usage,
- int client_id)
+ int client_id,
+ int surface_id)
: event(true, false),
size(size),
format(format),
usage(usage),
- client_id(client_id) {}
+ client_id(client_id),
+ surface_id(surface_id) {}
~AllocateGpuMemoryBufferRequest() {}
base::WaitableEvent event;
gfx::Size size;
gfx::GpuMemoryBuffer::Format format;
gfx::GpuMemoryBuffer::Usage usage;
int client_id;
+ int surface_id;
scoped_ptr<gfx::GpuMemoryBuffer> result;
};
-BrowserGpuMemoryBufferManager::BrowserGpuMemoryBufferManager(int gpu_client_id)
- : gpu_client_id_(gpu_client_id) {
+BrowserGpuMemoryBufferManager::BrowserGpuMemoryBufferManager(
+ GpuMemoryBufferFactoryHost* gpu_memory_buffer_factory_host,
+ int gpu_client_id)
+ : gpu_memory_buffer_factory_host_(gpu_memory_buffer_factory_host),
+ gpu_client_id_(gpu_client_id),
+ weak_ptr_factory_(this) {
DCHECK(!g_gpu_memory_buffer_manager);
g_gpu_memory_buffer_manager = this;
}
@@ -62,13 +74,44 @@ BrowserGpuMemoryBufferManager::AllocateGpuMemoryBuffer(
const gfx::Size& size,
gfx::GpuMemoryBuffer::Format format,
gfx::GpuMemoryBuffer::Usage usage) {
+ return AllocateGpuMemoryBufferCommon(size, format, usage, 0);
+}
+
+scoped_ptr<gfx::GpuMemoryBuffer>
+BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForScanout(
+ const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
+ int32 surface_id) {
+ DCHECK_GT(surface_id, 0);
+ return AllocateGpuMemoryBufferCommon(
+ size, format, gfx::GpuMemoryBuffer::SCANOUT, surface_id);
+}
+
+scoped_ptr<gfx::GpuMemoryBuffer>
+BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferCommon(
+ const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
+ gfx::GpuMemoryBuffer::Usage usage,
+ int32 surface_id) {
DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
- AllocateGpuMemoryBufferRequest request(size, format, usage, gpu_client_id_);
+ // Fallback to shared memory buffer if |format| and |usage| are not supported
+ // by factory.
+ if (!gpu_memory_buffer_factory_host_->IsGpuMemoryBufferConfigurationSupported(
+ format, usage)) {
+ DCHECK(GpuMemoryBufferImplSharedMemory::IsFormatSupported(format));
+ DCHECK_EQ(usage, gfx::GpuMemoryBuffer::MAP);
+ return GpuMemoryBufferImplSharedMemory::Create(
+ g_next_gpu_memory_buffer_id.GetNext(), size, format);
+ }
+
+ AllocateGpuMemoryBufferRequest request(size, format, usage, gpu_client_id_,
+ surface_id);
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
base::Bind(&BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferOnIO,
+ base::Unretained(this), // Safe as we wait for result below.
base::Unretained(&request)));
// We're blocking the UI thread, which is generally undesirable.
@@ -86,32 +129,42 @@ void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForChildProcess(
base::ProcessHandle child_process_handle,
int child_client_id,
const AllocationCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(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());
+ // Fallback to shared memory buffer if |format| and |usage| are not supported
+ // by factory.
+ if (!gpu_memory_buffer_factory_host_->IsGpuMemoryBufferConfigurationSupported(
+ format, usage)) {
+ // Early out if we cannot fallback to shared memory buffer.
+ if (!GpuMemoryBufferImplSharedMemory::IsFormatSupported(format) ||
+ !GpuMemoryBufferImplSharedMemory::IsSizeValidForFormat(size, format) ||
+ usage != gfx::GpuMemoryBuffer::MAP) {
+ callback.Run(gfx::GpuMemoryBufferHandle());
+ return;
+ }
+
+ buffers[new_id] = BufferInfo(size, format, gfx::SHARED_MEMORY_BUFFER);
+ callback.Run(GpuMemoryBufferImplSharedMemory::AllocateForChildProcess(
+ new_id, size, format, child_process_handle));
+ return;
+ }
+
// 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,
+ buffers[new_id] = BufferInfo(size, format, gfx::EMPTY_BUFFER);
+
+ gpu_memory_buffer_factory_host_->CreateGpuMemoryBuffer(
+ new_id, size, format, usage, child_client_id, 0,
base::Bind(&BrowserGpuMemoryBufferManager::
GpuMemoryBufferAllocatedForChildProcess,
- base::Unretained(this),
- child_process_handle,
- child_client_id,
- callback));
+ weak_ptr_factory_.GetWeakPtr(), child_client_id, callback));
}
gfx::GpuMemoryBuffer*
@@ -127,12 +180,43 @@ void BrowserGpuMemoryBufferManager::SetDestructionSyncPoint(
->set_destruction_sync_point(sync_point);
}
+bool BrowserGpuMemoryBufferManager::OnMemoryDump(
+ base::trace_event::ProcessMemoryDump* pmd) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ for (const auto& client : clients_) {
+ for (const auto& buffer : client.second) {
+ if (buffer.second.type == gfx::EMPTY_BUFFER)
+ continue;
+
+ base::trace_event::MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(
+ base::StringPrintf("%s/%d", kMemoryAllocatorName, buffer.first));
+ if (!dump)
+ return false;
+
+ size_t buffer_size_in_bytes = 0;
+ // Note: BufferSizeInBytes returns an approximated size for the buffer
+ // but the factory can be made to return the exact size if this
+ // approximation is not good enough.
+ bool valid_size = GpuMemoryBufferImpl::BufferSizeInBytes(
+ buffer.second.size, buffer.second.format, &buffer_size_in_bytes);
+ DCHECK(valid_size);
+
+ dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameOuterSize,
+ base::trace_event::MemoryAllocatorDump::kUnitsBytes,
+ buffer_size_in_bytes);
+ }
+ }
+
+ return true;
+}
+
void BrowserGpuMemoryBufferManager::ChildProcessDeletedGpuMemoryBuffer(
gfx::GpuMemoryBufferId id,
base::ProcessHandle child_process_handle,
int child_client_id,
uint32 sync_point) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(clients_.find(child_client_id) != clients_.end());
BufferMap& buffers = clients_[child_client_id];
@@ -145,13 +229,18 @@ void BrowserGpuMemoryBufferManager::ChildProcessDeletedGpuMemoryBuffer(
// 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) {
+ if (buffer_it->second.type == gfx::EMPTY_BUFFER) {
LOG(ERROR) << "Invalid GpuMemoryBuffer type.";
return;
}
- GpuMemoryBufferImpl::DeletedByChildProcess(
- buffer_it->second, id, child_process_handle, child_client_id, sync_point);
+ // Buffers allocated using the factory need to be destroyed through the
+ // factory.
+ if (buffer_it->second.type != gfx::SHARED_MEMORY_BUFFER) {
+ gpu_memory_buffer_factory_host_->DestroyGpuMemoryBuffer(id,
+ child_client_id,
+ sync_point);
+ }
buffers.erase(buffer_it);
}
@@ -159,35 +248,78 @@ void BrowserGpuMemoryBufferManager::ChildProcessDeletedGpuMemoryBuffer(
void BrowserGpuMemoryBufferManager::ProcessRemoved(
base::ProcessHandle process_handle,
int client_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
ClientMap::iterator client_it = clients_.find(client_id);
if (client_it == clients_.end())
return;
- for (auto &buffer_it : client_it->second) {
+ for (const auto& buffer : 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)
+ if (buffer.second.type == gfx::EMPTY_BUFFER)
+ continue;
+
+ // Skip shared memory buffers as they were not allocated using the factory.
+ if (buffer.second.type == gfx::SHARED_MEMORY_BUFFER)
continue;
- GpuMemoryBufferImpl::DeletedByChildProcess(buffer_it.second,
- buffer_it.first,
- process_handle,
- client_id,
- 0);
+ gpu_memory_buffer_factory_host_->DestroyGpuMemoryBuffer(buffer.first,
+ client_id, 0);
}
clients_.erase(client_it);
}
+void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferOnIO(
+ AllocateGpuMemoryBufferRequest* request) {
+ // Note: Unretained is safe as this is only used for synchronous allocation
+ // from a non-IO thread.
+ gpu_memory_buffer_factory_host_->CreateGpuMemoryBuffer(
+ g_next_gpu_memory_buffer_id.GetNext(), request->size, request->format,
+ request->usage, request->client_id, request->surface_id,
+ base::Bind(&BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedOnIO,
+ base::Unretained(this), base::Unretained(request)));
+}
+
+void BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedOnIO(
+ AllocateGpuMemoryBufferRequest* request,
+ const gfx::GpuMemoryBufferHandle& handle) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ // Early out if factory failed to allocate the buffer.
+ if (handle.is_null()) {
+ request->event.Signal();
+ return;
+ }
+
+ DCHECK_NE(handle.type, gfx::SHARED_MEMORY_BUFFER);
+ request->result = GpuMemoryBufferImpl::CreateFromHandle(
+ handle,
+ request->size,
+ request->format,
+ base::Bind(&BrowserGpuMemoryBufferManager::GpuMemoryBufferDeleted,
+ weak_ptr_factory_.GetWeakPtr(),
+ handle.id,
+ request->client_id));
+ request->event.Signal();
+}
+
+void BrowserGpuMemoryBufferManager::GpuMemoryBufferDeleted(
+ gfx::GpuMemoryBufferId id,
+ int client_id,
+ uint32 sync_point) {
+ gpu_memory_buffer_factory_host_->DestroyGpuMemoryBuffer(id,
+ client_id,
+ sync_point);
+}
+
void BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedForChildProcess(
- base::ProcessHandle child_process_handle,
int child_client_id,
const AllocationCallback& callback,
const gfx::GpuMemoryBufferHandle& handle) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
ClientMap::iterator client_it = clients_.find(child_client_id);
@@ -195,11 +327,8 @@ void BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedForChildProcess(
// allocated.
if (client_it == clients_.end()) {
if (!handle.is_null()) {
- GpuMemoryBufferImpl::DeletedByChildProcess(handle.type,
- handle.id,
- child_process_handle,
- child_client_id,
- 0);
+ gpu_memory_buffer_factory_host_->DestroyGpuMemoryBuffer(
+ handle.id, child_client_id, 0);
}
callback.Run(gfx::GpuMemoryBufferHandle());
return;
@@ -209,7 +338,7 @@ void BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedForChildProcess(
BufferMap::iterator buffer_it = buffers.find(handle.id);
DCHECK(buffer_it != buffers.end());
- DCHECK_EQ(buffer_it->second, gfx::EMPTY_BUFFER);
+ DCHECK_EQ(buffer_it->second.type, gfx::EMPTY_BUFFER);
if (handle.is_null()) {
buffers.erase(buffer_it);
@@ -217,34 +346,14 @@ void BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedForChildProcess(
return;
}
- // Store the type for this buffer so it can be cleaned up if the child
+ // The factory should never return a shared memory backed buffer.
+ DCHECK_NE(handle.type, gfx::SHARED_MEMORY_BUFFER);
+
+ // Store the type of this buffer so it can be cleaned up if the child
// process is removed.
- buffer_it->second = handle.type;
+ buffer_it->second.type = 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
index 84ad9e5c0f4..74ba943863e 100644
--- a/chromium/content/browser/gpu/browser_gpu_memory_buffer_manager.h
+++ b/chromium/content/browser/gpu/browser_gpu_memory_buffer_manager.h
@@ -6,19 +6,25 @@
#define CONTENT_BROWSER_GPU_BROWSER_GPU_MEMORY_BUFFER_MANAGER_H_
#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "base/trace_event/memory_dump_provider.h"
#include "content/common/content_export.h"
#include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
namespace content {
+class GpuMemoryBufferFactoryHost;
class GpuMemoryBufferImpl;
class CONTENT_EXPORT BrowserGpuMemoryBufferManager
- : public gpu::GpuMemoryBufferManager {
+ : public gpu::GpuMemoryBufferManager,
+ public base::trace_event::MemoryDumpProvider {
public:
typedef base::Callback<void(const gfx::GpuMemoryBufferHandle& handle)>
AllocationCallback;
- explicit BrowserGpuMemoryBufferManager(int gpu_client_id);
+ BrowserGpuMemoryBufferManager(
+ GpuMemoryBufferFactoryHost* gpu_memory_buffer_factory_host,
+ int gpu_client_id);
~BrowserGpuMemoryBufferManager() override;
static BrowserGpuMemoryBufferManager* current();
@@ -33,6 +39,15 @@ class CONTENT_EXPORT BrowserGpuMemoryBufferManager
void SetDestructionSyncPoint(gfx::GpuMemoryBuffer* buffer,
uint32 sync_point) override;
+ // Overridden from base::trace_event::MemoryDumpProvider:
+ bool OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd) override;
+
+ // Virtual for testing.
+ virtual scoped_ptr<gfx::GpuMemoryBuffer> AllocateGpuMemoryBufferForScanout(
+ const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
+ int32 surface_id);
+
void AllocateGpuMemoryBufferForChildProcess(
const gfx::Size& size,
gfx::GpuMemoryBuffer::Format format,
@@ -48,27 +63,45 @@ class CONTENT_EXPORT BrowserGpuMemoryBufferManager
void ProcessRemoved(base::ProcessHandle process_handle, int client_id);
private:
+ struct BufferInfo {
+ BufferInfo()
+ : format(gfx::GpuMemoryBuffer::RGBA_8888), type(gfx::EMPTY_BUFFER) {}
+ BufferInfo(const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
+ gfx::GpuMemoryBufferType type)
+ : size(size), format(format), type(type) {}
+
+ gfx::Size size;
+ gfx::GpuMemoryBuffer::Format format;
+ gfx::GpuMemoryBufferType type;
+ };
struct AllocateGpuMemoryBufferRequest;
+ scoped_ptr<gfx::GpuMemoryBuffer> AllocateGpuMemoryBufferCommon(
+ const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
+ gfx::GpuMemoryBuffer::Usage usage,
+ int32 surface_id);
+ void AllocateGpuMemoryBufferOnIO(AllocateGpuMemoryBufferRequest* request);
+ void GpuMemoryBufferAllocatedOnIO(AllocateGpuMemoryBufferRequest* request,
+ const gfx::GpuMemoryBufferHandle& handle);
+ void GpuMemoryBufferDeleted(gfx::GpuMemoryBufferId id,
+ int client_id,
+ uint32 sync_point);
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);
-
+ GpuMemoryBufferFactoryHost* gpu_memory_buffer_factory_host_;
int gpu_client_id_;
- typedef base::hash_map<gfx::GpuMemoryBufferId, gfx::GpuMemoryBufferType>
- BufferMap;
+ typedef base::hash_map<gfx::GpuMemoryBufferId, BufferInfo> BufferMap;
typedef base::hash_map<int, BufferMap> ClientMap;
ClientMap clients_;
+ base::WeakPtrFactory<BrowserGpuMemoryBufferManager> weak_ptr_factory_;
+
DISALLOW_COPY_AND_ASSIGN(BrowserGpuMemoryBufferManager);
};
diff --git a/chromium/content/browser/gpu/compositor_util.cc b/chromium/content/browser/gpu/compositor_util.cc
index 77cf2bc5a83..a96cdeae413 100644
--- a/chromium/content/browser/gpu/compositor_util.cc
+++ b/chromium/content/browser/gpu/compositor_util.cc
@@ -8,6 +8,7 @@
#include "base/logging.h"
#include "base/metrics/field_trial.h"
#include "base/strings/string_number_conversions.h"
+#include "base/sys_info.h"
#include "build/build_config.h"
#include "cc/base/switches.h"
#include "content/browser/gpu/gpu_data_manager_impl.h"
@@ -33,6 +34,8 @@ const char* kMultipleRasterThreadsFeatureName = "multiple_raster_threads";
const int kMinRasterThreads = 1;
const int kMaxRasterThreads = 64;
+const int kMinMSAASampleCount = 0;
+
struct GpuFeatureInfo {
std::string name;
bool blocked;
@@ -173,11 +176,13 @@ bool IsPinchVirtualViewportEnabled() {
if (command_line.HasSwitch(cc::switches::kEnablePinchVirtualViewport))
return true;
-#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
return true;
-#else
- return false;
-#endif
+}
+
+bool IsPropertyTreeVerificationEnabled() {
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
+ return command_line.HasSwitch(cc::switches::kEnablePropertyTreeVerification);
}
bool IsDelegatedRendererEnabled() {
@@ -199,18 +204,21 @@ bool IsDelegatedRendererEnabled() {
bool IsImplSidePaintingEnabled() {
const base::CommandLine& command_line =
*base::CommandLine::ForCurrentProcess();
-
- if (command_line.HasSwitch(switches::kEnableImplSidePainting))
- return true;
- else if (command_line.HasSwitch(switches::kDisableImplSidePainting))
+ if (command_line.HasSwitch(switches::kDisableImplSidePainting))
return false;
-
return true;
}
int NumberOfRendererRasterThreads() {
int num_raster_threads = 1;
+ // Async uploads uses its own thread, so allow an extra thread when async
+ // uploads is not in use.
+ bool allow_extra_thread =
+ IsZeroCopyUploadEnabled() || IsOneCopyUploadEnabled();
+ if (base::SysInfo::NumberOfProcessors() >= 4 && allow_extra_thread)
+ num_raster_threads = 2;
+
int force_num_raster_threads = ForceNumberOfRendererRasterThreads();
if (force_num_raster_threads)
num_raster_threads = force_num_raster_threads;
@@ -218,6 +226,29 @@ int NumberOfRendererRasterThreads() {
return num_raster_threads;
}
+bool IsOneCopyUploadEnabled() {
+ if (IsZeroCopyUploadEnabled())
+ return false;
+
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
+ if (command_line.HasSwitch(switches::kEnableOneCopy))
+ return true;
+ if (command_line.HasSwitch(switches::kDisableOneCopy))
+ return false;
+
+#if defined(OS_ANDROID)
+ return false;
+#endif
+ return true;
+}
+
+bool IsZeroCopyUploadEnabled() {
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
+ return command_line.HasSwitch(switches::kEnableZeroCopy);
+}
+
int ForceNumberOfRendererRasterThreads() {
const base::CommandLine& command_line =
*base::CommandLine::ForCurrentProcess();
@@ -232,7 +263,7 @@ int ForceNumberOfRendererRasterThreads() {
force_num_raster_threads <= kMaxRasterThreads) {
return force_num_raster_threads;
} else {
- LOG(WARNING) << "Failed to parse switch " <<
+ DLOG(WARNING) << "Failed to parse switch " <<
switches::kNumRasterThreads << ": " << string_value;
return 0;
}
@@ -254,7 +285,13 @@ bool IsGpuRasterizationEnabled() {
return false;
}
+#if defined(OS_ANDROID)
return true;
+#endif
+
+ // explicitly disable GPU rasterization on all non-android devices until we
+ // have full test coverage.
+ return false;
}
bool IsForceGpuRasterizationEnabled() {
@@ -268,13 +305,48 @@ bool IsForceGpuRasterizationEnabled() {
}
bool UseSurfacesEnabled() {
+#if defined(OS_ANDROID)
+ return false;
+#endif
+ bool enabled = false;
+#if defined(USE_AURA) || defined(OS_MACOSX)
+ enabled = true;
+#endif
+
const base::CommandLine& command_line =
*base::CommandLine::ForCurrentProcess();
- return command_line.HasSwitch(switches::kUseSurfaces);
+ // Flags override.
+ enabled |= command_line.HasSwitch(switches::kUseSurfaces);
+ enabled &= !command_line.HasSwitch(switches::kDisableSurfaces);
+ return enabled;
+}
+
+int GpuRasterizationMSAASampleCount() {
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
+
+ if (!command_line.HasSwitch(switches::kGpuRasterizationMSAASampleCount))
+#if defined(OS_ANDROID)
+ return 4;
+#else
+ return 8;
+#endif
+ std::string string_value = command_line.GetSwitchValueASCII(
+ switches::kGpuRasterizationMSAASampleCount);
+ int msaa_sample_count = 0;
+ if (base::StringToInt(string_value, &msaa_sample_count) &&
+ msaa_sample_count >= kMinMSAASampleCount) {
+ return msaa_sample_count;
+ } else {
+ DLOG(WARNING) << "Failed to parse switch "
+ << switches::kGpuRasterizationMSAASampleCount << ": "
+ << string_value;
+ return 0;
+ }
}
-base::Value* GetFeatureStatus() {
+base::DictionaryValue* GetFeatureStatus() {
GpuDataManagerImpl* manager = GpuDataManagerImpl::GetInstance();
std::string gpu_access_blocked_reason;
bool gpu_access_blocked =
@@ -371,10 +443,8 @@ base::Value* GetProblems() {
return problem_list;
}
-base::Value* GetDriverBugWorkarounds() {
- base::ListValue* workaround_list = new base::ListValue();
- GpuDataManagerImpl::GetInstance()->GetDriverBugWorkarounds(workaround_list);
- return workaround_list;
+std::vector<std::string> GetDriverBugWorkarounds() {
+ return GpuDataManagerImpl::GetInstance()->GetDriverBugWorkarounds();
}
} // namespace content
diff --git a/chromium/content/browser/gpu/compositor_util.h b/chromium/content/browser/gpu/compositor_util.h
index b26bb94968a..3d23ab51d5f 100644
--- a/chromium/content/browser/gpu/compositor_util.h
+++ b/chromium/content/browser/gpu/compositor_util.h
@@ -17,6 +17,10 @@ namespace content {
// flags, or platform default).
CONTENT_EXPORT bool IsPinchVirtualViewportEnabled();
+// Returns true if property tree verification is enabled (via flags or platform
+// default).
+CONTENT_EXPORT bool IsPropertyTreeVerificationEnabled();
+
// Returns true if delegated-renderer is on (via flags, or platform default).
CONTENT_EXPORT bool IsDelegatedRendererEnabled();
@@ -24,9 +28,21 @@ CONTENT_EXPORT bool IsDelegatedRendererEnabled();
// for the renderer.
CONTENT_EXPORT bool IsImplSidePaintingEnabled();
+// Returns true if one-copy uploads is on (via flags, or platform default).
+// Only one of one-copy and zero-copy can be enabled at a time.
+CONTENT_EXPORT bool IsOneCopyUploadEnabled();
+
+// Returns true if zero-copy uploads is on (via flags, or platform default).
+// Only one of one-copy and zero-copy can be enabled at a time.
+CONTENT_EXPORT bool IsZeroCopyUploadEnabled();
+
// Returns true if gpu rasterization is on (via flags) for the renderer.
CONTENT_EXPORT bool IsGpuRasterizationEnabled();
+// Returns the number of multisample antialiasing samples (via flags) for
+// GPU rasterization.
+CONTENT_EXPORT int GpuRasterizationMSAASampleCount();
+
// Returns true if force-gpu-rasterization is on (via flags) for the renderer.
CONTENT_EXPORT bool IsForceGpuRasterizationEnabled();
@@ -40,9 +56,9 @@ CONTENT_EXPORT int ForceNumberOfRendererRasterThreads();
// Returns true if using cc Surfaces is allowed.
CONTENT_EXPORT bool UseSurfacesEnabled();
-CONTENT_EXPORT base::Value* GetFeatureStatus();
+CONTENT_EXPORT base::DictionaryValue* GetFeatureStatus();
CONTENT_EXPORT base::Value* GetProblems();
-CONTENT_EXPORT base::Value* GetDriverBugWorkarounds();
+CONTENT_EXPORT std::vector<std::string> GetDriverBugWorkarounds();
} // namespace content
diff --git a/chromium/content/browser/gpu/compositor_util_browsertest.cc b/chromium/content/browser/gpu/compositor_util_browsertest.cc
deleted file mode 100644
index 550d7773c0a..00000000000
--- a/chromium/content/browser/gpu/compositor_util_browsertest.cc
+++ /dev/null
@@ -1,33 +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/gpu/compositor_util.h"
-#include "content/public/test/content_browser_test.h"
-
-#if defined(OS_MACOSX)
-#include "base/mac/mac_util.h"
-#elif defined(OS_WIN)
-#include "base/win/windows_version.h"
-#endif
-
-namespace content {
-
-typedef ContentBrowserTest CompositorUtilTest;
-
-// Test that compositing is in the expected mode on the bots for all platforms.
-IN_PROC_BROWSER_TEST_F(CompositorUtilTest, CompositingModeAsExpected) {
- enum CompositingMode {
- DIRECT,
- DELEGATED,
- } expected_mode = DIRECT;
-#if defined(USE_AURA) || defined(OS_ANDROID)
- expected_mode = DELEGATED;
-#elif defined(OS_MACOSX)
- expected_mode = DELEGATED;
-#endif
-
- 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 3e24bb5be2d..0d665d1fda2 100644
--- a/chromium/content/browser/gpu/gpu_data_manager_impl.cc
+++ b/chromium/content/browser/gpu/gpu_data_manager_impl.cc
@@ -132,6 +132,12 @@ bool GpuDataManagerImpl::CanUseGpuBrowserCompositor() const {
return private_->CanUseGpuBrowserCompositor();
}
+void GpuDataManagerImpl::GetDisabledExtensions(
+ std::string* disabled_extensions) const {
+ base::AutoLock auto_lock(lock_);
+ private_->GetDisabledExtensions(disabled_extensions);
+}
+
void GpuDataManagerImpl::Initialize() {
base::AutoLock auto_lock(lock_);
private_->Initialize();
@@ -187,10 +193,9 @@ void GpuDataManagerImpl::GetBlacklistReasons(base::ListValue* reasons) const {
private_->GetBlacklistReasons(reasons);
}
-void GpuDataManagerImpl::GetDriverBugWorkarounds(
- base::ListValue* workarounds) const {
+std::vector<std::string> GpuDataManagerImpl::GetDriverBugWorkarounds() const {
base::AutoLock auto_lock(lock_);
- private_->GetDriverBugWorkarounds(workarounds);
+ return private_->GetDriverBugWorkarounds();
}
void GpuDataManagerImpl::AddLogMessage(int level,
diff --git a/chromium/content/browser/gpu/gpu_data_manager_impl.h b/chromium/content/browser/gpu/gpu_data_manager_impl.h
index 981ad7a85b6..3f1d2761c2f 100644
--- a/chromium/content/browser/gpu/gpu_data_manager_impl.h
+++ b/chromium/content/browser/gpu/gpu_data_manager_impl.h
@@ -72,6 +72,11 @@ class CONTENT_EXPORT GpuDataManagerImpl
bool ShouldUseSwiftShader() const override;
void RegisterSwiftShaderPath(const base::FilePath& path) override;
bool ShouldUseWarp() const override;
+ // TODO(kbr): the threading model for the GpuDataManagerObservers is
+ // not well defined, and it's impossible for callers to correctly
+ // delete observers from anywhere except in one of the observer's
+ // notification methods. Observer addition and removal, and their
+ // callbacks, should probably be required to occur on the UI thread.
void AddObserver(GpuDataManagerObserver* observer) override;
void RemoveObserver(GpuDataManagerObserver* observer) override;
void UnblockDomainFrom3DAPIs(const GURL& url) override;
@@ -84,6 +89,7 @@ class CONTENT_EXPORT GpuDataManagerImpl
std::string* gl_version) override;
void DisableHardwareAcceleration() override;
bool CanUseGpuBrowserCompositor() const override;
+ void GetDisabledExtensions(std::string* disabled_extensions) const override;
// This collects preliminary GPU info, load GpuBlacklist, and compute the
// preliminary blacklisted features; it should only be called at browser
@@ -120,8 +126,8 @@ class CONTENT_EXPORT GpuDataManagerImpl
void GetBlacklistReasons(base::ListValue* reasons) const;
// Returns the workarounds that are applied to the current system as
- // a list of strings.
- void GetDriverBugWorkarounds(base::ListValue* workarounds) const;
+ // a vector of strings.
+ std::vector<std::string> GetDriverBugWorkarounds() const;
void AddLogMessage(int level,
const std::string& header,
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 f71a62c8652..201e4576586 100644
--- a/chromium/content/browser/gpu/gpu_data_manager_impl_private.cc
+++ b/chromium/content/browser/gpu/gpu_data_manager_impl_private.cc
@@ -7,13 +7,13 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/command_line.h"
-#include "base/debug/trace_event.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
#include "base/metrics/sparse_histogram.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/sys_info.h"
+#include "base/trace_event/trace_event.h"
#include "base/version.h"
#include "cc/base/switches.h"
#include "content/browser/gpu/gpu_process_host.h"
@@ -29,6 +29,7 @@
#include "gpu/config/gpu_driver_bug_workaround_type.h"
#include "gpu/config/gpu_feature_type.h"
#include "gpu/config/gpu_info_collector.h"
+#include "gpu/config/gpu_switches.h"
#include "gpu/config/gpu_util.h"
#include "ui/base/ui_base_switches.h"
#include "ui/gl/gl_implementation.h"
@@ -77,7 +78,7 @@ int GetGpuBlacklistHistogramValueWin(GpuFeatureStatus status) {
version_str = version_str.substr(0, pos);
Version os_version(version_str);
if (os_version.IsValid() && os_version.components().size() >= 2) {
- const std::vector<uint16>& version_numbers = os_version.components();
+ const std::vector<uint32_t>& version_numbers = os_version.components();
if (version_numbers[0] == 5)
sub_version = kWinXP;
else if (version_numbers[0] == 6 && version_numbers[1] == 0)
@@ -411,8 +412,10 @@ void GpuDataManagerImplPrivate::RegisterSwiftShaderPath(
}
bool GpuDataManagerImplPrivate::ShouldUseWarp() const {
- return use_warp_ ||
- CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseWarp);
+ std::string angle_impl_flag =
+ base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kUseANGLE);
+ return use_warp_ || angle_impl_flag == gfx::kANGLEImplementationWARPName;
}
void GpuDataManagerImplPrivate::AddObserver(GpuDataManagerObserver* observer) {
@@ -495,8 +498,7 @@ void GpuDataManagerImplPrivate::Initialize() {
return;
}
- const base::CommandLine* command_line =
- base::CommandLine::ForCurrentProcess();
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kSkipGpuDataLoading))
return;
@@ -540,6 +542,12 @@ void GpuDataManagerImplPrivate::Initialize() {
InitializeImpl(gpu_blacklist_string,
gpu_driver_bug_list_string,
gpu_info);
+
+ if (command_line->HasSwitch(switches::kSingleProcess) ||
+ command_line->HasSwitch(switches::kInProcessGPU)) {
+ command_line->AppendSwitch(switches::kDisableGpuWatchdog);
+ AppendGpuCommandLine(command_line);
+ }
}
void GpuDataManagerImplPrivate::UpdateGpuInfoHelper() {
@@ -556,6 +564,9 @@ void GpuDataManagerImplPrivate::UpdateGpuInfoHelper() {
if (gpu_driver_bug_list_) {
gpu_driver_bugs_ = gpu_driver_bug_list_->MakeDecision(
gpu::GpuControlList::kOsAny, std::string(), gpu_info_);
+
+ disabled_extensions_ =
+ JoinString(gpu_driver_bug_list_->GetDisabledExtensions(), ' ');
}
gpu::GpuDriverBugList::AppendWorkaroundsFromCommandLine(
&gpu_driver_bugs_, *base::CommandLine::ForCurrentProcess());
@@ -569,9 +580,14 @@ void GpuDataManagerImplPrivate::UpdateGpuInfo(const gpu::GPUInfo& gpu_info) {
if (use_swiftshader_ || ShouldUseWarp())
return;
+ bool was_info_available = IsCompleteGpuInfoAvailable();
gpu::MergeGPUInfo(&gpu_info_, gpu_info);
- if (IsCompleteGpuInfoAvailable())
+ if (IsCompleteGpuInfoAvailable()) {
complete_gpu_info_already_requested_ = true;
+ } else if (was_info_available) {
+ // Allow future requests to go through properly.
+ complete_gpu_info_already_requested_ = false;
+ }
UpdateGpuInfoHelper();
}
@@ -579,7 +595,8 @@ void GpuDataManagerImplPrivate::UpdateGpuInfo(const gpu::GPUInfo& gpu_info) {
void GpuDataManagerImplPrivate::UpdateVideoMemoryUsageStats(
const GPUVideoMemoryUsageStats& video_memory_usage_stats) {
GpuDataManagerImpl::UnlockedSession session(owner_);
- observer_list_->Notify(&GpuDataManagerObserver::OnVideoMemoryUsageStatsUpdate,
+ observer_list_->Notify(FROM_HERE,
+ &GpuDataManagerObserver::OnVideoMemoryUsageStatsUpdate,
video_memory_usage_stats);
}
@@ -587,8 +604,7 @@ void GpuDataManagerImplPrivate::AppendRendererCommandLine(
base::CommandLine* command_line) const {
DCHECK(command_line);
- if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE) &&
- !command_line->HasSwitch(switches::kDisableAcceleratedVideoDecode))
+ if (ShouldDisableAcceleratedVideoDecode(command_line))
command_line->AppendSwitch(switches::kDisableAcceleratedVideoDecode);
#if defined(ENABLE_WEBRTC)
if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_ENCODE) &&
@@ -643,8 +659,7 @@ void GpuDataManagerImplPrivate::AppendGpuCommandLine(
IntSetToString(gpu_driver_bugs_));
}
- if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE) &&
- !command_line->HasSwitch(switches::kDisableAcceleratedVideoDecode)) {
+ if (ShouldDisableAcceleratedVideoDecode(command_line)) {
command_line->AppendSwitch(switches::kDisableAcceleratedVideoDecode);
}
#if defined(ENABLE_WEBRTC)
@@ -667,8 +682,10 @@ void GpuDataManagerImplPrivate::AppendGpuCommandLine(
command_line->AppendSwitchASCII(switches::kGpuDriverVersion,
gpu_info_.driver_version);
- if (ShouldUseWarp())
- command_line->AppendSwitch(switches::kUseWarp);
+ if (ShouldUseWarp() && !command_line->HasSwitch(switches::kUseANGLE)) {
+ command_line->AppendSwitchASCII(switches::kUseANGLE,
+ gfx::kANGLEImplementationWARPName);
+ }
}
void GpuDataManagerImplPrivate::AppendPluginCommandLine(
@@ -706,9 +723,15 @@ void GpuDataManagerImplPrivate::UpdateRendererWebPrefs(
prefs->flash_stage3d_baseline_enabled = false;
if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS))
prefs->accelerated_2d_canvas_enabled = false;
- if (IsDriverBugWorkaroundActive(gpu::DISABLE_MULTISAMPLING) ||
+ // TODO(senorblanco): The renderer shouldn't have an extra setting
+ // for this, but should rely on extension availability.
+ // Note that |gl_multisampling_enabled| only affects the decoder's
+ // default framebuffer allocation, which does not support
+ // multisampled_render_to_texture, only msaa with explicit resolve.
+ if (IsDriverBugWorkaroundActive(
+ gpu::DISABLE_CHROMIUM_FRAMEBUFFER_MULTISAMPLE) ||
(IsDriverBugWorkaroundActive(gpu::DISABLE_MULTIMONITOR_MULTISAMPLING) &&
- display_count_ > 1))
+ display_count_ > 1))
prefs->gl_multisampling_enabled = false;
#if defined(USE_AURA)
@@ -718,9 +741,10 @@ void GpuDataManagerImplPrivate::UpdateRendererWebPrefs(
}
#endif
- if (!IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE) &&
- !base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableAcceleratedVideoDecode)) {
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
+ if (!ShouldDisableAcceleratedVideoDecode(command_line) &&
+ !command_line->HasSwitch(switches::kDisableAcceleratedVideoDecode)) {
prefs->pepper_accelerated_video_decode_enabled = true;
}
}
@@ -756,14 +780,16 @@ void GpuDataManagerImplPrivate::GetBlacklistReasons(
gpu_driver_bug_list_->GetReasons(reasons, "workarounds");
}
-void GpuDataManagerImplPrivate::GetDriverBugWorkarounds(
- base::ListValue* workarounds) const {
+std::vector<std::string>
+GpuDataManagerImplPrivate::GetDriverBugWorkarounds() const {
+ std::vector<std::string> workarounds;
for (std::set<int>::const_iterator it = gpu_driver_bugs_.begin();
it != gpu_driver_bugs_.end(); ++it) {
- workarounds->AppendString(
+ workarounds.push_back(
gpu::GpuDriverBugWorkaroundTypeToString(
static_cast<gpu::GpuDriverBugWorkaroundType>(*it)));
}
+ return workarounds;
}
void GpuDataManagerImplPrivate::AddLogMessage(
@@ -788,7 +814,7 @@ void GpuDataManagerImplPrivate::ProcessCrashed(
gpu_info_.process_crash_count = GpuProcessHost::gpu_crash_count();
GpuDataManagerImpl::UnlockedSession session(owner_);
observer_list_->Notify(
- &GpuDataManagerObserver::OnGpuProcessCrashed, exit_code);
+ FROM_HERE, &GpuDataManagerObserver::OnGpuProcessCrashed, exit_code);
}
}
@@ -844,7 +870,7 @@ bool GpuDataManagerImplPrivate::UpdateActiveGpu(
}
bool GpuDataManagerImplPrivate::CanUseGpuBrowserCompositor() const {
- if (CommandLine::ForCurrentProcess()->HasSwitch(
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableGpuCompositing))
return false;
if (ShouldUseWarp())
@@ -856,6 +882,33 @@ bool GpuDataManagerImplPrivate::CanUseGpuBrowserCompositor() const {
return true;
}
+
+bool GpuDataManagerImplPrivate::ShouldDisableAcceleratedVideoDecode(
+ const base::CommandLine* command_line) const {
+ // Make sure that we initialize the experiment first to make sure that
+ // statistics are bucket correctly in all cases.
+ // This experiment is temporary and will be removed once enough data
+ // to resolve crbug/442039 has been collected.
+ const std::string group_name = base::FieldTrialList::FindFullName(
+ "DisableAcceleratedVideoDecode");
+ if (command_line->HasSwitch(switches::kDisableAcceleratedVideoDecode)) {
+ // It was already disabled on the command line.
+ return false;
+ }
+ if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE))
+ return true;
+ if (group_name == "Disabled")
+ return true;
+ return false;
+}
+
+void GpuDataManagerImplPrivate::GetDisabledExtensions(
+ std::string* disabled_extensions) const {
+ DCHECK(disabled_extensions);
+
+ *disabled_extensions = disabled_extensions_;
+}
+
void GpuDataManagerImplPrivate::BlockDomainFrom3DAPIs(
const GURL& url, GpuDataManagerImpl::DomainGuilt guilt) {
BlockDomainFrom3DAPIsAtTime(url, guilt, base::Time::Now());
@@ -979,8 +1032,14 @@ void GpuDataManagerImplPrivate::UpdatePreliminaryBlacklistedFeatures() {
void GpuDataManagerImplPrivate::UpdateGpuSwitchingManager(
const gpu::GPUInfo& gpu_info) {
- ui::GpuSwitchingManager::GetInstance()->SetGpuCount(
- gpu_info.secondary_gpus.size() + 1);
+ // The vendor IDs might be 0 on non-PCI devices (like Android), but
+ // the length of the vector is all we care about in most cases.
+ std::vector<uint32> vendor_ids;
+ vendor_ids.push_back(gpu_info.gpu.vendor_id);
+ for (const auto& device : gpu_info.secondary_gpus) {
+ vendor_ids.push_back(device.vendor_id);
+ }
+ ui::GpuSwitchingManager::GetInstance()->SetGpuVendorIds(vendor_ids);
if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus()) {
if (gpu_driver_bugs_.count(gpu::FORCE_DISCRETE_GPU) == 1)
@@ -991,7 +1050,7 @@ void GpuDataManagerImplPrivate::UpdateGpuSwitchingManager(
}
void GpuDataManagerImplPrivate::NotifyGpuInfoUpdate() {
- observer_list_->Notify(&GpuDataManagerObserver::OnGpuInfoUpdate);
+ observer_list_->Notify(FROM_HERE, &GpuDataManagerObserver::OnGpuInfoUpdate);
}
void GpuDataManagerImplPrivate::EnableSwiftShaderIfNecessary() {
@@ -1013,9 +1072,9 @@ void GpuDataManagerImplPrivate::EnableWarpIfNecessary() {
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();
+ use_warp_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kViewerConnect) &&
+ !CanUseGpuBrowserCompositor();
#endif
}
@@ -1124,7 +1183,7 @@ void GpuDataManagerImplPrivate::Notify3DAPIBlocked(const GURL& url,
int render_view_id,
ThreeDAPIType requester) {
GpuDataManagerImpl::UnlockedSession session(owner_);
- observer_list_->Notify(&GpuDataManagerObserver::DidBlock3DAPIs,
+ observer_list_->Notify(FROM_HERE, &GpuDataManagerObserver::DidBlock3DAPIs,
url, render_process_id, render_view_id, requester);
}
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 b3466c14ca5..2a2b0c155fc 100644
--- a/chromium/content/browser/gpu/gpu_data_manager_impl_private.h
+++ b/chromium/content/browser/gpu/gpu_data_manager_impl_private.h
@@ -76,7 +76,7 @@ class CONTENT_EXPORT GpuDataManagerImplPrivate {
void GetBlacklistReasons(base::ListValue* reasons) const;
- void GetDriverBugWorkarounds(base::ListValue* workarounds) const;
+ std::vector<std::string> GetDriverBugWorkarounds() const;
void AddLogMessage(int level,
const std::string& header,
@@ -89,6 +89,10 @@ class CONTENT_EXPORT GpuDataManagerImplPrivate {
void HandleGpuSwitch();
bool CanUseGpuBrowserCompositor() const;
+ bool ShouldDisableAcceleratedVideoDecode(
+ const base::CommandLine* command_line) const;
+
+ void GetDisabledExtensions(std::string* disabled_extensions) const;
void BlockDomainFrom3DAPIs(
const GURL& url, GpuDataManagerImpl::DomainGuilt guilt);
@@ -270,10 +274,11 @@ class CONTENT_EXPORT GpuDataManagerImplPrivate {
// True if all future Initialize calls should be ignored.
bool finalized_;
+ std::string disabled_extensions_;
+
DISALLOW_COPY_AND_ASSIGN(GpuDataManagerImplPrivate);
};
} // namespace content
#endif // CONTENT_BROWSER_GPU_GPU_DATA_MANAGER_IMPL_PRIVATE_H_
-
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 8bcb01052e7..41223ac0ba2 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
@@ -8,9 +8,9 @@
#include "base/time/time.h"
#include "content/browser/gpu/gpu_data_manager_impl_private.h"
#include "content/public/browser/gpu_data_manager_observer.h"
-#include "gpu/command_buffer/service/gpu_switches.h"
#include "gpu/config/gpu_feature_type.h"
#include "gpu/config/gpu_info.h"
+#include "gpu/config/gpu_switches.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
diff --git a/chromium/content/browser/gpu/gpu_internals_ui.cc b/chromium/content/browser/gpu/gpu_internals_ui.cc
index 4eb492696c5..7991aa3a79a 100644
--- a/chromium/content/browser/gpu/gpu_internals_ui.cc
+++ b/chromium/content/browser/gpu/gpu_internals_ui.cc
@@ -144,6 +144,10 @@ base::DictionaryValue* GpuInfoAsDictionaryValue() {
}
#endif
+ std::string disabled_extensions;
+ GpuDataManagerImpl::GetInstance()->GetDisabledExtensions(
+ &disabled_extensions);
+
basic_info->Append(
NewDescriptionValuePair("Driver vendor", gpu_info.driver_vendor));
basic_info->Append(NewDescriptionValuePair("Driver version",
@@ -154,6 +158,8 @@ base::DictionaryValue* GpuInfoAsDictionaryValue() {
gpu_info.pixel_shader_version));
basic_info->Append(NewDescriptionValuePair("Vertex shader version",
gpu_info.vertex_shader_version));
+ basic_info->Append(NewDescriptionValuePair("Max. MSAA samples",
+ gpu_info.max_msaa_samples));
basic_info->Append(NewDescriptionValuePair("Machine model name",
gpu_info.machine_model_name));
basic_info->Append(NewDescriptionValuePair("Machine model version",
@@ -166,6 +172,8 @@ base::DictionaryValue* GpuInfoAsDictionaryValue() {
gpu_info.gl_version));
basic_info->Append(NewDescriptionValuePair("GL_EXTENSIONS",
gpu_info.gl_extensions));
+ basic_info->Append(NewDescriptionValuePair("Disabled Extensions",
+ disabled_extensions));
basic_info->Append(NewDescriptionValuePair("Window system binding vendor",
gpu_info.gl_ws_vendor));
basic_info->Append(NewDescriptionValuePair("Window system binding version",
@@ -213,22 +221,10 @@ base::DictionaryValue* GpuInfoAsDictionaryValue() {
info->Set("basic_info", basic_info);
#if defined(OS_WIN)
- base::ListValue* perf_info = new base::ListValue();
- perf_info->Append(NewDescriptionValuePair(
- "Graphics",
- base::StringPrintf("%.1f", gpu_info.performance_stats.graphics)));
- perf_info->Append(NewDescriptionValuePair(
- "Gaming",
- base::StringPrintf("%.1f", gpu_info.performance_stats.gaming)));
- perf_info->Append(NewDescriptionValuePair(
- "Overall",
- base::StringPrintf("%.1f", gpu_info.performance_stats.overall)));
- info->Set("performance_info", perf_info);
-
- base::Value* dx_info = gpu_info.dx_diagnostics.children.size() ?
- DxDiagNodeToList(gpu_info.dx_diagnostics) :
- base::Value::CreateNullValue();
- info->Set("diagnostics", dx_info);
+ scoped_ptr<base::Value> dx_info = base::Value::CreateNullValue();
+ if (gpu_info.dx_diagnostics.children.size())
+ dx_info.reset(DxDiagNodeToList(gpu_info.dx_diagnostics));
+ info->Set("diagnostics", dx_info.Pass());
#endif
return info;
@@ -288,7 +284,7 @@ GpuMessageHandler::~GpuMessageHandler() {
/* BrowserBridge.callAsync prepends a requestID to these messages. */
void GpuMessageHandler::RegisterMessages() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
web_ui()->RegisterMessageCallback("browserBridgeInitialized",
base::Bind(&GpuMessageHandler::OnBrowserBridgeInitialized,
@@ -347,7 +343,7 @@ void GpuMessageHandler::OnCallAsync(const base::ListValue* args) {
void GpuMessageHandler::OnBrowserBridgeInitialized(
const base::ListValue* args) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
// Watch for changes in GPUInfo
if (!observing_) {
@@ -367,7 +363,7 @@ void GpuMessageHandler::OnBrowserBridgeInitialized(
base::Value* GpuMessageHandler::OnRequestClientInfo(
const base::ListValue* list) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
base::DictionaryValue* dict = new base::DictionaryValue();
@@ -388,7 +384,7 @@ base::Value* GpuMessageHandler::OnRequestClientInfo(
}
base::Value* GpuMessageHandler::OnRequestLogMessages(const base::ListValue*) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
return GpuDataManagerImpl::GetInstance()->GetLogMessages();
}
@@ -397,13 +393,16 @@ void GpuMessageHandler::OnGpuInfoUpdate() {
// Get GPU Info.
scoped_ptr<base::DictionaryValue> gpu_info_val(GpuInfoAsDictionaryValue());
+
// Add in blacklisting features
base::DictionaryValue* feature_status = new base::DictionaryValue;
feature_status->Set("featureStatus", GetFeatureStatus());
feature_status->Set("problems", GetProblems());
- feature_status->Set("workarounds", GetDriverBugWorkarounds());
- if (feature_status)
- gpu_info_val->Set("featureStatus", feature_status);
+ base::ListValue* workarounds = new base::ListValue();
+ for (const std::string& workaround : GetDriverBugWorkarounds())
+ workarounds->AppendString(workaround);
+ feature_status->Set("workarounds", workarounds);
+ gpu_info_val->Set("featureStatus", feature_status);
// Send GPU Info to javascript.
web_ui()->CallJavascriptFunction("browserBridge.onGpuInfoUpdate",
diff --git a/chromium/content/browser/gpu/gpu_internals_ui.h b/chromium/content/browser/gpu/gpu_internals_ui.h
index 45912e30703..41fd7ead277 100644
--- a/chromium/content/browser/gpu/gpu_internals_ui.h
+++ b/chromium/content/browser/gpu/gpu_internals_ui.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CHROME_BROWSER_UI_WEBUI_GPU_INTERNALS_UI_H_
-#define CHROME_BROWSER_UI_WEBUI_GPU_INTERNALS_UI_H_
+#ifndef CONTENT_BROWSER_GPU_GPU_INTERNALS_UI_H_
+#define CONTENT_BROWSER_GPU_GPU_INTERNALS_UI_H_
#include "content/public/browser/web_ui_controller.h"
@@ -19,5 +19,5 @@ class GpuInternalsUI : public WebUIController {
} // namespace content
-#endif // CHROME_BROWSER_UI_WEBUI_GPU_INTERNALS_UI_H_
+#endif // CONTENT_BROWSER_GPU_GPU_INTERNALS_UI_H_
diff --git a/chromium/content/browser/gpu/gpu_ipc_browsertests.cc b/chromium/content/browser/gpu/gpu_ipc_browsertests.cc
index dd78ba6017d..7154c2eea99 100644
--- a/chromium/content/browser/gpu/gpu_ipc_browsertests.cc
+++ b/chromium/content/browser/gpu/gpu_ipc_browsertests.cc
@@ -12,8 +12,8 @@
#include "content/public/browser/gpu_data_manager.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/content_browser_test.h"
+#include "gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.h"
#include "ui/gl/gl_switches.h"
-#include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"
namespace {
@@ -36,8 +36,12 @@ class ContextTestBase : public content::ContentBrowserTest {
content::BrowserGpuChannelHostFactory::instance();
CHECK(factory);
bool lose_context_when_out_of_memory = false;
- scoped_refptr<content::GpuChannelHost> gpu_channel_host(
- factory->EstablishGpuChannelSync(kInitCause));
+ base::RunLoop run_loop;
+ factory->EstablishGpuChannel(kInitCause, run_loop.QuitClosure());
+ run_loop.Run();
+ scoped_refptr<content::GpuChannelHost>
+ gpu_channel_host(factory->GetGpuChannel());
+ DCHECK(gpu_channel_host.get());
context_.reset(
WebGraphicsContext3DCommandBufferImpl::CreateOffscreenContext(
gpu_channel_host.get(),
@@ -87,6 +91,12 @@ class BrowserGpuChannelHostFactoryTest : public ContentBrowserTest {
ContentBrowserTest::SetUpOnMainThread();
}
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ // Start all tests without a gpu channel so that the tests exercise a
+ // consistent codepath.
+ command_line->AppendSwitch(switches::kDisableGpuEarlyInit);
+ }
+
void OnContextLost(const base::Closure callback, int* counter) {
(*counter)++;
callback.Run();
@@ -129,16 +139,28 @@ class BrowserGpuChannelHostFactoryTest : public ContentBrowserTest {
}
};
-// Fails since UI Compositor establishes a GpuChannel.
-IN_PROC_BROWSER_TEST_F(BrowserGpuChannelHostFactoryTest, DISABLED_Basic) {
+// Test fails on Chromeos + Mac, flaky on Windows because UI Compositor
+// establishes a GPU channel.
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#define MAYBE_Basic Basic
+#else
+#define MAYBE_Basic DISABLED_Basic
+#endif
+IN_PROC_BROWSER_TEST_F(BrowserGpuChannelHostFactoryTest, MAYBE_Basic) {
DCHECK(!IsChannelEstablished());
EstablishAndWait();
EXPECT_TRUE(GetGpuChannel() != NULL);
}
-// Fails since UI Compositor establishes a GpuChannel.
+// Test fails on Chromeos + Mac, flaky on Windows because UI Compositor
+// establishes a GPU channel.
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#define MAYBE_EstablishAndTerminate EstablishAndTerminate
+#else
+#define MAYBE_EstablishAndTerminate DISABLED_EstablishAndTerminate
+#endif
IN_PROC_BROWSER_TEST_F(BrowserGpuChannelHostFactoryTest,
- DISABLED_EstablishAndTerminate) {
+ MAYBE_EstablishAndTerminate) {
DCHECK(!IsChannelEstablished());
base::RunLoop run_loop;
GetFactory()->EstablishGpuChannel(kInitCause, run_loop.QuitClosure());
@@ -148,9 +170,16 @@ IN_PROC_BROWSER_TEST_F(BrowserGpuChannelHostFactoryTest,
run_loop.Run();
}
-// Fails since UI Compositor establishes a GpuChannel.
+#if !defined(OS_ANDROID)
+// Test fails on Chromeos + Mac, flaky on Windows because UI Compositor
+// establishes a GPU channel.
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#define MAYBE_AlreadyEstablished AlreadyEstablished
+#else
+#define MAYBE_AlreadyEstablished DISABLED_AlreadyEstablished
+#endif
IN_PROC_BROWSER_TEST_F(BrowserGpuChannelHostFactoryTest,
- DISABLED_AlreadyEstablished) {
+ MAYBE_AlreadyEstablished) {
DCHECK(!IsChannelEstablished());
scoped_refptr<GpuChannelHost> gpu_channel =
GetFactory()->EstablishGpuChannelSync(kInitCause);
@@ -163,17 +192,24 @@ IN_PROC_BROWSER_TEST_F(BrowserGpuChannelHostFactoryTest,
EXPECT_TRUE(event);
EXPECT_EQ(gpu_channel.get(), GetGpuChannel());
}
-
-// Fails since UI Compositor establishes a GpuChannel.
+#endif
+
+// Test fails on Chromeos + Mac, flaky on Windows because UI Compositor
+// establishes a GPU channel.
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#define MAYBE_CrashAndRecover
+#else
+#define MAYBE_CrashAndRecover DISABLED_CrashAndRecover
+#endif
IN_PROC_BROWSER_TEST_F(BrowserGpuChannelHostFactoryTest,
- DISABLED_CrashAndRecover) {
+ MAYBE_CrashAndRecover) {
DCHECK(!IsChannelEstablished());
EstablishAndWait();
scoped_refptr<GpuChannelHost> host = GetGpuChannel();
scoped_refptr<ContextProviderCommandBuffer> provider =
ContextProviderCommandBuffer::Create(CreateContext(),
- "BrowserGpuChannelHostFactoryTest");
+ OFFSCREEN_CONTEXT_FOR_TESTING);
base::RunLoop run_loop;
int counter = 0;
provider->SetLostContextCallback(
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
deleted file mode 100644
index e57bd0c728c..00000000000
--- a/chromium/content/browser/gpu/gpu_memory_buffer_factory_host_impl.cc
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright (c) 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/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
deleted file mode 100644
index 6cdf6b726d5..00000000000
--- a/chromium/content/browser/gpu/gpu_memory_buffer_factory_host_impl.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright (c) 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#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 be7db476b0b..5ad53405fac 100644
--- a/chromium/content/browser/gpu/gpu_process_host.cc
+++ b/chromium/content/browser/gpu/gpu_process_host.cc
@@ -10,12 +10,12 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/command_line.h"
-#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/metrics/histogram.h"
#include "base/sha1.h"
#include "base/threading/thread.h"
+#include "base/trace_event/trace_event.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"
@@ -25,6 +25,7 @@
#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/in_process_child_thread_params.h"
#include "content/common/view_messages.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
@@ -44,6 +45,10 @@
#include "ui/events/latency_info.h"
#include "ui/gl/gl_switches.h"
+#if defined(OS_ANDROID)
+#include "base/android/build_info.h"
+#endif
+
#if defined(OS_WIN)
#include "base/win/windows_version.h"
#include "content/common/sandbox_win.h"
@@ -76,11 +81,11 @@ static const char* const kSwitchNames[] = {
switches::kDisableBreakpad,
switches::kDisableGpuSandbox,
switches::kDisableGpuWatchdog,
+ switches::kDisableGLExtensions,
switches::kDisableLogging,
switches::kDisableSeccompFilterSandbox,
#if defined(ENABLE_WEBRTC)
switches::kDisableWebRtcHWEncoding,
- switches::kEnableWebRtcHWVp8Encoding,
#endif
switches::kEnableLogging,
switches::kEnableShareGroupAsyncTextureUpload,
@@ -91,10 +96,11 @@ static const char* const kSwitchNames[] = {
switches::kGpuSandboxAllowSysVShm,
switches::kGpuSandboxFailuresFatal,
switches::kGpuSandboxStartEarly,
- switches::kIgnoreResolutionLimitsForAcceleratedVideoDecode,
switches::kLoggingLevel,
- switches::kLowEndDeviceMode,
+ switches::kEnableLowEndDeviceMode,
+ switches::kDisableLowEndDeviceMode,
switches::kNoSandbox,
+ switches::kProfilerTiming,
switches::kTestGLLib,
switches::kTraceStartup,
switches::kTraceToConsole,
@@ -156,7 +162,7 @@ class GpuSandboxedProcessLauncherDelegate
~GpuSandboxedProcessLauncherDelegate() override {}
#if defined(OS_WIN)
- virtual bool ShouldSandbox() override {
+ bool ShouldSandbox() override {
bool sandbox = !cmd_line_->HasSwitch(switches::kDisableGpuSandbox);
if(! sandbox) {
DVLOG(1) << "GPU sandbox is disabled";
@@ -164,8 +170,8 @@ class GpuSandboxedProcessLauncherDelegate
return sandbox;
}
- virtual void PreSandbox(bool* disable_default_policy,
- base::FilePath* exposed_dir) override {
+ void PreSandbox(bool* disable_default_policy,
+ base::FilePath* exposed_dir) override {
*disable_default_policy = true;
}
@@ -173,8 +179,7 @@ class GpuSandboxedProcessLauncherDelegate
// which is USER_RESTRICTED breaks both the DirectX backend and the OpenGL
// backend. Note that the GPU process is connected to the interactive
// desktop.
- virtual void PreSpawnTarget(sandbox::TargetPolicy* policy,
- bool* success) {
+ void PreSpawnTarget(sandbox::TargetPolicy* policy, bool* success) override {
if (base::win::GetVersion() > base::win::VERSION_XP) {
if (cmd_line_->GetSwitchValueASCII(switches::kUseGL) ==
gfx::kGLImplementationDesktopName) {
@@ -284,7 +289,7 @@ bool GpuProcessHost::ValidateHost(GpuProcessHost* host) {
// static
GpuProcessHost* GpuProcessHost::Get(GpuProcessKind kind,
CauseForGpuLaunch cause) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
// Don't grant further access to GPU if it is not allowed.
GpuDataManagerImpl* gpu_data_manager = GpuDataManagerImpl::GetInstance();
@@ -326,9 +331,10 @@ void GpuProcessHost::GetProcessHandles(
}
std::list<base::ProcessHandle> handles;
for (size_t i = 0; i < arraysize(g_gpu_process_hosts); ++i) {
+ // TODO(rvargas) crbug/417532: don't store ProcessHandles!.
GpuProcessHost* host = g_gpu_process_hosts[i];
if (host && ValidateHost(host))
- handles.push_back(host->process_->GetHandle());
+ handles.push_back(host->process_->GetProcess().Handle());
}
BrowserThread::PostTask(
BrowserThread::UI,
@@ -357,7 +363,7 @@ void GpuProcessHost::RegisterGpuMainThreadFactory(
// static
GpuProcessHost* GpuProcessHost::FromID(int host_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
for (int i = 0; i < GPU_PROCESS_KIND_COUNT; ++i) {
GpuProcessHost* host = g_gpu_process_hosts[i];
@@ -501,15 +507,11 @@ bool GpuProcessHost::Init() {
return false;
if (in_process_) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(g_gpu_main_thread_factory);
- base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
- command_line->AppendSwitch(switches::kDisableGpuWatchdog);
-
- GpuDataManagerImpl* gpu_data_manager = GpuDataManagerImpl::GetInstance();
- DCHECK(gpu_data_manager);
- gpu_data_manager->AppendGpuCommandLine(command_line);
-
- in_process_gpu_thread_.reset(g_gpu_main_thread_factory(channel_id));
+ in_process_gpu_thread_.reset(
+ g_gpu_main_thread_factory(InProcessChildThreadParams(
+ channel_id, base::MessageLoop::current()->task_runner())));
base::Thread::Options options;
#if defined(OS_WIN)
// WGL needs to create its own window and pump messages on it.
@@ -651,40 +653,46 @@ void GpuProcessHost::CreateViewCommandBuffer(
}
void GpuProcessHost::CreateGpuMemoryBuffer(
- gfx::GpuMemoryBufferType type,
gfx::GpuMemoryBufferId id,
const gfx::Size& size,
gfx::GpuMemoryBuffer::Format format,
gfx::GpuMemoryBuffer::Usage usage,
int client_id,
+ int32 surface_id,
const CreateGpuMemoryBufferCallback& callback) {
TRACE_EVENT0("gpu", "GpuProcessHost::CreateGpuMemoryBuffer");
DCHECK(CalledOnValidThread());
GpuMsg_CreateGpuMemoryBuffer_Params params;
- params.type = type;
params.id = id;
params.size = size;
params.format = format;
params.usage = usage;
params.client_id = client_id;
+ params.surface_handle =
+ GpuSurfaceTracker::GetInstance()->GetSurfaceHandle(surface_id).handle;
if (Send(new GpuMsg_CreateGpuMemoryBuffer(params))) {
create_gpu_memory_buffer_requests_.push(callback);
+ create_gpu_memory_buffer_surface_refs_.push(surface_id);
+ if (surface_id) {
+ surface_refs_.insert(std::make_pair(
+ surface_id, GpuSurfaceTracker::GetInstance()->GetSurfaceRefForSurface(
+ surface_id)));
+ }
} else {
callback.Run(gfx::GpuMemoryBufferHandle());
}
}
-void GpuProcessHost::DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferType type,
- gfx::GpuMemoryBufferId id,
+void GpuProcessHost::DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
int client_id,
int sync_point) {
TRACE_EVENT0("gpu", "GpuProcessHost::DestroyGpuMemoryBuffer");
DCHECK(CalledOnValidThread());
- Send(new GpuMsg_DestroyGpuMemoryBuffer(type, id, client_id, sync_point));
+ Send(new GpuMsg_DestroyGpuMemoryBuffer(id, client_id, sync_point));
}
void GpuProcessHost::OnInitialized(bool result, const gpu::GPUInfo& gpu_info) {
@@ -760,6 +768,13 @@ void GpuProcessHost::OnGpuMemoryBufferCreated(
create_gpu_memory_buffer_requests_.front();
create_gpu_memory_buffer_requests_.pop();
callback.Run(handle);
+
+ int32 surface_id = create_gpu_memory_buffer_surface_refs_.front();
+ create_gpu_memory_buffer_surface_refs_.pop();
+ SurfaceRefMap::iterator it = surface_refs_.find(surface_id);
+ if (it != surface_refs_.end()) {
+ surface_refs_.erase(it);
+ }
}
void GpuProcessHost::OnDidCreateOffscreenContext(const GURL& url) {
@@ -870,6 +885,13 @@ bool GpuProcessHost::LaunchGpuProcess(const std::string& channel_id) {
base::CommandLine::StringType gpu_launcher =
browser_command_line.GetSwitchValueNative(switches::kGpuLauncher);
+#if defined(OS_ANDROID)
+ // crbug.com/447735. readlink("self/proc/exe") sometimes fails on Android
+ // at startup with EACCES. As a workaround ignore this here, since the
+ // executable name is actually not used or useful anyways.
+ base::CommandLine* cmd_line =
+ new base::CommandLine(base::CommandLine::NO_PROGRAM);
+#else
#if defined(OS_LINUX)
int child_flags = gpu_launcher.empty() ? ChildProcessHost::CHILD_ALLOW_SELF :
ChildProcessHost::CHILD_NORMAL;
@@ -882,6 +904,7 @@ bool GpuProcessHost::LaunchGpuProcess(const std::string& channel_id) {
return false;
base::CommandLine* cmd_line = new base::CommandLine(exe_path);
+#endif
cmd_line->AppendSwitchASCII(switches::kProcessType, switches::kGpuProcess);
cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id);
@@ -918,7 +941,8 @@ bool GpuProcessHost::LaunchGpuProcess(const std::string& channel_id) {
process_->Launch(
new GpuSandboxedProcessLauncherDelegate(cmd_line,
process_->GetHost()),
- cmd_line);
+ cmd_line,
+ true);
process_launched_ = true;
UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessLifetimeEvents",
@@ -1030,6 +1054,9 @@ std::string GpuProcessHost::GetShaderPrefixKey() {
gpu::GPUInfo info = GpuDataManagerImpl::GetInstance()->GetGPUInfo();
std::string in_str = GetContentClient()->GetProduct() + "-" +
+#if defined(OS_ANDROID)
+ base::android::BuildInfo::GetInstance()->android_build_fp() + "-" +
+#endif
info.gl_vendor + "-" + info.gl_renderer + "-" +
info.driver_version + "-" + info.driver_vendor;
diff --git a/chromium/content/browser/gpu/gpu_process_host.h b/chromium/content/browser/gpu/gpu_process_host.h
index 2952d3869ef..b7d625bb9fe 100644
--- a/chromium/content/browser/gpu/gpu_process_host.h
+++ b/chromium/content/browser/gpu/gpu_process_host.h
@@ -26,9 +26,9 @@
#include "gpu/config/gpu_info.h"
#include "ipc/ipc_sender.h"
#include "ipc/message_filter.h"
+#include "ui/gfx/geometry/size.h"
#include "ui/gfx/gpu_memory_buffer.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/size.h"
#include "url/gurl.h"
struct GPUCreateCommandBufferConfig;
@@ -40,10 +40,12 @@ struct ChannelHandle;
namespace content {
class BrowserChildProcessHostImpl;
class GpuMainThread;
+class InProcessChildThreadParams;
class RenderWidgetHostViewFrameSubscriber;
class ShaderDiskCache;
-typedef base::Thread* (*GpuMainThreadFactoryFunction)(const std::string& id);
+typedef base::Thread* (*GpuMainThreadFactoryFunction)(
+ const InProcessChildThreadParams&);
class GpuProcessHost : public BrowserChildProcessHostDelegate,
public IPC::Sender,
@@ -119,17 +121,16 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate,
const CreateCommandBufferCallback& callback);
// Tells the GPU process to create a new GPU memory buffer.
- void CreateGpuMemoryBuffer(gfx::GpuMemoryBufferType type,
- gfx::GpuMemoryBufferId id,
+ void CreateGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
const gfx::Size& size,
gfx::GpuMemoryBuffer::Format format,
gfx::GpuMemoryBuffer::Usage usage,
int client_id,
+ int32 surface_id,
const CreateGpuMemoryBufferCallback& callback);
// Tells the GPU process to destroy GPU memory buffer.
- void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferType type,
- gfx::GpuMemoryBufferId id,
+ void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
int client_id,
int sync_point);
@@ -206,6 +207,9 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate,
// The pending create gpu memory buffer requests we need to reply to.
std::queue<CreateGpuMemoryBufferCallback> create_gpu_memory_buffer_requests_;
+ // Surface ids for pending gpu memory buffer request refs.
+ std::queue<int32> create_gpu_memory_buffer_surface_refs_;
+
// Qeueud messages to send when the process launches.
std::queue<IPC::Message*> queued_messages_;
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 8c4450628e7..1df45fc8396 100644
--- a/chromium/content/browser/gpu/gpu_process_host_ui_shim.cc
+++ b/chromium/content/browser/gpu/gpu_process_host_ui_shim.cc
@@ -7,10 +7,12 @@
#include <algorithm>
#include "base/bind.h"
-#include "base/debug/trace_event.h"
+#include "base/callback_helpers.h"
#include "base/id_map.h"
#include "base/lazy_instance.h"
#include "base/strings/string_number_conversions.h"
+#include "base/trace_event/trace_event.h"
+#include "content/browser/compositor/gpu_process_transport_factory.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"
@@ -23,7 +25,7 @@
#include "content/public/browser/browser_thread.h"
#if defined(OS_MACOSX)
-#include "content/browser/compositor/browser_compositor_ca_layer_tree_mac.h"
+#include "ui/accelerated_widget_mac/accelerated_widget_mac.h"
#endif
#if defined(USE_OZONE)
@@ -40,6 +42,13 @@ namespace {
#undef DestroyAll
#endif
+#if defined(OS_MACOSX)
+void OnSurfaceDisplayedCallback(int output_surface_id) {
+ content::ImageTransportFactory::GetInstance()->OnSurfaceDisplayed(
+ output_surface_id);
+}
+#endif
+
base::LazyInstance<IDMap<GpuProcessHostUIShim> > g_hosts_by_id =
LAZY_INSTANCE_INITIALIZER;
@@ -104,7 +113,10 @@ GpuProcessHostUIShim::GpuProcessHostUIShim(int host_id)
#if defined(USE_OZONE)
ui::OzonePlatform::GetInstance()
->GetGpuPlatformSupportHost()
- ->OnChannelEstablished(host_id, this);
+ ->OnChannelEstablished(
+ host_id,
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO),
+ base::Bind(&SendOnIOThreadTask, host_id_));
#endif
}
@@ -116,7 +128,7 @@ GpuProcessHostUIShim* GpuProcessHostUIShim::Create(int host_id) {
// static
void GpuProcessHostUIShim::Destroy(int host_id, const std::string& message) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
GpuDataManagerImpl::GetInstance()->AddLogMessage(
logging::LOG_ERROR, "GpuProcessHostUIShim",
@@ -133,7 +145,7 @@ void GpuProcessHostUIShim::Destroy(int host_id, const std::string& message) {
// static
void GpuProcessHostUIShim::DestroyAll() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
while (!g_hosts_by_id.Pointer()->IsEmpty()) {
IDMap<GpuProcessHostUIShim>::iterator it(g_hosts_by_id.Pointer());
delete it.GetCurrentValue();
@@ -142,13 +154,13 @@ void GpuProcessHostUIShim::DestroyAll() {
// static
GpuProcessHostUIShim* GpuProcessHostUIShim::FromID(int host_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
return g_hosts_by_id.Pointer()->Lookup(host_id);
}
// static
GpuProcessHostUIShim* GpuProcessHostUIShim::GetOneInstance() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (g_hosts_by_id.Pointer()->IsEmpty())
return NULL;
IDMap<GpuProcessHostUIShim>::iterator it(g_hosts_by_id.Pointer());
@@ -180,6 +192,13 @@ bool GpuProcessHostUIShim::OnMessageReceived(const IPC::Message& message) {
return OnControlMessageReceived(message);
}
+void GpuProcessHostUIShim::RelinquishGpuResources(
+ const base::Closure& callback) {
+ DCHECK(relinquish_callback_.is_null());
+ relinquish_callback_ = callback;
+ Send(new GpuMsg_RelinquishResources());
+}
+
void GpuProcessHostUIShim::SimulateRemoveAllContext() {
Send(new GpuMsg_Clean());
}
@@ -212,6 +231,10 @@ bool GpuProcessHostUIShim::OnControlMessageReceived(
OnGraphicsInfoCollected)
IPC_MESSAGE_HANDLER(GpuHostMsg_VideoMemoryUsageStats,
OnVideoMemoryUsageStatsReceived);
+ IPC_MESSAGE_HANDLER(GpuHostMsg_ResourcesRelinquished,
+ OnResourcesRelinquished)
+ IPC_MESSAGE_HANDLER(GpuHostMsg_AddSubscription, OnAddSubscription);
+ IPC_MESSAGE_HANDLER(GpuHostMsg_RemoveSubscription, OnRemoveSubscription);
IPC_MESSAGE_UNHANDLED_ERROR()
IPC_END_MESSAGE_MAP()
@@ -259,17 +282,25 @@ void GpuProcessHostUIShim::OnAcceleratedSurfaceBuffersSwapped(
// associated with a RenderWidgetHostViewBase.
AcceleratedSurfaceMsg_BufferPresented_Params ack_params;
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);
+
+ // If the frame was intended for an NSView that the gfx::AcceleratedWidget is
+ // no longer attached to, do not pass the frame along to the widget. Just ack
+ // it to the GPU process immediately, so we can proceed to the next frame.
+ bool should_not_show_frame =
+ content::ImageTransportFactory::GetInstance()
+ ->SurfaceShouldNotShowFramesAfterSuspendForRecycle(params.surface_id);
+ if (should_not_show_frame) {
+ OnSurfaceDisplayedCallback(params.surface_id);
+ } else {
+ gfx::AcceleratedWidget native_widget =
+ content::GpuSurfaceTracker::Get()->AcquireNativeWidget(
+ params.surface_id);
+ ui::AcceleratedWidgetMacGotAcceleratedFrame(
+ native_widget, params.surface_handle, params.latency_info, params.size,
+ params.scale_factor,
+ base::Bind(&OnSurfaceDisplayedCallback, params.surface_id),
+ &ack_params.disable_throttling, &ack_params.renderer_id);
+ }
Send(new AcceleratedSurfaceMsg_BufferPresented(params.route_id, ack_params));
#else
NOTREACHED();
@@ -282,4 +313,26 @@ void GpuProcessHostUIShim::OnVideoMemoryUsageStatsReceived(
video_memory_usage_stats);
}
+void GpuProcessHostUIShim::OnResourcesRelinquished() {
+ if (!relinquish_callback_.is_null()) {
+ base::ResetAndReturn(&relinquish_callback_).Run();
+ }
+}
+
+void GpuProcessHostUIShim::OnAddSubscription(
+ int32 process_id, unsigned int target) {
+ RenderProcessHost* rph = RenderProcessHost::FromID(process_id);
+ if (rph) {
+ rph->OnAddSubscription(target);
+ }
+}
+
+void GpuProcessHostUIShim::OnRemoveSubscription(
+ int32 process_id, unsigned int target) {
+ RenderProcessHost* rph = RenderProcessHost::FromID(process_id);
+ if (rph) {
+ rph->OnRemoveSubscription(target);
+ }
+}
+
} // namespace content
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 e47dc9049f7..ecd58d7cfba 100644
--- a/chromium/content/browser/gpu/gpu_process_host_ui_shim.h
+++ b/chromium/content/browser/gpu/gpu_process_host_ui_shim.h
@@ -12,7 +12,7 @@
#include <string>
-#include "base/callback_forward.h"
+#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/memory/linked_ptr.h"
#include "base/memory/ref_counted.h"
@@ -72,6 +72,7 @@ class GpuProcessHostUIShim : public IPC::Listener,
// actually received on the IO thread.
bool OnMessageReceived(const IPC::Message& message) override;
+ CONTENT_EXPORT void RelinquishGpuResources(const base::Closure& callback);
CONTENT_EXPORT void SimulateRemoveAllContext();
CONTENT_EXPORT void SimulateCrash();
CONTENT_EXPORT void SimulateHang();
@@ -93,9 +94,13 @@ class GpuProcessHostUIShim : public IPC::Listener,
const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params);
void OnVideoMemoryUsageStatsReceived(
const GPUVideoMemoryUsageStats& video_memory_usage_stats);
+ void OnResourcesRelinquished();
+ void OnAddSubscription(int32 process_id, unsigned int target);
+ void OnRemoveSubscription(int32 process_id, unsigned int target);
// The serial number of the GpuProcessHost / GpuProcessHostUIShim pair.
int host_id_;
+ base::Closure relinquish_callback_;
};
} // namespace content
diff --git a/chromium/content/browser/gpu/gpu_surface_tracker.h b/chromium/content/browser/gpu/gpu_surface_tracker.h
index 03d182fd14c..437a2f940d6 100644
--- a/chromium/content/browser/gpu/gpu_surface_tracker.h
+++ b/chromium/content/browser/gpu/gpu_surface_tracker.h
@@ -12,8 +12,8 @@
#include "base/memory/singleton.h"
#include "base/synchronization/lock.h"
#include "content/common/gpu/gpu_surface_lookup.h"
+#include "ui/gfx/geometry/size.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/size.h"
namespace content {
diff --git a/chromium/content/browser/gpu/shader_disk_cache.cc b/chromium/content/browser/gpu/shader_disk_cache.cc
index a50e3c38b98..6461f24039d 100644
--- a/chromium/content/browser/gpu/shader_disk_cache.cc
+++ b/chromium/content/browser/gpu/shader_disk_cache.cc
@@ -4,7 +4,6 @@
#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"
@@ -260,11 +259,6 @@ 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;
@@ -379,16 +373,16 @@ ShaderClearHelper::ShaderClearHelper(scoped_refptr<ShaderDiskCache> cache,
}
ShaderClearHelper::~ShaderClearHelper() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
}
void ShaderClearHelper::Clear() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
DoClearShaderCache(net::OK);
}
void ShaderClearHelper::DoClearShaderCache(int rv) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
// Hold a ref to ourselves so when we do the CacheCleared call we don't get
// auto-deleted when our ref count drops to zero.
@@ -473,7 +467,7 @@ void ShaderCacheFactory::ClearByPath(const base::FilePath& path,
const base::Time& delete_begin,
const base::Time& delete_end,
const base::Closure& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(!callback.is_null());
scoped_refptr<ShaderClearHelper> helper = new ShaderClearHelper(
@@ -497,7 +491,7 @@ void ShaderCacheFactory::ClearByPath(const base::FilePath& path,
}
void ShaderCacheFactory::CacheCleared(const base::FilePath& path) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
ShaderClearMap::iterator iter = shader_clear_map_.find(path);
if (iter == shader_clear_map_.end()) {
diff --git a/chromium/content/browser/histogram_controller.cc b/chromium/content/browser/histogram_controller.cc
index 3b11c32bf11..563a495619a 100644
--- a/chromium/content/browser/histogram_controller.cc
+++ b/chromium/content/browser/histogram_controller.cc
@@ -30,7 +30,7 @@ HistogramController::~HistogramController() {
void HistogramController::OnPendingProcesses(int sequence_number,
int pending_processes,
bool end) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (subscriber_)
subscriber_->OnPendingProcesses(sequence_number, pending_processes, end);
}
@@ -48,7 +48,7 @@ void HistogramController::OnHistogramDataCollected(
return;
}
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (subscriber_) {
subscriber_->OnHistogramDataCollected(sequence_number,
pickled_histograms);
@@ -56,7 +56,7 @@ void HistogramController::OnHistogramDataCollected(
}
void HistogramController::Register(HistogramSubscriber* subscriber) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(!subscriber_);
subscriber_ = subscriber;
}
@@ -69,7 +69,7 @@ void HistogramController::Unregister(
void HistogramController::GetHistogramDataFromChildProcesses(
int sequence_number) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
int pending_processes = 0;
for (BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) {
@@ -106,7 +106,7 @@ void HistogramController::GetHistogramDataFromChildProcesses(
}
void HistogramController::GetHistogramData(int sequence_number) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
int pending_processes = 0;
for (RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator());
diff --git a/chromium/content/browser/histogram_internals_request_job.cc b/chromium/content/browser/histogram_internals_request_job.cc
index e29dfca5e42..d8640dd1a70 100644
--- a/chromium/content/browser/histogram_internals_request_job.cc
+++ b/chromium/content/browser/histogram_internals_request_job.cc
@@ -6,7 +6,6 @@
#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"
@@ -60,11 +59,6 @@ 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_message_filter.cc b/chromium/content/browser/histogram_message_filter.cc
index 8eb7c7231ba..a93a309387a 100644
--- a/chromium/content/browser/histogram_message_filter.cc
+++ b/chromium/content/browser/histogram_message_filter.cc
@@ -41,7 +41,7 @@ void HistogramMessageFilter::OnChildHistogramData(
void HistogramMessageFilter::OnGetBrowserHistogram(
const std::string& name,
std::string* histogram_json) {
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
// Security: Only allow access to browser histograms when running in the
// context of a test.
bool using_stats_collection_controller =
diff --git a/chromium/content/browser/histogram_synchronizer.cc b/chromium/content/browser/histogram_synchronizer.cc
index 166172376cc..9b15b73b30f 100644
--- a/chromium/content/browser/histogram_synchronizer.cc
+++ b/chromium/content/browser/histogram_synchronizer.cc
@@ -50,18 +50,18 @@ class HistogramSynchronizer::RequestContext {
~RequestContext() {}
void SetReceivedProcessGroupCount(bool done) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
received_process_group_count_ = done;
}
// Methods for book keeping of processes_pending_.
void AddProcessesPending(int processes_pending) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
processes_pending_ += processes_pending;
}
void DecrementProcessesPending() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
--processes_pending_;
}
@@ -70,7 +70,7 @@ class HistogramSynchronizer::RequestContext {
// |processes_pending_| are zero, then delete the current object by calling
// Unregister.
void DeleteIfAllDone() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (processes_pending_ <= 0 && received_process_group_count_)
RequestContext::Unregister(sequence_number_);
@@ -79,7 +79,7 @@ class HistogramSynchronizer::RequestContext {
// Register |callback| in |outstanding_requests_| map for the given
// |sequence_number|.
static void Register(const base::Closure& callback, int sequence_number) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
RequestContext* request = new RequestContext(callback, sequence_number);
outstanding_requests_.Get()[sequence_number] = request;
@@ -88,7 +88,7 @@ class HistogramSynchronizer::RequestContext {
// Find the |RequestContext| in |outstanding_requests_| map for the given
// |sequence_number|.
static RequestContext* GetRequestContext(int sequence_number) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
RequestContextMap::iterator it =
outstanding_requests_.Get().find(sequence_number);
@@ -104,7 +104,7 @@ class HistogramSynchronizer::RequestContext {
// |outstanding_requests_| map. This method is called when all changes have
// been acquired, or when the wait time expires (whichever is sooner).
static void Unregister(int sequence_number) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
RequestContextMap::iterator it =
outstanding_requests_.Get().find(sequence_number);
@@ -190,7 +190,7 @@ void HistogramSynchronizer::FetchHistograms() {
base::Bind(&HistogramSynchronizer::FetchHistograms));
return;
}
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
HistogramSynchronizer* current_synchronizer =
HistogramSynchronizer::GetInstance();
@@ -229,7 +229,7 @@ void HistogramSynchronizer::FetchHistogramsAsynchronously(
void HistogramSynchronizer::RegisterAndNotifyAllProcesses(
ProcessHistogramRequester requester,
base::TimeDelta wait_time) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
int sequence_number = GetNextAvailableSequenceNumber(requester);
@@ -254,7 +254,7 @@ void HistogramSynchronizer::RegisterAndNotifyAllProcesses(
void HistogramSynchronizer::OnPendingProcesses(int sequence_number,
int pending_processes,
bool end) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
RequestContext* request = RequestContext::GetRequestContext(sequence_number);
if (!request)
@@ -267,7 +267,7 @@ void HistogramSynchronizer::OnPendingProcesses(int sequence_number,
void HistogramSynchronizer::OnHistogramDataCollected(
int sequence_number,
const std::vector<std::string>& pickled_histograms) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
base::HistogramDeltaSerialization::DeserializeAndAddSamples(
pickled_histograms);
diff --git a/chromium/content/browser/host_zoom_level_context.cc b/chromium/content/browser/host_zoom_level_context.cc
new file mode 100644
index 00000000000..02ddcf55d3c
--- /dev/null
+++ b/chromium/content/browser/host_zoom_level_context.cc
@@ -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.
+
+#include "content/browser/host_zoom_level_context.h"
+
+#include "base/files/file_path.h"
+#include "content/browser/host_zoom_map_impl.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace content {
+
+HostZoomLevelContext::HostZoomLevelContext(
+ scoped_ptr<ZoomLevelDelegate> zoom_level_delegate)
+ : host_zoom_map_impl_(new HostZoomMapImpl()),
+ zoom_level_delegate_(zoom_level_delegate.Pass()) {
+ if (zoom_level_delegate_)
+ zoom_level_delegate_->InitHostZoomMap(host_zoom_map_impl_.get());
+}
+
+HostZoomLevelContext::~HostZoomLevelContext() {}
+
+void HostZoomLevelContext::DeleteOnCorrectThread() const {
+ if (BrowserThread::IsMessageLoopValid(BrowserThread::UI) &&
+ !BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, this);
+ return;
+ }
+ delete this;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/host_zoom_level_context.h b/chromium/content/browser/host_zoom_level_context.h
new file mode 100644
index 00000000000..e45222f7f82
--- /dev/null
+++ b/chromium/content/browser/host_zoom_level_context.h
@@ -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.
+
+#ifndef CONTENT_BROWSER_HOST_ZOOM_LEVEL_CONTEXT_H_
+#define CONTENT_BROWSER_HOST_ZOOM_LEVEL_CONTEXT_H_
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/browser/host_zoom_map_impl.h"
+#include "content/public/browser/zoom_level_delegate.h"
+
+class PrefService;
+
+namespace content {
+struct HostZoomLevelContextDeleter;
+
+// This class manages a HostZoomMap and associates it with a ZoomLevelDelegate,
+// if one is provided. It also serves to keep the zoom level machinery details
+// separate from the owning StoragePartitionImpl.
+class HostZoomLevelContext
+ : public base::RefCountedThreadSafe<HostZoomLevelContext,
+ HostZoomLevelContextDeleter> {
+ public:
+ explicit HostZoomLevelContext(
+ scoped_ptr<ZoomLevelDelegate> zoom_level_delegate);
+
+ HostZoomMap* GetHostZoomMap() const { return host_zoom_map_impl_.get(); }
+ ZoomLevelDelegate* GetZoomLevelDelegate() const {
+ return zoom_level_delegate_.get();
+ }
+
+ protected:
+ virtual ~HostZoomLevelContext();
+
+ private:
+ friend class base::DeleteHelper<HostZoomLevelContext>;
+ friend class base::RefCountedThreadSafe<HostZoomLevelContext,
+ HostZoomLevelContextDeleter>;
+ friend struct HostZoomLevelContextDeleter;
+
+ void DeleteOnCorrectThread() const;
+
+ scoped_ptr<HostZoomMapImpl> host_zoom_map_impl_;
+ // Release the delegate before the HostZoomMap, in case it is carrying
+ // any HostZoomMap::Subscription pointers.
+ scoped_ptr<ZoomLevelDelegate> zoom_level_delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(HostZoomLevelContext);
+};
+
+struct HostZoomLevelContextDeleter {
+ static void Destruct(const HostZoomLevelContext* context) {
+ context->DeleteOnCorrectThread();
+ }
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_HOST_ZOOM_LEVEL_CONTEXT_H_
diff --git a/chromium/content/browser/host_zoom_map_impl.cc b/chromium/content/browser/host_zoom_map_impl.cc
index 81f8182924d..2c1c5ec3e8d 100644
--- a/chromium/content/browser/host_zoom_map_impl.cc
+++ b/chromium/content/browser/host_zoom_map_impl.cc
@@ -20,6 +20,8 @@
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/resource_context.h"
+#include "content/public/browser/site_instance.h"
+#include "content/public/browser/storage_partition.h"
#include "content/public/common/page_zoom.h"
#include "content/public/common/url_constants.h"
#include "net/base/net_util.h"
@@ -28,10 +30,8 @@ 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));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
RenderViewHost* render_view_host =
RenderViewHost::FromID(render_process_id, render_view_id);
if (!render_view_host)
@@ -61,29 +61,46 @@ GURL HostZoomMap::GetURLFromEntry(const NavigationEntry* entry) {
}
HostZoomMap* HostZoomMap::GetDefaultForBrowserContext(BrowserContext* context) {
- HostZoomMapImpl* rv = static_cast<HostZoomMapImpl*>(
- context->GetUserData(kHostZoomMapKeyName));
- if (!rv) {
- rv = new HostZoomMapImpl();
- context->SetUserData(kHostZoomMapKeyName, rv);
- }
- return rv;
+ StoragePartition* partition =
+ BrowserContext::GetDefaultStoragePartition(context);
+ DCHECK(partition);
+ return partition->GetHostZoomMap();
+}
+
+HostZoomMap* HostZoomMap::Get(SiteInstance* instance) {
+ StoragePartition* partition = BrowserContext::GetStoragePartition(
+ instance->GetBrowserContext(), instance);
+ DCHECK(partition);
+ return partition->GetHostZoomMap();
+}
+
+HostZoomMap* HostZoomMap::GetForWebContents(const WebContents* contents) {
+ StoragePartition* partition =
+ BrowserContext::GetStoragePartition(contents->GetBrowserContext(),
+ contents->GetSiteInstance());
+ DCHECK(partition);
+ return partition->GetHostZoomMap();
}
// 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::GetDefaultForBrowserContext(
- web_contents->GetBrowserContext()));
+ HostZoomMapImpl* host_zoom_map = static_cast<HostZoomMapImpl*>(
+ HostZoomMap::GetForWebContents(web_contents));
return host_zoom_map->GetZoomLevelForWebContents(
*static_cast<const WebContentsImpl*>(web_contents));
}
+bool HostZoomMap::PageScaleFactorIsOne(const WebContents* web_contents) {
+ HostZoomMapImpl* host_zoom_map = static_cast<HostZoomMapImpl*>(
+ HostZoomMap::GetForWebContents(web_contents));
+ return host_zoom_map->PageScaleFactorIsOneForWebContents(
+ *static_cast<const WebContentsImpl*>(web_contents));
+}
+
void HostZoomMap::SetZoomLevel(const WebContents* web_contents, double level) {
- HostZoomMapImpl* host_zoom_map =
- static_cast<HostZoomMapImpl*>(HostZoomMap::GetDefaultForBrowserContext(
- web_contents->GetBrowserContext()));
+ HostZoomMapImpl* host_zoom_map = static_cast<HostZoomMapImpl*>(
+ HostZoomMap::GetForWebContents(web_contents));
host_zoom_map->SetZoomLevelForWebContents(
*static_cast<const WebContentsImpl*>(web_contents), level);
}
@@ -108,7 +125,7 @@ void HostZoomMapImpl::CopyFrom(HostZoomMap* copy_interface) {
// UI: a.CopyFrom(b);
// IO: b.CopyFrom(a);
// can deadlock.
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
HostZoomMapImpl* copy = static_cast<HostZoomMapImpl*>(copy_interface);
base::AutoLock auto_lock(lock_);
base::AutoLock copy_auto_lock(copy->lock_);
@@ -126,6 +143,11 @@ void HostZoomMapImpl::CopyFrom(HostZoomMap* copy_interface) {
double HostZoomMapImpl::GetZoomLevelForHost(const std::string& host) const {
base::AutoLock auto_lock(lock_);
+ return GetZoomLevelForHostInternal(host);
+}
+
+double HostZoomMapImpl::GetZoomLevelForHostInternal(
+ const std::string& host) const {
HostZoomLevels::const_iterator i(host_zoom_levels_.find(host));
return (i == host_zoom_levels_.end()) ? default_zoom_level_ : i->second;
}
@@ -146,20 +168,25 @@ bool HostZoomMapImpl::HasZoomLevel(const std::string& scheme,
return i != zoom_levels.end();
}
-double HostZoomMapImpl::GetZoomLevelForHostAndScheme(
+double HostZoomMapImpl::GetZoomLevelForHostAndSchemeInternal(
const std::string& scheme,
const std::string& host) const {
- {
- base::AutoLock auto_lock(lock_);
- SchemeHostZoomLevels::const_iterator scheme_iterator(
- scheme_host_zoom_levels_.find(scheme));
- if (scheme_iterator != scheme_host_zoom_levels_.end()) {
- HostZoomLevels::const_iterator i(scheme_iterator->second.find(host));
- if (i != scheme_iterator->second.end())
- return i->second;
- }
+ SchemeHostZoomLevels::const_iterator scheme_iterator(
+ scheme_host_zoom_levels_.find(scheme));
+ if (scheme_iterator != scheme_host_zoom_levels_.end()) {
+ HostZoomLevels::const_iterator i(scheme_iterator->second.find(host));
+ if (i != scheme_iterator->second.end())
+ return i->second;
}
- return GetZoomLevelForHost(host);
+
+ return GetZoomLevelForHostInternal(host);
+}
+
+double HostZoomMapImpl::GetZoomLevelForHostAndScheme(
+ const std::string& scheme,
+ const std::string& host) const {
+ base::AutoLock auto_lock(lock_);
+ return GetZoomLevelForHostAndSchemeInternal(scheme, host);
}
HostZoomMap::ZoomLevelVector HostZoomMapImpl::GetAllZoomLevels() const {
@@ -200,7 +227,7 @@ HostZoomMap::ZoomLevelVector HostZoomMapImpl::GetAllZoomLevels() const {
void HostZoomMapImpl::SetZoomLevelForHost(const std::string& host,
double level) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
{
base::AutoLock auto_lock(lock_);
@@ -225,7 +252,7 @@ void HostZoomMapImpl::SetZoomLevelForHost(const std::string& host,
void HostZoomMapImpl::SetZoomLevelForHostAndScheme(const std::string& scheme,
const std::string& host,
double level) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
{
base::AutoLock auto_lock(lock_);
scheme_host_zoom_levels_[scheme][host] = level;
@@ -243,10 +270,12 @@ void HostZoomMapImpl::SetZoomLevelForHostAndScheme(const std::string& scheme,
}
double HostZoomMapImpl::GetDefaultZoomLevel() const {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
return default_zoom_level_;
}
void HostZoomMapImpl::SetDefaultZoomLevel(double level) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
default_zoom_level_ = level;
}
@@ -312,6 +341,39 @@ void HostZoomMapImpl::SetZoomLevelForView(int render_process_id,
SetZoomLevelForHost(host, level);
}
+void HostZoomMapImpl::SetPageScaleFactorIsOneForView(int render_process_id,
+ int render_view_id,
+ bool is_one) {
+ {
+ base::AutoLock auto_lock(lock_);
+ view_page_scale_factors_are_one_[RenderViewKey(render_process_id,
+ render_view_id)] = is_one;
+ }
+ HostZoomMap::ZoomLevelChange change;
+ change.mode = HostZoomMap::PAGE_SCALE_IS_ONE_CHANGED;
+ zoom_level_changed_callbacks_.Notify(change);
+}
+
+bool HostZoomMapImpl::PageScaleFactorIsOneForWebContents(
+ const WebContentsImpl& web_contents_impl) const {
+ if (!web_contents_impl.GetRenderProcessHost())
+ return true;
+ base::AutoLock auto_lock(lock_);
+ auto found = view_page_scale_factors_are_one_.find(
+ RenderViewKey(web_contents_impl.GetRenderProcessHost()->GetID(),
+ web_contents_impl.GetRoutingID()));
+ if (found == view_page_scale_factors_are_one_.end())
+ return true;
+ return found->second;
+}
+
+void HostZoomMapImpl::ClearPageScaleFactorIsOneForView(int render_process_id,
+ int render_view_id) {
+ base::AutoLock auto_lock(lock_);
+ view_page_scale_factors_are_one_.erase(
+ RenderViewKey(render_process_id, render_view_id));
+}
+
bool HostZoomMapImpl::UsesTemporaryZoomLevel(int render_process_id,
int render_view_id) const {
RenderViewKey key(render_process_id, render_view_id);
@@ -333,7 +395,7 @@ double HostZoomMapImpl::GetTemporaryZoomLevel(int render_process_id,
void HostZoomMapImpl::SetTemporaryZoomLevel(int render_process_id,
int render_view_id,
double level) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
{
RenderViewKey key(render_process_id, render_view_id);
@@ -353,6 +415,19 @@ void HostZoomMapImpl::SetTemporaryZoomLevel(int render_process_id,
zoom_level_changed_callbacks_.Notify(change);
}
+double HostZoomMapImpl::GetZoomLevelForView(const GURL& url,
+ int render_process_id,
+ int render_view_id) const {
+ RenderViewKey key(render_process_id, render_view_id);
+ base::AutoLock auto_lock(lock_);
+
+ if (ContainsKey(temporary_zoom_levels_, key))
+ return temporary_zoom_levels_.find(key)->second;
+
+ return GetZoomLevelForHostAndSchemeInternal(url.scheme(),
+ net::GetHostOrSpecFromURL(url));
+}
+
void HostZoomMapImpl::Observe(int type,
const NotificationSource& source,
const NotificationDetails& details) {
@@ -362,6 +437,7 @@ void HostZoomMapImpl::Observe(int type,
int render_process_id =
Source<RenderViewHost>(source)->GetProcess()->GetID();
ClearTemporaryZoomLevel(render_process_id, render_view_id);
+ ClearPageScaleFactorIsOneForView(render_process_id, render_view_id);
break;
}
default:
@@ -396,8 +472,10 @@ 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::GetDefaultForBrowserContext(
- render_process_host->GetBrowserContext()) == this) {
+ // TODO(wjmaclean) This will need to be cleaned up when
+ // RenderProcessHost::GetStoragePartition() goes away. Perhaps have
+ // RenderProcessHost expose a GetHostZoomMap() function?
+ if (render_process_host->GetStoragePartition()->GetHostZoomMap() == this) {
render_process_host->Send(
new ViewMsg_SetZoomLevelForCurrentURL(scheme, host, level));
}
@@ -413,6 +491,7 @@ void HostZoomMapImpl::SendErrorPageZoomLevelRefresh() {
}
HostZoomMapImpl::~HostZoomMapImpl() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
}
} // namespace content
diff --git a/chromium/content/browser/host_zoom_map_impl.h b/chromium/content/browser/host_zoom_map_impl.h
index 78d643d750a..a9b2a45d3ef 100644
--- a/chromium/content/browser/host_zoom_map_impl.h
+++ b/chromium/content/browser/host_zoom_map_impl.h
@@ -11,7 +11,6 @@
#include "base/compiler_specific.h"
#include "base/sequenced_task_runner_helpers.h"
-#include "base/supports_user_data.h"
#include "base/synchronization/lock.h"
#include "content/public/browser/host_zoom_map.h"
#include "content/public/browser/notification_observer.h"
@@ -24,13 +23,16 @@ class WebContentsImpl;
// HostZoomMap needs to be deleted on the UI thread because it listens
// to notifications on there (and holds a NotificationRegistrar).
class CONTENT_EXPORT HostZoomMapImpl : public NON_EXPORTED_BASE(HostZoomMap),
- public NotificationObserver,
- public base::SupportsUserData::Data {
+ public NotificationObserver {
public:
HostZoomMapImpl();
~HostZoomMapImpl() override;
// HostZoomMap implementation:
+ void SetPageScaleFactorIsOneForView(
+ int render_process_id, int render_view_id, bool is_one) override;
+ void ClearPageScaleFactorIsOneForView(
+ int render_process_id, int render_view_id) override;
void CopyFrom(HostZoomMap* copy) override;
double GetZoomLevelForHostAndScheme(const std::string& scheme,
const std::string& host) const override;
@@ -60,6 +62,9 @@ class CONTENT_EXPORT HostZoomMapImpl : public NON_EXPORTED_BASE(HostZoomMap),
double GetZoomLevelForWebContents(
const WebContentsImpl& web_contents_impl) const;
+ bool PageScaleFactorIsOneForWebContents(
+ const WebContentsImpl& web_contents_impl) const;
+
// Sets the zoom level for this WebContents. If this WebContents is using
// a temporary zoom level, then level is only applied to this WebContents.
// Otherwise, the level will be applied on a host level.
@@ -81,6 +86,14 @@ class CONTENT_EXPORT HostZoomMapImpl : public NON_EXPORTED_BASE(HostZoomMap),
double GetTemporaryZoomLevel(int render_process_id,
int render_view_id) const;
+ // Returns the zoom level regardless of whether it's temporary, host-keyed or
+ // scheme+host-keyed.
+ //
+ // This may be called on any thread.
+ double GetZoomLevelForView(const GURL& url,
+ int render_process_id,
+ int render_view_id) const;
+
// NotificationObserver implementation.
void Observe(int type,
const NotificationSource& source,
@@ -106,9 +119,16 @@ class CONTENT_EXPORT HostZoomMapImpl : public NON_EXPORTED_BASE(HostZoomMap),
};
typedef std::map<RenderViewKey, double> TemporaryZoomLevels;
+ typedef std::map<RenderViewKey, bool> ViewPageScaleFactorsAreOne;
double GetZoomLevelForHost(const std::string& host) const;
+ // Non-locked versions for internal use. These should only be called within
+ // a scope where a lock has been acquired.
+ double GetZoomLevelForHostInternal(const std::string& host) const;
+ double GetZoomLevelForHostAndSchemeInternal(const std::string& scheme,
+ const std::string& host) const;
+
// Notifies the renderers from this browser context to change the zoom level
// for the specified host and scheme.
// TODO(wjmaclean) Should we use a GURL here? crbug.com/384486
@@ -125,12 +145,16 @@ class CONTENT_EXPORT HostZoomMapImpl : public NON_EXPORTED_BASE(HostZoomMap),
SchemeHostZoomLevels scheme_host_zoom_levels_;
double default_zoom_level_;
+ // Page scale factor data for each renderer.
+ ViewPageScaleFactorsAreOne view_page_scale_factors_are_one_;
+
// Don't expect more than a couple of tabs that are using a temporary zoom
// level, so vector is fine for now.
TemporaryZoomLevels temporary_zoom_levels_;
- // Used around accesses to |host_zoom_levels_|, |default_zoom_level_| and
- // |temporary_zoom_levels_| to guarantee thread safety.
+ // Used around accesses to |host_zoom_levels_|, |default_zoom_level_|,
+ // |temporary_zoom_levels_|, and |view_page_scale_factors_are_one_| to
+ // guarantee thread safety.
mutable base::Lock lock_;
NotificationRegistrar registrar_;
diff --git a/chromium/content/browser/host_zoom_map_impl_browsertest.cc b/chromium/content/browser/host_zoom_map_impl_browsertest.cc
new file mode 100644
index 00000000000..fbfdc3c62e5
--- /dev/null
+++ b/chromium/content/browser/host_zoom_map_impl_browsertest.cc
@@ -0,0 +1,86 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/host_zoom_map_impl.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/test/content_browser_test.h"
+#include "content/shell/browser/shell.h"
+#include "url/gurl.h"
+
+namespace content {
+
+class HostZoomMapImplBrowserTest : public ContentBrowserTest {
+};
+
+void RunTestForURL(const GURL& url,
+ Shell* shell,
+ double host_zoom_level,
+ double temp_zoom_level) {
+ shell->LoadURL(url);
+ WebContents* web_contents = shell->web_contents();
+
+ HostZoomMapImpl* host_zoom_map = static_cast<HostZoomMapImpl*>(
+ HostZoomMap::GetForWebContents(web_contents));
+
+ int view_id = web_contents->GetRoutingID();
+ int render_process_id = web_contents->GetRenderProcessHost()->GetID();
+
+ // Assume caller has set the zoom level to |host_zoom_level| using
+ // either a host or host+scheme entry in the HostZoomMap prior to
+ // calling this function.
+ EXPECT_DOUBLE_EQ(host_zoom_level, host_zoom_map->GetZoomLevelForView(
+ url, render_process_id, view_id));
+
+ // Make sure that GetZoomLevelForView() works for temporary zoom levels.
+ host_zoom_map->SetTemporaryZoomLevel(render_process_id, view_id,
+ temp_zoom_level);
+ EXPECT_DOUBLE_EQ(temp_zoom_level, host_zoom_map->GetZoomLevelForView(
+ url, render_process_id, view_id));
+ // Clear the temporary zoom level in case subsequent test calls use the same
+ // web_contents.
+ host_zoom_map->ClearTemporaryZoomLevel(render_process_id, view_id);
+}
+
+// Test to make sure that GetZoomForView() works properly for zoom levels
+// stored by host value, and can distinguish temporary zoom levels from
+// these.
+IN_PROC_BROWSER_TEST_F(HostZoomMapImplBrowserTest, GetZoomForView_Host) {
+ GURL url("http://abc.com");
+
+ HostZoomMap* host_zoom_map =
+ HostZoomMap::GetForWebContents(shell()->web_contents());
+
+ double default_zoom_level = host_zoom_map->GetDefaultZoomLevel();
+ double host_zoom_level = default_zoom_level + 1.0;
+ double temp_zoom_level = default_zoom_level + 2.0;
+
+ host_zoom_map->SetZoomLevelForHost(url.host(), host_zoom_level);
+
+ RunTestForURL(url, shell(), host_zoom_level, temp_zoom_level);
+}
+
+// Test to make sure that GetZoomForView() works properly for zoom levels
+// stored by host and scheme values, and can distinguish temporary zoom levels
+// from these.
+IN_PROC_BROWSER_TEST_F(HostZoomMapImplBrowserTest,
+ GetZoomForView_HostAndScheme) {
+ GURL url("http://abc.com");
+
+ HostZoomMap* host_zoom_map =
+ HostZoomMap::GetForWebContents(shell()->web_contents());
+
+ double default_zoom_level = host_zoom_map->GetDefaultZoomLevel();
+ double host_zoom_level = default_zoom_level + 1.0;
+ double temp_zoom_level = default_zoom_level + 2.0;
+
+ host_zoom_map->SetZoomLevelForHostAndScheme(url.scheme(), url.host(),
+ host_zoom_level);
+
+ RunTestForURL(url, shell(), host_zoom_level, temp_zoom_level);
+}
+
+} // namespace content
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 b0ebe27fd7c..8f78f191b69 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 "storage/common/blob/shareable_file_reference.h"
+#include "storage/browser/blob/shareable_file_reference.h"
namespace content {
diff --git a/chromium/content/browser/indexed_db/indexed_db_backing_store.cc b/chromium/content/browser/indexed_db/indexed_db_backing_store.cc
index 781eadcdab8..79ab192c68e 100644
--- a/chromium/content/browser/indexed_db/indexed_db_backing_store.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_backing_store.cc
@@ -4,6 +4,8 @@
#include "content/browser/indexed_db/indexed_db_backing_store.h"
+#include <algorithm>
+
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/format_macros.h"
@@ -37,43 +39,45 @@
#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 "storage/common/fileapi/file_system_mount_option.h"
+#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBTypes.h"
#include "third_party/WebKit/public/web/WebSerializedScriptValueVersion.h"
#include "third_party/leveldatabase/env_chromium.h"
using base::FilePath;
using base::StringPiece;
+using std::string;
using storage::FileWriterDelegate;
namespace content {
namespace {
-FilePath GetBlobDirectoryName(const FilePath& pathBase, int64 database_id) {
- return pathBase.AppendASCII(base::StringPrintf("%" PRIx64, database_id));
+FilePath GetBlobDirectoryName(const FilePath& path_base, int64 database_id) {
+ return path_base.AppendASCII(base::StringPrintf("%" PRIx64, database_id));
}
-FilePath GetBlobDirectoryNameForKey(const FilePath& pathBase,
+FilePath GetBlobDirectoryNameForKey(const FilePath& path_base,
int64 database_id,
int64 key) {
- FilePath path = GetBlobDirectoryName(pathBase, database_id);
+ FilePath path = GetBlobDirectoryName(path_base, database_id);
path = path.AppendASCII(base::StringPrintf(
"%02x", static_cast<int>(key & 0x000000000000ff00) >> 8));
return path;
}
-FilePath GetBlobFileNameForKey(const FilePath& pathBase,
+FilePath GetBlobFileNameForKey(const FilePath& path_base,
int64 database_id,
int64 key) {
- FilePath path = GetBlobDirectoryNameForKey(pathBase, database_id, key);
+ FilePath path = GetBlobDirectoryNameForKey(path_base, database_id, key);
path = path.AppendASCII(base::StringPrintf("%" PRIx64, key));
return path;
}
-bool MakeIDBBlobDirectory(const FilePath& pathBase,
+bool MakeIDBBlobDirectory(const FilePath& path_base,
int64 database_id,
int64 key) {
- FilePath path = GetBlobDirectoryNameForKey(pathBase, database_id, key);
+ FilePath path = GetBlobDirectoryNameForKey(path_base, database_id, key);
return base::CreateDirectory(path);
}
@@ -554,19 +558,22 @@ static bool UpdateBlobKeyGeneratorCurrentNumber(
// though that may be costly. Still, database/directory deletion should always
// clean things up, and we can write an fsck that will do a full correction if
// need be.
-template <typename T>
-static leveldb::Status GetBlobJournal(const StringPiece& leveldb_key,
- T* leveldb_transaction,
+
+// Read and decode the specified blob journal via the supplied transaction.
+// The key must be either the primary journal key or live journal key.
+template <typename TransactionType>
+static leveldb::Status GetBlobJournal(const StringPiece& key,
+ TransactionType* transaction,
BlobJournalType* journal) {
std::string data;
bool found = false;
- leveldb::Status s = leveldb_transaction->Get(leveldb_key, &data, &found);
+ leveldb::Status s = transaction->Get(key, &data, &found);
if (!s.ok()) {
INTERNAL_READ_ERROR(READ_BLOB_JOURNAL);
return s;
}
journal->clear();
- if (!found || !data.size())
+ if (!found || data.empty())
return leveldb::Status::OK();
StringPiece slice(data);
if (!DecodeBlobJournal(&slice, journal)) {
@@ -576,72 +583,113 @@ static leveldb::Status GetBlobJournal(const StringPiece& leveldb_key,
return s;
}
-static void ClearBlobJournal(LevelDBTransaction* leveldb_transaction,
- const std::string& level_db_key) {
- leveldb_transaction->Remove(level_db_key);
+template <typename TransactionType>
+static leveldb::Status GetPrimaryBlobJournal(TransactionType* transaction,
+ BlobJournalType* journal) {
+ return GetBlobJournal(BlobJournalKey::Encode(), transaction, journal);
}
-static void UpdatePrimaryJournalWithBlobList(
- LevelDBTransaction* leveldb_transaction,
- const BlobJournalType& journal) {
- const std::string leveldb_key = BlobJournalKey::Encode();
- std::string data;
- EncodeBlobJournal(journal, &data);
- leveldb_transaction->Put(leveldb_key, &data);
+template <typename TransactionType>
+static leveldb::Status GetLiveBlobJournal(TransactionType* transaction,
+ BlobJournalType* journal) {
+ return GetBlobJournal(LiveBlobJournalKey::Encode(), transaction, journal);
}
-static void UpdateLiveBlobJournalWithBlobList(
- LevelDBTransaction* leveldb_transaction,
- const BlobJournalType& journal) {
- const std::string leveldb_key = LiveBlobJournalKey::Encode();
+// Clear the specified blob journal via the supplied transaction.
+// The key must be either the primary journal key or live journal key.
+template <typename TransactionType>
+static void ClearBlobJournal(TransactionType* transaction,
+ const std::string& key) {
+ transaction->Remove(key);
+}
+
+// Overwrite the specified blob journal via the supplied transaction.
+// The key must be either the primary journal key or live journal key.
+template <typename TransactionType>
+static void UpdateBlobJournal(TransactionType* transaction,
+ const std::string& key,
+ const BlobJournalType& journal) {
std::string data;
EncodeBlobJournal(journal, &data);
- leveldb_transaction->Put(leveldb_key, &data);
+ transaction->Put(key, &data);
}
-static leveldb::Status MergeBlobsIntoLiveBlobJournal(
- LevelDBTransaction* leveldb_transaction,
+template <typename TransactionType>
+static void UpdatePrimaryBlobJournal(TransactionType* transaction,
+ const BlobJournalType& journal) {
+ UpdateBlobJournal(transaction, BlobJournalKey::Encode(), journal);
+}
+
+template <typename TransactionType>
+static void UpdateLiveBlobJournal(TransactionType* transaction,
+ const BlobJournalType& journal) {
+ UpdateBlobJournal(transaction, LiveBlobJournalKey::Encode(), journal);
+}
+
+// Append blobs to the specified blob journal via the supplied transaction.
+// The key must be either the primary journal key or live journal key.
+template <typename TransactionType>
+static leveldb::Status AppendBlobsToBlobJournal(
+ TransactionType* transaction,
+ const std::string& key,
const BlobJournalType& journal) {
+ if (journal.empty())
+ return leveldb::Status::OK();
BlobJournalType old_journal;
- const std::string key = LiveBlobJournalKey::Encode();
- leveldb::Status s = GetBlobJournal(key, leveldb_transaction, &old_journal);
+ leveldb::Status s = GetBlobJournal(key, transaction, &old_journal);
if (!s.ok())
return s;
-
old_journal.insert(old_journal.end(), journal.begin(), journal.end());
-
- UpdateLiveBlobJournalWithBlobList(leveldb_transaction, old_journal);
+ UpdateBlobJournal(transaction, key, old_journal);
return leveldb::Status::OK();
}
-static void UpdateBlobJournalWithDatabase(
- LevelDBDirectTransaction* leveldb_transaction,
- int64 database_id) {
- BlobJournalType journal;
- journal.push_back(
- std::make_pair(database_id, DatabaseMetaDataKey::kAllBlobsKey));
- const std::string key = BlobJournalKey::Encode();
- std::string data;
- EncodeBlobJournal(journal, &data);
- leveldb_transaction->Put(key, &data);
+template <typename TransactionType>
+static leveldb::Status AppendBlobsToPrimaryBlobJournal(
+ TransactionType* transaction,
+ const BlobJournalType& journal) {
+ return AppendBlobsToBlobJournal(transaction, BlobJournalKey::Encode(),
+ journal);
}
-static leveldb::Status MergeDatabaseIntoLiveBlobJournal(
- LevelDBDirectTransaction* leveldb_transaction,
+template <typename TransactionType>
+static leveldb::Status AppendBlobsToLiveBlobJournal(
+ TransactionType* transaction,
+ const BlobJournalType& journal) {
+ return AppendBlobsToBlobJournal(transaction, LiveBlobJournalKey::Encode(),
+ journal);
+}
+
+// Append a database to the specified blob journal via the supplied transaction.
+// The key must be either the primary journal key or live journal key.
+static leveldb::Status MergeDatabaseIntoBlobJournal(
+ LevelDBDirectTransaction* transaction,
+ const std::string& key,
int64 database_id) {
BlobJournalType journal;
- const std::string key = LiveBlobJournalKey::Encode();
- leveldb::Status s = GetBlobJournal(key, leveldb_transaction, &journal);
+ leveldb::Status s = GetBlobJournal(key, transaction, &journal);
if (!s.ok())
return s;
journal.push_back(
std::make_pair(database_id, DatabaseMetaDataKey::kAllBlobsKey));
- std::string data;
- EncodeBlobJournal(journal, &data);
- leveldb_transaction->Put(key, &data);
+ UpdateBlobJournal(transaction, key, journal);
return leveldb::Status::OK();
}
+static leveldb::Status MergeDatabaseIntoPrimaryBlobJournal(
+ LevelDBDirectTransaction* leveldb_transaction,
+ int64 database_id) {
+ return MergeDatabaseIntoBlobJournal(leveldb_transaction,
+ BlobJournalKey::Encode(), database_id);
+}
+
+static leveldb::Status MergeDatabaseIntoLiveBlobJournal(
+ LevelDBDirectTransaction* leveldb_transaction,
+ int64 database_id) {
+ return MergeDatabaseIntoBlobJournal(
+ leveldb_transaction, LiveBlobJournalKey::Encode(), database_id);
+}
+
// Blob Data is encoded as a series of:
// { is_file [bool], key [int64 as varInt],
// type [string-with-length, may be empty],
@@ -714,7 +762,8 @@ IndexedDBBackingStore::IndexedDBBackingStore(
task_runner_(task_runner),
db_(db.Pass()),
comparator_(comparator.Pass()),
- active_blob_registry_(this) {
+ active_blob_registry_(this),
+ committing_transaction_count_(0) {
}
IndexedDBBackingStore::~IndexedDBBackingStore() {
@@ -744,6 +793,7 @@ IndexedDBBackingStore::RecordIdentifier::~RecordIdentifier() {}
IndexedDBBackingStore::Cursor::CursorOptions::CursorOptions() {}
IndexedDBBackingStore::Cursor::CursorOptions::~CursorOptions() {}
+// Values match entries in tools/metrics/histograms/histograms.xml
enum IndexedDBBackingStoreOpenResult {
INDEXED_DB_BACKING_STORE_OPEN_MEMORY_SUCCESS,
INDEXED_DB_BACKING_STORE_OPEN_SUCCESS,
@@ -753,7 +803,7 @@ enum IndexedDBBackingStoreOpenResult {
INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_REOPEN_FAILED,
INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_REOPEN_SUCCESS,
INDEXED_DB_BACKING_STORE_OPEN_FAILED_IO_ERROR_CHECKING_SCHEMA,
- INDEXED_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_ERR,
+ INDEXED_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_ERR_DEPRECATED,
INDEXED_DB_BACKING_STORE_OPEN_MEMORY_FAILED,
INDEXED_DB_BACKING_STORE_OPEN_ATTEMPT_NON_ASCII,
INDEXED_DB_BACKING_STORE_OPEN_DISK_FULL_DEPRECATED,
@@ -975,7 +1025,7 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open(
if (!status->ok()) {
if (leveldb_env::IndicatesDiskFull(*status)) {
*is_disk_full = true;
- } else if (leveldb_env::IsCorruption(*status)) {
+ } else if (status->IsCorruption()) {
*data_loss = blink::WebIDBDataLossTotal;
*data_loss_message = leveldb_env::GetCorruptionMessage(*status);
}
@@ -1013,18 +1063,18 @@ 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 || status->IsIOError() ||
+ status->IsCorruption());
if (db) {
HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_SUCCESS, origin_url);
- } else if (leveldb_env::IsIOError(*status)) {
+ } else if (status->IsIOError()) {
LOG(ERROR) << "Unable to open backing store, not trying to recover - "
<< 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 || status->IsCorruption());
LOG(ERROR) << "IndexedDB backing store open failed, attempting cleanup";
*status = leveldb_factory->DestroyLevelDB(file_path);
if (!status->ok()) {
@@ -1046,13 +1096,6 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open(
origin_url);
}
- if (!db) {
- NOTREACHED();
- HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_ERR,
- origin_url);
- return scoped_refptr<IndexedDBBackingStore>();
- }
-
scoped_refptr<IndexedDBBackingStore> backing_store =
Create(indexed_db_factory,
origin_url,
@@ -1171,8 +1214,8 @@ std::vector<base::string16> IndexedDBBackingStore::GetDatabaseNames(
// Decode database id (in iterator value).
int64 database_id = 0;
- StringPiece valueSlice(it->Value());
- if (!DecodeInt(&valueSlice, &database_id) || !valueSlice.empty()) {
+ StringPiece value_slice(it->Value());
+ if (!DecodeInt(&value_slice, &database_id) || !value_slice.empty()) {
INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_DATABASE_NAMES);
continue;
}
@@ -1418,9 +1461,6 @@ leveldb::Status IndexedDBBackingStore::DeleteDatabase(
LevelDBDirectTransaction::Create(db_.get());
leveldb::Status s;
- s = CleanUpBlobJournal(BlobJournalKey::Encode());
- if (!s.ok())
- return s;
IndexedDBDatabaseMetadata metadata;
bool success = false;
@@ -1454,7 +1494,9 @@ leveldb::Status IndexedDBBackingStore::DeleteDatabase(
if (!s.ok())
return s;
} else {
- UpdateBlobJournalWithDatabase(transaction.get(), metadata.id);
+ s = MergeDatabaseIntoPrimaryBlobJournal(transaction.get(), metadata.id);
+ if (!s.ok())
+ return s;
need_cleanup = true;
}
@@ -1464,8 +1506,10 @@ leveldb::Status IndexedDBBackingStore::DeleteDatabase(
return s;
}
+ // If another transaction is running, this will defer processing
+ // the journal until completion.
if (need_cleanup)
- CleanUpBlobJournal(BlobJournalKey::Encode());
+ CleanPrimaryJournalIgnoreReturn();
db_->Compact(start_key, stop_key);
return s;
@@ -2198,8 +2242,7 @@ class IndexedDBBackingStore::Transaction::ChainedBlobWriterImpl
: waiting_for_callback_(false),
database_id_(database_id),
backing_store_(backing_store),
- callback_(callback),
- aborted_(false) {
+ callback_(callback) {
blobs_.swap(*blobs);
iter_ = blobs_.begin();
backing_store->task_runner()->PostTask(
@@ -2217,8 +2260,8 @@ class IndexedDBBackingStore::Transaction::ChainedBlobWriterImpl
if (delegate_.get()) // Only present for Blob, not File.
content::BrowserThread::DeleteSoon(
content::BrowserThread::IO, FROM_HERE, delegate_.release());
- if (aborted_) {
- self_ref_ = NULL;
+ if (aborted_self_ref_.get()) {
+ aborted_self_ref_ = NULL;
return;
}
if (iter_->size() != -1 && iter_->size() != bytes_written)
@@ -2234,38 +2277,36 @@ class IndexedDBBackingStore::Transaction::ChainedBlobWriterImpl
void Abort() override {
if (!waiting_for_callback_)
return;
- self_ref_ = this;
- aborted_ = true;
+ aborted_self_ref_ = this;
}
private:
- ~ChainedBlobWriterImpl() override {}
+ ~ChainedBlobWriterImpl() override { DCHECK(!waiting_for_callback_); }
void WriteNextFile() {
DCHECK(!waiting_for_callback_);
- DCHECK(!aborted_);
+ DCHECK(!aborted_self_ref_.get());
if (iter_ == blobs_.end()) {
- DCHECK(!self_ref_.get());
callback_->Run(true);
return;
} else {
+ waiting_for_callback_ = true;
if (!backing_store_->WriteBlobFile(database_id_, *iter_, this)) {
+ waiting_for_callback_ = false;
callback_->Run(false);
return;
}
- waiting_for_callback_ = true;
}
}
bool waiting_for_callback_;
- scoped_refptr<ChainedBlobWriterImpl> self_ref_;
+ scoped_refptr<ChainedBlobWriterImpl> aborted_self_ref_;
WriteDescriptorVec blobs_;
WriteDescriptorVec::const_iterator iter_;
int64 database_id_;
IndexedDBBackingStore* backing_store_;
scoped_refptr<IndexedDBBackingStore::BlobWriteCallback> callback_;
scoped_ptr<FileWriterDelegate> delegate_;
- bool aborted_;
DISALLOW_COPY_AND_ASSIGN(ChainedBlobWriterImpl);
};
@@ -2293,32 +2334,47 @@ class LocalWriteClosure : public FileWriterDelegate::DelegateWriteCallback,
DCHECK(write_status == FileWriterDelegate::ERROR_WRITE_STARTED ||
write_status == FileWriterDelegate::ERROR_WRITE_NOT_STARTED);
}
- task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&IndexedDBBackingStore::Transaction::ChainedBlobWriter::
- ReportWriteCompletion,
- chained_blob_writer_,
- write_status == FileWriterDelegate::SUCCESS_COMPLETED,
- bytes_written_));
+
+ bool success = write_status == FileWriterDelegate::SUCCESS_COMPLETED;
+ if (success && !bytes_written_) {
+ // LocalFileStreamWriter only creates a file if data is actually written.
+ // If none was then create one now.
+ task_runner_->PostTask(
+ FROM_HERE, base::Bind(&LocalWriteClosure::CreateEmptyFile, this));
+ } else if (success && !last_modified_.is_null()) {
+ task_runner_->PostTask(
+ FROM_HERE, base::Bind(&LocalWriteClosure::UpdateTimeStamp, this));
+ } else {
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&IndexedDBBackingStore::Transaction::ChainedBlobWriter::
+ ReportWriteCompletion,
+ chained_blob_writer_,
+ success,
+ bytes_written_));
+ }
}
- void writeBlobToFileOnIOThread(const FilePath& file_path,
+ void WriteBlobToFileOnIOThread(const FilePath& file_path,
const GURL& blob_url,
+ const base::Time& last_modified,
net::URLRequestContext* request_context) {
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
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));
+ scoped_ptr<FileWriterDelegate> delegate(new FileWriterDelegate(
+ writer.Pass(), storage::FlushPolicy::FLUSH_ON_COMPLETION));
DCHECK(blob_url.is_valid());
scoped_ptr<net::URLRequest> blob_request(request_context->CreateRequest(
- blob_url, net::DEFAULT_PRIORITY, delegate.get(), NULL));
+ blob_url, net::DEFAULT_PRIORITY, delegate.get()));
+
+ this->file_path_ = file_path;
+ this->last_modified_ = last_modified;
delegate->Start(blob_request.Pass(),
base::Bind(&LocalWriteClosure::Run, this));
@@ -2338,11 +2394,38 @@ class LocalWriteClosure : public FileWriterDelegate::DelegateWriteCallback,
}
friend class base::RefCountedThreadSafe<LocalWriteClosure>;
+ // If necessary, update the timestamps on the file as a final
+ // step before reporting success.
+ void UpdateTimeStamp() {
+ DCHECK(task_runner_->RunsTasksOnCurrentThread());
+ if (!base::TouchFile(file_path_, last_modified_, last_modified_)) {
+ // TODO(ericu): Complain quietly; timestamp's probably not vital.
+ }
+ chained_blob_writer_->ReportWriteCompletion(true, bytes_written_);
+ }
+
+ // Create an empty file.
+ void CreateEmptyFile() {
+ DCHECK(task_runner_->RunsTasksOnCurrentThread());
+ base::File file(file_path_,
+ base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
+ bool success = file.created();
+ if (success && !last_modified_.is_null() &&
+ !file.SetTimes(last_modified_, last_modified_)) {
+ // TODO(cmumford): Complain quietly; timestamp's probably not vital.
+ }
+ file.Close();
+ chained_blob_writer_->ReportWriteCompletion(success, bytes_written_);
+ }
+
scoped_refptr<IndexedDBBackingStore::Transaction::ChainedBlobWriter>
chained_blob_writer_;
scoped_refptr<base::SequencedTaskRunner> task_runner_;
int64 bytes_written_;
+ base::FilePath file_path_;
+ base::Time last_modified_;
+
DISALLOW_COPY_AND_ASSIGN(LocalWriteClosure);
};
@@ -2356,8 +2439,7 @@ bool IndexedDBBackingStore::WriteBlobFile(
FilePath path = GetBlobFileName(database_id, descriptor.key());
- if (descriptor.is_file()) {
- DCHECK(!descriptor.file_path().empty());
+ if (descriptor.is_file() && !descriptor.file_path().empty()) {
if (!base::CopyFile(descriptor.file_path(), path))
return false;
@@ -2392,10 +2474,11 @@ bool IndexedDBBackingStore::WriteBlobFile(
content::BrowserThread::PostTask(
content::BrowserThread::IO,
FROM_HERE,
- base::Bind(&LocalWriteClosure::writeBlobToFileOnIOThread,
+ base::Bind(&LocalWriteClosure::WriteBlobToFileOnIOThread,
write_closure.get(),
path,
descriptor.url(),
+ descriptor.last_modified(),
request_context_));
}
return true;
@@ -2409,16 +2492,11 @@ void IndexedDBBackingStore::ReportBlobUnused(int64 database_id,
scoped_refptr<LevelDBTransaction> transaction =
IndexedDBClassFactory::Get()->CreateLevelDBTransaction(db_.get());
- std::string live_blob_key = LiveBlobJournalKey::Encode();
- BlobJournalType live_blob_journal;
- if (!GetBlobJournal(live_blob_key, transaction.get(), &live_blob_journal)
- .ok())
+ BlobJournalType live_blob_journal, primary_journal;
+ if (!GetLiveBlobJournal(transaction.get(), &live_blob_journal).ok())
return;
- DCHECK(live_blob_journal.size());
-
- std::string primary_key = BlobJournalKey::Encode();
- BlobJournalType primary_journal;
- if (!GetBlobJournal(primary_key, transaction.get(), &primary_journal).ok())
+ DCHECK(!live_blob_journal.empty());
+ if (!GetPrimaryBlobJournal(transaction.get(), &primary_journal).ok())
return;
// There are several cases to handle. If blob_key is kAllBlobsKey, we want to
@@ -2459,8 +2537,8 @@ void IndexedDBBackingStore::ReportBlobUnused(int64 database_id,
primary_journal.push_back(
std::make_pair(database_id, DatabaseMetaDataKey::kAllBlobsKey));
}
- UpdatePrimaryJournalWithBlobList(transaction.get(), primary_journal);
- UpdateLiveBlobJournalWithBlobList(transaction.get(), new_live_blob_journal);
+ UpdatePrimaryBlobJournal(transaction.get(), primary_journal);
+ UpdateLiveBlobJournal(transaction.get(), new_live_blob_journal);
transaction->Commit();
// We could just do the deletions/cleaning here, but if there are a lot of
// blobs about to be garbage collected, it'd be better to wait and do them all
@@ -2481,7 +2559,8 @@ void IndexedDBBackingStore::StartJournalCleaningTimer() {
}
// This assumes a file path of dbId/second-to-LSB-of-counter/counter.
-FilePath IndexedDBBackingStore::GetBlobFileName(int64 database_id, int64 key) {
+FilePath IndexedDBBackingStore::GetBlobFileName(int64 database_id,
+ int64 key) const {
return GetBlobFileNameForKey(blob_path_, database_id, key);
}
@@ -2601,26 +2680,19 @@ leveldb::Status IndexedDBBackingStore::GetIndexes(
return s;
}
-bool IndexedDBBackingStore::RemoveBlobFile(int64 database_id, int64 key) {
- FilePath fileName = GetBlobFileName(database_id, key);
- return base::DeleteFile(fileName, false);
+bool IndexedDBBackingStore::RemoveBlobFile(int64 database_id, int64 key) const {
+ FilePath path = GetBlobFileName(database_id, key);
+ return base::DeleteFile(path, false);
}
-bool IndexedDBBackingStore::RemoveBlobDirectory(int64 database_id) {
- FilePath dirName = GetBlobDirectoryName(blob_path_, database_id);
- return base::DeleteFile(dirName, true);
+bool IndexedDBBackingStore::RemoveBlobDirectory(int64 database_id) const {
+ FilePath path = GetBlobDirectoryName(blob_path_, database_id);
+ return base::DeleteFile(path, true);
}
-leveldb::Status IndexedDBBackingStore::CleanUpBlobJournal(
- const std::string& level_db_key) {
- scoped_refptr<LevelDBTransaction> journal_transaction =
- IndexedDBClassFactory::Get()->CreateLevelDBTransaction(db_.get());
- BlobJournalType journal;
- leveldb::Status s =
- GetBlobJournal(level_db_key, journal_transaction.get(), &journal);
- if (!s.ok())
- return s;
- if (!journal.size())
+leveldb::Status IndexedDBBackingStore::CleanUpBlobJournalEntries(
+ const BlobJournalType& journal) const {
+ if (journal.empty())
return leveldb::Status::OK();
for (const auto& entry : journal) {
int64 database_id = entry.first;
@@ -2635,6 +2707,25 @@ leveldb::Status IndexedDBBackingStore::CleanUpBlobJournal(
return IOErrorStatus();
}
}
+ return leveldb::Status::OK();
+}
+
+leveldb::Status IndexedDBBackingStore::CleanUpBlobJournal(
+ const std::string& level_db_key) const {
+ DCHECK(!committing_transaction_count_);
+ leveldb::Status s;
+ scoped_refptr<LevelDBTransaction> journal_transaction =
+ IndexedDBClassFactory::Get()->CreateLevelDBTransaction(db_.get());
+ BlobJournalType journal;
+
+ s = GetBlobJournal(level_db_key, journal_transaction.get(), &journal);
+ if (!s.ok())
+ return s;
+ if (journal.empty())
+ return leveldb::Status::OK();
+ s = CleanUpBlobJournalEntries(journal);
+ if (!s.ok())
+ return s;
ClearBlobJournal(journal_transaction.get(), level_db_key);
return journal_transaction->Commit();
}
@@ -2688,7 +2779,7 @@ leveldb::Status IndexedDBBackingStore::Transaction::GetBlobInfoForRecord(
entry.set_release_callback(
backing_store_->active_blob_registry()->GetFinalReleaseCallback(
database_id, entry.key()));
- if (entry.is_file()) {
+ if (entry.is_file() && !entry.file_path().empty()) {
base::File::Info info;
if (base::GetFileInfo(entry.file_path(), &info)) {
// This should always work, but it isn't fatal if it doesn't; it just
@@ -2703,7 +2794,11 @@ leveldb::Status IndexedDBBackingStore::Transaction::GetBlobInfoForRecord(
}
void IndexedDBBackingStore::CleanPrimaryJournalIgnoreReturn() {
- CleanUpBlobJournal(BlobJournalKey::Encode());
+ // While a transaction is busy it is not safe to clean the journal.
+ if (committing_transaction_count_ > 0)
+ StartJournalCleaningTimer();
+ else
+ CleanUpBlobJournal(BlobJournalKey::Encode());
}
WARN_UNUSED_RESULT static leveldb::Status SetMaxIndexId(
@@ -3628,7 +3723,7 @@ bool ObjectStoreCursorOptions(
} else {
cursor_options->low_key =
ObjectStoreDataKey::Encode(database_id, object_store_id, range.lower());
- cursor_options->low_open = range.lowerOpen();
+ cursor_options->low_open = range.lower_open();
}
leveldb::Status s;
@@ -3652,7 +3747,7 @@ bool ObjectStoreCursorOptions(
} else {
cursor_options->high_key =
ObjectStoreDataKey::Encode(database_id, object_store_id, range.upper());
- cursor_options->high_open = range.upperOpen();
+ cursor_options->high_open = range.upper_open();
if (!cursor_options->forward) {
// For reverse cursors, we need a key that exists.
@@ -3707,7 +3802,7 @@ bool IndexCursorOptions(
} else {
cursor_options->low_key = IndexDataKey::Encode(
database_id, object_store_id, index_id, range.lower());
- cursor_options->low_open = range.lowerOpen();
+ cursor_options->low_open = range.lower_open();
}
leveldb::Status s;
@@ -3728,7 +3823,7 @@ bool IndexCursorOptions(
} else {
cursor_options->high_key = IndexDataKey::Encode(
database_id, object_store_id, index_id, range.upper());
- cursor_options->high_open = range.upperOpen();
+ cursor_options->high_open = range.upper_open();
std::string found_high_key;
// Seek to the *last* key in the set of non-unique keys
@@ -3862,7 +3957,7 @@ IndexedDBBackingStore::OpenIndexCursor(
IndexedDBBackingStore::Transaction::Transaction(
IndexedDBBackingStore* backing_store)
- : backing_store_(backing_store), database_id_(-1) {
+ : backing_store_(backing_store), database_id_(-1), committing_(false) {
}
IndexedDBBackingStore::Transaction::~Transaction() {
@@ -3870,6 +3965,7 @@ IndexedDBBackingStore::Transaction::~Transaction() {
blob_change_map_.begin(), blob_change_map_.end());
STLDeleteContainerPairSecondPointers(incognito_blob_map_.begin(),
incognito_blob_map_.end());
+ DCHECK(!committing_);
}
void IndexedDBBackingStore::Transaction::Begin() {
@@ -3884,7 +3980,7 @@ void IndexedDBBackingStore::Transaction::Begin() {
incognito_blob_map_[iter.first] = iter.second->Clone().release();
}
-static GURL getURLFromUUID(const string& uuid) {
+static GURL GetURLFromUUID(const string& uuid) {
return GURL("blob:uuid/" + uuid);
}
@@ -3894,58 +3990,58 @@ leveldb::Status IndexedDBBackingStore::Transaction::HandleBlobPreTransaction(
if (backing_store_->is_incognito())
return leveldb::Status::OK();
- new_blob_entries->clear();
- new_files_to_write->clear();
- 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 (auto& iter : blob_change_map_) {
- std::vector<IndexedDBBlobInfo*> new_blob_keys;
- for (auto& entry : iter.second->mutable_blob_info()) {
- int64 next_blob_key = -1;
- bool result = GetBlobKeyGeneratorCurrentNumber(
- pre_transaction.get(), database_id_, &next_blob_key);
- if (!result || next_blob_key < 0)
- return InternalInconsistencyStatus();
- BlobJournalEntryType journal_entry =
- std::make_pair(database_id_, next_blob_key);
- journal.push_back(journal_entry);
- if (entry.is_file()) {
- new_files_to_write->push_back(
- WriteDescriptor(entry.file_path(),
- next_blob_key,
- entry.size(),
- entry.last_modified()));
- } else {
- new_files_to_write->push_back(
- WriteDescriptor(getURLFromUUID(entry.uuid()),
- next_blob_key,
- entry.size()));
- }
- 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());
- if (!BlobEntryKey::FromObjectStoreDataKey(&key_piece, &blob_entry_key)) {
- NOTREACHED();
+ DCHECK(new_blob_entries->empty());
+ DCHECK(new_files_to_write->empty());
+ DCHECK(blobs_to_write_.empty());
+
+ if (blob_change_map_.empty())
+ return leveldb::Status::OK();
+
+ // Create LevelDBTransaction for the name generator seed and add-journal.
+ scoped_refptr<LevelDBTransaction> pre_transaction =
+ IndexedDBClassFactory::Get()->CreateLevelDBTransaction(
+ backing_store_->db_.get());
+
+ for (auto& iter : blob_change_map_) {
+ std::vector<IndexedDBBlobInfo*> new_blob_keys;
+ for (auto& entry : iter.second->mutable_blob_info()) {
+ int64 next_blob_key = -1;
+ bool result = GetBlobKeyGeneratorCurrentNumber(
+ pre_transaction.get(), database_id_, &next_blob_key);
+ if (!result || next_blob_key < 0)
return InternalInconsistencyStatus();
+ blobs_to_write_.push_back(std::make_pair(database_id_, next_blob_key));
+ if (entry.is_file() && !entry.file_path().empty()) {
+ new_files_to_write->push_back(
+ WriteDescriptor(entry.file_path(), next_blob_key, entry.size(),
+ entry.last_modified()));
+ } else {
+ new_files_to_write->push_back(
+ WriteDescriptor(GetURLFromUUID(entry.uuid()), next_blob_key,
+ entry.size(), entry.last_modified()));
}
- new_blob_entries->push_back(
- std::make_pair(blob_entry_key, EncodeBlobData(new_blob_keys)));
+ 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();
}
- UpdatePrimaryJournalWithBlobList(pre_transaction.get(), journal);
- leveldb::Status s = pre_transaction->Commit();
- if (!s.ok())
+ BlobEntryKey blob_entry_key;
+ StringPiece key_piece(iter.second->key());
+ if (!BlobEntryKey::FromObjectStoreDataKey(&key_piece, &blob_entry_key)) {
+ NOTREACHED();
return InternalInconsistencyStatus();
+ }
+ new_blob_entries->push_back(
+ std::make_pair(blob_entry_key, EncodeBlobData(new_blob_keys)));
}
+
+ AppendBlobsToPrimaryBlobJournal(pre_transaction.get(), blobs_to_write_);
+ leveldb::Status s = pre_transaction->Commit();
+ if (!s.ok())
+ return InternalInconsistencyStatus();
+
return leveldb::Status::OK();
}
@@ -3989,24 +4085,17 @@ bool IndexedDBBackingStore::Transaction::CollectBlobFilesToRemove() {
return true;
}
-leveldb::Status IndexedDBBackingStore::Transaction::SortBlobsToRemove() {
+void IndexedDBBackingStore::Transaction::PartitionBlobsToRemove(
+ BlobJournalType* dead_blobs,
+ BlobJournalType* live_blobs) const {
IndexedDBActiveBlobRegistry* registry =
backing_store_->active_blob_registry();
- BlobJournalType primary_journal, live_blob_journal;
for (const auto& iter : blobs_to_remove_) {
if (registry->MarkDeletedCheckIfUsed(iter.first, iter.second))
- live_blob_journal.push_back(iter);
+ live_blobs->push_back(iter);
else
- primary_journal.push_back(iter);
+ dead_blobs->push_back(iter);
}
- UpdatePrimaryJournalWithBlobList(transaction_.get(), primary_journal);
- leveldb::Status s =
- MergeBlobsIntoLiveBlobJournal(transaction_.get(), live_blob_journal);
- if (!s.ok())
- return s;
- // To signal how many blobs need attention right now.
- blobs_to_remove_.swap(primary_journal);
- return leveldb::Status::OK();
}
leveldb::Status IndexedDBBackingStore::Transaction::CommitPhaseOne(
@@ -4017,13 +4106,6 @@ leveldb::Status IndexedDBBackingStore::Transaction::CommitPhaseOne(
leveldb::Status s;
- s = backing_store_->CleanUpBlobJournal(BlobJournalKey::Encode());
- if (!s.ok()) {
- INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD);
- transaction_ = NULL;
- return s;
- }
-
BlobEntryKeyValuePairVec new_blob_entries;
WriteDescriptorVec new_files_to_write;
s = HandleBlobPreTransaction(&new_blob_entries, &new_files_to_write);
@@ -4041,13 +4123,13 @@ leveldb::Status IndexedDBBackingStore::Transaction::CommitPhaseOne(
return InternalInconsistencyStatus();
}
- if (new_files_to_write.size()) {
+ committing_ = true;
+ ++backing_store_->committing_transaction_count_;
+
+ if (!new_files_to_write.empty()) {
// 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);
- // Remove the add journal, if any; once the blobs are written, and we
- // commit, this will do the cleanup.
- ClearBlobJournal(transaction_.get(), BlobJournalKey::Encode());
} else {
callback->Run(true);
}
@@ -4058,37 +4140,98 @@ leveldb::Status IndexedDBBackingStore::Transaction::CommitPhaseOne(
leveldb::Status IndexedDBBackingStore::Transaction::CommitPhaseTwo() {
IDB_TRACE("IndexedDBBackingStore::Transaction::CommitPhaseTwo");
leveldb::Status s;
- if (blobs_to_remove_.size()) {
- s = SortBlobsToRemove();
- if (!s.ok()) {
- INTERNAL_READ_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD);
- transaction_ = NULL;
+
+ DCHECK(committing_);
+ committing_ = false;
+ DCHECK_GT(backing_store_->committing_transaction_count_, 0UL);
+ --backing_store_->committing_transaction_count_;
+
+ BlobJournalType primary_journal, live_journal, saved_primary_journal,
+ dead_blobs;
+ if (!blob_change_map_.empty()) {
+ // Read the persisted states of the primary/live blob journals,
+ // so that they can be updated correctly by the transaction.
+ scoped_refptr<LevelDBTransaction> journal_transaction =
+ IndexedDBClassFactory::Get()->CreateLevelDBTransaction(
+ backing_store_->db_.get());
+ s = GetPrimaryBlobJournal(journal_transaction.get(), &primary_journal);
+ if (!s.ok())
return s;
+ s = GetLiveBlobJournal(journal_transaction.get(), &live_journal);
+ if (!s.ok())
+ return s;
+
+ // Remove newly added blobs from the journal - they will be accounted
+ // for in blob entry tables in the transaction.
+ std::sort(primary_journal.begin(), primary_journal.end());
+ std::sort(blobs_to_write_.begin(), blobs_to_write_.end());
+ BlobJournalType new_journal = base::STLSetDifference<BlobJournalType>(
+ primary_journal, blobs_to_write_);
+ primary_journal.swap(new_journal);
+
+ // Append newly deleted blobs to appropriate primary/live journals.
+ saved_primary_journal = primary_journal;
+ BlobJournalType live_blobs;
+ if (!blobs_to_remove_.empty()) {
+ DCHECK(!backing_store_->is_incognito());
+ PartitionBlobsToRemove(&dead_blobs, &live_blobs);
}
+ primary_journal.insert(primary_journal.end(), dead_blobs.begin(),
+ dead_blobs.end());
+ live_journal.insert(live_journal.end(), live_blobs.begin(),
+ live_blobs.end());
+ UpdatePrimaryBlobJournal(transaction_.get(), primary_journal);
+ UpdateLiveBlobJournal(transaction_.get(), live_journal);
}
+ // Actually commit. If this succeeds, the journals will appropriately
+ // reflect pending blob work - dead files that should be deleted
+ // immediately, and live files to monitor.
s = transaction_->Commit();
transaction_ = NULL;
- if (s.ok() && backing_store_->is_incognito() && !blob_change_map_.empty()) {
- BlobChangeMap& target_map = backing_store_->incognito_blob_map_;
- 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 (!s.ok()) {
+ INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD);
+ return s;
+ }
+
+ if (backing_store_->is_incognito()) {
+ if (!blob_change_map_.empty()) {
+ BlobChangeMap& target_map = backing_store_->incognito_blob_map_;
+ 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;
+ }
}
}
+ return leveldb::Status::OK();
}
- if (!s.ok())
- INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD);
- else if (blobs_to_remove_.size())
- s = backing_store_->CleanUpBlobJournal(BlobJournalKey::Encode());
+ // Actually delete dead blob files, then remove those entries
+ // from the persisted primary journal.
+ if (dead_blobs.empty())
+ return leveldb::Status::OK();
+
+ DCHECK(!blob_change_map_.empty());
+
+ s = backing_store_->CleanUpBlobJournalEntries(dead_blobs);
+ if (!s.ok()) {
+ INTERNAL_WRITE_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD);
+ return s;
+ }
+
+ scoped_refptr<LevelDBTransaction> update_journal_transaction =
+ IndexedDBClassFactory::Get()->CreateLevelDBTransaction(
+ backing_store_->db_.get());
+ UpdatePrimaryBlobJournal(update_journal_transaction.get(),
+ saved_primary_journal);
+ s = update_journal_transaction->Commit();
return s;
}
@@ -4124,7 +4267,7 @@ void IndexedDBBackingStore::Transaction::WriteNewBlobs(
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())
+ if (blob_entry_iter.second.empty())
transaction_->Remove(blob_entry_iter.first.Encode());
else
transaction_->Put(blob_entry_iter.first.Encode(),
@@ -4140,6 +4283,12 @@ void IndexedDBBackingStore::Transaction::WriteNewBlobs(
void IndexedDBBackingStore::Transaction::Rollback() {
IDB_TRACE("IndexedDBBackingStore::Transaction::Rollback");
+ if (committing_) {
+ committing_ = false;
+ DCHECK_GT(backing_store_->committing_transaction_count_, 0UL);
+ --backing_store_->committing_transaction_count_;
+ }
+
if (chained_blob_writer_.get()) {
chained_blob_writer_->Abort();
chained_blob_writer_ = NULL;
@@ -4247,8 +4396,13 @@ void IndexedDBBackingStore::Transaction::PutBlobInfo(
IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor(
const GURL& url,
int64_t key,
- int64_t size)
- : is_file_(false), url_(url), key_(key), size_(size) {
+ int64_t size,
+ base::Time last_modified)
+ : is_file_(false),
+ url_(url),
+ key_(key),
+ size_(size),
+ last_modified_(last_modified) {
}
IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor(
@@ -4263,4 +4417,12 @@ IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor(
last_modified_(last_modified) {
}
+IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor(
+ const WriteDescriptor& other) = default;
+IndexedDBBackingStore::Transaction::WriteDescriptor::~WriteDescriptor() =
+ default;
+IndexedDBBackingStore::Transaction::WriteDescriptor&
+ IndexedDBBackingStore::Transaction::WriteDescriptor::
+ operator=(const WriteDescriptor& other) = default;
+
} // namespace content
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 a15b2372a6b..d7e5dbc217c 100644
--- a/chromium/content/browser/indexed_db/indexed_db_backing_store.h
+++ b/chromium/content/browser/indexed_db/indexed_db_backing_store.h
@@ -123,10 +123,21 @@ class CONTENT_EXPORT IndexedDBBackingStore
virtual ~Transaction();
virtual void Begin();
+
+ // CommitPhaseOne determines what blobs (if any) need to be written to disk
+ // and updates the primary blob journal, and kicks off the async writing
+ // of the blob files. In case of crash/rollback, the journal indicates what
+ // files should be cleaned up.
// 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>);
+
+ // CommitPhaseTwo is called once the blob files (if any) have been written
+ // to disk, and commits the actual transaction to the backing store,
+ // including blob journal updates, then deletes any blob files deleted
+ // by the transaction and not referenced by running scripts.
virtual leveldb::Status CommitPhaseTwo();
+
virtual void Rollback();
void Reset() {
backing_store_ = NULL;
@@ -156,13 +167,19 @@ class CONTENT_EXPORT IndexedDBBackingStore
typedef std::vector<std::pair<BlobEntryKey, std::string> >
BlobEntryKeyValuePairVec;
- class WriteDescriptor {
+ class CONTENT_EXPORT WriteDescriptor {
public:
- WriteDescriptor(const GURL& url, int64_t key, int64_t size);
+ WriteDescriptor(const GURL& url,
+ int64_t key,
+ int64_t size,
+ base::Time last_modified);
WriteDescriptor(const base::FilePath& path,
int64_t key,
int64_t size,
base::Time last_modified);
+ WriteDescriptor(const WriteDescriptor& other);
+ ~WriteDescriptor();
+ WriteDescriptor& operator=(const WriteDescriptor& other);
bool is_file() const { return is_file_; }
const GURL& url() const {
@@ -210,24 +227,52 @@ class CONTENT_EXPORT IndexedDBBackingStore
private:
class BlobWriteCallbackWrapper;
+ // Called by CommitPhaseOne: Identifies the blob entries to write and adds
+ // them to the primary blob journal directly (i.e. not as part of the
+ // transaction). Populates blobs_to_write_.
leveldb::Status HandleBlobPreTransaction(
BlobEntryKeyValuePairVec* new_blob_entries,
WriteDescriptorVec* new_files_to_write);
- // Returns true on success, false on failure.
+
+ // Called by CommitPhaseOne: Populates blob_files_to_remove_ by
+ // determining which blobs are deleted as part of the transaction, and
+ // adds blob entry cleanup operations to the transaction. Returns true on
+ // success, false on failure.
bool CollectBlobFilesToRemove();
- // The callback will be called eventually on success or failure.
+
+ // Called by CommitPhaseOne: Kicks off the asynchronous writes of blobs
+ // identified in HandleBlobPreTransaction. 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();
+
+ // Called by CommitPhaseTwo: Partition blob references in blobs_to_remove_
+ // into live (active references) and dead (no references).
+ void PartitionBlobsToRemove(BlobJournalType* dead_blobs,
+ BlobJournalType* live_blobs) const;
IndexedDBBackingStore* backing_store_;
scoped_refptr<LevelDBTransaction> transaction_;
BlobChangeMap blob_change_map_;
BlobChangeMap incognito_blob_map_;
int64 database_id_;
+
+ // List of blob files being newly written as part of this transaction.
+ // These will be added to the primary blob journal prior to commit, then
+ // removed after a sucessful commit.
+ BlobJournalType blobs_to_write_;
+
+ // List of blob files being deleted as part of this transaction. These will
+ // be added to either the primary or live blob journal as appropriate
+ // following a successful commit.
BlobJournalType blobs_to_remove_;
scoped_refptr<ChainedBlobWriter> chained_blob_writer_;
+
+ // Set to true between CommitPhaseOne and CommitPhaseTwo/Rollback, to
+ // indicate that the committing_transaction_count_ on the backing store
+ // has been bumped, and journal cleaning should be deferred.
+ bool committing_;
};
class Cursor {
@@ -467,7 +512,7 @@ class CONTENT_EXPORT IndexedDBBackingStore
// Public for IndexedDBActiveBlobRegistry::ReleaseBlobRef.
virtual void ReportBlobUnused(int64 database_id, int64 blob_key);
- base::FilePath GetBlobFileName(int64 database_id, int64 key);
+ base::FilePath GetBlobFileName(int64 database_id, int64 key) const;
virtual scoped_ptr<Cursor> OpenObjectStoreKeyCursor(
IndexedDBBackingStore::Transaction* transaction,
@@ -520,8 +565,19 @@ class CONTENT_EXPORT IndexedDBBackingStore
int64 database_id,
const Transaction::WriteDescriptor& descriptor,
Transaction::ChainedBlobWriter* chained_blob_writer);
- virtual bool RemoveBlobFile(int64 database_id, int64 key);
+
+ // Remove the referenced file on disk.
+ virtual bool RemoveBlobFile(int64 database_id, int64 key) const;
+
+ // Schedule a call to CleanPrimaryJournalIgnoreReturn() via
+ // an owned timer. If this object is destroyed, the timer
+ // will automatically be cancelled.
virtual void StartJournalCleaningTimer();
+
+ // Attempt to clean the primary journal. This will remove
+ // any referenced files and delete the journal entry. If any
+ // transaction is currently committing this will be deferred
+ // via StartJournalCleaningTimer().
void CleanPrimaryJournalIgnoreReturn();
private:
@@ -551,8 +607,21 @@ class CONTENT_EXPORT IndexedDBBackingStore
int64 object_store_id,
IndexedDBObjectStoreMetadata::IndexMap* map)
WARN_UNUSED_RESULT;
- bool RemoveBlobDirectory(int64 database_id);
- leveldb::Status CleanUpBlobJournal(const std::string& level_db_key);
+
+ // Remove the blob directory for the specified database and all contained
+ // blob files.
+ bool RemoveBlobDirectory(int64 database_id) const;
+
+ // Synchronously read the key-specified blob journal entry from the backing
+ // store, delete all referenced blob files, and erase the journal entry.
+ // This must not be used while temporary entries are present e.g. during
+ // a two-stage transaction commit with blobs.
+ leveldb::Status CleanUpBlobJournal(const std::string& level_db_key) const;
+
+ // Synchronously delete the files and/or directories on disk referenced by
+ // the blob journal.
+ leveldb::Status CleanUpBlobJournalEntries(
+ const BlobJournalType& journal) const;
IndexedDBFactory* indexed_db_factory_;
const GURL origin_url_;
@@ -579,6 +648,11 @@ class CONTENT_EXPORT IndexedDBBackingStore
IndexedDBActiveBlobRegistry active_blob_registry_;
base::OneShotTimer<IndexedDBBackingStore> close_timer_;
+ // Incremented whenever a transaction starts committing, decremented when
+ // complete. While > 0, temporary journal entries may exist so out-of-band
+ // journal cleaning must be deferred.
+ size_t committing_transaction_count_;
+
DISALLOW_COPY_AND_ASSIGN(IndexedDBBackingStore);
};
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 da9bcda9386..09f1fa2e039 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
@@ -24,7 +24,7 @@
#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 "third_party/WebKit/public/platform/modules/indexeddb/WebIDBTypes.h"
using base::ASCIIToUTF16;
@@ -136,7 +136,7 @@ class TestableIndexedDBBackingStore : public IndexedDBBackingStore {
return true;
}
- bool RemoveBlobFile(int64 database_id, int64 key) override {
+ bool RemoveBlobFile(int64 database_id, int64 key) const override {
if (database_id_ != database_id ||
!KeyPrefix::IsValidDatabaseId(database_id)) {
return false;
@@ -169,7 +169,10 @@ class TestableIndexedDBBackingStore : public IndexedDBBackingStore {
int64 database_id_;
std::vector<Transaction::WriteDescriptor> writes_;
- std::vector<int64> removals_;
+
+ // This is modified in an overridden virtual function that is properly const
+ // in the real implementation, therefore must be mutable here.
+ mutable std::vector<int64> removals_;
DISALLOW_COPY_AND_ASSIGN(TestableIndexedDBBackingStore);
};
@@ -253,6 +256,11 @@ class IndexedDBBackingStoreTest : public testing::Test {
base::FilePath(FILE_PATH_LITERAL("path/to/file")),
base::UTF8ToUTF16("file name"),
base::UTF8ToUTF16("file type")));
+ m_blob_info.push_back(
+ IndexedDBBlobInfo("uuid 5",
+ base::FilePath(),
+ base::UTF8ToUTF16("file name"),
+ base::UTF8ToUTF16("file type")));
m_value3 = IndexedDBValue("value3", m_blob_info);
m_key1 = IndexedDBKey(99, blink::WebIDBKeyTypeNumber);
@@ -306,9 +314,10 @@ class IndexedDBBackingStoreTest : public testing::Test {
const IndexedDBBackingStore::Transaction::WriteDescriptor& desc =
backing_store_->writes()[i];
const IndexedDBBlobInfo& info = m_blob_info[i];
- if (desc.is_file() != info.is_file())
- return false;
- if (desc.is_file()) {
+ if (desc.is_file() != info.is_file()) {
+ if (!info.is_file() || !info.file_path().empty())
+ return false;
+ } else if (desc.is_file()) {
if (desc.file_path() != info.file_path())
return false;
} else {
@@ -638,6 +647,42 @@ TEST_F(IndexedDBBackingStoreTest, DeleteRangeEmptyRange) {
}
}
+TEST_F(IndexedDBBackingStoreTest, BlobJournalInterleavedTransactions) {
+ IndexedDBBackingStore::Transaction transaction1(backing_store_.get());
+ transaction1.Begin();
+ ScopedVector<storage::BlobDataHandle> handles1;
+ IndexedDBBackingStore::RecordIdentifier record1;
+ EXPECT_TRUE(backing_store_->PutRecord(&transaction1, 1, 1, m_key3, &m_value3,
+ &handles1, &record1).ok());
+ scoped_refptr<TestCallback> callback1(new TestCallback());
+ EXPECT_TRUE(transaction1.CommitPhaseOne(callback1).ok());
+ task_runner_->RunUntilIdle();
+ EXPECT_TRUE(CheckBlobWrites());
+ EXPECT_TRUE(callback1->called);
+ EXPECT_TRUE(callback1->succeeded);
+ EXPECT_EQ(0U, backing_store_->removals().size());
+
+ IndexedDBBackingStore::Transaction transaction2(backing_store_.get());
+ transaction2.Begin();
+ ScopedVector<storage::BlobDataHandle> handles2;
+ IndexedDBBackingStore::RecordIdentifier record2;
+ EXPECT_TRUE(backing_store_->PutRecord(&transaction2, 1, 1, m_key1, &m_value1,
+ &handles2, &record2).ok());
+ scoped_refptr<TestCallback> callback2(new TestCallback());
+ EXPECT_TRUE(transaction2.CommitPhaseOne(callback2).ok());
+ task_runner_->RunUntilIdle();
+ EXPECT_TRUE(CheckBlobWrites());
+ EXPECT_TRUE(callback2->called);
+ EXPECT_TRUE(callback2->succeeded);
+ EXPECT_EQ(0U, backing_store_->removals().size());
+
+ EXPECT_TRUE(transaction1.CommitPhaseTwo().ok());
+ EXPECT_EQ(0U, backing_store_->removals().size());
+
+ EXPECT_TRUE(transaction2.CommitPhaseTwo().ok());
+ EXPECT_EQ(0U, backing_store_->removals().size());
+}
+
TEST_F(IndexedDBBackingStoreTest, LiveBlobJournal) {
{
IndexedDBBackingStore::Transaction transaction1(backing_store_.get());
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 e4b1a3a1f12..d61de754b93 100644
--- a/chromium/content/browser/indexed_db/indexed_db_blob_info.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_blob_info.cc
@@ -49,7 +49,12 @@ IndexedDBBlobInfo::IndexedDBBlobInfo(int64 key,
: is_file_(true), type_(type), size_(-1), file_name_(file_name), key_(key) {
}
-IndexedDBBlobInfo::~IndexedDBBlobInfo() {}
+IndexedDBBlobInfo::IndexedDBBlobInfo(const IndexedDBBlobInfo& other) = default;
+
+IndexedDBBlobInfo::~IndexedDBBlobInfo() = default;
+
+IndexedDBBlobInfo& IndexedDBBlobInfo::operator=(
+ const IndexedDBBlobInfo& other) = default;
void IndexedDBBlobInfo::set_size(int64 size) {
DCHECK_EQ(-1, 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 5001b4bb765..60da7076a70 100644
--- a/chromium/content/browser/indexed_db/indexed_db_blob_info.h
+++ b/chromium/content/browser/indexed_db/indexed_db_blob_info.h
@@ -11,7 +11,7 @@
#include "base/files/file_path.h"
#include "base/time/time.h"
#include "content/common/content_export.h"
-#include "storage/common/blob/shareable_file_reference.h"
+#include "storage/browser/blob/shareable_file_reference.h"
namespace content {
@@ -33,7 +33,9 @@ class CONTENT_EXPORT IndexedDBBlobInfo {
const base::string16& type,
const base::string16& file_name);
+ IndexedDBBlobInfo(const IndexedDBBlobInfo& other);
~IndexedDBBlobInfo();
+ IndexedDBBlobInfo& operator=(const IndexedDBBlobInfo& other);
bool is_file() const { return is_file_; }
const std::string& uuid() const { return uuid_; }
diff --git a/chromium/content/browser/indexed_db/indexed_db_browsertest.cc b/chromium/content/browser/indexed_db/indexed_db_browsertest.cc
index 871d9f50f2f..21f6ad67116 100644
--- a/chromium/content/browser/indexed_db/indexed_db_browsertest.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_browsertest.cc
@@ -34,6 +34,7 @@
#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 "storage/browser/blob/blob_storage_context.h"
#include "storage/browser/database/database_util.h"
#include "storage/browser/quota/quota_manager.h"
@@ -109,9 +110,9 @@ class IndexedDBBrowserTest : public ContentBrowserTest {
return static_cast<IndexedDBContextImpl*>(partition->GetIndexedDBContext());
}
- void SetQuota(int quotaKilobytes) {
- const int kTemporaryStorageQuotaSize = quotaKilobytes
- * 1024 * QuotaManager::kPerHostTemporaryPortion;
+ void SetQuota(int quota_kilobytes) {
+ const int kTemporaryStorageQuotaSize =
+ quota_kilobytes * 1024 * QuotaManager::kPerHostTemporaryPortion;
SetTempQuota(kTemporaryStorageQuotaSize,
BrowserContext::GetDefaultStoragePartition(
shell()->web_contents()->GetBrowserContext())->GetQuotaManager());
@@ -124,7 +125,7 @@ class IndexedDBBrowserTest : public ContentBrowserTest {
base::Bind(&IndexedDBBrowserTest::SetTempQuota, bytes, qm));
return;
}
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
qm->SetTemporaryGlobalOverrideQuota(bytes, storage::QuotaCallback());
// Don't return until the quota has been set.
scoped_refptr<base::ThreadTestHelper> helper(new base::ThreadTestHelper(
@@ -149,6 +150,22 @@ class IndexedDBBrowserTest : public ContentBrowserTest {
return disk_usage_;
}
+ virtual int RequestBlobFileCount() {
+ PostTaskAndReplyWithResult(
+ GetContext()->TaskRunner(), FROM_HERE,
+ base::Bind(&IndexedDBContextImpl::GetOriginBlobFileCount, GetContext(),
+ GURL("file:///")),
+ base::Bind(&IndexedDBBrowserTest::DidGetBlobFileCount, this));
+ scoped_refptr<base::ThreadTestHelper> helper(
+ new base::ThreadTestHelper(BrowserMainLoop::GetInstance()
+ ->indexed_db_thread()
+ ->message_loop_proxy()));
+ EXPECT_TRUE(helper->Run());
+ // Wait for DidGetBlobFileCount to be called.
+ base::MessageLoop::current()->RunUntilIdle();
+ return blob_file_count_;
+ }
+
private:
static MockBrowserTestIndexedDBClassFactory* GetTestClassFactory() {
static ::base::LazyInstance<MockBrowserTestIndexedDBClassFactory>::Leaky
@@ -161,11 +178,13 @@ class IndexedDBBrowserTest : public ContentBrowserTest {
}
virtual void DidGetDiskUsage(int64 bytes) {
- EXPECT_GT(bytes, 0);
disk_usage_ = bytes;
}
+ virtual void DidGetBlobFileCount(int count) { blob_file_count_ = count; }
+
int64 disk_usage_;
+ int blob_file_count_ = 0;
DISALLOW_COPY_AND_ASSIGN(IndexedDBBrowserTest);
};
@@ -263,7 +282,7 @@ class IndexedDBBrowserTestWithGCExposed : public IndexedDBBrowserTest {
public:
IndexedDBBrowserTestWithGCExposed() {}
- void SetUpCommandLine(CommandLine* command_line) override {
+ void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitchASCII(switches::kJavaScriptFlags, "--expose-gc");
}
@@ -335,6 +354,7 @@ IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithVersion123456Schema,
EXPECT_GT(original_size, 0);
SimpleTest(GetTestUrl("indexeddb", "open_bad_db.html"));
int64 new_size = RequestDiskUsage();
+ EXPECT_GT(new_size, 0);
EXPECT_NE(original_size, new_size);
}
@@ -349,6 +369,7 @@ IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithVersion987654SSVData,
EXPECT_GT(original_size, 0);
SimpleTest(GetTestUrl("indexeddb", "open_bad_db.html"));
int64 new_size = RequestDiskUsage();
+ EXPECT_GT(new_size, 0);
EXPECT_NE(original_size, new_size);
}
@@ -363,6 +384,7 @@ IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithCorruptLevelDB,
EXPECT_GT(original_size, 0);
SimpleTest(GetTestUrl("indexeddb", "open_bad_db.html"));
int64 new_size = RequestDiskUsage();
+ EXPECT_GT(new_size, 0);
EXPECT_NE(original_size, new_size);
}
@@ -377,6 +399,7 @@ IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithMissingSSTFile,
EXPECT_GT(original_size, 0);
SimpleTest(GetTestUrl("indexeddb", "open_missing_table.html"));
int64 new_size = RequestDiskUsage();
+ EXPECT_GT(new_size, 0);
EXPECT_NE(original_size, new_size);
}
@@ -401,6 +424,96 @@ IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CanDeleteWhenOverQuotaTest) {
SimpleTest(GetTestUrl("indexeddb", "delete_over_quota.html"));
}
+IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, EmptyBlob) {
+ // First delete all IDB's for the test origin
+ GetContext()->TaskRunner()->PostTask(
+ FROM_HERE, base::Bind(&IndexedDBContextImpl::DeleteForOrigin,
+ GetContext(), GURL("file:///")));
+ EXPECT_EQ(0, RequestBlobFileCount()); // Start with no blob files.
+ const GURL test_url = GetTestUrl("indexeddb", "empty_blob.html");
+ // For some reason Android's futimes fails (EPERM) in this test. Do not assert
+ // file times on Android, but do so on other platforms. crbug.com/467247
+ // TODO(cmumford): Figure out why this is the case and fix if possible.
+#if defined(OS_ANDROID)
+ SimpleTest(GURL(test_url.spec() + "#ignoreTimes"));
+#else
+ SimpleTest(GURL(test_url.spec()));
+#endif
+ // Test stores one blob and one file to disk, so expect two files.
+ EXPECT_EQ(2, RequestBlobFileCount());
+}
+
+IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithGCExposed, BlobDidAck) {
+ SimpleTest(GetTestUrl("indexeddb", "blob_did_ack.html"));
+ // Wait for idle so that the blob ack has time to be received/processed by
+ // the browser process.
+ base::MessageLoop::current()->RunUntilIdle();
+ content::ChromeBlobStorageContext* blob_context =
+ ChromeBlobStorageContext::GetFor(
+ shell()->web_contents()->GetBrowserContext());
+ EXPECT_EQ(0UL, blob_context->context()->blob_count());
+}
+
+IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithGCExposed, BlobDidAckPrefetch) {
+ SimpleTest(GetTestUrl("indexeddb", "blob_did_ack_prefetch.html"));
+ // Wait for idle so that the blob ack has time to be received/processed by
+ // the browser process.
+ base::MessageLoop::current()->RunUntilIdle();
+ content::ChromeBlobStorageContext* blob_context =
+ ChromeBlobStorageContext::GetFor(
+ shell()->web_contents()->GetBrowserContext());
+ EXPECT_EQ(0UL, blob_context->context()->blob_count());
+}
+
+IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, BlobsCountAgainstQuota) {
+ SimpleTest(GetTestUrl("indexeddb", "blobs_use_quota.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DeleteForOriginDeletesBlobs) {
+ SimpleTest(GetTestUrl("indexeddb", "write_20mb_blob.html"));
+ int64 size = RequestDiskUsage();
+ // This assertion assumes that we do not compress blobs.
+ EXPECT_GT(size, 20 << 20 /* 20 MB */);
+ GetContext()->TaskRunner()->PostTask(
+ FROM_HERE, base::Bind(&IndexedDBContextImpl::DeleteForOrigin,
+ GetContext(), GURL("file:///")));
+ scoped_refptr<base::ThreadTestHelper> helper(
+ new base::ThreadTestHelper(BrowserMainLoop::GetInstance()
+ ->indexed_db_thread()
+ ->message_loop_proxy()));
+ ASSERT_TRUE(helper->Run());
+ EXPECT_EQ(0, RequestDiskUsage());
+}
+
+IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DiskFullOnCommit) {
+ // Ignore several preceding transactions:
+ // * The test calls deleteDatabase() which opens the backing store:
+ // #1: IndexedDBBackingStore::OpenBackingStore
+ // => IndexedDBBackingStore::SetUpMetadata
+ // #2: IndexedDBBackingStore::OpenBackingStore
+ // => IndexedDBBackingStore::CleanUpBlobJournal (no-op)
+ // * Then deletes the database:
+ // #3: IndexedDBFactoryImpl::DeleteDatabase
+ // => IndexedDBDatabase::Create
+ // => IndexedDBBackingStore::CreateIDBDatabaseMetaData
+ // #4: IndexedDBFactoryImpl::DeleteDatabase
+ // => IndexedDBDatabase::DeleteDatabase
+ // => IndexedDBBackingStore::DeleteDatabase
+ // => IndexedDBBackingStore::CleanUpBlobJournal (no-op)
+ // * The test calls open(), to create a new database:
+ // #5: IndexedDBFactoryImpl::Open
+ // => IndexedDBDatabase::Create
+ // => IndexedDBBackingStore::CreateIDBDatabaseMetaData
+ // #6: IndexedDBTransaction::Commit - initial "versionchange" transaction
+ // * Once the connection is opened, the test runs:
+ // #7: IndexedDBTransaction::Commit - the test's "readwrite" transaction)
+ const int instance_num = 7;
+ const int call_num = 1;
+ FailOperation(FAIL_CLASS_LEVELDB_TRANSACTION, FAIL_METHOD_COMMIT_DISK_FULL,
+ instance_num, call_num);
+ SimpleTest(GetTestUrl("indexeddb", "disk_full_on_commit.html"));
+}
+
namespace {
static void CompactIndexedDBBackingStore(
@@ -429,33 +542,35 @@ static void CorruptIndexedDBDatabase(
CompactIndexedDBBackingStore(context, origin_url);
- int numFiles = 0;
- int numErrors = 0;
- base::FilePath idb_data_path = context->GetFilePath(origin_url);
+ int num_files = 0;
+ int num_errors = 0;
const bool recursive = false;
- base::FileEnumerator enumerator(
- idb_data_path, recursive, base::FileEnumerator::FILES);
- for (base::FilePath idb_file = enumerator.Next(); !idb_file.empty();
- idb_file = enumerator.Next()) {
- int64 size(0);
- GetFileSize(idb_file, &size);
-
- if (idb_file.Extension() == FILE_PATH_LITERAL(".ldb")) {
- numFiles++;
- base::File file(idb_file,
- base::File::FLAG_WRITE | base::File::FLAG_OPEN_TRUNCATED);
- if (file.IsValid()) {
- // Was opened truncated, expand back to the original
- // file size and fill with zeros (corrupting the file).
- file.SetLength(size);
- } else {
- numErrors++;
+ for (const base::FilePath& idb_data_path :
+ context->GetStoragePaths(origin_url)) {
+ base::FileEnumerator enumerator(
+ idb_data_path, recursive, base::FileEnumerator::FILES);
+ for (base::FilePath idb_file = enumerator.Next(); !idb_file.empty();
+ idb_file = enumerator.Next()) {
+ int64 size(0);
+ GetFileSize(idb_file, &size);
+
+ if (idb_file.Extension() == FILE_PATH_LITERAL(".ldb")) {
+ num_files++;
+ base::File file(
+ idb_file, base::File::FLAG_WRITE | base::File::FLAG_OPEN_TRUNCATED);
+ if (file.IsValid()) {
+ // Was opened truncated, expand back to the original
+ // file size and fill with zeros (corrupting the file).
+ file.SetLength(size);
+ } else {
+ num_errors++;
+ }
}
}
+ VLOG(0) << "There were " << num_files << " in " << idb_data_path.value()
+ << " with " << num_errors << " errors";
}
- VLOG(0) << "There were " << numFiles << " in " << idb_data_path.value()
- << " with " << numErrors << " errors";
signal_when_finished->Signal();
}
@@ -562,13 +677,13 @@ static scoped_ptr<net::test_server::HttpResponse> CorruptDBRequestHandler(
}
// A request for a test resource
- base::FilePath resourcePath =
+ base::FilePath resource_path =
content::GetTestFilePath("indexeddb", request_path.c_str());
scoped_ptr<net::test_server::BasicHttpResponse> http_response(
new net::test_server::BasicHttpResponse);
http_response->set_code(net::HTTP_OK);
std::string file_contents;
- if (!base::ReadFileToString(resourcePath, &file_contents))
+ if (!base::ReadFileToString(resource_path, &file_contents))
return scoped_ptr<net::test_server::HttpResponse>();
http_response->set_content(file_contents);
return http_response.Pass();
@@ -672,8 +787,16 @@ IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, VersionChangeCrashResilience) {
"pass - part3 - rolled back");
}
+// crbug.com/427529
+// Disable this test for ASAN on Android because it takes too long to run.
+#if defined(ANDROID) && defined(ADDRESS_SANITIZER)
+#define MAYBE_ConnectionsClosedOnTabClose DISABLED_ConnectionsClosedOnTabClose
+#else
+#define MAYBE_ConnectionsClosedOnTabClose ConnectionsClosedOnTabClose
+#endif
// Verify that open DB connections are closed when a tab is destroyed.
-IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, ConnectionsClosedOnTabClose) {
+IN_PROC_BROWSER_TEST_F(
+ IndexedDBBrowserTest, MAYBE_ConnectionsClosedOnTabClose) {
NavigateAndWaitForTitle(shell(), "version_change_blocked.html", "#tab1",
"setVersion(2) complete");
@@ -686,8 +809,7 @@ IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, ConnectionsClosedOnTabClose) {
base::string16 expected_title16(ASCIIToUTF16("setVersion(3) complete"));
TitleWatcher title_watcher(new_shell->web_contents(), expected_title16);
- base::KillProcess(
- shell()->web_contents()->GetRenderProcessHost()->GetHandle(), 0, true);
+ shell()->web_contents()->GetRenderProcessHost()->Shutdown(0, true);
shell()->Close();
EXPECT_EQ(expected_title16, title_watcher.WaitAndGetTitle());
@@ -713,7 +835,7 @@ IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, ForceCloseEventTest) {
class IndexedDBBrowserTestSingleProcess : public IndexedDBBrowserTest {
public:
- void SetUpCommandLine(CommandLine* command_line) override {
+ void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitch(switches::kSingleProcess);
}
};
diff --git a/chromium/content/browser/indexed_db/indexed_db_callbacks.cc b/chromium/content/browser/indexed_db/indexed_db_callbacks.cc
index a5aafddd557..bfd0a8a0d06 100644
--- a/chromium/content/browser/indexed_db/indexed_db_callbacks.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_callbacks.cc
@@ -6,7 +6,6 @@
#include <algorithm>
-#include "base/guid.h"
#include "base/metrics/histogram.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
@@ -19,13 +18,13 @@
#include "content/browser/indexed_db/indexed_db_database_callbacks.h"
#include "content/browser/indexed_db/indexed_db_database_error.h"
#include "content/browser/indexed_db/indexed_db_metadata.h"
+#include "content/browser/indexed_db/indexed_db_return_value.h"
#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 "storage/browser/blob/blob_storage_context.h"
+#include "storage/browser/blob/shareable_file_reference.h"
#include "storage/browser/quota/quota_manager.h"
-#include "storage/common/blob/blob_data.h"
-#include "storage/common/blob/shareable_file_reference.h"
using storage::ShareableFileReference;
@@ -223,15 +222,10 @@ void IndexedDBCallbacks::OnSuccess(scoped_ptr<IndexedDBConnection> connection,
static std::string CreateBlobData(
const IndexedDBBlobInfo& blob_info,
scoped_refptr<IndexedDBDispatcherHost> dispatcher_host,
- storage::BlobStorageContext* blob_storage_context,
base::TaskRunner* task_runner) {
- std::string uuid = blob_info.uuid();
- if (!uuid.empty()) {
+ if (!blob_info.uuid().empty()) {
// We're sending back a live blob, not a reference into our backing store.
- scoped_ptr<storage::BlobDataHandle> blob_data_handle(
- blob_storage_context->GetBlobDataFromUUID(uuid));
- dispatcher_host->HoldBlobDataHandle(uuid, blob_data_handle.Pass());
- return uuid;
+ return dispatcher_host->HoldBlobData(blob_info);
}
scoped_refptr<ShareableFileReference> shareable_file =
ShareableFileReference::Get(blob_info.file_path());
@@ -243,17 +237,7 @@ static std::string CreateBlobData(
if (!blob_info.release_callback().is_null())
shareable_file->AddFinalReleaseCallback(blob_info.release_callback());
}
-
- uuid = base::GenerateGUID();
- 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<storage::BlobDataHandle> blob_data_handle(
- blob_storage_context->AddFinishedBlob(blob_data.get()));
- dispatcher_host->HoldBlobDataHandle(uuid, blob_data_handle.Pass());
-
- return uuid;
+ return dispatcher_host->HoldBlobData(blob_info);
}
static bool CreateAllBlobs(
@@ -268,7 +252,6 @@ static bool CreateAllBlobs(
(*blob_or_file_info)[i].uuid =
CreateBlobData(blob_info[i],
dispatcher_host,
- dispatcher_host->blob_storage_context(),
dispatcher_host->Context()->TaskRunner());
}
return true;
@@ -280,7 +263,7 @@ static void CreateBlobsAndSend(
scoped_refptr<IndexedDBDispatcherHost> dispatcher_host,
const std::vector<IndexedDBBlobInfo>& blob_info,
std::vector<IndexedDBMsg_BlobOrFileInfo>* blob_or_file_info) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (CreateAllBlobs(blob_info, blob_or_file_info, dispatcher_host))
dispatcher_host->Send(new MsgType(*params));
}
@@ -289,21 +272,35 @@ static void BlobLookupForCursorPrefetch(
IndexedDBMsg_CallbacksSuccessCursorPrefetch_Params* params,
scoped_refptr<IndexedDBDispatcherHost> dispatcher_host,
const std::vector<IndexedDBValue>& values) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DCHECK_EQ(values.size(), params->blob_or_file_infos.size());
-
- std::vector<IndexedDBValue>::const_iterator value_iter;
- std::vector<std::vector<IndexedDBMsg_BlobOrFileInfo> >::iterator blob_iter;
- for (value_iter = values.begin(), blob_iter =
- params->blob_or_file_infos.begin(); value_iter != values.end();
- ++value_iter, ++blob_iter) {
- if (!CreateAllBlobs(value_iter->blob_info, &*blob_iter, dispatcher_host))
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK_EQ(values.size(), params->values.size());
+
+ for (size_t i = 0; i < values.size(); ++i) {
+ if (!CreateAllBlobs(values[i].blob_info,
+ &params->values[i].blob_or_file_info, dispatcher_host))
return;
}
+
dispatcher_host->Send(
new IndexedDBMsg_CallbacksSuccessCursorPrefetch(*params));
}
+static void BlobLookupForGetAll(
+ IndexedDBMsg_CallbacksSuccessArray_Params* params,
+ scoped_refptr<IndexedDBDispatcherHost> dispatcher_host,
+ const std::vector<IndexedDBReturnValue>& values) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK_EQ(values.size(), params->values.size());
+
+ for (size_t i = 0; i < values.size(); ++i) {
+ if (!CreateAllBlobs(values[i].blob_info,
+ &params->values[i].blob_or_file_info, dispatcher_host))
+ return;
+ }
+
+ dispatcher_host->Send(new IndexedDBMsg_CallbacksSuccessArray(*params));
+}
+
static void FillInBlobData(
const std::vector<IndexedDBBlobInfo>& blob_info,
std::vector<IndexedDBMsg_BlobOrFileInfo>* blob_or_file_info) {
@@ -358,23 +355,21 @@ void IndexedDBCallbacks::OnSuccess(scoped_refptr<IndexedDBCursor> cursor,
params->key = key;
params->primary_key = primary_key;
if (value && !value->empty())
- std::swap(params->value, value->bits);
+ std::swap(params->value.bits, value->bits);
// TODO(alecflett): Avoid a copy here: the whole params object is
// being copied into the message.
if (!value || value->blob_info.empty()) {
dispatcher_host_->Send(new IndexedDBMsg_CallbacksSuccessIDBCursor(*params));
} else {
IndexedDBMsg_CallbacksSuccessIDBCursor_Params* p = params.get();
- FillInBlobData(value->blob_info, &p->blob_or_file_info);
+ FillInBlobData(value->blob_info, &p->value.blob_or_file_info);
RegisterBlobsAndSend(
value->blob_info,
base::Bind(
CreateBlobsAndSend<IndexedDBMsg_CallbacksSuccessIDBCursor_Params,
IndexedDBMsg_CallbacksSuccessIDBCursor>,
- base::Owned(params.release()),
- dispatcher_host_,
- value->blob_info,
- base::Unretained(&p->blob_or_file_info)));
+ base::Owned(params.release()), dispatcher_host_, value->blob_info,
+ base::Unretained(&p->value.blob_or_file_info)));
}
dispatcher_host_ = NULL;
}
@@ -405,7 +400,7 @@ void IndexedDBCallbacks::OnSuccess(const IndexedDBKey& key,
params->key = key;
params->primary_key = primary_key;
if (value && !value->empty())
- std::swap(params->value, value->bits);
+ std::swap(params->value.bits, value->bits);
// TODO(alecflett): Avoid a copy here: the whole params object is
// being copied into the message.
if (!value || value->blob_info.empty()) {
@@ -413,16 +408,15 @@ void IndexedDBCallbacks::OnSuccess(const IndexedDBKey& key,
new IndexedDBMsg_CallbacksSuccessCursorContinue(*params));
} else {
IndexedDBMsg_CallbacksSuccessCursorContinue_Params* p = params.get();
- FillInBlobData(value->blob_info, &p->blob_or_file_info);
+ FillInBlobData(value->blob_info, &p->value.blob_or_file_info);
RegisterBlobsAndSend(
value->blob_info,
base::Bind(CreateBlobsAndSend<
IndexedDBMsg_CallbacksSuccessCursorContinue_Params,
IndexedDBMsg_CallbacksSuccessCursorContinue>,
- base::Owned(params.release()),
- dispatcher_host_,
+ base::Owned(params.release()), dispatcher_host_,
value->blob_info,
- base::Unretained(&p->blob_or_file_info)));
+ base::Unretained(&p->value.blob_or_file_info)));
}
dispatcher_host_ = NULL;
}
@@ -442,12 +436,12 @@ void IndexedDBCallbacks::OnSuccessWithPrefetch(
DCHECK_EQ(kNoDatabaseCallbacks, ipc_database_callbacks_id_);
DCHECK_EQ(blink::WebIDBDataLossNone, data_loss_);
- std::vector<IndexedDBKey> msgKeys;
- std::vector<IndexedDBKey> msgPrimaryKeys;
+ std::vector<IndexedDBKey> msg_keys;
+ std::vector<IndexedDBKey> msg_primary_keys;
for (size_t i = 0; i < keys.size(); ++i) {
- msgKeys.push_back(keys[i]);
- msgPrimaryKeys.push_back(primary_keys[i]);
+ msg_keys.push_back(keys[i]);
+ msg_primary_keys.push_back(primary_keys[i]);
}
scoped_ptr<IndexedDBMsg_CallbacksSuccessCursorPrefetch_Params> params(
@@ -455,22 +449,18 @@ void IndexedDBCallbacks::OnSuccessWithPrefetch(
params->ipc_thread_id = ipc_thread_id_;
params->ipc_callbacks_id = ipc_callbacks_id_;
params->ipc_cursor_id = ipc_cursor_id_;
- params->keys = msgKeys;
- params->primary_keys = msgPrimaryKeys;
- std::vector<std::string>& values_bits = params->values;
- 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());
+ params->keys = msg_keys;
+ params->primary_keys = msg_primary_keys;
+ params->values.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) {
- values_bits[i].swap(iter->bits);
- if (iter->blob_info.size()) {
+ for (size_t i = 0; i < values->size(); ++i) {
+ params->values[i].bits.swap(values->at(i).bits);
+ if (!values->at(i).blob_info.empty()) {
found_blob_info = true;
- FillInBlobData(iter->blob_info, &values_blob_infos[i]);
- for (const auto& blob_iter : iter->blob_info) {
+ FillInBlobData(values->at(i).blob_info,
+ &params->values[i].blob_or_file_info);
+ for (const auto& blob_iter : values->at(i).blob_info) {
if (!blob_iter.mark_used_callback().is_null())
blob_iter.mark_used_callback().Run();
}
@@ -491,71 +481,86 @@ void IndexedDBCallbacks::OnSuccessWithPrefetch(
dispatcher_host_ = NULL;
}
-void IndexedDBCallbacks::OnSuccess(IndexedDBValue* value,
- const IndexedDBKey& key,
- const IndexedDBKeyPath& key_path) {
+void IndexedDBCallbacks::OnSuccess(IndexedDBReturnValue* value) {
DCHECK(dispatcher_host_.get());
- DCHECK_EQ(kNoCursor, ipc_cursor_id_);
+ if (value && value->primary_key.IsValid()) {
+ DCHECK_EQ(kNoCursor, ipc_cursor_id_);
+ } else {
+ DCHECK(kNoCursor == ipc_cursor_id_ || value == NULL);
+ }
DCHECK_EQ(kNoTransaction, host_transaction_id_);
DCHECK_EQ(kNoDatabase, ipc_database_id_);
DCHECK_EQ(kNoDatabaseCallbacks, ipc_database_callbacks_id_);
DCHECK_EQ(blink::WebIDBDataLossNone, data_loss_);
- scoped_ptr<IndexedDBMsg_CallbacksSuccessValueWithKey_Params> params(
- new IndexedDBMsg_CallbacksSuccessValueWithKey_Params());
+ scoped_ptr<IndexedDBMsg_CallbacksSuccessValue_Params> params(
+ new IndexedDBMsg_CallbacksSuccessValue_Params());
params->ipc_thread_id = ipc_thread_id_;
params->ipc_callbacks_id = ipc_callbacks_id_;
- params->primary_key = key;
- params->key_path = key_path;
+ if (value && value->primary_key.IsValid()) {
+ params->value.primary_key = value->primary_key;
+ params->value.key_path = value->key_path;
+ }
if (value && !value->empty())
- std::swap(params->value, value->bits);
+ std::swap(params->value.bits, value->bits);
if (!value || value->blob_info.empty()) {
- dispatcher_host_->Send(
- new IndexedDBMsg_CallbacksSuccessValueWithKey(*params));
+ dispatcher_host_->Send(new IndexedDBMsg_CallbacksSuccessValue(*params));
} else {
- IndexedDBMsg_CallbacksSuccessValueWithKey_Params* p = params.get();
- FillInBlobData(value->blob_info, &p->blob_or_file_info);
+ IndexedDBMsg_CallbacksSuccessValue_Params* p = params.get();
+ FillInBlobData(value->blob_info, &p->value.blob_or_file_info);
RegisterBlobsAndSend(
value->blob_info,
- base::Bind(
- CreateBlobsAndSend<IndexedDBMsg_CallbacksSuccessValueWithKey_Params,
- IndexedDBMsg_CallbacksSuccessValueWithKey>,
- base::Owned(params.release()),
- dispatcher_host_,
- value->blob_info,
- base::Unretained(&p->blob_or_file_info)));
+ base::Bind(CreateBlobsAndSend<IndexedDBMsg_CallbacksSuccessValue_Params,
+ IndexedDBMsg_CallbacksSuccessValue>,
+ base::Owned(params.release()), dispatcher_host_,
+ value->blob_info,
+ base::Unretained(&p->value.blob_or_file_info)));
}
dispatcher_host_ = NULL;
}
-void IndexedDBCallbacks::OnSuccess(IndexedDBValue* value) {
+void IndexedDBCallbacks::OnSuccessArray(
+ std::vector<IndexedDBReturnValue>* values,
+ const IndexedDBKeyPath& key_path) {
DCHECK(dispatcher_host_.get());
- DCHECK(kNoCursor == ipc_cursor_id_ || value == NULL);
+
DCHECK_EQ(kNoTransaction, host_transaction_id_);
DCHECK_EQ(kNoDatabase, ipc_database_id_);
DCHECK_EQ(kNoDatabaseCallbacks, ipc_database_callbacks_id_);
DCHECK_EQ(blink::WebIDBDataLossNone, data_loss_);
- scoped_ptr<IndexedDBMsg_CallbacksSuccessValue_Params> params(
- new IndexedDBMsg_CallbacksSuccessValue_Params());
+ scoped_ptr<IndexedDBMsg_CallbacksSuccessArray_Params> params(
+ new IndexedDBMsg_CallbacksSuccessArray_Params());
params->ipc_thread_id = ipc_thread_id_;
params->ipc_callbacks_id = ipc_callbacks_id_;
- if (value && !value->empty())
- std::swap(params->value, value->bits);
- if (!value || value->blob_info.empty()) {
- dispatcher_host_->Send(new IndexedDBMsg_CallbacksSuccessValue(*params));
+ params->values.resize(values->size());
+
+ bool found_blob_info = false;
+ for (size_t i = 0; i < values->size(); ++i) {
+ IndexedDBMsg_ReturnValue& pvalue = params->values[i];
+ IndexedDBReturnValue& value = (*values)[i];
+ pvalue.bits.swap(value.bits);
+ if (!value.blob_info.empty()) {
+ found_blob_info = true;
+ FillInBlobData(value.blob_info, &pvalue.blob_or_file_info);
+ for (const auto& blob_info : value.blob_info) {
+ if (!blob_info.mark_used_callback().is_null())
+ blob_info.mark_used_callback().Run();
+ }
+ }
+ pvalue.primary_key = value.primary_key;
+ pvalue.key_path = key_path;
+ }
+
+ if (found_blob_info) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(BlobLookupForGetAll, base::Owned(params.release()),
+ dispatcher_host_, *values));
} else {
- IndexedDBMsg_CallbacksSuccessValue_Params* p = params.get();
- FillInBlobData(value->blob_info, &p->blob_or_file_info);
- RegisterBlobsAndSend(
- value->blob_info,
- base::Bind(CreateBlobsAndSend<IndexedDBMsg_CallbacksSuccessValue_Params,
- IndexedDBMsg_CallbacksSuccessValue>,
- base::Owned(params.release()),
- dispatcher_host_,
- value->blob_info,
- base::Unretained(&p->blob_or_file_info)));
+ dispatcher_host_->Send(
+ new IndexedDBMsg_CallbacksSuccessArray(*params.get()));
}
dispatcher_host_ = NULL;
}
diff --git a/chromium/content/browser/indexed_db/indexed_db_callbacks.h b/chromium/content/browser/indexed_db/indexed_db_callbacks.h
index 4b8a2177a8c..ed61f797cb6 100644
--- a/chromium/content/browser/indexed_db/indexed_db_callbacks.h
+++ b/chromium/content/browser/indexed_db/indexed_db_callbacks.h
@@ -26,6 +26,7 @@ class IndexedDBCursor;
class IndexedDBDatabase;
class IndexedDBDatabaseCallbacks;
struct IndexedDBDatabaseMetadata;
+struct IndexedDBReturnValue;
struct IndexedDBValue;
class CONTENT_EXPORT IndexedDBCallbacks
@@ -85,13 +86,13 @@ class CONTENT_EXPORT IndexedDBCallbacks
const std::vector<IndexedDBKey>& primary_keys,
std::vector<IndexedDBValue>* values);
- // IndexedDBDatabase::Get (with key injection)
- virtual void OnSuccess(IndexedDBValue* value,
- const IndexedDBKey& key,
- const IndexedDBKeyPath& key_path);
-
// IndexedDBDatabase::Get
- virtual void OnSuccess(IndexedDBValue* value);
+ // IndexedDBCursor::Advance
+ virtual void OnSuccess(IndexedDBReturnValue* value);
+
+ // IndexedDBDatabase::GetAll
+ virtual void OnSuccessArray(std::vector<IndexedDBReturnValue>* values,
+ const IndexedDBKeyPath& key_path);
// IndexedDBDatabase::Put / IndexedDBCursor::Update
virtual void OnSuccess(const IndexedDBKey& key);
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 27f72f2b4b5..2b803d0aea3 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
@@ -142,8 +142,9 @@ TEST(IndexedDBNonRecoverableIOErrorTest, NuancedCleanupTest) {
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));
+ busted_factory.SetOpenError(MakeIOError("some filename", "some message",
+ leveldb_env::kNewLogger,
+ base::File::FILE_ERROR_NO_SPACE));
scoped_refptr<IndexedDBBackingStore> backing_store =
IndexedDBBackingStore::Open(factory,
origin,
@@ -176,8 +177,9 @@ TEST(IndexedDBNonRecoverableIOErrorTest, NuancedCleanupTest) {
&s);
ASSERT_TRUE(s.IsIOError());
- busted_factory.SetOpenError(MakeIOError(
- "some filename", "some message", leveldb_env::kNewLogger, EIO));
+ busted_factory.SetOpenError(MakeIOError("some filename", "some message",
+ leveldb_env::kNewLogger,
+ base::File::FILE_ERROR_IO));
scoped_refptr<IndexedDBBackingStore> backing_store3 =
IndexedDBBackingStore::Open(factory,
origin,
diff --git a/chromium/content/browser/indexed_db/indexed_db_connection.cc b/chromium/content/browser/indexed_db/indexed_db_connection.cc
index 3ed927937e8..f7133a69230 100644
--- a/chromium/content/browser/indexed_db/indexed_db_connection.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_connection.cc
@@ -9,25 +9,34 @@ namespace content {
IndexedDBConnection::IndexedDBConnection(
scoped_refptr<IndexedDBDatabase> database,
scoped_refptr<IndexedDBDatabaseCallbacks> callbacks)
- : database_(database), callbacks_(callbacks) {}
+ : database_(database), callbacks_(callbacks), weak_factory_(this) {}
IndexedDBConnection::~IndexedDBConnection() {}
void IndexedDBConnection::Close() {
if (!callbacks_.get())
return;
+ base::WeakPtr<IndexedDBConnection> this_obj = weak_factory_.GetWeakPtr();
database_->Close(this, false /* forced */);
- database_ = NULL;
- callbacks_ = NULL;
+ if (this_obj) {
+ database_ = nullptr;
+ callbacks_ = nullptr;
+ }
}
void IndexedDBConnection::ForceClose() {
if (!callbacks_.get())
return;
+
+ // IndexedDBDatabase::Close() can delete this instance.
+ base::WeakPtr<IndexedDBConnection> this_obj = weak_factory_.GetWeakPtr();
+ scoped_refptr<IndexedDBDatabaseCallbacks> callbacks(callbacks_);
database_->Close(this, true /* forced */);
- database_ = NULL;
- callbacks_->OnForcedClose();
- callbacks_ = NULL;
+ if (this_obj) {
+ database_ = nullptr;
+ callbacks_ = nullptr;
+ }
+ callbacks->OnForcedClose();
}
void IndexedDBConnection::VersionChangeIgnored() {
diff --git a/chromium/content/browser/indexed_db/indexed_db_connection.h b/chromium/content/browser/indexed_db/indexed_db_connection.h
index 096323d7cd0..41925d853cb 100644
--- a/chromium/content/browser/indexed_db/indexed_db_connection.h
+++ b/chromium/content/browser/indexed_db/indexed_db_connection.h
@@ -6,6 +6,7 @@
#define CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_CONNECTION_H_
#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
#include "content/browser/indexed_db/indexed_db_database.h"
#include "content/browser/indexed_db/indexed_db_database_callbacks.h"
@@ -37,6 +38,8 @@ class CONTENT_EXPORT IndexedDBConnection {
// May be NULL in unit tests.
scoped_refptr<IndexedDBDatabaseCallbacks> callbacks_;
+ base::WeakPtrFactory<IndexedDBConnection> weak_factory_;
+
DISALLOW_COPY_AND_ASSIGN(IndexedDBConnection);
};
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 b54d59a46ff..dbc041f2e71 100644
--- a/chromium/content/browser/indexed_db/indexed_db_context_impl.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_context_impl.cc
@@ -44,6 +44,9 @@ namespace content {
const base::FilePath::CharType IndexedDBContextImpl::kIndexedDBDirectory[] =
FILE_PATH_LITERAL("IndexedDB");
+static const base::FilePath::CharType kBlobExtension[] =
+ FILE_PATH_LITERAL(".blob");
+
static const base::FilePath::CharType kIndexedDBExtension[] =
FILE_PATH_LITERAL(".indexeddb");
@@ -139,12 +142,10 @@ std::vector<IndexedDBInfo> IndexedDBContextImpl::GetAllOriginsInfo() {
std::vector<GURL> origins = GetAllOrigins();
std::vector<IndexedDBInfo> result;
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,
GetOriginDiskUsage(origin_url),
GetOriginLastModified(origin_url),
- idb_directory,
connection_count));
}
return result;
@@ -167,8 +168,12 @@ base::ListValue* IndexedDBContextImpl::GetAllOriginsDetails() {
info->SetString("size", ui::FormatBytes(GetOriginDiskUsage(origin_url)));
info->SetDouble("last_modified",
GetOriginLastModified(origin_url).ToJsTime());
- if (!is_incognito())
- info->SetString("path", GetFilePath(origin_url).value());
+ if (!is_incognito()) {
+ scoped_ptr<base::ListValue> paths(new base::ListValue());
+ for (const base::FilePath& path : GetStoragePaths(origin_url))
+ paths->AppendString(path.value());
+ info->Set("paths", paths.release());
+ }
info->SetDouble("connection_count", GetConnectionCount(origin_url));
// This ends up being O(n^2) since we iterate over all open databases
@@ -268,6 +273,19 @@ base::ListValue* IndexedDBContextImpl::GetAllOriginsDetails() {
return list.release();
}
+int IndexedDBContextImpl::GetOriginBlobFileCount(const GURL& origin_url) {
+ DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
+ int count = 0;
+ base::FileEnumerator file_enumerator(
+ GetBlobPath(storage::GetIdentifierFromOrigin(origin_url)), true,
+ base::FileEnumerator::FILES);
+ for (base::FilePath file_path = file_enumerator.Next(); !file_path.empty();
+ file_path = file_enumerator.Next()) {
+ count++;
+ }
+ return count;
+}
+
int64 IndexedDBContextImpl::GetOriginDiskUsage(const GURL& origin_url) {
DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
if (data_path_.empty() || !IsInOriginSet(origin_url))
@@ -280,7 +298,7 @@ base::Time IndexedDBContextImpl::GetOriginLastModified(const GURL& origin_url) {
DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
if (data_path_.empty() || !IsInOriginSet(origin_url))
return base::Time();
- base::FilePath idb_directory = GetFilePath(origin_url);
+ base::FilePath idb_directory = GetLevelDBPath(origin_url);
base::File::Info file_info;
if (!base::GetFileInfo(idb_directory, &file_info))
return base::Time();
@@ -293,7 +311,7 @@ void IndexedDBContextImpl::DeleteForOrigin(const GURL& origin_url) {
if (data_path_.empty() || !IsInOriginSet(origin_url))
return;
- base::FilePath idb_directory = GetFilePath(origin_url);
+ base::FilePath idb_directory = GetLevelDBPath(origin_url);
EnsureDiskUsageCacheInitialized(origin_url);
leveldb::Status s = LevelDBDatabase::Destroy(idb_directory);
if (!s.ok()) {
@@ -306,7 +324,8 @@ void IndexedDBContextImpl::DeleteForOrigin(const GURL& origin_url) {
const bool kNonRecursive = false;
base::DeleteFile(idb_directory, kNonRecursive);
}
-
+ base::DeleteFile(GetBlobPath(storage::GetIdentifierFromOrigin(origin_url)),
+ true /* recursive */);
QueryDiskAndUpdateQuotaUsage(origin_url);
if (s.ok()) {
RemoveFromOriginSet(origin_url);
@@ -315,6 +334,39 @@ void IndexedDBContextImpl::DeleteForOrigin(const GURL& origin_url) {
}
}
+void IndexedDBContextImpl::CopyOriginData(const GURL& origin_url,
+ IndexedDBContext* dest_context) {
+ DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
+
+ if (data_path_.empty() || !IsInOriginSet(origin_url))
+ return;
+
+ IndexedDBContextImpl* dest_context_impl =
+ static_cast<IndexedDBContextImpl*>(dest_context);
+
+ ForceClose(origin_url, FORCE_CLOSE_COPY_ORIGIN);
+ std::string origin_id = storage::GetIdentifierFromOrigin(origin_url);
+
+ // Make sure we're not about to delete our own database.
+ CHECK_NE(dest_context_impl->data_path().value(), data_path().value());
+
+ // Delete any existing storage paths in the destination context.
+ // A previously failed migration may have left behind partially copied
+ // directories.
+ for (const base::FilePath& dest_path :
+ dest_context_impl->GetStoragePaths(origin_url))
+ base::DeleteFile(dest_path, true);
+
+ base::FilePath dest_data_path = dest_context_impl->data_path();
+ base::CreateDirectory(dest_data_path);
+
+ for (const base::FilePath& src_data_path : GetStoragePaths(origin_url)) {
+ if (base::PathExists(src_data_path)) {
+ base::CopyDirectory(src_data_path, dest_data_path, true);
+ }
+ }
+}
+
void IndexedDBContextImpl::ForceClose(const GURL origin_url,
ForceCloseReason reason) {
DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
@@ -341,14 +393,24 @@ size_t IndexedDBContextImpl::GetConnectionCount(const GURL& origin_url) {
return factory_->GetConnectionCount(origin_url);
}
-base::FilePath IndexedDBContextImpl::GetFilePath(const GURL& origin_url) const {
+base::FilePath IndexedDBContextImpl::GetLevelDBPath(
+ const GURL& origin_url) const {
std::string origin_id = storage::GetIdentifierFromOrigin(origin_url);
- return GetIndexedDBFilePath(origin_id);
+ return GetLevelDBPath(origin_id);
+}
+
+std::vector<base::FilePath> IndexedDBContextImpl::GetStoragePaths(
+ const GURL& origin_url) const {
+ std::string origin_id = storage::GetIdentifierFromOrigin(origin_url);
+ std::vector<base::FilePath> paths;
+ paths.push_back(GetLevelDBPath(origin_id));
+ paths.push_back(GetBlobPath(origin_id));
+ return paths;
}
base::FilePath IndexedDBContextImpl::GetFilePathForTesting(
const std::string& origin_id) const {
- return GetIndexedDBFilePath(origin_id);
+ return GetLevelDBPath(origin_id);
}
void IndexedDBContextImpl::SetTaskRunnerForTesting(
@@ -446,7 +508,14 @@ IndexedDBContextImpl::~IndexedDBContextImpl() {
&ClearSessionOnlyOrigins, data_path_, special_storage_policy_));
}
-base::FilePath IndexedDBContextImpl::GetIndexedDBFilePath(
+base::FilePath IndexedDBContextImpl::GetBlobPath(
+ const std::string& origin_id) const {
+ DCHECK(!data_path_.empty());
+ return data_path_.AppendASCII(origin_id).AddExtension(kIndexedDBExtension)
+ .AddExtension(kBlobExtension);
+}
+
+base::FilePath IndexedDBContextImpl::GetLevelDBPath(
const std::string& origin_id) const {
DCHECK(!data_path_.empty());
return data_path_.AppendASCII(origin_id).AddExtension(kIndexedDBExtension)
@@ -456,8 +525,10 @@ base::FilePath IndexedDBContextImpl::GetIndexedDBFilePath(
int64 IndexedDBContextImpl::ReadUsageFromDisk(const GURL& origin_url) const {
if (data_path_.empty())
return 0;
- base::FilePath file_path = GetFilePath(origin_url);
- return base::ComputeDirectorySize(file_path);
+ int64 total_size = 0;
+ for (const base::FilePath& path : GetStoragePaths(origin_url))
+ total_size += base::ComputeDirectorySize(path);
+ return total_size;
}
void IndexedDBContextImpl::EnsureDiskUsageCacheInitialized(
@@ -488,7 +559,7 @@ void IndexedDBContextImpl::GotUsageAndQuota(const GURL& origin_url,
storage::QuotaStatusCode status,
int64 usage,
int64 quota) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(status == storage::kQuotaStatusOk ||
status == storage::kQuotaErrorAbort)
<< "status was " << status;
@@ -523,7 +594,7 @@ void IndexedDBContextImpl::QueryAvailableQuota(const GURL& origin_url) {
}
return;
}
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!quota_manager_proxy() || !quota_manager_proxy()->quota_manager())
return;
quota_manager_proxy()->quota_manager()->GetUsageAndQuota(
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 8fff76c7a30..2955a3a2cf1 100644
--- a/chromium/content/browser/indexed_db/indexed_db_context_impl.h
+++ b/chromium/content/browser/indexed_db/indexed_db_context_impl.h
@@ -45,6 +45,7 @@ class CONTENT_EXPORT IndexedDBContextImpl
FORCE_CLOSE_DELETE_ORIGIN = 0,
FORCE_CLOSE_BACKING_STORE_FAILURE,
FORCE_CLOSE_INTERNALS_PAGE,
+ FORCE_CLOSE_COPY_ORIGIN,
FORCE_CLOSE_REASON_MAX
};
@@ -67,6 +68,8 @@ class CONTENT_EXPORT IndexedDBContextImpl
std::vector<IndexedDBInfo> GetAllOriginsInfo() override;
int64 GetOriginDiskUsage(const GURL& origin_url) override;
void DeleteForOrigin(const GURL& origin_url) override;
+ void CopyOriginData(const GURL& origin_url,
+ IndexedDBContext* dest_context) override;
base::FilePath GetFilePathForTesting(
const std::string& origin_id) const override;
void SetTaskRunnerForTesting(base::SequencedTaskRunner* task_runner) override;
@@ -88,14 +91,17 @@ class CONTENT_EXPORT IndexedDBContextImpl
// ForceClose takes a value rather than a reference since it may release the
// owning object.
void ForceClose(const GURL origin_url, ForceCloseReason reason);
+ // GetStoragePaths returns all paths owned by this database, in arbitrary
+ // order.
+ std::vector<base::FilePath> GetStoragePaths(const GURL& origin_url) const;
- base::FilePath GetFilePath(const GURL& origin_url) const;
base::FilePath data_path() const { return data_path_; }
bool IsInOriginSet(const GURL& origin_url) {
std::set<GURL>* set = GetOriginSet();
return set->find(origin_url) != set->end();
}
size_t GetConnectionCount(const GURL& origin_url);
+ int GetOriginBlobFileCount(const GURL& origin_url);
// For unit tests allow to override the |data_path_|.
void set_data_path_for_testing(const base::FilePath& data_path) {
@@ -117,7 +123,9 @@ class CONTENT_EXPORT IndexedDBContextImpl
typedef std::map<GURL, int64> OriginToSizeMap;
class IndexedDBGetUsageAndQuotaCallback;
- base::FilePath GetIndexedDBFilePath(const std::string& origin_id) const;
+ base::FilePath GetBlobPath(const std::string& origin_id) const;
+ base::FilePath GetLevelDBPath(const GURL& origin_url) const;
+ base::FilePath GetLevelDBPath(const std::string& origin_id) const;
int64 ReadUsageFromDisk(const GURL& origin_url) const;
void EnsureDiskUsageCacheInitialized(const GURL& origin_url);
void QueryDiskAndUpdateQuotaUsage(const GURL& origin_url);
diff --git a/chromium/content/browser/indexed_db/indexed_db_cursor.cc b/chromium/content/browser/indexed_db/indexed_db_cursor.cc
index 4fc3c0ea44e..7172dab8f93 100644
--- a/chromium/content/browser/indexed_db/indexed_db_cursor.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_cursor.cc
@@ -68,7 +68,7 @@ void IndexedDBCursor::CursorAdvanceOperation(
// will be ignored.
if (!cursor_ || !cursor_->Advance(count, &s)) {
cursor_.reset();
- callbacks->OnSuccess(static_cast<IndexedDBValue*>(NULL));
+ callbacks->OnSuccess(nullptr);
return;
}
@@ -90,7 +90,7 @@ void IndexedDBCursor::CursorIterationOperation(
IndexedDBBackingStore::Cursor::SEEK,
&s) || !s.ok()) {
cursor_.reset();
- callbacks->OnSuccess(static_cast<IndexedDBValue*>(NULL));
+ callbacks->OnSuccess(nullptr);
return;
}
@@ -121,6 +121,7 @@ void IndexedDBCursor::CursorPrefetchIterationOperation(
std::vector<IndexedDBValue> found_values;
saved_cursor_.reset();
+ // TODO(cmumford): Use IPC::Channel::kMaximumMessageSize
const size_t max_size_estimate = 10 * 1024 * 1024;
size_t size_estimate = 0;
leveldb::Status s;
@@ -165,7 +166,7 @@ void IndexedDBCursor::CursorPrefetchIterationOperation(
}
if (!found_keys.size()) {
- callbacks->OnSuccess(static_cast<IndexedDBValue*>(NULL));
+ callbacks->OnSuccess(nullptr);
return;
}
diff --git a/chromium/content/browser/indexed_db/indexed_db_cursor.h b/chromium/content/browser/indexed_db/indexed_db_cursor.h
index a0f42000b0c..9dc172a4cea 100644
--- a/chromium/content/browser/indexed_db/indexed_db_cursor.h
+++ b/chromium/content/browser/indexed_db/indexed_db_cursor.h
@@ -13,7 +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"
+#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBTypes.h"
namespace content {
diff --git a/chromium/content/browser/indexed_db/indexed_db_database.cc b/chromium/content/browser/indexed_db/indexed_db_database.cc
index 905cf061f3a..8a924eb43d3 100644
--- a/chromium/content/browser/indexed_db/indexed_db_database.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_database.cc
@@ -5,12 +5,14 @@
#include "content/browser/indexed_db/indexed_db_database.h"
#include <math.h>
+#include <limits>
#include <set>
#include "base/auto_reset.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
+#include "base/metrics/histogram_macros.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
@@ -21,13 +23,15 @@
#include "content/browser/indexed_db/indexed_db_factory.h"
#include "content/browser/indexed_db/indexed_db_index_writer.h"
#include "content/browser/indexed_db/indexed_db_pending_connection.h"
+#include "content/browser/indexed_db/indexed_db_return_value.h"
#include "content/browser/indexed_db/indexed_db_tracing.h"
#include "content/browser/indexed_db/indexed_db_transaction.h"
#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_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/WebKit/public/platform/modules/indexeddb/WebIDBDatabaseException.h"
#include "third_party/leveldatabase/env_chromium.h"
using base::ASCIIToUTF16;
@@ -36,6 +40,34 @@ using blink::WebIDBKeyTypeNumber;
namespace content {
+namespace {
+
+// Used for WebCore.IndexedDB.Schema.ObjectStore.KeyPathType and
+// WebCore.IndexedDB.Schema.Index.KeyPathType histograms. Do not
+// modify (delete, re-order, renumber) these values other than
+// the _MAX value.
+enum HistogramIDBKeyPathType {
+ KEY_PATH_TYPE_NONE = 0,
+ KEY_PATH_TYPE_STRING = 1,
+ KEY_PATH_TYPE_ARRAY = 2,
+ KEY_PATH_TYPE_MAX = 3, // Keep as last/max entry, for histogram range.
+};
+
+HistogramIDBKeyPathType HistogramKeyPathType(const IndexedDBKeyPath& key_path) {
+ switch (key_path.type()) {
+ case blink::WebIDBKeyPathTypeNull:
+ return KEY_PATH_TYPE_NONE;
+ case blink::WebIDBKeyPathTypeString:
+ return KEY_PATH_TYPE_STRING;
+ case blink::WebIDBKeyPathTypeArray:
+ return KEY_PATH_TYPE_ARRAY;
+ }
+ NOTREACHED();
+ return KEY_PATH_TYPE_NONE;
+}
+
+} // namespace
+
// PendingUpgradeCall has a scoped_ptr<IndexedDBConnection> because it owns the
// in-progress connection.
class IndexedDBDatabase::PendingUpgradeCall {
@@ -279,6 +311,11 @@ void IndexedDBDatabase::CreateObjectStore(int64 transaction_id,
return;
}
+ UMA_HISTOGRAM_ENUMERATION("WebCore.IndexedDB.Schema.ObjectStore.KeyPathType",
+ HistogramKeyPathType(key_path), KEY_PATH_TYPE_MAX);
+ UMA_HISTOGRAM_BOOLEAN("WebCore.IndexedDB.Schema.ObjectStore.AutoIncrement",
+ auto_increment);
+
// Store creation is done synchronously, as it may be followed by
// index creation (also sync) since preemptive OpenCursor/SetIndexKeys
// may follow.
@@ -302,7 +339,7 @@ void IndexedDBDatabase::CreateObjectStore(int64 transaction_id,
ASCIIToUTF16("Internal error creating object store '") +
object_store_metadata.name + ASCIIToUTF16("'."));
transaction->Abort(error);
- if (leveldb_env::IsCorruption(s))
+ if (s.IsCorruption())
factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
error);
return;
@@ -348,6 +385,12 @@ void IndexedDBDatabase::CreateIndex(int64 transaction_id,
if (!ValidateObjectStoreIdAndNewIndexId(object_store_id, index_id))
return;
+ UMA_HISTOGRAM_ENUMERATION("WebCore.IndexedDB.Schema.Index.KeyPathType",
+ HistogramKeyPathType(key_path), KEY_PATH_TYPE_MAX);
+ UMA_HISTOGRAM_BOOLEAN("WebCore.IndexedDB.Schema.Index.Unique", unique);
+ UMA_HISTOGRAM_BOOLEAN("WebCore.IndexedDB.Schema.Index.MultiEntry",
+ multi_entry);
+
// Index creation is done synchronously since preemptive
// OpenCursor/SetIndexKeys may follow.
const IndexedDBIndexMetadata index_metadata(
@@ -429,7 +472,7 @@ void IndexedDBDatabase::DeleteIndexOperation(
IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
error_string);
transaction->Abort(error);
- if (leveldb_env::IsCorruption(s))
+ if (s.IsCorruption())
factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
error);
return;
@@ -490,6 +533,24 @@ void IndexedDBDatabase::Abort(int64 transaction_id,
transaction->Abort(error);
}
+void IndexedDBDatabase::GetAll(int64 transaction_id,
+ int64 object_store_id,
+ scoped_ptr<IndexedDBKeyRange> key_range,
+ int64 max_count,
+ scoped_refptr<IndexedDBCallbacks> callbacks) {
+ IDB_TRACE1("IndexedDBDatabase::GetAll", "txn.id", transaction_id);
+ IndexedDBTransaction* transaction = GetTransaction(transaction_id);
+ if (!transaction)
+ return;
+
+ if (!ValidateObjectStoreId(object_store_id))
+ return;
+
+ transaction->ScheduleTask(
+ base::Bind(&IndexedDBDatabase::GetAllOperation, this, object_store_id,
+ Passed(&key_range), max_count, callbacks));
+}
+
void IndexedDBDatabase::Get(int64 transaction_id,
int64 object_store_id,
int64 index_id,
@@ -571,7 +632,7 @@ void IndexedDBDatabase::GetOperation(
DLOG(ERROR) << "Unable to open cursor operation: " << s.ToString();
IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
"Internal error deleting data in range");
- if (leveldb_env::IsCorruption(s)) {
+ if (s.IsCorruption()) {
factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
error);
}
@@ -588,7 +649,7 @@ void IndexedDBDatabase::GetOperation(
scoped_ptr<IndexedDBKey> primary_key;
if (index_id == IndexedDBIndexMetadata::kInvalidId) {
// Object Store Retrieval Operation
- IndexedDBValue value;
+ IndexedDBReturnValue value;
s = backing_store_->GetRecord(transaction->BackingStoreTransaction(),
id(),
object_store_id,
@@ -599,7 +660,7 @@ void IndexedDBDatabase::GetOperation(
"Internal error in GetRecord.");
callbacks->OnError(error);
- if (leveldb_env::IsCorruption(s))
+ if (s.IsCorruption())
factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
error);
return;
@@ -612,8 +673,8 @@ void IndexedDBDatabase::GetOperation(
if (object_store_metadata.auto_increment &&
!object_store_metadata.key_path.IsNull()) {
- callbacks->OnSuccess(&value, *key, object_store_metadata.key_path);
- return;
+ value.primary_key = *key;
+ value.key_path = object_store_metadata.key_path;
}
callbacks->OnSuccess(&value);
@@ -632,7 +693,7 @@ void IndexedDBDatabase::GetOperation(
IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
"Internal error in GetPrimaryKeyViaIndex.");
callbacks->OnError(error);
- if (leveldb_env::IsCorruption(s))
+ if (s.IsCorruption())
factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
error);
return;
@@ -648,7 +709,7 @@ void IndexedDBDatabase::GetOperation(
}
// Index Referenced Value Retrieval Operation
- IndexedDBValue value;
+ IndexedDBReturnValue value;
s = backing_store_->GetRecord(transaction->BackingStoreTransaction(),
id(),
object_store_id,
@@ -658,7 +719,7 @@ void IndexedDBDatabase::GetOperation(
IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
"Internal error in GetRecord.");
callbacks->OnError(error);
- if (leveldb_env::IsCorruption(s))
+ if (s.IsCorruption())
factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
error);
return;
@@ -670,12 +731,102 @@ void IndexedDBDatabase::GetOperation(
}
if (object_store_metadata.auto_increment &&
!object_store_metadata.key_path.IsNull()) {
- callbacks->OnSuccess(&value, *primary_key, object_store_metadata.key_path);
- return;
+ value.primary_key = *primary_key;
+ value.key_path = object_store_metadata.key_path;
}
callbacks->OnSuccess(&value);
}
+void IndexedDBDatabase::GetAllOperation(
+ int64 object_store_id,
+ scoped_ptr<IndexedDBKeyRange> key_range,
+ int64 max_count,
+ scoped_refptr<IndexedDBCallbacks> callbacks,
+ IndexedDBTransaction* transaction) {
+ IDB_TRACE1("IndexedDBDatabase::GetAllOperation", "txn.id", transaction->id());
+
+ DCHECK_GT(max_count, 0);
+
+ DCHECK(metadata_.object_stores.find(object_store_id) !=
+ metadata_.object_stores.end());
+ const IndexedDBObjectStoreMetadata& object_store_metadata =
+ metadata_.object_stores[object_store_id];
+
+ leveldb::Status s;
+
+ scoped_ptr<IndexedDBBackingStore::Cursor> cursor =
+ backing_store_->OpenObjectStoreCursor(
+ transaction->BackingStoreTransaction(), id(), object_store_id,
+ *key_range, blink::WebIDBCursorDirectionNext, &s);
+
+ if (!s.ok()) {
+ DLOG(ERROR) << "Unable to open cursor operation: " << s.ToString();
+ IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
+ "Internal error in GetAllOperation");
+ callbacks->OnError(error);
+ if (s.IsCorruption()) {
+ factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
+ error);
+ }
+ return;
+ }
+
+ std::vector<IndexedDBReturnValue> found_values;
+ if (!cursor) {
+ callbacks->OnSuccessArray(&found_values, object_store_metadata.key_path);
+ return;
+ }
+
+ bool did_first_seek = false;
+ bool generated_key = object_store_metadata.auto_increment &&
+ !object_store_metadata.key_path.IsNull();
+
+ size_t response_size = kMaxIDBMessageOverhead;
+ do {
+ bool cursor_valid;
+ if (did_first_seek) {
+ cursor_valid = cursor->Continue(&s);
+ } else {
+ cursor_valid = cursor->FirstSeek(&s);
+ did_first_seek = true;
+ }
+ if (!s.ok()) {
+ IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
+ "Internal error in GetAllOperation.");
+ callbacks->OnError(error);
+
+ if (s.IsCorruption())
+ factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
+ error);
+ return;
+ }
+
+ if (!cursor_valid)
+ break;
+
+ IndexedDBReturnValue return_value;
+ return_value.swap(*cursor->value());
+
+ size_t value_estimated_size = return_value.SizeEstimate();
+
+ if (generated_key) {
+ return_value.primary_key = cursor->primary_key();
+ value_estimated_size += return_value.primary_key.size_estimate();
+ }
+
+ if (response_size + value_estimated_size >
+ IPC::Channel::kMaximumMessageSize) {
+ // TODO(cmumford): Reach this limit in more gracefully (crbug.com/478949)
+ break;
+ }
+
+ found_values.push_back(return_value);
+ response_size += value_estimated_size;
+ } while (found_values.size() < static_cast<size_t>(max_count));
+
+ callbacks->OnSuccessArray(&found_values, object_store_metadata.key_path);
+}
+
static scoped_ptr<IndexedDBKey> GenerateKey(
IndexedDBBackingStore* backing_store,
IndexedDBTransaction* transaction,
@@ -804,7 +955,7 @@ void IndexedDBDatabase::PutOperation(scoped_ptr<PutOperationParams> params,
IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
"Internal error checking key existence.");
params->callbacks->OnError(error);
- if (leveldb_env::IsCorruption(s))
+ if (s.IsCorruption())
factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
error);
return;
@@ -857,7 +1008,7 @@ void IndexedDBDatabase::PutOperation(scoped_ptr<PutOperationParams> params,
blink::WebIDBDatabaseExceptionUnknownError,
"Internal error: backing store error performing put/add.");
params->callbacks->OnError(error);
- if (leveldb_env::IsCorruption(s))
+ if (s.IsCorruption())
factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
error);
return;
@@ -885,7 +1036,7 @@ void IndexedDBDatabase::PutOperation(scoped_ptr<PutOperationParams> params,
IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
"Internal error updating key generator.");
params->callbacks->OnError(error);
- if (leveldb_env::IsCorruption(s))
+ if (s.IsCorruption())
factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
error);
return;
@@ -920,7 +1071,7 @@ void IndexedDBDatabase::SetIndexKeys(int64 transaction_id,
IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
"Internal error setting index keys.");
transaction->Abort(error);
- if (leveldb_env::IsCorruption(s))
+ if (s.IsCorruption())
factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
error);
return;
@@ -1102,7 +1253,7 @@ void IndexedDBDatabase::OpenCursorOperation(
DLOG(ERROR) << "Unable to open cursor operation: " << s.ToString();
IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
"Internal error opening cursor operation");
- if (leveldb_env::IsCorruption(s)) {
+ if (s.IsCorruption()) {
factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
error);
}
@@ -1110,7 +1261,7 @@ void IndexedDBDatabase::OpenCursorOperation(
if (!backing_store_cursor) {
// Why is Success being called?
- params->callbacks->OnSuccess(static_cast<IndexedDBValue*>(NULL));
+ params->callbacks->OnSuccess(nullptr);
return;
}
@@ -1177,7 +1328,7 @@ void IndexedDBDatabase::CountOperation(
DLOG(ERROR) << "Unable perform count operation: " << s.ToString();
IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
"Internal error performing count operation");
- if (leveldb_env::IsCorruption(s)) {
+ if (s.IsCorruption()) {
factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
error);
}
@@ -1235,7 +1386,7 @@ void IndexedDBDatabase::DeleteRangeOperation(
IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
error_string);
transaction->Abort(error);
- if (leveldb_env::IsCorruption(s)) {
+ if (s.IsCorruption()) {
factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
error);
}
@@ -1271,7 +1422,7 @@ void IndexedDBDatabase::ClearOperation(
IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
"Internal error clearing object store");
callbacks->OnError(error);
- if (leveldb_env::IsCorruption(s)) {
+ if (s.IsCorruption()) {
factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
error);
}
@@ -1300,7 +1451,7 @@ void IndexedDBDatabase::DeleteObjectStoreOperation(
IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
error_string);
transaction->Abort(error);
- if (leveldb_env::IsCorruption(s))
+ if (s.IsCorruption())
factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
error);
return;
@@ -1706,6 +1857,9 @@ void IndexedDBDatabase::Close(IndexedDBConnection* connection, bool forced) {
DCHECK(connection->database() == this);
IDB_TRACE("IndexedDBDatabase::Close");
+
+ connections_.erase(connection);
+
// Abort outstanding transactions from the closing connection. This
// can not happen if the close is requested by the connection itself
// as the front-end defers the close until all transactions are
@@ -1720,7 +1874,6 @@ void IndexedDBDatabase::Close(IndexedDBConnection* connection, bool forced) {
}
}
- connections_.erase(connection);
if (pending_second_half_open_ &&
pending_second_half_open_->connection() == connection) {
pending_second_half_open_->callbacks()->OnError(
diff --git a/chromium/content/browser/indexed_db/indexed_db_database.h b/chromium/content/browser/indexed_db/indexed_db_database.h
index bcde7190c50..ee941dbb8c9 100644
--- a/chromium/content/browser/indexed_db/indexed_db_database.h
+++ b/chromium/content/browser/indexed_db/indexed_db_database.h
@@ -20,7 +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 "third_party/WebKit/public/platform/modules/indexeddb/WebIDBTypes.h"
#include "url/gurl.h"
namespace content {
@@ -122,6 +122,11 @@ class CONTENT_EXPORT IndexedDBDatabase
scoped_ptr<IndexedDBKeyRange> key_range,
bool key_only,
scoped_refptr<IndexedDBCallbacks> callbacks);
+ void GetAll(int64 transaction_id,
+ int64 object_store_id,
+ scoped_ptr<IndexedDBKeyRange> key_range,
+ int64 max_count,
+ scoped_refptr<IndexedDBCallbacks> callbacks);
void Put(int64 transaction_id,
int64 object_store_id,
IndexedDBValue* value,
@@ -200,6 +205,11 @@ class CONTENT_EXPORT IndexedDBDatabase
indexed_db::CursorType cursor_type,
scoped_refptr<IndexedDBCallbacks> callbacks,
IndexedDBTransaction* transaction);
+ void GetAllOperation(int64 object_store_id,
+ scoped_ptr<IndexedDBKeyRange> key_range,
+ int64 max_count,
+ scoped_refptr<IndexedDBCallbacks> callbacks,
+ IndexedDBTransaction* transaction);
struct PutOperationParams;
void PutOperation(scoped_ptr<PutOperationParams> params,
IndexedDBTransaction* transaction);
diff --git a/chromium/content/browser/indexed_db/indexed_db_database_error.cc b/chromium/content/browser/indexed_db/indexed_db_database_error.cc
new file mode 100644
index 00000000000..ff05a779392
--- /dev/null
+++ b/chromium/content/browser/indexed_db/indexed_db_database_error.cc
@@ -0,0 +1,28 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/indexed_db/indexed_db_database_error.h"
+
+namespace content {
+
+IndexedDBDatabaseError::IndexedDBDatabaseError(uint16 code) : code_(code) {
+}
+
+IndexedDBDatabaseError::IndexedDBDatabaseError() = default;
+
+IndexedDBDatabaseError::IndexedDBDatabaseError(uint16 code, const char* message)
+ : code_(code), message_(base::ASCIIToUTF16(message)) {
+}
+
+IndexedDBDatabaseError::IndexedDBDatabaseError(uint16 code,
+ const base::string16& message)
+ : code_(code), message_(message) {
+}
+
+IndexedDBDatabaseError::~IndexedDBDatabaseError() = default;
+
+IndexedDBDatabaseError& IndexedDBDatabaseError::operator=(
+ const IndexedDBDatabaseError& rhs) = default;
+
+} // namespace content
diff --git a/chromium/content/browser/indexed_db/indexed_db_database_error.h b/chromium/content/browser/indexed_db/indexed_db_database_error.h
index 25b5ea6ed1c..7b233f028fd 100644
--- a/chromium/content/browser/indexed_db/indexed_db_database_error.h
+++ b/chromium/content/browser/indexed_db/indexed_db_database_error.h
@@ -13,21 +13,20 @@ namespace content {
class IndexedDBDatabaseError {
public:
- explicit IndexedDBDatabaseError(uint16 code) : code_(code) {}
- IndexedDBDatabaseError(uint16 code, const char* message)
- : code_(code), message_(base::ASCIIToUTF16(message)) {}
- IndexedDBDatabaseError(uint16 code, const base::string16& message)
- : code_(code), message_(message) {}
- ~IndexedDBDatabaseError() {}
+ IndexedDBDatabaseError();
+ explicit IndexedDBDatabaseError(uint16 code);
+ IndexedDBDatabaseError(uint16 code, const char* message);
+ IndexedDBDatabaseError(uint16 code, const base::string16& message);
+ ~IndexedDBDatabaseError();
+
+ IndexedDBDatabaseError& operator=(const IndexedDBDatabaseError& rhs);
uint16 code() const { return code_; }
const base::string16& message() const { return message_; }
private:
- const uint16 code_;
- const base::string16 message_;
-
- DISALLOW_COPY_AND_ASSIGN(IndexedDBDatabaseError);
+ uint16 code_ = 0;
+ base::string16 message_;
};
} // namespace content
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 3584f03e83a..5284af054ff 100644
--- a/chromium/content/browser/indexed_db/indexed_db_dispatcher_host.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_dispatcher_host.cc
@@ -7,6 +7,7 @@
#include "base/bind.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
+#include "base/guid.h"
#include "base/memory/scoped_vector.h"
#include "base/process/process.h"
#include "base/stl_util.h"
@@ -26,10 +27,11 @@
#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_data_builder.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 "third_party/WebKit/public/platform/modules/indexeddb/WebIDBDatabaseException.h"
#include "url/gurl.h"
using storage::DatabaseUtil;
@@ -69,7 +71,8 @@ IndexedDBDispatcherHost::IndexedDBDispatcherHost(
}
IndexedDBDispatcherHost::~IndexedDBDispatcherHost() {
- STLDeleteValues(&blob_data_handle_map_);
+ for (auto& iter : blob_data_handle_map_)
+ delete iter.second.first;
}
void IndexedDBDispatcherHost::OnChannelConnected(int32 peer_pid) {
@@ -118,10 +121,16 @@ void IndexedDBDispatcherHost::ResetDispatcherHosts() {
base::TaskRunner* IndexedDBDispatcherHost::OverrideTaskRunnerForMessage(
const IPC::Message& message) {
- if (IPC_MESSAGE_CLASS(message) == IndexedDBMsgStart &&
- message.type() != IndexedDBHostMsg_DatabasePut::ID)
- return indexed_db_context_->TaskRunner();
- return NULL;
+ if (IPC_MESSAGE_CLASS(message) != IndexedDBMsgStart)
+ return NULL;
+
+ switch (message.type()) {
+ case IndexedDBHostMsg_DatabasePut::ID:
+ case IndexedDBHostMsg_AckReceivedBlobs::ID:
+ return NULL;
+ default:
+ return indexed_db_context_->TaskRunner();
+ }
}
bool IndexedDBDispatcherHost::OnMessageReceived(const IPC::Message& message) {
@@ -129,7 +138,8 @@ bool IndexedDBDispatcherHost::OnMessageReceived(const IPC::Message& message) {
return false;
DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread() ||
- message.type() == IndexedDBHostMsg_DatabasePut::ID);
+ (message.type() == IndexedDBHostMsg_DatabasePut::ID ||
+ message.type() == IndexedDBHostMsg_AckReceivedBlobs::ID));
bool handled = database_dispatcher_host_->OnMessageReceived(message) ||
cursor_dispatcher_host_->OnMessageReceived(message);
@@ -184,8 +194,8 @@ int64 IndexedDBDispatcherHost::HostTransactionId(int64 transaction_id) {
// transaction_id are guaranteed to be unique within that renderer.
base::ProcessId pid = peer_pid();
DCHECK(!(transaction_id >> 32)) << "Transaction ids can only be 32 bits";
- COMPILE_ASSERT(sizeof(base::ProcessId) <= sizeof(int32),
- Process_ID_must_fit_in_32_bits);
+ static_assert(sizeof(base::ProcessId) <= sizeof(int32),
+ "Process ID must fit in 32 bits");
return transaction_id | (static_cast<uint64>(pid) << 32);
}
@@ -209,18 +219,44 @@ uint32 IndexedDBDispatcherHost::TransactionIdToProcessId(
return (host_transaction_id >> 32) & 0xffffffff;
}
-void IndexedDBDispatcherHost::HoldBlobDataHandle(
- const std::string& uuid,
- scoped_ptr<storage::BlobDataHandle> blob_data_handle) {
+std::string IndexedDBDispatcherHost::HoldBlobData(
+ const IndexedDBBlobInfo& blob_info) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ std::string uuid = blob_info.uuid();
+ storage::BlobStorageContext* context = blob_storage_context_->context();
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle;
+ if (uuid.empty()) {
+ uuid = base::GenerateGUID();
+ storage::BlobDataBuilder blob_data_builder(uuid);
+ blob_data_builder.set_content_type(base::UTF16ToUTF8(blob_info.type()));
+ blob_data_builder.AppendFile(blob_info.file_path(), 0, blob_info.size(),
+ blob_info.last_modified());
+ blob_data_handle = context->AddFinishedBlob(&blob_data_builder);
+ } else {
+ auto iter = blob_data_handle_map_.find(uuid);
+ if (iter != blob_data_handle_map_.end()) {
+ iter->second.second += 1;
+ return uuid;
+ }
+ blob_data_handle = context->GetBlobDataFromUUID(uuid);
+ }
+
DCHECK(!ContainsKey(blob_data_handle_map_, uuid));
- blob_data_handle_map_[uuid] = blob_data_handle.release();
+ blob_data_handle_map_[uuid] = std::make_pair(blob_data_handle.release(), 1);
+ return uuid;
}
-void IndexedDBDispatcherHost::DropBlobDataHandle(const std::string& uuid) {
+void IndexedDBDispatcherHost::DropBlobData(const std::string& uuid) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
BlobDataHandleMap::iterator iter = blob_data_handle_map_.find(uuid);
if (iter != blob_data_handle_map_.end()) {
- delete iter->second;
- blob_data_handle_map_.erase(iter);
+ DCHECK_GE(iter->second.second, 1);
+ if (iter->second.second == 1) {
+ delete iter->second.first;
+ blob_data_handle_map_.erase(iter);
+ } else {
+ iter->second.second -= 1;
+ }
} else {
DLOG(FATAL) << "Failed to find blob UUID in map:" << uuid;
}
@@ -246,8 +282,8 @@ IndexedDBCursor* IndexedDBDispatcherHost::GetCursorFromId(int32 ipc_cursor_id) {
::IndexedDBObjectStoreMetadata idb_store_metadata;
idb_store_metadata.id = web_store_metadata.id;
idb_store_metadata.name = web_store_metadata.name;
- idb_store_metadata.keyPath = web_store_metadata.key_path;
- idb_store_metadata.autoIncrement = web_store_metadata.auto_increment;
+ idb_store_metadata.key_path = web_store_metadata.key_path;
+ idb_store_metadata.auto_increment = web_store_metadata.auto_increment;
idb_store_metadata.max_index_id = web_store_metadata.max_index_id;
for (const auto& index_iter : web_store_metadata.indexes) {
@@ -256,9 +292,9 @@ IndexedDBCursor* IndexedDBDispatcherHost::GetCursorFromId(int32 ipc_cursor_id) {
::IndexedDBIndexMetadata idb_index_metadata;
idb_index_metadata.id = web_index_metadata.id;
idb_index_metadata.name = web_index_metadata.name;
- idb_index_metadata.keyPath = web_index_metadata.key_path;
+ idb_index_metadata.key_path = web_index_metadata.key_path;
idb_index_metadata.unique = web_index_metadata.unique;
- idb_index_metadata.multiEntry = web_index_metadata.multi_entry;
+ idb_index_metadata.multi_entry = web_index_metadata.multi_entry;
idb_store_metadata.indexes.push_back(idb_index_metadata);
}
metadata.object_stores.push_back(idb_store_metadata);
@@ -342,9 +378,9 @@ void IndexedDBDispatcherHost::OnPutHelper(
void IndexedDBDispatcherHost::OnAckReceivedBlobs(
const std::vector<std::string>& uuids) {
- DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
for (const auto& uuid : uuids)
- DropBlobDataHandle(uuid);
+ DropBlobData(uuid);
}
void IndexedDBDispatcherHost::FinishTransaction(int64 host_transaction_id,
@@ -453,9 +489,9 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::CloseAll() {
bool IndexedDBDispatcherHost::DatabaseDispatcherHost::OnMessageReceived(
const IPC::Message& message) {
-
DCHECK(
- (message.type() == IndexedDBHostMsg_DatabasePut::ID) ||
+ (message.type() == IndexedDBHostMsg_DatabasePut::ID ||
+ message.type() == IndexedDBHostMsg_AckReceivedBlobs::ID) ||
parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
bool handled = true;
@@ -472,6 +508,7 @@ bool IndexedDBDispatcherHost::DatabaseDispatcherHost::OnMessageReceived(
OnVersionChangeIgnored)
IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDestroyed, OnDestroyed)
IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseGet, OnGet)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseGetAll, OnGetAll)
IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabasePut, OnPutWrapper)
IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseSetIndexKeys, OnSetIndexKeys)
IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseSetIndexesReady,
@@ -578,7 +615,10 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDestroyed(
int32 ipc_object_id) {
DCHECK(
parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
- IndexedDBConnection* connection = map_.Lookup(ipc_object_id);
+ IndexedDBConnection* connection =
+ parent_->GetOrTerminateProcess(&map_, ipc_object_id);
+ if (!connection)
+ return;
if (connection->IsConnected())
connection->Close();
parent_->Context()
@@ -607,11 +647,28 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnGet(
callbacks);
}
+void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnGetAll(
+ const IndexedDBHostMsg_DatabaseGetAll_Params& params) {
+ DCHECK(
+ parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
+ IndexedDBConnection* connection =
+ parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
+ if (!connection || !connection->IsConnected())
+ return;
+
+ scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
+ parent_, params.ipc_thread_id, params.ipc_callbacks_id));
+ connection->database()->GetAll(
+ parent_->HostTransactionId(params.transaction_id), params.object_store_id,
+ make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
+ params.max_count, callbacks);
+}
+
void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPutWrapper(
const IndexedDBHostMsg_DatabasePut_Params& params) {
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];
+ for (size_t i = 0; i < params.value.blob_or_file_info.size(); ++i) {
+ const IndexedDBMsg_BlobOrFileInfo& info = params.value.blob_or_file_info[i];
handles.push_back(parent_->blob_storage_context_->context()
->GetBlobDataFromUUID(info.uuid)
.release());
@@ -640,18 +697,22 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPut(
int64 host_transaction_id = parent_->HostTransactionId(params.transaction_id);
- std::vector<IndexedDBBlobInfo> blob_info(params.blob_or_file_info.size());
+ std::vector<IndexedDBBlobInfo> blob_info(
+ params.value.blob_or_file_info.size());
ChildProcessSecurityPolicyImpl* policy =
ChildProcessSecurityPolicyImpl::GetInstance();
- for (size_t i = 0; i < params.blob_or_file_info.size(); ++i) {
- const IndexedDBMsg_BlobOrFileInfo& info = params.blob_or_file_info[i];
+ for (size_t i = 0; i < params.value.blob_or_file_info.size(); ++i) {
+ const IndexedDBMsg_BlobOrFileInfo& info = params.value.blob_or_file_info[i];
if (info.is_file) {
- base::FilePath path = base::FilePath::FromUTF16Unsafe(info.file_path);
- if (!policy->CanReadFile(parent_->ipc_process_id_, path)) {
- parent_->BadMessageReceived();
- return;
+ base::FilePath path;
+ if (!info.file_path.empty()) {
+ path = base::FilePath::FromUTF16Unsafe(info.file_path);
+ if (!policy->CanReadFile(parent_->ipc_process_id_, path)) {
+ parent_->BadMessageReceived();
+ return;
+ }
}
blob_info[i] =
IndexedDBBlobInfo(info.uuid, path, info.file_name, info.mime_type);
@@ -667,7 +728,7 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPut(
// TODO(alecflett): Avoid a copy here.
IndexedDBValue value;
- value.bits = params.value;
+ value.bits = params.value.bits;
value.blob_info.swap(blob_info);
connection->database()->Put(host_transaction_id,
params.object_store_id,
@@ -681,7 +742,7 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPut(
&parent_->database_dispatcher_host_->transaction_size_map_;
// Size can't be big enough to overflow because it represents the
// actual bytes passed through IPC.
- (*map)[host_transaction_id] += params.value.size();
+ (*map)[host_transaction_id] += params.value.bits.size();
}
void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnSetIndexKeys(
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 667ec7cc2e8..b576a460730 100644
--- a/chromium/content/browser/indexed_db/indexed_db_dispatcher_host.h
+++ b/chromium/content/browser/indexed_db/indexed_db_dispatcher_host.h
@@ -7,6 +7,7 @@
#include <map>
#include <string>
+#include <utility>
#include <vector>
#include "base/basictypes.h"
@@ -25,6 +26,7 @@ struct IndexedDBHostMsg_DatabaseCreateObjectStore_Params;
struct IndexedDBHostMsg_DatabaseCreateTransaction_Params;
struct IndexedDBHostMsg_DatabaseDeleteRange_Params;
struct IndexedDBHostMsg_DatabaseGet_Params;
+struct IndexedDBHostMsg_DatabaseGetAll_Params;
struct IndexedDBHostMsg_DatabaseOpenCursor_Params;
struct IndexedDBHostMsg_DatabasePut_Params;
struct IndexedDBHostMsg_DatabaseSetIndexKeys_Params;
@@ -33,6 +35,7 @@ struct IndexedDBHostMsg_FactoryGetDatabaseNames_Params;
struct IndexedDBHostMsg_FactoryOpen_Params;
namespace content {
+class IndexedDBBlobInfo;
class IndexedDBConnection;
class IndexedDBContextImpl;
class IndexedDBCursor;
@@ -94,9 +97,7 @@ 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<storage::BlobDataHandle> blob_data_handle);
- void DropBlobDataHandle(const std::string& uuid);
+ std::string HoldBlobData(const IndexedDBBlobInfo& blob_info);
private:
// Friends to enable OnDestruct() delegation.
@@ -104,7 +105,8 @@ class IndexedDBDispatcherHost : public BrowserMessageFilter {
friend class base::DeleteHelper<IndexedDBDispatcherHost>;
// Used in nested classes.
- typedef std::map<std::string, storage::BlobDataHandle*> BlobDataHandleMap;
+ typedef std::map<std::string, std::pair<storage::BlobDataHandle*, int>>
+ BlobDataHandleMap;
typedef std::map<int64, int64> TransactionIDToDatabaseIDMap;
typedef std::map<int64, uint64> TransactionIDToSizeMap;
typedef std::map<int64, GURL> TransactionIDToURLMap;
@@ -162,6 +164,7 @@ class IndexedDBDispatcherHost : public BrowserMessageFilter {
void OnDestroyed(int32 ipc_database_id);
void OnGet(const IndexedDBHostMsg_DatabaseGet_Params& params);
+ void OnGetAll(const IndexedDBHostMsg_DatabaseGetAll_Params& params);
// OnPutWrapper starts on the IO thread so that it can grab BlobDataHandles
// before posting to the IDB TaskRunner for the rest of the job.
void OnPutWrapper(const IndexedDBHostMsg_DatabasePut_Params& params);
@@ -261,6 +264,7 @@ class IndexedDBDispatcherHost : public BrowserMessageFilter {
std::vector<storage::BlobDataHandle*> handles);
void ResetDispatcherHosts();
+ void DropBlobData(const std::string& uuid);
// The getter holds the context until OnChannelConnected() can be called from
// the IO thread, which will extract the net::URLRequestContext from it.
diff --git a/chromium/content/browser/indexed_db/indexed_db_factory.h b/chromium/content/browser/indexed_db/indexed_db_factory.h
index 935ba56c550..dc52342501f 100644
--- a/chromium/content/browser/indexed_db/indexed_db_factory.h
+++ b/chromium/content/browser/indexed_db/indexed_db_factory.h
@@ -37,7 +37,7 @@ class CONTENT_EXPORT IndexedDBFactory
typedef std::pair<OriginDBMapIterator, OriginDBMapIterator> OriginDBs;
virtual void ReleaseDatabase(const IndexedDBDatabase::Identifier& identifier,
- bool forcedClose) = 0;
+ bool forced_close) = 0;
virtual void GetDatabaseNames(scoped_refptr<IndexedDBCallbacks> callbacks,
const GURL& origin_url,
diff --git a/chromium/content/browser/indexed_db/indexed_db_factory_impl.cc b/chromium/content/browser/indexed_db/indexed_db_factory_impl.cc
index 9a62b78fb4c..38c24058ec5 100644
--- a/chromium/content/browser/indexed_db/indexed_db_factory_impl.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_factory_impl.cc
@@ -16,7 +16,7 @@
#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/WebKit/public/platform/modules/indexeddb/WebIDBDatabaseException.h"
#include "third_party/leveldatabase/env_chromium.h"
using base::ASCIIToUTF16;
@@ -52,7 +52,7 @@ void IndexedDBFactoryImpl::RemoveDatabaseFromMaps(
void IndexedDBFactoryImpl::ReleaseDatabase(
const IndexedDBDatabase::Identifier& identifier,
- bool forcedClose) {
+ bool forced_close) {
DCHECK(!database_map_.find(identifier)->second->backing_store());
RemoveDatabaseFromMaps(identifier);
@@ -60,7 +60,7 @@ void IndexedDBFactoryImpl::ReleaseDatabase(
// No grace period on a forced-close, as the initiator is
// assuming the backing store will be released once all
// connections are closed.
- ReleaseBackingStore(identifier.first, forcedClose);
+ ReleaseBackingStore(identifier.first, forced_close);
}
void IndexedDBFactoryImpl::ReleaseBackingStore(const GURL& origin_url,
@@ -266,7 +266,7 @@ void IndexedDBFactoryImpl::DeleteDatabase(
"Internal error creating database backend for "
"indexedDB.deleteDatabase."));
callbacks->OnError(error);
- if (leveldb_env::IsCorruption(s)) {
+ if (s.IsCorruption()) {
backing_store = NULL;
HandleBackingStoreCorruption(origin_url, error);
}
@@ -463,7 +463,7 @@ void IndexedDBFactoryImpl::Open(const base::string16& name,
"database backend for "
"indexedDB.open."));
connection.callbacks->OnError(error);
- if (leveldb_env::IsCorruption(s)) {
+ if (s.IsCorruption()) {
backing_store = NULL; // Closes the LevelDB so that it can be deleted
HandleBackingStoreCorruption(origin_url, error);
}
diff --git a/chromium/content/browser/indexed_db/indexed_db_factory_impl.h b/chromium/content/browser/indexed_db/indexed_db_factory_impl.h
index da9d2a9a45b..bf178bf5213 100644
--- a/chromium/content/browser/indexed_db/indexed_db_factory_impl.h
+++ b/chromium/content/browser/indexed_db/indexed_db_factory_impl.h
@@ -21,7 +21,7 @@ class CONTENT_EXPORT IndexedDBFactoryImpl : public IndexedDBFactory {
// content::IndexedDBFactory overrides:
void ReleaseDatabase(const IndexedDBDatabase::Identifier& identifier,
- bool forcedClose) override;
+ bool forced_close) override;
void GetDatabaseNames(scoped_refptr<IndexedDBCallbacks> callbacks,
const GURL& origin_url,
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 70f8ae64ad5..3d55ac7e63e 100644
--- a/chromium/content/browser/indexed_db/indexed_db_factory_unittest.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_factory_unittest.cc
@@ -15,8 +15,8 @@
#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 "third_party/WebKit/public/platform/modules/indexeddb/WebIDBDatabaseException.h"
+#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBTypes.h"
#include "url/gurl.h"
using base::ASCIIToUTF16;
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 c9de8a3acb8..53ae963c04a 100644
--- a/chromium/content/browser/indexed_db/indexed_db_index_writer.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_index_writer.cc
@@ -160,7 +160,7 @@ bool MakeIndexWriters(
if (!can_add_keys)
return true;
- index_writers->push_back(index_writer.release());
+ index_writers->push_back(index_writer.Pass());
}
*completed = true;
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 472e1b9abcf..2dfd6500466 100644
--- a/chromium/content/browser/indexed_db/indexed_db_internals_ui.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_internals_ui.cc
@@ -27,6 +27,19 @@
namespace content {
+namespace {
+
+bool AllowWhitelistedPaths(const std::vector<base::FilePath>& allowed_paths,
+ const base::FilePath& candidate_path) {
+ for (const base::FilePath& allowed_path : allowed_paths) {
+ if (allowed_path.IsParent(candidate_path))
+ return true;
+ }
+ return false;
+}
+
+} // namespace
+
IndexedDBInternalsUI::IndexedDBInternalsUI(WebUI* web_ui)
: WebUIController(web_ui) {
web_ui->RegisterMessageCallback(
@@ -70,7 +83,7 @@ void IndexedDBInternalsUI::AddContextFromStoragePartition(
}
void IndexedDBInternalsUI::GetAllOrigins(const base::ListValue* args) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
BrowserContext* browser_context =
web_ui()->GetWebContents()->GetBrowserContext();
@@ -103,7 +116,7 @@ void IndexedDBInternalsUI::GetAllOriginsOnIndexedDBThread(
void IndexedDBInternalsUI::OnOriginsReady(scoped_ptr<base::ListValue> origins,
const base::FilePath& path) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
web_ui()->CallJavascriptFunction(
"indexeddb.onOriginsReady", *origins, base::StringValue(path.value()));
}
@@ -158,7 +171,7 @@ bool IndexedDBInternalsUI::GetOriginContext(
}
void IndexedDBInternalsUI::DownloadOriginData(const base::ListValue* args) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
base::FilePath partition_path;
GURL origin_url;
@@ -177,7 +190,7 @@ void IndexedDBInternalsUI::DownloadOriginData(const base::ListValue* args) {
}
void IndexedDBInternalsUI::ForceCloseOrigin(const base::ListValue* args) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
base::FilePath partition_path;
GURL origin_url;
@@ -223,7 +236,9 @@ void IndexedDBInternalsUI::DownloadOriginDataOnIndexedDBThread(
// This happens on the "webkit" thread (which is really just the IndexedDB
// thread) as a simple way to avoid another script reopening the origin
// while we are zipping.
- zip::Zip(context->GetFilePath(origin_url), zip_path, true);
+ std::vector<base::FilePath> paths = context->GetStoragePaths(origin_url);
+ zip::ZipWithFilterCallback(context->data_path(), zip_path,
+ base::Bind(AllowWhitelistedPaths, paths));
BrowserThread::PostTask(BrowserThread::UI,
FROM_HERE,
@@ -275,7 +290,7 @@ void IndexedDBInternalsUI::OnDownloadDataReady(
const base::FilePath temp_path,
const base::FilePath zip_path,
size_t connection_count) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
const GURL url = GURL(FILE_PATH_LITERAL("file://") + zip_path.value());
BrowserContext* browser_context =
web_ui()->GetWebContents()->GetBrowserContext();
@@ -284,8 +299,8 @@ void IndexedDBInternalsUI::OnDownloadDataReady(
DownloadManager* dlm = BrowserContext::GetDownloadManager(browser_context);
const GURL referrer(web_ui()->GetWebContents()->GetLastCommittedURL());
- dl_params->set_referrer(
- content::Referrer(referrer, blink::WebReferrerPolicyDefault));
+ dl_params->set_referrer(content::Referrer::SanitizeForRequest(
+ url, content::Referrer(referrer, blink::WebReferrerPolicyDefault)));
// This is how to watch for the download to finish: first wait for it
// to start, then attach a DownloadItem::Observer to observe the
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 f8a3a1e51bd..45656a86038 100644
--- a/chromium/content/browser/indexed_db/indexed_db_leveldb_coding.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_leveldb_coding.cc
@@ -223,9 +223,9 @@ static const unsigned char kIndexMetaDataTypeMaximum = 255;
const unsigned char kMinimumIndexId = 30;
-inline void EncodeIntSafely(int64 nParam, int64 max, std::string* into) {
- DCHECK_LE(nParam, max);
- return EncodeInt(nParam, into);
+inline void EncodeIntSafely(int64 value, int64 max, std::string* into) {
+ DCHECK_LE(value, max);
+ return EncodeInt(value, into);
}
std::string MaxIDBKey() {
@@ -1256,10 +1256,10 @@ std::string KeyPrefix::EncodeInternal(int64 database_id,
kMaxIndexIdSizeBits) |
(object_store_id_string.size() - 1) << kMaxIndexIdSizeBits |
(index_id_string.size() - 1);
- COMPILE_ASSERT(kMaxDatabaseIdSizeBits + kMaxObjectStoreIdSizeBits +
- kMaxIndexIdSizeBits ==
- sizeof(first_byte) * 8,
- CANT_ENCODE_IDS);
+ static_assert(kMaxDatabaseIdSizeBits + kMaxObjectStoreIdSizeBits +
+ kMaxIndexIdSizeBits ==
+ sizeof(first_byte) * 8,
+ "cannot encode ids");
std::string ret;
ret.reserve(kDefaultInlineBufferSize);
ret.push_back(first_byte);
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 de16b55f07b..4d72652b88d 100644
--- a/chromium/content/browser/indexed_db/indexed_db_leveldb_coding.h
+++ b/chromium/content/browser/indexed_db/indexed_db_leveldb_coding.h
@@ -246,7 +246,7 @@ class DatabaseMetaDataKey {
// All keys <= 0 are invalid. This one's just a convenient example.
static const int64 kInvalidBlobKey;
- static bool IsValidBlobKey(int64 blobKey);
+ static bool IsValidBlobKey(int64 blob_key);
CONTENT_EXPORT static std::string Encode(int64 database_id,
MetaDataType type);
};
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 5f9edf1a811..43017e9d482 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
@@ -971,11 +971,11 @@ TEST(IndexedDBLevelDBCodingTest, EncodeVarIntVSEncodeByteTest) {
for (size_t i = 0; i < test_cases.size(); ++i) {
unsigned char n = test_cases[i];
- std::string vA = WrappedEncodeByte(n);
- std::string vB = WrappedEncodeVarInt(static_cast<int64>(n));
+ std::string a = WrappedEncodeByte(n);
+ std::string b = WrappedEncodeVarInt(static_cast<int64>(n));
- EXPECT_EQ(vA.size(), vB.size());
- EXPECT_EQ(*vA.begin(), *vB.begin());
+ EXPECT_EQ(a.size(), b.size());
+ EXPECT_EQ(*a.begin(), *b.begin());
}
}
diff --git a/chromium/content/browser/indexed_db/indexed_db_metadata.cc b/chromium/content/browser/indexed_db/indexed_db_metadata.cc
index 47b7219f15b..92c4c318c5a 100644
--- a/chromium/content/browser/indexed_db/indexed_db_metadata.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_metadata.cc
@@ -6,6 +6,28 @@
namespace content {
+IndexedDBIndexMetadata::IndexedDBIndexMetadata() = default;
+
+IndexedDBIndexMetadata::IndexedDBIndexMetadata(const base::string16& name,
+ int64 id,
+ const IndexedDBKeyPath& key_path,
+ bool unique,
+ bool multi_entry)
+ : name(name),
+ id(id),
+ key_path(key_path),
+ unique(unique),
+ multi_entry(multi_entry) {
+}
+
+IndexedDBIndexMetadata::IndexedDBIndexMetadata(
+ const IndexedDBIndexMetadata& other) = default;
+
+IndexedDBIndexMetadata::~IndexedDBIndexMetadata() = default;
+
+IndexedDBIndexMetadata& IndexedDBIndexMetadata::operator=(
+ const IndexedDBIndexMetadata& other) = default;
+
IndexedDBObjectStoreMetadata::IndexedDBObjectStoreMetadata(
const base::string16& name,
int64 id,
@@ -18,11 +40,19 @@ IndexedDBObjectStoreMetadata::IndexedDBObjectStoreMetadata(
auto_increment(auto_increment),
max_index_id(max_index_id) {}
-IndexedDBObjectStoreMetadata::IndexedDBObjectStoreMetadata() {}
-IndexedDBObjectStoreMetadata::~IndexedDBObjectStoreMetadata() {}
+IndexedDBObjectStoreMetadata::IndexedDBObjectStoreMetadata() = default;
+
+IndexedDBObjectStoreMetadata::IndexedDBObjectStoreMetadata(
+ const IndexedDBObjectStoreMetadata& other) = default;
+
+IndexedDBObjectStoreMetadata::~IndexedDBObjectStoreMetadata() = default;
+
+IndexedDBObjectStoreMetadata& IndexedDBObjectStoreMetadata::operator=(
+ const IndexedDBObjectStoreMetadata& other) = default;
IndexedDBDatabaseMetadata::IndexedDBDatabaseMetadata()
: int_version(NO_INT_VERSION) {}
+
IndexedDBDatabaseMetadata::IndexedDBDatabaseMetadata(
const base::string16& name,
int64 id,
@@ -35,6 +65,12 @@ IndexedDBDatabaseMetadata::IndexedDBDatabaseMetadata(
int_version(int_version),
max_object_store_id(max_object_store_id) {}
-IndexedDBDatabaseMetadata::~IndexedDBDatabaseMetadata() {}
+IndexedDBDatabaseMetadata::IndexedDBDatabaseMetadata(
+ const IndexedDBDatabaseMetadata& other) = default;
+
+IndexedDBDatabaseMetadata::~IndexedDBDatabaseMetadata() = default;
+
+IndexedDBDatabaseMetadata& IndexedDBDatabaseMetadata::operator=(
+ IndexedDBDatabaseMetadata& other) = default;
} // namespace content
diff --git a/chromium/content/browser/indexed_db/indexed_db_metadata.h b/chromium/content/browser/indexed_db/indexed_db_metadata.h
index a597616c55f..e294868f9f1 100644
--- a/chromium/content/browser/indexed_db/indexed_db_metadata.h
+++ b/chromium/content/browser/indexed_db/indexed_db_metadata.h
@@ -13,20 +13,19 @@
namespace content {
-struct IndexedDBIndexMetadata {
+struct CONTENT_EXPORT IndexedDBIndexMetadata {
static const int64 kInvalidId = -1;
- IndexedDBIndexMetadata() {}
+ IndexedDBIndexMetadata();
IndexedDBIndexMetadata(const base::string16& name,
int64 id,
const IndexedDBKeyPath& key_path,
bool unique,
- bool multi_entry)
- : name(name),
- id(id),
- key_path(key_path),
- unique(unique),
- multi_entry(multi_entry) {}
+ bool multi_entry);
+ IndexedDBIndexMetadata(const IndexedDBIndexMetadata& other);
+ ~IndexedDBIndexMetadata();
+ IndexedDBIndexMetadata& operator=(const IndexedDBIndexMetadata& other);
+
base::string16 name;
int64 id;
IndexedDBKeyPath key_path;
@@ -45,7 +44,11 @@ struct CONTENT_EXPORT IndexedDBObjectStoreMetadata {
const IndexedDBKeyPath& key_path,
bool auto_increment,
int64 max_index_id);
+ IndexedDBObjectStoreMetadata(const IndexedDBObjectStoreMetadata& other);
~IndexedDBObjectStoreMetadata();
+ IndexedDBObjectStoreMetadata& operator=(
+ const IndexedDBObjectStoreMetadata& other);
+
base::string16 name;
int64 id;
IndexedDBKeyPath key_path;
@@ -70,7 +73,9 @@ struct CONTENT_EXPORT IndexedDBDatabaseMetadata {
const base::string16& version,
int64 int_version,
int64 max_object_store_id);
+ IndexedDBDatabaseMetadata(const IndexedDBDatabaseMetadata& other);
~IndexedDBDatabaseMetadata();
+ IndexedDBDatabaseMetadata& operator=(IndexedDBDatabaseMetadata& other);
base::string16 name;
int64 id;
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 d8af36c5566..a33e4289645 100644
--- a/chromium/content/browser/indexed_db/indexed_db_quota_client.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_quota_client.cc
@@ -40,7 +40,7 @@ void GetAllOriginsOnIndexedDBThread(IndexedDBContextImpl* context,
void DidGetOrigins(const IndexedDBQuotaClient::GetOriginsCallback& callback,
const std::set<GURL>* origins) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
callback.Run(*origins);
}
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 7894a653f26..b9e9bceed0a 100644
--- a/chromium/content/browser/indexed_db/indexed_db_quota_client.h
+++ b/chromium/content/browser/indexed_db/indexed_db_quota_client.h
@@ -22,8 +22,7 @@ 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 storage::QuotaClient,
- public storage::QuotaTaskObserver {
+class IndexedDBQuotaClient : public storage::QuotaClient {
public:
CONTENT_EXPORT explicit IndexedDBQuotaClient(
IndexedDBContextImpl* indexed_db_context);
diff --git a/chromium/content/browser/indexed_db/indexed_db_return_value.h b/chromium/content/browser/indexed_db/indexed_db_return_value.h
new file mode 100644
index 00000000000..6a50a26165f
--- /dev/null
+++ b/chromium/content/browser/indexed_db/indexed_db_return_value.h
@@ -0,0 +1,27 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_RETURN_VALUE_H_
+#define CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_RETURN_VALUE_H_
+
+#include "content/browser/indexed_db/indexed_db_value.h"
+#include "content/common/content_export.h"
+#include "content/common/indexed_db/indexed_db_key.h"
+#include "content/common/indexed_db/indexed_db_key_path.h"
+
+namespace content {
+
+// Values returned to the IDB client may contain a primary key value generated
+// by IDB. This is optional and only done when using a key generator. This key
+// value cannot (at least easily) be amended to the object being written to the
+// database, so they are kept separately, and sent back with the original data
+// so that the render process can amend the returned object.
+struct CONTENT_EXPORT IndexedDBReturnValue : public IndexedDBValue {
+ IndexedDBKey primary_key; // primary key (only when using key generator)
+ IndexedDBKeyPath key_path;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_RETURN_VALUE_H_
diff --git a/chromium/content/browser/indexed_db/indexed_db_tracing.h b/chromium/content/browser/indexed_db/indexed_db_tracing.h
index b7a5a4157d3..489f157bf56 100644
--- a/chromium/content/browser/indexed_db/indexed_db_tracing.h
+++ b/chromium/content/browser/indexed_db/indexed_db_tracing.h
@@ -5,7 +5,7 @@
#ifndef CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_TRACING_H_
#define CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_TRACING_H_
-#include "base/debug/trace_event.h"
+#include "base/trace_event/trace_event.h"
#define IDB_TRACE(a) TRACE_EVENT0("IndexedDB", (a));
#define IDB_TRACE1(a, arg1_name, arg1_val) \
TRACE_EVENT1("IndexedDB", (a), (arg1_name), (arg1_val));
diff --git a/chromium/content/browser/indexed_db/indexed_db_transaction.cc b/chromium/content/browser/indexed_db/indexed_db_transaction.cc
index 6609e02499b..cb6fad6a01a 100644
--- a/chromium/content/browser/indexed_db/indexed_db_transaction.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_transaction.cc
@@ -14,7 +14,8 @@
#include "content/browser/indexed_db/indexed_db_database_callbacks.h"
#include "content/browser/indexed_db/indexed_db_tracing.h"
#include "content/browser/indexed_db/indexed_db_transaction_coordinator.h"
-#include "third_party/WebKit/public/platform/WebIDBDatabaseException.h"
+#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBDatabaseException.h"
+#include "third_party/leveldatabase/env_chromium.h"
namespace content {
@@ -318,10 +319,17 @@ leveldb::Status IndexedDBTransaction::CommitPhaseTwo() {
while (!abort_task_stack_.empty())
abort_task_stack_.pop().Run(NULL);
- callbacks_->OnAbort(
- id_,
- IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError,
- "Internal error committing transaction."));
+ IndexedDBDatabaseError error;
+ if (leveldb_env::IndicatesDiskFull(s)) {
+ error = IndexedDBDatabaseError(
+ blink::WebIDBDatabaseExceptionQuotaError,
+ "Encountered disk full while committing transaction.");
+ } else {
+ error = IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError,
+ "Internal error committing transaction.");
+ }
+ callbacks_->OnAbort(id_, error);
+
database_->TransactionFinished(this, false);
database_->TransactionCommitFailed(s);
}
diff --git a/chromium/content/browser/indexed_db/indexed_db_transaction.h b/chromium/content/browser/indexed_db/indexed_db_transaction.h
index bd0e543035c..c9706dddefa 100644
--- a/chromium/content/browser/indexed_db/indexed_db_transaction.h
+++ b/chromium/content/browser/indexed_db/indexed_db_transaction.h
@@ -17,7 +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"
+#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBTypes.h"
namespace content {
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 ca7f3838b88..58e838b2594 100644
--- a/chromium/content/browser/indexed_db/indexed_db_transaction_coordinator.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_transaction_coordinator.cc
@@ -7,7 +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"
+#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBTypes.h"
namespace content {
@@ -146,8 +146,6 @@ bool IndexedDBTransactionCoordinator::CanStartTransaction(
return true;
case blink::WebIDBTransactionModeReadOnly:
- return true;
-
case blink::WebIDBTransactionModeReadWrite:
return !DoSetsIntersect(transaction->scope(), locked_scope);
}
diff --git a/chromium/content/browser/indexed_db/indexed_db_value.cc b/chromium/content/browser/indexed_db/indexed_db_value.cc
index 28435211df5..e8be18a0264 100644
--- a/chromium/content/browser/indexed_db/indexed_db_value.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_value.cc
@@ -8,13 +8,16 @@
namespace content {
-IndexedDBValue::IndexedDBValue() {}
+IndexedDBValue::IndexedDBValue() = default;
IndexedDBValue::IndexedDBValue(
const std::string& input_bits,
const std::vector<IndexedDBBlobInfo>& input_blob_info)
: bits(input_bits), blob_info(input_blob_info) {
DCHECK(!input_blob_info.size() || input_bits.size());
}
-IndexedDBValue::~IndexedDBValue() {}
+IndexedDBValue::IndexedDBValue(const IndexedDBValue& other) = default;
+IndexedDBValue::~IndexedDBValue() = default;
+IndexedDBValue& IndexedDBValue::operator=(const IndexedDBValue& other) =
+ default;
} // namespace content
diff --git a/chromium/content/browser/indexed_db/indexed_db_value.h b/chromium/content/browser/indexed_db/indexed_db_value.h
index d313038dd69..7b2377ad03b 100644
--- a/chromium/content/browser/indexed_db/indexed_db_value.h
+++ b/chromium/content/browser/indexed_db/indexed_db_value.h
@@ -18,7 +18,9 @@ struct CONTENT_EXPORT IndexedDBValue {
IndexedDBValue();
IndexedDBValue(const std::string& input_bits,
const std::vector<IndexedDBBlobInfo>& input_blob_info);
+ IndexedDBValue(const IndexedDBValue& other);
~IndexedDBValue();
+ IndexedDBValue& operator=(const IndexedDBValue& other);
void swap(IndexedDBValue& value) {
bits.swap(value.bits);
diff --git a/chromium/content/browser/indexed_db/leveldb/leveldb_database.cc b/chromium/content/browser/indexed_db/leveldb/leveldb_database.cc
index 5f48cbef60e..1d816a849c7 100644
--- a/chromium/content/browser/indexed_db/leveldb/leveldb_database.cc
+++ b/chromium/content/browser/indexed_db/leveldb/leveldb_database.cc
@@ -103,6 +103,7 @@ static leveldb::Status OpenDB(
options.create_if_missing = true;
options.paranoid_checks = true;
options.filter_policy = filter_policy->get();
+ options.reuse_logs = leveldb_env::kDefaultLogReuseOptionValue;
options.compression = leveldb::kSnappyCompression;
// For info about the troubles we've run into with this parameter, see:
@@ -169,7 +170,7 @@ static int CheckFreeSpace(const char* const type,
? INT_MAX
: free_disk_space_in_k_bytes;
const uint64 histogram_max = static_cast<uint64>(1e9);
- COMPILE_ASSERT(histogram_max <= INT_MAX, histogram_max_too_big);
+ static_assert(histogram_max <= INT_MAX, "histogram_max too big");
base::Histogram::FactoryGet(name,
1,
histogram_max,
@@ -182,9 +183,9 @@ static int CheckFreeSpace(const char* const type,
static void ParseAndHistogramIOErrorDetails(const std::string& histogram_name,
const leveldb::Status& s) {
leveldb_env::MethodID method;
- int error = -1;
+ base::File::Error error = base::File::FILE_OK;
leveldb_env::ErrorParsingResult result =
- leveldb_env::ParseMethodAndError(s.ToString().c_str(), &method, &error);
+ leveldb_env::ParseMethodAndError(s, &method, &error);
if (result == leveldb_env::NONE)
return;
std::string method_histogram_name(histogram_name);
@@ -198,9 +199,9 @@ static void ParseAndHistogramIOErrorDetails(const std::string& histogram_name,
std::string error_histogram_name(histogram_name);
- if (result == leveldb_env::METHOD_AND_PFE) {
+ if (result == leveldb_env::METHOD_AND_BFE) {
DCHECK_LT(error, 0);
- error_histogram_name.append(std::string(".PFE.") +
+ error_histogram_name.append(std::string(".BFE.") +
leveldb_env::MethodIDToString(method));
base::LinearHistogram::FactoryGet(
error_histogram_name,
@@ -208,15 +209,6 @@ static void ParseAndHistogramIOErrorDetails(const std::string& histogram_name,
-base::File::FILE_ERROR_MAX,
-base::File::FILE_ERROR_MAX + 1,
base::HistogramBase::kUmaTargetedHistogramFlag)->Add(-error);
- } else if (result == leveldb_env::METHOD_AND_ERRNO) {
- error_histogram_name.append(std::string(".Errno.") +
- leveldb_env::MethodIDToString(method));
- base::LinearHistogram::FactoryGet(
- error_histogram_name,
- 1,
- ERANGE + 1,
- ERANGE + 2,
- base::HistogramBase::kUmaTargetedHistogramFlag)->Add(error);
}
}
diff --git a/chromium/content/browser/indexed_db/leveldb/leveldb_unittest.cc b/chromium/content/browser/indexed_db/leveldb/leveldb_unittest.cc
index 7c649872a2d..16544a9e796 100644
--- a/chromium/content/browser/indexed_db/leveldb/leveldb_unittest.cc
+++ b/chromium/content/browser/indexed_db/leveldb/leveldb_unittest.cc
@@ -72,6 +72,7 @@ TEST(LevelDBDatabaseTest, CorruptionTest) {
status = LevelDBDatabase::Open(temp_directory.path(), &comparator, &leveldb);
EXPECT_FALSE(leveldb);
EXPECT_FALSE(status.ok());
+ EXPECT_TRUE(status.IsCorruption());
status = LevelDBDatabase::Destroy(temp_directory.path());
EXPECT_TRUE(status.ok());
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 a683f3759fb..5cade12b5f8 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
@@ -8,6 +8,7 @@
#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/env_chromium.h"
#include "third_party/leveldatabase/src/include/leveldb/status.h"
namespace {
@@ -39,9 +40,9 @@ class FunctionTracer {
namespace content {
-class LevelDBTestTansaction : public LevelDBTransaction {
+class LevelDBTestTransaction : public LevelDBTransaction {
public:
- LevelDBTestTansaction(LevelDBDatabase* db,
+ LevelDBTestTransaction(LevelDBDatabase* db,
FailMethod fail_method,
int fail_on_call_num)
: LevelDBTransaction(db),
@@ -64,24 +65,32 @@ class LevelDBTestTansaction : public LevelDBTransaction {
}
leveldb::Status Commit() override {
- if (fail_method_ != FAIL_METHOD_COMMIT ||
+ if ((fail_method_ != FAIL_METHOD_COMMIT &&
+ fail_method_ != FAIL_METHOD_COMMIT_DISK_FULL) ||
++current_call_num_ != fail_on_call_num_)
return LevelDBTransaction::Commit();
+ // TODO(jsbell): Consider parameterizing the failure mode.
+ if (fail_method_ == FAIL_METHOD_COMMIT_DISK_FULL) {
+ return leveldb_env::MakeIOError("dummy filename", "Disk Full",
+ leveldb_env::kWritableFileAppend,
+ base::File::FILE_ERROR_NO_SPACE);
+ }
+
return leveldb::Status::Corruption("Corrupted for the test");
}
private:
- ~LevelDBTestTansaction() override {}
+ ~LevelDBTestTransaction() override {}
FailMethod fail_method_;
int fail_on_call_num_;
int current_call_num_;
};
-class LevelDBTraceTansaction : public LevelDBTransaction {
+class LevelDBTraceTransaction : public LevelDBTransaction {
public:
- LevelDBTraceTansaction(LevelDBDatabase* db, int tx_num)
+ LevelDBTraceTransaction(LevelDBDatabase* db, int tx_num)
: LevelDBTransaction(db),
commit_tracer_(s_class_name, "Commit", tx_num),
get_tracer_(s_class_name, "Get", tx_num) {}
@@ -101,13 +110,13 @@ class LevelDBTraceTansaction : public LevelDBTransaction {
private:
static const std::string s_class_name;
- ~LevelDBTraceTansaction() override {}
+ ~LevelDBTraceTransaction() override {}
FunctionTracer commit_tracer_;
FunctionTracer get_tracer_;
};
-const std::string LevelDBTraceTansaction::s_class_name = "LevelDBTransaction";
+const std::string LevelDBTraceTransaction::s_class_name = "LevelDBTransaction";
class LevelDBTraceIteratorImpl : public LevelDBIteratorImpl {
public:
@@ -204,13 +213,13 @@ MockBrowserTestIndexedDBClassFactory::CreateLevelDBTransaction(
instance_count_[FAIL_CLASS_LEVELDB_TRANSACTION] =
instance_count_[FAIL_CLASS_LEVELDB_TRANSACTION] + 1;
if (only_trace_calls_) {
- return new LevelDBTraceTansaction(
+ return new LevelDBTraceTransaction(
db, instance_count_[FAIL_CLASS_LEVELDB_TRANSACTION]);
} else {
if (failure_class_ == FAIL_CLASS_LEVELDB_TRANSACTION &&
instance_count_[FAIL_CLASS_LEVELDB_TRANSACTION] ==
fail_on_instance_num_[FAIL_CLASS_LEVELDB_TRANSACTION]) {
- return new LevelDBTestTansaction(
+ return new LevelDBTestTransaction(
db,
failure_method_,
fail_on_call_num_[FAIL_CLASS_LEVELDB_TRANSACTION]);
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 9e40b60a90a..6e6f6ae0cef 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
@@ -23,6 +23,7 @@ enum FailClass {
enum FailMethod {
FAIL_METHOD_NOTHING,
FAIL_METHOD_COMMIT,
+ FAIL_METHOD_COMMIT_DISK_FULL,
FAIL_METHOD_GET,
FAIL_METHOD_SEEK,
};
diff --git a/chromium/content/browser/indexed_db/mock_indexed_db_factory.h b/chromium/content/browser/indexed_db/mock_indexed_db_factory.h
index 6860cfa7da8..b480758692c 100644
--- a/chromium/content/browser/indexed_db/mock_indexed_db_factory.h
+++ b/chromium/content/browser/indexed_db/mock_indexed_db_factory.h
@@ -17,7 +17,7 @@ class MockIndexedDBFactory : public IndexedDBFactory {
MockIndexedDBFactory();
MOCK_METHOD2(ReleaseDatabase,
void(const IndexedDBDatabase::Identifier& identifier,
- bool forcedClose));
+ bool forced_close));
MOCK_METHOD4(GetDatabaseNames,
void(scoped_refptr<IndexedDBCallbacks> callbacks,
const GURL& origin_url,
@@ -41,8 +41,7 @@ class MockIndexedDBFactory : public IndexedDBFactory {
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;
+ OriginDBs GetOpenDatabasesForOrigin(const GURL& origin_url) const override;
MOCK_METHOD1(ForceClose, void(const GURL& origin_url));
MOCK_METHOD0(ContextDestroyed, void());
MOCK_METHOD1(DatabaseDeleted,
diff --git a/chromium/content/browser/loader/async_resource_handler.cc b/chromium/content/browser/loader/async_resource_handler.cc
index 5125bec8607..f0268e71d5f 100644
--- a/chromium/content/browser/loader/async_resource_handler.cc
+++ b/chromium/content/browser/loader/async_resource_handler.cc
@@ -12,7 +12,7 @@
#include "base/debug/alias.h"
#include "base/logging.h"
#include "base/memory/shared_memory.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
#include "base/strings/string_number_conversions.h"
#include "base/time/time.h"
#include "content/browser/devtools/devtools_netlog_observer.h"
@@ -28,8 +28,8 @@
#include "content/public/common/resource_response.h"
#include "net/base/io_buffer.h"
#include "net/base/load_flags.h"
-#include "net/base/net_log.h"
#include "net/base/net_util.h"
+#include "net/log/net_log.h"
#include "net/url_request/redirect_info.h"
using base::TimeTicks;
@@ -59,11 +59,6 @@ void InitializeResourceBufferConstants() {
GetNumericArg("resource-buffer-max-allocation-size", &kMaxAllocationSize);
}
-int CalcUsedPercentage(int bytes_read, int buffer_size) {
- double ratio = static_cast<double>(bytes_read) / buffer_size;
- return static_cast<int>(ratio * 100.0 + 0.5); // Round to nearest integer.
-}
-
} // namespace
class DependentIOBuffer : public net::WrappedIOBuffer {
@@ -114,13 +109,6 @@ 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();
}
@@ -151,8 +139,6 @@ bool AsyncResourceHandler::OnRequestRedirected(
if (!info->filter())
return false;
- redirect_start_time_ = TimeTicks::Now();
-
*defer = did_defer_ = true;
OnDefer();
@@ -193,16 +179,19 @@ bool AsyncResourceHandler::OnResponseStarted(ResourceResponse* response,
DevToolsNetLogObserver::PopulateResponseInfo(request(), response);
- HostZoomMap* host_zoom_map =
- GetHostZoomMapForResourceContext(info->GetContext());
+ const HostZoomMapImpl* host_zoom_map =
+ static_cast<const HostZoomMapImpl*>(info->filter()->GetHostZoomMap());
if (info->GetResourceType() == RESOURCE_TYPE_MAIN_FRAME && host_zoom_map) {
const GURL& request_url = request()->url();
+ int render_process_id = info->GetChildID();
+ int render_view_id = info->GetRouteID();
+
+ double zoom_level = host_zoom_map->GetZoomLevelForView(
+ request_url, render_process_id, render_view_id);
+
info->filter()->Send(new ViewMsg_SetZoomLevelForLoadingURL(
- info->GetRouteID(),
- request_url, host_zoom_map->GetZoomLevelForHostAndScheme(
- request_url.scheme(),
- net::GetHostOrSpecFromURL(request_url))));
+ render_view_id, request_url, zoom_level));
}
// If the parent handler downloaded the resource to a file, grant the child
@@ -253,9 +242,6 @@ bool AsyncResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf,
*buf = new DependentIOBuffer(buffer_.get(), memory);
*buf_size = allocation_size_;
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "Net.AsyncResourceHandler_SharedIOBuffer_Alloc",
- *buf_size, 0, kMaxAllocationSize, 100);
return true;
}
@@ -271,13 +257,6 @@ bool AsyncResourceHandler::OnReadCompleted(int bytes_read, bool* defer) {
buffer_->ShrinkLastAllocation(bytes_read);
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "Net.AsyncResourceHandler_SharedIOBuffer_Used",
- bytes_read, 0, kMaxAllocationSize, 100);
- UMA_HISTOGRAM_PERCENTAGE(
- "Net.AsyncResourceHandler_SharedIOBuffer_UsedPercentage",
- CalcUsedPercentage(bytes_read, allocation_size_));
-
if (!sent_first_data_msg_) {
base::SharedMemoryHandle handle;
int size;
@@ -297,14 +276,8 @@ bool AsyncResourceHandler::OnReadCompleted(int bytes_read, bool* defer) {
filter->Send(new ResourceMsg_DataReceived(
GetRequestID(), data_offset, bytes_read, encoded_data_length));
++pending_data_count_;
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "Net.AsyncResourceHandler_PendingDataCount",
- pending_data_count_, 0, 100, 100);
if (!buffer_->CanAllocate()) {
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "Net.AsyncResourceHandler_PendingDataCount_WhenFull",
- pending_data_count_, 0, 100, 100);
*defer = did_defer_ = true;
OnDefer();
}
diff --git a/chromium/content/browser/loader/async_resource_handler.h b/chromium/content/browser/loader/async_resource_handler.h
index e2954f4975a..fb4086db4ee 100644
--- a/chromium/content/browser/loader/async_resource_handler.h
+++ b/chromium/content/browser/loader/async_resource_handler.h
@@ -8,7 +8,6 @@
#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"
@@ -78,8 +77,6 @@ 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 f96b5506d8c..2d4e088318d 100644
--- a/chromium/content/browser/loader/buffered_resource_handler.cc
+++ b/chromium/content/browser/loader/buffered_resource_handler.cc
@@ -10,6 +10,7 @@
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/strings/string_util.h"
+#include "components/mime_util/mime_util.h"
#include "content/browser/download/download_resource_handler.h"
#include "content/browser/download/download_stats.h"
#include "content/browser/loader/certificate_resource_handler.h"
@@ -20,6 +21,7 @@
#include "content/public/browser/download_item.h"
#include "content/public/browser/download_save_info.h"
#include "content/public/browser/download_url_parameters.h"
+#include "content/public/browser/plugin_service.h"
#include "content/public/browser/resource_context.h"
#include "content/public/browser/resource_dispatcher_host_delegate.h"
#include "content/public/common/resource_response.h"
@@ -31,10 +33,6 @@
#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 {
@@ -83,10 +81,12 @@ class DependentIOBuffer : public net::WrappedIOBuffer {
BufferedResourceHandler::BufferedResourceHandler(
scoped_ptr<ResourceHandler> next_handler,
ResourceDispatcherHostImpl* host,
+ PluginService* plugin_service,
net::URLRequest* request)
: LayeredResourceHandler(request, next_handler.Pass()),
state_(STATE_STARTING),
host_(host),
+ plugin_service_(plugin_service),
read_buffer_size_(0),
bytes_read_(0),
must_download_(false),
@@ -111,16 +111,9 @@ bool BufferedResourceHandler::OnResponseStarted(ResourceResponse* response,
bool* defer) {
response_ = response;
- // TODO(darin): It is very odd to special-case 304 responses at this level.
- // We do so only because the code always has, see r24977 and r29355. The
- // fact that 204 is no longer special-cased this way suggests that 304 need
- // not be special-cased either.
- //
- // The network stack only forwards 304 responses that were not received in
- // response to a conditional request (i.e., If-Modified-Since). Other 304
- // responses end up being translated to 200 or whatever the cached response
- // code happens to be. It should be very rare to see a 304 at this level.
-
+ // A 304 response should not contain a Content-Type header (RFC 7232 section
+ // 4.1). The following code may incorrectly attempt to add a Content-Type to
+ // the response, and so must be skipped for 304 responses.
if (!(response_->head.headers.get() &&
response_->head.headers->response_code() == 304)) {
if (ShouldSniffContent()) {
@@ -304,7 +297,7 @@ bool BufferedResourceHandler::SelectNextHandler(bool* defer) {
ResourceRequestInfoImpl* info = GetRequestInfo();
const std::string& mime_type = response_->head.mime_type;
- if (net::IsSupportedCertificateMimeType(mime_type)) {
+ if (mime_util::IsSupportedCertificateMimeType(mime_type)) {
// Install certificate file.
info->set_is_download(true);
scoped_ptr<ResourceHandler> handler(
@@ -312,12 +305,30 @@ bool BufferedResourceHandler::SelectNextHandler(bool* defer) {
return UseAlternateNextHandler(handler.Pass(), std::string());
}
+ // Allow requests for object/embed tags to be intercepted as streams.
+ if (info->GetResourceType() == content::RESOURCE_TYPE_OBJECT) {
+ DCHECK(!info->allow_download());
+ std::string payload;
+ scoped_ptr<ResourceHandler> handler(
+ host_->MaybeInterceptAsStream(request(), response_.get(), &payload));
+ if (handler) {
+ DCHECK(!mime_util::IsSupportedMimeType(mime_type));
+ return UseAlternateNextHandler(handler.Pass(), payload);
+ }
+ }
+
if (!info->allow_download())
return true;
+ // info->allow_download() == true implies
+ // info->GetResourceType() == RESOURCE_TYPE_MAIN_FRAME or
+ // info->GetResourceType() == RESOURCE_TYPE_SUB_FRAME.
+ DCHECK(info->GetResourceType() == RESOURCE_TYPE_MAIN_FRAME ||
+ info->GetResourceType() == RESOURCE_TYPE_SUB_FRAME);
+
bool must_download = MustDownload();
if (!must_download) {
- if (net::IsSupportedMimeType(mime_type))
+ if (mime_util::IsSupportedMimeType(mime_type))
return true;
std::string payload;
@@ -332,7 +343,7 @@ bool BufferedResourceHandler::SelectNextHandler(bool* defer) {
bool has_plugin = HasSupportingPlugin(&stale);
if (stale) {
// Refresh the plugins asynchronously.
- PluginServiceImpl::GetInstance()->GetPlugins(
+ plugin_service_->GetPlugins(
base::Bind(&BufferedResourceHandler::OnPluginsLoaded,
weak_ptr_factory_.GetWeakPtr()));
request()->LogBlockedBy("BufferedResourceHandler");
@@ -464,7 +475,7 @@ bool BufferedResourceHandler::HasSupportingPlugin(bool* stale) {
bool allow_wildcard = false;
WebPluginInfo plugin;
- return PluginServiceImpl::GetInstance()->GetPluginInfo(
+ return plugin_service_->GetPluginInfo(
info->GetChildID(), info->GetRenderFrameID(), info->GetContext(),
request()->url(), GURL(), response_->head.mime_type, allow_wildcard,
stale, &plugin, NULL);
diff --git a/chromium/content/browser/loader/buffered_resource_handler.h b/chromium/content/browser/loader/buffered_resource_handler.h
index 8735359e21e..4e80ec53bd5 100644
--- a/chromium/content/browser/loader/buffered_resource_handler.h
+++ b/chromium/content/browser/loader/buffered_resource_handler.h
@@ -10,6 +10,7 @@
#include "base/memory/weak_ptr.h"
#include "content/browser/loader/layered_resource_handler.h"
+#include "content/common/content_export.h"
#include "content/public/browser/resource_controller.h"
namespace net {
@@ -17,16 +18,19 @@ class URLRequest;
}
namespace content {
+class PluginService;
class ResourceDispatcherHostImpl;
struct WebPluginInfo;
// Used to buffer a request until enough data has been received.
-class BufferedResourceHandler
+class CONTENT_EXPORT BufferedResourceHandler
: public LayeredResourceHandler,
public ResourceController {
public:
+ // If ENABLE_PLUGINS is defined, |plugin_service| must not be NULL.
BufferedResourceHandler(scoped_ptr<ResourceHandler> next_handler,
ResourceDispatcherHostImpl* host,
+ PluginService* plugin_service,
net::URLRequest* request);
~BufferedResourceHandler() override;
@@ -92,6 +96,7 @@ class BufferedResourceHandler
scoped_refptr<ResourceResponse> response_;
ResourceDispatcherHostImpl* host_;
+ PluginService* plugin_service_;
scoped_refptr<net::IOBuffer> read_buffer_;
int read_buffer_size_;
int bytes_read_;
diff --git a/chromium/content/browser/loader/buffered_resource_handler_unittest.cc b/chromium/content/browser/loader/buffered_resource_handler_unittest.cc
new file mode 100644
index 00000000000..e4d3668c371
--- /dev/null
+++ b/chromium/content/browser/loader/buffered_resource_handler_unittest.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/loader/buffered_resource_handler.h"
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/browser/loader/resource_dispatcher_host_impl.h"
+#include "content/public/browser/resource_controller.h"
+#include "content/public/browser/resource_dispatcher_host_delegate.h"
+#include "content/public/browser/resource_request_info.h"
+#include "content/public/common/resource_response.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "content/public/test/test_utils.h"
+#include "content/test/fake_plugin_service.h"
+#include "net/url_request/url_request_context.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace content {
+
+namespace {
+
+class TestResourceHandler : public ResourceHandler {
+ public:
+ TestResourceHandler() : ResourceHandler(nullptr) {}
+
+ void SetController(ResourceController* controller) override {}
+
+ bool OnUploadProgress(uint64 position, uint64 size) override {
+ NOTREACHED();
+ return false;
+ }
+
+ bool OnRequestRedirected(const net::RedirectInfo& redirect_info,
+ ResourceResponse* response,
+ bool* defer) override {
+ NOTREACHED();
+ return false;
+ }
+
+ bool OnResponseStarted(ResourceResponse* response, bool* defer) override {
+ return false;
+ }
+
+ bool OnWillStart(const GURL& url, bool* defer) override {
+ NOTREACHED();
+ return false;
+ }
+
+ bool OnBeforeNetworkStart(const GURL& url, bool* defer) override {
+ NOTREACHED();
+ return false;
+ }
+
+ bool OnWillRead(scoped_refptr<net::IOBuffer>* buf,
+ int* buf_size,
+ int min_size) override {
+ NOTREACHED();
+ return false;
+ }
+
+ bool OnReadCompleted(int bytes_read, bool* defer) override {
+ NOTREACHED();
+ return false;
+ }
+
+ void OnResponseCompleted(const net::URLRequestStatus& status,
+ const std::string& security_info,
+ bool* defer) override {
+ }
+
+ void OnDataDownloaded(int bytes_downloaded) override {
+ NOTREACHED();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestResourceHandler);
+};
+
+class TestResourceDispatcherHost : public ResourceDispatcherHostImpl {
+ public:
+ explicit TestResourceDispatcherHost(bool stream_has_handler)
+ : stream_has_handler_(stream_has_handler),
+ intercepted_as_stream_(false) {}
+
+ bool intercepted_as_stream() const { return intercepted_as_stream_; }
+
+ scoped_ptr<ResourceHandler> CreateResourceHandlerForDownload(
+ net::URLRequest* request,
+ bool is_content_initiated,
+ bool must_download,
+ uint32 id,
+ scoped_ptr<DownloadSaveInfo> save_info,
+ const DownloadUrlParameters::OnStartedCallback& started_cb) override {
+ return scoped_ptr<ResourceHandler>(new TestResourceHandler).Pass();
+ }
+
+ scoped_ptr<ResourceHandler> MaybeInterceptAsStream(
+ net::URLRequest* request,
+ ResourceResponse* response,
+ std::string* payload) override {
+ if (stream_has_handler_) {
+ intercepted_as_stream_ = true;
+ return scoped_ptr<ResourceHandler>(new TestResourceHandler).Pass();
+ } else {
+ return scoped_ptr<ResourceHandler>();
+ }
+ }
+
+ private:
+ // Whether the URL request should be intercepted as a stream.
+ bool stream_has_handler_;
+
+ // Whether the URL request has been intercepted as a stream.
+ bool intercepted_as_stream_;
+};
+
+class TestResourceDispatcherHostDelegate
+ : public ResourceDispatcherHostDelegate {
+ public:
+ TestResourceDispatcherHostDelegate(bool must_download)
+ : must_download_(must_download) {
+ }
+
+ bool ShouldForceDownloadResource(const GURL& url,
+ const std::string& mime_type) override {
+ return must_download_;
+ }
+
+ private:
+ const bool must_download_;
+};
+
+class TestResourceController : public ResourceController {
+ public:
+ void Cancel() override {}
+
+ void CancelAndIgnore() override {
+ NOTREACHED();
+ }
+
+ void CancelWithError(int error_code) override {
+ NOTREACHED();
+ }
+
+ void Resume() override {
+ NOTREACHED();
+ }
+};
+
+class BufferedResourceHandlerTest : public testing::Test {
+ public:
+ BufferedResourceHandlerTest() : stream_has_handler_(false) {}
+
+ void set_stream_has_handler(bool stream_has_handler) {
+ stream_has_handler_ = stream_has_handler;
+ }
+
+ bool TestStreamIsIntercepted(bool allow_download,
+ bool must_download,
+ ResourceType request_resource_type);
+
+ private:
+ // Whether the URL request should be intercepted as a stream.
+ bool stream_has_handler_;
+
+ TestBrowserThreadBundle thread_bundle_;
+};
+
+bool BufferedResourceHandlerTest::TestStreamIsIntercepted(
+ bool allow_download,
+ bool must_download,
+ ResourceType request_resource_type) {
+ net::URLRequestContext context;
+ scoped_ptr<net::URLRequest> request(context.CreateRequest(
+ GURL("http://www.google.com"), net::DEFAULT_PRIORITY, nullptr));
+ bool is_main_frame = request_resource_type == RESOURCE_TYPE_MAIN_FRAME;
+ ResourceRequestInfo::AllocateForTesting(
+ request.get(),
+ request_resource_type,
+ nullptr, // context
+ 0, // render_process_id
+ 0, // render_view_id
+ 0, // render_frame_id
+ is_main_frame, // is_main_frame
+ false, // parent_is_main_frame
+ allow_download, // allow_download
+ true); // is_async
+
+ TestResourceDispatcherHost host(stream_has_handler_);
+ TestResourceDispatcherHostDelegate host_delegate(must_download);
+ host.SetDelegate(&host_delegate);
+
+ FakePluginService plugin_service;
+ scoped_ptr<ResourceHandler> buffered_handler(
+ new BufferedResourceHandler(
+ scoped_ptr<ResourceHandler>(new TestResourceHandler()).Pass(),
+ &host,
+ &plugin_service,
+ request.get()));
+ TestResourceController resource_controller;
+ buffered_handler->SetController(&resource_controller);
+
+ scoped_refptr<ResourceResponse> response(new ResourceResponse);
+ // The MIME type isn't important but it shouldn't be empty.
+ response->head.mime_type = "application/pdf";
+
+ bool defer = false;
+ buffered_handler->OnResponseStarted(response.get(), &defer);
+
+ content::RunAllPendingInMessageLoop();
+
+ return host.intercepted_as_stream();
+}
+
+// Test that stream requests are correctly intercepted under the right
+// circumstances.
+TEST_F(BufferedResourceHandlerTest, StreamHandling) {
+ bool allow_download;
+ bool must_download;
+ ResourceType resource_type;
+
+ // Ensure the stream is handled by MaybeInterceptAsStream in the
+ // ResourceDispatcherHost.
+ set_stream_has_handler(true);
+
+ // Main frame request with no download allowed. Stream shouldn't be
+ // intercepted.
+ allow_download = false;
+ must_download = false;
+ resource_type = RESOURCE_TYPE_MAIN_FRAME;
+ EXPECT_FALSE(
+ TestStreamIsIntercepted(allow_download, must_download, resource_type));
+
+ // Main frame request with download allowed. Stream should be intercepted.
+ allow_download = true;
+ must_download = false;
+ resource_type = RESOURCE_TYPE_MAIN_FRAME;
+ EXPECT_TRUE(
+ TestStreamIsIntercepted(allow_download, must_download, resource_type));
+
+ // Main frame request with download forced. Stream shouldn't be intercepted.
+ allow_download = true;
+ must_download = true;
+ resource_type = RESOURCE_TYPE_MAIN_FRAME;
+ EXPECT_FALSE(
+ TestStreamIsIntercepted(allow_download, must_download, resource_type));
+
+ // Sub-resource request with download not allowed. Stream shouldn't be
+ // intercepted.
+ allow_download = false;
+ must_download = false;
+ resource_type = RESOURCE_TYPE_SUB_RESOURCE;
+ EXPECT_FALSE(
+ TestStreamIsIntercepted(allow_download, must_download, resource_type));
+
+ // Object request with download not allowed. Stream should be intercepted.
+ allow_download = false;
+ must_download = false;
+ resource_type = RESOURCE_TYPE_OBJECT;
+ EXPECT_TRUE(
+ TestStreamIsIntercepted(allow_download, must_download, resource_type));
+
+ // Test the cases where the stream isn't handled by MaybeInterceptAsStream
+ // in the ResourceDispatcherHost.
+ set_stream_has_handler(false);
+
+ allow_download = false;
+ must_download = false;
+ resource_type = RESOURCE_TYPE_OBJECT;
+ EXPECT_FALSE(
+ TestStreamIsIntercepted(allow_download, must_download, resource_type));
+
+ allow_download = true;
+ must_download = false;
+ resource_type = RESOURCE_TYPE_MAIN_FRAME;
+ EXPECT_FALSE(
+ TestStreamIsIntercepted(allow_download, must_download, resource_type));
+}
+
+} // namespace
+
+} // namespace content
diff --git a/chromium/content/browser/loader/certificate_resource_handler.cc b/chromium/content/browser/loader/certificate_resource_handler.cc
index eb1976bef05..b6226ca5510 100644
--- a/chromium/content/browser/loader/certificate_resource_handler.cc
+++ b/chromium/content/browser/loader/certificate_resource_handler.cc
@@ -4,26 +4,21 @@
#include "content/browser/loader/certificate_resource_handler.h"
-#include "base/strings/string_util.h"
+#include <limits.h>
+
+#include "components/mime_util/mime_util.h"
#include "content/browser/loader/resource_request_info_impl.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/common/resource_response.h"
#include "net/base/io_buffer.h"
-#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"
namespace content {
-CertificateResourceHandler::CertificateResourceHandler(
- net::URLRequest* request)
+CertificateResourceHandler::CertificateResourceHandler(net::URLRequest* request)
: ResourceHandler(request),
- content_length_(0),
- read_buffer_(NULL),
- resource_buffer_(NULL),
+ buffer_(new net::GrowableIOBuffer),
cert_type_(net::CERTIFICATE_MIME_TYPE_UNKNOWN) {
}
@@ -44,7 +39,8 @@ bool CertificateResourceHandler::OnRequestRedirected(
bool CertificateResourceHandler::OnResponseStarted(ResourceResponse* resp,
bool* defer) {
- cert_type_ = net::GetCertificateMimeTypeForMimeType(resp->head.mime_type);
+ cert_type_ =
+ mime_util::GetCertificateMimeTypeForMimeType(resp->head.mime_type);
return cert_type_ != net::CERTIFICATE_MIME_TYPE_UNKNOWN;
}
@@ -60,34 +56,40 @@ bool CertificateResourceHandler::OnBeforeNetworkStart(const GURL& url,
bool CertificateResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf,
int* buf_size,
int min_size) {
- static const int kReadBufSize = 32768;
+ static const int kInitialBufferSizeInBytes = 32768;
+ static const int kMaxCertificateSizeInBytes = 1024 * 1024;
// TODO(gauravsh): Should we use 'min_size' here?
- DCHECK(buf && buf_size);
- if (!read_buffer_.get()) {
- read_buffer_ = new net::IOBuffer(kReadBufSize);
+ DCHECK(buf);
+ DCHECK(buf_size);
+
+ if (buffer_->capacity() == 0) {
+ buffer_->SetCapacity(kInitialBufferSizeInBytes);
+ } else if (buffer_->RemainingCapacity() == 0) {
+ int capacity = buffer_->capacity();
+ if (capacity >= kMaxCertificateSizeInBytes)
+ return false;
+ static_assert(kMaxCertificateSizeInBytes < INT_MAX / 2,
+ "The size limit ensures the capacity remains in bounds.");
+ capacity *= 2;
+ if (capacity > kMaxCertificateSizeInBytes)
+ capacity = kMaxCertificateSizeInBytes;
+ buffer_->SetCapacity(capacity);
}
- *buf = read_buffer_.get();
- *buf_size = kReadBufSize;
+
+ *buf = buffer_.get();
+ *buf_size = buffer_->RemainingCapacity();
return true;
}
bool CertificateResourceHandler::OnReadCompleted(int bytes_read, bool* defer) {
+ DCHECK_LE(0, bytes_read);
+ DCHECK_LE(bytes_read, buffer_->RemainingCapacity());
if (!bytes_read)
return true;
- // We have more data to read.
- DCHECK(read_buffer_.get());
- content_length_ += bytes_read;
-
- // 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);
- // TODO(gauravsh): Should this be handled by a separate thread?
- buffer_.push_back(std::make_pair(buffer, bytes_read));
-
+ buffer_->set_offset(buffer_->offset() + bytes_read);
return true;
}
@@ -98,41 +100,13 @@ void CertificateResourceHandler::OnResponseCompleted(
if (urs.status() != net::URLRequestStatus::SUCCESS)
return;
- AssembleResource();
-
- const void* content_bytes = NULL;
- if (resource_buffer_.get())
- content_bytes = resource_buffer_->data();
-
// Note that it's up to the browser to verify that the certificate
// data is well-formed.
const ResourceRequestInfo* info = GetRequestInfo();
GetContentClient()->browser()->AddCertificate(
- cert_type_, content_bytes, content_length_,
- info->GetChildID(), info->GetRenderFrameID());
-}
-
-void CertificateResourceHandler::AssembleResource() {
- // 0-length IOBuffers are not allowed.
- if (content_length_ == 0) {
- resource_buffer_ = NULL;
- return;
- }
-
- // Create the new buffer.
- resource_buffer_ = new net::IOBuffer(content_length_);
-
- // Copy the data into it.
- size_t bytes_copied = 0;
- for (size_t i = 0; i < buffer_.size(); ++i) {
- net::IOBuffer* data = buffer_[i].first.get();
- size_t data_len = buffer_[i].second;
- DCHECK(data != NULL);
- DCHECK_LE(bytes_copied + data_len, content_length_);
- memcpy(resource_buffer_->data() + bytes_copied, data->data(), data_len);
- bytes_copied += data_len;
- }
- DCHECK_EQ(content_length_, bytes_copied);
+ cert_type_, buffer_->StartOfBuffer(),
+ static_cast<size_t>(buffer_->offset()), info->GetChildID(),
+ info->GetRenderFrameID());
}
void CertificateResourceHandler::OnDataDownloaded(int bytes_downloaded) {
diff --git a/chromium/content/browser/loader/certificate_resource_handler.h b/chromium/content/browser/loader/certificate_resource_handler.h
index e8ce4ba4be3..39f3e0e3b11 100644
--- a/chromium/content/browser/loader/certificate_resource_handler.h
+++ b/chromium/content/browser/loader/certificate_resource_handler.h
@@ -6,17 +6,14 @@
#define CONTENT_BROWSER_LOADER_CERTIFICATE_RESOURCE_HANDLER_H_
#include <string>
-#include <utility>
-#include <vector>
-#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
#include "content/browser/loader/resource_handler.h"
#include "net/base/mime_util.h"
namespace net {
-class IOBuffer;
+class GrowableIOBuffer;
class URLRequest;
class URLRequestStatus;
} // namespace net
@@ -66,16 +63,9 @@ class CertificateResourceHandler : public ResourceHandler {
void OnDataDownloaded(int bytes_downloaded) override;
private:
- typedef std::vector<std::pair<scoped_refptr<net::IOBuffer>,
- size_t> > ContentVector;
-
- void AssembleResource();
-
- size_t content_length_;
- ContentVector buffer_;
- scoped_refptr<net::IOBuffer> read_buffer_;
- scoped_refptr<net::IOBuffer> resource_buffer_; // Downloaded certificate.
+ scoped_refptr<net::GrowableIOBuffer> buffer_;
net::CertificateMimeType cert_type_;
+
DISALLOW_COPY_AND_ASSIGN(CertificateResourceHandler);
};
diff --git a/chromium/content/browser/loader/cross_site_resource_handler.cc b/chromium/content/browser/loader/cross_site_resource_handler.cc
index 2ec5ee56934..ccdd321ef33 100644
--- a/chromium/content/browser/loader/cross_site_resource_handler.cc
+++ b/chromium/content/browser/loader/cross_site_resource_handler.cc
@@ -68,6 +68,13 @@ void OnCrossSiteResponseHelper(const CrossSiteResponseParams& params) {
RenderFrameHostImpl::FromID(params.global_request_id.child_id,
params.render_frame_id);
if (rfh) {
+ if (rfh->GetParent()) {
+ // We should only swap processes for subframes in --site-per-process mode.
+ // CrossSiteResourceHandler is not installed on subframe requests in
+ // default Chrome.
+ CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess));
+ }
rfh->OnCrossSiteResponse(
params.global_request_id, cross_site_transferring_request.Pass(),
params.transfer_url_chain, params.referrer,
@@ -91,7 +98,8 @@ void OnDeferredAfterResponseStartedHelper(
// 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));
+ CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess));
RenderFrameHostImpl* rfh =
RenderFrameHostImpl::FromID(process_id, render_frame_id);
if (!rfh)
@@ -367,9 +375,6 @@ void CrossSiteResourceHandler::StartCrossSiteTransition(
int render_frame_id = info->GetRenderFrameID();
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);
BrowserThread::PostTask(
diff --git a/chromium/content/browser/loader/global_routing_id.h b/chromium/content/browser/loader/global_routing_id.h
index 4715c5a9ee8..a15e93d78da 100644
--- a/chromium/content/browser/loader/global_routing_id.h
+++ b/chromium/content/browser/loader/global_routing_id.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_PUBLIC_BROWSER_GLOBAL_ROUTING_ID_H_
-#define CONTENT_PUBLIC_BROWSER_GLOBAL_ROUTING_ID_H_
+#ifndef CONTENT_BROWSER_LOADER_GLOBAL_ROUTING_ID_H_
+#define CONTENT_BROWSER_LOADER_GLOBAL_ROUTING_ID_H_
namespace content {
@@ -39,4 +39,4 @@ struct GlobalRoutingID {
} // namespace content
-#endif // CONTENT_PUBLIC_BROWSER_GLOBAL_ROUTING_ID_H_
+#endif // CONTENT_BROWSER_LOADER_GLOBAL_ROUTING_ID_H_
diff --git a/chromium/content/browser/loader/navigation_resource_handler.cc b/chromium/content/browser/loader/navigation_resource_handler.cc
index 393b295776e..ec6119a830c 100644
--- a/chromium/content/browser/loader/navigation_resource_handler.cc
+++ b/chromium/content/browser/loader/navigation_resource_handler.cc
@@ -29,7 +29,7 @@ NavigationResourceHandler::NavigationResourceHandler(
NavigationResourceHandler::~NavigationResourceHandler() {
if (core_) {
- core_->NotifyRequestFailed(net::ERR_ABORTED);
+ core_->NotifyRequestFailed(false, net::ERR_ABORTED);
DetachFromCore();
}
}
@@ -131,7 +131,8 @@ void NavigationResourceHandler::OnResponseCompleted(
if (core_) {
DCHECK_NE(net::OK, status.error());
- core_->NotifyRequestFailed(status.error());
+ core_->NotifyRequestFailed(request()->response_info().was_cached,
+ status.error());
DetachFromCore();
}
}
diff --git a/chromium/content/browser/loader/navigation_resource_handler.h b/chromium/content/browser/loader/navigation_resource_handler.h
index 59090260de9..a291e27f085 100644
--- a/chromium/content/browser/loader/navigation_resource_handler.h
+++ b/chromium/content/browser/loader/navigation_resource_handler.h
@@ -57,4 +57,4 @@ class NavigationResourceHandler : public ResourceHandler {
} // namespace content
-#endif // CONTENT_BROWSER_LOADER_CERTIFICATE_RESOURCE_HANDLER_H_
+#endif // CONTENT_BROWSER_LOADER_NAVIGATION_RESOURCE_HANDLER_H_
diff --git a/chromium/content/browser/loader/navigation_url_loader.cc b/chromium/content/browser/loader/navigation_url_loader.cc
index e0e1e9e7735..6ea915e32e0 100644
--- a/chromium/content/browser/loader/navigation_url_loader.cc
+++ b/chromium/content/browser/loader/navigation_url_loader.cc
@@ -14,23 +14,20 @@ static NavigationURLLoaderFactory* g_factory = nullptr;
scoped_ptr<NavigationURLLoader> NavigationURLLoader::Create(
BrowserContext* browser_context,
- int64 frame_tree_node_id,
- const CommonNavigationParams& common_params,
+ int frame_tree_node_id,
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);
+ request_info.Pass(), delegate);
}
return scoped_ptr<NavigationURLLoader>(new NavigationURLLoaderImpl(
- browser_context, frame_tree_node_id, common_params, request_info.Pass(),
- request_body, delegate));
+ browser_context, frame_tree_node_id, request_info.Pass(), delegate));
}
void NavigationURLLoader::SetFactoryForTesting(
NavigationURLLoaderFactory* factory) {
+ DCHECK(g_factory == nullptr || factory == nullptr);
g_factory = factory;
}
diff --git a/chromium/content/browser/loader/navigation_url_loader.h b/chromium/content/browser/loader/navigation_url_loader.h
index 7713e736610..4b8c0524c1b 100644
--- a/chromium/content/browser/loader/navigation_url_loader.h
+++ b/chromium/content/browser/loader/navigation_url_loader.h
@@ -15,7 +15,6 @@ namespace content {
class BrowserContext;
class NavigationURLLoaderDelegate;
class NavigationURLLoaderFactory;
-class ResourceRequestBody;
struct CommonNavigationParams;
struct NavigationRequestInfo;
@@ -35,10 +34,8 @@ class CONTENT_EXPORT NavigationURLLoader {
// 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,
+ int frame_tree_node_id,
scoped_ptr<NavigationRequestInfo> request_info,
- ResourceRequestBody* request_body,
NavigationURLLoaderDelegate* delegate);
// For testing purposes; sets the factory for use in testing.
diff --git a/chromium/content/browser/loader/navigation_url_loader_delegate.h b/chromium/content/browser/loader/navigation_url_loader_delegate.h
index 199f48a2a98..62351aebf5f 100644
--- a/chromium/content/browser/loader/navigation_url_loader_delegate.h
+++ b/chromium/content/browser/loader/navigation_url_loader_delegate.h
@@ -36,8 +36,15 @@ class CONTENT_EXPORT NavigationURLLoaderDelegate {
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;
+ // network error code for the failure. |has_stale_copy_in_cache| is true if
+ // there is a stale copy of the unreachable page in cache.
+ virtual void OnRequestFailed(bool has_stale_copy_in_cache, int net_error) = 0;
+
+ // Called after the network request has begun on the IO thread at time
+ // |timestamp|. This is just a thread hop but is used to compare timing
+ // against the pre-PlzNavigate codepath which didn't start the network request
+ // until after the renderer was initialized.
+ virtual void OnRequestStarted(base::TimeTicks timestamp) = 0;
protected:
NavigationURLLoaderDelegate() {}
diff --git a/chromium/content/browser/loader/navigation_url_loader_factory.h b/chromium/content/browser/loader/navigation_url_loader_factory.h
index ddb4fe1dc3d..e6a6d8f0b10 100644
--- a/chromium/content/browser/loader/navigation_url_loader_factory.h
+++ b/chromium/content/browser/loader/navigation_url_loader_factory.h
@@ -17,10 +17,8 @@ class NavigationURLLoaderFactory {
public:
virtual scoped_ptr<NavigationURLLoader> CreateLoader(
BrowserContext* browser_context,
- int64 frame_tree_node_id,
- const CommonNavigationParams& common_params,
+ int frame_tree_node_id,
scoped_ptr<NavigationRequestInfo> request_info,
- ResourceRequestBody* request_body,
NavigationURLLoaderDelegate* delegate) = 0;
protected:
diff --git a/chromium/content/browser/loader/navigation_url_loader_impl.cc b/chromium/content/browser/loader/navigation_url_loader_impl.cc
index b6dbed08685..9d7db596e4a 100644
--- a/chromium/content/browser/loader/navigation_url_loader_impl.cc
+++ b/chromium/content/browser/loader/navigation_url_loader_impl.cc
@@ -17,10 +17,8 @@ namespace content {
NavigationURLLoaderImpl::NavigationURLLoaderImpl(
BrowserContext* browser_context,
- int64 frame_tree_node_id,
- const CommonNavigationParams& common_params,
+ int frame_tree_node_id,
scoped_ptr<NavigationRequestInfo> request_info,
- ResourceRequestBody* request_body,
NavigationURLLoaderDelegate* delegate)
: delegate_(delegate),
weak_factory_(this) {
@@ -31,8 +29,7 @@ NavigationURLLoaderImpl::NavigationURLLoaderImpl(
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)));
+ base::Passed(&request_info)));
}
NavigationURLLoaderImpl::~NavigationURLLoaderImpl() {
@@ -67,10 +64,17 @@ void NavigationURLLoaderImpl::NotifyResponseStarted(
delegate_->OnResponseStarted(response, body.Pass());
}
-void NavigationURLLoaderImpl::NotifyRequestFailed(int net_error) {
+void NavigationURLLoaderImpl::NotifyRequestFailed(bool in_cache,
+ int net_error) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- delegate_->OnRequestFailed(net_error);
+ delegate_->OnRequestFailed(in_cache, net_error);
+}
+
+void NavigationURLLoaderImpl::NotifyRequestStarted(base::TimeTicks timestamp) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ delegate_->OnRequestStarted(timestamp);
}
} // namespace content
diff --git a/chromium/content/browser/loader/navigation_url_loader_impl.h b/chromium/content/browser/loader/navigation_url_loader_impl.h
index ecfd2382e8e..f91458e9f24 100644
--- a/chromium/content/browser/loader/navigation_url_loader_impl.h
+++ b/chromium/content/browser/loader/navigation_url_loader_impl.h
@@ -9,6 +9,7 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
#include "content/browser/loader/navigation_url_loader.h"
namespace net {
@@ -25,10 +26,8 @@ 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,
+ int frame_tree_node_id,
scoped_ptr<NavigationRequestInfo> request_info,
- ResourceRequestBody* request_body,
NavigationURLLoaderDelegate* delegate);
~NavigationURLLoaderImpl() override;
@@ -48,7 +47,11 @@ class NavigationURLLoaderImpl : public NavigationURLLoader {
scoped_ptr<StreamHandle> body);
// Notifies the delegate the request failed to return a response.
- void NotifyRequestFailed(int net_error);
+ void NotifyRequestFailed(bool in_cache, int net_error);
+
+ // Notifies the delegate the begin navigation request was handled and a
+ // potential first network request is about to be made.
+ void NotifyRequestStarted(base::TimeTicks timestamp);
NavigationURLLoaderDelegate* delegate_;
diff --git a/chromium/content/browser/loader/navigation_url_loader_impl_core.cc b/chromium/content/browser/loader/navigation_url_loader_impl_core.cc
index 48845e8aa0c..7cbf6999946 100644
--- a/chromium/content/browser/loader/navigation_url_loader_impl_core.cc
+++ b/chromium/content/browser/loader/navigation_url_loader_impl_core.cc
@@ -6,6 +6,7 @@
#include "base/bind.h"
#include "base/location.h"
+#include "base/time/time.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"
@@ -36,16 +37,18 @@ NavigationURLLoaderImplCore::~NavigationURLLoaderImplCore() {
void NavigationURLLoaderImplCore::Start(
ResourceContext* resource_context,
- int64 frame_tree_node_id,
- const CommonNavigationParams& common_params,
- scoped_ptr<NavigationRequestInfo> request_info,
- ResourceRequestBody* request_body) {
+ int frame_tree_node_id,
+ scoped_ptr<NavigationRequestInfo> request_info) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&NavigationURLLoaderImpl::NotifyRequestStarted, loader_,
+ base::TimeTicks::Now()));
+
ResourceDispatcherHostImpl::Get()->BeginNavigationRequest(
resource_context, frame_tree_node_id,
- common_params, *request_info, request_body,
- this);
+ *request_info, this);
}
void NavigationURLLoaderImplCore::FollowRedirect() {
@@ -92,13 +95,14 @@ void NavigationURLLoaderImplCore::NotifyResponseStarted(
response->DeepCopy(), base::Passed(&body)));
}
-void NavigationURLLoaderImplCore::NotifyRequestFailed(int net_error) {
+void NavigationURLLoaderImplCore::NotifyRequestFailed(bool in_cache,
+ int net_error) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&NavigationURLLoaderImpl::NotifyRequestFailed, loader_,
- net_error));
+ in_cache, 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
index f31d3ccbdc3..77f90e31bf3 100644
--- a/chromium/content/browser/loader/navigation_url_loader_impl_core.h
+++ b/chromium/content/browser/loader/navigation_url_loader_impl_core.h
@@ -40,10 +40,8 @@ class 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);
+ int frame_tree_node_id,
+ scoped_ptr<NavigationRequestInfo> request_info);
// Follows the current pending redirect.
void FollowRedirect();
@@ -61,7 +59,7 @@ class NavigationURLLoaderImplCore {
scoped_ptr<StreamHandle> body);
// Notifies |loader_| on the UI thread that the request failed.
- void NotifyRequestFailed(int net_error);
+ void NotifyRequestFailed(bool in_cache, int net_error);
private:
base::WeakPtr<NavigationURLLoaderImpl> loader_;
diff --git a/chromium/content/browser/loader/navigation_url_loader_unittest.cc b/chromium/content/browser/loader/navigation_url_loader_unittest.cc
index e81cad218be..c636cda46a6 100644
--- a/chromium/content/browser/loader/navigation_url_loader_unittest.cc
+++ b/chromium/content/browser/loader/navigation_url_loader_unittest.cc
@@ -24,6 +24,7 @@
#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/load_flags.h"
#include "net/base/net_errors.h"
#include "net/http/http_response_headers.h"
#include "net/url_request/redirect_info.h"
@@ -62,8 +63,7 @@ class StreamProtocolHandler
class TestNavigationURLLoaderDelegate : public NavigationURLLoaderDelegate {
public:
TestNavigationURLLoaderDelegate()
- : net_error_(0) {
- }
+ : net_error_(0), on_request_handled_counter_(0) {}
const net::RedirectInfo& redirect_info() const { return redirect_info_; }
ResourceResponse* redirect_response() const {
@@ -72,6 +72,7 @@ class TestNavigationURLLoaderDelegate : public NavigationURLLoaderDelegate {
ResourceResponse* response() const { return response_.get(); }
StreamHandle* body() const { return body_.get(); }
int net_error() const { return net_error_; }
+ int on_request_handled_counter() const { return on_request_handled_counter_; }
void WaitForRequestRedirected() {
request_redirected_.reset(new base::RunLoop);
@@ -113,18 +114,24 @@ class TestNavigationURLLoaderDelegate : public NavigationURLLoaderDelegate {
response_started_->Quit();
}
- void OnRequestFailed(int net_error) override {
+ void OnRequestFailed(bool in_cache, int net_error) override {
net_error_ = net_error;
ASSERT_TRUE(request_failed_);
request_failed_->Quit();
}
+ void OnRequestStarted(base::TimeTicks timestamp) override {
+ ASSERT_FALSE(timestamp.is_null());
+ ++on_request_handled_counter_;
+ }
+
private:
net::RedirectInfo redirect_info_;
scoped_refptr<ResourceResponse> redirect_response_;
scoped_refptr<ResourceResponse> response_;
scoped_ptr<StreamHandle> body_;
int net_error_;
+ int on_request_handled_counter_;
scoped_ptr<base::RunLoop> request_redirected_;
scoped_ptr<base::RunLoop> response_started_;
@@ -163,25 +170,23 @@ class NavigationURLLoaderTest : public testing::Test {
request_context->set_job_factory(&job_factory_);
// NavigationURLLoader is only used for browser-side navigations.
- CommandLine::ForCurrentProcess()->AppendSwitch(
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableBrowserSideNavigation);
}
scoped_ptr<NavigationURLLoader> MakeTestLoader(
const GURL& url,
NavigationURLLoaderDelegate* delegate) {
- FrameHostMsg_BeginNavigation_Params begin_params;
+ BeginNavigationParams begin_params(
+ "GET", std::string(), net::LOAD_NORMAL, false);
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;
+ new NavigationRequestInfo(common_params, begin_params, url, true, false,
+ scoped_refptr<ResourceRequestBody>()));
return NavigationURLLoader::Create(
- browser_context_.get(), 0,
- common_params, request_info.Pass(), nullptr, delegate);
+ browser_context_.get(), 0, request_info.Pass(), delegate);
}
// Helper function for fetching the body of a URL to a string.
@@ -190,7 +195,7 @@ class NavigationURLLoaderTest : public testing::Test {
net::URLRequestContext* request_context =
browser_context_->GetResourceContext()->GetRequestContext();
scoped_ptr<net::URLRequest> request(request_context->CreateRequest(
- url, net::DEFAULT_PRIORITY, &delegate, nullptr));
+ url, net::DEFAULT_PRIORITY, &delegate));
request->Start();
base::RunLoop().Run();
@@ -222,6 +227,8 @@ TEST_F(NavigationURLLoaderTest, Basic) {
// Check the body is correct.
EXPECT_EQ(net::URLRequestTestJob::test_data_1(),
FetchURL(delegate.body()->GetURL()));
+
+ EXPECT_EQ(1, delegate.on_request_handled_counter());
}
// Tests that request failures are propagated correctly.
@@ -233,6 +240,7 @@ TEST_F(NavigationURLLoaderTest, RequestFailed) {
// Wait for the request to fail as expected.
delegate.WaitForRequestFailed();
EXPECT_EQ(net::ERR_UNKNOWN_URL_SCHEME, delegate.net_error());
+ EXPECT_EQ(1, delegate.on_request_handled_counter());
}
// Test that redirects are sent to the delegate.
@@ -252,6 +260,7 @@ TEST_F(NavigationURLLoaderTest, RequestRedirected) {
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());
+ EXPECT_EQ(1, delegate.on_request_handled_counter());
// Wait for the response to complete.
loader->FollowRedirect();
@@ -265,6 +274,8 @@ TEST_F(NavigationURLLoaderTest, RequestRedirected) {
EXPECT_TRUE(net::URLRequestTestJob::ProcessOnePendingMessage());
EXPECT_EQ(net::URLRequestTestJob::test_data_2(),
FetchURL(delegate.body()->GetURL()));
+
+ EXPECT_EQ(1, delegate.on_request_handled_counter());
}
// Tests that the destroying the loader cancels the request.
@@ -325,6 +336,7 @@ TEST_F(NavigationURLLoaderTest, CancelByContext) {
// Wait for the request to now be aborted.
delegate.WaitForRequestFailed();
EXPECT_EQ(net::ERR_ABORTED, delegate.net_error());
+ EXPECT_EQ(1, delegate.on_request_handled_counter());
}
// Tests that, if the request is blocked by the ResourceDispatcherHostDelegate,
@@ -340,6 +352,7 @@ TEST_F(NavigationURLLoaderTest, RequestBlocked) {
// Wait for the request to fail as expected.
delegate.WaitForRequestFailed();
EXPECT_EQ(net::ERR_ABORTED, delegate.net_error());
+ EXPECT_EQ(1, delegate.on_request_handled_counter());
host_.SetDelegate(nullptr);
}
diff --git a/chromium/content/browser/loader/power_save_block_resource_throttle.cc b/chromium/content/browser/loader/power_save_block_resource_throttle.cc
index 7a084b0a71d..42e0b0e46d8 100644
--- a/chromium/content/browser/loader/power_save_block_resource_throttle.cc
+++ b/chromium/content/browser/loader/power_save_block_resource_throttle.cc
@@ -41,7 +41,7 @@ const char* PowerSaveBlockResourceThrottle::GetNameForLogging() const {
void PowerSaveBlockResourceThrottle::ActivatePowerSaveBlocker() {
power_save_blocker_ = PowerSaveBlocker::Create(
PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
- "Uploading data.");
+ PowerSaveBlocker::kReasonOther, "Uploading data");
}
} // namespace content
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 00e63928076..6f402135c88 100644
--- a/chromium/content/browser/loader/redirect_to_file_resource_handler.cc
+++ b/chromium/content/browser/loader/redirect_to_file_resource_handler.cc
@@ -15,7 +15,7 @@
#include "net/base/io_buffer.h"
#include "net/base/mime_sniffer.h"
#include "net/base/net_errors.h"
-#include "storage/common/blob/shareable_file_reference.h"
+#include "storage/browser/blob/shareable_file_reference.h"
using storage::ShareableFileReference;
diff --git a/chromium/content/browser/loader/resource_dispatcher_host_browsertest.cc b/chromium/content/browser/loader/resource_dispatcher_host_browsertest.cc
index 8673c07b086..bb333a526eb 100644
--- a/chromium/content/browser/loader/resource_dispatcher_host_browsertest.cc
+++ b/chromium/content/browser/loader/resource_dispatcher_host_browsertest.cc
@@ -10,6 +10,9 @@
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/resource_dispatcher_host.h"
+#include "content/public/browser/resource_dispatcher_host_delegate.h"
+#include "content/public/browser/resource_request_info.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/url_constants.h"
#include "content/public/test/browser_test_utils.h"
@@ -39,11 +42,9 @@ class ResourceDispatcherHostBrowserTest : public ContentBrowserTest,
void SetUpOnMainThread() override {
base::FilePath path = GetTestFilePath("", "");
BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
+ BrowserThread::IO, FROM_HERE,
base::Bind(
- &net::URLRequestMockHTTPJob::AddUrlHandler,
- path,
+ &net::URLRequestMockHTTPJob::AddUrlHandlers, path,
make_scoped_refptr(content::BrowserThread::GetBlockingPool())));
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
@@ -463,7 +464,7 @@ IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest, CookiePolicy) {
base::Bind(&HandleRedirectRequest, "/redirect?"));
std::string set_cookie_url(base::StringPrintf(
- "http://localhost:%d/set_cookie.html", embedded_test_server()->port()));
+ "http://localhost:%u/set_cookie.html", embedded_test_server()->port()));
GURL url(embedded_test_server()->GetURL("/redirect?" + set_cookie_url));
ShellContentBrowserClient::SetSwapProcessesForRedirect(true);
@@ -472,4 +473,49 @@ IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest, CookiePolicy) {
CheckTitleTest(url, "cookie set");
}
+class PageTransitionResourceDispatcherHostDelegate
+ : public ResourceDispatcherHostDelegate {
+ public:
+ PageTransitionResourceDispatcherHostDelegate(GURL watch_url)
+ : watch_url_(watch_url) {}
+
+ // ResourceDispatcherHostDelegate implementation:
+ void RequestBeginning(net::URLRequest* request,
+ ResourceContext* resource_context,
+ AppCacheService* appcache_service,
+ ResourceType resource_type,
+ ScopedVector<ResourceThrottle>* throttles) override {
+ if (request->url() == watch_url_) {
+ const ResourceRequestInfo* info =
+ ResourceRequestInfo::ForRequest(request);
+ page_transition_ = info->GetPageTransition();
+ }
+ }
+
+ ui::PageTransition page_transition() { return page_transition_; }
+
+ private:
+ GURL watch_url_;
+ ui::PageTransition page_transition_;
+};
+
+// Test that ui::PAGE_TRANSITION_CLIENT_REDIRECT is correctly set
+// when encountering a meta refresh tag.
+IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest,
+ PageTransitionClientRedirect) {
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
+ PageTransitionResourceDispatcherHostDelegate delegate(
+ embedded_test_server()->GetURL("/title1.html"));
+ ResourceDispatcherHost::Get()->SetDelegate(&delegate);
+
+ NavigateToURLBlockUntilNavigationsComplete(
+ shell(),
+ embedded_test_server()->GetURL("/client_redirect.html"),
+ 2);
+
+ EXPECT_TRUE(
+ delegate.page_transition() & ui::PAGE_TRANSITION_CLIENT_REDIRECT);
+}
+
} // namespace content
diff --git a/chromium/content/browser/loader/resource_dispatcher_host_impl.cc b/chromium/content/browser/loader/resource_dispatcher_host_impl.cc
index 26ecf1d8dbb..9828244029a 100644
--- a/chromium/content/browser/loader/resource_dispatcher_host_impl.cc
+++ b/chromium/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -19,10 +19,12 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/shared_memory.h"
#include "base/message_loop/message_loop.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
#include "base/metrics/sparse_histogram.h"
+#include "base/profiler/scoped_tracker.h"
#include "base/stl_util.h"
#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/time/time.h"
#include "content/browser/appcache/appcache_interceptor.h"
#include "content/browser/appcache/chrome_appcache_service.h"
#include "content/browser/cert_store_impl.h"
@@ -65,6 +67,7 @@
#include "content/public/browser/download_manager.h"
#include "content/public/browser/download_url_parameters.h"
#include "content/public/browser/global_request_id.h"
+#include "content/public/browser/plugin_service.h"
#include "content/public/browser/resource_dispatcher_host_delegate.h"
#include "content/public/browser/resource_request_details.h"
#include "content/public/browser/resource_throttle.h"
@@ -93,16 +96,11 @@
#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/blob/shareable_file_reference.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"
-#if defined(ENABLE_PLUGINS)
-#include "content/browser/plugin_service_impl.h"
-#endif
-
using base::Time;
using base::TimeDelta;
using base::TimeTicks;
@@ -231,9 +229,9 @@ void AbortRequestBeforeItStarts(ResourceMessageFilter* filter,
}
void SetReferrerForRequest(net::URLRequest* request, const Referrer& referrer) {
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (!referrer.url.is_valid() ||
- base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kNoReferrers)) {
+ command_line->HasSwitch(switches::kNoReferrers)) {
request->SetReferrer(std::string());
} else {
request->SetReferrer(referrer.url.spec());
@@ -242,15 +240,28 @@ void SetReferrerForRequest(net::URLRequest* request, const Referrer& referrer) {
net::URLRequest::ReferrerPolicy net_referrer_policy =
net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE;
switch (referrer.policy) {
- case blink::WebReferrerPolicyDefault:
- net_referrer_policy =
- net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE;
- break;
case blink::WebReferrerPolicyAlways:
case blink::WebReferrerPolicyNever:
case blink::WebReferrerPolicyOrigin:
net_referrer_policy = net::URLRequest::NEVER_CLEAR_REFERRER;
break;
+ case blink::WebReferrerPolicyNoReferrerWhenDowngrade:
+ net_referrer_policy =
+ net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE;
+ break;
+ case blink::WebReferrerPolicyOriginWhenCrossOrigin:
+ net_referrer_policy =
+ net::URLRequest::ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN;
+ break;
+ case blink::WebReferrerPolicyDefault:
+ default:
+ net_referrer_policy =
+ command_line->HasSwitch(switches::kReducedReferrerGranularity)
+ ? net::URLRequest::
+ REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN
+ : net::URLRequest::
+ CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE;
+ break;
}
request->set_referrer_policy(net_referrer_policy);
}
@@ -340,8 +351,7 @@ void NotifyRedirectOnUI(int render_process_id,
static_cast<WebContentsImpl*>(WebContents::FromRenderFrameHost(host));
if (!web_contents)
return;
- web_contents->DidGetRedirectForResourceRequest(
- host->render_view_host(), *details.get());
+ web_contents->DidGetRedirectForResourceRequest(host, *details.get());
}
void NotifyResponseOnUI(int render_process_id,
@@ -396,7 +406,7 @@ void LogResourceRequestTimeOnUI(
int render_process_id,
int render_frame_id,
const GURL& url) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
RenderFrameHostImpl* host =
RenderFrameHostImpl::FromID(render_process_id, render_frame_id);
if (host != NULL) {
@@ -427,7 +437,7 @@ ResourceDispatcherHostImpl::ResourceDispatcherHostImpl()
filter_(NULL),
delegate_(NULL),
allow_cross_origin_auth_prompt_(false) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(!g_resource_dispatcher_host);
g_resource_dispatcher_host = this;
@@ -489,7 +499,7 @@ void ResourceDispatcherHostImpl::ResumeResponseDeferredAtStart(
void ResourceDispatcherHostImpl::CancelRequestsForContext(
ResourceContext* context) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(context);
CHECK(ContainsKey(active_resource_contexts_, context));
@@ -586,6 +596,7 @@ DownloadInterruptReason ResourceDispatcherHostImpl::BeginDownload(
int child_id,
int route_id,
bool prefer_cache,
+ bool do_not_prompt_for_login,
scoped_ptr<DownloadSaveInfo> save_info,
uint32 download_id,
const DownloadStartedCallback& started_callback) {
@@ -603,7 +614,7 @@ DownloadInterruptReason ResourceDispatcherHostImpl::BeginDownload(
SetReferrerForRequest(request.get(), referrer);
- int extra_load_flags = net::LOAD_IS_DOWNLOAD;
+ int extra_load_flags = net::LOAD_NORMAL;
if (prefer_cache) {
// If there is upload data attached, only retrieve from cache because there
// is no current mechanism to prompt the user for their consent for a
@@ -648,6 +659,7 @@ DownloadInterruptReason ResourceDispatcherHostImpl::BeginDownload(
ResourceRequestInfoImpl* extra_info =
CreateRequestInfo(child_id, route_id, true, context);
+ extra_info->set_do_not_prompt_for_login(do_not_prompt_for_login);
extra_info->AssociateWithRequest(request.get()); // Request takes ownership.
if (request->url().SchemeIs(url::kBlobScheme)) {
@@ -681,7 +693,7 @@ void ResourceDispatcherHostImpl::ClearLoginDelegateForRequest(
}
void ResourceDispatcherHostImpl::Shutdown() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
BrowserThread::PostTask(BrowserThread::IO,
FROM_HERE,
base::Bind(&ResourceDispatcherHostImpl::OnShutdown,
@@ -782,15 +794,16 @@ bool ResourceDispatcherHostImpl::HandleExternalProtocol(ResourceLoader* loader,
return false;
return delegate_->HandleExternalProtocol(
- url, info->GetChildID(), info->GetRouteID());
+ url, info->GetChildID(), info->GetRouteID(), info->IsMainFrame(),
+ info->GetPageTransition(), info->HasUserGesture());
}
void ResourceDispatcherHostImpl::DidStartRequest(ResourceLoader* loader) {
// Make sure we have the load state monitor running
if (!update_load_states_timer_->IsRunning()) {
- update_load_states_timer_->Start(FROM_HERE,
- TimeDelta::FromMilliseconds(kUpdateLoadStatesIntervalMsec),
- this, &ResourceDispatcherHostImpl::UpdateLoadStates);
+ update_load_states_timer_->Start(
+ FROM_HERE, TimeDelta::FromMilliseconds(kUpdateLoadStatesIntervalMsec),
+ this, &ResourceDispatcherHostImpl::UpdateLoadInfo);
}
}
@@ -850,7 +863,46 @@ void ResourceDispatcherHostImpl::DidFinishLoading(ResourceLoader* loader) {
"Net.ErrorCodesForMainFrame3",
-loader->request()->status().error());
- if (loader->request()->url().SchemeIsSecure()) {
+ // Record time to success and error for the most common errors, and for
+ // the aggregate remainder errors.
+ base::TimeDelta request_loading_time(
+ base::Time::Now() - loader->request()->request_time());
+ switch (loader->request()->status().error()) {
+ case net::OK:
+ UMA_HISTOGRAM_LONG_TIMES(
+ "Net.RequestTime.Success", request_loading_time);
+ break;
+ case net::ERR_ABORTED:
+ UMA_HISTOGRAM_LONG_TIMES(
+ "Net.RequestTime.ErrAborted", request_loading_time);
+ break;
+ case net::ERR_CONNECTION_RESET:
+ UMA_HISTOGRAM_LONG_TIMES(
+ "Net.RequestTime.ErrConnectionReset", request_loading_time);
+ break;
+ case net::ERR_CONNECTION_TIMED_OUT:
+ UMA_HISTOGRAM_LONG_TIMES(
+ "Net.RequestTime.ErrConnectionTimedOut", request_loading_time);
+ break;
+ case net::ERR_INTERNET_DISCONNECTED:
+ UMA_HISTOGRAM_LONG_TIMES(
+ "Net.RequestTime.ErrInternetDisconnected", request_loading_time);
+ break;
+ case net::ERR_NAME_NOT_RESOLVED:
+ UMA_HISTOGRAM_LONG_TIMES(
+ "Net.RequestTime.ErrNameNotResolved", request_loading_time);
+ break;
+ case net::ERR_TIMED_OUT:
+ UMA_HISTOGRAM_LONG_TIMES(
+ "Net.RequestTime.ErrTimedOut", request_loading_time);
+ break;
+ default:
+ UMA_HISTOGRAM_LONG_TIMES(
+ "Net.RequestTime.MiscError", request_loading_time);
+ break;
+ }
+
+ if (loader->request()->url().SchemeIsCryptographic()) {
if (loader->request()->url().host() == "www.google.com") {
UMA_HISTOGRAM_SPARSE_SLOWLY("Net.ErrorCodesForHTTPSGoogleMainFrame2",
-loader->request()->status().error());
@@ -875,7 +927,7 @@ void ResourceDispatcherHostImpl::DidFinishLoading(ResourceLoader* loader) {
-loader->request()->status().error());
}
- if (loader->request()->url().SchemeIsSecure()) {
+ if (loader->request()->url().SchemeIsCryptographic()) {
RecordCertificateHistograms(loader->request()->ssl_info(),
info->GetResourceType());
}
@@ -889,11 +941,10 @@ void ResourceDispatcherHostImpl::DidFinishLoading(ResourceLoader* loader) {
void ResourceDispatcherHostImpl::OnInit() {
scheduler_.reset(new ResourceScheduler);
- AppCacheInterceptor::EnsureRegistered();
}
void ResourceDispatcherHostImpl::OnShutdown() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
is_shutdown_ = true;
pending_loaders_.clear();
@@ -947,7 +998,7 @@ bool ResourceDispatcherHostImpl::OnMessageReceived(
GlobalRequestID id(filter_->child_id(), request_id);
DelegateMap::iterator it = delegate_map_.find(id);
if (it != delegate_map_.end()) {
- ObserverList<ResourceMessageDelegate>::Iterator del_it(*it->second);
+ ObserverList<ResourceMessageDelegate>::Iterator del_it(it->second);
ResourceMessageDelegate* delegate;
while (!handled && (delegate = del_it.GetNext()) != NULL) {
handled = delegate->OnMessageReceived(message);
@@ -967,10 +1018,16 @@ void ResourceDispatcherHostImpl::OnRequestResource(
int routing_id,
int request_id,
const ResourceHostMsg_Request& request_data) {
+ // TODO(pkasting): Remove ScopedTracker below once crbug.com/477117 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "477117 ResourceDispatcherHostImpl::OnRequestResource"));
// 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) {
+ request_data.transferred_request_request_id == -1 &&
+ !base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation)) {
BrowserThread::PostTask(
BrowserThread::UI,
FROM_HERE,
@@ -1048,7 +1105,7 @@ void ResourceDispatcherHostImpl::UpdateRequestForTransfer(
DelegateMap::iterator it = delegate_map_.find(old_request_id);
if (it != delegate_map_.end()) {
// Tell each delegate that the request ID has changed.
- ObserverList<ResourceMessageDelegate>::Iterator del_it(*it->second);
+ ObserverList<ResourceMessageDelegate>::Iterator del_it(it->second);
ResourceMessageDelegate* delegate;
while ((delegate = del_it.GetNext()) != NULL) {
delegate->set_request_id(new_request_id);
@@ -1064,6 +1121,13 @@ void ResourceDispatcherHostImpl::UpdateRequestForTransfer(
child_id,
request_data.appcache_host_id);
+ ServiceWorkerRequestHandler* handler =
+ ServiceWorkerRequestHandler::GetHandler(loader->request());
+ if (handler) {
+ handler->CompleteCrossSiteTransfer(
+ child_id, request_data.service_worker_provider_id);
+ }
+
// We should have a CrossSiteResourceHandler to finish the transfer.
DCHECK(info->cross_site_handler());
}
@@ -1092,25 +1156,23 @@ void ResourceDispatcherHostImpl::BeginRequest(
// If the request that's coming in is being transferred from another process,
// we want to reuse and resume the old loader rather than start a new one.
- {
- LoaderMap::iterator it = pending_loaders_.find(
- GlobalRequestID(request_data.transferred_request_child_id,
- request_data.transferred_request_request_id));
- if (it != pending_loaders_.end()) {
- // If the request is transferring to a new process, we can update our
- // state and let it resume with its existing ResourceHandlers.
- if (it->second->is_transferring()) {
- linked_ptr<ResourceLoader> deferred_loader = it->second;
- UpdateRequestForTransfer(child_id, route_id, request_id,
- request_data, deferred_loader);
-
- deferred_loader->CompleteTransfer();
- } else {
- RecordAction(base::UserMetricsAction("BadMessageTerminate_RDH"));
- filter_->BadMessageReceived();
- }
- return;
+ LoaderMap::iterator it = pending_loaders_.find(
+ GlobalRequestID(request_data.transferred_request_child_id,
+ request_data.transferred_request_request_id));
+ if (it != pending_loaders_.end()) {
+ // If the request is transferring to a new process, we can update our
+ // state and let it resume with its existing ResourceHandlers.
+ if (it->second->is_transferring()) {
+ linked_ptr<ResourceLoader> deferred_loader = it->second;
+ UpdateRequestForTransfer(child_id, route_id, request_id,
+ request_data, deferred_loader);
+
+ deferred_loader->CompleteTransfer();
+ } else {
+ RecordAction(base::UserMetricsAction("BadMessageTerminate_RDH"));
+ filter_->BadMessageReceived();
}
+ return;
}
ResourceContext* resource_context = NULL;
@@ -1135,26 +1197,10 @@ void ResourceDispatcherHostImpl::BeginRequest(
return;
}
- bool is_sync_load = sync_result != NULL;
- int load_flags =
- BuildLoadFlagsForRequest(request_data, child_id, is_sync_load);
-
- // Sync loads should have maximum priority and should be the only
- // requets that have the ignore limits flag set.
- if (is_sync_load) {
- DCHECK_EQ(request_data.priority, net::MAXIMUM_PRIORITY);
- DCHECK_NE(load_flags & net::LOAD_IGNORE_LIMITS, 0);
- } else {
- DCHECK_EQ(load_flags & net::LOAD_IGNORE_LIMITS, 0);
- }
-
// Construct the request.
- net::CookieStore* cookie_store =
- GetContentClient()->browser()->OverrideCookieStoreForRenderProcess(
- child_id);
scoped_ptr<net::URLRequest> new_request;
new_request = request_context->CreateRequest(
- request_data.url, request_data.priority, NULL, cookie_store);
+ request_data.url, request_data.priority, NULL);
new_request->set_method(request_data.method);
new_request->set_first_party_for_cookies(
@@ -1174,8 +1220,6 @@ void ResourceDispatcherHostImpl::BeginRequest(
headers.AddHeadersFromString(request_data.headers);
new_request->SetExtraRequestHeaders(headers);
- new_request->SetLoadFlags(load_flags);
-
storage::BlobStorageContext* blob_context =
GetBlobStorageContext(filter_->blob_storage_context());
// Resolve elements from request_body and prepare upload data.
@@ -1201,6 +1245,39 @@ void ResourceDispatcherHostImpl::BeginRequest(
bool allow_download = request_data.allow_download &&
IsResourceTypeFrame(request_data.resource_type);
+ bool do_not_prompt_for_login = request_data.do_not_prompt_for_login;
+ bool is_sync_load = sync_result != NULL;
+ int load_flags =
+ BuildLoadFlagsForRequest(request_data, child_id, is_sync_load);
+ if (request_data.resource_type == RESOURCE_TYPE_PREFETCH ||
+ request_data.resource_type == RESOURCE_TYPE_FAVICON) {
+ do_not_prompt_for_login = true;
+ }
+ if (request_data.resource_type == RESOURCE_TYPE_IMAGE &&
+ HTTP_AUTH_RELATION_BLOCKED_CROSS ==
+ HttpAuthRelationTypeOf(request_data.url,
+ request_data.first_party_for_cookies)) {
+ // Prevent third-party image content from prompting for login, as this
+ // is often a scam to extract credentials for another domain from the user.
+ // Only block image loads, as the attack applies largely to the "src"
+ // property of the <img> tag. It is common for web properties to allow
+ // untrusted values for <img src>; this is considered a fair thing for an
+ // HTML sanitizer to do. Conversely, any HTML sanitizer that didn't
+ // filter sources for <script>, <link>, <embed>, <object>, <iframe> tags
+ // would be considered vulnerable in and of itself.
+ do_not_prompt_for_login = true;
+ load_flags |= net::LOAD_DO_NOT_USE_EMBEDDED_IDENTITY;
+ }
+
+ // Sync loads should have maximum priority and should be the only
+ // requets that have the ignore limits flag set.
+ if (is_sync_load) {
+ DCHECK_EQ(request_data.priority, net::MAXIMUM_PRIORITY);
+ DCHECK_NE(load_flags & net::LOAD_IGNORE_LIMITS, 0);
+ } else {
+ DCHECK_EQ(load_flags & net::LOAD_IGNORE_LIMITS, 0);
+ }
+ new_request->SetLoadFlags(load_flags);
// Make extra info and read footer (contains request ID).
ResourceRequestInfoImpl* extra_info =
@@ -1223,6 +1300,7 @@ void ResourceDispatcherHostImpl::BeginRequest(
request_data.has_user_gesture,
request_data.enable_load_timing,
request_data.enable_upload_progress,
+ do_not_prompt_for_login,
request_data.referrer_policy,
request_data.visiblity_state,
resource_context,
@@ -1241,16 +1319,14 @@ void ResourceDispatcherHostImpl::BeginRequest(
}
// 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;
+ // ServiceWorker for synchronous loads to avoid renderer deadlocks.
ServiceWorkerRequestHandler::InitializeHandler(
new_request.get(),
filter_->service_worker_context(),
blob_context,
child_id,
request_data.service_worker_provider_id,
- request_data.skip_service_worker || is_sync_load || is_favicon_load,
+ request_data.skip_service_worker || is_sync_load,
request_data.fetch_request_mode,
request_data.fetch_credentials_mode,
request_data.resource_type,
@@ -1261,7 +1337,8 @@ void ResourceDispatcherHostImpl::BeginRequest(
// Have the appcache associate its extra info with the request.
AppCacheInterceptor::SetExtraRequestInfo(
new_request.get(), filter_->appcache_service(), child_id,
- request_data.appcache_host_id, request_data.resource_type);
+ request_data.appcache_host_id, request_data.resource_type,
+ request_data.should_reset_appcache);
scoped_ptr<ResourceHandler> handler(
CreateResourceHandler(
@@ -1281,6 +1358,10 @@ scoped_ptr<ResourceHandler> ResourceDispatcherHostImpl::CreateResourceHandler(
int process_type,
int child_id,
ResourceContext* resource_context) {
+ // TODO(pkasting): Remove ScopedTracker below once crbug.com/456331 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "456331 ResourceDispatcherHostImpl::CreateResourceHandler"));
// Construct the IPC resource handler.
scoped_ptr<ResourceHandler> handler;
if (sync_result) {
@@ -1345,9 +1426,15 @@ scoped_ptr<ResourceHandler> ResourceDispatcherHostImpl::AddStandardHandlers(
int child_id,
int route_id,
scoped_ptr<ResourceHandler> handler) {
+
+ PluginService* plugin_service = nullptr;
+#if defined(ENABLE_PLUGINS)
+ plugin_service = PluginService::GetInstance();
+#endif
// Insert a buffered event handler before the actual one.
handler.reset(
- new BufferedResourceHandler(handler.Pass(), this, request));
+ new BufferedResourceHandler(
+ handler.Pass(), this, plugin_service, request));
ScopedVector<ResourceThrottle> throttles;
if (delegate_) {
@@ -1461,9 +1548,9 @@ ResourceRequestInfoImpl* ResourceDispatcherHostImpl::CreateRequestInfo(
0,
request_id_,
MSG_ROUTING_NONE, // render_frame_id
- false, // is_main_frame
- false, // parent_is_main_frame
- -1, // parent_render_frame_id
+ false, // is_main_frame
+ false, // parent_is_main_frame
+ -1, // parent_render_frame_id
RESOURCE_TYPE_SUB_RESOURCE,
ui::PAGE_TRANSITION_LINK,
false, // should_replace_current_entry
@@ -1473,6 +1560,7 @@ ResourceRequestInfoImpl* ResourceDispatcherHostImpl::CreateRequestInfo(
false, // has_user_gesture
false, // enable_load_timing
false, // enable_upload_progress
+ false, // do_not_prompt_for_login
blink::WebReferrerPolicyDefault,
blink::WebPageVisibilityStateVisible,
context,
@@ -1516,6 +1604,10 @@ void ResourceDispatcherHostImpl::OnAudioRenderHostStreamStateChanged(
int child_id,
int route_id,
bool is_playing) {
+ // The ResourceDispatcherHost may have already been shut down.
+ // See http://crbug.com/455098
+ if (!scheduler_)
+ return;
scheduler_->OnAudibilityChanged(child_id, route_id, is_playing);
}
@@ -1548,13 +1640,8 @@ void ResourceDispatcherHostImpl::BeginSaveFile(
return;
}
- net::CookieStore* cookie_store =
- GetContentClient()->browser()->OverrideCookieStoreForRenderProcess(
- child_id);
scoped_ptr<net::URLRequest> request(
- request_context->CreateRequest(url, net::DEFAULT_PRIORITY, NULL,
- cookie_store));
-
+ request_context->CreateRequest(url, net::DEFAULT_PRIORITY, NULL));
request->set_method("GET");
SetReferrerForRequest(request.get(), referrer);
@@ -1804,10 +1891,8 @@ void ResourceDispatcherHostImpl::FinishedWithResourcesForRequest(
void ResourceDispatcherHostImpl::BeginNavigationRequest(
ResourceContext* resource_context,
- int64 frame_tree_node_id,
- const CommonNavigationParams& params,
+ int frame_tree_node_id,
const NavigationRequestInfo& info,
- scoped_refptr<ResourceRequestBody> request_body,
NavigationURLLoaderImplCore* loader) {
// PlzNavigate: BeginNavigationRequest currently should only be used for the
// browser-side navigations project.
@@ -1822,25 +1907,26 @@ void ResourceDispatcherHostImpl::BeginNavigationRequest(
// needs to be checked relative to the child that /requested/ the
// navigation. It's where file upload checks, etc., come in.
(delegate_ && !delegate_->ShouldBeginRequest(
- info.navigation_params.method,
- params.url,
+ info.begin_params.method,
+ info.common_params.url,
resource_type,
resource_context))) {
- loader->NotifyRequestFailed(net::ERR_ABORTED);
+ loader->NotifyRequestFailed(false, 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::strlcpy(
+ url_buf, info.common_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;
+ int load_flags = info.begin_params.load_flags;
load_flags |= net::LOAD_VERIFY_EV_CERT;
if (info.is_main_frame) {
load_flags |= net::LOAD_MAIN_FRAME;
@@ -1858,14 +1944,11 @@ void ResourceDispatcherHostImpl::BeginNavigationRequest(
// 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 = request_context->CreateRequest(
+ info.common_params.url, net::HIGHEST, nullptr);
- new_request->set_method(info.navigation_params.method);
+ new_request->set_method(info.begin_params.method);
new_request->set_first_party_for_cookies(
info.first_party_for_cookies);
if (info.is_main_frame) {
@@ -1873,26 +1956,26 @@ void ResourceDispatcherHostImpl::BeginNavigationRequest(
net::URLRequest::UPDATE_FIRST_PARTY_URL_ON_REDIRECT);
}
- SetReferrerForRequest(new_request.get(), params.referrer);
+ SetReferrerForRequest(new_request.get(), info.common_params.referrer);
net::HttpRequestHeaders headers;
- headers.AddHeadersFromString(info.navigation_params.headers);
+ headers.AddHeadersFromString(info.begin_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()) {
+ if (info.request_body.get()) {
storage::BlobStorageContext* blob_context = GetBlobStorageContext(
GetChromeBlobStorageContextForResourceContext(resource_context));
AttachRequestBodyBlobDataHandles(
- info.navigation_params.request_body.get(),
+ info.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(),
+ info.request_body.get(),
blob_context,
nullptr, // file_system_context
BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)
@@ -1917,17 +2000,18 @@ void ResourceDispatcherHostImpl::BeginNavigationRequest(
info.parent_is_main_frame,
-1, // request_data.parent_render_frame_id,
resource_type,
- params.transition,
+ info.common_params.transition,
// should_replace_current_entry. This was only maintained at layer for
// request transfers and isn't needed for browser-side navigations.
false,
false, // is download
false, // is stream
- params.allow_download,
- info.navigation_params.has_user_gesture,
+ info.common_params.allow_download,
+ info.begin_params.has_user_gesture,
true, // enable_load_timing
false, // enable_upload_progress
- params.referrer.policy,
+ false, // do_not_prompt_for_login
+ info.common_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.
@@ -1949,7 +2033,7 @@ void ResourceDispatcherHostImpl::BeginNavigationRequest(
}
// TODO(davidben): Attach ServiceWorkerRequestHandler.
-
+ // TODO(michaeln): Help out with this and that.
// TODO(davidben): Attach AppCacheInterceptor.
scoped_ptr<ResourceHandler> handler(new NavigationResourceHandler(
@@ -2039,6 +2123,10 @@ void ResourceDispatcherHostImpl::BeginRequestInternal(
void ResourceDispatcherHostImpl::StartLoading(
ResourceRequestInfoImpl* info,
const linked_ptr<ResourceLoader>& loader) {
+ // TODO(pkasting): Remove ScopedTracker below once crbug.com/456331 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "456331 ResourceDispatcherHostImpl::StartLoading"));
pending_loaders_[info->GetGlobalRequestID()] = loader;
loader->StartRequest();
@@ -2057,121 +2145,93 @@ net::URLRequest* ResourceDispatcherHostImpl::GetURLRequest(
return loader->request();
}
-namespace {
+// static
+bool ResourceDispatcherHostImpl::LoadInfoIsMoreInteresting(const LoadInfo& a,
+ const LoadInfo& b) {
+ // Set |*_uploading_size| to be the size of the corresponding upload body if
+ // it's currently being uploaded.
-// This function attempts to return the "more interesting" load state of |a|
-// and |b|. We don't have temporal information about these load states
-// (meaning we don't know when we transitioned into these states), so we just
-// rank them according to how "interesting" the states are.
-//
-// We take advantage of the fact that the load states are an enumeration listed
-// in the order in which they occur during the lifetime of a request, so we can
-// regard states with larger numeric values as being further along toward
-// completion. We regard those states as more interesting to report since they
-// represent progress.
-//
-// For example, by this measure "tranferring data" is a more interesting state
-// than "resolving host" because when we are transferring data we are actually
-// doing something that corresponds to changes that the user might observe,
-// whereas waiting for a host name to resolve implies being stuck.
-//
-const net::LoadStateWithParam& MoreInterestingLoadState(
- const net::LoadStateWithParam& a, const net::LoadStateWithParam& b) {
- return (a.state < b.state) ? b : a;
-}
+ uint64 a_uploading_size = 0;
+ if (a.load_state.state == net::LOAD_STATE_SENDING_REQUEST)
+ a_uploading_size = a.upload_size;
-// Carries information about a load state change.
-struct LoadInfo {
- GURL url;
- net::LoadStateWithParam load_state;
- uint64 upload_position;
- uint64 upload_size;
-};
+ uint64 b_uploading_size = 0;
+ if (b.load_state.state == net::LOAD_STATE_SENDING_REQUEST)
+ b_uploading_size = b.upload_size;
-// Map from ProcessID+RouteID pair to LoadState
-typedef std::map<GlobalRoutingID, LoadInfo> LoadInfoMap;
+ if (a_uploading_size != b_uploading_size)
+ return a_uploading_size > b_uploading_size;
-// Used to marshal calls to LoadStateChanged from the IO to UI threads. We do
-// them all as a single callback to avoid spamming the UI thread.
-void LoadInfoUpdateCallback(const LoadInfoMap& info_map) {
- LoadInfoMap::const_iterator i;
- for (i = info_map.begin(); i != info_map.end(); ++i) {
- RenderViewHostImpl* view =
- RenderViewHostImpl::FromID(i->first.child_id, i->first.route_id);
- if (view) // The view could be gone at this point.
- view->LoadStateChanged(i->second.url, i->second.load_state,
- i->second.upload_position,
- i->second.upload_size);
- }
+ return a.load_state.state > b.load_state.state;
}
-} // namespace
+// static
+void ResourceDispatcherHostImpl::UpdateLoadInfoOnUIThread(
+ scoped_ptr<LoadInfoMap> info_map) {
+ // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466285
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "466285 ResourceDispatcherHostImpl::UpdateLoadInfoOnUIThread"));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ for (const auto& load_info : *info_map) {
+ RenderViewHostImpl* view = RenderViewHostImpl::FromID(
+ load_info.first.child_id, load_info.first.route_id);
+ // The view could be gone at this point.
+ if (view) {
+ view->LoadStateChanged(load_info.second.url, load_info.second.load_state,
+ load_info.second.upload_position,
+ load_info.second.upload_size);
+ }
+ }
+}
-void ResourceDispatcherHostImpl::UpdateLoadStates() {
+scoped_ptr<ResourceDispatcherHostImpl::LoadInfoMap>
+ResourceDispatcherHostImpl::GetLoadInfoForAllRoutes() {
// Populate this map with load state changes, and then send them on to the UI
// thread where they can be passed along to the respective RVHs.
- LoadInfoMap info_map;
+ scoped_ptr<LoadInfoMap> info_map(new LoadInfoMap());
- LoaderMap::const_iterator i;
+ for (const auto& loader : pending_loaders_) {
+ // Also poll for upload progress on this timer and send upload progress ipc
+ // messages to the plugin process.
+ loader.second->ReportUploadProgress();
- // Determine the largest upload size of all requests
- // in each View (good chance it's zero).
- std::map<GlobalRoutingID, uint64> largest_upload_size;
- for (i = pending_loaders_.begin(); i != pending_loaders_.end(); ++i) {
- net::URLRequest* request = i->second->request();
- ResourceRequestInfoImpl* info = i->second->GetRequestInfo();
- uint64 upload_size = request->GetUploadProgress().size();
- if (request->GetLoadState().state != net::LOAD_STATE_SENDING_REQUEST)
- upload_size = 0;
- GlobalRoutingID id(info->GetGlobalRoutingID());
- if (upload_size && largest_upload_size[id] < upload_size)
- largest_upload_size[id] = upload_size;
- }
-
- for (i = pending_loaders_.begin(); i != pending_loaders_.end(); ++i) {
- net::URLRequest* request = i->second->request();
- ResourceRequestInfoImpl* info = i->second->GetRequestInfo();
- net::LoadStateWithParam load_state = request->GetLoadState();
- net::UploadProgress progress = request->GetUploadProgress();
+ net::URLRequest* request = loader.second->request();
+ net::UploadProgress upload_progress = request->GetUploadProgress();
- // We also poll for upload progress on this timer and send upload
- // progress ipc messages to the plugin process.
- i->second->ReportUploadProgress();
-
- GlobalRoutingID id(info->GetGlobalRoutingID());
+ LoadInfo load_info;
+ load_info.url = request->url();
+ load_info.load_state = request->GetLoadState();
+ load_info.upload_size = upload_progress.size();
+ load_info.upload_position = upload_progress.position();
- // If a request is uploading data, ignore all other requests so that the
- // upload progress takes priority for being shown in the status bar.
- if (largest_upload_size.find(id) != largest_upload_size.end() &&
- progress.size() < largest_upload_size[id])
- continue;
+ GlobalRoutingID id(loader.second->GetRequestInfo()->GetGlobalRoutingID());
+ LoadInfoMap::iterator existing = info_map->find(id);
- net::LoadStateWithParam to_insert = load_state;
- LoadInfoMap::iterator existing = info_map.find(id);
- if (existing != info_map.end()) {
- to_insert =
- MoreInterestingLoadState(existing->second.load_state, load_state);
- if (to_insert.state == existing->second.load_state.state)
- continue;
+ if (existing == info_map->end() ||
+ LoadInfoIsMoreInteresting(load_info, existing->second)) {
+ (*info_map)[id] = load_info;
}
- LoadInfo& load_info = info_map[id];
- load_info.url = request->url();
- load_info.load_state = to_insert;
- load_info.upload_size = progress.size();
- load_info.upload_position = progress.position();
}
+ return info_map.Pass();
+}
+
+void ResourceDispatcherHostImpl::UpdateLoadInfo() {
+ scoped_ptr<LoadInfoMap> info_map(GetLoadInfoForAllRoutes());
- if (info_map.empty())
+ if (info_map->empty())
return;
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
- base::Bind(&LoadInfoUpdateCallback, info_map));
+ base::Bind(&ResourceDispatcherHostImpl::UpdateLoadInfoOnUIThread,
+ base::Passed(&info_map)));
}
void ResourceDispatcherHostImpl::BlockRequestsForRoute(int child_id,
int route_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
GlobalRoutingID key(child_id, route_id);
DCHECK(blocked_loaders_map_.find(key) == blocked_loaders_map_.end()) <<
"BlockRequestsForRoute called multiple time for the same RVH";
@@ -2249,7 +2309,7 @@ bool ResourceDispatcherHostImpl::IsTransferredNavigation(
ResourceLoader* ResourceDispatcherHostImpl::GetLoader(
const GlobalRequestID& id) const {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
LoaderMap::const_iterator i = pending_loaders_.find(id);
if (i == pending_loaders_.end())
@@ -2301,24 +2361,7 @@ int ResourceDispatcherHostImpl::BuildLoadFlagsForRequest(
} else if (request_data.resource_type == RESOURCE_TYPE_SUB_FRAME) {
load_flags |= net::LOAD_SUB_FRAME;
} 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 == RESOURCE_TYPE_FAVICON) {
- load_flags |= net::LOAD_DO_NOT_PROMPT_FOR_LOGIN;
- } 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"
- // property of the <img> tag. It is common for web properties to allow
- // untrusted values for <img src>; this is considered a fair thing for an
- // HTML sanitizer to do. Conversely, any HTML sanitizer that didn't
- // filter sources for <script>, <link>, <embed>, <object>, <iframe> tags
- // would be considered vulnerable in and of itself.
- HttpAuthRelationType relation_type = HttpAuthRelationTypeOf(
- request_data.url, request_data.first_party_for_cookies);
- if (relation_type == HTTP_AUTH_RELATION_BLOCKED_CROSS) {
- load_flags |= (net::LOAD_DO_NOT_USE_EMBEDDED_IDENTITY |
- net::LOAD_DO_NOT_PROMPT_FOR_LOGIN);
- }
+ load_flags |= net::LOAD_PREFETCH;
}
if (is_sync_load)
diff --git a/chromium/content/browser/loader/resource_dispatcher_host_impl.h b/chromium/content/browser/loader/resource_dispatcher_host_impl.h
index a96af553b4a..87181a3854c 100644
--- a/chromium/content/browser/loader/resource_dispatcher_host_impl.h
+++ b/chromium/content/browser/loader/resource_dispatcher_host_impl.h
@@ -90,6 +90,7 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
int child_id,
int route_id,
bool prefer_cache,
+ bool do_not_prompt_for_login,
scoped_ptr<DownloadSaveInfo> save_info,
uint32 download_id,
const DownloadStartedCallback& started_callback) override;
@@ -226,8 +227,8 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
// Must be called after the ResourceRequestInfo has been created
// and associated with the request.
// |id| should be |content::DownloadItem::kInvalidId| to request automatic
- // assignment.
- scoped_ptr<ResourceHandler> CreateResourceHandlerForDownload(
+ // assignment. This is marked virtual so it can be overriden in testing.
+ virtual scoped_ptr<ResourceHandler> CreateResourceHandlerForDownload(
net::URLRequest* request,
bool is_content_initiated,
bool must_download,
@@ -238,8 +239,9 @@ 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 canceling
- // it, except on HTTP errors.
- scoped_ptr<ResourceHandler> MaybeInterceptAsStream(
+ // it, except on HTTP errors. This is marked virtual so it can be overriden in
+ // testing.
+ virtual scoped_ptr<ResourceHandler> MaybeInterceptAsStream(
net::URLRequest* request,
ResourceResponse* response,
std::string* payload);
@@ -260,10 +262,8 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
// 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,
+ int frame_tree_node_id,
const NavigationRequestInfo& info,
- scoped_refptr<ResourceRequestBody> request_body,
NavigationURLLoaderImplCore* loader);
private:
@@ -278,8 +278,6 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
FRIEND_TEST_ALL_PREFIXES(ResourceDispatcherHostTest,
TestProcessCancelDetachableTimesOut);
- class ShutdownTask;
-
struct OustandingRequestsStats {
int memory_cost;
int num_requests;
@@ -288,6 +286,17 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
friend class ShutdownTask;
friend class ResourceMessageDelegate;
+ // Information about status of a ResourceLoader.
+ struct LoadInfo {
+ GURL url;
+ net::LoadStateWithParam load_state;
+ uint64 upload_position;
+ uint64 upload_size;
+ };
+
+ // Map from ProcessID+RouteID pair to the "most interesting" LoadState.
+ typedef std::map<GlobalRoutingID, LoadInfo> LoadInfoMap;
+
// ResourceLoaderDelegate implementation:
ResourceDispatcherHostLoginDelegate* CreateLoginDelegate(
ResourceLoader* loader,
@@ -363,9 +372,33 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
// not rely on this iterator being valid on return.
void RemovePendingLoader(const LoaderMap::iterator& iter);
- // Checks all pending requests and updates the load states and upload
- // progress if necessary.
- void UpdateLoadStates();
+ // This function returns true if the LoadInfo of |a| is "more interesting"
+ // than the LoadInfo of |b|. The load that is currently sending the larger
+ // request body is considered more interesting. If neither request is
+ // sending a body (Neither request has a body, or any request that has a body
+ // is not currently sending the body), the request that is further along is
+ // considered more interesting.
+ //
+ // This takes advantage of the fact that the load states are an enumeration
+ // listed in the order in which they usually occur during the lifetime of a
+ // request, so states with larger numeric values are generally further along
+ // toward completion.
+ //
+ // For example, by this measure "tranferring data" is a more interesting state
+ // than "resolving host" because when transferring data something is being
+ // done that corresponds to changes that the user might observe, whereas
+ // waiting for a host name to resolve implies being stuck.
+ static bool LoadInfoIsMoreInteresting(const LoadInfo& a, const LoadInfo& b);
+
+ // Used to marshal calls to LoadStateChanged from the IO to UI threads. All
+ // are done as a single callback to avoid spamming the UI thread.
+ static void UpdateLoadInfoOnUIThread(scoped_ptr<LoadInfoMap> info_map);
+
+ // Gets the most interesting LoadInfo for each GlobalRoutingID.
+ scoped_ptr<LoadInfoMap> GetLoadInfoForAllRoutes();
+
+ // Checks all pending requests and updates the load info if necessary.
+ void UpdateLoadInfo();
// Resumes or cancels (if |cancel_requests| is true) any blocked requests.
void ProcessBlockedRequestsForRoute(int child_id,
diff --git a/chromium/content/browser/loader/resource_dispatcher_host_unittest.cc b/chromium/content/browser/loader/resource_dispatcher_host_unittest.cc
index d18facde88a..9db7d37188e 100644
--- a/chromium/content/browser/loader/resource_dispatcher_host_unittest.cc
+++ b/chromium/content/browser/loader/resource_dispatcher_host_unittest.cc
@@ -49,7 +49,7 @@
#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 "storage/browser/blob/shareable_file_reference.h"
#include "testing/gtest/include/gtest/gtest.h"
// TODO(eroman): Write unit tests for SafeBrowsing that exercise
@@ -94,7 +94,7 @@ void ReleaseHandlesInMessage(const IPC::Message& message) {
if (message.type() == ResourceMsg_SetDataBuffer::ID) {
PickleIterator iter(message);
int request_id;
- CHECK(message.ReadInt(&iter, &request_id));
+ CHECK(iter.ReadInt(&request_id));
base::SharedMemoryHandle shm_handle;
if (IPC::ParamTraits<base::SharedMemoryHandle>::Read(&message,
&iter,
@@ -139,6 +139,7 @@ static ResourceHostMsg_Request CreateResourceRequest(const char* method,
request.request_context = 0;
request.appcache_host_id = kAppCacheNoHostId;
request.download_to_file = false;
+ request.should_reset_appcache = false;
request.is_main_frame = true;
request.parent_is_main_frame = false;
request.parent_render_frame_id = -1;
@@ -210,13 +211,13 @@ class TestFilter : public ResourceMessageFilter {
explicit TestFilter(ResourceContext* resource_context)
: ResourceMessageFilter(
ChildProcessHostImpl::GenerateChildProcessUniqueId(),
- PROCESS_TYPE_RENDERER, NULL, NULL, NULL, NULL,
+ PROCESS_TYPE_RENDERER, NULL, NULL, NULL, NULL, NULL,
base::Bind(&TestFilter::GetContexts, base::Unretained(this))),
resource_context_(resource_context),
canceled_(false),
received_after_canceled_(0) {
ChildProcessSecurityPolicyImpl::GetInstance()->Add(child_id());
- set_peer_pid_for_testing(base::GetCurrentProcId());
+ set_peer_process_for_testing(base::Process::Current());
}
void set_canceled(bool canceled) { canceled_ = canceled; }
@@ -420,6 +421,7 @@ class URLRequestBigJob : public net::URLRequestSimpleJob {
: net::URLRequestSimpleJob(request, network_delegate) {
}
+ // URLRequestSimpleJob implementation:
int GetData(std::string* mime_type,
std::string* charset,
std::string* data,
@@ -439,6 +441,10 @@ class URLRequestBigJob : public net::URLRequestSimpleJob {
return net::OK;
}
+ base::TaskRunner* GetTaskRunner() const override {
+ return base::MessageLoopProxy::current().get();
+ }
+
private:
~URLRequestBigJob() override {}
@@ -455,6 +461,45 @@ class URLRequestBigJob : public net::URLRequestSimpleJob {
}
};
+// URLRequestJob used to test GetLoadInfoForAllRoutes. The LoadState and
+// UploadProgress values are set for the jobs at the time of creation, and
+// the jobs will never actually do anything.
+class URLRequestLoadInfoJob : public net::URLRequestJob {
+ public:
+ URLRequestLoadInfoJob(net::URLRequest* request,
+ net::NetworkDelegate* network_delegate,
+ const net::LoadState& load_state,
+ const net::UploadProgress& upload_progress)
+ : net::URLRequestJob(request, network_delegate),
+ load_state_(load_state),
+ upload_progress_(upload_progress) {}
+
+ // net::URLRequestJob implementation:
+ void Start() override {}
+ net::LoadState GetLoadState() const override { return load_state_; }
+ net::UploadProgress GetUploadProgress() const override {
+ return upload_progress_;
+ }
+
+ private:
+ ~URLRequestLoadInfoJob() override {}
+
+ // big-job:substring,N
+ static bool ParseURL(const GURL& url, std::string* text, int* count) {
+ std::vector<std::string> parts;
+ base::SplitString(url.path(), ',', &parts);
+
+ if (parts.size() != 2)
+ return false;
+
+ *text = parts[0];
+ return base::StringToInt(parts[1], count);
+ }
+
+ const net::LoadState load_state_;
+ const net::UploadProgress upload_progress_;
+};
+
class ResourceDispatcherHostTest;
class TestURLRequestJobFactory : public net::URLRequestJobFactory {
@@ -711,9 +756,21 @@ class ShareableFileReleaseWaiter {
DISALLOW_COPY_AND_ASSIGN(ShareableFileReleaseWaiter);
};
+// Information used to create resource requests that use URLRequestLoadInfoJobs.
+// The child_id is just that of ResourceDispatcherHostTest::filter_.
+struct LoadInfoTestRequestInfo {
+ int route_id;
+ GURL url;
+ net::LoadState load_state;
+ net::UploadProgress upload_progress;
+};
+
class ResourceDispatcherHostTest : public testing::Test,
public IPC::Sender {
public:
+ typedef ResourceDispatcherHostImpl::LoadInfo LoadInfo;
+ typedef ResourceDispatcherHostImpl::LoadInfoMap LoadInfoMap;
+
ResourceDispatcherHostTest()
: thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
old_factory_(NULL),
@@ -749,6 +806,19 @@ class ResourceDispatcherHostTest : public testing::Test,
return true;
}
+ scoped_ptr<LoadInfoMap> RunLoadInfoTest(LoadInfoTestRequestInfo* request_info,
+ size_t num_requests) {
+ for (size_t i = 0; i < num_requests; ++i) {
+ loader_test_request_info_.reset(
+ new LoadInfoTestRequestInfo(request_info[i]));
+ wait_for_request_create_loop_.reset(new base::RunLoop());
+ MakeTestRequest(request_info[i].route_id, i + 1, request_info[i].url);
+ wait_for_request_create_loop_->Run();
+ wait_for_request_create_loop_.reset();
+ }
+ return ResourceDispatcherHostImpl::Get()->GetLoadInfoForAllRoutes();
+ }
+
protected:
friend class TestURLRequestJobFactory;
@@ -872,6 +942,9 @@ class ResourceDispatcherHostTest : public testing::Test,
wait_for_request_complete_loop_.reset();
}
+ scoped_ptr<LoadInfoTestRequestInfo> loader_test_request_info_;
+ scoped_ptr<base::RunLoop> wait_for_request_create_loop_;
+
content::TestBrowserThreadBundle thread_bundle_;
scoped_ptr<TestBrowserContext> browser_context_;
scoped_ptr<TestURLRequestJobFactory> job_factory_;
@@ -1764,7 +1837,7 @@ TEST_F(ResourceDispatcherHostTest, TestBlockedRequestsDontLeak) {
TEST_F(ResourceDispatcherHostTest, CalculateApproximateMemoryCost) {
net::URLRequestContext context;
scoped_ptr<net::URLRequest> req(context.CreateRequest(
- GURL("http://www.google.com"), net::DEFAULT_PRIORITY, NULL, NULL));
+ GURL("http://www.google.com"), net::DEFAULT_PRIORITY, NULL));
EXPECT_EQ(
4427,
ResourceDispatcherHostImpl::CalculateApproximateMemoryCost(req.get()));
@@ -2651,6 +2724,8 @@ TEST_F(ResourceDispatcherHostTest, DataReceivedACKs) {
HandleScheme("big-job");
MakeTestRequest(0, 1, GURL("big-job:0123456789,1000000"));
+ base::RunLoop().RunUntilIdle();
+
// Sort all the messages we saw by request.
ResourceIPCAccumulator::ClassifiedMessages msgs;
accum_.GetClassifiedMessages(&msgs);
@@ -2728,6 +2803,8 @@ TEST_F(ResourceDispatcherHostTest, DelayedDataReceivedACKs) {
HandleScheme("big-job");
MakeTestRequest(0, 1, GURL("big-job:0123456789,1000000"));
+ base::RunLoop().RunUntilIdle();
+
// Sort all the messages we saw by request.
ResourceIPCAccumulator::ClassifiedMessages msgs;
accum_.GetClassifiedMessages(&msgs);
@@ -2775,6 +2852,8 @@ TEST_F(ResourceDispatcherHostTest, DataReceivedUnexpectedACKs) {
HandleScheme("big-job");
MakeTestRequest(0, 1, GURL("big-job:0123456789,1000000"));
+ base::RunLoop().RunUntilIdle();
+
// Sort all the messages we saw by request.
ResourceIPCAccumulator::ClassifiedMessages msgs;
accum_.GetClassifiedMessages(&msgs);
@@ -2971,11 +3050,158 @@ TEST_F(ResourceDispatcherHostTest, DownloadToFile) {
filter_->child_id(), response_head.download_file_path));
}
+// Tests GetLoadInfoForAllRoutes when there are no pending requests.
+TEST_F(ResourceDispatcherHostTest, LoadInfoNoRequests) {
+ scoped_ptr<LoadInfoMap> load_info_map = RunLoadInfoTest(nullptr, 0);
+ EXPECT_EQ(0u, load_info_map->size());
+}
+
+// Tests GetLoadInfoForAllRoutes when there are 3 requests from the same
+// RenderView. The second one is farthest along.
+TEST_F(ResourceDispatcherHostTest, LoadInfo) {
+ const GlobalRoutingID kId(filter_->child_id(), 0);
+ LoadInfoTestRequestInfo request_info[] = {
+ {kId.route_id,
+ GURL("test://1/"),
+ net::LOAD_STATE_SENDING_REQUEST,
+ net::UploadProgress(0, 0)},
+ {kId.route_id,
+ GURL("test://2/"),
+ net::LOAD_STATE_READING_RESPONSE,
+ net::UploadProgress(0, 0)},
+ {kId.route_id,
+ GURL("test://3/"),
+ net::LOAD_STATE_SENDING_REQUEST,
+ net::UploadProgress(0, 0)},
+ };
+ scoped_ptr<LoadInfoMap> load_info_map =
+ RunLoadInfoTest(request_info, arraysize(request_info));
+ ASSERT_EQ(1u, load_info_map->size());
+ ASSERT_TRUE(load_info_map->find(kId) != load_info_map->end());
+ EXPECT_EQ(GURL("test://2/"), (*load_info_map)[kId].url);
+ EXPECT_EQ(net::LOAD_STATE_READING_RESPONSE,
+ (*load_info_map)[kId].load_state.state);
+ EXPECT_EQ(0u, (*load_info_map)[kId].upload_position);
+ EXPECT_EQ(0u, (*load_info_map)[kId].upload_size);
+}
+
+// Tests GetLoadInfoForAllRoutes when there are 2 requests with the same
+// priority. The first one (Which will have the lowest ID) should be returned.
+TEST_F(ResourceDispatcherHostTest, LoadInfoSamePriority) {
+ const GlobalRoutingID kId(filter_->child_id(), 0);
+ LoadInfoTestRequestInfo request_info[] = {
+ {kId.route_id,
+ GURL("test://1/"),
+ net::LOAD_STATE_IDLE,
+ net::UploadProgress(0, 0)},
+ {kId.route_id,
+ GURL("test://2/"),
+ net::LOAD_STATE_IDLE,
+ net::UploadProgress(0, 0)},
+ };
+ scoped_ptr<LoadInfoMap> load_info_map =
+ RunLoadInfoTest(request_info, arraysize(request_info));
+ ASSERT_EQ(1u, load_info_map->size());
+ ASSERT_TRUE(load_info_map->find(kId) != load_info_map->end());
+ EXPECT_EQ(GURL("test://1/"), (*load_info_map)[kId].url);
+ EXPECT_EQ(net::LOAD_STATE_IDLE, (*load_info_map)[kId].load_state.state);
+ EXPECT_EQ(0u, (*load_info_map)[kId].upload_position);
+ EXPECT_EQ(0u, (*load_info_map)[kId].upload_size);
+}
+
+// Tests GetLoadInfoForAllRoutes when a request is uploading a body.
+TEST_F(ResourceDispatcherHostTest, LoadInfoUploadProgress) {
+ const GlobalRoutingID kId(filter_->child_id(), 0);
+ LoadInfoTestRequestInfo request_info[] = {
+ {kId.route_id,
+ GURL("test://1/"),
+ net::LOAD_STATE_READING_RESPONSE,
+ net::UploadProgress(0, 0)},
+ {kId.route_id,
+ GURL("test://1/"),
+ net::LOAD_STATE_READING_RESPONSE,
+ net::UploadProgress(1000, 1000)},
+ {kId.route_id,
+ GURL("test://2/"),
+ net::LOAD_STATE_SENDING_REQUEST,
+ net::UploadProgress(50, 100)},
+ {kId.route_id,
+ GURL("test://1/"),
+ net::LOAD_STATE_READING_RESPONSE,
+ net::UploadProgress(1000, 1000)},
+ {kId.route_id,
+ GURL("test://3/"),
+ net::LOAD_STATE_READING_RESPONSE,
+ net::UploadProgress(0, 0)},
+ };
+ scoped_ptr<LoadInfoMap> load_info_map =
+ RunLoadInfoTest(request_info, arraysize(request_info));
+ ASSERT_EQ(1u, load_info_map->size());
+ ASSERT_TRUE(load_info_map->find(kId) != load_info_map->end());
+ EXPECT_EQ(GURL("test://2/"), (*load_info_map)[kId].url);
+ EXPECT_EQ(net::LOAD_STATE_SENDING_REQUEST,
+ (*load_info_map)[kId].load_state.state);
+ EXPECT_EQ(50u, (*load_info_map)[kId].upload_position);
+ EXPECT_EQ(100u, (*load_info_map)[kId].upload_size);
+}
+
+// Tests GetLoadInfoForAllRoutes when there are 4 requests from 2 different
+// RenderViews. Also tests the case where the first / last requests are the
+// most interesting ones.
+TEST_F(ResourceDispatcherHostTest, LoadInfoTwoRenderViews) {
+ const GlobalRoutingID kId1(filter_->child_id(), 0);
+ const GlobalRoutingID kId2(filter_->child_id(), 1);
+ LoadInfoTestRequestInfo request_info[] = {
+ {kId1.route_id,
+ GURL("test://1/"),
+ net::LOAD_STATE_CONNECTING,
+ net::UploadProgress(0, 0)},
+ {kId2.route_id,
+ GURL("test://2/"),
+ net::LOAD_STATE_IDLE,
+ net::UploadProgress(0, 0)},
+ {kId1.route_id,
+ GURL("test://3/"),
+ net::LOAD_STATE_IDLE,
+ net::UploadProgress(0, 0)},
+ {kId2.route_id,
+ GURL("test://4/"),
+ net::LOAD_STATE_CONNECTING,
+ net::UploadProgress(0, 0)},
+ };
+ scoped_ptr<LoadInfoMap> load_info_map =
+ RunLoadInfoTest(request_info, arraysize(request_info));
+ ASSERT_EQ(2u, load_info_map->size());
+
+ ASSERT_TRUE(load_info_map->find(kId1) != load_info_map->end());
+ EXPECT_EQ(GURL("test://1/"), (*load_info_map)[kId1].url);
+ EXPECT_EQ(net::LOAD_STATE_CONNECTING,
+ (*load_info_map)[kId1].load_state.state);
+ EXPECT_EQ(0u, (*load_info_map)[kId1].upload_position);
+ EXPECT_EQ(0u, (*load_info_map)[kId1].upload_size);
+
+ ASSERT_TRUE(load_info_map->find(kId2) != load_info_map->end());
+ EXPECT_EQ(GURL("test://4/"), (*load_info_map)[kId2].url);
+ EXPECT_EQ(net::LOAD_STATE_CONNECTING,
+ (*load_info_map)[kId2].load_state.state);
+ EXPECT_EQ(0u, (*load_info_map)[kId2].upload_position);
+ EXPECT_EQ(0u, (*load_info_map)[kId2].upload_size);
+}
+
net::URLRequestJob* TestURLRequestJobFactory::MaybeCreateJobWithProtocolHandler(
const std::string& scheme,
net::URLRequest* request,
net::NetworkDelegate* network_delegate) const {
url_request_jobs_created_count_++;
+ if (test_fixture_->wait_for_request_create_loop_)
+ test_fixture_->wait_for_request_create_loop_->Quit();
+ if (test_fixture_->loader_test_request_info_) {
+ DCHECK_EQ(test_fixture_->loader_test_request_info_->url, request->url());
+ scoped_ptr<LoadInfoTestRequestInfo> info =
+ test_fixture_->loader_test_request_info_.Pass();
+ return new URLRequestLoadInfoJob(request, network_delegate,
+ info->load_state, info->upload_progress);
+ }
if (test_fixture_->response_headers_.empty()) {
if (delay_start_) {
return new URLRequestTestDelayedStartJob(request, network_delegate);
diff --git a/chromium/content/browser/loader/resource_loader.cc b/chromium/content/browser/loader/resource_loader.cc
index eae75eb4be5..6855cf61d20 100644
--- a/chromium/content/browser/loader/resource_loader.cc
+++ b/chromium/content/browser/loader/resource_loader.cc
@@ -7,6 +7,7 @@
#include "base/command_line.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram.h"
+#include "base/profiler/scoped_tracker.h"
#include "base/time/time.h"
#include "content/browser/appcache/appcache_interceptor.h"
#include "content/browser/child_process_security_policy_impl.h"
@@ -174,6 +175,13 @@ void ResourceLoader::MarkAsTransferring() {
CHECK(IsResourceTypeFrame(GetRequestInfo()->GetResourceType()))
<< "Can only transfer for navigations";
is_transferring_ = true;
+
+ int child_id = GetRequestInfo()->GetChildID();
+ AppCacheInterceptor::PrepareForCrossSiteTransfer(request(), child_id);
+ ServiceWorkerRequestHandler* handler =
+ ServiceWorkerRequestHandler::GetHandler(request());
+ if (handler)
+ handler->PrepareForCrossSiteTransfer(child_id);
}
void ResourceLoader::CompleteTransfer() {
@@ -183,6 +191,18 @@ void ResourceLoader::CompleteTransfer() {
// a later read stage.
DCHECK(DEFERRED_READ == deferred_stage_ ||
DEFERRED_RESPONSE_COMPLETE == deferred_stage_);
+ DCHECK(is_transferring_);
+
+ // In some cases, a process transfer doesn't really happen and the
+ // request is resumed in the original process. Real transfers to a new process
+ // are completed via ResourceDispatcherHostImpl::UpdateRequestForTransfer.
+ int child_id = GetRequestInfo()->GetChildID();
+ AppCacheInterceptor::MaybeCompleteCrossSiteTransferInOldProcess(
+ request(), child_id);
+ ServiceWorkerRequestHandler* handler =
+ ServiceWorkerRequestHandler::GetHandler(request());
+ if (handler)
+ handler->MaybeCompleteCrossSiteTransferInOldProcess(child_id);
is_transferring_ = false;
GetRequestInfo()->cross_site_handler()->ResumeResponse();
@@ -231,7 +251,6 @@ void ResourceLoader::OnReceivedRedirect(net::URLRequest* unused,
scoped_refptr<ResourceResponse> response(new ResourceResponse());
PopulateResourceResponse(info, request_.get(), response.get());
-
if (!handler_->OnRequestRedirected(redirect_info, response.get(), defer)) {
Cancel();
} else if (*defer) {
@@ -243,7 +262,8 @@ void ResourceLoader::OnAuthRequired(net::URLRequest* unused,
net::AuthChallengeInfo* auth_info) {
DCHECK_EQ(request_.get(), unused);
- if (request_->load_flags() & net::LOAD_DO_NOT_PROMPT_FOR_LOGIN) {
+ ResourceRequestInfoImpl* info = GetRequestInfo();
+ if (info->do_not_prompt_for_login()) {
request_->CancelAuth();
return;
}
@@ -271,11 +291,8 @@ void ResourceLoader::OnCertificateRequested(
DCHECK(!ssl_client_auth_handler_)
<< "OnCertificateRequested called with ssl_client_auth_handler pending";
ssl_client_auth_handler_.reset(new SSLClientAuthHandler(
- GetRequestInfo()->GetContext()->CreateClientCertStore(),
- request_.get(),
- cert_info,
- base::Bind(&ResourceLoader::ContinueWithCertificate,
- weak_ptr_factory_.GetWeakPtr())));
+ GetRequestInfo()->GetContext()->CreateClientCertStore(), request_.get(),
+ cert_info, this));
ssl_client_auth_handler_->SelectCertificate();
}
@@ -346,11 +363,10 @@ void ResourceLoader::OnResponseStarted(net::URLRequest* unused) {
if (is_deferred())
return;
- if (request_->status().is_success()) {
+ if (request_->status().is_success())
StartReading(false); // Read the first chunk.
- } else {
+ else
ResponseCompleted();
- }
}
void ResourceLoader::OnReadCompleted(net::URLRequest* unused, int bytes_read) {
@@ -379,6 +395,10 @@ void ResourceLoader::OnReadCompleted(net::URLRequest* unused, int bytes_read) {
if (bytes_read > 0) {
StartReading(true); // Read the next chunk.
} else {
+ // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 ResponseCompleted()"));
+
// URLRequest reported an EOF. Call ResponseCompleted.
DCHECK_EQ(0, bytes_read);
ResponseCompleted();
@@ -387,7 +407,7 @@ void ResourceLoader::OnReadCompleted(net::URLRequest* unused, int bytes_read) {
void ResourceLoader::CancelSSLRequest(int error,
const net::SSLInfo* ssl_info) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
// The request can be NULL if it was cancelled by the renderer (as the
// request of the user navigating to a new page from the location bar).
@@ -403,13 +423,25 @@ void ResourceLoader::CancelSSLRequest(int error,
}
void ResourceLoader::ContinueSSLRequest() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
DVLOG(1) << "ContinueSSLRequest() url: " << request_->url().spec();
request_->ContinueDespiteLastError();
}
+void ResourceLoader::ContinueWithCertificate(net::X509Certificate* cert) {
+ DCHECK(ssl_client_auth_handler_);
+ ssl_client_auth_handler_.reset();
+ request_->ContinueWithCertificate(cert);
+}
+
+void ResourceLoader::CancelCertificateSelection() {
+ DCHECK(ssl_client_auth_handler_);
+ ssl_client_auth_handler_.reset();
+ request_->CancelWithError(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
+}
+
void ResourceLoader::Resume() {
DCHECK(!is_transferring_);
@@ -524,7 +556,6 @@ void ResourceLoader::StoreSignedCertificateTimestamps(
void ResourceLoader::CompleteResponseStarted() {
ResourceRequestInfoImpl* info = GetRequestInfo();
-
scoped_refptr<ResourceResponse> response(new ResourceResponse());
PopulateResourceResponse(info, request_.get(), response.get());
@@ -553,6 +584,10 @@ void ResourceLoader::CompleteResponseStarted() {
delegate_->DidReceiveResponse(this);
+ // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnResponseStarted()"));
+
bool defer = false;
if (!handler_->OnResponseStarted(response.get(), &defer)) {
Cancel();
@@ -607,9 +642,15 @@ void ResourceLoader::ReadMore(int* bytes_read) {
// doesn't use the buffer.
scoped_refptr<net::IOBuffer> buf;
int buf_size;
- if (!handler_->OnWillRead(&buf, &buf_size, -1)) {
- Cancel();
- return;
+ {
+ // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
+ tracked_objects::ScopedTracker tracking_profile2(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnWillRead()"));
+
+ if (!handler_->OnWillRead(&buf, &buf_size, -1)) {
+ Cancel();
+ return;
+ }
}
DCHECK(buf.get());
@@ -625,6 +666,10 @@ void ResourceLoader::CompleteRead(int bytes_read) {
DCHECK(bytes_read >= 0);
DCHECK(request_->status().is_success());
+ // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnReadCompleted()"));
+
bool defer = false;
if (!handler_->OnReadCompleted(bytes_read, &defer)) {
Cancel();
@@ -660,7 +705,13 @@ void ResourceLoader::ResponseCompleted() {
}
bool defer = false;
- handler_->OnResponseCompleted(request_->status(), security_info, &defer);
+ {
+ // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnResponseCompleted()"));
+
+ handler_->OnResponseCompleted(request_->status(), security_info, &defer);
+ }
if (defer) {
// The handler is not ready to die yet. We will call DidFinishLoading when
// we resume.
@@ -708,9 +759,4 @@ 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 d740ec03b06..bb21509e363 100644
--- a/chromium/content/browser/loader/resource_loader.h
+++ b/chromium/content/browser/loader/resource_loader.h
@@ -5,10 +5,10 @@
#ifndef CONTENT_BROWSER_LOADER_RESOURCE_LOADER_H_
#define CONTENT_BROWSER_LOADER_RESOURCE_LOADER_H_
-#include "base/gtest_prod_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "content/browser/loader/resource_handler.h"
+#include "content/browser/ssl/ssl_client_auth_handler.h"
#include "content/browser/ssl/ssl_error_handler.h"
#include "content/common/content_export.h"
#include "content/public/browser/resource_controller.h"
@@ -23,13 +23,13 @@ namespace content {
class ResourceDispatcherHostLoginDelegate;
class ResourceLoaderDelegate;
class ResourceRequestInfoImpl;
-class SSLClientAuthHandler;
// This class is responsible for driving the URLRequest (i.e., calling Start,
// Read, and servicing events). It has a ResourceHandler, which is typically a
// chain of ResourceHandlers, and is the ResourceController for its handler.
class CONTENT_EXPORT ResourceLoader : public net::URLRequest::Delegate,
public SSLErrorHandler::Delegate,
+ public SSLClientAuthHandler::Delegate,
public ResourceController {
public:
ResourceLoader(scoped_ptr<net::URLRequest> request,
@@ -55,9 +55,6 @@ class CONTENT_EXPORT ResourceLoader : public net::URLRequest::Delegate,
void OnUploadProgressACK();
private:
- FRIEND_TEST_ALL_PREFIXES(ResourceLoaderTest, ClientCertStoreLookup);
- FRIEND_TEST_ALL_PREFIXES(ResourceLoaderTest, ClientCertStoreNull);
-
// net::URLRequest::Delegate implementation:
void OnReceivedRedirect(net::URLRequest* request,
const net::RedirectInfo& redirect_info,
@@ -77,6 +74,10 @@ class CONTENT_EXPORT ResourceLoader : public net::URLRequest::Delegate,
void CancelSSLRequest(int error, const net::SSLInfo* ssl_info) override;
void ContinueSSLRequest() override;
+ // SSLClientAuthHandler::Delegate implementation.
+ void ContinueWithCertificate(net::X509Certificate* cert) override;
+ void CancelCertificateSelection() override;
+
// ResourceController implementation:
void Resume() override;
void Cancel() override;
@@ -102,7 +103,6 @@ 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; }
diff --git a/chromium/content/browser/loader/resource_loader_unittest.cc b/chromium/content/browser/loader/resource_loader_unittest.cc
index 635f566f7dd..8be5ec1d0eb 100644
--- a/chromium/content/browser/loader/resource_loader_unittest.cc
+++ b/chromium/content/browser/loader/resource_loader_unittest.cc
@@ -6,28 +6,35 @@
#include "base/files/file.h"
#include "base/files/file_util.h"
+#include "base/macros.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/run_loop.h"
#include "content/browser/browser_thread_impl.h"
#include "content/browser/loader/redirect_to_file_resource_handler.h"
#include "content/browser/loader/resource_loader_delegate.h"
+#include "content/public/browser/client_certificate_delegate.h"
#include "content/public/browser/resource_request_info.h"
#include "content/public/common/resource_response.h"
#include "content/public/test/mock_resource_context.h"
+#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_browser_thread_bundle.h"
+#include "content/public/test/test_renderer_host.h"
#include "content/test/test_content_browser_client.h"
+#include "content/test/test_web_contents.h"
#include "ipc/ipc_message.h"
#include "net/base/io_buffer.h"
#include "net/base/mock_file_stream.h"
+#include "net/base/net_errors.h"
#include "net/base/request_priority.h"
#include "net/cert/x509_certificate.h"
#include "net/ssl/client_cert_store.h"
#include "net/ssl/ssl_cert_request_info.h"
#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_job_factory.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/common/blob/shareable_file_reference.h"
+#include "storage/browser/blob/shareable_file_reference.h"
#include "testing/gtest/include/gtest/gtest.h"
using storage::ShareableFileReference;
@@ -40,41 +47,115 @@ namespace {
// inspection.
class ClientCertStoreStub : public net::ClientCertStore {
public:
- ClientCertStoreStub(const net::CertificateList& certs)
- : response_(certs),
- request_count_(0) {}
-
- ~ClientCertStoreStub() override {}
-
- // Returns |cert_authorities| field of the certificate request passed in the
- // most recent call to GetClientCerts().
+ // Creates a new ClientCertStoreStub that returns |response| on query. It
+ // saves the number of requests and most recently certificate authorities list
+ // in |requested_authorities| and |request_count|, respectively. The caller is
+ // responsible for ensuring those pointers outlive the ClientCertStoreStub.
+ //
// TODO(ppi): Make the stub independent from the internal representation of
- // SSLCertRequestInfo. For now it seems that we cannot neither save the
+ // SSLCertRequestInfo. For now it seems that we can neither save the
// scoped_refptr<> (since it is never passed to us) nor copy the entire
// CertificateRequestInfo (since there is no copy constructor).
- std::vector<std::string> requested_authorities() {
- return requested_authorities_;
+ ClientCertStoreStub(const net::CertificateList& response,
+ int* request_count,
+ std::vector<std::string>* requested_authorities)
+ : response_(response),
+ requested_authorities_(requested_authorities),
+ request_count_(request_count) {
+ requested_authorities_->clear();
+ *request_count_ = 0;
}
- // Returns the number of calls to GetClientCerts().
- int request_count() {
- return request_count_;
- }
+ ~ClientCertStoreStub() override {}
// net::ClientCertStore:
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;
+ *requested_authorities_ = cert_request_info.cert_authorities;
+ ++(*request_count_);
+
*selected_certs = response_;
callback.Run();
}
private:
const net::CertificateList response_;
- int request_count_;
- std::vector<std::string> requested_authorities_;
+ std::vector<std::string>* requested_authorities_;
+ int* request_count_;
+};
+
+// Client certificate store which destroys its resource loader before the
+// asynchronous GetClientCerts callback is called.
+class LoaderDestroyingCertStore : public net::ClientCertStore {
+ public:
+ // Creates a client certificate store which, when looked up, posts a task to
+ // reset |loader| and then call the callback. The caller is responsible for
+ // ensuring the pointers remain valid until the process is complete.
+ explicit LoaderDestroyingCertStore(scoped_ptr<ResourceLoader>* loader)
+ : loader_(loader) {}
+
+ // net::ClientCertStore:
+ void GetClientCerts(const net::SSLCertRequestInfo& cert_request_info,
+ net::CertificateList* selected_certs,
+ const base::Closure& callback) override {
+ // Don't destroy |loader_| while it's on the stack.
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(&LoaderDestroyingCertStore::DoCallback,
+ base::Unretained(loader_), callback));
+ }
+
+ private:
+ static void DoCallback(scoped_ptr<ResourceLoader>* loader,
+ const base::Closure& callback) {
+ loader->reset();
+ callback.Run();
+ }
+
+ scoped_ptr<ResourceLoader>* loader_;
+};
+
+// A mock URLRequestJob which simulates an SSL client auth request.
+class MockClientCertURLRequestJob : public net::URLRequestTestJob {
+ public:
+ MockClientCertURLRequestJob(net::URLRequest* request,
+ net::NetworkDelegate* network_delegate)
+ : net::URLRequestTestJob(request, network_delegate) {}
+
+ static std::vector<std::string> test_authorities() {
+ return std::vector<std::string>(1, "dummy");
+ }
+
+ // net::URLRequestTestJob:
+ void Start() override {
+ scoped_refptr<net::SSLCertRequestInfo> cert_request_info(
+ new net::SSLCertRequestInfo);
+ cert_request_info->cert_authorities = test_authorities();
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&MockClientCertURLRequestJob::NotifyCertificateRequested,
+ this, cert_request_info));
+ }
+
+ void ContinueWithCertificate(net::X509Certificate* cert) override {
+ net::URLRequestTestJob::Start();
+ }
+
+ private:
+ ~MockClientCertURLRequestJob() override {}
+
+ DISALLOW_COPY_AND_ASSIGN(MockClientCertURLRequestJob);
+};
+
+class MockClientCertJobProtocolHandler
+ : public net::URLRequestJobFactory::ProtocolHandler {
+ public:
+ // URLRequestJobFactory::ProtocolHandler implementation:
+ net::URLRequestJob* MaybeCreateJob(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) const override {
+ return new MockClientCertURLRequestJob(request, network_delegate);
+ }
};
// Arbitrary read buffer size.
@@ -229,25 +310,28 @@ class SelectCertificateBrowserClient : public TestContentBrowserClient {
SelectCertificateBrowserClient() : call_count_(0) {}
void SelectClientCertificate(
- int render_process_id,
- int render_view_id,
+ WebContents* web_contents,
net::SSLCertRequestInfo* cert_request_info,
- const base::Callback<void(net::X509Certificate*)>& callback) override {
+ scoped_ptr<ClientCertificateDelegate> delegate) override {
++call_count_;
passed_certs_ = cert_request_info->client_certs;
+ delegate_ = delegate.Pass();
}
- int call_count() {
- return call_count_;
- }
+ int call_count() { return call_count_; }
+ net::CertificateList passed_certs() { return passed_certs_; }
- net::CertificateList passed_certs() {
- return passed_certs_;
+ void ContinueWithCertificate(net::X509Certificate* cert) {
+ delegate_->ContinueWithCertificate(cert);
+ delegate_.reset();
}
+ void CancelCertificateSelection() { delegate_.reset(); }
+
private:
net::CertificateList passed_certs_;
int call_count_;
+ scoped_ptr<ClientCertificateDelegate> delegate_;
};
class ResourceContextStub : public MockResourceContext {
@@ -287,19 +371,19 @@ class ResourceLoaderTest : public testing::Test,
resource_context_(&test_url_request_context_),
raw_ptr_resource_handler_(NULL),
raw_ptr_to_request_(NULL) {
- job_factory_.SetProtocolHandler(
- "test", net::URLRequestTestJob::CreateProtocolHandler());
test_url_request_context_.set_job_factory(&job_factory_);
}
- GURL test_url() const {
- return net::URLRequestTestJob::test_url_1();
- }
+ GURL test_url() const { return net::URLRequestTestJob::test_url_1(); }
std::string test_data() const {
return net::URLRequestTestJob::test_data_1();
}
+ virtual net::URLRequestJobFactory::ProtocolHandler* CreateProtocolHandler() {
+ return net::URLRequestTestJob::CreateProtocolHandler();
+ }
+
virtual scoped_ptr<ResourceHandler> WrapResourceHandler(
scoped_ptr<ResourceHandlerStub> leaf_handler,
net::URLRequest* request) {
@@ -307,23 +391,27 @@ class ResourceLoaderTest : public testing::Test,
}
void SetUp() override {
- const int kRenderProcessId = 1;
- const int kRenderViewId = 2;
+ job_factory_.SetProtocolHandler("test", CreateProtocolHandler());
+
+ browser_context_.reset(new TestBrowserContext());
+ scoped_refptr<SiteInstance> site_instance =
+ SiteInstance::Create(browser_context_.get());
+ web_contents_.reset(
+ TestWebContents::Create(browser_context_.get(), site_instance.get()));
+ RenderFrameHost* rfh = web_contents_->GetMainFrame();
scoped_ptr<net::URLRequest> request(
resource_context_.GetRequestContext()->CreateRequest(
test_url(),
net::DEFAULT_PRIORITY,
- NULL /* delegate */,
- NULL /* cookie_store */));
+ NULL /* delegate */));
raw_ptr_to_request_ = request.get();
- ResourceRequestInfo::AllocateForTesting(request.get(),
- RESOURCE_TYPE_MAIN_FRAME,
- &resource_context_,
- kRenderProcessId,
- kRenderViewId,
- MSG_ROUTING_NONE,
- false);
+ ResourceRequestInfo::AllocateForTesting(
+ request.get(), RESOURCE_TYPE_MAIN_FRAME, &resource_context_,
+ rfh->GetProcess()->GetID(), rfh->GetRenderViewHost()->GetRoutingID(),
+ rfh->GetRoutingID(), true /* is_main_frame */,
+ false /* parent_is_main_frame */, true /* allow_download */,
+ false /* is_async */);
scoped_ptr<ResourceHandlerStub> resource_handler(
new ResourceHandlerStub(request.get()));
raw_ptr_resource_handler_ = resource_handler.get();
@@ -333,6 +421,14 @@ class ResourceLoaderTest : public testing::Test,
this));
}
+ void TearDown() override {
+ // Destroy the WebContents and pump the event loop before destroying
+ // |rvh_test_enabler_| and |thread_bundle_|. This lets asynchronous cleanup
+ // tasks complete.
+ web_contents_.reset();
+ base::RunLoop().RunUntilIdle();
+ }
+
// ResourceLoaderDelegate:
ResourceDispatcherHostLoginDelegate* CreateLoginDelegate(
ResourceLoader* loader,
@@ -349,11 +445,14 @@ class ResourceLoaderTest : public testing::Test,
void DidReceiveResponse(ResourceLoader* loader) override {}
void DidFinishLoading(ResourceLoader* loader) override {}
- content::TestBrowserThreadBundle thread_bundle_;
+ TestBrowserThreadBundle thread_bundle_;
+ RenderViewHostTestEnabler rvh_test_enabler_;
net::URLRequestJobFactoryImpl job_factory_;
net::TestURLRequestContext test_url_request_context_;
ResourceContextStub resource_context_;
+ scoped_ptr<TestBrowserContext> browser_context_;
+ scoped_ptr<TestWebContents> web_contents_;
// The ResourceLoader owns the URLRequest and the ResourceHandler.
ResourceHandlerStub* raw_ptr_resource_handler_;
@@ -361,77 +460,144 @@ class ResourceLoaderTest : public testing::Test,
scoped_ptr<ResourceLoader> loader_;
};
-// Verifies if a call to net::UrlRequest::Delegate::OnCertificateRequested()
-// causes client cert store to be queried for certificates and if the returned
-// certificates are correctly passed to the content browser client for
-// selection.
-TEST_F(ResourceLoaderTest, ClientCertStoreLookup) {
+class ClientCertResourceLoaderTest : public ResourceLoaderTest {
+ protected:
+ net::URLRequestJobFactory::ProtocolHandler* CreateProtocolHandler() override {
+ return new MockClientCertJobProtocolHandler;
+ }
+};
+
+// Tests that client certificates are requested with ClientCertStore lookup.
+TEST_F(ClientCertResourceLoaderTest, WithStoreLookup) {
// Set up the test client cert store.
+ int store_request_count;
+ std::vector<std::string> store_requested_authorities;
net::CertificateList dummy_certs(1, scoped_refptr<net::X509Certificate>(
new net::X509Certificate("test", "test", base::Time(), base::Time())));
- scoped_ptr<ClientCertStoreStub> test_store(
- new ClientCertStoreStub(dummy_certs));
- EXPECT_EQ(0, test_store->request_count());
-
- // 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();
+ scoped_ptr<ClientCertStoreStub> test_store(new ClientCertStoreStub(
+ dummy_certs, &store_request_count, &store_requested_authorities));
resource_context_.SetClientCertStore(test_store.Pass());
- // Prepare a dummy certificate request.
- scoped_refptr<net::SSLCertRequestInfo> cert_request_info(
- new net::SSLCertRequestInfo());
- std::vector<std::string> dummy_authority(1, "dummy");
- cert_request_info->cert_authorities = dummy_authority;
-
// Plug in test content browser client.
SelectCertificateBrowserClient test_client;
ContentBrowserClient* old_client = SetBrowserClientForTesting(&test_client);
- // Everything is set up. Trigger the resource loader certificate request event
- // and run the message loop.
- loader_->OnCertificateRequested(raw_ptr_to_request_, cert_request_info.get());
+ // Start the request and wait for it to pause.
+ loader_->StartRequest();
base::RunLoop().RunUntilIdle();
- // Restore the original content browser client.
- SetBrowserClientForTesting(old_client);
+ EXPECT_FALSE(raw_ptr_resource_handler_->received_response_completed());
// Check if the test store was queried against correct |cert_authorities|.
- EXPECT_EQ(1, raw_ptr_to_store->request_count());
- EXPECT_EQ(dummy_authority, raw_ptr_to_store->requested_authorities());
+ EXPECT_EQ(1, store_request_count);
+ EXPECT_EQ(MockClientCertURLRequestJob::test_authorities(),
+ store_requested_authorities);
// Check if the retrieved certificates were passed to the content browser
// client.
EXPECT_EQ(1, test_client.call_count());
EXPECT_EQ(dummy_certs, test_client.passed_certs());
-}
-// Verifies if a call to net::URLRequest::Delegate::OnCertificateRequested()
-// on a platform with a NULL client cert store still calls the content browser
-// client for selection.
-TEST_F(ResourceLoaderTest, ClientCertStoreNull) {
- // Prepare a dummy certificate request.
- scoped_refptr<net::SSLCertRequestInfo> cert_request_info(
- new net::SSLCertRequestInfo());
- std::vector<std::string> dummy_authority(1, "dummy");
- cert_request_info->cert_authorities = dummy_authority;
+ // Continue the request.
+ test_client.ContinueWithCertificate(dummy_certs[0].get());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(raw_ptr_resource_handler_->received_response_completed());
+ EXPECT_EQ(net::OK, raw_ptr_resource_handler_->status().error());
+
+ // Restore the original content browser client.
+ SetBrowserClientForTesting(old_client);
+}
+// Tests that client certificates are requested on a platform with NULL
+// ClientCertStore.
+TEST_F(ClientCertResourceLoaderTest, WithNullStore) {
// Plug in test content browser client.
SelectCertificateBrowserClient test_client;
ContentBrowserClient* old_client = SetBrowserClientForTesting(&test_client);
- // Everything is set up. Trigger the resource loader certificate request event
- // and run the message loop.
- loader_->OnCertificateRequested(raw_ptr_to_request_, cert_request_info.get());
+ // Start the request and wait for it to pause.
+ loader_->StartRequest();
base::RunLoop().RunUntilIdle();
+ // Check if the SelectClientCertificate was called on the content browser
+ // client.
+ EXPECT_EQ(1, test_client.call_count());
+ EXPECT_EQ(net::CertificateList(), test_client.passed_certs());
+
+ // Continue the request.
+ scoped_refptr<net::X509Certificate> cert(
+ new net::X509Certificate("test", "test", base::Time(), base::Time()));
+ test_client.ContinueWithCertificate(cert.get());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(raw_ptr_resource_handler_->received_response_completed());
+ EXPECT_EQ(net::OK, raw_ptr_resource_handler_->status().error());
+
// Restore the original content browser client.
SetBrowserClientForTesting(old_client);
+}
+
+// Tests that the ContentBrowserClient may cancel a certificate request.
+TEST_F(ClientCertResourceLoaderTest, CancelSelection) {
+ // Plug in test content browser client.
+ SelectCertificateBrowserClient test_client;
+ ContentBrowserClient* old_client = SetBrowserClientForTesting(&test_client);
+
+ // Start the request and wait for it to pause.
+ loader_->StartRequest();
+ base::RunLoop().RunUntilIdle();
// Check if the SelectClientCertificate was called on the content browser
// client.
EXPECT_EQ(1, test_client.call_count());
EXPECT_EQ(net::CertificateList(), test_client.passed_certs());
+
+ // Cancel the request.
+ test_client.CancelCertificateSelection();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(raw_ptr_resource_handler_->received_response_completed());
+ EXPECT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED,
+ raw_ptr_resource_handler_->status().error());
+
+ // Restore the original content browser client.
+ SetBrowserClientForTesting(old_client);
+}
+
+// Verifies that requests without WebContents attached abort.
+TEST_F(ClientCertResourceLoaderTest, NoWebContents) {
+ // Destroy the WebContents before starting the request.
+ web_contents_.reset();
+
+ // Plug in test content browser client.
+ SelectCertificateBrowserClient test_client;
+ ContentBrowserClient* old_client = SetBrowserClientForTesting(&test_client);
+
+ // Start the request and wait for it to pause.
+ loader_->StartRequest();
+ base::RunLoop().RunUntilIdle();
+
+ // Check that SelectClientCertificate wasn't called and the request aborted.
+ EXPECT_EQ(0, test_client.call_count());
+ EXPECT_TRUE(raw_ptr_resource_handler_->received_response_completed());
+ EXPECT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED,
+ raw_ptr_resource_handler_->status().error());
+
+ // Restore the original content browser client.
+ SetBrowserClientForTesting(old_client);
+}
+
+// Verifies that ClientCertStore's callback doesn't crash if called after the
+// loader is destroyed.
+TEST_F(ClientCertResourceLoaderTest, StoreAsyncCancel) {
+ scoped_ptr<LoaderDestroyingCertStore> test_store(
+ new LoaderDestroyingCertStore(&loader_));
+ resource_context_.SetClientCertStore(test_store.Pass());
+
+ loader_->StartRequest();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(loader_);
+
+ // Pump the event loop to ensure nothing asynchronous crashes either.
+ base::RunLoop().RunUntilIdle();
}
TEST_F(ResourceLoaderTest, ResumeCancelledRequest) {
diff --git a/chromium/content/browser/loader/resource_message_delegate.h b/chromium/content/browser/loader/resource_message_delegate.h
index 934d60c0231..2a5dc45ebc4 100644
--- a/chromium/content/browser/loader/resource_message_delegate.h
+++ b/chromium/content/browser/loader/resource_message_delegate.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_LOADER_RESOURCE_MESSAGE_DELEGATE_
-#define CONTENT_BROWSER_LOADER_RESOURCE_MESSAGE_DELEGATE_
+#ifndef CONTENT_BROWSER_LOADER_RESOURCE_MESSAGE_DELEGATE_H_
+#define CONTENT_BROWSER_LOADER_RESOURCE_MESSAGE_DELEGATE_H_
#include "base/basictypes.h"
#include "content/common/content_export.h"
@@ -42,4 +42,4 @@ class CONTENT_EXPORT ResourceMessageDelegate {
} // namespace content
-#endif // CONTENT_BROWSER_LOADER_RESOURCE_MESSAGE_DELEGATE_
+#endif // CONTENT_BROWSER_LOADER_RESOURCE_MESSAGE_DELEGATE_H_
diff --git a/chromium/content/browser/loader/resource_message_filter.cc b/chromium/content/browser/loader/resource_message_filter.cc
index 9ffa29f5716..4a20d9ac1df 100644
--- a/chromium/content/browser/loader/resource_message_filter.cc
+++ b/chromium/content/browser/loader/resource_message_filter.cc
@@ -6,6 +6,7 @@
#include "content/browser/appcache/chrome_appcache_service.h"
#include "content/browser/fileapi/chrome_blob_storage_context.h"
+#include "content/browser/host_zoom_level_context.h"
#include "content/browser/loader/resource_dispatcher_host_impl.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/common/resource_messages.h"
@@ -21,6 +22,7 @@ ResourceMessageFilter::ResourceMessageFilter(
ChromeBlobStorageContext* blob_storage_context,
storage::FileSystemContext* file_system_context,
ServiceWorkerContextWrapper* service_worker_context,
+ HostZoomLevelContext* host_zoom_level_context,
const GetContextsCallback& get_contexts_callback)
: BrowserMessageFilter(ResourceMsgStart),
child_id_(child_id),
@@ -29,6 +31,7 @@ ResourceMessageFilter::ResourceMessageFilter(
blob_storage_context_(blob_storage_context),
file_system_context_(file_system_context),
service_worker_context_(service_worker_context),
+ host_zoom_level_context_(host_zoom_level_context),
get_contexts_callback_(get_contexts_callback),
weak_ptr_factory_(this) {
}
@@ -53,6 +56,12 @@ void ResourceMessageFilter::GetContexts(
return get_contexts_callback_.Run(request, resource_context, request_context);
}
+const HostZoomMap* ResourceMessageFilter::GetHostZoomMap() const {
+ if (host_zoom_level_context_.get())
+ return host_zoom_level_context_->GetHostZoomMap();
+ return NULL;
+}
+
base::WeakPtr<ResourceMessageFilter> ResourceMessageFilter::GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
diff --git a/chromium/content/browser/loader/resource_message_filter.h b/chromium/content/browser/loader/resource_message_filter.h
index 3b52a7773c0..1240cb4f5b3 100644
--- a/chromium/content/browser/loader/resource_message_filter.h
+++ b/chromium/content/browser/loader/resource_message_filter.h
@@ -26,6 +26,8 @@ class URLRequestContext;
namespace content {
class ChromeAppCacheService;
class ChromeBlobStorageContext;
+class HostZoomLevelContext;
+class HostZoomMap;
class ResourceContext;
class ServiceWorkerContextWrapper;
@@ -48,6 +50,7 @@ class CONTENT_EXPORT ResourceMessageFilter : public BrowserMessageFilter {
ChromeBlobStorageContext* blob_storage_context,
storage::FileSystemContext* file_system_context,
ServiceWorkerContextWrapper* service_worker_context,
+ HostZoomLevelContext* host_zoom_level_context,
const GetContextsCallback& get_contexts_callback);
// BrowserMessageFilter implementation.
@@ -77,6 +80,10 @@ class CONTENT_EXPORT ResourceMessageFilter : public BrowserMessageFilter {
return service_worker_context_.get();
}
+ // Returns a raw pointer to the HostZoomLevelContext's associated HostZoomMap,
+ // or NULL if no context is present.
+ const HostZoomMap* GetHostZoomMap() const;
+
int child_id() const { return child_id_; }
int process_type() const { return process_type_; }
@@ -96,6 +103,7 @@ class CONTENT_EXPORT ResourceMessageFilter : public BrowserMessageFilter {
scoped_refptr<ChromeBlobStorageContext> blob_storage_context_;
scoped_refptr<storage::FileSystemContext> file_system_context_;
scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_;
+ scoped_refptr<HostZoomLevelContext> host_zoom_level_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 8cae9a5c93b..be8ffa0ead4 100644
--- a/chromium/content/browser/loader/resource_request_info_impl.cc
+++ b/chromium/content/browser/loader/resource_request_info_impl.cc
@@ -29,7 +29,18 @@ void ResourceRequestInfo::AllocateForTesting(net::URLRequest* request,
int render_process_id,
int render_view_id,
int render_frame_id,
+ bool is_main_frame,
+ bool parent_is_main_frame,
+ bool allow_download,
bool is_async) {
+ // Make sure both |is_main_frame| and |parent_is_main_frame| aren't set at the
+ // same time.
+ DCHECK(!(is_main_frame && parent_is_main_frame));
+
+ // Make sure RESOURCE_TYPE_MAIN_FRAME is declared as being fetched as part of
+ // the main frame.
+ DCHECK(resource_type != RESOURCE_TYPE_MAIN_FRAME || is_main_frame);
+
ResourceRequestInfoImpl* info =
new ResourceRequestInfoImpl(
PROCESS_TYPE_RENDERER, // process_type
@@ -38,18 +49,19 @@ void ResourceRequestInfo::AllocateForTesting(net::URLRequest* request,
0, // origin_pid
0, // request_id
render_frame_id, // render_frame_id
- resource_type == RESOURCE_TYPE_MAIN_FRAME, // is_main_frame
- false, // parent_is_main_frame
+ is_main_frame, // is_main_frame
+ parent_is_main_frame, // parent_is_main_frame
0, // parent_render_frame_id
resource_type, // resource_type
ui::PAGE_TRANSITION_LINK, // transition_type
false, // should_replace_current_entry
false, // is_download
false, // is_stream
- true, // allow_download
+ allow_download, // allow_download
false, // has_user_gesture
false, // enable load timing
false, // enable upload progress
+ false, // do_not_prompt_for_login
blink::WebReferrerPolicyDefault, // referrer_policy
blink::WebPageVisibilityStateVisible, // visibility_state
context, // context
@@ -106,6 +118,7 @@ ResourceRequestInfoImpl::ResourceRequestInfoImpl(
bool has_user_gesture,
bool enable_load_timing,
bool enable_upload_progress,
+ bool do_not_prompt_for_login,
blink::WebReferrerPolicy referrer_policy,
blink::WebPageVisibilityState visibility_state,
ResourceContext* context,
@@ -129,6 +142,7 @@ ResourceRequestInfoImpl::ResourceRequestInfoImpl(
has_user_gesture_(has_user_gesture),
enable_load_timing_(enable_load_timing),
enable_upload_progress_(enable_upload_progress),
+ do_not_prompt_for_login_(do_not_prompt_for_login),
was_ignored_by_handler_(false),
counted_as_in_flight_request_(false),
resource_type_(resource_type),
diff --git a/chromium/content/browser/loader/resource_request_info_impl.h b/chromium/content/browser/loader/resource_request_info_impl.h
index 6b75fcdae87..29f0d71aefd 100644
--- a/chromium/content/browser/loader/resource_request_info_impl.h
+++ b/chromium/content/browser/loader/resource_request_info_impl.h
@@ -58,6 +58,7 @@ class ResourceRequestInfoImpl : public ResourceRequestInfo,
bool has_user_gesture,
bool enable_load_timing,
bool enable_upload_progress,
+ bool do_not_prompt_for_login,
blink::WebReferrerPolicy referrer_policy,
blink::WebPageVisibilityState visibility_state,
ResourceContext* context,
@@ -167,6 +168,11 @@ class ResourceRequestInfoImpl : public ResourceRequestInfo,
bool is_upload_progress_enabled() const { return enable_upload_progress_; }
+ bool do_not_prompt_for_login() const { return do_not_prompt_for_login_; }
+ void set_do_not_prompt_for_login(bool do_not_prompt) {
+ do_not_prompt_for_login_ = do_not_prompt;
+ }
+
private:
FRIEND_TEST_ALL_PREFIXES(ResourceDispatcherHostTest,
DeletedFilterDetached);
@@ -192,6 +198,7 @@ class ResourceRequestInfoImpl : public ResourceRequestInfo,
bool has_user_gesture_;
bool enable_load_timing_;
bool enable_upload_progress_;
+ bool do_not_prompt_for_login_;
bool was_ignored_by_handler_;
bool counted_as_in_flight_request_;
ResourceType resource_type_;
diff --git a/chromium/content/browser/loader/resource_scheduler.cc b/chromium/content/browser/loader/resource_scheduler.cc
index 82d96ab5162..a3d3d649ac2 100644
--- a/chromium/content/browser/loader/resource_scheduler.cc
+++ b/chromium/content/browser/loader/resource_scheduler.cc
@@ -27,20 +27,40 @@ namespace content {
namespace {
+// Post ResourceScheduler histograms of the following forms:
+// If |histogram_suffix| is NULL or the empty string:
+// ResourceScheduler.base_name.histogram_name
+// Else:
+// ResourceScheduler.base_name.histogram_name.histogram_suffix
void PostHistogram(const char* base_name,
- const char* suffix,
+ const char* histogram_name,
+ const char* histogram_suffix,
base::TimeDelta time) {
- std::string histogram_name =
- base::StringPrintf("ResourceScheduler.%s.%s", base_name, suffix);
+ std::string histogram =
+ base::StringPrintf("ResourceScheduler.%s.%s", base_name, histogram_name);
+ if (histogram_suffix && histogram_suffix[0] != '\0')
+ histogram = histogram + "." + histogram_suffix;
base::HistogramBase* histogram_counter = base::Histogram::FactoryTimeGet(
- histogram_name,
- base::TimeDelta::FromMilliseconds(1),
- base::TimeDelta::FromMinutes(5),
- 50,
+ histogram, base::TimeDelta::FromMilliseconds(1),
+ base::TimeDelta::FromMinutes(5), 50,
base::Histogram::kUmaTargetedHistogramFlag);
histogram_counter->AddTime(time);
}
+// For use with PostHistogram to specify the correct string for histogram
+// suffixes based on number of Clients.
+const char* GetNumClientsString(size_t num_clients) {
+ if (num_clients == 1)
+ return "1Client";
+ else if (num_clients <= 5)
+ return "Max5Clients";
+ else if (num_clients <= 15)
+ return "Max15Clients";
+ else if (num_clients <= 30)
+ return "Max30Clients";
+ return "Over30Clients";
+}
+
} // namespace
static const size_t kCoalescedTimerPeriod = 5000;
@@ -151,14 +171,11 @@ class ResourceScheduler::ScheduledResourceRequest
scheduler_(scheduler),
priority_(priority),
fifo_ordering_(0) {
- TRACE_EVENT_ASYNC_BEGIN1("net", "URLRequest", request_,
- "url", request->url().spec());
}
~ScheduledResourceRequest() override { scheduler_->RemoveRequest(this); }
void Start() {
- TRACE_EVENT_ASYNC_STEP_PAST0("net", "URLRequest", request_, "Queued");
ready_ = true;
if (!request_->status().is_success())
return;
@@ -182,9 +199,9 @@ class ResourceScheduler::ScheduledResourceRequest
controller()->Resume();
time_was_deferred = time - time_deferred_;
}
- PostHistogram("RequestTimeDeferred", client_state, time_was_deferred);
- PostHistogram(
- "RequestTimeThrottled", client_state, time - request_->creation_time());
+ PostHistogram("RequestTimeDeferred", client_state, NULL, time_was_deferred);
+ PostHistogram("RequestTimeThrottled", client_state, NULL,
+ time - request_->creation_time());
// TODO(aiolos): Remove one of the above histograms after gaining an
// understanding of the difference between them and which one is more
// interesting.
@@ -283,11 +300,11 @@ class ResourceScheduler::Client {
is_paused_(false),
has_body_(false),
using_spdy_proxy_(false),
+ load_started_time_(base::TimeTicks::Now()),
+ scheduler_(scheduler),
in_flight_delayable_count_(0),
total_layout_blocking_count_(0),
- throttle_state_(ResourceScheduler::THROTTLED) {
- scheduler_ = scheduler;
- }
+ throttle_state_(ResourceScheduler::THROTTLED) {}
~Client() {
// Update to default state and pause to ensure the scheduler has a
@@ -338,18 +355,21 @@ class ResourceScheduler::Client {
bool is_visible() const { return is_visible_; }
void OnAudibilityChanged(bool is_audible) {
- if (is_audible == is_audible_) {
- return;
- }
- is_audible_ = is_audible;
- UpdateThrottleState();
+ UpdateState(is_audible, &is_audible_);
}
void OnVisibilityChanged(bool is_visible) {
- if (is_visible == is_visible_) {
+ UpdateState(is_visible, &is_visible_);
+ }
+
+ // Function to update any client state variable used to determine whether a
+ // Client is active or background. Used for is_visible_ and is_audible_.
+ void UpdateState(bool new_state, bool* current_state) {
+ bool was_active = is_active();
+ *current_state = new_state;
+ if (was_active == is_active())
return;
- }
- is_visible_ = is_visible;
+ last_active_switch_time_ = base::TimeTicks::Now();
UpdateThrottleState();
}
@@ -359,6 +379,33 @@ class ResourceScheduler::Client {
}
is_loaded_ = is_loaded;
UpdateThrottleState();
+ if (!is_loaded_) {
+ load_started_time_ = base::TimeTicks::Now();
+ last_active_switch_time_ = base::TimeTicks();
+ return;
+ }
+ base::TimeTicks cur_time = base::TimeTicks::Now();
+ const char* num_clients =
+ GetNumClientsString(scheduler_->client_map_.size());
+ const char* client_catagory = "Other";
+ if (last_active_switch_time_.is_null()) {
+ client_catagory = is_active() ? "Active" : "Background";
+ } else if (is_active()) {
+ base::TimeDelta time_since_active = cur_time - last_active_switch_time_;
+ PostHistogram("ClientLoadedTime", "Other.SwitchedToActive", NULL,
+ time_since_active);
+ PostHistogram("ClientLoadedTime", "Other.SwitchedToActive", num_clients,
+ time_since_active);
+ }
+ base::TimeDelta time_since_load_started = cur_time - load_started_time_;
+ PostHistogram("ClientLoadedTime", client_catagory, NULL,
+ time_since_load_started);
+ PostHistogram("ClientLoadedTime", client_catagory, num_clients,
+ time_since_load_started);
+ // TODO(aiolos): The above histograms will not take main resource load time
+ // into account with PlzNavigate into account. The ResourceScheduler also
+ // will load the main resources without a clients with the current logic.
+ // Find a way to fix both of these issues.
}
void SetPaused() {
@@ -423,8 +470,8 @@ class ResourceScheduler::Client {
request->set_request_priority_params(new_priority_params);
if (!pending_requests_.IsQueued(request)) {
DCHECK(ContainsKey(in_flight_requests_, request));
- // The priority and SPDY support may have changed, so update the
- // delayable count.
+ // The priority of the request and priority support of the server may
+ // have changed, so update the delayable count.
SetRequestClassification(request, ClassifyRequest(request));
// Request has already started.
return;
@@ -567,7 +614,7 @@ class ResourceScheduler::Client {
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) &&
+ if (!http_server_properties.SupportsRequestPriority(host_port_pair) &&
ContainsKey(in_flight_requests_, request)) {
return IN_FLIGHT_DELAYABLE_REQUEST;
}
@@ -604,7 +651,7 @@ class ResourceScheduler::Client {
// * Synchronous requests.
// * Non-HTTP[S] requests.
//
- // 2. Requests to SPDY-capable origin servers.
+ // 2. Requests to request-priority-capable origin servers.
//
// 3. High-priority requests:
// * Higher priority requests (>= net::LOW).
@@ -618,8 +665,8 @@ class ResourceScheduler::Client {
// 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.
+ // * Non-delayable, High-priority and request-priority 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.
@@ -629,8 +676,10 @@ class ResourceScheduler::Client {
// * Never exceed 6 delayable requests for a given host.
//
// 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
+ // * Non-delayable and request-priority-capable requests are issued
+ // immediately.
+ // * At most one non-request-priority-capable request will be issued per
+ // THROTTLED Client
// * If no high priority requests are in flight, start loading low priority
// requests.
//
@@ -671,15 +720,16 @@ class ResourceScheduler::Client {
*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
- // against the delayable requests limit.
- if (http_server_properties.SupportsSpdy(host_port_pair)) {
+ // crbug.com/164101. Also, theoretically we should not count a
+ // request-priority capable request against the delayable requests limit.
+ if (http_server_properties.SupportsRequestPriority(host_port_pair)) {
return START_REQUEST;
}
if (throttle_state_ == THROTTLED &&
in_flight_requests_.size() >= kMaxNumThrottledRequestsPerClient) {
- // There may still be SPDY-capable requests that should be issued.
+ // There may still be request-priority-capable requests that should be
+ // issued.
return DO_NOT_START_REQUEST_AND_KEEP_SEARCHING;
}
@@ -754,6 +804,9 @@ class ResourceScheduler::Client {
bool using_spdy_proxy_;
RequestQueue pending_requests_;
RequestSet in_flight_requests_;
+ base::TimeTicks load_started_time_;
+ // The last time the client switched state between active and background.
+ base::TimeTicks last_active_switch_time_;
ResourceScheduler* scheduler_;
// The number of delayable in-flight requests.
size_t in_flight_delayable_count_;
@@ -853,8 +906,6 @@ void ResourceScheduler::OnClientCreated(int child_id,
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();
}
diff --git a/chromium/content/browser/loader/resource_scheduler_unittest.cc b/chromium/content/browser/loader/resource_scheduler_unittest.cc
index 2d1b0fe34bd..7095064c117 100644
--- a/chromium/content/browser/loader/resource_scheduler_unittest.cc
+++ b/chromium/content/browser/loader/resource_scheduler_unittest.cc
@@ -32,6 +32,8 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/latency_info.h"
+using std::string;
+
namespace content {
namespace {
@@ -120,6 +122,7 @@ class FakeResourceMessageFilter : public ResourceMessageFilter {
NULL /* blob_storage_context */,
NULL /* file_system_context */,
NULL /* service_worker_context */,
+ NULL /* host_zoom_level_context */,
base::Bind(&FakeResourceMessageFilter::GetContexts,
base::Unretained(this))) {
}
@@ -168,7 +171,7 @@ class ResourceSchedulerTest : public testing::Test {
int route_id,
bool is_async) {
scoped_ptr<net::URLRequest> url_request(
- context_.CreateRequest(GURL(url), priority, NULL, NULL));
+ context_.CreateRequest(GURL(url), priority, NULL));
ResourceRequestInfoImpl* info = new ResourceRequestInfoImpl(
PROCESS_TYPE_RENDERER, // process_type
child_id, // child_id
@@ -188,6 +191,7 @@ class ResourceSchedulerTest : public testing::Test {
false, // has_user_gesture
false, // enable_load_timing
false, // enable_upload_progress
+ false, // do_not_prompt_for_login
blink::WebReferrerPolicyDefault, // referrer_policy
blink::WebPageVisibilityStateVisible, // visibility_state
NULL, // context
diff --git a/chromium/content/browser/loader/temporary_file_stream.cc b/chromium/content/browser/loader/temporary_file_stream.cc
index e904d88e107..fc57c8aad89 100644
--- a/chromium/content/browser/loader/temporary_file_stream.cc
+++ b/chromium/content/browser/loader/temporary_file_stream.cc
@@ -10,7 +10,7 @@
#include "base/memory/ref_counted.h"
#include "content/public/browser/browser_thread.h"
#include "net/base/file_stream.h"
-#include "storage/common/blob/shareable_file_reference.h"
+#include "storage/browser/blob/shareable_file_reference.h"
using storage::ShareableFileReference;
@@ -23,7 +23,7 @@ void DidCreateTemporaryFile(
scoped_ptr<base::FileProxy> file_proxy,
base::File::Error error_code,
const base::FilePath& file_path) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!file_proxy->IsValid()) {
callback.Run(error_code, scoped_ptr<net::FileStream>(), NULL);
@@ -50,7 +50,7 @@ void DidCreateTemporaryFile(
void CreateTemporaryFileStream(
const CreateTemporaryFileStreamCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
scoped_ptr<base::FileProxy> file_proxy(new base::FileProxy(
BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE).get()));
diff --git a/chromium/content/browser/loader/temporary_file_stream_unittest.cc b/chromium/content/browser/loader/temporary_file_stream_unittest.cc
index 854a5ddf5ab..af57f0824ec 100644
--- a/chromium/content/browser/loader/temporary_file_stream_unittest.cc
+++ b/chromium/content/browser/loader/temporary_file_stream_unittest.cc
@@ -18,7 +18,7 @@
#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 "storage/browser/blob/shareable_file_reference.h"
#include "testing/gtest/include/gtest/gtest.h"
using storage::ShareableFileReference;
diff --git a/chromium/content/browser/loader/throttling_resource_handler.cc b/chromium/content/browser/loader/throttling_resource_handler.cc
index 1f17d336b6d..0378423ba15 100644
--- a/chromium/content/browser/loader/throttling_resource_handler.cc
+++ b/chromium/content/browser/loader/throttling_resource_handler.cc
@@ -40,7 +40,7 @@ bool ThrottlingResourceHandler::OnRequestRedirected(
*defer = false;
while (next_index_ < throttles_.size()) {
int index = next_index_;
- throttles_[index]->WillRedirectRequest(redirect_info.new_url, defer);
+ throttles_[index]->WillRedirectRequest(redirect_info, defer);
next_index_++;
if (cancelled_by_resource_throttle_)
return false;
diff --git a/chromium/content/browser/loader/upload_data_stream_builder.cc b/chromium/content/browser/loader/upload_data_stream_builder.cc
index 376e221d2a6..c497c16c0a7 100644
--- a/chromium/content/browser/loader/upload_data_stream_builder.cc
+++ b/chromium/content/browser/loader/upload_data_stream_builder.cc
@@ -11,12 +11,9 @@
#include "net/base/upload_bytes_element_reader.h"
#include "net/base/upload_file_element_reader.h"
#include "storage/browser/blob/blob_data_handle.h"
+#include "storage/browser/blob/blob_data_snapshot.h"
#include "storage/browser/blob/blob_storage_context.h"
-using storage::BlobData;
-using storage::BlobDataHandle;
-using storage::BlobStorageContext;
-
namespace content {
namespace {
@@ -64,6 +61,7 @@ class FileElementReader : public net::UploadFileElementReader {
};
void ResolveBlobReference(
+ ResourceRequestBody* body,
storage::BlobStorageContext* blob_context,
const ResourceRequestBody::Element& element,
std::vector<const ResourceRequestBody::Element*>* resolved_elements) {
@@ -74,23 +72,29 @@ void ResolveBlobReference(
if (!handle)
return;
+ // TODO(dmurph): Create a reader for blobs instead of decomposing the blob
+ // and storing the snapshot on the request to keep the resources around.
+ // Currently a handle is attached to the request in the resource dispatcher
+ // host, so we know the blob won't go away, but it's not very clear or useful.
+ scoped_ptr<storage::BlobDataSnapshot> snapshot = handle->CreateSnapshot();
// If there is no element in the referred blob data, just return.
- if (handle->data()->items().empty())
+ if (snapshot->items().empty())
return;
// Append the elements in the referenced blob data.
- for (size_t i = 0; i < handle->data()->items().size(); ++i) {
- const BlobData::Item& item = handle->data()->items().at(i);
- DCHECK_NE(BlobData::Item::TYPE_BLOB, item.type());
- resolved_elements->push_back(&item);
+ for (const auto& item : snapshot->items()) {
+ DCHECK_NE(storage::DataElement::TYPE_BLOB, item->type());
+ resolved_elements->push_back(item->data_element_ptr());
}
+ const void* key = snapshot.get();
+ body->SetUserData(key, snapshot.release());
}
} // namespace
scoped_ptr<net::UploadDataStream> UploadDataStreamBuilder::Build(
ResourceRequestBody* body,
- BlobStorageContext* blob_context,
+ storage::BlobStorageContext* blob_context,
storage::FileSystemContext* file_system_context,
base::TaskRunner* file_task_runner) {
// Resolve all blob elements.
@@ -98,7 +102,7 @@ scoped_ptr<net::UploadDataStream> UploadDataStreamBuilder::Build(
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(blob_context, element, &resolved_elements);
+ ResolveBlobReference(body, blob_context, element, &resolved_elements);
else
resolved_elements.push_back(&element);
}
@@ -128,6 +132,7 @@ scoped_ptr<net::UploadDataStream> UploadDataStreamBuilder::Build(
break;
case ResourceRequestBody::Element::TYPE_BLOB:
// Blob elements should be resolved beforehand.
+ // TODO(dmurph): Create blob reader and store the snapshot in there.
NOTREACHED();
break;
case ResourceRequestBody::Element::TYPE_UNKNOWN:
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 dfd22b25317..57161eaf4ca 100644
--- a/chromium/content/browser/loader/upload_data_stream_builder_unittest.cc
+++ b/chromium/content/browser/loader/upload_data_stream_builder_unittest.cc
@@ -5,6 +5,7 @@
#include "content/browser/loader/upload_data_stream_builder.h"
#include <algorithm>
+#include <string>
#include "base/files/file_path.h"
#include "base/files/file_util.h"
@@ -13,14 +14,18 @@
#include "base/run_loop.h"
#include "base/time/time.h"
#include "content/common/resource_request_body.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/base/test_completion_callback.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 "storage/browser/blob/blob_data_builder.h"
#include "storage/browser/blob/blob_storage_context.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
-using storage::BlobData;
+using storage::BlobDataBuilder;
using storage::BlobDataHandle;
using storage::BlobStorageContext;
@@ -105,29 +110,25 @@ TEST(UploadDataStreamBuilderTest, ResolveBlobAndCreateUploadDataStream) {
BlobStorageContext blob_storage_context;
const std::string blob_id0("id-0");
- scoped_refptr<BlobData> blob_data(new BlobData(blob_id0));
+ scoped_ptr<BlobDataBuilder> blob_data_builder(
+ new BlobDataBuilder(blob_id0));
scoped_ptr<BlobDataHandle> handle1 =
- blob_storage_context.AddFinishedBlob(blob_data.get());
+ blob_storage_context.AddFinishedBlob(blob_data_builder.get());
const std::string blob_id1("id-1");
- blob_data = new BlobData(blob_id1);
- blob_data->AppendData("BlobData");
- blob_data->AppendFile(
+ const std::string kBlobData = "BlobData";
+ blob_data_builder.reset(new BlobDataBuilder(blob_id1));
+ blob_data_builder->AppendData(kBlobData);
+ blob_data_builder->AppendFile(
base::FilePath(FILE_PATH_LITERAL("BlobFile.txt")), 0, 20, time1);
scoped_ptr<BlobDataHandle> handle2 =
- blob_storage_context.AddFinishedBlob(blob_data.get());
+ blob_storage_context.AddFinishedBlob(blob_data_builder.get());
// Setup upload data elements for comparison.
ResourceRequestBody::Element blob_element1, blob_element2;
- blob_element1.SetToBytes(
- blob_data->items().at(0).bytes() +
- static_cast<int>(blob_data->items().at(0).offset()),
- static_cast<int>(blob_data->items().at(0).length()));
+ blob_element1.SetToBytes(kBlobData.c_str(), kBlobData.size());
blob_element2.SetToFilePathRange(
- blob_data->items().at(1).path(),
- blob_data->items().at(1).offset(),
- blob_data->items().at(1).length(),
- blob_data->items().at(1).expected_modification_time());
+ base::FilePath(FILE_PATH_LITERAL("BlobFile.txt")), 0, 20, time1);
ResourceRequestBody::Element upload_element1, upload_element2;
upload_element1.SetToBytes("Hello", 5);
@@ -313,4 +314,70 @@ TEST(UploadDataStreamBuilderTest, ResolveBlobAndCreateUploadDataStream) {
base::RunLoop().RunUntilIdle();
}
+TEST(UploadDataStreamBuilderTest,
+ WriteUploadDataStreamWithEmptyFileBackedBlob) {
+ base::MessageLoopForIO message_loop;
+ {
+ base::FilePath test_blob_path;
+ ASSERT_TRUE(base::CreateTemporaryFile(&test_blob_path));
+
+ const uint64_t kZeroLength = 0;
+ base::Time blob_time;
+ base::Time::FromString("Tue, 15 Nov 1994, 12:45:26 GMT", &blob_time);
+ ASSERT_TRUE(base::TouchFile(test_blob_path, blob_time, blob_time));
+
+ BlobStorageContext blob_storage_context;
+
+ // A blob created from an empty file added several times.
+ const std::string blob_id("id-0");
+ scoped_ptr<BlobDataBuilder> blob_data_builder(new BlobDataBuilder(blob_id));
+ blob_data_builder->AppendFile(test_blob_path, 0, kZeroLength, blob_time);
+ scoped_ptr<BlobDataHandle> handle =
+ blob_storage_context.AddFinishedBlob(blob_data_builder.get());
+
+ ResourceRequestBody::Element blob_element;
+ blob_element.SetToFilePathRange(test_blob_path, 0, kZeroLength, blob_time);
+
+ scoped_refptr<ResourceRequestBody> request_body(new ResourceRequestBody());
+ scoped_ptr<net::UploadDataStream> upload(UploadDataStreamBuilder::Build(
+ request_body.get(), &blob_storage_context, NULL,
+ base::MessageLoopProxy::current().get()));
+
+ request_body = new ResourceRequestBody();
+ request_body->AppendBlob(blob_id);
+ request_body->AppendBlob(blob_id);
+ request_body->AppendBlob(blob_id);
+
+ upload = UploadDataStreamBuilder::Build(
+ request_body.get(), &blob_storage_context, NULL,
+ base::MessageLoopProxy::current().get());
+ ASSERT_TRUE(upload->GetElementReaders());
+ const auto& readers = *upload->GetElementReaders();
+ ASSERT_EQ(3U, readers.size());
+ EXPECT_TRUE(AreElementsEqual(*readers[0], blob_element));
+ EXPECT_TRUE(AreElementsEqual(*readers[1], blob_element));
+ EXPECT_TRUE(AreElementsEqual(*readers[2], blob_element));
+
+ net::TestCompletionCallback init_callback;
+ ASSERT_EQ(net::ERR_IO_PENDING, upload->Init(init_callback.callback()));
+ EXPECT_EQ(net::OK, init_callback.WaitForResult());
+
+ EXPECT_EQ(kZeroLength, upload->size());
+
+ // Purposely (try to) read more than what is in the stream. If we try to
+ // read zero bytes then UploadDataStream::Read will fail a DCHECK.
+ int kBufferLength = kZeroLength + 1;
+ scoped_ptr<char[]> buffer(new char[kBufferLength]);
+ scoped_refptr<net::IOBuffer> io_buffer =
+ new net::WrappedIOBuffer(buffer.get());
+ net::TestCompletionCallback read_callback;
+ int result =
+ upload->Read(io_buffer.get(), kBufferLength, read_callback.callback());
+ EXPECT_EQ(static_cast<int>(kZeroLength), read_callback.GetResult(result));
+
+ base::DeleteFile(test_blob_path, false);
+ }
+ // Clean up for ASAN.
+ base::RunLoop().RunUntilIdle();
+}
} // namespace content
diff --git a/chromium/content/browser/mach_broker_mac.h b/chromium/content/browser/mach_broker_mac.h
index 9088ca70265..5b4bfb817fb 100644
--- a/chromium/content/browser/mach_broker_mac.h
+++ b/chromium/content/browser/mach_broker_mac.h
@@ -5,11 +5,14 @@
#ifndef CONTENT_BROWSER_MACH_BROKER_MAC_H_
#define CONTENT_BROWSER_MACH_BROKER_MAC_H_
+#include <mach/mach.h>
+
#include <map>
#include <string>
-#include <mach/mach.h>
-
+#include "base/mac/dispatch_source_mach.h"
+#include "base/mac/scoped_mach_port.h"
+#include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h"
#include "base/process/process_handle.h"
#include "base/process/process_metrics.h"
@@ -61,7 +64,7 @@ class CONTENT_EXPORT MachBroker : public base::ProcessMetrics::PortProvider,
// Callers are expected to later update the port with FinalizePid(). Callers
// MUST acquire the lock given by GetLock() before calling this method (and
// release the lock afterwards).
- void AddPlaceholderForPid(base::ProcessHandle pid);
+ void AddPlaceholderForPid(base::ProcessHandle pid, int child_process_id);
// Implement |ProcessMetrics::PortProvider|.
mach_port_t TaskForPid(base::ProcessHandle process) const override;
@@ -69,7 +72,8 @@ class CONTENT_EXPORT MachBroker : public base::ProcessMetrics::PortProvider,
// Implement |BrowserChildProcessObserver|.
void BrowserChildProcessHostDisconnected(
const ChildProcessData& data) override;
- void BrowserChildProcessCrashed(const ChildProcessData& data) override;
+ void BrowserChildProcessCrashed(const ChildProcessData& data,
+ int exit_code) override;
// Implement |NotificationObserver|.
void Observe(int type,
@@ -78,39 +82,57 @@ class CONTENT_EXPORT MachBroker : public base::ProcessMetrics::PortProvider,
private:
friend class MachBrokerTest;
- friend class MachListenerThreadDelegate;
friend struct DefaultSingletonTraits<MachBroker>;
MachBroker();
~MachBroker() override;
+ // Performs any initialization work.
+ bool Init();
+
+ // Message handler that is invoked on |dispatch_source_| when an
+ // incoming message needs to be received.
+ void HandleRequest();
+
// Updates the mapping for |pid| to include the given |mach_info|. Does
// nothing if PlaceholderForPid() has not already been called for the given
// |pid|. Callers MUST acquire the lock given by GetLock() before calling
// this method (and release the lock afterwards).
void FinalizePid(base::ProcessHandle pid, mach_port_t task_port);
- // Removes all mappings belonging to |pid| from the broker.
- void InvalidatePid(base::ProcessHandle pid);
+ // Removes all mappings belonging to |child_process_id| from the broker.
+ void InvalidateChildProcessId(int child_process_id);
// 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();
- // True if the listener thread has been started.
- bool listener_thread_started_;
+ // Whether or not the class has been initialized.
+ bool initialized_;
// Used to register for notifications received by NotificationObserver.
// Accessed only on the UI thread.
NotificationRegistrar registrar_;
+ // The Mach port on which the server listens.
+ base::mac::ScopedMachReceiveRight server_port_;
+
+ // The dispatch source and queue on which Mach messages will be received.
+ scoped_ptr<base::DispatchSourceMach> dispatch_source_;
+
// Stores mach info for every process in the broker.
typedef std::map<base::ProcessHandle, mach_port_t> MachMap;
MachMap mach_map_;
- // Mutex that guards |mach_map_|.
+ // Stores the Child process unique id (RenderProcessHost ID) for every
+ // process.
+ typedef std::map<int, base::ProcessHandle> ChildProcessIdMap;
+ ChildProcessIdMap child_process_id_map_;
+
+ // Mutex that guards |mach_map_| and |child_process_id_map_|.
mutable base::Lock lock_;
DISALLOW_COPY_AND_ASSIGN(MachBroker);
diff --git a/chromium/content/browser/mach_broker_mac.mm b/chromium/content/browser/mach_broker_mac.mm
index f2e5f985c32..3efec6b94d6 100644
--- a/chromium/content/browser/mach_broker_mac.mm
+++ b/chromium/content/browser/mach_broker_mac.mm
@@ -13,11 +13,9 @@
#include "base/logging.h"
#include "base/mac/foundation_util.h"
#include "base/mac/mach_logging.h"
-#include "base/mac/scoped_mach_port.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/sys_string_conversions.h"
-#include "base/threading/platform_thread.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/child_process_data.h"
@@ -44,94 +42,6 @@ struct MachBroker_ParentRecvMsg : public MachBroker_ChildSendMsg {
} // namespace
-class MachListenerThreadDelegate : public base::PlatformThread::Delegate {
- public:
- explicit MachListenerThreadDelegate(MachBroker* broker)
- : broker_(broker),
- server_port_(MACH_PORT_NULL) {
- DCHECK(broker_);
- }
-
- bool Init() {
- DCHECK(server_port_.get() == MACH_PORT_NULL);
-
- mach_port_t port;
- kern_return_t kr = mach_port_allocate(mach_task_self(),
- MACH_PORT_RIGHT_RECEIVE,
- &port);
- if (kr != KERN_SUCCESS) {
- MACH_LOG(ERROR, kr) << "mach_port_allocate";
- return false;
- }
- server_port_.reset(port);
-
- // Allocate a send right for the server port.
- kr = mach_port_insert_right(
- mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND);
- if (kr != KERN_SUCCESS) {
- MACH_LOG(ERROR, kr) << "mach_port_insert_right";
- return false;
- }
- // Deallocate the right after registering with the bootstrap server.
- base::mac::ScopedMachSendRight send_right(port);
-
- // Register the port with the bootstrap server. Because bootstrap_register
- // is deprecated, this has to be wraped in an ObjC interface.
- NSPort* ns_port = [NSMachPort portWithMachPort:port
- options:NSMachPortDeallocateNone];
- NSString* name = base::SysUTF8ToNSString(broker_->GetMachPortName());
- return [[NSMachBootstrapServer sharedInstance] registerPort:ns_port
- name:name];
- }
-
- // Implement |PlatformThread::Delegate|.
- void ThreadMain() override {
- MachBroker_ParentRecvMsg msg;
- bzero(&msg, sizeof(msg));
- msg.header.msgh_size = sizeof(msg);
- msg.header.msgh_local_port = server_port_.get();
-
- const mach_msg_option_t options = MACH_RCV_MSG |
- MACH_RCV_TRAILER_TYPE(MACH_RCV_TRAILER_AUDIT) |
- MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT);
-
- kern_return_t kr;
- while ((kr = mach_msg(&msg.header,
- options,
- 0,
- sizeof(msg),
- server_port_,
- MACH_MSG_TIMEOUT_NONE,
- MACH_PORT_NULL)) == KERN_SUCCESS) {
- // Use the kernel audit information to make sure this message is from
- // a task that this process spawned. The kernel audit token contains the
- // unspoofable pid of the task that sent the message.
- //
- // TODO(rsesek): In the 10.7 SDK, there's audit_token_to_pid().
- pid_t child_pid;
- audit_token_to_au32(msg.trailer.msgh_audit,
- NULL, NULL, NULL, NULL, NULL, &child_pid, NULL, NULL);
-
- mach_port_t child_task_port = msg.child_task_port.name;
-
- // Take the lock and update the broker information.
- base::AutoLock lock(broker_->GetLock());
- broker_->FinalizePid(child_pid, child_task_port);
- }
-
- MACH_LOG(ERROR, kr) << "mach_msg";
- }
-
- private:
- // The MachBroker to use when new child task rights are received. Can be
- // NULL.
- MachBroker* broker_; // weak
-
- base::mac::ScopedMachReceiveRight server_port_;
-
- DISALLOW_COPY_AND_ASSIGN(MachListenerThreadDelegate);
-};
-
bool MachBroker::ChildSendTaskPortToParent() {
// Look up the named MachBroker port that's been registered with the
// bootstrap server.
@@ -168,7 +78,7 @@ bool MachBroker::ChildSendTaskPortToParent() {
}
MachBroker* MachBroker::GetInstance() {
- return Singleton<MachBroker, LeakySingletonTraits<MachBroker> >::get();
+ return Singleton<MachBroker, LeakySingletonTraits<MachBroker>>::get();
}
base::Lock& MachBroker::GetLock() {
@@ -178,28 +88,28 @@ base::Lock& MachBroker::GetLock() {
void MachBroker::EnsureRunning() {
lock_.AssertAcquired();
- if (!listener_thread_started_) {
- listener_thread_started_ = true;
+ if (initialized_)
+ return;
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&MachBroker::RegisterNotifications, base::Unretained(this)));
+ // Do not attempt to reinitialize in the event of failure.
+ initialized_ = true;
- // Intentional leak. This thread is never joined or reaped.
- MachListenerThreadDelegate* thread = new MachListenerThreadDelegate(this);
- if (thread->Init()) {
- base::PlatformThread::CreateNonJoinable(0, thread);
- } else {
- LOG(ERROR) << "Failed to initialize the MachListenerThreadDelegate";
- }
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&MachBroker::RegisterNotifications, base::Unretained(this)));
+
+ if (!Init()) {
+ LOG(ERROR) << "Failed to initialize the MachListenerThreadDelegate";
}
}
-void MachBroker::AddPlaceholderForPid(base::ProcessHandle pid) {
+void MachBroker::AddPlaceholderForPid(base::ProcessHandle pid,
+ int child_process_id) {
lock_.AssertAcquired();
DCHECK_EQ(0u, mach_map_.count(pid));
mach_map_[pid] = MACH_PORT_NULL;
+ child_process_id_map_[child_process_id] = pid;
}
mach_port_t MachBroker::TaskForPid(base::ProcessHandle pid) const {
@@ -212,40 +122,96 @@ mach_port_t MachBroker::TaskForPid(base::ProcessHandle pid) const {
void MachBroker::BrowserChildProcessHostDisconnected(
const ChildProcessData& data) {
- InvalidatePid(data.handle);
+ InvalidateChildProcessId(data.id);
}
-void MachBroker::BrowserChildProcessCrashed(const ChildProcessData& data) {
- InvalidatePid(data.handle);
+void MachBroker::BrowserChildProcessCrashed(const ChildProcessData& data,
+ int exit_code) {
+ InvalidateChildProcessId(data.id);
}
void MachBroker::Observe(int type,
const NotificationSource& source,
const NotificationDetails& details) {
- // TODO(rohitrao): These notifications do not always carry the proper PIDs,
- // especially when the renderer is already gone or has crashed. Find a better
- // way to listen for child process deaths. http://crbug.com/55734
- base::ProcessHandle handle = 0;
switch (type) {
- case NOTIFICATION_RENDERER_PROCESS_CLOSED:
- handle = Details<RenderProcessHost::RendererClosedDetails>(
- details)->handle;
- break;
case NOTIFICATION_RENDERER_PROCESS_TERMINATED:
- handle = Source<RenderProcessHost>(source)->GetHandle();
+ case NOTIFICATION_RENDERER_PROCESS_CLOSED: {
+ RenderProcessHost* host = Source<RenderProcessHost>(source).ptr();
+ InvalidateChildProcessId(host->GetID());
break;
+ }
default:
NOTREACHED() << "Unexpected notification";
break;
}
- InvalidatePid(handle);
}
-MachBroker::MachBroker() : listener_thread_started_(false) {
+MachBroker::MachBroker() : initialized_(false) {
}
MachBroker::~MachBroker() {}
+bool MachBroker::Init() {
+ DCHECK(server_port_.get() == MACH_PORT_NULL);
+
+ // Check in with launchd and publish the service name.
+ mach_port_t port;
+ kern_return_t kr =
+ bootstrap_check_in(bootstrap_port, GetMachPortName().c_str(), &port);
+ if (kr != KERN_SUCCESS) {
+ BOOTSTRAP_LOG(ERROR, kr) << "bootstrap_check_in";
+ return false;
+ }
+ server_port_.reset(port);
+
+ // Start the dispatch source.
+ std::string queue_name =
+ base::StringPrintf("%s.MachBroker", base::mac::BaseBundleID());
+ dispatch_source_.reset(new base::DispatchSourceMach(
+ queue_name.c_str(), server_port_.get(), ^{ HandleRequest(); }));
+ dispatch_source_->Resume();
+
+ return true;
+}
+
+void MachBroker::HandleRequest() {
+ MachBroker_ParentRecvMsg msg;
+ bzero(&msg, sizeof(msg));
+ msg.header.msgh_size = sizeof(msg);
+ msg.header.msgh_local_port = server_port_.get();
+
+ const mach_msg_option_t options = MACH_RCV_MSG |
+ MACH_RCV_TRAILER_TYPE(MACH_RCV_TRAILER_AUDIT) |
+ MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT);
+
+ kern_return_t kr = mach_msg(&msg.header,
+ options,
+ 0,
+ sizeof(msg),
+ server_port_,
+ MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+ if (kr != KERN_SUCCESS) {
+ MACH_LOG(ERROR, kr) << "mach_msg";
+ return;
+ }
+
+ // Use the kernel audit information to make sure this message is from
+ // a task that this process spawned. The kernel audit token contains the
+ // unspoofable pid of the task that sent the message.
+ //
+ // TODO(rsesek): In the 10.7 SDK, there's audit_token_to_pid().
+ pid_t child_pid;
+ audit_token_to_au32(msg.trailer.msgh_audit,
+ NULL, NULL, NULL, NULL, NULL, &child_pid, NULL, NULL);
+
+ mach_port_t child_task_port = msg.child_task_port.name;
+
+ // Take the lock and update the broker information.
+ base::AutoLock lock(GetLock());
+ FinalizePid(child_pid, child_task_port);
+}
+
void MachBroker::FinalizePid(base::ProcessHandle pid,
mach_port_t task_port) {
lock_.AssertAcquired();
@@ -262,16 +228,21 @@ void MachBroker::FinalizePid(base::ProcessHandle pid,
it->second = task_port;
}
-void MachBroker::InvalidatePid(base::ProcessHandle pid) {
+void MachBroker::InvalidateChildProcessId(int child_process_id) {
base::AutoLock lock(lock_);
- MachBroker::MachMap::iterator it = mach_map_.find(pid);
- if (it == mach_map_.end())
+ MachBroker::ChildProcessIdMap::iterator it =
+ child_process_id_map_.find(child_process_id);
+ if (it == child_process_id_map_.end())
return;
- kern_return_t kr = mach_port_deallocate(mach_task_self(),
- it->second);
- MACH_LOG_IF(WARNING, kr != KERN_SUCCESS, kr) << "mach_port_deallocate";
- mach_map_.erase(it);
+ MachMap::iterator mach_it = mach_map_.find(it->second);
+ if (mach_it != mach_map_.end()) {
+ kern_return_t kr = mach_port_deallocate(mach_task_self(),
+ mach_it->second);
+ MACH_LOG_IF(WARNING, kr != KERN_SUCCESS, kr) << "mach_port_deallocate";
+ mach_map_.erase(mach_it);
+ }
+ child_process_id_map_.erase(it);
}
// static
diff --git a/chromium/content/browser/mach_broker_mac_unittest.cc b/chromium/content/browser/mach_broker_mac_unittest.cc
index a7eca4fd2f4..9ba50c31090 100644
--- a/chromium/content/browser/mach_broker_mac_unittest.cc
+++ b/chromium/content/browser/mach_broker_mac_unittest.cc
@@ -12,13 +12,17 @@ namespace content {
class MachBrokerTest : public testing::Test {
public:
// Helper function to acquire/release locks and call |PlaceholderForPid()|.
- void AddPlaceholderForPid(base::ProcessHandle pid) {
+ void AddPlaceholderForPid(base::ProcessHandle pid, int child_process_id) {
base::AutoLock lock(broker_.GetLock());
- broker_.AddPlaceholderForPid(pid);
+ broker_.AddPlaceholderForPid(pid, child_process_id);
}
- void InvalidatePid(base::ProcessHandle pid) {
- broker_.InvalidatePid(pid);
+ void InvalidateChildProcessId(int child_process_id) {
+ broker_.InvalidateChildProcessId(child_process_id);
+ }
+
+ int GetChildProcessCount(int child_process_id) {
+ return broker_.child_process_id_map_.count(child_process_id);
}
// Helper function to acquire/release locks and call |FinalizePid()|.
@@ -39,7 +43,7 @@ TEST_F(MachBrokerTest, Locks) {
TEST_F(MachBrokerTest, AddPlaceholderAndFinalize) {
// Add a placeholder for PID 1.
- AddPlaceholderForPid(1);
+ AddPlaceholderForPid(1, 1);
EXPECT_EQ(0u, broker_.TaskForPid(1));
// Finalize PID 1.
@@ -50,15 +54,26 @@ TEST_F(MachBrokerTest, AddPlaceholderAndFinalize) {
EXPECT_EQ(0u, broker_.TaskForPid(2));
}
-TEST_F(MachBrokerTest, Invalidate) {
- AddPlaceholderForPid(1);
+TEST_F(MachBrokerTest, InvalidateChildProcessId) {
+ // Add a placeholder for PID 1 and child process id 50.
+ AddPlaceholderForPid(1, 50);
FinalizePid(1, 100u);
EXPECT_EQ(100u, broker_.TaskForPid(1));
- InvalidatePid(1u);
+ InvalidateChildProcessId(50);
EXPECT_EQ(0u, broker_.TaskForPid(1));
}
+TEST_F(MachBrokerTest, ValidateChildProcessIdMap) {
+ // Add a placeholder for PID 1 and child process id 50.
+ AddPlaceholderForPid(1, 50);
+ FinalizePid(1, 100u);
+
+ EXPECT_EQ(1, GetChildProcessCount(50));
+ InvalidateChildProcessId(50);
+ EXPECT_EQ(0, GetChildProcessCount(50));
+}
+
TEST_F(MachBrokerTest, FinalizeUnknownPid) {
// Finalizing an entry for an unknown pid should not add it to the map.
FinalizePid(1u, 100u);
diff --git a/chromium/content/browser/manifest/manifest_browsertest.cc b/chromium/content/browser/manifest/manifest_browsertest.cc
index 8eaca0a9445..043b5926d40 100644
--- a/chromium/content/browser/manifest/manifest_browsertest.cc
+++ b/chromium/content/browser/manifest/manifest_browsertest.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/command_line.h"
+#include "base/path_service.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/manifest.h"
@@ -15,11 +16,51 @@
namespace content {
+class ManifestBrowserTest;
+
+// Mock of a WebContentsDelegate that catches messages sent to the console.
+class MockWebContentsDelegate : public WebContentsDelegate {
+ public:
+ MockWebContentsDelegate(WebContents* web_contents, ManifestBrowserTest* test)
+ : web_contents_(web_contents),
+ test_(test) {
+ }
+
+ bool AddMessageToConsole(WebContents* source,
+ int32 level,
+ const base::string16& message,
+ int32 line_no,
+ const base::string16& source_id) override;
+
+ private:
+ WebContents* web_contents_;
+ ManifestBrowserTest* test_;
+};
+
class ManifestBrowserTest : public ContentBrowserTest {
protected:
- ManifestBrowserTest() {}
+ friend MockWebContentsDelegate;
+
+ ManifestBrowserTest()
+ : console_error_count_(0) {
+ cors_embedded_test_server_.reset(new net::test_server::EmbeddedTestServer);
+ base::FilePath test_data_dir;
+ CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir));
+ cors_embedded_test_server_->ServeFilesFromDirectory(
+ test_data_dir.AppendASCII("content/test/data/"));
+ }
+
~ManifestBrowserTest() override {}
+ void SetUpOnMainThread() override {
+ ContentBrowserTest::SetUpOnMainThread();
+ DCHECK(shell()->web_contents());
+
+ mock_web_contents_delegate_.reset(
+ new MockWebContentsDelegate(shell()->web_contents(), this));
+ shell()->web_contents()->SetDelegate(mock_web_contents_delegate_.get());
+ }
+
void GetManifestAndWait() {
shell()->web_contents()->GetManifest(
base::Bind(&ManifestBrowserTest::OnGetManifest,
@@ -38,13 +79,43 @@ class ManifestBrowserTest : public ContentBrowserTest {
return manifest_;
}
+ unsigned int console_error_count() const {
+ return console_error_count_;
+ }
+
+ void OnReceivedConsoleError() {
+ console_error_count_++;
+ }
+
+ net::test_server::EmbeddedTestServer* cors_embedded_test_server() const {
+ return cors_embedded_test_server_.get();
+ }
+
private:
scoped_refptr<MessageLoopRunner> message_loop_runner_;
+ scoped_ptr<MockWebContentsDelegate> mock_web_contents_delegate_;
+ scoped_ptr<net::test_server::EmbeddedTestServer> cors_embedded_test_server_;
Manifest manifest_;
+ int console_error_count_;
DISALLOW_COPY_AND_ASSIGN(ManifestBrowserTest);
};
+// The implementation of AddMessageToConsole isn't inlined because it needs
+// to know about |test_|.
+bool MockWebContentsDelegate::AddMessageToConsole(
+ WebContents* source,
+ int32 level,
+ const base::string16& message,
+ int32 line_no,
+ const base::string16& source_id) {
+ DCHECK(source == web_contents_);
+
+ if (level == logging::LOG_ERROR)
+ test_->OnReceivedConsoleError();
+ return false;
+}
+
// If a page has no manifest, requesting a manifest should return the empty
// manifest.
IN_PROC_BROWSER_TEST_F(ManifestBrowserTest, NoManifest) {
@@ -56,6 +127,7 @@ IN_PROC_BROWSER_TEST_F(ManifestBrowserTest, NoManifest) {
GetManifestAndWait();
EXPECT_TRUE(manifest().IsEmpty());
+ EXPECT_EQ(0u, console_error_count());
}
// If a page manifest points to a 404 URL, requesting the manifest should return
@@ -69,6 +141,7 @@ IN_PROC_BROWSER_TEST_F(ManifestBrowserTest, 404Manifest) {
GetManifestAndWait();
EXPECT_TRUE(manifest().IsEmpty());
+ EXPECT_EQ(0u, console_error_count());
}
// If a page has an empty manifest, requesting the manifest should return the
@@ -82,6 +155,7 @@ IN_PROC_BROWSER_TEST_F(ManifestBrowserTest, EmptyManifest) {
GetManifestAndWait();
EXPECT_TRUE(manifest().IsEmpty());
+ EXPECT_EQ(0u, console_error_count());
}
// If a page's manifest can't be parsed correctly, requesting the manifest
@@ -95,6 +169,7 @@ IN_PROC_BROWSER_TEST_F(ManifestBrowserTest, ParseErrorManifest) {
GetManifestAndWait();
EXPECT_TRUE(manifest().IsEmpty());
+ EXPECT_EQ(1u, console_error_count());
}
// If a page has a manifest that can be fetched and parsed, requesting the
@@ -108,6 +183,7 @@ IN_PROC_BROWSER_TEST_F(ManifestBrowserTest, DummyManifest) {
GetManifestAndWait();
EXPECT_FALSE(manifest().IsEmpty());
+ EXPECT_EQ(0u, console_error_count());
}
// If a page changes manifest during its life-time, requesting the manifest
@@ -143,18 +219,18 @@ IN_PROC_BROWSER_TEST_F(ManifestBrowserTest, DynamicManifest) {
GetManifestAndWait();
EXPECT_TRUE(manifest().IsEmpty());
}
+
+ EXPECT_EQ(0u, console_error_count());
}
// 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());
+ 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");
@@ -163,16 +239,56 @@ IN_PROC_BROWSER_TEST_F(ManifestBrowserTest, CORSManifest) {
shell()->LoadURL(test_url);
navigation_observer.Wait();
- std::string manifest_url =
- cors_embedded_test_server->GetURL("/manifest/dummy-manifest.json").spec();
+ 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());
+
+ EXPECT_EQ(0u, console_error_count());
+
+ // The purpose of this second load is to make sure the first load is fully
+ // finished. The first load will fail because of Access Control error but the
+ // underlying Blink loader will continue fetching the file. There is no
+ // reliable way to know when the fetch is finished from the browser test
+ // except by fetching the same file from same origin, making it succeed when
+ // it is actually fully loaded.
+ manifest_url =
+ embedded_test_server()->GetURL("/manifest/dummy-manifest.json").spec();
+ ASSERT_TRUE(content::ExecuteScript(shell()->web_contents(),
+ "setManifestTo('" + manifest_url + "')"));
+ GetManifestAndWait();
}
-// If a page's manifest is in an unsecure origin while the page is in a secure
+// If a page's manifest lives in a different origin, it should be accessible if
+// it has valid access controls headers.
+IN_PROC_BROWSER_TEST_F(ManifestBrowserTest, CORSManifestWithAcessControls) {
+ 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/manifest-cors.json").spec();
+ ASSERT_TRUE(content::ExecuteScript(shell()->web_contents(),
+ "setManifestTo('" + manifest_url + "')"));
+
+ GetManifestAndWait();
+ EXPECT_FALSE(manifest().IsEmpty());
+
+ EXPECT_EQ(0u, console_error_count());
+}
+
+// If a page's manifest is in an insecure 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(
@@ -197,6 +313,106 @@ IN_PROC_BROWSER_TEST_F(ManifestBrowserTest, MixedContentManifest) {
GetManifestAndWait();
EXPECT_TRUE(manifest().IsEmpty());
+
+ EXPECT_EQ(0u, console_error_count());
+}
+
+// If a page's manifest has some parsing errors, they should show up in the
+// developer console.
+IN_PROC_BROWSER_TEST_F(ManifestBrowserTest, ParsingErrorsManifest) {
+ GURL test_url = GetTestUrl("manifest", "parsing-errors.html");
+
+ TestNavigationObserver navigation_observer(shell()->web_contents(), 1);
+ shell()->LoadURL(test_url);
+ navigation_observer.Wait();
+
+ GetManifestAndWait();
+ EXPECT_TRUE(manifest().IsEmpty());
+ EXPECT_EQ(6u, console_error_count());
+}
+
+// If a page has a manifest and the page is navigated to a page without a
+// manifest, the page's manifest should be updated.
+IN_PROC_BROWSER_TEST_F(ManifestBrowserTest, Navigation) {
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+ {
+ GURL test_url =
+ embedded_test_server()->GetURL("/manifest/dummy-manifest.html");
+
+ TestNavigationObserver navigation_observer(shell()->web_contents(), 1);
+ shell()->LoadURL(test_url);
+ navigation_observer.Wait();
+
+ GetManifestAndWait();
+ EXPECT_FALSE(manifest().IsEmpty());
+ EXPECT_EQ(0u, console_error_count());
+ }
+
+ {
+ GURL test_url =
+ embedded_test_server()->GetURL("/manifest/no-manifest.html");
+
+ TestNavigationObserver navigation_observer(shell()->web_contents(), 1);
+ shell()->LoadURL(test_url);
+ navigation_observer.Wait();
+
+ GetManifestAndWait();
+ EXPECT_TRUE(manifest().IsEmpty());
+ EXPECT_EQ(0u, console_error_count());
+ }
+}
+
+// If a page has a manifest and the page is navigated using pushState (ie. same
+// page), it should keep its manifest state.
+IN_PROC_BROWSER_TEST_F(ManifestBrowserTest, PushStateNavigation) {
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+ GURL test_url =
+ embedded_test_server()->GetURL("/manifest/dummy-manifest.html");
+
+ {
+ TestNavigationObserver navigation_observer(shell()->web_contents(), 1);
+ shell()->LoadURL(test_url);
+ navigation_observer.Wait();
+ }
+
+ {
+ TestNavigationObserver navigation_observer(shell()->web_contents(), 1);
+ ASSERT_TRUE(content::ExecuteScript(
+ shell()->web_contents(),
+ "history.pushState({foo: \"bar\"}, 'page', 'page.html');"));
+ navigation_observer.Wait();
+ }
+
+ GetManifestAndWait();
+ EXPECT_FALSE(manifest().IsEmpty());
+ EXPECT_EQ(0u, console_error_count());
+}
+
+// If a page has a manifest and is navigated using an anchor (ie. same page), it
+// should keep its manifest state.
+IN_PROC_BROWSER_TEST_F(ManifestBrowserTest, AnchorNavigation) {
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+ GURL test_url =
+ embedded_test_server()->GetURL("/manifest/dummy-manifest.html");
+
+ {
+ TestNavigationObserver navigation_observer(shell()->web_contents(), 1);
+ shell()->LoadURL(test_url);
+ navigation_observer.Wait();
+ }
+
+ {
+ TestNavigationObserver navigation_observer(shell()->web_contents(), 1);
+ ASSERT_TRUE(content::ExecuteScript(
+ shell()->web_contents(),
+ "var a = document.createElement('a'); a.href='#foo';"
+ "document.body.appendChild(a); a.click();"));
+ navigation_observer.Wait();
+ }
+
+ GetManifestAndWait();
+ EXPECT_FALSE(manifest().IsEmpty());
+ EXPECT_EQ(0u, console_error_count());
}
} // namespace content
diff --git a/chromium/content/browser/manifest/manifest_manager_host.cc b/chromium/content/browser/manifest/manifest_manager_host.cc
index 50b3ecade66..c22ae0ad46a 100644
--- a/chromium/content/browser/manifest/manifest_manager_host.cc
+++ b/chromium/content/browser/manifest/manifest_manager_host.cc
@@ -4,6 +4,7 @@
#include "content/browser/manifest/manifest_manager_host.h"
+#include "base/stl_util.h"
#include "content/common/manifest_manager_messages.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
@@ -19,7 +20,8 @@ void KillRenderer(RenderFrameHost* render_frame_host) {
render_frame_host->GetProcess()->GetHandle();
if (process_handle == base::kNullProcessHandle)
return;
- base::KillProcess(process_handle, RESULT_CODE_KILLED_BAD_MESSAGE, false);
+ render_frame_host->GetProcess()->Shutdown(RESULT_CODE_KILLED_BAD_MESSAGE,
+ false);
}
} // anonymous namespace
@@ -29,6 +31,7 @@ ManifestManagerHost::ManifestManagerHost(WebContents* web_contents)
}
ManifestManagerHost::~ManifestManagerHost() {
+ STLDeleteValues(&pending_callbacks_);
}
ManifestManagerHost::CallbackMap* ManifestManagerHost::GetCallbackMapForFrame(
@@ -114,18 +117,25 @@ void ManifestManagerHost::OnRequestManifestResponse(
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());
+ for (auto& icon : manifest.icons) {
+ if (!icon.src.is_valid())
+ icon.src = GURL();
+ icon.type = base::NullableString16(
+ icon.type.string().substr(0, Manifest::kMaxIPCStringLength),
+ icon.type.is_null());
}
manifest.gcm_sender_id = base::NullableString16(
manifest.gcm_sender_id.string().substr(
0, Manifest::kMaxIPCStringLength),
manifest.gcm_sender_id.is_null());
+ for (auto& related_application : manifest.related_applications) {
+ if (!related_application.url.is_valid())
+ related_application.url = GURL();
+ related_application.id =
+ base::NullableString16(related_application.id.string().substr(
+ 0, Manifest::kMaxIPCStringLength),
+ related_application.id.is_null());
+ }
callback->Run(manifest);
callbacks->Remove(request_id);
diff --git a/chromium/content/browser/manifest/manifest_manager_host.h b/chromium/content/browser/manifest/manifest_manager_host.h
index aea980f0ba6..5e932df155a 100644
--- a/chromium/content/browser/manifest/manifest_manager_host.h
+++ b/chromium/content/browser/manifest/manifest_manager_host.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_RENDERER_MANIFEST_MANIFEST_MANAGER_HOST_H_
-#define CONTENT_RENDERER_MANIFEST_MANIFEST_MANAGER_HOST_H_
+#ifndef CONTENT_BROWSER_MANIFEST_MANIFEST_MANAGER_HOST_H_
+#define CONTENT_BROWSER_MANIFEST_MANIFEST_MANAGER_HOST_H_
#include "base/callback_forward.h"
#include "base/id_map.h"
@@ -51,4 +51,4 @@ class ManifestManagerHost : public WebContentsObserver {
} // namespace content
-#endif // CONTENT_RENDERER_MANIFEST_MANIFEST_MANAGER_HOST_H_
+#endif // CONTENT_BROWSER_MANIFEST_MANIFEST_MANAGER_HOST_H_
diff --git a/chromium/content/browser/media/OWNERS b/chromium/content/browser/media/OWNERS
index 2e3d17b05b9..6b25ab065f0 100644
--- a/chromium/content/browser/media/OWNERS
+++ b/chromium/content/browser/media/OWNERS
@@ -1,18 +1,16 @@
dalecurtis@chromium.org
ddorwin@chromium.org
-perkj@chromium.org
scherkus@chromium.org
-tommi@chromium.org
-vrk@chromium.org
xhwang@chromium.org
-xians@chromium.org
-per-file cast_*=hclam@chromium.org
-per-file cast_*=hubbe@chromium.org
-per-file cast_*=mikhal@chromium.org
-per-file cast_*=pwestin@google.com
+# WebRTC OWNERS.
+perkj@chromium.org
+tommi@chromium.org
per-file midi_*=toyoshim@chromium.org
# For changes related to the tab media indicators.
per-file audio_stream_monitor*=miu@chromium.org
+
+# For WebRTC browser tests, etc.
+per-file *webrtc*browsertest*=phoglund@chromium.org
diff --git a/chromium/content/browser/media/android/browser_demuxer_android.cc b/chromium/content/browser/media/android/browser_demuxer_android.cc
index a0cf7f7d738..ddaca7efa3c 100644
--- a/chromium/content/browser/media/android/browser_demuxer_android.cc
+++ b/chromium/content/browser/media/android/browser_demuxer_android.cc
@@ -4,7 +4,10 @@
#include "content/browser/media/android/browser_demuxer_android.h"
+#include "base/command_line.h"
#include "content/common/media/media_player_messages_android.h"
+#include "media/base/android/media_codec_player.h"
+#include "media/base/media_switches.h"
namespace content {
@@ -15,26 +18,25 @@ class BrowserDemuxerAndroid::Internal : public media::DemuxerAndroid {
: demuxer_(demuxer),
demuxer_client_id_(demuxer_client_id) {}
- virtual ~Internal() {
+ ~Internal() override {
DCHECK(ClientIDExists()) << demuxer_client_id_;
demuxer_->RemoveDemuxerClient(demuxer_client_id_);
}
// media::DemuxerAndroid implementation.
- virtual void Initialize(media::DemuxerAndroidClient* client) override {
+ 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 {
+ void RequestDemuxerData(media::DemuxerStream::Type type) override {
DCHECK(ClientIDExists()) << demuxer_client_id_;
demuxer_->Send(new MediaPlayerMsg_ReadFromDemuxer(
demuxer_client_id_, type));
}
- virtual void RequestDemuxerSeek(
- const base::TimeDelta& time_to_seek,
- bool is_browser_seek) override {
+ void RequestDemuxerSeek(const base::TimeDelta& time_to_seek,
+ bool is_browser_seek) override {
DCHECK(ClientIDExists()) << demuxer_client_id_;
demuxer_->Send(new MediaPlayerMsg_DemuxerSeekRequest(
demuxer_client_id_, time_to_seek, is_browser_seek));
@@ -53,21 +55,32 @@ class BrowserDemuxerAndroid::Internal : public media::DemuxerAndroid {
};
BrowserDemuxerAndroid::BrowserDemuxerAndroid()
- : BrowserMessageFilter(MediaPlayerMsgStart) {}
+ : BrowserMessageFilter(MediaPlayerMsgStart) {
+ bool enable_media_thread =
+ base::CommandLine::ForCurrentProcess()->
+ HasSwitch(switches::kEnableMediaThreadForMediaPlayback);
+
+ task_runner_ =
+ enable_media_thread ?
+ media::GetMediaTaskRunner().get() :
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI).get();
+
+}
BrowserDemuxerAndroid::~BrowserDemuxerAndroid() {}
-void BrowserDemuxerAndroid::OverrideThreadForMessage(
- const IPC::Message& message,
- BrowserThread::ID* thread) {
+base::TaskRunner* BrowserDemuxerAndroid::OverrideTaskRunnerForMessage(
+ const IPC::Message& message) {
+
switch (message.type()) {
case MediaPlayerHostMsg_DemuxerReady::ID:
case MediaPlayerHostMsg_ReadFromDemuxerAck::ID:
case MediaPlayerHostMsg_DurationChanged::ID:
case MediaPlayerHostMsg_DemuxerSeekDone::ID:
- *thread = BrowserThread::UI;
- return;
+ return task_runner_;
}
+
+ return nullptr;
}
bool BrowserDemuxerAndroid::OnMessageReceived(const IPC::Message& message) {
@@ -96,29 +109,46 @@ void BrowserDemuxerAndroid::AddDemuxerClient(
media::DemuxerAndroidClient* client) {
DVLOG(1) << __FUNCTION__ << " peer_pid=" << peer_pid()
<< " demuxer_client_id=" << demuxer_client_id;
+ DCHECK(task_runner_->BelongsToCurrentThread());
+
demuxer_clients_.AddWithID(client, demuxer_client_id);
+
+ if (pending_configs_.count(demuxer_client_id)) {
+ client->OnDemuxerConfigsAvailable(pending_configs_[demuxer_client_id]);
+ pending_configs_.erase(demuxer_client_id);
+ }
}
void BrowserDemuxerAndroid::RemoveDemuxerClient(int demuxer_client_id) {
DVLOG(1) << __FUNCTION__ << " peer_pid=" << peer_pid()
<< " demuxer_client_id=" << demuxer_client_id;
+ DCHECK(task_runner_->BelongsToCurrentThread());
+
demuxer_clients_.Remove(demuxer_client_id);
}
void BrowserDemuxerAndroid::OnDemuxerReady(
int demuxer_client_id,
const media::DemuxerConfigs& configs) {
+ DCHECK(task_runner_->BelongsToCurrentThread());
+
media::DemuxerAndroidClient* client =
demuxer_clients_.Lookup(demuxer_client_id);
+
if (client)
client->OnDemuxerConfigsAvailable(configs);
+ else
+ pending_configs_[demuxer_client_id] = configs;
}
void BrowserDemuxerAndroid::OnReadFromDemuxerAck(
int demuxer_client_id,
const media::DemuxerData& data) {
+ DCHECK(task_runner_->BelongsToCurrentThread());
+
media::DemuxerAndroidClient* client =
demuxer_clients_.Lookup(demuxer_client_id);
+
if (client)
client->OnDemuxerDataAvailable(data);
}
@@ -126,18 +156,26 @@ void BrowserDemuxerAndroid::OnReadFromDemuxerAck(
void BrowserDemuxerAndroid::OnDemuxerSeekDone(
int demuxer_client_id,
const base::TimeDelta& actual_browser_seek_time) {
+ DCHECK(task_runner_->BelongsToCurrentThread());
+
media::DemuxerAndroidClient* client =
demuxer_clients_.Lookup(demuxer_client_id);
+
if (client)
client->OnDemuxerSeekDone(actual_browser_seek_time);
}
void BrowserDemuxerAndroid::OnDurationChanged(int demuxer_client_id,
const base::TimeDelta& duration) {
+ DCHECK(task_runner_->BelongsToCurrentThread());
+
media::DemuxerAndroidClient* client =
demuxer_clients_.Lookup(demuxer_client_id);
+
if (client)
client->OnDemuxerDurationChanged(duration);
+ else
+ pending_configs_[demuxer_client_id].duration = duration;
}
} // namespace content
diff --git a/chromium/content/browser/media/android/browser_demuxer_android.h b/chromium/content/browser/media/android/browser_demuxer_android.h
index 1e7f799e68a..71ebd7f30b4 100644
--- a/chromium/content/browser/media/android/browser_demuxer_android.h
+++ b/chromium/content/browser/media/android/browser_demuxer_android.h
@@ -5,6 +5,8 @@
#ifndef CONTENT_BROWSER_MEDIA_ANDROID_BROWSER_DEMUXER_ANDROID_H_
#define CONTENT_BROWSER_MEDIA_ANDROID_BROWSER_DEMUXER_ANDROID_H_
+#include <map>
+
#include "base/id_map.h"
#include "content/public/browser/browser_message_filter.h"
#include "media/base/android/demuxer_android.h"
@@ -21,9 +23,10 @@ class CONTENT_EXPORT BrowserDemuxerAndroid : public BrowserMessageFilter {
BrowserDemuxerAndroid();
// BrowserMessageFilter overrides.
- virtual void OverrideThreadForMessage(const IPC::Message& message,
- BrowserThread::ID* thread) override;
- virtual bool OnMessageReceived(const IPC::Message& message) override;
+ base::TaskRunner* OverrideTaskRunnerForMessage(
+ const IPC::Message& message) override;
+
+ 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
@@ -32,7 +35,7 @@ class CONTENT_EXPORT BrowserDemuxerAndroid : public BrowserMessageFilter {
protected:
friend class base::RefCountedThreadSafe<BrowserDemuxerAndroid>;
- virtual ~BrowserDemuxerAndroid();
+ ~BrowserDemuxerAndroid() override;
private:
class Internal;
@@ -55,6 +58,15 @@ class CONTENT_EXPORT BrowserDemuxerAndroid : public BrowserMessageFilter {
IDMap<media::DemuxerAndroidClient> demuxer_clients_;
+ // When the demuxer client is created on UI thread but demuxer
+ // messages arrive on Media thread their relative order is undefined.
+ // Use |pending_configs_| map to keep the upcoming configurations
+ // until the client is created.
+ typedef std::map<int, media::DemuxerConfigs> ConfigsPerClient;
+ ConfigsPerClient pending_configs_;
+
+ base::SingleThreadTaskRunner* task_runner_;
+
DISALLOW_COPY_AND_ASSIGN(BrowserDemuxerAndroid);
};
diff --git a/chromium/content/browser/media/android/browser_media_player_manager.cc b/chromium/content/browser/media/android/browser_media_player_manager.cc
index b8016b471f4..68268f7406d 100644
--- a/chromium/content/browser/media/android/browser_media_player_manager.cc
+++ b/chromium/content/browser/media/android/browser_media_player_manager.cc
@@ -7,6 +7,7 @@
#include "base/android/scoped_java_ref.h"
#include "base/command_line.h"
#include "content/browser/android/content_view_core_impl.h"
+#include "content/browser/android/media_players_observer.h"
#include "content/browser/media/android/browser_demuxer_android.h"
#include "content/browser/media/android/media_resource_getter_impl.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
@@ -24,11 +25,13 @@
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_switches.h"
+#include "media/base/android/media_codec_player.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::MediaCodecPlayer;
using media::MediaPlayerAndroid;
using media::MediaPlayerBridge;
using media::MediaPlayerManager;
@@ -39,13 +42,19 @@ namespace content {
// Threshold on the number of media players per renderer before we start
// attempting to release inactive media players.
const int kMediaPlayerThreshold = 1;
+const int kInvalidMediaPlayerId = -1;
static BrowserMediaPlayerManager::Factory g_factory = NULL;
static media::MediaUrlInterceptor* media_url_interceptor_ = NULL;
// static
void BrowserMediaPlayerManager::RegisterFactory(Factory factory) {
- g_factory = factory;
+ // TODO(aberent) nullptr test is a temporary fix to simplify upstreaming Cast.
+ // Until Cast is fully upstreamed we want the downstream factory to take
+ // priority over the upstream factory. The downstream call happens first,
+ // so this will ensure that it does.
+ if (g_factory == nullptr)
+ g_factory = factory;
}
// static
@@ -56,13 +65,14 @@ void BrowserMediaPlayerManager::RegisterMediaUrlInterceptor(
// static
BrowserMediaPlayerManager* BrowserMediaPlayerManager::Create(
- RenderFrameHost* rfh) {
+ RenderFrameHost* rfh,
+ MediaPlayersObserver* audio_monitor) {
if (g_factory)
- return g_factory(rfh);
- return new BrowserMediaPlayerManager(rfh);
+ return g_factory(rfh, audio_monitor);
+ return new BrowserMediaPlayerManager(rfh, audio_monitor);
}
-ContentViewCoreImpl* BrowserMediaPlayerManager::GetContentViewCore() const {
+ContentViewCore* BrowserMediaPlayerManager::GetContentViewCore() const {
return ContentViewCoreImpl::FromWebContents(web_contents());
}
@@ -105,13 +115,24 @@ MediaPlayerAndroid* BrowserMediaPlayerManager::CreateMediaPlayer(
}
case MEDIA_PLAYER_TYPE_MEDIA_SOURCE: {
- return new MediaSourcePlayer(
- media_player_params.player_id,
- manager,
- base::Bind(&BrowserMediaPlayerManager::OnMediaResourcesRequested,
- weak_ptr_factory_.GetWeakPtr()),
- demuxer->CreateDemuxer(media_player_params.demuxer_client_id),
- media_player_params.frame_url);
+ if (base::CommandLine::ForCurrentProcess()->
+ HasSwitch(switches::kEnableMediaThreadForMediaPlayback)) {
+ return new MediaCodecPlayer(
+ media_player_params.player_id,
+ manager,
+ base::Bind(&BrowserMediaPlayerManager::OnMediaResourcesRequested,
+ weak_ptr_factory_.GetWeakPtr()),
+ demuxer->CreateDemuxer(media_player_params.demuxer_client_id),
+ media_player_params.frame_url);
+ } else {
+ return new MediaSourcePlayer(
+ media_player_params.player_id,
+ manager,
+ base::Bind(&BrowserMediaPlayerManager::OnMediaResourcesRequested,
+ weak_ptr_factory_.GetWeakPtr()),
+ demuxer->CreateDemuxer(media_player_params.demuxer_client_id),
+ media_player_params.frame_url);
+ }
}
}
@@ -120,9 +141,11 @@ MediaPlayerAndroid* BrowserMediaPlayerManager::CreateMediaPlayer(
}
BrowserMediaPlayerManager::BrowserMediaPlayerManager(
- RenderFrameHost* render_frame_host)
+ RenderFrameHost* render_frame_host,
+ MediaPlayersObserver* audio_monitor)
: render_frame_host_(render_frame_host),
- fullscreen_player_id_(-1),
+ audio_monitor_(audio_monitor),
+ fullscreen_player_id_(kInvalidMediaPlayerId),
fullscreen_player_is_released_(false),
web_contents_(WebContents::FromRenderFrameHost(render_frame_host)),
weak_ptr_factory_(this) {
@@ -133,44 +156,16 @@ BrowserMediaPlayerManager::~BrowserMediaPlayerManager() {
// (e.g. the WebContents may be destroyed before the render process). So
// we cannot DCHECK(players_.empty()) here. Instead, all media players in
// |players_| will be destroyed here because |player_| is a ScopedVector.
-}
-void BrowserMediaPlayerManager::FullscreenPlayerPlay() {
- MediaPlayerAndroid* player = GetFullscreenPlayer();
- if (player) {
- if (fullscreen_player_is_released_) {
- video_view_->OpenVideo();
- fullscreen_player_is_released_ = false;
- }
- player->Start();
- Send(new MediaPlayerMsg_DidMediaPlayerPlay(RoutingID(),
- fullscreen_player_id_));
- }
-}
+ for (MediaPlayerAndroid* player : players_)
+ player->DeleteOnCorrectThread();
-void BrowserMediaPlayerManager::FullscreenPlayerPause() {
- MediaPlayerAndroid* player = GetFullscreenPlayer();
- if (player) {
- player->Pause(true);
- Send(new MediaPlayerMsg_DidMediaPlayerPause(RoutingID(),
- fullscreen_player_id_));
- }
-}
-
-void BrowserMediaPlayerManager::FullscreenPlayerSeek(int msec) {
- MediaPlayerAndroid* player = GetFullscreenPlayer();
- if (player) {
- // TODO(kbalazs): if |fullscreen_player_is_released_| is true
- // at this point, player->GetCurrentTime() will be wrong until
- // FullscreenPlayerPlay (http://crbug.com/322798).
- OnSeekRequest(fullscreen_player_id_,
- base::TimeDelta::FromMilliseconds(msec));
- }
+ players_.weak_clear();
}
void BrowserMediaPlayerManager::ExitFullscreen(bool release_media_player) {
if (WebContentsDelegate* delegate = web_contents_->GetDelegate())
- delegate->ToggleFullscreenModeForTab(web_contents_, false);
+ delegate->ExitFullscreenModeForTab(web_contents_);
if (RenderWidgetHostViewAndroid* view_android =
static_cast<RenderWidgetHostViewAndroid*>(
web_contents_->GetRenderWidgetHostView())) {
@@ -181,9 +176,15 @@ void BrowserMediaPlayerManager::ExitFullscreen(bool release_media_player) {
new MediaPlayerMsg_DidExitFullscreen(RoutingID(), fullscreen_player_id_));
video_view_.reset();
MediaPlayerAndroid* player = GetFullscreenPlayer();
- fullscreen_player_id_ = -1;
+ fullscreen_player_id_ = kInvalidMediaPlayerId;
if (!player)
return;
+
+#if defined(VIDEO_HOLE)
+ if (external_video_surface_container_)
+ external_video_surface_container_->OnFrameInfoUpdated();
+#endif // defined(VIDEO_HOLE)
+
if (release_media_player)
ReleaseFullscreenPlayer(player);
else
@@ -209,7 +210,6 @@ void BrowserMediaPlayerManager::SetVideoSurface(
if (empty_surface)
return;
- Send(new MediaPlayerMsg_DidEnterFullscreen(RoutingID(), player->player_id()));
if (RenderWidgetHostViewAndroid* view_android =
static_cast<RenderWidgetHostViewAndroid*>(
web_contents_->GetRenderWidgetHostView())) {
@@ -281,6 +281,16 @@ void BrowserMediaPlayerManager::OnVideoSizeChanged(
video_view_->OnVideoSizeChanged(width, height);
}
+void BrowserMediaPlayerManager::OnAudibleStateChanged(
+ int player_id, bool is_audible) {
+ audio_monitor_->OnAudibleStateChanged(
+ render_frame_host_, player_id, is_audible);
+}
+
+void BrowserMediaPlayerManager::OnWaitingForDecryptionKey(int player_id) {
+ Send(new MediaPlayerMsg_WaitingForDecryptionKey(RoutingID(), player_id));
+}
+
media::MediaResourceGetter*
BrowserMediaPlayerManager::GetMediaResourceGetter() {
if (!media_resource_getter_.get()) {
@@ -322,7 +332,7 @@ void BrowserMediaPlayerManager::RequestFullScreen(int player_id) {
if (fullscreen_player_id_ == player_id)
return;
- if (fullscreen_player_id_ != -1) {
+ if (fullscreen_player_id_ != kInvalidMediaPlayerId) {
// TODO(qinmin): Determine the correct error code we should report to WMPA.
OnError(player_id, MediaPlayerAndroid::MEDIA_ERROR_DECODE);
return;
@@ -332,12 +342,6 @@ void BrowserMediaPlayerManager::RequestFullScreen(int player_id) {
}
#if defined(VIDEO_HOLE)
-bool
-BrowserMediaPlayerManager::ShouldUseVideoOverlayForEmbeddedEncryptedVideo() {
- RendererPreferences* prefs = web_contents_->GetMutableRendererPrefs();
- return prefs->use_video_overlay_for_embedded_encrypted_video;
-}
-
void BrowserMediaPlayerManager::AttachExternalVideoSurface(int player_id,
jobject surface) {
MediaPlayerAndroid* player = GetPlayer(player_id);
@@ -354,6 +358,9 @@ void BrowserMediaPlayerManager::DetachExternalVideoSurface(int player_id) {
}
void BrowserMediaPlayerManager::OnFrameInfoUpdated() {
+ if (fullscreen_player_id_ != kInvalidMediaPlayerId)
+ return;
+
if (external_video_surface_container_)
external_video_surface_container_->OnFrameInfoUpdated();
}
@@ -372,6 +379,20 @@ void BrowserMediaPlayerManager::OnNotifyExternalSurface(
}
}
+void BrowserMediaPlayerManager::ReleasePlayerOfExternalVideoSurfaceIfNeeded(
+ int future_player) {
+ int current_player = ExternalVideoSurfaceContainer::kInvalidPlayerId;
+
+ if (external_video_surface_container_)
+ current_player = external_video_surface_container_->GetCurrentPlayerId();
+
+ if (current_player == ExternalVideoSurfaceContainer::kInvalidPlayerId)
+ return;
+
+ if (current_player != future_player)
+ OnMediaInterrupted(current_player);
+}
+
void BrowserMediaPlayerManager::OnRequestExternalSurface(
int player_id, const gfx::RectF& rect) {
if (!external_video_surface_container_) {
@@ -382,6 +403,8 @@ void BrowserMediaPlayerManager::OnRequestExternalSurface(
// It's safe to use base::Unretained(this), because the callbacks will not
// be called after running ReleaseExternalVideoSurface().
if (external_video_surface_container_) {
+ // In case we're stealing the external surface from another player.
+ ReleasePlayerOfExternalVideoSurfaceIfNeeded(player_id);
external_video_surface_container_->RequestExternalVideoSurface(
player_id,
base::Bind(&BrowserMediaPlayerManager::AttachExternalVideoSurface,
@@ -393,8 +416,11 @@ void BrowserMediaPlayerManager::OnRequestExternalSurface(
#endif // defined(VIDEO_HOLE)
void BrowserMediaPlayerManager::OnEnterFullscreen(int player_id) {
- DCHECK_EQ(fullscreen_player_id_, -1);
+ DCHECK_EQ(fullscreen_player_id_, kInvalidMediaPlayerId);
#if defined(VIDEO_HOLE)
+ // If this fullscreen player is started when another player
+ // uses the external surface, release that other player.
+ ReleasePlayerOfExternalVideoSurfaceIfNeeded(player_id);
if (external_video_surface_container_)
external_video_surface_container_->ReleaseExternalVideoSurface(player_id);
#endif // defined(VIDEO_HOLE)
@@ -415,10 +441,6 @@ void BrowserMediaPlayerManager::OnEnterFullscreen(int player_id) {
}
// Force the second video to exit fullscreen.
- // TODO(qinmin): There is no need to send DidEnterFullscreen message.
- // However, if we don't send the message, page layers will not be
- // correctly restored. http:crbug.com/367346.
- Send(new MediaPlayerMsg_DidEnterFullscreen(RoutingID(), player_id));
Send(new MediaPlayerMsg_DidExitFullscreen(RoutingID(), player_id));
video_view_.reset();
}
@@ -504,7 +526,7 @@ void BrowserMediaPlayerManager::OnReleaseResources(int player_id) {
void BrowserMediaPlayerManager::OnDestroyPlayer(int player_id) {
RemovePlayer(player_id);
if (fullscreen_player_id_ == player_id)
- fullscreen_player_id_ = -1;
+ fullscreen_player_id_ = kInvalidMediaPlayerId;
}
void BrowserMediaPlayerManager::OnRequestRemotePlayback(int /* player_id */) {
@@ -526,7 +548,9 @@ void BrowserMediaPlayerManager::RemovePlayer(int player_id) {
it != players_.end(); ++it) {
if ((*it)->player_id() == player_id) {
ReleaseMediaResources(player_id);
- players_.erase(it);
+ (*it)->DeleteOnCorrectThread();
+ players_.weak_erase(it);
+ audio_monitor_->RemovePlayer(render_frame_host_, player_id);
break;
}
}
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 36506cd8241..a1ef3ff46c5 100644
--- a/chromium/content/browser/media/android/browser_media_player_manager.h
+++ b/chromium/content/browser/media/android/browser_media_player_manager.h
@@ -13,11 +13,12 @@
#include "content/browser/android/content_video_view.h"
#include "content/common/content_export.h"
#include "content/common/media/media_player_messages_enums_android.h"
+#include "content/public/browser/android/content_view_core.h"
#include "ipc/ipc_message.h"
#include "media/base/android/media_player_android.h"
#include "media/base/android/media_player_manager.h"
#include "media/base/android/media_url_interceptor.h"
-#include "ui/gfx/rect_f.h"
+#include "ui/gfx/geometry/rect_f.h"
#include "url/gurl.h"
namespace media {
@@ -30,6 +31,7 @@ namespace content {
class BrowserDemuxerAndroid;
class ContentViewCoreImpl;
class ExternalVideoSurfaceContainer;
+class MediaPlayersObserver;
class RenderFrameHost;
class WebContents;
@@ -42,7 +44,8 @@ class CONTENT_EXPORT BrowserMediaPlayerManager
: public media::MediaPlayerManager {
public:
// Permits embedders to provide an extended version of the class.
- typedef BrowserMediaPlayerManager* (*Factory)(RenderFrameHost*);
+ typedef BrowserMediaPlayerManager* (*Factory)(RenderFrameHost*,
+ MediaPlayersObserver*);
static void RegisterFactory(Factory factory);
// Permits embedders to handle custom urls.
@@ -50,16 +53,15 @@ class CONTENT_EXPORT BrowserMediaPlayerManager
media::MediaUrlInterceptor* media_url_interceptor);
// Returns a new instance using the registered factory if available.
- static BrowserMediaPlayerManager* Create(RenderFrameHost* rfh);
+ static BrowserMediaPlayerManager* Create(
+ RenderFrameHost* rfh,
+ MediaPlayersObserver* audio_monitor);
- ContentViewCoreImpl* GetContentViewCore() const;
+ ContentViewCore* GetContentViewCore() const;
- virtual ~BrowserMediaPlayerManager();
+ ~BrowserMediaPlayerManager() override;
// Fullscreen video playback controls.
- virtual void FullscreenPlayerPlay();
- virtual void FullscreenPlayerPause();
- virtual void FullscreenPlayerSeek(int msec);
virtual void ExitFullscreen(bool release_media_player);
virtual void SetVideoSurface(gfx::ScopedJavaSurface surface);
@@ -71,33 +73,31 @@ class CONTENT_EXPORT BrowserMediaPlayerManager
void ReleaseAllMediaPlayers();
// media::MediaPlayerManager overrides.
- virtual void OnTimeUpdate(
- 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;
- virtual void OnSeekComplete(
- int player_id,
- 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::MediaUrlInterceptor* GetMediaUrlInterceptor() override;
- virtual media::MediaPlayerAndroid* GetFullscreenPlayer() override;
- virtual media::MediaPlayerAndroid* GetPlayer(int player_id) override;
- virtual void RequestFullScreen(int player_id) override;
+ void OnTimeUpdate(int player_id,
+ base::TimeDelta current_timestamp,
+ base::TimeTicks current_time_ticks) override;
+ void OnMediaMetadataChanged(int player_id,
+ base::TimeDelta duration,
+ int width,
+ int height,
+ bool success) override;
+ void OnPlaybackComplete(int player_id) override;
+ void OnMediaInterrupted(int player_id) override;
+ void OnBufferingUpdate(int player_id, int percentage) override;
+ void OnSeekComplete(int player_id,
+ const base::TimeDelta& current_time) override;
+ void OnError(int player_id, int error) override;
+ void OnVideoSizeChanged(int player_id, int width, int height) override;
+ void OnAudibleStateChanged(
+ int player_id, bool is_audible_now) override;
+ void OnWaitingForDecryptionKey(int player_id) override;
+
+ media::MediaResourceGetter* GetMediaResourceGetter() override;
+ media::MediaUrlInterceptor* GetMediaUrlInterceptor() override;
+ media::MediaPlayerAndroid* GetFullscreenPlayer() override;
+ media::MediaPlayerAndroid* GetPlayer(int player_id) override;
+ void RequestFullScreen(int player_id) override;
#if defined(VIDEO_HOLE)
- virtual bool ShouldUseVideoOverlayForEmbeddedEncryptedVideo() override;
-
void AttachExternalVideoSurface(int player_id, jobject surface);
void DetachExternalVideoSurface(int player_id);
void OnFrameInfoUpdated();
@@ -125,7 +125,8 @@ class CONTENT_EXPORT BrowserMediaPlayerManager
protected:
// Clients must use Create() or subclass constructor.
- explicit BrowserMediaPlayerManager(RenderFrameHost* render_frame_host);
+ BrowserMediaPlayerManager(RenderFrameHost* render_frame_host,
+ MediaPlayersObserver* audio_monitor);
WebContents* web_contents() const { return web_contents_; }
@@ -169,11 +170,14 @@ class CONTENT_EXPORT BrowserMediaPlayerManager
void ReleasePlayer(media::MediaPlayerAndroid* player);
#if defined(VIDEO_HOLE)
+ void ReleasePlayerOfExternalVideoSurfaceIfNeeded(int future_player);
void OnRequestExternalSurface(int player_id, const gfx::RectF& rect);
#endif // defined(VIDEO_HOLE)
RenderFrameHost* const render_frame_host_;
+ MediaPlayersObserver* audio_monitor_;
+
// An array of managed players.
ScopedVector<media::MediaPlayerAndroid> players_;
diff --git a/chromium/content/browser/media/android/media_drm_credential_manager.cc b/chromium/content/browser/media/android/media_drm_credential_manager.cc
index 23c6cf2cecd..50d66538db8 100644
--- a/chromium/content/browser/media/android/media_drm_credential_manager.cc
+++ b/chromium/content/browser/media/android/media_drm_credential_manager.cc
@@ -9,7 +9,8 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/location.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
#include "jni/MediaDrmCredentialManager_jni.h"
#include "media/base/android/media_drm_bridge.h"
#include "url/gurl.h"
@@ -87,10 +88,11 @@ void MediaDrmCredentialManager::OnResetCredentialsCompleted(
media_drm_bridge_.reset();
}
+// TODO(ddorwin): The key system should be passed in. http://crbug.com/459400
bool MediaDrmCredentialManager::ResetCredentialsInternal(
SecurityLevel security_level) {
media_drm_bridge_ =
- media::MediaDrmBridge::CreateSessionless(kWidevineKeySystem);
+ media::MediaDrmBridge::CreateWithoutSessionSupport(kWidevineKeySystem);
if (!media_drm_bridge_)
return false;
@@ -100,7 +102,7 @@ bool MediaDrmCredentialManager::ResetCredentialsInternal(
if (!media_drm_bridge_->SetSecurityLevel(security_level)) {
// No need to reset credentials for unsupported |security_level|.
- base::MessageLoopProxy::current()->PostTask(
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(reset_credentials_cb, true));
return true;
}
diff --git a/chromium/content/browser/media/android/media_drm_credential_manager.h b/chromium/content/browser/media/android/media_drm_credential_manager.h
index f2cb0fa1fe7..cf16cea9528 100644
--- a/chromium/content/browser/media/android/media_drm_credential_manager.h
+++ b/chromium/content/browser/media/android/media_drm_credential_manager.h
@@ -22,6 +22,10 @@ class MediaDrmCredentialManager {
typedef base::Callback<void(bool)> ResetCredentialsCB;
// Called to reset the DRM credentials. (for Java)
+ // Only clears credentials for Widevine.
+ // TODO(ddorwin): This should accept a key system parameter so that this is
+ // clear to the caller, which can call it repeatedly as necessary.
+ // http://crbug.com/459400
static void ResetCredentials(JNIEnv* env, jclass clazz, jobject callback);
// Called to reset the DRM credentials. The result is returned in the
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 686e01c331c..457748414af 100644
--- a/chromium/content/browser/media/android/media_resource_getter_impl.cc
+++ b/chromium/content/browser/media/android/media_resource_getter_impl.cc
@@ -28,6 +28,8 @@
#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_data_item.h"
+#include "storage/browser/blob/blob_data_snapshot.h"
#include "storage/browser/blob/blob_storage_context.h"
#include "url/gurl.h"
@@ -47,7 +49,7 @@ static void RequestPlatformPathFromBlobURL(
const GURL& url,
ResourceContext* resource_context,
const base::Callback<void(const std::string&)>& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
ChromeBlobStorageContext* blob_storage_context =
GetChromeBlobStorageContextForResourceContext(resource_context);
@@ -59,18 +61,19 @@ static void RequestPlatformPathFromBlobURL(
ReturnResultOnUIThread(callback, std::string());
return;
}
- storage::BlobData* data = handle->data();
+ scoped_ptr<storage::BlobDataSnapshot> data = handle->CreateSnapshot();
if (!data) {
ReturnResultOnUIThread(callback, std::string());
NOTREACHED();
return;
}
- const std::vector<storage::BlobData::Item> items = data->items();
+ const std::vector<scoped_refptr<storage::BlobDataItem>>& items =
+ data->items();
// TODO(qinmin): handle the case when the blob data is not a single file.
DLOG_IF(WARNING, items.size() != 1u)
- << "More than one blob data are present: " << items.size();
- ReturnResultOnUIThread(callback, items[0].path().value());
+ << "More than one blob item is present: " << items.size();
+ ReturnResultOnUIThread(callback, items[0]->path().value());
}
static void RequestPlaformPathFromFileSystemURL(
@@ -78,7 +81,7 @@ static void RequestPlaformPathFromFileSystemURL(
int render_process_id,
scoped_refptr<storage::FileSystemContext> file_system_context,
const base::Callback<void(const std::string&)>& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
base::FilePath platform_path;
SyncGetPlatformPath(file_system_context.get(),
render_process_id,
@@ -197,7 +200,7 @@ MediaResourceGetterTask::~MediaResourceGetterTask() {}
net::AuthCredentials MediaResourceGetterTask::RequestAuthCredentials(
const GURL& url) const {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
net::HttpTransactionFactory* factory =
context_getter_->GetURLRequestContext()->http_transaction_factory();
if (!factory)
@@ -221,7 +224,7 @@ net::AuthCredentials MediaResourceGetterTask::RequestAuthCredentials(
void MediaResourceGetterTask::RequestCookies(
const GURL& url, const GURL& first_party_for_cookies,
const media::MediaResourceGetter::GetCookieCB& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
ChildProcessSecurityPolicyImpl* policy =
ChildProcessSecurityPolicyImpl::GetInstance();
if (!policy->CanAccessCookiesForOrigin(render_process_id_, url)) {
@@ -250,7 +253,7 @@ void MediaResourceGetterTask::CheckPolicyForCookies(
const GURL& url, const GURL& first_party_for_cookies,
const media::MediaResourceGetter::GetCookieCB& callback,
const net::CookieList& cookie_list) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (GetContentClient()->browser()->AllowGetCookie(
url, first_party_for_cookies, cookie_list,
resource_context_, render_process_id_, render_frame_id_)) {
@@ -280,7 +283,7 @@ MediaResourceGetterImpl::~MediaResourceGetterImpl() {}
void MediaResourceGetterImpl::GetAuthCredentials(
const GURL& url, const GetAuthCredentialsCB& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
scoped_refptr<MediaResourceGetterTask> task = new MediaResourceGetterTask(
browser_context_, 0, 0);
@@ -295,7 +298,7 @@ void MediaResourceGetterImpl::GetAuthCredentials(
void MediaResourceGetterImpl::GetCookies(
const GURL& url, const GURL& first_party_for_cookies,
const GetCookieCB& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
scoped_refptr<MediaResourceGetterTask> task = new MediaResourceGetterTask(
browser_context_, render_process_id_, render_frame_id_);
@@ -313,19 +316,19 @@ void MediaResourceGetterImpl::GetCookies(
void MediaResourceGetterImpl::GetAuthCredentialsCallback(
const GetAuthCredentialsCB& callback,
const net::AuthCredentials& credentials) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
callback.Run(credentials.username(), credentials.password());
}
void MediaResourceGetterImpl::GetCookiesCallback(
const GetCookieCB& callback, const std::string& cookies) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
callback.Run(cookies);
}
void MediaResourceGetterImpl::GetPlatformPathFromURL(
const GURL& url, const GetPlatformPathCB& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(url.SchemeIsFileSystem() || url.SchemeIs(url::kBlobScheme));
GetPlatformPathCB cb =
@@ -352,14 +355,14 @@ void MediaResourceGetterImpl::GetPlatformPathFromURL(
void MediaResourceGetterImpl::GetPlatformPathCallback(
const GetPlatformPathCB& callback, const std::string& platform_path) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
callback.Run(platform_path);
}
void MediaResourceGetterImpl::ExtractMediaMetadata(
const std::string& url, const std::string& cookies,
const std::string& user_agent, const ExtractMediaMetadataCB& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
base::SequencedWorkerPool* pool = content::BrowserThread::GetBlockingPool();
pool->PostWorkerTask(
FROM_HERE,
@@ -369,7 +372,7 @@ void MediaResourceGetterImpl::ExtractMediaMetadata(
void MediaResourceGetterImpl::ExtractMediaMetadata(
const int fd, const int64 offset, const int64 size,
const ExtractMediaMetadataCB& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
base::SequencedWorkerPool* pool = content::BrowserThread::GetBlockingPool();
pool->PostWorkerTask(
FROM_HERE,
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 4f0d2e81af8..9a55fcb7c2c 100644
--- a/chromium/content/browser/media/android/media_resource_getter_impl.h
+++ b/chromium/content/browser/media/android/media_resource_getter_impl.h
@@ -40,30 +40,25 @@ class MediaResourceGetterImpl : public media::MediaResourceGetter {
storage::FileSystemContext* file_system_context,
int render_process_id,
int render_frame_id);
- virtual ~MediaResourceGetterImpl();
+ ~MediaResourceGetterImpl() override;
// media::MediaResourceGetter implementation.
// Must be called on the UI thread.
- 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;
- virtual void ExtractMediaMetadata(
- const std::string& url,
- const std::string& cookies,
- const std::string& user_agent,
- const ExtractMediaMetadataCB& callback) override;
- virtual void ExtractMediaMetadata(
- const int fd,
- const int64 offset,
- const int64 size,
- const ExtractMediaMetadataCB& callback) override;
+ void GetAuthCredentials(const GURL& url,
+ const GetAuthCredentialsCB& callback) override;
+ void GetCookies(const GURL& url,
+ const GURL& first_party_for_cookies,
+ const GetCookieCB& callback) override;
+ void GetPlatformPathFromURL(const GURL& url,
+ const GetPlatformPathCB& callback) override;
+ void ExtractMediaMetadata(const std::string& url,
+ const std::string& cookies,
+ const std::string& user_agent,
+ const ExtractMediaMetadataCB& callback) override;
+ void ExtractMediaMetadata(const int fd,
+ const int64 offset,
+ const int64 size,
+ const ExtractMediaMetadataCB& callback) override;
static bool RegisterMediaResourceGetter(JNIEnv* env);
diff --git a/chromium/content/browser/media/audio_state_provider.cc b/chromium/content/browser/media/audio_state_provider.cc
new file mode 100644
index 00000000000..e09356a561f
--- /dev/null
+++ b/chromium/content/browser/media/audio_state_provider.cc
@@ -0,0 +1,30 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/media/audio_state_provider.h"
+
+#include "base/logging.h"
+#include "content/browser/media/audio_stream_monitor.h"
+#include "content/public/browser/web_contents.h"
+
+namespace content {
+
+AudioStateProvider::AudioStateProvider(WebContents* contents)
+ : web_contents_(contents),
+ was_recently_audible_(false) {
+ DCHECK(web_contents_);
+}
+
+bool AudioStateProvider::WasRecentlyAudible() const {
+ return was_recently_audible_;
+}
+
+void AudioStateProvider::Notify(bool new_state) {
+ if (was_recently_audible_ != new_state) {
+ was_recently_audible_ = new_state;
+ web_contents_->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB);
+ }
+}
+
+} // namespace content
diff --git a/chromium/content/browser/media/audio_state_provider.h b/chromium/content/browser/media/audio_state_provider.h
new file mode 100644
index 00000000000..5bd1b7189aa
--- /dev/null
+++ b/chromium/content/browser/media/audio_state_provider.h
@@ -0,0 +1,57 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_MEDIA_AUDIO_STATE_PROVIDER_H_
+#define CONTENT_BROWSER_MEDIA_AUDIO_STATE_PROVIDER_H_
+
+#include "content/common/content_export.h"
+
+namespace content {
+class WebContents;
+class AudioStreamMonitor;
+
+// This class is associated with a WebContents, and maintains the audible
+// state regarding all the players in it.
+// The audible state is true if at least one player is playing a sound.
+// Whenever the audible state of the WebContents as a whole changes, this
+// class sends a notification to it.
+//
+// Each WebContentsImpl owns an AudioStateProvider
+class CONTENT_EXPORT AudioStateProvider {
+ public:
+ explicit AudioStateProvider(WebContents* web_contents);
+ virtual ~AudioStateProvider() {}
+
+ // Indicates whether this service is available on the system.
+ virtual bool IsAudioStateAvailable() const = 0;
+
+ // If this provider uses monitoring (i.e. measure the signal),
+ // return its monitor.
+ virtual AudioStreamMonitor* audio_stream_monitor() = 0;
+
+ // Returns true if the WebContents is playing or has recently been
+ // playing the sound.
+ virtual bool WasRecentlyAudible() const;
+
+ void set_was_recently_audible_for_testing(bool value) {
+ was_recently_audible_ = value;
+ }
+
+ protected:
+ // Notify WebContents that the audio state has changed.
+ void Notify(bool new_state);
+
+ // The WebContents instance instance to receive indicator toggle
+ // notifications. This pointer should be valid for the lifetime of
+ // AudioStreamMonitor.
+ WebContents* const web_contents_;
+
+ // The audio state that is being maintained
+ bool was_recently_audible_;
+
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_MEDIA_AUDIO_STATE_PROVIDER_H_
diff --git a/chromium/content/browser/media/audio_stream_monitor.cc b/chromium/content/browser/media/audio_stream_monitor.cc
index 1d2f76f7f2c..bcc1e7649b9 100644
--- a/chromium/content/browser/media/audio_stream_monitor.cc
+++ b/chromium/content/browser/media/audio_stream_monitor.cc
@@ -21,23 +21,36 @@ AudioStreamMonitor* AudioStreamMonitorFromRenderFrame(int render_process_id,
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;
+
+ if (!web_contents)
+ return nullptr;
+
+ AudioStateProvider* audio_provider = web_contents->audio_state_provider();
+ return audio_provider ? audio_provider->audio_stream_monitor() : nullptr;
}
} // namespace
AudioStreamMonitor::AudioStreamMonitor(WebContents* contents)
- : web_contents_(contents),
- clock_(&default_tick_clock_),
- was_recently_audible_(false) {
- DCHECK(web_contents_);
+ : AudioStateProvider(contents),
+ clock_(&default_tick_clock_)
+{
}
AudioStreamMonitor::~AudioStreamMonitor() {}
+bool AudioStreamMonitor::IsAudioStateAvailable() const {
+ return media::AudioOutputController::will_monitor_audio_levels();
+}
+
+// This provider is the monitor.
+AudioStreamMonitor* AudioStreamMonitor::audio_stream_monitor() {
+ return this;
+}
+
bool AudioStreamMonitor::WasRecentlyAudible() const {
DCHECK(thread_checker_.CalledOnValidThread());
- return was_recently_audible_;
+ return AudioStateProvider::WasRecentlyAudible();
}
// static
@@ -46,7 +59,7 @@ void AudioStreamMonitor::StartMonitoringStream(
int render_frame_id,
int stream_id,
const ReadPowerAndClipCallback& read_power_callback) {
- if (!monitoring_available())
+ if (!media::AudioOutputController::will_monitor_audio_levels())
return;
BrowserThread::PostTask(BrowserThread::UI,
FROM_HERE,
@@ -61,7 +74,7 @@ void AudioStreamMonitor::StartMonitoringStream(
void AudioStreamMonitor::StopMonitoringStream(int render_process_id,
int render_frame_id,
int stream_id) {
- if (!monitoring_available())
+ if (!media::AudioOutputController::will_monitor_audio_levels())
return;
BrowserThread::PostTask(BrowserThread::UI,
FROM_HERE,
@@ -107,7 +120,8 @@ void AudioStreamMonitor::StartMonitoringStreamOnUIThread(
if (!poll_timer_.IsRunning()) {
poll_timer_.Start(
FROM_HERE,
- base::TimeDelta::FromSeconds(1) / kPowerMeasurementsPerSecond,
+ base::TimeDelta::FromSeconds(1) /
+ static_cast<int>(kPowerMeasurementsPerSecond),
base::Bind(&AudioStreamMonitor::Poll, base::Unretained(this)));
}
}
@@ -138,16 +152,12 @@ void AudioStreamMonitor::Poll() {
}
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);
- }
+ Notify(should_indicator_be_on);
if (!should_indicator_be_on) {
off_timer_.Stop();
diff --git a/chromium/content/browser/media/audio_stream_monitor.h b/chromium/content/browser/media/audio_stream_monitor.h
index d1a32d5f857..b3cbf16f4d3 100644
--- a/chromium/content/browser/media/audio_stream_monitor.h
+++ b/chromium/content/browser/media/audio_stream_monitor.h
@@ -14,6 +14,7 @@
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "build/build_config.h"
+#include "content/browser/media/audio_state_provider.h"
#include "content/common/content_export.h"
#include "media/audio/audio_output_controller.h"
@@ -22,7 +23,6 @@ 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
@@ -32,23 +32,23 @@ class WebContents;
// 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 {
+class CONTENT_EXPORT AudioStreamMonitor : public AudioStateProvider {
public:
explicit AudioStreamMonitor(WebContents* contents);
- ~AudioStreamMonitor();
+ ~AudioStreamMonitor() override;
// 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();
- }
+ bool IsAudioStateAvailable() const override;
+
+ // This provider is a monitor, the method returns |this|.
+ AudioStreamMonitor* audio_stream_monitor() override;
// 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;
+ bool WasRecentlyAudible() const override;
// Starts or stops audio level monitoring respectively for the stream owned by
// the specified renderer. Safe to call from any thread.
@@ -66,10 +66,6 @@ class CONTENT_EXPORT AudioStreamMonitor {
int render_frame_id,
int stream_id);
- void set_was_recently_audible_for_testing(bool value) {
- was_recently_audible_ = value;
- }
-
private:
friend class AudioStreamMonitorTest;
@@ -112,11 +108,6 @@ class CONTENT_EXPORT AudioStreamMonitor {
// 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_;
@@ -134,10 +125,6 @@ class CONTENT_EXPORT AudioStreamMonitor {
// 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_;
diff --git a/chromium/content/browser/media/audio_stream_monitor_unittest.cc b/chromium/content/browser/media/audio_stream_monitor_unittest.cc
index 2b36d877bcc..786775dec67 100644
--- a/chromium/content/browser/media/audio_stream_monitor_unittest.cc
+++ b/chromium/content/browser/media/audio_stream_monitor_unittest.cc
@@ -34,7 +34,7 @@ const int kAnotherStreamId = 6;
class MockWebContentsDelegate : public WebContentsDelegate {
public:
MOCK_METHOD2(NavigationStateChanged,
- void(const WebContents* source, InvalidateTypes changed_flags));
+ void(WebContents* source, InvalidateTypes changed_flags));
};
} // namespace
@@ -52,7 +52,13 @@ class AudioStreamMonitorTest : public RenderViewHostTestHarness {
WebContentsImpl* web_contents = reinterpret_cast<WebContentsImpl*>(
RenderViewHostTestHarness::web_contents());
web_contents->SetDelegate(&mock_web_contents_delegate_);
- monitor_ = web_contents->audio_stream_monitor();
+
+ AudioStateProvider* provider = web_contents->audio_state_provider();
+ ASSERT_TRUE(provider);
+
+ monitor_ = provider->audio_stream_monitor();
+ ASSERT_TRUE(monitor_);
+
const_cast<base::TickClock*&>(monitor_->clock_) = &clock_;
}
@@ -106,7 +112,7 @@ class AudioStreamMonitorTest : public RenderViewHostTestHarness {
static base::TimeDelta one_polling_interval() {
return base::TimeDelta::FromSeconds(1) /
- AudioStreamMonitor::kPowerMeasurementsPerSecond;
+ static_cast<int>(AudioStreamMonitor::kPowerMeasurementsPerSecond);
}
static base::TimeDelta holding_period() {
diff --git a/chromium/content/browser/media/capture/OWNERS b/chromium/content/browser/media/capture/OWNERS
index 063a202ff2d..b877289b762 100644
--- a/chromium/content/browser/media/capture/OWNERS
+++ b/chromium/content/browser/media/capture/OWNERS
@@ -1,4 +1,3 @@
-hclam@chromium.org
miu@chromium.org
sergeyu@chromium.org
wez@chromium.org
diff --git a/chromium/content/browser/media/capture/animated_content_sampler.cc b/chromium/content/browser/media/capture/animated_content_sampler.cc
new file mode 100644
index 00000000000..8727e762ed7
--- /dev/null
+++ b/chromium/content/browser/media/capture/animated_content_sampler.cc
@@ -0,0 +1,293 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/media/capture/animated_content_sampler.h"
+
+#include <algorithm>
+
+namespace content {
+
+namespace {
+
+// 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 = 2000;
+
+} // anonymous namespace
+
+AnimatedContentSampler::AnimatedContentSampler(
+ base::TimeDelta min_capture_period)
+ : min_capture_period_(min_capture_period),
+ sampling_state_(NOT_SAMPLING) {
+ DCHECK_GT(min_capture_period_, base::TimeDelta());
+}
+
+AnimatedContentSampler::~AnimatedContentSampler() {}
+
+void AnimatedContentSampler::SetTargetSamplingPeriod(base::TimeDelta period) {
+ target_sampling_period_ = period;
+}
+
+void AnimatedContentSampler::ConsiderPresentationEvent(
+ const gfx::Rect& damage_rect, base::TimeTicks event_time) {
+ // Analyze the current event and recent history to determine whether animating
+ // content is detected.
+ AddObservation(damage_rect, event_time);
+ if (!AnalyzeObservations(event_time, &detected_region_, &detected_period_) ||
+ detected_period_ <= base::TimeDelta() ||
+ detected_period_ >
+ base::TimeDelta::FromMicroseconds(kMaxLockInPeriodMicros)) {
+ // Animated content not detected.
+ detected_region_ = gfx::Rect();
+ detected_period_ = base::TimeDelta();
+ sampling_state_ = NOT_SAMPLING;
+ return;
+ }
+
+ // At this point, animation is being detected. Update the sampling period
+ // since the client may call the accessor method even if the heuristics below
+ // decide not to sample the current event.
+ sampling_period_ = ComputeSamplingPeriod(detected_period_,
+ target_sampling_period_,
+ min_capture_period_);
+
+ // If this is the first event causing animating content to be detected,
+ // transition to the START_SAMPLING state.
+ if (sampling_state_ == NOT_SAMPLING)
+ sampling_state_ = START_SAMPLING;
+
+ // If the current event does not represent a frame that is part of the
+ // animation, do not sample.
+ if (damage_rect != detected_region_) {
+ if (sampling_state_ == SHOULD_SAMPLE)
+ sampling_state_ = SHOULD_NOT_SAMPLE;
+ return;
+ }
+
+ // When starting sampling, determine where to sync-up for sampling and frame
+ // timestamp rewriting. Otherwise, just add one animation period's worth of
+ // tokens to the token bucket.
+ if (sampling_state_ == START_SAMPLING) {
+ if (event_time - frame_timestamp_ > sampling_period_) {
+ // The frame timestamp sequence should start with the current event
+ // time.
+ frame_timestamp_ = event_time - sampling_period_;
+ token_bucket_ = sampling_period_;
+ } else {
+ // The frame timestamp sequence will continue from the last recorded
+ // frame timestamp.
+ token_bucket_ = event_time - frame_timestamp_;
+ }
+
+ // Provide a little extra in the initial token bucket so that minor error in
+ // the detected period won't prevent a reasonably-timed event from being
+ // sampled.
+ token_bucket_ += detected_period_ / 2;
+ } else {
+ token_bucket_ += detected_period_;
+ }
+
+ // If the token bucket is full enough, take tokens from it and propose
+ // sampling. Otherwise, do not sample.
+ DCHECK_LE(detected_period_, sampling_period_);
+ if (token_bucket_ >= sampling_period_) {
+ token_bucket_ -= sampling_period_;
+ frame_timestamp_ = ComputeNextFrameTimestamp(event_time);
+ sampling_state_ = SHOULD_SAMPLE;
+ } else {
+ sampling_state_ = SHOULD_NOT_SAMPLE;
+ }
+}
+
+bool AnimatedContentSampler::HasProposal() const {
+ return sampling_state_ != NOT_SAMPLING;
+}
+
+bool AnimatedContentSampler::ShouldSample() const {
+ return sampling_state_ == SHOULD_SAMPLE;
+}
+
+void AnimatedContentSampler::RecordSample(base::TimeTicks frame_timestamp) {
+ if (sampling_state_ == NOT_SAMPLING)
+ frame_timestamp_ = frame_timestamp;
+ else if (sampling_state_ == SHOULD_SAMPLE)
+ sampling_state_ = SHOULD_NOT_SAMPLE;
+}
+
+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;
+}
+
+base::TimeTicks AnimatedContentSampler::ComputeNextFrameTimestamp(
+ base::TimeTicks event_time) const {
+ // The ideal next frame timestamp one sampling period since the last one.
+ const base::TimeTicks ideal_timestamp = frame_timestamp_ + sampling_period_;
+
+ // Account 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.
+ //
+ // TODO(miu): This is similar to the ClockSmoother in
+ // media/base/audio_shifter.cc. Consider refactor-and-reuse here.
+ const base::TimeDelta drift = ideal_timestamp - event_time;
+ const int64 correct_over_num_frames =
+ base::TimeDelta::FromMilliseconds(kDriftCorrectionMillis) /
+ sampling_period_;
+ DCHECK_GT(correct_over_num_frames, 0);
+
+ return ideal_timestamp - drift / correct_over_num_frames;
+}
+
+// static
+base::TimeDelta AnimatedContentSampler::ComputeSamplingPeriod(
+ base::TimeDelta animation_period,
+ base::TimeDelta target_sampling_period,
+ base::TimeDelta min_capture_period) {
+ // If the animation rate is unknown, return the ideal sampling period.
+ if (animation_period == base::TimeDelta()) {
+ return std::max(target_sampling_period, min_capture_period);
+ }
+
+ // Determine whether subsampling is needed. If so, compute the sampling
+ // period corresponding to the sampling rate is the closest integer division
+ // of the animation frame rate to the target sampling rate.
+ //
+ // For example, consider a target sampling rate of 30 FPS and an animation
+ // rate of 42 FPS. Possible sampling rates would be 42/1 = 42, 42/2 = 21,
+ // 42/3 = 14, and so on. Of these candidates, 21 FPS is closest to 30.
+ base::TimeDelta sampling_period;
+ if (animation_period < target_sampling_period) {
+ const int64 ratio = target_sampling_period / animation_period;
+ const double target_fps = 1.0 / target_sampling_period.InSecondsF();
+ const double animation_fps = 1.0 / animation_period.InSecondsF();
+ if (std::abs(animation_fps / ratio - target_fps) <
+ std::abs(animation_fps / (ratio + 1) - target_fps)) {
+ sampling_period = ratio * animation_period;
+ } else {
+ sampling_period = (ratio + 1) * animation_period;
+ }
+ } else {
+ sampling_period = animation_period;
+ }
+ return std::max(sampling_period, min_capture_period);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/media/capture/animated_content_sampler.h b/chromium/content/browser/media/capture/animated_content_sampler.h
new file mode 100644
index 00000000000..e11ba767de4
--- /dev/null
+++ b/chromium/content/browser/media/capture/animated_content_sampler.h
@@ -0,0 +1,157 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_MEDIA_CAPTURE_ANIMATED_CONTENT_SAMPLER_H_
+#define CONTENT_BROWSER_MEDIA_CAPTURE_ANIMATED_CONTENT_SAMPLER_H_
+
+#include <deque>
+
+#include "base/time/time.h"
+#include "content/common/content_export.h"
+#include "ui/gfx/geometry/rect.h"
+
+namespace content {
+
+// 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();
+
+ // Get/Set the target sampling period. This is used to determine whether to
+ // subsample the frames of animated content.
+ base::TimeDelta target_sampling_period() const {
+ return target_sampling_period_;
+ }
+ void SetTargetSamplingPeriod(base::TimeDelta period);
+
+ // 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 ShouldSample() returns true.
+ base::TimeTicks frame_timestamp() const { return frame_timestamp_; }
+
+ // Returns the current sampling period. This can be treated as the estimated
+ // duration of the frame to be sampled. Only valid when HasProposal()
+ // returns true.
+ base::TimeDelta sampling_period() const { return sampling_period_; }
+
+ // 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_|.
+ base::TimeTicks ComputeNextFrameTimestamp(base::TimeTicks event_time) const;
+
+ // When the animation frame rate is greater than the target sampling rate,
+ // this function determines an integer division of the animation frame rate
+ // that is closest to the target sampling rate. Returns the inverse of that
+ // result (the period). If the animation frame rate is slower or the same as
+ // the target sampling rate, this function just returns |animation_period|.
+ static base::TimeDelta ComputeSamplingPeriod(
+ base::TimeDelta animation_period,
+ base::TimeDelta target_sampling_period,
+ base::TimeDelta min_capture_period);
+
+ // 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_;
+
+ // Target period between sampled frames. This can be changed by the client at
+ // any time (e.g., to sample high frame rate content at a lower rate).
+ base::TimeDelta target_sampling_period_;
+
+ // The sampling period computed during the last call to
+ // ConsiderPresentationEvent().
+ base::TimeDelta sampling_period_;
+
+ // Indicates whether the last event caused animated content to be detected and
+ // whether the current event should be sampled.
+ enum {
+ NOT_SAMPLING,
+ START_SAMPLING,
+ SHOULD_NOT_SAMPLE,
+ SHOULD_SAMPLE
+ } sampling_state_;
+
+ // A token bucket that is used to decide which subset of the frames containing
+ // the animated content should be sampled. Here, the smallest discrete unit
+ // of time (one microsecond) equals one token; and, tokens are only taken from
+ // the bucket when at least a full sampling period's worth are present.
+ base::TimeDelta token_bucket_;
+
+ // The rewritten frame timestamp for the latest event.
+ base::TimeTicks frame_timestamp_;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_MEDIA_CAPTURE_ANIMATED_CONTENT_SAMPLER_H_
diff --git a/chromium/content/browser/media/capture/animated_content_sampler_unittest.cc b/chromium/content/browser/media/capture/animated_content_sampler_unittest.cc
new file mode 100644
index 00000000000..710f4336330
--- /dev/null
+++ b/chromium/content/browser/media/capture/animated_content_sampler_unittest.cc
@@ -0,0 +1,818 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/media/capture/animated_content_sampler.h"
+
+#include <cmath>
+#include <utility>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/rect.h"
+
+namespace content {
+
+namespace {
+
+base::TimeTicks InitialTestTimeTicks() {
+ return base::TimeTicks() + base::TimeDelta::FromSeconds(1);
+}
+
+base::TimeDelta FpsAsPeriod(int frame_rate) {
+ return base::TimeDelta::FromSeconds(1) / frame_rate;
+}
+
+} // namespace
+
+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();
+ }
+
+ static base::TimeDelta ComputeSamplingPeriod(
+ base::TimeDelta detected_period,
+ base::TimeDelta target_sampling_period,
+ base::TimeDelta min_capture_period) {
+ return AnimatedContentSampler::ComputeSamplingPeriod(
+ detected_period, target_sampling_period, min_capture_period);
+ }
+
+ 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());
+}
+
+TEST_F(AnimatedContentSamplerTest, TargetsSamplingPeriod) {
+ struct Helper {
+ static void RunTargetSamplingPeriodTest(int target_fps) {
+ const base::TimeDelta min_capture_period = FpsAsPeriod(60);
+ const base::TimeDelta target_sampling_period = FpsAsPeriod(target_fps);
+
+ for (int content_fps = 1; content_fps <= 60; ++content_fps) {
+ const base::TimeDelta content_period = FpsAsPeriod(content_fps);
+ const base::TimeDelta sampling_period =
+ ComputeSamplingPeriod(content_period,
+ target_sampling_period,
+ min_capture_period);
+ if (content_period >= target_sampling_period) {
+ ASSERT_EQ(content_period, sampling_period);
+ } else {
+ ASSERT_LE(min_capture_period, sampling_period);
+
+ // Check that the sampling rate is as close (or closer) to the target
+ // sampling rate than any integer-subsampling of the content frame
+ // rate.
+ const double absolute_diff =
+ std::abs(1.0 / sampling_period.InSecondsF() - target_fps);
+ const double fudge_for_acceptable_rounding_error = 0.005;
+ for (double divisor = 1; divisor < 4; ++divisor) {
+ SCOPED_TRACE(::testing::Message() << "target_fps=" << target_fps
+ << ", content_fps=" << content_fps
+ << ", divisor=" << divisor);
+ ASSERT_GE(std::abs(content_fps / divisor - target_fps),
+ absolute_diff - fudge_for_acceptable_rounding_error);
+ }
+ }
+ }
+ }
+ };
+
+ for (int target_fps = 1; target_fps <= 60; ++target_fps)
+ Helper::RunTargetSamplingPeriodTest(target_fps);
+}
+
+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.
+ base::TimeDelta target_sampling_period;
+
+ Scenario(int compositor_frequency,
+ int max_frame_rate,
+ int content_frame_rate)
+ : vsync_interval(FpsAsPeriod(compositor_frequency)),
+ min_capture_period(FpsAsPeriod(max_frame_rate)),
+ content_period(FpsAsPeriod(content_frame_rate)) {
+ CHECK(content_period >= vsync_interval)
+ << "Bad test params: Impossible to animate faster than the compositor.";
+ }
+
+ Scenario(int compositor_frequency,
+ int max_frame_rate,
+ int content_frame_rate,
+ int target_sampling_rate)
+ : vsync_interval(FpsAsPeriod(compositor_frequency)),
+ min_capture_period(FpsAsPeriod(max_frame_rate)),
+ content_period(FpsAsPeriod(content_frame_rate)),
+ target_sampling_period(FpsAsPeriod(target_sampling_rate)) {
+ 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()
+ << " }";
+}
+
+} // namespace
+
+class AnimatedContentSamplerParameterizedTest
+ : public AnimatedContentSamplerTest,
+ public ::testing::WithParamInterface<Scenario> {
+ public:
+ AnimatedContentSamplerParameterizedTest()
+ : count_dropped_frames_(0), count_sampled_frames_(0) {}
+ virtual ~AnimatedContentSamplerParameterizedTest() {}
+
+ void SetUp() override {
+ AnimatedContentSamplerTest::SetUp();
+ sampler()->SetTargetSamplingPeriod(GetParam().target_sampling_period);
+ }
+
+ protected:
+ typedef std::pair<gfx::Rect, base::TimeTicks> Event;
+
+ base::TimeDelta GetMinCapturePeriod() const override {
+ return GetParam().min_capture_period;
+ }
+
+ base::TimeDelta ComputeExpectedSamplingPeriod() const {
+ return AnimatedContentSamplerTest::ComputeSamplingPeriod(
+ GetParam().content_period,
+ GetParam().target_sampling_period,
+ 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,
+ base::TimeTicks* next_begin_time) {
+ DCHECK(GetParam().content_period >= GetParam().vsync_interval);
+ base::TimeTicks next_content_time = begin;
+ std::vector<Event> events;
+ base::TimeTicks compositor_time;
+ for (compositor_time = begin; compositor_time < end;
+ compositor_time += GetParam().vsync_interval) {
+ if (next_content_time <= compositor_time) {
+ next_content_time += GetParam().content_period;
+ if (include_content_frame_events) {
+ events.push_back(Event(GetContentDamageRect(), compositor_time));
+ continue;
+ }
+ }
+ if (include_random_events && GetRandomInRange(0, 1) == 0) {
+ events.push_back(Event(GetRandomDamageRect(), compositor_time));
+ }
+ }
+
+ if (next_begin_time) {
+ while (compositor_time < next_content_time)
+ compositor_time += GetParam().vsync_interval;
+ *next_begin_time = 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,
+ const char* description) {
+ SCOPED_TRACE(::testing::Message() << "Description: " << description);
+
+ gfx::Rect first_detected_region;
+
+ EXPECT_EQ(was_detecting_before, sampler()->HasProposal());
+ bool has_detection_switched = false;
+ bool has_detection_flip_flopped_once = 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. It is permissible for the lock-in
+ // to flip-flop once, but no more than that.
+ if (!has_detection_switched &&
+ was_detecting_before != sampler()->HasProposal()) {
+ has_detection_switched = true;
+ } else if (has_detection_switched &&
+ is_detecting_after != sampler()->HasProposal()) {
+ ASSERT_FALSE(has_detection_flip_flopped_once);
+ has_detection_flip_flopped_once = true;
+ has_detection_switched = false;
+ }
+ 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 expected_sampling_ratio =
+ GetParam().content_period.InSecondsF() /
+ ComputeExpectedSamplingPeriod().InSecondsF();
+ const int total_frames = count_dropped_frames_ + count_sampled_frames_;
+ EXPECT_NEAR(total_frames * expected_sampling_ratio,
+ count_sampled_frames_,
+ 1.5);
+ EXPECT_NEAR(total_frames * (1.0 - expected_sampling_ratio),
+ count_dropped_frames_,
+ 1.5);
+ }
+
+ 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.
+ RunEventSequence(
+ GenerateEventSequence(begin,
+ begin + base::TimeDelta::FromSeconds(5),
+ false,
+ true,
+ &begin),
+ false,
+ false,
+ false,
+ "Provide random events and expect no lock-in.");
+ if (HasFailure())
+ return;
+
+ // Provide content frame events with some random events mixed-in, and expect
+ // the sampler to lock-in.
+ RunEventSequence(
+ GenerateEventSequence(begin,
+ begin + base::TimeDelta::FromSeconds(5),
+ true,
+ true,
+ &begin),
+ false,
+ true,
+ false,
+ "Provide content frame events with some random events mixed-in, and "
+ "expect the sampler to lock-in.");
+ if (HasFailure())
+ return;
+
+ // Continue providing content frame events without the random events mixed-in
+ // and expect the lock-in to hold.
+ RunEventSequence(
+ GenerateEventSequence(begin,
+ begin + base::TimeDelta::FromSeconds(5),
+ true,
+ false,
+ &begin),
+ true,
+ true,
+ false,
+ "Continue providing content frame events without the random events "
+ "mixed-in and expect the lock-in to hold.");
+ if (HasFailure())
+ return;
+
+ // Continue providing just content frame events and expect the lock-in to
+ // hold. Also simulate the capture pipeline experiencing back pressure.
+ RunEventSequence(
+ GenerateEventSequence(begin,
+ begin + base::TimeDelta::FromSeconds(20),
+ true,
+ false,
+ &begin),
+ true,
+ true,
+ true,
+ "Continue providing just content frame events and expect the lock-in to "
+ "hold. Also simulate the capture pipeline experiencing back pressure.");
+ if (HasFailure())
+ return;
+
+
+ // Provide a half-second of random events only, and expect the lock-in to be
+ // broken.
+ RunEventSequence(
+ GenerateEventSequence(begin,
+ begin + base::TimeDelta::FromMilliseconds(500),
+ false,
+ true,
+ &begin),
+ true,
+ false,
+ false,
+ "Provide a half-second of random events only, and expect the lock-in to "
+ "be broken.");
+ if (HasFailure())
+ return;
+
+ // Now, go back to providing content frame events, and expect the sampler to
+ // lock-in once again.
+ RunEventSequence(
+ GenerateEventSequence(begin,
+ begin + base::TimeDelta::FromSeconds(5),
+ true,
+ false,
+ &begin),
+ false,
+ true,
+ false,
+ "Now, go back to providing content frame events, and expect the sampler "
+ "to lock-in once again.");
+}
+
+// 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();
+ RunEventSequence(
+ GenerateEventSequence(begin,
+ begin + base::TimeDelta::FromSeconds(5),
+ true,
+ false,
+ &begin),
+ false,
+ true,
+ false,
+ "Start the first animation and run for a bit, and expect the sampler to "
+ "lock-in.");
+ if (HasFailure())
+ return;
+
+ // Now, keep the first animation and blend in a 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.
+ std::vector<Event> first_animation_events =
+ GenerateEventSequence(begin,
+ begin + base::TimeDelta::FromSeconds(20),
+ true,
+ false,
+ &begin);
+ 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,
+ "Now, blend-in a second animation of the same size and frame rate, but "
+ "at a different position.");
+ if (HasFailure())
+ return;
+
+ // Now, run just the first animation, and expect the sampler to lock-in once
+ // again.
+ RunEventSequence(
+ GenerateEventSequence(begin,
+ begin + base::TimeDelta::FromSeconds(5),
+ true,
+ false,
+ &begin),
+ false,
+ true,
+ false,
+ "Now, run just the first animation, and expect the sampler to lock-in "
+ "once again.");
+ if (HasFailure())
+ return;
+
+ // 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.
+ first_animation_events =
+ GenerateEventSequence(begin,
+ begin + base::TimeDelta::FromSeconds(20),
+ true,
+ false,
+ &begin);
+ 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,
+ "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.");
+}
+
+// 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.
+ const base::TimeTicks begin = InitialTestTimeTicks();
+ std::vector<Event> events = GenerateEventSequence(
+ begin,
+ begin + base::TimeDelta::FromSeconds(20),
+ true,
+ false,
+ nullptr);
+ 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 +
+ ComputeExpectedSamplingPeriod() / 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 (second_highest_count > 0 &&
+ 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();
+ std::vector<Event> events =
+ GenerateEventSequence(begin,
+ begin + base::TimeDelta::FromMinutes(1),
+ true,
+ false,
+ nullptr);
+
+ // 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(60, 30, 30),
+ Scenario(60, 30, 25),
+ Scenario(60, 30, 24),
+
+ // High frame rate content that leverages the Compositor's
+ // capabilities, but capture is still at 30 Hz.
+ Scenario(60, 30, 60),
+ Scenario(60, 30, 50),
+ Scenario(60, 30, 48),
+
+ // High frame rate content that leverages the Compositor's
+ // capabilities, and capture is also a buttery 60 Hz.
+ Scenario(60, 60, 60),
+ Scenario(60, 60, 50),
+ Scenario(60, 60, 48),
+
+ // High frame rate content that leverages the Compositor's
+ // capabilities, but the client has disabled HFR sampling.
+ Scenario(60, 60, 60, 30),
+ Scenario(60, 60, 50, 30),
+ Scenario(60, 60, 48, 30),
+
+ // On some platforms, the Compositor runs at 50 Hz.
+ Scenario(50, 30, 30),
+ Scenario(50, 30, 25),
+ Scenario(50, 30, 24),
+ Scenario(50, 30, 50),
+ Scenario(50, 30, 48),
+
+ // Stable, but non-standard content frame rates.
+ Scenario(60, 30, 16),
+ Scenario(60, 30, 20),
+ Scenario(60, 30, 23),
+ Scenario(60, 30, 26),
+ Scenario(60, 30, 27),
+ Scenario(60, 30, 28),
+ Scenario(60, 30, 29),
+ Scenario(60, 30, 31),
+ Scenario(60, 30, 32),
+ Scenario(60, 30, 33)));
+
+} // namespace content
diff --git a/chromium/content/browser/media/capture/aura_window_capture_machine.cc b/chromium/content/browser/media/capture/aura_window_capture_machine.cc
new file mode 100644
index 00000000000..411736f5df5
--- /dev/null
+++ b/chromium/content/browser/media/capture/aura_window_capture_machine.cc
@@ -0,0 +1,449 @@
+// 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/media/capture/aura_window_capture_machine.h"
+
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "base/timer/timer.h"
+#include "cc/output/copy_output_request.h"
+#include "cc/output/copy_output_result.h"
+#include "content/browser/compositor/image_transport_factory.h"
+#include "content/browser/media/capture/content_video_capture_device_core.h"
+#include "content/browser/media/capture/desktop_capture_device_uma_types.h"
+#include "content/common/gpu/client/gl_helper.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/power_save_blocker.h"
+#include "media/base/video_capture_types.h"
+#include "media/base/video_util.h"
+#include "skia/ext/image_operations.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/aura/client/screen_position_client.h"
+#include "ui/aura/env.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_observer.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/base/cursor/cursors_aura.h"
+#include "ui/compositor/compositor.h"
+#include "ui/compositor/dip_util.h"
+#include "ui/compositor/layer.h"
+#include "ui/gfx/screen.h"
+
+namespace content {
+
+namespace {
+
+int clip_byte(int x) {
+ return std::max(0, std::min(x, 255));
+}
+
+int alpha_blend(int alpha, int src, int dst) {
+ return (src * alpha + dst * (255 - alpha)) / 255;
+}
+
+// Helper function to composite a cursor bitmap on a YUV420 video frame.
+void RenderCursorOnVideoFrame(
+ const scoped_refptr<media::VideoFrame>& target,
+ const SkBitmap& cursor_bitmap,
+ const gfx::Point& cursor_position) {
+ DCHECK(target.get());
+ DCHECK(!cursor_bitmap.isNull());
+
+ gfx::Rect rect = gfx::IntersectRects(
+ gfx::Rect(cursor_bitmap.width(), cursor_bitmap.height()) +
+ gfx::Vector2d(cursor_position.x(), cursor_position.y()),
+ target->visible_rect());
+
+ cursor_bitmap.lockPixels();
+ for (int y = rect.y(); y < rect.bottom(); ++y) {
+ int cursor_y = y - cursor_position.y();
+ uint8* yplane = target->data(media::VideoFrame::kYPlane) +
+ y * target->row_bytes(media::VideoFrame::kYPlane);
+ uint8* uplane = target->data(media::VideoFrame::kUPlane) +
+ (y / 2) * target->row_bytes(media::VideoFrame::kUPlane);
+ uint8* vplane = target->data(media::VideoFrame::kVPlane) +
+ (y / 2) * target->row_bytes(media::VideoFrame::kVPlane);
+ for (int x = rect.x(); x < rect.right(); ++x) {
+ int cursor_x = x - cursor_position.x();
+ SkColor color = cursor_bitmap.getColor(cursor_x, cursor_y);
+ int alpha = SkColorGetA(color);
+ int color_r = SkColorGetR(color);
+ int color_g = SkColorGetG(color);
+ int color_b = SkColorGetB(color);
+ int color_y = clip_byte(((color_r * 66 + color_g * 129 + color_b * 25 +
+ 128) >> 8) + 16);
+ yplane[x] = alpha_blend(alpha, color_y, yplane[x]);
+
+ // Only sample U and V at even coordinates.
+ if ((x % 2 == 0) && (y % 2 == 0)) {
+ int color_u = clip_byte(((color_r * -38 + color_g * -74 +
+ color_b * 112 + 128) >> 8) + 128);
+ int color_v = clip_byte(((color_r * 112 + color_g * -94 +
+ color_b * -18 + 128) >> 8) + 128);
+ uplane[x / 2] = alpha_blend(alpha, color_u, uplane[x / 2]);
+ vplane[x / 2] = alpha_blend(alpha, color_v, vplane[x / 2]);
+ }
+ }
+ }
+ cursor_bitmap.unlockPixels();
+}
+
+void CopyOutputFinishedForVideo(
+ base::TimeTicks start_time,
+ const ThreadSafeCaptureOracle::CaptureFrameCallback& capture_frame_cb,
+ const scoped_refptr<media::VideoFrame>& target,
+ const SkBitmap& cursor_bitmap,
+ const gfx::Point& cursor_position,
+ scoped_ptr<cc::SingleReleaseCallback> release_callback,
+ bool result) {
+ if (!cursor_bitmap.isNull())
+ RenderCursorOnVideoFrame(target, cursor_bitmap, cursor_position);
+ release_callback->Run(0, false);
+ capture_frame_cb.Run(target, start_time, result);
+}
+
+void RunSingleReleaseCallback(scoped_ptr<cc::SingleReleaseCallback> cb,
+ uint32 sync_point) {
+ cb->Run(sync_point, false);
+}
+
+} // namespace
+
+AuraWindowCaptureMachine::AuraWindowCaptureMachine()
+ : desktop_window_(NULL),
+ timer_(true, true),
+ screen_capture_(false) {}
+
+AuraWindowCaptureMachine::~AuraWindowCaptureMachine() {}
+
+bool AuraWindowCaptureMachine::Start(
+ const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy,
+ const media::VideoCaptureParams& params) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ // The window might be destroyed between SetWindow() and Start().
+ if (!desktop_window_)
+ return false;
+
+ // If the associated layer is already destroyed then return failure.
+ ui::Layer* layer = desktop_window_->layer();
+ if (!layer)
+ return false;
+
+ DCHECK(oracle_proxy.get());
+ oracle_proxy_ = oracle_proxy;
+ capture_params_ = params;
+
+ // Update capture size.
+ UpdateCaptureSize();
+
+ // Start observing compositor updates.
+ if (desktop_window_->GetHost())
+ desktop_window_->GetHost()->compositor()->AddObserver(this);
+
+ power_save_blocker_.reset(
+ PowerSaveBlocker::Create(
+ PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
+ PowerSaveBlocker::kReasonOther,
+ "DesktopCaptureDevice is running").release());
+
+ // Starts timer.
+ timer_.Start(FROM_HERE, oracle_proxy_->min_capture_period(),
+ base::Bind(&AuraWindowCaptureMachine::Capture, AsWeakPtr(),
+ false));
+
+ return true;
+}
+
+void AuraWindowCaptureMachine::Stop(const base::Closure& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ power_save_blocker_.reset();
+
+ // Stop observing compositor and window events.
+ if (desktop_window_) {
+ aura::WindowTreeHost* window_host = desktop_window_->GetHost();
+ // In the host destructor the compositor is destroyed before the window.
+ if (window_host && window_host->compositor())
+ window_host->compositor()->RemoveObserver(this);
+ desktop_window_->RemoveObserver(this);
+ desktop_window_ = NULL;
+ }
+
+ // Stop timer.
+ timer_.Stop();
+
+ callback.Run();
+}
+
+void AuraWindowCaptureMachine::SetWindow(aura::Window* window) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ DCHECK(!desktop_window_);
+ desktop_window_ = window;
+
+ // Start observing window events.
+ desktop_window_->AddObserver(this);
+
+ // We must store this for the UMA reporting in DidCopyOutput() as
+ // desktop_window_ might be destroyed at that point.
+ screen_capture_ = window->IsRootWindow();
+ IncrementDesktopCaptureCounter(screen_capture_ ? SCREEN_CAPTURER_CREATED
+ : WINDOW_CAPTURER_CREATED);
+}
+
+void AuraWindowCaptureMachine::UpdateCaptureSize() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (oracle_proxy_.get() && desktop_window_) {
+ ui::Layer* layer = desktop_window_->layer();
+ oracle_proxy_->UpdateCaptureSize(ui::ConvertSizeToPixel(
+ layer, layer->bounds().size()));
+ }
+ ClearCursorState();
+}
+
+void AuraWindowCaptureMachine::Capture(bool dirty) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ // Do not capture if the desktop window is already destroyed.
+ if (!desktop_window_)
+ return;
+
+ scoped_refptr<media::VideoFrame> frame;
+ ThreadSafeCaptureOracle::CaptureFrameCallback capture_frame_cb;
+
+ const base::TimeTicks start_time = base::TimeTicks::Now();
+ const VideoCaptureOracle::Event event =
+ dirty ? VideoCaptureOracle::kCompositorUpdate
+ : VideoCaptureOracle::kTimerPoll;
+ if (oracle_proxy_->ObserveEventAndDecideCapture(
+ event, gfx::Rect(), start_time, &frame, &capture_frame_cb)) {
+ scoped_ptr<cc::CopyOutputRequest> request =
+ cc::CopyOutputRequest::CreateRequest(
+ base::Bind(&AuraWindowCaptureMachine::DidCopyOutput,
+ AsWeakPtr(), frame, start_time, capture_frame_cb));
+ 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());
+ }
+}
+
+void AuraWindowCaptureMachine::DidCopyOutput(
+ scoped_refptr<media::VideoFrame> video_frame,
+ base::TimeTicks start_time,
+ const ThreadSafeCaptureOracle::CaptureFrameCallback& capture_frame_cb,
+ scoped_ptr<cc::CopyOutputResult> result) {
+ static bool first_call = true;
+
+ bool succeeded = ProcessCopyOutputResponse(
+ video_frame, start_time, capture_frame_cb, result.Pass());
+
+ base::TimeDelta capture_time = base::TimeTicks::Now() - start_time;
+
+ // The two UMA_ blocks must be put in its own scope since it creates a static
+ // variable which expected constant histogram name.
+ if (screen_capture_) {
+ UMA_HISTOGRAM_TIMES(kUmaScreenCaptureTime, capture_time);
+ } else {
+ UMA_HISTOGRAM_TIMES(kUmaWindowCaptureTime, capture_time);
+ }
+
+ if (first_call) {
+ first_call = false;
+ if (screen_capture_) {
+ IncrementDesktopCaptureCounter(succeeded ? FIRST_SCREEN_CAPTURE_SUCCEEDED
+ : FIRST_SCREEN_CAPTURE_FAILED);
+ } else {
+ IncrementDesktopCaptureCounter(succeeded
+ ? FIRST_WINDOW_CAPTURE_SUCCEEDED
+ : FIRST_WINDOW_CAPTURE_FAILED);
+ }
+ }
+}
+
+bool AuraWindowCaptureMachine::ProcessCopyOutputResponse(
+ scoped_refptr<media::VideoFrame> video_frame,
+ base::TimeTicks start_time,
+ const ThreadSafeCaptureOracle::CaptureFrameCallback& capture_frame_cb,
+ scoped_ptr<cc::CopyOutputResult> result) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ if (result->IsEmpty() || result->size().IsEmpty() || !desktop_window_)
+ return false;
+
+ if (capture_params_.requested_format.pixel_format ==
+ media::PIXEL_FORMAT_TEXTURE) {
+ DCHECK(!video_frame.get());
+ cc::TextureMailbox texture_mailbox;
+ scoped_ptr<cc::SingleReleaseCallback> release_callback;
+ result->TakeTexture(&texture_mailbox, &release_callback);
+ DCHECK(texture_mailbox.IsTexture());
+ if (!texture_mailbox.IsTexture())
+ return false;
+ video_frame = media::VideoFrame::WrapNativeTexture(
+ gpu::MailboxHolder(texture_mailbox.mailbox(), texture_mailbox.target(),
+ texture_mailbox.sync_point()),
+ base::Bind(&RunSingleReleaseCallback, base::Passed(&release_callback)),
+ result->size(), gfx::Rect(result->size()), result->size(),
+ base::TimeDelta(), false /* allow_overlay */, true /* has_alpha */);
+ capture_frame_cb.Run(video_frame, start_time, true);
+ return true;
+ } else {
+ DCHECK(video_frame.get());
+ }
+
+ // Compute the dest size we want after the letterboxing resize. Make the
+ // coordinates and sizes even because we letterbox in YUV space
+ // (see CopyRGBToVideoFrame). They need to be even for the UV samples to
+ // line up correctly.
+ // The video frame's visible_rect() and the result's size() are both physical
+ // pixels.
+ gfx::Rect region_in_frame = media::ComputeLetterboxRegion(
+ video_frame->visible_rect(), result->size());
+ region_in_frame = gfx::Rect(region_in_frame.x() & ~1,
+ region_in_frame.y() & ~1,
+ region_in_frame.width() & ~1,
+ region_in_frame.height() & ~1);
+ if (region_in_frame.IsEmpty())
+ return false;
+
+ ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
+ GLHelper* gl_helper = factory->GetGLHelper();
+ if (!gl_helper)
+ return false;
+
+ cc::TextureMailbox texture_mailbox;
+ scoped_ptr<cc::SingleReleaseCallback> release_callback;
+ result->TakeTexture(&texture_mailbox, &release_callback);
+ DCHECK(texture_mailbox.IsTexture());
+ if (!texture_mailbox.IsTexture())
+ return false;
+
+ gfx::Rect result_rect(result->size());
+ if (!yuv_readback_pipeline_ ||
+ yuv_readback_pipeline_->scaler()->SrcSize() != result_rect.size() ||
+ yuv_readback_pipeline_->scaler()->SrcSubrect() != result_rect ||
+ yuv_readback_pipeline_->scaler()->DstSize() != region_in_frame.size()) {
+ yuv_readback_pipeline_.reset(
+ gl_helper->CreateReadbackPipelineYUV(GLHelper::SCALER_QUALITY_FAST,
+ result_rect.size(),
+ result_rect,
+ region_in_frame.size(),
+ true,
+ true));
+ }
+
+ gfx::Point cursor_position_in_frame = UpdateCursorState(region_in_frame);
+ yuv_readback_pipeline_->ReadbackYUV(
+ texture_mailbox.mailbox(),
+ texture_mailbox.sync_point(),
+ video_frame.get(),
+ region_in_frame.origin(),
+ base::Bind(&CopyOutputFinishedForVideo,
+ start_time,
+ capture_frame_cb,
+ video_frame,
+ scaled_cursor_bitmap_,
+ cursor_position_in_frame,
+ base::Passed(&release_callback)));
+ return true;
+}
+
+gfx::Point AuraWindowCaptureMachine::UpdateCursorState(
+ const gfx::Rect& region_in_frame) {
+ const gfx::Rect desktop_bounds = desktop_window_->layer()->bounds();
+ if (desktop_bounds.IsEmpty()) {
+ // Return early to prevent divide-by-zero in calculations below.
+ ClearCursorState();
+ return gfx::Point();
+ }
+
+ gfx::NativeCursor cursor =
+ desktop_window_->GetHost()->last_cursor();
+ if (last_cursor_ != cursor ||
+ desktop_size_when_cursor_last_updated_ != desktop_bounds.size()) {
+ SkBitmap cursor_bitmap;
+ if (ui::GetCursorBitmap(cursor, &cursor_bitmap, &cursor_hot_point_)) {
+ const int scaled_width = cursor_bitmap.width() *
+ region_in_frame.width() / desktop_bounds.width();
+ const int scaled_height = cursor_bitmap.height() *
+ region_in_frame.height() / desktop_bounds.height();
+ if (scaled_width <= 0 || scaled_height <= 0) {
+ ClearCursorState();
+ return gfx::Point();
+ }
+ scaled_cursor_bitmap_ = skia::ImageOperations::Resize(
+ cursor_bitmap,
+ skia::ImageOperations::RESIZE_BEST,
+ scaled_width,
+ scaled_height);
+ last_cursor_ = cursor;
+ desktop_size_when_cursor_last_updated_ = desktop_bounds.size();
+ } else {
+ // Clear cursor state if ui::GetCursorBitmap failed so that we do not
+ // render cursor on the captured frame.
+ ClearCursorState();
+ }
+ }
+
+ gfx::Point cursor_position = aura::Env::GetInstance()->last_mouse_location();
+ aura::client::GetScreenPositionClient(desktop_window_->GetRootWindow())->
+ ConvertPointFromScreen(desktop_window_, &cursor_position);
+ const gfx::Point hot_point_in_dip = ui::ConvertPointToDIP(
+ desktop_window_->layer(), cursor_hot_point_);
+ cursor_position.Offset(-desktop_bounds.x() - hot_point_in_dip.x(),
+ -desktop_bounds.y() - hot_point_in_dip.y());
+ return gfx::Point(
+ region_in_frame.x() + cursor_position.x() * region_in_frame.width() /
+ desktop_bounds.width(),
+ region_in_frame.y() + cursor_position.y() * region_in_frame.height() /
+ desktop_bounds.height());
+}
+
+void AuraWindowCaptureMachine::ClearCursorState() {
+ last_cursor_ = ui::Cursor();
+ desktop_size_when_cursor_last_updated_ = gfx::Size();
+ cursor_hot_point_ = gfx::Point();
+ scaled_cursor_bitmap_.reset();
+}
+
+void AuraWindowCaptureMachine::OnWindowBoundsChanged(
+ aura::Window* window,
+ const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds) {
+ DCHECK(desktop_window_ && window == desktop_window_);
+
+ // Post task to update capture size on UI thread.
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
+ &AuraWindowCaptureMachine::UpdateCaptureSize, AsWeakPtr()));
+}
+
+void AuraWindowCaptureMachine::OnWindowDestroyed(aura::Window* window) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ Stop(base::Bind(&base::DoNothing));
+
+ oracle_proxy_->ReportError("OnWindowDestroyed()");
+}
+
+void AuraWindowCaptureMachine::OnWindowAddedToRootWindow(
+ aura::Window* window) {
+ DCHECK(window == desktop_window_);
+ window->GetHost()->compositor()->AddObserver(this);
+}
+
+void AuraWindowCaptureMachine::OnWindowRemovingFromRootWindow(
+ aura::Window* window,
+ aura::Window* new_root) {
+ DCHECK(window == desktop_window_);
+ window->GetHost()->compositor()->RemoveObserver(this);
+}
+
+void AuraWindowCaptureMachine::OnCompositingEnded(
+ ui::Compositor* compositor) {
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
+ &AuraWindowCaptureMachine::Capture, AsWeakPtr(), true));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/media/capture/aura_window_capture_machine.h b/chromium/content/browser/media/capture/aura_window_capture_machine.h
new file mode 100644
index 00000000000..f41e73ce460
--- /dev/null
+++ b/chromium/content/browser/media/capture/aura_window_capture_machine.h
@@ -0,0 +1,128 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_MEDIA_CAPTURE_AURA_WINDOW_CAPTURE_MACHINE_H_
+#define CONTENT_BROWSER_MEDIA_CAPTURE_AURA_WINDOW_CAPTURE_MACHINE_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/timer/timer.h"
+#include "content/browser/media/capture/content_video_capture_device_core.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_observer.h"
+#include "ui/base/cursor/cursors_aura.h"
+#include "ui/compositor/compositor.h"
+
+namespace cc {
+
+class CopyOutputResult;
+
+} // namespace cc
+
+namespace content {
+
+class PowerSaveBlocker;
+class ReadbackYUVInterface;
+
+class AuraWindowCaptureMachine
+ : public VideoCaptureMachine,
+ public aura::WindowObserver,
+ public ui::CompositorObserver,
+ public base::SupportsWeakPtr<AuraWindowCaptureMachine> {
+ public:
+ AuraWindowCaptureMachine();
+ ~AuraWindowCaptureMachine() override;
+
+ // VideoCaptureFrameSource overrides.
+ bool Start(const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy,
+ const media::VideoCaptureParams& params) override;
+ void Stop(const base::Closure& callback) override;
+
+ // Implements aura::WindowObserver.
+ 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.
+ void OnCompositingDidCommit(ui::Compositor* compositor) override {}
+ void OnCompositingStarted(ui::Compositor* compositor,
+ base::TimeTicks start_time) override {}
+ void OnCompositingEnded(ui::Compositor* compositor) override;
+ void OnCompositingAborted(ui::Compositor* compositor) override {}
+ void OnCompositingLockStateChanged(ui::Compositor* compositor) override {}
+ void OnCompositingShuttingDown(ui::Compositor* compositor) override {}
+
+ // Sets the window to use for capture.
+ void SetWindow(aura::Window* window);
+
+ private:
+ // Captures a frame.
+ // |dirty| is false for timer polls and true for compositor updates.
+ void Capture(bool dirty);
+
+ // Update capture size. Must be called on the UI thread.
+ void UpdateCaptureSize();
+
+ // Response callback for cc::Layer::RequestCopyOfOutput().
+ void DidCopyOutput(
+ scoped_refptr<media::VideoFrame> video_frame,
+ base::TimeTicks start_time,
+ const ThreadSafeCaptureOracle::CaptureFrameCallback& capture_frame_cb,
+ scoped_ptr<cc::CopyOutputResult> result);
+
+ // A helper which does the real work for DidCopyOutput. Returns true if
+ // succeeded.
+ bool ProcessCopyOutputResponse(
+ scoped_refptr<media::VideoFrame> video_frame,
+ base::TimeTicks start_time,
+ const ThreadSafeCaptureOracle::CaptureFrameCallback& capture_frame_cb,
+ scoped_ptr<cc::CopyOutputResult> result);
+
+ // Helper function to update cursor state.
+ // |region_in_frame| defines where the desktop is rendered in the captured
+ // frame.
+ // Returns the current cursor position in captured frame.
+ gfx::Point UpdateCursorState(const gfx::Rect& region_in_frame);
+
+ // Clears cursor state.
+ void ClearCursorState();
+
+ // The window associated with the desktop.
+ aura::Window* desktop_window_;
+
+ // The timer that kicks off period captures.
+ base::Timer timer_;
+
+ // Whether screen capturing or window capture.
+ bool screen_capture_;
+
+ // Makes all the decisions about which frames to copy, and how.
+ scoped_refptr<ThreadSafeCaptureOracle> oracle_proxy_;
+
+ // The capture parameters for this capture.
+ media::VideoCaptureParams capture_params_;
+
+ // YUV readback pipeline.
+ scoped_ptr<content::ReadbackYUVInterface> yuv_readback_pipeline_;
+
+ // Cursor state.
+ ui::Cursor last_cursor_;
+ gfx::Size desktop_size_when_cursor_last_updated_;
+ 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(AuraWindowCaptureMachine);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_MEDIA_CAPTURE_AURA_WINDOW_CAPTURE_MACHINE_H_
diff --git a/chromium/content/browser/media/capture/capture_resolution_chooser.cc b/chromium/content/browser/media/capture/capture_resolution_chooser.cc
new file mode 100644
index 00000000000..698882ab8d2
--- /dev/null
+++ b/chromium/content/browser/media/capture/capture_resolution_chooser.cc
@@ -0,0 +1,120 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/media/capture/capture_resolution_chooser.h"
+
+#include "media/base/limits.h"
+#include "media/base/video_util.h"
+
+namespace content {
+
+namespace {
+
+// Compute the minimum frame size from the given |max_frame_size| and
+// |resolution_change_policy|.
+gfx::Size ComputeMinimumCaptureSize(
+ const gfx::Size& max_frame_size,
+ media::ResolutionChangePolicy resolution_change_policy) {
+ switch (resolution_change_policy) {
+ case media::RESOLUTION_POLICY_FIXED_RESOLUTION:
+ return max_frame_size;
+ case media::RESOLUTION_POLICY_FIXED_ASPECT_RATIO: {
+ // TODO(miu): This is a place-holder until "min constraints" are plumbed-
+ // in from the MediaStream framework. http://crbug.com/473336
+ const int kMinLines = 180;
+ if (max_frame_size.height() <= kMinLines)
+ return max_frame_size;
+ const gfx::Size result(
+ kMinLines * max_frame_size.width() / max_frame_size.height(),
+ kMinLines);
+ if (result.width() <= 0 || result.width() > media::limits::kMaxDimension)
+ return max_frame_size;
+ return result;
+ }
+ case media::RESOLUTION_POLICY_ANY_WITHIN_LIMIT:
+ return gfx::Size(1, 1);
+ case media::RESOLUTION_POLICY_LAST:
+ break;
+ }
+ NOTREACHED();
+ return gfx::Size(1, 1);
+}
+
+// Returns |size|, unless it exceeds |max_size| or is under |min_size|. When
+// the bounds are exceeded, computes and returns an alternate size of similar
+// aspect ratio that is within the bounds.
+gfx::Size ComputeBoundedCaptureSize(const gfx::Size& size,
+ const gfx::Size& min_size,
+ const gfx::Size& max_size) {
+ if (size.width() > max_size.width() || size.height() > max_size.height()) {
+ gfx::Size result = media::ScaleSizeToFitWithinTarget(size, max_size);
+ result.SetToMax(min_size);
+ return result;
+ } else if (size.width() < min_size.width() ||
+ size.height() < min_size.height()) {
+ gfx::Size result = media::ScaleSizeToEncompassTarget(size, min_size);
+ result.SetToMin(max_size);
+ return result;
+ } else {
+ return size;
+ }
+}
+
+} // namespace
+
+CaptureResolutionChooser::CaptureResolutionChooser(
+ const gfx::Size& max_frame_size,
+ media::ResolutionChangePolicy resolution_change_policy)
+ : max_frame_size_(max_frame_size),
+ min_frame_size_(ComputeMinimumCaptureSize(max_frame_size,
+ resolution_change_policy)),
+ resolution_change_policy_(resolution_change_policy),
+ constrained_size_(max_frame_size) {
+ DCHECK_LT(0, max_frame_size_.width());
+ DCHECK_LT(0, max_frame_size_.height());
+ DCHECK_LE(min_frame_size_.width(), max_frame_size_.width());
+ DCHECK_LE(min_frame_size_.height(), max_frame_size_.height());
+
+ RecomputeCaptureSize();
+}
+
+CaptureResolutionChooser::~CaptureResolutionChooser() {}
+
+void CaptureResolutionChooser::SetSourceSize(const gfx::Size& source_size) {
+ if (source_size.IsEmpty())
+ return;
+
+ switch (resolution_change_policy_) {
+ case media::RESOLUTION_POLICY_FIXED_RESOLUTION:
+ // Source size changes do not affect the frame resolution. Frame
+ // resolution is always fixed to |max_frame_size_|.
+ break;
+
+ case media::RESOLUTION_POLICY_FIXED_ASPECT_RATIO:
+ constrained_size_ = ComputeBoundedCaptureSize(
+ media::PadToMatchAspectRatio(source_size, max_frame_size_),
+ min_frame_size_,
+ max_frame_size_);
+ RecomputeCaptureSize();
+ break;
+
+ case media::RESOLUTION_POLICY_ANY_WITHIN_LIMIT:
+ constrained_size_ = ComputeBoundedCaptureSize(
+ source_size, min_frame_size_, max_frame_size_);
+ RecomputeCaptureSize();
+ break;
+
+ case media::RESOLUTION_POLICY_LAST:
+ NOTREACHED();
+ }
+}
+
+void CaptureResolutionChooser::RecomputeCaptureSize() {
+ // TODO(miu): An upcoming change will introduce the ability to find the best
+ // capture resolution, given the current capabilities of the system.
+ // http://crbug.com/156767
+ capture_size_ = constrained_size_;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/media/capture/capture_resolution_chooser.h b/chromium/content/browser/media/capture/capture_resolution_chooser.h
new file mode 100644
index 00000000000..f1bda79acb9
--- /dev/null
+++ b/chromium/content/browser/media/capture/capture_resolution_chooser.h
@@ -0,0 +1,59 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_MEDIA_CAPTURE_CAPTURE_RESOLUTION_CHOOSER_H_
+#define CONTENT_BROWSER_MEDIA_CAPTURE_CAPTURE_RESOLUTION_CHOOSER_H_
+
+#include "content/common/content_export.h"
+#include "media/base/video_capture_types.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace content {
+
+// Encapsulates the logic that determines the capture frame resolution based on:
+// 1. The configured maximum frame resolution and resolution change policy.
+// 2. The resolution of the source content.
+// 3. The current capabilities of the end-to-end system, in terms of the
+// maximum number of pixels per frame.
+class CONTENT_EXPORT CaptureResolutionChooser {
+ public:
+ // media::ResolutionChangePolicy determines whether the variable frame
+ // resolutions being computed must adhere to a fixed aspect ratio or not, or
+ // that there must only be a single fixed resolution.
+ CaptureResolutionChooser(
+ const gfx::Size& max_frame_size,
+ media::ResolutionChangePolicy resolution_change_policy);
+ ~CaptureResolutionChooser();
+
+ // Returns the current capture frame resolution to use.
+ gfx::Size capture_size() const {
+ return capture_size_;
+ }
+
+ // Updates the capture size based on a change in the resolution of the source
+ // content.
+ void SetSourceSize(const gfx::Size& source_size);
+
+ private:
+ // Called after any update that requires |capture_size_| be re-computed.
+ void RecomputeCaptureSize();
+
+ // Hard constraints.
+ const gfx::Size max_frame_size_;
+ const gfx::Size min_frame_size_; // Computed from the ctor arguments.
+
+ // Specifies the set of heuristics to use.
+ const media::ResolutionChangePolicy resolution_change_policy_;
+
+ // The capture frame resolution to use, ignoring the limitations imposed by
+ // the capability metric.
+ gfx::Size constrained_size_;
+
+ // The current computed capture frame resolution.
+ gfx::Size capture_size_;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_MEDIA_CAPTURE_RESOLUTION_CHOOSER_H_
diff --git a/chromium/content/browser/media/capture/capture_resolution_chooser_unittest.cc b/chromium/content/browser/media/capture/capture_resolution_chooser_unittest.cc
new file mode 100644
index 00000000000..d91c0cec8dd
--- /dev/null
+++ b/chromium/content/browser/media/capture/capture_resolution_chooser_unittest.cc
@@ -0,0 +1,169 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/media/capture/capture_resolution_chooser.h"
+
+#include "base/location.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using tracked_objects::Location;
+
+namespace content {
+
+namespace {
+
+// 16:9 maximum and minimum frame sizes.
+const int kMaxFrameWidth = 3840;
+const int kMaxFrameHeight = 2160;
+const int kMinFrameWidth = 320;
+const int kMinFrameHeight = 180;
+
+// Checks whether |size| is strictly between (inclusive) |min_size| and
+// |max_size| and has the same aspect ratio as |max_size|.
+void ExpectIsWithinBoundsAndSameAspectRatio(const Location& location,
+ const gfx::Size& min_size,
+ const gfx::Size& max_size,
+ const gfx::Size& size) {
+ SCOPED_TRACE(::testing::Message() << "From here: " << location.ToString());
+ EXPECT_LE(min_size.width(), size.width());
+ EXPECT_LE(min_size.height(), size.height());
+ EXPECT_GE(max_size.width(), size.width());
+ EXPECT_GE(max_size.height(), size.height());
+ EXPECT_NEAR(static_cast<double>(max_size.width()) / max_size.height(),
+ static_cast<double>(size.width()) / size.height(),
+ 0.01);
+}
+
+} // namespace
+
+TEST(CaptureResolutionChooserTest,
+ FixedResolutionPolicy_CaptureSizeAlwaysFixed) {
+ const gfx::Size the_one_frame_size(kMaxFrameWidth, kMaxFrameHeight);
+ CaptureResolutionChooser chooser(the_one_frame_size,
+ media::RESOLUTION_POLICY_FIXED_RESOLUTION);
+ EXPECT_EQ(the_one_frame_size, chooser.capture_size());
+
+ chooser.SetSourceSize(the_one_frame_size);
+ EXPECT_EQ(the_one_frame_size, chooser.capture_size());
+
+ chooser.SetSourceSize(gfx::Size(kMaxFrameWidth + 424, kMaxFrameHeight - 101));
+ EXPECT_EQ(the_one_frame_size, chooser.capture_size());
+
+ chooser.SetSourceSize(gfx::Size(kMaxFrameWidth - 202, kMaxFrameHeight + 56));
+ EXPECT_EQ(the_one_frame_size, chooser.capture_size());
+
+ chooser.SetSourceSize(gfx::Size(kMinFrameWidth, kMinFrameHeight));
+ EXPECT_EQ(the_one_frame_size, chooser.capture_size());
+}
+
+TEST(CaptureResolutionChooserTest,
+ FixedAspectRatioPolicy_CaptureSizeHasSameAspectRatio) {
+ CaptureResolutionChooser chooser(
+ gfx::Size(kMaxFrameWidth, kMaxFrameHeight),
+ media::RESOLUTION_POLICY_FIXED_ASPECT_RATIO);
+
+ // Starting condition.
+ const gfx::Size min_size(kMinFrameWidth, kMinFrameHeight);
+ const gfx::Size max_size(kMaxFrameWidth, kMaxFrameHeight);
+ ExpectIsWithinBoundsAndSameAspectRatio(
+ FROM_HERE, min_size, max_size, chooser.capture_size());
+
+ // Max size in --> max size out.
+ chooser.SetSourceSize(gfx::Size(kMaxFrameWidth, kMaxFrameHeight));
+ ExpectIsWithinBoundsAndSameAspectRatio(
+ FROM_HERE, min_size, max_size, chooser.capture_size());
+
+ // Various source sizes within bounds.
+ chooser.SetSourceSize(gfx::Size(640, 480));
+ ExpectIsWithinBoundsAndSameAspectRatio(
+ FROM_HERE, min_size, max_size, chooser.capture_size());
+
+ chooser.SetSourceSize(gfx::Size(480, 640));
+ ExpectIsWithinBoundsAndSameAspectRatio(
+ FROM_HERE, min_size, max_size, chooser.capture_size());
+
+ chooser.SetSourceSize(gfx::Size(640, 640));
+ ExpectIsWithinBoundsAndSameAspectRatio(
+ FROM_HERE, min_size, max_size, chooser.capture_size());
+
+ // Bad source size results in no update.
+ const gfx::Size unchanged_size = chooser.capture_size();
+ chooser.SetSourceSize(gfx::Size(0, 0));
+ EXPECT_EQ(unchanged_size, chooser.capture_size());
+
+ // Downscaling size (preserving aspect ratio) when source size exceeds the
+ // upper bounds.
+ chooser.SetSourceSize(gfx::Size(kMaxFrameWidth * 2, kMaxFrameHeight * 2));
+ ExpectIsWithinBoundsAndSameAspectRatio(
+ FROM_HERE, min_size, max_size, chooser.capture_size());
+
+ chooser.SetSourceSize(gfx::Size(kMaxFrameWidth * 2, kMaxFrameHeight));
+ ExpectIsWithinBoundsAndSameAspectRatio(
+ FROM_HERE, min_size, max_size, chooser.capture_size());
+
+ chooser.SetSourceSize(gfx::Size(kMaxFrameWidth, kMaxFrameHeight * 2));
+ ExpectIsWithinBoundsAndSameAspectRatio(
+ FROM_HERE, min_size, max_size, chooser.capture_size());
+
+ // Upscaling size (preserving aspect ratio) when source size is under the
+ // lower bounds.
+ chooser.SetSourceSize(gfx::Size(kMinFrameWidth / 2, kMinFrameHeight / 2));
+ ExpectIsWithinBoundsAndSameAspectRatio(
+ FROM_HERE, min_size, max_size, chooser.capture_size());
+
+ chooser.SetSourceSize(gfx::Size(kMinFrameWidth / 2, kMaxFrameHeight));
+ ExpectIsWithinBoundsAndSameAspectRatio(
+ FROM_HERE, min_size, max_size, chooser.capture_size());
+
+ chooser.SetSourceSize(gfx::Size(kMinFrameWidth, kMinFrameHeight / 2));
+ ExpectIsWithinBoundsAndSameAspectRatio(
+ FROM_HERE, min_size, max_size, chooser.capture_size());
+}
+
+TEST(CaptureResolutionChooserTest,
+ AnyWithinLimitPolicy_CaptureSizeIsAnythingWithinLimits) {
+ const gfx::Size max_size(kMaxFrameWidth, kMaxFrameHeight);
+ CaptureResolutionChooser chooser(
+ max_size, media::RESOLUTION_POLICY_ANY_WITHIN_LIMIT);
+
+ // Starting condition.
+ EXPECT_EQ(max_size, chooser.capture_size());
+
+ // Max size in --> max size out.
+ chooser.SetSourceSize(max_size);
+ EXPECT_EQ(max_size, chooser.capture_size());
+
+ // Various source sizes within bounds.
+ chooser.SetSourceSize(gfx::Size(640, 480));
+ EXPECT_EQ(gfx::Size(640, 480), chooser.capture_size());
+
+ chooser.SetSourceSize(gfx::Size(480, 640));
+ EXPECT_EQ(gfx::Size(480, 640), chooser.capture_size());
+
+ chooser.SetSourceSize(gfx::Size(640, 640));
+ EXPECT_EQ(gfx::Size(640, 640), chooser.capture_size());
+
+ chooser.SetSourceSize(gfx::Size(2, 2));
+ EXPECT_EQ(gfx::Size(2, 2), chooser.capture_size());
+
+ // Bad source size results in no update.
+ const gfx::Size unchanged_size = chooser.capture_size();
+ chooser.SetSourceSize(gfx::Size(0, 0));
+ EXPECT_EQ(unchanged_size, chooser.capture_size());
+
+ // Downscaling size (preserving aspect ratio) when source size exceeds the
+ // upper bounds.
+ chooser.SetSourceSize(gfx::Size(kMaxFrameWidth * 2, kMaxFrameHeight * 2));
+ EXPECT_EQ(max_size, chooser.capture_size());
+
+ chooser.SetSourceSize(gfx::Size(kMaxFrameWidth * 2, kMaxFrameHeight));
+ EXPECT_EQ(gfx::Size(kMaxFrameWidth, kMaxFrameHeight / 2),
+ chooser.capture_size());
+
+ chooser.SetSourceSize(gfx::Size(kMaxFrameWidth, kMaxFrameHeight * 2));
+ EXPECT_EQ(gfx::Size(kMaxFrameWidth / 2, kMaxFrameHeight),
+ chooser.capture_size());
+}
+
+} // 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 f0499a23c22..da0862ccb8e 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
@@ -8,7 +8,6 @@
#include "base/bind.h"
#include "base/callback_forward.h"
#include "base/callback_helpers.h"
-#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
@@ -21,12 +20,14 @@
#include "base/threading/thread.h"
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
#include "content/public/browser/browser_thread.h"
#include "media/base/bind_to_current_loop.h"
+#include "media/base/video_capture_types.h"
#include "media/base/video_frame.h"
+#include "media/base/video_frame_metadata.h"
#include "media/base/video_util.h"
-#include "media/video/capture/video_capture_types.h"
-#include "ui/gfx/rect.h"
+#include "ui/gfx/geometry/rect.h"
namespace content {
@@ -34,7 +35,7 @@ namespace {
void DeleteCaptureMachineOnUIThread(
scoped_ptr<VideoCaptureMachine> capture_machine) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
capture_machine.reset();
}
@@ -43,24 +44,14 @@ void DeleteCaptureMachineOnUIThread(
ThreadSafeCaptureOracle::ThreadSafeCaptureOracle(
scoped_ptr<media::VideoCaptureDevice::Client> client,
- scoped_ptr<VideoCaptureOracle> oracle,
const media::VideoCaptureParams& params)
: client_(client.Pass()),
- oracle_(oracle.Pass()),
+ oracle_(base::TimeDelta::FromMicroseconds(
+ static_cast<int64>(1000000.0 / params.requested_format.frame_rate +
+ 0.5 /* to round to nearest int */))),
params_(params),
- capture_size_updated_(false) {
- switch (params_.requested_format.pixel_format) {
- case media::PIXEL_FORMAT_I420:
- video_frame_format_ = media::VideoFrame::I420;
- break;
- case media::PIXEL_FORMAT_TEXTURE:
- video_frame_format_ = media::VideoFrame::NATIVE_TEXTURE;
- break;
- default:
- LOG(FATAL) << "Unexpected pixel_format "
- << params_.requested_format.pixel_format;
- }
-}
+ resolution_chooser_(params.requested_format.frame_size,
+ params.resolution_change_policy) {}
ThreadSafeCaptureOracle::~ThreadSafeCaptureOracle() {}
@@ -70,24 +61,25 @@ bool ThreadSafeCaptureOracle::ObserveEventAndDecideCapture(
base::TimeTicks event_time,
scoped_refptr<media::VideoFrame>* storage,
CaptureFrameCallback* callback) {
+ // Grab the current time before waiting to acquire the |lock_|.
+ const base::TimeTicks capture_begin_time = base::TimeTicks::Now();
+
base::AutoLock guard(lock_);
if (!client_)
return false; // Capture is stopped.
+ const gfx::Size visible_size = resolution_chooser_.capture_size();
// 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_, coded_size);
+ scoped_ptr<media::VideoCaptureDevice::Client::Buffer> output_buffer(
+ client_->ReserveOutputBuffer(params_.requested_format.pixel_format,
+ coded_size));
const bool should_capture =
- oracle_->ObserveEventAndDecideCapture(event, damage_rect, event_time);
- const bool content_is_dirty =
- (event == VideoCaptureOracle::kCompositorUpdate ||
- event == VideoCaptureOracle::kSoftwarePaint);
+ oracle_.ObserveEventAndDecideCapture(event, damage_rect, event_time);
const char* event_name =
(event == VideoCaptureOracle::kTimerPoll ? "poll" :
(event == VideoCaptureOracle::kCompositorUpdate ? "gpu" :
@@ -95,18 +87,18 @@ bool ThreadSafeCaptureOracle::ObserveEventAndDecideCapture(
// Consider the various reasons not to initiate a capture.
if (should_capture && !output_buffer.get()) {
- TRACE_EVENT_INSTANT1("mirroring",
+ TRACE_EVENT_INSTANT1("gpu.capture",
"PipelineLimited",
TRACE_EVENT_SCOPE_THREAD,
"trigger",
event_name);
return false;
} else if (!should_capture && output_buffer.get()) {
- if (content_is_dirty) {
+ if (event == VideoCaptureOracle::kCompositorUpdate) {
// 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
// we're capturing at 30fps.
- TRACE_EVENT_INSTANT1("mirroring", "FpsRateLimited",
+ TRACE_EVENT_INSTANT1("gpu.capture", "FpsRateLimited",
TRACE_EVENT_SCOPE_THREAD,
"trigger", event_name);
}
@@ -114,63 +106,50 @@ bool ThreadSafeCaptureOracle::ObserveEventAndDecideCapture(
} 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", "NearlyPipelineLimited",
+ TRACE_EVENT_INSTANT1("gpu.capture", "NearlyPipelineLimited",
TRACE_EVENT_SCOPE_THREAD,
"trigger", event_name);
return false;
}
- int frame_number = oracle_->RecordCapture();
- TRACE_EVENT_ASYNC_BEGIN2("mirroring", "Capture", output_buffer.get(),
+ int frame_number = oracle_.RecordCapture();
+ TRACE_EVENT_ASYNC_BEGIN2("gpu.capture", "Capture", output_buffer.get(),
"frame_number", frame_number,
"trigger", event_name);
// NATIVE_TEXTURE frames wrap a texture mailbox, which we don't have at the
// moment. We do not construct those frames.
- if (video_frame_format_ != media::VideoFrame::NATIVE_TEXTURE) {
+ if (params_.requested_format.pixel_format != media::PIXEL_FORMAT_TEXTURE) {
*storage = media::VideoFrame::WrapExternalPackedMemory(
- video_frame_format_,
+ media::VideoFrame::I420,
coded_size,
gfx::Rect(visible_size),
visible_size,
static_cast<uint8*>(output_buffer->data()),
output_buffer->size(),
base::SharedMemory::NULLHandle(),
+ 0,
base::TimeDelta(),
base::Closure());
+ DCHECK(*storage);
}
*callback = base::Bind(&ThreadSafeCaptureOracle::DidCaptureFrame,
this,
frame_number,
- output_buffer);
+ base::Passed(&output_buffer),
+ capture_begin_time);
return true;
}
gfx::Size ThreadSafeCaptureOracle::GetCaptureSize() const {
base::AutoLock guard(lock_);
- return params_.requested_format.frame_size;
+ return resolution_chooser_.capture_size();
}
void ThreadSafeCaptureOracle::UpdateCaptureSize(const gfx::Size& source_size) {
base::AutoLock guard(lock_);
-
- // 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_.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() ||
- source_size.height() > params_.requested_format.frame_size.height()) {
- gfx::Rect capture_rect = media::ComputeLetterboxRegion(
- gfx::Rect(params_.requested_format.frame_size), source_size);
- params_.requested_format.frame_size.SetSize(
- MakeEven(capture_rect.width()), MakeEven(capture_rect.height()));
- } else {
- params_.requested_format.frame_size.SetSize(
- MakeEven(source_size.width()), MakeEven(source_size.height()));
- }
- capture_size_updated_ = true;
- }
+ resolution_chooser_.SetSourceSize(source_size);
+ VLOG(1) << "Source size changed to " << source_size.ToString()
+ << " --> Capture size is now "
+ << resolution_chooser_.capture_size().ToString();
}
void ThreadSafeCaptureOracle::Stop() {
@@ -186,12 +165,13 @@ void ThreadSafeCaptureOracle::ReportError(const std::string& reason) {
void ThreadSafeCaptureOracle::DidCaptureFrame(
int frame_number,
- const scoped_refptr<media::VideoCaptureDevice::Client::Buffer>& buffer,
+ scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer,
+ base::TimeTicks capture_begin_time,
const scoped_refptr<media::VideoFrame>& frame,
base::TimeTicks timestamp,
bool success) {
base::AutoLock guard(lock_);
- TRACE_EVENT_ASYNC_END2("mirroring", "Capture", buffer.get(),
+ TRACE_EVENT_ASYNC_END2("gpu.capture", "Capture", buffer.get(),
"success", success,
"timestamp", timestamp.ToInternalValue());
@@ -199,10 +179,15 @@ void ThreadSafeCaptureOracle::DidCaptureFrame(
return; // Capture is stopped.
if (success) {
- if (oracle_->CompleteCapture(frame_number, &timestamp)) {
- media::VideoCaptureFormat format = params_.requested_format;
- format.frame_size = frame->coded_size();
- client_->OnIncomingCapturedVideoFrame(buffer, format, frame, timestamp);
+ if (oracle_.CompleteCapture(frame_number, &timestamp)) {
+ // TODO(miu): Use the locked-in frame rate from AnimatedContentSampler.
+ frame->metadata()->SetDouble(media::VideoFrameMetadata::FRAME_RATE,
+ params_.requested_format.frame_rate);
+ frame->metadata()->SetTimeTicks(
+ media::VideoFrameMetadata::CAPTURE_BEGIN_TIME, capture_begin_time);
+ frame->metadata()->SetTimeTicks(
+ media::VideoFrameMetadata::CAPTURE_END_TIME, base::TimeTicks::Now());
+ client_->OnIncomingCapturedVideoFrame(buffer.Pass(), frame, timestamp);
}
}
}
@@ -234,30 +219,15 @@ void ContentVideoCaptureDeviceCore::AllocateAndStart(
return;
}
- if (params.requested_format.frame_size.width() < kMinFrameWidth ||
- params.requested_format.frame_size.height() < kMinFrameHeight) {
- std::string error_msg =
- "invalid frame size: " + params.requested_format.frame_size.ToString();
- DVLOG(1) << error_msg;
- client->OnError(error_msg);
- return;
- }
-
- media::VideoCaptureParams new_params = params;
- // Frame dimensions must each be an even integer since the client wants (or
- // will convert to) YUV420.
- new_params.requested_format.frame_size.SetSize(
- MakeEven(params.requested_format.frame_size.width()),
- MakeEven(params.requested_format.frame_size.height()));
-
- base::TimeDelta capture_period = base::TimeDelta::FromMicroseconds(
- 1000000.0 / params.requested_format.frame_rate + 0.5);
-
- scoped_ptr<VideoCaptureOracle> oracle(
- new VideoCaptureOracle(capture_period,
- kAcceleratedSubscriberIsSupported));
- oracle_proxy_ =
- new ThreadSafeCaptureOracle(client.Pass(), oracle.Pass(), new_params);
+ if (params.requested_format.frame_size.IsEmpty()) {
+ std::string error_msg =
+ "invalid frame size: " + params.requested_format.frame_size.ToString();
+ DVLOG(1) << error_msg;
+ client->OnError(error_msg);
+ return;
+ }
+
+ oracle_proxy_ = new ThreadSafeCaptureOracle(client.Pass(), params);
// Starts the capture machine asynchronously.
BrowserThread::PostTaskAndReplyWithResult(
@@ -266,7 +236,7 @@ void ContentVideoCaptureDeviceCore::AllocateAndStart(
base::Bind(&VideoCaptureMachine::Start,
base::Unretained(capture_machine_.get()),
oracle_proxy_,
- new_params),
+ params),
base::Bind(&ContentVideoCaptureDeviceCore::CaptureStarted, AsWeakPtr()));
TransitionStateTo(kCapturing);
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 c86bb6c883a..67dffd6ae65 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
@@ -11,6 +11,7 @@
#include "base/memory/weak_ptr.h"
#include "base/threading/thread.h"
#include "base/threading/thread_checker.h"
+#include "content/browser/media/capture/capture_resolution_chooser.h"
#include "content/browser/media/capture/video_capture_oracle.h"
#include "content/common/content_export.h"
#include "media/base/video_frame.h"
@@ -23,23 +24,6 @@ class VideoFrame;
namespace content {
-const int kMinFrameWidth = 2;
-const int kMinFrameHeight = 2;
-
-// Returns the nearest even integer closer to zero.
-template<typename IntType>
-IntType MakeEven(IntType x) {
- return x & static_cast<IntType>(-2);
-}
-
-// TODO(nick): Remove this once frame subscription is supported on Aura and
-// Linux.
-#if (defined(OS_WIN) || defined(OS_MACOSX)) || defined(USE_AURA)
-const bool kAcceleratedSubscriberIsSupported = true;
-#else
-const bool kAcceleratedSubscriberIsSupported = false;
-#endif
-
class VideoCaptureMachine;
// Thread-safe, refcounted proxy to the VideoCaptureOracle. This proxy wraps
@@ -50,7 +34,6 @@ class ThreadSafeCaptureOracle
: public base::RefCountedThreadSafe<ThreadSafeCaptureOracle> {
public:
ThreadSafeCaptureOracle(scoped_ptr<media::VideoCaptureDevice::Client> client,
- scoped_ptr<VideoCaptureOracle> oracle,
const media::VideoCaptureParams& params);
// Called when a captured frame is available or an error has occurred.
@@ -68,7 +51,11 @@ class ThreadSafeCaptureOracle
CaptureFrameCallback* callback);
base::TimeDelta min_capture_period() const {
- return oracle_->min_capture_period();
+ return oracle_.min_capture_period();
+ }
+
+ gfx::Size max_frame_size() const {
+ return params_.requested_format.frame_size;
}
// Returns the current capture resolution.
@@ -91,7 +78,8 @@ class ThreadSafeCaptureOracle
// Callback invoked on completion of all captures.
void DidCaptureFrame(
int frame_number,
- const scoped_refptr<media::VideoCaptureDevice::Client::Buffer>& buffer,
+ scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer,
+ base::TimeTicks capture_begin_time,
const scoped_refptr<media::VideoFrame>& frame,
base::TimeTicks timestamp,
bool success);
@@ -103,16 +91,13 @@ class ThreadSafeCaptureOracle
scoped_ptr<media::VideoCaptureDevice::Client> client_;
// Makes the decision to capture a frame.
- const scoped_ptr<VideoCaptureOracle> oracle_;
+ VideoCaptureOracle oracle_;
// The video capture parameters used to construct the oracle proxy.
- media::VideoCaptureParams params_;
-
- // Indicates if capture size has been updated after construction.
- bool capture_size_updated_;
+ const media::VideoCaptureParams params_;
- // The current capturing format, as a media::VideoFrame::Format.
- media::VideoFrame::Format video_frame_format_;
+ // Determines video capture frame sizes.
+ CaptureResolutionChooser resolution_chooser_;
};
// Keeps track of the video capture source frames and executes copying on the
diff --git a/chromium/content/browser/media/capture/desktop_capture_device.cc b/chromium/content/browser/media/capture/desktop_capture_device.cc
index c77ee0cc4c3..e42a678daff 100644
--- a/chromium/content/browser/media/capture/desktop_capture_device.cc
+++ b/chromium/content/browser/media/capture/desktop_capture_device.cc
@@ -12,19 +12,20 @@
#include "base/synchronization/lock.h"
#include "base/threading/thread.h"
#include "base/timer/timer.h"
+#include "content/browser/media/capture/capture_resolution_chooser.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/cropping_window_capturer.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_and_cursor_composer.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_capture_options.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_capturer.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
#include "third_party/webrtc/modules/desktop_capture/mouse_cursor_monitor.h"
#include "third_party/webrtc/modules/desktop_capture/screen_capturer.h"
-#include "third_party/webrtc/modules/desktop_capture/window_capturer.h"
namespace content {
@@ -46,6 +47,11 @@ webrtc::DesktopRect ComputeLetterboxRect(
result.x(), result.y(), result.right(), result.bottom());
}
+bool IsFrameUnpackedOrInverted(webrtc::DesktopFrame* frame) {
+ return frame->stride() !=
+ frame->size().width() * webrtc::DesktopFrame::kBytesPerPixel;
+}
+
} // namespace
class DesktopCaptureDevice::Core : public webrtc::DesktopCapturer::Callback {
@@ -67,11 +73,6 @@ class DesktopCaptureDevice::Core : public webrtc::DesktopCapturer::Callback {
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]
- // notifications.
- void RefreshCaptureFormat(const webrtc::DesktopSize& frame_size);
-
// Method that is scheduled on |task_runner_| to be called on regular interval
// to capture a frame.
void OnCaptureTimer();
@@ -92,24 +93,20 @@ class DesktopCaptureDevice::Core : public webrtc::DesktopCapturer::Callback {
// on the task_runner_ thread.
scoped_ptr<Client> client_;
- // Requested video capture format (width, height, frame rate, etc).
- media::VideoCaptureParams requested_params_;
-
- // Actual video capture format being generated.
- media::VideoCaptureFormat capture_format_;
+ // Requested video capture frame rate.
+ float requested_frame_rate_;
// Size of frame most recently captured from the source.
webrtc::DesktopSize previous_frame_size_;
+ // Determines the size of frames to deliver to the |client_|.
+ scoped_ptr<CaptureResolutionChooser> resolution_chooser_;
+
// DesktopFrame into which captured frames are down-scaled and/or letterboxed,
// depending upon the caller's requested capture capabilities. If frames can
// be returned to the caller directly then this is NULL.
scoped_ptr<webrtc::DesktopFrame> output_frame_;
- // Sub-rectangle of |output_frame_| into which the source will be scaled
- // and/or letterboxed.
- webrtc::DesktopRect output_rect_;
-
// Timer used to capture the frame.
base::OneShotTimer<Core> capture_timer_;
@@ -162,16 +159,16 @@ void DesktopCaptureDevice::Core::AllocateAndStart(
DCHECK(!client_.get());
client_ = client.Pass();
- requested_params_ = params;
+ requested_frame_rate_ = params.requested_format.frame_rate;
+ resolution_chooser_.reset(new CaptureResolutionChooser(
+ params.requested_format.frame_size,
+ params.resolution_change_policy));
- 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());
+ power_save_blocker_.reset(
+ PowerSaveBlocker::Create(
+ PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
+ PowerSaveBlocker::kReasonOther,
+ "DesktopCaptureDevice is running").release());
desktop_capturer_->Start(this);
@@ -231,16 +228,29 @@ void DesktopCaptureDevice::Core::OnCaptureCompleted(
scoped_ptr<webrtc::DesktopFrame> owned_frame(frame);
+ // If the frame size has changed, drop the output frame (if any), and
+ // determine the new output size.
+ if (!previous_frame_size_.equals(frame->size())) {
+ output_frame_.reset();
+ resolution_chooser_->SetSourceSize(gfx::Size(frame->size().width(),
+ frame->size().height()));
+ previous_frame_size_ = frame->size();
+ }
+ // Align to 2x2 pixel boundaries, as required by OnIncomingCapturedData() so
+ // it can convert the frame to I420 format.
+ const webrtc::DesktopSize output_size(
+ resolution_chooser_->capture_size().width() & ~1,
+ resolution_chooser_->capture_size().height() & ~1);
+ if (output_size.is_empty())
+ return;
+
// On OSX We receive a 1x1 frame when the shared window is minimized. It
// cannot be subsampled to I420 and will be dropped downstream. So we replace
// it with a black frame to avoid the video appearing frozen at the last
// frame.
if (frame->size().width() == 1 || frame->size().height() == 1) {
if (!black_frame_.get()) {
- black_frame_.reset(
- new webrtc::BasicDesktopFrame(
- webrtc::DesktopSize(capture_format_.frame_size.width(),
- capture_format_.frame_size.height())));
+ black_frame_.reset(new webrtc::BasicDesktopFrame(output_size));
memset(black_frame_->data(),
0,
black_frame_->stride() * black_frame_->size().height());
@@ -249,42 +259,16 @@ void DesktopCaptureDevice::Core::OnCaptureCompleted(
frame = black_frame_.get();
}
- // Handle initial frame size and size changes.
- RefreshCaptureFormat(frame->size());
-
- webrtc::DesktopSize output_size(capture_format_.frame_size.width(),
- capture_format_.frame_size.height());
size_t output_bytes = output_size.width() * output_size.height() *
webrtc::DesktopFrame::kBytesPerPixel;
const uint8_t* output_data = NULL;
- scoped_ptr<uint8_t[]> flipped_frame_buffer;
- if (frame->size().equals(output_size)) {
- // If the captured frame matches the output size, we can return the pixel
- // data directly, without scaling.
- output_data = frame->data();
-
- // If the |frame| generated by the screen capturer is inverted then we need
- // to flip |frame|.
- // This happens only on a specific platform. Refer to crbug.com/306876.
- if (frame->stride() < 0) {
- int height = frame->size().height();
- int bytes_per_row =
- frame->size().width() * webrtc::DesktopFrame::kBytesPerPixel;
- flipped_frame_buffer.reset(new uint8_t[output_bytes]);
- uint8_t* dest = flipped_frame_buffer.get();
- for (int row = 0; row < height; ++row) {
- memcpy(dest, output_data, bytes_per_row);
- dest += bytes_per_row;
- output_data += frame->stride();
- }
- output_data = flipped_frame_buffer.get();
- }
- } else {
- // Otherwise we need to down-scale and/or letterbox to the target format.
+ if (!frame->size().equals(output_size)) {
+ // Down-scale and/or letterbox to the target format if the frame does not
+ // match the output size.
// Allocate a buffer of the correct size to scale the frame into.
- // |output_frame_| is cleared whenever |output_rect_| changes, so we don't
+ // |output_frame_| is cleared whenever the output size changes, so we don't
// need to worry about clearing out stale pixel data in letterboxed areas.
if (!output_frame_) {
output_frame_.reset(new webrtc::BasicDesktopFrame(output_size));
@@ -294,61 +278,47 @@ void DesktopCaptureDevice::Core::OnCaptureCompleted(
// TODO(wez): Optimize this to scale only changed portions of the output,
// using ARGBScaleClip().
+ const webrtc::DesktopRect output_rect =
+ ComputeLetterboxRect(output_size, frame->size());
uint8_t* output_rect_data = output_frame_->data() +
- output_frame_->stride() * output_rect_.top() +
- webrtc::DesktopFrame::kBytesPerPixel * output_rect_.left();
+ output_frame_->stride() * output_rect.top() +
+ webrtc::DesktopFrame::kBytesPerPixel * output_rect.left();
libyuv::ARGBScale(frame->data(), frame->stride(),
frame->size().width(), frame->size().height(),
output_rect_data, output_frame_->stride(),
- output_rect_.width(), output_rect_.height(),
+ output_rect.width(), output_rect.height(),
libyuv::kFilterBilinear);
output_data = output_frame_->data();
- }
-
- client_->OnIncomingCapturedData(
- output_data, output_bytes, capture_format_, 0, base::TimeTicks::Now());
-}
-
-void DesktopCaptureDevice::Core::RefreshCaptureFormat(
- const webrtc::DesktopSize& frame_size) {
- if (previous_frame_size_.equals(frame_size))
- return;
-
- // Clear the output frame, if any, since it will either need resizing, or
- // clearing of stale data in letterbox areas, anyway.
- output_frame_.reset();
-
- if (previous_frame_size_.is_empty() ||
- 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.
- if (frame_size.width() >
- requested_params_.requested_format.frame_size.width() ||
- frame_size.height() >
- requested_params_.requested_format.frame_size.height()) {
- output_rect_ = ComputeLetterboxRect(
- webrtc::DesktopSize(
- requested_params_.requested_format.frame_size.width(),
- requested_params_.requested_format.frame_size.height()),
- frame_size);
- output_rect_.Translate(-output_rect_.left(), -output_rect_.top());
- } else {
- output_rect_ = webrtc::DesktopRect::MakeSize(frame_size);
+ } else if (IsFrameUnpackedOrInverted(frame)) {
+ // If |frame| is not packed top-to-bottom then create a packed top-to-bottom
+ // copy.
+ // This is required if the frame is inverted (see crbug.com/306876), or if
+ // |frame| is cropped form a larger frame (see crbug.com/437740).
+ if (!output_frame_) {
+ output_frame_.reset(new webrtc::BasicDesktopFrame(output_size));
+ memset(output_frame_->data(), 0, output_bytes);
}
- capture_format_.frame_size.SetSize(output_rect_.width(),
- output_rect_.height());
+
+ output_frame_->CopyPixelsFrom(
+ *frame,
+ webrtc::DesktopVector(),
+ webrtc::DesktopRect::MakeSize(frame->size()));
+ output_data = output_frame_->data();
} else {
- // Otherwise the output frame size cannot change, so just scale and
- // letterbox.
- output_rect_ = ComputeLetterboxRect(
- webrtc::DesktopSize(capture_format_.frame_size.width(),
- capture_format_.frame_size.height()),
- frame_size);
+ // If the captured frame matches the output size, we can return the pixel
+ // data directly.
+ output_data = frame->data();
}
- previous_frame_size_ = frame_size;
+ client_->OnIncomingCapturedData(
+ output_data,
+ output_bytes,
+ media::VideoCaptureFormat(gfx::Size(output_size.width(),
+ output_size.height()),
+ requested_frame_rate_,
+ media::PIXEL_FORMAT_ARGB),
+ 0,
+ base::TimeTicks::Now());
}
void DesktopCaptureDevice::Core::OnCaptureTimer() {
@@ -370,7 +340,8 @@ void DesktopCaptureDevice::Core::CaptureFrameAndScheduleNext() {
// Limit frame-rate to reduce CPU consumption.
base::TimeDelta capture_period = std::max(
(last_capture_duration * 100) / kMaximumCpuConsumptionPercentage,
- base::TimeDelta::FromSeconds(1) / capture_format_.frame_rate);
+ base::TimeDelta::FromMicroseconds(static_cast<int64>(
+ 1000000.0 / requested_frame_rate_ + 0.5 /* round to nearest int */)));
// Schedule a task for the next frame.
capture_timer_.Start(FROM_HERE, capture_period - last_capture_duration,
@@ -397,13 +368,14 @@ scoped_ptr<media::VideoCaptureDevice> DesktopCaptureDevice::Create(
// Leave desktop effects enabled during WebRTC captures.
options.set_disable_effects(false);
+#if defined(OS_WIN)
+ options.set_allow_use_magnification_api(true);
+#endif
+
scoped_ptr<webrtc::DesktopCapturer> capturer;
switch (source.type) {
case DesktopMediaID::TYPE_SCREEN: {
-#if defined(OS_WIN)
- options.set_allow_use_magnification_api(true);
-#endif
scoped_ptr<webrtc::ScreenCapturer> screen_capturer(
webrtc::ScreenCapturer::Create(options));
if (screen_capturer && screen_capturer->SelectScreen(source.id)) {
@@ -417,7 +389,7 @@ scoped_ptr<media::VideoCaptureDevice> DesktopCaptureDevice::Create(
case DesktopMediaID::TYPE_WINDOW: {
scoped_ptr<webrtc::WindowCapturer> window_capturer(
- webrtc::WindowCapturer::Create(options));
+ webrtc::CroppingWindowCapturer::Create(options));
if (window_capturer && window_capturer->SelectWindow(source.id)) {
window_capturer->BringSelectedWindowToFront();
capturer.reset(new webrtc::DesktopAndCursorComposer(
@@ -447,7 +419,7 @@ DesktopCaptureDevice::~DesktopCaptureDevice() {
void DesktopCaptureDevice::AllocateAndStart(
const media::VideoCaptureParams& params,
scoped_ptr<Client> client) {
- thread_.message_loop_proxy()->PostTask(
+ thread_.task_runner()->PostTask(
FROM_HERE,
base::Bind(&Core::AllocateAndStart, base::Unretained(core_.get()), params,
base::Passed(&client)));
@@ -455,16 +427,20 @@ void DesktopCaptureDevice::AllocateAndStart(
void DesktopCaptureDevice::StopAndDeAllocate() {
if (core_) {
- thread_.message_loop_proxy()->DeleteSoon(FROM_HERE, core_.release());
+ thread_.task_runner()->DeleteSoon(FROM_HERE, core_.release());
thread_.Stop();
}
}
void DesktopCaptureDevice::SetNotificationWindowId(
gfx::NativeViewId window_id) {
- thread_.message_loop_proxy()->PostTask(
+ // This may be called after the capturer has been stopped.
+ if (!core_)
+ return;
+ thread_.task_runner()->PostTask(
FROM_HERE,
- base::Bind(&Core::SetNotificationWindowId, base::Unretained(core_.get()),
+ base::Bind(&Core::SetNotificationWindowId,
+ base::Unretained(core_.get()),
window_id));
}
@@ -481,7 +457,7 @@ DesktopCaptureDevice::DesktopCaptureDevice(
thread_.StartWithOptions(base::Thread::Options(thread_type, 0));
- core_.reset(new Core(thread_.message_loop_proxy(), capturer.Pass(), type));
+ core_.reset(new Core(thread_.task_runner(), capturer.Pass(), type));
}
} // namespace content
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 6b6557f1844..93da72afd26 100644
--- a/chromium/content/browser/media/capture/desktop_capture_device_aura.cc
+++ b/chromium/content/browser/media/capture/desktop_capture_device_aura.cc
@@ -5,514 +5,35 @@
#include "content/browser/media/capture/desktop_capture_device_aura.h"
#include "base/logging.h"
-#include "base/metrics/histogram.h"
#include "base/timer/timer.h"
-#include "cc/output/copy_output_request.h"
-#include "cc/output/copy_output_result.h"
-#include "content/browser/compositor/image_transport_factory.h"
+#include "content/browser/media/capture/aura_window_capture_machine.h"
#include "content/browser/media/capture/content_video_capture_device_core.h"
-#include "content/browser/media/capture/desktop_capture_device_uma_types.h"
-#include "content/common/gpu/client/gl_helper.h"
#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/power_save_blocker.h"
-#include "media/base/video_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 "ui/aura/client/screen_position_client.h"
-#include "ui/aura/env.h"
#include "ui/aura/window.h"
-#include "ui/aura/window_observer.h"
-#include "ui/aura/window_tree_host.h"
-#include "ui/base/cursor/cursors_aura.h"
-#include "ui/compositor/compositor.h"
-#include "ui/compositor/dip_util.h"
-#include "ui/compositor/layer.h"
-#include "ui/gfx/screen.h"
namespace content {
namespace {
-int clip_byte(int x) {
- return std::max(0, std::min(x, 255));
-}
-
-int alpha_blend(int alpha, int src, int dst) {
- return (src * alpha + dst * (255 - alpha)) / 255;
-}
-
-// Helper function to composite a cursor bitmap on a YUV420 video frame.
-void RenderCursorOnVideoFrame(
- const scoped_refptr<media::VideoFrame>& target,
- const SkBitmap& cursor_bitmap,
- const gfx::Point& cursor_position) {
- DCHECK(target.get());
- DCHECK(!cursor_bitmap.isNull());
-
- gfx::Rect rect = gfx::IntersectRects(
- gfx::Rect(cursor_bitmap.width(), cursor_bitmap.height()) +
- gfx::Vector2d(cursor_position.x(), cursor_position.y()),
- target->visible_rect());
-
- cursor_bitmap.lockPixels();
- for (int y = rect.y(); y < rect.bottom(); ++y) {
- int cursor_y = y - cursor_position.y();
- uint8* yplane = target->data(media::VideoFrame::kYPlane) +
- y * target->row_bytes(media::VideoFrame::kYPlane);
- uint8* uplane = target->data(media::VideoFrame::kUPlane) +
- (y / 2) * target->row_bytes(media::VideoFrame::kUPlane);
- uint8* vplane = target->data(media::VideoFrame::kVPlane) +
- (y / 2) * target->row_bytes(media::VideoFrame::kVPlane);
- for (int x = rect.x(); x < rect.right(); ++x) {
- int cursor_x = x - cursor_position.x();
- SkColor color = cursor_bitmap.getColor(cursor_x, cursor_y);
- int alpha = SkColorGetA(color);
- int color_r = SkColorGetR(color);
- int color_g = SkColorGetG(color);
- int color_b = SkColorGetB(color);
- int color_y = clip_byte(((color_r * 66 + color_g * 129 + color_b * 25 +
- 128) >> 8) + 16);
- yplane[x] = alpha_blend(alpha, color_y, yplane[x]);
-
- // Only sample U and V at even coordinates.
- if ((x % 2 == 0) && (y % 2 == 0)) {
- int color_u = clip_byte(((color_r * -38 + color_g * -74 +
- color_b * 112 + 128) >> 8) + 128);
- int color_v = clip_byte(((color_r * 112 + color_g * -94 +
- color_b * -18 + 128) >> 8) + 128);
- uplane[x / 2] = alpha_blend(alpha, color_u, uplane[x / 2]);
- vplane[x / 2] = alpha_blend(alpha, color_v, vplane[x / 2]);
- }
- }
- }
- cursor_bitmap.unlockPixels();
-}
-
-class DesktopVideoCaptureMachine
- : public VideoCaptureMachine,
- public aura::WindowObserver,
- public ui::CompositorObserver,
- public base::SupportsWeakPtr<DesktopVideoCaptureMachine> {
- public:
- DesktopVideoCaptureMachine(const DesktopMediaID& source);
- ~DesktopVideoCaptureMachine() override;
-
- // VideoCaptureFrameSource overrides.
- bool Start(const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy,
- const media::VideoCaptureParams& params) override;
- void Stop(const base::Closure& callback) override;
-
- // Implements aura::WindowObserver.
- 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.
- 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.
- // |dirty| is false for timer polls and true for compositor updates.
- void Capture(bool dirty);
-
- // Update capture size. Must be called on the UI thread.
- void UpdateCaptureSize();
-
- // Response callback for cc::Layer::RequestCopyOfOutput().
- void DidCopyOutput(
- scoped_refptr<media::VideoFrame> video_frame,
- base::TimeTicks start_time,
- const ThreadSafeCaptureOracle::CaptureFrameCallback& capture_frame_cb,
- scoped_ptr<cc::CopyOutputResult> result);
-
- // A helper which does the real work for DidCopyOutput. Returns true if
- // succeeded.
- bool ProcessCopyOutputResponse(
- scoped_refptr<media::VideoFrame> video_frame,
- base::TimeTicks start_time,
- const ThreadSafeCaptureOracle::CaptureFrameCallback& capture_frame_cb,
- scoped_ptr<cc::CopyOutputResult> result);
-
- // Helper function to update cursor state.
- // |region_in_frame| defines the desktop bound in the captured frame.
- // Returns the current cursor position in captured frame.
- gfx::Point UpdateCursorState(const gfx::Rect& region_in_frame);
-
- // Clears cursor state.
- void ClearCursorState();
-
- // The window associated with the desktop.
- aura::Window* desktop_window_;
-
- // The timer that kicks off period captures.
- base::Timer timer_;
-
- // The id of the window being captured.
- DesktopMediaID window_id_;
-
- // Makes all the decisions about which frames to copy, and how.
- scoped_refptr<ThreadSafeCaptureOracle> oracle_proxy_;
-
- // The capture parameters for this capture.
- media::VideoCaptureParams capture_params_;
-
- // YUV readback pipeline.
- scoped_ptr<content::ReadbackYUVInterface> yuv_readback_pipeline_;
-
- // Cursor state.
- ui::Cursor last_cursor_;
- 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);
-};
-
-DesktopVideoCaptureMachine::DesktopVideoCaptureMachine(
- const DesktopMediaID& source)
- : desktop_window_(NULL),
- timer_(true, true),
- window_id_(source) {}
-
-DesktopVideoCaptureMachine::~DesktopVideoCaptureMachine() {}
-
-bool DesktopVideoCaptureMachine::Start(
- const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy,
- const media::VideoCaptureParams& params) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- desktop_window_ = content::DesktopMediaID::GetAuraWindowById(window_id_);
- if (!desktop_window_)
- return false;
-
- // If the associated layer is already destroyed then return failure.
- ui::Layer* layer = desktop_window_->layer();
- if (!layer)
- return false;
-
- DCHECK(oracle_proxy.get());
- oracle_proxy_ = oracle_proxy;
- capture_params_ = params;
-
- // Update capture size.
- UpdateCaptureSize();
-
- // Start observing window events.
- desktop_window_->AddObserver(this);
-
- // Start observing compositor updates.
- 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_->min_capture_period(),
- base::Bind(&DesktopVideoCaptureMachine::Capture, AsWeakPtr(),
- false));
-
- 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_) {
- if (desktop_window_->GetHost())
- desktop_window_->GetHost()->compositor()->RemoveObserver(this);
- desktop_window_->RemoveObserver(this);
- desktop_window_ = NULL;
- }
-
- // Stop timer.
- timer_.Stop();
-
- callback.Run();
-}
-
-void DesktopVideoCaptureMachine::UpdateCaptureSize() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (oracle_proxy_.get() && desktop_window_) {
- ui::Layer* layer = desktop_window_->layer();
- oracle_proxy_->UpdateCaptureSize(ui::ConvertSizeToPixel(
- layer, layer->bounds().size()));
- }
- ClearCursorState();
-}
-
-void DesktopVideoCaptureMachine::Capture(bool dirty) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- // Do not capture if the desktop window is already destroyed.
- if (!desktop_window_)
- return;
-
- scoped_refptr<media::VideoFrame> frame;
- ThreadSafeCaptureOracle::CaptureFrameCallback capture_frame_cb;
-
- const base::TimeTicks start_time = base::TimeTicks::Now();
- const VideoCaptureOracle::Event event =
- dirty ? VideoCaptureOracle::kCompositorUpdate
- : VideoCaptureOracle::kTimerPoll;
- if (oracle_proxy_->ObserveEventAndDecideCapture(
- 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 = gfx::Rect(desktop_window_->bounds().width(),
- desktop_window_->bounds().height());
- request->set_area(window_rect);
- desktop_window_->layer()->RequestCopyOfOutput(request.Pass());
- }
-}
-
-void CopyOutputFinishedForVideo(
- base::TimeTicks start_time,
- const ThreadSafeCaptureOracle::CaptureFrameCallback& capture_frame_cb,
- const scoped_refptr<media::VideoFrame>& target,
- const SkBitmap& cursor_bitmap,
- const gfx::Point& cursor_position,
- scoped_ptr<cc::SingleReleaseCallback> release_callback,
- bool result) {
- if (!cursor_bitmap.isNull())
- RenderCursorOnVideoFrame(target, cursor_bitmap, cursor_position);
- release_callback->Run(0, false);
- capture_frame_cb.Run(target, start_time, result);
-}
-
-void RunSingleReleaseCallback(scoped_ptr<cc::SingleReleaseCallback> cb,
- uint32 sync_point) {
- cb->Run(sync_point, false);
-}
-
-void DesktopVideoCaptureMachine::DidCopyOutput(
- scoped_refptr<media::VideoFrame> video_frame,
- base::TimeTicks start_time,
- const ThreadSafeCaptureOracle::CaptureFrameCallback& capture_frame_cb,
- scoped_ptr<cc::CopyOutputResult> result) {
- static bool first_call = true;
-
- bool succeeded = ProcessCopyOutputResponse(
- video_frame, start_time, capture_frame_cb, result.Pass());
-
- base::TimeDelta capture_time = base::TimeTicks::Now() - start_time;
-
- // The two UMA_ blocks must be put in its own scope since it creates a static
- // variable which expected constant histogram name.
- 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;
- if (window_id_.type == DesktopMediaID::TYPE_SCREEN) {
- IncrementDesktopCaptureCounter(succeeded ? FIRST_SCREEN_CAPTURE_SUCCEEDED
- : FIRST_SCREEN_CAPTURE_FAILED);
- } else {
- IncrementDesktopCaptureCounter(succeeded
- ? FIRST_WINDOW_CAPTURE_SUCCEEDED
- : FIRST_WINDOW_CAPTURE_FAILED);
- }
- }
-}
-
-bool DesktopVideoCaptureMachine::ProcessCopyOutputResponse(
- scoped_refptr<media::VideoFrame> video_frame,
- base::TimeTicks start_time,
- const ThreadSafeCaptureOracle::CaptureFrameCallback& capture_frame_cb,
- scoped_ptr<cc::CopyOutputResult> result) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (result->IsEmpty() || result->size().IsEmpty() || !desktop_window_)
- return false;
-
- if (capture_params_.requested_format.pixel_format ==
- media::PIXEL_FORMAT_TEXTURE) {
- DCHECK(!video_frame.get());
- cc::TextureMailbox texture_mailbox;
- scoped_ptr<cc::SingleReleaseCallback> release_callback;
- result->TakeTexture(&texture_mailbox, &release_callback);
- DCHECK(texture_mailbox.IsTexture());
- if (!texture_mailbox.IsTexture())
- return false;
- video_frame = media::VideoFrame::WrapNativeTexture(
- make_scoped_ptr(new gpu::MailboxHolder(texture_mailbox.mailbox(),
- texture_mailbox.target(),
- texture_mailbox.sync_point())),
- base::Bind(&RunSingleReleaseCallback, base::Passed(&release_callback)),
- result->size(),
- gfx::Rect(result->size()),
- result->size(),
- base::TimeDelta(),
- media::VideoFrame::ReadPixelsCB());
- capture_frame_cb.Run(video_frame, start_time, true);
- return true;
- }
-
- // Compute the dest size we want after the letterboxing resize. Make the
- // coordinates and sizes even because we letterbox in YUV space
- // (see CopyRGBToVideoFrame). They need to be even for the UV samples to
- // line up correctly.
- // The video frame's coded_size() and the result's size() are both physical
- // pixels.
- gfx::Rect region_in_frame =
- media::ComputeLetterboxRegion(gfx::Rect(video_frame->coded_size()),
- result->size());
- region_in_frame = gfx::Rect(region_in_frame.x() & ~1,
- region_in_frame.y() & ~1,
- region_in_frame.width() & ~1,
- region_in_frame.height() & ~1);
- if (region_in_frame.IsEmpty())
- return false;
-
- ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
- GLHelper* gl_helper = factory->GetGLHelper();
- if (!gl_helper)
- return false;
+void SetCaptureSource(AuraWindowCaptureMachine* machine,
+ const DesktopMediaID& source) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
- cc::TextureMailbox texture_mailbox;
- scoped_ptr<cc::SingleReleaseCallback> release_callback;
- result->TakeTexture(&texture_mailbox, &release_callback);
- DCHECK(texture_mailbox.IsTexture());
- if (!texture_mailbox.IsTexture())
- return false;
-
- gfx::Rect result_rect(result->size());
- if (!yuv_readback_pipeline_ ||
- yuv_readback_pipeline_->scaler()->SrcSize() != result_rect.size() ||
- yuv_readback_pipeline_->scaler()->SrcSubrect() != result_rect ||
- yuv_readback_pipeline_->scaler()->DstSize() != region_in_frame.size()) {
- yuv_readback_pipeline_.reset(
- gl_helper->CreateReadbackPipelineYUV(GLHelper::SCALER_QUALITY_FAST,
- result_rect.size(),
- result_rect,
- video_frame->coded_size(),
- region_in_frame,
- true,
- true));
- }
-
- gfx::Point cursor_position_in_frame = UpdateCursorState(region_in_frame);
- yuv_readback_pipeline_->ReadbackYUV(
- texture_mailbox.mailbox(),
- texture_mailbox.sync_point(),
- video_frame.get(),
- base::Bind(&CopyOutputFinishedForVideo,
- start_time,
- capture_frame_cb,
- video_frame,
- scaled_cursor_bitmap_,
- cursor_position_in_frame,
- base::Passed(&release_callback)));
- return true;
-}
-
-gfx::Point DesktopVideoCaptureMachine::UpdateCursorState(
- const gfx::Rect& region_in_frame) {
- const gfx::Rect desktop_bounds = desktop_window_->layer()->bounds();
- gfx::NativeCursor cursor =
- desktop_window_->GetHost()->last_cursor();
- if (last_cursor_ != cursor) {
- SkBitmap cursor_bitmap;
- if (ui::GetCursorBitmap(cursor, &cursor_bitmap, &cursor_hot_point_)) {
- scaled_cursor_bitmap_ = skia::ImageOperations::Resize(
- cursor_bitmap,
- skia::ImageOperations::RESIZE_BEST,
- cursor_bitmap.width() * region_in_frame.width() /
- desktop_bounds.width(),
- cursor_bitmap.height() * region_in_frame.height() /
- desktop_bounds.height());
- last_cursor_ = cursor;
- } else {
- // Clear cursor state if ui::GetCursorBitmap failed so that we do not
- // render cursor on the captured frame.
- ClearCursorState();
- }
- }
-
- gfx::Point cursor_position = aura::Env::GetInstance()->last_mouse_location();
- aura::client::GetScreenPositionClient(desktop_window_->GetRootWindow())->
- ConvertPointFromScreen(desktop_window_, &cursor_position);
- const gfx::Point hot_point_in_dip = ui::ConvertPointToDIP(
- desktop_window_->layer(), cursor_hot_point_);
- cursor_position.Offset(-desktop_bounds.x() - hot_point_in_dip.x(),
- -desktop_bounds.y() - hot_point_in_dip.y());
- return gfx::Point(
- region_in_frame.x() + cursor_position.x() * region_in_frame.width() /
- desktop_bounds.width(),
- region_in_frame.y() + cursor_position.y() * region_in_frame.height() /
- desktop_bounds.height());
-}
-
-void DesktopVideoCaptureMachine::ClearCursorState() {
- last_cursor_ = ui::Cursor();
- cursor_hot_point_ = gfx::Point();
- scaled_cursor_bitmap_.reset();
-}
-
-void DesktopVideoCaptureMachine::OnWindowBoundsChanged(
- aura::Window* window,
- const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds) {
- DCHECK(desktop_window_ && window == desktop_window_);
-
- // Post task to update capture size on UI thread.
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
- &DesktopVideoCaptureMachine::UpdateCaptureSize, AsWeakPtr()));
-}
-
-void DesktopVideoCaptureMachine::OnWindowDestroyed(aura::Window* window) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- Stop(base::Bind(&base::DoNothing));
-
- oracle_proxy_->ReportError("OnWindowDestroyed()");
-}
-
-void DesktopVideoCaptureMachine::OnWindowAddedToRootWindow(
- aura::Window* window) {
- DCHECK(window == desktop_window_);
- window->GetHost()->compositor()->AddObserver(this);
-}
-
-void DesktopVideoCaptureMachine::OnWindowRemovingFromRootWindow(
- aura::Window* window,
- aura::Window* new_root) {
- DCHECK(window == desktop_window_);
- window->GetHost()->compositor()->RemoveObserver(this);
-}
-
-void DesktopVideoCaptureMachine::OnCompositingEnded(
- ui::Compositor* compositor) {
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
- &DesktopVideoCaptureMachine::Capture, AsWeakPtr(), true));
+ aura::Window* window = DesktopMediaID::GetAuraWindowById(source);
+ machine->SetWindow(window);
}
} // namespace
DesktopCaptureDeviceAura::DesktopCaptureDeviceAura(
- const DesktopMediaID& source)
- : core_(new ContentVideoCaptureDeviceCore(scoped_ptr<VideoCaptureMachine>(
- new DesktopVideoCaptureMachine(source)))) {}
+ const DesktopMediaID& source) {
+ AuraWindowCaptureMachine* machine = new AuraWindowCaptureMachine();
+ core_.reset(new ContentVideoCaptureDeviceCore(make_scoped_ptr(machine)));
+ // |core_| owns |machine| and deletes it on UI thread so passing the raw
+ // pointer to the UI thread is safe here.
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(&SetCaptureSource, machine, source));
+}
DesktopCaptureDeviceAura::~DesktopCaptureDeviceAura() {
DVLOG(2) << "DesktopCaptureDeviceAura@" << this << " destroying.";
@@ -521,9 +42,6 @@ DesktopCaptureDeviceAura::~DesktopCaptureDeviceAura() {
// static
media::VideoCaptureDevice* DesktopCaptureDeviceAura::Create(
const DesktopMediaID& source) {
- IncrementDesktopCaptureCounter(source.type == DesktopMediaID::TYPE_SCREEN
- ? SCREEN_CAPTURER_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 8f3540a7fd6..404c730128f 100644
--- a/chromium/content/browser/media/capture/desktop_capture_device_aura.h
+++ b/chromium/content/browser/media/capture/desktop_capture_device_aura.h
@@ -37,7 +37,7 @@ class CONTENT_EXPORT DesktopCaptureDeviceAura
private:
DesktopCaptureDeviceAura(const DesktopMediaID& source);
- const scoped_ptr<class ContentVideoCaptureDeviceCore> core_;
+ scoped_ptr<class ContentVideoCaptureDeviceCore> core_;
DISALLOW_COPY_AND_ASSIGN(DesktopCaptureDeviceAura);
};
diff --git a/chromium/content/browser/media/capture/desktop_capture_device_aura_unittest.cc b/chromium/content/browser/media/capture/desktop_capture_device_aura_unittest.cc
index 81cbd15b20e..054c933f427 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
@@ -7,7 +7,7 @@
#include "base/synchronization/waitable_event.h"
#include "content/browser/browser_thread_impl.h"
#include "content/public/browser/desktop_media_id.h"
-#include "media/video/capture/video_capture_types.h"
+#include "media/base/video_capture_types.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/client/window_tree_client.h"
@@ -35,21 +35,44 @@ const int kFrameRate = 30;
class MockDeviceClient : public media::VideoCaptureDevice::Client {
public:
- MOCK_METHOD2(ReserveOutputBuffer,
- scoped_refptr<Buffer>(media::VideoFrame::Format format,
- const gfx::Size& dimensions));
- MOCK_METHOD1(OnError, void(const std::string& reason));
MOCK_METHOD5(OnIncomingCapturedData,
void(const uint8* data,
int length,
const media::VideoCaptureFormat& frame_format,
int rotation,
- base::TimeTicks timestamp));
- MOCK_METHOD4(OnIncomingCapturedVideoFrame,
- void(const scoped_refptr<Buffer>& buffer,
- const media::VideoCaptureFormat& buffer_format,
- const scoped_refptr<media::VideoFrame>& frame,
- base::TimeTicks timestamp));
+ const base::TimeTicks& timestamp));
+ MOCK_METHOD9(OnIncomingCapturedYuvData,
+ void (const uint8* y_data,
+ const uint8* u_data,
+ const uint8* v_data,
+ size_t y_stride,
+ size_t u_stride,
+ size_t v_stride,
+ const media::VideoCaptureFormat& frame_format,
+ int clockwise_rotation,
+ const base::TimeTicks& timestamp));
+ MOCK_METHOD0(DoReserveOutputBuffer, void(void));
+ MOCK_METHOD0(DoOnIncomingCapturedBuffer, void(void));
+ MOCK_METHOD0(DoOnIncomingCapturedVideoFrame, void(void));
+ MOCK_METHOD1(OnError, void(const std::string& reason));
+
+ // Trampoline methods to workaround GMOCK problems with scoped_ptr<>.
+ scoped_ptr<Buffer> ReserveOutputBuffer(media::VideoPixelFormat format,
+ const gfx::Size& dimensions) override {
+ DoReserveOutputBuffer();
+ return scoped_ptr<Buffer>();
+ }
+ void OnIncomingCapturedBuffer(scoped_ptr<Buffer> buffer,
+ const media::VideoCaptureFormat& frame_format,
+ const base::TimeTicks& timestamp) override {
+ DoOnIncomingCapturedBuffer();
+ }
+ void OnIncomingCapturedVideoFrame(
+ scoped_ptr<Buffer> buffer,
+ const scoped_refptr<media::VideoFrame>& frame,
+ const base::TimeTicks& timestamp) override {
+ DoOnIncomingCapturedVideoFrame();
+ }
};
// Test harness that sets up a minimal environment with necessary stubs.
@@ -57,10 +80,10 @@ class DesktopCaptureDeviceAuraTest : public testing::Test {
public:
DesktopCaptureDeviceAuraTest()
: browser_thread_for_ui_(BrowserThread::UI, &message_loop_) {}
- virtual ~DesktopCaptureDeviceAuraTest() {}
+ ~DesktopCaptureDeviceAuraTest() override {}
protected:
- virtual void SetUp() override {
+ void SetUp() override {
// The ContextFactory must exist before any Compositors are created.
bool enable_pixel_output = false;
ui::ContextFactory* context_factory =
@@ -75,14 +98,14 @@ class DesktopCaptureDeviceAuraTest : public testing::Test {
gfx::Rect desktop_bounds = root_window()->bounds();
window_delegate_.reset(new aura::test::TestWindowDelegate());
desktop_window_.reset(new aura::Window(window_delegate_.get()));
- desktop_window_->Init(aura::WINDOW_LAYER_TEXTURED);
+ desktop_window_->Init(ui::LAYER_TEXTURED);
desktop_window_->SetBounds(desktop_bounds);
aura::client::ParentWindowWithContext(
desktop_window_.get(), root_window(), desktop_bounds);
desktop_window_->Show();
}
- virtual void TearDown() override {
+ void TearDown() override {
helper_->RunAllPendingInMessageLoop();
root_window()->RemoveChild(desktop_window_.get());
desktop_window_.reset();
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 0388043642f..56e06ff66b4 100644
--- a/chromium/content/browser/media/capture/desktop_capture_device_unittest.cc
+++ b/chromium/content/browser/media/capture/desktop_capture_device_unittest.cc
@@ -4,6 +4,7 @@
#include "content/browser/media/capture/desktop_capture_device.h"
+#include <algorithm>
#include <string>
#include "base/basictypes.h"
@@ -13,6 +14,7 @@
#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_capture_options.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
#include "third_party/webrtc/modules/desktop_capture/screen_capturer.h"
@@ -21,8 +23,10 @@ using ::testing::_;
using ::testing::AnyNumber;
using ::testing::DoAll;
using ::testing::Expectation;
+using ::testing::Invoke;
using ::testing::InvokeWithoutArgs;
using ::testing::SaveArg;
+using ::testing::WithArg;
namespace content {
@@ -32,32 +36,82 @@ MATCHER_P2(EqualsCaptureCapability, width, height, "") {
return arg.width == width && arg.height == height;
}
-const int kTestFrameWidth1 = 100;
-const int kTestFrameHeight1 = 100;
-const int kTestFrameWidth2 = 200;
-const int kTestFrameHeight2 = 150;
+const int kTestFrameWidth1 = 500;
+const int kTestFrameHeight1 = 500;
+const int kTestFrameWidth2 = 400;
+const int kTestFrameHeight2 = 300;
const int kFrameRate = 30;
+// The value of the padding bytes in unpacked frames.
+const uint8_t kFramePaddingValue = 0;
+
+// Use a special value for frame pixels to tell pixel bytes apart from the
+// padding bytes in the unpacked frame test.
+const uint8_t kFakePixelValue = 1;
+
+// Use a special value for the first pixel to verify the result in the inverted
+// frame test.
+const uint8_t kFakePixelValueFirst = 2;
+
class MockDeviceClient : public media::VideoCaptureDevice::Client {
public:
- MOCK_METHOD2(ReserveOutputBuffer,
- scoped_refptr<Buffer>(media::VideoFrame::Format format,
- const gfx::Size& dimensions));
- MOCK_METHOD1(OnError, void(const std::string& reason));
MOCK_METHOD5(OnIncomingCapturedData,
void(const uint8* data,
int length,
const media::VideoCaptureFormat& frame_format,
int rotation,
- base::TimeTicks timestamp));
- MOCK_METHOD4(OnIncomingCapturedVideoFrame,
- void(const scoped_refptr<Buffer>& buffer,
- const media::VideoCaptureFormat& buffer_format,
- const scoped_refptr<media::VideoFrame>& frame,
- base::TimeTicks timestamp));
+ const base::TimeTicks& timestamp));
+ MOCK_METHOD9(OnIncomingCapturedYuvData,
+ void (const uint8* y_data,
+ const uint8* u_data,
+ const uint8* v_data,
+ size_t y_stride,
+ size_t u_stride,
+ size_t v_stride,
+ const media::VideoCaptureFormat& frame_format,
+ int clockwise_rotation,
+ const base::TimeTicks& timestamp));
+ MOCK_METHOD0(DoReserveOutputBuffer, void(void));
+ MOCK_METHOD0(DoOnIncomingCapturedBuffer, void(void));
+ MOCK_METHOD0(DoOnIncomingCapturedVideoFrame, void(void));
+ MOCK_METHOD1(OnError, void(const std::string& reason));
+
+ // Trampoline methods to workaround GMOCK problems with scoped_ptr<>.
+ scoped_ptr<Buffer> ReserveOutputBuffer(media::VideoPixelFormat format,
+ const gfx::Size& dimensions) override {
+ DoReserveOutputBuffer();
+ return scoped_ptr<Buffer>();
+ }
+ void OnIncomingCapturedBuffer(scoped_ptr<Buffer> buffer,
+ const media::VideoCaptureFormat& frame_format,
+ const base::TimeTicks& timestamp) override {
+ DoOnIncomingCapturedBuffer();
+ }
+ void OnIncomingCapturedVideoFrame(
+ scoped_ptr<Buffer> buffer,
+ const scoped_refptr<media::VideoFrame>& frame,
+ const base::TimeTicks& timestamp) override {
+ DoOnIncomingCapturedVideoFrame();
+ }
};
+// Creates a DesktopFrame that has the first pixel bytes set to
+// kFakePixelValueFirst, and the rest of the bytes set to kFakePixelValue, for
+// UnpackedFrame and InvertedFrame verification.
+webrtc::BasicDesktopFrame* CreateBasicFrame(const webrtc::DesktopSize& size) {
+ webrtc::BasicDesktopFrame* frame = new webrtc::BasicDesktopFrame(size);;
+ DCHECK_EQ(frame->size().width() * webrtc::DesktopFrame::kBytesPerPixel,
+ frame->stride());
+ memset(frame->data(),
+ kFakePixelValue,
+ frame->stride() * frame->size().height());
+ memset(frame->data(),
+ kFakePixelValueFirst,
+ webrtc::DesktopFrame::kBytesPerPixel);
+ return frame;
+}
+
// DesktopFrame wrapper that flips wrapped frame upside down by inverting
// stride.
class InvertedDesktopFrame : public webrtc::DesktopFrame {
@@ -82,13 +136,37 @@ class InvertedDesktopFrame : public webrtc::DesktopFrame {
DISALLOW_COPY_AND_ASSIGN(InvertedDesktopFrame);
};
+// DesktopFrame wrapper that copies the input frame and doubles the stride.
+class UnpackedDesktopFrame : public webrtc::DesktopFrame {
+ public:
+ // Takes ownership of |frame|.
+ explicit UnpackedDesktopFrame(webrtc::DesktopFrame* frame)
+ : webrtc::DesktopFrame(
+ frame->size(),
+ frame->stride() * 2,
+ new uint8_t[frame->stride() * 2 * frame->size().height()],
+ NULL) {
+ memset(data(), kFramePaddingValue, stride() * size().height());
+ CopyPixelsFrom(*frame,
+ webrtc::DesktopVector(),
+ webrtc::DesktopRect::MakeSize(size()));
+ delete frame;
+ }
+ ~UnpackedDesktopFrame() override {
+ delete[] data_;
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(UnpackedDesktopFrame);
+};
+
// TODO(sergeyu): Move this to a separate file where it can be reused.
class FakeScreenCapturer : public webrtc::ScreenCapturer {
public:
FakeScreenCapturer()
: callback_(NULL),
frame_index_(0),
- generate_inverted_frames_(false) {
+ generate_inverted_frames_(false),
+ generate_cropped_frames_(false) {
}
~FakeScreenCapturer() override {}
@@ -96,6 +174,10 @@ class FakeScreenCapturer : public webrtc::ScreenCapturer {
generate_inverted_frames_ = generate_inverted_frames;
}
+ void set_generate_cropped_frames(bool generate_cropped_frames) {
+ generate_cropped_frames_ = generate_cropped_frames;
+ }
+
// VideoFrameCapturer interface.
void Start(Callback* callback) override { callback_ = callback; }
@@ -108,15 +190,16 @@ class FakeScreenCapturer : public webrtc::ScreenCapturer {
}
frame_index_++;
- webrtc::DesktopFrame* frame = new webrtc::BasicDesktopFrame(size);
- if (generate_inverted_frames_)
+ webrtc::DesktopFrame* frame = CreateBasicFrame(size);;
+
+ if (generate_inverted_frames_) {
frame = new InvertedDesktopFrame(frame);
+ } else if (generate_cropped_frames_) {
+ frame = new UnpackedDesktopFrame(frame);
+ }
callback_->OnCaptureCompleted(frame);
}
- void SetMouseShapeObserver(
- MouseShapeObserver* mouse_shape_observer) override {}
-
bool GetScreenList(ScreenList* screens) override { return false; }
bool SelectScreen(webrtc::ScreenId id) override { return false; }
@@ -125,6 +208,33 @@ class FakeScreenCapturer : public webrtc::ScreenCapturer {
Callback* callback_;
int frame_index_;
bool generate_inverted_frames_;
+ bool generate_cropped_frames_;
+};
+
+// Helper used to check that only two specific frame sizes are delivered to the
+// OnIncomingCapturedData() callback.
+class FormatChecker {
+ public:
+ FormatChecker(const gfx::Size& size_for_even_frames,
+ const gfx::Size& size_for_odd_frames)
+ : size_for_even_frames_(size_for_even_frames),
+ size_for_odd_frames_(size_for_odd_frames),
+ frame_count_(0) {}
+
+ void ExpectAcceptableSize(const media::VideoCaptureFormat& format) {
+ if (frame_count_ % 2 == 0)
+ EXPECT_EQ(size_for_even_frames_, format.frame_size);
+ else
+ EXPECT_EQ(size_for_odd_frames_, format.frame_size);
+ ++frame_count_;
+ EXPECT_EQ(kFrameRate, format.frame_rate);
+ EXPECT_EQ(media::PIXEL_FORMAT_ARGB, format.pixel_format);
+ }
+
+ private:
+ const gfx::Size size_for_even_frames_;
+ const gfx::Size size_for_odd_frames_;
+ int frame_count_;
};
} // namespace
@@ -136,8 +246,16 @@ class DesktopCaptureDeviceTest : public testing::Test {
new DesktopCaptureDevice(capturer.Pass(), DesktopMediaID::TYPE_SCREEN));
}
+ void CopyFrame(const uint8_t* frame, int size,
+ const media::VideoCaptureFormat&, int, base::TimeTicks) {
+ ASSERT_TRUE(output_frame_.get() != NULL);
+ ASSERT_EQ(output_frame_->stride() * output_frame_->size().height(), size);
+ memcpy(output_frame_->data(), frame, size);
+ }
+
protected:
scoped_ptr<DesktopCaptureDevice> capture_device_;
+ scoped_ptr<webrtc::DesktopFrame> output_frame_;
};
// There is currently no screen capturer implementation for ozone. So disable
@@ -150,7 +268,8 @@ class DesktopCaptureDeviceTest : public testing::Test {
#endif
TEST_F(DesktopCaptureDeviceTest, MAYBE_Capture) {
scoped_ptr<webrtc::DesktopCapturer> capturer(
- webrtc::ScreenCapturer::Create());
+ webrtc::ScreenCapturer::Create(
+ webrtc::DesktopCaptureOptions::CreateDefault()));
CreateScreenCaptureDevice(capturer.Pass());
media::VideoCaptureFormat format;
@@ -187,15 +306,15 @@ TEST_F(DesktopCaptureDeviceTest, ScreenResolutionChangeConstantResolution) {
CreateScreenCaptureDevice(scoped_ptr<webrtc::DesktopCapturer>(mock_capturer));
- media::VideoCaptureFormat format;
+ FormatChecker format_checker(gfx::Size(kTestFrameWidth1, kTestFrameHeight1),
+ gfx::Size(kTestFrameWidth1, kTestFrameHeight1));
base::WaitableEvent done_event(false, false);
- int frame_size;
scoped_ptr<MockDeviceClient> client(new MockDeviceClient());
EXPECT_CALL(*client, OnError(_)).Times(0);
EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _)).WillRepeatedly(
- DoAll(SaveArg<1>(&frame_size),
- SaveArg<2>(&format),
+ DoAll(WithArg<2>(Invoke(&format_checker,
+ &FormatChecker::ExpectAcceptableSize)),
InvokeWithoutArgs(&done_event, &base::WaitableEvent::Signal)));
media::VideoCaptureParams capture_params;
@@ -203,23 +322,66 @@ TEST_F(DesktopCaptureDeviceTest, ScreenResolutionChangeConstantResolution) {
kTestFrameHeight1);
capture_params.requested_format.frame_rate = kFrameRate;
capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
+ capture_params.resolution_change_policy =
+ media::RESOLUTION_POLICY_FIXED_RESOLUTION;
capture_device_->AllocateAndStart(capture_params, client.Pass());
// Capture at least two frames, to ensure that the source frame size has
- // changed while capturing.
- EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
- done_event.Reset();
- EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
+ // changed to two different sizes while capturing. The mock for
+ // OnIncomingCapturedData() will use FormatChecker to examine the format of
+ // each frame being delivered.
+ for (int i = 0; i < 2; ++i) {
+ EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
+ done_event.Reset();
+ }
capture_device_->StopAndDeAllocate();
+}
- EXPECT_EQ(kTestFrameWidth1, format.frame_size.width());
- EXPECT_EQ(kTestFrameHeight1, format.frame_size.height());
- EXPECT_EQ(kFrameRate, format.frame_rate);
- EXPECT_EQ(media::PIXEL_FORMAT_ARGB, format.pixel_format);
+// Test that screen capturer behaves correctly if the source frame size changes,
+// where the video frames sent the the client vary in resolution but maintain
+// the same aspect ratio.
+TEST_F(DesktopCaptureDeviceTest, ScreenResolutionChangeFixedAspectRatio) {
+ FakeScreenCapturer* mock_capturer = new FakeScreenCapturer();
- EXPECT_EQ(format.frame_size.GetArea() * 4, frame_size);
+ CreateScreenCaptureDevice(scoped_ptr<webrtc::DesktopCapturer>(mock_capturer));
+
+ FormatChecker format_checker(gfx::Size(888, 500), gfx::Size(532, 300));
+ base::WaitableEvent done_event(false, false);
+
+ scoped_ptr<MockDeviceClient> client(new MockDeviceClient());
+ EXPECT_CALL(*client, OnError(_)).Times(0);
+ EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _)).WillRepeatedly(
+ DoAll(WithArg<2>(Invoke(&format_checker,
+ &FormatChecker::ExpectAcceptableSize)),
+ InvokeWithoutArgs(&done_event, &base::WaitableEvent::Signal)));
+
+ media::VideoCaptureParams capture_params;
+ const gfx::Size high_def_16_by_9(1920, 1080);
+ ASSERT_GE(high_def_16_by_9.width(),
+ std::max(kTestFrameWidth1, kTestFrameWidth2));
+ ASSERT_GE(high_def_16_by_9.height(),
+ std::max(kTestFrameHeight1, kTestFrameHeight2));
+ capture_params.requested_format.frame_size = high_def_16_by_9;
+ capture_params.requested_format.frame_rate = kFrameRate;
+ capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
+ capture_params.resolution_change_policy =
+ media::RESOLUTION_POLICY_FIXED_ASPECT_RATIO;
+
+ capture_device_->AllocateAndStart(
+ capture_params, client.Pass());
+
+ // Capture at least three frames, to ensure that the source frame size has
+ // changed to two different sizes while capturing. The mock for
+ // OnIncomingCapturedData() will use FormatChecker to examine the format of
+ // each frame being delivered.
+ for (int i = 0; i < 3; ++i) {
+ EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
+ done_event.Reset();
+ }
+
+ capture_device_->StopAndDeAllocate();
}
// Test that screen capturer behaves correctly if the source frame size changes
@@ -229,38 +391,131 @@ TEST_F(DesktopCaptureDeviceTest, ScreenResolutionChangeVariableResolution) {
CreateScreenCaptureDevice(scoped_ptr<webrtc::DesktopCapturer>(mock_capturer));
- media::VideoCaptureFormat format;
+ FormatChecker format_checker(gfx::Size(kTestFrameWidth1, kTestFrameHeight1),
+ gfx::Size(kTestFrameWidth2, kTestFrameHeight2));
base::WaitableEvent done_event(false, false);
scoped_ptr<MockDeviceClient> client(new MockDeviceClient());
EXPECT_CALL(*client, OnError(_)).Times(0);
EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _)).WillRepeatedly(
- DoAll(SaveArg<2>(&format),
+ DoAll(WithArg<2>(Invoke(&format_checker,
+ &FormatChecker::ExpectAcceptableSize)),
InvokeWithoutArgs(&done_event, &base::WaitableEvent::Signal)));
media::VideoCaptureParams capture_params;
- capture_params.requested_format.frame_size.SetSize(kTestFrameWidth2,
- kTestFrameHeight2);
+ const gfx::Size high_def_16_by_9(1920, 1080);
+ ASSERT_GE(high_def_16_by_9.width(),
+ std::max(kTestFrameWidth1, kTestFrameWidth2));
+ ASSERT_GE(high_def_16_by_9.height(),
+ std::max(kTestFrameHeight1, kTestFrameHeight2));
+ capture_params.requested_format.frame_size = high_def_16_by_9;
capture_params.requested_format.frame_rate = kFrameRate;
capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
+ capture_params.resolution_change_policy =
+ media::RESOLUTION_POLICY_ANY_WITHIN_LIMIT;
capture_device_->AllocateAndStart(
capture_params, client.Pass());
// Capture at least three frames, to ensure that the source frame size has
- // changed at least twice while capturing.
+ // changed to two different sizes while capturing. The mock for
+ // OnIncomingCapturedData() will use FormatChecker to examine the format of
+ // each frame being delivered.
+ for (int i = 0; i < 3; ++i) {
+ EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
+ done_event.Reset();
+ }
+
+ capture_device_->StopAndDeAllocate();
+}
+
+// This test verifies that an unpacked frame is converted to a packed frame.
+TEST_F(DesktopCaptureDeviceTest, UnpackedFrame) {
+ FakeScreenCapturer* mock_capturer = new FakeScreenCapturer();
+ mock_capturer->set_generate_cropped_frames(true);
+ CreateScreenCaptureDevice(scoped_ptr<webrtc::DesktopCapturer>(mock_capturer));
+
+ media::VideoCaptureFormat format;
+ base::WaitableEvent done_event(false, false);
+
+ int frame_size = 0;
+ output_frame_.reset(new webrtc::BasicDesktopFrame(
+ webrtc::DesktopSize(kTestFrameWidth1, kTestFrameHeight1)));
+
+ scoped_ptr<MockDeviceClient> client(new MockDeviceClient());
+ EXPECT_CALL(*client, OnError(_)).Times(0);
+ EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _)).WillRepeatedly(
+ DoAll(Invoke(this, &DesktopCaptureDeviceTest::CopyFrame),
+ SaveArg<1>(&frame_size),
+ InvokeWithoutArgs(&done_event, &base::WaitableEvent::Signal)));
+
+ media::VideoCaptureParams capture_params;
+ capture_params.requested_format.frame_size.SetSize(kTestFrameWidth1,
+ kTestFrameHeight1);
+ capture_params.requested_format.frame_rate = kFrameRate;
+ capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
+
+ capture_device_->AllocateAndStart(capture_params, client.Pass());
+
EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
done_event.Reset();
+ capture_device_->StopAndDeAllocate();
+
+ // Verifies that |output_frame_| has the same data as a packed frame of the
+ // same size.
+ scoped_ptr<webrtc::BasicDesktopFrame> expected_frame(CreateBasicFrame(
+ webrtc::DesktopSize(kTestFrameWidth1, kTestFrameHeight1)));
+ EXPECT_EQ(output_frame_->stride() * output_frame_->size().height(),
+ frame_size);
+ EXPECT_EQ(
+ 0, memcmp(output_frame_->data(), expected_frame->data(), frame_size));
+}
+
+// The test verifies that a bottom-to-top frame is converted to top-to-bottom.
+TEST_F(DesktopCaptureDeviceTest, InvertedFrame) {
+ FakeScreenCapturer* mock_capturer = new FakeScreenCapturer();
+ mock_capturer->set_generate_inverted_frames(true);
+ CreateScreenCaptureDevice(scoped_ptr<webrtc::DesktopCapturer>(mock_capturer));
+
+ media::VideoCaptureFormat format;
+ base::WaitableEvent done_event(false, false);
+
+ int frame_size = 0;
+ output_frame_.reset(new webrtc::BasicDesktopFrame(
+ webrtc::DesktopSize(kTestFrameWidth1, kTestFrameHeight1)));
+
+ scoped_ptr<MockDeviceClient> client(new MockDeviceClient());
+ EXPECT_CALL(*client, OnError(_)).Times(0);
+ EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _)).WillRepeatedly(
+ DoAll(Invoke(this, &DesktopCaptureDeviceTest::CopyFrame),
+ SaveArg<1>(&frame_size),
+ InvokeWithoutArgs(&done_event, &base::WaitableEvent::Signal)));
+
+ media::VideoCaptureParams capture_params;
+ capture_params.requested_format.frame_size.SetSize(kTestFrameWidth1,
+ kTestFrameHeight1);
+ capture_params.requested_format.frame_rate = kFrameRate;
+ capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
+
+ capture_device_->AllocateAndStart(capture_params, client.Pass());
+
EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
done_event.Reset();
- EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
-
capture_device_->StopAndDeAllocate();
- EXPECT_EQ(kTestFrameWidth1, format.frame_size.width());
- EXPECT_EQ(kTestFrameHeight1, format.frame_size.height());
- EXPECT_EQ(kFrameRate, format.frame_rate);
- EXPECT_EQ(media::PIXEL_FORMAT_ARGB, format.pixel_format);
+ // Verifies that |output_frame_| has the same pixel values as the inverted
+ // frame.
+ scoped_ptr<webrtc::DesktopFrame> inverted_frame(
+ new InvertedDesktopFrame(CreateBasicFrame(
+ webrtc::DesktopSize(kTestFrameWidth1, kTestFrameHeight1))));
+ EXPECT_EQ(output_frame_->stride() * output_frame_->size().height(),
+ frame_size);
+ for (int i = 0; i < output_frame_->size().height(); ++i) {
+ EXPECT_EQ(0,
+ memcmp(inverted_frame->data() + i * inverted_frame->stride(),
+ output_frame_->data() + i * output_frame_->stride(),
+ output_frame_->stride()));
+ }
}
} // namespace content
diff --git a/chromium/content/browser/media/capture/feedback_signal_accumulator.cc b/chromium/content/browser/media/capture/feedback_signal_accumulator.cc
new file mode 100644
index 00000000000..43d6d833c71
--- /dev/null
+++ b/chromium/content/browser/media/capture/feedback_signal_accumulator.cc
@@ -0,0 +1,56 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/media/capture/feedback_signal_accumulator.h"
+
+#include <algorithm>
+#include <cmath>
+
+namespace content {
+
+FeedbackSignalAccumulator::FeedbackSignalAccumulator(base::TimeDelta half_life)
+ : half_life_(half_life) {
+ DCHECK(half_life_ > base::TimeDelta());
+}
+
+void FeedbackSignalAccumulator::Reset(double starting_value,
+ base::TimeTicks timestamp) {
+ DCHECK(!timestamp.is_null());
+ average_ = update_value_ = prior_average_ = starting_value;
+ reset_time_ = update_time_ = prior_update_time_ = timestamp;
+}
+
+bool FeedbackSignalAccumulator::Update(double value,
+ base::TimeTicks timestamp) {
+ DCHECK(!reset_time_.is_null());
+
+ if (timestamp < update_time_) {
+ return false; // Not in chronological order.
+ } else if (timestamp == update_time_) {
+ if (timestamp == reset_time_) {
+ // Edge case: Multiple updates at reset timestamp.
+ average_ = update_value_ = prior_average_ =
+ std::max(value, update_value_);
+ return true;
+ }
+ if (value <= update_value_)
+ return true;
+ update_value_ = value;
+ } else {
+ prior_average_ = average_;
+ prior_update_time_ = update_time_;
+ update_value_ = value;
+ update_time_ = timestamp;
+ }
+
+ const double elapsed_us =
+ static_cast<double>((update_time_ - prior_update_time_).InMicroseconds());
+ const double weight = elapsed_us / (elapsed_us + half_life_.InMicroseconds());
+ average_ = weight * update_value_ + (1.0 - weight) * prior_average_;
+ DCHECK(std::isfinite(average_));
+
+ return true;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/media/capture/feedback_signal_accumulator.h b/chromium/content/browser/media/capture/feedback_signal_accumulator.h
new file mode 100644
index 00000000000..6d86109e473
--- /dev/null
+++ b/chromium/content/browser/media/capture/feedback_signal_accumulator.h
@@ -0,0 +1,67 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_MEDIA_CAPTURE_FEEDBACK_SIGNAL_ACCUMULATOR_H_
+#define CONTENT_BROWSER_MEDIA_CAPTURE_FEEDBACK_SIGNAL_ACCUMULATOR_H_
+
+#include "base/time/time.h"
+#include "content/common/content_export.h"
+
+namespace content {
+
+// Utility class for maintaining an exponentially-decaying average of feedback
+// signal values whose updates occur at undetermined, possibly irregular time
+// intervals.
+//
+// Feedback signals can be made by multiple sources. Meaning, there can be
+// several values provided for the same timestamp. In this case, the greatest
+// value is retained and used to re-compute the average. Therefore, the values
+// provided to this class' methods should be appropriately translated with this
+// in mind. For example, an "fraction available" metric should be translated
+// into a "fraction utilized" one.
+//
+// Usage note: Reset() must be called at least once before the first call to
+// Update().
+class CONTENT_EXPORT FeedbackSignalAccumulator {
+ public:
+ // |half_life| is the amount of time that must pass between two data points to
+ // move the accumulated average value halfway in-between. Example: If
+ // |half_life| is one second, then calling Reset(0.0, t=0s) and then
+ // Update(1.0, t=1s) will result in an accumulated average value of 0.5.
+ explicit FeedbackSignalAccumulator(base::TimeDelta half_life);
+
+ // Erase all memory of historical values, re-starting with the given
+ // |starting_value|.
+ void Reset(double starting_value, base::TimeTicks timestamp);
+ base::TimeTicks reset_time() const { return reset_time_; }
+
+ // Apply the given |value|, which was observed at the given |timestamp|, to
+ // the accumulated average. If the timestamp is in chronological order, the
+ // update succeeds and this method returns true. Otherwise the update has no
+ // effect and false is returned. If there are two or more updates at the same
+ // |timestamp|, only the one with the greatest value will be accounted for
+ // (see class comments for elaboration).
+ bool Update(double value, base::TimeTicks timestamp);
+ base::TimeTicks update_time() const { return update_time_; }
+
+ // Returns the current accumulated average value.
+ double current() const { return average_; }
+
+ private:
+ // In conjunction with the |update_time_| and |prior_update_time_|, this is
+ // used to compute the weight of the current update value versus the prior
+ // accumulated average.
+ const base::TimeDelta half_life_;
+
+ base::TimeTicks reset_time_; // |timestamp| passed in last call to Reset().
+ double average_; // Current accumulated average.
+ double update_value_; // Latest |value| accepted by Update().
+ base::TimeTicks update_time_; // Latest |timestamp| accepted by Update().
+ double prior_average_; // Accumulated average before last call to Update().
+ base::TimeTicks prior_update_time_; // |timestamp| in prior call to Update().
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_MEDIA_CAPTURE_FEEDBACK_SIGNAL_ACCUMULATOR_H_
diff --git a/chromium/content/browser/media/capture/feedback_signal_accumulator_unittest.cc b/chromium/content/browser/media/capture/feedback_signal_accumulator_unittest.cc
new file mode 100644
index 00000000000..50d187e790b
--- /dev/null
+++ b/chromium/content/browser/media/capture/feedback_signal_accumulator_unittest.cc
@@ -0,0 +1,202 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/media/capture/feedback_signal_accumulator.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+class FeedbackSignalAccumulatorTest : public ::testing::Test {
+ public:
+ FeedbackSignalAccumulatorTest()
+ : half_life_(base::TimeDelta::FromSeconds(1)),
+ acc_(half_life_),
+ t_(base::TimeTicks() + base::TimeDelta::FromSeconds(120)) {
+ acc_.Reset(0.0, t_);
+ }
+
+ protected:
+ const base::TimeDelta half_life_;
+ FeedbackSignalAccumulator acc_;
+ base::TimeTicks t_;
+};
+
+TEST_F(FeedbackSignalAccumulatorTest, HasCorrectStartingValueAfterReset) {
+ ASSERT_EQ(0.0, acc_.current());
+ ASSERT_EQ(t_, acc_.reset_time());
+ ASSERT_EQ(t_, acc_.update_time());
+
+ acc_.Reset(1.0, t_);
+ ASSERT_EQ(1.0, acc_.current());
+ ASSERT_EQ(t_, acc_.reset_time());
+ ASSERT_EQ(t_, acc_.update_time());
+
+ t_ += half_life_;
+ acc_.Reset(2.0, t_);
+ ASSERT_EQ(2.0, acc_.current());
+ ASSERT_EQ(t_, acc_.reset_time());
+ ASSERT_EQ(t_, acc_.update_time());
+}
+
+TEST_F(FeedbackSignalAccumulatorTest, DoesNotUpdateIfBeforeResetTime) {
+ acc_.Reset(0.0, t_);
+ ASSERT_EQ(0.0, acc_.current());
+ ASSERT_EQ(t_, acc_.update_time());
+
+ const base::TimeTicks one_usec_before =
+ t_ - base::TimeDelta::FromMicroseconds(1);
+ ASSERT_FALSE(acc_.Update(1.0, one_usec_before));
+ ASSERT_EQ(0.0, acc_.current());
+ ASSERT_EQ(t_, acc_.update_time());
+
+ const base::TimeTicks one_usec_after =
+ t_ + base::TimeDelta::FromMicroseconds(1);
+ ASSERT_TRUE(acc_.Update(1.0, one_usec_after));
+ ASSERT_LT(0.0, acc_.current());
+ ASSERT_EQ(one_usec_after, acc_.update_time());
+}
+
+TEST_F(FeedbackSignalAccumulatorTest, TakesMaxOfUpdatesAtResetTime) {
+ acc_.Reset(0.0, t_);
+ ASSERT_EQ(0.0, acc_.current());
+ ASSERT_EQ(t_, acc_.update_time());
+
+ ASSERT_TRUE(acc_.Update(1.0, t_));
+ ASSERT_EQ(1.0, acc_.current());
+ ASSERT_EQ(t_, acc_.update_time());
+
+ ASSERT_TRUE(acc_.Update(2.0, t_));
+ ASSERT_EQ(2.0, acc_.current());
+ ASSERT_EQ(t_, acc_.update_time());
+
+ ASSERT_TRUE(acc_.Update(1.0, t_));
+ ASSERT_EQ(2.0, acc_.current());
+ ASSERT_EQ(t_, acc_.update_time());
+}
+
+TEST_F(FeedbackSignalAccumulatorTest, AppliesMaxOfUpdatesWithSameTimestamp) {
+ acc_.Reset(0.0, t_);
+ ASSERT_EQ(0.0, acc_.current());
+ ASSERT_EQ(t_, acc_.update_time());
+ t_ += 1 * half_life_;
+
+ // Update with an identical value at the same timestamp.
+ for (int i = 0; i < 3; ++i) {
+ ASSERT_TRUE(acc_.Update(1.0, t_));
+ ASSERT_EQ(0.5, acc_.current());
+ ASSERT_EQ(t_, acc_.update_time());
+ }
+
+ // Now continue updating with different values at the same timestamp.
+ ASSERT_TRUE(acc_.Update(2.0, t_));
+ ASSERT_EQ(1.0, acc_.current());
+ ASSERT_EQ(t_, acc_.update_time());
+ ASSERT_TRUE(acc_.Update(3.0, t_));
+ ASSERT_EQ(1.5, acc_.current());
+ ASSERT_EQ(t_, acc_.update_time());
+ ASSERT_TRUE(acc_.Update(1.0, t_));
+ ASSERT_EQ(1.5, acc_.current());
+ ASSERT_EQ(t_, acc_.update_time());
+}
+
+TEST_F(FeedbackSignalAccumulatorTest, ProvidesExpectedHoldResponse) {
+ // Step one half-life interval per update.
+ acc_.Reset(0.0, t_);
+ ASSERT_EQ(0.0, acc_.current());
+ ASSERT_EQ(t_, acc_.update_time());
+ t_ += 1 * half_life_;
+ ASSERT_TRUE(acc_.Update(1.0, t_));
+ ASSERT_EQ(0.5, acc_.current());
+ ASSERT_EQ(t_, acc_.update_time());
+ t_ += 1 * half_life_;
+ ASSERT_TRUE(acc_.Update(1.0, t_));
+ ASSERT_EQ(0.75, acc_.current());
+ ASSERT_EQ(t_, acc_.update_time());
+ t_ += 1 * half_life_;
+ ASSERT_TRUE(acc_.Update(1.0, t_));
+ ASSERT_EQ(0.875, acc_.current());
+ ASSERT_EQ(t_, acc_.update_time());
+ t_ += 1 * half_life_;
+ ASSERT_TRUE(acc_.Update(1.0, t_));
+ ASSERT_EQ(0.9375, acc_.current());
+ ASSERT_EQ(t_, acc_.update_time());
+
+ // Step two half-life intervals per update.
+ acc_.Reset(0.0, t_);
+ ASSERT_EQ(0.0, acc_.current());
+ ASSERT_EQ(t_, acc_.update_time());
+ t_ += 2 * half_life_;
+ ASSERT_TRUE(acc_.Update(1.0, t_));
+ ASSERT_NEAR(0.666666667, acc_.current(), 0.000000001);
+ ASSERT_EQ(t_, acc_.update_time());
+ t_ += 2 * half_life_;
+ ASSERT_TRUE(acc_.Update(1.0, t_));
+ ASSERT_NEAR(0.888888889, acc_.current(), 0.000000001);
+ ASSERT_EQ(t_, acc_.update_time());
+ t_ += 2 * half_life_;
+ ASSERT_TRUE(acc_.Update(1.0, t_));
+ ASSERT_NEAR(0.962962963, acc_.current(), 0.000000001);
+ ASSERT_EQ(t_, acc_.update_time());
+ t_ += 2 * half_life_;
+ ASSERT_TRUE(acc_.Update(1.0, t_));
+ ASSERT_NEAR(0.987654321, acc_.current(), 0.000000001);
+ ASSERT_EQ(t_, acc_.update_time());
+
+ // Step three half-life intervals per update.
+ acc_.Reset(0.0, t_);
+ ASSERT_EQ(0.0, acc_.current());
+ ASSERT_EQ(t_, acc_.update_time());
+ t_ += 3 * half_life_;
+ ASSERT_TRUE(acc_.Update(1.0, t_));
+ ASSERT_EQ(0.75, acc_.current());
+ ASSERT_EQ(t_, acc_.update_time());
+ t_ += 3 * half_life_;
+ ASSERT_TRUE(acc_.Update(1.0, t_));
+ ASSERT_EQ(0.9375, acc_.current());
+ ASSERT_EQ(t_, acc_.update_time());
+ t_ += 3 * half_life_;
+ ASSERT_TRUE(acc_.Update(1.0, t_));
+ ASSERT_EQ(0.984375, acc_.current());
+ ASSERT_EQ(t_, acc_.update_time());
+ t_ += 3 * half_life_;
+ ASSERT_TRUE(acc_.Update(1.0, t_));
+ ASSERT_EQ(0.99609375, acc_.current());
+ ASSERT_EQ(t_, acc_.update_time());
+}
+
+TEST_F(FeedbackSignalAccumulatorTest, IgnoresUpdatesThatAreOutOfOrder) {
+ // First, go forward several steps, in order.
+ acc_.Reset(0.0, t_);
+ ASSERT_EQ(0.0, acc_.current());
+ ASSERT_EQ(t_, acc_.update_time());
+ t_ += 1 * half_life_;
+ ASSERT_TRUE(acc_.Update(2.0, t_));
+ ASSERT_EQ(1.0, acc_.current());
+ ASSERT_EQ(t_, acc_.update_time());
+ t_ += 1 * half_life_;
+ ASSERT_TRUE(acc_.Update(2.0, t_));
+ ASSERT_EQ(1.5, acc_.current());
+ ASSERT_EQ(t_, acc_.update_time());
+ t_ += 1 * half_life_;
+ ASSERT_TRUE(acc_.Update(2.0, t_));
+ ASSERT_EQ(1.75, acc_.current());
+ ASSERT_EQ(t_, acc_.update_time());
+ t_ += 1 * half_life_;
+ ASSERT_TRUE(acc_.Update(2.0, t_));
+ ASSERT_EQ(1.875, acc_.current());
+ ASSERT_EQ(t_, acc_.update_time());
+
+ // Go back 1 steps, then 1.5, then 2, then 2.5, etc. and expect the update to
+ // fail each time.
+ base::TimeTicks earlier = t_ - 1 * half_life_;
+ for (int i = 0; i < 5; ++i) {
+ ASSERT_FALSE(acc_.Update(999.0, earlier));
+ ASSERT_EQ(1.875, acc_.current());
+ ASSERT_EQ(t_, acc_.update_time());
+ earlier -= half_life_ / 2;
+ }
+}
+
+} // namespace content
diff --git a/chromium/content/browser/media/capture/smooth_event_sampler.cc b/chromium/content/browser/media/capture/smooth_event_sampler.cc
new file mode 100644
index 00000000000..a1638fd4e08
--- /dev/null
+++ b/chromium/content/browser/media/capture/smooth_event_sampler.cc
@@ -0,0 +1,100 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/media/capture/smooth_event_sampler.h"
+
+#include <algorithm>
+
+#include "base/trace_event/trace_event.h"
+
+namespace content {
+
+namespace {
+
+// The maximum amount of time that can elapse before considering unchanged
+// content as dirty for the purposes of timer-based overdue sampling. This is
+// the same value found in cc::FrameRateCounter.
+const int kOverdueDirtyThresholdMillis = 250; // 4 FPS
+
+} // anonymous namespace
+
+SmoothEventSampler::SmoothEventSampler(base::TimeDelta min_capture_period,
+ int redundant_capture_goal)
+ : redundant_capture_goal_(redundant_capture_goal),
+ overdue_sample_count_(0),
+ token_bucket_(base::TimeDelta::Max()) {
+ SetMinCapturePeriod(min_capture_period);
+}
+
+void SmoothEventSampler::SetMinCapturePeriod(base::TimeDelta period) {
+ DCHECK_GT(period, base::TimeDelta());
+ min_capture_period_ = period;
+ token_bucket_capacity_ = period + period / 2;
+ token_bucket_ = std::min(token_bucket_capacity_, token_bucket_);
+}
+
+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
+ // number of tokens in the bucket. Overflow occurs when there is too much
+ // time between events (a common case), or when RecordSample() is not being
+ // called often enough (a bug). On the other hand, if RecordSample() is being
+ // called too often (e.g., as a reaction to IsOverdueForSamplingAt()), the
+ // bucket will underflow.
+ if (!current_event_.is_null()) {
+ if (current_event_ < event_time) {
+ token_bucket_ += event_time - current_event_;
+ if (token_bucket_ > token_bucket_capacity_)
+ token_bucket_ = token_bucket_capacity_;
+ }
+ TRACE_COUNTER1("gpu.capture",
+ "MirroringTokenBucketUsec",
+ std::max<int64>(0, token_bucket_.InMicroseconds()));
+ }
+ current_event_ = event_time;
+}
+
+bool SmoothEventSampler::ShouldSample() const {
+ return token_bucket_ >= min_capture_period_;
+}
+
+void SmoothEventSampler::RecordSample() {
+ token_bucket_ -= min_capture_period_;
+ if (token_bucket_ < base::TimeDelta())
+ token_bucket_ = base::TimeDelta();
+ TRACE_COUNTER1("gpu.capture",
+ "MirroringTokenBucketUsec",
+ std::max<int64>(0, token_bucket_.InMicroseconds()));
+
+ if (HasUnrecordedEvent()) {
+ last_sample_ = current_event_;
+ overdue_sample_count_ = 0;
+ } else {
+ ++overdue_sample_count_;
+ }
+}
+
+bool SmoothEventSampler::IsOverdueForSamplingAt(base::TimeTicks event_time)
+ const {
+ DCHECK(!event_time.is_null());
+
+ if (!HasUnrecordedEvent() && overdue_sample_count_ >= redundant_capture_goal_)
+ return false; // Not dirty.
+
+ if (last_sample_.is_null())
+ return true;
+
+ // 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_;
+ return dirty_interval >=
+ base::TimeDelta::FromMilliseconds(kOverdueDirtyThresholdMillis);
+}
+
+bool SmoothEventSampler::HasUnrecordedEvent() const {
+ return !current_event_.is_null() && current_event_ != last_sample_;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/media/capture/smooth_event_sampler.h b/chromium/content/browser/media/capture/smooth_event_sampler.h
new file mode 100644
index 00000000000..886e6fbc488
--- /dev/null
+++ b/chromium/content/browser/media/capture/smooth_event_sampler.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_MEDIA_CAPTURE_SMOOTH_EVENT_SAMPLER_H_
+#define CONTENT_BROWSER_MEDIA_CAPTURE_SMOOTH_EVENT_SAMPLER_H_
+
+#include "base/time/time.h"
+#include "content/common/content_export.h"
+
+namespace content {
+
+// Filters a sequence of events to achieve a target frequency.
+class CONTENT_EXPORT SmoothEventSampler {
+ public:
+ SmoothEventSampler(base::TimeDelta min_capture_period,
+ int redundant_capture_goal);
+
+ // Get/Set minimum capture period. When setting a new value, the state of the
+ // sampler is retained so that sampling will continue smoothly.
+ base::TimeDelta min_capture_period() const { return min_capture_period_; }
+ void SetMinCapturePeriod(base::TimeDelta p);
+
+ // 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);
+
+ // Returns true if the last event considered should be sampled.
+ bool ShouldSample() const;
+
+ // 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();
+
+ // Returns true if, at time |event_time|, sampling should occur because too
+ // much time will have passed relative to the last event and/or sample.
+ bool IsOverdueForSamplingAt(base::TimeTicks event_time) const;
+
+ // Returns true if ConsiderPresentationEvent() has been called since the last
+ // call to RecordSample().
+ bool HasUnrecordedEvent() const;
+
+ private:
+ base::TimeDelta min_capture_period_;
+ const int redundant_capture_goal_;
+ base::TimeDelta token_bucket_capacity_;
+
+ base::TimeTicks current_event_;
+ base::TimeTicks last_sample_;
+ int overdue_sample_count_;
+ base::TimeDelta token_bucket_;
+
+ DISALLOW_COPY_AND_ASSIGN(SmoothEventSampler);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_MEDIA_CAPTURE_SMOOTH_EVENT_SAMPLER_H_
diff --git a/chromium/content/browser/media/capture/smooth_event_sampler_unittest.cc b/chromium/content/browser/media/capture/smooth_event_sampler_unittest.cc
new file mode 100644
index 00000000000..cfa974d0904
--- /dev/null
+++ b/chromium/content/browser/media/capture/smooth_event_sampler_unittest.cc
@@ -0,0 +1,488 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/media/capture/smooth_event_sampler.h"
+
+#include "base/strings/stringprintf.h"
+#include "testing/gtest/include/gtest/gtest.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(AddEventAndConsiderSampling(sampler, *t));
+ ASSERT_TRUE(sampler->HasUnrecordedEvent());
+ sampler->RecordSample();
+ ASSERT_FALSE(sampler->HasUnrecordedEvent());
+ ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t));
+ *t += vsync;
+ ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t));
+}
+
+void SteadyStateNoSampleAndAdvance(base::TimeDelta vsync,
+ SmoothEventSampler* sampler,
+ base::TimeTicks* t) {
+ ASSERT_FALSE(AddEventAndConsiderSampling(sampler, *t));
+ ASSERT_TRUE(sampler->HasUnrecordedEvent());
+ ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t));
+ *t += vsync;
+ ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t));
+}
+
+base::TimeTicks InitialTestTimeTicks() {
+ return base::TimeTicks() + base::TimeDelta::FromSeconds(1);
+}
+
+void TestRedundantCaptureStrategy(base::TimeDelta capture_period,
+ int redundant_capture_goal,
+ SmoothEventSampler* sampler,
+ base::TimeTicks* t) {
+ // Before any events have been considered, we're overdue for sampling.
+ ASSERT_TRUE(sampler->IsOverdueForSamplingAt(*t));
+
+ // Consider the first event. We want to sample that.
+ ASSERT_FALSE(sampler->HasUnrecordedEvent());
+ ASSERT_TRUE(AddEventAndConsiderSampling(sampler, *t));
+ ASSERT_TRUE(sampler->HasUnrecordedEvent());
+ sampler->RecordSample();
+ ASSERT_FALSE(sampler->HasUnrecordedEvent());
+
+ // 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());
+ ASSERT_TRUE(sampler->IsOverdueForSamplingAt(*t))
+ << "Should sample until redundant capture goal is hit";
+ sampler->RecordSample();
+ *t += capture_period; // Timer fires once every capture period.
+ }
+ ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t))
+ << "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) {
+ const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30;
+ const int redundant_capture_goal = 200;
+ const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 60;
+
+ SmoothEventSampler sampler(capture_period, redundant_capture_goal);
+ base::TimeTicks t = InitialTestTimeTicks();
+
+ TestRedundantCaptureStrategy(capture_period, redundant_capture_goal,
+ &sampler, &t);
+
+ // Steady state, we should capture every other vsync, indefinitely.
+ for (int i = 0; i < 100; i++) {
+ SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
+ SteadyStateSampleAndAdvance(vsync, &sampler, &t);
+ SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
+ }
+
+ // 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 < 20; i++) {
+ SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
+ ASSERT_EQ(i >= 14, sampler.IsOverdueForSamplingAt(t));
+ ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t));
+ ASSERT_TRUE(sampler.HasUnrecordedEvent());
+ t += vsync;
+ }
+
+ // Now suppose we can sample again. We should be back in the steady state,
+ // but at a different phase.
+ ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t));
+ for (int i = 0; i < 100; i++) {
+ SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
+ SteadyStateSampleAndAdvance(vsync, &sampler, &t);
+ SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
+ }
+}
+
+// 50Hz sampled at 30Hz should produce a sequence where some frames are skipped.
+TEST(SmoothEventSamplerTest, Sample50HertzAt30Hertz) {
+ const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30;
+ const int redundant_capture_goal = 2;
+ const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 50;
+
+ SmoothEventSampler sampler(capture_period, redundant_capture_goal);
+ base::TimeTicks t = InitialTestTimeTicks();
+
+ TestRedundantCaptureStrategy(capture_period, redundant_capture_goal,
+ &sampler, &t);
+
+ // Steady state, we should capture 1st, 2nd and 4th frames out of every five
+ // frames, indefinitely.
+ for (int i = 0; i < 100; i++) {
+ SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
+ SteadyStateSampleAndAdvance(vsync, &sampler, &t);
+ SteadyStateSampleAndAdvance(vsync, &sampler, &t);
+ SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
+ SteadyStateSampleAndAdvance(vsync, &sampler, &t);
+ SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
+ }
+
+ // 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 < 20; i++) {
+ SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
+ ASSERT_EQ(i >= 11, sampler.IsOverdueForSamplingAt(t));
+ ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t));
+ t += vsync;
+ }
+
+ // Now suppose we can sample again. We should be back in the steady state
+ // again.
+ ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t));
+ for (int i = 0; i < 100; i++) {
+ SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
+ SteadyStateSampleAndAdvance(vsync, &sampler, &t);
+ SteadyStateSampleAndAdvance(vsync, &sampler, &t);
+ SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
+ SteadyStateSampleAndAdvance(vsync, &sampler, &t);
+ SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
+ }
+}
+
+// 75Hz sampled at 30Hz should produce a sequence where some frames are skipped.
+TEST(SmoothEventSamplerTest, Sample75HertzAt30Hertz) {
+ const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30;
+ const int redundant_capture_goal = 32;
+ const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 75;
+
+ SmoothEventSampler sampler(capture_period, redundant_capture_goal);
+ base::TimeTicks t = InitialTestTimeTicks();
+
+ TestRedundantCaptureStrategy(capture_period, redundant_capture_goal,
+ &sampler, &t);
+
+ // Steady state, we should capture 1st and 3rd frames out of every five
+ // frames, indefinitely.
+ SteadyStateSampleAndAdvance(vsync, &sampler, &t);
+ SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
+ for (int i = 0; i < 100; i++) {
+ SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
+ SteadyStateSampleAndAdvance(vsync, &sampler, &t);
+ SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
+ SteadyStateSampleAndAdvance(vsync, &sampler, &t);
+ SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
+ SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
+ }
+
+ // 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 < 20; i++) {
+ SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
+ ASSERT_EQ(i >= 16, sampler.IsOverdueForSamplingAt(t));
+ ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t));
+ t += vsync;
+ }
+
+ // Now suppose we can sample again. We capture the next frame, and not the one
+ // after that, and then we're back in the steady state again.
+ ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t));
+ SteadyStateSampleAndAdvance(vsync, &sampler, &t);
+ SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
+ for (int i = 0; i < 100; i++) {
+ SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
+ SteadyStateSampleAndAdvance(vsync, &sampler, &t);
+ SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
+ SteadyStateSampleAndAdvance(vsync, &sampler, &t);
+ SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
+ SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
+ }
+}
+
+// 30Hz sampled at 30Hz should produce 30Hz.
+TEST(SmoothEventSamplerTest, Sample30HertzAt30Hertz) {
+ const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30;
+ const int redundant_capture_goal = 1;
+ const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 30;
+
+ SmoothEventSampler sampler(capture_period, redundant_capture_goal);
+ base::TimeTicks t = InitialTestTimeTicks();
+
+ TestRedundantCaptureStrategy(capture_period, redundant_capture_goal,
+ &sampler, &t);
+
+ // Steady state, we should capture every vsync, indefinitely.
+ for (int i = 0; i < 200; i++) {
+ SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
+ SteadyStateSampleAndAdvance(vsync, &sampler, &t);
+ }
+
+ // 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 < 10; i++) {
+ SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
+ ASSERT_EQ(i >= 7, sampler.IsOverdueForSamplingAt(t));
+ ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t));
+ t += vsync;
+ }
+
+ // Now suppose we can sample again. We should be back in the steady state.
+ ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t));
+ for (int i = 0; i < 100; i++) {
+ SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
+ SteadyStateSampleAndAdvance(vsync, &sampler, &t);
+ }
+}
+
+// 24Hz sampled at 30Hz should produce 24Hz.
+TEST(SmoothEventSamplerTest, Sample24HertzAt30Hertz) {
+ const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30;
+ const int redundant_capture_goal = 333;
+ const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 24;
+
+ SmoothEventSampler sampler(capture_period, redundant_capture_goal);
+ base::TimeTicks t = InitialTestTimeTicks();
+
+ TestRedundantCaptureStrategy(capture_period, redundant_capture_goal,
+ &sampler, &t);
+
+ // Steady state, we should capture every vsync, indefinitely.
+ for (int i = 0; i < 200; i++) {
+ SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
+ SteadyStateSampleAndAdvance(vsync, &sampler, &t);
+ }
+
+ // 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 < 10; i++) {
+ SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
+ ASSERT_EQ(i >= 6, sampler.IsOverdueForSamplingAt(t));
+ ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t));
+ t += vsync;
+ }
+
+ // Now suppose we can sample again. We should be back in the steady state.
+ ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t));
+ for (int i = 0; i < 100; i++) {
+ SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
+ SteadyStateSampleAndAdvance(vsync, &sampler, &t);
+ }
+}
+
+// Tests that changing the minimum capture period during usage results in the
+// desired behavior.
+TEST(SmoothEventSamplerTest, Sample60HertzWithVariedCapturePeriods) {
+ const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 60;
+ const base::TimeDelta one_to_one_period = vsync;
+ const base::TimeDelta two_to_one_period = vsync * 2;
+ const base::TimeDelta two_and_three_to_one_period =
+ base::TimeDelta::FromSeconds(1) / 24;
+ const int redundant_capture_goal = 1;
+
+ SmoothEventSampler sampler(one_to_one_period, redundant_capture_goal);
+ base::TimeTicks t = InitialTestTimeTicks();
+
+ TestRedundantCaptureStrategy(one_to_one_period, redundant_capture_goal,
+ &sampler, &t);
+
+ // With the capture rate at 60 Hz, we should capture every vsync.
+ for (int i = 0; i < 100; i++) {
+ SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
+ SteadyStateSampleAndAdvance(vsync, &sampler, &t);
+ }
+
+ // Now change to the capture rate to 30 Hz, and we should capture every other
+ // vsync.
+ sampler.SetMinCapturePeriod(two_to_one_period);
+ for (int i = 0; i < 100; i++) {
+ SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
+ SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
+ SteadyStateSampleAndAdvance(vsync, &sampler, &t);
+ }
+
+ // Now change the capture rate back to 60 Hz, and we should capture every
+ // vsync again.
+ sampler.SetMinCapturePeriod(one_to_one_period);
+ for (int i = 0; i < 100; i++) {
+ SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
+ SteadyStateSampleAndAdvance(vsync, &sampler, &t);
+ }
+
+ // Now change the capture rate to 24 Hz, and we should capture with a 2-3-2-3
+ // cadence.
+ sampler.SetMinCapturePeriod(two_and_three_to_one_period);
+ for (int i = 0; i < 100; i++) {
+ SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
+ SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
+ SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
+ SteadyStateSampleAndAdvance(vsync, &sampler, &t);
+ SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
+ SteadyStateSampleAndAdvance(vsync, &sampler, &t);
+ }
+}
+
+TEST(SmoothEventSamplerTest, DoubleDrawAtOneTimeStillDirties) {
+ const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30;
+ const base::TimeDelta overdue_period = base::TimeDelta::FromSeconds(1);
+
+ SmoothEventSampler sampler(capture_period, 1);
+ base::TimeTicks t = InitialTestTimeTicks();
+
+ 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(AddEventAndConsiderSampling(&sampler, t));
+ sampler.RecordSample();
+ 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.";
+ sampler.RecordSample();
+ ASSERT_FALSE(sampler.IsOverdueForSamplingAt(t + overdue_period));
+}
+
+namespace {
+
+struct DataPoint {
+ bool should_capture;
+ double increment_ms;
+};
+
+void ReplayCheckingSamplerDecisions(const DataPoint* data_points,
+ size_t num_data_points,
+ SmoothEventSampler* sampler) {
+ 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,
+ 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.
+ static const DataPoint data_points[] = {
+ { true, 1437.93 }, { true, 150.484 }, { true, 217.362 }, { true, 50.161 },
+ { true, 33.44 }, { false, 0 }, { true, 16.721 }, { true, 66.88 },
+ { true, 50.161 }, { false, 0 }, { false, 0 }, { true, 50.16 },
+ { true, 33.441 }, { true, 16.72 }, { false, 16.72 }, { true, 117.041 },
+ { true, 16.72 }, { false, 16.72 }, { true, 50.161 }, { true, 50.16 },
+ { true, 33.441 }, { true, 33.44 }, { true, 33.44 }, { true, 16.72 },
+ { false, 0 }, { true, 50.161 }, { false, 0 }, { true, 33.44 },
+ { true, 16.72 }, { false, 16.721 }, { true, 66.881 }, { false, 0 },
+ { true, 33.441 }, { true, 16.72 }, { true, 50.16 }, { true, 16.72 },
+ { false, 16.721 }, { true, 50.161 }, { true, 50.16 }, { false, 0 },
+ { true, 33.441 }, { true, 50.337 }, { true, 50.183 }, { true, 16.722 },
+ { true, 50.161 }, { true, 33.441 }, { true, 50.16 }, { true, 33.441 },
+ { true, 50.16 }, { true, 33.441 }, { true, 50.16 }, { true, 33.44 },
+ { true, 50.161 }, { true, 50.16 }, { true, 33.44 }, { true, 33.441 },
+ { true, 50.16 }, { true, 50.161 }, { true, 33.44 }, { true, 33.441 },
+ { true, 50.16 }, { true, 33.44 }, { true, 50.161 }, { true, 33.44 },
+ { true, 50.161 }, { true, 33.44 }, { true, 50.161 }, { true, 33.44 },
+ { true, 83.601 }, { true, 16.72 }, { true, 33.44 }, { false, 0 }
+ };
+
+ SmoothEventSampler sampler(base::TimeDelta::FromSeconds(1) / 30, 3);
+ ReplayCheckingSamplerDecisions(data_points, arraysize(data_points), &sampler);
+}
+
+TEST(SmoothEventSamplerTest, DrawingAt30FpsWith60HzVsyncSampledAt30Hertz) {
+ // Actual capturing of timing data: Initial instability as a 30 FPS video was
+ // started from a still screen, then followed by steady-state. Drawing
+ // framerate from the video rendering was a bit volatile, but averaged 30 FPS.
+ static const DataPoint data_points[] = {
+ { true, 2407.69 }, { true, 16.733 }, { true, 217.362 }, { true, 33.441 },
+ { true, 33.44 }, { true, 33.44 }, { true, 33.441 }, { true, 33.44 },
+ { true, 33.44 }, { true, 33.441 }, { true, 33.44 }, { true, 33.44 },
+ { true, 16.721 }, { true, 33.44 }, { false, 0 }, { true, 50.161 },
+ { true, 50.16 }, { false, 0 }, { true, 50.161 }, { true, 33.44 },
+ { true, 16.72 }, { false, 0 }, { false, 16.72 }, { true, 66.881 },
+ { false, 0 }, { true, 33.44 }, { true, 16.72 }, { true, 50.161 },
+ { false, 0 }, { true, 33.538 }, { true, 33.526 }, { true, 33.447 },
+ { true, 33.445 }, { true, 33.441 }, { true, 16.721 }, { true, 33.44 },
+ { true, 33.44 }, { true, 50.161 }, { true, 16.72 }, { true, 33.44 },
+ { true, 33.441 }, { true, 33.44 }, { false, 0 }, { false, 16.72 },
+ { true, 66.881 }, { true, 16.72 }, { false, 16.72 }, { true, 50.16 },
+ { true, 33.441 }, { true, 33.44 }, { true, 33.44 }, { true, 33.44 },
+ { true, 33.441 }, { true, 33.44 }, { true, 50.161 }, { false, 0 },
+ { true, 33.44 }, { true, 33.44 }, { true, 50.161 }, { true, 16.72 },
+ { true, 33.44 }, { true, 33.441 }, { false, 0 }, { true, 66.88 },
+ { true, 33.441 }, { true, 33.44 }, { true, 33.44 }, { false, 0 },
+ { true, 33.441 }, { true, 33.44 }, { true, 33.44 }, { false, 0 },
+ { true, 16.72 }, { true, 50.161 }, { false, 0 }, { true, 50.16 },
+ { false, 0.001 }, { true, 16.721 }, { true, 66.88 }, { true, 33.44 },
+ { true, 33.441 }, { true, 33.44 }, { true, 50.161 }, { true, 16.72 },
+ { false, 0 }, { true, 33.44 }, { false, 16.72 }, { true, 66.881 },
+ { true, 33.44 }, { true, 16.72 }, { true, 33.441 }, { false, 16.72 },
+ { true, 66.88 }, { true, 16.721 }, { true, 50.16 }, { true, 33.44 },
+ { true, 16.72 }, { true, 33.441 }, { true, 33.44 }, { true, 33.44 }
+ };
+
+ SmoothEventSampler sampler(base::TimeDelta::FromSeconds(1) / 30, 3);
+ ReplayCheckingSamplerDecisions(data_points, arraysize(data_points), &sampler);
+}
+
+TEST(SmoothEventSamplerTest, DrawingAt60FpsWith60HzVsyncSampledAt30Hertz) {
+ // Actual capturing of timing data: WebGL Acquarium demo
+ // (http://webglsamples.googlecode.com/hg/aquarium/aquarium.html) which ran
+ // between 55-60 FPS in the steady-state.
+ static const DataPoint data_points[] = {
+ { true, 16.72 }, { true, 16.72 }, { true, 4163.29 }, { true, 50.193 },
+ { true, 117.041 }, { true, 50.161 }, { true, 50.16 }, { true, 33.441 },
+ { true, 50.16 }, { true, 33.44 }, { false, 0 }, { false, 0 },
+ { true, 50.161 }, { true, 83.601 }, { true, 50.16 }, { true, 16.72 },
+ { true, 33.441 }, { false, 16.72 }, { true, 50.16 }, { true, 16.72 },
+ { false, 0.001 }, { true, 33.441 }, { false, 16.72 }, { true, 16.72 },
+ { true, 50.16 }, { false, 0 }, { true, 16.72 }, { true, 33.441 },
+ { false, 0 }, { true, 33.44 }, { false, 16.72 }, { true, 16.72 },
+ { true, 50.161 }, { false, 0 }, { true, 16.72 }, { true, 33.44 },
+ { false, 0 }, { true, 33.44 }, { false, 16.721 }, { true, 16.721 },
+ { true, 50.161 }, { false, 0 }, { true, 16.72 }, { true, 33.441 },
+ { false, 0 }, { true, 33.44 }, { false, 16.72 }, { true, 33.44 },
+ { false, 0 }, { true, 16.721 }, { true, 50.161 }, { false, 0 },
+ { true, 33.44 }, { false, 0 }, { true, 16.72 }, { true, 33.441 },
+ { false, 0 }, { true, 33.44 }, { false, 16.72 }, { true, 16.72 },
+ { true, 50.16 }, { false, 0 }, { true, 16.721 }, { true, 33.44 },
+ { false, 0 }, { true, 33.44 }, { false, 16.721 }, { true, 16.721 },
+ { true, 50.161 }, { false, 0 }, { true, 16.72 }, { true, 33.44 },
+ { false, 0 }, { true, 33.441 }, { false, 16.72 }, { true, 16.72 },
+ { true, 50.16 }, { false, 0 }, { true, 16.72 }, { true, 33.441 },
+ { true, 33.44 }, { false, 0 }, { true, 33.44 }, { true, 33.441 },
+ { false, 0 }, { true, 33.44 }, { true, 33.441 }, { false, 0 },
+ { true, 33.44 }, { false, 0 }, { true, 33.44 }, { false, 16.72 },
+ { true, 16.721 }, { true, 50.161 }, { false, 0 }, { true, 16.72 },
+ { true, 33.44 }, { true, 33.441 }, { false, 0 }, { true, 33.44 },
+ { true, 33.44 }, { false, 0 }, { true, 33.441 }, { false, 16.72 },
+ { true, 16.72 }, { true, 50.16 }, { false, 0 }, { true, 16.72 },
+ { true, 33.441 }, { false, 0 }, { true, 33.44 }, { false, 16.72 },
+ { true, 33.44 }, { false, 0 }, { true, 16.721 }, { true, 50.161 },
+ { false, 0 }, { true, 16.72 }, { true, 33.44 }, { false, 0 },
+ { true, 33.441 }, { false, 16.72 }, { true, 16.72 }, { true, 50.16 }
+ };
+
+ SmoothEventSampler sampler(base::TimeDelta::FromSeconds(1) / 30, 3);
+ ReplayCheckingSamplerDecisions(data_points, arraysize(data_points), &sampler);
+}
+
+} // 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 142bfe604c5..0b675075429 100644
--- a/chromium/content/browser/media/capture/video_capture_oracle.cc
+++ b/chromium/content/browser/media/capture/video_capture_oracle.cc
@@ -6,7 +6,6 @@
#include <algorithm>
-#include "base/debug/trace_event.h"
#include "base/format_macros.h"
#include "base/strings/stringprintf.h"
@@ -25,33 +24,6 @@ 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) {
@@ -64,12 +36,10 @@ double FractionFromExpectedFrameRate(base::TimeDelta delta, int frame_rate) {
} // anonymous namespace
-VideoCaptureOracle::VideoCaptureOracle(base::TimeDelta min_capture_period,
- bool events_are_reliable)
+VideoCaptureOracle::VideoCaptureOracle(base::TimeDelta min_capture_period)
: frame_number_(0),
last_delivered_frame_number_(-1),
smoothing_sampler_(min_capture_period,
- events_are_reliable,
kNumRedundantCapturesOfStaticContent),
content_sampler_(min_capture_period) {
}
@@ -92,7 +62,6 @@ bool VideoCaptureOracle::ObserveEventAndDecideCapture(
bool should_sample;
switch (event) {
case kCompositorUpdate:
- case kSoftwarePaint:
smoothing_sampler_.ConsiderPresentationEvent(event_time);
content_sampler_.ConsiderPresentationEvent(damage_rect, event_time);
if (content_sampler_.HasProposal()) {
@@ -122,7 +91,9 @@ bool VideoCaptureOracle::CompleteCapture(int frame_number,
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.";
+ LOG(WARNING) << "Out of order frame delivery detected (have #"
+ << frame_number << ", last was #"
+ << last_delivered_frame_number_ << "). Dropping frame.";
return false;
}
last_delivered_frame_number_ = frame_number;
@@ -173,264 +144,4 @@ void VideoCaptureOracle::SetFrameTimestamp(int frame_number,
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),
- min_capture_period_(min_capture_period),
- redundant_capture_goal_(redundant_capture_goal),
- token_bucket_capacity_(min_capture_period + min_capture_period / 2),
- overdue_sample_count_(0),
- token_bucket_(token_bucket_capacity_) {
- DCHECK_GT(min_capture_period_.InMicroseconds(), 0);
-}
-
-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
- // number of tokens in the bucket. Overflow occurs when there is too much
- // time between events (a common case), or when RecordSample() is not being
- // called often enough (a bug). On the other hand, if RecordSample() is being
- // called too often (e.g., as a reaction to IsOverdueForSamplingAt()), the
- // bucket will underflow.
- if (!current_event_.is_null()) {
- if (current_event_ < event_time) {
- token_bucket_ += event_time - current_event_;
- if (token_bucket_ > token_bucket_capacity_)
- token_bucket_ = token_bucket_capacity_;
- }
- TRACE_COUNTER1("mirroring",
- "MirroringTokenBucketUsec",
- std::max<int64>(0, token_bucket_.InMicroseconds()));
- }
- current_event_ = event_time;
-}
-
-bool SmoothEventSampler::ShouldSample() const {
- return token_bucket_ >= min_capture_period_;
-}
-
-void SmoothEventSampler::RecordSample() {
- 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()));
-
- if (HasUnrecordedEvent()) {
- last_sample_ = current_event_;
- overdue_sample_count_ = 0;
- } else {
- ++overdue_sample_count_;
- }
-}
-
-bool SmoothEventSampler::IsOverdueForSamplingAt(base::TimeTicks event_time)
- const {
- DCHECK(!event_time.is_null());
-
- // If we don't get events on compositor updates on this platform, then we
- // don't reliably know whether we're dirty.
- if (events_are_reliable_) {
- if (!HasUnrecordedEvent() &&
- overdue_sample_count_ >= redundant_capture_goal_) {
- return false; // Not dirty.
- }
- }
-
- if (last_sample_.is_null())
- return true;
-
- // 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_;
- 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 32e7baff4da..706f4a92dc5 100644
--- a/chromium/content/browser/media/capture/video_capture_oracle.h
+++ b/chromium/content/browser/media/capture/video_capture_oracle.h
@@ -5,169 +5,16 @@
#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/browser/media/capture/animated_content_sampler.h"
+#include "content/browser/media/capture/smooth_event_sampler.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:
- 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);
-
- // Returns true if the last event considered should be sampled.
- bool ShouldSample() const;
-
- // 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();
-
- // Returns true if, at time |event_time|, sampling should occur because too
- // much time will have passed relative to the last event and/or sample.
- bool IsOverdueForSamplingAt(base::TimeTicks event_time) const;
-
- // 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 min_capture_period_;
- const int redundant_capture_goal_;
- const base::TimeDelta token_bucket_capacity_;
-
- base::TimeTicks current_event_;
- base::TimeTicks last_sample_;
- int overdue_sample_count_;
- base::TimeDelta token_bucket_;
-
- 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
@@ -177,12 +24,10 @@ class CONTENT_EXPORT VideoCaptureOracle {
enum Event {
kTimerPoll,
kCompositorUpdate,
- kSoftwarePaint,
kNumEvents,
};
- VideoCaptureOracle(base::TimeDelta min_capture_period,
- bool events_are_reliable);
+ explicit VideoCaptureOracle(base::TimeDelta min_capture_period);
virtual ~VideoCaptureOracle();
// Record a event of type |event|, and decide whether the caller should do a
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 1a4222ac4d5..456bc515aa8 100644
--- a/chromium/content/browser/media/capture/video_capture_oracle_unittest.cc
+++ b/chromium/content/browser/media/capture/video_capture_oracle_unittest.cc
@@ -4,1110 +4,19 @@
#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(AddEventAndConsiderSampling(sampler, *t));
- ASSERT_TRUE(sampler->HasUnrecordedEvent());
- sampler->RecordSample();
- ASSERT_FALSE(sampler->HasUnrecordedEvent());
- ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t));
- *t += vsync;
- ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t));
-}
-
-void SteadyStateNoSampleAndAdvance(base::TimeDelta vsync,
- SmoothEventSampler* sampler,
- base::TimeTicks* t) {
- ASSERT_FALSE(AddEventAndConsiderSampling(sampler, *t));
- ASSERT_TRUE(sampler->HasUnrecordedEvent());
- ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t));
- *t += vsync;
- ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t));
-}
+namespace {
base::TimeTicks InitialTestTimeTicks() {
return base::TimeTicks() + base::TimeDelta::FromSeconds(1);
}
-void TestRedundantCaptureStrategy(base::TimeDelta capture_period,
- int redundant_capture_goal,
- SmoothEventSampler* sampler,
- base::TimeTicks* t) {
- // Before any events have been considered, we're overdue for sampling.
- ASSERT_TRUE(sampler->IsOverdueForSamplingAt(*t));
-
- // Consider the first event. We want to sample that.
- ASSERT_FALSE(sampler->HasUnrecordedEvent());
- ASSERT_TRUE(AddEventAndConsiderSampling(sampler, *t));
- ASSERT_TRUE(sampler->HasUnrecordedEvent());
- sampler->RecordSample();
- ASSERT_FALSE(sampler->HasUnrecordedEvent());
-
- // 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());
- ASSERT_TRUE(sampler->IsOverdueForSamplingAt(*t))
- << "Should sample until redundant capture goal is hit";
- sampler->RecordSample();
- *t += capture_period; // Timer fires once every capture period.
- }
- ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t))
- << "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) {
- const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30;
- const int redundant_capture_goal = 200;
- const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 60;
-
- SmoothEventSampler sampler(capture_period, true, redundant_capture_goal);
- base::TimeTicks t = InitialTestTimeTicks();
-
- TestRedundantCaptureStrategy(capture_period, redundant_capture_goal,
- &sampler, &t);
-
- // Steady state, we should capture every other vsync, indefinitely.
- for (int i = 0; i < 100; i++) {
- SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
- SteadyStateSampleAndAdvance(vsync, &sampler, &t);
- SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
- }
-
- // 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 < 20; i++) {
- SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
- ASSERT_EQ(i >= 14, sampler.IsOverdueForSamplingAt(t));
- ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t));
- ASSERT_TRUE(sampler.HasUnrecordedEvent());
- t += vsync;
- }
-
- // Now suppose we can sample again. We should be back in the steady state,
- // but at a different phase.
- ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t));
- for (int i = 0; i < 100; i++) {
- SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
- SteadyStateSampleAndAdvance(vsync, &sampler, &t);
- SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
- }
-}
-
-// 50Hz sampled at 30Hz should produce a sequence where some frames are skipped.
-TEST(SmoothEventSamplerTest, Sample50HertzAt30Hertz) {
- const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30;
- const int redundant_capture_goal = 2;
- const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 50;
-
- SmoothEventSampler sampler(capture_period, true, redundant_capture_goal);
- base::TimeTicks t = InitialTestTimeTicks();
-
- TestRedundantCaptureStrategy(capture_period, redundant_capture_goal,
- &sampler, &t);
-
- // Steady state, we should capture 1st, 2nd and 4th frames out of every five
- // frames, indefinitely.
- for (int i = 0; i < 100; i++) {
- SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
- SteadyStateSampleAndAdvance(vsync, &sampler, &t);
- SteadyStateSampleAndAdvance(vsync, &sampler, &t);
- SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
- SteadyStateSampleAndAdvance(vsync, &sampler, &t);
- SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
- }
-
- // 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 < 20; i++) {
- SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
- ASSERT_EQ(i >= 11, sampler.IsOverdueForSamplingAt(t));
- ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t));
- t += vsync;
- }
-
- // Now suppose we can sample again. We should be back in the steady state
- // again.
- ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t));
- for (int i = 0; i < 100; i++) {
- SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
- SteadyStateSampleAndAdvance(vsync, &sampler, &t);
- SteadyStateSampleAndAdvance(vsync, &sampler, &t);
- SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
- SteadyStateSampleAndAdvance(vsync, &sampler, &t);
- SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
- }
-}
-
-// 75Hz sampled at 30Hz should produce a sequence where some frames are skipped.
-TEST(SmoothEventSamplerTest, Sample75HertzAt30Hertz) {
- const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30;
- const int redundant_capture_goal = 32;
- const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 75;
-
- SmoothEventSampler sampler(capture_period, true, redundant_capture_goal);
- base::TimeTicks t = InitialTestTimeTicks();
-
- TestRedundantCaptureStrategy(capture_period, redundant_capture_goal,
- &sampler, &t);
-
- // Steady state, we should capture 1st and 3rd frames out of every five
- // frames, indefinitely.
- SteadyStateSampleAndAdvance(vsync, &sampler, &t);
- SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
- for (int i = 0; i < 100; i++) {
- SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
- SteadyStateSampleAndAdvance(vsync, &sampler, &t);
- SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
- SteadyStateSampleAndAdvance(vsync, &sampler, &t);
- SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
- SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
- }
-
- // 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 < 20; i++) {
- SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
- ASSERT_EQ(i >= 16, sampler.IsOverdueForSamplingAt(t));
- ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t));
- t += vsync;
- }
-
- // Now suppose we can sample again. We capture the next frame, and not the one
- // after that, and then we're back in the steady state again.
- ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t));
- SteadyStateSampleAndAdvance(vsync, &sampler, &t);
- SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
- for (int i = 0; i < 100; i++) {
- SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
- SteadyStateSampleAndAdvance(vsync, &sampler, &t);
- SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
- SteadyStateSampleAndAdvance(vsync, &sampler, &t);
- SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
- SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
- }
-}
-
-// 30Hz sampled at 30Hz should produce 30Hz.
-TEST(SmoothEventSamplerTest, Sample30HertzAt30Hertz) {
- const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30;
- const int redundant_capture_goal = 1;
- const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 30;
-
- SmoothEventSampler sampler(capture_period, true, redundant_capture_goal);
- base::TimeTicks t = InitialTestTimeTicks();
-
- TestRedundantCaptureStrategy(capture_period, redundant_capture_goal,
- &sampler, &t);
-
- // Steady state, we should capture every vsync, indefinitely.
- for (int i = 0; i < 200; i++) {
- SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
- SteadyStateSampleAndAdvance(vsync, &sampler, &t);
- }
-
- // 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 < 10; i++) {
- SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
- ASSERT_EQ(i >= 7, sampler.IsOverdueForSamplingAt(t));
- ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t));
- t += vsync;
- }
-
- // Now suppose we can sample again. We should be back in the steady state.
- ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t));
- for (int i = 0; i < 100; i++) {
- SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
- SteadyStateSampleAndAdvance(vsync, &sampler, &t);
- }
-}
-
-// 24Hz sampled at 30Hz should produce 24Hz.
-TEST(SmoothEventSamplerTest, Sample24HertzAt30Hertz) {
- const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30;
- const int redundant_capture_goal = 333;
- const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 24;
-
- SmoothEventSampler sampler(capture_period, true, redundant_capture_goal);
- base::TimeTicks t = InitialTestTimeTicks();
-
- TestRedundantCaptureStrategy(capture_period, redundant_capture_goal,
- &sampler, &t);
-
- // Steady state, we should capture every vsync, indefinitely.
- for (int i = 0; i < 200; i++) {
- SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
- SteadyStateSampleAndAdvance(vsync, &sampler, &t);
- }
-
- // 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 < 10; i++) {
- SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
- ASSERT_EQ(i >= 6, sampler.IsOverdueForSamplingAt(t));
- ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t));
- t += vsync;
- }
-
- // Now suppose we can sample again. We should be back in the steady state.
- ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t));
- for (int i = 0; i < 100; i++) {
- SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
- SteadyStateSampleAndAdvance(vsync, &sampler, &t);
- }
-}
-
-TEST(SmoothEventSamplerTest, DoubleDrawAtOneTimeStillDirties) {
- const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30;
- const base::TimeDelta overdue_period = base::TimeDelta::FromSeconds(1);
-
- SmoothEventSampler sampler(capture_period, true, 1);
- base::TimeTicks t = InitialTestTimeTicks();
-
- 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(AddEventAndConsiderSampling(&sampler, t));
- sampler.RecordSample();
- 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.";
- sampler.RecordSample();
- ASSERT_FALSE(sampler.IsOverdueForSamplingAt(t + overdue_period));
-}
-
-TEST(SmoothEventSamplerTest, FallbackToPollingIfUpdatesUnreliable) {
- const base::TimeDelta timer_interval = base::TimeDelta::FromSeconds(1) / 30;
-
- SmoothEventSampler should_not_poll(timer_interval, true, 1);
- SmoothEventSampler should_poll(timer_interval, false, 1);
- 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(AddEventAndConsiderSampling(&should_not_poll, t));
- ASSERT_TRUE(AddEventAndConsiderSampling(&should_poll, t));
- should_not_poll.RecordSample();
- should_poll.RecordSample();
-
- // 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.";
- ASSERT_FALSE(should_poll.IsOverdueForSamplingAt(t))
- << "Dirty interval has not elapsed yet.";
- }
-
- // 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; // 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))
- << "If updates are unreliable, must fall back to polling when idle.";
- should_not_poll.RecordSample();
- should_poll.RecordSample();
-
- // Forever more, the non-polling sampler returns false while the polling one
- // returns true.
- for (int i = 0; i < 100; ++i) {
- t += timer_interval;
- ASSERT_FALSE(should_not_poll.IsOverdueForSamplingAt(t))
- << "Sampled last event; should not be dirty.";
- ASSERT_TRUE(should_poll.IsOverdueForSamplingAt(t))
- << "If updates are unreliable, must fall back to polling when idle.";
- should_poll.RecordSample();
- }
- t += timer_interval / 3;
- ASSERT_FALSE(should_not_poll.IsOverdueForSamplingAt(t))
- << "Sampled last event; should not be dirty.";
- ASSERT_TRUE(should_poll.IsOverdueForSamplingAt(t))
- << "If updates are unreliable, must fall back to polling when idle.";
- should_poll.RecordSample();
-}
-
-namespace {
-
-struct DataPoint {
- bool should_capture;
- double increment_ms;
-};
-
-void ReplayCheckingSamplerDecisions(const DataPoint* data_points,
- size_t num_data_points,
- SmoothEventSampler* sampler) {
- 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,
- 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.
- static const DataPoint data_points[] = {
- { true, 1437.93 }, { true, 150.484 }, { true, 217.362 }, { true, 50.161 },
- { true, 33.44 }, { false, 0 }, { true, 16.721 }, { true, 66.88 },
- { true, 50.161 }, { false, 0 }, { false, 0 }, { true, 50.16 },
- { true, 33.441 }, { true, 16.72 }, { false, 16.72 }, { true, 117.041 },
- { true, 16.72 }, { false, 16.72 }, { true, 50.161 }, { true, 50.16 },
- { true, 33.441 }, { true, 33.44 }, { true, 33.44 }, { true, 16.72 },
- { false, 0 }, { true, 50.161 }, { false, 0 }, { true, 33.44 },
- { true, 16.72 }, { false, 16.721 }, { true, 66.881 }, { false, 0 },
- { true, 33.441 }, { true, 16.72 }, { true, 50.16 }, { true, 16.72 },
- { false, 16.721 }, { true, 50.161 }, { true, 50.16 }, { false, 0 },
- { true, 33.441 }, { true, 50.337 }, { true, 50.183 }, { true, 16.722 },
- { true, 50.161 }, { true, 33.441 }, { true, 50.16 }, { true, 33.441 },
- { true, 50.16 }, { true, 33.441 }, { true, 50.16 }, { true, 33.44 },
- { true, 50.161 }, { true, 50.16 }, { true, 33.44 }, { true, 33.441 },
- { true, 50.16 }, { true, 50.161 }, { true, 33.44 }, { true, 33.441 },
- { true, 50.16 }, { true, 33.44 }, { true, 50.161 }, { true, 33.44 },
- { true, 50.161 }, { true, 33.44 }, { true, 50.161 }, { true, 33.44 },
- { true, 83.601 }, { true, 16.72 }, { true, 33.44 }, { false, 0 }
- };
-
- SmoothEventSampler sampler(base::TimeDelta::FromSeconds(1) / 30, true, 3);
- ReplayCheckingSamplerDecisions(data_points, arraysize(data_points), &sampler);
-}
-
-TEST(SmoothEventSamplerTest, DrawingAt30FpsWith60HzVsyncSampledAt30Hertz) {
- // Actual capturing of timing data: Initial instability as a 30 FPS video was
- // started from a still screen, then followed by steady-state. Drawing
- // framerate from the video rendering was a bit volatile, but averaged 30 FPS.
- static const DataPoint data_points[] = {
- { true, 2407.69 }, { true, 16.733 }, { true, 217.362 }, { true, 33.441 },
- { true, 33.44 }, { true, 33.44 }, { true, 33.441 }, { true, 33.44 },
- { true, 33.44 }, { true, 33.441 }, { true, 33.44 }, { true, 33.44 },
- { true, 16.721 }, { true, 33.44 }, { false, 0 }, { true, 50.161 },
- { true, 50.16 }, { false, 0 }, { true, 50.161 }, { true, 33.44 },
- { true, 16.72 }, { false, 0 }, { false, 16.72 }, { true, 66.881 },
- { false, 0 }, { true, 33.44 }, { true, 16.72 }, { true, 50.161 },
- { false, 0 }, { true, 33.538 }, { true, 33.526 }, { true, 33.447 },
- { true, 33.445 }, { true, 33.441 }, { true, 16.721 }, { true, 33.44 },
- { true, 33.44 }, { true, 50.161 }, { true, 16.72 }, { true, 33.44 },
- { true, 33.441 }, { true, 33.44 }, { false, 0 }, { false, 16.72 },
- { true, 66.881 }, { true, 16.72 }, { false, 16.72 }, { true, 50.16 },
- { true, 33.441 }, { true, 33.44 }, { true, 33.44 }, { true, 33.44 },
- { true, 33.441 }, { true, 33.44 }, { true, 50.161 }, { false, 0 },
- { true, 33.44 }, { true, 33.44 }, { true, 50.161 }, { true, 16.72 },
- { true, 33.44 }, { true, 33.441 }, { false, 0 }, { true, 66.88 },
- { true, 33.441 }, { true, 33.44 }, { true, 33.44 }, { false, 0 },
- { true, 33.441 }, { true, 33.44 }, { true, 33.44 }, { false, 0 },
- { true, 16.72 }, { true, 50.161 }, { false, 0 }, { true, 50.16 },
- { false, 0.001 }, { true, 16.721 }, { true, 66.88 }, { true, 33.44 },
- { true, 33.441 }, { true, 33.44 }, { true, 50.161 }, { true, 16.72 },
- { false, 0 }, { true, 33.44 }, { false, 16.72 }, { true, 66.881 },
- { true, 33.44 }, { true, 16.72 }, { true, 33.441 }, { false, 16.72 },
- { true, 66.88 }, { true, 16.721 }, { true, 50.16 }, { true, 33.44 },
- { true, 16.72 }, { true, 33.441 }, { true, 33.44 }, { true, 33.44 }
- };
-
- SmoothEventSampler sampler(base::TimeDelta::FromSeconds(1) / 30, true, 3);
- ReplayCheckingSamplerDecisions(data_points, arraysize(data_points), &sampler);
-}
-
-TEST(SmoothEventSamplerTest, DrawingAt60FpsWith60HzVsyncSampledAt30Hertz) {
- // Actual capturing of timing data: WebGL Acquarium demo
- // (http://webglsamples.googlecode.com/hg/aquarium/aquarium.html) which ran
- // between 55-60 FPS in the steady-state.
- static const DataPoint data_points[] = {
- { true, 16.72 }, { true, 16.72 }, { true, 4163.29 }, { true, 50.193 },
- { true, 117.041 }, { true, 50.161 }, { true, 50.16 }, { true, 33.441 },
- { true, 50.16 }, { true, 33.44 }, { false, 0 }, { false, 0 },
- { true, 50.161 }, { true, 83.601 }, { true, 50.16 }, { true, 16.72 },
- { true, 33.441 }, { false, 16.72 }, { true, 50.16 }, { true, 16.72 },
- { false, 0.001 }, { true, 33.441 }, { false, 16.72 }, { true, 16.72 },
- { true, 50.16 }, { false, 0 }, { true, 16.72 }, { true, 33.441 },
- { false, 0 }, { true, 33.44 }, { false, 16.72 }, { true, 16.72 },
- { true, 50.161 }, { false, 0 }, { true, 16.72 }, { true, 33.44 },
- { false, 0 }, { true, 33.44 }, { false, 16.721 }, { true, 16.721 },
- { true, 50.161 }, { false, 0 }, { true, 16.72 }, { true, 33.441 },
- { false, 0 }, { true, 33.44 }, { false, 16.72 }, { true, 33.44 },
- { false, 0 }, { true, 16.721 }, { true, 50.161 }, { false, 0 },
- { true, 33.44 }, { false, 0 }, { true, 16.72 }, { true, 33.441 },
- { false, 0 }, { true, 33.44 }, { false, 16.72 }, { true, 16.72 },
- { true, 50.16 }, { false, 0 }, { true, 16.721 }, { true, 33.44 },
- { false, 0 }, { true, 33.44 }, { false, 16.721 }, { true, 16.721 },
- { true, 50.161 }, { false, 0 }, { true, 16.72 }, { true, 33.44 },
- { false, 0 }, { true, 33.441 }, { false, 16.72 }, { true, 16.72 },
- { true, 50.16 }, { false, 0 }, { true, 16.72 }, { true, 33.441 },
- { true, 33.44 }, { false, 0 }, { true, 33.44 }, { true, 33.441 },
- { false, 0 }, { true, 33.44 }, { true, 33.441 }, { false, 0 },
- { true, 33.44 }, { false, 0 }, { true, 33.44 }, { false, 16.72 },
- { true, 16.721 }, { true, 50.161 }, { false, 0 }, { true, 16.72 },
- { true, 33.44 }, { true, 33.441 }, { false, 0 }, { true, 33.44 },
- { true, 33.44 }, { false, 0 }, { true, 33.441 }, { false, 16.72 },
- { true, 16.72 }, { true, 50.16 }, { false, 0 }, { true, 16.72 },
- { true, 33.441 }, { false, 0 }, { true, 33.44 }, { false, 16.72 },
- { true, 33.44 }, { false, 0 }, { true, 16.721 }, { true, 50.161 },
- { false, 0 }, { true, 16.72 }, { true, 33.44 }, { false, 0 },
- { true, 33.441 }, { false, 16.72 }, { true, 16.72 }, { true, 50.16 }
- };
-
- SmoothEventSampler sampler(base::TimeDelta::FromSeconds(1) / 30, true, 3);
- 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) {
@@ -1116,7 +25,7 @@ TEST(VideoCaptureOracleTest, EnforcesEventTimeMonotonicity) {
const gfx::Rect damage_rect(0, 0, 1280, 720);
const base::TimeDelta event_increment = min_capture_period * 2;
- VideoCaptureOracle oracle(min_capture_period, true);
+ VideoCaptureOracle oracle(min_capture_period);
base::TimeTicks t = InitialTestTimeTicks();
for (int i = 0; i < 10; ++i) {
@@ -1152,7 +61,7 @@ TEST(VideoCaptureOracleTest, EnforcesFramesDeliveredInOrder) {
const gfx::Rect damage_rect(0, 0, 1280, 720);
const base::TimeDelta event_increment = min_capture_period * 2;
- VideoCaptureOracle oracle(min_capture_period, true);
+ VideoCaptureOracle oracle(min_capture_period);
// Most basic scenario: Frames delivered one at a time, with no additional
// captures in-between deliveries.
@@ -1208,7 +117,7 @@ TEST(VideoCaptureOracleTest, TransitionsSmoothlyBetweenSamplers) {
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);
+ VideoCaptureOracle oracle(min_capture_period);
// Run sequences of animation events and non-animation events through the
// oracle. As the oracle transitions between each sampler, make sure the
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 605124dd308..8fd1f976d59 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
@@ -91,7 +91,7 @@ class WebContentsAudioInputStream::Impl
// Called by WebContentsTracker when the target of the audio mirroring has
// changed.
- void OnTargetChanged(RenderWidgetHost* target);
+ void OnTargetChanged(bool had_target);
// Injected dependencies.
const int initial_render_process_id_;
@@ -305,11 +305,10 @@ void WebContentsAudioInputStream::Impl::ReleaseInput(
delete stream;
}
-void WebContentsAudioInputStream::Impl::OnTargetChanged(
- RenderWidgetHost* target) {
+void WebContentsAudioInputStream::Impl::OnTargetChanged(bool had_target) {
DCHECK(thread_checker_.CalledOnValidThread());
- is_target_lost_ = !target;
+ is_target_lost_ = !had_target;
if (state_ == MIRRORING) {
if (is_target_lost_) {
@@ -382,8 +381,8 @@ double WebContentsAudioInputStream::GetVolume() {
return impl_->mixer_stream()->GetVolume();
}
-void WebContentsAudioInputStream::SetAutomaticGainControl(bool enabled) {
- impl_->mixer_stream()->SetAutomaticGainControl(enabled);
+bool WebContentsAudioInputStream::SetAutomaticGainControl(bool enabled) {
+ return impl_->mixer_stream()->SetAutomaticGainControl(enabled);
}
bool WebContentsAudioInputStream::GetAutomaticGainControl() {
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 d66d27004b5..ff8074d4f0e 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
@@ -44,7 +44,7 @@ class CONTENT_EXPORT WebContentsAudioInputStream
double GetMaxVolume() override;
void SetVolume(double volume) override;
double GetVolume() override;
- void SetAutomaticGainControl(bool enabled) override;
+ bool SetAutomaticGainControl(bool enabled) override;
bool GetAutomaticGainControl() override;
bool IsMuted() override;
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 9772c9457ce..0eebd7a8083 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
@@ -9,6 +9,7 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
#include "content/browser/media/capture/audio_mirroring_manager.h"
@@ -86,7 +87,7 @@ class MockWebContentsTracker : public WebContentsTracker {
class MockVirtualAudioInputStream : public VirtualAudioInputStream {
public:
explicit MockVirtualAudioInputStream(
- const scoped_refptr<base::MessageLoopProxy>& worker_loop)
+ const scoped_refptr<base::SingleThreadTaskRunner>& worker_loop)
: VirtualAudioInputStream(TestAudioParameters(), worker_loop,
VirtualAudioInputStream::AfterCloseCallback()),
real_(TestAudioParameters(), worker_loop,
@@ -134,7 +135,7 @@ class MockVirtualAudioInputStream : public VirtualAudioInputStream {
MOCK_METHOD0(GetMaxVolume, double());
MOCK_METHOD1(SetVolume, void(double));
MOCK_METHOD0(GetVolume, double());
- MOCK_METHOD1(SetAutomaticGainControl, void(bool));
+ MOCK_METHOD1(SetAutomaticGainControl, bool(bool));
MOCK_METHOD0(GetAutomaticGainControl, bool());
MOCK_METHOD2(AddOutputStream, void(VirtualAudioOutputStream*,
const AudioParameters&));
@@ -355,13 +356,7 @@ 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));
- }
+ change_callback_.Run(render_process_id != -1 && render_frame_id != -1);
}
scoped_ptr<TestBrowserThreadBundle> thread_bundle_;
diff --git a/chromium/content/browser/media/capture/web_contents_audio_muter.cc b/chromium/content/browser/media/capture/web_contents_audio_muter.cc
index 4d321927a4f..6d25d550d18 100644
--- a/chromium/content/browser/media/capture/web_contents_audio_muter.cc
+++ b/chromium/content/browser/media/capture/web_contents_audio_muter.cc
@@ -12,7 +12,7 @@
#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/audio/fake_audio_worker.h"
#include "media/base/bind_to_current_loop.h"
namespace content {
@@ -30,14 +30,17 @@ namespace {
class AudioDiscarder : public media::AudioOutputStream {
public:
explicit AudioDiscarder(const media::AudioParameters& params)
- : consumer_(media::AudioManager::Get()->GetWorkerTaskRunner(), params) {}
+ : worker_(media::AudioManager::Get()->GetWorkerTaskRunner(), params),
+ audio_bus_(media::AudioBus::Create(params)) {}
// AudioOutputStream implementation.
bool Open() override { return true; }
void Start(AudioSourceCallback* callback) override {
- consumer_.Start(base::Bind(&AudioDiscarder::FetchAudioData, callback));
+ worker_.Start(base::Bind(&AudioDiscarder::FetchAudioData,
+ base::Unretained(this),
+ callback));
}
- void Stop() override { consumer_.Stop(); }
+ void Stop() override { worker_.Stop(); }
void SetVolume(double volume) override {}
void GetVolume(double* volume) override { *volume = 0; }
void Close() override { delete this; }
@@ -45,13 +48,13 @@ class AudioDiscarder : public media::AudioOutputStream {
private:
~AudioDiscarder() override {}
- static void FetchAudioData(AudioSourceCallback* callback,
- media::AudioBus* audio_bus) {
- callback->OnMoreData(audio_bus, 0);
+ void FetchAudioData(AudioSourceCallback* callback) {
+ callback->OnMoreData(audio_bus_.get(), 0);
}
// Calls FetchAudioData() at regular intervals and discards the data.
- media::FakeAudioConsumer consumer_;
+ media::FakeAudioWorker worker_;
+ scoped_ptr<media::AudioBus> audio_bus_;
DISALLOW_COPY_AND_ASSIGN(AudioDiscarder);
};
diff --git a/chromium/content/browser/media/capture/web_contents_tracker.cc b/chromium/content/browser/media/capture/web_contents_tracker.cc
index 6810ac097aa..5007a583af8 100644
--- a/chromium/content/browser/media/capture/web_contents_tracker.cc
+++ b/chromium/content/browser/media/capture/web_contents_tracker.cc
@@ -4,7 +4,7 @@
#include "content/browser/media/capture/web_contents_tracker.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/thread_task_runner_handle.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"
@@ -24,10 +24,10 @@ WebContentsTracker::~WebContentsTracker() {
void WebContentsTracker::Start(int render_process_id, int main_render_frame_id,
const ChangeCallback& callback) {
- DCHECK(!message_loop_.get() || message_loop_->BelongsToCurrentThread());
+ DCHECK(!task_runner_.get() || task_runner_->BelongsToCurrentThread());
- message_loop_ = base::MessageLoopProxy::current();
- DCHECK(message_loop_.get());
+ task_runner_ = base::ThreadTaskRunnerHandle::Get();
+ DCHECK(task_runner_.get());
callback_ = callback;
if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
@@ -41,9 +41,10 @@ void WebContentsTracker::Start(int render_process_id, int main_render_frame_id,
}
void WebContentsTracker::Stop() {
- DCHECK(message_loop_->BelongsToCurrentThread());
+ DCHECK(task_runner_->BelongsToCurrentThread());
callback_.Reset();
+ resize_callback_.Reset();
if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
WebContentsObserver::Observe(NULL);
@@ -78,6 +79,12 @@ RenderWidgetHost* WebContentsTracker::GetTargetRenderWidgetHost() const {
return rwh;
}
+void WebContentsTracker::SetResizeChangeCallback(
+ const base::Closure& callback) {
+ DCHECK(!task_runner_.get() || task_runner_->BelongsToCurrentThread());
+ resize_callback_ = callback;
+}
+
void WebContentsTracker::OnPossibleTargetChange(bool force_callback_run) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -88,20 +95,30 @@ void WebContentsTracker::OnPossibleTargetChange(bool force_callback_run) {
<< " to RenderWidgetHost@" << rwh;
last_target_ = rwh;
- if (message_loop_->BelongsToCurrentThread()) {
- MaybeDoCallback(rwh);
- } else {
- message_loop_->PostTask(
- FROM_HERE,
- base::Bind(&WebContentsTracker::MaybeDoCallback, this, rwh));
+ if (task_runner_->BelongsToCurrentThread()) {
+ MaybeDoCallback(rwh != nullptr);
+ return;
}
+
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&WebContentsTracker::MaybeDoCallback, this, rwh != nullptr));
}
-void WebContentsTracker::MaybeDoCallback(RenderWidgetHost* rwh) {
- DCHECK(message_loop_->BelongsToCurrentThread());
+void WebContentsTracker::MaybeDoCallback(bool was_still_tracking) {
+ DCHECK(task_runner_->BelongsToCurrentThread());
if (!callback_.is_null())
- callback_.Run(rwh);
+ callback_.Run(was_still_tracking);
+ if (was_still_tracking)
+ MaybeDoResizeCallback();
+}
+
+void WebContentsTracker::MaybeDoResizeCallback() {
+ DCHECK(task_runner_->BelongsToCurrentThread());
+
+ if (!resize_callback_.is_null())
+ resize_callback_.Run();
}
void WebContentsTracker::StartObservingWebContents(int render_process_id,
@@ -128,6 +145,19 @@ void WebContentsTracker::RenderFrameHostChanged(RenderFrameHost* old_host,
OnPossibleTargetChange(false);
}
+void WebContentsTracker::MainFrameWasResized(bool width_changed) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ if (task_runner_->BelongsToCurrentThread()) {
+ MaybeDoResizeCallback();
+ return;
+ }
+
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&WebContentsTracker::MaybeDoResizeCallback, this));
+}
+
void WebContentsTracker::WebContentsDestroyed() {
Observe(NULL);
OnPossibleTargetChange(false);
diff --git a/chromium/content/browser/media/capture/web_contents_tracker.h b/chromium/content/browser/media/capture/web_contents_tracker.h
index f124eaa47e8..591c5e35a9c 100644
--- a/chromium/content/browser/media/capture/web_contents_tracker.h
+++ b/chromium/content/browser/media/capture/web_contents_tracker.h
@@ -22,7 +22,7 @@
#include "content/public/browser/web_contents_observer.h"
namespace base {
-class MessageLoopProxy;
+class SingleThreadTaskRunner;
}
namespace content {
@@ -40,15 +40,15 @@ class CONTENT_EXPORT WebContentsTracker
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
+ // This is also invoked with false 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;
+ typedef base::Callback<void(bool was_still_tracking)> 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().
+ // indicate whether tracking successfully started (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);
@@ -59,6 +59,12 @@ class CONTENT_EXPORT WebContentsTracker
// Current target. This must only be called on the UI BrowserThread.
RenderWidgetHost* GetTargetRenderWidgetHost() const;
+ // Set a callback that is run whenever the main frame of the WebContents is
+ // resized. This method must be called on the same thread that calls
+ // Start()/Stop(), and |callback| will be run on that same thread. Calling
+ // the Stop() method guarantees the callback will never be invoked again.
+ void SetResizeChangeCallback(const base::Closure& callback);
+
protected:
friend class base::RefCountedThreadSafe<WebContentsTracker>;
~WebContentsTracker() override;
@@ -72,7 +78,12 @@ class CONTENT_EXPORT WebContentsTracker
// 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);
+ void MaybeDoCallback(bool was_still_tracking);
+
+ // Called on the thread that Start()/Stop() are called on. Checks whether the
+ // callback is still valid and, if so, runs it to indicate the main frame has
+ // changed in size.
+ void MaybeDoResizeCallback();
// Look-up the current WebContents instance associated with the given
// |render_process_id| and |main_render_frame_id| and begin observing it.
@@ -86,6 +97,10 @@ class CONTENT_EXPORT WebContentsTracker
void RenderFrameHostChanged(RenderFrameHost* old_host,
RenderFrameHost* new_host) override;
+ // WebContentsObserver override to notify the client that the source size has
+ // changed.
+ void MainFrameWasResized(bool width_changed) override;
+
// WebContentsObserver override to notify the client that the capture target
// has been permanently lost.
void WebContentsDestroyed() override;
@@ -99,8 +114,8 @@ class CONTENT_EXPORT WebContentsTracker
// RenderWidgetHosts.
const bool track_fullscreen_rwh_;
- // MessageLoop corresponding to the thread that called Start().
- scoped_refptr<base::MessageLoopProxy> message_loop_;
+ // TaskRunner corresponding to the thread that called Start().
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
// Callback to run when the target RenderWidgetHost has changed.
ChangeCallback callback_;
@@ -109,6 +124,9 @@ class CONTENT_EXPORT WebContentsTracker
// This is used to eliminate duplicate callback runs.
RenderWidgetHost* last_target_;
+ // Callback to run when the target RenderWidgetHost has resized.
+ base::Closure resize_callback_;
+
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 4a931fc54b0..292d856f8a8 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
@@ -69,21 +69,16 @@
#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/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_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.h"
+#include "media/base/video_capture_types.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"
@@ -91,21 +86,6 @@ namespace content {
namespace {
-// Compute a letterbox region, aligned to even coordinates.
-gfx::Rect ComputeYV12LetterboxRegion(const gfx::Size& frame_size,
- const gfx::Size& content_size) {
-
- gfx::Rect result = media::ComputeLetterboxRegion(gfx::Rect(frame_size),
- content_size);
-
- result.set_x(MakeEven(result.x()));
- result.set_y(MakeEven(result.y()));
- result.set_width(std::max(kMinFrameWidth, MakeEven(result.width())));
- result.set_height(std::max(kMinFrameHeight, MakeEven(result.height())));
-
- return result;
-}
-
void DeleteOnWorkerThread(scoped_ptr<base::Thread> render_thread,
const base::Closure& callback) {
render_thread.reset();
@@ -161,16 +141,14 @@ class FrameSubscriber : public RenderWidgetHostViewFrameSubscriber {
// knows how to do the capture and prepare the result for delivery.
//
// In practice, this means (a) installing a RenderWidgetHostFrameSubscriber in
-// the RenderWidgetHostView, to process updates that occur via accelerated
-// compositing, (b) installing itself as an observer of updates to the
-// RenderWidgetHost's backing store, to hook updates that occur via software
-// rendering, and (c) running a timer to possibly initiate non-event-driven
-// captures that the subscriber might request.
+// the RenderWidgetHostView, to process compositor updates, and (b) running a
+// timer to possibly initiate forced, non-event-driven captures needed by
+// downstream consumers that require frame repeats of unchanged content.
//
// All of this happens on the UI thread, although the
// RenderWidgetHostViewFrameSubscriber we install may be dispatching updates
// autonomously on some other thread.
-class ContentCaptureSubscription : public content::NotificationObserver {
+class ContentCaptureSubscription {
public:
typedef base::Callback<
void(const base::TimeTicks&,
@@ -185,12 +163,7 @@ class ContentCaptureSubscription : public content::NotificationObserver {
const RenderWidgetHost& source,
const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy,
const CaptureCallback& capture_callback);
- ~ContentCaptureSubscription() override;
-
- // content::NotificationObserver implementation.
- void Observe(int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) override;
+ ~ContentCaptureSubscription();
private:
void OnTimer();
@@ -202,9 +175,7 @@ class ContentCaptureSubscription : public content::NotificationObserver {
const int render_widget_id_;
VideoFrameDeliveryLog delivery_log_;
- FrameSubscriber paint_subscriber_;
FrameSubscriber timer_subscriber_;
- content::NotificationRegistrar registrar_;
CaptureCallback capture_callback_;
base::Timer timer_;
@@ -258,8 +229,8 @@ class WebContentsCaptureMachine : public VideoCaptureMachine {
const scoped_refptr<media::VideoFrame>& target,
const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
deliver_frame_cb,
- bool success,
- const SkBitmap& bitmap);
+ const SkBitmap& bitmap,
+ ReadbackResponse response);
// Response callback for RWHVP::CopyFromCompositingSurfaceToVideoFrame().
void DidCopyFromCompositingSurfaceToVideoFrame(
@@ -268,8 +239,12 @@ class WebContentsCaptureMachine : public VideoCaptureMachine {
deliver_frame_cb,
bool success);
- // Remove the old subscription, and start a new one if |rwh| is not NULL.
- void RenewFrameSubscription(RenderWidgetHost* rwh);
+ // Remove the old subscription, and attempt to start a new one if |had_target|
+ // is true.
+ void RenewFrameSubscription(bool had_target);
+
+ // Called whenever the render widget is resized.
+ void UpdateCaptureSize();
// Parameters saved in constructor.
const int initial_render_process_id_;
@@ -308,7 +283,7 @@ bool FrameSubscriber::ShouldCaptureFrame(
base::TimeTicks present_time,
scoped_refptr<media::VideoFrame>* storage,
DeliverFrameCallback* deliver_frame_cb) {
- TRACE_EVENT1("mirroring", "FrameSubscriber::ShouldCaptureFrame",
+ TRACE_EVENT1("gpu.capture", "FrameSubscriber::ShouldCaptureFrame",
"instance", this);
ThreadSafeCaptureOracle::CaptureFrameCallback capture_frame_cb;
@@ -329,8 +304,6 @@ ContentCaptureSubscription::ContentCaptureSubscription(
: render_process_id_(source.GetProcess()->GetID()),
render_widget_id_(source.GetRoutingID()),
delivery_log_(),
- paint_subscriber_(VideoCaptureOracle::kSoftwarePaint, oracle_proxy,
- &delivery_log_),
timer_subscriber_(VideoCaptureOracle::kTimerPoll, oracle_proxy,
&delivery_log_),
capture_callback_(capture_callback),
@@ -339,22 +312,15 @@ ContentCaptureSubscription::ContentCaptureSubscription(
RenderWidgetHostView* const view = source.GetView();
- // Subscribe to accelerated presents. These will be serviced directly by the
+ // Subscribe to compositor updates. These will be serviced directly by the
// oracle.
- if (view && kAcceleratedSubscriberIsSupported) {
+ if (view) {
scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber(
new FrameSubscriber(VideoCaptureOracle::kCompositorUpdate,
oracle_proxy, &delivery_log_));
view->BeginFrameSubscription(subscriber.Pass());
}
- // Subscribe to software paint events. This instance will service these by
- // reflecting them back to the WebContentsCaptureMachine via
- // |capture_callback|.
- registrar_.Add(
- this, content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
- Source<RenderWidgetHost>(&source));
-
// Subscribe to timer events. This instance will service these as well.
timer_.Start(FROM_HERE, oracle_proxy->min_capture_period(),
base::Bind(&ContentCaptureSubscription::OnTimer,
@@ -369,60 +335,16 @@ ContentCaptureSubscription::~ContentCaptureSubscription() {
return;
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- if (kAcceleratedSubscriberIsSupported) {
- RenderWidgetHost* const source =
- RenderWidgetHost::FromID(render_process_id_, render_widget_id_);
- RenderWidgetHostView* const view = source ? source->GetView() : NULL;
- if (view)
- view->EndFrameSubscription();
- }
-}
-
-void ContentCaptureSubscription::Observe(
- int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- DCHECK_EQ(NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE, type);
-
- RenderWidgetHostImpl* rwh =
- RenderWidgetHostImpl::From(Source<RenderWidgetHost>(source).ptr());
-
- // This message occurs on window resizes and visibility changes even when
- // accelerated compositing is active, so we need to filter out these cases.
- if (!rwh || !rwh->GetView())
- return;
- // Mac sends DID_UPDATE_BACKING_STORE messages to inform the capture system
- // of new software compositor frames, so always treat these messages as
- // signals of a new frame on Mac.
- // http://crbug.com/333986
-#if !defined(OS_MACOSX)
- if (rwh->GetView()->IsSurfaceAvailableForCopy())
- return;
-#endif
-
- TRACE_EVENT1("mirroring", "ContentCaptureSubscription::Observe",
- "instance", this);
-
- base::Closure copy_done_callback;
- scoped_refptr<media::VideoFrame> frame;
- RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback deliver_frame_cb;
- const base::TimeTicks start_time = base::TimeTicks::Now();
- 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,
- // it should run soon after the paint.
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(capture_callback_, start_time, frame, deliver_frame_cb));
- }
+ RenderWidgetHost* const source =
+ RenderWidgetHost::FromID(render_process_id_, render_widget_id_);
+ RenderWidgetHostView* const view = source ? source->GetView() : NULL;
+ if (view)
+ view->EndFrameSubscription();
}
void ContentCaptureSubscription::OnTimer() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- TRACE_EVENT0("mirroring", "ContentCaptureSubscription::OnTimer");
+ TRACE_EVENT0("gpu.capture", "ContentCaptureSubscription::OnTimer");
scoped_refptr<media::VideoFrame> frame;
RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback deliver_frame_cb;
@@ -463,8 +385,8 @@ void RenderVideoFrame(const SkBitmap& input,
// Calculate the width and height of the content region in the |output|, based
// on the aspect ratio of |input|.
- gfx::Rect region_in_frame = ComputeYV12LetterboxRegion(
- output->coded_size(), gfx::Size(input.width(), input.height()));
+ const gfx::Rect region_in_frame = media::ComputeLetterboxRegion(
+ output->visible_rect(), gfx::Size(input.width(), input.height()));
// Scale the bitmap to the required size, if necessary.
SkBitmap scaled_bitmap;
@@ -481,7 +403,8 @@ void RenderVideoFrame(const SkBitmap& input,
method = skia::ImageOperations::RESIZE_BOX;
}
- TRACE_EVENT_ASYNC_STEP_INTO0("mirroring", "Capture", output.get(), "Scale");
+ TRACE_EVENT_ASYNC_STEP_INTO0("gpu.capture",
+ "Capture", output.get(), "Scale");
scaled_bitmap = skia::ImageOperations::Resize(input, method,
region_in_frame.width(),
region_in_frame.height());
@@ -489,14 +412,22 @@ void RenderVideoFrame(const SkBitmap& input,
scaled_bitmap = input;
}
- TRACE_EVENT_ASYNC_STEP_INTO0("mirroring", "Capture", output.get(), "YUV");
+ TRACE_EVENT_ASYNC_STEP_INTO0("gpu.capture", "Capture", output.get(), "YUV");
{
- SkAutoLockPixels scaled_bitmap_locker(scaled_bitmap);
+ // Align to 2x2 pixel boundaries, as required by
+ // media::CopyRGBToVideoFrame().
+ const gfx::Rect region_in_yv12_frame(region_in_frame.x() & ~1,
+ region_in_frame.y() & ~1,
+ region_in_frame.width() & ~1,
+ region_in_frame.height() & ~1);
+ if (region_in_yv12_frame.IsEmpty())
+ return;
+ SkAutoLockPixels scaled_bitmap_locker(scaled_bitmap);
media::CopyRGBToVideoFrame(
reinterpret_cast<uint8*>(scaled_bitmap.getPixels()),
scaled_bitmap.rowBytes(),
- region_in_frame,
+ region_in_yv12_frame,
output.get());
}
@@ -567,6 +498,9 @@ bool WebContentsCaptureMachine::Start(
// Note: Creation of the first WeakPtr in the following statement will cause
// IsStarted() to return true from now on.
+ tracker_->SetResizeChangeCallback(
+ base::Bind(&WebContentsCaptureMachine::UpdateCaptureSize,
+ weak_ptr_factory_.GetWeakPtr()));
tracker_->Start(initial_render_process_id_, initial_main_render_frame_id_,
base::Bind(&WebContentsCaptureMachine::RenewFrameSubscription,
weak_ptr_factory_.GetWeakPtr()));
@@ -588,7 +522,7 @@ void WebContentsCaptureMachine::Stop(const base::Closure& callback) {
// Note: RenewFrameSubscription() must be called before stopping |tracker_| so
// the web_contents() can be notified that the capturing is ending.
- RenewFrameSubscription(NULL);
+ RenewFrameSubscription(false);
tracker_->Stop();
// The render thread cannot be stopped on the UI thread, so post a message
@@ -616,12 +550,7 @@ void WebContentsCaptureMachine::Capture(
return;
}
- gfx::Size video_size = target->coded_size();
gfx::Size view_size = view->GetViewBounds().size();
- gfx::Size fitted_size;
- if (!view_size.IsEmpty()) {
- fitted_size = ComputeYV12LetterboxRegion(video_size, view_size).size();
- }
if (view_size != last_view_size_) {
last_view_size_ = view_size;
@@ -640,6 +569,8 @@ void WebContentsCaptureMachine::Capture(
weak_ptr_factory_.GetWeakPtr(),
start_time, deliver_frame_cb));
} else {
+ const gfx::Size fitted_size = view_size.IsEmpty() ? gfx::Size() :
+ media::ComputeLetterboxRegion(target->visible_rect(), view_size).size();
rwh->CopyFromBackingStore(
gfx::Rect(),
fitted_size, // Size here is a request not always honored.
@@ -655,7 +586,10 @@ void WebContentsCaptureMachine::Capture(
gfx::Size WebContentsCaptureMachine::ComputeOptimalTargetSize() const {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- gfx::Size optimal_size = oracle_proxy_->GetCaptureSize();
+ // TODO(miu): Propagate capture frame size changes as new "preferred size"
+ // updates, rather than just using the max frame size.
+ // http://crbug.com/350491
+ gfx::Size optimal_size = oracle_proxy_->max_frame_size();
// 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
@@ -686,15 +620,15 @@ void WebContentsCaptureMachine::DidCopyFromBackingStore(
const scoped_refptr<media::VideoFrame>& target,
const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
deliver_frame_cb,
- bool success,
- const SkBitmap& bitmap) {
+ const SkBitmap& bitmap,
+ ReadbackResponse response) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
base::TimeTicks now = base::TimeTicks::Now();
DCHECK(render_thread_.get());
- if (success) {
+ if (response == READBACK_SUCCESS) {
UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeBitmap", now - start_time);
- TRACE_EVENT_ASYNC_STEP_INTO0("mirroring", "Capture", target.get(),
+ TRACE_EVENT_ASYNC_STEP_INTO0("gpu.capture", "Capture", target.get(),
"Render");
render_thread_->message_loop_proxy()->PostTask(FROM_HERE, base::Bind(
&RenderVideoFrame, bitmap, target,
@@ -723,9 +657,12 @@ void WebContentsCaptureMachine::DidCopyFromCompositingSurfaceToVideoFrame(
deliver_frame_cb.Run(start_time, success);
}
-void WebContentsCaptureMachine::RenewFrameSubscription(RenderWidgetHost* rwh) {
+void WebContentsCaptureMachine::RenewFrameSubscription(bool had_target) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ RenderWidgetHost* const rwh =
+ had_target ? tracker_->GetTargetRenderWidgetHost() : nullptr;
+
// Always destroy the old subscription before creating a new one.
const bool had_subscription = !!subscription_;
subscription_.reset();
@@ -754,6 +691,18 @@ void WebContentsCaptureMachine::RenewFrameSubscription(RenderWidgetHost* rwh) {
weak_ptr_factory_.GetWeakPtr())));
}
+void WebContentsCaptureMachine::UpdateCaptureSize() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ if (!oracle_proxy_)
+ return;
+ RenderWidgetHost* const rwh = tracker_->GetTargetRenderWidgetHost();
+ RenderWidgetHostView* const view = rwh ? rwh->GetView() : nullptr;
+ if (!view)
+ return;
+ oracle_proxy_->UpdateCaptureSize(view->GetViewBounds().size());
+}
+
} // namespace
WebContentsVideoCaptureDevice::WebContentsVideoCaptureDevice(
diff --git a/chromium/content/browser/media/capture/web_contents_video_capture_device_unittest.cc b/chromium/content/browser/media/capture/web_contents_video_capture_device_unittest.cc
index 09f84454f60..02b297f35e0 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
@@ -11,11 +11,13 @@
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "content/browser/browser_thread_impl.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/media/capture/video_capture_oracle.h"
#include "content/browser/media/capture/web_contents_capture_util.h"
#include "content/browser/renderer_host/media/video_capture_buffer_pool.h"
#include "content/browser/renderer_host/render_view_host_factory.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_widget_host_view_frame_subscriber.h"
@@ -25,11 +27,12 @@
#include "content/public/test/test_utils.h"
#include "content/test/test_render_view_host.h"
#include "content/test/test_web_contents.h"
+#include "media/base/video_capture_types.h"
#include "media/base/video_frame.h"
#include "media/base/video_util.h"
#include "media/base/yuv_convert.h"
-#include "media/video/capture/video_capture_types.h"
#include "skia/ext/platform_canvas.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/display.h"
@@ -76,7 +79,6 @@ SkColor ConvertRgbToYuv(SkColor rgb) {
// counted.
class CaptureTestSourceController {
public:
-
CaptureTestSourceController()
: color_(SK_ColorMAGENTA),
copy_result_size_(kTestWidth, kTestHeight),
@@ -161,13 +163,22 @@ class CaptureTestView : public TestRenderWidgetHostView {
explicit CaptureTestView(RenderWidgetHostImpl* rwh,
CaptureTestSourceController* controller)
: TestRenderWidgetHostView(rwh),
- controller_(controller) {}
+ controller_(controller),
+ fake_bounds_(100, 100, 100 + kTestWidth, 100 + kTestHeight) {}
~CaptureTestView() override {}
// TestRenderWidgetHostView overrides.
gfx::Rect GetViewBounds() const override {
- return gfx::Rect(100, 100, 100 + kTestWidth, 100 + kTestHeight);
+ return fake_bounds_;
+ }
+
+ void SetSize(const gfx::Size& size) override {
+ SetBounds(gfx::Rect(fake_bounds_.origin(), size));
+ }
+
+ void SetBounds(const gfx::Rect& rect) override {
+ fake_bounds_ = rect;
}
bool CanCopyToVideoFrame() const override {
@@ -212,6 +223,7 @@ class CaptureTestView : public TestRenderWidgetHostView {
private:
scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber_;
CaptureTestSourceController* const controller_;
+ gfx::Rect fake_bounds_;
DISALLOW_IMPLICIT_CONSTRUCTORS(CaptureTestView);
};
@@ -246,11 +258,10 @@ class CaptureTestRenderViewHost : public TestRenderViewHost {
}
// TestRenderViewHost overrides.
- void CopyFromBackingStore(
- const gfx::Rect& src_rect,
- const gfx::Size& accelerated_dst_size,
- const base::Callback<void(bool, const SkBitmap&)>& callback,
- const SkColorType color_type) override {
+ void CopyFromBackingStore(const gfx::Rect& src_rect,
+ const gfx::Size& accelerated_dst_size,
+ ReadbackRequestCallback& callback,
+ const SkColorType color_type) override {
gfx::Size size = controller_->GetCopyResultSize();
SkColor color = controller_->GetSolidColor();
@@ -262,7 +273,7 @@ class CaptureTestRenderViewHost : public TestRenderViewHost {
SkAutoLockPixels locker(output.GetBitmap());
output.GetBitmap().eraseColor(color);
}
- callback.Run(true, output.GetBitmap());
+ callback.Run(output.GetBitmap(), content::READBACK_SUCCESS);
controller_->SignalCopy();
}
@@ -308,75 +319,116 @@ class CaptureTestRenderViewHostFactory : public RenderViewHostFactory {
// WebContentsVideoCaptureDevice.
class StubClient : public media::VideoCaptureDevice::Client {
public:
- StubClient(const base::Callback<void(SkColor)>& color_callback,
- const base::Closure& error_callback)
- : color_callback_(color_callback),
+ StubClient(
+ const base::Callback<void(SkColor, const gfx::Size&)>& report_callback,
+ const base::Closure& error_callback)
+ : report_callback_(report_callback),
error_callback_(error_callback) {
buffer_pool_ = new VideoCaptureBufferPool(2);
}
~StubClient() override {}
- scoped_refptr<media::VideoCaptureDevice::Client::Buffer> ReserveOutputBuffer(
- media::VideoFrame::Format format,
+ MOCK_METHOD5(OnIncomingCapturedData,
+ void(const uint8* data,
+ int length,
+ const media::VideoCaptureFormat& frame_format,
+ int rotation,
+ const base::TimeTicks& timestamp));
+ MOCK_METHOD9(OnIncomingCapturedYuvData,
+ void (const uint8* y_data,
+ const uint8* u_data,
+ const uint8* v_data,
+ size_t y_stride,
+ size_t u_stride,
+ size_t v_stride,
+ const media::VideoCaptureFormat& frame_format,
+ int clockwise_rotation,
+ const base::TimeTicks& timestamp));
+
+ MOCK_METHOD0(DoOnIncomingCapturedBuffer, void(void));
+
+ scoped_ptr<media::VideoCaptureDevice::Client::Buffer> ReserveOutputBuffer(
+ media::VideoPixelFormat format,
const gfx::Size& dimensions) override {
- CHECK_EQ(format, media::VideoFrame::I420);
- const size_t frame_bytes =
- media::VideoFrame::AllocationSize(media::VideoFrame::I420, dimensions);
+ CHECK_EQ(format, media::PIXEL_FORMAT_I420);
int buffer_id_to_drop = VideoCaptureBufferPool::kInvalidId; // Ignored.
- int buffer_id =
- buffer_pool_->ReserveForProducer(frame_bytes, &buffer_id_to_drop);
+ int buffer_id = buffer_pool_->ReserveForProducer(format, dimensions,
+ &buffer_id_to_drop);
if (buffer_id == VideoCaptureBufferPool::kInvalidId)
return NULL;
- void* data;
- size_t size;
- buffer_pool_->GetBufferInfo(buffer_id, &data, &size);
- return scoped_refptr<media::VideoCaptureDevice::Client::Buffer>(
- new PoolBuffer(buffer_pool_, buffer_id, data, size));
- }
- void OnIncomingCapturedData(const uint8* data,
- int length,
- const media::VideoCaptureFormat& frame_format,
- int rotation,
- base::TimeTicks timestamp) override {
- FAIL();
+ return scoped_ptr<media::VideoCaptureDevice::Client::Buffer>(
+ new AutoReleaseBuffer(
+ buffer_pool_, buffer_pool_->GetBufferHandle(buffer_id), buffer_id));
+ }
+ // Trampoline method to workaround GMOCK problems with scoped_ptr<>.
+ void OnIncomingCapturedBuffer(scoped_ptr<Buffer> buffer,
+ const media::VideoCaptureFormat& frame_format,
+ const base::TimeTicks& timestamp) override {
+ DoOnIncomingCapturedBuffer();
}
void OnIncomingCapturedVideoFrame(
- const scoped_refptr<Buffer>& buffer,
- const media::VideoCaptureFormat& buffer_format,
+ scoped_ptr<Buffer> buffer,
const scoped_refptr<media::VideoFrame>& frame,
- base::TimeTicks timestamp) override {
- EXPECT_EQ(gfx::Size(kTestWidth, kTestHeight), buffer_format.frame_size);
- EXPECT_EQ(media::PIXEL_FORMAT_I420, buffer_format.pixel_format);
+ const base::TimeTicks& timestamp) override {
+ EXPECT_FALSE(frame->visible_rect().IsEmpty());
EXPECT_EQ(media::VideoFrame::I420, frame->format());
- uint8 yuv[3];
- for (int plane = 0; plane < 3; ++plane)
- yuv[plane] = frame->data(plane)[0];
- // TODO(nick): We just look at the first pixel presently, because if
- // the analysis is too slow, the backlog of frames will grow without bound
- // and trouble erupts. http://crbug.com/174519
- color_callback_.Run((SkColorSetRGB(yuv[0], yuv[1], yuv[2])));
+ double frame_rate = 0;
+ EXPECT_TRUE(
+ frame->metadata()->GetDouble(media::VideoFrameMetadata::FRAME_RATE,
+ &frame_rate));
+ EXPECT_EQ(kTestFramesPerSecond, frame_rate);
+
+ // TODO(miu): We just look at the center pixel presently, because if the
+ // analysis is too slow, the backlog of frames will grow without bound and
+ // trouble erupts. http://crbug.com/174519
+ using media::VideoFrame;
+ const gfx::Point center = frame->visible_rect().CenterPoint();
+ const int center_offset_y =
+ (frame->stride(VideoFrame::kYPlane) * center.y()) + center.x();
+ const int center_offset_uv =
+ (frame->stride(VideoFrame::kUPlane) * (center.y() / 2)) +
+ (center.x() / 2);
+ report_callback_.Run(
+ SkColorSetRGB(frame->data(VideoFrame::kYPlane)[center_offset_y],
+ frame->data(VideoFrame::kUPlane)[center_offset_uv],
+ frame->data(VideoFrame::kVPlane)[center_offset_uv]),
+ frame->visible_rect().size());
}
void OnError(const std::string& reason) override { error_callback_.Run(); }
private:
- class PoolBuffer : public media::VideoCaptureDevice::Client::Buffer {
+ class AutoReleaseBuffer : public media::VideoCaptureDevice::Client::Buffer {
public:
- PoolBuffer(const scoped_refptr<VideoCaptureBufferPool>& pool,
- int buffer_id,
- void* data,
- size_t size)
- : Buffer(buffer_id, data, size), pool_(pool) {}
+ AutoReleaseBuffer(
+ const scoped_refptr<VideoCaptureBufferPool>& pool,
+ scoped_ptr<VideoCaptureBufferPool::BufferHandle> buffer_handle,
+ int buffer_id)
+ : id_(buffer_id),
+ pool_(pool),
+ buffer_handle_(buffer_handle.Pass()) {
+ DCHECK(pool_.get());
+ }
+ int id() const override { return id_; }
+ size_t size() const override { return buffer_handle_->size(); }
+ void* data() override { return buffer_handle_->data(); }
+ gfx::GpuMemoryBufferType GetType() override {
+ return gfx::SHARED_MEMORY_BUFFER;
+ }
+ ClientBuffer AsClientBuffer() override { return nullptr; }
private:
- ~PoolBuffer() override { pool_->RelinquishProducerReservation(id()); }
+ ~AutoReleaseBuffer() override { pool_->RelinquishProducerReservation(id_); }
+
+ const int id_;
const scoped_refptr<VideoCaptureBufferPool> pool_;
+ const scoped_ptr<VideoCaptureBufferPool::BufferHandle> buffer_handle_;
};
scoped_refptr<VideoCaptureBufferPool> buffer_pool_;
- base::Callback<void(SkColor)> color_callback_;
+ base::Callback<void(SkColor, const gfx::Size&)> report_callback_;
base::Closure error_callback_;
DISALLOW_COPY_AND_ASSIGN(StubClient);
@@ -386,9 +438,11 @@ class StubClientObserver {
public:
StubClientObserver()
: error_encountered_(false),
- wait_color_yuv_(0xcafe1950) {
+ wait_color_yuv_(0xcafe1950),
+ wait_size_(kTestWidth, kTestHeight) {
client_.reset(new StubClient(
- base::Bind(&StubClientObserver::OnColor, base::Unretained(this)),
+ base::Bind(&StubClientObserver::DidDeliverFrame,
+ base::Unretained(this)),
base::Bind(&StubClientObserver::OnError, base::Unretained(this))));
}
@@ -398,16 +452,30 @@ class StubClientObserver {
return client_.Pass();
}
- void QuitIfConditionMet(SkColor color) {
+ void QuitIfConditionsMet(SkColor color, const gfx::Size& size) {
base::AutoLock guard(lock_);
- if (wait_color_yuv_ == color || error_encountered_)
+ if (error_encountered_)
+ base::MessageLoop::current()->Quit();
+ else if (wait_color_yuv_ == color && wait_size_.IsEmpty())
+ base::MessageLoop::current()->Quit();
+ else if (wait_color_yuv_ == color && wait_size_ == size)
base::MessageLoop::current()->Quit();
}
+ // Run the current loop until a frame is delivered with the |expected_color|
+ // and any non-empty frame size.
void WaitForNextColor(SkColor expected_color) {
+ WaitForNextColorAndFrameSize(expected_color, gfx::Size());
+ }
+
+ // Run the current loop until a frame is delivered with the |expected_color|
+ // and is of the |expected_size|.
+ void WaitForNextColorAndFrameSize(SkColor expected_color,
+ const gfx::Size& expected_size) {
{
base::AutoLock guard(lock_);
wait_color_yuv_ = ConvertRgbToYuv(expected_color);
+ wait_size_ = expected_size;
error_encountered_ = false;
}
RunCurrentLoopWithDeadline();
@@ -421,6 +489,7 @@ class StubClientObserver {
{
base::AutoLock guard(lock_);
wait_color_yuv_ = kNotInterested;
+ wait_size_ = gfx::Size();
error_encountered_ = false;
}
RunCurrentLoopWithDeadline();
@@ -441,22 +510,25 @@ class StubClientObserver {
error_encountered_ = true;
}
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
- &StubClientObserver::QuitIfConditionMet,
+ &StubClientObserver::QuitIfConditionsMet,
base::Unretained(this),
- kNothingYet));
+ kNothingYet,
+ gfx::Size()));
}
- void OnColor(SkColor color) {
+ void DidDeliverFrame(SkColor color, const gfx::Size& size) {
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
- &StubClientObserver::QuitIfConditionMet,
+ &StubClientObserver::QuitIfConditionsMet,
base::Unretained(this),
- color));
+ color,
+ size));
}
private:
base::Lock lock_;
bool error_encountered_;
SkColor wait_color_yuv_;
+ gfx::Size wait_size_;
scoped_ptr<StubClient> client_;
DISALLOW_COPY_AND_ASSIGN(StubClientObserver);
@@ -591,6 +663,22 @@ class WebContentsVideoCaptureDeviceTest : public testing::Test {
}
}
+ void SimulateSourceSizeChange(const gfx::Size& size) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ CaptureTestView* test_view = static_cast<CaptureTestView*>(
+ web_contents_->GetRenderViewHost()->GetView());
+ test_view->SetSize(size);
+ // Normally, RenderWidgetHostImpl would notify WebContentsImpl that the size
+ // has changed. However, in this test setup where there is no render
+ // process, we must notify WebContentsImpl directly.
+ WebContentsImpl* const as_web_contents_impl =
+ static_cast<WebContentsImpl*>(web_contents_.get());
+ RenderWidgetHostDelegate* const as_rwh_delegate =
+ static_cast<RenderWidgetHostDelegate*>(as_web_contents_impl);
+ as_rwh_delegate->RenderWidgetWasResized(
+ as_web_contents_impl->GetMainFrame()->GetRenderWidgetHost(), true);
+ }
+
void DestroyVideoCaptureDevice() { device_.reset(); }
StubClientObserver* client_observer() {
@@ -848,5 +936,158 @@ TEST_F(WebContentsVideoCaptureDeviceTest, BadFramesGoodFrames) {
device()->StopAndDeAllocate();
}
+// Tests that, when configured with the FIXED_ASPECT_RATIO resolution change
+// policy, the source size changes result in video frames of possibly varying
+// resolutions, but all with the same aspect ratio.
+TEST_F(WebContentsVideoCaptureDeviceTest, VariableResolution_FixedAspectRatio) {
+ 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.resolution_change_policy =
+ media::RESOLUTION_POLICY_FIXED_ASPECT_RATIO;
+
+ device()->AllocateAndStart(capture_params, client_observer()->PassClient());
+
+ for (int i = 0; i < 6; i++) {
+ const char* name = NULL;
+ switch (i % 3) {
+ case 0:
+ source()->SetCanCopyToVideoFrame(true);
+ source()->SetUseFrameSubscriber(false);
+ name = "VideoFrame";
+ break;
+ case 1:
+ source()->SetCanCopyToVideoFrame(false);
+ source()->SetUseFrameSubscriber(true);
+ name = "Subscriber";
+ break;
+ case 2:
+ source()->SetCanCopyToVideoFrame(false);
+ source()->SetUseFrameSubscriber(false);
+ name = "SkBitmap";
+ break;
+ default:
+ FAIL();
+ }
+
+ SCOPED_TRACE(base::StringPrintf("Using %s path, iteration #%d", name, i));
+
+ // Source size equals maximum size. Expect delivered frames to be
+ // kTestWidth by kTestHeight.
+ source()->SetSolidColor(SK_ColorRED);
+ SimulateSourceSizeChange(gfx::Size(kTestWidth, kTestHeight));
+ SimulateDrawEvent();
+ ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
+ SK_ColorRED, gfx::Size(kTestWidth, kTestHeight)));
+
+ // Source size is half in both dimensions. Expect delivered frames to be of
+ // the same aspect ratio as kTestWidth by kTestHeight, but larger than the
+ // half size because the minimum height is 180 lines.
+ source()->SetSolidColor(SK_ColorGREEN);
+ SimulateSourceSizeChange(gfx::Size(kTestWidth / 2, kTestHeight / 2));
+ SimulateDrawEvent();
+ ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
+ SK_ColorGREEN, gfx::Size(180 * kTestWidth / kTestHeight, 180)));
+
+ // Source size changes aspect ratio. Expect delivered frames to be padded
+ // in the horizontal dimension to preserve aspect ratio.
+ source()->SetSolidColor(SK_ColorBLUE);
+ SimulateSourceSizeChange(gfx::Size(kTestWidth / 2, kTestHeight));
+ SimulateDrawEvent();
+ ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
+ SK_ColorBLUE, gfx::Size(kTestWidth, kTestHeight)));
+
+ // Source size changes aspect ratio again. Expect delivered frames to be
+ // padded in the vertical dimension to preserve aspect ratio.
+ source()->SetSolidColor(SK_ColorBLACK);
+ SimulateSourceSizeChange(gfx::Size(kTestWidth, kTestHeight / 2));
+ SimulateDrawEvent();
+ ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
+ SK_ColorBLACK, gfx::Size(kTestWidth, kTestHeight)));
+ }
+
+ device()->StopAndDeAllocate();
+}
+
+// Tests that, when configured with the ANY_WITHIN_LIMIT resolution change
+// policy, the source size changes result in video frames of possibly varying
+// resolutions.
+TEST_F(WebContentsVideoCaptureDeviceTest, VariableResolution_AnyWithinLimits) {
+ 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.resolution_change_policy =
+ media::RESOLUTION_POLICY_ANY_WITHIN_LIMIT;
+
+ device()->AllocateAndStart(capture_params, client_observer()->PassClient());
+
+ for (int i = 0; i < 6; i++) {
+ const char* name = NULL;
+ switch (i % 3) {
+ case 0:
+ source()->SetCanCopyToVideoFrame(true);
+ source()->SetUseFrameSubscriber(false);
+ name = "VideoFrame";
+ break;
+ case 1:
+ source()->SetCanCopyToVideoFrame(false);
+ source()->SetUseFrameSubscriber(true);
+ name = "Subscriber";
+ break;
+ case 2:
+ source()->SetCanCopyToVideoFrame(false);
+ source()->SetUseFrameSubscriber(false);
+ name = "SkBitmap";
+ break;
+ default:
+ FAIL();
+ }
+
+ SCOPED_TRACE(base::StringPrintf("Using %s path, iteration #%d", name, i));
+
+ // Source size equals maximum size. Expect delivered frames to be
+ // kTestWidth by kTestHeight.
+ source()->SetSolidColor(SK_ColorRED);
+ SimulateSourceSizeChange(gfx::Size(kTestWidth, kTestHeight));
+ SimulateDrawEvent();
+ ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
+ SK_ColorRED, gfx::Size(kTestWidth, kTestHeight)));
+
+ // Source size is half in both dimensions. Expect delivered frames to also
+ // be half in both dimensions.
+ source()->SetSolidColor(SK_ColorGREEN);
+ SimulateSourceSizeChange(gfx::Size(kTestWidth / 2, kTestHeight / 2));
+ SimulateDrawEvent();
+ ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
+ SK_ColorGREEN, gfx::Size(kTestWidth / 2, kTestHeight / 2)));
+
+ // Source size changes to something arbitrary. Since the source size is
+ // less than the maximum size, expect delivered frames to be the same size
+ // as the source size.
+ source()->SetSolidColor(SK_ColorBLUE);
+ gfx::Size arbitrary_source_size(kTestWidth / 2 + 42, kTestHeight - 10);
+ SimulateSourceSizeChange(arbitrary_source_size);
+ SimulateDrawEvent();
+ ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
+ SK_ColorBLUE, arbitrary_source_size));
+
+ // Source size changes to something arbitrary that exceeds the maximum frame
+ // size. Since the source size exceeds the maximum size, expect delivered
+ // frames to be downscaled.
+ source()->SetSolidColor(SK_ColorBLACK);
+ arbitrary_source_size = gfx::Size(kTestWidth * 2 + 99, kTestHeight / 2);
+ SimulateSourceSizeChange(arbitrary_source_size);
+ SimulateDrawEvent();
+ ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
+ SK_ColorBLACK, gfx::Size(kTestWidth,
+ kTestWidth * arbitrary_source_size.height() /
+ arbitrary_source_size.width())));
+ }
+
+ device()->StopAndDeAllocate();
+}
+
} // namespace
} // namespace content
diff --git a/chromium/content/browser/media/cdm/browser_cdm_manager.cc b/chromium/content/browser/media/cdm/browser_cdm_manager.cc
index d3d4630cb08..813a8bad696 100644
--- a/chromium/content/browser/media/cdm/browser_cdm_manager.cc
+++ b/chromium/content/browser/media/cdm/browser_cdm_manager.cc
@@ -4,49 +4,112 @@
#include "content/browser/media/cdm/browser_cdm_manager.h"
+#include <string>
+
#include "base/bind.h"
-#include "base/command_line.h"
#include "base/lazy_instance.h"
+#include "base/memory/scoped_ptr.h"
#include "base/task_runner.h"
-#include "content/common/media/cdm_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/permission_manager.h"
+#include "content/public/browser/permission_type.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/common/content_switches.h"
#include "media/base/browser_cdm.h"
#include "media/base/browser_cdm_factory.h"
-#include "media/base/media_switches.h"
+#include "media/base/cdm_promise.h"
+#include "media/base/limits.h"
+
+#if defined(OS_ANDROID)
+#include "content/public/common/renderer_preferences.h"
+#endif
namespace content {
using media::BrowserCdm;
using media::MediaKeys;
-// Maximum lengths for various EME API parameters. These are checks to
-// prevent unnecessarily large parameters from being passed around, and the
-// lengths are somewhat arbitrary as the EME spec doesn't specify any limits.
-const size_t kMaxInitDataLength = 64 * 1024; // 64 KB
-const size_t kMaxSessionResponseLength = 64 * 1024; // 64 KB
-const size_t kMaxKeySystemLength = 256;
+namespace {
+
+#if defined(OS_ANDROID)
+// Android only supports 128-bit key IDs.
+const size_t kAndroidKeyIdBytes = 128 / 8;
+#endif
// 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) {
+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) {
+bool IdBelongsToFrame(uint64 id, int render_frame_id) {
return (id >> 32) == static_cast<uint64>(render_frame_id);
}
+// media::CdmPromiseTemplate implementation backed by a BrowserCdmManager.
+template <typename... T>
+class CdmPromiseInternal : public media::CdmPromiseTemplate<T...> {
+ public:
+ CdmPromiseInternal(BrowserCdmManager* manager,
+ int render_frame_id,
+ int cdm_id,
+ uint32_t promise_id)
+ : manager_(manager),
+ render_frame_id_(render_frame_id),
+ cdm_id_(cdm_id),
+ promise_id_(promise_id) {
+ DCHECK(manager_);
+ }
+
+ ~CdmPromiseInternal() final {}
+
+ // CdmPromiseTemplate<> implementation.
+ void resolve(const T&... result) final;
+
+ void reject(MediaKeys::Exception exception,
+ uint32_t system_code,
+ const std::string& error_message) final {
+ MarkPromiseSettled();
+ manager_->RejectPromise(render_frame_id_, cdm_id_, promise_id_, exception,
+ system_code, error_message);
+ }
+
+ private:
+ using media::CdmPromiseTemplate<T...>::MarkPromiseSettled;
+
+ BrowserCdmManager* const manager_;
+ const int render_frame_id_;
+ const int cdm_id_;
+ const uint32_t promise_id_;
+};
+
+template <>
+void CdmPromiseInternal<>::resolve() {
+ MarkPromiseSettled();
+ manager_->ResolvePromise(render_frame_id_, cdm_id_, promise_id_);
+}
+
+template <>
+void CdmPromiseInternal<std::string>::resolve(const std::string& session_id) {
+ MarkPromiseSettled();
+ manager_->ResolvePromiseWithSession(render_frame_id_, cdm_id_, promise_id_,
+ session_id);
+}
+
+typedef CdmPromiseInternal<> SimplePromise;
+typedef CdmPromiseInternal<std::string> NewSessionPromise;
+
+} // namespace
+
// Render process ID to BrowserCdmManager map.
typedef std::map<int, BrowserCdmManager*> BrowserCdmManagerMap;
-base::LazyInstance<BrowserCdmManagerMap> g_browser_cdm_manager_map =
+base::LazyInstance<BrowserCdmManagerMap>::Leaky g_browser_cdm_manager_map =
LAZY_INSTANCE_INITIALIZER;
BrowserCdmManager* BrowserCdmManager::FromProcess(int render_process_id) {
@@ -63,7 +126,9 @@ BrowserCdmManager::BrowserCdmManager(
const scoped_refptr<base::TaskRunner>& task_runner)
: BrowserMessageFilter(CdmMsgStart),
render_process_id_(render_process_id),
- task_runner_(task_runner) {
+ task_runner_(task_runner),
+ weak_ptr_factory_(this) {
+ DVLOG(1) << __FUNCTION__ << ": " << render_process_id_;
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!task_runner_.get()) {
@@ -71,21 +136,23 @@ BrowserCdmManager::BrowserCdmManager(
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.
+ DCHECK(!g_browser_cdm_manager_map.Get().count(render_process_id_))
+ << render_process_id_;
g_browser_cdm_manager_map.Get()[render_process_id] = this;
}
BrowserCdmManager::~BrowserCdmManager() {
+ DVLOG(1) << __FUNCTION__ << ": " << render_process_id_;
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(g_browser_cdm_manager_map.Get().count(render_process_id_));
+ DCHECK_EQ(this, g_browser_cdm_manager_map.Get()[render_process_id_]);
g_browser_cdm_manager_map.Get().erase(render_process_id_);
}
// Makes sure BrowserCdmManager is always deleted on the Browser UI thread.
void BrowserCdmManager::OnDestruct() const {
+ DVLOG(1) << __FUNCTION__ << ": " << render_process_id_;
if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
delete this;
} else {
@@ -107,242 +174,325 @@ bool BrowserCdmManager::OnMessageReceived(const IPC::Message& msg) {
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_SetServerCertificate, OnSetServerCertificate)
+ IPC_MESSAGE_HANDLER(CdmHostMsg_CreateSessionAndGenerateRequest,
+ OnCreateSessionAndGenerateRequest)
IPC_MESSAGE_HANDLER(CdmHostMsg_UpdateSession, OnUpdateSession)
- IPC_MESSAGE_HANDLER(CdmHostMsg_ReleaseSession, OnReleaseSession)
+ IPC_MESSAGE_HANDLER(CdmHostMsg_CloseSession, OnCloseSession)
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) {
+media::BrowserCdm* BrowserCdmManager::GetCdm(int render_frame_id,
+ int cdm_id) const {
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());
+ if (!task_runner_->RunsTasksOnCurrentThread()) {
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&BrowserCdmManager::RemoveAllCdmForFrame,
+ this, render_frame_id));
+ return;
+ }
+ RemoveAllCdmForFrame(render_frame_id);
+}
- 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);
+void BrowserCdmManager::ResolvePromise(int render_frame_id,
+ int cdm_id,
+ uint32_t promise_id) {
+ Send(new CdmMsg_ResolvePromise(render_frame_id, cdm_id, promise_id));
+}
+
+void BrowserCdmManager::ResolvePromiseWithSession(
+ int render_frame_id,
+ int cdm_id,
+ uint32_t promise_id,
+ const std::string& session_id) {
+ if (session_id.length() > media::limits::kMaxSessionIdLength) {
+ RejectPromise(render_frame_id, cdm_id, promise_id,
+ MediaKeys::INVALID_ACCESS_ERROR, 0,
+ "Session ID is too long.");
+ return;
}
- for (size_t i = 0; i < ids_to_remove.size(); ++i)
- RemoveCdm(ids_to_remove[i]);
+ Send(new CdmMsg_ResolvePromiseWithSession(render_frame_id, cdm_id, promise_id,
+ session_id));
}
-void BrowserCdmManager::OnSessionCreated(int render_frame_id,
- int cdm_id,
- uint32 session_id,
- const std::string& web_session_id) {
- Send(new CdmMsg_SessionCreated(
- render_frame_id, cdm_id, session_id, web_session_id));
+void BrowserCdmManager::RejectPromise(int render_frame_id,
+ int cdm_id,
+ uint32_t promise_id,
+ media::MediaKeys::Exception exception,
+ uint32_t system_code,
+ const std::string& error_message) {
+ Send(new CdmMsg_RejectPromise(render_frame_id, cdm_id, promise_id, exception,
+ system_code, error_message));
}
-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;
+void BrowserCdmManager::OnSessionMessage(
+ int render_frame_id,
+ int cdm_id,
+ const std::string& session_id,
+ media::MediaKeys::MessageType message_type,
+ const std::vector<uint8>& message,
+ const GURL& legacy_destination_url) {
+ GURL verified_gurl = legacy_destination_url;
if (!verified_gurl.is_valid() && !verified_gurl.is_empty()) {
- DLOG(WARNING) << "SessionMessage destination_url is invalid : "
- << destination_url.possibly_invalid_spec();
- verified_gurl = GURL::EmptyGURL(); // Replace invalid destination_url.
+ DLOG(WARNING) << "SessionMessage legacy_destination_url is invalid : "
+ << legacy_destination_url.possibly_invalid_spec();
+ verified_gurl =
+ GURL::EmptyGURL(); // Replace invalid legacy_destination_url.
}
- Send(new CdmMsg_SessionMessage(
- render_frame_id, cdm_id, session_id, message, verified_gurl));
-}
-
-void BrowserCdmManager::OnSessionReady(int render_frame_id,
- int cdm_id,
- uint32 session_id) {
- Send(new CdmMsg_SessionReady(render_frame_id, cdm_id, session_id));
+ Send(new CdmMsg_SessionMessage(render_frame_id, cdm_id, session_id,
+ message_type, message, verified_gurl));
}
void BrowserCdmManager::OnSessionClosed(int render_frame_id,
int cdm_id,
- uint32 session_id) {
+ const std::string& session_id) {
Send(new CdmMsg_SessionClosed(render_frame_id, cdm_id, session_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(
- render_frame_id, cdm_id, session_id, error_code, system_code));
+void BrowserCdmManager::OnLegacySessionError(
+ int render_frame_id,
+ int cdm_id,
+ const std::string& session_id,
+ MediaKeys::Exception exception_code,
+ uint32 system_code,
+ const std::string& error_message) {
+ Send(new CdmMsg_LegacySessionError(render_frame_id, cdm_id, session_id,
+ exception_code, system_code,
+ error_message));
}
-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.
- NOTREACHED() << "Invalid key system: " << key_system;
+void BrowserCdmManager::OnSessionKeysChange(int render_frame_id,
+ int cdm_id,
+ const std::string& session_id,
+ bool has_additional_usable_key,
+ media::CdmKeysInfo keys_info) {
+ std::vector<media::CdmKeyInformation> key_info_vector;
+ for (const auto& key_info : keys_info)
+ key_info_vector.push_back(*key_info);
+ Send(new CdmMsg_SessionKeysChange(render_frame_id, cdm_id, session_id,
+ has_additional_usable_key,
+ key_info_vector));
+}
+
+void BrowserCdmManager::OnSessionExpirationUpdate(
+ int render_frame_id,
+ int cdm_id,
+ const std::string& session_id,
+ const base::Time& new_expiry_time) {
+ Send(new CdmMsg_SessionExpirationUpdate(render_frame_id, cdm_id, session_id,
+ new_expiry_time));
+}
+
+void BrowserCdmManager::OnInitializeCdm(
+ int render_frame_id,
+ int cdm_id,
+ uint32_t promise_id,
+ const CdmHostMsg_InitializeCdm_Params& params) {
+ if (params.key_system.size() > media::limits::kMaxKeySystemLength) {
+ NOTREACHED() << "Invalid key system: " << params.key_system;
+ RejectPromise(render_frame_id, cdm_id, promise_id,
+ MediaKeys::INVALID_ACCESS_ERROR, 0, "Invalid key system.");
return;
}
- AddCdm(render_frame_id, cdm_id, key_system, security_origin);
+ AddCdm(render_frame_id, cdm_id, promise_id, params.key_system,
+ params.security_origin, params.use_hw_secure_codecs);
}
-void BrowserCdmManager::OnCreateSession(
+void BrowserCdmManager::OnSetServerCertificate(
int render_frame_id,
int cdm_id,
- uint32 session_id,
- CdmHostMsg_CreateSession_ContentType content_type,
+ uint32_t promise_id,
+ const std::vector<uint8_t>& certificate) {
+ DCHECK(task_runner_->RunsTasksOnCurrentThread());
+
+ scoped_ptr<SimplePromise> promise(
+ new SimplePromise(this, render_frame_id, cdm_id, promise_id));
+
+ BrowserCdm* cdm = GetCdm(render_frame_id, cdm_id);
+ if (!cdm) {
+ promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found.");
+ return;
+ }
+
+ if (certificate.empty()) {
+ promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Empty certificate.");
+ return;
+ }
+
+ cdm->SetServerCertificate(certificate, promise.Pass());
+}
+
+void BrowserCdmManager::OnCreateSessionAndGenerateRequest(
+ int render_frame_id,
+ int cdm_id,
+ uint32_t promise_id,
+ CdmHostMsg_CreateSession_InitDataType init_data_type,
const std::vector<uint8>& init_data) {
- if (init_data.size() > kMaxInitDataLength) {
+ DCHECK(task_runner_->RunsTasksOnCurrentThread());
+
+ scoped_ptr<NewSessionPromise> promise(
+ new NewSessionPromise(this, render_frame_id, cdm_id, promise_id));
+
+ if (init_data.size() > media::limits::kMaxInitDataLength) {
LOG(WARNING) << "InitData for ID: " << cdm_id
<< " too long: " << init_data.size();
- SendSessionError(render_frame_id, cdm_id, session_id);
+ promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Init data too long.");
+ return;
+ }
+#if defined(OS_ANDROID)
+ // 'webm' initData is a single key ID. On Android the length is restricted.
+ if (init_data_type == INIT_DATA_TYPE_WEBM &&
+ init_data.size() != kAndroidKeyIdBytes) {
+ promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0,
+ "'webm' initData is not the correct length.");
return;
}
+#endif
- // Convert the session content type into a MIME type. "audio" and "video"
- // don't matter, so using "video" for the MIME type.
- // Ref:
- // https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html#dom-createsession
- std::string mime_type;
- switch (content_type) {
- case CREATE_SESSION_TYPE_WEBM:
- mime_type = "video/webm";
+ media::EmeInitDataType eme_init_data_type;
+ switch (init_data_type) {
+ case INIT_DATA_TYPE_WEBM:
+ eme_init_data_type = media::EmeInitDataType::WEBM;
break;
- case CREATE_SESSION_TYPE_MP4:
- mime_type = "video/mp4";
+#if defined(USE_PROPRIETARY_CODECS)
+ case INIT_DATA_TYPE_CENC:
+ eme_init_data_type = media::EmeInitDataType::CENC;
break;
+#endif
default:
NOTREACHED();
+ promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0,
+ "Invalid init data type.");
return;
}
-#if defined(OS_ANDROID)
- if (CommandLine::ForCurrentProcess()
- ->HasSwitch(switches::kDisableInfobarForProtectedMediaIdentifier)) {
- CreateSessionIfPermitted(
- render_frame_id, cdm_id, session_id, mime_type, init_data, true);
- return;
- }
-#endif
-
BrowserCdm* cdm = GetCdm(render_frame_id, cdm_id);
if (!cdm) {
DLOG(WARNING) << "No CDM found for: " << render_frame_id << ", " << cdm_id;
- SendSessionError(render_frame_id, cdm_id, session_id);
+ promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found.");
return;
}
- 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();
- SendSessionError(render_frame_id, cdm_id, session_id);
- return;
- }
- GURL security_origin = iter->second;
+ CheckPermissionStatus(
+ render_frame_id, cdm_id,
+ base::Bind(&BrowserCdmManager::CreateSessionAndGenerateRequestIfPermitted,
+ this, render_frame_id, cdm_id, eme_init_data_type, init_data,
+ base::Passed(&promise)));
+}
+
+void BrowserCdmManager::OnUpdateSession(int render_frame_id,
+ int cdm_id,
+ uint32_t promise_id,
+ const std::string& session_id,
+ const std::vector<uint8>& response) {
+ DCHECK(task_runner_->RunsTasksOnCurrentThread());
+
+ scoped_ptr<SimplePromise> promise(
+ new SimplePromise(this, render_frame_id, cdm_id, promise_id));
- 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,
- this,
- render_frame_id,
- cdm_id,
- session_id,
- mime_type,
- init_data));
-}
-
-void BrowserCdmManager::OnUpdateSession(
- int render_frame_id,
- int cdm_id,
- uint32 session_id,
- const std::vector<uint8>& response) {
BrowserCdm* cdm = GetCdm(render_frame_id, cdm_id);
if (!cdm) {
- DLOG(WARNING) << "No CDM found for: " << render_frame_id << ", " << cdm_id;
- SendSessionError(render_frame_id, cdm_id, session_id);
+ promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found.");
return;
}
- if (response.size() > kMaxSessionResponseLength) {
+ if (response.size() > media::limits::kMaxSessionResponseLength) {
LOG(WARNING) << "Response for ID " << cdm_id
<< " is too long: " << response.size();
- SendSessionError(render_frame_id, cdm_id, session_id);
+ promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Response too long.");
return;
}
- cdm->UpdateSession(session_id, &response[0], response.size());
+ if (response.empty()) {
+ promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Response is empty.");
+ return;
+ }
+
+ cdm->UpdateSession(session_id, response, promise.Pass());
}
-void BrowserCdmManager::OnReleaseSession(int render_frame_id,
- int cdm_id,
- uint32 session_id) {
+void BrowserCdmManager::OnCloseSession(int render_frame_id,
+ int cdm_id,
+ uint32_t promise_id,
+ const std::string& session_id) {
+ DCHECK(task_runner_->RunsTasksOnCurrentThread());
+
+ scoped_ptr<SimplePromise> promise(
+ new SimplePromise(this, render_frame_id, cdm_id, promise_id));
+
BrowserCdm* cdm = GetCdm(render_frame_id, cdm_id);
if (!cdm) {
- DLOG(WARNING) << "No CDM found for: " << render_frame_id << ", " << cdm_id;
- SendSessionError(render_frame_id, cdm_id, session_id);
+ promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found.");
return;
}
- cdm->ReleaseSession(session_id);
+ cdm->CloseSession(session_id, promise.Pass());
}
void BrowserCdmManager::OnDestroyCdm(int render_frame_id, int cdm_id) {
+ DCHECK(task_runner_->RunsTasksOnCurrentThread());
RemoveCdm(GetId(render_frame_id, 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);
-}
-
-#define BROWSER_CDM_MANAGER_CB(func) \
- base::Bind(&BrowserCdmManager::func, this, render_frame_id, cdm_id)
+// Use a weak pointer here instead of |this| to avoid circular references.
+#define BROWSER_CDM_MANAGER_CB(func) \
+ base::Bind(&BrowserCdmManager::func, weak_ptr_factory_.GetWeakPtr(), \
+ render_frame_id, cdm_id)
void BrowserCdmManager::AddCdm(int render_frame_id,
int cdm_id,
+ uint32_t promise_id,
const std::string& key_system,
- const GURL& security_origin) {
+ const GURL& security_origin,
+ bool use_hw_secure_codecs) {
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)));
+ scoped_ptr<SimplePromise> promise(
+ new SimplePromise(this, render_frame_id, cdm_id, promise_id));
+
+ scoped_ptr<BrowserCdm> cdm(media::CreateBrowserCdm(
+ key_system, use_hw_secure_codecs,
+ BROWSER_CDM_MANAGER_CB(OnSessionMessage),
+ BROWSER_CDM_MANAGER_CB(OnSessionClosed),
+ BROWSER_CDM_MANAGER_CB(OnLegacySessionError),
+ BROWSER_CDM_MANAGER_CB(OnSessionKeysChange),
+ BROWSER_CDM_MANAGER_CB(OnSessionExpirationUpdate)));
if (!cdm) {
- // This failure will be discovered and reported by OnCreateSession()
- // as GetCdm() will return null.
DVLOG(1) << "failed to create CDM.";
+ promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "Failed to create CDM.");
return;
}
uint64 id = GetId(render_frame_id, cdm_id);
cdm_map_.add(id, cdm.Pass());
cdm_security_origin_map_[id] = security_origin;
+ promise->resolve();
+}
+
+void BrowserCdmManager::RemoveAllCdmForFrame(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::RemoveCdm(uint64 id) {
@@ -350,34 +500,90 @@ void BrowserCdmManager::RemoveCdm(uint64 id) {
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::CheckPermissionStatus(
+ int render_frame_id,
+ int cdm_id,
+ const PermissionStatusCB& permission_status_cb) {
+ // Always called on |task_runner_|, which may not be on the UI thread.
+ DCHECK(task_runner_->RunsTasksOnCurrentThread());
+
+ GURL security_origin;
+ std::map<uint64, GURL>::const_iterator iter =
+ cdm_security_origin_map_.find(GetId(render_frame_id, cdm_id));
+ DCHECK(iter != cdm_security_origin_map_.end());
+ if (iter != cdm_security_origin_map_.end())
+ security_origin = iter->second;
+
+ if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&BrowserCdmManager::CheckPermissionStatusOnUIThread, this,
+ render_frame_id, security_origin, permission_status_cb));
+ } else {
+ CheckPermissionStatusOnUIThread(render_frame_id, security_origin,
+ permission_status_cb);
}
}
-void BrowserCdmManager::CreateSessionIfPermitted(
+// Note: This function runs on the UI thread, which may be different from
+// |task_runner_|. Be careful about thread safety!
+void BrowserCdmManager::CheckPermissionStatusOnUIThread(
+ int render_frame_id,
+ const GURL& security_origin,
+ const base::Callback<void(bool)>& permission_status_cb) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ RenderFrameHost* rfh =
+ RenderFrameHost::FromID(render_process_id_, render_frame_id);
+ WebContents* web_contents = WebContents::FromRenderFrameHost(rfh);
+ PermissionManager* permission_manager =
+ web_contents->GetBrowserContext()->GetPermissionManager();
+ if (!permission_manager) {
+ permission_status_cb.Run(false);
+ return;
+ }
+
+ PermissionStatus permission_status = permission_manager->GetPermissionStatus(
+ content::PermissionType::PROTECTED_MEDIA_IDENTIFIER,
+ security_origin,
+ web_contents->GetLastCommittedURL().GetOrigin());
+
+ bool allowed = (permission_status == PERMISSION_STATUS_GRANTED);
+ if (!task_runner_->RunsTasksOnCurrentThread()) {
+ task_runner_->PostTask(FROM_HERE,
+ base::Bind(permission_status_cb, allowed));
+ } else {
+ permission_status_cb.Run(allowed);
+ }
+}
+
+void BrowserCdmManager::CreateSessionAndGenerateRequestIfPermitted(
int render_frame_id,
int cdm_id,
- uint32 session_id,
- const std::string& content_type,
+ media::EmeInitDataType init_data_type,
const std::vector<uint8>& init_data,
- bool permitted) {
- cdm_cancel_permission_map_.erase(GetId(render_frame_id, cdm_id));
- if (!permitted) {
- SendSessionError(render_frame_id, cdm_id, session_id);
+ scoped_ptr<media::NewSessionCdmPromise> promise,
+ bool permission_was_allowed) {
+ DCHECK(task_runner_->RunsTasksOnCurrentThread());
+
+ if (!permission_was_allowed) {
+ promise->reject(MediaKeys::NOT_SUPPORTED_ERROR, 0, "Permission denied.");
return;
}
BrowserCdm* cdm = GetCdm(render_frame_id, cdm_id);
if (!cdm) {
- DLOG(WARNING) << "No CDM found for: " << render_frame_id << ", " << cdm_id;
- SendSessionError(render_frame_id, cdm_id, session_id);
+ promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found.");
return;
}
- // This could fail, in which case a SessionError will be fired.
- cdm->CreateSession(session_id, content_type, &init_data[0], init_data.size());
+ // Only the temporary session type is supported in browser CDM path.
+ // TODO(xhwang): Add SessionType support if needed.
+ cdm->CreateSessionAndGenerateRequest(media::MediaKeys::TEMPORARY_SESSION,
+ init_data_type, init_data,
+ promise.Pass());
}
} // namespace content
diff --git a/chromium/content/browser/media/cdm/browser_cdm_manager.h b/chromium/content/browser/media/cdm/browser_cdm_manager.h
index 27fb5c93e83..57684da3db6 100644
--- a/chromium/content/browser/media/cdm/browser_cdm_manager.h
+++ b/chromium/content/browser/media/cdm/browser_cdm_manager.h
@@ -13,11 +13,15 @@
#include "base/callback.h"
#include "base/containers/scoped_ptr_hash_map.h"
#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
#include "content/common/content_export.h"
+#include "content/common/media/cdm_messages.h"
#include "content/common/media/cdm_messages_enums.h"
#include "content/public/browser/browser_message_filter.h"
+#include "content/public/common/permission_status.mojom.h"
#include "ipc/ipc_message.h"
-// TODO(xhwang): Drop this when KeyError is moved to a common header.
+#include "media/base/cdm_promise.h"
+#include "media/base/eme_constants.h"
#include "media/base/media_keys.h"
#include "url/gurl.h"
@@ -44,12 +48,12 @@ class CONTENT_EXPORT BrowserCdmManager : public BrowserMessageFilter {
const scoped_refptr<base::TaskRunner>& task_runner);
// BrowserMessageFilter implementations.
- virtual void OnDestruct() const override;
- virtual base::TaskRunner* OverrideTaskRunnerForMessage(
+ void OnDestruct() const override;
+ base::TaskRunner* OverrideTaskRunnerForMessage(
const IPC::Message& message) override;
- virtual bool OnMessageReceived(const IPC::Message& message) override;
+ bool OnMessageReceived(const IPC::Message& message) override;
- media::BrowserCdm* GetCdm(int render_frame_id, int cdm_id);
+ media::BrowserCdm* GetCdm(int render_frame_id, int cdm_id) const;
// 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
@@ -57,71 +61,116 @@ class CONTENT_EXPORT BrowserCdmManager : public BrowserMessageFilter {
// destroy the CDM will not be received.
void RenderFrameDeleted(int render_frame_id);
+ // Promise handlers.
+ void ResolvePromise(int render_frame_id, int cdm_id, uint32_t promise_id);
+ void ResolvePromiseWithSession(int render_frame_id,
+ int cdm_id,
+ uint32_t promise_id,
+ const std::string& session_id);
+ void RejectPromise(int render_frame_id,
+ int cdm_id,
+ uint32_t promise_id,
+ media::MediaKeys::Exception exception,
+ uint32_t system_code,
+ const std::string& error_message);
+
protected:
friend class base::RefCountedThreadSafe<BrowserCdmManager>;
friend class base::DeleteHelper<BrowserCdmManager>;
- virtual ~BrowserCdmManager();
+ ~BrowserCdmManager() override;
private:
// CDM callbacks.
- void OnSessionCreated(int render_frame_id,
- int cdm_id,
- uint32 session_id,
- const std::string& web_session_id);
void OnSessionMessage(int render_frame_id,
int cdm_id,
- uint32 session_id,
+ const std::string& session_id,
+ media::MediaKeys::MessageType message_type,
const std::vector<uint8>& message,
- const GURL& destination_url);
- 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);
+ const GURL& legacy_destination_url);
+ void OnSessionClosed(int render_frame_id,
+ int cdm_id,
+ const std::string& session_id);
+ void OnLegacySessionError(int render_frame_id,
+ int cdm_id,
+ const std::string& session_id,
+ media::MediaKeys::Exception exception_code,
+ uint32_t system_code,
+ const std::string& error_message);
+ void OnSessionKeysChange(int render_frame_id,
+ int cdm_id,
+ const std::string& session_id,
+ bool has_additional_usable_key,
+ media::CdmKeysInfo keys_info);
+ void OnSessionExpirationUpdate(int render_frame_id,
+ int cdm_id,
+ const std::string& session_id,
+ const base::Time& new_expiry_time);
// Message handlers.
void OnInitializeCdm(int render_frame_id,
int cdm_id,
- const std::string& key_system,
- const GURL& frame_url);
- void OnCreateSession(int render_frame_id,
- int cdm_id,
- uint32 session_id,
- CdmHostMsg_CreateSession_ContentType content_type,
- const std::vector<uint8>& init_data);
+ uint32_t promise_id,
+ const CdmHostMsg_InitializeCdm_Params& params);
+ void OnSetServerCertificate(int render_frame_id,
+ int cdm_id,
+ uint32_t promise_id,
+ const std::vector<uint8_t>& certificate);
+ void OnCreateSessionAndGenerateRequest(
+ int render_frame_id,
+ int cdm_id,
+ uint32_t promise_id,
+ CdmHostMsg_CreateSession_InitDataType init_data_type,
+ const std::vector<uint8>& init_data);
void OnUpdateSession(int render_frame_id,
int cdm_id,
- uint32 session_id,
+ uint32_t promise_id,
+ const std::string& session_id,
const std::vector<uint8>& response);
- void OnReleaseSession(int render_frame_id,
- int cdm_id, uint32 session_id);
+ void OnCloseSession(int render_frame_id,
+ int cdm_id,
+ uint32_t promise_id,
+ const std::string& session_id);
void OnDestroyCdm(int render_frame_id, 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 render_frame_id,
int cdm_id,
+ uint32_t promise_id,
const std::string& key_system,
- const GURL& security_origin);
+ const GURL& security_origin,
+ bool use_hw_secure_codecs);
+
+ // Removes all CDMs associated with |render_frame_id|.
+ void RemoveAllCdmForFrame(int render_frame_id);
// Removes the CDM with the specified id.
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 render_frame_id,
- int cdm_id,
- uint32 session_id,
- const std::string& content_type,
- const std::vector<uint8>& init_data,
- bool permitted);
+ using PermissionStatusCB = base::Callback<void(bool)>;
+
+ // Checks protected media identifier permission for the given
+ // |render_frame_id| and |cdm_id|.
+ void CheckPermissionStatus(int render_frame_id,
+ int cdm_id,
+ const PermissionStatusCB& permission_status_cb);
+
+ // Checks permission status on Browser UI thread. Runs |permission_status_cb|
+ // on the |task_runner_| with the permission status.
+ void CheckPermissionStatusOnUIThread(
+ int render_frame_id,
+ const GURL& security_origin,
+ const PermissionStatusCB& permission_status_cb);
+
+ // Calls CreateSessionAndGenerateRequest() on the CDM if
+ // |permission_was_allowed| is true. Otherwise rejects the |promise|.
+ void CreateSessionAndGenerateRequestIfPermitted(
+ int render_frame_id,
+ int cdm_id,
+ media::EmeInitDataType init_data_type,
+ const std::vector<uint8>& init_data,
+ scoped_ptr<media::NewSessionCdmPromise> promise,
+ bool permission_was_allowed);
const int render_process_id_;
@@ -133,14 +182,13 @@ class CONTENT_EXPORT BrowserCdmManager : public BrowserMessageFilter {
// |cdm_id|.
// Map of managed BrowserCdms.
- typedef base::ScopedPtrHashMap<uint64, media::BrowserCdm> CdmMap;
+ typedef base::ScopedPtrHashMap<uint64, scoped_ptr<media::BrowserCdm>> CdmMap;
CdmMap cdm_map_;
// Map of CDM's security origin.
std::map<uint64, GURL> cdm_security_origin_map_;
- // Map of callbacks to cancel the permission request.
- std::map<uint64, base::Closure> cdm_cancel_permission_map_;
+ base::WeakPtrFactory<BrowserCdmManager> weak_ptr_factory_;
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 3d561424107..b6067302274 100644
--- a/chromium/content/browser/media/encrypted_media_browsertest.cc
+++ b/chromium/content/browser/media/encrypted_media_browsertest.cc
@@ -129,7 +129,7 @@ class EncryptedMediaTest : public content::MediaBrowserTest,
}
#if defined(OS_ANDROID)
- virtual void SetUpCommandLine(CommandLine* command_line) override {
+ void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitch(
switches::kDisableGestureRequirementForMediaPlayback);
}
@@ -168,16 +168,35 @@ IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoClearAudio_WebM) {
TestSimplePlayback("bear-320x240-av_enc-v.webm", kWebMAudioVideo);
}
+IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_AudioOnly_WebM_Opus) {
+ // Opus is not supported on Android. http://crbug.com/318436
+#if defined(OS_ANDROID)
+ return;
+#endif
+ TestSimplePlayback("bear-320x240-opus-a_enc-a.webm", kWebMAudioOnly);
+}
+
+IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoAudio_WebM_Opus) {
+ // Opus is not supported on Android. http://crbug.com/318436
+#if defined(OS_ANDROID)
+ return;
+#endif
+ TestSimplePlayback("bear-320x240-opus-av_enc-av.webm", kWebMAudioVideo);
+}
+
+IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoClearAudio_WebM_Opus) {
+ // Opus is not supported on Android. http://crbug.com/318436
+#if defined(OS_ANDROID)
+ return;
+#endif
+ TestSimplePlayback("bear-320x240-opus-av_enc-v.webm", kWebMAudioVideo);
+}
+
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, ConfigChangeVideo) {
TestConfigChange();
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, FrameSizeChangeVideo) {
- // Times out on Windows XP. http://crbug.com/171937
-#if defined(OS_WIN)
- if (base::win::GetVersion() < base::win::VERSION_VISTA)
- return;
-#endif
TestFrameSizeChange();
}
diff --git a/chromium/content/browser/media/media_browsertest.cc b/chromium/content/browser/media/media_browsertest.cc
index 46f7a49b618..f47c4a506a9 100644
--- a/chromium/content/browser/media/media_browsertest.cc
+++ b/chromium/content/browser/media/media_browsertest.cc
@@ -13,13 +13,6 @@
#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
-#define MAYBE(x) DISABLED_##x
-#else
-#define MAYBE(x) x
-#endif
-
namespace content {
// Common test results.
@@ -238,40 +231,44 @@ IN_PROC_BROWSER_TEST_F(MediaTest, Navigate) {
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)) {
+IN_PROC_BROWSER_TEST_F(MediaTest, Yuv420pTheora) {
RunColorFormatTest("yuv420p.ogv", kEnded);
}
-IN_PROC_BROWSER_TEST_F(MediaTest, MAYBE(Yuv422pTheora)) {
+IN_PROC_BROWSER_TEST_F(MediaTest, Yuv422pTheora) {
RunColorFormatTest("yuv422p.ogv", kEnded);
}
-IN_PROC_BROWSER_TEST_F(MediaTest, MAYBE(Yuv444pTheora)) {
+IN_PROC_BROWSER_TEST_F(MediaTest, Yuv444pTheora) {
RunColorFormatTest("yuv444p.ogv", kEnded);
}
-IN_PROC_BROWSER_TEST_F(MediaTest, MAYBE(Yuv420pVp8)) {
+IN_PROC_BROWSER_TEST_F(MediaTest, Yuv420pVp8) {
RunColorFormatTest("yuv420p.webm", kEnded);
}
-IN_PROC_BROWSER_TEST_F(MediaTest, MAYBE(Yuv444pVp9)) {
+IN_PROC_BROWSER_TEST_F(MediaTest, Yuv444pVp9) {
RunColorFormatTest("yuv444p.webm", "ENDED");
}
#if defined(USE_PROPRIETARY_CODECS)
-IN_PROC_BROWSER_TEST_F(MediaTest, MAYBE(Yuv420pH264)) {
+IN_PROC_BROWSER_TEST_F(MediaTest, Yuv420pH264) {
RunColorFormatTest("yuv420p.mp4", kEnded);
}
-IN_PROC_BROWSER_TEST_F(MediaTest, MAYBE(Yuvj420pH264)) {
+IN_PROC_BROWSER_TEST_F(MediaTest, Yuv420pRec709H264) {
+ RunColorFormatTest("yuv420p_rec709.mp4", kEnded);
+}
+
+IN_PROC_BROWSER_TEST_F(MediaTest, Yuvj420pH264) {
RunColorFormatTest("yuvj420p.mp4", kEnded);
}
-IN_PROC_BROWSER_TEST_F(MediaTest, MAYBE(Yuv422pH264)) {
+IN_PROC_BROWSER_TEST_F(MediaTest, Yuv422pH264) {
RunColorFormatTest("yuv422p.mp4", kEnded);
}
-IN_PROC_BROWSER_TEST_F(MediaTest, MAYBE(Yuv444pH264)) {
+IN_PROC_BROWSER_TEST_F(MediaTest, Yuv444pH264) {
RunColorFormatTest("yuv444p.mp4", kEnded);
}
diff --git a/chromium/content/browser/media/media_canplaytype_browsertest.cc b/chromium/content/browser/media/media_canplaytype_browsertest.cc
index e454de461ec..b44a3a1f752 100644
--- a/chromium/content/browser/media/media_canplaytype_browsertest.cc
+++ b/chromium/content/browser/media/media_canplaytype_browsertest.cc
@@ -25,24 +25,24 @@ const char kPropProbably[] = "";
const char kPropMaybe[] = "";
#endif // USE_PROPRIETARY_CODECS
-// TODO(amogh.bihani): Change the opus tests when opus is on
-// Android. (http://crbug.com/318436).
#if !defined(OS_ANDROID)
const char kOggVideoProbably[] = "probably";
const char kOggVideoMaybe[] = "maybe";
const char kTheoraProbably[] = "probably";
-const char kOpusProbably[] = "probably";
+const char kOggOpusProbably[] = "probably";
+const char* kMpeg2AacProbably = kPropProbably;
#else
const char kOggVideoProbably[] = "";
const char kOggVideoMaybe[] = "";
const char kTheoraProbably[] = "";
-const char kOpusProbably[] = "";
+const char kOggOpusProbably[] = "";
+const char kMpeg2AacProbably[] = "";
#endif // !OS_ANDROID
namespace content {
class MediaCanPlayTypeTest : public MediaBrowserTest {
-public:
+ public:
MediaCanPlayTypeTest() : url_("about:blank") { }
void SetUpOnMainThread() override { NavigateToURL(shell(), url_); }
@@ -60,19 +60,58 @@ 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\"'"));
+ void TestMPEGUnacceptableCombinations(const std::string& mime) {
+ // AVC codecs must be followed by valid 6-digit hexadecimal number.
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1.12345\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3.12345\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1.1234567\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3.1234567\"'"));
+ // TODO(ddorwin): These four should return "". See crbug.com/457076.
+// EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1.number\"'"));
+// EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3.number\"'"));
+// EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1.12345.\"'"));
+// EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3.12345.\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1.123456.\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3.123456.\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1.123456.7\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3.123456.7\"'"));
+
+ // AAC codecs must be followed by one or two valid hexadecimal numbers.
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.no\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.0k\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.0k.0k\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.4.\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.40.0k\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.40.\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.40k\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.40.2k\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.40.2k\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.40.2.\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.40.2.0\"'"));
+
+ // Unlike just "avc1", just "mp4a" is not supported.
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.\"'"));
+
+ // Other names for the codecs are not supported.
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"h264\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"h.264\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"H264\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"H.264\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"aac\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"AAC\"'"));
// 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.\"'"));
+ // A simple substring match is not sufficient.
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"lavc1337\"'"));
+ 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\"'"));
@@ -92,6 +131,8 @@ public:
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=\"vp8, mp4a.40.02\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"vp9, mp4a.40.02\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"1\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1, 1\"'"));
@@ -102,6 +143,7 @@ public:
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\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"theora, mp4a.40.02\"'"));
// Codecs are case sensitive.
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"AVC1\"'"));
@@ -110,12 +152,17 @@ public:
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=\"MP4A.40.02\"'"));
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\"'"));
+ EXPECT_EQ(kNot,
+ CanPlay("'" + mime + "; codecs=\", AVC1.4D401E, MP4.40.02\"'"));
+ EXPECT_EQ(kNot,
+ CanPlay("'" + mime + "; codecs=\", AVC3.64001F, MP4.40.02\"'"));
// Unknown codecs.
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc2\"'"));
@@ -128,7 +175,7 @@ public:
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"unknown\"'"));
}
- void TestOGGUnacceptableCombinations(std::string mime) {
+ void TestOGGUnacceptableCombinations(const std::string& mime) {
// Codecs not belonging to OGG container.
EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"vp8\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"vp8.0\"'"));
@@ -151,7 +198,9 @@ public:
EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"mp4a.40\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"mp4a.40.2\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"mp4a.40.02\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"theora, mp4a.40.2\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"theora, mp4a.40.02\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"1\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"theora, 1\"'"));
@@ -167,7 +216,7 @@ public:
EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"unknown\"'"));
}
- void TestWEBMUnacceptableCombinations(std::string mime) {
+ void TestWEBMUnacceptableCombinations(const std::string& mime) {
// Codecs not belonging to WEBM container.
EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"1\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"vp8, 1\"'"));
@@ -190,6 +239,7 @@ public:
EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"mp4a.40\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"mp4a.40.2\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"mp4a.40.02\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"vp8, mp4a.40\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"vp9, mp4a.40\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"vp8.0, mp4a.40\"'"));
@@ -205,7 +255,7 @@ public:
EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"unknown\"'"));
}
- void TestWAVUnacceptableCombinations(std::string mime) {
+ void TestWAVUnacceptableCombinations(const std::string& mime) {
// Codecs not belonging to WAV container.
EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"vp8\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"vp9\"'"));
@@ -226,12 +276,13 @@ public:
EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"mp4a.40\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"mp4a.40.2\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"mp4a.40.02\"'"));
// Unknown codec.
EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"unknown\"'"));
}
-private:
+ private:
GURL url_;
DISALLOW_COPY_AND_ASSIGN(MediaCanPlayTypeTest);
};
@@ -249,13 +300,18 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_wav) {
}
IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_webm) {
- // On Android, VP9 is supported only on KitKat and above (API level 19).
+ // On Android, VP9 is supported only on KitKat and above (API level 19) and
+ // Opus is supported only on Lollipop and above (API level 21).
std::string VP9Probably = "probably";
std::string VP9AndOpusProbably = "probably";
+ std::string OpusProbably = "probably";
#if defined(OS_ANDROID)
- VP9AndOpusProbably = "";
if (base::android::BuildInfo::GetInstance()->sdk_int() < 19)
VP9Probably = "";
+ if (base::android::BuildInfo::GetInstance()->sdk_int() < 21) {
+ OpusProbably = "";
+ VP9AndOpusProbably = "";
+ }
#endif
EXPECT_EQ(kMaybe, CanPlay("'video/webm'"));
@@ -263,8 +319,8 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_webm) {
EXPECT_EQ(kProbably, CanPlay("'video/webm; codecs=\"vp8.0\"'"));
EXPECT_EQ(kProbably, CanPlay("'video/webm; codecs=\"vp8, vorbis\"'"));
EXPECT_EQ(kProbably, CanPlay("'video/webm; codecs=\"vp8.0, vorbis\"'"));
- EXPECT_EQ(kOpusProbably, CanPlay("'video/webm; codecs=\"vp8, opus\"'"));
- EXPECT_EQ(kOpusProbably, CanPlay("'video/webm; codecs=\"vp8.0, opus\"'"));
+ EXPECT_EQ(OpusProbably, CanPlay("'video/webm; codecs=\"vp8, opus\"'"));
+ EXPECT_EQ(OpusProbably, CanPlay("'video/webm; codecs=\"vp8.0, opus\"'"));
EXPECT_EQ(VP9Probably, CanPlay("'video/webm; codecs=\"vp9\"'"));
EXPECT_EQ(VP9Probably, CanPlay("'video/webm; codecs=\"vp9.0\"'"));
@@ -281,8 +337,8 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_webm) {
EXPECT_EQ(kMaybe, CanPlay("'audio/webm'"));
EXPECT_EQ(kProbably, CanPlay("'audio/webm; codecs=\"vorbis\"'"));
- EXPECT_EQ(kOpusProbably, CanPlay("'audio/webm; codecs=\"opus\"'"));
- EXPECT_EQ(kOpusProbably, CanPlay("'audio/webm; codecs=\"opus, vorbis\"'"));
+ EXPECT_EQ(OpusProbably, CanPlay("'audio/webm; codecs=\"opus\"'"));
+ EXPECT_EQ(OpusProbably, CanPlay("'audio/webm; codecs=\"opus, vorbis\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/webm; codecs=\"vp8\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/webm; codecs=\"vp8.0\"'"));
@@ -315,8 +371,8 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_ogg) {
EXPECT_EQ(kMaybe, CanPlay("'audio/ogg'"));
EXPECT_EQ(kProbably, CanPlay("'audio/ogg; codecs=\"vorbis\"'"));
- EXPECT_EQ(kOpusProbably, CanPlay("'audio/ogg; codecs=\"opus\"'"));
- EXPECT_EQ(kOpusProbably, CanPlay("'audio/ogg; codecs=\"vorbis, opus\"'"));
+ EXPECT_EQ(kOggOpusProbably, CanPlay("'audio/ogg; codecs=\"opus\"'"));
+ EXPECT_EQ(kOggOpusProbably, CanPlay("'audio/ogg; codecs=\"vorbis, opus\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/ogg; codecs=\"theora\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/ogg; codecs=\"theora, opus\"'"));
@@ -327,15 +383,15 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_ogg) {
EXPECT_EQ(kMaybe, CanPlay("'application/ogg'"));
EXPECT_EQ(kProbably, CanPlay("'application/ogg; codecs=\"vorbis\"'"));
EXPECT_EQ(kTheoraProbably, CanPlay("'application/ogg; codecs=\"theora\"'"));
- EXPECT_EQ(kOpusProbably, CanPlay("'application/ogg; codecs=\"opus\"'"));
+ EXPECT_EQ(kOggOpusProbably, CanPlay("'application/ogg; codecs=\"opus\"'"));
EXPECT_EQ(kTheoraProbably,
CanPlay("'application/ogg; codecs=\"theora, vorbis\"'"));
EXPECT_EQ(kTheoraProbably,
CanPlay("'application/ogg; codecs=\"theora, opus\"'"));
- EXPECT_EQ(kOpusProbably,
+ EXPECT_EQ(kOggOpusProbably,
CanPlay("'application/ogg; codecs=\"opus, vorbis\"'"));
- TestOGGUnacceptableCombinations("application/ogg");
+ TestOGGUnacceptableCombinations("application/ogg");
}
IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_mp3) {
@@ -356,8 +412,8 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_mp3) {
EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"avc1.4D401E\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"avc3.64001F\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"mp4a\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"mp4a.40.2\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"mp4a.40.02\"'"));
TestMPEGUnacceptableCombinations("audio/mpeg");
@@ -370,8 +426,8 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_mp3) {
EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"avc1.4D401E\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"avc3.64001F\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"mp4a\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"mp4a.40.2\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"mp4a.40.02\"'"));
TestMPEGUnacceptableCombinations("audio/mp3");
@@ -384,8 +440,8 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_mp3) {
EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"avc1.4D401E\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"avc3.64001F\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"mp4a\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"mp4a.40.2\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"mp4a.40.02\"'"));
TestMPEGUnacceptableCombinations("audio/x-mp3");
}
@@ -411,13 +467,22 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_mp4) {
EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42F01E\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"mp4a.40.2\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"mp4a.40.02\"'"));
EXPECT_EQ(kPropProbably,
CanPlay("'video/mp4; codecs=\"avc1.42E01E, mp4a.40.2\"'"));
EXPECT_EQ(kPropProbably,
+ CanPlay("'video/mp4; codecs=\"avc1.42E01E, mp4a.40.02\"'"));
+ EXPECT_EQ(kPropProbably,
CanPlay("'video/mp4; codecs=\"avc3.42E01E, mp4a.40.5\"'"));
+ EXPECT_EQ(kPropProbably,
+ CanPlay("'video/mp4; codecs=\"avc3.42E01E, mp4a.40.05\"'"));
+ EXPECT_EQ(kPropProbably,
+ CanPlay("'video/mp4; codecs=\"avc3.42E01E, mp4a.40.29\"'"));
EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1, mp4a.40.2\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1, mp4a.40.02\"'"));
EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3, mp4a.40.2\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3, mp4a.40.02\"'"));
EXPECT_EQ(kPropMaybe,
CanPlay("'video/mp4; codecs=\"avc1.42E01E, mp4a.40\"'"));
EXPECT_EQ(kPropMaybe,
@@ -445,13 +510,22 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_mp4) {
EXPECT_EQ(kPropProbably, CanPlay("'video/x-m4v; codecs=\"avc1.42F01E\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'video/x-m4v; codecs=\"mp4a.40.2\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/x-m4v; codecs=\"mp4a.40.02\"'"));
EXPECT_EQ(kPropProbably,
CanPlay("'video/x-m4v; codecs=\"avc1.42E01E, mp4a.40.2\"'"));
EXPECT_EQ(kPropProbably,
+ CanPlay("'video/x-m4v; codecs=\"avc1.42E01E, mp4a.40.02\"'"));
+ EXPECT_EQ(kPropProbably,
CanPlay("'video/x-m4v; codecs=\"avc3.42E01E, mp4a.40.5\"'"));
+ EXPECT_EQ(kPropProbably,
+ CanPlay("'video/x-m4v; codecs=\"avc3.42E01E, mp4a.40.05\"'"));
+ EXPECT_EQ(kPropProbably,
+ CanPlay("'video/x-m4v; codecs=\"avc3.42E01E, mp4a.40.29\"'"));
EXPECT_EQ(kPropMaybe, CanPlay("'video/x-m4v; codecs=\"avc1, mp4a.40.2\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/x-m4v; codecs=\"avc1, mp4a.40.02\"'"));
EXPECT_EQ(kPropMaybe, CanPlay("'video/x-m4v; codecs=\"avc3, mp4a.40.2\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/x-m4v; codecs=\"avc3, mp4a.40.02\"'"));
EXPECT_EQ(kPropMaybe,
CanPlay("'video/x-m4v; codecs=\"avc1.42E01E, mp4a.40\"'"));
EXPECT_EQ(kPropMaybe,
@@ -462,6 +536,10 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_mp4) {
EXPECT_EQ(kPropMaybe, CanPlay("'audio/mp4'"));
EXPECT_EQ(kPropMaybe, CanPlay("'audio/mp4; codecs=\"mp4a.40\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.40.2\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.40.02\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.40.5\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.40.05\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.40.29\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"avc1\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"avc3\"'"));
@@ -476,6 +554,10 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_mp4) {
EXPECT_EQ(kPropMaybe, CanPlay("'audio/x-m4a'"));
EXPECT_EQ(kPropMaybe, CanPlay("'audio/x-m4a; codecs=\"mp4a.40\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'audio/x-m4a; codecs=\"mp4a.40.2\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'audio/x-m4a; codecs=\"mp4a.40.02\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'audio/x-m4a; codecs=\"mp4a.40.5\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'audio/x-m4a; codecs=\"mp4a.40.05\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'audio/x-m4a; codecs=\"mp4a.40.29\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/x-m4a; codecs=\"avc1\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/x-m4a; codecs=\"avc3\"'"));
@@ -488,6 +570,346 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_mp4) {
TestMPEGUnacceptableCombinations("audio/x-m4a");
}
+// When modifying this test, also change CodecSupportTest_Avc3Variants.
+IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_Avc1Variants) {
+ // avc1 without extensions results in "maybe" for compatibility.
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1\"'"));
+
+ // Any 6-digit hexadecimal number will result in at least "maybe".
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.123456\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.ABCDEF\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.abcdef\"'"));
+ EXPECT_EQ(kNot, CanPlay("'video/mp4; codecs=\"avc1.12345\"'"));
+ EXPECT_EQ(kNot, CanPlay("'video/mp4; codecs=\"avc1.1234567\"'"));
+
+ // Both upper and lower case hexadecimal digits are accepted.
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42E01E\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42e01e\"'"));
+
+ // From a YouTube DASH MSE test manifest.
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.4d401f\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.4d401e\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.4d4015\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.640028\"'"));
+
+ //
+ // Baseline Profile (66 == 0x42).
+ // The first four digits must be 42E0, but Chrome also allows 42[8-F]0.
+ // (See http://crbug.com/408552#c17.)
+ // The last two digits must be any valid level.
+ //
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42E00A\"'"));
+
+ // The third digit must be 8-F.
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42001E\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42101E\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42201E\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42301E\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42401E\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42501E\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42601E\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42701E\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42801E\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42901E\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42A01E\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42B01E\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42C01E\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42D01E\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42E01E\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42F01E\"'"));
+
+ // The fourth digit must be 0.
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42E11E\"'"));
+
+ //
+ // Main Profile (77 == 0x4D).
+ // The first four digits must be 4D40.
+ // The last two digits must be any valid level.
+ //
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.4D400A\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.4D401E\"'"));
+
+ // Other values are not allowed for the third and fourth digits.
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.4D301E\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.4D501E\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.4D411E\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.4D4F1E\"'"));
+
+ //
+ // High Profile (100 == 0x64).
+ // The first four digits must be 6400.
+ // The last two digits must be any valid level.
+ //
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.64000A\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.64001E\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.64001F\"'"));
+
+ // Other values are not allowed for the third and fourth digits.
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.64101E\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.64f01E\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.64011E\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.640F1E\"'"));
+
+ //
+ // Other profiles are not known to be supported.
+ //
+
+ // Extended Profile (88 == 0x58).
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.58A01E\"'"));
+}
+
+// When modifying this test, also change CodecSupportTest_Avc1Variants.
+IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_Avc3Variants) {
+ // avc3 without extensions results in "maybe" for compatibility.
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3\"'"));
+
+ // Any 6-digit hexadecimal number will result in at least "maybe".
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3.123456\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3.ABCDEF\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3.abcdef\"'"));
+ EXPECT_EQ(kNot, CanPlay("'video/mp4; codecs=\"avc3.12345\"'"));
+ EXPECT_EQ(kNot, CanPlay("'video/mp4; codecs=\"avc3.1234567\"'"));
+
+ // Both upper and lower case hexadecimal digits are accepted.
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.42E01E\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.42e01e\"'"));
+
+ // From a YouTube DASH MSE test manifest.
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.4d401f\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.4d401e\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.4d4015\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.640028\"'"));
+
+ //
+ // Baseline Profile (66 == 0x42).
+ // The first four digits must be 42E0, but Chrome also allows 42[8-F]0.
+ // (See http://crbug.com/408552#c17.)
+ // The last two digits must be any valid level.
+ //
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.42E00A\"'"));
+
+ // The third digit must be 8-F.
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3.42001E\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3.42101E\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3.42201E\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3.42301E\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3.42401E\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3.42501E\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3.42601E\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3.42701E\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.42801E\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.42901E\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.42A01E\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.42B01E\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.42C01E\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.42D01E\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.42E01E\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.42F01E\"'"));
+
+ // The fourth digit must be 0.
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3.42E11E\"'"));
+
+ //
+ // Main Profile (77 == 0x4D).
+ // The first four digits must be 4D40.
+ // The last two digits must be any valid level.
+ //
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.4D400A\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.4D401E\"'"));
+
+ // Other values are not allowed for the third and fourth digits.
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3.4D301E\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3.4D501E\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3.4D411E\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3.4D4F1E\"'"));
+
+ //
+ // High Profile (100 == 0x64).
+ // The first four digits must be 6400.
+ // The last two digits must be any valid level.
+ //
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.64000A\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.64001E\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.64001F\"'"));
+
+ // Other values are not allowed for the third and fourth digits.
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3.64101E\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3.64f01E\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3.64011E\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3.640F1E\"'"));
+
+ //
+ // Other profiles are not known to be supported.
+ //
+
+ // Extended Profile (88 == 0x58).
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3.58A01E\"'"));
+}
+
+// Tests AVC levels using AVC1 Baseline (0x42E0zz).
+// Other supported values for the first four hexadecimal digits should behave
+// the same way but are not tested.
+// For each full level, the following are tested:
+// * The hexadecimal value before it is not supported.
+// * The hexadecimal value for the main level and all sub-levels are supported.
+// * The hexadecimal value after the last sub-level it is not supported.
+// * Decimal representations of the levels are not supported.
+
+IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_AvcLevels) {
+ // Level 0 is not supported.
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42E000\"'"));
+
+ // Levels 1 (0x0A), 1.1 (0x0B), 1.2 (0x0C), 1.3 (0x0D).
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42E009\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42E00A\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42E00B\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42E00C\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42E00D\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42E00E\"'"));
+ // Verify that decimal representations of levels are not supported.
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42E001\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42E010\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42E011\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42E012\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42E013\"'"));
+
+ // Levels 2 (0x14), 2.1 (0x15), 2.2 (0x16)
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42E013\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42E014\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42E015\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42E016\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42E017\"'"));
+ // Verify that decimal representations of levels are not supported.
+ // However, 20 is level 3.2.
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42E002\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42E020\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42E021\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42E022\"'"));
+
+ // Levels 3 (0x1e), 3.1 (0x1F), 3.2 (0x20)
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42E01D\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42E01E\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42E01F\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42E020\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42E021\"'"));
+ // Verify that decimal representations of levels are not supported.
+ // However, 32 is level 5.
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42E003\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42E030\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42E031\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42E032\"'"));
+
+ // Levels 4 (0x28), 4.1 (0x29), 4.2 (0x2A)
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42E027\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42E028\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42E029\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42E02A\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42E02B\"'"));
+ // Verify that decimal representations of levels are not supported.
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42E004\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42E040\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42E041\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42E042\"'"));
+
+ // Levels 5 (0x32), 5.1 (0x33).
+ // Note: Level 5.2 (0x34) is not considered valid (crbug.com/460376).
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42E031\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42E032\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42E033\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42E034\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42E035\"'"));
+ // Verify that decimal representations of levels are not supported.
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42E005\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42E050\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42E051\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42E052\"'"));
+}
+
+// All values that return positive results are tested. There are also
+// negative tests for values around or that could potentially be confused with
+// (e.g. case, truncation, hex <-> deciemal conversion) those values that return
+// positive results.
+IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_Mp4aVariants) {
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.\"'"));
+
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.6\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.60\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.61\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.62\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.63\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.65\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.65\"'"));
+ // MPEG2 AAC Main, LC, and SSR are supported except on Android.
+ EXPECT_EQ(kMpeg2AacProbably, CanPlay("'audio/mp4; codecs=\"mp4a.66\"'"));
+ EXPECT_EQ(kMpeg2AacProbably, CanPlay("'audio/mp4; codecs=\"mp4a.67\"'"));
+ EXPECT_EQ(kMpeg2AacProbably, CanPlay("'audio/mp4; codecs=\"mp4a.68\"'"));
+ // MP3.
+ EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.69\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.6A\"'"));
+ // MP3.
+ EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.6B\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.6b\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.6C\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.6D\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.6E\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.6F\"'"));
+
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.76\"'"));
+
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.4\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.39\"'"));
+
+ // mp4a.40 without further extension is ambiguous and results in "maybe".
+ EXPECT_EQ(kPropMaybe, CanPlay("'audio/mp4; codecs=\"mp4a.40\"'"));
+
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.40.\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.40.0\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.40.1\"'"));
+ // MPEG4 AAC LC.
+ EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.40.2\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.40.3\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.40.4\"'"));
+ // MPEG4 AAC SBR v1.
+ EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.40.5\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.40.6\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.40.7\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.40.8\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.40.9\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.40.10\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.40.20\"'"));
+ // MPEG4 AAC SBR PS v2.
+ EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.40.29\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.40.30\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.40.40\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.40.50\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.40.290\"'"));
+ // Check conversions of decimal 29 to hex and hex 29 to decimal.
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.40.1d\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.40.1D\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.40.41\"'"));
+
+ // Allow leading zeros in aud-oti for specific MPEG4 AAC strings.
+ // See http://crbug.com/440607.
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.40.00\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.40.01\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.40.02\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.40.03\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.40.04\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.40.05\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.40.029\"'"));
+
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.41\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.41.2\"'"));
+
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.4.2\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.400.2\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.040.2\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.4.5\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.400.5\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.040.5\"'"));
+}
+
IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_HLS) {
// HLS are supported only on Android IceCreamSandwich and above (API level 14)
std::string probablyCanPlayHLS = kNot;
@@ -532,15 +954,27 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_HLS) {
EXPECT_EQ(probablyCanPlayHLS,
CanPlay("'application/x-mpegurl; codecs=\"mp4a.40.2\"'"));
EXPECT_EQ(probablyCanPlayHLS,
+ CanPlay("'application/x-mpegurl; codecs=\"mp4a.40.02\"'"));
+ EXPECT_EQ(probablyCanPlayHLS,
CanPlay("'application/x-mpegurl; codecs=\"avc1.42E01E, mp4a.40.2\"'"));
EXPECT_EQ(probablyCanPlayHLS,
+ CanPlay("'application/x-mpegurl; codecs=\"avc1.42E01E, mp4a.40.02\"'"));
+ EXPECT_EQ(probablyCanPlayHLS,
CanPlay("'application/x-mpegurl; codecs=\"avc3.42E01E, mp4a.40.5\"'"));
+ EXPECT_EQ(probablyCanPlayHLS,
+ CanPlay("'application/x-mpegurl; codecs=\"avc3.42E01E, mp4a.40.05\"'"));
+ EXPECT_EQ(probablyCanPlayHLS,
+ CanPlay("'application/x-mpegurl; codecs=\"avc3.42E01E, mp4a.40.29\"'"));
EXPECT_EQ(maybeCanPlayHLS,
CanPlay("'application/x-mpegurl; codecs=\"avc1, mp4a.40.2\"'"));
EXPECT_EQ(maybeCanPlayHLS,
+ CanPlay("'application/x-mpegurl; codecs=\"avc1, mp4a.40.02\"'"));
+ EXPECT_EQ(maybeCanPlayHLS,
CanPlay("'application/x-mpegurl; codecs=\"avc3, mp4a.40.2\"'"));
EXPECT_EQ(maybeCanPlayHLS,
+ CanPlay("'application/x-mpegurl; codecs=\"avc3, mp4a.40.02\"'"));
+ EXPECT_EQ(maybeCanPlayHLS,
CanPlay("'application/x-mpegurl; codecs=\"avc1.42E01E, mp4a.40\"'"));
EXPECT_EQ(maybeCanPlayHLS,
CanPlay("'application/x-mpegurl; codecs=\"avc3.42E01E, mp4a.40\"'"));
@@ -580,12 +1014,24 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_HLS) {
EXPECT_EQ(probablyCanPlayHLS,
CanPlay("'application/vnd.apple.mpegurl; codecs=\"mp4a.40.2\"'"));
+ EXPECT_EQ(probablyCanPlayHLS,
+ CanPlay("'application/vnd.apple.mpegurl; codecs=\"mp4a.40.02\"'"));
+ EXPECT_EQ(probablyCanPlayHLS,
+ CanPlay("'application/vnd.apple.mpegurl; codecs=\"mp4a.40.5\"'"));
+ EXPECT_EQ(probablyCanPlayHLS,
+ CanPlay("'application/vnd.apple.mpegurl; codecs=\"mp4a.40.05\"'"));
+ EXPECT_EQ(probablyCanPlayHLS,
+ CanPlay("'application/vnd.apple.mpegurl; codecs=\"mp4a.40.29\"'"));
EXPECT_EQ(maybeCanPlayHLS,
CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc1, mp4a.40.2\"'"));
EXPECT_EQ(maybeCanPlayHLS,
+ CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc1, mp4a.40.02\"'"));
+ EXPECT_EQ(maybeCanPlayHLS,
CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc3, mp4a.40.2\"'"));
EXPECT_EQ(maybeCanPlayHLS,
+ CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc3, mp4a.40.02\"'"));
+ EXPECT_EQ(maybeCanPlayHLS,
CanPlay("'application/vnd.apple.mpegurl; "
"codecs=\"avc1.42E01E, mp4a.40\"'"));
EXPECT_EQ(maybeCanPlayHLS,
diff --git a/chromium/content/browser/media/media_internals.cc b/chromium/content/browser/media/media_internals.cc
index 4d600851783..f0b071a4e12 100644
--- a/chromium/content/browser/media/media_internals.cc
+++ b/chromium/content/browser/media/media_internals.cc
@@ -4,14 +4,23 @@
#include "content/browser/media/media_internals.h"
+#include "base/metrics/histogram.h"
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.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_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/web_contents.h"
#include "content/public/browser/web_ui.h"
#include "media/audio/audio_parameters.h"
-#include "media/base/media_log.h"
#include "media/base/media_log_event.h"
+#include "media/filters/decrypting_video_decoder.h"
+#include "media/filters/gpu_video_decoder.h"
namespace {
@@ -35,6 +44,7 @@ std::string EffectsToString(int effects) {
{ media::AudioParameters::ECHO_CANCELLER, "ECHO_CANCELLER" },
{ media::AudioParameters::DUCKING, "DUCKING" },
{ media::AudioParameters::KEYBOARD_MIC, "KEYBOARD_MIC" },
+ { media::AudioParameters::HOTWORD, "HOTWORD" },
};
std::string ret;
@@ -56,6 +66,22 @@ std::string EffectsToString(int effects) {
return ret;
}
+std::string FormatToString(media::AudioParameters::Format format) {
+ switch (format) {
+ case media::AudioParameters::AUDIO_PCM_LINEAR:
+ return "pcm_linear";
+ case media::AudioParameters::AUDIO_PCM_LOW_LATENCY:
+ return "pcm_low_latency";
+ case media::AudioParameters::AUDIO_FAKE:
+ return "fake";
+ case media::AudioParameters::AUDIO_LAST_FORMAT:
+ break;
+ }
+
+ NOTREACHED();
+ return "unknown";
+}
+
const char kAudioLogStatusKey[] = "status";
const char kAudioLogUpdateFunction[] = "media.updateAudioComponent";
@@ -79,6 +105,11 @@ class AudioLogImpl : public media::AudioLog {
void OnError(int component_id) override;
void OnSetVolume(int component_id, double volume) override;
+ // Called by MediaInternals to update the WebContents title for a stream.
+ void SendWebContentsTitle(int component_id,
+ int render_process_id,
+ int render_frame_id);
+
private:
void SendSingleStringUpdate(int component_id,
const std::string& key,
@@ -86,6 +117,11 @@ class AudioLogImpl : public media::AudioLog {
void StoreComponentMetadata(int component_id, base::DictionaryValue* dict);
std::string FormatCacheKey(int component_id);
+ static void SendWebContentsTitleHelper(const std::string& cache_key,
+ scoped_ptr<base::DictionaryValue> dict,
+ int render_process_id,
+ int render_frame_id);
+
const int owner_id_;
const media::AudioLogFactory::AudioComponent component_;
content::MediaInternals* const media_internals_;
@@ -110,6 +146,7 @@ void AudioLogImpl::OnCreated(int component_id,
dict.SetString(kAudioLogStatusKey, "created");
dict.SetString("device_id", device_id);
+ dict.SetString("device_type", FormatToString(params.format()));
dict.SetInteger("frames_per_buffer", params.frames_per_buffer());
dict.SetInteger("sample_rate", params.sample_rate());
dict.SetInteger("channels", params.channels());
@@ -117,8 +154,9 @@ void AudioLogImpl::OnCreated(int component_id,
ChannelLayoutToString(params.channel_layout()));
dict.SetString("effects", EffectsToString(params.effects()));
- media_internals_->SendUpdateAndCacheAudioStreamKey(
- FormatCacheKey(component_id), kAudioLogUpdateFunction, &dict);
+ media_internals_->SendAudioLogUpdate(MediaInternals::CREATE,
+ FormatCacheKey(component_id),
+ kAudioLogUpdateFunction, &dict);
}
void AudioLogImpl::OnStarted(int component_id) {
@@ -133,8 +171,9 @@ void AudioLogImpl::OnClosed(int component_id) {
base::DictionaryValue dict;
StoreComponentMetadata(component_id, &dict);
dict.SetString(kAudioLogStatusKey, "closed");
- media_internals_->SendUpdateAndPurgeAudioStreamCache(
- FormatCacheKey(component_id), kAudioLogUpdateFunction, &dict);
+ media_internals_->SendAudioLogUpdate(MediaInternals::UPDATE_AND_DELETE,
+ FormatCacheKey(component_id),
+ kAudioLogUpdateFunction, &dict);
}
void AudioLogImpl::OnError(int component_id) {
@@ -145,22 +184,62 @@ void AudioLogImpl::OnSetVolume(int component_id, double volume) {
base::DictionaryValue dict;
StoreComponentMetadata(component_id, &dict);
dict.SetDouble("volume", volume);
- media_internals_->SendUpdateAndCacheAudioStreamKey(
- FormatCacheKey(component_id), kAudioLogUpdateFunction, &dict);
+ media_internals_->SendAudioLogUpdate(MediaInternals::UPDATE_IF_EXISTS,
+ FormatCacheKey(component_id),
+ kAudioLogUpdateFunction, &dict);
+}
+
+void AudioLogImpl::SendWebContentsTitle(int component_id,
+ int render_process_id,
+ int render_frame_id) {
+ scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
+ StoreComponentMetadata(component_id, dict.get());
+ SendWebContentsTitleHelper(FormatCacheKey(component_id), dict.Pass(),
+ render_process_id, render_frame_id);
}
std::string AudioLogImpl::FormatCacheKey(int component_id) {
return base::StringPrintf("%d:%d:%d", owner_id_, component_, component_id);
}
+// static
+void AudioLogImpl::SendWebContentsTitleHelper(
+ const std::string& cache_key,
+ scoped_ptr<base::DictionaryValue> dict,
+ int render_process_id,
+ int render_frame_id) {
+ // Page title information can only be retrieved from the UI thread.
+ if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&SendWebContentsTitleHelper, cache_key, base::Passed(&dict),
+ render_process_id, render_frame_id));
+ return;
+ }
+
+ const WebContents* web_contents = WebContents::FromRenderFrameHost(
+ RenderFrameHost::FromID(render_process_id, render_frame_id));
+ if (!web_contents)
+ return;
+
+ // Note: by this point the given audio log entry could have been destroyed, so
+ // we use UPDATE_IF_EXISTS to discard such instances.
+ dict->SetInteger("render_process_id", render_process_id);
+ dict->SetString("web_contents_title", web_contents->GetTitle());
+ MediaInternals::GetInstance()->SendAudioLogUpdate(
+ MediaInternals::UPDATE_IF_EXISTS, cache_key, kAudioLogUpdateFunction,
+ dict.get());
+}
+
void AudioLogImpl::SendSingleStringUpdate(int component_id,
const std::string& key,
const std::string& value) {
base::DictionaryValue dict;
StoreComponentMetadata(component_id, &dict);
dict.SetString(key, value);
- media_internals_->SendUpdateAndCacheAudioStreamKey(
- FormatCacheKey(component_id), kAudioLogUpdateFunction, &dict);
+ media_internals_->SendAudioLogUpdate(MediaInternals::UPDATE_IF_EXISTS,
+ FormatCacheKey(component_id),
+ kAudioLogUpdateFunction, &dict);
}
void AudioLogImpl::StoreComponentMetadata(int component_id,
@@ -170,19 +249,224 @@ void AudioLogImpl::StoreComponentMetadata(int component_id,
dict->SetInteger("component_type", component_);
}
+class MediaInternals::MediaInternalsUMAHandler : public NotificationObserver {
+ public:
+ MediaInternalsUMAHandler();
+
+ // NotificationObserver implementation.
+ void Observe(int type,
+ const NotificationSource& source,
+ const NotificationDetails& details) override;
+
+ // Reports the pipeline status to UMA for every player
+ // associated with the renderer process and then deletes the player state.
+ void LogAndClearPlayersInRenderer(int render_process_id);
+
+ // Helper function to save the event payload to RendererPlayerMap.
+ void SavePlayerState(const media::MediaLogEvent& event,
+ int render_process_id);
+
+ private:
+ struct PipelineInfo {
+ media::PipelineStatus last_pipeline_status;
+ bool has_audio;
+ bool has_video;
+ bool video_dds;
+ bool video_decoder_changed;
+ std::string audio_codec_name;
+ std::string video_codec_name;
+ std::string video_decoder;
+ PipelineInfo()
+ : last_pipeline_status(media::PIPELINE_OK),
+ has_audio(false),
+ has_video(false),
+ video_dds(false),
+ video_decoder_changed(false) {}
+ };
+
+ // Helper function to report PipelineStatus associated with a player to UMA.
+ void ReportUMAForPipelineStatus(const PipelineInfo& player_info);
+
+ // Helper to generate PipelineStatus UMA name for AudioVideo streams.
+ std::string GetUMANameForAVStream(const PipelineInfo& player_info);
+
+ // Key is playerid
+ typedef std::map<int, PipelineInfo> PlayerInfoMap;
+
+ // Key is renderer id
+ typedef std::map<int, PlayerInfoMap> RendererPlayerMap;
+
+ // Stores player information per renderer
+ RendererPlayerMap renderer_info_;
+
+ NotificationRegistrar registrar_;
+
+ DISALLOW_COPY_AND_ASSIGN(MediaInternalsUMAHandler);
+};
+
+MediaInternals::MediaInternalsUMAHandler::MediaInternalsUMAHandler() {
+ registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_TERMINATED,
+ NotificationService::AllBrowserContextsAndSources());
+}
+
+void MediaInternals::MediaInternalsUMAHandler::Observe(
+ int type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DCHECK_EQ(type, NOTIFICATION_RENDERER_PROCESS_TERMINATED);
+ RenderProcessHost* process = Source<RenderProcessHost>(source).ptr();
+
+ // Post the task to the IO thread to avoid race in updating renderer_info_ map
+ // by both SavePlayerState & LogAndClearPlayersInRenderer from different
+ // threads.
+ // Using base::Unretained() on MediaInternalsUMAHandler is safe since
+ // it is owned by MediaInternals and share the same lifetime
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&MediaInternalsUMAHandler::LogAndClearPlayersInRenderer,
+ base::Unretained(this), process->GetID()));
+}
+
+void MediaInternals::MediaInternalsUMAHandler::SavePlayerState(
+ const media::MediaLogEvent& event,
+ int render_process_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ PlayerInfoMap& player_info = renderer_info_[render_process_id];
+ switch (event.type) {
+ case media::MediaLogEvent::PIPELINE_ERROR: {
+ int status;
+ event.params.GetInteger("pipeline_error", &status);
+ player_info[event.id].last_pipeline_status =
+ static_cast<media::PipelineStatus>(status);
+ break;
+ }
+ case media::MediaLogEvent::PROPERTY_CHANGE:
+ if (event.params.HasKey("found_audio_stream")) {
+ event.params.GetBoolean("found_audio_stream",
+ &player_info[event.id].has_audio);
+ }
+ if (event.params.HasKey("found_video_stream")) {
+ event.params.GetBoolean("found_video_stream",
+ &player_info[event.id].has_video);
+ }
+ if (event.params.HasKey("audio_codec_name")) {
+ event.params.GetString("audio_codec_name",
+ &player_info[event.id].audio_codec_name);
+ }
+ if (event.params.HasKey("video_codec_name")) {
+ event.params.GetString("video_codec_name",
+ &player_info[event.id].video_codec_name);
+ }
+ if (event.params.HasKey("video_decoder")) {
+ std::string previous_video_decoder(player_info[event.id].video_decoder);
+ event.params.GetString("video_decoder",
+ &player_info[event.id].video_decoder);
+ if (!previous_video_decoder.empty() &&
+ previous_video_decoder != player_info[event.id].video_decoder) {
+ player_info[event.id].video_decoder_changed = true;
+ }
+ }
+ if (event.params.HasKey("video_dds")) {
+ event.params.GetBoolean("video_dds", &player_info[event.id].video_dds);
+ }
+ break;
+ default:
+ break;
+ }
+ return;
+}
+
+std::string MediaInternals::MediaInternalsUMAHandler::GetUMANameForAVStream(
+ const PipelineInfo& player_info) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ static const char kPipelineUmaPrefix[] = "Media.PipelineStatus.AudioVideo.";
+ std::string uma_name = kPipelineUmaPrefix;
+ if (player_info.video_codec_name == "vp8") {
+ uma_name += "VP8.";
+ } else if (player_info.video_codec_name == "vp9") {
+ uma_name += "VP9.";
+ } else if (player_info.video_codec_name == "h264") {
+ uma_name += "H264.";
+ } else {
+ return uma_name + "Other";
+ }
+
+ if (player_info.video_decoder ==
+ media::DecryptingVideoDecoder::kDecoderName) {
+ return uma_name + "DVD";
+ }
+
+ if (player_info.video_dds) {
+ uma_name += "DDS.";
+ }
+
+ if (player_info.video_decoder == media::GpuVideoDecoder::kDecoderName) {
+ uma_name += "HW";
+ } else {
+ uma_name += "SW";
+ }
+ return uma_name;
+}
+
+void MediaInternals::MediaInternalsUMAHandler::ReportUMAForPipelineStatus(
+ const PipelineInfo& player_info) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (player_info.has_video && player_info.has_audio) {
+ base::LinearHistogram::FactoryGet(
+ GetUMANameForAVStream(player_info), 1, media::PIPELINE_STATUS_MAX,
+ media::PIPELINE_STATUS_MAX + 1,
+ base::HistogramBase::kUmaTargetedHistogramFlag)
+ ->Add(player_info.last_pipeline_status);
+ } else if (player_info.has_audio) {
+ UMA_HISTOGRAM_ENUMERATION("Media.PipelineStatus.AudioOnly",
+ player_info.last_pipeline_status,
+ media::PIPELINE_STATUS_MAX + 1);
+ } else if (player_info.has_video) {
+ UMA_HISTOGRAM_ENUMERATION("Media.PipelineStatus.VideoOnly",
+ player_info.last_pipeline_status,
+ media::PIPELINE_STATUS_MAX + 1);
+ } else {
+ UMA_HISTOGRAM_ENUMERATION("Media.PipelineStatus.Unsupported",
+ player_info.last_pipeline_status,
+ media::PIPELINE_STATUS_MAX + 1);
+ }
+ // Report whether video decoder fallback happened, but only if a video decoder
+ // was reported.
+ if (!player_info.video_decoder.empty()) {
+ UMA_HISTOGRAM_BOOLEAN("Media.VideoDecoderFallback",
+ player_info.video_decoder_changed);
+ }
+}
+
+void MediaInternals::MediaInternalsUMAHandler::LogAndClearPlayersInRenderer(
+ int render_process_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ auto players_it = renderer_info_.find(render_process_id);
+ if (players_it == renderer_info_.end())
+ return;
+ auto it = players_it->second.begin();
+ while (it != players_it->second.end()) {
+ ReportUMAForPipelineStatus(it->second);
+ players_it->second.erase(it++);
+ }
+}
+
MediaInternals* MediaInternals::GetInstance() {
return g_media_internals.Pointer();
}
-MediaInternals::MediaInternals() : owner_ids_() {}
+MediaInternals::MediaInternals()
+ : owner_ids_(), uma_handler_(new MediaInternalsUMAHandler()) {
+}
+
MediaInternals::~MediaInternals() {}
void MediaInternals::OnMediaEvents(
int render_process_id, const std::vector<media::MediaLogEvent>& events) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
// Notify observers that |event| has occurred.
- for (std::vector<media::MediaLogEvent>::const_iterator event = events.begin();
- event != events.end(); ++event) {
+ for (auto event = events.begin(); event != events.end(); ++event) {
base::DictionaryValue dict;
dict.SetInteger("renderer", render_process_id);
dict.SetInteger("player", event->id);
@@ -193,18 +477,34 @@ void MediaInternals::OnMediaEvents(
const double ticks = event->time.ToInternalValue();
const double ticks_millis = ticks / base::Time::kMicrosecondsPerMillisecond;
dict.SetDouble("ticksMillis", ticks_millis);
- dict.Set("params", event->params.DeepCopy());
+
+ // Convert PipelineStatus to human readable string
+ if (event->type == media::MediaLogEvent::PIPELINE_ERROR) {
+ int status;
+ if (!event->params.GetInteger("pipeline_error", &status) ||
+ status < static_cast<int>(media::PIPELINE_OK) ||
+ status > static_cast<int>(media::PIPELINE_STATUS_MAX)) {
+ continue;
+ }
+ media::PipelineStatus error = static_cast<media::PipelineStatus>(status);
+ dict.SetString("params.pipeline_error",
+ media::MediaLog::PipelineStatusToString(error));
+ } else {
+ dict.Set("params", event->params.DeepCopy());
+ }
+
SendUpdate(SerializeUpdate("media.onMediaEvent", &dict));
+ uma_handler_->SavePlayerState(*event, render_process_id);
}
}
void MediaInternals::AddUpdateCallback(const UpdateCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
update_callbacks_.push_back(callback);
}
void MediaInternals::RemoveUpdateCallback(const UpdateCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
for (size_t i = 0; i < update_callbacks_.size(); ++i) {
if (update_callbacks_[i].Equals(callback)) {
update_callbacks_.erase(update_callbacks_.begin() + i);
@@ -225,14 +525,14 @@ void MediaInternals::SendAudioStreamData() {
}
void MediaInternals::SendVideoCaptureDeviceCapabilities() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(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));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
video_capture_capabilities_cached_data_.Clear();
for (const auto& video_capture_device_info : video_capture_device_infos) {
@@ -245,10 +545,10 @@ void MediaInternals::UpdateVideoCaptureDeviceCapabilities(
device_dict->SetString(
"name", video_capture_device_info.name.GetNameAndModel());
device_dict->Set("formats", format_list);
-#if defined(OS_WIN) || defined(OS_MACOSX)
+#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) || \
+ defined(OS_ANDROID)
device_dict->SetString(
- "captureApi",
- video_capture_device_info.name.GetCaptureApiTypeString());
+ "captureApi", video_capture_device_info.name.GetCaptureApiTypeString());
#endif
video_capture_capabilities_cached_data_.Append(device_dict);
}
@@ -264,6 +564,15 @@ scoped_ptr<media::AudioLog> MediaInternals::CreateAudioLog(
owner_ids_[component]++, component, this));
}
+void MediaInternals::SetWebContentsTitleForAudioLogEntry(
+ int component_id,
+ int render_process_id,
+ int render_frame_id,
+ media::AudioLog* audio_log) {
+ static_cast<AudioLogImpl*>(audio_log)
+ ->SendWebContentsTitle(component_id, render_process_id, render_frame_id);
+}
+
void MediaInternals::SendUpdate(const base::string16& update) {
// SendUpdate() may be called from any thread, but must run on the IO thread.
// TODO(dalecurtis): This is pretty silly since the update callbacks simply
@@ -278,32 +587,30 @@ void MediaInternals::SendUpdate(const base::string16& update) {
update_callbacks_[i].Run(update);
}
-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 (!audio_streams_cached_data_.HasKey(cache_key)) {
- audio_streams_cached_data_.Set(cache_key, value->DeepCopy());
- return;
+void MediaInternals::SendAudioLogUpdate(AudioLogUpdateType type,
+ const std::string& cache_key,
+ const std::string& function,
+ const base::DictionaryValue* value) {
+ {
+ base::AutoLock auto_lock(lock_);
+ const bool has_entry = audio_streams_cached_data_.HasKey(cache_key);
+ if ((type == UPDATE_IF_EXISTS || type == UPDATE_AND_DELETE) && !has_entry) {
+ return;
+ } else if (!has_entry) {
+ DCHECK_EQ(type, CREATE);
+ audio_streams_cached_data_.Set(cache_key, value->DeepCopy());
+ } else if (type == UPDATE_AND_DELETE) {
+ scoped_ptr<base::Value> out_value;
+ CHECK(audio_streams_cached_data_.Remove(cache_key, &out_value));
+ } else {
+ base::DictionaryValue* existing_dict = NULL;
+ CHECK(
+ audio_streams_cached_data_.GetDictionary(cache_key, &existing_dict));
+ existing_dict->MergeDictionary(value);
+ }
}
- base::DictionaryValue* existing_dict = NULL;
- CHECK(audio_streams_cached_data_.GetDictionary(cache_key, &existing_dict));
- existing_dict->MergeDictionary(value);
-}
-
-void MediaInternals::SendUpdateAndPurgeAudioStreamCache(
- const std::string& cache_key,
- const std::string& function,
- const base::DictionaryValue* value) {
SendUpdate(SerializeUpdate(function, value));
-
- base::AutoLock auto_lock(lock_);
- scoped_ptr<base::Value> 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 4c1b2ed2ed6..657fea43bd5 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/base/media_log.h"
#include "media/video/capture/video_capture_device_info.h"
namespace media {
@@ -58,7 +59,18 @@ class CONTENT_EXPORT MediaInternals
// AudioLogFactory implementation. Safe to call from any thread.
scoped_ptr<media::AudioLog> CreateAudioLog(AudioComponent component) override;
+ // If possible, i.e. a WebContents exists for the given RenderFrameHostID,
+ // tells an existing AudioLogEntry the WebContents title for easier
+ // differentiation on the UI.
+ void SetWebContentsTitleForAudioLogEntry(int component_id,
+ int render_process_id,
+ int render_frame_id,
+ media::AudioLog* audio_log);
+
private:
+ // Inner class to handle reporting pipelinestatus to UMA
+ class MediaInternalsUMAHandler;
+
friend class AudioLogImpl;
friend class MediaInternalsTest;
friend struct base::DefaultLazyInstanceTraits<MediaInternals>;
@@ -69,16 +81,19 @@ 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 SendAudioStreamData() calls
+ // Caches |value| under |cache_key| so that future SendAudioLogUpdate() 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);
+ // each registered UpdateCallback.
+ enum AudioLogUpdateType {
+ CREATE, // Creates a new AudioLog cache entry.
+ UPDATE_IF_EXISTS, // Updates an existing AudioLog cache entry, does
+ // nothing if it doesn't exist.
+ UPDATE_AND_DELETE, // Deletes an existing AudioLog cache entry.
+ };
+ void SendAudioLogUpdate(AudioLogUpdateType type,
+ 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_;
@@ -88,10 +103,11 @@ class CONTENT_EXPORT MediaInternals
base::Lock lock_;
base::DictionaryValue audio_streams_cached_data_;
int owner_ids_[AUDIO_COMPONENT_MAX];
+ scoped_ptr<MediaInternalsUMAHandler> uma_handler_;
DISALLOW_COPY_AND_ASSIGN(MediaInternals);
};
-} // namespace content
+} // namespace content
#endif // CONTENT_BROWSER_MEDIA_MEDIA_INTERNALS_H_
diff --git a/chromium/content/browser/media/media_internals_handler.cc b/chromium/content/browser/media/media_internals_handler.cc
index 74eb8354a16..aafe26ea259 100644
--- a/chromium/content/browser/media/media_internals_handler.cc
+++ b/chromium/content/browser/media/media_internals_handler.cc
@@ -24,7 +24,7 @@ MediaInternalsMessageHandler::~MediaInternalsMessageHandler() {
}
void MediaInternalsMessageHandler::RegisterMessages() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
proxy_->Attach(this);
web_ui()->RegisterMessageCallback("getEverything",
diff --git a/chromium/content/browser/media/media_internals_proxy.cc b/chromium/content/browser/media/media_internals_proxy.cc
index 4193a834812..05f4dd82a63 100644
--- a/chromium/content/browser/media/media_internals_proxy.cc
+++ b/chromium/content/browser/media/media_internals_proxy.cc
@@ -33,7 +33,7 @@ MediaInternalsProxy::MediaInternalsProxy() {
void MediaInternalsProxy::Observe(int type,
const NotificationSource& source,
const NotificationDetails& details) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK_EQ(type, NOTIFICATION_RENDERER_PROCESS_TERMINATED);
RenderProcessHost* process = Source<RenderProcessHost>(source).ptr();
CallJavaScriptFunctionOnUIThread("media.onRendererTerminated",
@@ -41,7 +41,7 @@ void MediaInternalsProxy::Observe(int type,
}
void MediaInternalsProxy::Attach(MediaInternalsMessageHandler* handler) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
handler_ = handler;
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
@@ -49,7 +49,7 @@ void MediaInternalsProxy::Attach(MediaInternalsMessageHandler* handler) {
}
void MediaInternalsProxy::Detach() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
handler_ = NULL;
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
@@ -58,7 +58,7 @@ void MediaInternalsProxy::Detach() {
}
void MediaInternalsProxy::GetEverything() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
// Ask MediaInternals for all its data.
BrowserThread::PostTask(
@@ -70,7 +70,7 @@ void MediaInternalsProxy::GetEverything() {
}
void MediaInternalsProxy::OnUpdate(const base::string16& update) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&MediaInternalsProxy::UpdateUIOnUIThread, this, update));
@@ -116,40 +116,41 @@ base::Value* MediaInternalsProxy::GetConstants() {
}
void MediaInternalsProxy::ObserveMediaInternalsOnIOThread() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
update_callback_ = base::Bind(&MediaInternalsProxy::OnUpdate,
base::Unretained(this));
MediaInternals::GetInstance()->AddUpdateCallback(update_callback_);
if (GetContentClient()->browser()->GetNetLog()) {
net::NetLog* net_log = GetContentClient()->browser()->GetNetLog();
- net_log->AddThreadSafeObserver(this, net::NetLog::LOG_ALL_BUT_BYTES);
+ net_log->DeprecatedAddObserver(
+ this, net::NetLogCaptureMode::IncludeCookiesAndCredentials());
}
}
void MediaInternalsProxy::StopObservingMediaInternalsOnIOThread() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
MediaInternals::GetInstance()->RemoveUpdateCallback(update_callback_);
if (GetContentClient()->browser()->GetNetLog()) {
net::NetLog* net_log = GetContentClient()->browser()->GetNetLog();
- net_log->RemoveThreadSafeObserver(this);
+ net_log->DeprecatedRemoveObserver(this);
}
}
void MediaInternalsProxy::GetEverythingOnIOThread() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
MediaInternals::GetInstance()->SendAudioStreamData();
MediaInternals::GetInstance()->SendVideoCaptureDeviceCapabilities();
}
void MediaInternalsProxy::UpdateUIOnUIThread(const base::string16& update) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
// Don't forward updates to a destructed UI.
if (handler_)
handler_->OnUpdate(update);
}
void MediaInternalsProxy::AddNetEventOnUIThread(base::Value* entry) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
// Send the updates to the page in kMediaInternalsProxyEventDelayMilliseconds
// if an update is not already pending.
@@ -165,14 +166,14 @@ void MediaInternalsProxy::AddNetEventOnUIThread(base::Value* entry) {
}
void MediaInternalsProxy::SendNetEventsOnUIThread() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
CallJavaScriptFunctionOnUIThread("media.onNetUpdate",
pending_net_updates_.release());
}
void MediaInternalsProxy::CallJavaScriptFunctionOnUIThread(
const std::string& function, base::Value* args) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
scoped_ptr<base::Value> args_value(args);
std::vector<const base::Value*> args_vector;
args_vector.push_back(args_value.get());
diff --git a/chromium/content/browser/media/media_internals_proxy.h b/chromium/content/browser/media/media_internals_proxy.h
index c2672f09d45..af6740c087b 100644
--- a/chromium/content/browser/media/media_internals_proxy.h
+++ b/chromium/content/browser/media/media_internals_proxy.h
@@ -11,7 +11,7 @@
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
-#include "net/base/net_log.h"
+#include "net/log/net_log.h"
namespace base {
class ListValue;
diff --git a/chromium/content/browser/media/media_internals_unittest.cc b/chromium/content/browser/media/media_internals_unittest.cc
index da8e2c51eb3..ad43e3393e6 100644
--- a/chromium/content/browser/media/media_internals_unittest.cc
+++ b/chromium/content/browser/media/media_internals_unittest.cc
@@ -109,22 +109,30 @@ class MediaInternalsVideoCaptureDeviceTest : public testing::Test,
MediaInternals::UpdateCallback update_cb_;
};
-#if defined(OS_WIN) || defined(OS_MACOSX)
+#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) || \
+ defined(OS_ANDROID)
TEST_F(MediaInternalsVideoCaptureDeviceTest,
AllCaptureApiTypesHaveProperStringRepresentation) {
typedef media::VideoCaptureDevice::Name VideoCaptureDeviceName;
typedef std::map<VideoCaptureDeviceName::CaptureApiType, std::string>
CaptureApiTypeStringMap;
CaptureApiTypeStringMap m;
-#if defined(OS_WIN)
+#if defined(OS_LINUX)
+ m[VideoCaptureDeviceName::V4L2_SINGLE_PLANE] = "V4L2 SPLANE";
+ m[VideoCaptureDeviceName::V4L2_MULTI_PLANE] = "V4L2 MPLANE";
+#elif defined(OS_WIN)
m[VideoCaptureDeviceName::MEDIA_FOUNDATION] = "Media Foundation";
m[VideoCaptureDeviceName::DIRECT_SHOW] = "Direct Show";
- 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";
+#elif defined(OS_ANDROID)
+ m[VideoCaptureDeviceName::API1] = "Camera API1";
+ m[VideoCaptureDeviceName::API2_LEGACY] = "Camera API2 Legacy";
+ m[VideoCaptureDeviceName::API2_FULL] = "Camera API2 Full";
+ m[VideoCaptureDeviceName::API2_LIMITED] = "Camera API2 Limited";
+ m[VideoCaptureDeviceName::TANGO] = "Tango API";
#endif
EXPECT_EQ(media::VideoCaptureDevice::Name::API_TYPE_UNKNOWN, m.size());
for (CaptureApiTypeStringMap::iterator it = m.begin(); it != m.end(); ++it) {
@@ -147,7 +155,7 @@ TEST_F(MediaInternalsVideoCaptureDeviceTest,
const media::VideoCaptureFormat capture_format(
kFrameSize, kFrameRate, kPixelFormat);
const std::string expected_string =
- base::StringPrintf("resolution: %s, fps: %f, pixel format: %s",
+ base::StringPrintf("resolution: %s, fps: %.3f, pixel format: %s",
kFrameSize.ToString().c_str(),
kFrameRate,
media::VideoCaptureFormat::PixelFormatToString(
@@ -172,8 +180,13 @@ TEST_F(MediaInternalsVideoCaptureDeviceTest,
#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"),
+#elif defined(OS_LINUX)
+ media::VideoCaptureDevice::Name(
+ "dummy", "/dev/dummy",
+ media::VideoCaptureDevice::Name::V4L2_SINGLE_PLANE),
+#elif defined(OS_ANDROID)
+ media::VideoCaptureDevice::Name("dummy", "dummy",
+ media::VideoCaptureDevice::Name::API2_LEGACY),
#else
media::VideoCaptureDevice::Name("dummy", "dummy"),
#endif
@@ -187,7 +200,7 @@ TEST_F(MediaInternalsVideoCaptureDeviceTest,
// exactly one device_info in the |device_infos|.
media_internals_->UpdateVideoCaptureDeviceCapabilities(device_infos);
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if defined(OS_LINUX)
ExpectString("id", "/dev/dummy");
#else
ExpectString("id", "dummy");
@@ -196,10 +209,14 @@ TEST_F(MediaInternalsVideoCaptureDeviceTest,
base::ListValue expected_list;
expected_list.AppendString(format_hd.ToString());
ExpectListOfStrings("formats", expected_list);
-#if defined(OS_MACOSX)
- ExpectString("captureApi", "QTKit");
+#if defined(OS_LINUX)
+ ExpectString("captureApi", "V4L2 SPLANE");
#elif defined(OS_WIN)
ExpectString("captureApi", "Direct Show");
+#elif defined(OS_MACOSX)
+ ExpectString("captureApi", "QTKit");
+#elif defined(OS_ANDROID)
+ ExpectString("captureApi", "Camera API2 Legacy");
#endif
}
diff --git a/chromium/content/browser/media/media_source_browsertest.cc b/chromium/content/browser/media/media_source_browsertest.cc
index 684b37d6505..191ff66045e 100644
--- a/chromium/content/browser/media/media_source_browsertest.cc
+++ b/chromium/content/browser/media/media_source_browsertest.cc
@@ -49,7 +49,7 @@ class MediaSourceTest : public content::MediaBrowserTest {
}
#if defined(OS_ANDROID)
- virtual void SetUpCommandLine(CommandLine* command_line) override {
+ void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitch(
switches::kDisableGestureRequirementForMediaPlayback);
}
diff --git a/chromium/content/browser/media/media_web_contents_observer.cc b/chromium/content/browser/media/media_web_contents_observer.cc
index 7f9e2b65564..f87cfb1e40d 100644
--- a/chromium/content/browser/media/media_web_contents_observer.cc
+++ b/chromium/content/browser/media/media_web_contents_observer.cc
@@ -8,11 +8,13 @@
#include "base/stl_util.h"
#include "content/browser/media/cdm/browser_cdm_manager.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
+#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "ipc/ipc_message_macros.h"
#if defined(OS_ANDROID)
+#include "content/browser/android/media_players_observer.h"
#include "content/browser/media/android/browser_media_player_manager.h"
#include "content/common/media/media_player_messages_android.h"
#include "media/base/android/media_player_android.h"
@@ -21,8 +23,9 @@
namespace content {
MediaWebContentsObserver::MediaWebContentsObserver(
- RenderViewHost* render_view_host)
- : WebContentsObserver(WebContents::FromRenderViewHost(render_view_host)) {
+ WebContents* web_contents)
+ : WebContentsObserver(web_contents)
+{
}
MediaWebContentsObserver::~MediaWebContentsObserver() {
@@ -30,11 +33,15 @@ MediaWebContentsObserver::~MediaWebContentsObserver() {
void MediaWebContentsObserver::RenderFrameDeleted(
RenderFrameHost* render_frame_host) {
+#if defined(OS_ANDROID)
uintptr_t key = reinterpret_cast<uintptr_t>(render_frame_host);
// Always destroy the media players before CDMs because we do not support
// detaching CDMs from media players yet. See http://crbug.com/330324
-#if defined(OS_ANDROID)
media_player_managers_.erase(key);
+
+ MediaPlayersObserver* audio_observer = GetMediaPlayersObserver();
+ if (audio_observer)
+ audio_observer->RenderFrameDeleted(render_frame_host);
#endif
// TODO(xhwang): Currently MediaWebContentsObserver, BrowserMediaPlayerManager
// and BrowserCdmManager all run on browser UI thread. So this call is okay.
@@ -161,11 +168,24 @@ BrowserMediaPlayerManager* MediaWebContentsObserver::GetMediaPlayerManager(
if (!media_player_managers_.contains(key)) {
media_player_managers_.set(
key,
- make_scoped_ptr(BrowserMediaPlayerManager::Create(render_frame_host)));
+ make_scoped_ptr(BrowserMediaPlayerManager::Create(
+ render_frame_host, GetMediaPlayersObserver())));
}
return media_player_managers_.get(key);
}
+MediaPlayersObserver*
+MediaWebContentsObserver::GetMediaPlayersObserver() const {
+ AudioStateProvider* provider =
+ static_cast<WebContentsImpl*>(web_contents())->audio_state_provider();
+
+ MediaPlayersObserver* audio_observer =
+ static_cast<MediaPlayersObserver*>(provider);
+
+ DCHECK(audio_observer);
+ return audio_observer;
+}
+
#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 d79e1ce930e..8fbe08084fa 100644
--- a/chromium/content/browser/media/media_web_contents_observer.h
+++ b/chromium/content/browser/media/media_web_contents_observer.h
@@ -7,14 +7,18 @@
#include "base/compiler_specific.h"
#include "base/containers/scoped_ptr_hash_map.h"
+#include "base/memory/scoped_ptr.h"
#include "content/common/content_export.h"
#include "content/public/browser/web_contents_observer.h"
namespace content {
+#if defined(OS_ANDROID)
+class MediaPlayersObserver;
+#endif // defined(OS_ANDROID)
+
class BrowserCdmManager;
class BrowserMediaPlayerManager;
-class RenderViewHost;
// This class manages all RenderFrame based media related managers at the
// browser side. It receives IPC messages from media RenderFrameObservers and
@@ -22,15 +26,15 @@ class RenderViewHost;
// for sending IPCs back to the RenderFrameObservers at the render side.
class CONTENT_EXPORT MediaWebContentsObserver : public WebContentsObserver {
public:
- explicit MediaWebContentsObserver(RenderViewHost* render_view_host);
- virtual ~MediaWebContentsObserver();
+ explicit MediaWebContentsObserver(WebContents* web_contents);
+ ~MediaWebContentsObserver() override;
// WebContentsObserver implementations.
- virtual void RenderFrameDeleted(RenderFrameHost* render_frame_host) override;
+ void RenderFrameDeleted(RenderFrameHost* render_frame_host) override;
#if defined(OS_ANDROID)
- virtual bool OnMessageReceived(const IPC::Message& message,
- RenderFrameHost* render_frame_host) override;
+ 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.
@@ -46,13 +50,16 @@ class CONTENT_EXPORT MediaWebContentsObserver : public WebContentsObserver {
void OnSetCdm(RenderFrameHost* render_frame_host, int player_id, int cdm_id);
+ MediaPlayersObserver* GetMediaPlayersObserver() const;
+
#if defined(VIDEO_HOLE)
void OnFrameInfoUpdated();
#endif // defined(VIDEO_HOLE)
private:
// Map from RenderFrameHost* to BrowserMediaPlayerManager.
- typedef base::ScopedPtrHashMap<uintptr_t, BrowserMediaPlayerManager>
+ typedef base::ScopedPtrHashMap<uintptr_t,
+ scoped_ptr<BrowserMediaPlayerManager>>
MediaPlayerManagerMap;
MediaPlayerManagerMap media_player_managers_;
#endif // defined(OS_ANDROID)
diff --git a/chromium/content/browser/media/midi_dispatcher_host.cc b/chromium/content/browser/media/midi_dispatcher_host.cc
deleted file mode 100644
index 944dae51d8d..00000000000
--- a/chromium/content/browser/media/midi_dispatcher_host.cc
+++ /dev/null
@@ -1,140 +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/media/midi_dispatcher_host.h"
-
-#include "base/bind.h"
-#include "content/browser/child_process_security_policy_impl.h"
-#include "content/browser/frame_host/render_frame_host_impl.h"
-#include "content/common/media/midi_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/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"
-#include "url/gurl.h"
-
-namespace content {
-
-MidiDispatcherHost::PendingPermission::PendingPermission(
- int render_process_id,
- int render_frame_id,
- int bridge_id)
- : render_process_id(render_process_id),
- render_frame_id(render_frame_id),
- bridge_id(bridge_id) {
-}
-
-MidiDispatcherHost::PendingPermission::~PendingPermission() {
-}
-
-MidiDispatcherHost::MidiDispatcherHost(WebContents* web_contents)
- : WebContentsObserver(web_contents),
- weak_factory_(this) {
-}
-
-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;
- IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(MidiDispatcherHost, message,
- render_frame_host)
- IPC_MESSAGE_HANDLER(MidiHostMsg_RequestSysExPermission,
- OnRequestSysExPermission)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-void MidiDispatcherHost::OnRequestSysExPermission(
- RenderFrameHost* render_frame_host,
- int bridge_id,
- const GURL& 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_process_id, render_frame_id, bridge_id);
- pending_permissions_.push_back(pending_permission);
-
- 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));
-}
-
-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) {
- 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;
- }
- }
-}
-
-void MidiDispatcherHost::WasSysExPermissionGranted(int render_process_id,
- int render_frame_id,
- int bridge_id,
- bool is_allowed) {
- 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) {
- RenderFrameHost* render_frame_host =
- RenderFrameHost::FromID(render_process_id, render_frame_id);
- if (render_frame_host) {
- render_frame_host->Send(new MidiMsg_SysExPermissionApproved(
- render_frame_id, bridge_id, is_allowed));
- }
-
- if (is_allowed) {
- ChildProcessSecurityPolicyImpl::GetInstance()->
- GrantSendMidiSysExMessage(render_process_id);
- }
-
- pending_permissions_.erase(pending_permissions_.begin() + i);
- return;
- }
- }
-}
-
-} // namespace content
diff --git a/chromium/content/browser/media/midi_dispatcher_host.h b/chromium/content/browser/media/midi_dispatcher_host.h
deleted file mode 100644
index a487178851d..00000000000
--- a/chromium/content/browser/media/midi_dispatcher_host.h
+++ /dev/null
@@ -1,64 +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_MEDIA_MIDI_DISPATCHER_HOST_H_
-#define CONTENT_BROWSER_MEDIA_MIDI_DISPATCHER_HOST_H_
-
-#include <vector>
-
-#include "base/callback_forward.h"
-#include "base/memory/weak_ptr.h"
-#include "content/public/browser/web_contents_observer.h"
-
-namespace content {
-
-class BrowserContext;
-
-// MidiDispatcherHost handles permissions for using system exclusive messages.
-class MidiDispatcherHost : public WebContentsObserver {
- public:
- explicit MidiDispatcherHost(WebContents* web_contents);
- ~MidiDispatcherHost() override;
-
- // WebContentsObserver implementation.
- 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,
- int bridge_id,
- const GURL& origin,
- bool user_gesture);
- void OnCancelSysExPermissionRequest(RenderFrameHost* render_frame_host,
- int bridge_id,
- const GURL& requesting_frame);
- void WasSysExPermissionGranted(int render_process_id,
- int render_frame_id,
- int bridge_id,
- bool is_allowed);
- void CancelPermissionRequestsForFrame(RenderFrameHost* render_frame_host);
-
- struct PendingPermission {
- PendingPermission(int render_process_id,
- int render_frame_id,
- int bridge_id);
- ~PendingPermission();
- int render_process_id;
- int render_frame_id;
- int bridge_id;
- };
- std::vector<PendingPermission> pending_permissions_;
-
- base::WeakPtrFactory<MidiDispatcherHost> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(MidiDispatcherHost);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_MEDIA_MIDI_DISPATCHER_HOST_H_
diff --git a/chromium/content/browser/media/midi_host.cc b/chromium/content/browser/media/midi_host.cc
index 2fc01478575..721095e0bc3 100644
--- a/chromium/content/browser/media/midi_host.cc
+++ b/chromium/content/browser/media/midi_host.cc
@@ -6,8 +6,8 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
-#include "base/debug/trace_event.h"
#include "base/process/process.h"
+#include "base/trace_event/trace_event.h"
#include "content/browser/browser_main_loop.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/media/media_internals.h"
@@ -19,9 +19,6 @@
#include "media/midi/midi_message_queue.h"
#include "media/midi/midi_message_util.h"
-using media::MidiManager;
-using media::MidiPortInfoList;
-
namespace content {
namespace {
@@ -45,17 +42,19 @@ bool IsSystemRealTimeMessage(uint8 data) {
} // namespace
-using media::kSysExByte;
-using media::kEndOfSysExByte;
+using media::midi::kSysExByte;
+using media::midi::kEndOfSysExByte;
-MidiHost::MidiHost(int renderer_process_id, media::MidiManager* midi_manager)
+MidiHost::MidiHost(int renderer_process_id,
+ media::midi::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) {
+ bytes_sent_since_last_acknowledgement_(0),
+ output_port_count_(0) {
CHECK(midi_manager_);
}
@@ -90,6 +89,15 @@ void MidiHost::OnStartSession() {
void MidiHost::OnSendData(uint32 port,
const std::vector<uint8>& data,
double timestamp) {
+ {
+ base::AutoLock auto_lock(output_port_count_lock_);
+ if (output_port_count_ <= port) {
+ RecordAction(base::UserMetricsAction("BadMessageTerminate_MIDIPort"));
+ BadMessageReceived();
+ return;
+ }
+ }
+
if (data.empty())
return;
@@ -123,9 +131,9 @@ void MidiHost::OnEndSession() {
midi_manager_->EndSession(this);
}
-void MidiHost::CompleteStartSession(media::MidiResult result) {
+void MidiHost::CompleteStartSession(media::midi::MidiResult result) {
DCHECK(is_session_requested_);
- if (result == media::MIDI_OK) {
+ if (result == media::midi::MIDI_OK) {
// ChildSecurityPolicy is set just before OnStartSession by
// MidiDispatcherHost. So we can safely cache the policy.
has_sys_ex_permission_ = ChildProcessSecurityPolicyImpl::GetInstance()->
@@ -134,17 +142,29 @@ void MidiHost::CompleteStartSession(media::MidiResult result) {
Send(new MidiMsg_SessionStarted(result));
}
-void MidiHost::AddInputPort(const media::MidiPortInfo& info) {
+void MidiHost::AddInputPort(const media::midi::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));
}
-void MidiHost::AddOutputPort(const media::MidiPortInfo& info) {
+void MidiHost::AddOutputPort(const media::midi::MidiPortInfo& info) {
+ base::AutoLock auto_lock(output_port_count_lock_);
+ output_port_count_++;
Send(new MidiMsg_AddOutputPort(info));
}
+void MidiHost::SetInputPortState(uint32 port,
+ media::midi::MidiPortState state) {
+ Send(new MidiMsg_SetInputPortState(port, state));
+}
+
+void MidiHost::SetOutputPortState(uint32 port,
+ media::midi::MidiPortState state) {
+ Send(new MidiMsg_SetOutputPortState(port, state));
+}
+
void MidiHost::ReceiveMidiData(
uint32 port,
const uint8* data,
@@ -158,7 +178,7 @@ void MidiHost::ReceiveMidiData(
// Lazy initialization
if (received_messages_queues_[port] == nullptr)
- received_messages_queues_[port] = new media::MidiMessageQueue(true);
+ received_messages_queues_[port] = new media::midi::MidiMessageQueue(true);
received_messages_queues_[port]->Add(data, length);
std::vector<uint8> message;
@@ -222,7 +242,7 @@ bool MidiHost::IsValidWebMIDIData(const std::vector<uint8>& data) {
in_sysex = true;
continue; // Found SysEX
}
- waiting_data_length = media::GetMidiMessageLength(current);
+ waiting_data_length = media::midi::GetMidiMessageLength(current);
if (waiting_data_length == 0)
return false; // Error: |current| should have been a valid status byte.
--waiting_data_length; // Found status byte
diff --git a/chromium/content/browser/media/midi_host.h b/chromium/content/browser/media/midi_host.h
index 3a469bf93b9..7a47775ede5 100644
--- a/chromium/content/browser/media/midi_host.h
+++ b/chromium/content/browser/media/midi_host.h
@@ -16,29 +16,35 @@
#include "content/public/browser/browser_message_filter.h"
#include "content/public/browser/browser_thread.h"
#include "media/midi/midi_manager.h"
+#include "media/midi/midi_port_info.h"
namespace media {
+namespace midi {
class MidiManager;
class MidiMessageQueue;
}
+}
namespace content {
-class CONTENT_EXPORT MidiHost
- : public BrowserMessageFilter,
- public media::MidiManagerClient {
+class CONTENT_EXPORT MidiHost : public BrowserMessageFilter,
+ public media::midi::MidiManagerClient {
public:
// Called from UI thread from the owner of this object.
- MidiHost(int renderer_process_id, media::MidiManager* midi_manager);
+ MidiHost(int renderer_process_id, media::midi::MidiManager* midi_manager);
// BrowserMessageFilter implementation.
void OnDestruct() const override;
bool OnMessageReceived(const IPC::Message& message) override;
// MidiManagerClient implementation.
- void CompleteStartSession(media::MidiResult result) override;
- void AddInputPort(const media::MidiPortInfo& info) override;
- void AddOutputPort(const media::MidiPortInfo& info) override;
+ void CompleteStartSession(media::midi::MidiResult result) override;
+ void AddInputPort(const media::midi::MidiPortInfo& info) override;
+ void AddOutputPort(const media::midi::MidiPortInfo& info) override;
+ void SetInputPortState(uint32 port,
+ media::midi::MidiPortState state) override;
+ void SetOutputPortState(uint32 port,
+ media::midi::MidiPortState state) override;
void ReceiveMidiData(uint32 port,
const uint8* data,
size_t length,
@@ -55,13 +61,14 @@ class CONTENT_EXPORT MidiHost
void OnEndSession();
+ protected:
+ ~MidiHost() override;
+
private:
FRIEND_TEST_ALL_PREFIXES(MidiHostTest, IsValidWebMIDIData);
friend class base::DeleteHelper<MidiHost>;
friend class BrowserThread;
- ~MidiHost() override;
-
// Returns true if |data| fulfills the requirements of MidiOutput.send API
// defined in the WebMIDI spec.
// - |data| must be any number of complete MIDI messages (data abbreviation
@@ -83,10 +90,10 @@ class CONTENT_EXPORT MidiHost
// does not support MIDI. If not supported then a call to
// OnRequestAccess() will always refuse access and a call to
// OnSendData() will do nothing.
- media::MidiManager* const midi_manager_;
+ media::midi::MidiManager* const midi_manager_;
// Buffers where data sent from each MIDI input port is stored.
- ScopedVector<media::MidiMessageQueue> received_messages_queues_;
+ ScopedVector<media::midi::MidiMessageQueue> received_messages_queues_;
// Protects access to |received_messages_queues_|;
base::Lock messages_queues_lock_;
@@ -102,6 +109,12 @@ class CONTENT_EXPORT MidiHost
// Protects access to |sent_bytes_in_flight_|.
base::Lock in_flight_lock_;
+ // How many output port exists.
+ uint32 output_port_count_;
+
+ // Protects access to |output_port_count_|.
+ base::Lock output_port_count_lock_;
+
DISALLOW_COPY_AND_ASSIGN(MidiHost);
};
diff --git a/chromium/content/browser/media/midi_host_unittest.cc b/chromium/content/browser/media/midi_host_unittest.cc
index e06e4e4de51..29f079669a2 100644
--- a/chromium/content/browser/media/midi_host_unittest.cc
+++ b/chromium/content/browser/media/midi_host_unittest.cc
@@ -4,6 +4,12 @@
#include "content/browser/media/midi_host.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/strings/stringprintf.h"
+#include "content/common/media/midi_messages.h"
+#include "content/public/test/test_browser_thread.h"
+#include "media/midi/midi_manager.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
@@ -27,6 +33,8 @@ const uint8 kBrokenData2[] = { 0xf7 };
const uint8 kBrokenData3[] = { 0xf2, 0x00 };
const uint8 kDataByte0[] = { 0x00 };
+const int kRenderProcessId = 0;
+
template <typename T, size_t N>
const std::vector<T> AsVector(const T(&data)[N]) {
std::vector<T> buffer;
@@ -39,9 +47,113 @@ void PushToVector(const T(&data)[N], std::vector<T>* buffer) {
buffer->insert(buffer->end(), data, data + N);
}
+enum MidiEventType {
+ DISPATCH_SEND_MIDI_DATA,
+};
+
+struct MidiEvent {
+ MidiEvent(MidiEventType in_type,
+ uint32 in_port_index,
+ const std::vector<uint8>& in_data,
+ double in_timestamp)
+ : type(in_type),
+ port_index(in_port_index),
+ data(in_data),
+ timestamp(in_timestamp) {}
+
+ MidiEventType type;
+ uint32 port_index;
+ std::vector<uint8> data;
+ double timestamp;
+};
+
+class FakeMidiManager : public media::midi::MidiManager {
+ public:
+ void DispatchSendMidiData(media::midi::MidiManagerClient* client,
+ uint32 port_index,
+ const std::vector<uint8>& data,
+ double timestamp) override {
+ events_.push_back(MidiEvent(DISPATCH_SEND_MIDI_DATA,
+ port_index,
+ data,
+ timestamp));
+ }
+ std::vector<MidiEvent> events_;
+};
+
+class MidiHostForTesting : public MidiHost {
+ public:
+ MidiHostForTesting(int renderer_process_id,
+ media::midi::MidiManager* midi_manager)
+ : MidiHost(renderer_process_id, midi_manager) {}
+
+ private:
+ ~MidiHostForTesting() override {}
+
+ // BrowserMessageFilter implementation.
+ // Override BadMessageReceived() so to do nothing since the original
+ // implementation to kill a malicious renderer process causes a check failure
+ // in unit tests.
+ void BadMessageReceived() override {}
+};
+
+class MidiHostTest : public testing::Test {
+ public:
+ MidiHostTest()
+ : io_browser_thread_(BrowserThread::IO, &message_loop_),
+ host_(new MidiHostForTesting(kRenderProcessId, &manager_)),
+ data_(kNoteOn, kNoteOn + arraysize(kNoteOn)),
+ port_id_(0) {}
+
+ protected:
+ void AddOutputPort() {
+ const std::string id = base::StringPrintf("i-can-%d", port_id_++);
+ const std::string manufacturer("yukatan");
+ const std::string name("doki-doki-pi-pine");
+ const std::string version("3.14159265359");
+ media::midi::MidiPortState state = media::midi::MIDI_PORT_CONNECTED;
+ media::midi::MidiPortInfo info(id, manufacturer, name, version, state);
+
+ host_->AddOutputPort(info);
+ }
+
+ void OnSendData(uint32 port) {
+ scoped_ptr<IPC::Message> message(
+ new MidiHostMsg_SendData(port, data_, 0.0));
+ host_->OnMessageReceived(*message.get());
+ }
+
+ size_t GetEventSize() const {
+ return manager_.events_.size();
+ }
+
+ void CheckSendEventAt(size_t at, uint32 port) {
+ EXPECT_EQ(DISPATCH_SEND_MIDI_DATA, manager_.events_[at].type);
+ EXPECT_EQ(port, manager_.events_[at].port_index);
+ EXPECT_EQ(data_, manager_.events_[at].data);
+ EXPECT_EQ(0.0, manager_.events_[at].timestamp);
+ }
+
+ void RunLoopUntilIdle() {
+ base::RunLoop run_loop;
+ run_loop.RunUntilIdle();
+ }
+
+ private:
+ base::MessageLoop message_loop_;
+ TestBrowserThread io_browser_thread_;
+
+ FakeMidiManager manager_;
+ scoped_refptr<MidiHostForTesting> host_;
+ std::vector<uint8> data_;
+ int32 port_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(MidiHostTest);
+};
+
} // namespace
-TEST(MidiHostTest, IsValidWebMIDIData) {
+TEST_F(MidiHostTest, IsValidWebMIDIData) {
// Test single event scenario
EXPECT_TRUE(MidiHost::IsValidWebMIDIData(AsVector(kGMOn)));
EXPECT_TRUE(MidiHost::IsValidWebMIDIData(AsVector(kGSOn)));
@@ -88,4 +200,34 @@ TEST(MidiHostTest, IsValidWebMIDIData) {
}
}
+// Test if sending data to out of range port is ignored.
+TEST_F(MidiHostTest, OutputPortCheck) {
+ // Only one output port is available.
+ AddOutputPort();
+
+ // Sending data to port 0 should be delivered.
+ uint32 port0 = 0;
+ OnSendData(port0);
+ RunLoopUntilIdle();
+ EXPECT_EQ(1U, GetEventSize());
+ CheckSendEventAt(0, port0);
+
+ // Sending data to port 1 should not be delivered.
+ uint32 port1 = 1;
+ OnSendData(port1);
+ RunLoopUntilIdle();
+ EXPECT_EQ(1U, GetEventSize());
+
+ // Two output ports are available from now on.
+ AddOutputPort();
+
+ // Sending data to port 0 and 1 should be delivered now.
+ OnSendData(port0);
+ OnSendData(port1);
+ RunLoopUntilIdle();
+ EXPECT_EQ(3U, GetEventSize());
+ CheckSendEventAt(1, port0);
+ CheckSendEventAt(2, port1);
+}
+
} // namespace conent
diff --git a/chromium/content/browser/media/webrtc_aecdump_browsertest.cc b/chromium/content/browser/media/webrtc_aecdump_browsertest.cc
index bdeed59bea7..148aee73bd0 100644
--- a/chromium/content/browser/media/webrtc_aecdump_browsertest.cc
+++ b/chromium/content/browser/media/webrtc_aecdump_browsertest.cc
@@ -157,19 +157,11 @@ IN_PROC_BROWSER_TEST_F(WebRtcAecDumpBrowserTest,
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) {
+// Flaky on XP and Mac: http://crbug.com/425034.
+IN_PROC_BROWSER_TEST_F(WebRtcAecDumpBrowserTest, DISABLED_TwoCallsWithAecDump) {
if (OnWinXp()) {
- // http://crbug.com/425034.
LOG(INFO) << "Disabled on Win XP: skipping test...";
return;
}
diff --git a/chromium/content/browser/media/webrtc_browsertest.cc b/chromium/content/browser/media/webrtc_browsertest.cc
index 45c3623550a..e69d4c93f99 100644
--- a/chromium/content/browser/media/webrtc_browsertest.cc
+++ b/chromium/content/browser/media/webrtc_browsertest.cc
@@ -33,9 +33,6 @@ namespace content {
#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
@@ -113,12 +110,8 @@ IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
MakeTypicalPeerConnectionCall(javascript);
}
-#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)
+#if defined(THREAD_SANITIZER)
#define MAYBE_CanSetupVideoCallWith16To9AspectRatio \
DISABLED_CanSetupVideoCallWith16To9AspectRatio
#else
@@ -144,21 +137,16 @@ IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
MAYBE_CanSetupVideoCallWith4To3AspectRatio) {
const std::string javascript =
- "callAndExpectResolution({video: {mandatory: {minWidth: 960,"
- "maxAspectRatio: 1.333}}}, 960, 720);";
+ "callAndExpectResolution({video: {mandatory: { minWidth: 960,"
+ "maxWidth: 960, minAspectRatio: 1.333, 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
+// Flaky everywhere: http://crbug.com/477498
IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
- MAYBE_CanSetupVideoCallAndDisableLocalVideo) {
+ DISABLED_CanSetupVideoCallAndDisableLocalVideo) {
const std::string javascript =
"callAndDisableLocalVideo({video: true});";
MakeTypicalPeerConnectionCall(javascript);
@@ -181,44 +169,39 @@ IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
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_F(MAYBE_WebRtcBrowserTest,
- DISABLED_CanMakeEmptyCallThenAddStreamsAndRenegotiate) {
+ CanMakeEmptyCallThenAddStreamsAndRenegotiate) {
const char* kJavascript =
"callEmptyThenAddOneStreamAndRenegotiate({video: true, audio: true});";
MakeTypicalPeerConnectionCall(kJavascript);
}
-// Below 2 test will make a complete PeerConnection-based call between pc1 and
-// pc2, and then use the remote stream to setup a call between pc3 and pc4, and
-// then verify that video is received on pc3 and pc4.
-// 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.
-#if defined(THREAD_SANITIZER)
-// Flaky on TSAN v2. http://crbug.com/373637
-#define MAYBE_CanForwardRemoteStream DISABLED_CanForwardRemoteStream
-#define MAYBE_CanForwardRemoteStream720p DISABLED_CanForwardRemoteStream720p
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
+ CanMakeAudioCallAndThenRenegotiateToVideo) {
+ const char* kJavascript =
+ "callAndRenegotiateToVideo({audio: true}, {audio: true, video:true});";
+ MakeTypicalPeerConnectionCall(kJavascript);
+}
+
+#if defined(OS_MACOSX)
+// Flaky on Mac-10.9: https://crbug.com/484826
+#define MAYBE_CanMakeVideoCallAndThenRenegotiateToAudio DISABLED_CanMakeVideoCallAndThenRenegotiateToAudio
#else
-#define MAYBE_CanForwardRemoteStream CanForwardRemoteStream
-#define MAYBE_CanForwardRemoteStream720p CanForwardRemoteStream720p
-#endif
-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.
- base::CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kDisableWebRtcHWDecoding);
+#define MAYBE_CanMakeVideoCallAndThenRenegotiateToAudio CanMakeVideoCallAndThenRenegotiateToAudio
#endif
- MakeTypicalPeerConnectionCall(
- "callAndForwardRemoteStream({video: true, audio: false});");
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
+ MAYBE_CanMakeVideoCallAndThenRenegotiateToAudio) {
+ MakeAudioDetectingPeerConnectionCall(base::StringPrintf(
+ "callAndRenegotiateToAudio("
+ " %s, {audio: true, video:true}, {audio: true});",
+ kUseLenientAudioChecking));
}
-IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
- MAYBE_CanForwardRemoteStream720p) {
+// This test makes a call between pc1 and pc2 where a video only stream is sent
+// from pc1 to pc2. The stream sent from pc1 to pc2 is cloned from the stream
+// received on pc2 to test that cloning of remote video tracks works as
+// intended and is sent back to pc1.
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest, CanForwardRemoteStream) {
#if defined (OS_ANDROID)
// This test fails on Nexus 5 devices.
// TODO(henrika): see http://crbug.com/362437 and http://crbug.com/359389
@@ -226,9 +209,8 @@ IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kDisableWebRtcHWDecoding);
#endif
- const std::string javascript = GenerateGetUserMediaCall(
- "callAndForwardRemoteStream", 1280, 1280, 720, 720, 10, 30);
- MakeTypicalPeerConnectionCall(javascript);
+ MakeTypicalPeerConnectionCall(
+ "callAndForwardRemoteStream({video: true, audio: false});");
}
IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
@@ -365,9 +347,7 @@ IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
// MediaStream that has been created based on a MediaStream created with
// getUserMedia. When video is flowing, the VideoTrack is removed and an
// AudioTrack is added instead.
-// TODO(phoglund): This test is manual since not all buildbots has an audio
-// input.
-IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest, MANUAL_CallAndModifyStream) {
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest, CallAndModifyStream) {
MakeTypicalPeerConnectionCall(
"callWithNewVideoMediaStreamLaterSwitchToAudio();");
}
diff --git a/chromium/content/browser/media/webrtc_getusermedia_browsertest.cc b/chromium/content/browser/media/webrtc_getusermedia_browsertest.cc
index 8c8bf2dba09..d7bca4f9ea4 100644
--- a/chromium/content/browser/media/webrtc_getusermedia_browsertest.cc
+++ b/chromium/content/browser/media/webrtc_getusermedia_browsertest.cc
@@ -3,10 +3,10 @@
// found in the LICENSE file.
#include "base/command_line.h"
-#include "base/debug/trace_event_impl.h"
#include "base/json/json_reader.h"
#include "base/strings/stringprintf.h"
#include "base/test/trace_event_analyzer.h"
+#include "base/trace_event/trace_event_impl.h"
#include "base/values.h"
#include "content/browser/media/webrtc_internals.h"
#include "content/browser/web_contents/web_contents_impl.h"
@@ -82,11 +82,12 @@ class WebRtcGetUserMediaBrowserTest: public WebRtcContentBrowserTest {
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_log_ = base::trace_event::TraceLog::GetInstance();
+ base::trace_event::TraceOptions trace_options(
+ base::trace_event::RECORD_UNTIL_FULL);
trace_options.enable_sampling = true;
- trace_log_->SetEnabled(base::debug::CategoryFilter("video"),
- base::debug::TraceLog::RECORDING_MODE,
+ trace_log_->SetEnabled(base::trace_event::CategoryFilter("video"),
+ base::trace_event::TraceLog::RECORDING_MODE,
trace_options);
// Check that we are indeed recording.
EXPECT_EQ(trace_log_->GetNumTracesRecorded(), 1);
@@ -231,7 +232,7 @@ class WebRtcGetUserMediaBrowserTest: public WebRtcContentBrowserTest {
}
private:
- base::debug::TraceLog* trace_log_;
+ base::trace_event::TraceLog* trace_log_;
scoped_refptr<base::RefCountedString> recorded_trace_data_;
scoped_refptr<MessageLoopRunner> message_loop_runner_;
};
@@ -239,7 +240,15 @@ class WebRtcGetUserMediaBrowserTest: public WebRtcContentBrowserTest {
// 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_F(WebRtcGetUserMediaBrowserTest, GetVideoStreamAndStop) {
+
+// Test fails under MSan, http://crbug.com/445745
+#if defined(MEMORY_SANITIZER)
+#define MAYBE_GetVideoStreamAndStop DISABLED_GetVideoStreamAndStop
+#else
+#define MAYBE_GetVideoStreamAndStop GetVideoStreamAndStop
+#endif
+IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
+ MAYBE_GetVideoStreamAndStop) {
ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
@@ -249,8 +258,16 @@ IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest, GetVideoStreamAndStop) {
base::StringPrintf("%s({video: true});", kGetUserMediaAndStop));
}
+// Test fails under MSan, http://crbug.com/445745
+#if defined(MEMORY_SANITIZER)
+#define MAYBE_RenderSameTrackMediastreamAndStop \
+ DISABLED_RenderSameTrackMediastreamAndStop
+#else
+#define MAYBE_RenderSameTrackMediastreamAndStop \
+ RenderSameTrackMediastreamAndStop
+#endif
IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
- RenderSameTrackMediastreamAndStop) {
+ MAYBE_RenderSameTrackMediastreamAndStop) {
ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
@@ -451,10 +468,19 @@ IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
expected_result);
}
+// Test fails under MSan, http://crbug.com/445745
+#if defined(MEMORY_SANITIZER)
+#define MAYBE_TwoGetUserMediaWithFirstHdSecondVga \
+ DISABLED_TwoGetUserMediaWithFirstHdSecondVga
+#else
+#define MAYBE_TwoGetUserMediaWithFirstHdSecondVga \
+ TwoGetUserMediaWithFirstHdSecondVga
+#endif
IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
- TwoGetUserMediaWithFirstHdSecondVga) {
+ MAYBE_TwoGetUserMediaWithFirstHdSecondVga) {
std::string constraints1 =
- "{video: {mandatory: {minWidth:1280 , minHeight: 720}}}";
+ "{video: {mandatory: {maxWidth:1280 , minWidth:1280 , maxHeight: 720,\
+ minHeight: 720}}}";
std::string constraints2 =
"{video: {mandatory: {maxWidth:640 , maxHeight: 480}}}";
std::string expected_result = "w=1280:h=720-w=640:h=480";
@@ -462,8 +488,37 @@ IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
expected_result);
}
+#if defined(OS_WIN)
+// Timing out on Winodws 7 bot: http://crbug.com/443294
+#define MAYBE_TwoGetUserMediaWithFirst1080pSecondVga\
+ DISABLED_TwoGetUserMediaWithFirst1080pSecondVga
+#else
+#define MAYBE_TwoGetUserMediaWithFirst1080pSecondVga\
+ TwoGetUserMediaWithFirst1080pSecondVga
+#endif
+
IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
- TwoGetUserMediaAndVerifyFrameRate) {
+ MAYBE_TwoGetUserMediaWithFirst1080pSecondVga) {
+ std::string constraints1 =
+ "{video: {mandatory: {maxWidth:1920 , minWidth:1920 , maxHeight: 1080,\
+ minHeight: 1080}}}";
+ std::string constraints2 =
+ "{video: {mandatory: {maxWidth:640 , maxHeight: 480}}}";
+ std::string expected_result = "w=1920:h=1080-w=640:h=480";
+ RunTwoGetTwoGetUserMediaWithDifferentContraints(constraints1, constraints2,
+ expected_result);
+}
+
+// Test fails under MSan, http://crbug.com/445745
+#if defined(MEMORY_SANITIZER)
+#define MAYBE_TwoGetUserMediaAndVerifyFrameRate \
+ DISABLED_TwoGetUserMediaAndVerifyFrameRate
+#else
+#define MAYBE_TwoGetUserMediaAndVerifyFrameRate \
+ TwoGetUserMediaAndVerifyFrameRate
+#endif
+IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
+ MAYBE_TwoGetUserMediaAndVerifyFrameRate) {
ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
@@ -540,13 +595,20 @@ IN_PROC_BROWSER_TEST_F(
TraceVideoCaptureControllerPerformanceDuringGetUserMedia) {
RunGetUserMediaAndCollectMeasures(
10,
- "VideoCaptureController::OnIncomingCapturedData",
- "VideoCaptureController");
+ "VideoCaptureDeviceClient::OnIncomingCapturedData",
+ "VideoCaptureDeviceClient");
}
+// Test fails under MSan, http://crbug.com/445745
+#if defined(MEMORY_SANITIZER)
+#define MAYBE_TestGetUserMediaAspectRatio4To3 \
+ DISABLED_TestGetUserMediaAspectRatio4To3
+#else
+#define MAYBE_TestGetUserMediaAspectRatio4To3 TestGetUserMediaAspectRatio4To3
+#endif
// This test calls getUserMedia and checks for aspect ratio behavior.
IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
- TestGetUserMediaAspectRatio4To3) {
+ MAYBE_TestGetUserMediaAspectRatio4To3) {
ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
@@ -559,9 +621,16 @@ IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
ExecuteJavascriptAndReturnResult(constraints_4_3));
}
+// Test fails under MSan, http://crbug.com/445745
+#if defined(MEMORY_SANITIZER)
+#define MAYBE_TestGetUserMediaAspectRatio16To9 \
+ DISABLED_TestGetUserMediaAspectRatio16To9
+#else
+#define MAYBE_TestGetUserMediaAspectRatio16To9 TestGetUserMediaAspectRatio16To9
+#endif
// This test calls getUserMedia and checks for aspect ratio behavior.
IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
- TestGetUserMediaAspectRatio16To9) {
+ MAYBE_TestGetUserMediaAspectRatio16To9) {
ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
@@ -574,9 +643,16 @@ IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
ExecuteJavascriptAndReturnResult(constraints_16_9));
}
+// Test fails under MSan, http://crbug.com/445745
+#if defined(MEMORY_SANITIZER)
+#define MAYBE_TestGetUserMediaAspectRatio1To1 \
+ DISABLED_TestGetUserMediaAspectRatio1To1
+#else
+#define MAYBE_TestGetUserMediaAspectRatio1To1 TestGetUserMediaAspectRatio1To1
+#endif
// This test calls getUserMedia and checks for aspect ratio behavior.
IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
- TestGetUserMediaAspectRatio1To1) {
+ MAYBE_TestGetUserMediaAspectRatio1To1) {
ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
@@ -589,6 +665,68 @@ IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
ExecuteJavascriptAndReturnResult(constraints_1_1));
}
+// This test calls getUserMedia in an iframe and immediately close the iframe
+// in the scope of the success callback.
+IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
+ AudioInIFrameAndCloseInSuccessCb) {
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
+ GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
+ NavigateToURL(shell(), url);
+
+ std::string call =
+ "getUserMediaInIframeAndCloseInSuccessCb({audio: true});";
+ ExecuteJavascriptAndWaitForOk(call);
+}
+
+IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
+ VideoInIFrameAndCloseInSuccessCb) {
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
+ GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
+ NavigateToURL(shell(), url);
+
+ std::string call =
+ "getUserMediaInIframeAndCloseInSuccessCb({video: true});";
+ ExecuteJavascriptAndWaitForOk(call);
+}
+
+// This test calls getUserMedia in an iframe and immediately close the iframe
+// in the scope of the failure callback.
+IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
+ VideoWithBadConstraintsInIFrameAndCloseInFailureCb) {
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
+ GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
+
+ int large_value = 99999;
+ std::string call =
+ GenerateGetUserMediaCall("getUserMediaInIframeAndCloseInFailureCb",
+ large_value,
+ large_value,
+ large_value,
+ large_value,
+ large_value,
+ large_value);
+ NavigateToURL(shell(), url);
+
+ ExecuteJavascriptAndWaitForOk(call);
+}
+
+IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
+ InvalidSourceIdInIFrameAndCloseInFailureCb) {
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
+ GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
+
+ std::string call =
+ GenerateGetUserMediaWithMandatorySourceID(
+ "getUserMediaInIframeAndCloseInFailureCb", "invalid", "invalid");
+ NavigateToURL(shell(), url);
+
+ ExecuteJavascriptAndWaitForOk(call);
+}
+
namespace {
struct UserMediaSizes {
@@ -613,8 +751,15 @@ class WebRtcConstraintsBrowserTest
UserMediaSizes user_media_;
};
+// Test fails under MSan, http://crbug.com/445745
+#if defined(MEMORY_SANITIZER)
+#define MAYBE_GetUserMediaConstraints DISABLED_GetUserMediaConstraints
+#else
+#define MAYBE_GetUserMediaConstraints GetUserMediaConstraints
+#endif
// This test calls getUserMedia in sequence with different constraints.
-IN_PROC_BROWSER_TEST_P(WebRtcConstraintsBrowserTest, GetUserMediaConstraints) {
+IN_PROC_BROWSER_TEST_P(WebRtcConstraintsBrowserTest,
+ MAYBE_GetUserMediaConstraints) {
ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
diff --git a/chromium/content/browser/media/webrtc_identity_store.cc b/chromium/content/browser/media/webrtc_identity_store.cc
index 419cb96ab7c..2cf8fb13c8a 100644
--- a/chromium/content/browser/media/webrtc_identity_store.cc
+++ b/chromium/content/browser/media/webrtc_identity_store.cc
@@ -83,7 +83,7 @@ class WebRTCIdentityRequest {
common_name_(common_name) {}
void Cancel(WebRTCIdentityRequestHandle* handle) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (callbacks_.find(handle) == callbacks_.end())
return;
callbacks_.erase(handle);
@@ -104,7 +104,7 @@ class WebRTCIdentityRequest {
// WebRTCIdentityStoreBackend::FindIdentity, because it needs to live longer
// than that if the identity does not exist in DB.
void Post(const WebRTCIdentityRequestResult& result) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
for (CallbackMap::iterator it = callbacks_.begin(); it != callbacks_.end();
++it)
it->second.Run(result.error, result.certificate, result.private_key);
@@ -136,7 +136,7 @@ class WebRTCIdentityRequestHandle {
// Cancel the request. Does nothing if the request finished or was already
// cancelled.
void Cancel() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!request_)
return;
@@ -149,7 +149,7 @@ class WebRTCIdentityRequestHandle {
}
void OnRequestStarted(WebRTCIdentityRequest* request) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(request);
request_ = request;
}
@@ -157,7 +157,7 @@ class WebRTCIdentityRequestHandle {
void OnRequestComplete(int error,
const std::string& certificate,
const std::string& private_key) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(request_);
request_ = NULL;
base::ResetAndReturn(&callback_).Run(error, certificate, private_key);
@@ -184,7 +184,7 @@ base::Closure WebRTCIdentityStore::RequestIdentity(
const std::string& identity_name,
const std::string& common_name,
const CompletionCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
WebRTCIdentityRequest* request =
FindRequest(origin, identity_name, common_name);
// If there is no identical request in flight, create a new one, queue it,
@@ -220,20 +220,20 @@ base::Closure WebRTCIdentityStore::RequestIdentity(
void WebRTCIdentityStore::DeleteBetween(base::Time delete_begin,
base::Time delete_end,
const base::Closure& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
backend_->DeleteBetween(delete_begin, delete_end, callback);
}
void WebRTCIdentityStore::SetValidityPeriodForTesting(
base::TimeDelta validity_period) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
validity_period_ = validity_period;
backend_->SetValidityPeriodForTesting(validity_period);
}
void WebRTCIdentityStore::SetTaskRunnerForTesting(
const scoped_refptr<base::TaskRunner>& task_runner) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
task_runner_ = task_runner;
}
@@ -241,7 +241,7 @@ void WebRTCIdentityStore::BackendFindCallback(WebRTCIdentityRequest* request,
int error,
const std::string& certificate,
const std::string& private_key) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (error == net::OK) {
DVLOG(2) << "Identity found in DB.";
WebRTCIdentityRequestResult result(error, certificate, private_key);
@@ -270,7 +270,7 @@ void WebRTCIdentityStore::BackendFindCallback(WebRTCIdentityRequest* request,
void WebRTCIdentityStore::GenerateIdentityCallback(
WebRTCIdentityRequest* request,
WebRTCIdentityRequestResult* result) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (result->error == net::OK) {
DVLOG(2) << "New identity generated and added to the backend.";
backend_->AddIdentity(request->origin_,
@@ -285,7 +285,7 @@ void WebRTCIdentityStore::GenerateIdentityCallback(
void WebRTCIdentityStore::PostRequestResult(
WebRTCIdentityRequest* request,
const WebRTCIdentityRequestResult& result) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
// Removes the in flight request from the queue.
for (size_t i = 0; i < in_flight_requests_.size(); ++i) {
if (in_flight_requests_[i] == request) {
diff --git a/chromium/content/browser/media/webrtc_identity_store.h b/chromium/content/browser/media/webrtc_identity_store.h
index 6bf10fe61a2..dff44552d90 100644
--- a/chromium/content/browser/media/webrtc_identity_store.h
+++ b/chromium/content/browser/media/webrtc_identity_store.h
@@ -81,7 +81,7 @@ class CONTENT_EXPORT WebRTCIdentityStore
private:
friend class base::RefCountedThreadSafe<WebRTCIdentityStore>;
- friend class WebRTCIdentityStoreTest;
+ friend class WebRtcIdentityStoreTest;
void SetValidityPeriodForTesting(base::TimeDelta validity_period);
void SetTaskRunnerForTesting(
diff --git a/chromium/content/browser/media/webrtc_identity_store_backend.cc b/chromium/content/browser/media/webrtc_identity_store_backend.cc
index f6ecbad5c20..59ee8167e07 100644
--- a/chromium/content/browser/media/webrtc_identity_store_backend.cc
+++ b/chromium/content/browser/media/webrtc_identity_store_backend.cc
@@ -10,7 +10,6 @@
#include "base/strings/string_util.h"
#include "content/public/browser/browser_thread.h"
#include "net/base/net_errors.h"
-#include "sql/error_delegate_util.h"
#include "sql/statement.h"
#include "sql/transaction.h"
#include "storage/browser/quota/special_storage_policy.h"
@@ -129,7 +128,7 @@ class WebRTCIdentityStoreBackend::SqlLiteStorage
void DeleteBetween(base::Time delete_begin, base::Time delete_end);
void SetValidityPeriodForTesting(base::TimeDelta validity_period) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
+ DCHECK_CURRENTLY_ON(BrowserThread::DB);
DCHECK(!db_.get());
validity_period_ = validity_period;
}
@@ -191,7 +190,7 @@ bool WebRTCIdentityStoreBackend::FindIdentity(
const std::string& identity_name,
const std::string& common_name,
const FindIdentityCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (state_ == CLOSED)
return false;
@@ -252,7 +251,7 @@ void WebRTCIdentityStoreBackend::AddIdentity(const GURL& origin,
const std::string& common_name,
const std::string& certificate,
const std::string& private_key) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (state_ == CLOSED)
return;
@@ -304,7 +303,7 @@ void WebRTCIdentityStoreBackend::Close() {
void WebRTCIdentityStoreBackend::DeleteBetween(base::Time delete_begin,
base::Time delete_end,
const base::Closure& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (state_ == CLOSED)
return;
@@ -329,7 +328,7 @@ void WebRTCIdentityStoreBackend::DeleteBetween(base::Time delete_begin,
void WebRTCIdentityStoreBackend::SetValidityPeriodForTesting(
base::TimeDelta validity_period) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
validity_period_ = validity_period;
BrowserThread::PostTask(
BrowserThread::DB,
@@ -342,7 +341,7 @@ void WebRTCIdentityStoreBackend::SetValidityPeriodForTesting(
WebRTCIdentityStoreBackend::~WebRTCIdentityStoreBackend() {}
void WebRTCIdentityStoreBackend::OnLoaded(scoped_ptr<IdentityMap> out_map) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (state_ != LOADING)
return;
@@ -367,7 +366,7 @@ void WebRTCIdentityStoreBackend::OnLoaded(scoped_ptr<IdentityMap> out_map) {
//
void WebRTCIdentityStoreBackend::SqlLiteStorage::Load(IdentityMap* out_map) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
+ DCHECK_CURRENTLY_ON(BrowserThread::DB);
DCHECK(!db_.get());
// Ensure the parent directory for storing certs is created before reading
@@ -421,7 +420,7 @@ void WebRTCIdentityStoreBackend::SqlLiteStorage::Load(IdentityMap* out_map) {
}
void WebRTCIdentityStoreBackend::SqlLiteStorage::Close() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
+ DCHECK_CURRENTLY_ON(BrowserThread::DB);
Commit();
db_.reset();
}
@@ -430,7 +429,7 @@ void WebRTCIdentityStoreBackend::SqlLiteStorage::AddIdentity(
const GURL& origin,
const std::string& identity_name,
const Identity& identity) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
+ DCHECK_CURRENTLY_ON(BrowserThread::DB);
if (!db_.get())
return;
@@ -447,7 +446,7 @@ void WebRTCIdentityStoreBackend::SqlLiteStorage::DeleteIdentity(
const GURL& origin,
const std::string& identity_name,
const Identity& identity) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
+ DCHECK_CURRENTLY_ON(BrowserThread::DB);
if (!db_.get())
return;
BatchOperation(DELETE_IDENTITY, origin, identity_name, identity);
@@ -456,7 +455,7 @@ void WebRTCIdentityStoreBackend::SqlLiteStorage::DeleteIdentity(
void WebRTCIdentityStoreBackend::SqlLiteStorage::DeleteBetween(
base::Time delete_begin,
base::Time delete_end) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
+ DCHECK_CURRENTLY_ON(BrowserThread::DB);
if (!db_.get())
return;
@@ -490,7 +489,7 @@ void WebRTCIdentityStoreBackend::SqlLiteStorage::DeleteBetween(
void WebRTCIdentityStoreBackend::SqlLiteStorage::OnDatabaseError(
int error,
sql::Statement* stmt) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
+ DCHECK_CURRENTLY_ON(BrowserThread::DB);
db_->RazeAndClose();
// It's not safe to reset |db_| here.
@@ -501,7 +500,7 @@ void WebRTCIdentityStoreBackend::SqlLiteStorage::BatchOperation(
const GURL& origin,
const std::string& identity_name,
const Identity& identity) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
+ DCHECK_CURRENTLY_ON(BrowserThread::DB);
// Commit every 30 seconds.
static const base::TimeDelta kCommitInterval(
base::TimeDelta::FromSeconds(30));
@@ -529,7 +528,7 @@ void WebRTCIdentityStoreBackend::SqlLiteStorage::BatchOperation(
}
void WebRTCIdentityStoreBackend::SqlLiteStorage::Commit() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
+ DCHECK_CURRENTLY_ON(BrowserThread::DB);
// Maybe an old timer fired or we are already Close()'ed.
if (!db_.get() || pending_operations_.empty())
return;
diff --git a/chromium/content/browser/media/webrtc_identity_store_backend.h b/chromium/content/browser/media/webrtc_identity_store_backend.h
index 81919746741..57c16ab39b5 100644
--- a/chromium/content/browser/media/webrtc_identity_store_backend.h
+++ b/chromium/content/browser/media/webrtc_identity_store_backend.h
@@ -7,10 +7,12 @@
#include <map>
#include <string>
+#include <vector>
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
#include "base/time/time.h"
-#include "sql/connection.h"
-#include "sql/meta_table.h"
class GURL;
diff --git a/chromium/content/browser/media/webrtc_identity_store_unittest.cc b/chromium/content/browser/media/webrtc_identity_store_unittest.cc
index 9078f1a19ac..1395e6f4402 100644
--- a/chromium/content/browser/media/webrtc_identity_store_unittest.cc
+++ b/chromium/content/browser/media/webrtc_identity_store_unittest.cc
@@ -37,19 +37,19 @@ static void OnRequestCompleted(bool* completed,
*out_key = private_key;
}
-class WebRTCIdentityStoreTest : public testing::Test {
+class WebRtcIdentityStoreTest : public testing::Test {
public:
- WebRTCIdentityStoreTest()
+ WebRtcIdentityStoreTest()
: browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP |
TestBrowserThreadBundle::REAL_DB_THREAD),
pool_owner_(
- new base::SequencedWorkerPoolOwner(3, "WebRTCIdentityStoreTest")),
+ new base::SequencedWorkerPoolOwner(3, "WebRtcIdentityStoreTest")),
webrtc_identity_store_(
new WebRTCIdentityStore(base::FilePath(), NULL)) {
webrtc_identity_store_->SetTaskRunnerForTesting(pool_owner_->pool());
}
- ~WebRTCIdentityStoreTest() override { pool_owner_->pool()->Shutdown(); }
+ ~WebRtcIdentityStoreTest() override { pool_owner_->pool()->Shutdown(); }
void SetValidityPeriod(base::TimeDelta validity_period) {
webrtc_identity_store_->SetValidityPeriodForTesting(validity_period);
@@ -89,7 +89,7 @@ class WebRTCIdentityStoreTest : public testing::Test {
scoped_refptr<WebRTCIdentityStore> webrtc_identity_store_;
};
-TEST_F(WebRTCIdentityStoreTest, RequestIdentity) {
+TEST_F(WebRtcIdentityStoreTest, RequestIdentity) {
bool completed = false;
std::string dummy;
base::Closure cancel_callback =
@@ -102,7 +102,7 @@ TEST_F(WebRTCIdentityStoreTest, RequestIdentity) {
EXPECT_TRUE(completed);
}
-TEST_F(WebRTCIdentityStoreTest, CancelRequest) {
+TEST_F(WebRtcIdentityStoreTest, CancelRequest) {
bool completed = false;
std::string dummy;
base::Closure cancel_callback = webrtc_identity_store_->RequestIdentity(
@@ -117,7 +117,7 @@ TEST_F(WebRTCIdentityStoreTest, CancelRequest) {
EXPECT_FALSE(completed);
}
-TEST_F(WebRTCIdentityStoreTest, ConcurrentUniqueRequests) {
+TEST_F(WebRtcIdentityStoreTest, ConcurrentUniqueRequests) {
bool completed_1 = false;
bool completed_2 = false;
std::string dummy;
@@ -140,7 +140,7 @@ TEST_F(WebRTCIdentityStoreTest, ConcurrentUniqueRequests) {
EXPECT_TRUE(completed_2);
}
-TEST_F(WebRTCIdentityStoreTest, DifferentCommonNameReturnNewIdentity) {
+TEST_F(WebRtcIdentityStoreTest, DifferentCommonNameReturnNewIdentity) {
bool completed_1 = false;
bool completed_2 = false;
std::string cert_1, cert_2, key_1, key_2;
@@ -167,7 +167,7 @@ TEST_F(WebRTCIdentityStoreTest, DifferentCommonNameReturnNewIdentity) {
EXPECT_NE(key_1, key_2);
}
-TEST_F(WebRTCIdentityStoreTest, SerialIdenticalRequests) {
+TEST_F(WebRtcIdentityStoreTest, SerialIdenticalRequests) {
bool completed_1 = false;
bool completed_2 = false;
std::string cert_1, cert_2, key_1, key_2;
@@ -194,7 +194,7 @@ TEST_F(WebRTCIdentityStoreTest, SerialIdenticalRequests) {
EXPECT_EQ(key_1, key_2);
}
-TEST_F(WebRTCIdentityStoreTest, ConcurrentIdenticalRequestsJoined) {
+TEST_F(WebRtcIdentityStoreTest, ConcurrentIdenticalRequestsJoined) {
bool completed_1 = false;
bool completed_2 = false;
std::string cert_1, cert_2, key_1, key_2;
@@ -220,7 +220,7 @@ TEST_F(WebRTCIdentityStoreTest, ConcurrentIdenticalRequestsJoined) {
EXPECT_EQ(key_1, key_2);
}
-TEST_F(WebRTCIdentityStoreTest, CancelOneOfIdenticalRequests) {
+TEST_F(WebRtcIdentityStoreTest, CancelOneOfIdenticalRequests) {
bool completed_1 = false;
bool completed_2 = false;
std::string cert_1, cert_2, key_1, key_2;
@@ -246,7 +246,7 @@ TEST_F(WebRTCIdentityStoreTest, CancelOneOfIdenticalRequests) {
EXPECT_TRUE(completed_2);
}
-TEST_F(WebRTCIdentityStoreTest, DeleteDataAndGenerateNewIdentity) {
+TEST_F(WebRtcIdentityStoreTest, DeleteDataAndGenerateNewIdentity) {
bool completed_1 = false;
bool completed_2 = false;
std::string cert_1, cert_2, key_1, key_2;
@@ -279,7 +279,7 @@ TEST_F(WebRTCIdentityStoreTest, DeleteDataAndGenerateNewIdentity) {
EXPECT_NE(key_1, key_2);
}
-TEST_F(WebRTCIdentityStoreTest, ExpiredIdentityDeleted) {
+TEST_F(WebRtcIdentityStoreTest, ExpiredIdentityDeleted) {
// The identities will expire immediately after creation.
SetValidityPeriod(base::TimeDelta::FromMilliseconds(0));
@@ -309,7 +309,7 @@ TEST_F(WebRTCIdentityStoreTest, ExpiredIdentityDeleted) {
EXPECT_NE(key_1, key_2);
}
-TEST_F(WebRTCIdentityStoreTest, IdentityPersistentAcrossRestart) {
+TEST_F(WebRtcIdentityStoreTest, IdentityPersistentAcrossRestart) {
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
Restart(temp_dir.path());
@@ -343,7 +343,7 @@ TEST_F(WebRTCIdentityStoreTest, IdentityPersistentAcrossRestart) {
EXPECT_EQ(key_1, key_2);
}
-TEST_F(WebRTCIdentityStoreTest, HandleDBErrors) {
+TEST_F(WebRtcIdentityStoreTest, HandleDBErrors) {
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
Restart(temp_dir.path());
diff --git a/chromium/content/browser/media/webrtc_internals.cc b/chromium/content/browser/media/webrtc_internals.cc
index 56078a109ef..952633c2d36 100644
--- a/chromium/content/browser/media/webrtc_internals.cc
+++ b/chromium/content/browser/media/webrtc_internals.cc
@@ -73,7 +73,7 @@ void WebRTCInternals::OnAddPeerConnection(int render_process_id,
const string& url,
const string& rtc_configuration,
const string& constraints) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
base::DictionaryValue* dict = new base::DictionaryValue();
if (!dict)
@@ -93,7 +93,7 @@ void WebRTCInternals::OnAddPeerConnection(int render_process_id,
}
void WebRTCInternals::OnRemovePeerConnection(ProcessId pid, int lid) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
for (size_t i = 0; i < peer_connection_data_.GetSize(); ++i) {
base::DictionaryValue* dict = NULL;
peer_connection_data_.GetDictionary(i, &dict);
@@ -121,7 +121,7 @@ void WebRTCInternals::OnRemovePeerConnection(ProcessId pid, int lid) {
void WebRTCInternals::OnUpdatePeerConnection(
ProcessId pid, int lid, const string& type, const string& value) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
for (size_t i = 0; i < peer_connection_data_.GetSize(); ++i) {
base::DictionaryValue* record = NULL;
@@ -187,7 +187,7 @@ void WebRTCInternals::OnGetUserMedia(int rid,
bool video,
const std::string& audio_constraints,
const std::string& video_constraints) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
base::DictionaryValue* dict = new base::DictionaryValue();
dict->SetInteger("rid", rid);
@@ -205,12 +205,12 @@ void WebRTCInternals::OnGetUserMedia(int rid,
}
void WebRTCInternals::AddObserver(WebRTCInternalsUIObserver *observer) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
observers_.AddObserver(observer);
}
void WebRTCInternals::RemoveObserver(WebRTCInternalsUIObserver *observer) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
observers_.RemoveObserver(observer);
// Disables the AEC recording if it is enabled and the last webrtc-internals
@@ -220,7 +220,7 @@ void WebRTCInternals::RemoveObserver(WebRTCInternalsUIObserver *observer) {
}
void WebRTCInternals::UpdateObserver(WebRTCInternalsUIObserver* observer) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (peer_connection_data_.GetSize() > 0)
observer->OnUpdate("updateAllPeerConnections", &peer_connection_data_);
@@ -266,7 +266,7 @@ void WebRTCInternals::DisableAecDump() {
}
void WebRTCInternals::ResetForTesting() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
observers_.Clear();
peer_connection_data_.Clear();
CreateOrReleasePowerSaveBlocker();
@@ -285,7 +285,7 @@ void WebRTCInternals::SendUpdate(const string& command, base::Value* value) {
void WebRTCInternals::Observe(int type,
const NotificationSource& source,
const NotificationDetails& details) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK_EQ(type, NOTIFICATION_RENDERER_PROCESS_TERMINATED);
OnRendererExit(Source<RenderProcessHost>(source)->GetID());
}
@@ -306,7 +306,7 @@ void WebRTCInternals::FileSelectionCanceled(void* params) {
}
void WebRTCInternals::OnRendererExit(int render_process_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
// Iterates from the end of the list to remove the PeerConnections created
// by the exitting renderer.
@@ -368,7 +368,7 @@ void WebRTCInternals::EnableAecDumpOnAllRenderProcessHosts() {
#endif
void WebRTCInternals::CreateOrReleasePowerSaveBlocker() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (peer_connection_data_.empty() && power_save_blocker_) {
DVLOG(1) << ("Releasing the block on application suspension since no "
@@ -377,9 +377,11 @@ void WebRTCInternals::CreateOrReleasePowerSaveBlocker() {
} 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();
+ power_save_blocker_ =
+ content::PowerSaveBlocker::Create(
+ PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
+ PowerSaveBlocker::kReasonOther,
+ "WebRTC has active PeerConnections").Pass();
}
}
diff --git a/chromium/content/browser/media/webrtc_internals.h b/chromium/content/browser/media/webrtc_internals.h
index db8693ab3eb..754bf20ff9c 100644
--- a/chromium/content/browser/media/webrtc_internals.h
+++ b/chromium/content/browser/media/webrtc_internals.h
@@ -107,7 +107,7 @@ class CONTENT_EXPORT WebRTCInternals : public NotificationObserver,
FRIEND_TEST_ALL_PREFIXES(WebRtcAecDumpBrowserTest,
CallWithAecDumpEnabledThenDisabled);
FRIEND_TEST_ALL_PREFIXES(WebRtcAecDumpBrowserTest, TwoCallsWithAecDump);
- FRIEND_TEST_ALL_PREFIXES(WebRTCInternalsTest,
+ FRIEND_TEST_ALL_PREFIXES(WebRtcInternalsTest,
AecRecordingFileSelectionCanceled);
WebRTCInternals();
diff --git a/chromium/content/browser/media/webrtc_internals_browsertest.cc b/chromium/content/browser/media/webrtc_internals_browsertest.cc
index e9f1e611407..05c42ccae7b 100644
--- a/chromium/content/browser/media/webrtc_internals_browsertest.cc
+++ b/chromium/content/browser/media/webrtc_internals_browsertest.cc
@@ -153,9 +153,9 @@ class MAYBE_WebRtcInternalsBrowserTest: public ContentBrowserTest {
void SetUpOnMainThread() override {
// Assume this is set by the content test launcher.
- ASSERT_TRUE(CommandLine::ForCurrentProcess()->HasSwitch(
+ ASSERT_TRUE(base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kUseFakeUIForMediaStream));
- ASSERT_TRUE(CommandLine::ForCurrentProcess()->HasSwitch(
+ ASSERT_TRUE(base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kUseFakeDeviceForMediaStream));
}
diff --git a/chromium/content/browser/media/webrtc_internals_message_handler.cc b/chromium/content/browser/media/webrtc_internals_message_handler.cc
index bffd5098bfa..8bfae991c06 100644
--- a/chromium/content/browser/media/webrtc_internals_message_handler.cc
+++ b/chromium/content/browser/media/webrtc_internals_message_handler.cc
@@ -73,7 +73,7 @@ void WebRTCInternalsMessageHandler::OnDOMLoadDone(
void WebRTCInternalsMessageHandler::OnUpdate(const std::string& command,
const base::Value* args) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
std::vector<const base::Value*> args_vector;
if (args)
args_vector.push_back(args);
diff --git a/chromium/content/browser/media/webrtc_internals_unittest.cc b/chromium/content/browser/media/webrtc_internals_unittest.cc
index afe3587db5e..17d5ec4c13f 100644
--- a/chromium/content/browser/media/webrtc_internals_unittest.cc
+++ b/chromium/content/browser/media/webrtc_internals_unittest.cc
@@ -18,7 +18,7 @@ static const std::string kContraints = "c";
static const std::string kRtcConfiguration = "r";
static const std::string kUrl = "u";
-class MockWebRTCInternalsProxy : public WebRTCInternalsUIObserver {
+class MockWebRtcInternalsProxy : public WebRTCInternalsUIObserver {
public:
void OnUpdate(const std::string& command, const base::Value* value) override {
command_ = command;
@@ -39,9 +39,9 @@ class MockWebRTCInternalsProxy : public WebRTCInternalsUIObserver {
scoped_ptr<base::Value> value_;
};
-class WebRTCInternalsTest : public testing::Test {
+class WebRtcInternalsTest : public testing::Test {
public:
- WebRTCInternalsTest() : io_thread_(BrowserThread::UI, &io_loop_) {
+ WebRtcInternalsTest() : io_thread_(BrowserThread::UI, &io_loop_) {
WebRTCInternals::GetInstance()->ResetForTesting();
}
@@ -92,9 +92,9 @@ class WebRTCInternalsTest : public testing::Test {
} // namespace
-TEST_F(WebRTCInternalsTest, AddRemoveObserver) {
- scoped_ptr<MockWebRTCInternalsProxy> observer(
- new MockWebRTCInternalsProxy());
+TEST_F(WebRtcInternalsTest, AddRemoveObserver) {
+ scoped_ptr<MockWebRtcInternalsProxy> observer(
+ new MockWebRtcInternalsProxy());
WebRTCInternals::GetInstance()->AddObserver(observer.get());
WebRTCInternals::GetInstance()->RemoveObserver(observer.get());
WebRTCInternals::GetInstance()->OnAddPeerConnection(
@@ -104,9 +104,9 @@ TEST_F(WebRTCInternalsTest, AddRemoveObserver) {
WebRTCInternals::GetInstance()->OnRemovePeerConnection(3, 4);
}
-TEST_F(WebRTCInternalsTest, SendAddPeerConnectionUpdate) {
- scoped_ptr<MockWebRTCInternalsProxy> observer(
- new MockWebRTCInternalsProxy());
+TEST_F(WebRtcInternalsTest, SendAddPeerConnectionUpdate) {
+ scoped_ptr<MockWebRtcInternalsProxy> observer(
+ new MockWebRtcInternalsProxy());
WebRTCInternals::GetInstance()->AddObserver(observer.get());
WebRTCInternals::GetInstance()->OnAddPeerConnection(
0, 1, 2, kUrl, kRtcConfiguration, kContraints);
@@ -125,9 +125,9 @@ TEST_F(WebRTCInternalsTest, SendAddPeerConnectionUpdate) {
WebRTCInternals::GetInstance()->OnRemovePeerConnection(1, 2);
}
-TEST_F(WebRTCInternalsTest, SendRemovePeerConnectionUpdate) {
- scoped_ptr<MockWebRTCInternalsProxy> observer(
- new MockWebRTCInternalsProxy());
+TEST_F(WebRtcInternalsTest, SendRemovePeerConnectionUpdate) {
+ scoped_ptr<MockWebRtcInternalsProxy> observer(
+ new MockWebRtcInternalsProxy());
WebRTCInternals::GetInstance()->AddObserver(observer.get());
WebRTCInternals::GetInstance()->OnAddPeerConnection(
0, 1, 2, kUrl, kRtcConfiguration, kContraints);
@@ -143,9 +143,9 @@ TEST_F(WebRTCInternalsTest, SendRemovePeerConnectionUpdate) {
WebRTCInternals::GetInstance()->RemoveObserver(observer.get());
}
-TEST_F(WebRTCInternalsTest, SendUpdatePeerConnectionUpdate) {
- scoped_ptr<MockWebRTCInternalsProxy> observer(
- new MockWebRTCInternalsProxy());
+TEST_F(WebRtcInternalsTest, SendUpdatePeerConnectionUpdate) {
+ scoped_ptr<MockWebRtcInternalsProxy> observer(
+ new MockWebRtcInternalsProxy());
WebRTCInternals::GetInstance()->AddObserver(observer.get());
WebRTCInternals::GetInstance()->OnAddPeerConnection(
0, 1, 2, kUrl, kRtcConfiguration, kContraints);
@@ -173,8 +173,8 @@ TEST_F(WebRTCInternalsTest, SendUpdatePeerConnectionUpdate) {
WebRTCInternals::GetInstance()->RemoveObserver(observer.get());
}
-TEST_F(WebRTCInternalsTest, AddGetUserMedia) {
- scoped_ptr<MockWebRTCInternalsProxy> observer(new MockWebRTCInternalsProxy());
+TEST_F(WebRtcInternalsTest, AddGetUserMedia) {
+ scoped_ptr<MockWebRtcInternalsProxy> observer(new MockWebRtcInternalsProxy());
// Add one observer before "getUserMedia".
WebRTCInternals::GetInstance()->AddObserver(observer.get());
@@ -193,7 +193,7 @@ TEST_F(WebRTCInternalsTest, AddGetUserMedia) {
WebRTCInternals::GetInstance()->RemoveObserver(observer.get());
}
-TEST_F(WebRTCInternalsTest, SendAllUpdateWithGetUserMedia) {
+TEST_F(WebRtcInternalsTest, SendAllUpdateWithGetUserMedia) {
const int rid = 1;
const int pid = 2;
const std::string audio_constraint = "aaa";
@@ -201,7 +201,7 @@ TEST_F(WebRTCInternalsTest, SendAllUpdateWithGetUserMedia) {
WebRTCInternals::GetInstance()->OnGetUserMedia(
rid, pid, kUrl, true, true, audio_constraint, video_constraint);
- scoped_ptr<MockWebRTCInternalsProxy> observer(new MockWebRTCInternalsProxy());
+ scoped_ptr<MockWebRtcInternalsProxy> observer(new MockWebRtcInternalsProxy());
// Add one observer after "getUserMedia".
WebRTCInternals::GetInstance()->AddObserver(observer.get());
WebRTCInternals::GetInstance()->UpdateObserver(observer.get());
@@ -213,7 +213,7 @@ TEST_F(WebRTCInternalsTest, SendAllUpdateWithGetUserMedia) {
WebRTCInternals::GetInstance()->RemoveObserver(observer.get());
}
-TEST_F(WebRTCInternalsTest, SendAllUpdatesWithPeerConnectionUpdate) {
+TEST_F(WebRtcInternalsTest, SendAllUpdatesWithPeerConnectionUpdate) {
const int rid = 0, pid = 1, lid = 2;
const std::string update_type = "fakeType";
const std::string update_value = "fakeValue";
@@ -223,7 +223,7 @@ TEST_F(WebRTCInternalsTest, SendAllUpdatesWithPeerConnectionUpdate) {
WebRTCInternals::GetInstance()->OnUpdatePeerConnection(
pid, lid, update_type, update_value);
- scoped_ptr<MockWebRTCInternalsProxy> observer(new MockWebRTCInternalsProxy());
+ scoped_ptr<MockWebRtcInternalsProxy> observer(new MockWebRtcInternalsProxy());
WebRTCInternals::GetInstance()->AddObserver(observer.get());
WebRTCInternals::GetInstance()->UpdateObserver(observer.get());
@@ -256,9 +256,9 @@ TEST_F(WebRTCInternalsTest, SendAllUpdatesWithPeerConnectionUpdate) {
EXPECT_FALSE(time.empty());
}
-TEST_F(WebRTCInternalsTest, OnAddStats) {
+TEST_F(WebRtcInternalsTest, OnAddStats) {
const int rid = 0, pid = 1, lid = 2;
- scoped_ptr<MockWebRTCInternalsProxy> observer(new MockWebRTCInternalsProxy());
+ scoped_ptr<MockWebRtcInternalsProxy> observer(new MockWebRtcInternalsProxy());
WebRTCInternals::GetInstance()->AddObserver(observer.get());
WebRTCInternals::GetInstance()->OnAddPeerConnection(
rid, pid, lid, kUrl, kRtcConfiguration, kContraints);
@@ -277,8 +277,8 @@ TEST_F(WebRTCInternalsTest, OnAddStats) {
VerifyList(dict, "reports", list);
}
-TEST_F(WebRTCInternalsTest, AecRecordingFileSelectionCanceled) {
- scoped_ptr<MockWebRTCInternalsProxy> observer(new MockWebRTCInternalsProxy());
+TEST_F(WebRtcInternalsTest, AecRecordingFileSelectionCanceled) {
+ scoped_ptr<MockWebRtcInternalsProxy> observer(new MockWebRtcInternalsProxy());
WebRTCInternals::GetInstance()->AddObserver(observer.get());
WebRTCInternals::GetInstance()->FileSelectionCanceled(NULL);
EXPECT_EQ("aecRecordingFileSelectionCancelled", observer->command());
diff --git a/chromium/content/browser/media/webrtc_webcam_browsertest.cc b/chromium/content/browser/media/webrtc_webcam_browsertest.cc
index 1be6ee51045..3c65ed9f784 100644
--- a/chromium/content/browser/media/webrtc_webcam_browsertest.cc
+++ b/chromium/content/browser/media/webrtc_webcam_browsertest.cc
@@ -28,7 +28,7 @@ bool IsUseFakeDeviceForMediaStream(const base::CommandLine::StringType& arg) {
}
void RemoveFakeDeviceFromCommandLine(base::CommandLine* command_line) {
- CommandLine::StringVector argv = command_line->argv();
+ base::CommandLine::StringVector argv = command_line->argv();
argv.erase(std::remove_if(argv.begin(), argv.end(),
IsUseFakeDeviceForMediaStream),
argv.end());
diff --git a/chromium/content/browser/message_port_message_filter.cc b/chromium/content/browser/message_port_message_filter.cc
index ab3174bc8cc..5ff0319d6ea 100644
--- a/chromium/content/browser/message_port_message_filter.cc
+++ b/chromium/content/browser/message_port_message_filter.cc
@@ -5,6 +5,7 @@
#include "content/browser/message_port_message_filter.h"
#include "content/browser/message_port_service.h"
+#include "content/common/frame_messages.h"
#include "content/common/message_port_messages.h"
namespace content {
@@ -19,7 +20,7 @@ MessagePortMessageFilter::~MessagePortMessageFilter() {
}
void MessagePortMessageFilter::OnChannelClosing() {
- MessagePortService::GetInstance()->OnMessagePortMessageFilterClosing(this);
+ MessagePortService::GetInstance()->OnMessagePortDelegateClosing(this);
}
bool MessagePortMessageFilter::OnMessageReceived(const IPC::Message& message) {
@@ -42,6 +43,9 @@ bool MessagePortMessageFilter::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_FORWARD(MessagePortHostMsg_SendQueuedMessages,
MessagePortService::GetInstance(),
MessagePortService::SendQueuedMessages)
+ IPC_MESSAGE_FORWARD(MessagePortHostMsg_ReleaseMessages,
+ MessagePortService::GetInstance(),
+ MessagePortService::ReleaseMessages)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
@@ -56,22 +60,48 @@ int MessagePortMessageFilter::GetNextRoutingID() {
return next_routing_id_.Run();
}
+void MessagePortMessageFilter::SendMessage(
+ int route_id,
+ const MessagePortMessage& message,
+ const std::vector<TransferredMessagePort>& sent_message_ports) {
+ // Generate new routing ids for all ports that were sent around. This avoids
+ // waiting for the created ports to send a sync message back to get routing
+ // ids.
+ std::vector<int> new_routing_ids;
+ UpdateMessagePortsWithNewRoutes(sent_message_ports, &new_routing_ids);
+ Send(new MessagePortMsg_Message(route_id, message, sent_message_ports,
+ new_routing_ids));
+}
+
+void MessagePortMessageFilter::SendMessagesAreQueued(int route_id) {
+ Send(new MessagePortMsg_MessagesQueued(route_id));
+}
+
void MessagePortMessageFilter::UpdateMessagePortsWithNewRoutes(
- const std::vector<int>& message_port_ids,
+ const std::vector<TransferredMessagePort>& message_ports,
std::vector<int>* new_routing_ids) {
DCHECK(new_routing_ids);
new_routing_ids->clear();
- new_routing_ids->resize(message_port_ids.size());
+ new_routing_ids->resize(message_ports.size());
- for (size_t i = 0; i < message_port_ids.size(); ++i) {
+ for (size_t i = 0; i < message_ports.size(); ++i) {
(*new_routing_ids)[i] = GetNextRoutingID();
MessagePortService::GetInstance()->UpdateMessagePort(
- message_port_ids[i],
+ message_ports[i].id,
this,
(*new_routing_ids)[i]);
}
}
+void MessagePortMessageFilter::RouteMessageEventWithMessagePorts(
+ int routing_id,
+ const FrameMsg_PostMessage_Params& params) {
+ FrameMsg_PostMessage_Params new_params(params);
+ UpdateMessagePortsWithNewRoutes(params.message_ports,
+ &new_params.new_routing_ids);
+ Send(new FrameMsg_PostMessageEvent(routing_id, new_params));
+}
+
void MessagePortMessageFilter::OnCreateMessagePort(int *route_id,
int* message_port_id) {
*route_id = next_routing_id_.Run();
diff --git a/chromium/content/browser/message_port_message_filter.h b/chromium/content/browser/message_port_message_filter.h
index 21bfbb24e17..be6bfde7095 100644
--- a/chromium/content/browser/message_port_message_filter.h
+++ b/chromium/content/browser/message_port_message_filter.h
@@ -8,12 +8,23 @@
#include "base/callback.h"
#include "content/common/content_export.h"
#include "content/public/browser/browser_message_filter.h"
+#include "content/public/browser/message_port_delegate.h"
+
+// Windows headers will redefine SendMessage.
+#ifdef SendMessage
+#undef SendMessage
+#endif
+
+struct FrameMsg_PostMessage_Params;
namespace content {
+struct TransferredMessagePort;
// Filter for MessagePort related IPC messages (creating and destroying a
// MessagePort, sending a message via a MessagePort etc).
-class CONTENT_EXPORT MessagePortMessageFilter : public BrowserMessageFilter {
+class CONTENT_EXPORT MessagePortMessageFilter
+ : public MessagePortDelegate,
+ public BrowserMessageFilter {
public:
typedef base::Callback<int(void)> NextRoutingIDCallback;
@@ -28,12 +39,23 @@ class CONTENT_EXPORT MessagePortMessageFilter : public BrowserMessageFilter {
int GetNextRoutingID();
- // Updates message ports registered for |message_port_ids| and returns
+ // MessagePortDelegate implementation.
+ void SendMessage(
+ int route_id,
+ const MessagePortMessage& message,
+ const std::vector<TransferredMessagePort>& sent_message_ports) override;
+ void SendMessagesAreQueued(int route_id) override;
+
+ // Updates message ports registered for |message_ports| and returns
// new routing IDs for the updated ports via |new_routing_ids|.
void UpdateMessagePortsWithNewRoutes(
- const std::vector<int>& message_port_ids,
+ const std::vector<TransferredMessagePort>& message_ports,
std::vector<int>* new_routing_ids);
+ void RouteMessageEventWithMessagePorts(
+ int routing_id,
+ const FrameMsg_PostMessage_Params& params);
+
protected:
// This is protected, so we can define sub classes for testing.
~MessagePortMessageFilter() override;
@@ -54,4 +76,4 @@ class CONTENT_EXPORT MessagePortMessageFilter : public BrowserMessageFilter {
} // namespace content
-#endif // CONTENT_BROWSER_WORKER_MESSAGE_FILTER_H_
+#endif // CONTENT_BROWSER_MESSAGE_PORT_MESSAGE_FILTER_H_
diff --git a/chromium/content/browser/message_port_provider.cc b/chromium/content/browser/message_port_provider.cc
new file mode 100644
index 00000000000..ddd19adb874
--- /dev/null
+++ b/chromium/content/browser/message_port_provider.cc
@@ -0,0 +1,116 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/public/browser/message_port_provider.h"
+
+#include "base/basictypes.h"
+#include "content/browser/browser_thread_impl.h"
+#include "content/browser/message_port_message_filter.h"
+#include "content/browser/message_port_service.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/common/frame_messages.h"
+#include "content/public/browser/message_port_delegate.h"
+
+namespace content {
+
+// static
+void MessagePortProvider::PostMessageToFrame(
+ WebContents* web_contents,
+ const base::string16& source_origin,
+ const base::string16& target_origin,
+ const base::string16& data,
+ const std::vector<TransferredMessagePort>& ports) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ FrameMsg_PostMessage_Params params;
+ params.is_data_raw_string = true;
+ params.data = data;
+ // Blink requires a source frame to transfer ports. This is why a
+ // source routing id is set here. See WebDOMMessageEvent::initMessageEvent()
+ // TODO(alexmos, sgurun): Clean this up once crbug.com/473258 is fixed.
+ // Once message ports can work with a null source frame,
+ // source_view_routing_id can be removed, and this can just pass in
+ // MSG_ROUTING_NONE for the source frame.
+ params.source_view_routing_id = web_contents->GetRoutingID();
+ params.source_routing_id = MSG_ROUTING_NONE;
+ params.source_origin = source_origin;
+ params.target_origin = target_origin;
+ params.message_ports = ports;
+
+ RenderProcessHostImpl* rph =
+ static_cast<RenderProcessHostImpl*>(web_contents->GetRenderProcessHost());
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&MessagePortMessageFilter::RouteMessageEventWithMessagePorts,
+ rph->message_port_message_filter(),
+ web_contents->GetMainFrame()->GetRoutingID(), params));
+}
+
+// static
+void MessagePortProvider::CreateMessageChannel(MessagePortDelegate* delegate,
+ int* port1,
+ int* port2) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ *port1 = 0;
+ *port2 = 0;
+ MessagePortService* msp = MessagePortService::GetInstance();
+ msp->Create(MSG_ROUTING_NONE, delegate, port1);
+ msp->Create(MSG_ROUTING_NONE, delegate, port2);
+ // Update the routing number of the message ports to be equal to the message
+ // port numbers.
+ msp->UpdateMessagePort(*port1, delegate, *port1);
+ msp->UpdateMessagePort(*port2, delegate, *port2);
+ msp->Entangle(*port1, *port2);
+ msp->Entangle(*port2, *port1);
+}
+
+// static
+void MessagePortProvider::PostMessageToPort(
+ int sender_port_id,
+ const MessagePortMessage& message,
+ const std::vector<TransferredMessagePort>& sent_ports) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ MessagePortService* msp = MessagePortService::GetInstance();
+ msp->PostMessage(sender_port_id, message, sent_ports);
+}
+
+// static
+void MessagePortProvider::ClosePort(int message_port_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ MessagePortService* msp = MessagePortService::GetInstance();
+ msp->ClosePort(message_port_id);
+}
+
+// static
+void MessagePortProvider::HoldMessages(int message_port_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ MessagePortService* msp = MessagePortService::GetInstance();
+ msp->HoldMessages(message_port_id);
+}
+
+// static
+void MessagePortProvider::ReleaseMessages(int message_port_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ MessagePortService* msp = MessagePortService::GetInstance();
+ msp->ReleaseMessages(message_port_id);
+}
+
+// static
+void MessagePortProvider::OnMessagePortDelegateClosing(
+ MessagePortDelegate* delegate) {
+ MessagePortService::GetInstance()->OnMessagePortDelegateClosing(delegate);
+}
+
+// static
+void MessagePortProvider::UpdateMessagePort(int message_port_id,
+ MessagePortDelegate* delegate) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ MessagePortService::GetInstance()->UpdateMessagePort(message_port_id,
+ delegate,
+ message_port_id);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/message_port_provider_browsertest.cc b/chromium/content/browser/message_port_provider_browsertest.cc
new file mode 100644
index 00000000000..425e08fa954
--- /dev/null
+++ b/chromium/content/browser/message_port_provider_browsertest.cc
@@ -0,0 +1,145 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/synchronization/waitable_event.h"
+#include "content/browser/message_port_service.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/message_port_delegate.h"
+#include "content/public/browser/message_port_provider.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"
+
+namespace content {
+
+// This test verifies the functionality of the Message Port Provider API.
+
+// A mock class for testing message port provider.
+class MockMessagePortDelegate : public MessagePortDelegate {
+ public:
+ // A container to hold received messages
+ struct Message {
+ int route_id; // the routing id of the target port
+ MessagePortMessage data; // the message data
+ std::vector<TransferredMessagePort> sent_ports; // any transferred ports
+ };
+
+ typedef std::vector<Message> Messages;
+
+ MockMessagePortDelegate() { }
+ ~MockMessagePortDelegate() override { }
+
+ // MessagePortDelegate implementation
+ void SendMessage(
+ int route_id,
+ const MessagePortMessage& message,
+ const std::vector<TransferredMessagePort>& sent_message_ports) override {
+ Message m;
+ m.route_id = route_id;
+ m.data = message;
+ m.sent_ports = sent_message_ports;
+ messages_.push_back(m);
+ }
+
+ void SendMessagesAreQueued(int route_id) override { }
+
+ const Messages& getReceivedMessages() {
+ return messages_;
+ }
+ private:
+ Messages messages_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockMessagePortDelegate);
+};
+
+
+class MessagePortProviderBrowserTest : public ContentBrowserTest {
+};
+
+// Verify that messages can be posted to main frame.
+IN_PROC_BROWSER_TEST_F(MessagePortProviderBrowserTest, PostMessage) {
+ const std::string data =
+ "<!DOCTYPE html><html><body>"
+ " <script type=\"text/javascript\">"
+ " onmessage = function (e) { document.title = e.data; }"
+ " </script>"
+ "</body></html>";
+ const base::string16 target_origin(base::UTF8ToUTF16("http://baseurl"));
+ const GURL base_url(target_origin);
+ const GURL history_url;
+ // Load data. Blocks until it is done.
+ content::LoadDataWithBaseURL(shell(), history_url, data, base_url);
+ const base::string16 source_origin(base::UTF8ToUTF16("source"));
+ const base::string16 message(base::UTF8ToUTF16("success"));
+ const std::vector<TransferredMessagePort> ports;
+ content::TitleWatcher title_watcher(shell()->web_contents(), message);
+ MessagePortProvider::PostMessageToFrame(shell()->web_contents(),
+ source_origin,
+ target_origin,
+ message,
+ ports);
+ EXPECT_EQ(message, title_watcher.WaitAndGetTitle());
+}
+
+namespace {
+
+void VerifyCreateChannelOnIOThread(base::WaitableEvent* event) {
+
+ const base::char16 MESSAGE1[] = { 0x1000, 0 };
+ const base::char16 MESSAGE2[] = { 0x1001, 0 };
+
+ MockMessagePortDelegate delegate;
+ int port1;
+ int port2;
+
+ MessagePortProvider::CreateMessageChannel(&delegate, &port1, &port2);
+ MessagePortService* service = MessagePortService::GetInstance();
+ // Send a message to port1 transferring no ports.
+ std::vector<TransferredMessagePort> sent_ports;
+ service->PostMessage(port1, MessagePortMessage(base::string16(MESSAGE1)),
+ sent_ports);
+ // Verify that message is received
+ const MockMessagePortDelegate::Messages& received =
+ delegate.getReceivedMessages();
+ EXPECT_EQ(received.size(), 1u);
+ // Verify that message sent to port1 is received by entangled port, which is
+ // port2.
+ EXPECT_EQ(received[0].route_id, port2);
+ EXPECT_EQ(received[0].data.message_as_string, MESSAGE1);
+ EXPECT_EQ(received[0].sent_ports.size(), 0u);
+
+ // Create a new channel, and transfer one of its ports to port2, making sure
+ // the transferred port is received.
+ TransferredMessagePort port3;
+ TransferredMessagePort port4;
+ MessagePortProvider::CreateMessageChannel(&delegate, &port3.id, &port4.id);
+ sent_ports.push_back(port3);
+ service->PostMessage(port1, MessagePortMessage(base::string16(MESSAGE2)),
+ sent_ports);
+ EXPECT_EQ(received.size(), 2u);
+ EXPECT_EQ(received[1].route_id, port2);
+ EXPECT_EQ(received[1].data.message_as_string, MESSAGE2);
+ EXPECT_EQ(received[1].sent_ports.size(), 1u);
+ EXPECT_EQ(received[1].sent_ports[0].id, port3.id);
+
+ event->Signal();
+}
+
+} // namespace
+
+// Verify that a message channel can be created and used for exchanging
+// messages.
+IN_PROC_BROWSER_TEST_F(MessagePortProviderBrowserTest, CreateChannel) {
+ base::WaitableEvent event(true, false);
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&VerifyCreateChannelOnIOThread, &event));
+ event.Wait();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/message_port_service.cc b/chromium/content/browser/message_port_service.cc
index 0d9f6084e86..915ae483d31 100644
--- a/chromium/content/browser/message_port_service.cc
+++ b/chromium/content/browser/message_port_service.cc
@@ -4,16 +4,17 @@
#include "content/browser/message_port_service.h"
-#include "content/browser/message_port_message_filter.h"
#include "content/common/message_port_messages.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/message_port_delegate.h"
namespace content {
struct MessagePortService::MessagePort {
- // |filter| and |route_id| are what we need to send messages to the port.
- // |filter| is just a weak pointer since we get notified when its process has
- // gone away and remove it.
- MessagePortMessageFilter* filter;
+ // |delegate| and |route_id| are what we need to send messages to the port.
+ // |delegate| is just a raw pointer since it notifies us by calling
+ // OnMessagePortDelegateClosing before it gets destroyed.
+ MessagePortDelegate* delegate;
int route_id;
// A globally unique id for this message port.
int message_port_id;
@@ -27,7 +28,24 @@ struct MessagePortService::MessagePort {
// system.
// This flag should only be set to true in response to
// MessagePortHostMsg_QueueMessages.
- bool queue_messages;
+ bool queue_for_inflight_messages;
+ // If true, all messages to this message port are queued and not delivered.
+ // This is needed so that when a message port is sent to a new process all
+ // messages are held in the browser process until the destination process is
+ // ready to receive messages. This flag is set true when a message port is
+ // transferred to a different process but there isn't immediately a
+ // MessagePortDelegate available for that new process. Once the
+ // destination process is ready to receive messages it sends
+ // MessagePortHostMsg_ReleaseMessages to set this flag to false.
+ bool hold_messages_for_destination;
+ // Returns true if messages should be queued for either reason.
+ bool queue_messages() const {
+ return queue_for_inflight_messages || hold_messages_for_destination;
+ }
+ // If true, the message port should be destroyed but was currently still
+ // waiting for a SendQueuedMessages message from a renderer. As soon as that
+ // message is received the port will actually be destroyed.
+ bool should_be_destroyed;
QueuedMessages queued_messages;
};
@@ -42,58 +60,65 @@ MessagePortService::MessagePortService()
MessagePortService::~MessagePortService() {
}
-void MessagePortService::UpdateMessagePort(
- int message_port_id,
- MessagePortMessageFilter* filter,
- int routing_id) {
+void MessagePortService::UpdateMessagePort(int message_port_id,
+ MessagePortDelegate* delegate,
+ int routing_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!message_ports_.count(message_port_id)) {
NOTREACHED();
return;
}
MessagePort& port = message_ports_[message_port_id];
- port.filter = filter;
+ port.delegate = delegate;
port.route_id = routing_id;
}
-void MessagePortService::OnMessagePortMessageFilterClosing(
- MessagePortMessageFilter* filter) {
+void MessagePortService::OnMessagePortDelegateClosing(
+ MessagePortDelegate* delegate) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
// Check if the (possibly) crashed process had any message ports.
for (MessagePorts::iterator iter = message_ports_.begin();
iter != message_ports_.end();) {
MessagePorts::iterator cur_item = iter++;
- if (cur_item->second.filter == filter) {
+ if (cur_item->second.delegate == delegate) {
Erase(cur_item->first);
}
}
}
void MessagePortService::Create(int route_id,
- MessagePortMessageFilter* filter,
+ MessagePortDelegate* delegate,
int* message_port_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
*message_port_id = ++next_message_port_id_;
MessagePort port;
- port.filter = filter;
+ port.delegate = delegate;
port.route_id = route_id;
port.message_port_id = *message_port_id;
port.entangled_message_port_id = MSG_ROUTING_NONE;
- port.queue_messages = false;
+ port.queue_for_inflight_messages = false;
+ port.hold_messages_for_destination = false;
+ port.should_be_destroyed = false;
message_ports_[*message_port_id] = port;
}
void MessagePortService::Destroy(int message_port_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!message_ports_.count(message_port_id)) {
NOTREACHED();
return;
}
DCHECK(message_ports_[message_port_id].queued_messages.empty());
+
Erase(message_port_id);
}
void MessagePortService::Entangle(int local_message_port_id,
int remote_message_port_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!message_ports_.count(local_message_port_id) ||
!message_ports_.count(remote_message_port_id)) {
NOTREACHED();
@@ -108,8 +133,9 @@ void MessagePortService::Entangle(int local_message_port_id,
void MessagePortService::PostMessage(
int sender_message_port_id,
- const base::string16& message,
- const std::vector<int>& sent_message_port_ids) {
+ const MessagePortMessage& message,
+ const std::vector<TransferredMessagePort>& sent_message_ports) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!message_ports_.count(sender_message_port_id)) {
NOTREACHED();
return;
@@ -125,76 +151,67 @@ void MessagePortService::PostMessage(
return;
}
- PostMessageTo(entangled_message_port_id, message, sent_message_port_ids);
+ PostMessageTo(entangled_message_port_id, message, sent_message_ports);
}
void MessagePortService::PostMessageTo(
int message_port_id,
- const base::string16& message,
- const std::vector<int>& sent_message_port_ids) {
+ const MessagePortMessage& message,
+ const std::vector<TransferredMessagePort>& sent_message_ports) {
if (!message_ports_.count(message_port_id)) {
NOTREACHED();
return;
}
- for (size_t i = 0; i < sent_message_port_ids.size(); ++i) {
- if (!message_ports_.count(sent_message_port_ids[i])) {
+ for (size_t i = 0; i < sent_message_ports.size(); ++i) {
+ if (!message_ports_.count(sent_message_ports[i].id)) {
NOTREACHED();
return;
}
}
MessagePort& entangled_port = message_ports_[message_port_id];
-
- std::vector<MessagePort*> sent_ports(sent_message_port_ids.size());
- for (size_t i = 0; i < sent_message_port_ids.size(); ++i)
- sent_ports[i] = &message_ports_[sent_message_port_ids[i]];
-
- if (entangled_port.queue_messages) {
+ if (entangled_port.queue_messages()) {
+ // If the target port is currently holding messages because the destination
+ // renderer isn't available yet, all message ports being sent should also be
+ // put in this state.
+ if (entangled_port.hold_messages_for_destination) {
+ for (const auto& port : sent_message_ports)
+ HoldMessages(port.id);
+ }
entangled_port.queued_messages.push_back(
- std::make_pair(message, sent_message_port_ids));
+ std::make_pair(message, sent_message_ports));
return;
}
- if (!entangled_port.filter) {
+ if (!entangled_port.delegate) {
NOTREACHED();
return;
}
- // If a message port was sent around, the new location will need a routing
- // id. Instead of having the created port send us a sync message to get it,
- // send along with the message.
- std::vector<int> new_routing_ids(sent_message_port_ids.size());
- for (size_t i = 0; i < sent_message_port_ids.size(); ++i) {
- new_routing_ids[i] = entangled_port.filter->GetNextRoutingID();
- sent_ports[i]->filter = entangled_port.filter;
-
- // Update the entry for the sent port as it can be in a different process.
- sent_ports[i]->route_id = new_routing_ids[i];
- }
-
// Now send the message to the entangled port.
- entangled_port.filter->Send(new MessagePortMsg_Message(
- entangled_port.route_id, message, sent_message_port_ids,
- new_routing_ids));
+ entangled_port.delegate->SendMessage(entangled_port.route_id, message,
+ sent_message_ports);
}
void MessagePortService::QueueMessages(int message_port_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!message_ports_.count(message_port_id)) {
NOTREACHED();
return;
}
MessagePort& port = message_ports_[message_port_id];
- if (port.filter) {
- port.filter->Send(new MessagePortMsg_MessagesQueued(port.route_id));
- port.queue_messages = true;
- port.filter = NULL;
+ if (port.delegate) {
+ port.delegate->SendMessagesAreQueued(port.route_id);
+ port.queue_for_inflight_messages = true;
+ port.delegate = NULL;
}
}
void MessagePortService::SendQueuedMessages(
int message_port_id,
const QueuedMessages& queued_messages) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!message_ports_.count(message_port_id)) {
NOTREACHED();
return;
@@ -203,21 +220,35 @@ void MessagePortService::SendQueuedMessages(
// Send the queued messages to the port again. This time they'll reach the
// new location.
MessagePort& port = message_ports_[message_port_id];
- port.queue_messages = false;
+ port.queue_for_inflight_messages = false;
+
+ // If the port is currently holding messages waiting for the target renderer,
+ // all ports in messages being sent to the port should also be put on hold.
+ if (port.hold_messages_for_destination) {
+ for (const auto& message : queued_messages)
+ for (const TransferredMessagePort& sent_port : message.second)
+ HoldMessages(sent_port.id);
+ }
+
port.queued_messages.insert(port.queued_messages.begin(),
queued_messages.begin(),
queued_messages.end());
- SendQueuedMessagesIfPossible(message_port_id);
+
+ if (port.should_be_destroyed)
+ ClosePort(message_port_id);
+ else
+ SendQueuedMessagesIfPossible(message_port_id);
}
void MessagePortService::SendQueuedMessagesIfPossible(int message_port_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!message_ports_.count(message_port_id)) {
NOTREACHED();
return;
}
MessagePort& port = message_ports_[message_port_id];
- if (port.queue_messages || !port.filter)
+ if (port.queue_messages() || !port.delegate)
return;
for (QueuedMessages::iterator iter = port.queued_messages.begin();
@@ -227,6 +258,52 @@ void MessagePortService::SendQueuedMessagesIfPossible(int message_port_id) {
port.queued_messages.clear();
}
+void MessagePortService::HoldMessages(int message_port_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (!message_ports_.count(message_port_id)) {
+ NOTREACHED();
+ return;
+ }
+
+ // Any ports in messages currently in the queue should also be put on hold.
+ for (const auto& message : message_ports_[message_port_id].queued_messages)
+ for (const TransferredMessagePort& sent_port : message.second)
+ HoldMessages(sent_port.id);
+
+ message_ports_[message_port_id].hold_messages_for_destination = true;
+}
+
+void MessagePortService::ClosePort(int message_port_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (!message_ports_.count(message_port_id)) {
+ NOTREACHED();
+ return;
+ }
+
+ if (message_ports_[message_port_id].queue_for_inflight_messages) {
+ message_ports_[message_port_id].should_be_destroyed = true;
+ return;
+ }
+
+ // First close any message ports in the queue for this message port.
+ for (const auto& message : message_ports_[message_port_id].queued_messages)
+ for (const TransferredMessagePort& sent_port : message.second)
+ ClosePort(sent_port.id);
+
+ Erase(message_port_id);
+}
+
+void MessagePortService::ReleaseMessages(int message_port_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (!message_ports_.count(message_port_id)) {
+ NOTREACHED();
+ return;
+ }
+
+ message_ports_[message_port_id].hold_messages_for_destination = false;
+ SendQueuedMessagesIfPossible(message_port_id);
+}
+
void MessagePortService::Erase(int message_port_id) {
MessagePorts::iterator erase_item = message_ports_.find(message_port_id);
DCHECK(erase_item != message_ports_.end());
diff --git a/chromium/content/browser/message_port_service.h b/chromium/content/browser/message_port_service.h
index 668959167f7..d5e3379d57d 100644
--- a/chromium/content/browser/message_port_service.h
+++ b/chromium/content/browser/message_port_service.h
@@ -12,14 +12,17 @@
#include "base/basictypes.h"
#include "base/memory/singleton.h"
#include "base/strings/string16.h"
+#include "content/common/content_export.h"
+#include "content/public/common/message_port_types.h"
#include "ipc/ipc_message.h"
namespace content {
-class MessagePortMessageFilter;
+class MessagePortDelegate;
-class MessagePortService {
+class CONTENT_EXPORT MessagePortService {
public:
- typedef std::vector<std::pair<base::string16, std::vector<int> > >
+ typedef std::vector<std::pair<content::MessagePortMessage,
+ std::vector<TransferredMessagePort>>>
QueuedMessages;
// Returns the MessagePortService singleton.
@@ -27,25 +30,40 @@ class MessagePortService {
// These methods correspond to the message port related IPCs.
void Create(int route_id,
- MessagePortMessageFilter* filter,
+ MessagePortDelegate* delegate,
int* message_port_id);
void Destroy(int message_port_id);
void Entangle(int local_message_port_id, int remote_message_port_id);
- void PostMessage(int sender_message_port_id,
- const base::string16& message,
- const std::vector<int>& sent_message_port_ids);
+ void PostMessage(
+ int sender_message_port_id,
+ const MessagePortMessage& message,
+ const std::vector<TransferredMessagePort>& sent_message_ports);
void QueueMessages(int message_port_id);
void SendQueuedMessages(int message_port_id,
const QueuedMessages& queued_messages);
+ void ReleaseMessages(int message_port_id);
// Updates the information needed to reach a message port when it's sent to a
// (possibly different) process.
- void UpdateMessagePort(
- int message_port_id,
- MessagePortMessageFilter* filter,
- int routing_id);
-
- void OnMessagePortMessageFilterClosing(MessagePortMessageFilter* filter);
+ void UpdateMessagePort(int message_port_id,
+ MessagePortDelegate* delegate,
+ int routing_id);
+
+ // The message port is being transferred to a new renderer process, but the
+ // code doing that isn't able to immediately update the message port with a
+ // new filter and routing_id. This queues up all messages sent to this port
+ // until later ReleaseMessages is called for this port (this will happen
+ // automatically as soon as a WebMessagePortChannelImpl instance is created
+ // for this port in the renderer. The browser side code is still responsible
+ // for updating the port with a new filter before that happens. If ultimately
+ // transfering the port to a new process fails, ClosePort should be called to
+ // clean up the port.
+ void HoldMessages(int message_port_id);
+
+ // Closes and cleans up the message port.
+ void ClosePort(int message_port_id);
+
+ void OnMessagePortDelegateClosing(MessagePortDelegate* filter);
// Attempts to send the queued messages for a message port.
void SendQueuedMessagesIfPossible(int message_port_id);
@@ -56,9 +74,10 @@ class MessagePortService {
MessagePortService();
~MessagePortService();
- void PostMessageTo(int message_port_id,
- const base::string16& message,
- const std::vector<int>& sent_message_port_ids);
+ void PostMessageTo(
+ int message_port_id,
+ const MessagePortMessage& message,
+ const std::vector<TransferredMessagePort>& sent_message_ports);
// Handles the details of removing a message port id. Before calling this,
// verify that the message port id exists.
diff --git a/chromium/content/browser/mojo/mojo_application_host.cc b/chromium/content/browser/mojo/mojo_application_host.cc
index 18219676a3e..b1a9382f9ad 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/edk/embedder/platform_channel_pair.h"
+#include "third_party/mojo/src/mojo/edk/embedder/platform_channel_pair.h"
namespace content {
namespace {
@@ -21,9 +21,34 @@ base::PlatformFile PlatformFileFromScopedPlatformHandle(
#endif
}
+class ApplicationSetupImpl : public ApplicationSetup {
+ public:
+ ApplicationSetupImpl(ServiceRegistryImpl* service_registry,
+ mojo::InterfaceRequest<ApplicationSetup> request)
+ : binding_(this, request.Pass()),
+ service_registry_(service_registry) {
+ }
+
+ ~ApplicationSetupImpl() override {
+ }
+
+ private:
+ // ApplicationSetup implementation.
+ void ExchangeServiceProviders(
+ mojo::InterfaceRequest<mojo::ServiceProvider> services,
+ mojo::ServiceProviderPtr exposed_services) override {
+ service_registry_->Bind(services.Pass());
+ service_registry_->BindRemoteServiceProvider(exposed_services.Pass());
+ }
+
+ mojo::Binding<ApplicationSetup> binding_;
+ ServiceRegistryImpl* service_registry_;
+};
+
} // namespace
-MojoApplicationHost::MojoApplicationHost() : did_activate_(false) {
+MojoApplicationHost::MojoApplicationHost()
+ : did_activate_(false) {
#if defined(OS_ANDROID)
service_registry_android_.reset(
new ServiceRegistryAndroid(&service_registry_));
@@ -38,16 +63,27 @@ bool MojoApplicationHost::Init() {
mojo::embedder::PlatformChannelPair channel_pair;
+ scoped_refptr<base::TaskRunner> io_task_runner;
+ if (io_task_runner_override_) {
+ io_task_runner = io_task_runner_override_;
+ } else {
+ io_task_runner =
+ BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::IO)
+ ->task_runner();
+ }
+
mojo::ScopedMessagePipeHandle message_pipe = channel_init_.Init(
PlatformFileFromScopedPlatformHandle(channel_pair.PassServerHandle()),
- BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO));
+ io_task_runner);
if (!message_pipe.is_valid())
return false;
// Forward this to the client once we know its process handle.
client_handle_ = channel_pair.PassClientHandle();
- service_registry_.BindRemoteServiceProvider(message_pipe.Pass());
+ application_setup_.reset(new ApplicationSetupImpl(
+ &service_registry_,
+ mojo::MakeRequest<ApplicationSetup>(message_pipe.Pass())));
return true;
}
@@ -66,4 +102,14 @@ void MojoApplicationHost::WillDestroySoon() {
channel_init_.WillDestroySoon();
}
+void MojoApplicationHost::ShutdownOnIOThread() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ channel_init_.ShutdownOnIOThread();
+}
+
+void MojoApplicationHost::OverrideIOTaskRunnerForTest(
+ scoped_refptr<base::TaskRunner> io_task_runner) {
+ io_task_runner_override_ = io_task_runner;
+}
+
} // namespace content
diff --git a/chromium/content/browser/mojo/mojo_application_host.h b/chromium/content/browser/mojo/mojo_application_host.h
index 1825b3eab55..fffb59e05c6 100644
--- a/chromium/content/browser/mojo/mojo_application_host.h
+++ b/chromium/content/browser/mojo/mojo_application_host.h
@@ -7,9 +7,10 @@
#include "base/memory/scoped_ptr.h"
#include "base/process/process_handle.h"
+#include "content/common/application_setup.mojom.h"
+#include "content/common/mojo/channel_init.h"
#include "content/common/mojo/service_registry_impl.h"
-#include "mojo/edk/embedder/channel_init.h"
-#include "mojo/edk/embedder/scoped_platform_handle.h"
+#include "third_party/mojo/src/mojo/edk/embedder/scoped_platform_handle.h"
#if defined(OS_ANDROID)
#include "content/browser/mojo/service_registry_android.h"
@@ -26,10 +27,10 @@ namespace content {
// should use MojoApplication to handle messages generated by an instance of
// MojoApplicationHost. MojoApplicationHost makes the ServiceRegistry interface
// available so that child-provided services can be invoked.
-class MojoApplicationHost {
+class CONTENT_EXPORT MojoApplicationHost {
public:
MojoApplicationHost();
- virtual ~MojoApplicationHost();
+ ~MojoApplicationHost();
// Two-phase initialization:
// 1- Init makes service_registry() available synchronously.
@@ -39,16 +40,31 @@ class MojoApplicationHost {
void WillDestroySoon();
+ // Shuts down the Mojo channel. Must be called from the IO thread.
+ void ShutdownOnIOThread();
+
ServiceRegistry* service_registry() { return &service_registry_; }
+#if defined(OS_ANDROID)
+ ServiceRegistryAndroid* service_registry_android() {
+ return service_registry_android_.get();
+ }
+#endif
+
+ void OverrideIOTaskRunnerForTest(
+ scoped_refptr<base::TaskRunner> io_task_runner);
+
private:
- mojo::embedder::ChannelInit channel_init_;
+ ChannelInit channel_init_;
mojo::embedder::ScopedPlatformHandle client_handle_;
bool did_activate_;
+ scoped_ptr<ApplicationSetup> application_setup_;
ServiceRegistryImpl service_registry_;
+ scoped_refptr<base::TaskRunner> io_task_runner_override_;
+
#if defined(OS_ANDROID)
scoped_ptr<ServiceRegistryAndroid> service_registry_android_;
#endif
diff --git a/chromium/content/browser/mojo/service_registrar_android.cc b/chromium/content/browser/mojo/service_registrar_android.cc
new file mode 100644
index 00000000000..30ea7421019
--- /dev/null
+++ b/chromium/content/browser/mojo/service_registrar_android.cc
@@ -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.
+
+#include "content/browser/mojo/service_registrar_android.h"
+
+#include "base/android/jni_android.h"
+#include "content/browser/mojo/service_registry_android.h"
+#include "jni/ServiceRegistrar_jni.h"
+
+namespace content {
+
+// static
+bool ServiceRegistrarAndroid::Register(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+// static
+void ServiceRegistrarAndroid::RegisterProcessHostServices(
+ ServiceRegistryAndroid* registry) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ Java_ServiceRegistrar_registerProcessHostServices(
+ env, registry->GetObj().obj(), base::android::GetApplicationContext());
+}
+
+// static
+void ServiceRegistrarAndroid::RegisterFrameHostServices(
+ ServiceRegistryAndroid* registry) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ Java_ServiceRegistrar_registerFrameHostServices(
+ env, registry->GetObj().obj(), base::android::GetApplicationContext());
+}
+} // namespace content
diff --git a/chromium/content/browser/mojo/service_registrar_android.h b/chromium/content/browser/mojo/service_registrar_android.h
new file mode 100644
index 00000000000..fdf62d4f742
--- /dev/null
+++ b/chromium/content/browser/mojo/service_registrar_android.h
@@ -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.
+
+#ifndef CONTENT_BROWSER_MOJO_SERVICE_REGISTRAR_ANDROID_H_
+#define CONTENT_BROWSER_MOJO_SERVICE_REGISTRAR_ANDROID_H_
+
+#include <jni.h>
+
+namespace content {
+
+class ServiceRegistryAndroid;
+
+// Registrar for mojo services in Java exposed by the browser. This calls into
+// Java where the services are registered with the indicated registry.
+class ServiceRegistrarAndroid {
+ public:
+ static bool Register(JNIEnv* env);
+ static void RegisterProcessHostServices(ServiceRegistryAndroid* registry);
+ static void RegisterFrameHostServices(ServiceRegistryAndroid* registry);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_MOJO_SERVICE_REGISTRAR_ANDROID_H_
diff --git a/chromium/content/browser/mojo/service_registry_android.h b/chromium/content/browser/mojo/service_registry_android.h
index 0873531be25..37ec10a4be8 100644
--- a/chromium/content/browser/mojo/service_registry_android.h
+++ b/chromium/content/browser/mojo/service_registry_android.h
@@ -37,9 +37,7 @@ class CONTENT_EXPORT ServiceRegistryAndroid {
jstring j_name,
jint handle);
- const base::android::ScopedJavaGlobalRef<jobject>& GetObjForTesting() {
- return obj_;
- }
+ const base::android::ScopedJavaGlobalRef<jobject>& GetObj() { return obj_; }
private:
ServiceRegistryImpl* service_registry_;
diff --git a/chromium/content/browser/navigator_connect/OWNERS b/chromium/content/browser/navigator_connect/OWNERS
new file mode 100644
index 00000000000..1b10b3436d9
--- /dev/null
+++ b/chromium/content/browser/navigator_connect/OWNERS
@@ -0,0 +1 @@
+mek@chromium.org
diff --git a/chromium/content/browser/navigator_connect/navigator_connect_context_impl.cc b/chromium/content/browser/navigator_connect/navigator_connect_context_impl.cc
new file mode 100644
index 00000000000..c5f01f4534a
--- /dev/null
+++ b/chromium/content/browser/navigator_connect/navigator_connect_context_impl.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/navigator_connect/navigator_connect_context_impl.h"
+
+#include "content/browser/message_port_message_filter.h"
+#include "content/browser/message_port_service.h"
+#include "content/public/browser/navigator_connect_service_factory.h"
+#include "content/public/common/navigator_connect_client.h"
+
+namespace content {
+
+NavigatorConnectContextImpl::NavigatorConnectContextImpl() {
+}
+
+NavigatorConnectContextImpl::~NavigatorConnectContextImpl() {
+}
+
+void NavigatorConnectContextImpl::AddFactory(
+ scoped_ptr<NavigatorConnectServiceFactory> factory) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&NavigatorConnectContextImpl::AddFactoryOnIOThread, this,
+ base::Passed(&factory)));
+}
+
+void NavigatorConnectContextImpl::AddFactoryOnIOThread(
+ scoped_ptr<NavigatorConnectServiceFactory> factory) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ service_factories_.push_back(factory.release());
+}
+
+void NavigatorConnectContextImpl::Connect(
+ NavigatorConnectClient client,
+ MessagePortMessageFilter* message_port_message_filter,
+ const ConnectCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ // Create a new message channel. Client port is setup to talk to client
+ // process, service port is initially setup without a delegate.
+ MessagePortService* message_port_service = MessagePortService::GetInstance();
+ int client_port;
+ int client_port_route_id = message_port_message_filter->GetNextRoutingID();
+ message_port_service->Create(client_port_route_id,
+ message_port_message_filter, &client_port);
+ int service_port;
+ message_port_service->Create(MSG_ROUTING_NONE, nullptr, &service_port);
+ message_port_service->Entangle(client_port, service_port);
+ message_port_service->Entangle(service_port, client_port);
+ // Hold messages on client port while setting up connection.
+ message_port_service->HoldMessages(client_port);
+
+ // The message_port_id stored in the client object is the one associated with
+ // the service.
+ client.message_port_id = service_port;
+
+ // Find factory to handle request, more recently added factories should take
+ // priority as per comment at NavigatorConnectContext::AddFactory..
+ NavigatorConnectServiceFactory* factory = nullptr;
+ for (auto it = service_factories_.rbegin(); it != service_factories_.rend();
+ ++it) {
+ if ((*it)->HandlesUrl(client.target_url)) {
+ factory = *it;
+ break;
+ }
+ }
+
+ if (!factory) {
+ // No factories found.
+ OnConnectResult(client, client_port, client_port_route_id, callback,
+ nullptr, false);
+ return;
+ }
+
+ // Actually initiate connection.
+ factory->Connect(
+ client, base::Bind(&NavigatorConnectContextImpl::OnConnectResult, this,
+ client, client_port, client_port_route_id, callback));
+}
+
+void NavigatorConnectContextImpl::OnConnectResult(
+ const NavigatorConnectClient& client,
+ int client_message_port_id,
+ int client_port_route_id,
+ const ConnectCallback& callback,
+ MessagePortDelegate* delegate,
+ bool data_as_values) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (delegate) {
+ // Update service side port with delegate.
+ MessagePortService::GetInstance()->UpdateMessagePort(
+ client.message_port_id, delegate, client.message_port_id);
+ TransferredMessagePort port;
+ port.id = client_message_port_id;
+ port.send_messages_as_values = data_as_values;
+ callback.Run(port, client_port_route_id, true);
+ } else {
+ // Destroy ports since connection failed.
+ MessagePortService::GetInstance()->Destroy(client.message_port_id);
+ MessagePortService::GetInstance()->Destroy(client_message_port_id);
+ callback.Run(TransferredMessagePort(), MSG_ROUTING_NONE, false);
+ }
+}
+
+} // namespace content
diff --git a/chromium/content/browser/navigator_connect/navigator_connect_context_impl.h b/chromium/content/browser/navigator_connect/navigator_connect_context_impl.h
new file mode 100644
index 00000000000..ffb4647041f
--- /dev/null
+++ b/chromium/content/browser/navigator_connect/navigator_connect_context_impl.h
@@ -0,0 +1,65 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_NAVIGATOR_CONNECT_NAVIGATOR_CONNECT_CONTEXT_IMPL_H_
+#define CONTENT_BROWSER_NAVIGATOR_CONNECT_NAVIGATOR_CONNECT_CONTEXT_IMPL_H_
+
+#include <map>
+#include "base/callback_forward.h"
+#include "base/memory/scoped_vector.h"
+#include "content/public/browser/message_port_delegate.h"
+#include "content/public/browser/navigator_connect_context.h"
+
+namespace content {
+
+class MessagePortMessageFilter;
+class NavigatorConnectService;
+class NavigatorConnectServiceFactory;
+struct NavigatorConnectClient;
+struct TransferredMessagePort;
+
+// Tracks all active navigator.connect connections, as well as available service
+// factories. Delegates connection requests to the correct factory and passes
+// messages on to the correct service.
+// One instance of this class exists per StoragePartition.
+// TODO(mek): Somehow clean up connections when the client side goes away.
+class NavigatorConnectContextImpl : public NavigatorConnectContext {
+ public:
+ using ConnectCallback =
+ base::Callback<void(const TransferredMessagePort& message_port,
+ int message_port_route_id,
+ bool success)>;
+
+ explicit NavigatorConnectContextImpl();
+
+ // Called when a new connection request comes in from a client. Finds the
+ // correct service factory and passes the connection request off to there.
+ // Can call the callback before this method call returns.
+ void Connect(NavigatorConnectClient client,
+ MessagePortMessageFilter* message_port_message_filter,
+ const ConnectCallback& callback);
+
+ // NavigatorConnectContext implementation.
+ void AddFactory(scoped_ptr<NavigatorConnectServiceFactory> factory) override;
+
+ private:
+ ~NavigatorConnectContextImpl() override;
+
+ void AddFactoryOnIOThread(scoped_ptr<NavigatorConnectServiceFactory> factory);
+
+ // Callback called by service factories when a connection succeeded or failed.
+ void OnConnectResult(const NavigatorConnectClient& client,
+ int client_message_port_id,
+ int client_port_route_id,
+ const ConnectCallback& callback,
+ MessagePortDelegate* delegate,
+ bool data_as_values);
+
+ // List of factories to try to handle URLs.
+ ScopedVector<NavigatorConnectServiceFactory> service_factories_;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_NAVIGATOR_CONNECT_NAVIGATOR_CONNECT_CONTEXT_IMPL_H_
diff --git a/chromium/content/browser/navigator_connect/navigator_connect_dispatcher_host.cc b/chromium/content/browser/navigator_connect/navigator_connect_dispatcher_host.cc
new file mode 100644
index 00000000000..daa46ba7f18
--- /dev/null
+++ b/chromium/content/browser/navigator_connect/navigator_connect_dispatcher_host.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/navigator_connect/navigator_connect_dispatcher_host.h"
+
+#include "content/browser/message_port_service.h"
+#include "content/browser/navigator_connect/navigator_connect_context_impl.h"
+#include "content/browser/service_worker/service_worker_context_wrapper.h"
+#include "content/common/navigator_connect_messages.h"
+#include "content/public/common/navigator_connect_client.h"
+
+namespace content {
+
+NavigatorConnectDispatcherHost::NavigatorConnectDispatcherHost(
+ const scoped_refptr<NavigatorConnectContextImpl>& navigator_connect_context,
+ MessagePortMessageFilter* message_port_message_filter)
+ : BrowserMessageFilter(NavigatorConnectMsgStart),
+ navigator_connect_context_(navigator_connect_context),
+ message_port_message_filter_(message_port_message_filter) {
+}
+
+NavigatorConnectDispatcherHost::~NavigatorConnectDispatcherHost() {
+}
+
+bool NavigatorConnectDispatcherHost::OnMessageReceived(
+ const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(NavigatorConnectDispatcherHost, message)
+ IPC_MESSAGE_HANDLER(NavigatorConnectHostMsg_Connect, OnConnect)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void NavigatorConnectDispatcherHost::OnConnect(
+ int thread_id,
+ int request_id,
+ const NavigatorConnectClient& client) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ DCHECK(client.message_port_id == MSG_ROUTING_NONE)
+ << "Connect request should not include a message port";
+
+ navigator_connect_context_->Connect(
+ client, message_port_message_filter_,
+ base::Bind(&NavigatorConnectDispatcherHost::OnConnectResult, this,
+ thread_id, request_id));
+}
+
+void NavigatorConnectDispatcherHost::OnConnectResult(
+ int thread_id,
+ int request_id,
+ const TransferredMessagePort& message_port,
+ int message_port_route_id,
+ bool accept_connection) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ Send(new NavigatorConnectMsg_ConnectResult(
+ thread_id, request_id, message_port, message_port_route_id,
+ accept_connection));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/navigator_connect/navigator_connect_dispatcher_host.h b/chromium/content/browser/navigator_connect/navigator_connect_dispatcher_host.h
new file mode 100644
index 00000000000..614382eac2f
--- /dev/null
+++ b/chromium/content/browser/navigator_connect/navigator_connect_dispatcher_host.h
@@ -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.
+
+#ifndef CONTENT_BROWSER_NAVIGATOR_CONNECT_NAVIGATOR_CONNECT_DISPATCHER_HOST_H_
+#define CONTENT_BROWSER_NAVIGATOR_CONNECT_NAVIGATOR_CONNECT_DISPATCHER_HOST_H_
+
+#include "content/public/browser/browser_message_filter.h"
+
+class GURL;
+
+namespace content {
+
+class MessagePortMessageFilter;
+class NavigatorConnectContextImpl;
+struct NavigatorConnectClient;
+struct TransferredMessagePort;
+
+// Receives navigator.connect connection attempts from a child process.
+// Attempts to find a service that serves the URL the connection is made to
+// and sets up the actual connection.
+// Constructed on the UI thread, but all other methods are called on the IO
+// thread. Typically there is one instance of this class for each renderer
+// process, and this class lives at least as long as the renderer process is
+// alive (since this class is refcounted it could outlive the renderer process
+// if it is still handling a connection attempt).
+class NavigatorConnectDispatcherHost : public BrowserMessageFilter {
+ public:
+ NavigatorConnectDispatcherHost(
+ const scoped_refptr<NavigatorConnectContextImpl>&
+ navigator_connect_context,
+ MessagePortMessageFilter* message_port_message_filter);
+
+ private:
+ ~NavigatorConnectDispatcherHost() override;
+
+ // BrowserMessageFilter implementation.
+ bool OnMessageReceived(const IPC::Message& message) override;
+
+ // IPC Message handlers.
+ void OnConnect(int thread_id,
+ int request_id,
+ const NavigatorConnectClient& client);
+
+ // Callback called when the service worker finished handling the cross origin
+ // connection event.
+ void OnConnectResult(int thread_id,
+ int request_id,
+ const TransferredMessagePort& message_port,
+ int message_port_route_id,
+ bool accept_connection);
+
+ scoped_refptr<NavigatorConnectContextImpl> navigator_connect_context_;
+ MessagePortMessageFilter* const message_port_message_filter_;
+
+ DISALLOW_COPY_AND_ASSIGN(NavigatorConnectDispatcherHost);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_NAVIGATOR_CONNECT_NAVIGATOR_CONNECT_DISPATCHER_HOST_H_
diff --git a/chromium/content/browser/navigator_connect/navigator_connect_service_worker_service_factory.cc b/chromium/content/browser/navigator_connect/navigator_connect_service_worker_service_factory.cc
new file mode 100644
index 00000000000..17ee080c87f
--- /dev/null
+++ b/chromium/content/browser/navigator_connect/navigator_connect_service_worker_service_factory.cc
@@ -0,0 +1,201 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/navigator_connect/navigator_connect_service_worker_service_factory.h"
+
+#include "base/bind.h"
+#include "content/browser/message_port_service.h"
+#include "content/browser/service_worker/service_worker_context_wrapper.h"
+#include "content/browser/service_worker/service_worker_utils.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/message_port_delegate.h"
+#include "content/public/common/navigator_connect_client.h"
+
+namespace content {
+
+namespace {
+
+// MessagePortDelegate implementation that directs all messages to the
+// oncrossoriginmessage event of a service worker.
+// TODO(mek): Somehow clean up message ports when a service worker is
+// unregistered.
+class NavigatorConnectServiceWorkerService : public MessagePortDelegate {
+ public:
+ NavigatorConnectServiceWorkerService(
+ const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context,
+ const NavigatorConnectClient& client,
+ const scoped_refptr<ServiceWorkerRegistration>&
+ service_worker_registration);
+ ~NavigatorConnectServiceWorkerService() override;
+
+ // MessagePortDelegate implementation.
+ void SendMessage(
+ int route_id,
+ const MessagePortMessage& message,
+ const std::vector<TransferredMessagePort>& sent_message_ports) override;
+ void SendMessagesAreQueued(int route_id) override;
+
+ private:
+ // Callback called by SendMessage when the ServiceWorkerRegistration for this
+ // service has been located.
+ void DeliverMessage(
+ const base::string16& message,
+ const std::vector<TransferredMessagePort>& sent_message_ports,
+ ServiceWorkerStatusCode service_worker_status,
+ const scoped_refptr<ServiceWorkerRegistration>&
+ service_worker_registration);
+
+ scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_;
+ NavigatorConnectClient client_;
+ int64 service_worker_registration_id_;
+ GURL service_worker_registration_origin_;
+
+ base::WeakPtrFactory<NavigatorConnectServiceWorkerService> weak_factory_;
+};
+
+NavigatorConnectServiceWorkerService::NavigatorConnectServiceWorkerService(
+ const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context,
+ const NavigatorConnectClient& client,
+ const scoped_refptr<ServiceWorkerRegistration>& service_worker_registration)
+ : service_worker_context_(service_worker_context),
+ client_(client),
+ service_worker_registration_id_(service_worker_registration->id()),
+ service_worker_registration_origin_(
+ service_worker_registration->pattern().GetOrigin()),
+ weak_factory_(this) {
+}
+
+NavigatorConnectServiceWorkerService::~NavigatorConnectServiceWorkerService() {
+}
+
+void NavigatorConnectServiceWorkerService::SendMessage(
+ int route_id,
+ const MessagePortMessage& message,
+ const std::vector<TransferredMessagePort>& sent_message_ports) {
+ DCHECK(route_id == client_.message_port_id);
+ DCHECK(message.message_as_value.empty());
+
+ // Hold messages on transferred message ports. Actual delivery of the message
+ // by the service can be asynchronous. When a message is delivered,
+ // WebMessagePortChannelImpl instances will be constructed which send
+ // MessagePortHostMsg_ReleaseMessages to release messages.
+ for (const auto& port : sent_message_ports)
+ MessagePortService::GetInstance()->HoldMessages(port.id);
+
+ service_worker_context_->FindRegistrationForId(
+ service_worker_registration_id_, service_worker_registration_origin_,
+ base::Bind(&NavigatorConnectServiceWorkerService::DeliverMessage,
+ weak_factory_.GetWeakPtr(), message.message_as_string,
+ sent_message_ports));
+}
+
+void NavigatorConnectServiceWorkerService::SendMessagesAreQueued(int route_id) {
+ NOTREACHED() << "navigator.connect endpoints should never queue messages.";
+}
+
+void NavigatorConnectServiceWorkerService::DeliverMessage(
+ const base::string16& message,
+ const std::vector<TransferredMessagePort>& sent_message_ports,
+ ServiceWorkerStatusCode service_worker_status,
+ const scoped_refptr<ServiceWorkerRegistration>&
+ service_worker_registration) {
+ if (service_worker_status != SERVICE_WORKER_OK) {
+ // TODO(mek): Do something when no service worker was found.
+ return;
+ }
+
+ ServiceWorkerVersion* active_version =
+ service_worker_registration->active_version();
+ if (!active_version) {
+ // TODO(mek): Do something when no active version exists.
+ return;
+ }
+
+ active_version->DispatchCrossOriginMessageEvent(
+ client_, message, sent_message_ports,
+ base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
+}
+
+} // namespace
+
+NavigatorConnectServiceWorkerServiceFactory::
+ NavigatorConnectServiceWorkerServiceFactory(const scoped_refptr<
+ ServiceWorkerContextWrapper>& service_worker_context)
+ : service_worker_context_(service_worker_context), weak_factory_(this) {
+}
+
+NavigatorConnectServiceWorkerServiceFactory::
+ ~NavigatorConnectServiceWorkerServiceFactory() {
+}
+
+bool NavigatorConnectServiceWorkerServiceFactory::HandlesUrl(
+ const GURL& target_url) {
+ // Always return true, all URLs could potentially have a service worker, and
+ // this factory will be installed as first factory, so it will only be used
+ // if no other factory claims to handle the url.
+ return true;
+}
+
+void NavigatorConnectServiceWorkerServiceFactory::Connect(
+ const NavigatorConnectClient& client,
+ const ConnectCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ // Find the right service worker to service this connection.
+ service_worker_context_->FindRegistrationForDocument(
+ client.target_url,
+ base::Bind(&NavigatorConnectServiceWorkerServiceFactory::
+ GotServiceWorkerRegistration,
+ weak_factory_.GetWeakPtr(), callback, client));
+}
+
+void NavigatorConnectServiceWorkerServiceFactory::GotServiceWorkerRegistration(
+ const ConnectCallback& callback,
+ const NavigatorConnectClient& client,
+ ServiceWorkerStatusCode status,
+ const scoped_refptr<ServiceWorkerRegistration>& registration) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (status != SERVICE_WORKER_OK) {
+ // No service worker found, reject connection attempt.
+ OnConnectResult(callback, client, registration, status, false);
+ return;
+ }
+
+ ServiceWorkerVersion* active_version = registration->active_version();
+ if (!active_version) {
+ // No active version, reject connection attempt.
+ OnConnectResult(callback, client, registration, status, false);
+ return;
+ }
+
+ active_version->DispatchCrossOriginConnectEvent(
+ base::Bind(&NavigatorConnectServiceWorkerServiceFactory::OnConnectResult,
+ weak_factory_.GetWeakPtr(), callback, client, registration),
+ client);
+}
+
+void NavigatorConnectServiceWorkerServiceFactory::OnConnectResult(
+ const ConnectCallback& callback,
+ const NavigatorConnectClient& client,
+ const scoped_refptr<ServiceWorkerRegistration>& service_worker_registration,
+ ServiceWorkerStatusCode status,
+ bool accept_connection) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (status != SERVICE_WORKER_OK || !accept_connection) {
+ callback.Run(nullptr, false);
+ return;
+ }
+
+ // TODO(mek): http://crbug.com/462744 Keep track of these
+ // NavigatorConnectServiceWorkerService instances and clean them up when a
+ // service worker registration is deleted.
+ callback.Run(
+ new NavigatorConnectServiceWorkerService(service_worker_context_, client,
+ service_worker_registration),
+ false);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/navigator_connect/navigator_connect_service_worker_service_factory.h b/chromium/content/browser/navigator_connect/navigator_connect_service_worker_service_factory.h
new file mode 100644
index 00000000000..4e0239f8c4d
--- /dev/null
+++ b/chromium/content/browser/navigator_connect/navigator_connect_service_worker_service_factory.h
@@ -0,0 +1,61 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_NAVIGATOR_CONNECT_NAVIGATOR_CONNECT_SERVICE_WORKER_SERVICE_FACTORY_H_
+#define CONTENT_BROWSER_NAVIGATOR_CONNECT_NAVIGATOR_CONNECT_SERVICE_WORKER_SERVICE_FACTORY_H_
+
+#include <map>
+
+#include "base/memory/weak_ptr.h"
+#include "content/common/service_worker/service_worker_status_code.h"
+#include "content/public/browser/navigator_connect_service_factory.h"
+
+namespace content {
+
+class ServiceWorkerContextWrapper;
+class ServiceWorkerRegistration;
+
+// Service worker specific NavigatorConnectServiceFactory implementation. This
+// class accepts all URLs (and thus has to be the first factory to be added to
+// NavigatorConnectContext or no other factories will ever by used).
+// Tries to find a service worker registration to handle the url being connected
+// to.
+class NavigatorConnectServiceWorkerServiceFactory
+ : public NavigatorConnectServiceFactory {
+ public:
+ explicit NavigatorConnectServiceWorkerServiceFactory(
+ const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context);
+ ~NavigatorConnectServiceWorkerServiceFactory() override;
+
+ // NavigatorConnectServiceFactory implementation.
+ bool HandlesUrl(const GURL& target_url) override;
+ void Connect(const NavigatorConnectClient& client,
+ const ConnectCallback& callback) override;
+
+ private:
+ // Callback called when the Service Worker context found (or didn't find) a
+ // service worker registration to serve a particular URL.
+ void GotServiceWorkerRegistration(
+ const ConnectCallback& callback,
+ const NavigatorConnectClient& client,
+ ServiceWorkerStatusCode status,
+ const scoped_refptr<ServiceWorkerRegistration>& registration);
+
+ // Callback called when the service worker finished handling the cross origin
+ // connection event.
+ void OnConnectResult(
+ const ConnectCallback& callback,
+ const NavigatorConnectClient& client,
+ const scoped_refptr<ServiceWorkerRegistration>& registration,
+ ServiceWorkerStatusCode status,
+ bool accept_connection);
+
+ scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_;
+ base::WeakPtrFactory<NavigatorConnectServiceWorkerServiceFactory>
+ weak_factory_;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_NAVIGATOR_CONNECT_NAVIGATOR_CONNECT_SERVICE_WORKER_SERVICE_FACTORY_H_
diff --git a/chromium/content/browser/net/sqlite_persistent_cookie_store.cc b/chromium/content/browser/net/sqlite_persistent_cookie_store.cc
index 1009d29c626..19731654fc8 100644
--- a/chromium/content/browser/net/sqlite_persistent_cookie_store.cc
+++ b/chromium/content/browser/net/sqlite_persistent_cookie_store.cc
@@ -12,14 +12,15 @@
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/callback.h"
-#include "base/command_line.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"
#include "base/memory/scoped_ptr.h"
+#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
+#include "base/profiler/scoped_tracker.h"
#include "base/sequenced_task_runner.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
@@ -27,13 +28,12 @@
#include "base/threading/sequenced_worker_pool.h"
#include "base/time/time.h"
#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/cookie_crypto_delegate.h"
#include "content/public/browser/cookie_store_factory.h"
-#include "content/public/common/content_switches.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "net/cookies/canonical_cookie.h"
#include "net/cookies/cookie_constants.h"
#include "net/cookies/cookie_util.h"
+#include "net/extras/sqlite/cookie_crypto_delegate.h"
#include "sql/error_delegate_util.h"
#include "sql/meta_table.h"
#include "sql/statement.h"
@@ -44,6 +44,15 @@
using base::Time;
+namespace {
+
+// The persistent cookie store is loaded into memory on eTLD at a time. This
+// variable controls the delay between loading eTLDs, so as to not overload the
+// CPU or I/O with these low priority requests immediately after start up.
+const int kLoadDelayMilliseconds = 0;
+
+} // namespace
+
namespace content {
// This class is designed to be shared between any client thread and the
@@ -77,7 +86,7 @@ class SQLitePersistentCookieStore::Backend
const scoped_refptr<base::SequencedTaskRunner>& background_task_runner,
bool restore_old_session_cookies,
storage::SpecialStoragePolicy* special_storage_policy,
- CookieCryptoDelegate* crypto_delegate)
+ net::CookieCryptoDelegate* crypto_delegate)
: path_(path),
num_pending_(0),
force_keep_session_state_(false),
@@ -99,6 +108,12 @@ class SQLitePersistentCookieStore::Backend
void LoadCookiesForKey(const std::string& domain,
const LoadedCallback& loaded_callback);
+ // Steps through all results of |smt|, makes a cookie from each, and adds the
+ // cookie to |cookies|. This method also updates |cookies_per_origin_| and
+ // |num_cookies_read_|.
+ void MakeCookiesFromSQLStatement(std::vector<net::CanonicalCookie*>* cookies,
+ sql::Statement* statement);
+
// Batch a cookie addition.
void AddCookie(const net::CanonicalCookie& cc);
@@ -124,6 +139,10 @@ class SQLitePersistentCookieStore::Backend
~Backend() {
DCHECK(!db_.get()) << "Close should have already been called.";
DCHECK(num_pending_ == 0 && pending_.empty());
+
+ for (net::CanonicalCookie* cookie : cookies_) {
+ delete cookie;
+ }
}
// Database upgrade statements.
@@ -172,7 +191,8 @@ class SQLitePersistentCookieStore::Backend
// Sends notification when a single priority load completes. Updates priority
// load metric data. The data is sent only after the final load completes.
void CompleteLoadForKeyInForeground(const LoadedCallback& loaded_callback,
- bool load_success);
+ bool load_success,
+ const base::Time& requested_at);
// Sends all metrics, including posting a ReportMetricsInBackground task.
// Called after all priority and regular loading is complete.
@@ -213,6 +233,11 @@ class SQLitePersistentCookieStore::Backend
void PostClientTask(const tracked_objects::Location& origin,
const base::Closure& task);
+ // Shared code between the different load strategies to be used after all
+ // cookies have been loaded.
+ void FinishedLoadingCookies(const LoadedCallback& loaded_callback,
+ bool success);
+
base::FilePath path_;
scoped_ptr<sql::Connection> db_;
sql::MetaTable meta_table_;
@@ -228,6 +253,8 @@ class SQLitePersistentCookieStore::Backend
// Temporary buffer for cookies loaded from DB. Accumulates cookies to reduce
// the number of messages sent to the client runner. Sent back in response to
// individual load requests for domain keys or when all loading completes.
+ // Ownership of the cookies in this vector is transferred to the client in
+ // response to individual load requests or when all loading completes.
std::vector<net::CanonicalCookie*> cookies_;
// Map of domain keys(eTLD+1) to domains/hosts that are to be loaded from DB.
@@ -277,7 +304,7 @@ class SQLitePersistentCookieStore::Backend
// cookies stored persistently).
//
// Not owned.
- CookieCryptoDelegate* crypto_;
+ net::CookieCryptoDelegate* crypto_;
DISALLOW_COPY_AND_ASSIGN(Backend);
};
@@ -286,6 +313,13 @@ namespace {
// Version number of the database.
//
+// Version 9 adds a partial index to track non-persistent cookies.
+// Non-persistent cookies sometimes need to be deleted on startup. There are
+// frequently few or no non-persistent cookies, so the partial index allows the
+// deletion to be sped up or skipped, without having to page in the DB.
+//
+// Version 8 adds "first-party only" cookies.
+//
// Version 7 adds encrypted values. Old values will continue to be used but
// all new values written will be encrypted on selected operating systems. New
// records read by old clients will simply get an empty cookie value while old
@@ -309,7 +343,7 @@ namespace {
// Version 3 updated the database to include the last access time, so we can
// expire them in decreasing order of use when we've reached the maximum
// number of cookies.
-const int kCurrentVersionNumber = 7;
+const int kCurrentVersionNumber = 9;
const int kCompatibleVersionNumber = 5;
// Possible values for the 'priority' column.
@@ -372,34 +406,43 @@ class IncrementTimeDelta {
// Initializes the cookies table, returning true on success.
bool InitTable(sql::Connection* db) {
- if (!db->DoesTableExist("cookies")) {
- std::string stmt(base::StringPrintf(
- "CREATE TABLE cookies ("
- "creation_utc INTEGER NOT NULL UNIQUE PRIMARY KEY,"
- "host_key TEXT NOT NULL,"
- "name TEXT NOT NULL,"
- "value TEXT NOT NULL,"
- "path TEXT NOT NULL,"
- "expires_utc INTEGER NOT NULL,"
- "secure INTEGER NOT NULL,"
- "httponly INTEGER NOT NULL,"
- "last_access_utc INTEGER NOT NULL, "
- "has_expires INTEGER NOT NULL DEFAULT 1, "
- "persistent INTEGER NOT NULL DEFAULT 1,"
- "priority INTEGER NOT NULL DEFAULT %d,"
- "encrypted_value BLOB DEFAULT '')",
- CookiePriorityToDBCookiePriority(net::COOKIE_PRIORITY_DEFAULT)));
- if (!db->Execute(stmt.c_str()))
- return false;
- }
+ if (db->DoesTableExist("cookies"))
+ return true;
+
+ std::string stmt(base::StringPrintf(
+ "CREATE TABLE cookies ("
+ "creation_utc INTEGER NOT NULL UNIQUE PRIMARY KEY,"
+ "host_key TEXT NOT NULL,"
+ "name TEXT NOT NULL,"
+ "value TEXT NOT NULL,"
+ "path TEXT NOT NULL,"
+ "expires_utc INTEGER NOT NULL,"
+ "secure INTEGER NOT NULL,"
+ "httponly INTEGER NOT NULL,"
+ "last_access_utc INTEGER NOT NULL, "
+ "has_expires INTEGER NOT NULL DEFAULT 1, "
+ "persistent INTEGER NOT NULL DEFAULT 1,"
+ "priority INTEGER NOT NULL DEFAULT %d,"
+ "encrypted_value BLOB DEFAULT '',"
+ "firstpartyonly INTEGER NOT NULL DEFAULT 0)",
+ CookiePriorityToDBCookiePriority(net::COOKIE_PRIORITY_DEFAULT)));
+ if (!db->Execute(stmt.c_str()))
+ return false;
- // Older code created an index on creation_utc, which is already
- // primary key for the table.
- if (!db->Execute("DROP INDEX IF EXISTS cookie_times"))
+ if (!db->Execute("CREATE INDEX domain ON cookies(host_key)"))
return false;
- if (!db->Execute("CREATE INDEX IF NOT EXISTS domain ON cookies(host_key)"))
+#if defined(OS_IOS)
+ // iOS 8.1 and older doesn't support partial indices. iOS 8.2 supports
+ // partial indices.
+ if (!db->Execute("CREATE INDEX is_transient ON cookies(persistent)")) {
+#else
+ if (!db->Execute(
+ "CREATE INDEX is_transient ON cookies(persistent) "
+ "where persistent != 1")) {
+#endif
return false;
+ }
return true;
}
@@ -408,8 +451,6 @@ bool InitTable(sql::Connection* db) {
void SQLitePersistentCookieStore::Backend::Load(
const LoadedCallback& loaded_callback) {
- // This function should be called only once per instance.
- DCHECK(!db_.get());
PostBackgroundTask(FROM_HERE, base::Bind(
&Backend::LoadAndNotifyInBackground, this,
loaded_callback, base::Time::Now()));
@@ -477,14 +518,21 @@ void SQLitePersistentCookieStore::Backend::LoadKeyAndNotifyInBackground(
PostClientTask(FROM_HERE, base::Bind(
&SQLitePersistentCookieStore::Backend::CompleteLoadForKeyInForeground,
- this, loaded_callback, success));
+ this, loaded_callback, success, posted_at));
}
void SQLitePersistentCookieStore::Backend::CompleteLoadForKeyInForeground(
const LoadedCallback& loaded_callback,
- bool load_success) {
+ bool load_success,
+ const::Time& requested_at) {
DCHECK(client_task_runner_->RunsTasksOnCurrentThread());
+ UMA_HISTOGRAM_CUSTOM_TIMES(
+ "Cookie.TimeKeyLoadTotalWait",
+ base::Time::Now() - requested_at,
+ base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(1),
+ 50);
+
Notify(loaded_callback, load_success);
{
@@ -652,6 +700,9 @@ bool SQLitePersistentCookieStore::Backend::InitializeDatabase() {
50);
initialized_ = true;
+
+ if (!restore_old_session_cookies_)
+ DeleteSessionCookiesOnStartup();
return true;
}
@@ -677,14 +728,16 @@ void SQLitePersistentCookieStore::Backend::ChainLoadCookies(
// then post a background task to continue chain-load;
// Otherwise notify on client runner.
if (load_success && keys_to_load_.size() > 0) {
- PostBackgroundTask(FROM_HERE, base::Bind(
- &Backend::ChainLoadCookies, this, loaded_callback));
+ bool success = background_task_runner_->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&Backend::ChainLoadCookies, this, loaded_callback),
+ base::TimeDelta::FromMilliseconds(kLoadDelayMilliseconds));
+ if (!success) {
+ LOG(WARNING) << "Failed to post task from " << FROM_HERE.ToString()
+ << " to background_task_runner_.";
+ }
} else {
- PostClientTask(FROM_HERE, base::Bind(
- &Backend::CompleteLoadInForeground, this,
- loaded_callback, load_success));
- if (load_success && !restore_old_session_cookies_)
- DeleteSessionCookiesOnStartup();
+ FinishedLoadingCookies(loaded_callback, load_success);
}
}
@@ -697,14 +750,14 @@ bool SQLitePersistentCookieStore::Backend::LoadCookiesForDomains(
smt.Assign(db_->GetCachedStatement(
SQL_FROM_HERE,
"SELECT creation_utc, host_key, name, value, encrypted_value, path, "
- "expires_utc, secure, httponly, last_access_utc, has_expires, "
- "persistent, priority FROM cookies WHERE host_key = ?"));
+ "expires_utc, secure, httponly, firstpartyonly, last_access_utc, "
+ "has_expires, persistent, priority FROM cookies WHERE host_key = ?"));
} else {
smt.Assign(db_->GetCachedStatement(
SQL_FROM_HERE,
"SELECT creation_utc, host_key, name, value, encrypted_value, path, "
- "expires_utc, secure, httponly, last_access_utc, has_expires, "
- "persistent, priority FROM cookies WHERE host_key = ? "
+ "expires_utc, secure, httponly, firstpartyonly, last_access_utc, "
+ "has_expires, persistent, priority FROM cookies WHERE host_key = ? "
"AND persistent = 1"));
}
if (!smt.is_valid()) {
@@ -718,35 +771,7 @@ bool SQLitePersistentCookieStore::Backend::LoadCookiesForDomains(
std::set<std::string>::const_iterator it = domains.begin();
for (; it != domains.end(); ++it) {
smt.BindString(0, *it);
- while (smt.Step()) {
- std::string value;
- std::string encrypted_value = smt.ColumnString(4);
- if (!encrypted_value.empty() && crypto_) {
- crypto_->DecryptString(encrypted_value, &value);
- } else {
- DCHECK(encrypted_value.empty());
- value = smt.ColumnString(3);
- }
- scoped_ptr<net::CanonicalCookie> cc(new net::CanonicalCookie(
- // The "source" URL is not used with persisted cookies.
- GURL(), // Source
- smt.ColumnString(2), // name
- value, // value
- smt.ColumnString(1), // domain
- smt.ColumnString(5), // path
- Time::FromInternalValue(smt.ColumnInt64(0)), // creation_utc
- Time::FromInternalValue(smt.ColumnInt64(6)), // expires_utc
- Time::FromInternalValue(smt.ColumnInt64(9)), // last_access_utc
- smt.ColumnInt(7) != 0, // secure
- smt.ColumnInt(8) != 0, // httponly
- DBCookiePriorityToCookiePriority(
- static_cast<DBCookiePriority>(smt.ColumnInt(12))))); // priority
- DLOG_IF(WARNING,
- cc->CreationDate() > Time::Now()) << L"CreationDate too recent";
- cookies_per_origin_[CookieOrigin(cc->Domain(), cc->IsSecure())]++;
- cookies.push_back(cc.release());
- ++num_cookies_read_;
- }
+ MakeCookiesFromSQLStatement(&cookies, &smt);
smt.Reset(true);
}
{
@@ -756,6 +781,42 @@ bool SQLitePersistentCookieStore::Backend::LoadCookiesForDomains(
return true;
}
+void SQLitePersistentCookieStore::Backend::MakeCookiesFromSQLStatement(
+ std::vector<net::CanonicalCookie*>* cookies,
+ sql::Statement* statement) {
+ sql::Statement& smt = *statement;
+ while (smt.Step()) {
+ std::string value;
+ std::string encrypted_value = smt.ColumnString(4);
+ if (!encrypted_value.empty() && crypto_) {
+ crypto_->DecryptString(encrypted_value, &value);
+ } else {
+ DCHECK(encrypted_value.empty());
+ value = smt.ColumnString(3);
+ }
+ scoped_ptr<net::CanonicalCookie> cc(new net::CanonicalCookie(
+ // The "source" URL is not used with persisted cookies.
+ GURL(), // Source
+ smt.ColumnString(2), // name
+ value, // value
+ smt.ColumnString(1), // domain
+ smt.ColumnString(5), // path
+ Time::FromInternalValue(smt.ColumnInt64(0)), // creation_utc
+ Time::FromInternalValue(smt.ColumnInt64(6)), // expires_utc
+ Time::FromInternalValue(smt.ColumnInt64(10)), // last_access_utc
+ smt.ColumnInt(7) != 0, // secure
+ smt.ColumnInt(8) != 0, // httponly
+ smt.ColumnInt(9) != 0, // firstpartyonly
+ DBCookiePriorityToCookiePriority(
+ static_cast<DBCookiePriority>(smt.ColumnInt(13))))); // priority
+ DLOG_IF(WARNING, cc->CreationDate() > Time::Now())
+ << L"CreationDate too recent";
+ cookies_per_origin_[CookieOrigin(cc->Domain(), cc->IsSecure())]++;
+ cookies->push_back(cc.release());
+ ++num_cookies_read_;
+ }
+}
+
bool SQLitePersistentCookieStore::Backend::EnsureDatabaseVersion() {
// Version check.
if (!meta_table_.Init(
@@ -883,6 +944,68 @@ bool SQLitePersistentCookieStore::Backend::EnsureDatabaseVersion() {
base::TimeTicks::Now() - start_time);
}
+ if (cur_version == 7) {
+ const base::TimeTicks start_time = base::TimeTicks::Now();
+ sql::Transaction transaction(db_.get());
+ if (!transaction.Begin())
+ return false;
+ // Alter the table to add a 'firstpartyonly' column.
+ if (!db_->Execute(
+ "ALTER TABLE cookies "
+ "ADD COLUMN firstpartyonly INTEGER DEFAULT 0")) {
+ LOG(WARNING) << "Unable to update cookie database to version 8.";
+ return false;
+ }
+ ++cur_version;
+ meta_table_.SetVersionNumber(cur_version);
+ meta_table_.SetCompatibleVersionNumber(
+ std::min(cur_version, kCompatibleVersionNumber));
+ transaction.Commit();
+ UMA_HISTOGRAM_TIMES("Cookie.TimeDatabaseMigrationToV8",
+ base::TimeTicks::Now() - start_time);
+ }
+
+ if (cur_version == 8) {
+ const base::TimeTicks start_time = base::TimeTicks::Now();
+ sql::Transaction transaction(db_.get());
+ if (!transaction.Begin())
+ return false;
+
+ if (!db_->Execute("DROP INDEX IF EXISTS cookie_times")) {
+ LOG(WARNING)
+ << "Unable to drop table cookie_times in update to version 9.";
+ return false;
+ }
+
+ if (!db_->Execute(
+ "CREATE INDEX IF NOT EXISTS domain ON cookies(host_key)")) {
+ LOG(WARNING) << "Unable to create index domain in update to version 9.";
+ return false;
+ }
+
+#if defined(OS_IOS)
+ // iOS 8.1 and older doesn't support partial indices. iOS 8.2 supports
+ // partial indices.
+ if (!db_->Execute(
+ "CREATE INDEX IF NOT EXISTS is_transient ON cookies(persistent)")) {
+#else
+ if (!db_->Execute(
+ "CREATE INDEX IF NOT EXISTS is_transient ON cookies(persistent) "
+ "where persistent != 1")) {
+#endif
+ LOG(WARNING)
+ << "Unable to create index is_transient in update to version 9.";
+ return false;
+ }
+ ++cur_version;
+ meta_table_.SetVersionNumber(cur_version);
+ meta_table_.SetCompatibleVersionNumber(
+ std::min(cur_version, kCompatibleVersionNumber));
+ transaction.Commit();
+ UMA_HISTOGRAM_TIMES("Cookie.TimeDatabaseMigrationToV9",
+ base::TimeTicks::Now() - start_time);
+ }
+
// Put future migration cases here.
if (cur_version < kCurrentVersionNumber) {
@@ -890,7 +1013,7 @@ bool SQLitePersistentCookieStore::Backend::EnsureDatabaseVersion() {
meta_table_.Reset();
db_.reset(new sql::Connection);
- if (!base::DeleteFile(path_, false) ||
+ if (!sql::Connection::Delete(path_) ||
!db_->Open(path_) ||
!meta_table_.Init(
db_.get(), kCurrentVersionNumber, kCompatibleVersionNumber)) {
@@ -966,11 +1089,12 @@ void SQLitePersistentCookieStore::Backend::Commit() {
if (!db_.get() || ops.empty())
return;
- sql::Statement add_smt(db_->GetCachedStatement(SQL_FROM_HERE,
+ sql::Statement add_smt(db_->GetCachedStatement(
+ SQL_FROM_HERE,
"INSERT INTO cookies (creation_utc, host_key, name, value, "
- "encrypted_value, path, expires_utc, secure, httponly, last_access_utc, "
- "has_expires, persistent, priority) "
- "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)"));
+ "encrypted_value, path, expires_utc, secure, httponly, firstpartyonly, "
+ "last_access_utc, has_expires, persistent, priority) "
+ "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
if (!add_smt.is_valid())
return;
@@ -1015,11 +1139,12 @@ void SQLitePersistentCookieStore::Backend::Commit() {
add_smt.BindInt64(6, po->cc().ExpiryDate().ToInternalValue());
add_smt.BindInt(7, po->cc().IsSecure());
add_smt.BindInt(8, po->cc().IsHttpOnly());
- add_smt.BindInt64(9, po->cc().LastAccessDate().ToInternalValue());
- add_smt.BindInt(10, po->cc().IsPersistent());
+ add_smt.BindInt(9, po->cc().IsFirstPartyOnly());
+ add_smt.BindInt64(10, po->cc().LastAccessDate().ToInternalValue());
add_smt.BindInt(11, po->cc().IsPersistent());
- add_smt.BindInt(
- 12, CookiePriorityToDBCookiePriority(po->cc().Priority()));
+ add_smt.BindInt(12, po->cc().IsPersistent());
+ add_smt.BindInt(13,
+ CookiePriorityToDBCookiePriority(po->cc().Priority()));
if (!add_smt.Run())
NOTREACHED() << "Could not add a cookie to the DB.";
break;
@@ -1180,8 +1305,14 @@ void SQLitePersistentCookieStore::Backend::SetForceKeepSessionState() {
void SQLitePersistentCookieStore::Backend::DeleteSessionCookiesOnStartup() {
DCHECK(background_task_runner_->RunsTasksOnCurrentThread());
- if (!db_->Execute("DELETE FROM cookies WHERE persistent == 0"))
+ base::Time start_time = base::Time::Now();
+ if (!db_->Execute("DELETE FROM cookies WHERE persistent != 1"))
LOG(WARNING) << "Unable to delete session cookies.";
+
+ UMA_HISTOGRAM_TIMES("Cookie.Startup.TimeSpentDeletingCookies",
+ base::Time::Now() - start_time);
+ UMA_HISTOGRAM_COUNTS("Cookie.Startup.NumberOfCookiesDeleted",
+ db_->GetLastChangeCount());
}
void SQLitePersistentCookieStore::Backend::PostBackgroundTask(
@@ -1200,13 +1331,20 @@ void SQLitePersistentCookieStore::Backend::PostClientTask(
}
}
+void SQLitePersistentCookieStore::Backend::FinishedLoadingCookies(
+ const LoadedCallback& loaded_callback,
+ bool success) {
+ PostClientTask(FROM_HERE, base::Bind(&Backend::CompleteLoadInForeground, this,
+ loaded_callback, success));
+}
+
SQLitePersistentCookieStore::SQLitePersistentCookieStore(
const base::FilePath& path,
const scoped_refptr<base::SequencedTaskRunner>& client_task_runner,
const scoped_refptr<base::SequencedTaskRunner>& background_task_runner,
bool restore_old_session_cookies,
storage::SpecialStoragePolicy* special_storage_policy,
- CookieCryptoDelegate* crypto_delegate)
+ net::CookieCryptoDelegate* crypto_delegate)
: backend_(new Backend(path,
client_task_runner,
background_task_runner,
@@ -1275,6 +1413,10 @@ CookieStoreConfig::~CookieStoreConfig() {
}
net::CookieStore* CreateCookieStore(const CookieStoreConfig& config) {
+ // TODO(bcwhite): Remove ScopedTracker below once crbug.com/483686 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION("483686 content::CreateCookieStore"));
+
net::CookieMonster* cookie_monster = NULL;
if (config.path.empty()) {
@@ -1317,11 +1459,6 @@ net::CookieStore* CreateCookieStore(const CookieStoreConfig& config) {
}
}
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableFileCookies)) {
- cookie_monster->SetEnableFileScheme(true);
- }
-
return cookie_monster;
}
diff --git a/chromium/content/browser/net/sqlite_persistent_cookie_store.h b/chromium/content/browser/net/sqlite_persistent_cookie_store.h
index 786b6b6725a..09835ba6216 100644
--- a/chromium/content/browser/net/sqlite_persistent_cookie_store.h
+++ b/chromium/content/browser/net/sqlite_persistent_cookie_store.h
@@ -25,6 +25,7 @@ class SequencedTaskRunner;
namespace net {
class CanonicalCookie;
+class CookieCryptoDelegate;
}
namespace storage {
@@ -32,7 +33,6 @@ class SpecialStoragePolicy;
}
namespace content {
-class CookieCryptoDelegate;
// Implements the PersistentCookieStore interface in terms of a SQLite database.
// For documentation about the actual member functions consult the documentation
@@ -51,7 +51,7 @@ class CONTENT_EXPORT SQLitePersistentCookieStore
const scoped_refptr<base::SequencedTaskRunner>& background_task_runner,
bool restore_old_session_cookies,
storage::SpecialStoragePolicy* special_storage_policy,
- CookieCryptoDelegate* crypto_delegate);
+ net::CookieCryptoDelegate* crypto_delegate);
// net::CookieMonster::PersistentCookieStore:
void Load(const LoadedCallback& loaded_callback) override;
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 21f3c85d8f5..7421bf15a96 100644
--- a/chromium/content/browser/net/sqlite_persistent_cookie_store_perftest.cc
+++ b/chromium/content/browser/net/sqlite_persistent_cookie_store_perftest.cc
@@ -13,9 +13,9 @@
#include "base/test/perf_time_logger.h"
#include "base/test/sequenced_worker_pool_owner.h"
#include "base/threading/sequenced_worker_pool.h"
-#include "content/public/browser/cookie_crypto_delegate.h"
#include "net/cookies/canonical_cookie.h"
#include "net/cookies/cookie_constants.h"
+#include "net/extras/sqlite/cookie_crypto_delegate.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
@@ -78,11 +78,9 @@ class SQLitePersistentCookieStorePerfTest : public testing::Test {
GURL gurl("www" + domain_name);
for (int cookie_num = 0; cookie_num < 50; ++cookie_num) {
t += base::TimeDelta::FromInternalValue(10);
- store_->AddCookie(
- net::CanonicalCookie(gurl,
- base::StringPrintf("Cookie_%d", cookie_num), "1",
- domain_name, "/", t, t, t, false, false,
- net::COOKIE_PRIORITY_DEFAULT));
+ store_->AddCookie(net::CanonicalCookie(
+ gurl, base::StringPrintf("Cookie_%d", cookie_num), "1", domain_name,
+ "/", t, t, t, false, false, false, net::COOKIE_PRIORITY_DEFAULT));
}
}
// Replace the store effectively destroying the current one and forcing it
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 47590d7274b..af7859a26a9 100644
--- a/chromium/content/browser/net/sqlite_persistent_cookie_store_unittest.cc
+++ b/chromium/content/browser/net/sqlite_persistent_cookie_store_unittest.cc
@@ -19,12 +19,12 @@
#include "base/test/sequenced_worker_pool_owner.h"
#include "base/threading/sequenced_worker_pool.h"
#include "base/time/time.h"
-#include "content/public/browser/cookie_crypto_delegate.h"
#include "content/public/browser/cookie_store_factory.h"
#include "crypto/encryptor.h"
#include "crypto/symmetric_key.h"
#include "net/cookies/canonical_cookie.h"
#include "net/cookies/cookie_constants.h"
+#include "net/extras/sqlite/cookie_crypto_delegate.h"
#include "sql/connection.h"
#include "sql/meta_table.h"
#include "sql/statement.h"
@@ -37,7 +37,7 @@ namespace {
const base::FilePath::CharType kCookieFilename[] = FILE_PATH_LITERAL("Cookies");
-class CookieCryptor : public content::CookieCryptoDelegate {
+class CookieCryptor : public net::CookieCryptoDelegate {
public:
CookieCryptor();
bool EncryptString(const std::string& plaintext,
@@ -159,10 +159,20 @@ class SQLitePersistentCookieStoreTest : public testing::Test {
const std::string& domain,
const std::string& path,
const base::Time& creation) {
- store_->AddCookie(
- net::CanonicalCookie(GURL(), name, value, domain, path, creation,
- creation, creation, false, false,
- net::COOKIE_PRIORITY_DEFAULT));
+ store_->AddCookie(net::CanonicalCookie(
+ GURL(), name, value, domain, path, creation, creation, creation, false,
+ false, false, net::COOKIE_PRIORITY_DEFAULT));
+ }
+
+ void AddCookieWithExpiration(const std::string& name,
+ const std::string& value,
+ const std::string& domain,
+ const std::string& path,
+ const base::Time& creation,
+ const base::Time& expiration) {
+ store_->AddCookie(net::CanonicalCookie(
+ GURL(), name, value, domain, path, creation, expiration, creation,
+ false, false, false, net::COOKIE_PRIORITY_DEFAULT));
}
std::string ReadRawDBContents() {
@@ -189,7 +199,7 @@ class SQLitePersistentCookieStoreTest : public testing::Test {
CanonicalCookieVector cookies_;
base::ScopedTempDir temp_dir_;
scoped_refptr<SQLitePersistentCookieStore> store_;
- scoped_ptr<content::CookieCryptoDelegate> cookie_crypto_delegate_;
+ scoped_ptr<net::CookieCryptoDelegate> cookie_crypto_delegate_;
};
TEST_F(SQLitePersistentCookieStoreTest, TestInvalidMetaTableRecovery) {
@@ -258,6 +268,82 @@ TEST_F(SQLitePersistentCookieStoreTest, TestPersistance) {
ASSERT_EQ(0U, cookies.size());
}
+TEST_F(SQLitePersistentCookieStoreTest, TestSessionCookiesDeletedOnStartup) {
+ // Initialize the cookie store with 3 persistent cookies, 5 transient
+ // cookies.
+ InitializeStore(false, false);
+
+ // Add persistent cookies.
+ base::Time t = base::Time::Now();
+ AddCookie("A", "B", "a1.com", "/", t);
+ t += base::TimeDelta::FromInternalValue(10);
+ AddCookie("A", "B", "a2.com", "/", t);
+ t += base::TimeDelta::FromInternalValue(10);
+ AddCookie("A", "B", "a3.com", "/", t);
+
+ // Add transient cookies.
+ t += base::TimeDelta::FromInternalValue(10);
+ AddCookieWithExpiration("A", "B", "b1.com", "/", t, base::Time());
+ t += base::TimeDelta::FromInternalValue(10);
+ AddCookieWithExpiration("A", "B", "b2.com", "/", t, base::Time());
+ t += base::TimeDelta::FromInternalValue(10);
+ AddCookieWithExpiration("A", "B", "b3.com", "/", t, base::Time());
+ t += base::TimeDelta::FromInternalValue(10);
+ AddCookieWithExpiration("A", "B", "b4.com", "/", t, base::Time());
+ t += base::TimeDelta::FromInternalValue(10);
+ AddCookieWithExpiration("A", "B", "b5.com", "/", t, base::Time());
+ DestroyStore();
+
+ // Load the store a second time. Before the store finishes loading, add a
+ // transient cookie and flush it to disk.
+ store_ = new SQLitePersistentCookieStore(
+ temp_dir_.path().Append(kCookieFilename),
+ client_task_runner(),
+ background_task_runner(),
+ false, NULL, NULL);
+
+ // Posting a blocking task to db_thread_ makes sure that the DB thread waits
+ // until both Load and Flush have been posted to its task queue.
+ background_task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&SQLitePersistentCookieStoreTest::WaitOnDBEvent,
+ base::Unretained(this)));
+ store_->Load(base::Bind(&SQLitePersistentCookieStoreTest::OnLoaded,
+ base::Unretained(this)));
+ t += base::TimeDelta::FromInternalValue(10);
+ AddCookieWithExpiration("A", "B", "c.com", "/", t, base::Time());
+ base::WaitableEvent event(false, false);
+ store_->Flush(base::Bind(&base::WaitableEvent::Signal,
+ base::Unretained(&event)));
+
+ // Now the DB-thread queue contains:
+ // (active:)
+ // 1. Wait (on db_event)
+ // (pending:)
+ // 2. "Init And Chain-Load First Domain"
+ // 3. Add Cookie (c.com)
+ // 4. Flush Cookie (c.com)
+ db_thread_event_.Signal();
+ event.Wait();
+ loaded_event_.Wait();
+ STLDeleteElements(&cookies_);
+ DestroyStore();
+
+ // Load the store a third time, this time restoring session cookies. The
+ // store should contain exactly 4 cookies: the 3 persistent, and "c.com",
+ // which was added during the second cookie store load.
+ store_ = new SQLitePersistentCookieStore(
+ temp_dir_.path().Append(kCookieFilename),
+ client_task_runner(),
+ background_task_runner(),
+ true, NULL, NULL);
+ store_->Load(base::Bind(&SQLitePersistentCookieStoreTest::OnLoaded,
+ base::Unretained(this)));
+ loaded_event_.Wait();
+ ASSERT_EQ(4u, cookies_.size());
+ STLDeleteElements(&cookies_);
+}
+
// Test that priority load of cookies for a specfic domain key could be
// completed before the entire store is loaded
TEST_F(SQLitePersistentCookieStoreTest, TestLoadCookiesForKey) {
@@ -361,11 +447,10 @@ TEST_F(SQLitePersistentCookieStoreTest, TestLoadOldSessionCookies) {
InitializeStore(false, true);
// Add a session cookie.
- store_->AddCookie(
- net::CanonicalCookie(
- GURL(), "C", "D", "sessioncookie.com", "/", base::Time::Now(),
- base::Time(), base::Time::Now(), false, false,
- net::COOKIE_PRIORITY_DEFAULT));
+ store_->AddCookie(net::CanonicalCookie(GURL(), "C", "D", "sessioncookie.com",
+ "/", base::Time::Now(), base::Time(),
+ base::Time::Now(), false, false, false,
+ net::COOKIE_PRIORITY_DEFAULT));
// Force the store to write its data to the disk.
DestroyStore();
@@ -389,11 +474,10 @@ TEST_F(SQLitePersistentCookieStoreTest, TestDontLoadOldSessionCookies) {
InitializeStore(false, true);
// Add a session cookie.
- store_->AddCookie(
- net::CanonicalCookie(
- GURL(), "C", "D", "sessioncookie.com", "/", base::Time::Now(),
- base::Time(), base::Time::Now(), false, false,
- net::COOKIE_PRIORITY_DEFAULT));
+ store_->AddCookie(net::CanonicalCookie(GURL(), "C", "D", "sessioncookie.com",
+ "/", base::Time::Now(), base::Time(),
+ base::Time::Now(), false, false, false,
+ net::COOKIE_PRIORITY_DEFAULT));
// Force the store to write its data to the disk.
DestroyStore();
@@ -420,19 +504,16 @@ TEST_F(SQLitePersistentCookieStoreTest, PersistIsPersistent) {
static const char kPersistentName[] = "persistent";
// Add a session cookie.
- store_->AddCookie(
- net::CanonicalCookie(
- GURL(), kSessionName, "val", "sessioncookie.com", "/",
- base::Time::Now(), base::Time(), base::Time::Now(), false, false,
- net::COOKIE_PRIORITY_DEFAULT));
+ store_->AddCookie(net::CanonicalCookie(
+ GURL(), kSessionName, "val", "sessioncookie.com", "/", base::Time::Now(),
+ base::Time(), base::Time::Now(), false, false, false,
+ net::COOKIE_PRIORITY_DEFAULT));
// Add a persistent cookie.
- store_->AddCookie(
- net::CanonicalCookie(
- GURL(), kPersistentName, "val", "sessioncookie.com", "/",
- base::Time::Now() - base::TimeDelta::FromDays(1),
- base::Time::Now() + base::TimeDelta::FromDays(1),
- base::Time::Now(), false, false,
- net::COOKIE_PRIORITY_DEFAULT));
+ store_->AddCookie(net::CanonicalCookie(
+ GURL(), kPersistentName, "val", "sessioncookie.com", "/",
+ base::Time::Now() - base::TimeDelta::FromDays(1),
+ base::Time::Now() + base::TimeDelta::FromDays(1), base::Time::Now(),
+ false, false, false, net::COOKIE_PRIORITY_DEFAULT));
// Force the store to write its data to the disk.
DestroyStore();
@@ -473,31 +554,25 @@ TEST_F(SQLitePersistentCookieStoreTest, PriorityIsPersistent) {
InitializeStore(false, true);
// Add a low-priority persistent cookie.
- store_->AddCookie(
- net::CanonicalCookie(
- GURL(), kLowName, kCookieValue, kCookieDomain, kCookiePath,
- base::Time::Now() - base::TimeDelta::FromMinutes(1),
- base::Time::Now() + base::TimeDelta::FromDays(1),
- base::Time::Now(), false, false,
- net::COOKIE_PRIORITY_LOW));
+ store_->AddCookie(net::CanonicalCookie(
+ GURL(), kLowName, kCookieValue, kCookieDomain, kCookiePath,
+ base::Time::Now() - base::TimeDelta::FromMinutes(1),
+ base::Time::Now() + base::TimeDelta::FromDays(1), base::Time::Now(),
+ false, false, false, net::COOKIE_PRIORITY_LOW));
// Add a medium-priority persistent cookie.
- store_->AddCookie(
- net::CanonicalCookie(
- GURL(), kMediumName, kCookieValue, kCookieDomain, kCookiePath,
- base::Time::Now() - base::TimeDelta::FromMinutes(2),
- base::Time::Now() + base::TimeDelta::FromDays(1),
- base::Time::Now(), false, false,
- net::COOKIE_PRIORITY_MEDIUM));
+ store_->AddCookie(net::CanonicalCookie(
+ GURL(), kMediumName, kCookieValue, kCookieDomain, kCookiePath,
+ base::Time::Now() - base::TimeDelta::FromMinutes(2),
+ base::Time::Now() + base::TimeDelta::FromDays(1), base::Time::Now(),
+ false, false, false, net::COOKIE_PRIORITY_MEDIUM));
// Add a high-priority peristent cookie.
- store_->AddCookie(
- net::CanonicalCookie(
- GURL(), kHighName, kCookieValue, kCookieDomain, kCookiePath,
- base::Time::Now() - base::TimeDelta::FromMinutes(3),
- base::Time::Now() + base::TimeDelta::FromDays(1),
- base::Time::Now(), false, false,
- net::COOKIE_PRIORITY_HIGH));
+ store_->AddCookie(net::CanonicalCookie(
+ GURL(), kHighName, kCookieValue, kCookieDomain, kCookiePath,
+ base::Time::Now() - base::TimeDelta::FromMinutes(3),
+ base::Time::Now() + base::TimeDelta::FromDays(1), base::Time::Now(),
+ false, false, false, net::COOKIE_PRIORITY_HIGH));
// Force the store to write its data to the disk.
DestroyStore();
diff --git a/chromium/content/browser/net_info_browsertest.cc b/chromium/content/browser/net_info_browsertest.cc
index cea69620487..fb805f3ec40 100644
--- a/chromium/content/browser/net_info_browsertest.cc
+++ b/chromium/content/browser/net_info_browsertest.cc
@@ -21,7 +21,7 @@ class NetInfoBrowserTest : public content::ContentBrowserTest {
}
#if defined(OS_CHROMEOS)
- virtual void SetUp() override {
+ void SetUp() override {
// ChromeOS's NetworkChangeNotifier isn't known to content and therefore
// doesn't get created in content_browsertests. Insert a mock
// NetworkChangeNotifier.
diff --git a/chromium/content/browser/notification_service_impl.h b/chromium/content/browser/notification_service_impl.h
index 2df369a6d0f..6704fe43c55 100644
--- a/chromium/content/browser/notification_service_impl.h
+++ b/chromium/content/browser/notification_service_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_PUBLIC_BROWSER_NOTIFICATION_SERVICE_IMPL_H_
-#define CONTENT_PUBLIC_BROWSER_NOTIFICATION_SERVICE_IMPL_H_
+#ifndef CONTENT_BROWSER_NOTIFICATION_SERVICE_IMPL_H_
+#define CONTENT_BROWSER_NOTIFICATION_SERVICE_IMPL_H_
#include <map>
@@ -92,4 +92,4 @@ class CONTENT_EXPORT NotificationServiceImpl : public NotificationService {
} // namespace content
-#endif // CONTENT_PUBLIC_BROWSER_NOTIFICATION_SERVICE_IMPL_H_
+#endif // CONTENT_BROWSER_NOTIFICATION_SERVICE_IMPL_H_
diff --git a/chromium/content/browser/notifications/BUILD.gn b/chromium/content/browser/notifications/BUILD.gn
new file mode 100644
index 00000000000..0f6d5456988
--- /dev/null
+++ b/chromium/content/browser/notifications/BUILD.gn
@@ -0,0 +1,11 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/protobuf/proto_library.gni")
+
+proto_library("notification_proto") {
+ sources = [
+ "notification_database_data.proto",
+ ]
+}
diff --git a/chromium/content/browser/notifications/DEPS b/chromium/content/browser/notifications/DEPS
new file mode 100644
index 00000000000..a0ec7348e6f
--- /dev/null
+++ b/chromium/content/browser/notifications/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+third_party/leveldatabase",
+] \ No newline at end of file
diff --git a/chromium/content/browser/notifications/OWNERS b/chromium/content/browser/notifications/OWNERS
index 2fca67fdfda..e0a6572eb52 100644
--- a/chromium/content/browser/notifications/OWNERS
+++ b/chromium/content/browser/notifications/OWNERS
@@ -1 +1,4 @@
+johnme@chromium.org
+mkwst@chromium.org
+mvanouwerkerk@chromium.org
peter@chromium.org \ No newline at end of file
diff --git a/chromium/content/browser/notifications/notification_database.cc b/chromium/content/browser/notifications/notification_database.cc
new file mode 100644
index 00000000000..9e64693b835
--- /dev/null
+++ b/chromium/content/browser/notifications/notification_database.cc
@@ -0,0 +1,381 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/notifications/notification_database.h"
+
+#include <string>
+
+#include "base/files/file_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "content/browser/notifications/notification_database_data_conversions.h"
+#include "content/common/service_worker/service_worker_types.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/notification_database_data.h"
+#include "storage/common/database/database_identifier.h"
+#include "third_party/leveldatabase/env_chromium.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/write_batch.h"
+#include "url/gurl.h"
+
+// Notification LevelDB database schema (in alphabetized order)
+// =======================
+//
+// key: "DATA:" <origin identifier> '\x00' <notification_id>
+// value: String containing the NotificationDatabaseDataProto protocol buffer
+// in serialized form.
+//
+// key: "NEXT_NOTIFICATION_ID"
+// value: Decimal string which fits into an int64_t.
+
+namespace content {
+namespace {
+
+// Keys of the fields defined in the database.
+const char kNextNotificationIdKey[] = "NEXT_NOTIFICATION_ID";
+const char kDataKeyPrefix[] = "DATA:";
+
+// Separates the components of compound keys.
+const char kKeySeparator = '\x00';
+
+// The first notification id which to be handed out by the database.
+const int64_t kFirstNotificationId = 1;
+
+// Converts the LevelDB |status| to one of the notification database's values.
+NotificationDatabase::Status LevelDBStatusToStatus(
+ const leveldb::Status& status) {
+ if (status.ok())
+ return NotificationDatabase::STATUS_OK;
+ else if (status.IsNotFound())
+ return NotificationDatabase::STATUS_ERROR_NOT_FOUND;
+ else if (status.IsCorruption())
+ return NotificationDatabase::STATUS_ERROR_CORRUPTED;
+
+ return NotificationDatabase::STATUS_ERROR_FAILED;
+}
+
+// Creates a prefix for the data entries based on |origin|.
+std::string CreateDataPrefix(const GURL& origin) {
+ if (!origin.is_valid())
+ return kDataKeyPrefix;
+
+ return base::StringPrintf("%s%s%c",
+ kDataKeyPrefix,
+ storage::GetIdentifierFromOrigin(origin).c_str(),
+ kKeySeparator);
+}
+
+// Creates the compound data key in which notification data is stored.
+std::string CreateDataKey(const GURL& origin, int64_t notification_id) {
+ DCHECK(origin.is_valid());
+ return CreateDataPrefix(origin) + base::Int64ToString(notification_id);
+}
+
+// Deserializes data in |serialized_data| to |notification_database_data|.
+// Will return if the deserialization was successful.
+NotificationDatabase::Status DeserializedNotificationData(
+ const std::string& serialized_data,
+ NotificationDatabaseData* notification_database_data) {
+ DCHECK(notification_database_data);
+ if (DeserializeNotificationDatabaseData(serialized_data,
+ notification_database_data)) {
+ return NotificationDatabase::STATUS_OK;
+ }
+
+ DLOG(ERROR) << "Unable to deserialize a notification's data.";
+ return NotificationDatabase::STATUS_ERROR_CORRUPTED;
+}
+
+} // namespace
+
+NotificationDatabase::NotificationDatabase(const base::FilePath& path)
+ : path_(path) {
+}
+
+NotificationDatabase::~NotificationDatabase() {
+ DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+}
+
+NotificationDatabase::Status NotificationDatabase::Open(
+ bool create_if_missing) {
+ DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+ DCHECK_EQ(STATE_UNINITIALIZED, state_);
+
+ if (!create_if_missing) {
+ if (IsInMemoryDatabase() ||
+ !base::PathExists(path_) ||
+ base::IsDirectoryEmpty(path_)) {
+ return NotificationDatabase::STATUS_ERROR_NOT_FOUND;
+ }
+ }
+
+ filter_policy_.reset(leveldb::NewBloomFilterPolicy(10));
+
+ leveldb::Options options;
+ options.create_if_missing = create_if_missing;
+ options.paranoid_checks = true;
+ options.reuse_logs = leveldb_env::kDefaultLogReuseOptionValue;
+ options.filter_policy = filter_policy_.get();
+ if (IsInMemoryDatabase()) {
+ env_.reset(leveldb::NewMemEnv(leveldb::Env::Default()));
+ options.env = env_.get();
+ }
+
+ leveldb::DB* db = nullptr;
+ Status status = LevelDBStatusToStatus(
+ leveldb::DB::Open(options, path_.AsUTF8Unsafe(), &db));
+ if (status != STATUS_OK)
+ return status;
+
+ state_ = STATE_INITIALIZED;
+ db_.reset(db);
+
+ return ReadNextNotificationId();
+}
+
+NotificationDatabase::Status NotificationDatabase::ReadNotificationData(
+ int64_t notification_id,
+ const GURL& origin,
+ NotificationDatabaseData* notification_database_data) const {
+ DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+ DCHECK_EQ(STATE_INITIALIZED, state_);
+ DCHECK_GE(notification_id, kFirstNotificationId);
+ DCHECK(origin.is_valid());
+ DCHECK(notification_database_data);
+
+ std::string key = CreateDataKey(origin, notification_id);
+ std::string serialized_data;
+
+ Status status = LevelDBStatusToStatus(
+ db_->Get(leveldb::ReadOptions(), key, &serialized_data));
+ if (status != STATUS_OK)
+ return status;
+
+ return DeserializedNotificationData(serialized_data,
+ notification_database_data);
+}
+
+NotificationDatabase::Status
+NotificationDatabase::ReadAllNotificationData(
+ std::vector<NotificationDatabaseData>* notification_data_vector) const {
+ return ReadAllNotificationDataInternal(GURL() /* origin */,
+ kInvalidServiceWorkerRegistrationId,
+ notification_data_vector);
+}
+
+NotificationDatabase::Status
+NotificationDatabase::ReadAllNotificationDataForOrigin(
+ const GURL& origin,
+ std::vector<NotificationDatabaseData>* notification_data_vector) const {
+ return ReadAllNotificationDataInternal(origin,
+ kInvalidServiceWorkerRegistrationId,
+ notification_data_vector);
+}
+
+NotificationDatabase::Status
+NotificationDatabase::ReadAllNotificationDataForServiceWorkerRegistration(
+ const GURL& origin,
+ int64_t service_worker_registration_id,
+ std::vector<NotificationDatabaseData>* notification_data_vector) const {
+ return ReadAllNotificationDataInternal(origin,
+ service_worker_registration_id,
+ notification_data_vector);
+}
+
+NotificationDatabase::Status NotificationDatabase::WriteNotificationData(
+ const GURL& origin,
+ const NotificationDatabaseData& notification_database_data,
+ int64_t* notification_id) {
+ DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+ DCHECK_EQ(STATE_INITIALIZED, state_);
+ DCHECK(notification_id);
+ DCHECK(origin.is_valid());
+
+ DCHECK_GE(next_notification_id_, kFirstNotificationId);
+
+ NotificationDatabaseData storage_data = notification_database_data;
+ storage_data.notification_id = next_notification_id_;
+
+ std::string serialized_data;
+ if (!SerializeNotificationDatabaseData(storage_data,
+ &serialized_data)) {
+ DLOG(ERROR) << "Unable to serialize data for a notification belonging "
+ << "to: " << origin;
+ return STATUS_ERROR_FAILED;
+ }
+
+ leveldb::WriteBatch batch;
+ batch.Put(CreateDataKey(origin, next_notification_id_), serialized_data);
+ batch.Put(kNextNotificationIdKey,
+ base::Int64ToString(next_notification_id_ + 1));
+
+ Status status = LevelDBStatusToStatus(
+ db_->Write(leveldb::WriteOptions(), &batch));
+ if (status != STATUS_OK)
+ return status;
+
+ *notification_id = next_notification_id_++;
+ return STATUS_OK;
+}
+
+NotificationDatabase::Status NotificationDatabase::DeleteNotificationData(
+ int64_t notification_id,
+ const GURL& origin) {
+ DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+ DCHECK_EQ(STATE_INITIALIZED, state_);
+ DCHECK_GE(notification_id, kFirstNotificationId);
+ DCHECK(origin.is_valid());
+
+ std::string key = CreateDataKey(origin, notification_id);
+ return LevelDBStatusToStatus(db_->Delete(leveldb::WriteOptions(), key));
+}
+
+NotificationDatabase::Status
+NotificationDatabase::DeleteAllNotificationDataForOrigin(
+ const GURL& origin,
+ std::set<int64_t>* deleted_notification_set) {
+ return DeleteAllNotificationDataInternal(origin,
+ kInvalidServiceWorkerRegistrationId,
+ deleted_notification_set);
+}
+
+NotificationDatabase::Status
+NotificationDatabase::DeleteAllNotificationDataForServiceWorkerRegistration(
+ const GURL& origin,
+ int64_t service_worker_registration_id,
+ std::set<int64_t>* deleted_notification_set) {
+ return DeleteAllNotificationDataInternal(origin,
+ service_worker_registration_id,
+ deleted_notification_set);
+}
+
+NotificationDatabase::Status NotificationDatabase::Destroy() {
+ DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+
+ leveldb::Options options;
+ if (IsInMemoryDatabase()) {
+ if (!env_)
+ return STATUS_OK; // The database has not been initialized.
+
+ options.env = env_.get();
+ }
+
+ state_ = STATE_DISABLED;
+ db_.reset();
+
+ return LevelDBStatusToStatus(
+ leveldb::DestroyDB(path_.AsUTF8Unsafe(), options));
+}
+
+NotificationDatabase::Status NotificationDatabase::ReadNextNotificationId() {
+ std::string value;
+ Status status = LevelDBStatusToStatus(
+ db_->Get(leveldb::ReadOptions(), kNextNotificationIdKey, &value));
+
+ if (status == STATUS_ERROR_NOT_FOUND) {
+ next_notification_id_ = kFirstNotificationId;
+ return STATUS_OK;
+ }
+
+ if (status != STATUS_OK)
+ return status;
+
+ if (!base::StringToInt64(value, &next_notification_id_) ||
+ next_notification_id_ < kFirstNotificationId) {
+ return STATUS_ERROR_CORRUPTED;
+ }
+
+ return STATUS_OK;
+}
+
+NotificationDatabase::Status
+NotificationDatabase::ReadAllNotificationDataInternal(
+ const GURL& origin,
+ int64_t service_worker_registration_id,
+ std::vector<NotificationDatabaseData>* notification_data_vector) const {
+ DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+ DCHECK(notification_data_vector);
+
+ const std::string prefix = CreateDataPrefix(origin);
+
+ leveldb::Slice prefix_slice(prefix);
+
+ NotificationDatabaseData notification_database_data;
+ scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(leveldb::ReadOptions()));
+ for (iter->Seek(prefix_slice); iter->Valid(); iter->Next()) {
+ if (!iter->key().starts_with(prefix_slice))
+ break;
+
+ Status status = DeserializedNotificationData(iter->value().ToString(),
+ &notification_database_data);
+ if (status != STATUS_OK)
+ return status;
+
+ if (service_worker_registration_id != kInvalidServiceWorkerRegistrationId &&
+ notification_database_data.service_worker_registration_id !=
+ service_worker_registration_id) {
+ continue;
+ }
+
+ notification_data_vector->push_back(notification_database_data);
+ }
+
+ return LevelDBStatusToStatus(iter->status());
+}
+
+NotificationDatabase::Status
+NotificationDatabase::DeleteAllNotificationDataInternal(
+ const GURL& origin,
+ int64_t service_worker_registration_id,
+ std::set<int64_t>* deleted_notification_set) {
+ DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+ DCHECK(deleted_notification_set);
+ DCHECK(origin.is_valid());
+
+ const std::string prefix = CreateDataPrefix(origin);
+
+ leveldb::Slice prefix_slice(prefix);
+ leveldb::WriteBatch batch;
+
+ NotificationDatabaseData notification_database_data;
+ scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(leveldb::ReadOptions()));
+ for (iter->Seek(prefix_slice); iter->Valid(); iter->Next()) {
+ if (!iter->key().starts_with(prefix_slice))
+ break;
+
+ if (service_worker_registration_id != kInvalidServiceWorkerRegistrationId) {
+ Status status = DeserializedNotificationData(iter->value().ToString(),
+ &notification_database_data);
+ if (status != STATUS_OK)
+ return status;
+
+ if (notification_database_data.service_worker_registration_id !=
+ service_worker_registration_id) {
+ continue;
+ }
+ }
+
+ leveldb::Slice notification_id_slice = iter->key();
+ notification_id_slice.remove_prefix(prefix_slice.size());
+
+ int64_t notification_id = 0;
+ if (!base::StringToInt64(notification_id_slice.ToString(),
+ &notification_id)) {
+ return STATUS_ERROR_CORRUPTED;
+ }
+
+ deleted_notification_set->insert(notification_id);
+ batch.Delete(iter->key());
+ }
+
+ if (deleted_notification_set->empty())
+ return STATUS_OK;
+
+ return LevelDBStatusToStatus(db_->Write(leveldb::WriteOptions(), &batch));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/notifications/notification_database.h b/chromium/content/browser/notifications/notification_database.h
new file mode 100644
index 00000000000..1404e63501a
--- /dev/null
+++ b/chromium/content/browser/notifications/notification_database.h
@@ -0,0 +1,195 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_NOTIFICATIONS_NOTIFICATION_DATABASE_H_
+#define CONTENT_BROWSER_NOTIFICATIONS_NOTIFICATION_DATABASE_H_
+
+#include <stdint.h>
+#include <set>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/sequence_checker.h"
+#include "content/common/content_export.h"
+
+class GURL;
+
+namespace leveldb {
+class DB;
+class Env;
+class FilterPolicy;
+class WriteBatch;
+}
+
+namespace content {
+
+struct NotificationDatabaseData;
+
+// Implementation of the persistent notification database.
+//
+// The database is built on top of a LevelDB database, either in memory or on
+// the filesystem depending on the path passed to the constructor. When writing
+// a new notification, it will be assigned an id guaranteed to be unique for the
+// lifetime of the database.
+//
+// This class must only be used on a thread or sequenced task runner that allows
+// file I/O. The same thread or task runner must be used for all method calls.
+class CONTENT_EXPORT NotificationDatabase {
+ public:
+ // Result status codes for interations with the database. Will be used for
+ // UMA, so the assigned ids must remain stable.
+ enum Status {
+ STATUS_OK = 0,
+
+ // The database, a notification, or a LevelDB key associated with the
+ // operation could not be found.
+ STATUS_ERROR_NOT_FOUND = 1,
+
+ // The database, or data in the database, could not be parsed as valid data.
+ STATUS_ERROR_CORRUPTED = 2,
+
+ // General failure code. More specific failures should be used if available.
+ STATUS_ERROR_FAILED = 3,
+
+ // Number of entries in the status enumeration. Used by UMA. Must always be
+ // one higher than the otherwise highest value in this enumeration.
+ STATUS_COUNT = 4
+ };
+
+ explicit NotificationDatabase(const base::FilePath& path);
+ ~NotificationDatabase();
+
+ // Opens the database. If |path| is non-empty, it will be created on the given
+ // directory on the filesystem. If |path| is empty, the database will be
+ // created in memory instead, and its lifetime will be tied to this instance.
+ // |create_if_missing| determines whether to create the database if necessary.
+ Status Open(bool create_if_missing);
+
+ // Reads the notification data for the notification identified by
+ // |notification_id| and belonging to |origin| from the database, and stores
+ // it in |notification_database_data|. Returns the status code.
+ Status ReadNotificationData(
+ int64_t notification_id,
+ const GURL& origin,
+ NotificationDatabaseData* notification_database_data) const;
+
+ // Reads all notification data for all origins from the database, and appends
+ // the data to |notification_data_vector|. Returns the status code.
+ Status ReadAllNotificationData(
+ std::vector<NotificationDatabaseData>* notification_data_vector) const;
+
+ // Reads all notification data associated with |origin| from the database, and
+ // appends the data to |notification_data_vector|. Returns the status code.
+ Status ReadAllNotificationDataForOrigin(
+ const GURL& origin,
+ std::vector<NotificationDatabaseData>* notification_data_vector) const;
+
+ // Reads all notification data associated to |service_worker_registration_id|
+ // belonging to |origin| from the database, and appends the data to the
+ // |notification_data_vector|. Returns the status code.
+ Status ReadAllNotificationDataForServiceWorkerRegistration(
+ const GURL& origin,
+ int64_t service_worker_registration_id,
+ std::vector<NotificationDatabaseData>* notification_data_vector) const;
+
+ // Writes the |notification_database_data| for a new notification belonging to
+ // |origin| to the database, and returns the status code of the writing
+ // operation. The id of the new notification will be set in |notification_id|.
+ Status WriteNotificationData(
+ const GURL& origin,
+ const NotificationDatabaseData& notification_database_data,
+ int64_t* notification_id);
+
+ // Deletes all data associated with the notification identified by
+ // |notification_id| belonging to |origin| from the database. Returns the
+ // status code of the deletion operation. Note that it is not considered a
+ // failure if the to-be-deleted notification does not exist.
+ Status DeleteNotificationData(int64_t notification_id, const GURL& origin);
+
+ // Deletes all data associated with |origin| from the database, and appends
+ // the deleted notification ids to |deleted_notification_set|. Returns the
+ // status code of the deletion operation.
+ Status DeleteAllNotificationDataForOrigin(
+ const GURL& origin,
+ std::set<int64_t>* deleted_notification_set);
+
+ // Deletes all data associated with the |service_worker_registration_id|
+ // belonging to |origin| from the database, and appends the deleted
+ // notification ids to |deleted_notification_set|. Returns the status code
+ // of the deletion operation.
+ Status DeleteAllNotificationDataForServiceWorkerRegistration(
+ const GURL& origin,
+ int64_t service_worker_registration_id,
+ std::set<int64_t>* deleted_notification_set);
+
+ // Completely destroys the contents of this database.
+ Status Destroy();
+
+ private:
+ friend class NotificationDatabaseTest;
+
+ // TODO(peter): Convert to an enum class when DCHECK_EQ supports this.
+ // See https://crbug.com/463869.
+ enum State {
+ STATE_UNINITIALIZED,
+ STATE_INITIALIZED,
+ STATE_DISABLED,
+ };
+
+ // Reads the next available notification id from the database and returns
+ // the status code of the reading operation. The value will be stored in
+ // the |next_notification_id_| member.
+ Status ReadNextNotificationId();
+
+ // Reads all notification data with the given constraints. |origin| may be
+ // empty to read all notification data from all origins. If |origin| is
+ // set, but |service_worker_registration_id| is invalid, then all notification
+ // data for |origin| will be read. If both are set, then all notification data
+ // for the given |service_worker_registration_id| will be read.
+ Status ReadAllNotificationDataInternal(
+ const GURL& origin,
+ int64_t service_worker_registration_id,
+ std::vector<NotificationDatabaseData>* notification_data_vector) const;
+
+ // Deletes all notification data with the given constraints. |origin| must
+ // always be set - use Destroy() when the goal is to empty the database. If
+ // |service_worker_registration_id| is invalid, all notification data for the
+ // |origin| will be deleted.
+ // All deleted notification ids will be written to |deleted_notification_set|.
+ Status DeleteAllNotificationDataInternal(
+ const GURL& origin,
+ int64_t service_worker_registration_id,
+ std::set<int64_t>* deleted_notification_set);
+
+ // Returns whether the database has been opened.
+ bool IsOpen() const { return db_ != nullptr; }
+
+ // Returns whether the database should only exist in memory.
+ bool IsInMemoryDatabase() const { return path_.empty(); }
+
+ // Exposes the LevelDB database used to back this notification database.
+ // Should only be used for testing purposes.
+ leveldb::DB* GetDBForTesting() const { return db_.get(); }
+
+ base::FilePath path_;
+
+ int64_t next_notification_id_ = 0;
+
+ scoped_ptr<const leveldb::FilterPolicy> filter_policy_;
+
+ // The declaration order for these members matters, as |db_| depends on |env_|
+ // and thus has to be destructed first.
+ scoped_ptr<leveldb::Env> env_;
+ scoped_ptr<leveldb::DB> db_;
+
+ State state_ = STATE_UNINITIALIZED;
+
+ base::SequenceChecker sequence_checker_;
+
+ DISALLOW_COPY_AND_ASSIGN(NotificationDatabase);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_NOTIFICATIONS_NOTIFICATION_DATABASE_H_
diff --git a/chromium/content/browser/notifications/notification_database_data.proto b/chromium/content/browser/notifications/notification_database_data.proto
new file mode 100644
index 00000000000..5d8fe20c6eb
--- /dev/null
+++ b/chromium/content/browser/notifications/notification_database_data.proto
@@ -0,0 +1,43 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package content;
+
+// Stores information about a Web Notification. This message is the protocol
+// buffer meant to serialize the content::NotificationDatabaseData structure.
+//
+// Next tag: 5
+message NotificationDatabaseDataProto {
+ optional int64 notification_id = 1;
+
+ optional string origin = 2;
+ optional int64 service_worker_registration_id = 3;
+
+ // Actual data payload of the notification. This message is the protocol
+ // buffer meant to serialize the content::PlatformNotificationData structure.
+ //
+ // Next tag: 10
+ message NotificationData {
+ enum Direction {
+ LEFT_TO_RIGHT = 0;
+ RIGHT_TO_LEFT = 1;
+ }
+
+ optional string title = 1;
+ optional Direction direction = 2;
+ optional string lang = 3;
+ optional string body = 4;
+ optional string tag = 5;
+ optional string icon = 6;
+ repeated int32 vibration_pattern = 9 [packed=true];
+ optional bool silent = 7;
+ optional bytes data = 8;
+ }
+
+ optional NotificationData notification_data = 4;
+}
diff --git a/chromium/content/browser/notifications/notification_database_data_conversions.cc b/chromium/content/browser/notifications/notification_database_data_conversions.cc
new file mode 100644
index 00000000000..349b9c834b4
--- /dev/null
+++ b/chromium/content/browser/notifications/notification_database_data_conversions.cc
@@ -0,0 +1,98 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/notifications/notification_database_data_conversions.h"
+
+#include "base/logging.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/browser/notifications/notification_database_data.pb.h"
+#include "content/public/browser/notification_database_data.h"
+
+namespace content {
+
+bool DeserializeNotificationDatabaseData(const std::string& input,
+ NotificationDatabaseData* output) {
+ DCHECK(output);
+
+ NotificationDatabaseDataProto message;
+ if (!message.ParseFromString(input))
+ return false;
+
+ output->notification_id = message.notification_id();
+ output->origin = GURL(message.origin());
+ output->service_worker_registration_id =
+ message.service_worker_registration_id();
+
+ PlatformNotificationData* notification_data = &output->notification_data;
+ const NotificationDatabaseDataProto::NotificationData& payload =
+ message.notification_data();
+
+ notification_data->title = base::UTF8ToUTF16(payload.title());
+ notification_data->direction =
+ payload.direction() ==
+ NotificationDatabaseDataProto::NotificationData::RIGHT_TO_LEFT ?
+ PlatformNotificationData::NotificationDirectionRightToLeft :
+ PlatformNotificationData::NotificationDirectionLeftToRight;
+ notification_data->lang = payload.lang();
+ notification_data->body = base::UTF8ToUTF16(payload.body());
+ notification_data->tag = payload.tag();
+ notification_data->icon = GURL(payload.icon());
+
+ if (payload.vibration_pattern().size() > 0) {
+ notification_data->vibration_pattern.assign(
+ payload.vibration_pattern().begin(),
+ payload.vibration_pattern().end());
+ }
+
+ notification_data->silent = payload.silent();
+
+ if (payload.data().length()) {
+ notification_data->data.assign(payload.data().begin(),
+ payload.data().end());
+ }
+
+ return true;
+}
+
+bool SerializeNotificationDatabaseData(const NotificationDatabaseData& input,
+ std::string* output) {
+ DCHECK(output);
+
+ scoped_ptr<NotificationDatabaseDataProto::NotificationData> payload(
+ new NotificationDatabaseDataProto::NotificationData());
+
+ const PlatformNotificationData& notification_data = input.notification_data;
+
+ payload->set_title(base::UTF16ToUTF8(notification_data.title));
+ payload->set_direction(
+ notification_data.direction ==
+ PlatformNotificationData::NotificationDirectionRightToLeft ?
+ NotificationDatabaseDataProto::NotificationData::RIGHT_TO_LEFT :
+ NotificationDatabaseDataProto::NotificationData::LEFT_TO_RIGHT);
+ payload->set_lang(notification_data.lang);
+ payload->set_body(base::UTF16ToUTF8(notification_data.body));
+ payload->set_tag(notification_data.tag);
+ payload->set_icon(notification_data.icon.spec());
+
+ for (size_t i = 0; i < notification_data.vibration_pattern.size(); ++i)
+ payload->add_vibration_pattern(notification_data.vibration_pattern[i]);
+
+ payload->set_silent(notification_data.silent);
+
+ if (notification_data.data.size()) {
+ payload->set_data(&notification_data.data.front(),
+ notification_data.data.size());
+ }
+
+ NotificationDatabaseDataProto message;
+ message.set_notification_id(input.notification_id);
+ message.set_origin(input.origin.spec());
+ message.set_service_worker_registration_id(
+ input.service_worker_registration_id);
+ message.set_allocated_notification_data(payload.release());
+
+ return message.SerializeToString(output);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/notifications/notification_database_data_conversions.h b/chromium/content/browser/notifications/notification_database_data_conversions.h
new file mode 100644
index 00000000000..84475b518a2
--- /dev/null
+++ b/chromium/content/browser/notifications/notification_database_data_conversions.h
@@ -0,0 +1,30 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_NOTIFICATIONS_NOTIFICATION_DATABASE_DATA_CONVERSIONS_H_
+#define CONTENT_BROWSER_NOTIFICATIONS_NOTIFICATION_DATABASE_DATA_CONVERSIONS_H_
+
+#include <string>
+
+#include "content/common/content_export.h"
+
+namespace content {
+
+struct NotificationDatabaseData;
+
+// Parses the serialized notification data |input| into a new object, |output|.
+// Returns whether the serialized |input| could be deserialized successfully.
+CONTENT_EXPORT bool DeserializeNotificationDatabaseData(
+ const std::string& input,
+ NotificationDatabaseData* output);
+
+// Serializes the contents of |input| into the string |output|. Returns whether
+// the notification data could be serialized successfully.
+CONTENT_EXPORT bool SerializeNotificationDatabaseData(
+ const NotificationDatabaseData& input,
+ std::string* output);
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_NOTIFICATIONS_NOTIFICATION_DATABASE_DATA_CONVERSIONS_H_
diff --git a/chromium/content/browser/notifications/notification_database_data_unittest.cc b/chromium/content/browser/notifications/notification_database_data_unittest.cc
new file mode 100644
index 00000000000..2613108db5c
--- /dev/null
+++ b/chromium/content/browser/notifications/notification_database_data_unittest.cc
@@ -0,0 +1,89 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/utf_string_conversions.h"
+#include "content/browser/notifications/notification_database_data.pb.h"
+#include "content/browser/notifications/notification_database_data_conversions.h"
+#include "content/public/browser/notification_database_data.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+const int64_t kNotificationId = 42;
+const int64_t kServiceWorkerRegistrationId = 9001;
+
+const char kOrigin[] = "https://example.com/";
+const char kNotificationTitle[] = "My Notification";
+const char kNotificationLang[] = "nl";
+const char kNotificationBody[] = "Hello, world!";
+const char kNotificationTag[] = "my_tag";
+const char kNotificationIconUrl[] = "https://example.com/icon.png";
+const int kNotificationVibrationPattern[] = { 100, 200, 300 };
+const unsigned char kNotificationData[] = { 0xdf, 0xff, 0x0, 0x0, 0xff, 0xdf };
+
+TEST(NotificationDatabaseDataTest, SerializeAndDeserializeData) {
+ std::vector<int> vibration_pattern(
+ kNotificationVibrationPattern,
+ kNotificationVibrationPattern + arraysize(kNotificationVibrationPattern));
+
+ std::vector<char> developer_data(
+ kNotificationData, kNotificationData + arraysize(kNotificationData));
+
+ PlatformNotificationData notification_data;
+ notification_data.title = base::ASCIIToUTF16(kNotificationTitle);
+ notification_data.direction =
+ PlatformNotificationData::NotificationDirectionRightToLeft;
+ notification_data.lang = kNotificationLang;
+ notification_data.body = base::ASCIIToUTF16(kNotificationBody);
+ notification_data.tag = kNotificationTag;
+ notification_data.icon = GURL(kNotificationIconUrl);
+ notification_data.vibration_pattern = vibration_pattern;
+ notification_data.silent = true;
+ notification_data.data = developer_data;
+
+ NotificationDatabaseData database_data;
+ database_data.notification_id = kNotificationId;
+ database_data.origin = GURL(kOrigin);
+ database_data.service_worker_registration_id = kServiceWorkerRegistrationId;
+ database_data.notification_data = notification_data;
+
+ std::string serialized_data;
+
+ // Serialize the data in |notification_data| to the string |serialized_data|.
+ ASSERT_TRUE(SerializeNotificationDatabaseData(database_data,
+ &serialized_data));
+
+ NotificationDatabaseData copied_data;
+
+ // Deserialize the data in |serialized_data| to |copied_data|.
+ ASSERT_TRUE(DeserializeNotificationDatabaseData(serialized_data,
+ &copied_data));
+
+ EXPECT_EQ(database_data.notification_id, copied_data.notification_id);
+ EXPECT_EQ(database_data.origin, copied_data.origin);
+ EXPECT_EQ(database_data.service_worker_registration_id,
+ copied_data.service_worker_registration_id);
+
+ const PlatformNotificationData& copied_notification_data =
+ copied_data.notification_data;
+
+ EXPECT_EQ(notification_data.title, copied_notification_data.title);
+ EXPECT_EQ(notification_data.direction, copied_notification_data.direction);
+ EXPECT_EQ(notification_data.lang, copied_notification_data.lang);
+ EXPECT_EQ(notification_data.body, copied_notification_data.body);
+ EXPECT_EQ(notification_data.tag, copied_notification_data.tag);
+ EXPECT_EQ(notification_data.icon, copied_notification_data.icon);
+
+ EXPECT_THAT(copied_notification_data.vibration_pattern,
+ testing::ElementsAreArray(kNotificationVibrationPattern));
+
+ EXPECT_EQ(notification_data.silent, copied_notification_data.silent);
+
+ ASSERT_EQ(developer_data.size(), copied_notification_data.data.size());
+ for (size_t i = 0; i < developer_data.size(); ++i)
+ EXPECT_EQ(developer_data[i], copied_notification_data.data[i]);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/notifications/notification_database_unittest.cc b/chromium/content/browser/notifications/notification_database_unittest.cc
new file mode 100644
index 00000000000..65c537ec192
--- /dev/null
+++ b/chromium/content/browser/notifications/notification_database_unittest.cc
@@ -0,0 +1,592 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/notifications/notification_database.h"
+
+#include "base/files/scoped_temp_dir.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/public/browser/notification_database_data.h"
+#include "content/public/common/platform_notification_data.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/leveldatabase/src/include/leveldb/db.h"
+#include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
+#include "url/gurl.h"
+
+namespace content {
+
+const int kExampleServiceWorkerRegistrationId = 42;
+
+const struct {
+ const char* origin;
+ int64_t service_worker_registration_id;
+} kExampleNotificationData[] = {
+ { "https://example.com", 0 },
+ { "https://example.com", kExampleServiceWorkerRegistrationId },
+ { "https://example.com", kExampleServiceWorkerRegistrationId },
+ { "https://example.com", kExampleServiceWorkerRegistrationId + 1 },
+ { "https://chrome.com", 0 },
+ { "https://chrome.com", 0 },
+ { "https://chrome.com", kExampleServiceWorkerRegistrationId }
+};
+
+class NotificationDatabaseTest : public ::testing::Test {
+ protected:
+ // Creates a new NotificationDatabase instance in memory.
+ NotificationDatabase* CreateDatabaseInMemory() {
+ return new NotificationDatabase(base::FilePath());
+ }
+
+ // Creates a new NotificationDatabase instance in |path|.
+ NotificationDatabase* CreateDatabaseOnFileSystem(
+ const base::FilePath& path) {
+ return new NotificationDatabase(path);
+ }
+
+ // Creates a new notification for |service_worker_registration_id| belonging
+ // to |origin| and writes it to the database. The written notification id
+ // will be stored in |notification_id|.
+ void CreateAndWriteNotification(NotificationDatabase* database,
+ const GURL& origin,
+ int64_t service_worker_registration_id,
+ int64_t* notification_id) {
+ NotificationDatabaseData database_data;
+ database_data.origin = origin;
+ database_data.service_worker_registration_id =
+ service_worker_registration_id;
+
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->WriteNotificationData(origin,
+ database_data,
+ notification_id));
+ }
+
+ // Populates |database| with a series of example notifications that differ in
+ // their origin and Service Worker registration id.
+ void PopulateDatabaseWithExampleData(NotificationDatabase* database) {
+ int64_t notification_id;
+ for (size_t i = 0; i < arraysize(kExampleNotificationData); ++i) {
+ ASSERT_NO_FATAL_FAILURE(CreateAndWriteNotification(
+ database,
+ GURL(kExampleNotificationData[i].origin),
+ kExampleNotificationData[i].service_worker_registration_id,
+ &notification_id));
+ }
+ }
+
+ // Returns if |database| has been opened.
+ bool IsDatabaseOpen(NotificationDatabase* database) {
+ return database->IsOpen();
+ }
+
+ // Returns if |database| is an in-memory only database.
+ bool IsInMemoryDatabase(NotificationDatabase* database) {
+ return database->IsInMemoryDatabase();
+ }
+
+ // Writes a LevelDB key-value pair directly to the LevelDB backing the
+ // notification database in |database|.
+ void WriteLevelDBKeyValuePair(NotificationDatabase* database,
+ const std::string& key,
+ const std::string& value) {
+ leveldb::Status status =
+ database->GetDBForTesting()->Put(leveldb::WriteOptions(), key, value);
+ ASSERT_TRUE(status.ok());
+ }
+};
+
+TEST_F(NotificationDatabaseTest, OpenCloseMemory) {
+ scoped_ptr<NotificationDatabase> database(CreateDatabaseInMemory());
+
+ // Should return false because the database does not exist in memory.
+ EXPECT_EQ(NotificationDatabase::STATUS_ERROR_NOT_FOUND,
+ database->Open(false /* create_if_missing */));
+
+ // Should return true, indicating that the database could be created.
+ EXPECT_EQ(NotificationDatabase::STATUS_OK,
+ database->Open(true /* create_if_missing */));
+
+ EXPECT_TRUE(IsDatabaseOpen(database.get()));
+ EXPECT_TRUE(IsInMemoryDatabase(database.get()));
+
+ // Verify that in-memory databases do not persist when being re-created.
+ database.reset(CreateDatabaseInMemory());
+
+ EXPECT_EQ(NotificationDatabase::STATUS_ERROR_NOT_FOUND,
+ database->Open(false /* create_if_missing */));
+}
+
+TEST_F(NotificationDatabaseTest, OpenCloseFileSystem) {
+ base::ScopedTempDir database_dir;
+ ASSERT_TRUE(database_dir.CreateUniqueTempDir());
+
+ scoped_ptr<NotificationDatabase> database(
+ CreateDatabaseOnFileSystem(database_dir.path()));
+
+ // Should return false because the database does not exist on the file system.
+ EXPECT_EQ(NotificationDatabase::STATUS_ERROR_NOT_FOUND,
+ database->Open(false /* create_if_missing */));
+
+ // Should return true, indicating that the database could be created.
+ EXPECT_EQ(NotificationDatabase::STATUS_OK,
+ database->Open(true /* create_if_missing */));
+
+ EXPECT_TRUE(IsDatabaseOpen(database.get()));
+ EXPECT_FALSE(IsInMemoryDatabase(database.get()));
+
+ // Close the database, and re-open it without attempting to create it because
+ // the files on the file system should still exist as expected.
+ database.reset(CreateDatabaseOnFileSystem(database_dir.path()));
+ EXPECT_EQ(NotificationDatabase::STATUS_OK,
+ database->Open(false /* create_if_missing */));
+}
+
+TEST_F(NotificationDatabaseTest, DestroyDatabase) {
+ base::ScopedTempDir database_dir;
+ ASSERT_TRUE(database_dir.CreateUniqueTempDir());
+
+ scoped_ptr<NotificationDatabase> database(
+ CreateDatabaseOnFileSystem(database_dir.path()));
+
+ EXPECT_EQ(NotificationDatabase::STATUS_OK,
+ database->Open(true /* create_if_missing */));
+ EXPECT_TRUE(IsDatabaseOpen(database.get()));
+
+ // Destroy the database. This will immediately close it as well.
+ ASSERT_EQ(NotificationDatabase::STATUS_OK, database->Destroy());
+ EXPECT_FALSE(IsDatabaseOpen(database.get()));
+
+ // Try to re-open the database (but not re-create it). This should fail as
+ // the files associated with the database should have been blown away.
+ database.reset(CreateDatabaseOnFileSystem(database_dir.path()));
+ EXPECT_EQ(NotificationDatabase::STATUS_ERROR_NOT_FOUND,
+ database->Open(false /* create_if_missing */));
+}
+
+TEST_F(NotificationDatabaseTest, NotificationIdIncrements) {
+ base::ScopedTempDir database_dir;
+ ASSERT_TRUE(database_dir.CreateUniqueTempDir());
+
+ scoped_ptr<NotificationDatabase> database(
+ CreateDatabaseOnFileSystem(database_dir.path()));
+
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->Open(true /* create_if_missing */));
+
+ GURL origin("https://example.com");
+
+ int64_t notification_id = 0;
+
+ // Verify that getting two ids on the same database instance results in
+ // incrementing values. Notification ids will start at 1.
+ ASSERT_NO_FATAL_FAILURE(CreateAndWriteNotification(
+ database.get(), origin, 0 /* sw_registration_id */, &notification_id));
+ EXPECT_EQ(notification_id, 1);
+
+ ASSERT_NO_FATAL_FAILURE(CreateAndWriteNotification(
+ database.get(), origin, 0 /* sw_registration_id */, &notification_id));
+ EXPECT_EQ(notification_id, 2);
+
+ database.reset(CreateDatabaseOnFileSystem(database_dir.path()));
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->Open(false /* create_if_missing */));
+
+ // Verify that the next notification id was stored in the database, and
+ // continues where we expect it to be, even after closing and opening it.
+ ASSERT_NO_FATAL_FAILURE(CreateAndWriteNotification(
+ database.get(), origin, 0 /* sw_registration_id */, &notification_id));
+ EXPECT_EQ(notification_id, 3);
+}
+
+TEST_F(NotificationDatabaseTest, NotificationIdIncrementsStorage) {
+ scoped_ptr<NotificationDatabase> database(CreateDatabaseInMemory());
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->Open(true /* create_if_missing */));
+
+ GURL origin("https://example.com");
+
+ NotificationDatabaseData database_data;
+ database_data.notification_id = -1;
+
+ int64_t notification_id = 0;
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->WriteNotificationData(origin,
+ database_data,
+ &notification_id));
+
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->ReadNotificationData(notification_id,
+ origin,
+ &database_data));
+
+ EXPECT_EQ(notification_id, database_data.notification_id);
+}
+
+TEST_F(NotificationDatabaseTest, NotificationIdCorruption) {
+ base::ScopedTempDir database_dir;
+ ASSERT_TRUE(database_dir.CreateUniqueTempDir());
+
+ scoped_ptr<NotificationDatabase> database(
+ CreateDatabaseOnFileSystem(database_dir.path()));
+
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->Open(true /* create_if_missing */));
+
+ GURL origin("https://example.com");
+
+ NotificationDatabaseData database_data;
+ int64_t notification_id = 0;
+
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->WriteNotificationData(origin,
+ database_data,
+ &notification_id));
+ EXPECT_EQ(notification_id, 1);
+
+ // Deliberately write an invalid value as the next notification id. When
+ // re-opening the database, the Open() method should realize that an invalid
+ // value is being read, and mark the database as corrupted.
+ ASSERT_NO_FATAL_FAILURE(WriteLevelDBKeyValuePair(database.get(),
+ "NEXT_NOTIFICATION_ID",
+ "-42"));
+
+ database.reset(CreateDatabaseOnFileSystem(database_dir.path()));
+ EXPECT_EQ(NotificationDatabase::STATUS_ERROR_CORRUPTED,
+ database->Open(false /* create_if_missing */));
+}
+
+TEST_F(NotificationDatabaseTest, ReadInvalidNotificationData) {
+ scoped_ptr<NotificationDatabase> database(CreateDatabaseInMemory());
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->Open(true /* create_if_missing */));
+
+ NotificationDatabaseData database_data;
+
+ // Reading the notification data for a notification that does not exist should
+ // return the ERROR_NOT_FOUND status code.
+ EXPECT_EQ(NotificationDatabase::STATUS_ERROR_NOT_FOUND,
+ database->ReadNotificationData(9001,
+ GURL("https://chrome.com"),
+ &database_data));
+}
+
+TEST_F(NotificationDatabaseTest, ReadNotificationDataDifferentOrigin) {
+ scoped_ptr<NotificationDatabase> database(CreateDatabaseInMemory());
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->Open(true /* create_if_missing */));
+
+ int64_t notification_id = 0;
+ GURL origin("https://example.com");
+
+ NotificationDatabaseData database_data, read_database_data;
+ database_data.notification_data.title = base::UTF8ToUTF16("My Notification");
+
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->WriteNotificationData(origin,
+ database_data,
+ &notification_id));
+
+ // Reading the notification from the database when given a different origin
+ // should return the ERROR_NOT_FOUND status code.
+ EXPECT_EQ(NotificationDatabase::STATUS_ERROR_NOT_FOUND,
+ database->ReadNotificationData(notification_id,
+ GURL("https://chrome.com"),
+ &read_database_data));
+
+ // However, reading the notification from the database with the same origin
+ // should return STATUS_OK and the associated notification data.
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->ReadNotificationData(notification_id,
+ origin,
+ &read_database_data));
+
+ EXPECT_EQ(database_data.notification_data.title,
+ read_database_data.notification_data.title);
+}
+
+TEST_F(NotificationDatabaseTest, ReadNotificationDataReflection) {
+ scoped_ptr<NotificationDatabase> database(CreateDatabaseInMemory());
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->Open(true /* create_if_missing */));
+
+ int64_t notification_id = 0;
+
+ GURL origin("https://example.com");
+
+ PlatformNotificationData notification_data;
+ notification_data.title = base::UTF8ToUTF16("My Notification");
+ notification_data.direction =
+ PlatformNotificationData::NotificationDirectionRightToLeft;
+ notification_data.lang = "nl-NL";
+ notification_data.body = base::UTF8ToUTF16("Hello, world!");
+ notification_data.tag = "replace id";
+ notification_data.icon = GURL("https://example.com/icon.png");
+ notification_data.silent = true;
+
+ NotificationDatabaseData database_data;
+ database_data.notification_id = notification_id;
+ database_data.origin = origin;
+ database_data.service_worker_registration_id = 42;
+ database_data.notification_data = notification_data;
+
+ // Write the constructed notification to the database, and then immediately
+ // read it back from the database again as well.
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->WriteNotificationData(origin,
+ database_data,
+ &notification_id));
+
+ NotificationDatabaseData read_database_data;
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->ReadNotificationData(notification_id,
+ origin,
+ &read_database_data));
+
+ // Verify that all members retrieved from the database are exactly the same
+ // as the ones that were written to it. This tests the serialization behavior.
+
+ EXPECT_EQ(notification_id, read_database_data.notification_id);
+
+ EXPECT_EQ(database_data.origin, read_database_data.origin);
+ EXPECT_EQ(database_data.service_worker_registration_id,
+ read_database_data.service_worker_registration_id);
+
+ const PlatformNotificationData& read_notification_data =
+ read_database_data.notification_data;
+
+ EXPECT_EQ(notification_data.title, read_notification_data.title);
+ EXPECT_EQ(notification_data.direction, read_notification_data.direction);
+ EXPECT_EQ(notification_data.lang, read_notification_data.lang);
+ EXPECT_EQ(notification_data.body, read_notification_data.body);
+ EXPECT_EQ(notification_data.tag, read_notification_data.tag);
+ EXPECT_EQ(notification_data.icon, read_notification_data.icon);
+ EXPECT_EQ(notification_data.silent, read_notification_data.silent);
+}
+
+TEST_F(NotificationDatabaseTest, ReadWriteMultipleNotificationData) {
+ scoped_ptr<NotificationDatabase> database(CreateDatabaseInMemory());
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->Open(true /* create_if_missing */));
+
+ GURL origin("https://example.com");
+ int64_t notification_id = 0;
+
+ // Write ten notifications to the database, each with a unique title and
+ // notification id (it is the responsibility of the user to increment this).
+ for (int i = 1; i <= 10; ++i) {
+ ASSERT_NO_FATAL_FAILURE(CreateAndWriteNotification(
+ database.get(), origin, i /* sw_registration_id */, &notification_id));
+ EXPECT_EQ(notification_id, i);
+ }
+
+ NotificationDatabaseData database_data;
+
+ // Read the ten notifications from the database, and verify that the titles
+ // of each of them matches with how they were created.
+ for (int i = 1; i <= 10; ++i) {
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->ReadNotificationData(i /* notification_id */,
+ origin,
+ &database_data));
+
+ EXPECT_EQ(i, database_data.service_worker_registration_id);
+ }
+}
+
+TEST_F(NotificationDatabaseTest, DeleteInvalidNotificationData) {
+ scoped_ptr<NotificationDatabase> database(CreateDatabaseInMemory());
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->Open(true /* create_if_missing */));
+
+ // Deleting non-existing notifications is not considered to be a failure.
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->DeleteNotificationData(9001,
+ GURL("https://chrome.com")));
+}
+
+TEST_F(NotificationDatabaseTest, DeleteNotificationDataSameOrigin) {
+ scoped_ptr<NotificationDatabase> database(CreateDatabaseInMemory());
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->Open(true /* create_if_missing */));
+
+ int64_t notification_id = 0;
+
+ NotificationDatabaseData database_data;
+ GURL origin("https://example.com");
+
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->WriteNotificationData(origin,
+ database_data,
+ &notification_id));
+
+ // Reading a notification after writing one should succeed.
+ EXPECT_EQ(NotificationDatabase::STATUS_OK,
+ database->ReadNotificationData(notification_id,
+ origin,
+ &database_data));
+
+ // Delete the notification which was just written to the database, and verify
+ // that reading it again will fail.
+ EXPECT_EQ(NotificationDatabase::STATUS_OK,
+ database->DeleteNotificationData(notification_id, origin));
+ EXPECT_EQ(NotificationDatabase::STATUS_ERROR_NOT_FOUND,
+ database->ReadNotificationData(notification_id,
+ origin,
+ &database_data));
+}
+
+TEST_F(NotificationDatabaseTest, DeleteNotificationDataDifferentOrigin) {
+ scoped_ptr<NotificationDatabase> database(CreateDatabaseInMemory());
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->Open(true /* create_if_missing */));
+
+ int64_t notification_id = 0;
+
+ NotificationDatabaseData database_data;
+ GURL origin("https://example.com");
+
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->WriteNotificationData(origin,
+ database_data,
+ &notification_id));
+
+ // Attempting to delete the notification with a different origin, but with the
+ // same |notification_id|, should not return an error (the notification could
+ // not be found, but that's not considered a failure). However, it should not
+ // remove the notification either.
+ EXPECT_EQ(NotificationDatabase::STATUS_OK,
+ database->DeleteNotificationData(notification_id,
+ GURL("https://chrome.com")));
+
+ EXPECT_EQ(NotificationDatabase::STATUS_OK,
+ database->ReadNotificationData(notification_id,
+ origin,
+ &database_data));
+}
+
+TEST_F(NotificationDatabaseTest, ReadAllNotificationData) {
+ scoped_ptr<NotificationDatabase> database(CreateDatabaseInMemory());
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->Open(true /* create_if_missing */));
+
+ ASSERT_NO_FATAL_FAILURE(PopulateDatabaseWithExampleData(database.get()));
+
+ std::vector<NotificationDatabaseData> notifications;
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->ReadAllNotificationData(&notifications));
+
+ EXPECT_EQ(arraysize(kExampleNotificationData), notifications.size());
+}
+
+TEST_F(NotificationDatabaseTest, ReadAllNotificationDataEmpty) {
+ scoped_ptr<NotificationDatabase> database(CreateDatabaseInMemory());
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->Open(true /* create_if_missing */));
+
+ std::vector<NotificationDatabaseData> notifications;
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->ReadAllNotificationData(&notifications));
+
+ EXPECT_EQ(0u, notifications.size());
+}
+
+TEST_F(NotificationDatabaseTest, ReadAllNotificationDataForOrigin) {
+ scoped_ptr<NotificationDatabase> database(CreateDatabaseInMemory());
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->Open(true /* create_if_missing */));
+
+ ASSERT_NO_FATAL_FAILURE(PopulateDatabaseWithExampleData(database.get()));
+
+ GURL origin("https://example.com");
+
+ std::vector<NotificationDatabaseData> notifications;
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->ReadAllNotificationDataForOrigin(origin, &notifications));
+
+ EXPECT_EQ(4u, notifications.size());
+}
+
+TEST_F(NotificationDatabaseTest,
+ ReadAllNotificationDataForServiceWorkerRegistration) {
+ scoped_ptr<NotificationDatabase> database(CreateDatabaseInMemory());
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->Open(true /* create_if_missing */));
+
+ ASSERT_NO_FATAL_FAILURE(PopulateDatabaseWithExampleData(database.get()));
+
+ GURL origin("https://example.com:443");
+
+ std::vector<NotificationDatabaseData> notifications;
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->ReadAllNotificationDataForServiceWorkerRegistration(
+ origin, kExampleServiceWorkerRegistrationId, &notifications));
+
+ EXPECT_EQ(2u, notifications.size());
+}
+
+TEST_F(NotificationDatabaseTest, DeleteAllNotificationDataForOrigin) {
+ scoped_ptr<NotificationDatabase> database(CreateDatabaseInMemory());
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->Open(true /* create_if_missing */));
+
+ ASSERT_NO_FATAL_FAILURE(PopulateDatabaseWithExampleData(database.get()));
+
+ GURL origin("https://example.com:443");
+
+ std::set<int64_t> deleted_notification_set;
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->DeleteAllNotificationDataForOrigin(
+ origin, &deleted_notification_set));
+
+ EXPECT_EQ(4u, deleted_notification_set.size());
+
+ std::vector<NotificationDatabaseData> notifications;
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->ReadAllNotificationDataForOrigin(origin, &notifications));
+
+ EXPECT_EQ(0u, notifications.size());
+}
+
+TEST_F(NotificationDatabaseTest, DeleteAllNotificationDataForOriginEmpty) {
+ scoped_ptr<NotificationDatabase> database(CreateDatabaseInMemory());
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->Open(true /* create_if_missing */));
+
+ GURL origin("https://example.com");
+
+ std::set<int64_t> deleted_notification_set;
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->DeleteAllNotificationDataForOrigin(
+ origin, &deleted_notification_set));
+
+ EXPECT_EQ(0u, deleted_notification_set.size());
+}
+
+TEST_F(NotificationDatabaseTest,
+ DeleteAllNotificationDataForServiceWorkerRegistration) {
+ scoped_ptr<NotificationDatabase> database(CreateDatabaseInMemory());
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->Open(true /* create_if_missing */));
+
+ ASSERT_NO_FATAL_FAILURE(PopulateDatabaseWithExampleData(database.get()));
+
+ GURL origin("https://example.com:443");
+ std::set<int64_t> deleted_notification_set;
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->DeleteAllNotificationDataForServiceWorkerRegistration(
+ origin,
+ kExampleServiceWorkerRegistrationId,
+ &deleted_notification_set));
+
+ EXPECT_EQ(2u, deleted_notification_set.size());
+
+ std::vector<NotificationDatabaseData> notifications;
+ ASSERT_EQ(NotificationDatabase::STATUS_OK,
+ database->ReadAllNotificationDataForServiceWorkerRegistration(
+ origin, kExampleServiceWorkerRegistrationId, &notifications));
+
+ EXPECT_EQ(0u, notifications.size());
+}
+
+} // namespace content
diff --git a/chromium/content/browser/notifications/notification_event_dispatcher_impl.cc b/chromium/content/browser/notifications/notification_event_dispatcher_impl.cc
new file mode 100644
index 00000000000..b135177f7e3
--- /dev/null
+++ b/chromium/content/browser/notifications/notification_event_dispatcher_impl.cc
@@ -0,0 +1,211 @@
+// Copyright 2014 The Chromium Authors. 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_event_dispatcher_impl.h"
+
+#include "base/callback.h"
+#include "content/browser/notifications/platform_notification_context_impl.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/notification_database_data.h"
+#include "content/public/browser/storage_partition.h"
+#include "content/public/common/platform_notification_data.h"
+
+namespace content {
+namespace {
+
+using NotificationClickDispatchCompleteCallback =
+ NotificationEventDispatcher::NotificationClickDispatchCompleteCallback;
+
+// To be called when the notificationclick event has finished executing. Will
+// post a task to call |dispatch_complete_callback| on the UI thread.
+void NotificationClickEventFinished(
+ const NotificationClickDispatchCompleteCallback& dispatch_complete_callback,
+ const scoped_refptr<ServiceWorkerRegistration>& service_worker_registration,
+ ServiceWorkerStatusCode service_worker_status) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ PersistentNotificationStatus status = PERSISTENT_NOTIFICATION_STATUS_SUCCESS;
+ switch (service_worker_status) {
+ case SERVICE_WORKER_OK:
+ // Success status was initialized above.
+ break;
+ case SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED:
+ status = PERSISTENT_NOTIFICATION_STATUS_EVENT_WAITUNTIL_REJECTED;
+ break;
+ case SERVICE_WORKER_ERROR_FAILED:
+ case SERVICE_WORKER_ERROR_ABORT:
+ case SERVICE_WORKER_ERROR_START_WORKER_FAILED:
+ case SERVICE_WORKER_ERROR_PROCESS_NOT_FOUND:
+ case SERVICE_WORKER_ERROR_NOT_FOUND:
+ case SERVICE_WORKER_ERROR_EXISTS:
+ case SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED:
+ case SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED:
+ case SERVICE_WORKER_ERROR_IPC_FAILED:
+ case SERVICE_WORKER_ERROR_NETWORK:
+ case SERVICE_WORKER_ERROR_SECURITY:
+ case SERVICE_WORKER_ERROR_STATE:
+ case SERVICE_WORKER_ERROR_TIMEOUT:
+ case SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED:
+ case SERVICE_WORKER_ERROR_DISK_CACHE:
+ case SERVICE_WORKER_ERROR_MAX_VALUE:
+ status = PERSISTENT_NOTIFICATION_STATUS_SERVICE_WORKER_ERROR;
+ break;
+ }
+
+ BrowserThread::PostTask(BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(dispatch_complete_callback, status));
+}
+
+// Dispatches the notificationclick on |service_worker_registration| if the
+// registration was available. Must be called on the IO thread.
+void DispatchNotificationClickEventOnRegistration(
+ const NotificationDatabaseData& notification_database_data,
+ const NotificationClickDispatchCompleteCallback& dispatch_complete_callback,
+ ServiceWorkerStatusCode service_worker_status,
+ const scoped_refptr<ServiceWorkerRegistration>&
+ service_worker_registration) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (service_worker_status == SERVICE_WORKER_OK) {
+ base::Callback<void(ServiceWorkerStatusCode)> dispatch_event_callback =
+ base::Bind(&NotificationClickEventFinished,
+ dispatch_complete_callback,
+ service_worker_registration);
+
+ service_worker_registration->active_version()->
+ DispatchNotificationClickEvent(
+ dispatch_event_callback,
+ notification_database_data.notification_id,
+ notification_database_data.notification_data);
+ return;
+ }
+
+ PersistentNotificationStatus status = PERSISTENT_NOTIFICATION_STATUS_SUCCESS;
+ switch (service_worker_status) {
+ case SERVICE_WORKER_ERROR_NOT_FOUND:
+ status = PERSISTENT_NOTIFICATION_STATUS_NO_SERVICE_WORKER;
+ break;
+ case SERVICE_WORKER_ERROR_FAILED:
+ case SERVICE_WORKER_ERROR_ABORT:
+ case SERVICE_WORKER_ERROR_START_WORKER_FAILED:
+ case SERVICE_WORKER_ERROR_PROCESS_NOT_FOUND:
+ case SERVICE_WORKER_ERROR_EXISTS:
+ case SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED:
+ case SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED:
+ case SERVICE_WORKER_ERROR_IPC_FAILED:
+ case SERVICE_WORKER_ERROR_NETWORK:
+ case SERVICE_WORKER_ERROR_SECURITY:
+ case SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED:
+ case SERVICE_WORKER_ERROR_STATE:
+ case SERVICE_WORKER_ERROR_TIMEOUT:
+ case SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED:
+ case SERVICE_WORKER_ERROR_DISK_CACHE:
+ case SERVICE_WORKER_ERROR_MAX_VALUE:
+ status = PERSISTENT_NOTIFICATION_STATUS_SERVICE_WORKER_ERROR;
+ break;
+ case SERVICE_WORKER_OK:
+ NOTREACHED();
+ break;
+ }
+
+ BrowserThread::PostTask(BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(dispatch_complete_callback, status));
+}
+
+// Finds the ServiceWorkerRegistration associated with the |origin| and
+// |service_worker_registration_id|. Must be called on the IO thread.
+void FindServiceWorkerRegistration(
+ const GURL& origin,
+ const NotificationClickDispatchCompleteCallback& dispatch_complete_callback,
+ scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
+ bool success,
+ const NotificationDatabaseData& notification_database_data) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (!success) {
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(dispatch_complete_callback,
+ PERSISTENT_NOTIFICATION_STATUS_DATABASE_ERROR));
+ return;
+ }
+
+ service_worker_context->FindRegistrationForId(
+ notification_database_data.service_worker_registration_id,
+ origin,
+ base::Bind(&DispatchNotificationClickEventOnRegistration,
+ notification_database_data,
+ dispatch_complete_callback));
+}
+
+// Reads the data associated with the |persistent_notification_id| belonging to
+// |origin| from the notification context.
+void ReadNotificationDatabaseData(
+ int64_t persistent_notification_id,
+ const GURL& origin,
+ const NotificationClickDispatchCompleteCallback& dispatch_complete_callback,
+ scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
+ scoped_refptr<PlatformNotificationContextImpl> notification_context) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ notification_context->ReadNotificationData(
+ persistent_notification_id,
+ origin,
+ base::Bind(&FindServiceWorkerRegistration,
+ origin, dispatch_complete_callback, service_worker_context));
+}
+
+} // namespace
+
+// static
+NotificationEventDispatcher* NotificationEventDispatcher::GetInstance() {
+ return NotificationEventDispatcherImpl::GetInstance();
+}
+
+NotificationEventDispatcherImpl*
+NotificationEventDispatcherImpl::GetInstance() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ return Singleton<NotificationEventDispatcherImpl>::get();
+}
+
+NotificationEventDispatcherImpl::NotificationEventDispatcherImpl() {}
+
+NotificationEventDispatcherImpl::~NotificationEventDispatcherImpl() {}
+
+void NotificationEventDispatcherImpl::DispatchNotificationClickEvent(
+ BrowserContext* browser_context,
+ int64_t persistent_notification_id,
+ const GURL& origin,
+ const NotificationClickDispatchCompleteCallback&
+ dispatch_complete_callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DCHECK_GT(persistent_notification_id, 0);
+ DCHECK(origin.is_valid());
+
+ StoragePartition* partition =
+ BrowserContext::GetStoragePartitionForSite(browser_context, origin);
+
+ scoped_refptr<ServiceWorkerContextWrapper> service_worker_context =
+ static_cast<ServiceWorkerContextWrapper*>(
+ partition->GetServiceWorkerContext());
+ scoped_refptr<PlatformNotificationContextImpl> notification_context =
+ static_cast<PlatformNotificationContextImpl*>(
+ partition->GetPlatformNotificationContext());
+
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&ReadNotificationDatabaseData,
+ persistent_notification_id,
+ origin,
+ dispatch_complete_callback,
+ service_worker_context,
+ notification_context));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/notifications/notification_event_dispatcher_impl.h b/chromium/content/browser/notifications/notification_event_dispatcher_impl.h
new file mode 100644
index 00000000000..86265dbac7f
--- /dev/null
+++ b/chromium/content/browser/notifications/notification_event_dispatcher_impl.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_NOTIFICATIONS_NOTIFICATION_EVENT_DISPATCHER_IMPL_H_
+#define CONTENT_BROWSER_NOTIFICATIONS_NOTIFICATION_EVENT_DISPATCHER_IMPL_H_
+
+#include "base/memory/singleton.h"
+#include "content/public/browser/notification_event_dispatcher.h"
+
+namespace content {
+
+class NotificationEventDispatcherImpl : public NotificationEventDispatcher {
+ public:
+ // Returns the instance of the NotificationEventDispatcherImpl. Must be called
+ // on the UI thread.
+ static NotificationEventDispatcherImpl* GetInstance();
+
+ // NotificationEventDispatcher implementation.
+ void DispatchNotificationClickEvent(
+ BrowserContext* browser_context,
+ int64_t persistent_notification_id,
+ const GURL& origin,
+ const NotificationClickDispatchCompleteCallback&
+ dispatch_complete_callback) override;
+
+ private:
+ NotificationEventDispatcherImpl();
+ ~NotificationEventDispatcherImpl() override;
+
+ friend struct DefaultSingletonTraits<NotificationEventDispatcherImpl>;
+
+ DISALLOW_COPY_AND_ASSIGN(NotificationEventDispatcherImpl);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_NOTIFICATIONS_NOTIFICATION_EVENT_DISPATCHER_IMPL_H_
diff --git a/chromium/content/browser/notifications/notification_message_filter.cc b/chromium/content/browser/notifications/notification_message_filter.cc
index fecd0730b77..9b9d38139e7 100644
--- a/chromium/content/browser/notifications/notification_message_filter.cc
+++ b/chromium/content/browser/notifications/notification_message_filter.cc
@@ -6,30 +6,63 @@
#include "base/callback.h"
#include "content/browser/notifications/page_notification_delegate.h"
+#include "content/browser/notifications/platform_notification_context_impl.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/browser/notification_database_data.h"
+#include "content/public/browser/platform_notification_service.h"
+#include "content/public/browser/render_process_host.h"
#include "content/public/common/content_client.h"
namespace content {
+namespace {
+
+const int kMinimumVibrationDurationMs = 1; // 1 millisecond
+const int kMaximumVibrationDurationMs = 10000; // 10 seconds
+
+PlatformNotificationData SanitizeNotificationData(
+ const PlatformNotificationData& notification_data) {
+ PlatformNotificationData sanitized_data = notification_data;
+
+ // Make sure that the vibration values are within reasonable bounds.
+ for (int& pattern : sanitized_data.vibration_pattern) {
+ pattern = std::min(kMaximumVibrationDurationMs,
+ std::max(kMinimumVibrationDurationMs, pattern));
+ }
+
+ return sanitized_data;
+}
+
+} // namespace
+
NotificationMessageFilter::NotificationMessageFilter(
int process_id,
+ PlatformNotificationContextImpl* notification_context,
ResourceContext* resource_context,
BrowserContext* browser_context)
: BrowserMessageFilter(PlatformNotificationMsgStart),
process_id_(process_id),
+ notification_context_(notification_context),
resource_context_(resource_context),
- browser_context_(browser_context) {}
+ browser_context_(browser_context),
+ weak_factory_io_(this) {}
NotificationMessageFilter::~NotificationMessageFilter() {}
void NotificationMessageFilter::DidCloseNotification(int notification_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
close_closures_.erase(notification_id);
}
+void NotificationMessageFilter::OnDestruct() const {
+ BrowserThread::DeleteOnIOThread::Destruct(this);
+}
+
bool NotificationMessageFilter::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(NotificationMessageFilter, message)
@@ -37,8 +70,14 @@ bool NotificationMessageFilter::OnMessageReceived(const IPC::Message& message) {
OnCheckNotificationPermission)
IPC_MESSAGE_HANDLER(PlatformNotificationHostMsg_Show,
OnShowPlatformNotification)
+ IPC_MESSAGE_HANDLER(PlatformNotificationHostMsg_ShowPersistent,
+ OnShowPersistentNotification)
+ IPC_MESSAGE_HANDLER(PlatformNotificationHostMsg_GetNotifications,
+ OnGetNotifications)
IPC_MESSAGE_HANDLER(PlatformNotificationHostMsg_Close,
OnClosePlatformNotification)
+ IPC_MESSAGE_HANDLER(PlatformNotificationHostMsg_ClosePersistent,
+ OnClosePersistentNotification)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
@@ -54,31 +93,157 @@ void NotificationMessageFilter::OverrideThreadForMessage(
void NotificationMessageFilter::OnCheckNotificationPermission(
const GURL& origin, blink::WebNotificationPermission* permission) {
- *permission =
- GetContentClient()->browser()->CheckDesktopNotificationPermission(
- origin,
- resource_context_,
- process_id_);
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ *permission = GetPermissionForOriginOnIO(origin);
}
void NotificationMessageFilter::OnShowPlatformNotification(
- int notification_id, const ShowDesktopNotificationHostMsgParams& params) {
+ int notification_id,
+ const GURL& origin,
+ const SkBitmap& icon,
+ const PlatformNotificationData& notification_data) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (!RenderProcessHost::FromID(process_id_))
+ return;
+
scoped_ptr<DesktopNotificationDelegate> delegate(
new PageNotificationDelegate(process_id_, notification_id));
+ PlatformNotificationService* service =
+ GetContentClient()->browser()->GetPlatformNotificationService();
+ DCHECK(service);
+
+ if (!VerifyNotificationPermissionGranted(service, origin))
+ return;
+
base::Closure close_closure;
- GetContentClient()->browser()->ShowDesktopNotification(params,
- browser_context_,
- process_id_,
- delegate.Pass(),
- &close_closure);
+ service->DisplayNotification(browser_context_,
+ origin,
+ icon,
+ SanitizeNotificationData(notification_data),
+ delegate.Pass(),
+ &close_closure);
if (!close_closure.is_null())
close_closures_[notification_id] = close_closure;
}
+void NotificationMessageFilter::OnShowPersistentNotification(
+ int request_id,
+ int64 service_worker_registration_id,
+ const GURL& origin,
+ const SkBitmap& icon,
+ const PlatformNotificationData& notification_data) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (GetPermissionForOriginOnIO(origin) !=
+ blink::WebNotificationPermissionAllowed) {
+ BadMessageReceived();
+ return;
+ }
+
+ NotificationDatabaseData database_data;
+ database_data.origin = origin;
+ database_data.service_worker_registration_id = service_worker_registration_id;
+
+ PlatformNotificationData sanitized_notification_data =
+ SanitizeNotificationData(notification_data);
+ database_data.notification_data = sanitized_notification_data;
+
+ // TODO(peter): Significantly reduce the amount of information we need to
+ // retain outside of the database for displaying notifications.
+ notification_context_->WriteNotificationData(
+ origin,
+ database_data,
+ base::Bind(&NotificationMessageFilter::DidWritePersistentNotificationData,
+ weak_factory_io_.GetWeakPtr(),
+ request_id,
+ origin,
+ icon,
+ sanitized_notification_data));
+}
+
+void NotificationMessageFilter::DidWritePersistentNotificationData(
+ int request_id,
+ const GURL& origin,
+ const SkBitmap& icon,
+ const PlatformNotificationData& notification_data,
+ bool success,
+ int64_t persistent_notification_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (success) {
+ PlatformNotificationService* service =
+ GetContentClient()->browser()->GetPlatformNotificationService();
+ DCHECK(service);
+
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&PlatformNotificationService::DisplayPersistentNotification,
+ base::Unretained(service), // The service is a singleton.
+ browser_context_,
+ persistent_notification_id,
+ origin,
+ icon,
+ notification_data));
+ }
+
+ Send(new PlatformNotificationMsg_DidShowPersistent(request_id, success));
+}
+
+void NotificationMessageFilter::OnGetNotifications(
+ int request_id,
+ int64_t service_worker_registration_id,
+ const GURL& origin,
+ const std::string& filter_tag) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (GetPermissionForOriginOnIO(origin) !=
+ blink::WebNotificationPermissionAllowed) {
+ // No permission has been granted for the given origin. It is harmless to
+ // try to get notifications without permission, so return an empty vector
+ // indicating that no (accessible) notifications exist at this time.
+ Send(new PlatformNotificationMsg_DidGetNotifications(
+ request_id, std::vector<PersistentNotificationInfo>()));
+ return;
+ }
+
+ notification_context_->ReadAllNotificationDataForServiceWorkerRegistration(
+ origin,
+ service_worker_registration_id,
+ base::Bind(&NotificationMessageFilter::DidGetNotifications,
+ weak_factory_io_.GetWeakPtr(),
+ request_id,
+ filter_tag));
+}
+
+void NotificationMessageFilter::DidGetNotifications(
+ int request_id,
+ const std::string& filter_tag,
+ bool success,
+ const std::vector<NotificationDatabaseData>& notifications) {
+ std::vector<PersistentNotificationInfo> persistent_notifications;
+ for (const NotificationDatabaseData& database_data : notifications) {
+ if (!filter_tag.empty()) {
+ const std::string& tag = database_data.notification_data.tag;
+ if (tag != filter_tag)
+ continue;
+ }
+
+ persistent_notifications.push_back(std::make_pair(
+ database_data.notification_id, database_data.notification_data));
+ }
+
+ Send(new PlatformNotificationMsg_DidGetNotifications(
+ request_id, persistent_notifications));
+}
+
void NotificationMessageFilter::OnClosePlatformNotification(
int notification_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (!RenderProcessHost::FromID(process_id_))
+ return;
+
if (!close_closures_.count(notification_id))
return;
@@ -86,4 +251,75 @@ void NotificationMessageFilter::OnClosePlatformNotification(
close_closures_.erase(notification_id);
}
+void NotificationMessageFilter::OnClosePersistentNotification(
+ const GURL& origin,
+ int64_t persistent_notification_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (GetPermissionForOriginOnIO(origin) !=
+ blink::WebNotificationPermissionAllowed) {
+ BadMessageReceived();
+ return;
+ }
+
+ PlatformNotificationService* service =
+ GetContentClient()->browser()->GetPlatformNotificationService();
+ DCHECK(service);
+
+ // There's no point in waiting until the database data has been removed before
+ // closing the notification presented to the user. Post that task immediately.
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&PlatformNotificationService::ClosePersistentNotification,
+ base::Unretained(service), // The service is a singleton.
+ browser_context_,
+ persistent_notification_id));
+
+ notification_context_->DeleteNotificationData(
+ persistent_notification_id,
+ origin,
+ base::Bind(&NotificationMessageFilter::
+ DidDeletePersistentNotificationData,
+ weak_factory_io_.GetWeakPtr()));
+}
+
+void NotificationMessageFilter::DidDeletePersistentNotificationData(
+ bool success) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ // TODO(peter): Consider feeding back to the renderer that the notification
+ // has been closed.
+}
+
+blink::WebNotificationPermission
+NotificationMessageFilter::GetPermissionForOriginOnIO(
+ const GURL& origin) const {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ PlatformNotificationService* service =
+ GetContentClient()->browser()->GetPlatformNotificationService();
+ if (!service)
+ return blink::WebNotificationPermissionDenied;
+
+ return service->CheckPermissionOnIOThread(resource_context_,
+ origin,
+ process_id_);
+}
+
+bool NotificationMessageFilter::VerifyNotificationPermissionGranted(
+ PlatformNotificationService* service,
+ const GURL& origin) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ blink::WebNotificationPermission permission =
+ service->CheckPermissionOnUIThread(browser_context_,
+ origin,
+ process_id_);
+
+ if (permission == blink::WebNotificationPermissionAllowed)
+ return true;
+
+ BadMessageReceived();
+ return false;
+}
+
} // namespace content
diff --git a/chromium/content/browser/notifications/notification_message_filter.h b/chromium/content/browser/notifications/notification_message_filter.h
index 0b5159b18b7..c5ad0a4ac69 100644
--- a/chromium/content/browser/notifications/notification_message_filter.h
+++ b/chromium/content/browser/notifications/notification_message_filter.h
@@ -8,21 +8,27 @@
#include <map>
#include "base/callback_forward.h"
+#include "base/memory/weak_ptr.h"
#include "content/public/browser/browser_message_filter.h"
-#include "third_party/WebKit/public/platform/WebNotificationPermission.h"
+#include "content/public/browser/notification_database_data.h"
+#include "third_party/WebKit/public/platform/modules/notifications/WebNotificationPermission.h"
class GURL;
+class SkBitmap;
namespace content {
class BrowserContext;
+class PlatformNotificationContextImpl;
+struct PlatformNotificationData;
+class PlatformNotificationService;
class ResourceContext;
-struct ShowDesktopNotificationHostMsgParams;
class NotificationMessageFilter : public BrowserMessageFilter {
public:
NotificationMessageFilter(
int process_id,
+ PlatformNotificationContextImpl* notification_context,
ResourceContext* resource_context,
BrowserContext* browser_context);
@@ -31,6 +37,7 @@ class NotificationMessageFilter : public BrowserMessageFilter {
void DidCloseNotification(int notification_id);
// BrowserMessageFilter implementation. Called on the UI thread.
+ void OnDestruct() const override;
bool OnMessageReceived(const IPC::Message& message) override;
void OverrideThreadForMessage(
const IPC::Message& message, content::BrowserThread::ID* thread) override;
@@ -39,18 +46,82 @@ class NotificationMessageFilter : public BrowserMessageFilter {
~NotificationMessageFilter() override;
private:
+ friend class base::DeleteHelper<NotificationMessageFilter>;
+ friend class BrowserThread;
+
void OnCheckNotificationPermission(
const GURL& origin, blink::WebNotificationPermission* permission);
void OnShowPlatformNotification(
- int notification_id, const ShowDesktopNotificationHostMsgParams& params);
+ int notification_id,
+ const GURL& origin,
+ const SkBitmap& icon,
+ const PlatformNotificationData& notification_data);
+ void OnShowPersistentNotification(
+ int request_id,
+ int64 service_worker_registration_id,
+ const GURL& origin,
+ const SkBitmap& icon,
+ const PlatformNotificationData& notification_data);
+ void OnGetNotifications(int request_id,
+ int64_t service_worker_registration_id,
+ const GURL& origin,
+ const std::string& filter_tag);
void OnClosePlatformNotification(int notification_id);
+ void OnClosePersistentNotification(
+ const GURL& origin,
+ int64_t persistent_notification_id);
+
+ // Callback to be invoked by the notification context when the notification
+ // data for the persistent notification may have been written, as indicated by
+ // |success|. Will present the notification to the user when successful.
+ void DidWritePersistentNotificationData(
+ int request_id,
+ const GURL& origin,
+ const SkBitmap& icon,
+ const PlatformNotificationData& notification_data,
+ bool success,
+ int64_t persistent_notification_id);
+
+ // Callback to be invoked when all notifications belonging to a Service Worker
+ // registration have been read from the database. The |success| argument
+ // indicates whether the data could be read successfully, whereas the actual
+ // notifications will be stored in |notifications|.
+ void DidGetNotifications(
+ int request_id,
+ const std::string& filter_tag,
+ bool success,
+ const std::vector<NotificationDatabaseData>& notifications);
+
+ // Callback to be invoked when the data associated with a persistent
+ // notification has been removed by the database, unless an error occurred,
+ // which will be indicated by |success|.
+ void DidDeletePersistentNotificationData(bool success);
+
+ // Returns the permission status for |origin|. Must only be used on the IO
+ // thread. If the PlatformNotificationService is unavailable, permission will
+ // assumed to be denied.
+ blink::WebNotificationPermission GetPermissionForOriginOnIO(
+ const GURL& origin) const;
+
+ // Verifies that Web Notification permission has been granted for |origin| in
+ // cases where the renderer shouldn't send messages if it weren't the case. If
+ // no permission has been granted, a bad message has been received and the
+ // renderer should be killed accordingly.
+ bool VerifyNotificationPermissionGranted(
+ PlatformNotificationService* service,
+ const GURL& origin);
int process_id_;
+ scoped_refptr<PlatformNotificationContextImpl> notification_context_;
ResourceContext* resource_context_;
BrowserContext* browser_context_;
// Map mapping notification ids to their associated close closures.
std::map<int, base::Closure> close_closures_;
+
+ base::WeakPtrFactory<NotificationMessageFilter> weak_factory_io_;
+
+ DISALLOW_COPY_AND_ASSIGN(NotificationMessageFilter);
};
} // namespace content
diff --git a/chromium/content/browser/notifications/notification_proto.gyp b/chromium/content/browser/notifications/notification_proto.gyp
new file mode 100644
index 00000000000..effe03e10fb
--- /dev/null
+++ b/chromium/content/browser/notifications/notification_proto.gyp
@@ -0,0 +1,17 @@
+{
+ 'targets': [
+ {
+ # GN version: //content/browser/notifications:notification_proto
+ 'target_name': 'notification_proto',
+ 'type': 'static_library',
+ 'sources': [
+ 'notification_database_data.proto',
+ ],
+ 'variables': {
+ 'proto_in_dir': '.',
+ 'proto_out_dir': 'content/browser/notifications',
+ },
+ 'includes': [ '../../../build/protoc.gypi' ]
+ },
+ ],
+}
diff --git a/chromium/content/browser/notifications/page_notification_delegate.cc b/chromium/content/browser/notifications/page_notification_delegate.cc
index dacfffbfd22..fdf085d7c7c 100644
--- a/chromium/content/browser/notifications/page_notification_delegate.cc
+++ b/chromium/content/browser/notifications/page_notification_delegate.cc
@@ -26,8 +26,7 @@ void PageNotificationDelegate::NotificationDisplayed() {
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) {
+void PageNotificationDelegate::NotificationClosed() {
RenderProcessHost* sender = RenderProcessHost::FromID(render_process_id_);
if (!sender)
return;
diff --git a/chromium/content/browser/notifications/page_notification_delegate.h b/chromium/content/browser/notifications/page_notification_delegate.h
index dd3422f2c4e..fd45f9152bc 100644
--- a/chromium/content/browser/notifications/page_notification_delegate.h
+++ b/chromium/content/browser/notifications/page_notification_delegate.h
@@ -19,7 +19,7 @@ class PageNotificationDelegate : public DesktopNotificationDelegate {
// DesktopNotificationDelegate implementation.
void NotificationDisplayed() override;
- void NotificationClosed(bool by_user) override;
+ void NotificationClosed() override;
void NotificationClick() override;
private:
diff --git a/chromium/content/browser/notifications/platform_notification_context_impl.cc b/chromium/content/browser/notifications/platform_notification_context_impl.cc
new file mode 100644
index 00000000000..bdeabce55af
--- /dev/null
+++ b/chromium/content/browser/notifications/platform_notification_context_impl.cc
@@ -0,0 +1,429 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/notifications/platform_notification_context_impl.h"
+
+#include "base/bind_helpers.h"
+#include "base/files/file_util.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "content/browser/notifications/notification_database.h"
+#include "content/browser/service_worker/service_worker_context_wrapper.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/notification_database_data.h"
+#include "content/public/browser/platform_notification_service.h"
+
+using base::DoNothing;
+
+namespace content {
+
+// Name of the directory in the user's profile directory where the notification
+// database files should be stored.
+const base::FilePath::CharType kPlatformNotificationsDirectory[] =
+ FILE_PATH_LITERAL("Platform Notifications");
+
+PlatformNotificationContextImpl::PlatformNotificationContextImpl(
+ const base::FilePath& path,
+ BrowserContext* browser_context,
+ const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context)
+ : path_(path),
+ browser_context_(browser_context),
+ service_worker_context_(service_worker_context) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+}
+
+PlatformNotificationContextImpl::~PlatformNotificationContextImpl() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ // If the database has been initialized, it must be deleted on the task runner
+ // thread as closing it may cause file I/O.
+ if (database_) {
+ DCHECK(task_runner_);
+ task_runner_->DeleteSoon(FROM_HERE, database_.release());
+ }
+}
+
+void PlatformNotificationContextImpl::Initialize() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ PlatformNotificationService* service =
+ GetContentClient()->browser()->GetPlatformNotificationService();
+ if (service) {
+ std::set<std::string> displayed_notifications;
+
+ bool notification_synchronization_supported =
+ service->GetDisplayedPersistentNotifications(browser_context_,
+ &displayed_notifications);
+
+ // Synchronize the notifications stored in the database with the set of
+ // displaying notifications in |displayed_notifications|. This is necessary
+ // because flakiness may cause a platform to inform Chrome of a notification
+ // that has since been closed, or because the platform does not support
+ // notifications that exceed the lifetime of the browser process.
+
+ // TODO(peter): Synchronizing the actual notifications will be done when the
+ // persistent notification ids are stable. For M44 we need to support the
+ // case where there may be no notifications after a Chrome restart.
+ if (notification_synchronization_supported &&
+ !displayed_notifications.size()) {
+ prune_database_on_open_ = true;
+ }
+ }
+
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&PlatformNotificationContextImpl::InitializeOnIO, this));
+}
+
+void PlatformNotificationContextImpl::InitializeOnIO() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ // |service_worker_context_| may be NULL in tests.
+ if (service_worker_context_)
+ service_worker_context_->AddObserver(this);
+}
+
+void PlatformNotificationContextImpl::Shutdown() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&PlatformNotificationContextImpl::ShutdownOnIO, this));
+}
+
+void PlatformNotificationContextImpl::ShutdownOnIO() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ // |service_worker_context_| may be NULL in tests.
+ if (service_worker_context_)
+ service_worker_context_->RemoveObserver(this);
+}
+
+void PlatformNotificationContextImpl::ReadNotificationData(
+ int64_t notification_id,
+ const GURL& origin,
+ const ReadResultCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ LazyInitialize(
+ base::Bind(&PlatformNotificationContextImpl::DoReadNotificationData,
+ this, notification_id, origin, callback),
+ base::Bind(callback, false /* success */, NotificationDatabaseData()));
+}
+
+void PlatformNotificationContextImpl::DoReadNotificationData(
+ int64_t notification_id,
+ const GURL& origin,
+ const ReadResultCallback& callback) {
+ DCHECK(task_runner_->RunsTasksOnCurrentThread());
+
+ NotificationDatabaseData database_data;
+ NotificationDatabase::Status status =
+ database_->ReadNotificationData(notification_id,
+ origin,
+ &database_data);
+
+ UMA_HISTOGRAM_ENUMERATION("Notifications.Database.ReadResult",
+ status, NotificationDatabase::STATUS_COUNT);
+
+ if (status == NotificationDatabase::STATUS_OK) {
+ BrowserThread::PostTask(BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(callback,
+ true /* success */,
+ database_data));
+ return;
+ }
+
+ // Blow away the database if reading data failed due to corruption.
+ if (status == NotificationDatabase::STATUS_ERROR_CORRUPTED)
+ DestroyDatabase();
+
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(callback, false /* success */, NotificationDatabaseData()));
+}
+
+void PlatformNotificationContextImpl::
+ ReadAllNotificationDataForServiceWorkerRegistration(
+ const GURL& origin,
+ int64_t service_worker_registration_id,
+ const ReadAllResultCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ LazyInitialize(
+ base::Bind(&PlatformNotificationContextImpl::
+ DoReadAllNotificationDataForServiceWorkerRegistration,
+ this, origin, service_worker_registration_id, callback),
+ base::Bind(callback,
+ false /* success */,
+ std::vector<NotificationDatabaseData>()));
+}
+
+void PlatformNotificationContextImpl::
+ DoReadAllNotificationDataForServiceWorkerRegistration(
+ const GURL& origin,
+ int64_t service_worker_registration_id,
+ const ReadAllResultCallback& callback) {
+ DCHECK(task_runner_->RunsTasksOnCurrentThread());
+
+ std::vector<NotificationDatabaseData> notification_datas;
+
+ NotificationDatabase::Status status =
+ database_->ReadAllNotificationDataForServiceWorkerRegistration(
+ origin, service_worker_registration_id, &notification_datas);
+
+ UMA_HISTOGRAM_ENUMERATION("Notifications.Database.ReadForServiceWorkerResult",
+ status, NotificationDatabase::STATUS_COUNT);
+
+ if (status == NotificationDatabase::STATUS_OK) {
+ BrowserThread::PostTask(BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(callback,
+ true /* success */,
+ notification_datas));
+ return;
+ }
+
+ // Blow away the database if reading data failed due to corruption.
+ if (status == NotificationDatabase::STATUS_ERROR_CORRUPTED)
+ DestroyDatabase();
+
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(callback,
+ false /* success */,
+ std::vector<NotificationDatabaseData>()));
+}
+
+void PlatformNotificationContextImpl::WriteNotificationData(
+ const GURL& origin,
+ const NotificationDatabaseData& database_data,
+ const WriteResultCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ LazyInitialize(
+ base::Bind(&PlatformNotificationContextImpl::DoWriteNotificationData,
+ this, origin, database_data, callback),
+ base::Bind(callback, false /* success */, 0 /* notification_id */));
+}
+
+void PlatformNotificationContextImpl::DoWriteNotificationData(
+ const GURL& origin,
+ const NotificationDatabaseData& database_data,
+ const WriteResultCallback& callback) {
+ DCHECK(task_runner_->RunsTasksOnCurrentThread());
+
+ int64_t notification_id = 0;
+ NotificationDatabase::Status status =
+ database_->WriteNotificationData(origin,
+ database_data,
+ &notification_id);
+
+ UMA_HISTOGRAM_ENUMERATION("Notifications.Database.WriteResult",
+ status, NotificationDatabase::STATUS_COUNT);
+
+ if (status == NotificationDatabase::STATUS_OK) {
+ DCHECK_GT(notification_id, 0);
+ BrowserThread::PostTask(BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(callback,
+ true /* success */,
+ notification_id));
+ return;
+ }
+
+ // Blow away the database if writing data failed due to corruption.
+ if (status == NotificationDatabase::STATUS_ERROR_CORRUPTED)
+ DestroyDatabase();
+
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(callback, false /* success */, 0 /* notification_id */));
+}
+
+void PlatformNotificationContextImpl::DeleteNotificationData(
+ int64_t notification_id,
+ const GURL& origin,
+ const DeleteResultCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ LazyInitialize(
+ base::Bind(&PlatformNotificationContextImpl::DoDeleteNotificationData,
+ this, notification_id, origin, callback),
+ base::Bind(callback, false /* success */));
+}
+
+void PlatformNotificationContextImpl::DoDeleteNotificationData(
+ int64_t notification_id,
+ const GURL& origin,
+ const DeleteResultCallback& callback) {
+ DCHECK(task_runner_->RunsTasksOnCurrentThread());
+
+ NotificationDatabase::Status status =
+ database_->DeleteNotificationData(notification_id, origin);
+
+ UMA_HISTOGRAM_ENUMERATION("Notifications.Database.DeleteResult",
+ status, NotificationDatabase::STATUS_COUNT);
+
+ bool success = status == NotificationDatabase::STATUS_OK;
+
+ // Blow away the database if deleting data failed due to corruption. Following
+ // the contract of the delete methods, consider this to be a success as the
+ // caller's goal has been achieved: the data is gone.
+ if (status == NotificationDatabase::STATUS_ERROR_CORRUPTED) {
+ DestroyDatabase();
+ success = true;
+ }
+
+ BrowserThread::PostTask(BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(callback, success));
+}
+
+void PlatformNotificationContextImpl::OnRegistrationDeleted(
+ int64_t registration_id,
+ const GURL& pattern) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ LazyInitialize(
+ base::Bind(&PlatformNotificationContextImpl::
+ DoDeleteNotificationsForServiceWorkerRegistration,
+ this, pattern.GetOrigin(), registration_id),
+ base::Bind(&DoNothing));
+}
+
+void PlatformNotificationContextImpl::
+ DoDeleteNotificationsForServiceWorkerRegistration(
+ const GURL& origin,
+ int64_t service_worker_registration_id) {
+ DCHECK(task_runner_->RunsTasksOnCurrentThread());
+
+ std::set<int64_t> deleted_notifications_set;
+ NotificationDatabase::Status status =
+ database_->DeleteAllNotificationDataForServiceWorkerRegistration(
+ origin, service_worker_registration_id, &deleted_notifications_set);
+
+ UMA_HISTOGRAM_ENUMERATION(
+ "Notifications.Database.DeleteServiceWorkerRegistrationResult",
+ status, NotificationDatabase::STATUS_COUNT);
+
+ // Blow away the database if a corruption error occurred during the deletion.
+ if (status == NotificationDatabase::STATUS_ERROR_CORRUPTED)
+ DestroyDatabase();
+
+ // TODO(peter): Close the notifications in |deleted_notifications_set|.
+}
+
+void PlatformNotificationContextImpl::OnStorageWiped() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ LazyInitialize(
+ base::Bind(base::IgnoreResult(
+ &PlatformNotificationContextImpl::DestroyDatabase), this),
+ base::Bind(&DoNothing));
+}
+
+void PlatformNotificationContextImpl::LazyInitialize(
+ const base::Closure& success_closure,
+ const base::Closure& failure_closure) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (!task_runner_) {
+ base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool();
+ base::SequencedWorkerPool::SequenceToken token = pool->GetSequenceToken();
+
+ task_runner_ = pool->GetSequencedTaskRunner(token);
+ }
+
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&PlatformNotificationContextImpl::OpenDatabase,
+ this, success_closure, failure_closure));
+}
+
+void PlatformNotificationContextImpl::OpenDatabase(
+ const base::Closure& success_closure,
+ const base::Closure& failure_closure) {
+ DCHECK(task_runner_->RunsTasksOnCurrentThread());
+
+ if (database_) {
+ success_closure.Run();
+ return;
+ }
+
+ database_.reset(new NotificationDatabase(GetDatabasePath()));
+ NotificationDatabase::Status status =
+ database_->Open(true /* create_if_missing */);
+
+ UMA_HISTOGRAM_ENUMERATION("Notifications.Database.OpenResult",
+ status, NotificationDatabase::STATUS_COUNT);
+
+ // TODO(peter): Do finer-grained synchronization here.
+ if (prune_database_on_open_) {
+ prune_database_on_open_ = false;
+ DestroyDatabase();
+
+ database_.reset(new NotificationDatabase(GetDatabasePath()));
+ status = database_->Open(true /* create_if_missing */);
+
+ // TODO(peter): Find the appropriate UMA to cover in regards to
+ // synchronizing notifications after the implementation is complete.
+ }
+
+ // When the database could not be opened due to corruption, destroy it, blow
+ // away the contents of the directory and try re-opening the database.
+ if (status == NotificationDatabase::STATUS_ERROR_CORRUPTED) {
+ if (DestroyDatabase()) {
+ database_.reset(new NotificationDatabase(GetDatabasePath()));
+ status = database_->Open(true /* create_if_missing */);
+
+ UMA_HISTOGRAM_ENUMERATION(
+ "Notifications.Database.OpenAfterCorruptionResult",
+ status, NotificationDatabase::STATUS_COUNT);
+ }
+ }
+
+ if (status == NotificationDatabase::STATUS_OK) {
+ success_closure.Run();
+ return;
+ }
+
+ database_.reset();
+
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, failure_closure);
+}
+
+bool PlatformNotificationContextImpl::DestroyDatabase() {
+ DCHECK(task_runner_->RunsTasksOnCurrentThread());
+ DCHECK(database_);
+
+ NotificationDatabase::Status status = database_->Destroy();
+ UMA_HISTOGRAM_ENUMERATION("Notifications.Database.DestroyResult",
+ status, NotificationDatabase::STATUS_COUNT);
+
+ database_.reset();
+
+ // TODO(peter): Close any existing persistent notifications on the platform.
+
+ // Remove all files in the directory that the database was previously located
+ // in, to make sure that any left-over files are gone as well.
+ base::FilePath database_path = GetDatabasePath();
+ if (!database_path.empty())
+ return base::DeleteFile(database_path, true);
+
+ return true;
+}
+
+base::FilePath PlatformNotificationContextImpl::GetDatabasePath() const {
+ if (path_.empty())
+ return path_;
+
+ return path_.Append(kPlatformNotificationsDirectory);
+}
+
+void PlatformNotificationContextImpl::SetTaskRunnerForTesting(
+ const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
+ task_runner_ = task_runner;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/notifications/platform_notification_context_impl.h b/chromium/content/browser/notifications/platform_notification_context_impl.h
new file mode 100644
index 00000000000..a41729b9944
--- /dev/null
+++ b/chromium/content/browser/notifications/platform_notification_context_impl.h
@@ -0,0 +1,161 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_NOTIFICATIONS_PLATFORM_NOTIFICATION_CONTEXT_IMPL_H_
+#define CONTENT_BROWSER_NOTIFICATIONS_PLATFORM_NOTIFICATION_CONTEXT_IMPL_H_
+
+#include <stdint.h>
+#include <set>
+#include <string>
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/ref_counted.h"
+#include "content/browser/service_worker/service_worker_context_observer.h"
+#include "content/common/content_export.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/platform_notification_context.h"
+
+class GURL;
+
+namespace base {
+class SequencedTaskRunner;
+}
+
+namespace content {
+
+class BrowserContext;
+class NotificationDatabase;
+struct NotificationDatabaseData;
+class ServiceWorkerContextWrapper;
+
+// Implementation of the Web Notification storage context. The public methods
+// defined in this interface must only be called on the IO thread unless
+// otherwise specified.
+class CONTENT_EXPORT PlatformNotificationContextImpl
+ : NON_EXPORTED_BASE(public PlatformNotificationContext),
+ NON_EXPORTED_BASE(public ServiceWorkerContextObserver) {
+ public:
+ // Constructs a new platform notification context. If |path| is non-empty, the
+ // database will be initialized in the "Platform Notifications" subdirectory
+ // of |path|. Otherwise, the database will be initialized in memory. The
+ // constructor must only be called on the IO thread.
+ PlatformNotificationContextImpl(
+ const base::FilePath& path,
+ BrowserContext* browser_context,
+ const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context);
+
+ // To be called on the UI thread to initialize the instance.
+ void Initialize();
+
+ // To be called on the UI thread when the context is being shut down.
+ void Shutdown();
+
+ // PlatformNotificationContext implementation.
+ void ReadNotificationData(int64_t notification_id,
+ const GURL& origin,
+ const ReadResultCallback& callback) override;
+ void WriteNotificationData(const GURL& origin,
+ const NotificationDatabaseData& database_data,
+ const WriteResultCallback& callback) override;
+ void DeleteNotificationData(int64_t notification_id,
+ const GURL& origin,
+ const DeleteResultCallback& callback) override;
+ void ReadAllNotificationDataForServiceWorkerRegistration(
+ const GURL& origin,
+ int64_t service_worker_registration_id,
+ const ReadAllResultCallback& callback) override;
+
+ // ServiceWorkerContextObserver implementation.
+ void OnRegistrationDeleted(int64_t registration_id,
+ const GURL& pattern) override;
+ void OnStorageWiped() override;
+
+ private:
+ friend class PlatformNotificationContextTest;
+
+ ~PlatformNotificationContextImpl() override;
+
+ void InitializeOnIO();
+ void ShutdownOnIO();
+
+ // Initializes the database if neccesary. Must be called on the IO thread.
+ // |success_closure| will be invoked on a the |task_runner_| thread when
+ // everything is available, or |failure_closure_| will be invoked on the
+ // IO thread when initialization fails.
+ void LazyInitialize(const base::Closure& success_closure,
+ const base::Closure& failure_closure);
+
+ // Opens the database. Must be called on the |task_runner_| thread. When the
+ // database has been opened, |success_closure| will be invoked on the task
+ // thread, otherwise |failure_closure_| will be invoked on the IO thread.
+ void OpenDatabase(const base::Closure& success_closure,
+ const base::Closure& failure_closure);
+
+ // Actually reads the notification data from the database. Must only be
+ // called on the |task_runner_| thread. |callback| will be invoked on the
+ // IO thread when the operation has completed.
+ void DoReadNotificationData(int64_t notification_id,
+ const GURL& origin,
+ const ReadResultCallback& callback);
+
+ // Actually reads all notification data from the database. Must only be
+ // called on the |task_runner_| thread. |callback| will be invoked on the
+ // IO thread when the operation has completed.
+ void DoReadAllNotificationDataForServiceWorkerRegistration(
+ const GURL& origin,
+ int64_t service_worker_registration_id,
+ const ReadAllResultCallback& callback);
+
+ // Actually writes the notification database to the database. Must only be
+ // called on the |task_runner_| thread. |callback| will be invoked on the
+ // IO thread when the operation has completed.
+ void DoWriteNotificationData(const GURL& origin,
+ const NotificationDatabaseData& database_data,
+ const WriteResultCallback& callback);
+
+ // Actually deletes the notification information from the database. Must only
+ // be called on the |task_runner_| thread. |callback| will be invoked on the
+ // IO thread when the operation has completed.
+ void DoDeleteNotificationData(int64_t notification_id,
+ const GURL& origin,
+ const DeleteResultCallback& callback);
+
+ // Deletes all notifications associated with |service_worker_registration_id|
+ // belonging to |origin|. Must be called on the |task_runner_| thread.
+ void DoDeleteNotificationsForServiceWorkerRegistration(
+ const GURL& origin,
+ int64_t service_worker_registration_id);
+
+ // Destroys the database regardless of its initialization status. This method
+ // must only be called on the |task_runner_| thread. Returns if the directory
+ // the database was stored in could be emptied.
+ bool DestroyDatabase();
+
+ // Returns the path in which the database should be initialized. May be empty.
+ base::FilePath GetDatabasePath() const;
+
+ // Sets the task runner to use for testing purposes.
+ void SetTaskRunnerForTesting(
+ const scoped_refptr<base::SequencedTaskRunner>& task_runner);
+
+ base::FilePath path_;
+ BrowserContext* browser_context_;
+
+ scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_;
+
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
+ scoped_ptr<NotificationDatabase> database_;
+
+ // Indicates whether the database should be pruned when it's opened.
+ bool prune_database_on_open_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(PlatformNotificationContextImpl);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_NOTIFICATIONS_PLATFORM_NOTIFICATION_CONTEXT_IMPL_H_
diff --git a/chromium/content/browser/notifications/platform_notification_context_unittest.cc b/chromium/content/browser/notifications/platform_notification_context_unittest.cc
new file mode 100644
index 00000000000..30ab46a78fa
--- /dev/null
+++ b/chromium/content/browser/notifications/platform_notification_context_unittest.cc
@@ -0,0 +1,448 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/run_loop.h"
+#include "content/browser/notifications/platform_notification_context_impl.h"
+#include "content/browser/service_worker/embedded_worker_test_helper.h"
+#include "content/browser/service_worker/service_worker_context_wrapper.h"
+#include "content/common/service_worker/service_worker_types.h"
+#include "content/public/browser/notification_database_data.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"
+#include "url/gurl.h"
+
+namespace content {
+
+// Fake render process id to use in tests requiring one.
+const int kFakeRenderProcessId = 99;
+
+// Fake Service Worker registration id to use in tests requiring one.
+const int64_t kFakeServiceWorkerRegistrationId = 42;
+
+class PlatformNotificationContextTest : public ::testing::Test {
+ public:
+ PlatformNotificationContextTest()
+ : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP),
+ success_(false) {}
+
+ // Callback to provide when reading a single notification from the database.
+ void DidReadNotificationData(
+ bool success, const NotificationDatabaseData& database_data) {
+ success_ = success;
+ database_data_ = database_data;
+ }
+
+ // Callback to provide when writing a notification to the database.
+ void DidWriteNotificationData(bool success, int64_t notification_id) {
+ success_ = success;
+ notification_id_ = notification_id;
+ }
+
+ // Callback to provide when deleting notification data from the database.
+ void DidDeleteNotificationData(bool success) {
+ success_ = success;
+ }
+
+ // Callback to provide when registering a Service Worker with a Service
+ // Worker Context. Will write the registration id to |store_registration_id|.
+ void DidRegisterServiceWorker(int64_t* store_registration_id,
+ ServiceWorkerStatusCode status,
+ const std::string& status_message,
+ int64_t service_worker_registration_id) {
+ DCHECK(store_registration_id);
+ EXPECT_EQ(SERVICE_WORKER_OK, status);
+
+ *store_registration_id = service_worker_registration_id;
+ }
+
+ // Callback to provide when unregistering a Service Worker. Will write the
+ // resulting status code to |store_status|.
+ void DidUnregisterServiceWorker(ServiceWorkerStatusCode* store_status,
+ ServiceWorkerStatusCode status) {
+ DCHECK(store_status);
+ *store_status = status;
+ }
+
+ // Callback to provide when reading multiple notifications from the database.
+ // Will store the success value in the class member, and write the read
+ // notification datas to |store_notification_datas|.
+ void DidReadAllNotificationDatas(
+ std::vector<NotificationDatabaseData>* store_notification_datas,
+ bool success,
+ const std::vector<NotificationDatabaseData>& notification_datas) {
+ DCHECK(store_notification_datas);
+
+ success_ = success;
+ *store_notification_datas = notification_datas;
+ }
+
+ protected:
+ // Creates a new PlatformNotificationContextImpl instance. When using this
+ // method, the underlying database will always be created in memory. The
+ // current message loop proxy will be used as the task runner.
+ PlatformNotificationContextImpl* CreatePlatformNotificationContext() {
+ PlatformNotificationContextImpl* context =
+ new PlatformNotificationContextImpl(base::FilePath(),
+ &browser_context_,
+ nullptr);
+ context->Initialize();
+
+ OverrideTaskRunnerForTesting(context);
+ return context;
+ }
+
+ // Overrides the task runner in |context| with the current message loop
+ // proxy, to reduce the number of threads involved in the tests.
+ void OverrideTaskRunnerForTesting(PlatformNotificationContextImpl* context) {
+ context->SetTaskRunnerForTesting(base::MessageLoopProxy::current());
+ }
+
+ // Returns the testing browsing context that can be used for this test.
+ BrowserContext* browser_context() { return &browser_context_; }
+
+ // Returns whether the last invoked callback finished successfully.
+ bool success() const { return success_; }
+
+ // Returns the NotificationDatabaseData associated with the last invoked
+ // ReadNotificationData callback.
+ const NotificationDatabaseData& database_data() const {
+ return database_data_;
+ }
+
+ // Returns the notification id of the notification last written.
+ int64_t notification_id() const { return notification_id_; }
+
+ private:
+ TestBrowserThreadBundle thread_bundle_;
+ TestBrowserContext browser_context_;
+
+ bool success_;
+ NotificationDatabaseData database_data_;
+ int64_t notification_id_;
+};
+
+TEST_F(PlatformNotificationContextTest, ReadNonExistentNotification) {
+ scoped_refptr<PlatformNotificationContextImpl> context =
+ CreatePlatformNotificationContext();
+
+ context->ReadNotificationData(
+ 42 /* notification_id */,
+ GURL("https://example.com"),
+ base::Bind(&PlatformNotificationContextTest::DidReadNotificationData,
+ base::Unretained(this)));
+
+ base::RunLoop().RunUntilIdle();
+
+ // The read operation should have failed, as it does not exist.
+ ASSERT_FALSE(success());
+}
+
+TEST_F(PlatformNotificationContextTest, WriteReadNotification) {
+ scoped_refptr<PlatformNotificationContextImpl> context =
+ CreatePlatformNotificationContext();
+
+ GURL origin("https://example.com");
+ NotificationDatabaseData notification_database_data;
+ notification_database_data.origin = origin;
+
+ context->WriteNotificationData(
+ origin,
+ notification_database_data,
+ base::Bind(&PlatformNotificationContextTest::DidWriteNotificationData,
+ base::Unretained(this)));
+
+ base::RunLoop().RunUntilIdle();
+
+ // The write operation should have succeeded with a notification id.
+ ASSERT_TRUE(success());
+ EXPECT_GT(notification_id(), 0);
+
+ context->ReadNotificationData(
+ notification_id(),
+ origin,
+ base::Bind(&PlatformNotificationContextTest::DidReadNotificationData,
+ base::Unretained(this)));
+
+ base::RunLoop().RunUntilIdle();
+
+ // The read operation should have succeeded, with the right notification.
+ ASSERT_TRUE(success());
+
+ const NotificationDatabaseData& read_database_data = database_data();
+ EXPECT_EQ(notification_database_data.origin, read_database_data.origin);
+}
+
+TEST_F(PlatformNotificationContextTest, DeleteInvalidNotification) {
+ scoped_refptr<PlatformNotificationContextImpl> context =
+ CreatePlatformNotificationContext();
+
+ context->DeleteNotificationData(
+ 42 /* notification_id */,
+ GURL("https://example.com"),
+ base::Bind(&PlatformNotificationContextTest::DidDeleteNotificationData,
+ base::Unretained(this)));
+
+ base::RunLoop().RunUntilIdle();
+
+ // The notification may not have existed, but since the goal of deleting data
+ // is to make sure that it's gone, the goal has been satisfied. As such,
+ // deleting a non-existent notification is considered to be a success.
+ EXPECT_TRUE(success());
+}
+
+TEST_F(PlatformNotificationContextTest, DeleteNotification) {
+ scoped_refptr<PlatformNotificationContextImpl> context =
+ CreatePlatformNotificationContext();
+
+ GURL origin("https://example.com");
+ NotificationDatabaseData notification_database_data;
+
+ context->WriteNotificationData(
+ origin,
+ notification_database_data,
+ base::Bind(&PlatformNotificationContextTest::DidWriteNotificationData,
+ base::Unretained(this)));
+
+ base::RunLoop().RunUntilIdle();
+
+ // The write operation should have succeeded with a notification id.
+ ASSERT_TRUE(success());
+ EXPECT_GT(notification_id(), 0);
+
+ context->DeleteNotificationData(
+ notification_id(),
+ origin,
+ base::Bind(&PlatformNotificationContextTest::DidDeleteNotificationData,
+ base::Unretained(this)));
+
+ base::RunLoop().RunUntilIdle();
+
+ // The notification existed, so it should have been removed successfully.
+ ASSERT_TRUE(success());
+
+ context->ReadNotificationData(
+ notification_id(),
+ origin,
+ base::Bind(&PlatformNotificationContextTest::DidReadNotificationData,
+ base::Unretained(this)));
+
+ base::RunLoop().RunUntilIdle();
+
+ // The notification was removed, so we shouldn't be able to read it from
+ // the database anymore.
+ EXPECT_FALSE(success());
+}
+
+TEST_F(PlatformNotificationContextTest, ServiceWorkerUnregistered) {
+ scoped_ptr<EmbeddedWorkerTestHelper> embedded_worker_test_helper(
+ new EmbeddedWorkerTestHelper(base::FilePath(), kFakeRenderProcessId));
+
+ // Manually create the PlatformNotificationContextImpl so that the Service
+ // Worker context wrapper can be passed in.
+ scoped_refptr<PlatformNotificationContextImpl> notification_context(
+ new PlatformNotificationContextImpl(
+ base::FilePath(),
+ browser_context(),
+ embedded_worker_test_helper->context_wrapper()));
+ notification_context->Initialize();
+
+ OverrideTaskRunnerForTesting(notification_context.get());
+
+ GURL origin("https://example.com");
+ GURL script_url("https://example.com/worker.js");
+
+ int64_t service_worker_registration_id = kInvalidServiceWorkerRegistrationId;
+
+ // Register a Service Worker to get a valid registration id.
+ embedded_worker_test_helper->context()->RegisterServiceWorker(
+ origin,
+ script_url,
+ nullptr /* provider_host */,
+ base::Bind(&PlatformNotificationContextTest::DidRegisterServiceWorker,
+ base::Unretained(this), &service_worker_registration_id));
+
+ base::RunLoop().RunUntilIdle();
+ ASSERT_NE(service_worker_registration_id,
+ kInvalidServiceWorkerRegistrationId);
+
+ NotificationDatabaseData notification_database_data;
+
+ // Create a notification for that Service Worker registration.
+ notification_context->WriteNotificationData(
+ origin,
+ notification_database_data,
+ base::Bind(&PlatformNotificationContextTest::DidWriteNotificationData,
+ base::Unretained(this)));
+
+ base::RunLoop().RunUntilIdle();
+
+ ASSERT_TRUE(success());
+ EXPECT_GT(notification_id(), 0);
+
+ ServiceWorkerStatusCode unregister_status;
+
+ // Now drop the Service Worker registration which owns that notification.
+ embedded_worker_test_helper->context()->UnregisterServiceWorker(
+ origin,
+ base::Bind(&PlatformNotificationContextTest::DidUnregisterServiceWorker,
+ base::Unretained(this), &unregister_status));
+
+ base::RunLoop().RunUntilIdle();
+ ASSERT_EQ(SERVICE_WORKER_OK, unregister_status);
+
+ // And verify that the associated notification has indeed been dropped.
+ notification_context->ReadNotificationData(
+ notification_id(),
+ origin,
+ base::Bind(&PlatformNotificationContextTest::DidReadNotificationData,
+ base::Unretained(this)));
+
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_FALSE(success());
+}
+
+TEST_F(PlatformNotificationContextTest, DestroyDatabaseOnStorageWiped) {
+ scoped_refptr<PlatformNotificationContextImpl> context =
+ CreatePlatformNotificationContext();
+
+ GURL origin("https://example.com");
+ NotificationDatabaseData notification_database_data;
+
+ context->WriteNotificationData(
+ origin,
+ notification_database_data,
+ base::Bind(&PlatformNotificationContextTest::DidWriteNotificationData,
+ base::Unretained(this)));
+
+ base::RunLoop().RunUntilIdle();
+
+ // The write operation should have succeeded with a notification id.
+ ASSERT_TRUE(success());
+ EXPECT_GT(notification_id(), 0);
+
+ // Call the OnStorageWiped override from the ServiceWorkerContextObserver,
+ // which indicates that the database should go away entirely.
+ context->OnStorageWiped();
+
+ // Verify that reading notification data fails because the data does not
+ // exist anymore. Deliberately omit RunUntilIdle(), since this is unlikely to
+ // be the case when OnStorageWiped gets called in production.
+ context->ReadNotificationData(
+ notification_id(),
+ origin,
+ base::Bind(&PlatformNotificationContextTest::DidReadNotificationData,
+ base::Unretained(this)));
+
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_FALSE(success());
+}
+
+TEST_F(PlatformNotificationContextTest, DestroyOnDiskDatabase) {
+ base::ScopedTempDir database_dir;
+ ASSERT_TRUE(database_dir.CreateUniqueTempDir());
+
+ // Manually construct the PlatformNotificationContextImpl because this test
+ // requires the database to be created on the filesystem.
+ scoped_refptr<PlatformNotificationContextImpl> context(
+ new PlatformNotificationContextImpl(database_dir.path(),
+ browser_context(),
+ nullptr));
+
+ OverrideTaskRunnerForTesting(context.get());
+
+ // Trigger a read-operation to force creating the database.
+ context->ReadNotificationData(
+ 42 /* notification_id */,
+ GURL("https://example.com"),
+ base::Bind(&PlatformNotificationContextTest::DidReadNotificationData,
+ base::Unretained(this)));
+
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_FALSE(IsDirectoryEmpty(database_dir.path()));
+ EXPECT_FALSE(success());
+
+ // Blow away the database by faking a Service Worker Context wipe-out.
+ context->OnStorageWiped();
+
+ base::RunLoop().RunUntilIdle();
+
+ // The database's directory should be empty at this point.
+ EXPECT_TRUE(IsDirectoryEmpty(database_dir.path()));
+}
+
+TEST_F(PlatformNotificationContextTest, ReadAllServiceWorkerDataEmpty) {
+ scoped_refptr<PlatformNotificationContextImpl> context =
+ CreatePlatformNotificationContext();
+
+ GURL origin("https://example.com");
+
+ std::vector<NotificationDatabaseData> notification_database_datas;
+ context->ReadAllNotificationDataForServiceWorkerRegistration(
+ origin,
+ kFakeServiceWorkerRegistrationId,
+ base::Bind(&PlatformNotificationContextTest::DidReadAllNotificationDatas,
+ base::Unretained(this),
+ &notification_database_datas));
+
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_TRUE(success());
+ EXPECT_EQ(0u, notification_database_datas.size());
+}
+
+TEST_F(PlatformNotificationContextTest, ReadAllServiceWorkerDataFilled) {
+ scoped_refptr<PlatformNotificationContextImpl> context =
+ CreatePlatformNotificationContext();
+
+ GURL origin("https://example.com");
+
+ NotificationDatabaseData notification_database_data;
+ notification_database_data.origin = origin;
+ notification_database_data.service_worker_registration_id =
+ kFakeServiceWorkerRegistrationId;
+
+ // Insert ten notifications into the database belonging to origin and the
+ // test Service Worker Registration id.
+ for (int i = 0; i < 10; ++i) {
+ context->WriteNotificationData(
+ origin,
+ notification_database_data,
+ base::Bind(&PlatformNotificationContextTest::DidWriteNotificationData,
+ base::Unretained(this)));
+
+ base::RunLoop().RunUntilIdle();
+
+ ASSERT_TRUE(success());
+ }
+
+ // Now read the notifications from the database again. There should be ten,
+ // all set with the correct origin and Service Worker Registration id.
+ std::vector<NotificationDatabaseData> notification_database_datas;
+ context->ReadAllNotificationDataForServiceWorkerRegistration(
+ origin,
+ kFakeServiceWorkerRegistrationId,
+ base::Bind(&PlatformNotificationContextTest::DidReadAllNotificationDatas,
+ base::Unretained(this),
+ &notification_database_datas));
+
+ base::RunLoop().RunUntilIdle();
+
+ ASSERT_TRUE(success());
+ ASSERT_EQ(10u, notification_database_datas.size());
+
+ for (int i = 0; i < 10; ++i) {
+ EXPECT_EQ(origin, notification_database_datas[i].origin);
+ EXPECT_EQ(kFakeServiceWorkerRegistrationId,
+ notification_database_datas[i].service_worker_registration_id);
+ }
+}
+
+} // namespace content
diff --git a/chromium/content/browser/pepper_flash_settings_helper_impl.cc b/chromium/content/browser/pepper_flash_settings_helper_impl.cc
index f51248cd564..2524dbbdda0 100644
--- a/chromium/content/browser/pepper_flash_settings_helper_impl.cc
+++ b/chromium/content/browser/pepper_flash_settings_helper_impl.cc
@@ -25,7 +25,7 @@ PepperFlashSettingsHelperImpl::~PepperFlashSettingsHelperImpl() {
void PepperFlashSettingsHelperImpl::OpenChannelToBroker(
const base::FilePath& path,
const OpenChannelCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (callback.is_null())
return;
@@ -52,7 +52,7 @@ void PepperFlashSettingsHelperImpl::OnPpapiChannelOpened(
const IPC::ChannelHandle& channel_handle,
base::ProcessId /* plugin_pid */,
int /* plugin_child_id */) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(!callback_.is_null());
if (!channel_handle.name.empty())
diff --git a/chromium/content/browser/permissions/OWNERS b/chromium/content/browser/permissions/OWNERS
new file mode 100644
index 00000000000..fee7a6d84c1
--- /dev/null
+++ b/chromium/content/browser/permissions/OWNERS
@@ -0,0 +1,2 @@
+mlamouri@chromium.org
+timvolodine@chromium.org \ No newline at end of file
diff --git a/chromium/content/browser/permissions/permission_service_context.cc b/chromium/content/browser/permissions/permission_service_context.cc
new file mode 100644
index 00000000000..6922fb608e0
--- /dev/null
+++ b/chromium/content/browser/permissions/permission_service_context.cc
@@ -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.
+
+#include "content/browser/permissions/permission_service_context.h"
+
+#include "content/browser/permissions/permission_service_impl.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"
+
+namespace content {
+
+PermissionServiceContext::PermissionServiceContext(
+ RenderFrameHost* render_frame_host)
+ : WebContentsObserver(WebContents::FromRenderFrameHost(render_frame_host)),
+ render_frame_host_(render_frame_host),
+ render_process_host_(nullptr) {
+}
+
+PermissionServiceContext::PermissionServiceContext(
+ RenderProcessHost* render_process_host)
+ : WebContentsObserver(nullptr),
+ render_frame_host_(nullptr),
+ render_process_host_(render_process_host) {
+}
+
+PermissionServiceContext::~PermissionServiceContext() {
+}
+
+void PermissionServiceContext::CreateService(
+ mojo::InterfaceRequest<PermissionService> request) {
+ PermissionServiceImpl* service =
+ new PermissionServiceImpl(this);
+
+ services_.push_back(service);
+ mojo::WeakBindToRequest(service, &request);
+}
+
+void PermissionServiceContext::ServiceHadConnectionError(
+ PermissionServiceImpl* service) {
+ auto it = std::find(services_.begin(), services_.end(), service);
+ DCHECK(it != services_.end());
+ services_.erase(it);
+}
+
+void PermissionServiceContext::RenderFrameDeleted(
+ RenderFrameHost* render_frame_host) {
+ CancelPendingOperations(render_frame_host);
+}
+
+void PermissionServiceContext::DidNavigateAnyFrame(
+ RenderFrameHost* render_frame_host,
+ const LoadCommittedDetails& details,
+ const FrameNavigateParams& params) {
+ if (details.is_in_page)
+ return;
+
+ CancelPendingOperations(render_frame_host);
+}
+
+void PermissionServiceContext::CancelPendingOperations(
+ RenderFrameHost* render_frame_host) const {
+ if (render_frame_host != render_frame_host_)
+ return;
+
+ for (auto* service : services_)
+ service->CancelPendingOperations();
+}
+
+BrowserContext* PermissionServiceContext::GetBrowserContext() const {
+ if (!web_contents()) {
+ DCHECK(render_process_host_);
+ return render_process_host_->GetBrowserContext();
+ }
+ return web_contents()->GetBrowserContext();
+}
+
+GURL PermissionServiceContext::GetEmbeddingOrigin() const {
+ return web_contents() ? web_contents()->GetLastCommittedURL().GetOrigin()
+ : GURL();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/permissions/permission_service_context.h b/chromium/content/browser/permissions/permission_service_context.h
new file mode 100644
index 00000000000..355a572aa25
--- /dev/null
+++ b/chromium/content/browser/permissions/permission_service_context.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_PERMISSIONS_PERMISSION_SERVICE_CONTEXT_H_
+#define CONTENT_BROWSER_PERMISSIONS_PERMISSION_SERVICE_CONTEXT_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_vector.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h"
+
+namespace content {
+
+class PermissionService;
+class PermissionServiceImpl;
+class RenderFrameHost;
+class RenderProcessHost;
+
+// Provides information to a PermissionService. It is used by the
+// PermissionService to handle request permission UI.
+// There is one PermissionServiceContext per RenderFrameHost/RenderProcessHost
+// which owns it. It then owns all PermissionService associated to their owner.
+class PermissionServiceContext : public WebContentsObserver {
+ public:
+ explicit PermissionServiceContext(RenderFrameHost* render_frame_host);
+ explicit PermissionServiceContext(RenderProcessHost* render_process_host);
+ ~PermissionServiceContext() override;
+
+ void CreateService(mojo::InterfaceRequest<PermissionService> request);
+
+ // Called by a PermissionService identified as |service| when it has a
+ // connection error in order to get unregistered and killed.
+ void ServiceHadConnectionError(PermissionServiceImpl* service);
+
+ BrowserContext* GetBrowserContext() const;
+ GURL GetEmbeddingOrigin() const;
+
+ private:
+ // WebContentsObserver
+ void RenderFrameDeleted(RenderFrameHost* render_frame_host) override;
+ void DidNavigateAnyFrame(RenderFrameHost* render_frame_host,
+ const LoadCommittedDetails& details,
+ const FrameNavigateParams& params) override;
+
+ void CancelPendingOperations(RenderFrameHost*) const;
+
+ RenderFrameHost* render_frame_host_;
+ RenderProcessHost* render_process_host_;
+ ScopedVector<PermissionServiceImpl> services_;
+
+ DISALLOW_COPY_AND_ASSIGN(PermissionServiceContext);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_PERMISSIONS_PERMISSION_SERVICE_CONTEXT_H_
diff --git a/chromium/content/browser/permissions/permission_service_impl.cc b/chromium/content/browser/permissions/permission_service_impl.cc
new file mode 100644
index 00000000000..8e6bcd54898
--- /dev/null
+++ b/chromium/content/browser/permissions/permission_service_impl.cc
@@ -0,0 +1,284 @@
+// Copyright 2014 The Chromium Authors. 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/permissions/permission_service_impl.h"
+
+#include "base/bind.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/permission_manager.h"
+#include "content/public/browser/permission_type.h"
+
+namespace content {
+
+namespace {
+
+PermissionType PermissionNameToPermissionType(PermissionName name) {
+ switch(name) {
+ case PERMISSION_NAME_GEOLOCATION:
+ return PermissionType::GEOLOCATION;
+ case PERMISSION_NAME_NOTIFICATIONS:
+ return PermissionType::NOTIFICATIONS;
+ case PERMISSION_NAME_PUSH_NOTIFICATIONS:
+ return PermissionType::PUSH_MESSAGING;
+ case PERMISSION_NAME_MIDI_SYSEX:
+ return PermissionType::MIDI_SYSEX;
+ case PERMISSION_NAME_PROTECTED_MEDIA_IDENTIFIER:
+ return PermissionType::PROTECTED_MEDIA_IDENTIFIER;
+ }
+
+ NOTREACHED();
+ return PermissionType::NUM;
+}
+
+} // anonymous namespace
+
+PermissionServiceImpl::PendingRequest::PendingRequest(
+ PermissionType permission,
+ const GURL& origin,
+ const PermissionStatusCallback& callback)
+ : permission(permission),
+ origin(origin),
+ callback(callback) {
+}
+
+PermissionServiceImpl::PendingRequest::~PendingRequest() {
+ if (!callback.is_null())
+ callback.Run(PERMISSION_STATUS_ASK);
+}
+
+PermissionServiceImpl::PendingSubscription::PendingSubscription(
+ PermissionType permission,
+ const GURL& origin,
+ const PermissionStatusCallback& callback)
+ : id(-1),
+ permission(permission),
+ origin(origin),
+ callback(callback) {
+}
+
+PermissionServiceImpl::PendingSubscription::~PendingSubscription() {
+ if (!callback.is_null())
+ callback.Run(PERMISSION_STATUS_ASK);
+}
+
+PermissionServiceImpl::PermissionServiceImpl(PermissionServiceContext* context)
+ : context_(context),
+ weak_factory_(this) {
+}
+
+PermissionServiceImpl::~PermissionServiceImpl() {
+ DCHECK(pending_requests_.IsEmpty());
+}
+
+void PermissionServiceImpl::OnConnectionError() {
+ context_->ServiceHadConnectionError(this);
+ // After that call, |this| will be deleted.
+}
+
+void PermissionServiceImpl::RequestPermission(
+ PermissionName permission,
+ const mojo::String& origin,
+ bool user_gesture,
+ const PermissionStatusCallback& callback) {
+ // This condition is valid if the call is coming from a ChildThread instead of
+ // a RenderFrame. Some consumers of the service run in Workers and some in
+ // Frames. In the context of a Worker, it is not possible to show a
+ // permission prompt because there is no tab. In the context of a Frame, we
+ // can. Even if the call comes from a context where it is not possible to show
+ // any UI, we want to still return something relevant so the current
+ // permission status is returned.
+ if (!context_->web_contents()) {
+ // There is no way to show a UI so the call will simply return the current
+ // permission.
+ HasPermission(permission, origin, callback);
+ return;
+ }
+
+ BrowserContext* browser_context = context_->GetBrowserContext();
+ DCHECK(browser_context);
+ if (!browser_context->GetPermissionManager()) {
+ callback.Run(content::PERMISSION_STATUS_DENIED);
+ return;
+ }
+
+ PermissionType permission_type = PermissionNameToPermissionType(permission);
+ int request_id = pending_requests_.Add(
+ new PendingRequest(permission_type, GURL(origin), callback));
+
+ browser_context->GetPermissionManager()->RequestPermission(
+ permission_type,
+ context_->web_contents(),
+ request_id,
+ GURL(origin),
+ user_gesture, // TODO(mlamouri): should be removed (crbug.com/423770)
+ base::Bind(&PermissionServiceImpl::OnRequestPermissionResponse,
+ weak_factory_.GetWeakPtr(),
+ request_id));
+}
+
+void PermissionServiceImpl::OnRequestPermissionResponse(
+ int request_id,
+ PermissionStatus status) {
+ PendingRequest* request = pending_requests_.Lookup(request_id);
+ PermissionStatusCallback callback(request->callback);
+ request->callback.reset();
+ pending_requests_.Remove(request_id);
+ callback.Run(status);
+}
+
+void PermissionServiceImpl::CancelPendingOperations() {
+ DCHECK(context_->web_contents());
+ DCHECK(context_->GetBrowserContext());
+
+ PermissionManager* permission_manager =
+ context_->GetBrowserContext()->GetPermissionManager();
+ if (!permission_manager)
+ return;
+
+ // Cancel pending requests.
+ for (RequestsMap::Iterator<PendingRequest> it(&pending_requests_);
+ !it.IsAtEnd(); it.Advance()) {
+ permission_manager->CancelPermissionRequest(
+ it.GetCurrentValue()->permission,
+ context_->web_contents(),
+ it.GetCurrentKey(),
+ it.GetCurrentValue()->origin);
+ }
+ pending_requests_.Clear();
+
+ // Cancel pending subscriptions.
+ for (SubscriptionsMap::Iterator<PendingSubscription>
+ it(&pending_subscriptions_); !it.IsAtEnd(); it.Advance()) {
+ it.GetCurrentValue()->callback.Run(GetPermissionStatusFromType(
+ it.GetCurrentValue()->permission, it.GetCurrentValue()->origin));
+ it.GetCurrentValue()->callback.reset();
+ permission_manager->UnsubscribePermissionStatusChange(
+ it.GetCurrentValue()->id);
+ }
+ pending_subscriptions_.Clear();
+}
+
+void PermissionServiceImpl::HasPermission(
+ PermissionName permission,
+ const mojo::String& origin,
+ const PermissionStatusCallback& callback) {
+ callback.Run(GetPermissionStatusFromName(permission, GURL(origin)));
+}
+
+void PermissionServiceImpl::RevokePermission(
+ PermissionName permission,
+ const mojo::String& origin,
+ const PermissionStatusCallback& callback) {
+ GURL origin_url(origin);
+ PermissionType permission_type = PermissionNameToPermissionType(permission);
+ PermissionStatus status = GetPermissionStatusFromType(permission_type,
+ origin_url);
+
+ // Resetting the permission should only be possible if the permission is
+ // already granted.
+ if (status != PERMISSION_STATUS_GRANTED) {
+ callback.Run(status);
+ return;
+ }
+
+ ResetPermissionStatus(permission_type, origin_url);
+
+ callback.Run(GetPermissionStatusFromType(permission_type, origin_url));
+}
+
+void PermissionServiceImpl::GetNextPermissionChange(
+ PermissionName permission,
+ const mojo::String& mojo_origin,
+ PermissionStatus last_known_status,
+ const PermissionStatusCallback& callback) {
+ GURL origin(mojo_origin);
+ PermissionStatus current_status =
+ GetPermissionStatusFromName(permission, origin);
+ if (current_status != last_known_status) {
+ callback.Run(current_status);
+ return;
+ }
+
+ BrowserContext* browser_context = context_->GetBrowserContext();
+ DCHECK(browser_context);
+ if (!browser_context->GetPermissionManager()) {
+ callback.Run(current_status);
+ return;
+ }
+
+ PermissionType permission_type = PermissionNameToPermissionType(permission);
+
+ // We need to pass the id of PendingSubscription in pending_subscriptions_
+ // to the callback but SubscribePermissionStatusChange() will also return an
+ // id which is different.
+ PendingSubscription* subscription =
+ new PendingSubscription(permission_type, origin, callback);
+ int pending_subscription_id = pending_subscriptions_.Add(subscription);
+
+ GURL embedding_origin = context_->GetEmbeddingOrigin();
+ subscription->id =
+ browser_context->GetPermissionManager()->SubscribePermissionStatusChange(
+ permission_type,
+ origin,
+ // If the embedding_origin is empty, we,ll use the |origin| instead.
+ embedding_origin.is_empty() ? origin : embedding_origin,
+ base::Bind(&PermissionServiceImpl::OnPermissionStatusChanged,
+ weak_factory_.GetWeakPtr(),
+ pending_subscription_id));
+}
+
+PermissionStatus PermissionServiceImpl::GetPermissionStatusFromName(
+ PermissionName permission, const GURL& origin) {
+ return GetPermissionStatusFromType(PermissionNameToPermissionType(permission),
+ origin);
+}
+
+PermissionStatus PermissionServiceImpl::GetPermissionStatusFromType(
+ PermissionType type, const GURL& origin) {
+ BrowserContext* browser_context = context_->GetBrowserContext();
+ DCHECK(browser_context);
+ if (!browser_context->GetPermissionManager())
+ return PERMISSION_STATUS_DENIED;
+
+ // If the embedding_origin is empty we'll use |origin| instead.
+ GURL embedding_origin = context_->GetEmbeddingOrigin();
+ return browser_context->GetPermissionManager()->GetPermissionStatus(
+ type, origin, embedding_origin.is_empty() ? origin : embedding_origin);
+}
+
+void PermissionServiceImpl::ResetPermissionStatus(PermissionType type,
+ const GURL& origin) {
+ BrowserContext* browser_context = context_->GetBrowserContext();
+ DCHECK(browser_context);
+ if (!browser_context->GetPermissionManager())
+ return;
+
+ // If the embedding_origin is empty we'll use |origin| instead.
+ GURL embedding_origin = context_->GetEmbeddingOrigin();
+ browser_context->GetPermissionManager()->ResetPermission(
+ type, origin, embedding_origin.is_empty() ? origin : embedding_origin);
+}
+
+void PermissionServiceImpl::OnPermissionStatusChanged(
+ int pending_subscription_id,
+ PermissionStatus status) {
+ PendingSubscription* subscription =
+ pending_subscriptions_.Lookup(pending_subscription_id);
+
+ BrowserContext* browser_context = context_->GetBrowserContext();
+ DCHECK(browser_context);
+ if (browser_context->GetPermissionManager()) {
+ browser_context->GetPermissionManager()->UnsubscribePermissionStatusChange(
+ subscription->id);
+ }
+
+ PermissionStatusCallback callback = subscription->callback;
+
+ subscription->callback.reset();
+ pending_subscriptions_.Remove(pending_subscription_id);
+
+ callback.Run(status);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/permissions/permission_service_impl.h b/chromium/content/browser/permissions/permission_service_impl.h
new file mode 100644
index 00000000000..3908f859cda
--- /dev/null
+++ b/chromium/content/browser/permissions/permission_service_impl.h
@@ -0,0 +1,108 @@
+// Copyright 2014 The Chromium Authors. 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_PERMISSIONS_PERMISSION_SERVICE_IMPL_H_
+#define CONTENT_BROWSER_PERMISSIONS_PERMISSION_SERVICE_IMPL_H_
+
+#include "base/id_map.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "content/browser/permissions/permission_service_context.h"
+#include "content/common/permission_service.mojom.h"
+
+namespace content {
+
+enum class PermissionType;
+
+// Implements the PermissionService Mojo interface.
+// This service can be created from a RenderFrameHost or a RenderProcessHost.
+// It is owned by a PermissionServiceContext.
+// It receives at PermissionServiceContext instance when created which allows it
+// to have some information about the current context. That enables the service
+// to know whether it can show UI and have knowledge of the associated
+// WebContents for example.
+class PermissionServiceImpl : public mojo::InterfaceImpl<PermissionService> {
+ public:
+ ~PermissionServiceImpl() override;
+
+ // Clear pending operations currently run by the service. This will be called
+ // by PermissionServiceContext when it will need the service to clear its
+ // state for example, if the frame changes.
+ void CancelPendingOperations();
+
+ protected:
+ friend PermissionServiceContext;
+
+ PermissionServiceImpl(PermissionServiceContext* context);
+
+ private:
+ using PermissionStatusCallback = mojo::Callback<void(PermissionStatus)>;
+
+ struct PendingRequest {
+ PendingRequest(PermissionType permission, const GURL& origin,
+ const PermissionStatusCallback& callback);
+ ~PendingRequest();
+
+ PermissionType permission;
+ GURL origin;
+ PermissionStatusCallback callback;
+ };
+ using RequestsMap = IDMap<PendingRequest, IDMapOwnPointer>;
+
+ struct PendingSubscription {
+ PendingSubscription(PermissionType permission, const GURL& origin,
+ const PermissionStatusCallback& callback);
+ ~PendingSubscription();
+
+ // Subscription ID received from the PermissionManager.
+ int id;
+ PermissionType permission;
+ GURL origin;
+ PermissionStatusCallback callback;
+ };
+ using SubscriptionsMap = IDMap<PendingSubscription, IDMapOwnPointer>;
+
+ // PermissionService.
+ void HasPermission(PermissionName permission,
+ const mojo::String& origin,
+ const PermissionStatusCallback& callback) override;
+ void RequestPermission(PermissionName permission,
+ const mojo::String& origin,
+ bool user_gesture,
+ const PermissionStatusCallback& callback) override;
+ void RevokePermission(PermissionName permission,
+ const mojo::String& origin,
+ const PermissionStatusCallback& callback) override;
+ void GetNextPermissionChange(
+ PermissionName permission,
+ const mojo::String& origin,
+ PermissionStatus last_known_status,
+ const PermissionStatusCallback& callback) override;
+
+ // mojo::InterfaceImpl.
+ void OnConnectionError() override;
+
+ void OnRequestPermissionResponse(int request_id, PermissionStatus status);
+
+ PermissionStatus GetPermissionStatusFromName(PermissionName permission,
+ const GURL& origin);
+ PermissionStatus GetPermissionStatusFromType(PermissionType type,
+ const GURL& origin);
+ void ResetPermissionStatus(PermissionType type, const GURL& origin);
+
+ void OnPermissionStatusChanged(int pending_subscription_id,
+ PermissionStatus status);
+
+ RequestsMap pending_requests_;
+ SubscriptionsMap pending_subscriptions_;
+ // context_ owns |this|.
+ PermissionServiceContext* context_;
+ base::WeakPtrFactory<PermissionServiceImpl> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(PermissionServiceImpl);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_PERMISSIONS_PERMISSION_SERVICE_IMPL_H_
diff --git a/chromium/content/browser/plugin_browsertest.cc b/chromium/content/browser/plugin_browsertest.cc
index a5ca6da74ea..c37f7b702e6 100644
--- a/chromium/content/browser/plugin_browsertest.cc
+++ b/chromium/content/browser/plugin_browsertest.cc
@@ -20,7 +20,7 @@
#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"
+#include "ui/gfx/geometry/rect.h"
#if defined(OS_WIN)
#include "base/win/registry.h"
@@ -33,13 +33,21 @@
#define MAYBE(x) x
#endif
+// In-process windowless plugin tests that create canvas break on Windows since
+// Win32k Renderer Lockdown was enabled in M42.
+#if defined(OS_WIN)
+#define MAYBE_INPROC_WINDOWLESS(x) DISABLED_##x
+#else
+#define MAYBE_INPROC_WINDOWLESS(x) x
+#endif
+
using base::ASCIIToUTF16;
namespace content {
namespace {
void SetUrlRequestMock(const base::FilePath& path) {
- net::URLRequestMockHTTPJob::AddUrlHandler(
+ net::URLRequestMockHTTPJob::AddUrlHandlers(
path, content::BrowserThread::GetBlockingPool());
}
@@ -49,7 +57,7 @@ class PluginTest : public ContentBrowserTest {
protected:
PluginTest() {}
- void SetUpCommandLine(CommandLine* command_line) override {
+ void SetUpCommandLine(base::CommandLine* command_line) override {
// Some NPAPI tests schedule garbage collection to force object tear-down.
command_line->AppendSwitchASCII(switches::kJavaScriptFlags, "--expose_gc");
@@ -74,6 +82,7 @@ class PluginTest : public ContentBrowserTest {
// explicitly registered.
command_line->AppendSwitchPath(switches::kExtraPluginDir, plugin_dir);
#endif
+ command_line->AppendSwitch(switches::kEnableNpapi);
}
void SetUpOnMainThread() override {
@@ -166,8 +175,9 @@ IN_PROC_BROWSER_TEST_F(PluginTest, MAYBE(NPObjectSetException)) {
// a synchronous mouseup works correctly.
// This was never ported to Mac. The only thing remaining is to make
// SimulateMouseClick get to Mac plugins, currently it doesn't work.
-IN_PROC_BROWSER_TEST_F(PluginTest,
- MAYBE(SelfDeletePluginInvokeInSynchronousMouseUp)) {
+IN_PROC_BROWSER_TEST_F(
+ PluginTest,
+ MAYBE_INPROC_WINDOWLESS(SelfDeletePluginInvokeInSynchronousMouseUp)) {
NavigateToURL(shell(), GetURL("execute_script_delete_in_mouse_up.html"));
base::string16 expected_title(ASCIIToUTF16("OK"));
@@ -264,8 +274,9 @@ IN_PROC_BROWSER_TEST_F(PluginTest, MAYBE(NPObjectProxy)) {
// Tests if a plugin executing a self deleting script in the context of
// a synchronous paint event works correctly
// http://crbug.com/44960
-IN_PROC_BROWSER_TEST_F(PluginTest,
- MAYBE(SelfDeletePluginInvokeInSynchronousPaint)) {
+IN_PROC_BROWSER_TEST_F(
+ PluginTest,
+ MAYBE_INPROC_WINDOWLESS(SelfDeletePluginInvokeInSynchronousPaint)) {
LoadAndWait(GetURL("execute_script_delete_in_paint.html"));
}
#endif
@@ -273,7 +284,7 @@ IN_PROC_BROWSER_TEST_F(PluginTest,
// Tests that if a plugin executes a self resizing script in the context of a
// synchronous paint, the plugin doesn't use deallocated memory.
// http://crbug.com/139462
-IN_PROC_BROWSER_TEST_F(PluginTest, MAYBE(ResizeDuringPaint)) {
+IN_PROC_BROWSER_TEST_F(PluginTest, MAYBE_INPROC_WINDOWLESS(ResizeDuringPaint)) {
LoadAndWait(GetURL("resize_during_paint.html"));
}
@@ -320,12 +331,14 @@ IN_PROC_BROWSER_TEST_F(PluginTest, MAYBE(NewFails)) {
LoadAndWait(GetURL("new_fails.html"));
}
-IN_PROC_BROWSER_TEST_F(PluginTest, MAYBE(SelfDeletePluginInNPNEvaluate)) {
+IN_PROC_BROWSER_TEST_F(PluginTest,
+ MAYBE_INPROC_WINDOWLESS(SelfDeletePluginInNPNEvaluate)) {
LoadAndWait(GetURL("execute_script_delete_in_npn_evaluate.html"));
}
-IN_PROC_BROWSER_TEST_F(PluginTest,
- MAYBE(SelfDeleteCreatePluginInNPNEvaluate)) {
+IN_PROC_BROWSER_TEST_F(
+ PluginTest,
+ MAYBE_INPROC_WINDOWLESS(SelfDeleteCreatePluginInNPNEvaluate)) {
LoadAndWait(GetURL("npn_plugin_delete_create_in_evaluate.html"));
}
diff --git a/chromium/content/browser/plugin_data_remover_impl.cc b/chromium/content/browser/plugin_data_remover_impl.cc
index f74b37831b5..43930ba1de7 100644
--- a/chromium/content/browser/plugin_data_remover_impl.cc
+++ b/chromium/content/browser/plugin_data_remover_impl.cc
@@ -69,7 +69,7 @@ class PluginDataRemoverImpl::Context
is_removing_(false),
browser_context_path_(browser_context->GetPath()),
resource_context_(browser_context->GetResourceContext()) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
}
void Init(const std::string& mime_type) {
@@ -95,7 +95,7 @@ class PluginDataRemoverImpl::Context
if (!plugins.empty()) // May be empty for some tests.
plugin_path = plugins[0].path;
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
remove_start_time_ = base::Time::Now();
is_removing_ = true;
// Balanced in On[Ppapi]ChannelOpened or OnError. Exactly one them will
@@ -212,9 +212,9 @@ class PluginDataRemoverImpl::Context
kClearAllData, max_age);
}
- // Connects the client side of a newly opened plug-in channel.
+ // Connects the client side of a newly opened plugin channel.
void ConnectToChannel(const IPC::ChannelHandle& handle, bool is_ppapi) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
// If we timed out, don't bother connecting.
if (!is_removing_)
@@ -264,7 +264,7 @@ class PluginDataRemoverImpl::Context
// Signals that we are finished with removing data (successful or not). This
// method is safe to call multiple times.
void SignalDone() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!is_removing_)
return;
is_removing_ = false;
@@ -288,7 +288,7 @@ class PluginDataRemoverImpl::Context
// The name of the plugin. Use only on the I/O thread.
std::string plugin_name_;
- // The channel is NULL until we have opened a connection to the plug-in
+ // The channel is NULL until we have opened a connection to the plugin
// process.
scoped_ptr<IPC::Channel> channel_;
};
diff --git a/chromium/content/browser/plugin_data_remover_impl.h b/chromium/content/browser/plugin_data_remover_impl.h
index 704ebaaa637..ed2b7ea3163 100644
--- a/chromium/content/browser/plugin_data_remover_impl.h
+++ b/chromium/content/browser/plugin_data_remover_impl.h
@@ -22,9 +22,9 @@ class CONTENT_EXPORT PluginDataRemoverImpl : public PluginDataRemover {
// PluginDataRemover implementation:
base::WaitableEvent* StartRemoving(base::Time begin_time) override;
- // The plug-in whose data should be removed (usually Flash) is specified via
+ // The plugin 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
- // different plug-in (for example in tests).
+ // different plugin (for example in tests).
void set_mime_type(const std::string& mime_type) { mime_type_ = mime_type; }
private:
diff --git a/chromium/content/browser/plugin_data_remover_impl_browsertest.cc b/chromium/content/browser/plugin_data_remover_impl_browsertest.cc
index 97adba91bd0..da502672b8d 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();
}
- void SetUpCommandLine(CommandLine* command_line) override {
+ void SetUpCommandLine(base::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 22bc2b614c2..b8750ed90ea 100644
--- a/chromium/content/browser/plugin_loader_posix.cc
+++ b/chromium/content/browser/plugin_loader_posix.cc
@@ -19,12 +19,12 @@
namespace content {
PluginLoaderPosix::PluginLoaderPosix()
- : next_load_index_(0) {
+ : next_load_index_(0), loading_plugins_(false) {
}
void PluginLoaderPosix::GetPlugins(
const PluginService::GetPluginsCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
std::vector<WebPluginInfo> cached_plugins;
if (PluginList::Singleton()->GetPluginsNoRefresh(&cached_plugins)) {
@@ -34,9 +34,12 @@ void PluginLoaderPosix::GetPlugins(
return;
}
- if (callbacks_.empty()) {
+ if (!loading_plugins_) {
+ loading_plugins_ = true;
callbacks_.push_back(callback);
+ // When |loading_plugins_| is set to false, this instance must call
+ // SetPlugins().
PluginList::Singleton()->PrepareForPluginLoading();
BrowserThread::PostTask(BrowserThread::FILE,
@@ -81,6 +84,10 @@ void PluginLoaderPosix::OnProcessCrashed(int exit_code) {
LoadPluginsInternal();
}
+void PluginLoaderPosix::OnProcessLaunchFailed() {
+ FinishedLoadingPlugins();
+}
+
bool PluginLoaderPosix::Send(IPC::Message* message) {
if (process_host_.get())
return process_host_->Send(message);
@@ -91,7 +98,7 @@ PluginLoaderPosix::~PluginLoaderPosix() {
}
void PluginLoaderPosix::GetPluginsToLoad() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
base::TimeTicks start_time(base::TimeTicks::Now());
@@ -116,19 +123,18 @@ void PluginLoaderPosix::GetPluginsToLoad() {
}
void PluginLoaderPosix::LoadPluginsInternal() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
// Check if the list is empty or all plugins have already been loaded before
// forking.
- if (MaybeRunPendingCallbacks())
+ if (IsFinishedLoadingPlugins()) {
+ FinishedLoadingPlugins();
return;
+ }
RecordAction(
base::UserMetricsAction("PluginLoaderPosix.LaunchUtilityProcess"));
- if (load_start_time_.is_null())
- load_start_time_ = base::TimeTicks::Now();
-
UtilityProcessHostImpl* host = new UtilityProcessHostImpl(
this,
BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO).get());
@@ -138,7 +144,13 @@ void PluginLoaderPosix::LoadPluginsInternal() {
host->set_child_flags(ChildProcessHost::CHILD_ALLOW_HEAP_EXECUTION);
#endif
- process_host_->Send(new UtilityMsg_LoadPlugins(canonical_list_));
+ bool launched = LaunchUtilityProcess();
+ if (!launched) {
+ // The utility process either failed to start or failed to receive the IPC.
+ // This process will never receive any callbacks for OnPluginLoaded() or
+ // OnPluginLoadFailed().
+ FinishedLoadingPlugins();
+ }
}
void PluginLoaderPosix::GetPluginsWrapper(
@@ -159,12 +171,18 @@ void PluginLoaderPosix::OnPluginLoaded(uint32 index,
return;
}
- if (!MaybeAddInternalPlugin(plugin.path))
+ auto it = FindInternalPlugin(plugin.path);
+ if (it != internal_plugins_.end()) {
+ loaded_plugins_.push_back(*it);
+ internal_plugins_.erase(it);
+ } else {
loaded_plugins_.push_back(plugin);
+ }
++next_load_index_;
- MaybeRunPendingCallbacks();
+ if (IsFinishedLoadingPlugins())
+ FinishedLoadingPlugins();
}
void PluginLoaderPosix::OnPluginLoadFailed(uint32 index,
@@ -177,44 +195,45 @@ void PluginLoaderPosix::OnPluginLoadFailed(uint32 index,
++next_load_index_;
- MaybeAddInternalPlugin(plugin_path);
- MaybeRunPendingCallbacks();
+ auto it = FindInternalPlugin(plugin_path);
+ if (it != internal_plugins_.end()) {
+ loaded_plugins_.push_back(*it);
+ internal_plugins_.erase(it);
+ }
+
+ if (IsFinishedLoadingPlugins())
+ FinishedLoadingPlugins();
}
-bool PluginLoaderPosix::MaybeAddInternalPlugin(
+std::vector<WebPluginInfo>::iterator PluginLoaderPosix::FindInternalPlugin(
const base::FilePath& plugin_path) {
- for (std::vector<WebPluginInfo>::iterator it = internal_plugins_.begin();
- it != internal_plugins_.end();
- ++it) {
- if (it->path == plugin_path) {
- loaded_plugins_.push_back(*it);
- internal_plugins_.erase(it);
- return true;
- }
- }
- return false;
+ return std::find_if(internal_plugins_.begin(), internal_plugins_.end(),
+ [&plugin_path](const WebPluginInfo& plugin) {
+ return plugin.path == plugin_path;
+ });
}
-bool PluginLoaderPosix::MaybeRunPendingCallbacks() {
- if (next_load_index_ < canonical_list_.size())
- return false;
+bool PluginLoaderPosix::IsFinishedLoadingPlugins() {
+ if (canonical_list_.empty())
+ return true;
+
+ DCHECK(next_load_index_ <= canonical_list_.size());
+ return next_load_index_ == canonical_list_.size();
+}
+void PluginLoaderPosix::FinishedLoadingPlugins() {
+ loading_plugins_ = false;
PluginList::Singleton()->SetPlugins(loaded_plugins_);
- for (std::vector<PluginService::GetPluginsCallback>::iterator it =
- callbacks_.begin();
- it != callbacks_.end(); ++it) {
- base::MessageLoop::current()->PostTask(FROM_HERE,
- base::Bind(*it, loaded_plugins_));
+ for (auto& callback : callbacks_) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(callback, loaded_plugins_));
}
callbacks_.clear();
+}
- LOCAL_HISTOGRAM_TIMES("PluginLoaderPosix.LoadDone",
- (base::TimeTicks::Now() - load_start_time_) *
- base::Time::kMicrosecondsPerMillisecond);
- load_start_time_ = base::TimeTicks();
-
- return true;
+bool PluginLoaderPosix::LaunchUtilityProcess() {
+ return process_host_->Send(new UtilityMsg_LoadPlugins(canonical_list_));
}
} // namespace content
diff --git a/chromium/content/browser/plugin_loader_posix.h b/chromium/content/browser/plugin_loader_posix.h
index 5b1580c17fa..3a50bcd496c 100644
--- a/chromium/content/browser/plugin_loader_posix.h
+++ b/chromium/content/browser/plugin_loader_posix.h
@@ -56,6 +56,7 @@ class CONTENT_EXPORT PluginLoaderPosix
// UtilityProcessHostClient:
void OnProcessCrashed(int exit_code) override;
+ void OnProcessLaunchFailed() override;
bool OnMessageReceived(const IPC::Message& message) override;
// IPC::Sender:
@@ -80,15 +81,27 @@ class CONTENT_EXPORT PluginLoaderPosix
void OnPluginLoaded(uint32 index, const WebPluginInfo& plugin);
void OnPluginLoadFailed(uint32 index, const base::FilePath& plugin_path);
- // Checks if the plugin path is an internal plugin, and, if it is, adds it to
- // |loaded_plugins_|.
- bool MaybeAddInternalPlugin(const base::FilePath& plugin_path);
+ // Returns an iterator to the plugin in |internal_plugins_| whose path
+ // matches |plugin_path|.
+ std::vector<WebPluginInfo>::iterator FindInternalPlugin(
+ const base::FilePath& plugin_path);
// Runs all the registered callbacks on each's target loop if the condition
// for ending the load process is done (i.e. the |next_load_index_| is outside
// the range of the |canonical_list_|).
bool MaybeRunPendingCallbacks();
+ // Returns true if there are no plugins left to load.
+ bool IsFinishedLoadingPlugins();
+
+ // This method should be called when the plugins are finished loading.
+ // It updates the PluginList's list of plugins, and runs the queued callbacks.
+ void FinishedLoadingPlugins();
+
+ // Launches the utility process that loads the plugins.
+ // Virtual for testing.
+ virtual bool LaunchUtilityProcess();
+
// The process host for which this is a client.
base::WeakPtr<UtilityProcessHost> process_host_;
@@ -110,8 +123,8 @@ class CONTENT_EXPORT PluginLoaderPosix
// plugin loading process has been completed.
std::vector<PluginService::GetPluginsCallback> callbacks_;
- // The time at which plugin loading started.
- base::TimeTicks load_start_time_;
+ // True if there is (or is about to be) a utility process that loads plugins.
+ bool loading_plugins_;
friend class MockPluginLoaderPosix;
DISALLOW_COPY_AND_ASSIGN(PluginLoaderPosix);
diff --git a/chromium/content/browser/plugin_loader_posix_unittest.cc b/chromium/content/browser/plugin_loader_posix_unittest.cc
index 59e30b1ddd3..9b7e29b8248 100644
--- a/chromium/content/browser/plugin_loader_posix_unittest.cc
+++ b/chromium/content/browser/plugin_loader_posix_unittest.cc
@@ -47,6 +47,13 @@ class MockPluginLoaderPosix : public PluginLoaderPosix {
PluginLoaderPosix::LoadPluginsInternal();
}
+ bool LaunchUtilityProcess() override {
+ // This method always does nothing and returns false. The actual
+ // implementation of this method launches another process, which is not
+ // very unit_test friendly.
+ return false;
+ }
+
void TestOnPluginLoaded(uint32 index, const WebPluginInfo& plugin) {
OnPluginLoaded(index, plugin);
}
@@ -394,4 +401,23 @@ TEST_F(PluginLoaderPosixTest, AllCrashed) {
EXPECT_EQ(0u, plugin_loader()->loaded_plugins().size());
}
+TEST_F(PluginLoaderPosixTest, PluginLaunchFailed) {
+ int did_callback = 0;
+ PluginService::GetPluginsCallback callback =
+ base::Bind(&VerifyCallback, base::Unretained(&did_callback));
+
+ EXPECT_CALL(*plugin_loader(), LoadPluginsInternal())
+ .WillOnce(testing::Invoke(
+ plugin_loader(), &MockPluginLoaderPosix::RealLoadPluginsInternal));
+
+ plugin_loader()->GetPlugins(callback);
+ message_loop()->RunUntilIdle();
+ EXPECT_EQ(1, did_callback);
+ EXPECT_EQ(0u, plugin_loader()->loaded_plugins().size());
+
+ // TODO(erikchen): This is a genuine leak that should be fixed.
+ // https://code.google.com/p/chromium/issues/detail?id=431906
+ testing::Mock::AllowLeak(plugin_loader());
+}
+
} // namespace content
diff --git a/chromium/content/browser/plugin_process_host.cc b/chromium/content/browser/plugin_process_host.cc
index dd969d3e6c7..d33b89b9705 100644
--- a/chromium/content/browser/plugin_process_host.cc
+++ b/chromium/content/browser/plugin_process_host.cc
@@ -24,8 +24,8 @@
#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"
+#include "content/browser/loader/resource_message_filter.h"
#include "content/browser/plugin_service_impl.h"
#include "content/common/child_process_host_impl.h"
#include "content/common/plugin_process_messages.h"
@@ -47,7 +47,7 @@
#if defined(OS_MACOSX)
#include "base/mac/mac_util.h"
-#include "ui/gfx/rect.h"
+#include "ui/gfx/geometry/rect.h"
#endif
#if defined(OS_WIN)
@@ -106,7 +106,7 @@ class PluginSandboxedProcessLauncherDelegate
~PluginSandboxedProcessLauncherDelegate() override {}
#if defined(OS_WIN)
- virtual bool ShouldSandbox() override {
+ bool ShouldSandbox() override {
return false;
}
@@ -146,7 +146,7 @@ PluginProcessHost::~PluginProcessHost() {
PostMessage(*window_index, WM_CLOSE, 0, 0);
}
#elif defined(OS_MACOSX)
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
// If the plugin process crashed but had fullscreen windows open at the time,
// make sure that the menu bar is visible.
for (size_t i = 0; i < plugin_fullscreen_windows_set_.size(); ++i) {
@@ -189,8 +189,8 @@ bool PluginProcessHost::Init(const WebPluginInfo& info) {
browser_command_line.GetSwitchValueNative(switches::kPluginLauncher);
#if defined(OS_MACOSX)
- // Run the plug-in process in a mode tolerant of heap execution without
- // explicit mprotect calls. Some plug-ins still rely on this quaint and
+ // Run the plugin process in a mode tolerant of heap execution without
+ // explicit mprotect calls. Some plugins still rely on this quaint and
// archaic "feature." See http://crbug.com/93551.
int flags = ChildProcessHost::CHILD_ALLOW_HEAP_EXECUTION;
#elif defined(OS_LINUX)
@@ -248,31 +248,32 @@ bool PluginProcessHost::Init(const WebPluginInfo& info) {
cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id);
- process_->Launch(
- new PluginSandboxedProcessLauncherDelegate(process_->GetHost()),
- cmd_line);
-
// The plugin needs to be shutdown gracefully, i.e. NP_Shutdown needs to be
// called on the plugin. The plugin process exits when it receives the
// OnChannelError notification indicating that the browser plugin channel has
// been destroyed.
- process_->SetTerminateChildOnShutdown(false);
+ bool terminate_on_shutdown = false;
+ process_->Launch(
+ new PluginSandboxedProcessLauncherDelegate(process_->GetHost()),
+ cmd_line,
+ terminate_on_shutdown);
ResourceMessageFilter::GetContextsCallback get_contexts_callback(
base::Bind(&PluginProcessHost::GetContexts,
base::Unretained(this)));
- // TODO(jam): right now we're passing NULL for appcache, blob storage, and
- // file system. If NPAPI plugins actually use this, we'll have to plumb them.
+ // TODO(jam): right now we're passing NULL for appcache, blob storage, file
+ // system and host zoom level context. If NPAPI plugins actually use this,
+ // we'll have to plumb them.
ResourceMessageFilter* resource_message_filter = new ResourceMessageFilter(
- process_->GetData().id, PROCESS_TYPE_PLUGIN, NULL, NULL, NULL, NULL,
+ process_->GetData().id, PROCESS_TYPE_PLUGIN, NULL, NULL, NULL, NULL, NULL,
get_contexts_callback);
process_->AddFilter(resource_message_filter);
return true;
}
void PluginProcessHost::ForceShutdown() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
Send(new PluginProcessMsg_NotifyRenderersOfPendingShutdown());
process_->ForceShutdown();
}
diff --git a/chromium/content/browser/plugin_process_host_mac.cc b/chromium/content/browser/plugin_process_host_mac.cc
index f3ad53f217b..c7ece477fbd 100644
--- a/chromium/content/browser/plugin_process_host_mac.cc
+++ b/chromium/content/browser/plugin_process_host_mac.cc
@@ -15,7 +15,7 @@
#include "content/browser/plugin_process_host.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/child_process_data.h"
-#include "ui/gfx/rect.h"
+#include "ui/gfx/geometry/rect.h"
namespace content {
@@ -83,7 +83,7 @@ void PluginProcessHost::OnPluginHideWindow(uint32 window_id,
}
void PluginProcessHost::OnAppActivation() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
// If our plugin process has any modal windows up, we need to bring it forward
// so that they act more like an in-process modal window would.
diff --git a/chromium/content/browser/plugin_service_impl.cc b/chromium/content/browser/plugin_service_impl.cc
index 49b66389dd3..b6ec7838be8 100644
--- a/chromium/content/browser/plugin_service_impl.cc
+++ b/chromium/content/browser/plugin_service_impl.cc
@@ -18,6 +18,7 @@
#include "content/browser/ppapi_plugin_process_host.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
+#include "content/common/content_switches_internal.h"
#include "content/common/pepper_plugin_list.h"
#include "content/common/plugin_list.h"
#include "content/common/view_messages.h"
@@ -59,6 +60,16 @@ enum FlashUsage {
FLASH_USAGE_ENUM_COUNT
};
+enum NPAPIPluginStatus {
+ // Platform does not support NPAPI.
+ NPAPI_STATUS_UNSUPPORTED,
+ // Platform supports NPAPI and NPAPI is disabled.
+ NPAPI_STATUS_DISABLED,
+ // Platform supports NPAPI and NPAPI is enabled.
+ NPAPI_STATUS_ENABLED,
+ NPAPI_STATUS_ENUM_COUNT
+};
+
bool LoadPluginListInProcess() {
#if defined(OS_WIN)
return true;
@@ -89,7 +100,7 @@ void WillLoadPluginsCallback(
#if defined(OS_MACOSX)
void NotifyPluginsOfActivation() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
for (PluginProcessHostIterator iter; !iter.Done(); ++iter)
iter->OnAppActivation();
@@ -143,7 +154,7 @@ PluginServiceImpl* PluginServiceImpl::GetInstance() {
}
PluginServiceImpl::PluginServiceImpl()
- : filter_(NULL) {
+ : npapi_plugins_enabled_(false), filter_(NULL) {
// Collect the total number of browser processes (which create
// PluginServiceImpl objects, to be precise). The number is used to normalize
// the number of processes which start at least one NPAPI/PPAPI Flash process.
@@ -267,7 +278,7 @@ PpapiPluginProcessHost* PluginServiceImpl::FindPpapiBrokerProcess(
PluginProcessHost* PluginServiceImpl::FindOrStartNpapiPluginProcess(
int render_process_id,
const base::FilePath& plugin_path) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (filter_ && !filter_->CanLoadPlugin(render_process_id, plugin_path))
return NULL;
@@ -308,7 +319,7 @@ PpapiPluginProcessHost* PluginServiceImpl::FindOrStartPpapiPluginProcess(
int render_process_id,
const base::FilePath& plugin_path,
const base::FilePath& profile_data_directory) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (filter_ && !filter_->CanLoadPlugin(render_process_id, plugin_path)) {
VLOG(1) << "Unable to load ppapi plugin: " << plugin_path.MaybeAsASCII();
@@ -351,7 +362,7 @@ PpapiPluginProcessHost* PluginServiceImpl::FindOrStartPpapiPluginProcess(
PpapiPluginProcessHost* PluginServiceImpl::FindOrStartPpapiBrokerProcess(
int render_process_id,
const base::FilePath& plugin_path) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (filter_ && !filter_->CanLoadPlugin(render_process_id, plugin_path))
return NULL;
@@ -379,7 +390,7 @@ void PluginServiceImpl::OpenChannelToNpapiPlugin(
const GURL& page_url,
const std::string& mime_type,
PluginProcessHost::Client* client) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(!ContainsKey(pending_plugin_clients_, client));
pending_plugin_clients_.insert(client);
@@ -426,7 +437,7 @@ void PluginServiceImpl::OpenChannelToPpapiBroker(
void PluginServiceImpl::CancelOpenChannelToNpapiPlugin(
PluginProcessHost::Client* client) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(ContainsKey(pending_plugin_clients_, client));
pending_plugin_clients_.erase(client);
}
@@ -468,13 +479,18 @@ void PluginServiceImpl::GetAllowedPluginForOpenChannelToPlugin(
render_process_id,
plugin_path,
client));
+ if (filter_) {
+ DCHECK_EQ(WebPluginInfo::PLUGIN_TYPE_NPAPI, info.type);
+ filter_->NPAPIPluginLoaded(render_process_id, render_frame_id, mime_type,
+ info);
+ }
}
void PluginServiceImpl::FinishOpenChannelToPlugin(
int render_process_id,
const base::FilePath& plugin_path,
PluginProcessHost::Client* client) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
// Make sure it hasn't been canceled yet.
if (!ContainsKey(pending_plugin_clients_, client))
@@ -613,7 +629,7 @@ void PluginServiceImpl::GetPluginsInternal(
void PluginServiceImpl::GetPluginsOnIOThread(
base::MessageLoopProxy* target_loop,
const GetPluginsCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
// If we switch back to loading plugins in process, then we need to make
// sure g_thread_init() gets called since plugins may call glib at load.
@@ -707,7 +723,7 @@ static const unsigned int kMaxCrashesPerInterval = 3;
static const unsigned int kCrashesInterval = 120;
void PluginServiceImpl::RegisterPluginCrash(const base::FilePath& path) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
std::map<base::FilePath, std::vector<base::Time> >::iterator i =
crash_times_.find(path);
if (i == crash_times_.end()) {
@@ -722,7 +738,7 @@ void PluginServiceImpl::RegisterPluginCrash(const base::FilePath& path) {
}
bool PluginServiceImpl::IsPluginUnstable(const base::FilePath& path) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
std::map<base::FilePath, std::vector<base::Time> >::const_iterator i =
crash_times_.find(path);
if (i == crash_times_.end()) {
@@ -760,8 +776,9 @@ void PluginServiceImpl::AddExtraPluginDir(const base::FilePath& path) {
void PluginServiceImpl::RegisterInternalPlugin(
const WebPluginInfo& info,
bool add_at_beginning) {
- if (!NPAPIPluginsSupported() &&
- info.type == WebPluginInfo::PLUGIN_TYPE_NPAPI) {
+ // Internal plugins should never be NPAPI.
+ CHECK_NE(info.type, WebPluginInfo::PLUGIN_TYPE_NPAPI);
+ if (info.type == WebPluginInfo::PLUGIN_TYPE_NPAPI) {
DVLOG(0) << "Don't register NPAPI plugins when they're not supported";
return;
}
@@ -778,17 +795,49 @@ void PluginServiceImpl::GetInternalPlugins(
}
bool PluginServiceImpl::NPAPIPluginsSupported() {
+ if (npapi_plugins_enabled_)
+ return true;
+
+ static bool command_line_checked = false;
+
+ if (!command_line_checked) {
#if defined(OS_WIN) || defined(OS_MACOSX)
- return true;
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
+ npapi_plugins_enabled_ = command_line->HasSwitch(switches::kEnableNpapi);
+#if defined(OS_WIN)
+ // NPAPI plugins don't play well with Win32k renderer lockdown.
+ if (npapi_plugins_enabled_)
+ DisableWin32kRendererLockdown();
+#endif
+ NPAPIPluginStatus status =
+ npapi_plugins_enabled_ ? NPAPI_STATUS_ENABLED : NPAPI_STATUS_DISABLED;
#else
- return false;
+ NPAPIPluginStatus status = NPAPI_STATUS_UNSUPPORTED;
#endif
+ UMA_HISTOGRAM_ENUMERATION("Plugin.NPAPIStatus", status,
+ NPAPI_STATUS_ENUM_COUNT);
+ }
+
+ return npapi_plugins_enabled_;
}
void PluginServiceImpl::DisablePluginsDiscoveryForTesting() {
PluginList::Singleton()->DisablePluginsDiscovery();
}
+void PluginServiceImpl::EnableNpapiPlugins() {
+#if defined(OS_WIN)
+ DisableWin32kRendererLockdown();
+#endif
+ npapi_plugins_enabled_ = true;
+ RefreshPlugins();
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&PluginService::PurgePluginListCache,
+ static_cast<BrowserContext*>(NULL), false));
+}
+
#if defined(OS_MACOSX)
void PluginServiceImpl::AppActivated() {
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
@@ -799,8 +848,8 @@ void PluginServiceImpl::AppActivated() {
bool GetPluginPropertyFromWindow(
HWND window, const wchar_t* plugin_atom_property,
base::string16* plugin_property) {
- ATOM plugin_atom = reinterpret_cast<ATOM>(
- GetPropW(window, plugin_atom_property));
+ ATOM plugin_atom = static_cast<ATOM>(
+ reinterpret_cast<uintptr_t>(GetPropW(window, plugin_atom_property)));
if (plugin_atom != 0) {
WCHAR plugin_property_local[MAX_PATH] = {0};
GlobalGetAtomNameW(plugin_atom,
diff --git a/chromium/content/browser/plugin_service_impl.h b/chromium/content/browser/plugin_service_impl.h
index 8770974a973..1d419e09dea 100644
--- a/chromium/content/browser/plugin_service_impl.h
+++ b/chromium/content/browser/plugin_service_impl.h
@@ -106,13 +106,14 @@ class CONTENT_EXPORT PluginServiceImpl
void UnregisterInternalPlugin(const base::FilePath& path) override;
void GetInternalPlugins(std::vector<WebPluginInfo>* plugins) override;
bool NPAPIPluginsSupported() override;
+ void EnableNpapiPlugins() override;
void DisablePluginsDiscoveryForTesting() override;
#if defined(OS_MACOSX)
void AppActivated() override;
#elif defined(OS_WIN)
- virtual bool GetPluginInfoFromWindow(HWND window,
- base::string16* plugin_name,
- base::string16* plugin_version) override;
+ bool GetPluginInfoFromWindow(HWND window,
+ base::string16* plugin_name,
+ base::string16* plugin_version) override;
// Returns true iff the given HWND is a plugin.
bool IsPluginWindow(HWND window);
@@ -153,7 +154,7 @@ class CONTENT_EXPORT PluginServiceImpl
// Cancels opening a channel to a NPAPI plugin.
void CancelOpenChannelToNpapiPlugin(PluginProcessHost::Client* client);
- // Used to monitor plug-in stability.
+ // Used to monitor plugin stability.
void RegisterPluginCrash(const base::FilePath& plugin_path);
private:
@@ -226,6 +227,8 @@ class CONTENT_EXPORT PluginServiceImpl
base::win::RegKey hklm_key_;
#endif
+ bool npapi_plugins_enabled_;
+
#if defined(OS_POSIX) && !defined(OS_OPENBSD) && !defined(OS_ANDROID)
ScopedVector<base::FilePathWatcher> file_watchers_;
#endif
@@ -237,14 +240,14 @@ class CONTENT_EXPORT PluginServiceImpl
std::set<PluginProcessHost::Client*> pending_plugin_clients_;
- // Used to sequentialize loading plug-ins from disk.
+ // Used to sequentialize loading plugins from disk.
base::SequencedWorkerPool::SequenceToken plugin_list_token_;
#if defined(OS_POSIX)
scoped_refptr<PluginLoaderPosix> plugin_loader_;
#endif
- // Used to detect if a given plug-in is crashing over and over.
+ // Used to detect if a given plugin is crashing over and over.
std::map<base::FilePath, std::vector<base::Time> > crash_times_;
DISALLOW_COPY_AND_ASSIGN(PluginServiceImpl);
diff --git a/chromium/content/browser/plugin_service_impl_browsertest.cc b/chromium/content/browser/plugin_service_impl_browsertest.cc
index b8a3dfb2248..e60516e67e0 100644
--- a/chromium/content/browser/plugin_service_impl_browsertest.cc
+++ b/chromium/content/browser/plugin_service_impl_browsertest.cc
@@ -24,7 +24,7 @@ namespace content {
const char kNPAPITestPluginMimeType[] = "application/vnd.npapi-test";
void OpenChannel(PluginProcessHost::Client* client) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
// Start opening the channel
PluginServiceImpl::GetInstance()->OpenChannelToNpapiPlugin(
0, 0, GURL(), GURL(), kNPAPITestPluginMimeType, client);
@@ -132,7 +132,7 @@ class PluginServiceTest : public ContentBrowserTest {
return shell()->web_contents()->GetBrowserContext()->GetResourceContext();
}
- void SetUpCommandLine(CommandLine* command_line) override {
+ void SetUpCommandLine(base::CommandLine* command_line) override {
#if defined(OS_MACOSX)
base::FilePath browser_directory;
PathService::Get(base::DIR_MODULE, &browser_directory);
@@ -181,11 +181,11 @@ class MockCanceledPluginServiceClient : public PluginProcessHost::Client {
get_resource_context_called_(false) {
}
- virtual ~MockCanceledPluginServiceClient() {}
+ ~MockCanceledPluginServiceClient() override {}
// Client implementation.
MOCK_METHOD0(ID, int());
- virtual ResourceContext* GetResourceContext() override {
+ ResourceContext* GetResourceContext() override {
get_resource_context_called_ = true;
return context_;
}
@@ -250,13 +250,13 @@ class MockCanceledBeforeSentPluginProcessHostClient
// Client implementation.
void SetPluginInfo(const WebPluginInfo& info) override {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
ASSERT_TRUE(info.mime_types.size());
ASSERT_EQ(kNPAPITestPluginMimeType, info.mime_types[0].mime_type);
set_plugin_info_called_ = true;
}
void OnFoundPluginProcessHost(PluginProcessHost* host) override {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
set_on_found_plugin_process_host_called();
set_host(host);
// This gets called right before we request the plugin<=>renderer channel,
@@ -327,7 +327,7 @@ class MockCanceledAfterSentPluginProcessHostClient
// We override this guy again since we don't want to cancel yet.
void OnFoundPluginProcessHost(PluginProcessHost* host) override {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
set_on_found_plugin_process_host_called();
set_host(host);
}
diff --git a/chromium/content/browser/power_profiler/power_data_provider_ia_win.cc b/chromium/content/browser/power_profiler/power_data_provider_ia_win.cc
index 2127ae29973..e6509ea31f7 100644
--- a/chromium/content/browser/power_profiler/power_data_provider_ia_win.cc
+++ b/chromium/content/browser/power_profiler/power_data_provider_ia_win.cc
@@ -64,6 +64,10 @@ base::TimeDelta PowerDataProviderIA::GetSamplingRate() {
return base::TimeDelta::FromMilliseconds(kDefaultSamplePeriodMs);
}
+PowerDataProvider::AccuracyLevel PowerDataProviderIA::GetAccuracyLevel() {
+ return High;
+}
+
bool PowerDataProviderIA::Initialize() {
if (is_open_)
return true;
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 427a5fa202a..8356fecc538 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
@@ -15,12 +15,14 @@ class PowerDataProviderIA : public PowerDataProvider {
public:
PowerDataProviderIA();
- virtual ~PowerDataProviderIA();
+ ~PowerDataProviderIA() override;
bool Initialize();
- virtual PowerEventVector GetData() override;
- virtual base::TimeDelta GetSamplingRate() override;
- virtual AccuracyLevel GetAccuracyLevel() override { return High; }
+
+ // PowerDataProvider:
+ PowerEventVector GetData() override;
+ base::TimeDelta GetSamplingRate() override;
+ AccuracyLevel GetAccuracyLevel() override;
private:
CIntelPowerGadgetLib energy_lib_;
diff --git a/chromium/content/browser/power_profiler/power_event.cc b/chromium/content/browser/power_profiler/power_event.cc
index 52d3fd70677..f8c3eab15df 100644
--- a/chromium/content/browser/power_profiler/power_event.cc
+++ b/chromium/content/browser/power_profiler/power_event.cc
@@ -11,7 +11,7 @@ const char* kPowerTypeNames[] = {
"Device"
};
-COMPILE_ASSERT(arraysize(kPowerTypeNames) == PowerEvent::ID_COUNT,
- kPowerTypeNames_incorrect_size);
+static_assert(arraysize(kPowerTypeNames) == PowerEvent::ID_COUNT,
+ "kPowerTypeNames array has incorrect size");
} // namespace content
diff --git a/chromium/content/browser/power_profiler/power_profiler_service.cc b/chromium/content/browser/power_profiler/power_profiler_service.cc
index 84ddb1bd15a..9961b6fbcc8 100644
--- a/chromium/content/browser/power_profiler/power_profiler_service.cc
+++ b/chromium/content/browser/power_profiler/power_profiler_service.cc
@@ -14,7 +14,7 @@ namespace content {
PowerProfilerService::PowerProfilerService()
: status_(UNINITIALIZED),
data_provider_(PowerDataProvider::Create()) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
// No provider supported for current platform.
if (!data_provider_.get())
@@ -33,7 +33,7 @@ PowerProfilerService::PowerProfilerService(
status_(UNINITIALIZED),
sample_period_(sample_period),
data_provider_(provider.Pass()) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (data_provider_.get())
status_ = INITIALIZED;
diff --git a/chromium/content/browser/power_save_blocker_android.cc b/chromium/content/browser/power_save_blocker_android.cc
index 2f79ef99f27..20ea63ccc58 100644
--- a/chromium/content/browser/power_save_blocker_android.cc
+++ b/chromium/content/browser/power_save_blocker_android.cc
@@ -2,30 +2,26 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "content/browser/power_save_blocker_android.h"
-
#include "base/android/jni_android.h"
-#include "base/android/jni_weak_ref.h"
#include "base/logging.h"
+#include "content/browser/android/content_view_core_impl.h"
#include "content/browser/power_save_blocker_impl.h"
+#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/android/content_view_core.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/web_contents_observer.h"
#include "jni/PowerSaveBlocker_jni.h"
-#include "ui/base/android/view_android.h"
-
-using base::android::AttachCurrentThread;
-using base::android::ScopedJavaLocalRef;
-using gfx::NativeView;
+#include "ui/android/view_android.h"
namespace content {
+using base::android::AttachCurrentThread;
+
class PowerSaveBlockerImpl::Delegate
- : public base::RefCountedThreadSafe<PowerSaveBlockerImpl::Delegate> {
+ : public base::RefCountedThreadSafe<PowerSaveBlockerImpl::Delegate>,
+ public WebContentsObserver {
public:
- explicit Delegate(NativeView view_android) {
- j_view_android_ = JavaObjectWeakGlobalRef(
- AttachCurrentThread(), view_android->GetJavaObject().obj());
- }
+ explicit Delegate(WebContents* web_contents);
// Does the actual work to apply or remove the desired power save block.
void ApplyBlock();
@@ -33,31 +29,66 @@ class PowerSaveBlockerImpl::Delegate
private:
friend class base::RefCountedThreadSafe<Delegate>;
- ~Delegate() {}
+ ~Delegate() override;
+
+ base::android::ScopedJavaLocalRef<jobject> GetContentViewCore();
- JavaObjectWeakGlobalRef j_view_android_;
+ base::android::ScopedJavaGlobalRef<jobject> java_power_save_blocker_;
DISALLOW_COPY_AND_ASSIGN(Delegate);
};
+PowerSaveBlockerImpl::Delegate::Delegate(WebContents* web_contents)
+ : WebContentsObserver(web_contents) {
+ JNIEnv* env = AttachCurrentThread();
+ java_power_save_blocker_.Reset(Java_PowerSaveBlocker_create(env));
+}
+
+PowerSaveBlockerImpl::Delegate::~Delegate() {
+}
+
void PowerSaveBlockerImpl::Delegate::ApplyBlock() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ base::android::ScopedJavaLocalRef<jobject> java_content_view_core =
+ GetContentViewCore();
+ if (java_content_view_core.is_null())
+ return;
+
+ ScopedJavaLocalRef<jobject> obj(java_power_save_blocker_);
JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> j_object = j_view_android_.get(env);
- if (j_object.obj())
- Java_PowerSaveBlocker_applyBlock(env, j_object.obj());
+ Java_PowerSaveBlocker_applyBlock(env, obj.obj(),
+ java_content_view_core.obj());
}
void PowerSaveBlockerImpl::Delegate::RemoveBlock() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ base::android::ScopedJavaLocalRef<jobject> java_content_view_core =
+ GetContentViewCore();
+ if (java_content_view_core.is_null())
+ return;
+
+ ScopedJavaLocalRef<jobject> obj(java_power_save_blocker_);
JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> j_object = j_view_android_.get(env);
- if (j_object.obj())
- Java_PowerSaveBlocker_removeBlock(env, j_object.obj());
+ Java_PowerSaveBlocker_removeBlock(env, obj.obj(),
+ java_content_view_core.obj());
+}
+
+base::android::ScopedJavaLocalRef<jobject>
+PowerSaveBlockerImpl::Delegate::GetContentViewCore() {
+ if (!web_contents())
+ return base::android::ScopedJavaLocalRef<jobject>();
+
+ ContentViewCoreImpl* content_view_core_impl =
+ ContentViewCoreImpl::FromWebContents(web_contents());
+ if (!content_view_core_impl)
+ return base::android::ScopedJavaLocalRef<jobject>();
+
+ return content_view_core_impl->GetJavaObject();
}
PowerSaveBlockerImpl::PowerSaveBlockerImpl(PowerSaveBlockerType type,
- const std::string& reason) {
+ Reason reason,
+ const std::string& description) {
// Don't support kPowerSaveBlockPreventAppSuspension
}
@@ -69,15 +100,13 @@ PowerSaveBlockerImpl::~PowerSaveBlockerImpl() {
}
}
-void PowerSaveBlockerImpl::InitDisplaySleepBlocker(NativeView view_android) {
- if (!view_android)
+void PowerSaveBlockerImpl::InitDisplaySleepBlocker(WebContents* web_contents) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (!web_contents)
return;
- delegate_ = new Delegate(view_android);
- // This may be called on any thread.
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&Delegate::ApplyBlock, delegate_));
+ delegate_ = new Delegate(web_contents);
+ delegate_->ApplyBlock();
}
bool RegisterPowerSaveBlocker(JNIEnv* env) {
diff --git a/chromium/content/browser/power_save_blocker_chromeos.cc b/chromium/content/browser/power_save_blocker_chromeos.cc
index f9a6722f8d2..83c6e8aab23 100644
--- a/chromium/content/browser/power_save_blocker_chromeos.cc
+++ b/chromium/content/browser/power_save_blocker_chromeos.cc
@@ -11,33 +11,52 @@
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/power_policy_controller.h"
#include "content/public/browser/browser_thread.h"
namespace content {
+namespace {
+
+// Converts a PowerSaveBlocker::Reason to a
+// chromeos::PowerPolicyController::WakeLockReason.
+chromeos::PowerPolicyController::WakeLockReason GetWakeLockReason(
+ PowerSaveBlocker::Reason reason) {
+ switch (reason) {
+ case PowerSaveBlocker::kReasonAudioPlayback:
+ return chromeos::PowerPolicyController::REASON_AUDIO_PLAYBACK;
+ case PowerSaveBlocker::kReasonVideoPlayback:
+ return chromeos::PowerPolicyController::REASON_VIDEO_PLAYBACK;
+ case PowerSaveBlocker::kReasonOther:
+ return chromeos::PowerPolicyController::REASON_OTHER;
+ }
+ return chromeos::PowerPolicyController::REASON_OTHER;
+}
+
+} // namespace
+
class PowerSaveBlockerImpl::Delegate
: public base::RefCountedThreadSafe<PowerSaveBlockerImpl::Delegate> {
public:
- Delegate(PowerSaveBlockerType type, const std::string& reason)
- : type_(type),
- reason_(reason),
- block_id_(0) {}
+ Delegate(PowerSaveBlockerType type,
+ Reason reason,
+ const std::string& description)
+ : type_(type), reason_(reason), description_(description), block_id_(0) {}
void ApplyBlock() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (!chromeos::DBusThreadManager::IsInitialized())
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (!chromeos::PowerPolicyController::IsInitialized())
return;
- chromeos::PowerPolicyController* controller =
- chromeos::DBusThreadManager::Get()->GetPowerPolicyController();
+ auto* controller = chromeos::PowerPolicyController::Get();
switch (type_) {
case kPowerSaveBlockPreventAppSuspension:
- block_id_ = controller->AddSystemWakeLock(reason_);
+ block_id_ = controller->AddSystemWakeLock(GetWakeLockReason(reason_),
+ description_);
break;
case kPowerSaveBlockPreventDisplaySleep:
- block_id_ = controller->AddScreenWakeLock(reason_);
+ block_id_ = controller->AddScreenWakeLock(GetWakeLockReason(reason_),
+ description_);
break;
default:
NOTREACHED() << "Unhandled block type " << type_;
@@ -45,12 +64,11 @@ class PowerSaveBlockerImpl::Delegate
}
void RemoveBlock() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (!chromeos::DBusThreadManager::IsInitialized())
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (!chromeos::PowerPolicyController::IsInitialized())
return;
- chromeos::DBusThreadManager::Get()->GetPowerPolicyController()->
- RemoveWakeLock(block_id_);
+ chromeos::PowerPolicyController::Get()->RemoveWakeLock(block_id_);
}
private:
@@ -58,7 +76,8 @@ class PowerSaveBlockerImpl::Delegate
virtual ~Delegate() {}
PowerSaveBlockerType type_;
- std::string reason_;
+ Reason reason_;
+ std::string description_;
// ID corresponding to the block request in PowerPolicyController.
int block_id_;
@@ -67,8 +86,9 @@ class PowerSaveBlockerImpl::Delegate
};
PowerSaveBlockerImpl::PowerSaveBlockerImpl(PowerSaveBlockerType type,
- const std::string& reason)
- : delegate_(new Delegate(type, reason)) {
+ Reason reason,
+ const std::string& description)
+ : delegate_(new Delegate(type, reason, description)) {
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(&Delegate::ApplyBlock, delegate_));
}
diff --git a/chromium/content/browser/power_save_blocker_impl.cc b/chromium/content/browser/power_save_blocker_impl.cc
index 01007ad9afa..416ddb334c4 100644
--- a/chromium/content/browser/power_save_blocker_impl.cc
+++ b/chromium/content/browser/power_save_blocker_impl.cc
@@ -11,8 +11,10 @@ PowerSaveBlocker::~PowerSaveBlocker() {}
// static
scoped_ptr<PowerSaveBlocker> PowerSaveBlocker::Create(
PowerSaveBlockerType type,
- const std::string& reason) {
- return scoped_ptr<PowerSaveBlocker>(new PowerSaveBlockerImpl(type, reason));
+ Reason reason,
+ const std::string& description) {
+ return scoped_ptr<PowerSaveBlocker>(
+ new PowerSaveBlockerImpl(type, reason, description));
}
} // namespace content
diff --git a/chromium/content/browser/power_save_blocker_impl.h b/chromium/content/browser/power_save_blocker_impl.h
index 39ba8f24f8e..a30422646fe 100644
--- a/chromium/content/browser/power_save_blocker_impl.h
+++ b/chromium/content/browser/power_save_blocker_impl.h
@@ -5,22 +5,27 @@
#ifndef CONTENT_BROWSER_POWER_SAVE_BLOCKER_IMPL_H_
#define CONTENT_BROWSER_POWER_SAVE_BLOCKER_IMPL_H_
+#include <string>
+
#include "base/memory/ref_counted.h"
#include "content/public/browser/power_save_blocker.h"
-#include "ui/gfx/native_widget_types.h"
namespace content {
+class WebContents;
+
class PowerSaveBlockerImpl : public PowerSaveBlocker {
public:
- PowerSaveBlockerImpl(PowerSaveBlockerType type, const std::string& reason);
+ PowerSaveBlockerImpl(PowerSaveBlockerType type,
+ Reason reason,
+ const std::string& description);
~PowerSaveBlockerImpl() override;
#if defined(OS_ANDROID)
// In Android platform, the kPowerSaveBlockPreventDisplaySleep type of
- // PowerSaveBlocker should associated with the ViewAndroid,
- // so the blocker could be removed by platform if the view isn't visble
- void InitDisplaySleepBlocker(gfx::NativeView view_android);
+ // PowerSaveBlocker should associated with a WebContents, so the blocker
+ // could be removed by platform if the WebContents is hidden.
+ void InitDisplaySleepBlocker(WebContents* web_contents);
#endif
private:
diff --git a/chromium/content/browser/power_save_blocker_mac.cc b/chromium/content/browser/power_save_blocker_mac.cc
index 9b3fe090c3c..ca466606cf8 100644
--- a/chromium/content/browser/power_save_blocker_mac.cc
+++ b/chromium/content/browser/power_save_blocker_mac.cc
@@ -41,8 +41,10 @@ base::LazyInstance<base::Thread, PowerSaveBlockerLazyInstanceTraits>
class PowerSaveBlockerImpl::Delegate
: public base::RefCountedThreadSafe<PowerSaveBlockerImpl::Delegate> {
public:
- Delegate(PowerSaveBlockerType type, const std::string& reason)
- : type_(type), reason_(reason), assertion_(kIOPMNullAssertionID) {}
+ Delegate(PowerSaveBlockerType type, const std::string& description)
+ : type_(type),
+ description_(description),
+ assertion_(kIOPMNullAssertionID) {}
// Does the actual work to apply or remove the desired power save block.
void ApplyBlock();
@@ -52,7 +54,7 @@ class PowerSaveBlockerImpl::Delegate
friend class base::RefCountedThreadSafe<Delegate>;
~Delegate() {}
PowerSaveBlockerType type_;
- std::string reason_;
+ std::string description_;
IOPMAssertionID assertion_;
};
@@ -75,12 +77,10 @@ void PowerSaveBlockerImpl::Delegate::ApplyBlock() {
break;
}
if (level) {
- base::ScopedCFTypeRef<CFStringRef> cf_reason(
- base::SysUTF8ToCFStringRef(reason_));
- IOReturn result = IOPMAssertionCreateWithName(level,
- kIOPMAssertionLevelOn,
- cf_reason,
- &assertion_);
+ base::ScopedCFTypeRef<CFStringRef> cf_description(
+ base::SysUTF8ToCFStringRef(description_));
+ IOReturn result = IOPMAssertionCreateWithName(level, kIOPMAssertionLevelOn,
+ cf_description, &assertion_);
LOG_IF(ERROR, result != kIOReturnSuccess)
<< "IOPMAssertionCreate: " << result;
}
@@ -98,8 +98,9 @@ void PowerSaveBlockerImpl::Delegate::RemoveBlock() {
}
PowerSaveBlockerImpl::PowerSaveBlockerImpl(PowerSaveBlockerType type,
- const std::string& reason)
- : delegate_(new Delegate(type, reason)) {
+ Reason reason,
+ const std::string& description)
+ : delegate_(new Delegate(type, description)) {
g_power_thread.Pointer()->message_loop()->PostTask(
FROM_HERE,
base::Bind(&Delegate::ApplyBlock, delegate_));
diff --git a/chromium/content/browser/power_save_blocker_ozone.cc b/chromium/content/browser/power_save_blocker_ozone.cc
index f21f4144cf6..de7562c47e4 100644
--- a/chromium/content/browser/power_save_blocker_ozone.cc
+++ b/chromium/content/browser/power_save_blocker_ozone.cc
@@ -24,7 +24,8 @@ class PowerSaveBlockerImpl::Delegate
};
PowerSaveBlockerImpl::PowerSaveBlockerImpl(PowerSaveBlockerType type,
- const std::string& reason)
+ Reason reason,
+ const std::string& description)
: delegate_(new Delegate()) {
NOTIMPLEMENTED();
}
diff --git a/chromium/content/browser/power_save_blocker_win.cc b/chromium/content/browser/power_save_blocker_win.cc
index 4cbecf4447a..6d2841146ba 100644
--- a/chromium/content/browser/power_save_blocker_win.cc
+++ b/chromium/content/browser/power_save_blocker_win.cc
@@ -17,7 +17,8 @@ namespace {
int g_blocker_count[2];
-HANDLE CreatePowerRequest(POWER_REQUEST_TYPE type, const std::string& reason) {
+HANDLE CreatePowerRequest(POWER_REQUEST_TYPE type,
+ const std::string& description) {
typedef HANDLE (WINAPI* PowerCreateRequestPtr)(PREASON_CONTEXT);
typedef BOOL (WINAPI* PowerSetRequestPtr)(HANDLE, POWER_REQUEST_TYPE);
@@ -39,11 +40,12 @@ HANDLE CreatePowerRequest(POWER_REQUEST_TYPE type, const std::string& reason) {
if (!PowerCreateRequestFn || !PowerSetRequestFn)
return INVALID_HANDLE_VALUE;
}
- base::string16 wide_reason = base::ASCIIToUTF16(reason);
+ base::string16 wide_description = base::ASCIIToUTF16(description);
REASON_CONTEXT context = {0};
context.Version = POWER_REQUEST_CONTEXT_VERSION;
context.Flags = POWER_REQUEST_CONTEXT_SIMPLE_STRING;
- context.Reason.SimpleReasonString = const_cast<wchar_t*>(wide_reason.c_str());
+ context.Reason.SimpleReasonString =
+ const_cast<wchar_t*>(wide_description.c_str());
base::win::ScopedHandle handle(PowerCreateRequestFn(&context));
if (!handle.IsValid())
@@ -110,8 +112,8 @@ void ApplySimpleBlock(PowerSaveBlocker::PowerSaveBlockerType type,
class PowerSaveBlockerImpl::Delegate
: public base::RefCountedThreadSafe<PowerSaveBlockerImpl::Delegate> {
public:
- Delegate(PowerSaveBlockerType type, const std::string& reason)
- : type_(type), reason_(reason) {}
+ Delegate(PowerSaveBlockerType type, const std::string& description)
+ : type_(type), description_(description) {}
// Does the actual work to apply or remove the desired power save block.
void ApplyBlock();
@@ -125,22 +127,22 @@ class PowerSaveBlockerImpl::Delegate
~Delegate() {}
PowerSaveBlockerType type_;
- const std::string reason_;
+ const std::string description_;
base::win::ScopedHandle handle_;
DISALLOW_COPY_AND_ASSIGN(Delegate);
};
void PowerSaveBlockerImpl::Delegate::ApplyBlock() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (base::win::GetVersion() < base::win::VERSION_WIN7)
return ApplySimpleBlock(type_, 1);
- handle_.Set(CreatePowerRequest(RequestType(), reason_));
+ handle_.Set(CreatePowerRequest(RequestType(), description_));
}
void PowerSaveBlockerImpl::Delegate::RemoveBlock() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (base::win::GetVersion() < base::win::VERSION_WIN7)
return ApplySimpleBlock(type_, -1);
@@ -158,8 +160,9 @@ POWER_REQUEST_TYPE PowerSaveBlockerImpl::Delegate::RequestType() {
}
PowerSaveBlockerImpl::PowerSaveBlockerImpl(PowerSaveBlockerType type,
- const std::string& reason)
- : delegate_(new Delegate(type, reason)) {
+ Reason reason,
+ const std::string& description)
+ : delegate_(new Delegate(type, description)) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&Delegate::ApplyBlock, delegate_));
diff --git a/chromium/content/browser/power_save_blocker_x11.cc b/chromium/content/browser/power_save_blocker_x11.cc
index f1d028c7f45..bc20e025b8b 100644
--- a/chromium/content/browser/power_save_blocker_x11.cc
+++ b/chromium/content/browser/power_save_blocker_x11.cc
@@ -67,7 +67,7 @@ class PowerSaveBlockerImpl::Delegate
: public base::RefCountedThreadSafe<PowerSaveBlockerImpl::Delegate> {
public:
// Picks an appropriate D-Bus API to use based on the desktop environment.
- Delegate(PowerSaveBlockerType type, const std::string& reason);
+ Delegate(PowerSaveBlockerType type, const std::string& description);
// Post a task to initialize the delegate on the UI thread, which will itself
// then post a task to apply the power save block on the FILE thread.
@@ -93,6 +93,11 @@ class PowerSaveBlockerImpl::Delegate
void ApplyBlock(DBusAPI api);
void RemoveBlock(DBusAPI api);
+ // Asynchronous callback functions for ApplyBlock and RemoveBlock.
+ // Functions do not receive ownership of |response|.
+ void ApplyBlockFinished(DBusAPI api, dbus::Response* response);
+ void RemoveBlockFinished(dbus::Response* response);
+
// If DPMS (the power saving system in X11) is not enabled, then we don't want
// to try to disable power saving, since on some desktop environments that may
// enable DPMS with very poor default settings (e.g. turning off the display
@@ -104,7 +109,7 @@ class PowerSaveBlockerImpl::Delegate
static DBusAPI SelectAPI();
const PowerSaveBlockerType type_;
- const std::string reason_;
+ const std::string description_;
// Initially, we post a message to the UI thread to select an API. When it
// finishes, it will post a message to the FILE thread to perform the actual
@@ -115,6 +120,15 @@ class PowerSaveBlockerImpl::Delegate
bool enqueue_apply_;
base::Lock lock_;
+ // Indicates that a D-Bus power save blocking request is in flight.
+ bool block_inflight_;
+ // Used to detect erronous redundant calls to RemoveBlock().
+ bool unblock_inflight_;
+ // Indicates that RemoveBlock() is called before ApplyBlock() has finished.
+ // If it's true, then the RemoveBlock() call will be processed immediately
+ // after ApplyBlock() has finished.
+ bool enqueue_unblock_;
+
scoped_refptr<dbus::Bus> bus_;
// The cookie that identifies our inhibit request,
@@ -125,9 +139,9 @@ class PowerSaveBlockerImpl::Delegate
};
PowerSaveBlockerImpl::Delegate::Delegate(PowerSaveBlockerType type,
- const std::string& reason)
+ const std::string& description)
: type_(type),
- reason_(reason),
+ description_(description),
api_(NO_API),
enqueue_apply_(false),
inhibit_cookie_(0) {
@@ -139,6 +153,9 @@ void PowerSaveBlockerImpl::Delegate::Init() {
base::AutoLock lock(lock_);
DCHECK(!enqueue_apply_);
enqueue_apply_ = true;
+ block_inflight_ = false;
+ unblock_inflight_ = false;
+ enqueue_unblock_ = false;
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(&Delegate::InitOnUIThread, this));
}
@@ -157,7 +174,7 @@ void PowerSaveBlockerImpl::Delegate::CleanUp() {
}
void PowerSaveBlockerImpl::Delegate::InitOnUIThread() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
base::AutoLock lock(lock_);
api_ = SelectAPI();
if (enqueue_apply_ && api_ != NO_API) {
@@ -171,8 +188,9 @@ void PowerSaveBlockerImpl::Delegate::InitOnUIThread() {
}
void PowerSaveBlockerImpl::Delegate::ApplyBlock(DBusAPI api) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- DCHECK(!bus_.get()); // ApplyBlock() should only be called once.
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+ DCHECK(!bus_); // ApplyBlock() should only be called once.
+ DCHECK(!block_inflight_);
dbus::Bus::Options options;
options.bus_type = dbus::Bus::SESSION;
@@ -202,7 +220,7 @@ void PowerSaveBlockerImpl::Delegate::ApplyBlock(DBusAPI api) {
message_writer->AppendString(
base::CommandLine::ForCurrentProcess()->GetProgram().value());
message_writer->AppendUint32(0); // should be toplevel_xid
- message_writer->AppendString(reason_);
+ message_writer->AppendString(description_);
{
uint32 flags = 0;
switch (type_) {
@@ -229,30 +247,57 @@ void PowerSaveBlockerImpl::Delegate::ApplyBlock(DBusAPI api) {
// reason: The reason for the inhibit
message_writer->AppendString(
base::CommandLine::ForCurrentProcess()->GetProgram().value());
- message_writer->AppendString(reason_);
+ message_writer->AppendString(description_);
break;
}
- // We could do this method call asynchronously, but if we did, we'd need to
- // handle the case where we want to cancel the block before we get a reply.
- // We're on the FILE thread so it should be OK to block briefly here.
- scoped_ptr<dbus::Response> response(object_proxy->CallMethodAndBlock(
- method_call.get(), dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
+ block_inflight_ = true;
+ object_proxy->CallMethod(
+ method_call.get(), dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+ base::Bind(&PowerSaveBlockerImpl::Delegate::ApplyBlockFinished, this,
+ api));
+}
+
+void PowerSaveBlockerImpl::Delegate::ApplyBlockFinished(
+ DBusAPI api,
+ dbus::Response* response) {
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+ DCHECK(bus_);
+ DCHECK(block_inflight_);
+ block_inflight_ = false;
+
if (response) {
// The method returns an inhibit_cookie, used to uniquely identify
// this request. It should be used as an argument to Uninhibit()
// in order to remove the request.
- dbus::MessageReader message_reader(response.get());
+ dbus::MessageReader message_reader(response);
if (!message_reader.PopUint32(&inhibit_cookie_))
LOG(ERROR) << "Invalid Inhibit() response: " << response->ToString();
} else {
LOG(ERROR) << "No response to Inhibit() request!";
}
+
+ if (enqueue_unblock_) {
+ enqueue_unblock_ = false;
+ // RemoveBlock() was called while the Inhibit operation was in flight,
+ // so go ahead and remove the block now.
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+ base::Bind(&Delegate::RemoveBlock, this, api_));
+ }
}
void PowerSaveBlockerImpl::Delegate::RemoveBlock(DBusAPI api) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- DCHECK(bus_.get()); // RemoveBlock() should only be called once.
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+ DCHECK(bus_); // RemoveBlock() should only be called once.
+ DCHECK(!unblock_inflight_);
+
+ if (block_inflight_) {
+ DCHECK(!enqueue_unblock_);
+ // Can't call RemoveBlock until ApplyBlock's async operation has
+ // finished. Enqueue it for execution once ApplyBlock is done.
+ enqueue_unblock_ = true;
+ return;
+ }
scoped_refptr<dbus::ObjectProxy> object_proxy;
scoped_ptr<dbus::MethodCall> method_call;
@@ -279,8 +324,18 @@ void PowerSaveBlockerImpl::Delegate::RemoveBlock(DBusAPI api) {
dbus::MessageWriter message_writer(method_call.get());
message_writer.AppendUint32(inhibit_cookie_);
- scoped_ptr<dbus::Response> response(object_proxy->CallMethodAndBlock(
- method_call.get(), dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
+ unblock_inflight_ = true;
+ object_proxy->CallMethod(
+ method_call.get(), dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+ base::Bind(&PowerSaveBlockerImpl::Delegate::RemoveBlockFinished, this));
+}
+
+void PowerSaveBlockerImpl::Delegate::RemoveBlockFinished(
+ dbus::Response* response) {
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+ DCHECK(bus_);
+ unblock_inflight_ = false;
+
if (!response)
LOG(ERROR) << "No response to Uninhibit() request!";
// We don't care about checking the result. We assume it works; we can't
@@ -325,9 +380,10 @@ DBusAPI PowerSaveBlockerImpl::Delegate::SelectAPI() {
return NO_API;
}
-PowerSaveBlockerImpl::PowerSaveBlockerImpl(
- PowerSaveBlockerType type, const std::string& reason)
- : delegate_(new Delegate(type, reason)) {
+PowerSaveBlockerImpl::PowerSaveBlockerImpl(PowerSaveBlockerType type,
+ Reason reason,
+ const std::string& description)
+ : delegate_(new Delegate(type, description)) {
delegate_->Init();
}
diff --git a/chromium/content/browser/power_usage_monitor_impl.cc b/chromium/content/browser/power_usage_monitor_impl.cc
new file mode 100644
index 00000000000..fb294f3e0ca
--- /dev/null
+++ b/chromium/content/browser/power_usage_monitor_impl.cc
@@ -0,0 +1,276 @@
+// Copyright 2014 The Chromium Authors. 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/power_usage_monitor_impl.h"
+
+#include "base/bind.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/metrics/histogram.h"
+#include "base/strings/stringprintf.h"
+#include "base/sys_info.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_source.h"
+#include "content/public/browser/notification_types.h"
+#include "content/public/browser/power_usage_monitor.h"
+#include "content/public/browser/render_process_host.h"
+
+namespace content {
+
+namespace {
+
+// Wait this long after power on before enabling power usage monitoring.
+const int kMinUptimeMinutes = 30;
+
+// Minimum discharge time after which we collect the discharge rate.
+const int kMinDischargeMinutes = 30;
+
+class PowerUsageMonitorSystemInterface
+ : public PowerUsageMonitor::SystemInterface {
+ public:
+ explicit PowerUsageMonitorSystemInterface(PowerUsageMonitor* owner)
+ : power_usage_monitor_(owner),
+ weak_ptr_factory_(this) {}
+ ~PowerUsageMonitorSystemInterface() override {}
+
+ void ScheduleHistogramReport(base::TimeDelta delay) override {
+ BrowserThread::PostDelayedTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(
+ &PowerUsageMonitorSystemInterface::ReportBatteryLevelHistogram,
+ weak_ptr_factory_.GetWeakPtr(),
+ Now(),
+ delay),
+ delay);
+ }
+
+ void CancelPendingHistogramReports() override {
+ weak_ptr_factory_.InvalidateWeakPtrs();
+ }
+
+ void RecordDischargePercentPerHour(int percent_per_hour) override {
+ UMA_HISTOGRAM_PERCENTAGE("Power.BatteryDischargePercentPerHour",
+ percent_per_hour);
+ }
+
+ base::Time Now() override { return base::Time::Now(); }
+
+ protected:
+ void ReportBatteryLevelHistogram(base::Time start_time,
+ base::TimeDelta discharge_time) {
+ // It's conceivable that the code to cancel pending histogram reports on
+ // system suspend, will only get called after the system has woken up.
+ // To mitigage this, check whether more time has passed than expected and
+ // abort histogram recording in this case.
+
+ // Delayed tasks are subject to timer coalescing and can fire anywhere from
+ // delay -> delay * 1.5) . In most cases, the OS should fire the task
+ // at the next wakeup and not as late as it can.
+ // A threshold of 2 minutes is used, since that should be large enough to
+ // take the slop factor due to coalescing into account.
+ base::TimeDelta threshold = discharge_time +
+ base::TimeDelta::FromMinutes(2);
+ if ((Now() - start_time) > threshold) {
+ return;
+ }
+
+ const std::string histogram_name = base::StringPrintf(
+ "Power.BatteryDischarge_%d", discharge_time.InMinutes());
+ base::HistogramBase* histogram =
+ base::Histogram::FactoryGet(histogram_name,
+ 1,
+ 100,
+ 101,
+ base::Histogram::kUmaTargetedHistogramFlag);
+ double discharge_amount = power_usage_monitor_->discharge_amount();
+ histogram->Add(discharge_amount * 100);
+ }
+
+ private:
+ PowerUsageMonitor* power_usage_monitor_; // Not owned.
+
+ // Used to cancel in progress delayed tasks.
+ base::WeakPtrFactory<PowerUsageMonitorSystemInterface> weak_ptr_factory_;
+};
+
+} // namespace
+
+void StartPowerUsageMonitor() {
+ static base::LazyInstance<PowerUsageMonitor>::Leaky monitor =
+ LAZY_INSTANCE_INITIALIZER;
+ monitor.Get().Start();
+}
+
+PowerUsageMonitor::PowerUsageMonitor()
+ : callback_(base::Bind(&PowerUsageMonitor::OnBatteryStatusUpdate,
+ base::Unretained(this))),
+ system_interface_(new PowerUsageMonitorSystemInterface(this)),
+ started_(false),
+ tracking_discharge_(false),
+ on_battery_power_(false),
+ initial_battery_level_(0),
+ current_battery_level_(0) {
+}
+
+PowerUsageMonitor::~PowerUsageMonitor() {
+ if (started_)
+ base::PowerMonitor::Get()->RemoveObserver(this);
+}
+
+void PowerUsageMonitor::Start() {
+ // Power monitoring may be delayed based on uptime, but renderer process
+ // lifetime tracking needs to start immediately so processes created before
+ // then are accounted for.
+ registrar_.Add(this,
+ NOTIFICATION_RENDERER_PROCESS_CREATED,
+ NotificationService::AllBrowserContextsAndSources());
+ registrar_.Add(this,
+ NOTIFICATION_RENDERER_PROCESS_CLOSED,
+ NotificationService::AllBrowserContextsAndSources());
+ subscription_ =
+ device::BatteryStatusService::GetInstance()->AddCallback(callback_);
+
+ // Delay initialization until the system has been up for a while.
+ // This is to mitigate the effect of increased power draw during system start.
+ base::TimeDelta uptime =
+ base::TimeDelta::FromMilliseconds(base::SysInfo::Uptime());
+ base::TimeDelta min_uptime = base::TimeDelta::FromMinutes(kMinUptimeMinutes);
+ if (uptime < min_uptime) {
+ base::TimeDelta delay = min_uptime - uptime;
+ BrowserThread::PostDelayedTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&PowerUsageMonitor::StartInternal, base::Unretained(this)),
+ delay);
+ } else {
+ StartInternal();
+ }
+}
+
+void PowerUsageMonitor::StartInternal() {
+ DCHECK(!started_);
+ started_ = true;
+
+ // PowerMonitor is used to get suspend/resume notifications.
+ base::PowerMonitor::Get()->AddObserver(this);
+}
+
+void PowerUsageMonitor::DischargeStarted(double battery_level) {
+ on_battery_power_ = true;
+
+ // If all browser windows are closed, don't report power metrics since
+ // Chrome's power draw is likely not significant.
+ if (live_renderer_ids_.empty())
+ return;
+
+ // Cancel any in-progress ReportBatteryLevelHistogram() calls.
+ system_interface_->CancelPendingHistogramReports();
+
+ tracking_discharge_ = true;
+ start_discharge_time_ = system_interface_->Now();
+
+ initial_battery_level_ = battery_level;
+ current_battery_level_ = battery_level;
+
+ const int kBatteryReportingIntervalMinutes[] = {5, 15, 30};
+ for (auto reporting_interval : kBatteryReportingIntervalMinutes) {
+ base::TimeDelta delay = base::TimeDelta::FromMinutes(reporting_interval);
+ system_interface_->ScheduleHistogramReport(delay);
+ }
+}
+
+void PowerUsageMonitor::WallPowerConnected(double battery_level) {
+ on_battery_power_ = false;
+
+ if (tracking_discharge_) {
+ DCHECK(!start_discharge_time_.is_null());
+ base::TimeDelta discharge_time =
+ system_interface_->Now() - start_discharge_time_;
+
+ if (discharge_time.InMinutes() > kMinDischargeMinutes) {
+ // Record the rate at which the battery discharged over the entire period
+ // the system was on battery power.
+ double discharge_hours = discharge_time.InSecondsF() / 3600.0;
+ int percent_per_hour =
+ floor(((discharge_amount() / discharge_hours) * 100.0) + 0.5);
+ system_interface_->RecordDischargePercentPerHour(percent_per_hour);
+ }
+ }
+
+ // Cancel any in-progress ReportBatteryLevelHistogram() calls.
+ system_interface_->CancelPendingHistogramReports();
+
+ initial_battery_level_ = 0;
+ current_battery_level_ = 0;
+ start_discharge_time_ = base::Time();
+ tracking_discharge_ = false;
+}
+
+void PowerUsageMonitor::OnBatteryStatusUpdate(
+ const device::BatteryStatus& status) {
+ bool now_on_battery_power = (status.charging == 0);
+ bool was_on_battery_power = on_battery_power_;
+ double battery_level = status.level;
+
+ if (now_on_battery_power == was_on_battery_power) {
+ if (now_on_battery_power)
+ current_battery_level_ = battery_level;
+ return;
+ } else if (now_on_battery_power) { // Wall power disconnected.
+ DischargeStarted(battery_level);
+ } else { // Wall power connected.
+ WallPowerConnected(battery_level);
+ }
+}
+
+void PowerUsageMonitor::OnRenderProcessNotification(int type, int rph_id) {
+ size_t previous_num_live_renderers = live_renderer_ids_.size();
+
+ if (type == NOTIFICATION_RENDERER_PROCESS_CREATED) {
+ live_renderer_ids_.insert(rph_id);
+ } else if (type == NOTIFICATION_RENDERER_PROCESS_CLOSED) {
+ live_renderer_ids_.erase(rph_id);
+ } else {
+ NOTREACHED() << "Unexpected notification type: " << type;
+ }
+
+ if (live_renderer_ids_.empty() && previous_num_live_renderers != 0) {
+ // All render processes have died.
+ CancelPendingHistogramReporting();
+ tracking_discharge_ = false;
+ }
+
+}
+
+void PowerUsageMonitor::SetSystemInterfaceForTest(
+ scoped_ptr<SystemInterface> interface) {
+ system_interface_ = interface.Pass();
+}
+
+void PowerUsageMonitor::OnPowerStateChange(bool on_battery_power) {
+}
+
+void PowerUsageMonitor::OnResume() {
+}
+
+void PowerUsageMonitor::OnSuspend() {
+ CancelPendingHistogramReporting();
+}
+
+void PowerUsageMonitor::Observe(int type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ RenderProcessHost* rph = Source<RenderProcessHost>(source).ptr();
+ OnRenderProcessNotification(type, rph->GetID());
+}
+
+void PowerUsageMonitor::CancelPendingHistogramReporting() {
+ // Cancel any in-progress histogram reports and reporting of discharge UMA.
+ system_interface_->CancelPendingHistogramReports();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/power_usage_monitor_impl.h b/chromium/content/browser/power_usage_monitor_impl.h
new file mode 100644
index 00000000000..9b95ae4d4ae
--- /dev/null
+++ b/chromium/content/browser/power_usage_monitor_impl.h
@@ -0,0 +1,133 @@
+// Copyright 2014 The Chromium Authors. 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_POWER_USAGE_MONITOR_IMPL_H_
+#define CONTENT_BROWSER_POWER_USAGE_MONITOR_IMPL_H_
+
+#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/singleton.h"
+#include "base/power_monitor/power_monitor.h"
+#include "base/time/time.h"
+#include "content/common/content_export.h"
+#include "content/public/browser/browser_message_filter.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+#include "device/battery/battery_status_service.h"
+
+namespace content {
+
+// Record statistics on power usage.
+//
+// Two main statics are recorded by this class:
+// * Power.BatteryDischarge_{5,15,30} - delta between battery level when
+// unplugged from wallpower, over the specified period - in minutes.
+// * Power.BatteryDischargeRateWhenUnplugged - the rate of battery discharge
+// from the device being unplugged until it's plugged back in, if said period
+// was longer than 30 minutes.
+//
+// Heuristics:
+// * Data collection starts after system uptime exceeds 30 minutes.
+// * If the machine goes to sleep or all renderers are closed then the current
+// measurement is cancelled.
+class CONTENT_EXPORT PowerUsageMonitor : public base::PowerObserver,
+ public NotificationObserver {
+ public:
+ class SystemInterface {
+ public:
+ virtual ~SystemInterface() {}
+
+ virtual void ScheduleHistogramReport(base::TimeDelta delay) = 0;
+ virtual void CancelPendingHistogramReports() = 0;
+
+ // Record the battery discharge percent per hour over the time the system
+ // is on battery power, legal values [0,100].
+ virtual void RecordDischargePercentPerHour(int percent_per_hour) = 0;
+
+ // Allow tests to override clock.
+ virtual base::Time Now() = 0;
+ };
+
+ public:
+ PowerUsageMonitor();
+ ~PowerUsageMonitor() override;
+
+ double discharge_amount() const {
+ return initial_battery_level_ - current_battery_level_;
+ }
+
+ // Start monitoring power usage.
+ // Note that the actual monitoring will be delayed until 30 minutes after
+ // system boot.
+ void Start();
+
+ void SetSystemInterfaceForTest(scoped_ptr<SystemInterface> interface);
+
+ // Overridden from base::PowerObserver:
+ void OnPowerStateChange(bool on_battery_power) override;
+ void OnResume() override;
+ void OnSuspend() override;
+
+ // Overridden from NotificationObserver:
+ void Observe(int type,
+ const NotificationSource& source,
+ const NotificationDetails& details) override;
+
+ private:
+ friend class PowerUsageMonitorTest;
+ FRIEND_TEST_ALL_PREFIXES(PowerUsageMonitorTest, OnBatteryStatusUpdate);
+ FRIEND_TEST_ALL_PREFIXES(PowerUsageMonitorTest, OnRenderProcessNotification);
+
+ // Start monitoring system power usage.
+ // This function may be called after a delay, see Start() for details.
+ void StartInternal();
+
+ void OnBatteryStatusUpdate(const device::BatteryStatus& status);
+ void OnRenderProcessNotification(int type, int rph_id);
+
+ void DischargeStarted(double battery_level);
+ void WallPowerConnected(double battery_level);
+
+ void CancelPendingHistogramReporting();
+
+ device::BatteryStatusService::BatteryUpdateCallback callback_;
+ scoped_ptr<device::BatteryStatusService::BatteryUpdateSubscription>
+ subscription_;
+
+ NotificationRegistrar registrar_;
+
+ scoped_ptr<SystemInterface> system_interface_;
+
+ // True if monitoring was started (Start() called).
+ bool started_;
+
+ // True if collecting metrics for the current discharge cycle e.g. if no
+ // renderers are open we don't keep track of discharge.
+ bool tracking_discharge_;
+
+ // True if the system is running on battery power, false if on wall power.
+ bool on_battery_power_;
+
+ // Battery level when wall power disconnected. [0.0, 1.0] - 0 if on wall
+ // power, 1 means fully charged.
+ double initial_battery_level_;
+
+ // Current battery level. [0.0, 1.0] - 0 if on wall power, 1 means fully
+ // charged.
+ double current_battery_level_;
+
+ // Timestamp when wall power was disconnected, null Time object otherwise.
+ base::Time start_discharge_time_;
+
+ // IDs of live renderer processes.
+ base::hash_set<int> live_renderer_ids_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PowerUsageMonitor);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_POWER_USAGE_MONITOR_IMPL_H_
diff --git a/chromium/content/browser/power_usage_monitor_impl_unittest.cc b/chromium/content/browser/power_usage_monitor_impl_unittest.cc
new file mode 100644
index 00000000000..efa46f2593a
--- /dev/null
+++ b/chromium/content/browser/power_usage_monitor_impl_unittest.cc
@@ -0,0 +1,167 @@
+// Copyright 2014 The Chromium Authors. 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/power_usage_monitor_impl.h"
+
+#include "content/public/browser/notification_types.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "device/battery/battery_monitor.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+// Dummy ID to identify a phantom RenderProcessHost in tests.
+const int kDummyRenderProcessHostID = 1;
+
+class SystemInterfaceForTest : public PowerUsageMonitor::SystemInterface {
+ public:
+ SystemInterfaceForTest()
+ : num_pending_histogram_reports_(0),
+ discharge_percent_per_hour_(0),
+ now_(base::Time::FromInternalValue(1000)) {}
+ ~SystemInterfaceForTest() override {}
+
+ int num_pending_histogram_reports() const {
+ return num_pending_histogram_reports_;
+ }
+
+ int discharge_percent_per_hour() const {
+ return discharge_percent_per_hour_;
+ }
+
+ void AdvanceClockSeconds(int seconds) {
+ now_ += base::TimeDelta::FromSeconds(seconds);
+ }
+
+ void AdvanceClockMinutes(int minutes) {
+ now_ += base::TimeDelta::FromMinutes(minutes);
+ }
+
+ void ScheduleHistogramReport(base::TimeDelta delay) override {
+ num_pending_histogram_reports_++;
+ }
+
+ void CancelPendingHistogramReports() override {
+ num_pending_histogram_reports_ = 0;
+ }
+
+ void RecordDischargePercentPerHour(int percent_per_hour) override {
+ discharge_percent_per_hour_ = percent_per_hour;
+ }
+
+ base::Time Now() override { return now_; }
+
+ private:
+ int num_pending_histogram_reports_;
+ int discharge_percent_per_hour_;
+ base::Time now_;
+};
+
+class PowerUsageMonitorTest : public testing::Test {
+ protected:
+ void SetUp() override {
+ monitor_.reset(new PowerUsageMonitor);
+ // PowerUsageMonitor assumes ownership.
+ scoped_ptr<SystemInterfaceForTest> test_interface(
+ new SystemInterfaceForTest());
+ system_interface_ = test_interface.get();
+ monitor_->SetSystemInterfaceForTest(test_interface.Pass());
+
+ // Without live renderers, the monitor won't do anything.
+ monitor_->OnRenderProcessNotification(NOTIFICATION_RENDERER_PROCESS_CREATED,
+ kDummyRenderProcessHostID);
+ }
+
+ void UpdateBatteryStatus(bool charging, double battery_level) {
+ device::BatteryStatus battery_status;
+ battery_status.charging = charging;
+ battery_status.level = battery_level;
+ monitor_->OnBatteryStatusUpdate(battery_status);
+ }
+
+ void KillTestRenderer() {
+ monitor_->OnRenderProcessNotification(
+ NOTIFICATION_RENDERER_PROCESS_CLOSED, kDummyRenderProcessHostID);
+ }
+
+ scoped_ptr<PowerUsageMonitor> monitor_;
+ SystemInterfaceForTest* system_interface_;
+ TestBrowserThreadBundle thread_bundle_;
+};
+
+TEST_F(PowerUsageMonitorTest, StartStopQuickly) {
+ // Going on battery power.
+ UpdateBatteryStatus(false, 1.0);
+ int initial_num_histogram_reports =
+ system_interface_->num_pending_histogram_reports();
+ ASSERT_GT(initial_num_histogram_reports, 0);
+
+ // Battery level goes down a bit.
+ system_interface_->AdvanceClockSeconds(1);
+ UpdateBatteryStatus(false, 0.9);
+ ASSERT_EQ(initial_num_histogram_reports,
+ system_interface_->num_pending_histogram_reports());
+ ASSERT_EQ(0, system_interface_->discharge_percent_per_hour());
+
+ // Wall power connected.
+ system_interface_->AdvanceClockSeconds(30);
+ UpdateBatteryStatus(true, 0);
+ ASSERT_EQ(0, system_interface_->num_pending_histogram_reports());
+ ASSERT_EQ(0, system_interface_->discharge_percent_per_hour());
+}
+
+TEST_F(PowerUsageMonitorTest, DischargePercentReported) {
+ // Going on battery power.
+ UpdateBatteryStatus(false, 1.0);
+ int initial_num_histogram_reports =
+ system_interface_->num_pending_histogram_reports();
+ ASSERT_GT(initial_num_histogram_reports, 0);
+
+ // Battery level goes down a bit.
+ system_interface_->AdvanceClockSeconds(30);
+ UpdateBatteryStatus(false, 0.9);
+ ASSERT_EQ(initial_num_histogram_reports,
+ system_interface_->num_pending_histogram_reports());
+ ASSERT_EQ(0, system_interface_->discharge_percent_per_hour());
+
+ // Wall power connected.
+ system_interface_->AdvanceClockMinutes(31);
+ UpdateBatteryStatus(true, 0);
+ ASSERT_EQ(0, system_interface_->num_pending_histogram_reports());
+ ASSERT_GT(system_interface_->discharge_percent_per_hour(), 0);
+}
+
+TEST_F(PowerUsageMonitorTest, NoRenderersDisablesMonitoring) {
+ KillTestRenderer();
+
+ // Going on battery power.
+ UpdateBatteryStatus(false, 1.0);
+ ASSERT_EQ(0, system_interface_->num_pending_histogram_reports());
+ ASSERT_EQ(0, system_interface_->discharge_percent_per_hour());
+
+ // Wall power connected.
+ system_interface_->AdvanceClockSeconds(30);
+ UpdateBatteryStatus(true, 0.5);
+ ASSERT_EQ(0, system_interface_->num_pending_histogram_reports());
+ ASSERT_EQ(0, system_interface_->discharge_percent_per_hour());
+}
+
+TEST_F(PowerUsageMonitorTest, NoRenderersCancelsInProgressMonitoring) {
+ // Going on battery power.
+ UpdateBatteryStatus(false, 1.0);
+ ASSERT_GT(system_interface_->num_pending_histogram_reports(), 0);
+ ASSERT_EQ(0, system_interface_->discharge_percent_per_hour());
+
+ // All renderers killed.
+ KillTestRenderer();
+ ASSERT_EQ(0, system_interface_->num_pending_histogram_reports());
+
+ // Wall power connected.
+ system_interface_->AdvanceClockMinutes(31);
+ UpdateBatteryStatus(true, 0);
+ ASSERT_EQ(0, system_interface_->num_pending_histogram_reports());
+ ASSERT_EQ(0, system_interface_->discharge_percent_per_hour());
+}
+
+} // namespace content
diff --git a/chromium/content/browser/ppapi_plugin_process_host.cc b/chromium/content/browser/ppapi_plugin_process_host.cc
index 22b69ba76d2..c59b70cbb94 100644
--- a/chromium/content/browser/ppapi_plugin_process_host.cc
+++ b/chromium/content/browser/ppapi_plugin_process_host.cc
@@ -51,12 +51,11 @@ class PpapiPluginSandboxedProcessLauncherDelegate
~PpapiPluginSandboxedProcessLauncherDelegate() override {}
#if defined(OS_WIN)
- virtual bool ShouldSandbox() override {
+ bool ShouldSandbox() override {
return !is_broker_;
}
- virtual void PreSpawnTarget(sandbox::TargetPolicy* policy,
- bool* success) {
+ void PreSpawnTarget(sandbox::TargetPolicy* policy, bool* success) override {
if (is_broker_)
return;
// The Pepper process as locked-down as a renderer execpt that it can
@@ -74,7 +73,7 @@ class PpapiPluginSandboxedProcessLauncherDelegate
*base::CommandLine::ForCurrentProcess();
base::CommandLine::StringType plugin_launcher = browser_command_line
.GetSwitchValueNative(switches::kPpapiPluginLauncher);
- return !is_broker_ && plugin_launcher.empty() && info_.is_sandboxed;
+ return !is_broker_ && plugin_launcher.empty();
}
base::ScopedFD TakeIpcFd() override { return ipc_fd_.Pass(); }
#endif // OS_WIN
@@ -199,6 +198,24 @@ void PpapiPluginProcessHost::DidDeleteOutOfProcessInstance(
}
// static
+void PpapiPluginProcessHost::OnPluginInstanceThrottleStateChange(
+ int plugin_process_id,
+ int32 pp_instance,
+ bool is_throttled) {
+ for (PpapiPluginProcessHostIterator iter; !iter.Done(); ++iter) {
+ if (iter->process_.get() &&
+ iter->process_->GetData().id == plugin_process_id) {
+ // Found the plugin.
+ iter->host_impl_->OnThrottleStateChanged(pp_instance, is_throttled);
+ return;
+ }
+ }
+ // Note: It's possible that the plugin process has already been deleted by
+ // the time this message is received. For example, it could have crashed.
+ // That's OK, we can just ignore this message.
+}
+
+// static
void PpapiPluginProcessHost::FindByName(
const base::string16& name,
std::vector<PpapiPluginProcessHost*>* hosts) {
@@ -341,6 +358,10 @@ bool PpapiPluginProcessHost::Init(const PepperPluginInfo& info) {
if (!existing_args.empty())
existing_args.append(",");
existing_args.append("enable_hw_video_decode=1");
+#if defined(OS_MACOSX)
+ // TODO(ihf): Remove this once Flash newer than 15.0.0.223 is released.
+ existing_args.append(",enable_hw_video_decode_mac=1");
+#endif
}
cmd_line->AppendSwitchASCII(switches::kPpapiFlashArgs, existing_args);
}
@@ -355,18 +376,14 @@ bool PpapiPluginProcessHost::Init(const PepperPluginInfo& info) {
cmd_line->PrependWrapper(plugin_launcher);
// On posix, never use the zygote for the broker. Also, only use the zygote if
- // the plugin is sandboxed, and we are not using a plugin launcher - having a
- // plugin launcher means we need to use another process instead of just
- // forking the zygote.
-#if defined(OS_POSIX)
- if (!info.is_sandboxed)
- cmd_line->AppendSwitchASCII(switches::kNoSandbox, std::string());
-#endif // OS_POSIX
+ // we are not using a plugin launcher - having a plugin launcher means we need
+ // to use another process instead of just forking the zygote.
process_->Launch(
new PpapiPluginSandboxedProcessLauncherDelegate(is_broker_,
info,
process_->GetHost()),
- cmd_line);
+ cmd_line,
+ true);
return true;
}
@@ -392,7 +409,7 @@ void PpapiPluginProcessHost::RequestPluginChannel(Client* client) {
void PpapiPluginProcessHost::OnProcessLaunched() {
VLOG(2) << "ppapi plugin process launched.";
- host_impl_->set_plugin_process_handle(process_->GetHandle());
+ host_impl_->set_plugin_process(process_->GetProcess().Duplicate());
}
void PpapiPluginProcessHost::OnProcessCrashed(int exit_code) {
diff --git a/chromium/content/browser/ppapi_plugin_process_host.h b/chromium/content/browser/ppapi_plugin_process_host.h
index 3f90d3025dc..e4c58a9b33b 100644
--- a/chromium/content/browser/ppapi_plugin_process_host.h
+++ b/chromium/content/browser/ppapi_plugin_process_host.h
@@ -90,6 +90,11 @@ class PpapiPluginProcessHost : public BrowserChildProcessHostDelegate,
static void DidDeleteOutOfProcessInstance(int plugin_process_id,
int32 pp_instance);
+ // Notification that a Plugin instance has been throttled or unthrottled.
+ static void OnPluginInstanceThrottleStateChange(int plugin_process_id,
+ int32 pp_instance,
+ bool is_throttled);
+
// Returns the instances that match the specified process name.
// It can only be called on the IO thread.
static void FindByName(const base::string16& name,
diff --git a/chromium/content/browser/presentation/OWNERS b/chromium/content/browser/presentation/OWNERS
new file mode 100644
index 00000000000..44b349ce215
--- /dev/null
+++ b/chromium/content/browser/presentation/OWNERS
@@ -0,0 +1,3 @@
+avayvod@chromium.org
+imcheng@chromium.org
+mfoltz@chromium.org \ No newline at end of file
diff --git a/chromium/content/browser/presentation/presentation_service_impl.cc b/chromium/content/browser/presentation/presentation_service_impl.cc
new file mode 100644
index 00000000000..916ddedd356
--- /dev/null
+++ b/chromium/content/browser/presentation/presentation_service_impl.cc
@@ -0,0 +1,674 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/presentation/presentation_service_impl.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "content/browser/presentation/presentation_type_converters.h"
+#include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/navigation_details.h"
+#include "content/public/browser/presentation_session_message.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/content_client.h"
+#include "content/public/common/frame_navigate_params.h"
+#include "content/public/common/presentation_constants.h"
+
+namespace content {
+
+namespace {
+
+const int kInvalidRequestSessionId = -1;
+
+int GetNextRequestSessionId() {
+ static int next_request_session_id = 0;
+ return ++next_request_session_id;
+}
+
+// The return value takes ownership of the contents of |input|.
+presentation::SessionMessagePtr ToMojoSessionMessage(
+ content::PresentationSessionMessage* input) {
+ presentation::SessionMessagePtr output(presentation::SessionMessage::New());
+ output->presentation_url.Swap(&input->presentation_url);
+ output->presentation_id.Swap(&input->presentation_id);
+ if (input->is_binary()) {
+ // binary data
+ output->type = presentation::PresentationMessageType::
+ PRESENTATION_MESSAGE_TYPE_ARRAY_BUFFER;
+ output->data.Swap(input->data.get());
+ } else {
+ // string message
+ output->type =
+ presentation::PresentationMessageType::PRESENTATION_MESSAGE_TYPE_TEXT;
+ output->message.Swap(input->message.get());
+ }
+ return output.Pass();
+}
+
+scoped_ptr<content::PresentationSessionMessage> GetPresentationSessionMessage(
+ presentation::SessionMessagePtr input) {
+ DCHECK(!input.is_null());
+ scoped_ptr<content::PresentationSessionMessage> output;
+ if (input->type == presentation::PresentationMessageType::
+ PRESENTATION_MESSAGE_TYPE_TEXT) {
+ DCHECK(!input->message.is_null());
+ DCHECK(input->data.is_null());
+ // Return null PresentationSessionMessage if size exceeds.
+ if (input->message.size() > content::kMaxPresentationSessionMessageSize)
+ return output.Pass();
+
+ output = content::PresentationSessionMessage::CreateStringMessage(
+ input->presentation_url,
+ input->presentation_id,
+ make_scoped_ptr(new std::string));
+ input->message.Swap(output->message.get());
+
+ } else if (input->type == presentation::PresentationMessageType::
+ PRESENTATION_MESSAGE_TYPE_ARRAY_BUFFER) {
+ DCHECK(!input->data.is_null());
+ DCHECK(input->message.is_null());
+ // Return null PresentationSessionMessage if size exceeds.
+ if (input->data.size() > content::kMaxPresentationSessionMessageSize)
+ return output.Pass();
+
+ output = content::PresentationSessionMessage::CreateBinaryMessage(
+ input->presentation_url,
+ input->presentation_id,
+ make_scoped_ptr(new std::vector<uint8_t>));
+ input->data.Swap(output->data.get());
+ }
+
+ return output.Pass();
+}
+
+void InvokeNewSessionMojoCallbackWithError(
+ const NewSessionMojoCallback& callback) {
+ callback.Run(
+ presentation::PresentationSessionInfoPtr(),
+ presentation::PresentationError::From(
+ PresentationError(PRESENTATION_ERROR_UNKNOWN, "Internal error")));
+}
+
+} // namespace
+
+PresentationServiceImpl::PresentationServiceImpl(
+ RenderFrameHost* render_frame_host,
+ WebContents* web_contents,
+ PresentationServiceDelegate* delegate)
+ : WebContentsObserver(web_contents),
+ delegate_(delegate),
+ start_session_request_id_(kInvalidRequestSessionId),
+ weak_factory_(this) {
+ DCHECK(render_frame_host);
+ DCHECK(web_contents);
+
+ render_process_id_ = render_frame_host->GetProcess()->GetID();
+ render_frame_id_ = render_frame_host->GetRoutingID();
+ DVLOG(2) << "PresentationServiceImpl: "
+ << render_process_id_ << ", " << render_frame_id_;
+ if (delegate_)
+ delegate_->AddObserver(render_process_id_, render_frame_id_, this);
+}
+
+PresentationServiceImpl::~PresentationServiceImpl() {
+ if (delegate_)
+ delegate_->RemoveObserver(render_process_id_, render_frame_id_);
+}
+
+// static
+void PresentationServiceImpl::CreateMojoService(
+ RenderFrameHost* render_frame_host,
+ mojo::InterfaceRequest<presentation::PresentationService> request) {
+ DVLOG(2) << "CreateMojoService";
+ WebContents* web_contents =
+ WebContents::FromRenderFrameHost(render_frame_host);
+ DCHECK(web_contents);
+
+ // This object will be deleted when the RenderFrameHost is about to be
+ // deleted (RenderFrameDeleted) or if a connection error occurred
+ // (OnConnectionError).
+ PresentationServiceImpl* impl = new PresentationServiceImpl(
+ render_frame_host,
+ web_contents,
+ GetContentClient()->browser()->GetPresentationServiceDelegate(
+ web_contents));
+ impl->Bind(request.Pass());
+}
+
+void PresentationServiceImpl::Bind(
+ mojo::InterfaceRequest<presentation::PresentationService> request) {
+ binding_.reset(new mojo::Binding<presentation::PresentationService>(
+ this, request.Pass()));
+ binding_->set_error_handler(this);
+}
+
+void PresentationServiceImpl::OnConnectionError() {
+ DVLOG(1) << "OnConnectionError";
+ delete this;
+}
+
+void PresentationServiceImpl::SetClient(
+ presentation::PresentationServiceClientPtr client) {
+ DCHECK(!client_.get());
+ // TODO(imcheng): Set ErrorHandler to listen for errors.
+ client_ = client.Pass();
+}
+
+void PresentationServiceImpl::ListenForScreenAvailability() {
+ DVLOG(2) << "ListenForScreenAvailability";
+ if (!delegate_)
+ return;
+
+ if (screen_availability_listener_.get() &&
+ screen_availability_listener_->GetPresentationUrl() ==
+ default_presentation_url_) {
+ return;
+ }
+
+ ResetScreenAvailabilityListener(default_presentation_url_);
+}
+
+void PresentationServiceImpl::ResetScreenAvailabilityListener(
+ const std::string& presentation_url) {
+ DCHECK(delegate_);
+ DCHECK(!screen_availability_listener_.get() ||
+ presentation_url != default_presentation_url_);
+
+ // (1) Unregister old listener with delegate
+ StopListeningForScreenAvailability();
+
+ // (2) Replace old listener with new listener
+ screen_availability_listener_.reset(new ScreenAvailabilityListenerImpl(
+ presentation_url, this));
+
+ // (3) Register new listener with delegate
+ if (!delegate_->AddScreenAvailabilityListener(
+ render_process_id_,
+ render_frame_id_,
+ screen_availability_listener_.get())) {
+ DVLOG(1) << "AddScreenAvailabilityListener failed. Ignoring request.";
+ screen_availability_listener_.reset();
+ }
+}
+
+void PresentationServiceImpl::StopListeningForScreenAvailability() {
+ DVLOG(2) << "StopListeningForScreenAvailability";
+ if (!delegate_)
+ return;
+
+ if (screen_availability_listener_.get()) {
+ delegate_->RemoveScreenAvailabilityListener(
+ render_process_id_,
+ render_frame_id_,
+ screen_availability_listener_.get());
+ screen_availability_listener_.reset();
+ }
+}
+
+void PresentationServiceImpl::ListenForDefaultSessionStart(
+ const DefaultSessionMojoCallback& callback) {
+ if (!default_session_start_context_.get())
+ default_session_start_context_.reset(new DefaultSessionStartContext);
+ default_session_start_context_->AddCallback(callback);
+}
+
+void PresentationServiceImpl::StartSession(
+ const mojo::String& presentation_url,
+ const mojo::String& presentation_id,
+ const NewSessionMojoCallback& callback) {
+ DVLOG(2) << "StartSession";
+ if (!delegate_) {
+ InvokeNewSessionMojoCallbackWithError(callback);
+ return;
+ }
+
+ // Currently not processing a request, so no need for queueing.
+ if (start_session_request_id_ == kInvalidRequestSessionId) {
+ DoStartSession(make_scoped_ptr(new StartSessionRequest(
+ presentation_url, presentation_id, callback)));
+ return;
+ }
+
+ if (queued_start_session_requests_.size() >= kMaxNumQueuedSessionRequests) {
+ InvokeNewSessionMojoCallbackWithError(callback);
+ return;
+ }
+
+ queued_start_session_requests_.push_back(
+ make_linked_ptr(new StartSessionRequest(
+ presentation_url, presentation_id, callback)));
+}
+
+void PresentationServiceImpl::JoinSession(
+ const mojo::String& presentation_url,
+ const mojo::String& presentation_id,
+ const NewSessionMojoCallback& callback) {
+ DVLOG(2) << "JoinSession";
+ if (!delegate_) {
+ InvokeNewSessionMojoCallbackWithError(callback);
+ return;
+ }
+
+ int request_session_id = RegisterJoinSessionCallback(callback);
+ if (request_session_id == kInvalidRequestSessionId) {
+ InvokeNewSessionMojoCallbackWithError(callback);
+ return;
+ }
+ delegate_->JoinSession(
+ render_process_id_,
+ render_frame_id_,
+ presentation_url,
+ presentation_id,
+ base::Bind(&PresentationServiceImpl::OnJoinSessionSucceeded,
+ weak_factory_.GetWeakPtr(), request_session_id),
+ base::Bind(&PresentationServiceImpl::OnJoinSessionError,
+ weak_factory_.GetWeakPtr(), request_session_id));
+}
+
+void PresentationServiceImpl::HandleQueuedStartSessionRequests() {
+ if (queued_start_session_requests_.empty())
+ return;
+
+ linked_ptr<StartSessionRequest> request =
+ queued_start_session_requests_.front();
+ queued_start_session_requests_.pop_front();
+ DoStartSession(make_scoped_ptr(request.release()));
+}
+
+int PresentationServiceImpl::RegisterJoinSessionCallback(
+ const NewSessionMojoCallback& callback) {
+ if (pending_join_session_cbs_.size() >= kMaxNumQueuedSessionRequests)
+ return kInvalidRequestSessionId;
+
+ int request_id = GetNextRequestSessionId();
+ pending_join_session_cbs_[request_id].reset(
+ new NewSessionMojoCallbackWrapper(callback));
+ return request_id;
+}
+
+void PresentationServiceImpl::DoStartSession(
+ scoped_ptr<StartSessionRequest> request) {
+ DCHECK_EQ(kInvalidRequestSessionId, start_session_request_id_);
+ DCHECK(!pending_start_session_cb_.get());
+
+ int request_session_id = GetNextRequestSessionId();
+ start_session_request_id_ = request_session_id;
+ pending_start_session_cb_ = request->PassCallback();
+
+ delegate_->StartSession(
+ render_process_id_,
+ render_frame_id_,
+ request->presentation_url(),
+ request->presentation_id(),
+ base::Bind(&PresentationServiceImpl::OnStartSessionSucceeded,
+ weak_factory_.GetWeakPtr(), request_session_id),
+ base::Bind(&PresentationServiceImpl::OnStartSessionError,
+ weak_factory_.GetWeakPtr(), request_session_id));
+}
+
+void PresentationServiceImpl::OnStartSessionSucceeded(
+ int request_session_id,
+ const PresentationSessionInfo& session_info) {
+ if (request_session_id == start_session_request_id_) {
+ CHECK(pending_start_session_cb_.get());
+ pending_start_session_cb_->Run(
+ presentation::PresentationSessionInfo::From(session_info),
+ presentation::PresentationErrorPtr());
+ pending_start_session_cb_.reset();
+ start_session_request_id_ = kInvalidRequestSessionId;
+ HandleQueuedStartSessionRequests();
+ }
+}
+
+void PresentationServiceImpl::OnStartSessionError(
+ int request_session_id,
+ const PresentationError& error) {
+ if (request_session_id == start_session_request_id_) {
+ CHECK(pending_start_session_cb_.get());
+ pending_start_session_cb_->Run(
+ presentation::PresentationSessionInfoPtr(),
+ presentation::PresentationError::From(error));
+ pending_start_session_cb_.reset();
+ start_session_request_id_ = kInvalidRequestSessionId;
+ HandleQueuedStartSessionRequests();
+ }
+}
+
+void PresentationServiceImpl::OnJoinSessionSucceeded(
+ int request_session_id,
+ const PresentationSessionInfo& session_info) {
+ RunAndEraseJoinSessionMojoCallback(
+ request_session_id,
+ presentation::PresentationSessionInfo::From(session_info),
+ presentation::PresentationErrorPtr());
+}
+
+void PresentationServiceImpl::OnJoinSessionError(
+ int request_session_id,
+ const PresentationError& error) {
+ RunAndEraseJoinSessionMojoCallback(
+ request_session_id,
+ presentation::PresentationSessionInfoPtr(),
+ presentation::PresentationError::From(error));
+}
+
+void PresentationServiceImpl::RunAndEraseJoinSessionMojoCallback(
+ int request_session_id,
+ presentation::PresentationSessionInfoPtr session,
+ presentation::PresentationErrorPtr error) {
+ auto it = pending_join_session_cbs_.find(request_session_id);
+ if (it == pending_join_session_cbs_.end())
+ return;
+
+ DCHECK(it->second.get());
+ it->second->Run(session.Pass(), error.Pass());
+ pending_join_session_cbs_.erase(it);
+}
+
+void PresentationServiceImpl::SetDefaultPresentationURL(
+ const mojo::String& default_presentation_url,
+ const mojo::String& default_presentation_id) {
+ DVLOG(2) << "SetDefaultPresentationURL";
+ if (!delegate_)
+ return;
+
+ const std::string& old_default_url = default_presentation_url_;
+ const std::string& new_default_url = default_presentation_url.get();
+
+ // Don't call delegate if nothing changed.
+ if (old_default_url == new_default_url &&
+ default_presentation_id_ == default_presentation_id) {
+ return;
+ }
+
+ if (old_default_url != new_default_url) {
+ // If DPU changed, replace screen availability listeners if any.
+ if (screen_availability_listener_.get())
+ ResetScreenAvailabilityListener(new_default_url);
+ }
+
+ delegate_->SetDefaultPresentationUrl(
+ render_process_id_,
+ render_frame_id_,
+ default_presentation_url,
+ default_presentation_id);
+ default_presentation_url_ = default_presentation_url;
+ default_presentation_id_ = default_presentation_id;
+}
+
+
+void PresentationServiceImpl::SendSessionMessage(
+ presentation::SessionMessagePtr session_message,
+ const SendMessageMojoCallback& callback) {
+ DVLOG(2) << "SendSessionMessage";
+ DCHECK(!session_message.is_null());
+ // send_message_callback_ should be null by now, otherwise resetting of
+ // send_message_callback_ with new callback will drop the old callback.
+ if (!delegate_ || send_message_callback_) {
+ callback.Run(false);
+ return;
+ }
+
+ send_message_callback_.reset(new SendMessageMojoCallback(callback));
+ delegate_->SendMessage(
+ render_process_id_,
+ render_frame_id_,
+ GetPresentationSessionMessage(session_message.Pass()),
+ base::Bind(&PresentationServiceImpl::OnSendMessageCallback,
+ weak_factory_.GetWeakPtr()));
+}
+
+void PresentationServiceImpl::OnSendMessageCallback() {
+ // It is possible that Reset() is invoked before receiving this callback.
+ // So, always check send_message_callback_ for non-null.
+ if (send_message_callback_) {
+ send_message_callback_->Run(true);
+ send_message_callback_.reset();
+ }
+}
+
+void PresentationServiceImpl::CloseSession(
+ const mojo::String& presentation_url,
+ const mojo::String& presentation_id) {
+ NOTIMPLEMENTED();
+}
+
+void PresentationServiceImpl::ListenForSessionStateChange(
+ const SessionStateCallback& callback) {
+ NOTIMPLEMENTED();
+}
+
+bool PresentationServiceImpl::FrameMatches(
+ content::RenderFrameHost* render_frame_host) const {
+ if (!render_frame_host)
+ return false;
+
+ return render_frame_host->GetProcess()->GetID() == render_process_id_ &&
+ render_frame_host->GetRoutingID() == render_frame_id_;
+}
+
+void PresentationServiceImpl::ListenForSessionMessages(
+ const SessionMessagesCallback& callback) {
+ DVLOG(2) << "ListenForSessionMessages";
+ if (!delegate_) {
+ callback.Run(mojo::Array<presentation::SessionMessagePtr>());
+ return;
+ }
+
+ // Crash early if renderer is misbehaving.
+ CHECK(!on_session_messages_callback_.get());
+
+ on_session_messages_callback_.reset(new SessionMessagesCallback(callback));
+ delegate_->ListenForSessionMessages(
+ render_process_id_, render_frame_id_,
+ base::Bind(&PresentationServiceImpl::OnSessionMessages,
+ weak_factory_.GetWeakPtr()));
+}
+
+void PresentationServiceImpl::OnSessionMessages(
+ scoped_ptr<ScopedVector<PresentationSessionMessage>> messages) {
+ DCHECK(messages.get() && !messages->empty());
+ if (!on_session_messages_callback_.get()) {
+ // The Reset method of this class was invoked.
+ return;
+ }
+
+ mojo::Array<presentation::SessionMessagePtr> mojoMessages(messages->size());
+ for (size_t i = 0; i < messages->size(); ++i) {
+ mojoMessages[i] = ToMojoSessionMessage((*messages)[i]);
+ }
+
+ on_session_messages_callback_->Run(mojoMessages.Pass());
+ on_session_messages_callback_.reset();
+}
+
+void PresentationServiceImpl::DidNavigateAnyFrame(
+ content::RenderFrameHost* render_frame_host,
+ const content::LoadCommittedDetails& details,
+ const content::FrameNavigateParams& params) {
+ DVLOG(2) << "PresentationServiceImpl::DidNavigateAnyFrame";
+ if (!FrameMatches(render_frame_host))
+ return;
+
+ std::string prev_url_host = details.previous_url.host();
+ std::string curr_url_host = params.url.host();
+
+ // If a frame navigation is in-page (e.g. navigating to a fragment in
+ // same page) then we do not unregister listeners.
+ bool in_page_navigation = details.is_in_page ||
+ details.type == content::NAVIGATION_TYPE_IN_PAGE;
+
+ DVLOG(2) << "DidNavigateAnyFrame: "
+ << "prev host: " << prev_url_host << ", curr host: " << curr_url_host
+ << ", in_page_navigation: " << in_page_navigation;
+
+ if (in_page_navigation)
+ return;
+
+ // Reset if the frame actually navigated.
+ Reset();
+}
+
+void PresentationServiceImpl::RenderFrameDeleted(
+ content::RenderFrameHost* render_frame_host) {
+ DVLOG(2) << "PresentationServiceImpl::RenderFrameDeleted";
+ if (!FrameMatches(render_frame_host))
+ return;
+
+ // RenderFrameDeleted means the associated RFH is going to be deleted soon.
+ // This object should also be deleted.
+ Reset();
+ delete this;
+}
+
+void PresentationServiceImpl::Reset() {
+ DVLOG(2) << "PresentationServiceImpl::Reset";
+ if (delegate_)
+ delegate_->Reset(render_process_id_, render_frame_id_);
+
+ default_presentation_url_.clear();
+ default_presentation_id_.clear();
+
+ screen_availability_listener_.reset();
+
+ queued_start_session_requests_.clear();
+ start_session_request_id_ = kInvalidRequestSessionId;
+ pending_start_session_cb_.reset();
+
+ pending_join_session_cbs_.clear();
+
+ default_session_start_context_.reset();
+
+ if (on_session_messages_callback_.get()) {
+ on_session_messages_callback_->Run(
+ mojo::Array<presentation::SessionMessagePtr>());
+ on_session_messages_callback_.reset();
+ }
+
+ if (send_message_callback_) {
+ // Run the callback with false, indicating the renderer to stop sending
+ // the requests and invalidate all pending requests.
+ send_message_callback_->Run(false);
+ send_message_callback_.reset();
+ }
+}
+
+void PresentationServiceImpl::OnDelegateDestroyed() {
+ DVLOG(2) << "PresentationServiceImpl::OnDelegateDestroyed";
+ delegate_ = nullptr;
+ Reset();
+}
+
+void PresentationServiceImpl::OnDefaultPresentationStarted(
+ const PresentationSessionInfo& session) {
+ if (default_session_start_context_.get())
+ default_session_start_context_->set_session(session);
+}
+
+PresentationServiceImpl::ScreenAvailabilityListenerImpl
+::ScreenAvailabilityListenerImpl(
+ const std::string& presentation_url,
+ PresentationServiceImpl* service)
+ : presentation_url_(presentation_url),
+ service_(service) {
+ DCHECK(service_);
+ DCHECK(service_->client_.get());
+}
+
+PresentationServiceImpl::ScreenAvailabilityListenerImpl::
+~ScreenAvailabilityListenerImpl() {
+}
+
+std::string PresentationServiceImpl::ScreenAvailabilityListenerImpl
+ ::GetPresentationUrl() const {
+ return presentation_url_;
+}
+
+void PresentationServiceImpl::ScreenAvailabilityListenerImpl
+ ::OnScreenAvailabilityChanged(bool available) {
+ service_->client_->OnScreenAvailabilityUpdated(available);
+}
+
+PresentationServiceImpl::NewSessionMojoCallbackWrapper
+::NewSessionMojoCallbackWrapper(const NewSessionMojoCallback& callback)
+ : callback_(callback) {
+}
+
+PresentationServiceImpl::NewSessionMojoCallbackWrapper
+::~NewSessionMojoCallbackWrapper() {
+ if (!callback_.is_null())
+ InvokeNewSessionMojoCallbackWithError(callback_);
+}
+
+void PresentationServiceImpl::NewSessionMojoCallbackWrapper::Run(
+ presentation::PresentationSessionInfoPtr session,
+ presentation::PresentationErrorPtr error) {
+ DCHECK(!callback_.is_null());
+ callback_.Run(session.Pass(), error.Pass());
+ callback_.reset();
+}
+
+PresentationServiceImpl::StartSessionRequest::StartSessionRequest(
+ const std::string& presentation_url,
+ const std::string& presentation_id,
+ const NewSessionMojoCallback& callback)
+ : presentation_url_(presentation_url),
+ presentation_id_(presentation_id),
+ callback_wrapper_(new NewSessionMojoCallbackWrapper(callback)) {
+}
+
+PresentationServiceImpl::StartSessionRequest::~StartSessionRequest() {
+}
+
+scoped_ptr<PresentationServiceImpl::NewSessionMojoCallbackWrapper>
+PresentationServiceImpl::StartSessionRequest::PassCallback() {
+ return callback_wrapper_.Pass();
+}
+
+PresentationServiceImpl::DefaultSessionStartContext
+::DefaultSessionStartContext() {
+}
+
+PresentationServiceImpl::DefaultSessionStartContext
+::~DefaultSessionStartContext() {
+ Reset();
+}
+
+void PresentationServiceImpl::DefaultSessionStartContext::AddCallback(
+ const DefaultSessionMojoCallback& callback) {
+ if (session_.get()) {
+ DCHECK(callbacks_.empty());
+ callback.Run(presentation::PresentationSessionInfo::From(*session_));
+ session_.reset();
+ } else {
+ callbacks_.push_back(new DefaultSessionMojoCallback(callback));
+ }
+}
+
+void PresentationServiceImpl::DefaultSessionStartContext::set_session(
+ const PresentationSessionInfo& session) {
+ if (callbacks_.empty()) {
+ session_.reset(new PresentationSessionInfo(session));
+ } else {
+ DCHECK(!session_.get());
+ ScopedVector<DefaultSessionMojoCallback> callbacks;
+ callbacks.swap(callbacks_);
+ for (const auto& callback : callbacks)
+ callback->Run(presentation::PresentationSessionInfo::From(session));
+ }
+}
+
+void PresentationServiceImpl::DefaultSessionStartContext::Reset() {
+ ScopedVector<DefaultSessionMojoCallback> callbacks;
+ callbacks.swap(callbacks_);
+ for (const auto& callback : callbacks)
+ callback->Run(presentation::PresentationSessionInfoPtr());
+ session_.reset();
+}
+
+} // namespace content
+
diff --git a/chromium/content/browser/presentation/presentation_service_impl.h b/chromium/content/browser/presentation/presentation_service_impl.h
new file mode 100644
index 00000000000..9d4f5a12dce
--- /dev/null
+++ b/chromium/content/browser/presentation/presentation_service_impl.h
@@ -0,0 +1,346 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_PRESENTATION_PRESENTATION_SERVICE_IMPL_H_
+#define CONTENT_BROWSER_PRESENTATION_PRESENTATION_SERVICE_IMPL_H_
+
+#include <deque>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/containers/hash_tables.h"
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "base/memory/linked_ptr.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/memory/weak_ptr.h"
+#include "content/common/content_export.h"
+#include "content/common/presentation/presentation_service.mojom.h"
+#include "content/public/browser/navigation_details.h"
+#include "content/public/browser/presentation_screen_availability_listener.h"
+#include "content/public/browser/presentation_service_delegate.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/common/frame_navigate_params.h"
+
+namespace content {
+
+struct FrameNavigateParams;
+struct LoadCommittedDetails;
+struct PresentationSessionMessage;
+class RenderFrameHost;
+
+using NewSessionMojoCallback = mojo::Callback<
+ void(presentation::PresentationSessionInfoPtr,
+ presentation::PresentationErrorPtr)>;
+
+// Implementation of Mojo PresentationService.
+// It handles Presentation API requests coming from Blink / renderer process
+// and delegates the requests to the embedder's media router via
+// PresentationServiceDelegate.
+// An instance of this class tied to a RenderFrameHost and listens to events
+// related to the RFH via implementing WebContentsObserver.
+// This class is instantiated on-demand via Mojo's ConnectToRemoteService
+// from the renderer when the first presentation API request is handled.
+class CONTENT_EXPORT PresentationServiceImpl
+ : public NON_EXPORTED_BASE(presentation::PresentationService),
+ public mojo::ErrorHandler,
+ public WebContentsObserver,
+ public PresentationServiceDelegate::Observer {
+ public:
+ ~PresentationServiceImpl() override;
+
+ // Static factory method to create an instance of PresentationServiceImpl.
+ // |render_frame_host|: The RFH the instance is associated with.
+ // |request|: The instance will be bound to this request. Used for Mojo setup.
+ static void CreateMojoService(
+ RenderFrameHost* render_frame_host,
+ mojo::InterfaceRequest<presentation::PresentationService> request);
+
+ private:
+ friend class PresentationServiceImplTest;
+ FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, Reset);
+ FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, DidNavigateThisFrame);
+ FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
+ DidNavigateOtherFrame);
+ FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, ThisRenderFrameDeleted);
+ FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
+ OtherRenderFrameDeleted);
+ FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, DelegateFails);
+ FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
+ SetDefaultPresentationUrl);
+ FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
+ SetSameDefaultPresentationUrl);
+ FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
+ ClearDefaultPresentationUrl);
+ FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
+ ListenForDefaultSessionStart);
+ FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
+ ListenForDefaultSessionStartAfterSet);
+ FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
+ DefaultSessionStartReset);
+ FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
+ ReceiveSessionMessagesAfterReset);
+ FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
+ MaxPendingStartSessionRequests);
+ FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
+ MaxPendingJoinSessionRequests);
+
+ // Maximum number of queued StartSession or JoinSession requests.
+ static const int kMaxNumQueuedSessionRequests = 10;
+
+ using DefaultSessionMojoCallback =
+ mojo::Callback<void(presentation::PresentationSessionInfoPtr)>;
+ using SessionStateCallback =
+ mojo::Callback<void(presentation::PresentationSessionInfoPtr,
+ presentation::PresentationSessionState)>;
+ using SessionMessagesCallback =
+ mojo::Callback<void(mojo::Array<presentation::SessionMessagePtr>)>;
+ using SendMessageMojoCallback = mojo::Callback<void(bool)>;
+
+ // Listener implementation owned by PresentationServiceImpl. An instance of
+ // this is created when an |onavailablechange| handler is added.
+ // The instance receives screen availability results from the embedder and
+ // propagates results back to PresentationServiceImpl.
+ class CONTENT_EXPORT ScreenAvailabilityListenerImpl
+ : public PresentationScreenAvailabilityListener {
+ public:
+ ScreenAvailabilityListenerImpl(
+ const std::string& presentation_url,
+ PresentationServiceImpl* service);
+ ~ScreenAvailabilityListenerImpl() override;
+
+ // PresentationScreenAvailabilityListener implementation.
+ std::string GetPresentationUrl() const override;
+ void OnScreenAvailabilityChanged(bool available) override;
+
+ private:
+ const std::string presentation_url_;
+ PresentationServiceImpl* const service_;
+ };
+
+ class CONTENT_EXPORT DefaultSessionStartContext {
+ public:
+ DefaultSessionStartContext();
+ ~DefaultSessionStartContext();
+
+ // Adds a callback. May invoke the callback immediately if |session| using
+ // default presentation URL was already started.
+ void AddCallback(const DefaultSessionMojoCallback& callback);
+
+ // Sets the session info. Maybe invoke callbacks queued with AddCallback().
+ void set_session(const PresentationSessionInfo& session);
+
+ private:
+ // Flush all queued callbacks by invoking them with null
+ // PresentationSessionInfoPtr.
+ void Reset();
+
+ ScopedVector<DefaultSessionMojoCallback> callbacks_;
+ scoped_ptr<PresentationSessionInfo> session_;
+ };
+
+ // Ensures the provided NewSessionMojoCallback is invoked exactly once
+ // before it goes out of scope.
+ class NewSessionMojoCallbackWrapper {
+ public:
+ explicit NewSessionMojoCallbackWrapper(
+ const NewSessionMojoCallback& callback);
+ ~NewSessionMojoCallbackWrapper();
+
+ void Run(presentation::PresentationSessionInfoPtr session,
+ presentation::PresentationErrorPtr error);
+
+ private:
+ NewSessionMojoCallback callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(NewSessionMojoCallbackWrapper);
+ };
+
+ // Context for a queued StartSession request.
+ class CONTENT_EXPORT StartSessionRequest {
+ public:
+ StartSessionRequest(const std::string& presentation_url,
+ const std::string& presentation_id,
+ const NewSessionMojoCallback& callback);
+ ~StartSessionRequest();
+
+ scoped_ptr<NewSessionMojoCallbackWrapper> PassCallback();
+
+ const std::string& presentation_url() const { return presentation_url_; }
+ const std::string& presentation_id() const { return presentation_id_; }
+
+ private:
+ const std::string presentation_url_;
+ const std::string presentation_id_;
+ scoped_ptr<NewSessionMojoCallbackWrapper> callback_wrapper_;
+
+ DISALLOW_COPY_AND_ASSIGN(StartSessionRequest);
+ };
+
+ // |render_frame_host|: The RFH this instance is associated with.
+ // |web_contents|: The WebContents to observe.
+ // |delegate|: Where Presentation API requests are delegated to. Not owned
+ // by this class.
+ PresentationServiceImpl(
+ RenderFrameHost* render_frame_host,
+ WebContents* web_contents,
+ PresentationServiceDelegate* delegate);
+
+ // PresentationService implementation.
+ void SetDefaultPresentationURL(
+ const mojo::String& presentation_url,
+ const mojo::String& presentation_id) override;
+ void SetClient(presentation::PresentationServiceClientPtr client) override;
+ void ListenForScreenAvailability() override;
+ void StopListeningForScreenAvailability() override;
+ void ListenForDefaultSessionStart(
+ const DefaultSessionMojoCallback& callback) override;
+ void StartSession(
+ const mojo::String& presentation_url,
+ const mojo::String& presentation_id,
+ const NewSessionMojoCallback& callback) override;
+ void JoinSession(
+ const mojo::String& presentation_url,
+ const mojo::String& presentation_id,
+ const NewSessionMojoCallback& callback) override;
+ void SendSessionMessage(
+ presentation::SessionMessagePtr session_message,
+ const SendMessageMojoCallback& callback) override;
+ void CloseSession(
+ const mojo::String& presentation_url,
+ const mojo::String& presentation_id) override;
+ void ListenForSessionStateChange(
+ const SessionStateCallback& callback) override;
+ void ListenForSessionMessages(
+ const SessionMessagesCallback& callback) override;
+
+ // Creates a binding between this object and |request|.
+ void Bind(mojo::InterfaceRequest<presentation::PresentationService> request);
+
+ // mojo::ErrorHandler override.
+ // Note that this is called when the RenderFrameHost is deleted.
+ void OnConnectionError() override;
+
+ // WebContentsObserver override.
+ void DidNavigateAnyFrame(
+ content::RenderFrameHost* render_frame_host,
+ const content::LoadCommittedDetails& details,
+ const content::FrameNavigateParams& params) override;
+ void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
+
+ // PresentationServiceDelegate::Observer
+ void OnDelegateDestroyed() override;
+ void OnDefaultPresentationStarted(const PresentationSessionInfo& session)
+ override;
+
+ // Finds the callback from |pending_join_session_cbs_| using
+ // |request_session_id|.
+ // If it exists, invoke it with |session| and |error|, then erase it from
+ // |pending_join_session_cbs_|.
+ void RunAndEraseJoinSessionMojoCallback(
+ int request_session_id,
+ presentation::PresentationSessionInfoPtr session,
+ presentation::PresentationErrorPtr error);
+
+ // Creates a new screen availability listener for |presentation_url| and
+ // registers it with |delegate_|. Replaces the existing listener if any.
+ void ResetScreenAvailabilityListener(const std::string& presentation_url);
+
+ // Removes all listeners and resets default presentation URL on this instance
+ // and informs the PresentationServiceDelegate of such.
+ void Reset();
+
+ // These functions are bound as base::Callbacks and passed to
+ // embedder's implementation of PresentationServiceDelegate for later
+ // invocation.
+ void OnStartSessionSucceeded(
+ int request_session_id,
+ const PresentationSessionInfo& session_info);
+ void OnStartSessionError(
+ int request_session_id,
+ const PresentationError& error);
+ void OnJoinSessionSucceeded(
+ int request_session_id,
+ const PresentationSessionInfo& session_info);
+ void OnJoinSessionError(
+ int request_session_id,
+ const PresentationError& error);
+ void OnSendMessageCallback();
+
+ // Requests delegate to start a session.
+ void DoStartSession(scoped_ptr<StartSessionRequest> request);
+
+ // Passed to embedder's implementation of PresentationServiceDelegate for
+ // later invocation when session messages arrive.
+ // For optimization purposes, this method will empty the messages
+ // passed to it.
+ void OnSessionMessages(
+ scoped_ptr<ScopedVector<PresentationSessionMessage>> messages);
+
+ // Removes the head of the queue (which represents the request that has just
+ // been processed).
+ // Checks if there are any queued StartSession requests and if so, executes
+ // the first one in the queue.
+ void HandleQueuedStartSessionRequests();
+
+ // Associates a JoinSession |callback| with a unique request ID and
+ // stores it in a map.
+ // Returns a positive value on success.
+ int RegisterJoinSessionCallback(const NewSessionMojoCallback& callback);
+
+ // Returns true if this object is associated with |render_frame_host|.
+ bool FrameMatches(content::RenderFrameHost* render_frame_host) const;
+
+ // Embedder-specific delegate to forward Presentation requests to.
+ // May be null if embedder does not support Presentation API.
+ PresentationServiceDelegate* delegate_;
+
+ // Proxy to the PresentationServiceClient to send results (e.g., screen
+ // availability) to.
+ presentation::PresentationServiceClientPtr client_;
+
+ std::string default_presentation_url_;
+ std::string default_presentation_id_;
+
+ scoped_ptr<ScreenAvailabilityListenerImpl> screen_availability_listener_;
+
+ // We only allow one StartSession request to be processed at a time.
+ // StartSession requests are queued here. When a request has been processed,
+ // it is removed from head of the queue.
+ std::deque<linked_ptr<StartSessionRequest>> queued_start_session_requests_;
+
+ // For StartSession requests.
+ // Set to a positive value when a StartSession request is being processed.
+ int start_session_request_id_;
+ scoped_ptr<NewSessionMojoCallbackWrapper> pending_start_session_cb_;
+
+ // For JoinSession requests.
+ base::hash_map<int, linked_ptr<NewSessionMojoCallbackWrapper>>
+ pending_join_session_cbs_;
+
+ scoped_ptr<DefaultSessionStartContext> default_session_start_context_;
+
+ // RAII binding of |this| to an Presentation interface request.
+ // The binding is removed when binding_ is cleared or goes out of scope.
+ scoped_ptr<mojo::Binding<presentation::PresentationService>> binding_;
+
+ // There can be only one send message request at a time.
+ scoped_ptr<SendMessageMojoCallback> send_message_callback_;
+
+ scoped_ptr<SessionMessagesCallback> on_session_messages_callback_;
+
+ // ID of the RenderFrameHost this object is associated with.
+ int render_process_id_;
+ int render_frame_id_;
+
+ // NOTE: Weak pointers must be invalidated before all other member variables.
+ base::WeakPtrFactory<PresentationServiceImpl> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(PresentationServiceImpl);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_PRESENTATION_PRESENTATION_SERVICE_IMPL_H_
diff --git a/chromium/content/browser/presentation/presentation_service_impl_unittest.cc b/chromium/content/browser/presentation/presentation_service_impl_unittest.cc
new file mode 100644
index 00000000000..677418fd90a
--- /dev/null
+++ b/chromium/content/browser/presentation/presentation_service_impl_unittest.cc
@@ -0,0 +1,840 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/test/test_timeouts.h"
+#include "content/browser/presentation/presentation_service_impl.h"
+#include "content/public/browser/presentation_service_delegate.h"
+#include "content/public/browser/presentation_session.h"
+#include "content/public/common/presentation_constants.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 "mojo/public/cpp/bindings/interface_ptr.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using ::testing::_;
+using ::testing::Eq;
+using ::testing::InvokeWithoutArgs;
+using ::testing::Mock;
+using ::testing::Return;
+using ::testing::SaveArg;
+
+namespace content {
+
+namespace {
+
+bool ArePresentationSessionsEqual(
+ const presentation::PresentationSessionInfo& expected,
+ const presentation::PresentationSessionInfo& actual) {
+ return expected.url == actual.url && expected.id == actual.id;
+}
+
+bool ArePresentationSessionMessagesEqual(
+ const presentation::SessionMessage* expected,
+ const presentation::SessionMessage* actual) {
+ return expected->presentation_url == actual->presentation_url &&
+ expected->presentation_id == actual->presentation_id &&
+ expected->type == actual->type &&
+ expected->message == actual->message &&
+ expected->data.Equals(actual->data);
+}
+
+void DoNothing(
+ presentation::PresentationSessionInfoPtr info,
+ presentation::PresentationErrorPtr error) {
+}
+
+} // namespace
+
+class MockPresentationServiceDelegate : public PresentationServiceDelegate {
+ public:
+ MOCK_METHOD3(AddObserver,
+ void(int render_process_id,
+ int render_frame_id,
+ PresentationServiceDelegate::Observer* observer));
+ MOCK_METHOD2(RemoveObserver,
+ void(int render_process_id, int render_frame_id));
+ MOCK_METHOD3(AddScreenAvailabilityListener,
+ bool(
+ int render_process_id,
+ int routing_id,
+ PresentationScreenAvailabilityListener* listener));
+ MOCK_METHOD3(RemoveScreenAvailabilityListener,
+ void(
+ int render_process_id,
+ int routing_id,
+ PresentationScreenAvailabilityListener* listener));
+ MOCK_METHOD2(Reset,
+ void(
+ int render_process_id,
+ int routing_id));
+ MOCK_METHOD4(SetDefaultPresentationUrl,
+ void(
+ int render_process_id,
+ int routing_id,
+ const std::string& default_presentation_url,
+ const std::string& default_presentation_id));
+ MOCK_METHOD6(StartSession,
+ void(
+ int render_process_id,
+ int render_frame_id,
+ const std::string& presentation_url,
+ const std::string& presentation_id,
+ const PresentationSessionSuccessCallback& success_cb,
+ const PresentationSessionErrorCallback& error_cb));
+ MOCK_METHOD6(JoinSession,
+ void(
+ int render_process_id,
+ int render_frame_id,
+ const std::string& presentation_url,
+ const std::string& presentation_id,
+ const PresentationSessionSuccessCallback& success_cb,
+ const PresentationSessionErrorCallback& error_cb));
+
+ MOCK_METHOD3(ListenForSessionMessages,
+ void(
+ int render_process_id,
+ int render_frame_id,
+ const PresentationSessionMessageCallback& message_cb));
+
+ MOCK_METHOD4(SendMessageRawPtr,
+ void(
+ int render_process_id,
+ int render_frame_id,
+ PresentationSessionMessage* message_request,
+ const SendMessageCallback& send_message_cb));
+
+ void SendMessage(
+ int render_process_id,
+ int render_frame_id,
+ scoped_ptr<PresentationSessionMessage> message_request,
+ const SendMessageCallback& send_message_cb) {
+ SendMessageRawPtr(
+ render_process_id,
+ render_frame_id,
+ message_request.release(),
+ send_message_cb);
+ }
+};
+
+class MockPresentationServiceClient :
+ public presentation::PresentationServiceClient {
+ public:
+ MOCK_METHOD1(OnScreenAvailabilityUpdated, void(bool available));
+};
+
+class PresentationServiceImplTest : public RenderViewHostImplTestHarness {
+ public:
+ PresentationServiceImplTest() : default_session_started_count_(0) {}
+
+ void SetUp() override {
+ RenderViewHostImplTestHarness::SetUp();
+
+ auto request = mojo::GetProxy(&service_ptr_);
+ EXPECT_CALL(mock_delegate_, AddObserver(_, _, _)).Times(1);
+ service_impl_.reset(new PresentationServiceImpl(
+ contents()->GetMainFrame(), contents(), &mock_delegate_));
+ service_impl_->Bind(request.Pass());
+
+ presentation::PresentationServiceClientPtr client_ptr;
+ client_binding_.reset(
+ new mojo::Binding<presentation::PresentationServiceClient>(
+ &mock_client_, mojo::GetProxy(&client_ptr)));
+ service_impl_->SetClient(client_ptr.Pass());
+ }
+
+ void TearDown() override {
+ service_ptr_.reset();
+ if (service_impl_.get()) {
+ EXPECT_CALL(mock_delegate_, RemoveObserver(_, _)).Times(1);
+ service_impl_.reset();
+ }
+ RenderViewHostImplTestHarness::TearDown();
+ }
+
+ void ListenForScreenAvailabilityAndWait(bool delegate_success) {
+ base::RunLoop run_loop;
+ // This will call to |service_impl_| via mojo. Process the message
+ // using RunLoop.
+ // The callback shouldn't be invoked since there is no availability
+ // result yet.
+ EXPECT_CALL(mock_delegate_, AddScreenAvailabilityListener(_, _, _))
+ .WillOnce(DoAll(
+ InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit),
+ Return(delegate_success)));
+ service_ptr_->ListenForScreenAvailability();
+ run_loop.Run();
+
+ EXPECT_TRUE(Mock::VerifyAndClearExpectations(&mock_delegate_));
+ }
+
+ void RunLoopFor(base::TimeDelta duration) {
+ base::RunLoop run_loop;
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE, run_loop.QuitClosure(), duration);
+ run_loop.Run();
+ }
+
+ void SaveQuitClosureAndRunLoop() {
+ base::RunLoop run_loop;
+ run_loop_quit_closure_ = run_loop.QuitClosure();
+ run_loop.Run();
+ run_loop_quit_closure_.Reset();
+ }
+
+ void SimulateScreenAvailabilityChangeAndWait(bool available) {
+ auto* listener = service_impl_->screen_availability_listener_.get();
+ ASSERT_TRUE(listener);
+
+ base::RunLoop run_loop;
+ EXPECT_CALL(mock_client_, OnScreenAvailabilityUpdated(available))
+ .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
+ listener->OnScreenAvailabilityChanged(available);
+ run_loop.Run();
+ }
+
+ void ExpectReset() {
+ EXPECT_CALL(mock_delegate_, Reset(_, _)).Times(1);
+ }
+
+ void ExpectCleanState() {
+ EXPECT_TRUE(service_impl_->default_presentation_url_.empty());
+ EXPECT_TRUE(service_impl_->default_presentation_id_.empty());
+ EXPECT_TRUE(service_impl_->queued_start_session_requests_.empty());
+ EXPECT_FALSE(service_impl_->screen_availability_listener_.get());
+ EXPECT_FALSE(service_impl_->default_session_start_context_.get());
+ EXPECT_FALSE(service_impl_->on_session_messages_callback_.get());
+ }
+
+ void ExpectNewSessionMojoCallbackSuccess(
+ presentation::PresentationSessionInfoPtr info,
+ presentation::PresentationErrorPtr error) {
+ EXPECT_FALSE(info.is_null());
+ EXPECT_TRUE(error.is_null());
+ if (!run_loop_quit_closure_.is_null())
+ run_loop_quit_closure_.Run();
+ }
+
+ void ExpectNewSessionMojoCallbackError(
+ presentation::PresentationSessionInfoPtr info,
+ presentation::PresentationErrorPtr error) {
+ EXPECT_TRUE(info.is_null());
+ EXPECT_FALSE(error.is_null());
+ if (!run_loop_quit_closure_.is_null())
+ run_loop_quit_closure_.Run();
+ }
+
+ void ExpectDefaultSessionStarted(
+ const presentation::PresentationSessionInfo& expected_session,
+ presentation::PresentationSessionInfoPtr actual_session) {
+ ASSERT_TRUE(!actual_session.is_null());
+ EXPECT_TRUE(ArePresentationSessionsEqual(
+ expected_session, *actual_session));
+ ++default_session_started_count_;
+ if (!run_loop_quit_closure_.is_null())
+ run_loop_quit_closure_.Run();
+ }
+
+ void ExpectDefaultSessionNull(
+ presentation::PresentationSessionInfoPtr actual_session) {
+ EXPECT_TRUE(actual_session.is_null());
+ ++default_session_started_count_;
+ if (!run_loop_quit_closure_.is_null())
+ run_loop_quit_closure_.Run();
+ }
+
+ void ExpectSessionMessages(
+ mojo::Array<presentation::SessionMessagePtr> actual_msgs) {
+ EXPECT_TRUE(actual_msgs.size() == expected_msgs_.size());
+ for (size_t i = 0; i < actual_msgs.size(); ++i) {
+ EXPECT_TRUE(ArePresentationSessionMessagesEqual(expected_msgs_[i].get(),
+ actual_msgs[i].get()));
+ }
+ if (!run_loop_quit_closure_.is_null())
+ run_loop_quit_closure_.Run();
+ }
+
+ void ExpectSendMessageMojoCallback(bool success) {
+ EXPECT_TRUE(success);
+ EXPECT_FALSE(service_impl_->send_message_callback_);
+ if (!run_loop_quit_closure_.is_null())
+ run_loop_quit_closure_.Run();
+ }
+
+ void RunListenForSessionMessages(std::string& text_msg,
+ std::vector<uint8_t>& binary_data) {
+ std::string presentation_url("http://fooUrl");
+ std::string presentation_id("presentationId");
+
+ expected_msgs_ = mojo::Array<presentation::SessionMessagePtr>::New(2);
+ expected_msgs_[0] = presentation::SessionMessage::New();
+ expected_msgs_[0]->presentation_url = presentation_url;
+ expected_msgs_[0]->presentation_id = presentation_id;
+ expected_msgs_[0]->type =
+ presentation::PresentationMessageType::PRESENTATION_MESSAGE_TYPE_TEXT;
+ expected_msgs_[0]->message = text_msg;
+ expected_msgs_[1] = presentation::SessionMessage::New();
+ expected_msgs_[1]->presentation_url = presentation_url;
+ expected_msgs_[1]->presentation_id = presentation_id;
+ expected_msgs_[1]->type = presentation::PresentationMessageType::
+ PRESENTATION_MESSAGE_TYPE_ARRAY_BUFFER;
+ expected_msgs_[1]->data = mojo::Array<uint8_t>::From(binary_data);
+
+ service_ptr_->ListenForSessionMessages(
+ base::Bind(&PresentationServiceImplTest::ExpectSessionMessages,
+ base::Unretained(this)));
+
+ base::RunLoop run_loop;
+ base::Callback<void(scoped_ptr<ScopedVector<PresentationSessionMessage>>)>
+ message_cb;
+ EXPECT_CALL(mock_delegate_, ListenForSessionMessages(_, _, _))
+ .WillOnce(DoAll(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit),
+ SaveArg<2>(&message_cb)));
+ run_loop.Run();
+
+ scoped_ptr<ScopedVector<PresentationSessionMessage>> messages(
+ new ScopedVector<PresentationSessionMessage>());
+ messages->push_back(
+ content::PresentationSessionMessage::CreateStringMessage(
+ presentation_url, presentation_id,
+ scoped_ptr<std::string>(new std::string(text_msg))));
+ messages->push_back(
+ content::PresentationSessionMessage::CreateBinaryMessage(
+ presentation_url, presentation_id,
+ scoped_ptr<std::vector<uint8_t>>(
+ new std::vector<uint8_t>(binary_data))));
+ message_cb.Run(messages.Pass());
+ SaveQuitClosureAndRunLoop();
+ }
+
+ MockPresentationServiceDelegate mock_delegate_;
+
+ scoped_ptr<PresentationServiceImpl> service_impl_;
+ mojo::InterfacePtr<presentation::PresentationService> service_ptr_;
+
+ MockPresentationServiceClient mock_client_;
+ scoped_ptr<mojo::Binding<presentation::PresentationServiceClient>>
+ client_binding_;
+
+ base::Closure run_loop_quit_closure_;
+ int default_session_started_count_;
+ mojo::Array<presentation::SessionMessagePtr> expected_msgs_;
+};
+
+TEST_F(PresentationServiceImplTest, ListenForScreenAvailability) {
+ ListenForScreenAvailabilityAndWait(true);
+
+ SimulateScreenAvailabilityChangeAndWait(true);
+ SimulateScreenAvailabilityChangeAndWait(false);
+ SimulateScreenAvailabilityChangeAndWait(true);
+}
+
+TEST_F(PresentationServiceImplTest, Reset) {
+ ListenForScreenAvailabilityAndWait(true);
+
+ ExpectReset();
+ service_impl_->Reset();
+ ExpectCleanState();
+}
+
+TEST_F(PresentationServiceImplTest, DidNavigateThisFrame) {
+ ListenForScreenAvailabilityAndWait(true);
+
+ ExpectReset();
+ service_impl_->DidNavigateAnyFrame(
+ contents()->GetMainFrame(),
+ content::LoadCommittedDetails(),
+ content::FrameNavigateParams());
+ ExpectCleanState();
+}
+
+TEST_F(PresentationServiceImplTest, DidNavigateOtherFrame) {
+ ListenForScreenAvailabilityAndWait(true);
+
+ // TODO(imcheng): How to get a different RenderFrameHost?
+ service_impl_->DidNavigateAnyFrame(
+ nullptr,
+ content::LoadCommittedDetails(),
+ content::FrameNavigateParams());
+
+ // Availability is reported and callback is invoked since it was not
+ // removed.
+ SimulateScreenAvailabilityChangeAndWait(true);
+}
+
+TEST_F(PresentationServiceImplTest, ThisRenderFrameDeleted) {
+ ListenForScreenAvailabilityAndWait(true);
+
+ ExpectReset();
+
+ // Since the frame matched the service, |service_impl_| will be deleted.
+ PresentationServiceImpl* service = service_impl_.release();
+ EXPECT_CALL(mock_delegate_, RemoveObserver(_, _)).Times(1);
+ service->RenderFrameDeleted(contents()->GetMainFrame());
+}
+
+TEST_F(PresentationServiceImplTest, OtherRenderFrameDeleted) {
+ ListenForScreenAvailabilityAndWait(true);
+
+ // TODO(imcheng): How to get a different RenderFrameHost?
+ service_impl_->RenderFrameDeleted(nullptr);
+
+ // Availability is reported and callback should be invoked since listener
+ // has not been deleted.
+ SimulateScreenAvailabilityChangeAndWait(true);
+}
+
+TEST_F(PresentationServiceImplTest, DelegateFails) {
+ ListenForScreenAvailabilityAndWait(false);
+ ASSERT_FALSE(service_impl_->screen_availability_listener_.get());
+}
+
+TEST_F(PresentationServiceImplTest, SetDefaultPresentationUrl) {
+ std::string url1("http://fooUrl");
+ std::string dpu_id("dpuId");
+ EXPECT_CALL(mock_delegate_,
+ SetDefaultPresentationUrl(_, _, Eq(url1), Eq(dpu_id)))
+ .Times(1);
+ service_impl_->SetDefaultPresentationURL(url1, dpu_id);
+ EXPECT_EQ(url1, service_impl_->default_presentation_url_);
+
+ // Now there should be a listener for DPU = |url1|.
+ ListenForScreenAvailabilityAndWait(true);
+ auto* listener = service_impl_->screen_availability_listener_.get();
+ ASSERT_TRUE(listener);
+ EXPECT_EQ(url1, listener->GetPresentationUrl());
+
+ std::string url2("http://barUrl");
+ // Sets different DPU.
+ // Adds listener for url2 and removes listener for url1.
+ EXPECT_CALL(
+ mock_delegate_,
+ AddScreenAvailabilityListener(_, _, _))
+ .WillOnce(Return(true));
+ EXPECT_CALL(
+ mock_delegate_,
+ RemoveScreenAvailabilityListener(_, _, _))
+ .Times(1);
+ EXPECT_CALL(mock_delegate_,
+ SetDefaultPresentationUrl(_, _, Eq(url2), Eq(dpu_id)))
+ .Times(1);
+ service_impl_->SetDefaultPresentationURL(url2, dpu_id);
+ EXPECT_EQ(url2, service_impl_->default_presentation_url_);
+
+ listener = service_impl_->screen_availability_listener_.get();
+ ASSERT_TRUE(listener);
+ EXPECT_EQ(url2, listener->GetPresentationUrl());
+}
+
+TEST_F(PresentationServiceImplTest, SetSameDefaultPresentationUrl) {
+ std::string url("http://fooUrl");
+ std::string dpu_id("dpuId");
+ EXPECT_CALL(mock_delegate_,
+ SetDefaultPresentationUrl(_, _, Eq(url), Eq(dpu_id)))
+ .Times(1);
+ service_impl_->SetDefaultPresentationURL(url, dpu_id);
+ EXPECT_TRUE(Mock::VerifyAndClearExpectations(&mock_delegate_));
+ EXPECT_EQ(url, service_impl_->default_presentation_url_);
+
+ // Same URL as before; no-ops.
+ service_impl_->SetDefaultPresentationURL(url, dpu_id);
+ EXPECT_TRUE(Mock::VerifyAndClearExpectations(&mock_delegate_));
+ EXPECT_EQ(url, service_impl_->default_presentation_url_);
+}
+
+TEST_F(PresentationServiceImplTest, StartSessionSuccess) {
+ std::string presentation_url("http://fooUrl");
+ std::string presentation_id("presentationId");
+ service_ptr_->StartSession(
+ presentation_url,
+ presentation_id,
+ base::Bind(
+ &PresentationServiceImplTest::ExpectNewSessionMojoCallbackSuccess,
+ base::Unretained(this)));
+ base::RunLoop run_loop;
+ base::Callback<void(const PresentationSessionInfo&)> success_cb;
+ EXPECT_CALL(mock_delegate_, StartSession(
+ _, _, Eq(presentation_url), Eq(presentation_id), _, _))
+ .WillOnce(DoAll(
+ InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit),
+ SaveArg<4>(&success_cb)));
+ run_loop.Run();
+ success_cb.Run(PresentationSessionInfo(presentation_url, presentation_id));
+ SaveQuitClosureAndRunLoop();
+}
+
+TEST_F(PresentationServiceImplTest, StartSessionError) {
+ std::string presentation_url("http://fooUrl");
+ std::string presentation_id("presentationId");
+ service_ptr_->StartSession(
+ presentation_url,
+ presentation_id,
+ base::Bind(
+ &PresentationServiceImplTest::ExpectNewSessionMojoCallbackError,
+ base::Unretained(this)));
+ base::RunLoop run_loop;
+ base::Callback<void(const PresentationError&)> error_cb;
+ EXPECT_CALL(mock_delegate_, StartSession(
+ _, _, Eq(presentation_url), Eq(presentation_id), _, _))
+ .WillOnce(DoAll(
+ InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit),
+ SaveArg<5>(&error_cb)));
+ run_loop.Run();
+ error_cb.Run(PresentationError(PRESENTATION_ERROR_UNKNOWN, "Error message"));
+ SaveQuitClosureAndRunLoop();
+}
+
+TEST_F(PresentationServiceImplTest, JoinSessionSuccess) {
+ std::string presentation_url("http://fooUrl");
+ std::string presentation_id("presentationId");
+ service_ptr_->JoinSession(
+ presentation_url,
+ presentation_id,
+ base::Bind(
+ &PresentationServiceImplTest::ExpectNewSessionMojoCallbackSuccess,
+ base::Unretained(this)));
+ base::RunLoop run_loop;
+ base::Callback<void(const PresentationSessionInfo&)> success_cb;
+ EXPECT_CALL(mock_delegate_, JoinSession(
+ _, _, Eq(presentation_url), Eq(presentation_id), _, _))
+ .WillOnce(DoAll(
+ InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit),
+ SaveArg<4>(&success_cb)));
+ run_loop.Run();
+ success_cb.Run(PresentationSessionInfo(presentation_url, presentation_id));
+ SaveQuitClosureAndRunLoop();
+}
+
+TEST_F(PresentationServiceImplTest, JoinSessionError) {
+ std::string presentation_url("http://fooUrl");
+ std::string presentation_id("presentationId");
+ service_ptr_->JoinSession(
+ presentation_url,
+ presentation_id,
+ base::Bind(
+ &PresentationServiceImplTest::ExpectNewSessionMojoCallbackError,
+ base::Unretained(this)));
+ base::RunLoop run_loop;
+ base::Callback<void(const PresentationError&)> error_cb;
+ EXPECT_CALL(mock_delegate_, JoinSession(
+ _, _, Eq(presentation_url), Eq(presentation_id), _, _))
+ .WillOnce(DoAll(
+ InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit),
+ SaveArg<5>(&error_cb)));
+ run_loop.Run();
+ error_cb.Run(PresentationError(PRESENTATION_ERROR_UNKNOWN, "Error message"));
+ SaveQuitClosureAndRunLoop();
+}
+
+TEST_F(PresentationServiceImplTest, ListenForSessionMessages) {
+ std::string text_msg("123");
+ std::vector<uint8_t> binary_data(3, '\1');
+ RunListenForSessionMessages(text_msg, binary_data);
+}
+
+TEST_F(PresentationServiceImplTest, ListenForSessionMessagesWithEmptyMsg) {
+ std::string text_msg("");
+ std::vector<uint8_t> binary_data{};
+ RunListenForSessionMessages(text_msg, binary_data);
+}
+
+TEST_F(PresentationServiceImplTest, ReceiveSessionMessagesAfterReset) {
+ std::string presentation_url("http://fooUrl");
+ std::string presentation_id("presentationId");
+ std::string text_msg("123");
+ expected_msgs_ = mojo::Array<presentation::SessionMessagePtr>();
+ service_ptr_->ListenForSessionMessages(
+ base::Bind(&PresentationServiceImplTest::ExpectSessionMessages,
+ base::Unretained(this)));
+
+ base::RunLoop run_loop;
+ base::Callback<void(scoped_ptr<ScopedVector<PresentationSessionMessage>>)>
+ message_cb;
+ EXPECT_CALL(mock_delegate_, ListenForSessionMessages(_, _, _))
+ .WillOnce(DoAll(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit),
+ SaveArg<2>(&message_cb)));
+ run_loop.Run();
+
+ scoped_ptr<ScopedVector<PresentationSessionMessage>> messages(
+ new ScopedVector<PresentationSessionMessage>());
+ messages->push_back(content::PresentationSessionMessage::CreateStringMessage(
+ presentation_url, presentation_id,
+ scoped_ptr<std::string>(new std::string(text_msg))));
+ ExpectReset();
+ service_impl_->Reset();
+ message_cb.Run(messages.Pass());
+ SaveQuitClosureAndRunLoop();
+}
+
+TEST_F(PresentationServiceImplTest, StartSessionInProgress) {
+ std::string presentation_url1("http://fooUrl");
+ std::string presentation_id1("presentationId1");
+ std::string presentation_url2("http://barUrl");
+ std::string presentation_id2("presentationId2");
+ service_ptr_->StartSession(
+ presentation_url1,
+ presentation_id1,
+ base::Bind(
+ &PresentationServiceImplTest::ExpectNewSessionMojoCallbackSuccess,
+ base::Unretained(this)));
+ service_ptr_->StartSession(
+ presentation_url2,
+ presentation_id2,
+ base::Bind(
+ &PresentationServiceImplTest::ExpectNewSessionMojoCallbackSuccess,
+ base::Unretained(this)));
+ base::RunLoop run_loop;
+ base::Callback<void(const PresentationSessionInfo&)> success_cb;
+ EXPECT_CALL(mock_delegate_, StartSession(
+ _, _, Eq(presentation_url1), Eq(presentation_id1), _, _))
+ .WillOnce(DoAll(
+ InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit),
+ SaveArg<4>(&success_cb)));
+ run_loop.Run();
+
+ // Running the callback means the first request is done. It should now
+ // move on to the queued request.
+ EXPECT_CALL(mock_delegate_, StartSession(
+ _, _, Eq(presentation_url2), Eq(presentation_id2), _, _))
+ .Times(1);
+ success_cb.Run(PresentationSessionInfo(presentation_url1, presentation_id1));
+ SaveQuitClosureAndRunLoop();
+}
+
+TEST_F(PresentationServiceImplTest, ListenForDefaultSessionStart) {
+ std::string presentation_url1("http://fooUrl1");
+ std::string presentation_id1("presentationId1");
+ presentation::PresentationSessionInfo expected_session;
+ expected_session.url = presentation_url1;
+ expected_session.id = presentation_id1;
+ service_ptr_->ListenForDefaultSessionStart(
+ base::Bind(&PresentationServiceImplTest::ExpectDefaultSessionStarted,
+ base::Unretained(this),
+ expected_session));
+ RunLoopFor(base::TimeDelta::FromMilliseconds(50));
+ service_impl_->OnDefaultPresentationStarted(
+ content::PresentationSessionInfo(presentation_url1, presentation_id1));
+ SaveQuitClosureAndRunLoop();
+ EXPECT_EQ(1, default_session_started_count_);
+}
+
+TEST_F(PresentationServiceImplTest, ListenForDefaultSessionStartAfterSet) {
+ // Note that the callback will only pick up presentation_url2/id2 since
+ // ListenForDefaultSessionStart wasn't called yet when the DPU was still
+ // presentation_url1.
+ std::string presentation_url1("http://fooUrl1");
+ std::string presentation_id1("presentationId1");
+ std::string presentation_url2("http://fooUrl2");
+ std::string presentation_id2("presentationId2");
+ service_impl_->OnDefaultPresentationStarted(
+ content::PresentationSessionInfo(presentation_url1, presentation_id1));
+
+ presentation::PresentationSessionInfo expected_session;
+ expected_session.url = presentation_url2;
+ expected_session.id = presentation_id2;
+ service_ptr_->ListenForDefaultSessionStart(
+ base::Bind(&PresentationServiceImplTest::ExpectDefaultSessionStarted,
+ base::Unretained(this),
+ expected_session));
+ RunLoopFor(base::TimeDelta::FromMilliseconds(50));
+ service_impl_->OnDefaultPresentationStarted(
+ content::PresentationSessionInfo(presentation_url2, presentation_id2));
+ SaveQuitClosureAndRunLoop();
+ EXPECT_EQ(1, default_session_started_count_);
+}
+
+TEST_F(PresentationServiceImplTest, DefaultSessionStartReset) {
+ service_ptr_->ListenForDefaultSessionStart(
+ base::Bind(&PresentationServiceImplTest::ExpectDefaultSessionNull,
+ base::Unretained(this)));
+ RunLoopFor(TestTimeouts::tiny_timeout());
+
+ ExpectReset();
+ service_impl_->Reset();
+ ExpectCleanState();
+ SaveQuitClosureAndRunLoop();
+ EXPECT_EQ(1, default_session_started_count_);
+}
+
+TEST_F(PresentationServiceImplTest, SendStringMessage) {
+ std::string presentation_url("http://foo.com/index.html");
+ std::string presentation_id("presentationId");
+ std::string message("Test presentation session message");
+
+ presentation::SessionMessagePtr message_request(
+ presentation::SessionMessage::New());
+ message_request->presentation_url = presentation_url;
+ message_request->presentation_id = presentation_id;
+ message_request->type = presentation::PresentationMessageType::
+ PRESENTATION_MESSAGE_TYPE_TEXT;
+ message_request->message = message;
+ service_ptr_->SendSessionMessage(
+ message_request.Pass(),
+ base::Bind(
+ &PresentationServiceImplTest::ExpectSendMessageMojoCallback,
+ base::Unretained(this)));
+
+ base::RunLoop run_loop;
+ base::Closure send_message_cb;
+ PresentationSessionMessage* test_message = nullptr;
+ EXPECT_CALL(mock_delegate_, SendMessageRawPtr(
+ _, _, _, _))
+ .WillOnce(DoAll(
+ InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit),
+ SaveArg<2>(&test_message),
+ SaveArg<3>(&send_message_cb)));
+ run_loop.Run();
+
+ EXPECT_TRUE(test_message);
+ EXPECT_EQ(presentation_url, test_message->presentation_url);
+ EXPECT_EQ(presentation_id, test_message->presentation_id);
+ EXPECT_FALSE(test_message->is_binary());
+ EXPECT_TRUE(test_message->message.get()->size() <=
+ kMaxPresentationSessionMessageSize);
+ EXPECT_EQ(message, *(test_message->message.get()));
+ EXPECT_FALSE(test_message->data);
+ delete test_message;
+ send_message_cb.Run();
+ SaveQuitClosureAndRunLoop();
+}
+
+TEST_F(PresentationServiceImplTest, SendArrayBuffer) {
+ std::string presentation_url("http://foo.com/index.html");
+ std::string presentation_id("presentationId");
+ // Test Array buffer data.
+ const uint8 buffer[] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
+ std::vector<uint8> data;
+ data.assign(buffer, buffer + sizeof(buffer));
+
+ presentation::SessionMessagePtr message_request(
+ presentation::SessionMessage::New());
+ message_request->presentation_url = presentation_url;
+ message_request->presentation_id = presentation_id;
+ message_request->type = presentation::PresentationMessageType::
+ PRESENTATION_MESSAGE_TYPE_ARRAY_BUFFER;
+ message_request->data = mojo::Array<uint8>::From(data);
+ service_ptr_->SendSessionMessage(
+ message_request.Pass(),
+ base::Bind(
+ &PresentationServiceImplTest::ExpectSendMessageMojoCallback,
+ base::Unretained(this)));
+
+ base::RunLoop run_loop;
+ base::Closure send_message_cb;
+ PresentationSessionMessage* test_message = nullptr;
+ EXPECT_CALL(mock_delegate_, SendMessageRawPtr(
+ _, _, _, _))
+ .WillOnce(DoAll(
+ InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit),
+ SaveArg<2>(&test_message),
+ SaveArg<3>(&send_message_cb)));
+ run_loop.Run();
+
+ EXPECT_TRUE(test_message);
+ EXPECT_EQ(presentation_url, test_message->presentation_url);
+ EXPECT_EQ(presentation_id, test_message->presentation_id);
+ EXPECT_TRUE(test_message->is_binary());
+ EXPECT_FALSE(test_message->message);
+ EXPECT_EQ(data.size(), test_message->data.get()->size());
+ EXPECT_TRUE(test_message->data.get()->size() <=
+ kMaxPresentationSessionMessageSize);
+ EXPECT_EQ(0, memcmp(buffer, &(*test_message->data.get())[0], sizeof(buffer)));
+ delete test_message;
+ send_message_cb.Run();
+ SaveQuitClosureAndRunLoop();
+}
+
+TEST_F(PresentationServiceImplTest, SendArrayBufferWithExceedingLimit) {
+ std::string presentation_url("http://foo.com/index.html");
+ std::string presentation_id("presentationId");
+ // Create buffer with size exceeding the limit.
+ // Use same size as in content::kMaxPresentationSessionMessageSize.
+ const size_t kMaxBufferSizeInBytes = 64 * 1024; // 64 KB.
+ uint8 buffer[kMaxBufferSizeInBytes+1];
+ memset(buffer, 0, kMaxBufferSizeInBytes+1);
+ std::vector<uint8> data;
+ data.assign(buffer, buffer + sizeof(buffer));
+
+ presentation::SessionMessagePtr message_request(
+ presentation::SessionMessage::New());
+ message_request->presentation_url = presentation_url;
+ message_request->presentation_id = presentation_id;
+ message_request->type = presentation::PresentationMessageType::
+ PRESENTATION_MESSAGE_TYPE_ARRAY_BUFFER;
+ message_request->data = mojo::Array<uint8>::From(data);
+ service_ptr_->SendSessionMessage(
+ message_request.Pass(),
+ base::Bind(
+ &PresentationServiceImplTest::ExpectSendMessageMojoCallback,
+ base::Unretained(this)));
+
+ base::RunLoop run_loop;
+ base::Closure send_message_cb;
+ PresentationSessionMessage* test_message = nullptr;
+ EXPECT_CALL(mock_delegate_, SendMessageRawPtr(
+ _, _, _, _))
+ .WillOnce(DoAll(
+ InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit),
+ SaveArg<2>(&test_message),
+ SaveArg<3>(&send_message_cb)));
+ run_loop.Run();
+
+ EXPECT_FALSE(test_message);
+ send_message_cb.Run();
+ SaveQuitClosureAndRunLoop();
+}
+
+TEST_F(PresentationServiceImplTest, MaxPendingStartSessionRequests) {
+ const char* presentation_url = "http://fooUrl%d";
+ const char* presentation_id = "presentationId%d";
+ int num_requests = PresentationServiceImpl::kMaxNumQueuedSessionRequests + 1;
+ int i = 0;
+ // First request will be processed. The subsequent
+ // |kMaxNumQueuedSessionRequests| requests will be queued.
+ EXPECT_CALL(mock_delegate_, StartSession(_, _, _, _, _, _)).Times(1);
+ for (; i < num_requests; ++i) {
+ service_ptr_->StartSession(
+ base::StringPrintf(presentation_url, i),
+ base::StringPrintf(presentation_id, i),
+ base::Bind(&DoNothing));
+ }
+
+ // Exceeded maximum queue size, should invoke mojo callback with error.
+ service_ptr_->StartSession(
+ base::StringPrintf(presentation_url, i),
+ base::StringPrintf(presentation_id, i),
+ base::Bind(
+ &PresentationServiceImplTest::ExpectNewSessionMojoCallbackError,
+ base::Unretained(this)));
+ SaveQuitClosureAndRunLoop();
+}
+
+TEST_F(PresentationServiceImplTest, MaxPendingJoinSessionRequests) {
+ const char* presentation_url = "http://fooUrl%d";
+ const char* presentation_id = "presentationId%d";
+ int num_requests = PresentationServiceImpl::kMaxNumQueuedSessionRequests;
+ int i = 0;
+ EXPECT_CALL(mock_delegate_, JoinSession(_, _, _, _, _, _))
+ .Times(num_requests);
+ for (; i < num_requests; ++i) {
+ service_ptr_->JoinSession(
+ base::StringPrintf(presentation_url, i),
+ base::StringPrintf(presentation_id, i),
+ base::Bind(&DoNothing));
+ }
+
+ // Exceeded maximum queue size, should invoke mojo callback with error.
+ service_ptr_->JoinSession(
+ base::StringPrintf(presentation_url, i),
+ base::StringPrintf(presentation_id, i),
+ base::Bind(
+ &PresentationServiceImplTest::ExpectNewSessionMojoCallbackError,
+ base::Unretained(this)));
+ SaveQuitClosureAndRunLoop();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/presentation/presentation_type_converters.cc b/chromium/content/browser/presentation/presentation_type_converters.cc
new file mode 100644
index 00000000000..73c4804edbe
--- /dev/null
+++ b/chromium/content/browser/presentation/presentation_type_converters.cc
@@ -0,0 +1,29 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/presentation/presentation_type_converters.h"
+
+#include "base/logging.h"
+
+namespace content {
+
+presentation::PresentationErrorType PresentationErrorTypeToMojo(
+ content::PresentationErrorType input) {
+ switch (input) {
+ case content::PRESENTATION_ERROR_NO_AVAILABLE_SCREENS:
+ return presentation::PRESENTATION_ERROR_TYPE_NO_AVAILABLE_SCREENS;
+ case content::PRESENTATION_ERROR_SESSION_REQUEST_CANCELLED:
+ return presentation::PRESENTATION_ERROR_TYPE_SESSION_REQUEST_CANCELLED;
+ case content::PRESENTATION_ERROR_NO_PRESENTATION_FOUND:
+ return presentation::PRESENTATION_ERROR_TYPE_NO_PRESENTATION_FOUND;
+ case content::PRESENTATION_ERROR_UNKNOWN:
+ return presentation::PRESENTATION_ERROR_TYPE_UNKNOWN;
+ default:
+ NOTREACHED();
+ return presentation::PRESENTATION_ERROR_TYPE_UNKNOWN;
+ }
+}
+
+} // namespace content
+
diff --git a/chromium/content/browser/presentation/presentation_type_converters.h b/chromium/content/browser/presentation/presentation_type_converters.h
new file mode 100644
index 00000000000..d5e5725cf75
--- /dev/null
+++ b/chromium/content/browser/presentation/presentation_type_converters.h
@@ -0,0 +1,50 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_PRESENTATION_PRESENTATION_TYPE_CONVERTERS_H_
+#define CONTENT_BROWSER_PRESENTATION_PRESENTATION_TYPE_CONVERTERS_H_
+
+#include "content/common/content_export.h"
+#include "content/common/presentation/presentation_service.mojom.h"
+#include "content/public/browser/presentation_session.h"
+
+namespace content {
+
+CONTENT_EXPORT presentation::PresentationErrorType PresentationErrorTypeToMojo(
+ PresentationErrorType input);
+
+} // namespace content
+
+namespace mojo {
+
+// MediaSink conversion helpers.
+template <>
+struct TypeConverter<presentation::PresentationSessionInfoPtr,
+ content::PresentationSessionInfo> {
+ static presentation::PresentationSessionInfoPtr Convert(
+ const content::PresentationSessionInfo& input) {
+ presentation::PresentationSessionInfoPtr output(
+ presentation::PresentationSessionInfo::New());
+ output->url = input.presentation_url;
+ output->id = input.presentation_id;
+ return output.Pass();
+ }
+};
+
+template <>
+struct TypeConverter<presentation::PresentationErrorPtr,
+ content::PresentationError> {
+ static presentation::PresentationErrorPtr Convert(
+ const content::PresentationError& input) {
+ presentation::PresentationErrorPtr output(
+ presentation::PresentationError::New());
+ output->error_type = PresentationErrorTypeToMojo(input.error_type);
+ output->message = input.message;
+ return output.Pass();
+ }
+};
+
+} // namespace mojo
+
+#endif // CONTENT_BROWSER_PRESENTATION_PRESENTATION_TYPE_CONVERTERS_H_
diff --git a/chromium/content/browser/presentation/presentation_type_converters_unittest.cc b/chromium/content/browser/presentation/presentation_type_converters_unittest.cc
new file mode 100644
index 00000000000..3107aff3d03
--- /dev/null
+++ b/chromium/content/browser/presentation/presentation_type_converters_unittest.cc
@@ -0,0 +1,34 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "content/browser/presentation/presentation_type_converters.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+TEST(PresentationTypeConvertersTest, PresentationSessionInfo) {
+ std::string presentation_url("http://fooUrl");
+ std::string presentation_id("presentationId");
+ PresentationSessionInfo session(presentation_url, presentation_id);
+ presentation::PresentationSessionInfoPtr session_mojo(
+ presentation::PresentationSessionInfo::From(session));
+ EXPECT_FALSE(session_mojo.is_null());
+ EXPECT_EQ(presentation_url, session_mojo->url);
+ EXPECT_EQ(presentation_id, session_mojo->id);
+}
+
+TEST(PresentationTypeConvertersTest, PresentationError) {
+ std::string message("Error message");
+ PresentationError error(PRESENTATION_ERROR_NO_AVAILABLE_SCREENS, message);
+ presentation::PresentationErrorPtr error_mojo(
+ presentation::PresentationError::From(error));
+ EXPECT_FALSE(error_mojo.is_null());
+ EXPECT_EQ(presentation::PRESENTATION_ERROR_TYPE_NO_AVAILABLE_SCREENS,
+ error_mojo->error_type);
+ EXPECT_EQ(message, error_mojo->message);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/profiler_controller_impl.cc b/chromium/content/browser/profiler_controller_impl.cc
index 27c95ed9138..7427d15f686 100644
--- a/chromium/content/browser/profiler_controller_impl.cc
+++ b/chromium/content/browser/profiler_controller_impl.cc
@@ -33,7 +33,7 @@ ProfilerControllerImpl::~ProfilerControllerImpl() {
void ProfilerControllerImpl::OnPendingProcesses(int sequence_number,
int pending_processes,
bool end) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (subscriber_)
subscriber_->OnPendingProcesses(sequence_number, pending_processes, end);
}
@@ -41,7 +41,7 @@ void ProfilerControllerImpl::OnPendingProcesses(int sequence_number,
void ProfilerControllerImpl::OnProfilerDataCollected(
int sequence_number,
const tracked_objects::ProcessDataSnapshot& profiler_data,
- int process_type) {
+ content::ProcessType process_type) {
if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
@@ -53,7 +53,7 @@ void ProfilerControllerImpl::OnProfilerDataCollected(
return;
}
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (subscriber_) {
subscriber_->OnProfilerDataCollected(sequence_number, profiler_data,
process_type);
@@ -61,7 +61,7 @@ void ProfilerControllerImpl::OnProfilerDataCollected(
}
void ProfilerControllerImpl::Register(ProfilerSubscriber* subscriber) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(!subscriber_);
subscriber_ = subscriber;
}
@@ -72,8 +72,9 @@ void ProfilerControllerImpl::Unregister(const ProfilerSubscriber* subscriber) {
}
void ProfilerControllerImpl::GetProfilerDataFromChildProcesses(
- int sequence_number) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ int sequence_number,
+ int current_profiling_phase) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
int pending_processes = 0;
for (BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) {
@@ -85,8 +86,10 @@ void ProfilerControllerImpl::GetProfilerDataFromChildProcesses(
continue;
++pending_processes;
- if (!iter.Send(new ChildProcessMsg_GetChildProfilerData(sequence_number)))
+ if (!iter.Send(new ChildProcessMsg_GetChildProfilerData(
+ sequence_number, current_profiling_phase))) {
--pending_processes;
+ }
}
BrowserThread::PostTask(
@@ -100,26 +103,66 @@ void ProfilerControllerImpl::GetProfilerDataFromChildProcesses(
true));
}
-void ProfilerControllerImpl::GetProfilerData(int sequence_number) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+// static
+void ProfilerControllerImpl::NotifyChildProcessesOfProfilingPhaseCompletion(
+ int profiling_phase) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ for (BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) {
+ // In some cases, there may be no child process of the given type (for
+ // example, the GPU process may not exist and there may instead just be a
+ // GPU thread in the browser process). If that's the case, then the process
+ // handle will be base::kNullProcessHandle and we shouldn't send it a
+ // message.
+ if (iter.GetData().handle == base::kNullProcessHandle)
+ continue;
+
+ iter.Send(new ChildProcessMsg_ProfilingPhaseCompleted(profiling_phase));
+ }
+}
+
+void ProfilerControllerImpl::GetProfilerData(int sequence_number,
+ int current_profiling_phase) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ // Iterates through renderers in UI thread, and through other child processes
+ // in IO thread, and send them GetChildProfilerData message. Renderers have to
+ // be contacted from UI thread, and other processes - from IO thread.
int pending_processes = 0;
for (RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator());
!it.IsAtEnd(); it.Advance()) {
++pending_processes;
- if (!it.GetCurrentValue()->Send(
- new ChildProcessMsg_GetChildProfilerData(sequence_number))) {
+ if (!it.GetCurrentValue()->Send(new ChildProcessMsg_GetChildProfilerData(
+ sequence_number, current_profiling_phase))) {
--pending_processes;
}
}
OnPendingProcesses(sequence_number, pending_processes, false);
BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
+ BrowserThread::IO, FROM_HERE,
base::Bind(&ProfilerControllerImpl::GetProfilerDataFromChildProcesses,
- base::Unretained(this),
- sequence_number));
+ base::Unretained(this), sequence_number,
+ current_profiling_phase));
+}
+
+void ProfilerControllerImpl::OnProfilingPhaseCompleted(int profiling_phase) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ // Iterates through renderers in UI thread, and through other child processes
+ // in IO thread, and send them OnProfilingPhase message. Renderers have to be
+ // contacted from UI thread, and other processes - from IO thread.
+ for (RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator());
+ !it.IsAtEnd(); it.Advance()) {
+ it.GetCurrentValue()->Send(
+ new ChildProcessMsg_ProfilingPhaseCompleted(profiling_phase));
+ }
+
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&ProfilerControllerImpl::
+ NotifyChildProcessesOfProfilingPhaseCompletion,
+ profiling_phase));
}
} // namespace content
diff --git a/chromium/content/browser/profiler_controller_impl.h b/chromium/content/browser/profiler_controller_impl.h
index 44e160c9a5d..cf2c10cb656 100644
--- a/chromium/content/browser/profiler_controller_impl.h
+++ b/chromium/content/browser/profiler_controller_impl.h
@@ -39,18 +39,25 @@ class ProfilerControllerImpl : public ProfilerController {
void OnProfilerDataCollected(
int sequence_number,
const tracked_objects::ProcessDataSnapshot& profiler_data,
- int process_type);
+ content::ProcessType process_type);
// ProfilerController implementation:
void Register(ProfilerSubscriber* subscriber) override;
void Unregister(const ProfilerSubscriber* subscriber) override;
- void GetProfilerData(int sequence_number) override;
+ void GetProfilerData(int sequence_number,
+ int current_profiling_phase) override;
+ void OnProfilingPhaseCompleted(int profiling_phase) override;
private:
friend struct DefaultSingletonTraits<ProfilerControllerImpl>;
// Contact child processes and get their profiler data.
- void GetProfilerDataFromChildProcesses(int sequence_number);
+ void GetProfilerDataFromChildProcesses(int sequence_number,
+ int current_profiling_phase);
+
+ // Contact child processes and notify them of a profiling phase completion.
+ static void NotifyChildProcessesOfProfilingPhaseCompletion(
+ int profiling_phase);
ProfilerSubscriber* subscriber_;
diff --git a/chromium/content/browser/profiler_message_filter.cc b/chromium/content/browser/profiler_message_filter.cc
index ef8b2b72ffc..4bd85e21a54 100644
--- a/chromium/content/browser/profiler_message_filter.cc
+++ b/chromium/content/browser/profiler_message_filter.cc
@@ -11,9 +11,8 @@
namespace content {
-ProfilerMessageFilter::ProfilerMessageFilter(int process_type)
- : BrowserMessageFilter(ChildProcessMsgStart),
- process_type_(process_type) {
+ProfilerMessageFilter::ProfilerMessageFilter(content::ProcessType process_type)
+ : BrowserMessageFilter(ChildProcessMsgStart), process_type_(process_type) {
}
void ProfilerMessageFilter::OnChannelConnected(int32 peer_pid) {
diff --git a/chromium/content/browser/profiler_message_filter.h b/chromium/content/browser/profiler_message_filter.h
index df4ce53e061..875e45d0aa6 100644
--- a/chromium/content/browser/profiler_message_filter.h
+++ b/chromium/content/browser/profiler_message_filter.h
@@ -8,6 +8,7 @@
#include <string>
#include "content/public/browser/browser_message_filter.h"
+#include "content/public/common/process_type.h"
namespace tracked_objects {
struct ProcessDataSnapshot;
@@ -18,7 +19,7 @@ namespace content {
// This class sends and receives profiler messages in the browser process.
class ProfilerMessageFilter : public BrowserMessageFilter {
public:
- explicit ProfilerMessageFilter(int process_type);
+ explicit ProfilerMessageFilter(content::ProcessType process_type);
// BrowserMessageFilter implementation.
void OnChannelConnected(int32 peer_pid) override;
@@ -39,7 +40,7 @@ class ProfilerMessageFilter : public BrowserMessageFilter {
void OnTcmallocStats(const std::string& output);
#endif
- int process_type_;
+ content::ProcessType process_type_;
DISALLOW_COPY_AND_ASSIGN(ProfilerMessageFilter);
};
diff --git a/chromium/content/browser/push_messaging/OWNERS b/chromium/content/browser/push_messaging/OWNERS
index de1f744c561..d08448c9a60 100644
--- a/chromium/content/browser/push_messaging/OWNERS
+++ b/chromium/content/browser/push_messaging/OWNERS
@@ -1,2 +1,9 @@
-mvanouwerkerk@chromium.org
+# Push Messaging OWNERS
+#
+# This file also covers ownership of the following directories:
+# //content/child/push_messaging/
+# //content/renderer/push_messaging/
+johnme@chromium.org
+mvanouwerkerk@chromium.org
+peter@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
index ed9046f0565..946e6d5cb57 100644
--- a/chromium/content/browser/push_messaging/push_messaging_message_filter.cc
+++ b/chromium/content/browser/push_messaging/push_messaging_message_filter.cc
@@ -7,177 +7,820 @@
#include <string>
#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/logging.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_core.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
+#include "content/browser/service_worker/service_worker_storage.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"
+#include "content/public/common/child_process_host.h"
+#include "content/public/common/push_messaging_status.h"
+#include "third_party/WebKit/public/platform/modules/push_messaging/WebPushPermissionStatus.h"
namespace content {
+
+const char kPushSenderIdServiceWorkerKey[] = "push_sender_id";
+const char kPushRegistrationIdServiceWorkerKey[] = "push_registration_id";
+
namespace {
+// These UMA methods are only called from IO thread, but it would be acceptable
+// (even though slightly racy) to call them from UI thread as well, see
+// https://groups.google.com/a/chromium.org/d/msg/chromium-dev/FNzZRJtN2aw/Aw0CWAXJJ1kJ
void RecordRegistrationStatus(PushRegistrationStatus status) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
UMA_HISTOGRAM_ENUMERATION("PushMessaging.RegistrationStatus",
status,
PUSH_REGISTRATION_STATUS_LAST + 1);
}
+void RecordUnregistrationStatus(PushUnregistrationStatus status) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ UMA_HISTOGRAM_ENUMERATION("PushMessaging.UnregistrationStatus",
+ status,
+ PUSH_UNREGISTRATION_STATUS_LAST + 1);
+}
+
+void RecordGetRegistrationStatus(PushGetRegistrationStatus status) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ UMA_HISTOGRAM_ENUMERATION("PushMessaging.GetRegistrationStatus",
+ status,
+ PUSH_GETREGISTRATION_STATUS_LAST + 1);
+}
+
} // namespace
+struct PushMessagingMessageFilter::RegisterData {
+ RegisterData();
+ RegisterData(const RegisterData& other) = default;
+ bool FromDocument() const;
+ int request_id;
+ GURL requesting_origin;
+ int64_t service_worker_registration_id;
+ bool user_visible;
+ // The following member should only be read if FromDocument() is true.
+ int render_frame_id;
+};
+
+
+// Inner core of this message filter which lives on the UI thread.
+class PushMessagingMessageFilter::Core {
+ public:
+ Core(const base::WeakPtr<PushMessagingMessageFilter>& io_parent,
+ int render_process_id);
+
+ // Public Register methods on UI thread --------------------------------------
+
+ // Called via PostTask from IO thread.
+ void RegisterOnUI(const RegisterData& data, const std::string& sender_id);
+
+ // Public Unregister methods on UI thread ------------------------------------
+
+ // Called via PostTask from IO thread.
+ void UnregisterFromService(int request_id,
+ int64_t service_worker_registration_id,
+ const GURL& requesting_origin,
+ const std::string& sender_id);
+
+ // Public GetPermission methods on UI thread ---------------------------------
+
+ // Called via PostTask from IO thread.
+ void GetPermissionStatusOnUI(const GURL& requesting_origin,
+ bool user_visible,
+ int request_id);
+
+ // Public helper methods on UI thread ----------------------------------------
+
+ // Called (directly) from both the UI and IO threads.
+ bool is_incognito() const { return is_incognito_; }
+
+ // Returns a push messaging service. May return null.
+ PushMessagingService* service();
+
+ private:
+ friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>;
+ friend class base::DeleteHelper<Core>;
+
+ ~Core();
+
+ // Private Register methods on UI thread -------------------------------------
+
+ void DidRegister(const RegisterData& data,
+ const std::string& push_registration_id,
+ PushRegistrationStatus status);
+
+ // Private Unregister methods on UI thread -----------------------------------
+
+ void DidUnregisterFromService(int request_id,
+ int64_t service_worker_registration_id,
+ PushUnregistrationStatus unregistration_status);
+
+ // Private helper methods on UI thread ---------------------------------------
+
+ void Send(IPC::Message* message);
+
+ // Outer part of this message filter which lives on the IO thread.
+ base::WeakPtr<PushMessagingMessageFilter> io_parent_;
+
+ int render_process_id_;
+
+ bool is_incognito_;
+
+ base::WeakPtrFactory<Core> weak_factory_ui_to_ui_;
+
+ DISALLOW_COPY_AND_ASSIGN(Core);
+};
+
+
+PushMessagingMessageFilter::RegisterData::RegisterData()
+ : request_id(0),
+ service_worker_registration_id(0),
+ user_visible(false),
+ render_frame_id(ChildProcessHost::kInvalidUniqueID) {
+}
+
+bool PushMessagingMessageFilter::RegisterData::FromDocument() const {
+ return render_frame_id != ChildProcessHost::kInvalidUniqueID;
+}
+
+PushMessagingMessageFilter::Core::Core(
+ const base::WeakPtr<PushMessagingMessageFilter>& io_parent,
+ int render_process_id)
+ : io_parent_(io_parent),
+ render_process_id_(render_process_id),
+ weak_factory_ui_to_ui_(this) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ RenderProcessHost* process_host =
+ RenderProcessHost::FromID(render_process_id_); // Can't be null yet.
+ is_incognito_ = process_host->GetBrowserContext()->IsOffTheRecord();
+}
+
+PushMessagingMessageFilter::Core::~Core() {}
+
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) {
+ weak_factory_io_to_io_(this) {
+ // Although this class is used only on the IO thread, it is constructed on UI.
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ // Normally, it would be unsafe to obtain a weak pointer from the UI thread,
+ // but it's ok in the constructor since we can't be destroyed before our
+ // constructor finishes.
+ ui_core_.reset(new Core(weak_factory_io_to_io_.GetWeakPtr(),
+ render_process_id));
+ PushMessagingService* push_service = ui_core_->service();
+ if (push_service)
+ push_endpoint_ = push_service->GetPushEndpoint();
}
PushMessagingMessageFilter::~PushMessagingMessageFilter() {}
+void PushMessagingMessageFilter::OnDestruct() const {
+ BrowserThread::DeleteOnIOThread::Destruct(this);
+}
+
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_HANDLER(PushMessagingHostMsg_RegisterFromDocument,
+ OnRegisterFromDocument)
+ IPC_MESSAGE_HANDLER(PushMessagingHostMsg_RegisterFromWorker,
+ OnRegisterFromWorker)
+ IPC_MESSAGE_HANDLER(PushMessagingHostMsg_Unregister,
+ OnUnregister)
+ IPC_MESSAGE_HANDLER(PushMessagingHostMsg_GetRegistration, OnGetRegistration)
+ IPC_MESSAGE_HANDLER(PushMessagingHostMsg_GetPermissionStatus,
+ OnGetPermissionStatus)
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));
+// Register methods on both IO and UI threads, merged in order of use from
+// PushMessagingMessageFilter and Core.
+// -----------------------------------------------------------------------------
+
+void PushMessagingMessageFilter::OnRegisterFromDocument(
+ int render_frame_id,
+ int request_id,
+ const std::string& sender_id,
+ bool user_visible,
+ int64_t service_worker_registration_id) {
+ DCHECK_CURRENTLY_ON(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);
+ // TODO(peter): Persist |user_visible| in Service Worker storage.
+ RegisterData data;
+ data.request_id = request_id;
+ data.service_worker_registration_id = service_worker_registration_id;
+ data.render_frame_id = render_frame_id;
+ data.user_visible = user_visible;
+
+ ServiceWorkerRegistration* service_worker_registration =
+ service_worker_context_->GetLiveRegistration(
+ service_worker_registration_id);
+ if (!service_worker_registration ||
+ !service_worker_registration->active_version()) {
+ SendRegisterError(data, PUSH_REGISTRATION_STATUS_NO_SERVICE_WORKER);
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) {
+ data.requesting_origin = service_worker_registration->pattern().GetOrigin();
+
+ service_worker_context_->StoreRegistrationUserData(
+ service_worker_registration_id,
+ data.requesting_origin,
+ kPushSenderIdServiceWorkerKey,
+ sender_id,
+ base::Bind(&PushMessagingMessageFilter::DidPersistSenderId,
+ weak_factory_io_to_io_.GetWeakPtr(),
+ data, sender_id));
+}
+
+void PushMessagingMessageFilter::OnRegisterFromWorker(
+ int request_id,
+ int64_t service_worker_registration_id,
+ bool user_visible) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ RegisterData data;
+ data.request_id = request_id;
+ data.service_worker_registration_id = service_worker_registration_id;
+ data.user_visible = user_visible;
+
+ ServiceWorkerRegistration* service_worker_registration =
+ service_worker_context_->GetLiveRegistration(
+ service_worker_registration_id);
+ if (!service_worker_registration) {
+ SendRegisterError(data, PUSH_REGISTRATION_STATUS_NO_SERVICE_WORKER);
+ return;
+ }
+ data.requesting_origin = service_worker_registration->pattern().GetOrigin();
+
+ // This sender_id will be ignored; instead it will be fetched from storage.
+ CheckForExistingRegistration(data, std::string() /* sender_id */);
+}
+
+void PushMessagingMessageFilter::DidPersistSenderId(
+ const RegisterData& data,
+ const std::string& sender_id,
+ ServiceWorkerStatusCode service_worker_status) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- ServiceWorkerProviderHost* service_worker_host =
- service_worker_context_->context()->GetProviderHost(
- render_process_id_, service_worker_provider_id);
+ if (service_worker_status != SERVICE_WORKER_OK)
+ SendRegisterError(data, PUSH_REGISTRATION_STATUS_STORAGE_ERROR);
+ else
+ CheckForExistingRegistration(data, sender_id);
+}
- if (service_worker_host && service_worker_host->active_version()) {
+void PushMessagingMessageFilter::CheckForExistingRegistration(
+ const RegisterData& data,
+ const std::string& sender_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ service_worker_context_->GetRegistrationUserData(
+ data.service_worker_registration_id,
+ kPushRegistrationIdServiceWorkerKey,
+ base::Bind(&PushMessagingMessageFilter::DidCheckForExistingRegistration,
+ weak_factory_io_to_io_.GetWeakPtr(), data, sender_id));
+}
+
+void PushMessagingMessageFilter::DidCheckForExistingRegistration(
+ const RegisterData& data,
+ const std::string& sender_id,
+ const std::string& push_registration_id,
+ ServiceWorkerStatusCode service_worker_status) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (service_worker_status == SERVICE_WORKER_OK) {
+ SendRegisterSuccess(data, PUSH_REGISTRATION_STATUS_SUCCESS_FROM_CACHE,
+ push_registration_id);
+ return;
+ }
+ // TODO(johnme): The spec allows the register algorithm to reject with an
+ // AbortError when accessing storage fails. Perhaps we should do that if
+ // service_worker_status != SERVICE_WORKER_ERROR_NOT_FOUND instead of
+ // attempting to do a fresh registration?
+ // https://w3c.github.io/push-api/#widl-PushRegistrationManager-register-Promise-PushRegistration
+ if (data.FromDocument()) {
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));
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&Core::RegisterOnUI, base::Unretained(ui_core_.get()),
+ data, sender_id));
} else {
- Send(new PushMessagingMsg_PermissionStatusFailure(
- render_frame_id, permission_callback_id));
+ service_worker_context_->GetRegistrationUserData(
+ data.service_worker_registration_id,
+ kPushSenderIdServiceWorkerKey,
+ base::Bind(&PushMessagingMessageFilter::DidGetSenderIdFromStorage,
+ weak_factory_io_to_io_.GetWeakPtr(), data));
}
}
-void PushMessagingMessageFilter::DoRegister(
- int render_frame_id,
- int callbacks_id,
+void PushMessagingMessageFilter::DidGetSenderIdFromStorage(
+ const RegisterData& data,
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);
+ ServiceWorkerStatusCode service_worker_status) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (service_worker_status != SERVICE_WORKER_OK) {
+ SendRegisterError(data, PUSH_REGISTRATION_STATUS_NO_SENDER_ID);
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));
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&Core::RegisterOnUI, base::Unretained(ui_core_.get()),
+ data, sender_id));
}
-void PushMessagingMessageFilter::DoPermissionStatusRequest(
- const GURL& requesting_origin,
- int render_frame_id,
- int callback_id) {
+void PushMessagingMessageFilter::Core::RegisterOnUI(
+ const PushMessagingMessageFilter::RegisterData& data,
+ const std::string& sender_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- blink::WebPushPermissionStatus permission_value =
- service()->GetPermissionStatus(
- requesting_origin, render_process_id_, render_frame_id);
+ PushMessagingService* push_service = service();
+ if (!push_service) {
+ if (!is_incognito()) {
+ // TODO(johnme): Might be better not to expose the API in this case.
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&PushMessagingMessageFilter::SendRegisterError,
+ io_parent_,
+ data, PUSH_REGISTRATION_STATUS_SERVICE_NOT_AVAILABLE));
+ } else {
+ // Prevent websites from detecting incognito mode, by emulating what would
+ // have happened if we had a PushMessagingService available.
+ if (!data.FromDocument() || !data.user_visible) {
+ // Throw a permission denied error under the same circumstances.
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&PushMessagingMessageFilter::SendRegisterError,
+ io_parent_,
+ data,
+ PUSH_REGISTRATION_STATUS_INCOGNITO_PERMISSION_DENIED));
+ }
+ // Else leave the promise hanging forever, to simulate a user ignoring the
+ // infobar. TODO(johnme): Simulate the user dismissing the infobar after a
+ // random time period.
+ }
+ return;
+ }
- Send(new PushMessagingMsg_PermissionStatusResult(
- render_frame_id, callback_id, permission_value));
+ if (data.FromDocument()) {
+ push_service->RegisterFromDocument(
+ data.requesting_origin, data.service_worker_registration_id, sender_id,
+ render_process_id_, data.render_frame_id, data.user_visible,
+ base::Bind(&Core::DidRegister, weak_factory_ui_to_ui_.GetWeakPtr(),
+ data));
+ } else {
+ push_service->RegisterFromWorker(
+ data.requesting_origin, data.service_worker_registration_id, sender_id,
+ data.user_visible,
+ base::Bind(&Core::DidRegister, weak_factory_ui_to_ui_.GetWeakPtr(),
+ data));
+ }
}
-void PushMessagingMessageFilter::DidRegister(
- int render_frame_id,
- int callbacks_id,
- const GURL& push_endpoint,
+void PushMessagingMessageFilter::Core::DidRegister(
+ const RegisterData& data,
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));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (status == PUSH_REGISTRATION_STATUS_SUCCESS_FROM_PUSH_SERVICE) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&PushMessagingMessageFilter::PersistRegistrationOnIO,
+ io_parent_, data, push_registration_id));
+ } else {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&PushMessagingMessageFilter::SendRegisterError, io_parent_,
+ data, status));
+ }
+}
+
+void PushMessagingMessageFilter::PersistRegistrationOnIO(
+ const RegisterData& data,
+ const std::string& push_registration_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ service_worker_context_->StoreRegistrationUserData(
+ data.service_worker_registration_id,
+ data.requesting_origin,
+ kPushRegistrationIdServiceWorkerKey,
+ push_registration_id,
+ base::Bind(&PushMessagingMessageFilter::DidPersistRegistrationOnIO,
+ weak_factory_io_to_io_.GetWeakPtr(),
+ data, push_registration_id));
+}
+
+void PushMessagingMessageFilter::DidPersistRegistrationOnIO(
+ const RegisterData& data,
+ const std::string& push_registration_id,
+ ServiceWorkerStatusCode service_worker_status) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (service_worker_status == SERVICE_WORKER_OK) {
+ SendRegisterSuccess(data,
+ PUSH_REGISTRATION_STATUS_SUCCESS_FROM_PUSH_SERVICE,
+ push_registration_id);
+ } else {
+ // TODO(johnme): Unregister, so PushMessagingServiceImpl can decrease count.
+ SendRegisterError(data, PUSH_REGISTRATION_STATUS_STORAGE_ERROR);
+ }
+}
+
+void PushMessagingMessageFilter::SendRegisterError(
+ const RegisterData& data, PushRegistrationStatus status) {
+ // Only called from IO thread, but would be safe to call from UI thread.
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (data.FromDocument()) {
+ Send(new PushMessagingMsg_RegisterFromDocumentError(
+ data.render_frame_id, data.request_id, status));
+ } else {
+ Send(new PushMessagingMsg_RegisterFromWorkerError(
+ data.request_id, status));
+ }
+ RecordRegistrationStatus(status);
+}
+
+void PushMessagingMessageFilter::SendRegisterSuccess(
+ const RegisterData& data,
+ PushRegistrationStatus status,
+ const std::string& push_registration_id) {
+ // Only called from IO thread, but would be safe to call from UI thread.
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (push_endpoint_.is_empty()) {
+ // This shouldn't be possible in incognito mode, since we've already checked
+ // that we have an existing registration. Hence it's ok to throw an error.
+ DCHECK(!ui_core_->is_incognito());
+ SendRegisterError(data, PUSH_REGISTRATION_STATUS_SERVICE_NOT_AVAILABLE);
+ return;
+ }
+ if (data.FromDocument()) {
+ Send(new PushMessagingMsg_RegisterFromDocumentSuccess(
+ data.render_frame_id,
+ data.request_id, push_endpoint_, push_registration_id));
} else {
- Send(new PushMessagingMsg_RegisterError(
- render_frame_id, callbacks_id, status));
+ Send(new PushMessagingMsg_RegisterFromWorkerSuccess(
+ data.request_id, push_endpoint_, push_registration_id));
}
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();
+// Unregister methods on both IO and UI threads, merged in order of use from
+// PushMessagingMessageFilter and Core.
+// -----------------------------------------------------------------------------
+
+void PushMessagingMessageFilter::OnUnregister(
+ int request_id, int64_t service_worker_registration_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ ServiceWorkerRegistration* service_worker_registration =
+ service_worker_context_->GetLiveRegistration(
+ service_worker_registration_id);
+ if (!service_worker_registration) {
+ DidUnregister(request_id, PUSH_UNREGISTRATION_STATUS_NO_SERVICE_WORKER);
+ return;
+ }
+
+ service_worker_context_->GetRegistrationUserData(
+ service_worker_registration_id,
+ kPushRegistrationIdServiceWorkerKey,
+ base::Bind(
+ &PushMessagingMessageFilter::UnregisterHavingGottenPushRegistrationId,
+ weak_factory_io_to_io_.GetWeakPtr(), request_id,
+ service_worker_registration_id,
+ service_worker_registration->pattern().GetOrigin()));
+}
+
+void PushMessagingMessageFilter::UnregisterHavingGottenPushRegistrationId(
+ int request_id,
+ int64_t service_worker_registration_id,
+ const GURL& requesting_origin,
+ const std::string& push_registration_id, // Unused, we just want the status
+ ServiceWorkerStatusCode service_worker_status) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (service_worker_status == SERVICE_WORKER_OK) {
+ service_worker_context_->GetRegistrationUserData(
+ service_worker_registration_id,
+ kPushSenderIdServiceWorkerKey,
+ base::Bind(
+ &PushMessagingMessageFilter::UnregisterHavingGottenSenderId,
+ weak_factory_io_to_io_.GetWeakPtr(),
+ request_id,
+ service_worker_registration_id,
+ requesting_origin));
+ } else {
+ // Errors are handled the same, whether we were trying to get the
+ // push_registration_id or the sender_id.
+ UnregisterHavingGottenSenderId(request_id, service_worker_registration_id,
+ requesting_origin,
+ std::string() /* sender_id */,
+ service_worker_status);
+ }
+}
+
+void PushMessagingMessageFilter::UnregisterHavingGottenSenderId(
+ int request_id,
+ int64_t service_worker_registration_id,
+ const GURL& requesting_origin,
+ const std::string& sender_id,
+ ServiceWorkerStatusCode service_worker_status) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ switch (service_worker_status) {
+ case SERVICE_WORKER_OK:
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&Core::UnregisterFromService,
+ base::Unretained(ui_core_.get()), request_id,
+ service_worker_registration_id, requesting_origin,
+ sender_id));
+ break;
+ case SERVICE_WORKER_ERROR_NOT_FOUND:
+ // We did not find a registration, stop here and notify the renderer that
+ // it was a success even though we did not unregister.
+ DidUnregister(request_id,
+ PUSH_UNREGISTRATION_STATUS_SUCCESS_WAS_NOT_REGISTERED);
+ break;
+ case SERVICE_WORKER_ERROR_FAILED:
+ DidUnregister(request_id,
+ PUSH_UNREGISTRATION_STATUS_STORAGE_ERROR);
+ break;
+ case SERVICE_WORKER_ERROR_ABORT:
+ case SERVICE_WORKER_ERROR_START_WORKER_FAILED:
+ case SERVICE_WORKER_ERROR_PROCESS_NOT_FOUND:
+ case SERVICE_WORKER_ERROR_EXISTS:
+ case SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED:
+ case SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED:
+ case SERVICE_WORKER_ERROR_IPC_FAILED:
+ case SERVICE_WORKER_ERROR_NETWORK:
+ case SERVICE_WORKER_ERROR_SECURITY:
+ case SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED:
+ case SERVICE_WORKER_ERROR_STATE:
+ case SERVICE_WORKER_ERROR_TIMEOUT:
+ case SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED:
+ case SERVICE_WORKER_ERROR_DISK_CACHE:
+ case SERVICE_WORKER_ERROR_MAX_VALUE:
+ NOTREACHED() << "Got unexpected error code: " << service_worker_status
+ << " " << ServiceWorkerStatusToString(service_worker_status);
+ DidUnregister(request_id, PUSH_UNREGISTRATION_STATUS_STORAGE_ERROR);
+ break;
+ }
+}
+
+void PushMessagingMessageFilter::Core::UnregisterFromService(
+ int request_id,
+ int64_t service_worker_registration_id,
+ const GURL& requesting_origin,
+ const std::string& sender_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ PushMessagingService* push_service = service();
+ if (!push_service) {
+ // This shouldn't be possible in incognito mode, since we've already checked
+ // that we have an existing registration. Hence it's ok to throw an error.
+ DCHECK(!is_incognito());
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&PushMessagingMessageFilter::DidUnregister, io_parent_,
+ request_id,
+ PUSH_UNREGISTRATION_STATUS_SERVICE_NOT_AVAILABLE));
+ return;
+ }
+
+ push_service->Unregister(
+ requesting_origin, service_worker_registration_id, sender_id,
+ base::Bind(&Core::DidUnregisterFromService,
+ weak_factory_ui_to_ui_.GetWeakPtr(),
+ request_id, service_worker_registration_id));
+}
+
+void PushMessagingMessageFilter::Core::DidUnregisterFromService(
+ int request_id,
+ int64_t service_worker_registration_id,
+ PushUnregistrationStatus unregistration_status) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ switch (unregistration_status) {
+ case PUSH_UNREGISTRATION_STATUS_SUCCESS_UNREGISTERED:
+ case PUSH_UNREGISTRATION_STATUS_SUCCESS_WAS_NOT_REGISTERED:
+ case PUSH_UNREGISTRATION_STATUS_PENDING_NETWORK_ERROR:
+ case PUSH_UNREGISTRATION_STATUS_PENDING_SERVICE_ERROR:
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&PushMessagingMessageFilter::ClearRegistrationData,
+ io_parent_, request_id, service_worker_registration_id,
+ unregistration_status));
+ break;
+ case PUSH_UNREGISTRATION_STATUS_NO_SERVICE_WORKER:
+ case PUSH_UNREGISTRATION_STATUS_SERVICE_NOT_AVAILABLE:
+ case PUSH_UNREGISTRATION_STATUS_STORAGE_ERROR:
+ case PUSH_UNREGISTRATION_STATUS_NETWORK_ERROR:
+ NOTREACHED();
+ break;
+ }
+}
+
+void PushMessagingMessageFilter::ClearRegistrationData(
+ int request_id,
+ int64_t service_worker_registration_id,
+ PushUnregistrationStatus unregistration_status) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ service_worker_context_->ClearRegistrationUserData(
+ service_worker_registration_id,
+ kPushRegistrationIdServiceWorkerKey,
+ base::Bind(&PushMessagingMessageFilter::DidClearRegistrationData,
+ weak_factory_io_to_io_.GetWeakPtr(),
+ request_id, unregistration_status));
+}
+
+void PushMessagingMessageFilter::DidClearRegistrationData(
+ int request_id,
+ PushUnregistrationStatus unregistration_status,
+ ServiceWorkerStatusCode service_worker_status) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (service_worker_status != SERVICE_WORKER_OK &&
+ service_worker_status != SERVICE_WORKER_ERROR_NOT_FOUND) {
+ unregistration_status = PUSH_UNREGISTRATION_STATUS_STORAGE_ERROR;
+ DLOG(WARNING) << "Got unexpected error code: " << service_worker_status
+ << " " << ServiceWorkerStatusToString(service_worker_status);
+ }
+
+ DidUnregister(request_id, unregistration_status);
+}
+
+void PushMessagingMessageFilter::DidUnregister(
+ int request_id,
+ PushUnregistrationStatus unregistration_status) {
+ // Only called from IO thread, but would be safe to call from UI thread.
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ switch (unregistration_status) {
+ case PUSH_UNREGISTRATION_STATUS_SUCCESS_UNREGISTERED:
+ case PUSH_UNREGISTRATION_STATUS_PENDING_NETWORK_ERROR:
+ case PUSH_UNREGISTRATION_STATUS_PENDING_SERVICE_ERROR:
+ Send(new PushMessagingMsg_UnregisterSuccess(request_id, true));
+ break;
+ case PUSH_UNREGISTRATION_STATUS_SUCCESS_WAS_NOT_REGISTERED:
+ Send(new PushMessagingMsg_UnregisterSuccess(request_id, false));
+ break;
+ case PUSH_UNREGISTRATION_STATUS_NO_SERVICE_WORKER:
+ case PUSH_UNREGISTRATION_STATUS_SERVICE_NOT_AVAILABLE:
+ case PUSH_UNREGISTRATION_STATUS_STORAGE_ERROR:
+ Send(new PushMessagingMsg_UnregisterError(
+ request_id, blink::WebPushError::ErrorTypeAbort,
+ PushUnregistrationStatusToString(unregistration_status)));
+ break;
+ case PUSH_UNREGISTRATION_STATUS_NETWORK_ERROR:
+ NOTREACHED();
+ break;
+ }
+ RecordUnregistrationStatus(unregistration_status);
+}
+
+// GetRegistration methods on both IO and UI threads, merged in order of use
+// from PushMessagingMessageFilter and Core.
+// -----------------------------------------------------------------------------
+
+void PushMessagingMessageFilter::OnGetRegistration(
+ int request_id,
+ int64_t service_worker_registration_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ // TODO(johnme): Validate arguments?
+ service_worker_context_->GetRegistrationUserData(
+ service_worker_registration_id,
+ kPushRegistrationIdServiceWorkerKey,
+ base::Bind(&PushMessagingMessageFilter::DidGetRegistration,
+ weak_factory_io_to_io_.GetWeakPtr(), request_id));
+}
+
+void PushMessagingMessageFilter::DidGetRegistration(
+ int request_id,
+ const std::string& push_registration_id,
+ ServiceWorkerStatusCode service_worker_status) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ PushGetRegistrationStatus get_status =
+ PUSH_GETREGISTRATION_STATUS_STORAGE_ERROR;
+ switch (service_worker_status) {
+ case SERVICE_WORKER_OK:
+ if (push_endpoint_.is_empty()) {
+ // Return not found in incognito mode, so websites can't detect it.
+ get_status =
+ ui_core_->is_incognito()
+ ? PUSH_GETREGISTRATION_STATUS_INCOGNITO_REGISTRATION_NOT_FOUND
+ : PUSH_GETREGISTRATION_STATUS_SERVICE_NOT_AVAILABLE;
+ break;
+ }
+ Send(new PushMessagingMsg_GetRegistrationSuccess(request_id,
+ push_endpoint_,
+ push_registration_id));
+ RecordGetRegistrationStatus(PUSH_GETREGISTRATION_STATUS_SUCCESS);
+ return;
+ case SERVICE_WORKER_ERROR_NOT_FOUND:
+ get_status = PUSH_GETREGISTRATION_STATUS_REGISTRATION_NOT_FOUND;
+ break;
+ case SERVICE_WORKER_ERROR_FAILED:
+ get_status = PUSH_GETREGISTRATION_STATUS_STORAGE_ERROR;
+ break;
+ case SERVICE_WORKER_ERROR_ABORT:
+ case SERVICE_WORKER_ERROR_START_WORKER_FAILED:
+ case SERVICE_WORKER_ERROR_PROCESS_NOT_FOUND:
+ case SERVICE_WORKER_ERROR_EXISTS:
+ case SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED:
+ case SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED:
+ case SERVICE_WORKER_ERROR_IPC_FAILED:
+ case SERVICE_WORKER_ERROR_NETWORK:
+ case SERVICE_WORKER_ERROR_SECURITY:
+ case SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED:
+ case SERVICE_WORKER_ERROR_STATE:
+ case SERVICE_WORKER_ERROR_TIMEOUT:
+ case SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED:
+ case SERVICE_WORKER_ERROR_DISK_CACHE:
+ case SERVICE_WORKER_ERROR_MAX_VALUE:
+ NOTREACHED() << "Got unexpected error code: " << service_worker_status
+ << " " << ServiceWorkerStatusToString(service_worker_status);
+ get_status = PUSH_GETREGISTRATION_STATUS_STORAGE_ERROR;
+ break;
}
- return service_;
+ Send(new PushMessagingMsg_GetRegistrationError(request_id, get_status));
+ RecordGetRegistrationStatus(get_status);
+}
+
+// GetPermission methods on both IO and UI threads, merged in order of use from
+// PushMessagingMessageFilter and Core.
+// -----------------------------------------------------------------------------
+
+void PushMessagingMessageFilter::OnGetPermissionStatus(
+ int request_id,
+ int64_t service_worker_registration_id,
+ bool user_visible) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ ServiceWorkerRegistration* service_worker_registration =
+ service_worker_context_->GetLiveRegistration(
+ service_worker_registration_id);
+ if (!service_worker_registration) {
+ Send(new PushMessagingMsg_GetPermissionStatusError(
+ request_id, blink::WebPushError::ErrorTypeAbort));
+ return;
+ }
+
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&Core::GetPermissionStatusOnUI,
+ base::Unretained(ui_core_.get()),
+ service_worker_registration->pattern().GetOrigin(),
+ user_visible, request_id));
+}
+
+void PushMessagingMessageFilter::Core::GetPermissionStatusOnUI(
+ const GURL& requesting_origin, bool user_visible, int request_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ blink::WebPushPermissionStatus permission_status;
+ PushMessagingService* push_service = service();
+ if (push_service) {
+ if (!user_visible && !push_service->SupportNonVisibleMessages()) {
+ Send(new PushMessagingMsg_GetPermissionStatusError(
+ request_id, blink::WebPushError::ErrorTypeNotSupported));
+ return;
+ }
+ GURL embedding_origin = requesting_origin;
+ permission_status = push_service->GetPermissionStatus(requesting_origin,
+ embedding_origin,
+ user_visible);
+ } else if (is_incognito()) {
+ // Return prompt, so the website can't detect incognito mode.
+ permission_status = blink::WebPushPermissionStatusPrompt;
+ } else {
+ Send(new PushMessagingMsg_GetPermissionStatusError(
+ request_id, blink::WebPushError::ErrorTypeAbort));
+ return;
+ }
+ Send(new PushMessagingMsg_GetPermissionStatusSuccess(request_id,
+ permission_status));
+}
+
+// Helper methods on both IO and UI threads, merged from
+// PushMessagingMessageFilter and Core.
+// -----------------------------------------------------------------------------
+
+void PushMessagingMessageFilter::Core::Send(IPC::Message* message) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&PushMessagingMessageFilter::SendIPC, io_parent_,
+ base::Passed(make_scoped_ptr(message))));
+}
+
+void PushMessagingMessageFilter::SendIPC(scoped_ptr<IPC::Message> message) {
+ Send(message.release());
+}
+
+PushMessagingService* PushMessagingMessageFilter::Core::service() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ RenderProcessHost* process_host =
+ RenderProcessHost::FromID(render_process_id_);
+ return process_host
+ ? process_host->GetBrowserContext()->GetPushMessagingService()
+ : nullptr;
}
} // 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
index 4f9ebd9f994..afd8d6743a4 100644
--- a/chromium/content/browser/push_messaging/push_messaging_message_filter.h
+++ b/chromium/content/browser/push_messaging/push_messaging_message_filter.h
@@ -5,10 +5,13 @@
#ifndef CONTENT_BROWSER_PUSH_MESSAGING_PUSH_MESSAGING_MESSAGE_FILTER_H_
#define CONTENT_BROWSER_PUSH_MESSAGING_PUSH_MESSAGING_MESSAGE_FILTER_H_
+#include <stdint.h>
#include <string>
#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
+#include "content/common/service_worker/service_worker_status_code.h"
#include "content/public/browser/browser_message_filter.h"
#include "content/public/common/push_messaging_status.h"
#include "url/gurl.h"
@@ -20,6 +23,9 @@ namespace content {
class PushMessagingService;
class ServiceWorkerContextWrapper;
+extern const char kPushSenderIdServiceWorkerKey[];
+extern const char kPushRegistrationIdServiceWorkerKey[];
+
class PushMessagingMessageFilter : public BrowserMessageFilter {
public:
PushMessagingMessageFilter(
@@ -27,46 +33,127 @@ class PushMessagingMessageFilter : public BrowserMessageFilter {
ServiceWorkerContextWrapper* service_worker_context);
private:
+ struct RegisterData;
+ class Core;
+
+ friend class BrowserThread;
+ friend class base::DeleteHelper<PushMessagingMessageFilter>;
+
~PushMessagingMessageFilter() override;
// BrowserMessageFilter implementation.
+ void OnDestruct() const override;
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_;
+ // Register methods on IO thread ---------------------------------------------
+
+ void OnRegisterFromDocument(int render_frame_id,
+ int request_id,
+ const std::string& sender_id,
+ bool user_visible,
+ int64_t service_worker_registration_id);
+
+ void OnRegisterFromWorker(int request_id,
+ int64_t service_worker_registration_id,
+ bool user_visible);
+
+ void DidPersistSenderId(const RegisterData& data,
+ const std::string& sender_id,
+ ServiceWorkerStatusCode service_worker_status);
+
+ // sender_id is ignored if data.FromDocument() is false.
+ void CheckForExistingRegistration(
+ const RegisterData& data,
+ const std::string& sender_id);
+
+ // sender_id is ignored if data.FromDocument() is false.
+ void DidCheckForExistingRegistration(
+ const RegisterData& data,
+ const std::string& sender_id,
+ const std::string& push_registration_id,
+ ServiceWorkerStatusCode service_worker_status);
+
+ void DidGetSenderIdFromStorage(const RegisterData& data,
+ const std::string& sender_id,
+ ServiceWorkerStatusCode service_worker_status);
+
+ // Called via PostTask from UI thread.
+ void PersistRegistrationOnIO(const RegisterData& data,
+ const std::string& push_registration_id);
+
+ void DidPersistRegistrationOnIO(
+ const RegisterData& data,
+ const std::string& push_registration_id,
+ ServiceWorkerStatusCode service_worker_status);
+
+ // Called both from IO thread, and via PostTask from UI thread.
+ void SendRegisterError(const RegisterData& data,
+ PushRegistrationStatus status);
+ // Called both from IO thread, and via PostTask from UI thread.
+ void SendRegisterSuccess(const RegisterData& data,
+ PushRegistrationStatus status,
+ const std::string& push_registration_id);
+
+ // Unregister methods on IO thread -------------------------------------------
+
+ void OnUnregister(int request_id, int64_t service_worker_registration_id);
+
+ void UnregisterHavingGottenPushRegistrationId(
+ int request_id,
+ int64_t service_worker_registration_id,
+ const GURL& requesting_origin,
+ const std::string& push_registration_id,
+ ServiceWorkerStatusCode service_worker_status);
+
+ void UnregisterHavingGottenSenderId(
+ int request_id,
+ int64_t service_worker_registration_id,
+ const GURL& requesting_origin,
+ const std::string& sender_id,
+ ServiceWorkerStatusCode service_worker_status);
+
+ // Called via PostTask from UI thread.
+ void ClearRegistrationData(int request_id,
+ int64_t service_worker_registration_id,
+ PushUnregistrationStatus unregistration_status);
+
+ void DidClearRegistrationData(int request_id,
+ PushUnregistrationStatus unregistration_status,
+ ServiceWorkerStatusCode service_worker_status);
+
+ // Called both from IO thread, and via PostTask from UI thread.
+ void DidUnregister(int request_id,
+ PushUnregistrationStatus unregistration_status);
+
+ // GetRegistration methods on IO thread --------------------------------------
+
+ void OnGetRegistration(int request_id,
+ int64_t service_worker_registration_id);
+
+ void DidGetRegistration(int request_id,
+ const std::string& push_registration_id,
+ ServiceWorkerStatusCode status);
+
+ // GetPermission methods on IO thread ----------------------------------------
+
+ void OnGetPermissionStatus(int request_id,
+ int64_t service_worker_registration_id,
+ bool user_visible);
+
+ // Helper methods on IO thread -----------------------------------------------
+
+ // Called via PostTask from UI thread.
+ void SendIPC(scoped_ptr<IPC::Message> message);
+
+ // Inner core of this message filter which lives on the UI thread.
+ scoped_ptr<Core, BrowserThread::DeleteOnUIThread> ui_core_;
+
scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_;
- // Owned by the content embedder's browsing context.
- PushMessagingService* service_;
+ // Empty if no PushMessagingService was available when constructed.
+ GURL push_endpoint_;
- base::WeakPtrFactory<PushMessagingMessageFilter> weak_factory_;
+ base::WeakPtrFactory<PushMessagingMessageFilter> weak_factory_io_to_io_;
DISALLOW_COPY_AND_ASSIGN(PushMessagingMessageFilter);
};
diff --git a/chromium/content/browser/push_messaging/push_messaging_router.cc b/chromium/content/browser/push_messaging/push_messaging_router.cc
index fc5218a8a2d..f5d75f2e70f 100644
--- a/chromium/content/browser/push_messaging/push_messaging_router.cc
+++ b/chromium/content/browser/push_messaging/push_messaging_router.cc
@@ -8,12 +8,25 @@
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/service_worker/service_worker_registration.h"
#include "content/browser/service_worker/service_worker_storage.h"
+#include "content/common/service_worker/service_worker_status_code.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/storage_partition.h"
namespace content {
+namespace {
+
+void RunDeliverCallback(
+ const PushMessagingRouter::DeliverMessageCallback& deliver_message_callback,
+ PushDeliveryStatus delivery_status) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(deliver_message_callback, delivery_status));
+}
+
+} // namespace
+
// static
void PushMessagingRouter::DeliverMessage(
BrowserContext* browser_context,
@@ -21,7 +34,7 @@ void PushMessagingRouter::DeliverMessage(
int64 service_worker_registration_id,
const std::string& data,
const DeliverMessageCallback& deliver_message_callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
StoragePartition* partition =
BrowserContext::GetStoragePartitionForSite(browser_context, origin);
scoped_refptr<ServiceWorkerContextWrapper> service_worker_context =
@@ -45,10 +58,10 @@ void PushMessagingRouter::FindServiceWorkerRegistration(
const std::string& data,
const DeliverMessageCallback& deliver_message_callback,
scoped_refptr<ServiceWorkerContextWrapper> service_worker_context) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(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_context->FindRegistrationForId(
service_worker_registration_id,
origin,
base::Bind(&PushMessagingRouter::FindServiceWorkerRegistrationCallback,
@@ -63,25 +76,40 @@ void PushMessagingRouter::FindServiceWorkerRegistrationCallback(
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));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ // TODO(mvanouwerkerk): UMA logging.
+ if (service_worker_status != SERVICE_WORKER_OK) {
+ RunDeliverCallback(deliver_message_callback,
+ PUSH_DELIVERY_STATUS_NO_SERVICE_WORKER);
+ return;
}
+
+ ServiceWorkerVersion* version = service_worker_registration->active_version();
+ if (!version) {
+ // Using NO_SERVICE_WORKER status will unsubscribe with GCM, so don't use it
+ // if we have a waiting version in the hopper. On the other hand, if there
+ // is no waiting version, it's an unexpected error case: we should have been
+ // informed the registration went away (but we may not have been:
+ // crbug.com/402458)
+ // TODO(falken): Promote the waiting version instead of returning error.
+ if (service_worker_registration->waiting_version()) {
+ RunDeliverCallback(deliver_message_callback,
+ PUSH_DELIVERY_STATUS_SERVICE_WORKER_ERROR);
+ } else {
+ RunDeliverCallback(deliver_message_callback,
+ PUSH_DELIVERY_STATUS_NO_SERVICE_WORKER);
+ }
+ 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(&PushMessagingRouter::DeliverMessageEnd,
+ deliver_message_callback, service_worker_registration);
+ version->DispatchPushEvent(dispatch_event_callback, data);
}
// static
@@ -89,16 +117,41 @@ void PushMessagingRouter::DeliverMessageEnd(
const DeliverMessageCallback& deliver_message_callback,
const scoped_refptr<ServiceWorkerRegistration>& service_worker_registration,
ServiceWorkerStatusCode service_worker_status) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(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));
+ PUSH_DELIVERY_STATUS_SERVICE_WORKER_ERROR;
+ switch (service_worker_status) {
+ case SERVICE_WORKER_OK:
+ delivery_status = PUSH_DELIVERY_STATUS_SUCCESS;
+ break;
+ case SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED:
+ delivery_status = PUSH_DELIVERY_STATUS_EVENT_WAITUNTIL_REJECTED;
+ break;
+ case SERVICE_WORKER_ERROR_FAILED:
+ case SERVICE_WORKER_ERROR_ABORT:
+ case SERVICE_WORKER_ERROR_START_WORKER_FAILED:
+ case SERVICE_WORKER_ERROR_PROCESS_NOT_FOUND:
+ case SERVICE_WORKER_ERROR_NOT_FOUND:
+ case SERVICE_WORKER_ERROR_IPC_FAILED:
+ case SERVICE_WORKER_ERROR_TIMEOUT:
+ case SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED:
+ case SERVICE_WORKER_ERROR_DISK_CACHE:
+ delivery_status = PUSH_DELIVERY_STATUS_SERVICE_WORKER_ERROR;
+ break;
+ case SERVICE_WORKER_ERROR_EXISTS:
+ case SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED:
+ case SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED:
+ case SERVICE_WORKER_ERROR_NETWORK:
+ case SERVICE_WORKER_ERROR_SECURITY:
+ case SERVICE_WORKER_ERROR_STATE:
+ case SERVICE_WORKER_ERROR_MAX_VALUE:
+ NOTREACHED() << "Got unexpected error code: " << service_worker_status
+ << " " << ServiceWorkerStatusToString(service_worker_status);
+ delivery_status = PUSH_DELIVERY_STATUS_SERVICE_WORKER_ERROR;
+ break;
+ }
+ RunDeliverCallback(deliver_message_callback, delivery_status);
}
} // namespace content
diff --git a/chromium/content/browser/quota/quota_database_unittest.cc b/chromium/content/browser/quota/quota_database_unittest.cc
index 5b5b00e1454..8241c188d0b 100644
--- a/chromium/content/browser/quota/quota_database_unittest.cc
+++ b/chromium/content/browser/quota/quota_database_unittest.cc
@@ -15,7 +15,6 @@
#include "sql/connection.h"
#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"
diff --git a/chromium/content/browser/quota_dispatcher_host.cc b/chromium/content/browser/quota_dispatcher_host.cc
index 2ea8a5ec9b5..3cbfee2c24d 100644
--- a/chromium/content/browser/quota_dispatcher_host.cc
+++ b/chromium/content/browser/quota_dispatcher_host.cc
@@ -118,8 +118,7 @@ class QuotaDispatcherHost::RequestQuotaDispatcher
DCHECK(dispatcher_host());
DCHECK(params_.storage_type == storage::kStorageTypeTemporary ||
- params_.storage_type == storage::kStorageTypePersistent ||
- params_.storage_type == storage::kStorageTypeSyncable);
+ params_.storage_type == storage::kStorageTypePersistent);
if (params_.storage_type == storage::kStorageTypePersistent) {
quota_manager()->GetUsageAndQuotaForWebApps(
params_.origin_url, params_.storage_type,
diff --git a/chromium/content/browser/renderer_data_memoizing_store.h b/chromium/content/browser/renderer_data_memoizing_store.h
index ce8e2937380..035f70b7e3c 100644
--- a/chromium/content/browser/renderer_data_memoizing_store.h
+++ b/chromium/content/browser/renderer_data_memoizing_store.h
@@ -126,7 +126,7 @@ class RendererDataMemoizingStore : public RenderProcessHostObserver {
};
void StartObservingProcess(int process_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
RenderProcessHost* host = RenderProcessHost::FromID(process_id);
if (!host) {
// We lost the race to observe the host before it was destroyed. Since
@@ -153,8 +153,8 @@ class RendererDataMemoizingStore : public RenderProcessHostObserver {
id_to_item_.erase(item_iter);
}
- void RenderProcessHostDestroyed(RenderProcessHost* host) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ void RenderProcessHostDestroyed(RenderProcessHost* host) override {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
RemoveRenderProcessItems(host->GetID());
}
diff --git a/chromium/content/browser/renderer_host/DEPS b/chromium/content/browser/renderer_host/DEPS
index 3afe25bd977..85fd36e6559 100644
--- a/chromium/content/browser/renderer_host/DEPS
+++ b/chromium/content/browser/renderer_host/DEPS
@@ -20,7 +20,7 @@ specific_include_rules = {
"+content/browser/web_contents",
"+content/public/browser/web_contents.h",
"+content/public/browser/web_contents_view.h",
- "+media/filters",
+ "+media/blink",
],
"sandbox_ipc_linux\.cc": [
"+third_party/WebKit/public/platform/linux/WebFontInfo.h",
diff --git a/chromium/content/browser/renderer_host/OWNERS b/chromium/content/browser/renderer_host/OWNERS
index 2e48dfae455..8cac44c5df7 100644
--- a/chromium/content/browser/renderer_host/OWNERS
+++ b/chromium/content/browser/renderer_host/OWNERS
@@ -10,8 +10,6 @@ asvitkine@chromium.org
# for GPU-related stuff in *mac*
kbr@chromium.org
ccameron@chromium.org
-per-file compositing_iosurface*=hclam@chromium.org
-per-file compositing_iosurface*=miu@chromium.org
# for *android*
sievers@chromium.org
@@ -20,6 +18,7 @@ aelias@chromium.org
# For touch/gesture specific changes
rjkroege@chromium.org
sadrul@chromium.org
+jdduke@chromium.org
# WebSocket
per-file *websocket*=ricea@chromium.org
diff --git a/chromium/content/browser/renderer_host/begin_frame_observer_proxy.cc b/chromium/content/browser/renderer_host/begin_frame_observer_proxy.cc
new file mode 100644
index 00000000000..7a6651f53c3
--- /dev/null
+++ b/chromium/content/browser/renderer_host/begin_frame_observer_proxy.cc
@@ -0,0 +1,70 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/renderer_host/begin_frame_observer_proxy.h"
+
+namespace content {
+
+BeginFrameObserverProxy::BeginFrameObserverProxy(
+ BeginFrameObserverProxyClient* client)
+ : needs_begin_frames_(false),
+ client_(client),
+ compositor_(nullptr) {
+}
+
+BeginFrameObserverProxy::~BeginFrameObserverProxy() {
+}
+
+void BeginFrameObserverProxy::SetNeedsBeginFrames(bool needs_begin_frames) {
+ if (needs_begin_frames_ == needs_begin_frames)
+ return;
+
+ needs_begin_frames_ = needs_begin_frames;
+
+ // In some cases, BeginFrame message is requested before |client_|'s window is
+ // added in the root window hierarchy.
+ if (!compositor_)
+ return;
+
+ if (needs_begin_frames)
+ StartObservingBeginFrames();
+ else
+ StopObservingBeginFrames();
+}
+
+void BeginFrameObserverProxy::SetCompositor(ui::Compositor* compositor) {
+ DCHECK(!compositor_);
+ DCHECK(compositor);
+
+ compositor_ = compositor;
+ if (needs_begin_frames_)
+ StartObservingBeginFrames();
+}
+
+void BeginFrameObserverProxy::ResetCompositor() {
+ if (!compositor_)
+ return;
+
+ if (needs_begin_frames_)
+ StopObservingBeginFrames();
+ compositor_ = nullptr;
+}
+
+void BeginFrameObserverProxy::OnSendBeginFrame(const cc::BeginFrameArgs& args) {
+ if (last_sent_begin_frame_args_.frame_time != args.frame_time)
+ client_->SendBeginFrame(args);
+ last_sent_begin_frame_args_ = args;
+}
+
+void BeginFrameObserverProxy::StartObservingBeginFrames() {
+ DCHECK(compositor_);
+ compositor_->AddBeginFrameObserver(this);
+}
+
+void BeginFrameObserverProxy::StopObservingBeginFrames() {
+ DCHECK(compositor_);
+ compositor_->RemoveBeginFrameObserver(this);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/renderer_host/begin_frame_observer_proxy.h b/chromium/content/browser/renderer_host/begin_frame_observer_proxy.h
new file mode 100644
index 00000000000..fd2aa6d7a06
--- /dev/null
+++ b/chromium/content/browser/renderer_host/begin_frame_observer_proxy.h
@@ -0,0 +1,60 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_RENDERER_HOST_BEGIN_FRAME_OBSERVER_PROXY_H_
+#define CONTENT_BROWSER_RENDERER_HOST_BEGIN_FRAME_OBSERVER_PROXY_H_
+
+#include "content/common/content_export.h"
+#include "ui/compositor/compositor.h"
+#include "ui/compositor/compositor_observer.h"
+
+namespace cc {
+struct BeginFrameArgs;
+}
+
+namespace content {
+
+// This is the interface from the BeginFrameObserverProxy which manages sending
+// BeginFrame messages.
+class BeginFrameObserverProxyClient {
+ public:
+ virtual void SendBeginFrame(const cc::BeginFrameArgs& args) = 0;
+};
+
+// This class is used to manage all of the RenderWidgetHostView state and
+// functionality that is associated with BeginFrame message handling.
+class CONTENT_EXPORT BeginFrameObserverProxy
+ : public ui::CompositorBeginFrameObserver {
+ public:
+ explicit BeginFrameObserverProxy(BeginFrameObserverProxyClient* client);
+ ~BeginFrameObserverProxy() override;
+
+ void SetNeedsBeginFrames(bool needs_begin_frames);
+
+ void SetCompositor(ui::Compositor* compositor);
+ void ResetCompositor();
+
+ // Overridden from ui::CompositorBeginFrameObserver:
+ void OnSendBeginFrame(const cc::BeginFrameArgs& args) override;
+
+ private:
+ void StartObservingBeginFrames();
+ void StopObservingBeginFrames();
+
+ // True when RenderWidget needs a BeginFrame message.
+ bool needs_begin_frames_;
+
+ // Used whether to send begin frame to client or not. When |args| from
+ // Compositor is different from this, send to client.
+ cc::BeginFrameArgs last_sent_begin_frame_args_;
+
+ BeginFrameObserverProxyClient* client_;
+ ui::Compositor* compositor_;
+
+ DISALLOW_COPY_AND_ASSIGN(BeginFrameObserverProxy);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_RENDERER_HOST_BEGIN_FRAME_OBSERVER_PROXY_H_
diff --git a/chromium/content/browser/renderer_host/begin_frame_observer_proxy_unittest.cc b/chromium/content/browser/renderer_host/begin_frame_observer_proxy_unittest.cc
new file mode 100644
index 00000000000..b54eadd7cae
--- /dev/null
+++ b/chromium/content/browser/renderer_host/begin_frame_observer_proxy_unittest.cc
@@ -0,0 +1,97 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <algorithm>
+#include <list>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/test/test_simple_task_runner.h"
+#include "cc/output/begin_frame_args.h"
+#include "cc/test/begin_frame_args_test.h"
+#include "content/browser/renderer_host/begin_frame_observer_proxy.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/compositor/compositor.h"
+#include "ui/compositor/test/context_factories_for_test.h"
+
+using testing::Mock;
+using testing::_;
+
+namespace content {
+namespace {
+
+class MockBeginFrameObserverProxyClient : public BeginFrameObserverProxyClient {
+ public:
+ MOCK_METHOD1(SendBeginFrame, void(const cc::BeginFrameArgs&));
+};
+
+class BeginFrameObserverProxyTest : public testing::Test {
+ public:
+ BeginFrameObserverProxyTest() {}
+ ~BeginFrameObserverProxyTest() override {}
+
+ void SetUp() override {
+ bool enable_pixel_output = false;
+ ui::ContextFactory* context_factory =
+ ui::InitializeContextFactoryForTests(enable_pixel_output);
+ compositor_task_runner_ = new base::TestSimpleTaskRunner();
+ compositor_.reset(new ui::Compositor(gfx::kNullAcceleratedWidget,
+ context_factory,
+ compositor_task_runner_));
+ }
+
+ void TearDown() override {
+ compositor_.reset();
+ ui::TerminateContextFactoryForTests();
+ }
+
+ ui::Compositor* compositor() { return compositor_.get(); }
+
+ private:
+ scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_;
+ scoped_ptr<ui::Compositor> compositor_;
+};
+
+} // namespace
+
+TEST_F(BeginFrameObserverProxyTest, BeginFrameScheduling) {
+ MockBeginFrameObserverProxyClient client;
+ BeginFrameObserverProxy begin_frame_observer(&client);
+ begin_frame_observer.SetCompositor(compositor());
+ begin_frame_observer.SetNeedsBeginFrames(true);
+
+ // SendBeginFrame is called when new |args| is delivered.
+ cc::BeginFrameArgs args =
+ cc::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE,
+ base::TimeTicks::FromInternalValue(33));
+ EXPECT_CALL(client, SendBeginFrame(args));
+ compositor()->SendBeginFramesToChildren(args);
+ Mock::VerifyAndClearExpectations(&client);
+
+ // SendBeginFrame is called when new |args2| is delivered.
+ cc::BeginFrameArgs args2 =
+ cc::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE,
+ base::TimeTicks::FromInternalValue(66));
+ EXPECT_CALL(client, SendBeginFrame(args2));
+ compositor()->SendBeginFramesToChildren(args2);
+ Mock::VerifyAndClearExpectations(&client);
+
+ // SendBeginFrame is not called when used |args2| is delivered.
+ EXPECT_CALL(client, SendBeginFrame(_)).Times(0);
+ compositor()->SendBeginFramesToChildren(args2);
+ Mock::VerifyAndClearExpectations(&client);
+
+ // SendBeginFrame is not called when compositor is reset.
+ begin_frame_observer.ResetCompositor();
+ cc::BeginFrameArgs args3 =
+ cc::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE,
+ base::TimeTicks::FromInternalValue(99));
+ EXPECT_CALL(client, SendBeginFrame(_)).Times(0);
+ compositor()->SendBeginFramesToChildren(args3);
+ Mock::VerifyAndClearExpectations(&client);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/renderer_host/clipboard_message_filter.cc b/chromium/content/browser/renderer_host/clipboard_message_filter.cc
index 3ea8071cb1c..88e24d9736b 100644
--- a/chromium/content/browser/renderer_host/clipboard_message_filter.cc
+++ b/chromium/content/browser/renderer_host/clipboard_message_filter.cc
@@ -7,53 +7,36 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/location.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
+#include "base/pickle.h"
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "content/common/clipboard_messages.h"
#include "content/public/browser/browser_context.h"
#include "ipc/ipc_message_macros.h"
#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/base/clipboard/custom_data_helper.h"
+#include "ui/base/clipboard/scoped_clipboard_writer.h"
#include "ui/gfx/codec/png_codec.h"
-#include "ui/gfx/size.h"
+#include "ui/gfx/geometry/size.h"
#include "url/gurl.h"
namespace content {
namespace {
-enum BitmapPolicy {
- kFilterBitmap,
- kAllowBitmap,
-};
-void SanitizeObjectMap(ui::Clipboard::ObjectMap* objects,
- BitmapPolicy bitmap_policy) {
- if (bitmap_policy != kAllowBitmap)
- objects->erase(ui::Clipboard::CBF_SMBITMAP);
-
- ui::Clipboard::ObjectMap::iterator data_it =
- objects->find(ui::Clipboard::CBF_DATA);
- if (data_it != objects->end()) {
- const ui::Clipboard::FormatType& web_custom_format =
- ui::Clipboard::GetWebCustomDataFormatType();
- if (data_it->second.size() != 2 ||
- !web_custom_format.Equals(
- ui::Clipboard::FormatType::Deserialize(std::string(
- &data_it->second[0].front(),
- data_it->second[0].size())))) {
- // CBF_DATA should always have two parameters associated with it, and the
- // associated FormatType should always be web custom data. If not, then
- // data is malformed and we'll ignore it.
- objects->erase(ui::Clipboard::CBF_DATA);
- }
- }
+void ReleaseSharedMemoryPixels(void* addr, void* context) {
+ delete reinterpret_cast<base::SharedMemory*>(context);
}
} // namespace
-
ClipboardMessageFilter::ClipboardMessageFilter()
- : BrowserMessageFilter(ClipboardMsgStart) {}
+ : BrowserMessageFilter(ClipboardMsgStart),
+ clipboard_writer_(
+ new ui::ScopedClipboardWriter(ui::CLIPBOARD_TYPE_COPY_PASTE)) {
+}
void ClipboardMessageFilter::OverrideThreadForMessage(
const IPC::Message& message, BrowserThread::ID* thread) {
@@ -80,8 +63,6 @@ void ClipboardMessageFilter::OverrideThreadForMessage(
bool ClipboardMessageFilter::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(ClipboardMessageFilter, message)
- IPC_MESSAGE_HANDLER(ClipboardHostMsg_WriteObjectsAsync, OnWriteObjectsAsync)
- IPC_MESSAGE_HANDLER(ClipboardHostMsg_WriteObjectsSync, OnWriteObjectsSync)
IPC_MESSAGE_HANDLER(ClipboardHostMsg_GetSequenceNumber, OnGetSequenceNumber)
IPC_MESSAGE_HANDLER(ClipboardHostMsg_IsFormatAvailable, OnIsFormatAvailable)
IPC_MESSAGE_HANDLER(ClipboardHostMsg_Clear, OnClear)
@@ -92,6 +73,14 @@ bool ClipboardMessageFilter::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(ClipboardHostMsg_ReadRTF, OnReadRTF)
IPC_MESSAGE_HANDLER_DELAY_REPLY(ClipboardHostMsg_ReadImage, OnReadImage)
IPC_MESSAGE_HANDLER(ClipboardHostMsg_ReadCustomData, OnReadCustomData)
+ IPC_MESSAGE_HANDLER(ClipboardHostMsg_WriteText, OnWriteText)
+ IPC_MESSAGE_HANDLER(ClipboardHostMsg_WriteHTML, OnWriteHTML)
+ IPC_MESSAGE_HANDLER(ClipboardHostMsg_WriteSmartPasteMarker,
+ OnWriteSmartPasteMarker)
+ IPC_MESSAGE_HANDLER(ClipboardHostMsg_WriteCustomData, OnWriteCustomData)
+ IPC_MESSAGE_HANDLER(ClipboardHostMsg_WriteBookmark, OnWriteBookmark)
+ IPC_MESSAGE_HANDLER(ClipboardHostMsg_WriteImage, OnWriteImage)
+ IPC_MESSAGE_HANDLER(ClipboardHostMsg_CommitWrite, OnCommitWrite);
#if defined(OS_MACOSX)
IPC_MESSAGE_HANDLER(ClipboardHostMsg_FindPboardWriteStringAsync,
OnFindPboardWriteString)
@@ -102,71 +91,7 @@ bool ClipboardMessageFilter::OnMessageReceived(const IPC::Message& message) {
}
ClipboardMessageFilter::~ClipboardMessageFilter() {
-}
-
-void ClipboardMessageFilter::OnWriteObjectsSync(
- const ui::Clipboard::ObjectMap& objects,
- base::SharedMemoryHandle bitmap_handle) {
- DCHECK(base::SharedMemory::IsHandleValid(bitmap_handle))
- << "Bad bitmap handle";
-
- // On Windows, we can't write directly from the IO thread, so we copy the data
- // into a heap allocated map and post a task to the UI thread. On other
- // platforms, to lower the amount of time the renderer has to wait for the
- // sync IPC to complete, we also take a copy and post a task to flush the data
- // to the clipboard later.
- scoped_ptr<ui::Clipboard::ObjectMap> long_living_objects(
- new ui::Clipboard::ObjectMap(objects));
- SanitizeObjectMap(long_living_objects.get(), kAllowBitmap);
- // Splice the shared memory handle into the data. |long_living_objects| now
- // contains a heap-allocated SharedMemory object that references
- // |bitmap_handle|. This reference will keep the shared memory section alive
- // when this IPC returns, and the SharedMemory object will eventually be
- // freed by ui::Clipboard::WriteObjects().
- if (!ui::Clipboard::ReplaceSharedMemHandle(
- long_living_objects.get(), bitmap_handle, PeerHandle()))
- return;
-
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(&ClipboardMessageFilter::WriteObjectsOnUIThread,
- base::Owned(long_living_objects.release())));
-}
-
-// On Windows, the write must be performed on the UI thread because the
-// clipboard object from the IO thread cannot create windows so it cannot be
-// the "owner" of the clipboard's contents. See http://crbug.com/5823.
-// TODO(dcheng): Temporarily a member of ClipboardMessageFilter so it can access
-// ui::Clipboard::WriteObjects().
-void ClipboardMessageFilter::WriteObjectsOnUIThread(
- const ui::Clipboard::ObjectMap* objects) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- static ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
- clipboard->WriteObjects(ui::CLIPBOARD_TYPE_COPY_PASTE, *objects);
-}
-
-void ClipboardMessageFilter::OnWriteObjectsAsync(
- const ui::Clipboard::ObjectMap& objects) {
- // This async message doesn't support shared-memory based bitmaps; they must
- // be removed otherwise we might dereference a rubbish pointer.
- scoped_ptr<ui::Clipboard::ObjectMap> sanitized_objects(
- new ui::Clipboard::ObjectMap(objects));
- SanitizeObjectMap(sanitized_objects.get(), kFilterBitmap);
-
-#if defined(OS_WIN)
- // We cannot write directly from the IO thread, and cannot service the IPC
- // on the UI thread. We'll copy the relevant data and post a task to preform
- // the write on the UI thread.
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(
- &WriteObjectsOnUIThread, base::Owned(sanitized_objects.release())));
-#else
- GetClipboard()->WriteObjects(
- ui::CLIPBOARD_TYPE_COPY_PASTE, *sanitized_objects.get());
-#endif
+ clipboard_writer_->Reset();
}
void ClipboardMessageFilter::OnGetSequenceNumber(ui::ClipboardType type,
@@ -286,6 +211,91 @@ void ClipboardMessageFilter::OnReadCustomData(ui::ClipboardType clipboard_type,
GetClipboard()->ReadCustomData(clipboard_type, type, result);
}
+void ClipboardMessageFilter::OnWriteText(ui::ClipboardType clipboard_type,
+ const base::string16& text) {
+ clipboard_writer_->WriteText(text);
+}
+
+void ClipboardMessageFilter::OnWriteHTML(ui::ClipboardType clipboard_type,
+ const base::string16& markup,
+ const GURL& url) {
+ clipboard_writer_->WriteHTML(markup, url.spec());
+}
+
+void ClipboardMessageFilter::OnWriteSmartPasteMarker(
+ ui::ClipboardType clipboard_type) {
+ clipboard_writer_->WriteWebSmartPaste();
+}
+
+void ClipboardMessageFilter::OnWriteCustomData(
+ ui::ClipboardType clipboard_type,
+ const std::map<base::string16, base::string16>& data) {
+ Pickle pickle;
+ ui::WriteCustomDataToPickle(data, &pickle);
+ clipboard_writer_->WritePickledData(
+ pickle, ui::Clipboard::GetWebCustomDataFormatType());
+}
+
+void ClipboardMessageFilter::OnWriteBookmark(ui::ClipboardType clipboard_type,
+ const std::string& url,
+ const base::string16& title) {
+ clipboard_writer_->WriteBookmark(title, url);
+}
+
+void ClipboardMessageFilter::OnWriteImage(ui::ClipboardType clipboard_type,
+ const gfx::Size& size,
+ base::SharedMemoryHandle handle) {
+ if (!base::SharedMemory::IsHandleValid(handle)) {
+ return;
+ }
+
+ scoped_ptr<base::SharedMemory> bitmap_buffer(
+#if defined(OS_WIN)
+ new base::SharedMemory(handle, true, PeerHandle()));
+#else
+ new base::SharedMemory(handle, true));
+#endif
+
+ SkBitmap bitmap;
+ // Let Skia do some sanity checking for (no negative widths/heights, no
+ // overflows while calculating bytes per row, etc).
+ if (!bitmap.setInfo(
+ SkImageInfo::MakeN32Premul(size.width(), size.height()))) {
+ return;
+ }
+
+ // Make sure the size is representable as a signed 32-bit int, so
+ // SkBitmap::getSize() won't be truncated.
+ if (!sk_64_isS32(bitmap.computeSize64()))
+ return;
+
+ if (!bitmap_buffer->Map(bitmap.getSize()))
+ return;
+
+ if (!bitmap.installPixels(bitmap.info(), bitmap_buffer->memory(),
+ bitmap.rowBytes(), NULL, &ReleaseSharedMemoryPixels,
+ bitmap_buffer.get()))
+ return;
+
+ // On success, SkBitmap now owns the SharedMemory.
+ ignore_result(bitmap_buffer.release());
+ clipboard_writer_->WriteImage(bitmap);
+}
+
+void ClipboardMessageFilter::OnCommitWrite(ui::ClipboardType clipboard_type) {
+#if defined(OS_WIN)
+ // On non-Windows platforms, all clipboard IPCs are handled on the UI thread.
+ // However, Windows handles the clipboard IPCs on the IO thread to prevent
+ // deadlocks. Clipboard writes must still occur on the UI thread because the
+ // clipboard object from the IO thread cannot create windows so it cannot be
+ // the "owner" of the clipboard's contents. See http://crbug.com/5823.
+ BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE,
+ clipboard_writer_.release());
+#endif
+ clipboard_writer_.reset(
+ new ui::ScopedClipboardWriter(ui::CLIPBOARD_TYPE_COPY_PASTE));
+}
+
// static
ui::Clipboard* ClipboardMessageFilter::GetClipboard() {
// We have a static instance of the clipboard service for use by all message
diff --git a/chromium/content/browser/renderer_host/clipboard_message_filter.h b/chromium/content/browser/renderer_host/clipboard_message_filter.h
index 792bfc5b774..f563ed51432 100644
--- a/chromium/content/browser/renderer_host/clipboard_message_filter.h
+++ b/chromium/content/browser/renderer_host/clipboard_message_filter.h
@@ -9,15 +9,23 @@
#include <vector>
#include "base/basictypes.h"
+#include "base/memory/shared_memory.h"
#include "content/common/clipboard_format.h"
+#include "content/common/content_export.h"
#include "content/public/browser/browser_message_filter.h"
#include "ui/base/clipboard/clipboard.h"
class GURL;
+namespace ui {
+class ScopedClipboardWriter;
+} // namespace ui
+
namespace content {
-class ClipboardMessageFilter : public BrowserMessageFilter {
+class ClipboardMessageFilterTest;
+
+class CONTENT_EXPORT ClipboardMessageFilter : public BrowserMessageFilter {
public:
ClipboardMessageFilter();
@@ -26,12 +34,9 @@ class ClipboardMessageFilter : public BrowserMessageFilter {
bool OnMessageReceived(const IPC::Message& message) override;
private:
- ~ClipboardMessageFilter() override;
+ friend class ClipboardMessageFilterTest;
- void OnWriteObjectsAsync(const ui::Clipboard::ObjectMap& objects);
- void OnWriteObjectsSync(const ui::Clipboard::ObjectMap& objects,
- base::SharedMemoryHandle bitmap_handle);
- static void WriteObjectsOnUIThread(const ui::Clipboard::ObjectMap* objects);
+ ~ClipboardMessageFilter() override;
void OnGetSequenceNumber(const ui::ClipboardType type,
uint64* sequence_number);
@@ -57,6 +62,22 @@ class ClipboardMessageFilter : public BrowserMessageFilter {
void OnReadData(const ui::Clipboard::FormatType& format,
std::string* data);
+ void OnWriteText(ui::ClipboardType clipboard_type,
+ const base::string16& text);
+ void OnWriteHTML(ui::ClipboardType clipboard_type,
+ const base::string16& markup,
+ const GURL& url);
+ void OnWriteSmartPasteMarker(ui::ClipboardType clipboard_type);
+ void OnWriteCustomData(ui::ClipboardType clipboard_type,
+ const std::map<base::string16, base::string16>& data);
+ void OnWriteBookmark(ui::ClipboardType clipboard_type,
+ const std::string& url,
+ const base::string16& title);
+ void OnWriteImage(ui::ClipboardType clipboard_type,
+ const gfx::Size& size,
+ base::SharedMemoryHandle handle);
+ void OnCommitWrite(ui::ClipboardType clipboard_type);
+
#if defined(OS_MACOSX)
void OnFindPboardWriteString(const base::string16& text);
#endif
@@ -67,6 +88,8 @@ class ClipboardMessageFilter : public BrowserMessageFilter {
// thread.
static ui::Clipboard* GetClipboard();
+ scoped_ptr<ui::ScopedClipboardWriter> clipboard_writer_;
+
DISALLOW_COPY_AND_ASSIGN(ClipboardMessageFilter);
};
diff --git a/chromium/content/browser/renderer_host/clipboard_message_filter_unittest.cc b/chromium/content/browser/renderer_host/clipboard_message_filter_unittest.cc
new file mode 100644
index 00000000000..ecaaf69d283
--- /dev/null
+++ b/chromium/content/browser/renderer_host/clipboard_message_filter_unittest.cc
@@ -0,0 +1,132 @@
+// Copyright 2014 The Chromium Authors. 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/clipboard_message_filter.h"
+
+#include <string.h>
+
+#include "base/memory/ref_counted.h"
+#include "base/process/process_handle.h"
+#include "base/run_loop.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/base/test/test_clipboard.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace content {
+
+class ClipboardMessageFilterTest : public ::testing::Test {
+ protected:
+ ClipboardMessageFilterTest()
+ : filter_(new ClipboardMessageFilter),
+ clipboard_(ui::TestClipboard::CreateForCurrentThread()) {
+ filter_->set_peer_process_for_testing(base::Process::Current());
+ }
+
+ ~ClipboardMessageFilterTest() override {
+ ui::Clipboard::DestroyClipboardForCurrentThread();
+ }
+
+ scoped_ptr<base::SharedMemory> CreateAndMapReadOnlySharedMemory(size_t size) {
+ scoped_ptr<base::SharedMemory> m = CreateReadOnlySharedMemory(size);
+ if (!m->Map(size))
+ return nullptr;
+ return m;
+ }
+
+ scoped_ptr<base::SharedMemory> CreateReadOnlySharedMemory(size_t size) {
+ scoped_ptr<base::SharedMemory> m(new base::SharedMemory());
+ base::SharedMemoryCreateOptions options;
+ options.size = size;
+ options.share_read_only = true;
+ if (!m->Create(options))
+ return nullptr;
+ return m;
+ }
+
+ void CallWriteImage(const gfx::Size& size,
+ base::SharedMemory* shared_memory) {
+ base::SharedMemoryHandle handle;
+ ASSERT_TRUE(shared_memory->GiveReadOnlyToProcess(
+ base::GetCurrentProcessHandle(), &handle));
+ CallWriteImageDirectly(size, handle);
+ }
+
+ // Prefer to use CallWriteImage() in tests.
+ void CallWriteImageDirectly(const gfx::Size& size,
+ base::SharedMemoryHandle handle) {
+ filter_->OnWriteImage(ui::CLIPBOARD_TYPE_COPY_PASTE, size, handle);
+ }
+
+ void CallCommitWrite() {
+ filter_->OnCommitWrite(ui::CLIPBOARD_TYPE_COPY_PASTE);
+ base::RunLoop().RunUntilIdle();
+ }
+
+ ui::Clipboard* clipboard() { return clipboard_; }
+
+ private:
+ const TestBrowserThreadBundle thread_bundle_;
+ const scoped_refptr<ClipboardMessageFilter> filter_;
+ ui::Clipboard* const clipboard_;
+};
+
+// Test that it actually works.
+TEST_F(ClipboardMessageFilterTest, SimpleImage) {
+ static const uint32_t bitmap_data[] = {
+ 0x33333333, 0xdddddddd, 0xeeeeeeee, 0x00000000,
+ 0x88888888, 0x66666666, 0x55555555, 0xbbbbbbbb,
+ 0x44444444, 0xaaaaaaaa, 0x99999999, 0x77777777,
+ 0xffffffff, 0x11111111, 0x22222222, 0xcccccccc,
+ };
+
+ scoped_ptr<base::SharedMemory> shared_memory =
+ CreateAndMapReadOnlySharedMemory(sizeof(bitmap_data));
+ memcpy(shared_memory->memory(), bitmap_data, sizeof(bitmap_data));
+
+ CallWriteImage(gfx::Size(4, 4), shared_memory.get());
+ uint64_t sequence_number =
+ clipboard()->GetSequenceNumber(ui::CLIPBOARD_TYPE_COPY_PASTE);
+ CallCommitWrite();
+
+ EXPECT_NE(sequence_number,
+ clipboard()->GetSequenceNumber(ui::CLIPBOARD_TYPE_COPY_PASTE));
+ EXPECT_FALSE(clipboard()->IsFormatAvailable(
+ ui::Clipboard::GetPlainTextFormatType(), ui::CLIPBOARD_TYPE_COPY_PASTE));
+ EXPECT_TRUE(clipboard()->IsFormatAvailable(
+ ui::Clipboard::GetBitmapFormatType(), ui::CLIPBOARD_TYPE_COPY_PASTE));
+
+ SkBitmap actual = clipboard()->ReadImage(ui::CLIPBOARD_TYPE_COPY_PASTE);
+ SkAutoLockPixels locked(actual);
+ EXPECT_EQ(sizeof(bitmap_data), actual.getSize());
+ EXPECT_EQ(0,
+ memcmp(bitmap_data, actual.getAddr32(0, 0), sizeof(bitmap_data)));
+}
+
+// Test with a size that would overflow a naive 32-bit row bytes calculation.
+TEST_F(ClipboardMessageFilterTest, ImageSizeOverflows32BitRowBytes) {
+ scoped_ptr<base::SharedMemory> shared_memory =
+ CreateReadOnlySharedMemory(0x20000000);
+
+ CallWriteImage(gfx::Size(0x20000000, 1), shared_memory.get());
+ uint64_t sequence_number =
+ clipboard()->GetSequenceNumber(ui::CLIPBOARD_TYPE_COPY_PASTE);
+ CallCommitWrite();
+
+ EXPECT_EQ(sequence_number,
+ clipboard()->GetSequenceNumber(ui::CLIPBOARD_TYPE_COPY_PASTE));
+}
+
+TEST_F(ClipboardMessageFilterTest, InvalidSharedMemoryHandle) {
+ CallWriteImageDirectly(gfx::Size(5, 5), base::SharedMemory::NULLHandle());
+ uint64_t sequence_number =
+ clipboard()->GetSequenceNumber(ui::CLIPBOARD_TYPE_COPY_PASTE);
+ CallCommitWrite();
+
+ EXPECT_EQ(sequence_number,
+ clipboard()->GetSequenceNumber(ui::CLIPBOARD_TYPE_COPY_PASTE));
+}
+
+} // 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 5d8ecc8138c..23891bd015b 100644
--- a/chromium/content/browser/renderer_host/compositor_impl_android.cc
+++ b/chromium/content/browser/renderer_host/compositor_impl_android.cc
@@ -18,6 +18,8 @@
#include "base/memory/weak_ptr.h"
#include "base/single_thread_task_runner.h"
#include "base/synchronization/lock.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/simple_thread.h"
#include "base/threading/thread.h"
#include "base/threading/thread_checker.h"
#include "cc/base/switches.h"
@@ -27,10 +29,17 @@
#include "cc/output/context_provider.h"
#include "cc/output/output_surface.h"
#include "cc/output/output_surface_client.h"
+#include "cc/raster/task_graph_runner.h"
+#include "cc/scheduler/begin_frame_source.h"
+#include "cc/surfaces/onscreen_display_client.h"
+#include "cc/surfaces/surface_display_output_surface.h"
+#include "cc/surfaces/surface_id_allocator.h"
+#include "cc/surfaces/surface_manager.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/compositor_util.h"
#include "content/browser/gpu/gpu_surface_tracker.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/common/gpu/client/command_buffer_proxy_impl.h"
@@ -41,16 +50,15 @@
#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/blink/webgraphicscontext3d_in_process_command_buffer_impl.h"
#include "gpu/command_buffer/client/context_support.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "third_party/khronos/GLES2/gl2ext.h"
#include "third_party/skia/include/core/SkMallocPixelRef.h"
-#include "ui/base/android/window_android.h"
+#include "ui/android/window_android.h"
#include "ui/gfx/android/device_display_info.h"
#include "ui/gfx/frame_time.h"
-#include "webkit/common/gpu/context_provider_in_process.h"
-#include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"
namespace content {
@@ -69,16 +77,12 @@ class OutputSurfaceWithoutParent : public cc::OutputSurface {
base::Bind(&OutputSurfaceWithoutParent::OnSwapBuffersCompleted,
base::Unretained(this))) {
capabilities_.adjust_deadline_for_parent = false;
+ capabilities_.max_frames_pending = 2;
compositor_impl_ = compositor_impl;
main_thread_ = base::MessageLoopProxy::current();
}
- 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);
- }
-
+ void SwapBuffers(cc::CompositorFrame* frame) override {
GetCommandBufferProxy()->SetLatencyInfo(frame->metadata.latency_info);
DCHECK(frame->gl_frame_data->sub_buffer_rect ==
gfx::Rect(frame->gl_frame_data->size));
@@ -86,7 +90,7 @@ class OutputSurfaceWithoutParent : public cc::OutputSurface {
client_->DidSwapBuffers();
}
- virtual bool BindToClient(cc::OutputSurfaceClient* client) override {
+ bool BindToClient(cc::OutputSurfaceClient* client) override {
if (!OutputSurface::BindToClient(client))
return false;
@@ -128,6 +132,38 @@ class OutputSurfaceWithoutParent : public cc::OutputSurface {
static bool g_initialized = false;
+bool g_use_surface_manager = false;
+base::LazyInstance<cc::SurfaceManager> g_surface_manager =
+ LAZY_INSTANCE_INITIALIZER;
+
+
+int g_surface_id_namespace = 0;
+
+class SingleThreadTaskGraphRunner
+ : public cc::TaskGraphRunner,
+ public base::DelegateSimpleThread::Delegate {
+ public:
+ SingleThreadTaskGraphRunner()
+ : worker_thread_(this, "CompositorTileWorker1") {
+ worker_thread_.Start();
+ worker_thread_.SetThreadPriority(base::ThreadPriority::BACKGROUND);
+ }
+
+ ~SingleThreadTaskGraphRunner() override {
+ Shutdown();
+ worker_thread_.Join();
+ }
+
+ private:
+ // Overridden from base::DelegateSimpleThread::Delegate:
+ void Run() override { cc::TaskGraphRunner::Run(); }
+
+ base::DelegateSimpleThread worker_thread_;
+};
+
+base::LazyInstance<SingleThreadTaskGraphRunner> g_task_graph_runner =
+ LAZY_INSTANCE_INITIALIZER;
+
} // anonymous namespace
// static
@@ -140,6 +176,7 @@ Compositor* Compositor::Create(CompositorClient* client,
void Compositor::Initialize() {
DCHECK(!CompositorImpl::IsInitialized());
g_initialized = true;
+ g_use_surface_manager = UseSurfacesEnabled();
}
// static
@@ -147,9 +184,23 @@ bool CompositorImpl::IsInitialized() {
return g_initialized;
}
+// static
+cc::SurfaceManager* CompositorImpl::GetSurfaceManager() {
+ if (!g_use_surface_manager)
+ return nullptr;
+ return g_surface_manager.Pointer();
+}
+
+// static
+scoped_ptr<cc::SurfaceIdAllocator> CompositorImpl::CreateSurfaceIdAllocator() {
+ return make_scoped_ptr(new cc::SurfaceIdAllocator(++g_surface_id_namespace));
+}
+
CompositorImpl::CompositorImpl(CompositorClient* client,
gfx::NativeWindow root_window)
: root_layer_(cc::Layer::Create()),
+ resource_manager_(&ui_resource_provider_),
+ surface_id_allocator_(CreateSurfaceIdAllocator()),
has_transparent_background_(false),
device_scale_factor_(1),
window_(NULL),
@@ -163,16 +214,16 @@ CompositorImpl::CompositorImpl(CompositorClient* client,
will_composite_immediately_(false),
composite_on_vsync_trigger_(DO_NOT_COMPOSITE),
pending_swapbuffers_(0U),
+ num_successive_context_creation_failures_(0),
+ output_surface_request_pending_(false),
weak_factory_(this) {
DCHECK(client);
DCHECK(root_window);
- ImageTransportFactoryAndroid::AddObserver(this);
root_window->AttachCompositor(this);
}
CompositorImpl::~CompositorImpl() {
root_window_->DetachCompositor();
- ImageTransportFactoryAndroid::RemoveObserver(this);
// Clean-up any surface references.
SetSurface(NULL);
}
@@ -222,7 +273,7 @@ void CompositorImpl::PostComposite(CompositingTrigger trigger) {
delay = next_composite - now;
}
}
- TRACE_EVENT2("cc", "CompositorImpl::PostComposite",
+ TRACE_EVENT2("cc,benchmark", "CompositorImpl::PostComposite",
"trigger", trigger,
"delay", delay.InMillisecondsF());
@@ -238,27 +289,20 @@ void CompositorImpl::PostComposite(CompositingTrigger trigger) {
}
void CompositorImpl::Composite(CompositingTrigger trigger) {
- BrowserGpuChannelHostFactory* factory =
- BrowserGpuChannelHostFactory::instance();
- if (!factory->GetGpuChannel() || factory->GetGpuChannel()->IsLost()) {
- CauseForGpuLaunch cause =
- CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE;
- factory->EstablishGpuChannel(cause,
- base::Bind(&CompositorImpl::ScheduleComposite,
- weak_factory_.GetWeakPtr()));
- return;
- }
+ if (trigger == COMPOSITE_IMMEDIATELY)
+ will_composite_immediately_ = false;
DCHECK(host_);
DCHECK(trigger == COMPOSITE_IMMEDIATELY || trigger == COMPOSITE_EVENTUALLY);
DCHECK(needs_composite_);
DCHECK(!DidCompositeThisFrame());
- if (trigger == COMPOSITE_IMMEDIATELY)
- will_composite_immediately_ = false;
-
DCHECK_LE(pending_swapbuffers_, kMaxSwapBuffers);
- if (pending_swapbuffers_ == kMaxSwapBuffers) {
+ // Swap Ack accounting is unreliable if the OutputSurface was lost.
+ // In that case still attempt to composite, which will cause creation of a
+ // new OutputSurface and reset pending_swapbuffers_.
+ if (pending_swapbuffers_ == kMaxSwapBuffers &&
+ !host_->output_surface_lost()) {
TRACE_EVENT0("compositor", "CompositorImpl_SwapLimit");
return;
}
@@ -292,12 +336,12 @@ void CompositorImpl::Composite(CompositingTrigger trigger) {
root_window_->RequestVSyncUpdate();
}
-UIResourceProvider& CompositorImpl::GetUIResourceProvider() {
+ui::UIResourceProvider& CompositorImpl::GetUIResourceProvider() {
return ui_resource_provider_;
}
-ui::SystemUIResourceManager& CompositorImpl::GetSystemUIResourceManager() {
- return ui_resource_provider_.GetSystemUIResourceManager();
+ui::ResourceManager& CompositorImpl::GetResourceManager() {
+ return resource_manager_;
}
void CompositorImpl::SetRootLayer(scoped_refptr<cc::Layer> root_layer) {
@@ -358,7 +402,47 @@ void CompositorImpl::SetSurface(jobject surface) {
}
}
+void CompositorImpl::CreateLayerTreeHost() {
+ DCHECK(!host_);
+ DCHECK(!WillCompositeThisFrame());
+ needs_composite_ = false;
+ pending_swapbuffers_ = 0;
+ cc::LayerTreeSettings settings;
+ settings.renderer_settings.refresh_rate = 60.0;
+ settings.renderer_settings.allow_antialiasing = false;
+ settings.renderer_settings.highp_threshold_min = 2048;
+ settings.impl_side_painting = true;
+
+ 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;
+
+ cc::LayerTreeHost::InitParams params;
+ params.client = this;
+ params.shared_bitmap_manager = HostSharedBitmapManager::current();
+ params.gpu_memory_buffer_manager = BrowserGpuMemoryBufferManager::current();
+ params.task_graph_runner = g_task_graph_runner.Pointer();
+ params.main_task_runner = base::ThreadTaskRunnerHandle::Get();
+ params.settings = &settings;
+ host_ = cc::LayerTreeHost::CreateSingleThreaded(this, &params);
+ host_->SetRootLayer(root_layer_);
+
+ host_->SetVisible(true);
+ host_->SetLayerTreeHostClientReady();
+ host_->SetViewportSize(size_);
+ host_->set_has_transparent_background(has_transparent_background_);
+ host_->SetDeviceScaleFactor(device_scale_factor_);
+
+ if (needs_animate_)
+ host_->SetNeedsAnimate();
+}
+
void CompositorImpl::SetVisible(bool visible) {
+ TRACE_EVENT1("cc", "CompositorImpl::SetVisible", "visible", visible);
if (!visible) {
DCHECK(host_);
// Look for any layers that were attached to the root for readback
@@ -379,42 +463,18 @@ void CompositorImpl::SetVisible(bool visible) {
CancelComposite();
ui_resource_provider_.SetLayerTreeHost(NULL);
host_.reset();
+ establish_gpu_channel_timeout_.Stop();
+ output_surface_request_pending_ = false;
+ display_client_.reset();
+ if (current_composite_task_) {
+ current_composite_task_->Cancel();
+ current_composite_task_.reset();
+ }
} else if (!host_) {
- DCHECK(!WillComposite());
- needs_composite_ = false;
- pending_swapbuffers_ = 0;
- cc::LayerTreeSettings settings;
- settings.refresh_rate = 60.0;
- settings.impl_side_painting = false;
- settings.allow_antialiasing = false;
- settings.calculate_top_controls_position = false;
- settings.top_controls_height = 0.f;
- settings.highp_threshold_min = 2048;
-
- 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(),
- BrowserGpuMemoryBufferManager::current(),
- settings,
- base::MessageLoopProxy::current());
- host_->SetRootLayer(root_layer_);
-
- host_->SetVisible(true);
- host_->SetLayerTreeHostClientReady();
- host_->SetViewportSize(size_);
- host_->set_has_transparent_background(has_transparent_background_);
- host_->SetDeviceScaleFactor(device_scale_factor_);
+ CreateLayerTreeHost();
ui_resource_provider_.SetLayerTreeHost(host_.get());
}
+ root_window_->OnVisibilityChanged(visible);
}
void CompositorImpl::setDeviceScaleFactor(float factor) {
@@ -430,6 +490,8 @@ void CompositorImpl::SetWindowBounds(const gfx::Size& size) {
size_ = size;
if (host_)
host_->SetViewportSize(size);
+ if (display_client_)
+ display_client_->display()->Resize(size);
root_layer_->SetBounds(size);
}
@@ -453,8 +515,6 @@ CreateGpuProcessViewContext(
const scoped_refptr<GpuChannelHost>& gpu_channel_host,
const blink::WebGraphicsContext3D::Attributes attributes,
int surface_id) {
- DCHECK(gpu_channel_host.get());
-
GURL url("chrome://gpu/Compositor::createContext3D");
static const size_t kBytesPerPixel = 4;
gfx::DeviceDisplayInfo display_info;
@@ -486,24 +546,58 @@ void CompositorImpl::Layout() {
ignore_schedule_composite_ = false;
}
-void CompositorImpl::RequestNewOutputSurface(bool fallback) {
+void CompositorImpl::OnGpuChannelEstablished() {
+ establish_gpu_channel_timeout_.Stop();
+ CreateOutputSurface();
+}
+
+void CompositorImpl::OnGpuChannelTimeout() {
+ LOG(FATAL) << "Timed out waiting for GPU channel.";
+}
+
+void CompositorImpl::RequestNewOutputSurface() {
+ output_surface_request_pending_ = true;
+
+#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) || defined(SYZYASAN)
+ const int64 kGpuChannelTimeoutInSeconds = 30;
+#else
+ const int64 kGpuChannelTimeoutInSeconds = 10;
+#endif
+
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));
+ CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE,
+ base::Bind(&CompositorImpl::OnGpuChannelEstablished,
+ weak_factory_.GetWeakPtr()));
+ establish_gpu_channel_timeout_.Start(
+ FROM_HERE, base::TimeDelta::FromSeconds(kGpuChannelTimeoutInSeconds),
+ this, &CompositorImpl::OnGpuChannelTimeout);
return;
}
- CreateOutputSurface(fallback);
+ CreateOutputSurface();
}
-void CompositorImpl::CreateOutputSurface(bool fallback) {
+void CompositorImpl::DidInitializeOutputSurface() {
+ num_successive_context_creation_failures_ = 0;
+ output_surface_request_pending_ = false;
+}
+
+void CompositorImpl::DidFailToInitializeOutputSurface() {
+ LOG(ERROR) << "Failed to init OutputSurface for compositor.";
+ LOG_IF(FATAL, ++num_successive_context_creation_failures_ >= 2)
+ << "Too many context creation failures. Giving up... ";
+ RequestNewOutputSurface();
+}
+
+void CompositorImpl::CreateOutputSurface() {
+ // We might have had a request from a LayerTreeHost that was then
+ // deleted.
+ if (!output_surface_request_pending_)
+ return;
+
blink::WebGraphicsContext3D::Attributes attrs;
attrs.shareResources = true;
attrs.noAutomaticFlushes = true;
@@ -512,24 +606,41 @@ void CompositorImpl::CreateOutputSurface(bool fallback) {
DCHECK(window_);
DCHECK(surface_id_);
- scoped_refptr<ContextProviderCommandBuffer> context_provider;
BrowserGpuChannelHostFactory* factory =
BrowserGpuChannelHostFactory::instance();
- scoped_refptr<GpuChannelHost> gpu_channel_host = factory->GetGpuChannel();
- 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.";
- host_->SetOutputSurface(scoped_ptr<cc::OutputSurface>());
- return;
+ // This channel might be lost (and even if it isn't right now, it might
+ // still get marked as lost from the IO thread, at any point in time really).
+ // But from here on just try and always lead to either
+ // DidInitializeOutputSurface() or DidFailToInitializeOutputSurface().
+ scoped_refptr<GpuChannelHost> gpu_channel_host(factory->GetGpuChannel());
+ scoped_refptr<ContextProviderCommandBuffer> context_provider(
+ ContextProviderCommandBuffer::Create(
+ CreateGpuProcessViewContext(gpu_channel_host, attrs, surface_id_),
+ BROWSER_COMPOSITOR_ONSCREEN_CONTEXT));
+ DCHECK(context_provider.get());
+
+ scoped_ptr<cc::OutputSurface> real_output_surface(
+ new OutputSurfaceWithoutParent(context_provider,
+ weak_factory_.GetWeakPtr()));
+
+ cc::SurfaceManager* manager = GetSurfaceManager();
+ if (manager) {
+ display_client_.reset(new cc::OnscreenDisplayClient(
+ real_output_surface.Pass(), manager, HostSharedBitmapManager::current(),
+ BrowserGpuMemoryBufferManager::current(),
+ host_->settings().renderer_settings,
+ base::MessageLoopProxy::current()));
+ scoped_ptr<cc::SurfaceDisplayOutputSurface> surface_output_surface(
+ new cc::SurfaceDisplayOutputSurface(
+ manager, surface_id_allocator_.get(), context_provider));
+
+ display_client_->set_surface_output_surface(surface_output_surface.get());
+ surface_output_surface->set_display_client(display_client_.get());
+ display_client_->display()->Resize(size_);
+ host_->SetOutputSurface(surface_output_surface.Pass());
+ } else {
+ host_->SetOutputSurface(real_output_surface.Pass());
}
-
- host_->SetOutputSurface(
- scoped_ptr<cc::OutputSurface>(new OutputSurfaceWithoutParent(
- context_provider, weak_factory_.GetWeakPtr())));
}
void CompositorImpl::PopulateGpuCapabilities(
@@ -538,10 +649,6 @@ void CompositorImpl::PopulateGpuCapabilities(
gpu_capabilities.texture_format_etc1_npot);
}
-void CompositorImpl::OnLostResources() {
- client_->DidLoseResources();
-}
-
void CompositorImpl::ScheduleComposite() {
DCHECK(!needs_composite_ || WillComposite());
if (ignore_schedule_composite_)
@@ -625,6 +732,7 @@ void CompositorImpl::OnVSync(base::TimeTicks frame_time,
}
void CompositorImpl::SetNeedsAnimate() {
+ needs_animate_ = true;
if (!host_)
return;
diff --git a/chromium/content/browser/renderer_host/compositor_impl_android.h b/chromium/content/browser/renderer_host/compositor_impl_android.h
index 402271b1084..672a5664f74 100644
--- a/chromium/content/browser/renderer_host/compositor_impl_android.h
+++ b/chromium/content/browser/renderer_host/compositor_impl_android.h
@@ -10,17 +10,17 @@
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
+#include "base/timer/timer.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"
+#include "ui/android/resources/resource_manager_impl.h"
+#include "ui/android/resources/ui_resource_provider.h"
+#include "ui/android/window_android_compositor.h"
class SkBitmap;
struct ANativeWindow;
@@ -28,11 +28,13 @@ struct ANativeWindow;
namespace cc {
class Layer;
class LayerTreeHost;
+class OnscreenDisplayClient;
+class SurfaceIdAllocator;
+class SurfaceManager;
}
namespace content {
class CompositorClient;
-class UIResourceProvider;
// -----------------------------------------------------------------------------
// Browser-side compositor that manages a tree of content and UI layers.
@@ -41,67 +43,68 @@ class CONTENT_EXPORT CompositorImpl
: public Compositor,
public cc::LayerTreeHostClient,
public cc::LayerTreeHostSingleThreadClient,
- public ImageTransportFactoryAndroidObserver,
public ui::WindowAndroidCompositor {
public:
CompositorImpl(CompositorClient* client, gfx::NativeWindow root_window);
- virtual ~CompositorImpl();
+ ~CompositorImpl() override;
static bool IsInitialized();
+ static cc::SurfaceManager* GetSurfaceManager();
+ static scoped_ptr<cc::SurfaceIdAllocator> CreateSurfaceIdAllocator();
+
void PopulateGpuCapabilities(gpu::Capabilities gpu_capabilities);
private:
// Compositor implementation.
- 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;
+ void SetRootLayer(scoped_refptr<cc::Layer> root) override;
+ void SetSurface(jobject surface) override;
+ void setDeviceScaleFactor(float factor) override;
+ void SetWindowBounds(const gfx::Size& size) override;
+ void SetHasTransparentBackground(bool flag) override;
+ void SetNeedsComposite() override;
+ ui::UIResourceProvider& GetUIResourceProvider() override;
+ ui::ResourceManager& GetResourceManager() override;
// LayerTreeHostClient implementation.
- 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;
+ void WillBeginMainFrame() override {}
+ void DidBeginMainFrame() override {}
+ void BeginMainFrame(const cc::BeginFrameArgs& args) override {}
+ void BeginMainFrameNotExpectedSoon() override {}
+ void Layout() override;
+ void ApplyViewportDeltas(const gfx::Vector2dF& inner_delta,
+ const gfx::Vector2dF& outer_delta,
+ const gfx::Vector2dF& elastic_overscroll_delta,
+ float page_scale,
+ float top_controls_delta) override {}
+ void ApplyViewportDeltas(const gfx::Vector2d& scroll_delta,
+ float page_scale,
+ float top_controls_delta) override {}
+ void RequestNewOutputSurface() override;
+ void DidInitializeOutputSurface() override;
+ void DidFailToInitializeOutputSurface() override;
+ void WillCommit() override {}
+ void DidCommit() override;
+ void DidCommitAndDrawFrame() override {}
+ void DidCompleteSwapBuffers() override;
+ void DidCompletePageScaleAnimation() override {}
// LayerTreeHostSingleThreadClient implementation.
- virtual void ScheduleComposite() override;
- virtual void ScheduleAnimation() override;
- virtual void DidPostSwapBuffers() override;
- virtual void DidAbortSwapBuffers() override;
-
- // ImageTransportFactoryAndroidObserver implementation.
- virtual void OnLostResources() override;
+ void ScheduleComposite() override;
+ void ScheduleAnimation() override;
+ void DidPostSwapBuffers() override;
+ void DidAbortSwapBuffers() override;
// WindowAndroidCompositor implementation.
- virtual void AttachLayerForReadback(scoped_refptr<cc::Layer> layer) override;
- virtual void RequestCopyOfOutputOnRootLayer(
+ void AttachLayerForReadback(scoped_refptr<cc::Layer> layer) override;
+ void RequestCopyOfOutputOnRootLayer(
scoped_ptr<cc::CopyOutputRequest> request) override;
- virtual void OnVSync(base::TimeTicks frame_time,
- base::TimeDelta vsync_period) override;
- virtual void SetNeedsAnimate() override;
- virtual ui::SystemUIResourceManager& GetSystemUIResourceManager() override;
+ void OnVSync(base::TimeTicks frame_time,
+ base::TimeDelta vsync_period) override;
+ void SetNeedsAnimate() override;
void SetWindowSurface(ANativeWindow* window);
+ void SetVisible(bool visible);
enum CompositingTrigger {
DO_NOT_COMPOSITE,
@@ -110,7 +113,7 @@ class CONTENT_EXPORT CompositorImpl
};
void PostComposite(CompositingTrigger trigger);
void Composite(CompositingTrigger trigger);
- void CreateOutputSurface(bool fallback);
+ void CreateOutputSurface();
bool WillCompositeThisFrame() const {
return current_composite_task_ &&
@@ -132,7 +135,10 @@ class CONTENT_EXPORT CompositorImpl
composite_on_vsync_trigger_ = DO_NOT_COMPOSITE;
will_composite_immediately_ = false;
}
+ void CreateLayerTreeHost();
+
void OnGpuChannelEstablished();
+ void OnGpuChannelTimeout();
// root_layer_ is the persistent internal root layer, while subroot_layer_
// is the one attached by the compositor client.
@@ -140,7 +146,11 @@ class CONTENT_EXPORT CompositorImpl
scoped_refptr<cc::Layer> subroot_layer_;
scoped_ptr<cc::LayerTreeHost> host_;
- content::UIResourceProviderImpl ui_resource_provider_;
+ ui::UIResourceProvider ui_resource_provider_;
+ ui::ResourceManagerImpl resource_manager_;
+
+ scoped_ptr<cc::OnscreenDisplayClient> display_client_;
+ scoped_ptr<cc::SurfaceIdAllocator> surface_id_allocator_;
gfx::Size size_;
bool has_transparent_background_;
@@ -180,9 +190,19 @@ class CONTENT_EXPORT CompositorImpl
// the GPU thread.
unsigned int pending_swapbuffers_;
+ size_t num_successive_context_creation_failures_;
+
base::TimeDelta vsync_period_;
base::TimeTicks last_vsync_;
+ base::OneShotTimer<CompositorImpl> establish_gpu_channel_timeout_;
+
+ // Whether there is an OutputSurface request pending from the current
+ // |host_|. Becomes |true| if RequestNewOutputSurface is called, and |false|
+ // if |host_| is deleted or we succeed in creating *and* initializing an
+ // OutputSurface (which is essentially the contract with cc).
+ bool output_surface_request_pending_;
+
base::WeakPtrFactory<CompositorImpl> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(CompositorImpl);
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 9d5b7d87274..2d36b2f859f 100644
--- a/chromium/content/browser/renderer_host/compositor_resize_lock_aura.cc
+++ b/chromium/content/browser/renderer_host/compositor_resize_lock_aura.cc
@@ -4,7 +4,7 @@
#include "content/browser/renderer_host/compositor_resize_lock_aura.h"
-#include "base/debug/trace_event.h"
+#include "base/trace_event/trace_event.h"
#include "content/public/browser/browser_thread.h"
#include "ui/aura/window_event_dispatcher.h"
#include "ui/aura/window_tree_host.h"
diff --git a/chromium/content/browser/renderer_host/database_message_filter.cc b/chromium/content/browser/renderer_host/database_message_filter.cc
index bb5bdd6946e..4b37773dd2a 100644
--- a/chromium/content/browser/renderer_host/database_message_filter.cc
+++ b/chromium/content/browser/renderer_host/database_message_filter.cc
@@ -89,16 +89,15 @@ void DatabaseMessageFilter::OverrideThreadForMessage(
bool DatabaseMessageFilter::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(DatabaseMessageFilter, message)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(DatabaseHostMsg_OpenFile,
- OnDatabaseOpenFile)
+ IPC_MESSAGE_HANDLER(DatabaseHostMsg_OpenFile, OnDatabaseOpenFile)
IPC_MESSAGE_HANDLER_DELAY_REPLY(DatabaseHostMsg_DeleteFile,
OnDatabaseDeleteFile)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(DatabaseHostMsg_GetFileAttributes,
- OnDatabaseGetFileAttributes)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(DatabaseHostMsg_GetFileSize,
- OnDatabaseGetFileSize)
+ IPC_MESSAGE_HANDLER(DatabaseHostMsg_GetFileAttributes,
+ OnDatabaseGetFileAttributes)
+ IPC_MESSAGE_HANDLER(DatabaseHostMsg_GetFileSize, OnDatabaseGetFileSize)
IPC_MESSAGE_HANDLER_DELAY_REPLY(DatabaseHostMsg_GetSpaceAvailable,
OnDatabaseGetSpaceAvailable)
+ IPC_MESSAGE_HANDLER(DatabaseHostMsg_SetFileSize, OnDatabaseSetFileSize)
IPC_MESSAGE_HANDLER(DatabaseHostMsg_Opened, OnDatabaseOpened)
IPC_MESSAGE_HANDLER(DatabaseHostMsg_Modified, OnDatabaseModified)
IPC_MESSAGE_HANDLER(DatabaseHostMsg_Closed, OnDatabaseClosed)
@@ -114,7 +113,7 @@ DatabaseMessageFilter::~DatabaseMessageFilter() {
void DatabaseMessageFilter::OnDatabaseOpenFile(
const base::string16& vfs_file_name,
int desired_flags,
- IPC::Message* reply_msg) {
+ IPC::PlatformFileForTransit* handle) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
base::File file;
const base::File* tracked_file = NULL;
@@ -156,19 +155,15 @@ void DatabaseMessageFilter::OnDatabaseOpenFile(
// Then we duplicate the file handle to make it useable in the renderer
// process. The original handle is closed, unless we saved it in the
// database tracker.
- IPC::PlatformFileForTransit target_handle =
- IPC::InvalidPlatformFileForTransit();
+ *handle = IPC::InvalidPlatformFileForTransit();
if (file.IsValid()) {
- target_handle = IPC::TakeFileHandleForProcess(file.Pass(), PeerHandle());
+ *handle = IPC::TakeFileHandleForProcess(file.Pass(), PeerHandle());
} else if (tracked_file) {
DCHECK(tracked_file->IsValid());
- target_handle =
+ *handle =
IPC::GetFileHandleForProcess(tracked_file->GetPlatformFile(),
PeerHandle(), false);
}
-
- DatabaseHostMsg_OpenFile::WriteReplyParams(reply_msg, target_handle);
- Send(reply_msg);
}
void DatabaseMessageFilter::OnDatabaseDeleteFile(
@@ -228,30 +223,24 @@ void DatabaseMessageFilter::DatabaseDeleteFile(
void DatabaseMessageFilter::OnDatabaseGetFileAttributes(
const base::string16& vfs_file_name,
- IPC::Message* reply_msg) {
+ int32* attributes) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
- int32 attributes = -1;
+ *attributes = -1;
base::FilePath db_file =
DatabaseUtil::GetFullFilePathForVfsFile(db_tracker_.get(), vfs_file_name);
if (!db_file.empty())
- attributes = VfsBackend::GetFileAttributes(db_file);
-
- DatabaseHostMsg_GetFileAttributes::WriteReplyParams(
- reply_msg, attributes);
- Send(reply_msg);
+ *attributes = VfsBackend::GetFileAttributes(db_file);
}
void DatabaseMessageFilter::OnDatabaseGetFileSize(
- const base::string16& vfs_file_name, IPC::Message* reply_msg) {
+ const base::string16& vfs_file_name,
+ int64* size) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
- int64 size = 0;
+ *size = 0;
base::FilePath db_file =
DatabaseUtil::GetFullFilePathForVfsFile(db_tracker_.get(), vfs_file_name);
if (!db_file.empty())
- size = VfsBackend::GetFileSize(db_file);
-
- DatabaseHostMsg_GetFileSize::WriteReplyParams(reply_msg, size);
- Send(reply_msg);
+ *size = VfsBackend::GetFileSize(db_file);
}
void DatabaseMessageFilter::OnDatabaseGetSpaceAvailable(
@@ -288,6 +277,16 @@ void DatabaseMessageFilter::OnDatabaseGetUsageAndQuota(
Send(reply_msg);
}
+void DatabaseMessageFilter::OnDatabaseSetFileSize(
+ const base::string16& vfs_file_name, int64 size, bool* success) {
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+ *success = false;
+ base::FilePath db_file =
+ DatabaseUtil::GetFullFilePathForVfsFile(db_tracker_.get(), vfs_file_name);
+ if (!db_file.empty())
+ *success = VfsBackend::SetFileSize(db_file, size);
+}
+
void DatabaseMessageFilter::OnDatabaseOpened(
const std::string& origin_identifier,
const base::string16& database_name,
diff --git a/chromium/content/browser/renderer_host/database_message_filter.h b/chromium/content/browser/renderer_host/database_message_filter.h
index dcac74ab2bc..13f27bcda3a 100644
--- a/chromium/content/browser/renderer_host/database_message_filter.h
+++ b/chromium/content/browser/renderer_host/database_message_filter.h
@@ -8,6 +8,7 @@
#include "base/containers/hash_tables.h"
#include "base/strings/string16.h"
#include "content/public/browser/browser_message_filter.h"
+#include "ipc/ipc_platform_file.h"
#include "storage/browser/database/database_tracker.h"
#include "storage/common/database/database_connections.h"
#include "storage/common/quota/quota_types.h"
@@ -40,14 +41,17 @@ class DatabaseMessageFilter : public BrowserMessageFilter,
// VFS message handlers (file thread)
void OnDatabaseOpenFile(const base::string16& vfs_file_name,
int desired_flags,
- IPC::Message* reply_msg);
+ IPC::PlatformFileForTransit* handle);
void OnDatabaseDeleteFile(const base::string16& vfs_file_name,
const bool& sync_dir,
IPC::Message* reply_msg);
void OnDatabaseGetFileAttributes(const base::string16& vfs_file_name,
- IPC::Message* reply_msg);
+ int32* attributes);
void OnDatabaseGetFileSize(const base::string16& vfs_file_name,
- IPC::Message* reply_msg);
+ int64* size);
+ void OnDatabaseSetFileSize(const base::string16& vfs_file_name,
+ int64 size,
+ bool* success);
// Quota message handler (io thread)
void OnDatabaseGetSpaceAvailable(const std::string& origin_identifier,
diff --git a/chromium/content/browser/renderer_host/delegated_frame_evictor.cc b/chromium/content/browser/renderer_host/delegated_frame_evictor.cc
index 33d6b2c479f..65ae4832932 100644
--- a/chromium/content/browser/renderer_host/delegated_frame_evictor.cc
+++ b/chromium/content/browser/renderer_host/delegated_frame_evictor.cc
@@ -10,11 +10,13 @@ namespace content {
DelegatedFrameEvictor::DelegatedFrameEvictor(
DelegatedFrameEvictorClient* client)
- : client_(client), has_frame_(false) {}
+ : client_(client), has_frame_(false), visible_(false) {
+}
DelegatedFrameEvictor::~DelegatedFrameEvictor() { DiscardedFrame(); }
void DelegatedFrameEvictor::SwappedFrame(bool visible) {
+ visible_ = visible;
has_frame_ = true;
RendererFrameManager::GetInstance()->AddFrame(this, visible);
}
@@ -25,11 +27,14 @@ void DelegatedFrameEvictor::DiscardedFrame() {
}
void DelegatedFrameEvictor::SetVisible(bool visible) {
+ if (visible_ == visible)
+ return;
+ visible_ = visible;
if (has_frame_) {
if (visible) {
- RendererFrameManager::GetInstance()->LockFrame(this);
+ LockFrame();
} else {
- RendererFrameManager::GetInstance()->UnlockFrame(this);
+ UnlockFrame();
}
}
}
diff --git a/chromium/content/browser/renderer_host/delegated_frame_evictor.h b/chromium/content/browser/renderer_host/delegated_frame_evictor.h
index 796b6c255f0..9e9f68a61ad 100644
--- a/chromium/content/browser/renderer_host/delegated_frame_evictor.h
+++ b/chromium/content/browser/renderer_host/delegated_frame_evictor.h
@@ -35,6 +35,7 @@ class CONTENT_EXPORT DelegatedFrameEvictor : public RendererFrameManagerClient {
DelegatedFrameEvictorClient* client_;
bool has_frame_;
+ bool visible_;
DISALLOW_COPY_AND_ASSIGN(DelegatedFrameEvictor);
};
diff --git a/chromium/content/browser/renderer_host/dip_util.cc b/chromium/content/browser/renderer_host/dip_util.cc
index 30490158a3c..225d17bcb44 100644
--- a/chromium/content/browser/renderer_host/dip_util.cc
+++ b/chromium/content/browser/renderer_host/dip_util.cc
@@ -7,13 +7,14 @@
#include "content/public/browser/render_widget_host_view.h"
#include "ui/base/layout.h"
#include "ui/gfx/display.h"
-#include "ui/gfx/point.h"
-#include "ui/gfx/point_conversions.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/rect_conversions.h"
+#include "ui/gfx/geometry/dip_util.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/point_conversions.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/screen.h"
-#include "ui/gfx/size.h"
-#include "ui/gfx/size_conversions.h"
namespace content {
@@ -23,41 +24,17 @@ float GetScaleFactorForView(const RenderWidgetHostView* view) {
gfx::Point ConvertViewPointToDIP(const RenderWidgetHostView* view,
const gfx::Point& point_in_pixel) {
- return gfx::ToFlooredPoint(
- gfx::ScalePoint(point_in_pixel, 1.0f / GetScaleFactorForView(view)));
+ return gfx::ConvertPointToDIP(GetScaleFactorForView(view), point_in_pixel);
}
gfx::Size ConvertViewSizeToPixel(const RenderWidgetHostView* view,
const gfx::Size& size_in_dip) {
- return ConvertSizeToPixel(GetScaleFactorForView(view), size_in_dip);
+ return gfx::ConvertSizeToPixel(GetScaleFactorForView(view), size_in_dip);
}
gfx::Rect ConvertViewRectToPixel(const RenderWidgetHostView* view,
const gfx::Rect& rect_in_dip) {
- return ConvertRectToPixel(GetScaleFactorForView(view), rect_in_dip);
-}
-
-gfx::Size ConvertSizeToDIP(float scale_factor,
- const gfx::Size& size_in_pixel) {
- return gfx::ToFlooredSize(
- gfx::ScaleSize(size_in_pixel, 1.0f / scale_factor));
-}
-
-gfx::Rect ConvertRectToDIP(float scale_factor,
- const gfx::Rect& rect_in_pixel) {
- return gfx::ToFlooredRectDeprecated(
- gfx::ScaleRect(rect_in_pixel, 1.0f / scale_factor));
-}
-
-gfx::Size ConvertSizeToPixel(float scale_factor,
- const gfx::Size& size_in_dip) {
- return gfx::ToFlooredSize(gfx::ScaleSize(size_in_dip, scale_factor));
-}
-
-gfx::Rect ConvertRectToPixel(float scale_factor,
- const gfx::Rect& rect_in_dip) {
- return gfx::ToFlooredRectDeprecated(
- gfx::ScaleRect(rect_in_dip, scale_factor));
+ return gfx::ConvertRectToPixel(GetScaleFactorForView(view), rect_in_dip);
}
} // namespace content
diff --git a/chromium/content/browser/renderer_host/dip_util.h b/chromium/content/browser/renderer_host/dip_util.h
index 27e7dd19e9e..4da0012f7c8 100644
--- a/chromium/content/browser/renderer_host/dip_util.h
+++ b/chromium/content/browser/renderer_host/dip_util.h
@@ -29,15 +29,6 @@ CONTENT_EXPORT gfx::Size ConvertViewSizeToPixel(
CONTENT_EXPORT gfx::Rect ConvertViewRectToPixel(
const RenderWidgetHostView* view, const gfx::Rect& rect_in_dip);
-CONTENT_EXPORT gfx::Size ConvertSizeToDIP(
- float scale_factor, const gfx::Size& size_in_pixel);
-CONTENT_EXPORT gfx::Rect ConvertRectToDIP(
- float scale_factor, const gfx::Rect& rect_in_pixel);
-CONTENT_EXPORT gfx::Size ConvertSizeToPixel(
- float scale_factor, const gfx::Size& size_in_pixel);
-CONTENT_EXPORT gfx::Rect ConvertRectToPixel(
- float scale_factor, const gfx::Rect& rect_in_dip);
-
} // namespace content
#endif // CONTENT_BROWSER_RENDERER_HOST_DIP_UTIL_H_
diff --git a/chromium/content/browser/renderer_host/display_link_mac.cc b/chromium/content/browser/renderer_host/display_link_mac.cc
index b4592a9f3b7..79920f6f10b 100644
--- a/chromium/content/browser/renderer_host/display_link_mac.cc
+++ b/chromium/content/browser/renderer_host/display_link_mac.cc
@@ -4,8 +4,9 @@
#include "content/browser/renderer_host/display_link_mac.h"
-#include "base/debug/trace_event.h"
#include "base/logging.h"
+#include "base/trace_event/trace_event.h"
+#include "content/browser/renderer_host/render_widget_resize_helper.h"
namespace base {
@@ -63,64 +64,70 @@ DisplayLinkMac::DisplayLinkMac(
base::ScopedTypeRef<CVDisplayLinkRef> display_link)
: display_id_(display_id),
display_link_(display_link),
- stop_timer_(
- FROM_HERE, base::TimeDelta::FromSeconds(1),
- this, &DisplayLinkMac::StopDisplayLink),
timebase_and_interval_valid_(false) {
DCHECK(display_map_.Get().find(display_id) == display_map_.Get().end());
+ if (display_map_.Get().empty()) {
+ CGError register_error = CGDisplayRegisterReconfigurationCallback(
+ DisplayReconfigurationCallBack, nullptr);
+ DPLOG_IF(ERROR, register_error != kCGErrorSuccess)
+ << "CGDisplayRegisterReconfigurationCallback: "
+ << register_error;
+ }
display_map_.Get().insert(std::make_pair(display_id_, this));
}
DisplayLinkMac::~DisplayLinkMac() {
- if (CVDisplayLinkIsRunning(display_link_))
- CVDisplayLinkStop(display_link_);
+ StopDisplayLink();
DisplayMap::iterator found = display_map_.Get().find(display_id_);
DCHECK(found != display_map_.Get().end());
DCHECK(found->second == this);
display_map_.Get().erase(found);
+ if (display_map_.Get().empty()) {
+ CGError remove_error = CGDisplayRemoveReconfigurationCallback(
+ DisplayReconfigurationCallBack, nullptr);
+ DPLOG_IF(ERROR, remove_error != kCGErrorSuccess)
+ << "CGDisplayRemoveReconfigurationCallback: "
+ << remove_error;
+ }
}
bool DisplayLinkMac::GetVSyncParameters(
base::TimeTicks* timebase, base::TimeDelta* interval) {
- StartOrContinueDisplayLink();
-
- base::AutoLock lock(lock_);
- if (!timebase_and_interval_valid_)
+ if (!timebase_and_interval_valid_) {
+ StartOrContinueDisplayLink();
return false;
+ }
*timebase = timebase_;
*interval = interval_;
return true;
}
-void DisplayLinkMac::Tick(const CVTimeStamp* cv_time) {
- TRACE_EVENT0("browser", "DisplayLinkMac::GetVSyncParameters");
- base::AutoLock lock(lock_);
+void DisplayLinkMac::Tick(const CVTimeStamp& cv_time) {
+ TRACE_EVENT0("browser", "DisplayLinkMac::Tick");
// Verify that videoRefreshPeriod is 32 bits.
- DCHECK((cv_time->videoRefreshPeriod & ~0xffffFFFFull) == 0ull);
+ DCHECK((cv_time.videoRefreshPeriod & ~0xffffFFFFull) == 0ull);
// Verify that the numerator and denominator make some sense.
- uint32 numerator = static_cast<uint32>(cv_time->videoRefreshPeriod);
- uint32 denominator = cv_time->videoTimeScale;
+ uint32 numerator = static_cast<uint32>(cv_time.videoRefreshPeriod);
+ uint32 denominator = cv_time.videoTimeScale;
if (numerator <= 0 || denominator <= 0) {
LOG(WARNING) << "Unexpected numerator or denominator, bailing.";
return;
}
timebase_ = base::TimeTicks::FromInternalValue(
- cv_time->hostTime / 1000);
+ cv_time.hostTime / 1000);
interval_ = base::TimeDelta::FromMicroseconds(
1000000 * static_cast<int64>(numerator) / denominator);
timebase_and_interval_valid_ = true;
+
+ StopDisplayLink();
}
void DisplayLinkMac::StartOrContinueDisplayLink() {
- // Reset the timer, so that the display link won't be turned off for another
- // second.
- stop_timer_.Reset();
-
if (CVDisplayLinkIsRunning(display_link_))
return;
@@ -140,6 +147,7 @@ void DisplayLinkMac::StopDisplayLink() {
}
}
+// static
CVReturn DisplayLinkMac::DisplayLinkCallback(
CVDisplayLinkRef display_link,
const CVTimeStamp* now,
@@ -147,12 +155,27 @@ CVReturn DisplayLinkMac::DisplayLinkCallback(
CVOptionFlags flags_in,
CVOptionFlags* flags_out,
void* context) {
+ TRACE_EVENT0("browser", "DisplayLinkMac::DisplayLinkCallback");
DisplayLinkMac* display_link_mac = static_cast<DisplayLinkMac*>(context);
- display_link_mac->Tick(output_time);
+ RenderWidgetResizeHelper::Get()->task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&DisplayLinkMac::Tick, display_link_mac, *output_time));
return kCVReturnSuccess;
}
// static
+void DisplayLinkMac::DisplayReconfigurationCallBack(
+ CGDirectDisplayID display,
+ CGDisplayChangeSummaryFlags flags,
+ void* user_info) {
+ DisplayMap::iterator found = display_map_.Get().find(display);
+ if (found == display_map_.Get().end())
+ return;
+ DisplayLinkMac* display_link_mac = found->second;
+ display_link_mac->timebase_and_interval_valid_ = false;
+}
+
+// static
base::LazyInstance<DisplayLinkMac::DisplayMap>
DisplayLinkMac::display_map_ = LAZY_INSTANCE_INITIALIZER;
diff --git a/chromium/content/browser/renderer_host/display_link_mac.h b/chromium/content/browser/renderer_host/display_link_mac.h
index 1833f8f2d3f..479e0642298 100644
--- a/chromium/content/browser/renderer_host/display_link_mac.h
+++ b/chromium/content/browser/renderer_host/display_link_mac.h
@@ -37,8 +37,10 @@ class DisplayLinkMac : public base::RefCounted<DisplayLinkMac> {
void StartOrContinueDisplayLink();
void StopDisplayLink();
- void Tick(const CVTimeStamp* time);
+ void Tick(const CVTimeStamp& time);
+ // Called by the system on the display link thread, and posts a call to Tick
+ // to the UI thread.
static CVReturn DisplayLinkCallback(
CVDisplayLinkRef display_link,
const CVTimeStamp* now,
@@ -47,24 +49,24 @@ class DisplayLinkMac : public base::RefCounted<DisplayLinkMac> {
CVOptionFlags* flags_out,
void* context);
+ // This is called whenever the display is reconfigured, and marks that the
+ // vsync parameters must be recalculated.
+ static void DisplayReconfigurationCallBack(
+ CGDirectDisplayID display,
+ CGDisplayChangeSummaryFlags flags,
+ void* user_info);
+
// The display that this display link is attached to.
CGDirectDisplayID display_id_;
// CVDisplayLink for querying VSync timing info.
base::ScopedTypeRef<CVDisplayLinkRef> display_link_;
- // Timer for stopping the display link if it has not been queried in
- // the last second.
- base::DelayTimer<DisplayLinkMac> stop_timer_;
-
// VSync parameters computed during Tick.
bool timebase_and_interval_valid_;
base::TimeTicks timebase_;
base::TimeDelta interval_;
- // Lock for sharing data between UI thread and display-link thread.
- base::Lock lock_;
-
// Each display link instance consumes a non-negligible number of cycles, so
// make all display links on the same screen share the same object.
typedef std::map<CGDirectDisplayID, DisplayLinkMac*> DisplayMap;
diff --git a/chromium/content/browser/renderer_host/event_with_latency_info.h b/chromium/content/browser/renderer_host/event_with_latency_info.h
index 483c4cffc39..37f67475b38 100644
--- a/chromium/content/browser/renderer_host/event_with_latency_info.h
+++ b/chromium/content/browser/renderer_host/event_with_latency_info.h
@@ -22,7 +22,9 @@ template <typename T>
class EventWithLatencyInfo {
public:
T event;
- ui::LatencyInfo latency;
+ mutable ui::LatencyInfo latency;
+
+ explicit EventWithLatencyInfo(const T& e) : event(e) {}
EventWithLatencyInfo(const T& e, const ui::LatencyInfo& l)
: event(e), latency(l) {}
diff --git a/chromium/content/browser/renderer_host/frame_metadata_util.cc b/chromium/content/browser/renderer_host/frame_metadata_util.cc
new file mode 100644
index 00000000000..11cf5d2e65e
--- /dev/null
+++ b/chromium/content/browser/renderer_host/frame_metadata_util.cc
@@ -0,0 +1,39 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/renderer_host/frame_metadata_util.h"
+
+#include "cc/output/compositor_frame_metadata.h"
+
+namespace {
+
+// Used to accomodate finite precision when comparing scaled viewport and
+// content widths. While this value may seem large, width=device-width on an N7
+// V1 saw errors of ~0.065 between computed window and content widths.
+const float kMobileViewportWidthEpsilon = 0.15f;
+
+bool HasFixedPageScale(const cc::CompositorFrameMetadata& frame_metadata) {
+ return frame_metadata.min_page_scale_factor ==
+ frame_metadata.max_page_scale_factor;
+}
+
+bool HasMobileViewport(const cc::CompositorFrameMetadata& frame_metadata) {
+ float window_width_dip =
+ 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;
+}
+
+} // namespace
+
+namespace content {
+
+bool IsMobileOptimizedFrame(const cc::CompositorFrameMetadata& frame_metadata) {
+ bool has_mobile_viewport = HasMobileViewport(frame_metadata);
+ bool has_fixed_page_scale = HasFixedPageScale(frame_metadata);
+ return has_fixed_page_scale || has_mobile_viewport;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/renderer_host/frame_metadata_util.h b/chromium/content/browser/renderer_host/frame_metadata_util.h
new file mode 100644
index 00000000000..54b97b8054c
--- /dev/null
+++ b/chromium/content/browser/renderer_host/frame_metadata_util.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_FRAME_METADATA_UTIL_H_
+#define CONTENT_BROWSER_RENDERER_HOST_FRAME_METADATA_UTIL_H_
+
+#include "content/common/content_export.h"
+
+namespace cc {
+class CompositorFrameMetadata;
+}
+
+namespace content {
+
+// Decides whether frame metadata corresponds to mobile-optimized content.
+// By default returns |false|, except for the following cases:
+// - page that has a width=device-width or narrower viewport
+// (indicating that this is a mobile-optimized or responsive web design);
+// - page that prevents zooming in or out.
+CONTENT_EXPORT bool IsMobileOptimizedFrame(
+ const cc::CompositorFrameMetadata& frame_metadata);
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_RENDERER_HOST_FRAME_METADATA_UTIL_H_
diff --git a/chromium/content/browser/renderer_host/gamepad_browser_message_filter.cc b/chromium/content/browser/renderer_host/gamepad_browser_message_filter.cc
index ef66a5cbd30..c03e478827e 100644
--- a/chromium/content/browser/renderer_host/gamepad_browser_message_filter.cc
+++ b/chromium/content/browser/renderer_host/gamepad_browser_message_filter.cc
@@ -46,14 +46,20 @@ void GamepadBrowserMessageFilter::OnGamepadDisconnected(
void GamepadBrowserMessageFilter::OnGamepadStartPolling(
base::SharedMemoryHandle* renderer_handle) {
GamepadService* service = GamepadService::GetInstance();
- CHECK(!is_started_);
+ DCHECK(!is_started_);
+ if (is_started_)
+ return;
+
is_started_ = true;
service->ConsumerBecameActive(this);
*renderer_handle = service->GetSharedMemoryHandleForProcess(PeerHandle());
}
void GamepadBrowserMessageFilter::OnGamepadStopPolling() {
- CHECK(is_started_);
+ DCHECK(is_started_);
+ if (!is_started_)
+ return;
+
is_started_ = false;
GamepadService::GetInstance()->ConsumerBecameInactive(this);
}
diff --git a/chromium/content/browser/renderer_host/image_transport_factory_android.cc b/chromium/content/browser/renderer_host/image_transport_factory_android.cc
deleted file mode 100644
index 41e315608e0..00000000000
--- a/chromium/content/browser/renderer_host/image_transport_factory_android.cc
+++ /dev/null
@@ -1,160 +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/image_transport_factory_android.h"
-
-#include "base/lazy_instance.h"
-#include "base/strings/stringprintf.h"
-#include "content/browser/gpu/browser_gpu_channel_host_factory.h"
-#include "content/common/gpu/client/gl_helper.h"
-#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
-#include "content/common/gpu/gpu_process_launch_causes.h"
-#include "gpu/command_buffer/client/gles2_implementation.h"
-#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
-#include "third_party/khronos/GLES2/gl2.h"
-#include "ui/gfx/android/device_display_info.h"
-
-namespace content {
-
-base::LazyInstance<ObserverList<ImageTransportFactoryAndroidObserver> >::Leaky
- g_factory_observers = LAZY_INSTANCE_INITIALIZER;
-
-class GLContextLostListener
- : public blink::WebGraphicsContext3D::WebGraphicsContextLostCallback {
- public:
- // WebGraphicsContextLostCallback implementation.
- virtual void onContextLost() override;
- private:
- static void DidLoseContext();
-};
-
-namespace {
-
-static ImageTransportFactoryAndroid* g_factory = NULL;
-
-class CmdBufferImageTransportFactory : public ImageTransportFactoryAndroid {
- public:
- CmdBufferImageTransportFactory();
- virtual ~CmdBufferImageTransportFactory();
-
- virtual GLHelper* GetGLHelper() override;
- virtual uint32 GetChannelID() override {
- return BrowserGpuChannelHostFactory::instance()->GetGpuChannelId();
- }
-
- private:
- scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context_;
- scoped_ptr<GLHelper> gl_helper_;
-
- DISALLOW_COPY_AND_ASSIGN(CmdBufferImageTransportFactory);
-};
-
-CmdBufferImageTransportFactory::CmdBufferImageTransportFactory() {
- BrowserGpuChannelHostFactory* factory =
- BrowserGpuChannelHostFactory::instance();
- scoped_refptr<GpuChannelHost> gpu_channel_host(factory->EstablishGpuChannelSync(
- CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE));
- DCHECK(gpu_channel_host.get());
-
- blink::WebGraphicsContext3D::Attributes attrs;
- attrs.shareResources = true;
- GURL url("chrome://gpu/ImageTransportFactoryAndroid");
- static const size_t kBytesPerPixel = 4;
- gfx::DeviceDisplayInfo display_info;
- size_t full_screen_texture_size_in_bytes = display_info.GetDisplayHeight() *
- display_info.GetDisplayWidth() *
- kBytesPerPixel;
- WebGraphicsContext3DCommandBufferImpl::SharedMemoryLimits limits;
- limits.command_buffer_size = 64 * 1024;
- limits.start_transfer_buffer_size = 64 * 1024;
- limits.min_transfer_buffer_size = 64 * 1024;
- limits.max_transfer_buffer_size = std::min(
- 3 * full_screen_texture_size_in_bytes, kDefaultMaxTransferBufferSize);
- limits.mapped_memory_reclaim_limit =
- WebGraphicsContext3DCommandBufferImpl::kNoLimit;
- bool lose_context_when_out_of_memory = false;
- context_.reset(
- new WebGraphicsContext3DCommandBufferImpl(0, // offscreen
- url,
- gpu_channel_host.get(),
- attrs,
- lose_context_when_out_of_memory,
- limits,
- NULL));
- context_->setContextLostCallback(context_lost_listener_.get());
- if (context_->InitializeOnCurrentThread())
- context_->pushGroupMarkerEXT(
- base::StringPrintf("CmdBufferImageTransportFactory-%p",
- context_.get()).c_str());
-}
-
-CmdBufferImageTransportFactory::~CmdBufferImageTransportFactory() {
- context_->setContextLostCallback(NULL);
-}
-
-GLHelper* CmdBufferImageTransportFactory::GetGLHelper() {
- if (!gl_helper_)
- gl_helper_.reset(new GLHelper(context_->GetImplementation(),
- context_->GetContextSupport()));
-
- return gl_helper_.get();
-}
-
-} // 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();
-
- return g_factory;
-}
-
-ImageTransportFactoryAndroid::ImageTransportFactoryAndroid()
- : context_lost_listener_(new GLContextLostListener()) {}
-
-ImageTransportFactoryAndroid::~ImageTransportFactoryAndroid() {}
-
-void ImageTransportFactoryAndroid::AddObserver(
- ImageTransportFactoryAndroidObserver* observer) {
- g_factory_observers.Get().AddObserver(observer);
-}
-
-void ImageTransportFactoryAndroid::RemoveObserver(
- ImageTransportFactoryAndroidObserver* observer) {
- g_factory_observers.Get().RemoveObserver(observer);
-}
-
-void GLContextLostListener::onContextLost() {
- // Need to post a task because the command buffer client cannot be deleted
- // from within this callback.
- LOG(ERROR) << "Context lost.";
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&GLContextLostListener::DidLoseContext));
-}
-
-void GLContextLostListener::DidLoseContext() {
- delete g_factory;
- g_factory = NULL;
- FOR_EACH_OBSERVER(ImageTransportFactoryAndroidObserver,
- g_factory_observers.Get(),
- OnLostResources());
-}
-
-} // namespace content
diff --git a/chromium/content/browser/renderer_host/image_transport_factory_android.h b/chromium/content/browser/renderer_host/image_transport_factory_android.h
deleted file mode 100644
index 25623811406..00000000000
--- a/chromium/content/browser/renderer_host/image_transport_factory_android.h
+++ /dev/null
@@ -1,58 +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_IMAGE_TRANSPORT_FACTORY_ANDROID_H_
-#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 {
-class GLShareGroup;
-}
-
-namespace gpu {
-namespace gles2 {
-class GLES2Interface;
-}
-}
-
-namespace content {
-class GLHelper;
-class GLContextLostListener;
-
-class ImageTransportFactoryAndroidObserver {
- public:
- virtual ~ImageTransportFactoryAndroidObserver() {}
- virtual void OnLostResources() = 0;
-};
-
-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;
- virtual uint32 GetChannelID() = 0;
-
- static void AddObserver(ImageTransportFactoryAndroidObserver* observer);
- static void RemoveObserver(ImageTransportFactoryAndroidObserver* observer);
-
-protected:
- ImageTransportFactoryAndroid();
-
- scoped_ptr<GLContextLostListener> context_lost_listener_;
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_RENDERER_HOST_IMAGE_TRANSPORT_FACTORY_ANDROID_H_
diff --git a/chromium/content/browser/renderer_host/ime_adapter_android.cc b/chromium/content/browser/renderer_host/ime_adapter_android.cc
index b7d3748002d..ac820f5765c 100644
--- a/chromium/content/browser/renderer_host/ime_adapter_android.cc
+++ b/chromium/content/browser/renderer_host/ime_adapter_android.cc
@@ -11,7 +11,6 @@
#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"
@@ -58,6 +57,8 @@ NativeWebKeyboardEvent NativeWebKeyboardEventFromKeyEvent(
type = blink::WebInputEvent::RawKeyDown;
else if (action == AKEY_EVENT_ACTION_UP)
type = blink::WebInputEvent::KeyUp;
+ else
+ NOTREACHED() << "Invalid Android key event action: " << action;
return NativeWebKeyboardEvent(java_key_event, type, modifiers,
time_ms / 1000.0, key_code, unicode_char, is_system_key);
}
@@ -65,39 +66,7 @@ NativeWebKeyboardEvent NativeWebKeyboardEventFromKeyEvent(
} // anonymous namespace
bool RegisterImeAdapter(JNIEnv* env) {
- if (!RegisterNativesImpl(env))
- return false;
-
- Java_ImeAdapter_initializeWebInputEvents(env,
- blink::WebInputEvent::RawKeyDown,
- blink::WebInputEvent::KeyUp,
- blink::WebInputEvent::Char,
- blink::WebInputEvent::ShiftKey,
- blink::WebInputEvent::AltKey,
- blink::WebInputEvent::ControlKey,
- blink::WebInputEvent::CapsLockOn,
- blink::WebInputEvent::NumLockOn);
- Java_ImeAdapter_initializeTextInputTypes(
- env,
- ui::TEXT_INPUT_TYPE_NONE,
- ui::TEXT_INPUT_TYPE_TEXT,
- ui::TEXT_INPUT_TYPE_TEXT_AREA,
- ui::TEXT_INPUT_TYPE_PASSWORD,
- ui::TEXT_INPUT_TYPE_SEARCH,
- ui::TEXT_INPUT_TYPE_URL,
- ui::TEXT_INPUT_TYPE_EMAIL,
- 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;
+ return RegisterNativesImpl(env);
}
// Callback from Java to convert BackgroundColorSpan data to a
@@ -108,8 +77,8 @@ void AppendBackgroundColorSpan(JNIEnv*,
jint start,
jint end,
jint background_color) {
- DCHECK(start >= 0);
- DCHECK(end >= 0);
+ DCHECK_GE(start, 0);
+ DCHECK_GE(end, 0);
// Do not check |background_color|.
std::vector<blink::WebCompositionUnderline>* underlines =
reinterpret_cast<std::vector<blink::WebCompositionUnderline>*>(
@@ -129,8 +98,8 @@ void AppendUnderlineSpan(JNIEnv*,
jlong underlines_ptr,
jint start,
jint end) {
- DCHECK(start >= 0);
- DCHECK(end >= 0);
+ DCHECK_GE(start, 0);
+ DCHECK_GE(end, 0);
std::vector<blink::WebCompositionUnderline>* underlines =
reinterpret_cast<std::vector<blink::WebCompositionUnderline>*>(
underlines_ptr);
@@ -268,36 +237,6 @@ 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();
diff --git a/chromium/content/browser/renderer_host/ime_adapter_android.h b/chromium/content/browser/renderer_host/ime_adapter_android.h
index 50e9dbfa89d..1621811f02c 100644
--- a/chromium/content/browser/renderer_host/ime_adapter_android.h
+++ b/chromium/content/browser/renderer_host/ime_adapter_android.h
@@ -7,10 +7,7 @@
#include <jni.h>
-#include <vector>
-
#include "base/android/jni_weak_ref.h"
-#include "ui/gfx/geometry/rect.h"
namespace content {
@@ -67,7 +64,6 @@ 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/OWNERS b/chromium/content/browser/renderer_host/input/OWNERS
index 4893edbdf02..f2dd9a38a25 100644
--- a/chromium/content/browser/renderer_host/input/OWNERS
+++ b/chromium/content/browser/renderer_host/input/OWNERS
@@ -1,3 +1,3 @@
aelias@chromium.org
jdduke@chromium.org
-nduca@chromium.org
+tdresser@chromium.org
diff --git a/chromium/content/browser/renderer_host/input/gesture_event_queue.cc b/chromium/content/browser/renderer_host/input/gesture_event_queue.cc
index b16923be17f..a13fde15a42 100644
--- a/chromium/content/browser/renderer_host/input/gesture_event_queue.cc
+++ b/chromium/content/browser/renderer_host/input/gesture_event_queue.cc
@@ -4,17 +4,55 @@
#include "content/browser/renderer_host/input/gesture_event_queue.h"
-#include "base/debug/trace_event.h"
-#include "base/strings/string_number_conversions.h"
-#include "content/browser/renderer_host/input/input_router.h"
+#include "base/trace_event/trace_event.h"
#include "content/browser/renderer_host/input/touchpad_tap_suppression_controller.h"
#include "content/browser/renderer_host/input/touchscreen_tap_suppression_controller.h"
-#include "content/public/common/content_switches.h"
using blink::WebGestureEvent;
using blink::WebInputEvent;
namespace content {
+namespace {
+
+// Whether |event_in_queue| is GesturePinchUpdate or GestureScrollUpdate and
+// has the same modifiers/source as the new scroll/pinch event. Compatible
+// scroll and pinch event pairs can be logically coalesced.
+bool IsCompatibleScrollorPinch(
+ const GestureEventWithLatencyInfo& new_event,
+ const GestureEventWithLatencyInfo& event_in_queue) {
+ DCHECK(new_event.event.type == WebInputEvent::GestureScrollUpdate ||
+ new_event.event.type == WebInputEvent::GesturePinchUpdate)
+ << "Invalid event type for pinch/scroll coalescing: "
+ << WebInputEventTraits::GetName(new_event.event.type);
+ DLOG_IF(WARNING, new_event.event.timeStampSeconds <
+ event_in_queue.event.timeStampSeconds)
+ << "Event time not monotonic?\n";
+ return (event_in_queue.event.type == WebInputEvent::GestureScrollUpdate ||
+ event_in_queue.event.type == WebInputEvent::GesturePinchUpdate) &&
+ event_in_queue.event.modifiers == new_event.event.modifiers &&
+ event_in_queue.event.sourceDevice == new_event.event.sourceDevice;
+}
+
+// Returns the transform matrix corresponding to the gesture event.
+gfx::Transform GetTransformForEvent(
+ const GestureEventWithLatencyInfo& gesture_event) {
+ gfx::Transform gesture_transform;
+ if (gesture_event.event.type == WebInputEvent::GestureScrollUpdate) {
+ gesture_transform.Translate(gesture_event.event.data.scrollUpdate.deltaX,
+ gesture_event.event.data.scrollUpdate.deltaY);
+ } else if (gesture_event.event.type == WebInputEvent::GesturePinchUpdate) {
+ float scale = gesture_event.event.data.pinchUpdate.scale;
+ gesture_transform.Translate(-gesture_event.event.x, -gesture_event.event.y);
+ gesture_transform.Scale(scale, scale);
+ gesture_transform.Translate(gesture_event.event.x, gesture_event.event.y);
+ } else {
+ NOTREACHED() << "Invalid event type for transform retrieval: "
+ << WebInputEventTraits::GetName(gesture_event.event.type);
+ }
+ return gesture_transform;
+}
+
+} // namespace
GestureEventQueue::Config::Config() {
}
@@ -40,6 +78,18 @@ GestureEventQueue::GestureEventQueue(
GestureEventQueue::~GestureEventQueue() { }
+void GestureEventQueue::QueueEvent(
+ const GestureEventWithLatencyInfo& gesture_event) {
+ TRACE_EVENT0("input", "GestureEventQueue::QueueEvent");
+ if (!ShouldForwardForBounceReduction(gesture_event) ||
+ !ShouldForwardForGFCFiltering(gesture_event) ||
+ !ShouldForwardForTapSuppression(gesture_event)) {
+ return;
+ }
+
+ QueueAndForwardIfNecessary(gesture_event);
+}
+
bool GestureEventQueue::ShouldDiscardFlingCancelEvent(
const GestureEventWithLatencyInfo& gesture_event) const {
if (coalesced_gesture_events_.empty() && fling_in_progress_)
@@ -89,16 +139,6 @@ bool GestureEventQueue::ShouldForwardForBounceReduction(
}
}
-// NOTE: The filters are applied successively. This simplifies the change.
-bool GestureEventQueue::ShouldForward(
- const GestureEventWithLatencyInfo& gesture_event) {
- TRACE_EVENT0("input", "GestureEventQueue::ShouldForward");
- return ShouldForwardForBounceReduction(gesture_event) &&
- ShouldForwardForGFCFiltering(gesture_event) &&
- ShouldForwardForTapSuppression(gesture_event) &&
- ShouldForwardForCoalescing(gesture_event);
-}
-
bool GestureEventQueue::ShouldForwardForGFCFiltering(
const GestureEventWithLatencyInfo& gesture_event) const {
return gesture_event.event.type != WebInputEvent::GestureFlingCancel ||
@@ -132,7 +172,7 @@ bool GestureEventQueue::ShouldForwardForTapSuppression(
}
}
-bool GestureEventQueue::ShouldForwardForCoalescing(
+void GestureEventQueue::QueueAndForwardIfNecessary(
const GestureEventWithLatencyInfo& gesture_event) {
switch (gesture_event.event.type) {
case WebInputEvent::GestureFlingCancel:
@@ -143,18 +183,20 @@ bool GestureEventQueue::ShouldForwardForCoalescing(
break;
case WebInputEvent::GesturePinchUpdate:
case WebInputEvent::GestureScrollUpdate:
- MergeOrInsertScrollAndPinchEvent(gesture_event);
- return ShouldHandleEventNow();
+ QueueScrollOrPinchAndForwardIfNecessary(gesture_event);
+ return;
default:
break;
}
+
coalesced_gesture_events_.push_back(gesture_event);
- return ShouldHandleEventNow();
+ if (coalesced_gesture_events_.size() == 1)
+ client_->SendGestureEventImmediately(gesture_event);
}
void GestureEventQueue::ProcessGestureAck(InputEventAckState ack_result,
- WebInputEvent::Type type,
- const ui::LatencyInfo& latency) {
+ WebInputEvent::Type type,
+ const ui::LatencyInfo& latency) {
TRACE_EVENT0("input", "GestureEventQueue::ProcessGestureAck");
if (coalesced_gesture_events_.empty()) {
@@ -227,22 +269,13 @@ TouchpadTapSuppressionController*
return &touchpad_tap_suppression_controller_;
}
-bool GestureEventQueue::ExpectingGestureAck() const {
- return !coalesced_gesture_events_.empty();
-}
-
void GestureEventQueue::FlingHasBeenHalted() {
fling_in_progress_ = false;
}
-bool GestureEventQueue::ShouldHandleEventNow() const {
- return coalesced_gesture_events_.size() == 1;
-}
-
void GestureEventQueue::ForwardGestureEvent(
const GestureEventWithLatencyInfo& gesture_event) {
- if (ShouldForwardForCoalescing(gesture_event))
- client_->SendGestureEventImmediately(gesture_event);
+ QueueAndForwardIfNecessary(gesture_event);
}
void GestureEventQueue::SendScrollEndingEventsNow() {
@@ -254,19 +287,34 @@ void GestureEventQueue::SendScrollEndingEventsNow() {
for (GestureQueue::const_iterator it = debouncing_deferral_queue.begin();
it != debouncing_deferral_queue.end(); it++) {
if (ShouldForwardForGFCFiltering(*it) &&
- ShouldForwardForTapSuppression(*it) &&
- ShouldForwardForCoalescing(*it)) {
- client_->SendGestureEventImmediately(*it);
+ ShouldForwardForTapSuppression(*it)) {
+ QueueAndForwardIfNecessary(*it);
}
}
}
-void GestureEventQueue::MergeOrInsertScrollAndPinchEvent(
+void GestureEventQueue::QueueScrollOrPinchAndForwardIfNecessary(
const GestureEventWithLatencyInfo& gesture_event) {
+ DCHECK_GE(coalesced_gesture_events_.size(), EventsInFlightCount());
const size_t unsent_events_count =
coalesced_gesture_events_.size() - EventsInFlightCount();
if (!unsent_events_count) {
coalesced_gesture_events_.push_back(gesture_event);
+ if (coalesced_gesture_events_.size() == 1) {
+ client_->SendGestureEventImmediately(gesture_event);
+ } else if (coalesced_gesture_events_.size() == 2) {
+ DCHECK(!ignore_next_ack_);
+ // If there is an in-flight scroll, the new pinch can be forwarded
+ // immediately, avoiding a potential frame delay between the two
+ // (similarly for an in-flight pinch with a new scroll).
+ const GestureEventWithLatencyInfo& first_event =
+ coalesced_gesture_events_.front();
+ if (gesture_event.event.type != first_event.event.type &&
+ IsCompatibleScrollorPinch(gesture_event, first_event)) {
+ ignore_next_ack_ = true;
+ client_->SendGestureEventImmediately(gesture_event);
+ }
+ }
return;
}
@@ -276,7 +324,7 @@ void GestureEventQueue::MergeOrInsertScrollAndPinchEvent(
return;
}
- if (!ShouldTryMerging(gesture_event, *last_event)) {
+ if (!IsCompatibleScrollorPinch(gesture_event, *last_event)) {
coalesced_gesture_events_.push_back(gesture_event);
return;
}
@@ -305,7 +353,7 @@ void GestureEventQueue::MergeOrInsertScrollAndPinchEvent(
if (unsent_events_count > 1) {
const GestureEventWithLatencyInfo& second_last_event =
coalesced_gesture_events_[coalesced_gesture_events_.size() - 2];
- if (ShouldTryMerging(gesture_event, second_last_event)) {
+ if (IsCompatibleScrollorPinch(gesture_event, second_last_event)) {
// Keep the oldest LatencyInfo.
DCHECK_LE(second_last_event.latency.trace_id,
scroll_event.latency.trace_id);
@@ -336,34 +384,6 @@ void GestureEventQueue::MergeOrInsertScrollAndPinchEvent(
coalesced_gesture_events_.push_back(pinch_event);
}
-bool GestureEventQueue::ShouldTryMerging(
- const GestureEventWithLatencyInfo& new_event,
- const GestureEventWithLatencyInfo& event_in_queue) const {
- DLOG_IF(WARNING,
- new_event.event.timeStampSeconds <
- event_in_queue.event.timeStampSeconds)
- << "Event time not monotonic?\n";
- return (event_in_queue.event.type == WebInputEvent::GestureScrollUpdate ||
- event_in_queue.event.type == WebInputEvent::GesturePinchUpdate) &&
- event_in_queue.event.modifiers == new_event.event.modifiers &&
- event_in_queue.event.sourceDevice == new_event.event.sourceDevice;
-}
-
-gfx::Transform GestureEventQueue::GetTransformForEvent(
- const GestureEventWithLatencyInfo& gesture_event) const {
- gfx::Transform gesture_transform;
- if (gesture_event.event.type == WebInputEvent::GestureScrollUpdate) {
- gesture_transform.Translate(gesture_event.event.data.scrollUpdate.deltaX,
- gesture_event.event.data.scrollUpdate.deltaY);
- } else if (gesture_event.event.type == WebInputEvent::GesturePinchUpdate) {
- float scale = gesture_event.event.data.pinchUpdate.scale;
- gesture_transform.Translate(-gesture_event.event.x, -gesture_event.event.y);
- gesture_transform.Scale(scale,scale);
- gesture_transform.Translate(gesture_event.event.x, gesture_event.event.y);
- }
- return gesture_transform;
-}
-
size_t GestureEventQueue::EventsInFlightCount() const {
if (coalesced_gesture_events_.empty())
return 0;
diff --git a/chromium/content/browser/renderer_host/input/gesture_event_queue.h b/chromium/content/browser/renderer_host/input/gesture_event_queue.h
index 8bc433bfb85..208b2de457c 100644
--- a/chromium/content/browser/renderer_host/input/gesture_event_queue.h
+++ b/chromium/content/browser/renderer_host/input/gesture_event_queue.h
@@ -81,11 +81,10 @@ class CONTENT_EXPORT GestureEventQueue {
const Config& config);
~GestureEventQueue();
- // Returns |true| if the caller should immediately forward the provided
- // |GestureEventWithLatencyInfo| argument to the renderer.
- // If this function returns false, then the event may be queued and forwared
- // at a later point.
- bool ShouldForward(const GestureEventWithLatencyInfo&);
+ // Adds a gesture to the queue if it passes the relevant filters. If
+ // there are no events currently queued, the event will be forwarded
+ // immediately.
+ void QueueEvent(const GestureEventWithLatencyInfo&);
// Indicates that the caller has received an acknowledgement from the renderer
// with state |ack_result| and event |type|. May send events if the queue is
@@ -103,9 +102,6 @@ class CONTENT_EXPORT GestureEventQueue {
void ForwardGestureEvent(const GestureEventWithLatencyInfo& gesture_event);
- // Whether the queue is expecting a gesture event ack.
- bool ExpectingGestureAck() const;
-
bool empty() const {
return coalesced_gesture_events_.empty() &&
debouncing_deferral_queue_.empty();
@@ -132,15 +128,6 @@ class CONTENT_EXPORT GestureEventQueue {
bool ShouldDiscardFlingCancelEvent(
const GestureEventWithLatencyInfo& gesture_event) const;
- // Returns |true| if the only event in the queue is the current event and
- // hence that event should be handled now.
- bool ShouldHandleEventNow() const;
-
- // Merge or append a GestureScrollUpdate or GesturePinchUpdate into
- // the coalescing queue.
- void MergeOrInsertScrollAndPinchEvent(
- const GestureEventWithLatencyInfo& gesture_event);
-
// Sub-filter for removing bounces from in-progress scrolls.
bool ShouldForwardForBounceReduction(
const GestureEventWithLatencyInfo& gesture_event);
@@ -156,21 +143,13 @@ class CONTENT_EXPORT GestureEventQueue {
// Puts the events in a queue to forward them one by one; i.e., forward them
// whenever ACK for previous event is received. This queue also tries to
// coalesce events as much as possible.
- bool ShouldForwardForCoalescing(
+ void QueueAndForwardIfNecessary(
const GestureEventWithLatencyInfo& gesture_event);
- // Whether the event_in_queue is GesturePinchUpdate or
- // GestureScrollUpdate and it has the same modifiers as the
- // new event.
- bool ShouldTryMerging(
- const GestureEventWithLatencyInfo& new_event,
- const GestureEventWithLatencyInfo& event_in_queue)const;
-
- // Returns the transform matrix corresponding to the gesture event.
- // Assumes the gesture event sent is either GestureScrollUpdate or
- // GesturePinchUpdate. Returns the identity matrix otherwise.
- gfx::Transform GetTransformForEvent(
- const GestureEventWithLatencyInfo& gesture_event) const;
+ // Merge or append a GestureScrollUpdate or GesturePinchUpdate into
+ // the coalescing queue, forwarding immediately if appropriate.
+ void QueueScrollOrPinchAndForwardIfNecessary(
+ const GestureEventWithLatencyInfo& gesture_event);
// The number of sent events for which we're awaiting an ack. These events
// remain at the head of the queue until ack'ed.
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 c4b6d9600ab..3e57cd03531 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
@@ -77,15 +77,8 @@ class GestureEventQueueTest : public testing::Test,
queue()->set_debounce_interval_time_ms_for_testing(interval_ms);
}
- // Returns the result of |GestureEventQueue::ShouldForward()|.
- bool SimulateGestureEvent(const WebGestureEvent& gesture) {
- GestureEventWithLatencyInfo gesture_with_latency(gesture,
- ui::LatencyInfo());
- if (queue()->ShouldForward(gesture_with_latency)) {
- SendGestureEventImmediately(gesture_with_latency);
- return true;
- }
- return false;
+ void SimulateGestureEvent(const WebGestureEvent& gesture) {
+ queue()->QueueEvent(GestureEventWithLatencyInfo(gesture));
}
void SimulateGestureEvent(WebInputEvent::Type type,
@@ -95,8 +88,8 @@ class GestureEventQueueTest : public testing::Test,
}
void SimulateGestureScrollUpdateEvent(float dX, float dY, int modifiers) {
- SimulateGestureEvent(
- SyntheticWebGestureEventBuilder::BuildScrollUpdate(dX, dY, modifiers));
+ SimulateGestureEvent(SyntheticWebGestureEventBuilder::BuildScrollUpdate(
+ dX, dY, modifiers, blink::WebGestureDeviceTouchscreen));
}
void SimulateGesturePinchUpdateEvent(float scale,
@@ -180,9 +173,7 @@ class GestureEventQueueTest : public testing::Test,
return queue()->scrolling_in_progress_;
}
- bool FlingInProgress() {
- return queue()->fling_in_progress_;
- }
+ bool FlingInProgress() { return queue()->fling_in_progress_; }
bool WillIgnoreNextACK() {
return queue()->ignore_next_ack_;
@@ -670,9 +661,8 @@ TEST_F(GestureEventQueueTest, CoalescesPinchSequencesWithEarlyAck) {
GestureEventLastQueueEvent().type);
EXPECT_EQ(1U, GestureEventQueueSize());
-
SimulateGesturePinchUpdateEvent(2, 60, 60, 1);
- EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
+ EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
EXPECT_EQ(WebInputEvent::GesturePinchUpdate,
GestureEventLastQueueEvent().type);
EXPECT_EQ(2U, GestureEventQueueSize());
@@ -681,7 +671,7 @@ TEST_F(GestureEventQueueTest, CoalescesPinchSequencesWithEarlyAck) {
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
EXPECT_EQ(WebInputEvent::GesturePinchUpdate,
GestureEventLastQueueEvent().type);
- EXPECT_EQ(2U, GestureEventQueueSize());
+ EXPECT_EQ(3U, GestureEventQueueSize());
SimulateGestureScrollUpdateEvent(5, 5, 1);
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
@@ -689,16 +679,22 @@ TEST_F(GestureEventQueueTest, CoalescesPinchSequencesWithEarlyAck) {
// pinch following the scroll.
EXPECT_EQ(WebInputEvent::GesturePinchUpdate,
GestureEventLastQueueEvent().type);
- EXPECT_EQ(3U, GestureEventQueueSize());
+ EXPECT_EQ(4U, GestureEventQueueSize());
SimulateGesturePinchUpdateEvent(4, 60, 60, 1);
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
- EXPECT_EQ(3U, GestureEventQueueSize());
+ EXPECT_EQ(4U, GestureEventQueueSize());
SendInputEventACK(WebInputEvent::GestureScrollUpdate,
INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
+ EXPECT_EQ(3U, GestureEventQueueSize());
+
+ SendInputEventACK(WebInputEvent::GesturePinchUpdate,
+ INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(2U, GetAndResetSentGestureEventCount());
EXPECT_EQ(2U, GestureEventQueueSize());
+ EXPECT_EQ(2.f, last_acked_event().data.pinchUpdate.scale);
SendInputEventACK(WebInputEvent::GestureScrollUpdate,
INPUT_EVENT_ACK_STATE_CONSUMED);
@@ -707,7 +703,7 @@ TEST_F(GestureEventQueueTest, CoalescesPinchSequencesWithEarlyAck) {
SendInputEventACK(WebInputEvent::GesturePinchUpdate,
INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(WebInputEvent::GesturePinchUpdate, last_acked_event().type);
- EXPECT_EQ(2.f * 3.f * 4.f, last_acked_event().data.pinchUpdate.scale);
+ EXPECT_EQ(3.f * 4.f, last_acked_event().data.pinchUpdate.scale);
EXPECT_EQ(0U, GestureEventQueueSize());
}
diff --git a/chromium/content/browser/renderer_host/input/gesture_text_selector.cc b/chromium/content/browser/renderer_host/input/gesture_text_selector.cc
deleted file mode 100644
index 67c4fe7ebb0..00000000000
--- a/chromium/content/browser/renderer_host/input/gesture_text_selector.cc
+++ /dev/null
@@ -1,115 +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/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
deleted file mode 100644
index e494045b731..00000000000
--- a/chromium/content/browser/renderer_host/input/gesture_text_selector.h
+++ /dev/null
@@ -1,72 +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_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
deleted file mode 100644
index dfa2af1ee54..00000000000
--- a/chromium/content/browser/renderer_host/input/gesture_text_selector_unittest.cc
+++ /dev/null
@@ -1,223 +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 <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_ack_handler.h b/chromium/content/browser/renderer_host/input/input_ack_handler.h
index 0e34b824c84..d050dcdf7c9 100644
--- a/chromium/content/browser/renderer_host/input/input_ack_handler.h
+++ b/chromium/content/browser/renderer_host/input/input_ack_handler.h
@@ -38,4 +38,4 @@ class CONTENT_EXPORT InputAckHandler {
} // namespace content
-#endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_INPUT_ACK_HANDLER_H_
+#endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_INPUT_ACK_HANDLER_H_
diff --git a/chromium/content/browser/renderer_host/input/input_router.h b/chromium/content/browser/renderer_host/input/input_router.h
index 96b68c322fe..3f33ae8faf8 100644
--- a/chromium/content/browser/renderer_host/input/input_router.h
+++ b/chromium/content/browser/renderer_host/input/input_router.h
@@ -24,10 +24,6 @@ class InputRouter : public IPC::Listener {
public:
~InputRouter() override {}
- // Should be called only in response to |SetNeedsFlush| requests made via
- // the |InputRouterClient|.
- virtual void Flush() = 0;
-
// Send and take ownership of the the given InputMsg_*. This should be used
// only for event types not associated with a WebInputEvent. Returns true on
// success and false otherwise.
@@ -50,11 +46,6 @@ class InputRouter : public IPC::Listener {
// Returns the oldest queued or in-flight keyboard event sent to the router.
virtual const NativeWebKeyboardEvent* GetLastKeyboardEvent() const = 0;
- // Returns |true| if the caller should immediately forward touch events to the
- // router. When |false|, the caller can forego sending touch events, and
- // instead consume them directly.
- virtual bool ShouldForwardTouchEvent() const = 0;
-
// Allow the router to make more informed input handling decisions based on
// the current view.
enum ViewFlags {
@@ -64,9 +55,15 @@ class InputRouter : public IPC::Listener {
};
virtual void OnViewUpdated(int view_flags) = 0;
+ // Request a notification from the input router when all events have been
+ // fully dispatched and there are no longer any pending events.
+ // Note: This may trigger a synchronous notification if the router is empty.
+ virtual void RequestNotificationWhenFlushed() = 0;
+
+ // Whether there are any events pending dispatch to or ack from the renderer.
virtual bool HasPendingEvents() const = 0;
};
} // namespace content
-#endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_INPUT_ROUTER_H_
+#endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_INPUT_ROUTER_H_
diff --git a/chromium/content/browser/renderer_host/input/input_router_client.h b/chromium/content/browser/renderer_host/input/input_router_client.h
index 3b0e6a9c351..dd3c6a0a382 100644
--- a/chromium/content/browser/renderer_host/input/input_router_client.h
+++ b/chromium/content/browser/renderer_host/input/input_router_client.h
@@ -42,11 +42,6 @@ class CONTENT_EXPORT InputRouterClient {
// Called when the renderer notifies that it has touch event handlers.
virtual void OnHasTouchEventHandlers(bool has_handlers) = 0;
- // Certain router implementations require periodic flushing of queued events.
- // When this method is called, the client should ensure a timely call, either
- // synchronous or asynchronous, of |Flush| on the InputRouter.
- virtual void SetNeedsFlush() = 0;
-
// Called when the router has finished flushing all events queued at the time
// of the call to Flush. The call will typically be asynchronous with
// respect to the call to |Flush| on the InputRouter.
@@ -55,8 +50,11 @@ class CONTENT_EXPORT InputRouterClient {
// Called when the router has received an overscroll notification from the
// renderer.
virtual void DidOverscroll(const DidOverscrollParams& params) = 0;
+
+ // Called when a renderer fling has terminated.
+ virtual void DidStopFlinging() = 0;
};
} // namespace content
-#endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_INPUT_ROUTER_CLIENT_H_
+#endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_INPUT_ROUTER_CLIENT_H_
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 d78b6cb2a90..3ed530f9eca 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
@@ -50,13 +50,7 @@ GestureEventQueue::Config GetGestureEventQueueConfig() {
}
TouchEventQueue::Config GetTouchEventQueueConfig() {
- TouchEventQueue::Config config;
-
- config.touchmove_slop_suppression_length_dips =
- ui::GestureConfiguration::GetInstance()
- ->max_touch_move_in_pixels_for_click();
-
- return config;
+ return TouchEventQueue::Config();
}
#elif defined(OS_ANDROID)
@@ -86,13 +80,6 @@ TouchEventQueue::Config GetTouchEventQueueConfig() {
base::TimeDelta::FromMilliseconds(kTouchAckTimeoutDelayMs);
config.touch_ack_timeout_supported = true;
- const double touch_slop_length_pixels =
- static_cast<double>(gfx::ViewConfiguration::GetTouchSlopInPixels());
- const double device_scale_factor =
- gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().device_scale_factor();
- config.touchmove_slop_suppression_length_dips =
- touch_slop_length_pixels / device_scale_factor;
-
return config;
}
@@ -103,36 +90,17 @@ GestureEventQueue::Config GetGestureEventQueueConfig() {
}
TouchEventQueue::Config GetTouchEventQueueConfig() {
- TouchEventQueue::Config config;
- config.touchmove_slop_suppression_length_dips =
- ui::GestureDetector::Config().touch_slop;
- return config;
+ return TouchEventQueue::Config();
}
#endif
-TouchEventQueue::TouchScrollingMode GetTouchScrollingMode() {
- std::string modeString =
- base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kTouchScrollingMode);
- if (modeString == switches::kTouchScrollingModeAsyncTouchmove)
- return TouchEventQueue::TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE;
- if (modeString == switches::kTouchScrollingModeSyncTouchmove)
- return TouchEventQueue::TOUCH_SCROLLING_MODE_SYNC_TOUCHMOVE;
- if (modeString == switches::kTouchScrollingModeTouchcancel)
- return TouchEventQueue::TOUCH_SCROLLING_MODE_TOUCHCANCEL;
- if (modeString != "")
- LOG(ERROR) << "Invalid --touch-scrolling-mode option: " << modeString;
- return TouchEventQueue::TOUCH_SCROLLING_MODE_DEFAULT;
-}
-
} // namespace
InputRouterImpl::Config GetInputRouterConfigForPlatform() {
InputRouterImpl::Config config;
config.gesture_config = GetGestureEventQueueConfig();
config.touch_config = GetTouchEventQueueConfig();
- config.touch_config.touch_scrolling_mode = GetTouchScrollingMode();
return config;
}
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 4848f6dc6f4..c812b41da21 100644
--- a/chromium/content/browser/renderer_host/input/input_router_impl.cc
+++ b/chromium/content/browser/renderer_host/input/input_router_impl.cc
@@ -38,6 +38,7 @@ using blink::WebInputEvent;
using blink::WebKeyboardEvent;
using blink::WebMouseEvent;
using blink::WebMouseWheelEvent;
+using blink::WebTouchEvent;
namespace content {
namespace {
@@ -75,6 +76,7 @@ InputRouterImpl::InputRouterImpl(IPC::Sender* sender,
current_view_flags_(0),
current_ack_source_(ACK_SOURCE_NONE),
flush_requested_(false),
+ active_renderer_fling_count_(0),
touch_event_queue_(this, config.touch_config),
gesture_event_queue_(this, this, config.gesture_config) {
DCHECK(sender);
@@ -87,11 +89,6 @@ InputRouterImpl::~InputRouterImpl() {
STLDeleteElements(&pending_select_messages_);
}
-void InputRouterImpl::Flush() {
- flush_requested_ = true;
- SignalFlushedIfNecessary();
-}
-
bool InputRouterImpl::SendInput(scoped_ptr<IPC::Message> message) {
DCHECK(IPC_MESSAGE_ID_CLASS(message->type()) == InputMsgStart);
switch (message->type()) {
@@ -125,27 +122,21 @@ void InputRouterImpl::SendMouseEvent(
void InputRouterImpl::SendWheelEvent(
const MouseWheelEventWithLatencyInfo& wheel_event) {
- SendWheelEvent(QueuedWheelEvent(wheel_event, false));
-}
-
-void InputRouterImpl::SendWheelEvent(const QueuedWheelEvent& wheel_event) {
if (mouse_wheel_pending_) {
// If there's already a mouse wheel event waiting to be sent to the
// renderer, add the new deltas to that event. Not doing so (e.g., by
// dropping the old event, as for mouse moves) results in very slow
- // scrolling on the Mac (on which many, very small wheel events are sent).
- // Note that we can't coalesce wheel events for pinches because the GEQ
- // expects one ACK for each (but it's fine to coalesce non-pinch wheels
- // into a pinch one). Note that the GestureEventQueue ensures we only
- // ever have a single pinch event queued here.
+ // scrolling on the Mac.
+ if (wheel_event.event.hasPreciseScrollingDeltas)
+ DCHECK(wheel_event.event.canScroll);
+ DCHECK(!(wheel_event.event.hasPreciseScrollingDeltas &&
+ !wheel_event.event.canScroll));
if (coalesced_mouse_wheel_events_.empty() ||
- wheel_event.synthesized_from_pinch ||
- !coalesced_mouse_wheel_events_.back().event.CanCoalesceWith(
- wheel_event.event)) {
+ (!coalesced_mouse_wheel_events_.empty() &&
+ !coalesced_mouse_wheel_events_.back().CanCoalesceWith(wheel_event))) {
coalesced_mouse_wheel_events_.push_back(wheel_event);
} else {
- coalesced_mouse_wheel_events_.back().event.CoalesceWith(
- wheel_event.event);
+ coalesced_mouse_wheel_events_.back().CoalesceWith(wheel_event);
}
return;
}
@@ -156,8 +147,7 @@ void InputRouterImpl::SendWheelEvent(const QueuedWheelEvent& wheel_event) {
LOCAL_HISTOGRAM_COUNTS_100("Renderer.WheelQueueSize",
coalesced_mouse_wheel_events_.size());
- FilterAndSendWebInputEvent(
- wheel_event.event.event, wheel_event.event.latency, false);
+ FilterAndSendWebInputEvent(wheel_event.event, wheel_event.latency, false);
}
void InputRouterImpl::SendKeyboardEvent(const NativeWebKeyboardEvent& key_event,
@@ -187,10 +177,7 @@ void InputRouterImpl::SendGestureEvent(
if (gesture_event.event.sourceDevice == blink::WebGestureDeviceTouchscreen)
touch_event_queue_.OnGestureScrollEvent(gesture_event);
- if (!gesture_event_queue_.ShouldForward(gesture_event))
- return;
-
- SendGestureEventImmediately(gesture_event);
+ gesture_event_queue_.QueueEvent(gesture_event);
}
void InputRouterImpl::SendTouchEvent(
@@ -237,12 +224,6 @@ void InputRouterImpl::SendTouchEventImmediately(
void InputRouterImpl::SendGestureEventImmediately(
const GestureEventWithLatencyInfo& gesture_event) {
- if (gesture_event.event.type == WebInputEvent::GesturePinchUpdate &&
- gesture_event.event.sourceDevice == blink::WebGestureDeviceTouchpad) {
- SendSyntheticWheelEventForPinch(gesture_event);
- return;
- }
-
FilterAndSendWebInputEvent(gesture_event.event, gesture_event.latency, false);
}
@@ -252,12 +233,6 @@ const NativeWebKeyboardEvent* InputRouterImpl::GetLastKeyboardEvent() const {
return &key_queue_.front();
}
-bool InputRouterImpl::ShouldForwardTouchEvent() const {
- // Always send a touch event if the renderer has a touch-event handler or
- // there are pending touch events.
- return touch_event_queue_.has_handlers() || !touch_event_queue_.empty();
-}
-
void InputRouterImpl::OnViewUpdated(int view_flags) {
current_view_flags_ = view_flags;
@@ -265,6 +240,22 @@ void InputRouterImpl::OnViewUpdated(int view_flags) {
UpdateTouchAckTimeoutEnabled();
}
+void InputRouterImpl::RequestNotificationWhenFlushed() {
+ flush_requested_ = true;
+ SignalFlushedIfNecessary();
+}
+
+bool InputRouterImpl::HasPendingEvents() const {
+ return !touch_event_queue_.empty() ||
+ !gesture_event_queue_.empty() ||
+ !key_queue_.empty() ||
+ mouse_move_pending_ ||
+ mouse_wheel_pending_ ||
+ select_message_pending_ ||
+ move_caret_pending_ ||
+ active_renderer_fling_count_ > 0;
+}
+
bool InputRouterImpl::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(InputRouterImpl, message)
@@ -278,6 +269,7 @@ bool InputRouterImpl::OnMessageReceived(const IPC::Message& message) {
OnHasTouchEventHandlers)
IPC_MESSAGE_HANDLER(InputHostMsg_SetTouchAction,
OnSetTouchAction)
+ IPC_MESSAGE_HANDLER(InputHostMsg_DidStopFlinging, OnDidStopFlinging)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
@@ -369,8 +361,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_NE(static_cast<int>(ignores_ack),
- static_cast<const blink::WebTouchEvent&>(input_event).cancelable);
+ const WebTouchEvent& touch = static_cast<const WebTouchEvent&>(input_event);
+ DCHECK_NE(ignores_ack, !!touch.cancelable);
}
// If we don't care about the ack disposition, send the ack immediately.
@@ -425,43 +417,6 @@ bool InputRouterImpl::OfferToRenderer(const WebInputEvent& input_event,
return false;
}
-void InputRouterImpl::SendSyntheticWheelEventForPinch(
- const GestureEventWithLatencyInfo& pinch_event) {
- // We match typical trackpad behavior on Windows by sending fake wheel events
- // with the ctrl modifier set when we see trackpad pinch gestures. Ideally
- // we'd someday get a standard 'pinch' event and send that instead.
-
- WebMouseWheelEvent wheelEvent;
- wheelEvent.type = WebInputEvent::MouseWheel;
- wheelEvent.timeStampSeconds = pinch_event.event.timeStampSeconds;
- wheelEvent.windowX = wheelEvent.x = pinch_event.event.x;
- wheelEvent.windowY = wheelEvent.y = pinch_event.event.y;
- wheelEvent.globalX = pinch_event.event.globalX;
- wheelEvent.globalY = pinch_event.event.globalY;
- wheelEvent.modifiers =
- pinch_event.event.modifiers | WebInputEvent::ControlKey;
- wheelEvent.deltaX = 0;
- // The function to convert scales to deltaY values is designed to be
- // compatible with websites existing use of wheel events, and with existing
- // Windows trackpad behavior. In particular, we want:
- // - deltas should accumulate via addition: f(s1*s2)==f(s1)+f(s2)
- // - deltas should invert via negation: f(1/s) == -f(s)
- // - zoom in should be positive: f(s) > 0 iff s > 1
- // - magnitude roughly matches wheels: f(2) > 25 && f(2) < 100
- // - a formula that's relatively easy to use from JavaScript
- // Note that 'wheel' event deltaY values have their sign inverted. So to
- // convert a wheel deltaY back to a scale use Math.exp(-deltaY/100).
- DCHECK_GT(pinch_event.event.data.pinchUpdate.scale, 0);
- wheelEvent.deltaY = 100.0f * log(pinch_event.event.data.pinchUpdate.scale);
- wheelEvent.hasPreciseScrollingDeltas = true;
- wheelEvent.wheelTicksX = 0;
- wheelEvent.wheelTicksY =
- pinch_event.event.data.pinchUpdate.scale > 1 ? 1 : -1;
-
- SendWheelEvent(QueuedWheelEvent(
- MouseWheelEventWithLatencyInfo(wheelEvent, pinch_event.latency), true));
-}
-
void InputRouterImpl::OnInputEventAck(
const InputHostMsg_HandleInputEvent_ACK_Params& ack) {
client_->DecrementInFlightEventCount();
@@ -543,6 +498,17 @@ void InputRouterImpl::OnSetTouchAction(TouchAction touch_action) {
UpdateTouchAckTimeoutEnabled();
}
+void InputRouterImpl::OnDidStopFlinging() {
+ DCHECK_GT(active_renderer_fling_count_, 0);
+ // Note that we're only guaranteed to get a fling end notification from the
+ // renderer, not from any other consumers. Consequently, the GestureEventQueue
+ // cannot use this bookkeeping for logic like tap suppression.
+ --active_renderer_fling_count_;
+ SignalFlushedIfNecessary();
+
+ client_->DidStopFlinging();
+}
+
void InputRouterImpl::ProcessInputEventAck(
WebInputEvent::Type event_type,
InputEventAckState ack_result,
@@ -620,19 +586,11 @@ void InputRouterImpl::ProcessWheelAck(InputEventAckState ack_result,
const ui::LatencyInfo& latency) {
// TODO(miletus): Add renderer side latency to each uncoalesced mouse
// wheel event and add terminal component to each of them.
- current_wheel_event_.event.latency.AddNewLatencyFrom(latency);
-
- if (current_wheel_event_.synthesized_from_pinch) {
- // Ack the GesturePinchUpdate event that generated this wheel event.
- ProcessInputEventAck(WebInputEvent::GesturePinchUpdate,
- ack_result,
- current_wheel_event_.event.latency,
- current_ack_source_);
- } else {
- // Process the unhandled wheel event here before calling SendWheelEvent()
- // since it will mutate current_wheel_event_.
- ack_handler_->OnWheelEventAck(current_wheel_event_.event, ack_result);
- }
+ current_wheel_event_.latency.AddNewLatencyFrom(latency);
+
+ // Process the unhandled wheel event here before calling SendWheelEvent()
+ // since it will mutate current_wheel_event_.
+ ack_handler_->OnWheelEventAck(current_wheel_event_, ack_result);
// Mark the wheel event complete only after the ACKs have been handled above.
// For example, ACKing the GesturePinchUpdate could cause another
@@ -642,7 +600,8 @@ void InputRouterImpl::ProcessWheelAck(InputEventAckState ack_result,
// Send the next (coalesced or synthetic) mouse wheel event.
if (!coalesced_mouse_wheel_events_.empty()) {
- QueuedWheelEvent next_wheel_event = coalesced_mouse_wheel_events_.front();
+ MouseWheelEventWithLatencyInfo next_wheel_event =
+ coalesced_mouse_wheel_events_.front();
coalesced_mouse_wheel_events_.pop_front();
SendWheelEvent(next_wheel_event);
}
@@ -651,8 +610,10 @@ void InputRouterImpl::ProcessWheelAck(InputEventAckState ack_result,
void InputRouterImpl::ProcessGestureAck(WebInputEvent::Type type,
InputEventAckState ack_result,
const ui::LatencyInfo& latency) {
- if (!gesture_event_queue_.ExpectingGestureAck())
- return;
+ if (type == blink::WebInputEvent::GestureFlingStart &&
+ ack_result == INPUT_EVENT_ACK_STATE_CONSUMED) {
+ ++active_renderer_fling_count_;
+ }
// |gesture_event_queue_| will forward to OnGestureEventAck when appropriate.
gesture_event_queue_.ProcessGestureAck(ack_result, type, latency);
@@ -694,27 +655,4 @@ void InputRouterImpl::SignalFlushedIfNecessary() {
client_->DidFlush();
}
-bool InputRouterImpl::HasPendingEvents() const {
- return !touch_event_queue_.empty() ||
- !gesture_event_queue_.empty() ||
- !key_queue_.empty() ||
- mouse_move_pending_ ||
- mouse_wheel_pending_ ||
- select_message_pending_ ||
- move_caret_pending_;
-}
-
-InputRouterImpl::QueuedWheelEvent::QueuedWheelEvent()
- : synthesized_from_pinch(false) {
-}
-
-InputRouterImpl::QueuedWheelEvent::QueuedWheelEvent(
- const MouseWheelEventWithLatencyInfo& event,
- bool synthesized_from_pinch)
- : event(event), synthesized_from_pinch(synthesized_from_pinch) {
-}
-
-InputRouterImpl::QueuedWheelEvent::~QueuedWheelEvent() {
-}
-
} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/input_router_impl.h b/chromium/content/browser/renderer_host/input/input_router_impl.h
index 2b00c12996f..73f95797561 100644
--- a/chromium/content/browser/renderer_host/input/input_router_impl.h
+++ b/chromium/content/browser/renderer_host/input/input_router_impl.h
@@ -56,7 +56,6 @@ class CONTENT_EXPORT InputRouterImpl
~InputRouterImpl() override;
// InputRouter
- void Flush() override;
bool SendInput(scoped_ptr<IPC::Message> message) override;
void SendMouseEvent(const MouseEventWithLatencyInfo& mouse_event) override;
void SendWheelEvent(
@@ -68,8 +67,8 @@ class CONTENT_EXPORT InputRouterImpl
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;
+ void RequestNotificationWhenFlushed() override;
bool HasPendingEvents() const override;
// IPC::Listener
@@ -124,26 +123,6 @@ private:
const ui::LatencyInfo& latency_info,
bool is_keyboard_shortcut);
- // A data structure that attaches some metadata to a WebMouseWheelEvent
- // and its latency info.
- struct QueuedWheelEvent {
- QueuedWheelEvent();
- QueuedWheelEvent(const MouseWheelEventWithLatencyInfo& event,
- bool synthesized_from_pinch);
- ~QueuedWheelEvent();
-
- MouseWheelEventWithLatencyInfo event;
- bool synthesized_from_pinch;
- };
-
- // Enqueue or send a mouse wheel event.
- void SendWheelEvent(const QueuedWheelEvent& wheel_event);
-
- // Given a Touchpad GesturePinchUpdate event, create and send a synthetic
- // wheel event for it.
- void SendSyntheticWheelEventForPinch(
- const GestureEventWithLatencyInfo& pinch_event);
-
// IPC message handlers
void OnInputEventAck(const InputHostMsg_HandleInputEvent_ACK_Params& ack);
void OnDidOverscroll(const DidOverscrollParams& params);
@@ -151,6 +130,7 @@ private:
void OnSelectMessageAck();
void OnHasTouchEventHandlers(bool has_handlers);
void OnSetTouchAction(TouchAction touch_action);
+ void OnDidStopFlinging();
// Indicates the source of an ack provided to |ProcessInputEventAck()|.
// The source is tracked by |current_ack_source_|, which aids in ack routing.
@@ -202,8 +182,6 @@ private:
// all events have been dispatched (i.e., |HasPendingEvents()| is false).
void SignalFlushedIfNecessary();
- bool IsInOverscrollGesture() const;
-
int routing_id() const { return routing_id_; }
@@ -237,7 +215,7 @@ private:
// (Similar to |mouse_move_pending_|.) True if a mouse wheel event was sent
// and we are waiting for a corresponding ack.
bool mouse_wheel_pending_;
- QueuedWheelEvent current_wheel_event_;
+ MouseWheelEventWithLatencyInfo current_wheel_event_;
// (Similar to |next_mouse_move_|.) The next mouse wheel events to send.
// Unlike mouse moves, mouse wheel events received while one is pending are
@@ -246,7 +224,7 @@ private:
// high rate; not waiting for the ack results in jankiness, and using the same
// mechanism as for mouse moves (just dropping old events when multiple ones
// would be queued) results in very slow scrolling.
- typedef std::deque<QueuedWheelEvent> WheelEventQueue;
+ typedef std::deque<MouseWheelEventWithLatencyInfo> WheelEventQueue;
WheelEventQueue coalesced_mouse_wheel_events_;
// A queue of keyboard events. We can't trust data from the renderer so we
@@ -269,6 +247,11 @@ private:
// to the client_ after all events have been dispatched/acked.
bool flush_requested_;
+ // Whether there are any active flings in the renderer. As the fling
+ // end notification is asynchronous, we use a count rather than a boolean
+ // to avoid races in bookkeeping when starting a new fling.
+ int active_renderer_fling_count_;
+
TouchEventQueue touch_event_queue_;
GestureEventQueue gesture_event_queue_;
TouchActionFilter touch_action_filter_;
@@ -280,4 +263,4 @@ private:
} // namespace content
-#endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_INPUT_ROUTER_IMPL_H_
+#endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_INPUT_ROUTER_IMPL_H_
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 ad832642acf..5888a8baacd 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
@@ -78,8 +78,8 @@ class NullInputRouterClient : public InputRouterClient {
void DecrementInFlightEventCount() override {}
void OnHasTouchEventHandlers(bool has_handlers) override {}
void DidFlush() override {}
- void SetNeedsFlush() override {}
void DidOverscroll(const DidOverscrollParams& params) override {}
+ void DidStopFlinging() override {}
};
class NullIPCSender : public IPC::Sender {
@@ -108,8 +108,8 @@ class NullIPCSender : public IPC::Sender {
// TODO(jdduke): Use synthetic gesture pipeline, crbug.com/344598.
typedef std::vector<WebGestureEvent> Gestures;
Gestures BuildScrollSequence(size_t steps,
- gfx::Vector2dF origin,
- gfx::Vector2dF distance) {
+ const gfx::Vector2dF& origin,
+ const gfx::Vector2dF& distance) {
Gestures gestures;
const gfx::Vector2dF delta = ScaleVector2d(distance, 1.f / steps);
@@ -135,8 +135,8 @@ Gestures BuildScrollSequence(size_t steps,
typedef std::vector<WebTouchEvent> Touches;
Touches BuildTouchSequence(size_t steps,
- gfx::Vector2dF origin,
- gfx::Vector2dF distance) {
+ const gfx::Vector2dF& origin,
+ const gfx::Vector2dF& distance) {
Touches touches;
const gfx::Vector2dF delta = ScaleVector2d(distance, 1.f / steps);
@@ -261,10 +261,8 @@ class InputRouterImplPerfTest : public testing::Test {
ui::LatencyInfo latency;
latency.AddLatencyNumber(
ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT, 1, 0);
- latency.AddLatencyNumber(
- ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_RWH_COMPONENT,
- 1,
- NextLatencyID());
+ latency.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, 1,
+ NextLatencyID());
return latency;
}
@@ -300,8 +298,8 @@ class InputRouterImplPerfTest : public testing::Test {
void SimulateTouchAndScrollEventSequence(const char* test_name,
size_t steps,
- gfx::Vector2dF origin,
- gfx::Vector2dF distance,
+ const gfx::Vector2dF& origin,
+ const gfx::Vector2dF& distance,
size_t iterations) {
OnHasTouchEventHandlers(true);
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 ed922c9d8ac..f3872b04036 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
@@ -49,7 +49,7 @@ const WebInputEvent* GetInputEventFromMessage(const IPC::Message& message) {
PickleIterator iter(message);
const char* data;
int data_length;
- if (!message.ReadData(&iter, &data, &data_length))
+ if (!iter.ReadData(&data, &data_length))
return NULL;
return reinterpret_cast<const WebInputEvent*>(data);
}
@@ -80,7 +80,7 @@ WebInputEvent& GetEventWithType(WebInputEvent::Type type) {
bool GetIsShortcutFromHandleInputEventMessage(const IPC::Message* msg) {
InputMsg_HandleInputEvent::Schema::Param param;
InputMsg_HandleInputEvent::Read(msg, &param);
- return param.c;
+ return get<2>(param);
}
template<typename MSG_T, typename ARG_T1>
@@ -88,7 +88,7 @@ void ExpectIPCMessageWithArg1(const IPC::Message* msg, const ARG_T1& arg1) {
ASSERT_EQ(MSG_T::ID, msg->type());
typename MSG_T::Schema::Param param;
ASSERT_TRUE(MSG_T::Read(msg, &param));
- EXPECT_EQ(arg1, param.a);
+ EXPECT_EQ(arg1, get<0>(param));
}
template<typename MSG_T, typename ARG_T1, typename ARG_T2>
@@ -98,8 +98,8 @@ void ExpectIPCMessageWithArg2(const IPC::Message* msg,
ASSERT_EQ(MSG_T::ID, msg->type());
typename MSG_T::Schema::Param param;
ASSERT_TRUE(MSG_T::Read(msg, &param));
- EXPECT_EQ(arg1, param.a);
- EXPECT_EQ(arg2, param.b);
+ EXPECT_EQ(arg1, get<0>(param));
+ EXPECT_EQ(arg2, get<1>(param));
}
#if defined(USE_AURA)
@@ -132,11 +132,6 @@ bool EventListIsSubset(const ScopedVector<ui::TouchEvent>& subset,
}
#endif // defined(USE_AURA)
-// Expected function used for converting pinch scales to deltaY values.
-float PinchScaleToWheelDelta(float scale) {
- return 100.0 * log(scale);
-}
-
} // namespace
class InputRouterImplTest : public testing::Test {
@@ -192,53 +187,60 @@ class InputRouterImplTest : public testing::Test {
void SimulateWheelEvent(float dX, float dY, int modifiers, bool precise) {
input_router_->SendWheelEvent(MouseWheelEventWithLatencyInfo(
- SyntheticWebMouseWheelEventBuilder::Build(dX, dY, modifiers, precise),
- ui::LatencyInfo()));
+ SyntheticWebMouseWheelEventBuilder::Build(dX, dY, modifiers, precise)));
}
void SimulateMouseEvent(WebInputEvent::Type type, int x, int y) {
input_router_->SendMouseEvent(MouseEventWithLatencyInfo(
- SyntheticWebMouseEventBuilder::Build(type, x, y, 0),
- ui::LatencyInfo()));
+ SyntheticWebMouseEventBuilder::Build(type, x, y, 0)));
}
void SimulateWheelEventWithPhase(WebMouseWheelEvent::Phase phase) {
input_router_->SendWheelEvent(MouseWheelEventWithLatencyInfo(
- SyntheticWebMouseWheelEventBuilder::Build(phase), ui::LatencyInfo()));
+ SyntheticWebMouseWheelEventBuilder::Build(phase)));
}
- void SimulateGestureEvent(const WebGestureEvent& gesture) {
- input_router_->SendGestureEvent(
- GestureEventWithLatencyInfo(gesture, ui::LatencyInfo()));
+ void SimulateGestureEvent(WebGestureEvent gesture) {
+ // Ensure non-zero touchscreen fling velocities, as the router will
+ // validate aganst such.
+ if (gesture.type == WebInputEvent::GestureFlingStart &&
+ gesture.sourceDevice == blink::WebGestureDeviceTouchscreen &&
+ !gesture.data.flingStart.velocityX &&
+ !gesture.data.flingStart.velocityY) {
+ gesture.data.flingStart.velocityX = 5.f;
+ }
+
+ input_router_->SendGestureEvent(GestureEventWithLatencyInfo(gesture));
}
void SimulateGestureEvent(WebInputEvent::Type type,
- WebGestureDevice sourceDevice) {
+ WebGestureDevice source_device) {
SimulateGestureEvent(
- SyntheticWebGestureEventBuilder::Build(type, sourceDevice));
+ SyntheticWebGestureEventBuilder::Build(type, source_device));
}
- void SimulateGestureScrollUpdateEvent(float dX, float dY, int modifiers) {
- SimulateGestureEvent(
- SyntheticWebGestureEventBuilder::BuildScrollUpdate(dX, dY, modifiers));
+ void SimulateGestureScrollUpdateEvent(float dX,
+ float dY,
+ int modifiers,
+ WebGestureDevice source_device) {
+ SimulateGestureEvent(SyntheticWebGestureEventBuilder::BuildScrollUpdate(
+ dX, dY, modifiers, source_device));
}
void SimulateGesturePinchUpdateEvent(float scale,
- float anchorX,
- float anchorY,
+ float anchor_x,
+ float anchor_y,
int modifiers,
- WebGestureDevice sourceDevice) {
+ WebGestureDevice source_device) {
SimulateGestureEvent(SyntheticWebGestureEventBuilder::BuildPinchUpdate(
- scale, anchorX, anchorY, modifiers, sourceDevice));
+ scale, anchor_x, anchor_y, modifiers, source_device));
}
- void SimulateGestureFlingStartEvent(float velocityX,
- float velocityY,
- WebGestureDevice sourceDevice) {
- SimulateGestureEvent(
- SyntheticWebGestureEventBuilder::BuildFling(velocityX,
- velocityY,
- sourceDevice));
+ void SimulateGestureFlingStartEvent(float velocity_x,
+ float velocity_y,
+ WebGestureDevice source_device) {
+ SimulateGestureEvent(SyntheticWebGestureEventBuilder::BuildFling(
+ velocity_x, velocity_y, source_device));
}
void SetTouchTimestamp(base::TimeDelta timestamp) {
@@ -246,8 +248,7 @@ class InputRouterImplTest : public testing::Test {
}
void SendTouchEvent() {
- input_router_->SendTouchEvent(
- TouchEventWithLatencyInfo(touch_event_, ui::LatencyInfo()));
+ input_router_->SendTouchEvent(TouchEventWithLatencyInfo(touch_event_));
touch_event_.ResetPoints();
}
@@ -287,8 +288,8 @@ class InputRouterImplTest : public testing::Test {
return input_router()->touch_event_queue_.IsAckTimeoutEnabled();
}
- void Flush() const {
- return input_router_->Flush();
+ void RequestNotificationWhenFlushed() const {
+ return input_router_->RequestNotificationWhenFlushed();
}
size_t GetAndResetDidFlushCount() {
@@ -817,8 +818,6 @@ TEST_F(InputRouterImplTest, TouchEventQueueFlush) {
EXPECT_EQ(0U, GetSentMessageCountAndResetSink());
EXPECT_TRUE(TouchEventQueueEmpty());
- EXPECT_TRUE(input_router_->ShouldForwardTouchEvent());
-
// Send a touch-press event.
PressTouchPoint(1, 1);
SendTouchEvent();
@@ -833,14 +832,12 @@ TEST_F(InputRouterImplTest, TouchEventQueueFlush) {
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());
}
#if defined(USE_AURA)
@@ -850,7 +847,6 @@ TEST_F(InputRouterImplTest, AckedTouchEventState) {
input_router_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, true));
EXPECT_EQ(0U, GetSentMessageCountAndResetSink());
EXPECT_TRUE(TouchEventQueueEmpty());
- EXPECT_TRUE(input_router_->ShouldForwardTouchEvent());
// Send a bunch of events, and make sure the ACKed events are correct.
ScopedVector<ui::TouchEvent> expected_events;
@@ -992,8 +988,7 @@ TEST_F(InputRouterImplTest, TouchTypesIgnoringAck) {
TEST_F(InputRouterImplTest, GestureTypesIgnoringAck) {
// We test every gesture type, ensuring that the stream of gestures is valid.
- const int kEventTypesLength = 29;
- WebInputEvent::Type eventTypes[kEventTypesLength] = {
+ const WebInputEvent::Type eventTypes[] = {
WebInputEvent::GestureTapDown,
WebInputEvent::GestureShowPress,
WebInputEvent::GestureTapCancel,
@@ -1018,12 +1013,11 @@ TEST_F(InputRouterImplTest, GestureTypesIgnoringAck) {
WebInputEvent::GestureTapCancel,
WebInputEvent::GestureScrollBegin,
WebInputEvent::GestureScrollUpdate,
- WebInputEvent::GestureScrollUpdateWithoutPropagation,
WebInputEvent::GesturePinchBegin,
WebInputEvent::GesturePinchUpdate,
WebInputEvent::GesturePinchEnd,
WebInputEvent::GestureScrollEnd};
- for (int i = 0; i < kEventTypesLength; ++i) {
+ for (size_t i = 0; i < arraysize(eventTypes); ++i) {
WebInputEvent::Type type = eventTypes[i];
if (!WebInputEventTraits::IgnoresAckDisposition(GetEventWithType(type))) {
SimulateGestureEvent(type, blink::WebGestureDeviceTouchscreen);
@@ -1303,7 +1297,7 @@ TEST_F(InputRouterImplTest,
EXPECT_EQ(1U, ack_handler_->GetAndResetAckCount());
EXPECT_FALSE(TouchEventTimeoutEnabled());
- MoveTouchPoint(0, 1, 1);
+ MoveTouchPoint(0, 1, 2);
SendTouchEvent();
EXPECT_FALSE(TouchEventTimeoutEnabled());
EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
@@ -1551,7 +1545,7 @@ TEST_F(InputRouterImplTest, InputFlush) {
EXPECT_FALSE(HasPendingEvents());
// Flushing an empty router should immediately trigger DidFlush.
- Flush();
+ RequestNotificationWhenFlushed();
EXPECT_EQ(1U, GetAndResetDidFlushCount());
EXPECT_FALSE(HasPendingEvents());
@@ -1562,7 +1556,7 @@ TEST_F(InputRouterImplTest, InputFlush) {
EXPECT_TRUE(HasPendingEvents());
// DidFlush should be called only after the event is ack'ed.
- Flush();
+ RequestNotificationWhenFlushed();
EXPECT_EQ(0U, GetAndResetDidFlushCount());
SendInputEventACK(WebInputEvent::TouchStart,
INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
@@ -1581,11 +1575,11 @@ TEST_F(InputRouterImplTest, InputFlush) {
blink::WebGestureDeviceTouchscreen);
SimulateGestureEvent(WebInputEvent::GesturePinchUpdate,
blink::WebGestureDeviceTouchscreen);
- Flush();
+ RequestNotificationWhenFlushed();
EXPECT_EQ(0U, GetAndResetDidFlushCount());
// Repeated flush calls should have no effect.
- Flush();
+ RequestNotificationWhenFlushed();
EXPECT_EQ(0U, GetAndResetDidFlushCount());
// There are still pending gestures.
@@ -1607,6 +1601,59 @@ TEST_F(InputRouterImplTest, InputFlush) {
EXPECT_FALSE(HasPendingEvents());
}
+// Test that the router will call the client's |DidFlush| after all fling
+// animations have completed.
+TEST_F(InputRouterImplTest, InputFlushAfterFling) {
+ EXPECT_FALSE(HasPendingEvents());
+
+ // Simulate a fling.
+ SimulateGestureEvent(WebInputEvent::GestureScrollBegin,
+ blink::WebGestureDeviceTouchscreen);
+ SimulateGestureEvent(WebInputEvent::GestureFlingStart,
+ blink::WebGestureDeviceTouchscreen);
+ EXPECT_TRUE(HasPendingEvents());
+
+ // If the fling is unconsumed, the flush is complete.
+ RequestNotificationWhenFlushed();
+ EXPECT_EQ(0U, GetAndResetDidFlushCount());
+ SimulateGestureEvent(WebInputEvent::GestureScrollBegin,
+ blink::WebGestureDeviceTouchscreen);
+ SendInputEventACK(WebInputEvent::GestureFlingStart,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_FALSE(HasPendingEvents());
+ EXPECT_EQ(1U, GetAndResetDidFlushCount());
+
+ // Simulate a second fling.
+ SimulateGestureEvent(WebInputEvent::GestureFlingStart,
+ blink::WebGestureDeviceTouchscreen);
+ EXPECT_TRUE(HasPendingEvents());
+
+ // If the fling is consumed, the flush is complete only when the renderer
+ // reports that is has ended.
+ RequestNotificationWhenFlushed();
+ EXPECT_EQ(0U, GetAndResetDidFlushCount());
+ SendInputEventACK(WebInputEvent::GestureFlingStart,
+ INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_TRUE(HasPendingEvents());
+ EXPECT_EQ(0U, GetAndResetDidFlushCount());
+
+ // The fling end notification should signal that the router is flushed.
+ input_router()->OnMessageReceived(InputHostMsg_DidStopFlinging(0));
+ EXPECT_EQ(1U, GetAndResetDidFlushCount());
+
+ // Even flings consumed by the client require a fling-end notification.
+ client_->set_filter_state(INPUT_EVENT_ACK_STATE_CONSUMED);
+ SimulateGestureEvent(WebInputEvent::GestureScrollBegin,
+ blink::WebGestureDeviceTouchscreen);
+ SimulateGestureEvent(WebInputEvent::GestureFlingStart,
+ blink::WebGestureDeviceTouchscreen);
+ ASSERT_TRUE(HasPendingEvents());
+ RequestNotificationWhenFlushed();
+ EXPECT_EQ(0U, GetAndResetDidFlushCount());
+ input_router()->OnMessageReceived(InputHostMsg_DidStopFlinging(0));
+ EXPECT_EQ(1U, GetAndResetDidFlushCount());
+}
+
// Test that GesturePinchUpdate is handled specially for trackpad
TEST_F(InputRouterImplTest, TouchpadPinchUpdate) {
// GesturePinchUpdate for trackpad sends synthetic wheel events.
@@ -1619,24 +1666,17 @@ TEST_F(InputRouterImplTest, TouchpadPinchUpdate) {
// Verify we actually sent a special wheel event to the renderer.
const WebInputEvent* input_event =
GetInputEventFromMessage(*process_->sink().GetMessageAt(0));
- ASSERT_EQ(WebInputEvent::MouseWheel, input_event->type);
- const WebMouseWheelEvent* wheel_event =
- static_cast<const WebMouseWheelEvent*>(input_event);
- EXPECT_EQ(20, wheel_event->x);
- EXPECT_EQ(25, wheel_event->y);
- EXPECT_EQ(20, wheel_event->globalX);
- EXPECT_EQ(25, wheel_event->globalY);
- EXPECT_EQ(20, wheel_event->windowX);
- EXPECT_EQ(25, wheel_event->windowY);
- EXPECT_EQ(PinchScaleToWheelDelta(1.5), wheel_event->deltaY);
- EXPECT_EQ(0, wheel_event->deltaX);
- EXPECT_EQ(1, wheel_event->hasPreciseScrollingDeltas);
- EXPECT_EQ(1, wheel_event->wheelTicksY);
- EXPECT_EQ(0, wheel_event->wheelTicksX);
+ ASSERT_EQ(WebInputEvent::GesturePinchUpdate, input_event->type);
+ const WebGestureEvent* gesture_event =
+ static_cast<const WebGestureEvent*>(input_event);
+ EXPECT_EQ(20, gesture_event->x);
+ EXPECT_EQ(25, gesture_event->y);
+ EXPECT_EQ(20, gesture_event->globalX);
+ EXPECT_EQ(25, gesture_event->globalY);
EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
// Indicate that the wheel event was unhandled.
- SendInputEventACK(WebInputEvent::MouseWheel,
+ SendInputEventACK(WebInputEvent::GesturePinchUpdate,
INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
// Check that the correct unhandled pinch event was received.
@@ -1650,15 +1690,13 @@ TEST_F(InputRouterImplTest, TouchpadPinchUpdate) {
SimulateGesturePinchUpdateEvent(
0.3f, 20, 25, 0, blink::WebGestureDeviceTouchpad);
input_event = GetInputEventFromMessage(*process_->sink().GetMessageAt(0));
- ASSERT_EQ(WebInputEvent::MouseWheel, input_event->type);
- wheel_event = static_cast<const WebMouseWheelEvent*>(input_event);
- EXPECT_FLOAT_EQ(PinchScaleToWheelDelta(0.3f), wheel_event->deltaY);
- EXPECT_EQ(1, wheel_event->hasPreciseScrollingDeltas);
- EXPECT_EQ(-1, wheel_event->wheelTicksY);
+ ASSERT_EQ(WebInputEvent::GesturePinchUpdate, input_event->type);
+ gesture_event = static_cast<const WebGestureEvent*>(input_event);
EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
// Indicate that the wheel event was handled this time.
- SendInputEventACK(WebInputEvent::MouseWheel, INPUT_EVENT_ACK_STATE_CONSUMED);
+ SendInputEventACK(WebInputEvent::GesturePinchUpdate,
+ INPUT_EVENT_ACK_STATE_CONSUMED);
// Check that the correct HANDLED pinch event was received.
EXPECT_EQ(1U, ack_handler_->GetAndResetAckCount());
@@ -1668,158 +1706,11 @@ TEST_F(InputRouterImplTest, TouchpadPinchUpdate) {
ack_handler_->acked_gesture_event().data.pinchUpdate.scale);
}
-// Test that touchpad pinch events are coalesced property, with their synthetic
-// wheel events getting the right ACKs.
-TEST_F(InputRouterImplTest, TouchpadPinchCoalescing) {
- // Send the first pinch.
- SimulateGesturePinchUpdateEvent(
- 1.5f, 20, 25, 0, blink::WebGestureDeviceTouchpad);
-
- // Verify we sent the wheel event to the renderer.
- const WebInputEvent* input_event =
- GetInputEventFromMessage(*process_->sink().GetMessageAt(0));
- ASSERT_EQ(WebInputEvent::MouseWheel, input_event->type);
- const WebMouseWheelEvent* wheel_event =
- static_cast<const WebMouseWheelEvent*>(input_event);
- EXPECT_EQ(PinchScaleToWheelDelta(1.5f), wheel_event->deltaY);
- EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
- EXPECT_EQ(0U, ack_handler_->GetAndResetAckCount());
- EXPECT_EQ(1, client_->in_flight_event_count());
-
- // Send a second pinch, this should be queued in the GestureEventQueue.
- SimulateGesturePinchUpdateEvent(
- 1.6f, 20, 25, 0, blink::WebGestureDeviceTouchpad);
- EXPECT_EQ(0U, GetSentMessageCountAndResetSink());
- EXPECT_EQ(0U, ack_handler_->GetAndResetAckCount());
-
- // Send a third pinch, this should be coalesced into the second in the
- // GestureEventQueue.
- SimulateGesturePinchUpdateEvent(
- 1.7f, 20, 25, 0, blink::WebGestureDeviceTouchpad);
- EXPECT_EQ(0U, GetSentMessageCountAndResetSink());
- EXPECT_EQ(0U, ack_handler_->GetAndResetAckCount());
-
- // Indicate that the first wheel event was unhandled and verify the ACK.
- SendInputEventACK(WebInputEvent::MouseWheel,
- INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
- EXPECT_EQ(1U, ack_handler_->GetAndResetAckCount());
- EXPECT_EQ(WebInputEvent::GesturePinchUpdate, ack_handler_->ack_event_type());
- EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, ack_handler_->ack_state());
- EXPECT_EQ(1.5f, ack_handler_->acked_gesture_event().data.pinchUpdate.scale);
-
- // Verify a second wheel event was sent representing the 2nd and 3rd pinch
- // events.
- EXPECT_EQ(1, client_->in_flight_event_count());
- input_event = GetInputEventFromMessage(*process_->sink().GetMessageAt(0));
- ASSERT_EQ(WebInputEvent::MouseWheel, input_event->type);
- wheel_event = static_cast<const WebMouseWheelEvent*>(input_event);
- EXPECT_FLOAT_EQ(PinchScaleToWheelDelta(1.6f * 1.7f),
- PinchScaleToWheelDelta(1.6f) + PinchScaleToWheelDelta(1.7f));
- EXPECT_FLOAT_EQ(PinchScaleToWheelDelta(1.6f * 1.7f), wheel_event->deltaY);
- EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
- EXPECT_EQ(0U, ack_handler_->GetAndResetAckCount());
-
- // Indicate that the second wheel event was handled and verify the ACK.
- SendInputEventACK(WebInputEvent::MouseWheel, INPUT_EVENT_ACK_STATE_CONSUMED);
- EXPECT_EQ(1U, ack_handler_->GetAndResetAckCount());
- EXPECT_EQ(WebInputEvent::GesturePinchUpdate, ack_handler_->ack_event_type());
- EXPECT_EQ(INPUT_EVENT_ACK_STATE_CONSUMED, ack_handler_->ack_state());
- EXPECT_FLOAT_EQ(1.6f * 1.7f,
- ack_handler_->acked_gesture_event().data.pinchUpdate.scale);
-}
-
-// Test interleaving pinch and wheel events.
-TEST_F(InputRouterImplTest, TouchpadPinchAndWheel) {
- // Simulate queued wheel and pinch events events.
- // Note that in practice interleaving pinch and wheel events should be rare
- // (eg. requires the use of a mouse and trackpad at the same time).
-
- // Use the control modifier to match the synthetic wheel events so that
- // they're elligble for coalescing.
- int mod = WebInputEvent::ControlKey;
-
- // Event 1: sent directly.
- SimulateWheelEvent(0, -5, mod, true);
- EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
-
- // Event 2: enqueued in InputRouter.
- SimulateWheelEvent(0, -10, mod, true);
- EXPECT_EQ(0U, GetSentMessageCountAndResetSink());
-
- // Event 3: enqueued in InputRouter, not coalesced into #2.
- SimulateGesturePinchUpdateEvent(
- 1.5f, 20, 25, 0, blink::WebGestureDeviceTouchpad);
- EXPECT_EQ(0U, GetSentMessageCountAndResetSink());
-
- // Event 4: enqueued in GestureEventQueue.
- SimulateGesturePinchUpdateEvent(
- 1.2f, 20, 25, 0, blink::WebGestureDeviceTouchpad);
- EXPECT_EQ(0U, GetSentMessageCountAndResetSink());
-
- // Event 5: coalesced into wheel event for #3.
- SimulateWheelEvent(2, 0, mod, true);
- EXPECT_EQ(0U, GetSentMessageCountAndResetSink());
-
- // Send ack for #1.
- SendInputEventACK(WebInputEvent::MouseWheel,
- INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
- EXPECT_EQ(1U, ack_handler_->GetAndResetAckCount());
- EXPECT_EQ(WebInputEvent::MouseWheel, ack_handler_->ack_event_type());
-
- // Verify we sent #2.
- ASSERT_EQ(1U, process_->sink().message_count());
- const WebInputEvent* input_event =
- GetInputEventFromMessage(*process_->sink().GetMessageAt(0));
- ASSERT_EQ(WebInputEvent::MouseWheel, input_event->type);
- const WebMouseWheelEvent* wheel_event =
- static_cast<const WebMouseWheelEvent*>(input_event);
- EXPECT_EQ(0, wheel_event->deltaX);
- EXPECT_EQ(-10, wheel_event->deltaY);
- EXPECT_EQ(mod, wheel_event->modifiers);
- EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
-
- // Send ack for #2.
- SendInputEventACK(WebInputEvent::MouseWheel,
- INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
- EXPECT_EQ(1U, ack_handler_->GetAndResetAckCount());
- EXPECT_EQ(WebInputEvent::MouseWheel, ack_handler_->ack_event_type());
-
- // Verify we sent #3 (with #5 coalesced in).
- ASSERT_EQ(1U, process_->sink().message_count());
- input_event = GetInputEventFromMessage(*process_->sink().GetMessageAt(0));
- ASSERT_EQ(WebInputEvent::MouseWheel, input_event->type);
- wheel_event = static_cast<const WebMouseWheelEvent*>(input_event);
- EXPECT_EQ(2, wheel_event->deltaX);
- EXPECT_EQ(PinchScaleToWheelDelta(1.5f), wheel_event->deltaY);
- EXPECT_EQ(mod, wheel_event->modifiers);
- EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
-
- // Send ack for #3.
- SendInputEventACK(WebInputEvent::MouseWheel,
- INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
- EXPECT_EQ(1U, ack_handler_->GetAndResetAckCount());
- EXPECT_EQ(WebInputEvent::GesturePinchUpdate, ack_handler_->ack_event_type());
-
- // Verify we sent #4.
- ASSERT_EQ(1U, process_->sink().message_count());
- input_event = GetInputEventFromMessage(*process_->sink().GetMessageAt(0));
- ASSERT_EQ(WebInputEvent::MouseWheel, input_event->type);
- wheel_event = static_cast<const WebMouseWheelEvent*>(input_event);
- EXPECT_EQ(0, wheel_event->deltaX);
- EXPECT_FLOAT_EQ(PinchScaleToWheelDelta(1.2f), wheel_event->deltaY);
- EXPECT_EQ(mod, wheel_event->modifiers);
- EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
-
- // Send ack for #4.
- SendInputEventACK(WebInputEvent::MouseWheel,
- INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
- EXPECT_EQ(1U, ack_handler_->GetAndResetAckCount());
- EXPECT_EQ(WebInputEvent::GesturePinchUpdate, ack_handler_->ack_event_type());
-}
-
// Test proper handling of touchpad Gesture{Pinch,Scroll}Update sequences.
TEST_F(InputRouterImplTest, TouchpadPinchAndScrollUpdate) {
// The first scroll should be sent immediately.
+ SimulateGestureScrollUpdateEvent(1.5f, 0.f, 0,
+ blink::WebGestureDeviceTouchpad);
SimulateGestureEvent(WebInputEvent::GestureScrollUpdate,
blink::WebGestureDeviceTouchpad);
ASSERT_EQ(1U, GetSentMessageCountAndResetSink());
@@ -1827,23 +1718,23 @@ TEST_F(InputRouterImplTest, TouchpadPinchAndScrollUpdate) {
// Subsequent scroll and pinch events should remain queued, coalescing as
// more trackpad events arrive.
- SimulateGestureEvent(WebInputEvent::GesturePinchUpdate,
- blink::WebGestureDeviceTouchpad);
+ SimulateGesturePinchUpdateEvent(1.5f, 20, 25, 0,
+ blink::WebGestureDeviceTouchpad);
ASSERT_EQ(0U, GetSentMessageCountAndResetSink());
EXPECT_EQ(1, client_->in_flight_event_count());
- SimulateGestureEvent(WebInputEvent::GestureScrollUpdate,
- blink::WebGestureDeviceTouchpad);
+ SimulateGestureScrollUpdateEvent(1.5f, 1.5f, 0,
+ blink::WebGestureDeviceTouchpad);
ASSERT_EQ(0U, GetSentMessageCountAndResetSink());
EXPECT_EQ(1, client_->in_flight_event_count());
- SimulateGestureEvent(WebInputEvent::GesturePinchUpdate,
- blink::WebGestureDeviceTouchpad);
+ SimulateGesturePinchUpdateEvent(1.5f, 20, 25, 0,
+ blink::WebGestureDeviceTouchpad);
ASSERT_EQ(0U, GetSentMessageCountAndResetSink());
EXPECT_EQ(1, client_->in_flight_event_count());
- SimulateGestureEvent(WebInputEvent::GestureScrollUpdate,
- blink::WebGestureDeviceTouchpad);
+ SimulateGestureScrollUpdateEvent(0.f, 1.5f, 0,
+ blink::WebGestureDeviceTouchpad);
ASSERT_EQ(0U, GetSentMessageCountAndResetSink());
EXPECT_EQ(1, client_->in_flight_event_count());
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 93f7ccadf4f..b482e517e0f 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
@@ -83,4 +83,4 @@ class MockInputAckHandler : public InputAckHandler {
} // namespace content
-#endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_MOCK_INPUT_ACK_HANDLER_H_
+#endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_MOCK_INPUT_ACK_HANDLER_H_
diff --git a/chromium/content/browser/renderer_host/input/mock_input_router_client.cc b/chromium/content/browser/renderer_host/input/mock_input_router_client.cc
index 068af8c9206..fcb5de1a049 100644
--- a/chromium/content/browser/renderer_host/input/mock_input_router_client.cc
+++ b/chromium/content/browser/renderer_host/input/mock_input_router_client.cc
@@ -19,13 +19,13 @@ using blink::WebTouchPoint;
namespace content {
MockInputRouterClient::MockInputRouterClient()
- : input_router_(NULL),
- in_flight_event_count_(0),
- has_touch_handler_(false),
- filter_state_(INPUT_EVENT_ACK_STATE_NOT_CONSUMED),
- filter_input_event_called_(false),
- did_flush_called_count_(0),
- set_needs_flush_called_(false) {}
+ : input_router_(NULL),
+ in_flight_event_count_(0),
+ has_touch_handler_(false),
+ filter_state_(INPUT_EVENT_ACK_STATE_NOT_CONSUMED),
+ filter_input_event_called_(false),
+ did_flush_called_count_(0) {
+}
MockInputRouterClient::~MockInputRouterClient() {}
@@ -50,10 +50,6 @@ void MockInputRouterClient::OnHasTouchEventHandlers(
has_touch_handler_ = has_handlers;
}
-void MockInputRouterClient::SetNeedsFlush() {
- set_needs_flush_called_ = true;
-}
-
void MockInputRouterClient::DidFlush() {
++did_flush_called_count_;
}
@@ -62,6 +58,9 @@ void MockInputRouterClient::DidOverscroll(const DidOverscrollParams& params) {
overscroll_ = params;
}
+void MockInputRouterClient::DidStopFlinging() {
+}
+
bool MockInputRouterClient::GetAndResetFilterEventCalled() {
bool filter_input_event_called = filter_input_event_called_;
filter_input_event_called_ = false;
diff --git a/chromium/content/browser/renderer_host/input/mock_input_router_client.h b/chromium/content/browser/renderer_host/input/mock_input_router_client.h
index a552ac0debf..c4938a4a4e2 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
@@ -26,9 +26,9 @@ class MockInputRouterClient : public InputRouterClient {
void IncrementInFlightEventCount() override;
void DecrementInFlightEventCount() override;
void OnHasTouchEventHandlers(bool has_handlers) override;
- void SetNeedsFlush() override;
void DidFlush() override;
void DidOverscroll(const DidOverscrollParams& params) override;
+ void DidStopFlinging() override;
bool GetAndResetFilterEventCalled();
size_t GetAndResetDidFlushCount();
@@ -60,11 +60,10 @@ class MockInputRouterClient : public InputRouterClient {
scoped_ptr<InputEvent> last_filter_event_;
size_t did_flush_called_count_;
- bool set_needs_flush_called_;
DidOverscrollParams overscroll_;
};
} // namespace content
-#endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_MOCK_INPUT_ROUTER_CLIENT_H_
+#endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_MOCK_INPUT_ROUTER_CLIENT_H_
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 fa21047d71b..8d36c812cc0 100644
--- a/chromium/content/browser/renderer_host/input/motion_event_android.cc
+++ b/chromium/content/browser/renderer_host/input/motion_event_android.cc
@@ -6,9 +6,11 @@
#include <android/input.h>
+#include <cmath>
+
#include "base/android/jni_android.h"
-#include "base/float_util.h"
#include "jni/MotionEvent_jni.h"
+#include "ui/events/base_event_utils.h"
#include "ui/events/event_constants.h"
using base::android::AttachCurrentThread;
@@ -92,7 +94,7 @@ base::TimeTicks FromAndroidTime(int64 time_ms) {
}
float ToValidFloat(float x) {
- if (base::IsNaN(x))
+ if (std::isnan(x))
return 0.f;
// Wildly large orientation values have been observed in the wild after device
@@ -104,6 +106,17 @@ float ToValidFloat(float x) {
return x;
}
+size_t ToValidHistorySize(jint history_size, ui::MotionEvent::Action action) {
+ DCHECK_GE(history_size, 0);
+ // While the spec states that only ACTION_MOVE events should contain
+ // historical entries, it's possible that an embedder could repurpose an
+ // ACTION_MOVE event into a different kind of event. In that case, the
+ // historical values are meaningless, and should not be exposed.
+ if (action != ui::MotionEvent::ACTION_MOVE)
+ return 0;
+ return history_size;
+}
+
} // namespace
MotionEventAndroid::Pointer::Pointer(jint id,
@@ -148,17 +161,17 @@ MotionEventAndroid::MotionEventAndroid(float pix_to_dip,
cached_time_(FromAndroidTime(time_ms)),
cached_action_(FromAndroidAction(android_action)),
cached_pointer_count_(pointer_count),
- cached_history_size_(history_size),
+ cached_history_size_(ToValidHistorySize(history_size, cached_action_)),
cached_action_index_(action_index),
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)) {
+ ToDips(raw_offset_y_pixels)),
+ unique_event_id_(ui::GetNextTouchEventId()) {
DCHECK_GT(pointer_count, 0);
- DCHECK_GE(history_size, 0);
event_.Reset(env, event);
- if (cached_pointer_count_ > MAX_POINTERS_TO_CACHE || history_size > 0)
+ if (cached_pointer_count_ > MAX_POINTERS_TO_CACHE || cached_history_size_ > 0)
DCHECK(event_.obj());
cached_pointers_[0] = FromAndroidPointer(pointer0);
@@ -168,8 +181,8 @@ MotionEventAndroid::MotionEventAndroid(float pix_to_dip,
MotionEventAndroid::~MotionEventAndroid() {
}
-int MotionEventAndroid::GetId() const {
- return 0;
+uint32 MotionEventAndroid::GetUniqueEventId() const {
+ return unique_event_id_;
}
MotionEventAndroid::Action MotionEventAndroid::GetAction() const {
@@ -177,6 +190,11 @@ MotionEventAndroid::Action MotionEventAndroid::GetAction() const {
}
int MotionEventAndroid::GetActionIndex() const {
+ DCHECK(cached_action_ == ACTION_POINTER_UP ||
+ cached_action_ == ACTION_POINTER_DOWN)
+ << "Invalid action for GetActionIndex(): " << cached_action_;
+ DCHECK_GE(cached_action_index_, 0);
+ DCHECK_LT(cached_action_index_, static_cast<int>(cached_pointer_count_));
return cached_action_index_;
}
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 4af9f72e00b..bf4dfed040e 100644
--- a/chromium/content/browser/renderer_host/input/motion_event_android.h
+++ b/chromium/content/browser/renderer_host/input/motion_event_android.h
@@ -55,35 +55,35 @@ class CONTENT_EXPORT MotionEventAndroid : public ui::MotionEvent {
jfloat raw_offset_y_pixels,
const Pointer& pointer0,
const Pointer& pointer1);
- virtual ~MotionEventAndroid();
+ ~MotionEventAndroid() override;
// 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 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(
+ uint32 GetUniqueEventId() 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;
+ size_t GetHistorySize() const override;
+ 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 ToolType GetToolType(size_t pointer_index) const override;
- virtual int GetButtonState() const override;
- virtual int GetFlags() const override;
+ float GetHistoricalTouchMajor(size_t pointer_index,
+ size_t historical_index) const override;
+ float GetHistoricalX(size_t pointer_index,
+ size_t historical_index) const override;
+ float GetHistoricalY(size_t pointer_index,
+ size_t historical_index) const override;
+ ToolType GetToolType(size_t pointer_index) const override;
+ int GetButtonState() const override;
+ int GetFlags() const override;
static bool RegisterMotionEventAndroid(JNIEnv* env);
@@ -123,6 +123,9 @@ class CONTENT_EXPORT MotionEventAndroid : public ui::MotionEvent {
ToolType tool_type;
} cached_pointers_[MAX_POINTERS_TO_CACHE];
+ // A unique identifier for the Android motion event.
+ const uint32 unique_event_id_;
+
DISALLOW_COPY_AND_ASSIGN(MotionEventAndroid);
};
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
index d7482d9aa7e..9a33b318ab5 100644
--- a/chromium/content/browser/renderer_host/input/motion_event_android_unittest.cc
+++ b/chromium/content/browser/renderer_host/input/motion_event_android_unittest.cc
@@ -5,7 +5,6 @@
#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"
@@ -18,7 +17,7 @@ namespace {
const float kPixToDip = 0.5f;
int kAndroidActionDown = AMOTION_EVENT_ACTION_DOWN;
-
+int kAndroidActionPointerDown = AMOTION_EVENT_ACTION_POINTER_DOWN;
int kAndroidAltKeyDown = AMETA_ALT_ON;
// Corresponds to TOOL_TYPE_FINGER, see
@@ -86,7 +85,6 @@ TEST(MotionEventAndroidTest, Constructor) {
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) {
@@ -171,4 +169,54 @@ TEST(MotionEventAndroidTest, InvalidOrientationsSanitized) {
EXPECT_EQ(0.f, event.GetOrientation(1));
}
+TEST(MotionEventAndroidTest, NonEmptyHistoryForNonMoveEventsSanitized) {
+ int pointer_count = 1;
+ size_t history_size = 5;
+ MotionEventAndroid::Pointer p0(0, 0, 0, 0, 0, 0, 0);
+ MotionEventAndroid::Pointer p1(0, 0, 0, 0, 0, 0, 0);
+ MotionEventAndroid event(kPixToDip,
+ base::android::AttachCurrentThread(),
+ nullptr,
+ 0,
+ kAndroidActionDown,
+ pointer_count,
+ history_size,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ p0,
+ p1);
+
+ EXPECT_EQ(0U, event.GetHistorySize());
+}
+
+TEST(MotionEventAndroidTest, ActionIndexForPointerDown) {
+ 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);
+ int pointer_count = 2;
+ int history_size = 0;
+ int action_index = 1;
+ MotionEventAndroid event(kPixToDip,
+ base::android::AttachCurrentThread(),
+ nullptr,
+ 0,
+ kAndroidActionPointerDown,
+ pointer_count,
+ history_size,
+ action_index,
+ 0,
+ 0,
+ 0,
+ 0,
+ p0,
+ p1);
+
+ EXPECT_EQ(MotionEvent::ACTION_POINTER_DOWN, event.GetAction());
+ EXPECT_EQ(action_index, event.GetActionIndex());
+}
+
} // 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 77a40a4fe25..bc47cf8c177 100644
--- a/chromium/content/browser/renderer_host/input/motion_event_web.cc
+++ b/chromium/content/browser/renderer_host/input/motion_event_web.cc
@@ -63,21 +63,29 @@ int GetActionIndexFrom(const WebTouchEvent& event) {
MotionEventWeb::MotionEventWeb(const WebTouchEvent& event)
: event_(event),
cached_action_(GetActionFrom(event)),
- cached_action_index_(GetActionIndexFrom(event)) {
+ cached_action_index_(GetActionIndexFrom(event)),
+ unique_event_id_(event.uniqueTouchEventId) {
DCHECK_GT(GetPointerCount(), 0U);
}
MotionEventWeb::~MotionEventWeb() {}
-int MotionEventWeb::GetId() const {
- return 0;
+uint32 MotionEventWeb::GetUniqueEventId() const {
+ return unique_event_id_;
}
MotionEventWeb::Action MotionEventWeb::GetAction() const {
return cached_action_;
}
-int MotionEventWeb::GetActionIndex() const { return cached_action_index_; }
+int MotionEventWeb::GetActionIndex() const {
+ DCHECK(cached_action_ == ACTION_POINTER_UP ||
+ cached_action_ == ACTION_POINTER_DOWN)
+ << "Invalid action for GetActionIndex(): " << cached_action_;
+ DCHECK_GE(cached_action_index_, 0);
+ DCHECK_LT(cached_action_index_, static_cast<int>(event_.touchesLength));
+ return cached_action_index_;
+}
size_t MotionEventWeb::GetPointerCount() const { return event_.touchesLength; }
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 f3d85abfc12..34e954168b8 100644
--- a/chromium/content/browser/renderer_host/input/motion_event_web.h
+++ b/chromium/content/browser/renderer_host/input/motion_event_web.h
@@ -17,7 +17,7 @@ class MotionEventWeb : public ui::MotionEvent {
~MotionEventWeb() override;
// ui::MotionEvent
- int GetId() const override;
+ uint32 GetUniqueEventId() const override;
Action GetAction() const override;
int GetActionIndex() const override;
size_t GetPointerCount() const override;
@@ -39,6 +39,7 @@ class MotionEventWeb : public ui::MotionEvent {
blink::WebTouchEvent event_;
Action cached_action_;
int cached_action_index_;
+ const uint32 unique_event_id_;
DISALLOW_COPY_AND_ASSIGN(MotionEventWeb);
};
diff --git a/chromium/content/browser/renderer_host/input/mouse_wheel_rails_filter_mac.cc b/chromium/content/browser/renderer_host/input/mouse_wheel_rails_filter_mac.cc
new file mode 100644
index 00000000000..3681ba9ba67
--- /dev/null
+++ b/chromium/content/browser/renderer_host/input/mouse_wheel_rails_filter_mac.cc
@@ -0,0 +1,38 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/renderer_host/input/mouse_wheel_rails_filter_mac.h"
+
+using blink::WebInputEvent;
+using blink::WebMouseWheelEvent;
+
+namespace content {
+
+MouseWheelRailsFilterMac::MouseWheelRailsFilterMac() {
+}
+
+MouseWheelRailsFilterMac::~MouseWheelRailsFilterMac() {
+}
+
+WebInputEvent::RailsMode MouseWheelRailsFilterMac::UpdateRailsMode(
+ const WebMouseWheelEvent& event) {
+ // A somewhat-arbitrary decay constant for hysteresis.
+ const float kDecayConstant = 0.8f;
+
+ if (event.phase == WebMouseWheelEvent::PhaseBegan) {
+ decayed_delta_ = gfx::Vector2dF();
+ }
+ if (event.deltaX == 0 && event.deltaY == 0)
+ return WebInputEvent::RailsModeFree;
+
+ decayed_delta_.Scale(kDecayConstant);
+ decayed_delta_ +=
+ gfx::Vector2dF(std::abs(event.deltaX), std::abs(event.deltaY));
+
+ if (decayed_delta_.y() >= decayed_delta_.x())
+ return WebInputEvent::RailsModeVertical;
+ return WebInputEvent::RailsModeHorizontal;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/mouse_wheel_rails_filter_mac.h b/chromium/content/browser/renderer_host/input/mouse_wheel_rails_filter_mac.h
new file mode 100644
index 00000000000..ffed162c97d
--- /dev/null
+++ b/chromium/content/browser/renderer_host/input/mouse_wheel_rails_filter_mac.h
@@ -0,0 +1,27 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_RENDERER_HOST_INPUT_MOUSE_WHEEL_RAILS_FILTER_MAC_H_
+#define CONTENT_BROWSER_RENDERER_HOST_INPUT_MOUSE_WHEEL_RAILS_FILTER_MAC_H_
+
+#include "content/common/content_export.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
+#include "ui/gfx/geometry/vector2d_f.h"
+
+namespace content {
+
+class CONTENT_EXPORT MouseWheelRailsFilterMac {
+ public:
+ MouseWheelRailsFilterMac();
+ ~MouseWheelRailsFilterMac();
+ blink::WebInputEvent::RailsMode UpdateRailsMode(
+ const blink::WebMouseWheelEvent& event);
+
+ private:
+ gfx::Vector2dF decayed_delta_;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_MOUSE_WHEEL_RAILS_FILTER_MAC_H_
diff --git a/chromium/content/browser/renderer_host/input/mouse_wheel_rails_filter_unittest_mac.cc b/chromium/content/browser/renderer_host/input/mouse_wheel_rails_filter_unittest_mac.cc
new file mode 100644
index 00000000000..7811ef7512d
--- /dev/null
+++ b/chromium/content/browser/renderer_host/input/mouse_wheel_rails_filter_unittest_mac.cc
@@ -0,0 +1,64 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/renderer_host/input/mouse_wheel_rails_filter_mac.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using blink::WebInputEvent;
+using blink::WebMouseWheelEvent;
+
+namespace content {
+namespace {
+
+WebMouseWheelEvent MakeEvent(WebMouseWheelEvent::Phase phase,
+ float delta_x,
+ float delta_y) {
+ WebMouseWheelEvent event;
+ event.phase = phase;
+ event.deltaX = delta_x;
+ event.deltaY = delta_y;
+ return event;
+}
+
+TEST(MouseWheelRailsFilterMacTest, Functionality) {
+ WebInputEvent::RailsMode mode;
+ MouseWheelRailsFilterMac filter;
+
+ // Start with a mostly-horizontal event and see that it is locked
+ // horizontally and continues to be locked.
+ mode =
+ filter.UpdateRailsMode(MakeEvent(WebMouseWheelEvent::PhaseBegan, 2, 1));
+ EXPECT_EQ(mode, WebInputEvent::RailsModeHorizontal);
+ mode = filter.UpdateRailsMode(
+ MakeEvent(WebMouseWheelEvent::PhaseChanged, 2, 2));
+ EXPECT_EQ(mode, WebInputEvent::RailsModeHorizontal);
+ mode = filter.UpdateRailsMode(
+ MakeEvent(WebMouseWheelEvent::PhaseChanged, 10, -4));
+ EXPECT_EQ(mode, WebInputEvent::RailsModeHorizontal);
+
+ // Change from horizontal to vertical and back.
+ mode =
+ filter.UpdateRailsMode(MakeEvent(WebMouseWheelEvent::PhaseBegan, 4, 1));
+ EXPECT_EQ(mode, WebInputEvent::RailsModeHorizontal);
+ mode = filter.UpdateRailsMode(
+ MakeEvent(WebMouseWheelEvent::PhaseChanged, 3, 4));
+ EXPECT_EQ(mode, WebInputEvent::RailsModeHorizontal);
+ mode = filter.UpdateRailsMode(
+ MakeEvent(WebMouseWheelEvent::PhaseChanged, 1, 4));
+ EXPECT_EQ(mode, WebInputEvent::RailsModeVertical);
+ mode = filter.UpdateRailsMode(
+ MakeEvent(WebMouseWheelEvent::PhaseChanged, 10, 0));
+ EXPECT_EQ(mode, WebInputEvent::RailsModeHorizontal);
+
+ // Make sure zeroes don't break things.
+ mode = filter.UpdateRailsMode(
+ MakeEvent(WebMouseWheelEvent::PhaseChanged, 0, 0));
+ EXPECT_EQ(mode, WebInputEvent::RailsModeFree);
+ mode =
+ filter.UpdateRailsMode(MakeEvent(WebMouseWheelEvent::PhaseBegan, 0, 0));
+ EXPECT_EQ(mode, WebInputEvent::RailsModeFree);
+}
+
+} // namespace
+} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/render_widget_host_latency_tracker.cc b/chromium/content/browser/renderer_host/input/render_widget_host_latency_tracker.cc
new file mode 100644
index 00000000000..2ca7f74da38
--- /dev/null
+++ b/chromium/content/browser/renderer_host/input/render_widget_host_latency_tracker.cc
@@ -0,0 +1,470 @@
+// Copyright 2014 The Chromium Authors. 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/render_widget_host_latency_tracker.h"
+
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "content/browser/renderer_host/render_widget_host_impl.h"
+
+using blink::WebGestureEvent;
+using blink::WebInputEvent;
+using blink::WebMouseEvent;
+using blink::WebMouseWheelEvent;
+using blink::WebTouchEvent;
+using ui::LatencyInfo;
+
+namespace content {
+namespace {
+
+const uint32 kMaxInputCoordinates = LatencyInfo::kMaxInputCoordinates;
+const size_t kBrowserCompositeLatencyHistorySize = 60;
+const double kBrowserCompositeLatencyEstimationPercentile = 90.0;
+const double kBrowserCompositeLatencyEstimationSlack = 1.1;
+
+void UpdateLatencyCoordinatesImpl(const blink::WebTouchEvent& touch,
+ LatencyInfo* latency) {
+ latency->input_coordinates_size =
+ std::min(kMaxInputCoordinates, touch.touchesLength);
+ for (uint32 i = 0; i < latency->input_coordinates_size; ++i) {
+ latency->input_coordinates[i] = LatencyInfo::InputCoordinate(
+ touch.touches[i].position.x, touch.touches[i].position.y);
+ }
+}
+
+void UpdateLatencyCoordinatesImpl(const WebGestureEvent& gesture,
+ LatencyInfo* latency) {
+ latency->input_coordinates_size = 1;
+ latency->input_coordinates[0] =
+ LatencyInfo::InputCoordinate(gesture.x, gesture.y);
+}
+
+void UpdateLatencyCoordinatesImpl(const WebMouseEvent& mouse,
+ LatencyInfo* latency) {
+ latency->input_coordinates_size = 1;
+ latency->input_coordinates[0] =
+ LatencyInfo::InputCoordinate(mouse.x, mouse.y);
+}
+
+void UpdateLatencyCoordinatesImpl(const WebMouseWheelEvent& wheel,
+ LatencyInfo* latency) {
+ latency->input_coordinates_size = 1;
+ latency->input_coordinates[0] =
+ LatencyInfo::InputCoordinate(wheel.x, wheel.y);
+}
+
+void UpdateLatencyCoordinates(const WebInputEvent& event,
+ float device_scale_factor,
+ LatencyInfo* latency) {
+ if (WebInputEvent::isMouseEventType(event.type)) {
+ UpdateLatencyCoordinatesImpl(static_cast<const WebMouseEvent&>(event),
+ latency);
+ } else if (WebInputEvent::isGestureEventType(event.type)) {
+ UpdateLatencyCoordinatesImpl(static_cast<const WebGestureEvent&>(event),
+ latency);
+ } else if (WebInputEvent::isTouchEventType(event.type)) {
+ UpdateLatencyCoordinatesImpl(static_cast<const WebTouchEvent&>(event),
+ latency);
+ } else if (event.type == WebInputEvent::MouseWheel) {
+ UpdateLatencyCoordinatesImpl(static_cast<const WebMouseWheelEvent&>(event),
+ latency);
+ }
+ if (device_scale_factor == 1)
+ return;
+ for (uint32 i = 0; i < latency->input_coordinates_size; ++i) {
+ latency->input_coordinates[i].x *= device_scale_factor;
+ latency->input_coordinates[i].y *= device_scale_factor;
+ }
+}
+
+void ComputeInputLatencyHistograms(WebInputEvent::Type type,
+ int64 latency_component_id,
+ const LatencyInfo& latency) {
+ LatencyInfo::LatencyComponent rwh_component;
+ if (!latency.FindLatency(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
+ latency_component_id, &rwh_component)) {
+ return;
+ }
+ DCHECK_EQ(rwh_component.event_count, 1u);
+
+ LatencyInfo::LatencyComponent ui_component;
+ if (latency.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;
+ }
+ }
+
+ LatencyInfo::LatencyComponent acked_component;
+ if (latency.FindLatency(ui::INPUT_EVENT_LATENCY_ACK_RWH_COMPONENT, 0,
+ &acked_component)) {
+ DCHECK_EQ(acked_component.event_count, 1u);
+ base::TimeDelta acked_delta =
+ acked_component.event_time - rwh_component.event_time;
+ 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;
+ }
+ }
+}
+
+// Touch to scroll latency that is mostly under 1 second.
+#define UMA_HISTOGRAM_TOUCH_TO_SCROLL_LATENCY(name, start, end) \
+ UMA_HISTOGRAM_CUSTOM_COUNTS( \
+ name, (end.event_time - start.event_time).InMicroseconds(), 1, 1000000, \
+ 100)
+
+// Long scroll latency component that is mostly under 200ms.
+#define UMA_HISTOGRAM_SCROLL_LATENCY_LONG(name, start, end) \
+ UMA_HISTOGRAM_CUSTOM_COUNTS( \
+ name, \
+ (end.event_time - start.event_time).InMicroseconds(), \
+ 1000, 200000, 50)
+
+// Short scroll latency component that is mostly under 50ms.
+#define UMA_HISTOGRAM_SCROLL_LATENCY_SHORT(name, start, end) \
+ UMA_HISTOGRAM_CUSTOM_COUNTS( \
+ name, \
+ (end.event_time - start.event_time).InMicroseconds(), \
+ 1, 50000, 50)
+
+void ComputeScrollLatencyHistograms(
+ const LatencyInfo::LatencyComponent& gpu_swap_begin_component,
+ const LatencyInfo::LatencyComponent& gpu_swap_end_component,
+ int64 latency_component_id,
+ const LatencyInfo& latency) {
+ DCHECK(!gpu_swap_begin_component.event_time.is_null());
+ DCHECK(!gpu_swap_end_component.event_time.is_null());
+ LatencyInfo::LatencyComponent first_original_component, original_component;
+ if (latency.FindLatency(
+ ui::INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT,
+ latency_component_id, &first_original_component)) {
+ // This UMA metric tracks the time between the final frame swap for the
+ // first scroll event in a sequence and the original timestamp of that
+ // scroll event's underlying touch event.
+ for (size_t i = 0; i < first_original_component.event_count; i++) {
+ UMA_HISTOGRAM_TOUCH_TO_SCROLL_LATENCY(
+ "Event.Latency.TouchToFirstScrollUpdateSwapBegin",
+ first_original_component, gpu_swap_begin_component);
+ // TODO(brianderson): Remove this version once we have enough overlapping
+ // data with the metric above. crbug.com/478845
+ UMA_HISTOGRAM_TOUCH_TO_SCROLL_LATENCY(
+ "Event.Latency.TouchToFirstScrollUpdateSwap",
+ first_original_component, gpu_swap_end_component);
+ }
+ original_component = first_original_component;
+ } else if (!latency.FindLatency(
+ ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT,
+ latency_component_id, &original_component)) {
+ return;
+ }
+
+ // This UMA metric tracks the time from when the original touch event is
+ // created (averaged if there are multiple) to when the scroll gesture
+ // results in final frame swap.
+ for (size_t i = 0; i < original_component.event_count; i++) {
+ UMA_HISTOGRAM_TOUCH_TO_SCROLL_LATENCY(
+ "Event.Latency.TouchToScrollUpdateSwapBegin", original_component,
+ gpu_swap_begin_component);
+ // TODO(brianderson): Remove this version once we have enough overlapping
+ // data with the metric above. crbug.com/478845
+ UMA_HISTOGRAM_TOUCH_TO_SCROLL_LATENCY(
+ "Event.Latency.TouchToScrollUpdateSwap", original_component,
+ gpu_swap_end_component);
+ }
+
+ // TODO(miletus): Add validation for making sure the following components
+ // are present and their event times are legit.
+ LatencyInfo::LatencyComponent rendering_scheduled_component;
+ bool rendering_scheduled_on_main = latency.FindLatency(
+ ui::INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_MAIN_COMPONENT,
+ 0, &rendering_scheduled_component);
+
+ if (!rendering_scheduled_on_main) {
+ if (!latency.FindLatency(
+ ui::INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_IMPL_COMPONENT,
+ 0, &rendering_scheduled_component))
+ return;
+ }
+
+ if (rendering_scheduled_on_main) {
+ UMA_HISTOGRAM_SCROLL_LATENCY_LONG(
+ "Event.Latency.ScrollUpdate.TouchToHandled_Main",
+ original_component, rendering_scheduled_component);
+ } else {
+ UMA_HISTOGRAM_SCROLL_LATENCY_LONG(
+ "Event.Latency.ScrollUpdate.TouchToHandled_Impl",
+ original_component, rendering_scheduled_component);
+ }
+
+ LatencyInfo::LatencyComponent renderer_swap_component;
+ if (!latency.FindLatency(ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT,
+ 0, &renderer_swap_component))
+ return;
+
+ if (rendering_scheduled_on_main) {
+ UMA_HISTOGRAM_SCROLL_LATENCY_LONG(
+ "Event.Latency.ScrollUpdate.HandledToRendererSwap_Main",
+ rendering_scheduled_component, renderer_swap_component);
+ } else {
+ UMA_HISTOGRAM_SCROLL_LATENCY_LONG(
+ "Event.Latency.ScrollUpdate.HandledToRendererSwap_Impl",
+ rendering_scheduled_component, renderer_swap_component);
+ }
+
+ LatencyInfo::LatencyComponent browser_received_swap_component;
+ if (!latency.FindLatency(
+ ui::INPUT_EVENT_BROWSER_RECEIVED_RENDERER_SWAP_COMPONENT,
+ 0, &browser_received_swap_component))
+ return;
+
+ UMA_HISTOGRAM_SCROLL_LATENCY_SHORT(
+ "Event.Latency.ScrollUpdate.RendererSwapToBrowserNotified",
+ renderer_swap_component, browser_received_swap_component);
+
+ UMA_HISTOGRAM_SCROLL_LATENCY_LONG(
+ "Event.Latency.ScrollUpdate.BrowserNotifiedToBeforeGpuSwap",
+ browser_received_swap_component, gpu_swap_begin_component);
+
+ UMA_HISTOGRAM_SCROLL_LATENCY_SHORT("Event.Latency.ScrollUpdate.GpuSwap",
+ gpu_swap_begin_component,
+ gpu_swap_end_component);
+}
+
+// LatencyComponents generated in the renderer must have component IDs
+// provided to them by the browser process. This function adds the correct
+// component ID where necessary.
+void AddLatencyInfoComponentIds(LatencyInfo* latency,
+ int64 latency_component_id) {
+ LatencyInfo::LatencyMap new_components;
+ auto lc = latency->latency_components.begin();
+ while (lc != latency->latency_components.end()) {
+ ui::LatencyComponentType component_type = lc->first.first;
+ if (component_type == ui::WINDOW_SNAPSHOT_FRAME_NUMBER_COMPONENT) {
+ // Generate a new component entry with the correct component ID
+ auto key = std::make_pair(component_type, latency_component_id);
+ new_components[key] = lc->second;
+
+ // Remove the old entry
+ latency->latency_components.erase(lc++);
+ } else {
+ ++lc;
+ }
+ }
+
+ // Add newly generated components into the latency info
+ for (lc = new_components.begin(); lc != new_components.end(); ++lc) {
+ latency->latency_components[lc->first] = lc->second;
+ }
+}
+
+} // namespace
+
+RenderWidgetHostLatencyTracker::RenderWidgetHostLatencyTracker()
+ : last_event_id_(0),
+ latency_component_id_(0),
+ device_scale_factor_(1),
+ has_seent_first_gesture_scroll_update_(false),
+ browser_composite_latency_history_(kBrowserCompositeLatencyHistorySize) {
+}
+
+RenderWidgetHostLatencyTracker::~RenderWidgetHostLatencyTracker() {
+}
+
+void RenderWidgetHostLatencyTracker::Initialize(int routing_id,
+ int process_id) {
+ DCHECK_EQ(0, last_event_id_);
+ DCHECK_EQ(0, latency_component_id_);
+ last_event_id_ = static_cast<int64>(process_id) << 32;
+ latency_component_id_ = routing_id | last_event_id_;
+}
+
+void RenderWidgetHostLatencyTracker::OnInputEvent(
+ const blink::WebInputEvent& event,
+ LatencyInfo* latency) {
+ DCHECK(latency);
+ if (latency->FindLatency(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
+ latency_component_id_, NULL)) {
+ return;
+ }
+
+ if (event.timeStampSeconds &&
+ !latency->FindLatency(ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
+ 0, NULL)) {
+ latency->AddLatencyNumberWithTimestamp(
+ ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
+ 0,
+ 0,
+ base::TimeTicks() +
+ base::TimeDelta::FromSecondsD(event.timeStampSeconds),
+ 1);
+ }
+
+ latency->AddLatencyNumberWithTraceName(
+ ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
+ latency_component_id_, ++last_event_id_,
+ WebInputEventTraits::GetName(event.type));
+
+ UpdateLatencyCoordinates(event, device_scale_factor_, latency);
+
+ if (event.type == blink::WebInputEvent::GestureScrollBegin) {
+ has_seent_first_gesture_scroll_update_ = false;
+ } else if (event.type == blink::WebInputEvent::GestureScrollUpdate) {
+ // Make a copy of the INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT with a
+ // different name INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT.
+ // So we can track the latency specifically for scroll update events.
+ LatencyInfo::LatencyComponent original_component;
+ if (latency->FindLatency(ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0,
+ &original_component)) {
+ latency->AddLatencyNumberWithTimestamp(
+ has_seent_first_gesture_scroll_update_
+ ? ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT
+ : ui::INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT,
+ latency_component_id_, original_component.sequence_number,
+ original_component.event_time, original_component.event_count);
+ }
+
+ has_seent_first_gesture_scroll_update_ = true;
+ }
+}
+
+void RenderWidgetHostLatencyTracker::OnInputEventAck(
+ const blink::WebInputEvent& event,
+ LatencyInfo* latency) {
+ DCHECK(latency);
+
+ // Latency ends when it is acked but does not cause render scheduling.
+ bool rendering_scheduled = latency->FindLatency(
+ ui::INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_MAIN_COMPONENT, 0, nullptr);
+ rendering_scheduled |= latency->FindLatency(
+ ui::INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_IMPL_COMPONENT, 0, nullptr);
+
+ if (WebInputEvent::isGestureEventType(event.type)) {
+ if (!rendering_scheduled) {
+ latency->AddLatencyNumber(
+ ui::INPUT_EVENT_LATENCY_TERMINATED_GESTURE_COMPONENT, 0, 0);
+ // TODO(jdduke): Consider exposing histograms for gesture event types.
+ }
+ return;
+ }
+
+ if (WebInputEvent::isTouchEventType(event.type)) {
+ latency->AddLatencyNumber(ui::INPUT_EVENT_LATENCY_ACK_RWH_COMPONENT, 0, 0);
+ if (!rendering_scheduled) {
+ latency->AddLatencyNumber(
+ ui::INPUT_EVENT_LATENCY_TERMINATED_TOUCH_COMPONENT, 0, 0);
+ }
+ ComputeInputLatencyHistograms(WebInputEvent::TouchTypeFirst,
+ latency_component_id_, *latency);
+ return;
+ }
+
+ if (event.type == WebInputEvent::MouseWheel) {
+ latency->AddLatencyNumber(ui::INPUT_EVENT_LATENCY_ACK_RWH_COMPONENT, 0, 0);
+ if (!rendering_scheduled) {
+ latency->AddLatencyNumber(
+ ui::INPUT_EVENT_LATENCY_TERMINATED_MOUSE_COMPONENT, 0, 0);
+ }
+ ComputeInputLatencyHistograms(WebInputEvent::MouseWheel,
+ latency_component_id_, *latency);
+ return;
+ }
+
+ // TODO(jdduke): Determine if mouse and keyboard events are worth hooking
+ // into LatencyInfo.
+}
+
+void RenderWidgetHostLatencyTracker::OnSwapCompositorFrame(
+ std::vector<LatencyInfo>* latencies) {
+ DCHECK(latencies);
+ for (LatencyInfo& latency : *latencies) {
+ AddLatencyInfoComponentIds(&latency, latency_component_id_);
+ latency.AddLatencyNumber(
+ ui::INPUT_EVENT_BROWSER_RECEIVED_RENDERER_SWAP_COMPONENT, 0, 0);
+ }
+}
+
+void RenderWidgetHostLatencyTracker::OnFrameSwapped(
+ const LatencyInfo& latency) {
+ LatencyInfo::LatencyComponent gpu_swap_end_component;
+ if (!latency.FindLatency(
+ ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0,
+ &gpu_swap_end_component)) {
+ return;
+ }
+
+ LatencyInfo::LatencyComponent gpu_swap_begin_component;
+ if (!latency.FindLatency(ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0,
+ &gpu_swap_begin_component)) {
+ return;
+ }
+
+ LatencyInfo::LatencyComponent tab_switch_component;
+ if (latency.FindLatency(ui::TAB_SHOW_COMPONENT, latency_component_id_,
+ &tab_switch_component)) {
+ base::TimeDelta delta =
+ gpu_swap_end_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);
+ }
+ }
+
+ if (!latency.FindLatency(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
+ latency_component_id_, nullptr)) {
+ return;
+ }
+
+ ComputeScrollLatencyHistograms(gpu_swap_begin_component,
+ gpu_swap_end_component, latency_component_id_,
+ latency);
+
+ LatencyInfo::LatencyComponent browser_swap_component;
+ if (latency.FindLatency(
+ ui::INPUT_EVENT_BROWSER_RECEIVED_RENDERER_SWAP_COMPONENT, 0,
+ &browser_swap_component)) {
+ base::TimeDelta delta =
+ gpu_swap_begin_component.event_time - browser_swap_component.event_time;
+ browser_composite_latency_history_.InsertSample(delta);
+ }
+}
+
+base::TimeDelta
+RenderWidgetHostLatencyTracker::GetEstimatedBrowserCompositeTime() const {
+ // TODO(brianderson): 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)));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/render_widget_host_latency_tracker.h b/chromium/content/browser/renderer_host/input/render_widget_host_latency_tracker.h
new file mode 100644
index 00000000000..64e6f7f7bbc
--- /dev/null
+++ b/chromium/content/browser/renderer_host/input/render_widget_host_latency_tracker.h
@@ -0,0 +1,78 @@
+// Copyright 2014 The Chromium Authors. 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_RENDER_WIDGET_HOST_LATENCY_TRACKER_H_
+#define CONTENT_BROWSER_RENDERER_HOST_INPUT_RENDER_WIDGET_HOST_LATENCY_TRACKER_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "cc/base/rolling_time_delta_history.h"
+#include "content/browser/renderer_host/event_with_latency_info.h"
+#include "content/common/content_export.h"
+#include "ui/events/latency_info.h"
+
+namespace content {
+
+// Utility class for tracking the latency of events passing through
+// a given RenderWidgetHost.
+class CONTENT_EXPORT RenderWidgetHostLatencyTracker {
+ public:
+ RenderWidgetHostLatencyTracker();
+ ~RenderWidgetHostLatencyTracker();
+
+ // Associates the latency tracker with a given route and process.
+ // Called once after the RenderWidgetHost is fully initialized.
+ void Initialize(int routing_id, int process_id);
+
+ // Populates the LatencyInfo with relevant entries for latency tracking.
+ // Called when an event is received by the RenderWidgetHost, prior to
+ // that event being forwarded to the renderer (via the InputRouter).
+ void OnInputEvent(const blink::WebInputEvent& event,
+ ui::LatencyInfo* latency);
+
+ // Populates the LatencyInfo with relevant entries for latency tracking, also
+ // terminating latency tracking for events that did not trigger rendering and
+ // performing relevant UMA latency reporting. Called when an event is ack'ed
+ // to the RenderWidgetHost (from the InputRouter).
+ void OnInputEventAck(const blink::WebInputEvent& event,
+ ui::LatencyInfo* latency);
+
+ // Populates renderer-created LatencyInfo entries with the appropriate latency
+ // component id. Called when the RenderWidgetHost receives a compositor swap
+ // update from the renderer.
+ void OnSwapCompositorFrame(std::vector<ui::LatencyInfo>* latencies);
+
+ // Terminates latency tracking for events that triggered rendering, also
+ // performing relevant UMA latency reporting.
+ // Called when the RenderWidgetHost receives a swap update from the GPU.
+ void OnFrameSwapped(const ui::LatencyInfo& latency);
+
+ // Produces an estimate of the time between browser composite and GPU swap,
+ // as informed by historical latency values.
+ base::TimeDelta GetEstimatedBrowserCompositeTime() const;
+
+ // WebInputEvent coordinates are in DPIs, while LatencyInfo expects
+ // coordinates in device pixels.
+ void set_device_scale_factor(float device_scale_factor) {
+ device_scale_factor_ = device_scale_factor;
+ }
+
+ // Returns the ID that uniquely describes this component to the latency
+ // subsystem.
+ int64 latency_component_id() const { return latency_component_id_; }
+
+ private:
+ int64 last_event_id_;
+ int64 latency_component_id_;
+ float device_scale_factor_;
+ bool has_seent_first_gesture_scroll_update_;
+ cc::RollingTimeDeltaHistory browser_composite_latency_history_;
+
+ DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostLatencyTracker);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_RENDER_WIDGET_HOST_LATENCY_TRACKER_H_
diff --git a/chromium/content/browser/renderer_host/input/render_widget_host_latency_tracker_unittest.cc b/chromium/content/browser/renderer_host/input/render_widget_host_latency_tracker_unittest.cc
new file mode 100644
index 00000000000..3db83653a41
--- /dev/null
+++ b/chromium/content/browser/renderer_host/input/render_widget_host_latency_tracker_unittest.cc
@@ -0,0 +1,224 @@
+// Copyright 2014 The Chromium Authors. 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/render_widget_host_latency_tracker.h"
+#include "content/common/input/synthetic_web_input_event_builders.h"
+#include "content/public/browser/native_web_keyboard_event.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using blink::WebInputEvent;
+
+namespace content {
+namespace {
+
+const int kTestRoutingId = 3;
+const int kTestProcessId = 1;
+
+} // namespace
+
+TEST(RenderWidgetHostLatencyTrackerTest, Basic) {
+ RenderWidgetHostLatencyTracker tracker;
+ tracker.Initialize(kTestRoutingId, kTestProcessId);
+
+ {
+ auto scroll = SyntheticWebGestureEventBuilder::BuildScrollUpdate(
+ 5.f, -5.f, 0, blink::WebGestureDeviceTouchscreen);
+ scroll.timeStampSeconds =
+ (base::TimeTicks::Now() - base::TimeTicks()).InSecondsF();
+ ui::LatencyInfo scroll_latency;
+ tracker.OnInputEvent(scroll, &scroll_latency);
+ EXPECT_TRUE(
+ scroll_latency.FindLatency(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
+ tracker.latency_component_id(), nullptr));
+ EXPECT_TRUE(
+ scroll_latency.FindLatency(ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
+ 0, nullptr));
+ EXPECT_EQ(1U, scroll_latency.input_coordinates_size);
+ }
+
+ {
+ auto wheel = SyntheticWebMouseWheelEventBuilder::Build(
+ blink::WebMouseWheelEvent::PhaseChanged);
+ wheel.timeStampSeconds =
+ (base::TimeTicks::Now() - base::TimeTicks()).InSecondsF();
+ ui::LatencyInfo wheel_latency;
+ tracker.OnInputEvent(wheel, &wheel_latency);
+ EXPECT_TRUE(
+ wheel_latency.FindLatency(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
+ tracker.latency_component_id(), nullptr));
+ EXPECT_TRUE(
+ wheel_latency.FindLatency(ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
+ 0, nullptr));
+ EXPECT_EQ(1U, wheel_latency.input_coordinates_size);
+ }
+
+ {
+ SyntheticWebTouchEvent touch;
+ touch.PressPoint(0, 0);
+ touch.PressPoint(1, 1);
+ ui::LatencyInfo touch_latency;
+ tracker.OnInputEvent(touch, &touch_latency);
+ EXPECT_TRUE(
+ touch_latency.FindLatency(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
+ tracker.latency_component_id(), nullptr));
+ EXPECT_TRUE(
+ touch_latency.FindLatency(ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
+ 0, nullptr));
+ EXPECT_EQ(2U, touch_latency.input_coordinates_size);
+ }
+}
+
+TEST(RenderWidgetHostLatencyTrackerTest,
+ LatencyTerminatedOnAckIfRenderingNotScheduled) {
+ RenderWidgetHostLatencyTracker tracker;
+ tracker.Initialize(kTestRoutingId, kTestProcessId);
+
+ {
+ auto scroll = SyntheticWebGestureEventBuilder::BuildScrollBegin(5.f, -5.f);
+ ui::LatencyInfo scroll_latency;
+ tracker.OnInputEvent(scroll, &scroll_latency);
+ tracker.OnInputEventAck(scroll, &scroll_latency);
+ EXPECT_TRUE(scroll_latency.FindLatency(
+ ui::INPUT_EVENT_LATENCY_TERMINATED_GESTURE_COMPONENT, 0, nullptr));
+ EXPECT_TRUE(scroll_latency.terminated);
+ }
+
+ {
+ auto wheel = SyntheticWebMouseWheelEventBuilder::Build(
+ blink::WebMouseWheelEvent::PhaseChanged);
+ ui::LatencyInfo wheel_latency;
+ tracker.OnInputEvent(wheel, &wheel_latency);
+ tracker.OnInputEventAck(wheel, &wheel_latency);
+ EXPECT_TRUE(wheel_latency.FindLatency(
+ ui::INPUT_EVENT_LATENCY_TERMINATED_MOUSE_COMPONENT, 0, nullptr));
+ EXPECT_TRUE(wheel_latency.terminated);
+ }
+
+ {
+ SyntheticWebTouchEvent touch;
+ touch.PressPoint(0, 0);
+ ui::LatencyInfo touch_latency;
+ tracker.OnInputEvent(touch, &touch_latency);
+ tracker.OnInputEventAck(touch, &touch_latency);
+ EXPECT_TRUE(touch_latency.FindLatency(
+ ui::INPUT_EVENT_LATENCY_TERMINATED_TOUCH_COMPONENT, 0, nullptr));
+ EXPECT_TRUE(touch_latency.terminated);
+ }
+}
+
+TEST(RenderWidgetHostLatencyTrackerTest, InputCoordinatesPopulated) {
+ RenderWidgetHostLatencyTracker tracker;
+ tracker.Initialize(kTestRoutingId, kTestProcessId);
+
+ {
+ auto event = SyntheticWebMouseWheelEventBuilder::Build(-5, 0, 0, true);
+ event.x = 100;
+ event.y = 200;
+ ui::LatencyInfo latency_info;
+ tracker.OnInputEvent(event, &latency_info);
+ EXPECT_EQ(1u, latency_info.input_coordinates_size);
+ EXPECT_EQ(100, latency_info.input_coordinates[0].x);
+ EXPECT_EQ(200, latency_info.input_coordinates[0].y);
+ }
+
+ {
+ auto event = SyntheticWebMouseEventBuilder::Build(WebInputEvent::MouseMove);
+ event.x = 300;
+ event.y = 400;
+ ui::LatencyInfo latency_info;
+ tracker.OnInputEvent(event, &latency_info);
+ EXPECT_EQ(1u, latency_info.input_coordinates_size);
+ EXPECT_EQ(300, latency_info.input_coordinates[0].x);
+ EXPECT_EQ(400, latency_info.input_coordinates[0].y);
+ }
+
+ {
+ auto event = SyntheticWebGestureEventBuilder::Build(
+ WebInputEvent::GestureScrollBegin, blink::WebGestureDeviceTouchscreen);
+ event.x = 500;
+ event.y = 600;
+ ui::LatencyInfo latency_info;
+ tracker.OnInputEvent(event, &latency_info);
+ EXPECT_EQ(1u, latency_info.input_coordinates_size);
+ EXPECT_EQ(500, latency_info.input_coordinates[0].x);
+ EXPECT_EQ(600, latency_info.input_coordinates[0].y);
+ }
+
+ {
+ SyntheticWebTouchEvent event;
+ event.PressPoint(700, 800);
+ event.PressPoint(900, 1000);
+ event.PressPoint(1100, 1200); // LatencyInfo only holds two coordinates.
+ ui::LatencyInfo latency_info;
+ tracker.OnInputEvent(event, &latency_info);
+ EXPECT_EQ(2u, latency_info.input_coordinates_size);
+ EXPECT_EQ(700, latency_info.input_coordinates[0].x);
+ EXPECT_EQ(800, latency_info.input_coordinates[0].y);
+ EXPECT_EQ(900, latency_info.input_coordinates[1].x);
+ EXPECT_EQ(1000, latency_info.input_coordinates[1].y);
+ }
+
+ {
+ NativeWebKeyboardEvent event;
+ event.type = blink::WebKeyboardEvent::KeyDown;
+ ui::LatencyInfo latency_info;
+ tracker.OnInputEvent(event, &latency_info);
+ EXPECT_EQ(0u, latency_info.input_coordinates_size);
+ }
+}
+
+TEST(RenderWidgetHostLatencyTrackerTest, ScrollLatency) {
+ RenderWidgetHostLatencyTracker tracker;
+ tracker.Initialize(kTestRoutingId, kTestProcessId);
+
+ auto scroll_begin = SyntheticWebGestureEventBuilder::BuildScrollBegin(5, -5);
+ ui::LatencyInfo scroll_latency;
+ scroll_latency.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0,
+ 0);
+ tracker.OnInputEvent(scroll_begin, &scroll_latency);
+ EXPECT_TRUE(
+ scroll_latency.FindLatency(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
+ tracker.latency_component_id(), nullptr));
+ EXPECT_EQ(2U, scroll_latency.latency_components.size());
+
+ // The first GestureScrollUpdate should be provided with
+ // INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT.
+ auto first_scroll_update = SyntheticWebGestureEventBuilder::BuildScrollUpdate(
+ 5.f, -5.f, 0, blink::WebGestureDeviceTouchscreen);
+ scroll_latency = ui::LatencyInfo();
+ scroll_latency.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0,
+ 0);
+ tracker.OnInputEvent(first_scroll_update, &scroll_latency);
+ EXPECT_TRUE(
+ scroll_latency.FindLatency(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
+ tracker.latency_component_id(), nullptr));
+ EXPECT_TRUE(scroll_latency.FindLatency(
+ ui::INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT,
+ tracker.latency_component_id(), nullptr));
+ EXPECT_FALSE(scroll_latency.FindLatency(
+ ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT,
+ tracker.latency_component_id(), nullptr));
+ EXPECT_EQ(3U, scroll_latency.latency_components.size());
+
+ // Subseqeunt GestureScrollUpdates should be provided with
+ // INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT.
+ auto scroll_update = SyntheticWebGestureEventBuilder::BuildScrollUpdate(
+ -5.f, 5.f, 0, blink::WebGestureDeviceTouchscreen);
+ scroll_latency = ui::LatencyInfo();
+ scroll_latency.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0,
+ 0);
+ tracker.OnInputEvent(scroll_update, &scroll_latency);
+ EXPECT_TRUE(
+ scroll_latency.FindLatency(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
+ tracker.latency_component_id(), nullptr));
+ EXPECT_FALSE(scroll_latency.FindLatency(
+ ui::INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT,
+ tracker.latency_component_id(), nullptr));
+ EXPECT_TRUE(scroll_latency.FindLatency(
+ ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT,
+ tracker.latency_component_id(), nullptr));
+ EXPECT_EQ(3U, scroll_latency.latency_components.size());
+}
+
+} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/selection_event_type.h b/chromium/content/browser/renderer_host/input/selection_event_type.h
deleted file mode 100644
index 567259f0496..00000000000
--- a/chromium/content/browser/renderer_host/input/selection_event_type.h
+++ /dev/null
@@ -1,29 +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_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/stylus_text_selector.cc b/chromium/content/browser/renderer_host/input/stylus_text_selector.cc
new file mode 100644
index 00000000000..b226dec4142
--- /dev/null
+++ b/chromium/content/browser/renderer_host/input/stylus_text_selector.cc
@@ -0,0 +1,141 @@
+// Copyright 2014 The Chromium Authors. 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/stylus_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::GetGestureProviderConfig(
+ ui::GestureProviderConfigType::CURRENT_PLATFORM)
+ .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
+
+StylusTextSelector::StylusTextSelector(StylusTextSelectorClient* client)
+ : client_(client),
+ text_selection_triggered_(false),
+ secondary_button_pressed_(false),
+ dragging_(false),
+ dragged_(false),
+ anchor_x_(0.0f),
+ anchor_y_(0.0f) {
+ DCHECK(client);
+}
+
+StylusTextSelector::~StylusTextSelector() {
+}
+
+bool StylusTextSelector::OnTouchEvent(const MotionEvent& event) {
+ // Only trigger selection on ACTION_DOWN to prevent partial touch or gesture
+ // sequences from being forwarded.
+ if (event.GetAction() == MotionEvent::ACTION_DOWN)
+ text_selection_triggered_ = ShouldStartTextSelection(event);
+
+ if (!text_selection_triggered_)
+ return false;
+
+ secondary_button_pressed_ =
+ event.GetButtonState() == MotionEvent::BUTTON_SECONDARY;
+
+ switch (event.GetAction()) {
+ case MotionEvent::ACTION_DOWN:
+ dragging_ = false;
+ dragged_ = false;
+ anchor_x_ = event.GetX();
+ anchor_y_ = event.GetY();
+ break;
+
+ case MotionEvent::ACTION_MOVE:
+ if (!secondary_button_pressed_) {
+ dragging_ = false;
+ anchor_x_ = event.GetX();
+ anchor_y_ = event.GetY();
+ }
+ break;
+
+ case MotionEvent::ACTION_UP:
+ case MotionEvent::ACTION_CANCEL:
+ if (dragged_)
+ client_->OnStylusSelectEnd();
+ dragged_ = false;
+ dragging_ = false;
+ break;
+
+ case MotionEvent::ACTION_POINTER_UP:
+ case MotionEvent::ACTION_POINTER_DOWN:
+ break;
+ }
+
+ if (!gesture_detector_)
+ gesture_detector_ = CreateGestureDetector(this);
+
+ gesture_detector_->OnTouchEvent(event);
+
+ // Always return true, even if |gesture_detector_| technically doesn't
+ // consume the event. This prevents forwarding of a partial touch stream.
+ return true;
+}
+
+bool StylusTextSelector::OnSingleTapUp(const MotionEvent& e) {
+ DCHECK(text_selection_triggered_);
+ DCHECK(!dragging_);
+ client_->OnStylusSelectTap(e.GetEventTime(), e.GetX(), e.GetY());
+ return true;
+}
+
+bool StylusTextSelector::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;
+
+ if (!dragging_) {
+ dragging_ = true;
+ dragged_ = true;
+ client_->OnStylusSelectBegin(anchor_x_, anchor_y_, e2.GetX(), e2.GetY());
+ } else {
+ client_->OnStylusSelectUpdate(e2.GetX(), e2.GetY());
+ }
+
+ return true;
+}
+
+// static
+bool StylusTextSelector::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/stylus_text_selector.h b/chromium/content/browser/renderer_host/input/stylus_text_selector.h
new file mode 100644
index 00000000000..163a7e966ee
--- /dev/null
+++ b/chromium/content/browser/renderer_host/input/stylus_text_selector.h
@@ -0,0 +1,78 @@
+// Copyright 2014 The Chromium Authors. 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_STYLUS_TEXT_SELECTOR_H_
+#define CONTENT_BROWSER_RENDERER_HOST_INPUT_STYLUS_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 StylusTextSelectorTest;
+
+// Interface with which the StylusTextSelector conveys drag and tap gestures
+// when the activating button is pressed.
+// selection handles, or long press.
+class CONTENT_EXPORT StylusTextSelectorClient {
+ public:
+ virtual ~StylusTextSelectorClient() {}
+
+ // (x0, y0) and (x1, y1) indicate the bounds of the initial selection.
+ virtual void OnStylusSelectBegin(float x0, float y0, float x1, float y1) = 0;
+ virtual void OnStylusSelectUpdate(float x, float y) = 0;
+ virtual void OnStylusSelectEnd() = 0;
+ virtual void OnStylusSelectTap(base::TimeTicks time, float x, float y) = 0;
+};
+
+// Provides stylus-based text selection and interaction, including:
+// * Selection manipulation when an activating stylus button is pressed and
+// the stylus is dragged.
+// * Word selection and context menu activation when the when an activating
+// stylus button is pressed and the stylus is tapped.
+class CONTENT_EXPORT StylusTextSelector : public ui::SimpleGestureListener {
+ public:
+ explicit StylusTextSelector(StylusTextSelectorClient* client);
+ ~StylusTextSelector() 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 StylusTextSelectorTest;
+ FRIEND_TEST_ALL_PREFIXES(StylusTextSelectorTest, 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);
+
+ StylusTextSelectorClient* client_;
+ bool text_selection_triggered_;
+ bool secondary_button_pressed_;
+ bool dragging_;
+ bool dragged_;
+ float anchor_x_;
+ float anchor_y_;
+ scoped_ptr<ui::GestureDetector> gesture_detector_;
+
+ DISALLOW_COPY_AND_ASSIGN(StylusTextSelector);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_STYLUS_TEXT_SELECTOR_H_
diff --git a/chromium/content/browser/renderer_host/input/stylus_text_selector_unittest.cc b/chromium/content/browser/renderer_host/input/stylus_text_selector_unittest.cc
new file mode 100644
index 00000000000..1c8e5105bcd
--- /dev/null
+++ b/chromium/content/browser/renderer_host/input/stylus_text_selector_unittest.cc
@@ -0,0 +1,247 @@
+// Copyright 2014 The Chromium Authors. 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/stylus_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 StylusTextSelectorTest : public testing::Test,
+ public StylusTextSelectorClient {
+ public:
+ StylusTextSelectorTest() {}
+ ~StylusTextSelectorTest() override {}
+
+ // Test implementation.
+ void SetUp() override {
+ selector_.reset(new StylusTextSelector(this));
+ event_log_.clear();
+ }
+
+ void TearDown() override {
+ selector_.reset();
+ event_log_.clear();
+ }
+
+ // StylusTextSelectorClient implementation.
+ void OnStylusSelectBegin(float x0, float y0, float x1, float y1) override {
+ std::stringstream ss;
+ ss << "Begin(" << x0 << ", " << y0 << ", " << x1 << ", " << y1 << ")";
+ event_log_.push_back(ss.str());
+ }
+
+ void OnStylusSelectUpdate(float x, float y) override {
+ std::stringstream ss;
+ ss << "Update(" << x << ", " << y << ")";
+ event_log_.push_back(ss.str());
+ }
+
+ void OnStylusSelectEnd() override { event_log_.push_back("End"); }
+
+ void OnStylusSelectTap(base::TimeTicks time, float x, float y) override {
+ event_log_.push_back("Tap");
+ }
+
+ protected:
+ scoped_ptr<StylusTextSelector> selector_;
+ std::vector<std::string> event_log_;
+};
+
+TEST_F(StylusTextSelectorTest, 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(StylusTextSelectorTest, 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(StylusTextSelectorTest, 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;
+ const float x3 = 150.0f;
+ const float y3 = 150.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(1u, event_log_.size());
+ EXPECT_STREQ("Begin(50, 30, 100, 90)", event_log_.back().c_str());
+
+ event_time += base::TimeDelta::FromMilliseconds(10);
+ action_move = MockMotionEvent(MotionEvent::ACTION_MOVE, event_time, x3, y3);
+ 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("Update(150, 150)", event_log_.back().c_str());
+
+ // 3. ACTION_UP
+ event_time += base::TimeDelta::FromMilliseconds(10);
+ MockMotionEvent action_up(MotionEvent::ACTION_UP, event_time, x3, y3);
+ action_up.SetToolType(0, MotionEvent::TOOL_TYPE_STYLUS);
+ action_up.set_button_state(0);
+ EXPECT_TRUE(selector_->OnTouchEvent(action_up));
+ ASSERT_EQ(3u, event_log_.size()); // NO CHANGE
+ EXPECT_STREQ("End", event_log_.back().c_str());
+}
+
+TEST_F(StylusTextSelectorTest, 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(1u, event_log_.size());
+ EXPECT_STREQ("Begin(50, 30, 70, 50)", event_log_.back().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(1u, event_log_.size()); // NO CHANGE
+
+ // 4. ACTION_MOVE with stylus + button pressed again
+ // Note that the end action is deferred until the stylus is lifted.
+ 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(2u, event_log_.size());
+ EXPECT_STREQ("Begin(90, 70, 110, 90)", event_log_.back().c_str());
+
+ // 5. ACTION_MOVE with stylus + no button
+ event_time += base::TimeDelta::FromMilliseconds(10);
+ x += 20; // 130
+ y += 20; // 110
+ action_move = MockMotionEvent(MotionEvent::ACTION_MOVE, event_time, x, y);
+ action_move.SetToolType(0, MotionEvent::TOOL_TYPE_STYLUS);
+ EXPECT_TRUE(selector_->OnTouchEvent(action_move));
+ EXPECT_EQ(2u, event_log_.size()); // NO CHANGE
+
+ // 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(3u, event_log_.size());
+ EXPECT_STREQ("End", event_log_.back().c_str());
+}
+
+TEST_F(StylusTextSelectorTest, 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("Tap", event_log_.back().c_str());
+}
+
+} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/synthetic_gesture.cc b/chromium/content/browser/renderer_host/input/synthetic_gesture.cc
index bc887e1dfe2..2e25288dc13 100644
--- a/chromium/content/browser/renderer_host/input/synthetic_gesture.cc
+++ b/chromium/content/browser/renderer_host/input/synthetic_gesture.cc
@@ -7,6 +7,7 @@
#include "base/logging.h"
#include "content/browser/renderer_host/input/synthetic_gesture_target.h"
#include "content/browser/renderer_host/input/synthetic_pinch_gesture.h"
+#include "content/browser/renderer_host/input/synthetic_smooth_drag_gesture.h"
#include "content/browser/renderer_host/input/synthetic_smooth_scroll_gesture.h"
#include "content/browser/renderer_host/input/synthetic_tap_gesture.h"
@@ -32,6 +33,9 @@ scoped_ptr<SyntheticGesture> SyntheticGesture::Create(
case SyntheticGestureParams::SMOOTH_SCROLL_GESTURE:
return CreateGesture<SyntheticSmoothScrollGesture,
SyntheticSmoothScrollGestureParams>(gesture_params);
+ case SyntheticGestureParams::SMOOTH_DRAG_GESTURE:
+ return CreateGesture<SyntheticSmoothDragGesture,
+ SyntheticSmoothDragGestureParams>(gesture_params);
case SyntheticGestureParams::PINCH_GESTURE:
return CreateGesture<SyntheticPinchGesture,
SyntheticPinchGestureParams>(gesture_params);
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 6e5e20fb22a..536426b71db 100644
--- a/chromium/content/browser/renderer_host/input/synthetic_gesture_controller.cc
+++ b/chromium/content/browser/renderer_host/input/synthetic_gesture_controller.cc
@@ -4,7 +4,7 @@
#include "content/browser/renderer_host/input/synthetic_gesture_controller.h"
-#include "base/debug/trace_event.h"
+#include "base/trace_event/trace_event.h"
#include "content/browser/renderer_host/input/synthetic_gesture_target.h"
#include "content/common/input/synthetic_smooth_scroll_gesture_params.h"
#include "content/common/input_messages.h"
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 8c08361e7d0..5d84b4b48fc 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
@@ -9,10 +9,13 @@
#include "content/browser/renderer_host/input/synthetic_gesture_controller.h"
#include "content/browser/renderer_host/input/synthetic_gesture_target.h"
#include "content/browser/renderer_host/input/synthetic_pinch_gesture.h"
+#include "content/browser/renderer_host/input/synthetic_smooth_drag_gesture.h"
+#include "content/browser/renderer_host/input/synthetic_smooth_move_gesture.h"
#include "content/browser/renderer_host/input/synthetic_smooth_scroll_gesture.h"
#include "content/browser/renderer_host/input/synthetic_tap_gesture.h"
#include "content/browser/renderer_host/render_widget_host_delegate.h"
#include "content/common/input/synthetic_pinch_gesture_params.h"
+#include "content/common/input/synthetic_smooth_drag_gesture_params.h"
#include "content/common/input/synthetic_smooth_scroll_gesture_params.h"
#include "content/common/input/synthetic_tap_gesture_params.h"
#include "content/public/test/mock_render_process_host.h"
@@ -20,10 +23,10 @@
#include "content/test/test_render_view_host.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
-#include "ui/gfx/point.h"
-#include "ui/gfx/point_f.h"
-#include "ui/gfx/vector2d.h"
-#include "ui/gfx/vector2d_f.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/geometry/vector2d.h"
+#include "ui/gfx/geometry/vector2d_f.h"
using blink::WebInputEvent;
using blink::WebMouseEvent;
@@ -39,6 +42,8 @@ const int kPointerAssumedStoppedTimeMs = 43;
const float kTouchSlopInDips = 7.0f;
const float kMinScalingSpanInDips = 27.5f;
+enum TouchGestureType { TOUCH_SCROLL, TOUCH_DRAG };
+
class MockSyntheticGesture : public SyntheticGesture {
public:
MockSyntheticGesture(bool* finished, int num_steps)
@@ -110,24 +115,24 @@ class MockSyntheticGestureTarget : public SyntheticGestureTarget {
int pointer_assumed_stopped_time_ms_;
};
-class MockScrollGestureTarget : public MockSyntheticGestureTarget {
+class MockMoveGestureTarget : public MockSyntheticGestureTarget {
public:
- MockScrollGestureTarget() : total_abs_scroll_distance_length_(0) {}
- ~MockScrollGestureTarget() override {}
+ MockMoveGestureTarget() : total_abs_move_distance_length_(0) {}
+ ~MockMoveGestureTarget() override {}
gfx::Vector2dF start_to_end_distance() const {
return start_to_end_distance_;
}
- float total_abs_scroll_distance_length() const {
- return total_abs_scroll_distance_length_;
+ float total_abs_move_distance_length() const {
+ return total_abs_move_distance_length_;
}
protected:
gfx::Vector2dF start_to_end_distance_;
- float total_abs_scroll_distance_length_;
+ float total_abs_move_distance_length_;
};
-class MockScrollMouseTarget : public MockScrollGestureTarget {
+class MockScrollMouseTarget : public MockMoveGestureTarget {
public:
MockScrollMouseTarget() {}
~MockScrollMouseTarget() override {}
@@ -138,14 +143,14 @@ class MockScrollMouseTarget : public MockScrollGestureTarget {
static_cast<const WebMouseWheelEvent&>(event);
gfx::Vector2dF delta(mouse_wheel_event.deltaX, mouse_wheel_event.deltaY);
start_to_end_distance_ += delta;
- total_abs_scroll_distance_length_ += delta.Length();
+ total_abs_move_distance_length_ += delta.Length();
}
};
-class MockScrollTouchTarget : public MockScrollGestureTarget {
+class MockMoveTouchTarget : public MockMoveGestureTarget {
public:
- MockScrollTouchTarget() : started_(false) {}
- ~MockScrollTouchTarget() override {}
+ MockMoveTouchTarget() : started_(false) {}
+ ~MockMoveTouchTarget() override {}
void DispatchInputEventToPlatform(const WebInputEvent& event) override {
ASSERT_TRUE(WebInputEvent::isTouchEventType(event.type));
@@ -165,7 +170,7 @@ class MockScrollTouchTarget : public MockScrollGestureTarget {
gfx::PointF touch_point(touch_event.touches[0].position.x,
touch_event.touches[0].position.y);
gfx::Vector2dF delta = touch_point - last_touch_point_;
- total_abs_scroll_distance_length_ += delta.Length();
+ total_abs_move_distance_length_ += delta.Length();
if (touch_event.type == WebInputEvent::TouchEnd)
start_to_end_distance_ = touch_point - start_;
@@ -180,6 +185,39 @@ class MockScrollTouchTarget : public MockScrollGestureTarget {
bool started_;
};
+class MockDragMouseTarget : public MockMoveGestureTarget {
+ public:
+ MockDragMouseTarget() : started_(false) {}
+ ~MockDragMouseTarget() override {}
+
+ void DispatchInputEventToPlatform(const WebInputEvent& event) override {
+ ASSERT_TRUE(WebInputEvent::isMouseEventType(event.type));
+ const WebMouseEvent& mouse_event = static_cast<const WebMouseEvent&>(event);
+ if (!started_) {
+ EXPECT_EQ(mouse_event.button, WebMouseEvent::ButtonLeft);
+ EXPECT_EQ(mouse_event.clickCount, 1);
+ EXPECT_EQ(mouse_event.type, WebInputEvent::MouseDown);
+ start_.SetPoint(mouse_event.x, mouse_event.y);
+ last_mouse_point_ = start_;
+ started_ = true;
+ } else {
+ EXPECT_EQ(mouse_event.button, WebMouseEvent::ButtonLeft);
+ ASSERT_NE(mouse_event.type, WebInputEvent::MouseDown);
+
+ gfx::PointF mouse_point(mouse_event.x, mouse_event.y);
+ gfx::Vector2dF delta = mouse_point - last_mouse_point_;
+ total_abs_move_distance_length_ += delta.Length();
+ if (mouse_event.type == WebInputEvent::MouseUp)
+ start_to_end_distance_ = mouse_point - start_;
+ last_mouse_point_ = mouse_point;
+ }
+ }
+
+ private:
+ bool started_;
+ gfx::PointF start_, last_mouse_point_;
+};
+
class MockSyntheticPinchTouchTarget : public MockSyntheticGestureTarget {
public:
enum ZoomDirection {
@@ -356,10 +394,10 @@ class MockSyntheticTapMouseTarget : public MockSyntheticTapGestureTarget {
}
};
-class SyntheticGestureControllerTest : public testing::Test {
+class SyntheticGestureControllerTestBase {
public:
- SyntheticGestureControllerTest() {}
- ~SyntheticGestureControllerTest() override {}
+ SyntheticGestureControllerTestBase() {}
+ ~SyntheticGestureControllerTestBase() {}
protected:
template<typename MockGestureTarget>
@@ -369,22 +407,11 @@ class SyntheticGestureControllerTest : public testing::Test {
scoped_ptr<SyntheticGestureTarget>(target_)));
}
- void SetUp() override {
- start_time_ = base::TimeTicks::Now();
- time_ = start_time_;
- num_success_ = 0;
- num_failure_ = 0;
- }
-
- void TearDown() override {
- controller_.reset();
- target_ = NULL;
- time_ = base::TimeTicks();
- }
-
void QueueSyntheticGesture(scoped_ptr<SyntheticGesture> gesture) {
- controller_->QueueSyntheticGesture(gesture.Pass(),
- base::Bind(&SyntheticGestureControllerTest::OnSyntheticGestureCompleted,
+ controller_->QueueSyntheticGesture(
+ gesture.Pass(),
+ base::Bind(
+ &SyntheticGestureControllerTestBase::OnSyntheticGestureCompleted,
base::Unretained(this)));
}
@@ -417,6 +444,42 @@ class SyntheticGestureControllerTest : public testing::Test {
int num_failure_;
};
+class SyntheticGestureControllerTest
+ : public SyntheticGestureControllerTestBase,
+ public testing::Test {
+ protected:
+ void SetUp() override {
+ start_time_ = base::TimeTicks::Now();
+ time_ = start_time_;
+ num_success_ = 0;
+ num_failure_ = 0;
+ }
+
+ void TearDown() override {
+ controller_.reset();
+ target_ = nullptr;
+ time_ = base::TimeTicks();
+ }
+};
+
+class SyntheticGestureControllerTestWithParam
+ : public SyntheticGestureControllerTestBase,
+ public testing::TestWithParam<bool> {
+ protected:
+ void SetUp() override {
+ start_time_ = base::TimeTicks::Now();
+ time_ = start_time_;
+ num_success_ = 0;
+ num_failure_ = 0;
+ }
+
+ void TearDown() override {
+ controller_.reset();
+ target_ = nullptr;
+ time_ = base::TimeTicks();
+ }
+};
+
TEST_F(SyntheticGestureControllerTest, SingleGesture) {
CreateControllerAndTarget<MockSyntheticGestureTarget>();
@@ -524,7 +587,7 @@ TEST_F(SyntheticGestureControllerTest, GestureCompletedOnDidFlushInput) {
EXPECT_EQ(2, num_success_);
}
-gfx::Vector2d AddTouchSlopToVector(const gfx::Vector2d& vector,
+gfx::Vector2d AddTouchSlopToVector(const gfx::Vector2dF& vector,
SyntheticGestureTarget* target) {
const int kTouchSlop = target->GetTouchSlopInDips();
@@ -543,46 +606,62 @@ gfx::Vector2d AddTouchSlopToVector(const gfx::Vector2d& vector,
return gfx::Vector2d(x, y);
}
-TEST_F(SyntheticGestureControllerTest, SingleScrollGestureTouchVertical) {
- CreateControllerAndTarget<MockScrollTouchTarget>();
+TEST_P(SyntheticGestureControllerTestWithParam,
+ SingleMoveGestureTouchVertical) {
+ CreateControllerAndTarget<MockMoveTouchTarget>();
- SyntheticSmoothScrollGestureParams params;
- params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT;
- params.anchor.SetPoint(89, 32);
+ SyntheticSmoothMoveGestureParams params;
+ params.input_type = SyntheticSmoothMoveGestureParams::TOUCH_INPUT;
+ if (GetParam() == TOUCH_DRAG) {
+ params.add_slop = false;
+ }
+ params.start_point.SetPoint(89, 32);
params.distances.push_back(gfx::Vector2d(0, 123));
- scoped_ptr<SyntheticSmoothScrollGesture> gesture(
- new SyntheticSmoothScrollGesture(params));
+ scoped_ptr<SyntheticSmoothMoveGesture> gesture(
+ new SyntheticSmoothMoveGesture(params));
QueueSyntheticGesture(gesture.Pass());
FlushInputUntilComplete();
- MockScrollGestureTarget* scroll_target =
- static_cast<MockScrollGestureTarget*>(target_);
+ MockMoveGestureTarget* scroll_target =
+ static_cast<MockMoveGestureTarget*>(target_);
EXPECT_EQ(1, num_success_);
EXPECT_EQ(0, num_failure_);
- EXPECT_EQ(AddTouchSlopToVector(params.distances[0], target_),
- scroll_target->start_to_end_distance());
+ if (GetParam() == TOUCH_SCROLL) {
+ EXPECT_EQ(AddTouchSlopToVector(params.distances[0], target_),
+ scroll_target->start_to_end_distance());
+ } else {
+ EXPECT_EQ(params.distances[0], scroll_target->start_to_end_distance());
+ }
}
-TEST_F(SyntheticGestureControllerTest, SingleScrollGestureTouchHorizontal) {
- CreateControllerAndTarget<MockScrollTouchTarget>();
+TEST_P(SyntheticGestureControllerTestWithParam,
+ SingleScrollGestureTouchHorizontal) {
+ CreateControllerAndTarget<MockMoveTouchTarget>();
- SyntheticSmoothScrollGestureParams params;
- params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT;
- params.anchor.SetPoint(12, -23);
+ SyntheticSmoothMoveGestureParams params;
+ params.input_type = SyntheticSmoothMoveGestureParams::TOUCH_INPUT;
+ if (GetParam() == TOUCH_DRAG) {
+ params.add_slop = false;
+ }
+ params.start_point.SetPoint(12, -23);
params.distances.push_back(gfx::Vector2d(-234, 0));
- scoped_ptr<SyntheticSmoothScrollGesture> gesture(
- new SyntheticSmoothScrollGesture(params));
+ scoped_ptr<SyntheticSmoothMoveGesture> gesture(
+ new SyntheticSmoothMoveGesture(params));
QueueSyntheticGesture(gesture.Pass());
FlushInputUntilComplete();
- MockScrollGestureTarget* scroll_target =
- static_cast<MockScrollGestureTarget*>(target_);
+ MockMoveGestureTarget* scroll_target =
+ static_cast<MockMoveGestureTarget*>(target_);
EXPECT_EQ(1, num_success_);
EXPECT_EQ(0, num_failure_);
- EXPECT_EQ(AddTouchSlopToVector(params.distances[0], target_),
- scroll_target->start_to_end_distance());
+ if (GetParam() == TOUCH_SCROLL) {
+ EXPECT_EQ(AddTouchSlopToVector(params.distances[0], target_),
+ scroll_target->start_to_end_distance());
+ } else {
+ EXPECT_EQ(params.distances[0], scroll_target->start_to_end_distance());
+ }
}
void CheckIsWithinRangeSingle(float scroll_distance,
@@ -599,27 +678,27 @@ void CheckIsWithinRangeSingle(float scroll_distance,
void CheckSingleScrollDistanceIsWithinRange(
const gfx::Vector2dF& scroll_distance,
- const gfx::Vector2d& target_distance,
+ const gfx::Vector2dF& target_distance,
SyntheticGestureTarget* target) {
CheckIsWithinRangeSingle(scroll_distance.x(), target_distance.x(), target);
CheckIsWithinRangeSingle(scroll_distance.y(), target_distance.y(), target);
}
TEST_F(SyntheticGestureControllerTest, SingleScrollGestureTouchDiagonal) {
- CreateControllerAndTarget<MockScrollTouchTarget>();
+ CreateControllerAndTarget<MockMoveTouchTarget>();
- SyntheticSmoothScrollGestureParams params;
- params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT;
- params.anchor.SetPoint(0, 7);
+ SyntheticSmoothMoveGestureParams params;
+ params.input_type = SyntheticSmoothMoveGestureParams::TOUCH_INPUT;
+ params.start_point.SetPoint(0, 7);
params.distances.push_back(gfx::Vector2d(413, -83));
- scoped_ptr<SyntheticSmoothScrollGesture> gesture(
- new SyntheticSmoothScrollGesture(params));
+ scoped_ptr<SyntheticSmoothMoveGesture> gesture(
+ new SyntheticSmoothMoveGesture(params));
QueueSyntheticGesture(gesture.Pass());
FlushInputUntilComplete();
- MockScrollGestureTarget* scroll_target =
- static_cast<MockScrollGestureTarget*>(target_);
+ MockMoveGestureTarget* scroll_target =
+ static_cast<MockMoveGestureTarget*>(target_);
EXPECT_EQ(1, num_success_);
EXPECT_EQ(0, num_failure_);
CheckSingleScrollDistanceIsWithinRange(
@@ -627,26 +706,25 @@ TEST_F(SyntheticGestureControllerTest, SingleScrollGestureTouchDiagonal) {
}
TEST_F(SyntheticGestureControllerTest, SingleScrollGestureTouchLongStop) {
- CreateControllerAndTarget<MockScrollTouchTarget>();
+ CreateControllerAndTarget<MockMoveTouchTarget>();
// Create a smooth scroll with a short distance and set the pointer assumed
// stopped time high, so that the stopping should dominate the time the
// gesture is active.
- SyntheticSmoothScrollGestureParams params;
- params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT;
- params.anchor.SetPoint(-98, -23);
+ SyntheticSmoothMoveGestureParams params;
+ params.input_type = SyntheticSmoothMoveGestureParams::TOUCH_INPUT;
+ params.start_point.SetPoint(-98, -23);
params.distances.push_back(gfx::Vector2d(21, -12));
params.prevent_fling = true;
-
target_->set_pointer_assumed_stopped_time_ms(543);
- scoped_ptr<SyntheticSmoothScrollGesture> gesture(
- new SyntheticSmoothScrollGesture(params));
+ scoped_ptr<SyntheticSmoothMoveGesture> gesture(
+ new SyntheticSmoothMoveGesture(params));
QueueSyntheticGesture(gesture.Pass());
FlushInputUntilComplete();
- MockScrollGestureTarget* scroll_target =
- static_cast<MockScrollGestureTarget*>(target_);
+ MockMoveGestureTarget* scroll_target =
+ static_cast<MockMoveGestureTarget*>(target_);
EXPECT_EQ(1, num_success_);
EXPECT_EQ(0, num_failure_);
CheckSingleScrollDistanceIsWithinRange(
@@ -655,26 +733,26 @@ TEST_F(SyntheticGestureControllerTest, SingleScrollGestureTouchLongStop) {
}
TEST_F(SyntheticGestureControllerTest, SingleScrollGestureTouchFling) {
- CreateControllerAndTarget<MockScrollTouchTarget>();
+ CreateControllerAndTarget<MockMoveTouchTarget>();
// Create a smooth scroll with a short distance and set the pointer assumed
// stopped time high. Disable 'prevent_fling' and check that the gesture
// finishes without waiting before it stops.
- SyntheticSmoothScrollGestureParams params;
- params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT;
- params.anchor.SetPoint(-89, 78);
+ SyntheticSmoothMoveGestureParams params;
+ params.input_type = SyntheticSmoothMoveGestureParams::TOUCH_INPUT;
+ params.start_point.SetPoint(-89, 78);
params.distances.push_back(gfx::Vector2d(-43, 19));
params.prevent_fling = false;
target_->set_pointer_assumed_stopped_time_ms(543);
- scoped_ptr<SyntheticSmoothScrollGesture> gesture(
- new SyntheticSmoothScrollGesture(params));
+ scoped_ptr<SyntheticSmoothMoveGesture> gesture(
+ new SyntheticSmoothMoveGesture(params));
QueueSyntheticGesture(gesture.Pass());
FlushInputUntilComplete();
- MockScrollGestureTarget* scroll_target =
- static_cast<MockScrollGestureTarget*>(target_);
+ MockMoveGestureTarget* scroll_target =
+ static_cast<MockMoveGestureTarget*>(target_);
EXPECT_EQ(1, num_success_);
EXPECT_EQ(0, num_failure_);
CheckSingleScrollDistanceIsWithinRange(
@@ -682,21 +760,25 @@ TEST_F(SyntheticGestureControllerTest, SingleScrollGestureTouchFling) {
EXPECT_LE(GetTotalTime(), target_->PointerAssumedStoppedTime());
}
-TEST_F(SyntheticGestureControllerTest, SingleScrollGestureTouchZeroDistance) {
- CreateControllerAndTarget<MockScrollTouchTarget>();
+TEST_P(SyntheticGestureControllerTestWithParam,
+ SingleScrollGestureTouchZeroDistance) {
+ CreateControllerAndTarget<MockMoveTouchTarget>();
- SyntheticSmoothScrollGestureParams params;
- params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT;
- params.anchor.SetPoint(-32, 43);
+ SyntheticSmoothMoveGestureParams params;
+ params.input_type = SyntheticSmoothMoveGestureParams::TOUCH_INPUT;
+ if (GetParam() == TOUCH_DRAG) {
+ params.add_slop = false;
+ }
+ params.start_point.SetPoint(-32, 43);
params.distances.push_back(gfx::Vector2d(0, 0));
- scoped_ptr<SyntheticSmoothScrollGesture> gesture(
- new SyntheticSmoothScrollGesture(params));
+ scoped_ptr<SyntheticSmoothMoveGesture> gesture(
+ new SyntheticSmoothMoveGesture(params));
QueueSyntheticGesture(gesture.Pass());
FlushInputUntilComplete();
- MockScrollGestureTarget* scroll_target =
- static_cast<MockScrollGestureTarget*>(target_);
+ MockMoveGestureTarget* scroll_target =
+ static_cast<MockMoveGestureTarget*>(target_);
EXPECT_EQ(1, num_success_);
EXPECT_EQ(0, num_failure_);
EXPECT_EQ(gfx::Vector2dF(0, 0), scroll_target->start_to_end_distance());
@@ -705,18 +787,18 @@ TEST_F(SyntheticGestureControllerTest, SingleScrollGestureTouchZeroDistance) {
TEST_F(SyntheticGestureControllerTest, SingleScrollGestureMouseVertical) {
CreateControllerAndTarget<MockScrollMouseTarget>();
- SyntheticSmoothScrollGestureParams params;
- params.gesture_source_type = SyntheticGestureParams::MOUSE_INPUT;
- params.anchor.SetPoint(432, 89);
+ SyntheticSmoothMoveGestureParams params;
+ params.input_type = SyntheticSmoothMoveGestureParams::MOUSE_WHEEL_INPUT;
+ params.start_point.SetPoint(432, 89);
params.distances.push_back(gfx::Vector2d(0, -234));
- scoped_ptr<SyntheticSmoothScrollGesture> gesture(
- new SyntheticSmoothScrollGesture(params));
+ scoped_ptr<SyntheticSmoothMoveGesture> gesture(
+ new SyntheticSmoothMoveGesture(params));
QueueSyntheticGesture(gesture.Pass());
FlushInputUntilComplete();
- MockScrollGestureTarget* scroll_target =
- static_cast<MockScrollGestureTarget*>(target_);
+ MockMoveGestureTarget* scroll_target =
+ static_cast<MockMoveGestureTarget*>(target_);
EXPECT_EQ(1, num_success_);
EXPECT_EQ(0, num_failure_);
EXPECT_EQ(params.distances[0], scroll_target->start_to_end_distance());
@@ -725,18 +807,18 @@ TEST_F(SyntheticGestureControllerTest, SingleScrollGestureMouseVertical) {
TEST_F(SyntheticGestureControllerTest, SingleScrollGestureMouseHorizontal) {
CreateControllerAndTarget<MockScrollMouseTarget>();
- SyntheticSmoothScrollGestureParams params;
- params.gesture_source_type = SyntheticGestureParams::MOUSE_INPUT;
- params.anchor.SetPoint(90, 12);
+ SyntheticSmoothMoveGestureParams params;
+ params.input_type = SyntheticSmoothMoveGestureParams::MOUSE_WHEEL_INPUT;
+ params.start_point.SetPoint(90, 12);
params.distances.push_back(gfx::Vector2d(345, 0));
- scoped_ptr<SyntheticSmoothScrollGesture> gesture(
- new SyntheticSmoothScrollGesture(params));
+ scoped_ptr<SyntheticSmoothMoveGesture> gesture(
+ new SyntheticSmoothMoveGesture(params));
QueueSyntheticGesture(gesture.Pass());
FlushInputUntilComplete();
- MockScrollGestureTarget* scroll_target =
- static_cast<MockScrollGestureTarget*>(target_);
+ MockMoveGestureTarget* scroll_target =
+ static_cast<MockMoveGestureTarget*>(target_);
EXPECT_EQ(1, num_success_);
EXPECT_EQ(0, num_failure_);
EXPECT_EQ(params.distances[0], scroll_target->start_to_end_distance());
@@ -745,18 +827,18 @@ TEST_F(SyntheticGestureControllerTest, SingleScrollGestureMouseHorizontal) {
TEST_F(SyntheticGestureControllerTest, SingleScrollGestureMouseDiagonal) {
CreateControllerAndTarget<MockScrollMouseTarget>();
- SyntheticSmoothScrollGestureParams params;
- params.gesture_source_type = SyntheticGestureParams::MOUSE_INPUT;
- params.anchor.SetPoint(90, 12);
+ SyntheticSmoothMoveGestureParams params;
+ params.input_type = SyntheticSmoothMoveGestureParams::MOUSE_WHEEL_INPUT;
+ params.start_point.SetPoint(90, 12);
params.distances.push_back(gfx::Vector2d(-194, 303));
- scoped_ptr<SyntheticSmoothScrollGesture> gesture(
- new SyntheticSmoothScrollGesture(params));
+ scoped_ptr<SyntheticSmoothMoveGesture> gesture(
+ new SyntheticSmoothMoveGesture(params));
QueueSyntheticGesture(gesture.Pass());
FlushInputUntilComplete();
- MockScrollGestureTarget* scroll_target =
- static_cast<MockScrollGestureTarget*>(target_);
+ MockMoveGestureTarget* scroll_target =
+ static_cast<MockMoveGestureTarget*>(target_);
EXPECT_EQ(1, num_success_);
EXPECT_EQ(0, num_failure_);
EXPECT_EQ(params.distances[0], scroll_target->start_to_end_distance());
@@ -765,19 +847,19 @@ TEST_F(SyntheticGestureControllerTest, SingleScrollGestureMouseDiagonal) {
TEST_F(SyntheticGestureControllerTest, MultiScrollGestureMouse) {
CreateControllerAndTarget<MockScrollMouseTarget>();
- SyntheticSmoothScrollGestureParams params;
- params.gesture_source_type = SyntheticGestureParams::MOUSE_INPUT;
- params.anchor.SetPoint(90, 12);
+ SyntheticSmoothMoveGestureParams params;
+ params.input_type = SyntheticSmoothMoveGestureParams::MOUSE_WHEEL_INPUT;
+ params.start_point.SetPoint(90, 12);
params.distances.push_back(gfx::Vector2d(-129, 212));
params.distances.push_back(gfx::Vector2d(8, -9));
- scoped_ptr<SyntheticSmoothScrollGesture> gesture(
- new SyntheticSmoothScrollGesture(params));
+ scoped_ptr<SyntheticSmoothMoveGesture> gesture(
+ new SyntheticSmoothMoveGesture(params));
QueueSyntheticGesture(gesture.Pass());
FlushInputUntilComplete();
- MockScrollGestureTarget* scroll_target =
- static_cast<MockScrollGestureTarget*>(target_);
+ MockMoveGestureTarget* scroll_target =
+ static_cast<MockMoveGestureTarget*>(target_);
EXPECT_EQ(1, num_success_);
EXPECT_EQ(0, num_failure_);
EXPECT_EQ(params.distances[0] + params.distances[1],
@@ -787,25 +869,25 @@ TEST_F(SyntheticGestureControllerTest, MultiScrollGestureMouse) {
TEST_F(SyntheticGestureControllerTest, MultiScrollGestureMouseHorizontal) {
CreateControllerAndTarget<MockScrollMouseTarget>();
- SyntheticSmoothScrollGestureParams params;
- params.gesture_source_type = SyntheticGestureParams::MOUSE_INPUT;
- params.anchor.SetPoint(90, 12);
+ SyntheticSmoothMoveGestureParams params;
+ params.input_type = SyntheticSmoothMoveGestureParams::MOUSE_WHEEL_INPUT;
+ params.start_point.SetPoint(90, 12);
params.distances.push_back(gfx::Vector2d(-129, 0));
params.distances.push_back(gfx::Vector2d(79, 0));
- scoped_ptr<SyntheticSmoothScrollGesture> gesture(
- new SyntheticSmoothScrollGesture(params));
+ scoped_ptr<SyntheticSmoothMoveGesture> gesture(
+ new SyntheticSmoothMoveGesture(params));
QueueSyntheticGesture(gesture.Pass());
FlushInputUntilComplete();
- MockScrollGestureTarget* scroll_target =
- static_cast<MockScrollGestureTarget*>(target_);
+ MockMoveGestureTarget* scroll_target =
+ static_cast<MockMoveGestureTarget*>(target_);
EXPECT_EQ(1, num_success_);
EXPECT_EQ(0, num_failure_);
// This check only works for horizontal or vertical scrolls because of
// floating point precision issues with diagonal scrolls.
EXPECT_FLOAT_EQ(params.distances[0].Length() + params.distances[1].Length(),
- scroll_target->total_abs_scroll_distance_length());
+ scroll_target->total_abs_move_distance_length());
EXPECT_EQ(params.distances[0] + params.distances[1],
scroll_target->start_to_end_distance());
}
@@ -824,28 +906,28 @@ void CheckIsWithinRangeMulti(float scroll_distance,
void CheckMultiScrollDistanceIsWithinRange(
const gfx::Vector2dF& scroll_distance,
- const gfx::Vector2d& target_distance,
+ const gfx::Vector2dF& target_distance,
SyntheticGestureTarget* target) {
CheckIsWithinRangeMulti(scroll_distance.x(), target_distance.x(), target);
CheckIsWithinRangeMulti(scroll_distance.y(), target_distance.y(), target);
}
TEST_F(SyntheticGestureControllerTest, MultiScrollGestureTouch) {
- CreateControllerAndTarget<MockScrollTouchTarget>();
+ CreateControllerAndTarget<MockMoveTouchTarget>();
- SyntheticSmoothScrollGestureParams params;
- params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT;
- params.anchor.SetPoint(8, -13);
+ SyntheticSmoothMoveGestureParams params;
+ params.input_type = SyntheticSmoothMoveGestureParams::TOUCH_INPUT;
+ params.start_point.SetPoint(8, -13);
params.distances.push_back(gfx::Vector2d(234, 133));
params.distances.push_back(gfx::Vector2d(-9, 78));
- scoped_ptr<SyntheticSmoothScrollGesture> gesture(
- new SyntheticSmoothScrollGesture(params));
+ scoped_ptr<SyntheticSmoothMoveGesture> gesture(
+ new SyntheticSmoothMoveGesture(params));
QueueSyntheticGesture(gesture.Pass());
FlushInputUntilComplete();
- MockScrollGestureTarget* scroll_target =
- static_cast<MockScrollGestureTarget*>(target_);
+ MockMoveGestureTarget* scroll_target =
+ static_cast<MockMoveGestureTarget*>(target_);
EXPECT_EQ(1, num_success_);
EXPECT_EQ(0, num_failure_);
CheckMultiScrollDistanceIsWithinRange(
@@ -854,31 +936,168 @@ TEST_F(SyntheticGestureControllerTest, MultiScrollGestureTouch) {
target_);
}
-TEST_F(SyntheticGestureControllerTest, MultiScrollGestureTouchVertical) {
- CreateControllerAndTarget<MockScrollTouchTarget>();
+TEST_P(SyntheticGestureControllerTestWithParam,
+ MultiScrollGestureTouchVertical) {
+ CreateControllerAndTarget<MockMoveTouchTarget>();
- SyntheticSmoothScrollGestureParams params;
- params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT;
- params.anchor.SetPoint(234, -13);
+ SyntheticSmoothMoveGestureParams params;
+ params.input_type = SyntheticSmoothMoveGestureParams::TOUCH_INPUT;
+ if (GetParam() == TOUCH_DRAG) {
+ params.add_slop = false;
+ }
+ params.start_point.SetPoint(234, -13);
params.distances.push_back(gfx::Vector2d(0, 133));
params.distances.push_back(gfx::Vector2d(0, 78));
- scoped_ptr<SyntheticSmoothScrollGesture> gesture(
- new SyntheticSmoothScrollGesture(params));
+ scoped_ptr<SyntheticSmoothMoveGesture> gesture(
+ new SyntheticSmoothMoveGesture(params));
QueueSyntheticGesture(gesture.Pass());
FlushInputUntilComplete();
- MockScrollGestureTarget* scroll_target =
- static_cast<MockScrollGestureTarget*>(target_);
+ MockMoveGestureTarget* scroll_target =
+ static_cast<MockMoveGestureTarget*>(target_);
EXPECT_EQ(1, num_success_);
EXPECT_EQ(0, num_failure_);
- EXPECT_FLOAT_EQ(
- params.distances[0].Length() + params.distances[1].Length() +
- target_->GetTouchSlopInDips(),
- scroll_target->total_abs_scroll_distance_length());
+ if (GetParam() == TOUCH_SCROLL) {
+ EXPECT_FLOAT_EQ(params.distances[0].Length() +
+ params.distances[1].Length() +
+ target_->GetTouchSlopInDips(),
+ scroll_target->total_abs_move_distance_length());
EXPECT_EQ(AddTouchSlopToVector(params.distances[0] + params.distances[1],
target_),
scroll_target->start_to_end_distance());
+ } else {
+ EXPECT_FLOAT_EQ(params.distances[0].Length() + params.distances[1].Length(),
+ scroll_target->total_abs_move_distance_length());
+ EXPECT_EQ(params.distances[0] + params.distances[1],
+ scroll_target->start_to_end_distance());
+ }
+}
+
+INSTANTIATE_TEST_CASE_P(Single,
+ SyntheticGestureControllerTestWithParam,
+ testing::Values(TOUCH_SCROLL, TOUCH_DRAG));
+
+TEST_F(SyntheticGestureControllerTest, SingleDragGestureMouseDiagonal) {
+ CreateControllerAndTarget<MockDragMouseTarget>();
+
+ SyntheticSmoothMoveGestureParams params;
+ params.input_type = SyntheticSmoothMoveGestureParams::MOUSE_DRAG_INPUT;
+ params.start_point.SetPoint(0, 7);
+ params.distances.push_back(gfx::Vector2d(413, -83));
+
+ scoped_ptr<SyntheticSmoothMoveGesture> gesture(
+ new SyntheticSmoothMoveGesture(params));
+ QueueSyntheticGesture(gesture.Pass());
+ FlushInputUntilComplete();
+
+ MockMoveGestureTarget* drag_target =
+ static_cast<MockMoveGestureTarget*>(target_);
+ EXPECT_EQ(1, num_success_);
+ EXPECT_EQ(0, num_failure_);
+ EXPECT_EQ(drag_target->start_to_end_distance(), params.distances[0]);
+}
+
+TEST_F(SyntheticGestureControllerTest, SingleDragGestureMouseZeroDistance) {
+ CreateControllerAndTarget<MockDragMouseTarget>();
+
+ SyntheticSmoothMoveGestureParams params;
+ params.input_type = SyntheticSmoothMoveGestureParams::MOUSE_DRAG_INPUT;
+ params.start_point.SetPoint(-32, 43);
+ params.distances.push_back(gfx::Vector2d(0, 0));
+
+ scoped_ptr<SyntheticSmoothMoveGesture> gesture(
+ new SyntheticSmoothMoveGesture(params));
+ QueueSyntheticGesture(gesture.Pass());
+ FlushInputUntilComplete();
+
+ MockMoveGestureTarget* drag_target =
+ static_cast<MockMoveGestureTarget*>(target_);
+ EXPECT_EQ(1, num_success_);
+ EXPECT_EQ(0, num_failure_);
+ EXPECT_EQ(gfx::Vector2dF(0, 0), drag_target->start_to_end_distance());
+}
+
+TEST_F(SyntheticGestureControllerTest, MultiDragGestureMouse) {
+ CreateControllerAndTarget<MockDragMouseTarget>();
+
+ SyntheticSmoothMoveGestureParams params;
+ params.input_type = SyntheticSmoothMoveGestureParams::MOUSE_DRAG_INPUT;
+ params.start_point.SetPoint(8, -13);
+ params.distances.push_back(gfx::Vector2d(234, 133));
+ params.distances.push_back(gfx::Vector2d(-9, 78));
+
+ scoped_ptr<SyntheticSmoothMoveGesture> gesture(
+ new SyntheticSmoothMoveGesture(params));
+ QueueSyntheticGesture(gesture.Pass());
+ FlushInputUntilComplete();
+
+ MockMoveGestureTarget* drag_target =
+ static_cast<MockMoveGestureTarget*>(target_);
+ EXPECT_EQ(1, num_success_);
+ EXPECT_EQ(0, num_failure_);
+ EXPECT_EQ(drag_target->start_to_end_distance(),
+ params.distances[0] + params.distances[1]);
+}
+
+TEST_F(SyntheticGestureControllerTest,
+ SyntheticSmoothDragTestUsingSingleMouseDrag) {
+ CreateControllerAndTarget<MockDragMouseTarget>();
+
+ SyntheticSmoothDragGestureParams params;
+ params.gesture_source_type = SyntheticGestureParams::MOUSE_INPUT;
+ params.distances.push_back(gfx::Vector2d(234, 133));
+ params.speed_in_pixels_s = 800;
+
+ scoped_ptr<SyntheticSmoothDragGesture> gesture(
+ new SyntheticSmoothDragGesture(params));
+ const base::TimeTicks timestamp;
+ gesture->ForwardInputEvents(timestamp, target_);
+}
+
+TEST_F(SyntheticGestureControllerTest,
+ SyntheticSmoothDragTestUsingSingleTouchDrag) {
+ CreateControllerAndTarget<MockMoveTouchTarget>();
+
+ SyntheticSmoothDragGestureParams params;
+ params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT;
+ params.start_point.SetPoint(89, 32);
+ params.distances.push_back(gfx::Vector2d(0, 123));
+ params.speed_in_pixels_s = 800;
+
+ scoped_ptr<SyntheticSmoothDragGesture> gesture(
+ new SyntheticSmoothDragGesture(params));
+ const base::TimeTicks timestamp;
+ gesture->ForwardInputEvents(timestamp, target_);
+}
+
+TEST_F(SyntheticGestureControllerTest,
+ SyntheticSmoothScrollTestUsingSingleTouchScroll) {
+ CreateControllerAndTarget<MockMoveTouchTarget>();
+
+ SyntheticSmoothScrollGestureParams params;
+ params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT;
+
+ scoped_ptr<SyntheticSmoothScrollGesture> gesture(
+ new SyntheticSmoothScrollGesture(params));
+ const base::TimeTicks timestamp;
+ gesture->ForwardInputEvents(timestamp, target_);
+}
+
+TEST_F(SyntheticGestureControllerTest,
+ SyntheticSmoothScrollTestUsingSingleMouseScroll) {
+ CreateControllerAndTarget<MockScrollMouseTarget>();
+
+ SyntheticSmoothScrollGestureParams params;
+ params.gesture_source_type = SyntheticGestureParams::MOUSE_INPUT;
+ params.anchor.SetPoint(432, 89);
+ params.distances.push_back(gfx::Vector2d(0, -234));
+ params.speed_in_pixels_s = 800;
+
+ scoped_ptr<SyntheticSmoothScrollGesture> gesture(
+ new SyntheticSmoothScrollGesture(params));
+ const base::TimeTicks timestamp;
+ gesture->ForwardInputEvents(timestamp, target_);
}
TEST_F(SyntheticGestureControllerTest, PinchGestureTouchZoomIn) {
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 571fcbdb76f..afd124e55b5 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
@@ -18,28 +18,28 @@ class SyntheticGestureTargetAndroid : public SyntheticGestureTargetBase {
SyntheticGestureTargetAndroid(
RenderWidgetHostImpl* host,
base::android::ScopedJavaLocalRef<jobject> touch_event_synthesizer);
- virtual ~SyntheticGestureTargetAndroid();
+ ~SyntheticGestureTargetAndroid() override;
static bool RegisterTouchEventSynthesizer(JNIEnv* env);
// SyntheticGestureTargetBase:
- virtual void DispatchWebTouchEventToPlatform(
+ void DispatchWebTouchEventToPlatform(
const blink::WebTouchEvent& web_touch,
const ui::LatencyInfo& latency_info) override;
- virtual void DispatchWebMouseWheelEventToPlatform(
+ void DispatchWebMouseWheelEventToPlatform(
const blink::WebMouseWheelEvent& web_wheel,
const ui::LatencyInfo& latency_info) override;
- virtual void DispatchWebMouseEventToPlatform(
+ void DispatchWebMouseEventToPlatform(
const blink::WebMouseEvent& web_mouse,
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:
// 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 a7626d440d4..ba187b00534 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,6 +10,7 @@
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/events/event_processor.h"
+#include "ui/events/event_utils.h"
#include "ui/events/gesture_detection/gesture_configuration.h"
using blink::WebTouchEvent;
@@ -47,8 +48,8 @@ void SyntheticGestureTargetAura::DispatchWebMouseWheelEventToPlatform(
const blink::WebMouseWheelEvent& web_wheel,
const ui::LatencyInfo&) {
gfx::Point location(web_wheel.x, web_wheel.y);
- ui::MouseEvent mouse_event(
- ui::ET_MOUSEWHEEL, location, location, ui::EF_NONE, ui::EF_NONE);
+ ui::MouseEvent mouse_event(ui::ET_MOUSEWHEEL, location, location,
+ ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
ui::MouseWheelEvent wheel_event(
mouse_event, web_wheel.deltaX, web_wheel.deltaY);
@@ -117,7 +118,8 @@ void SyntheticGestureTargetAura::DispatchWebMouseEventToPlatform(
gfx::Point location(web_mouse.x, web_mouse.y);
ui::EventType event_type = WebMouseEventTypeToEventType(web_mouse.type);
int flags = WebMouseEventButtonToFlags(web_mouse.button);
- ui::MouseEvent mouse_event(event_type, location, location, flags, flags);
+ ui::MouseEvent mouse_event(event_type, location, location,
+ ui::EventTimeForNow(), flags, flags);
aura::Window* window = GetWindow();
mouse_event.ConvertLocationToTarget(window, window->GetRootWindow());
diff --git a/chromium/content/browser/renderer_host/input/synthetic_smooth_drag_gesture.cc b/chromium/content/browser/renderer_host/input/synthetic_smooth_drag_gesture.cc
new file mode 100644
index 00000000000..abce8415df2
--- /dev/null
+++ b/chromium/content/browser/renderer_host/input/synthetic_smooth_drag_gesture.cc
@@ -0,0 +1,57 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/renderer_host/input/synthetic_smooth_drag_gesture.h"
+
+namespace content {
+
+SyntheticSmoothDragGesture::SyntheticSmoothDragGesture(
+ const SyntheticSmoothDragGestureParams& params)
+ : params_(params) {
+}
+
+SyntheticSmoothDragGesture::~SyntheticSmoothDragGesture() {
+}
+
+SyntheticGesture::Result SyntheticSmoothDragGesture::ForwardInputEvents(
+ const base::TimeTicks& timestamp,
+ SyntheticGestureTarget* target) {
+ if (!move_gesture_) {
+ if (!InitializeMoveGesture(params_.gesture_source_type, target))
+ return SyntheticGesture::GESTURE_SOURCE_TYPE_NOT_IMPLEMENTED;
+ }
+ return move_gesture_->ForwardInputEvents(timestamp, target);
+}
+
+SyntheticSmoothMoveGestureParams::InputType
+SyntheticSmoothDragGesture::GetInputSourceType(
+ SyntheticGestureParams::GestureSourceType gesture_source_type) {
+ if (gesture_source_type == SyntheticGestureParams::MOUSE_INPUT)
+ return SyntheticSmoothMoveGestureParams::MOUSE_DRAG_INPUT;
+ else
+ return SyntheticSmoothMoveGestureParams::TOUCH_INPUT;
+}
+
+bool SyntheticSmoothDragGesture::InitializeMoveGesture(
+ SyntheticGestureParams::GestureSourceType gesture_type,
+ SyntheticGestureTarget* target) {
+ if (gesture_type == SyntheticGestureParams::DEFAULT_INPUT)
+ gesture_type = target->GetDefaultSyntheticGestureSourceType();
+
+ if (gesture_type == SyntheticGestureParams::TOUCH_INPUT ||
+ gesture_type == SyntheticGestureParams::MOUSE_INPUT) {
+ SyntheticSmoothMoveGestureParams move_params;
+ move_params.start_point = params_.start_point;
+ move_params.distances = params_.distances;
+ move_params.speed_in_pixels_s = params_.speed_in_pixels_s;
+ move_params.prevent_fling = true;
+ move_params.input_type = GetInputSourceType(gesture_type);
+ move_params.add_slop = false;
+ move_gesture_.reset(new SyntheticSmoothMoveGesture(move_params));
+ return true;
+ }
+ return false;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/synthetic_smooth_drag_gesture.h b/chromium/content/browser/renderer_host/input/synthetic_smooth_drag_gesture.h
new file mode 100644
index 00000000000..05de2426c7c
--- /dev/null
+++ b/chromium/content/browser/renderer_host/input/synthetic_smooth_drag_gesture.h
@@ -0,0 +1,38 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_RENDERER_HOST_INPUT_SYNTHETIC_SMOOTH_DRAG_GESTURE_H_
+#define CONTENT_BROWSER_RENDERER_HOST_INPUT_SYNTHETIC_SMOOTH_DRAG_GESTURE_H_
+
+#include "content/browser/renderer_host/input/synthetic_smooth_move_gesture.h"
+
+#include "content/common/input/synthetic_smooth_drag_gesture_params.h"
+
+namespace content {
+class CONTENT_EXPORT SyntheticSmoothDragGesture : public SyntheticGesture {
+ public:
+ explicit SyntheticSmoothDragGesture(
+ const SyntheticSmoothDragGestureParams& params);
+ ~SyntheticSmoothDragGesture() override;
+
+ // SyntheticGesture implementation:
+ SyntheticGesture::Result ForwardInputEvents(
+ const base::TimeTicks& timestamp,
+ SyntheticGestureTarget* target) override;
+
+ private:
+ static SyntheticSmoothMoveGestureParams::InputType GetInputSourceType(
+ SyntheticGestureParams::GestureSourceType gesture_source_type);
+
+ bool InitializeMoveGesture(
+ SyntheticGestureParams::GestureSourceType gesture_type,
+ SyntheticGestureTarget* target);
+
+ scoped_ptr<SyntheticSmoothMoveGesture> move_gesture_;
+ SyntheticSmoothDragGestureParams params_;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_SYNTHETIC_SMOOTH_DRAG_GESTURE_H_
diff --git a/chromium/content/browser/renderer_host/input/synthetic_smooth_move_gesture.cc b/chromium/content/browser/renderer_host/input/synthetic_smooth_move_gesture.cc
new file mode 100644
index 00000000000..80f3ef76c66
--- /dev/null
+++ b/chromium/content/browser/renderer_host/input/synthetic_smooth_move_gesture.cc
@@ -0,0 +1,374 @@
+// 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/input/synthetic_smooth_move_gesture.h"
+
+#include "base/logging.h"
+#include "ui/gfx/geometry/point_f.h"
+
+namespace content {
+namespace {
+
+gfx::Vector2d FloorTowardZero(const gfx::Vector2dF& vector) {
+ int x = vector.x() > 0 ? floor(vector.x()) : ceil(vector.x());
+ int y = vector.y() > 0 ? floor(vector.y()) : ceil(vector.y());
+ return gfx::Vector2d(x, y);
+}
+
+gfx::Vector2d CeilFromZero(const gfx::Vector2dF& vector) {
+ int x = vector.x() > 0 ? ceil(vector.x()) : floor(vector.x());
+ int y = vector.y() > 0 ? ceil(vector.y()) : floor(vector.y());
+ return gfx::Vector2d(x, y);
+}
+
+gfx::Vector2dF ProjectScalarOntoVector(float scalar,
+ const gfx::Vector2dF& vector) {
+ return gfx::ScaleVector2d(vector, scalar / vector.Length());
+}
+
+const int kDefaultSpeedInPixelsPerSec = 800;
+
+} // namespace
+
+SyntheticSmoothMoveGestureParams::SyntheticSmoothMoveGestureParams()
+ : speed_in_pixels_s(kDefaultSpeedInPixelsPerSec),
+ prevent_fling(true),
+ add_slop(true) {}
+
+SyntheticSmoothMoveGestureParams::~SyntheticSmoothMoveGestureParams() {}
+
+SyntheticSmoothMoveGesture::SyntheticSmoothMoveGesture(
+ SyntheticSmoothMoveGestureParams params)
+ : params_(params),
+ current_move_segment_start_position_(params.start_point),
+ state_(SETUP) {
+}
+
+SyntheticSmoothMoveGesture::~SyntheticSmoothMoveGesture() {}
+
+SyntheticGesture::Result SyntheticSmoothMoveGesture::ForwardInputEvents(
+ const base::TimeTicks& timestamp,
+ SyntheticGestureTarget* target) {
+ if (state_ == SETUP) {
+ state_ = STARTED;
+ current_move_segment_ = -1;
+ current_move_segment_stop_time_ = timestamp;
+ }
+
+ switch (params_.input_type) {
+ case SyntheticSmoothMoveGestureParams::TOUCH_INPUT:
+ ForwardTouchInputEvents(timestamp, target);
+ break;
+ case SyntheticSmoothMoveGestureParams::MOUSE_DRAG_INPUT:
+ ForwardMouseClickInputEvents(timestamp, target);
+ break;
+ case SyntheticSmoothMoveGestureParams::MOUSE_WHEEL_INPUT:
+ ForwardMouseWheelInputEvents(timestamp, target);
+ break;
+ default:
+ return SyntheticGesture::GESTURE_SOURCE_TYPE_NOT_IMPLEMENTED;
+ }
+ return (state_ == DONE) ? SyntheticGesture::GESTURE_FINISHED
+ : SyntheticGesture::GESTURE_RUNNING;
+}
+
+// TODO(ssid): Clean up the switch statements by adding functions instead of
+// large code, in the Forward*Events functions. Move the actions for all input
+// types to different class (SyntheticInputDevice) which generates input events
+// for all input types. The gesture class can use instance of device actions.
+// Refer: crbug.com/461825
+
+void SyntheticSmoothMoveGesture::ForwardTouchInputEvents(
+ const base::TimeTicks& timestamp,
+ SyntheticGestureTarget* target) {
+ base::TimeTicks event_timestamp = timestamp;
+ switch (state_) {
+ case STARTED:
+ if (MoveIsNoOp()) {
+ state_ = DONE;
+ break;
+ }
+ if (params_.add_slop)
+ AddTouchSlopToFirstDistance(target);
+ ComputeNextMoveSegment();
+ PressTouchPoint(target, event_timestamp);
+ state_ = MOVING;
+ break;
+ case MOVING: {
+ event_timestamp = ClampTimestamp(timestamp);
+ gfx::Vector2dF delta = GetPositionDeltaAtTime(event_timestamp);
+ MoveTouchPoint(target, delta, event_timestamp);
+
+ if (FinishedCurrentMoveSegment(event_timestamp)) {
+ if (!IsLastMoveSegment()) {
+ current_move_segment_start_position_ +=
+ params_.distances[current_move_segment_];
+ ComputeNextMoveSegment();
+ } else if (params_.prevent_fling) {
+ state_ = STOPPING;
+ } else {
+ ReleaseTouchPoint(target, event_timestamp);
+ state_ = DONE;
+ }
+ }
+ } break;
+ case STOPPING:
+ if (timestamp - current_move_segment_stop_time_ >=
+ target->PointerAssumedStoppedTime()) {
+ event_timestamp = current_move_segment_stop_time_ +
+ target->PointerAssumedStoppedTime();
+ ReleaseTouchPoint(target, event_timestamp);
+ state_ = DONE;
+ }
+ break;
+ case SETUP:
+ NOTREACHED()
+ << "State SETUP invalid for synthetic scroll using touch input.";
+ case DONE:
+ NOTREACHED()
+ << "State DONE invalid for synthetic scroll using touch input.";
+ }
+}
+
+void SyntheticSmoothMoveGesture::ForwardMouseWheelInputEvents(
+ const base::TimeTicks& timestamp,
+ SyntheticGestureTarget* target) {
+ switch (state_) {
+ case STARTED:
+ if (MoveIsNoOp()) {
+ state_ = DONE;
+ break;
+ }
+ ComputeNextMoveSegment();
+ state_ = MOVING;
+ // Fall through to forward the first event.
+ case MOVING: {
+ // Even though WebMouseWheelEvents take floating point deltas,
+ // internally the scroll position is stored as an integer. We therefore
+ // keep track of the discrete delta which is consistent with the
+ // internal scrolling state. This ensures that when the gesture has
+ // finished we've scrolled exactly the specified distance.
+ base::TimeTicks event_timestamp = ClampTimestamp(timestamp);
+ gfx::Vector2dF current_move_segment_total_delta =
+ GetPositionDeltaAtTime(event_timestamp);
+ gfx::Vector2d delta_discrete =
+ FloorTowardZero(current_move_segment_total_delta -
+ current_move_segment_total_delta_discrete_);
+ ForwardMouseWheelEvent(target, delta_discrete, event_timestamp);
+ current_move_segment_total_delta_discrete_ += delta_discrete;
+
+ if (FinishedCurrentMoveSegment(event_timestamp)) {
+ if (!IsLastMoveSegment()) {
+ current_move_segment_total_delta_discrete_ = gfx::Vector2d();
+ ComputeNextMoveSegment();
+ ForwardMouseWheelInputEvents(timestamp, target);
+ } else {
+ state_ = DONE;
+ }
+ }
+ } break;
+ case SETUP:
+ NOTREACHED() << "State SETUP invalid for synthetic scroll using mouse "
+ "wheel input.";
+ case STOPPING:
+ NOTREACHED() << "State STOPPING invalid for synthetic scroll using mouse "
+ "wheel input.";
+ case DONE:
+ NOTREACHED()
+ << "State DONE invalid for synthetic scroll using mouse wheel input.";
+ }
+}
+
+void SyntheticSmoothMoveGesture::ForwardMouseClickInputEvents(
+ const base::TimeTicks& timestamp,
+ SyntheticGestureTarget* target) {
+ base::TimeTicks event_timestamp = timestamp;
+ switch (state_) {
+ case STARTED:
+ if (MoveIsNoOp()) {
+ state_ = DONE;
+ break;
+ }
+ ComputeNextMoveSegment();
+ PressMousePoint(target, event_timestamp);
+ state_ = MOVING;
+ break;
+ case MOVING: {
+ base::TimeTicks event_timestamp = ClampTimestamp(timestamp);
+ gfx::Vector2dF delta = GetPositionDeltaAtTime(event_timestamp);
+ MoveMousePoint(target, delta, event_timestamp);
+
+ if (FinishedCurrentMoveSegment(event_timestamp)) {
+ if (!IsLastMoveSegment()) {
+ current_move_segment_start_position_ +=
+ params_.distances[current_move_segment_];
+ ComputeNextMoveSegment();
+ } else {
+ ReleaseMousePoint(target, event_timestamp);
+ state_ = DONE;
+ }
+ }
+ } break;
+ case STOPPING:
+ NOTREACHED()
+ << "State STOPPING invalid for synthetic drag using mouse input.";
+ case SETUP:
+ NOTREACHED()
+ << "State SETUP invalid for synthetic drag using mouse input.";
+ case DONE:
+ NOTREACHED()
+ << "State DONE invalid for synthetic drag using mouse input.";
+ }
+}
+
+void SyntheticSmoothMoveGesture::ForwardTouchEvent(
+ SyntheticGestureTarget* target,
+ const base::TimeTicks& timestamp) {
+ touch_event_.timeStampSeconds = ConvertTimestampToSeconds(timestamp);
+
+ target->DispatchInputEventToPlatform(touch_event_);
+}
+
+void SyntheticSmoothMoveGesture::ForwardMouseWheelEvent(
+ SyntheticGestureTarget* target,
+ const gfx::Vector2dF& delta,
+ const base::TimeTicks& timestamp) const {
+ blink::WebMouseWheelEvent mouse_wheel_event =
+ SyntheticWebMouseWheelEventBuilder::Build(delta.x(), delta.y(), 0, false);
+
+ mouse_wheel_event.x = current_move_segment_start_position_.x();
+ mouse_wheel_event.y = current_move_segment_start_position_.y();
+
+ mouse_wheel_event.timeStampSeconds = ConvertTimestampToSeconds(timestamp);
+
+ target->DispatchInputEventToPlatform(mouse_wheel_event);
+}
+
+void SyntheticSmoothMoveGesture::PressTouchPoint(
+ SyntheticGestureTarget* target,
+ const base::TimeTicks& timestamp) {
+ DCHECK_EQ(current_move_segment_, 0);
+ touch_event_.PressPoint(current_move_segment_start_position_.x(),
+ current_move_segment_start_position_.y());
+ ForwardTouchEvent(target, timestamp);
+}
+
+void SyntheticSmoothMoveGesture::MoveTouchPoint(
+ SyntheticGestureTarget* target,
+ const gfx::Vector2dF& delta,
+ const base::TimeTicks& timestamp) {
+ DCHECK_GE(current_move_segment_, 0);
+ DCHECK_LT(current_move_segment_, static_cast<int>(params_.distances.size()));
+ gfx::PointF touch_position = current_move_segment_start_position_ + delta;
+ touch_event_.MovePoint(0, touch_position.x(), touch_position.y());
+ ForwardTouchEvent(target, timestamp);
+}
+
+void SyntheticSmoothMoveGesture::ReleaseTouchPoint(
+ SyntheticGestureTarget* target,
+ const base::TimeTicks& timestamp) {
+ DCHECK_EQ(current_move_segment_,
+ static_cast<int>(params_.distances.size()) - 1);
+ touch_event_.ReleasePoint(0);
+ ForwardTouchEvent(target, timestamp);
+}
+
+void SyntheticSmoothMoveGesture::PressMousePoint(
+ SyntheticGestureTarget* target,
+ const base::TimeTicks& timestamp) {
+ DCHECK_EQ(params_.input_type,
+ SyntheticSmoothMoveGestureParams::MOUSE_DRAG_INPUT);
+ blink::WebMouseEvent mouse_event = SyntheticWebMouseEventBuilder::Build(
+ blink::WebInputEvent::MouseDown, current_move_segment_start_position_.x(),
+ current_move_segment_start_position_.y(), 0);
+ mouse_event.clickCount = 1;
+ mouse_event.timeStampSeconds = ConvertTimestampToSeconds(timestamp);
+ target->DispatchInputEventToPlatform(mouse_event);
+}
+
+void SyntheticSmoothMoveGesture::ReleaseMousePoint(
+ SyntheticGestureTarget* target,
+ const base::TimeTicks& timestamp) {
+ DCHECK_EQ(params_.input_type,
+ SyntheticSmoothMoveGestureParams::MOUSE_DRAG_INPUT);
+ gfx::PointF mouse_position =
+ current_move_segment_start_position_ + GetPositionDeltaAtTime(timestamp);
+ blink::WebMouseEvent mouse_event = SyntheticWebMouseEventBuilder::Build(
+ blink::WebInputEvent::MouseUp, mouse_position.x(), mouse_position.y(), 0);
+ mouse_event.timeStampSeconds = ConvertTimestampToSeconds(timestamp);
+ target->DispatchInputEventToPlatform(mouse_event);
+}
+
+void SyntheticSmoothMoveGesture::MoveMousePoint(
+ SyntheticGestureTarget* target,
+ const gfx::Vector2dF& delta,
+ const base::TimeTicks& timestamp) {
+ gfx::PointF mouse_position = current_move_segment_start_position_ + delta;
+ DCHECK_EQ(params_.input_type,
+ SyntheticSmoothMoveGestureParams::MOUSE_DRAG_INPUT);
+ blink::WebMouseEvent mouse_event = SyntheticWebMouseEventBuilder::Build(
+ blink::WebInputEvent::MouseMove, mouse_position.x(), mouse_position.y(),
+ 0);
+ mouse_event.button = blink::WebMouseEvent::ButtonLeft;
+ mouse_event.timeStampSeconds = ConvertTimestampToSeconds(timestamp);
+ target->DispatchInputEventToPlatform(mouse_event);
+}
+
+void SyntheticSmoothMoveGesture::AddTouchSlopToFirstDistance(
+ SyntheticGestureTarget* target) {
+ DCHECK_GE(params_.distances.size(), 1ul);
+ gfx::Vector2dF& first_move_distance = params_.distances[0];
+ DCHECK_GT(first_move_distance.Length(), 0);
+ first_move_distance += CeilFromZero(ProjectScalarOntoVector(
+ target->GetTouchSlopInDips(), first_move_distance));
+}
+
+gfx::Vector2dF SyntheticSmoothMoveGesture::GetPositionDeltaAtTime(
+ const base::TimeTicks& timestamp) const {
+ // Make sure the final delta is correct. Using the computation below can lead
+ // to issues with floating point precision.
+ if (FinishedCurrentMoveSegment(timestamp))
+ return params_.distances[current_move_segment_];
+
+ float delta_length =
+ params_.speed_in_pixels_s *
+ (timestamp - current_move_segment_start_time_).InSecondsF();
+ return ProjectScalarOntoVector(delta_length,
+ params_.distances[current_move_segment_]);
+}
+
+void SyntheticSmoothMoveGesture::ComputeNextMoveSegment() {
+ current_move_segment_++;
+ DCHECK_LT(current_move_segment_, static_cast<int>(params_.distances.size()));
+ int64 total_duration_in_us = static_cast<int64>(
+ 1e6 * (params_.distances[current_move_segment_].Length() /
+ params_.speed_in_pixels_s));
+ DCHECK_GT(total_duration_in_us, 0);
+ current_move_segment_start_time_ = current_move_segment_stop_time_;
+ current_move_segment_stop_time_ =
+ current_move_segment_start_time_ +
+ base::TimeDelta::FromMicroseconds(total_duration_in_us);
+}
+
+base::TimeTicks SyntheticSmoothMoveGesture::ClampTimestamp(
+ const base::TimeTicks& timestamp) const {
+ return std::min(timestamp, current_move_segment_stop_time_);
+}
+
+bool SyntheticSmoothMoveGesture::FinishedCurrentMoveSegment(
+ const base::TimeTicks& timestamp) const {
+ return timestamp >= current_move_segment_stop_time_;
+}
+
+bool SyntheticSmoothMoveGesture::IsLastMoveSegment() const {
+ DCHECK_LT(current_move_segment_, static_cast<int>(params_.distances.size()));
+ return current_move_segment_ ==
+ static_cast<int>(params_.distances.size()) - 1;
+}
+
+bool SyntheticSmoothMoveGesture::MoveIsNoOp() const {
+ return params_.distances.size() == 0 || params_.distances[0].IsZero();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/synthetic_smooth_move_gesture.h b/chromium/content/browser/renderer_host/input/synthetic_smooth_move_gesture.h
new file mode 100644
index 00000000000..fe9790cf98a
--- /dev/null
+++ b/chromium/content/browser/renderer_host/input/synthetic_smooth_move_gesture.h
@@ -0,0 +1,118 @@
+// 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_INPUT_SYNTHETIC_SMOOTH_MOVE_GESTURE_H_
+#define CONTENT_BROWSER_RENDERER_HOST_INPUT_SYNTHETIC_SMOOTH_MOVE_GESTURE_H_
+
+#include <vector>
+
+#include "base/time/time.h"
+#include "content/browser/renderer_host/input/synthetic_gesture.h"
+#include "content/browser/renderer_host/input/synthetic_gesture_target.h"
+#include "content/common/content_export.h"
+#include "content/common/input/synthetic_smooth_drag_gesture_params.h"
+#include "content/common/input/synthetic_smooth_scroll_gesture_params.h"
+#include "content/common/input/synthetic_web_input_event_builders.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
+#include "ui/gfx/geometry/vector2d.h"
+#include "ui/gfx/geometry/vector2d_f.h"
+
+namespace content {
+
+class CONTENT_EXPORT SyntheticSmoothMoveGestureParams {
+ public:
+ SyntheticSmoothMoveGestureParams();
+ ~SyntheticSmoothMoveGestureParams();
+
+ enum InputType { MOUSE_DRAG_INPUT, MOUSE_WHEEL_INPUT, TOUCH_INPUT };
+
+ InputType input_type;
+ gfx::PointF start_point;
+ std::vector<gfx::Vector2dF> distances;
+ int speed_in_pixels_s;
+ bool prevent_fling;
+ bool add_slop;
+};
+
+// This class is used as helper class for simulation of scroll and drag.
+// Simulates scrolling/dragging given a sequence of distances as a continuous
+// gestures (i.e. when synthesizing touch or mouse drag events, the pointer is
+// not lifted when changing scroll direction).
+// If no distance is provided or the first one is 0, no touch events are
+// generated.
+// When synthesizing touch events for scrolling, the first distance is extended
+// to compensate for the touch slop.
+class CONTENT_EXPORT SyntheticSmoothMoveGesture : public SyntheticGesture {
+ public:
+ SyntheticSmoothMoveGesture(SyntheticSmoothMoveGestureParams params);
+ ~SyntheticSmoothMoveGesture() override;
+
+ // SyntheticGesture implementation:
+ SyntheticGesture::Result ForwardInputEvents(
+ const base::TimeTicks& timestamp,
+ SyntheticGestureTarget* target) override;
+
+ private:
+ enum GestureState {
+ SETUP,
+ STARTED,
+ MOVING,
+ STOPPING,
+ DONE
+ };
+
+ void ForwardTouchInputEvents(
+ const base::TimeTicks& timestamp, SyntheticGestureTarget* target);
+ void ForwardMouseWheelInputEvents(
+ const base::TimeTicks& timestamp, SyntheticGestureTarget* target);
+ void ForwardMouseClickInputEvents(
+ const base::TimeTicks& timestamp, SyntheticGestureTarget* target);
+
+ void ForwardTouchEvent(SyntheticGestureTarget* target,
+ const base::TimeTicks& timestamp);
+ void ForwardMouseWheelEvent(SyntheticGestureTarget* target,
+ const gfx::Vector2dF& delta,
+ const base::TimeTicks& timestamp) const;
+
+ void PressTouchPoint(SyntheticGestureTarget* target,
+ const base::TimeTicks& timestamp);
+ void MoveTouchPoint(SyntheticGestureTarget* target,
+ const gfx::Vector2dF& delta,
+ const base::TimeTicks& timestamp);
+ void ReleaseTouchPoint(SyntheticGestureTarget* target,
+ const base::TimeTicks& timestamp);
+
+ void PressMousePoint(SyntheticGestureTarget* target,
+ const base::TimeTicks& timestamp);
+ void ReleaseMousePoint(SyntheticGestureTarget* target,
+ const base::TimeTicks& timestamp);
+ void MoveMousePoint(SyntheticGestureTarget* target,
+ const gfx::Vector2dF& delta,
+ const base::TimeTicks& timestamp);
+
+ void AddTouchSlopToFirstDistance(SyntheticGestureTarget* target);
+ gfx::Vector2dF GetPositionDeltaAtTime(const base::TimeTicks& timestamp) const;
+ void ComputeNextMoveSegment();
+ base::TimeTicks ClampTimestamp(const base::TimeTicks& timestamp) const;
+ bool FinishedCurrentMoveSegment(const base::TimeTicks& timestamp) const;
+ bool IsLastMoveSegment() const;
+ bool MoveIsNoOp() const;
+
+ SyntheticSmoothMoveGestureParams params_;
+ // Used for mouse input.
+ gfx::Vector2d current_move_segment_total_delta_discrete_;
+ // Used for touch input.
+ gfx::PointF current_move_segment_start_position_;
+ SyntheticWebTouchEvent touch_event_;
+ GestureState state_;
+ int current_move_segment_;
+ base::TimeTicks current_move_segment_start_time_;
+ base::TimeTicks current_move_segment_stop_time_;
+
+ DISALLOW_COPY_AND_ASSIGN(SyntheticSmoothMoveGesture);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_SYNTHETIC_SMOOTH_MOVE_GESTURE_H_
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 8800aca2969..de5265912ca 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
@@ -4,267 +4,54 @@
#include "content/browser/renderer_host/input/synthetic_smooth_scroll_gesture.h"
-#include "base/logging.h"
-#include "ui/gfx/point_f.h"
-
namespace content {
-namespace {
-
-gfx::Vector2d FloorTowardZero(const gfx::Vector2dF& vector) {
- int x = vector.x() > 0 ? floor(vector.x()) : ceil(vector.x());
- int y = vector.y() > 0 ? floor(vector.y()) : ceil(vector.y());
- return gfx::Vector2d(x, y);
-}
-
-gfx::Vector2d CeilFromZero(const gfx::Vector2dF& vector) {
- int x = vector.x() > 0 ? ceil(vector.x()) : floor(vector.x());
- int y = vector.y() > 0 ? ceil(vector.y()) : floor(vector.y());
- return gfx::Vector2d(x, y);
-}
-
-gfx::Vector2dF ProjectScalarOntoVector(
- float scalar, const gfx::Vector2d& vector) {
- return gfx::ScaleVector2d(vector, scalar / vector.Length());
-}
-
-} // namespace
SyntheticSmoothScrollGesture::SyntheticSmoothScrollGesture(
const SyntheticSmoothScrollGestureParams& params)
- : params_(params),
- gesture_source_type_(SyntheticGestureParams::DEFAULT_INPUT),
- state_(SETUP) {}
-
-SyntheticSmoothScrollGesture::~SyntheticSmoothScrollGesture() {}
-
-SyntheticGesture::Result SyntheticSmoothScrollGesture::ForwardInputEvents(
- const base::TimeTicks& timestamp, SyntheticGestureTarget* target) {
- if (state_ == SETUP) {
- gesture_source_type_ = params_.gesture_source_type;
- if (gesture_source_type_ == SyntheticGestureParams::DEFAULT_INPUT)
- gesture_source_type_ = target->GetDefaultSyntheticGestureSourceType();
-
- state_ = STARTED;
- current_scroll_segment_ = -1;
- current_scroll_segment_stop_time_ = timestamp;
- }
-
- DCHECK_NE(gesture_source_type_, SyntheticGestureParams::DEFAULT_INPUT);
- if (gesture_source_type_ == SyntheticGestureParams::TOUCH_INPUT)
- ForwardTouchInputEvents(timestamp, target);
- else if (gesture_source_type_ == SyntheticGestureParams::MOUSE_INPUT)
- ForwardMouseInputEvents(timestamp, target);
- else
- return SyntheticGesture::GESTURE_SOURCE_TYPE_NOT_IMPLEMENTED;
-
- return (state_ == DONE) ? SyntheticGesture::GESTURE_FINISHED
- : SyntheticGesture::GESTURE_RUNNING;
+ : params_(params) {
}
-void SyntheticSmoothScrollGesture::ForwardTouchInputEvents(
- const base::TimeTicks& timestamp, SyntheticGestureTarget* target) {
- base::TimeTicks event_timestamp = timestamp;
- switch (state_) {
- case STARTED:
- if (ScrollIsNoOp()) {
- state_ = DONE;
- break;
- }
- AddTouchSlopToFirstDistance(target);
- ComputeNextScrollSegment();
- current_scroll_segment_start_position_ = params_.anchor;
- PressTouchPoint(target, event_timestamp);
- state_ = MOVING;
- break;
- case MOVING: {
- event_timestamp = ClampTimestamp(timestamp);
- gfx::Vector2dF delta = GetPositionDeltaAtTime(event_timestamp);
- MoveTouchPoint(target, delta, event_timestamp);
-
- if (FinishedCurrentScrollSegment(event_timestamp)) {
- if (!IsLastScrollSegment()) {
- current_scroll_segment_start_position_ +=
- params_.distances[current_scroll_segment_];
- ComputeNextScrollSegment();
- } else if (params_.prevent_fling) {
- state_ = STOPPING;
- } else {
- ReleaseTouchPoint(target, event_timestamp);
- state_ = DONE;
- }
- }
- } break;
- case STOPPING:
- if (timestamp - current_scroll_segment_stop_time_ >=
- target->PointerAssumedStoppedTime()) {
- event_timestamp = current_scroll_segment_stop_time_ +
- target->PointerAssumedStoppedTime();
- ReleaseTouchPoint(target, event_timestamp);
- state_ = DONE;
- }
- break;
- case SETUP:
- NOTREACHED()
- << "State STARTED invalid for synthetic scroll using touch input.";
- case DONE:
- NOTREACHED()
- << "State DONE invalid for synthetic scroll using touch input.";
- }
+SyntheticSmoothScrollGesture::~SyntheticSmoothScrollGesture() {
}
-void SyntheticSmoothScrollGesture::ForwardMouseInputEvents(
- const base::TimeTicks& timestamp, SyntheticGestureTarget* target) {
- switch (state_) {
- case STARTED:
- if (ScrollIsNoOp()) {
- state_ = DONE;
- break;
- }
- ComputeNextScrollSegment();
- state_ = MOVING;
- // Fall through to forward the first event.
- case MOVING: {
- // Even though WebMouseWheelEvents take floating point deltas,
- // internally the scroll position is stored as an integer. We therefore
- // keep track of the discrete delta which is consistent with the
- // internal scrolling state. This ensures that when the gesture has
- // finished we've scrolled exactly the specified distance.
- base::TimeTicks event_timestamp = ClampTimestamp(timestamp);
- gfx::Vector2dF current_scroll_segment_total_delta =
- GetPositionDeltaAtTime(event_timestamp);
- gfx::Vector2d delta_discrete =
- FloorTowardZero(current_scroll_segment_total_delta -
- current_scroll_segment_total_delta_discrete_);
- ForwardMouseWheelEvent(target, delta_discrete, event_timestamp);
- current_scroll_segment_total_delta_discrete_ += delta_discrete;
-
- if (FinishedCurrentScrollSegment(event_timestamp)) {
- if (!IsLastScrollSegment()) {
- current_scroll_segment_total_delta_discrete_ = gfx::Vector2d();
- ComputeNextScrollSegment();
- ForwardMouseInputEvents(timestamp, target);
- } else {
- state_ = DONE;
- }
- }
- } break;
- case SETUP:
- NOTREACHED()
- << "State STARTED invalid for synthetic scroll using touch input.";
- case STOPPING:
- NOTREACHED()
- << "State STOPPING invalid for synthetic scroll using touch input.";
- case DONE:
- NOTREACHED()
- << "State DONE invalid for synthetic scroll using touch input.";
+SyntheticGesture::Result SyntheticSmoothScrollGesture::ForwardInputEvents(
+ const base::TimeTicks& timestamp,
+ SyntheticGestureTarget* target) {
+ if (!move_gesture_) {
+ if (!InitializeMoveGesture(params_.gesture_source_type, target))
+ return SyntheticGesture::GESTURE_SOURCE_TYPE_NOT_IMPLEMENTED;
}
+ return move_gesture_->ForwardInputEvents(timestamp, target);
}
-void SyntheticSmoothScrollGesture::ForwardTouchEvent(
- SyntheticGestureTarget* target, const base::TimeTicks& timestamp) {
- touch_event_.timeStampSeconds = ConvertTimestampToSeconds(timestamp);
-
- target->DispatchInputEventToPlatform(touch_event_);
-}
-
-void SyntheticSmoothScrollGesture::ForwardMouseWheelEvent(
- SyntheticGestureTarget* target,
- const gfx::Vector2dF& delta,
- const base::TimeTicks& timestamp) const {
- blink::WebMouseWheelEvent mouse_wheel_event =
- SyntheticWebMouseWheelEventBuilder::Build(delta.x(), delta.y(), 0, false);
-
- mouse_wheel_event.x = params_.anchor.x();
- mouse_wheel_event.y = params_.anchor.y();
-
- mouse_wheel_event.timeStampSeconds = ConvertTimestampToSeconds(timestamp);
-
- target->DispatchInputEventToPlatform(mouse_wheel_event);
-}
-
-void SyntheticSmoothScrollGesture::PressTouchPoint(
- SyntheticGestureTarget* target, const base::TimeTicks& timestamp) {
- DCHECK_EQ(current_scroll_segment_, 0);
- touch_event_.PressPoint(params_.anchor.x(), params_.anchor.y());
- ForwardTouchEvent(target, timestamp);
-}
-
-void SyntheticSmoothScrollGesture::MoveTouchPoint(
- SyntheticGestureTarget* target,
- const gfx::Vector2dF& delta,
- const base::TimeTicks& timestamp) {
- DCHECK_GE(current_scroll_segment_, 0);
- DCHECK_LT(current_scroll_segment_,
- static_cast<int>(params_.distances.size()));
- gfx::PointF touch_position = current_scroll_segment_start_position_ + delta;
- touch_event_.MovePoint(0, touch_position.x(), touch_position.y());
- ForwardTouchEvent(target, timestamp);
-}
-
-void SyntheticSmoothScrollGesture::ReleaseTouchPoint(
- SyntheticGestureTarget* target, const base::TimeTicks& timestamp) {
- DCHECK_EQ(current_scroll_segment_,
- static_cast<int>(params_.distances.size()) - 1);
- touch_event_.ReleasePoint(0);
- ForwardTouchEvent(target, timestamp);
+SyntheticSmoothMoveGestureParams::InputType
+SyntheticSmoothScrollGesture::GetInputSourceType(
+ SyntheticGestureParams::GestureSourceType gesture_source_type) {
+ if (gesture_source_type == SyntheticGestureParams::MOUSE_INPUT)
+ return SyntheticSmoothMoveGestureParams::MOUSE_WHEEL_INPUT;
+ else
+ return SyntheticSmoothMoveGestureParams::TOUCH_INPUT;
}
-void SyntheticSmoothScrollGesture::AddTouchSlopToFirstDistance(
+bool SyntheticSmoothScrollGesture::InitializeMoveGesture(
+ SyntheticGestureParams::GestureSourceType gesture_type,
SyntheticGestureTarget* target) {
- DCHECK_GE(params_.distances.size(), 1ul);
- gfx::Vector2d& first_scroll_distance = params_.distances[0];
- DCHECK_GT(first_scroll_distance.Length(), 0);
- first_scroll_distance += CeilFromZero(ProjectScalarOntoVector(
- target->GetTouchSlopInDips(), first_scroll_distance));
-}
-
-gfx::Vector2dF SyntheticSmoothScrollGesture::GetPositionDeltaAtTime(
- const base::TimeTicks& timestamp) const {
- // Make sure the final delta is correct. Using the computation below can lead
- // to issues with floating point precision.
- if (FinishedCurrentScrollSegment(timestamp))
- return params_.distances[current_scroll_segment_];
-
- float delta_length =
- params_.speed_in_pixels_s *
- (timestamp - current_scroll_segment_start_time_).InSecondsF();
- return ProjectScalarOntoVector(delta_length,
- params_.distances[current_scroll_segment_]);
-}
-
-void SyntheticSmoothScrollGesture::ComputeNextScrollSegment() {
- current_scroll_segment_++;
- DCHECK_LT(current_scroll_segment_,
- static_cast<int>(params_.distances.size()));
- int64 total_duration_in_us = static_cast<int64>(
- 1e6 * (params_.distances[current_scroll_segment_].Length() /
- params_.speed_in_pixels_s));
- DCHECK_GT(total_duration_in_us, 0);
- current_scroll_segment_start_time_ = current_scroll_segment_stop_time_;
- current_scroll_segment_stop_time_ =
- current_scroll_segment_start_time_ +
- base::TimeDelta::FromMicroseconds(total_duration_in_us);
-}
-
-base::TimeTicks SyntheticSmoothScrollGesture::ClampTimestamp(
- const base::TimeTicks& timestamp) const {
- return std::min(timestamp, current_scroll_segment_stop_time_);
-}
-
-bool SyntheticSmoothScrollGesture::FinishedCurrentScrollSegment(
- const base::TimeTicks& timestamp) const {
- return timestamp >= current_scroll_segment_stop_time_;
-}
-
-bool SyntheticSmoothScrollGesture::IsLastScrollSegment() const {
- DCHECK_LT(current_scroll_segment_,
- static_cast<int>(params_.distances.size()));
- return current_scroll_segment_ ==
- static_cast<int>(params_.distances.size()) - 1;
-}
-
-bool SyntheticSmoothScrollGesture::ScrollIsNoOp() const {
- return params_.distances.size() == 0 || params_.distances[0].IsZero();
+ if (gesture_type == SyntheticGestureParams::DEFAULT_INPUT)
+ gesture_type = target->GetDefaultSyntheticGestureSourceType();
+
+ if (gesture_type == SyntheticGestureParams::TOUCH_INPUT ||
+ gesture_type == SyntheticGestureParams::MOUSE_INPUT) {
+ SyntheticSmoothMoveGestureParams move_params;
+ move_params.start_point = params_.anchor;
+ move_params.distances = params_.distances;
+ move_params.speed_in_pixels_s = params_.speed_in_pixels_s;
+ move_params.prevent_fling = params_.prevent_fling;
+ move_params.input_type = GetInputSourceType(gesture_type);
+ move_params.add_slop = true;
+ move_gesture_.reset(new SyntheticSmoothMoveGesture(move_params));
+ return true;
+ }
+ return false;
}
} // namespace content
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 080e2dbaec1..1819b3dd6af 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
@@ -5,85 +5,32 @@
#ifndef CONTENT_BROWSER_RENDERER_HOST_INPUT_SYNTHETIC_SMOOTH_SCROLL_GESTURE_H_
#define CONTENT_BROWSER_RENDERER_HOST_INPUT_SYNTHETIC_SMOOTH_SCROLL_GESTURE_H_
-#include "base/time/time.h"
-#include "content/browser/renderer_host/input/synthetic_gesture.h"
-#include "content/browser/renderer_host/input/synthetic_gesture_target.h"
-#include "content/common/content_export.h"
+#include "content/browser/renderer_host/input/synthetic_smooth_move_gesture.h"
+
#include "content/common/input/synthetic_smooth_scroll_gesture_params.h"
-#include "content/common/input/synthetic_web_input_event_builders.h"
-#include "third_party/WebKit/public/web/WebInputEvent.h"
-#include "ui/gfx/vector2d.h"
-#include "ui/gfx/vector2d_f.h"
namespace content {
-
-// Simulates scrolling given a sequence of scroll distances as a continuous
-// gestures (i.e. when synthesizing touch events, the touch pointer is not
-// lifted when changing scroll direction).
-// If no distance is provided or the first one is 0, no touch events are
-// generated.
-// When synthesizing touch events, the first distance is extended to compensate
-// for the touch slop.
class CONTENT_EXPORT SyntheticSmoothScrollGesture : public SyntheticGesture {
public:
explicit SyntheticSmoothScrollGesture(
const SyntheticSmoothScrollGestureParams& params);
~SyntheticSmoothScrollGesture() override;
+ // SyntheticGesture implementation:
SyntheticGesture::Result ForwardInputEvents(
const base::TimeTicks& timestamp,
SyntheticGestureTarget* target) override;
private:
- enum GestureState {
- SETUP,
- STARTED,
- MOVING,
- STOPPING,
- DONE
- };
-
- void ForwardTouchInputEvents(
- const base::TimeTicks& timestamp, SyntheticGestureTarget* target);
- void ForwardMouseInputEvents(
- const base::TimeTicks& timestamp, SyntheticGestureTarget* target);
+ static SyntheticSmoothMoveGestureParams::InputType GetInputSourceType(
+ SyntheticGestureParams::GestureSourceType gesture_source_type);
- void ForwardTouchEvent(SyntheticGestureTarget* target,
- const base::TimeTicks& timestamp);
- void ForwardMouseWheelEvent(SyntheticGestureTarget* target,
- const gfx::Vector2dF& delta,
- const base::TimeTicks& timestamp) const;
-
- void PressTouchPoint(SyntheticGestureTarget* target,
- const base::TimeTicks& timestamp);
- void MoveTouchPoint(SyntheticGestureTarget* target,
- const gfx::Vector2dF& delta,
- const base::TimeTicks& timestamp);
- void ReleaseTouchPoint(SyntheticGestureTarget* target,
- const base::TimeTicks& timestamp);
-
- void AddTouchSlopToFirstDistance(SyntheticGestureTarget* target);
- gfx::Vector2dF GetPositionDeltaAtTime(const base::TimeTicks& timestamp)
- const;
- void ComputeNextScrollSegment();
- base::TimeTicks ClampTimestamp(const base::TimeTicks& timestamp) const;
- bool FinishedCurrentScrollSegment(const base::TimeTicks& timestamp) const;
- bool IsLastScrollSegment() const;
- bool ScrollIsNoOp() const;
+ bool InitializeMoveGesture(
+ SyntheticGestureParams::GestureSourceType gesture_type,
+ SyntheticGestureTarget* target);
+ scoped_ptr<SyntheticSmoothMoveGesture> move_gesture_;
SyntheticSmoothScrollGestureParams params_;
- // Used for mouse input.
- gfx::Vector2d current_scroll_segment_total_delta_discrete_;
- // Used for touch input.
- gfx::Point current_scroll_segment_start_position_;
- SyntheticWebTouchEvent touch_event_;
- SyntheticGestureParams::GestureSourceType gesture_source_type_;
- GestureState state_;
- int current_scroll_segment_;
- base::TimeTicks current_scroll_segment_start_time_;
- base::TimeTicks current_scroll_segment_stop_time_;
-
- DISALLOW_COPY_AND_ASSIGN(SyntheticSmoothScrollGesture);
};
} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/tap_suppression_controller.cc b/chromium/content/browser/renderer_host/input/tap_suppression_controller.cc
index c6b17e6ecf6..78b3a076d6d 100644
--- a/chromium/content/browser/renderer_host/input/tap_suppression_controller.cc
+++ b/chromium/content/browser/renderer_host/input/tap_suppression_controller.cc
@@ -4,8 +4,8 @@
#include "content/browser/renderer_host/input/tap_suppression_controller.h"
-#include "base/debug/trace_event.h"
#include "base/logging.h"
+#include "base/trace_event/trace_event.h"
#include "content/browser/renderer_host/input/tap_suppression_controller_client.h"
namespace content {
diff --git a/chromium/content/browser/renderer_host/input/timeout_monitor.cc b/chromium/content/browser/renderer_host/input/timeout_monitor.cc
index 93b310286b0..f46464a194f 100644
--- a/chromium/content/browser/renderer_host/input/timeout_monitor.cc
+++ b/chromium/content/browser/renderer_host/input/timeout_monitor.cc
@@ -4,8 +4,10 @@
#include "content/browser/renderer_host/input/timeout_monitor.h"
-using base::Time;
+#include "base/trace_event/trace_event.h"
+
using base::TimeDelta;
+using base::TimeTicks;
namespace content {
@@ -14,14 +16,52 @@ TimeoutMonitor::TimeoutMonitor(const TimeoutHandler& timeout_handler)
DCHECK(!timeout_handler_.is_null());
}
-TimeoutMonitor::~TimeoutMonitor() {}
+TimeoutMonitor::~TimeoutMonitor() {
+ Stop();
+}
void TimeoutMonitor::Start(TimeDelta delay) {
+ if (!IsRunning()) {
+ TRACE_EVENT_ASYNC_BEGIN0("renderer_host", "TimeoutMonitor", this);
+ TRACE_EVENT_INSTANT0("renderer_host", "TimeoutMonitor::Start",
+ TRACE_EVENT_SCOPE_THREAD);
+ }
+
+ StartImpl(delay);
+}
+
+void TimeoutMonitor::Restart(TimeDelta delay) {
+ if (!IsRunning()) {
+ Start(delay);
+ return;
+ }
+
+ TRACE_EVENT_INSTANT0("renderer_host", "TimeoutMonitor::Restart",
+ TRACE_EVENT_SCOPE_THREAD);
+ // Setting to null will cause StartTimeoutMonitor to restart the timer.
+ time_when_considered_timed_out_ = TimeTicks();
+ StartImpl(delay);
+}
+
+void TimeoutMonitor::Stop() {
+ if (!IsRunning())
+ return;
+
+ // We do not bother to stop the timeout_timer_ here in case it will be
+ // started again shortly, which happens to be the common use case.
+ TRACE_EVENT_INSTANT0("renderer_host", "TimeoutMonitor::Stop",
+ TRACE_EVENT_SCOPE_THREAD);
+ TRACE_EVENT_ASYNC_END1("renderer_host", "TimeoutMonitor", this,
+ "result", "stopped");
+ time_when_considered_timed_out_ = TimeTicks();
+}
+
+void TimeoutMonitor::StartImpl(base::TimeDelta delay) {
// Set time_when_considered_timed_out_ if it's null. Also, update
// time_when_considered_timed_out_ if the caller's request is sooner than the
// existing one. This will have the side effect that the existing timeout will
// be forgotten.
- Time requested_end_time = Time::Now() + delay;
+ TimeTicks requested_end_time = TimeTicks::Now() + delay;
if (time_when_considered_timed_out_.is_null() ||
time_when_considered_timed_out_ > requested_end_time)
time_when_considered_timed_out_ = requested_end_time;
@@ -43,30 +83,24 @@ void TimeoutMonitor::Start(TimeDelta delay) {
timeout_timer_.Start(FROM_HERE, delay, this, &TimeoutMonitor::CheckTimedOut);
}
-void TimeoutMonitor::Restart(TimeDelta delay) {
- // Setting to null will cause StartTimeoutMonitor to restart the timer.
- time_when_considered_timed_out_ = Time();
- Start(delay);
-}
-
-void TimeoutMonitor::Stop() {
- // We do not bother to stop the timeout_timer_ here in case it will be
- // started again shortly, which happens to be the common use case.
- time_when_considered_timed_out_ = Time();
-}
-
void TimeoutMonitor::CheckTimedOut() {
// If we received a call to |Stop()|.
if (time_when_considered_timed_out_.is_null())
return;
// If we have not waited long enough, then wait some more.
- Time now = Time::Now();
+ TimeTicks now = TimeTicks::Now();
if (now < time_when_considered_timed_out_) {
- Start(time_when_considered_timed_out_ - now);
+ TRACE_EVENT_INSTANT0("renderer_host", "TimeoutMonitor::Reschedule",
+ TRACE_EVENT_SCOPE_THREAD);
+ StartImpl(time_when_considered_timed_out_ - now);
return;
}
+ TRACE_EVENT_ASYNC_END1("renderer_host", "TimeoutMonitor", this,
+ "result", "timed_out");
+ TRACE_EVENT0("renderer_host", "TimeoutMonitor::TimeOutHandler");
+ time_when_considered_timed_out_ = TimeTicks();
timeout_handler_.Run();
}
diff --git a/chromium/content/browser/renderer_host/input/timeout_monitor.h b/chromium/content/browser/renderer_host/input/timeout_monitor.h
index 88154e86e75..9c0729f2c76 100644
--- a/chromium/content/browser/renderer_host/input/timeout_monitor.h
+++ b/chromium/content/browser/renderer_host/input/timeout_monitor.h
@@ -31,13 +31,14 @@ class CONTENT_EXPORT TimeoutMonitor {
bool IsRunning() const;
private:
+ void StartImpl(base::TimeDelta delay);
void CheckTimedOut();
TimeoutHandler timeout_handler_;
// Indicates a time in the future when we would consider the input as
// having timed out, if it does not receive an appropriate stop request.
- base::Time time_when_considered_timed_out_;
+ base::TimeTicks time_when_considered_timed_out_;
// This timer runs to check if |time_when_considered_timed_out_| has past.
base::OneShotTimer<TimeoutMonitor> timeout_timer_;
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 c9d0a2bef86..38718b3f8c0 100644
--- a/chromium/content/browser/renderer_host/input/touch_action_browsertest.cc
+++ b/chromium/content/browser/renderer_host/input/touch_action_browsertest.cc
@@ -97,7 +97,7 @@ class TouchActionBrowserTest : public ContentBrowserTest {
}
// ContentBrowserTest:
- void SetUpCommandLine(CommandLine* cmd) override {
+ void SetUpCommandLine(base::CommandLine* cmd) override {
cmd->AppendSwitchASCII(switches::kTouchEvents,
switches::kTouchEventsEnabled);
// TODO(rbyers): Remove this switch once touch-action ships.
@@ -179,14 +179,8 @@ IN_PROC_BROWSER_TEST_F(TouchActionBrowserTest, DISABLED_DefaultAuto) {
EXPECT_EQ(1, ExecuteScriptAndExtractInt("eventCounts.touchstart"));
EXPECT_EQ(1, ExecuteScriptAndExtractInt("eventCounts.touchmove"));
- if (TouchEventQueue::TOUCH_SCROLLING_MODE_DEFAULT ==
- TouchEventQueue::TOUCH_SCROLLING_MODE_TOUCHCANCEL) {
- EXPECT_EQ(0, ExecuteScriptAndExtractInt("eventCounts.touchend"));
- EXPECT_EQ(1, ExecuteScriptAndExtractInt("eventCounts.touchcancel"));
- } else {
- EXPECT_EQ(1, ExecuteScriptAndExtractInt("eventCounts.touchend"));
- EXPECT_EQ(0, ExecuteScriptAndExtractInt("eventCounts.touchcancel"));
- }
+ EXPECT_EQ(1, ExecuteScriptAndExtractInt("eventCounts.touchend"));
+ EXPECT_EQ(0, ExecuteScriptAndExtractInt("eventCounts.touchcancel"));
}
// Verify that touching a touch-action: none region disables scrolling and
diff --git a/chromium/content/browser/renderer_host/input/touch_action_filter.cc b/chromium/content/browser/renderer_host/input/touch_action_filter.cc
index 53d47c4234c..b12f283c3e1 100644
--- a/chromium/content/browser/renderer_host/input/touch_action_filter.cc
+++ b/chromium/content/browser/renderer_host/input/touch_action_filter.cc
@@ -13,6 +13,19 @@ using blink::WebInputEvent;
using blink::WebGestureEvent;
namespace content {
+namespace {
+
+// Actions on an axis are disallowed if the perpendicular axis has a filter set
+// and no filter is set for the queried axis.
+bool IsYAxisActionDisallowed(TouchAction action) {
+ return ((action & TOUCH_ACTION_PAN_X) && !(action & TOUCH_ACTION_PAN_Y));
+}
+
+bool IsXAxisActionDisallowed(TouchAction action) {
+ return ((action & TOUCH_ACTION_PAN_Y) && !(action & TOUCH_ACTION_PAN_X));
+}
+
+} // namespace
TouchActionFilter::TouchActionFilter() :
drop_scroll_gesture_events_(false),
@@ -25,20 +38,22 @@ TouchActionFilter::TouchActionFilter() :
bool TouchActionFilter::FilterGestureEvent(WebGestureEvent* gesture_event) {
// Filter for allowable touch actions first (eg. before the TouchEventQueue
// can decide to send a touch cancel event).
- switch(gesture_event->type) {
+ switch (gesture_event->type) {
case WebInputEvent::GestureScrollBegin:
DCHECK(!drop_scroll_gesture_events_);
drop_scroll_gesture_events_ = ShouldSuppressScroll(*gesture_event);
return drop_scroll_gesture_events_;
case WebInputEvent::GestureScrollUpdate:
- if (drop_scroll_gesture_events_)
+ if (drop_scroll_gesture_events_) {
return true;
- else {
- if (allowed_touch_action_ == TOUCH_ACTION_PAN_X) {
+ } else {
+ // Scrolls restricted to a specific axis shouldn't permit movement
+ // in the perpendicular axis.
+ if (IsYAxisActionDisallowed(allowed_touch_action_)) {
gesture_event->data.scrollUpdate.deltaY = 0;
gesture_event->data.scrollUpdate.velocityY = 0;
- } else if (allowed_touch_action_ == TOUCH_ACTION_PAN_Y) {
+ } else if (IsXAxisActionDisallowed(allowed_touch_action_)) {
gesture_event->data.scrollUpdate.deltaX = 0;
gesture_event->data.scrollUpdate.velocityX = 0;
}
@@ -48,11 +63,22 @@ bool TouchActionFilter::FilterGestureEvent(WebGestureEvent* gesture_event) {
case WebInputEvent::GestureFlingStart:
if (gesture_event->sourceDevice != blink::WebGestureDeviceTouchscreen)
break;
+ // Touchscreen flings should always have non-zero velocity.
+ DCHECK(gesture_event->data.flingStart.velocityX ||
+ gesture_event->data.flingStart.velocityY);
if (!drop_scroll_gesture_events_) {
- if (allowed_touch_action_ == TOUCH_ACTION_PAN_X)
+ // Flings restricted to a specific axis shouldn't permit velocity
+ // in the perpendicular axis.
+ if (IsYAxisActionDisallowed(allowed_touch_action_))
gesture_event->data.flingStart.velocityY = 0;
- if (allowed_touch_action_ == TOUCH_ACTION_PAN_Y)
+ else if (IsXAxisActionDisallowed(allowed_touch_action_))
gesture_event->data.flingStart.velocityX = 0;
+ // As the renderer expects a scroll-ending event, but does not expect a
+ // zero-velocity fling, convert the now zero-velocity fling accordingly.
+ if (!gesture_event->data.flingStart.velocityX &&
+ !gesture_event->data.flingStart.velocityY) {
+ gesture_event->type = WebInputEvent::GestureScrollEnd;
+ }
}
return FilterScrollEndingGesture();
@@ -175,9 +201,27 @@ bool TouchActionFilter::ShouldSuppressScroll(
// Determine the primary initial axis of the scroll, and check whether
// panning along that axis is permitted.
if (fabs(gesture_event.data.scrollBegin.deltaXHint) >
- fabs(gesture_event.data.scrollBegin.deltaYHint))
- return !(allowed_touch_action_ & TOUCH_ACTION_PAN_X);
- return !(allowed_touch_action_ & TOUCH_ACTION_PAN_Y);
+ fabs(gesture_event.data.scrollBegin.deltaYHint)) {
+ if (gesture_event.data.scrollBegin.deltaXHint > 0 &&
+ allowed_touch_action_ & TOUCH_ACTION_PAN_LEFT) {
+ return false;
+ } else if (gesture_event.data.scrollBegin.deltaXHint < 0 &&
+ allowed_touch_action_ & TOUCH_ACTION_PAN_RIGHT) {
+ return false;
+ } else {
+ return true;
+ }
+ } else {
+ if (gesture_event.data.scrollBegin.deltaYHint > 0 &&
+ allowed_touch_action_ & TOUCH_ACTION_PAN_UP) {
+ return false;
+ } else if (gesture_event.data.scrollBegin.deltaYHint < 0 &&
+ allowed_touch_action_ & TOUCH_ACTION_PAN_DOWN) {
+ return false;
+ } else {
+ return true;
+ }
+ }
}
TouchAction TouchActionFilter::Intersect(TouchAction ta1, TouchAction ta2) {
@@ -194,4 +238,4 @@ TouchAction TouchActionFilter::Intersect(TouchAction ta1, TouchAction ta2) {
return static_cast<TouchAction>(ta1 & ta2);
}
-}
+} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/touch_action_filter.h b/chromium/content/browser/renderer_host/input/touch_action_filter.h
index 2eedc064209..4e27eaaa668 100644
--- a/chromium/content/browser/renderer_host/input/touch_action_filter.h
+++ b/chromium/content/browser/renderer_host/input/touch_action_filter.h
@@ -69,4 +69,4 @@ private:
};
}
-#endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_TOUCH_ACTION_FILTER_H_
+#endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_TOUCH_ACTION_FILTER_H_
diff --git a/chromium/content/browser/renderer_host/input/touch_action_filter_unittest.cc b/chromium/content/browser/renderer_host/input/touch_action_filter_unittest.cc
index aac1fb664a0..c435d1e67e8 100644
--- a/chromium/content/browser/renderer_host/input/touch_action_filter_unittest.cc
+++ b/chromium/content/browser/renderer_host/input/touch_action_filter_unittest.cc
@@ -13,6 +13,99 @@ using blink::WebGestureEvent;
using blink::WebInputEvent;
namespace content {
+namespace {
+
+const blink::WebGestureDevice kSourceDevice =
+ blink::WebGestureDeviceTouchscreen;
+
+} // namespace
+
+static void PanTest(TouchAction action,
+ float scroll_x,
+ float scroll_y,
+ float dx,
+ float dy,
+ float fling_x,
+ float fling_y,
+ float expected_dx,
+ float expected_dy,
+ float expected_fling_x,
+ float expected_fling_y) {
+ TouchActionFilter filter;
+ WebGestureEvent scroll_end = SyntheticWebGestureEventBuilder::Build(
+ WebInputEvent::GestureScrollEnd, kSourceDevice);
+
+ {
+ // Scrolls with no direction hint are permitted in the |action| direction.
+ filter.ResetTouchAction();
+ filter.OnSetTouchAction(action);
+
+ WebGestureEvent scroll_begin =
+ SyntheticWebGestureEventBuilder::BuildScrollBegin(0, 0);
+ EXPECT_FALSE(filter.FilterGestureEvent(&scroll_begin));
+
+ WebGestureEvent scroll_update =
+ SyntheticWebGestureEventBuilder::BuildScrollUpdate(dx, dy, 0,
+ kSourceDevice);
+ EXPECT_FALSE(filter.FilterGestureEvent(&scroll_update));
+ EXPECT_EQ(expected_dx, scroll_update.data.scrollUpdate.deltaX);
+ EXPECT_EQ(expected_dy, scroll_update.data.scrollUpdate.deltaY);
+
+ EXPECT_FALSE(filter.FilterGestureEvent(&scroll_end));
+ }
+
+ {
+ // Scrolls hinted mostly in the larger axis are permitted in that axis.
+ filter.ResetTouchAction();
+ filter.OnSetTouchAction(action);
+ WebGestureEvent scroll_begin =
+ SyntheticWebGestureEventBuilder::BuildScrollBegin(scroll_x, scroll_y);
+ EXPECT_FALSE(filter.FilterGestureEvent(&scroll_begin));
+
+ WebGestureEvent scroll_update =
+ SyntheticWebGestureEventBuilder::BuildScrollUpdate(dx, dy, 0,
+ kSourceDevice);
+ EXPECT_FALSE(filter.FilterGestureEvent(&scroll_update));
+ EXPECT_EQ(expected_dx, scroll_update.data.scrollUpdate.deltaX);
+ EXPECT_EQ(expected_dy, scroll_update.data.scrollUpdate.deltaY);
+
+ // Ensure that scrolls in the opposite direction are not filtered once
+ // scrolling has started. (Once scrolling is started, the direction may
+ // be reversed by the user even if scrolls that start in the reversed
+ // direction are disallowed.
+ WebGestureEvent scroll_update2 =
+ SyntheticWebGestureEventBuilder::BuildScrollUpdate(-dx, -dy, 0,
+ kSourceDevice);
+ EXPECT_FALSE(filter.FilterGestureEvent(&scroll_update2));
+ EXPECT_EQ(-expected_dx, scroll_update2.data.scrollUpdate.deltaX);
+ EXPECT_EQ(-expected_dy, scroll_update2.data.scrollUpdate.deltaY);
+
+ WebGestureEvent fling_start = SyntheticWebGestureEventBuilder::BuildFling(
+ fling_x, fling_y, kSourceDevice);
+ EXPECT_FALSE(filter.FilterGestureEvent(&fling_start));
+ EXPECT_EQ(expected_fling_x, fling_start.data.flingStart.velocityX);
+ EXPECT_EQ(expected_fling_y, fling_start.data.flingStart.velocityY);
+ }
+
+ {
+ // Scrolls hinted mostly in the opposite direction are suppressed entirely.
+ filter.ResetTouchAction();
+ filter.OnSetTouchAction(action);
+ WebGestureEvent scroll_begin =
+ SyntheticWebGestureEventBuilder::BuildScrollBegin(scroll_y, scroll_x);
+ EXPECT_TRUE(filter.FilterGestureEvent(&scroll_begin));
+
+ WebGestureEvent scroll_update =
+ SyntheticWebGestureEventBuilder::BuildScrollUpdate(dx, dy, 0,
+ kSourceDevice);
+ EXPECT_TRUE(filter.FilterGestureEvent(&scroll_update));
+ EXPECT_EQ(dx, scroll_update.data.scrollUpdate.deltaX);
+ EXPECT_EQ(dy, scroll_update.data.scrollUpdate.deltaY);
+
+ EXPECT_TRUE(filter.FilterGestureEvent(&scroll_end));
+ }
+ filter.ResetTouchAction();
+}
TEST(TouchActionFilterTest, SimpleFilter) {
TouchActionFilter filter;
@@ -22,11 +115,12 @@ TEST(TouchActionFilterTest, SimpleFilter) {
const float kDeltaX = 5;
const float kDeltaY = 10;
WebGestureEvent scroll_update =
- SyntheticWebGestureEventBuilder::BuildScrollUpdate(kDeltaX, kDeltaY, 0);
+ SyntheticWebGestureEventBuilder::BuildScrollUpdate(kDeltaX, kDeltaY, 0,
+ kSourceDevice);
WebGestureEvent scroll_end = SyntheticWebGestureEventBuilder::Build(
- WebInputEvent::GestureScrollEnd, blink::WebGestureDeviceTouchscreen);
+ WebInputEvent::GestureScrollEnd, kSourceDevice);
WebGestureEvent tap = SyntheticWebGestureEventBuilder::Build(
- WebInputEvent::GestureTap, blink::WebGestureDeviceTouchscreen);
+ WebInputEvent::GestureTap, kSourceDevice);
// No events filtered by default.
filter.ResetTouchAction();
@@ -95,11 +189,12 @@ TEST(TouchActionFilterTest, Fling) {
WebGestureEvent scroll_begin =
SyntheticWebGestureEventBuilder::BuildScrollBegin(2, 3);
WebGestureEvent scroll_update =
- SyntheticWebGestureEventBuilder::BuildScrollUpdate(5, 10, 0);
+ SyntheticWebGestureEventBuilder::BuildScrollUpdate(5, 10, 0,
+ kSourceDevice);
const float kFlingX = 7;
const float kFlingY = -4;
WebGestureEvent fling_start = SyntheticWebGestureEventBuilder::BuildFling(
- kFlingX, kFlingY, blink::WebGestureDeviceTouchscreen);
+ kFlingX, kFlingY, kSourceDevice);
WebGestureEvent pad_fling = SyntheticWebGestureEventBuilder::BuildFling(
kFlingX, kFlingY, blink::WebGestureDeviceTouchpad);
@@ -122,150 +217,76 @@ TEST(TouchActionFilterTest, Fling) {
filter.ResetTouchAction();
}
-TEST(TouchActionFilterTest, PanX) {
- TouchActionFilter filter;
+TEST(TouchActionFilterTest, PanLeft) {
const float kDX = 5;
const float kDY = 10;
+ const float kScrollX = 7;
+ const float kScrollY = 6;
const float kFlingX = 7;
const float kFlingY = -4;
- WebGestureEvent scroll_end = SyntheticWebGestureEventBuilder::Build(
- WebInputEvent::GestureScrollEnd, blink::WebGestureDeviceTouchscreen);
- {
- // Scrolls with no direction hint are permitted in the X axis.
- filter.ResetTouchAction();
- filter.OnSetTouchAction(TOUCH_ACTION_PAN_X);
-
- WebGestureEvent scroll_begin =
- SyntheticWebGestureEventBuilder::BuildScrollBegin(0, 0);
- EXPECT_FALSE(filter.FilterGestureEvent(&scroll_begin));
-
- WebGestureEvent scroll_update =
- SyntheticWebGestureEventBuilder::BuildScrollUpdate(kDX, kDY, 0);
- EXPECT_FALSE(filter.FilterGestureEvent(&scroll_update));
- EXPECT_EQ(kDX, scroll_update.data.scrollUpdate.deltaX);
- EXPECT_EQ(0, scroll_update.data.scrollUpdate.deltaY);
+ PanTest(TOUCH_ACTION_PAN_LEFT, kScrollX, kScrollY, kDX, kDY, kFlingX, kFlingY,
+ kDX, 0, kFlingX, 0);
+}
- EXPECT_FALSE(filter.FilterGestureEvent(&scroll_end));
- }
+TEST(TouchActionFilterTest, PanRight) {
+ const float kDX = 5;
+ const float kDY = 10;
+ const float kScrollX = -7;
+ const float kScrollY = 6;
+ const float kFlingX = 7;
+ const float kFlingY = -4;
- {
- // Scrolls hinted mostly in the X axis are permitted in that axis.
- filter.ResetTouchAction();
- filter.OnSetTouchAction(TOUCH_ACTION_PAN_X);
- WebGestureEvent scroll_begin =
- SyntheticWebGestureEventBuilder::BuildScrollBegin(-7, 6);
- EXPECT_FALSE(filter.FilterGestureEvent(&scroll_begin));
+ PanTest(TOUCH_ACTION_PAN_RIGHT, kScrollX, kScrollY, kDX, kDY, kFlingX,
+ kFlingY, kDX, 0, kFlingX, 0);
+}
- WebGestureEvent scroll_update =
- SyntheticWebGestureEventBuilder::BuildScrollUpdate(kDX, kDY, 0);
- EXPECT_FALSE(filter.FilterGestureEvent(&scroll_update));
- EXPECT_EQ(kDX, scroll_update.data.scrollUpdate.deltaX);
- EXPECT_EQ(0, scroll_update.data.scrollUpdate.deltaY);
+TEST(TouchActionFilterTest, PanX) {
+ const float kDX = 5;
+ const float kDY = 10;
+ const float kScrollX = 7;
+ const float kScrollY = 6;
+ const float kFlingX = 7;
+ const float kFlingY = -4;
- WebGestureEvent scroll_update2 =
- SyntheticWebGestureEventBuilder::BuildScrollUpdate(-4, -2, 0);
- EXPECT_FALSE(filter.FilterGestureEvent(&scroll_update2));
- EXPECT_EQ(-4, scroll_update2.data.scrollUpdate.deltaX);
- EXPECT_EQ(0, scroll_update2.data.scrollUpdate.deltaY);
+ PanTest(TOUCH_ACTION_PAN_X, kScrollX, kScrollY, kDX, kDY, kFlingX, kFlingY,
+ kDX, 0, kFlingX, 0);
+}
- WebGestureEvent fling_start = SyntheticWebGestureEventBuilder::BuildFling(
- kFlingX, kFlingY, blink::WebGestureDeviceTouchscreen);
- EXPECT_FALSE(filter.FilterGestureEvent(&fling_start));
- EXPECT_EQ(kFlingX, fling_start.data.flingStart.velocityX);
- EXPECT_EQ(0, fling_start.data.flingStart.velocityY);
- }
+TEST(TouchActionFilterTest, PanUp) {
+ const float kDX = 5;
+ const float kDY = 10;
+ const float kScrollX = 6;
+ const float kScrollY = 7;
+ const float kFlingX = 7;
+ const float kFlingY = -4;
- {
- // Scrolls hinted mostly in the Y direction are suppressed entirely.
- filter.ResetTouchAction();
- filter.OnSetTouchAction(TOUCH_ACTION_PAN_X);
- WebGestureEvent scroll_begin =
- SyntheticWebGestureEventBuilder::BuildScrollBegin(-7, 8);
- EXPECT_TRUE(filter.FilterGestureEvent(&scroll_begin));
+ PanTest(TOUCH_ACTION_PAN_UP, kScrollX, kScrollY, kDX, kDY, kFlingX, kFlingY,
+ 0, kDY, 0, kFlingY);
+}
- WebGestureEvent scroll_update =
- SyntheticWebGestureEventBuilder::BuildScrollUpdate(kDX, kDY, 0);
- EXPECT_TRUE(filter.FilterGestureEvent(&scroll_update));
- EXPECT_EQ(kDX, scroll_update.data.scrollUpdate.deltaX);
- EXPECT_EQ(kDY, scroll_update.data.scrollUpdate.deltaY);
+TEST(TouchActionFilterTest, PanDown) {
+ const float kDX = 5;
+ const float kDY = 10;
+ const float kScrollX = 6;
+ const float kScrollY = -7;
+ const float kFlingX = 7;
+ const float kFlingY = -4;
- EXPECT_TRUE(filter.FilterGestureEvent(&scroll_end));
- }
- filter.ResetTouchAction();
+ PanTest(TOUCH_ACTION_PAN_DOWN, kScrollX, kScrollY, kDX, kDY, kFlingX, kFlingY,
+ 0, kDY, 0, kFlingY);
}
TEST(TouchActionFilterTest, PanY) {
- TouchActionFilter filter;
const float kDX = 5;
const float kDY = 10;
+ const float kScrollX = 6;
+ const float kScrollY = 7;
const float kFlingX = 7;
const float kFlingY = -4;
- WebGestureEvent scroll_end = SyntheticWebGestureEventBuilder::Build(
- WebInputEvent::GestureScrollEnd, blink::WebGestureDeviceTouchscreen);
-
- {
- // Scrolls with no direction hint are permitted in the Y axis.
- filter.ResetTouchAction();
- filter.OnSetTouchAction(TOUCH_ACTION_PAN_Y);
-
- WebGestureEvent scroll_begin =
- SyntheticWebGestureEventBuilder::BuildScrollBegin(0, 0);
- EXPECT_FALSE(filter.FilterGestureEvent(&scroll_begin));
- WebGestureEvent scroll_update =
- SyntheticWebGestureEventBuilder::BuildScrollUpdate(kDX, kDY, 0);
- EXPECT_FALSE(filter.FilterGestureEvent(&scroll_update));
- EXPECT_EQ(0, scroll_update.data.scrollUpdate.deltaX);
- EXPECT_EQ(kDY, scroll_update.data.scrollUpdate.deltaY);
-
- EXPECT_FALSE(filter.FilterGestureEvent(&scroll_end));
- }
-
- {
- // Scrolls hinted mostly in the Y axis are permitted in that axis.
- filter.ResetTouchAction();
- filter.OnSetTouchAction(TOUCH_ACTION_PAN_Y);
- WebGestureEvent scroll_begin =
- SyntheticWebGestureEventBuilder::BuildScrollBegin(-6, 7);
- EXPECT_FALSE(filter.FilterGestureEvent(&scroll_begin));
-
- WebGestureEvent scroll_update =
- SyntheticWebGestureEventBuilder::BuildScrollUpdate(kDX, kDY, 0);
- EXPECT_FALSE(filter.FilterGestureEvent(&scroll_update));
- EXPECT_EQ(0, scroll_update.data.scrollUpdate.deltaX);
- EXPECT_EQ(kDY, scroll_update.data.scrollUpdate.deltaY);
-
- WebGestureEvent scroll_update2 =
- SyntheticWebGestureEventBuilder::BuildScrollUpdate(-4, -2, 0);
- EXPECT_FALSE(filter.FilterGestureEvent(&scroll_update2));
- EXPECT_EQ(0, scroll_update2.data.scrollUpdate.deltaX);
- EXPECT_EQ(-2, scroll_update2.data.scrollUpdate.deltaY);
-
- WebGestureEvent fling_start = SyntheticWebGestureEventBuilder::BuildFling(
- kFlingX, kFlingY, blink::WebGestureDeviceTouchscreen);
- EXPECT_FALSE(filter.FilterGestureEvent(&fling_start));
- EXPECT_EQ(0, fling_start.data.flingStart.velocityX);
- EXPECT_EQ(kFlingY, fling_start.data.flingStart.velocityY);
- }
-
- {
- // Scrolls hinted mostly in the X direction are suppressed entirely.
- filter.ResetTouchAction();
- filter.OnSetTouchAction(TOUCH_ACTION_PAN_Y);
- WebGestureEvent scroll_begin =
- SyntheticWebGestureEventBuilder::BuildScrollBegin(-8, 7);
- EXPECT_TRUE(filter.FilterGestureEvent(&scroll_begin));
-
- WebGestureEvent scroll_update =
- SyntheticWebGestureEventBuilder::BuildScrollUpdate(kDX, kDY, 0);
- EXPECT_TRUE(filter.FilterGestureEvent(&scroll_update));
- EXPECT_EQ(kDX, scroll_update.data.scrollUpdate.deltaX);
- EXPECT_EQ(kDY, scroll_update.data.scrollUpdate.deltaY);
-
- EXPECT_TRUE(filter.FilterGestureEvent(&scroll_end));
- }
- filter.ResetTouchAction();
+ PanTest(TOUCH_ACTION_PAN_Y, kScrollX, kScrollY, kDX, kDY, kFlingX, kFlingY, 0,
+ kDY, 0, kFlingY);
}
TEST(TouchActionFilterTest, PanXY) {
@@ -284,13 +305,14 @@ TEST(TouchActionFilterTest, PanXY) {
EXPECT_FALSE(filter.FilterGestureEvent(&scroll_begin));
WebGestureEvent scroll_update =
- SyntheticWebGestureEventBuilder::BuildScrollUpdate(kDX, kDY, 0);
+ SyntheticWebGestureEventBuilder::BuildScrollUpdate(kDX, kDY, 0,
+ kSourceDevice);
EXPECT_FALSE(filter.FilterGestureEvent(&scroll_update));
EXPECT_EQ(kDX, scroll_update.data.scrollUpdate.deltaX);
EXPECT_EQ(kDY, scroll_update.data.scrollUpdate.deltaY);
WebGestureEvent fling_start = SyntheticWebGestureEventBuilder::BuildFling(
- kFlingX, kFlingY, blink::WebGestureDeviceTouchscreen);
+ kFlingX, kFlingY, kSourceDevice);
EXPECT_FALSE(filter.FilterGestureEvent(&fling_start));
EXPECT_EQ(kFlingX, fling_start.data.flingStart.velocityX);
EXPECT_EQ(kFlingY, fling_start.data.flingStart.velocityY);
@@ -305,13 +327,14 @@ TEST(TouchActionFilterTest, PanXY) {
EXPECT_FALSE(filter.FilterGestureEvent(&scroll_begin));
WebGestureEvent scroll_update =
- SyntheticWebGestureEventBuilder::BuildScrollUpdate(kDX, kDY, 0);
+ SyntheticWebGestureEventBuilder::BuildScrollUpdate(kDX, kDY, 0,
+ kSourceDevice);
EXPECT_FALSE(filter.FilterGestureEvent(&scroll_update));
EXPECT_EQ(kDX, scroll_update.data.scrollUpdate.deltaX);
EXPECT_EQ(kDY, scroll_update.data.scrollUpdate.deltaY);
WebGestureEvent fling_start = SyntheticWebGestureEventBuilder::BuildFling(
- kFlingX, kFlingY, blink::WebGestureDeviceTouchscreen);
+ kFlingX, kFlingY, kSourceDevice);
EXPECT_FALSE(filter.FilterGestureEvent(&fling_start));
EXPECT_EQ(kFlingX, fling_start.data.flingStart.velocityX);
EXPECT_EQ(kFlingY, fling_start.data.flingStart.velocityY);
@@ -348,9 +371,10 @@ TEST(TouchActionFilterTest, MultiTouch) {
const float kDeltaX = 5;
const float kDeltaY = 10;
WebGestureEvent scroll_update =
- SyntheticWebGestureEventBuilder::BuildScrollUpdate(kDeltaX, kDeltaY, 0);
+ SyntheticWebGestureEventBuilder::BuildScrollUpdate(kDeltaX, kDeltaY, 0,
+ kSourceDevice);
WebGestureEvent scroll_end = SyntheticWebGestureEventBuilder::Build(
- WebInputEvent::GestureScrollEnd, blink::WebGestureDeviceTouchscreen);
+ WebInputEvent::GestureScrollEnd, kSourceDevice);
// For multiple points, the intersection is what matters.
filter.ResetTouchAction();
@@ -380,14 +404,14 @@ TEST(TouchActionFilterTest, Pinch) {
WebGestureEvent scroll_begin =
SyntheticWebGestureEventBuilder::BuildScrollBegin(2, 3);
WebGestureEvent pinch_begin = SyntheticWebGestureEventBuilder::Build(
- WebInputEvent::GesturePinchBegin, blink::WebGestureDeviceTouchscreen);
+ WebInputEvent::GesturePinchBegin, kSourceDevice);
WebGestureEvent pinch_update =
- SyntheticWebGestureEventBuilder::BuildPinchUpdate(
- 1.2f, 5, 5, 0, blink::WebGestureDeviceTouchscreen);
+ SyntheticWebGestureEventBuilder::BuildPinchUpdate(1.2f, 5, 5, 0,
+ kSourceDevice);
WebGestureEvent pinch_end = SyntheticWebGestureEventBuilder::Build(
- WebInputEvent::GesturePinchEnd, blink::WebGestureDeviceTouchscreen);
+ WebInputEvent::GesturePinchEnd, kSourceDevice);
WebGestureEvent scroll_end = SyntheticWebGestureEventBuilder::Build(
- WebInputEvent::GestureScrollEnd, blink::WebGestureDeviceTouchscreen);
+ WebInputEvent::GestureScrollEnd, kSourceDevice);
// Pinch is allowed with touch-action: auto.
filter.ResetTouchAction();
@@ -476,13 +500,13 @@ TEST(TouchActionFilterTest, DoubleTapWithTouchActionAuto) {
TouchActionFilter filter;
WebGestureEvent tap_down = SyntheticWebGestureEventBuilder::Build(
- WebInputEvent::GestureTapDown, blink::WebGestureDeviceTouchscreen);
+ WebInputEvent::GestureTapDown, kSourceDevice);
WebGestureEvent unconfirmed_tap = SyntheticWebGestureEventBuilder::Build(
- WebInputEvent::GestureTapUnconfirmed, blink::WebGestureDeviceTouchscreen);
+ WebInputEvent::GestureTapUnconfirmed, kSourceDevice);
WebGestureEvent tap_cancel = SyntheticWebGestureEventBuilder::Build(
- WebInputEvent::GestureTapCancel, blink::WebGestureDeviceTouchscreen);
+ WebInputEvent::GestureTapCancel, kSourceDevice);
WebGestureEvent double_tap = SyntheticWebGestureEventBuilder::Build(
- WebInputEvent::GestureDoubleTap, blink::WebGestureDeviceTouchscreen);
+ WebInputEvent::GestureDoubleTap, kSourceDevice);
// Double tap is allowed with touch action auto.
filter.ResetTouchAction();
@@ -504,13 +528,13 @@ TEST(TouchActionFilterTest, DoubleTap) {
TouchActionFilter filter;
WebGestureEvent tap_down = SyntheticWebGestureEventBuilder::Build(
- WebInputEvent::GestureTapDown, blink::WebGestureDeviceTouchscreen);
+ WebInputEvent::GestureTapDown, kSourceDevice);
WebGestureEvent unconfirmed_tap = SyntheticWebGestureEventBuilder::Build(
- WebInputEvent::GestureTapUnconfirmed, blink::WebGestureDeviceTouchscreen);
+ WebInputEvent::GestureTapUnconfirmed, kSourceDevice);
WebGestureEvent tap_cancel = SyntheticWebGestureEventBuilder::Build(
- WebInputEvent::GestureTapCancel, blink::WebGestureDeviceTouchscreen);
+ WebInputEvent::GestureTapCancel, kSourceDevice);
WebGestureEvent double_tap = SyntheticWebGestureEventBuilder::Build(
- WebInputEvent::GestureDoubleTap, blink::WebGestureDeviceTouchscreen);
+ WebInputEvent::GestureDoubleTap, kSourceDevice);
// Double tap is disabled with any touch action other than auto.
filter.ResetTouchAction();
@@ -533,11 +557,11 @@ TEST(TouchActionFilterTest, SingleTapWithTouchActionAuto) {
TouchActionFilter filter;
WebGestureEvent tap_down = SyntheticWebGestureEventBuilder::Build(
- WebInputEvent::GestureTapDown, blink::WebGestureDeviceTouchscreen);
+ WebInputEvent::GestureTapDown, kSourceDevice);
WebGestureEvent unconfirmed_tap1 = SyntheticWebGestureEventBuilder::Build(
- WebInputEvent::GestureTapUnconfirmed, blink::WebGestureDeviceTouchscreen);
+ WebInputEvent::GestureTapUnconfirmed, kSourceDevice);
WebGestureEvent tap = SyntheticWebGestureEventBuilder::Build(
- WebInputEvent::GestureTap, blink::WebGestureDeviceTouchscreen);
+ WebInputEvent::GestureTap, kSourceDevice);
// Single tap is allowed with touch action auto.
filter.ResetTouchAction();
@@ -552,11 +576,11 @@ TEST(TouchActionFilterTest, SingleTap) {
TouchActionFilter filter;
WebGestureEvent tap_down = SyntheticWebGestureEventBuilder::Build(
- WebInputEvent::GestureTapDown, blink::WebGestureDeviceTouchscreen);
+ WebInputEvent::GestureTapDown, kSourceDevice);
WebGestureEvent unconfirmed_tap1 = SyntheticWebGestureEventBuilder::Build(
- WebInputEvent::GestureTapUnconfirmed, blink::WebGestureDeviceTouchscreen);
+ WebInputEvent::GestureTapUnconfirmed, kSourceDevice);
WebGestureEvent tap = SyntheticWebGestureEventBuilder::Build(
- WebInputEvent::GestureTap, blink::WebGestureDeviceTouchscreen);
+ WebInputEvent::GestureTap, kSourceDevice);
// With touch action other than auto, tap unconfirmed is turned into tap.
filter.ResetTouchAction();
@@ -572,11 +596,11 @@ TEST(TouchActionFilterTest, TouchActionResetsOnResetTouchAction) {
TouchActionFilter filter;
WebGestureEvent tap = SyntheticWebGestureEventBuilder::Build(
- WebInputEvent::GestureTap, blink::WebGestureDeviceTouchscreen);
+ WebInputEvent::GestureTap, kSourceDevice);
WebGestureEvent scroll_begin =
SyntheticWebGestureEventBuilder::BuildScrollBegin(2, 3);
WebGestureEvent scroll_end = SyntheticWebGestureEventBuilder::Build(
- WebInputEvent::GestureScrollEnd, blink::WebGestureDeviceTouchscreen);
+ WebInputEvent::GestureScrollEnd, kSourceDevice);
filter.ResetTouchAction();
filter.OnSetTouchAction(TOUCH_ACTION_NONE);
@@ -597,14 +621,14 @@ TEST(TouchActionFilterTest, TouchActionResetMidSequence) {
WebGestureEvent scroll_begin =
SyntheticWebGestureEventBuilder::BuildScrollBegin(2, 3);
WebGestureEvent pinch_begin = SyntheticWebGestureEventBuilder::Build(
- WebInputEvent::GesturePinchBegin, blink::WebGestureDeviceTouchscreen);
+ WebInputEvent::GesturePinchBegin, kSourceDevice);
WebGestureEvent pinch_update =
- SyntheticWebGestureEventBuilder::BuildPinchUpdate(
- 1.2f, 5, 5, 0, blink::WebGestureDeviceTouchscreen);
+ SyntheticWebGestureEventBuilder::BuildPinchUpdate(1.2f, 5, 5, 0,
+ kSourceDevice);
WebGestureEvent pinch_end = SyntheticWebGestureEventBuilder::Build(
- WebInputEvent::GesturePinchEnd, blink::WebGestureDeviceTouchscreen);
+ WebInputEvent::GesturePinchEnd, kSourceDevice);
WebGestureEvent scroll_end = SyntheticWebGestureEventBuilder::Build(
- WebInputEvent::GestureScrollEnd, blink::WebGestureDeviceTouchscreen);
+ WebInputEvent::GestureScrollEnd, kSourceDevice);
filter.OnSetTouchAction(TOUCH_ACTION_NONE);
EXPECT_TRUE(filter.FilterGestureEvent(&scroll_begin));
@@ -630,4 +654,42 @@ TEST(TouchActionFilterTest, TouchActionResetMidSequence) {
EXPECT_FALSE(filter.FilterGestureEvent(&scroll_end));
}
+TEST(TouchActionFilterTest, ZeroVelocityFlingsConvertedToScrollEnd) {
+ TouchActionFilter filter;
+ const float kFlingX = 7;
+ const float kFlingY = -4;
+
+ {
+ // Scrolls hinted mostly in the Y axis will suppress flings with a
+ // component solely on the X axis, converting them to a GestureScrollEnd.
+ filter.ResetTouchAction();
+ filter.OnSetTouchAction(TOUCH_ACTION_PAN_Y);
+ WebGestureEvent scroll_begin =
+ SyntheticWebGestureEventBuilder::BuildScrollBegin(-6, 7);
+ EXPECT_FALSE(filter.FilterGestureEvent(&scroll_begin));
+
+ WebGestureEvent fling_start = SyntheticWebGestureEventBuilder::BuildFling(
+ kFlingX, 0, kSourceDevice);
+ EXPECT_FALSE(filter.FilterGestureEvent(&fling_start));
+ EXPECT_EQ(WebInputEvent::GestureScrollEnd, fling_start.type);
+ }
+
+ filter.ResetTouchAction();
+
+ {
+ // Scrolls hinted mostly in the X axis will suppress flings with a
+ // component solely on the Y axis, converting them to a GestureScrollEnd.
+ filter.ResetTouchAction();
+ filter.OnSetTouchAction(TOUCH_ACTION_PAN_X);
+ WebGestureEvent scroll_begin =
+ SyntheticWebGestureEventBuilder::BuildScrollBegin(-7, 6);
+ EXPECT_FALSE(filter.FilterGestureEvent(&scroll_begin));
+
+ WebGestureEvent fling_start = SyntheticWebGestureEventBuilder::BuildFling(
+ 0, kFlingY, kSourceDevice);
+ EXPECT_FALSE(filter.FilterGestureEvent(&fling_start));
+ EXPECT_EQ(WebInputEvent::GestureScrollEnd, fling_start.type);
+ }
+}
+
} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/touch_emulator.cc b/chromium/content/browser/renderer_host/input/touch_emulator.cc
index 61ae63ef1ff..8388e09e337 100644
--- a/chromium/content/browser/renderer_host/input/touch_emulator.cc
+++ b/chromium/content/browser/renderer_host/input/touch_emulator.cc
@@ -11,6 +11,8 @@
#include "content/public/common/content_client.h"
#include "content/public/common/content_switches.h"
#include "third_party/WebKit/public/platform/WebCursorInfo.h"
+#include "ui/events/base_event_utils.h"
+#include "ui/events/blink/blink_event_util.h"
#include "ui/events/gesture_detection/gesture_provider_config_helper.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/screen.h"
@@ -27,10 +29,10 @@ namespace content {
namespace {
-ui::GestureProvider::Config GetGestureProviderConfig() {
- // TODO(dgozman): Use different configs to emulate mobile/desktop as
- // requested by renderer.
- ui::GestureProvider::Config config = ui::DefaultGestureProviderConfig();
+ui::GestureProvider::Config GetEmulatorGestureProviderConfig(
+ ui::GestureProviderConfigType config_type) {
+ ui::GestureProvider::Config config =
+ ui::GetGestureProviderConfig(config_type);
config.gesture_begin_end_types_enabled = false;
config.gesture_detector_config.swipe_enabled = false;
config.gesture_detector_config.two_finger_tap_enabled = false;
@@ -45,8 +47,9 @@ const double kMouseMoveDropIntervalSeconds = 5.f / 1000;
TouchEmulator::TouchEmulator(TouchEmulatorClient* client)
: client_(client),
- gesture_provider_(GetGestureProviderConfig(), this),
- enabled_(false),
+ gesture_provider_config_type_(
+ ui::GestureProviderConfigType::CURRENT_PLATFORM),
+ double_tap_enabled_(true),
emulated_stream_active_sequence_count_(0),
native_stream_active_sequence_count_(0) {
DCHECK(client_);
@@ -67,12 +70,6 @@ TouchEmulator::TouchEmulator(TouchEmulatorClient* client)
WebCursor::CursorInfo cursor_info;
cursor_info.type = blink::WebCursorInfo::TypePointer;
pointer_cursor_.InitFromCursorInfo(cursor_info);
-
- // TODO(dgozman): Use synthetic secondary touch to support multi-touch.
- gesture_provider_.SetMultiTouchZoomSupportEnabled(false);
- // TODO(dgozman): Enable double tap if requested by the renderer.
- // TODO(dgozman): Don't break double-tap-based pinch with shift handling.
- gesture_provider_.SetDoubleTapSupportForPlatformEnabled(false);
}
TouchEmulator::~TouchEmulator() {
@@ -91,21 +88,32 @@ void TouchEmulator::ResetState() {
pinch_gesture_active_ = false;
}
-void TouchEmulator::Enable() {
- if (!enabled_) {
- enabled_ = true;
- ResetState();
+void TouchEmulator::Enable(ui::GestureProviderConfigType config_type) {
+ if (!gesture_provider_ || gesture_provider_config_type_ != config_type) {
+ gesture_provider_config_type_ = config_type;
+ gesture_provider_.reset(new ui::FilteredGestureProvider(
+ GetEmulatorGestureProviderConfig(config_type), this));
+ // TODO(dgozman): Use synthetic secondary touch to support multi-touch.
+ gesture_provider_->SetMultiTouchZoomSupportEnabled(false);
+ gesture_provider_->SetDoubleTapSupportForPageEnabled(double_tap_enabled_);
}
UpdateCursor();
}
void TouchEmulator::Disable() {
- if (!enabled_)
+ if (!enabled())
return;
- enabled_ = false;
- UpdateCursor();
CancelTouch();
+ gesture_provider_.reset();
+ UpdateCursor();
+ ResetState();
+}
+
+void TouchEmulator::SetDoubleTapSupportForPageEnabled(bool enabled) {
+ double_tap_enabled_ = enabled;
+ if (gesture_provider_)
+ gesture_provider_->SetDoubleTapSupportForPageEnabled(enabled);
}
gfx::SizeF TouchEmulator::InitCursorFromResource(
@@ -127,7 +135,7 @@ gfx::SizeF TouchEmulator::InitCursorFromResource(
}
bool TouchEmulator::HandleMouseEvent(const WebMouseEvent& mouse_event) {
- if (!enabled_)
+ if (!enabled())
return false;
if (mouse_event.button == WebMouseEvent::ButtonRight &&
@@ -157,17 +165,21 @@ bool TouchEmulator::HandleMouseEvent(const WebMouseEvent& mouse_event) {
UpdateShiftPressed((mouse_event.modifiers & WebInputEvent::ShiftKey) != 0);
- if (FillTouchEventAndPoint(mouse_event) &&
- gesture_provider_.OnTouchEvent(MotionEventWeb(touch_event_))) {
- ForwardTouchEventToClient();
+ if (mouse_event.type != WebInputEvent::MouseDown &&
+ mouse_event.type != WebInputEvent::MouseMove &&
+ mouse_event.type != WebInputEvent::MouseUp) {
+ return true;
}
+ FillTouchEventAndPoint(mouse_event);
+ HandleEmulatedTouchEvent(touch_event_);
+
// Do not pass mouse events to the renderer.
return true;
}
bool TouchEmulator::HandleMouseWheelEvent(const WebMouseWheelEvent& event) {
- if (!enabled_)
+ if (!enabled())
return false;
// Send mouse wheel for easy scrolling when there is no active touch.
@@ -175,7 +187,7 @@ bool TouchEmulator::HandleMouseWheelEvent(const WebMouseWheelEvent& event) {
}
bool TouchEmulator::HandleKeyboardEvent(const WebKeyboardEvent& event) {
- if (!enabled_)
+ if (!enabled())
return false;
if (!UpdateShiftPressed((event.modifiers & WebInputEvent::ShiftKey) != 0))
@@ -212,25 +224,32 @@ bool TouchEmulator::HandleTouchEvent(const blink::WebTouchEvent& event) {
return false;
}
-void TouchEmulator::ForwardTouchEventToClient() {
+void TouchEmulator::HandleEmulatedTouchEvent(blink::WebTouchEvent event) {
+ DCHECK(gesture_provider_);
+ event.uniqueTouchEventId = ui::GetNextTouchEventId();
+ auto result = gesture_provider_->OnTouchEvent(MotionEventWeb(event));
+ if (!result.succeeded)
+ return;
+
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);
+ gesture_provider_->OnSyncTouchEventAck(event_consumed);
return;
}
- bool is_sequence_start =
- WebTouchEventTraits::IsTouchSequenceStart(touch_event_);
+ bool is_sequence_start = WebTouchEventTraits::IsTouchSequenceStart(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);
+ gesture_provider_->OnSyncTouchEventAck(event_consumed);
return;
}
if (is_sequence_start)
emulated_stream_active_sequence_count_++;
- client_->ForwardEmulatedTouchEvent(touch_event_);
+
+ event.causesScrollingIfUncanceled = result.did_generate_scroll;
+ client_->ForwardEmulatedTouchEvent(event);
}
bool TouchEmulator::HandleTouchEventAck(
@@ -241,7 +260,8 @@ bool TouchEmulator::HandleTouchEventAck(
emulated_stream_active_sequence_count_--;
const bool event_consumed = ack_result == INPUT_EVENT_ACK_STATE_CONSUMED;
- gesture_provider_.OnTouchEventAck(event_consumed);
+ if (gesture_provider_)
+ gesture_provider_->OnAsyncTouchEventAck(event_consumed);
return true;
}
@@ -254,7 +274,7 @@ bool TouchEmulator::HandleTouchEventAck(
void TouchEmulator::OnGestureEvent(const ui::GestureEventData& gesture) {
WebGestureEvent gesture_event =
- CreateWebGestureEventFromGestureEventData(gesture);
+ ui::CreateWebGestureEventFromGestureEventData(gesture);
switch (gesture_event.type) {
case WebInputEvent::Undefined:
@@ -319,20 +339,20 @@ void TouchEmulator::OnGestureEvent(const ui::GestureEventData& gesture) {
}
void TouchEmulator::CancelTouch() {
- if (!emulated_stream_active_sequence_count_)
+ if (!emulated_stream_active_sequence_count_ || !enabled())
return;
WebTouchEventTraits::ResetTypeAndTouchStates(
WebInputEvent::TouchCancel,
(base::TimeTicks::Now() - base::TimeTicks()).InSecondsF(),
&touch_event_);
- if (gesture_provider_.GetCurrentDownEvent() &&
- gesture_provider_.OnTouchEvent(MotionEventWeb(touch_event_)))
- ForwardTouchEventToClient();
+ DCHECK(gesture_provider_);
+ if (gesture_provider_->GetCurrentDownEvent())
+ HandleEmulatedTouchEvent(touch_event_);
}
void TouchEmulator::UpdateCursor() {
- if (!enabled_)
+ if (!enabled())
client_->SetCursor(pointer_cursor_);
else
client_->SetCursor(InPinchGestureMode() ? pinch_cursor_ : touch_cursor_);
@@ -393,13 +413,7 @@ void TouchEmulator::ScrollEnd(const WebGestureEvent& event) {
client_->ForwardGestureEvent(scroll_event);
}
-bool TouchEmulator::FillTouchEventAndPoint(const WebMouseEvent& mouse_event) {
- if (mouse_event.type != WebInputEvent::MouseDown &&
- mouse_event.type != WebInputEvent::MouseMove &&
- mouse_event.type != WebInputEvent::MouseUp) {
- return false;
- }
-
+void TouchEmulator::FillTouchEventAndPoint(const WebMouseEvent& mouse_event) {
WebInputEvent::Type eventType;
switch (mouse_event.type) {
case WebInputEvent::MouseDown:
@@ -413,7 +427,7 @@ bool TouchEmulator::FillTouchEventAndPoint(const WebMouseEvent& mouse_event) {
break;
default:
eventType = WebInputEvent::Undefined;
- NOTREACHED();
+ NOTREACHED() << "Invalid event for touch emulation: " << mouse_event.type;
}
touch_event_.touchesLength = 1;
touch_event_.modifiers = mouse_event.modifiers;
@@ -430,8 +444,6 @@ bool TouchEmulator::FillTouchEventAndPoint(const WebMouseEvent& mouse_event) {
point.screenPosition.x = mouse_event.globalX;
point.position.y = mouse_event.y;
point.screenPosition.y = mouse_event.globalY;
-
- return true;
}
bool TouchEmulator::InPinchGestureMode() const {
diff --git a/chromium/content/browser/renderer_host/input/touch_emulator.h b/chromium/content/browser/renderer_host/input/touch_emulator.h
index c364eb9fdca..87c985d3e65 100644
--- a/chromium/content/browser/renderer_host/input/touch_emulator.h
+++ b/chromium/content/browser/renderer_host/input/touch_emulator.h
@@ -10,7 +10,8 @@
#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"
+#include "ui/events/gesture_detection/gesture_provider_config_helper.h"
+#include "ui/gfx/geometry/size_f.h"
namespace content {
@@ -20,12 +21,15 @@ class CONTENT_EXPORT TouchEmulator : public ui::GestureProviderClient {
explicit TouchEmulator(TouchEmulatorClient* client);
~TouchEmulator() override;
- void Enable();
+ void Enable(ui::GestureProviderConfigType config_type);
void Disable();
+ // See GestureProvider::SetDoubleTapSupportForPageEnabled.
+ void SetDoubleTapSupportForPageEnabled(bool enabled);
+
// 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_; }
+ bool enabled() const { return gesture_provider_; }
// Returns |true| if the event was consumed. Consumed event should not
// propagate any further.
@@ -57,7 +61,7 @@ class CONTENT_EXPORT TouchEmulator : public ui::GestureProviderClient {
// Whether we should convert scrolls into pinches.
bool InPinchGestureMode() const;
- bool FillTouchEventAndPoint(const blink::WebMouseEvent& mouse_event);
+ void FillTouchEventAndPoint(const blink::WebMouseEvent& mouse_event);
void FillPinchEvent(const blink::WebInputEvent& event);
// The following methods generate and pass gesture events to the renderer.
@@ -66,14 +70,18 @@ class CONTENT_EXPORT TouchEmulator : public ui::GestureProviderClient {
void PinchEnd(const blink::WebGestureEvent& event);
void ScrollEnd(const blink::WebGestureEvent& event);
- void ForwardTouchEventToClient();
+ // Offers the emulated event to |gesture_provider_|, conditionally forwarding
+ // it to the client if appropriate.
+ void HandleEmulatedTouchEvent(blink::WebTouchEvent event);
TouchEmulatorClient* const client_;
- ui::FilteredGestureProvider gesture_provider_;
+ // Emulator is enabled iff gesture provider is created.
// Disabled emulator does only process touch acks left from previous
// emulation. It does not intercept any events.
- bool enabled_;
+ scoped_ptr<ui::FilteredGestureProvider> gesture_provider_;
+ ui::GestureProviderConfigType gesture_provider_config_type_;
+ bool double_tap_enabled_;
// While emulation is on, default cursor is touch. Pressing shift changes
// cursor to the pinch one.
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 80eb51ad28a..4b8bd1d5d6e 100644
--- a/chromium/content/browser/renderer_host/input/touch_emulator_unittest.cc
+++ b/chromium/content/browser/renderer_host/input/touch_emulator_unittest.cc
@@ -53,7 +53,8 @@ class TouchEmulatorTest : public testing::Test,
#endif
emulator_.reset(new TouchEmulator(this));
- emulator_->Enable();
+ emulator_->SetDoubleTapSupportForPageEnabled(false);
+ emulator_->Enable(ui::GestureProviderConfigType::GENERIC_MOBILE);
}
void TearDown() override {
@@ -62,6 +63,7 @@ class TouchEmulatorTest : public testing::Test,
#if defined(USE_AURA)
aura::Env::DeleteInstance();
+ gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, nullptr);
screen_.reset();
#endif
}
@@ -75,8 +77,8 @@ class TouchEmulatorTest : public testing::Test,
EXPECT_EQ(1U, event.touchesLength);
EXPECT_EQ(last_mouse_x_, event.touches[0].position.x);
EXPECT_EQ(last_mouse_y_, event.touches[0].position.y);
- int expectedCancelable = event.type != WebInputEvent::TouchCancel;
- EXPECT_EQ(expectedCancelable, event.cancelable);
+ bool expected_cancelable = event.type != WebInputEvent::TouchCancel;
+ EXPECT_EQ(expected_cancelable, !!event.cancelable);
if (ack_touches_synchronously_) {
emulator()->HandleTouchEventAck(
event, INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
@@ -282,6 +284,20 @@ TEST_F(TouchEmulatorTest, Touch) {
ExpectedEvents());
}
+TEST_F(TouchEmulatorTest, DoubleTapSupport) {
+ emulator()->SetDoubleTapSupportForPageEnabled(true);
+ MouseMove(100, 200);
+ EXPECT_EQ("", ExpectedEvents());
+ MouseDown(100, 200);
+ EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
+ MouseUp(100, 200);
+ EXPECT_EQ("TouchEnd GestureTapUnconfirmed", ExpectedEvents());
+ MouseDown(100, 200);
+ EXPECT_EQ("TouchStart GestureTapCancel GestureTapDown", ExpectedEvents());
+ MouseUp(100, 200);
+ EXPECT_EQ("TouchEnd GestureTapCancel GestureDoubleTap", ExpectedEvents());
+}
+
TEST_F(TouchEmulatorTest, MultipleTouches) {
MouseMove(100, 200);
EXPECT_EQ("", ExpectedEvents());
@@ -373,7 +389,39 @@ TEST_F(TouchEmulatorTest, DisableAndReenable) {
MouseMove(300, 300);
EXPECT_EQ("", ExpectedEvents());
- emulator()->Enable();
+ emulator()->Enable(ui::GestureProviderConfigType::GENERIC_MOBILE);
+ MouseDown(300, 300);
+ EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
+ MouseDrag(300, 400);
+ EXPECT_EQ(
+ "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate",
+ ExpectedEvents());
+
+ // Disable while scroll is in progress.
+ emulator()->Disable();
+ EXPECT_EQ("TouchCancel GestureScrollEnd", ExpectedEvents());
+}
+
+TEST_F(TouchEmulatorTest, DisableAndReenableDifferentConfig) {
+ MouseDown(100, 200);
+ EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
+ MouseDrag(200, 200);
+ EXPECT_EQ(
+ "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate",
+ ExpectedEvents());
+ PressShift();
+ MouseDrag(300, 200);
+ EXPECT_EQ("TouchMove GesturePinchBegin", ExpectedEvents());
+
+ // Disable while pinch is in progress.
+ emulator()->Disable();
+ EXPECT_EQ("TouchCancel GesturePinchEnd GestureScrollEnd", ExpectedEvents());
+ MouseUp(300, 200);
+ ReleaseShift();
+ MouseMove(300, 300);
+ EXPECT_EQ("", ExpectedEvents());
+
+ emulator()->Enable(ui::GestureProviderConfigType::GENERIC_DESKTOP);
MouseDown(300, 300);
EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
MouseDrag(300, 400);
@@ -433,7 +481,7 @@ TEST_F(TouchEmulatorTest, MouseWheel) {
emulator()->Disable();
EXPECT_EQ("TouchCancel GestureTapCancel", ExpectedEvents());
EXPECT_TRUE(SendMouseWheelEvent());
- emulator()->Enable();
+ emulator()->Enable(ui::GestureProviderConfigType::GENERIC_MOBILE);
EXPECT_TRUE(SendMouseWheelEvent());
}
@@ -459,7 +507,7 @@ TEST_F(TouchEmulatorTest, MultipleTouchStreams) {
EXPECT_EQ("", ExpectedEvents());
// Re-enabling in the middle of a touch sequence should not affect this.
emulator()->Disable();
- emulator()->Enable();
+ emulator()->Enable(ui::GestureProviderConfigType::GENERIC_MOBILE);
MouseDrag(300, 300);
EXPECT_EQ("", ExpectedEvents());
MouseUp(300, 300);
@@ -474,7 +522,7 @@ TEST_F(TouchEmulatorTest, MultipleTouchStreams) {
EXPECT_TRUE(TouchEnd(20, 20, false));
EXPECT_TRUE(TouchStart(30, 30, false));
AckOldestTouchEvent(); // TouchStart.
- emulator()->Enable();
+ emulator()->Enable(ui::GestureProviderConfigType::GENERIC_MOBILE);
AckOldestTouchEvent(); // TouchMove.
AckOldestTouchEvent(); // TouchEnd.
MouseDown(300, 200);
@@ -519,4 +567,12 @@ TEST_F(TouchEmulatorTest, MultipleTouchStreamsLateEnable) {
ExpectedEvents());
}
+TEST_F(TouchEmulatorTest, CancelAfterDisableDoesNotCrash) {
+ DisableSynchronousTouchAck();
+ MouseDown(100, 200);
+ emulator()->Disable();
+ EXPECT_EQ("TouchStart TouchCancel", ExpectedEvents());
+ emulator()->CancelTouch();
+}
+
} // 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 fa109dedddf..b766b3d1b51 100644
--- a/chromium/content/browser/renderer_host/input/touch_event_queue.cc
+++ b/chromium/content/browser/renderer_host/input/touch_event_queue.cc
@@ -5,8 +5,8 @@
#include "content/browser/renderer_host/input/touch_event_queue.h"
#include "base/auto_reset.h"
-#include "base/debug/trace_event.h"
#include "base/stl_util.h"
+#include "base/trace_event/trace_event.h"
#include "content/browser/renderer_host/input/timeout_monitor.h"
#include "content/common/input/web_touch_event_traits.h"
#include "ui/gfx/geometry/point_f.h"
@@ -23,15 +23,10 @@ namespace {
// scrolling is active and possible.
const double kAsyncTouchMoveIntervalSec = .2;
-// A slop region just larger than that used by many web applications. When
-// touchmove's are being sent asynchronously, movement outside this region will
-// trigger an immediate async touchmove to cancel potential tap-related logic.
-const double kApplicationSlopRegionLengthDipsSqared = 15. * 15.;
-
-// Using a small epsilon when comparing slop distances allows pixel perfect
-// slop determination when using fractional DIP coordinates (assuming the slop
-// region and DPI scale are reasonably proportioned).
-const float kSlopEpsilon = .05f;
+// A sanity check on touches received to ensure that touch movement outside
+// the platform slop region will cause scrolling, as indicated by the event's
+// |causesScrollingIfUncanceled| bit.
+const double kMaxConceivablePlatformSlopRegionLengthDipsSquared = 60. * 60.;
TouchEventWithLatencyInfo ObtainCancelEventForTouchEvent(
const TouchEventWithLatencyInfo& event_to_cancel) {
@@ -50,10 +45,19 @@ bool ShouldTouchTriggerTimeout(const WebTouchEvent& event) {
!WebInputEventTraits::IgnoresAckDisposition(event);
}
-bool OutsideApplicationSlopRegion(const WebTouchEvent& event,
- const gfx::PointF& anchor) {
- return (gfx::PointF(event.touches[0].position) - anchor).LengthSquared() >
- kApplicationSlopRegionLengthDipsSqared;
+// Compare all properties of touch points to determine the state.
+bool HasPointChanged(const WebTouchPoint& point_1,
+ const WebTouchPoint& point_2) {
+ DCHECK_EQ(point_1.id, point_2.id);
+ if (point_1.screenPosition != point_2.screenPosition ||
+ point_1.position != point_2.position ||
+ point_1.radiusX != point_2.radiusX ||
+ point_1.radiusY != point_2.radiusY ||
+ point_1.rotationAngle != point_2.rotationAngle ||
+ point_1.force != point_2.force) {
+ return true;
+ }
+ return false;
}
} // namespace
@@ -107,7 +111,7 @@ class TouchEventQueue::TouchTimeoutHandler {
SetPendingAckState(PENDING_ACK_CANCEL_EVENT);
TouchEventWithLatencyInfo cancel_event =
ObtainCancelEventForTouchEvent(timeout_event_);
- touch_queue_->SendTouchEventImmediately(cancel_event);
+ touch_queue_->SendTouchEventImmediately(&cancel_event);
} else {
SetPendingAckState(PENDING_ACK_NONE);
touch_queue_->UpdateTouchConsumerStates(timeout_event_.event,
@@ -215,27 +219,16 @@ class TouchEventQueue::TouchTimeoutHandler {
bool enabled_for_current_sequence_;
};
-// Provides touchmove slop suppression for a single touch that remains within
-// a given slop region, unless the touchstart is preventDefault'ed.
-// TODO(jdduke): Use a flag bundled with each TouchEvent declaring whether it
-// has exceeded the slop region, removing duplicated slop determination logic.
+// Provides touchmove slop suppression for a touch sequence until a
+// (unprevented) touch will trigger immediate scrolling.
class TouchEventQueue::TouchMoveSlopSuppressor {
public:
- TouchMoveSlopSuppressor(double slop_suppression_length_dips)
- : 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;
- }
- }
+ TouchMoveSlopSuppressor() : suppressing_touchmoves_(false) {}
bool FilterEvent(const WebTouchEvent& event) {
if (WebTouchEventTraits::IsTouchSequenceStart(event)) {
- touch_sequence_start_position_ =
- gfx::PointF(event.touches[0].position);
- suppressing_touchmoves_ = slop_suppression_length_dips_squared_ != 0;
+ suppressing_touchmoves_ = true;
+ touch_start_location_ = gfx::PointF(event.touches[0].position);
}
if (event.type == WebInputEvent::TouchEnd ||
@@ -246,17 +239,18 @@ class TouchEventQueue::TouchMoveSlopSuppressor {
return false;
if (suppressing_touchmoves_) {
- // Movement with a secondary pointer should terminate suppression.
if (event.touchesLength > 1) {
suppressing_touchmoves_ = false;
- } else if (event.touchesLength == 1) {
- // Movement outside of the slop region should terminate suppression.
- gfx::PointF position(event.touches[0].position);
- if ((position - touch_sequence_start_position_).LengthSquared() >
- slop_suppression_length_dips_squared_)
- suppressing_touchmoves_ = false;
+ } else if (event.causesScrollingIfUncanceled) {
+ suppressing_touchmoves_ = false;
+ } else {
+ // No sane slop region should be larger than 60 DIPs.
+ DCHECK_LT((gfx::PointF(event.touches[0].position) -
+ touch_start_location_).LengthSquared(),
+ kMaxConceivablePlatformSlopRegionLengthDipsSquared);
}
}
+
return suppressing_touchmoves_;
}
@@ -268,10 +262,12 @@ class TouchEventQueue::TouchMoveSlopSuppressor {
bool suppressing_touchmoves() const { return suppressing_touchmoves_; }
private:
- double slop_suppression_length_dips_squared_;
- gfx::PointF touch_sequence_start_position_;
bool suppressing_touchmoves_;
+ // Sanity check that the upstream touch provider is properly reporting whether
+ // the touch sequence will cause scrolling.
+ gfx::PointF touch_start_location_;
+
DISALLOW_COPY_AND_ASSIGN(TouchMoveSlopSuppressor);
};
@@ -362,25 +358,21 @@ class CoalescedWebTouchEvent {
};
TouchEventQueue::Config::Config()
- : touchmove_slop_suppression_length_dips(0),
- touch_scrolling_mode(TOUCH_SCROLLING_MODE_DEFAULT),
- touch_ack_timeout_delay(base::TimeDelta::FromMilliseconds(200)),
+ : touch_ack_timeout_delay(base::TimeDelta::FromMilliseconds(200)),
touch_ack_timeout_supported(false) {
}
TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client,
const Config& config)
: client_(client),
- dispatching_touch_ack_(NULL),
+ dispatching_touch_ack_(false),
dispatching_touch_(false),
has_handlers_(true),
+ has_handler_for_current_sequence_(false),
drop_remaining_touches_in_sequence_(false),
- touchmove_slop_suppressor_(new TouchMoveSlopSuppressor(
- config.touchmove_slop_suppression_length_dips)),
+ touchmove_slop_suppressor_(new TouchMoveSlopSuppressor),
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) {
+ last_sent_touch_timestamp_sec_(0) {
DCHECK(client);
if (config.touch_ack_timeout_supported) {
timeout_handler_.reset(
@@ -481,15 +473,12 @@ void TouchEventQueue::ForwardNextEventToRenderer() {
// application be sent touches at key points in the gesture stream,
// e.g., when the application slop region is exceeded or touchmove
// coalescing fails because of different modifiers.
- const bool send_touchmove_now =
- size() > 1 ||
- (touch.event.timeStampSeconds >=
- last_sent_touch_timestamp_sec_ + kAsyncTouchMoveIntervalSec) ||
- (needs_async_touchmove_for_outer_slop_region_ &&
- OutsideApplicationSlopRegion(touch.event,
- touch_sequence_start_position_)) ||
- (pending_async_touchmove_ &&
- !pending_async_touchmove_->CanCoalesceWith(touch));
+ bool send_touchmove_now = size() > 1;
+ send_touchmove_now |= pending_async_touchmove_ &&
+ !pending_async_touchmove_->CanCoalesceWith(touch);
+ send_touchmove_now |=
+ touch.event.timeStampSeconds >=
+ last_sent_touch_timestamp_sec_ + kAsyncTouchMoveIntervalSec;
if (!send_touchmove_now) {
if (!pending_async_touchmove_) {
@@ -525,21 +514,21 @@ void TouchEventQueue::ForwardNextEventToRenderer() {
pending_async_touchmove_.Pass();
async_move->event.cancelable = false;
touch_queue_.push_front(new CoalescedWebTouchEvent(*async_move, true));
- SendTouchEventImmediately(*async_move);
+ SendTouchEventImmediately(async_move.get());
return;
}
}
- // Note: Marking touchstart events as not-cancelable prevents them from
- // blocking subsequent gestures, but it may not be the best long term solution
- // for tracking touch point dispatch.
- if (send_touch_events_async_)
+ // Note: Touchstart events are marked cancelable to allow transitions between
+ // platform scrolling and JS pinching. Touchend events, however, remain
+ // uncancelable, mitigating the risk of jank when transitioning to a fling.
+ if (send_touch_events_async_ && touch.event.type != WebInputEvent::TouchStart)
touch.event.cancelable = false;
// A synchronous ack will reset |dispatching_touch_|, in which case
// the touch timeout should not be started.
base::AutoReset<bool> dispatching_touch(&dispatching_touch_, true);
- SendTouchEventImmediately(touch);
+ SendTouchEventImmediately(&touch);
if (dispatching_touch_ && timeout_handler_)
timeout_handler_->StartIfNecessary(touch);
}
@@ -547,80 +536,32 @@ void TouchEventQueue::ForwardNextEventToRenderer() {
void TouchEventQueue::OnGestureScrollEvent(
const GestureEventWithLatencyInfo& gesture_event) {
if (gesture_event.event.type == blink::WebInputEvent::GestureScrollBegin) {
- if (!touch_consumer_states_.is_empty() &&
+ if (has_handler_for_current_sequence_ &&
!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.
- 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();
return;
}
- if (gesture_event.event.type != blink::WebInputEvent::GestureScrollUpdate)
- return;
-
- if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE)
+ if (gesture_event.event.type == blink::WebInputEvent::GestureScrollUpdate)
send_touch_events_async_ = true;
-
- if (touch_scrolling_mode_ != TOUCH_SCROLLING_MODE_TOUCHCANCEL)
- return;
-
- // We assume that scroll events are generated synchronously from
- // dispatching a touch event ack. This allows us to generate a synthetic
- // cancel event that has the same touch ids as the touch event that
- // is being acked. Otherwise, we don't perform the touch-cancel optimization.
- if (!dispatching_touch_ack_)
- return;
-
- if (drop_remaining_touches_in_sequence_)
- return;
-
- drop_remaining_touches_in_sequence_ = true;
-
- // Fake a TouchCancel to cancel the touch points of the touch event
- // that is currently being acked.
- // Note: |dispatching_touch_ack_| is non-null when we reach here, meaning we
- // are in the scope of PopTouchEventToClient() and that no touch event
- // in the queue is waiting for ack from renderer. So we can just insert
- // the touch cancel at the beginning of the queue.
- touch_queue_.push_front(new CoalescedWebTouchEvent(
- ObtainCancelEventForTouchEvent(
- dispatching_touch_ack_->coalesced_event()), true));
}
void TouchEventQueue::OnGestureEventAck(
const GestureEventWithLatencyInfo& event,
InputEventAckState ack_result) {
- if (touch_scrolling_mode_ != TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE)
- return;
-
- if (event.event.type != blink::WebInputEvent::GestureScrollUpdate)
- return;
-
// Throttle sending touchmove events as long as the scroll events are handled.
// Note that there's no guarantee that this ACK is for the most recent
// gesture event (or even part of the current sequence). Worst case, the
// delay in updating the absorption state will result in minor UI glitches.
// A valid |pending_async_touchmove_| will be flushed when the next event is
// forwarded.
- send_touch_events_async_ = (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED);
- if (!send_touch_events_async_)
- needs_async_touchmove_for_outer_slop_region_ = false;
+ if (event.event.type == blink::WebInputEvent::GestureScrollUpdate)
+ send_touch_events_async_ = (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED);
}
void TouchEventQueue::OnHasTouchEventHandlers(bool has_handlers) {
@@ -671,7 +612,7 @@ void TouchEventQueue::FlushQueue() {
}
void TouchEventQueue::PopTouchEventToClient(InputEventAckState ack_result) {
- AckTouchEventToClient(ack_result, PopTouchEvent(), NULL);
+ AckTouchEventToClient(ack_result, PopTouchEvent(), nullptr);
}
void TouchEventQueue::PopTouchEventToClient(
@@ -690,8 +631,7 @@ void TouchEventQueue::AckTouchEventToClient(
// 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());
+ base::AutoReset<bool> dispatching_touch_ack(&dispatching_touch_ack_, true);
acked_event->DispatchAckToClient(ack_result, optional_latency_info, client_);
}
@@ -703,32 +643,44 @@ scoped_ptr<CoalescedWebTouchEvent> TouchEventQueue::PopTouchEvent() {
}
void TouchEventQueue::SendTouchEventImmediately(
- const TouchEventWithLatencyInfo& touch) {
- if (needs_async_touchmove_for_outer_slop_region_) {
- // Any event other than a touchmove (e.g., touchcancel or secondary
- // touchstart) after a scroll has started will interrupt the need to send a
- // an outer slop-region exceeding touchmove.
- if (touch.event.type != WebInputEvent::TouchMove ||
- OutsideApplicationSlopRegion(touch.event,
- touch_sequence_start_position_))
- needs_async_touchmove_for_outer_slop_region_ = false;
+ TouchEventWithLatencyInfo* touch) {
+ // For touchmove events, compare touch points position from current event
+ // to last sent event and update touch points state.
+ if (touch->event.type == WebInputEvent::TouchMove) {
+ CHECK(last_sent_touchevent_);
+ for (unsigned int i = 0; i < last_sent_touchevent_->touchesLength; ++i) {
+ const WebTouchPoint& last_touch_point =
+ last_sent_touchevent_->touches[i];
+ // Touches with same id may not have same index in Touches array.
+ for (unsigned int j = 0; j < touch->event.touchesLength; ++j) {
+ const WebTouchPoint& current_touchmove_point = touch->event.touches[j];
+ if (current_touchmove_point.id != last_touch_point.id)
+ continue;
+
+ if (!HasPointChanged(last_touch_point, current_touchmove_point))
+ touch->event.touches[j].state = WebTouchPoint::StateStationary;
+
+ break;
+ }
+ }
}
- client_->SendTouchEventImmediately(touch);
+ if (last_sent_touchevent_)
+ *last_sent_touchevent_ = touch->event;
+ else
+ last_sent_touchevent_.reset(new WebTouchEvent(touch->event));
+
+ client_->SendTouchEventImmediately(*touch);
}
TouchEventQueue::PreFilterResult
TouchEventQueue::FilterBeforeForwarding(const WebTouchEvent& event) {
- if (timeout_handler_ && timeout_handler_->FilterEvent(event))
- return ACK_WITH_NO_CONSUMER_EXISTS;
-
- if (touchmove_slop_suppressor_->FilterEvent(event))
- return ACK_WITH_NOT_CONSUMED;
-
if (WebTouchEventTraits::IsTouchSequenceStart(event)) {
- touch_consumer_states_.clear();
+ has_handler_for_current_sequence_ = false;
send_touch_events_async_ = false;
pending_async_touchmove_.reset();
+ last_sent_touchevent_.reset();
+
touch_sequence_start_position_ = gfx::PointF(event.touches[0].position);
drop_remaining_touches_in_sequence_ = false;
if (!has_handlers_) {
@@ -737,22 +689,56 @@ TouchEventQueue::FilterBeforeForwarding(const WebTouchEvent& event) {
}
}
+ if (timeout_handler_ && timeout_handler_->FilterEvent(event))
+ return ACK_WITH_NO_CONSUMER_EXISTS;
+
+ if (touchmove_slop_suppressor_->FilterEvent(event))
+ return ACK_WITH_NOT_CONSUMED;
+
if (drop_remaining_touches_in_sequence_ &&
event.type != WebInputEvent::TouchCancel) {
return ACK_WITH_NO_CONSUMER_EXISTS;
}
- if (event.type == WebInputEvent::TouchStart)
- return has_handlers_ ? FORWARD_TO_RENDERER : ACK_WITH_NO_CONSUMER_EXISTS;
+ if (event.type == WebInputEvent::TouchStart) {
+ return (has_handlers_ || has_handler_for_current_sequence_)
+ ? FORWARD_TO_RENDERER
+ : ACK_WITH_NO_CONSUMER_EXISTS;
+ }
- for (unsigned int i = 0; i < event.touchesLength; ++i) {
- const WebTouchPoint& point = event.touches[i];
- // If a point has been stationary, then don't take it into account.
- if (point.state == WebTouchPoint::StateStationary)
- continue;
+ if (has_handler_for_current_sequence_) {
+ // Only forward a touch if it has a non-stationary pointer that is active
+ // in the current touch sequence.
+ for (size_t i = 0; i < event.touchesLength; ++i) {
+ const WebTouchPoint& point = event.touches[i];
+ if (point.state == WebTouchPoint::StateStationary)
+ continue;
+
+ // |last_sent_touchevent_| will be non-null as long as there is an
+ // active touch sequence being forwarded to the renderer.
+ if (!last_sent_touchevent_)
+ continue;
+
+ for (size_t j = 0; j < last_sent_touchevent_->touchesLength; ++j) {
+ if (point.id != last_sent_touchevent_->touches[j].id)
+ continue;
+
+ if (event.type != WebInputEvent::TouchMove)
+ return FORWARD_TO_RENDERER;
+
+ // All pointers in TouchMove events may have state as StateMoved,
+ // even though none of the pointers have not changed in real.
+ // Forward these events when at least one pointer has changed.
+ if (HasPointChanged(last_sent_touchevent_->touches[j], point))
+ return FORWARD_TO_RENDERER;
+
+ // This is a TouchMove event for which we have yet to find a
+ // non-stationary pointer. Continue checking the next pointers
+ // in the |event|.
+ break;
+ }
- if (touch_consumer_states_.has_bit(point.id))
- return FORWARD_TO_RENDERER;
+ }
}
return ACK_WITH_NO_CONSUMER_EXISTS;
@@ -760,26 +746,13 @@ TouchEventQueue::FilterBeforeForwarding(const WebTouchEvent& event) {
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) {
- // The points have been released. Erase the ACK states.
- for (unsigned i = 0; i < event.touchesLength; ++i) {
- const WebTouchPoint& point = event.touches[i];
- if (point.state == WebTouchPoint::StateReleased ||
- point.state == WebTouchPoint::StateCancelled)
- 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) {
- 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);
- }
- }
+ if (event.type == WebInputEvent::TouchStart) {
+ if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED)
+ send_touch_events_async_ = false;
+ has_handler_for_current_sequence_ |=
+ ack_result != INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS;
+ } else if (WebTouchEventTraits::IsTouchSequenceEnd(event)) {
+ has_handler_for_current_sequence_ = false;
}
}
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 3bdab903750..a61b90d8eca 100644
--- a/chromium/content/browser/renderer_host/input/touch_event_queue.h
+++ b/chromium/content/browser/renderer_host/input/touch_event_queue.h
@@ -14,7 +14,6 @@
#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 {
@@ -38,35 +37,9 @@ class CONTENT_EXPORT TouchEventQueueClient {
// A queue for throttling and coalescing touch-events.
class CONTENT_EXPORT TouchEventQueue {
public:
- // Different ways of dealing with touch events during scrolling.
- // TODO(rbyers): Remove this once we're confident that touch move absorption
- // is OK. http://crbug.com/350430
- enum TouchScrollingMode {
- // Send a touchcancel on scroll start and no further touch events for the
- // duration of the scroll. Chrome Android's traditional behavior.
- TOUCH_SCROLLING_MODE_TOUCHCANCEL,
- // Send touchmove events throughout a scroll, blocking on each ACK and
- // using the disposition to determine whether a scroll update should be
- // sent. Mobile Safari's default overflow scroll behavior.
- TOUCH_SCROLLING_MODE_SYNC_TOUCHMOVE,
- // Send touchmove events throughout a scroll, but throttle sending and
- // ignore the ACK as long as scrolling remains possible. Unconsumed scroll
- // events return touchmove events to being dispatched synchronously.
- TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE,
- TOUCH_SCROLLING_MODE_DEFAULT = TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE
- };
-
struct CONTENT_EXPORT Config {
Config();
- // Determines the bounds of the (square) touchmove slop suppression region.
- // Defaults to 0 (disabled).
- double touchmove_slop_suppression_length_dips;
-
- // Determines the type of touch scrolling.
- // Defaults to TouchEventQueue:::TOUCH_SCROLLING_MODE_DEFAULT.
- TouchEventQueue::TouchScrollingMode touch_scrolling_mode;
-
// Controls whether touch ack timeouts will trigger touch cancellation.
// Defaults to 200ms.
base::TimeDelta touch_ack_timeout_delay;
@@ -168,8 +141,9 @@ class CONTENT_EXPORT TouchEventQueue {
// Safely pop the head of the queue.
scoped_ptr<CoalescedWebTouchEvent> PopTouchEvent();
- // Dispatch |touch| to the client.
- void SendTouchEventImmediately(const TouchEventWithLatencyInfo& touch);
+ // Dispatch |touch| to the client. Before dispatching, updates pointer
+ // states in touchmove events for pointers that have not changed position.
+ void SendTouchEventImmediately(TouchEventWithLatencyInfo* touch);
enum PreFilterResult {
ACK_WITH_NO_CONSUMER_EXISTS,
@@ -189,20 +163,13 @@ class CONTENT_EXPORT TouchEventQueue {
typedef std::deque<CoalescedWebTouchEvent*> TouchQueue;
TouchQueue touch_queue_;
- // 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.
gfx::PointF touch_sequence_start_position_;
// Used to defer touch forwarding when ack dispatch triggers |QueueEvent()|.
- // If not NULL, |dispatching_touch_ack_| is the touch event of which the ack
- // is being dispatched.
- const CoalescedWebTouchEvent* dispatching_touch_ack_;
+ // True within the scope of |AckTouchEventToClient()|.
+ bool dispatching_touch_ack_;
// Used to prevent touch timeout scheduling if we receive a synchronous
// ack after forwarding a touch event to the client.
@@ -211,12 +178,14 @@ class CONTENT_EXPORT TouchEventQueue {
// Whether the renderer has at least one touch handler.
bool has_handlers_;
+ // Whether any pointer in the touch sequence reported having a consumer.
+ bool has_handler_for_current_sequence_;
+
// 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.
+ // cancelled after a touch timeout.
bool drop_remaining_touches_in_sequence_;
// Optional handler for timed-out touch event acks.
@@ -232,14 +201,11 @@ class CONTENT_EXPORT TouchEventQueue {
// until a sufficient time period has elapsed since the last sent touch event.
// For details see the design doc at http://goo.gl/lVyJAa.
bool send_touch_events_async_;
- bool needs_async_touchmove_for_outer_slop_region_;
scoped_ptr<TouchEventWithLatencyInfo> pending_async_touchmove_;
double last_sent_touch_timestamp_sec_;
- // How touch events are handled during scrolling. For now this is a global
- // setting for experimentation, but we may evolve it into an app-controlled
- // mode.
- const TouchScrollingMode touch_scrolling_mode_;
+ // Event is saved to compare pointer positions for new touchmove events.
+ scoped_ptr<blink::WebTouchEvent> last_sent_touchevent_;
DISALLOW_COPY_AND_ASSIGN(TouchEventQueue);
};
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 fcd5ce8d07b..398dfb79edd 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
@@ -9,6 +9,7 @@
#include "content/browser/renderer_host/input/timeout_monitor.h"
#include "content/browser/renderer_host/input/touch_event_queue.h"
#include "content/common/input/synthetic_web_input_event_builders.h"
+#include "content/common/input/web_touch_event_traits.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
@@ -21,6 +22,8 @@ namespace content {
namespace {
const double kMinSecondsBetweenThrottledTouchmoves = 0.2;
+const float kSlopLengthDips = 10;
+const float kHalfSlopLengthDips = kSlopLengthDips / 2;
base::TimeDelta DefaultTouchTimeoutDelay() {
return base::TimeDelta::FromMilliseconds(1);
@@ -34,13 +37,14 @@ class TouchEventQueueTest : public testing::Test,
: sent_event_count_(0),
acked_event_count_(0),
last_acked_event_state_(INPUT_EVENT_ACK_STATE_UNKNOWN),
- slop_length_dips_(0),
- touch_scrolling_mode_(TouchEventQueue::TOUCH_SCROLLING_MODE_DEFAULT) {}
+ slop_length_dips_(0) {}
~TouchEventQueueTest() override {}
// testing::Test
- void SetUp() override { ResetQueueWithConfig(CreateConfig()); }
+ void SetUp() override {
+ ResetQueueWithConfig(TouchEventQueue::Config());
+ }
void TearDown() override { queue_.reset(); }
@@ -75,31 +79,31 @@ class TouchEventQueueTest : public testing::Test,
}
protected:
- TouchEventQueue::Config CreateConfig() {
- TouchEventQueue::Config config;
- config.touch_scrolling_mode = touch_scrolling_mode_;
- config.touchmove_slop_suppression_length_dips = slop_length_dips_;
- return config;
- }
-
- void SetTouchScrollingMode(TouchEventQueue::TouchScrollingMode mode) {
- touch_scrolling_mode_ = mode;
- ResetQueueWithConfig(CreateConfig());
- }
-
void SetUpForTouchMoveSlopTesting(double slop_length_dips) {
slop_length_dips_ = slop_length_dips;
- ResetQueueWithConfig(CreateConfig());
}
void SetUpForTimeoutTesting(base::TimeDelta timeout_delay) {
- TouchEventQueue::Config config = CreateConfig();
+ TouchEventQueue::Config config;
config.touch_ack_timeout_delay = timeout_delay;
config.touch_ack_timeout_supported = true;
ResetQueueWithConfig(config);
}
- void SendTouchEvent(const WebTouchEvent& event) {
+ void SendTouchEvent(WebTouchEvent event) {
+ if (slop_length_dips_) {
+ event.causesScrollingIfUncanceled = false;
+ if (WebTouchEventTraits::IsTouchSequenceStart(event))
+ anchor_ = event.touches[0].position;
+ if (event.type == WebInputEvent::TouchMove) {
+ gfx::Vector2dF delta = anchor_ - event.touches[0].position;
+ if (delta.LengthSquared() > slop_length_dips_ * slop_length_dips_)
+ event.causesScrollingIfUncanceled = true;
+ }
+ } else {
+ event.causesScrollingIfUncanceled =
+ event.type == WebInputEvent::TouchMove;
+ }
queue_->QueueEvent(TouchEventWithLatencyInfo(event, ui::LatencyInfo()));
}
@@ -155,6 +159,46 @@ class TouchEventQueueTest : public testing::Test,
SendTouchEvent();
}
+ void ChangeTouchPointRadius(int index, float radius_x, float radius_y) {
+ CHECK_GE(index, 0);
+ CHECK_LT(index, touch_event_.touchesLengthCap);
+ WebTouchPoint& point = touch_event_.touches[index];
+ point.radiusX = radius_x;
+ point.radiusY = radius_y;
+ touch_event_.touches[index].state = WebTouchPoint::StateMoved;
+ touch_event_.causesScrollingIfUncanceled = true;
+ WebTouchEventTraits::ResetType(WebInputEvent::TouchMove,
+ touch_event_.timeStampSeconds,
+ &touch_event_);
+ SendTouchEvent();
+ }
+
+ void ChangeTouchPointRotationAngle(int index, float rotation_angle) {
+ CHECK_GE(index, 0);
+ CHECK_LT(index, touch_event_.touchesLengthCap);
+ WebTouchPoint& point = touch_event_.touches[index];
+ point.rotationAngle = rotation_angle;
+ touch_event_.touches[index].state = WebTouchPoint::StateMoved;
+ touch_event_.causesScrollingIfUncanceled = true;
+ WebTouchEventTraits::ResetType(WebInputEvent::TouchMove,
+ touch_event_.timeStampSeconds,
+ &touch_event_);
+ SendTouchEvent();
+ }
+
+ void ChangeTouchPointForce(int index, float force) {
+ CHECK_GE(index, 0);
+ CHECK_LT(index, touch_event_.touchesLengthCap);
+ WebTouchPoint& point = touch_event_.touches[index];
+ point.force = force;
+ touch_event_.touches[index].state = WebTouchPoint::StateMoved;
+ touch_event_.causesScrollingIfUncanceled = true;
+ WebTouchEventTraits::ResetType(WebInputEvent::TouchMove,
+ touch_event_.timeStampSeconds,
+ &touch_event_);
+ SendTouchEvent();
+ }
+
void ReleaseTouchPoint(int index) {
touch_event_.ReleasePoint(index);
SendTouchEvent();
@@ -249,7 +293,7 @@ class TouchEventQueueTest : public testing::Test,
scoped_ptr<WebGestureEvent> followup_gesture_event_;
scoped_ptr<InputEventAckState> sync_ack_result_;
double slop_length_dips_;
- TouchEventQueue::TouchScrollingMode touch_scrolling_mode_;
+ gfx::PointF anchor_;
base::MessageLoopForUI message_loop_;
};
@@ -327,10 +371,9 @@ TEST_F(TouchEventQueueTest, BasicMultiTouch) {
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) {
+// Tests that the touch-queue continues delivering events for an active touch
+// sequence after all handlers are removed.
+TEST_F(TouchEventQueueTest, TouchesForwardedIfHandlerRemovedDuringSequence) {
OnHasTouchEventHandlers(true);
EXPECT_EQ(0U, queued_event_count());
EXPECT_EQ(0U, GetAndResetSentEventCount());
@@ -352,21 +395,27 @@ TEST_F(TouchEventQueueTest, NoNewTouchesForwardedAfterHandlersRemoved) {
EXPECT_EQ(0U, queued_event_count());
EXPECT_EQ(INPUT_EVENT_ACK_STATE_CONSUMED, acked_event_state());
- // Try forwarding a new pointer. It should be rejected immediately.
+ // Try forwarding a new pointer. It should be forwarded as usual.
PressTouchPoint(2, 2);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
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.
+ // Further events for any pointer should be forwarded, even for pointers that
+ // reported no consumer.
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());
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ EXPECT_EQ(0U, GetAndResetAckedEventCount());
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
+ EXPECT_EQ(0U, GetAndResetSentEventCount());
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
- // Events for the first pointer, that had a handler, should be forwarded, even
- // if the renderer reports that no handlers exist.
+ // Events for the first pointer, that had a handler, should be forwarded.
MoveTouchPoint(0, 4, 4);
ReleaseTouchPoint(0);
EXPECT_EQ(1U, GetAndResetSentEventCount());
@@ -684,113 +733,56 @@ TEST_F(TouchEventQueueTest, NoConsumer) {
}
TEST_F(TouchEventQueueTest, ConsumerIgnoreMultiFinger) {
- // Press two touch points and move them around a bit. The renderer consumes
- // the events for the first touch point, but returns NO_CONSUMER_EXISTS for
- // the second touch point.
-
+ // Interleave three pointer press, move and release events.
PressTouchPoint(1, 1);
- EXPECT_EQ(1U, GetAndResetSentEventCount());
-
MoveTouchPoint(0, 5, 5);
-
PressTouchPoint(10, 10);
-
- MoveTouchPoint(0, 2, 2);
-
- MoveTouchPoint(1, 4, 10);
-
- MoveTouchPoints(0, 10, 10, 1, 20, 20);
+ MoveTouchPoint(1, 15, 15);
+ PressTouchPoint(20, 20);
+ MoveTouchPoint(2, 25, 25);
+ ReleaseTouchPoint(2);
+ MoveTouchPoint(1, 20, 20);
+ ReleaseTouchPoint(1);
+ MoveTouchPoint(0, 10, 10);
+ ReleaseTouchPoint(0);
// Since the first touch-press is still pending ACK, no other event should
// have been sent to the renderer.
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
EXPECT_EQ(0U, GetAndResetSentEventCount());
- // The queue includes the two presses, the first touch-move of the first
- // point, and a coalesced touch-move of both points.
- EXPECT_EQ(4U, queued_event_count());
+ EXPECT_EQ(11U, queued_event_count());
// ACK the first press as CONSUMED. This should cause the first touch-move of
// the first touch-point to be dispatched.
SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(1U, GetAndResetSentEventCount());
- EXPECT_EQ(3U, queued_event_count());
+ EXPECT_EQ(10U, queued_event_count());
// ACK the first move as CONSUMED.
SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(1U, GetAndResetSentEventCount());
- EXPECT_EQ(2U, queued_event_count());
+ EXPECT_EQ(9U, queued_event_count());
- // ACK the second press as NO_CONSUMER_EXISTS. This will dequeue the coalesced
- // touch-move event (which contains both touch points). Although the second
- // touch-point does not need to be sent to the renderer, the first touch-point
- // did move, and so the coalesced touch-event will be sent to the renderer.
+ // ACK the second press as NO_CONSUMER_EXISTS. The second pointer's touchmove
+ // should still be forwarded, despite lacking a direct consumer.
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
EXPECT_EQ(1U, GetAndResetSentEventCount());
- EXPECT_EQ(1U, queued_event_count());
+ EXPECT_EQ(8U, queued_event_count());
// ACK the coalesced move as NOT_CONSUMED.
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
- EXPECT_EQ(0U, GetAndResetSentEventCount());
- EXPECT_EQ(0U, queued_event_count());
-
- // Move just the second touch point. Because the first touch point did not
- // move, this event should not reach the renderer.
- MoveTouchPoint(1, 30, 30);
- EXPECT_EQ(0U, GetAndResetSentEventCount());
- EXPECT_EQ(0U, queued_event_count());
-
- // Move just the first touch point. This should reach the renderer.
- MoveTouchPoint(0, 10, 10);
- EXPECT_EQ(1U, GetAndResetSentEventCount());
- EXPECT_EQ(1U, queued_event_count());
-
- // Move both fingers. This event should reach the renderer (after the ACK of
- // the previous move event is received), because the first touch point did
- // move.
- MoveTouchPoints(0, 15, 15, 1, 25, 25);
- EXPECT_EQ(0U, GetAndResetSentEventCount());
-
- SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
- EXPECT_EQ(1U, GetAndResetSentEventCount());
- EXPECT_EQ(1U, queued_event_count());
-
- SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
- EXPECT_EQ(0U, GetAndResetSentEventCount());
- EXPECT_EQ(0U, queued_event_count());
-
- // Release the first finger. Then move the second finger around some, then
- // press another finger. Once the release event is ACKed, the move events of
- // the second finger should be immediately released to the view, and the
- // touch-press event should be dispatched to the renderer.
- ReleaseTouchPoint(0);
- EXPECT_EQ(1U, GetAndResetSentEventCount());
- EXPECT_EQ(1U, queued_event_count());
-
- MoveTouchPoint(1, 40, 40);
-
- MoveTouchPoint(1, 50, 50);
-
- PressTouchPoint(1, 1);
-
- MoveTouchPoint(1, 30, 30);
- EXPECT_EQ(0U, GetAndResetSentEventCount());
- EXPECT_EQ(4U, queued_event_count());
-
- SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_EQ(1U, GetAndResetSentEventCount());
- EXPECT_EQ(2U, queued_event_count());
- EXPECT_EQ(WebInputEvent::TouchMove, acked_event().type);
+ EXPECT_EQ(7U, queued_event_count());
- // ACK the press with NO_CONSUMED_EXISTS. This should release the queued
- // touch-move events to the view.
+ // All remaining touch events should be forwarded, even if the third pointer
+ // press also reports no consumer.
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
- EXPECT_EQ(0U, GetAndResetSentEventCount());
- EXPECT_EQ(0U, queued_event_count());
- EXPECT_EQ(WebInputEvent::TouchMove, acked_event().type);
+ EXPECT_EQ(6U, queued_event_count());
- ReleaseTouchPoint(2);
- ReleaseTouchPoint(1);
- EXPECT_EQ(0U, GetAndResetSentEventCount());
- EXPECT_EQ(0U, queued_event_count());
+ while (queued_event_count())
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+
+ EXPECT_EQ(6U, GetAndResetSentEventCount());
}
// Tests that touch-event's enqueued via a touch ack are properly handled.
@@ -933,140 +925,6 @@ TEST_F(TouchEventQueueTest, NoTouchBasic) {
EXPECT_EQ(1U, GetAndResetAckedEventCount());
}
-// Tests that no TouchEvents are sent to renderer during scrolling.
-TEST_F(TouchEventQueueTest, TouchCancelOnScroll) {
- SetTouchScrollingMode(TouchEventQueue::TOUCH_SCROLLING_MODE_TOUCHCANCEL);
- // Queue a TouchStart.
- PressTouchPoint(0, 1);
- EXPECT_EQ(1U, GetAndResetSentEventCount());
- SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
- EXPECT_EQ(1U, GetAndResetAckedEventCount());
-
- MoveTouchPoint(0, 20, 5);
- 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(3U, queued_event_count());
- EXPECT_EQ(0U, GetAndResetSentEventCount());
- EXPECT_EQ(WebInputEvent::TouchStart, latest_event().type);
-
- WebGestureEvent followup_scroll;
- followup_scroll.type = WebInputEvent::GestureScrollBegin;
- 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_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);
-
- // Acking the TouchCancel will result in dispatch of the next TouchStart.
- SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
- // The synthetic TouchCancel should not reach client, only the TouchStart.
- EXPECT_EQ(1U, GetAndResetAckedEventCount());
- EXPECT_EQ(0U, GetAndResetSentEventCount());
- EXPECT_EQ(WebInputEvent::TouchStart, acked_event().type);
-
- // TouchMove should not be sent to the renderer.
- MoveTouchPoint(0, 30, 5);
- EXPECT_EQ(1U, GetAndResetAckedEventCount());
- EXPECT_EQ(0U, GetAndResetSentEventCount());
- EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, acked_event_state());
-
- // GestureScrollUpdates should not change affect touch forwarding.
- SendGestureEvent(WebInputEvent::GestureScrollUpdate);
-
- // TouchEnd should not be sent to the renderer.
- ReleaseTouchPoint(0);
- EXPECT_EQ(1U, GetAndResetAckedEventCount());
- EXPECT_EQ(0U, GetAndResetSentEventCount());
- EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, acked_event_state());
-
- ReleaseTouchPoint(0);
- EXPECT_EQ(1U, GetAndResetAckedEventCount());
- EXPECT_EQ(0U, GetAndResetSentEventCount());
- EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, acked_event_state());
-
- // Touch events from a new gesture sequence should be forwarded normally.
- PressTouchPoint(80, 10);
- EXPECT_EQ(1U, GetAndResetSentEventCount());
- SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
- EXPECT_EQ(1U, GetAndResetAckedEventCount());
-
- MoveTouchPoint(0, 80, 20);
- EXPECT_EQ(1U, GetAndResetSentEventCount());
- SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
- EXPECT_EQ(1U, GetAndResetAckedEventCount());
-
- ReleaseTouchPoint(0);
- EXPECT_EQ(1U, GetAndResetSentEventCount());
- SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
- EXPECT_EQ(1U, GetAndResetAckedEventCount());
-}
-
-// Tests that a scroll event will not insert a synthetic TouchCancel if there
-// was no consumer for the current touch sequence.
-TEST_F(TouchEventQueueTest, NoTouchCancelOnScrollIfNoConsumer) {
- SetTouchScrollingMode(TouchEventQueue::TOUCH_SCROLLING_MODE_TOUCHCANCEL);
-
- // Queue a TouchStart.
- PressTouchPoint(0, 1);
- EXPECT_EQ(1U, GetAndResetSentEventCount());
- SendTouchEventAck(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
- EXPECT_EQ(1U, GetAndResetAckedEventCount());
- EXPECT_EQ(WebInputEvent::TouchStart, sent_event().type);
-
- // Queue a TouchMove that turns into a GestureScrollBegin.
- WebGestureEvent followup_scroll;
- followup_scroll.type = WebInputEvent::GestureScrollBegin;
- SetFollowupEvent(followup_scroll);
- MoveTouchPoint(0, 20, 5);
-
- // The TouchMove has no consumer, and should be ack'ed immediately. However,
- // *no* synthetic TouchCancel should be inserted as the touch sequence
- // had no consumer.
- EXPECT_EQ(0U, queued_event_count());
- EXPECT_EQ(0U, GetAndResetSentEventCount());
- EXPECT_EQ(1U, GetAndResetAckedEventCount());
- EXPECT_EQ(0U, queued_event_count());
- EXPECT_EQ(WebInputEvent::TouchStart, sent_event().type);
-
- // Subsequent TouchMove's should not be sent to the renderer.
- MoveTouchPoint(0, 30, 5);
- EXPECT_EQ(1U, GetAndResetAckedEventCount());
- EXPECT_EQ(0U, GetAndResetSentEventCount());
- EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, acked_event_state());
-
- // TouchEnd should not be sent to the renderer.
- ReleaseTouchPoint(0);
- EXPECT_EQ(1U, GetAndResetAckedEventCount());
- EXPECT_EQ(0U, GetAndResetSentEventCount());
- EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, acked_event_state());
-
- // Touch events from a new gesture sequence should be forwarded normally.
- PressTouchPoint(80, 10);
- EXPECT_EQ(1U, GetAndResetSentEventCount());
- SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
- EXPECT_EQ(1U, GetAndResetAckedEventCount());
-}
-
// Tests that IsTouchStartPendingAck works correctly.
TEST_F(TouchEventQueueTest, PendingStart) {
@@ -1441,8 +1299,6 @@ 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 float kSlopLengthDips = 10;
- const float kHalfSlopLengthDips = kSlopLengthDips / 2;
SetUpForTouchMoveSlopTesting(kSlopLengthDips);
// Queue a TouchStart.
@@ -1526,8 +1382,6 @@ TEST_F(TouchEventQueueTest, TouchMoveSuppressionIncludingSlopBoundary) {
// 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.
@@ -1560,51 +1414,9 @@ TEST_F(TouchEventQueueTest, NoTouchMoveSuppressionIfDisabled) {
EXPECT_EQ(0U, GetAndResetAckedEventCount());
}
-// Tests that TouchMove's are not dropped due to incorrect handling of DPI
-// scaling.
-TEST_F(TouchEventQueueTest, TouchMoveSuppressionWithDIPScaling) {
- const float kSlopLengthPixels = 7.f;
- const float kDPIScale = 3.f;
- SetUpForTouchMoveSlopTesting(kSlopLengthPixels / kDPIScale);
-
- // Queue a TouchStart.
- PressTouchPoint(0, 0);
- SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
- ASSERT_EQ(1U, GetAndResetSentEventCount());
- ASSERT_EQ(1U, GetAndResetAckedEventCount());
-
- // TouchMove's along the slop boundary should be suppresed.
- MoveTouchPoint(0, 0, kSlopLengthPixels / kDPIScale);
- EXPECT_EQ(0U, queued_event_count());
- EXPECT_EQ(0U, GetAndResetSentEventCount());
- EXPECT_EQ(1U, GetAndResetAckedEventCount());
-
- // Reset the touch sequence.
- ReleaseTouchPoint(0);
- SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
- SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
- GetAndResetSentEventCount();
- GetAndResetAckedEventCount();
-
- // Queue a TouchStart.
- PressTouchPoint(0, 0);
- SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
- ASSERT_EQ(1U, GetAndResetSentEventCount());
- ASSERT_EQ(1U, GetAndResetAckedEventCount());
-
- // TouchMove's outside the region should not be suppressed.
- const float kPixelCoordOutsideSlopRegion = kSlopLengthPixels + 0.5f;
- MoveTouchPoint(0, 0, kPixelCoordOutsideSlopRegion / kDPIScale);
- EXPECT_EQ(1U, queued_event_count());
- EXPECT_EQ(1U, GetAndResetSentEventCount());
- EXPECT_EQ(0U, GetAndResetAckedEventCount());
-}
-
// Tests that TouchMove's are not dropped if a secondary pointer is present
// during any movement.
TEST_F(TouchEventQueueTest, NoTouchMoveSuppressionAfterMultiTouch) {
- const float kSlopLengthDips = 10;
- const float kHalfSlopLengthDips = kSlopLengthDips / 2;
SetUpForTouchMoveSlopTesting(kSlopLengthDips);
// Queue a TouchStart.
@@ -1626,7 +1438,7 @@ TEST_F(TouchEventQueueTest, NoTouchMoveSuppressionAfterMultiTouch) {
EXPECT_EQ(1U, GetAndResetAckedEventCount());
// TouchMove with a secondary pointer should not be suppressed.
- MoveTouchPoint(1, kSlopLengthDips, 0);
+ MoveTouchPoint(1, kSlopLengthDips+1, 0);
EXPECT_EQ(1U, queued_event_count());
EXPECT_EQ(1U, GetAndResetSentEventCount());
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
@@ -1675,8 +1487,8 @@ TEST_F(TouchEventQueueTest, SecondaryTouchForwardedAfterPrimaryHadNoConsumer) {
EXPECT_EQ(1U, GetAndResetAckedEventCount());
}
-// Tests that no touch points will be forwarded after scrolling begins while no
-// touch points have a consumer.
+// Tests that secondary touch points can be forwarded after scrolling begins
+// while first touch point has no consumer.
TEST_F(TouchEventQueueTest, NoForwardingAfterScrollWithNoTouchConsumers) {
// Queue a TouchStart.
PressTouchPoint(0, 0);
@@ -1692,44 +1504,21 @@ TEST_F(TouchEventQueueTest, NoForwardingAfterScrollWithNoTouchConsumers) {
EXPECT_EQ(1U, GetAndResetAckedEventCount());
EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, acked_event_state());
- // The secondary pointer press should not be forwarded.
+ // The secondary pointer press should be forwarded.
PressTouchPoint(20, 0);
- EXPECT_EQ(0U, GetAndResetSentEventCount());
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
EXPECT_EQ(1U, GetAndResetAckedEventCount());
- EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, acked_event_state());
- // Neither should any further touchmoves be forwarded.
+ // TouchMove with a secondary pointer should also be forwarded.
MoveTouchPoint(1, 25, 0);
- EXPECT_EQ(0U, GetAndResetSentEventCount());
+ EXPECT_EQ(1U, queued_event_count());
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(1U, GetAndResetAckedEventCount());
- EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, acked_event_state());
-}
-
-TEST_F(TouchEventQueueTest, SyncTouchMoveDoesntCancelTouchOnScroll) {
- SetTouchScrollingMode(TouchEventQueue::TOUCH_SCROLLING_MODE_SYNC_TOUCHMOVE);
- // Queue a TouchStart.
- PressTouchPoint(0, 1);
- EXPECT_EQ(1U, GetAndResetSentEventCount());
- SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
- EXPECT_EQ(1U, GetAndResetAckedEventCount());
-
- MoveTouchPoint(0, 20, 5);
- EXPECT_EQ(1U, queued_event_count());
- EXPECT_EQ(1U, GetAndResetSentEventCount());
-
- // GestureScrollBegin doesn't insert a synthetic TouchCancel.
- WebGestureEvent followup_scroll;
- followup_scroll.type = WebInputEvent::GestureScrollBegin;
- SetFollowupEvent(followup_scroll);
- SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
- EXPECT_EQ(0U, GetAndResetSentEventCount());
- EXPECT_EQ(1U, GetAndResetAckedEventCount());
- EXPECT_EQ(0U, queued_event_count());
}
TEST_F(TouchEventQueueTest, AsyncTouch) {
- SetTouchScrollingMode(TouchEventQueue::TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE);
-
// Queue a TouchStart.
PressTouchPoint(0, 1);
EXPECT_EQ(1U, GetAndResetSentEventCount());
@@ -1740,7 +1529,7 @@ TEST_F(TouchEventQueueTest, AsyncTouch) {
SendGestureEventAck(WebInputEvent::GestureScrollUpdate,
INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
- MoveTouchPoint(0, 10, 5);
+ MoveTouchPoint(0, 10, 5+i);
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_FALSE(HasPendingAsyncTouchMove());
EXPECT_TRUE(sent_event().cancelable);
@@ -1750,7 +1539,7 @@ TEST_F(TouchEventQueueTest, AsyncTouch) {
// Consuming a scroll event will throttle subsequent touchmoves.
SendGestureEventAck(WebInputEvent::GestureScrollUpdate,
INPUT_EVENT_ACK_STATE_CONSUMED);
- MoveTouchPoint(0, 10, 5);
+ MoveTouchPoint(0, 10, 7+i);
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_TRUE(HasPendingAsyncTouchMove());
EXPECT_EQ(0U, queued_event_count());
@@ -1761,8 +1550,6 @@ TEST_F(TouchEventQueueTest, AsyncTouch) {
// Ensure that touchmove's are appropriately throttled during a typical
// scroll sequences that transitions between scrolls consumed and unconsumed.
TEST_F(TouchEventQueueTest, AsyncTouchThrottledAfterScroll) {
- SetTouchScrollingMode(TouchEventQueue::TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE);
-
// Process a TouchStart
PressTouchPoint(0, 1);
EXPECT_EQ(1U, GetAndResetSentEventCount());
@@ -1843,7 +1630,7 @@ TEST_F(TouchEventQueueTest, AsyncTouchThrottledAfterScroll) {
EXPECT_EQ(1U, GetAndResetSentEventCount());
EXPECT_EQ(1U, GetAndResetAckedEventCount());
- MoveTouchPoint(0, 0, 5);
+ MoveTouchPoint(0, 0, 6);
followup_scroll.type = WebInputEvent::GestureScrollUpdate;
SetFollowupEvent(followup_scroll);
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
@@ -1858,16 +1645,6 @@ TEST_F(TouchEventQueueTest, AsyncTouchThrottledAfterScroll) {
EXPECT_EQ(0U, GetAndResetSentEventCount());
EXPECT_EQ(1U, GetAndResetAckedEventCount());
- // As soon as a touchmove exceeds the outer slop region it will be forwarded
- // immediately.
- MoveTouchPoint(0, 0, 20);
- SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
- EXPECT_FALSE(HasPendingAsyncTouchMove());
- EXPECT_FALSE(sent_event().cancelable);
- EXPECT_EQ(0U, queued_event_count());
- EXPECT_EQ(1U, GetAndResetSentEventCount());
- EXPECT_EQ(1U, GetAndResetAckedEventCount());
-
// Subsequent touchmove's should be deferred.
MoveTouchPoint(0, 0, 25);
EXPECT_TRUE(HasPendingAsyncTouchMove());
@@ -1906,7 +1683,7 @@ TEST_F(TouchEventQueueTest, AsyncTouchThrottledAfterScroll) {
// that the flushed touchmove's ack will not reach the client (its
// constituent events have already been ack'ed).
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
- EXPECT_FALSE(sent_event().cancelable);
+ EXPECT_TRUE(sent_event().cancelable);
EXPECT_EQ(WebInputEvent::TouchStart, sent_event().type);
EXPECT_EQ(1U, queued_event_count());
EXPECT_EQ(1U, GetAndResetSentEventCount());
@@ -1931,7 +1708,7 @@ TEST_F(TouchEventQueueTest, AsyncTouchThrottledAfterScroll) {
// The pending touchmove should be coalesced with the next (now synchronous)
// touchmove.
- MoveTouchPoint(0, 0, 25);
+ MoveTouchPoint(0, 0, 26);
EXPECT_TRUE(sent_event().cancelable);
EXPECT_FALSE(HasPendingAsyncTouchMove());
EXPECT_EQ(WebInputEvent::TouchMove, sent_event().type);
@@ -1967,10 +1744,62 @@ TEST_F(TouchEventQueueTest, AsyncTouchThrottledAfterScroll) {
EXPECT_EQ(1U, GetAndResetAckedEventCount());
}
+TEST_F(TouchEventQueueTest, AsyncTouchFlushedByTouchEnd) {
+ PressTouchPoint(0, 0);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+
+ // Initiate async touchmove dispatch after the start of a scroll sequence.
+ MoveTouchPoint(0, 0, 5);
+ WebGestureEvent followup_scroll;
+ 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, 10);
+ 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, 100);
+ EXPECT_TRUE(HasPendingAsyncTouchMove());
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_EQ(0U, GetAndResetSentEventCount());
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+
+ // Return the touch sequence to the original touchstart position. Note that
+ // this (0, 0) touchmove will coalesce with the previous (0, 100) touchmove.
+ MoveTouchPoint(0, 0, 0);
+ EXPECT_TRUE(HasPendingAsyncTouchMove());
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_EQ(0U, GetAndResetSentEventCount());
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+
+ // Queuing the final touchend should flush the pending, async touchmove.
+ ReleaseTouchPoint(0);
+ EXPECT_FALSE(HasPendingAsyncTouchMove());
+ EXPECT_EQ(WebInputEvent::TouchMove, sent_event().type);
+ EXPECT_FALSE(sent_event().cancelable);
+ EXPECT_EQ(0, sent_event().touches[0].position.x);
+ EXPECT_EQ(0, sent_event().touches[0].position.y);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+
+ // Touchend is not cancelable during async touch dispatch.
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_IGNORED);
+ EXPECT_EQ(WebInputEvent::TouchEnd, sent_event().type);
+ EXPECT_FALSE(sent_event().cancelable);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+}
+
// Ensure that async touch dispatch and touch ack timeout interactions work
// appropriately.
TEST_F(TouchEventQueueTest, AsyncTouchWithAckTimeout) {
- SetTouchScrollingMode(TouchEventQueue::TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE);
SetUpForTimeoutTesting(DefaultTouchTimeoutDelay());
// The touchstart should start the timeout.
@@ -2053,8 +1882,6 @@ TEST_F(TouchEventQueueTest, AsyncTouchWithAckTimeout) {
// Ensure that if the touch ack for an async touchmove triggers a follow-up
// touch event, that follow-up touch will be forwarded appropriately.
TEST_F(TouchEventQueueTest, AsyncTouchWithTouchCancelAfterAck) {
- SetTouchScrollingMode(TouchEventQueue::TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE);
-
PressTouchPoint(0, 0);
EXPECT_EQ(1U, GetAndResetSentEventCount());
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
@@ -2108,8 +1935,6 @@ TEST_F(TouchEventQueueTest, AsyncTouchWithTouchCancelAfterAck) {
// 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);
@@ -2147,8 +1972,6 @@ TEST_F(TouchEventQueueTest, AsyncTouchWithHardTouchStartReset) {
}
TEST_F(TouchEventQueueTest, TouchAbsorptionWithConsumedFirstMove) {
- SetTouchScrollingMode(TouchEventQueue::TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE);
-
// Queue a TouchStart.
PressTouchPoint(0, 1);
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
@@ -2187,6 +2010,65 @@ TEST_F(TouchEventQueueTest, TouchAbsorptionWithConsumedFirstMove) {
EXPECT_EQ(0U, GetAndResetSentEventCount());
}
+TEST_F(TouchEventQueueTest, TouchStartCancelableDuringScroll) {
+ // Queue a touchstart and touchmove that go unconsumed, transitioning to an
+ // active scroll sequence.
+ PressTouchPoint(0, 1);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ ASSERT_EQ(1U, GetAndResetSentEventCount());
+ EXPECT_TRUE(sent_event().cancelable);
+
+ MoveTouchPoint(0, 20, 5);
+ EXPECT_TRUE(sent_event().cancelable);
+ SendGestureEvent(blink::WebInputEvent::GestureScrollBegin);
+ SendGestureEvent(blink::WebInputEvent::GestureScrollUpdate);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ ASSERT_EQ(1U, GetAndResetSentEventCount());
+ EXPECT_TRUE(sent_event().cancelable);
+
+ // Even though scrolling has begun, touchstart events should be cancelable,
+ // allowing, for example, customized pinch processing.
+ PressTouchPoint(10, 11);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+ ASSERT_EQ(1U, GetAndResetSentEventCount());
+ EXPECT_TRUE(sent_event().cancelable);
+
+ // As the touch start was consumed, touchmoves should no longer be throttled.
+ MoveTouchPoint(1, 11, 11);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+ ASSERT_EQ(1U, GetAndResetSentEventCount());
+ EXPECT_TRUE(sent_event().cancelable);
+
+ // With throttling disabled, touchend and touchmove events should also be
+ // cancelable.
+ MoveTouchPoint(1, 12, 12);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+ ASSERT_EQ(1U, GetAndResetSentEventCount());
+ EXPECT_TRUE(sent_event().cancelable);
+ ReleaseTouchPoint(1);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+ ASSERT_EQ(1U, GetAndResetSentEventCount());
+ EXPECT_TRUE(sent_event().cancelable);
+
+ // If subsequent touchmoves aren't consumed, the generated scroll events
+ // will restore async touch dispatch.
+ MoveTouchPoint(0, 25, 5);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ SendGestureEvent(blink::WebInputEvent::GestureScrollUpdate);
+ ASSERT_EQ(1U, GetAndResetSentEventCount());
+ EXPECT_TRUE(sent_event().cancelable);
+ AdvanceTouchTime(kMinSecondsBetweenThrottledTouchmoves + 0.1);
+ MoveTouchPoint(0, 30, 5);
+ ASSERT_EQ(1U, GetAndResetSentEventCount());
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_IGNORED);
+ EXPECT_FALSE(sent_event().cancelable);
+
+ // The touchend will be uncancelable during an active scroll sequence.
+ ReleaseTouchPoint(0);
+ ASSERT_EQ(1U, GetAndResetSentEventCount());
+ EXPECT_FALSE(sent_event().cancelable);
+}
+
TEST_F(TouchEventQueueTest, UnseenTouchPointerIdsNotForwarded) {
SyntheticWebTouchEvent event;
event.PressPoint(0, 0);
@@ -2225,4 +2107,155 @@ TEST_F(TouchEventQueueTest, UnseenTouchPointerIdsNotForwarded) {
EXPECT_EQ(1U, GetAndResetAckedEventCount());
}
+// Tests that touch points states are correct in TouchMove events.
+TEST_F(TouchEventQueueTest, PointerStatesInTouchMove) {
+ PressTouchPoint(1, 1);
+ PressTouchPoint(2, 2);
+ PressTouchPoint(3, 3);
+ PressTouchPoint(4, 4);
+ EXPECT_EQ(4U, queued_event_count());
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+
+ // Receive ACK for the first three touch-events.
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(1U, queued_event_count());
+
+ // Test current touches state before sending TouchMoves.
+ const WebTouchEvent& event1 = sent_event();
+ EXPECT_EQ(WebInputEvent::TouchStart, event1.type);
+ EXPECT_EQ(WebTouchPoint::StateStationary, event1.touches[0].state);
+ EXPECT_EQ(WebTouchPoint::StateStationary, event1.touches[1].state);
+ EXPECT_EQ(WebTouchPoint::StateStationary, event1.touches[2].state);
+ EXPECT_EQ(WebTouchPoint::StatePressed, event1.touches[3].state);
+
+ // Move x-position for 1st touch, y-position for 2nd touch
+ // and do not move other touches.
+ MoveTouchPoints(0, 1.1f, 1.f, 1, 2.f, 20.001f);
+ MoveTouchPoints(2, 3.f, 3.f, 3, 4.f, 4.f);
+ EXPECT_EQ(2U, queued_event_count());
+
+ // Receive an ACK for the last TouchPress event.
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+
+ // 1st TouchMove is sent. Test for touches state.
+ const WebTouchEvent& event2 = sent_event();
+ EXPECT_EQ(WebInputEvent::TouchMove, event2.type);
+ EXPECT_EQ(WebTouchPoint::StateMoved, event2.touches[0].state);
+ EXPECT_EQ(WebTouchPoint::StateMoved, event2.touches[1].state);
+ EXPECT_EQ(WebTouchPoint::StateStationary, event2.touches[2].state);
+ EXPECT_EQ(WebTouchPoint::StateStationary, event2.touches[3].state);
+
+ // Move only 4th touch but not others.
+ MoveTouchPoints(0, 1.1f, 1.f, 1, 2.f, 20.001f);
+ MoveTouchPoints(2, 3.f, 3.f, 3, 4.1f, 4.1f);
+
+ // Receive an ACK for previous (1st) TouchMove.
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+
+ // 2nd TouchMove is sent. Test for touches state.
+ const WebTouchEvent& event3 = sent_event();
+ EXPECT_EQ(WebInputEvent::TouchMove, event3.type);
+ EXPECT_EQ(WebTouchPoint::StateStationary, event3.touches[0].state);
+ EXPECT_EQ(WebTouchPoint::StateStationary, event3.touches[1].state);
+ EXPECT_EQ(WebTouchPoint::StateStationary, event3.touches[2].state);
+ EXPECT_EQ(WebTouchPoint::StateMoved, event3.touches[3].state);
+}
+
+// Tests that touch point state is correct in TouchMove events
+// when point properties other than position changed.
+TEST_F(TouchEventQueueTest, PointerStatesWhenOtherThanPositionChanged) {
+ PressTouchPoint(1, 1);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+
+ // Default initial radiusX/Y is (1.f, 1.f).
+ // Default initial rotationAngle is 1.f.
+ // Default initial force is 1.f.
+
+ // Change touch point radius only.
+ ChangeTouchPointRadius(0, 1.5f, 1.f);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+
+ // TouchMove is sent. Test for pointer state.
+ const WebTouchEvent& event1 = sent_event();
+ EXPECT_EQ(WebInputEvent::TouchMove, event1.type);
+ EXPECT_EQ(WebTouchPoint::StateMoved, event1.touches[0].state);
+
+ // Change touch point force.
+ ChangeTouchPointForce(0, 0.9f);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+
+ // TouchMove is sent. Test for pointer state.
+ const WebTouchEvent& event2 = sent_event();
+ EXPECT_EQ(WebInputEvent::TouchMove, event2.type);
+ EXPECT_EQ(WebTouchPoint::StateMoved, event2.touches[0].state);
+
+ // Change touch point rotationAngle.
+ ChangeTouchPointRotationAngle(0, 1.1f);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+
+ // TouchMove is sent. Test for pointer state.
+ const WebTouchEvent& event3 = sent_event();
+ EXPECT_EQ(WebInputEvent::TouchMove, event3.type);
+ EXPECT_EQ(WebTouchPoint::StateMoved, event3.touches[0].state);
+
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_EQ(4U, GetAndResetSentEventCount());
+ EXPECT_EQ(4U, GetAndResetAckedEventCount());
+}
+
+// Tests that TouchMoves are filtered when none of the points are changed.
+TEST_F(TouchEventQueueTest, FilterTouchMovesWhenNoPointerChanged) {
+ PressTouchPoint(1, 1);
+ PressTouchPoint(2, 2);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_EQ(2U, GetAndResetSentEventCount());
+ EXPECT_EQ(2U, GetAndResetAckedEventCount());
+
+ // Move 1st touch point.
+ MoveTouchPoint(0, 10, 10);
+ EXPECT_EQ(1U, queued_event_count());
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ EXPECT_EQ(0U, GetAndResetAckedEventCount());
+
+ // TouchMove should be allowed and test for touches state.
+ const WebTouchEvent& event1 = sent_event();
+ EXPECT_EQ(WebInputEvent::TouchMove, event1.type);
+ EXPECT_EQ(WebTouchPoint::StateMoved, event1.touches[0].state);
+ EXPECT_EQ(WebTouchPoint::StateStationary, event1.touches[1].state);
+
+ // Do not really move any touch points, but use previous values.
+ MoveTouchPoint(0, 10, 10);
+ ChangeTouchPointRadius(1, 1, 1);
+ MoveTouchPoint(1, 2, 2);
+ EXPECT_EQ(2U, queued_event_count());
+ EXPECT_EQ(0U, GetAndResetSentEventCount());
+
+ // Receive an ACK for 1st TouchMove.
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+
+ // Tries to forward TouchMove but should be filtered
+ // when none of the touch points have changed.
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_EQ(0U, GetAndResetSentEventCount());
+ EXPECT_EQ(4U, GetAndResetAckedEventCount());
+ EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, acked_event_state());
+
+ // Move 2nd touch point.
+ MoveTouchPoint(1, 3, 3);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+
+ // TouchMove should be allowed and test for touches state.
+ const WebTouchEvent& event2 = sent_event();
+ EXPECT_EQ(WebInputEvent::TouchMove, event2.type);
+ EXPECT_EQ(WebTouchPoint::StateStationary, event2.touches[0].state);
+ EXPECT_EQ(WebTouchPoint::StateMoved, event2.touches[1].state);
+}
+
} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/touch_handle.cc b/chromium/content/browser/renderer_host/input/touch_handle.cc
deleted file mode 100644
index acfe3bd70f8..00000000000
--- a/chromium/content/browser/renderer_host/input/touch_handle.cc
+++ /dev/null
@@ -1,267 +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/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
deleted file mode 100644
index 7859febef23..00000000000
--- a/chromium/content/browser/renderer_host/input/touch_handle.h
+++ /dev/null
@@ -1,135 +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_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
deleted file mode 100644
index a3459e6c585..00000000000
--- a/chromium/content/browser/renderer_host/input/touch_handle_unittest.cc
+++ /dev/null
@@ -1,491 +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/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 3a9f2fd734e..3324d236f26 100644
--- a/chromium/content/browser/renderer_host/input/touch_input_browsertest.cc
+++ b/chromium/content/browser/renderer_host/input/touch_input_browsertest.cc
@@ -36,6 +36,11 @@ void GiveItSomeTime() {
const char kTouchEventDataURL[] =
"data:text/html;charset=utf-8,"
+#if defined(OS_ANDROID)
+ "<head>"
+ "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">"
+ "</head>"
+#endif
"<body onload='setup();'>"
"<div id='first'></div><div id='second'></div><div id='third'></div>"
"<style>"
@@ -112,8 +117,8 @@ class InputEventMessageFilter : public BrowserMessageFilter {
if (message.type() == InputHostMsg_HandleInputEvent_ACK::ID) {
InputHostMsg_HandleInputEvent_ACK::Param params;
InputHostMsg_HandleInputEvent_ACK::Read(&message, &params);
- WebInputEvent::Type type = params.a.type;
- InputEventAckState ack = params.a.state;
+ WebInputEvent::Type type = get<0>(params).type;
+ InputEventAckState ack = get<0>(params).state;
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(&InputEventMessageFilter::ReceivedEventAck,
this, type, ack));
@@ -159,7 +164,7 @@ class TouchInputBrowserTest : public ContentBrowserTest {
host->GetProcess()->AddFilter(filter_.get());
}
- void SetUpCommandLine(CommandLine* cmd) override {
+ void SetUpCommandLine(base::CommandLine* cmd) override {
cmd->AppendSwitchASCII(switches::kTouchEvents,
switches::kTouchEventsEnabled);
}
diff --git a/chromium/content/browser/renderer_host/input/touch_selection_controller.cc b/chromium/content/browser/renderer_host/input/touch_selection_controller.cc
deleted file mode 100644
index 4c8807d0fcc..00000000000
--- a/chromium/content/browser/renderer_host/input/touch_selection_controller.cc
+++ /dev/null
@@ -1,423 +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/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
deleted file mode 100644
index abe4ed46fac..00000000000
--- a/chromium/content/browser/renderer_host/input/touch_selection_controller.h
+++ /dev/null
@@ -1,150 +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_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
deleted file mode 100644
index de7d620ff97..00000000000
--- a/chromium/content/browser/renderer_host/input/touch_selection_controller_unittest.cc
+++ /dev/null
@@ -1,810 +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/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/web_input_event_builders_win.cc b/chromium/content/browser/renderer_host/input/web_input_event_builders_win.cc
index 73c9174bfe4..c1952a60064 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
@@ -6,6 +6,7 @@
#include "base/logging.h"
#include "content/browser/renderer_host/input/web_input_event_util.h"
+#include "ui/gfx/win/dpi.h"
using blink::WebInputEvent;
using blink::WebKeyboardEvent;
@@ -161,8 +162,9 @@ WebKeyboardEvent WebKeyboardEventBuilder::Build(HWND hwnd,
// this case.
// 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)
+ // already down, therefore this is an auto-repeat. Only apply this to key
+ // down events, to match DOM semantics.
+ if ((result.type == WebInputEvent::RawKeyDown) && (lparam & 0x40000000))
result.modifiers |= WebInputEvent::IsAutoRepeat;
result.modifiers |= GetLocationModifier(wparam, lparam);
@@ -203,7 +205,9 @@ WebMouseEvent WebMouseEventBuilder::Build(HWND hwnd,
result.button = WebMouseEvent::ButtonNone;
break;
case WM_MOUSELEAVE:
- result.type = WebInputEvent::MouseLeave;
+ // TODO(rbyers): This should be MouseLeave but is disabled temporarily.
+ // See http://crbug.com/450631
+ result.type = WebInputEvent::MouseMove;
result.button = WebMouseEvent::ButtonNone;
// set the current mouse position (relative to the client area of the
// current window) since none is specified for this event
@@ -253,8 +257,12 @@ WebMouseEvent WebMouseEventBuilder::Build(HWND hwnd,
POINT global_point = { result.x, result.y };
ClientToScreen(hwnd, &global_point);
- result.globalX = global_point.x;
- result.globalY = global_point.y;
+ // We need to convert the global point back to DIP before using it.
+ gfx::Point dip_global_point = gfx::win::ScreenToDIPPoint(
+ gfx::Point(global_point.x, global_point.y));
+
+ result.globalX = dip_global_point.x();
+ result.globalY = dip_global_point.y();
// calculate number of clicks:
diff --git a/chromium/content/browser/renderer_host/input/web_input_event_builders_win.h b/chromium/content/browser/renderer_host/input/web_input_event_builders_win.h
index 4cd6d0dea96..21aa7d3bf68 100644
--- a/chromium/content/browser/renderer_host/input/web_input_event_builders_win.h
+++ b/chromium/content/browser/renderer_host/input/web_input_event_builders_win.h
@@ -7,11 +7,12 @@
#include <windows.h>
+#include "content/common/content_export.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
namespace content {
-class WebKeyboardEventBuilder {
+class CONTENT_EXPORT WebKeyboardEventBuilder {
public:
static blink::WebKeyboardEvent Build(HWND hwnd,
UINT message,
@@ -20,7 +21,7 @@ class WebKeyboardEventBuilder {
DWORD time_ms);
};
-class WebMouseEventBuilder {
+class CONTENT_EXPORT WebMouseEventBuilder {
public:
static blink::WebMouseEvent Build(HWND hwnd,
UINT message,
@@ -29,7 +30,7 @@ class WebMouseEventBuilder {
DWORD time_ms);
};
-class WebMouseWheelEventBuilder {
+class CONTENT_EXPORT WebMouseWheelEventBuilder {
public:
static blink::WebMouseWheelEvent Build(HWND hwnd,
UINT message,
@@ -40,4 +41,4 @@ class WebMouseWheelEventBuilder {
} // namespace content
-#endif // CONTENT_BROWSER_RENDERER_HOST_WEB_INPUT_EVENT_BUILDERS_WIN_H_
+#endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_WEB_INPUT_EVENT_BUILDERS_WIN_H_
diff --git a/chromium/content/browser/renderer_host/input/web_input_event_unittest.cc b/chromium/content/browser/renderer_host/input/web_input_event_unittest.cc
new file mode 100644
index 00000000000..f7814365019
--- /dev/null
+++ b/chromium/content/browser/renderer_host/input/web_input_event_unittest.cc
@@ -0,0 +1,57 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/command_line.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
+#include "ui/events/event_constants.h"
+#include "ui/gfx/display.h"
+#include "ui/gfx/switches.h"
+
+#if defined(OS_WIN)
+#include "base/win/windows_version.h"
+#include "content/browser/renderer_host/input/web_input_event_builders_win.h"
+#endif
+
+using blink::WebMouseEvent;
+
+namespace content {
+
+#if defined(OS_WIN)
+// This test validates that Pixel to DIP conversion occurs as needed in the
+// WebMouseEventBuilder::Build function.
+TEST(WebInputEventBuilderTest, TestMouseEventScale) {
+ if (base::win::GetVersion() < base::win::VERSION_WIN7)
+ return;
+
+ gfx::Display::ResetForceDeviceScaleFactorForTesting();
+
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ command_line->AppendSwitchASCII(switches::kForceDeviceScaleFactor, "2");
+
+ // Synthesize a mouse move with x = 300 and y = 200.
+ WebMouseEvent mouse_move =
+ WebMouseEventBuilder::Build(::GetDesktopWindow(), WM_MOUSEMOVE, 0,
+ MAKELPARAM(300, 200), 100);
+
+ // The WebMouseEvent.x, WebMouseEvent.y, WebMouseEvent.windowX and
+ // WebMouseEvent.windowY fields should be in pixels on return and hence
+ // should be the same value as the x and y coordinates passed in to the
+ // WebMouseEventBuilder::Build function.
+ EXPECT_EQ(300, mouse_move.x);
+ EXPECT_EQ(200, mouse_move.y);
+
+ EXPECT_EQ(300, mouse_move.windowX);
+ EXPECT_EQ(200, mouse_move.windowY);
+
+ // WebMouseEvent.globalX and WebMouseEvent.globalY are calculated in DIPs.
+ EXPECT_EQ(150, mouse_move.globalX);
+ EXPECT_EQ(100, mouse_move.globalY);
+
+ command_line->AppendSwitchASCII(switches::kForceDeviceScaleFactor, "1");
+ gfx::Display::ResetForceDeviceScaleFactorForTesting();
+}
+#endif
+
+} // namespace content
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 81fc359e63c..ab4880739f2 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
@@ -11,9 +11,11 @@
#include "base/strings/string_util.h"
#include "content/common/input/web_touch_event_traits.h"
+#include "ui/events/blink/blink_event_util.h"
#include "ui/events/event_constants.h"
#include "ui/events/gesture_detection/gesture_event_data.h"
#include "ui/events/gesture_detection/motion_event.h"
+#include "ui/gfx/geometry/safe_integer_conversions.h"
using blink::WebGestureEvent;
using blink::WebInputEvent;
@@ -139,102 +141,6 @@ const char* GetKeyIdentifier(ui::KeyboardCode key_code) {
};
}
-WebInputEvent::Type ToWebInputEventType(MotionEvent::Action action) {
- switch (action) {
- case MotionEvent::ACTION_DOWN:
- return WebInputEvent::TouchStart;
- case MotionEvent::ACTION_MOVE:
- return WebInputEvent::TouchMove;
- case MotionEvent::ACTION_UP:
- return WebInputEvent::TouchEnd;
- case MotionEvent::ACTION_CANCEL:
- return WebInputEvent::TouchCancel;
- case MotionEvent::ACTION_POINTER_DOWN:
- return WebInputEvent::TouchStart;
- case MotionEvent::ACTION_POINTER_UP:
- return WebInputEvent::TouchEnd;
- }
- NOTREACHED() << "Invalid MotionEvent::Action.";
- return WebInputEvent::Undefined;
-}
-
-// Note that |is_action_pointer| is meaningful only in the context of
-// |ACTION_POINTER_UP| and |ACTION_POINTER_DOWN|; other actions map directly to
-// WebTouchPoint::State.
-WebTouchPoint::State ToWebTouchPointState(MotionEvent::Action action,
- bool is_action_pointer) {
- switch (action) {
- case MotionEvent::ACTION_DOWN:
- return WebTouchPoint::StatePressed;
- case MotionEvent::ACTION_MOVE:
- return WebTouchPoint::StateMoved;
- case MotionEvent::ACTION_UP:
- return WebTouchPoint::StateReleased;
- case MotionEvent::ACTION_CANCEL:
- return WebTouchPoint::StateCancelled;
- case MotionEvent::ACTION_POINTER_DOWN:
- return is_action_pointer ? WebTouchPoint::StatePressed
- : WebTouchPoint::StateStationary;
- case MotionEvent::ACTION_POINTER_UP:
- return is_action_pointer ? WebTouchPoint::StateReleased
- : WebTouchPoint::StateStationary;
- }
- NOTREACHED() << "Invalid MotionEvent::Action.";
- return WebTouchPoint::StateUndefined;
-}
-
-WebTouchPoint CreateWebTouchPoint(const MotionEvent& event,
- size_t pointer_index) {
- WebTouchPoint touch;
- touch.id = event.GetPointerId(pointer_index);
- touch.state = ToWebTouchPointState(
- event.GetAction(),
- static_cast<int>(pointer_index) == event.GetActionIndex());
- touch.position.x = event.GetX(pointer_index);
- touch.position.y = event.GetY(pointer_index);
- touch.screenPosition.x = event.GetRawX(pointer_index);
- touch.screenPosition.y = event.GetRawY(pointer_index);
-
- // 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;
-}
-
} // namespace
namespace content {
@@ -254,159 +160,6 @@ 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(
- ToWebInputEventType(event.GetAction()),
- (event.GetEventTime() - base::TimeTicks()).InSecondsF(),
- &result);
-
- result.modifiers = EventFlagsToWebEventModifiers(event.GetFlags());
- result.touchesLength =
- std::min(event.GetPointerCount(),
- static_cast<size_t>(WebTouchEvent::touchesLengthCap));
- DCHECK_GT(result.touchesLength, 0U);
-
- for (size_t i = 0; i < result.touchesLength; ++i)
- result.touches[i] = CreateWebTouchPoint(event, i);
-
- return result;
-}
-
-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;
- gesture.globalY = data.raw_y;
- gesture.timeStampSeconds = (data.time - base::TimeTicks()).InSecondsF();
- gesture.sourceDevice = blink::WebGestureDeviceTouchscreen;
-
- switch (data.type()) {
- case ui::ET_GESTURE_SHOW_PRESS:
- gesture.type = WebInputEvent::GestureShowPress;
- gesture.data.showPress.width = data.details.bounding_box_f().width();
- gesture.data.showPress.height = data.details.bounding_box_f().height();
- break;
- case ui::ET_GESTURE_DOUBLE_TAP:
- gesture.type = WebInputEvent::GestureDoubleTap;
- DCHECK_EQ(1, data.details.tap_count());
- gesture.data.tap.tapCount = data.details.tap_count();
- gesture.data.tap.width = data.details.bounding_box_f().width();
- gesture.data.tap.height = data.details.bounding_box_f().height();
- break;
- case ui::ET_GESTURE_TAP:
- gesture.type = WebInputEvent::GestureTap;
- DCHECK_EQ(1, data.details.tap_count());
- gesture.data.tap.tapCount = data.details.tap_count();
- gesture.data.tap.width = data.details.bounding_box_f().width();
- gesture.data.tap.height = data.details.bounding_box_f().height();
- break;
- case ui::ET_GESTURE_TAP_UNCONFIRMED:
- gesture.type = WebInputEvent::GestureTapUnconfirmed;
- DCHECK_EQ(1, data.details.tap_count());
- gesture.data.tap.tapCount = data.details.tap_count();
- gesture.data.tap.width = data.details.bounding_box_f().width();
- gesture.data.tap.height = data.details.bounding_box_f().height();
- break;
- case ui::ET_GESTURE_LONG_PRESS:
- gesture.type = WebInputEvent::GestureLongPress;
- gesture.data.longPress.width = data.details.bounding_box_f().width();
- gesture.data.longPress.height = data.details.bounding_box_f().height();
- break;
- case ui::ET_GESTURE_LONG_TAP:
- gesture.type = WebInputEvent::GestureLongTap;
- gesture.data.longPress.width = data.details.bounding_box_f().width();
- gesture.data.longPress.height = data.details.bounding_box_f().height();
- break;
- case ui::ET_GESTURE_SCROLL_BEGIN:
- gesture.type = WebInputEvent::GestureScrollBegin;
- gesture.data.scrollBegin.deltaXHint = data.details.scroll_x_hint();
- gesture.data.scrollBegin.deltaYHint = data.details.scroll_y_hint();
- break;
- case ui::ET_GESTURE_SCROLL_UPDATE:
- gesture.type = WebInputEvent::GestureScrollUpdate;
- gesture.data.scrollUpdate.deltaX = data.details.scroll_x();
- gesture.data.scrollUpdate.deltaY = data.details.scroll_y();
- break;
- case ui::ET_GESTURE_SCROLL_END:
- gesture.type = WebInputEvent::GestureScrollEnd;
- break;
- case ui::ET_SCROLL_FLING_START:
- gesture.type = WebInputEvent::GestureFlingStart;
- gesture.data.flingStart.velocityX = data.details.velocity_x();
- gesture.data.flingStart.velocityY = data.details.velocity_y();
- break;
- case ui::ET_SCROLL_FLING_CANCEL:
- gesture.type = WebInputEvent::GestureFlingCancel;
- break;
- case ui::ET_GESTURE_PINCH_BEGIN:
- gesture.type = WebInputEvent::GesturePinchBegin;
- break;
- case ui::ET_GESTURE_PINCH_UPDATE:
- gesture.type = WebInputEvent::GesturePinchUpdate;
- gesture.data.pinchUpdate.scale = data.details.scale();
- break;
- case ui::ET_GESTURE_PINCH_END:
- gesture.type = WebInputEvent::GesturePinchEnd;
- break;
- case ui::ET_GESTURE_TAP_CANCEL:
- gesture.type = WebInputEvent::GestureTapCancel;
- break;
- case ui::ET_GESTURE_TAP_DOWN:
- gesture.type = WebInputEvent::GestureTapDown;
- gesture.data.tapDown.width = data.details.bounding_box_f().width();
- gesture.data.tapDown.height = data.details.bounding_box_f().height();
- break;
- case ui::ET_GESTURE_BEGIN:
- case ui::ET_GESTURE_END:
- NOTREACHED() << "ET_GESTURE_BEGIN and ET_GESTURE_END are only produced "
- << "in Aura, and should never end up here.";
- break;
- default:
- NOTREACHED() << "ui::EventType provided wasn't a valid gesture event.";
- break;
- }
-
- 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;
@@ -429,8 +182,6 @@ int WebEventModifiersToEventFlags(int modifiers) {
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;
}
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 1cadd7d0050..c4b1a8c47a6 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
@@ -5,12 +5,14 @@
#ifndef CONTENT_BROWSER_RENDERER_HOST_INPUT_WEB_INPUT_EVENT_UTIL_H_
#define CONTENT_BROWSER_RENDERER_HOST_INPUT_WEB_INPUT_EVENT_UTIL_H_
+#include "base/time/time.h"
#include "content/common/content_export.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
#include "ui/events/keycodes/keyboard_codes.h"
namespace ui {
struct GestureEventData;
+struct GestureEventDetails;
class MotionEvent;
}
@@ -22,18 +24,6 @@ CONTENT_EXPORT void UpdateWindowsKeyCodeAndKeyIdentifier(
blink::WebKeyboardEvent* event,
ui::KeyboardCode windows_key_code);
-// Creates a WebTouchEvent from |event|, scaling all size components from
-// |event| by |scale|.
-CONTENT_EXPORT blink::WebTouchEvent CreateWebTouchEventFromMotionEvent(
- const ui::MotionEvent& event);
-
-// Creates a WebGestureEvent from |event|, scaling all size components from
-// |event| by |scale|.
-CONTENT_EXPORT blink::WebGestureEvent CreateWebGestureEventFromGestureEventData(
- const ui::GestureEventData& data);
-
-int EventFlagsToWebEventModifiers(int flags);
-
int WebEventModifiersToEventFlags(int modifiers);
} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/web_input_event_util_posix.cc b/chromium/content/browser/renderer_host/input/web_input_event_util_posix.cc
index 7ae224281f5..1eabf91a314 100644
--- a/chromium/content/browser/renderer_host/input/web_input_event_util_posix.cc
+++ b/chromium/content/browser/renderer_host/input/web_input_event_util_posix.cc
@@ -6,22 +6,6 @@
namespace content {
-ui::KeyboardCode GetWindowsKeyCodeWithoutLocation(ui::KeyboardCode key_code) {
- switch (key_code) {
- case ui::VKEY_LCONTROL:
- case ui::VKEY_RCONTROL:
- return ui::VKEY_CONTROL;
- case ui::VKEY_LSHIFT:
- case ui::VKEY_RSHIFT:
- return ui::VKEY_SHIFT;
- case ui::VKEY_LMENU:
- case ui::VKEY_RMENU:
- return ui::VKEY_MENU;
- default:
- return key_code;
- }
-}
-
blink::WebInputEvent::Modifiers GetLocationModifiersFromWindowsKeyCode(
ui::KeyboardCode key_code) {
switch (key_code) {
diff --git a/chromium/content/browser/renderer_host/input/web_input_event_util_posix.h b/chromium/content/browser/renderer_host/input/web_input_event_util_posix.h
index 9f2f4c05c02..d4d11afec58 100644
--- a/chromium/content/browser/renderer_host/input/web_input_event_util_posix.h
+++ b/chromium/content/browser/renderer_host/input/web_input_event_util_posix.h
@@ -10,7 +10,6 @@
namespace content {
-ui::KeyboardCode GetWindowsKeyCodeWithoutLocation(ui::KeyboardCode key_code);
blink::WebInputEvent::Modifiers GetLocationModifiersFromWindowsKeyCode(
ui::KeyboardCode key_code);
diff --git a/chromium/content/browser/renderer_host/input/web_input_event_util_unittest.cc b/chromium/content/browser/renderer_host/input/web_input_event_util_unittest.cc
index 1d29a070c17..862d6c14863 100644
--- a/chromium/content/browser/renderer_host/input/web_input_event_util_unittest.cc
+++ b/chromium/content/browser/renderer_host/input/web_input_event_util_unittest.cc
@@ -12,8 +12,12 @@
#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/blink/blink_event_util.h"
#include "ui/events/event_constants.h"
+#include "ui/events/gesture_detection/gesture_event_data.h"
#include "ui/events/gesture_detection/motion_event_generic.h"
+#include "ui/events/gesture_event_details.h"
+#include "ui/gfx/geometry/safe_integer_conversions.h"
using blink::WebInputEvent;
using blink::WebTouchEvent;
@@ -34,6 +38,7 @@ TEST(WebInputEventUtilTest, MotionEventConversion) {
MotionEventGeneric event(
MotionEvent::ACTION_DOWN, base::TimeTicks::Now(), pointer);
event.set_flags(ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN);
+ event.set_unique_event_id(123456U);
WebTouchEvent expected_event;
expected_event.type = WebInputEvent::TouchStart;
@@ -52,10 +57,54 @@ TEST(WebInputEventUtilTest, MotionEventConversion) {
expected_pointer.rotationAngle = 0.f;
expected_pointer.force = pointer.pressure;
expected_event.touches[0] = expected_pointer;
+ expected_event.uniqueTouchEventId = 123456U;
- WebTouchEvent actual_event = CreateWebTouchEventFromMotionEvent(event);
+ WebTouchEvent actual_event =
+ ui::CreateWebTouchEventFromMotionEvent(event, false);
EXPECT_EQ(WebInputEventTraits::ToString(expected_event),
WebInputEventTraits::ToString(actual_event));
}
+TEST(WebInputEventUtilTest, ScrollUpdateConversion) {
+ int motion_event_id = 0;
+ MotionEvent::ToolType tool_type = MotionEvent::TOOL_TYPE_UNKNOWN;
+ base::TimeTicks timestamp = base::TimeTicks::Now();
+ gfx::Vector2dF delta(-5.f, 10.f);
+ gfx::PointF pos(1.f, 2.f);
+ gfx::PointF raw_pos(11.f, 12.f);
+ size_t touch_points = 1;
+ gfx::RectF rect(pos, gfx::SizeF());
+ int flags = 0;
+ ui::GestureEventDetails details(ui::ET_GESTURE_SCROLL_UPDATE,
+ delta.x(),
+ delta.y());
+ details.mark_previous_scroll_update_in_sequence_prevented();
+ ui::GestureEventData event(details,
+ motion_event_id,
+ tool_type,
+ timestamp,
+ pos.x(),
+ pos.y(),
+ raw_pos.x(),
+ raw_pos.y(),
+ touch_points,
+ rect,
+ flags);
+
+ blink::WebGestureEvent web_event =
+ ui::CreateWebGestureEventFromGestureEventData(event);
+ EXPECT_EQ(WebInputEvent::GestureScrollUpdate, web_event.type);
+ EXPECT_EQ(0, web_event.modifiers);
+ EXPECT_EQ((timestamp - base::TimeTicks()).InSecondsF(),
+ web_event.timeStampSeconds);
+ EXPECT_EQ(gfx::ToFlooredInt(pos.x()), web_event.x);
+ EXPECT_EQ(gfx::ToFlooredInt(pos.y()), web_event.y);
+ EXPECT_EQ(gfx::ToFlooredInt(raw_pos.x()), web_event.globalX);
+ EXPECT_EQ(gfx::ToFlooredInt(raw_pos.y()), web_event.globalY);
+ EXPECT_EQ(blink::WebGestureDeviceTouchscreen, web_event.sourceDevice);
+ EXPECT_EQ(delta.x(), web_event.data.scrollUpdate.deltaX);
+ EXPECT_EQ(delta.y(), web_event.data.scrollUpdate.deltaY);
+ EXPECT_TRUE(web_event.data.scrollUpdate.previousUpdateInSequencePrevented);
+}
+
} // 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 25333b365c2..5126ad2bc2d 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,7 +7,8 @@
#include "base/command_line.h"
#include "base/memory/scoped_ptr.h"
#include "base/win/windows_version.h"
-#include "content/browser/renderer_host/legacy_render_widget_host_win_delegate.h"
+#include "content/browser/accessibility/browser_accessibility_manager_win.h"
+#include "content/browser/accessibility/browser_accessibility_win.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"
@@ -21,44 +22,42 @@
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() {
- if (::IsWindow(hwnd()))
- ::DestroyWindow(hwnd());
-}
-
// static
LegacyRenderWidgetHostHWND* LegacyRenderWidgetHostHWND::Create(
- HWND parent,
- LegacyRenderWidgetHostHWNDDelegate* delegate) {
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableLegacyIntermediateWindow)) {
+ 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.
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableLegacyIntermediateWindow) ||
+ (!GetWindowEventTarget(parent) && parent != ::GetDesktopWindow()))
return nullptr;
- }
LegacyRenderWidgetHostHWND* legacy_window_instance =
- new LegacyRenderWidgetHostHWND(parent, delegate);
- // If we failed to create the child, return NULL.
+ 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())) {
delete legacy_window_instance;
- return nullptr;
+ return NULL;
}
legacy_window_instance->Init();
return legacy_window_instance;
}
-void LegacyRenderWidgetHostHWND::UpdateParent(HWND parent) {
- if (!::IsWindow(hwnd()))
- return;
+void LegacyRenderWidgetHostHWND::Destroy() {
+ if (::IsWindow(hwnd()))
+ ::DestroyWindow(hwnd());
+}
+void LegacyRenderWidgetHostHWND::UpdateParent(HWND parent) {
+ if (GetWindowEventTarget(GetParent()))
+ GetWindowEventTarget(GetParent())->HandleParentChanged();
::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
@@ -71,49 +70,49 @@ void LegacyRenderWidgetHostHWND::UpdateParent(HWND parent) {
}
HWND LegacyRenderWidgetHostHWND::GetParent() {
- if (!::IsWindow(hwnd()))
- return NULL;
-
return ::GetParent(hwnd());
}
void LegacyRenderWidgetHostHWND::Show() {
- if (::IsWindow(hwnd()))
- ::ShowWindow(hwnd(), SW_SHOW);
+ ::ShowWindow(hwnd(), SW_SHOW);
}
void LegacyRenderWidgetHostHWND::Hide() {
- if (::IsWindow(hwnd()))
- ::ShowWindow(hwnd(), SW_HIDE);
+ ::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(),
SWP_NOREDRAW);
}
-LegacyRenderWidgetHostHWND::LegacyRenderWidgetHostHWND(
- HWND parent,
- LegacyRenderWidgetHostHWNDDelegate* delegate)
+void LegacyRenderWidgetHostHWND::OnFinalMessage(HWND hwnd) {
+ if (host_) {
+ host_->OnLegacyWindowDestroyed();
+ host_ = NULL;
+ }
+ delete this;
+}
+
+LegacyRenderWidgetHostHWND::LegacyRenderWidgetHostHWND(HWND parent)
: mouse_tracking_enabled_(false),
- delegate_(delegate) {
- DCHECK(delegate_);
+ host_(NULL) {
RECT rect = {0};
Base::Create(parent, rect, L"Chrome Legacy Window",
WS_CHILDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
WS_EX_TRANSPARENT);
}
+LegacyRenderWidgetHostHWND::~LegacyRenderWidgetHostHWND() {
+ DCHECK(!::IsWindow(hwnd()));
+}
+
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,
@@ -157,16 +156,24 @@ LRESULT LegacyRenderWidgetHostHWND::OnGetObject(UINT message,
return static_cast<LRESULT>(0L);
}
- if (OBJID_CLIENT != obj_id)
+ if (OBJID_CLIENT != obj_id || !host_)
+ return static_cast<LRESULT>(0L);
+
+ RenderWidgetHostImpl* rwhi = RenderWidgetHostImpl::From(
+ host_->GetRenderWidgetHost());
+ if (!rwhi)
return static_cast<LRESULT>(0L);
- base::win::ScopedComPtr<IAccessible> native_accessible(
- delegate_->GetNativeViewAccessible());
- if (!native_accessible)
+ BrowserAccessibilityManagerWin* manager =
+ static_cast<BrowserAccessibilityManagerWin*>(
+ rwhi->GetRootBrowserAccessibilityManager());
+ if (!manager)
return static_cast<LRESULT>(0L);
+ base::win::ScopedComPtr<IAccessible> root(
+ manager->GetRoot()->ToBrowserAccessibilityWin());
return LresultFromObject(IID_IAccessible, w_param,
- static_cast<IAccessible*>(native_accessible.Detach()));
+ static_cast<IAccessible*>(root.Detach()));
}
// We send keyboard/mouse/touch messages to the parent window via SendMessage.
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 3222e05c1d4..a1e952daf07 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
@@ -13,14 +13,15 @@
#include "base/basictypes.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"
+#include "ui/gfx/geometry/rect.h"
namespace ui {
class WindowEventTarget;
}
namespace content {
+class RenderWidgetHostViewAura;
+
// 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.
@@ -38,11 +39,12 @@ namespace content {
// 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,
-// and delegates its accessibility implementation to the
-// gfx::NativeViewAccessible provided by the owner class.
+// 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.
class CONTENT_EXPORT LegacyRenderWidgetHostHWND
: public ATL::CWindowImpl<LegacyRenderWidgetHostHWND,
NON_EXPORTED_BASE(ATL::CWindow),
@@ -54,14 +56,13 @@ class CONTENT_EXPORT LegacyRenderWidgetHostHWND
NON_EXPORTED_BASE(ATL::CWindow),
ATL::CWinTraits<WS_CHILD> > Base;
- 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 LegacyRenderWidgetHostHWND* Create(
- HWND parent,
- LegacyRenderWidgetHostHWNDDelegate* delegate);
+ static LegacyRenderWidgetHostHWND* Create(HWND parent);
+
+ // Destroys the HWND managed by this class.
+ void Destroy();
BEGIN_MSG_MAP_EX(LegacyRenderWidgetHostHWND)
MESSAGE_HANDLER_EX(WM_GETOBJECT, OnGetObject)
@@ -83,8 +84,6 @@ 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.
@@ -92,7 +91,7 @@ class CONTENT_EXPORT LegacyRenderWidgetHostHWND
void UpdateParent(HWND parent);
HWND GetParent();
- IAccessible* window_accessible() { return window_accessible_; }
+ IAccessible* window_accessible() { return window_accessible_.get(); }
// Functions to show and hide the window.
void Show();
@@ -101,9 +100,18 @@ class CONTENT_EXPORT LegacyRenderWidgetHostHWND
// Resizes the window to the bounds passed in.
void SetBounds(const gfx::Rect& bounds);
+ // The pointer to the containing RenderWidgetHostViewAura instance is passed
+ // here.
+ void set_host(RenderWidgetHostViewAura* host) {
+ host_ = host;
+ }
+
+ protected:
+ void OnFinalMessage(HWND hwnd) override;
+
private:
- LegacyRenderWidgetHostHWND(HWND parent,
- LegacyRenderWidgetHostHWNDDelegate* delegate);
+ LegacyRenderWidgetHostHWND(HWND parent);
+ ~LegacyRenderWidgetHostHWND() override;
bool Init();
@@ -128,16 +136,17 @@ class CONTENT_EXPORT LegacyRenderWidgetHostHWND
LRESULT OnNCCalcSize(UINT message, WPARAM w_param, LPARAM l_param);
LRESULT OnSize(UINT message, WPARAM w_param, LPARAM l_param);
- LegacyRenderWidgetHostHWNDDelegate* delegate_;
-
base::win::ScopedComPtr<IAccessible> window_accessible_;
// Set to true if we turned on mouse tracking.
bool mouse_tracking_enabled_;
+ RenderWidgetHostViewAura* host_;
+
DISALLOW_COPY_AND_ASSIGN(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
deleted file mode 100644
index a94d81e0939..00000000000
--- a/chromium/content/browser/renderer_host/legacy_render_widget_host_win_delegate.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (c) 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#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/OWNERS b/chromium/content/browser/renderer_host/media/OWNERS
index 0db86f8db0f..52968b10b24 100644
--- a/chromium/content/browser/renderer_host/media/OWNERS
+++ b/chromium/content/browser/renderer_host/media/OWNERS
@@ -1,9 +1,10 @@
dalecurtis@chromium.org
ddorwin@chromium.org
-perkj@chromium.org
scherkus@chromium.org
-tommi@chromium.org
-vrk@chromium.org
-wjia@chromium.org
xhwang@chromium.org
-xians@chromium.org
+
+# WebRTC OWNERS.
+perkj@chromium.org
+tommi@chromium.org
+
+per-file video_capture*=mcasas@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 e360eb0eef2..111dc1e2952 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
@@ -6,13 +6,13 @@
#include "base/bind.h"
#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram_macros.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/media_stream_request.h"
#include "media/audio/audio_input_ipc.h"
#include "media/audio/audio_manager_base.h"
#include "media/audio/audio_parameters.h"
#include "media/base/channel_layout.h"
-#include "media/base/scoped_histogram_timer.h"
#if defined(OS_CHROMEOS)
#include "chromeos/audio/cras_audio_handler.h"
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 a2d4ca4f92c..b123ce482f5 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
@@ -44,11 +44,12 @@ class CONTENT_EXPORT AudioInputDeviceManager : public MediaStreamProvider {
// is not opened, otherwise the opened device. Called on IO thread.
const StreamDeviceInfo* GetOpenedDeviceInfoById(int session_id);
+ void Unregister();
+
// MediaStreamProvider implementation, called on IO thread.
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;
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 7b421ba6d55..15dd9e610c7 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
@@ -71,11 +71,13 @@ AudioInputRendererHost::AudioEntry::AudioEntry()
AudioInputRendererHost::AudioEntry::~AudioEntry() {}
AudioInputRendererHost::AudioInputRendererHost(
+ int render_process_id,
media::AudioManager* audio_manager,
MediaStreamManager* media_stream_manager,
AudioMirroringManager* audio_mirroring_manager,
media::UserInputMonitor* user_input_monitor)
: BrowserMessageFilter(AudioMsgStart),
+ render_process_id_(render_process_id),
audio_manager_(audio_manager),
media_stream_manager_(media_stream_manager),
audio_mirroring_manager_(audio_mirroring_manager),
@@ -84,7 +86,7 @@ AudioInputRendererHost::AudioInputRendererHost(
media::AudioLogFactory::AUDIO_INPUT_CONTROLLER)) {}
AudioInputRendererHost::~AudioInputRendererHost() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(audio_entries_.empty());
}
@@ -272,7 +274,7 @@ bool AudioInputRendererHost::OnMessageReceived(const IPC::Message& message) {
void AudioInputRendererHost::OnCreateStream(
int stream_id,
- int render_view_id,
+ int render_frame_id,
int session_id,
const AudioInputHostMsg_CreateStream_Config& config) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -282,32 +284,28 @@ void AudioInputRendererHost::OnCreateStream(
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));
+ base::Bind(&AudioInputRendererHost::DoCreateStream, this, stream_id,
+ render_frame_id, session_id, config));
} else {
- DoCreateStream(stream_id, render_view_id, session_id, config);
+ DoCreateStream(stream_id, render_frame_id, session_id, config);
}
#else
- DoCreateStream(stream_id, render_view_id, session_id, config);
+ DoCreateStream(stream_id, render_frame_id, session_id, config);
#endif
}
void AudioInputRendererHost::DoCreateStream(
int stream_id,
- int render_view_id,
+ int render_frame_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
+ << "AIRH::OnCreateStream(render_frame_id=" << render_frame_id
<< ", session_id=" << session_id << ")";
- DCHECK_GT(render_view_id, 0);
+ DCHECK_GT(render_frame_id, 0);
// media::AudioParameters is validated in the deserializer.
if (LookupById(stream_id) != NULL) {
@@ -423,6 +421,8 @@ void AudioInputRendererHost::DoCreateStream(
entry->stream_id = stream_id;
audio_entries_.insert(std::make_pair(stream_id, entry.release()));
audio_log_->OnCreated(stream_id, audio_params, device_id);
+ MediaInternals::GetInstance()->SetWebContentsTitleForAudioLogEntry(
+ stream_id, render_process_id_, render_frame_id, audio_log_.get());
}
void AudioInputRendererHost::OnRecordStream(int stream_id) {
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 b847bf6d4dc..eca0a6499be 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
@@ -101,7 +101,8 @@ class CONTENT_EXPORT AudioInputRendererHost
// Called from UI thread from the owner of this object.
// |user_input_monitor| is used for typing detection and can be NULL.
- AudioInputRendererHost(media::AudioManager* audio_manager,
+ AudioInputRendererHost(int render_process_id,
+ media::AudioManager* audio_manager,
MediaStreamManager* media_stream_manager,
AudioMirroringManager* audio_mirroring_manager,
media::UserInputMonitor* user_input_monitor);
@@ -140,17 +141,17 @@ class CONTENT_EXPORT AudioInputRendererHost
// registers to AudioInputDeviceManager. Then calls DoCreateStream.
// For non-ChromeOS: Just calls DoCreateStream.
void OnCreateStream(int stream_id,
- int render_view_id,
+ int render_frame_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|.
+ // consumed by an entity in the RenderFrame referenced by |render_frame_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 DoCreateStream(int stream_id,
- int render_view_id,
+ int render_frame_id,
int session_id,
const AudioInputHostMsg_CreateStream_Config& config);
@@ -209,6 +210,9 @@ class CONTENT_EXPORT AudioInputRendererHost
void MaybeUnregisterKeyboardMicStream(
const AudioInputHostMsg_CreateStream_Config& config);
+ // ID of the RenderProcessHost that owns this instance.
+ const int render_process_id_;
+
// Used to create an AudioInputController.
media::AudioManager* audio_manager_;
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 43555fcdb19..5f140ac2b8f 100644
--- a/chromium/content/browser/renderer_host/media/audio_renderer_host.cc
+++ b/chromium/content/browser/renderer_host/media/audio_renderer_host.cc
@@ -18,9 +18,12 @@
#include "content/browser/renderer_host/media/audio_input_device_manager.h"
#include "content/browser/renderer_host/media/audio_sync_reader.h"
#include "content/browser/renderer_host/media/media_stream_manager.h"
+#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/common/media/audio_messages.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/media_observer.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_view_host.h"
#include "content/public/common/content_switches.h"
#include "media/audio/audio_manager_base.h"
#include "media/base/audio_bus.h"
@@ -31,12 +34,35 @@ using media::AudioManager;
namespace content {
+namespace {
+// TODO(aiolos): This is a temporary hack until the resource scheduler is
+// migrated to RenderFrames for the Site Isolation project. It's called in
+// response to low frequency playback state changes. http://crbug.com/472869
+int RenderFrameIdToRenderViewId(int render_process_id, int render_frame_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ RenderFrameHost* const frame =
+ RenderFrameHost::FromID(render_process_id, render_frame_id);
+ return frame ? frame->GetRenderViewHost()->GetRoutingID() : MSG_ROUTING_NONE;
+}
+
+void NotifyResourceDispatcherOfAudioStateChange(int render_process_id,
+ bool is_playing,
+ int render_view_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (render_view_id == MSG_ROUTING_NONE || !ResourceDispatcherHostImpl::Get())
+ return;
+
+ ResourceDispatcherHostImpl::Get()->OnAudioRenderHostStreamStateChanged(
+ render_process_id, render_view_id, is_playing);
+}
+
+} // namespace
+
class AudioRendererHost::AudioEntry
: public media::AudioOutputController::EventHandler {
public:
AudioEntry(AudioRendererHost* host,
int stream_id,
- int render_view_id,
int render_frame_id,
const media::AudioParameters& params,
const std::string& output_device_id,
@@ -48,10 +74,6 @@ class AudioRendererHost::AudioEntry
return stream_id_;
}
- int render_view_id() const {
- return render_view_id_;
- }
-
int render_frame_id() const { return render_frame_id_; }
media::AudioOutputController* controller() const { return controller_.get(); }
@@ -73,13 +95,11 @@ class AudioRendererHost::AudioEntry
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_;
- // The routing ID of the source render view/frame.
- const int render_view_id_;
+ // The routing ID of the source RenderFrame.
const int render_frame_id_;
// Shared memory for transmission of the audio data. Used by |reader_|.
@@ -97,7 +117,6 @@ class AudioRendererHost::AudioEntry
AudioRendererHost::AudioEntry::AudioEntry(
AudioRendererHost* host,
int stream_id,
- int render_view_id,
int render_frame_id,
const media::AudioParameters& params,
const std::string& output_device_id,
@@ -105,7 +124,6 @@ AudioRendererHost::AudioEntry::AudioEntry(
scoped_ptr<media::AudioOutputController::SyncReader> reader)
: host_(host),
stream_id_(stream_id),
- render_view_id_(render_view_id),
render_frame_id_(render_frame_id),
shared_memory_(shared_memory.Pass()),
reader_(reader.Pass()),
@@ -146,14 +164,11 @@ AudioRendererHost::~AudioRendererHost() {
}
void AudioRendererHost::GetOutputControllers(
- int render_view_id,
- const RenderViewHost::GetAudioOutputControllersCallback& callback) const {
+ const RenderProcessHost::GetAudioOutputControllersCallback&
+ callback) const {
BrowserThread::PostTaskAndReplyWithResult(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(&AudioRendererHost::DoGetOutputControllers, this,
- render_view_id),
- callback);
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&AudioRendererHost::DoGetOutputControllers, this), callback);
}
void AudioRendererHost::OnChannelClosing() {
@@ -202,16 +217,6 @@ void AudioRendererHost::AudioEntry::OnError() {
base::Bind(&AudioRendererHost::ReportErrorAndClose, host_, stream_id_));
}
-void AudioRendererHost::AudioEntry::OnDeviceChange(int new_buffer_size,
- int new_sample_rate) {
- BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(base::IgnoreResult(&AudioRendererHost::Send), host_,
- new AudioMsg_NotifyDeviceChanged(
- stream_id_, new_buffer_size, new_sample_rate)));
-}
-
void AudioRendererHost::DoCompleteCreation(int stream_id) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -281,17 +286,15 @@ void AudioRendererHost::DoNotifyStreamStateChanged(int stream_id,
UpdateNumPlayingStreams(entry, is_playing);
}
-RenderViewHost::AudioOutputControllerList
-AudioRendererHost::DoGetOutputControllers(int render_view_id) const {
+RenderProcessHost::AudioOutputControllerList
+AudioRendererHost::DoGetOutputControllers() const {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- RenderViewHost::AudioOutputControllerList controllers;
+ RenderProcessHost::AudioOutputControllerList controllers;
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());
+ controllers.push_back(it->second->controller());
}
return controllers;
@@ -313,16 +316,16 @@ bool AudioRendererHost::OnMessageReceived(const IPC::Message& message) {
return handled;
}
-void AudioRendererHost::OnCreateStream(
- int stream_id, int render_view_id, int render_frame_id, int session_id,
- const media::AudioParameters& params) {
+void AudioRendererHost::OnCreateStream(int stream_id,
+ int render_frame_id,
+ int session_id,
+ const media::AudioParameters& params) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DVLOG(1) << "AudioRendererHost@" << this
<< "::OnCreateStream(stream_id=" << stream_id
- << ", render_view_id=" << render_view_id
+ << ", render_frame_id=" << render_frame_id
<< ", session_id=" << session_id << ")";
- DCHECK_GT(render_view_id, 0);
DCHECK_GT(render_frame_id, 0);
// media::AudioParameters is validated in the deserializer.
@@ -362,7 +365,6 @@ void AudioRendererHost::OnCreateStream(
scoped_ptr<AudioEntry> entry(new AudioEntry(this,
stream_id,
- render_view_id,
render_frame_id,
params,
output_device_id,
@@ -374,6 +376,8 @@ void AudioRendererHost::OnCreateStream(
}
audio_entries_.insert(std::make_pair(stream_id, entry.release()));
audio_log_->OnCreated(stream_id, params, output_device_id);
+ MediaInternals::GetInstance()->SetWebContentsTitleForAudioLogEntry(
+ stream_id, render_process_id_, render_frame_id, audio_log_.get());
}
void AudioRendererHost::OnPlayStream(int stream_id) {
@@ -480,19 +484,23 @@ void AudioRendererHost::UpdateNumPlayingStreams(AudioEntry* entry,
bool should_alert_resource_scheduler;
if (is_playing) {
should_alert_resource_scheduler =
- !RenderViewHasActiveAudio(entry->render_view_id());
+ !RenderFrameHasActiveAudio(entry->render_frame_id());
entry->set_playing(true);
base::AtomicRefCountInc(&num_playing_streams_);
} else {
entry->set_playing(false);
should_alert_resource_scheduler =
- !RenderViewHasActiveAudio(entry->render_view_id());
+ !RenderFrameHasActiveAudio(entry->render_frame_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);
+ BrowserThread::PostTaskAndReplyWithResult(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&RenderFrameIdToRenderViewId, render_process_id_,
+ entry->render_frame_id()),
+ base::Bind(&NotifyResourceDispatcherOfAudioStateChange,
+ render_process_id_, is_playing));
}
}
@@ -500,12 +508,12 @@ bool AudioRendererHost::HasActiveAudio() {
return !base::AtomicRefCountIsZero(&num_playing_streams_);
}
-bool AudioRendererHost::RenderViewHasActiveAudio(int render_view_id) const {
+bool AudioRendererHost::RenderFrameHasActiveAudio(int render_frame_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())
+ if (entry->render_frame_id() == render_frame_id && entry->playing())
return true;
}
return false;
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 11bc13f3900..69d3ea14c73 100644
--- a/chromium/content/browser/renderer_host/media/audio_renderer_host.h
+++ b/chromium/content/browser/renderer_host/media/audio_renderer_host.h
@@ -48,7 +48,7 @@
#include "content/common/content_export.h"
#include "content/public/browser/browser_message_filter.h"
#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_process_host.h"
#include "media/audio/audio_io.h"
#include "media/audio/audio_logging.h"
#include "media/audio/audio_output_controller.h"
@@ -77,8 +77,8 @@ class CONTENT_EXPORT AudioRendererHost : public BrowserMessageFilter {
// Calls |callback| with the list of AudioOutputControllers for this object.
void GetOutputControllers(
- int render_view_id,
- const RenderViewHost::GetAudioOutputControllersCallback& callback) const;
+ const RenderProcessHost::GetAudioOutputControllersCallback&
+ callback) const;
// BrowserMessageFilter implementation.
void OnChannelClosing() override;
@@ -89,9 +89,9 @@ class CONTENT_EXPORT AudioRendererHost : public BrowserMessageFilter {
// 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;
+ // Returns true if any streams managed by the RenderFrame identified by
+ // |render_frame_id| are actively playing. Can be called from any thread.
+ bool RenderFrameHasActiveAudio(int render_frame_id) const;
private:
friend class AudioRendererHostTest;
@@ -112,14 +112,13 @@ class CONTENT_EXPORT AudioRendererHost : public BrowserMessageFilter {
// Audio related IPC message handlers.
// Creates an audio output stream with the specified format whose data is
- // produced by an entity in the render view referenced by |render_view_id|.
+ // produced by an entity in the RenderFrame referenced by |render_frame_id|.
// |session_id| is used for unified IO to find out which input device to be
// opened for the stream. For clients that do not use unified IO,
// |session_id| will be ignored.
// Upon success/failure, the peer is notified via the NotifyStreamCreated
// message.
void OnCreateStream(int stream_id,
- int render_view_id,
int render_frame_id,
int session_id,
const media::AudioParameters& params);
@@ -144,8 +143,7 @@ class CONTENT_EXPORT AudioRendererHost : public BrowserMessageFilter {
// Send playing/paused status to the renderer.
void DoNotifyStreamStateChanged(int stream_id, bool is_playing);
- RenderViewHost::AudioOutputControllerList DoGetOutputControllers(
- int render_view_id) const;
+ RenderProcessHost::AudioOutputControllerList DoGetOutputControllers() const;
// Send an error message to the renderer.
void SendErrorMessage(int stream_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 8c03eaca66b..c50430e074e 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
@@ -29,7 +29,6 @@ using ::testing::NotNull;
namespace {
const int kRenderProcessId = 1;
-const int kRenderViewId = 4;
const int kRenderFrameId = 5;
const int kStreamId = 50;
} // namespace
@@ -154,7 +153,7 @@ class AudioRendererHostTest : public testing::Test {
media_stream_manager_.get());
// Simulate IPC channel connected.
- host_->set_peer_pid_for_testing(base::GetCurrentProcId());
+ host_->set_peer_process_for_testing(base::Process::Current());
}
~AudioRendererHostTest() override {
@@ -198,8 +197,7 @@ class AudioRendererHostTest : public testing::Test {
media::AudioParameters::kAudioCDSampleRate, 16,
media::AudioParameters::kAudioCDSampleRate / 10);
}
- host_->OnCreateStream(kStreamId, kRenderViewId, kRenderFrameId, session_id,
- params);
+ host_->OnCreateStream(kStreamId, kRenderFrameId, session_id, params);
// At some point in the future, a corresponding RemoveDiverter() call must
// be made.
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 e6657ef74ca..7c493e1c68c 100644
--- a/chromium/content/browser/renderer_host/media/audio_sync_reader.cc
+++ b/chromium/content/browser/renderer_host/media/audio_sync_reader.cc
@@ -39,7 +39,7 @@ namespace content {
AudioSyncReader::AudioSyncReader(base::SharedMemory* shared_memory,
const media::AudioParameters& params)
: shared_memory_(shared_memory),
- mute_audio_(CommandLine::ForCurrentProcess()->HasSwitch(
+ mute_audio_(base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kMuteAudio)),
packet_size_(shared_memory_->requested_size()),
renderer_callback_count_(0),
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 77174cc6205..421d816606f 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
@@ -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_MEDIA_MEDIA_CAPTURE_DEVICES_H
-#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_CAPTURE_DEVICES_H
+#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_CAPTURE_DEVICES_IMPL_H_
+#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_CAPTURE_DEVICES_IMPL_H_
#include "base/memory/singleton.h"
#include "content/public/browser/media_capture_devices.h"
@@ -46,4 +46,4 @@ class MediaCaptureDevicesImpl : public MediaCaptureDevices {
} // namespace content
-#endif // CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_CAPTURE_DEVICES_H
+#endif // CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_CAPTURE_DEVICES_IMPL_H_
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 9b3d22f2661..848f78c49c8 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
@@ -115,12 +115,12 @@ class MockMediaStreamDispatcherHost : public MediaStreamDispatcherHost,
StreamDeviceInfoArray enumerated_devices_;
private:
- virtual ~MockMediaStreamDispatcherHost() {}
+ ~MockMediaStreamDispatcherHost() override {}
// 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 {
+ bool Send(IPC::Message* message) override {
CHECK(message);
current_ipc_ = message;
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 0124f21297f..1ae9fe52e5e 100644
--- a/chromium/content/browser/renderer_host/media/media_stream_manager.cc
+++ b/chromium/content/browser/renderer_host/media/media_stream_manager.cc
@@ -12,6 +12,7 @@
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/power_monitor/power_monitor.h"
+#include "base/profiler/scoped_tracker.h"
#include "base/rand_util.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
@@ -93,7 +94,7 @@ void ParseStreamType(const StreamOptions& options,
if (audio_stream_source == kMediaStreamSourceTab) {
*audio_type = content::MEDIA_TAB_AUDIO_CAPTURE;
} else if (audio_stream_source == kMediaStreamSourceSystem) {
- *audio_type = content::MEDIA_LOOPBACK_AUDIO_CAPTURE;
+ *audio_type = content::MEDIA_DESKTOP_AUDIO_CAPTURE;
}
} else {
// This is normal audio device capture.
@@ -134,6 +135,27 @@ void FilterAudioEffects(const StreamOptions& options, int* effects) {
}
}
+// Unlike other effects, hotword is off by default, so turn it on if it's
+// requested and available.
+void EnableHotwordEffect(const StreamOptions& options, int* effects) {
+ DCHECK(effects);
+ std::string value;
+ if (options.GetFirstAudioConstraintByName(
+ kMediaStreamAudioHotword, &value, NULL) && value == "true") {
+#if defined(OS_CHROMEOS)
+ chromeos::AudioDeviceList devices;
+ chromeos::CrasAudioHandler::Get()->GetAudioDevices(&devices);
+ // Only enable if a hotword device exists.
+ for (size_t i = 0; i < devices.size(); ++i) {
+ if (devices[i].type == chromeos::AUDIO_TYPE_AOKR) {
+ DCHECK(devices[i].is_input);
+ *effects |= media::AudioParameters::HOTWORD;
+ }
+ }
+#endif
+ }
+}
+
// Private helper method for SendMessageToNativeLog() that obtains the global
// MediaStreamManager instance on the UI thread before sending |message| to the
// webrtcLoggingPrivate API.
@@ -217,7 +239,9 @@ class MediaStreamManager::DeviceRequest {
salt_callback(salt_callback),
state_(NUM_MEDIA_TYPES, MEDIA_REQUEST_STATE_NOT_REQUESTED),
audio_type_(MEDIA_NO_SERVICE),
- video_type_(MEDIA_NO_SERVICE) {
+ video_type_(MEDIA_NO_SERVICE),
+ target_process_id_(-1),
+ target_frame_id_(-1) {
}
~DeviceRequest() {}
@@ -243,6 +267,8 @@ class MediaStreamManager::DeviceRequest {
void CreateUIRequest(const std::string& requested_audio_device_id,
const std::string& requested_video_device_id) {
DCHECK(!ui_request_);
+ target_process_id_ = requesting_process_id;
+ target_frame_id_ = requesting_frame_id;
ui_request_.reset(new MediaStreamRequest(requesting_process_id,
requesting_frame_id,
page_request_id,
@@ -258,9 +284,10 @@ 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 CreateTabCaptureUIRequest(int target_render_process_id,
- int target_render_frame_id,
- const std::string& tab_capture_id) {
+ int target_render_frame_id) {
DCHECK(!ui_request_);
+ target_process_id_ = target_render_process_id;
+ target_frame_id_ = target_render_frame_id;
ui_request_.reset(new MediaStreamRequest(target_render_process_id,
target_render_frame_id,
page_request_id,
@@ -271,10 +298,12 @@ class MediaStreamManager::DeviceRequest {
"",
audio_type_,
video_type_));
- ui_request_->tab_capture_device_id = tab_capture_id;
}
- const MediaStreamRequest* UIRequest() const { return ui_request_.get(); }
+ bool HasUIRequest() const { return ui_request_.get() != nullptr; }
+ scoped_ptr<MediaStreamRequest> DetachUIRequest() {
+ return ui_request_.Pass();
+ }
// Update the request state and notify observers.
void SetState(MediaStreamType stream_type, MediaRequestState new_state) {
@@ -292,14 +321,8 @@ class MediaStreamManager::DeviceRequest {
if (!media_observer)
return;
- // If |ui_request_| doesn't exist, it means that the request has not yet
- // been setup fully and there are no valid observers.
- if (!ui_request_)
- return;
-
media_observer->OnMediaRequestStateChanged(
- ui_request_->render_process_id, ui_request_->render_frame_id,
- ui_request_->page_request_id, ui_request_->security_origin,
+ target_process_id_, target_frame_id_, page_request_id, security_origin,
stream_type, new_state);
}
@@ -344,11 +367,15 @@ class MediaStreamManager::DeviceRequest {
scoped_ptr<MediaStreamUIProxy> ui_proxy;
+ std::string tab_capture_device_id;
+
private:
std::vector<MediaRequestState> state_;
scoped_ptr<MediaStreamRequest> ui_request_;
MediaStreamType audio_type_;
MediaStreamType video_type_;
+ int target_process_id_;
+ int target_frame_id_;
};
MediaStreamManager::EnumerationCache::EnumerationCache()
@@ -473,7 +500,7 @@ void MediaStreamManager::GenerateStream(MediaStreamRequester* requester,
bool user_gesture) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DVLOG(1) << "GenerateStream()";
- if (CommandLine::ForCurrentProcess()->HasSwitch(
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kUseFakeUIForMediaStream)) {
UseFakeUI(scoped_ptr<FakeMediaStreamUIProxy>());
}
@@ -967,10 +994,25 @@ void MediaStreamManager::StartMonitoring() {
#if defined(OS_MACOSX)
void MediaStreamManager::StartMonitoringOnUIThread() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ // TODO(erikchen): Remove ScopedTracker below once crbug.com/458404 is fixed.
+ tracked_objects::ScopedTracker tracking_profile1(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "458404 MediaStreamManager::GetBrowserMainLoop"));
BrowserMainLoop* browser_main_loop = content::BrowserMainLoop::GetInstance();
if (browser_main_loop) {
- browser_main_loop->device_monitor_mac()
- ->StartMonitoring(audio_manager_->GetWorkerTaskRunner());
+ // TODO(erikchen): Remove ScopedTracker below once crbug.com/458404 is
+ // fixed.
+ tracked_objects::ScopedTracker tracking_profile2(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "458404 MediaStreamManager::GetWorkerTaskRunner"));
+ const scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+ audio_manager_->GetWorkerTaskRunner();
+ // TODO(erikchen): Remove ScopedTracker below once crbug.com/458404 is
+ // fixed.
+ tracked_objects::ScopedTracker tracking_profile3(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "458404 MediaStreamManager::DeviceMonitorMac::StartMonitoring"));
+ browser_main_loop->device_monitor_mac()->StartMonitoring(task_runner);
}
}
#endif
@@ -1142,7 +1184,7 @@ void MediaStreamManager::DeleteRequest(const std::string& label) {
void MediaStreamManager::PostRequestToUI(const std::string& label,
DeviceRequest* request) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(request->UIRequest());
+ DCHECK(request->HasUIRequest());
DVLOG(1) << "PostRequestToUI({label= " << label << "})";
const MediaStreamType audio_type = request->audio_type();
@@ -1182,7 +1224,7 @@ void MediaStreamManager::PostRequestToUI(const std::string& label,
}
request->ui_proxy->RequestAccess(
- *request->UIRequest(),
+ request->DetachUIRequest(),
base::Bind(&MediaStreamManager::HandleAccessRequestResponse,
base::Unretained(this), label));
}
@@ -1319,10 +1361,10 @@ bool MediaStreamManager::SetupTabCaptureRequest(DeviceRequest* request) {
request->video_type() != MEDIA_NO_SERVICE)) {
return false;
}
+ request->tab_capture_device_id = capture_device_id;
request->CreateTabCaptureUIRequest(target_render_process_id,
- target_render_frame_id,
- capture_device_id);
+ target_render_frame_id);
DVLOG(3) << "SetupTabCaptureRequest "
<< ", {capture_device_id = " << capture_device_id << "}"
@@ -1333,7 +1375,7 @@ bool MediaStreamManager::SetupTabCaptureRequest(DeviceRequest* request) {
}
bool MediaStreamManager::SetupScreenCaptureRequest(DeviceRequest* request) {
- DCHECK(request->audio_type() == MEDIA_LOOPBACK_AUDIO_CAPTURE ||
+ DCHECK(request->audio_type() == MEDIA_DESKTOP_AUDIO_CAPTURE ||
request->video_type() == MEDIA_DESKTOP_VIDEO_CAPTURE);
// For screen capture we only support two valid combinations:
@@ -1341,7 +1383,7 @@ bool MediaStreamManager::SetupScreenCaptureRequest(DeviceRequest* request) {
// (2) screen video capture with loopback audio capture.
if (request->video_type() != MEDIA_DESKTOP_VIDEO_CAPTURE ||
(request->audio_type() != MEDIA_NO_SERVICE &&
- request->audio_type() != MEDIA_LOOPBACK_AUDIO_CAPTURE)) {
+ request->audio_type() != MEDIA_DESKTOP_AUDIO_CAPTURE)) {
LOG(ERROR) << "Invalid screen capture request.";
return false;
}
@@ -1412,6 +1454,8 @@ bool MediaStreamManager::FindExistingRequestedDeviceInfo(
// is set to and not what the capabilities are.
FilterAudioEffects(request->options,
&existing_device_info->device.input.effects);
+ EnableHotwordEffect(request->options,
+ &existing_device_info->device.input.effects);
*existing_request_state = request->state(device_it->device.type);
return true;
}
@@ -1579,25 +1623,45 @@ void MediaStreamManager::FinalizeMediaAccessRequest(
}
void MediaStreamManager::InitializeDeviceManagersOnIOThread() {
+ // TODO(dalecurtis): Remove ScopedTracker below once crbug.com/457525 is
+ // fixed.
+ tracked_objects::ScopedTracker tracking_profile1(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "457525 MediaStreamManager::InitializeDeviceManagersOnIOThread 1"));
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (device_task_runner_.get())
return;
device_task_runner_ = audio_manager_->GetWorkerTaskRunner();
+ // TODO(dalecurtis): Remove ScopedTracker below once crbug.com/457525 is
+ // fixed.
+ tracked_objects::ScopedTracker tracking_profile2(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "457525 MediaStreamManager::InitializeDeviceManagersOnIOThread 2"));
audio_input_device_manager_ = new AudioInputDeviceManager(audio_manager_);
audio_input_device_manager_->Register(this, device_task_runner_);
+ // TODO(dalecurtis): Remove ScopedTracker below once crbug.com/457525 is
+ // fixed.
+ tracked_objects::ScopedTracker tracking_profile3(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "457525 MediaStreamManager::InitializeDeviceManagersOnIOThread 3"));
// We want to be notified of IO message loop destruction to delete the thread
// and the device managers.
io_loop_ = base::MessageLoop::current();
io_loop_->AddDestructionObserver(this);
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kUseFakeDeviceForMediaStream)) {
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kUseFakeDeviceForMediaStream)) {
audio_input_device_manager()->UseFakeDevice();
}
+ // TODO(dalecurtis): Remove ScopedTracker below once crbug.com/457525 is
+ // fixed.
+ tracked_objects::ScopedTracker tracking_profile4(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "457525 MediaStreamManager::InitializeDeviceManagersOnIOThread 4"));
video_capture_manager_ =
new VideoCaptureManager(media::VideoCaptureDeviceFactory::CreateFactory(
BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI)));
@@ -1651,6 +1715,8 @@ void MediaStreamManager::Opened(MediaStreamType stream_type,
// request asks for.
FilterAudioEffects(request->options,
&device_it->device.input.effects);
+ EnableHotwordEffect(request->options,
+ &device_it->device.input.effects);
device_it->device.matched_output = info->device.matched_output;
}
@@ -1888,7 +1954,7 @@ void MediaStreamManager::HandleAccessRequestResponse(
if (device_info.device.type == content::MEDIA_TAB_VIDEO_CAPTURE ||
device_info.device.type == content::MEDIA_TAB_AUDIO_CAPTURE) {
- device_info.device.id = request->UIRequest()->tab_capture_device_id;
+ device_info.device.id = request->tab_capture_device_id;
// Initialize the sample_rate and channel_layout here since for audio
// mirroring, we don't go through EnumerateDevices where these are usually
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 9499e32f257..b95d1ebd0df 100644
--- a/chromium/content/browser/renderer_host/media/media_stream_manager.h
+++ b/chromium/content/browser/renderer_host/media/media_stream_manager.h
@@ -289,7 +289,7 @@ class CONTENT_EXPORT MediaStreamManager
// MEDIA_TAB_VIDEO_CAPTURE for being posted to the UI by parsing
// StreamOptions::Constraints for requested tab capture IDs.
bool SetupTabCaptureRequest(DeviceRequest* request);
- // Prepare |request| of type MEDIA_LOOPBACK_AUDIO_CAPTURE and/or
+ // Prepare |request| of type MEDIA_DESKTOP_AUDIO_CAPTURE and/or
// MEDIA_DESKTOP_VIDEO_CAPTURE for being posted to the UI by parsing
// StreamOptions::Constraints for the requested desktop ID.
bool SetupScreenCaptureRequest(DeviceRequest* request);
diff --git a/chromium/content/browser/renderer_host/media/media_stream_provider.h b/chromium/content/browser/renderer_host/media/media_stream_provider.h
index 3413a99bd34..551e36d8b45 100644
--- a/chromium/content/browser/renderer_host/media/media_stream_provider.h
+++ b/chromium/content/browser/renderer_host/media/media_stream_provider.h
@@ -67,9 +67,6 @@ class CONTENT_EXPORT MediaStreamProvider
const scoped_refptr<base::SingleThreadTaskRunner>&
device_task_runner) = 0;
- // Unregisters the previously registered listener.
- virtual void Unregister() = 0;
-
// Enumerates existing capture devices and calls |DevicesEnumerated|.
virtual void EnumerateDevices(MediaStreamType stream_type) = 0;
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 d6d827540a6..bcb3575c213 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,6 +5,7 @@
#include "content/browser/renderer_host/media/media_stream_ui_proxy.h"
#include "base/command_line.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_thread.h"
@@ -13,13 +14,35 @@
namespace content {
+void SetAndCheckAncestorFlag(MediaStreamRequest* request) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ RenderFrameHostImpl* rfh =
+ RenderFrameHostImpl::FromID(request->render_process_id,
+ request->render_frame_id);
+
+ if (rfh == NULL) {
+ // RenderFrame destroyed before the request is handled?
+ return;
+ }
+ FrameTreeNode* node = rfh->frame_tree_node();
+
+ while (node->parent() != NULL) {
+ if (!node->HasSameOrigin(*node->parent())) {
+ request->all_ancestors_have_same_origin = false;
+ return;
+ }
+ node = node->parent();
+ }
+ request->all_ancestors_have_same_origin = true;
+}
+
class MediaStreamUIProxy::Core {
public:
explicit Core(const base::WeakPtr<MediaStreamUIProxy>& proxy,
RenderFrameHostDelegate* test_render_delegate);
~Core();
- void RequestAccess(const MediaStreamRequest& request);
+ void RequestAccess(scoped_ptr<MediaStreamRequest> request);
bool CheckAccess(const GURL& security_origin,
MediaStreamType type,
int process_id,
@@ -58,11 +81,11 @@ MediaStreamUIProxy::Core::~Core() {
}
void MediaStreamUIProxy::Core::RequestAccess(
- const MediaStreamRequest& request) {
+ scoped_ptr<MediaStreamRequest> request) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
RenderFrameHostDelegate* render_delegate = GetRenderFrameHostDelegate(
- request.render_process_id, request.render_frame_id);
+ request->render_process_id, request->render_frame_id);
// Tab may have gone away, or has no delegate from which to request access.
if (!render_delegate) {
@@ -71,10 +94,11 @@ void MediaStreamUIProxy::Core::RequestAccess(
scoped_ptr<MediaStreamUI>());
return;
}
+ SetAndCheckAncestorFlag(request.get());
render_delegate->RequestMediaAccessPermission(
- request, base::Bind(&Core::ProcessAccessRequestResponse,
- weak_factory_.GetWeakPtr()));
+ *request, base::Bind(&Core::ProcessAccessRequestResponse,
+ weak_factory_.GetWeakPtr()));
}
bool MediaStreamUIProxy::Core::CheckAccess(const GURL& security_origin,
@@ -154,14 +178,15 @@ MediaStreamUIProxy::~MediaStreamUIProxy() {
}
void MediaStreamUIProxy::RequestAccess(
- const MediaStreamRequest& request,
+ scoped_ptr<MediaStreamRequest> request,
const ResponseCallback& response_callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
response_callback_ = response_callback;
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
- base::Bind(&Core::RequestAccess, base::Unretained(core_.get()), request));
+ base::Bind(&Core::RequestAccess, base::Unretained(core_.get()),
+ base::Passed(&request)));
}
void MediaStreamUIProxy::CheckAccess(
@@ -262,14 +287,14 @@ void FakeMediaStreamUIProxy::SetCameraAccess(bool access) {
}
void FakeMediaStreamUIProxy::RequestAccess(
- const MediaStreamRequest& request,
+ scoped_ptr<MediaStreamRequest> request,
const ResponseCallback& response_callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
response_callback_ = response_callback;
- if (CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kUseFakeUIForMediaStream) == "deny") {
+ if (base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kUseFakeUIForMediaStream) == "deny") {
// Immediately deny the request.
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
@@ -289,25 +314,25 @@ void FakeMediaStreamUIProxy::RequestAccess(
for (MediaStreamDevices::const_iterator it = devices_.begin();
it != devices_.end(); ++it) {
if (!accepted_audio &&
- IsAudioInputMediaType(request.audio_type) &&
+ IsAudioInputMediaType(request->audio_type) &&
IsAudioInputMediaType(it->type) &&
- (request.requested_audio_device_id.empty() ||
- request.requested_audio_device_id == it->id)) {
+ (request->requested_audio_device_id.empty() ||
+ request->requested_audio_device_id == it->id)) {
devices_to_use.push_back(*it);
accepted_audio = true;
} else if (!accepted_video &&
- IsVideoMediaType(request.video_type) &&
+ IsVideoMediaType(request->video_type) &&
IsVideoMediaType(it->type) &&
- (request.requested_video_device_id.empty() ||
- request.requested_video_device_id == it->id)) {
+ (request->requested_video_device_id.empty() ||
+ request->requested_video_device_id == it->id)) {
devices_to_use.push_back(*it);
accepted_video = true;
}
}
// 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)) {
+ if ((request->audio_type != MEDIA_NO_SERVICE && !accepted_audio) ||
+ (request->video_type != MEDIA_NO_SERVICE && !accepted_video)) {
devices_to_use.clear();
}
@@ -332,8 +357,8 @@ void FakeMediaStreamUIProxy::CheckAccess(
type == MEDIA_DEVICE_VIDEO_CAPTURE);
bool have_access = false;
- if (CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kUseFakeUIForMediaStream) != "deny") {
+ if (base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kUseFakeUIForMediaStream) != "deny") {
have_access =
type == MEDIA_DEVICE_AUDIO_CAPTURE ? mic_access_ : camera_access_;
}
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 23fc592e62b..117f7c4a666 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
@@ -38,7 +38,7 @@ class CONTENT_EXPORT MediaStreamUIProxy {
// WebContentsDelegate::RequestMediaAccessPermission(). The specified
// |response_callback| is called when the WebContentsDelegate approves or
// denies request.
- virtual void RequestAccess(const MediaStreamRequest& request,
+ virtual void RequestAccess(scoped_ptr<MediaStreamRequest> request,
const ResponseCallback& response_callback);
// Checks if we have permission to access the microphone or camera. Note that
@@ -97,7 +97,7 @@ class CONTENT_EXPORT FakeMediaStreamUIProxy : public MediaStreamUIProxy {
void SetCameraAccess(bool access);
// MediaStreamUIProxy overrides.
- void RequestAccess(const MediaStreamRequest& request,
+ void RequestAccess(scoped_ptr<MediaStreamRequest> request,
const ResponseCallback& response_callback) override;
void CheckAccess(const GURL& security_origin,
MediaStreamType type,
diff --git a/chromium/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc b/chromium/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc
index 4eb7546e651..373de9d2480 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
@@ -6,19 +6,18 @@
#include "base/message_loop/message_loop.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"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/rect.h"
+#include "ui/gfx/geometry/rect.h"
using testing::_;
using testing::Return;
using testing::SaveArg;
namespace content {
-namespace {
+namespace {
class MockRenderFrameHostDelegate : public RenderFrameHostDelegate {
public:
MOCK_METHOD2(RequestMediaAccessPermission,
@@ -76,28 +75,31 @@ class MediaStreamUIProxyTest : public testing::Test {
MATCHER_P(SameRequest, expected, "") {
return
- expected.render_process_id == arg.render_process_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 &&
- expected.requested_audio_device_id == arg.requested_audio_device_id &&
- expected.requested_video_device_id == arg.requested_video_device_id &&
- expected.audio_type == arg.audio_type &&
- expected.video_type == arg.video_type;
+ expected->render_process_id == arg.render_process_id &&
+ expected->render_frame_id == arg.render_frame_id &&
+ expected->security_origin == arg.security_origin &&
+ expected->request_type == arg.request_type &&
+ expected->requested_audio_device_id == arg.requested_audio_device_id &&
+ expected->requested_video_device_id == arg.requested_video_device_id &&
+ expected->audio_type == arg.audio_type &&
+ expected->video_type == arg.video_type;
}
TEST_F(MediaStreamUIProxyTest, Deny) {
- MediaStreamRequest request(0, 0, 0, GURL("http://origin/"), false,
+ scoped_ptr<MediaStreamRequest> request (
+ new MediaStreamRequest(0, 0, 0, GURL("http://origin/"),
+ false,
MEDIA_GENERATE_STREAM, std::string(),
std::string(),
MEDIA_DEVICE_AUDIO_CAPTURE,
- MEDIA_DEVICE_VIDEO_CAPTURE);
+ MEDIA_DEVICE_VIDEO_CAPTURE));
+ MediaStreamRequest* request_ptr = request.get();
proxy_->RequestAccess(
- request, base::Bind(&MockResponseCallback::OnAccessRequestResponse,
- base::Unretained(&response_callback_)));
+ request.Pass(), base::Bind(&MockResponseCallback::OnAccessRequestResponse,
+ base::Unretained(&response_callback_)));
MediaResponseCallback callback;
- EXPECT_CALL(delegate_, RequestMediaAccessPermission(SameRequest(request), _))
+ EXPECT_CALL(delegate_, RequestMediaAccessPermission(SameRequest(request_ptr),
+ _))
.WillOnce(SaveArg<1>(&callback));
message_loop_.RunUntilIdle();
ASSERT_FALSE(callback.is_null());
@@ -114,16 +116,20 @@ TEST_F(MediaStreamUIProxyTest, Deny) {
}
TEST_F(MediaStreamUIProxyTest, AcceptAndStart) {
- MediaStreamRequest request(0, 0, 0, GURL("http://origin/"), false,
+ scoped_ptr<MediaStreamRequest> request (
+ new MediaStreamRequest(0, 0, 0,
+ GURL("http://origin/"), false,
MEDIA_GENERATE_STREAM, std::string(),
std::string(),
MEDIA_DEVICE_AUDIO_CAPTURE,
- MEDIA_DEVICE_VIDEO_CAPTURE);
+ MEDIA_DEVICE_VIDEO_CAPTURE));
+ MediaStreamRequest* request_ptr = request.get();
proxy_->RequestAccess(
- request, base::Bind(&MockResponseCallback::OnAccessRequestResponse,
- base::Unretained(&response_callback_)));
+ request.Pass(), base::Bind(&MockResponseCallback::OnAccessRequestResponse,
+ base::Unretained(&response_callback_)));
MediaResponseCallback callback;
- EXPECT_CALL(delegate_, RequestMediaAccessPermission(SameRequest(request), _))
+ EXPECT_CALL(delegate_, RequestMediaAccessPermission(SameRequest(request_ptr),
+ _))
.WillOnce(SaveArg<1>(&callback));
message_loop_.RunUntilIdle();
ASSERT_FALSE(callback.is_null());
@@ -148,16 +154,20 @@ TEST_F(MediaStreamUIProxyTest, AcceptAndStart) {
// Verify that the proxy can be deleted before the request is processed.
TEST_F(MediaStreamUIProxyTest, DeleteBeforeAccepted) {
- MediaStreamRequest request(0, 0, 0, GURL("http://origin/"), false,
+ scoped_ptr<MediaStreamRequest> request (
+ new MediaStreamRequest(0, 0, 0,
+ GURL("http://origin/"), false,
MEDIA_GENERATE_STREAM, std::string(),
std::string(),
MEDIA_DEVICE_AUDIO_CAPTURE,
- MEDIA_DEVICE_VIDEO_CAPTURE);
+ MEDIA_DEVICE_VIDEO_CAPTURE));
+ MediaStreamRequest* request_ptr = request.get();
proxy_->RequestAccess(
- request, base::Bind(&MockResponseCallback::OnAccessRequestResponse,
- base::Unretained(&response_callback_)));
+ request.Pass(), base::Bind(&MockResponseCallback::OnAccessRequestResponse,
+ base::Unretained(&response_callback_)));
MediaResponseCallback callback;
- EXPECT_CALL(delegate_, RequestMediaAccessPermission(SameRequest(request), _))
+ EXPECT_CALL(delegate_, RequestMediaAccessPermission(SameRequest(request_ptr)
+ , _))
.WillOnce(SaveArg<1>(&callback));
message_loop_.RunUntilIdle();
ASSERT_FALSE(callback.is_null());
@@ -170,16 +180,20 @@ TEST_F(MediaStreamUIProxyTest, DeleteBeforeAccepted) {
}
TEST_F(MediaStreamUIProxyTest, StopFromUI) {
- MediaStreamRequest request(0, 0, 0, GURL("http://origin/"), false,
+ scoped_ptr<MediaStreamRequest> request (
+ new MediaStreamRequest(0, 0, 0,
+ GURL("http://origin/"), false,
MEDIA_GENERATE_STREAM, std::string(),
std::string(),
MEDIA_DEVICE_AUDIO_CAPTURE,
- MEDIA_DEVICE_VIDEO_CAPTURE);
+ MEDIA_DEVICE_VIDEO_CAPTURE));
+ MediaStreamRequest* request_ptr = request.get();
proxy_->RequestAccess(
- request, base::Bind(&MockResponseCallback::OnAccessRequestResponse,
- base::Unretained(&response_callback_)));
+ request.Pass(), base::Bind(&MockResponseCallback::OnAccessRequestResponse,
+ base::Unretained(&response_callback_)));
MediaResponseCallback callback;
- EXPECT_CALL(delegate_, RequestMediaAccessPermission(SameRequest(request), _))
+ EXPECT_CALL(delegate_, RequestMediaAccessPermission(SameRequest(request_ptr)
+ , _))
.WillOnce(SaveArg<1>(&callback));
message_loop_.RunUntilIdle();
ASSERT_FALSE(callback.is_null());
@@ -214,22 +228,22 @@ TEST_F(MediaStreamUIProxyTest, StopFromUI) {
}
TEST_F(MediaStreamUIProxyTest, WindowIdCallbackCalled) {
- MediaStreamRequest request(0,
- 0,
- 0,
- GURL("http://origin/"),
- false,
- MEDIA_GENERATE_STREAM,
- std::string(),
+ scoped_ptr<MediaStreamRequest> request (
+ new MediaStreamRequest(0, 0, 0,
+ GURL("http://origin/"), false,
+ MEDIA_GENERATE_STREAM, std::string(),
std::string(),
MEDIA_NO_SERVICE,
- MEDIA_DESKTOP_VIDEO_CAPTURE);
+ MEDIA_DESKTOP_VIDEO_CAPTURE));
+ MediaStreamRequest* request_ptr = request.get();
+
proxy_->RequestAccess(
- request,
+ request.Pass(),
base::Bind(&MockResponseCallback::OnAccessRequestResponse,
base::Unretained(&response_callback_)));
MediaResponseCallback callback;
- EXPECT_CALL(delegate_, RequestMediaAccessPermission(SameRequest(request), _))
+ EXPECT_CALL(delegate_, RequestMediaAccessPermission(SameRequest(request_ptr),
+ _))
.WillOnce(SaveArg<1>(&callback));
message_loop_.RunUntilIdle();
diff --git a/chromium/content/browser/renderer_host/media/mock_media_observer.cc b/chromium/content/browser/renderer_host/media/mock_media_observer.cc
deleted file mode 100644
index 731801fe798..00000000000
--- a/chromium/content/browser/renderer_host/media/mock_media_observer.cc
+++ /dev/null
@@ -1,13 +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/media/mock_media_observer.h"
-
-namespace content {
-
-MockMediaObserver::MockMediaObserver() {}
-
-MockMediaObserver::~MockMediaObserver() {}
-
-} // namespace 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
deleted file mode 100644
index ae4e7e61f28..00000000000
--- a/chromium/content/browser/renderer_host/media/mock_media_observer.h
+++ /dev/null
@@ -1,32 +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_MEDIA_MOCK_MEDIA_OBSERVER_H_
-#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_MOCK_MEDIA_OBSERVER_H_
-
-#include <string>
-
-#include "base/basictypes.h"
-#include "content/public/browser/media_observer.h"
-#include "media/audio/audio_parameters.h"
-#include "media/base/media_log_event.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-namespace content {
-
-class MockMediaObserver : public MediaObserver {
- public:
- MockMediaObserver();
- virtual ~MockMediaObserver();
-
- MOCK_METHOD6(OnMediaRequestStateChanged,
- void(int render_process_id, int render_frame_id,
- int page_request_id, const GURL& security_origin,
- MediaStreamType stream_type,
- const MediaRequestState state));
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_RENDERER_HOST_MEDIA_MOCK_MEDIA_OBSERVER_H_
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 cae185d6598..e3accebb63a 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
@@ -42,7 +42,7 @@ PeerConnectionTrackerHost::~PeerConnectionTrackerHost() {
}
void PeerConnectionTrackerHost::OnChannelConnected(int32 peer_pid) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(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
@@ -56,7 +56,7 @@ void PeerConnectionTrackerHost::OnChannelConnected(int32 peer_pid) {
}
void PeerConnectionTrackerHost::OnChannelClosing() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
base::PowerMonitor* power_monitor = base::PowerMonitor::Get();
if (power_monitor)
power_monitor->RemoveObserver(this);
@@ -112,7 +112,7 @@ void PeerConnectionTrackerHost::OnSuspend() {
}
void PeerConnectionTrackerHost::SendOnSuspendOnUIThread() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
content::RenderProcessHost* host =
content::RenderProcessHost::FromID(render_process_id_);
if (host)
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 f583a94adaa..894a6710d0d 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_buffer_pool.cc
+++ b/chromium/content/browser/renderer_host/media/video_capture_buffer_pool.cc
@@ -4,18 +4,195 @@
#include "content/browser/renderer_host/media/video_capture_buffer_pool.h"
-#include "base/bind.h"
-#include "base/callback.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/stl_util.h"
+#include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
+#include "content/common/gpu/client/gpu_memory_buffer_impl.h"
+#include "content/public/browser/browser_thread.h"
#include "media/base/video_frame.h"
-#include "media/base/video_util.h"
+
+using media::VideoFrame;
namespace content {
const int VideoCaptureBufferPool::kInvalidId = -1;
+VideoFrame::Format VideoPixelFormatToVideoFrameFormat(
+ media::VideoPixelFormat pixel_format) {
+ static struct {
+ media::VideoPixelFormat pixel_format;
+ VideoFrame::Format frame_format;
+ } const kVideoPixelFormatToVideoFrameFormat[] = {
+ {media::PIXEL_FORMAT_I420, VideoFrame::I420},
+ {media::PIXEL_FORMAT_TEXTURE, VideoFrame::NATIVE_TEXTURE},
+ {media::PIXEL_FORMAT_GPUMEMORYBUFFER, VideoFrame::NATIVE_TEXTURE},
+ };
+
+ for (const auto& format_pair : kVideoPixelFormatToVideoFrameFormat) {
+ if (format_pair.pixel_format == pixel_format)
+ return format_pair.frame_format;
+ }
+ LOG(ERROR) << "Unsupported VideoPixelFormat "
+ << media::VideoCaptureFormat::PixelFormatToString(pixel_format);
+ return VideoFrame::UNKNOWN;
+}
+
+// A simple holder of a memory-backed buffer and accesors to it.
+class SimpleBufferHandle final : public VideoCaptureBufferPool::BufferHandle {
+ public:
+ SimpleBufferHandle(void* data, size_t size) : data_(data), size_(size) {}
+ ~SimpleBufferHandle() override {}
+
+ size_t size() const override { return size_; }
+ void* data() override { return data_; }
+ gfx::GpuMemoryBufferType GetType() override {
+ return gfx::SHARED_MEMORY_BUFFER;
+ }
+ ClientBuffer AsClientBuffer() override { return nullptr; }
+
+ private:
+ void* const data_;
+ const size_t size_;
+};
+
+// A holder of a GpuMemoryBuffer-backed buffer, Map()ed on ctor and Unmap()ed on
+// dtor. Holds a weak reference to its GpuMemoryBuffer.
+// TODO(mcasas) Map()ed on ctor, or on first use?
+class GpuMemoryBufferBufferHandle
+ final : public VideoCaptureBufferPool::BufferHandle {
+ public:
+ GpuMemoryBufferBufferHandle(gfx::GpuMemoryBuffer* gmb, size_t size)
+ : gmb_(gmb),
+ data_(new void* [GpuMemoryBufferImpl::
+ NumberOfPlanesForGpuMemoryBufferFormat(
+ gmb_->GetFormat())]),
+ size_(size) {
+ DCHECK(gmb && !gmb_->IsMapped());
+ gmb_->Map(data_.get());
+ }
+ ~GpuMemoryBufferBufferHandle() override { gmb_->Unmap(); }
+
+ size_t size() const override { return size_; }
+ void* data() override { return data_[0]; }
+ gfx::GpuMemoryBufferType GetType() override {
+ return gmb_->GetHandle().type;
+ }
+ ClientBuffer AsClientBuffer() override { return gmb_->AsClientBuffer(); }
+
+ private:
+ gfx::GpuMemoryBuffer* const gmb_;
+ scoped_ptr<void*[]> data_;
+ const size_t size_;
+};
+
+// Tracker specifics for SharedMemory.
+class VideoCaptureBufferPool::SharedMemTracker final : public Tracker {
+ public:
+ SharedMemTracker();
+ bool Init(VideoFrame::Format format, const gfx::Size& dimensions) override;
+
+ size_t mapped_size() const override { return shared_memory_.mapped_size(); }
+
+ scoped_ptr<BufferHandle> GetBufferHandle() override {
+ return make_scoped_ptr(
+ new SimpleBufferHandle(shared_memory_.memory(), mapped_size()));
+ }
+
+ bool ShareToProcess(base::ProcessHandle process_handle,
+ base::SharedMemoryHandle* new_handle) override {
+ return shared_memory_.ShareToProcess(process_handle, new_handle);
+ }
+
+ private:
+ // The memory created to be shared with renderer processes.
+ base::SharedMemory shared_memory_;
+};
+
+// Tracker specifics for GpuMemoryBuffer. Owns one GpuMemoryBuffer and its
+// associated pixel dimensions.
+class VideoCaptureBufferPool::GpuMemoryBufferTracker final : public Tracker {
+ public:
+ GpuMemoryBufferTracker();
+ bool Init(VideoFrame::Format format, const gfx::Size& dimensions) override;
+ ~GpuMemoryBufferTracker() override;
+
+ size_t mapped_size() const override { return packed_size_; }
+ scoped_ptr<BufferHandle> GetBufferHandle() override {
+ return make_scoped_ptr(new GpuMemoryBufferBufferHandle(
+ gpu_memory_buffer_.get(), packed_size_));
+ }
+
+ bool ShareToProcess(base::ProcessHandle process_handle,
+ base::SharedMemoryHandle* new_handle) override {
+ return true;
+ }
+
+ private:
+ size_t packed_size_;
+ scoped_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer_;
+};
+
+VideoCaptureBufferPool::SharedMemTracker::SharedMemTracker() : Tracker() {
+}
+
+bool VideoCaptureBufferPool::SharedMemTracker::Init(
+ VideoFrame::Format format,
+ const gfx::Size& dimensions) {
+ DVLOG(2) << "allocating ShMem of " << dimensions.ToString();
+ set_pixel_format(format);
+ // Input |dimensions| can be 0x0 for trackers that do not require memory
+ // backing. The allocated size is calculated using VideoFrame methods since
+ // this will be the abstraction used to wrap the underlying data.
+ set_pixel_count(dimensions.GetArea());
+ const size_t byte_count = VideoFrame::AllocationSize(format, dimensions);
+ if (!byte_count)
+ return true;
+ return shared_memory_.CreateAndMapAnonymous(byte_count);
+}
+
+VideoCaptureBufferPool::GpuMemoryBufferTracker::GpuMemoryBufferTracker()
+ : Tracker(), gpu_memory_buffer_(nullptr) {}
+
+VideoCaptureBufferPool::GpuMemoryBufferTracker::~GpuMemoryBufferTracker() {
+ if (gpu_memory_buffer_->IsMapped())
+ gpu_memory_buffer_->Unmap();
+}
+
+bool VideoCaptureBufferPool::GpuMemoryBufferTracker::Init(
+ VideoFrame::Format format,
+ const gfx::Size& dimensions) {
+ DVLOG(2) << "allocating GMB for " << dimensions.ToString();
+ // BrowserGpuMemoryBufferManager::current() may not be accessed on IO Thread.
+ DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK(BrowserGpuMemoryBufferManager::current());
+ set_pixel_format(format);
+ set_pixel_count(dimensions.GetArea());
+ gpu_memory_buffer_ =
+ BrowserGpuMemoryBufferManager::current()->AllocateGpuMemoryBuffer(
+ dimensions,
+ gfx::GpuMemoryBuffer::BGRA_8888,
+ gfx::GpuMemoryBuffer::MAP);
+ DLOG_IF(ERROR, !gpu_memory_buffer_.get()) << "Allocating GpuMemoryBuffer";
+ if (!gpu_memory_buffer_.get())
+ return false;
+ int plane_sizes;
+ gpu_memory_buffer_->GetStride(&plane_sizes);
+ packed_size_ = plane_sizes * dimensions.height();
+ return true;
+}
+
+//static
+scoped_ptr<VideoCaptureBufferPool::Tracker>
+VideoCaptureBufferPool::Tracker::CreateTracker(bool use_gmb) {
+ if (!use_gmb)
+ return make_scoped_ptr(new SharedMemTracker());
+ else
+ return make_scoped_ptr(new GpuMemoryBufferTracker());
+}
+
+VideoCaptureBufferPool::Tracker::~Tracker() {}
+
VideoCaptureBufferPool::VideoCaptureBufferPool(int count)
: count_(count),
next_buffer_id_(0) {
@@ -23,7 +200,7 @@ VideoCaptureBufferPool::VideoCaptureBufferPool(int count)
}
VideoCaptureBufferPool::~VideoCaptureBufferPool() {
- STLDeleteValues(&buffers_);
+ STLDeleteValues(&trackers_);
}
base::SharedMemoryHandle VideoCaptureBufferPool::ShareToProcess(
@@ -32,140 +209,149 @@ base::SharedMemoryHandle VideoCaptureBufferPool::ShareToProcess(
size_t* memory_size) {
base::AutoLock lock(lock_);
- Buffer* buffer = GetBuffer(buffer_id);
- if (!buffer) {
+ Tracker* tracker = GetTracker(buffer_id);
+ if (!tracker) {
NOTREACHED() << "Invalid buffer_id.";
return base::SharedMemory::NULLHandle();
}
base::SharedMemoryHandle remote_handle;
- buffer->shared_memory.ShareToProcess(process_handle, &remote_handle);
- *memory_size = buffer->shared_memory.requested_size();
- return remote_handle;
+ if (tracker->ShareToProcess(process_handle, &remote_handle)) {
+ *memory_size = tracker->mapped_size();
+ return remote_handle;
+ }
+ DPLOG(ERROR) << "Error mapping Shared Memory";
+ return base::SharedMemoryHandle();
}
-bool VideoCaptureBufferPool::GetBufferInfo(int buffer_id,
- void** memory,
- size_t* size) {
+scoped_ptr<VideoCaptureBufferPool::BufferHandle>
+VideoCaptureBufferPool::GetBufferHandle(int buffer_id) {
base::AutoLock lock(lock_);
- Buffer* buffer = GetBuffer(buffer_id);
- if (!buffer) {
+ Tracker* tracker = GetTracker(buffer_id);
+ if (!tracker) {
NOTREACHED() << "Invalid buffer_id.";
- return false;
+ return scoped_ptr<BufferHandle>();
}
- DCHECK(buffer->held_by_producer);
- *memory = buffer->shared_memory.memory();
- *size = buffer->shared_memory.mapped_size();
- return true;
+ DCHECK(tracker->held_by_producer());
+ return tracker->GetBufferHandle();
}
-int VideoCaptureBufferPool::ReserveForProducer(size_t size,
+int VideoCaptureBufferPool::ReserveForProducer(media::VideoPixelFormat format,
+ const gfx::Size& dimensions,
int* buffer_id_to_drop) {
base::AutoLock lock(lock_);
- return ReserveForProducerInternal(size, buffer_id_to_drop);
+ return ReserveForProducerInternal(format, dimensions, buffer_id_to_drop);
}
void VideoCaptureBufferPool::RelinquishProducerReservation(int buffer_id) {
base::AutoLock lock(lock_);
- Buffer* buffer = GetBuffer(buffer_id);
- if (!buffer) {
+ Tracker* tracker = GetTracker(buffer_id);
+ if (!tracker) {
NOTREACHED() << "Invalid buffer_id.";
return;
}
- DCHECK(buffer->held_by_producer);
- buffer->held_by_producer = false;
+ DCHECK(tracker->held_by_producer());
+ tracker->set_held_by_producer(false);
}
void VideoCaptureBufferPool::HoldForConsumers(
int buffer_id,
int num_clients) {
base::AutoLock lock(lock_);
- Buffer* buffer = GetBuffer(buffer_id);
- if (!buffer) {
+ Tracker* tracker = GetTracker(buffer_id);
+ if (!tracker) {
NOTREACHED() << "Invalid buffer_id.";
return;
}
- DCHECK(buffer->held_by_producer);
- DCHECK(!buffer->consumer_hold_count);
+ DCHECK(tracker->held_by_producer());
+ DCHECK(!tracker->consumer_hold_count());
- buffer->consumer_hold_count = num_clients;
- // Note: |held_by_producer| will stay true until
+ tracker->set_consumer_hold_count(num_clients);
+ // Note: |held_by_producer()| will stay true until
// RelinquishProducerReservation() (usually called by destructor of the object
- // wrapping this buffer, e.g. a media::VideoFrame).
+ // wrapping this tracker, e.g. a media::VideoFrame).
}
void VideoCaptureBufferPool::RelinquishConsumerHold(int buffer_id,
int num_clients) {
base::AutoLock lock(lock_);
- Buffer* buffer = GetBuffer(buffer_id);
- if (!buffer) {
+ Tracker* tracker = GetTracker(buffer_id);
+ if (!tracker) {
NOTREACHED() << "Invalid buffer_id.";
return;
}
- DCHECK_GE(buffer->consumer_hold_count, num_clients);
+ DCHECK_GE(tracker->consumer_hold_count(), num_clients);
- buffer->consumer_hold_count -= num_clients;
+ tracker->set_consumer_hold_count(tracker->consumer_hold_count() -
+ num_clients);
}
-VideoCaptureBufferPool::Buffer::Buffer()
- : held_by_producer(false), consumer_hold_count(0) {}
-
-int VideoCaptureBufferPool::ReserveForProducerInternal(size_t size,
- int* buffer_id_to_drop) {
+int VideoCaptureBufferPool::ReserveForProducerInternal(
+ media::VideoPixelFormat format,
+ const gfx::Size& dimensions,
+ int* buffer_id_to_drop) {
+ DCHECK(format == media::PIXEL_FORMAT_I420 ||
+ format == media::PIXEL_FORMAT_TEXTURE ||
+ format == media::PIXEL_FORMAT_GPUMEMORYBUFFER );
lock_.AssertAcquired();
+ *buffer_id_to_drop = kInvalidId;
- // Look for a buffer that's allocated, big enough, and not in use. Track the
- // largest one that's not big enough, in case we have to reallocate a buffer.
+ const size_t size_in_pixels = dimensions.GetArea();
+ // Look for a tracker that's allocated, big enough, and not in use. Track the
+ // largest one that's not big enough, in case we have to reallocate a tracker.
*buffer_id_to_drop = kInvalidId;
- size_t realloc_size = 0;
- BufferMap::iterator realloc = buffers_.end();
- for (BufferMap::iterator it = buffers_.begin(); it != buffers_.end(); ++it) {
- Buffer* buffer = it->second;
- if (!buffer->consumer_hold_count && !buffer->held_by_producer) {
- if (buffer->shared_memory.requested_size() >= size) {
- // Existing buffer is big enough. Reuse it.
- buffer->held_by_producer = true;
+ size_t largest_size_in_pixels = 0;
+ TrackerMap::iterator tracker_to_drop = trackers_.end();
+ for (TrackerMap::iterator it = trackers_.begin(); it != trackers_.end();
+ ++it) {
+ Tracker* const tracker = it->second;
+ if (!tracker->consumer_hold_count() && !tracker->held_by_producer()) {
+ if (tracker->pixel_count() >= size_in_pixels &&
+ (tracker->pixel_format() ==
+ VideoPixelFormatToVideoFrameFormat(format))) {
+ // Existing tracker is big enough and has correct format. Reuse it.
+ tracker->set_held_by_producer(true);
return it->first;
}
- if (buffer->shared_memory.requested_size() > realloc_size) {
- realloc_size = buffer->shared_memory.requested_size();
- realloc = it;
+ if (tracker->pixel_count() > largest_size_in_pixels) {
+ largest_size_in_pixels = tracker->pixel_count();
+ tracker_to_drop = it;
}
}
}
- // Preferentially grow the pool by creating a new buffer. If we're at maximum
+ // Preferably grow the pool by creating a new tracker. If we're at maximum
// size, then reallocate by deleting an existing one instead.
- if (buffers_.size() == static_cast<size_t>(count_)) {
- if (realloc == buffers_.end()) {
- // We're out of space, and can't find an unused buffer to reallocate.
+ if (trackers_.size() == static_cast<size_t>(count_)) {
+ if (tracker_to_drop == trackers_.end()) {
+ // We're out of space, and can't find an unused tracker to reallocate.
return kInvalidId;
}
- *buffer_id_to_drop = realloc->first;
- delete realloc->second;
- buffers_.erase(realloc);
+ *buffer_id_to_drop = tracker_to_drop->first;
+ delete tracker_to_drop->second;
+ trackers_.erase(tracker_to_drop);
}
- // Create the new buffer.
- int buffer_id = next_buffer_id_++;
- scoped_ptr<Buffer> buffer(new Buffer());
- if (size) {
- // |size| can be 0 for buffers that do not require memory backing.
- if (!buffer->shared_memory.CreateAndMapAnonymous(size))
- return kInvalidId;
+ // Create the new tracker.
+ const int buffer_id = next_buffer_id_++;
+
+ scoped_ptr<Tracker> tracker =
+ Tracker::CreateTracker(format == media::PIXEL_FORMAT_GPUMEMORYBUFFER);
+ if (!tracker->Init(VideoPixelFormatToVideoFrameFormat(format), dimensions)) {
+ DLOG(ERROR) << "Error initializing Tracker";
+ return kInvalidId;
}
- buffer->held_by_producer = true;
- buffers_[buffer_id] = buffer.release();
+ tracker->set_held_by_producer(true);
+ trackers_[buffer_id] = tracker.release();
+
return buffer_id;
}
-VideoCaptureBufferPool::Buffer* VideoCaptureBufferPool::GetBuffer(
+VideoCaptureBufferPool::Tracker* VideoCaptureBufferPool::GetTracker(
int buffer_id) {
- BufferMap::iterator it = buffers_.find(buffer_id);
- if (it == buffers_.end())
- return NULL;
- return it->second;
+ TrackerMap::const_iterator it = trackers_.find(buffer_id);
+ return (it == trackers_.end()) ? NULL : it->second;
}
} // namespace content
diff --git a/chromium/content/browser/renderer_host/media/video_capture_buffer_pool.h b/chromium/content/browser/renderer_host/media/video_capture_buffer_pool.h
index 0ee32a78223..4351dd7deb4 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_buffer_pool.h
+++ b/chromium/content/browser/renderer_host/media/video_capture_buffer_pool.h
@@ -9,26 +9,23 @@
#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_vector.h"
#include "base/memory/shared_memory.h"
#include "base/process/process.h"
#include "base/synchronization/lock.h"
#include "content/common/content_export.h"
-#include "ui/gfx/size.h"
-
-namespace media {
-
-class VideoFrame;
-
-} // namespace media
+#include "media/base/video_capture_types.h"
+#include "media/base/video_frame.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/gpu_memory_buffer.h"
namespace content {
// A thread-safe class that does the bookkeeping and lifetime management for a
-// pool of shared-memory pixel buffers cycled between an in-process producer
-// (e.g. a VideoCaptureDevice) and a set of out-of-process consumers. The pool
-// is intended to be orchestrated by a VideoCaptureController, but is designed
-// to outlive the controller if necessary.
+// pool of pixel buffers cycled between an in-process producer (e.g. a
+// VideoCaptureDevice) and a set of out-of-process consumers. The pool is
+// intended to be orchestrated by a VideoCaptureDevice::Client, but is designed
+// to outlive the controller if necessary. The pixel buffers may be backed by a
+// SharedMemory, but this is not compulsory.
//
// Producers get a buffer by calling ReserveForProducer(), and may pass on their
// ownership to the consumer by calling HoldForConsumers(), or drop the buffer
@@ -47,6 +44,17 @@ class CONTENT_EXPORT VideoCaptureBufferPool
: public base::RefCountedThreadSafe<VideoCaptureBufferPool> {
public:
static const int kInvalidId;
+
+ // Abstraction of a pool's buffer data buffer and size for clients.
+ class BufferHandle {
+ public:
+ virtual ~BufferHandle() {}
+ virtual size_t size() const = 0;
+ virtual void* data() = 0;
+ virtual gfx::GpuMemoryBufferType GetType() = 0;
+ virtual ClientBuffer AsClientBuffer() = 0;
+ };
+
explicit VideoCaptureBufferPool(int count);
// One-time (per client/per-buffer) initialization to share a particular
@@ -56,14 +64,13 @@ class CONTENT_EXPORT VideoCaptureBufferPool
base::ProcessHandle process_handle,
size_t* memory_size);
- // Query the memory parameters of |buffer_id|. Fills in parameters in the
- // pointer arguments, and returns true iff the buffer exists.
- bool GetBufferInfo(int buffer_id, void** memory, size_t* size);
+ // Try and obtain a BufferHandle for |buffer_id|.
+ scoped_ptr<BufferHandle> GetBufferHandle(int buffer_id);
- // Reserve or allocate a buffer of at least |size| bytes and return its id.
- // This will fail (returning kInvalidId) if the pool already is at its |count|
- // limit of the number of allocations, and all allocated buffers are in use by
- // the producer and/or consumers.
+ // Reserve or allocate a buffer to support a packed frame of |dimensions| of
+ // pixel |format| and return its id. This will fail (returning kInvalidId) if
+ // the pool already is at its |count| limit of the number of allocations, and
+ // all allocated buffers are in use by the producer and/or consumers.
//
// If successful, the reserved buffer remains reserved (and writable by the
// producer) until ownership is transferred either to the consumer via
@@ -73,7 +80,9 @@ class CONTENT_EXPORT VideoCaptureBufferPool
// On occasion, this call will decide to free an old buffer to make room for a
// new allocation at a larger size. If so, the ID of the destroyed buffer is
// returned via |buffer_id_to_drop|.
- int ReserveForProducer(size_t size, int* buffer_id_to_drop);
+ int ReserveForProducer(media::VideoPixelFormat format,
+ const gfx::Size& dimensions,
+ int* buffer_id_to_drop);
// Indicate that a buffer held for the producer should be returned back to the
// pool without passing on to the consumer. This effectively is the opposite
@@ -90,32 +99,57 @@ class CONTENT_EXPORT VideoCaptureBufferPool
// done, a buffer is returned to the pool for reuse.
void RelinquishConsumerHold(int buffer_id, int num_clients);
- int count() const { return count_; }
-
private:
- friend class base::RefCountedThreadSafe<VideoCaptureBufferPool>;
-
- // Per-buffer state.
- struct Buffer {
- Buffer();
-
- // The memory created to be shared with renderer processes.
- base::SharedMemory shared_memory;
-
- // Tracks whether this buffer is currently referenced by the producer.
- bool held_by_producer;
-
- // Number of consumer processes which hold this shared memory.
- int consumer_hold_count;
+ class GpuMemoryBufferTracker;
+ class SharedMemTracker;
+ // Generic class to keep track of the state of a given mappable resource.
+ class Tracker {
+ public:
+ static scoped_ptr<Tracker> CreateTracker(bool use_gmb);
+
+ Tracker()
+ : pixel_count_(0), held_by_producer_(false), consumer_hold_count_(0) {}
+ virtual bool Init(media::VideoFrame::Format format,
+ const gfx::Size& dimensions) = 0;
+ virtual ~Tracker();
+
+ size_t pixel_count() const { return pixel_count_; }
+ void set_pixel_count(size_t count) { pixel_count_ = count; }
+ media::VideoFrame::Format pixel_format() const { return pixel_format_; }
+ void set_pixel_format(media::VideoFrame::Format format) {
+ pixel_format_ = format;
+ }
+ bool held_by_producer() const { return held_by_producer_; }
+ void set_held_by_producer(bool value) { held_by_producer_ = value; }
+ int consumer_hold_count() const { return consumer_hold_count_; }
+ void set_consumer_hold_count(int value) { consumer_hold_count_ = value; }
+
+ // Returns a handle to the underlying storage, be that a block of Shared
+ // Memory, or a GpuMemoryBuffer.
+ virtual scoped_ptr<BufferHandle> GetBufferHandle() = 0;
+ // The actual size of the underlying backing resource.
+ virtual size_t mapped_size() const = 0;
+
+ virtual bool ShareToProcess(base::ProcessHandle process_handle,
+ base::SharedMemoryHandle* new_handle) = 0;
+
+ private:
+ size_t pixel_count_;
+ media::VideoFrame::Format pixel_format_;
+ // Indicates whether this Tracker is currently referenced by the producer.
+ bool held_by_producer_;
+ // Number of consumer processes which hold this Tracker.
+ int consumer_hold_count_;
};
- typedef std::map<int, Buffer*> BufferMap;
-
+ friend class base::RefCountedThreadSafe<VideoCaptureBufferPool>;
virtual ~VideoCaptureBufferPool();
- int ReserveForProducerInternal(size_t size, int* buffer_id_to_drop);
+ int ReserveForProducerInternal(media::VideoPixelFormat format,
+ const gfx::Size& dimensions,
+ int* tracker_id_to_drop);
- Buffer* GetBuffer(int buffer_id);
+ Tracker* GetTracker(int buffer_id);
// The max number of buffers that the pool is allowed to have at any moment.
const int count_;
@@ -126,8 +160,9 @@ class CONTENT_EXPORT VideoCaptureBufferPool
// The ID of the next buffer.
int next_buffer_id_;
- // The buffers, indexed by |buffer_id|.
- BufferMap buffers_;
+ // The buffers, indexed by the first parameter, a buffer id.
+ using TrackerMap = std::map<int, Tracker*>;
+ TrackerMap trackers_;
DISALLOW_IMPLICIT_CONSTRUCTORS(VideoCaptureBufferPool);
};
diff --git a/chromium/content/browser/renderer_host/media/video_capture_buffer_pool_unittest.cc b/chromium/content/browser/renderer_host/media/video_capture_buffer_pool_unittest.cc
index 39fd9857b3e..147aefa1d6e 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_buffer_pool_unittest.cc
+++ b/chromium/content/browser/renderer_host/media/video_capture_buffer_pool_unittest.cc
@@ -9,140 +9,247 @@
#include "base/bind.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#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/gpu/browser_gpu_memory_buffer_manager.h"
#include "content/browser/renderer_host/media/video_capture_controller.h"
#include "media/base/video_frame.h"
#include "media/base/video_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
-class VideoCaptureBufferPoolTest : public testing::Test {
+static const media::VideoPixelFormat kCaptureFormats[] = {
+ media::PIXEL_FORMAT_I420,
+ media::PIXEL_FORMAT_TEXTURE,
+#if !defined(OS_ANDROID)
+ media::PIXEL_FORMAT_GPUMEMORYBUFFER
+#endif
+};
+
+class VideoCaptureBufferPoolTest
+ : public testing::TestWithParam<media::VideoPixelFormat> {
protected:
+ // A GpuMemoryBuffer Mock to provide a trivial RGBA buffer as Map() backing.
+ // We need to allocate on ctor and deallocate on dtor so that consecutive
+ // Map()-Unmap() cycles yield the same underlying data pointer.
+ class MockGpuMemoryBuffer : public gfx::GpuMemoryBuffer {
+ public:
+ explicit MockGpuMemoryBuffer(const gfx::Size& size)
+ : size_(size), data_(new uint8[size_.GetArea() * 4]), mapped_(false) {}
+ ~MockGpuMemoryBuffer() override { delete[] data_; }
+
+ bool Map(void** data) override {
+ EXPECT_EQ(mapped_, false);
+ mapped_ = true;
+ data[0] = static_cast<void*>(data_);
+ return true;
+ }
+ void Unmap() override {
+ EXPECT_EQ(mapped_, true);
+ mapped_ = false;
+ }
+ bool IsMapped() const override { return mapped_; }
+ Format GetFormat() const override { return BGRA_8888; }
+ void GetStride(int* stride) const override {
+ *stride = size_.width() * 4;
+ return;
+ }
+ gfx::GpuMemoryBufferHandle GetHandle() const override {
+ return gfx::GpuMemoryBufferHandle();
+ }
+ ClientBuffer AsClientBuffer() override { return nullptr; }
+
+ private:
+ const gfx::Size size_;
+ uint8* const data_;
+ bool mapped_;
+ };
+
+#if !defined(OS_ANDROID)
+ // The next two classes are needed to replicate the GpuMemoryBuffer allocation
+ // on Browser side.
+ class StubBrowserGpuMemoryBufferManager
+ : public BrowserGpuMemoryBufferManager {
+ public:
+ StubBrowserGpuMemoryBufferManager()
+ : BrowserGpuMemoryBufferManager(nullptr, 1) {}
+
+ scoped_ptr<gfx::GpuMemoryBuffer> AllocateGpuMemoryBuffer(
+ const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
+ gfx::GpuMemoryBuffer::Usage usage) override {
+ return make_scoped_ptr(new MockGpuMemoryBuffer(size));
+ }
+ };
+ class MockBufferQueue : public BufferQueue {
+ public:
+ MockBufferQueue(scoped_refptr<cc::ContextProvider> context_provider,
+ BrowserGpuMemoryBufferManager* gpu_memory_buffer_manager,
+ unsigned int internalformat)
+ : BufferQueue(context_provider,
+ internalformat,
+ nullptr,
+ gpu_memory_buffer_manager,
+ 1) {}
+ MOCK_METHOD4(CopyBufferDamage,
+ void(int, int, const gfx::Rect&, const gfx::Rect&));
+ };
+#endif
+
+ // This is a generic Buffer tracker
class Buffer {
public:
Buffer(const scoped_refptr<VideoCaptureBufferPool> pool,
- int id,
- void* data,
- size_t size)
- : pool_(pool), id_(id), data_(data), size_(size) {}
+ scoped_ptr<VideoCaptureBufferPool::BufferHandle> buffer_handle,
+ int id)
+ : id_(id), pool_(pool), buffer_handle_(buffer_handle.Pass()) {}
~Buffer() { pool_->RelinquishProducerReservation(id()); }
int id() const { return id_; }
- void* data() const { return data_; }
- size_t size() const { return size_; }
+ size_t size() { return buffer_handle_->size(); }
+ void* data() { return buffer_handle_->data(); }
private:
- const scoped_refptr<VideoCaptureBufferPool> pool_;
const int id_;
- void* const data_;
- const size_t size_;
+ const scoped_refptr<VideoCaptureBufferPool> pool_;
+ const scoped_ptr<VideoCaptureBufferPool::BufferHandle> buffer_handle_;
};
+
VideoCaptureBufferPoolTest()
: expected_dropped_id_(0),
pool_(new VideoCaptureBufferPool(3)) {}
+#if !defined(OS_ANDROID)
+ void SetUp() override {
+ scoped_refptr<cc::TestContextProvider> context_provider =
+ cc::TestContextProvider::Create(cc::TestWebGraphicsContext3D::Create());
+ context_provider->BindToCurrentThread();
+ gpu_memory_buffer_manager_.reset(new StubBrowserGpuMemoryBufferManager);
+ output_surface_.reset(new MockBufferQueue(
+ context_provider, gpu_memory_buffer_manager_.get(), GL_RGBA));
+ output_surface_->Initialize();
+ }
+#endif
+
void ExpectDroppedId(int expected_dropped_id) {
expected_dropped_id_ = expected_dropped_id;
}
- scoped_ptr<Buffer> ReserveI420Buffer(const gfx::Size& dimensions) {
- const size_t frame_bytes =
- media::VideoFrame::AllocationSize(media::VideoFrame::I420, dimensions);
- // To verify that ReserveI420Buffer always sets |buffer_id_to_drop|,
+ scoped_ptr<Buffer> ReserveBuffer(const gfx::Size& dimensions,
+ media::VideoPixelFormat pixel_format) {
+ // To verify that ReserveBuffer always sets |buffer_id_to_drop|,
// initialize it to something different than the expected value.
int buffer_id_to_drop = ~expected_dropped_id_;
- int buffer_id = pool_->ReserveForProducer(frame_bytes, &buffer_id_to_drop);
+ DVLOG(1) << media::VideoCaptureFormat::PixelFormatToString(pixel_format)
+ << " " << dimensions.ToString();
+ int buffer_id =
+ pool_->ReserveForProducer(pixel_format, dimensions, &buffer_id_to_drop);
if (buffer_id == VideoCaptureBufferPool::kInvalidId)
return scoped_ptr<Buffer>();
-
- void* memory;
- size_t size;
- pool_->GetBufferInfo(buffer_id, &memory, &size);
EXPECT_EQ(expected_dropped_id_, buffer_id_to_drop);
- return scoped_ptr<Buffer>(new Buffer(pool_, buffer_id, memory, size));
+
+ scoped_ptr<VideoCaptureBufferPool::BufferHandle> buffer_handle =
+ pool_->GetBufferHandle(buffer_id);
+ return scoped_ptr<Buffer>(
+ new Buffer(pool_, buffer_handle.Pass(), buffer_id));
}
+ base::MessageLoop loop_;
int expected_dropped_id_;
scoped_refptr<VideoCaptureBufferPool> pool_;
private:
+#if !defined(OS_ANDROID)
+ scoped_ptr<StubBrowserGpuMemoryBufferManager> gpu_memory_buffer_manager_;
+ scoped_ptr<MockBufferQueue> output_surface_;
+#endif
+
DISALLOW_COPY_AND_ASSIGN(VideoCaptureBufferPoolTest);
};
-TEST_F(VideoCaptureBufferPoolTest, BufferPool) {
- const gfx::Size size_lo = gfx::Size(640, 480);
- const gfx::Size size_hi = gfx::Size(1024, 768);
- scoped_refptr<media::VideoFrame> non_pool_frame =
- media::VideoFrame::CreateFrame(media::VideoFrame::YV12, size_lo,
- gfx::Rect(size_lo), size_lo,
- base::TimeDelta());
+TEST_P(VideoCaptureBufferPoolTest, BufferPool) {
+ const gfx::Size size_lo = gfx::Size(10, 10);
+ const gfx::Size size_hi = gfx::Size(21, 33);
+ const media::VideoCaptureFormat format_lo(size_lo, 0.0, GetParam());
+ const media::VideoCaptureFormat format_hi(size_hi, 0.0, GetParam());
// Reallocation won't happen for the first part of the test.
ExpectDroppedId(VideoCaptureBufferPool::kInvalidId);
- scoped_ptr<Buffer> buffer1 = ReserveI420Buffer(size_lo);
- ASSERT_TRUE(NULL != buffer1.get());
- ASSERT_LE(media::VideoFrame::AllocationSize(media::VideoFrame::I420, size_lo),
- buffer1->size());
- scoped_ptr<Buffer> buffer2 = ReserveI420Buffer(size_lo);
- ASSERT_TRUE(NULL != buffer2.get());
- ASSERT_LE(media::VideoFrame::AllocationSize(media::VideoFrame::I420, size_lo),
- buffer2->size());
- scoped_ptr<Buffer> buffer3 = ReserveI420Buffer(size_lo);
- ASSERT_TRUE(NULL != buffer3.get());
- ASSERT_LE(media::VideoFrame::AllocationSize(media::VideoFrame::I420, size_lo),
- buffer3->size());
+ scoped_ptr<Buffer> buffer1 = ReserveBuffer(size_lo, GetParam());
+ ASSERT_NE(nullptr, buffer1.get());
+ ASSERT_LE(format_lo.ImageAllocationSize(), buffer1->size());
+ scoped_ptr<Buffer> buffer2 = ReserveBuffer(size_lo, GetParam());
+ ASSERT_NE(nullptr, buffer2.get());
+ ASSERT_LE(format_lo.ImageAllocationSize(), buffer2->size());
+ scoped_ptr<Buffer> buffer3 = ReserveBuffer(size_lo, GetParam());
+ ASSERT_NE(nullptr, buffer3.get());
+ ASSERT_LE(format_lo.ImageAllocationSize(), buffer3->size());
+
+ // Texture backed Frames cannot be manipulated via mapping.
+ if (GetParam() != media::PIXEL_FORMAT_TEXTURE) {
+ ASSERT_NE(nullptr, buffer1->data());
+ ASSERT_NE(nullptr, buffer2->data());
+ ASSERT_NE(nullptr, buffer3->data());
+ }
// Touch the memory.
- memset(buffer1->data(), 0x11, buffer1->size());
- memset(buffer2->data(), 0x44, buffer2->size());
- memset(buffer3->data(), 0x77, buffer3->size());
+ if (buffer1->data() != nullptr)
+ memset(buffer1->data(), 0x11, buffer1->size());
+ if (buffer2->data() != nullptr)
+ memset(buffer2->data(), 0x44, buffer2->size());
+ if (buffer3->data() != nullptr)
+ memset(buffer3->data(), 0x77, buffer3->size());
// Fourth buffer should fail.
- ASSERT_FALSE(ReserveI420Buffer(size_lo)) << "Pool should be empty";
+ ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
// Release 1st buffer and retry; this should succeed.
buffer1.reset();
- scoped_ptr<Buffer> buffer4 = ReserveI420Buffer(size_lo);
- ASSERT_TRUE(NULL != buffer4.get());
+ scoped_ptr<Buffer> buffer4 = ReserveBuffer(size_lo, GetParam());
+ ASSERT_NE(nullptr, buffer4.get());
- ASSERT_FALSE(ReserveI420Buffer(size_lo)) << "Pool should be empty";
- ASSERT_FALSE(ReserveI420Buffer(size_hi)) << "Pool should be empty";
+ ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
+ ASSERT_FALSE(ReserveBuffer(size_hi, GetParam())) << "Pool should be empty";
// Validate the IDs
int buffer_id2 = buffer2->id();
ASSERT_EQ(1, buffer_id2);
- int buffer_id3 = buffer3->id();
+ const int buffer_id3 = buffer3->id();
ASSERT_EQ(2, buffer_id3);
- void* const memory_pointer3 = buffer3->data();
- int buffer_id4 = buffer4->id();
+ const int buffer_id4 = buffer4->id();
ASSERT_EQ(0, buffer_id4);
+ void* const memory_pointer3 = buffer3->data();
// Deliver a buffer.
pool_->HoldForConsumers(buffer_id3, 2);
- ASSERT_FALSE(ReserveI420Buffer(size_lo)) << "Pool should be empty";
+ ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
buffer3.reset(); // Old producer releases buffer. Should be a noop.
- ASSERT_FALSE(ReserveI420Buffer(size_lo)) << "Pool should be empty";
- ASSERT_FALSE(ReserveI420Buffer(size_hi)) << "Pool should be empty";
+ ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
+ ASSERT_FALSE(ReserveBuffer(size_hi, GetParam())) << "Pool should be empty";
buffer2.reset(); // Active producer releases buffer. Should free a buffer.
- buffer1 = ReserveI420Buffer(size_lo);
- ASSERT_TRUE(NULL != buffer1.get());
- ASSERT_FALSE(ReserveI420Buffer(size_lo)) << "Pool should be empty";
+ buffer1 = ReserveBuffer(size_lo, GetParam());
+ ASSERT_NE(nullptr, buffer1.get());
+ ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
// First consumer finishes.
pool_->RelinquishConsumerHold(buffer_id3, 1);
- ASSERT_FALSE(ReserveI420Buffer(size_lo)) << "Pool should be empty";
+ ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
// Second consumer finishes. This should free that buffer.
pool_->RelinquishConsumerHold(buffer_id3, 1);
- buffer3 = ReserveI420Buffer(size_lo);
- ASSERT_TRUE(NULL != buffer3.get());
+ buffer3 = ReserveBuffer(size_lo, GetParam());
+ ASSERT_NE(nullptr, buffer3.get());
ASSERT_EQ(buffer_id3, buffer3->id()) << "Buffer ID should be reused.";
ASSERT_EQ(memory_pointer3, buffer3->data());
- ASSERT_FALSE(ReserveI420Buffer(size_lo)) << "Pool should be empty";
+ ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
// Now deliver & consume buffer1, but don't release the buffer.
int buffer_id1 = buffer1->id();
@@ -154,35 +261,33 @@ TEST_F(VideoCaptureBufferPoolTest, BufferPool) {
// be re-allocated to the producer, because |buffer1| still references it. But
// when |buffer1| goes away, we should be able to re-reserve the buffer (and
// the ID ought to be the same).
- ASSERT_FALSE(ReserveI420Buffer(size_lo)) << "Pool should be empty";
+ ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
buffer1.reset(); // Should free the buffer.
- buffer2 = ReserveI420Buffer(size_lo);
- ASSERT_TRUE(NULL != buffer2.get());
+ buffer2 = ReserveBuffer(size_lo, GetParam());
+ ASSERT_NE(nullptr, buffer2.get());
ASSERT_EQ(buffer_id1, buffer2->id());
buffer_id2 = buffer_id1;
- ASSERT_FALSE(ReserveI420Buffer(size_lo)) << "Pool should be empty";
+ ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
// Now try reallocation with different resolutions. We expect reallocation
// to occur only when the old buffer is too small.
buffer2.reset();
ExpectDroppedId(buffer_id2);
- buffer2 = ReserveI420Buffer(size_hi);
- ASSERT_TRUE(NULL != buffer2.get());
- ASSERT_LE(media::VideoFrame::AllocationSize(media::VideoFrame::I420, size_hi),
- buffer2->size());
+ buffer2 = ReserveBuffer(size_hi, GetParam());
+ ASSERT_NE(nullptr, buffer2.get());
+ ASSERT_LE(format_hi.ImageAllocationSize(), buffer2->size());
ASSERT_EQ(3, buffer2->id());
void* const memory_pointer_hi = buffer2->data();
buffer2.reset(); // Frees it.
ExpectDroppedId(VideoCaptureBufferPool::kInvalidId);
- buffer2 = ReserveI420Buffer(size_lo);
+ buffer2 = ReserveBuffer(size_lo, GetParam());
void* const memory_pointer_lo = buffer2->data();
ASSERT_EQ(memory_pointer_hi, memory_pointer_lo)
<< "Decrease in resolution should not reallocate buffer";
- ASSERT_TRUE(NULL != buffer2.get());
+ ASSERT_NE(nullptr, buffer2.get());
ASSERT_EQ(3, buffer2->id());
- ASSERT_LE(media::VideoFrame::AllocationSize(media::VideoFrame::I420, size_lo),
- buffer2->size());
- ASSERT_FALSE(ReserveI420Buffer(size_lo)) << "Pool should be empty";
+ ASSERT_LE(format_lo.ImageAllocationSize(), buffer2->size());
+ ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
// Tear down the pool_, writing into the buffers. The buffer should preserve
// the lifetime of the underlying memory.
@@ -190,13 +295,19 @@ TEST_F(VideoCaptureBufferPoolTest, BufferPool) {
pool_ = NULL;
// Touch the memory.
- memset(buffer2->data(), 0x22, buffer2->size());
- memset(buffer4->data(), 0x55, buffer4->size());
-
+ if (buffer2->data() != nullptr)
+ memset(buffer2->data(), 0x22, buffer2->size());
+ if (buffer4->data() != nullptr)
+ memset(buffer4->data(), 0x55, buffer4->size());
buffer2.reset();
- memset(buffer4->data(), 0x77, buffer4->size());
+ if (buffer4->data() != nullptr)
+ memset(buffer4->data(), 0x77, buffer4->size());
buffer4.reset();
}
+INSTANTIATE_TEST_CASE_P(,
+ VideoCaptureBufferPoolTest,
+ testing::ValuesIn(kCaptureFormats));
+
} // 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 c0b462bce26..23ee7074a2d 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_controller.cc
+++ b/chromium/content/browser/renderer_host/media/video_capture_controller.cc
@@ -8,28 +8,26 @@
#include <set>
#include "base/bind.h"
-#include "base/debug/trace_event.h"
+#include "base/command_line.h"
#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_buffer_pool.h"
+#include "content/browser/renderer_host/media/video_capture_device_client.h"
#include "content/browser/renderer_host/media/video_capture_manager.h"
#include "content/common/gpu/client/gl_helper.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/common/content_switches.h"
#include "gpu/command_buffer/common/mailbox_holder.h"
#include "media/base/video_frame.h"
-#include "media/base/video_util.h"
-#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
+#if !defined(OS_ANDROID)
#include "content/browser/compositor/image_transport_factory.h"
#endif
using media::VideoCaptureFormat;
+using media::VideoFrame;
namespace content {
@@ -42,23 +40,7 @@ static const int kInfiniteRatio = 99999;
name, \
(height) ? ((width) * 100) / (height) : kInfiniteRatio);
-class PoolBuffer : public media::VideoCaptureDevice::Client::Buffer {
- public:
- PoolBuffer(const scoped_refptr<VideoCaptureBufferPool>& pool,
- int buffer_id,
- void* data,
- size_t size)
- : Buffer(buffer_id, data, size), pool_(pool) {
- DCHECK(pool_.get());
- }
-
- private:
- ~PoolBuffer() override { pool_->RelinquishProducerReservation(id()); }
-
- const scoped_refptr<VideoCaptureBufferPool> pool_;
-};
-
-class SyncPointClientImpl : public media::VideoFrame::SyncPointClient {
+class SyncPointClientImpl : public VideoFrame::SyncPointClient {
public:
explicit SyncPointClientImpl(GLHelper* gl_helper) : gl_helper_(gl_helper) {}
~SyncPointClientImpl() override {}
@@ -71,27 +53,27 @@ class SyncPointClientImpl : public media::VideoFrame::SyncPointClient {
GLHelper* gl_helper_;
};
-void ReturnVideoFrame(const scoped_refptr<media::VideoFrame>& video_frame,
+void ReturnVideoFrame(const scoped_refptr<VideoFrame>& video_frame,
uint32 sync_point) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
#if defined(OS_ANDROID)
- GLHelper* gl_helper =
- ImageTransportFactoryAndroid::GetInstance()->GetGLHelper();
+ NOTREACHED();
#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);
+ if (gl_helper) {
+ gl_helper->WaitSyncPoint(sync_point);
+ SyncPointClientImpl client(gl_helper);
+ video_frame->UpdateReleaseSyncPoint(&client);
+ }
+#endif
}
} // anonymous namespace
struct VideoCaptureController::ControllerClient {
- ControllerClient(const VideoCaptureControllerID& id,
+ ControllerClient(VideoCaptureControllerID id,
VideoCaptureControllerEventHandler* handler,
base::ProcessHandle render_process,
media::VideoCaptureSessionId session_id,
@@ -120,7 +102,7 @@ struct VideoCaptureController::ControllerClient {
// Buffers currently held by this client, and syncpoint callback to call when
// they are returned from the client.
- typedef std::map<int, scoped_refptr<media::VideoFrame> > ActiveBufferMap;
+ typedef std::map<int, scoped_refptr<VideoFrame>> ActiveBufferMap;
ActiveBufferMap active_buffers;
// State of capture session, controlled by VideoCaptureManager directly. This
@@ -140,82 +122,35 @@ struct VideoCaptureController::ControllerClient {
bool paused;
};
-// Receives events from the VideoCaptureDevice and posts them to a
-// VideoCaptureController on the IO thread. An instance of this class may safely
-// outlive its target VideoCaptureController.
-//
-// Methods of this class may be called from any thread, and in practice will
-// often be called on some auxiliary thread depending on the platform and the
-// device type; including, for example, the DirectShow thread on Windows, the
-// v4l2_thread on Linux, and the UI thread for tab capture.
-class VideoCaptureController::VideoCaptureDeviceClient
- : public media::VideoCaptureDevice::Client {
- public:
- explicit VideoCaptureDeviceClient(
- const base::WeakPtr<VideoCaptureController>& controller,
- const scoped_refptr<VideoCaptureBufferPool>& buffer_pool);
- ~VideoCaptureDeviceClient() override;
-
- // VideoCaptureDevice::Client implementation.
- 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;
- void OnError(const std::string& reason) override;
- void OnLog(const std::string& message) override;
-
- private:
- scoped_refptr<Buffer> DoReserveOutputBuffer(media::VideoFrame::Format format,
- const gfx::Size& dimensions);
-
- // The controller to which we post events.
- const base::WeakPtr<VideoCaptureController> controller_;
-
- // The pool of shared-memory buffers used for capturing.
- const scoped_refptr<VideoCaptureBufferPool> buffer_pool_;
-};
-
VideoCaptureController::VideoCaptureController(int max_buffers)
: buffer_pool_(new VideoCaptureBufferPool(max_buffers)),
state_(VIDEO_CAPTURE_STATE_STARTED),
has_received_frames_(false),
weak_ptr_factory_(this) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
}
-VideoCaptureController::VideoCaptureDeviceClient::VideoCaptureDeviceClient(
- const base::WeakPtr<VideoCaptureController>& controller,
- const scoped_refptr<VideoCaptureBufferPool>& buffer_pool)
- : controller_(controller), buffer_pool_(buffer_pool) {}
-
-VideoCaptureController::VideoCaptureDeviceClient::~VideoCaptureDeviceClient() {}
-
-base::WeakPtr<VideoCaptureController> VideoCaptureController::GetWeakPtr() {
+base::WeakPtr<VideoCaptureController>
+VideoCaptureController::GetWeakPtrForIOThread() {
return weak_ptr_factory_.GetWeakPtr();
}
scoped_ptr<media::VideoCaptureDevice::Client>
-VideoCaptureController::NewDeviceClient() {
- scoped_ptr<media::VideoCaptureDevice::Client> result(
- new VideoCaptureDeviceClient(this->GetWeakPtr(), buffer_pool_));
- return result.Pass();
+VideoCaptureController::NewDeviceClient(
+ const scoped_refptr<base::SingleThreadTaskRunner>& capture_task_runner) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ return make_scoped_ptr(new VideoCaptureDeviceClient(
+ this->GetWeakPtrForIOThread(), buffer_pool_, capture_task_runner));
}
void VideoCaptureController::AddClient(
- const VideoCaptureControllerID& id,
+ VideoCaptureControllerID id,
VideoCaptureControllerEventHandler* event_handler,
base::ProcessHandle render_process,
media::VideoCaptureSessionId session_id,
const media::VideoCaptureParams& params) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DVLOG(1) << "VideoCaptureController::AddClient, id " << id.device_id
+ DVLOG(1) << "VideoCaptureController::AddClient, id " << id
<< ", " << params.requested_format.frame_size.ToString()
<< ", " << params.requested_format.frame_rate
<< ", " << session_id
@@ -246,22 +181,18 @@ void VideoCaptureController::AddClient(
}
int VideoCaptureController::RemoveClient(
- const VideoCaptureControllerID& id,
+ VideoCaptureControllerID id,
VideoCaptureControllerEventHandler* event_handler) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DVLOG(1) << "VideoCaptureController::RemoveClient, id " << id.device_id;
+ DVLOG(1) << "VideoCaptureController::RemoveClient, id " << id;
ControllerClient* client = FindClient(id, event_handler, controller_clients_);
if (!client)
return kInvalidMediaCaptureSessionId;
// Take back all buffers held by the |client|.
- for (ControllerClient::ActiveBufferMap::iterator buffer_it =
- client->active_buffers.begin();
- buffer_it != client->active_buffers.end();
- ++buffer_it) {
- buffer_pool_->RelinquishConsumerHold(buffer_it->first, 1);
- }
+ for (const auto& buffer : client->active_buffers)
+ buffer_pool_->RelinquishConsumerHold(buffer.first, 1);
client->active_buffers.clear();
int session_id = client->session_id;
@@ -272,18 +203,18 @@ int VideoCaptureController::RemoveClient(
}
void VideoCaptureController::PauseOrResumeClient(
- const VideoCaptureControllerID& id,
+ VideoCaptureControllerID id,
VideoCaptureControllerEventHandler* event_handler,
bool pause) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DVLOG(1) << "VideoCaptureController::PauseOrResumeClient, id "
- << id.device_id << ", " << pause;
+ << id << ", " << pause;
ControllerClient* client = FindClient(id, event_handler, controller_clients_);
if (!client)
return;
- DCHECK(client->paused != pause);
+ DLOG_IF(WARNING, client->paused == pause) << "Redundant client configuration";
client->paused = pause;
}
@@ -300,7 +231,7 @@ void VideoCaptureController::StopSession(int session_id) {
}
void VideoCaptureController::ReturnBuffer(
- const VideoCaptureControllerID& id,
+ VideoCaptureControllerID id,
VideoCaptureControllerEventHandler* event_handler,
int buffer_id,
uint32 sync_point) {
@@ -316,10 +247,13 @@ void VideoCaptureController::ReturnBuffer(
NOTREACHED();
return;
}
- scoped_refptr<media::VideoFrame> frame = iter->second;
+ scoped_refptr<VideoFrame> frame = iter->second;
client->active_buffers.erase(iter);
buffer_pool_->RelinquishConsumerHold(buffer_id, 1);
+#if defined(OS_ANDROID)
+ DCHECK_EQ(0u, sync_point);
+#endif
if (sync_point)
BrowserThread::PostTask(BrowserThread::UI,
FROM_HERE,
@@ -332,334 +266,113 @@ VideoCaptureController::GetVideoCaptureFormat() const {
return video_capture_format_;
}
-scoped_refptr<media::VideoCaptureDevice::Client::Buffer>
-VideoCaptureController::VideoCaptureDeviceClient::ReserveOutputBuffer(
- media::VideoFrame::Format format,
- const gfx::Size& size) {
- return DoReserveOutputBuffer(format, size);
-}
-
-void VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedData(
- const uint8* data,
- int length,
- const VideoCaptureFormat& frame_format,
- int rotation,
- base::TimeTicks timestamp) {
- TRACE_EVENT0("video", "VideoCaptureController::OnIncomingCapturedData");
-
- if (!frame_format.IsValid())
- return;
-
- // Chopped pixels in width/height in case video capture device has odd
- // numbers for width/height.
- int chopped_width = 0;
- int chopped_height = 0;
- int new_unrotated_width = frame_format.frame_size.width();
- int new_unrotated_height = frame_format.frame_size.height();
-
- if (new_unrotated_width & 1) {
- --new_unrotated_width;
- chopped_width = 1;
- }
- if (new_unrotated_height & 1) {
- --new_unrotated_height;
- chopped_height = 1;
- }
-
- int destination_width = new_unrotated_width;
- int destination_height = new_unrotated_height;
- if (rotation == 90 || rotation == 270) {
- destination_width = new_unrotated_height;
- destination_height = new_unrotated_width;
- }
- const gfx::Size dimensions(destination_width, destination_height);
- if (!media::VideoFrame::IsValidConfig(media::VideoFrame::I420,
- dimensions,
- gfx::Rect(dimensions),
- dimensions)) {
- return;
- }
-
- scoped_refptr<Buffer> buffer =
- DoReserveOutputBuffer(media::VideoFrame::I420, dimensions);
-
- if (!buffer.get())
- return;
- uint8* yplane = NULL;
- bool flip = false;
- yplane = reinterpret_cast<uint8*>(buffer->data());
- uint8* uplane =
- yplane +
- media::VideoFrame::PlaneAllocationSize(
- media::VideoFrame::I420, media::VideoFrame::kYPlane, dimensions);
- uint8* vplane =
- uplane +
- media::VideoFrame::PlaneAllocationSize(
- media::VideoFrame::I420, media::VideoFrame::kUPlane, dimensions);
- int yplane_stride = dimensions.width();
- int uv_plane_stride = yplane_stride / 2;
- int crop_x = 0;
- int crop_y = 0;
- libyuv::FourCC origin_colorspace = libyuv::FOURCC_ANY;
-
- libyuv::RotationMode rotation_mode = libyuv::kRotate0;
- if (rotation == 90)
- rotation_mode = libyuv::kRotate90;
- else if (rotation == 180)
- rotation_mode = libyuv::kRotate180;
- else if (rotation == 270)
- rotation_mode = libyuv::kRotate270;
-
- switch (frame_format.pixel_format) {
- case media::PIXEL_FORMAT_UNKNOWN: // Color format not set.
- break;
- case media::PIXEL_FORMAT_I420:
- DCHECK(!chopped_width && !chopped_height);
- origin_colorspace = libyuv::FOURCC_I420;
- break;
- case media::PIXEL_FORMAT_YV12:
- DCHECK(!chopped_width && !chopped_height);
- origin_colorspace = libyuv::FOURCC_YV12;
- break;
- case media::PIXEL_FORMAT_NV21:
- DCHECK(!chopped_width && !chopped_height);
- origin_colorspace = libyuv::FOURCC_NV21;
- break;
- case media::PIXEL_FORMAT_YUY2:
- DCHECK(!chopped_width && !chopped_height);
- origin_colorspace = libyuv::FOURCC_YUY2;
- break;
- case media::PIXEL_FORMAT_UYVY:
- DCHECK(!chopped_width && !chopped_height);
- origin_colorspace = libyuv::FOURCC_UYVY;
- break;
- case media::PIXEL_FORMAT_RGB24:
- origin_colorspace = libyuv::FOURCC_24BG;
-#if defined(OS_WIN)
- // TODO(wjia): Currently, for RGB24 on WIN, capture device always
- // passes in positive src_width and src_height. Remove this hardcoded
- // value when nagative src_height is supported. The negative src_height
- // indicates that vertical flipping is needed.
- flip = true;
-#endif
- break;
- case media::PIXEL_FORMAT_ARGB:
- origin_colorspace = libyuv::FOURCC_ARGB;
- break;
- case media::PIXEL_FORMAT_MJPEG:
- origin_colorspace = libyuv::FOURCC_MJPG;
- break;
- default:
- NOTREACHED();
- }
-
- libyuv::ConvertToI420(data,
- length,
- yplane,
- yplane_stride,
- uplane,
- uv_plane_stride,
- vplane,
- uv_plane_stride,
- crop_x,
- crop_y,
- frame_format.frame_size.width(),
- (flip ? -frame_format.frame_size.height() :
- frame_format.frame_size.height()),
- new_unrotated_width,
- new_unrotated_height,
- rotation_mode,
- origin_colorspace);
- scoped_refptr<media::VideoFrame> frame =
- media::VideoFrame::WrapExternalPackedMemory(
- media::VideoFrame::I420,
- dimensions,
- gfx::Rect(dimensions),
- dimensions,
- yplane,
- media::VideoFrame::AllocationSize(media::VideoFrame::I420,
- dimensions),
- base::SharedMemory::NULLHandle(),
- base::TimeDelta(),
- base::Closure());
- DCHECK(frame.get());
-
- VideoCaptureFormat format(
- dimensions, frame_format.frame_rate, media::PIXEL_FORMAT_I420);
- BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(
- &VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread,
- controller_,
- buffer,
- format,
- frame,
- timestamp));
-}
-
-void
-VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedVideoFrame(
- const scoped_refptr<Buffer>& buffer,
- const VideoCaptureFormat& buffer_format,
- const scoped_refptr<media::VideoFrame>& frame,
- base::TimeTicks timestamp) {
- BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(
- &VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread,
- controller_,
- buffer,
- buffer_format,
- frame,
- timestamp));
-}
-
-void VideoCaptureController::VideoCaptureDeviceClient::OnError(
- const std::string& 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_));
-}
-
-void VideoCaptureController::VideoCaptureDeviceClient::OnLog(
- const std::string& message) {
- MediaStreamManager::SendMessageToNativeLog("Video capture: " + message);
-}
-
-scoped_refptr<media::VideoCaptureDevice::Client::Buffer>
-VideoCaptureController::VideoCaptureDeviceClient::DoReserveOutputBuffer(
- media::VideoFrame::Format format,
- const gfx::Size& dimensions) {
- size_t frame_bytes = 0;
- if (format == media::VideoFrame::NATIVE_TEXTURE) {
- DCHECK_EQ(dimensions.width(), 0);
- DCHECK_EQ(dimensions.height(), 0);
- } else {
- // The capture pipeline expects I420 for now.
- DCHECK_EQ(format, media::VideoFrame::I420)
- << "Non-I420 output buffer format " << format << " requested";
- frame_bytes = media::VideoFrame::AllocationSize(format, dimensions);
- }
-
- int buffer_id_to_drop = VideoCaptureBufferPool::kInvalidId;
- int buffer_id =
- buffer_pool_->ReserveForProducer(frame_bytes, &buffer_id_to_drop);
- if (buffer_id == VideoCaptureBufferPool::kInvalidId)
- return NULL;
- void* data;
- size_t size;
- buffer_pool_->GetBufferInfo(buffer_id, &data, &size);
-
- scoped_refptr<media::VideoCaptureDevice::Client::Buffer> output_buffer(
- new PoolBuffer(buffer_pool_, buffer_id, data, size));
-
- if (buffer_id_to_drop != VideoCaptureBufferPool::kInvalidId) {
- BrowserThread::PostTask(BrowserThread::IO,
- FROM_HERE,
- base::Bind(&VideoCaptureController::DoBufferDestroyedOnIOThread,
- controller_, buffer_id_to_drop));
- }
-
- return output_buffer;
-}
-
VideoCaptureController::~VideoCaptureController() {
STLDeleteContainerPointers(controller_clients_.begin(),
controller_clients_.end());
}
void VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread(
- const scoped_refptr<media::VideoCaptureDevice::Client::Buffer>& buffer,
- const media::VideoCaptureFormat& buffer_format,
- const scoped_refptr<media::VideoFrame>& frame,
- base::TimeTicks timestamp) {
+ scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer,
+ const scoped_refptr<VideoFrame>& frame,
+ const base::TimeTicks& timestamp) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK_NE(buffer->id(), VideoCaptureBufferPool::kInvalidId);
+ const int buffer_id = buffer->id();
+ DCHECK_NE(buffer_id, VideoCaptureBufferPool::kInvalidId);
int count = 0;
if (state_ == VIDEO_CAPTURE_STATE_STARTED) {
- for (ControllerClients::iterator client_it = controller_clients_.begin();
- client_it != controller_clients_.end(); ++client_it) {
- ControllerClient* client = *client_it;
+ if (!frame->metadata()->HasKey(media::VideoFrameMetadata::FRAME_RATE)) {
+ frame->metadata()->SetDouble(media::VideoFrameMetadata::FRAME_RATE,
+ video_capture_format_.frame_rate);
+ }
+ scoped_ptr<base::DictionaryValue> metadata(new base::DictionaryValue());
+ frame->metadata()->MergeInternalValuesInto(metadata.get());
+
+ for (const auto& client : controller_clients_) {
if (client->session_closed || client->paused)
continue;
- if (frame->format() == media::VideoFrame::NATIVE_TEXTURE) {
- client->event_handler->OnMailboxBufferReady(client->controller_id,
- buffer->id(),
- *frame->mailbox_holder(),
- buffer_format,
- timestamp);
- } else {
- bool is_new_buffer = client->known_buffers.insert(buffer->id()).second;
+ scoped_ptr<base::DictionaryValue> copy_of_metadata;
+ if (client == controller_clients_.back())
+ copy_of_metadata = metadata.Pass();
+ else
+ copy_of_metadata.reset(metadata->DeepCopy());
+
+ if (frame->format() == VideoFrame::NATIVE_TEXTURE) {
+ DCHECK(frame->coded_size() == frame->visible_rect().size())
+ << "Textures are always supposed to be tightly packed.";
+ DCHECK_EQ(1u, VideoFrame::NumTextures(frame->texture_format()));
+ client->event_handler->OnMailboxBufferReady(
+ client->controller_id, buffer_id, frame->mailbox_holder(0),
+ frame->coded_size(), timestamp, copy_of_metadata.Pass());
+ } else if (frame->format() == media::VideoFrame::I420) {
+ bool is_new_buffer = client->known_buffers.insert(buffer_id).second;
if (is_new_buffer) {
// On the first use of a buffer on a client, share the memory handle.
size_t memory_size = 0;
base::SharedMemoryHandle remote_handle = buffer_pool_->ShareToProcess(
- buffer->id(), client->render_process_handle, &memory_size);
+ buffer_id, client->render_process_handle, &memory_size);
client->event_handler->OnBufferCreated(
- client->controller_id, remote_handle, memory_size, buffer->id());
+ client->controller_id, remote_handle, memory_size, buffer_id);
}
client->event_handler->OnBufferReady(
- client->controller_id, buffer->id(), buffer_format,
- frame->visible_rect(), timestamp);
+ client->controller_id, buffer_id, frame->coded_size(),
+ frame->visible_rect(), timestamp, copy_of_metadata.Pass());
+ } else {
+ // VideoFrame format not supported.
+ NOTREACHED();
+ break;
}
bool inserted =
- client->active_buffers.insert(std::make_pair(buffer->id(), frame))
+ client->active_buffers.insert(std::make_pair(buffer_id, frame))
.second;
- DCHECK(inserted) << "Unexpected duplicate buffer: " << buffer->id();
+ DCHECK(inserted) << "Unexpected duplicate buffer: " << buffer_id;
count++;
}
}
if (!has_received_frames_) {
UMA_HISTOGRAM_COUNTS("Media.VideoCapture.Width",
- buffer_format.frame_size.width());
+ frame->visible_rect().width());
UMA_HISTOGRAM_COUNTS("Media.VideoCapture.Height",
- buffer_format.frame_size.height());
+ frame->visible_rect().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);
+ frame->visible_rect().width(),
+ frame->visible_rect().height());
+ double frame_rate;
+ if (!frame->metadata()->GetDouble(media::VideoFrameMetadata::FRAME_RATE,
+ &frame_rate))
+ frame_rate = video_capture_format_.frame_rate;
+ UMA_HISTOGRAM_COUNTS("Media.VideoCapture.FrameRate", frame_rate);
has_received_frames_ = true;
}
- buffer_pool_->HoldForConsumers(buffer->id(), count);
+ buffer_pool_->HoldForConsumers(buffer_id, count);
}
void VideoCaptureController::DoErrorOnIOThread() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
state_ = VIDEO_CAPTURE_STATE_ERROR;
- for (ControllerClients::iterator client_it = controller_clients_.begin();
- client_it != controller_clients_.end(); ++client_it) {
- ControllerClient* client = *client_it;
+ for (const auto* client : controller_clients_) {
if (client->session_closed)
continue;
-
client->event_handler->OnError(client->controller_id);
}
}
+void VideoCaptureController::DoLogOnIOThread(const std::string& message) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ MediaStreamManager::SendMessageToNativeLog("Video capture: " + message);
+}
+
void VideoCaptureController::DoBufferDestroyedOnIOThread(
int buffer_id_to_drop) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- for (ControllerClients::iterator client_it = controller_clients_.begin();
- client_it != controller_clients_.end(); ++client_it) {
- ControllerClient* client = *client_it;
+ for (auto* client : controller_clients_) {
if (client->session_closed)
continue;
@@ -670,30 +383,23 @@ void VideoCaptureController::DoBufferDestroyedOnIOThread(
}
}
-VideoCaptureController::ControllerClient*
-VideoCaptureController::FindClient(
- const VideoCaptureControllerID& id,
+VideoCaptureController::ControllerClient* VideoCaptureController::FindClient(
+ VideoCaptureControllerID id,
VideoCaptureControllerEventHandler* handler,
const ControllerClients& clients) {
- for (ControllerClients::const_iterator client_it = clients.begin();
- client_it != clients.end(); ++client_it) {
- if ((*client_it)->controller_id == id &&
- (*client_it)->event_handler == handler) {
- return *client_it;
- }
+ for (auto* client : clients) {
+ if (client->controller_id == id && client->event_handler == handler)
+ return client;
}
return NULL;
}
-VideoCaptureController::ControllerClient*
-VideoCaptureController::FindClient(
+VideoCaptureController::ControllerClient* VideoCaptureController::FindClient(
int session_id,
const ControllerClients& clients) {
- for (ControllerClients::const_iterator client_it = clients.begin();
- client_it != clients.end(); ++client_it) {
- if ((*client_it)->session_id == session_id) {
- return *client_it;
- }
+ for (auto client : clients) {
+ if (client->session_id == session_id)
+ return client;
}
return NULL;
}
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 720213ecf26..0dd86842f6f 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_controller.h
+++ b/chromium/content/browser/renderer_host/media/video_capture_controller.h
@@ -19,13 +19,6 @@
// it possible for the Manager to delete the Controller and its Device when
// there are no clients left.
//
-// A helper class, VCC::VideoCaptureDeviceClient, is responsible for:
-//
-// * Conveying events from the device thread (where VideoCaptureDevices live)
-// the IO thread (where the VideoCaptureController lives).
-// * Performing some image transformations on the output of the Device;
-// specifically, colorspace conversion and rotation.
-//
// Interactions between VideoCaptureController and other classes:
//
// * VideoCaptureController indirectly observes a VideoCaptureDevice
@@ -54,12 +47,11 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/process/process.h"
-#include "content/browser/renderer_host/media/video_capture_buffer_pool.h"
#include "content/browser/renderer_host/media/video_capture_controller_event_handler.h"
#include "content/common/content_export.h"
#include "content/common/media/video_capture.h"
+#include "media/base/video_capture_types.h"
#include "media/video/capture/video_capture_device.h"
-#include "media/video/capture/video_capture_types.h"
namespace content {
class VideoCaptureBufferPool;
@@ -74,16 +66,18 @@ class CONTENT_EXPORT VideoCaptureController {
explicit VideoCaptureController(int max_buffers);
virtual ~VideoCaptureController();
- base::WeakPtr<VideoCaptureController> GetWeakPtr();
+ base::WeakPtr<VideoCaptureController> GetWeakPtrForIOThread();
// Return a new VideoCaptureDeviceClient to forward capture events to this
- // instance.
- scoped_ptr<media::VideoCaptureDevice::Client> NewDeviceClient();
+ // instance. Some device clients need to allocate resources for the given
+ // capture |format| and/or work on Capture Thread (|capture_task_runner|).
+ scoped_ptr<media::VideoCaptureDevice::Client> NewDeviceClient(
+ const scoped_refptr<base::SingleThreadTaskRunner>& capture_task_runner);
// Start video capturing and try to use the resolution specified in |params|.
// Buffers will be shared to the client as necessary. The client will continue
// to receive frames from the device until RemoveClient() is called.
- void AddClient(const VideoCaptureControllerID& id,
+ void AddClient(VideoCaptureControllerID id,
VideoCaptureControllerEventHandler* event_handler,
base::ProcessHandle render_process,
media::VideoCaptureSessionId session_id,
@@ -93,11 +87,11 @@ class CONTENT_EXPORT VideoCaptureController {
// |event_handler|, and |event_handler| shouldn't use those buffers any more.
// Returns the session_id of the stopped client, or
// kInvalidMediaCaptureSessionId if the indicated client was not registered.
- int RemoveClient(const VideoCaptureControllerID& id,
+ int RemoveClient(VideoCaptureControllerID id,
VideoCaptureControllerEventHandler* event_handler);
// Pause or resume the video capture for specified client.
- void PauseOrResumeClient(const VideoCaptureControllerID& id,
+ void PauseOrResumeClient(VideoCaptureControllerID id,
VideoCaptureControllerEventHandler* event_handler,
bool pause);
@@ -115,7 +109,7 @@ class CONTENT_EXPORT VideoCaptureController {
// buffer was backed by a texture, |sync_point| will be waited on before
// destroying or recycling the texture, to synchronize with texture users in
// the renderer process.
- void ReturnBuffer(const VideoCaptureControllerID& id,
+ void ReturnBuffer(VideoCaptureControllerID id,
VideoCaptureControllerEventHandler* event_handler,
int buffer_id,
uint32 sync_point);
@@ -124,32 +118,27 @@ class CONTENT_EXPORT VideoCaptureController {
bool has_received_frames() const { return has_received_frames_; }
- private:
- class VideoCaptureDeviceClient;
-
- struct ControllerClient;
- typedef std::list<ControllerClient*> ControllerClients;
-
// Worker functions on IO thread. Called by the VideoCaptureDeviceClient.
void DoIncomingCapturedVideoFrameOnIOThread(
- const scoped_refptr<media::VideoCaptureDevice::Client::Buffer>& buffer,
- const media::VideoCaptureFormat& format,
+ scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer,
const scoped_refptr<media::VideoFrame>& frame,
- base::TimeTicks timestamp);
+ const base::TimeTicks& timestamp);
void DoErrorOnIOThread();
- void DoDeviceStoppedOnIOThread();
+ void DoLogOnIOThread(const std::string& message);
void DoBufferDestroyedOnIOThread(int buffer_id_to_drop);
+ private:
+ struct ControllerClient;
+ typedef std::list<ControllerClient*> ControllerClients;
+
// Find a client of |id| and |handler| in |clients|.
- ControllerClient* FindClient(
- const VideoCaptureControllerID& id,
- VideoCaptureControllerEventHandler* handler,
- const ControllerClients& clients);
+ ControllerClient* FindClient(VideoCaptureControllerID id,
+ VideoCaptureControllerEventHandler* handler,
+ const ControllerClients& clients);
// Find a client of |session_id| in |clients|.
- ControllerClient* FindClient(
- int session_id,
- const ControllerClients& clients);
+ ControllerClient* FindClient(int session_id,
+ const ControllerClients& clients);
// The pool of shared-memory buffers used for capturing.
const scoped_refptr<VideoCaptureBufferPool> buffer_pool_;
diff --git a/chromium/content/browser/renderer_host/media/video_capture_controller_event_handler.cc b/chromium/content/browser/renderer_host/media/video_capture_controller_event_handler.cc
deleted file mode 100644
index 7d2d0be3283..00000000000
--- a/chromium/content/browser/renderer_host/media/video_capture_controller_event_handler.cc
+++ /dev/null
@@ -1,23 +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/media/video_capture_controller_event_handler.h"
-
-namespace content {
-
-VideoCaptureControllerID::VideoCaptureControllerID(int did)
- : device_id(did) {
-}
-
-bool VideoCaptureControllerID::operator<(
- const VideoCaptureControllerID& vc) const {
- return this->device_id < vc.device_id;
-}
-
-bool VideoCaptureControllerID::operator==(
- const VideoCaptureControllerID& vc) const {
- return this->device_id == vc.device_id;
-}
-
-} // namespace content
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 2bddf694606..283def2f6d9 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_controller_event_handler.h
+++ b/chromium/content/browser/renderer_host/media/video_capture_controller_event_handler.h
@@ -5,33 +5,27 @@
#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_CONTROLLER_EVENT_HANDLER_H_
#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_CONTROLLER_EVENT_HANDLER_H_
+#include "base/memory/scoped_ptr.h"
#include "base/memory/shared_memory.h"
-#include "base/time/time.h"
#include "content/common/content_export.h"
+namespace base {
+class DictionaryValue;
+class TimeTicks;
+} // namespace base
+
namespace gfx {
class Rect;
+class Size;
} // namespace gfx
namespace gpu {
struct MailboxHolder;
} // namespace gpu
-namespace media {
-class VideoCaptureFormat;
-} // namespace media
-
namespace content {
-// ID used for identifying an object of VideoCaptureController.
-struct CONTENT_EXPORT VideoCaptureControllerID {
- explicit VideoCaptureControllerID(int device_id);
-
- bool operator<(const VideoCaptureControllerID& vc) const;
- bool operator==(const VideoCaptureControllerID& vc) const;
-
- int device_id;
-};
+typedef int VideoCaptureControllerID;
// VideoCaptureControllerEventHandler is the interface for
// VideoCaptureController to notify clients about the events such as
@@ -39,34 +33,37 @@ struct CONTENT_EXPORT VideoCaptureControllerID {
class CONTENT_EXPORT VideoCaptureControllerEventHandler {
public:
// An Error has occurred in the VideoCaptureDevice.
- virtual void OnError(const VideoCaptureControllerID& id) = 0;
+ virtual void OnError(VideoCaptureControllerID id) = 0;
// A buffer has been newly created.
- virtual void OnBufferCreated(const VideoCaptureControllerID& id,
+ virtual void OnBufferCreated(VideoCaptureControllerID id,
base::SharedMemoryHandle handle,
int length,
int buffer_id) = 0;
// A previously created buffer has been freed and will no longer be used.
- virtual void OnBufferDestroyed(const VideoCaptureControllerID& id,
+ virtual void OnBufferDestroyed(VideoCaptureControllerID id,
int buffer_id) = 0;
// A buffer has been filled with I420 video.
- virtual void OnBufferReady(const VideoCaptureControllerID& id,
+ virtual void OnBufferReady(VideoCaptureControllerID id,
int buffer_id,
- const media::VideoCaptureFormat& format,
+ const gfx::Size& coded_size,
const gfx::Rect& visible_rect,
- base::TimeTicks timestamp) = 0;
+ const base::TimeTicks& timestamp,
+ scoped_ptr<base::DictionaryValue> metadata) = 0;
// A texture mailbox buffer has been filled with data.
- virtual void OnMailboxBufferReady(const VideoCaptureControllerID& id,
- int buffer_id,
- const gpu::MailboxHolder& mailbox_holder,
- const media::VideoCaptureFormat& format,
- base::TimeTicks timestamp) = 0;
+ virtual void OnMailboxBufferReady(
+ VideoCaptureControllerID id,
+ int buffer_id,
+ const gpu::MailboxHolder& mailbox_holder,
+ const gfx::Size& packed_frame_size,
+ const base::TimeTicks& timestamp,
+ scoped_ptr<base::DictionaryValue> metadata) = 0;
// The capture session has ended and no more frames will be sent.
- virtual void OnEnded(const VideoCaptureControllerID& id) = 0;
+ virtual void OnEnded(VideoCaptureControllerID id) = 0;
protected:
virtual ~VideoCaptureControllerEventHandler() {}
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 87cb033b1fa..f44069f633e 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
@@ -12,6 +12,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
+#include "base/thread_task_runner_handle.h"
#include "content/browser/renderer_host/media/media_stream_provider.h"
#include "content/browser/renderer_host/media/video_capture_controller.h"
#include "content/browser/renderer_host/media/video_capture_controller_event_handler.h"
@@ -20,19 +21,19 @@
#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"
+#include "media/base/video_capture_types.h"
#include "media/base/video_util.h"
-#include "media/video/capture/video_capture_types.h"
#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
+#if !defined(OS_ANDROID)
#include "content/browser/compositor/test/no_transport_image_transport_factory.h"
#endif
+using ::testing::_;
using ::testing::InSequence;
using ::testing::Mock;
+using ::testing::SaveArg;
namespace content {
@@ -42,35 +43,36 @@ class MockVideoCaptureControllerEventHandler
explicit MockVideoCaptureControllerEventHandler(
VideoCaptureController* controller)
: controller_(controller) {}
- virtual ~MockVideoCaptureControllerEventHandler() {}
+ ~MockVideoCaptureControllerEventHandler() override {}
// These mock methods are delegated to by our fake implementation of
// VideoCaptureControllerEventHandler, to be used in EXPECT_CALL().
- MOCK_METHOD1(DoBufferCreated, void(const VideoCaptureControllerID&));
- MOCK_METHOD1(DoBufferDestroyed, void(const VideoCaptureControllerID&));
- MOCK_METHOD1(DoBufferReady, void(const VideoCaptureControllerID&));
- MOCK_METHOD1(DoMailboxBufferReady, void(const VideoCaptureControllerID&));
- MOCK_METHOD1(DoEnded, void(const VideoCaptureControllerID&));
- MOCK_METHOD1(DoError, void(const VideoCaptureControllerID&));
-
- virtual void OnError(const VideoCaptureControllerID& id) override {
+ MOCK_METHOD1(DoBufferCreated, void(VideoCaptureControllerID));
+ MOCK_METHOD1(DoBufferDestroyed, void(VideoCaptureControllerID));
+ MOCK_METHOD2(DoBufferReady, void(VideoCaptureControllerID, const gfx::Size&));
+ MOCK_METHOD1(DoMailboxBufferReady, void(VideoCaptureControllerID));
+ MOCK_METHOD1(DoEnded, void(VideoCaptureControllerID));
+ MOCK_METHOD1(DoError, void(VideoCaptureControllerID));
+
+ void OnError(VideoCaptureControllerID id) override {
DoError(id);
}
- virtual void OnBufferCreated(const VideoCaptureControllerID& id,
- base::SharedMemoryHandle handle,
- int length, int buffer_id) override {
+ void OnBufferCreated(VideoCaptureControllerID id,
+ base::SharedMemoryHandle handle,
+ int length, int buffer_id) override {
DoBufferCreated(id);
}
- virtual void OnBufferDestroyed(const VideoCaptureControllerID& id,
- int buffer_id) override {
+ void OnBufferDestroyed(VideoCaptureControllerID id, int buffer_id) override {
DoBufferDestroyed(id);
}
- virtual void OnBufferReady(const VideoCaptureControllerID& id,
- int buffer_id,
- const media::VideoCaptureFormat& format,
- const gfx::Rect& visible_rect,
- base::TimeTicks timestamp) override {
- DoBufferReady(id);
+ void OnBufferReady(
+ VideoCaptureControllerID id,
+ int buffer_id,
+ const gfx::Size& coded_size,
+ const gfx::Rect& visible_rect,
+ const base::TimeTicks& timestamp,
+ scoped_ptr<base::DictionaryValue> metadata) override {
+ DoBufferReady(id, coded_size);
base::MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(&VideoCaptureController::ReturnBuffer,
@@ -80,11 +82,13 @@ class MockVideoCaptureControllerEventHandler
buffer_id,
0));
}
- virtual void OnMailboxBufferReady(const VideoCaptureControllerID& id,
- int buffer_id,
- const gpu::MailboxHolder& mailbox_holder,
- const media::VideoCaptureFormat& format,
- base::TimeTicks timestamp) override {
+ void OnMailboxBufferReady(
+ VideoCaptureControllerID id,
+ int buffer_id,
+ const gpu::MailboxHolder& mailbox_holder,
+ const gfx::Size& packed_frame_size,
+ const base::TimeTicks& timestamp,
+ scoped_ptr<base::DictionaryValue> metadata) override {
DoMailboxBufferReady(id);
base::MessageLoop::current()->PostTask(
FROM_HERE,
@@ -95,7 +99,7 @@ class MockVideoCaptureControllerEventHandler
buffer_id,
mailbox_holder.sync_point));
}
- virtual void OnEnded(const VideoCaptureControllerID& id) override {
+ void OnEnded(VideoCaptureControllerID id) override {
DoEnded(id);
// OnEnded() must respond by (eventually) unregistering the client.
base::MessageLoop::current()->PostTask(FROM_HERE,
@@ -117,7 +121,8 @@ class VideoCaptureControllerTest : public testing::Test {
void SetUp() override {
controller_.reset(new VideoCaptureController(kPoolSize));
- device_ = controller_->NewDeviceClient().Pass();
+ device_ = controller_->NewDeviceClient(
+ base::ThreadTaskRunnerHandle::Get());
client_a_.reset(new MockVideoCaptureControllerEventHandler(
controller_.get()));
client_b_.reset(new MockVideoCaptureControllerEventHandler(
@@ -126,34 +131,28 @@ class VideoCaptureControllerTest : public testing::Test {
void TearDown() override { base::RunLoop().RunUntilIdle(); }
- scoped_refptr<media::VideoFrame> WrapI420Buffer(
- const scoped_refptr<media::VideoCaptureDevice::Client::Buffer>& buffer,
- gfx::Size dimensions) {
+ scoped_refptr<media::VideoFrame> WrapI420Buffer(gfx::Size dimensions,
+ uint8* data) {
return media::VideoFrame::WrapExternalPackedMemory(
media::VideoFrame::I420,
dimensions,
gfx::Rect(dimensions),
dimensions,
- reinterpret_cast<uint8*>(buffer->data()),
+ data,
media::VideoFrame::AllocationSize(media::VideoFrame::I420, dimensions),
base::SharedMemory::NULLHandle(),
+ 0,
base::TimeDelta(),
base::Closure());
}
scoped_refptr<media::VideoFrame> WrapMailboxBuffer(
- const scoped_refptr<media::VideoCaptureDevice::Client::Buffer>& buffer,
- scoped_ptr<gpu::MailboxHolder> holder,
+ const gpu::MailboxHolder& holder,
const media::VideoFrame::ReleaseMailboxCB& release_cb,
gfx::Size dimensions) {
return media::VideoFrame::WrapNativeTexture(
- holder.Pass(),
- release_cb,
- dimensions,
- gfx::Rect(dimensions),
- dimensions,
- base::TimeDelta(),
- media::VideoFrame::ReadPixelsCB());
+ holder, release_cb, dimensions, gfx::Rect(dimensions), dimensions,
+ base::TimeDelta(), false /* allow_overlay */, true /* has_alpha */);
}
TestBrowserThreadBundle bundle_;
@@ -276,11 +275,7 @@ static void CacheSyncPoint(uint32* called_release_sync_point,
// 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
+#if !defined(OS_ANDROID)
ImageTransportFactory::InitializeForUnitTests(
scoped_ptr<ImageTransportFactory>(new NoTransportImageTransportFactory));
#endif
@@ -295,7 +290,7 @@ TEST_F(VideoCaptureControllerTest, NormalCaptureMultipleClients) {
media::VideoCaptureParams session_1 = session_100;
- gfx::Size capture_resolution(444, 200);
+ const gfx::Size capture_resolution(444, 200);
// The device format needn't match the VideoCaptureParams (the camera can do
// what it wants). Pick something random.
@@ -328,34 +323,30 @@ TEST_F(VideoCaptureControllerTest, NormalCaptureMultipleClients) {
// Now, simulate an incoming captured buffer from the capture device. As a
// side effect this will cause the first buffer to be shared with clients.
uint8 buffer_no = 1;
- scoped_refptr<media::VideoCaptureDevice::Client::Buffer> buffer;
- buffer =
- device_->ReserveOutputBuffer(media::VideoFrame::I420, capture_resolution);
+ scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer(
+ device_->ReserveOutputBuffer(media::PIXEL_FORMAT_I420,
+ capture_resolution));
ASSERT_TRUE(buffer.get());
memset(buffer->data(), buffer_no++, buffer->size());
{
InSequence s;
EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_1)).Times(1);
- EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_1)).Times(1);
+ EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_1,_)).Times(1);
}
{
InSequence s;
EXPECT_CALL(*client_b_, DoBufferCreated(client_b_route_1)).Times(1);
- EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_1)).Times(1);
+ EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_1,_)).Times(1);
}
{
InSequence s;
EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_2)).Times(1);
- EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_2)).Times(1);
+ EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_2,_)).Times(1);
}
- device_->OnIncomingCapturedVideoFrame(
- buffer,
- media::VideoCaptureFormat(capture_resolution,
- device_format.frame_rate,
- media::PIXEL_FORMAT_I420),
- WrapI420Buffer(buffer, capture_resolution),
- base::TimeTicks());
- buffer = NULL;
+ scoped_refptr<media::VideoFrame> video_frame =
+ WrapI420Buffer(capture_resolution, static_cast<uint8*>(buffer->data()));
+ device_->OnIncomingCapturedVideoFrame(buffer.Pass(), video_frame,
+ base::TimeTicks());
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(client_a_.get());
@@ -364,23 +355,20 @@ TEST_F(VideoCaptureControllerTest, NormalCaptureMultipleClients) {
// Second buffer which ought to use the same shared memory buffer. In this
// case pretend that the Buffer pointer is held by the device for a long
// delay. This shouldn't affect anything.
- buffer =
- device_->ReserveOutputBuffer(media::VideoFrame::I420, capture_resolution);
- ASSERT_TRUE(buffer.get());
- memset(buffer->data(), buffer_no++, buffer->size());
- device_->OnIncomingCapturedVideoFrame(
- buffer,
- media::VideoCaptureFormat(capture_resolution,
- device_format.frame_rate,
- media::PIXEL_FORMAT_I420),
- WrapI420Buffer(buffer, capture_resolution),
- base::TimeTicks());
- buffer = NULL;
+ scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer2 =
+ device_->ReserveOutputBuffer(media::PIXEL_FORMAT_I420,
+ capture_resolution);
+ ASSERT_TRUE(buffer2.get());
+ memset(buffer2->data(), buffer_no++, buffer2->size());
+ video_frame =
+ WrapI420Buffer(capture_resolution, static_cast<uint8*>(buffer2->data()));
+ device_->OnIncomingCapturedVideoFrame(buffer2.Pass(), video_frame,
+ base::TimeTicks());
// The buffer should be delivered to the clients in any order.
- EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_1)).Times(1);
- EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_1)).Times(1);
- EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_2)).Times(1);
+ EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_1,_)).Times(1);
+ EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_1,_)).Times(1);
+ EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_2,_)).Times(1);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(client_a_.get());
Mock::VerifyAndClearExpectations(client_b_.get());
@@ -395,35 +383,32 @@ TEST_F(VideoCaptureControllerTest, NormalCaptureMultipleClients) {
// Third, fourth, and fifth buffers. Pretend they all arrive at the same time.
for (int i = 0; i < kPoolSize; i++) {
- buffer = device_->ReserveOutputBuffer(media::VideoFrame::I420,
- capture_resolution);
+ scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer =
+ device_->ReserveOutputBuffer(media::PIXEL_FORMAT_I420,
+ capture_resolution);
ASSERT_TRUE(buffer.get());
memset(buffer->data(), buffer_no++, buffer->size());
- device_->OnIncomingCapturedVideoFrame(
- buffer,
- media::VideoCaptureFormat(capture_resolution,
- device_format.frame_rate,
- media::PIXEL_FORMAT_I420),
- WrapI420Buffer(buffer, capture_resolution),
- base::TimeTicks());
- buffer = NULL;
+ video_frame =
+ WrapI420Buffer(capture_resolution, static_cast<uint8*>(buffer->data()));
+ device_->OnIncomingCapturedVideoFrame(buffer.Pass(), video_frame,
+ base::TimeTicks());
}
// ReserveOutputBuffer ought to fail now, because the pool is depleted.
- ASSERT_FALSE(device_->ReserveOutputBuffer(media::VideoFrame::I420,
+ ASSERT_FALSE(device_->ReserveOutputBuffer(media::PIXEL_FORMAT_I420,
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);
- EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_2)).Times(kPoolSize);
+ EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_2,_)).Times(kPoolSize);
EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_1))
.Times(kPoolSize - 1);
- EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_1)).Times(kPoolSize);
+ EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_1,_)).Times(kPoolSize);
EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_2))
.Times(kPoolSize - 1);
- EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_2)).Times(kPoolSize);
+ EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_2,_)).Times(kPoolSize);
EXPECT_CALL(*client_b_, DoBufferCreated(client_b_route_1))
.Times(kPoolSize - 1);
- EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_1)).Times(kPoolSize);
+ EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_1,_)).Times(kPoolSize);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(client_a_.get());
Mock::VerifyAndClearExpectations(client_b_.get());
@@ -435,98 +420,87 @@ TEST_F(VideoCaptureControllerTest, NormalCaptureMultipleClients) {
EXPECT_CALL(*client_b_, DoEnded(client_b_route_1)).Times(1);
controller_->StopSession(300);
// Queue up another buffer.
- buffer =
- device_->ReserveOutputBuffer(media::VideoFrame::I420, capture_resolution);
- ASSERT_TRUE(buffer.get());
- memset(buffer->data(), buffer_no++, buffer->size());
- device_->OnIncomingCapturedVideoFrame(
- buffer,
- media::VideoCaptureFormat(capture_resolution,
- device_format.frame_rate,
- media::PIXEL_FORMAT_I420),
- WrapI420Buffer(buffer, capture_resolution),
- base::TimeTicks());
- buffer = NULL;
- buffer =
- device_->ReserveOutputBuffer(media::VideoFrame::I420, capture_resolution);
+ scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer3 =
+ device_->ReserveOutputBuffer(media::PIXEL_FORMAT_I420,
+ capture_resolution);
+ ASSERT_TRUE(buffer3.get());
+ memset(buffer3->data(), buffer_no++, buffer3->size());
+ video_frame =
+ WrapI420Buffer(capture_resolution, static_cast<uint8*>(buffer3->data()));
+ device_->OnIncomingCapturedVideoFrame(buffer3.Pass(), video_frame,
+ base::TimeTicks());
+
+ scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer4 =
+ device_->ReserveOutputBuffer(media::PIXEL_FORMAT_I420,
+ capture_resolution);
{
// Kill A2 via session close (posts a task to disconnect, but A2 must not
// be sent either of these two buffers).
EXPECT_CALL(*client_a_, DoEnded(client_a_route_2)).Times(1);
controller_->StopSession(200);
}
- ASSERT_TRUE(buffer.get());
- memset(buffer->data(), buffer_no++, buffer->size());
- device_->OnIncomingCapturedVideoFrame(
- buffer,
- media::VideoCaptureFormat(capture_resolution,
- device_format.frame_rate,
- media::PIXEL_FORMAT_I420),
- WrapI420Buffer(buffer, capture_resolution),
- base::TimeTicks());
- buffer = NULL;
+ ASSERT_TRUE(buffer4.get());
+ memset(buffer4->data(), buffer_no++, buffer4->size());
+ video_frame =
+ WrapI420Buffer(capture_resolution, static_cast<uint8*>(buffer4->data()));
+ device_->OnIncomingCapturedVideoFrame(buffer4.Pass(), video_frame,
+ base::TimeTicks());
// B2 is the only client left, and is the only one that should
// get the buffer.
- EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_2)).Times(2);
+ EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_2,_)).Times(2);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(client_a_.get());
Mock::VerifyAndClearExpectations(client_b_.get());
// Allocate all buffers from the buffer pool, half as SHM buffer and half as
// mailbox buffers. Make sure of different counts though.
- int shm_buffers = kPoolSize / 2;
- int mailbox_buffers = kPoolSize - shm_buffers;
+#if defined(OS_ANDROID)
+ int mailbox_buffers = 0;
+#else
+ int mailbox_buffers = kPoolSize / 2;
+ GLHelper* gl_helper = ImageTransportFactory::GetInstance()->GetGLHelper();
+#endif
+ int shm_buffers = kPoolSize - mailbox_buffers;
if (shm_buffers == mailbox_buffers) {
shm_buffers--;
mailbox_buffers++;
}
for (int i = 0; i < shm_buffers; ++i) {
- buffer = device_->ReserveOutputBuffer(media::VideoFrame::I420,
- capture_resolution);
+ scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer =
+ device_->ReserveOutputBuffer(media::PIXEL_FORMAT_I420,
+ capture_resolution);
ASSERT_TRUE(buffer.get());
- device_->OnIncomingCapturedVideoFrame(
- buffer,
- media::VideoCaptureFormat(capture_resolution,
- device_format.frame_rate,
- media::PIXEL_FORMAT_I420),
- WrapI420Buffer(buffer, capture_resolution),
- base::TimeTicks());
- buffer = NULL;
+ video_frame =
+ WrapI420Buffer(capture_resolution, static_cast<uint8*>(buffer->data()));
+ device_->OnIncomingCapturedVideoFrame(buffer.Pass(), video_frame,
+ base::TimeTicks());
}
std::vector<uint32> mailbox_syncpoints(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));
+ scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer =
+ device_->ReserveOutputBuffer(media::PIXEL_FORMAT_TEXTURE,
+ capture_resolution);
ASSERT_TRUE(buffer.get());
+#if !defined(OS_ANDROID)
mailbox_syncpoints[i] = gl_helper->InsertSyncPoint();
+#endif
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_syncpoints[i]),
- capture_resolution),
+ buffer.Pass(),
+ WrapMailboxBuffer(
+ 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,
+ ASSERT_FALSE(device_->ReserveOutputBuffer(media::PIXEL_FORMAT_I420,
+ capture_resolution).get());
+ ASSERT_FALSE(device_->ReserveOutputBuffer(media::PIXEL_FORMAT_TEXTURE,
capture_resolution).get());
- ASSERT_FALSE(device_->ReserveOutputBuffer(media::VideoFrame::NATIVE_TEXTURE,
- gfx::Size(0, 0)).get());
- EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_2)).Times(shm_buffers);
+ 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();
@@ -539,9 +513,7 @@ TEST_F(VideoCaptureControllerTest, NormalCaptureMultipleClients) {
}
Mock::VerifyAndClearExpectations(client_b_.get());
-#if defined(OS_ANDROID)
- ImageTransportFactoryAndroid::TerminateForUnitTests();
-#else
+#if !defined(OS_ANDROID)
ImageTransportFactory::Terminate();
#endif
}
@@ -575,17 +547,14 @@ TEST_F(VideoCaptureControllerTest, ErrorBeforeDeviceCreation) {
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(client_b_.get());
- scoped_refptr<media::VideoCaptureDevice::Client::Buffer> buffer =
- device_->ReserveOutputBuffer(media::VideoFrame::I420, capture_resolution);
+ scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer(
+ device_->ReserveOutputBuffer(media::PIXEL_FORMAT_I420,
+ capture_resolution));
ASSERT_TRUE(buffer.get());
-
- device_->OnIncomingCapturedVideoFrame(
- buffer,
- media::VideoCaptureFormat(
- capture_resolution, 30, media::PIXEL_FORMAT_I420),
- WrapI420Buffer(buffer, capture_resolution),
- base::TimeTicks());
- buffer = NULL;
+ scoped_refptr<media::VideoFrame> video_frame =
+ WrapI420Buffer(capture_resolution, static_cast<uint8*>(buffer->data()));
+ device_->OnIncomingCapturedVideoFrame(buffer.Pass(), video_frame,
+ base::TimeTicks());
base::RunLoop().RunUntilIdle();
}
@@ -614,18 +583,15 @@ TEST_F(VideoCaptureControllerTest, ErrorAfterDeviceCreation) {
Mock::VerifyAndClearExpectations(client_a_.get());
const gfx::Size dims(320, 240);
- scoped_refptr<media::VideoCaptureDevice::Client::Buffer> buffer =
- device_->ReserveOutputBuffer(media::VideoFrame::I420, dims);
+ scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer(
+ device_->ReserveOutputBuffer(media::PIXEL_FORMAT_I420, dims));
ASSERT_TRUE(buffer.get());
- device_->OnError("Test error");
- device_->OnIncomingCapturedVideoFrame(
- buffer,
- media::VideoCaptureFormat(
- dims, device_format.frame_rate, media::PIXEL_FORMAT_I420),
- WrapI420Buffer(buffer, dims),
- base::TimeTicks());
- buffer = NULL;
+ scoped_refptr<media::VideoFrame> video_frame =
+ WrapI420Buffer(dims, static_cast<uint8*>(buffer->data()));
+ device_->OnError("Test Error");
+ device_->OnIncomingCapturedVideoFrame(buffer.Pass(), video_frame,
+ base::TimeTicks());
EXPECT_CALL(*client_a_, DoError(route_id)).Times(1);
base::RunLoop().RunUntilIdle();
@@ -639,4 +605,106 @@ TEST_F(VideoCaptureControllerTest, ErrorAfterDeviceCreation) {
Mock::VerifyAndClearExpectations(client_b_.get());
}
+// Tests that buffer-based capture API accepts all memory-backed pixel formats.
+TEST_F(VideoCaptureControllerTest, DataCaptureInEachVideoFormatInSequence) {
+ // The usual ReserveOutputBuffer() -> OnIncomingCapturedVideoFrame() cannot
+ // be used since it does not accept all pixel formats. The memory backed
+ // buffer OnIncomingCapturedData() is used instead, with a dummy scratchpad
+ // buffer.
+ const size_t kScratchpadSizeInBytes = 400;
+ unsigned char data[kScratchpadSizeInBytes];
+ // Initialize memory to satisfy DrMemory tests.
+ memset(data, 0, kScratchpadSizeInBytes);
+ const gfx::Size capture_resolution(10, 10);
+ ASSERT_GE(kScratchpadSizeInBytes, capture_resolution.GetArea() * 4u)
+ << "Scratchpad is too small to hold the largest pixel format (ARGB).";
+
+ const int kSessionId = 100;
+ // This Test skips PIXEL_FORMAT_TEXTURE and PIXEL_FORMAT_UNKNOWN.
+ for (int format = 0; format < media::PIXEL_FORMAT_TEXTURE; ++format) {
+ media::VideoCaptureParams params;
+ params.requested_format = media::VideoCaptureFormat(
+ capture_resolution, 30, media::VideoPixelFormat(format));
+
+ // Start with one client.
+ const VideoCaptureControllerID route_id(0x99);
+ controller_->AddClient(route_id,
+ client_a_.get(),
+ base::kNullProcessHandle,
+ kSessionId,
+ params);
+ ASSERT_EQ(1, controller_->GetClientCount());
+ device_->OnIncomingCapturedData(
+ data,
+ params.requested_format.ImageAllocationSize(),
+ params.requested_format,
+ 0 /* clockwise_rotation */,
+ base::TimeTicks());
+ EXPECT_EQ(kSessionId, controller_->RemoveClient(route_id, client_a_.get()));
+ Mock::VerifyAndClearExpectations(client_a_.get());
+ }
+}
+
+// Test that we receive the expected resolution for a given captured frame
+// resolution and rotation. Odd resolutions are also cropped.
+TEST_F(VideoCaptureControllerTest, CheckRotationsAndCrops) {
+ const int kSessionId = 100;
+ const struct SizeAndRotation {
+ gfx::Size input_resolution;
+ int rotation;
+ gfx::Size output_resolution;
+ } kSizeAndRotations[] = {{{6, 4}, 0, {6, 4}},
+ {{6, 4}, 90, {4, 6}},
+ {{6, 4}, 180, {6, 4}},
+ {{6, 4}, 270, {4, 6}},
+ {{7, 4}, 0, {6, 4}},
+ {{7, 4}, 90, {4, 6}},
+ {{7, 4}, 180, {6, 4}},
+ {{7, 4}, 270, {4, 6}}};
+ // The usual ReserveOutputBuffer() -> OnIncomingCapturedVideoFrame() cannot
+ // be used since it does not resolve rotations or crops. The memory backed
+ // buffer OnIncomingCapturedData() is used instead, with a dummy scratchpad
+ // buffer.
+ const size_t kScratchpadSizeInBytes = 400;
+ unsigned char data[kScratchpadSizeInBytes] = {};
+
+ media::VideoCaptureParams params;
+ for (const auto& size_and_rotation : kSizeAndRotations) {
+ ASSERT_GE(kScratchpadSizeInBytes,
+ size_and_rotation.input_resolution.GetArea() * 4u)
+ << "Scratchpad is too small to hold the largest pixel format (ARGB).";
+
+ params.requested_format = media::VideoCaptureFormat(
+ size_and_rotation.input_resolution, 30, media::PIXEL_FORMAT_ARGB);
+
+ const VideoCaptureControllerID route_id(0x99);
+ controller_->AddClient(route_id, client_a_.get(), base::kNullProcessHandle,
+ kSessionId, params);
+ ASSERT_EQ(1, controller_->GetClientCount());
+
+ device_->OnIncomingCapturedData(
+ data,
+ params.requested_format.ImageAllocationSize(),
+ params.requested_format,
+ size_and_rotation.rotation,
+ base::TimeTicks());
+ gfx::Size coded_size;
+ {
+ InSequence s;
+ EXPECT_CALL(*client_a_, DoBufferCreated(route_id)).Times(1);
+ EXPECT_CALL(*client_a_, DoBufferReady(route_id, _))
+ .Times(1)
+ .WillOnce(SaveArg<1>(&coded_size));
+ }
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(coded_size.width(), size_and_rotation.output_resolution.width());
+ EXPECT_EQ(coded_size.height(),
+ size_and_rotation.output_resolution.height());
+
+ EXPECT_EQ(kSessionId, controller_->RemoveClient(route_id, client_a_.get()));
+ Mock::VerifyAndClearExpectations(client_a_.get());
+ }
+}
+
} // namespace content
diff --git a/chromium/content/browser/renderer_host/media/video_capture_device_client.cc b/chromium/content/browser/renderer_host/media/video_capture_device_client.cc
new file mode 100644
index 00000000000..5196ad3b428
--- /dev/null
+++ b/chromium/content/browser/renderer_host/media/video_capture_device_client.cc
@@ -0,0 +1,673 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/renderer_host/media/video_capture_device_client.h"
+
+#include "base/bind.h"
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event.h"
+#include "content/browser/compositor/image_transport_factory.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_data_manager_impl.h"
+#include "content/browser/renderer_host/media/video_capture_buffer_pool.h"
+#include "content/browser/renderer_host/media/video_capture_controller.h"
+#include "content/common/gpu/client/context_provider_command_buffer.h"
+#include "content/common/gpu/client/gl_helper.h"
+#include "content/common/gpu/client/gpu_channel_host.h"
+#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
+#include "content/common/gpu/gpu_process_launch_causes.h"
+#include "content/public/browser/browser_thread.h"
+#include "gpu/command_buffer/common/mailbox_holder.h"
+#include "media/base/bind_to_current_loop.h"
+#include "media/base/video_capture_types.h"
+#include "media/base/video_frame.h"
+#include "third_party/khronos/GLES2/gl2ext.h"
+#include "third_party/libyuv/include/libyuv.h"
+
+using media::VideoCaptureFormat;
+using media::VideoFrame;
+
+namespace content {
+
+namespace {
+
+#if !defined(OS_ANDROID)
+// Modelled after GpuProcessTransportFactory::CreateContextCommon().
+scoped_ptr<content::WebGraphicsContext3DCommandBufferImpl> CreateContextCommon(
+ scoped_refptr<content::GpuChannelHost> gpu_channel_host,
+ int surface_id) {
+ if (!content::GpuDataManagerImpl::GetInstance()->
+ CanUseGpuBrowserCompositor()) {
+ DLOG(ERROR) << "No accelerated graphics found. Check chrome://gpu";
+ return scoped_ptr<content::WebGraphicsContext3DCommandBufferImpl>();
+ }
+ blink::WebGraphicsContext3D::Attributes attrs;
+ attrs.shareResources = true;
+ attrs.depth = false;
+ attrs.stencil = false;
+ attrs.antialias = false;
+ attrs.noAutomaticFlushes = true;
+
+ if (!gpu_channel_host.get()) {
+ DLOG(ERROR) << "Failed to establish GPU channel.";
+ return scoped_ptr<content::WebGraphicsContext3DCommandBufferImpl>();
+ }
+ GURL url("chrome://gpu/GpuProcessTransportFactory::CreateCaptureContext");
+ return make_scoped_ptr(
+ new WebGraphicsContext3DCommandBufferImpl(
+ surface_id,
+ url,
+ gpu_channel_host.get(),
+ attrs,
+ true /* lose_context_when_out_of_memory */,
+ content::WebGraphicsContext3DCommandBufferImpl::SharedMemoryLimits(),
+ NULL));
+}
+
+// Modelled after
+// GpuProcessTransportFactory::CreateOffscreenCommandBufferContext().
+scoped_ptr<content::WebGraphicsContext3DCommandBufferImpl>
+CreateOffscreenCommandBufferContext() {
+ content::CauseForGpuLaunch cause = content::CAUSE_FOR_GPU_LAUNCH_CANVAS_2D;
+ // Android does not support synchronous opening of GPU channels. Should use
+ // EstablishGpuChannel() instead.
+ if (!content::BrowserGpuChannelHostFactory::instance())
+ return scoped_ptr<content::WebGraphicsContext3DCommandBufferImpl>();
+ scoped_refptr<content::GpuChannelHost> gpu_channel_host(
+ content::BrowserGpuChannelHostFactory::instance()->
+ EstablishGpuChannelSync(cause));
+ DCHECK(gpu_channel_host);
+ return CreateContextCommon(gpu_channel_host, 0);
+}
+#endif
+
+typedef base::Callback<void(scoped_refptr<ContextProviderCommandBuffer>)>
+ ProcessContextCallback;
+
+void CreateContextOnUIThread(ProcessContextCallback bottom_half) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+#if !defined(OS_ANDROID)
+ bottom_half.Run(ContextProviderCommandBuffer::Create(
+ CreateOffscreenCommandBufferContext(), OFFSCREEN_VIDEO_CAPTURE_CONTEXT));
+ return;
+#endif
+}
+
+void ResetLostContextCallback(
+ const scoped_refptr<ContextProviderCommandBuffer>& capture_thread_context) {
+ capture_thread_context->SetLostContextCallback(
+ cc::ContextProvider::LostContextCallback());
+}
+
+} // anonymous namespace
+
+// Class combining a Client::Buffer interface implementation and a pool buffer
+// implementation to guarantee proper cleanup on destruction on our side.
+class AutoReleaseBuffer : public media::VideoCaptureDevice::Client::Buffer {
+ public:
+ AutoReleaseBuffer(const scoped_refptr<VideoCaptureBufferPool>& pool,
+ int buffer_id)
+ : id_(buffer_id),
+ pool_(pool),
+ buffer_handle_(pool_->GetBufferHandle(buffer_id).Pass()) {
+ DCHECK(pool_.get());
+ }
+ int id() const override { return id_; }
+ size_t size() const override { return buffer_handle_->size(); }
+ void* data() override { return buffer_handle_->data(); }
+ gfx::GpuMemoryBufferType GetType() override {
+ return buffer_handle_->GetType();
+ }
+ ClientBuffer AsClientBuffer() override {
+ return buffer_handle_->AsClientBuffer();
+ }
+
+ private:
+ ~AutoReleaseBuffer() override { pool_->RelinquishProducerReservation(id_); }
+
+ const int id_;
+ const scoped_refptr<VideoCaptureBufferPool> pool_;
+ const scoped_ptr<VideoCaptureBufferPool::BufferHandle> buffer_handle_;
+};
+
+// Internal ref-counted class wrapping an incoming GpuMemoryBuffer into a
+// Texture backed VideoFrame. This VideoFrame creation is balanced by a waiting
+// on the associated |sync_point|. After VideoFrame consumption the inserted
+// ReleaseCallback() will be called, where the Texture is destroyed.
+//
+// This class jumps between threads due to GPU-related thread limitations, i.e.
+// some objects cannot be accessed from IO Thread whereas others need to be
+// constructed on UI Thread. For this reason most of the operations are carried
+// out on Capture Thread (|capture_task_runner_|).
+class VideoCaptureDeviceClient::TextureWrapHelper final
+ : public base::RefCountedThreadSafe<TextureWrapHelper> {
+ public:
+ TextureWrapHelper(
+ const base::WeakPtr<VideoCaptureController>& controller,
+ const scoped_refptr<base::SingleThreadTaskRunner>& capture_task_runner);
+
+ // Wraps the GpuMemoryBuffer-backed |buffer| into a Texture, and sends it to
+ // |controller_| wrapped in a VideoFrame.
+ void OnIncomingCapturedGpuMemoryBuffer(
+ scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer,
+ const media::VideoCaptureFormat& frame_format,
+ const base::TimeTicks& timestamp);
+
+ private:
+ friend class base::RefCountedThreadSafe<TextureWrapHelper>;
+ ~TextureWrapHelper();
+
+ // Creates some necessary members in |capture_task_runner_|.
+ void Init();
+ // Runs the bottom half of the GlHelper creation.
+ void CreateGlHelper(
+ scoped_refptr<ContextProviderCommandBuffer> capture_thread_context);
+
+ // Recycles |memory_buffer|, deletes Image and Texture on VideoFrame release.
+ void ReleaseCallback(GLuint image_id,
+ GLuint texture_id,
+ uint32 sync_point);
+
+ // The Command Buffer lost the GL context, f.i. GPU process crashed. Signal
+ // error to our owner so the capture can be torn down.
+ void LostContextCallback();
+
+ // Prints the error |message| and notifies |controller_| of an error.
+ void OnError(const std::string& message);
+
+ // |controller_| should only be used on IO thread.
+ const base::WeakPtr<VideoCaptureController> controller_;
+ const scoped_refptr<base::SingleThreadTaskRunner> capture_task_runner_;
+
+ // Command buffer reference, needs to be destroyed when unused. It is created
+ // on UI Thread and bound to Capture Thread. In particular, it cannot be used
+ // from IO Thread.
+ scoped_refptr<ContextProviderCommandBuffer> capture_thread_context_;
+ // Created and used from Capture Thread. Cannot be used from IO Thread.
+ scoped_ptr<GLHelper> gl_helper_;
+
+ DISALLOW_COPY_AND_ASSIGN(TextureWrapHelper);
+};
+
+VideoCaptureDeviceClient::VideoCaptureDeviceClient(
+ const base::WeakPtr<VideoCaptureController>& controller,
+ const scoped_refptr<VideoCaptureBufferPool>& buffer_pool,
+ const scoped_refptr<base::SingleThreadTaskRunner>& capture_task_runner)
+ : controller_(controller),
+ buffer_pool_(buffer_pool),
+ capture_task_runner_(capture_task_runner),
+ last_captured_pixel_format_(media::PIXEL_FORMAT_UNKNOWN) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+}
+
+VideoCaptureDeviceClient::~VideoCaptureDeviceClient() {}
+
+void VideoCaptureDeviceClient::OnIncomingCapturedData(
+ const uint8* data,
+ int length,
+ const VideoCaptureFormat& frame_format,
+ int rotation,
+ const base::TimeTicks& timestamp) {
+ TRACE_EVENT0("video", "VideoCaptureDeviceClient::OnIncomingCapturedData");
+
+ if (last_captured_pixel_format_ != frame_format.pixel_format) {
+ OnLog("Pixel format: " + media::VideoCaptureFormat::PixelFormatToString(
+ frame_format.pixel_format));
+ last_captured_pixel_format_ = frame_format.pixel_format;
+ }
+
+ if (!frame_format.IsValid())
+ return;
+
+ // |chopped_{width,height} and |new_unrotated_{width,height}| are the lowest
+ // bit decomposition of {width, height}, grabbing the odd and even parts.
+ const int chopped_width = frame_format.frame_size.width() & 1;
+ const int chopped_height = frame_format.frame_size.height() & 1;
+ const int new_unrotated_width = frame_format.frame_size.width() & ~1;
+ const int new_unrotated_height = frame_format.frame_size.height() & ~1;
+
+ int destination_width = new_unrotated_width;
+ int destination_height = new_unrotated_height;
+ if (rotation == 90 || rotation == 270) {
+ destination_width = new_unrotated_height;
+ destination_height = new_unrotated_width;
+ }
+
+ DCHECK_EQ(rotation % 90, 0)
+ << " Rotation must be a multiple of 90, now: " << rotation;
+ libyuv::RotationMode rotation_mode = libyuv::kRotate0;
+ if (rotation == 90)
+ rotation_mode = libyuv::kRotate90;
+ else if (rotation == 180)
+ rotation_mode = libyuv::kRotate180;
+ else if (rotation == 270)
+ rotation_mode = libyuv::kRotate270;
+
+ const gfx::Size dimensions(destination_width, destination_height);
+ if (!VideoFrame::IsValidConfig(VideoFrame::I420,
+ dimensions,
+ gfx::Rect(dimensions),
+ dimensions)) {
+ return;
+ }
+
+ scoped_ptr<Buffer> buffer(
+ ReserveOutputBuffer(media::PIXEL_FORMAT_I420, dimensions));
+ if (!buffer.get())
+ return;
+
+ uint8* const yplane = reinterpret_cast<uint8*>(buffer->data());
+ uint8* const uplane =
+ yplane + VideoFrame::PlaneAllocationSize(VideoFrame::I420,
+ VideoFrame::kYPlane, dimensions);
+ uint8* const vplane =
+ uplane + VideoFrame::PlaneAllocationSize(VideoFrame::I420,
+ VideoFrame::kUPlane, dimensions);
+ int yplane_stride = dimensions.width();
+ int uv_plane_stride = yplane_stride / 2;
+ int crop_x = 0;
+ int crop_y = 0;
+ libyuv::FourCC origin_colorspace = libyuv::FOURCC_ANY;
+
+ bool flip = false;
+ switch (frame_format.pixel_format) {
+ case media::PIXEL_FORMAT_UNKNOWN: // Color format not set.
+ break;
+ case media::PIXEL_FORMAT_I420:
+ DCHECK(!chopped_width && !chopped_height);
+ origin_colorspace = libyuv::FOURCC_I420;
+ break;
+ case media::PIXEL_FORMAT_YV12:
+ DCHECK(!chopped_width && !chopped_height);
+ origin_colorspace = libyuv::FOURCC_YV12;
+ break;
+ case media::PIXEL_FORMAT_NV12:
+ DCHECK(!chopped_width && !chopped_height);
+ origin_colorspace = libyuv::FOURCC_NV12;
+ break;
+ case media::PIXEL_FORMAT_NV21:
+ DCHECK(!chopped_width && !chopped_height);
+ origin_colorspace = libyuv::FOURCC_NV21;
+ break;
+ case media::PIXEL_FORMAT_YUY2:
+ DCHECK(!chopped_width && !chopped_height);
+ origin_colorspace = libyuv::FOURCC_YUY2;
+ break;
+ case media::PIXEL_FORMAT_UYVY:
+ DCHECK(!chopped_width && !chopped_height);
+ origin_colorspace = libyuv::FOURCC_UYVY;
+ break;
+ case media::PIXEL_FORMAT_RGB24:
+ origin_colorspace = libyuv::FOURCC_24BG;
+#if defined(OS_WIN)
+ // TODO(wjia): Currently, for RGB24 on WIN, capture device always
+ // passes in positive src_width and src_height. Remove this hardcoded
+ // value when nagative src_height is supported. The negative src_height
+ // indicates that vertical flipping is needed.
+ flip = true;
+#endif
+ break;
+ case media::PIXEL_FORMAT_RGB32:
+// Fallback to PIXEL_FORMAT_ARGB setting |flip| in Windows platforms.
+#if defined(OS_WIN)
+ flip = true;
+#endif
+ case media::PIXEL_FORMAT_ARGB:
+ origin_colorspace = libyuv::FOURCC_ARGB;
+ break;
+ case media::PIXEL_FORMAT_MJPEG:
+ origin_colorspace = libyuv::FOURCC_MJPG;
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ // The input |length| can be greater than the required buffer size because of
+ // paddings and/or alignments, but it cannot be smaller.
+ DCHECK_GE(static_cast<size_t>(length), frame_format.ImageAllocationSize());
+
+ if (libyuv::ConvertToI420(data,
+ length,
+ yplane,
+ yplane_stride,
+ uplane,
+ uv_plane_stride,
+ vplane,
+ uv_plane_stride,
+ crop_x,
+ crop_y,
+ frame_format.frame_size.width(),
+ (flip ? -1 : 1) * frame_format.frame_size.height(),
+ new_unrotated_width,
+ new_unrotated_height,
+ rotation_mode,
+ origin_colorspace) != 0) {
+ DLOG(WARNING) << "Failed to convert buffer's pixel format to I420 from "
+ << media::VideoCaptureFormat::PixelFormatToString(
+ frame_format.pixel_format);
+ return;
+ }
+
+ OnIncomingCapturedBuffer(buffer.Pass(),
+ media::VideoCaptureFormat(dimensions,
+ frame_format.frame_rate,
+ media::PIXEL_FORMAT_I420),
+ timestamp);
+}
+
+void
+VideoCaptureDeviceClient::OnIncomingCapturedYuvData(
+ const uint8* y_data,
+ const uint8* u_data,
+ const uint8* v_data,
+ size_t y_stride,
+ size_t u_stride,
+ size_t v_stride,
+ const VideoCaptureFormat& frame_format,
+ int clockwise_rotation,
+ const base::TimeTicks& timestamp) {
+ TRACE_EVENT0("video", "VideoCaptureDeviceClient::OnIncomingCapturedYuvData");
+ DCHECK_EQ(frame_format.pixel_format, media::PIXEL_FORMAT_I420);
+ DCHECK_EQ(clockwise_rotation, 0) << "Rotation not supported";
+
+ scoped_ptr<Buffer> buffer(
+ ReserveOutputBuffer(frame_format.pixel_format, frame_format.frame_size));
+ if (!buffer.get())
+ return;
+
+ // Blit (copy) here from y,u,v into buffer.data()). Needed so we can return
+ // the parameter buffer synchronously to the driver.
+ const size_t y_plane_size = VideoFrame::PlaneAllocationSize(VideoFrame::I420,
+ VideoFrame::kYPlane, frame_format.frame_size);
+ const size_t u_plane_size = VideoFrame::PlaneAllocationSize(
+ VideoFrame::I420, VideoFrame::kUPlane, frame_format.frame_size);
+ uint8* const dst_y = reinterpret_cast<uint8*>(buffer->data());
+ uint8* const dst_u = dst_y + y_plane_size;
+ uint8* const dst_v = dst_u + u_plane_size;
+
+ const size_t dst_y_stride = VideoFrame::RowBytes(
+ VideoFrame::kYPlane, VideoFrame::I420, frame_format.frame_size.width());
+ const size_t dst_u_stride = VideoFrame::RowBytes(
+ VideoFrame::kUPlane, VideoFrame::I420, frame_format.frame_size.width());
+ const size_t dst_v_stride = VideoFrame::RowBytes(
+ VideoFrame::kVPlane, VideoFrame::I420, frame_format.frame_size.width());
+ DCHECK_GE(y_stride, dst_y_stride);
+ DCHECK_GE(u_stride, dst_u_stride);
+ DCHECK_GE(v_stride, dst_v_stride);
+
+ if (libyuv::I420Copy(y_data, y_stride,
+ u_data, u_stride,
+ v_data, v_stride,
+ dst_y, dst_y_stride,
+ dst_u, dst_u_stride,
+ dst_v, dst_v_stride,
+ frame_format.frame_size.width(),
+ frame_format.frame_size.height())) {
+ DLOG(WARNING) << "Failed to copy buffer";
+ return;
+ }
+
+ OnIncomingCapturedBuffer(buffer.Pass(), frame_format, timestamp);
+};
+
+scoped_ptr<media::VideoCaptureDevice::Client::Buffer>
+VideoCaptureDeviceClient::ReserveOutputBuffer(media::VideoPixelFormat format,
+ const gfx::Size& dimensions) {
+ DCHECK(format == media::PIXEL_FORMAT_I420 ||
+ format == media::PIXEL_FORMAT_TEXTURE ||
+ format == media::PIXEL_FORMAT_GPUMEMORYBUFFER);
+ DCHECK_GT(dimensions.width(), 0);
+ DCHECK_GT(dimensions.height(), 0);
+
+ if (format == media::PIXEL_FORMAT_GPUMEMORYBUFFER && !texture_wrap_helper_) {
+ texture_wrap_helper_ =
+ new TextureWrapHelper(controller_, capture_task_runner_);
+ }
+
+ int buffer_id_to_drop = VideoCaptureBufferPool::kInvalidId;
+ const int buffer_id =
+ buffer_pool_->ReserveForProducer(format, dimensions, &buffer_id_to_drop);
+ if (buffer_id == VideoCaptureBufferPool::kInvalidId)
+ return NULL;
+
+ scoped_ptr<media::VideoCaptureDevice::Client::Buffer> output_buffer(
+ new AutoReleaseBuffer(buffer_pool_, buffer_id));
+
+ if (buffer_id_to_drop != VideoCaptureBufferPool::kInvalidId) {
+ BrowserThread::PostTask(BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&VideoCaptureController::DoBufferDestroyedOnIOThread,
+ controller_, buffer_id_to_drop));
+ }
+
+ return output_buffer.Pass();
+}
+
+void VideoCaptureDeviceClient::OnIncomingCapturedBuffer(
+ scoped_ptr<Buffer> buffer,
+ const media::VideoCaptureFormat& frame_format,
+ const base::TimeTicks& timestamp) {
+ if (frame_format.pixel_format == media::PIXEL_FORMAT_GPUMEMORYBUFFER) {
+ capture_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureWrapHelper::OnIncomingCapturedGpuMemoryBuffer,
+ texture_wrap_helper_,
+ base::Passed(&buffer),
+ frame_format,
+ timestamp));
+ } else {
+ DCHECK_EQ(frame_format.pixel_format, media::PIXEL_FORMAT_I420);
+ scoped_refptr<VideoFrame> video_frame =
+ VideoFrame::WrapExternalPackedMemory(
+ VideoFrame::I420,
+ frame_format.frame_size,
+ gfx::Rect(frame_format.frame_size),
+ frame_format.frame_size,
+ reinterpret_cast<uint8*>(buffer->data()),
+ VideoFrame::AllocationSize(VideoFrame::I420,
+ frame_format.frame_size),
+ base::SharedMemory::NULLHandle(),
+ 0 /* shared_memory_offset */,
+ base::TimeDelta(),
+ base::Closure());
+ DCHECK(video_frame.get());
+ video_frame->metadata()->SetDouble(media::VideoFrameMetadata::FRAME_RATE,
+ frame_format.frame_rate);
+ OnIncomingCapturedVideoFrame(buffer.Pass(), video_frame, timestamp);
+ }
+}
+
+void VideoCaptureDeviceClient::OnIncomingCapturedVideoFrame(
+ scoped_ptr<Buffer> buffer,
+ const scoped_refptr<VideoFrame>& frame,
+ const base::TimeTicks& timestamp) {
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(
+ &VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread,
+ controller_,
+ base::Passed(&buffer),
+ frame,
+ timestamp));
+}
+
+void VideoCaptureDeviceClient::OnError(
+ const std::string& 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;
+ OnLog(log_message);
+ BrowserThread::PostTask(BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&VideoCaptureController::DoErrorOnIOThread, controller_));
+}
+
+void VideoCaptureDeviceClient::OnLog(
+ const std::string& message) {
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(&VideoCaptureController::DoLogOnIOThread,
+ controller_, message));
+}
+
+VideoCaptureDeviceClient::TextureWrapHelper::TextureWrapHelper(
+ const base::WeakPtr<VideoCaptureController>& controller,
+ const scoped_refptr<base::SingleThreadTaskRunner>& capture_task_runner)
+ : controller_(controller),
+ capture_task_runner_(capture_task_runner) {
+ capture_task_runner_->PostTask(FROM_HERE,
+ base::Bind(&TextureWrapHelper::Init, this));
+}
+
+void
+VideoCaptureDeviceClient::TextureWrapHelper::OnIncomingCapturedGpuMemoryBuffer(
+ scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer,
+ const media::VideoCaptureFormat& frame_format,
+ const base::TimeTicks& timestamp) {
+ DCHECK(capture_task_runner_->BelongsToCurrentThread());
+ DCHECK_EQ(frame_format.pixel_format, media::PIXEL_FORMAT_GPUMEMORYBUFFER);
+ if (!gl_helper_) {
+ // |gl_helper_| might not exist due to asynchronous initialization not
+ // finished or due to termination in process after a context loss.
+ DVLOG(1) << " Skipping ingress frame, no GL context.";
+ return;
+ }
+
+ gpu::gles2::GLES2Interface* gl = capture_thread_context_->ContextGL();
+ GLuint image_id = gl->CreateImageCHROMIUM(buffer->AsClientBuffer(),
+ frame_format.frame_size.width(),
+ frame_format.frame_size.height(),
+ GL_BGRA_EXT);
+ DCHECK(image_id);
+
+ GLuint texture_id = gl_helper_->CreateTexture();
+ DCHECK(texture_id);
+ {
+ content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl, texture_id);
+ gl->BindTexImage2DCHROMIUM(GL_TEXTURE_2D, image_id);
+ }
+
+ const gpu::MailboxHolder& mailbox_holder(
+ gl_helper_->ProduceMailboxHolderFromTexture(texture_id));
+ DCHECK(!mailbox_holder.mailbox.IsZero());
+ DCHECK(mailbox_holder.mailbox.Verify());
+ DCHECK(mailbox_holder.texture_target);
+ DCHECK(mailbox_holder.sync_point);
+
+ scoped_refptr<media::VideoFrame> video_frame =
+ media::VideoFrame::WrapNativeTexture(
+ mailbox_holder,
+ media::BindToCurrentLoop(base::Bind(
+ &VideoCaptureDeviceClient::TextureWrapHelper::ReleaseCallback,
+ this, image_id, texture_id)),
+ frame_format.frame_size, gfx::Rect(frame_format.frame_size),
+ frame_format.frame_size, base::TimeDelta(), true /* allow_overlay */,
+ true /* has_alpha */);
+ video_frame->metadata()->SetDouble(media::VideoFrameMetadata::FRAME_RATE,
+ frame_format.frame_rate);
+
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(
+ &VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread,
+ controller_, base::Passed(&buffer), video_frame, timestamp));
+}
+
+VideoCaptureDeviceClient::TextureWrapHelper::~TextureWrapHelper() {
+ // Might not be running on capture_task_runner_'s thread. Ensure owned objects
+ // are destroyed on the correct threads.
+ if (gl_helper_)
+ capture_task_runner_->DeleteSoon(FROM_HERE, gl_helper_.release());
+
+ if (capture_thread_context_) {
+ capture_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&ResetLostContextCallback, capture_thread_context_));
+ capture_thread_context_->AddRef();
+ ContextProviderCommandBuffer* raw_capture_thread_context =
+ capture_thread_context_.get();
+ capture_thread_context_ = nullptr;
+ capture_task_runner_->ReleaseSoon(FROM_HERE, raw_capture_thread_context);
+ }
+}
+
+void VideoCaptureDeviceClient::TextureWrapHelper::Init() {
+ DCHECK(capture_task_runner_->BelongsToCurrentThread());
+
+ // In threaded compositing mode, we have to create our own context for Capture
+ // to avoid using the GPU command queue from multiple threads. Context
+ // creation must happen on UI thread; then the context needs to be bound to
+ // the appropriate thread, which is done in CreateGlHelper().
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(
+ &CreateContextOnUIThread,
+ media::BindToCurrentLoop(base::Bind(
+ &VideoCaptureDeviceClient::TextureWrapHelper::CreateGlHelper,
+ this))));
+}
+
+void VideoCaptureDeviceClient::TextureWrapHelper::CreateGlHelper(
+ scoped_refptr<ContextProviderCommandBuffer> capture_thread_context) {
+ DCHECK(capture_task_runner_->BelongsToCurrentThread());
+
+ if (!capture_thread_context.get()) {
+ DLOG(ERROR) << "No offscreen GL Context!";
+ return;
+ }
+ // This may not happen in IO Thread. The destructor resets the context lost
+ // callback, so base::Unretained is safe; otherwise it'd be a circular ref
+ // counted dependency.
+ capture_thread_context->SetLostContextCallback(media::BindToCurrentLoop(
+ base::Bind(
+ &VideoCaptureDeviceClient::TextureWrapHelper::LostContextCallback,
+ base::Unretained(this))));
+ if (!capture_thread_context->BindToCurrentThread()) {
+ capture_thread_context = NULL;
+ DLOG(ERROR) << "Couldn't bind the Capture Context to the Capture Thread.";
+ return;
+ }
+ DCHECK(capture_thread_context);
+ capture_thread_context_ = capture_thread_context;
+
+ // At this point, |capture_thread_context| is a cc::ContextProvider. Creation
+ // of our GLHelper should happen on Capture Thread.
+ gl_helper_.reset(new GLHelper(capture_thread_context->ContextGL(),
+ capture_thread_context->ContextSupport()));
+ DCHECK(gl_helper_);
+}
+
+void VideoCaptureDeviceClient::TextureWrapHelper::ReleaseCallback(
+ GLuint image_id,
+ GLuint texture_id,
+ uint32 sync_point) {
+ DCHECK(capture_task_runner_->BelongsToCurrentThread());
+
+ if (gl_helper_) {
+ gl_helper_->DeleteTexture(texture_id);
+ capture_thread_context_->ContextGL()->DestroyImageCHROMIUM(image_id);
+ }
+}
+
+void VideoCaptureDeviceClient::TextureWrapHelper::LostContextCallback() {
+ DCHECK(capture_task_runner_->BelongsToCurrentThread());
+ // Prevent incoming frames from being processed while OnError gets groked.
+ gl_helper_.reset();
+ OnError("GLContext lost");
+}
+
+void VideoCaptureDeviceClient::TextureWrapHelper::OnError(
+ const std::string& message) {
+ DCHECK(capture_task_runner_->BelongsToCurrentThread());
+ DLOG(ERROR) << message;
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&VideoCaptureController::DoErrorOnIOThread, controller_));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/renderer_host/media/video_capture_device_client.h b/chromium/content/browser/renderer_host/media/video_capture_device_client.h
new file mode 100644
index 00000000000..afb69548713
--- /dev/null
+++ b/chromium/content/browser/renderer_host/media/video_capture_device_client.h
@@ -0,0 +1,90 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_DEVICE_CLIENT_H_
+#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_DEVICE_CLIENT_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "content/common/content_export.h"
+#include "media/video/capture/video_capture_device.h"
+
+namespace content {
+class VideoCaptureBufferPool;
+class VideoCaptureController;
+
+// Receives events from the VideoCaptureDevice and posts them to a |controller_|
+// on the IO thread. An instance of this class may safely outlive its target
+// VideoCaptureController. This is a shallow class meant to convert incoming
+// frames and holds no significant state.
+//
+// Methods of this class may be called from any thread, and in practice will
+// often be called on some auxiliary thread depending on the platform and the
+// device type; including, for example, the DirectShow thread on Windows, the
+// v4l2_thread on Linux, and the UI thread for tab capture.
+//
+// It has an internal ref counted TextureWrapHelper class used to wrap incoming
+// GpuMemoryBuffers into Texture backed VideoFrames. This class creates and
+// manages the necessary entities to interact with the GPU process, notably an
+// offscreen Context to avoid janking the UI thread.
+class CONTENT_EXPORT VideoCaptureDeviceClient
+ : public media::VideoCaptureDevice::Client {
+ public:
+ VideoCaptureDeviceClient(
+ const base::WeakPtr<VideoCaptureController>& controller,
+ const scoped_refptr<VideoCaptureBufferPool>& buffer_pool,
+ const scoped_refptr<base::SingleThreadTaskRunner>& capture_task_runner);
+ ~VideoCaptureDeviceClient() override;
+
+ // VideoCaptureDevice::Client implementation.
+ void OnIncomingCapturedData(const uint8* data,
+ int length,
+ const media::VideoCaptureFormat& frame_format,
+ int rotation,
+ const base::TimeTicks& timestamp) override;
+ void OnIncomingCapturedYuvData(const uint8* y_data,
+ const uint8* u_data,
+ const uint8* v_data,
+ size_t y_stride,
+ size_t u_stride,
+ size_t v_stride,
+ const media::VideoCaptureFormat& frame_format,
+ int clockwise_rotation,
+ const base::TimeTicks& timestamp) override;
+ scoped_ptr<Buffer> ReserveOutputBuffer(media::VideoPixelFormat format,
+ const gfx::Size& dimensions) override;
+ void OnIncomingCapturedBuffer(scoped_ptr<Buffer> buffer,
+ const media::VideoCaptureFormat& frame_format,
+ const base::TimeTicks& timestamp) override;
+ void OnIncomingCapturedVideoFrame(
+ scoped_ptr<Buffer> buffer,
+ const scoped_refptr<media::VideoFrame>& frame,
+ const base::TimeTicks& timestamp) override;
+ void OnError(const std::string& reason) override;
+ void OnLog(const std::string& message) override;
+
+ private:
+ // The controller to which we post events.
+ const base::WeakPtr<VideoCaptureController> controller_;
+
+ // The pool of shared-memory buffers used for capturing.
+ const scoped_refptr<VideoCaptureBufferPool> buffer_pool_;
+
+ // Internal delegate for GpuMemoryBuffer-into-VideoFrame wrapping.
+ class TextureWrapHelper;
+ scoped_refptr<TextureWrapHelper> texture_wrap_helper_;
+ // Reference to Capture Thread task runner, where |texture_wrap_helper_|
+ // lives.
+ const scoped_refptr<base::SingleThreadTaskRunner> capture_task_runner_;
+
+ media::VideoPixelFormat last_captured_pixel_format_;
+
+ DISALLOW_COPY_AND_ASSIGN(VideoCaptureDeviceClient);
+};
+
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_DEVICE_CLIENT_H_
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 cc340e3dd80..a546bbd26ab 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_host.cc
+++ b/chromium/content/browser/renderer_host/media/video_capture_host.cc
@@ -5,6 +5,7 @@
#include "content/browser/renderer_host/media/video_capture_host.h"
#include "base/bind.h"
+#include "base/bind_helpers.h"
#include "base/memory/scoped_ptr.h"
#include "content/browser/browser_main_loop.h"
#include "content/browser/renderer_host/media/media_stream_manager.h"
@@ -16,6 +17,7 @@ namespace content {
VideoCaptureHost::VideoCaptureHost(MediaStreamManager* media_stream_manager)
: BrowserMessageFilter(VideoCaptureMsgStart),
media_stream_manager_(media_stream_manager) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
}
VideoCaptureHost::~VideoCaptureHost() {}
@@ -25,14 +27,14 @@ void VideoCaptureHost::OnChannelClosing() {
for (EntryMap::iterator it = entries_.begin(); it != entries_.end(); ) {
const base::WeakPtr<VideoCaptureController>& controller = it->second;
if (controller) {
- VideoCaptureControllerID controller_id(it->first);
+ const VideoCaptureControllerID controller_id(it->first);
media_stream_manager_->video_capture_manager()->StopCaptureForClient(
controller.get(), controller_id, this, false);
++it;
} else {
// Remove the entry for this controller_id so that when the controller
// is added, the controller will be notified to stop for this client
- // in DoControllerAddedOnIOThread.
+ // in DoControllerAdded.
entries_.erase(it++);
}
}
@@ -45,154 +47,107 @@ void VideoCaptureHost::OnDestruct() const {
///////////////////////////////////////////////////////////////////////////////
// Implements VideoCaptureControllerEventHandler.
-void VideoCaptureHost::OnError(const VideoCaptureControllerID& controller_id) {
+void VideoCaptureHost::OnError(VideoCaptureControllerID controller_id) {
DVLOG(1) << "VideoCaptureHost::OnError";
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
- base::Bind(&VideoCaptureHost::DoHandleErrorOnIOThread,
- this, controller_id));
-}
-
-void VideoCaptureHost::OnBufferCreated(
- const VideoCaptureControllerID& controller_id,
- base::SharedMemoryHandle handle,
- int length,
- int buffer_id) {
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&VideoCaptureHost::DoSendNewBufferOnIOThread,
- this, controller_id, handle, length, buffer_id));
-}
-
-void VideoCaptureHost::OnBufferDestroyed(
- const VideoCaptureControllerID& controller_id,
- int buffer_id) {
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&VideoCaptureHost::DoSendFreeBufferOnIOThread,
- this, controller_id, buffer_id));
-}
-
-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,
- FROM_HERE,
- base::Bind(&VideoCaptureHost::DoSendFilledBufferOnIOThread,
- this,
- controller_id,
- buffer_id,
- frame_format,
- visible_rect,
- timestamp));
-}
-
-void VideoCaptureHost::OnMailboxBufferReady(
- const VideoCaptureControllerID& controller_id,
- int buffer_id,
- const gpu::MailboxHolder& mailbox_holder,
- const media::VideoCaptureFormat& frame_format,
- base::TimeTicks timestamp) {
- BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(&VideoCaptureHost::DoSendFilledMailboxBufferOnIOThread,
- this,
- controller_id,
- buffer_id,
- mailbox_holder,
- frame_format,
- timestamp));
-}
-
-void VideoCaptureHost::OnEnded(const VideoCaptureControllerID& controller_id) {
- DVLOG(1) << "VideoCaptureHost::OnEnded";
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&VideoCaptureHost::DoEndedOnIOThread, this, controller_id));
+ base::Bind(&VideoCaptureHost::DoError, this, controller_id));
}
-void VideoCaptureHost::DoSendNewBufferOnIOThread(
- const VideoCaptureControllerID& controller_id,
- base::SharedMemoryHandle handle,
- int length,
- int buffer_id) {
+void VideoCaptureHost::OnBufferCreated(VideoCaptureControllerID controller_id,
+ base::SharedMemoryHandle handle,
+ int length,
+ int buffer_id) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
if (entries_.find(controller_id) == entries_.end())
return;
- Send(new VideoCaptureMsg_NewBuffer(controller_id.device_id, handle,
- length, buffer_id));
+ Send(new VideoCaptureMsg_NewBuffer(controller_id, handle, length, buffer_id));
}
-void VideoCaptureHost::DoSendFreeBufferOnIOThread(
- const VideoCaptureControllerID& controller_id,
- int buffer_id) {
+void VideoCaptureHost::OnBufferDestroyed(VideoCaptureControllerID controller_id,
+ int buffer_id) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
if (entries_.find(controller_id) == entries_.end())
return;
- Send(new VideoCaptureMsg_FreeBuffer(controller_id.device_id, buffer_id));
+ Send(new VideoCaptureMsg_FreeBuffer(controller_id, buffer_id));
}
-void VideoCaptureHost::DoSendFilledBufferOnIOThread(
- const VideoCaptureControllerID& controller_id,
+void VideoCaptureHost::OnBufferReady(
+ VideoCaptureControllerID controller_id,
int buffer_id,
- const media::VideoCaptureFormat& format,
+ const gfx::Size& coded_size,
const gfx::Rect& visible_rect,
- base::TimeTicks timestamp) {
+ const base::TimeTicks& timestamp,
+ scoped_ptr<base::DictionaryValue> metadata) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
if (entries_.find(controller_id) == entries_.end())
return;
- Send(new VideoCaptureMsg_BufferReady(
- controller_id.device_id, buffer_id, format, visible_rect, timestamp));
+ VideoCaptureMsg_BufferReady_Params params;
+ params.device_id = controller_id;
+ params.buffer_id = buffer_id;
+ params.coded_size = coded_size;
+ params.visible_rect = visible_rect;
+ params.timestamp = timestamp;
+ if (metadata)
+ params.metadata.Swap(metadata.get());
+ Send(new VideoCaptureMsg_BufferReady(params));
}
-void VideoCaptureHost::DoSendFilledMailboxBufferOnIOThread(
- const VideoCaptureControllerID& controller_id,
+void VideoCaptureHost::OnMailboxBufferReady(
+ VideoCaptureControllerID controller_id,
int buffer_id,
const gpu::MailboxHolder& mailbox_holder,
- const media::VideoCaptureFormat& format,
- base::TimeTicks timestamp) {
+ const gfx::Size& packed_frame_size,
+ const base::TimeTicks& timestamp,
+ scoped_ptr<base::DictionaryValue> metadata) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (entries_.find(controller_id) == entries_.end())
return;
- Send(new VideoCaptureMsg_MailboxBufferReady(
- controller_id.device_id, buffer_id, mailbox_holder, format, timestamp));
+ VideoCaptureMsg_MailboxBufferReady_Params params;
+ params.device_id = controller_id;
+ params.buffer_id = buffer_id;
+ params.mailbox_holder = mailbox_holder;
+ params.packed_frame_size = packed_frame_size;
+ params.timestamp = timestamp;
+ if (metadata)
+ params.metadata.Swap(metadata.get());
+ Send(new VideoCaptureMsg_MailboxBufferReady(params));
}
-void VideoCaptureHost::DoHandleErrorOnIOThread(
- const VideoCaptureControllerID& controller_id) {
+void VideoCaptureHost::OnEnded(VideoCaptureControllerID controller_id) {
+ DVLOG(1) << "VideoCaptureHost::OnEnded";
DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&VideoCaptureHost::DoEnded, this, controller_id));
+}
+void VideoCaptureHost::DoError(VideoCaptureControllerID controller_id) {
+ DVLOG(1) << "VideoCaptureHost::DoError";
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (entries_.find(controller_id) == entries_.end())
return;
- Send(new VideoCaptureMsg_StateChanged(controller_id.device_id,
+ Send(new VideoCaptureMsg_StateChanged(controller_id,
VIDEO_CAPTURE_STATE_ERROR));
- DeleteVideoCaptureControllerOnIOThread(controller_id, true);
+ DeleteVideoCaptureController(controller_id, true);
}
-void VideoCaptureHost::DoEndedOnIOThread(
- const VideoCaptureControllerID& controller_id) {
+void VideoCaptureHost::DoEnded(VideoCaptureControllerID controller_id) {
+ DVLOG(1) << "VideoCaptureHost::DoEnded";
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DVLOG(1) << "VideoCaptureHost::DoEndedOnIOThread";
if (entries_.find(controller_id) == entries_.end())
return;
- Send(new VideoCaptureMsg_StateChanged(controller_id.device_id,
+ Send(new VideoCaptureMsg_StateChanged(controller_id,
VIDEO_CAPTURE_STATE_ENDED));
- DeleteVideoCaptureControllerOnIOThread(controller_id, false);
+ DeleteVideoCaptureController(controller_id, false);
}
///////////////////////////////////////////////////////////////////////////////
@@ -225,8 +180,11 @@ void VideoCaptureHost::OnStartCapture(int device_id,
<< ", format=" << params.requested_format.ToString()
<< "@" << params.requested_format.frame_rate
<< " (" << (params.resolution_change_policy ==
- media::RESOLUTION_POLICY_DYNAMIC_WITHIN_LIMIT ?
- "variable" : "constant")
+ media::RESOLUTION_POLICY_FIXED_RESOLUTION ?
+ "fixed resolution" :
+ (params.resolution_change_policy ==
+ media::RESOLUTION_POLICY_FIXED_ASPECT_RATIO ?
+ "fixed aspect ratio" : "variable resolution"))
<< ")";
VideoCaptureControllerID controller_id(device_id);
if (entries_.find(controller_id) != entries_.end()) {
@@ -248,18 +206,6 @@ void VideoCaptureHost::OnStartCapture(int device_id,
void VideoCaptureHost::OnControllerAdded(
int device_id,
const base::WeakPtr<VideoCaptureController>& controller) {
- BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(&VideoCaptureHost::DoControllerAddedOnIOThread,
- this,
- device_id,
- controller));
-}
-
-void VideoCaptureHost::DoControllerAddedOnIOThread(
- int device_id,
- const base::WeakPtr<VideoCaptureController>& controller) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
VideoCaptureControllerID controller_id(device_id);
EntryMap::iterator it = entries_.find(controller_id);
@@ -290,7 +236,7 @@ void VideoCaptureHost::OnStopCapture(int device_id) {
Send(new VideoCaptureMsg_StateChanged(device_id,
VIDEO_CAPTURE_STATE_STOPPED));
- DeleteVideoCaptureControllerOnIOThread(controller_id, false);
+ DeleteVideoCaptureController(controller_id, false);
}
void VideoCaptureHost::OnPauseCapture(int device_id) {
@@ -374,8 +320,8 @@ void VideoCaptureHost::OnGetDeviceFormatsInUse(
formats_in_use));
}
-void VideoCaptureHost::DeleteVideoCaptureControllerOnIOThread(
- const VideoCaptureControllerID& controller_id, bool on_error) {
+void VideoCaptureHost::DeleteVideoCaptureController(
+ VideoCaptureControllerID controller_id, bool on_error) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
EntryMap::iterator it = entries_.find(controller_id);
diff --git a/chromium/content/browser/renderer_host/media/video_capture_host.h b/chromium/content/browser/renderer_host/media/video_capture_host.h
index 1fd9813760e..eb845dc62c0 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_host.h
+++ b/chromium/content/browser/renderer_host/media/video_capture_host.h
@@ -33,7 +33,7 @@
// | |
// | ... (resolution change) |
// | < VideoCaptureMsg_FreeBuffer(1) | Buffers are re-allocated
-// | < VideoCaptureMsg_NewBuffer(4) | at a larger size, as
+// | < VideoCaptureMsg_NewBuffer(4) | with a larger size, as
// | < VideoCaptureMsg_BufferReady(4) | needed.
// | VideoCaptureHostMsg_BufferReady(2) > |
// | < VideoCaptureMsg_FreeBuffer(2) |
@@ -57,6 +57,7 @@
#include "base/memory/weak_ptr.h"
#include "base/sequenced_task_runner_helpers.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/common/content_export.h"
#include "content/public/browser/browser_message_filter.h"
#include "ipc/ipc_message.h"
@@ -76,24 +77,27 @@ class CONTENT_EXPORT VideoCaptureHost
bool OnMessageReceived(const IPC::Message& message) override;
// VideoCaptureControllerEventHandler implementation.
- void OnError(const VideoCaptureControllerID& id) override;
- void OnBufferCreated(const VideoCaptureControllerID& id,
+ void OnError(VideoCaptureControllerID id) override;
+ void OnBufferCreated(VideoCaptureControllerID id,
base::SharedMemoryHandle handle,
int length,
int buffer_id) override;
- void OnBufferDestroyed(const VideoCaptureControllerID& id,
+ void OnBufferDestroyed(VideoCaptureControllerID id,
int buffer_id) override;
- void OnBufferReady(const VideoCaptureControllerID& id,
+ void OnBufferReady(VideoCaptureControllerID id,
int buffer_id,
- const media::VideoCaptureFormat& format,
+ const gfx::Size& coded_size,
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;
+ const base::TimeTicks& timestamp,
+ scoped_ptr<base::DictionaryValue> metadata) override;
+ void OnMailboxBufferReady(
+ VideoCaptureControllerID id,
+ int buffer_id,
+ const gpu::MailboxHolder& mailbox_holder,
+ const gfx::Size& packed_frame_size,
+ const base::TimeTicks& timestamp,
+ scoped_ptr<base::DictionaryValue> metadata) override;
+ void OnEnded(VideoCaptureControllerID id) override;
private:
friend class BrowserThread;
@@ -101,10 +105,13 @@ class CONTENT_EXPORT VideoCaptureHost
friend class MockVideoCaptureHost;
friend class VideoCaptureHostTest;
+ void DoError(VideoCaptureControllerID id);
+ void DoEnded(VideoCaptureControllerID id);
+
~VideoCaptureHost() override;
// IPC message: Start capture on the VideoCaptureDevice referenced by
- // |session_id|. |device_id| is an id created by VideoCaptureMessageFilter
+ // |device_id|. |session_id| is an id created by VideoCaptureMessageFilter
// to identify a session between a VideoCaptureMessageFilter and a
// VideoCaptureHost.
void OnStartCapture(int device_id,
@@ -113,9 +120,6 @@ class CONTENT_EXPORT VideoCaptureHost
void OnControllerAdded(
int device_id,
const base::WeakPtr<VideoCaptureController>& controller);
- void DoControllerAddedOnIOThread(
- int device_id,
- const base::WeakPtr<VideoCaptureController>& controller);
// IPC message: Stop capture on device referenced by |device_id|.
void OnStopCapture(int device_id);
@@ -140,51 +144,18 @@ class CONTENT_EXPORT VideoCaptureHost
// IPC message: Get a device's currently in use format(s), referenced by
// |capture_session_id|. |device_id| is needed for message back-routing
// purposes.
- void OnGetDeviceFormatsInUse(
- int device_id,
- media::VideoCaptureSessionId capture_session_id);
-
- // Sends a newly created buffer to the VideoCaptureMessageFilter.
- void DoSendNewBufferOnIOThread(
- const VideoCaptureControllerID& controller_id,
- base::SharedMemoryHandle handle,
- int length,
- int buffer_id);
-
- void DoSendFreeBufferOnIOThread(
- const VideoCaptureControllerID& controller_id,
- int buffer_id);
-
- // Sends a filled buffer to the VideoCaptureMessageFilter.
- void DoSendFilledBufferOnIOThread(
- 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.
- void DoSendFilledMailboxBufferOnIOThread(
- const VideoCaptureControllerID& controller_id,
- int buffer_id,
- const gpu::MailboxHolder& mailbox_holder,
- const media::VideoCaptureFormat& format,
- base::TimeTicks timestamp);
-
- // Handles error coming from VideoCaptureDevice.
- void DoHandleErrorOnIOThread(const VideoCaptureControllerID& controller_id);
-
- void DoEndedOnIOThread(const VideoCaptureControllerID& controller_id);
+ void OnGetDeviceFormatsInUse(int device_id,
+ media::VideoCaptureSessionId capture_session_id);
// Deletes the controller and notifies the VideoCaptureManager. |on_error| is
// true if this is triggered by VideoCaptureControllerEventHandler::OnError.
- void DeleteVideoCaptureControllerOnIOThread(
- const VideoCaptureControllerID& controller_id, bool on_error);
+ void DeleteVideoCaptureController(VideoCaptureControllerID controller_id,
+ bool on_error);
- MediaStreamManager* media_stream_manager_;
+ MediaStreamManager* const media_stream_manager_;
typedef std::map<VideoCaptureControllerID,
- base::WeakPtr<VideoCaptureController> > EntryMap;
+ base::WeakPtr<VideoCaptureController>> EntryMap;
// A map of VideoCaptureControllerID to the VideoCaptureController to which it
// is connected. An entry in this map holds a null controller while it is in
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 6787a385e6e..763ed1f9ca8 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
@@ -28,8 +28,8 @@
#include "content/test/test_content_browser_client.h"
#include "media/audio/audio_manager.h"
#include "media/base/media_switches.h"
+#include "media/base/video_capture_types.h"
#include "media/base/video_frame.h"
-#include "media/video/capture/video_capture_types.h"
#include "net/url_request/url_request_context.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -64,23 +64,27 @@ static const int kDeviceId = 555;
// verifying the output.
class DumpVideo {
public:
- DumpVideo() : expected_size_(0) {}
- void StartDump(int width, int height) {
+ DumpVideo() {}
+ const gfx::Size& coded_size() const { return coded_size_; }
+ void StartDump(const gfx::Size& coded_size) {
base::FilePath file_name = base::FilePath(base::StringPrintf(
- FILE_PATH_LITERAL("dump_w%d_h%d.yuv"), width, height));
+ FILE_PATH_LITERAL("dump_w%d_h%d.yuv"),
+ coded_size.width(),
+ coded_size.height()));
file_.reset(base::OpenFile(file_name, "wb"));
- expected_size_ = media::VideoFrame::AllocationSize(
- media::VideoFrame::I420, gfx::Size(width, height));
+ coded_size_ = coded_size;
}
void NewVideoFrame(const void* buffer) {
if (file_.get() != NULL) {
- ASSERT_EQ(1U, fwrite(buffer, expected_size_, 1, file_.get()));
+ const int size = media::VideoFrame::AllocationSize(
+ media::VideoFrame::I420, coded_size_);
+ ASSERT_EQ(1U, fwrite(buffer, size, 1, file_.get()));
}
}
private:
base::ScopedFILE file_;
- int expected_size_;
+ gfx::Size coded_size_;
};
class MockMediaStreamRequester : public MediaStreamRequester {
@@ -130,18 +134,20 @@ class MockVideoCaptureHost : public VideoCaptureHost {
int buffer_id));
MOCK_METHOD2(OnBufferFreed,
void(int device_id, int buffer_id));
- MOCK_METHOD5(OnBufferFilled,
+ MOCK_METHOD6(OnBufferFilled,
void(int device_id,
int buffer_id,
- const media::VideoCaptureFormat& format,
+ const gfx::Size& coded_size,
const gfx::Rect& visible_rect,
- base::TimeTicks timestamp));
- MOCK_METHOD5(OnMailboxBufferFilled,
+ const base::TimeTicks& timestamp,
+ const base::DictionaryValue& metadata));
+ MOCK_METHOD6(OnMailboxBufferFilled,
void(int device_id,
int buffer_id,
const gpu::MailboxHolder& mailbox_holder,
- const media::VideoCaptureFormat& format,
- base::TimeTicks timestamp));
+ const gfx::Size& packed_frame_size,
+ const base::TimeTicks& timestamp,
+ const base::DictionaryValue& metadata));
MOCK_METHOD2(OnStateChanged, void(int device_id, VideoCaptureState state));
// Use class DumpVideo to write I420 video to file.
@@ -174,7 +180,7 @@ class MockVideoCaptureHost : public VideoCaptureHost {
}
private:
- virtual ~MockVideoCaptureHost() {
+ ~MockVideoCaptureHost() override {
STLDeleteContainerPairSecondPointers(filled_dib_.begin(),
filled_dib_.end());
}
@@ -182,7 +188,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 {
+ bool Send(IPC::Message* message) override {
CHECK(message);
// In this method we dispatch the messages to the according handlers as if
@@ -224,41 +230,34 @@ class MockVideoCaptureHost : public VideoCaptureHost {
filled_dib_.erase(it);
}
- 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];
+ void OnBufferFilledDispatch(
+ const VideoCaptureMsg_BufferReady_Params& params) {
+ base::SharedMemory* dib = filled_dib_[params.buffer_id];
ASSERT_TRUE(dib != NULL);
if (dump_video_) {
- if (!format_.IsValid()) {
- dumper_.StartDump(frame_format.frame_size.width(),
- frame_format.frame_size.height());
- format_ = frame_format;
- }
- ASSERT_EQ(format_.frame_size.width(), frame_format.frame_size.width())
- << "Dump format does not handle variable resolution.";
- ASSERT_EQ(format_.frame_size.height(), frame_format.frame_size.height())
+ if (dumper_.coded_size().IsEmpty())
+ dumper_.StartDump(params.coded_size);
+ ASSERT_TRUE(dumper_.coded_size() == params.coded_size)
<< "Dump format does not handle variable resolution.";
dumper_.NewVideoFrame(dib->memory());
}
- OnBufferFilled(device_id, buffer_id, frame_format, visible_rect, timestamp);
+ OnBufferFilled(params.device_id, params.buffer_id, params.coded_size,
+ params.visible_rect, params.timestamp, params.metadata);
if (return_buffers_) {
- VideoCaptureHost::OnReceiveEmptyBuffer(device_id, buffer_id, 0);
+ VideoCaptureHost::OnReceiveEmptyBuffer(
+ params.device_id, params.buffer_id, 0);
}
}
- void OnMailboxBufferFilledDispatch(int device_id,
- int buffer_id,
- const gpu::MailboxHolder& mailbox_holder,
- const media::VideoCaptureFormat& format,
- base::TimeTicks timestamp) {
- OnMailboxBufferFilled(
- device_id, buffer_id, mailbox_holder, format, timestamp);
+ void OnMailboxBufferFilledDispatch(
+ const VideoCaptureMsg_MailboxBufferReady_Params& params) {
+ OnMailboxBufferFilled(params.device_id, params.buffer_id,
+ params.mailbox_holder, params.packed_frame_size,
+ params.timestamp, params.metadata);
if (return_buffers_) {
- VideoCaptureHost::OnReceiveEmptyBuffer(device_id, buffer_id, 0);
+ VideoCaptureHost::OnReceiveEmptyBuffer(
+ params.device_id, params.buffer_id, 0);
}
}
@@ -287,7 +286,7 @@ class VideoCaptureHostTest : public testing::Test {
message_loop_(base::MessageLoopProxy::current()),
opened_session_id_(kInvalidMediaCaptureSessionId) {}
- virtual void SetUp() override {
+ void SetUp() override {
SetBrowserClientForTesting(&browser_client_);
#if defined(OS_CHROMEOS)
@@ -310,7 +309,7 @@ class VideoCaptureHostTest : public testing::Test {
OpenSession();
}
- virtual void TearDown() override {
+ void TearDown() override {
// Verifies and removes the expectations on host_ and
// returns true iff successful.
Mock::VerifyAndClearExpectations(host_.get());
@@ -407,7 +406,7 @@ class VideoCaptureHostTest : public testing::Test {
.WillRepeatedly(Return());
base::RunLoop run_loop;
- EXPECT_CALL(*host_.get(), OnBufferFilled(kDeviceId, _, _, _, _))
+ EXPECT_CALL(*host_.get(), OnBufferFilled(kDeviceId, _, _, _, _, _))
.Times(AnyNumber())
.WillOnce(ExitMessageLoop(message_loop_, run_loop.QuitClosure()));
@@ -431,6 +430,7 @@ class VideoCaptureHostTest : public testing::Test {
host_->OnStartCapture(kDeviceId, opened_session_id_, params);
host_->OnStopCapture(kDeviceId);
run_loop.RunUntilIdle();
+ WaitForVideoDeviceThread();
}
#ifdef DUMP_VIDEO
@@ -440,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()));
@@ -472,7 +472,7 @@ class VideoCaptureHostTest : public testing::Test {
void NotifyPacketReady() {
base::RunLoop run_loop;
- EXPECT_CALL(*host_.get(), OnBufferFilled(kDeviceId, _, _, _, _))
+ EXPECT_CALL(*host_.get(), OnBufferFilled(kDeviceId, _, _, _, _, _))
.Times(AnyNumber())
.WillOnce(ExitMessageLoop(message_loop_, run_loop.QuitClosure()))
.RetiresOnSaturation();
@@ -493,6 +493,16 @@ class VideoCaptureHostTest : public testing::Test {
base::RunLoop().RunUntilIdle();
}
+ void WaitForVideoDeviceThread() {
+ base::RunLoop run_loop;
+ media_stream_manager_->video_capture_manager()->device_task_runner()
+ ->PostTaskAndReply(
+ FROM_HERE,
+ base::Bind(&base::DoNothing),
+ run_loop.QuitClosure());
+ run_loop.Run();
+ }
+
scoped_refptr<MockVideoCaptureHost> host_;
private:
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 617a8696dee..a213a564bab 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_manager.cc
+++ b/chromium/content/browser/renderer_host/media/video_capture_manager.cc
@@ -4,12 +4,14 @@
#include "content/browser/renderer_host/media/video_capture_manager.h"
+#include <algorithm>
#include <set>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
+#include "base/metrics/histogram_macros.h"
#include "base/stl_util.h"
#include "base/task_runner_util.h"
#include "base/threading/sequenced_worker_pool.h"
@@ -19,10 +21,8 @@
#include "content/browser/renderer_host/media/video_capture_controller_event_handler.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/desktop_media_id.h"
-#include "content/public/common/content_switches.h"
#include "content/public/common/media_stream_request.h"
#include "media/base/bind_to_current_loop.h"
-#include "media/base/scoped_histogram_timer.h"
#include "media/video/capture/video_capture_device.h"
#include "media/video/capture/video_capture_device_factory.h"
@@ -71,7 +71,7 @@ void ConsolidateCaptureFormats(media::VideoCaptureFormats* formats) {
}
}
-// The maximum number of buffers in the capture pipeline. See
+// The maximum number of buffers in the capture pipeline. See
// VideoCaptureController ctor comments for more details.
const int kMaxNumberOfBuffers = 3;
const int kMaxNumberOfBuffersForTabCapture = 5;
@@ -94,6 +94,9 @@ void LogVideoCaptureEvent(VideoCaptureEvent event) {
NUM_VIDEO_CAPTURE_EVENT);
}
+// Counter used for identifying a DeviceRequest to start a capture device.
+static int g_device_start_id = 0;
+
} // namespace
namespace content {
@@ -102,12 +105,52 @@ VideoCaptureManager::DeviceEntry::DeviceEntry(
MediaStreamType stream_type,
const std::string& id,
scoped_ptr<VideoCaptureController> controller)
- : stream_type(stream_type),
+ : serial_id(g_device_start_id++),
+ stream_type(stream_type),
id(id),
- video_capture_controller(controller.Pass()) {}
+ video_capture_controller_(controller.Pass()) {}
+
+VideoCaptureManager::DeviceEntry::~DeviceEntry() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ // DCHECK that this DeviceEntry does not still own a
+ // media::VideoCaptureDevice. media::VideoCaptureDevice must be deleted on
+ // the device thread.
+ DCHECK(video_capture_device_ == nullptr);
+}
+
+void VideoCaptureManager::DeviceEntry::SetVideoCaptureDevice(
+ scoped_ptr<media::VideoCaptureDevice> device) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ video_capture_device_.swap(device);
+}
-VideoCaptureManager::DeviceEntry::~DeviceEntry() {}
+scoped_ptr<media::VideoCaptureDevice>
+VideoCaptureManager::DeviceEntry::ReleaseVideoCaptureDevice() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return video_capture_device_.Pass();
+}
+
+VideoCaptureController*
+VideoCaptureManager::DeviceEntry::video_capture_controller() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return video_capture_controller_.get();
+}
+
+media::VideoCaptureDevice*
+VideoCaptureManager::DeviceEntry::video_capture_device() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return video_capture_device_.get();
+}
+VideoCaptureManager::CaptureDeviceStartRequest::CaptureDeviceStartRequest(
+ int serial_id,
+ media::VideoCaptureSessionId session_id,
+ const media::VideoCaptureParams& params)
+ : serial_id_(serial_id),
+ session_id_(session_id),
+ params_(params),
+ abort_start_(false) {
+}
VideoCaptureManager::VideoCaptureManager(
scoped_ptr<media::VideoCaptureDeviceFactory> factory)
@@ -118,6 +161,7 @@ VideoCaptureManager::VideoCaptureManager(
VideoCaptureManager::~VideoCaptureManager() {
DCHECK(devices_.empty());
+ DCHECK(device_start_queue_.empty());
}
void VideoCaptureManager::Register(
@@ -202,7 +246,8 @@ void VideoCaptureManager::Close(int capture_session_id) {
if (existing_device) {
// Remove any client that is still using the session. This is safe to call
// even if there are no clients using the session.
- existing_device->video_capture_controller->StopSession(capture_session_id);
+ existing_device->video_capture_controller()
+ ->StopSession(capture_session_id);
// StopSession() may have removed the last client, so we might need to
// close the device.
@@ -216,22 +261,140 @@ void VideoCaptureManager::Close(int capture_session_id) {
sessions_.erase(session_it);
}
-void VideoCaptureManager::DoStartDeviceOnDeviceThread(
+void VideoCaptureManager::QueueStartDevice(
media::VideoCaptureSessionId session_id,
DeviceEntry* entry,
+ const media::VideoCaptureParams& params) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ device_start_queue_.push_back(
+ CaptureDeviceStartRequest(entry->serial_id, session_id, params));
+ if (device_start_queue_.size() == 1)
+ HandleQueuedStartRequest();
+}
+
+void VideoCaptureManager::DoStopDevice(DeviceEntry* entry) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(std::find(devices_.begin(), devices_.end(), entry) != devices_.end());
+
+ // Find the matching start request.
+ for (DeviceStartQueue::reverse_iterator request =
+ device_start_queue_.rbegin();
+ request != device_start_queue_.rend(); ++request) {
+ if (request->serial_id() == entry->serial_id) {
+ request->set_abort_start();
+ DVLOG(3) << "DoStopDevice, aborting start request for device "
+ << entry->id << " serial_id = " << entry->serial_id;
+ return;
+ }
+ }
+
+ DVLOG(3) << "DoStopDevice. Send stop request for device = " << entry->id
+ << " serial_id = " << entry->serial_id << ".";
+ if (entry->video_capture_device()) {
+ // |entry->video_capture_device| can be null if creating the device fails.
+ device_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&VideoCaptureManager::DoStopDeviceOnDeviceThread, this,
+ base::Passed(entry->ReleaseVideoCaptureDevice())));
+ }
+}
+
+void VideoCaptureManager::HandleQueuedStartRequest() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ // Remove all start requests that have been aborted.
+ while (device_start_queue_.begin() != device_start_queue_.end() &&
+ device_start_queue_.begin()->abort_start()) {
+ device_start_queue_.pop_front();
+ }
+ DeviceStartQueue::iterator request = device_start_queue_.begin();
+ if (request == device_start_queue_.end())
+ return;
+
+ const int serial_id = request->serial_id();
+ DeviceEntries::iterator entry_it = std::find_if(
+ devices_.begin(), devices_.end(),
+ [serial_id] (const DeviceEntry* e) {
+ return e->serial_id == serial_id;
+ });
+ DCHECK(entry_it != devices_.end());
+ DeviceEntry* entry = (*entry_it);
+
+ DVLOG(3) << "HandleQueuedStartRequest, Post start to device thread, device = "
+ << entry->id << " start id = " << entry->serial_id;
+ base::PostTaskAndReplyWithResult(
+ device_task_runner_.get(),
+ FROM_HERE,
+ base::Bind(
+ &VideoCaptureManager::DoStartDeviceOnDeviceThread,
+ this,
+ request->session_id(),
+ entry->id,
+ entry->stream_type,
+ request->params(),
+ base::Passed(entry->video_capture_controller()->NewDeviceClient(
+ device_task_runner_))),
+ base::Bind(&VideoCaptureManager::OnDeviceStarted, this,
+ request->serial_id()));
+}
+
+void VideoCaptureManager::OnDeviceStarted(
+ int serial_id,
+ scoped_ptr<media::VideoCaptureDevice> device) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(serial_id == device_start_queue_.begin()->serial_id());
+ DVLOG(3) << "OnDeviceStarted";
+ if (device_start_queue_.front().abort_start()) {
+ // |device| can be null if creation failed in DoStartDeviceOnDeviceThread.
+ // The device is no longer wanted. Stop the device again.
+ DVLOG(3) << "OnDeviceStarted but start request have been aborted.";
+ media::VideoCaptureDevice* device_ptr = device.get();
+ base::Closure closure =
+ base::Bind(&VideoCaptureManager::DoStopDeviceOnDeviceThread, this,
+ base::Passed(&device));
+ if (device_ptr && !device_task_runner_->PostTask(FROM_HERE, closure)) {
+ // PostTask failed. The device must be stopped anyway.
+ device_ptr->StopAndDeAllocate();
+ }
+ } else {
+ DeviceEntries::iterator entry_it = std::find_if(
+ devices_.begin(), devices_.end(),
+ [serial_id] (const DeviceEntry* e) {
+ return e->serial_id == serial_id;
+ });
+ DCHECK(entry_it != devices_.end());
+ DeviceEntry* entry = *entry_it;
+ DCHECK(!entry->video_capture_device());
+ entry->SetVideoCaptureDevice(device.Pass());
+
+ if (entry->stream_type == MEDIA_DESKTOP_VIDEO_CAPTURE) {
+ const media::VideoCaptureSessionId session_id =
+ device_start_queue_.front().session_id();
+ MaybePostDesktopCaptureWindowId(session_id);
+ }
+ }
+
+ device_start_queue_.pop_front();
+ HandleQueuedStartRequest();
+}
+
+scoped_ptr<media::VideoCaptureDevice>
+VideoCaptureManager::DoStartDeviceOnDeviceThread(
+ media::VideoCaptureSessionId session_id,
+ const std::string& id,
+ MediaStreamType stream_type,
const media::VideoCaptureParams& params,
scoped_ptr<media::VideoCaptureDevice::Client> device_client) {
SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StartDeviceTime");
DCHECK(IsOnDeviceThread());
scoped_ptr<media::VideoCaptureDevice> video_capture_device;
- switch (entry->stream_type) {
+ switch (stream_type) {
case MEDIA_DEVICE_VIDEO_CAPTURE: {
// 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.
- media::VideoCaptureDeviceInfo* found =
- FindDeviceInfoById(entry->id, devices_info_cache_);
+ const media::VideoCaptureDeviceInfo* found =
+ FindDeviceInfoById(id, devices_info_cache_);
if (found) {
video_capture_device =
video_capture_device_factory_->Create(found->name);
@@ -240,27 +403,21 @@ void VideoCaptureManager::DoStartDeviceOnDeviceThread(
}
case MEDIA_TAB_VIDEO_CAPTURE: {
video_capture_device.reset(
- WebContentsVideoCaptureDevice::Create(entry->id));
+ WebContentsVideoCaptureDevice::Create(id));
break;
}
case MEDIA_DESKTOP_VIDEO_CAPTURE: {
#if defined(ENABLE_SCREEN_CAPTURE)
- DesktopMediaID id = DesktopMediaID::Parse(entry->id);
+ DesktopMediaID desktop_id = DesktopMediaID::Parse(id);
#if defined(USE_AURA)
- if (id.type == DesktopMediaID::TYPE_AURA_WINDOW) {
- video_capture_device.reset(DesktopCaptureDeviceAura::Create(id));
+ if (desktop_id.type == DesktopMediaID::TYPE_AURA_WINDOW) {
+ video_capture_device.reset(
+ DesktopCaptureDeviceAura::Create(desktop_id));
} else
#endif
- if (id.type != DesktopMediaID::TYPE_NONE &&
- id.type != DesktopMediaID::TYPE_AURA_WINDOW) {
- video_capture_device = DesktopCaptureDevice::Create(id);
- if (notification_window_ids_.find(session_id) !=
- 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;
- }
+ if (desktop_id.type != DesktopMediaID::TYPE_NONE &&
+ desktop_id.type != DesktopMediaID::TYPE_AURA_WINDOW) {
+ video_capture_device = DesktopCaptureDevice::Create(desktop_id);
}
#endif // defined(ENABLE_SCREEN_CAPTURE)
break;
@@ -273,11 +430,11 @@ void VideoCaptureManager::DoStartDeviceOnDeviceThread(
if (!video_capture_device) {
device_client->OnError("Could not create capture device");
- return;
+ return nullptr;
}
video_capture_device->AllocateAndStart(params, device_client.Pass());
- entry->video_capture_device = video_capture_device.Pass();
+ return video_capture_device.Pass();
}
void VideoCaptureManager::StartCaptureForClient(
@@ -298,28 +455,19 @@ void VideoCaptureManager::StartCaptureForClient(
return;
}
- DCHECK(entry->video_capture_controller);
+ DCHECK(entry->video_capture_controller());
LogVideoCaptureEvent(VIDEO_CAPTURE_START_CAPTURE);
// First client starts the device.
- if (entry->video_capture_controller->GetActiveClientCount() == 0) {
+ if (entry->video_capture_controller()->GetActiveClientCount() == 0) {
DVLOG(1) << "VideoCaptureManager starting device (type = "
<< entry->stream_type << ", id = " << entry->id << ")";
-
- device_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(
- &VideoCaptureManager::DoStartDeviceOnDeviceThread,
- this,
- session_id,
- entry,
- params,
- base::Passed(entry->video_capture_controller->NewDeviceClient())));
+ QueueStartDevice(session_id, entry, params);
}
// Run the callback first, as AddClient() may trigger OnFrameInfo().
- done_cb.Run(entry->video_capture_controller->GetWeakPtr());
- entry->video_capture_controller->AddClient(
+ done_cb.Run(entry->video_capture_controller()->GetWeakPtrForIOThread());
+ entry->video_capture_controller()->AddClient(
client_id, client_handler, client_render_process, session_id, params);
}
@@ -392,10 +540,7 @@ void VideoCaptureManager::PauseCaptureForClient(
return;
// There is no more client, release the camera.
- device_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&VideoCaptureManager::DoStopDeviceOnDeviceThread, this,
- base::Unretained(entry)));
+ DoStopDevice(entry);
}
void VideoCaptureManager::ResumeCaptureForClient(
@@ -423,15 +568,7 @@ void VideoCaptureManager::ResumeCaptureForClient(
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())));
+ QueueStartDevice(session_id, entry, params);
}
bool VideoCaptureManager::GetDeviceSupportedFormats(
@@ -470,7 +607,7 @@ bool VideoCaptureManager::GetDeviceFormatsInUse(
if (device_in_use) {
// Currently only one format-in-use is supported at the VCC level.
formats_in_use->push_back(
- device_in_use->video_capture_controller->GetVideoCaptureFormat());
+ device_in_use->video_capture_controller()->GetVideoCaptureFormat());
}
return true;
}
@@ -481,23 +618,26 @@ void VideoCaptureManager::SetDesktopCaptureWindowId(
DCHECK_CURRENTLY_ON(BrowserThread::IO);
VLOG(2) << "SetDesktopCaptureWindowId called for session " << session_id;
+ notification_window_ids_[session_id] = window_id;
+ MaybePostDesktopCaptureWindowId(session_id);
+}
+
+void VideoCaptureManager::MaybePostDesktopCaptureWindowId(
+ media::VideoCaptureSessionId 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(
- &VideoCaptureManager::SaveDesktopCaptureWindowIdOnDeviceThread,
- this,
- session_id,
- window_id));
return;
}
DeviceEntry* const existing_device =
GetDeviceEntryForMediaStreamDevice(session_it->second);
if (!existing_device) {
- VLOG(2) << "Failed to find an existing device.";
+ DVLOG(2) << "Failed to find an existing screen capture device.";
+ return;
+ }
+
+ if (!existing_device->video_capture_device()) {
+ DVLOG(2) << "Screen capture device not yet started.";
return;
}
@@ -509,21 +649,31 @@ void VideoCaptureManager::SetDesktopCaptureWindowId(
return;
}
+ auto window_id_it = notification_window_ids_.find(session_id);
+ if (window_id_it == notification_window_ids_.end()) {
+ DVLOG(2) << "Notification window id not set for screen capture.";
+ return;
+ }
+
+ // Post |existing_device->video_capture_device| to the VideoCaptureDevice to
+ // the device_task_runner_. This is safe since the device is destroyed on the
+ // device_task_runner_.
device_task_runner_->PostTask(
FROM_HERE,
base::Bind(&VideoCaptureManager::SetDesktopCaptureWindowIdOnDeviceThread,
this,
- existing_device,
- window_id));
+ existing_device->video_capture_device(),
+ window_id_it->second));
+
+ notification_window_ids_.erase(window_id_it);
}
-void VideoCaptureManager::DoStopDeviceOnDeviceThread(DeviceEntry* entry) {
+void VideoCaptureManager::DoStopDeviceOnDeviceThread(
+ scoped_ptr<media::VideoCaptureDevice> device) {
SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StopDeviceTime");
DCHECK(IsOnDeviceThread());
- if (entry->video_capture_device) {
- entry->video_capture_device->StopAndDeAllocate();
- }
- entry->video_capture_device.reset();
+ device->StopAndDeAllocate();
+ DVLOG(3) << "DoStopDeviceOnDeviceThread";
}
void VideoCaptureManager::OnOpened(
@@ -635,7 +785,7 @@ VideoCaptureManager::GetDeviceEntryForController(
// Look up |controller| in |devices_|.
for (DeviceEntries::const_iterator it = devices_.begin();
it != devices_.end(); ++it) {
- if ((*it)->video_capture_controller.get() == controller) {
+ if ((*it)->video_capture_controller() == controller) {
return *it;
}
}
@@ -645,7 +795,7 @@ VideoCaptureManager::GetDeviceEntryForController(
void VideoCaptureManager::DestroyDeviceEntryIfNoClients(DeviceEntry* entry) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
// Removal of the last client stops the device.
- if (entry->video_capture_controller->GetClientCount() == 0) {
+ if (entry->video_capture_controller()->GetClientCount() == 0) {
DVLOG(1) << "VideoCaptureManager stopping device (type = "
<< entry->stream_type << ", id = " << entry->id << ")";
@@ -653,12 +803,11 @@ void VideoCaptureManager::DestroyDeviceEntryIfNoClients(DeviceEntry* entry) {
// deleted immediately, and the device is freed asynchronously. After this
// point, subsequent requests to open this same device ID will create a new
// DeviceEntry, VideoCaptureController, and VideoCaptureDevice.
- devices_.erase(entry);
- entry->video_capture_controller.reset();
- device_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&VideoCaptureManager::DoStopDeviceOnDeviceThread, this,
- base::Owned(entry)));
+ DoStopDevice(entry);
+ DeviceEntries::iterator device_it = std::find(devices_.begin(),
+ devices_.end(),
+ entry);
+ devices_.erase(device_it);
}
}
@@ -688,7 +837,7 @@ VideoCaptureManager::DeviceEntry* VideoCaptureManager::GetOrCreateDeviceEntry(
DeviceEntry* new_device = new DeviceEntry(device_info.type,
device_info.id,
video_capture_controller.Pass());
- devices_.insert(new_device);
+ devices_.push_back(new_device);
return new_device;
}
@@ -703,27 +852,15 @@ media::VideoCaptureDeviceInfo* VideoCaptureManager::FindDeviceInfoById(
}
void VideoCaptureManager::SetDesktopCaptureWindowIdOnDeviceThread(
- DeviceEntry* entry,
+ media::VideoCaptureDevice* device,
gfx::NativeViewId window_id) {
DCHECK(IsOnDeviceThread());
- DCHECK(entry->stream_type == MEDIA_DESKTOP_VIDEO_CAPTURE);
#if defined(ENABLE_SCREEN_CAPTURE)
- DesktopCaptureDevice* device =
- static_cast<DesktopCaptureDevice*>(entry->video_capture_device.get());
- device->SetNotificationWindowId(window_id);
+ DesktopCaptureDevice* desktop_device =
+ static_cast<DesktopCaptureDevice*>(device);
+ desktop_device->SetNotificationWindowId(window_id);
VLOG(2) << "Screen capture notification window passed on device thread.";
#endif
}
-void VideoCaptureManager::SaveDesktopCaptureWindowIdOnDeviceThread(
- media::VideoCaptureSessionId session_id,
- gfx::NativeViewId window_id) {
- DCHECK(IsOnDeviceThread());
- 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 544fb86472f..3b0b4667682 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_manager.h
+++ b/chromium/content/browser/renderer_host/media/video_capture_manager.h
@@ -12,23 +12,26 @@
#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_MANAGER_H_
#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_MANAGER_H_
+#include <list>
#include <map>
#include <set>
#include <string>
#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_vector.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/process/process_handle.h"
+#include "base/threading/thread_checker.h"
#include "base/timer/elapsed_timer.h"
#include "content/browser/renderer_host/media/media_stream_provider.h"
#include "content/browser/renderer_host/media/video_capture_controller_event_handler.h"
#include "content/common/content_export.h"
#include "content/common/media/media_stream_options.h"
+#include "media/base/video_capture_types.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 {
class VideoCaptureController;
@@ -44,13 +47,13 @@ class CONTENT_EXPORT VideoCaptureManager : public MediaStreamProvider {
explicit VideoCaptureManager(
scoped_ptr<media::VideoCaptureDeviceFactory> factory);
+ void Unregister();
+
// Implements MediaStreamProvider.
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;
@@ -138,9 +141,14 @@ class CONTENT_EXPORT VideoCaptureManager : public MediaStreamProvider {
}
#endif
+ // Returns the SingleThreadTaskRunner where devices are enumerated on and
+ // started.
+ scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner() {
+ return device_task_runner_;
+ }
private:
~VideoCaptureManager() override;
- struct DeviceEntry;
+ class DeviceEntry;
// 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|
@@ -182,28 +190,42 @@ class CONTENT_EXPORT VideoCaptureManager : public MediaStreamProvider {
const media::VideoCaptureDeviceInfos& old_device_info_cache,
scoped_ptr<media::VideoCaptureDevice::Names> names_snapshot);
- // Creates and Starts a new VideoCaptureDevice, storing the result in
- // |entry->video_capture_device|. Ownership of |client| passes to
+ // Starting a capture device can take 1-2 seconds.
+ // To avoid multiple unnecessary start/stop commands to the OS, each start
+ // request is queued in |device_start_queue_|.
+ // QueueStartDevice creates a new entry in |device_start_queue_| and posts a
+ // request to start the device on the device thread unless there is
+ // another request pending start.
+ void QueueStartDevice(media::VideoCaptureSessionId session_id,
+ DeviceEntry* entry,
+ const media::VideoCaptureParams& params);
+ void OnDeviceStarted(int serial_id,
+ scoped_ptr<media::VideoCaptureDevice> device);
+ void DoStopDevice(DeviceEntry* entry);
+ void HandleQueuedStartRequest();
+
+ // Creates and Starts a new VideoCaptureDevice. The resulting
+ // VideoCaptureDevice is returned to the IO-thread and stored in
+ // a DeviceEntry in |devices_|. Ownership of |client| passes to
// the device.
- void DoStartDeviceOnDeviceThread(
+ scoped_ptr<media::VideoCaptureDevice> DoStartDeviceOnDeviceThread(
media::VideoCaptureSessionId session_id,
- DeviceEntry* entry,
+ const std::string& device_id,
+ MediaStreamType stream_type,
const media::VideoCaptureParams& params,
scoped_ptr<media::VideoCaptureDevice::Client> client);
// Stops and destroys the VideoCaptureDevice held in
- // |entry->video_capture_device|.
- void DoStopDeviceOnDeviceThread(DeviceEntry* entry);
+ // |device|.
+ void DoStopDeviceOnDeviceThread(scoped_ptr<media::VideoCaptureDevice> device);
media::VideoCaptureDeviceInfo* FindDeviceInfoById(
const std::string& id,
media::VideoCaptureDeviceInfos& device_vector);
- void SetDesktopCaptureWindowIdOnDeviceThread(DeviceEntry* entry,
- gfx::NativeViewId window_id);
-
- void SaveDesktopCaptureWindowIdOnDeviceThread(
- media::VideoCaptureSessionId session_id,
+ void MaybePostDesktopCaptureWindowId(media::VideoCaptureSessionId session_id);
+ void SetDesktopCaptureWindowIdOnDeviceThread(
+ media::VideoCaptureDevice* device,
gfx::NativeViewId window_id);
// The message loop of media stream device thread, where VCD's live.
@@ -226,27 +248,66 @@ class CONTENT_EXPORT VideoCaptureManager : public MediaStreamProvider {
// when they are not used any longer.
//
// The set of currently started VideoCaptureDevice and VideoCaptureController
- // objects is only accessed from IO thread, though the DeviceEntry instances
- // themselves may visit to the device thread for device creation and
- // destruction.
- struct DeviceEntry {
+ // objects is only accessed from IO thread.
+ class DeviceEntry {
+ public:
DeviceEntry(MediaStreamType stream_type,
const std::string& id,
scoped_ptr<VideoCaptureController> controller);
~DeviceEntry();
+ const int serial_id;
const MediaStreamType stream_type;
const std::string id;
- // The controller. Only used from the IO thread.
- scoped_ptr<VideoCaptureController> video_capture_controller;
+ VideoCaptureController* video_capture_controller();
+ media::VideoCaptureDevice* video_capture_device();
+
+ void SetVideoCaptureDevice(scoped_ptr<media::VideoCaptureDevice> device);
+ scoped_ptr<media::VideoCaptureDevice> ReleaseVideoCaptureDevice();
- // The capture device. Only used from the device thread.
- scoped_ptr<media::VideoCaptureDevice> video_capture_device;
+ private:
+ // The controller.
+ scoped_ptr<VideoCaptureController> video_capture_controller_;
+
+ // The capture device.
+ scoped_ptr<media::VideoCaptureDevice> video_capture_device_;
+
+ base::ThreadChecker thread_checker_;
};
- typedef std::set<DeviceEntry*> DeviceEntries;
+
+ typedef ScopedVector<DeviceEntry> DeviceEntries;
+ // Currently opened devices. The device may or may not be started.
DeviceEntries devices_;
+ // Class used for queuing request for starting a device.
+ class CaptureDeviceStartRequest {
+ public:
+ CaptureDeviceStartRequest(
+ int serial_id,
+ media::VideoCaptureSessionId session_id,
+ const media::VideoCaptureParams& params);
+ int serial_id() const { return serial_id_;}
+ media::VideoCaptureSessionId session_id() const { return session_id_; }
+ media::VideoCaptureParams params() const { return params_; }
+
+ // Set to true if the device should be stopped before it has successfully
+ // been started.
+ bool abort_start() const { return abort_start_; }
+ void set_abort_start() { abort_start_ = true; }
+
+ private:
+ const int serial_id_;
+ const media::VideoCaptureSessionId session_id_;
+ const media::VideoCaptureParams params_;
+ // Set to true if the device should be stopped before it has successfully
+ // been started.
+ bool abort_start_;
+ };
+
+ typedef std::list<CaptureDeviceStartRequest> DeviceStartQueue;
+ DeviceStartQueue device_start_queue_;
+
// Device creation factory injected on construction from MediaStreamManager or
// from the test harness.
scoped_ptr<media::VideoCaptureDeviceFactory> video_capture_device_factory_;
@@ -260,7 +321,7 @@ class CONTENT_EXPORT VideoCaptureManager : public MediaStreamProvider {
// active device capture format from the VideoCaptureController associated.
media::VideoCaptureDeviceInfos devices_info_cache_;
- // Accessed on the device thread only.
+ // Map used by DesktopCapture.
std::map<media::VideoCaptureSessionId, gfx::NativeViewId>
notification_window_ids_;
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 e42601ae44b..a8e45add526 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
@@ -44,24 +44,27 @@ class MockMediaStreamProviderListener : public MediaStreamProviderListener {
// Needed as an input argument to StartCaptureForClient().
class MockFrameObserver : public VideoCaptureControllerEventHandler {
public:
- MOCK_METHOD1(OnError, void(const VideoCaptureControllerID& id));
-
- 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,
- 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 {}
+ MOCK_METHOD1(OnError, void(VideoCaptureControllerID id));
+
+ void OnBufferCreated(VideoCaptureControllerID id,
+ base::SharedMemoryHandle handle,
+ int length, int buffer_id) override {}
+ void OnBufferDestroyed(VideoCaptureControllerID id, int buffer_id) override {}
+ void OnBufferReady(
+ VideoCaptureControllerID id,
+ int buffer_id,
+ const gfx::Size& coded_size,
+ const gfx::Rect& visible_rect,
+ const base::TimeTicks& timestamp,
+ scoped_ptr<base::DictionaryValue> metadata) override {}
+ void OnMailboxBufferReady(
+ VideoCaptureControllerID id,
+ int buffer_id,
+ const gpu::MailboxHolder& mailbox_holder,
+ const gfx::Size& packed_frame_size,
+ const base::TimeTicks& timestamp,
+ scoped_ptr<base::DictionaryValue> metadata) override {}
+ void OnEnded(VideoCaptureControllerID id) override {}
void OnGotControllerCallback(VideoCaptureControllerID) {}
};
@@ -176,6 +179,33 @@ TEST_F(VideoCaptureManagerTest, CreateAndClose) {
vcm_->Unregister();
}
+TEST_F(VideoCaptureManagerTest, CreateAndCloseMultipleTimes) {
+ StreamDeviceInfoArray devices;
+
+ InSequence s;
+ EXPECT_CALL(*listener_, DevicesEnumerated(MEDIA_DEVICE_VIDEO_CAPTURE, _))
+ .WillOnce(SaveArg<1>(&devices));
+
+ vcm_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE);
+
+ // Wait to get device callback.
+ message_loop_->RunUntilIdle();
+
+ for (int i = 1 ; i < 3 ; ++i) {
+ EXPECT_CALL(*listener_, Opened(MEDIA_DEVICE_VIDEO_CAPTURE, i));
+ EXPECT_CALL(*listener_, Closed(MEDIA_DEVICE_VIDEO_CAPTURE, i));
+ int video_session_id = vcm_->Open(devices.front());
+ VideoCaptureControllerID client_id = StartClient(video_session_id, true);
+
+ StopClient(client_id);
+ vcm_->Close(video_session_id);
+ }
+
+ // Wait to check callbacks before removing the listener.
+ message_loop_->RunUntilIdle();
+ vcm_->Unregister();
+}
+
// Try to open, start, and abort a device.
TEST_F(VideoCaptureManagerTest, CreateAndAbort) {
StreamDeviceInfoArray devices;
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 4a9c5d2db38..c4209420169 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
@@ -116,10 +116,10 @@ class WebRTCIdentityServiceHostTest : public ::testing::Test {
IPC::Message ipc = host_->GetLastMessage();
EXPECT_EQ(ipc.type(), WebRTCIdentityHostMsg_RequestFailed::ID);
- Tuple2<int, int> error_in_message;
+ Tuple<int, int> error_in_message;
WebRTCIdentityHostMsg_RequestFailed::Read(&ipc, &error_in_message);
- EXPECT_EQ(FAKE_SEQUENCE_NUMBER, error_in_message.a);
- EXPECT_EQ(error, error_in_message.b);
+ EXPECT_EQ(FAKE_SEQUENCE_NUMBER, get<0>(error_in_message));
+ EXPECT_EQ(error, get<1>(error_in_message));
}
void VerifyIdentityReadyMessage(const std::string& cert,
@@ -128,11 +128,11 @@ class WebRTCIdentityServiceHostTest : public ::testing::Test {
IPC::Message ipc = host_->GetLastMessage();
EXPECT_EQ(ipc.type(), WebRTCIdentityHostMsg_IdentityReady::ID);
- Tuple3<int, std::string, std::string> identity_in_message;
+ Tuple<int, std::string, std::string> identity_in_message;
WebRTCIdentityHostMsg_IdentityReady::Read(&ipc, &identity_in_message);
- EXPECT_EQ(FAKE_SEQUENCE_NUMBER, identity_in_message.a);
- EXPECT_EQ(cert, identity_in_message.b);
- EXPECT_EQ(key, identity_in_message.c);
+ EXPECT_EQ(FAKE_SEQUENCE_NUMBER, get<0>(identity_in_message));
+ EXPECT_EQ(cert, get<1>(identity_in_message));
+ EXPECT_EQ(key, get<2>(identity_in_message));
}
protected:
diff --git a/chromium/content/browser/renderer_host/native_web_keyboard_event.cc b/chromium/content/browser/renderer_host/native_web_keyboard_event.cc
deleted file mode 100644
index 502b30d9981..00000000000
--- a/chromium/content/browser/renderer_host/native_web_keyboard_event.cc
+++ /dev/null
@@ -1,27 +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/public/browser/native_web_keyboard_event.h"
-
-#include "ui/events/event_constants.h"
-
-namespace content {
-
-int GetModifiersFromNativeWebKeyboardEvent(
- const NativeWebKeyboardEvent& event) {
- int modifiers = ui::EF_NONE;
- if (event.modifiers & NativeWebKeyboardEvent::ShiftKey)
- modifiers |= ui::EF_SHIFT_DOWN;
- if (event.modifiers & NativeWebKeyboardEvent::ControlKey)
- modifiers |= ui::EF_CONTROL_DOWN;
- if (event.modifiers & NativeWebKeyboardEvent::AltKey)
- modifiers |= ui::EF_ALT_DOWN;
-#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
- if (event.modifiers & NativeWebKeyboardEvent::MetaKey)
- modifiers |= ui::EF_COMMAND_DOWN;
-#endif
- return modifiers;
-}
-
-} // namespace content
diff --git a/chromium/content/browser/renderer_host/native_web_keyboard_event_aura.cc b/chromium/content/browser/renderer_host/native_web_keyboard_event_aura.cc
index 8757b9be943..626d901f31f 100644
--- a/chromium/content/browser/renderer_host/native_web_keyboard_event_aura.cc
+++ b/chromium/content/browser/renderer_host/native_web_keyboard_event_aura.cc
@@ -14,8 +14,8 @@ namespace {
// queued in RenderWidgetHost and may be passed and used
// RenderViewHostDelegate::HandledKeybardEvent after the original aura
// event is destroyed.
-ui::Event* CopyEvent(ui::Event* event) {
- return event ? new ui::KeyEvent(*static_cast<ui::KeyEvent*>(event)) : NULL;
+ui::Event* CopyEvent(const ui::Event* event) {
+ return event ? ui::Event::Clone(*event).release() : nullptr;
}
int EventFlagsToWebInputEventModifiers(int flags) {
@@ -39,9 +39,12 @@ NativeWebKeyboardEvent::NativeWebKeyboardEvent()
}
NativeWebKeyboardEvent::NativeWebKeyboardEvent(gfx::NativeEvent native_event)
- : WebKeyboardEvent(MakeWebKeyboardEvent(
- static_cast<ui::KeyEvent*>(native_event))),
- os_event(CopyEvent(native_event)),
+ : NativeWebKeyboardEvent(static_cast<ui::KeyEvent&>(*native_event)) {
+}
+
+NativeWebKeyboardEvent::NativeWebKeyboardEvent(const ui::KeyEvent& key_event)
+ : WebKeyboardEvent(MakeWebKeyboardEvent(key_event)),
+ os_event(CopyEvent(&key_event)),
skip_in_browser(false),
match_edit_command(false) {
}
diff --git a/chromium/content/browser/renderer_host/native_web_keyboard_event_mac.mm b/chromium/content/browser/renderer_host/native_web_keyboard_event_mac.mm
index fea2939f2c1..76c5c1006bf 100644
--- a/chromium/content/browser/renderer_host/native_web_keyboard_event_mac.mm
+++ b/chromium/content/browser/renderer_host/native_web_keyboard_event_mac.mm
@@ -7,6 +7,7 @@
#import <AppKit/AppKit.h>
#include "third_party/WebKit/public/web/mac/WebInputEventFactory.h"
+#include "ui/events/event.h"
using blink::WebInputEventFactory;
@@ -23,14 +24,8 @@ NativeWebKeyboardEvent::NativeWebKeyboardEvent(gfx::NativeEvent native_event)
skip_in_browser(false) {
}
-NativeWebKeyboardEvent::NativeWebKeyboardEvent(wchar_t character,
- int modifiers,
- double time_stamp_seconds)
- : WebKeyboardEvent(WebInputEventFactory::keyboardEvent(character,
- modifiers,
- time_stamp_seconds)),
- os_event(NULL),
- skip_in_browser(false) {
+NativeWebKeyboardEvent::NativeWebKeyboardEvent(const ui::KeyEvent& key_event)
+ : NativeWebKeyboardEvent(key_event.native_event()) {
}
NativeWebKeyboardEvent::NativeWebKeyboardEvent(
diff --git a/chromium/content/browser/renderer_host/overscroll_controller.cc b/chromium/content/browser/renderer_host/overscroll_controller.cc
index 86dc692fea2..b622dc85338 100644
--- a/chromium/content/browser/renderer_host/overscroll_controller.cc
+++ b/chromium/content/browser/renderer_host/overscroll_controller.cc
@@ -35,11 +35,13 @@ OverscrollController::~OverscrollController() {
}
bool OverscrollController::WillHandleEvent(const blink::WebInputEvent& event) {
- if (scroll_state_ != STATE_UNKNOWN) {
+ bool reset_scroll_state = false;
+ if (scroll_state_ != STATE_UNKNOWN ||
+ overscroll_delta_x_ || overscroll_delta_y_) {
switch (event.type) {
case blink::WebInputEvent::GestureScrollEnd:
case blink::WebInputEvent::GestureFlingStart:
- scroll_state_ = STATE_UNKNOWN;
+ reset_scroll_state = true;
break;
case blink::WebInputEvent::MouseWheel: {
@@ -48,7 +50,7 @@ bool OverscrollController::WillHandleEvent(const blink::WebInputEvent& event) {
if (!wheel.hasPreciseScrollingDeltas ||
wheel.phase == blink::WebMouseWheelEvent::PhaseEnded ||
wheel.phase == blink::WebMouseWheelEvent::PhaseCancelled) {
- scroll_state_ = STATE_UNKNOWN;
+ reset_scroll_state = true;
}
break;
}
@@ -56,12 +58,15 @@ bool OverscrollController::WillHandleEvent(const blink::WebInputEvent& event) {
default:
if (blink::WebInputEvent::isMouseEventType(event.type) ||
blink::WebInputEvent::isKeyboardEventType(event.type)) {
- scroll_state_ = STATE_UNKNOWN;
+ reset_scroll_state = true;
}
break;
}
}
+ if (reset_scroll_state)
+ scroll_state_ = STATE_UNKNOWN;
+
if (DispatchEventCompletesAction(event)) {
CompleteAction();
@@ -80,8 +85,11 @@ bool OverscrollController::WillHandleEvent(const blink::WebInputEvent& event) {
// Consume the event only if it updates the overscroll state.
if (ProcessEventForOverscroll(event))
return true;
+ } else if (reset_scroll_state) {
+ overscroll_delta_x_ = overscroll_delta_y_ = 0.f;
}
+
return false;
}
@@ -163,7 +171,6 @@ bool OverscrollController::DispatchEventCompletesAction (
return false;
break;
case OVERSCROLL_NONE:
- case OVERSCROLL_COUNT:
NOTREACHED();
}
}
diff --git a/chromium/content/browser/renderer_host/overscroll_controller.h b/chromium/content/browser/renderer_host/overscroll_controller.h
index a6287efd3bd..04a95910149 100644
--- a/chromium/content/browser/renderer_host/overscroll_controller.h
+++ b/chromium/content/browser/renderer_host/overscroll_controller.h
@@ -25,8 +25,7 @@ enum OverscrollMode {
OVERSCROLL_NORTH,
OVERSCROLL_SOUTH,
OVERSCROLL_WEST,
- OVERSCROLL_EAST,
- OVERSCROLL_COUNT
+ OVERSCROLL_EAST
};
// When a page is scrolled beyond the scrollable region, it will trigger an
diff --git a/chromium/content/browser/renderer_host/overscroll_controller_delegate.h b/chromium/content/browser/renderer_host/overscroll_controller_delegate.h
index 54b5da18857..b3d4757933f 100644
--- a/chromium/content/browser/renderer_host/overscroll_controller_delegate.h
+++ b/chromium/content/browser/renderer_host/overscroll_controller_delegate.h
@@ -8,13 +8,14 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "content/browser/renderer_host/overscroll_controller.h"
-#include "ui/gfx/rect.h"
+#include "content/common/content_export.h"
+#include "ui/gfx/geometry/rect.h"
namespace content {
// The delegate receives overscroll gesture updates from the controller and
// should perform appropriate actions.
-class OverscrollControllerDelegate {
+class CONTENT_EXPORT OverscrollControllerDelegate {
public:
OverscrollControllerDelegate() {}
virtual ~OverscrollControllerDelegate() {}
diff --git a/chromium/content/browser/renderer_host/p2p/OWNERS b/chromium/content/browser/renderer_host/p2p/OWNERS
index 49f36fb7949..5e2b3d678cd 100644
--- a/chromium/content/browser/renderer_host/p2p/OWNERS
+++ b/chromium/content/browser/renderer_host/p2p/OWNERS
@@ -1,3 +1,2 @@
-hclam@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 8bab6aff976..724294f085e 100644
--- a/chromium/content/browser/renderer_host/p2p/socket_dispatcher_host.cc
+++ b/chromium/content/browser/renderer_host/p2p/socket_dispatcher_host.cc
@@ -12,9 +12,9 @@
#include "net/base/address_list.h"
#include "net/base/completion_callback.h"
#include "net/base/net_errors.h"
-#include "net/base/net_log.h"
#include "net/base/sys_addrinfo.h"
#include "net/dns/single_request_host_resolver.h"
+#include "net/log/net_log.h"
#include "net/url_request/url_request_context_getter.h"
using content::BrowserMessageFilter;
@@ -152,7 +152,7 @@ void P2PSocketDispatcherHost::StartRtpDump(
bool incoming,
bool outgoing,
const RenderProcessHost::WebRtcRtpPacketCallback& packet_callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if ((!dump_incoming_rtp_packet_ && incoming) ||
(!dump_outgoing_rtp_packet_ && outgoing)) {
@@ -170,7 +170,7 @@ void P2PSocketDispatcherHost::StartRtpDump(
void P2PSocketDispatcherHost::StopRtpDumpOnUIThread(bool incoming,
bool outgoing) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
@@ -256,9 +256,15 @@ void P2PSocketDispatcherHost::OnAcceptIncomingTcpConnection(
P2PSocketHost* socket = LookupSocket(listen_socket_id);
if (!socket) {
LOG(ERROR) << "Received P2PHostMsg_AcceptIncomingTcpConnection "
- "for invalid socket_id.";
+ "for invalid listen_socket_id.";
return;
}
+ if (LookupSocket(connected_socket_id) != NULL) {
+ LOG(ERROR) << "Received P2PHostMsg_AcceptIncomingTcpConnection "
+ "for duplicated connected_socket_id.";
+ return;
+ }
+
P2PSocketHost* accepted_connection =
socket->AcceptIncomingTcpConnection(remote_address, connected_socket_id);
if (accepted_connection) {
@@ -313,8 +319,7 @@ void P2PSocketDispatcherHost::OnDestroySocket(int socket_id) {
void P2PSocketDispatcherHost::DoGetNetworkList() {
net::NetworkInterfaceList list;
- net::GetNetworkList(&list, net::EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES |
- net::INCLUDE_ONLY_TEMP_IPV6_ADDRESS_IF_POSSIBLE);
+ net::GetNetworkList(&list, net::EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES);
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE, base::Bind(
&P2PSocketDispatcherHost::SendNetworkList, this, list));
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host.cc b/chromium/content/browser/renderer_host/p2p/socket_host.cc
index 8f6e71f3c71..f2e76c37163 100644
--- a/chromium/content/browser/renderer_host/p2p/socket_host.cc
+++ b/chromium/content/browser/renderer_host/p2p/socket_host.cc
@@ -141,12 +141,11 @@ void UpdateAbsSendTimeExtensionValue(char* extension_data,
return;
}
- // Now() has resolution ~1-15ms, using HighResNow(). But it is warned not to
- // use it unless necessary, as it is expensive than Now().
+ // Now() has resolution ~1-15ms
uint32 now_second = abs_send_time;
if (!now_second) {
uint64 now_us =
- (base::TimeTicks::HighResNow() - base::TimeTicks()).InMicroseconds();
+ (base::TimeTicks::Now() - base::TimeTicks()).InMicroseconds();
// Convert second to 24-bit unsigned with 18 bit fractional part
now_second =
((now_us << 18) / base::Time::kMicrosecondsPerSecond) & 0x00FFFFFF;
@@ -463,12 +462,12 @@ P2PSocketHost::P2PSocketHost(IPC::Sender* message_sender,
state_(STATE_UNINITIALIZED),
dump_incoming_rtp_packet_(false),
dump_outgoing_rtp_packet_(false),
- 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) {
+ send_bytes_delayed_cur_(0),
+ weak_ptr_factory_(this) {
}
P2PSocketHost::~P2PSocketHost() {
@@ -579,7 +578,7 @@ void P2PSocketHost::StartRtpDump(
bool incoming,
bool outgoing,
const RenderProcessHost::WebRtcRtpPacketCallback& packet_callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(!packet_callback.is_null());
DCHECK(incoming || outgoing);
@@ -595,7 +594,7 @@ void P2PSocketHost::StartRtpDump(
}
void P2PSocketHost::StopRtpDump(bool incoming, bool outgoing) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(incoming || outgoing);
if (incoming) {
@@ -653,7 +652,7 @@ void P2PSocketHost::DumpRtpPacketOnIOThread(scoped_ptr<uint8[]> packet_header,
size_t header_length,
size_t packet_length,
bool incoming) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if ((incoming && !dump_incoming_rtp_packet_) ||
(!incoming && !dump_outgoing_rtp_packet_) ||
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host.h b/chromium/content/browser/renderer_host/p2p/socket_host.h
index 390c115efb6..b569a0a1041 100644
--- a/chromium/content/browser/renderer_host/p2p/socket_host.h
+++ b/chromium/content/browser/renderer_host/p2p/socket_host.h
@@ -160,8 +160,6 @@ class CONTENT_EXPORT P2PSocketHost {
bool dump_outgoing_rtp_packet_;
RenderProcessHost::WebRtcRtpPacketCallback packet_dump_callback_;
- base::WeakPtrFactory<P2PSocketHost> weak_ptr_factory_;
-
ProtocolType protocol_type_;
private:
@@ -175,6 +173,8 @@ class CONTENT_EXPORT P2PSocketHost {
int32 send_bytes_delayed_max_;
int32 send_bytes_delayed_cur_;
+ base::WeakPtrFactory<P2PSocketHost> weak_ptr_factory_;
+
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 79f7b14b0b8..a92e3e52df8 100644
--- a/chromium/content/browser/renderer_host/p2p/socket_host_tcp.cc
+++ b/chromium/content/browser/renderer_host/p2p/socket_host_tcp.cc
@@ -142,6 +142,7 @@ void P2PSocketHostTcpBase::OnConnected(int result) {
DCHECK_NE(result, net::ERR_IO_PENDING);
if (result != net::OK) {
+ LOG(WARNING) << "Error from connecting socket, result=" << result;
OnError();
return;
}
@@ -206,6 +207,7 @@ void P2PSocketHostTcpBase::StartTls() {
int status = socket_->Connect(
base::Bind(&P2PSocketHostTcpBase::ProcessTlsSslConnectDone,
base::Unretained(this)));
+
if (status != net::ERR_IO_PENDING) {
ProcessTlsSslConnectDone(status);
}
@@ -215,6 +217,7 @@ void P2PSocketHostTcpBase::ProcessTlsSslConnectDone(int status) {
DCHECK_NE(status, net::ERR_IO_PENDING);
DCHECK_EQ(state_, STATE_TLS_CONNECTING);
if (status != net::OK) {
+ LOG(WARNING) << "Error from connecting TLS socket, status=" << status;
OnError();
return;
}
@@ -256,22 +259,30 @@ bool P2PSocketHostTcpBase::DoSendSocketCreateMsg() {
VLOG(1) << "Local address: " << local_address.ToString();
net::IPEndPoint remote_address;
+
+ // GetPeerAddress returns ERR_NAME_NOT_RESOLVED if the socket is connected
+ // through a proxy.
result = socket_->GetPeerAddress(&remote_address);
- if (result < 0) {
+ if (result < 0 && result != net::ERR_NAME_NOT_RESOLVED) {
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 (!remote_address.address().empty()) {
+ 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;
+ }
+ } else {
+ VLOG(1) << "Remote address is unknown since connection is proxied";
}
// 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
+ // successful. 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_, local_address, remote_address));
@@ -401,7 +412,8 @@ void P2PSocketHostTcpBase::HandleWriteResult(int result) {
if (result >= 0) {
write_buffer_->DidConsume(result);
if (write_buffer_->BytesRemaining() == 0) {
- message_sender_->Send(new P2PMsg_OnSendComplete(id_));
+ message_sender_->Send(
+ new P2PMsg_OnSendComplete(id_, P2PSendPacketMetrics()));
if (write_queue_.empty()) {
write_buffer_ = NULL;
} else {
@@ -435,6 +447,10 @@ void P2PSocketHostTcpBase::DidCompleteRead(int result) {
LOG(ERROR) << "Error when reading from TCP socket: " << result;
OnError();
return;
+ } else if (result == 0) {
+ LOG(WARNING) << "Remote peer has shutdown TCP socket.";
+ OnError();
+ return;
}
read_buffer_->set_offset(read_buffer_->offset() + result);
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host_test_utils.cc b/chromium/content/browser/renderer_host/p2p/socket_host_test_utils.cc
index ba40aecf4a4..ed0796649b2 100644
--- a/chromium/content/browser/renderer_host/p2p/socket_host_test_utils.cc
+++ b/chromium/content/browser/renderer_host/p2p/socket_host_test_utils.cc
@@ -172,6 +172,10 @@ bool FakeSocket::GetSSLInfo(net::SSLInfo* ssl_info) {
return false;
}
+void FakeSocket::GetConnectionAttempts(net::ConnectionAttempts* out) const {
+ out->clear();
+}
+
void CreateRandomPacket(std::vector<char>* packet) {
size_t size = kStunHeaderSize + rand() % 1000;
packet->resize(size);
@@ -204,7 +208,7 @@ void CreateStunError(std::vector<char>* packet) {
CreateStunPacket(packet, kStunBindingError);
}
-net::IPEndPoint ParseAddress(const std::string ip_str, int port) {
+net::IPEndPoint ParseAddress(const std::string ip_str, uint16 port) {
net::IPAddressNumber ip;
EXPECT_TRUE(net::ParseIPLiteralToNumber(ip_str, &ip));
return net::IPEndPoint(ip, port);
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host_test_utils.h b/chromium/content/browser/renderer_host/p2p/socket_host_test_utils.h
index acab45ff25f..9ab46340705 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
@@ -16,9 +16,9 @@
const char kTestLocalIpAddress[] = "123.44.22.4";
const char kTestIpAddress1[] = "123.44.22.31";
-const int kTestPort1 = 234;
+const uint16 kTestPort1 = 234;
const char kTestIpAddress2[] = "133.11.22.33";
-const int kTestPort2 = 543;
+const uint16 kTestPort2 = 543;
class MockIPCSender : public IPC::Sender {
public:
@@ -63,6 +63,10 @@ class FakeSocket : public net::StreamSocket {
bool WasNpnNegotiated() const override;
net::NextProto GetNegotiatedProtocol() const override;
bool GetSSLInfo(net::SSLInfo* ssl_info) override;
+ void GetConnectionAttempts(net::ConnectionAttempts* out) const override;
+ void ClearConnectionAttempts() override {}
+ void AddConnectionAttempts(const net::ConnectionAttempts& attempts) override {
+ }
private:
void DoAsyncWrite(scoped_refptr<net::IOBuffer> buf, int buf_len,
@@ -91,7 +95,7 @@ void CreateStunRequest(std::vector<char>* packet);
void CreateStunResponse(std::vector<char>* packet);
void CreateStunError(std::vector<char>* packet);
-net::IPEndPoint ParseAddress(const std::string ip_str, int port);
+net::IPEndPoint ParseAddress(const std::string ip_str, uint16 port);
MATCHER_P(MatchMessage, type, "") {
return arg->type() == type;
@@ -102,7 +106,7 @@ MATCHER_P(MatchPacketMessage, packet_content, "") {
return false;
P2PMsg_OnDataReceived::Param params;
P2PMsg_OnDataReceived::Read(arg, &params);
- return params.c == packet_content;
+ return get<2>(params) == packet_content;
}
MATCHER_P(MatchIncomingSocketMessage, address, "") {
@@ -111,7 +115,7 @@ MATCHER_P(MatchIncomingSocketMessage, address, "") {
P2PMsg_OnIncomingTcpConnection::Param params;
P2PMsg_OnIncomingTcpConnection::Read(
arg, &params);
- return params.b == address;
+ return get<1>(params) == address;
}
#endif // CONTENT_BROWSER_RENDERER_HOST_P2P_SOCKET_HOST_TEST_UTILS_H_
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 29883179715..5137972ebb0 100644
--- a/chromium/content/browser/renderer_host/p2p/socket_host_udp.cc
+++ b/chromium/content/browser/renderer_host/p2p/socket_host_udp.cc
@@ -5,11 +5,11 @@
#include "content/browser/renderer_host/p2p/socket_host_udp.h"
#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 "base/trace_event/trace_event.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"
@@ -39,13 +39,32 @@ const int kRecvSocketBufferSize = 65536; // 64K
//
// This is caused by WSAENETRESET or WSAECONNRESET which means the
// last send resulted in an "ICMP Port Unreachable" message.
+struct {
+ int code;
+ const char* name;
+} static const kTransientErrors[] {
+ {net::ERR_ADDRESS_UNREACHABLE, "net::ERR_ADDRESS_UNREACHABLE"},
+ {net::ERR_ADDRESS_INVALID, "net::ERR_ADDRESS_INVALID"},
+ {net::ERR_ACCESS_DENIED, "net::ERR_ACCESS_DENIED"},
+ {net::ERR_CONNECTION_RESET, "net::ERR_CONNECTION_RESET"},
+ {net::ERR_OUT_OF_MEMORY, "net::ERR_OUT_OF_MEMORY"},
+ {net::ERR_INTERNET_DISCONNECTED, "net::ERR_INTERNET_DISCONNECTED"}
+};
+
bool IsTransientError(int error) {
- return error == net::ERR_ADDRESS_UNREACHABLE ||
- error == net::ERR_ADDRESS_INVALID ||
- error == net::ERR_ACCESS_DENIED ||
- error == net::ERR_CONNECTION_RESET ||
- error == net::ERR_OUT_OF_MEMORY ||
- error == net::ERR_INTERNET_DISCONNECTED;
+ for (const auto& transient_error : kTransientErrors) {
+ if (transient_error.code == error)
+ return true;
+ }
+ return false;
+}
+
+const char* GetTransientErrorName(int error) {
+ for (const auto& transient_error : kTransientErrors) {
+ if (transient_error.code == error)
+ return transient_error.name;
+ }
+ return "";
}
} // namespace
@@ -72,12 +91,16 @@ P2PSocketHostUdp::P2PSocketHostUdp(IPC::Sender* message_sender,
int socket_id,
P2PMessageThrottler* throttler)
: P2PSocketHost(message_sender, socket_id, P2PSocketHost::UDP),
- socket_(
- new net::UDPServerSocket(GetContentClient()->browser()->GetNetLog(),
- net::NetLog::Source())),
send_pending_(false),
last_dscp_(net::DSCP_CS0),
- throttler_(throttler) {
+ throttler_(throttler),
+ send_buffer_size_(0) {
+ net::UDPServerSocket* socket = new net::UDPServerSocket(
+ GetContentClient()->browser()->GetNetLog(), net::NetLog::Source());
+#if defined(OS_WIN)
+ socket->UseNonBlockingIO();
+#endif
+ socket_.reset(socket);
}
P2PSocketHostUdp::~P2PSocketHostUdp() {
@@ -98,6 +121,8 @@ void P2PSocketHostUdp::SetSendBufferSize() {
if (!SetOption(P2P_SOCKET_OPT_SNDBUF, send_buffer_size)) {
LOG(WARNING) << "Failed to set socket send buffer size to "
<< send_buffer_size;
+ } else {
+ send_buffer_size_ = send_buffer_size;
}
}
}
@@ -332,7 +357,8 @@ void P2PSocketHostUdp::HandleSendResult(uint64 packet_id,
return;
}
VLOG(0) << "sendto() has failed twice returning a "
- " transient error. Dropping the packet.";
+ " transient error " << GetTransientErrorName(result)
+ << ". Dropping the packet.";
}
// UMA to track the histograms from 1ms to 1 sec for how long a packet spends
@@ -342,7 +368,8 @@ void P2PSocketHostUdp::HandleSendResult(uint64 packet_id,
base::TimeTicks::Now() -
base::TimeTicks::FromInternalValue(tick_received) /* sample */);
- message_sender_->Send(new P2PMsg_OnSendComplete(id_));
+ message_sender_->Send(
+ new P2PMsg_OnSendComplete(id_, P2PSendPacketMetrics(packet_id)));
}
P2PSocketHost* P2PSocketHostUdp::AcceptIncomingTcpConnection(
@@ -358,6 +385,11 @@ bool P2PSocketHostUdp::SetOption(P2PSocketOption option, int value) {
case P2P_SOCKET_OPT_RCVBUF:
return socket_->SetReceiveBufferSize(value) == net::OK;
case P2P_SOCKET_OPT_SNDBUF:
+ // Ignore any following call to set the send buffer size if we're under
+ // experiment.
+ if (send_buffer_size_ > 0) {
+ return true;
+ }
return socket_->SetSendBufferSize(value) == net::OK;
case P2P_SOCKET_OPT_DSCP:
return (net::OK == socket_->SetDiffServCodePoint(
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 f0b04a65496..1839663637b 100644
--- a/chromium/content/browser/renderer_host/p2p/socket_host_udp.h
+++ b/chromium/content/browser/renderer_host/p2p/socket_host_udp.h
@@ -86,6 +86,9 @@ class CONTENT_EXPORT P2PSocketHostUdp : public P2PSocketHost {
ConnectedPeerSet connected_peers_;
P2PMessageThrottler* throttler_;
+ // Keep track of the send socket buffer size under experiment.
+ size_t send_buffer_size_;
+
DISALLOW_COPY_AND_ASSIGN(P2PSocketHostUdp);
};
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 130245e6022..d263ee1c91e 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
@@ -32,7 +32,8 @@ BrowserPpapiHost* BrowserPpapiHost::CreateExternalPluginProcess(
profile_directory,
false /* in_process */,
true /* external_plugin */);
- browser_ppapi_host->set_plugin_process_handle(plugin_child_process);
+ browser_ppapi_host->set_plugin_process(
+ base::Process::DeprecatedGetProcessFromHandle(plugin_child_process));
scoped_refptr<PepperMessageFilter> pepper_message_filter(
new PepperMessageFilter());
@@ -52,7 +53,6 @@ BrowserPpapiHostImpl::BrowserPpapiHostImpl(
bool in_process,
bool external_plugin)
: ppapi_host_(new ppapi::host::PpapiHost(sender, permissions)),
- plugin_process_handle_(base::kNullProcessHandle),
plugin_name_(plugin_name),
plugin_path_(plugin_path),
profile_data_directory_(profile_data_directory),
@@ -68,6 +68,12 @@ BrowserPpapiHostImpl::~BrowserPpapiHostImpl() {
// Notify the filter so it won't foward messages to us.
message_filter_->OnHostDestroyed();
+ // Notify instance observers about our impending destruction.
+ for (auto& instance_data : instance_map_) {
+ FOR_EACH_OBSERVER(InstanceObserver, instance_data.second->observer_list,
+ OnHostDestroyed());
+ }
+
// Delete the host explicitly first. This shutdown will destroy the
// resources, which may want to do cleanup in their destructors and expect
// their pointers to us to be valid.
@@ -78,29 +84,29 @@ ppapi::host::PpapiHost* BrowserPpapiHostImpl::GetPpapiHost() {
return ppapi_host_.get();
}
-base::ProcessHandle BrowserPpapiHostImpl::GetPluginProcessHandle() const {
+const base::Process& BrowserPpapiHostImpl::GetPluginProcess() const {
// Handle should previously have been set before use.
- DCHECK(in_process_ || plugin_process_handle_ != base::kNullProcessHandle);
- return plugin_process_handle_;
+ DCHECK(in_process_ || plugin_process_.IsValid());
+ return plugin_process_;
}
bool BrowserPpapiHostImpl::IsValidInstance(PP_Instance instance) const {
- return instance_map_.find(instance) != instance_map_.end();
+ return instance_map_.contains(instance);
}
bool BrowserPpapiHostImpl::GetRenderFrameIDsForInstance(
PP_Instance instance,
int* render_process_id,
int* render_frame_id) const {
- InstanceMap::const_iterator found = instance_map_.find(instance);
- if (found == instance_map_.end()) {
+ auto* data = instance_map_.get(instance);
+ if (data == nullptr) {
*render_process_id = 0;
*render_frame_id = 0;
return false;
}
- *render_process_id = found->second.render_process_id;
- *render_frame_id = found->second.render_frame_id;
+ *render_process_id = data->renderer_data.render_process_id;
+ *render_frame_id = data->renderer_data.render_frame_id;
return true;
}
@@ -117,17 +123,17 @@ const base::FilePath& BrowserPpapiHostImpl::GetProfileDataDirectory() {
}
GURL BrowserPpapiHostImpl::GetDocumentURLForInstance(PP_Instance instance) {
- InstanceMap::const_iterator found = instance_map_.find(instance);
- if (found == instance_map_.end())
+ auto* data = instance_map_.get(instance);
+ if (data == nullptr)
return GURL();
- return found->second.document_url;
+ return data->renderer_data.document_url;
}
GURL BrowserPpapiHostImpl::GetPluginURLForInstance(PP_Instance instance) {
- InstanceMap::const_iterator found = instance_map_.find(instance);
- if (found == instance_map_.end())
+ auto* data = instance_map_.get(instance);
+ if (data == nullptr)
return GURL();
- return found->second.plugin_url;
+ return data->renderer_data.plugin_url;
}
void BrowserPpapiHostImpl::SetOnKeepaliveCallback(
@@ -135,20 +141,55 @@ void BrowserPpapiHostImpl::SetOnKeepaliveCallback(
on_keepalive_callback_ = callback;
}
+bool BrowserPpapiHostImpl::IsPotentiallySecurePluginContext(
+ PP_Instance instance) {
+ auto* data = instance_map_.get(instance);
+ if (data == nullptr)
+ return false;
+ return data->renderer_data.is_potentially_secure_plugin_context;
+}
+
void BrowserPpapiHostImpl::AddInstance(
PP_Instance instance,
- const PepperRendererInstanceData& instance_data) {
- DCHECK(instance_map_.find(instance) == instance_map_.end());
- instance_map_[instance] = instance_data;
+ const PepperRendererInstanceData& renderer_instance_data) {
+ DCHECK(!instance_map_.contains(instance));
+ instance_map_.add(instance,
+ make_scoped_ptr(new InstanceData(renderer_instance_data)));
}
void BrowserPpapiHostImpl::DeleteInstance(PP_Instance instance) {
- InstanceMap::iterator found = instance_map_.find(instance);
- if (found == instance_map_.end()) {
- NOTREACHED();
- return;
+ int erased = instance_map_.erase(instance);
+ DCHECK_EQ(1, erased);
+}
+
+void BrowserPpapiHostImpl::AddInstanceObserver(PP_Instance instance,
+ InstanceObserver* observer) {
+ instance_map_.get(instance)->observer_list.AddObserver(observer);
+}
+
+void BrowserPpapiHostImpl::RemoveInstanceObserver(PP_Instance instance,
+ InstanceObserver* observer) {
+ auto* data = instance_map_.get(instance);
+ if (data)
+ data->observer_list.RemoveObserver(observer);
+}
+
+void BrowserPpapiHostImpl::OnThrottleStateChanged(PP_Instance instance,
+ bool is_throttled) {
+ auto* data = instance_map_.get(instance);
+ if (data) {
+ data->is_throttled = is_throttled;
+ FOR_EACH_OBSERVER(InstanceObserver, data->observer_list,
+ OnThrottleStateChanged(is_throttled));
}
- instance_map_.erase(found);
+}
+
+bool BrowserPpapiHostImpl::IsThrottled(PP_Instance instance) const {
+ auto* data = instance_map_.get(instance);
+ if (data)
+ return data->is_throttled;
+
+ return false;
}
BrowserPpapiHostImpl::HostMessageFilter::HostMessageFilter(
@@ -192,6 +233,14 @@ void BrowserPpapiHostImpl::HostMessageFilter::OnHostMsgLogInterfaceUsage(
UMA_HISTOGRAM_SPARSE_SLOWLY("Pepper.InterfaceUsed", hash);
}
+BrowserPpapiHostImpl::InstanceData::InstanceData(
+ const PepperRendererInstanceData& renderer_data)
+ : renderer_data(renderer_data), is_throttled(false) {
+}
+
+BrowserPpapiHostImpl::InstanceData::~InstanceData() {
+}
+
void BrowserPpapiHostImpl::OnKeepalive() {
// An instance has been active. The on_keepalive_callback_ will be
// used to permit the content embedder to handle this, e.g. by tracking
@@ -206,12 +255,15 @@ void BrowserPpapiHostImpl::OnKeepalive() {
BrowserPpapiHost::OnKeepaliveInstanceData instance_data(instance_map_.size());
- InstanceMap::iterator instance = instance_map_.begin();
+ auto instance = instance_map_.begin();
int i = 0;
while (instance != instance_map_.end()) {
- instance_data[i].render_process_id = instance->second.render_process_id;
- instance_data[i].render_frame_id = instance->second.render_frame_id;
- instance_data[i].document_url = instance->second.document_url;
+ instance_data[i].render_process_id =
+ instance->second->renderer_data.render_process_id;
+ instance_data[i].render_frame_id =
+ instance->second->renderer_data.render_frame_id;
+ instance_data[i].document_url =
+ instance->second->renderer_data.document_url;
++instance;
++i;
}
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 bd0c61d7c59..a29eb7ed55d 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
@@ -10,9 +10,12 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
+#include "base/containers/scoped_ptr_hash_map.h"
#include "base/files/file_path.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "base/process/process.h"
#include "content/browser/renderer_host/pepper/content_browser_pepper_host_factory.h"
#include "content/browser/renderer_host/pepper/ssl_context_helper.h"
#include "content/common/content_export.h"
@@ -30,9 +33,19 @@ namespace content {
class CONTENT_EXPORT BrowserPpapiHostImpl : public BrowserPpapiHost {
public:
- // The creator is responsible for calling set_plugin_process_handle as soon
- // as it is known (we start the process asynchronously so it won't be known
- // when this object is created).
+ class InstanceObserver {
+ public:
+ // Called when the plugin instance is throttled or unthrottled because of
+ // the Plugin Power Saver feature. Invoked on the IO thread.
+ virtual void OnThrottleStateChanged(bool is_throttled) = 0;
+
+ // Called right before the instance is destroyed.
+ virtual void OnHostDestroyed() = 0;
+ };
+
+ // The creator is responsible for calling set_plugin_process as soon as it is
+ // known (we start the process asynchronously so it won't be known when this
+ // object is created).
// |external_plugin| signfies that this is a proxy created for an embedder's
// plugin, i.e. using BrowserPpapiHost::CreateExternalPluginProcess.
BrowserPpapiHostImpl(IPC::Sender* sender,
@@ -46,7 +59,7 @@ class CONTENT_EXPORT BrowserPpapiHostImpl : public BrowserPpapiHost {
// BrowserPpapiHost.
ppapi::host::PpapiHost* GetPpapiHost() override;
- base::ProcessHandle GetPluginProcessHandle() const override;
+ const base::Process& GetPluginProcess() const override;
bool IsValidInstance(PP_Instance instance) const override;
bool GetRenderFrameIDsForInstance(PP_Instance instance,
int* render_process_id,
@@ -59,8 +72,13 @@ class CONTENT_EXPORT BrowserPpapiHostImpl : public BrowserPpapiHost {
void SetOnKeepaliveCallback(
const BrowserPpapiHost::OnKeepaliveCallback& callback) override;
- void set_plugin_process_handle(base::ProcessHandle handle) {
- plugin_process_handle_ = handle;
+ // Whether the plugin context is secure. That is, it is served from a secure
+ // origin and it is embedded within a hierarchy of secure frames. This value
+ // comes from the renderer so should not be trusted. It is used for metrics.
+ bool IsPotentiallySecurePluginContext(PP_Instance instance);
+
+ void set_plugin_process(base::Process process) {
+ plugin_process_ = process.Pass();
}
bool external_plugin() const { return external_plugin_; }
@@ -69,9 +87,15 @@ class CONTENT_EXPORT BrowserPpapiHostImpl : public BrowserPpapiHost {
// or destroyed. They allow us to maintain a mapping of PP_Instance to data
// associated with the instance including view IDs in the browser process.
void AddInstance(PP_Instance instance,
- const PepperRendererInstanceData& instance_data);
+ const PepperRendererInstanceData& renderer_instance_data);
void DeleteInstance(PP_Instance instance);
+ void AddInstanceObserver(PP_Instance instance, InstanceObserver* observer);
+ void RemoveInstanceObserver(PP_Instance instance, InstanceObserver* observer);
+
+ void OnThrottleStateChanged(PP_Instance instance, bool is_throttled);
+ bool IsThrottled(PP_Instance instance) const;
+
scoped_refptr<IPC::MessageFilter> message_filter() {
return message_filter_;
}
@@ -107,11 +131,21 @@ class CONTENT_EXPORT BrowserPpapiHostImpl : public BrowserPpapiHost {
BrowserPpapiHostImpl* browser_ppapi_host_impl_;
};
+ struct InstanceData {
+ InstanceData(const PepperRendererInstanceData& renderer_data);
+ ~InstanceData();
+
+ PepperRendererInstanceData renderer_data;
+ bool is_throttled;
+
+ ObserverList<InstanceObserver> observer_list;
+ };
+
// Reports plugin activity to the callback set with SetOnKeepaliveCallback.
void OnKeepalive();
scoped_ptr<ppapi::host::PpapiHost> ppapi_host_;
- base::ProcessHandle plugin_process_handle_;
+ base::Process plugin_process_;
std::string plugin_name_;
base::FilePath plugin_path_;
base::FilePath profile_data_directory_;
@@ -125,10 +159,8 @@ class CONTENT_EXPORT BrowserPpapiHostImpl : public BrowserPpapiHost {
scoped_refptr<SSLContextHelper> ssl_context_helper_;
- // Tracks all PP_Instances in this plugin and associated renderer-related
- // data.
- typedef std::map<PP_Instance, PepperRendererInstanceData> InstanceMap;
- InstanceMap instance_map_;
+ // Tracks all PP_Instances in this plugin and associated data.
+ base::ScopedPtrHashMap<PP_Instance, scoped_ptr<InstanceData>> instance_map_;
scoped_refptr<HostMessageFilter> message_filter_;
diff --git a/chromium/content/browser/renderer_host/pepper/browser_ppapi_host_test.cc b/chromium/content/browser/renderer_host/pepper/browser_ppapi_host_test.cc
index 428f63544b0..accc30357fe 100644
--- a/chromium/content/browser/renderer_host/pepper/browser_ppapi_host_test.cc
+++ b/chromium/content/browser/renderer_host/pepper/browser_ppapi_host_test.cc
@@ -17,7 +17,7 @@ BrowserPpapiHostTest::BrowserPpapiHostTest() : sink_() {
base::FilePath(),
false /* in_process */,
false /* external_plugin */));
- ppapi_host_->set_plugin_process_handle(base::GetCurrentProcessHandle());
+ ppapi_host_->set_plugin_process(base::Process::Current());
}
BrowserPpapiHostTest::~BrowserPpapiHostTest() {}
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 9a88cfc460a..f52a2016aad 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
@@ -56,7 +56,7 @@ ContentBrowserPepperHostFactory::~ContentBrowserPepperHostFactory() {}
scoped_ptr<ResourceHost> ContentBrowserPepperHostFactory::CreateResourceHost(
ppapi::host::PpapiHost* host,
- const ppapi::proxy::ResourceMessageCallParams& params,
+ PP_Resource resource,
PP_Instance instance,
const IPC::Message& message) {
DCHECK(host == host_->GetPpapiHost());
@@ -69,7 +69,7 @@ scoped_ptr<ResourceHost> ContentBrowserPepperHostFactory::CreateResourceHost(
switch (message.type()) {
case PpapiHostMsg_FileIO_Create::ID: {
return scoped_ptr<ResourceHost>(
- new PepperFileIOHost(host_, instance, params.pp_resource()));
+ new PepperFileIOHost(host_, instance, resource));
}
case PpapiHostMsg_FileSystem_Create::ID: {
PP_FileSystemType file_system_type;
@@ -79,24 +79,21 @@ scoped_ptr<ResourceHost> ContentBrowserPepperHostFactory::CreateResourceHost(
return scoped_ptr<ResourceHost>();
}
return scoped_ptr<ResourceHost>(new PepperFileSystemBrowserHost(
- host_, instance, params.pp_resource(), file_system_type));
+ host_, instance, resource, file_system_type));
}
case PpapiHostMsg_Gamepad_Create::ID: {
return scoped_ptr<ResourceHost>(
- new PepperGamepadHost(host_, instance, params.pp_resource()));
+ new PepperGamepadHost(host_, instance, resource));
}
case PpapiHostMsg_NetworkProxy_Create::ID: {
return scoped_ptr<ResourceHost>(
- new PepperNetworkProxyHost(host_, instance, params.pp_resource()));
+ new PepperNetworkProxyHost(host_, instance, resource));
}
case PpapiHostMsg_HostResolver_Create::ID: {
scoped_refptr<ResourceMessageFilter> host_resolver(
new PepperHostResolverMessageFilter(host_, instance, false));
- return scoped_ptr<ResourceHost>(
- new MessageFilterHost(host_->GetPpapiHost(),
- instance,
- params.pp_resource(),
- host_resolver));
+ return scoped_ptr<ResourceHost>(new MessageFilterHost(
+ host_->GetPpapiHost(), instance, resource, host_resolver));
}
case PpapiHostMsg_FileRef_CreateForFileAPI::ID: {
PP_Resource file_system;
@@ -107,7 +104,7 @@ scoped_ptr<ResourceHost> ContentBrowserPepperHostFactory::CreateResourceHost(
return scoped_ptr<ResourceHost>();
}
return scoped_ptr<ResourceHost>(new PepperFileRefHost(
- host_, instance, params.pp_resource(), file_system, internal_path));
+ host_, instance, resource, file_system, internal_path));
}
case PpapiHostMsg_TCPSocket_Create::ID: {
ppapi::TCPSocketVersion version;
@@ -116,14 +113,14 @@ scoped_ptr<ResourceHost> ContentBrowserPepperHostFactory::CreateResourceHost(
return scoped_ptr<ResourceHost>();
}
- return CreateNewTCPSocket(instance, params.pp_resource(), version);
+ return CreateNewTCPSocket(instance, resource, version);
}
case PpapiHostMsg_UDPSocket_Create::ID: {
if (CanCreateSocket()) {
scoped_refptr<ResourceMessageFilter> udp_socket(
new PepperUDPSocketMessageFilter(host_, instance, false));
return scoped_ptr<ResourceHost>(new MessageFilterHost(
- host_->GetPpapiHost(), instance, params.pp_resource(), udp_socket));
+ host_->GetPpapiHost(), instance, resource, udp_socket));
} else {
return scoped_ptr<ResourceHost>();
}
@@ -136,11 +133,8 @@ scoped_ptr<ResourceHost> ContentBrowserPepperHostFactory::CreateResourceHost(
case PpapiHostMsg_Printing_Create::ID: {
scoped_ptr<PepperPrintSettingsManager> manager(
new PepperPrintSettingsManagerImpl());
- return scoped_ptr<ResourceHost>(
- new PepperPrintingHost(host_->GetPpapiHost(),
- instance,
- params.pp_resource(),
- manager.Pass()));
+ return scoped_ptr<ResourceHost>(new PepperPrintingHost(
+ host_->GetPpapiHost(), instance, resource, manager.Pass()));
}
case PpapiHostMsg_TrueTypeFont_Create::ID: {
SerializedTrueTypeFontDesc desc;
@@ -153,12 +147,12 @@ scoped_ptr<ResourceHost> ContentBrowserPepperHostFactory::CreateResourceHost(
if (!base::IsStringUTF8(desc.family))
return scoped_ptr<ResourceHost>();
- return scoped_ptr<ResourceHost>(new PepperTrueTypeFontHost(
- host_, instance, params.pp_resource(), desc));
+ return scoped_ptr<ResourceHost>(
+ new PepperTrueTypeFontHost(host_, instance, resource, desc));
}
case PpapiHostMsg_TrueTypeFontSingleton_Create::ID: {
- return scoped_ptr<ResourceHost>(new PepperTrueTypeFontListHost(
- host_, instance, params.pp_resource()));
+ return scoped_ptr<ResourceHost>(
+ new PepperTrueTypeFontListHost(host_, instance, resource));
}
}
}
@@ -167,8 +161,8 @@ scoped_ptr<ResourceHost> ContentBrowserPepperHostFactory::CreateResourceHost(
if (GetPermissions().HasPermission(ppapi::PERMISSION_PRIVATE)) {
switch (message.type()) {
case PpapiHostMsg_BrowserFontSingleton_Create::ID:
- return scoped_ptr<ResourceHost>(new PepperBrowserFontSingletonHost(
- host_, instance, params.pp_resource()));
+ return scoped_ptr<ResourceHost>(
+ new PepperBrowserFontSingletonHost(host_, instance, resource));
}
}
@@ -182,38 +176,35 @@ scoped_ptr<ResourceHost> ContentBrowserPepperHostFactory::CreateResourceHost(
scoped_refptr<ResourceMessageFilter> host_resolver(
new PepperHostResolverMessageFilter(host_, instance, true));
return scoped_ptr<ResourceHost>(new MessageFilterHost(
- host_->GetPpapiHost(), instance, params.pp_resource(), host_resolver));
+ host_->GetPpapiHost(), instance, resource, host_resolver));
}
if (message.type() == PpapiHostMsg_TCPServerSocket_CreatePrivate::ID) {
if (CanCreateSocket()) {
scoped_refptr<ResourceMessageFilter> tcp_server_socket(
new PepperTCPServerSocketMessageFilter(this, host_, instance, true));
- return scoped_ptr<ResourceHost>(
- new MessageFilterHost(host_->GetPpapiHost(),
- instance,
- params.pp_resource(),
- tcp_server_socket));
+ return scoped_ptr<ResourceHost>(new MessageFilterHost(
+ host_->GetPpapiHost(), instance, resource, tcp_server_socket));
} else {
return scoped_ptr<ResourceHost>();
}
}
if (message.type() == PpapiHostMsg_TCPSocket_CreatePrivate::ID) {
- return CreateNewTCPSocket(
- instance, params.pp_resource(), ppapi::TCP_SOCKET_VERSION_PRIVATE);
+ return CreateNewTCPSocket(instance, resource,
+ ppapi::TCP_SOCKET_VERSION_PRIVATE);
}
if (message.type() == PpapiHostMsg_UDPSocket_CreatePrivate::ID) {
if (CanCreateSocket()) {
scoped_refptr<ResourceMessageFilter> udp_socket(
new PepperUDPSocketMessageFilter(host_, instance, true));
return scoped_ptr<ResourceHost>(new MessageFilterHost(
- host_->GetPpapiHost(), instance, params.pp_resource(), udp_socket));
+ host_->GetPpapiHost(), instance, resource, udp_socket));
} else {
return scoped_ptr<ResourceHost>();
}
}
if (message.type() == PpapiHostMsg_NetworkMonitor_Create::ID) {
return scoped_ptr<ResourceHost>(
- new PepperNetworkMonitorHost(host_, instance, params.pp_resource()));
+ new PepperNetworkMonitorHost(host_, instance, resource));
}
// Flash interfaces.
@@ -222,11 +213,8 @@ scoped_ptr<ResourceHost> ContentBrowserPepperHostFactory::CreateResourceHost(
case PpapiHostMsg_FlashFile_Create::ID: {
scoped_refptr<ResourceMessageFilter> file_filter(
new PepperFlashFileMessageFilter(instance, host_));
- return scoped_ptr<ResourceHost>(
- new MessageFilterHost(host_->GetPpapiHost(),
- instance,
- params.pp_resource(),
- file_filter));
+ return scoped_ptr<ResourceHost>(new MessageFilterHost(
+ host_->GetPpapiHost(), instance, resource, file_filter));
}
}
}
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 84161f3392d..dffa7fe83db 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
@@ -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_PEPPER_CONTENT_BROWSER_PEPPER_HOST_FACTORY_H_
-#define CONTENT_BROWSER_PEPPER_CONTENT_BROWSER_PEPPER_HOST_FACTORY_H_
+#ifndef CONTENT_BROWSER_RENDERER_HOST_PEPPER_CONTENT_BROWSER_PEPPER_HOST_FACTORY_H_
+#define CONTENT_BROWSER_RENDERER_HOST_PEPPER_CONTENT_BROWSER_PEPPER_HOST_FACTORY_H_
#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
@@ -30,7 +30,7 @@ class ContentBrowserPepperHostFactory : public ppapi::host::HostFactory {
scoped_ptr<ppapi::host::ResourceHost> CreateResourceHost(
ppapi::host::PpapiHost* host,
- const ppapi::proxy::ResourceMessageCallParams& params,
+ PP_Resource resource,
PP_Instance instance,
const IPC::Message& message) override;
@@ -57,4 +57,4 @@ class ContentBrowserPepperHostFactory : public ppapi::host::HostFactory {
} // namespace content
-#endif // CONTENT_BROWSER_PEPPER_CONTENT_BROWSER_PEPPER_HOST_FACTORY_H_
+#endif // CONTENT_BROWSER_RENDERER_HOST_PEPPER_CONTENT_BROWSER_PEPPER_HOST_FACTORY_H_
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 31850f85171..78228911867 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
@@ -477,7 +477,7 @@ bool PepperFileIOHost::AddFileToReplyContext(
int32_t open_flags,
ppapi::host::ReplyMessageContext* reply_context) const {
base::ProcessId plugin_process_id =
- base::GetProcId(browser_ppapi_host_->GetPluginProcessHandle());
+ base::GetProcId(browser_ppapi_host_->GetPluginProcess().Handle());
if (plugin_process_id == base::kNullProcessId)
plugin_process_id = resolved_render_process_id_;
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 36f7dba09a4..bae9a54b6cf 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
@@ -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_RENDERER_PEPPER_PEPPER_FILE_IO_HOST_H_
-#define CONTENT_RENDERER_PEPPER_PEPPER_FILE_IO_HOST_H_
+#ifndef CONTENT_BROWSER_RENDERER_HOST_PEPPER_PEPPER_FILE_IO_HOST_H_
+#define CONTENT_BROWSER_RENDERER_HOST_PEPPER_PEPPER_FILE_IO_HOST_H_
#include <string>
@@ -139,4 +139,4 @@ class PepperFileIOHost : public ppapi::host::ResourceHost,
} // namespace content
-#endif // CONTENT_RENDERER_PEPPER_PEPPER_FILE_IO_HOST_H_
+#endif // CONTENT_BROWSER_RENDERER_HOST_PEPPER_PEPPER_FILE_IO_HOST_H_
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 5452bafc09c..48da55d5ae7 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
@@ -42,7 +42,7 @@ bool CanCreateReadWrite(int process_id, const base::FilePath& path) {
PepperFlashFileMessageFilter::PepperFlashFileMessageFilter(
PP_Instance instance,
BrowserPpapiHost* host)
- : plugin_process_handle_(host->GetPluginProcessHandle()) {
+ : plugin_process_(host->GetPluginProcess().Duplicate()) {
int unused;
host->GetRenderFrameIDsForInstance(instance, &render_process_id_, &unused);
base::FilePath profile_data_directory = host->GetProfileDataDirectory();
@@ -134,7 +134,7 @@ int32_t PepperFlashFileMessageFilter::OnOpenFile(
}
IPC::PlatformFileForTransit transit_file =
- IPC::TakeFileHandleForProcess(file.Pass(), plugin_process_handle_);
+ IPC::TakeFileHandleForProcess(file.Pass(), plugin_process_.Handle());
ppapi::host::ReplyMessageContext reply_context =
context->MakeReplyMessageContext();
reply_context.params.AppendHandle(ppapi::proxy::SerializedHandle(
@@ -256,7 +256,7 @@ int32_t PepperFlashFileMessageFilter::OnCreateTemporaryFile(
return ppapi::FileErrorToPepperError(file.error_details());
IPC::PlatformFileForTransit transit_file =
- IPC::TakeFileHandleForProcess(file.Pass(), plugin_process_handle_);
+ IPC::TakeFileHandleForProcess(file.Pass(), plugin_process_.Handle());
ppapi::host::ReplyMessageContext reply_context =
context->MakeReplyMessageContext();
reply_context.params.AppendHandle(ppapi::proxy::SerializedHandle(
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 301f97e9632..fa6bb6ff9b8 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
@@ -75,7 +75,7 @@ class PepperFlashFileMessageFilter : public ppapi::host::ResourceMessageFilter {
base::FilePath plugin_data_directory_;
int render_process_id_;
- base::ProcessHandle plugin_process_handle_;
+ base::Process plugin_process_;
DISALLOW_COPY_AND_ASSIGN(PepperFlashFileMessageFilter);
};
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_gamepad_host.cc b/chromium/content/browser/renderer_host/pepper/pepper_gamepad_host.cc
index 21d02d9bec8..e7a0aa79516 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_gamepad_host.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_gamepad_host.cc
@@ -72,7 +72,7 @@ void PepperGamepadHost::GotUserGesture(
const ppapi::host::ReplyMessageContext& context) {
base::SharedMemoryHandle handle =
gamepad_service_->GetSharedMemoryHandleForProcess(
- browser_ppapi_host_->GetPluginProcessHandle());
+ browser_ppapi_host_->GetPluginProcess().Handle());
context.params.AppendHandle(ppapi::proxy::SerializedHandle(
handle, sizeof(ppapi::ContentGamepadHardwareBuffer)));
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 b5787e170b5..0329e2ee950 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
@@ -51,9 +51,9 @@ inline ptrdiff_t AddressDiff(const void* a, const void* b) {
// code can see both definitions so we do the validation here.
TEST_F(PepperGamepadHostTest, ValidateHardwareBuffersMatch) {
// Hardware buffer.
- COMPILE_ASSERT(sizeof(ppapi::ContentGamepadHardwareBuffer) ==
- sizeof(GamepadHardwareBuffer),
- gamepad_hardware_buffers_must_match);
+ static_assert(sizeof(ppapi::ContentGamepadHardwareBuffer) ==
+ sizeof(GamepadHardwareBuffer),
+ "gamepad hardware buffers must match");
ppapi::ContentGamepadHardwareBuffer ppapi_buf;
GamepadHardwareBuffer content_buf;
EXPECT_EQ(AddressDiff(&content_buf.sequence, &content_buf),
@@ -64,8 +64,8 @@ TEST_F(PepperGamepadHostTest, ValidateHardwareBuffersMatch) {
TEST_F(PepperGamepadHostTest, ValidateGamepadsMatch) {
// Gamepads.
- COMPILE_ASSERT(sizeof(ppapi::WebKitGamepads) == sizeof(blink::WebGamepads),
- gamepads_data_must_match);
+ static_assert(sizeof(ppapi::WebKitGamepads) == sizeof(blink::WebGamepads),
+ "gamepads data must match");
ppapi::WebKitGamepads ppapi_gamepads;
blink::WebGamepads web_gamepads;
EXPECT_EQ(AddressDiff(&web_gamepads.length, &web_gamepads),
@@ -84,8 +84,8 @@ TEST_F(PepperGamepadHostTest, ValidateGamepadsMatch) {
TEST_F(PepperGamepadHostTest, ValidateGamepadMatch) {
// Gamepad.
- COMPILE_ASSERT(sizeof(ppapi::WebKitGamepad) == sizeof(blink::WebGamepad),
- gamepad_data_must_match);
+ static_assert(sizeof(ppapi::WebKitGamepad) == sizeof(blink::WebGamepad),
+ "gamepad data must match");
ppapi::WebKitGamepad ppapi_gamepad;
blink::WebGamepad web_gamepad;
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 36b006c8075..de06ef321a9 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
@@ -105,7 +105,7 @@ TEST_F(PepperPrintingHostTest, GetDefaultPrintSettings) {
reply_msg_param;
ASSERT_TRUE(PpapiPluginMsg_Printing_GetDefaultPrintSettingsReply::Read(
&reply_msg, &reply_msg_param));
- PP_PrintSettings_Dev actual_settings = reply_msg_param.a;
+ PP_PrintSettings_Dev actual_settings = get<0>(reply_msg_param);
EXPECT_TRUE(PP_RectEqual(expected_settings.printable_area,
actual_settings.printable_area));
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_renderer_connection.cc b/chromium/content/browser/renderer_host/pepper/pepper_renderer_connection.cc
index 8c233bbc6a7..ead65473e3f 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_renderer_connection.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_renderer_connection.cc
@@ -208,7 +208,7 @@ void PepperRendererConnection::OnMsgCreateResourceHostsFromHost(
if (!resource_host.get()) {
resource_host = host->GetPpapiHost()->CreateResourceHost(
- params, instance, nested_msg);
+ params.pp_resource(), instance, nested_msg);
}
if (resource_host.get())
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_socket_utils.cc b/chromium/content/browser/renderer_host/pepper/pepper_socket_utils.cc
index dda97a1718b..45d35ce4160 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_socket_utils.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_socket_utils.cc
@@ -28,7 +28,7 @@ SocketPermissionRequest CreateSocketPermissionRequest(
const PP_NetAddress_Private& net_addr) {
std::string host =
ppapi::NetAddressPrivateImpl::DescribeNetAddress(net_addr, false);
- int port = 0;
+ uint16 port = 0;
std::vector<unsigned char> address;
ppapi::NetAddressPrivateImpl::NetAddressToIPEndPoint(
net_addr, &address, &port);
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc b/chromium/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc
index 87ba64f54c1..0093c720863 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc
@@ -163,7 +163,7 @@ void PepperTCPServerSocketMessageFilter::DoListen(
DCHECK_CURRENTLY_ON(BrowserThread::IO);
net::IPAddressNumber address;
- int port;
+ uint16 port;
if (state_ != STATE_BEFORE_LISTENING ||
!NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &address, &port)) {
SendListenError(context, PP_ERROR_FAILED);
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_tcp_socket.cc b/chromium/content/browser/renderer_host/pepper/pepper_tcp_socket.cc
index 474a2fd6bd5..8d590f77adb 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_tcp_socket.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_tcp_socket.cc
@@ -107,7 +107,7 @@ void PepperTCPSocket::ConnectWithNetAddress(
}
net::IPAddressNumber address;
- int port;
+ uint16 port;
if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(
net_addr, &address, &port)) {
SendConnectACKError(PP_ERROR_ADDRESS_INVALID);
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc b/chromium/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc
index 38248f42341..aa63ab16308 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc
@@ -7,9 +7,11 @@
#include <cstring>
#include "base/bind.h"
+#include "base/location.h"
#include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/profiler/scoped_tracker.h"
#include "build/build_config.h"
-#include "content/browser/renderer_host/pepper/browser_ppapi_host_impl.h"
#include "content/browser/renderer_host/pepper/content_browser_pepper_host_factory.h"
#include "content/browser/renderer_host/pepper/pepper_socket_utils.h"
#include "content/public/browser/browser_context.h"
@@ -57,18 +59,24 @@ PepperTCPSocketMessageFilter::PepperTCPSocketMessageFilter(
external_plugin_(host->external_plugin()),
render_process_id_(0),
render_frame_id_(0),
- ppapi_host_(host->GetPpapiHost()),
+ host_(host),
factory_(factory),
instance_(instance),
state_(TCPSocketState::INITIAL),
end_of_file_reached_(false),
bind_input_addr_(NetAddressPrivateImpl::kInvalidNetAddress),
+ socket_options_(SOCKET_OPTION_NODELAY),
+ rcvbuf_size_(0),
+ sndbuf_size_(0),
address_index_(0),
socket_(new net::TCPSocket(NULL, net::NetLog::Source())),
ssl_context_helper_(host->ssl_context_helper()),
- pending_accept_(false) {
+ pending_accept_(false),
+ pending_read_on_unthrottle_(false),
+ pending_read_net_result_(0) {
DCHECK(host);
++g_num_instances;
+ host_->AddInstanceObserver(instance_, this);
if (!host->GetRenderFrameIDsForInstance(
instance, &render_process_id_, &render_frame_id_)) {
NOTREACHED();
@@ -84,20 +92,26 @@ PepperTCPSocketMessageFilter::PepperTCPSocketMessageFilter(
external_plugin_(host->external_plugin()),
render_process_id_(0),
render_frame_id_(0),
- ppapi_host_(host->GetPpapiHost()),
+ host_(host),
factory_(NULL),
instance_(instance),
state_(TCPSocketState::CONNECTED),
end_of_file_reached_(false),
bind_input_addr_(NetAddressPrivateImpl::kInvalidNetAddress),
+ socket_options_(SOCKET_OPTION_NODELAY),
+ rcvbuf_size_(0),
+ sndbuf_size_(0),
address_index_(0),
socket_(socket.Pass()),
ssl_context_helper_(host->ssl_context_helper()),
- pending_accept_(false) {
+ pending_accept_(false),
+ pending_read_on_unthrottle_(false),
+ pending_read_net_result_(0) {
DCHECK(host);
DCHECK_NE(version, ppapi::TCP_SOCKET_VERSION_1_0);
++g_num_instances;
+ host_->AddInstanceObserver(instance_, this);
if (!host->GetRenderFrameIDsForInstance(
instance, &render_process_id_, &render_frame_id_)) {
NOTREACHED();
@@ -105,6 +119,8 @@ PepperTCPSocketMessageFilter::PepperTCPSocketMessageFilter(
}
PepperTCPSocketMessageFilter::~PepperTCPSocketMessageFilter() {
+ if (host_)
+ host_->RemoveInstanceObserver(instance_, this);
if (socket_)
socket_->Close();
if (ssl_socket_)
@@ -163,6 +179,21 @@ int32_t PepperTCPSocketMessageFilter::OnResourceMessageReceived(
return PP_ERROR_FAILED;
}
+void PepperTCPSocketMessageFilter::OnThrottleStateChanged(bool is_throttled) {
+ if (pending_read_on_unthrottle_ && !is_throttled) {
+ DCHECK(read_buffer_);
+ OnReadCompleted(pending_read_reply_message_context_,
+ pending_read_net_result_);
+ DCHECK(!read_buffer_);
+ pending_read_on_unthrottle_ = false;
+ }
+}
+
+void PepperTCPSocketMessageFilter::OnHostDestroyed() {
+ host_->RemoveInstanceObserver(instance_, this);
+ host_ = nullptr;
+}
+
int32_t PepperTCPSocketMessageFilter::OnMsgBind(
const ppapi::host::HostMessageContext* context,
const PP_NetAddress_Private& net_addr) {
@@ -456,35 +487,57 @@ int32_t PepperTCPSocketMessageFilter::OnMsgSetOption(
switch (name) {
case PP_TCPSOCKET_OPTION_NO_DELAY: {
- if (state_.state() != TCPSocketState::CONNECTED)
- return PP_ERROR_FAILED;
-
bool boolean_value = false;
if (!value.GetBool(&boolean_value))
return PP_ERROR_BADARGUMENT;
- return socket_->SetNoDelay(boolean_value) ? PP_OK : PP_ERROR_FAILED;
+
+ // If the socket is already connected, proxy the value to TCPSocket.
+ if (state_.state() == TCPSocketState::CONNECTED)
+ return socket_->SetNoDelay(boolean_value) ? PP_OK : PP_ERROR_FAILED;
+
+ // TCPSocket instance is not yet created. So remember the value here.
+ if (boolean_value) {
+ socket_options_ |= SOCKET_OPTION_NODELAY;
+ } else {
+ socket_options_ &= ~SOCKET_OPTION_NODELAY;
+ }
+ return PP_OK;
+ }
+ case PP_TCPSOCKET_OPTION_SEND_BUFFER_SIZE: {
+ int32_t integer_value = 0;
+ if (!value.GetInt32(&integer_value) ||
+ integer_value <= 0 ||
+ integer_value > TCPSocketResourceBase::kMaxSendBufferSize)
+ return PP_ERROR_BADARGUMENT;
+
+ // If the socket is already connected, proxy the value to TCPSocket.
+ if (state_.state() == TCPSocketState::CONNECTED) {
+ return NetErrorToPepperError(
+ socket_->SetSendBufferSize(integer_value));
+ }
+
+ // TCPSocket instance is not yet created. So remember the value here.
+ socket_options_ |= SOCKET_OPTION_SNDBUF_SIZE;
+ sndbuf_size_ = integer_value;
+ return PP_OK;
}
- case PP_TCPSOCKET_OPTION_SEND_BUFFER_SIZE:
case PP_TCPSOCKET_OPTION_RECV_BUFFER_SIZE: {
- if (state_.state() != TCPSocketState::CONNECTED)
- return PP_ERROR_FAILED;
-
int32_t integer_value = 0;
- if (!value.GetInt32(&integer_value) || integer_value <= 0)
+ if (!value.GetInt32(&integer_value) ||
+ integer_value <= 0 ||
+ integer_value > TCPSocketResourceBase::kMaxReceiveBufferSize)
return PP_ERROR_BADARGUMENT;
- int net_result = net::ERR_UNEXPECTED;
- if (name == PP_TCPSOCKET_OPTION_SEND_BUFFER_SIZE) {
- if (integer_value > TCPSocketResourceBase::kMaxSendBufferSize)
- return PP_ERROR_BADARGUMENT;
- net_result = socket_->SetSendBufferSize(integer_value);
- } else {
- if (integer_value > TCPSocketResourceBase::kMaxReceiveBufferSize)
- return PP_ERROR_BADARGUMENT;
- net_result = socket_->SetReceiveBufferSize(integer_value);
+ // If the socket is already connected, proxy the value to TCPSocket.
+ if (state_.state() == TCPSocketState::CONNECTED) {
+ return NetErrorToPepperError(
+ socket_->SetReceiveBufferSize(integer_value));
}
- // TODO(wtc): Add error mapping code.
- return (net_result == net::OK) ? PP_OK : PP_ERROR_FAILED;
+
+ // TCPSocket instance is not yet created. So remember the value here.
+ socket_options_ |= SOCKET_OPTION_RCVBUF_SIZE;
+ rcvbuf_size_ = integer_value;
+ return PP_OK;
}
default: {
NOTREACHED();
@@ -510,7 +563,7 @@ void PepperTCPSocketMessageFilter::DoBind(
int pp_result = PP_OK;
do {
net::IPAddressNumber address;
- int port;
+ uint16 port;
if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(
net_addr, &address, &port)) {
pp_result = PP_ERROR_ADDRESS_INVALID;
@@ -600,7 +653,7 @@ void PepperTCPSocketMessageFilter::DoConnectWithNetAddress(
state_.SetPendingTransition(TCPSocketState::CONNECT);
net::IPAddressNumber address;
- int port;
+ uint16 port;
if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(
net_addr, &address, &port)) {
state_.CompletePendingTransition(false);
@@ -690,17 +743,42 @@ void PepperTCPSocketMessageFilter::StartConnect(
DCHECK(state_.IsPending(TCPSocketState::CONNECT));
DCHECK_LT(address_index_, address_list_.size());
- int net_result = net::OK;
- if (!socket_->IsValid())
- net_result = socket_->Open(address_list_[address_index_].GetFamily());
+ if (!socket_->IsValid()) {
+ int net_result = socket_->Open(address_list_[address_index_].GetFamily());
+ if (net_result != net::OK) {
+ OnConnectCompleted(context, net_result);
+ return;
+ }
+ }
+
+ socket_->SetDefaultOptionsForClient();
- if (net_result == net::OK) {
- net_result = socket_->Connect(
- address_list_[address_index_],
- base::Bind(&PepperTCPSocketMessageFilter::OnConnectCompleted,
- base::Unretained(this),
- context));
+ if (!(socket_options_ & SOCKET_OPTION_NODELAY)) {
+ if (!socket_->SetNoDelay(false)) {
+ OnConnectCompleted(context, net::ERR_FAILED);
+ return;
+ }
+ }
+ if (socket_options_ & SOCKET_OPTION_RCVBUF_SIZE) {
+ int net_result = socket_->SetReceiveBufferSize(rcvbuf_size_);
+ if (net_result != net::OK) {
+ OnConnectCompleted(context, net_result);
+ return;
+ }
}
+ if (socket_options_ & SOCKET_OPTION_SNDBUF_SIZE) {
+ int net_result = socket_->SetSendBufferSize(sndbuf_size_);
+ if (net_result != net::OK) {
+ OnConnectCompleted(context, net_result);
+ return;
+ }
+ }
+
+ int net_result = socket_->Connect(
+ address_list_[address_index_],
+ base::Bind(&PepperTCPSocketMessageFilter::OnConnectCompleted,
+ base::Unretained(this),
+ context));
if (net_result != net::ERR_IO_PENDING)
OnConnectCompleted(context, net_result);
}
@@ -710,6 +788,11 @@ void PepperTCPSocketMessageFilter::OnConnectCompleted(
int net_result) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ // TODO(rvargas): Remove ScopedTracker below once crbug.com/462784 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "462784 PepperTCPSocketMessageFilter::OnConnectCompleted"));
+
if (!state_.IsPending(TCPSocketState::CONNECT)) {
DCHECK(state_.state() == TCPSocketState::CLOSED);
SendConnectError(context, PP_ERROR_FAILED);
@@ -748,7 +831,6 @@ void PepperTCPSocketMessageFilter::OnConnectCompleted(
break;
}
- socket_->SetDefaultOptionsForClient();
SendConnectReply(context, PP_OK, local_addr, remote_addr);
state_.CompletePendingTransition(true);
return;
@@ -799,6 +881,13 @@ void PepperTCPSocketMessageFilter::OnReadCompleted(
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(read_buffer_.get());
+ if (host_ && host_->IsThrottled(instance_)) {
+ pending_read_on_unthrottle_ = true;
+ pending_read_reply_message_context_ = context;
+ pending_read_net_result_ = net_result;
+ return;
+ }
+
if (net_result > 0) {
SendReadReply(
context, PP_OK, std::string(read_buffer_->data(), net_result));
@@ -884,7 +973,8 @@ void PepperTCPSocketMessageFilter::OnAcceptCompleted(
SendAcceptError(context, PP_ERROR_NOSPACE);
return;
}
- int pending_host_id = ppapi_host_->AddPendingResourceHost(host.Pass());
+ int pending_host_id =
+ host_->GetPpapiHost()->AddPendingResourceHost(host.Pass());
if (pending_host_id)
SendAcceptReply(context, PP_OK, pending_host_id, local_addr, remote_addr);
else
@@ -911,6 +1001,9 @@ void PepperTCPSocketMessageFilter::SendConnectReply(
int32_t pp_result,
const PP_NetAddress_Private& local_addr,
const PP_NetAddress_Private& remote_addr) {
+ UMA_HISTOGRAM_BOOLEAN("Pepper.PluginContextSecurity.TCPConnect",
+ host_->IsPotentiallySecurePluginContext(instance_));
+
ppapi::host::ReplyMessageContext reply_context(context);
reply_context.params.set_result(pp_result);
SendReply(reply_context,
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 7c9250f4899..3e8aea68228 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
@@ -12,6 +12,7 @@
#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+#include "content/browser/renderer_host/pepper/browser_ppapi_host_impl.h"
#include "content/browser/renderer_host/pepper/ssl_context_helper.h"
#include "content/common/content_export.h"
#include "net/base/address_list.h"
@@ -47,7 +48,8 @@ class ContentBrowserPepperHostFactory;
class ResourceContext;
class CONTENT_EXPORT PepperTCPSocketMessageFilter
- : public ppapi::host::ResourceMessageFilter {
+ : public ppapi::host::ResourceMessageFilter,
+ public BrowserPpapiHostImpl::InstanceObserver {
public:
PepperTCPSocketMessageFilter(ContentBrowserPepperHostFactory* factory,
BrowserPpapiHostImpl* host,
@@ -63,6 +65,12 @@ class CONTENT_EXPORT PepperTCPSocketMessageFilter
static size_t GetNumInstances();
private:
+ enum SocketOption {
+ SOCKET_OPTION_NODELAY = 1 << 0,
+ SOCKET_OPTION_RCVBUF_SIZE = 1 << 1,
+ SOCKET_OPTION_SNDBUF_SIZE = 1 << 2
+ };
+
~PepperTCPSocketMessageFilter() override;
// ppapi::host::ResourceMessageFilter overrides.
@@ -72,6 +80,10 @@ class CONTENT_EXPORT PepperTCPSocketMessageFilter
const IPC::Message& msg,
ppapi::host::HostMessageContext* context) override;
+ // BrowserPpapiHostImpl::InstanceObserver overrides.
+ void OnThrottleStateChanged(bool is_throttled) override;
+ void OnHostDestroyed() override;
+
int32_t OnMsgBind(const ppapi::host::HostMessageContext* context,
const PP_NetAddress_Private& net_addr);
int32_t OnMsgConnect(const ppapi::host::HostMessageContext* context,
@@ -170,7 +182,7 @@ class CONTENT_EXPORT PepperTCPSocketMessageFilter
// The following fields are used only on the IO thread.
// Non-owning ptr.
- ppapi::host::PpapiHost* ppapi_host_;
+ BrowserPpapiHostImpl* host_;
// Non-owning ptr.
ContentBrowserPepperHostFactory* factory_;
PP_Instance instance_;
@@ -185,6 +197,14 @@ class CONTENT_EXPORT PepperTCPSocketMessageFilter
scoped_ptr<net::SingleRequestHostResolver> resolver_;
+ // Bitwise-or of SocketOption flags. This stores the state about whether
+ // each option is set before Connect() is called.
+ int socket_options_;
+
+ // Locally cached value of buffer size.
+ int32_t rcvbuf_size_;
+ int32_t sndbuf_size_;
+
// |address_list_| may store multiple addresses when
// PPB_TCPSocket_Private.Connect() is used, which involves name resolution.
// In that case, we will try each address in the list until a connection is
@@ -212,6 +232,12 @@ class CONTENT_EXPORT PepperTCPSocketMessageFilter
scoped_ptr<net::TCPSocket> accepted_socket_;
net::IPEndPoint accepted_address_;
+ // If the plugin is throttled, we defer completing socket reads until
+ // the plugin is unthrottled.
+ bool pending_read_on_unthrottle_;
+ ppapi::host::ReplyMessageContext pending_read_reply_message_context_;
+ int pending_read_net_result_;
+
DISALLOW_COPY_AND_ASSIGN(PepperTCPSocketMessageFilter);
};
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 158d8ea9de1..e271dbbb08a 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
@@ -76,7 +76,9 @@ void GetFontsInFamily_SlowBlocking(const std::string& family,
memset(&logfont, 0, sizeof(logfont));
logfont.lfCharSet = DEFAULT_CHARSET;
base::string16 family16 = base::UTF8ToUTF16(family);
- memcpy(&logfont.lfFaceName, &family16[0], sizeof(logfont.lfFaceName));
+ // Copy the family name, leaving room for a terminating null (already set
+ // since we zeroed the whole struct above.)
+ family16.copy(logfont.lfFaceName, LF_FACESIZE - 1);
base::win::ScopedCreateDC hdc(::CreateCompatibleDC(NULL));
::EnumFontFamiliesExW(hdc.Get(),
&logfont,
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
index 6eb36a1e358..633a3266e1b 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_truetype_font_win.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_truetype_font_win.cc
@@ -26,16 +26,15 @@ class PepperTrueTypeFontWin : public PepperTrueTypeFont {
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;
+ 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:
- virtual ~PepperTrueTypeFontWin();
+ ~PepperTrueTypeFontWin() override;
DWORD GetFontData(HDC hdc,
DWORD table,
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 26c0e44ee34..0d377768419 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
@@ -8,15 +8,18 @@
#include "base/compiler_specific.h"
#include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
#include "content/browser/renderer_host/pepper/browser_ppapi_host_impl.h"
#include "content/browser/renderer_host/pepper/pepper_socket_utils.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/content_browser_client.h"
#include "content/public/common/process_type.h"
#include "content/public/common/socket_permission_request.h"
#include "ipc/ipc_message_macros.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
-#include "net/udp/udp_server_socket.h"
+#include "net/base/rand_callback.h"
+#include "net/udp/udp_socket.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/c/private/ppb_net_address_private.h"
#include "ppapi/host/dispatch_host_message.h"
@@ -25,12 +28,15 @@
#include "ppapi/host/ppapi_host.h"
#include "ppapi/host/resource_host.h"
#include "ppapi/proxy/ppapi_messages.h"
+#include "ppapi/proxy/udp_socket_filter.h"
#include "ppapi/proxy/udp_socket_resource_base.h"
#include "ppapi/shared_impl/private/net_address_private_impl.h"
#include "ppapi/shared_impl/socket_option_data.h"
using ppapi::NetAddressPrivateImpl;
using ppapi::host::NetErrorToPepperError;
+using ppapi::proxy::UDPSocketFilter;
+using ppapi::proxy::UDPSocketResourceBase;
namespace {
@@ -40,15 +46,29 @@ size_t g_num_instances = 0;
namespace content {
+PepperUDPSocketMessageFilter::PendingSend::PendingSend(
+ const net::IPAddressNumber& address,
+ int port,
+ const scoped_refptr<net::IOBufferWithSize>& buffer,
+ const ppapi::host::ReplyMessageContext& context)
+ : address(address), port(port), buffer(buffer), context(context) {
+}
+
+PepperUDPSocketMessageFilter::PendingSend::~PendingSend() {
+}
+
PepperUDPSocketMessageFilter::PepperUDPSocketMessageFilter(
BrowserPpapiHostImpl* host,
PP_Instance instance,
bool private_api)
- : allow_address_reuse_(false),
- allow_broadcast_(false),
+ : host_(host),
+ socket_options_(0),
+ rcvbuf_size_(0),
+ sndbuf_size_(0),
+ multicast_ttl_(0),
+ can_use_multicast_(PP_ERROR_FAILED),
closed_(false),
- remaining_recv_slots_(
- ppapi::proxy::UDPSocketResourceBase::kPluginReceiveBufferSlots),
+ remaining_recv_slots_(UDPSocketFilter::kPluginReceiveBufferSlots),
external_plugin_(host->external_plugin()),
private_api_(private_api),
render_process_id_(0),
@@ -82,6 +102,8 @@ PepperUDPSocketMessageFilter::OverrideTaskRunnerForMessage(
return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
case PpapiHostMsg_UDPSocket_Bind::ID:
case PpapiHostMsg_UDPSocket_SendTo::ID:
+ case PpapiHostMsg_UDPSocket_JoinGroup::ID:
+ case PpapiHostMsg_UDPSocket_LeaveGroup::ID:
return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
}
return NULL;
@@ -100,6 +122,10 @@ int32_t PepperUDPSocketMessageFilter::OnResourceMessageReceived(
OnMsgClose)
PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
PpapiHostMsg_UDPSocket_RecvSlotAvailable, OnMsgRecvSlotAvailable)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_UDPSocket_JoinGroup,
+ OnMsgJoinGroup)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_UDPSocket_LeaveGroup,
+ OnMsgLeaveGroup)
PPAPI_END_MESSAGE_MAP()
return PP_ERROR_FAILED;
}
@@ -114,10 +140,11 @@ int32_t PepperUDPSocketMessageFilter::OnMsgSetOption(
return PP_ERROR_FAILED;
switch (name) {
- case PP_UDPSOCKET_OPTION_ADDRESS_REUSE:
- case PP_UDPSOCKET_OPTION_BROADCAST: {
+ case PP_UDPSOCKET_OPTION_ADDRESS_REUSE: {
if (socket_.get()) {
- // They only take effect before the socket is bound.
+ // AllowReuseAddress is only effective before Bind().
+ // Note that this limitation originally comes from Windows, but
+ // PPAPI tries to provide platform independent APIs.
return PP_ERROR_FAILED;
}
@@ -125,38 +152,105 @@ int32_t PepperUDPSocketMessageFilter::OnMsgSetOption(
if (!value.GetBool(&boolean_value))
return PP_ERROR_BADARGUMENT;
- if (name == PP_UDPSOCKET_OPTION_ADDRESS_REUSE)
- allow_address_reuse_ = boolean_value;
- else
- allow_broadcast_ = boolean_value;
+ if (boolean_value) {
+ socket_options_ |= SOCKET_OPTION_ADDRESS_REUSE;
+ } else {
+ socket_options_ &= ~SOCKET_OPTION_ADDRESS_REUSE;
+ }
return PP_OK;
}
- case PP_UDPSOCKET_OPTION_SEND_BUFFER_SIZE:
- case PP_UDPSOCKET_OPTION_RECV_BUFFER_SIZE: {
- if (!socket_.get()) {
- // They only take effect after the socket is bound.
- return PP_ERROR_FAILED;
+ case PP_UDPSOCKET_OPTION_BROADCAST: {
+ bool boolean_value = false;
+ if (!value.GetBool(&boolean_value))
+ return PP_ERROR_BADARGUMENT;
+
+ // If the socket is already bound, proxy the value to UDPSocket.
+ if (socket_.get())
+ return NetErrorToPepperError(socket_->SetBroadcast(boolean_value));
+
+ // UDPSocket instance is not yet created, so remember the value here.
+ if (boolean_value) {
+ socket_options_ |= SOCKET_OPTION_BROADCAST;
+ } else {
+ socket_options_ &= ~SOCKET_OPTION_BROADCAST;
}
+ return PP_OK;
+ }
+ case PP_UDPSOCKET_OPTION_SEND_BUFFER_SIZE: {
+ int32_t integer_value = 0;
+ if (!value.GetInt32(&integer_value) || integer_value <= 0 ||
+ integer_value > UDPSocketResourceBase::kMaxSendBufferSize)
+ return PP_ERROR_BADARGUMENT;
+
+ // If the socket is already bound, proxy the value to UDPSocket.
+ if (socket_.get()) {
+ return NetErrorToPepperError(
+ socket_->SetSendBufferSize(integer_value));
+ }
+
+ // UDPSocket instance is not yet created, so remember the value here.
+ socket_options_ |= SOCKET_OPTION_SNDBUF_SIZE;
+ sndbuf_size_ = integer_value;
+ return PP_OK;
+ }
+ case PP_UDPSOCKET_OPTION_RECV_BUFFER_SIZE: {
int32_t integer_value = 0;
- if (!value.GetInt32(&integer_value) || integer_value <= 0)
+ if (!value.GetInt32(&integer_value) || integer_value <= 0 ||
+ integer_value > UDPSocketFilter::kMaxReceiveBufferSize)
return PP_ERROR_BADARGUMENT;
- int net_result = net::ERR_UNEXPECTED;
- if (name == PP_UDPSOCKET_OPTION_SEND_BUFFER_SIZE) {
- if (integer_value >
- ppapi::proxy::UDPSocketResourceBase::kMaxSendBufferSize) {
- return PP_ERROR_BADARGUMENT;
- }
- net_result = socket_->SetSendBufferSize(integer_value);
+ // If the socket is already bound, proxy the value to UDPSocket.
+ if (socket_.get()) {
+ return NetErrorToPepperError(
+ socket_->SetReceiveBufferSize(integer_value));
+ }
+
+ // UDPSocket instance is not yet created, so remember the value here.
+ socket_options_ |= SOCKET_OPTION_RCVBUF_SIZE;
+ rcvbuf_size_ = integer_value;
+ return PP_OK;
+ }
+ case PP_UDPSOCKET_OPTION_MULTICAST_LOOP: {
+ bool boolean_value = false;
+ if (!value.GetBool(&boolean_value))
+ return PP_ERROR_BADARGUMENT;
+
+ // If the socket is already bound, proxy the value to UDPSocket.
+ if (socket_) {
+ if (can_use_multicast_ != PP_OK)
+ return can_use_multicast_;
+
+ return NetErrorToPepperError(
+ socket_->SetMulticastLoopbackMode(boolean_value));
+ }
+
+ // UDPSocket instance is not yet created, so remember the value here.
+ if (boolean_value) {
+ socket_options_ |= SOCKET_OPTION_MULTICAST_LOOP;
} else {
- if (integer_value >
- ppapi::proxy::UDPSocketResourceBase::kMaxReceiveBufferSize) {
- return PP_ERROR_BADARGUMENT;
- }
- net_result = socket_->SetReceiveBufferSize(integer_value);
+ socket_options_ &= ~SOCKET_OPTION_MULTICAST_LOOP;
+ }
+ return PP_OK;
+ }
+ case PP_UDPSOCKET_OPTION_MULTICAST_TTL: {
+ int32_t integer_value = 0;
+ if (!value.GetInt32(&integer_value) ||
+ integer_value < 0 || integer_value > 255)
+ return PP_ERROR_BADARGUMENT;
+
+ // If the socket is already bound, proxy the value to UDPSocket.
+ if (socket_) {
+ if (can_use_multicast_ != PP_OK)
+ return can_use_multicast_;
+
+ return NetErrorToPepperError(
+ socket_->SetMulticastTimeToLive(integer_value));
}
- // TODO(wtc): Add error mapping code.
- return (net_result == net::OK) ? PP_OK : PP_ERROR_FAILED;
+
+ // UDPSocket instance is not yet created, so remember the value here.
+ socket_options_ |= SOCKET_OPTION_MULTICAST_TTL;
+ multicast_ttl_ = integer_value;
+ return PP_OK;
}
default: {
NOTREACHED();
@@ -171,6 +265,12 @@ int32_t PepperUDPSocketMessageFilter::OnMsgBind(
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(context);
+ // Check for permissions to use multicast APIS. This check must be done while
+ // on the UI thread, so we cache the value here to be used later on.
+ PP_NetAddress_Private any_addr;
+ NetAddressPrivateImpl::GetAnyAddress(PP_FALSE, &any_addr);
+ can_use_multicast_ = CanUseMulticastAPI(any_addr);
+
SocketPermissionRequest request =
pepper_socket_utils::CreateSocketPermissionRequest(
SocketPermissionRequest::UDP_BIND, addr);
@@ -230,8 +330,7 @@ int32_t PepperUDPSocketMessageFilter::OnMsgRecvSlotAvailable(
const ppapi::host::HostMessageContext* context) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (remaining_recv_slots_ <
- ppapi::proxy::UDPSocketResourceBase::kPluginReceiveBufferSlots) {
+ if (remaining_recv_slots_ < UDPSocketFilter::kPluginReceiveBufferSlots) {
remaining_recv_slots_++;
}
@@ -243,6 +342,48 @@ int32_t PepperUDPSocketMessageFilter::OnMsgRecvSlotAvailable(
return PP_OK;
}
+int32_t PepperUDPSocketMessageFilter::OnMsgJoinGroup(
+ const ppapi::host::HostMessageContext* context,
+ const PP_NetAddress_Private& addr) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ int32_t ret = CanUseMulticastAPI(addr);
+ if (ret != PP_OK)
+ return ret;
+
+ if (!socket_)
+ return PP_ERROR_FAILED;
+
+ net::IPAddressNumber group;
+ uint16 port;
+
+ if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &group, &port))
+ return PP_ERROR_ADDRESS_INVALID;
+
+ return NetErrorToPepperError(socket_->JoinGroup(group));
+}
+
+int32_t PepperUDPSocketMessageFilter::OnMsgLeaveGroup(
+ const ppapi::host::HostMessageContext* context,
+ const PP_NetAddress_Private& addr) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ int32_t ret = CanUseMulticastAPI(addr);
+ if (ret != PP_OK)
+ return ret;
+
+ if (!socket_)
+ return PP_ERROR_FAILED;
+
+ net::IPAddressNumber group;
+ uint16 port;
+
+ if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &group, &port))
+ return PP_ERROR_ADDRESS_INVALID;
+
+ return NetErrorToPepperError(socket_->LeaveGroup(group));
+}
+
void PepperUDPSocketMessageFilter::DoBind(
const ppapi::host::ReplyMessageContext& context,
const PP_NetAddress_Private& addr) {
@@ -253,33 +394,93 @@ void PepperUDPSocketMessageFilter::DoBind(
return;
}
- scoped_ptr<net::UDPServerSocket> socket(
- new net::UDPServerSocket(NULL, net::NetLog::Source()));
+ scoped_ptr<net::UDPSocket> socket(new net::UDPSocket(
+ net::DatagramSocket::DEFAULT_BIND, net::RandIntCallback(),
+ NULL, net::NetLog::Source()));
net::IPAddressNumber address;
- int port;
+ uint16 port;
if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &address, &port)) {
SendBindError(context, PP_ERROR_ADDRESS_INVALID);
return;
}
+ net::IPEndPoint end_point(address, port);
+ {
+ int net_result = socket->Open(end_point.GetFamily());
+ if (net_result != net::OK) {
+ SendBindError(context, NetErrorToPepperError(net_result));
+ return;
+ }
+ }
+
+ if (socket_options_ & SOCKET_OPTION_ADDRESS_REUSE) {
+ int net_result = socket->AllowAddressReuse();
+ if (net_result != net::OK) {
+ SendBindError(context, NetErrorToPepperError(net_result));
+ return;
+ }
+ }
+ if (socket_options_ & SOCKET_OPTION_BROADCAST) {
+ int net_result = socket->SetBroadcast(true);
+ if (net_result != net::OK) {
+ SendBindError(context, NetErrorToPepperError(net_result));
+ return;
+ }
+ }
+ if (socket_options_ & SOCKET_OPTION_SNDBUF_SIZE) {
+ int net_result = socket->SetSendBufferSize(sndbuf_size_);
+ if (net_result != net::OK) {
+ SendBindError(context, NetErrorToPepperError(net_result));
+ return;
+ }
+ }
+ if (socket_options_ & SOCKET_OPTION_RCVBUF_SIZE) {
+ int net_result = socket->SetReceiveBufferSize(rcvbuf_size_);
+ if (net_result != net::OK) {
+ SendBindError(context, NetErrorToPepperError(net_result));
+ return;
+ }
+ }
+ if (socket_options_ & SOCKET_OPTION_MULTICAST_LOOP) {
+ if (can_use_multicast_ != PP_OK) {
+ SendBindError(context, NetErrorToPepperError(can_use_multicast_));
+ return;
+ }
- if (allow_address_reuse_)
- socket->AllowAddressReuse();
- if (allow_broadcast_)
- socket->AllowBroadcast();
+ int net_result = socket->SetMulticastLoopbackMode(true);
+ if (net_result != net::OK) {
+ SendBindError(context, NetErrorToPepperError(net_result));
+ return;
+ }
+ }
+ if (socket_options_ & SOCKET_OPTION_MULTICAST_TTL) {
+ if (can_use_multicast_ != PP_OK) {
+ SendBindError(context, NetErrorToPepperError(can_use_multicast_));
+ return;
+ }
- int32_t pp_result =
- NetErrorToPepperError(socket->Listen(net::IPEndPoint(address, port)));
- if (pp_result != PP_OK) {
- SendBindError(context, pp_result);
- return;
+ int net_result = socket->SetMulticastTimeToLive(multicast_ttl_);
+ if (net_result != net::OK) {
+ SendBindError(context, NetErrorToPepperError(net_result));
+ return;
+ }
+ }
+
+ {
+ int net_result = socket->Bind(end_point);
+ if (net_result != net::OK) {
+ SendBindError(context, NetErrorToPepperError(net_result));
+ return;
+ }
}
net::IPEndPoint bound_address;
- pp_result = NetErrorToPepperError(socket->GetLocalAddress(&bound_address));
- if (pp_result != PP_OK) {
- SendBindError(context, pp_result);
- return;
+ {
+ int net_result = socket->GetLocalAddress(&bound_address);
+ if (net_result != net::OK) {
+ SendBindError(context, NetErrorToPepperError(net_result));
+ return;
+ }
}
PP_NetAddress_Private net_address = NetAddressPrivateImpl::kInvalidNetAddress;
@@ -289,8 +490,6 @@ void PepperUDPSocketMessageFilter::DoBind(
return;
}
- allow_address_reuse_ = false;
- allow_broadcast_ = false;
socket_.swap(socket);
SendBindReply(context, PP_OK, net_address);
@@ -304,8 +503,7 @@ void PepperUDPSocketMessageFilter::DoRecvFrom() {
DCHECK(!recvfrom_buffer_.get());
DCHECK_GT(remaining_recv_slots_, 0u);
- recvfrom_buffer_ = new net::IOBuffer(
- ppapi::proxy::UDPSocketResourceBase::kMaxReadSize);
+ recvfrom_buffer_ = new net::IOBuffer(UDPSocketFilter::kMaxReadSize);
// Use base::Unretained(this), so that the lifespan of this object doesn't
// have to last until the callback is called.
@@ -313,9 +511,7 @@ void PepperUDPSocketMessageFilter::DoRecvFrom() {
// 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_,
+ recvfrom_buffer_.get(), UDPSocketFilter::kMaxReadSize, &recvfrom_address_,
base::Bind(&PepperUDPSocketMessageFilter::OnRecvFromCompleted,
base::Unretained(this)));
if (net_result != net::ERR_IO_PENDING)
@@ -334,42 +530,54 @@ void PepperUDPSocketMessageFilter::DoSendTo(
return;
}
- if (sendto_buffer_.get()) {
- SendSendToError(context, PP_ERROR_INPROGRESS);
- return;
- }
-
size_t num_bytes = data.size();
if (num_bytes == 0 ||
- num_bytes > static_cast<size_t>(
- ppapi::proxy::UDPSocketResourceBase::kMaxWriteSize)) {
+ num_bytes > static_cast<size_t>(UDPSocketResourceBase::kMaxWriteSize)) {
// Size of |data| is checked on the plugin side.
NOTREACHED();
SendSendToError(context, PP_ERROR_BADARGUMENT);
return;
}
- sendto_buffer_ = new net::IOBufferWithSize(num_bytes);
- memcpy(sendto_buffer_->data(), data.data(), num_bytes);
-
net::IPAddressNumber address;
- int port;
+ uint16 port;
if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &address, &port)) {
SendSendToError(context, PP_ERROR_ADDRESS_INVALID);
return;
}
- // Please see OnMsgRecvFrom() for the reason why we use base::Unretained(this)
+ scoped_refptr<net::IOBufferWithSize> buffer(
+ new net::IOBufferWithSize(num_bytes));
+ memcpy(buffer->data(), data.data(), num_bytes);
+
+ // Make sure a malicious plugin can't queue up an unlimited number of buffers.
+ size_t num_pending_sends = pending_sends_.size();
+ if (num_pending_sends == UDPSocketResourceBase::kPluginSendBufferSlots) {
+ SendSendToError(context, PP_ERROR_FAILED);
+ return;
+ }
+
+ pending_sends_.push(PendingSend(address, port, buffer, context));
+ // If there are other sends pending, we can't start yet.
+ if (num_pending_sends)
+ return;
+ int net_result = StartPendingSend();
+ if (net_result != net::ERR_IO_PENDING)
+ FinishPendingSend(net_result);
+}
+
+int PepperUDPSocketMessageFilter::StartPendingSend() {
+ DCHECK(!pending_sends_.empty());
+ const PendingSend& pending_send = pending_sends_.front();
+ // See OnMsgRecvFrom() for the reason why we use base::Unretained(this)
// when calling |socket_| methods.
int net_result = socket_->SendTo(
- sendto_buffer_.get(),
- sendto_buffer_->size(),
- net::IPEndPoint(address, port),
+ pending_send.buffer.get(),
+ pending_send.buffer->size(),
+ net::IPEndPoint(pending_send.address, pending_send.port),
base::Bind(&PepperUDPSocketMessageFilter::OnSendToCompleted,
- base::Unretained(this),
- context));
- if (net_result != net::ERR_IO_PENDING)
- OnSendToCompleted(context, net_result);
+ base::Unretained(this)));
+ return net_result;
}
void PepperUDPSocketMessageFilter::Close() {
@@ -410,24 +618,39 @@ void PepperUDPSocketMessageFilter::OnRecvFromCompleted(int net_result) {
DoRecvFrom();
}
-void PepperUDPSocketMessageFilter::OnSendToCompleted(
- const ppapi::host::ReplyMessageContext& context,
- int net_result) {
+void PepperUDPSocketMessageFilter::OnSendToCompleted(int net_result) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(sendto_buffer_.get());
+ FinishPendingSend(net_result);
+
+ // Start pending sends until none are left or a send doesn't complete.
+ while (!pending_sends_.empty()) {
+ net_result = StartPendingSend();
+ if (net_result == net::ERR_IO_PENDING)
+ break;
+ FinishPendingSend(net_result);
+ }
+}
+void PepperUDPSocketMessageFilter::FinishPendingSend(int net_result) {
+ DCHECK(!pending_sends_.empty());
+ const PendingSend& pending_send = pending_sends_.front();
int32_t pp_result = NetErrorToPepperError(net_result);
if (pp_result < 0)
- SendSendToError(context, pp_result);
+ SendSendToError(pending_send.context, pp_result);
else
- SendSendToReply(context, PP_OK, pp_result);
- sendto_buffer_ = NULL;
+ SendSendToReply(pending_send.context, PP_OK, pp_result);
+
+ pending_sends_.pop();
}
void PepperUDPSocketMessageFilter::SendBindReply(
const ppapi::host::ReplyMessageContext& context,
int32_t result,
const PP_NetAddress_Private& addr) {
+ UMA_HISTOGRAM_BOOLEAN(
+ "Pepper.PluginContextSecurity.UDPBind",
+ host_->IsPotentiallySecurePluginContext(resource_host()->pp_instance()));
+
ppapi::host::ReplyMessageContext reply_context(context);
reply_context.params.set_result(result);
SendReply(reply_context, PpapiPluginMsg_UDPSocket_BindReply(addr));
@@ -471,4 +694,30 @@ void PepperUDPSocketMessageFilter::SendSendToError(
SendSendToReply(context, result, 0);
}
+int32_t PepperUDPSocketMessageFilter::CanUseMulticastAPI(
+ const PP_NetAddress_Private& addr) {
+ // Check for Dev API.
+ // TODO(etrunko): remove check when Multicast API reaches beta/stable.
+ // https://crbug.com/464452
+ ContentBrowserClient* content_browser_client = GetContentClient()->browser();
+ if (!content_browser_client->IsPluginAllowedToUseDevChannelAPIs(nullptr,
+ GURL())) {
+ return PP_ERROR_NOTSUPPORTED;
+ }
+
+ // Check for plugin permissions.
+ SocketPermissionRequest request =
+ pepper_socket_utils::CreateSocketPermissionRequest(
+ SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP, addr);
+ if (!pepper_socket_utils::CanUseSocketAPIs(external_plugin_,
+ private_api_,
+ &request,
+ render_process_id_,
+ render_frame_id_)) {
+ return PP_ERROR_NOACCESS;
+ }
+
+ return PP_OK;
+}
+
} // namespace content
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 1aa2c36cad4..708c5479a29 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
@@ -5,6 +5,7 @@
#ifndef CONTENT_BROWSER_RENDERER_HOST_PEPPER_PEPPER_UDP_SOCKET_MESSAGE_FILTER_H_
#define CONTENT_BROWSER_RENDERER_HOST_PEPPER_PEPPER_UDP_SOCKET_MESSAGE_FILTER_H_
+#include <queue>
#include <string>
#include "base/basictypes.h"
@@ -16,6 +17,7 @@
#include "content/public/common/process_type.h"
#include "net/base/completion_callback.h"
#include "net/base/ip_endpoint.h"
+#include "net/udp/udp_socket.h"
#include "ppapi/c/pp_instance.h"
#include "ppapi/c/pp_stdint.h"
#include "ppapi/c/ppb_udp_socket.h"
@@ -26,7 +28,6 @@ struct PP_NetAddress_Private;
namespace net {
class IOBuffer;
class IOBufferWithSize;
-class UDPServerSocket;
}
namespace ppapi {
@@ -56,6 +57,28 @@ class CONTENT_EXPORT PepperUDPSocketMessageFilter
~PepperUDPSocketMessageFilter() override;
private:
+ enum SocketOption {
+ SOCKET_OPTION_ADDRESS_REUSE = 1 << 0,
+ SOCKET_OPTION_BROADCAST = 1 << 1,
+ SOCKET_OPTION_RCVBUF_SIZE = 1 << 2,
+ SOCKET_OPTION_SNDBUF_SIZE = 1 << 3,
+ SOCKET_OPTION_MULTICAST_LOOP = 1 << 4,
+ SOCKET_OPTION_MULTICAST_TTL = 1 << 5
+ };
+
+ struct PendingSend {
+ PendingSend(const net::IPAddressNumber& address,
+ int port,
+ const scoped_refptr<net::IOBufferWithSize>& buffer,
+ const ppapi::host::ReplyMessageContext& context);
+ ~PendingSend();
+
+ net::IPAddressNumber address;
+ int port;
+ scoped_refptr<net::IOBufferWithSize> buffer;
+ ppapi::host::ReplyMessageContext context;
+ };
+
// ppapi::host::ResourceMessageFilter overrides.
scoped_refptr<base::TaskRunner> OverrideTaskRunnerForMessage(
const IPC::Message& message) override;
@@ -74,6 +97,10 @@ class CONTENT_EXPORT PepperUDPSocketMessageFilter
int32_t OnMsgClose(const ppapi::host::HostMessageContext* context);
int32_t OnMsgRecvSlotAvailable(
const ppapi::host::HostMessageContext* context);
+ int32_t OnMsgJoinGroup(const ppapi::host::HostMessageContext* context,
+ const PP_NetAddress_Private& addr);
+ int32_t OnMsgLeaveGroup(const ppapi::host::HostMessageContext* context,
+ const PP_NetAddress_Private& addr);
void DoBind(const ppapi::host::ReplyMessageContext& context,
const PP_NetAddress_Private& addr);
@@ -81,11 +108,12 @@ class CONTENT_EXPORT PepperUDPSocketMessageFilter
void DoSendTo(const ppapi::host::ReplyMessageContext& context,
const std::string& data,
const PP_NetAddress_Private& addr);
+ int StartPendingSend();
void Close();
void OnRecvFromCompleted(int net_result);
- void OnSendToCompleted(const ppapi::host::ReplyMessageContext& context,
- int net_result);
+ void OnSendToCompleted(int net_result);
+ void FinishPendingSend(int net_result);
void SendBindReply(const ppapi::host::ReplyMessageContext& context,
int32_t result,
@@ -103,14 +131,28 @@ class CONTENT_EXPORT PepperUDPSocketMessageFilter
void SendSendToError(const ppapi::host::ReplyMessageContext& context,
int32_t result);
- bool allow_address_reuse_;
- bool allow_broadcast_;
+ int32_t CanUseMulticastAPI(const PP_NetAddress_Private& addr);
+
+ BrowserPpapiHostImpl* host_;
+
+ // Bitwise-or of SocketOption flags. This stores the state about whether
+ // each option is set before Bind() is called.
+ int socket_options_;
- scoped_ptr<net::UDPServerSocket> socket_;
+ // Locally cached value of buffer size.
+ int32_t rcvbuf_size_;
+ int32_t sndbuf_size_;
+
+ // Multicast options, if socket hasn't been bound
+ int multicast_ttl_;
+ int32_t can_use_multicast_;
+
+ scoped_ptr<net::UDPSocket> socket_;
bool closed_;
scoped_refptr<net::IOBuffer> recvfrom_buffer_;
- scoped_refptr<net::IOBufferWithSize> sendto_buffer_;
+
+ std::queue<PendingSend> pending_sends_;
net::IPEndPoint recvfrom_address_;
diff --git a/chromium/content/browser/renderer_host/render_message_filter.cc b/chromium/content/browser/renderer_host/render_message_filter.cc
index 0474e081bc7..3aee5699f56 100644
--- a/chromium/content/browser/renderer_host/render_message_filter.cc
+++ b/chromium/content/browser/renderer_host/render_message_filter.cc
@@ -34,11 +34,8 @@
#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"
@@ -71,7 +68,6 @@
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
#include "ppapi/shared_impl/file_type_conversion.h"
-#include "third_party/WebKit/public/web/WebNotificationPresenter.h"
#include "ui/gfx/color_profile.h"
#if defined(OS_MACOSX)
@@ -108,7 +104,6 @@ const int kPluginsRefreshThresholdInSeconds = 3;
const uint32 kFilteredMessageClasses[] = {
ChildProcessMsgStart,
- DesktopNotificationMsgStart,
FrameMsgStart,
ViewMsgStart,
};
@@ -134,6 +129,12 @@ class RenderMessageCompletionCallback {
}
virtual ~RenderMessageCompletionCallback() {
+ if (reply_msg_) {
+ // If the owner of this class failed to call SendReplyAndDeleteThis(),
+ // send an error reply to prevent the renderer from being hung.
+ reply_msg_->set_reply_error();
+ filter_->Send(reply_msg_);
+ }
}
RenderMessageFilter* filter() { return filter_.get(); }
@@ -141,6 +142,7 @@ class RenderMessageCompletionCallback {
void SendReplyAndDeleteThis() {
filter_->Send(reply_msg_);
+ reply_msg_ = NULL;
delete this;
}
@@ -302,11 +304,12 @@ RenderMessageFilter::RenderMessageFilter(
media::AudioManager* audio_manager,
MediaInternals* media_internals,
DOMStorageContextWrapper* dom_storage_context)
- : BrowserMessageFilter(
- kFilteredMessageClasses, arraysize(kFilteredMessageClasses)),
+ : BrowserMessageFilter(kFilteredMessageClasses,
+ arraysize(kFilteredMessageClasses)),
resource_dispatcher_host_(ResourceDispatcherHostImpl::Get()),
plugin_service_(plugin_service),
profile_data_directory_(browser_context->GetPath()),
+ bitmap_manager_client_(HostSharedBitmapManager::current()),
request_context_(request_context),
resource_context_(browser_context->GetResourceContext()),
render_widget_helper_(render_widget_helper),
@@ -325,7 +328,6 @@ RenderMessageFilter::~RenderMessageFilter() {
// This function should be called on the IO thread.
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)
@@ -367,11 +369,9 @@ bool RenderMessageFilter::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(ViewHostMsg_CreateWidget, OnCreateWidget)
IPC_MESSAGE_HANDLER(ViewHostMsg_CreateFullscreenWidget,
OnCreateFullscreenWidget)
- IPC_MESSAGE_HANDLER(ViewHostMsg_SetCookie, OnSetCookie)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetCookies, OnGetCookies)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetRawCookies, OnGetRawCookies)
- IPC_MESSAGE_HANDLER(ViewHostMsg_DeleteCookie, OnDeleteCookie)
- IPC_MESSAGE_HANDLER(ViewHostMsg_CookiesEnabled, OnCookiesEnabled)
+ IPC_MESSAGE_HANDLER(FrameHostMsg_SetCookie, OnSetCookie)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(FrameHostMsg_GetCookies, OnGetCookies)
+ IPC_MESSAGE_HANDLER(FrameHostMsg_CookiesEnabled, OnCookiesEnabled)
#if defined(OS_MACOSX)
IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_LoadFont, OnLoadFont)
#endif
@@ -391,6 +391,8 @@ bool RenderMessageFilter::OnMessageReceived(const IPC::Message& message) {
OnDidDeleteOutOfProcessPepperInstance)
IPC_MESSAGE_HANDLER(ViewHostMsg_OpenChannelToPpapiBroker,
OnOpenChannelToPpapiBroker)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_PluginInstanceThrottleStateChange,
+ OnPluginInstanceThrottleStateChange)
#endif
#if defined(OS_MACOSX)
IPC_MESSAGE_HANDLER_GENERIC(ViewHostMsg_SwapCompositorFrame,
@@ -400,10 +402,8 @@ bool RenderMessageFilter::OnMessageReceived(const IPC::Message& 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_SyncAllocateSharedMemory, OnAllocateSharedMemory)
IPC_MESSAGE_HANDLER_DELAY_REPLY(
ChildProcessHostMsg_SyncAllocateSharedBitmap, OnAllocateSharedBitmap)
IPC_MESSAGE_HANDLER_DELAY_REPLY(
@@ -415,13 +415,11 @@ bool RenderMessageFilter::OnMessageReceived(const IPC::Message& message) {
OnAllocatedSharedBitmap)
IPC_MESSAGE_HANDLER(ChildProcessHostMsg_DeletedSharedBitmap,
OnDeletedSharedBitmap)
- IPC_MESSAGE_HANDLER(
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(
ChildProcessHostMsg_SyncAllocateLockedDiscardableSharedMemory,
OnAllocateLockedDiscardableSharedMemory)
-#if defined(OS_POSIX) && !defined(OS_ANDROID)
- IPC_MESSAGE_HANDLER(ViewHostMsg_AllocTransportDIB, OnAllocTransportDIB)
- IPC_MESSAGE_HANDLER(ViewHostMsg_FreeTransportDIB, OnFreeTransportDIB)
-#endif
+ IPC_MESSAGE_HANDLER(ChildProcessHostMsg_DeletedDiscardableSharedMemory,
+ OnDeletedDiscardableSharedMemory)
IPC_MESSAGE_HANDLER(ViewHostMsg_DidGenerateCacheableMetadata,
OnCacheableMetadataAvailable)
IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_Keygen, OnKeygen)
@@ -570,9 +568,9 @@ void RenderMessageFilter::OnSetCookie(int render_frame_id,
if (GetContentClient()->browser()->AllowSetCookie(
url, first_party_for_cookies, cookie, resource_context_,
render_process_id_, render_frame_id, &options)) {
- net::CookieStore* cookie_store = GetCookieStoreForURL(url);
+ net::URLRequestContext* context = GetRequestContextForURL(url);
// Pass a null callback since we don't care about when the 'set' completes.
- cookie_store->SetCookieWithOptionsAsync(
+ context->cookie_store()->SetCookieWithOptionsAsync(
url, cookie, options, net::CookieStore::SetCookiesCallback());
}
}
@@ -594,57 +592,21 @@ void RenderMessageFilter::OnGetCookies(int render_frame_id,
base::strlcpy(url_buf, url.spec().c_str(), arraysize(url_buf));
base::debug::Alias(url_buf);
- net::CookieStore* cookie_store = GetCookieStoreForURL(url);
- cookie_store->GetAllCookiesForURLAsync(
+ net::URLRequestContext* context = GetRequestContextForURL(url);
+ context->cookie_store()->GetAllCookiesForURLAsync(
url, base::Bind(&RenderMessageFilter::CheckPolicyForCookies, this,
render_frame_id, url, first_party_for_cookies,
reply_msg));
}
-void RenderMessageFilter::OnGetRawCookies(
- const GURL& url,
- const GURL& first_party_for_cookies,
- IPC::Message* reply_msg) {
- ChildProcessSecurityPolicyImpl* policy =
- ChildProcessSecurityPolicyImpl::GetInstance();
- // Only return raw cookies to trusted renderers or if this request is
- // not targeted to an an external host like ChromeFrame.
- // TODO(ananta) We need to support retreiving raw cookies from external
- // hosts.
- if (!policy->CanReadRawCookies(render_process_id_) ||
- !policy->CanAccessCookiesForOrigin(render_process_id_, url)) {
- SendGetRawCookiesResponse(reply_msg, net::CookieList());
- return;
- }
-
- // We check policy here to avoid sending back cookies that would not normally
- // be applied to outbound requests for the given URL. Since this cookie info
- // is visible in the developer tools, it is helpful to make it match reality.
- net::CookieStore* cookie_store = GetCookieStoreForURL(url);
- cookie_store->GetAllCookiesForURLAsync(
- url, base::Bind(&RenderMessageFilter::SendGetRawCookiesResponse,
- this, reply_msg));
-}
-
-void RenderMessageFilter::OnDeleteCookie(const GURL& url,
- const std::string& cookie_name) {
- ChildProcessSecurityPolicyImpl* policy =
- ChildProcessSecurityPolicyImpl::GetInstance();
- if (!policy->CanAccessCookiesForOrigin(render_process_id_, url))
- return;
-
- net::CookieStore* cookie_store = GetCookieStoreForURL(url);
- cookie_store->DeleteCookieAsync(url, cookie_name, base::Closure());
-}
-
void RenderMessageFilter::OnCookiesEnabled(
int render_frame_id,
const GURL& url,
const GURL& first_party_for_cookies,
bool* cookies_enabled) {
- // TODO(ananta): If this render view is associated with an automation channel,
- // aka ChromeFrame then we need to retrieve cookie settings from the external
- // host.
+ // TODO(ananta): If this render frame is associated with an automation
+ // channel, aka ChromeFrame then we need to retrieve cookie settings from the
+ // external host.
*cookies_enabled = GetContentClient()->browser()->AllowGetCookie(
url, first_party_for_cookies, net::CookieList(), resource_context_,
render_process_id_, render_frame_id);
@@ -819,6 +781,15 @@ void RenderMessageFilter::OnOpenChannelToPpapiBroker(
path,
new OpenChannelToPpapiBrokerCallback(this, routing_id));
}
+
+void RenderMessageFilter::OnPluginInstanceThrottleStateChange(
+ int plugin_child_id,
+ int32 pp_instance,
+ bool is_throttled) {
+ // Feature is only implemented for non-external Plugins.
+ PpapiPluginProcessHost::OnPluginInstanceThrottleStateChange(
+ plugin_child_id, pp_instance, is_throttled);
+}
#endif // defined(ENABLE_PLUGINS)
void RenderMessageFilter::OnGenerateRoutingID(int* route_id) {
@@ -852,18 +823,9 @@ void RenderMessageFilter::DownloadUrl(int render_view_id,
scoped_ptr<DownloadSaveInfo> save_info(new DownloadSaveInfo());
save_info->suggested_name = suggested_name;
save_info->prompt_for_save_location = use_prompt;
-
- // There may be a special cookie store that we could use for this download,
- // rather than the default one. Since this feature is generally only used for
- // proper render views, and not downloads, we do not need to retrieve the
- // special cookie store here, but just initialize the request to use the
- // 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));
+ url, net::DEFAULT_PRIORITY, NULL));
RecordDownloadSource(INITIATED_BY_RENDERER);
resource_dispatcher_host_->BeginDownload(
request.Pass(),
@@ -873,6 +835,7 @@ void RenderMessageFilter::DownloadUrl(int render_view_id,
render_process_id_,
render_view_id,
false,
+ false,
save_info.Pass(),
DownloadItem::kInvalidId,
ResourceDispatcherHostImpl::DownloadStartedCallback());
@@ -898,22 +861,23 @@ void RenderMessageFilter::OnSaveImageFromDataURL(int render_view_id,
DownloadUrl(render_view_id, data_url, Referrer(), base::string16(), true);
}
-void RenderMessageFilter::OnCheckNotificationPermission(
- const GURL& source_origin, int* result) {
-#if defined(ENABLE_NOTIFICATIONS)
- *result = GetContentClient()->browser()->
- CheckDesktopNotificationPermission(source_origin, resource_context_,
- render_process_id_);
-#else
- *result = blink::WebNotificationPresenter::PermissionAllowed;
-#endif
+void RenderMessageFilter::AllocateSharedMemoryOnFileThread(
+ uint32 buffer_size,
+ IPC::Message* reply_msg) {
+ base::SharedMemoryHandle handle;
+ ChildProcessHostImpl::AllocateSharedMemory(buffer_size, PeerHandle(),
+ &handle);
+ ChildProcessHostMsg_SyncAllocateSharedMemory::WriteReplyParams(reply_msg,
+ handle);
+ Send(reply_msg);
}
-void RenderMessageFilter::OnAllocateSharedMemory(
- uint32 buffer_size,
- base::SharedMemoryHandle* handle) {
- ChildProcessHostImpl::AllocateSharedMemory(
- buffer_size, PeerHandle(), handle);
+void RenderMessageFilter::OnAllocateSharedMemory(uint32 buffer_size,
+ IPC::Message* reply_msg) {
+ BrowserThread::PostTask(
+ BrowserThread::FILE_USER_BLOCKING, FROM_HERE,
+ base::Bind(&RenderMessageFilter::AllocateSharedMemoryOnFileThread, this,
+ buffer_size, reply_msg));
}
void RenderMessageFilter::AllocateSharedBitmapOnFileThread(
@@ -921,8 +885,8 @@ void RenderMessageFilter::AllocateSharedBitmapOnFileThread(
const cc::SharedBitmapId& id,
IPC::Message* reply_msg) {
base::SharedMemoryHandle handle;
- HostSharedBitmapManager::current()->AllocateSharedBitmapForChild(
- PeerHandle(), buffer_size, id, &handle);
+ bitmap_manager_client_.AllocateSharedBitmapForChild(PeerHandle(), buffer_size,
+ id, &handle);
ChildProcessHostMsg_SyncAllocateSharedBitmap::WriteReplyParams(reply_msg,
handle);
Send(reply_msg);
@@ -945,67 +909,74 @@ void RenderMessageFilter::OnAllocatedSharedBitmap(
size_t buffer_size,
const base::SharedMemoryHandle& handle,
const cc::SharedBitmapId& id) {
- HostSharedBitmapManager::current()->ChildAllocatedSharedBitmap(
- buffer_size, handle, PeerHandle(), id);
+ bitmap_manager_client_.ChildAllocatedSharedBitmap(buffer_size, handle,
+ PeerHandle(), id);
}
void RenderMessageFilter::OnDeletedSharedBitmap(const cc::SharedBitmapId& id) {
- HostSharedBitmapManager::current()->ChildDeletedSharedBitmap(id);
+ bitmap_manager_client_.ChildDeletedSharedBitmap(id);
+}
+
+void RenderMessageFilter::AllocateLockedDiscardableSharedMemoryOnFileThread(
+ uint32 size,
+ DiscardableSharedMemoryId id,
+ IPC::Message* reply_msg) {
+ base::SharedMemoryHandle handle;
+ HostDiscardableSharedMemoryManager::current()
+ ->AllocateLockedDiscardableSharedMemoryForChild(PeerHandle(), size, id,
+ &handle);
+ ChildProcessHostMsg_SyncAllocateLockedDiscardableSharedMemory::
+ WriteReplyParams(reply_msg, handle);
+ Send(reply_msg);
}
void RenderMessageFilter::OnAllocateLockedDiscardableSharedMemory(
uint32 size,
- base::SharedMemoryHandle* handle) {
+ DiscardableSharedMemoryId id,
+ IPC::Message* reply_msg) {
+ BrowserThread::PostTask(
+ BrowserThread::FILE_USER_BLOCKING, FROM_HERE,
+ base::Bind(&RenderMessageFilter::
+ AllocateLockedDiscardableSharedMemoryOnFileThread,
+ this, size, id, reply_msg));
+}
+
+void RenderMessageFilter::DeletedDiscardableSharedMemoryOnFileThread(
+ DiscardableSharedMemoryId id) {
HostDiscardableSharedMemoryManager::current()
- ->AllocateLockedDiscardableSharedMemoryForChild(
- PeerHandle(), size, handle);
+ ->ChildDeletedDiscardableSharedMemory(id, PeerHandle());
+}
+
+void RenderMessageFilter::OnDeletedDiscardableSharedMemory(
+ DiscardableSharedMemoryId id) {
+ BrowserThread::PostTask(
+ BrowserThread::FILE_USER_BLOCKING, FROM_HERE,
+ base::Bind(
+ &RenderMessageFilter::DeletedDiscardableSharedMemoryOnFileThread,
+ this, id));
}
-net::CookieStore* RenderMessageFilter::GetCookieStoreForURL(
+net::URLRequestContext* RenderMessageFilter::GetRequestContextForURL(
const GURL& url) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
net::URLRequestContext* context =
GetContentClient()->browser()->OverrideRequestContextForURL(
url, resource_context_);
+ if (!context)
+ context = request_context_->GetURLRequestContext();
- // If we should use a special URLRequestContext rather than the default one,
- // return the cookie store of that special URLRequestContext.
- if (context)
- return context->cookie_store();
-
- // Otherwise, if there is a special cookie store to be used for this process,
- // return that cookie store.
- net::CookieStore* cookie_store =
- GetContentClient()->browser()->OverrideCookieStoreForRenderProcess(
- render_process_id_);
- if (cookie_store)
- return cookie_store;
-
- // Otherwise, return the cookie store of the default request context used
- // for this renderer.
- return request_context_->GetURLRequestContext()->cookie_store();
-}
-
-#if defined(OS_POSIX) && !defined(OS_ANDROID)
-void RenderMessageFilter::OnAllocTransportDIB(
- uint32 size, bool cache_in_browser, TransportDIB::Handle* handle) {
- render_widget_helper_->AllocTransportDIB(size, cache_in_browser, handle);
-}
-
-void RenderMessageFilter::OnFreeTransportDIB(
- TransportDIB::Id dib_id) {
- render_widget_helper_->FreeTransportDIB(dib_id);
+ return context;
}
-#endif
void RenderMessageFilter::OnCacheableMetadataAvailable(
const GURL& url,
- double expected_response_time,
+ base::Time expected_response_time,
const std::vector<char>& data) {
net::HttpCache* cache = request_context_->GetURLRequestContext()->
http_transaction_factory()->GetCache();
- DCHECK(cache);
+ if (!cache)
+ return;
// Use the same priority for the metadata write as for script
// resources (see defaultPriorityForResourceType() in WebKit's
@@ -1015,10 +986,7 @@ void RenderMessageFilter::OnCacheableMetadataAvailable(
const net::RequestPriority kPriority = net::LOW;
scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(data.size()));
memcpy(buf->data(), &data.front(), data.size());
- cache->WriteMetadata(url,
- kPriority,
- base::Time::FromDoubleT(expected_response_time),
- buf.get(),
+ cache->WriteMetadata(url, kPriority, expected_response_time, buf.get(),
data.size());
}
@@ -1093,14 +1061,14 @@ void RenderMessageFilter::CheckPolicyForCookies(
const GURL& first_party_for_cookies,
IPC::Message* reply_msg,
const net::CookieList& cookie_list) {
- net::CookieStore* cookie_store = GetCookieStoreForURL(url);
+ net::URLRequestContext* context = GetRequestContextForURL(url);
// Check the policy for get cookies, and pass cookie_list to the
// TabSpecificContentSetting for logging purpose.
if (GetContentClient()->browser()->AllowGetCookie(
url, first_party_for_cookies, cookie_list, resource_context_,
render_process_id_, render_frame_id)) {
// Gets the cookies from cookie store if allowed.
- cookie_store->GetCookiesWithOptionsAsync(
+ context->cookie_store()->GetCookiesWithOptionsAsync(
url, net::CookieOptions(),
base::Bind(&RenderMessageFilter::SendGetCookiesResponse,
this, reply_msg));
@@ -1111,17 +1079,7 @@ void RenderMessageFilter::CheckPolicyForCookies(
void RenderMessageFilter::SendGetCookiesResponse(IPC::Message* reply_msg,
const std::string& cookies) {
- ViewHostMsg_GetCookies::WriteReplyParams(reply_msg, cookies);
- Send(reply_msg);
-}
-
-void RenderMessageFilter::SendGetRawCookiesResponse(
- IPC::Message* reply_msg,
- const net::CookieList& cookie_list) {
- std::vector<CookieData> cookies;
- for (size_t i = 0; i < cookie_list.size(); ++i)
- cookies.push_back(CookieData(cookie_list[i]));
- ViewHostMsg_GetRawCookies::WriteReplyParams(reply_msg, cookies);
+ FrameHostMsg_GetCookies::WriteReplyParams(reply_msg, cookies);
Send(reply_msg);
}
diff --git a/chromium/content/browser/renderer_host/render_message_filter.h b/chromium/content/browser/renderer_host/render_message_filter.h
index 9d836262035..b384cf4a407 100644
--- a/chromium/content/browser/renderer_host/render_message_filter.h
+++ b/chromium/content/browser/renderer_host/render_message_filter.h
@@ -20,6 +20,8 @@
#include "base/strings/string16.h"
#include "build/build_config.h"
#include "cc/resources/shared_bitmap_manager.h"
+#include "content/common/host_discardable_shared_memory_manager.h"
+#include "content/common/host_shared_bitmap_manager.h"
#include "content/public/browser/browser_message_filter.h"
#include "content/public/common/three_d_api_types.h"
#include "ipc/message_filter.h"
@@ -70,7 +72,6 @@ struct MediaLogEvent;
}
namespace net {
-class CookieStore;
class KeygenHandler;
class URLRequestContext;
class URLRequestContextGetter;
@@ -114,10 +115,10 @@ class CONTENT_EXPORT RenderMessageFilter : public BrowserMessageFilter {
int render_process_id() const { return render_process_id_; }
- // Returns the correct net::CookieStore depending on what type of url is
+ // Returns the correct net::URLRequestContext depending on what type of url is
// given.
// Only call on the IO thread.
- net::CookieStore* GetCookieStoreForURL(const GURL& url);
+ net::URLRequestContext* GetRequestContextForURL(const GURL& url);
protected:
~RenderMessageFilter() override;
@@ -156,11 +157,6 @@ class CONTENT_EXPORT RenderMessageFilter : public BrowserMessageFilter {
const GURL& url,
const GURL& first_party_for_cookies,
IPC::Message* reply_msg);
- void OnGetRawCookies(const GURL& url,
- const GURL& first_party_for_cookies,
- IPC::Message* reply_msg);
- void OnDeleteCookie(const GURL& url,
- const std::string& cookieName);
void OnCookiesEnabled(int render_frame_id,
const GURL& url,
const GURL& first_party_for_cookies,
@@ -205,6 +201,9 @@ class CONTENT_EXPORT RenderMessageFilter : public BrowserMessageFilter {
bool is_external);
void OnOpenChannelToPpapiBroker(int routing_id,
const base::FilePath& path);
+ void OnPluginInstanceThrottleStateChange(int plugin_child_id,
+ int32 pp_instance,
+ bool is_throttled);
#endif // defined(ENABLE_PLUGINS)
void OnGenerateRoutingID(int* route_id);
void OnDownloadUrl(int render_view_id,
@@ -212,8 +211,6 @@ class CONTENT_EXPORT RenderMessageFilter : public BrowserMessageFilter {
const Referrer& referrer,
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 OnGetAudioHardwareConfig(media::AudioParameters* input_params,
media::AudioParameters* output_params);
@@ -226,8 +223,9 @@ class CONTENT_EXPORT RenderMessageFilter : public BrowserMessageFilter {
// Used to ask the browser to allocate a block of shared memory for the
// renderer to send back data in, since shared memory can't be created
// in the renderer on POSIX due to the sandbox.
- void OnAllocateSharedMemory(uint32 buffer_size,
- base::SharedMemoryHandle* handle);
+ void AllocateSharedMemoryOnFileThread(uint32 buffer_size,
+ IPC::Message* reply_msg);
+ void OnAllocateSharedMemory(uint32 buffer_size, IPC::Message* reply_msg);
void AllocateSharedBitmapOnFileThread(uint32 buffer_size,
const cc::SharedBitmapId& id,
IPC::Message* reply_msg);
@@ -241,17 +239,18 @@ class CONTENT_EXPORT RenderMessageFilter : public BrowserMessageFilter {
void OnResolveProxy(const GURL& url, IPC::Message* reply_msg);
// Browser side discardable shared memory allocation.
- void OnAllocateLockedDiscardableSharedMemory(
+ void AllocateLockedDiscardableSharedMemoryOnFileThread(
uint32 size,
- base::SharedMemoryHandle* handle);
+ DiscardableSharedMemoryId id,
+ IPC::Message* reply_message);
+ void OnAllocateLockedDiscardableSharedMemory(uint32 size,
+ DiscardableSharedMemoryId id,
+ IPC::Message* reply_message);
+ void DeletedDiscardableSharedMemoryOnFileThread(DiscardableSharedMemoryId id);
+ void OnDeletedDiscardableSharedMemory(DiscardableSharedMemoryId id);
- // Browser side transport DIB allocation
- void OnAllocTransportDIB(uint32 size,
- bool cache_in_browser,
- TransportDIB::Handle* result);
- void OnFreeTransportDIB(TransportDIB::Id dib_id);
void OnCacheableMetadataAvailable(const GURL& url,
- double expected_response_time,
+ base::Time expected_response_time,
const std::vector<char>& data);
void OnKeygen(uint32 key_size_index, const std::string& challenge_string,
const GURL& url, IPC::Message* reply_msg);
@@ -272,8 +271,6 @@ class CONTENT_EXPORT RenderMessageFilter : public BrowserMessageFilter {
// Callback functions for getting cookies from cookie store.
void SendGetCookiesResponse(IPC::Message* reply_msg,
const std::string& cookies);
- void SendGetRawCookiesResponse(IPC::Message* reply_msg,
- const net::CookieList& cookie_list);
bool CheckBenchmarkingEnabled() const;
bool CheckPreparsedJsCachingEnabled() const;
@@ -314,6 +311,8 @@ class CONTENT_EXPORT RenderMessageFilter : public BrowserMessageFilter {
PluginServiceImpl* plugin_service_;
base::FilePath profile_data_directory_;
+ HostSharedBitmapManagerClient bitmap_manager_client_;
+
// Contextual information to be used for requests created here.
scoped_refptr<net::URLRequestContextGetter> request_context_;
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 f2856bfdc86..99247b2cea5 100644
--- a/chromium/content/browser/renderer_host/render_process_host_browsertest.cc
+++ b/chromium/content/browser/renderer_host/render_process_host_browsertest.cc
@@ -103,8 +103,7 @@ IN_PROC_BROWSER_TEST_F(RenderProcessHostTest,
// Navigate to a different page.
GURL::Replacements replace_host;
- std::string host_str("localhost"); // Must stay in scope with replace_host.
- replace_host.SetHostStr(host_str);
+ replace_host.SetHostStr("localhost");
GURL another_url = embedded_test_server()->GetURL("/simple_page.html");
another_url = another_url.ReplaceComponents(replace_host);
NavigateToURL(CreateBrowser(), another_url);
@@ -178,7 +177,10 @@ IN_PROC_BROWSER_TEST_F(RenderProcessHostTest,
rph->AddObserver(&observer_logger);
// This will crash the render process, and start all the callbacks.
- NavigateToURL(shell(), GURL(kChromeUICrashURL));
+ // We can't use NavigateToURL here since it accesses the shell() after
+ // navigating, which the shell_closer deletes.
+ NavigateToURLBlockUntilNavigationsComplete(
+ shell(), GURL(kChromeUICrashURL), 1);
// The key here is that all the RenderProcessExited callbacks precede all the
// RenderProcessHostDestroyed callbacks.
@@ -195,42 +197,5 @@ 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 c582a6e97a6..f0f19963ff6 100644
--- a/chromium/content/browser/renderer_host/render_process_host_impl.cc
+++ b/chromium/content/browser/renderer_host/render_process_host_impl.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 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.
@@ -16,13 +16,14 @@
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/command_line.h"
-#include "base/debug/trace_event.h"
+#include "base/debug/dump_without_crashing.h"
#include "base/files/file.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
#include "base/process/process_handle.h"
+#include "base/profiler/scoped_tracker.h"
#include "base/rand_util.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
@@ -31,14 +32,20 @@
#include "base/sys_info.h"
#include "base/threading/thread.h"
#include "base/threading/thread_restrictions.h"
+#include "base/trace_event/trace_event.h"
#include "base/tracked_objects.h"
#include "cc/base/switches.h"
+#include "components/scheduler/common/scheduler_switches.h"
#include "content/browser/appcache/appcache_dispatcher_host.h"
#include "content/browser/appcache/chrome_appcache_service.h"
+#include "content/browser/bad_message.h"
+#include "content/browser/bluetooth/bluetooth_dispatcher_host.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/cache_storage/cache_storage_context_impl.h"
+#include "content/browser/cache_storage/cache_storage_dispatcher_host.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"
@@ -50,6 +57,7 @@
#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/browser_gpu_channel_host_factory.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"
@@ -65,7 +73,10 @@
#include "content/browser/message_port_message_filter.h"
#include "content/browser/mime_registry_message_filter.h"
#include "content/browser/mojo/mojo_application_host.h"
+#include "content/browser/navigator_connect/navigator_connect_dispatcher_host.h"
#include "content/browser/notifications/notification_message_filter.h"
+#include "content/browser/permissions/permission_service_context.h"
+#include "content/browser/permissions/permission_service_impl.h"
#include "content/browser/profiler_message_filter.h"
#include "content/browser/push_messaging/push_messaging_message_filter.h"
#include "content/browser/quota_dispatcher_host.h"
@@ -98,17 +109,21 @@
#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/common/child_process_host_impl.h"
#include "content/common/child_process_messages.h"
#include "content/common/content_switches_internal.h"
+#include "content/common/frame_messages.h"
+#include "content/common/gpu/gpu_memory_buffer_factory.h"
#include "content/common/gpu/gpu_messages.h"
+#include "content/common/in_process_child_thread_params.h"
+#include "content/common/mojo/channel_init.h"
#include "content/common/mojo/mojo_messages.h"
#include "content/common/resource_messages.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/navigator_connect_context.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_process_host_factory.h"
@@ -121,13 +136,17 @@
#include "content/public/browser/worker_service.h"
#include "content/public/common/content_constants.h"
#include "content/public/common/content_switches.h"
+#include "content/public/common/mojo_channel_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 "device/vibration/vibration_manager_impl.h"
+#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/gpu_switches.h"
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
#include "gpu/command_buffer/service/gpu_switches.h"
#include "ipc/ipc_channel.h"
#include "ipc/ipc_logging.h"
@@ -138,6 +157,8 @@
#include "net/url_request/url_request_context_getter.h"
#include "ppapi/shared_impl/ppapi_switches.h"
#include "storage/browser/fileapi/sandbox_file_system_backend.h"
+#include "third_party/icu/source/common/unicode/unistr.h"
+#include "third_party/icu/source/i18n/unicode/timezone.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/ui_base_switches.h"
#include "ui/events/event_switches.h"
@@ -147,14 +168,18 @@
#include "ui/native_theme/native_theme_switches.h"
#if defined(OS_ANDROID)
+#include "content/browser/android/child_process_launcher_android.h"
#include "content/browser/media/android/browser_demuxer_android.h"
+#include "content/browser/mojo/service_registrar_android.h"
#include "content/browser/screen_orientation/screen_orientation_message_filter_android.h"
#endif
#if defined(OS_WIN)
#include "base/win/scoped_com_initializer.h"
+#include "base/win/windows_version.h"
#include "content/common/font_cache_dispatcher_win.h"
#include "content/common/sandbox_win.h"
+#include "sandbox/win/src/sandbox_policy.h"
#include "ui/gfx/win/dpi.h"
#endif
@@ -310,9 +335,27 @@ class RendererSandboxedProcessLauncherDelegate
~RendererSandboxedProcessLauncherDelegate() override {}
#if defined(OS_WIN)
- virtual void PreSpawnTarget(sandbox::TargetPolicy* policy,
- bool* success) {
+ void PreSpawnTarget(sandbox::TargetPolicy* policy, bool* success) override {
AddBaseHandleClosePolicy(policy);
+
+ if (base::win::GetVersion() == base::win::VERSION_WIN8 ||
+ base::win::GetVersion() == base::win::VERSION_WIN8_1) {
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
+ if (!command_line.HasSwitch(switches::kDisableAppContainer)) {
+ // TODO(shrikant): Check if these constants should be different across
+ // various versions of Chromium code base or could be same.
+ // If there should be different SID per channel then move this code
+ // in chrome rather than content and assign SID based on
+ // VersionInfo::GetChannel().
+ const wchar_t kAppContainerSid[] =
+ L"S-1-15-2-3251537155-1984446955-2931258699-841473695-1938553385-"
+ L"924012148-129201922";
+
+ policy->SetLowBox(kAppContainerSid);
+ }
+ }
+
GetContentClient()->browser()->PreSpawnRenderer(policy, success);
}
@@ -448,6 +491,10 @@ RenderProcessHostImpl::RenderProcessHostImpl(
within_process_died_observer_(false),
power_monitor_broadcaster_(this),
worker_ref_count_(0),
+ max_worker_count_(0),
+ permission_service_context_(new PermissionServiceContext(this)),
+ pending_valuebuffer_state_(new gpu::ValueStateMap()),
+ subscribe_uniform_enabled_(false),
weak_factory_(this) {
widget_helper_ = new RenderWidgetHelper();
@@ -466,6 +513,9 @@ RenderProcessHostImpl::RenderProcessHostImpl(
base::Bind(&CacheShaderInfo, GetID(),
storage_partition_impl_->GetPath()));
}
+ subscribe_uniform_enabled_ =
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableSubscribeUniformExtension);
// Note: When we create the RenderProcessHostImpl, it's technically
// backgrounded, because it has no visible listeners. But the process
@@ -547,14 +597,12 @@ bool RenderProcessHostImpl::Init() {
return true;
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.
+ // process.
const base::CommandLine& browser_command_line =
*base::CommandLine::ForCurrentProcess();
renderer_prefix =
browser_command_line.GetSwitchValueNative(switches::kRendererCmdPrefix);
-#endif // defined(OS_POSIX)
#if defined(OS_LINUX)
int flags = renderer_prefix.empty() ? ChildProcessHost::CHILD_ALLOW_SELF :
@@ -591,7 +639,10 @@ bool RenderProcessHostImpl::Init() {
// thread in the renderer process runs the WebKit code and can sometimes
// make blocking calls to the UI thread (i.e. this thread), they need to run
// on separate threads.
- in_process_renderer_.reset(g_renderer_main_thread_factory(channel_id));
+ in_process_renderer_.reset(
+ g_renderer_main_thread_factory(InProcessChildThreadParams(
+ channel_id, BrowserThread::UnsafeGetMessageLoopForThread(
+ BrowserThread::IO)->task_runner())));
base::Thread::Options options;
#if defined(OS_WIN) && !defined(OS_MACOSX)
@@ -602,11 +653,17 @@ bool RenderProcessHostImpl::Init() {
// in-process plugins.
options.message_loop_type = base::MessageLoop::TYPE_DEFAULT;
#endif
+
+ // As for execution sequence, this callback should have no any dependency
+ // on starting in-process-render-thread.
+ // So put it here to trigger ChannelMojo initialization earlier to enable
+ // in-process-render-thread using ChannelMojo there.
+ OnProcessLaunched(); // Fake a callback that the process is ready.
+
in_process_renderer_->StartWithOptions(options);
g_in_process_thread = in_process_renderer_->message_loop();
- OnProcessLaunched(); // Fake a callback that the process is ready.
} else {
// Build command line for renderer. We call AppendRendererCommandLine()
// first so the process type argument will appear first.
@@ -640,29 +697,23 @@ bool RenderProcessHostImpl::Init() {
return true;
}
-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);
+ scoped_refptr<base::SequencedTaskRunner> mojo_task_runner =
+ BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::IO)
+ ->task_runner();
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)));
+ channel_mojo_host_.reset(new IPC::ChannelMojoHost(mojo_task_runner));
}
- return IPC::ChannelProxy::Create(
- IPC::ChannelMojo::CreateServerFactory(
- channel_mojo_host_->channel_delegate(), channel_id),
- this,
- runner.get());
+ return IPC::ChannelProxy::Create(IPC::ChannelMojo::CreateServerFactory(
+ channel_mojo_host_->channel_delegate(),
+ mojo_task_runner, channel_id),
+ this, runner.get());
}
return IPC::ChannelProxy::Create(
@@ -671,6 +722,8 @@ scoped_ptr<IPC::ChannelProxy> RenderProcessHostImpl::CreateChannelProxy(
void RenderProcessHostImpl::CreateMessageFilters() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ const base::CommandLine& browser_command_line =
+ *base::CommandLine::ForCurrentProcess();
AddFilter(new ResourceSchedulerFilter(GetID()));
MediaInternals* media_internals = MediaInternals::GetInstance();
media::AudioManager* audio_manager =
@@ -716,12 +769,14 @@ void RenderProcessHostImpl::CreateMessageFilters() {
ChromeBlobStorageContext::GetFor(browser_context),
storage_partition_impl_->GetFileSystemContext(),
storage_partition_impl_->GetServiceWorkerContext(),
+ storage_partition_impl_->GetHostZoomLevelContext(),
get_contexts_callback);
AddFilter(resource_message_filter);
MediaStreamManager* media_stream_manager =
BrowserMainLoop::GetInstance()->media_stream_manager();
AddFilter(new AudioInputRendererHost(
+ GetID(),
audio_manager,
media_stream_manager,
AudioMirroringManager::GetInstance(),
@@ -743,7 +798,6 @@ void RenderProcessHostImpl::CreateMessageFilters() {
GetID()));
AddFilter(new ClipboardMessageFilter);
AddFilter(new DOMStorageMessageFilter(
- GetID(),
storage_partition_impl_->GetDOMStorageContext()));
AddFilter(new IndexedDBDispatcherHost(
GetID(),
@@ -809,6 +863,11 @@ void RenderProcessHostImpl::CreateMessageFilters() {
base::Unretained(widget_helper_.get())));
AddFilter(message_port_message_filter_.get());
+ scoped_refptr<CacheStorageDispatcherHost> cache_storage_filter =
+ new CacheStorageDispatcherHost();
+ cache_storage_filter->Init(storage_partition_impl_->GetCacheStorageContext());
+ AddFilter(cache_storage_filter.get());
+
scoped_refptr<ServiceWorkerDispatcherHost> service_worker_filter =
new ServiceWorkerDispatcherHost(
GetID(), message_port_message_filter_.get(), resource_context);
@@ -847,6 +906,7 @@ void RenderProcessHostImpl::CreateMessageFilters() {
notification_message_filter_ = new NotificationMessageFilter(
GetID(),
+ storage_partition_impl_->GetPlatformNotificationContext(),
resource_context,
browser_context);
AddFilter(notification_message_filter_.get());
@@ -858,11 +918,9 @@ void RenderProcessHostImpl::CreateMessageFilters() {
AddFilter(new ProfilerMessageFilter(PROCESS_TYPE_RENDERER));
AddFilter(new HistogramMessageFilter());
#if defined(USE_TCMALLOC) && (defined(OS_LINUX) || defined(OS_ANDROID))
- if (base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableMemoryBenchmarking))
+ if (browser_command_line.HasSwitch(switches::kEnableMemoryBenchmarking))
AddFilter(new MemoryBenchmarkMessageFilter());
#endif
- AddFilter(new VibrationMessageFilter());
AddFilter(new PushMessagingMessageFilter(
GetID(), storage_partition_impl_->GetServiceWorkerContext()));
#if defined(OS_ANDROID)
@@ -870,11 +928,33 @@ void RenderProcessHostImpl::CreateMessageFilters() {
#endif
AddFilter(new GeofencingDispatcherHost(
storage_partition_impl_->GetGeofencingManager()));
+ AddFilter(new NavigatorConnectDispatcherHost(
+ storage_partition_impl_->GetNavigatorConnectContext(),
+ message_port_message_filter_.get()));
+ if (browser_command_line.HasSwitch(
+ switches::kEnableExperimentalWebPlatformFeatures)) {
+ AddFilter(new BluetoothDispatcherHost());
+ }
}
void RenderProcessHostImpl::RegisterMojoServices() {
mojo_application_host_->service_registry()->AddService(
base::Bind(&device::BatteryMonitorImpl::Create));
+
+ mojo_application_host_->service_registry()->AddService(
+ base::Bind(&device::VibrationManagerImpl::Create));
+
+ mojo_application_host_->service_registry()->AddService(
+ base::Bind(&PermissionServiceContext::CreateService,
+ base::Unretained(permission_service_context_.get())));
+
+#if defined(OS_ANDROID)
+ ServiceRegistrarAndroid::RegisterProcessHostServices(
+ mojo_application_host_->service_registry_android());
+#endif
+
+ GetContentClient()->browser()->OverrideRenderProcessMojoServices(
+ mojo_application_host_->service_registry());
}
int RenderProcessHostImpl::GetNextRoutingID() {
@@ -891,8 +971,8 @@ void RenderProcessHostImpl::ResumeResponseDeferredAtStart(
widget_helper_->ResumeResponseDeferredAtStart(request_id);
}
-void RenderProcessHostImpl::NotifyTimezoneChange() {
- Send(new ViewMsg_TimezoneChange());
+void RenderProcessHostImpl::NotifyTimezoneChange(const std::string& zone_id) {
+ Send(new ViewMsg_TimezoneChange(zone_id));
}
ServiceRegistry* RenderProcessHostImpl::GetServiceRegistry() {
@@ -905,6 +985,46 @@ const base::TimeTicks& RenderProcessHostImpl::GetInitTimeForNavigationMetrics()
return init_time_;
}
+bool RenderProcessHostImpl::SubscribeUniformEnabled() const {
+ return subscribe_uniform_enabled_;
+}
+
+void RenderProcessHostImpl::OnAddSubscription(unsigned int target) {
+ DCHECK(subscribe_uniform_enabled_);
+ subscription_set_.insert(target);
+ const gpu::ValueState* state = pending_valuebuffer_state_->GetState(target);
+ if (state) {
+ SendUpdateValueState(target, *state);
+ }
+}
+
+void RenderProcessHostImpl::OnRemoveSubscription(unsigned int target) {
+ DCHECK(subscribe_uniform_enabled_);
+ subscription_set_.erase(target);
+}
+
+void RenderProcessHostImpl::SendUpdateValueState(unsigned int target,
+ const gpu::ValueState& state) {
+ DCHECK(subscribe_uniform_enabled_);
+ if (subscription_set_.find(target) != subscription_set_.end()) {
+ GpuProcessHost::SendOnIO(
+ GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
+ CAUSE_FOR_GPU_LAUNCH_NO_LAUNCH,
+ new GpuMsg_UpdateValueState(id_, target, state));
+ } else {
+ // Store the ValueState locally in case a Valuebuffer subscribes to it later
+ pending_valuebuffer_state_->UpdateState(target, state);
+ }
+}
+
+#if defined(ENABLE_BROWSER_CDMS)
+media::BrowserCdm* RenderProcessHostImpl::GetBrowserCdm(int render_frame_id,
+ int cdm_id) const {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ return browser_cdm_manager_->GetCdm(render_frame_id, cdm_id);
+}
+#endif
+
void RenderProcessHostImpl::AddRoute(
int32 routing_id,
IPC::Listener* listener) {
@@ -917,19 +1037,6 @@ void RenderProcessHostImpl::RemoveRoute(int32 routing_id) {
DCHECK(listeners_.Lookup(routing_id) != NULL);
listeners_.Remove(routing_id);
-#if defined(OS_WIN)
- // Dump the handle table if handle auditing is enabled.
- const base::CommandLine& browser_command_line =
- *base::CommandLine::ForCurrentProcess();
- if (browser_command_line.HasSwitch(switches::kAuditHandles) ||
- browser_command_line.HasSwitch(switches::kAuditAllHandles)) {
- DumpHandles();
-
- // We wait to close the channels until the child process has finished
- // dumping handles and sends us ChildProcessHostMsg_DumpHandlesDone.
- return;
- }
-#endif
// Keep the one renderer thread around forever in single process mode.
if (!run_renderer_in_process())
Cleanup();
@@ -944,7 +1051,7 @@ void RenderProcessHostImpl::RemoveObserver(
observers_.RemoveObserver(observer);
}
-void RenderProcessHostImpl::ReceivedBadMessage() {
+void RenderProcessHostImpl::ShutdownForBadMessage() {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kDisableKillAfterBadIPC))
return;
@@ -956,8 +1063,7 @@ void RenderProcessHostImpl::ReceivedBadMessage() {
}
// We kill the renderer but don't include a NOTREACHED, because we want the
// browser to try to survive when it gets illegal messages from the renderer.
- base::KillProcess(GetHandle(), RESULT_CODE_KILLED_BAD_MESSAGE,
- false);
+ Shutdown(RESULT_CODE_KILLED_BAD_MESSAGE, false);
}
void RenderProcessHostImpl::WidgetRestored() {
@@ -997,22 +1103,45 @@ static void AppendCompositorCommandLineFlags(base::CommandLine* command_line) {
if (IsPinchVirtualViewportEnabled())
command_line->AppendSwitch(cc::switches::kEnablePinchVirtualViewport);
+ if (IsPropertyTreeVerificationEnabled())
+ command_line->AppendSwitch(cc::switches::kEnablePropertyTreeVerification);
+
if (IsDelegatedRendererEnabled())
command_line->AppendSwitch(switches::kEnableDelegatedRenderer);
if (IsImplSidePaintingEnabled()) {
- command_line->AppendSwitch(switches::kEnableImplSidePainting);
command_line->AppendSwitchASCII(
switches::kNumRasterThreads,
base::IntToString(NumberOfRendererRasterThreads()));
+ } else {
+ command_line->AppendSwitch(switches::kDisableImplSidePainting);
}
if (IsGpuRasterizationEnabled())
command_line->AppendSwitch(switches::kEnableGpuRasterization);
+ int msaa_sample_count = GpuRasterizationMSAASampleCount();
+ if (msaa_sample_count > 0) {
+ command_line->AppendSwitchASCII(
+ switches::kGpuRasterizationMSAASampleCount,
+ base::IntToString(msaa_sample_count));
+ }
+
+ DCHECK_IMPLIES(IsZeroCopyUploadEnabled(), !IsOneCopyUploadEnabled());
+ DCHECK_IMPLIES(IsOneCopyUploadEnabled(), !IsZeroCopyUploadEnabled());
+ if (IsZeroCopyUploadEnabled())
+ command_line->AppendSwitch(switches::kEnableZeroCopy);
+ if (!IsOneCopyUploadEnabled())
+ command_line->AppendSwitch(switches::kDisableOneCopy);
+
if (IsForceGpuRasterizationEnabled())
command_line->AppendSwitch(switches::kForceGpuRasterization);
+ command_line->AppendSwitchASCII(
+ switches::kUseImageTextureTarget,
+ base::UintToString(
+ BrowserGpuChannelHostFactory::GetImageTextureTarget()));
+
// Appending disable-gpu-feature switches due to software rendering list.
GpuDataManagerImpl* gpu_data_manager = GpuDataManagerImpl::GetInstance();
DCHECK(gpu_data_manager);
@@ -1039,7 +1168,7 @@ void RenderProcessHostImpl::AppendRendererCommandLine(
// renderer so that it can act in accordance with each state, or record
// histograms relating to the base::FieldTrial states.
std::string field_trial_states;
- base::FieldTrialList::StatesToString(&field_trial_states);
+ base::FieldTrialList::AllStatesToString(&field_trial_states);
if (!field_trial_states.empty()) {
command_line->AppendSwitchASCII(switches::kForceFieldTrials,
field_trial_states);
@@ -1065,101 +1194,104 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
// 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[] = {
- switches::kAllowInsecureWebSocketFromHttpsOrigin,
switches::kAllowLoopbackInPeerConnection,
switches::kAudioBufferSize,
- switches::kAuditAllHandles,
- switches::kAuditHandles,
switches::kBlinkPlatformLogChannels,
+ switches::kBlinkSettings,
switches::kBlockCrossSiteDocuments,
switches::kDefaultTileWidth,
switches::kDefaultTileHeight,
switches::kDisable3DAPIs,
+ switches::kDisableAcceleratedJpegDecoding,
switches::kDisableAcceleratedVideoDecode,
- switches::kDisableApplicationCache,
- switches::kDisableBlinkScheduler,
+ switches::kDisableBlinkFeatures,
switches::kDisableBreakpad,
switches::kDisablePreferCompositingToLCDText,
- switches::kDisableCompositingForTransition,
switches::kDisableDatabases,
+ switches::kDisableDelayAgnosticAec,
switches::kDisableDirectNPAPIRequests,
switches::kDisableDisplayList2dCanvas,
switches::kDisableDistanceFieldText,
+ switches::kDisableEncryptedMedia,
switches::kDisableFileSystem,
switches::kDisableGpuCompositing,
switches::kDisableGpuVsync,
switches::kDisableLowResTiling,
switches::kDisableHistogramCustomizer,
+ switches::kDisableIconNtp,
switches::kDisableLCDText,
- switches::kDisableLayerSquashing,
switches::kDisableLocalStorage,
switches::kDisableLogging,
switches::kDisableMediaSource,
- switches::kDisableOneCopy,
+ switches::kDisableMojoChannel,
+ switches::kDisableNewVideoRenderer,
+ switches::kDisableNotifications,
switches::kDisableOverlayScrollbar,
+ switches::kDisablePermissionsAPI,
switches::kDisablePinch,
switches::kDisablePrefixedEncryptedMedia,
switches::kDisableSeccompFilterSandbox,
- switches::kDisableSessionStorage,
switches::kDisableSharedWorkers,
+ switches::kDisableSpeechAPI,
switches::kDisableSVG1DOM,
switches::kDisableThreadedCompositing,
switches::kDisableThreadedScrolling,
switches::kDisableTouchAdjustment,
switches::kDisableTouchDragDrop,
switches::kDisableTouchEditing,
- switches::kDisableV8IdleNotificationAfterCommit,
+ switches::kDisableV8IdleTasks,
switches::kDomAutomationController,
- switches::kEnableAcceleratedJpegDecoding,
switches::kEnableBeginFrameScheduling,
switches::kEnableBleedingEdgeRenderingFastPaths,
+ switches::kEnableBlinkFeatures,
switches::kEnableBrowserSideNavigation,
- switches::kEnablePreferCompositingToLCDText,
- switches::kEnableCompositingForTransition,
+ switches::kEnableCompositorAnimationTimelines,
switches::kEnableCredentialManagerAPI,
switches::kEnableDeferredImageDecoding,
+ switches::kEnableDelayAgnosticAec,
switches::kEnableDisplayList2dCanvas,
switches::kEnableDistanceFieldText,
- switches::kEnableEncryptedMedia,
switches::kEnableExperimentalCanvasFeatures,
switches::kEnableExperimentalWebPlatformFeatures,
switches::kEnableGPUClientLogging,
switches::kEnableGpuClientTracing,
switches::kEnableGPUServiceLogging,
+ switches::kEnableIconNtp,
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::kEnablePluginPlaceholderTesting,
switches::kEnablePreciseMemoryInfo,
+ switches::kEnablePreferCompositingToLCDText,
+ switches::kEnablePushMessagePayload,
switches::kEnableRendererMojoChannel,
switches::kEnableSeccompFilterSandbox,
switches::kEnableSkiaBenchmarking,
+ switches::kEnableSlimmingPaint,
switches::kEnableSmoothScrolling,
+ switches::kEnableStaleWhileRevalidate,
switches::kEnableStatsTable,
switches::kEnableStrictSiteIsolation,
switches::kEnableThreadedCompositing,
switches::kEnableTouchDragDrop,
switches::kEnableTouchEditing,
- switches::kEnableV8IdleNotificationAfterCommit,
+ switches::kEnableUnsafeES3APIs,
switches::kEnableViewport,
switches::kEnableViewportMeta,
switches::kEnableVtune,
switches::kEnableWebGLDraftExtensions,
switches::kEnableWebGLImageChromium,
- switches::kEnableWebMIDI,
- switches::kEnableZeroCopy,
+ switches::kExplicitlyAllowedPorts,
switches::kForceDeviceScaleFactor,
+ switches::kForceDisplayList2dCanvas,
switches::kFullMemoryCrashReport,
- switches::kIgnoreResolutionLimitsForAcceleratedVideoDecode,
switches::kIPCConnectionTimeout,
switches::kJavaScriptFlags,
switches::kLoggingLevel,
@@ -1169,11 +1301,12 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
switches::kMemoryMetrics,
switches::kNoReferrers,
switches::kNoSandbox,
+ switches::kOverridePluginPowerSaverForTesting,
switches::kPpapiInProcess,
switches::kProfilerTiming,
+ switches::kReducedReferrerGranularity,
switches::kReduceSecurityForTesting,
switches::kRegisterPepperPlugins,
- switches::kRendererAssertTest,
switches::kRendererStartupDialog,
switches::kRootLayerScrolls,
switches::kShowPaintRects,
@@ -1181,14 +1314,16 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
switches::kStatsCollectionController,
switches::kTestType,
switches::kTouchEvents,
+ switches::kTouchTextSelectionStrategy,
switches::kTraceToConsole,
- switches::kUseDiscardableMemory,
// This flag needs to be propagated to the renderer process for
// --in-process-webgl.
switches::kUseGL,
switches::kUseMobileUserAgent,
+ switches::kUseNormalPriorityForTileTaskWorkerThreads,
switches::kV,
switches::kVideoThreads,
+ switches::kVideoUnderflowThresholdMs,
switches::kVModule,
// Please keep these in alphabetical order. Compositor switches here should
// also be added to chrome/browser/chromeos/login/chrome_restart_request.cc.
@@ -1198,41 +1333,36 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
cc::switches::kDisableThreadedAnimation,
cc::switches::kEnableGpuBenchmarking,
cc::switches::kEnableMainFrameBeforeActivation,
- cc::switches::kEnableTopControlsPositionCalculation,
- cc::switches::kMaxTilesForInterestArea,
cc::switches::kMaxUnusedResourceMemoryUsagePercentage,
cc::switches::kShowCompositedLayerBorders,
cc::switches::kShowFPSCounter,
cc::switches::kShowLayerAnimationBounds,
- cc::switches::kShowNonOccludingRects,
- cc::switches::kShowOccludingRects,
cc::switches::kShowPropertyChangedRects,
cc::switches::kShowReplicaScreenSpaceRects,
cc::switches::kShowScreenSpaceRects,
cc::switches::kShowSurfaceDamageRects,
cc::switches::kSlowDownRasterScaleFactor,
cc::switches::kStrictLayerPropertyChangeChecking,
- cc::switches::kTopControlsHeight,
cc::switches::kTopControlsHideThreshold,
cc::switches::kTopControlsShowThreshold,
+
+ scheduler::switches::kDisableBlinkScheduler,
+
#if defined(ENABLE_PLUGINS)
switches::kEnablePepperTesting,
- switches::kEnablePluginPowerSaver,
#endif
#if defined(ENABLE_WEBRTC)
- switches::kDisableAudioTrackProcessing,
switches::kDisableWebRtcHWDecoding,
switches::kDisableWebRtcHWEncoding,
- switches::kEnableWebRtcHWVp8Encoding,
switches::kEnableWebRtcHWH264Encoding,
+ switches::kEnableWebRtcStunOrigin,
+ switches::kWebRtcMaxCaptureFramerate,
#endif
- switches::kLowEndDeviceMode,
+ switches::kEnableLowEndDeviceMode,
+ switches::kDisableLowEndDeviceMode,
#if defined(OS_ANDROID)
switches::kDisableGestureRequirementForMediaPlayback,
switches::kDisableWebRTC,
- switches::kEnableSpeechRecognition,
- switches::kMediaDrmEnableNonCompositing,
- switches::kNetworkCountryIso,
switches::kDisableWebAudio,
switches::kRendererWaitForJavaDebugger,
#endif
@@ -1240,12 +1370,10 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
// 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::kEnableWin32kRendererLockDown,
+ switches::kDisableWin32kRendererLockDown,
+ switches::kTraceExportEventsToETW,
#endif
#if defined(OS_CHROMEOS)
switches::kDisableVaapiAcceleratedVideoEncode,
@@ -1295,9 +1423,25 @@ base::ProcessHandle RenderProcessHostImpl::GetHandle() const {
return child_process_launcher_->GetProcess().Handle();
}
+bool RenderProcessHostImpl::Shutdown(int exit_code, bool wait) {
+ if (run_renderer_in_process())
+ return false; // Single process mode never shuts down the renderer.
+
+#if defined(OS_ANDROID)
+ // Android requires a different approach for killing.
+ StopChildProcess(GetHandle());
+ return true;
+#else
+ if (!child_process_launcher_.get() || child_process_launcher_->IsStarting())
+ return false;
+
+ return child_process_launcher_->GetProcess().Terminate(exit_code, wait);
+#endif
+}
+
bool RenderProcessHostImpl::FastShutdownIfPossible() {
if (run_renderer_in_process())
- return false; // Single process mode never shutdown the renderer.
+ return false; // Single process mode never shuts down the renderer.
if (!GetContentClient()->browser()->IsFastShutdownPossible())
return false;
@@ -1325,18 +1469,10 @@ bool RenderProcessHostImpl::FastShutdownIfPossible() {
// died due to fast shutdown versus another cause.
fast_shutdown_started_ = true;
- ProcessDied(false /* already_dead */);
+ ProcessDied(false /* already_dead */, nullptr);
return true;
}
-void RenderProcessHostImpl::DumpHandles() {
-#if defined(OS_WIN)
- Send(new ChildProcessMsg_DumpHandles());
-#else
- NOTIMPLEMENTED();
-#endif
-}
-
bool RenderProcessHostImpl::Send(IPC::Message* msg) {
TRACE_EVENT0("renderer_host", "RenderProcessHostImpl::Send");
if (!channel_) {
@@ -1370,8 +1506,6 @@ bool RenderProcessHostImpl::OnMessageReceived(const IPC::Message& msg) {
IPC_BEGIN_MESSAGE_MAP(RenderProcessHostImpl, msg)
IPC_MESSAGE_HANDLER(ChildProcessHostMsg_ShutdownRequest,
OnShutdownRequest)
- IPC_MESSAGE_HANDLER(ChildProcessHostMsg_DumpHandlesDone,
- OnDumpHandlesDone)
IPC_MESSAGE_HANDLER(ViewHostMsg_SuddenTerminationChanged,
SuddenTerminationChanged)
IPC_MESSAGE_HANDLER(ViewHostMsg_UserMetricsRecordAction,
@@ -1419,7 +1553,7 @@ void RenderProcessHostImpl::OnChannelConnected(int32 peer_pid) {
}
void RenderProcessHostImpl::OnChannelError() {
- ProcessDied(true /* already_dead */);
+ ProcessDied(true /* already_dead */, nullptr);
}
void RenderProcessHostImpl::OnBadMessageReceived(const IPC::Message& message) {
@@ -1428,7 +1562,13 @@ void RenderProcessHostImpl::OnBadMessageReceived(const IPC::Message& message) {
LOG(ERROR) << "bad message " << message.type() << " terminating renderer.";
BrowserChildProcessHostImpl::HistogramBadMessageTerminated(
PROCESS_TYPE_RENDERER);
- ReceivedBadMessage();
+
+ // Create a memory dump. This will contain enough stack frames to work out
+ // what the bad message was.
+ base::debug::DumpWithoutCrashing();
+
+ bad_message::ReceivedBadMessage(this,
+ bad_message::RPH_DESERIALIZATION_FAILED);
}
BrowserContext* RenderProcessHostImpl::GetBrowserContext() const {
@@ -1481,6 +1621,14 @@ void RenderProcessHostImpl::Cleanup() {
"SharedWorker.RendererSurviveForWorkerTime",
base::TimeTicks::Now() - survive_for_worker_start_time_);
}
+
+ if (max_worker_count_ > 0) {
+ // Record the max number of workers (SharedWorker or ServiceWorker)
+ // that are simultaneously hosted in this renderer process.
+ UMA_HISTOGRAM_COUNTS("Render.Workers.MaxWorkerCountInRendererProcess",
+ max_worker_count_);
+ }
+
// We cannot clean up twice; if this fails, there is an issue with our
// control flow.
DCHECK(!deleting_soon_);
@@ -1505,8 +1653,14 @@ void RenderProcessHostImpl::Cleanup() {
// away first, since deleting the channel proxy will post a
// OnChannelClosed() to IPC::ChannelProxy::Context on the IO thread.
channel_.reset();
+
+ // The following members should be cleared in ProcessDied() as well!
gpu_message_filter_ = NULL;
message_port_message_filter_ = NULL;
+#if defined(ENABLE_BROWSER_CDMS)
+ browser_cdm_manager_ = NULL;
+#endif
+
RemoveUserData(kSessionStorageHolderKey);
// Remove ourself from the list of renderer processes so that we can't be
@@ -1656,7 +1810,6 @@ void RenderProcessHostImpl::FilterURL(RenderProcessHost* rph,
// navigation to the home page. This is often a privileged page
// (chrome://newtab/) which is exactly what we don't want.
*url = GURL(url::kAboutBlankURL);
- RecordAction(base::UserMetricsAction("FilterURLTermiate_Invalid"));
return;
}
@@ -1664,7 +1817,6 @@ void RenderProcessHostImpl::FilterURL(RenderProcessHost* rph,
// The renderer treats all URLs in the about: scheme as being about:blank.
// Canonicalize about: URLs to about:blank.
*url = GURL(url::kAboutBlankURL);
- RecordAction(base::UserMetricsAction("FilterURLTermiate_About"));
}
// Do not allow browser plugin guests to navigate to non-web URLs, since they
@@ -1678,7 +1830,6 @@ void RenderProcessHostImpl::FilterURL(RenderProcessHost* rph,
// later.
VLOG(1) << "Blocked URL " << url->spec();
*url = GURL(url::kAboutBlankURL);
- RecordAction(base::UserMetricsAction("FilterURLTermiate_Blocked"));
}
}
@@ -1884,7 +2035,8 @@ void RenderProcessHostImpl::RegisterProcessHostForSite(
map->RegisterProcess(site, process);
}
-void RenderProcessHostImpl::ProcessDied(bool already_dead) {
+void RenderProcessHostImpl::ProcessDied(bool already_dead,
+ RendererClosedDetails* known_details) {
// Our child process has died. If we didn't expect it, it's a crash.
// In any case, we need to let everyone know it's gone.
// The OnChannelError notification can fire multiple times due to nested sync
@@ -1900,18 +2052,25 @@ void RenderProcessHostImpl::ProcessDied(bool already_dead) {
// child_process_launcher_ can be NULL in single process mode or if fast
// termination happened.
+ base::TerminationStatus status = base::TERMINATION_STATUS_NORMAL_TERMINATION;
int exit_code = 0;
- base::TerminationStatus status =
- child_process_launcher_.get() ?
- child_process_launcher_->GetChildTerminationStatus(already_dead,
- &exit_code) :
- base::TERMINATION_STATUS_NORMAL_TERMINATION;
+ if (known_details) {
+ status = known_details->status;
+ exit_code = known_details->exit_code;
+ } else if (child_process_launcher_.get()) {
+ status = child_process_launcher_->GetChildTerminationStatus(already_dead,
+ &exit_code);
+ }
- RendererClosedDetails details(GetHandle(), status, exit_code);
+ RendererClosedDetails details(status, exit_code);
mojo_application_host_->WillDestroySoon();
child_process_launcher_.reset();
channel_.reset();
+ while (!queued_messages_.empty()) {
+ delete queued_messages_.front();
+ queued_messages_.pop();
+ }
within_process_died_observer_ = true;
NotificationService::current()->Notify(
@@ -1925,14 +2084,17 @@ void RenderProcessHostImpl::ProcessDied(bool already_dead) {
gpu_message_filter_ = NULL;
message_port_message_filter_ = NULL;
+#if defined(ENABLE_BROWSER_CDMS)
+ browser_cdm_manager_ = NULL;
+#endif
RemoveUserData(kSessionStorageHolderKey);
IDMap<IPC::Listener>::iterator iter(&listeners_);
while (!iter.IsAtEnd()) {
iter.GetCurrentValue()->OnMessageReceived(
- ViewHostMsg_RenderProcessGone(iter.GetCurrentKey(),
- static_cast<int>(status),
- exit_code));
+ FrameHostMsg_RenderProcessGone(iter.GetCurrentKey(),
+ static_cast<int>(status),
+ exit_code));
iter.Advance();
}
@@ -1947,7 +2109,7 @@ void RenderProcessHostImpl::ProcessDied(bool already_dead) {
// TODO(darin): clean this up
}
-int RenderProcessHostImpl::GetActiveViewCount() {
+int RenderProcessHost::GetActiveViewCount() {
int num_active_views = 0;
scoped_ptr<RenderWidgetHostIterator> widgets(
RenderWidgetHost::GetRenderWidgetHosts());
@@ -2031,11 +2193,9 @@ void RenderProcessHostImpl::SuddenTerminationChanged(bool enabled) {
SetSuddenTerminationAllowed(enabled);
}
-void RenderProcessHostImpl::OnDumpHandlesDone() {
- Cleanup();
-}
-
void RenderProcessHostImpl::SetBackgrounded(bool backgrounded) {
+ TRACE_EVENT1("renderer_host", "RenderProcessHostImpl::SetBackgrounded",
+ "backgrounded", backgrounded);
// Note: we always set the backgrounded_ value. If the process is NULL
// (and hence hasn't been created yet), we will set the process priority
// later when we create the process.
@@ -2047,6 +2207,11 @@ void RenderProcessHostImpl::SetBackgrounded(bool backgrounded) {
if (backgrounded_ && audio_renderer_host_->HasActiveAudio())
return;
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch(switches::kDisableRendererBackgrounding))
+ return;
+
#if defined(OS_WIN)
// The cbstext.dll loads as a global GetMessage hook in the browser process
// and intercepts/unintercepts the kernel32 API SetPriorityClass in a
@@ -2058,20 +2223,34 @@ void RenderProcessHostImpl::SetBackgrounded(bool backgrounded) {
return;
#endif // OS_WIN
+#if defined(OS_WIN) || defined(OS_MACOSX)
+ // Same as below, but bound to an experiment (http://crbug.com/458594 on
+ // Windows, http://crbug.com/398103 on the Mac). Enabled by default in the
+ // absence of field trials to get coverage on the perf waterfall.
+ base::FieldTrial* trial =
+ base::FieldTrialList::Find("BackgroundRendererProcesses");
+ if (!trial || !StartsWithASCII(trial->group_name(), "Disallow", true)) {
+ child_process_launcher_->SetProcessBackgrounded(backgrounded);
+ }
+#else
+ // Control the background state from the browser process, otherwise the task
+ // telling the renderer to "unbackground" itself may be preempted by other
+ // tasks executing at lowered priority ahead of it or simply by not being
+ // swiftly scheduled by the OS per the low process priority
+ // (http://crbug.com/398103).
+ child_process_launcher_->SetProcessBackgrounded(backgrounded);
+#endif // OS_WIN
+
// Notify the child process of background state.
Send(new ChildProcessMsg_SetProcessBackgrounded(backgrounded));
-
-#if !defined(OS_WIN)
- // Backgrounding may require elevated privileges not available to renderer
- // processes, so control backgrounding from the process host.
-
- // Windows Vista+ has a fancy process backgrounding mode that can only be set
- // from within the process.
- child_process_launcher_->SetProcessBackgrounded(backgrounded);
-#endif // !OS_WIN
}
void RenderProcessHostImpl::OnProcessLaunched() {
+ // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile1(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "465841 RenderProcessHostImpl::OnProcessLaunched::Start"));
// No point doing anything, since this object will be destructed soon. We
// especially don't want to send the RENDERER_PROCESS_CREATED notification,
// since some clients might expect a RENDERER_PROCESS_TERMINATED afterwards to
@@ -2080,10 +2259,20 @@ void RenderProcessHostImpl::OnProcessLaunched() {
return;
if (child_process_launcher_) {
+ // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile2(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "465841 RenderProcessHostImpl::OnProcessLaunched::Backgrounded"));
DCHECK(child_process_launcher_->GetProcess().IsValid());
SetBackgrounded(backgrounded_);
}
+ // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile3(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "465841 RenderProcessHostImpl::OnProcessLaunched::Notify"));
// NOTE: This needs to be before sending queued messages because
// ExtensionService uses this notification to initialize the renderer process
// with state that must be there before any JavaScript executes.
@@ -2096,25 +2285,58 @@ void RenderProcessHostImpl::OnProcessLaunched() {
Source<RenderProcessHost>(this),
NotificationService::NoDetails());
+ // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile4(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "465841 RenderProcessHostImpl::OnProcessLaunched::MojoActivate"));
// 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.
mojo_application_host_->Activate(this, GetHandle());
+ // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile5(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "465841 RenderProcessHostImpl::OnProcessLaunched::MojoClientLaunch"));
if (channel_mojo_host_)
channel_mojo_host_->OnClientLaunched(GetHandle());
+ // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile6(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "465841 "
+ "RenderProcessHostImpl::OnProcessLaunched::SendQueuedMessages"));
while (!queued_messages_.empty()) {
Send(queued_messages_.front());
queued_messages_.pop();
}
#if defined(ENABLE_WEBRTC)
+ // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile7(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "465841 RenderProcessHostImpl::OnProcessLaunched::EnableAec"));
if (WebRTCInternals::GetInstance()->aec_dump_enabled())
EnableAecDump(WebRTCInternals::GetInstance()->aec_dump_file_path());
#endif
}
+void RenderProcessHostImpl::OnProcessLaunchFailed() {
+ // If this object will be destructed soon, then observers have already been
+ // sent a RenderProcessHostDestroyed notification, and we must observe our
+ // contract that says that will be the last call.
+ if (deleting_soon_)
+ return;
+
+ RendererClosedDetails details { base::TERMINATION_STATUS_PROCESS_WAS_KILLED,
+ -1 };
+ ProcessDied(true, &details);
+}
+
scoped_refptr<AudioRendererHost>
RenderProcessHostImpl::audio_renderer_host() const {
return audio_renderer_host_;
@@ -2233,6 +2455,8 @@ void RenderProcessHostImpl::SendDisableAecDumpToRenderer() {
void RenderProcessHostImpl::IncrementWorkerRefCount() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
++worker_ref_count_;
+ if (worker_ref_count_ > max_worker_count_)
+ max_worker_count_ = worker_ref_count_;
}
void RenderProcessHostImpl::DecrementWorkerRefCount() {
@@ -2243,4 +2467,9 @@ void RenderProcessHostImpl::DecrementWorkerRefCount() {
Cleanup();
}
+void RenderProcessHostImpl::GetAudioOutputControllers(
+ const GetAudioOutputControllersCallback& callback) const {
+ audio_renderer_host()->GetOutputControllers(callback);
+}
+
} // 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 b3bdf3bea7f..e7c8d94fedb 100644
--- a/chromium/content/browser/renderer_host/render_process_host_impl.h
+++ b/chromium/content/browser/renderer_host/render_process_host_impl.h
@@ -20,7 +20,7 @@
#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"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/interface_ptr.h"
#include "ui/gfx/gpu_memory_buffer.h"
#include "ui/gl/gpu_switching_observer.h"
@@ -33,6 +33,10 @@ namespace gfx {
class Size;
}
+namespace gpu {
+class ValueStateMap;
+}
+
namespace IPC {
class ChannelMojoHost;
}
@@ -42,12 +46,14 @@ class AudioRendererHost;
class BrowserCdmManager;
class BrowserDemuxerAndroid;
class GpuMessageFilter;
+class InProcessChildThreadParams;
class MessagePortMessageFilter;
class MojoApplicationHost;
class NotificationMessageFilter;
#if defined(ENABLE_WEBRTC)
class P2PSocketDispatcherHost;
#endif
+class PermissionServiceContext;
class PeerConnectionTrackerHost;
class RendererMainThread;
class RenderWidgetHelper;
@@ -58,7 +64,7 @@ class StoragePartition;
class StoragePartitionImpl;
typedef base::Thread* (*RendererMainThreadFactoryFunction)(
- const std::string& id);
+ const InProcessChildThreadParams& params);
// Implements a concrete RenderProcessHost for the browser process for talking
// to actual renderer processes (as opposed to mocks).
@@ -97,14 +103,14 @@ class CONTENT_EXPORT RenderProcessHostImpl
void RemoveRoute(int32 routing_id) override;
void AddObserver(RenderProcessHostObserver* observer) override;
void RemoveObserver(RenderProcessHostObserver* observer) override;
- void ReceivedBadMessage() override;
+ void ShutdownForBadMessage() override;
void WidgetRestored() override;
void WidgetHidden() override;
int VisibleWidgetCount() const override;
bool IsIsolatedGuest() const override;
StoragePartition* GetStoragePartition() const override;
+ bool Shutdown(int exit_code, bool wait) override;
bool FastShutdownIfPossible() override;
- void DumpHandles() override;
base::ProcessHandle GetHandle() const override;
BrowserContext* GetBrowserContext() const override;
bool InSameStoragePartition(StoragePartition* partition) const override;
@@ -135,9 +141,18 @@ class CONTENT_EXPORT RenderProcessHostImpl
const WebRtcRtpPacketCallback& packet_callback) override;
#endif
void ResumeDeferredNavigation(const GlobalRequestID& request_id) override;
- void NotifyTimezoneChange() override;
+ void NotifyTimezoneChange(const std::string& timezone) override;
ServiceRegistry* GetServiceRegistry() override;
const base::TimeTicks& GetInitTimeForNavigationMetrics() const override;
+ bool SubscribeUniformEnabled() const override;
+ void OnAddSubscription(unsigned int target) override;
+ void OnRemoveSubscription(unsigned int target) override;
+ void SendUpdateValueState(
+ unsigned int target, const gpu::ValueState& state) override;
+#if defined(ENABLE_BROWSER_CDMS)
+ media::BrowserCdm* GetBrowserCdm(int render_frame_id,
+ int cdm_id) const override;
+#endif
// IPC::Sender via RenderProcessHost.
bool Send(IPC::Message* msg) override;
@@ -150,6 +165,7 @@ class CONTENT_EXPORT RenderProcessHostImpl
// ChildProcessLauncher::Client implementation.
void OnProcessLaunched() override;
+ void OnProcessLaunchFailed() override;
scoped_refptr<AudioRendererHost> audio_renderer_host() const;
@@ -159,10 +175,6 @@ class CONTENT_EXPORT RenderProcessHostImpl
child_process_activity_time_ = base::TimeTicks::Now();
}
- // Returns the current number of active views in this process. Excludes
- // any RenderViewHosts that are swapped out.
- int GetActiveViewCount();
-
// Start and end frame subscription for a specific renderer.
// This API only supports subscription to accelerated composited frames.
void BeginFrameSubscription(
@@ -259,6 +271,9 @@ class CONTENT_EXPORT RenderProcessHostImpl
// immediately after receiving response headers.
void ResumeResponseDeferredAtStart(const GlobalRequestID& request_id);
+ void GetAudioOutputControllers(
+ const GetAudioOutputControllersCallback& callback) const override;
+
protected:
// A proxy for our IPC::Channel that lives on the IO thread (see
// browser_process.h)
@@ -286,8 +301,8 @@ class CONTENT_EXPORT RenderProcessHostImpl
private:
friend class VisitRelayingRenderProcessHost;
+ friend class ChildProcessLauncherBrowserTest_ChildSpawnFail_Test;
- bool ShouldUseMojoChannel() const;
scoped_ptr<IPC::ChannelProxy> CreateChannelProxy(
const std::string& channel_id);
@@ -299,7 +314,6 @@ class CONTENT_EXPORT RenderProcessHostImpl
// Control message handlers.
void OnShutdownRequest();
- void OnDumpHandlesDone();
void SuddenTerminationChanged(bool enabled);
void OnUserMetricsRecordAction(const std::string& action);
void OnSavedPageAsMHTML(int job_id, int64 mhtml_file_size);
@@ -320,7 +334,7 @@ class CONTENT_EXPORT RenderProcessHostImpl
void SetBackgrounded(bool backgrounded);
// Handle termination of our process.
- void ProcessDied(bool already_dead);
+ void ProcessDied(bool already_dead, RendererClosedDetails* known_details);
// GpuSwitchingObserver implementation.
void OnGpuSwitched() override;
@@ -465,6 +479,27 @@ class CONTENT_EXPORT RenderProcessHostImpl
// Records the time when the process starts surviving for workers for UMA.
base::TimeTicks survive_for_worker_start_time_;
+ // Records the maximum # of workers simultaneously hosted in this process
+ // for UMA.
+ int max_worker_count_;
+
+ // Context shared for each PermissionService instance created for this RPH.
+ scoped_ptr<PermissionServiceContext> permission_service_context_;
+
+ // This is a set of all subscription targets valuebuffers in the GPU process
+ // are currently subscribed too. Used to prevent sending unnecessary
+ // ValueState updates.
+ typedef base::hash_set<unsigned int> SubscriptionSet;
+ SubscriptionSet subscription_set_;
+
+ // Maintains ValueStates which are not currently subscribed too so we can
+ // pass them to the GpuService if a Valuebuffer ever subscribes to the
+ // respective subscription target
+ scoped_refptr<gpu::ValueStateMap> pending_valuebuffer_state_;
+
+ // Whether or not the CHROMIUM_subscribe_uniform WebGL extension is enabled
+ bool subscribe_uniform_enabled_;
+
base::WeakPtrFactory<RenderProcessHostImpl> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(RenderProcessHostImpl);
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 41a110e3f5c..0b109911ddd 100644
--- a/chromium/content/browser/renderer_host/render_view_host_delegate.cc
+++ b/chromium/content/browser/renderer_host/render_view_host_delegate.cc
@@ -22,14 +22,14 @@ WebContents* RenderViewHostDelegate::GetAsWebContents() {
return NULL;
}
-WebPreferences RenderViewHostDelegate::ComputeWebkitPrefs() {
- return WebPreferences();
-}
-
bool RenderViewHostDelegate::IsFullscreenForCurrentTab() const {
return false;
}
+blink::WebDisplayMode RenderViewHostDelegate::GetDisplayMode() const {
+ return blink::WebDisplayModeBrowser;
+}
+
SessionStorageNamespace* RenderViewHostDelegate::GetSessionStorageNamespace(
SiteInstance* instance) {
return NULL;
@@ -48,4 +48,8 @@ bool RenderViewHostDelegate::IsNeverVisible() {
return false;
}
+bool RenderViewHostDelegate::IsVirtualKeyboardRequested() {
+ return false;
+}
+
} // namespace content
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 b7074f5704b..21d8a337452 100644
--- a/chromium/content/browser/renderer_host/render_view_host_delegate.h
+++ b/chromium/content/browser/renderer_host/render_view_host_delegate.h
@@ -14,6 +14,7 @@
#include "content/browser/dom_storage/session_storage_namespace_impl.h"
#include "content/common/content_export.h"
#include "net/base/load_states.h"
+#include "third_party/WebKit/public/platform/WebDisplayMode.h"
#include "third_party/WebKit/public/web/WebPopupType.h"
#include "ui/base/window_open_disposition.h"
@@ -21,7 +22,6 @@ class GURL;
class SkBitmap;
struct ViewHostMsg_CreateWindow_Params;
struct FrameHostMsg_DidCommitProvisionalLoad_Params;
-struct ViewMsg_PostMessage_Params;
namespace base {
class ListValue;
@@ -110,7 +110,8 @@ class CONTENT_EXPORT RenderViewHostDelegate {
const PageState& state) {}
// The destination URL has changed should be updated.
- virtual void UpdateTargetURL(const GURL& url) {}
+ virtual void UpdateTargetURL(RenderViewHost* render_view_host,
+ const GURL& url) {}
// The page is trying to close the RenderView's representation in the client.
virtual void Close(RenderViewHost* render_view_host) {}
@@ -128,20 +129,11 @@ class CONTENT_EXPORT RenderViewHostDelegate {
// The page wants to close the active view in this tab.
virtual void RouteCloseEvent(RenderViewHost* rvh) {}
- // The page wants to post a message to the active view in this tab.
- virtual void RouteMessageEvent(
- RenderViewHost* rvh,
- const ViewMsg_PostMessage_Params& params) {}
-
// Return a dummy RendererPreferences object that will be used by the renderer
// associated with the owning RenderViewHost.
virtual RendererPreferences GetRendererPrefs(
BrowserContext* browser_context) const = 0;
- // Computes a WebPreferences object that will be used by the renderer
- // associated with the owning render view host.
- 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
// bombing), see DownloadRequestLimiter for details.
@@ -176,25 +168,17 @@ class CONTENT_EXPORT RenderViewHostDelegate {
// Notification that the view has lost capture.
virtual void LostCapture() {}
- // Notifications about mouse events in this view. This is useful for
- // implementing global 'on hover' features external to the view.
- virtual void HandleMouseMove() {}
- virtual void HandleMouseDown() {}
- virtual void HandleMouseLeave() {}
- virtual void HandleMouseUp() {}
- virtual void HandlePointerActivate() {}
- virtual void HandleGestureBegin() {}
- virtual void HandleGestureEnd() {}
-
// Called when a file selection is to be done.
virtual void RunFileChooser(
RenderViewHost* render_view_host,
const FileChooserParams& params) {}
- // Notification that the page wants to go into or out of fullscreen mode.
- virtual void ToggleFullscreenMode(bool enter_fullscreen) {}
+ // Returns whether the associated tab is in fullscreen mode.
virtual bool IsFullscreenForCurrentTab() const;
+ // Returns the display mode for the view.
+ virtual blink::WebDisplayMode GetDisplayMode() const;
+
// The contents' preferred size changed.
virtual void UpdatePreferredSize(const gfx::Size& pref_size) {}
@@ -250,13 +234,13 @@ class CONTENT_EXPORT RenderViewHostDelegate {
// the Windows function which is actually a #define.
virtual void ShowCreatedWindow(int route_id,
WindowOpenDisposition disposition,
- const gfx::Rect& initial_pos,
+ const gfx::Rect& initial_rect,
bool user_gesture) {}
// Show the newly created widget with the specified bounds.
// The widget is identified by the route_id passed to CreateNewWidget.
virtual void ShowCreatedWidget(int route_id,
- const gfx::Rect& initial_pos) {}
+ const gfx::Rect& initial_rect) {}
// Show the newly created full screen widget. Similar to above.
virtual void ShowCreatedFullscreenWidget(int route_id) {}
@@ -280,6 +264,13 @@ class CONTENT_EXPORT RenderViewHostDelegate {
// created by the RenderViewHost.
virtual FrameTree* GetFrameTree();
+ // Optional state storage for if the Virtual Keyboard has been requested by
+ // this page or not. If it has, this can be used to suppress things like the
+ // link disambiguation dialog, which doesn't interact well with the virtual
+ // keyboard.
+ virtual void SetIsVirtualKeyboardRequested(bool requested) {}
+ virtual bool IsVirtualKeyboardRequested();
+
protected:
virtual ~RenderViewHostDelegate() {}
};
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 01a5e1bb5d8..a6f7a4567da 100644
--- a/chromium/content/browser/renderer_host/render_view_host_impl.cc
+++ b/chromium/content/browser/renderer_host/render_view_host_impl.cc
@@ -11,7 +11,6 @@
#include "base/callback.h"
#include "base/command_line.h"
-#include "base/debug/trace_event.h"
#include "base/i18n/rtl.h"
#include "base/json/json_reader.h"
#include "base/message_loop/message_loop.h"
@@ -22,8 +21,10 @@
#include "base/strings/utf_string_conversions.h"
#include "base/sys_info.h"
#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
#include "base/values.h"
#include "cc/base/switches.h"
+#include "content/browser/bad_message.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/dom_storage/session_storage_namespace_impl.h"
#include "content/browser/frame_host/frame_tree.h"
@@ -53,6 +54,7 @@
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_message_filter.h"
#include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/focused_node_details.h"
#include "content/public/browser/native_web_keyboard_event.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_service.h"
@@ -87,10 +89,8 @@
#if defined(OS_WIN)
#include "base/win/win_util.h"
-#endif
-
-#if defined(ENABLE_BROWSER_CDMS)
-#include "content/browser/media/media_web_contents_observer.h"
+#include "ui/gfx/platform_font_win.h"
+#include "ui/gfx/win/dpi.h"
#endif
using base::TimeDelta;
@@ -126,6 +126,40 @@ void DismissVirtualKeyboardTask() {
}
}
}
+
+void GetWindowsSpecificPrefs(RendererPreferences* prefs) {
+ NONCLIENTMETRICS_XP metrics = {0};
+ base::win::GetNonClientMetrics(&metrics);
+
+ prefs->caption_font_family_name = metrics.lfCaptionFont.lfFaceName;
+ prefs->caption_font_height = gfx::PlatformFontWin::GetFontSize(
+ metrics.lfCaptionFont);
+
+ prefs->small_caption_font_family_name = metrics.lfSmCaptionFont.lfFaceName;
+ prefs->small_caption_font_height = gfx::PlatformFontWin::GetFontSize(
+ metrics.lfSmCaptionFont);
+
+ prefs->menu_font_family_name = metrics.lfMenuFont.lfFaceName;
+ prefs->menu_font_height = gfx::PlatformFontWin::GetFontSize(
+ metrics.lfMenuFont);
+
+ prefs->status_font_family_name = metrics.lfStatusFont.lfFaceName;
+ prefs->status_font_height = gfx::PlatformFontWin::GetFontSize(
+ metrics.lfStatusFont);
+
+ prefs->message_font_family_name = metrics.lfMessageFont.lfFaceName;
+ prefs->message_font_height = gfx::PlatformFontWin::GetFontSize(
+ metrics.lfMessageFont);
+
+ prefs->vertical_scroll_bar_width_in_dips =
+ gfx::win::GetSystemMetricsInDIP(SM_CXVSCROLL);
+ prefs->horizontal_scroll_bar_height_in_dips =
+ gfx::win::GetSystemMetricsInDIP(SM_CYHSCROLL);
+ prefs->arrow_bitmap_height_vertical_scroll_bar_in_dips =
+ gfx::win::GetSystemMetricsInDIP(SM_CYVSCROLL);
+ prefs->arrow_bitmap_width_horizontal_scroll_bar_in_dips =
+ gfx::win::GetSystemMetricsInDIP(SM_CXHSCROLL);
+}
#endif
} // namespace
@@ -183,8 +217,6 @@ RenderViewHostImpl::RenderViewHostImpl(
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_close_ack_(false),
sudden_termination_allowed_(false),
render_view_termination_status_(base::TERMINATION_STATUS_STILL_RUNNING),
@@ -204,7 +236,8 @@ RenderViewHostImpl::RenderViewHostImpl(
static_cast<RenderProcessHostImpl*>(GetProcess())
->audio_renderer_host();
if (arh.get())
- has_active_audio = arh->RenderViewHasActiveAudio(GetRoutingID());
+ has_active_audio =
+ arh->RenderFrameHasActiveAudio(main_frame_routing_id_);
}
BrowserThread::PostTask(
BrowserThread::IO,
@@ -216,9 +249,6 @@ RenderViewHostImpl::RenderViewHostImpl(
!is_hidden(),
has_active_audio));
}
-#if defined(ENABLE_BROWSER_CDMS)
- media_web_contents_observer_.reset(new MediaWebContentsObserver(this));
-#endif
}
RenderViewHostImpl::~RenderViewHostImpl() {
@@ -260,7 +290,7 @@ bool RenderViewHostImpl::CreateRenderView(
DCHECK(GetProcess()->HasConnection());
DCHECK(GetProcess()->GetBrowserContext());
- renderer_initialized_ = true;
+ set_renderer_initialized(true);
GpuSurfaceTracker::Get()->SetSurfaceHandle(
surface_id(), GetCompositingSurface());
@@ -274,6 +304,9 @@ bool RenderViewHostImpl::CreateRenderView(
ViewMsg_New_Params params;
params.renderer_preferences =
delegate_->GetRendererPrefs(GetProcess()->GetBrowserContext());
+#if defined(OS_WIN)
+ GetWindowsSpecificPrefs(&params.renderer_preferences);
+#endif
params.web_preferences = GetWebkitPreferences();
params.view_id = GetRoutingID();
params.main_frame_routing_id = main_frame_routing_id_;
@@ -289,9 +322,26 @@ bool RenderViewHostImpl::CreateRenderView(
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.enable_auto_resize = auto_resize_enabled();
+ params.min_size = min_size_for_auto_resize();
+ params.max_size = max_size_for_auto_resize();
+ GetResizeParams(&params.initial_size);
+ if (!is_active_) {
+ params.replicated_frame_state =
+ static_cast<RenderFrameHostImpl*>(GetMainFrame())->frame_tree_node()
+ ->current_replication_state();
+ }
- Send(new ViewMsg_New(params));
+ if (!Send(new ViewMsg_New(params)))
+ return false;
+ SetInitialRenderSizeParams(params.initial_size);
+
+ // If the RWHV has not yet been set, the surface ID namespace will get
+ // passed down by the call to SetView().
+ if (view_) {
+ Send(new ViewMsg_SetSurfaceIdNamespace(GetRoutingID(),
+ view_->GetSurfaceIdNamespace()));
+ }
// If it's enabled, tell the renderer to set up the Javascript bindings for
// sending messages back to the browser.
@@ -301,44 +351,44 @@ bool RenderViewHostImpl::CreateRenderView(
// Let our delegate know that we created a RenderView.
delegate_->RenderViewCreated(this);
+ // Since this method creates the main RenderFrame in the renderer process,
+ // set the proper state on its corresponding RenderFrameHost.
+ RenderFrameHostImpl::FromID(GetProcess()->GetID(), main_frame_routing_id_)
+ ->SetRenderFrameCreated(true);
+
return true;
}
bool RenderViewHostImpl::IsRenderViewLive() const {
- return GetProcess()->HasConnection() && renderer_initialized_;
+ return GetProcess()->HasConnection() && renderer_initialized();
}
void RenderViewHostImpl::SyncRendererPrefs() {
- Send(new ViewMsg_SetRendererPrefs(GetRoutingID(),
- delegate_->GetRendererPrefs(
- GetProcess()->GetBrowserContext())));
+ RendererPreferences renderer_preferences =
+ delegate_->GetRendererPrefs(GetProcess()->GetBrowserContext());
+#if defined(OS_WIN)
+ GetWindowsSpecificPrefs(&renderer_preferences);
+#endif
+ Send(new ViewMsg_SetRendererPrefs(GetRoutingID(), renderer_preferences));
}
-WebPreferences RenderViewHostImpl::ComputeWebkitPrefs(const GURL& url) {
+WebPreferences RenderViewHostImpl::ComputeWebkitPrefs() {
TRACE_EVENT0("browser", "RenderViewHostImpl::GetWebkitPrefs");
WebPreferences prefs;
const base::CommandLine& command_line =
*base::CommandLine::ForCurrentProcess();
- prefs.javascript_enabled =
- !command_line.HasSwitch(switches::kDisableJavaScript);
prefs.web_security_enabled =
!command_line.HasSwitch(switches::kDisableWebSecurity);
- prefs.plugins_enabled =
- !command_line.HasSwitch(switches::kDisablePlugins);
prefs.java_enabled =
!command_line.HasSwitch(switches::kDisableJava);
prefs.remote_fonts_enabled =
!command_line.HasSwitch(switches::kDisableRemoteFonts);
- prefs.xslt_enabled =
- !command_line.HasSwitch(switches::kDisableXSLT);
+ prefs.application_cache_enabled = true;
prefs.xss_auditor_enabled =
!command_line.HasSwitch(switches::kDisableXSSAuditor);
- prefs.application_cache_enabled =
- !command_line.HasSwitch(switches::kDisableApplicationCache);
-
prefs.local_storage_enabled =
!command_line.HasSwitch(switches::kDisableLocalStorage);
prefs.databases_enabled =
@@ -370,12 +420,6 @@ WebPreferences RenderViewHostImpl::ComputeWebkitPrefs(const GURL& url) {
prefs.allow_file_access_from_file_urls =
command_line.HasSwitch(switches::kAllowFileAccessFromFiles);
- prefs.layer_squashing_enabled = true;
- if (command_line.HasSwitch(switches::kEnableLayerSquashing))
- prefs.layer_squashing_enabled = true;
- if (command_line.HasSwitch(switches::kDisableLayerSquashing))
- prefs.layer_squashing_enabled = false;
-
prefs.accelerated_2d_canvas_enabled =
GpuProcessHost::gpu_enabled() &&
!command_line.HasSwitch(switches::kDisableAccelerated2dCanvas);
@@ -386,10 +430,10 @@ WebPreferences RenderViewHostImpl::ComputeWebkitPrefs(const GURL& url) {
prefs.accelerated_2d_canvas_msaa_sample_count =
atoi(command_line.GetSwitchValueASCII(
switches::kAcceleratedCanvas2dMSAASampleCount).c_str());
- prefs.container_culling_enabled =
- command_line.HasSwitch(switches::kEnableContainerCulling);
- prefs.text_blobs_enabled =
- command_line.HasSwitch(switches::kEnableTextBlobs);
+ // Text blobs rely on impl-side painting for proper LCD handling.
+ prefs.text_blobs_enabled = command_line.HasSwitch(switches::kForceTextBlobs)
+ || (content::IsImplSidePaintingEnabled() &&
+ !command_line.HasSwitch(switches::kDisableTextBlobs));
prefs.region_based_columns_enabled =
command_line.HasSwitch(switches::kEnableRegionBasedColumns);
@@ -413,6 +457,11 @@ WebPreferences RenderViewHostImpl::ComputeWebkitPrefs(const GURL& url) {
prefs.touch_enabled = ui::AreTouchEventsEnabled();
prefs.device_supports_touch = prefs.touch_enabled &&
ui::IsTouchDevicePresent();
+ prefs.available_pointer_types = ui::GetAvailablePointerTypes();
+ prefs.primary_pointer_type = ui::GetPrimaryPointerType();
+ prefs.available_hover_types = ui::GetAvailableHoverTypes();
+ prefs.primary_hover_type = ui::GetPrimaryHoverType();
+
#if defined(OS_ANDROID)
prefs.device_supports_mouse = false;
#endif
@@ -471,36 +520,18 @@ WebPreferences RenderViewHostImpl::ComputeWebkitPrefs(const GURL& url) {
prefs.spatial_navigation_enabled = command_line.HasSwitch(
switches::kEnableSpatialNavigation);
- 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;
- }
- }
+ prefs.disable_reading_from_canvas = command_line.HasSwitch(
+ switches::kDisableReadingFromCanvas);
- 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;
- }
+ prefs.strict_mixed_content_checking = command_line.HasSwitch(
+ switches::kEnableStrictMixedContentChecking);
- GetContentClient()->browser()->OverrideWebkitPrefs(this, url, &prefs);
+ prefs.strict_powerful_feature_restrictions = command_line.HasSwitch(
+ switches::kEnableStrictPowerfulFeatureRestrictions);
+
+ prefs.v8_cache_options = GetV8CacheOptions();
+
+ GetContentClient()->browser()->OverrideWebkitPrefs(this, &prefs);
return prefs;
}
@@ -705,10 +736,8 @@ void RenderViewHostImpl::AllowBindings(int bindings_flags) {
GetProcess()->GetID())) {
// This process has no bindings yet. Make sure it does not have more
// than this single active view.
- RenderProcessHostImpl* process =
- static_cast<RenderProcessHostImpl*>(GetProcess());
// --single-process only has one renderer.
- if (process->GetActiveViewCount() > 1 &&
+ if (GetProcess()->GetActiveViewCount() > 1 &&
!base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kSingleProcess))
return;
@@ -720,7 +749,7 @@ void RenderViewHostImpl::AllowBindings(int bindings_flags) {
}
enabled_bindings_ |= bindings_flags;
- if (renderer_initialized_)
+ if (renderer_initialized())
Send(new ViewMsg_AllowBindings(GetRoutingID(), enabled_bindings_));
}
@@ -739,8 +768,7 @@ void RenderViewHostImpl::SetWebUIProperty(const std::string& name,
} else {
RecordAction(
base::UserMetricsAction("BindingsMismatchTerminate_RVH_WebUI"));
- base::KillProcess(
- GetProcess()->GetHandle(), content::RESULT_CODE_KILLED, false);
+ GetProcess()->Shutdown(content::RESULT_CODE_KILLED, false);
}
}
@@ -863,25 +891,22 @@ bool RenderViewHostImpl::OnMessageReceived(const IPC::Message& msg) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(RenderViewHostImpl, msg)
+ IPC_MESSAGE_HANDLER(FrameHostMsg_RenderProcessGone, OnRenderProcessGone)
IPC_MESSAGE_HANDLER(ViewHostMsg_ShowView, OnShowView)
IPC_MESSAGE_HANDLER(ViewHostMsg_ShowWidget, OnShowWidget)
IPC_MESSAGE_HANDLER(ViewHostMsg_ShowFullscreenWidget,
OnShowFullscreenWidget)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_RunModal, OnRunModal)
IPC_MESSAGE_HANDLER(ViewHostMsg_RenderViewReady, OnRenderViewReady)
- IPC_MESSAGE_HANDLER(ViewHostMsg_RenderProcessGone, OnRenderProcessGone)
IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateState, OnUpdateState)
IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateTargetURL, OnUpdateTargetURL)
IPC_MESSAGE_HANDLER(ViewHostMsg_Close, OnClose)
IPC_MESSAGE_HANDLER(ViewHostMsg_RequestMove, OnRequestMove)
IPC_MESSAGE_HANDLER(ViewHostMsg_DocumentAvailableInMainFrame,
OnDocumentAvailableInMainFrame)
- IPC_MESSAGE_HANDLER(ViewHostMsg_ToggleFullscreen, OnToggleFullscreen)
IPC_MESSAGE_HANDLER(ViewHostMsg_DidContentsPreferredSizeChange,
OnDidContentsPreferredSizeChange)
IPC_MESSAGE_HANDLER(ViewHostMsg_RouteCloseEvent,
OnRouteCloseEvent)
- IPC_MESSAGE_HANDLER(ViewHostMsg_RouteMessageEvent, OnRouteMessageEvent)
IPC_MESSAGE_HANDLER(DragHostMsg_StartDragging, OnStartDragging)
IPC_MESSAGE_HANDLER(DragHostMsg_UpdateDragCursor, OnUpdateDragCursor)
IPC_MESSAGE_HANDLER(DragHostMsg_TargetDrop_ACK, OnTargetDropACK)
@@ -889,6 +914,8 @@ 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)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_PageScaleFactorIsOneChanged,
+ OnPageScaleFactorIsOneChanged)
IPC_MESSAGE_HANDLER(ViewHostMsg_RunFileChooser, OnRunFileChooser)
IPC_MESSAGE_HANDLER(ViewHostMsg_FocusedNodeTouched, OnFocusedNodeTouched)
// Have the super handle all other messages.
@@ -904,21 +931,6 @@ void RenderViewHostImpl::Init() {
}
void RenderViewHostImpl::Shutdown() {
- // If we are being run modally (see RunModal), then we need to cleanup.
- if (run_modal_reply_msg_) {
- Send(run_modal_reply_msg_);
- run_modal_reply_msg_ = NULL;
- RenderViewHostImpl* opener =
- RenderViewHostImpl::FromID(GetProcess()->GetID(), run_modal_opener_id_);
- if (opener) {
- opener->StartHangMonitorTimeout(TimeDelta::FromMilliseconds(
- hung_renderer_delay_ms_));
- // Balance out the decrement when we got created.
- opener->increment_in_flight_event_count();
- }
- run_modal_opener_id_ = MSG_ROUTING_NONE;
- }
-
// We can't release the SessionStorageNamespace until our peer
// in the renderer has wound down.
if (GetProcess()->HasConnection()) {
@@ -985,19 +997,19 @@ void RenderViewHostImpl::CreateNewFullscreenWidget(int route_id) {
void RenderViewHostImpl::OnShowView(int route_id,
WindowOpenDisposition disposition,
- const gfx::Rect& initial_pos,
+ const gfx::Rect& initial_rect,
bool user_gesture) {
if (is_active_) {
delegate_->ShowCreatedWindow(
- route_id, disposition, initial_pos, user_gesture);
+ route_id, disposition, initial_rect, user_gesture);
}
Send(new ViewMsg_Move_ACK(route_id));
}
void RenderViewHostImpl::OnShowWidget(int route_id,
- const gfx::Rect& initial_pos) {
+ const gfx::Rect& initial_rect) {
if (is_active_)
- delegate_->ShowCreatedWidget(route_id, initial_pos);
+ delegate_->ShowCreatedWidget(route_id, initial_rect);
Send(new ViewMsg_Move_ACK(route_id));
}
@@ -1007,26 +1019,6 @@ void RenderViewHostImpl::OnShowFullscreenWidget(int route_id) {
Send(new ViewMsg_Move_ACK(route_id));
}
-void RenderViewHostImpl::OnRunModal(int opener_id, IPC::Message* reply_msg) {
- DCHECK(!run_modal_reply_msg_);
- run_modal_reply_msg_ = reply_msg;
- run_modal_opener_id_ = opener_id;
-
- RecordAction(base::UserMetricsAction("ShowModalDialog"));
-
- RenderViewHostImpl* opener =
- RenderViewHostImpl::FromID(GetProcess()->GetID(), run_modal_opener_id_);
- if (opener) {
- opener->StopHangMonitorTimeout();
- // The ack for the mouse down won't come until the dialog closes, so fake it
- // so that we don't get a timeout.
- opener->decrement_in_flight_event_count();
- }
-
- // TODO(darin): Bug 1107929: Need to inform our delegate to show this view in
- // an app-modal fashion.
-}
-
void RenderViewHostImpl::OnRenderViewReady() {
render_view_termination_status_ = base::TERMINATION_STATUS_STILL_RUNNING;
SendScreenRects();
@@ -1035,22 +1027,10 @@ void RenderViewHostImpl::OnRenderViewReady() {
}
void RenderViewHostImpl::OnRenderProcessGone(int status, int exit_code) {
- // Keep the termination status so we can get at it later when we
- // need to know why it died.
- render_view_termination_status_ =
- static_cast<base::TerminationStatus>(status);
-
- // Reset frame tree state associated with this process. This must happen
- // before RenderViewTerminated because observers expect the subframes of any
- // affected frames to be cleared first.
- delegate_->GetFrameTree()->RenderProcessGone(this);
-
- // Our base class RenderWidgetHost needs to reset some stuff.
- RendererExited(render_view_termination_status_, exit_code);
-
- delegate_->RenderViewTerminated(this,
- static_cast<base::TerminationStatus>(status),
- exit_code);
+ // Do nothing, otherwise RenderWidgetHostImpl will assume it is not a
+ // RenderViewHostImpl and destroy itself.
+ // TODO(nasko): Remove this hack once RenderViewHost and RenderWidgetHost are
+ // decoupled.
}
void RenderViewHostImpl::OnUpdateState(int32 page_id, const PageState& state) {
@@ -1063,7 +1043,8 @@ void RenderViewHostImpl::OnUpdateState(int32 page_id, const PageState& state) {
// Without this check, the renderer can trick the browser into using
// filenames it can't access in a future session restore.
if (!CanAccessFilesOfPageState(state)) {
- GetProcess()->ReceivedBadMessage();
+ bad_message::ReceivedBadMessage(
+ GetProcess(), bad_message::RVH_CAN_ACCESS_FILES_OF_PAGE_STATE);
return;
}
@@ -1072,7 +1053,7 @@ void RenderViewHostImpl::OnUpdateState(int32 page_id, const PageState& state) {
void RenderViewHostImpl::OnUpdateTargetURL(const GURL& url) {
if (is_active_)
- delegate_->UpdateTargetURL(url);
+ delegate_->UpdateTargetURL(this, url);
// Send a notification back to the renderer that we are ready to
// receive more target urls.
@@ -1099,21 +1080,12 @@ void RenderViewHostImpl::OnDocumentAvailableInMainFrame(
return;
HostZoomMapImpl* host_zoom_map =
- static_cast<HostZoomMapImpl*>(HostZoomMap::GetDefaultForBrowserContext(
- GetProcess()->GetBrowserContext()));
+ static_cast<HostZoomMapImpl*>(HostZoomMap::Get(GetSiteInstance()));
host_zoom_map->SetTemporaryZoomLevel(GetProcess()->GetID(),
GetRoutingID(),
host_zoom_map->GetDefaultZoomLevel());
}
-void RenderViewHostImpl::OnToggleFullscreen(bool enter_fullscreen) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- delegate_->ToggleFullscreenMode(enter_fullscreen);
- // We need to notify the contents that its fullscreen state has changed. This
- // is done as part of the resize message.
- WasResized();
-}
-
void RenderViewHostImpl::OnDidContentsPreferredSizeChange(
const gfx::Size& new_size) {
delegate_->UpdatePreferredSize(new_size);
@@ -1128,12 +1100,6 @@ void RenderViewHostImpl::OnRouteCloseEvent() {
delegate_->RouteCloseEvent(this);
}
-void RenderViewHostImpl::OnRouteMessageEvent(
- const ViewMsg_PostMessage_Params& params) {
- // Give to the delegate to route to the active RenderViewHost.
- delegate_->RouteMessageEvent(this, params);
-}
-
void RenderViewHostImpl::OnStartDragging(
const DropData& drop_data,
WebDragOperationsMask drag_operations_mask,
@@ -1207,23 +1173,34 @@ void RenderViewHostImpl::OnTakeFocus(bool reverse) {
view->TakeFocus(reverse);
}
-void RenderViewHostImpl::OnFocusedNodeChanged(bool is_editable_node) {
+void RenderViewHostImpl::OnFocusedNodeChanged(
+ bool is_editable_node,
+ const gfx::Rect& node_bounds_in_viewport) {
is_focused_element_editable_ = is_editable_node;
if (view_)
view_->FocusedNodeChanged(is_editable_node);
#if defined(OS_WIN)
if (!is_editable_node && virtual_keyboard_requested_) {
virtual_keyboard_requested_ = false;
+ delegate_->SetIsVirtualKeyboardRequested(false);
BrowserThread::PostDelayedTask(
BrowserThread::UI, FROM_HERE,
base::Bind(base::IgnoreResult(&DismissVirtualKeyboardTask)),
TimeDelta::FromMilliseconds(kVirtualKeyboardDisplayWaitTimeoutMs));
}
#endif
- NotificationService::current()->Notify(
- NOTIFICATION_FOCUS_CHANGED_IN_PAGE,
- Source<RenderViewHost>(this),
- Details<const bool>(&is_editable_node));
+
+ // Convert node_bounds to screen coordinates.
+ gfx::Rect view_bounds_in_screen = view_->GetViewBounds();
+ gfx::Point origin = node_bounds_in_viewport.origin();
+ origin.Offset(view_bounds_in_screen.x(), view_bounds_in_screen.y());
+ gfx::Rect node_bounds_in_screen(origin.x(), origin.y(),
+ node_bounds_in_viewport.width(),
+ node_bounds_in_viewport.height());
+ FocusedNodeDetails details = {is_editable_node, node_bounds_in_screen};
+ NotificationService::current()->Notify(NOTIFICATION_FOCUS_CHANGED_IN_PAGE,
+ Source<RenderViewHost>(this),
+ Details<FocusedNodeDetails>(&details));
}
void RenderViewHostImpl::OnUserGesture() {
@@ -1248,10 +1225,14 @@ void RenderViewHostImpl::RequestToLockMouse(bool user_gesture,
delegate_->RequestToLockMouse(user_gesture, last_unlocked_by_target);
}
-bool RenderViewHostImpl::IsFullscreen() const {
+bool RenderViewHostImpl::IsFullscreenGranted() const {
return delegate_->IsFullscreenForCurrentTab();
}
+blink::WebDisplayMode RenderViewHostImpl::GetDisplayMode() const {
+ return delegate_->GetDisplayMode();
+}
+
void RenderViewHostImpl::OnFocus() {
// Note: We allow focus and blur from swapped out RenderViewHosts, even when
// the active RenderViewHost is in a different BrowsingInstance (e.g., WebUI).
@@ -1268,36 +1249,9 @@ gfx::Rect RenderViewHostImpl::GetRootWindowResizerRect() const {
void RenderViewHostImpl::ForwardMouseEvent(
const blink::WebMouseEvent& mouse_event) {
-
- // We make a copy of the mouse event because
- // RenderWidgetHost::ForwardMouseEvent will delete |mouse_event|.
- blink::WebMouseEvent event_copy(mouse_event);
- RenderWidgetHostImpl::ForwardMouseEvent(event_copy);
-
- switch (event_copy.type) {
- case WebInputEvent::MouseMove:
- delegate_->HandleMouseMove();
- break;
- case WebInputEvent::MouseLeave:
- delegate_->HandleMouseLeave();
- break;
- case WebInputEvent::MouseDown:
- delegate_->HandleMouseDown();
- break;
- case WebInputEvent::MouseWheel:
- if (ignore_input_events())
- delegate_->OnIgnoredUIEvent();
- break;
- case WebInputEvent::MouseUp:
- delegate_->HandleMouseUp();
- default:
- // For now, we don't care about the rest.
- break;
- }
-}
-
-void RenderViewHostImpl::OnPointerEventActivate() {
- delegate_->HandlePointerActivate();
+ RenderWidgetHostImpl::ForwardMouseEvent(mouse_event);
+ if (mouse_event.type == WebInputEvent::MouseWheel && ignore_input_events())
+ delegate_->OnIgnoredUIEvent();
}
void RenderViewHostImpl::ForwardKeyboardEvent(
@@ -1319,12 +1273,6 @@ void RenderViewHostImpl::OnTextSurroundingSelectionResponse(
view_->OnTextSurroundingSelectionResponse(content, start_offset, end_offset);
}
-void RenderViewHostImpl::ExitFullscreen() {
- RejectMouseLockOrUnlockIfNecessary();
- // Notify delegate_ and renderer of fullscreen state change.
- OnToggleFullscreen(false);
-}
-
WebPreferences RenderViewHostImpl::GetWebkitPreferences() {
if (!web_preferences_.get()) {
OnWebkitPreferencesChanged();
@@ -1344,17 +1292,10 @@ void RenderViewHostImpl::OnWebkitPreferencesChanged() {
if (updating_web_preferences_)
return;
updating_web_preferences_ = true;
- UpdateWebkitPreferences(delegate_->ComputeWebkitPrefs());
+ UpdateWebkitPreferences(ComputeWebkitPrefs());
updating_web_preferences_ = false;
}
-void RenderViewHostImpl::GetAudioOutputControllers(
- const GetAudioOutputControllersCallback& callback) const {
- scoped_refptr<AudioRendererHost> audio_host =
- static_cast<RenderProcessHostImpl*>(GetProcess())->audio_renderer_host();
- audio_host->GetOutputControllers(GetRoutingID(), callback);
-}
-
void RenderViewHostImpl::ClearFocusedElement() {
is_focused_element_editable_ = false;
Send(new ViewMsg_ClearFocusedElement(GetRoutingID()));
@@ -1378,12 +1319,12 @@ void RenderViewHostImpl::EnablePreferredSizeMode() {
void RenderViewHostImpl::EnableAutoResize(const gfx::Size& min_size,
const gfx::Size& max_size) {
- SetShouldAutoResize(true);
+ SetAutoResize(true, min_size, max_size);
Send(new ViewMsg_EnableAutoResize(GetRoutingID(), min_size, max_size));
}
void RenderViewHostImpl::DisableAutoResize(const gfx::Size& new_size) {
- SetShouldAutoResize(false);
+ SetAutoResize(false, gfx::Size(), gfx::Size());
Send(new ViewMsg_DisableAutoResize(GetRoutingID(), new_size));
if (!new_size.IsEmpty())
GetView()->SetSize(new_size);
@@ -1414,8 +1355,7 @@ void RenderViewHostImpl::NotifyMoveOrResizeStarted() {
void RenderViewHostImpl::OnDidZoomURL(double zoom_level,
const GURL& url) {
HostZoomMapImpl* host_zoom_map =
- static_cast<HostZoomMapImpl*>(HostZoomMap::GetDefaultForBrowserContext(
- GetProcess()->GetBrowserContext()));
+ static_cast<HostZoomMapImpl*>(HostZoomMap::Get(GetSiteInstance()));
host_zoom_map->SetZoomLevelForView(GetProcess()->GetID(),
GetRoutingID(),
@@ -1423,7 +1363,29 @@ void RenderViewHostImpl::OnDidZoomURL(double zoom_level,
net::GetHostOrSpecFromURL(url));
}
+void RenderViewHostImpl::OnPageScaleFactorIsOneChanged(bool is_one) {
+ if (!GetSiteInstance())
+ return;
+ HostZoomMapImpl* host_zoom_map =
+ static_cast<HostZoomMapImpl*>(HostZoomMap::Get(GetSiteInstance()));
+ if (!host_zoom_map)
+ return;
+ if (!GetProcess())
+ return;
+ host_zoom_map->SetPageScaleFactorIsOneForView(GetProcess()->GetID(),
+ GetRoutingID(), is_one);
+}
+
void RenderViewHostImpl::OnRunFileChooser(const FileChooserParams& params) {
+ // Do not allow messages with absolute paths in them as this can permit a
+ // renderer to coerce the browser to perform I/O on a renderer controlled
+ // path.
+ if (params.default_file_name != params.default_file_name.BaseName()) {
+ bad_message::ReceivedBadMessage(GetProcess(),
+ bad_message::RVH_FILE_CHOOSER_PATH);
+ return;
+ }
+
delegate_->RunFileChooser(this, params);
}
@@ -1431,8 +1393,10 @@ void RenderViewHostImpl::OnFocusedNodeTouched(bool editable) {
#if defined(OS_WIN)
if (editable) {
virtual_keyboard_requested_ = base::win::DisplayVirtualKeyboard();
+ delegate_->SetIsVirtualKeyboardRequested(true);
} else {
virtual_keyboard_requested_ = false;
+ delegate_->SetIsVirtualKeyboardRequested(false);
base::win::DismissVirtualKeyboard();
}
#endif
@@ -1444,18 +1408,22 @@ bool RenderViewHostImpl::CanAccessFilesOfPageState(
ChildProcessSecurityPolicyImpl::GetInstance();
const std::vector<base::FilePath>& file_paths = state.GetReferencedFiles();
- for (std::vector<base::FilePath>::const_iterator file = file_paths.begin();
- file != file_paths.end(); ++file) {
- if (!policy->CanReadFile(GetProcess()->GetID(), *file))
+ for (const auto& file : file_paths) {
+ if (!policy->CanReadFile(GetProcess()->GetID(), file))
return false;
}
return true;
}
-void RenderViewHostImpl::AttachToFrameTree() {
- FrameTree* frame_tree = delegate_->GetFrameTree();
+void RenderViewHostImpl::GrantFileAccessFromPageState(const PageState& state) {
+ ChildProcessSecurityPolicyImpl* policy =
+ ChildProcessSecurityPolicyImpl::GetInstance();
- frame_tree->ResetForMainFrameSwap();
+ const std::vector<base::FilePath>& file_paths = state.GetReferencedFiles();
+ for (const auto& file : file_paths) {
+ if (!policy->CanReadFile(GetProcess()->GetID(), file))
+ policy->GrantReadFile(GetProcess()->GetID(), file);
+ }
}
void RenderViewHostImpl::SelectWordAroundCaret() {
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 c6fdf055b0d..f5f3dec861f 100644
--- a/chromium/content/browser/renderer_host/render_view_host_impl.h
+++ b/chromium/content/browser/renderer_host/render_view_host_impl.h
@@ -29,7 +29,6 @@
class SkBitmap;
class FrameMsg_Navigate;
-struct FrameMsg_Navigate_Params;
struct MediaPlayerAction;
struct ViewHostMsg_CreateWindow_Params;
struct ViewMsg_PostMessage_Params;
@@ -84,6 +83,13 @@ struct FileChooserParams;
// you will not be able to traverse pages back and forward. We need to determine
// if we want to bring that and other functionality down into this object so it
// can be shared by others.
+//
+// DEPRECATED: RenderViewHostImpl is being removed as part of the SiteIsolation
+// project. New code should not be added here, but to either RenderFrameHostImpl
+// (if frame specific) or WebContentsImpl (if page specific).
+//
+// For context, please see https://crbug.com/467770 and
+// http://www.chromium.org/developers/design-documents/site-isolation.
class CONTENT_EXPORT RenderViewHostImpl
: public RenderViewHost,
public RenderWidgetHostImpl {
@@ -117,7 +123,6 @@ class CONTENT_EXPORT RenderViewHostImpl
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(
@@ -153,7 +158,6 @@ class CONTENT_EXPORT RenderViewHostImpl
void ExecutePluginActionAtLocation(
const gfx::Point& location,
const blink::WebPluginAction& action) override;
- void ExitFullscreen() override;
void FilesSelectedInChooser(
const std::vector<content::FileChooserFileInfo>& files,
FileChooserParams::Mode permissions) override;
@@ -169,15 +173,11 @@ class CONTENT_EXPORT RenderViewHostImpl
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;
+ void ActivateNearestFindResult(int request_id, float x, float y) override;
+ void RequestFindMatchRects(int current_version) override;
#endif
void set_delegate(RenderViewHostDelegate* d) {
@@ -205,9 +205,6 @@ class CONTENT_EXPORT RenderViewHostImpl
return render_view_termination_status_;
}
- // Returns the content specific prefs for this RenderViewHost.
- 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.
@@ -229,6 +226,10 @@ class CONTENT_EXPORT RenderViewHostImpl
// longer on the stack when we attempt to swap it out.
void SuppressDialogsUntilSwapOut();
+ // Tells the renderer process to run the page's unload handler.
+ // A ClosePage_ACK ack is sent back when the handler execution completes.
+ void ClosePage();
+
// 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.
@@ -272,7 +273,6 @@ class CONTENT_EXPORT RenderViewHostImpl
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;
@@ -290,12 +290,6 @@ class CONTENT_EXPORT RenderViewHostImpl
// Creates a full screen RenderWidget.
void CreateNewFullscreenWidget(int route_id);
-#if defined(ENABLE_BROWSER_CDMS)
- MediaWebContentsObserver* media_web_contents_observer() {
- return media_web_contents_observer_.get();
- }
-#endif
-
int main_frame_routing_id() const {
return main_frame_routing_id_;
}
@@ -304,13 +298,6 @@ class CONTENT_EXPORT RenderViewHostImpl
size_t start_offset,
size_t end_offset);
- // Update the FrameTree to use this RenderViewHost's main frame
- // RenderFrameHost. Called when the RenderViewHost is committed.
- //
- // TODO(ajwong): Remove once RenderViewHost no longer owns the main frame
- // RenderFrameHost.
- void AttachToFrameTree();
-
// Increases the refcounting on this RVH. This is done by the FrameTree on
// creation of a RenderFrameHost.
void increment_ref_count() { ++frames_ref_count_; }
@@ -336,18 +323,18 @@ class CONTENT_EXPORT RenderViewHostImpl
void OnRenderAutoResized(const gfx::Size& size) override;
void RequestToLockMouse(bool user_gesture,
bool last_unlocked_by_target) override;
- bool IsFullscreen() const override;
+ bool IsFullscreenGranted() const override;
+ blink::WebDisplayMode GetDisplayMode() const override;
void OnFocus() override;
void OnBlur() override;
// IPC message handlers.
void OnShowView(int route_id,
WindowOpenDisposition disposition,
- const gfx::Rect& initial_pos,
+ const gfx::Rect& initial_rect,
bool user_gesture);
- void OnShowWidget(int route_id, const gfx::Rect& initial_pos);
+ void OnShowWidget(int route_id, const gfx::Rect& initial_rect);
void OnShowFullscreenWidget(int route_id);
- void OnRunModal(int opener_id, IPC::Message* reply_msg);
void OnRenderViewReady();
void OnRenderProcessGone(int status, int error_code);
void OnUpdateState(int32 page_id, const PageState& state);
@@ -355,11 +342,9 @@ class CONTENT_EXPORT RenderViewHostImpl
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 OnPasteFromSelectionClipboard();
void OnRouteCloseEvent();
- void OnRouteMessageEvent(const ViewMsg_PostMessage_Params& params);
void OnStartDragging(const DropData& drop_data,
blink::WebDragOperationsMask operations_allowed,
const SkBitmap& bitmap,
@@ -368,9 +353,11 @@ class CONTENT_EXPORT RenderViewHostImpl
void OnUpdateDragCursor(blink::WebDragOperation drag_operation);
void OnTargetDropACK();
void OnTakeFocus(bool reverse);
- void OnFocusedNodeChanged(bool is_editable_node);
+ void OnFocusedNodeChanged(bool is_editable_node,
+ const gfx::Rect& node_bounds_in_viewport);
void OnClosePageACK();
void OnDidZoomURL(double zoom_level, const GURL& url);
+ void OnPageScaleFactorIsOneChanged(bool is_one);
void OnRunFileChooser(const FileChooserParams& params);
void OnFocusedNodeTouched(bool editable);
@@ -388,8 +375,22 @@ class CONTENT_EXPORT RenderViewHostImpl
// to fire.
static const int64 kUnloadTimeoutMS;
+ // Returns the content specific prefs for this RenderViewHost.
+ // TODO(creis): Move most of this method to RenderProcessHost, since it's
+ // mostly the same across all RVHs in a process. Move the rest to RFH.
+ // See https://crbug.com/304341.
+ WebPreferences ComputeWebkitPrefs();
+
+ // Returns whether the current RenderProcessHost has read access to the files
+ // reported in |state|.
bool CanAccessFilesOfPageState(const PageState& state) const;
+ // Grants the current RenderProcessHost read access to any file listed in
+ // |validated_state|. It is important that the PageState has been validated
+ // upon receipt from the renderer process to prevent it from forging access to
+ // files without the user's consent.
+ void GrantFileAccessFromPageState(const PageState& validated_state);
+
// The number of RenderFrameHosts which have a reference to this RVH.
int frames_ref_count_;
@@ -428,12 +429,6 @@ class CONTENT_EXPORT RenderViewHostImpl
// Routing ID for the main frame's RenderFrameHost.
int main_frame_routing_id_;
- // If we were asked to RunModal, then this will hold the reply_msg that we
- // must return to the renderer to unblock it.
- IPC::Message* run_modal_reply_msg_;
- // This will hold the routing id of the RenderView that opened us.
- int run_modal_opener_id_;
-
// Set to true when waiting for a ViewHostMsg_ClosePageACK.
// TODO(creis): Move to RenderFrameHost and RenderWidgetHost.
// See http://crbug.com/418265.
@@ -448,11 +443,6 @@ class CONTENT_EXPORT RenderViewHostImpl
// Set to true if we requested the on screen keyboard to be displayed.
bool virtual_keyboard_requested_;
-#if defined(ENABLE_BROWSER_CDMS)
- // Manages all the media player and CDM managers and forwards IPCs to them.
- scoped_ptr<MediaWebContentsObserver> media_web_contents_observer_;
-#endif
-
// True if the current focused element is editable.
bool is_focused_element_editable_;
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 638442e5f60..8b396b95f57 100644
--- a/chromium/content/browser/renderer_host/render_view_host_unittest.cc
+++ b/chromium/content/browser/renderer_host/render_view_host_unittest.cc
@@ -64,7 +64,8 @@ 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) {
- contents()->GetMainFrame()->SendNavigate(1, GURL("about:cache"));
+ main_test_rfh()->NavigateAndCommitRendererInitiated(
+ 1, true, GURL("about:cache"));
ASSERT_TRUE(controller().GetVisibleEntry());
EXPECT_EQ(GURL(url::kAboutBlankURL),
controller().GetVisibleEntry()->GetURL());
@@ -98,7 +99,7 @@ TEST_F(RenderViewHostTest, ResetUnloadOnReload) {
controller().LoadURL(
url2, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
// Simulate the ClosePage call which is normally sent by the net::URLRequest.
- rvh()->ClosePage();
+ test_rvh()->ClosePage();
// Needed so that navigations are not suspended on the RFH.
main_test_rfh()->SendBeforeUnloadACK(true);
contents()->Stop();
@@ -232,13 +233,16 @@ 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());
- contents()->GetMainFrame()->SendNavigateWithFile(1, url, file_path);
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(url, false);
+ main_test_rfh()->PrepareForCommit();
+ contents()->GetMainFrame()->SendNavigateWithFile(1, 1, true, url, file_path);
EXPECT_EQ(1, process()->bad_msg_count());
ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadFile(
process()->GetID(), file_path);
- contents()->GetMainFrame()->SendNavigateWithFile(process()->GetID(), url,
- file_path);
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(url, false);
+ main_test_rfh()->PrepareForCommit();
+ contents()->GetMainFrame()->SendNavigateWithFile(2, 2, true, url, file_path);
EXPECT_EQ(1, process()->bad_msg_count());
}
diff --git a/chromium/content/browser/renderer_host/render_widget_helper.cc b/chromium/content/browser/renderer_host/render_widget_helper.cc
index 9261de92d62..e9d83f49f14 100644
--- a/chromium/content/browser/renderer_host/render_widget_helper.cc
+++ b/chromium/content/browser/renderer_host/render_widget_helper.cc
@@ -48,10 +48,6 @@ RenderWidgetHelper::~RenderWidgetHelper() {
WidgetHelperMap::iterator it = widget_map.find(render_process_id_);
if (it != widget_map.end() && it->second == this)
widget_map.erase(it);
-
-#if defined(OS_POSIX) && !defined(OS_ANDROID)
- ClearAllocatedDIBs();
-#endif
}
void RenderWidgetHelper::Init(
@@ -216,50 +212,4 @@ void RenderWidgetHelper::OnCreateFullscreenWidgetOnUI(int opener_id,
host->CreateNewFullscreenWidget(route_id);
}
-#if defined(OS_POSIX) && !defined(OS_ANDROID)
-void RenderWidgetHelper::AllocTransportDIB(uint32 size,
- bool cache_in_browser,
- TransportDIB::Handle* result) {
- scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory());
- if (!shared_memory->CreateAnonymous(size)) {
- result->fd = -1;
- result->auto_close = false;
- return;
- }
-
- shared_memory->GiveToProcess(0 /* pid, not needed */, result);
-
- if (cache_in_browser) {
- // Keep a copy of the file descriptor around
- base::AutoLock locked(allocated_dibs_lock_);
- allocated_dibs_[shared_memory->id()] = dup(result->fd);
- }
-}
-
-void RenderWidgetHelper::FreeTransportDIB(TransportDIB::Id dib_id) {
- base::AutoLock locked(allocated_dibs_lock_);
-
- const std::map<TransportDIB::Id, int>::iterator
- i = allocated_dibs_.find(dib_id);
-
- if (i != allocated_dibs_.end()) {
- if (IGNORE_EINTR(close(i->second)) < 0)
- PLOG(ERROR) << "close";
- allocated_dibs_.erase(i);
- } else {
- DLOG(WARNING) << "Renderer asked us to free unknown transport DIB";
- }
-}
-
-void RenderWidgetHelper::ClearAllocatedDIBs() {
- for (std::map<TransportDIB::Id, int>::iterator
- i = allocated_dibs_.begin(); i != allocated_dibs_.end(); ++i) {
- if (IGNORE_EINTR(close(i->second)) < 0)
- PLOG(ERROR) << "close: " << i->first;
- }
-
- allocated_dibs_.clear();
-}
-#endif
-
} // namespace content
diff --git a/chromium/content/browser/renderer_host/render_widget_helper.h b/chromium/content/browser/renderer_host/render_widget_helper.h
index 98b3ca6cdb8..7f32035f2c6 100644
--- a/chromium/content/browser/renderer_host/render_widget_helper.h
+++ b/chromium/content/browser/renderer_host/render_widget_helper.h
@@ -17,7 +17,6 @@
#include "content/public/common/window_container_type.h"
#include "third_party/WebKit/public/web/WebPopupType.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/surface/transport_dib.h"
namespace IPC {
class Message;
@@ -116,20 +115,6 @@ class RenderWidgetHelper
int* surface_id);
void CreateNewFullscreenWidget(int opener_id, int* route_id, int* surface_id);
-#if defined(OS_POSIX)
- // Called on the IO thread to handle the allocation of a TransportDIB. If
- // |cache_in_browser| is |true|, then a copy of the shmem is kept by the
- // browser, and it is the caller's repsonsibility to call
- // FreeTransportDIB(). In all cases, the caller is responsible for deleting
- // the resulting TransportDIB.
- void AllocTransportDIB(uint32 size,
- bool cache_in_browser,
- TransportDIB::Handle* result);
-
- // Called on the IO thread to handle the freeing of a transport DIB
- void FreeTransportDIB(TransportDIB::Id dib_id);
-#endif
-
private:
friend class base::RefCountedThreadSafe<RenderWidgetHelper>;
friend struct BrowserThread::DeleteOnThread<BrowserThread::IO>;
@@ -163,16 +148,6 @@ class RenderWidgetHelper
// receiving response headers.
void OnResumeResponseDeferredAtStart(const GlobalRequestID& request_id);
-#if defined(OS_POSIX)
- // Called on destruction to release all allocated transport DIBs
- void ClearAllocatedDIBs();
-
- // On POSIX we keep file descriptors to all the allocated DIBs around until
- // the renderer frees them.
- base::Lock allocated_dibs_lock_;
- std::map<TransportDIB::Id, int> allocated_dibs_;
-#endif
-
int render_process_id_;
// The next routing id to use.
diff --git a/chromium/content/browser/renderer_host/render_widget_host_browsertest.cc b/chromium/content/browser/renderer_host/render_widget_host_browsertest.cc
deleted file mode 100644
index e85a4856824..00000000000
--- a/chromium/content/browser/renderer_host/render_widget_host_browsertest.cc
+++ /dev/null
@@ -1,30 +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 "base/path_service.h"
-#include "base/run_loop.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/common/content_paths.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/filename_util.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-
-namespace content {
-
-class RenderWidgetHostBrowserTest : public ContentBrowserTest {
- public:
- RenderWidgetHostBrowserTest() {}
-
- void SetUpOnMainThread() override {
- ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &test_dir_));
- }
-
- protected:
- base::FilePath test_dir_;
-};
-
-} // namespace content
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 a3a474ffab1..db2d0fb6006 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_delegate.cc
+++ b/chromium/content/browser/renderer_host/render_widget_host_delegate.cc
@@ -23,11 +23,6 @@ bool RenderWidgetHostDelegate::PreHandleGestureEvent(
return false;
}
-bool RenderWidgetHostDelegate::HandleGestureEvent(
- const blink::WebGestureEvent& event) {
- return false;
-}
-
BrowserAccessibilityManager*
RenderWidgetHostDelegate::GetRootBrowserAccessibilityManager() {
return NULL;
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 669dc255ba4..a2eb5e6e379 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_delegate.h
+++ b/chromium/content/browser/renderer_host/render_widget_host_delegate.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_RENDER_WIDGET_HOST_DELEGATE_H_
-#define CONTENT_BROWSER_RENDER_WIDGET_HOST_DELEGATE_H_
+#ifndef CONTENT_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_DELEGATE_H_
+#define CONTENT_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_DELEGATE_H_
#include "base/basictypes.h"
#include "build/build_config.h"
@@ -34,6 +34,13 @@ class CONTENT_EXPORT RenderWidgetHostDelegate {
// The RenderWidgetHost got the focus.
virtual void RenderWidgetGotFocus(RenderWidgetHostImpl* render_widget_host) {}
+ // The RenderWidget was resized.
+ virtual void RenderWidgetWasResized(RenderWidgetHostImpl* render_widget_host,
+ bool width_changed) {}
+
+ // The screen info has changed.
+ virtual void ScreenInfoChanged() {}
+
// 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
@@ -57,10 +64,6 @@ class CONTENT_EXPORT RenderWidgetHostDelegate {
// Returns true if the |event| was handled.
virtual bool PreHandleGestureEvent(const blink::WebGestureEvent& event);
- // Callback to inform the browser that the renderer did not process the
- // specified gesture event. Returns true if the |event| was handled.
- virtual bool HandleGestureEvent(const blink::WebGestureEvent& event);
-
// Notifies that screen rects were sent to renderer process.
virtual void DidSendScreenRects(RenderWidgetHostImpl* rwh) {}
@@ -82,4 +85,4 @@ class CONTENT_EXPORT RenderWidgetHostDelegate {
} // namespace content
-#endif // CONTENT_BROWSER_RENDER_WIDGET_HOST_DELEGATE_H_
+#endif // CONTENT_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_DELEGATE_H_
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 9a1d709a2ef..41245f2d80a 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/chromium/content/browser/renderer_host/render_widget_host_impl.cc
@@ -12,7 +12,6 @@
#include "base/bind.h"
#include "base/command_line.h"
#include "base/containers/hash_tables.h"
-#include "base/debug/trace_event.h"
#include "base/i18n/rtl.h"
#include "base/lazy_instance.h"
#include "base/message_loop/message_loop.h"
@@ -21,17 +20,20 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/thread_task_runner_handle.h"
+#include "base/trace_event/trace_event.h"
#include "cc/base/switches.h"
#include "cc/output/compositor_frame.h"
#include "cc/output/compositor_frame_ack.h"
#include "content/browser/accessibility/accessibility_mode_helper.h"
#include "content/browser/accessibility/browser_accessibility_state_impl.h"
+#include "content/browser/bad_message.h"
#include "content/browser/browser_plugin/browser_plugin_guest.h"
#include "content/browser/gpu/compositor_util.h"
#include "content/browser/gpu/gpu_process_host.h"
#include "content/browser/gpu/gpu_process_host_ui_shim.h"
#include "content/browser/gpu/gpu_surface_tracker.h"
#include "content/browser/renderer_host/dip_util.h"
+#include "content/browser/renderer_host/frame_metadata_util.h"
#include "content/browser/renderer_host/input/input_router_config_helper.h"
#include "content/browser/renderer_host/input/input_router_impl.h"
#include "content/browser/renderer_host/input/synthetic_gesture.h"
@@ -47,6 +49,7 @@
#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/frame_messages.h"
#include "content/common/gpu/gpu_messages.h"
#include "content/common/host_shared_bitmap_manager.h"
#include "content/common/input_messages.h"
@@ -55,18 +58,19 @@
#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/user_metrics.h"
#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 "gpu/GLES2/gl2extchromium.h"
+#include "gpu/command_buffer/service/gpu_switches.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/size_conversions.h"
#include "ui/gfx/geometry/vector2d_conversions.h"
-#include "ui/gfx/size_conversions.h"
#include "ui/gfx/skbitmap_operations.h"
#include "ui/snapshot/snapshot.h"
@@ -89,10 +93,6 @@ namespace {
bool g_check_for_pending_resize_ack = true;
-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*>
RoutingIDWidgetMap;
@@ -159,20 +159,18 @@ RenderWidgetHostImpl::RenderWidgetHostImpl(RenderWidgetHostDelegate* delegate,
int routing_id,
bool hidden)
: view_(NULL),
+ hung_renderer_delay_(
+ base::TimeDelta::FromMilliseconds(kHungRendererDelayMs)),
renderer_initialized_(false),
- hung_renderer_delay_ms_(kHungRendererDelayMs),
delegate_(delegate),
process_(process),
routing_id_(routing_id),
surface_id_(0),
is_loading_(false),
is_hidden_(hidden),
- is_fullscreen_(false),
repaint_ack_pending_(false),
resize_ack_pending_(false),
- screen_info_out_of_date_(false),
- top_controls_layout_height_(0.f),
- should_auto_resize_(false),
+ auto_resize_enabled_(false),
waiting_for_screen_rects_ack_(false),
needs_repainting_on_restore_(false),
is_unresponsive_(false),
@@ -187,9 +185,9 @@ RenderWidgetHostImpl::RenderWidgetHostImpl(RenderWidgetHostDelegate* delegate,
pending_mouse_lock_request_(false),
allow_privileged_mouse_lock_(false),
has_touch_handler_(false),
- last_input_number_(static_cast<int64>(GetProcess()->GetID()) << 32),
next_browser_snapshot_id_(1),
- browser_composite_latency_history_(kBrowserCompositeLatencyHistorySize),
+ owned_by_render_frame_host_(false),
+ is_focused_(false),
weak_factory_(this) {
CHECK(delegate_);
if (routing_id_ == MSG_ROUTING_NONE) {
@@ -222,6 +220,8 @@ RenderWidgetHostImpl::RenderWidgetHostImpl(RenderWidgetHostDelegate* delegate,
if (!hidden)
process_->WidgetRestored();
+ latency_tracker_.Initialize(routing_id_, GetProcess()->GetID());
+
input_router_.reset(new InputRouterImpl(
process_, this, this, routing_id_, GetInputRouterConfigForPlatform()));
@@ -321,6 +321,13 @@ void RenderWidgetHostImpl::SetView(RenderWidgetHostViewBase* view) {
view_weak_.reset();
view_ = view;
+ // If the renderer has not yet been initialized, then the surface ID
+ // namespace will be sent during initialization.
+ if (view_ && renderer_initialized_) {
+ Send(new ViewMsg_SetSurfaceIdNamespace(routing_id_,
+ view_->GetSurfaceIdNamespace()));
+ }
+
GpuSurfaceTracker::Get()->SetSurfaceHandle(
surface_id_, GetCompositingSurface());
@@ -362,7 +369,8 @@ void RenderWidgetHostImpl::ResetSizeAndRepaintPendingFlags() {
"renderer_host", "RenderWidgetHostImpl::repaint_ack_pending_", this);
}
repaint_ack_pending_ = false;
- last_requested_size_.SetSize(0, 0);
+ if (old_resize_params_)
+ old_resize_params_->new_size = gfx::Size();
}
void RenderWidgetHostImpl::SendScreenRects() {
@@ -392,7 +400,7 @@ void RenderWidgetHostImpl::SuppressNextCharEvents() {
}
void RenderWidgetHostImpl::FlushInput() {
- input_router_->Flush();
+ input_router_->RequestNotificationWhenFlushed();
if (synthetic_gesture_controller_)
synthetic_gesture_controller_->Flush(base::TimeTicks::Now());
}
@@ -414,9 +422,21 @@ void RenderWidgetHostImpl::Init() {
Send(new ViewMsg_CreatingNew_ACK(routing_id_));
GetProcess()->ResumeRequestsForView(routing_id_);
+ // If the RWHV has not yet been set, the surface ID namespace will get
+ // passed down by the call to SetView().
+ if (view_) {
+ Send(new ViewMsg_SetSurfaceIdNamespace(routing_id_,
+ view_->GetSurfaceIdNamespace()));
+ }
+
WasResized();
}
+void RenderWidgetHostImpl::InitForFrame() {
+ DCHECK(process_->HasConnection());
+ renderer_initialized_ = true;
+}
+
void RenderWidgetHostImpl::Shutdown() {
RejectMouseLockOrUnlockIfNecessary();
@@ -440,12 +460,12 @@ bool RenderWidgetHostImpl::IsRenderView() const {
bool RenderWidgetHostImpl::OnMessageReceived(const IPC::Message &msg) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(RenderWidgetHostImpl, msg)
+ IPC_MESSAGE_HANDLER(FrameHostMsg_RenderProcessGone, OnRenderProcessGone)
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)
IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateScreenRects_ACK,
OnUpdateScreenRectsAck)
@@ -453,7 +473,6 @@ bool RenderWidgetHostImpl::OnMessageReceived(const IPC::Message &msg) {
IPC_MESSAGE_HANDLER(ViewHostMsg_SetTooltipText, OnSetTooltipText)
IPC_MESSAGE_HANDLER_GENERIC(ViewHostMsg_SwapCompositorFrame,
OnSwapCompositorFrame(msg))
- IPC_MESSAGE_HANDLER(ViewHostMsg_DidStopFlinging, OnFlingingStopped)
IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateRect, OnUpdateRect)
IPC_MESSAGE_HANDLER(ViewHostMsg_Focus, OnFocus)
IPC_MESSAGE_HANDLER(ViewHostMsg_Blur, OnBlur)
@@ -473,10 +492,8 @@ bool RenderWidgetHostImpl::OnMessageReceived(const IPC::Message &msg) {
IPC_MESSAGE_HANDLER(ViewHostMsg_WindowlessPluginDummyWindowDestroyed,
OnWindowlessPluginDummyWindowDestroyed)
#endif
-#if defined(OS_MACOSX) || defined(USE_AURA) || defined(OS_ANDROID)
IPC_MESSAGE_HANDLER(InputHostMsg_ImeCompositionRangeChanged,
OnImeCompositionRangeChanged)
-#endif
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
@@ -507,6 +524,7 @@ void RenderWidgetHostImpl::WasHidden() {
if (is_hidden_)
return;
+ TRACE_EVENT0("renderer_host", "RenderWidgetHostImpl::WasHidden");
is_hidden_ = true;
// Don't bother reporting hung state when we aren't active.
@@ -529,10 +547,17 @@ void RenderWidgetHostImpl::WasHidden() {
void RenderWidgetHostImpl::WasShown(const ui::LatencyInfo& latency_info) {
if (!is_hidden_)
return;
+
+ TRACE_EVENT0("renderer_host", "RenderWidgetHostImpl::WasShown");
is_hidden_ = false;
SendScreenRects();
+ // When hidden, timeout monitoring for input events is disabled. Restore it
+ // now to ensure consistent hang detection.
+ if (in_flight_event_count_)
+ RestartHangMonitorTimeout();
+
// Always repaint on restore.
bool needs_repainting = true;
needs_repainting_on_restore_ = false;
@@ -564,62 +589,82 @@ void RenderWidgetHostImpl::WasShown(const ui::LatencyInfo& latency_info) {
WasResized();
}
+bool RenderWidgetHostImpl::GetResizeParams(
+ ViewMsg_Resize_Params* resize_params) {
+ *resize_params = ViewMsg_Resize_Params();
+
+ GetWebScreenInfo(&resize_params->screen_info);
+ resize_params->resizer_rect = GetRootWindowResizerRect();
+
+ if (view_) {
+ resize_params->new_size = view_->GetRequestedRendererSize();
+ resize_params->physical_backing_size = view_->GetPhysicalBackingSize();
+ resize_params->top_controls_height = view_->GetTopControlsHeight();
+ resize_params->top_controls_shrink_blink_size =
+ view_->DoTopControlsShrinkBlinkSize();
+ resize_params->visible_viewport_size = view_->GetVisibleViewportSize();
+ resize_params->is_fullscreen_granted = IsFullscreenGranted();
+ resize_params->display_mode = GetDisplayMode();
+ }
+
+ const bool size_changed =
+ !old_resize_params_ ||
+ old_resize_params_->new_size != resize_params->new_size ||
+ (old_resize_params_->physical_backing_size.IsEmpty() &&
+ !resize_params->physical_backing_size.IsEmpty());
+ bool dirty = size_changed ||
+ old_resize_params_->screen_info != resize_params->screen_info ||
+ old_resize_params_->physical_backing_size !=
+ resize_params->physical_backing_size ||
+ old_resize_params_->is_fullscreen_granted !=
+ resize_params->is_fullscreen_granted ||
+ old_resize_params_->display_mode != resize_params->display_mode ||
+ old_resize_params_->top_controls_height !=
+ resize_params->top_controls_height ||
+ old_resize_params_->top_controls_shrink_blink_size !=
+ resize_params->top_controls_shrink_blink_size ||
+ old_resize_params_->visible_viewport_size !=
+ resize_params->visible_viewport_size;
+
+ // We don't expect to receive an ACK when the requested size or the physical
+ // backing size is empty, or when the main viewport size didn't change.
+ resize_params->needs_resize_ack =
+ g_check_for_pending_resize_ack && !resize_params->new_size.IsEmpty() &&
+ !resize_params->physical_backing_size.IsEmpty() && size_changed;
+
+ return dirty;
+}
+
+void RenderWidgetHostImpl::SetInitialRenderSizeParams(
+ const ViewMsg_Resize_Params& resize_params) {
+ resize_ack_pending_ = resize_params.needs_resize_ack;
+
+ old_resize_params_ =
+ make_scoped_ptr(new ViewMsg_Resize_Params(resize_params));
+}
+
void RenderWidgetHostImpl::WasResized() {
// Skip if the |delegate_| has already been detached because
// it's web contents is being deleted.
if (resize_ack_pending_ || !process_->HasConnection() || !view_ ||
- !renderer_initialized_ || should_auto_resize_ || !delegate_) {
+ !renderer_initialized_ || auto_resize_enabled_ || !delegate_) {
return;
}
- gfx::Size new_size(view_->GetRequestedRendererSize());
-
- gfx::Size old_physical_backing_size = physical_backing_size_;
- physical_backing_size_ = view_->GetPhysicalBackingSize();
- bool was_fullscreen = is_fullscreen_;
- is_fullscreen_ = IsFullscreen();
- 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();
-
- bool size_changed = new_size != last_requested_size_;
- bool side_payload_changed =
- screen_info_out_of_date_ ||
- old_physical_backing_size != physical_backing_size_ ||
- was_fullscreen != is_fullscreen_ ||
- old_top_controls_layout_height !=
- top_controls_layout_height_ ||
- old_visible_viewport_size != visible_viewport_size_;
-
- if (!size_changed && !side_payload_changed)
+ scoped_ptr<ViewMsg_Resize_Params> params(new ViewMsg_Resize_Params);
+ if (!GetResizeParams(params.get()))
return;
- if (!screen_info_) {
- screen_info_.reset(new blink::WebScreenInfo);
- GetWebScreenInfo(screen_info_.get());
+ bool width_changed =
+ !old_resize_params_ ||
+ old_resize_params_->new_size.width() != params->new_size.width();
+ if (Send(new ViewMsg_Resize(routing_id_, *params))) {
+ resize_ack_pending_ = params->needs_resize_ack;
+ old_resize_params_.swap(params);
}
- // We don't expect to receive an ACK when the requested size or the physical
- // backing size is empty, or when the main viewport size didn't change.
- if (!new_size.IsEmpty() && !physical_backing_size_.IsEmpty() && size_changed)
- resize_ack_pending_ = g_check_for_pending_resize_ack;
-
- ViewMsg_Resize_Params params;
- params.screen_info = *screen_info_;
- params.new_size = new_size;
- params.physical_backing_size = physical_backing_size_;
- 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_;
- if (!Send(new ViewMsg_Resize(routing_id_, params))) {
- resize_ack_pending_ = false;
- } else {
- last_requested_size_ = new_size;
- }
+ if (delegate_)
+ delegate_->RenderWidgetWasResized(this, width_changed);
}
void RenderWidgetHostImpl::ResizeRectChanged(const gfx::Rect& new_rect) {
@@ -633,10 +678,14 @@ void RenderWidgetHostImpl::GotFocus() {
}
void RenderWidgetHostImpl::Focus() {
+ is_focused_ = true;
+
Send(new InputMsg_SetFocus(routing_id_, true));
}
void RenderWidgetHostImpl::Blur() {
+ is_focused_ = false;
+
// If there is a pending mouse lock request, we don't want to reject it at
// this point. The user can switch focus back to this view and approve the
// request later.
@@ -675,19 +724,20 @@ void RenderWidgetHostImpl::ViewDestroyed() {
void RenderWidgetHostImpl::CopyFromBackingStore(
const gfx::Rect& src_subrect,
const gfx::Size& accelerated_dst_size,
- const base::Callback<void(bool, const SkBitmap&)>& callback,
- const SkColorType color_type) {
+ ReadbackRequestCallback& callback,
+ const SkColorType preferred_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, color_type);
+ view_->CopyFromCompositingSurface(accelerated_copy_rect,
+ accelerated_dst_size, callback,
+ preferred_color_type);
return;
}
- callback.Run(false, SkBitmap());
+ callback.Run(SkBitmap(), content::READBACK_FAILED);
}
bool RenderWidgetHostImpl::CanCopyFromBackingStore() {
@@ -732,8 +782,6 @@ 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.
@@ -746,7 +794,7 @@ void RenderWidgetHostImpl::WaitForSurface() {
// size of the view_. (For auto-sized views, current_size_ is updated during
// UpdateRect messages.)
gfx::Size view_size = current_size_;
- if (!should_auto_resize_) {
+ if (!auto_resize_enabled_) {
// Get the desired size from the current view bounds.
gfx::Rect view_rect = view_->GetViewBounds();
if (view_rect.IsEmpty())
@@ -755,16 +803,14 @@ void RenderWidgetHostImpl::WaitForSurface() {
}
TRACE_EVENT2("renderer_host",
- "RenderWidgetHostImpl::WaitForBackingStore",
+ "RenderWidgetHostImpl::WaitForSurface",
"width",
base::IntToString(view_size.width()),
"height",
base::IntToString(view_size.height()));
// We should not be asked to paint while we are hidden. If we are hidden,
- // then it means that our consumer failed to call WasShown. If we're not
- // force creating the backing store, it's OK since we can feel free to give
- // out our cached one if we have it.
+ // then it means that our consumer failed to call WasShown.
DCHECK(!is_hidden_) << "WaitForSurface called while hidden!";
// We should never be called recursively; this can theoretically lead to
@@ -773,12 +819,12 @@ void RenderWidgetHostImpl::WaitForSurface() {
base::AutoReset<bool> auto_reset_in_get_backing_store(
&in_get_backing_store_, true);
- // We might have a surface that we can use!
+ // We might have a surface that we can use already.
if (view_->HasAcceleratedSurface(view_size))
return;
- // We do not have a suitable backing store in the cache, so send out a
- // request to the renderer to paint the view if required.
+ // Request that the renderer produce a frame of the right size, if it
+ // hasn't been requested already.
if (!repaint_ack_pending_ && !resize_ack_pending_) {
repaint_start_time_ = TimeTicks::Now();
repaint_ack_pending_ = true;
@@ -787,37 +833,32 @@ void RenderWidgetHostImpl::WaitForSurface() {
Send(new ViewMsg_Repaint(routing_id_, view_size));
}
- TimeDelta max_delay = TimeDelta::FromMilliseconds(kPaintMsgTimeoutMS);
- TimeTicks end_time = TimeTicks::Now() + max_delay;
- do {
- TRACE_EVENT0("renderer_host", "WaitForSurface::WaitForUpdate");
-
- // When we have asked the RenderWidget to resize, and we are still waiting
- // 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 (RenderWidgetResizeHelper::Get()->WaitForSingleTaskToRun(max_delay)) {
-
+ // Pump a nested message loop until we time out or get a frame of the right
+ // size.
+ TimeTicks start_time = TimeTicks::Now();
+ TimeDelta time_left = TimeDelta::FromMilliseconds(kPaintMsgTimeoutMS);
+ TimeTicks timeout_time = start_time + time_left;
+ while (1) {
+ TRACE_EVENT0("renderer_host", "WaitForSurface::WaitForSingleTaskToRun");
+ if (RenderWidgetResizeHelper::Get()->WaitForSingleTaskToRun(time_left)) {
// For auto-resized views, current_size_ determines the view_size and it
// may have changed during the handling of an UpdateRect message.
- if (should_auto_resize_)
+ if (auto_resize_enabled_)
view_size = current_size_;
-
- // Break now if we got a backing store or accelerated surface of the
- // correct size.
if (view_->HasAcceleratedSurface(view_size))
- return;
- } else {
+ break;
+ }
+ time_left = timeout_time - TimeTicks::Now();
+ if (time_left <= TimeDelta::FromSeconds(0)) {
TRACE_EVENT0("renderer_host", "WaitForSurface::Timeout");
break;
}
+ }
- // Loop if we still have time left and haven't gotten a properly sized
- // BackingStore yet. This is necessary to support the GPU path which
- // typically has multiple frames pipelined -- we may need to skip one or two
- // BackingStore messages to get to the latest.
- max_delay = end_time - TimeTicks::Now();
- } while (max_delay > TimeDelta::FromSeconds(0));
+ UMA_HISTOGRAM_CUSTOM_TIMES("OSX.RendererHost.SurfaceWaitTime",
+ TimeTicks::Now() - start_time,
+ TimeDelta::FromMilliseconds(1),
+ TimeDelta::FromMilliseconds(200), 50);
}
#endif
@@ -843,8 +884,7 @@ void RenderWidgetHostImpl::StartHangMonitorTimeout(base::TimeDelta delay) {
void RenderWidgetHostImpl::RestartHangMonitorTimeout() {
if (hang_monitor_timeout_)
- hang_monitor_timeout_->Restart(
- base::TimeDelta::FromMilliseconds(hung_renderer_delay_ms_));
+ hang_monitor_timeout_->Restart(hung_renderer_delay_);
}
void RenderWidgetHostImpl::StopHangMonitorTimeout() {
@@ -862,11 +902,6 @@ 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 = 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))
@@ -879,11 +914,20 @@ void RenderWidgetHostImpl::ForwardMouseEventWithLatencyInfo(
if (touch_emulator_ && touch_emulator_->HandleMouseEvent(mouse_event))
return;
- input_router_->SendMouseEvent(MouseEventWithLatencyInfo(mouse_event,
- latency_info));
-}
+ MouseEventWithLatencyInfo mouse_with_latency(mouse_event, ui_latency);
+ latency_tracker_.OnInputEvent(mouse_event, &mouse_with_latency.latency);
+ input_router_->SendMouseEvent(mouse_with_latency);
-void RenderWidgetHostImpl::OnPointerEventActivate() {
+ // Pass mouse state to gpu service if the subscribe uniform
+ // extension is enabled.
+ if (process_->SubscribeUniformEnabled()) {
+ gpu::ValueState state;
+ state.int_value[0] = mouse_event.x;
+ state.int_value[1] = mouse_event.y;
+ // TODO(orglofch) Separate the mapping of pending value states to the
+ // Gpu Service to be per RWH not per process
+ process_->SendUpdateValueState(GL_MOUSE_POSITION_CHROMIUM, state);
+ }
}
void RenderWidgetHostImpl::ForwardWheelEvent(
@@ -896,20 +940,15 @@ void RenderWidgetHostImpl::ForwardWheelEventWithLatencyInfo(
const ui::LatencyInfo& ui_latency) {
TRACE_EVENT0("input", "RenderWidgetHostImpl::ForwardWheelEvent");
- 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;
if (touch_emulator_ && touch_emulator_->HandleMouseWheelEvent(wheel_event))
return;
- input_router_->SendWheelEvent(MouseWheelEventWithLatencyInfo(wheel_event,
- latency_info));
+ MouseWheelEventWithLatencyInfo wheel_with_latency(wheel_event, ui_latency);
+ latency_tracker_.OnInputEvent(wheel_event, &wheel_with_latency.latency);
+ input_router_->SendWheelEvent(wheel_with_latency);
}
void RenderWidgetHostImpl::ForwardGestureEvent(
@@ -928,35 +967,8 @@ void RenderWidgetHostImpl::ForwardGestureEventWithLatencyInfo(
if (delegate_->PreHandleGestureEvent(gesture_event))
return;
- 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(
- ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_RWH_COMPONENT,
- GetLatencyComponentId(),
- ++last_input_number_);
-
- // Make a copy of the INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT with a
- // different name INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT.
- // So we can track the latency specifically for scroll update events.
- ui::LatencyInfo::LatencyComponent original_component;
- if (latency_info.FindLatency(ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
- 0,
- &original_component)) {
- latency_info.AddLatencyNumberWithTimestamp(
- ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT,
- GetLatencyComponentId(),
- original_component.sequence_number,
- original_component.event_time,
- original_component.event_count);
- }
- }
-
- GestureEventWithLatencyInfo gesture_with_latency(gesture_event, latency_info);
+ GestureEventWithLatencyInfo gesture_with_latency(gesture_event, ui_latency);
+ latency_tracker_.OnInputEvent(gesture_event, &gesture_with_latency.latency);
input_router_->SendGestureEvent(gesture_with_latency);
}
@@ -964,19 +976,8 @@ void RenderWidgetHostImpl::ForwardEmulatedTouchEvent(
const blink::WebTouchEvent& touch_event) {
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);
+ TouchEventWithLatencyInfo touch_with_latency(touch_event);
+ latency_tracker_.OnInputEvent(touch_event, &touch_with_latency.latency);
input_router_->SendTouchEvent(touch_with_latency);
}
@@ -988,23 +989,7 @@ void RenderWidgetHostImpl::ForwardTouchEventWithLatencyInfo(
// Always forward TouchEvents for touch stream consistency. They will be
// ignored if appropriate in FilterInputEvent().
- 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);
-
+ TouchEventWithLatencyInfo touch_with_latency(touch_event, ui_latency);
if (touch_emulator_ &&
touch_emulator_->HandleTouchEvent(touch_with_latency.event)) {
if (view_) {
@@ -1014,6 +999,7 @@ void RenderWidgetHostImpl::ForwardTouchEventWithLatencyInfo(
return;
}
+ latency_tracker_.OnInputEvent(touch_event, &touch_with_latency.latency);
input_router_->SendTouchEvent(touch_with_latency);
}
@@ -1081,10 +1067,9 @@ void RenderWidgetHostImpl::ForwardKeyboardEvent(
if (touch_emulator_ && touch_emulator_->HandleKeyboardEvent(key_event))
return;
- input_router_->SendKeyboardEvent(
- key_event,
- CreateInputEventLatencyInfoIfNotExist(NULL, key_event.type, NULL, 0),
- is_shortcut);
+ ui::LatencyInfo latency;
+ latency_tracker_.OnInputEvent(key_event, &latency);
+ input_router_->SendKeyboardEvent(key_event, latency, is_shortcut);
}
void RenderWidgetHostImpl::QueueSyntheticGesture(
@@ -1117,7 +1102,7 @@ void RenderWidgetHostImpl::SendCursorVisibilityState(bool is_visible) {
}
int64 RenderWidgetHostImpl::GetLatencyComponentId() const {
- return GetRoutingID() | (static_cast<int64>(GetProcess()->GetID()) << 32);
+ return latency_tracker_.latency_component_id();
}
// static
@@ -1125,42 +1110,6 @@ void RenderWidgetHostImpl::DisableResizeAckCheckForTesting() {
g_check_for_pending_resize_ack = false;
}
-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;
- // In Aura, gesture event will already carry its original touch event's
- // INPUT_EVENT_LATENCY_RWH_COMPONENT.
- if (!info.FindLatency(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
- GetLatencyComponentId(),
- NULL)) {
- info.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
- 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;
-}
-
-
void RenderWidgetHostImpl::AddKeyPressEventCallback(
const KeyPressEventCallback& callback) {
key_press_event_callbacks_.push_back(callback);
@@ -1198,7 +1147,9 @@ void RenderWidgetHostImpl::GetWebScreenInfo(blink::WebScreenInfo* result) {
view_->GetScreenInfo(result);
else
RenderWidgetHostViewBase::GetDefaultScreenInfo(result);
- screen_info_out_of_date_ = false;
+ // TODO(sievers): find a way to make this done another way so the method
+ // can be const.
+ latency_tracker_.set_device_scale_factor(result->deviceScaleFactor);
}
const NativeWebKeyboardEvent*
@@ -1207,18 +1158,15 @@ const NativeWebKeyboardEvent*
}
void RenderWidgetHostImpl::NotifyScreenInfoChanged() {
+ if (delegate_)
+ delegate_->ScreenInfoChanged();
+
// The resize message (which may not happen immediately) will carry with it
// the screen info as well as the new size (if the screen has changed scale
// factor).
- InvalidateScreenInfo();
WasResized();
}
-void RenderWidgetHostImpl::InvalidateScreenInfo() {
- screen_info_out_of_date_ = true;
- screen_info_.reset();
-}
-
void RenderWidgetHostImpl::GetSnapshotFromBrowser(
const base::Callback<void(const unsigned char*,size_t)> callback) {
int id = next_browser_snapshot_id_++;
@@ -1274,6 +1222,7 @@ void RenderWidgetHostImpl::RendererExited(base::TerminationStatus status,
// Reset this to ensure the hung renderer mechanism is working properly.
in_flight_event_count_ = 0;
+ StopHangMonitorTimeout();
if (view_) {
GpuSurfaceTracker::Get()->SetSurfaceHandle(surface_id_,
@@ -1376,12 +1325,20 @@ bool RenderWidgetHostImpl::IsMouseLocked() const {
return view_ ? view_->IsMouseLocked() : false;
}
-bool RenderWidgetHostImpl::IsFullscreen() const {
+bool RenderWidgetHostImpl::IsFullscreenGranted() const {
return false;
}
-void RenderWidgetHostImpl::SetShouldAutoResize(bool enable) {
- should_auto_resize_ = enable;
+blink::WebDisplayMode RenderWidgetHostImpl::GetDisplayMode() const {
+ return blink::WebDisplayModeBrowser;
+}
+
+void RenderWidgetHostImpl::SetAutoResize(bool enable,
+ const gfx::Size& min_size,
+ const gfx::Size& max_size) {
+ auto_resize_enabled_ = enable;
+ min_size_for_auto_resize_ = min_size;
+ max_size_for_auto_resize_ = max_size;
}
void RenderWidgetHostImpl::Destroy() {
@@ -1394,8 +1351,10 @@ void RenderWidgetHostImpl::Destroy() {
// Note that in the process of the view shutting down, it can call a ton
// of other messages on us. So if you do any other deinitialization here,
// do it after this call to view_->Destroy().
- if (view_)
+ if (view_) {
view_->Destroy();
+ view_ = nullptr;
+ }
delete this;
}
@@ -1422,10 +1381,16 @@ void RenderWidgetHostImpl::OnRenderViewReady() {
}
void RenderWidgetHostImpl::OnRenderProcessGone(int status, int exit_code) {
- // TODO(evanm): This synchronously ends up calling "delete this".
- // Is that really what we want in response to this message? I'm matching
- // previous behavior of the code here.
- Destroy();
+ // RenderFrameHost owns a RenderWidgetHost when it needs one, in which case
+ // it handles destruction.
+ if (!owned_by_render_frame_host_) {
+ // TODO(evanm): This synchronously ends up calling "delete this".
+ // Is that really what we want in response to this message? I'm matching
+ // previous behavior of the code here.
+ Destroy();
+ } else {
+ RendererExited(static_cast<base::TerminationStatus>(status), exit_code);
+ }
}
void RenderWidgetHostImpl::OnClose() {
@@ -1488,26 +1453,24 @@ bool RenderWidgetHostImpl::OnSwapCompositorFrame(
const IPC::Message& message) {
// This trace event is used in
// chrome/browser/extensions/api/cast_streaming/performance_test.cc
- TRACE_EVENT0("test_fps",
- TRACE_DISABLED_BY_DEFAULT("OnSwapCompositorFrame"));
+ TRACE_EVENT0("test_fps,benchmark", "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());
+ uint32 output_surface_id = get<0>(param);
+ get<1>(param).AssignTo(frame.get());
std::vector<IPC::Message> messages_to_deliver_with_frame;
- messages_to_deliver_with_frame.swap(param.c);
+ messages_to_deliver_with_frame.swap(get<2>(param));
- for (size_t i = 0; i < frame->metadata.latency_info.size(); i++)
- AddLatencyInfoComponentIds(&frame->metadata.latency_info[i]);
+ latency_tracker_.OnSwapCompositorFrame(&frame->metadata.latency_info);
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 (touch_emulator_) {
+ touch_emulator_->SetDoubleTapSupportForPageEnabled(
+ !IsMobileOptimizedFrame(frame->metadata));
}
if (view_) {
@@ -1543,11 +1506,6 @@ bool RenderWidgetHostImpl::OnSwapCompositorFrame(
return true;
}
-void RenderWidgetHostImpl::OnFlingingStopped() {
- if (view_)
- view_->DidStopFlinging();
-}
-
void RenderWidgetHostImpl::OnUpdateRect(
const ViewHostMsg_UpdateRect_Params& params) {
TRACE_EVENT0("renderer_host", "RenderWidgetHostImpl::OnUpdateRect");
@@ -1581,7 +1539,7 @@ void RenderWidgetHostImpl::OnUpdateRect(
DidUpdateBackingStore(params, paint_start);
- if (should_auto_resize_) {
+ if (auto_resize_enabled_) {
bool post_callback = new_auto_size_.IsEmpty();
new_auto_size_ = params.view_size;
if (post_callback) {
@@ -1641,8 +1599,8 @@ void RenderWidgetHostImpl::OnQueueSyntheticGesture(
// Only allow untrustworthy gestures if explicitly enabled.
if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
cc::switches::kEnableGpuBenchmarking)) {
- RecordAction(base::UserMetricsAction("BadMessageTerminate_RWH7"));
- GetProcess()->ReceivedBadMessage();
+ bad_message::ReceivedBadMessage(GetProcess(),
+ bad_message::RWH_SYNTHETIC_GESTURE);
return;
}
@@ -1654,25 +1612,24 @@ void RenderWidgetHostImpl::OnQueueSyntheticGesture(
void RenderWidgetHostImpl::OnFocus() {
// Only RenderViewHost can deal with that message.
- RecordAction(base::UserMetricsAction("BadMessageTerminate_RWH4"));
- GetProcess()->ReceivedBadMessage();
+ bad_message::ReceivedBadMessage(GetProcess(), bad_message::RWH_FOCUS);
}
void RenderWidgetHostImpl::OnBlur() {
// Only RenderViewHost can deal with that message.
- RecordAction(base::UserMetricsAction("BadMessageTerminate_RWH5"));
- GetProcess()->ReceivedBadMessage();
+ bad_message::ReceivedBadMessage(GetProcess(), bad_message::RWH_BLUR);
}
void RenderWidgetHostImpl::OnSetCursor(const WebCursor& cursor) {
SetCursor(cursor);
}
-void RenderWidgetHostImpl::SetTouchEventEmulationEnabled(bool enabled) {
+void RenderWidgetHostImpl::SetTouchEventEmulationEnabled(
+ bool enabled, ui::GestureProviderConfigType config_type) {
if (enabled) {
if (!touch_emulator_)
touch_emulator_.reset(new TouchEmulator(this));
- touch_emulator_->Enable();
+ touch_emulator_->Enable(config_type);
} else {
if (touch_emulator_)
touch_emulator_->Disable();
@@ -1688,14 +1645,12 @@ void RenderWidgetHostImpl::OnTextInputTypeChanged(
view_->TextInputTypeChanged(type, input_mode, can_compose_inline, flags);
}
-#if defined(OS_MACOSX) || defined(USE_AURA) || defined(OS_ANDROID)
void RenderWidgetHostImpl::OnImeCompositionRangeChanged(
const gfx::Range& range,
const std::vector<gfx::Rect>& character_bounds) {
if (view_)
view_->ImeCompositionRangeChanged(range, character_bounds);
}
-#endif
void RenderWidgetHostImpl::OnImeCancelComposition() {
if (view_)
@@ -1737,8 +1692,8 @@ void RenderWidgetHostImpl::OnShowDisambiguationPopup(
scoped_ptr<cc::SharedBitmap> bitmap =
HostSharedBitmapManager::current()->GetSharedBitmapFromId(size, id);
if (!bitmap) {
- RecordAction(base::UserMetricsAction("BadMessageTerminate_RWH6"));
- GetProcess()->ReceivedBadMessage();
+ bad_message::ReceivedBadMessage(GetProcess(),
+ bad_message::RWH_SHARED_BITMAP);
return;
}
@@ -1833,27 +1788,29 @@ InputEventAckState RenderWidgetHostImpl::FilterInputEvent(
if (!process_->HasConnection())
return INPUT_EVENT_ACK_STATE_UNKNOWN;
- if (event.type == WebInputEvent::MouseDown)
+ if (event.type == WebInputEvent::MouseDown ||
+ event.type == WebInputEvent::GestureTapDown) {
OnUserGesture();
+ }
return view_ ? view_->FilterInputEvent(event)
: INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
}
void RenderWidgetHostImpl::IncrementInFlightEventCount() {
- StartHangMonitorTimeout(
- TimeDelta::FromMilliseconds(hung_renderer_delay_ms_));
increment_in_flight_event_count();
+ if (!is_hidden_)
+ StartHangMonitorTimeout(hung_renderer_delay_);
}
void RenderWidgetHostImpl::DecrementInFlightEventCount() {
- DCHECK_GE(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();
+ if (!is_hidden_)
+ RestartHangMonitorTimeout();
}
}
@@ -1864,8 +1821,6 @@ void RenderWidgetHostImpl::OnHasTouchEventHandlers(bool has_handlers) {
void RenderWidgetHostImpl::DidFlush() {
if (synthetic_gesture_controller_)
synthetic_gesture_controller_->OnDidFlushInput();
- if (view_)
- view_->OnDidFlushInput();
}
void RenderWidgetHostImpl::DidOverscroll(const DidOverscrollParams& params) {
@@ -1873,6 +1828,11 @@ void RenderWidgetHostImpl::DidOverscroll(const DidOverscrollParams& params) {
view_->DidOverscroll(params);
}
+void RenderWidgetHostImpl::DidStopFlinging() {
+ if (view_)
+ view_->DidStopFlinging();
+}
+
void RenderWidgetHostImpl::OnKeyboardEventAck(
const NativeWebKeyboardEvent& event,
InputEventAckState ack_result) {
@@ -1897,17 +1857,7 @@ 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.
- latency.AddLatencyNumber(
- ui::INPUT_EVENT_LATENCY_TERMINATED_MOUSE_COMPONENT, 0, 0);
- }
- ComputeInputLatencyHistograms(blink::WebInputEvent::MouseWheel, latency);
+ latency_tracker_.OnInputEventAck(wheel_event.event, &wheel_event.latency);
if (!is_hidden() && view_) {
if (ack_result != INPUT_EVENT_ACK_STATE_CONSUMED &&
@@ -1921,19 +1871,7 @@ void RenderWidgetHostImpl::OnWheelEventAck(
void RenderWidgetHostImpl::OnGestureEventAck(
const GestureEventWithLatencyInfo& event,
InputEventAckState ack_result) {
- if (!event.latency.FindLatency(
- ui::INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_COMPONENT, 0, NULL)) {
- // GestureEvent latency ends when it is acked but does not cause any
- // rendering scheduled.
- ui::LatencyInfo latency = event.latency;
- latency.AddLatencyNumber(
- ui::INPUT_EVENT_LATENCY_TERMINATED_GESTURE_COMPONENT, 0 ,0);
- }
-
- if (ack_result != INPUT_EVENT_ACK_STATE_CONSUMED) {
- if (delegate_->HandleGestureEvent(event.event))
- ack_result = INPUT_EVENT_ACK_STATE_CONSUMED;
- }
+ latency_tracker_.OnInputEventAck(event.event, &event.latency);
if (view_)
view_->GestureEventAck(event.event, ack_result);
@@ -1942,17 +1880,7 @@ void RenderWidgetHostImpl::OnGestureEventAck(
void RenderWidgetHostImpl::OnTouchEventAck(
const TouchEventWithLatencyInfo& event,
InputEventAckState ack_result) {
- TouchEventWithLatencyInfo touch_event = event;
- touch_event.latency.AddLatencyNumber(
- 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);
- }
- ComputeInputLatencyHistograms(
- blink::WebInputEvent::TouchTypeFirst, touch_event.latency);
+ latency_tracker_.OnInputEventAck(event.event, &event.latency);
if (touch_emulator_ &&
touch_emulator_->HandleTouchEventAck(event.event, ack_result)) {
@@ -1960,13 +1888,12 @@ void RenderWidgetHostImpl::OnTouchEventAck(
}
if (view_)
- view_->ProcessAckedTouchEvent(touch_event, ack_result);
+ view_->ProcessAckedTouchEvent(event, ack_result);
}
void RenderWidgetHostImpl::OnUnexpectedEventAck(UnexpectedEventAckType type) {
if (type == BAD_ACK_MESSAGE) {
- RecordAction(base::UserMetricsAction("BadMessageTerminate_RWH2"));
- process_->ReceivedBadMessage();
+ bad_message::ReceivedBadMessage(process_, bad_message::RWH_BAD_ACK_MESSAGE);
} else if (type == UNEXPECTED_EVENT_TYPE) {
suppress_next_char_events_ = false;
}
@@ -1981,17 +1908,6 @@ 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();
-}
-
void RenderWidgetHostImpl::StartUserGesture() {
OnUserGesture();
}
@@ -2073,7 +1989,7 @@ void RenderWidgetHostImpl::DelayedAutoResized() {
// indicate that no callback is in progress (i.e. without this line
// DelayedAutoResized will not get called again).
new_auto_size_.SetSize(0, 0);
- if (!should_auto_resize_)
+ if (!auto_resize_enabled_)
return;
OnRenderAutoResized(new_size);
@@ -2083,73 +1999,8 @@ void RenderWidgetHostImpl::DetachDelegate() {
delegate_ = NULL;
}
-void RenderWidgetHostImpl::ComputeInputLatencyHistograms(
- blink::WebInputEvent::Type type,
- const ui::LatencyInfo& latency_info) const {
- ui::LatencyInfo::LatencyComponent rwh_component;
- if (!latency_info.FindLatency(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
- GetLatencyComponentId(),
- &rwh_component))
- return;
- DCHECK_EQ(rwh_component.event_count, 1u);
-
- 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;
- }
- }
-
- ui::LatencyInfo::LatencyComponent acked_component;
- if (latency_info.FindLatency(ui::INPUT_EVENT_LATENCY_ACK_RWH_COMPONENT,
- 0,
- &acked_component)) {
- DCHECK_EQ(acked_component.event_count, 1u);
- base::TimeDelta acked_delta =
- acked_component.event_time - rwh_component.event_time;
- 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)) {
@@ -2171,124 +2022,13 @@ void RenderWidgetHostImpl::FrameSwapped(const ui::LatencyInfo& latency_info) {
#endif
}
- 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)) {
- return;
- }
-
- ui::LatencyInfo::LatencyComponent original_component;
- if (latency_info.FindLatency(
- ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT,
- GetLatencyComponentId(),
- &original_component)) {
- // This UMA metric tracks the time from when the original touch event is
- // created (averaged if there are multiple) to when the scroll gesture
- // results in final frame swap.
- base::TimeDelta delta =
- swap_component.event_time - original_component.event_time;
- for (size_t i = 0; i < original_component.event_count; i++) {
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "Event.Latency.TouchToScrollUpdateSwap",
- delta.InMicroseconds(),
- 1,
- 1000000,
- 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);
- }
+ latency_tracker_.OnFrameSwapped(latency_info);
}
void RenderWidgetHostImpl::DidReceiveRendererFrame() {
view_->DidReceiveRendererFrame();
}
-void RenderWidgetHostImpl::WindowSnapshotAsyncCallback(
- int routing_id,
- int snapshot_id,
- gfx::Size snapshot_size,
- scoped_refptr<base::RefCountedBytes> png_data) {
- if (!png_data.get()) {
- std::vector<unsigned char> png_vector;
- Send(new ViewMsg_WindowSnapshotCompleted(
- routing_id, snapshot_id, gfx::Size(), png_vector));
- return;
- }
-
- Send(new ViewMsg_WindowSnapshotCompleted(
- routing_id, snapshot_id, snapshot_size, png_data->data()));
-}
-
-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 base::CommandLine& command_line =
- *base::CommandLine::ForCurrentProcess();
- if (!command_line.HasSwitch(cc::switches::kEnableGpuBenchmarking)) {
- Send(new ViewMsg_WindowSnapshotCompleted(
- GetRoutingID(), snapshot_id, gfx::Size(), png));
- return;
- }
-
- gfx::Rect view_bounds = GetView()->GetViewBounds();
- gfx::Rect snapshot_bounds(view_bounds.size());
- gfx::Size snapshot_size = snapshot_bounds.size();
-
- if (ui::GrabViewSnapshot(
- GetView()->GetNativeView(), &png, snapshot_bounds)) {
- Send(new ViewMsg_WindowSnapshotCompleted(
- GetRoutingID(), snapshot_id, snapshot_size, png));
- return;
- }
-
- ui::GrabViewSnapshotAsync(
- GetView()->GetNativeView(),
- snapshot_bounds,
- base::ThreadTaskRunnerHandle::Get(),
- base::Bind(&RenderWidgetHostImpl::WindowSnapshotAsyncCallback,
- weak_factory_.GetWeakPtr(),
- GetRoutingID(),
- snapshot_id,
- snapshot_size));
-}
-
void RenderWidgetHostImpl::WindowSnapshotReachedScreen(int snapshot_id) {
DCHECK(base::MessageLoopForUI::IsCurrent());
@@ -2347,7 +2087,6 @@ void RenderWidgetHostImpl::CompositorFrameDrawn(
++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_OLD_SNAPSHOT_FRAME_NUMBER_COMPONENT ||
b->first.first == ui::TAB_SHOW_COMPONENT) {
// Matches with GetLatencyComponentId
int routing_id = b->first.second & 0xffffffff;
@@ -2365,33 +2104,6 @@ void RenderWidgetHostImpl::CompositorFrameDrawn(
}
}
-void RenderWidgetHostImpl::AddLatencyInfoComponentIds(
- ui::LatencyInfo* latency_info) {
- ui::LatencyInfo::LatencyMap new_components;
- ui::LatencyInfo::LatencyMap::iterator lc =
- 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 ||
- 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());
- new_components[key] = lc->second;
-
- // Remove the old entry
- latency_info->latency_components.erase(lc++);
- } else {
- ++lc;
- }
- }
-
- // Add newly generated components into the latency info
- for (lc = new_components.begin(); lc != new_components.end(); ++lc) {
- latency_info->latency_components[lc->first] = lc->second;
- }
-}
-
BrowserAccessibilityManager*
RenderWidgetHostImpl::GetRootBrowserAccessibilityManager() {
return delegate_ ? delegate_->GetRootBrowserAccessibilityManager() : NULL;
@@ -2403,15 +2115,8 @@ BrowserAccessibilityManager*
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)));
+base::TimeDelta RenderWidgetHostImpl::GetEstimatedBrowserCompositeTime() const {
+ return latency_tracker_.GetEstimatedBrowserCompositeTime();
}
#if defined(OS_WIN)
@@ -2421,10 +2126,4 @@ gfx::NativeViewAccessible
}
#endif
-SkColorType RenderWidgetHostImpl::PreferredReadbackFormat() {
- if (view_)
- return view_->PreferredReadbackFormat();
- 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 71aa04fcf34..4e89686898e 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_impl.h
+++ b/chromium/content/browser/renderer_host/render_widget_host_impl.h
@@ -23,21 +23,24 @@
#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/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"
+#include "content/browser/renderer_host/input/render_widget_host_latency_tracker.h"
#include "content/browser/renderer_host/input/synthetic_gesture.h"
#include "content/browser/renderer_host/input/touch_emulator_client.h"
#include "content/common/input/input_event_ack_state.h"
#include "content/common/input/synthetic_gesture_packet.h"
#include "content/common/view_message_enums.h"
+#include "content/public/browser/readback_types.h"
#include "content/public/browser/render_widget_host.h"
#include "content/public/common/page_zoom.h"
#include "ipc/ipc_listener.h"
+#include "third_party/WebKit/public/platform/WebDisplayMode.h"
#include "ui/base/ime/text_input_mode.h"
#include "ui/base/ime/text_input_type.h"
+#include "ui/events/gesture_detection/gesture_provider_config_helper.h"
#include "ui/events/latency_info.h"
#include "ui/gfx/native_widget_types.h"
@@ -46,6 +49,7 @@ struct ViewHostMsg_BeginSmoothScroll_Params;
struct ViewHostMsg_SelectionBounds_Params;
struct ViewHostMsg_TextInputState_Params;
struct ViewHostMsg_UpdateRect_Params;
+struct ViewMsg_Resize_Params;
namespace base {
class TimeTicks;
@@ -121,8 +125,8 @@ class CONTENT_EXPORT RenderWidgetHostImpl
// uses RenderWidgetHost::AsRenderWidgetHostImpl().
static RenderWidgetHostImpl* From(RenderWidgetHost* rwh);
- void set_hung_renderer_delay_ms(const base::TimeDelta& timeout) {
- hung_renderer_delay_ms_ = timeout.InMilliseconds();
+ void set_hung_renderer_delay(const base::TimeDelta& delay) {
+ hung_renderer_delay_ = delay;
}
// RenderWidgetHost implementation.
@@ -131,15 +135,14 @@ class CONTENT_EXPORT RenderWidgetHostImpl
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 SkColorType color_type) override;
+ void CopyFromBackingStore(const gfx::Rect& src_rect,
+ const gfx::Size& accelerated_dst_size,
+ ReadbackRequestCallback& callback,
+ const SkColorType preferred_color_type) override;
bool CanCopyFromBackingStore() override;
#if defined(OS_ANDROID)
- virtual void LockBackingStore() override;
- virtual void UnlockBackingStore() override;
+ void LockBackingStore() override;
+ void UnlockBackingStore() override;
#endif
void ForwardMouseEvent(const blink::WebMouseEvent& mouse_event) override;
void ForwardWheelEvent(const blink::WebMouseWheelEvent& wheel_event) override;
@@ -160,8 +163,6 @@ class CONTENT_EXPORT RenderWidgetHostImpl
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(
@@ -172,11 +173,6 @@ class CONTENT_EXPORT RenderWidgetHostImpl
// Notification that the screen info has changed.
void NotifyScreenInfoChanged();
- // Invalidates the cached screen info so that next resize request
- // will carry the up to date screen info. Unlike
- // |NotifyScreenInfoChanged|, this doesn't send a message to the renderer.
- void InvalidateScreenInfo();
-
// Sets the View of this RenderWidgetHost.
void SetView(RenderWidgetHostViewBase* view);
@@ -189,6 +185,15 @@ class CONTENT_EXPORT RenderWidgetHostImpl
// menus, and other times when the renderer initiates creating an object.
virtual void Init();
+ // Initializes a RenderWidgetHost that is attached to a RenderFrameHost.
+ void InitForFrame();
+
+ // Signal whether this RenderWidgetHost is owned by a RenderFrameHost, in
+ // which case it does not do self-deletion.
+ void set_owned_by_render_frame_host(bool owned_by_rfh) {
+ owned_by_render_frame_host_ = owned_by_rfh;
+ }
+
// Tells the renderer to die and then calls Destroy().
virtual void Shutdown();
@@ -214,6 +219,15 @@ class CONTENT_EXPORT RenderWidgetHostImpl
virtual void GotFocus();
virtual void LostCapture();
+ // Indicates whether the RenderWidgetHost thinks it is focused.
+ // This is different from RenderWidgetHostView::HasFocus() in the sense that
+ // it reflects what the renderer process knows: it saves the state that is
+ // sent/received.
+ // RenderWidgetHostView::HasFocus() is checking whether the view is focused so
+ // it is possible in some edge cases that a view was requested to be focused
+ // but it failed, thus HasFocus() returns false.
+ bool is_focused() const { return is_focused_; }
+
// Called to notify the RenderWidget that it has lost the mouse lock.
virtual void LostMouseLock();
@@ -269,7 +283,8 @@ class CONTENT_EXPORT RenderWidgetHostImpl
const ui::LatencyInfo& ui_latency);
// Enables/disables touch emulation using mouse event. See TouchEmulator.
- void SetTouchEventEmulationEnabled(bool enabled);
+ void SetTouchEventEmulationEnabled(
+ bool enabled, ui::GestureProviderConfigType config_type);
// TouchEmulatorClient implementation.
void ForwardGestureEvent(
@@ -287,9 +302,6 @@ class CONTENT_EXPORT RenderWidgetHostImpl
void CancelUpdateTextDirection();
- // Called when a mouse click/gesture tap activates the renderer.
- virtual void OnPointerEventActivate();
-
// Notifies the renderer whether or not the input method attached to this
// process is activated.
// When the input method is activated, a renderer process sends IPC messages
@@ -353,9 +365,6 @@ class CONTENT_EXPORT RenderWidgetHostImpl
// |ignore_input_events_| or |process_->IgnoreInputEvents()| is true.
bool IgnoreInputEvents() const;
- // Event queries delegated to the |input_router_|.
- bool ShouldForwardTouchEvent() const;
-
bool has_touch_handler() const { return has_touch_handler_; }
// Notification that the user has made some kind of input that could
@@ -388,9 +397,6 @@ class CONTENT_EXPORT RenderWidgetHostImpl
bool GotResponseToLockMouseRequest(bool allowed);
// Tells the RenderWidget about the latest vsync parameters.
- // Note: Make sure the timebase was obtained using
- // base::TimeTicks::HighResNow. Using the non-high res timer will result in
- // incorrect synchronization across processes.
virtual void UpdateVSyncParameters(base::TimeTicks timebase,
base::TimeDelta interval);
@@ -427,15 +433,25 @@ class CONTENT_EXPORT RenderWidgetHostImpl
// suppress_next_char_events_.
void SuppressNextCharEvents();
- // Called by RenderWidgetHostView in response to OnSetNeedsFlushInput.
+ // Called by the view in response to a flush request.
void FlushInput();
- // InputRouterClient
- void SetNeedsFlush() override;
+ // Request a flush signal from the view.
+ void SetNeedsFlush();
// Indicates whether the renderer drives the RenderWidgetHosts's size or the
// other way around.
- bool should_auto_resize() { return should_auto_resize_; }
+ bool auto_resize_enabled() { return auto_resize_enabled_; }
+
+ // The minimum size of this renderer when auto-resize is enabled.
+ const gfx::Size& min_size_for_auto_resize() const {
+ return min_size_for_auto_resize_;
+ }
+
+ // The maximum size of this renderer when auto-resize is enabled.
+ const gfx::Size& max_size_for_auto_resize() const {
+ return max_size_for_auto_resize_;
+ }
void FrameSwapped(const ui::LatencyInfo& latency_info);
void DidReceiveRendererFrame();
@@ -444,23 +460,14 @@ class CONTENT_EXPORT RenderWidgetHostImpl
// subsystem.
int64 GetLatencyComponentId() const;
+ base::TimeDelta GetEstimatedBrowserCompositeTime() const;
+
static void CompositorFrameDrawn(
const std::vector<ui::LatencyInfo>& latency_info);
// Don't check whether we expected a resize ack during layout tests.
static void DisableResizeAckCheckForTesting();
- void WindowSnapshotAsyncCallback(
- int routing_id,
- int snapshot_id,
- gfx::Size snapshot_size,
- scoped_refptr<base::RefCountedBytes> png_data);
-
- // LatencyComponents generated in the renderer must have component IDs
- // provided to them by the browser process. This function adds the correct
- // component ID where necessary.
- void AddLatencyInfoComponentIds(ui::LatencyInfo* latency_info);
-
InputRouter* input_router() { return input_router_.get(); }
// Get the BrowserAccessibilityManager for the root of the frame tree,
@@ -470,7 +477,7 @@ class CONTENT_EXPORT RenderWidgetHostImpl
// or create it if it doesn't already exist.
BrowserAccessibilityManager* GetOrCreateRootBrowserAccessibilityManager();
- base::TimeDelta GetEstimatedBrowserCompositeTime();
+ void RejectMouseLockOrUnlockIfNecessary();
#if defined(OS_WIN)
gfx::NativeViewAccessible GetParentNativeViewAccessible();
@@ -479,20 +486,6 @@ class CONTENT_EXPORT RenderWidgetHostImpl
protected:
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 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
// consistent if a new renderer is created.
@@ -535,20 +528,41 @@ class CONTENT_EXPORT RenderWidgetHostImpl
virtual void RequestToLockMouse(bool user_gesture,
bool last_unlocked_by_target);
- void RejectMouseLockOrUnlockIfNecessary();
bool IsMouseLocked() const;
- // RenderViewHost overrides this method to report when in fullscreen mode.
- virtual bool IsFullscreen() const;
+ // RenderViewHost overrides this method to report whether tab-initiated
+ // fullscreen was granted.
+ virtual bool IsFullscreenGranted() const;
+
+ virtual blink::WebDisplayMode GetDisplayMode() const;
// Indicates if the render widget host should track the render widget's size
// as opposed to visa versa.
- void SetShouldAutoResize(bool enable);
+ void SetAutoResize(bool enable,
+ const gfx::Size& min_size,
+ const gfx::Size& max_size);
+
+ // Fills in the |resize_params| struct.
+ // Returns |false| if the update is redundant, |true| otherwise.
+ bool GetResizeParams(ViewMsg_Resize_Params* resize_params);
+
+ // Sets the |resize_params| that were sent to the renderer bundled with the
+ // request to create a new RenderWidget.
+ void SetInitialRenderSizeParams(const ViewMsg_Resize_Params& resize_params);
// Expose increment/decrement of the in-flight event count, so
// RenderViewHostImpl can account for in-flight beforeunload/unload events.
int increment_in_flight_event_count() { return ++in_flight_event_count_; }
- int decrement_in_flight_event_count() { return --in_flight_event_count_; }
+ int decrement_in_flight_event_count() {
+ DCHECK_GT(in_flight_event_count_, 0);
+ return --in_flight_event_count_;
+ }
+
+ void set_renderer_initialized(bool renderer_initialized) {
+ renderer_initialized_ = renderer_initialized;
+ }
+
+ bool renderer_initialized() const { return renderer_initialized_; }
// The View associated with the RenderViewHost. The lifetime of this object
// is associated with the lifetime of the Render process. If the Renderer
@@ -563,13 +577,8 @@ class CONTENT_EXPORT RenderWidgetHostImpl
// 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.
- int64 hung_renderer_delay_ms_;
+ base::TimeDelta hung_renderer_delay_;
private:
friend class MockRenderWidgetHost;
@@ -577,7 +586,7 @@ class CONTENT_EXPORT RenderWidgetHostImpl
// Tell this object to destroy itself.
void Destroy();
- // Called by |hang_timeout_monitor_| on delayed response from the renderer.
+ // Called by |hang_monitor_timeout_| on delayed response from the renderer.
void RendererIsUnresponsive();
// Called if we know the renderer is responsive. When we currently think the
@@ -594,7 +603,6 @@ class CONTENT_EXPORT RenderWidgetHostImpl
void OnSetTooltipText(const base::string16& tooltip_text,
blink::WebTextDirection text_direction_hint);
bool OnSwapCompositorFrame(const IPC::Message& message);
- void OnFlingingStopped();
void OnUpdateRect(const ViewHostMsg_UpdateRect_Params& params);
void OnQueueSyntheticGesture(const SyntheticGesturePacket& gesture_packet);
virtual void OnFocus();
@@ -605,11 +613,9 @@ class CONTENT_EXPORT RenderWidgetHostImpl
bool can_compose_inline,
int flags);
-#if defined(OS_MACOSX) || defined(USE_AURA) || defined(OS_ANDROID)
void OnImeCompositionRangeChanged(
const gfx::Range& range,
const std::vector<gfx::Rect>& character_bounds);
-#endif
void OnImeCancelComposition();
void OnLockMouse(bool user_gesture,
bool last_unlocked_by_target,
@@ -650,6 +656,7 @@ class CONTENT_EXPORT RenderWidgetHostImpl
void OnHasTouchEventHandlers(bool has_handlers) override;
void DidFlush() override;
void DidOverscroll(const DidOverscrollParams& params) override;
+ void DidStopFlinging() override;
// InputAckHandler
void OnKeyboardEventAck(const NativeWebKeyboardEvent& event,
@@ -668,8 +675,6 @@ class CONTENT_EXPORT RenderWidgetHostImpl
// which may get in recursive loops).
void DelayedAutoResized();
- void WindowOldSnapshotReachedScreen(int snapshot_id);
-
void WindowSnapshotReachedScreen(int snapshot_id);
void OnSnapshotDataReceived(int snapshot_id,
@@ -680,6 +685,11 @@ class CONTENT_EXPORT RenderWidgetHostImpl
int snapshot_id,
scoped_refptr<base::RefCountedBytes> png_data);
+ // 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_;
+
// Our delegate, which wants to know mainly about keyboard events.
// It will remain non-NULL until DetachDelegate() is called.
RenderWidgetHostDelegate* delegate_;
@@ -702,51 +712,30 @@ class CONTENT_EXPORT RenderWidgetHostImpl
// most recent call to process_->WidgetRestored() / WidgetHidden().
bool is_hidden_;
- // Indicates whether a page is fullscreen or not.
- bool is_fullscreen_;
-
// Set if we are waiting for a repaint ack for the view.
bool repaint_ack_pending_;
// True when waiting for RESIZE_ACK.
bool resize_ack_pending_;
- // Cached copy of the screen info so that it doesn't need to be updated every
- // time the window is resized.
- scoped_ptr<blink::WebScreenInfo> screen_info_;
-
- // Set if screen_info_ may have changed and should be recomputed and force a
- // resize message.
- bool screen_info_out_of_date_;
-
// The current size of the RenderWidget.
gfx::Size current_size_;
- // The size of the view's backing surface in non-DPI-adjusted pixels.
- gfx::Size physical_backing_size_;
-
- // 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
- // DPI-adjusted pixels.
- gfx::Size visible_viewport_size_;
-
- // The size we last sent as requested size to the renderer. |current_size_|
- // is only updated once the resize message has been ack'd. This on the other
- // hand is updated when the resize message is sent. This is very similar to
- // |resize_ack_pending_|, but the latter is not set if the new size has width
- // or height zero, which is why we need this too.
- gfx::Size last_requested_size_;
+ // Resize information that was previously sent to the renderer.
+ scoped_ptr<ViewMsg_Resize_Params> old_resize_params_;
// The next auto resize to send.
gfx::Size new_auto_size_;
// True if the render widget host should track the render widget's size as
// opposed to visa versa.
- bool should_auto_resize_;
+ bool auto_resize_enabled_;
+
+ // The minimum size for the render widget if auto-resize is enabled.
+ gfx::Size min_size_for_auto_resize_;
+
+ // The maximum size for the render widget if auto-resize is enabled.
+ gfx::Size max_size_for_auto_resize_;
bool waiting_for_screen_rects_ack_;
gfx::Rect last_view_screen_rect_;
@@ -767,17 +756,10 @@ class CONTENT_EXPORT RenderWidgetHostImpl
// This is true if the renderer is currently unresponsive.
bool is_unresponsive_;
- // The following value indicates a time in the future when we would consider
- // the renderer hung if it does not generate an appropriate response message.
- base::Time time_when_considered_hung_;
-
// This value denotes the number of input events yet to be acknowledged
// by the renderer.
int in_flight_event_count_;
- // This timer runs to check if time_when_considered_hung_ has past.
- base::OneShotTimer<RenderWidgetHostImpl> hung_renderer_timer_;
-
// Flag to detect recursive calls to GetBackingStore().
bool in_get_backing_store_;
@@ -836,14 +818,22 @@ class CONTENT_EXPORT RenderWidgetHostImpl
std::list<HWND> dummy_windows_for_activation_;
#endif
- int64 last_input_number_;
+ RenderWidgetHostLatencyTracker latency_tracker_;
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_;
+ // Indicates whether a RenderFramehost has ownership, in which case this
+ // object does not self destroy.
+ bool owned_by_render_frame_host_;
+
+ // Indicates whether this RenderWidgetHost thinks is focused. This is trying
+ // to match what the renderer process knows. It is different from
+ // RenderWidgetHostView::HasFocus in that in that the focus request may fail,
+ // causing HasFocus to return false when is_focused_ is true.
+ bool is_focused_;
base::WeakPtrFactory<RenderWidgetHostImpl> weak_factory_;
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 830ab01ed0c..e559b6d9878 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_unittest.cc
+++ b/chromium/content/browser/renderer_host/render_widget_host_unittest.cc
@@ -70,7 +70,6 @@ class MockInputRouter : public InputRouter {
~MockInputRouter() override {}
// InputRouter
- void Flush() override { flush_called_ = true; }
bool SendInput(scoped_ptr<IPC::Message> message) override {
send_event_called_ = true;
return true;
@@ -100,8 +99,8 @@ class MockInputRouter : public InputRouter {
NOTREACHED();
return NULL;
}
- bool ShouldForwardTouchEvent() const override { return true; }
void OnViewUpdated(int view_flags) override {}
+ void RequestNotificationWhenFlushed() override {}
bool HasPendingEvents() const override { return false; }
// IPC::Listener
@@ -110,7 +109,6 @@ class MockInputRouter : public InputRouter {
return false;
}
- bool flush_called_;
bool send_event_called_;
bool sent_mouse_event_;
bool sent_wheel_event_;
@@ -139,9 +137,11 @@ class MockRenderWidgetHost : public RenderWidgetHostImpl {
}
// Allow poking at a few private members.
+ using RenderWidgetHostImpl::GetResizeParams;
using RenderWidgetHostImpl::OnUpdateRect;
using RenderWidgetHostImpl::RendererExited;
- using RenderWidgetHostImpl::last_requested_size_;
+ using RenderWidgetHostImpl::SetInitialRenderSizeParams;
+ using RenderWidgetHostImpl::old_resize_params_;
using RenderWidgetHostImpl::is_hidden_;
using RenderWidgetHostImpl::resize_ack_pending_;
using RenderWidgetHostImpl::input_router_;
@@ -157,10 +157,6 @@ class MockRenderWidgetHost : public RenderWidgetHostImpl {
return unresponsive_timer_fired_;
}
- void set_hung_renderer_delay_ms(int64 delay_ms) {
- hung_renderer_delay_ms_ = delay_ms;
- }
-
void DisableGestureDebounce() {
input_router_.reset(new InputRouterImpl(
process_, this, this, routing_id_, InputRouterImpl::Config()));
@@ -196,36 +192,16 @@ namespace {
class RenderWidgetHostProcess : public MockRenderProcessHost {
public:
explicit RenderWidgetHostProcess(BrowserContext* browser_context)
- : MockRenderProcessHost(browser_context),
- update_msg_reply_flags_(0) {
+ : MockRenderProcessHost(browser_context) {
}
~RenderWidgetHostProcess() override {}
- void set_update_msg_reply_flags(int flags) {
- update_msg_reply_flags_ = flags;
- }
-
- // Fills the given update parameters with resonable default values.
- void InitUpdateRectParams(ViewHostMsg_UpdateRect_Params* params);
-
bool HasConnection() const override { return true; }
protected:
- // 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_;
-
DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostProcess);
};
-void RenderWidgetHostProcess::InitUpdateRectParams(
- ViewHostMsg_UpdateRect_Params* params) {
- const int w = 100, h = 100;
-
- params->view_size = gfx::Size(w, h);
- params->flags = update_msg_reply_flags_;
-}
-
// TestView --------------------------------------------------------------------
// This test view allows us to specify the size, and keep track of acked
@@ -269,6 +245,9 @@ class TestView : public TestRenderWidgetHostView {
void ClearMockPhysicalBackingSize() {
use_fake_physical_backing_size_ = false;
}
+ void SetScreenInfo(const blink::WebScreenInfo& screen_info) {
+ screen_info_ = screen_info;
+ }
// RenderWidgetHostView override.
gfx::Rect GetViewBounds() const override { return bounds_; }
@@ -294,6 +273,9 @@ class TestView : public TestRenderWidgetHostView {
return mock_physical_backing_size_;
return TestRenderWidgetHostView::GetPhysicalBackingSize();
}
+ void GetScreenInfo(blink::WebScreenInfo* screen_info) override {
+ *screen_info = screen_info_;
+ }
#if defined(USE_AURA)
~TestView() override {
// Simulate the mouse exit event dispatched when an aura window is
@@ -316,6 +298,7 @@ class TestView : public TestRenderWidgetHostView {
bool use_fake_physical_backing_size_;
gfx::Size mock_physical_backing_size_;
InputEventAckState ack_result_;
+ blink::WebScreenInfo screen_info_;
DISALLOW_COPY_AND_ASSIGN(TestView);
};
@@ -440,10 +423,13 @@ class RenderWidgetHostTest : public testing::Test {
host_.reset(
new MockRenderWidgetHost(delegate_.get(), process_, MSG_ROUTING_NONE));
view_.reset(new TestView(host_.get()));
+ ConfigureView(view_.get());
host_->SetView(view_.get());
+ SetInitialRenderSizeParams();
host_->Init();
host_->DisableGestureDebounce();
}
+
void TearDown() override {
view_.reset();
host_.reset();
@@ -453,6 +439,7 @@ class RenderWidgetHostTest : public testing::Test {
#if defined(USE_AURA)
aura::Env::DeleteInstance();
+ gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, nullptr);
screen_.reset();
#endif
#if defined(USE_AURA) || (defined(OS_MACOSX) && !defined(OS_IOS))
@@ -464,6 +451,15 @@ class RenderWidgetHostTest : public testing::Test {
base::MessageLoop::current()->RunUntilIdle();
}
+ void SetInitialRenderSizeParams() {
+ ViewMsg_Resize_Params render_size_params;
+ host_->GetResizeParams(&render_size_params);
+ host_->SetInitialRenderSizeParams(render_size_params);
+ }
+
+ virtual void ConfigureView(TestView* view) {
+ }
+
int64 GetLatencyComponentId() {
return host_->GetLatencyComponentId();
}
@@ -577,7 +573,7 @@ class RenderWidgetHostTest : public testing::Test {
PickleIterator iter(message);
const char* data;
int data_length;
- if (!message.ReadData(&iter, &data, &data_length))
+ if (!iter.ReadData(&data, &data_length))
return NULL;
return reinterpret_cast<const WebInputEvent*>(data);
}
@@ -615,14 +611,20 @@ class RenderWidgetHostWithSourceTest
// -----------------------------------------------------------------------------
TEST_F(RenderWidgetHostTest, Resize) {
- // The initial bounds is the empty rect, and the screen info hasn't been sent
- // yet, so setting it to the same thing shouldn't send the resize message.
+ // The initial bounds is the empty rect, so setting it to the same thing
+ // shouldn't send the resize message.
view_->set_bounds(gfx::Rect());
host_->WasResized();
EXPECT_FALSE(host_->resize_ack_pending_);
EXPECT_FALSE(process_->sink().GetUniqueMessageMatching(ViewMsg_Resize::ID));
- // Setting the bounds to a "real" rect should send out the notification.
+ // No resize ack if the physical backing gets set, but the view bounds are
+ // zero.
+ view_->SetMockPhysicalBackingSize(gfx::Size(200, 200));
+ host_->WasResized();
+ EXPECT_FALSE(host_->resize_ack_pending_);
+
+ // Setting the view bounds to nonzero should send out the notification.
// but should not expect ack for empty physical backing size.
gfx::Rect original_size(0, 0, 100, 100);
process_->sink().ClearMessages();
@@ -630,17 +632,22 @@ TEST_F(RenderWidgetHostTest, Resize) {
view_->SetMockPhysicalBackingSize(gfx::Size());
host_->WasResized();
EXPECT_FALSE(host_->resize_ack_pending_);
- EXPECT_EQ(original_size.size(), host_->last_requested_size_);
+ EXPECT_EQ(original_size.size(), host_->old_resize_params_->new_size);
EXPECT_TRUE(process_->sink().GetUniqueMessageMatching(ViewMsg_Resize::ID));
- // Setting the bounds to a "real" rect should send out the notification.
- // but should not expect ack for only physical backing size change.
+ // Setting the bounds and physical backing size to nonzero should send out
+ // the notification and expect an ack.
process_->sink().ClearMessages();
view_->ClearMockPhysicalBackingSize();
host_->WasResized();
- EXPECT_FALSE(host_->resize_ack_pending_);
- EXPECT_EQ(original_size.size(), host_->last_requested_size_);
+ EXPECT_TRUE(host_->resize_ack_pending_);
+ EXPECT_EQ(original_size.size(), host_->old_resize_params_->new_size);
EXPECT_TRUE(process_->sink().GetUniqueMessageMatching(ViewMsg_Resize::ID));
+ ViewHostMsg_UpdateRect_Params params;
+ params.flags = ViewHostMsg_UpdateRect_Flags::IS_RESIZE_ACK;
+ params.view_size = original_size.size();
+ host_->OnUpdateRect(params);
+ EXPECT_FALSE(host_->resize_ack_pending_);
// Send out a update that's not a resize ack after setting resize ack pending
// flag. This should not clean the resize ack pending flag.
@@ -650,11 +657,11 @@ TEST_F(RenderWidgetHostTest, Resize) {
view_->set_bounds(second_size);
host_->WasResized();
EXPECT_TRUE(host_->resize_ack_pending_);
- ViewHostMsg_UpdateRect_Params params;
- process_->InitUpdateRectParams(&params);
+ params.flags = 0;
+ params.view_size = gfx::Size(100, 100);
host_->OnUpdateRect(params);
EXPECT_TRUE(host_->resize_ack_pending_);
- EXPECT_EQ(second_size.size(), host_->last_requested_size_);
+ EXPECT_EQ(second_size.size(), host_->old_resize_params_->new_size);
// Sending out a new notification should NOT send out a new IPC message since
// a resize ACK is pending.
@@ -663,7 +670,7 @@ TEST_F(RenderWidgetHostTest, Resize) {
view_->set_bounds(third_size);
host_->WasResized();
EXPECT_TRUE(host_->resize_ack_pending_);
- EXPECT_EQ(second_size.size(), host_->last_requested_size_);
+ EXPECT_EQ(second_size.size(), host_->old_resize_params_->new_size);
EXPECT_FALSE(process_->sink().GetUniqueMessageMatching(ViewMsg_Resize::ID));
// Send a update that's a resize ack, but for the original_size we sent. Since
@@ -674,16 +681,17 @@ TEST_F(RenderWidgetHostTest, Resize) {
params.view_size = original_size.size();
host_->OnUpdateRect(params);
EXPECT_TRUE(host_->resize_ack_pending_);
- EXPECT_EQ(third_size.size(), host_->last_requested_size_);
- ASSERT_TRUE(process_->sink().GetUniqueMessageMatching(ViewMsg_Resize::ID));
+ EXPECT_EQ(third_size.size(), host_->old_resize_params_->new_size);
+ EXPECT_TRUE(process_->sink().GetUniqueMessageMatching(ViewMsg_Resize::ID));
// Send the resize ack for the latest size.
process_->sink().ClearMessages();
+ params.flags = ViewHostMsg_UpdateRect_Flags::IS_RESIZE_ACK;
params.view_size = third_size.size();
host_->OnUpdateRect(params);
EXPECT_FALSE(host_->resize_ack_pending_);
- EXPECT_EQ(third_size.size(), host_->last_requested_size_);
- ASSERT_FALSE(process_->sink().GetFirstMessageMatching(ViewMsg_Resize::ID));
+ EXPECT_EQ(third_size.size(), host_->old_resize_params_->new_size);
+ EXPECT_FALSE(process_->sink().GetFirstMessageMatching(ViewMsg_Resize::ID));
// Now clearing the bounds should send out a notification but we shouldn't
// expect a resize ack (since the renderer won't ack empty sizes). The message
@@ -692,7 +700,7 @@ TEST_F(RenderWidgetHostTest, Resize) {
view_->set_bounds(gfx::Rect());
host_->WasResized();
EXPECT_FALSE(host_->resize_ack_pending_);
- EXPECT_EQ(gfx::Size(), host_->last_requested_size_);
+ EXPECT_EQ(gfx::Size(), host_->old_resize_params_->new_size);
EXPECT_TRUE(process_->sink().GetUniqueMessageMatching(ViewMsg_Resize::ID));
// Send a rect that has no area but has either width or height set.
@@ -700,22 +708,62 @@ TEST_F(RenderWidgetHostTest, Resize) {
view_->set_bounds(gfx::Rect(0, 0, 0, 30));
host_->WasResized();
EXPECT_FALSE(host_->resize_ack_pending_);
- EXPECT_EQ(gfx::Size(0, 30), host_->last_requested_size_);
+ EXPECT_EQ(gfx::Size(0, 30), host_->old_resize_params_->new_size);
EXPECT_TRUE(process_->sink().GetUniqueMessageMatching(ViewMsg_Resize::ID));
// Set the same size again. It should not be sent again.
process_->sink().ClearMessages();
host_->WasResized();
EXPECT_FALSE(host_->resize_ack_pending_);
- EXPECT_EQ(gfx::Size(0, 30), host_->last_requested_size_);
+ EXPECT_EQ(gfx::Size(0, 30), host_->old_resize_params_->new_size);
EXPECT_FALSE(process_->sink().GetFirstMessageMatching(ViewMsg_Resize::ID));
// A different size should be sent again, however.
view_->set_bounds(gfx::Rect(0, 0, 0, 31));
host_->WasResized();
EXPECT_FALSE(host_->resize_ack_pending_);
- EXPECT_EQ(gfx::Size(0, 31), host_->last_requested_size_);
+ EXPECT_EQ(gfx::Size(0, 31), host_->old_resize_params_->new_size);
+ EXPECT_TRUE(process_->sink().GetUniqueMessageMatching(ViewMsg_Resize::ID));
+}
+
+// Test that a resize event is sent if WasResized() is called after a
+// WebScreenInfo change.
+TEST_F(RenderWidgetHostTest, ResizeScreenInfo) {
+ blink::WebScreenInfo screen_info;
+ screen_info.deviceScaleFactor = 1.f;
+ screen_info.rect = blink::WebRect(0, 0, 800, 600);
+ screen_info.availableRect = blink::WebRect(0, 0, 800, 600);
+ screen_info.orientationAngle = 0;
+ screen_info.orientationType = blink::WebScreenOrientationPortraitPrimary;
+
+ view_->SetScreenInfo(screen_info);
+ host_->WasResized();
+ EXPECT_FALSE(host_->resize_ack_pending_);
+ EXPECT_TRUE(process_->sink().GetUniqueMessageMatching(ViewMsg_Resize::ID));
+ process_->sink().ClearMessages();
+
+ screen_info.orientationAngle = 180;
+ screen_info.orientationType = blink::WebScreenOrientationLandscapePrimary;
+
+ view_->SetScreenInfo(screen_info);
+ host_->WasResized();
+ EXPECT_FALSE(host_->resize_ack_pending_);
EXPECT_TRUE(process_->sink().GetUniqueMessageMatching(ViewMsg_Resize::ID));
+ process_->sink().ClearMessages();
+
+ screen_info.deviceScaleFactor = 2.f;
+
+ view_->SetScreenInfo(screen_info);
+ host_->WasResized();
+ EXPECT_FALSE(host_->resize_ack_pending_);
+ EXPECT_TRUE(process_->sink().GetUniqueMessageMatching(ViewMsg_Resize::ID));
+ process_->sink().ClearMessages();
+
+ // No screen change.
+ view_->SetScreenInfo(screen_info);
+ host_->WasResized();
+ EXPECT_FALSE(host_->resize_ack_pending_);
+ EXPECT_FALSE(process_->sink().GetUniqueMessageMatching(ViewMsg_Resize::ID));
}
// Test for crbug.com/25097. If a renderer crashes between a resize and the
@@ -729,7 +777,7 @@ TEST_F(RenderWidgetHostTest, ResizeThenCrash) {
view_->set_bounds(original_size);
host_->WasResized();
EXPECT_TRUE(host_->resize_ack_pending_);
- EXPECT_EQ(original_size.size(), host_->last_requested_size_);
+ EXPECT_EQ(original_size.size(), host_->old_resize_params_->new_size);
EXPECT_TRUE(process_->sink().GetUniqueMessageMatching(ViewMsg_Resize::ID));
// Simulate a renderer crash before the update message. Ensure all the
@@ -738,7 +786,7 @@ TEST_F(RenderWidgetHostTest, ResizeThenCrash) {
host_->SetView(NULL);
host_->RendererExited(base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
EXPECT_FALSE(host_->resize_ack_pending_);
- EXPECT_EQ(gfx::Size(), host_->last_requested_size_);
+ EXPECT_EQ(gfx::Size(), host_->old_resize_params_->new_size);
// Reset the view so we can exit the test cleanly.
host_->SetView(view_.get());
@@ -766,9 +814,9 @@ TEST_F(RenderWidgetHostTest, Background) {
process_->sink().GetUniqueMessageMatching(
ViewMsg_SetBackgroundOpaque::ID);
ASSERT_TRUE(set_background);
- Tuple1<bool> sent_background;
+ Tuple<bool> sent_background;
ViewMsg_SetBackgroundOpaque::Read(set_background, &sent_background);
- EXPECT_FALSE(sent_background.a);
+ EXPECT_FALSE(get<0>(sent_background));
#if defined(USE_AURA)
// See the comment above |InitAsChild(NULL)|.
@@ -791,7 +839,7 @@ TEST_F(RenderWidgetHostTest, HiddenPaint) {
// Send it an update as from the renderer.
process_->sink().ClearMessages();
ViewHostMsg_UpdateRect_Params params;
- process_->InitUpdateRectParams(&params);
+ params.view_size = gfx::Size(100, 100);
host_->OnUpdateRect(params);
// Now unhide.
@@ -803,9 +851,9 @@ TEST_F(RenderWidgetHostTest, HiddenPaint) {
const IPC::Message* restored = process_->sink().GetUniqueMessageMatching(
ViewMsg_WasShown::ID);
ASSERT_TRUE(restored);
- Tuple2<bool, ui::LatencyInfo> needs_repaint;
+ Tuple<bool, ui::LatencyInfo> needs_repaint;
ViewMsg_WasShown::Read(restored, &needs_repaint);
- EXPECT_TRUE(needs_repaint.a);
+ EXPECT_TRUE(get<0>(needs_repaint));
}
TEST_F(RenderWidgetHostTest, IgnoreKeyEventsHandledByRenderer) {
@@ -977,13 +1025,51 @@ TEST_F(RenderWidgetHostTest, ShorterDelayHangMonitorTimeout) {
EXPECT_TRUE(host_->unresponsive_timer_fired());
}
+// Test that the hang monitor timer is effectively disabled when the widget is
+// hidden.
+TEST_F(RenderWidgetHostTest, HangMonitorTimeoutDisabledForInputWhenHidden) {
+ host_->set_hung_renderer_delay(base::TimeDelta::FromMicroseconds(1));
+ SimulateMouseEvent(WebInputEvent::MouseMove, 10, 10, 0, false);
+
+ // Hiding the widget should deactivate the timeout.
+ host_->WasHidden();
+
+ // The timeout should not fire.
+ EXPECT_FALSE(host_->unresponsive_timer_fired());
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::MessageLoop::QuitClosure(),
+ TimeDelta::FromMicroseconds(2));
+ base::MessageLoop::current()->Run();
+ EXPECT_FALSE(host_->unresponsive_timer_fired());
+
+ // The timeout should never reactivate while hidden.
+ SimulateMouseEvent(WebInputEvent::MouseMove, 10, 10, 0, false);
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::MessageLoop::QuitClosure(),
+ TimeDelta::FromMicroseconds(2));
+ base::MessageLoop::current()->Run();
+ EXPECT_FALSE(host_->unresponsive_timer_fired());
+
+ // Showing the widget should restore the timeout, as the events have
+ // not yet been ack'ed.
+ host_->WasShown(ui::LatencyInfo());
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::MessageLoop::QuitClosure(),
+ TimeDelta::FromMicroseconds(2));
+ base::MessageLoop::current()->Run();
+ EXPECT_TRUE(host_->unresponsive_timer_fired());
+}
+
// Test that the hang monitor catches two input events but only one ack.
// This can happen if the second input event causes the renderer to hang.
// This test will catch a regression of crbug.com/111185.
TEST_F(RenderWidgetHostTest, MultipleInputEvents) {
// Configure the host to wait 10ms before considering
// the renderer hung.
- host_->set_hung_renderer_delay_ms(10);
+ host_->set_hung_renderer_delay(base::TimeDelta::FromMicroseconds(10));
// Send two events but only one ack.
SimulateKeyboardEvent(WebInputEvent::RawKeyDown);
@@ -995,7 +1081,7 @@ TEST_F(RenderWidgetHostTest, MultipleInputEvents) {
base::MessageLoop::current()->PostDelayedTask(
FROM_HERE,
base::MessageLoop::QuitClosure(),
- TimeDelta::FromMilliseconds(40));
+ TimeDelta::FromMicroseconds(20));
base::MessageLoop::current()->Run();
EXPECT_TRUE(host_->unresponsive_timer_fired());
}
@@ -1007,7 +1093,7 @@ std::string GetInputMessageTypes(RenderWidgetHostProcess* process) {
EXPECT_EQ(InputMsg_HandleInputEvent::ID, message->type());
InputMsg_HandleInputEvent::Param params;
EXPECT_TRUE(InputMsg_HandleInputEvent::Read(message, &params));
- const WebInputEvent* event = params.a;
+ const WebInputEvent* event = get<0>(params);
if (i != 0)
result += " ";
result += WebInputEventTraits::GetName(event->type);
@@ -1020,7 +1106,8 @@ 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_->SetTouchEventEmulationEnabled(true);
+ host_->SetTouchEventEmulationEnabled(
+ true, ui::GestureProviderConfigType::GENERIC_MOBILE);
process_->sink().ClearMessages();
view_->set_bounds(gfx::Rect(0, 0, 400, 200));
view_->Show();
@@ -1119,7 +1206,8 @@ TEST_F(RenderWidgetHostTest, TouchEmulator) {
EXPECT_EQ(0U, process_->sink().message_count());
// Turn off emulation during a pinch.
- host_->SetTouchEventEmulationEnabled(false);
+ host_->SetTouchEventEmulationEnabled(
+ false, ui::GestureProviderConfigType::GENERIC_MOBILE);
EXPECT_EQ(WebInputEvent::TouchCancel, host_->acked_touch_event_type());
EXPECT_EQ("GesturePinchEnd GestureScrollEnd",
GetInputMessageTypes(process_));
@@ -1134,7 +1222,8 @@ TEST_F(RenderWidgetHostTest, TouchEmulator) {
EXPECT_EQ(0U, process_->sink().message_count());
// Turn on emulation.
- host_->SetTouchEventEmulationEnabled(true);
+ host_->SetTouchEventEmulationEnabled(
+ true, ui::GestureProviderConfigType::GENERIC_MOBILE);
EXPECT_EQ(0U, process_->sink().message_count());
// Another touch.
@@ -1153,7 +1242,8 @@ TEST_F(RenderWidgetHostTest, TouchEmulator) {
INPUT_EVENT_ACK_STATE_CONSUMED);
// Turn off emulation during a scroll.
- host_->SetTouchEventEmulationEnabled(false);
+ host_->SetTouchEventEmulationEnabled(
+ false, ui::GestureProviderConfigType::GENERIC_MOBILE);
EXPECT_EQ(WebInputEvent::TouchCancel, host_->acked_touch_event_type());
EXPECT_EQ("GestureScrollEnd", GetInputMessageTypes(process_));
@@ -1329,7 +1419,7 @@ ui::LatencyInfo GetLatencyInfoFromInputEvent(RenderWidgetHostProcess* process) {
InputMsg_HandleInputEvent::Param params;
EXPECT_TRUE(InputMsg_HandleInputEvent::Read(message, &params));
process->sink().ClearMessages();
- return params.b;
+ return get<1>(params);
}
void CheckLatencyInfoComponentInMessage(RenderWidgetHostProcess* process,
@@ -1398,79 +1488,6 @@ 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()));
@@ -1494,4 +1511,39 @@ TEST_F(RenderWidgetHostTest, RendererExitedResetsIsHidden) {
ASSERT_FALSE(host_->input_router()->HasPendingEvents());
}
+TEST_F(RenderWidgetHostTest, ResizeParams) {
+ gfx::Rect bounds(0, 0, 100, 100);
+ gfx::Size physical_backing_size(40, 50);
+ view_->set_bounds(bounds);
+ view_->SetMockPhysicalBackingSize(physical_backing_size);
+
+ ViewMsg_Resize_Params resize_params;
+ host_->GetResizeParams(&resize_params);
+ EXPECT_EQ(bounds.size(), resize_params.new_size);
+ EXPECT_EQ(physical_backing_size, resize_params.physical_backing_size);
+}
+
+class RenderWidgetHostInitialSizeTest : public RenderWidgetHostTest {
+ public:
+ RenderWidgetHostInitialSizeTest()
+ : RenderWidgetHostTest(), initial_size_(200, 100) {}
+
+ void ConfigureView(TestView* view) override {
+ view->set_bounds(gfx::Rect(initial_size_));
+ }
+
+ protected:
+ gfx::Size initial_size_;
+};
+
+TEST_F(RenderWidgetHostInitialSizeTest, InitialSize) {
+ // Having an initial size set means that the size information had been sent
+ // with the reqiest to new up the RenderView and so subsequent WasResized
+ // calls should not result in new IPC (unless the size has actually changed).
+ host_->WasResized();
+ EXPECT_FALSE(process_->sink().GetUniqueMessageMatching(ViewMsg_Resize::ID));
+ EXPECT_EQ(initial_size_, host_->old_resize_params_->new_size);
+ EXPECT_TRUE(host_->resize_ack_pending_);
+}
+
} // 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 e8a4f55e0c8..0576b33ca82 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
@@ -17,16 +17,21 @@
#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"
#include "cc/layers/delegated_renderer_layer.h"
#include "cc/layers/layer.h"
+#include "cc/layers/surface_layer.h"
#include "cc/output/compositor_frame.h"
#include "cc/output/compositor_frame_ack.h"
#include "cc/output/copy_output_request.h"
#include "cc/output/copy_output_result.h"
+#include "cc/output/latency_info_swap_promise.h"
#include "cc/output/viewport_selection_bound.h"
#include "cc/resources/single_release_callback.h"
+#include "cc/surfaces/surface.h"
+#include "cc/surfaces/surface_factory.h"
+#include "cc/surfaces/surface_id_allocator.h"
+#include "cc/surfaces/surface_manager.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"
@@ -34,8 +39,9 @@
#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"
+#include "content/browser/android/overscroll_controller_android.h"
+#include "content/browser/devtools/render_frame_devtools_agent_host.h"
+#include "content/browser/gpu/browser_gpu_channel_host_factory.h"
#include "content/browser/gpu/compositor_util.h"
#include "content/browser/gpu/gpu_data_manager_impl.h"
#include "content/browser/gpu/gpu_process_host_ui_shim.h"
@@ -43,53 +49,69 @@
#include "content/browser/media/media_web_contents_observer.h"
#include "content/browser/renderer_host/compositor_impl_android.h"
#include "content/browser/renderer_host/dip_util.h"
-#include "content/browser/renderer_host/image_transport_factory_android.h"
+#include "content/browser/renderer_host/frame_metadata_util.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"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/common/gpu/client/gl_helper.h"
+#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
#include "content/common/gpu/gpu_messages.h"
+#include "content/common/gpu/gpu_process_launch_causes.h"
#include "content/common/input/did_overscroll_params.h"
#include "content/common/input_messages.h"
#include "content/common/view_messages.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host_iterator.h"
#include "content/public/common/content_switches.h"
+#include "gpu/command_buffer/client/gles2_implementation.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/config/gpu_driver_bug_workaround_type.h"
#include "skia/ext/image_operations.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "third_party/khronos/GLES2/gl2ext.h"
#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/android/window_android.h"
+#include "ui/android/window_android_compositor.h"
+#include "ui/events/blink/blink_event_util.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/geometry/dip_util.h"
+#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/screen.h"
-#include "ui/gfx/size_conversions.h"
+#include "ui/touch_selection/touch_selection_controller.h"
namespace content {
namespace {
-const int kUndefinedOutputSurfaceId = -1;
+void SatisfyCallback(cc::SurfaceManager* manager,
+ cc::SurfaceSequence sequence) {
+ std::vector<uint32_t> sequences;
+ sequences.push_back(sequence.sequence);
+ manager->DidSatisfySequences(sequence.id_namespace, &sequences);
+}
-// Used to accomodate finite precision when comparing scaled viewport and
-// content widths. While this value may seem large, width=device-width on an N7
-// V1 saw errors of ~0.065 between computed window and content widths.
-const float kMobileViewportWidthEpsilon = 0.15f;
+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);
+}
-// Used for conditional creation of EdgeEffect types for overscroll.
-const int kKitKatMR2SDKVersion = 19;
+const int kUndefinedOutputSurfaceId = -1;
static const char kAsyncReadBackString[] = "Compositing.CopyFromSurfaceTime";
@@ -98,8 +120,125 @@ void SendImeEventAck(RenderWidgetHostImpl* host) {
host->Send(new ViewMsg_ImeEventAck(host->GetRoutingID()));
}
+class GLHelperHolder
+ : public blink::WebGraphicsContext3D::WebGraphicsContextLostCallback {
+ public:
+ static GLHelperHolder* Create();
+ ~GLHelperHolder() override;
+
+ void Initialize();
+
+ // WebGraphicsContextLostCallback implementation.
+ void onContextLost() override;
+
+ GLHelper* GetGLHelper() { return gl_helper_.get(); }
+ bool IsLost() { return !context_.get() || context_->isContextLost(); }
+
+ private:
+ GLHelperHolder();
+ static scoped_ptr<WebGraphicsContext3DCommandBufferImpl> CreateContext3D();
+
+ scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context_;
+ scoped_ptr<GLHelper> gl_helper_;
+
+ DISALLOW_COPY_AND_ASSIGN(GLHelperHolder);
+};
+
+GLHelperHolder* GLHelperHolder::Create() {
+ GLHelperHolder* holder = new GLHelperHolder;
+ holder->Initialize();
+
+ return holder;
+}
+
+GLHelperHolder::GLHelperHolder() {
+}
+
+GLHelperHolder::~GLHelperHolder() {
+}
+
+void GLHelperHolder::Initialize() {
+ context_ = CreateContext3D();
+ if (context_) {
+ context_->setContextLostCallback(this);
+ gl_helper_.reset(new GLHelper(context_->GetImplementation(),
+ context_->GetContextSupport()));
+ }
+}
+
+void GLHelperHolder::onContextLost() {
+ // Need to post a task because the command buffer client cannot be deleted
+ // from within this callback.
+ LOG(ERROR) << "Context lost.";
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&RenderWidgetHostViewAndroid::OnContextLost));
+}
+
+scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
+GLHelperHolder::CreateContext3D() {
+ BrowserGpuChannelHostFactory* factory =
+ BrowserGpuChannelHostFactory::instance();
+ scoped_refptr<GpuChannelHost> gpu_channel_host(factory->GetGpuChannel());
+ // GLHelper can only be used in asynchronous APIs for postprocessing after
+ // Browser Compositor operations (i.e. readback).
+ if (!gpu_channel_host.get()) {
+ // The Browser Compositor is in charge of reestablishing the channel.
+ return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>();
+ }
+
+ blink::WebGraphicsContext3D::Attributes attrs;
+ attrs.shareResources = true;
+ GURL url("chrome://gpu/RenderWidgetHostViewAndroid");
+ static const size_t kBytesPerPixel = 4;
+ gfx::DeviceDisplayInfo display_info;
+ size_t full_screen_texture_size_in_bytes = display_info.GetDisplayHeight() *
+ display_info.GetDisplayWidth() *
+ kBytesPerPixel;
+ WebGraphicsContext3DCommandBufferImpl::SharedMemoryLimits limits;
+ limits.command_buffer_size = 64 * 1024;
+ limits.start_transfer_buffer_size = 64 * 1024;
+ limits.min_transfer_buffer_size = 64 * 1024;
+ limits.max_transfer_buffer_size = std::min(
+ 3 * full_screen_texture_size_in_bytes, kDefaultMaxTransferBufferSize);
+ limits.mapped_memory_reclaim_limit =
+ WebGraphicsContext3DCommandBufferImpl::kNoLimit;
+ bool lose_context_when_out_of_memory = false;
+ scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context(
+ new WebGraphicsContext3DCommandBufferImpl(
+ 0, // offscreen
+ url, gpu_channel_host.get(), attrs, lose_context_when_out_of_memory,
+ limits, nullptr));
+ if (context->InitializeOnCurrentThread()) {
+ context->traceBeginCHROMIUM(
+ "gpu_toplevel",
+ base::StringPrintf("CmdBufferImageTransportFactory-%p",
+ context.get()).c_str());
+ } else {
+ context.reset();
+ }
+
+ return context.Pass();
+}
+
+// This can only be used for readback postprocessing. It may return null if the
+// channel was lost and not reestablished yet.
+GLHelper* GetPostReadbackGLHelper() {
+ static GLHelperHolder* g_readback_helper_holder = nullptr;
+
+ if (g_readback_helper_holder && g_readback_helper_holder->IsLost()) {
+ delete g_readback_helper_holder;
+ g_readback_helper_holder = nullptr;
+ }
+
+ if (!g_readback_helper_holder)
+ g_readback_helper_holder = GLHelperHolder::Create();
+
+ return g_readback_helper_holder->GetGLHelper();
+}
+
void CopyFromCompositingSurfaceFinished(
- const base::Callback<void(bool, const SkBitmap&)>& callback,
+ ReadbackRequestCallback& callback,
scoped_ptr<cc::SingleReleaseCallback> release_callback,
scoped_ptr<SkBitmap> bitmap,
const base::TimeTicks& start_time,
@@ -110,151 +249,84 @@ void CopyFromCompositingSurfaceFinished(
bitmap_pixels_lock.reset();
uint32 sync_point = 0;
if (result) {
- GLHelper* gl_helper =
- ImageTransportFactoryAndroid::GetInstance()->GetGLHelper();
- sync_point = gl_helper->InsertSyncPoint();
+ GLHelper* gl_helper = GetPostReadbackGLHelper();
+ if (gl_helper)
+ 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);
-}
-
-ui::LatencyInfo CreateLatencyInfo(const blink::WebInputEvent& event) {
- ui::LatencyInfo latency_info;
- // The latency number should only be added if the timestamp is valid.
- if (event.timeStampSeconds) {
- const int64 time_micros = static_cast<int64>(
- event.timeStampSeconds * base::Time::kMicrosecondsPerSecond);
- latency_info.AddLatencyNumberWithTimestamp(
- ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
- 0,
- 0,
- base::TimeTicks() + base::TimeDelta::FromMicroseconds(time_micros),
- 1);
- }
- return latency_info;
-}
-
-OverscrollGlow::DisplayParameters CreateOverscrollDisplayParameters(
- const cc::CompositorFrameMetadata& frame_metadata) {
- const float scale_factor =
- frame_metadata.page_scale_factor * frame_metadata.device_scale_factor;
-
- // Compute the size and offsets for each edge, where each effect is sized to
- // 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.scrollable_viewport_size, scale_factor);
- params.edge_offsets[OverscrollGlow::EDGE_TOP] =
- -frame_metadata.root_scroll_offset.y() * scale_factor;
- params.edge_offsets[OverscrollGlow::EDGE_LEFT] =
- -frame_metadata.root_scroll_offset.x() * scale_factor;
- params.edge_offsets[OverscrollGlow::EDGE_BOTTOM] =
- (frame_metadata.root_layer_size.height() -
- frame_metadata.root_scroll_offset.y() -
- 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.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())));
+ ReadbackResponse response = result ? READBACK_SUCCESS : READBACK_FAILED;
+ callback.Run(*bitmap, response);
}
-scoped_ptr<TouchSelectionController> CreateSelectionController(
- TouchSelectionControllerClient* client,
+scoped_ptr<ui::TouchSelectionController> CreateSelectionController(
+ ui::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(
+ bool show_on_tap_for_empty_editable = false;
+ return make_scoped_ptr(new ui::TouchSelectionController(
client,
base::TimeDelta::FromMilliseconds(tap_timeout_ms),
- touch_slop_pixels / content_view_core->GetDpiScale()));
+ touch_slop_pixels / content_view_core->GetDpiScale(),
+ show_on_tap_for_empty_editable));
+}
+
+scoped_ptr<OverscrollControllerAndroid> CreateOverscrollController(
+ ContentViewCoreImpl* content_view_core) {
+ return make_scoped_ptr(new OverscrollControllerAndroid(content_view_core));
}
ui::GestureProvider::Config CreateGestureProviderConfig() {
- ui::GestureProvider::Config config = ui::DefaultGestureProviderConfig();
+ ui::GestureProvider::Config config = ui::GetGestureProviderConfig(
+ ui::GestureProviderConfigType::CURRENT_PLATFORM);
config.disable_click_delay =
base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableClickDelay);
return config;
}
-bool HasFixedPageScale(const cc::CompositorFrameMetadata& frame_metadata) {
- return frame_metadata.min_page_scale_factor ==
- frame_metadata.max_page_scale_factor;
+ui::SelectionBound::Type ConvertSelectionBoundType(
+ cc::SelectionBoundType type) {
+ switch (type) {
+ case cc::SELECTION_BOUND_LEFT:
+ return ui::SelectionBound::LEFT;
+ case cc::SELECTION_BOUND_RIGHT:
+ return ui::SelectionBound::RIGHT;
+ case cc::SELECTION_BOUND_CENTER:
+ return ui::SelectionBound::CENTER;
+ case cc::SELECTION_BOUND_EMPTY:
+ return ui::SelectionBound::EMPTY;
+ }
+ NOTREACHED() << "Unknown selection bound type";
+ return ui::SelectionBound::EMPTY;
}
-bool HasMobileViewport(const cc::CompositorFrameMetadata& frame_metadata) {
- float window_width_dip =
- 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;
+ui::SelectionBound ConvertSelectionBound(
+ const cc::ViewportSelectionBound& bound) {
+ ui::SelectionBound ui_bound;
+ ui_bound.set_type(ConvertSelectionBoundType(bound.type));
+ ui_bound.set_visible(bound.visible);
+ if (ui_bound.type() != ui::SelectionBound::EMPTY)
+ ui_bound.SetEdge(bound.edge_top, bound.edge_bottom);
+ return ui_bound;
}
-} // 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) {
-}
+gfx::RectF GetSelectionRect(const ui::TouchSelectionController& controller) {
+ gfx::RectF rect = controller.GetRectBetweenBounds();
+ if (rect.IsEmpty())
+ return rect;
-ReadbackRequest::ReadbackRequest() {
+ rect.Union(controller.GetStartHandleRect());
+ rect.Union(controller.GetEndHandleRect());
+ return rect;
}
-ReadbackRequest::~ReadbackRequest() {
-}
+} // anonymous namespace
RenderWidgetHostViewAndroid::LastFrameInfo::LastFrameInfo(
uint32 output_id,
@@ -263,43 +335,55 @@ RenderWidgetHostViewAndroid::LastFrameInfo::LastFrameInfo(
RenderWidgetHostViewAndroid::LastFrameInfo::~LastFrameInfo() {}
+void RenderWidgetHostViewAndroid::OnContextLost() {
+ scoped_ptr<RenderWidgetHostIterator> widgets(
+ RenderWidgetHostImpl::GetAllRenderWidgetHosts());
+ while (RenderWidgetHost* widget = widgets->GetNextHost()) {
+ if (widget->GetView()) {
+ static_cast<RenderWidgetHostViewAndroid*>(widget->GetView())
+ ->OnLostResources();
+ }
+ }
+}
+
RenderWidgetHostViewAndroid::RenderWidgetHostViewAndroid(
RenderWidgetHostImpl* widget_host,
ContentViewCoreImpl* content_view_core)
: host_(widget_host),
outstanding_vsync_requests_(0),
is_showing_(!widget_host->is_hidden()),
- content_view_core_(NULL),
+ content_view_core_(nullptr),
+ content_view_core_window_android_(nullptr),
ime_adapter_android_(this),
cached_background_color_(SK_ColorWHITE),
last_output_surface_id_(kUndefinedOutputSurfaceId),
- overscroll_effect_enabled_(
- !base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableOverscrollEdgeEffect)),
gesture_provider_(CreateGestureProviderConfig(), this),
- gesture_text_selector_(this),
+ stylus_text_selector_(this),
accelerated_surface_route_id_(0),
- using_synchronous_compositor_(SynchronousCompositorImpl::FromID(
- widget_host->GetProcess()->GetID(),
- widget_host->GetRoutingID()) != NULL),
+ using_browser_compositor_(CompositorImpl::IsInitialized()),
frame_evictor_(new DelegatedFrameEvictor(this)),
locks_on_frame_count_(0),
observing_root_window_(false),
weak_ptr_factory_(this) {
host_->SetView(this);
SetContentViewCore(content_view_core);
- ImageTransportFactoryAndroid::AddObserver(this);
}
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);
+ DCHECK(!surface_factory_);
+ DCHECK(surface_id_.is_null());
}
+void RenderWidgetHostViewAndroid::Blur() {
+ host_->SetInputMethodActive(false);
+ host_->Blur();
+ if (overscroll_controller_)
+ overscroll_controller_->Disable();
+}
bool RenderWidgetHostViewAndroid::OnMessageReceived(
const IPC::Message& message) {
@@ -308,12 +392,14 @@ bool RenderWidgetHostViewAndroid::OnMessageReceived(
IPC_MESSAGE_HANDLER(ViewHostMsg_StartContentIntent, OnStartContentIntent)
IPC_MESSAGE_HANDLER(ViewHostMsg_DidChangeBodyBackgroundColor,
OnDidChangeBodyBackgroundColor)
- IPC_MESSAGE_HANDLER(ViewHostMsg_SetNeedsBeginFrame,
- OnSetNeedsBeginFrame)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_SetNeedsBeginFrames,
+ OnSetNeedsBeginFrames)
IPC_MESSAGE_HANDLER(ViewHostMsg_TextInputStateChanged,
OnTextInputStateChanged)
IPC_MESSAGE_HANDLER(ViewHostMsg_SmartClipDataExtracted,
OnSmartClipDataExtracted)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_ShowUnhandledTapUIIfNeeded,
+ OnShowUnhandledTapUIIfNeeded)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
@@ -338,31 +424,6 @@ RenderWidgetHostViewAndroid::GetRenderWidgetHost() const {
return host_;
}
-void RenderWidgetHostViewAndroid::WasShown() {
- if (!host_ || !host_->is_hidden())
- return;
-
- host_->WasShown(ui::LatencyInfo());
-
- if (content_view_core_) {
- StartObservingRootWindow();
- RequestVSyncUpdate(BEGIN_FRAME);
- }
-}
-
-void RenderWidgetHostViewAndroid::WasHidden() {
- RunAckCallbacks();
-
- if (!host_ || host_->is_hidden())
- return;
-
- // Inform the renderer that we are being hidden so it can reduce its resource
- // utilization.
- host_->WasHidden();
-
- StopObservingRootWindow();
-}
-
void RenderWidgetHostViewAndroid::WasResized() {
host_->WasResized();
}
@@ -377,32 +438,15 @@ 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,
- SkColorType color_type,
+ SkColorType preferred_color_type,
gfx::Rect src_subrect,
- 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));
+ ReadbackRequestCallback& result_callback) {
+ if (!host_ || host_->is_hidden() || !IsSurfaceAvailableForCopy()) {
+ result_callback.Run(SkBitmap(), READBACK_SURFACE_UNAVAILABLE);
return;
}
-
gfx::Size bounds = layer_->bounds();
if (src_subrect.IsEmpty())
src_subrect = gfx::Rect(bounds);
@@ -414,16 +458,26 @@ void RenderWidgetHostViewAndroid::GetScaledContentBitmap(
DCHECK_GT(device_scale_factor, 0);
gfx::Size dst_size(
gfx::ToCeiledSize(gfx::ScaleSize(bounds, scale / device_scale_factor)));
- CopyFromCompositingSurface(
- 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_);
+ CopyFromCompositingSurface(src_subrect, dst_size, result_callback,
+ preferred_color_type);
+}
+
+scoped_refptr<cc::Layer> RenderWidgetHostViewAndroid::CreateDelegatedLayer()
+ const {
+ scoped_refptr<cc::Layer> delegated_layer;
+ if (!surface_id_.is_null()) {
+ cc::SurfaceManager* manager = CompositorImpl::GetSurfaceManager();
+ DCHECK(manager);
+ // manager must outlive compositors using it.
+ scoped_refptr<cc::SurfaceLayer> surface_layer = cc::SurfaceLayer::Create(
+ base::Bind(&SatisfyCallback, base::Unretained(manager)),
+ base::Bind(&RequireCallback, base::Unretained(manager)));
+ surface_layer->SetSurfaceId(surface_id_, 1.f, texture_size_in_layer_);
+ delegated_layer = surface_layer;
+ } else {
+ DCHECK(frame_provider_.get());
+ delegated_layer = cc::DelegatedRendererLayer::Create(frame_provider_);
+ }
delegated_layer->SetBounds(content_size_in_layer_);
delegated_layer->SetIsDrawable(true);
delegated_layer->SetContentsOpaque(true);
@@ -475,15 +529,8 @@ void RenderWidgetHostViewAndroid::MovePluginWindows(
void RenderWidgetHostViewAndroid::Focus() {
host_->Focus();
host_->SetInputMethodActive(true);
- if (overscroll_effect_)
- overscroll_effect_->Enable();
-}
-
-void RenderWidgetHostViewAndroid::Blur() {
- host_->SetInputMethodActive(false);
- host_->Blur();
- if (overscroll_effect_)
- overscroll_effect_->Disable();
+ if (overscroll_controller_)
+ overscroll_controller_->Enable();
}
bool RenderWidgetHostViewAndroid::HasFocus() const {
@@ -502,11 +549,7 @@ void RenderWidgetHostViewAndroid::Show() {
return;
is_showing_ = true;
- if (layer_.get())
- layer_->SetHideLayerAndSubtree(false);
-
- frame_evictor_->SetVisible(true);
- WasShown();
+ ShowInternal();
}
void RenderWidgetHostViewAndroid::Hide() {
@@ -514,14 +557,10 @@ void RenderWidgetHostViewAndroid::Hide() {
return;
is_showing_ = false;
- 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();
+ bool hide_frontbuffer = true;
+ bool stop_observing_root_window = true;
+ HideInternal(hide_frontbuffer, stop_observing_root_window);
}
bool RenderWidgetHostViewAndroid::IsShowing() {
@@ -576,6 +615,18 @@ void RenderWidgetHostViewAndroid::OnTextSurroundingSelectionResponse(
text_surrounding_selection_callback_.Reset();
}
+void RenderWidgetHostViewAndroid::OnShowUnhandledTapUIIfNeeded(int x_dip,
+ int y_dip) {
+ if (!content_view_core_)
+ return;
+ // Validate the coordinates are within the viewport.
+ gfx::Size viewport_size = content_view_core_->GetViewportSizeDip();
+ if (x_dip < 0 || x_dip > viewport_size.width() ||
+ y_dip < 0 || y_dip > viewport_size.height())
+ return;
+ content_view_core_->OnShowUnhandledTapUIIfNeeded(x_dip, y_dip);
+}
+
void RenderWidgetHostViewAndroid::ReleaseLocksOnSurface() {
if (!frame_evictor_->HasFrame()) {
DCHECK_EQ(locks_on_frame_count_, 0u);
@@ -584,7 +635,7 @@ void RenderWidgetHostViewAndroid::ReleaseLocksOnSurface() {
while (locks_on_frame_count_ > 0) {
UnlockCompositingSurface();
}
- RunAckCallbacks();
+ RunAckCallbacks(cc::SurfaceDrawStatus::DRAW_SKIPPED);
}
gfx::Rect RenderWidgetHostViewAndroid::GetViewBounds() const {
@@ -601,12 +652,21 @@ gfx::Size RenderWidgetHostViewAndroid::GetPhysicalBackingSize() const {
return content_view_core_->GetPhysicalBackingSize();
}
-float RenderWidgetHostViewAndroid::GetTopControlsLayoutHeight() const {
+bool RenderWidgetHostViewAndroid::DoTopControlsShrinkBlinkSize() const {
+ if (!content_view_core_)
+ return false;
+
+ // Whether or not Blink's viewport size should be shrunk by the height of the
+ // URL-bar.
+ return content_view_core_->DoTopControlsShrinkBlinkSize();
+}
+
+float RenderWidgetHostViewAndroid::GetTopControlsHeight() const {
if (!content_view_core_)
return 0.f;
- // The amount that the viewport size given to Blink is shrunk by the URL-bar.
- return content_view_core_->GetTopControlsLayoutHeightDip();
+ // The height of the top controls.
+ return content_view_core_->GetTopControlsHeightDip();
}
void RenderWidgetHostViewAndroid::UpdateCursor(const WebCursor& cursor) {
@@ -632,15 +692,6 @@ long RenderWidgetHostViewAndroid::GetNativeImeAdapter() {
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.
@@ -669,9 +720,8 @@ void RenderWidgetHostViewAndroid::OnDidChangeBodyBackgroundColor(
content_view_core_->OnBackgroundColorChanged(color);
}
-void RenderWidgetHostViewAndroid::OnSetNeedsBeginFrame(bool enabled) {
- DCHECK(!using_synchronous_compositor_);
- TRACE_EVENT1("cc", "RenderWidgetHostViewAndroid::OnSetNeedsBeginFrame",
+void RenderWidgetHostViewAndroid::OnSetNeedsBeginFrames(bool enabled) {
+ TRACE_EVENT1("cc", "RenderWidgetHostViewAndroid::OnSetNeedsBeginFrames",
"enabled", enabled);
if (enabled)
RequestVSyncUpdate(PERSISTENT_BEGIN_FRAME);
@@ -698,24 +748,28 @@ bool RenderWidgetHostViewAndroid::OnTouchEvent(
if (!host_)
return false;
+ // If a browser-based widget consumes the touch event, it's critical that
+ // touch event interception be disabled. This avoids issues with
+ // double-handling for embedder-detected gestures like side swipe.
if (selection_controller_ &&
- selection_controller_->WillHandleTouchEvent(event))
+ selection_controller_->WillHandleTouchEvent(event)) {
+ RequestDisallowInterceptTouchEvent();
return true;
+ }
- if (gesture_text_selector_.OnTouchEvent(event))
+ if (stylus_text_selector_.OnTouchEvent(event)) {
+ RequestDisallowInterceptTouchEvent();
return true;
+ }
- if (!gesture_provider_.OnTouchEvent(event))
+ ui::FilteredGestureProvider::TouchHandlingResult result =
+ gesture_provider_.OnTouchEvent(event);
+ if (!result.succeeded)
return false;
- 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);
- }
+ blink::WebTouchEvent web_event =
+ ui::CreateWebTouchEventFromMotionEvent(event, result.did_generate_scroll);
+ host_->ForwardTouchEventWithLatencyInfo(web_event, ui::LatencyInfo());
// 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
@@ -735,12 +789,24 @@ bool RenderWidgetHostViewAndroid::OnTouchHandleEvent(
void RenderWidgetHostViewAndroid::ResetGestureDetection() {
const ui::MotionEvent* current_down_event =
gesture_provider_.GetCurrentDownEvent();
- if (!current_down_event)
+ if (!current_down_event) {
+ // A hard reset ensures prevention of any timer-based events that might fire
+ // after a touch sequence has ended.
+ gesture_provider_.ResetDetection();
return;
+ }
scoped_ptr<ui::MotionEvent> cancel_event = current_down_event->Cancel();
- DCHECK(cancel_event);
- OnTouchEvent(*cancel_event);
+ if (gesture_provider_.OnTouchEvent(*cancel_event).succeeded) {
+ bool causes_scrolling = false;
+ host_->ForwardTouchEventWithLatencyInfo(
+ ui::CreateWebTouchEventFromMotionEvent(*cancel_event, causes_scrolling),
+ ui::LatencyInfo());
+ }
+}
+
+void RenderWidgetHostViewAndroid::OnDidNavigateMainFrameToNewPage() {
+ ResetGestureDetection();
}
void RenderWidgetHostViewAndroid::SetDoubleTapSupportEnabled(bool enabled) {
@@ -759,13 +825,11 @@ void RenderWidgetHostViewAndroid::ImeCancelComposition() {
void RenderWidgetHostViewAndroid::ImeCompositionRangeChanged(
const gfx::Range& range,
const std::vector<gfx::Rect>& character_bounds) {
- ime_adapter_android_.SetCharacterBounds(character_bounds);
+ // TODO(yukawa): Implement this.
}
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(
@@ -777,6 +841,13 @@ void RenderWidgetHostViewAndroid::Destroy() {
RemoveLayers();
SetContentViewCore(NULL);
+ if (!surface_id_.is_null()) {
+ DCHECK(surface_factory_.get());
+ surface_factory_->Destroy(surface_id_);
+ surface_id_ = cc::SurfaceId();
+ }
+ surface_factory_.reset();
+
// The RenderWidgetHost's destruction led here, so don't call it.
host_ = NULL;
@@ -793,9 +864,6 @@ void RenderWidgetHostViewAndroid::SelectionChanged(const base::string16& text,
const gfx::Range& range) {
RenderWidgetHostViewBase::SelectionChanged(text, offset, range);
- if (selection_controller_)
- selection_controller_->OnSelectionEmpty(text.empty());
-
if (!content_view_core_)
return;
if (range.is_empty()) {
@@ -832,30 +900,29 @@ void RenderWidgetHostViewAndroid::SetBackgroundColor(SkColor color) {
void RenderWidgetHostViewAndroid::CopyFromCompositingSurface(
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
- CopyFromCompositingSurfaceCallback& callback,
- const SkColorType color_type) {
+ ReadbackRequestCallback& callback,
+ const SkColorType preferred_color_type) {
TRACE_EVENT0("cc", "RenderWidgetHostViewAndroid::CopyFromCompositingSurface");
- if ((!host_ || host_->is_hidden()) ||
- !IsReadbackConfigSupported(color_type)) {
- callback.Run(false, SkBitmap());
+ if (!host_ || host_->is_hidden()) {
+ callback.Run(SkBitmap(), READBACK_SURFACE_UNAVAILABLE);
return;
}
base::TimeTicks start_time = base::TimeTicks::Now();
- if (!using_synchronous_compositor_ && !IsSurfaceAvailableForCopy()) {
- callback.Run(false, SkBitmap());
+ if (using_browser_compositor_ && !IsSurfaceAvailableForCopy()) {
+ callback.Run(SkBitmap(), READBACK_SURFACE_UNAVAILABLE);
return;
}
const gfx::Display& display =
gfx::Screen::GetNativeScreen()->GetPrimaryDisplay();
float device_scale_factor = display.device_scale_factor();
gfx::Size dst_size_in_pixel =
- ConvertRectToPixel(device_scale_factor, gfx::Rect(dst_size)).size();
+ gfx::ConvertRectToPixel(device_scale_factor, gfx::Rect(dst_size)).size();
gfx::Rect src_subrect_in_pixel =
- ConvertRectToPixel(device_scale_factor, src_subrect);
+ gfx::ConvertRectToPixel(device_scale_factor, src_subrect);
- if (using_synchronous_compositor_) {
+ if (!using_browser_compositor_) {
SynchronousCopyContents(src_subrect_in_pixel, dst_size_in_pixel, callback,
- color_type);
+ preferred_color_type);
UMA_HISTOGRAM_TIMES("Compositing.CopyFromSurfaceTimeSynchronous",
base::TimeTicks::Now() - start_time);
return;
@@ -863,27 +930,24 @@ void RenderWidgetHostViewAndroid::CopyFromCompositingSurface(
scoped_ptr<cc::CopyOutputRequest> request;
scoped_refptr<cc::Layer> readback_layer;
- DCHECK(content_view_core_);
- DCHECK(content_view_core_->GetWindowAndroid());
+ DCHECK(content_view_core_window_android_);
ui::WindowAndroidCompositor* compositor =
- content_view_core_->GetWindowAndroid()->GetCompositor();
+ content_view_core_window_android_->GetCompositor();
DCHECK(compositor);
- DCHECK(frame_provider_.get());
- scoped_refptr<cc::DelegatedRendererLayer> delegated_layer =
- CreateDelegatedLayerForFrameProvider();
- delegated_layer->SetHideLayerAndSubtree(true);
- compositor->AttachLayerForReadback(delegated_layer);
+ DCHECK(frame_provider_.get() || !surface_id_.is_null());
+ scoped_refptr<cc::Layer> layer = CreateDelegatedLayer();
+ DCHECK(layer);
+ layer->SetHideLayerAndSubtree(true);
+ compositor->AttachLayerForReadback(layer);
- readback_layer = delegated_layer;
+ readback_layer = layer;
request = cc::CopyOutputRequest::CreateRequest(
base::Bind(&RenderWidgetHostViewAndroid::
PrepareTextureCopyOutputResultForDelegatedReadback,
- dst_size_in_pixel,
- color_type,
- start_time,
- readback_layer,
- callback));
- request->set_area(src_subrect_in_pixel);
+ dst_size_in_pixel, preferred_color_type, start_time,
+ readback_layer, callback));
+ if (!src_subrect_in_pixel.IsEmpty())
+ request->set_area(src_subrect_in_pixel);
readback_layer->RequestCopyOfOutput(request.Pass());
}
@@ -917,73 +981,108 @@ void RenderWidgetHostViewAndroid::SendDelegatedFrameAck(
uint32 output_surface_id) {
DCHECK(host_);
cc::CompositorFrameAck ack;
+ 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,
- host_->GetProcess()->GetID(),
- ack);
+ host_->Send(new ViewMsg_SwapCompositorFrameAck(host_->GetRoutingID(),
+ output_surface_id, ack));
}
void RenderWidgetHostViewAndroid::SendReturnedDelegatedResources(
uint32 output_surface_id) {
- DCHECK(resource_collection_.get());
-
+ DCHECK(host_);
cc::CompositorFrameAck ack;
- resource_collection_->TakeUnusedResourcesForChildCompositor(&ack.resources);
- DCHECK(!ack.resources.empty());
+ if (!surface_returned_resources_.empty()) {
+ ack.resources.swap(surface_returned_resources_);
+ } else {
+ DCHECK(resource_collection_.get());
+ resource_collection_->TakeUnusedResourcesForChildCompositor(&ack.resources);
+ }
- RenderWidgetHostImpl::SendReclaimCompositorResources(
- host_->GetRoutingID(),
- output_surface_id,
- host_->GetProcess()->GetID(),
- ack);
+ host_->Send(new ViewMsg_ReclaimCompositorResources(host_->GetRoutingID(),
+ output_surface_id, ack));
}
void RenderWidgetHostViewAndroid::UnusedResourcesAreAvailable() {
+ DCHECK(surface_id_.is_null());
if (ack_callbacks_.size())
return;
SendReturnedDelegatedResources(last_output_surface_id_);
}
+void RenderWidgetHostViewAndroid::ReturnResources(
+ const cc::ReturnedResourceArray& resources) {
+ if (resources.empty())
+ return;
+ std::copy(resources.begin(), resources.end(),
+ std::back_inserter(surface_returned_resources_));
+ if (!ack_callbacks_.size())
+ SendReturnedDelegatedResources(last_output_surface_id_);
+}
+
void RenderWidgetHostViewAndroid::DestroyDelegatedContent() {
RemoveLayers();
frame_provider_ = NULL;
+ if (!surface_id_.is_null()) {
+ DCHECK(surface_factory_.get());
+ surface_factory_->Destroy(surface_id_);
+ surface_id_ = cc::SurfaceId();
+ }
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(
- uint32 output_surface_id,
- scoped_ptr<cc::DelegatedFrameData> frame_data) {
- bool has_content = !texture_size_in_layer_.IsEmpty();
+void RenderWidgetHostViewAndroid::CheckOutputSurfaceChanged(
+ uint32 output_surface_id) {
+ if (output_surface_id == last_output_surface_id_)
+ return;
+ // Drop the cc::DelegatedFrameResourceCollection so that we will not return
+ // any resources from the old output surface with the new output surface id.
+ if (resource_collection_.get()) {
+ resource_collection_->SetClient(NULL);
+ if (resource_collection_->LoseAllResources())
+ SendReturnedDelegatedResources(last_output_surface_id_);
+ resource_collection_ = NULL;
+ }
+ DestroyDelegatedContent();
+ surface_factory_.reset();
+ if (!surface_returned_resources_.empty())
+ SendReturnedDelegatedResources(last_output_surface_id_);
- if (output_surface_id != last_output_surface_id_) {
- // Drop the cc::DelegatedFrameResourceCollection so that we will not return
- // any resources from the old output surface with the new output surface id.
- if (resource_collection_.get()) {
- resource_collection_->SetClient(NULL);
- if (resource_collection_->LoseAllResources())
- SendReturnedDelegatedResources(last_output_surface_id_);
- resource_collection_ = NULL;
- }
- DestroyDelegatedContent();
+ last_output_surface_id_ = output_surface_id;
+}
- last_output_surface_id_ = output_surface_id;
- }
+void RenderWidgetHostViewAndroid::SubmitFrame(
+ scoped_ptr<cc::DelegatedFrameData> frame_data) {
+ cc::SurfaceManager* manager = CompositorImpl::GetSurfaceManager();
+ if (manager) {
+ if (!surface_factory_) {
+ id_allocator_ = CompositorImpl::CreateSurfaceIdAllocator();
+ surface_factory_ = make_scoped_ptr(new cc::SurfaceFactory(manager, this));
+ }
+ if (surface_id_.is_null() ||
+ texture_size_in_layer_ != current_surface_size_) {
+ RemoveLayers();
+ if (!surface_id_.is_null())
+ surface_factory_->Destroy(surface_id_);
+ surface_id_ = id_allocator_->GenerateId();
+ surface_factory_->Create(surface_id_);
+ layer_ = CreateDelegatedLayer();
- // DelegatedRendererLayerImpl applies the inverse device_scale_factor of the
- // renderer frame, assuming that the browser compositor will scale
- // it back up to device scale. But on Android we put our browser layers in
- // physical pixels and set our browser CC device_scale_factor to 1, so this
- // suppresses the transform. This line may need to be removed when fixing
- // http://crbug.com/384134 or http://crbug.com/310763
- frame_data->device_scale_factor = 1.0f;
+ DCHECK(layer_);
- if (!has_content) {
- DestroyDelegatedContent();
+ current_surface_size_ = texture_size_in_layer_;
+ AttachLayers();
+ }
+ scoped_ptr<cc::CompositorFrame> compositor_frame =
+ make_scoped_ptr(new cc::CompositorFrame());
+ compositor_frame->delegated_frame_data = frame_data.Pass();
+
+ cc::SurfaceFactory::DrawCallback ack_callback =
+ base::Bind(&RenderWidgetHostViewAndroid::RunAckCallbacks,
+ weak_ptr_factory_.GetWeakPtr());
+ surface_factory_->SubmitFrame(surface_id_, compositor_frame.Pass(),
+ ack_callback);
} else {
if (!resource_collection_.get()) {
resource_collection_ = new cc::DelegatedFrameResourceCollection;
@@ -1000,12 +1099,32 @@ void RenderWidgetHostViewAndroid::SwapDelegatedFrame(
frame_provider_->SetFrameData(frame_data.Pass());
}
}
+}
+
+void RenderWidgetHostViewAndroid::SwapDelegatedFrame(
+ uint32 output_surface_id,
+ scoped_ptr<cc::DelegatedFrameData> frame_data) {
+ CheckOutputSurfaceChanged(output_surface_id);
+ bool has_content = !texture_size_in_layer_.IsEmpty();
+
+ // DelegatedRendererLayerImpl applies the inverse device_scale_factor of the
+ // renderer frame, assuming that the browser compositor will scale
+ // it back up to device scale. But on Android we put our browser layers in
+ // physical pixels and set our browser CC device_scale_factor to 1, so this
+ // suppresses the transform. This line may need to be removed when fixing
+ // http://crbug.com/384134 or http://crbug.com/310763
+ frame_data->device_scale_factor = 1.0f;
+
+ if (!has_content) {
+ DestroyDelegatedContent();
+ } else {
+ SubmitFrame(frame_data.Pass());
+ }
if (layer_.get()) {
layer_->SetIsDrawable(true);
layer_->SetContentsOpaque(true);
layer_->SetBounds(content_size_in_layer_);
- layer_->SetNeedsDisplay();
}
base::Closure ack_callback =
@@ -1015,7 +1134,7 @@ void RenderWidgetHostViewAndroid::SwapDelegatedFrame(
ack_callbacks_.push(ack_callback);
if (host_->is_hidden())
- RunAckCallbacks();
+ RunAckCallbacks(cc::SurfaceDrawStatus::DRAW_SKIPPED);
}
void RenderWidgetHostViewAndroid::ComputeContentsSize(
@@ -1028,10 +1147,6 @@ void RenderWidgetHostViewAndroid::ComputeContentsSize(
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(
@@ -1070,18 +1185,6 @@ void RenderWidgetHostViewAndroid::InternalSwapCompositorFrame(
// 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(
@@ -1129,9 +1232,10 @@ void RenderWidgetHostViewAndroid::SynchronousFrameMetadata(
// Unblock the compositor.
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
- base::Bind(&RenderViewDevToolsAgentHost::SynchronousSwapCompositorFrame,
- static_cast<RenderViewDevToolsAgentHost*>(dtah.get()),
- frame_metadata));
+ base::Bind(
+ &RenderFrameDevToolsAgentHost::SynchronousSwapCompositorFrame,
+ static_cast<RenderFrameDevToolsAgentHost*>(dtah.get()),
+ frame_metadata));
}
}
@@ -1143,13 +1247,13 @@ void RenderWidgetHostViewAndroid::SetOverlayVideoMode(bool 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_;
+ return using_browser_compositor_;
}
void RenderWidgetHostViewAndroid::SetNeedsAnimate() {
- DCHECK(content_view_core_);
- DCHECK(!using_synchronous_compositor_);
- content_view_core_->GetWindowAndroid()->SetNeedsAnimate();
+ DCHECK(content_view_core_window_android_);
+ DCHECK(using_browser_compositor_);
+ content_view_core_window_android_->SetNeedsAnimate();
}
void RenderWidgetHostViewAndroid::MoveCaret(const gfx::PointF& position) {
@@ -1170,18 +1274,26 @@ void RenderWidgetHostViewAndroid::SelectBetweenCoordinates(
}
void RenderWidgetHostViewAndroid::OnSelectionEvent(
- SelectionEventType event,
- const gfx::PointF& position) {
+ ui::SelectionEventType event) {
DCHECK(content_view_core_);
- content_view_core_->OnSelectionEvent(event, position);
-}
-
-scoped_ptr<TouchHandleDrawable> RenderWidgetHostViewAndroid::CreateDrawable() {
+ DCHECK(selection_controller_);
+ // If a selection drag has started, it has taken over the active touch
+ // sequence. Immediately cancel gesture detection and any downstream touch
+ // listeners (e.g., web content) to communicate this transfer.
+ if (event == ui::SELECTION_SHOWN)
+ ResetGestureDetection();
+ content_view_core_->OnSelectionEvent(
+ event, selection_controller_->GetStartPosition(),
+ GetSelectionRect(*selection_controller_));
+}
+
+scoped_ptr<ui::TouchHandleDrawable>
+RenderWidgetHostViewAndroid::CreateDrawable() {
DCHECK(content_view_core_);
- if (using_synchronous_compositor_)
+ if (!using_browser_compositor_)
return content_view_core_->CreatePopupTouchHandleDrawable();
- return scoped_ptr<TouchHandleDrawable>(new CompositedTouchHandleDrawable(
+ return scoped_ptr<ui::TouchHandleDrawable>(new CompositedTouchHandleDrawable(
content_view_core_->GetLayer().get(),
content_view_core_->GetDpiScale(),
// Use the activity context (instead of the application context) to ensure
@@ -1192,47 +1304,62 @@ scoped_ptr<TouchHandleDrawable> RenderWidgetHostViewAndroid::CreateDrawable() {
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,
+ ReadbackRequestCallback& callback,
const SkColorType color_type) {
+ gfx::Size input_size_in_pixel;
+ if (src_subrect_in_pixel.IsEmpty())
+ input_size_in_pixel = content_size_in_layer_;
+ else
+ input_size_in_pixel = src_subrect_in_pixel.size();
+
+ gfx::Size output_size_in_pixel;
+ if (dst_size_in_pixel.IsEmpty())
+ output_size_in_pixel = input_size_in_pixel;
+ else
+ output_size_in_pixel = dst_size_in_pixel;
+ int output_width = output_size_in_pixel.width();
+ int output_height = output_size_in_pixel.height();
+
SynchronousCompositor* compositor =
SynchronousCompositorImpl::FromID(host_->GetProcess()->GetID(),
host_->GetRoutingID());
if (!compositor) {
- callback.Run(false, SkBitmap());
+ callback.Run(SkBitmap(), READBACK_FAILED);
return;
}
SkBitmap bitmap;
- bitmap.allocPixels(SkImageInfo::Make(dst_size_in_pixel.width(),
- dst_size_in_pixel.height(),
+ bitmap.allocPixels(SkImageInfo::Make(output_width,
+ output_height,
color_type,
kPremul_SkAlphaType));
SkCanvas canvas(bitmap);
canvas.scale(
- (float)dst_size_in_pixel.width() / (float)src_subrect_in_pixel.width(),
- (float)dst_size_in_pixel.height() / (float)src_subrect_in_pixel.height());
+ (float)output_width / (float)input_size_in_pixel.width(),
+ (float)output_height / (float)input_size_in_pixel.height());
compositor->DemandDrawSw(&canvas);
- callback.Run(true, bitmap);
+ callback.Run(bitmap, READBACK_SUCCESS);
}
void RenderWidgetHostViewAndroid::OnFrameMetadataUpdated(
const cc::CompositorFrameMetadata& frame_metadata) {
-
- // Disable double tap zoom for pages that have a width=device-width or
- // narrower viewport (indicating that this is a mobile-optimized or responsive
- // web design, so text will be legible without zooming). Also disable
- // double tap and pinch for pages that prevent zooming in or out.
- bool has_mobile_viewport = HasMobileViewport(frame_metadata);
- bool has_fixed_page_scale = HasFixedPageScale(frame_metadata);
- gesture_provider_.SetDoubleTapSupportForPageEnabled(
- !has_fixed_page_scale && !has_mobile_viewport);
+ bool is_mobile_optimized = IsMobileOptimizedFrame(frame_metadata);
+ gesture_provider_.SetDoubleTapSupportForPageEnabled(!is_mobile_optimized);
if (!content_view_core_)
return;
+ if (overscroll_controller_)
+ overscroll_controller_->OnFrameMetadataUpdated(frame_metadata);
+
if (selection_controller_) {
+ selection_controller_->OnSelectionEditable(
+ frame_metadata.selection.is_editable);
+ selection_controller_->OnSelectionEmpty(
+ frame_metadata.selection.is_empty_text_form_control);
selection_controller_->OnSelectionBoundsChanged(
- frame_metadata.selection_start, frame_metadata.selection_end);
+ ConvertSelectionBound(frame_metadata.selection.start),
+ ConvertSelectionBound(frame_metadata.selection.end));
}
// All offsets and sizes are in CSS pixels.
@@ -1244,12 +1371,16 @@ void RenderWidgetHostViewAndroid::OnFrameMetadataUpdated(
frame_metadata.root_layer_size,
frame_metadata.scrollable_viewport_size,
frame_metadata.location_bar_offset,
- frame_metadata.location_bar_content_translation);
+ frame_metadata.location_bar_content_translation,
+ is_mobile_optimized);
#if defined(VIDEO_HOLE)
if (host_ && host_->IsRenderView()) {
RenderViewHostImpl* rvhi = static_cast<RenderViewHostImpl*>(
RenderViewHost::From(host_));
- rvhi->media_web_contents_observer()->OnFrameInfoUpdated();
+ WebContentsImpl* web_contents_impl =
+ static_cast<WebContentsImpl*>(WebContents::FromRenderViewHost(rvhi));
+ if (web_contents_impl)
+ web_contents_impl->media_web_contents_observer()->OnFrameInfoUpdated();
}
#endif // defined(VIDEO_HOLE)
}
@@ -1259,6 +1390,53 @@ void RenderWidgetHostViewAndroid::AcceleratedSurfaceInitialized(int route_id) {
accelerated_surface_route_id_ = route_id;
}
+void RenderWidgetHostViewAndroid::ShowInternal() {
+ DCHECK(is_showing_);
+ if (!host_ || !host_->is_hidden())
+ return;
+
+ if (layer_.get())
+ layer_->SetHideLayerAndSubtree(false);
+
+ frame_evictor_->SetVisible(true);
+
+ if (overscroll_controller_)
+ overscroll_controller_->Enable();
+
+ host_->WasShown(ui::LatencyInfo());
+
+ if (content_view_core_) {
+ StartObservingRootWindow();
+ RequestVSyncUpdate(BEGIN_FRAME);
+ }
+}
+
+void RenderWidgetHostViewAndroid::HideInternal(
+ bool hide_frontbuffer,
+ bool stop_observing_root_window) {
+ if (hide_frontbuffer) {
+ if (layer_.get() && locks_on_frame_count_ == 0)
+ layer_->SetHideLayerAndSubtree(true);
+
+ frame_evictor_->SetVisible(false);
+ }
+
+ if (stop_observing_root_window)
+ StopObservingRootWindow();
+
+ if (!host_ || host_->is_hidden())
+ return;
+
+ if (overscroll_controller_)
+ overscroll_controller_->Disable();
+
+ RunAckCallbacks(cc::SurfaceDrawStatus::DRAW_SKIPPED);
+
+ // Inform the renderer that we are being hidden so it can reduce its resource
+ // utilization.
+ host_->WasHidden();
+}
+
void RenderWidgetHostViewAndroid::AttachLayers() {
if (!content_view_core_)
return;
@@ -1266,8 +1444,8 @@ void RenderWidgetHostViewAndroid::AttachLayers() {
return;
content_view_core_->AttachLayer(layer_);
- if (overscroll_effect_)
- overscroll_effect_->Enable();
+ if (overscroll_controller_)
+ overscroll_controller_->Enable();
layer_->SetHideLayerAndSubtree(!is_showing_);
}
@@ -1279,31 +1457,34 @@ void RenderWidgetHostViewAndroid::RemoveLayers() {
return;
content_view_core_->RemoveLayer(layer_);
- if (overscroll_effect_)
- overscroll_effect_->Disable();
+ if (overscroll_controller_)
+ overscroll_controller_->Disable();
}
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;
+
+ // If the host has been hidden, defer vsync requests until it is shown
+ // again via |Show()|.
+ if (!host_ || host_->is_hidden())
+ return;
+
// 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();
+ content_view_core_window_android_->RequestVSyncUpdate();
}
void RenderWidgetHostViewAndroid::StartObservingRootWindow() {
- DCHECK(content_view_core_);
+ DCHECK(content_view_core_window_android_);
+ DCHECK(is_showing_);
if (observing_root_window_)
return;
observing_root_window_ = true;
- content_view_core_->GetWindowAndroid()->AddObserver(this);
+ content_view_core_window_android_->AddObserver(this);
// Clear existing vsync requests to allow a request to the new window.
uint32 outstanding_vsync_requests = outstanding_vsync_requests_;
@@ -1312,7 +1493,7 @@ void RenderWidgetHostViewAndroid::StartObservingRootWindow() {
}
void RenderWidgetHostViewAndroid::StopObservingRootWindow() {
- if (!content_view_core_) {
+ if (!content_view_core_window_android_) {
DCHECK(!observing_root_window_);
return;
}
@@ -1321,38 +1502,57 @@ void RenderWidgetHostViewAndroid::StopObservingRootWindow() {
return;
observing_root_window_ = false;
- content_view_core_->GetWindowAndroid()->RemoveObserver(this);
+ content_view_core_window_android_->RemoveObserver(this);
}
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();
+ if (using_browser_compositor_) {
+ 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)));
+ host_->Send(new ViewMsg_BeginFrame(
+ host_->GetRoutingID(),
+ cc::BeginFrameArgs::Create(BEGINFRAME_FROM_HERE, frame_time, deadline,
+ vsync_period, cc::BeginFrameArgs::NORMAL)));
+ } else {
+ SynchronousCompositorImpl* compositor = SynchronousCompositorImpl::FromID(
+ host_->GetProcess()->GetID(), host_->GetRoutingID());
+ if (compositor) {
+ // The synchronous compositor synchronously does it's work in this call.
+ // It does not use a deadline.
+ compositor->BeginFrame(cc::BeginFrameArgs::Create(
+ BEGINFRAME_FROM_HERE, frame_time, base::TimeTicks(), vsync_period,
+ cc::BeginFrameArgs::NORMAL));
+ }
+ }
}
bool RenderWidgetHostViewAndroid::Animate(base::TimeTicks frame_time) {
- bool needs_animate =
- overscroll_effect_ ? overscroll_effect_->Animate(frame_time) : false;
+ bool needs_animate = false;
+ if (overscroll_controller_) {
+ needs_animate |= overscroll_controller_->Animate(
+ frame_time, content_view_core_->GetLayer().get());
+ }
if (selection_controller_)
needs_animate |= selection_controller_->Animate(frame_time);
return needs_animate;
}
+void RenderWidgetHostViewAndroid::RequestDisallowInterceptTouchEvent() {
+ if (content_view_core_)
+ content_view_core_->RequestDisallowInterceptTouchEvent();
+}
+
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(
@@ -1375,9 +1575,9 @@ gfx::Rect RenderWidgetHostViewAndroid::GetBoundsInRootWindow() {
gfx::GLSurfaceHandle RenderWidgetHostViewAndroid::GetCompositingSurface() {
gfx::GLSurfaceHandle handle =
gfx::GLSurfaceHandle(gfx::kNullPluginWindow, gfx::NULL_TRANSPORT);
- if (CompositorImpl::IsInitialized()) {
+ if (using_browser_compositor_) {
handle.parent_client_id =
- ImageTransportFactoryAndroid::GetInstance()->GetChannelID();
+ BrowserGpuChannelHostFactory::instance()->GetGpuChannelId();
}
return handle;
}
@@ -1385,18 +1585,14 @@ gfx::GLSurfaceHandle RenderWidgetHostViewAndroid::GetCompositingSurface() {
void RenderWidgetHostViewAndroid::ProcessAckedTouchEvent(
const TouchEventWithLatencyInfo& touch, InputEventAckState ack_result) {
const bool event_consumed = ack_result == INPUT_EVENT_ACK_STATE_CONSUMED;
- gesture_provider_.OnTouchEventAck(event_consumed);
+ gesture_provider_.OnAsyncTouchEventAck(event_consumed);
}
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 (overscroll_controller_)
+ overscroll_controller_->OnGestureEventAck(event, ack_result);
if (content_view_core_)
content_view_core_->OnGestureEventAck(event, ack_result);
@@ -1404,21 +1600,28 @@ void RenderWidgetHostViewAndroid::GestureEventAck(
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 (selection_controller_ &&
+ blink::WebInputEvent::isGestureEventType(input_event.type)) {
+ const blink::WebGestureEvent& gesture_event =
+ static_cast<const blink::WebGestureEvent&>(input_event);
+ gfx::PointF gesture_location(gesture_event.x, gesture_event.y);
+ if (input_event.type == blink::WebInputEvent::GestureLongPress) {
+ if (selection_controller_->WillHandleLongPressEvent(gesture_location))
+ return INPUT_EVENT_ACK_STATE_CONSUMED;
+ } else if (input_event.type == blink::WebInputEvent::GestureTap) {
+ if (selection_controller_->WillHandleTapEvent(gesture_location))
+ return INPUT_EVENT_ACK_STATE_CONSUMED;
}
}
- if (content_view_core_ &&
- content_view_core_->FilterInputEvent(input_event))
+ if (overscroll_controller_ &&
+ blink::WebInputEvent::isGestureEventType(input_event.type) &&
+ overscroll_controller_->WillHandleGestureEvent(
+ static_cast<const blink::WebGestureEvent&>(input_event))) {
+ return INPUT_EVENT_ACK_STATE_CONSUMED;
+ }
+
+ if (content_view_core_ && content_view_core_->FilterInputEvent(input_event))
return INPUT_EVENT_ACK_STATE_CONSUMED;
if (!host_)
@@ -1501,11 +1704,11 @@ void RenderWidgetHostViewAndroid::SendMouseWheelEvent(
void RenderWidgetHostViewAndroid::SendGestureEvent(
const blink::WebGestureEvent& event) {
// Sending a gesture that may trigger overscroll should resume the effect.
- if (overscroll_effect_)
- overscroll_effect_->Enable();
+ if (overscroll_controller_)
+ overscroll_controller_->Enable();
if (host_)
- host_->ForwardGestureEventWithLatencyInfo(event, CreateLatencyInfo(event));
+ host_->ForwardGestureEventWithLatencyInfo(event, ui::LatencyInfo());
}
void RenderWidgetHostViewAndroid::MoveCaret(const gfx::Point& point) {
@@ -1532,17 +1735,16 @@ void RenderWidgetHostViewAndroid::OnShowingPastePopup(
// 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();
+ ui::SelectionBound insertion_bound;
+ insertion_bound.set_type(ui::SelectionBound::CENTER);
+ insertion_bound.set_visible(true);
+ insertion_bound.SetEdge(point, point);
+ selection_controller_->HideAndDisallowShowingAutomatically();
selection_controller_->OnSelectionEditable(true);
selection_controller_->OnSelectionEmpty(true);
selection_controller_->OnSelectionBoundsChanged(insertion_bound,
insertion_bound);
+ selection_controller_->AllowShowingFromCurrentSelection();
}
SkColor RenderWidgetHostViewAndroid::GetCachedBackgroundColor() const {
@@ -1554,23 +1756,8 @@ void RenderWidgetHostViewAndroid::DidOverscroll(
if (!content_view_core_ || !layer_.get() || !is_showing_)
return;
- const float device_scale_factor = content_view_core_->GetDpiScale();
-
- 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),
- gfx::ScaleVector2d(
- params.causal_event_viewport_point.OffsetFromOrigin(),
- device_scale_factor))) {
- SetNeedsAnimate();
- }
+ if (overscroll_controller_)
+ overscroll_controller_->OnOverscrolled(params);
}
void RenderWidgetHostViewAndroid::DidStopFlinging() {
@@ -1585,13 +1772,16 @@ void RenderWidgetHostViewAndroid::SetContentViewCore(
bool resize = false;
if (content_view_core != content_view_core_) {
- overscroll_effect_.reset();
+ overscroll_controller_.reset();
selection_controller_.reset();
ReleaseLocksOnSurface();
resize = true;
}
content_view_core_ = content_view_core;
+ content_view_core_window_android_ =
+ content_view_core_ ? content_view_core_->GetWindowAndroid() : nullptr;
+ DCHECK_EQ(!!content_view_core_, !!content_view_core_window_android_);
BrowserAccessibilityManager* manager = NULL;
if (host_)
@@ -1608,7 +1798,8 @@ void RenderWidgetHostViewAndroid::SetContentViewCore(
if (!content_view_core_)
return;
- StartObservingRootWindow();
+ if (is_showing_)
+ StartObservingRootWindow();
if (resize)
WasResized();
@@ -1616,12 +1807,14 @@ void RenderWidgetHostViewAndroid::SetContentViewCore(
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_);
+ if (!overscroll_controller_ &&
+ content_view_core_window_android_->GetCompositor()) {
+ overscroll_controller_ = CreateOverscrollController(content_view_core_);
+ }
}
-void RenderWidgetHostViewAndroid::RunAckCallbacks() {
+void RenderWidgetHostViewAndroid::RunAckCallbacks(
+ cc::SurfaceDrawStatus status) {
while (!ack_callbacks_.empty()) {
ack_callbacks_.front().Run();
ack_callbacks_.pop();
@@ -1630,45 +1823,69 @@ void RenderWidgetHostViewAndroid::RunAckCallbacks() {
void RenderWidgetHostViewAndroid::OnGestureEvent(
const ui::GestureEventData& gesture) {
- SendGestureEvent(CreateWebGestureEventFromGestureEventData(gesture));
+ blink::WebGestureEvent web_gesture =
+ ui::CreateWebGestureEventFromGestureEventData(gesture);
+ // TODO(jdduke): Remove this workaround after Android fixes UiAutomator to
+ // stop providing shift meta values to synthetic MotionEvents. This prevents
+ // unintended shift+click interpretation of all accessibility clicks.
+ // See crbug.com/443247.
+ if (web_gesture.type == blink::WebInputEvent::GestureTap &&
+ web_gesture.modifiers == blink::WebInputEvent::ShiftKey) {
+ web_gesture.modifiers = 0;
+ }
+ SendGestureEvent(web_gesture);
}
void RenderWidgetHostViewAndroid::OnCompositingDidCommit() {
- RunAckCallbacks();
+ RunAckCallbacks(cc::SurfaceDrawStatus::DRAWN);
+}
+
+void RenderWidgetHostViewAndroid::OnRootWindowVisibilityChanged(bool visible) {
+ DCHECK(is_showing_);
+ if (visible) {
+ ShowInternal();
+ } else {
+ bool hide_frontbuffer = true;
+ bool stop_observing_root_window = false;
+ HideInternal(hide_frontbuffer, stop_observing_root_window);
+ }
}
void RenderWidgetHostViewAndroid::OnAttachCompositor() {
DCHECK(content_view_core_);
- if (overscroll_effect_enabled_ && !overscroll_effect_)
- overscroll_effect_ = CreateOverscrollEffect(content_view_core_);
+ if (!overscroll_controller_)
+ overscroll_controller_ = CreateOverscrollController(content_view_core_);
}
void RenderWidgetHostViewAndroid::OnDetachCompositor() {
DCHECK(content_view_core_);
- DCHECK(!using_synchronous_compositor_);
- RunAckCallbacks();
- overscroll_effect_.reset();
+ DCHECK(using_browser_compositor_);
+ RunAckCallbacks(cc::SurfaceDrawStatus::DRAW_SKIPPED);
+ overscroll_controller_.reset();
}
void RenderWidgetHostViewAndroid::OnVSync(base::TimeTicks frame_time,
base::TimeDelta vsync_period) {
- TRACE_EVENT0("cc", "RenderWidgetHostViewAndroid::OnVSync");
- if (!host_)
+ TRACE_EVENT0("cc,benchmark", "RenderWidgetHostViewAndroid::OnVSync");
+ if (!host_ || host_->is_hidden())
return;
- const uint32 current_vsync_requests = outstanding_vsync_requests_;
- outstanding_vsync_requests_ = 0;
-
- if (current_vsync_requests & FLUSH_INPUT)
+ if (outstanding_vsync_requests_ & FLUSH_INPUT) {
+ outstanding_vsync_requests_ &= ~FLUSH_INPUT;
host_->FlushInput();
+ }
- if (current_vsync_requests & BEGIN_FRAME ||
- current_vsync_requests & PERSISTENT_BEGIN_FRAME) {
+ if (outstanding_vsync_requests_ & BEGIN_FRAME ||
+ outstanding_vsync_requests_ & PERSISTENT_BEGIN_FRAME) {
+ outstanding_vsync_requests_ &= ~BEGIN_FRAME;
SendBeginFrame(frame_time, vsync_period);
}
- if (current_vsync_requests & PERSISTENT_BEGIN_FRAME)
- RequestVSyncUpdate(PERSISTENT_BEGIN_FRAME);
+ // This allows for SendBeginFrame and FlushInput to modify
+ // outstanding_vsync_requests.
+ uint32 outstanding_vsync_requests = outstanding_vsync_requests_;
+ outstanding_vsync_requests_ = 0;
+ RequestVSyncUpdate(outstanding_vsync_requests);
}
void RenderWidgetHostViewAndroid::OnAnimate(base::TimeTicks begin_frame_time) {
@@ -1676,24 +1893,36 @@ void RenderWidgetHostViewAndroid::OnAnimate(base::TimeTicks begin_frame_time) {
SetNeedsAnimate();
}
+void RenderWidgetHostViewAndroid::OnActivityPaused() {
+ TRACE_EVENT0("browser", "RenderWidgetHostViewAndroid::OnActivityPaused");
+ DCHECK(is_showing_);
+ bool hide_frontbuffer = false;
+ bool stop_observing_root_window = false;
+ HideInternal(hide_frontbuffer, stop_observing_root_window);
+}
+
+void RenderWidgetHostViewAndroid::OnActivityResumed() {
+ TRACE_EVENT0("browser", "RenderWidgetHostViewAndroid::OnActivityResumed");
+ DCHECK(is_showing_);
+ ShowInternal();
+}
+
void RenderWidgetHostViewAndroid::OnLostResources() {
ReleaseLocksOnSurface();
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 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) {
+void RenderWidgetHostViewAndroid::
+ PrepareTextureCopyOutputResultForDelegatedReadback(
+ const gfx::Size& dst_size_in_pixel,
+ SkColorType color_type,
+ const base::TimeTicks& start_time,
+ scoped_refptr<cc::Layer> readback_layer,
+ ReadbackRequestCallback& callback,
+ scoped_ptr<cc::CopyOutputResult> result) {
readback_layer->RemoveFromParent();
PrepareTextureCopyOutputResult(
dst_size_in_pixel, color_type, start_time, callback, result.Pass());
@@ -1702,31 +1931,39 @@ RenderWidgetHostViewAndroid::PrepareTextureCopyOutputResultForDelegatedReadback(
// static
void RenderWidgetHostViewAndroid::PrepareTextureCopyOutputResult(
const gfx::Size& dst_size_in_pixel,
- const SkColorType color_type,
+ SkColorType color_type,
const base::TimeTicks& start_time,
- const base::Callback<void(bool, const SkBitmap&)>& callback,
+ ReadbackRequestCallback& callback,
scoped_ptr<cc::CopyOutputResult> result) {
base::ScopedClosureRunner scoped_callback_runner(
- base::Bind(callback, false, SkBitmap()));
+ base::Bind(callback, SkBitmap(), READBACK_FAILED));
TRACE_EVENT0("cc",
"RenderWidgetHostViewAndroid::PrepareTextureCopyOutputResult");
if (!result->HasTexture() || result->IsEmpty() || result->size().IsEmpty())
return;
+ gfx::Size output_size_in_pixel;
+ if (dst_size_in_pixel.IsEmpty())
+ output_size_in_pixel = result->size();
+ else
+ output_size_in_pixel = dst_size_in_pixel;
+
+ GLHelper* gl_helper = GetPostReadbackGLHelper();
+ if (!gl_helper)
+ return;
+ if (!gl_helper->IsReadbackConfigSupported(color_type))
+ color_type = kRGBA_8888_SkColorType;
scoped_ptr<SkBitmap> bitmap(new SkBitmap);
- if (!bitmap->tryAllocPixels(SkImageInfo::Make(dst_size_in_pixel.width(),
- dst_size_in_pixel.height(),
+ if (!bitmap->tryAllocPixels(SkImageInfo::Make(output_size_in_pixel.width(),
+ output_size_in_pixel.height(),
color_type,
- kOpaque_SkAlphaType)))
+ kOpaque_SkAlphaType))) {
+ scoped_callback_runner.Reset(
+ base::Bind(callback, SkBitmap(), READBACK_BITMAP_ALLOCATION_FAILURE));
return;
+ }
- ImageTransportFactoryAndroid* factory =
- ImageTransportFactoryAndroid::GetInstance();
- GLHelper* gl_helper = factory->GetGLHelper();
-
- if (!gl_helper)
- return;
scoped_ptr<SkAutoLockPixels> bitmap_pixels_lock(
new SkAutoLockPixels(*bitmap));
@@ -1746,7 +1983,7 @@ void RenderWidgetHostViewAndroid::PrepareTextureCopyOutputResult(
texture_mailbox.sync_point(),
result->size(),
gfx::Rect(result->size()),
- dst_size_in_pixel,
+ output_size_in_pixel,
pixels,
color_type,
base::Bind(&CopyFromCompositingSurfaceFinished,
@@ -1758,42 +1995,27 @@ void RenderWidgetHostViewAndroid::PrepareTextureCopyOutputResult(
GLHelper::SCALER_QUALITY_GOOD);
}
-bool RenderWidgetHostViewAndroid::IsReadbackConfigSupported(
- SkColorType color_type) {
- ImageTransportFactoryAndroid* factory =
- ImageTransportFactoryAndroid::GetInstance();
- GLHelper* gl_helper = factory->GetGLHelper();
- if (!gl_helper)
- return false;
- return gl_helper->IsReadbackConfigSupported(color_type);
+void RenderWidgetHostViewAndroid::OnStylusSelectBegin(float x0,
+ float y0,
+ float x1,
+ float y1) {
+ SelectBetweenCoordinates(gfx::PointF(x0, y0), gfx::PointF(x1, y1));
}
-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::SysInfo::IsLowEndDevice()) {
- if (IsReadbackConfigSupported(kRGB_565_SkColorType))
- return kRGB_565_SkColorType;
- }
- return kN32_SkColorType;
+void RenderWidgetHostViewAndroid::OnStylusSelectUpdate(float x, float y) {
+ MoveRangeSelectionExtent(gfx::PointF(x, y));
}
-void RenderWidgetHostViewAndroid::ShowSelectionHandlesAutomatically() {
- // Fake a long press to allow automatic selection handle showing.
+void RenderWidgetHostViewAndroid::OnStylusSelectEnd() {
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));
+ selection_controller_->AllowShowingFromCurrentSelection();
}
-void RenderWidgetHostViewAndroid::LongPress(
- base::TimeTicks time, float x, float y) {
+void RenderWidgetHostViewAndroid::OnStylusSelectTap(base::TimeTicks time,
+ float x,
+ float y) {
+ // Treat the stylus tap as a long press, activating either a word selection or
+ // context menu depending on the targetted content.
blink::WebGestureEvent long_press = WebGestureEventBuilder::Build(
blink::WebInputEvent::GestureLongPress,
(time - base::TimeTicks()).InSecondsF(), x, y);
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 129b773fbfc..fc8decb070d 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
@@ -16,21 +16,23 @@
#include "base/process/process.h"
#include "cc/layers/delegated_frame_resource_collection.h"
#include "cc/output/begin_frame_args.h"
+#include "cc/surfaces/surface_factory_client.h"
+#include "cc/surfaces/surface_id.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/browser/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/input/stylus_text_selector.h"
#include "content/browser/renderer_host/render_widget_host_view_base.h"
#include "content/common/content_export.h"
+#include "content/public/browser/readback_types.h"
#include "gpu/command_buffer/common/mailbox.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
-#include "ui/base/android/window_android_observer.h"
+#include "ui/android/window_android_observer.h"
#include "ui/events/gesture_detection/filtered_gesture_provider.h"
-#include "ui/gfx/size.h"
-#include "ui/gfx/vector2d_f.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/geometry/vector2d_f.h"
+#include "ui/touch_selection/touch_selection_controller.h"
struct ViewHostMsg_TextInputState_Params;
@@ -39,6 +41,9 @@ class CopyOutputResult;
class DelegatedFrameProvider;
class DelegatedRendererLayer;
class Layer;
+class SurfaceFactory;
+class SurfaceIdAllocator;
+enum class SurfaceDrawStatus;
}
namespace blink {
@@ -49,168 +54,154 @@ class WebMouseEvent;
namespace content {
class ContentViewCoreImpl;
-class OverscrollGlow;
+class OverscrollControllerAndroid;
class RenderWidgetHost;
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.
// -----------------------------------------------------------------------------
class CONTENT_EXPORT RenderWidgetHostViewAndroid
: public RenderWidgetHostViewBase,
public cc::DelegatedFrameResourceCollectionClient,
- public ImageTransportFactoryAndroidObserver,
+ public cc::SurfaceFactoryClient,
public ui::GestureProviderClient,
public ui::WindowAndroidObserver,
public DelegatedFrameEvictorClient,
- public GestureTextSelectorClient,
- public TouchSelectionControllerClient {
+ public StylusTextSelectorClient,
+ public ui::TouchSelectionControllerClient {
public:
RenderWidgetHostViewAndroid(RenderWidgetHostImpl* widget,
ContentViewCoreImpl* content_view_core);
- virtual ~RenderWidgetHostViewAndroid();
+ ~RenderWidgetHostViewAndroid() override;
+
+ void Blur();
// RenderWidgetHostView implementation.
- 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;
- 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::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 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(
+ bool OnMessageReceived(const IPC::Message& msg) override;
+ void InitAsChild(gfx::NativeView parent_view) override;
+ void InitAsPopup(RenderWidgetHostView* parent_host_view,
+ const gfx::Rect& pos) override;
+ void InitAsFullscreen(RenderWidgetHostView* reference_host_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;
+ void MovePluginWindows(const std::vector<WebPluginGeometry>& moves) 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::Size GetPhysicalBackingSize() const override;
+ bool DoTopControlsShrinkBlinkSize() const override;
+ float GetTopControlsHeight() const 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 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;
- virtual void SelectionChanged(const base::string16& text,
- size_t offset,
- const gfx::Range& range) override;
- virtual void SelectionBoundsChanged(
+ void FocusedNodeChanged(bool is_editable_node) 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;
- 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(
+ void AcceleratedSurfaceInitialized(int route_id) override;
+ bool HasAcceleratedSurface(const gfx::Size& desired_size) override;
+ void SetBackgroundColor(SkColor color) override;
+ void CopyFromCompositingSurface(
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
- CopyFromCompositingSurfaceCallback& callback,
- const SkColorType color_type) override;
- virtual void CopyFromCompositingSurfaceToVideoFrame(
+ ReadbackRequestCallback& callback,
+ const SkColorType preferred_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 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;
- virtual InputEventAckState FilterInputEvent(
+ bool CanCopyToVideoFrame() const override;
+ void GetScreenInfo(blink::WebScreenInfo* results) override;
+ gfx::Rect GetBoundsInRootWindow() override;
+ gfx::GLSurfaceHandle GetCompositingSurface() override;
+ void ProcessAckedTouchEvent(const TouchEventWithLatencyInfo& touch,
+ InputEventAckState ack_result) override;
+ InputEventAckState FilterInputEvent(
const blink::WebInputEvent& input_event) override;
- virtual void OnSetNeedsFlushInput() override;
- virtual void GestureEventAck(const blink::WebGestureEvent& event,
- InputEventAckState ack_result) override;
- virtual BrowserAccessibilityManager* CreateBrowserAccessibilityManager(
+ void OnSetNeedsFlushInput() override;
+ void GestureEventAck(const blink::WebGestureEvent& event,
+ InputEventAckState ack_result) override;
+ 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& rect_pixels,
- const SkBitmap& zoomed_bitmap) override;
- virtual scoped_ptr<SyntheticGestureTarget> CreateSyntheticGestureTarget()
- 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;
+ bool LockMouse() override;
+ void UnlockMouse() override;
+ void OnSwapCompositorFrame(uint32 output_surface_id,
+ scoped_ptr<cc::CompositorFrame> frame) override;
+ void DidOverscroll(const DidOverscrollParams& params) override;
+ void DidStopFlinging() override;
+ void ShowDisambiguationPopup(const gfx::Rect& rect_pixels,
+ const SkBitmap& zoomed_bitmap) override;
+ scoped_ptr<SyntheticGestureTarget> CreateSyntheticGestureTarget() override;
+ void LockCompositingSurface() override;
+ void UnlockCompositingSurface() override;
+ void OnTextSurroundingSelectionResponse(const base::string16& content,
+ size_t start_offset,
+ size_t end_offset) override;
+ void OnDidNavigateMainFrameToNewPage() override;
// cc::DelegatedFrameResourceCollectionClient implementation.
- virtual void UnusedResourcesAreAvailable() override;
+ void UnusedResourcesAreAvailable() override;
+
+ // cc::SurfaceFactoryClient implementation.
+ void ReturnResources(const cc::ReturnedResourceArray& resources) override;
// ui::GestureProviderClient implementation.
- virtual void OnGestureEvent(const ui::GestureEventData& gesture) override;
+ void OnGestureEvent(const ui::GestureEventData& gesture) override;
// ui::WindowAndroidObserver implementation.
- 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;
-
- // ImageTransportFactoryAndroidObserver implementation.
- virtual void OnLostResources() override;
+ void OnCompositingDidCommit() override;
+ void OnRootWindowVisibilityChanged(bool visible) override;
+ void OnAttachCompositor() override;
+ void OnDetachCompositor() override;
+ void OnVSync(base::TimeTicks frame_time,
+ base::TimeDelta vsync_period) override;
+ void OnAnimate(base::TimeTicks begin_frame_time) override;
+ void OnActivityPaused() override;
+ void OnActivityResumed() override;
// DelegatedFrameEvictor implementation
- virtual void EvictDelegatedFrame() override;
-
- virtual SkColorType 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;
+ void EvictDelegatedFrame() override;
+
+ // StylusTextSelectorClient implementation.
+ void OnStylusSelectBegin(float x0, float y0, float x1, float y1) override;
+ void OnStylusSelectUpdate(float x, float y) override;
+ void OnStylusSelectEnd() override;
+ void OnStylusSelectTap(base::TimeTicks time, float x, float y) override;
+
+ // ui::TouchSelectionControllerClient implementation.
+ bool SupportsAnimation() const override;
+ void SetNeedsAnimate() override;
+ void MoveCaret(const gfx::PointF& position) override;
+ void MoveRangeSelectionExtent(const gfx::PointF& extent) override;
+ void SelectBetweenCoordinates(const gfx::PointF& base,
+ const gfx::PointF& extent) override;
+ void OnSelectionEvent(ui::SelectionEventType event) override;
+ scoped_ptr<ui::TouchHandleDrawable> CreateDrawable() override;
// Non-virtual methods
void SetContentViewCore(ContentViewCoreImpl* content_view_core);
@@ -223,7 +214,7 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
void OnTextInputStateChanged(const ViewHostMsg_TextInputState_Params& params);
void OnDidChangeBodyBackgroundColor(SkColor color);
void OnStartContentIntent(const GURL& content_url);
- void OnSetNeedsBeginFrame(bool enabled);
+ void OnSetNeedsBeginFrames(bool enabled);
void OnSmartClipDataExtracted(const base::string16& text,
const base::string16& html,
const gfx::Rect rect);
@@ -238,14 +229,12 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
void WasResized();
- void GetScaledContentBitmap(
- float scale,
- SkColorType color_type,
- gfx::Rect src_subrect,
- const base::Callback<void(bool, const SkBitmap&)>& result_callback);
+ void GetScaledContentBitmap(float scale,
+ SkColorType preferred_color_type,
+ gfx::Rect src_subrect,
+ ReadbackRequestCallback& result_callback);
- scoped_refptr<cc::DelegatedRendererLayer>
- CreateDelegatedLayerForFrameProvider() const;
+ scoped_refptr<cc::Layer> CreateDelegatedLayer() const;
bool HasValidFrame() const;
@@ -253,6 +242,7 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
void DismissTextHandles();
void SetTextHandlesTemporarilyHidden(bool hidden);
void OnShowingPastePopup(const gfx::PointF& point);
+ void OnShowUnhandledTapUIIfNeeded(int x_dip, int y_dip);
void SynchronousFrameMetadata(
const cc::CompositorFrameMetadata& frame_metadata);
@@ -265,21 +255,14 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
void SetTextSurroundingSelectionCallback(
const TextSurroundingSelectionCallback& callback);
+ static void OnContextLost();
+
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 RunAckCallbacks(cc::SurfaceDrawStatus status);
void DestroyDelegatedContent();
+ void CheckOutputSurfaceChanged(uint32 output_surface_id);
+ void SubmitFrame(scoped_ptr<cc::DelegatedFrameData> frame_data);
void SwapDelegatedFrame(uint32 output_surface_id,
scoped_ptr<cc::DelegatedFrameData> frame_data);
void SendDelegatedFrameAck(uint32 output_surface_id);
@@ -289,6 +272,8 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
const cc::CompositorFrameMetadata& frame_metadata);
void ComputeContentsSize(const cc::CompositorFrameMetadata& frame_metadata);
+ void ShowInternal();
+ void HideInternal(bool hide_frontbuffer, bool stop_observing_root_window);
void AttachLayers();
void RemoveLayers();
@@ -296,26 +281,23 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
// of the copy.
static void PrepareTextureCopyOutputResult(
const gfx::Size& dst_size_in_pixel,
- const SkColorType color_type,
+ SkColorType color_type,
const base::TimeTicks& start_time,
- const base::Callback<void(bool, const SkBitmap&)>& callback,
+ ReadbackRequestCallback& callback,
scoped_ptr<cc::CopyOutputResult> result);
static void PrepareTextureCopyOutputResultForDelegatedReadback(
const gfx::Size& dst_size_in_pixel,
- const SkColorType color_type,
+ SkColorType color_type,
const base::TimeTicks& start_time,
scoped_refptr<cc::Layer> readback_layer,
- const base::Callback<void(bool, const SkBitmap&)>& callback,
+ ReadbackRequestCallback& callback,
scoped_ptr<cc::CopyOutputResult> result);
// DevTools ScreenCast support for Android WebView.
- void SynchronousCopyContents(
- const gfx::Rect& src_subrect_in_pixel,
- const gfx::Size& dst_size_in_pixel,
- const base::Callback<void(bool, const SkBitmap&)>& callback,
- const SkColorType color_type);
-
- bool IsReadbackConfigSupported(SkColorType color_type);
+ void SynchronousCopyContents(const gfx::Rect& src_subrect_in_pixel,
+ const gfx::Size& dst_size_in_pixel,
+ ReadbackRequestCallback& callback,
+ const 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.
@@ -329,6 +311,7 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
void InternalSwapCompositorFrame(uint32 output_surface_id,
scoped_ptr<cc::CompositorFrame> frame);
+ void OnLostResources();
enum VSyncRequestType {
FLUSH_INPUT = 1 << 0,
@@ -340,13 +323,13 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
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();
+ void RequestDisallowInterceptTouchEvent();
// The model object.
RenderWidgetHostImpl* host_;
+ bool use_surfaces_;
+
// Used to control action dispatch at the next |OnVSync()| call.
uint32 outstanding_vsync_requests_;
@@ -355,6 +338,13 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
// ContentViewCoreImpl is our interface to the view system.
ContentViewCoreImpl* content_view_core_;
+ // Cache the WindowAndroid instance exposed by ContentViewCore to avoid
+ // calling into ContentViewCore when it is being detached from the
+ // WebContents during destruction. The WindowAndroid has stronger lifetime
+ // guarantees, and should be safe to use for observer detachment.
+ // This will be non-null iff |content_view_core_| is non-null.
+ ui::WindowAndroid* content_view_core_window_android_;
+
ImeAdapterAndroid ime_adapter_android_;
// Body background color of the underlying document.
@@ -362,7 +352,13 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
scoped_refptr<cc::DelegatedFrameResourceCollection> resource_collection_;
scoped_refptr<cc::DelegatedFrameProvider> frame_provider_;
- scoped_refptr<cc::DelegatedRendererLayer> layer_;
+ scoped_refptr<cc::Layer> layer_;
+
+ 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_;
// The most recent texture size that was pushed to the texture layer.
gfx::Size texture_size_in_layer_;
@@ -376,27 +372,26 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
std::queue<base::Closure> ack_callbacks_;
- const bool overscroll_effect_enabled_;
- // Used to render overscroll overlays.
- scoped_ptr<OverscrollGlow> overscroll_effect_;
+ // Used to control and render overscroll-related effects.
+ scoped_ptr<OverscrollControllerAndroid> overscroll_controller_;
// Provides gesture synthesis given a stream of touch events (derived from
// Android MotionEvent's) and touch event acks.
ui::FilteredGestureProvider gesture_provider_;
// Handles gesture based text selection
- GestureTextSelector gesture_text_selector_;
+ StylusTextSelector stylus_text_selector_;
// Manages selection handle rendering and manipulation.
// This will always be NULL if |content_view_core_| is NULL.
- scoped_ptr<TouchSelectionController> selection_controller_;
+ scoped_ptr<ui::TouchSelectionController> selection_controller_;
int accelerated_surface_route_id_;
// Size to use if we have no backing ContentViewCore
gfx::Size default_size_;
- const bool using_synchronous_compositor_;
+ const bool using_browser_compositor_;
scoped_ptr<DelegatedFrameEvictor> frame_evictor_;
@@ -415,9 +410,6 @@ 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_;
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 074a309e045..867d80cc497 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
@@ -4,15 +4,17 @@
#include "content/browser/renderer_host/render_widget_host_view_aura.h"
+#include <set>
+
#include "base/auto_reset.h"
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/command_line.h"
-#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/string_number_conversions.h"
+#include "base/trace_event/trace_event.h"
#include "cc/layers/layer.h"
#include "cc/output/copy_output_request.h"
#include "cc/output/copy_output_result.h"
@@ -20,6 +22,7 @@
#include "cc/trees/layer_tree_settings.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/browser/accessibility/browser_accessibility_state_impl.h"
+#include "content/browser/bad_message.h"
#include "content/browser/frame_host/frame_tree.h"
#include "content/browser/frame_host/frame_tree_node.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
@@ -27,6 +30,7 @@
#include "content/browser/renderer_host/compositor_resize_lock_aura.h"
#include "content/browser/renderer_host/dip_util.h"
#include "content/browser/renderer_host/input/synthetic_gesture_target_aura.h"
+#include "content/browser/renderer_host/input/web_input_event_util.h"
#include "content/browser/renderer_host/overscroll_controller.h"
#include "content/browser/renderer_host/render_view_host_delegate.h"
#include "content/browser/renderer_host/render_view_host_delegate_view.h"
@@ -64,14 +68,15 @@
#include "ui/base/ui_base_types.h"
#include "ui/compositor/compositor_vsync_manager.h"
#include "ui/compositor/dip_util.h"
+#include "ui/events/blink/blink_event_util.h"
#include "ui/events/event.h"
#include "ui/events/event_utils.h"
#include "ui/events/gestures/gesture_recognizer.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/display.h"
-#include "ui/gfx/rect_conversions.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/screen.h"
-#include "ui/gfx/size_conversions.h"
#include "ui/gfx/skia_util.h"
#include "ui/wm/public/activation_client.h"
#include "ui/wm/public/scoped_tooltip_disabler.h"
@@ -230,64 +235,6 @@ BOOL CALLBACK DismissOwnedPopups(HWND window, LPARAM arg) {
}
#endif
-void UpdateWebTouchEventAfterDispatch(blink::WebTouchEvent* event,
- blink::WebTouchPoint* point) {
- if (point->state != blink::WebTouchPoint::StateReleased &&
- point->state != blink::WebTouchPoint::StateCancelled)
- return;
-
- 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) {
- if (event->type() == ui::ET_MOUSE_CAPTURE_CHANGED)
- return false;
-
-#if defined(OS_WIN)
- // Renderer cannot handle WM_XBUTTON or NC events.
- switch (event->native_event().message) {
- case WM_XBUTTONDOWN:
- case WM_XBUTTONUP:
- case WM_XBUTTONDBLCLK:
- case WM_NCMOUSELEAVE:
- case WM_NCMOUSEMOVE:
- case WM_NCLBUTTONDOWN:
- case WM_NCLBUTTONUP:
- case WM_NCLBUTTONDBLCLK:
- case WM_NCRBUTTONDOWN:
- case WM_NCRBUTTONUP:
- case WM_NCRBUTTONDBLCLK:
- case WM_NCMBUTTONDOWN:
- case WM_NCMBUTTONUP:
- case WM_NCMBUTTONDBLCLK:
- case WM_NCXBUTTONDOWN:
- case WM_NCXBUTTONUP:
- case WM_NCXBUTTONDBLCLK:
- return false;
- default:
- break;
- }
-#elif defined(USE_X11)
- // Renderer only supports standard mouse buttons, so ignore programmable
- // buttons.
- switch (event->type()) {
- case ui::ET_MOUSE_PRESSED:
- case ui::ET_MOUSE_RELEASED:
- return event->IsAnyButton();
- default:
- break;
- }
-#endif
- return true;
-}
-
// We don't mark these as handled so that they're sent back to the
// DefWindowProc so it can generate WM_APPCOMMAND as necessary.
bool IsXButtonUpEvent(const ui::MouseEvent* event) {
@@ -326,17 +273,22 @@ void GetScreenInfoForWindow(WebScreenInfo* results, aura::Window* window) {
RenderWidgetHostViewBase::GetOrientationTypeForDesktop(display);
}
-bool PointerEventActivates(const ui::Event& event) {
- if (event.type() == ui::ET_MOUSE_PRESSED)
- return true;
+bool IsFractionalScaleFactor(float scale_factor) {
+ return (scale_factor - static_cast<int>(scale_factor)) > 0;
+}
- if (event.type() == ui::ET_GESTURE_BEGIN) {
- const ui::GestureEvent& gesture =
- static_cast<const ui::GestureEvent&>(event);
- return gesture.details().touch_points() == 1;
+// Reset unchanged touch point to StateStationary for touchmove and
+// touchcancel.
+void MarkUnchangedTouchPointsAsStationary(
+ blink::WebTouchEvent* event,
+ int changed_touch_id) {
+ if (event->type == blink::WebInputEvent::TouchMove ||
+ event->type == blink::WebInputEvent::TouchCancel) {
+ for (size_t i = 0; i < event->touchesLength; ++i) {
+ if (event->touches[i].id != changed_touch_id)
+ event->touches[i].state = blink::WebTouchPoint::StateStationary;
+ }
}
-
- return false;
}
} // namespace
@@ -385,6 +337,12 @@ void RenderWidgetHostViewAura::ApplyEventFilterForPopupExit(
if (target != window_ &&
(!popup_parent_host_view_ ||
target != popup_parent_host_view_->window_)) {
+ // If we enter this code path it means that we did not receive any focus
+ // lost notifications for the popup window. Ensure that blink is aware
+ // of the fact that focus was lost for the host window by sending a Blur
+ // notification.
+ if (popup_parent_host_view_ && popup_parent_host_view_->host_)
+ popup_parent_host_view_->host_->Blur();
// Note: popup_parent_host_view_ may be NULL when there are multiple
// popup children per view. See: RenderWidgetHostViewAura::InitAsPopup().
Shutdown();
@@ -416,12 +374,64 @@ class RenderWidgetHostViewAura::WindowObserver : public aura::WindowObserver {
view_->RemovingFromRootWindow();
}
+ void OnWindowHierarchyChanged(const HierarchyChangeParams& params) override {
+ view_->ParentHierarchyChanged();
+ }
+
private:
RenderWidgetHostViewAura* view_;
DISALLOW_COPY_AND_ASSIGN(WindowObserver);
};
+// This class provides functionality to observe the ancestors of the RWHVA for
+// bounds changes. This is done to snap the RWHVA window to a pixel boundary,
+// which could change when the bounds relative to the root changes.
+// An example where this happens is below:-
+// The fast resize code path for bookmarks where in the parent of RWHVA which
+// is WCV has its bounds changed before the bookmark is hidden. This results in
+// the traditional bounds change notification for the WCV reporting the old
+// bounds as the bookmark is still around. Observing all the ancestors of the
+// RWHVA window enables us to know when the bounds of the window relative to
+// root changes and allows us to snap accordingly.
+class RenderWidgetHostViewAura::WindowAncestorObserver
+ : public aura::WindowObserver {
+ public:
+ explicit WindowAncestorObserver(RenderWidgetHostViewAura* view)
+ : view_(view) {
+ aura::Window* parent = view_->window_->parent();
+ while (parent) {
+ parent->AddObserver(this);
+ ancestors_.insert(parent);
+ parent = parent->parent();
+ }
+ }
+
+ ~WindowAncestorObserver() override {
+ RemoveAncestorObservers();
+ }
+
+ void OnWindowBoundsChanged(aura::Window* window,
+ const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds) override {
+ DCHECK(ancestors_.find(window) != ancestors_.end());
+ if (new_bounds.origin() != old_bounds.origin())
+ view_->HandleParentBoundsChanged();
+ }
+
+ private:
+ void RemoveAncestorObservers() {
+ for (auto ancestor : ancestors_)
+ ancestor->RemoveObserver(this);
+ ancestors_.clear();
+ }
+
+ RenderWidgetHostViewAura* view_;
+ std::set<aura::Window*> ancestors_;
+
+ DISALLOW_COPY_AND_ASSIGN(WindowAncestorObserver);
+};
+
////////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewAura, public:
@@ -448,6 +458,8 @@ RenderWidgetHostViewAura::RenderWidgetHostViewAura(RenderWidgetHost* host,
cursor_visibility_state_in_renderer_(UNKNOWN),
#if defined(OS_WIN)
legacy_render_widget_host_HWND_(NULL),
+ legacy_window_destroyed_(false),
+ showing_context_menu_(false),
#endif
has_snapped_to_boundary_(false),
touch_editing_client_(NULL),
@@ -457,9 +469,9 @@ RenderWidgetHostViewAura::RenderWidgetHostViewAura(RenderWidgetHost* host,
host_->SetView(this);
window_observer_.reset(new WindowObserver(this));
+
aura::client::SetTooltipText(window_, &tooltip_);
aura::client::SetActivationDelegate(window_, this);
- aura::client::SetActivationChangeObserver(window_, this);
aura::client::SetFocusChangeObserver(window_, this);
window_->set_layer_owner_delegate(delegated_frame_host_.get());
gfx::Screen::GetScreenFor(window_)->AddObserver(this);
@@ -489,7 +501,7 @@ bool RenderWidgetHostViewAura::OnMessageReceived(
void RenderWidgetHostViewAura::InitAsChild(
gfx::NativeView parent_view) {
window_->SetType(ui::wm::WINDOW_TYPE_CONTROL);
- window_->Init(aura::WINDOW_LAYER_SOLID_COLOR);
+ window_->Init(ui::LAYER_SOLID_COLOR);
window_->SetName("RenderWidgetHostViewAura");
window_->layer()->SetColor(background_color_);
}
@@ -518,7 +530,7 @@ void RenderWidgetHostViewAura::InitAsPopup(
}
popup_parent_host_view_->popup_child_host_view_ = this;
window_->SetType(ui::wm::WINDOW_TYPE_MENU);
- window_->Init(aura::WINDOW_LAYER_SOLID_COLOR);
+ window_->Init(ui::LAYER_SOLID_COLOR);
window_->SetName("RenderWidgetHostViewAura");
window_->layer()->SetColor(background_color_);
@@ -546,7 +558,7 @@ void RenderWidgetHostViewAura::InitAsFullscreen(
RenderWidgetHostView* reference_host_view) {
is_fullscreen_ = true;
window_->SetType(ui::wm::WINDOW_TYPE_NORMAL);
- window_->Init(aura::WINDOW_LAYER_SOLID_COLOR);
+ window_->Init(ui::LAYER_SOLID_COLOR);
window_->SetName("RenderWidgetHostViewAura");
window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
window_->layer()->SetColor(background_color_);
@@ -574,7 +586,9 @@ RenderWidgetHost* RenderWidgetHostViewAura::GetRenderWidgetHost() const {
return host_;
}
-void RenderWidgetHostViewAura::WasShown() {
+void RenderWidgetHostViewAura::Show() {
+ window_->Show();
+
DCHECK(host_);
if (!host_->is_hidden())
return;
@@ -601,25 +615,49 @@ void RenderWidgetHostViewAura::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);
+
+ if (legacy_render_widget_host_HWND_)
+ legacy_render_widget_host_HWND_->Show();
#endif
}
-void RenderWidgetHostViewAura::WasHidden() {
- if (!host_ || host_->is_hidden())
- return;
- host_->WasHidden();
- delegated_frame_host_->WasHidden();
+void RenderWidgetHostViewAura::Hide() {
+ window_->Hide();
+
+ if (host_ && !host_->is_hidden()) {
+ host_->WasHidden();
+ delegated_frame_host_->WasHidden();
#if defined(OS_WIN)
- constrained_rects_.clear();
- aura::WindowTreeHost* host = window_->GetHost();
- if (host) {
- HWND parent = host->GetAcceleratedWidget();
- LPARAM lparam = reinterpret_cast<LPARAM>(this);
- EnumChildWindows(parent, HideWindowsCallback, lparam);
+ constrained_rects_.clear();
+ aura::WindowTreeHost* host = window_->GetHost();
+ if (host) {
+ HWND parent = host->GetAcceleratedWidget();
+ LPARAM lparam = reinterpret_cast<LPARAM>(this);
+ EnumChildWindows(parent, HideWindowsCallback, lparam);
+ // We reparent the legacy Chrome_RenderWidgetHostHWND window to the global
+ // hidden window on the same lines as Windowed plugin windows.
+ if (legacy_render_widget_host_HWND_)
+ legacy_render_widget_host_HWND_->UpdateParent(ui::GetHiddenWindow());
+ }
+#endif
}
+
+#if defined(OS_WIN)
+ if (legacy_render_widget_host_HWND_)
+ legacy_render_widget_host_HWND_->Hide();
#endif
}
@@ -670,7 +708,6 @@ gfx::NativeViewAccessible RenderWidgetHostViewAura::GetNativeViewAccessible() {
aura::WindowTreeHost* host = window_->GetHost();
if (!host)
return static_cast<gfx::NativeViewAccessible>(NULL);
- HWND hwnd = host->GetAcceleratedWidget();
BrowserAccessibilityManager* manager =
host_->GetOrCreateRootBrowserAccessibilityManager();
if (manager)
@@ -707,6 +744,87 @@ RenderFrameHostImpl* RenderWidgetHostViewAura::GetFocusedFrame() {
return focused_frame->current_frame_host();
}
+bool RenderWidgetHostViewAura::CanRendererHandleEvent(
+ const ui::MouseEvent* event,
+ bool mouse_locked,
+ bool selection_popup) {
+#if defined(OS_WIN)
+ bool showing_context_menu = showing_context_menu_;
+ showing_context_menu_ = false;
+#endif
+
+ if (event->type() == ui::ET_MOUSE_CAPTURE_CHANGED)
+ return false;
+
+ if ((mouse_locked || selection_popup) &&
+ (event->type() == ui::ET_MOUSE_EXITED))
+ return false;
+
+#if defined(OS_WIN)
+ // Don't forward the mouse leave message which is received when the context
+ // menu is displayed by the page. This confuses the page and causes state
+ // changes.
+ if (showing_context_menu) {
+ if (event->type() == ui::ET_MOUSE_EXITED)
+ return false;
+ }
+ // Renderer cannot handle WM_XBUTTON or NC events.
+ switch (event->native_event().message) {
+ case WM_XBUTTONDOWN:
+ case WM_XBUTTONUP:
+ case WM_XBUTTONDBLCLK:
+ case WM_NCMOUSELEAVE:
+ case WM_NCMOUSEMOVE:
+ case WM_NCLBUTTONDOWN:
+ case WM_NCLBUTTONUP:
+ case WM_NCLBUTTONDBLCLK:
+ case WM_NCRBUTTONDOWN:
+ case WM_NCRBUTTONUP:
+ case WM_NCRBUTTONDBLCLK:
+ case WM_NCMBUTTONDOWN:
+ case WM_NCMBUTTONUP:
+ case WM_NCMBUTTONDBLCLK:
+ case WM_NCXBUTTONDOWN:
+ case WM_NCXBUTTONUP:
+ case WM_NCXBUTTONDBLCLK:
+ return false;
+ default:
+ break;
+ }
+#elif defined(USE_X11)
+ // Renderer only supports standard mouse buttons, so ignore programmable
+ // buttons.
+ switch (event->type()) {
+ case ui::ET_MOUSE_PRESSED:
+ case ui::ET_MOUSE_RELEASED: {
+ const int kAllowedButtons = ui::EF_LEFT_MOUSE_BUTTON |
+ ui::EF_MIDDLE_MOUSE_BUTTON |
+ ui::EF_RIGHT_MOUSE_BUTTON;
+ return (event->flags() & kAllowedButtons) != 0;
+ }
+ default:
+ break;
+ }
+#endif
+ return true;
+}
+
+void RenderWidgetHostViewAura::HandleParentBoundsChanged() {
+ SnapToPhysicalPixelBoundary();
+#if defined(OS_WIN)
+ if (legacy_render_widget_host_HWND_) {
+ legacy_render_widget_host_HWND_->SetBounds(
+ window_->GetBoundsInRootWindow());
+ }
+#endif
+}
+
+void RenderWidgetHostViewAura::ParentHierarchyChanged() {
+ ancestor_window_observer_.reset(new WindowAncestorObserver(this));
+ // Snap when we receive a hierarchy changed. http://crbug.com/388908.
+ HandleParentBoundsChanged();
+}
+
void RenderWidgetHostViewAura::MovePluginWindows(
const std::vector<WebPluginGeometry>& plugin_window_moves) {
#if defined(OS_WIN)
@@ -768,10 +886,6 @@ void RenderWidgetHostViewAura::Focus() {
window_->Focus();
}
-void RenderWidgetHostViewAura::Blur() {
- window_->Blur();
-}
-
bool RenderWidgetHostViewAura::HasFocus() const {
return window_->HasFocus();
}
@@ -780,16 +894,6 @@ bool RenderWidgetHostViewAura::IsSurfaceAvailableForCopy() const {
return delegated_frame_host_->CanCopyToBitmap();
}
-void RenderWidgetHostViewAura::Show() {
- window_->Show();
- WasShown();
-}
-
-void RenderWidgetHostViewAura::Hide() {
- window_->Hide();
- WasHidden();
-}
-
bool RenderWidgetHostViewAura::IsShowing() {
return window_->IsVisible();
}
@@ -929,29 +1033,56 @@ gfx::Size RenderWidgetHostViewAura::GetRequestedRendererSize() const {
void RenderWidgetHostViewAura::SelectionBoundsChanged(
const ViewHostMsg_SelectionBounds_Params& params) {
- if (selection_anchor_rect_ == params.anchor_rect &&
- selection_focus_rect_ == params.focus_rect)
- return;
+ ui::SelectionBound anchor_bound, focus_bound;
+ anchor_bound.SetEdge(params.anchor_rect.origin(),
+ params.anchor_rect.bottom_left());
+ focus_bound.SetEdge(params.focus_rect.origin(),
+ params.focus_rect.bottom_left());
+
+ if (params.anchor_rect == params.focus_rect) {
+ anchor_bound.set_type(ui::SelectionBound::CENTER);
+ focus_bound.set_type(ui::SelectionBound::CENTER);
+ } else {
+ // Whether text is LTR at the anchor handle.
+ bool anchor_LTR = params.anchor_dir == blink::WebTextDirectionLeftToRight;
+ // Whether text is LTR at the focus handle.
+ bool focus_LTR = params.focus_dir == blink::WebTextDirectionLeftToRight;
+
+ if ((params.is_anchor_first && anchor_LTR) ||
+ (!params.is_anchor_first && !anchor_LTR)) {
+ anchor_bound.set_type(ui::SelectionBound::LEFT);
+ } else {
+ anchor_bound.set_type(ui::SelectionBound::RIGHT);
+ }
+ if ((params.is_anchor_first && focus_LTR) ||
+ (!params.is_anchor_first && !focus_LTR)) {
+ focus_bound.set_type(ui::SelectionBound::RIGHT);
+ } else {
+ focus_bound.set_type(ui::SelectionBound::LEFT);
+ }
+ }
- selection_anchor_rect_ = params.anchor_rect;
- selection_focus_rect_ = params.focus_rect;
+ if (anchor_bound == selection_anchor_ && focus_bound == selection_focus_)
+ return;
+ selection_anchor_ = anchor_bound;
+ selection_focus_ = focus_bound;
if (GetInputMethod())
GetInputMethod()->OnCaretBoundsChanged(this);
if (touch_editing_client_) {
- touch_editing_client_->OnSelectionOrCursorChanged(selection_anchor_rect_,
- selection_focus_rect_);
+ touch_editing_client_->OnSelectionOrCursorChanged(
+ anchor_bound, focus_bound);
}
}
void RenderWidgetHostViewAura::CopyFromCompositingSurface(
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
- CopyFromCompositingSurfaceCallback& callback,
- const SkColorType color_type) {
+ ReadbackRequestCallback& callback,
+ const SkColorType preferred_color_type) {
delegated_frame_host_->CopyFromCompositingSurface(
- src_subrect, dst_size, callback, color_type);
+ src_subrect, dst_size, callback, preferred_color_type);
}
void RenderWidgetHostViewAura::CopyFromCompositingSurfaceToVideoFrame(
@@ -1008,11 +1139,17 @@ void RenderWidgetHostViewAura::UpdateConstrainedWindowRects(
void RenderWidgetHostViewAura::UpdateMouseLockRegion() {
// Clip the cursor if chrome is running on regular desktop.
if (gfx::Screen::GetScreenFor(window_) == gfx::Screen::GetNativeScreen()) {
- RECT window_rect = window_->GetBoundsInScreen().ToRECT();
+ RECT window_rect =
+ gfx::win::DIPToScreenRect(window_->GetBoundsInScreen()).ToRECT();
::ClipCursor(&window_rect);
}
}
-#endif // defined(OS_WIN)
+
+void RenderWidgetHostViewAura::OnLegacyWindowDestroyed() {
+ legacy_render_widget_host_HWND_ = NULL;
+ legacy_window_destroyed_ = true;
+}
+#endif
void RenderWidgetHostViewAura::OnSwapCompositorFrame(
uint32 output_surface_id,
@@ -1031,9 +1168,8 @@ void RenderWidgetHostViewAura::OnSwapCompositorFrame(
if (frame->software_frame_data) {
DLOG(ERROR) << "Unable to use software frame in aura";
- RecordAction(
- base::UserMetricsAction("BadMessageTerminate_SharedMemoryAura"));
- host_->GetProcess()->ReceivedBadMessage();
+ bad_message::ReceivedBadMessage(host_->GetProcess(),
+ bad_message::RWHVA_SHARED_MEMORY);
return;
}
}
@@ -1044,11 +1180,6 @@ void RenderWidgetHostViewAura::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) {
}
@@ -1056,9 +1187,8 @@ void RenderWidgetHostViewAura::SetParentNativeViewAccessible(
gfx::NativeViewId RenderWidgetHostViewAura::GetParentForWindowlessPlugin()
const {
if (legacy_render_widget_host_HWND_) {
- HWND hwnd = legacy_render_widget_host_HWND_->hwnd();
- if (::IsWindow(hwnd))
- return reinterpret_cast<gfx::NativeViewId>(hwnd);
+ return reinterpret_cast<gfx::NativeViewId>(
+ legacy_render_widget_host_HWND_->hwnd());
}
return NULL;
}
@@ -1136,22 +1266,46 @@ void RenderWidgetHostViewAura::GestureEventAck(
}
void RenderWidgetHostViewAura::ProcessAckedTouchEvent(
- const TouchEventWithLatencyInfo& touch, InputEventAckState ack_result) {
+ const TouchEventWithLatencyInfo& touch,
+ InputEventAckState ack_result) {
ScopedVector<ui::TouchEvent> events;
- if (!MakeUITouchEventsFromWebTouchEvents(touch, &events,
- SCREEN_COORDINATES))
- return;
-
aura::WindowTreeHost* host = window_->GetHost();
// |host| is NULL during tests.
if (!host)
return;
- ui::EventResult result = (ack_result ==
- 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) {
- host->dispatcher()->ProcessedTouchEvent((*iter), window_, result);
+ ui::EventResult result = (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED)
+ ? ui::ER_HANDLED
+ : ui::ER_UNHANDLED;
+
+ blink::WebTouchPoint::State required_state;
+ switch (touch.event.type) {
+ case blink::WebInputEvent::TouchStart:
+ required_state = blink::WebTouchPoint::StatePressed;
+ break;
+ case blink::WebInputEvent::TouchEnd:
+ required_state = blink::WebTouchPoint::StateReleased;
+ break;
+ case blink::WebInputEvent::TouchMove:
+ required_state = blink::WebTouchPoint::StateMoved;
+ break;
+ case blink::WebInputEvent::TouchCancel:
+ required_state = blink::WebTouchPoint::StateCancelled;
+ break;
+ default:
+ required_state = blink::WebTouchPoint::StateUndefined;
+ NOTREACHED();
+ break;
+ }
+
+ // Only send acks for one changed touch point.
+ bool sent_ack = false;
+ for (size_t i = 0; i < touch.event.touchesLength; ++i) {
+ if (touch.event.touches[i].state == required_state) {
+ DCHECK(!sent_ack);
+ host->dispatcher()->ProcessedTouchEvent(window_, result);
+ sent_ack = true;
+ }
}
}
@@ -1179,9 +1333,19 @@ InputEventAckState RenderWidgetHostViewAura::FilterInputEvent(
if (overscroll_controller_)
consumed |= overscroll_controller_->WillHandleEvent(input_event);
- return consumed && !WebTouchEvent::isTouchEventType(input_event.type)
- ? INPUT_EVENT_ACK_STATE_CONSUMED
- : INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
+ // Touch events should always propagate to the renderer.
+ if (WebTouchEvent::isTouchEventType(input_event.type))
+ return INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
+
+ // Reporting consumed for a fling suggests that there's now an *active* fling
+ // that requires both animation and a fling-end notification. However, the
+ // OverscrollController consumes a fling to stop its propagation; it doesn't
+ // actually tick a fling animation. Report no consumer to convey this.
+ if (consumed && input_event.type == blink::WebInputEvent::GestureFlingStart)
+ return INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS;
+
+ return consumed ? INPUT_EVENT_ACK_STATE_CONSUMED
+ : INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
}
BrowserAccessibilityManager*
@@ -1201,11 +1365,8 @@ RenderWidgetHostViewAura::CreateBrowserAccessibilityManager(
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;
- }
+ if (legacy_render_widget_host_HWND_)
+ return legacy_render_widget_host_HWND_->hwnd();
#endif
return gfx::kNullAcceleratedWidget;
}
@@ -1227,6 +1388,14 @@ gfx::GLSurfaceHandle RenderWidgetHostViewAura::GetCompositingSurface() {
void RenderWidgetHostViewAura::ShowDisambiguationPopup(
const gfx::Rect& rect_pixels,
const SkBitmap& zoomed_bitmap) {
+ RenderViewHostDelegate* delegate = NULL;
+ if (host_->IsRenderView())
+ delegate = RenderViewHost::From(host_)->GetDelegate();
+ // Suppress the link disambiguation popup if the virtual keyboard is currently
+ // requested, as it doesn't interact well with the keyboard.
+ if (delegate && delegate->IsVirtualKeyboardRequested())
+ return;
+
// |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);
@@ -1246,35 +1415,36 @@ void RenderWidgetHostViewAura::ShowDisambiguationPopup(
disambiguation_target_rect_,
zoomed_size,
base::Bind(&RenderWidgetHostViewAura::DisambiguationPopupRendered,
- base::internal::SupportsWeakPtrBase::StaticAsWeakPtr
- <RenderWidgetHostViewAura>(this)),
- kN32_SkColorType);
+ weak_ptr_factory_.GetWeakPtr()),
+ kN32_SkColorType);
}
void RenderWidgetHostViewAura::DisambiguationPopupRendered(
- bool success,
- const SkBitmap& result) {
- if (!success || disambiguation_scroll_offset_ != last_scroll_offset_)
+ const SkBitmap& result,
+ ReadbackResponse response) {
+ if ((response != READBACK_SUCCESS) ||
+ disambiguation_scroll_offset_ != last_scroll_offset_)
return;
// Use RenderViewHostDelegate to get to the WebContentsViewAura, which will
- // actually show the delegate.
+ // actually show the disambiguation popup.
RenderViewHostDelegate* delegate = NULL;
if (host_->IsRenderView())
delegate = RenderViewHost::From(host_)->GetDelegate();
RenderViewHostDelegateView* delegate_view = NULL;
- if (delegate)
+ if (delegate) {
delegate_view = delegate->GetDelegateView();
+ if (delegate->IsVirtualKeyboardRequested())
+ return;
+ }
if (delegate_view) {
delegate_view->ShowDisambiguationPopup(
disambiguation_target_rect_,
result,
base::Bind(&RenderWidgetHostViewAura::ProcessDisambiguationGesture,
- base::internal::SupportsWeakPtrBase::StaticAsWeakPtr
- <RenderWidgetHostViewAura>(this)),
+ weak_ptr_factory_.GetWeakPtr()),
base::Bind(&RenderWidgetHostViewAura::ProcessDisambiguationMouse,
- base::internal::SupportsWeakPtrBase::StaticAsWeakPtr
- <RenderWidgetHostViewAura>(this)));
+ weak_ptr_factory_.GetWeakPtr()));
}
}
@@ -1291,7 +1461,7 @@ void RenderWidgetHostViewAura::HideDisambiguationPopup() {
void RenderWidgetHostViewAura::ProcessDisambiguationGesture(
ui::GestureEvent* event) {
- blink::WebGestureEvent web_gesture = content::MakeWebGestureEvent(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 ||
@@ -1303,7 +1473,7 @@ void RenderWidgetHostViewAura::ProcessDisambiguationGesture(
void RenderWidgetHostViewAura::ProcessDisambiguationMouse(
ui::MouseEvent* event) {
- blink::WebMouseEvent web_mouse = content::MakeWebMouseEvent(event);
+ blink::WebMouseEvent web_mouse = content::MakeWebMouseEvent(*event);
host_->ForwardMouseEvent(web_mouse);
}
@@ -1493,8 +1663,8 @@ gfx::Rect RenderWidgetHostViewAura::ConvertRectFromScreen(
}
gfx::Rect RenderWidgetHostViewAura::GetCaretBounds() const {
- const gfx::Rect rect =
- gfx::UnionRects(selection_anchor_rect_, selection_focus_rect_);
+ gfx::Rect rect =
+ ui::RectBetweenSelectionBounds(selection_anchor_, selection_focus_);
return ConvertRectToScreen(rect);
}
@@ -1617,11 +1787,11 @@ void RenderWidgetHostViewAura::OnCandidateWindowHidden() {
host_->CandidateWindowHidden();
}
-bool RenderWidgetHostViewAura::IsEditingCommandEnabled(int command_id) {
+bool RenderWidgetHostViewAura::IsEditCommandEnabled(int command_id) {
return false;
}
-void RenderWidgetHostViewAura::ExecuteEditingCommand(int command_id) {
+void RenderWidgetHostViewAura::SetEditCommandForNextKeyEvent(int command_id) {
}
////////////////////////////////////////////////////////////////////////////////
@@ -1671,6 +1841,10 @@ void RenderWidgetHostViewAura::OnBoundsChanged(const gfx::Rect& old_bounds,
GetInputMethod()->OnCaretBoundsChanged(this);
}
+ui::TextInputClient* RenderWidgetHostViewAura::GetFocusedTextInputClient() {
+ return GetTextInputClient();
+}
+
gfx::NativeCursor RenderWidgetHostViewAura::GetCursor(const gfx::Point& point) {
if (mouse_locked_)
return ui::kCursorNone;
@@ -1698,7 +1872,7 @@ void RenderWidgetHostViewAura::OnCaptureLost() {
touch_editing_client_->EndTouchEditing(false);
}
-void RenderWidgetHostViewAura::OnPaint(gfx::Canvas* canvas) {
+void RenderWidgetHostViewAura::OnPaint(const ui::PaintContext& context) {
NOTREACHED();
}
@@ -1728,7 +1902,20 @@ void RenderWidgetHostViewAura::OnWindowDestroying(aura::Window* window) {
}
LPARAM lparam = reinterpret_cast<LPARAM>(this);
EnumChildWindows(parent, WindowDestroyingCallback, lparam);
- legacy_render_widget_host_HWND_ = NULL;
+
+ // The LegacyRenderWidgetHostHWND instance is destroyed when its window is
+ // destroyed. Normally we control when that happens via the Destroy call
+ // in the dtor. However there may be cases where the window is destroyed
+ // by Windows, i.e. the parent window is destroyed before the
+ // RenderWidgetHostViewAura instance goes away etc. To avoid that we
+ // destroy the LegacyRenderWidgetHostHWND instance here.
+ if (legacy_render_widget_host_HWND_) {
+ legacy_render_widget_host_HWND_->set_host(NULL);
+ legacy_render_widget_host_HWND_->Destroy();
+ // The Destroy call above will delete the LegacyRenderWidgetHostHWND
+ // instance.
+ legacy_render_widget_host_HWND_ = NULL;
+ }
#endif
// Make sure that the input method no longer references to this object before
@@ -1804,18 +1991,8 @@ void RenderWidgetHostViewAura::OnKeyEvent(ui::KeyEvent* event) {
}
// We don't have to communicate with an input method here.
- if (!event->HasNativeEvent()) {
- NativeWebKeyboardEvent webkit_event(
- event->type(),
- event->is_char(),
- event->is_char() ? event->GetCharacter() : event->key_code(),
- event->flags(),
- ui::EventTimeForNow().InSecondsF());
- ForwardKeyboardEvent(webkit_event);
- } else {
- NativeWebKeyboardEvent webkit_event(event);
- ForwardKeyboardEvent(webkit_event);
- }
+ NativeWebKeyboardEvent webkit_event(*event);
+ ForwardKeyboardEvent(webkit_event);
}
event->SetHandled();
}
@@ -1833,7 +2010,7 @@ void RenderWidgetHostViewAura::OnMouseEvent(ui::MouseEvent* event) {
if (event->type() == ui::ET_MOUSEWHEEL) {
blink::WebMouseWheelEvent mouse_wheel_event =
- MakeWebMouseWheelEvent(static_cast<ui::MouseWheelEvent*>(event));
+ MakeWebMouseWheelEvent(static_cast<ui::MouseWheelEvent&>(*event));
if (mouse_wheel_event.deltaX != 0 || mouse_wheel_event.deltaY != 0)
host_->ForwardWheelEvent(mouse_wheel_event);
return;
@@ -1850,12 +2027,31 @@ void RenderWidgetHostViewAura::OnMouseEvent(ui::MouseEvent* event) {
return;
}
- blink::WebMouseEvent mouse_event = MakeWebMouseEvent(event);
+ blink::WebMouseEvent mouse_event = MakeWebMouseEvent(*event);
bool is_move_to_center_event = (event->type() == ui::ET_MOUSE_MOVED ||
event->type() == ui::ET_MOUSE_DRAGGED) &&
mouse_event.x == center.x() && mouse_event.y == center.y();
+ // For fractional scale factors, the conversion from pixels to dip and
+ // vice versa could result in off by 1 or 2 errors which hurts us because
+ // we want to avoid sending the artificial move to center event to the
+ // renderer. Sending the move to center to the renderer cause the cursor
+ // to bounce around the center of the screen leading to the lock operation
+ // not working correctly.
+ // Workaround is to treat a mouse move or drag event off by at most 2 px
+ // from the center as a move to center event.
+ if (synthetic_move_sent_ &&
+ IsFractionalScaleFactor(current_device_scale_factor_)) {
+ if (event->type() == ui::ET_MOUSE_MOVED ||
+ event->type() == ui::ET_MOUSE_DRAGGED) {
+ if ((abs(mouse_event.x - center.x()) <= 2) &&
+ (abs(mouse_event.y - center.y()) <= 2)) {
+ is_move_to_center_event = true;
+ }
+ }
+ }
+
ModifyEventMovementAndCoords(&mouse_event);
bool should_not_forward = is_move_to_center_event && synthetic_move_sent_;
@@ -1867,8 +2063,10 @@ void RenderWidgetHostViewAura::OnMouseEvent(ui::MouseEvent* event) {
synthetic_move_sent_ = true;
window_->MoveCursorTo(center);
}
+ bool is_selection_popup = popup_child_host_view_ &&
+ popup_child_host_view_->NeedsInputGrab();
// Forward event to renderer.
- if (CanRendererHandleEvent(event) &&
+ if (CanRendererHandleEvent(event, mouse_locked_, is_selection_popup) &&
!(event->flags() & ui::EF_FROM_TOUCH)) {
host_->ForwardMouseEvent(mouse_event);
// Ensure that we get keyboard focus on mouse down as a plugin window
@@ -1915,23 +2113,27 @@ void RenderWidgetHostViewAura::OnMouseEvent(ui::MouseEvent* event) {
HideDisambiguationPopup();
blink::WebMouseWheelEvent mouse_wheel_event =
- MakeWebMouseWheelEvent(static_cast<ui::MouseWheelEvent*>(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);
- // Ensure that we get keyboard focus on mouse down as a plugin window may
- // have grabbed keyboard focus.
- if (event->type() == ui::ET_MOUSE_PRESSED)
- SetKeyboardFocus();
+ } else {
+ bool is_selection_popup = popup_child_host_view_ &&
+ popup_child_host_view_->NeedsInputGrab();
+ if (CanRendererHandleEvent(event, mouse_locked_, is_selection_popup) &&
+ !(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);
+ // Ensure that we get keyboard focus on mouse down as a plugin window may
+ // have grabbed keyboard focus.
+ if (event->type() == ui::ET_MOUSE_PRESSED)
+ SetKeyboardFocus();
+ }
}
switch (event->type()) {
@@ -1978,13 +2180,12 @@ void RenderWidgetHostViewAura::OnScrollEvent(ui::ScrollEvent* event) {
MakeWebGestureEventFlingCancel();
host_->ForwardGestureEvent(gesture_event);
blink::WebMouseWheelEvent mouse_wheel_event =
- MakeWebMouseWheelEvent(event);
+ MakeWebMouseWheelEvent(*event);
host_->ForwardWheelEvent(mouse_wheel_event);
RecordAction(base::UserMetricsAction("TrackpadScroll"));
} else if (event->type() == ui::ET_SCROLL_FLING_START ||
event->type() == ui::ET_SCROLL_FLING_CANCEL) {
- blink::WebGestureEvent gesture_event =
- MakeWebGestureEvent(event);
+ blink::WebGestureEvent gesture_event = MakeWebGestureEvent(*event);
host_->ForwardGestureEvent(gesture_event);
if (event->type() == ui::ET_SCROLL_FLING_START)
RecordAction(base::UserMetricsAction("TrackpadScrollFling"));
@@ -1999,23 +2200,25 @@ void RenderWidgetHostViewAura::OnTouchEvent(ui::TouchEvent* event) {
return;
// Update the touch event first.
- blink::WebTouchPoint* point = UpdateWebTouchEventFromUIEvent(*event,
- &touch_event_);
-
- // Forward the touch event only if a touch point was updated, and there's a
- // touch-event handler in the page, and no other touch-event is in the queue.
- // It is important to always consume the event if there is a touch-event
- // handler in the page, or some touch-event is already in the queue, even if
- // no point has been updated, to make sure that this event does not get
- // processed by the gesture recognizer before the events in the queue.
- if (host_->ShouldForwardTouchEvent())
+ if (!pointer_state_.OnTouch(*event)) {
event->StopPropagation();
-
- if (point) {
- if (host_->ShouldForwardTouchEvent())
- host_->ForwardTouchEventWithLatencyInfo(touch_event_, *event->latency());
- UpdateWebTouchEventAfterDispatch(&touch_event_, point);
+ return;
}
+
+ blink::WebTouchEvent touch_event = ui::CreateWebTouchEventFromMotionEvent(
+ pointer_state_, event->may_cause_scrolling());
+ pointer_state_.CleanupRemovedTouchPoints(*event);
+
+ // It is important to always mark events as being handled asynchronously when
+ // they are forwarded. This ensures that the current event does not get
+ // processed by the gesture recognizer before events currently awaiting
+ // dispatch in the touch queue.
+ event->DisableSynchronousHandling();
+
+ // Set unchanged touch point to StateStationary for touchmove and
+ // touchcancel to make sure only send one ack per WebTouchEvent.
+ MarkUnchangedTouchPointsAsStationary(&touch_event, event->touch_id());
+ host_->ForwardTouchEventWithLatencyInfo(touch_event, *event->latency());
}
void RenderWidgetHostViewAura::OnGestureEvent(ui::GestureEvent* event) {
@@ -2035,16 +2238,7 @@ void RenderWidgetHostViewAura::OnGestureEvent(ui::GestureEvent* event) {
if (event->type() == ui::ET_GESTURE_TAP)
FinishImeCompositionSession();
- RenderViewHostDelegate* delegate = NULL;
- if (host_->IsRenderView())
- delegate = RenderViewHost::From(host_)->GetDelegate();
-
- if (delegate && event->type() == ui::ET_GESTURE_BEGIN &&
- event->details().touch_points() == 1) {
- delegate->HandleGestureBegin();
- }
-
- blink::WebGestureEvent gesture = MakeWebGestureEvent(event);
+ blink::WebGestureEvent gesture = MakeWebGestureEvent(*event);
if (event->type() == ui::ET_GESTURE_TAP_DOWN) {
// Webkit does not stop a fling-scroll on tap-down. So explicitly send an
// event to stop any in-progress flings.
@@ -2066,11 +2260,6 @@ void RenderWidgetHostViewAura::OnGestureEvent(ui::GestureEvent* event) {
}
}
- if (delegate && event->type() == ui::ET_GESTURE_END &&
- event->details().touch_points() == 1) {
- delegate->HandleGestureEnd();
- }
-
// If a gesture is not processed by the webpage, then WebKit processes it
// (e.g. generates synthetic mouse events).
event->SetHandled();
@@ -2090,20 +2279,6 @@ bool RenderWidgetHostViewAura::ShouldActivate() const {
}
////////////////////////////////////////////////////////////////////////////////
-// RenderWidgetHostViewAura,
-// aura::client::ActivationChangeObserver implementation:
-
-void RenderWidgetHostViewAura::OnWindowActivated(aura::Window* gained_active,
- aura::Window* lost_active) {
- DCHECK(window_ == gained_active || window_ == lost_active);
- if (window_ == gained_active) {
- const ui::Event* event = window_->GetHost()->dispatcher()->current_event();
- if (event && PointerEventActivates(*event))
- host_->OnPointerEventActivate();
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewAura, aura::client::CursorClientObserver implementation:
void RenderWidgetHostViewAura::OnCursorVisibilityChanged(bool is_visible) {
@@ -2236,6 +2411,13 @@ 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)
+ // The LegacyRenderWidgetHostHWND window should have been destroyed in
+ // RenderWidgetHostViewAura::OnWindowDestroying and the pointer should
+ // be set to NULL.
+ DCHECK(!legacy_render_widget_host_HWND_);
+#endif
}
void RenderWidgetHostViewAura::UpdateCursorIfOverSelf() {
@@ -2283,7 +2465,8 @@ void RenderWidgetHostViewAura::Shutdown() {
}
bool RenderWidgetHostViewAura::NeedsInputGrab() {
- return popup_type_ == blink::WebPopupTypeSelect;
+ return popup_type_ == blink::WebPopupTypeSelect ||
+ popup_type_ == blink::WebPopupTypePage;
}
bool RenderWidgetHostViewAura::NeedsMouseCapture() {
@@ -2376,10 +2559,13 @@ void RenderWidgetHostViewAura::SnapToPhysicalPixelBoundary() {
has_snapped_to_boundary_ = true;
}
-void RenderWidgetHostViewAura::InternalSetBounds(const gfx::Rect& rect) {
- if (HasDisplayPropertyChanged(window_))
- host_->InvalidateScreenInfo();
+void RenderWidgetHostViewAura::OnShowContextMenu() {
+#if defined(OS_WIN)
+ showing_context_menu_ = true;
+#endif
+}
+void RenderWidgetHostViewAura::InternalSetBounds(const gfx::Rect& rect) {
SnapToPhysicalPixelBoundary();
// Don't recursively call SetBounds if this bounds update is the result of
// a Window::SetBoundsInternal call.
@@ -2388,10 +2574,38 @@ void RenderWidgetHostViewAura::InternalSetBounds(const gfx::Rect& rect) {
host_->WasResized();
delegated_frame_host_->WasResized();
if (touch_editing_client_) {
- touch_editing_client_->OnSelectionOrCursorChanged(selection_anchor_rect_,
- selection_focus_rect_);
+ touch_editing_client_->OnSelectionOrCursorChanged(selection_anchor_,
+ selection_focus_);
}
#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 (!legacy_window_destroyed_ && GetNativeViewId()) {
+ if (!legacy_render_widget_host_HWND_) {
+ legacy_render_widget_host_HWND_ = LegacyRenderWidgetHostHWND::Create(
+ reinterpret_cast<HWND>(GetNativeViewId()));
+ }
+ if (legacy_render_widget_host_HWND_) {
+ legacy_render_widget_host_HWND_->set_host(this);
+ legacy_render_widget_host_HWND_->SetBounds(
+ window_->GetBoundsInRootWindow());
+ // There are cases where the parent window is created, made visible and
+ // the associated RenderWidget is also visible before the
+ // LegacyRenderWidgetHostHWND instace is created. Ensure that it is shown
+ // here.
+ if (!host_->is_hidden())
+ legacy_render_widget_host_HWND_->Show();
+ }
+ }
+
if (mouse_locked_)
UpdateMouseLockRegion();
#endif
@@ -2437,7 +2651,15 @@ void RenderWidgetHostViewAura::AddedToRootWindow() {
input_method->SetFocusedTextInputClient(this);
}
- delegated_frame_host_->AddedToWindow();
+#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_->SetCompositor(window_->GetHost()->compositor());
}
void RenderWidgetHostViewAura::RemovingFromRootWindow() {
@@ -2449,7 +2671,14 @@ void RenderWidgetHostViewAura::RemovingFromRootWindow() {
DetachFromInputMethod();
window_->GetHost()->RemoveObserver(this);
- delegated_frame_host_->RemovingFromWindow();
+ delegated_frame_host_->ResetCompositor();
+
+#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() {
@@ -2487,44 +2716,38 @@ void RenderWidgetHostViewAura::ForwardKeyboardEvent(
host_->ForwardKeyboardEvent(event);
}
-SkColorType RenderWidgetHostViewAura::PreferredReadbackFormat() {
- return kN32_SkColorType;
-}
-
////////////////////////////////////////////////////////////////////////////////
// DelegatedFrameHost, public:
-ui::Compositor* RenderWidgetHostViewAura::GetCompositor() const {
- aura::WindowTreeHost* host = window_->GetHost();
- return host ? host->compositor() : NULL;
-}
-
-ui::Layer* RenderWidgetHostViewAura::GetLayer() {
+ui::Layer* RenderWidgetHostViewAura::DelegatedFrameHostGetLayer() const {
return window_->layer();
}
-RenderWidgetHostImpl* RenderWidgetHostViewAura::GetHost() {
- return host_;
+bool RenderWidgetHostViewAura::DelegatedFrameHostIsVisible() const {
+ return !host_->is_hidden();
}
-bool RenderWidgetHostViewAura::IsVisible() {
- return IsShowing();
-}
-
-gfx::Size RenderWidgetHostViewAura::DesiredFrameSize() {
+gfx::Size RenderWidgetHostViewAura::DelegatedFrameHostDesiredSizeInDIP() const {
return window_->bounds().size();
}
-float RenderWidgetHostViewAura::CurrentDeviceScaleFactor() {
- return current_device_scale_factor_;
-}
-
-gfx::Size RenderWidgetHostViewAura::ConvertViewSizeToPixel(
- const gfx::Size& size) {
- return content::ConvertViewSizeToPixel(this, size);
+bool RenderWidgetHostViewAura::DelegatedFrameCanCreateResizeLock() const {
+#if !defined(OS_CHROMEOS)
+ // On Windows and Linux, holding pointer moves will not help throttling
+ // resizes.
+ // TODO(piman): on Windows we need to block (nested message loop?) the
+ // WM_SIZE event. On Linux we need to throttle at the WM level using
+ // _NET_WM_SYNC_REQUEST.
+ return false;
+#else
+ if (host_->auto_resize_enabled())
+ return false;
+ return true;
+#endif
}
-scoped_ptr<ResizeLock> RenderWidgetHostViewAura::CreateResizeLock(
+scoped_ptr<ResizeLock>
+RenderWidgetHostViewAura::DelegatedFrameHostCreateResizeLock(
bool defer_compositor_lock) {
gfx::Size desired_size = window_->bounds().size();
return scoped_ptr<ResizeLock>(new CompositorResizeLock(
@@ -2534,8 +2757,40 @@ scoped_ptr<ResizeLock> RenderWidgetHostViewAura::CreateResizeLock(
base::TimeDelta::FromMilliseconds(kResizeLockTimeoutMs)));
}
-DelegatedFrameHost* RenderWidgetHostViewAura::GetDelegatedFrameHost() const {
- return delegated_frame_host_.get();
+void RenderWidgetHostViewAura::DelegatedFrameHostResizeLockWasReleased() {
+ host_->WasResized();
+}
+
+void RenderWidgetHostViewAura::DelegatedFrameHostSendCompositorSwapAck(
+ int output_surface_id,
+ const cc::CompositorFrameAck& ack) {
+ host_->Send(new ViewMsg_SwapCompositorFrameAck(host_->GetRoutingID(),
+ output_surface_id, ack));
+}
+
+void RenderWidgetHostViewAura::DelegatedFrameHostSendReclaimCompositorResources(
+ int output_surface_id,
+ const cc::CompositorFrameAck& ack) {
+ host_->Send(new ViewMsg_ReclaimCompositorResources(host_->GetRoutingID(),
+ output_surface_id, ack));
+}
+
+void RenderWidgetHostViewAura::DelegatedFrameHostOnLostCompositorResources() {
+ host_->ScheduleComposite();
+}
+
+void RenderWidgetHostViewAura::DelegatedFrameHostUpdateVSyncParameters(
+ const base::TimeTicks& timebase,
+ const base::TimeDelta& interval) {
+ host_->UpdateVSyncParameters(timebase, interval);
+}
+
+void RenderWidgetHostViewAura::OnDidNavigateMainFrameToNewPage() {
+ ui::GestureRecognizer::Get()->CancelActiveTouches(window_);
+}
+
+uint32_t RenderWidgetHostViewAura::GetSurfaceIdNamespace() {
+ return delegated_frame_host_->GetSurfaceIdNamespace();
}
////////////////////////////////////////////////////////////////////////////////
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 ee70b04cac9..462cf87992a 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
@@ -29,10 +29,12 @@
#include "ui/aura/window_delegate.h"
#include "ui/aura/window_tree_host_observer.h"
#include "ui/base/ime/text_input_client.h"
+#include "ui/base/touch/selection_bound.h"
+#include "ui/base/touch/touch_editing_controller.h"
+#include "ui/events/gestures/motion_event_aura.h"
#include "ui/gfx/display_observer.h"
-#include "ui/gfx/insets.h"
-#include "ui/gfx/rect.h"
-#include "ui/wm/public/activation_change_observer.h"
+#include "ui/gfx/geometry/insets.h"
+#include "ui/gfx/geometry/rect.h"
#include "ui/wm/public/activation_delegate.h"
namespace aura {
@@ -83,10 +85,8 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
public aura::WindowTreeHostObserver,
public aura::WindowDelegate,
public aura::client::ActivationDelegate,
- public aura::client::ActivationChangeObserver,
public aura::client::FocusChangeObserver,
- public aura::client::CursorClientObserver,
- public base::SupportsWeakPtr<RenderWidgetHostViewAura> {
+ public aura::client::CursorClientObserver {
public:
// Displays and controls touch editing elements such as selection handles.
class TouchEditingClient {
@@ -101,8 +101,9 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
virtual void EndTouchEditing(bool quick) = 0;
// Notifies the client that the selection bounds need to be updated.
- virtual void OnSelectionOrCursorChanged(const gfx::Rect& anchor,
- const gfx::Rect& focus) = 0;
+ virtual void OnSelectionOrCursorChanged(
+ const ui::SelectionBound& anchor,
+ const ui::SelectionBound& focus) = 0;
// Notifies the client that the current text input type as changed.
virtual void OnTextInputTypeChanged(ui::TextInputType type) = 0;
@@ -162,11 +163,8 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
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,
@@ -187,10 +185,11 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
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 CopyFromCompositingSurface(
+ const gfx::Rect& src_subrect,
+ const gfx::Size& dst_size,
+ ReadbackRequestCallback& callback,
+ const SkColorType preferred_color_type) override;
void CopyFromCompositingSurfaceToVideoFrame(
const gfx::Rect& src_subrect,
const scoped_refptr<media::VideoFrame>& target,
@@ -224,12 +223,13 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
void OnSwapCompositorFrame(uint32 output_surface_id,
scoped_ptr<cc::CompositorFrame> frame) override;
void DidStopFlinging() override;
+ void OnDidNavigateMainFrameToNewPage() override;
+ uint32_t GetSurfaceIdNamespace() override;
#if defined(OS_WIN)
- void SetLegacyRenderWidgetHostHWND(LegacyRenderWidgetHostHWND* legacy_hwnd);
- virtual void SetParentNativeViewAccessible(
+ void SetParentNativeViewAccessible(
gfx::NativeViewAccessible accessible_parent) override;
- virtual gfx::NativeViewId GetParentForWindowlessPlugin() const override;
+ gfx::NativeViewId GetParentForWindowlessPlugin() const override;
#endif
// Overridden from ui::TextInputClient:
@@ -262,8 +262,8 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
void OnCandidateWindowShown() override;
void OnCandidateWindowUpdated() override;
void OnCandidateWindowHidden() override;
- bool IsEditingCommandEnabled(int command_id) override;
- void ExecuteEditingCommand(int command_id) override;
+ bool IsEditCommandEnabled(int command_id) override;
+ void SetEditCommandForNextKeyEvent(int command_id) override;
// Overridden from gfx::DisplayObserver:
void OnDisplayAdded(const gfx::Display& new_display) override;
@@ -276,6 +276,7 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
gfx::Size GetMaximumSize() const override;
void OnBoundsChanged(const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds) override;
+ ui::TextInputClient* GetFocusedTextInputClient() override;
gfx::NativeCursor GetCursor(const gfx::Point& point) override;
int GetNonClientComponent(const gfx::Point& point) const override;
bool ShouldDescendIntoChildForEventHandling(
@@ -283,7 +284,7 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
const gfx::Point& location) override;
bool CanFocus() override;
void OnCaptureLost() override;
- void OnPaint(gfx::Canvas* canvas) override;
+ void OnPaint(const ui::PaintContext& context) override;
void OnDeviceScaleFactorChanged(float device_scale_factor) override;
void OnWindowDestroying(aura::Window* window) override;
void OnWindowDestroyed(aura::Window* window) override;
@@ -301,10 +302,6 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
// Overridden from aura::client::ActivationDelegate:
bool ShouldActivate() const override;
- // Overridden from aura::client::ActivationChangeObserver:
- void OnWindowActivated(aura::Window* gained_activation,
- aura::Window* lost_activation) override;
-
// Overridden from aura::client::CursorClientObserver:
void OnCursorVisibilityChanged(bool is_visible) override;
@@ -326,9 +323,13 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
// Updates the cursor clip region. Used for mouse locking.
void UpdateMouseLockRegion();
+
+ // Notification that the LegacyRenderWidgetHostHWND was destroyed.
+ void OnLegacyWindowDestroyed();
#endif
- void DisambiguationPopupRendered(bool success, const SkBitmap& result);
+ void DisambiguationPopupRendered(const SkBitmap& result,
+ ReadbackResponse response);
void HideDisambiguationPopup();
@@ -350,13 +351,19 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
return overscroll_controller_.get();
}
+ // Called when the context menu is about to be displayed.
+ void OnShowContextMenu();
+
protected:
~RenderWidgetHostViewAura() override;
// Exposed for tests.
aura::Window* window() { return window_; }
- SkColorType PreferredReadbackFormat() override;
- DelegatedFrameHost* GetDelegatedFrameHost() const override;
+
+ DelegatedFrameHost* GetDelegatedFrameHost() const {
+ return delegated_frame_host_.get();
+ }
+ const ui::MotionEventAura& pointer_state() const { return pointer_state_; }
private:
FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraTest,
@@ -366,6 +373,7 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraTest,
TouchEventPositionsArentRounded);
FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraTest, TouchEventSyncAsync);
+ FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraTest, Resize);
FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraTest, SwapNotifiesWindow);
FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraTest, RecreateLayers);
FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraTest,
@@ -379,6 +387,8 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraTest,
UpdateCursorIfOverSelf);
FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraCopyRequestTest,
+ DedupeFrameSubscriberRequests);
+ FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraCopyRequestTest,
DestroyedAfterCopyRequest);
FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraTest,
VisibleViewportTest);
@@ -392,6 +402,9 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
class WindowObserver;
friend class WindowObserver;
+ class WindowAncestorObserver;
+ friend class WindowAncestorObserver;
+
void UpdateCursorIfOverSelf();
// Tracks whether SnapToPhysicalPixelBoundary() has been called.
@@ -445,14 +458,23 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
void RemovingFromRootWindow();
// DelegatedFrameHostClient implementation.
- 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;
+ ui::Layer* DelegatedFrameHostGetLayer() const override;
+ bool DelegatedFrameHostIsVisible() const override;
+ gfx::Size DelegatedFrameHostDesiredSizeInDIP() const override;
+ bool DelegatedFrameCanCreateResizeLock() const override;
+ scoped_ptr<ResizeLock> DelegatedFrameHostCreateResizeLock(
+ bool defer_compositor_lock) override;
+ void DelegatedFrameHostResizeLockWasReleased() override;
+ void DelegatedFrameHostSendCompositorSwapAck(
+ int output_surface_id,
+ const cc::CompositorFrameAck& ack) override;
+ void DelegatedFrameHostSendReclaimCompositorResources(
+ int output_surface_id,
+ const cc::CompositorFrameAck& ack) override;
+ void DelegatedFrameHostOnLostCompositorResources() override;
+ void DelegatedFrameHostUpdateVSyncParameters(
+ const base::TimeTicks& timebase,
+ const base::TimeDelta& interval) override;
// Detaches |this| from the input method object.
void DetachFromInputMethod();
@@ -477,6 +499,17 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
RenderFrameHostImpl* GetFocusedFrame();
+ // Returns true if the |event| passed in can be forwarded to the renderer.
+ bool CanRendererHandleEvent(const ui::MouseEvent* event,
+ bool mouse_locked,
+ bool selection_popup);
+
+ // Called when the parent window bounds change.
+ void HandleParentBoundsChanged();
+
+ // Called when the parent window hierarchy for our window changes.
+ void ParentHierarchyChanged();
+
// The model object.
RenderWidgetHostImpl* host_;
@@ -486,6 +519,9 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
scoped_ptr<WindowObserver> window_observer_;
+ // Tracks the ancestors of the RWHVA window for window location changes.
+ scoped_ptr<WindowAncestorObserver> ancestor_window_observer_;
+
// Are we in the process of closing? Tracked so fullscreen views can avoid
// sending a second shutdown request to the host when they lose the focus
// after requesting shutdown for another reason (e.g. Escape key).
@@ -513,10 +549,9 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
// The cursor for the page. This is passed up from the renderer.
WebCursor current_cursor_;
- // The touch-event. Its touch-points are updated as necessary. A new
- // touch-point is added from an ET_TOUCH_PRESSED event, and a touch-point is
- // removed from the list on an ET_TOUCH_RELEASED event.
- blink::WebTouchEvent touch_event_;
+ // Stores the current state of the active pointers targeting this
+ // object.
+ ui::MotionEventAura pointer_state_;
// The current text input type.
ui::TextInputType text_input_type_;
@@ -526,9 +561,9 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
int text_input_flags_;
bool can_compose_inline_;
- // Rectangles for the selection anchor and focus.
- gfx::Rect selection_anchor_rect_;
- gfx::Rect selection_focus_rect_;
+ // Bounds for the selection.
+ ui::SelectionBound selection_anchor_;
+ ui::SelectionBound selection_focus_;
// The current composition character bounds.
std::vector<gfx::Rect> composition_character_bounds_;
@@ -593,7 +628,21 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
// for accessibility, as the container for windowless plugins like
// Flash/Silverlight, etc and for legacy drivers for trackpoints/trackpads,
// etc.
+ // The LegacyRenderWidgetHostHWND instance is created during the first call
+ // to RenderWidgetHostViewAura::InternalSetBounds. The instance is destroyed
+ // when the LegacyRenderWidgetHostHWND hwnd is destroyed.
content::LegacyRenderWidgetHostHWND* legacy_render_widget_host_HWND_;
+
+ // Set to true if the legacy_render_widget_host_HWND_ instance was destroyed
+ // by Windows. This could happen if the browser window was destroyed by
+ // DestroyWindow for e.g. This flag helps ensure that we don't try to create
+ // the LegacyRenderWidgetHostHWND instance again as that would be a futile
+ // exercise.
+ bool legacy_window_destroyed_;
+
+ // Set to true when a context menu is being displayed. Reset to false when
+ // a mouse leave is received in this context.
+ bool showing_context_menu_;
#endif
bool has_snapped_to_boundary_;
@@ -615,8 +664,6 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
// RenderWidgetHostViewGuest.
bool is_guest_view_hack_;
- base::WeakPtrFactory<RenderWidgetHostViewAura> weak_ptr_factory_;
-
gfx::Rect disambiguation_target_rect_;
// The last scroll offset when we start to render the link disambiguation
@@ -624,6 +671,7 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
// compositing surface and showing the disambiguation popup.
gfx::Vector2dF disambiguation_scroll_offset_;
+ base::WeakPtrFactory<RenderWidgetHostViewAura> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewAura);
};
diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/chromium/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
index 511c68cec11..3c4e660da2d 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
@@ -6,6 +6,7 @@
#include "base/basictypes.h"
#include "base/command_line.h"
+#include "base/memory/scoped_vector.h"
#include "base/memory/shared_memory.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
@@ -19,6 +20,8 @@
#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/input/input_router.h"
+#include "content/browser/renderer_host/input/web_input_event_util.h"
#include "content/browser/renderer_host/overscroll_controller.h"
#include "content/browser/renderer_host/overscroll_controller_delegate.h"
#include "content/browser/renderer_host/render_widget_host_delegate.h"
@@ -42,6 +45,7 @@
#include "ui/aura/env.h"
#include "ui/aura/layout_manager.h"
#include "ui/aura/test/aura_test_helper.h"
+#include "ui/aura/test/aura_test_utils.h"
#include "ui/aura/test/test_cursor_client.h"
#include "ui/aura/test/test_screen.h"
#include "ui/aura/test/test_window_delegate.h"
@@ -52,9 +56,12 @@
#include "ui/compositor/compositor.h"
#include "ui/compositor/layer_tree_owner.h"
#include "ui/compositor/test/draw_waiter_for_test.h"
+#include "ui/events/blink/blink_event_util.h"
#include "ui/events/event.h"
#include "ui/events/event_utils.h"
#include "ui/events/gesture_detection/gesture_configuration.h"
+#include "ui/events/keycodes/dom/dom_code.h"
+#include "ui/events/keycodes/dom/keycode_converter.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"
@@ -132,6 +139,17 @@ class MockRenderWidgetHostDelegate : public RenderWidgetHostDelegate {
public:
MockRenderWidgetHostDelegate() {}
~MockRenderWidgetHostDelegate() override {}
+ const NativeWebKeyboardEvent* last_event() const { return last_event_.get(); }
+ protected:
+ // RenderWidgetHostDelegate:
+ bool PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
+ bool* is_keyboard_shortcut) override {
+ last_event_.reset(new NativeWebKeyboardEvent(event));
+ return true;
+ }
+ private:
+ scoped_ptr<NativeWebKeyboardEvent> last_event_;
+ DISALLOW_COPY_AND_ASSIGN(MockRenderWidgetHostDelegate);
};
// Simple observer that keeps track of changes to a window for tests.
@@ -194,6 +212,28 @@ class FakeFrameSubscriber : public RenderWidgetHostViewFrameSubscriber {
base::Callback<void(bool)> callback_;
};
+class FakeWindowEventDispatcher : public aura::WindowEventDispatcher {
+ public:
+ FakeWindowEventDispatcher(aura::WindowTreeHost* host)
+ : WindowEventDispatcher(host),
+ processed_touch_event_count_(0) {}
+
+ void ProcessedTouchEvent(aura::Window* window,
+ ui::EventResult result) override {
+ WindowEventDispatcher::ProcessedTouchEvent(window, result);
+ processed_touch_event_count_++;
+ }
+
+ size_t GetAndResetProcessedTouchEventCount() {
+ size_t count = processed_touch_event_count_;
+ processed_touch_event_count_ = 0;
+ return count;
+ }
+
+ private:
+ size_t processed_touch_event_count_;
+};
+
class FakeRenderWidgetHostViewAura : public RenderWidgetHostViewAura {
public:
FakeRenderWidgetHostViewAura(RenderWidgetHost* widget,
@@ -201,24 +241,29 @@ class FakeRenderWidgetHostViewAura : public RenderWidgetHostViewAura {
: RenderWidgetHostViewAura(widget, is_guest_view_hack),
has_resize_lock_(false) {}
+ void UseFakeDispatcher() {
+ dispatcher_ = new FakeWindowEventDispatcher(window()->GetHost());
+ scoped_ptr<aura::WindowEventDispatcher> dispatcher(dispatcher_);
+ aura::test::SetHostDispatcher(window()->GetHost(), dispatcher.Pass());
+ }
+
~FakeRenderWidgetHostViewAura() override {}
- scoped_ptr<ResizeLock> CreateResizeLock(bool defer_compositor_lock) override {
+ scoped_ptr<ResizeLock> DelegatedFrameHostCreateResizeLock(
+ bool defer_compositor_lock) override {
gfx::Size desired_size = window()->bounds().size();
return scoped_ptr<ResizeLock>(
new FakeResizeLock(desired_size, defer_compositor_lock));
}
+ bool DelegatedFrameCanCreateResizeLock() const override { return true; }
+
void RunOnCompositingDidCommit() {
GetDelegatedFrameHost()->OnCompositingDidCommitForTesting(
window()->GetHost()->compositor());
}
- bool ShouldCreateResizeLock() override {
- return GetDelegatedFrameHost()->ShouldCreateResizeLockForTesting();
- }
-
- void RequestCopyOfOutput(scoped_ptr<cc::CopyOutputRequest> request) override {
+ void InterceptCopyOfOutput(scoped_ptr<cc::CopyOutputRequest> request) {
last_copy_request_ = request.Pass();
if (last_copy_request_->has_texture_mailbox()) {
// Give the resulting texture a size.
@@ -255,9 +300,24 @@ class FakeRenderWidgetHostViewAura : public RenderWidgetHostViewAura {
: ResizeLock(new_size, defer_compositor_lock) {}
};
+ void OnTouchEvent(ui::TouchEvent* event) override {
+ RenderWidgetHostViewAura::OnTouchEvent(event);
+ if (pointer_state().GetPointerCount() > 0) {
+ touch_event_.reset(
+ new blink::WebTouchEvent(ui::CreateWebTouchEventFromMotionEvent(
+ pointer_state(), event->may_cause_scrolling())));
+ } else {
+ // Never create a WebTouchEvent with 0 touch points.
+ touch_event_.reset();
+ }
+ }
+
bool has_resize_lock_;
gfx::Size last_frame_size_;
scoped_ptr<cc::CopyOutputRequest> last_copy_request_;
+ // null if there are 0 active touch points.
+ scoped_ptr<blink::WebTouchEvent> touch_event_;
+ FakeWindowEventDispatcher* dispatcher_;
};
// A layout manager that always resizes a child to the root window size.
@@ -295,6 +355,15 @@ class MockWindowObserver : public aura::WindowObserver {
MOCK_METHOD2(OnDelegatedFrameDamage, void(aura::Window*, const gfx::Rect&));
};
+const WebInputEvent* GetInputEventFromMessage(const IPC::Message& message) {
+ PickleIterator iter(message);
+ const char* data;
+ int data_length;
+ if (!iter.ReadData(&data, &data_length))
+ return NULL;
+ return reinterpret_cast<const WebInputEvent*>(data);
+}
+
} // namespace
class RenderWidgetHostViewAuraTest : public testing::Test {
@@ -363,6 +432,49 @@ class RenderWidgetHostViewAuraTest : public testing::Test {
widget_host_uses_shutdown_to_destroy_ = use;
}
+ void SimulateMemoryPressure(
+ base::MemoryPressureListener::MemoryPressureLevel level) {
+ // Here should be base::MemoryPressureListener::NotifyMemoryPressure, but
+ // since the RendererFrameManager is installing a MemoryPressureListener
+ // which uses ObserverListThreadSafe, which furthermore remembers the
+ // message loop for the thread it was created in. Between tests, the
+ // RendererFrameManager singleton survives and and the MessageLoop gets
+ // destroyed. The correct fix would be to have ObserverListThreadSafe look
+ // up the proper message loop every time (see crbug.com/443824.)
+ RendererFrameManager::GetInstance()->OnMemoryPressure(level);
+ }
+
+ void SendInputEventACK(WebInputEvent::Type type,
+ InputEventAckState ack_result) {
+ InputHostMsg_HandleInputEvent_ACK_Params ack;
+ ack.type = type;
+ ack.state = ack_result;
+ InputHostMsg_HandleInputEvent_ACK response(0, ack);
+ widget_host_->OnMessageReceived(response);
+ }
+
+ size_t GetSentMessageCountAndResetSink() {
+ size_t count = sink_->message_count();
+ sink_->ClearMessages();
+ return count;
+ }
+
+ void AckLastSentInputEventIfNecessary(InputEventAckState ack_result) {
+ if (!sink_->message_count())
+ return;
+
+ InputMsg_HandleInputEvent::Param params;
+ if (!InputMsg_HandleInputEvent::Read(
+ sink_->GetMessageAt(sink_->message_count() - 1), &params)) {
+ return;
+ }
+
+ if (WebInputEventTraits::IgnoresAckDisposition(*get<0>(params)))
+ return;
+
+ SendInputEventACK(get<0>(params)->type, ack_result);
+ }
+
protected:
// If true, then calls RWH::Shutdown() instead of deleting RWH.
bool widget_host_uses_shutdown_to_destroy_;
@@ -531,8 +643,8 @@ class RenderWidgetHostViewAuraOverscrollTest
}
void SimulateGestureScrollUpdateEvent(float dX, float dY, int modifiers) {
- SimulateGestureEventCore(
- SyntheticWebGestureEventBuilder::BuildScrollUpdate(dX, dY, modifiers));
+ SimulateGestureEventCore(SyntheticWebGestureEventBuilder::BuildScrollUpdate(
+ dX, dY, modifiers, blink::WebGestureDeviceTouchscreen));
}
void SimulateGesturePinchUpdateEvent(float scale,
@@ -555,15 +667,6 @@ class RenderWidgetHostViewAuraOverscrollTest
velocityX, velocityY, sourceDevice));
}
- void SendInputEventACK(WebInputEvent::Type type,
- InputEventAckState ack_result) {
- InputHostMsg_HandleInputEvent_ACK_Params ack;
- ack.type = type;
- ack.state = ack_result;
- InputHostMsg_HandleInputEvent_ACK response(0, ack);
- widget_host_->OnMessageReceived(response);
- }
-
bool ScrollStateIsContentScrolling() const {
return scroll_state() == OverscrollController::STATE_CONTENT_SCROLLING;
}
@@ -617,28 +720,6 @@ class RenderWidgetHostViewAuraOverscrollTest
SendTouchEvent();
}
- size_t GetSentMessageCountAndResetSink() {
- size_t count = sink_->message_count();
- sink_->ClearMessages();
- return count;
- }
-
- void AckLastSentInputEventIfNecessary(InputEventAckState ack_result) {
- if (!sink_->message_count())
- return;
-
- InputMsg_HandleInputEvent::Param params;
- if (!InputMsg_HandleInputEvent::Read(
- sink_->GetMessageAt(sink_->message_count() - 1), &params)) {
- return;
- }
-
- if (WebInputEventTraits::IgnoresAckDisposition(*params.a))
- return;
-
- SendInputEventACK(params.a->type, ack_result);
- }
-
SyntheticWebTouchEvent touch_event_;
scoped_ptr<TestOverscrollDelegate> overscroll_delegate_;
@@ -727,7 +808,7 @@ TEST_F(RenderWidgetHostViewAuraTest, DestroyFullscreenOnBlur) {
TestWindowObserver observer(window);
aura::test::TestWindowDelegate delegate;
scoped_ptr<aura::Window> sibling(new aura::Window(&delegate));
- sibling->Init(aura::WINDOW_LAYER_TEXTURED);
+ sibling->Init(ui::LAYER_TEXTURED);
sibling->Show();
window->parent()->AddChild(sibling.get());
sibling->Focus();
@@ -832,7 +913,7 @@ TEST_F(RenderWidgetHostViewAuraTest, PopupClosesWhenParentLosesFocus) {
aura::test::TestWindowDelegate delegate;
scoped_ptr<aura::Window> dialog_window(new aura::Window(&delegate));
- dialog_window->Init(aura::WINDOW_LAYER_TEXTURED);
+ dialog_window->Init(ui::LAYER_TEXTURED);
aura::client::ParentWindowWithContext(
dialog_window.get(), popup_window, gfx::Rect());
dialog_window->Show();
@@ -878,19 +959,20 @@ TEST_F(RenderWidgetHostViewAuraTest, SetCompositionText) {
InputMsg_ImeSetComposition::Param params;
InputMsg_ImeSetComposition::Read(msg, &params);
// composition text
- EXPECT_EQ(composition_text.text, params.a);
+ EXPECT_EQ(composition_text.text, get<0>(params));
// underlines
- ASSERT_EQ(underlines.size(), params.b.size());
+ ASSERT_EQ(underlines.size(), get<1>(params).size());
for (size_t i = 0; i < underlines.size(); ++i) {
- EXPECT_EQ(underlines[i].start_offset, params.b[i].startOffset);
- EXPECT_EQ(underlines[i].end_offset, params.b[i].endOffset);
- EXPECT_EQ(underlines[i].color, params.b[i].color);
- EXPECT_EQ(underlines[i].thick, params.b[i].thick);
- EXPECT_EQ(underlines[i].background_color, params.b[i].backgroundColor);
+ EXPECT_EQ(underlines[i].start_offset, get<1>(params)[i].startOffset);
+ EXPECT_EQ(underlines[i].end_offset, get<1>(params)[i].endOffset);
+ EXPECT_EQ(underlines[i].color, get<1>(params)[i].color);
+ EXPECT_EQ(underlines[i].thick, get<1>(params)[i].thick);
+ EXPECT_EQ(underlines[i].background_color,
+ get<1>(params)[i].backgroundColor);
}
// highlighted range
- EXPECT_EQ(4, params.c) << "Should be the same to the caret pos";
- EXPECT_EQ(4, params.d) << "Should be the same to the caret pos";
+ EXPECT_EQ(4, get<2>(params)) << "Should be the same to the caret pos";
+ EXPECT_EQ(4, get<3>(params)) << "Should be the same to the caret pos";
}
view_->ImeCancelComposition();
@@ -922,9 +1004,9 @@ TEST_F(RenderWidgetHostViewAuraTest, FinishCompositionByMouse) {
sink_->ClearMessages();
// Simulates the mouse press.
- ui::MouseEvent mouse_event(ui::ET_MOUSE_PRESSED,
- gfx::Point(), gfx::Point(),
- ui::EF_LEFT_MOUSE_BUTTON, 0);
+ ui::MouseEvent mouse_event(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
+ ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
+ 0);
view_->OnMouseEvent(&mouse_event);
EXPECT_FALSE(view_->has_composition_text_);
@@ -944,10 +1026,10 @@ TEST_F(RenderWidgetHostViewAuraTest, FinishCompositionByMouse) {
TEST_F(RenderWidgetHostViewAuraTest, TouchEventState) {
view_->InitAsChild(NULL);
view_->Show();
+ GetSentMessageCountAndResetSink();
// Start with no touch-event handler in the renderer.
widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, false));
- EXPECT_FALSE(widget_host_->ShouldForwardTouchEvent());
ui::TouchEvent press(ui::ET_TOUCH_PRESSED,
gfx::Point(30, 30),
@@ -962,89 +1044,169 @@ TEST_F(RenderWidgetHostViewAuraTest, TouchEventState) {
0,
ui::EventTimeForNow());
+ // The touch events should get forwared from the view, but they should not
+ // reach the renderer.
view_->OnTouchEvent(&press);
- EXPECT_FALSE(press.handled());
- EXPECT_EQ(blink::WebInputEvent::TouchStart, view_->touch_event_.type);
- EXPECT_TRUE(view_->touch_event_.cancelable);
- EXPECT_EQ(1U, view_->touch_event_.touchesLength);
+ EXPECT_EQ(0U, GetSentMessageCountAndResetSink());
+ EXPECT_TRUE(press.synchronous_handling_disabled());
+ EXPECT_EQ(blink::WebInputEvent::TouchStart, view_->touch_event_->type);
+ EXPECT_TRUE(view_->touch_event_->cancelable);
+ EXPECT_EQ(1U, view_->touch_event_->touchesLength);
EXPECT_EQ(blink::WebTouchPoint::StatePressed,
- view_->touch_event_.touches[0].state);
+ view_->touch_event_->touches[0].state);
view_->OnTouchEvent(&move);
- EXPECT_FALSE(move.handled());
- EXPECT_EQ(blink::WebInputEvent::TouchMove, view_->touch_event_.type);
- EXPECT_TRUE(view_->touch_event_.cancelable);
- EXPECT_EQ(1U, view_->touch_event_.touchesLength);
+ EXPECT_EQ(0U, GetSentMessageCountAndResetSink());
+ EXPECT_TRUE(press.synchronous_handling_disabled());
+ EXPECT_EQ(blink::WebInputEvent::TouchMove, view_->touch_event_->type);
+ EXPECT_TRUE(view_->touch_event_->cancelable);
+ EXPECT_EQ(1U, view_->touch_event_->touchesLength);
EXPECT_EQ(blink::WebTouchPoint::StateMoved,
- view_->touch_event_.touches[0].state);
+ view_->touch_event_->touches[0].state);
view_->OnTouchEvent(&release);
- EXPECT_FALSE(release.handled());
- EXPECT_EQ(blink::WebInputEvent::TouchEnd, view_->touch_event_.type);
- EXPECT_TRUE(view_->touch_event_.cancelable);
- EXPECT_EQ(0U, view_->touch_event_.touchesLength);
+ EXPECT_EQ(0U, GetSentMessageCountAndResetSink());
+ EXPECT_TRUE(press.synchronous_handling_disabled());
+ EXPECT_EQ(nullptr, view_->touch_event_);
// Now install some touch-event handlers and do the same steps. The touch
// events should now be consumed. However, the touch-event state should be
// updated as before.
widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, true));
- EXPECT_TRUE(widget_host_->ShouldForwardTouchEvent());
view_->OnTouchEvent(&press);
- EXPECT_TRUE(press.stopped_propagation());
- EXPECT_EQ(blink::WebInputEvent::TouchStart, view_->touch_event_.type);
- EXPECT_TRUE(view_->touch_event_.cancelable);
- EXPECT_EQ(1U, view_->touch_event_.touchesLength);
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+ EXPECT_TRUE(press.synchronous_handling_disabled());
+ EXPECT_EQ(blink::WebInputEvent::TouchStart, view_->touch_event_->type);
+ EXPECT_TRUE(view_->touch_event_->cancelable);
+ EXPECT_EQ(1U, view_->touch_event_->touchesLength);
EXPECT_EQ(blink::WebTouchPoint::StatePressed,
- view_->touch_event_.touches[0].state);
+ view_->touch_event_->touches[0].state);
view_->OnTouchEvent(&move);
- EXPECT_TRUE(move.stopped_propagation());
- EXPECT_EQ(blink::WebInputEvent::TouchMove, view_->touch_event_.type);
- EXPECT_TRUE(view_->touch_event_.cancelable);
- EXPECT_EQ(1U, view_->touch_event_.touchesLength);
+ EXPECT_TRUE(move.synchronous_handling_disabled());
+ EXPECT_EQ(blink::WebInputEvent::TouchMove, view_->touch_event_->type);
+ EXPECT_TRUE(view_->touch_event_->cancelable);
+ EXPECT_EQ(1U, view_->touch_event_->touchesLength);
EXPECT_EQ(blink::WebTouchPoint::StateMoved,
- view_->touch_event_.touches[0].state);
-
+ view_->touch_event_->touches[0].state);
view_->OnTouchEvent(&release);
- EXPECT_TRUE(release.stopped_propagation());
- EXPECT_EQ(blink::WebInputEvent::TouchEnd, view_->touch_event_.type);
- EXPECT_TRUE(view_->touch_event_.cancelable);
- EXPECT_EQ(0U, view_->touch_event_.touchesLength);
+ EXPECT_TRUE(release.synchronous_handling_disabled());
+ EXPECT_EQ(nullptr, view_->touch_event_);
// Now start a touch event, and remove the event-handlers before the release.
view_->OnTouchEvent(&press);
- EXPECT_TRUE(press.stopped_propagation());
- EXPECT_EQ(blink::WebInputEvent::TouchStart, view_->touch_event_.type);
- EXPECT_EQ(1U, view_->touch_event_.touchesLength);
+ EXPECT_TRUE(press.synchronous_handling_disabled());
+ EXPECT_EQ(blink::WebInputEvent::TouchStart, view_->touch_event_->type);
+ EXPECT_EQ(1U, view_->touch_event_->touchesLength);
EXPECT_EQ(blink::WebTouchPoint::StatePressed,
- view_->touch_event_.touches[0].state);
+ 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());
+ EXPECT_EQ(0U, GetSentMessageCountAndResetSink());
ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(20, 20), 0,
base::Time::NowFromSystemTime() - base::Time());
view_->OnTouchEvent(&move2);
- EXPECT_FALSE(move2.handled());
- EXPECT_EQ(blink::WebInputEvent::TouchMove, view_->touch_event_.type);
- EXPECT_EQ(1U, view_->touch_event_.touchesLength);
+ EXPECT_TRUE(press.synchronous_handling_disabled());
+ EXPECT_EQ(blink::WebInputEvent::TouchMove, view_->touch_event_->type);
+ EXPECT_EQ(1U, view_->touch_event_->touchesLength);
EXPECT_EQ(blink::WebTouchPoint::StateMoved,
- view_->touch_event_.touches[0].state);
+ view_->touch_event_->touches[0].state);
ui::TouchEvent release2(ui::ET_TOUCH_RELEASED, gfx::Point(20, 20), 0,
base::Time::NowFromSystemTime() - base::Time());
view_->OnTouchEvent(&release2);
- EXPECT_FALSE(release2.handled());
- EXPECT_EQ(blink::WebInputEvent::TouchEnd, view_->touch_event_.type);
- EXPECT_EQ(0U, view_->touch_event_.touchesLength);
+ EXPECT_TRUE(press.synchronous_handling_disabled());
+ EXPECT_EQ(nullptr, view_->touch_event_);
+}
+
+// Checks that touch-event state is maintained correctly for multiple touch
+// points.
+TEST_F(RenderWidgetHostViewAuraTest, MultiTouchPointsStates) {
+ view_->InitAsFullscreen(parent_view_);
+ view_->Show();
+ view_->UseFakeDispatcher();
+ GetSentMessageCountAndResetSink();
+
+ ui::TouchEvent press0(ui::ET_TOUCH_PRESSED, gfx::Point(30, 30), 0,
+ ui::EventTimeForNow());
+
+ view_->OnTouchEvent(&press0);
+ SendInputEventACK(blink::WebInputEvent::TouchStart,
+ INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(blink::WebInputEvent::TouchStart, view_->touch_event_->type);
+ EXPECT_EQ(1U, view_->touch_event_->touchesLength);
+ EXPECT_EQ(1U, view_->dispatcher_->GetAndResetProcessedTouchEventCount());
+
+ ui::TouchEvent move0(ui::ET_TOUCH_MOVED, gfx::Point(20, 20), 0,
+ ui::EventTimeForNow());
+
+ view_->OnTouchEvent(&move0);
+ SendInputEventACK(blink::WebInputEvent::TouchMove,
+ INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(blink::WebInputEvent::TouchMove, view_->touch_event_->type);
+ EXPECT_EQ(1U, view_->touch_event_->touchesLength);
+ EXPECT_EQ(1U, view_->dispatcher_->GetAndResetProcessedTouchEventCount());
+
+ // For the second touchstart, only the state of the second touch point is
+ // StatePressed, the state of the first touch point is StateStationary.
+ ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 1,
+ ui::EventTimeForNow());
+
+ view_->OnTouchEvent(&press1);
+ SendInputEventACK(blink::WebInputEvent::TouchStart,
+ INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(blink::WebInputEvent::TouchStart, view_->touch_event_->type);
+ EXPECT_EQ(2U, view_->touch_event_->touchesLength);
+ EXPECT_EQ(1U, view_->dispatcher_->GetAndResetProcessedTouchEventCount());
+
+ // For the touchmove of second point, the state of the second touch point is
+ // StateMoved, the state of the first touch point is StateStationary.
+ ui::TouchEvent move1(ui::ET_TOUCH_MOVED, gfx::Point(30, 30), 1,
+ ui::EventTimeForNow());
+
+ view_->OnTouchEvent(&move1);
+ SendInputEventACK(blink::WebInputEvent::TouchMove,
+ INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(blink::WebInputEvent::TouchMove, view_->touch_event_->type);
+ EXPECT_EQ(2U, view_->touch_event_->touchesLength);
+ EXPECT_EQ(1U, view_->dispatcher_->GetAndResetProcessedTouchEventCount());
+
+ // For the touchmove of first point, the state of the first touch point is
+ // StateMoved, the state of the second touch point is StateStationary.
+ ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(10, 10), 0,
+ ui::EventTimeForNow());
+
+ view_->OnTouchEvent(&move2);
+ SendInputEventACK(blink::WebInputEvent::TouchMove,
+ INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(blink::WebInputEvent::TouchMove, view_->touch_event_->type);
+ EXPECT_EQ(2U, view_->touch_event_->touchesLength);
+ EXPECT_EQ(1U, view_->dispatcher_->GetAndResetProcessedTouchEventCount());
+
+ ui::TouchEvent cancel0(ui::ET_TOUCH_CANCELLED, gfx::Point(10, 10), 0,
+ ui::EventTimeForNow());
+
+ // For the touchcancel, only the state of the current touch point is
+ // StateCancelled, the state of the other touch point is StateStationary.
+ view_->OnTouchEvent(&cancel0);
+ EXPECT_EQ(blink::WebInputEvent::TouchCancel, view_-> touch_event_->type);
+ EXPECT_EQ(1U, view_->touch_event_->touchesLength);
+ EXPECT_EQ(1U, view_->dispatcher_->GetAndResetProcessedTouchEventCount());
+
+ ui::TouchEvent cancel1(ui::ET_TOUCH_CANCELLED, gfx::Point(30, 30), 1,
+ ui::EventTimeForNow());
+
+ view_->OnTouchEvent(&cancel1);
+ EXPECT_EQ(1U, view_->dispatcher_->GetAndResetProcessedTouchEventCount());
+ EXPECT_EQ(nullptr, view_->touch_event_);
}
// Checks that touch-events are queued properly when there is a touch-event
@@ -1054,7 +1216,6 @@ TEST_F(RenderWidgetHostViewAuraTest, TouchEventSyncAsync) {
view_->Show();
widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, true));
- EXPECT_TRUE(widget_host_->ShouldForwardTouchEvent());
ui::TouchEvent press(ui::ET_TOUCH_PRESSED,
gfx::Point(30, 30),
@@ -1070,32 +1231,31 @@ TEST_F(RenderWidgetHostViewAuraTest, TouchEventSyncAsync) {
ui::EventTimeForNow());
view_->OnTouchEvent(&press);
- EXPECT_TRUE(press.stopped_propagation());
- EXPECT_EQ(blink::WebInputEvent::TouchStart, view_->touch_event_.type);
- EXPECT_EQ(1U, view_->touch_event_.touchesLength);
+ EXPECT_TRUE(press.synchronous_handling_disabled());
+ EXPECT_EQ(blink::WebInputEvent::TouchStart, view_->touch_event_->type);
+ EXPECT_EQ(1U, view_->touch_event_->touchesLength);
EXPECT_EQ(blink::WebTouchPoint::StatePressed,
- view_->touch_event_.touches[0].state);
+ view_->touch_event_->touches[0].state);
view_->OnTouchEvent(&move);
- EXPECT_TRUE(move.stopped_propagation());
- EXPECT_EQ(blink::WebInputEvent::TouchMove, view_->touch_event_.type);
- EXPECT_EQ(1U, view_->touch_event_.touchesLength);
+ EXPECT_TRUE(move.synchronous_handling_disabled());
+ EXPECT_EQ(blink::WebInputEvent::TouchMove, view_->touch_event_->type);
+ EXPECT_EQ(1U, view_->touch_event_->touchesLength);
EXPECT_EQ(blink::WebTouchPoint::StateMoved,
- view_->touch_event_.touches[0].state);
+ view_->touch_event_->touches[0].state);
// Send the same move event. Since the point hasn't moved, it won't affect the
// queue. However, the view should consume the event.
view_->OnTouchEvent(&move);
- EXPECT_TRUE(move.stopped_propagation());
- EXPECT_EQ(blink::WebInputEvent::TouchMove, view_->touch_event_.type);
- EXPECT_EQ(1U, view_->touch_event_.touchesLength);
+ EXPECT_TRUE(move.synchronous_handling_disabled());
+ EXPECT_EQ(blink::WebInputEvent::TouchMove, view_->touch_event_->type);
+ EXPECT_EQ(1U, view_->touch_event_->touchesLength);
EXPECT_EQ(blink::WebTouchPoint::StateMoved,
- view_->touch_event_.touches[0].state);
+ view_->touch_event_->touches[0].state);
view_->OnTouchEvent(&release);
- EXPECT_TRUE(release.stopped_propagation());
- EXPECT_EQ(blink::WebInputEvent::TouchEnd, view_->touch_event_.type);
- EXPECT_EQ(0U, view_->touch_event_.touchesLength);
+ EXPECT_TRUE(release.synchronous_handling_disabled());
+ EXPECT_EQ(nullptr, view_->touch_event_);
}
TEST_F(RenderWidgetHostViewAuraTest, PhysicalBackingSizeWithScale) {
@@ -1114,9 +1274,9 @@ TEST_F(RenderWidgetHostViewAuraTest, PhysicalBackingSizeWithScale) {
EXPECT_EQ(ViewMsg_Resize::ID, msg->type());
ViewMsg_Resize::Param params;
ViewMsg_Resize::Read(msg, &params);
- EXPECT_EQ("100x100", params.a.new_size.ToString()); // dip size
+ EXPECT_EQ("100x100", get<0>(params).new_size.ToString()); // dip size
EXPECT_EQ("100x100",
- params.a.physical_backing_size.ToString()); // backing size
+ get<0>(params).physical_backing_size.ToString()); // backing size
}
widget_host_->ResetSizeAndRepaintPendingFlags();
@@ -1131,10 +1291,10 @@ TEST_F(RenderWidgetHostViewAuraTest, PhysicalBackingSizeWithScale) {
EXPECT_EQ(ViewMsg_Resize::ID, msg->type());
ViewMsg_Resize::Param params;
ViewMsg_Resize::Read(msg, &params);
- EXPECT_EQ(2.0f, params.a.screen_info.deviceScaleFactor);
- EXPECT_EQ("100x100", params.a.new_size.ToString()); // dip size
+ EXPECT_EQ(2.0f, get<0>(params).screen_info.deviceScaleFactor);
+ EXPECT_EQ("100x100", get<0>(params).new_size.ToString()); // dip size
EXPECT_EQ("200x200",
- params.a.physical_backing_size.ToString()); // backing size
+ get<0>(params).physical_backing_size.ToString()); // backing size
}
widget_host_->ResetSizeAndRepaintPendingFlags();
@@ -1149,10 +1309,10 @@ TEST_F(RenderWidgetHostViewAuraTest, PhysicalBackingSizeWithScale) {
EXPECT_EQ(ViewMsg_Resize::ID, msg->type());
ViewMsg_Resize::Param params;
ViewMsg_Resize::Read(msg, &params);
- EXPECT_EQ(1.0f, params.a.screen_info.deviceScaleFactor);
- EXPECT_EQ("100x100", params.a.new_size.ToString()); // dip size
+ EXPECT_EQ(1.0f, get<0>(params).screen_info.deviceScaleFactor);
+ EXPECT_EQ("100x100", get<0>(params).new_size.ToString()); // dip size
EXPECT_EQ("100x100",
- params.a.physical_backing_size.ToString()); // backing size
+ get<0>(params).physical_backing_size.ToString()); // backing size
}
}
@@ -1172,7 +1332,7 @@ TEST_F(RenderWidgetHostViewAuraTest, CursorVisibilityChange) {
cursor_client.AddObserver(view_);
// Expect a message the first time the cursor is shown.
- view_->WasShown();
+ view_->Show();
sink_->ClearMessages();
cursor_client.ShowCursor();
EXPECT_EQ(1u, sink_->message_count());
@@ -1197,7 +1357,7 @@ TEST_F(RenderWidgetHostViewAuraTest, CursorVisibilityChange) {
EXPECT_EQ(0u, sink_->message_count());
// No messages should be sent while the view is invisible.
- view_->WasHidden();
+ view_->Hide();
sink_->ClearMessages();
cursor_client.ShowCursor();
EXPECT_EQ(0u, sink_->message_count());
@@ -1207,7 +1367,7 @@ TEST_F(RenderWidgetHostViewAuraTest, CursorVisibilityChange) {
// Show the view. Since the cursor was invisible when the view was hidden,
// no message should be sent.
sink_->ClearMessages();
- view_->WasShown();
+ view_->Show();
EXPECT_FALSE(sink_->GetUniqueMessageMatching(
InputMsg_CursorVisibilityChange::ID));
@@ -1224,7 +1384,7 @@ TEST_F(RenderWidgetHostViewAuraTest, CursorVisibilityChange) {
InputMsg_CursorVisibilityChange::ID));
// No messages should be sent while the view is invisible.
- view_->WasHidden();
+ view_->Hide();
sink_->ClearMessages();
cursor_client.HideCursor();
EXPECT_EQ(0u, sink_->message_count());
@@ -1232,7 +1392,7 @@ TEST_F(RenderWidgetHostViewAuraTest, CursorVisibilityChange) {
// Show the view. Since the cursor was visible when the view was hidden,
// a message is expected to be sent.
sink_->ClearMessages();
- view_->WasShown();
+ view_->Show();
EXPECT_TRUE(sink_->GetUniqueMessageMatching(
InputMsg_CursorVisibilityChange::ID));
@@ -1304,7 +1464,7 @@ 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_);
- view_->WasShown();
+ view_->Show();
widget_host_->ResetSizeAndRepaintPendingFlags();
sink_->ClearMessages();
@@ -1317,14 +1477,14 @@ TEST_F(RenderWidgetHostViewAuraTest, DISABLED_FullscreenResize) {
ViewMsg_Resize::Param params;
ViewMsg_Resize::Read(msg, &params);
EXPECT_EQ("0,0 800x600",
- gfx::Rect(params.a.screen_info.availableRect).ToString());
- EXPECT_EQ("800x600", params.a.new_size.ToString());
+ gfx::Rect(get<0>(params).screen_info.availableRect).ToString());
+ EXPECT_EQ("800x600", get<0>(params).new_size.ToString());
// Resizes are blocked until we swapped a frame of the correct size, and
// we've committed it.
view_->OnSwapCompositorFrame(
0,
MakeDelegatedFrame(
- 1.f, params.a.new_size, gfx::Rect(params.a.new_size)));
+ 1.f, get<0>(params).new_size, gfx::Rect(get<0>(params).new_size)));
ui::DrawWaiterForTest::WaitForCommit(
root_window->GetHost()->compositor());
}
@@ -1342,12 +1502,12 @@ TEST_F(RenderWidgetHostViewAuraTest, DISABLED_FullscreenResize) {
ViewMsg_Resize::Param params;
ViewMsg_Resize::Read(msg, &params);
EXPECT_EQ("0,0 1600x1200",
- gfx::Rect(params.a.screen_info.availableRect).ToString());
- EXPECT_EQ("1600x1200", params.a.new_size.ToString());
+ gfx::Rect(get<0>(params).screen_info.availableRect).ToString());
+ EXPECT_EQ("1600x1200", get<0>(params).new_size.ToString());
view_->OnSwapCompositorFrame(
0,
MakeDelegatedFrame(
- 1.f, params.a.new_size, gfx::Rect(params.a.new_size)));
+ 1.f, get<0>(params).new_size, gfx::Rect(get<0>(params).new_size)));
ui::DrawWaiterForTest::WaitForCommit(
root_window->GetHost()->compositor());
}
@@ -1364,7 +1524,7 @@ TEST_F(RenderWidgetHostViewAuraTest, SwapNotifiesWindow) {
parent_view_->GetNativeView()->GetRootWindow(),
gfx::Rect());
view_->SetSize(view_size);
- view_->WasShown();
+ view_->Show();
MockWindowObserver observer;
view_->window_->AddObserver(&observer);
@@ -1395,7 +1555,7 @@ TEST_F(RenderWidgetHostViewAuraTest, RecreateLayers) {
view_->GetNativeView(), parent_view_->GetNativeView()->GetRootWindow(),
gfx::Rect());
view_->SetSize(view_size);
- view_->WasShown();
+ view_->Show();
view_->OnSwapCompositorFrame(0,
MakeDelegatedFrame(1.f, view_size, view_rect));
@@ -1422,7 +1582,7 @@ TEST_F(RenderWidgetHostViewAuraTest, Resize) {
view_->InitAsChild(NULL);
aura::client::ParentWindowWithContext(
view_->GetNativeView(), root_window, gfx::Rect(size1));
- view_->WasShown();
+ view_->Show();
view_->SetSize(size1);
view_->OnSwapCompositorFrame(
0, MakeDelegatedFrame(1.f, size1, gfx::Rect(size1)));
@@ -1446,7 +1606,7 @@ TEST_F(RenderWidgetHostViewAuraTest, Resize) {
EXPECT_EQ(ViewMsg_Resize::ID, msg->type());
ViewMsg_Resize::Param params;
ViewMsg_Resize::Read(msg, &params);
- EXPECT_EQ(size2.ToString(), params.a.new_size.ToString());
+ EXPECT_EQ(size2.ToString(), get<0>(params).new_size.ToString());
}
// Send resize ack to observe new Resize messages.
update_params.view_size = size2;
@@ -1474,37 +1634,53 @@ TEST_F(RenderWidgetHostViewAuraTest, Resize) {
// produce a Resize message after the commit.
view_->OnSwapCompositorFrame(
0, MakeDelegatedFrame(1.f, size2, gfx::Rect(size2)));
- // No frame ack yet.
- EXPECT_EQ(0u, sink_->message_count());
+ cc::SurfaceId surface_id = view_->surface_id();
+ if (surface_id.is_null()) {
+ // No frame ack yet.
+ EXPECT_EQ(0u, sink_->message_count());
+ } else {
+ // Frame isn't desired size, so early ack.
+ EXPECT_EQ(1u, sink_->message_count());
+ }
EXPECT_EQ(size2.ToString(), view_->GetRequestedRendererSize().ToString());
// Wait for commit, then we should unlock the compositor and send a Resize
// message (and a frame ack)
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(swap_index)->type());
- {
- const IPC::Message* msg = sink_->GetMessageAt(resize_index);
- EXPECT_EQ(ViewMsg_Resize::ID, msg->type());
- ViewMsg_Resize::Param params;
- ViewMsg_Resize::Read(msg, &params);
- EXPECT_EQ(size3.ToString(), params.a.new_size.ToString());
+
+ bool has_resize = false;
+ for (uint32 i = 0; i < sink_->message_count(); ++i) {
+ const IPC::Message* msg = sink_->GetMessageAt(i);
+ switch (msg->type()) {
+ case InputMsg_HandleInputEvent::ID: {
+ // On some platforms, the call to view_->Show() causes a posted task to
+ // call
+ // ui::WindowEventDispatcher::SynthesizeMouseMoveAfterChangeToWindow,
+ // which the above WaitForCommit may cause to be picked up. Be robust
+ // to this extra IPC coming in.
+ InputMsg_HandleInputEvent::Param params;
+ InputMsg_HandleInputEvent::Read(msg, &params);
+ const blink::WebInputEvent* event = get<0>(params);
+ EXPECT_EQ(blink::WebInputEvent::MouseMove, event->type);
+ break;
+ }
+ case ViewMsg_SwapCompositorFrameAck::ID:
+ break;
+ case ViewMsg_Resize::ID: {
+ EXPECT_FALSE(has_resize);
+ ViewMsg_Resize::Param params;
+ ViewMsg_Resize::Read(msg, &params);
+ EXPECT_EQ(size3.ToString(), get<0>(params).new_size.ToString());
+ has_resize = true;
+ break;
+ }
+ default:
+ ADD_FAILURE() << "Unexpected message " << msg->type();
+ break;
+ }
}
+ EXPECT_TRUE(has_resize);
update_params.view_size = size3;
widget_host_->OnMessageReceived(
ViewHostMsg_UpdateRect(widget_host_->GetRoutingID(), update_params));
@@ -1644,8 +1820,10 @@ TEST_F(RenderWidgetHostViewAuraTest, OutputSurfaceIdChange) {
}
TEST_F(RenderWidgetHostViewAuraTest, DiscardDelegatedFrames) {
+ view_->InitAsChild(NULL);
+
size_t max_renderer_frames =
- RendererFrameManager::GetInstance()->max_number_of_saved_frames();
+ RendererFrameManager::GetInstance()->GetMaxNumberOfSavedFrames();
ASSERT_LE(2u, max_renderer_frames);
size_t renderer_count = max_renderer_frames + 1;
gfx::Rect view_rect(100, 100);
@@ -1673,11 +1851,11 @@ TEST_F(RenderWidgetHostViewAuraTest, DiscardDelegatedFrames) {
// Make each renderer visible, and swap a frame on it, then make it invisible.
for (size_t i = 0; i < renderer_count; ++i) {
- views[i]->WasShown();
+ views[i]->Show();
views[i]->OnSwapCompositorFrame(
1, MakeDelegatedFrame(1.f, frame_size, view_rect));
EXPECT_TRUE(views[i]->HasFrameData());
- views[i]->WasHidden();
+ views[i]->Hide();
}
// There should be max_renderer_frames with a frame in it, and one without it.
@@ -1687,7 +1865,7 @@ TEST_F(RenderWidgetHostViewAuraTest, DiscardDelegatedFrames) {
EXPECT_TRUE(views[i]->HasFrameData());
// LRU renderer is [0], make it visible, it shouldn't evict anything yet.
- views[0]->WasShown();
+ views[0]->Show();
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
@@ -1701,7 +1879,7 @@ TEST_F(RenderWidgetHostViewAuraTest, DiscardDelegatedFrames) {
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();
+ views[0]->Hide();
// LRU renderer is [1], still hidden. Swap a frame on it, it should evict
// the next LRU [2].
@@ -1716,7 +1894,7 @@ TEST_F(RenderWidgetHostViewAuraTest, DiscardDelegatedFrames) {
// 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();
+ views[i]->Show();
// 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.
@@ -1737,7 +1915,7 @@ TEST_F(RenderWidgetHostViewAuraTest, DiscardDelegatedFrames) {
// Make [0] visible, and swap a frame on it. Nothing should be evicted
// although we're above the limit.
- views[0]->WasShown();
+ views[0]->Show();
// We don't have a frame, wait.
EXPECT_TRUE(views[0]->released_front_lock_active());
views[0]->OnSwapCompositorFrame(
@@ -1747,55 +1925,54 @@ TEST_F(RenderWidgetHostViewAuraTest, DiscardDelegatedFrames) {
EXPECT_TRUE(views[i]->HasFrameData());
// Make [0] hidden, it should evict its frame.
- views[0]->WasHidden();
+ views[0]->Hide();
EXPECT_FALSE(views[0]->HasFrameData());
// Make [0] visible, don't give it a frame, it should be waiting.
- views[0]->WasShown();
+ views[0]->Show();
EXPECT_TRUE(views[0]->released_front_lock_active());
// Make [0] hidden, it should stop waiting.
- views[0]->WasHidden();
+ views[0]->Hide();
EXPECT_FALSE(views[0]->released_front_lock_active());
// Make [1] hidden, resize it. It should drop its frame.
- views[1]->WasHidden();
+ views[1]->Hide();
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();
+ views[1]->Show();
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();
+ views[i]->Hide();
// Allocate enough bitmaps so that two frames (proportionally) would be
// enough hit the handle limit.
int handles_per_frame = 5;
RendererFrameManager::GetInstance()->set_max_handles(handles_per_frame * 2);
+ HostSharedBitmapManagerClient bitmap_client(
+ HostSharedBitmapManager::current());
+
for (size_t i = 0; i < (renderer_count - 1) * handles_per_frame; i++) {
- HostSharedBitmapManager::current()->ChildAllocatedSharedBitmap(
- 1,
- base::SharedMemory::NULLHandle(),
- base::GetCurrentProcessHandle(),
+ bitmap_client.ChildAllocatedSharedBitmap(
+ 1, base::SharedMemory::NULLHandle(), base::GetCurrentProcessHandle(),
cc::SharedBitmap::GenerateId());
}
// Hiding this last bitmap should evict all but two frames.
- views[renderer_count - 1]->WasHidden();
+ views[renderer_count - 1]->Hide();
for (size_t i = 0; i < renderer_count; ++i) {
if (i + 2 < renderer_count)
EXPECT_FALSE(views[i]->HasFrameData());
else
EXPECT_TRUE(views[i]->HasFrameData());
}
- HostSharedBitmapManager::current()->ProcessRemoved(
- base::GetCurrentProcessHandle());
RendererFrameManager::GetInstance()->set_max_handles(
base::SharedMemory::GetHandleLimit());
@@ -1806,8 +1983,10 @@ TEST_F(RenderWidgetHostViewAuraTest, DiscardDelegatedFrames) {
}
TEST_F(RenderWidgetHostViewAuraTest, DiscardDelegatedFramesWithLocking) {
+ view_->InitAsChild(NULL);
+
size_t max_renderer_frames =
- RendererFrameManager::GetInstance()->max_number_of_saved_frames();
+ RendererFrameManager::GetInstance()->GetMaxNumberOfSavedFrames();
ASSERT_LE(2u, max_renderer_frames);
size_t renderer_count = max_renderer_frames + 1;
gfx::Rect view_rect(100, 100);
@@ -1836,23 +2015,23 @@ TEST_F(RenderWidgetHostViewAuraTest, DiscardDelegatedFramesWithLocking) {
// Make each renderer visible and swap a frame on it. No eviction should
// occur because all frames are visible.
for (size_t i = 0; i < renderer_count; ++i) {
- views[i]->WasShown();
+ views[i]->Show();
views[i]->OnSwapCompositorFrame(
1, MakeDelegatedFrame(1.f, frame_size, view_rect));
EXPECT_TRUE(views[i]->HasFrameData());
}
// If we hide [0], then [0] should be evicted.
- views[0]->WasHidden();
+ views[0]->Hide();
EXPECT_FALSE(views[0]->HasFrameData());
// If we lock [0] before hiding it, then [0] should not be evicted.
- views[0]->WasShown();
+ views[0]->Show();
views[0]->OnSwapCompositorFrame(
1, MakeDelegatedFrame(1.f, frame_size, view_rect));
EXPECT_TRUE(views[0]->HasFrameData());
views[0]->GetDelegatedFrameHost()->LockResources();
- views[0]->WasHidden();
+ views[0]->Hide();
EXPECT_TRUE(views[0]->HasFrameData());
// If we unlock [0] now, then [0] should be evicted.
@@ -1865,6 +2044,72 @@ TEST_F(RenderWidgetHostViewAuraTest, DiscardDelegatedFramesWithLocking) {
}
}
+// Test that changing the memory pressure should delete saved frames. This test
+// only applies to ChromeOS.
+TEST_F(RenderWidgetHostViewAuraTest, DiscardDelegatedFramesWithMemoryPressure) {
+ view_->InitAsChild(NULL);
+
+ size_t max_renderer_frames =
+ RendererFrameManager::GetInstance()->GetMaxNumberOfSavedFrames();
+ ASSERT_LE(2u, max_renderer_frames);
+ size_t renderer_count = max_renderer_frames;
+ gfx::Rect view_rect(100, 100);
+ gfx::Size frame_size = view_rect.size();
+ DCHECK_EQ(0u, HostSharedBitmapManager::current()->AllocatedBitmapCount());
+
+ scoped_ptr<RenderWidgetHostImpl * []> hosts(
+ new RenderWidgetHostImpl* [renderer_count]);
+ scoped_ptr<FakeRenderWidgetHostViewAura * []> views(
+ new FakeRenderWidgetHostViewAura* [renderer_count]);
+
+ // Create a bunch of renderers.
+ for (size_t i = 0; i < renderer_count; ++i) {
+ hosts[i] = new RenderWidgetHostImpl(
+ &delegate_, process_host_, MSG_ROUTING_NONE, false);
+ hosts[i]->Init();
+ views[i] = new FakeRenderWidgetHostViewAura(hosts[i], false);
+ views[i]->InitAsChild(NULL);
+ aura::client::ParentWindowWithContext(
+ views[i]->GetNativeView(),
+ parent_view_->GetNativeView()->GetRootWindow(),
+ gfx::Rect());
+ views[i]->SetSize(view_rect.size());
+ }
+
+ // Make each renderer visible and swap a frame on it. No eviction should
+ // occur because all frames are visible.
+ for (size_t i = 0; i < renderer_count; ++i) {
+ views[i]->Show();
+ views[i]->OnSwapCompositorFrame(
+ 1, MakeDelegatedFrame(1.f, frame_size, view_rect));
+ EXPECT_TRUE(views[i]->HasFrameData());
+ }
+
+ // If we hide one, it should not get evicted.
+ views[0]->Hide();
+ message_loop_.RunUntilIdle();
+ EXPECT_TRUE(views[0]->HasFrameData());
+ // Using a lesser memory pressure event however, should evict.
+ SimulateMemoryPressure(
+ base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE);
+ message_loop_.RunUntilIdle();
+ EXPECT_FALSE(views[0]->HasFrameData());
+
+ // Check the same for a higher pressure event.
+ views[1]->Hide();
+ message_loop_.RunUntilIdle();
+ EXPECT_TRUE(views[1]->HasFrameData());
+ SimulateMemoryPressure(
+ base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
+ message_loop_.RunUntilIdle();
+ EXPECT_FALSE(views[1]->HasFrameData());
+
+ for (size_t i = 0; i < renderer_count; ++i) {
+ views[i]->Destroy();
+ delete hosts[i];
+ }
+}
+
TEST_F(RenderWidgetHostViewAuraTest, SoftwareDPIChange) {
gfx::Rect view_rect(100, 100);
gfx::Size frame_size(100, 100);
@@ -1875,7 +2120,7 @@ TEST_F(RenderWidgetHostViewAuraTest, SoftwareDPIChange) {
parent_view_->GetNativeView()->GetRootWindow(),
gfx::Rect());
view_->SetSize(view_rect.size());
- view_->WasShown();
+ view_->Show();
// With a 1x DPI UI and 1x DPI Renderer.
view_->OnSwapCompositorFrame(
@@ -1906,38 +2151,133 @@ class RenderWidgetHostViewAuraCopyRequestTest
RenderWidgetHostViewAuraCopyRequestTest()
: callback_count_(0), result_(false) {}
- void CallbackMethod(const base::Closure& quit_closure, bool result) {
+ void CallbackMethod(bool result) {
result_ = result;
callback_count_++;
- quit_closure.Run();
+ quit_closure_.Run();
+ }
+
+ void RunLoopUntilCallback() {
+ base::RunLoop run_loop;
+ quit_closure_ = run_loop.QuitClosure();
+ run_loop.Run();
}
int callback_count_;
bool result_;
private:
+ base::Closure quit_closure_;
+
DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewAuraCopyRequestTest);
};
-TEST_F(RenderWidgetHostViewAuraCopyRequestTest, DestroyedAfterCopyRequest) {
- base::RunLoop run_loop;
+// Tests that only one copy/readback request will be executed per one browser
+// composite operation, even when multiple render frame swaps occur in between
+// browser composites, and even if the frame subscriber desires more frames than
+// the number of browser composites.
+TEST_F(RenderWidgetHostViewAuraCopyRequestTest, DedupeFrameSubscriberRequests) {
+ gfx::Rect view_rect(100, 100);
+ scoped_ptr<cc::CopyOutputRequest> request;
+
+ view_->InitAsChild(NULL);
+ view_->GetDelegatedFrameHost()->SetRequestCopyOfOutputCallbackForTesting(
+ base::Bind(&FakeRenderWidgetHostViewAura::InterceptCopyOfOutput,
+ base::Unretained(view_)));
+ aura::client::ParentWindowWithContext(
+ view_->GetNativeView(),
+ parent_view_->GetNativeView()->GetRootWindow(),
+ gfx::Rect());
+ view_->SetSize(view_rect.size());
+ view_->Show();
+
+ view_->BeginFrameSubscription(make_scoped_ptr(new FakeFrameSubscriber(
+ view_rect.size(),
+ base::Bind(&RenderWidgetHostViewAuraCopyRequestTest::CallbackMethod,
+ base::Unretained(this)))).Pass());
+ int expected_callback_count = 0;
+ ASSERT_EQ(expected_callback_count, callback_count_);
+ ASSERT_FALSE(view_->last_copy_request_);
+
+ // Normal case: A browser composite executes for each render frame swap.
+ for (int i = 0; i < 3; ++i) {
+ // Renderer provides another frame.
+ view_->OnSwapCompositorFrame(
+ 1, MakeDelegatedFrame(1.f, view_rect.size(), gfx::Rect(view_rect)));
+ ASSERT_TRUE(view_->last_copy_request_);
+ request = view_->last_copy_request_.Pass();
+
+ // Browser composites with the frame, executing the copy request, and then
+ // the result is delivered.
+ view_->RunOnCompositingDidCommit();
+ request->SendTextureResult(view_rect.size(),
+ request->texture_mailbox(),
+ scoped_ptr<cc::SingleReleaseCallback>());
+ RunLoopUntilCallback();
+
+ // The callback should be run with success status.
+ ++expected_callback_count;
+ ASSERT_EQ(expected_callback_count, callback_count_);
+ EXPECT_TRUE(result_);
+ }
+
+ // De-duping case: One browser composite executes per varied number of render
+ // frame swaps.
+ for (int i = 0; i < 3; ++i) {
+ const int num_swaps = 1 + i % 3;
+
+ // The renderer provides |num_swaps| frames.
+ for (int j = 0; j < num_swaps; ++j) {
+ view_->OnSwapCompositorFrame(
+ 1, MakeDelegatedFrame(1.f, view_rect.size(), gfx::Rect(view_rect)));
+ ASSERT_TRUE(view_->last_copy_request_);
+ // The following statement simulates the layer de-duping the copy request
+ // coming from the same source (i.e., the DelegatedFrameHost):
+ request = view_->last_copy_request_.Pass();
+ if (j > 0) {
+ ++expected_callback_count;
+ ASSERT_EQ(expected_callback_count, callback_count_);
+ EXPECT_FALSE(result_); // The prior copy request was aborted.
+ }
+ }
+
+ // Browser composites with the frame, executing the last copy request that
+ // was made, and then the result is delivered.
+ view_->RunOnCompositingDidCommit();
+ request->SendTextureResult(view_rect.size(),
+ request->texture_mailbox(),
+ scoped_ptr<cc::SingleReleaseCallback>());
+ RunLoopUntilCallback();
+ // The final callback should be run with success status.
+ ++expected_callback_count;
+ ASSERT_EQ(expected_callback_count, callback_count_);
+ EXPECT_TRUE(result_);
+ }
+
+ // Destroy the RenderWidgetHostViewAura and ImageTransportFactory.
+ TearDownEnvironment();
+}
+
+TEST_F(RenderWidgetHostViewAuraCopyRequestTest, DestroyedAfterCopyRequest) {
gfx::Rect view_rect(100, 100);
scoped_ptr<cc::CopyOutputRequest> request;
view_->InitAsChild(NULL);
+ view_->GetDelegatedFrameHost()->SetRequestCopyOfOutputCallbackForTesting(
+ base::Bind(&FakeRenderWidgetHostViewAura::InterceptCopyOfOutput,
+ base::Unretained(view_)));
aura::client::ParentWindowWithContext(
view_->GetNativeView(),
parent_view_->GetNativeView()->GetRootWindow(),
gfx::Rect());
view_->SetSize(view_rect.size());
- view_->WasShown();
+ view_->Show();
scoped_ptr<FakeFrameSubscriber> frame_subscriber(new FakeFrameSubscriber(
view_rect.size(),
base::Bind(&RenderWidgetHostViewAuraCopyRequestTest::CallbackMethod,
- base::Unretained(this),
- run_loop.QuitClosure())));
+ base::Unretained(this))));
EXPECT_EQ(0, callback_count_);
EXPECT_FALSE(view_->last_copy_request_);
@@ -1951,14 +2291,15 @@ TEST_F(RenderWidgetHostViewAuraCopyRequestTest, DestroyedAfterCopyRequest) {
EXPECT_TRUE(view_->last_copy_request_->has_texture_mailbox());
request = view_->last_copy_request_.Pass();
+ // Notify DelegatedFrameHost that the copy requests were moved to the
+ // compositor thread by calling OnCompositingDidCommit().
+ view_->RunOnCompositingDidCommit();
// Send back the mailbox included in the request. There's no release callback
// since the mailbox came from the RWHVA originally.
request->SendTextureResult(view_rect.size(),
request->texture_mailbox(),
scoped_ptr<cc::SingleReleaseCallback>());
-
- // This runs until the callback happens.
- run_loop.Run();
+ RunLoopUntilCallback();
// The callback should succeed.
EXPECT_EQ(1, callback_count_);
@@ -1973,8 +2314,8 @@ TEST_F(RenderWidgetHostViewAuraCopyRequestTest, DestroyedAfterCopyRequest) {
// Destroy the RenderWidgetHostViewAura and ImageTransportFactory.
TearDownEnvironment();
- // Send back the mailbox included in the request. There's no release callback
- // since the mailbox came from the RWHVA originally.
+ // Send the result after-the-fact. It goes nowhere since DelegatedFrameHost
+ // has been destroyed.
request->SendTextureResult(view_rect.size(),
request->texture_mailbox(),
scoped_ptr<cc::SingleReleaseCallback>());
@@ -1996,7 +2337,7 @@ TEST_F(RenderWidgetHostViewAuraTest, VisibleViewportTest) {
parent_view_->GetNativeView()->GetRootWindow(),
gfx::Rect());
view_->SetSize(view_rect.size());
- view_->WasShown();
+ view_->Show();
// Defaults to full height of the view.
EXPECT_EQ(100, view_->GetVisibleViewportSize().height());
@@ -2013,7 +2354,7 @@ TEST_F(RenderWidgetHostViewAuraTest, VisibleViewportTest) {
ViewMsg_Resize::Param params;
ViewMsg_Resize::Read(message, &params);
- EXPECT_EQ(60, params.a.visible_viewport_size.height());
+ EXPECT_EQ(60, get<0>(params).visible_viewport_size.height());
}
// Ensures that touch event positions are never truncated to integers.
@@ -2030,15 +2371,15 @@ TEST_F(RenderWidgetHostViewAuraTest, TouchEventPositionsArentRounded) {
ui::EventTimeForNow());
view_->OnTouchEvent(&press);
- EXPECT_EQ(blink::WebInputEvent::TouchStart, view_->touch_event_.type);
- EXPECT_TRUE(view_->touch_event_.cancelable);
- EXPECT_EQ(1U, view_->touch_event_.touchesLength);
+ EXPECT_EQ(blink::WebInputEvent::TouchStart, view_->touch_event_->type);
+ EXPECT_TRUE(view_->touch_event_->cancelable);
+ EXPECT_EQ(1U, view_->touch_event_->touchesLength);
EXPECT_EQ(blink::WebTouchPoint::StatePressed,
- view_->touch_event_.touches[0].state);
- EXPECT_EQ(kX, view_->touch_event_.touches[0].screenPosition.x);
- EXPECT_EQ(kX, view_->touch_event_.touches[0].position.x);
- EXPECT_EQ(kY, view_->touch_event_.touches[0].screenPosition.y);
- EXPECT_EQ(kY, view_->touch_event_.touches[0].position.y);
+ view_->touch_event_->touches[0].state);
+ EXPECT_EQ(kX, view_->touch_event_->touches[0].screenPosition.x);
+ EXPECT_EQ(kX, view_->touch_event_->touches[0].position.x);
+ EXPECT_EQ(kY, view_->touch_event_->touches[0].screenPosition.y);
+ EXPECT_EQ(kY, view_->touch_event_->touches[0].position.y);
}
// Tests that scroll ACKs are correctly handled by the overscroll-navigation
@@ -2866,6 +3207,10 @@ TEST_F(RenderWidgetHostViewAuraOverscrollTest,
EXPECT_TRUE(ScrollStateIsUnknown());
EXPECT_EQ(0U, sink_->message_count());
+ // Dropped flings should neither propagate *nor* indicate that they were
+ // consumed and have triggered a fling animation (as tracked by the router).
+ EXPECT_FALSE(parent_host_->input_router()->HasPendingEvents());
+
SimulateWheelEvent(-5, 0, 0, true); // sent directly
SimulateWheelEvent(-60, 0, 0, true); // enqueued
SimulateWheelEvent(-100, 0, 0, true); // coalesced into previous event
@@ -2890,6 +3235,7 @@ TEST_F(RenderWidgetHostViewAuraOverscrollTest,
EXPECT_EQ(OVERSCROLL_WEST, overscroll_delegate()->completed_mode());
EXPECT_TRUE(ScrollStateIsUnknown());
EXPECT_EQ(0U, sink_->message_count());
+ EXPECT_FALSE(parent_host_->input_router()->HasPendingEvents());
}
TEST_F(RenderWidgetHostViewAuraOverscrollTest, OverscrollResetsOnBlur) {
@@ -2939,8 +3285,196 @@ TEST_F(RenderWidgetHostViewAuraOverscrollTest, OverscrollResetsOnBlur) {
// 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) {
+ view_->InitAsChild(NULL);
TearDownEnvironment();
ASSERT_FALSE(guest_view_weak_.get());
}
+// Tests that invalid touch events are consumed and handled
+// synchronously.
+TEST_F(RenderWidgetHostViewAuraTest,
+ InvalidEventsHaveSyncHandlingDisabled) {
+ view_->InitAsChild(NULL);
+ view_->Show();
+ GetSentMessageCountAndResetSink();
+
+ widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, true));
+
+ ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(30, 30), 0,
+ ui::EventTimeForNow());
+
+ // Construct a move with a touch id which doesn't exist.
+ ui::TouchEvent invalid_move(ui::ET_TOUCH_MOVED, gfx::Point(30, 30), 1,
+ ui::EventTimeForNow());
+
+ // Valid press is handled asynchronously.
+ view_->OnTouchEvent(&press);
+ EXPECT_TRUE(press.synchronous_handling_disabled());
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+ AckLastSentInputEventIfNecessary(INPUT_EVENT_ACK_STATE_CONSUMED);
+
+ // Invalid move is handled synchronously, but is consumed. It should not
+ // be forwarded to the renderer.
+ view_->OnTouchEvent(&invalid_move);
+ EXPECT_EQ(0U, GetSentMessageCountAndResetSink());
+ EXPECT_FALSE(invalid_move.synchronous_handling_disabled());
+ EXPECT_TRUE(invalid_move.stopped_propagation());
+}
+
+// Checks key event codes.
+TEST_F(RenderWidgetHostViewAuraTest, KeyEvent) {
+ view_->InitAsChild(NULL);
+ view_->Show();
+
+ ui::KeyEvent key_event(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::DomCode::KEY_A,
+ ui::EF_NONE);
+ view_->OnKeyEvent(&key_event);
+
+ const NativeWebKeyboardEvent* event = delegate_.last_event();
+ EXPECT_NE(nullptr, event);
+ if (event) {
+ EXPECT_EQ(key_event.key_code(), event->windowsKeyCode);
+ EXPECT_EQ(ui::KeycodeConverter::DomCodeToNativeKeycode(key_event.code()),
+ event->nativeKeyCode);
+ }
+}
+
+TEST_F(RenderWidgetHostViewAuraTest, SetCanScrollForWebMouseWheelEvent) {
+ view_->InitAsChild(NULL);
+ view_->Show();
+
+ sink_->ClearMessages();
+
+ // Simulates the mouse wheel event with ctrl modifier applied.
+ ui::MouseWheelEvent event(gfx::Vector2d(1, 1), gfx::Point(), gfx::Point(),
+ ui::EventTimeForNow(), ui::EF_CONTROL_DOWN, 0);
+ view_->OnMouseEvent(&event);
+
+ const WebInputEvent* input_event =
+ GetInputEventFromMessage(*sink_->GetMessageAt(0));
+ const WebMouseWheelEvent* wheel_event =
+ static_cast<const WebMouseWheelEvent*>(input_event);
+ // Check if the canScroll set to false when ctrl-scroll is generated from
+ // mouse wheel event.
+ EXPECT_FALSE(wheel_event->canScroll);
+ sink_->ClearMessages();
+
+ // Ack'ing the outstanding event should flush the pending event queue.
+ SendInputEventACK(blink::WebInputEvent::MouseWheel,
+ INPUT_EVENT_ACK_STATE_CONSUMED);
+
+ // Simulates the mouse wheel event with no modifier applied.
+ event = ui::MouseWheelEvent(gfx::Vector2d(1, 1), gfx::Point(), gfx::Point(),
+ ui::EventTimeForNow(), ui::EF_NONE, 0);
+
+ view_->OnMouseEvent(&event);
+
+ input_event = GetInputEventFromMessage(*sink_->GetMessageAt(0));
+ wheel_event = static_cast<const WebMouseWheelEvent*>(input_event);
+ // Check if the canScroll set to true when no modifier is applied to the
+ // mouse wheel event.
+ EXPECT_TRUE(wheel_event->canScroll);
+ sink_->ClearMessages();
+
+ SendInputEventACK(blink::WebInputEvent::MouseWheel,
+ INPUT_EVENT_ACK_STATE_CONSUMED);
+
+ // Simulates the scroll event with ctrl modifier applied.
+ ui::ScrollEvent scroll(ui::ET_SCROLL, gfx::Point(2, 2), ui::EventTimeForNow(),
+ ui::EF_CONTROL_DOWN, 0, 5, 0, 5, 2);
+ view_->OnScrollEvent(&scroll);
+
+ input_event = GetInputEventFromMessage(*sink_->GetMessageAt(0));
+ wheel_event = static_cast<const WebMouseWheelEvent*>(input_event);
+ // Check if the canScroll set to true when ctrl-touchpad-scroll is generated
+ // from scroll event.
+ EXPECT_TRUE(wheel_event->canScroll);
+}
+
+// Ensures that the mapping from ui::TouchEvent to blink::WebTouchEvent doesn't
+// lose track of the number of acks required.
+TEST_F(RenderWidgetHostViewAuraTest, CorrectNumberOfAcksAreDispatched) {
+ view_->InitAsFullscreen(parent_view_);
+ view_->Show();
+ view_->UseFakeDispatcher();
+
+ ui::TouchEvent press1(
+ ui::ET_TOUCH_PRESSED, gfx::Point(30, 30), 0, ui::EventTimeForNow());
+
+ view_->OnTouchEvent(&press1);
+ SendInputEventACK(blink::WebInputEvent::TouchStart,
+ INPUT_EVENT_ACK_STATE_CONSUMED);
+
+ ui::TouchEvent press2(
+ ui::ET_TOUCH_PRESSED, gfx::Point(20, 20), 1, ui::EventTimeForNow());
+ view_->OnTouchEvent(&press2);
+ SendInputEventACK(blink::WebInputEvent::TouchStart,
+ INPUT_EVENT_ACK_STATE_CONSUMED);
+
+ EXPECT_EQ(2U, view_->dispatcher_->GetAndResetProcessedTouchEventCount());
+}
+
+// Tests that the scroll deltas stored within the overscroll controller get
+// reset at the end of the overscroll gesture even if the overscroll threshold
+// isn't surpassed and the overscroll mode stays OVERSCROLL_NONE.
+TEST_F(RenderWidgetHostViewAuraOverscrollTest, ScrollDeltasResetOnEnd) {
+ SetUpOverscrollEnvironment();
+ // Wheel event scroll ending with mouse move.
+ SimulateWheelEvent(-30, -10, 0, true); // sent directly
+ SendInputEventACK(WebInputEvent::MouseWheel,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode());
+ EXPECT_EQ(-30.f, overscroll_delta_x());
+ EXPECT_EQ(-10.f, overscroll_delta_y());
+ SimulateMouseMove(5, 10, 0);
+ EXPECT_EQ(0.f, overscroll_delta_x());
+ EXPECT_EQ(0.f, overscroll_delta_y());
+
+ // Scroll gesture.
+ SimulateGestureEvent(WebInputEvent::GestureScrollBegin,
+ blink::WebGestureDeviceTouchscreen);
+ SimulateGestureScrollUpdateEvent(-30, -5, 0);
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode());
+ EXPECT_EQ(-30.f, overscroll_delta_x());
+ EXPECT_EQ(-5.f, overscroll_delta_y());
+ SimulateGestureEvent(WebInputEvent::GestureScrollEnd,
+ blink::WebGestureDeviceTouchscreen);
+ EXPECT_EQ(0.f, overscroll_delta_x());
+ EXPECT_EQ(0.f, overscroll_delta_y());
+
+ // Wheel event scroll ending with a fling.
+ SimulateWheelEvent(5, 0, 0, true);
+ SendInputEventACK(WebInputEvent::MouseWheel,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ SimulateWheelEvent(10, -5, 0, true);
+ SendInputEventACK(WebInputEvent::MouseWheel,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode());
+ EXPECT_EQ(15.f, overscroll_delta_x());
+ EXPECT_EQ(-5.f, overscroll_delta_y());
+ SimulateGestureFlingStartEvent(0.f, 0.1f, blink::WebGestureDeviceTouchpad);
+ EXPECT_EQ(0.f, overscroll_delta_x());
+ EXPECT_EQ(0.f, overscroll_delta_y());
+}
+
+// Tests the RenderWidgetHostImpl sends the correct surface ID namespace to
+// the renderer process.
+TEST_F(RenderWidgetHostViewAuraTest, SurfaceIdNamespaceInitialized) {
+ gfx::Size size(5, 5);
+
+ const IPC::Message* msg =
+ sink_->GetUniqueMessageMatching(ViewMsg_SetSurfaceIdNamespace::ID);
+ EXPECT_TRUE(msg);
+ ViewMsg_SetSurfaceIdNamespace::Param params;
+ ViewMsg_SetSurfaceIdNamespace::Read(msg, &params);
+ view_->InitAsChild(NULL);
+ view_->Show();
+ view_->SetSize(size);
+ view_->OnSwapCompositorFrame(0,
+ MakeDelegatedFrame(1.f, size, gfx::Rect(size)));
+ EXPECT_EQ(view_->GetSurfaceIdNamespace(), get<0>(params));
+}
+
} // 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 b11990ae990..83f29aa8a00 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
@@ -5,6 +5,7 @@
#include "content/browser/renderer_host/render_widget_host_view_base.h"
#include "base/logging.h"
+#include "base/profiler/scoped_tracker.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/browser/gpu/gpu_data_manager_impl.h"
#include "content/browser/renderer_host/input/synthetic_gesture_target_base.h"
@@ -13,9 +14,9 @@
#include "content/common/content_switches_internal.h"
#include "content/public/browser/render_widget_host_view_frame_subscriber.h"
#include "ui/gfx/display.h"
+#include "ui/gfx/geometry/size_conversions.h"
+#include "ui/gfx/geometry/size_f.h"
#include "ui/gfx/screen.h"
-#include "ui/gfx/size_conversions.h"
-#include "ui/gfx/size_f.h"
#if defined(OS_WIN)
#include "base/command_line.h"
@@ -83,6 +84,10 @@ void NotifyPluginProcessHostHelper(HWND window, HWND parent, int tries) {
// parent which is typically the RVH window which turns on user gesture.
LRESULT CALLBACK PluginWrapperWindowProc(HWND window, unsigned int message,
WPARAM wparam, LPARAM lparam) {
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION("440919 PluginWrapperWindowProc"));
+
if (message == WM_PARENTNOTIFY) {
switch (LOWORD(wparam)) {
case WM_LBUTTONDOWN:
@@ -186,8 +191,8 @@ void RenderWidgetHostViewBase::MovePluginWindowsHelper(
if (moves.empty())
return;
- bool oop_plugins =
- !CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess);
+ bool oop_plugins = !base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSingleProcess);
HDWP defer_window_pos_info =
::BeginDeferWindowPos(static_cast<int>(moves.size()));
@@ -406,7 +411,11 @@ gfx::Size RenderWidgetHostViewBase::GetPhysicalBackingSize() const {
display.device_scale_factor()));
}
-float RenderWidgetHostViewBase::GetTopControlsLayoutHeight() const {
+bool RenderWidgetHostViewBase::DoTopControlsShrinkBlinkSize() const {
+ return false;
+}
+
+float RenderWidgetHostViewBase::GetTopControlsHeight() const {
return 0.f;
}
@@ -455,10 +464,6 @@ InputEventAckState RenderWidgetHostViewBase::FilterInputEvent(
return INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
}
-void RenderWidgetHostViewBase::OnDidFlushInput() {
- // The notification can safely be ignored by most implementations.
-}
-
void RenderWidgetHostViewBase::OnSetNeedsFlushInput() {
if (flush_input_timer_.IsRunning())
return;
@@ -605,10 +610,6 @@ void RenderWidgetHostViewBase::FlushInput() {
impl->FlushInput();
}
-SkColorType RenderWidgetHostViewBase::PreferredReadbackFormat() {
- return kN32_SkColorType;
-}
-
void RenderWidgetHostViewBase::OnTextSurroundingSelectionResponse(
const base::string16& content,
size_t start_offset,
@@ -691,4 +692,11 @@ RenderWidgetHostViewBase::GetOrientationTypeForDesktop(
: blink::WebScreenOrientationLandscapeSecondary;
}
+void RenderWidgetHostViewBase::OnDidNavigateMainFrameToNewPage() {
+}
+
+uint32_t RenderWidgetHostViewBase::GetSurfaceIdNamespace() {
+ return 0;
+}
+
} // 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 9e3a4f384ca..ba64be727df 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
@@ -12,14 +12,15 @@
#include <string>
#include <vector>
-#include "base/memory/scoped_ptr.h"
#include "base/callback_forward.h"
+#include "base/memory/scoped_ptr.h"
#include "base/process/kill.h"
#include "base/timer/timer.h"
#include "cc/output/compositor_frame.h"
#include "content/browser/renderer_host/event_with_latency_info.h"
#include "content/common/content_export.h"
#include "content/common/input/input_event_ack_state.h"
+#include "content/public/browser/readback_types.h"
#include "content/public/browser/render_widget_host_view.h"
#include "ipc/ipc_listener.h"
#include "third_party/WebKit/public/platform/WebScreenOrientationType.h"
@@ -28,9 +29,9 @@
#include "ui/base/ime/text_input_mode.h"
#include "ui/base/ime/text_input_type.h"
#include "ui/gfx/display.h"
+#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/range/range.h"
-#include "ui/gfx/rect.h"
#include "ui/surface/transport_dib.h"
class SkBitmap;
@@ -56,12 +57,6 @@ 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 {
@@ -73,6 +68,8 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView,
void SetBackgroundColorToDefault() final;
bool GetBackgroundOpaque() override;
ui::TextInputClient* GetTextInputClient() override;
+ void WasUnOccluded() override {}
+ void WasOccluded() override {}
bool IsShowingContextMenu() const override;
void SetShowingContextMenu(bool showing_menu) override;
base::string16 GetSelectedText() const override;
@@ -86,9 +83,6 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView,
// IPC::Listener implementation:
bool OnMessageReceived(const IPC::Message& msg) override;
- // Called by the host when the input flush has completed.
- void OnDidFlushInput();
-
void SetPopupType(blink::WebPopupType popup_type);
blink::WebPopupType GetPopupType();
@@ -125,8 +119,12 @@ 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 amount that the viewport size given to Blink is shrunk by the URL-bar.
- virtual float GetTopControlsLayoutHeight() const;
+ // Whether or not Blink's viewport size should be shrunk by the height of the
+ // URL-bar.
+ virtual bool DoTopControlsShrinkBlinkSize() const;
+
+ // The height of the URL-bar top controls.
+ virtual float GetTopControlsHeight() const;
// Called prior to forwarding input event messages to the renderer, giving
// the view a chance to perform in-process event filtering or processing.
@@ -161,8 +159,6 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView,
virtual gfx::AcceleratedWidget AccessibilityGetAcceleratedWidget();
virtual gfx::NativeViewAccessible AccessibilityGetNativeViewAccessible();
- virtual SkColorType PreferredReadbackFormat();
-
// Informs that the focused DOM node has changed.
virtual void FocusedNodeChanged(bool is_editable_node) {}
@@ -181,6 +177,10 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView,
virtual void DidStopFlinging() {}
+ // Returns the compositing surface ID namespace, or 0 if Surfaces are not
+ // enabled.
+ virtual uint32_t GetSurfaceIdNamespace();
+
//----------------------------------------------------------------------------
// The following static methods are implemented by each platform.
@@ -192,7 +192,7 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView,
// Perform all the initialization steps necessary for this object to represent
// a popup (such as a <select> dropdown), then shows the popup at |pos|.
virtual void InitAsPopup(RenderWidgetHostView* parent_host_view,
- const gfx::Rect& pos) = 0;
+ const gfx::Rect& bounds) = 0;
// Perform all the initialization steps necessary for this object to represent
// a full screen window.
@@ -200,20 +200,11 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView,
// helps to position the full screen widget on the correct monitor.
virtual void InitAsFullscreen(RenderWidgetHostView* reference_host_view) = 0;
- // Notifies the View that it has become visible.
- virtual void WasShown() = 0;
-
- // Notifies the View that it has been hidden.
- virtual void WasHidden() = 0;
-
// Moves all plugin windows as described in the given list.
// |scroll_offset| is the scroll offset of the render view.
virtual void MovePluginWindows(
const std::vector<WebPluginGeometry>& moves) = 0;
- // Take focus from the associated View component.
- virtual void Blur() = 0;
-
// Sets the cursor to the one associated with the specified cursor_type
virtual void UpdateCursor(const WebCursor& cursor) = 0;
@@ -257,15 +248,17 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView,
// 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|.
+ // physical for Android), and is the region to be copied from this view. When
+ // |src_subrect| is empty then the whole surface will be copied. The copy is
+ // then scaled to a SkBitmap of size |dst_size|. If |dst_size| is empty then
+ // output will be unscaled. |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,
- CopyFromCompositingSurfaceCallback& callback,
- const SkColorType color_type) = 0;
+ ReadbackRequestCallback& callback,
+ const SkColorType preferred_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
@@ -323,6 +316,10 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView,
virtual void ShowDisambiguationPopup(const gfx::Rect& rect_pixels,
const SkBitmap& zoomed_bitmap);
+ // Called by the WebContentsImpl when a user tries to navigate a new page on
+ // main frame.
+ virtual void OnDidNavigateMainFrameToNewPage();
+
#if defined(OS_ANDROID)
// Instructs the view to not drop the surface even when the view is hidden.
virtual void LockCompositingSurface() = 0;
@@ -338,12 +335,10 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView,
const NativeWebKeyboardEvent& event) = 0;
#endif
-#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,
const std::vector<gfx::Rect>& character_bounds) = 0;
-#endif
#if defined(OS_WIN)
virtual void SetParentNativeViewAccessible(
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 a04a117f292..7e6794a2a83 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
@@ -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/barrier_closure.h"
#include "base/command_line.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/path_service.h"
@@ -23,7 +24,7 @@
#include "content/public/test/content_browser_test_utils.h"
#include "content/shell/browser/shell.h"
#include "media/base/video_frame.h"
-#include "media/filters/skcanvas_video_renderer.h"
+#include "media/blink/skcanvas_video_renderer.h"
#include "net/base/filename_util.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkCanvas.h"
@@ -106,10 +107,10 @@ class RenderWidgetHostViewBrowserTest : public ContentBrowserTest {
// Callback when using CopyFromBackingStore() API.
void FinishCopyFromBackingStore(const base::Closure& quit_closure,
- bool frame_captured,
- const SkBitmap& bitmap) {
+ const SkBitmap& bitmap,
+ ReadbackResponse response) {
++callback_invoke_count_;
- if (frame_captured) {
+ if (response == READBACK_SUCCESS) {
++frames_captured_;
EXPECT_FALSE(bitmap.empty());
}
@@ -301,17 +302,8 @@ IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTest,
// Tests that the callback passed to CopyFromCompositingSurfaceToVideoFrame is
// always called, even when the RenderWidgetHost is deleting in the middle of
// an async copy.
-//
-// Test is flaky on Win. http://crbug.com/276783
-#if defined(OS_WIN) || (defined(OS_CHROMEOS) && !defined(NDEBUG))
-#define MAYBE_CopyFromCompositingSurface_CallbackDespiteDelete \
- DISABLED_CopyFromCompositingSurface_CallbackDespiteDelete
-#else
-#define MAYBE_CopyFromCompositingSurface_CallbackDespiteDelete \
- CopyFromCompositingSurface_CallbackDespiteDelete
-#endif
IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTest,
- MAYBE_CopyFromCompositingSurface_CallbackDespiteDelete) {
+ CopyFromCompositingSurface_CallbackDespiteDelete) {
SET_UP_SURFACE_OR_PASS_TEST(NULL);
RenderWidgetHostViewBase* const view = GetRenderWidgetHostView();
if (!view->CanCopyToVideoFrame()) {
@@ -360,7 +352,6 @@ IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTest,
EXPECT_LE(1, frames_captured());
}
-// Test that we can copy twice from an accelerated composited page.
IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTest, CopyTwice) {
SET_UP_SURFACE_OR_PASS_TEST(NULL);
RenderWidgetHostViewBase* const view = GetRenderWidgetHostView();
@@ -378,22 +369,17 @@ IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTest, CopyTwice) {
scoped_refptr<media::VideoFrame> second_output =
media::VideoFrame::CreateBlackFrame(frame_size());
ASSERT_TRUE(second_output.get());
+ base::Closure closure = base::BarrierClosure(2, run_loop.QuitClosure());
view->CopyFromCompositingSurfaceToVideoFrame(
- gfx::Rect(view->GetViewBounds().size()),
- first_output,
+ gfx::Rect(view->GetViewBounds().size()), first_output,
base::Bind(&RenderWidgetHostViewBrowserTest::FrameDelivered,
- base::Unretained(this),
- base::MessageLoopProxy::current(),
- base::Closure(),
- base::TimeTicks::Now()));
+ base::Unretained(this), base::MessageLoopProxy::current(),
+ closure, base::TimeTicks::Now()));
view->CopyFromCompositingSurfaceToVideoFrame(
- gfx::Rect(view->GetViewBounds().size()),
- second_output,
+ gfx::Rect(view->GetViewBounds().size()), second_output,
base::Bind(&RenderWidgetHostViewBrowserTest::FrameDelivered,
- base::Unretained(this),
- base::MessageLoopProxy::current(),
- run_loop.QuitClosure(),
- base::TimeTicks::Now()));
+ base::Unretained(this), base::MessageLoopProxy::current(),
+ closure, base::TimeTicks::Now()));
run_loop.Run();
EXPECT_EQ(2, callback_invoke_count());
@@ -404,7 +390,7 @@ class CompositingRenderWidgetHostViewBrowserTestTabCapture
: public CompositingRenderWidgetHostViewBrowserTest {
public:
CompositingRenderWidgetHostViewBrowserTestTabCapture()
- : expected_copy_from_compositing_surface_result_(false),
+ : readback_response_(READBACK_NO_RESPONSE),
allowable_error_(0),
test_url_("data:text/html,<!doctype html>") {}
@@ -413,22 +399,56 @@ class CompositingRenderWidgetHostViewBrowserTestTabCapture
CompositingRenderWidgetHostViewBrowserTest::SetUp();
}
- void CopyFromCompositingSurfaceCallback(base::Closure quit_callback,
- bool result,
- const SkBitmap& bitmap) {
- EXPECT_EQ(expected_copy_from_compositing_surface_result_, result);
- if (!result) {
+ void ReadbackRequestCallbackTest(base::Closure quit_callback,
+ const SkBitmap& bitmap,
+ ReadbackResponse response) {
+ readback_response_ = response;
+ if (response != READBACK_SUCCESS) {
quit_callback.Run();
return;
}
+ SkAutoLockPixels bitmap_lock(bitmap);
+
+ // Check that the |bitmap| contains cyan and/or yellow pixels. This is
+ // needed because the compositor will read back "blank" frames until the
+ // first frame from the renderer is composited. See comments in
+ // PerformTestWithLeftRightRects() for more details about eliminating test
+ // flakiness.
+ bool contains_a_test_color = false;
+ for (int i = 0; i < bitmap.width(); ++i) {
+ for (int j = 0; j < bitmap.height(); ++j) {
+ if (!exclude_rect_.IsEmpty() && exclude_rect_.Contains(i, j))
+ continue;
+
+ const unsigned high_threshold = 0xff - allowable_error_;
+ const unsigned low_threshold = 0x00 + allowable_error_;
+ const SkColor color = bitmap.getColor(i, j);
+ const bool is_cyan = SkColorGetR(color) <= low_threshold &&
+ SkColorGetG(color) >= high_threshold &&
+ SkColorGetB(color) >= high_threshold;
+ const bool is_yellow = SkColorGetR(color) >= high_threshold &&
+ SkColorGetG(color) >= high_threshold &&
+ SkColorGetB(color) <= low_threshold;
+ if (is_cyan || is_yellow) {
+ contains_a_test_color = true;
+ break;
+ }
+ }
+ }
+ if (!contains_a_test_color) {
+ readback_response_ = READBACK_NO_TEST_COLORS;
+ quit_callback.Run();
+ return;
+ }
+
+ // Compare the readback |bitmap| to the |expected_bitmap|, pixel-by-pixel.
const SkBitmap& expected_bitmap =
expected_copy_from_compositing_surface_bitmap_;
EXPECT_EQ(expected_bitmap.width(), bitmap.width());
EXPECT_EQ(expected_bitmap.height(), bitmap.height());
EXPECT_EQ(expected_bitmap.colorType(), bitmap.colorType());
SkAutoLockPixels expected_bitmap_lock(expected_bitmap);
- SkAutoLockPixels bitmap_lock(bitmap);
int fails = 0;
for (int i = 0; i < bitmap.width() && fails < 10; ++i) {
for (int j = 0; j < bitmap.height() && fails < 10; ++j) {
@@ -472,12 +492,12 @@ class CompositingRenderWidgetHostViewBrowserTestTabCapture
quit_callback.Run();
}
- void CopyFromCompositingSurfaceCallbackForVideo(
+ void ReadbackRequestCallbackForVideo(
scoped_refptr<media::VideoFrame> video_frame,
base::Closure quit_callback,
bool result) {
- EXPECT_EQ(expected_copy_from_compositing_surface_result_, result);
if (!result) {
+ readback_response_ = READBACK_TO_VIDEO_FRAME_FAILED;
quit_callback.Run();
return;
}
@@ -489,17 +509,9 @@ class CompositingRenderWidgetHostViewBrowserTestTabCapture
video_frame->visible_rect().height());
// Don't clear the canvas because drawing a video frame by Src mode.
SkCanvas canvas(bitmap);
- video_renderer.Copy(video_frame, &canvas);
+ video_renderer.Copy(video_frame, &canvas, media::Context3D());
- CopyFromCompositingSurfaceCallback(quit_callback,
- result,
- bitmap);
- }
-
- void SetExpectedCopyFromCompositingSurfaceResult(bool result,
- const SkBitmap& bitmap) {
- expected_copy_from_compositing_surface_result_ = result;
- expected_copy_from_compositing_surface_bitmap_ = bitmap;
+ ReadbackRequestCallbackTest(quit_callback, bitmap, READBACK_SUCCESS);
}
void SetAllowableError(int amount) { allowable_error_ = amount; }
@@ -554,80 +566,103 @@ class CompositingRenderWidgetHostViewBrowserTestTabCapture
if (!ShouldContinueAfterTestURLLoad())
return;
- RenderWidgetHostViewBase* rwhvp = GetRenderWidgetHostView();
- if (video_frame && !rwhvp->CanCopyToVideoFrame()) {
- // This should only happen on Mac when using the software compositor.
- // Otherwise, raise an error. This can be removed when Mac is moved to a
- // browser compositor.
- // http://crbug.com/314190
-#if defined(OS_MACOSX)
- if (!content::GpuDataManager::GetInstance()->GpuAccessAllowed(NULL)) {
- LOG(WARNING) << ("Blindly passing this test because copying to "
- "video frames is not supported on this platform.");
- return;
- }
-#endif
- NOTREACHED();
- }
-
- // The page is loaded in the renderer, wait for a new frame to arrive.
- uint32 frame = rwhvp->RendererFrameNumber();
- while (!GetRenderWidgetHost()->ScheduleComposite())
- GiveItSomeTime();
- while (rwhvp->RendererFrameNumber() == frame)
- GiveItSomeTime();
-
- SkBitmap expected_bitmap;
- SetupLeftRightBitmap(output_size, &expected_bitmap);
- SetExpectedCopyFromCompositingSurfaceResult(true, expected_bitmap);
+ RenderWidgetHostViewBase* rwhv = GetRenderWidgetHostView();
+ ASSERT_TRUE(!video_frame || rwhv->CanCopyToVideoFrame());
+
+ SetupLeftRightBitmap(output_size,
+ &expected_copy_from_compositing_surface_bitmap_);
+
+ // The page is loaded in the renderer. Request frames from the renderer
+ // until readback succeeds. When readback succeeds, the resulting
+ // SkBitmap/VideoFrame is examined to ensure it matches the expected result.
+ // This loop is needed because:
+ // 1. Painting/Compositing is not synchronous with the Javascript engine,
+ // and so the "DONE" signal above could be received before the renderer
+ // provides a frame with the expected content. http://crbug.com/405282
+ // 2. Avoiding test flakiness: On some platforms, the readback operation
+ // is allowed to transiently fail. The purpose of these tests is to
+ // confirm correct cropping/scaling behavior; and not that every
+ // readback must succeed. http://crbug.com/444237
+ uint32 last_frame_number = 0;
+ do {
+ // Wait for renderer to provide the next frame.
+ while (!GetRenderWidgetHost()->ScheduleComposite())
+ GiveItSomeTime();
+ while (rwhv->RendererFrameNumber() == last_frame_number)
+ GiveItSomeTime();
+ last_frame_number = rwhv->RendererFrameNumber();
- base::RunLoop run_loop;
- if (video_frame) {
- // Allow pixel differences as long as we have the right idea.
- SetAllowableError(0x10);
- // Exclude the middle two columns which are blended between the two sides.
- SetExcludeRect(
- gfx::Rect(output_size.width() / 2 - 1, 0, 2, output_size.height()));
-
- scoped_refptr<media::VideoFrame> video_frame =
- media::VideoFrame::CreateFrame(media::VideoFrame::YV12,
- output_size,
- gfx::Rect(output_size),
- output_size,
- base::TimeDelta());
-
- base::Callback<void(bool success)> callback =
- base::Bind(&CompositingRenderWidgetHostViewBrowserTestTabCapture::
- CopyFromCompositingSurfaceCallbackForVideo,
- base::Unretained(this),
- video_frame,
- run_loop.QuitClosure());
- rwhvp->CopyFromCompositingSurfaceToVideoFrame(copy_rect,
- video_frame,
- callback);
- } else {
- 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()));
+ // Request readback. The callbacks will examine the pixels in the
+ // SkBitmap/VideoFrame result if readback was successful.
+ readback_response_ = READBACK_NO_RESPONSE;
+ base::RunLoop run_loop;
+ if (video_frame) {
+ // Allow pixel differences as long as we have the right idea.
+ SetAllowableError(0x10);
+ // Exclude the middle two columns which are blended between the two
+ // sides.
+ SetExcludeRect(
+ gfx::Rect(output_size.width() / 2 - 1, 0, 2, output_size.height()));
+
+ scoped_refptr<media::VideoFrame> video_frame =
+ media::VideoFrame::CreateFrame(media::VideoFrame::YV12,
+ output_size,
+ gfx::Rect(output_size),
+ output_size,
+ base::TimeDelta());
+
+ base::Callback<void(bool success)> callback =
+ base::Bind(&CompositingRenderWidgetHostViewBrowserTestTabCapture::
+ ReadbackRequestCallbackForVideo,
+ base::Unretained(this),
+ video_frame,
+ run_loop.QuitClosure());
+ rwhv->CopyFromCompositingSurfaceToVideoFrame(
+ copy_rect, video_frame, callback);
+ } else {
+ 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()));
+ }
}
+
+ ReadbackRequestCallback callback =
+ base::Bind(&CompositingRenderWidgetHostViewBrowserTestTabCapture::
+ ReadbackRequestCallbackTest,
+ base::Unretained(this),
+ run_loop.QuitClosure());
+ rwhv->CopyFromCompositingSurface(
+ copy_rect, output_size, callback, kN32_SkColorType);
}
+ run_loop.Run();
- base::Callback<void(bool, const SkBitmap&)> callback =
- base::Bind(&CompositingRenderWidgetHostViewBrowserTestTabCapture::
- CopyFromCompositingSurfaceCallback,
- base::Unretained(this),
- run_loop.QuitClosure());
- rwhvp->CopyFromCompositingSurface(copy_rect,
- output_size,
- callback,
- kN32_SkColorType);
- }
- run_loop.Run();
+ // If the readback operation did not provide a frame, log the reason
+ // to aid in future debugging. This information will also help determine
+ // whether the implementation is broken, or a test bot is in a bad state.
+ #define CASE_LOG_READBACK_WARNING(enum_value) \
+ case enum_value: \
+ LOG(WARNING) << "Readback attempt failed (render frame #" \
+ << last_frame_number << "). Reason: " #enum_value; \
+ break
+ switch (readback_response_) {
+ case READBACK_SUCCESS:
+ break;
+ CASE_LOG_READBACK_WARNING(READBACK_FAILED);
+ CASE_LOG_READBACK_WARNING(READBACK_SURFACE_UNAVAILABLE);
+ CASE_LOG_READBACK_WARNING(READBACK_BITMAP_ALLOCATION_FAILURE);
+ CASE_LOG_READBACK_WARNING(READBACK_NO_TEST_COLORS);
+ CASE_LOG_READBACK_WARNING(READBACK_TO_VIDEO_FRAME_FAILED);
+ default:
+ LOG(ERROR)
+ << "Invalid readback response value: " << readback_response_;
+ NOTREACHED();
+ }
+ } while (readback_response_ != READBACK_SUCCESS);
}
// Sets up |bitmap| to have size |copy_size|. It floods the left half with
@@ -649,12 +684,22 @@ class CompositingRenderWidgetHostViewBrowserTestTabCapture
}
protected:
+ // Additional ReadbackResponse enum values only used within this test module,
+ // to distinguish readback exception cases further.
+ enum ExtraReadbackResponsesForTest {
+ READBACK_NO_RESPONSE = -1337,
+ READBACK_NO_TEST_COLORS,
+ READBACK_TO_VIDEO_FRAME_FAILED,
+ };
+
virtual bool ShouldContinueAfterTestURLLoad() {
return true;
}
private:
- bool expected_copy_from_compositing_surface_result_;
+ // |readback_response_| is always a content::ReadbackResponse or
+ // ExtraReadbackResponsesForTest enum value.
+ int readback_response_;
SkBitmap expected_copy_from_compositing_surface_bitmap_;
int allowable_error_;
gfx::Rect exclude_rect_;
@@ -780,12 +825,9 @@ class CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI
CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI);
};
-// 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)
+// NineImagePainter implementation crashes the process on Windows when this
+// content_browsertest forces a device scale factor. http://crbug.com/399349
+#if defined(OS_WIN)
#define MAYBE_CopyToBitmap_EntireRegion DISABLED_CopyToBitmap_EntireRegion
#define MAYBE_CopyToBitmap_CenterRegion DISABLED_CopyToBitmap_CenterRegion
#define MAYBE_CopyToBitmap_ScaledResult DISABLED_CopyToBitmap_ScaledResult
@@ -898,16 +940,24 @@ IN_PROC_BROWSER_TEST_P(
video_frame);
}
+#if defined(OS_CHROMEOS)
+// On ChromeOS there is no software compositing.
+static const auto kTestCompositingModes = testing::Values(GL_COMPOSITING);
+#else
+static const auto kTestCompositingModes =
+ testing::Values(GL_COMPOSITING, SOFTWARE_COMPOSITING);
+#endif
+
INSTANTIATE_TEST_CASE_P(GLAndSoftwareCompositing,
CompositingRenderWidgetHostViewBrowserTest,
- testing::Values(GL_COMPOSITING, SOFTWARE_COMPOSITING));
+ kTestCompositingModes);
INSTANTIATE_TEST_CASE_P(GLAndSoftwareCompositing,
CompositingRenderWidgetHostViewBrowserTestTabCapture,
- testing::Values(GL_COMPOSITING, SOFTWARE_COMPOSITING));
+ kTestCompositingModes);
INSTANTIATE_TEST_CASE_P(
GLAndSoftwareCompositing,
CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI,
- testing::Values(GL_COMPOSITING, SOFTWARE_COMPOSITING));
+ kTestCompositingModes);
#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 2be8d87df02..0c8ba4b4a28 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
@@ -9,6 +9,7 @@
#include <IOSurface/IOSurfaceAPI.h>
#include <list>
#include <map>
+#include <set>
#include <string>
#include <utility>
#include <vector>
@@ -19,22 +20,23 @@
#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/compositor/io_surface_layer_mac.h"
#include "content/browser/renderer_host/display_link_mac.h"
+#include "content/browser/renderer_host/input/mouse_wheel_rails_filter_mac.h"
#include "content/browser/renderer_host/render_widget_host_view_base.h"
-#include "content/browser/renderer_host/software_frame_manager.h"
#include "content/common/content_export.h"
#include "content/common/cursors/webcursor.h"
#include "content/common/edit_command.h"
#import "content/public/browser/render_widget_host_view_mac_base.h"
#include "ipc/ipc_sender.h"
#include "third_party/WebKit/public/web/WebCompositionUnderline.h"
+#include "ui/accelerated_widget_mac/accelerated_widget_mac.h"
+#include "ui/accelerated_widget_mac/io_surface_layer.h"
#include "ui/base/cocoa/base_view.h"
#include "ui/base/cocoa/remote_layer_api.h"
#include "ui/gfx/display_observer.h"
namespace content {
-class BrowserCompositorviewMac;
+class RenderWidgetHostImpl;
class RenderWidgetHostViewMac;
class RenderWidgetHostViewMacEditCommandHelper;
class WebContents;
@@ -68,6 +70,7 @@ class Layer;
responderDelegate_;
BOOL canBeKeyView_;
BOOL closeOnDeactivate_;
+ BOOL opaque_;
scoped_ptr<content::RenderWidgetHostViewMacEditCommandHelper>
editCommand_helper_;
@@ -148,11 +151,41 @@ class Layer;
// Event monitor for scroll wheel end event.
id endWheelMonitor_;
+ // When a gesture starts, the system does not inform the view of which type
+ // of gesture is happening (magnify, rotate, etc), rather, it just informs
+ // the view that some as-yet-undefined gesture is starting. Capture the
+ // information about the gesture's beginning event here. It will be used to
+ // create a specific gesture begin event later.
+ scoped_ptr<blink::WebGestureEvent> gestureBeginEvent_;
+
+ // To avoid accidental pinches, require that a certain zoom threshold be
+ // reached before forwarding it to the browser. Use |pinchUnusedAmount_| to
+ // hold this value. If the user reaches this value, don't re-require the
+ // threshold be reached until the page has been zoomed back to page scale of
+ // one.
+ bool pinchHasReachedZoomThreshold_;
+ float pinchUnusedAmount_;
+ NSTimeInterval pinchLastGestureTimestamp_;
+
+ // This is set if a GesturePinchBegin event has been sent in the lifetime of
+ // |gestureBeginEvent_|. If set, a GesturePinchEnd will be sent when the
+ // gesture ends.
+ BOOL gestureBeginPinchSent_;
+
// 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
// key down event.
BOOL suppressNextEscapeKeyUp_;
+
+ // The set of key codes from key down events that we haven't seen the matching
+ // key up events yet.
+ // Used for filtering out non-matching NSKeyUp events.
+ std::set<unsigned short> keyDownCodes_;
+
+ // The filter used to guide touch events towards a horizontal or vertical
+ // orientation.
+ content::MouseWheelRailsFilterMac mouseWheelFilter_;
}
@property(nonatomic, readonly) NSRange selectedRange;
@@ -160,6 +193,7 @@ class Layer;
- (void)setCanBeKeyView:(BOOL)can;
- (void)setCloseOnDeactivate:(BOOL)b;
+- (void)setOpaque:(BOOL)opaque;
- (void)setToolTipAtMousePoint:(NSString *)string;
// True for always-on-top special windows (e.g. Balloons and Panels).
- (BOOL)acceptsMouseEventsWhenInactive;
@@ -180,7 +214,6 @@ class Layer;
@end
namespace content {
-class RenderWidgetHostImpl;
///////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewMac
@@ -201,7 +234,7 @@ class RenderWidgetHostImpl;
class CONTENT_EXPORT RenderWidgetHostViewMac
: public RenderWidgetHostViewBase,
public DelegatedFrameHostClient,
- public BrowserCompositorViewMacClient,
+ public ui::AcceleratedWidgetMacNSView,
public IPC::Sender,
public gfx::DisplayObserver {
public:
@@ -240,6 +273,8 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
void Show() override;
void Hide() override;
bool IsShowing() override;
+ void WasUnOccluded() override;
+ void WasOccluded() override;
gfx::Rect GetViewBounds() const override;
void SetShowingContextMenu(bool showing) override;
void SetActive(bool active) override;
@@ -256,11 +291,8 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
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,
@@ -281,11 +313,10 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
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,
- SkColorType color_type) override;
+ void CopyFromCompositingSurface(const gfx::Rect& src_subrect,
+ const gfx::Size& dst_size,
+ ReadbackRequestCallback& callback,
+ SkColorType preferred_color_type) override;
void CopyFromCompositingSurfaceToVideoFrame(
const gfx::Rect& src_subrect,
const scoped_refptr<media::VideoFrame>& target,
@@ -314,11 +345,11 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
void WheelEventAck(const blink::WebMouseWheelEvent& event,
InputEventAckState ack_result) override;
+ uint32_t GetSurfaceIdNamespace() override;
+
// IPC::Sender implementation.
bool Send(IPC::Message* message) override;
- SkColorType PreferredReadbackFormat() override;
-
// gfx::DisplayObserver implementation.
void OnDisplayAdded(const gfx::Display& new_display) override;
void OnDisplayRemoved(const gfx::Display& old_display) override;
@@ -377,29 +408,29 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
// The background CoreAnimation layer which is hosted by |cocoa_view_|.
base::scoped_nsobject<CALayer> background_layer_;
- // The state of |delegated_frame_host_| and |browser_compositor_view_| to
+ // The state of |delegated_frame_host_| and |browser_compositor_| to
// manage being visible, hidden, or occluded.
enum BrowserCompositorViewState {
// Effects:
- // - |browser_compositor_view_| exists and |delegated_frame_host_| is
+ // - |browser_compositor_| 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
+ // - |browser_compositor_| 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
+ // occluded by other windows, etc). The |browser_compositor_| 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
+ // - |browser_compositor_| 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
@@ -409,18 +440,22 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
};
BrowserCompositorViewState browser_compositor_state_;
- // Delegated frame management and compositior.
+ // Delegated frame management and compositor.
scoped_ptr<DelegatedFrameHost> delegated_frame_host_;
scoped_ptr<ui::Layer> root_layer_;
- // Container for the CALayer tree drawn by the browser compositor.
- scoped_ptr<BrowserCompositorViewMac> browser_compositor_view_;
+ // Container for ui::Compositor the CALayer tree drawn by it.
+ scoped_ptr<BrowserCompositorMac> browser_compositor_;
- // Placeholder that is allocated while browser_compositor_view_ is NULL,
+ // Placeholder that is allocated while browser_compositor_ 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_;
+ scoped_ptr<BrowserCompositorMacPlaceholder>
+ browser_compositor_placeholder_;
+
+ // Set when the currently-displayed frame is the minimum scale. Used to
+ // determine if pinch gestures need to be thresholded.
+ bool page_at_minimum_scale_;
NSWindow* pepper_fullscreen_window() const {
return pepper_fullscreen_window_;
@@ -446,20 +481,30 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
void PauseForPendingResizeOrRepaintsAndDraw();
// DelegatedFrameHostClient implementation.
- 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(
+ ui::Layer* DelegatedFrameHostGetLayer() const override;
+ bool DelegatedFrameHostIsVisible() const override;
+ gfx::Size DelegatedFrameHostDesiredSizeInDIP() const override;
+ bool DelegatedFrameCanCreateResizeLock() const override;
+ scoped_ptr<ResizeLock> DelegatedFrameHostCreateResizeLock(
+ bool defer_compositor_lock) override;
+ void DelegatedFrameHostResizeLockWasReleased() override;
+ void DelegatedFrameHostSendCompositorSwapAck(
+ int output_surface_id,
+ const cc::CompositorFrameAck& ack) override;
+ void DelegatedFrameHostSendReclaimCompositorResources(
+ int output_surface_id,
+ const cc::CompositorFrameAck& ack) override;
+ void DelegatedFrameHostOnLostCompositorResources() override;
+ void DelegatedFrameHostUpdateVSyncParameters(
+ const base::TimeTicks& timebase,
+ const base::TimeDelta& interval) override;
+
+ // AcceleratedWidgetMacNSView implementation.
+ NSView* AcceleratedWidgetGetNSView() const override;
+ bool AcceleratedWidgetShouldIgnoreBackpressure() const override;
+ void AcceleratedWidgetSwapCompleted(
const std::vector<ui::LatencyInfo>& latency_info) override;
+ void AcceleratedWidgetHitError() override;
// Transition from being in the Suspended state to being in the Destroyed
// state, if appropriate (see BrowserCompositorViewState for details).
@@ -517,9 +562,6 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
// RenderWidgetHostViewGuest.
bool is_guest_view_hack_;
- // Factory used to safely scope delayed calls to ShutdownHost().
- base::WeakPtrFactory<RenderWidgetHostViewMac> weak_factory_;
-
// selected text on the renderer.
std::string selected_text_;
@@ -547,6 +589,9 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
// The current caret bounds.
gfx::Rect caret_rect_;
+ // Factory used to safely scope delayed calls to ShutdownHost().
+ base::WeakPtrFactory<RenderWidgetHostViewMac> weak_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 84a6008c5a0..c173466feb2 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
@@ -13,7 +13,6 @@
#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/debug/crash_logging.h"
-#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/mac/mac_util.h"
#include "base/mac/scoped_cftyperef.h"
@@ -26,36 +25,36 @@
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/sys_info.h"
+#include "base/trace_event/trace_event.h"
#import "content/browser/accessibility/browser_accessibility_cocoa.h"
#include "content/browser/accessibility/browser_accessibility_manager_mac.h"
+#include "content/browser/bad_message.h"
#import "content/browser/cocoa/system_hotkey_helper_mac.h"
#import "content/browser/cocoa/system_hotkey_map.h"
-#include "content/browser/compositor/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/gpu/compositor_util.h"
-#include "content/browser/renderer_host/render_widget_helper.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
+#include "content/browser/renderer_host/render_widget_helper.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/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"
+#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/native_web_keyboard_event.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_widget_host_view_frame_subscriber.h"
#import "content/public/browser/render_widget_host_view_mac_delegate.h"
-#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"
@@ -63,20 +62,23 @@
#include "third_party/WebKit/public/web/WebInputEvent.h"
#include "third_party/WebKit/public/web/mac/WebInputEventFactory.h"
#import "third_party/mozilla/ComplexTextInputPanel.h"
+#include "ui/accelerated_widget_mac/io_surface_layer.h"
+#include "ui/accelerated_widget_mac/surface_handle_types.h"
#include "ui/base/cocoa/animation_utils.h"
#import "ui/base/cocoa/fullscreen_window_manager.h"
#import "ui/base/cocoa/underlay_opengl_hosting_window.h"
-#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/base/layout.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/layer.h"
+#include "ui/events/keycodes/keyboard_codes.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/geometry/dip_util.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
#include "ui/gfx/screen.h"
-#include "ui/gfx/size_conversions.h"
#include "ui/gl/gl_switches.h"
using content::BrowserAccessibility;
@@ -107,6 +109,23 @@ BOOL EventIsReservedBySystem(NSEvent* event) {
return helper->map()->IsEventReserved(event);
}
+RenderWidgetHostViewMac* GetRenderWidgetHostViewToUse(
+ RenderWidgetHostViewMac* render_widget_host_view) {
+ WebContents* web_contents = render_widget_host_view->GetWebContents();
+ if (!web_contents)
+ return render_widget_host_view;
+ content::BrowserPluginGuestManager* guest_manager =
+ web_contents->GetBrowserContext()->GetGuestManager();
+ if (!guest_manager)
+ return render_widget_host_view;
+ content::WebContents* guest =
+ guest_manager->GetFullPageGuest(web_contents);
+ if (!guest)
+ return render_widget_host_view;
+ return static_cast<RenderWidgetHostViewMac*>(
+ guest->GetRenderWidgetHostView());
+}
+
} // namespace
// These are not documented, so use only after checking -respondsToSelector:.
@@ -394,55 +413,66 @@ namespace content {
////////////////////////////////////////////////////////////////////////////////
// DelegatedFrameHost, public:
-ui::Compositor* RenderWidgetHostViewMac::GetCompositor() const {
- // 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() {
+ui::Layer* RenderWidgetHostViewMac::DelegatedFrameHostGetLayer() const {
return root_layer_.get();
}
-RenderWidgetHostImpl* RenderWidgetHostViewMac::GetHost() {
- return render_widget_host_;
-}
-
-bool RenderWidgetHostViewMac::IsVisible() {
+bool RenderWidgetHostViewMac::DelegatedFrameHostIsVisible() const {
return !render_widget_host_->is_hidden();
}
-gfx::Size RenderWidgetHostViewMac::DesiredFrameSize() {
+gfx::Size RenderWidgetHostViewMac::DelegatedFrameHostDesiredSizeInDIP() const {
return GetViewBounds().size();
}
-float RenderWidgetHostViewMac::CurrentDeviceScaleFactor() {
- return ViewScaleFactor();
+bool RenderWidgetHostViewMac::DelegatedFrameCanCreateResizeLock() const {
+ // Mac uses the RenderWidgetResizeHelper instead of a resize lock.
+ return false;
}
-gfx::Size RenderWidgetHostViewMac::ConvertViewSizeToPixel(
- const gfx::Size& size) {
- return gfx::ToEnclosingRect(gfx::ScaleRect(gfx::Rect(size),
- ViewScaleFactor())).size();
+scoped_ptr<ResizeLock>
+RenderWidgetHostViewMac::DelegatedFrameHostCreateResizeLock(
+ bool defer_compositor_lock) {
+ NOTREACHED();
+ return scoped_ptr<ResizeLock>();
}
-scoped_ptr<ResizeLock> RenderWidgetHostViewMac::CreateResizeLock(
- bool defer_compositor_lock) {
+void RenderWidgetHostViewMac::DelegatedFrameHostResizeLockWasReleased() {
NOTREACHED();
- ResizeLock* lock = NULL;
- return scoped_ptr<ResizeLock>(lock);
}
-DelegatedFrameHost* RenderWidgetHostViewMac::GetDelegatedFrameHost() const {
- return delegated_frame_host_.get();
+void RenderWidgetHostViewMac::DelegatedFrameHostSendCompositorSwapAck(
+ int output_surface_id,
+ const cc::CompositorFrameAck& ack) {
+ render_widget_host_->Send(new ViewMsg_SwapCompositorFrameAck(
+ render_widget_host_->GetRoutingID(), output_surface_id, ack));
+}
+
+void RenderWidgetHostViewMac::DelegatedFrameHostSendReclaimCompositorResources(
+ int output_surface_id,
+ const cc::CompositorFrameAck& ack) {
+ render_widget_host_->Send(new ViewMsg_ReclaimCompositorResources(
+ render_widget_host_->GetRoutingID(), output_surface_id, ack));
+}
+
+void RenderWidgetHostViewMac::DelegatedFrameHostOnLostCompositorResources() {
+ render_widget_host_->ScheduleComposite();
+}
+
+void RenderWidgetHostViewMac::DelegatedFrameHostUpdateVSyncParameters(
+ const base::TimeTicks& timebase,
+ const base::TimeDelta& interval) {
+ render_widget_host_->UpdateVSyncParameters(timebase, interval);
}
////////////////////////////////////////////////////////////////////////////////
-// BrowserCompositorViewMacClient, public:
+// AcceleratedWidgetMacNSView, public:
+
+NSView* RenderWidgetHostViewMac::AcceleratedWidgetGetNSView() const {
+ return cocoa_view_;
+}
-bool RenderWidgetHostViewMac::BrowserCompositorViewShouldAckImmediately()
+bool RenderWidgetHostViewMac::AcceleratedWidgetShouldIgnoreBackpressure()
const {
// If vsync is disabled, then always draw and ack frames immediately.
static bool is_vsync_disabled =
@@ -484,17 +514,26 @@ bool RenderWidgetHostViewMac::BrowserCompositorViewShouldAckImmediately()
return false;
}
-void RenderWidgetHostViewMac::BrowserCompositorViewFrameSwapped(
+void RenderWidgetHostViewMac::AcceleratedWidgetSwapCompleted(
const std::vector<ui::LatencyInfo>& all_latency_info) {
if (!render_widget_host_)
return;
+ base::TimeTicks swap_time = base::TimeTicks::Now();
for (auto latency_info : all_latency_info) {
- latency_info.AddLatencyNumber(
- ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0);
+ latency_info.AddLatencyNumberWithTimestamp(
+ ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, 0, swap_time, 1);
+ latency_info.AddLatencyNumberWithTimestamp(
+ ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0,
+ swap_time, 1);
render_widget_host_->FrameSwapped(latency_info);
}
}
+void RenderWidgetHostViewMac::AcceleratedWidgetHitError() {
+ // Request a new frame be drawn.
+ browser_compositor_->compositor()->ScheduleFullRedraw();
+}
+
///////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewBase, public:
@@ -513,13 +552,13 @@ RenderWidgetHostViewMac::RenderWidgetHostViewMac(RenderWidgetHost* widget,
text_input_type_(ui::TEXT_INPUT_TYPE_NONE),
can_compose_inline_(true),
browser_compositor_state_(BrowserCompositorDestroyed),
- browser_compositor_view_placeholder_(
- new BrowserCompositorViewPlaceholderMac),
+ browser_compositor_placeholder_(new BrowserCompositorMacPlaceholder),
+ page_at_minimum_scale_(true),
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) {
+ fullscreen_parent_host_view_(NULL),
+ weak_factory_(this) {
// |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.
@@ -529,8 +568,9 @@ RenderWidgetHostViewMac::RenderWidgetHostViewMac(RenderWidgetHost* widget,
// Paint this view host with |background_color_| when there is no content
// ready to draw.
background_layer_.reset([[CALayer alloc] init]);
- [background_layer_
- setBackgroundColor:gfx::CGColorCreateFromSkColor(background_color_)];
+ // Set the default color to be white. This is the wrong thing to do, but many
+ // UI components expect this view to be opaque.
+ [background_layer_ setBackgroundColor:CGColorGetConstantColor(kCGColorWhite)];
[cocoa_view_ setLayer:background_layer_];
[cocoa_view_ setWantsLayer:YES];
@@ -587,15 +627,26 @@ void RenderWidgetHostViewMac::EnsureBrowserCompositorView() {
// 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_ = BrowserCompositorMac::Create();
+ browser_compositor_->compositor()->SetRootLayer(root_layer_.get());
+ browser_compositor_->compositor()->SetHostHasTransparentBackground(
+ !GetBackgroundOpaque());
+ browser_compositor_->accelerated_widget_mac()->SetNSView(this);
browser_compositor_state_ = BrowserCompositorSuspended;
}
// Show the DelegatedFrameHost to transition from Suspended -> Active.
if (browser_compositor_state_ == BrowserCompositorSuspended) {
- delegated_frame_host_->AddedToWindow();
+ delegated_frame_host_->SetCompositor(browser_compositor_->compositor());
delegated_frame_host_->WasShown(ui::LatencyInfo());
+ // Unsuspend the browser compositor after showing the delegated frame host.
+ // If there is not a saved delegated frame, then the delegated frame host
+ // will keep the compositor locked until a delegated frame is swapped.
+ float scale_factor = ViewScaleFactor();
+ browser_compositor_->compositor()->SetScaleAndSize(
+ scale_factor,
+ gfx::ConvertSizeToPixel(scale_factor, GetViewBounds().size()));
+ browser_compositor_->Unsuspend();
browser_compositor_state_ = BrowserCompositorActive;
}
}
@@ -606,10 +657,13 @@ void RenderWidgetHostViewMac::SuspendBrowserCompositorView() {
// Hide the DelegatedFrameHost to transition from Active -> Suspended.
if (browser_compositor_state_ == BrowserCompositorActive) {
+ // Ensure that any changes made to the ui::Compositor do not result in new
+ // frames being produced.
+ browser_compositor_->Suspend();
// 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();
+ delegated_frame_host_->ResetCompositor();
browser_compositor_state_ = BrowserCompositorSuspended;
}
}
@@ -623,7 +677,10 @@ void RenderWidgetHostViewMac::DestroyBrowserCompositorView() {
// Destroy the BrowserCompositorView to transition Suspended -> Destroyed.
if (browser_compositor_state_ == BrowserCompositorSuspended) {
- browser_compositor_view_.reset();
+ browser_compositor_->accelerated_widget_mac()->ResetNSView();
+ browser_compositor_->compositor()->SetScaleAndSize(1.0, gfx::Size(0, 0));
+ browser_compositor_->compositor()->SetRootLayer(nullptr);
+ BrowserCompositorMac::Recycle(browser_compositor_.Pass());
browser_compositor_state_ = BrowserCompositorDestroyed;
}
}
@@ -789,7 +846,10 @@ void RenderWidgetHostViewMac::SendVSyncParametersToRenderer() {
return;
}
- render_widget_host_->UpdateVSyncParameters(vsync_timebase_, vsync_interval_);
+ if (browser_compositor_) {
+ browser_compositor_->compositor()->vsync_manager()->UpdateVSyncParameters(
+ vsync_timebase_, vsync_interval_);
+ }
}
void RenderWidgetHostViewMac::SpeakText(const std::string& text) {
@@ -806,7 +866,34 @@ RenderWidgetHost* RenderWidgetHostViewMac::GetRenderWidgetHost() const {
return render_widget_host_;
}
-void RenderWidgetHostViewMac::WasShown() {
+void RenderWidgetHostViewMac::Show() {
+ ScopedCAActionDisabler disabler;
+ [cocoa_view_ setHidden:NO];
+ if (!render_widget_host_->is_hidden())
+ return;
+
+ // Re-create the browser compositor. If the DelegatedFrameHost has a cached
+ // frame from the last time it was visible, then it will immediately be
+ // drawn. If not, then the compositor will remain locked until a new delegated
+ // frame is swapped.
+ EnsureBrowserCompositorView();
+
+ WasUnOccluded();
+
+ // 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();
+}
+
+void RenderWidgetHostViewMac::Hide() {
+ ScopedCAActionDisabler disabler;
+ [cocoa_view_ setHidden:YES];
+ WasOccluded();
+ DestroySuspendedBrowserCompositorViewIfNeeded();
+}
+
+void RenderWidgetHostViewMac::WasUnOccluded() {
if (!render_widget_host_->is_hidden())
return;
@@ -816,23 +903,14 @@ void RenderWidgetHostViewMac::WasShown() {
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();
}
-void RenderWidgetHostViewMac::WasHidden() {
+void RenderWidgetHostViewMac::WasOccluded() {
if (render_widget_host_->is_hidden())
return;
- // If we have a renderer, then inform it that we are being hidden so it can
- // reduce its resource utilization.
render_widget_host_->WasHidden();
-
SuspendBrowserCompositorView();
- DestroySuspendedBrowserCompositorViewIfNeeded();
}
void RenderWidgetHostViewMac::SetSize(const gfx::Size& size) {
@@ -902,8 +980,7 @@ gfx::NativeViewId RenderWidgetHostViewMac::GetNativeViewId() const {
}
gfx::NativeViewAccessible RenderWidgetHostViewMac::GetNativeViewAccessible() {
- NOTIMPLEMENTED();
- return static_cast<gfx::NativeViewAccessible>(NULL);
+ return cocoa_view_;
}
void RenderWidgetHostViewMac::MovePluginWindows(
@@ -918,11 +995,6 @@ void RenderWidgetHostViewMac::Focus() {
[[cocoa_view_ window] makeFirstResponder:cocoa_view_];
}
-void RenderWidgetHostViewMac::Blur() {
- UnlockMouse();
- [[cocoa_view_ window] makeFirstResponder:nil];
-}
-
bool RenderWidgetHostViewMac::HasFocus() const {
return [[cocoa_view_ window] firstResponder] == cocoa_view_;
}
@@ -933,18 +1005,6 @@ bool RenderWidgetHostViewMac::IsSurfaceAvailableForCopy() const {
return false;
}
-void RenderWidgetHostViewMac::Show() {
- [cocoa_view_ setHidden:NO];
-
- WasShown();
-}
-
-void RenderWidgetHostViewMac::Hide() {
- [cocoa_view_ setHidden:YES];
-
- WasHidden();
-}
-
bool RenderWidgetHostViewMac::IsShowing() {
return ![cocoa_view_ isHidden];
}
@@ -1183,11 +1243,11 @@ bool RenderWidgetHostViewMac::IsPopup() const {
void RenderWidgetHostViewMac::CopyFromCompositingSurface(
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
- const base::Callback<void(bool, const SkBitmap&)>& callback,
- const SkColorType color_type) {
+ ReadbackRequestCallback& callback,
+ const SkColorType preferred_color_type) {
if (delegated_frame_host_) {
delegated_frame_host_->CopyFromCompositingSurface(
- src_subrect, dst_size, callback, color_type);
+ src_subrect, dst_size, callback, preferred_color_type);
}
}
@@ -1399,8 +1459,10 @@ bool RenderWidgetHostViewMac::GetCachedFirstRectForCharacterRange(
bool RenderWidgetHostViewMac::HasAcceleratedSurface(
const gfx::Size& desired_size) {
- if (browser_compositor_view_)
- return browser_compositor_view_->HasFrameOfSize(desired_size);
+ if (browser_compositor_) {
+ return browser_compositor_->accelerated_widget_mac()->HasFrameOfSize(
+ desired_size);
+ }
return false;
}
@@ -1409,6 +1471,10 @@ void RenderWidgetHostViewMac::OnSwapCompositorFrame(
TRACE_EVENT0("browser", "RenderWidgetHostViewMac::OnSwapCompositorFrame");
last_scroll_offset_ = frame->metadata.root_scroll_offset;
+
+ page_at_minimum_scale_ = frame->metadata.page_scale_factor ==
+ frame->metadata.min_page_scale_factor;
+
if (frame->delegated_frame_data) {
float scale_factor = frame->metadata.device_scale_factor;
@@ -1416,13 +1482,12 @@ void RenderWidgetHostViewMac::OnSwapCompositorFrame(
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);
+ gfx::Size dip_size = gfx::ConvertSizeToDIP(scale_factor, pixel_size);
root_layer_->SetBounds(gfx::Rect(dip_size));
if (!render_widget_host_->is_hidden()) {
EnsureBrowserCompositorView();
- browser_compositor_view_->GetCompositor()->SetScaleAndSize(
+ browser_compositor_->compositor()->SetScaleAndSize(
scale_factor, pixel_size);
}
@@ -1435,9 +1500,8 @@ void RenderWidgetHostViewMac::OnSwapCompositorFrame(
frame->metadata.latency_info);
} else {
DLOG(ERROR) << "Received unexpected frame type.";
- RecordAction(
- base::UserMetricsAction("BadMessageTerminate_UnexpectedFrameType"));
- render_widget_host_->GetProcess()->ReceivedBadMessage();
+ bad_message::ReceivedBadMessage(render_widget_host_->GetProcess(),
+ bad_message::RWHVM_UNEXPECTED_FRAME_TYPE);
}
}
@@ -1502,6 +1566,13 @@ void RenderWidgetHostViewMac::WheelEventAck(
[cocoa_view_ processedWheelEvent:event consumed:consumed];
}
+uint32_t RenderWidgetHostViewMac::GetSurfaceIdNamespace() {
+ if (delegated_frame_host_)
+ return delegated_frame_host_->GetSurfaceIdNamespace();
+
+ return 0;
+}
+
bool RenderWidgetHostViewMac::Send(IPC::Message* message) {
if (render_widget_host_)
return render_widget_host_->Send(message);
@@ -1519,7 +1590,7 @@ void RenderWidgetHostViewMac::ShutdownBrowserCompositor() {
DestroyBrowserCompositorView();
delegated_frame_host_.reset();
root_layer_.reset();
- browser_compositor_view_placeholder_.reset();
+ browser_compositor_placeholder_.reset();
}
void RenderWidgetHostViewMac::SetActive(bool active) {
@@ -1562,13 +1633,14 @@ void RenderWidgetHostViewMac::ShowDefinitionForSelection() {
void RenderWidgetHostViewMac::SetBackgroundColor(SkColor color) {
RenderWidgetHostViewBase::SetBackgroundColor(color);
+ bool opaque = GetBackgroundOpaque();
+
if (render_widget_host_)
- render_widget_host_->SetBackgroundOpaque(GetBackgroundOpaque());
+ render_widget_host_->SetBackgroundOpaque(opaque);
- if (background_layer_) {
- [background_layer_
- setBackgroundColor:gfx::CGColorCreateFromSkColor(background_color_)];
- }
+ [cocoa_view_ setOpaque:opaque];
+ if (browser_compositor_state_ != BrowserCompositorDestroyed)
+ browser_compositor_->compositor()->SetHostHasTransparentBackground(!opaque);
}
BrowserAccessibilityManager*
@@ -1645,15 +1717,11 @@ void RenderWidgetHostViewMac::PauseForPendingResizeOrRepaintsAndDraw() {
return;
// Wait for a frame of the right size to come in.
- if (browser_compositor_view_)
- browser_compositor_view_->BeginPumpingFrames();
+ if (browser_compositor_)
+ browser_compositor_->accelerated_widget_mac()->BeginPumpingFrames();
render_widget_host_->PauseForPendingResizeOrRepaints();
- if (browser_compositor_view_)
- browser_compositor_view_->EndPumpingFrames();
-}
-
-SkColorType RenderWidgetHostViewMac::PreferredReadbackFormat() {
- return kN32_SkColorType;
+ if (browser_compositor_)
+ browser_compositor_->accelerated_widget_mac()->EndPumpingFrames();
}
////////////////////////////////////////////////////////////////////////////////
@@ -1692,7 +1760,9 @@ void RenderWidgetHostViewMac::OnDisplayMetricsChanged(
renderWidgetHostView_.reset(r);
canBeKeyView_ = YES;
+ opaque_ = YES;
focusedPluginIdentifier_ = -1;
+ pinchHasReachedZoomThreshold_ = false;
// OpenGL support:
if ([self respondsToSelector:
@@ -1780,6 +1850,10 @@ void RenderWidgetHostViewMac::OnDisplayMetricsChanged(
closeOnDeactivate_ = b;
}
+- (void)setOpaque:(BOOL)opaque {
+ opaque_ = opaque;
+}
+
- (BOOL)shouldIgnoreMouseEvent:(NSEvent*)theEvent {
NSWindow* window = [self window];
// If this is a background window, don't handle mouse movement events. This
@@ -1995,6 +2069,15 @@ void RenderWidgetHostViewMac::OnDisplayMetricsChanged(
return;
}
+ // Do not forward key up events unless preceded by a matching key down,
+ // otherwise we might get an event from releasing the return key in the
+ // omnibox (http://crbug.com/338736).
+ if ([theEvent type] == NSKeyUp) {
+ auto numErased = keyDownCodes_.erase([theEvent keyCode]);
+ if (numErased < 1)
+ return;
+ }
+
// We only handle key down events and just simply forward other events.
if ([theEvent type] != NSKeyDown) {
widgetHost->ForwardKeyboardEvent(event);
@@ -2006,6 +2089,8 @@ void RenderWidgetHostViewMac::OnDisplayMetricsChanged(
return;
}
+ keyDownCodes_.insert([theEvent keyCode]);
+
base::scoped_nsobject<RenderWidgetHostViewCocoa> keepSelfAlive([self retain]);
// Records the current marked text state, so that we can know if the marked
@@ -2193,8 +2278,9 @@ void RenderWidgetHostViewMac::OnDisplayMetricsChanged(
// Allow rubber-banding in both directions.
bool canRubberbandLeft = true;
bool canRubberbandRight = true;
- const WebMouseWheelEvent webEvent = WebInputEventFactory::mouseWheelEvent(
+ WebMouseWheelEvent webEvent = WebInputEventFactory::mouseWheelEvent(
event, self, canRubberbandLeft, canRubberbandRight);
+ webEvent.railsMode = mouseWheelFilter_.UpdateRailsMode(webEvent);
renderWidgetHostView_->render_widget_host_->ForwardWheelEvent(webEvent);
}
@@ -2206,23 +2292,57 @@ void RenderWidgetHostViewMac::OnDisplayMetricsChanged(
- (void)beginGestureWithEvent:(NSEvent*)event {
[responderDelegate_ beginGestureWithEvent:event];
+ gestureBeginEvent_.reset(
+ new WebGestureEvent(WebInputEventFactory::gestureEvent(event, self)));
+
+ // If the page is at the minimum zoom level, require a threshold be reached
+ // before the pinch has an effect.
+ if (renderWidgetHostView_->page_at_minimum_scale_) {
+ pinchHasReachedZoomThreshold_ = false;
+ pinchUnusedAmount_ = 1;
+ }
}
+
- (void)endGestureWithEvent:(NSEvent*)event {
[responderDelegate_ endGestureWithEvent:event];
+ gestureBeginEvent_.reset();
+
+ if (!renderWidgetHostView_->render_widget_host_)
+ return;
+
+ if (gestureBeginPinchSent_) {
+ WebGestureEvent endEvent(WebInputEventFactory::gestureEvent(event, self));
+ endEvent.type = WebInputEvent::GesturePinchEnd;
+ renderWidgetHostView_->render_widget_host_->ForwardGestureEvent(endEvent);
+ gestureBeginPinchSent_ = NO;
+ }
}
+
- (void)touchesMovedWithEvent:(NSEvent*)event {
[responderDelegate_ touchesMovedWithEvent:event];
}
+
- (void)touchesBeganWithEvent:(NSEvent*)event {
[responderDelegate_ touchesBeganWithEvent:event];
}
+
- (void)touchesCancelledWithEvent:(NSEvent*)event {
[responderDelegate_ touchesCancelledWithEvent:event];
}
+
- (void)touchesEndedWithEvent:(NSEvent*)event {
[responderDelegate_ touchesEndedWithEvent:event];
}
+- (void)smartMagnifyWithEvent:(NSEvent*)event {
+ const WebGestureEvent& smartMagnifyEvent =
+ WebInputEventFactory::gestureEvent(event, self);
+ if (renderWidgetHostView_ && renderWidgetHostView_->render_widget_host_) {
+ renderWidgetHostView_->render_widget_host_->ForwardGestureEvent(
+ smartMagnifyEvent);
+ }
+}
+
// This is invoked only on 10.8 or newer when the user taps a word using
// three fingers.
- (void)quickLookWithEvent:(NSEvent*)event {
@@ -2289,24 +2409,43 @@ void RenderWidgetHostViewMac::OnDisplayMetricsChanged(
if (renderWidgetHostView_->render_widget_host_) {
BOOL canRubberbandLeft = [responderDelegate_ canRubberbandLeft:self];
BOOL canRubberbandRight = [responderDelegate_ canRubberbandRight:self];
- const WebMouseWheelEvent webEvent = WebInputEventFactory::mouseWheelEvent(
+ WebMouseWheelEvent webEvent = WebInputEventFactory::mouseWheelEvent(
event, self, canRubberbandLeft, canRubberbandRight);
+ webEvent.railsMode = mouseWheelFilter_.UpdateRailsMode(webEvent);
renderWidgetHostView_->render_widget_host_->ForwardWheelEvent(webEvent);
}
}
// Called repeatedly during a pinch gesture, with incremental change values.
- (void)magnifyWithEvent:(NSEvent*)event {
- if (renderWidgetHostView_->render_widget_host_) {
- // Send a GesturePinchUpdate event.
- // Note that we don't attempt to bracket these by GesturePinchBegin/End (or
- // GestureSrollBegin/End) as is done for touchscreen. Keeping track of when
- // a pinch is active would take a little more work here, and we don't need
- // it for anything yet.
- const WebGestureEvent& webEvent =
- WebInputEventFactory::gestureEvent(event, self);
- renderWidgetHostView_->render_widget_host_->ForwardGestureEvent(webEvent);
+ if (!renderWidgetHostView_->render_widget_host_)
+ return;
+
+ // If, due to nesting of multiple gestures (e.g, from multiple touch
+ // devices), the beginning of the gesture has been lost, skip the remainder
+ // of the gesture.
+ if (!gestureBeginEvent_)
+ return;
+
+ if (!pinchHasReachedZoomThreshold_) {
+ pinchUnusedAmount_ *= (1 + [event magnification]);
+ if (pinchUnusedAmount_ < 0.667 || pinchUnusedAmount_ > 1.5)
+ pinchHasReachedZoomThreshold_ = true;
+ }
+
+ // Send a GesturePinchBegin event if none has been sent yet.
+ if (!gestureBeginPinchSent_) {
+ WebGestureEvent beginEvent(*gestureBeginEvent_);
+ beginEvent.type = WebInputEvent::GesturePinchBegin;
+ renderWidgetHostView_->render_widget_host_->ForwardGestureEvent(beginEvent);
+ gestureBeginPinchSent_ = YES;
}
+
+ // Send a GesturePinchUpdate event.
+ WebGestureEvent updateEvent =
+ WebInputEventFactory::gestureEvent(event, self);
+ updateEvent.data.pinchUpdate.zoomDisabled = !pinchHasReachedZoomThreshold_;
+ renderWidgetHostView_->render_widget_host_->ForwardGestureEvent(updateEvent);
}
- (void)viewWillMoveToWindow:(NSWindow*)newWindow {
@@ -2532,7 +2671,8 @@ void RenderWidgetHostViewMac::OnDisplayMetricsChanged(
- (id)accessibilityAttributeValue:(NSString *)attribute {
BrowserAccessibilityManager* manager =
- renderWidgetHostView_->GetHost()->GetRootBrowserAccessibilityManager();
+ renderWidgetHostView_->render_widget_host_
+ ->GetRootBrowserAccessibilityManager();
// Contents specifies document view of RenderWidgetHostViewCocoa provided by
// BrowserAccessibilityManager. Children includes all subviews in addition to
@@ -2558,7 +2698,8 @@ void RenderWidgetHostViewMac::OnDisplayMetricsChanged(
- (id)accessibilityHitTest:(NSPoint)point {
BrowserAccessibilityManager* manager =
- renderWidgetHostView_->GetHost()->GetRootBrowserAccessibilityManager();
+ renderWidgetHostView_->render_widget_host_
+ ->GetRootBrowserAccessibilityManager();
if (!manager)
return self;
NSPoint pointInWindow = [[self window] convertScreenToBase:point];
@@ -2572,13 +2713,15 @@ void RenderWidgetHostViewMac::OnDisplayMetricsChanged(
- (BOOL)accessibilityIsIgnored {
BrowserAccessibilityManager* manager =
- renderWidgetHostView_->GetHost()->GetRootBrowserAccessibilityManager();
+ renderWidgetHostView_->render_widget_host_
+ ->GetRootBrowserAccessibilityManager();
return !manager;
}
- (NSUInteger)accessibilityGetIndexOf:(id)child {
BrowserAccessibilityManager* manager =
- renderWidgetHostView_->GetHost()->GetRootBrowserAccessibilityManager();
+ renderWidgetHostView_->render_widget_host_
+ ->GetRootBrowserAccessibilityManager();
// Only child is root.
if (manager &&
manager->GetRoot()->ToBrowserAccessibilityCocoa() == child) {
@@ -2590,7 +2733,8 @@ void RenderWidgetHostViewMac::OnDisplayMetricsChanged(
- (id)accessibilityFocusedUIElement {
BrowserAccessibilityManager* manager =
- renderWidgetHostView_->GetHost()->GetRootBrowserAccessibilityManager();
+ renderWidgetHostView_->render_widget_host_
+ ->GetRootBrowserAccessibilityManager();
if (manager) {
BrowserAccessibility* focused_item = manager->GetFocus(NULL);
DCHECK(focused_item);
@@ -3177,11 +3321,11 @@ extern NSString *NSTextInputReplacementRangeAttributeName;
}
- (void)startSpeaking:(id)sender {
- renderWidgetHostView_->SpeakSelection();
+ GetRenderWidgetHostViewToUse(renderWidgetHostView_.get())->SpeakSelection();
}
- (void)stopSpeaking:(id)sender {
- renderWidgetHostView_->StopSpeaking();
+ GetRenderWidgetHostViewToUse(renderWidgetHostView_.get())->StopSpeaking();
}
- (void)cancelComposition {
@@ -3192,8 +3336,13 @@ extern NSString *NSTextInputReplacementRangeAttributeName;
// doesn't call any NSTextInput functions, such as setMarkedText or
// insertText. So, we need to send an IPC message to a renderer so it can
// delete the composition node.
+ // TODO(erikchen): NSInputManager is deprecated since OSX 10.6. Switch to
+ // NSTextInputContext. http://www.crbug.com/479010.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
NSInputManager *currentInputManager = [NSInputManager currentInputManager];
[currentInputManager markedTextAbandoned:self];
+#pragma clang diagnostic pop
hasMarkedText_ = NO;
// Should not call [self unmarkText] here, because it'll send unnecessary
@@ -3340,7 +3489,7 @@ extern NSString *NSTextInputReplacementRangeAttributeName;
}
- (BOOL)isOpaque {
- return YES;
+ return opaque_;
}
// "-webkit-app-region: drag | no-drag" is implemented on Mac by excluding
diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_mac_dictionary_helper.h b/chromium/content/browser/renderer_host/render_widget_host_view_mac_dictionary_helper.h
index a14d312c776..4a94d9feb22 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_view_mac_dictionary_helper.h
+++ b/chromium/content/browser/renderer_host/render_widget_host_view_mac_dictionary_helper.h
@@ -6,7 +6,7 @@
#define CONTENT_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_VIEW_MAC_DICTIONARY_HELPER_H_
#include "base/basictypes.h"
-#include "ui/gfx/vector2d.h"
+#include "ui/gfx/geometry/vector2d.h"
namespace content {
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 6ecb6698d52..09539ed920b 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
@@ -97,14 +97,14 @@ class RenderWidgetHostEditCommandCounter : public RenderWidgetHostImpl {
class RenderWidgetHostViewMacEditCommandHelperTest : public PlatformTest {
protected:
- virtual void SetUp() {
+ void SetUp() override {
if (IsDelegatedRendererEnabled()) {
ImageTransportFactory::InitializeForUnitTests(
scoped_ptr<ImageTransportFactory>(
new NoTransportImageTransportFactory));
}
}
- virtual void TearDown() {
+ void TearDown() override {
if (IsDelegatedRendererEnabled())
ImageTransportFactory::Terminate();
}
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 685039aefcd..2c8787dc6ca 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
@@ -4,6 +4,8 @@
#include "content/browser/renderer_host/render_widget_host_view_mac.h"
+#include <Cocoa/Cocoa.h>
+
#include "base/mac/mac_util.h"
#include "base/mac/scoped_nsautorelease_pool.h"
#include "base/mac/sdk_forward_declarations.h"
@@ -24,6 +26,8 @@
#include "content/test/test_render_view_host.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#import "third_party/ocmock/OCMock/OCMock.h"
+#import "third_party/ocmock/ocmock_extensions.h"
#include "ui/events/test/cocoa_test_event_utils.h"
#import "ui/gfx/test/ui_cocoa_test_helper.h"
@@ -88,6 +92,27 @@ namespace content {
namespace {
+id MockGestureEvent(NSEventType type, double magnification) {
+ id event = [OCMockObject mockForClass:[NSEvent class]];
+ NSPoint locationInWindow = NSMakePoint(0, 0);
+ CGFloat deltaX = 0;
+ CGFloat deltaY = 0;
+ NSTimeInterval timestamp = 1;
+ NSUInteger modifierFlags = 0;
+
+ [(NSEvent*)[[event stub] andReturnValue:OCMOCK_VALUE(type)] type];
+ [(NSEvent*)[[event stub]
+ andReturnValue:OCMOCK_VALUE(locationInWindow)] locationInWindow];
+ [(NSEvent*)[[event stub] andReturnValue:OCMOCK_VALUE(deltaX)] deltaX];
+ [(NSEvent*)[[event stub] andReturnValue:OCMOCK_VALUE(deltaY)] deltaY];
+ [(NSEvent*)[[event stub] andReturnValue:OCMOCK_VALUE(timestamp)] timestamp];
+ [(NSEvent*)[[event stub]
+ andReturnValue:OCMOCK_VALUE(modifierFlags)] modifierFlags];
+ [(NSEvent*)[[event stub]
+ andReturnValue:OCMOCK_VALUE(magnification)] magnification];
+ return event;
+}
+
class MockRenderWidgetHostDelegate : public RenderWidgetHostDelegate {
public:
MockRenderWidgetHostDelegate() {}
@@ -166,7 +191,7 @@ class RenderWidgetHostViewMacTest : public RenderViewHostImplTestHarness {
public:
RenderWidgetHostViewMacTest() : old_rwhv_(NULL), rwhv_mac_(NULL) {}
- virtual void SetUp() {
+ void SetUp() override {
RenderViewHostImplTestHarness::SetUp();
if (IsDelegatedRendererEnabled()) {
ImageTransportFactory::InitializeForUnitTests(
@@ -183,7 +208,7 @@ class RenderWidgetHostViewMacTest : public RenderViewHostImplTestHarness {
rwhv_mac_ = new RenderWidgetHostViewMac(rvh(), false);
rwhv_cocoa_.reset([rwhv_mac_->cocoa_view() retain]);
}
- virtual void TearDown() {
+ void TearDown() override {
// Make sure the rwhv_mac_ is gone once the superclass's |TearDown()| runs.
rwhv_cocoa_.reset();
RecycleAndWait();
@@ -801,4 +826,197 @@ TEST_F(RenderWidgetHostViewMacTest, GuestViewDoesNotLeak) {
ASSERT_FALSE(guest_rwhv_weak.get());
}
+// Tests setting background transparency. See also (disabled on Mac)
+// RenderWidgetHostTest.Background. This test has some additional checks for
+// Mac.
+TEST_F(RenderWidgetHostViewMacTest, Background) {
+ TestBrowserContext browser_context;
+ MockRenderProcessHost* process_host =
+ new MockRenderProcessHost(&browser_context);
+ MockRenderWidgetHostDelegate delegate;
+ MockRenderWidgetHostImpl* host = new MockRenderWidgetHostImpl(
+ &delegate, process_host, MSG_ROUTING_NONE);
+ RenderWidgetHostViewMac* view = new RenderWidgetHostViewMac(host, false);
+
+ EXPECT_TRUE(view->GetBackgroundOpaque());
+ EXPECT_TRUE([view->cocoa_view() isOpaque]);
+
+ view->SetBackgroundColor(SK_ColorTRANSPARENT);
+ EXPECT_FALSE(view->GetBackgroundOpaque());
+ EXPECT_FALSE([view->cocoa_view() isOpaque]);
+
+ const IPC::Message* set_background;
+ set_background = process_host->sink().GetUniqueMessageMatching(
+ ViewMsg_SetBackgroundOpaque::ID);
+ ASSERT_TRUE(set_background);
+ Tuple<bool> sent_background;
+ ViewMsg_SetBackgroundOpaque::Read(set_background, &sent_background);
+ EXPECT_FALSE(get<0>(sent_background));
+
+ // Try setting it back.
+ process_host->sink().ClearMessages();
+ view->SetBackgroundColor(SK_ColorWHITE);
+ EXPECT_TRUE(view->GetBackgroundOpaque());
+ EXPECT_TRUE([view->cocoa_view() isOpaque]);
+ set_background = process_host->sink().GetUniqueMessageMatching(
+ ViewMsg_SetBackgroundOpaque::ID);
+ ASSERT_TRUE(set_background);
+ ViewMsg_SetBackgroundOpaque::Read(set_background, &sent_background);
+ EXPECT_TRUE(get<0>(sent_background));
+
+ host->Shutdown();
+}
+
+class RenderWidgetHostViewMacPinchTest : public RenderWidgetHostViewMacTest {
+ public:
+ RenderWidgetHostViewMacPinchTest() : process_host_(NULL) {}
+
+ bool ZoomDisabledForPinchUpdateMessage() {
+ const IPC::Message* message = NULL;
+ // The first message may be a PinchBegin. Go for the second message if
+ // there are two.
+ switch (process_host_->sink().message_count()) {
+ case 1:
+ message = process_host_->sink().GetMessageAt(0);
+ break;
+ case 2:
+ message = process_host_->sink().GetMessageAt(1);
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ DCHECK(message);
+ Tuple<IPC::WebInputEventPointer, ui::LatencyInfo, bool> data;
+ InputMsg_HandleInputEvent::Read(message, &data);
+ IPC::WebInputEventPointer ipc_event = get<0>(data);
+ const blink::WebGestureEvent* gesture_event =
+ static_cast<const blink::WebGestureEvent*>(ipc_event);
+ return gesture_event->data.pinchUpdate.zoomDisabled;
+ }
+
+ MockRenderProcessHost* process_host_;
+};
+
+TEST_F(RenderWidgetHostViewMacPinchTest, PinchThresholding) {
+ // This tests Lion+ functionality, so don't run the test pre-Lion.
+ if (!base::mac::IsOSLionOrLater())
+ return;
+
+ // Initialize the view associated with a MockRenderWidgetHostImpl, rather than
+ // the MockRenderProcessHost that is set up by the test harness which mocks
+ // out |OnMessageReceived()|.
+ TestBrowserContext browser_context;
+ process_host_ = new MockRenderProcessHost(&browser_context);
+ MockRenderWidgetHostDelegate delegate;
+ MockRenderWidgetHostImpl* host = new MockRenderWidgetHostImpl(
+ &delegate, process_host_, MSG_ROUTING_NONE);
+ RenderWidgetHostViewMac* view = new RenderWidgetHostViewMac(host, false);
+
+ // We'll use this IPC message to ack events.
+ InputHostMsg_HandleInputEvent_ACK_Params ack;
+ ack.type = blink::WebInputEvent::GesturePinchUpdate;
+ ack.state = INPUT_EVENT_ACK_STATE_CONSUMED;
+ scoped_ptr<IPC::Message> response(
+ new InputHostMsg_HandleInputEvent_ACK(0, ack));
+
+ // Do a gesture that crosses the threshold.
+ {
+ NSEvent* pinchBeginEvent =
+ MockGestureEvent(NSEventTypeBeginGesture, 0);
+ NSEvent* pinchUpdateEvents[3] = {
+ MockGestureEvent(NSEventTypeMagnify, 0.25),
+ MockGestureEvent(NSEventTypeMagnify, 0.25),
+ MockGestureEvent(NSEventTypeMagnify, 0.25),
+ };
+ NSEvent* pinchEndEvent =
+ MockGestureEvent(NSEventTypeEndGesture, 0);
+
+ [view->cocoa_view() beginGestureWithEvent:pinchBeginEvent];
+ EXPECT_EQ(0U, process_host_->sink().message_count());
+
+ // No zoom is sent for the first update event.
+ [view->cocoa_view() magnifyWithEvent:pinchUpdateEvents[0]];
+ host->OnMessageReceived(*response);
+ EXPECT_EQ(2U, process_host_->sink().message_count());
+ EXPECT_TRUE(ZoomDisabledForPinchUpdateMessage());
+ process_host_->sink().ClearMessages();
+
+ // The second update event crosses the threshold of 0.4, and so zoom is no
+ // longer disabled.
+ [view->cocoa_view() magnifyWithEvent:pinchUpdateEvents[1]];
+ EXPECT_FALSE(ZoomDisabledForPinchUpdateMessage());
+ host->OnMessageReceived(*response);
+ EXPECT_EQ(1U, process_host_->sink().message_count());
+ process_host_->sink().ClearMessages();
+
+ // The third update still has zoom enabled.
+ [view->cocoa_view() magnifyWithEvent:pinchUpdateEvents[2]];
+ EXPECT_FALSE(ZoomDisabledForPinchUpdateMessage());
+ host->OnMessageReceived(*response);
+ EXPECT_EQ(1U, process_host_->sink().message_count());
+ process_host_->sink().ClearMessages();
+
+ [view->cocoa_view() endGestureWithEvent:pinchEndEvent];
+ EXPECT_EQ(1U, process_host_->sink().message_count());
+ process_host_->sink().ClearMessages();
+ }
+
+ // Do a gesture that doesn't cross the threshold, but happens when we're not
+ // at page scale factor one, so it should be sent to the renderer.
+ {
+ NSEvent* pinchBeginEvent = MockGestureEvent(NSEventTypeBeginGesture, 0);
+ NSEvent* pinchUpdateEvent = MockGestureEvent(NSEventTypeMagnify, 0.25);
+ NSEvent* pinchEndEvent = MockGestureEvent(NSEventTypeEndGesture, 0);
+
+ view->page_at_minimum_scale_ = false;
+
+ [view->cocoa_view() beginGestureWithEvent:pinchBeginEvent];
+ EXPECT_EQ(0U, process_host_->sink().message_count());
+
+ // Expect that a zoom happen because the time threshold has not passed.
+ [view->cocoa_view() magnifyWithEvent:pinchUpdateEvent];
+ EXPECT_FALSE(ZoomDisabledForPinchUpdateMessage());
+ host->OnMessageReceived(*response);
+ EXPECT_EQ(2U, process_host_->sink().message_count());
+ process_host_->sink().ClearMessages();
+
+ [view->cocoa_view() endGestureWithEvent:pinchEndEvent];
+ EXPECT_EQ(1U, process_host_->sink().message_count());
+ process_host_->sink().ClearMessages();
+ }
+
+ // Do a gesture again, after the page scale is no longer at one, and ensure
+ // that it is thresholded again.
+ {
+ NSEvent* pinchBeginEvent = MockGestureEvent(NSEventTypeBeginGesture, 0);
+ NSEvent* pinchUpdateEvent = MockGestureEvent(NSEventTypeMagnify, 0.25);
+ NSEvent* pinchEndEvent = MockGestureEvent(NSEventTypeEndGesture, 0);
+
+ view->page_at_minimum_scale_ = true;
+
+ [view->cocoa_view() beginGestureWithEvent:pinchBeginEvent];
+ EXPECT_EQ(0U, process_host_->sink().message_count());
+
+ // Get back to zoom one right after the begin event. This should still keep
+ // the thresholding in place (it is latched at the begin event).
+ view->page_at_minimum_scale_ = false;
+
+ // Expect that zoom be disabled because the time threshold has passed.
+ [view->cocoa_view() magnifyWithEvent:pinchUpdateEvent];
+ EXPECT_EQ(2U, process_host_->sink().message_count());
+ EXPECT_TRUE(ZoomDisabledForPinchUpdateMessage());
+ host->OnMessageReceived(*response);
+ process_host_->sink().ClearMessages();
+
+ [view->cocoa_view() endGestureWithEvent:pinchEndEvent];
+ EXPECT_EQ(1U, process_host_->sink().message_count());
+ process_host_->sink().ClearMessages();
+ }
+
+ // Clean up.
+ host->Shutdown();
+}
+
+
} // namespace content
diff --git a/chromium/content/browser/renderer_host/renderer_frame_manager.cc b/chromium/content/browser/renderer_host/renderer_frame_manager.cc
index 0a93e298943..e87732ee5f6 100644
--- a/chromium/content/browser/renderer_host/renderer_frame_manager.cc
+++ b/chromium/content/browser/renderer_host/renderer_frame_manager.cc
@@ -6,12 +6,21 @@
#include <algorithm>
+#include "base/bind.h"
#include "base/logging.h"
+#include "base/memory/memory_pressure_listener.h"
+#include "base/memory/memory_pressure_monitor.h"
#include "base/memory/shared_memory.h"
#include "base/sys_info.h"
#include "content/common/host_shared_bitmap_manager.h"
namespace content {
+namespace {
+
+const int kModeratePressurePercentage = 50;
+const int kCriticalPressurePercentage = 10;
+
+} // namespace
RendererFrameManager* RendererFrameManager::GetInstance() {
return Singleton<RendererFrameManager>::get();
@@ -24,7 +33,7 @@ void RendererFrameManager::AddFrame(RendererFrameManagerClient* frame,
locked_frames_[frame] = 1;
else
unlocked_frames_.push_front(frame);
- CullUnlockedFrames();
+ CullUnlockedFrames(GetMaxNumberOfSavedFrames());
}
void RendererFrameManager::RemoveFrame(RendererFrameManagerClient* frame) {
@@ -57,11 +66,40 @@ void RendererFrameManager::UnlockFrame(RendererFrameManagerClient* frame) {
} else {
RemoveFrame(frame);
unlocked_frames_.push_front(frame);
- CullUnlockedFrames();
+ CullUnlockedFrames(GetMaxNumberOfSavedFrames());
}
}
-RendererFrameManager::RendererFrameManager() {
+size_t RendererFrameManager::GetMaxNumberOfSavedFrames() const {
+ base::MemoryPressureMonitor* monitor = base::MemoryPressureMonitor::Get();
+
+ if (!monitor)
+ return max_number_of_saved_frames_;
+
+ // Until we have a global OnMemoryPressureChanged event we need to query the
+ // value from our specific pressure monitor.
+ int percentage = 100;
+ switch (monitor->GetCurrentPressureLevel()) {
+ case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
+ percentage = 100;
+ break;
+ case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
+ percentage = kModeratePressurePercentage;
+ break;
+ case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
+ percentage = kCriticalPressurePercentage;
+ break;
+ }
+ size_t frames = (max_number_of_saved_frames_ * percentage) / 100;
+ return std::max(static_cast<size_t>(1), frames);
+}
+
+RendererFrameManager::RendererFrameManager()
+ : memory_pressure_listener_(
+ base::Bind(&RendererFrameManager::OnMemoryPressure,
+ base::Unretained(this))) {
+ // Note: With the destruction of this class the |memory_pressure_listener_|
+ // gets destroyed and the observer will remove itself.
max_number_of_saved_frames_ =
#if defined(OS_ANDROID)
1;
@@ -73,9 +111,7 @@ RendererFrameManager::RendererFrameManager() {
RendererFrameManager::~RendererFrameManager() {}
-void RendererFrameManager::CullUnlockedFrames() {
- uint32 saved_frame_limit = max_number_of_saved_frames();
-
+void RendererFrameManager::CullUnlockedFrames(size_t saved_frame_limit) {
if (unlocked_frames_.size() + locked_frames_.size() > 0) {
float handles_per_frame =
HostSharedBitmapManager::current()->AllocatedBitmapCount() * 1.0f /
@@ -95,4 +131,24 @@ void RendererFrameManager::CullUnlockedFrames() {
}
}
+void RendererFrameManager::OnMemoryPressure(
+ base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
+ int saved_frame_limit = max_number_of_saved_frames_;
+ if (saved_frame_limit <= 1)
+ return;
+ int percentage = 100;
+ switch (memory_pressure_level) {
+ case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
+ percentage = kModeratePressurePercentage;
+ break;
+ case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
+ percentage = kCriticalPressurePercentage;
+ break;
+ case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
+ // No need to change anything when there is no pressure.
+ return;
+ }
+ CullUnlockedFrames(std::max(1, (saved_frame_limit * percentage) / 100));
+}
+
} // namespace content
diff --git a/chromium/content/browser/renderer_host/renderer_frame_manager.h b/chromium/content/browser/renderer_host/renderer_frame_manager.h
index f8d90f476f0..8a789ef22cc 100644
--- a/chromium/content/browser/renderer_host/renderer_frame_manager.h
+++ b/chromium/content/browser/renderer_host/renderer_frame_manager.h
@@ -9,17 +9,26 @@
#include <map>
#include "base/basictypes.h"
+#include "base/memory/memory_pressure_listener.h"
#include "base/memory/singleton.h"
#include "content/common/content_export.h"
namespace content {
+class RenderWidgetHostViewAuraTest;
+
class CONTENT_EXPORT RendererFrameManagerClient {
public:
virtual ~RendererFrameManagerClient() {}
virtual void EvictCurrentFrame() = 0;
};
+// This class is responsible for globally managing which renderers keep their
+// compositor frame when offscreen. We actively discard compositor frames for
+// offscreen tabs, but keep a minimum amount, as an LRU cache, to make switching
+// between a small set of tabs faster. The limit is a soft limit, because
+// clients can lock their frame to prevent it from being discarded, e.g. if the
+// tab is visible, or while capturing a screenshot.
class CONTENT_EXPORT RendererFrameManager {
public:
static RendererFrameManager* GetInstance();
@@ -29,20 +38,29 @@ class CONTENT_EXPORT RendererFrameManager {
void LockFrame(RendererFrameManagerClient*);
void UnlockFrame(RendererFrameManagerClient*);
- size_t max_number_of_saved_frames() const {
- return max_number_of_saved_frames_;
- }
+ size_t GetMaxNumberOfSavedFrames() const;
// For testing only
void set_max_handles(float max_handles) { max_handles_ = max_handles; }
private:
+ // Please remove when crbug.com/443824 has been fixed.
+ friend class RenderWidgetHostViewAuraTest;
+
RendererFrameManager();
~RendererFrameManager();
- void CullUnlockedFrames();
+ void CullUnlockedFrames(size_t saved_frame_limit);
+
+ // React on memory pressure events to adjust the number of cached frames.
+ void OnMemoryPressure(
+ base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level);
friend struct DefaultSingletonTraits<RendererFrameManager>;
+ // Listens for system under pressure notifications and adjusts number of
+ // cached frames accordingly.
+ base::MemoryPressureListener memory_pressure_listener_;
+
std::map<RendererFrameManagerClient*, size_t> locked_frames_;
std::list<RendererFrameManagerClient*> unlocked_frames_;
size_t max_number_of_saved_frames_;
diff --git a/chromium/content/browser/renderer_host/sandbox_ipc_linux.cc b/chromium/content/browser/renderer_host/sandbox_ipc_linux.cc
index b2e024e1e8c..bc24bca7249 100644
--- a/chromium/content/browser/renderer_host/sandbox_ipc_linux.cc
+++ b/chromium/content/browser/renderer_host/sandbox_ipc_linux.cc
@@ -144,23 +144,23 @@ void SandboxIPCHandler::HandleRequestFromRenderer(int fd) {
PickleIterator iter(pickle);
int kind;
- if (!pickle.ReadInt(&iter, &kind))
+ if (!iter.ReadInt(&kind))
return;
if (kind == FontConfigIPC::METHOD_MATCH) {
- HandleFontMatchRequest(fd, pickle, iter, fds.get());
+ HandleFontMatchRequest(fd, iter, fds.get());
} else if (kind == FontConfigIPC::METHOD_OPEN) {
- HandleFontOpenRequest(fd, pickle, iter, fds.get());
+ HandleFontOpenRequest(fd, iter, fds.get());
} else if (kind == LinuxSandbox::METHOD_GET_FALLBACK_FONT_FOR_CHAR) {
- HandleGetFallbackFontForChar(fd, pickle, iter, fds.get());
+ HandleGetFallbackFontForChar(fd, iter, fds.get());
} else if (kind == LinuxSandbox::METHOD_LOCALTIME) {
- HandleLocaltime(fd, pickle, iter, fds.get());
+ HandleLocaltime(fd, iter, fds.get());
} else if (kind == LinuxSandbox::METHOD_GET_STYLE_FOR_STRIKE) {
- HandleGetStyleForStrike(fd, pickle, iter, fds.get());
+ HandleGetStyleForStrike(fd, iter, fds.get());
} else if (kind == LinuxSandbox::METHOD_MAKE_SHARED_MEMORY_SEGMENT) {
- HandleMakeSharedMemorySegment(fd, pickle, iter, fds.get());
+ HandleMakeSharedMemorySegment(fd, iter, fds.get());
} else if (kind == LinuxSandbox::METHOD_MATCH_WITH_FALLBACK) {
- HandleMatchWithFallback(fd, pickle, iter, fds.get());
+ HandleMatchWithFallback(fd, iter, fds.get());
}
}
@@ -176,13 +176,11 @@ int SandboxIPCHandler::FindOrAddPath(const SkString& path) {
void SandboxIPCHandler::HandleFontMatchRequest(
int fd,
- const Pickle& pickle,
PickleIterator iter,
const std::vector<base::ScopedFD*>& fds) {
uint32_t requested_style;
std::string family;
- if (!pickle.ReadString(&iter, &family) ||
- !pickle.ReadUInt32(&iter, &requested_style))
+ if (!iter.ReadString(&family) || !iter.ReadUInt32(&requested_style))
return;
SkFontConfigInterface::FontIdentity result_identity;
@@ -216,11 +214,10 @@ void SandboxIPCHandler::HandleFontMatchRequest(
void SandboxIPCHandler::HandleFontOpenRequest(
int fd,
- const Pickle& pickle,
PickleIterator iter,
const std::vector<base::ScopedFD*>& fds) {
uint32_t index;
- if (!pickle.ReadUInt32(&iter, &index))
+ if (!iter.ReadUInt32(&index))
return;
if (index >= static_cast<uint32_t>(paths_.count()))
return;
@@ -245,7 +242,6 @@ void SandboxIPCHandler::HandleFontOpenRequest(
void SandboxIPCHandler::HandleGetFallbackFontForChar(
int fd,
- const Pickle& pickle,
PickleIterator iter,
const std::vector<base::ScopedFD*>& fds) {
// The other side of this call is
@@ -253,11 +249,11 @@ void SandboxIPCHandler::HandleGetFallbackFontForChar(
EnsureWebKitInitialized();
WebUChar32 c;
- if (!pickle.ReadInt(&iter, &c))
+ if (!iter.ReadInt(&c))
return;
std::string preferred_locale;
- if (!pickle.ReadString(&iter, &preferred_locale))
+ if (!iter.ReadString(&preferred_locale))
return;
blink::WebFallbackFont fallbackFont;
@@ -286,23 +282,22 @@ void SandboxIPCHandler::HandleGetFallbackFontForChar(
void SandboxIPCHandler::HandleGetStyleForStrike(
int fd,
- const Pickle& pickle,
PickleIterator iter,
const std::vector<base::ScopedFD*>& fds) {
std::string family;
bool bold, italic;
uint16 pixel_size;
- if (!pickle.ReadString(&iter, &family) ||
- !pickle.ReadBool(&iter, &bold) ||
- !pickle.ReadBool(&iter, &italic) ||
- !pickle.ReadUInt16(&iter, &pixel_size)) {
+ if (!iter.ReadString(&family) ||
+ !iter.ReadBool(&bold) ||
+ !iter.ReadBool(&italic) ||
+ !iter.ReadUInt16(&pixel_size)) {
return;
}
EnsureWebKitInitialized();
- gfx::FontRenderParamsQuery query(true);
+ gfx::FontRenderParamsQuery query;
query.families.push_back(family);
query.pixel_size = pixel_size;
query.style = gfx::Font::NORMAL |
@@ -325,16 +320,13 @@ void SandboxIPCHandler::HandleGetStyleForStrike(
void SandboxIPCHandler::HandleLocaltime(
int fd,
- const Pickle& pickle,
PickleIterator iter,
const std::vector<base::ScopedFD*>& fds) {
// The other side of this call is in zygote_main_linux.cc
std::string time_string;
- if (!pickle.ReadString(&iter, &time_string) ||
- time_string.size() != sizeof(time_t)) {
+ if (!iter.ReadString(&time_string) || time_string.size() != sizeof(time_t))
return;
- }
time_t time;
memcpy(&time, time_string.data(), sizeof(time));
@@ -358,15 +350,14 @@ void SandboxIPCHandler::HandleLocaltime(
void SandboxIPCHandler::HandleMakeSharedMemorySegment(
int fd,
- const Pickle& pickle,
PickleIterator iter,
const std::vector<base::ScopedFD*>& fds) {
base::SharedMemoryCreateOptions options;
uint32_t size;
- if (!pickle.ReadUInt32(&iter, &size))
+ if (!iter.ReadUInt32(&size))
return;
options.size = size;
- if (!pickle.ReadBool(&iter, &options.executable))
+ if (!iter.ReadBool(&options.executable))
return;
int shm_fd = -1;
base::SharedMemory shm;
@@ -378,18 +369,17 @@ void SandboxIPCHandler::HandleMakeSharedMemorySegment(
void SandboxIPCHandler::HandleMatchWithFallback(
int fd,
- const Pickle& pickle,
PickleIterator iter,
const std::vector<base::ScopedFD*>& fds) {
std::string face;
bool is_bold, is_italic;
uint32 charset, fallback_family;
- if (!pickle.ReadString(&iter, &face) || face.empty() ||
- !pickle.ReadBool(&iter, &is_bold) ||
- !pickle.ReadBool(&iter, &is_italic) ||
- !pickle.ReadUInt32(&iter, &charset) ||
- !pickle.ReadUInt32(&iter, &fallback_family)) {
+ if (!iter.ReadString(&face) || face.empty() ||
+ !iter.ReadBool(&is_bold) ||
+ !iter.ReadBool(&is_italic) ||
+ !iter.ReadUInt32(&charset) ||
+ !iter.ReadUInt32(&fallback_family)) {
return;
}
diff --git a/chromium/content/browser/renderer_host/sandbox_ipc_linux.h b/chromium/content/browser/renderer_host/sandbox_ipc_linux.h
index e6ac19bbfac..33b58c26c39 100644
--- a/chromium/content/browser/renderer_host/sandbox_ipc_linux.h
+++ b/chromium/content/browser/renderer_host/sandbox_ipc_linux.h
@@ -4,8 +4,8 @@
// http://code.google.com/p/chromium/wiki/LinuxSandboxIPC
-#ifndef CONTENT_BROWSER_RENDERER_HOST_SANDBOX_IPC_H_
-#define CONTENT_BROWSER_RENDERER_HOST_SANDBOX_IPC_H_
+#ifndef CONTENT_BROWSER_RENDERER_HOST_SANDBOX_IPC_LINUX_H_
+#define CONTENT_BROWSER_RENDERER_HOST_SANDBOX_IPC_LINUX_H_
#include <vector>
@@ -36,37 +36,30 @@ class SandboxIPCHandler : public base::DelegateSimpleThread::Delegate {
void HandleRequestFromRenderer(int fd);
void HandleFontMatchRequest(int fd,
- const Pickle& pickle,
PickleIterator iter,
const std::vector<base::ScopedFD*>& fds);
void HandleFontOpenRequest(int fd,
- const Pickle& pickle,
PickleIterator iter,
const std::vector<base::ScopedFD*>& fds);
void HandleGetFallbackFontForChar(int fd,
- const Pickle& pickle,
PickleIterator iter,
const std::vector<base::ScopedFD*>& fds);
void HandleGetStyleForStrike(int fd,
- const Pickle& pickle,
PickleIterator iter,
const std::vector<base::ScopedFD*>& fds);
void HandleLocaltime(int fd,
- const Pickle& pickle,
PickleIterator iter,
const std::vector<base::ScopedFD*>& fds);
void HandleMakeSharedMemorySegment(int fd,
- const Pickle& pickle,
PickleIterator iter,
const std::vector<base::ScopedFD*>& fds);
void HandleMatchWithFallback(int fd,
- const Pickle& pickle,
PickleIterator iter,
const std::vector<base::ScopedFD*>& fds);
@@ -84,4 +77,4 @@ class SandboxIPCHandler : public base::DelegateSimpleThread::Delegate {
} // namespace content
-#endif // CONTENT_BROWSER_RENDERER_HOST_SANDBOX_IPC_H_
+#endif // CONTENT_BROWSER_RENDERER_HOST_SANDBOX_IPC_LINUX_H_
diff --git a/chromium/content/browser/renderer_host/software_frame_manager.cc b/chromium/content/browser/renderer_host/software_frame_manager.cc
deleted file mode 100644
index 08ac5000a14..00000000000
--- a/chromium/content/browser/renderer_host/software_frame_manager.cc
+++ /dev/null
@@ -1,180 +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/software_frame_manager.h"
-
-#include "base/bind.h"
-#include "base/callback_helpers.h"
-#include "base/debug/alias.h"
-#include "base/numerics/safe_math.h"
-#include "cc/resources/shared_bitmap.h"
-#include "content/browser/renderer_host/dip_util.h"
-#include "content/common/host_shared_bitmap_manager.h"
-#include "content/public/browser/user_metrics.h"
-
-namespace {
-
-void ReleaseMailbox(scoped_refptr<content::SoftwareFrame> frame,
- uint32 sync_point,
- bool lost_resource) {}
-
-} // namespace
-
-namespace content {
-
-////////////////////////////////////////////////////////////////////////////////
-// SoftwareFrame
-
-class CONTENT_EXPORT SoftwareFrame : public base::RefCounted<SoftwareFrame> {
- private:
- friend class base::RefCounted<SoftwareFrame>;
- friend class SoftwareFrameManager;
-
- SoftwareFrame(base::WeakPtr<SoftwareFrameManagerClient> frame_manager_client,
- uint32 output_surface_id,
- unsigned frame_id,
- float frame_device_scale_factor,
- gfx::Size frame_size_pixels,
- scoped_ptr<cc::SharedBitmap> shared_bitmap);
- ~SoftwareFrame();
-
- base::WeakPtr<SoftwareFrameManagerClient> frame_manager_client_;
- const uint32 output_surface_id_;
- const unsigned frame_id_;
- float frame_device_scale_factor_;
- const gfx::Size frame_size_pixels_;
- scoped_ptr<cc::SharedBitmap> shared_bitmap_;
-
- DISALLOW_COPY_AND_ASSIGN(SoftwareFrame);
-};
-
-SoftwareFrame::SoftwareFrame(
- base::WeakPtr<SoftwareFrameManagerClient> frame_manager_client,
- uint32 output_surface_id,
- unsigned frame_id,
- float frame_device_scale_factor,
- gfx::Size frame_size_pixels,
- scoped_ptr<cc::SharedBitmap> shared_bitmap)
- : frame_manager_client_(frame_manager_client),
- output_surface_id_(output_surface_id),
- frame_id_(frame_id),
- frame_device_scale_factor_(frame_device_scale_factor),
- frame_size_pixels_(frame_size_pixels),
- shared_bitmap_(shared_bitmap.Pass()) {}
-
-SoftwareFrame::~SoftwareFrame() {
- if (frame_manager_client_) {
- frame_manager_client_->SoftwareFrameWasFreed(
- output_surface_id_, frame_id_);
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// SoftwareFrameManager
-
-SoftwareFrameManager::SoftwareFrameManager(
- base::WeakPtr<SoftwareFrameManagerClient> client)
- : client_(client) {}
-
-SoftwareFrameManager::~SoftwareFrameManager() {
- DiscardCurrentFrame();
-}
-
-bool SoftwareFrameManager::SwapToNewFrame(
- uint32 output_surface_id,
- const cc::SoftwareFrameData* frame_data,
- float frame_device_scale_factor,
- base::ProcessHandle process_handle) {
- scoped_ptr<cc::SharedBitmap> shared_bitmap =
- HostSharedBitmapManager::current()->GetSharedBitmapFromId(
- frame_data->size, frame_data->bitmap_id);
-
- if (!shared_bitmap) {
- RecordAction(
- base::UserMetricsAction("BadMessageTerminate_SharedMemoryManager1"));
- return false;
- }
-
- scoped_refptr<SoftwareFrame> next_frame(
- new SoftwareFrame(client_,
- output_surface_id,
- frame_data->id,
- frame_device_scale_factor,
- frame_data->size,
- shared_bitmap.Pass()));
- current_frame_.swap(next_frame);
- return true;
-}
-
-bool SoftwareFrameManager::HasCurrentFrame() const {
- return current_frame_.get() ? true : false;
-}
-
-void SoftwareFrameManager::DiscardCurrentFrame() {
- if (!HasCurrentFrame())
- return;
- current_frame_ = NULL;
- RendererFrameManager::GetInstance()->RemoveFrame(this);
-}
-
-void SoftwareFrameManager::SwapToNewFrameComplete(bool visible) {
- DCHECK(HasCurrentFrame());
- RendererFrameManager::GetInstance()->AddFrame(this, visible);
-}
-
-void SoftwareFrameManager::SetVisibility(bool visible) {
- if (HasCurrentFrame()) {
- if (visible) {
- RendererFrameManager::GetInstance()->LockFrame(this);
- } else {
- RendererFrameManager::GetInstance()->UnlockFrame(this);
- }
- }
-}
-
-uint32 SoftwareFrameManager::GetCurrentFrameOutputSurfaceId() const {
- DCHECK(HasCurrentFrame());
- return current_frame_->output_surface_id_;
-}
-
-void SoftwareFrameManager::GetCurrentFrameMailbox(
- cc::TextureMailbox* mailbox,
- scoped_ptr<cc::SingleReleaseCallback>* callback) {
- DCHECK(HasCurrentFrame());
- *mailbox = cc::TextureMailbox(current_frame_->shared_bitmap_->memory(),
- current_frame_->frame_size_pixels_);
- *callback = cc::SingleReleaseCallback::Create(
- base::Bind(ReleaseMailbox, current_frame_));
-}
-
-void* SoftwareFrameManager::GetCurrentFramePixels() const {
- DCHECK(HasCurrentFrame());
- DCHECK(current_frame_->shared_bitmap_);
- return current_frame_->shared_bitmap_->pixels();
-}
-
-float SoftwareFrameManager::GetCurrentFrameDeviceScaleFactor() const {
- DCHECK(HasCurrentFrame());
- return current_frame_->frame_device_scale_factor_;
-}
-
-gfx::Size SoftwareFrameManager::GetCurrentFrameSizeInPixels() const {
- DCHECK(HasCurrentFrame());
- return current_frame_->frame_size_pixels_;
-}
-
-gfx::Size SoftwareFrameManager::GetCurrentFrameSizeInDIP() const {
- DCHECK(HasCurrentFrame());
- return ConvertSizeToDIP(current_frame_->frame_device_scale_factor_,
- current_frame_->frame_size_pixels_);
-}
-
-void SoftwareFrameManager::EvictCurrentFrame() {
- DCHECK(HasCurrentFrame());
- DiscardCurrentFrame();
- if (client_)
- client_->ReleaseReferencesToSoftwareFrame();
-}
-
-} // namespace content
diff --git a/chromium/content/browser/renderer_host/software_frame_manager.h b/chromium/content/browser/renderer_host/software_frame_manager.h
deleted file mode 100644
index 55729857080..00000000000
--- a/chromium/content/browser/renderer_host/software_frame_manager.h
+++ /dev/null
@@ -1,79 +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_SOFTWARE_FRAME_MANAGER_H_
-#define CONTENT_BROWSER_RENDERER_HOST_SOFTWARE_FRAME_MANAGER_H_
-
-#include <list>
-#include <set>
-
-#include "base/basictypes.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/shared_memory.h"
-#include "base/memory/weak_ptr.h"
-#include "cc/output/software_frame_data.h"
-#include "cc/resources/single_release_callback.h"
-#include "cc/resources/texture_mailbox.h"
-#include "content/browser/renderer_host/renderer_frame_manager.h"
-#include "content/common/content_export.h"
-#include "ui/gfx/size.h"
-
-namespace content {
-class SoftwareFrame;
-
-class CONTENT_EXPORT SoftwareFrameManagerClient {
- public:
- // Called when the memory for the current software frame was freed.
- virtual void SoftwareFrameWasFreed(
- uint32 output_surface_id, unsigned frame_id) = 0;
-
- // Called when the SoftwareFrameMemoryManager has requested that the frame
- // be evicted. Upon receiving this callback, the client should release any
- // references that it may hold to the current frame, to ensure that its memory
- // is freed expediently.
- virtual void ReleaseReferencesToSoftwareFrame() = 0;
-};
-
-class CONTENT_EXPORT SoftwareFrameManager : public RendererFrameManagerClient {
- public:
- explicit SoftwareFrameManager(
- base::WeakPtr<SoftwareFrameManagerClient> client);
- ~SoftwareFrameManager() override;
-
- // Swaps to a new frame from shared memory. This frame is guaranteed to
- // not be evicted until SwapToNewFrameComplete is called.
- bool SwapToNewFrame(
- uint32 output_surface_id,
- const cc::SoftwareFrameData* frame_data,
- float frame_device_scale_factor,
- base::ProcessHandle process_handle);
- void SwapToNewFrameComplete(bool visible);
- void SetVisibility(bool visible);
- bool HasCurrentFrame() const;
- void DiscardCurrentFrame();
- uint32 GetCurrentFrameOutputSurfaceId() const;
- void GetCurrentFrameMailbox(
- cc::TextureMailbox* mailbox,
- scoped_ptr<cc::SingleReleaseCallback>* callback);
- void* GetCurrentFramePixels() const;
- float GetCurrentFrameDeviceScaleFactor() const;
- gfx::Size GetCurrentFrameSizeInPixels() const;
- gfx::Size GetCurrentFrameSizeInDIP() const;
-
- private:
- // Called by SoftwareFrameMemoryManager to demand that the current frame
- // be evicted.
- void EvictCurrentFrame() override;
-
- base::WeakPtr<SoftwareFrameManagerClient> client_;
-
- // This holds the current software framebuffer.
- scoped_refptr<SoftwareFrame> current_frame_;
-
- DISALLOW_COPY_AND_ASSIGN(SoftwareFrameManager);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_RENDERER_HOST_SOFTWARE_FRAME_MANAGER_H_
diff --git a/chromium/content/browser/renderer_host/software_frame_manager_unittest.cc b/chromium/content/browser/renderer_host/software_frame_manager_unittest.cc
deleted file mode 100644
index 0569f259f1b..00000000000
--- a/chromium/content/browser/renderer_host/software_frame_manager_unittest.cc
+++ /dev/null
@@ -1,266 +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/software_frame_manager.h"
-
-#include <vector>
-
-#include "base/memory/scoped_vector.h"
-#include "base/memory/shared_memory.h"
-#include "base/sys_info.h"
-#include "content/common/host_shared_bitmap_manager.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace content {
-
-class FakeSoftwareFrameManagerClient : public SoftwareFrameManagerClient {
- public:
- FakeSoftwareFrameManagerClient()
- : evicted_count_(0), weak_ptr_factory_(this) {
- software_frame_manager_.reset(new SoftwareFrameManager(
- weak_ptr_factory_.GetWeakPtr()));
- }
- virtual ~FakeSoftwareFrameManagerClient() {
- HostSharedBitmapManager::current()->ProcessRemoved(
- base::GetCurrentProcessHandle());
- }
- void SoftwareFrameWasFreed(uint32 output_surface_id,
- unsigned frame_id) override {
- freed_frames_.push_back(std::make_pair(output_surface_id, frame_id));
- }
- void ReleaseReferencesToSoftwareFrame() override { ++evicted_count_; }
-
- bool SwapToNewFrame(uint32 output_surface, unsigned frame_id) {
- cc::SoftwareFrameData frame;
- frame.id = frame_id;
- frame.size = gfx::Size(1, 1);
- frame.damage_rect = gfx::Rect(frame.size);
- frame.bitmap_id = cc::SharedBitmap::GenerateId();
- scoped_ptr<base::SharedMemory> memory =
- make_scoped_ptr(new base::SharedMemory);
- memory->CreateAnonymous(4);
- HostSharedBitmapManager::current()->ChildAllocatedSharedBitmap(
- 4, memory->handle(), base::GetCurrentProcessHandle(), frame.bitmap_id);
- allocated_memory_.push_back(memory.release());
- return software_frame_manager_->SwapToNewFrame(
- output_surface, &frame, 1.0, base::GetCurrentProcessHandle());
- }
-
- SoftwareFrameManager* software_frame_manager() {
- return software_frame_manager_.get();
- }
- size_t freed_frame_count() const { return freed_frames_.size(); }
- size_t evicted_frame_count() const { return evicted_count_; }
-
- private:
- std::vector<std::pair<uint32,unsigned> > freed_frames_;
- size_t evicted_count_;
- ScopedVector<base::SharedMemory> allocated_memory_;
-
- scoped_ptr<SoftwareFrameManager> software_frame_manager_;
- base::WeakPtrFactory<FakeSoftwareFrameManagerClient>
- weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(FakeSoftwareFrameManagerClient);
-};
-
-class SoftwareFrameManagerTest : public testing::Test {
- public:
- SoftwareFrameManagerTest() {}
- void AllocateClients(size_t num_clients) {
- for (size_t i = 0; i < num_clients; ++i)
- clients_.push_back(new FakeSoftwareFrameManagerClient);
- }
- void FreeClients() {
- for (size_t i = 0; i < clients_.size(); ++i)
- delete clients_[i];
- clients_.clear();
- }
- size_t MaxNumberOfSavedFrames() const {
- size_t result =
- RendererFrameManager::GetInstance()->max_number_of_saved_frames();
- return result;
- }
-
- protected:
- std::vector<FakeSoftwareFrameManagerClient*> clients_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(SoftwareFrameManagerTest);
-};
-
-TEST_F(SoftwareFrameManagerTest, DoNotEvictVisible) {
- // Create twice as many frames as are allowed.
- AllocateClients(2 * MaxNumberOfSavedFrames());
-
- // Swap a visible frame to all clients_. Because they are all visible,
- // the should not be evicted.
- for (size_t i = 0; i < clients_.size(); ++i) {
- bool swap_result = clients_[i]->SwapToNewFrame(
- static_cast<uint32>(i), 0);
- clients_[i]->software_frame_manager()->SwapToNewFrameComplete(true);
- EXPECT_TRUE(swap_result);
- EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
- EXPECT_EQ(0u, clients_[i]->freed_frame_count());
- }
- for (size_t i = 0; i < clients_.size(); ++i) {
- EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
- EXPECT_EQ(0u, clients_[i]->freed_frame_count());
- }
-
- // Swap another frame and make sure the original was freed (but not evicted).
- for (size_t i = 0; i < clients_.size(); ++i) {
- bool swap_result = clients_[i]->SwapToNewFrame(
- static_cast<uint32>(i), 1);
- clients_[i]->software_frame_manager()->SwapToNewFrameComplete(true);
- EXPECT_TRUE(swap_result);
- EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
- EXPECT_EQ(1u, clients_[i]->freed_frame_count());
- }
- for (size_t i = 0; i < clients_.size(); ++i) {
- EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
- EXPECT_EQ(1u, clients_[i]->freed_frame_count());
- }
-
- // Mark the frames as nonvisible and make sure they start getting evicted.
- for (size_t i = 0; i < clients_.size(); ++i) {
- clients_[i]->software_frame_manager()->SetVisibility(false);
- if (clients_.size() - i > MaxNumberOfSavedFrames()) {
- EXPECT_EQ(1u, clients_[i]->evicted_frame_count());
- EXPECT_EQ(2u, clients_[i]->freed_frame_count());
- } else {
- EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
- EXPECT_EQ(1u, clients_[i]->freed_frame_count());
- }
- }
-
- // Clean up.
- FreeClients();
-}
-
-TEST_F(SoftwareFrameManagerTest, DoNotEvictDuringSwap) {
- // Create twice as many frames as are allowed.
- AllocateClients(2 * MaxNumberOfSavedFrames());
-
- // Swap a visible frame to all clients_. Because they are all visible,
- // the should not be evicted.
- for (size_t i = 0; i < clients_.size(); ++i) {
- bool swap_result = clients_[i]->SwapToNewFrame(static_cast<uint32>(i), 0);
- clients_[i]->software_frame_manager()->SwapToNewFrameComplete(true);
- EXPECT_TRUE(swap_result);
- EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
- EXPECT_EQ(0u, clients_[i]->freed_frame_count());
- }
- for (size_t i = 0; i < clients_.size(); ++i) {
- EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
- EXPECT_EQ(0u, clients_[i]->freed_frame_count());
- }
-
- // Now create a test non-visible client, and swap a non-visible frame in.
- scoped_ptr<FakeSoftwareFrameManagerClient> test_client(
- new FakeSoftwareFrameManagerClient);
- test_client->software_frame_manager()->SetVisibility(false);
- {
- bool swap_result = test_client->SwapToNewFrame(
- static_cast<uint32>(500), 0);
- EXPECT_TRUE(swap_result);
- EXPECT_EQ(0u, test_client->evicted_frame_count());
- EXPECT_EQ(0u, test_client->freed_frame_count());
- test_client->software_frame_manager()->SwapToNewFrameComplete(false);
- EXPECT_EQ(1u, test_client->evicted_frame_count());
- EXPECT_EQ(1u, test_client->freed_frame_count());
- }
-
- // Clean up.
- FreeClients();
-}
-
-TEST_F(SoftwareFrameManagerTest, Cleanup) {
- // Create twice as many frames as are allowed.
- AllocateClients(2 * MaxNumberOfSavedFrames());
-
- // Swap a visible frame to all clients_. Because they are all visible,
- // the should not be evicted.
- for (size_t i = 0; i < clients_.size(); ++i) {
- bool swap_result = clients_[i]->SwapToNewFrame(static_cast<uint32>(i), 0);
- clients_[i]->software_frame_manager()->SwapToNewFrameComplete(true);
- EXPECT_TRUE(swap_result);
- EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
- EXPECT_EQ(0u, clients_[i]->freed_frame_count());
- }
-
- // Destroy them.
- FreeClients();
-
- // Create the maximum number of frames, all non-visible. They should not
- // be evicted, because the previous frames were cleaned up at destruction.
- AllocateClients(MaxNumberOfSavedFrames());
- for (size_t i = 0; i < clients_.size(); ++i) {
- cc::SoftwareFrameData frame;
- bool swap_result = clients_[i]->SwapToNewFrame(static_cast<uint32>(i), 0);
- clients_[i]->software_frame_manager()->SwapToNewFrameComplete(true);
- EXPECT_TRUE(swap_result);
- EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
- EXPECT_EQ(0u, clients_[i]->freed_frame_count());
- }
- for (size_t i = 0; i < clients_.size(); ++i) {
- EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
- EXPECT_EQ(0u, clients_[i]->freed_frame_count());
- }
-
- // Clean up.
- FreeClients();
-}
-
-TEST_F(SoftwareFrameManagerTest, EvictVersusFree) {
- // Create twice as many frames as are allowed and swap a visible frame to all
- // clients_. Because they are all visible, the should not be evicted.
- AllocateClients(2 * MaxNumberOfSavedFrames());
- for (size_t i = 0; i < clients_.size(); ++i) {
- clients_[i]->SwapToNewFrame(static_cast<uint32>(i), 0);
- clients_[i]->software_frame_manager()->SwapToNewFrameComplete(true);
- }
-
- // Create a test client with a frame that is not evicted.
- scoped_ptr<FakeSoftwareFrameManagerClient> test_client(
- new FakeSoftwareFrameManagerClient);
- bool swap_result = test_client->SwapToNewFrame(static_cast<uint32>(500), 0);
- EXPECT_TRUE(swap_result);
- test_client->software_frame_manager()->SwapToNewFrameComplete(true);
- EXPECT_EQ(0u, test_client->evicted_frame_count());
- EXPECT_EQ(0u, test_client->freed_frame_count());
-
- // Take out a reference on the current frame and make the memory manager
- // evict it. The frame will not be freed until this reference is released.
- cc::TextureMailbox mailbox;
- scoped_ptr<cc::SingleReleaseCallback> callback;
- test_client->software_frame_manager()->GetCurrentFrameMailbox(
- &mailbox, &callback);
- test_client->software_frame_manager()->SetVisibility(false);
- EXPECT_EQ(1u, test_client->evicted_frame_count());
- EXPECT_EQ(0u, test_client->freed_frame_count());
-
- // Swap a few frames. The frames will be freed as they are swapped out.
- for (size_t frame = 0; frame < 10; ++frame) {
- bool swap_result = test_client->SwapToNewFrame(
- static_cast<uint32>(500), 1 + static_cast<int>(frame));
- EXPECT_TRUE(swap_result);
- test_client->software_frame_manager()->SwapToNewFrameComplete(true);
- EXPECT_EQ(frame, test_client->freed_frame_count());
- EXPECT_EQ(1u, test_client->evicted_frame_count());
- }
-
- // The reference to the frame that we didn't free is in the callback
- // object. It will go away when the callback is destroyed.
- EXPECT_EQ(9u, test_client->freed_frame_count());
- EXPECT_EQ(1u, test_client->evicted_frame_count());
- callback->Run(0, false);
- callback.reset();
- EXPECT_EQ(10u, test_client->freed_frame_count());
- EXPECT_EQ(1u, test_client->evicted_frame_count());
-
- FreeClients();
-}
-
-} // namespace content
diff --git a/chromium/content/browser/renderer_host/text_input_client_mac.h b/chromium/content/browser/renderer_host/text_input_client_mac.h
index 6a079471352..4e50eff5c7e 100644
--- a/chromium/content/browser/renderer_host/text_input_client_mac.h
+++ b/chromium/content/browser/renderer_host/text_input_client_mac.h
@@ -12,7 +12,7 @@
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
#include "content/common/content_export.h"
-#include "ui/gfx/point.h"
+#include "ui/gfx/geometry/point.h"
template <typename T> struct DefaultSingletonTraits;
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 e208ccd953e..4b94a9ec8dd 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
@@ -200,9 +200,10 @@ TEST_F(TextInputClientMacTest, GetSubstring) {
NSDictionary* attributes =
[NSDictionary dictionaryWithObject:[NSColor purpleColor]
forKey:NSForegroundColorAttributeName];
- base::scoped_nsobject<NSAttributedString> kSuccessValue(
- [[NSAttributedString alloc] initWithString:@"Barney is a purple dinosaur"
- attributes:attributes]);
+ base::scoped_nsobject<NSMutableAttributedString> kSuccessValue(
+ [[NSMutableAttributedString alloc]
+ initWithString:@"Barney is a purple dinosaur"
+ attributes:attributes]);
PostTask(FROM_HERE,
base::Bind(&TextInputClientMac::SetSubstringAndSignal,
diff --git a/chromium/content/browser/renderer_host/text_input_client_message_filter.mm b/chromium/content/browser/renderer_host/text_input_client_message_filter.mm
index 76507005778..090daaa522d 100644
--- a/chromium/content/browser/renderer_host/text_input_client_message_filter.mm
+++ b/chromium/content/browser/renderer_host/text_input_client_message_filter.mm
@@ -10,7 +10,7 @@
#include "content/common/text_input_client_messages.h"
#include "content/public/browser/render_widget_host_view.h"
#include "ipc/ipc_message_macros.h"
-#include "ui/gfx/point.h"
+#include "ui/gfx/geometry/point.h"
#include "ui/gfx/range/range.h"
namespace content {
diff --git a/chromium/content/browser/renderer_host/ui_events_helper.cc b/chromium/content/browser/renderer_host/ui_events_helper.cc
index b514425cc88..7aa038e1dcc 100644
--- a/chromium/content/browser/renderer_host/ui_events_helper.cc
+++ b/chromium/content/browser/renderer_host/ui_events_helper.cc
@@ -7,36 +7,12 @@
#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/blink/blink_event_util.h"
#include "ui/events/event.h"
#include "ui/events/event_constants.h"
namespace {
-int WebModifiersToUIFlags(int modifiers) {
- int flags = ui::EF_NONE;
-
- 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::RightButtonDown)
- flags |= ui::EF_RIGHT_MOUSE_BUTTON;
- if (modifiers & blink::WebInputEvent::MiddleButtonDown)
- flags |= ui::EF_MIDDLE_MOUSE_BUTTON;
-
- if (modifiers & blink::WebInputEvent::CapsLockOn)
- flags |= ui::EF_CAPS_LOCK_DOWN;
-
- return flags;
-}
-
ui::EventType WebTouchPointStateToEventType(
blink::WebTouchPoint::State state) {
switch (state) {
@@ -57,38 +33,6 @@ ui::EventType WebTouchPointStateToEventType(
}
}
-blink::WebTouchPoint::State TouchPointStateFromEvent(
- const ui::TouchEvent& event) {
- switch (event.type()) {
- case ui::ET_TOUCH_PRESSED:
- return blink::WebTouchPoint::StatePressed;
- case ui::ET_TOUCH_RELEASED:
- return blink::WebTouchPoint::StateReleased;
- case ui::ET_TOUCH_MOVED:
- return blink::WebTouchPoint::StateMoved;
- case ui::ET_TOUCH_CANCELLED:
- return blink::WebTouchPoint::StateCancelled;
- default:
- return blink::WebTouchPoint::StateUndefined;
- }
-}
-
-blink::WebInputEvent::Type TouchEventTypeFromEvent(
- const ui::TouchEvent& event) {
- switch (event.type()) {
- case ui::ET_TOUCH_PRESSED:
- return blink::WebInputEvent::TouchStart;
- case ui::ET_TOUCH_RELEASED:
- return blink::WebInputEvent::TouchEnd;
- case ui::ET_TOUCH_MOVED:
- return blink::WebInputEvent::TouchMove;
- case ui::ET_TOUCH_CANCELLED:
- return blink::WebInputEvent::TouchCancel;
- default:
- return blink::WebInputEvent::Undefined;
- }
-}
-
} // namespace
namespace content {
@@ -117,7 +61,7 @@ bool MakeUITouchEventsFromWebTouchEvents(
return false;
}
- int flags = WebModifiersToUIFlags(touch.modifiers);
+ int flags = WebEventModifiersToEventFlags(touch.modifiers);
base::TimeDelta timestamp = base::TimeDelta::FromMicroseconds(
static_cast<int64>(touch.timeStampSeconds * 1000000));
for (unsigned i = 0; i < touch.touchesLength; ++i) {
@@ -147,166 +91,9 @@ bool MakeUITouchEventsFromWebTouchEvents(
blink::WebGestureEvent MakeWebGestureEventFromUIEvent(
const ui::GestureEvent& event) {
- blink::WebGestureEvent gesture_event;
-
- switch (event.type()) {
- case ui::ET_GESTURE_TAP:
- gesture_event.type = blink::WebInputEvent::GestureTap;
- gesture_event.data.tap.tapCount = event.details().tap_count();
- gesture_event.data.tap.width = event.details().bounding_box().width();
- gesture_event.data.tap.height = event.details().bounding_box().height();
- break;
- case ui::ET_GESTURE_TAP_DOWN:
- gesture_event.type = blink::WebInputEvent::GestureTapDown;
- gesture_event.data.tapDown.width =
- event.details().bounding_box().width();
- gesture_event.data.tapDown.height =
- event.details().bounding_box().height();
- break;
- case ui::ET_GESTURE_SHOW_PRESS:
- gesture_event.type = blink::WebInputEvent::GestureShowPress;
- gesture_event.data.showPress.width =
- event.details().bounding_box().width();
- gesture_event.data.showPress.height =
- event.details().bounding_box().height();
- break;
- case ui::ET_GESTURE_TAP_CANCEL:
- gesture_event.type = blink::WebInputEvent::GestureTapCancel;
- break;
- case ui::ET_GESTURE_SCROLL_BEGIN:
- gesture_event.type = blink::WebInputEvent::GestureScrollBegin;
- gesture_event.data.scrollBegin.deltaXHint =
- event.details().scroll_x_hint();
- gesture_event.data.scrollBegin.deltaYHint =
- event.details().scroll_y_hint();
- break;
- case ui::ET_GESTURE_SCROLL_UPDATE:
- gesture_event.type = blink::WebInputEvent::GestureScrollUpdate;
- gesture_event.data.scrollUpdate.deltaX = event.details().scroll_x();
- gesture_event.data.scrollUpdate.deltaY = event.details().scroll_y();
- break;
- case ui::ET_GESTURE_SCROLL_END:
- gesture_event.type = blink::WebInputEvent::GestureScrollEnd;
- break;
- case ui::ET_GESTURE_PINCH_BEGIN:
- gesture_event.type = blink::WebInputEvent::GesturePinchBegin;
- break;
- case ui::ET_GESTURE_PINCH_UPDATE:
- gesture_event.type = blink::WebInputEvent::GesturePinchUpdate;
- gesture_event.data.pinchUpdate.scale = event.details().scale();
- break;
- case ui::ET_GESTURE_PINCH_END:
- gesture_event.type = blink::WebInputEvent::GesturePinchEnd;
- break;
- case ui::ET_SCROLL_FLING_START:
- gesture_event.type = blink::WebInputEvent::GestureFlingStart;
- gesture_event.data.flingStart.velocityX = event.details().velocity_x();
- gesture_event.data.flingStart.velocityY = event.details().velocity_y();
- break;
- case ui::ET_SCROLL_FLING_CANCEL:
- gesture_event.type = blink::WebInputEvent::GestureFlingCancel;
- break;
- case ui::ET_GESTURE_LONG_PRESS:
- gesture_event.type = blink::WebInputEvent::GestureLongPress;
- gesture_event.data.longPress.width =
- event.details().bounding_box().width();
- gesture_event.data.longPress.height =
- event.details().bounding_box().height();
- break;
- case ui::ET_GESTURE_LONG_TAP:
- gesture_event.type = blink::WebInputEvent::GestureLongTap;
- gesture_event.data.longPress.width =
- event.details().bounding_box().width();
- gesture_event.data.longPress.height =
- event.details().bounding_box().height();
- break;
- case ui::ET_GESTURE_TWO_FINGER_TAP:
- gesture_event.type = blink::WebInputEvent::GestureTwoFingerTap;
- gesture_event.data.twoFingerTap.firstFingerWidth =
- event.details().first_finger_width();
- gesture_event.data.twoFingerTap.firstFingerHeight =
- event.details().first_finger_height();
- break;
- case ui::ET_GESTURE_BEGIN:
- case ui::ET_GESTURE_END:
- case ui::ET_GESTURE_SWIPE:
- gesture_event.type = blink::WebInputEvent::Undefined;
- break;
- default:
- NOTREACHED() << "Unknown gesture type: " << event.type();
- }
-
- gesture_event.sourceDevice = blink::WebGestureDeviceTouchscreen;
- gesture_event.modifiers = EventFlagsToWebEventModifiers(event.flags());
- gesture_event.timeStampSeconds = event.time_stamp().InSecondsF();
-
- return gesture_event;
-}
-
-blink::WebTouchPoint* UpdateWebTouchEventFromUIEvent(
- const ui::TouchEvent& event,
- blink::WebTouchEvent* web_event) {
- blink::WebTouchPoint* point = NULL;
- switch (event.type()) {
- case ui::ET_TOUCH_PRESSED:
- // Add a new touch point.
- if (web_event->touchesLength < blink::WebTouchEvent::touchesLengthCap) {
- point = &web_event->touches[web_event->touchesLength++];
- point->id = event.touch_id();
- }
- break;
- case ui::ET_TOUCH_RELEASED:
- case ui::ET_TOUCH_CANCELLED:
- case ui::ET_TOUCH_MOVED: {
- // The touch point should have been added to the event from an earlier
- // _PRESSED event. So find that.
- // At the moment, only a maximum of 4 touch-points are allowed. So a
- // simple loop should be sufficient.
- for (unsigned i = 0; i < web_event->touchesLength; ++i) {
- point = web_event->touches + i;
- if (point->id == event.touch_id())
- break;
- point = NULL;
- }
- break;
- }
- default:
- DLOG(WARNING) << "Unknown touch event " << event.type();
- break;
- }
-
- if (!point)
- return NULL;
-
- // The spec requires the radii values to be positive (and 1 when unknown).
- point->radiusX = std::max(1.f, event.radius_x());
- point->radiusY = std::max(1.f, event.radius_y());
- point->rotationAngle = event.rotation_angle();
- point->force = event.force();
-
- // Update the location and state of the point.
- point->state = TouchPointStateFromEvent(event);
- point->position.x = event.x();
- point->position.y = event.y();
-
- const gfx::PointF& root_point = event.root_location_f();
- point->screenPosition.x = root_point.x();
- point->screenPosition.y = root_point.y();
-
- // Mark the rest of the points as stationary.
- for (unsigned i = 0; i < web_event->touchesLength; ++i) {
- blink::WebTouchPoint* iter = web_event->touches + i;
- if (iter != point)
- iter->state = blink::WebTouchPoint::StateStationary;
- }
-
- // Update the type of the touch event.
- WebTouchEventTraits::ResetType(TouchEventTypeFromEvent(event),
- event.time_stamp().InSecondsF(),
- web_event);
- web_event->modifiers = EventFlagsToWebEventModifiers(event.flags());
-
- return point;
+ return ui::CreateWebGestureEvent(event.details(), event.time_stamp(),
+ event.location_f(), event.root_location_f(),
+ event.flags());
}
} // namespace content
diff --git a/chromium/content/browser/renderer_host/ui_events_helper.h b/chromium/content/browser/renderer_host/ui_events_helper.h
index 883ba48cf00..fc57dd7a9e7 100644
--- a/chromium/content/browser/renderer_host/ui_events_helper.h
+++ b/chromium/content/browser/renderer_host/ui_events_helper.h
@@ -48,14 +48,6 @@ CONTENT_EXPORT bool MakeUITouchEventsFromWebTouchEvents(
blink::WebGestureEvent MakeWebGestureEventFromUIEvent(
const ui::GestureEvent& event);
-int EventFlagsToWebEventModifiers(int flags);
-
-// Updates the WebTouchEvent based on the TouchEvent. It returns the updated
-// WebTouchPoint contained in the WebTouchEvent, or NULL if no point was
-// updated.
-blink::WebTouchPoint* UpdateWebTouchEventFromUIEvent(
- const ui::TouchEvent& event,
- blink::WebTouchEvent* web_event);
-}
+} // namespace content
#endif // CONTENT_BROWSER_RENDERER_HOST_UI_EVENTS_HELPER_H_
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 4fe79c16dd1..b09f67e6802 100644
--- a/chromium/content/browser/renderer_host/web_input_event_aura.cc
+++ b/chromium/content/browser/renderer_host/web_input_event_aura.cc
@@ -6,16 +6,35 @@
#include "content/browser/renderer_host/input/web_input_event_util.h"
#include "content/browser/renderer_host/ui_events_helper.h"
+#include "ui/aura/client/screen_position_client.h"
#include "ui/aura/window.h"
+#include "ui/events/blink/blink_event_util.h"
#include "ui/events/event.h"
#include "ui/events/event_utils.h"
-
-#if defined(USE_X11) || defined(USE_OZONE)
-#include "ui/events/keycodes/dom4/keycode_converter.h"
-#endif
+#include "ui/events/keycodes/dom/keycode_converter.h"
namespace content {
+namespace {
+
+gfx::Point GetScreenLocationFromEvent(const ui::LocatedEvent& event) {
+ if (!event.target())
+ return event.root_location();
+
+ aura::Window* root =
+ static_cast<aura::Window*>(event.target())->GetRootWindow();
+ aura::client::ScreenPositionClient* spc =
+ aura::client::GetScreenPositionClient(root);
+ if (!spc)
+ return event.root_location();
+
+ gfx::Point screen_location(event.root_location());
+ spc->ConvertPointToScreen(root, &screen_location);
+ return screen_location;
+}
+
+} // namespace
+
#if defined(OS_WIN)
blink::WebMouseEvent MakeUntranslatedWebMouseEventFromNativeEvent(
const base::NativeEvent& native_event);
@@ -26,17 +45,30 @@ blink::WebKeyboardEvent MakeWebKeyboardEventFromNativeEvent(
blink::WebGestureEvent MakeWebGestureEventFromNativeEvent(
const base::NativeEvent& native_event);
#endif
-#if defined(USE_X11) || defined(USE_OZONE)
+
blink::WebKeyboardEvent MakeWebKeyboardEventFromAuraEvent(
- ui::KeyEvent* event) {
+ const ui::KeyEvent& event) {
blink::WebKeyboardEvent webkit_event;
- webkit_event.timeStampSeconds = event->time_stamp().InSecondsF();
- webkit_event.modifiers = EventFlagsToWebEventModifiers(event->flags());
+ webkit_event.timeStampSeconds = event.time_stamp().InSecondsF();
+ webkit_event.modifiers = ui::EventFlagsToWebEventModifiers(event.flags());
+ switch (ui::KeycodeConverter::DomCodeToLocation(event.code())) {
+ case ui::DomKeyLocation::LEFT:
+ webkit_event.modifiers |= blink::WebInputEvent::IsLeft;
+ break;
+ case ui::DomKeyLocation::RIGHT:
+ webkit_event.modifiers |= blink::WebInputEvent::IsRight;
+ break;
+ case ui::DomKeyLocation::NUMPAD:
+ webkit_event.modifiers |= blink::WebInputEvent::IsKeyPad;
+ break;
+ case ui::DomKeyLocation::STANDARD:
+ break;
+ }
- switch (event->type()) {
+ switch (event.type()) {
case ui::ET_KEY_PRESSED:
- webkit_event.type = event->is_char() ? blink::WebInputEvent::Char :
+ webkit_event.type = event.is_char() ? blink::WebInputEvent::Char :
blink::WebInputEvent::RawKeyDown;
break;
case ui::ET_KEY_RELEASED:
@@ -49,11 +81,12 @@ blink::WebKeyboardEvent MakeWebKeyboardEventFromAuraEvent(
if (webkit_event.modifiers & blink::WebInputEvent::AltKey)
webkit_event.isSystemKey = true;
- webkit_event.windowsKeyCode = event->GetLocatedWindowsKeyboardCode();
+ 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();
+ ui::KeycodeConverter::DomCodeToNativeKeycode(event.code());
+ webkit_event.domCode = static_cast<int>(event.code());
+ webkit_event.unmodifiedText[0] = event.GetUnmodifiedText();
+ webkit_event.text[0] = event.GetText();
webkit_event.setKeyIdentifierFromWindowsKeyCode();
@@ -61,27 +94,27 @@ blink::WebKeyboardEvent MakeWebKeyboardEventFromAuraEvent(
}
blink::WebMouseWheelEvent MakeWebMouseWheelEventFromAuraEvent(
- ui::ScrollEvent* event) {
+ const ui::ScrollEvent& event) {
blink::WebMouseWheelEvent webkit_event;
webkit_event.type = blink::WebInputEvent::MouseWheel;
webkit_event.button = blink::WebMouseEvent::ButtonNone;
- webkit_event.modifiers = EventFlagsToWebEventModifiers(event->flags());
- webkit_event.timeStampSeconds = event->time_stamp().InSecondsF();
+ webkit_event.modifiers = ui::EventFlagsToWebEventModifiers(event.flags());
+ webkit_event.timeStampSeconds = event.time_stamp().InSecondsF();
webkit_event.hasPreciseScrollingDeltas = true;
float offset_ordinal_x = 0.f;
float offset_ordinal_y = 0.f;
- if ((event->flags() & ui::EF_SHIFT_DOWN) != 0 && event->x_offset() == 0) {
- webkit_event.deltaX = event->y_offset();
+ if ((event.flags() & ui::EF_SHIFT_DOWN) != 0 && event.x_offset() == 0) {
+ webkit_event.deltaX = event.y_offset();
webkit_event.deltaY = 0;
- offset_ordinal_x = event->y_offset_ordinal();
- offset_ordinal_y = event->x_offset_ordinal();
+ offset_ordinal_x = event.y_offset_ordinal();
+ offset_ordinal_y = event.x_offset_ordinal();
} else {
- webkit_event.deltaX = event->x_offset();
- webkit_event.deltaY = event->y_offset();
- offset_ordinal_x = event->x_offset_ordinal();
- offset_ordinal_y = event->y_offset_ordinal();
+ webkit_event.deltaX = event.x_offset();
+ webkit_event.deltaY = event.y_offset();
+ offset_ordinal_x = event.x_offset_ordinal();
+ offset_ordinal_y = event.y_offset_ordinal();
}
if (offset_ordinal_x != 0.f && webkit_event.deltaX != 0.f)
@@ -94,37 +127,35 @@ blink::WebMouseWheelEvent MakeWebMouseWheelEventFromAuraEvent(
}
blink::WebGestureEvent MakeWebGestureEventFromAuraEvent(
- ui::ScrollEvent* event) {
+ const ui::ScrollEvent& event) {
blink::WebGestureEvent webkit_event;
- switch (event->type()) {
+ switch (event.type()) {
case ui::ET_SCROLL_FLING_START:
webkit_event.type = blink::WebInputEvent::GestureFlingStart;
- webkit_event.data.flingStart.velocityX = event->x_offset();
- webkit_event.data.flingStart.velocityY = event->y_offset();
+ webkit_event.data.flingStart.velocityX = event.x_offset();
+ webkit_event.data.flingStart.velocityY = event.y_offset();
break;
case ui::ET_SCROLL_FLING_CANCEL:
webkit_event.type = blink::WebInputEvent::GestureFlingCancel;
break;
case ui::ET_SCROLL:
- NOTREACHED() << "Invalid gesture type: " << event->type();
+ NOTREACHED() << "Invalid gesture type: " << event.type();
break;
default:
- NOTREACHED() << "Unknown gesture type: " << event->type();
+ NOTREACHED() << "Unknown gesture type: " << event.type();
}
webkit_event.sourceDevice = blink::WebGestureDeviceTouchpad;
- webkit_event.modifiers = EventFlagsToWebEventModifiers(event->flags());
- webkit_event.timeStampSeconds = event->time_stamp().InSecondsF();
+ webkit_event.modifiers = ui::EventFlagsToWebEventModifiers(event.flags());
+ webkit_event.timeStampSeconds = event.time_stamp().InSecondsF();
return webkit_event;
}
-#endif
-
blink::WebMouseEvent MakeWebMouseEventFromAuraEvent(
- ui::MouseEvent* event);
+ const ui::MouseEvent& event);
blink::WebMouseWheelEvent MakeWebMouseWheelEventFromAuraEvent(
- ui::MouseWheelEvent* event);
+ const ui::MouseWheelEvent& event);
// General approach:
//
@@ -149,39 +180,40 @@ blink::WebMouseWheelEvent MakeWebMouseWheelEventFromAuraEvent(
// ui::MouseEvent. This will not be necessary once only XInput2 is supported.
//
-blink::WebMouseEvent MakeWebMouseEvent(ui::MouseEvent* event) {
+blink::WebMouseEvent MakeWebMouseEvent(const ui::MouseEvent& event) {
// Construct an untranslated event from the platform event data.
blink::WebMouseEvent webkit_event =
#if defined(OS_WIN)
// On Windows we have WM_ events comming from desktop and pure aura
// events comming from metro mode.
- event->native_event().message ?
- MakeUntranslatedWebMouseEventFromNativeEvent(event->native_event()) :
+ event.native_event().message ?
+ MakeUntranslatedWebMouseEventFromNativeEvent(event.native_event()) :
MakeWebMouseEventFromAuraEvent(event);
#else
MakeWebMouseEventFromAuraEvent(event);
#endif
// Replace the event's coordinate fields with translated position data from
// |event|.
- webkit_event.windowX = webkit_event.x = event->x();
- webkit_event.windowY = webkit_event.y = event->y();
+ webkit_event.windowX = webkit_event.x = event.x();
+ webkit_event.windowY = webkit_event.y = event.y();
#if defined(OS_WIN)
- if (event->native_event().message)
+ if (event.native_event().message)
return webkit_event;
#endif
- const gfx::Point root_point = event->root_location();
- webkit_event.globalX = root_point.x();
- webkit_event.globalY = root_point.y();
+ const gfx::Point screen_point = GetScreenLocationFromEvent(event);
+ webkit_event.globalX = screen_point.x();
+ webkit_event.globalY = screen_point.y();
return webkit_event;
}
-blink::WebMouseWheelEvent MakeWebMouseWheelEvent(ui::MouseWheelEvent* event) {
+blink::WebMouseWheelEvent MakeWebMouseWheelEvent(
+ const ui::MouseWheelEvent& event) {
#if defined(OS_WIN)
// Construct an untranslated event from the platform event data.
- blink::WebMouseWheelEvent webkit_event = event->native_event().message ?
- MakeUntranslatedWebMouseWheelEventFromNativeEvent(event->native_event()) :
+ blink::WebMouseWheelEvent webkit_event = event.native_event().message ?
+ MakeUntranslatedWebMouseWheelEventFromNativeEvent(event.native_event()) :
MakeWebMouseWheelEventFromAuraEvent(event);
#else
blink::WebMouseWheelEvent webkit_event =
@@ -190,21 +222,30 @@ blink::WebMouseWheelEvent MakeWebMouseWheelEvent(ui::MouseWheelEvent* event) {
// Replace the event's coordinate fields with translated position data from
// |event|.
- webkit_event.windowX = webkit_event.x = event->x();
- webkit_event.windowY = webkit_event.y = event->y();
-
- const gfx::Point root_point = event->root_location();
- webkit_event.globalX = root_point.x();
- webkit_event.globalY = root_point.y();
+ webkit_event.windowX = webkit_event.x = event.x();
+ webkit_event.windowY = webkit_event.y = event.y();
+
+ const gfx::Point screen_point = GetScreenLocationFromEvent(event);
+ webkit_event.globalX = screen_point.x();
+ webkit_event.globalY = screen_point.y();
+
+ // Scroll events generated from the mouse wheel when the control key is held
+ // don't trigger scrolling. Instead, they may cause zooming.
+ bool from_mouse_wheel = !webkit_event.hasPreciseScrollingDeltas;
+ if ((webkit_event.modifiers & blink::WebInputEvent::ControlKey) &&
+ from_mouse_wheel) {
+ webkit_event.canScroll = false;
+ }
return webkit_event;
}
-blink::WebMouseWheelEvent MakeWebMouseWheelEvent(ui::ScrollEvent* event) {
+blink::WebMouseWheelEvent MakeWebMouseWheelEvent(const ui::ScrollEvent& event) {
#if defined(OS_WIN)
// Construct an untranslated event from the platform event data.
- blink::WebMouseWheelEvent webkit_event =
- MakeUntranslatedWebMouseWheelEventFromNativeEvent(event->native_event());
+ blink::WebMouseWheelEvent webkit_event = event.native_event().message ?
+ MakeUntranslatedWebMouseWheelEventFromNativeEvent(event.native_event()) :
+ MakeWebMouseWheelEventFromAuraEvent(event);
#else
blink::WebMouseWheelEvent webkit_event =
MakeWebMouseWheelEventFromAuraEvent(event);
@@ -212,70 +253,71 @@ blink::WebMouseWheelEvent MakeWebMouseWheelEvent(ui::ScrollEvent* event) {
// Replace the event's coordinate fields with translated position data from
// |event|.
- webkit_event.windowX = webkit_event.x = event->x();
- webkit_event.windowY = webkit_event.y = event->y();
+ webkit_event.windowX = webkit_event.x = event.x();
+ webkit_event.windowY = webkit_event.y = event.y();
- const gfx::Point root_point = event->root_location();
- webkit_event.globalX = root_point.x();
- webkit_event.globalY = root_point.y();
+ const gfx::Point screen_point = GetScreenLocationFromEvent(event);
+ webkit_event.globalX = screen_point.x();
+ webkit_event.globalY = screen_point.y();
return webkit_event;
}
-blink::WebKeyboardEvent MakeWebKeyboardEvent(ui::KeyEvent* event) {
+blink::WebKeyboardEvent MakeWebKeyboardEvent(const ui::KeyEvent& event) {
// 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
+ // event.native_event(). X11 is not so fortunate, there is no separate
// translated event type, so DesktopHostLinux sends an extra KeyEvent with
// 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
- return MakeWebKeyboardEventFromAuraEvent(event);
+ if (event.HasNativeEvent()) {
+ // Key events require no translation by the aura system.
+ blink::WebKeyboardEvent webkit_event(
+ MakeWebKeyboardEventFromNativeEvent(event.native_event()));
+ webkit_event.domCode = static_cast<int>(event.code());
+ return webkit_event;
+ }
#endif
+ return MakeWebKeyboardEventFromAuraEvent(event);
}
-blink::WebGestureEvent MakeWebGestureEvent(ui::GestureEvent* event) {
+blink::WebGestureEvent MakeWebGestureEvent(const ui::GestureEvent& event) {
blink::WebGestureEvent gesture_event;
#if defined(OS_WIN)
- if (event->HasNativeEvent())
- gesture_event = MakeWebGestureEventFromNativeEvent(event->native_event());
+ if (event.HasNativeEvent())
+ gesture_event = MakeWebGestureEventFromNativeEvent(event.native_event());
else
- gesture_event = MakeWebGestureEventFromUIEvent(*event);
+ gesture_event = MakeWebGestureEventFromUIEvent(event);
#else
- gesture_event = MakeWebGestureEventFromUIEvent(*event);
+ gesture_event = MakeWebGestureEventFromUIEvent(event);
#endif
- gesture_event.x = event->x();
- gesture_event.y = event->y();
+ gesture_event.x = event.x();
+ gesture_event.y = event.y();
- const gfx::Point root_point = event->root_location();
- gesture_event.globalX = root_point.x();
- gesture_event.globalY = root_point.y();
+ const gfx::Point screen_point = GetScreenLocationFromEvent(event);
+ gesture_event.globalX = screen_point.x();
+ gesture_event.globalY = screen_point.y();
return gesture_event;
}
-blink::WebGestureEvent MakeWebGestureEvent(ui::ScrollEvent* event) {
+blink::WebGestureEvent MakeWebGestureEvent(const ui::ScrollEvent& event) {
blink::WebGestureEvent gesture_event;
#if defined(OS_WIN)
- gesture_event = MakeWebGestureEventFromNativeEvent(event->native_event());
+ gesture_event = MakeWebGestureEventFromNativeEvent(event.native_event());
#else
gesture_event = MakeWebGestureEventFromAuraEvent(event);
#endif
- gesture_event.x = event->x();
- gesture_event.y = event->y();
+ gesture_event.x = event.x();
+ gesture_event.y = event.y();
- const gfx::Point root_point = event->root_location();
- gesture_event.globalX = root_point.x();
- gesture_event.globalY = root_point.y();
+ const gfx::Point screen_point = GetScreenLocationFromEvent(event);
+ gesture_event.globalX = screen_point.x();
+ gesture_event.globalY = screen_point.y();
return gesture_event;
}
@@ -289,21 +331,22 @@ blink::WebGestureEvent MakeWebGestureEventFlingCancel() {
return gesture_event;
}
-blink::WebMouseEvent MakeWebMouseEventFromAuraEvent(ui::MouseEvent* event) {
+blink::WebMouseEvent MakeWebMouseEventFromAuraEvent(
+ const ui::MouseEvent& event) {
blink::WebMouseEvent webkit_event;
- webkit_event.modifiers = EventFlagsToWebEventModifiers(event->flags());
- webkit_event.timeStampSeconds = event->time_stamp().InSecondsF();
+ webkit_event.modifiers = ui::EventFlagsToWebEventModifiers(event.flags());
+ webkit_event.timeStampSeconds = event.time_stamp().InSecondsF();
webkit_event.button = blink::WebMouseEvent::ButtonNone;
- int button_flags = event->flags();
- if (event->type() == ui::ET_MOUSE_PRESSED ||
- event->type() == ui::ET_MOUSE_RELEASED) {
+ 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 (event.changed_button_flags())
+ button_flags = event.changed_button_flags();
}
if (button_flags & ui::EF_LEFT_MOUSE_BUTTON)
webkit_event.button = blink::WebMouseEvent::ButtonLeft;
@@ -312,14 +355,14 @@ blink::WebMouseEvent MakeWebMouseEventFromAuraEvent(ui::MouseEvent* event) {
if (button_flags & ui::EF_RIGHT_MOUSE_BUTTON)
webkit_event.button = blink::WebMouseEvent::ButtonRight;
- switch (event->type()) {
+ switch (event.type()) {
case ui::ET_MOUSE_PRESSED:
webkit_event.type = blink::WebInputEvent::MouseDown;
- webkit_event.clickCount = event->GetClickCount();
+ webkit_event.clickCount = event.GetClickCount();
break;
case ui::ET_MOUSE_RELEASED:
webkit_event.type = blink::WebInputEvent::MouseUp;
- webkit_event.clickCount = event->GetClickCount();
+ webkit_event.clickCount = event.GetClickCount();
break;
case ui::ET_MOUSE_ENTERED:
case ui::ET_MOUSE_EXITED:
@@ -328,7 +371,7 @@ blink::WebMouseEvent MakeWebMouseEventFromAuraEvent(ui::MouseEvent* event) {
webkit_event.type = blink::WebInputEvent::MouseMove;
break;
default:
- NOTIMPLEMENTED() << "Received unexpected event: " << event->type();
+ NOTIMPLEMENTED() << "Received unexpected event: " << event.type();
break;
}
@@ -336,20 +379,20 @@ blink::WebMouseEvent MakeWebMouseEventFromAuraEvent(ui::MouseEvent* event) {
}
blink::WebMouseWheelEvent MakeWebMouseWheelEventFromAuraEvent(
- ui::MouseWheelEvent* event) {
+ const ui::MouseWheelEvent& event) {
blink::WebMouseWheelEvent webkit_event;
webkit_event.type = blink::WebInputEvent::MouseWheel;
webkit_event.button = blink::WebMouseEvent::ButtonNone;
- webkit_event.modifiers = EventFlagsToWebEventModifiers(event->flags());
- webkit_event.timeStampSeconds = event->time_stamp().InSecondsF();
+ webkit_event.modifiers = ui::EventFlagsToWebEventModifiers(event.flags());
+ webkit_event.timeStampSeconds = event.time_stamp().InSecondsF();
- if ((event->flags() & ui::EF_SHIFT_DOWN) != 0 && event->x_offset() == 0) {
- webkit_event.deltaX = event->y_offset();
+ if ((event.flags() & ui::EF_SHIFT_DOWN) != 0 && event.x_offset() == 0) {
+ webkit_event.deltaX = event.y_offset();
webkit_event.deltaY = 0;
} else {
- webkit_event.deltaX = event->x_offset();
- webkit_event.deltaY = event->y_offset();
+ webkit_event.deltaX = event.x_offset();
+ webkit_event.deltaY = event.y_offset();
}
webkit_event.wheelTicksX = webkit_event.deltaX / kPixelsPerTick;
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 7d6e6ca1bf3..6ce8ed20e38 100644
--- a/chromium/content/browser/renderer_host/web_input_event_aura.h
+++ b/chromium/content/browser/renderer_host/web_input_event_aura.h
@@ -23,17 +23,17 @@ namespace content {
const int kPixelsPerTick = 53;
CONTENT_EXPORT blink::WebMouseEvent MakeWebMouseEvent(
- ui::MouseEvent* event);
+ const ui::MouseEvent& event);
CONTENT_EXPORT blink::WebMouseWheelEvent MakeWebMouseWheelEvent(
- ui::MouseWheelEvent* event);
+ const ui::MouseWheelEvent& event);
CONTENT_EXPORT blink::WebMouseWheelEvent MakeWebMouseWheelEvent(
- ui::ScrollEvent* event);
+ const ui::ScrollEvent& event);
CONTENT_EXPORT blink::WebKeyboardEvent MakeWebKeyboardEvent(
- ui::KeyEvent* event);
+ const ui::KeyEvent& event);
CONTENT_EXPORT blink::WebGestureEvent MakeWebGestureEvent(
- ui::GestureEvent* event);
+ const ui::GestureEvent& event);
CONTENT_EXPORT blink::WebGestureEvent MakeWebGestureEvent(
- ui::ScrollEvent* event);
+ const ui::ScrollEvent& event);
CONTENT_EXPORT blink::WebGestureEvent MakeWebGestureEventFlingCancel();
} // namespace content
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 5a86f734d69..9f0cf473a73 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
@@ -7,6 +7,10 @@
#include "base/basictypes.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/event.h"
+#include "ui/events/event_utils.h"
+#include "ui/events/keycodes/dom/dom_code.h"
+#include "ui/events/keycodes/dom/dom_key.h"
+#include "ui/events/keycodes/dom/keycode_converter.h"
#if defined(USE_X11)
#include <X11/keysym.h>
@@ -20,38 +24,72 @@ namespace content {
// Checks that MakeWebKeyboardEvent makes a DOM3 spec compliant key event.
// crbug.com/127142
TEST(WebInputEventAuraTest, TestMakeWebKeyboardEvent) {
+ {
+ // Press Ctrl.
+ ui::KeyEvent event(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL,
+ ui::DomCode::CONTROL_LEFT, ui::EF_CONTROL_DOWN);
+ blink::WebKeyboardEvent webkit_event = MakeWebKeyboardEvent(event);
+ // However, modifier bit for Control in |webkit_event| should be set.
+ EXPECT_EQ(blink::WebInputEvent::ControlKey | blink::WebInputEvent::IsLeft,
+ webkit_event.modifiers);
+ EXPECT_EQ(static_cast<int>(ui::DomCode::CONTROL_LEFT),
+ webkit_event.domCode);
+ }
+ {
+ // Release Ctrl.
+ ui::KeyEvent event(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL,
+ ui::DomCode::CONTROL_LEFT, ui::EF_NONE);
+ blink::WebKeyboardEvent webkit_event = MakeWebKeyboardEvent(event);
+ // However, modifier bit for Control in |webkit_event| shouldn't be set.
+ EXPECT_EQ(blink::WebInputEvent::IsLeft, webkit_event.modifiers);
+ EXPECT_EQ(static_cast<int>(ui::DomCode::CONTROL_LEFT),
+ webkit_event.domCode);
+ }
#if defined(USE_X11)
+ const int kLocationModifiers =
+ blink::WebInputEvent::IsLeft | blink::WebInputEvent::IsRight;
ui::ScopedXI2Event xev;
{
// Press Ctrl.
xev.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL, 0);
ui::KeyEvent event(xev);
- blink::WebKeyboardEvent webkit_event = MakeWebKeyboardEvent(&event);
+ 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);
+ EXPECT_EQ(blink::WebInputEvent::ControlKey,
+ webkit_event.modifiers & ~kLocationModifiers);
}
{
// Release Ctrl.
xev.InitKeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL, ControlMask);
ui::KeyEvent event(xev);
- blink::WebKeyboardEvent webkit_event = MakeWebKeyboardEvent(&event);
+ blink::WebKeyboardEvent webkit_event = MakeWebKeyboardEvent(event);
// However, modifier bit for Control in |webkit_event| shouldn't be set.
- EXPECT_EQ(webkit_event.modifiers, 0);
+ EXPECT_EQ(0, webkit_event.modifiers & ~kLocationModifiers);
}
#endif
}
// Checks that MakeWebKeyboardEvent returns a correct windowsKeyCode.
-TEST(WebInputEventAuraTest, TestMakeWebKeyboardEventWindowsKeyCode) {
+#if defined(OS_CHROMEOS) || defined(THREAD_SANITIZER)
+// Fails on Chrome OS and under ThreadSanitizer on Linux, see
+// https://crbug.com/449103.
+#define MAYBE_TestMakeWebKeyboardEventWindowsKeyCode \
+ DISABLED_TestMakeWebKeyboardEventWindowsKeyCode
+#else
+#define MAYBE_TestMakeWebKeyboardEventWindowsKeyCode \
+ TestMakeWebKeyboardEventWindowsKeyCode
+#endif
+TEST(WebInputEventAuraTest, MAYBE_TestMakeWebKeyboardEventWindowsKeyCode) {
#if defined(USE_X11)
ui::ScopedXI2Event xev;
{
// Press left Ctrl.
xev.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL, 0);
XEvent* xevent = xev;
- xevent->xkey.keycode = XKeysymToKeycode(gfx::GetXDisplay(), XK_Control_L);
+ xevent->xkey.keycode =
+ ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::CONTROL_LEFT);
ui::KeyEvent event(xev);
- blink::WebKeyboardEvent webkit_event = MakeWebKeyboardEvent(&event);
+ 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);
}
@@ -59,9 +97,10 @@ TEST(WebInputEventAuraTest, TestMakeWebKeyboardEventWindowsKeyCode) {
// Press right Ctrl.
xev.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL, 0);
XEvent* xevent = xev;
- xevent->xkey.keycode = XKeysymToKeycode(gfx::GetXDisplay(), XK_Control_R);
+ xevent->xkey.keycode = ui::KeycodeConverter::DomCodeToNativeKeycode(
+ ui::DomCode::CONTROL_RIGHT);
ui::KeyEvent event(xev);
- blink::WebKeyboardEvent webkit_event = MakeWebKeyboardEvent(&event);
+ 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);
}
@@ -71,70 +110,116 @@ TEST(WebInputEventAuraTest, TestMakeWebKeyboardEventWindowsKeyCode) {
// to return VKEY_[LR]XXX instead of VKEY_XXX.
// https://bugs.webkit.org/show_bug.cgi?id=86694
#endif
+ {
+ // Press left Ctrl.
+ ui::KeyEvent event(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL,
+ ui::DomCode::CONTROL_LEFT, ui::EF_CONTROL_DOWN,
+ ui::DomKey::CONTROL, 0, ui::EventTimeForNow());
+ 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);
+ }
+ {
+ // Press right Ctrl.
+ ui::KeyEvent event(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL,
+ ui::DomCode::CONTROL_RIGHT, ui::EF_CONTROL_DOWN,
+ ui::DomKey::CONTROL, 0, ui::EventTimeForNow());
+ 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);
+ }
}
-// Checks that MakeWebKeyboardEvent fills a correct keypard modifier.
+// Checks that MakeWebKeyboardEvent fills a correct keypad modifier.
TEST(WebInputEventAuraTest, TestMakeWebKeyboardEventKeyPadKeyCode) {
#if defined(USE_X11)
+#define XK(x) XK_##x
+#else
+#define XK(x) 0
+#endif
struct TestCase {
+ ui::DomCode dom_code; // The physical key (location).
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.
+ uint32 x_keysym; // The X11 keysym.
+ 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::DomCode::DIGIT0, ui::VKEY_0, XK(0), false},
+ {ui::DomCode::DIGIT1, ui::VKEY_1, XK(1), false},
+ {ui::DomCode::DIGIT2, ui::VKEY_2, XK(2), false},
+ {ui::DomCode::DIGIT3, ui::VKEY_3, XK(3), false},
+ {ui::DomCode::DIGIT4, ui::VKEY_4, XK(4), false},
+ {ui::DomCode::DIGIT5, ui::VKEY_5, XK(5), false},
+ {ui::DomCode::DIGIT6, ui::VKEY_6, XK(6), false},
+ {ui::DomCode::DIGIT7, ui::VKEY_7, XK(7), false},
+ {ui::DomCode::DIGIT8, ui::VKEY_8, XK(8), false},
+ {ui::DomCode::DIGIT9, 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::DomCode::NUMPAD0, ui::VKEY_NUMPAD0, XK(KP_0), true},
+ {ui::DomCode::NUMPAD1, ui::VKEY_NUMPAD1, XK(KP_1), true},
+ {ui::DomCode::NUMPAD2, ui::VKEY_NUMPAD2, XK(KP_2), true},
+ {ui::DomCode::NUMPAD3, ui::VKEY_NUMPAD3, XK(KP_3), true},
+ {ui::DomCode::NUMPAD4, ui::VKEY_NUMPAD4, XK(KP_4), true},
+ {ui::DomCode::NUMPAD5, ui::VKEY_NUMPAD5, XK(KP_5), true},
+ {ui::DomCode::NUMPAD6, ui::VKEY_NUMPAD6, XK(KP_6), true},
+ {ui::DomCode::NUMPAD7, ui::VKEY_NUMPAD7, XK(KP_7), true},
+ {ui::DomCode::NUMPAD8, ui::VKEY_NUMPAD8, XK(KP_8), true},
+ {ui::DomCode::NUMPAD9, 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::DomCode::NUMPAD_MULTIPLY, ui::VKEY_MULTIPLY, XK(KP_Multiply), true},
+ {ui::DomCode::NUMPAD_SUBTRACT, ui::VKEY_SUBTRACT, XK(KP_Subtract), true},
+ {ui::DomCode::NUMPAD_ADD, ui::VKEY_ADD, XK(KP_Add), true},
+ {ui::DomCode::NUMPAD_DIVIDE, ui::VKEY_DIVIDE, XK(KP_Divide), true},
+ {ui::DomCode::NUMPAD_DECIMAL, ui::VKEY_DECIMAL, XK(KP_Decimal), true},
+ {ui::DomCode::NUMPAD_DECIMAL, ui::VKEY_DELETE, XK(KP_Delete), true},
+ {ui::DomCode::NUMPAD0, ui::VKEY_INSERT, XK(KP_Insert), true},
+ {ui::DomCode::NUMPAD1, ui::VKEY_END, XK(KP_End), true},
+ {ui::DomCode::NUMPAD2, ui::VKEY_DOWN, XK(KP_Down), true},
+ {ui::DomCode::NUMPAD3, ui::VKEY_NEXT, XK(KP_Page_Down), true},
+ {ui::DomCode::NUMPAD4, ui::VKEY_LEFT, XK(KP_Left), true},
+ {ui::DomCode::NUMPAD5, ui::VKEY_CLEAR, XK(KP_Begin), true},
+ {ui::DomCode::NUMPAD6, ui::VKEY_RIGHT, XK(KP_Right), true},
+ {ui::DomCode::NUMPAD7, ui::VKEY_HOME, XK(KP_Home), true},
+ {ui::DomCode::NUMPAD8, ui::VKEY_UP, XK(KP_Up), true},
+ {ui::DomCode::NUMPAD9, ui::VKEY_PRIOR, XK(KP_Page_Up), true},
};
+ for (const auto& test_case : kTesCases) {
+ ui::KeyEvent event(ui::ET_KEY_PRESSED, test_case.ui_keycode,
+ test_case.dom_code, ui::EF_NONE);
+ blink::WebKeyboardEvent webkit_event = MakeWebKeyboardEvent(event);
+ EXPECT_EQ(test_case.expected_result,
+ (webkit_event.modifiers & blink::WebInputEvent::IsKeyPad) != 0)
+ << "Failed in "
+ << "{dom_code:"
+ << ui::KeycodeConverter::DomCodeToCodeString(test_case.dom_code)
+ << ", ui_keycode:" << test_case.ui_keycode
+ << "}, expect: " << test_case.expected_result;
+ }
+#if defined(USE_X11)
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);
+ // TODO: re-enable the two cases excluded here once all trybots
+ // are sufficiently up to date to round-trip the associated keys.
+ if ((test_case.x_keysym == XK_KP_Divide) ||
+ (test_case.x_keysym == XK_KP_Decimal))
+ continue;
+
+ xev.InitKeyEvent(ui::ET_KEY_PRESSED, test_case.ui_keycode, ui::EF_NONE);
XEvent* xevent = xev;
- xevent->xkey.keycode = XKeysymToKeycode(gfx::GetXDisplay(),
- test_case.x_keycode);
+ xevent->xkey.keycode =
+ XKeysymToKeycode(gfx::GetXDisplay(), test_case.x_keysym);
+ if (!xevent->xkey.keycode)
+ continue;
ui::KeyEvent event(xev);
- blink::WebKeyboardEvent webkit_event = MakeWebKeyboardEvent(&event);
+ 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
+ << "{dom_code:"
+ << ui::KeycodeConverter::DomCodeToCodeString(test_case.dom_code)
+ << ", ui_keycode:" << test_case.ui_keycode
+ << ", x_keysym:" << test_case.x_keysym
<< "}, expect: " << test_case.expected_result;
}
#endif
diff --git a/chromium/content/browser/renderer_host/webmenurunner_mac.h b/chromium/content/browser/renderer_host/webmenurunner_mac.h
index 392ce9a0399..30424d7a6b8 100644
--- a/chromium/content/browser/renderer_host/webmenurunner_mac.h
+++ b/chromium/content/browser/renderer_host/webmenurunner_mac.h
@@ -61,4 +61,4 @@
@end // @interface WebMenuRunner
-#endif // CONTENT_BROWSER_RENDERER_HOST_WEBMENURUNNER_MAC_H_
+#endif // CONTENT_BROWSER_RENDERER_HOST_WEBMENURUNNER_MAC_H_
diff --git a/chromium/content/browser/renderer_host/websocket_dispatcher_host.cc b/chromium/content/browser/renderer_host/websocket_dispatcher_host.cc
index d49199a7cb8..ab4e68b76c1 100644
--- a/chromium/content/browser/renderer_host/websocket_dispatcher_host.cc
+++ b/chromium/content/browser/renderer_host/websocket_dispatcher_host.cc
@@ -9,6 +9,8 @@
#include "base/callback.h"
#include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/rand_util.h"
#include "base/stl_util.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/renderer_host/websocket_host.h"
@@ -23,6 +25,10 @@ namespace {
// fully-qualified every time.
typedef WebSocketDispatcherHost::WebSocketHostState WebSocketHostState;
+// Max number of pending connections per WebSocketDispatcherHost
+// used for per-renderer WebSocket throttling.
+const int kMaxPendingWebSocketConnections = 255;
+
} // namespace
WebSocketDispatcherHost::WebSocketDispatcherHost(
@@ -33,7 +39,12 @@ WebSocketDispatcherHost::WebSocketDispatcherHost(
get_context_callback_(get_context_callback),
websocket_host_factory_(
base::Bind(&WebSocketDispatcherHost::CreateWebSocketHost,
- base::Unretained(this))) {}
+ base::Unretained(this))),
+ num_pending_connections_(0),
+ num_current_succeeded_connections_(0),
+ num_previous_succeeded_connections_(0),
+ num_current_failed_connections_(0),
+ num_previous_failed_connections_(0) {}
WebSocketDispatcherHost::WebSocketDispatcherHost(
int process_id,
@@ -42,10 +53,18 @@ WebSocketDispatcherHost::WebSocketDispatcherHost(
: BrowserMessageFilter(WebSocketMsgStart),
process_id_(process_id),
get_context_callback_(get_context_callback),
- websocket_host_factory_(websocket_host_factory) {}
+ websocket_host_factory_(websocket_host_factory),
+ num_pending_connections_(0),
+ num_current_succeeded_connections_(0),
+ num_previous_succeeded_connections_(0),
+ num_current_failed_connections_(0),
+ num_previous_failed_connections_(0) {}
-WebSocketHost* WebSocketDispatcherHost::CreateWebSocketHost(int routing_id) {
- return new WebSocketHost(routing_id, this, get_context_callback_.Run());
+WebSocketHost* WebSocketDispatcherHost::CreateWebSocketHost(
+ int routing_id,
+ base::TimeDelta delay) {
+ return new WebSocketHost(
+ routing_id, this, get_context_callback_.Run(), delay);
}
bool WebSocketDispatcherHost::OnMessageReceived(const IPC::Message& message) {
@@ -73,8 +92,24 @@ bool WebSocketDispatcherHost::OnMessageReceived(const IPC::Message& message) {
// little extreme. So for now just ignore the bogus request.
return true; // We handled the message (by ignoring it).
}
- host = websocket_host_factory_.Run(routing_id);
+ if (num_pending_connections_ >= kMaxPendingWebSocketConnections) {
+ if(!Send(new WebSocketMsg_NotifyFailure(routing_id,
+ "Error in connection establishment: net::ERR_INSUFFICIENT_RESOURCES"
+ ))) {
+ DVLOG(1) << "Sending of message type "
+ << "WebSocketMsg_NotifyFailure failed.";
+ }
+ return true;
+ }
+ host = websocket_host_factory_.Run(routing_id, CalculateDelay());
hosts_.insert(WebSocketHostTable::value_type(routing_id, host));
+ ++num_pending_connections_;
+ if (!throttling_period_timer_.IsRunning())
+ throttling_period_timer_.Start(
+ FROM_HERE,
+ base::TimeDelta::FromMinutes(2),
+ this,
+ &WebSocketDispatcherHost::ThrottlingPeriodTimerCallback);
}
if (!host) {
DVLOG(1) << "Received invalid routing ID " << routing_id
@@ -110,18 +145,18 @@ WebSocketHostState WebSocketDispatcherHost::SendOrDrop(IPC::Message* message) {
WebSocketHostState WebSocketDispatcherHost::SendAddChannelResponse(
int routing_id,
- bool fail,
const std::string& selected_protocol,
const std::string& extensions) {
- if (SendOrDrop(new WebSocketMsg_AddChannelResponse(
- routing_id, fail, selected_protocol, extensions)) ==
- WEBSOCKET_HOST_DELETED)
- return WEBSOCKET_HOST_DELETED;
- if (fail) {
- DeleteWebSocketHost(routing_id);
- return WEBSOCKET_HOST_DELETED;
- }
- return WEBSOCKET_HOST_ALIVE;
+ // Update throttling counters (success).
+ WebSocketHost* host = GetHost(routing_id);
+ DCHECK(host);
+ host->OnHandshakeSucceeded();
+ --num_pending_connections_;
+ DCHECK_GE(num_pending_connections_, 0);
+ ++num_current_succeeded_connections_;
+
+ return SendOrDrop(new WebSocketMsg_AddChannelResponse(
+ routing_id, selected_protocol, extensions));
}
WebSocketHostState WebSocketDispatcherHost::SendFrame(
@@ -200,8 +235,55 @@ WebSocketDispatcherHost::~WebSocketDispatcherHost() {
void WebSocketDispatcherHost::DeleteWebSocketHost(int routing_id) {
WebSocketHostTable::iterator it = hosts_.find(routing_id);
DCHECK(it != hosts_.end());
+ DCHECK(it->second);
+ if (!it->second->handshake_succeeded()) {
+ // Update throttling counters (failure).
+ --num_pending_connections_;
+ DCHECK_GE(num_pending_connections_, 0);
+ ++num_current_failed_connections_;
+ }
+
delete it->second;
hosts_.erase(it);
+
+ DCHECK_LE(base::checked_cast<size_t>(num_pending_connections_),
+ hosts_.size());
+}
+
+int64_t WebSocketDispatcherHost::num_failed_connections() const {
+ return num_previous_failed_connections_ +
+ num_current_failed_connections_;
+}
+
+int64_t WebSocketDispatcherHost::num_succeeded_connections() const {
+ return num_previous_succeeded_connections_ +
+ num_current_succeeded_connections_;
+}
+
+// Calculate delay as described in
+// the per-renderer WebSocket throttling design doc:
+// https://docs.google.com/document/d/1aw2oN5PKfk-1gLnBrlv1OwLA8K3-ykM2ckwX2lubTg4/edit?usp=sharing
+base::TimeDelta WebSocketDispatcherHost::CalculateDelay() const {
+ int64_t f = num_failed_connections();
+ int64_t s = num_succeeded_connections();
+ int p = num_pending_connections();
+ return base::TimeDelta::FromMilliseconds(
+ base::RandInt(1000, 5000) *
+ (1 << std::min(p + f / (s + 1), INT64_C(16))) / 65536);
+}
+
+void WebSocketDispatcherHost::ThrottlingPeriodTimerCallback() {
+ num_previous_failed_connections_ = num_current_failed_connections_;
+ num_current_failed_connections_ = 0;
+
+ num_previous_succeeded_connections_ = num_current_succeeded_connections_;
+ num_current_succeeded_connections_ = 0;
+
+ if (num_pending_connections_ == 0 &&
+ num_previous_failed_connections_ == 0 &&
+ num_previous_succeeded_connections_ == 0) {
+ throttling_period_timer_.Stop();
+ }
}
} // namespace content
diff --git a/chromium/content/browser/renderer_host/websocket_dispatcher_host.h b/chromium/content/browser/renderer_host/websocket_dispatcher_host.h
index b9cdd343837..debbf584c73 100644
--- a/chromium/content/browser/renderer_host/websocket_dispatcher_host.h
+++ b/chromium/content/browser/renderer_host/websocket_dispatcher_host.h
@@ -5,13 +5,15 @@
#ifndef CONTENT_BROWSER_RENDERER_HOST_WEBSOCKET_DISPATCHER_HOST_H_
#define CONTENT_BROWSER_RENDERER_HOST_WEBSOCKET_DISPATCHER_HOST_H_
+#include <stdint.h>
#include <string>
#include <vector>
-#include "base/basictypes.h"
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/containers/hash_tables.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
#include "content/common/content_export.h"
#include "content/common/websocket.h"
#include "content/public/browser/browser_message_filter.h"
@@ -32,9 +34,10 @@ class CONTENT_EXPORT WebSocketDispatcherHost : public BrowserMessageFilter {
public:
typedef base::Callback<net::URLRequestContext*()> GetRequestContextCallback;
- // Given a routing_id, WebSocketHostFactory returns a new instance of
- // WebSocketHost or its subclass.
- typedef base::Callback<WebSocketHost*(int)> WebSocketHostFactory; // NOLINT
+ // Given a routing_id and delay, WebSocketHostFactory returns a new
+ // instance of WebSocketHost or its subclass.
+ typedef base::Callback<WebSocketHost*(int, base::TimeDelta)>
+ WebSocketHostFactory;
// Return value for methods that may delete the WebSocketHost. This enum is
// binary-compatible with net::WebSocketEventInterface::ChannelState, to make
@@ -49,12 +52,6 @@ class CONTENT_EXPORT WebSocketDispatcherHost : public BrowserMessageFilter {
int process_id,
const GetRequestContextCallback& get_context_callback);
- // For testing. Specify a factory method that creates mock version of
- // WebSocketHost.
- WebSocketDispatcherHost(int process_id,
- const GetRequestContextCallback& get_context_callback,
- const WebSocketHostFactory& websocket_host_factory);
-
// BrowserMessageFilter:
bool OnMessageReceived(const IPC::Message& message) override;
@@ -63,11 +60,9 @@ class CONTENT_EXPORT WebSocketDispatcherHost : public BrowserMessageFilter {
// return WEBSOCKET_HOST_DELETED and delete the WebSocketHost on failure,
// leading to the WebSocketChannel and EventInterface also being deleted.
- // Sends a WebSocketMsg_AddChannelResponse IPC, and then deletes and
- // unregisters the WebSocketHost if |fail| is true.
+ // Sends a WebSocketMsg_AddChannelResponse IPC.
WebSocketHostState SendAddChannelResponse(
int routing_id,
- bool fail,
const std::string& selected_protocol,
const std::string& extensions) WARN_UNUSED_RESULT;
@@ -113,12 +108,26 @@ class CONTENT_EXPORT WebSocketDispatcherHost : public BrowserMessageFilter {
int render_process_id() const { return process_id_; }
- private:
- typedef base::hash_map<int, WebSocketHost*> WebSocketHostTable;
+ protected:
+ // For testing. Specify a factory method that creates mock version of
+ // WebSocketHost.
+ WebSocketDispatcherHost(int process_id,
+ const GetRequestContextCallback& get_context_callback,
+ const WebSocketHostFactory& websocket_host_factory);
+
+ int num_pending_connections() const { return num_pending_connections_; }
+
+ // The number of handshakes that failed/succeeded in the current and
+ // previous time period, respectively.
+ int64_t num_failed_connections() const;
+ int64_t num_succeeded_connections() const;
~WebSocketDispatcherHost() override;
- WebSocketHost* CreateWebSocketHost(int routing_id);
+ private:
+ typedef base::hash_map<int, WebSocketHost*> WebSocketHostTable;
+
+ WebSocketHost* CreateWebSocketHost(int routing_id, base::TimeDelta delay);
// Looks up a WebSocketHost object by |routing_id|. Returns the object if one
// is found, or NULL otherwise.
@@ -134,6 +143,14 @@ class CONTENT_EXPORT WebSocketDispatcherHost : public BrowserMessageFilter {
// removes it from the |hosts_| table.
void DeleteWebSocketHost(int routing_id);
+ // Calculates the delay for per-renderer WebSocket throttling.
+ base::TimeDelta CalculateDelay() const;
+
+ // Rotates the counts of successful and failed connections for current
+ // and previous time periods. Called every two minutes while the counts
+ // are non-zero.
+ void ThrottlingPeriodTimerCallback();
+
// Table of WebSocketHost objects, owned by this object, indexed by
// routing_id.
WebSocketHostTable hosts_;
@@ -147,6 +164,22 @@ class CONTENT_EXPORT WebSocketDispatcherHost : public BrowserMessageFilter {
WebSocketHostFactory websocket_host_factory_;
+ // Timer and counters for per-renderer WebSocket throttling.
+ base::RepeatingTimer<WebSocketDispatcherHost> throttling_period_timer_;
+
+ // The current number of pending connections.
+ int num_pending_connections_;
+
+ // The number of handshakes that failed in the current and previous time
+ // period.
+ int64_t num_current_succeeded_connections_;
+ int64_t num_previous_succeeded_connections_;
+
+ // The number of handshakes that succeeded in the current and previous time
+ // period.
+ int64_t num_current_failed_connections_;
+ int64_t num_previous_failed_connections_;
+
DISALLOW_COPY_AND_ASSIGN(WebSocketDispatcherHost);
};
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 0d2e7057bbc..4eb1104bfb7 100644
--- a/chromium/content/browser/renderer_host/websocket_dispatcher_host_unittest.cc
+++ b/chromium/content/browser/renderer_host/websocket_dispatcher_host_unittest.cc
@@ -11,10 +11,12 @@
#include "base/bind_helpers.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop.h"
#include "content/browser/renderer_host/websocket_host.h"
#include "content/common/websocket.h"
#include "content/common/websocket_messages.h"
#include "ipc/ipc_message.h"
+#include "net/websockets/websocket_errors.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
#include "url/origin.h"
@@ -33,26 +35,64 @@ class MockWebSocketHost : public WebSocketHost {
MockWebSocketHost(int routing_id,
WebSocketDispatcherHost* dispatcher,
net::URLRequestContext* url_request_context,
+ base::TimeDelta delay,
WebSocketDispatcherHostTest* owner);
~MockWebSocketHost() override {}
bool OnMessageReceived(const IPC::Message& message) override {
received_messages_.push_back(message);
- return true;
+ switch (message.type()) {
+ case WebSocketMsg_DropChannel::ID:
+ // Needed for PerRendererThrottlingFailedHandshakes, because without
+ // calling WebSocketHost::OnMessageReceived() (and thus
+ // WebSocketHost::OnDropChannel()), the connection stays pending and
+ // we cannot test per-renderer throttling with failed connections.
+ return WebSocketHost::OnMessageReceived(message);
+
+ default:
+ return true;
+ }
}
void GoAway() override;
std::vector<IPC::Message> received_messages_;
base::WeakPtr<WebSocketDispatcherHostTest> owner_;
+ base::TimeDelta delay_;
+};
+
+class TestingWebSocketDispatcherHost : public WebSocketDispatcherHost {
+ public:
+ TestingWebSocketDispatcherHost(
+ int process_id,
+ const GetRequestContextCallback& get_context_callback,
+ const WebSocketHostFactory& websocket_host_factory)
+ : WebSocketDispatcherHost(process_id,
+ get_context_callback,
+ websocket_host_factory) {}
+
+ // This is needed because BrowserMessageFilter::Send() tries post the task to
+ // the IO thread, which doesn't exist in the context of these tests.
+ bool Send(IPC::Message* message) override {
+ delete message;
+ return true;
+ }
+
+ using WebSocketDispatcherHost::num_pending_connections;
+ using WebSocketDispatcherHost::num_failed_connections;
+ using WebSocketDispatcherHost::num_succeeded_connections;
+
+ private:
+ ~TestingWebSocketDispatcherHost() override {}
};
class WebSocketDispatcherHostTest : public ::testing::Test {
public:
WebSocketDispatcherHostTest()
- : weak_ptr_factory_(this) {
- dispatcher_host_ = new WebSocketDispatcherHost(
+ : next_routing_id_(123),
+ weak_ptr_factory_(this) {
+ dispatcher_host_ = new TestingWebSocketDispatcherHost(
kMagicRenderProcessId,
base::Bind(&WebSocketDispatcherHostTest::OnGetRequestContext,
base::Unretained(this)),
@@ -75,35 +115,90 @@ class WebSocketDispatcherHostTest : public ::testing::Test {
}
protected:
- scoped_refptr<WebSocketDispatcherHost> dispatcher_host_;
+ // Adds |n| connections. Returns true if succeeded.
+ bool AddMultipleChannels(int number_of_channels) {
+ GURL socket_url("ws://example.com/test");
+ std::vector<std::string> requested_protocols;
+ url::Origin origin("http://example.com");
+ int render_frame_id = -3;
+
+ for (int i = 0; i < number_of_channels; ++i) {
+ int routing_id = next_routing_id_++;
+ WebSocketHostMsg_AddChannelRequest message(
+ routing_id,
+ socket_url,
+ requested_protocols,
+ origin,
+ render_frame_id);
+ if (!dispatcher_host_->OnMessageReceived(message))
+ return false;
+ }
+
+ return true;
+ }
+
+ // Adds and cancels |n| connections. Returns true if succeeded.
+ bool AddAndCancelMultipleChannels(int number_of_channels) {
+ GURL socket_url("ws://example.com/test");
+ std::vector<std::string> requested_protocols;
+ url::Origin origin("http://example.com");
+ int render_frame_id = -3;
+
+ for (int i = 0; i < number_of_channels; ++i) {
+ int routing_id = next_routing_id_++;
+ WebSocketHostMsg_AddChannelRequest messageAddChannelRequest(
+ routing_id,
+ socket_url,
+ requested_protocols,
+ origin,
+ render_frame_id);
+ if (!dispatcher_host_->OnMessageReceived(messageAddChannelRequest))
+ return false;
+
+ WebSocketMsg_DropChannel messageDropChannel(
+ routing_id, false, net::kWebSocketErrorAbnormalClosure, "");
+ if (!dispatcher_host_->OnMessageReceived(messageDropChannel))
+ return false;
+ }
+
+ return true;
+ }
+
+ scoped_refptr<TestingWebSocketDispatcherHost> dispatcher_host_;
// 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() {
return NULL;
}
- WebSocketHost* CreateWebSocketHost(int routing_id) {
- MockWebSocketHost* host =
- new MockWebSocketHost(routing_id, dispatcher_host_.get(), NULL, this);
+ WebSocketHost* CreateWebSocketHost(int routing_id, base::TimeDelta delay) {
+ MockWebSocketHost* host = new MockWebSocketHost(
+ routing_id, dispatcher_host_.get(), NULL, delay, this);
mock_hosts_.push_back(host);
return host;
}
+
+ base::MessageLoop message_loop_;
+
+ int next_routing_id_;
+
+ base::WeakPtrFactory<WebSocketDispatcherHostTest> weak_ptr_factory_;
};
MockWebSocketHost::MockWebSocketHost(
int routing_id,
WebSocketDispatcherHost* dispatcher,
net::URLRequestContext* url_request_context,
+ base::TimeDelta delay,
WebSocketDispatcherHostTest* owner)
- : WebSocketHost(routing_id, dispatcher, url_request_context),
- owner_(owner->GetWeakPtr()) {}
+ : WebSocketHost(routing_id, dispatcher, url_request_context, delay),
+ owner_(owner->GetWeakPtr()),
+ delay_(delay) {}
void MockWebSocketHost::GoAway() {
if (owner_)
@@ -128,7 +223,7 @@ TEST_F(WebSocketDispatcherHostTest, AddChannelRequest) {
GURL socket_url("ws://example.com/test");
std::vector<std::string> requested_protocols;
requested_protocols.push_back("hello");
- url::Origin origin("http://example.com/test");
+ url::Origin origin("http://example.com");
int render_frame_id = -2;
WebSocketHostMsg_AddChannelRequest message(
routing_id, socket_url, requested_protocols, origin, render_frame_id);
@@ -162,7 +257,7 @@ TEST_F(WebSocketDispatcherHostTest, SendFrame) {
GURL socket_url("ws://example.com/test");
std::vector<std::string> requested_protocols;
requested_protocols.push_back("hello");
- url::Origin origin("http://example.com/test");
+ url::Origin origin("http://example.com");
int render_frame_id = -2;
WebSocketHostMsg_AddChannelRequest add_channel_message(
routing_id, socket_url, requested_protocols, origin, render_frame_id);
@@ -215,5 +310,133 @@ TEST_F(WebSocketDispatcherHostTest, Destruct) {
EXPECT_EQ(456, gone_hosts_[1]);
}
+TEST_F(WebSocketDispatcherHostTest, DelayFor4thPendingConnectionIsZero) {
+ ASSERT_TRUE(AddMultipleChannels(4));
+
+ EXPECT_EQ(4, dispatcher_host_->num_pending_connections());
+ EXPECT_EQ(0, dispatcher_host_->num_failed_connections());
+ EXPECT_EQ(0, dispatcher_host_->num_succeeded_connections());
+
+ ASSERT_EQ(4U, mock_hosts_.size());
+ EXPECT_EQ(base::TimeDelta(), mock_hosts_[3]->delay_);
+}
+
+TEST_F(WebSocketDispatcherHostTest, DelayFor8thPendingConnectionIsNonZero) {
+ ASSERT_TRUE(AddMultipleChannels(8));
+
+ EXPECT_EQ(8, dispatcher_host_->num_pending_connections());
+ EXPECT_EQ(0, dispatcher_host_->num_failed_connections());
+ EXPECT_EQ(0, dispatcher_host_->num_succeeded_connections());
+
+ ASSERT_EQ(8U, mock_hosts_.size());
+ EXPECT_LT(base::TimeDelta(), mock_hosts_[7]->delay_);
+}
+
+TEST_F(WebSocketDispatcherHostTest, DelayFor17thPendingConnection) {
+ ASSERT_TRUE(AddMultipleChannels(17));
+
+ EXPECT_EQ(17, dispatcher_host_->num_pending_connections());
+ EXPECT_EQ(0, dispatcher_host_->num_failed_connections());
+ EXPECT_EQ(0, dispatcher_host_->num_succeeded_connections());
+
+ ASSERT_EQ(17U, mock_hosts_.size());
+ EXPECT_LE(base::TimeDelta::FromMilliseconds(1000), mock_hosts_[16]->delay_);
+ EXPECT_GE(base::TimeDelta::FromMilliseconds(5000), mock_hosts_[16]->delay_);
+}
+
+// The 256th connection is rejected by per-renderer WebSocket throttling.
+// This is not counted as a failure.
+TEST_F(WebSocketDispatcherHostTest, Rejects256thPendingConnection) {
+ ASSERT_TRUE(AddMultipleChannels(256));
+
+ EXPECT_EQ(255, dispatcher_host_->num_pending_connections());
+ EXPECT_EQ(0, dispatcher_host_->num_failed_connections());
+ EXPECT_EQ(0, dispatcher_host_->num_succeeded_connections());
+
+ ASSERT_EQ(255U, mock_hosts_.size());
+}
+
+TEST_F(WebSocketDispatcherHostTest, DelayIsZeroAfter3FailedConnections) {
+ ASSERT_TRUE(AddAndCancelMultipleChannels(3));
+
+ EXPECT_EQ(0, dispatcher_host_->num_pending_connections());
+ EXPECT_EQ(3, dispatcher_host_->num_failed_connections());
+ EXPECT_EQ(0, dispatcher_host_->num_succeeded_connections());
+
+ ASSERT_TRUE(AddMultipleChannels(1));
+
+ ASSERT_EQ(4U, mock_hosts_.size());
+ EXPECT_EQ(base::TimeDelta(), mock_hosts_[3]->delay_);
+}
+
+TEST_F(WebSocketDispatcherHostTest, DelayIsNonZeroAfter7FailedConnections) {
+ ASSERT_TRUE(AddAndCancelMultipleChannels(7));
+
+ EXPECT_EQ(0, dispatcher_host_->num_pending_connections());
+ EXPECT_EQ(7, dispatcher_host_->num_failed_connections());
+ EXPECT_EQ(0, dispatcher_host_->num_succeeded_connections());
+
+ ASSERT_TRUE(AddMultipleChannels(1));
+
+ ASSERT_EQ(8U, mock_hosts_.size());
+ EXPECT_LT(base::TimeDelta(), mock_hosts_[7]->delay_);
+}
+
+TEST_F(WebSocketDispatcherHostTest, DelayAfter16FailedConnections) {
+ ASSERT_TRUE(AddAndCancelMultipleChannels(16));
+
+ EXPECT_EQ(0, dispatcher_host_->num_pending_connections());
+ EXPECT_EQ(16, dispatcher_host_->num_failed_connections());
+ EXPECT_EQ(0, dispatcher_host_->num_succeeded_connections());
+
+ ASSERT_TRUE(AddMultipleChannels(1));
+
+ ASSERT_EQ(17U, mock_hosts_.size());
+ EXPECT_LE(base::TimeDelta::FromMilliseconds(1000), mock_hosts_[16]->delay_);
+ EXPECT_GE(base::TimeDelta::FromMilliseconds(5000), mock_hosts_[16]->delay_);
+}
+
+TEST_F(WebSocketDispatcherHostTest, NotRejectedAfter255FailedConnections) {
+ ASSERT_TRUE(AddAndCancelMultipleChannels(255));
+
+ EXPECT_EQ(0, dispatcher_host_->num_pending_connections());
+ EXPECT_EQ(255, dispatcher_host_->num_failed_connections());
+ EXPECT_EQ(0, dispatcher_host_->num_succeeded_connections());
+
+ ASSERT_TRUE(AddMultipleChannels(1));
+
+ EXPECT_EQ(1, dispatcher_host_->num_pending_connections());
+ EXPECT_EQ(255, dispatcher_host_->num_failed_connections());
+ EXPECT_EQ(0, dispatcher_host_->num_succeeded_connections());
+}
+
+// This is a regression test for https://crrev.com/998173003/.
+TEST_F(WebSocketDispatcherHostTest, InvalidScheme) {
+ int routing_id = 123;
+ GURL socket_url("http://example.com/test");
+ std::vector<std::string> requested_protocols;
+ requested_protocols.push_back("hello");
+ url::Origin origin("http://example.com");
+ int render_frame_id = -2;
+ WebSocketHostMsg_AddChannelRequest message(
+ routing_id, socket_url, requested_protocols, origin, render_frame_id);
+
+ ASSERT_TRUE(dispatcher_host_->OnMessageReceived(message));
+
+ ASSERT_EQ(1U, mock_hosts_.size());
+ MockWebSocketHost* host = mock_hosts_[0];
+
+ // Tests that WebSocketHost::OnMessageReceived() doesn't cause a crash and
+ // the connection with an invalid scheme fails here.
+ // We call WebSocketHost::OnMessageReceived() here explicitly because
+ // MockWebSocketHost does not call WebSocketHost::OnMessageReceived() for
+ // WebSocketHostMsg_AddChannelRequest.
+ host->WebSocketHost::OnMessageReceived(message);
+
+ EXPECT_EQ(0, dispatcher_host_->num_pending_connections());
+ EXPECT_EQ(1, dispatcher_host_->num_failed_connections());
+ EXPECT_EQ(0, dispatcher_host_->num_succeeded_connections());
+}
+
} // namespace
} // namespace content
diff --git a/chromium/content/browser/renderer_host/websocket_host.cc b/chromium/content/browser/renderer_host/websocket_host.cc
index 9b557fedab3..cd8dd25a997 100644
--- a/chromium/content/browser/renderer_host/websocket_host.cc
+++ b/chromium/content/browser/renderer_host/websocket_host.cc
@@ -40,15 +40,15 @@ net::WebSocketFrameHeader::OpCode MessageTypeToOpCode(
typedef net::WebSocketFrameHeader::OpCode OpCode;
// These compile asserts verify that the same underlying values are used for
// both types, so we can simply cast between them.
- COMPILE_ASSERT(static_cast<OpCode>(WEB_SOCKET_MESSAGE_TYPE_CONTINUATION) ==
- net::WebSocketFrameHeader::kOpCodeContinuation,
- enum_values_must_match_for_opcode_continuation);
- COMPILE_ASSERT(static_cast<OpCode>(WEB_SOCKET_MESSAGE_TYPE_TEXT) ==
- net::WebSocketFrameHeader::kOpCodeText,
- enum_values_must_match_for_opcode_text);
- COMPILE_ASSERT(static_cast<OpCode>(WEB_SOCKET_MESSAGE_TYPE_BINARY) ==
- net::WebSocketFrameHeader::kOpCodeBinary,
- enum_values_must_match_for_opcode_binary);
+ static_assert(static_cast<OpCode>(WEB_SOCKET_MESSAGE_TYPE_CONTINUATION) ==
+ net::WebSocketFrameHeader::kOpCodeContinuation,
+ "enum values must match for opcode continuation");
+ static_assert(static_cast<OpCode>(WEB_SOCKET_MESSAGE_TYPE_TEXT) ==
+ net::WebSocketFrameHeader::kOpCodeText,
+ "enum values must match for opcode text");
+ static_assert(static_cast<OpCode>(WEB_SOCKET_MESSAGE_TYPE_BINARY) ==
+ net::WebSocketFrameHeader::kOpCodeBinary,
+ "enum values must match for opcode binary");
return static_cast<OpCode>(type);
}
@@ -57,7 +57,7 @@ WebSocketMessageType OpCodeToMessageType(
DCHECK(opCode == net::WebSocketFrameHeader::kOpCodeContinuation ||
opCode == net::WebSocketFrameHeader::kOpCodeText ||
opCode == net::WebSocketFrameHeader::kOpCodeBinary);
- // This cast is guaranteed valid by the COMPILE_ASSERT() statements above.
+ // This cast is guaranteed valid by the static_assert() statements above.
return static_cast<WebSocketMessageType>(opCode);
}
@@ -71,12 +71,12 @@ ChannelState StateCast(WebSocketDispatcherHost::WebSocketHostState host_state) {
host_state == WEBSOCKET_HOST_DELETED);
// These compile asserts verify that we can get away with using static_cast<>
// for the conversion.
- COMPILE_ASSERT(static_cast<ChannelState>(WEBSOCKET_HOST_ALIVE) ==
- net::WebSocketEventInterface::CHANNEL_ALIVE,
- enum_values_must_match_for_state_alive);
- COMPILE_ASSERT(static_cast<ChannelState>(WEBSOCKET_HOST_DELETED) ==
- net::WebSocketEventInterface::CHANNEL_DELETED,
- enum_values_must_match_for_state_deleted);
+ static_assert(static_cast<ChannelState>(WEBSOCKET_HOST_ALIVE) ==
+ net::WebSocketEventInterface::CHANNEL_ALIVE,
+ "enum values must match for state_alive");
+ static_assert(static_cast<ChannelState>(WEBSOCKET_HOST_DELETED) ==
+ net::WebSocketEventInterface::CHANNEL_DELETED,
+ "enum values must match for state_deleted");
return static_cast<ChannelState>(host_state);
}
@@ -92,8 +92,7 @@ class WebSocketEventHandler : public net::WebSocketEventInterface {
// net::WebSocketEventInterface implementation
- ChannelState OnAddChannelResponse(bool fail,
- const std::string& selected_subprotocol,
+ ChannelState OnAddChannelResponse(const std::string& selected_subprotocol,
const std::string& extensions) override;
ChannelState OnDataFrame(bool fin,
WebSocketMessageType type,
@@ -156,16 +155,15 @@ WebSocketEventHandler::~WebSocketEventHandler() {
}
ChannelState WebSocketEventHandler::OnAddChannelResponse(
- bool fail,
const std::string& selected_protocol,
const std::string& extensions) {
DVLOG(3) << "WebSocketEventHandler::OnAddChannelResponse"
- << " routing_id=" << routing_id_ << " fail=" << fail
+ << " routing_id=" << routing_id_
<< " selected_protocol=\"" << selected_protocol << "\""
<< " extensions=\"" << extensions << "\"";
return StateCast(dispatcher_->SendAddChannelResponse(
- routing_id_, fail, selected_protocol, extensions));
+ routing_id_, selected_protocol, extensions));
}
ChannelState WebSocketEventHandler::OnDataFrame(
@@ -314,10 +312,15 @@ void WebSocketEventHandler::SSLErrorHandlerDelegate::ContinueSSLRequest() {
WebSocketHost::WebSocketHost(int routing_id,
WebSocketDispatcherHost* dispatcher,
- net::URLRequestContext* url_request_context)
+ net::URLRequestContext* url_request_context,
+ base::TimeDelta delay)
: dispatcher_(dispatcher),
url_request_context_(url_request_context),
- routing_id_(routing_id) {
+ routing_id_(routing_id),
+ delay_(delay),
+ pending_flow_control_quota_(0),
+ handshake_succeeded_(false),
+ weak_ptr_factory_(this) {
DVLOG(1) << "WebSocketHost: created routing_id=" << routing_id;
}
@@ -351,11 +354,56 @@ void WebSocketHost::OnAddChannelRequest(
<< origin.string() << "\"";
DCHECK(!channel_);
+ if (delay_ > base::TimeDelta()) {
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&WebSocketHost::AddChannel,
+ weak_ptr_factory_.GetWeakPtr(),
+ socket_url,
+ requested_protocols,
+ origin,
+ render_frame_id),
+ delay_);
+ } else {
+ AddChannel(socket_url, requested_protocols, origin, render_frame_id);
+ }
+ // |this| may have been deleted here.
+}
+
+void WebSocketHost::AddChannel(
+ const GURL& socket_url,
+ const std::vector<std::string>& requested_protocols,
+ const url::Origin& origin,
+ int render_frame_id) {
+ DVLOG(3) << "WebSocketHost::AddChannel"
+ << " routing_id=" << routing_id_ << " socket_url=\"" << socket_url
+ << "\" requested_protocols=\""
+ << JoinString(requested_protocols, ", ") << "\" origin=\""
+ << origin.string() << "\"";
+
+ DCHECK(!channel_);
+
scoped_ptr<net::WebSocketEventInterface> event_interface(
new WebSocketEventHandler(dispatcher_, routing_id_, render_frame_id));
channel_.reset(
new net::WebSocketChannel(event_interface.Pass(), url_request_context_));
+
+ if (pending_flow_control_quota_ > 0) {
+ // channel_->SendFlowControl(pending_flow_control_quota_) must be called
+ // after channel_->SendAddChannelRequest() below.
+ // We post OnFlowControl() here using |weak_ptr_factory_| instead of
+ // calling SendFlowControl directly, because |this| may have been deleted
+ // after channel_->SendAddChannelRequest().
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&WebSocketHost::OnFlowControl,
+ weak_ptr_factory_.GetWeakPtr(),
+ pending_flow_control_quota_));
+ pending_flow_control_quota_ = 0;
+ }
+
channel_->SendAddChannelRequest(socket_url, requested_protocols, origin);
+ // |this| may have been deleted here.
}
void WebSocketHost::OnSendFrame(bool fin,
@@ -373,7 +421,14 @@ void WebSocketHost::OnFlowControl(int64 quota) {
DVLOG(3) << "WebSocketHost::OnFlowControl"
<< " routing_id=" << routing_id_ << " quota=" << quota;
- DCHECK(channel_);
+ if (!channel_) {
+ // WebSocketChannel is not yet created due to the delay introduced by
+ // per-renderer WebSocket throttling.
+ // SendFlowControl() is called after WebSocketChannel is created.
+ pending_flow_control_quota_ += quota;
+ return;
+ }
+
channel_->SendFlowControl(quota);
}
@@ -384,7 +439,18 @@ void WebSocketHost::OnDropChannel(bool was_clean,
<< " routing_id=" << routing_id_ << " was_clean=" << was_clean
<< " code=" << code << " reason=\"" << reason << "\"";
- DCHECK(channel_);
+ if (!channel_) {
+ // WebSocketChannel is not yet created due to the delay introduced by
+ // per-renderer WebSocket throttling.
+ WebSocketDispatcherHost::WebSocketHostState result =
+ dispatcher_->DoDropChannel(routing_id_,
+ false,
+ net::kWebSocketErrorAbnormalClosure,
+ "");
+ DCHECK_EQ(WebSocketDispatcherHost::WEBSOCKET_HOST_DELETED, result);
+ return;
+ }
+
// TODO(yhirano): Handle |was_clean| appropriately.
channel_->StartClosingHandshake(code, reason);
}
diff --git a/chromium/content/browser/renderer_host/websocket_host.h b/chromium/content/browser/renderer_host/websocket_host.h
index 39c1e41edbe..89b368685d6 100644
--- a/chromium/content/browser/renderer_host/websocket_host.h
+++ b/chromium/content/browser/renderer_host/websocket_host.h
@@ -9,6 +9,8 @@
#include <vector>
#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
#include "content/common/content_export.h"
#include "content/common/websocket.h"
@@ -37,7 +39,8 @@ class CONTENT_EXPORT WebSocketHost {
public:
WebSocketHost(int routing_id,
WebSocketDispatcherHost* dispatcher,
- net::URLRequestContext* url_request_context);
+ net::URLRequestContext* url_request_context,
+ base::TimeDelta delay);
virtual ~WebSocketHost();
// The renderer process is going away.
@@ -50,6 +53,9 @@ class CONTENT_EXPORT WebSocketHost {
int routing_id() const { return routing_id_; }
+ bool handshake_succeeded() const { return handshake_succeeded_; }
+ void OnHandshakeSucceeded() { handshake_succeeded_ = true; }
+
private:
// Handlers for each message type, dispatched by OnMessageReceived(), as
// defined in content/common/websocket_messages.h
@@ -59,6 +65,11 @@ class CONTENT_EXPORT WebSocketHost {
const url::Origin& origin,
int render_frame_id);
+ void AddChannel(const GURL& socket_url,
+ const std::vector<std::string>& requested_protocols,
+ const url::Origin& origin,
+ int render_frame_id);
+
void OnSendFrame(bool fin,
WebSocketMessageType type,
const std::vector<char>& data);
@@ -79,6 +90,20 @@ class CONTENT_EXPORT WebSocketHost {
// The ID used to route messages.
const int routing_id_;
+ // Delay used for per-renderer WebSocket throttling.
+ base::TimeDelta delay_;
+
+ // SendFlowControl() is delayed when OnFlowControl() is called before
+ // AddChannel() is called.
+ // Zero indicates there is no pending SendFlowControl().
+ int64_t pending_flow_control_quota_;
+
+ // handshake_succeeded_ is set and used by WebSocketDispatcherHost
+ // to manage counters for per-renderer WebSocket throttling.
+ bool handshake_succeeded_;
+
+ base::WeakPtrFactory<WebSocketHost> weak_ptr_factory_;
+
DISALLOW_COPY_AND_ASSIGN(WebSocketHost);
};
diff --git a/chromium/content/browser/resolve_proxy_msg_helper_unittest.cc b/chromium/content/browser/resolve_proxy_msg_helper_unittest.cc
index 1a19018e711..c03545c47e7 100644
--- a/chromium/content/browser/resolve_proxy_msg_helper_unittest.cc
+++ b/chromium/content/browser/resolve_proxy_msg_helper_unittest.cc
@@ -58,9 +58,10 @@ class ResolveProxyMsgHelperTest : public testing::Test, public IPC::Listener {
};
ResolveProxyMsgHelperTest()
- : resolver_(new net::MockAsyncProxyResolver),
- service_(
- new net::ProxyService(new MockProxyConfigService, resolver_, NULL)),
+ : resolver_factory_(new net::MockAsyncProxyResolverFactory(false)),
+ service_(new net::ProxyService(new MockProxyConfigService,
+ make_scoped_ptr(resolver_factory_),
+ NULL)),
helper_(new TestResolveProxyMsgHelper(service_.get(), this)),
io_thread_(BrowserThread::IO, &message_loop_) {
test_sink_.AddFilter(this);
@@ -80,7 +81,8 @@ class ResolveProxyMsgHelperTest : public testing::Test, public IPC::Listener {
return IPC::SyncMessage::GenerateReply(&message);
}
- net::MockAsyncProxyResolver* resolver_;
+ net::MockAsyncProxyResolverFactory* resolver_factory_;
+ net::MockAsyncProxyResolver resolver_;
scoped_ptr<net::ProxyService> service_;
scoped_refptr<ResolveProxyMsgHelper> helper_;
scoped_ptr<PendingResult> pending_result_;
@@ -90,7 +92,8 @@ class ResolveProxyMsgHelperTest : public testing::Test, public IPC::Listener {
TupleTypes<ViewHostMsg_ResolveProxy::ReplyParam>::ValueTuple reply_data;
EXPECT_TRUE(ViewHostMsg_ResolveProxy::ReadReplyParam(&msg, &reply_data));
DCHECK(!pending_result_.get());
- pending_result_.reset(new PendingResult(reply_data.a, reply_data.b));
+ pending_result_.reset(
+ new PendingResult(get<0>(reply_data), get<1>(reply_data)));
test_sink_.ClearMessages();
return true;
}
@@ -117,12 +120,14 @@ TEST_F(ResolveProxyMsgHelperTest, Sequential) {
helper_->OnResolveProxy(url1, msg1);
// Finish ProxyService's initialization.
- resolver_->pending_set_pac_script_request()->CompleteNow(net::OK);
+ ASSERT_EQ(1u, resolver_factory_->pending_requests().size());
+ resolver_factory_->pending_requests()[0]->CompleteNowWithForwarder(
+ net::OK, &resolver_);
- ASSERT_EQ(1u, resolver_->pending_requests().size());
- EXPECT_EQ(url1, resolver_->pending_requests()[0]->url());
- resolver_->pending_requests()[0]->results()->UseNamedProxy("result1:80");
- resolver_->pending_requests()[0]->CompleteNow(net::OK);
+ ASSERT_EQ(1u, resolver_.pending_requests().size());
+ EXPECT_EQ(url1, resolver_.pending_requests()[0]->url());
+ resolver_.pending_requests()[0]->results()->UseNamedProxy("result1:80");
+ resolver_.pending_requests()[0]->CompleteNow(net::OK);
// Check result.
EXPECT_EQ(true, pending_result()->result);
@@ -131,10 +136,10 @@ TEST_F(ResolveProxyMsgHelperTest, Sequential) {
helper_->OnResolveProxy(url2, msg2);
- ASSERT_EQ(1u, resolver_->pending_requests().size());
- EXPECT_EQ(url2, resolver_->pending_requests()[0]->url());
- resolver_->pending_requests()[0]->results()->UseNamedProxy("result2:80");
- resolver_->pending_requests()[0]->CompleteNow(net::OK);
+ ASSERT_EQ(1u, resolver_.pending_requests().size());
+ EXPECT_EQ(url2, resolver_.pending_requests()[0]->url());
+ resolver_.pending_requests()[0]->results()->UseNamedProxy("result2:80");
+ resolver_.pending_requests()[0]->CompleteNow(net::OK);
// Check result.
EXPECT_EQ(true, pending_result()->result);
@@ -143,10 +148,10 @@ TEST_F(ResolveProxyMsgHelperTest, Sequential) {
helper_->OnResolveProxy(url3, msg3);
- ASSERT_EQ(1u, resolver_->pending_requests().size());
- EXPECT_EQ(url3, resolver_->pending_requests()[0]->url());
- resolver_->pending_requests()[0]->results()->UseNamedProxy("result3:80");
- resolver_->pending_requests()[0]->CompleteNow(net::OK);
+ ASSERT_EQ(1u, resolver_.pending_requests().size());
+ EXPECT_EQ(url3, resolver_.pending_requests()[0]->url());
+ resolver_.pending_requests()[0]->results()->UseNamedProxy("result3:80");
+ resolver_.pending_requests()[0]->CompleteNow(net::OK);
// Check result.
EXPECT_EQ(true, pending_result()->result);
@@ -170,40 +175,42 @@ TEST_F(ResolveProxyMsgHelperTest, QueueRequests) {
helper_->OnResolveProxy(url1, msg1);
// Finish ProxyService's initialization.
- resolver_->pending_set_pac_script_request()->CompleteNow(net::OK);
+ ASSERT_EQ(1u, resolver_factory_->pending_requests().size());
+ resolver_factory_->pending_requests()[0]->CompleteNowWithForwarder(
+ net::OK, &resolver_);
helper_->OnResolveProxy(url2, msg2);
helper_->OnResolveProxy(url3, msg3);
// ResolveProxyHelper only keeps 1 request outstanding in ProxyService
// at a time.
- ASSERT_EQ(1u, resolver_->pending_requests().size());
- EXPECT_EQ(url1, resolver_->pending_requests()[0]->url());
+ ASSERT_EQ(1u, resolver_.pending_requests().size());
+ EXPECT_EQ(url1, resolver_.pending_requests()[0]->url());
- resolver_->pending_requests()[0]->results()->UseNamedProxy("result1:80");
- resolver_->pending_requests()[0]->CompleteNow(net::OK);
+ resolver_.pending_requests()[0]->results()->UseNamedProxy("result1:80");
+ resolver_.pending_requests()[0]->CompleteNow(net::OK);
// Check result.
EXPECT_EQ(true, pending_result()->result);
EXPECT_EQ("PROXY result1:80", pending_result()->proxy_list);
clear_pending_result();
- ASSERT_EQ(1u, resolver_->pending_requests().size());
- EXPECT_EQ(url2, resolver_->pending_requests()[0]->url());
+ ASSERT_EQ(1u, resolver_.pending_requests().size());
+ EXPECT_EQ(url2, resolver_.pending_requests()[0]->url());
- resolver_->pending_requests()[0]->results()->UseNamedProxy("result2:80");
- resolver_->pending_requests()[0]->CompleteNow(net::OK);
+ resolver_.pending_requests()[0]->results()->UseNamedProxy("result2:80");
+ resolver_.pending_requests()[0]->CompleteNow(net::OK);
// Check result.
EXPECT_EQ(true, pending_result()->result);
EXPECT_EQ("PROXY result2:80", pending_result()->proxy_list);
clear_pending_result();
- ASSERT_EQ(1u, resolver_->pending_requests().size());
- EXPECT_EQ(url3, resolver_->pending_requests()[0]->url());
+ ASSERT_EQ(1u, resolver_.pending_requests().size());
+ EXPECT_EQ(url3, resolver_.pending_requests()[0]->url());
- resolver_->pending_requests()[0]->results()->UseNamedProxy("result3:80");
- resolver_->pending_requests()[0]->CompleteNow(net::OK);
+ resolver_.pending_requests()[0]->results()->UseNamedProxy("result3:80");
+ resolver_.pending_requests()[0]->CompleteNow(net::OK);
// Check result.
EXPECT_EQ(true, pending_result()->result);
@@ -228,15 +235,17 @@ TEST_F(ResolveProxyMsgHelperTest, CancelPendingRequests) {
helper_->OnResolveProxy(url1, msg1);
// Finish ProxyService's initialization.
- resolver_->pending_set_pac_script_request()->CompleteNow(net::OK);
+ ASSERT_EQ(1u, resolver_factory_->pending_requests().size());
+ resolver_factory_->pending_requests()[0]->CompleteNowWithForwarder(
+ net::OK, &resolver_);
helper_->OnResolveProxy(url2, msg2);
helper_->OnResolveProxy(url3, msg3);
// ResolveProxyHelper only keeps 1 request outstanding in ProxyService
// at a time.
- ASSERT_EQ(1u, resolver_->pending_requests().size());
- EXPECT_EQ(url1, resolver_->pending_requests()[0]->url());
+ ASSERT_EQ(1u, resolver_.pending_requests().size());
+ EXPECT_EQ(url1, resolver_.pending_requests()[0]->url());
// Delete the underlying ResolveProxyMsgHelper -- this should cancel all
// the requests which are outstanding.
@@ -244,7 +253,7 @@ TEST_F(ResolveProxyMsgHelperTest, CancelPendingRequests) {
// The pending requests sent to the proxy resolver should have been cancelled.
- EXPECT_EQ(0u, resolver_->pending_requests().size());
+ EXPECT_EQ(0u, resolver_.pending_requests().size());
EXPECT_TRUE(pending_result() == NULL);
diff --git a/chromium/content/browser/resource_context_impl.cc b/chromium/content/browser/resource_context_impl.cc
index f9f3bc890a7..b99c80d54ab 100644
--- a/chromium/content/browser/resource_context_impl.cc
+++ b/chromium/content/browser/resource_context_impl.cc
@@ -6,7 +6,6 @@
#include "base/logging.h"
#include "content/browser/fileapi/chrome_blob_storage_context.h"
-#include "content/browser/host_zoom_map_impl.h"
#include "content/browser/loader/resource_dispatcher_host_impl.h"
#include "content/browser/loader/resource_request_info_impl.h"
#include "content/browser/streams/stream_context.h"
@@ -24,19 +23,9 @@ namespace {
// Key names on ResourceContext.
const char kBlobStorageContextKeyName[] = "content_blob_storage_context";
-const char kHostZoomMapKeyName[] = "content_host_zoom_map";
const char kStreamContextKeyName[] = "content_stream_context";
const char kURLDataManagerBackendKeyName[] = "url_data_manager_backend";
-class NonOwningZoomData : public base::SupportsUserData::Data {
- public:
- explicit NonOwningZoomData(HostZoomMap* hzm) : host_zoom_map_(hzm) {}
- HostZoomMap* host_zoom_map() { return host_zoom_map_; }
-
- private:
- HostZoomMap* host_zoom_map_;
-};
-
// Used by the default implementation of GetMediaDeviceIDSalt, below.
std::string ReturnEmptySalt() {
return std::string();
@@ -79,31 +68,22 @@ void ResourceContext::CreateKeygenHandler(
}
ChromeBlobStorageContext* GetChromeBlobStorageContextForResourceContext(
- ResourceContext* resource_context) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ const ResourceContext* resource_context) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
return UserDataAdapter<ChromeBlobStorageContext>::Get(
resource_context, kBlobStorageContextKeyName);
}
StreamContext* GetStreamContextForResourceContext(
- ResourceContext* resource_context) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ const ResourceContext* resource_context) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
return UserDataAdapter<StreamContext>::Get(
resource_context, kStreamContextKeyName);
}
-HostZoomMap* GetHostZoomMapForResourceContext(ResourceContext* context) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- NonOwningZoomData* result = static_cast<NonOwningZoomData*>(
- context->GetUserData(kHostZoomMapKeyName));
- if (!result)
- return NULL;
- return result->host_zoom_map();
-}
-
URLDataManagerBackend* GetURLDataManagerForResourceContext(
ResourceContext* context) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!context->GetUserData(kURLDataManagerBackendKeyName)) {
context->SetUserData(kURLDataManagerBackendKeyName,
new URLDataManagerBackend());
@@ -114,7 +94,6 @@ URLDataManagerBackend* GetURLDataManagerForResourceContext(
void InitializeResourceContext(BrowserContext* browser_context) {
ResourceContext* resource_context = browser_context->GetResourceContext();
- DCHECK(!resource_context->GetUserData(kHostZoomMapKeyName));
resource_context->SetUserData(
kBlobStorageContextKeyName,
@@ -126,13 +105,6 @@ void InitializeResourceContext(BrowserContext* browser_context) {
new UserDataAdapter<StreamContext>(
StreamContext::GetFor(browser_context)));
- // This object is owned by the BrowserContext and not ResourceContext, so
- // store a non-owning pointer here.
- resource_context->SetUserData(
- kHostZoomMapKeyName,
- new NonOwningZoomData(
- HostZoomMap::GetDefaultForBrowserContext(browser_context)));
-
resource_context->DetachUserDataThread();
}
diff --git a/chromium/content/browser/resource_context_impl.h b/chromium/content/browser/resource_context_impl.h
index ed4de4de4a3..903cc543a24 100644
--- a/chromium/content/browser/resource_context_impl.h
+++ b/chromium/content/browser/resource_context_impl.h
@@ -5,6 +5,7 @@
#ifndef CONTENT_BROWSER_RESOURCE_CONTEXT_IMPL_H_
#define CONTENT_BROWSER_RESOURCE_CONTEXT_IMPL_H_
+#include "content/common/content_export.h"
#include "content/public/browser/resource_context.h"
namespace content {
@@ -12,7 +13,6 @@ namespace content {
class ChromeBlobStorageContext;
class StreamContext;
class BrowserContext;
-class HostZoomMap;
class URLDataManagerBackend;
// Getters for objects that are part of BrowserContext which are also used on
@@ -20,18 +20,16 @@ class URLDataManagerBackend;
// public API.
ChromeBlobStorageContext* GetChromeBlobStorageContextForResourceContext(
- ResourceContext* resource_context);
+ const ResourceContext* resource_context);
-StreamContext* GetStreamContextForResourceContext(
- ResourceContext* resource_context);
-
-HostZoomMap* GetHostZoomMapForResourceContext(ResourceContext* context);
+CONTENT_EXPORT StreamContext* GetStreamContextForResourceContext(
+ const ResourceContext* resource_context);
URLDataManagerBackend* GetURLDataManagerForResourceContext(
ResourceContext* context);
// Initialize the above data on the ResourceContext from a given BrowserContext.
-void InitializeResourceContext(BrowserContext* browser_context);
+CONTENT_EXPORT void InitializeResourceContext(BrowserContext* browser_context);
} // namespace content
diff --git a/chromium/content/browser/resources/accessibility/OWNERS b/chromium/content/browser/resources/accessibility/OWNERS
new file mode 100644
index 00000000000..cad33362653
--- /dev/null
+++ b/chromium/content/browser/resources/accessibility/OWNERS
@@ -0,0 +1,2 @@
+aboxhall@chromium.org
+dmazzoni@chromium.org
diff --git a/chromium/content/browser/resources/accessibility/accessibility.html b/chromium/content/browser/resources/accessibility/accessibility.html
index c1a2d8d0bfc..888a16c795c 100644
--- a/chromium/content/browser/resources/accessibility/accessibility.html
+++ b/chromium/content/browser/resources/accessibility/accessibility.html
@@ -1,4 +1,4 @@
-<!DOCTYPE HTML>
+<!doctype html>
<html>
<!--
Copyright (c) 2013 The Chromium Authors. All rights reserved.
@@ -8,9 +8,11 @@ found in the LICENSE file.
<head>
<meta charset="utf-8">
<title>Accessibility</title>
+ <link rel="stylesheet" href="chrome://resources/css/chrome_shared.css">
<link rel="stylesheet" href="accessibility.css">
<script src="chrome://resources/js/cr.js"></script>
<script src="chrome://resources/js/load_time_data.js"></script>
+ <script src="chrome://resources/js/action_link.js"></script>
<script src="chrome://resources/js/util.js"></script>
<script src="strings.js"></script>
<script src="accessibility.js"></script>
@@ -18,8 +20,9 @@ found in the LICENSE file.
<body>
<h1>Accessibility</h1>
<div id="global" class="row">Global accessibility mode:
- <a id="toggle_global" href="#"></a></div>
+ <a is="action-link" role="button" id="toggle_global" aria-labelledby="global"></a>
+ </div>
<div id="pages" class="list"></div>
- <script src="chrome://resources/js/i18n_template2.js"></script>
+ <script src="chrome://resources/js/i18n_template.js"></script>
</body>
</html>
diff --git a/chromium/content/browser/resources/accessibility/accessibility.js b/chromium/content/browser/resources/accessibility/accessibility.js
index 37af8e75d44..7277dd2713c 100644
--- a/chromium/content/browser/resources/accessibility/accessibility.js
+++ b/chromium/content/browser/resources/accessibility/accessibility.js
@@ -80,6 +80,8 @@ cr.define('accessibility', function() {
function addGlobalAccessibilityModeToggle(global_a11y_mode) {
var full_a11y_on = isAccessibilityComplete(global_a11y_mode);
$('toggle_global').textContent = (full_a11y_on ? 'on' : 'off');
+ $('toggle_global').setAttribute('aria-pressed',
+ (full_a11y_on ? 'true' : 'false'));
$('toggle_global').addEventListener('click',
toggleGlobalAccessibility);
}
@@ -149,18 +151,19 @@ cr.define('accessibility', function() {
}
function createToggleAccessibilityElement(data) {
- var link = document.createElement('a');
- link.setAttribute('href', '#');
+ var link = document.createElement('a', 'action-link');
+ link.setAttribute('role', 'button');
var full_a11y_on = isAccessibilityComplete(data['a11y_mode']);
link.textContent = 'accessibility ' + (full_a11y_on ? 'on' : 'off');
+ link.setAttribute('aria-pressed', (full_a11y_on ? 'true' : 'false'));
link.addEventListener('click',
toggleAccessibility.bind(this, data, link));
return link;
}
function createShowAccessibilityTreeElement(data, row, opt_refresh) {
- var link = document.createElement('a');
- link.setAttribute('href', '#');
+ var link = document.createElement('a', 'action-link');
+ link.setAttribute('role', 'button');
if (opt_refresh)
link.textContent = 'refresh accessibility tree';
else
@@ -172,8 +175,8 @@ cr.define('accessibility', function() {
}
function createHideAccessibilityTreeElement(id) {
- var link = document.createElement('a');
- link.setAttribute('href', '#');
+ var link = document.createElement('a', 'action-link');
+ link.setAttribute('role', 'button');
link.textContent = 'hide accessibility tree';
link.addEventListener('click',
function() {
diff --git a/chromium/content/browser/resources/gpu/gpu_internals.html b/chromium/content/browser/resources/gpu/gpu_internals.html
index 709af4326f9..8a1c4271da9 100644
--- a/chromium/content/browser/resources/gpu/gpu_internals.html
+++ b/chromium/content/browser/resources/gpu/gpu_internals.html
@@ -1,11 +1,11 @@
-<!DOCTYPE HTML>
+<!doctype html>
<html>
<!--
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.
-->
-<head i18n-values="dir:textdirection;">
+<head i18n-values="dir:textdirection;lang:language">
<meta name="viewport" content="width=device-width" />
<style>
* {
@@ -49,7 +49,7 @@ tabbox tabpanels {
<div id="debug-div">
</div>
<include src="info_view.html">
- <script src="chrome://resources/js/i18n_template2.js"></script>
+ <script src="chrome://resources/js/i18n_template.js"></script>
<script src="chrome://resources/js/jstemplate_compiled.js"></script>
</body>
</html>
diff --git a/chromium/content/browser/resources/gpu/info_view.html b/chromium/content/browser/resources/gpu/info_view.html
index 76b235e2230..7a4fade55b4 100644
--- a/chromium/content/browser/resources/gpu/info_view.html
+++ b/chromium/content/browser/resources/gpu/info_view.html
@@ -27,11 +27,6 @@ found in the LICENSE file.
<div id="client-info"></div>
</div>
- <div class="performance-div">
- <h3>Performance Information</h3>
- <div id="performance-info"></div>
- </div>
-
<div>
<h3>Driver Information</h3>
<div id="basic-info"></div>
diff --git a/chromium/content/browser/resources/gpu/info_view.js b/chromium/content/browser/resources/gpu/info_view.js
index e4d1795cf99..40810054558 100644
--- a/chromium/content/browser/resources/gpu/info_view.js
+++ b/chromium/content/browser/resources/gpu/info_view.js
@@ -152,7 +152,6 @@ cr.define('gpu', function() {
var problemsList = this.querySelector('.problems-list');
var workaroundsDiv = this.querySelector('.workarounds-div');
var workaroundsList = this.querySelector('.workarounds-list');
- var performanceDiv = this.querySelector('.performance-div');
var gpuInfo = browserBridge.gpuInfo;
var i;
if (gpuInfo) {
@@ -223,13 +222,6 @@ cr.define('gpu', function() {
else
this.setTable_('basic-info', []);
- if (gpuInfo.performance_info) {
- performanceDiv.hidden = false;
- this.setTable_('performance-info', gpuInfo.performance_info);
- } else {
- performanceDiv.hidden = true;
- }
-
if (gpuInfo.diagnostics) {
diagnosticsDiv.hidden = false;
diagnosticsLoadingDiv.hidden = true;
diff --git a/chromium/content/browser/resources/gpu/timeline_test.html b/chromium/content/browser/resources/gpu/timeline_test.html
index 107840a8dd8..4e04cf4929f 100644
--- a/chromium/content/browser/resources/gpu/timeline_test.html
+++ b/chromium/content/browser/resources/gpu/timeline_test.html
@@ -1,4 +1,4 @@
-<!DOCTYPE html>
+<!doctype html>
<!--
Copyright (c) 2012 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
diff --git a/chromium/content/browser/resources/indexed_db/indexeddb_internals.css b/chromium/content/browser/resources/indexed_db/indexeddb_internals.css
index 774938b3201..232796a9759 100644
--- a/chromium/content/browser/resources/indexed_db/indexeddb_internals.css
+++ b/chromium/content/browser/resources/indexed_db/indexeddb_internals.css
@@ -48,6 +48,11 @@
font-weight: bold;
}
+.indexeddb-path {
+ display: block;
+ margin-left: 1em;
+}
+
.indexeddb-transaction-list {
margin-left: 10px;
border-collapse: collapse;
diff --git a/chromium/content/browser/resources/indexed_db/indexeddb_internals.html b/chromium/content/browser/resources/indexed_db/indexeddb_internals.html
index f389e9fbc89..b1179de3406 100644
--- a/chromium/content/browser/resources/indexed_db/indexeddb_internals.html
+++ b/chromium/content/browser/resources/indexed_db/indexeddb_internals.html
@@ -1,5 +1,5 @@
-<!DOCTYPE html>
-<html i18n-values="dir:textdirection;">
+<!doctype html>
+<html i18n-values="dir:textdirection;lang:language">
<head>
<meta charset="utf-8">
<title>IndexedDB</title>
@@ -39,9 +39,9 @@
jsvalues=".idb_origin_url:url;.idb_partition_path:$partition_path"
jscontent="connection_count">
</div>
- <div class="indexeddb-last-modified">
- <span>Path:</span>
- <span jscontent="path"></span>
+ <div class="indexeddb-paths">
+ <span>Paths:</span>
+ <span class="indexeddb-path" jscontent="$this" jsselect="$this.paths"></span>
</div>
<div class="controls">
<a href="#" class="force-close"
@@ -183,6 +183,6 @@
<script src="chrome://resources/js/load_time_data.js"></script>
<script src="chrome://resources/js/jstemplate_compiled.js"></script>
<script src="strings.js"></script>
- <script src="chrome://resources/js/i18n_template2.js"></script>
+ <script src="chrome://resources/js/i18n_template.js"></script>
</body>
</html>
diff --git a/chromium/content/browser/resources/media/OWNERS b/chromium/content/browser/resources/media/OWNERS
index ad545785604..ae057213b51 100644
--- a/chromium/content/browser/resources/media/OWNERS
+++ b/chromium/content/browser/resources/media/OWNERS
@@ -2,7 +2,4 @@ dalecurtis@chromium.org
ddorwin@chromium.org
scherkus@chromium.org
tommi@chromium.org
-vrk@chromium.org
-wjia@chromium.org
xhwang@chromium.org
-xians@chromium.org
diff --git a/chromium/content/browser/resources/media/client_renderer.js b/chromium/content/browser/resources/media/client_renderer.js
index 0eedb35df46..a631cbef87b 100644
--- a/chromium/content/browser/resources/media/client_renderer.js
+++ b/chromium/content/browser/resources/media/client_renderer.js
@@ -5,11 +5,13 @@
var ClientRenderer = (function() {
var ClientRenderer = function() {
this.playerListElement = document.getElementById('player-list');
- this.propertiesTable =
- document.getElementById('property-table').querySelector('tbody');
+ this.audioPropertiesTable =
+ document.getElementById('audio-property-table').querySelector('tbody');
+ this.playerPropertiesTable =
+ document.getElementById('player-property-table').querySelector('tbody');
this.logTable = document.getElementById('log').querySelector('tbody');
this.graphElement = document.getElementById('graphs');
- this.propertyName = document.getElementById('property-name');
+ this.audioPropertyName = document.getElementById('audio-property-name');
this.selectedPlayer = null;
this.selectedAudioComponentType = null;
@@ -27,10 +29,26 @@ var ClientRenderer = (function() {
this.bufferCanvas.height = media.BAR_HEIGHT;
this.clipboardTextarea = document.getElementById('clipboard-textarea');
- this.clipboardButton = document.getElementById('copy-button');
- this.clipboardButton.onclick = this.copyToClipboard_.bind(this);
+ var clipboardButtons = document.getElementsByClassName('copy-button');
+ for (var i = 0; i < clipboardButtons.length; i++) {
+ clipboardButtons[i].onclick = this.copyToClipboard_.bind(this);
+ }
this.hiddenKeys = ['component_id', 'component_type', 'owner_id'];
+
+ // Tell CSS to hide certain content prior to making selections.
+ document.body.classList.add(ClientRenderer.Css_.NO_PLAYERS_SELECTED);
+ document.body.classList.add(ClientRenderer.Css_.NO_COMPONENTS_SELECTED);
+ };
+
+ /**
+ * CSS classes added / removed in JS to trigger styling changes.
+ * @private @enum {string}
+ */
+ ClientRenderer.Css_ = {
+ NO_PLAYERS_SELECTED: 'no-players-selected',
+ NO_COMPONENTS_SELECTED: 'no-components-selected',
+ SELECTABLE_BUTTON: 'selectable-button'
};
function removeChildren(element) {
@@ -39,17 +57,42 @@ var ClientRenderer = (function() {
}
};
- function createButton(text, select_cb) {
- var button = document.createElement('button');
-
- button.appendChild(document.createTextNode(text));
- button.onclick = function() {
+ function createSelectableButton(id, groupName, text, select_cb) {
+ // For CSS styling.
+ var radioButton = document.createElement('input');
+ radioButton.classList.add(ClientRenderer.Css_.SELECTABLE_BUTTON);
+ radioButton.type = 'radio';
+ radioButton.id = id;
+ radioButton.name = groupName;
+
+ var buttonLabel = document.createElement('label');
+ buttonLabel.classList.add(ClientRenderer.Css_.SELECTABLE_BUTTON);
+ buttonLabel.setAttribute('for', radioButton.id);
+ buttonLabel.appendChild(document.createTextNode(text));
+
+ var fragment = document.createDocumentFragment();
+ fragment.appendChild(radioButton);
+ fragment.appendChild(buttonLabel);
+
+ // Listen to 'change' rather than 'click' to keep styling in sync with
+ // button behavior.
+ radioButton.addEventListener('change', function() {
select_cb();
- };
+ });
- return button;
+ return fragment;
};
+ function selectSelectableButton(id) {
+ var element = document.getElementById(id);
+ if (!element) {
+ console.error('failed to select button with id: ' + id);
+ return;
+ }
+
+ element.checked = true;
+ }
+
ClientRenderer.prototype = {
/**
* Called when an audio component is added to the collection.
@@ -64,6 +107,10 @@ var ClientRenderer = (function() {
if (this.selectedAudioComponentType == componentType &&
this.selectedAudioComponentId &&
this.selectedAudioComponentId in components) {
+ // TODO(chcunningham): This path is used both for adding and updating
+ // the components. Split this up to have a separate update method.
+ // At present, this selectAudioComponent call is key to *updating* the
+ // the property table for existing audio components.
this.selectAudioComponent_(
componentType, this.selectedAudioComponentId,
components[this.selectedAudioComponentId]);
@@ -78,12 +125,6 @@ var ClientRenderer = (function() {
*/
audioComponentRemoved: function(componentType, components) {
this.redrawAudioComponentList_(componentType, components);
-
- // Clear the component if it was previously currently selected.
- if (this.selectedAudioComponentType == componentType &&
- !(this.selectedAudioComponentId in components)) {
- this.selectAudioComponent_(null, null, {});
- }
},
/**
@@ -113,7 +154,7 @@ var ClientRenderer = (function() {
*/
playerUpdated: function(players, player, key, value) {
if (player === this.selectedPlayer) {
- this.drawProperties_(player.properties);
+ this.drawProperties_(player.properties, this.playerPropertiesTable);
this.drawLog_();
this.drawGraphs_();
}
@@ -183,54 +224,100 @@ var ClientRenderer = (function() {
}
},
- redrawAudioComponentList_: function(componentType, components) {
- function redrawList(renderer, baseName, element) {
- var fragment = document.createDocumentFragment();
- for (id in components) {
- var li = document.createElement('li');
- var friendlyName = baseName + ' ' + id;
- li.appendChild(createButton(
- friendlyName, renderer.selectAudioComponent_.bind(
- renderer, componentType, id, components[id], friendlyName)));
- fragment.appendChild(li);
- }
- removeChildren(element);
- element.appendChild(fragment);
+ getAudioComponentName_ : function(componentType, id) {
+ var baseName;
+ switch (componentType) {
+ case 0:
+ case 1:
+ baseName = 'Controller';
+ break;
+ case 2:
+ baseName = 'Stream';
+ break;
+ default:
+ baseName = 'UnknownType'
+ console.error('Unrecognized component type: ' + componentType);
+ break;
}
+ return baseName + ' ' + id;
+ },
+ getListElementForAudioComponent_ : function(componentType) {
+ var listElement;
switch (componentType) {
case 0:
- redrawList(this, 'Controller', document.getElementById(
- 'audio-input-controller-list'));
+ listElement = document.getElementById(
+ 'audio-input-controller-list');
break;
case 1:
- redrawList(this, 'Controller', document.getElementById(
- 'audio-output-controller-list'));
+ listElement = document.getElementById(
+ 'audio-output-controller-list');
break;
case 2:
- redrawList(this, 'Stream', document.getElementById(
- 'audio-output-stream-list'));
+ listElement = document.getElementById(
+ 'audio-output-stream-list');
break;
default:
+ console.error('Unrecognized component type: ' + componentType);
+ listElement = null;
break;
}
+ return listElement;
+ },
+
+ redrawAudioComponentList_: function(componentType, components) {
+ // Group name imposes rule that only one component can be selected
+ // (and have its properties displayed) at a time.
+ var buttonGroupName = 'audio-components';
+
+ var listElement = this.getListElementForAudioComponent_(componentType);
+ if (!listElement) {
+ console.error('Failed to find list element for component type: ' +
+ componentType);
+ return;
+ }
+
+ var fragment = document.createDocumentFragment();
+ for (id in components) {
+ var li = document.createElement('li');
+ var button_cb = this.selectAudioComponent_.bind(
+ this, componentType, id, components[id]);
+ var friendlyName = this.getAudioComponentName_(componentType, id);
+ li.appendChild(createSelectableButton(
+ id, buttonGroupName, friendlyName, button_cb));
+ fragment.appendChild(li);
+ }
+ removeChildren(listElement);
+ listElement.appendChild(fragment);
+
+ if (this.selectedAudioComponentType &&
+ this.selectedAudioComponentType == componentType &&
+ this.selectedAudioComponentId in components) {
+ // Re-select the selected component since the button was just recreated.
+ selectSelectableButton(this.selectedAudioComponentId);
+ }
},
selectAudioComponent_: function(
- componentType, componentId, componentData, friendlyName) {
- this.selectedPlayer = null;
+ componentType, componentId, componentData) {
+ document.body.classList.remove(
+ ClientRenderer.Css_.NO_COMPONENTS_SELECTED);
+
this.selectedAudioComponentType = componentType;
this.selectedAudioComponentId = componentId;
this.selectedAudioCompontentData = componentData;
- this.drawProperties_(componentData);
- removeChildren(this.logTable);
- removeChildren(this.graphElement);
+ this.drawProperties_(componentData, this.audioPropertiesTable);
- removeChildren(this.propertyName);
- this.propertyName.appendChild(document.createTextNode(friendlyName));
+ removeChildren(this.audioPropertyName);
+ this.audioPropertyName.appendChild(document.createTextNode(
+ this.getAudioComponentName_(componentType, componentId)));
},
redrawPlayerList_: function(players) {
+ // Group name imposes rule that only one component can be selected
+ // (and have its properties displayed) at a time.
+ var buttonGroupName = 'player-buttons';
+
var fragment = document.createDocumentFragment();
for (id in players) {
var player = players[id];
@@ -239,32 +326,38 @@ var ClientRenderer = (function() {
'Player ' + player.id;
var li = document.createElement('li');
- li.appendChild(createButton(
- usableName, this.selectPlayer_.bind(this, player)));
+ var button_cb = this.selectPlayer_.bind(this, player);
+ li.appendChild(createSelectableButton(
+ id, buttonGroupName, usableName, button_cb));
fragment.appendChild(li);
}
removeChildren(this.playerListElement);
this.playerListElement.appendChild(fragment);
+
+ if (this.selectedPlayer && this.selectedPlayer.id in players) {
+ // Re-select the selected player since the button was just recreated.
+ selectSelectableButton(this.selectedPlayer.id);
+ }
},
selectPlayer_: function(player) {
+ document.body.classList.remove(ClientRenderer.Css_.NO_PLAYERS_SELECTED);
+
this.selectedPlayer = player;
this.selectedPlayerLogIndex = 0;
this.selectedAudioComponentType = null;
this.selectedAudioComponentId = null;
this.selectedAudioCompontentData = null;
- this.drawProperties_(player.properties);
+ this.drawProperties_(player.properties, this.playerPropertiesTable);
removeChildren(this.logTable);
removeChildren(this.graphElement);
this.drawLog_();
this.drawGraphs_();
- removeChildren(this.propertyName);
- this.propertyName.appendChild(document.createTextNode('Player'));
},
- drawProperties_: function(propertyMap) {
- removeChildren(this.propertiesTable);
+ drawProperties_: function(propertyMap, propertiesTable) {
+ removeChildren(propertiesTable);
var sortedKeys = Object.keys(propertyMap).sort();
for (var i = 0; i < sortedKeys.length; ++i) {
var key = sortedKeys[i];
@@ -272,7 +365,7 @@ var ClientRenderer = (function() {
continue;
var value = propertyMap[key];
- var row = this.propertiesTable.insertRow(-1);
+ var row = propertiesTable.insertRow(-1);
var keyCell = row.insertCell(-1);
var valueCell = row.insertCell(-1);
@@ -372,11 +465,11 @@ var ClientRenderer = (function() {
},
copyToClipboard_: function() {
- var properties = this.selectedAudioCompontentData ||
- this.selectedPlayer.properties || false;
- if (!properties) {
+ if (!this.selectedPlayer && !this.selectedAudioCompontentData) {
return;
}
+ var properties = this.selectedAudioCompontentData ||
+ this.selectedPlayer.properties;
var stringBuffer = [];
for (var key in properties) {
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 7f2d128a79d..424fc65d3c5 100644
--- a/chromium/content/browser/resources/media/disjoint_range_set_test.html
+++ b/chromium/content/browser/resources/media/disjoint_range_set_test.html
@@ -1,4 +1,4 @@
-<!DOCTYPE html>
+<!doctype html>
<html>
<!--
Copyright (c) 2011 The Chromium Authors. All rights reserved.
diff --git a/chromium/content/browser/resources/media/dump_creator.js b/chromium/content/browser/resources/media/dump_creator.js
index 15d708b3daf..e412f3623bc 100644
--- a/chromium/content/browser/resources/media/dump_creator.js
+++ b/chromium/content/browser/resources/media/dump_creator.js
@@ -32,7 +32,7 @@ var DumpCreator = (function() {
'Download the PeerConnection updates and stats data' +
'</button></a></div>' +
'<p><label><input type=checkbox>' +
- 'Enable diagnostic audio recordings.</label></p>' +
+ 'Enable diagnostic audio recordings</label></p>' +
'<p>A diagnostic audio recording is used for analyzing audio' +
' problems. It contains the audio played out from the speaker and' +
' recorded from the microphone and is saved to the local disk.' +
@@ -52,7 +52,7 @@ var DumpCreator = (function() {
' disabled (--disable-audio-track-processing): (1) Only one recording' +
' per render process is supported. (2) When the box is unchecked or' +
' this page is closed, ongoing recordings will continue until the' +
- ' call ends or the page with the recording is closed.</p>';
+ ' call ends or the page with the recording is closed</p>';
content.getElementsByTagName('a')[0].addEventListener(
'click', this.onDownloadData_.bind(this));
diff --git a/chromium/content/browser/resources/media/media_internals.css b/chromium/content/browser/resources/media/media_internals.css
index 0165c3f4010..7b2c43feca4 100644
--- a/chromium/content/browser/resources/media/media_internals.css
+++ b/chromium/content/browser/resources/media/media_internals.css
@@ -12,6 +12,22 @@ body,
font-family:Arial;
}
+tabbox {
+ margin-top: 10px;
+}
+
+tab {
+ -webkit-user-select: none;
+}
+
+body tabpanels {
+ box-shadow: none;
+}
+
+tabpanel {
+ padding: 10px;
+}
+
table {
font-family: sans-serif;
-webkit-font-smoothing: antialiased;
@@ -21,7 +37,7 @@ table {
display: block;
}
th {
- background-color: rgb(112, 196, 105);
+ background-color: #4AA9E4;
font-weight: normal;
color: white;
padding: 2px;
@@ -84,12 +100,13 @@ h3 {
padding: 0px;
}
-#property-wrapper,
+.property-wrapper,
#log-wrapper {
+ align-self: stretch;
display:block;
flex-grow: 0.25;
- align-self: stretch;
overflow: auto;
+ margin-bottom: 10px;
}
#video-capture-capabilities-wrapper {
@@ -157,3 +174,34 @@ h3 {
#video-capture-capabilities-table .video-capture-formats-table td {
padding:2px;
}
+
+.show-none-if-empty:empty:after {
+ content: "none";
+ color: rgba(0, 0, 0, .5);
+}
+
+label.selectable-button {
+ -webkit-appearance: button;
+ -webkit-user-select: none;
+ padding: 2px 5px;
+ margin-bottom: 5px;
+}
+
+input.selectable-button {
+ display: none;
+}
+
+input.selectable-button:checked + label.selectable-button {
+ background-color: #4AA9E4;
+ color: white;
+}
+
+.no-players-selected #players .property-wrapper,
+.no-players-selected #players #log-wrapper {
+ display: none;
+}
+
+.no-components-selected #audio .property-wrapper {
+ display: none;
+}
+
diff --git a/chromium/content/browser/resources/media/media_internals.html b/chromium/content/browser/resources/media/media_internals.html
index d271082d2da..2d3d6572490 100644
--- a/chromium/content/browser/resources/media/media_internals.html
+++ b/chromium/content/browser/resources/media/media_internals.html
@@ -4,85 +4,120 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<!DOCTYPE html>
-<html i18n-values="dir:textdirection">
+<html i18n-values="dir:textdirection;lang:language">
<head>
<meta charset="utf-8">
<title i18n-content="Media Internals"></title>
<link rel="stylesheet" href="media_internals.css">
<script src="chrome://resources/js/cr.js"></script>
+ <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/util.js"></script>
+ <script src="chrome://resources/js/cr/ui/tabs.js"></script>
+ <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
+ <link rel="stylesheet" href="chrome://resources/css/tabs.css">
</head>
<body>
+ <tabbox>
+ <tabs>
+ <tab>Players</tab>
+ <tab>Audio</tab>
+ <tab>Video Capture</tab>
+ </tabs>
+ <tabpanels>
+ <tabpanel id="players">
+ <div id="list-wrapper">
+ <div id="player-list-wrapper">
+ <h2>Players</h2>
+ <ul id="player-list" class="show-none-if-empty"></ul>
+ </div>
+ </div>
+ <div class="property-wrapper">
+ <h2>
+ Player Properties
+ <button class="copy-button">Copy to clipboard</button>
+ </h2>
+ <table id="player-property-table">
+ <thead>
+ <tr>
+ <th>Property</th>
+ <th>Value</th>
+ </tr>
+ </thead>
+ <tbody></tbody>
+ </table>
+ </div>
+ <div id="log-wrapper">
+ <h2>
+ Log <input id="filter-text" type="text" placeholder="property filter">
+ </h2>
+ <table id="log">
+ <thead>
+ <tr>
+ <th class="timestamp">Timestamp</th>
+ <th>Property</th>
+ <th>Value</th>
+ </tr>
+ </thead>
+ <tbody></tbody>
+ </table>
+ </div>
+ <ul id="graphs"></ul>
+ </tabpanel>
+ <tabpanel id="audio">
+ <div id="audio-component-list-wrapper">
+ <h2>Input Controllers</h2>
+ <ul id="audio-input-controller-list" class="show-none-if-empty"></ul>
+ </div>
+ <div id="audio-component-list-wrapper">
+ <h2>Output Controllers</h2>
+ <ul id="audio-output-controller-list" class="show-none-if-empty"></ul>
+ </div>
+ <div id="audio-component-list-wrapper">
+ <h2>Output Streams</h2>
+ <ul id="audio-output-stream-list" class="show-none-if-empty"></ul>
+ </div>
+ <div class="property-wrapper">
+ <h2>
+ <span id="audio-property-name"></span> Properties
+ <button class="copy-button">Copy to clipboard</button>
+ </h2>
+ <table id="audio-property-table">
+ <thead>
+ <tr>
+ <th>Property</th>
+ <th>Value</th>
+ </tr>
+ </thead>
+ <tbody></tbody>
+ </table>
+ </div>
+ </tabpanel>
+ <tabpanel id="video-capture">
+ <div id="video-capture-capabilities-wrapper">
+ <h2>
+ <span>Video Capture Device Capabilities</span>
+ <button id="video-capture-capabilities-copy-button">
+ Copy to clipboard
+ </button>
+ </h2>
+ <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" class="show-none-if-empty"></tbody>
+ </table>
+ </div>
+ </tabpanel>
+ </tabpanels>
+ </tabbox>
<textarea id="clipboard-textarea" class="hiddenClipboard"></textarea>
- <div id="container">
- <div id="list-wrapper">
- <div id="player-list-wrapper">
- <h2>Players</h2>
- <ul id="player-list"></ul>
- </div>
- <div id="audio-component-list-wrapper">
- <h2>Input Controllers</h2>
- <ul id="audio-input-controller-list"></ul>
- </div>
- <div id="audio-component-list-wrapper">
- <h2>Output Controllers</h2>
- <ul id="audio-output-controller-list"></ul>
- </div>
- <div id="audio-component-list-wrapper">
- <h2>Output Streams</h2>
- <ul id="audio-output-stream-list"></ul>
- </div>
- </div>
- <div id="property-wrapper">
- <h2>
- <span id="property-name"></span> Properties
- <button id="copy-button">Copy to clipboard</button>
- </h2>
- <table id="property-table">
- <thead>
- <tr>
- <th>Property</th>
- <th>Value</th>
- </tr>
- </thead>
- <tbody></tbody>
- </table>
- <ul id="graphs"></ul>
- </div>
- <div id="log-wrapper">
- <h2>
- Log <input id="filter-text" type="text">
- </h2>
- <table id="log">
- <thead>
- <tr>
- <th class="timestamp">Timestamp</th>
- <th>Property</th>
- <th>Value</th>
- </tr>
- </thead>
- <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>
</html>
diff --git a/chromium/content/browser/resources/media/media_internals.js b/chromium/content/browser/resources/media/media_internals.js
index 936f86d357b..554d6690982 100644
--- a/chromium/content/browser/resources/media/media_internals.js
+++ b/chromium/content/browser/resources/media/media_internals.js
@@ -13,3 +13,4 @@ var media = {};
<include src="client_renderer.js"/>
media.initialize(new Manager(new ClientRenderer()));
+cr.ui.decorate('tabbox', cr.ui.TabBox);
diff --git a/chromium/content/browser/resources/media/ssrc_info_manager.js b/chromium/content/browser/resources/media/ssrc_info_manager.js
index bb99f81d7e9..f588e1ec10c 100644
--- a/chromium/content/browser/resources/media/ssrc_info_manager.js
+++ b/chromium/content/browser/resources/media/ssrc_info_manager.js
@@ -48,7 +48,7 @@ var SsrcInfoManager = (function() {
function SsrcInfoManager() {
/**
* Map from ssrc id to an object containing all the stream properties.
- * @type {!Object.<string, !Object.<string>>}
+ * @type {!Object<string, !Object<string>>}
* @private
*/
this.streamInfoContainer_ = {};
@@ -133,7 +133,7 @@ var SsrcInfoManager = (function() {
/**
* @param {string} sdp The ssrc id.
- * @return {!Object.<string>} The object containing the ssrc infomation.
+ * @return {!Object<string>} The object containing the ssrc infomation.
*/
getStreamInfo: function(ssrc) {
return this.streamInfoContainer_[ssrc];
diff --git a/chromium/content/browser/resources/media/stats_table.js b/chromium/content/browser/resources/media/stats_table.js
index 07b5687fb33..8ad804a089f 100644
--- a/chromium/content/browser/resources/media/stats_table.js
+++ b/chromium/content/browser/resources/media/stats_table.js
@@ -110,7 +110,7 @@ var StatsTable = (function(ssrcInfoManager) {
*
* @param {!Element} statsTable Which table to update.
* @param {number} time The number of miliseconds since epoch.
- * @param {Array.<string>} statsData An array of stats name and value pairs.
+ * @param {Array<string>} statsData An array of stats name and value pairs.
* @private
*/
addStatsToTable_: function(statsTable, time, statsData) {
@@ -142,7 +142,7 @@ var StatsTable = (function(ssrcInfoManager) {
trElement.cells[1].textContent = value;
// Highlights the table for the active connection.
- if (rowName == 'googActiveConnection' && value == 'true')
+ if (rowName == 'googActiveConnection' && value == true)
statsTable.parentElement.classList.add('stats-table-active-connection');
}
};
diff --git a/chromium/content/browser/resources/media/webrtc_internals.html b/chromium/content/browser/resources/media/webrtc_internals.html
index b6a538f4e2b..39434b9be38 100644
--- a/chromium/content/browser/resources/media/webrtc_internals.html
+++ b/chromium/content/browser/resources/media/webrtc_internals.html
@@ -1,5 +1,5 @@
-<!DOCTYPE HTML>
-<html i18n-values="dir:textdirection;">
+<!doctype html>
+<html i18n-values="dir:textdirection;lang:language">
<head>
<meta charset="utf-8">
<title>WebRTC Internals</title>
diff --git a/chromium/content/browser/resources/media/webrtc_internals.js b/chromium/content/browser/resources/media/webrtc_internals.js
index 3a1f9cd25c1..3becab15092 100644
--- a/chromium/content/browser/resources/media/webrtc_internals.js
+++ b/chromium/content/browser/resources/media/webrtc_internals.js
@@ -117,7 +117,7 @@ function requestStats() {
/**
* A helper function for getting a peer connection element id.
*
- * @param {!Object.<string, number>} data The object containing the pid and lid
+ * @param {!Object<string, number>} data The object containing the pid and lid
* of the peer connection.
* @return {string} The peer connection element id.
*/
@@ -174,7 +174,7 @@ function addPeerConnectionUpdate(peerConnectionElement, update) {
/**
* Removes all information about a peer connection.
*
- * @param {!Object.<string, number>} data The object containing the pid and lid
+ * @param {!Object<string, number>} data The object containing the pid and lid
* of a peer connection.
*/
function removePeerConnection(data) {
@@ -205,9 +205,11 @@ function addPeerConnection(data) {
if (!peerConnectionElement) {
peerConnectionElement = tabView.addTab(id, data.url + ' [' + id + ']');
}
- peerConnectionElement.innerHTML =
- '<p>' + data.url + ' ' + data.rtcConfiguration + ' ' + data.constraints +
- '</p>';
+
+ var p = document.createElement('p');
+ p.textContent = data.url + ', ' + data.rtcConfiguration + ', ' +
+ data.constraints;
+ peerConnectionElement.appendChild(p);
return peerConnectionElement;
}
@@ -227,7 +229,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
+ * @param {Array<!Object>} data An array of the information of all peer
* connections. Each array item contains pid, lid, url, rtcConfiguration,
* constraints, and an array of updates as the log.
*/
diff --git a/chromium/content/browser/resources/service_worker/serviceworker_internals.html b/chromium/content/browser/resources/service_worker/serviceworker_internals.html
index 8c4e6afbd58..fd3fb9ea747 100644
--- a/chromium/content/browser/resources/service_worker/serviceworker_internals.html
+++ b/chromium/content/browser/resources/service_worker/serviceworker_internals.html
@@ -1,5 +1,5 @@
-<!DOCTYPE html>
-<html i18n-values="dir:textdirection;">
+<!doctype html>
+<html i18n-values="dir:textdirection;lang:language">
<head>
<meta charset="utf-8">
<title>ServiceWorker</title>
@@ -119,15 +119,13 @@
</div>
</div>
<div id="serviceworker-options-template">
- <div>
+ <div class="checkbox">
<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>
+ jsvalues=".checked:$this.debug_on_start">
+ <span>
+ Open DevTools window and pause JavaScript execution on Service Worker startup for debugging.
+ </span>
</label>
</div>
</div>
@@ -143,6 +141,6 @@
<script src="chrome://resources/js/load_time_data.js"></script>
<script src="chrome://resources/js/jstemplate_compiled.js"></script>
<script src="strings.js"></script>
- <script src="chrome://resources/js/i18n_template2.js"></script>
+ <script src="chrome://resources/js/i18n_template.js"></script>
</body>
</html>
diff --git a/chromium/content/browser/resources/service_worker/serviceworker_internals.js b/chromium/content/browser/resources/service_worker/serviceworker_internals.js
index 93bf437fbc5..b5c85eebfab 100644
--- a/chromium/content/browser/resources/service_worker/serviceworker_internals.js
+++ b/chromium/content/browser/resources/service_worker/serviceworker_internals.js
@@ -192,11 +192,7 @@ cr.define('serviceworker', function() {
}
}
- function onWorkerStarted(partition_id, version_id, process_id, thread_id) {
- update();
- }
-
- function onWorkerStopped(partition_id, version_id, process_id, thread_id) {
+ function onRunningStateChanged(partition_id, version_id) {
update();
}
@@ -258,8 +254,7 @@ cr.define('serviceworker', function() {
onOptions: onOptions,
onOperationComplete: onOperationComplete,
onPartitionData: onPartitionData,
- onWorkerStarted: onWorkerStarted,
- onWorkerStopped: onWorkerStopped,
+ onRunningStateChanged: onRunningStateChanged,
onErrorReported: onErrorReported,
onConsoleMessageReported: onConsoleMessageReported,
onVersionStateChanged: onVersionStateChanged,
diff --git a/chromium/content/browser/safe_util_win.h b/chromium/content/browser/safe_util_win.h
index 38604298d49..a668e95bc0c 100644
--- a/chromium/content/browser/safe_util_win.h
+++ b/chromium/content/browser/safe_util_win.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_COMMON_SAFE_UTIL_WIN_H_
-#define CONTENT_COMMON_SAFE_UTIL_WIN_H_
+#ifndef CONTENT_BROWSER_SAFE_UTIL_WIN_H_
+#define CONTENT_BROWSER_SAFE_UTIL_WIN_H_
#include <string>
#include <windows.h>
@@ -50,4 +50,4 @@ HRESULT AVScanFile(const base::FilePath& full_path,
const GUID& client_guid);
} // namespace content
-#endif // CONTENT_COMMON_SAFE_UTIL_WIN_H_
+#endif // CONTENT_BROWSER_SAFE_UTIL_WIN_H_
diff --git a/chromium/content/browser/screen_orientation/screen_orientation_browsertest.cc b/chromium/content/browser/screen_orientation/screen_orientation_browsertest.cc
index 33b026cf5bb..d7516cbf80a 100644
--- a/chromium/content/browser/screen_orientation/screen_orientation_browsertest.cc
+++ b/chromium/content/browser/screen_orientation/screen_orientation_browsertest.cc
@@ -32,14 +32,6 @@ class ScreenOrientationBrowserTest : public ContentBrowserTest {
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()
@@ -65,9 +57,10 @@ class ScreenOrientationBrowserTest : public ContentBrowserTest {
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.top_controls_height = 0.f;
+ params.top_controls_shrink_blink_size = false;
params.resizer_rect = gfx::Rect();
- params.is_fullscreen = false;
+ params.is_fullscreen_granted = false;
rwh->Send(new ViewMsg_Resize(rwh->GetRoutingID(), params));
}
@@ -114,7 +107,14 @@ class ScreenOrientationBrowserTest : public ContentBrowserTest {
// 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) {
+// Flaky on Chrome OS: http://crbug.com/468259
+#if defined(OS_CHROMEOS)
+#define MAYBE_ScreenOrientationChange DISABLED_ScreenOrientationChange
+#else
+#define MAYBE_ScreenOrientationChange ScreenOrientationChange
+#endif
+IN_PROC_BROWSER_TEST_F(ScreenOrientationBrowserTest,
+ MAYBE_ScreenOrientationChange) {
std::string types[] = { "portrait-primary",
"portrait-secondary",
"landscape-primary",
@@ -125,9 +125,7 @@ IN_PROC_BROWSER_TEST_F(ScreenOrientationBrowserTest, ScreenOrientationChange) {
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.
@@ -152,16 +150,23 @@ IN_PROC_BROWSER_TEST_F(ScreenOrientationBrowserTest, ScreenOrientationChange) {
}
#endif // defined(USE_AURA) || defined(OS_ANDROID)
-IN_PROC_BROWSER_TEST_F(ScreenOrientationBrowserTest, WindowOrientationChange) {
+// Flaky on Chrome OS: http://crbug.com/468259
+#if defined(OS_CHROMEOS)
+#define MAYBE_WindowOrientationChange DISABLED_WindowOrientationChange
+#else
+#define MAYBE_WindowOrientationChange WindowOrientationChange
+#endif
+IN_PROC_BROWSER_TEST_F(ScreenOrientationBrowserTest,
+ MAYBE_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
+#if USE_AURA || defined(OS_ANDROID)
WaitForResizeComplete(shell()->web_contents());
-#endif // USE_AURA
+#endif // USE_AURA || defined(OS_ANDROID)
if (!WindowOrientationSupported())
return;
@@ -178,8 +183,10 @@ IN_PROC_BROWSER_TEST_F(ScreenOrientationBrowserTest, WindowOrientationChange) {
}
}
+// LockSmoke test seems to have become flaky on all non-ChromeOS platforms.
+// The cause is unfortunately unknown. See https://crbug.com/448876
// Chromium Android does not support fullscreen
-IN_PROC_BROWSER_TEST_F(ScreenOrientationBrowserTest, LockSmoke) {
+IN_PROC_BROWSER_TEST_F(ScreenOrientationBrowserTest, DISABLED_LockSmoke) {
GURL test_url = GetTestUrl("screen_orientation",
"screen_orientation_lock_smoke.html");
@@ -196,9 +203,9 @@ IN_PROC_BROWSER_TEST_F(ScreenOrientationBrowserTest, LockSmoke) {
#endif // defined(OS_WIN)
navigation_observer.Wait();
-#if USE_AURA
+#if USE_AURA || defined(OS_ANDROID)
WaitForResizeComplete(shell()->web_contents());
-#endif // USE_AURA
+#endif // USE_AURA || defined(OS_ANDROID)
std::string expected =
#if defined(OS_ANDROID)
@@ -236,4 +243,30 @@ IN_PROC_BROWSER_TEST_F(ScreenOrientationBrowserTest, CrashTest_UseAfterDetach) {
// here.
}
+#if defined(OS_ANDROID)
+class ScreenOrientationLockDisabledBrowserTest : public ContentBrowserTest {
+ public:
+ ScreenOrientationLockDisabledBrowserTest() {}
+ ~ScreenOrientationLockDisabledBrowserTest() override {}
+
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ command_line->AppendSwitch(switches::kDisableScreenOrientationLock);
+ }
+};
+
+// Check that when --disable-screen-orientation-lock is passed to the command
+// line, screen.orientation.lock() correctly reports to not be supported.
+IN_PROC_BROWSER_TEST_F(ScreenOrientationLockDisabledBrowserTest, NotSupported) {
+ GURL test_url = GetTestUrl("screen_orientation",
+ "screen_orientation_lock_disabled.html");
+
+ TestNavigationObserver navigation_observer(shell()->web_contents(), 2);
+ shell()->LoadURL(test_url);
+ navigation_observer.Wait();
+
+ EXPECT_EQ("NotSupportedError",
+ shell()->web_contents()->GetLastCommittedURL().ref());
+}
+#endif // defined(OS_ANDROID)
+
} // 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
index bb2f5bc61f9..839b24c901b 100644
--- a/chromium/content/browser/screen_orientation/screen_orientation_delegate_android.cc
+++ b/chromium/content/browser/screen_orientation/screen_orientation_delegate_android.cc
@@ -42,6 +42,7 @@ bool ScreenOrientationDelegateAndroid::FullScreenRequired(
}
void ScreenOrientationDelegateAndroid::Lock(
+ WebContents* web_contents,
blink::WebScreenOrientationLockType lock_orientation) {
Java_ScreenOrientationProvider_lockOrientation(
base::android::AttachCurrentThread(), lock_orientation);
@@ -52,7 +53,7 @@ bool ScreenOrientationDelegateAndroid::ScreenOrientationProviderSupported() {
return true;
}
-void ScreenOrientationDelegateAndroid::Unlock() {
+void ScreenOrientationDelegateAndroid::Unlock(WebContents* web_contents) {
Java_ScreenOrientationProvider_unlockOrientation(
base::android::AttachCurrentThread());
}
diff --git a/chromium/content/browser/screen_orientation/screen_orientation_delegate_android.h b/chromium/content/browser/screen_orientation/screen_orientation_delegate_android.h
index fa3ee6e2211..75582094ca5 100644
--- a/chromium/content/browser/screen_orientation/screen_orientation_delegate_android.h
+++ b/chromium/content/browser/screen_orientation/screen_orientation_delegate_android.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_SCREEN_ORIENTATION_SCREEN_ORIENTATION_DELEGATE_H_
-#define CONTENT_BROWSER_SCREEN_ORIENTATION_SCREEN_ORIENTATION_DELEGATE_H_
+#ifndef CONTENT_BROWSER_SCREEN_ORIENTATION_SCREEN_ORIENTATION_DELEGATE_ANDROID_H_
+#define CONTENT_BROWSER_SCREEN_ORIENTATION_SCREEN_ORIENTATION_DELEGATE_ANDROID_H_
#include <jni.h>
@@ -20,7 +20,7 @@ class WebContents;
class ScreenOrientationDelegateAndroid : public ScreenOrientationDelegate {
public:
ScreenOrientationDelegateAndroid();
- virtual ~ScreenOrientationDelegateAndroid();
+ ~ScreenOrientationDelegateAndroid() override;
static bool Register(JNIEnv* env);
@@ -35,11 +35,11 @@ class ScreenOrientationDelegateAndroid : public ScreenOrientationDelegate {
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;
+ bool FullScreenRequired(WebContents* web_contents) override;
+ void Lock(WebContents* web_contents,
+ blink::WebScreenOrientationLockType lock_orientation) override;
+ bool ScreenOrientationProviderSupported() override;
+ void Unlock(WebContents* web_contents) override;
private:
DISALLOW_COPY_AND_ASSIGN(ScreenOrientationDelegateAndroid);
@@ -47,4 +47,4 @@ class ScreenOrientationDelegateAndroid : public ScreenOrientationDelegate {
} // namespace content
-#endif // CONTENT_BROWSER_SCREEN_ORIENTATION_SCREEN_ORIENTATION_DELEGATE_H_
+#endif // CONTENT_BROWSER_SCREEN_ORIENTATION_SCREEN_ORIENTATION_DELEGATE_ANDROID_H_
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
index a8840837883..29bc534ea7d 100644
--- a/chromium/content/browser/screen_orientation/screen_orientation_dispatcher_host_impl.h
+++ b/chromium/content/browser/screen_orientation/screen_orientation_dispatcher_host_impl.h
@@ -69,4 +69,4 @@ class CONTENT_EXPORT ScreenOrientationDispatcherHostImpl
} // namespace content
-#endif // CONTENT_BROWSER_SCREEN_ORIENTATION_SCREEN_ORIENTATION_DISPATCHER_HOST_IMPL_H_
+#endif // CONTENT_BROWSER_SCREEN_ORIENTATION_SCREEN_ORIENTATION_DISPATCHER_HOST_IMPL_H_
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
index 9a01ed4e866..9d85fe62010 100644
--- a/chromium/content/browser/screen_orientation/screen_orientation_message_filter_android.h
+++ b/chromium/content/browser/screen_orientation/screen_orientation_message_filter_android.h
@@ -14,10 +14,10 @@ class ScreenOrientationMessageFilterAndroid : public BrowserMessageFilter {
ScreenOrientationMessageFilterAndroid();
// BrowserMessageFilter implementation.
- virtual bool OnMessageReceived(const IPC::Message& message) override;
+ bool OnMessageReceived(const IPC::Message& message) override;
private:
- virtual ~ScreenOrientationMessageFilterAndroid();
+ ~ScreenOrientationMessageFilterAndroid() override;
void OnStartListening();
void OnStopListening();
diff --git a/chromium/content/browser/security_exploit_browsertest.cc b/chromium/content/browser/security_exploit_browsertest.cc
index 2a1be07b9a9..62d3b62c674 100644
--- a/chromium/content/browser/security_exploit_browsertest.cc
+++ b/chromium/content/browser/security_exploit_browsertest.cc
@@ -4,21 +4,31 @@
#include "base/command_line.h"
#include "base/containers/hash_tables.h"
+#include "base/strings/utf_string_conversions.h"
#include "content/browser/dom_storage/dom_storage_context_wrapper.h"
#include "content/browser/dom_storage/session_storage_namespace_impl.h"
#include "content/browser/frame_host/navigator.h"
#include "content/browser/renderer_host/render_view_host_factory.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/view_messages.h"
#include "content/public/browser/browser_context.h"
+#include "content/public/browser/interstitial_page.h"
+#include "content/public/browser/interstitial_page_delegate.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/common/content_switches.h"
+#include "content/public/common/file_chooser_params.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 "ipc/ipc_security_test_util.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+
+using IPC::IpcSecurityTestUtil;
namespace content {
@@ -35,10 +45,11 @@ namespace {
// the attempt is the return value.
RenderViewHostImpl* PrepareToDuplicateHosts(Shell* shell,
int* target_routing_id) {
- GURL foo("http://foo.com/files/simple_page.html");
+ GURL foo("http://foo.com/simple_page.html");
// Start off with initial navigation, so we get the first process allocated.
NavigateToURL(shell, foo);
+ EXPECT_EQ(base::ASCIIToUTF16("OK"), shell->web_contents()->GetTitle());
// Open another window, so we generate some more routing ids.
ShellAddedObserver shell2_observer;
@@ -55,12 +66,11 @@ RenderViewHostImpl* PrepareToDuplicateHosts(Shell* shell,
shell->web_contents()->GetRenderViewHost()->GetRoutingID());
// Now, simulate a link click coming from the renderer.
- GURL extension_url("https://bar.com/files/simple_page.html");
+ GURL extension_url("https://bar.com/simple_page.html");
WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell->web_contents());
wc->GetFrameTree()->root()->navigator()->RequestOpenURL(
- wc->GetFrameTree()->root()->current_frame_host(), extension_url,
- Referrer(), CURRENT_TAB,
- false, true);
+ wc->GetFrameTree()->root()->current_frame_host(), extension_url, nullptr,
+ Referrer(), CURRENT_TAB, false, true);
// Since the navigation above requires a cross-process swap, there will be a
// pending RenderViewHost. Ensure it exists and is in a different process
@@ -84,25 +94,56 @@ RenderViewHostImpl* PrepareToDuplicateHosts(Shell* shell,
class SecurityExploitBrowserTest : public ContentBrowserTest {
public:
SecurityExploitBrowserTest() {}
- void SetUpCommandLine(CommandLine* command_line) override {
- ASSERT_TRUE(test_server()->Start());
+
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
// Add a host resolver rule to map all outgoing requests to the test server.
// This allows us to use "real" hostnames in URLs, which we can use to
// create arbitrary SiteInstances.
command_line->AppendSwitchASCII(
switches::kHostResolverRules,
- "MAP * " + test_server()->host_port_pair().ToString() +
+ "MAP * " +
+ net::HostPortPair::FromURL(embedded_test_server()->base_url())
+ .ToString() +
",EXCLUDE localhost");
}
+
+ protected:
+ // Tests that a given file path sent in a ViewHostMsg_RunFileChooser will
+ // cause renderer to be killed.
+ void TestFileChooserWithPath(const base::FilePath& path);
};
+void SecurityExploitBrowserTest::TestFileChooserWithPath(
+ const base::FilePath& path) {
+ GURL foo("http://foo.com/simple_page.html");
+ NavigateToURL(shell(), foo);
+ EXPECT_EQ(base::ASCIIToUTF16("OK"), shell()->web_contents()->GetTitle());
+
+ content::RenderViewHost* compromised_renderer =
+ shell()->web_contents()->GetRenderViewHost();
+ content::RenderProcessHostWatcher terminated(
+ shell()->web_contents(),
+ content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+
+ FileChooserParams params;
+ params.default_file_name = path;
+
+ ViewHostMsg_RunFileChooser evil(compromised_renderer->GetRoutingID(), params);
+
+ IpcSecurityTestUtil::PwnMessageReceived(
+ compromised_renderer->GetProcess()->GetChannel(), evil);
+ terminated.Wait();
+}
+
// Ensure that we kill the renderer process if we try to give it WebUI
// properties and it doesn't have enabled WebUI bindings.
IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest, SetWebUIProperty) {
- GURL foo("http://foo.com/files/simple_page.html");
+ GURL foo("http://foo.com/simple_page.html");
NavigateToURL(shell(), foo);
+ EXPECT_EQ(base::ASCIIToUTF16("OK"), shell()->web_contents()->GetTitle());
EXPECT_EQ(0,
shell()->web_contents()->GetRenderViewHost()->GetEnabledBindings());
@@ -166,4 +207,111 @@ IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest,
// If the above operation doesn't crash, the test has succeeded!
}
+// This is a test for crbug.com/444198. It tries to send a
+// ViewHostMsg_RunFileChooser containing an invalid path. The browser should
+// correctly terminate the renderer in these cases.
+IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest, AttemptRunFileChoosers) {
+ TestFileChooserWithPath(base::FilePath(FILE_PATH_LITERAL("../../*.txt")));
+ TestFileChooserWithPath(base::FilePath(FILE_PATH_LITERAL("/etc/*.conf")));
+#if defined(OS_WIN)
+ TestFileChooserWithPath(
+ base::FilePath(FILE_PATH_LITERAL("\\\\evilserver\\evilshare\\*.txt")));
+ TestFileChooserWithPath(base::FilePath(FILE_PATH_LITERAL("c:\\*.txt")));
+ TestFileChooserWithPath(base::FilePath(FILE_PATH_LITERAL("..\\..\\*.txt")));
+#endif
+}
+
+class SecurityExploitTestInterstitialPage : public InterstitialPageDelegate {
+ public:
+ explicit SecurityExploitTestInterstitialPage(WebContents* contents) {
+ InterstitialPage* interstitial = InterstitialPage::Create(
+ contents, true, contents->GetLastCommittedURL(), this);
+ interstitial->Show();
+ }
+
+ // InterstitialPageDelegate implementation.
+ void CommandReceived(const std::string& command) override {
+ last_command_ = command;
+ }
+
+ std::string GetHTMLContents() override {
+ return "<html><head><script>"
+ "window.domAutomationController.setAutomationId(1);"
+ "window.domAutomationController.send(\"okay\");"
+ "</script></head>"
+ "<body>this page is an interstitial</body></html>";
+ }
+
+ std::string last_command() { return last_command_; }
+
+ private:
+ std::string last_command_;
+ DISALLOW_COPY_AND_ASSIGN(SecurityExploitTestInterstitialPage);
+};
+
+// Fails due to InterstitialPage's reliance on PostNonNestableTask
+// http://crbug.com/432737
+#if defined(OS_ANDROID)
+#define MAYBE_InterstitialCommandFromUnderlyingContent \
+ DISABLED_InterstitialCommandFromUnderlyingContent
+#else
+#define MAYBE_InterstitialCommandFromUnderlyingContent \
+ InterstitialCommandFromUnderlyingContent
+#endif
+
+// The interstitial should not be controllable by the underlying content.
+IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest,
+ MAYBE_InterstitialCommandFromUnderlyingContent) {
+ // Start off with initial navigation, to allocate the process.
+ GURL foo("http://foo.com/simple_page.html");
+ NavigateToURL(shell(), foo);
+ EXPECT_EQ(base::ASCIIToUTF16("OK"), shell()->web_contents()->GetTitle());
+
+ DOMMessageQueue message_queue;
+
+ // Install and show an interstitial page.
+ SecurityExploitTestInterstitialPage* interstitial =
+ new SecurityExploitTestInterstitialPage(shell()->web_contents());
+
+ ASSERT_EQ("", interstitial->last_command());
+ content::WaitForInterstitialAttach(shell()->web_contents());
+
+ InterstitialPage* interstitial_page =
+ shell()->web_contents()->GetInterstitialPage();
+ ASSERT_TRUE(interstitial_page != NULL);
+ ASSERT_TRUE(shell()->web_contents()->ShowingInterstitialPage());
+ ASSERT_TRUE(interstitial_page->GetDelegateForTesting() == interstitial);
+
+ // The interstitial page ought to be able to send a message.
+ std::string message;
+ ASSERT_TRUE(message_queue.WaitForMessage(&message));
+ ASSERT_EQ("\"okay\"", message);
+ ASSERT_EQ("\"okay\"", interstitial->last_command());
+
+ // Send an automation message from the underlying content and wait for it to
+ // be dispatched on this thread. This message should not be received by the
+ // interstitial.
+ content::RenderFrameHost* compromised_renderer =
+ shell()->web_contents()->GetMainFrame();
+ FrameHostMsg_DomOperationResponse evil(compromised_renderer->GetRoutingID(),
+ "evil", MSG_ROUTING_NONE);
+ IpcSecurityTestUtil::PwnMessageReceived(
+ compromised_renderer->GetProcess()->GetChannel(), evil);
+
+ ASSERT_TRUE(message_queue.WaitForMessage(&message));
+ ASSERT_EQ("evil", message)
+ << "Automation message should be received by WebContents.";
+ ASSERT_EQ("\"okay\"", interstitial->last_command())
+ << "Interstitial should not be affected.";
+
+ // Send a second message from the interstitial page, and make sure that the
+ // "evil" message doesn't arrive in the intervening period.
+ ASSERT_TRUE(content::ExecuteScript(
+ interstitial_page->GetMainFrame(),
+ "window.domAutomationController.send(\"okay2\");"));
+ ASSERT_TRUE(message_queue.WaitForMessage(&message));
+ ASSERT_EQ("\"okay2\"", message);
+ ASSERT_EQ("\"okay2\"", interstitial->last_command());
+}
+
} // namespace content
diff --git a/chromium/content/browser/service_worker/BUILD.gn b/chromium/content/browser/service_worker/BUILD.gn
index 43a2ff1b435..e3f3f916a8e 100644
--- a/chromium/content/browser/service_worker/BUILD.gn
+++ b/chromium/content/browser/service_worker/BUILD.gn
@@ -4,10 +4,8 @@
import("//third_party/protobuf/proto_library.gni")
-proto_library("proto") {
+proto_library("service_worker_proto") {
sources = [
- "service_worker_cache.proto",
"service_worker_database.proto",
]
}
-
diff --git a/chromium/content/browser/service_worker/PRESUBMIT.py b/chromium/content/browser/service_worker/PRESUBMIT.py
new file mode 100644
index 00000000000..928d9fe0512
--- /dev/null
+++ b/chromium/content/browser/service_worker/PRESUBMIT.py
@@ -0,0 +1,14 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Presubmit script for service_worker.
+
+See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
+for more details about the presubmit API built into depot_tools.
+"""
+
+def CheckChangeOnUpload(input_api, output_api):
+ results = []
+ results += input_api.canned_checks.CheckPatchFormatted(input_api, output_api)
+ return results
diff --git a/chromium/content/browser/service_worker/embedded_worker_instance.cc b/chromium/content/browser/service_worker/embedded_worker_instance.cc
index 3eb9bda1c5f..fd09125c13f 100644
--- a/chromium/content/browser/service_worker/embedded_worker_instance.cc
+++ b/chromium/content/browser/service_worker/embedded_worker_instance.cc
@@ -8,10 +8,13 @@
#include <utility>
#include "base/bind_helpers.h"
-#include "base/debug/trace_event.h"
-#include "content/browser/devtools/embedded_worker_devtools_manager.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/threading/non_thread_safe.h"
+#include "base/trace_event/trace_event.h"
+#include "content/browser/devtools/service_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/content_switches_internal.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"
@@ -31,62 +34,44 @@ struct SecondGreater {
}
};
-void NotifyWorkerReadyForInspection(int worker_process_id,
- int worker_route_id) {
- if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
- BrowserThread::PostTask(BrowserThread::UI,
- FROM_HERE,
- base::Bind(NotifyWorkerReadyForInspection,
- worker_process_id,
- worker_route_id));
- return;
- }
- EmbeddedWorkerDevToolsManager::GetInstance()->WorkerReadyForInspection(
+void NotifyWorkerReadyForInspectionOnUI(int worker_process_id,
+ int worker_route_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ ServiceWorkerDevToolsManager::GetInstance()->WorkerReadyForInspection(
worker_process_id, worker_route_id);
}
-void NotifyWorkerDestroyed(int worker_process_id, int worker_route_id) {
- if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(NotifyWorkerDestroyed, worker_process_id, worker_route_id));
- return;
- }
- EmbeddedWorkerDevToolsManager::GetInstance()->WorkerDestroyed(
+void NotifyWorkerDestroyedOnUI(int worker_process_id, int worker_route_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ ServiceWorkerDevToolsManager::GetInstance()->WorkerDestroyed(
worker_process_id, worker_route_id);
}
-void RegisterToWorkerDevToolsManager(
+void NotifyWorkerStopIgnoredOnUI(int worker_process_id, int worker_route_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ ServiceWorkerDevToolsManager::GetInstance()->WorkerStopIgnored(
+ worker_process_id, worker_route_id);
+}
+
+void RegisterToWorkerDevToolsManagerOnUI(
int process_id,
const ServiceWorkerContextCore* service_worker_context,
- base::WeakPtr<ServiceWorkerContextCore> service_worker_context_weak,
+ const 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 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;
- }
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
int worker_devtools_agent_route_id = MSG_ROUTING_NONE;
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();
wait_for_debugger =
- EmbeddedWorkerDevToolsManager::GetInstance()->ServiceWorkerCreated(
+ ServiceWorkerDevToolsManager::GetInstance()->WorkerCreated(
process_id,
worker_devtools_agent_route_id,
- EmbeddedWorkerDevToolsManager::ServiceWorkerIdentifier(
+ ServiceWorkerDevToolsManager::ServiceWorkerIdentifier(
service_worker_context,
service_worker_context_weak,
service_worker_version_id,
@@ -100,11 +85,49 @@ void RegisterToWorkerDevToolsManager(
} // namespace
+// Lives on IO thread, proxies notifications to DevToolsManager that lives on
+// UI thread. Owned by EmbeddedWorkerInstance.
+class EmbeddedWorkerInstance::DevToolsProxy : public base::NonThreadSafe {
+ public:
+ DevToolsProxy(int process_id, int agent_route_id)
+ : process_id_(process_id),
+ agent_route_id_(agent_route_id) {}
+
+ ~DevToolsProxy() {
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(NotifyWorkerDestroyedOnUI,
+ process_id_, agent_route_id_));
+ }
+
+ void NotifyWorkerReadyForInspection() {
+ DCHECK(CalledOnValidThread());
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(NotifyWorkerReadyForInspectionOnUI,
+ process_id_, agent_route_id_));
+ }
+
+ void NotifyWorkerStopIgnored() {
+ DCHECK(CalledOnValidThread());
+ BrowserThread::PostTask(BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(NotifyWorkerStopIgnoredOnUI,
+ process_id_, agent_route_id_));
+ }
+
+ int agent_route_id() const { return agent_route_id_; }
+
+ private:
+ const int process_id_;
+ const int agent_route_id_;
+ DISALLOW_COPY_AND_ASSIGN(DevToolsProxy);
+};
+
EmbeddedWorkerInstance::~EmbeddedWorkerInstance() {
if (status_ == STARTING || status_ == RUNNING)
Stop();
- if (worker_devtools_agent_route_id_ != MSG_ROUTING_NONE)
- NotifyWorkerDestroyed(process_id_, worker_devtools_agent_route_id_);
+ devtools_proxy_.reset();
if (context_ && process_id_ != -1)
context_->process_manager()->ReleaseWorkerProcess(embedded_worker_id_);
registry_->RemoveWorker(process_id_, embedded_worker_id_);
@@ -120,7 +143,11 @@ void EmbeddedWorkerInstance::Start(int64 service_worker_version_id,
return;
}
DCHECK(status_ == STOPPED);
+ start_timing_ = base::TimeTicks::Now();
status_ = STARTING;
+ starting_phase_ = ALLOCATING_PROCESS;
+ network_accessed_for_script_ = false;
+ FOR_EACH_OBSERVER(Listener, listener_list_, OnStarting());
scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params(
new EmbeddedWorkerMsg_StartWorker_Params());
TRACE_EVENT_ASYNC_BEGIN2("ServiceWorker",
@@ -135,6 +162,7 @@ void EmbeddedWorkerInstance::Start(int64 service_worker_version_id,
params->worker_devtools_agent_route_id = MSG_ROUTING_NONE;
params->pause_after_download = pause_after_download;
params->wait_for_debugger = false;
+ params->v8_cache_options = GetV8CacheOptions();
context_->process_manager()->AllocateWorkerProcess(
embedded_worker_id_,
scope,
@@ -147,14 +175,25 @@ void EmbeddedWorkerInstance::Start(int64 service_worker_version_id,
}
ServiceWorkerStatusCode EmbeddedWorkerInstance::Stop() {
- DCHECK(status_ == STARTING || status_ == RUNNING);
+ DCHECK(status_ == STARTING || status_ == RUNNING) << status_;
ServiceWorkerStatusCode status =
registry_->StopWorker(process_id_, embedded_worker_id_);
- if (status == SERVICE_WORKER_OK)
+ if (status == SERVICE_WORKER_OK) {
status_ = STOPPING;
+ FOR_EACH_OBSERVER(Listener, listener_list_, OnStopping());
+ }
return status;
}
+void EmbeddedWorkerInstance::StopIfIdle() {
+ if (devtools_attached_) {
+ if (devtools_proxy_)
+ devtools_proxy_->NotifyWorkerStopIgnored();
+ return;
+ }
+ Stop();
+}
+
void EmbeddedWorkerInstance::ResumeAfterDownload() {
DCHECK_EQ(STARTING, status_);
registry_->Send(
@@ -179,9 +218,11 @@ EmbeddedWorkerInstance::EmbeddedWorkerInstance(
registry_(context->embedded_worker_registry()),
embedded_worker_id_(embedded_worker_id),
status_(STOPPED),
+ starting_phase_(NOT_STARTING),
process_id_(-1),
thread_id_(kInvalidEmbeddedWorkerThreadId),
- worker_devtools_agent_route_id_(MSG_ROUTING_NONE),
+ devtools_attached_(false),
+ network_accessed_for_script_(false),
weak_factory_(this) {
}
@@ -220,23 +261,32 @@ void EmbeddedWorkerInstance::ProcessAllocated(
params.get(),
"Status", status);
if (status != SERVICE_WORKER_OK) {
+ Status old_status = status_;
status_ = STOPPED;
callback.Run(status);
+ FOR_EACH_OBSERVER(Listener, listener_list_, OnStopped(old_status));
return;
}
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),
- callback));
+
+ // Register this worker to DevToolsManager on UI thread, then continue to
+ // call SendStartWorker on IO thread.
+ starting_phase_ = REGISTERING_TO_DEVTOOLS;
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(RegisterToWorkerDevToolsManagerOnUI,
+ process_id_,
+ context_.get(),
+ context_,
+ service_worker_version_id,
+ script_url,
+ base::Bind(&EmbeddedWorkerInstance::SendStartWorker,
+ weak_factory_.GetWeakPtr(),
+ base::Passed(&params),
+ callback)));
}
void EmbeddedWorkerInstance::SendStartWorker(
@@ -244,9 +294,27 @@ void EmbeddedWorkerInstance::SendStartWorker(
const StatusCallback& callback,
int worker_devtools_agent_route_id,
bool wait_for_debugger) {
- worker_devtools_agent_route_id_ = worker_devtools_agent_route_id;
+ if (worker_devtools_agent_route_id != MSG_ROUTING_NONE) {
+ DCHECK(!devtools_proxy_);
+ devtools_proxy_.reset(new DevToolsProxy(process_id_,
+ worker_devtools_agent_route_id));
+ }
params->worker_devtools_agent_route_id = worker_devtools_agent_route_id;
params->wait_for_debugger = wait_for_debugger;
+ if (params->pause_after_download || params->wait_for_debugger) {
+ // We don't measure the start time when pause_after_download or
+ // wait_for_debugger flag is set. So we set the NULL time here.
+ start_timing_ = base::TimeTicks();
+ } else {
+ DCHECK(!start_timing_.is_null());
+ UMA_HISTOGRAM_TIMES("EmbeddedWorkerInstance.ProcessAllocation",
+ base::TimeTicks::Now() - start_timing_);
+ // Reset |start_timing_| to measure the time excluding the process
+ // allocation time.
+ start_timing_ = base::TimeTicks::Now();
+ }
+
+ starting_phase_ = SENT_START_WORKER;
ServiceWorkerStatusCode status =
registry_->SendStartWorker(params.Pass(), process_id_);
if (status != SERVICE_WORKER_OK) {
@@ -258,22 +326,44 @@ void EmbeddedWorkerInstance::SendStartWorker(
}
void EmbeddedWorkerInstance::OnReadyForInspection() {
- if (worker_devtools_agent_route_id_ != MSG_ROUTING_NONE)
- NotifyWorkerReadyForInspection(process_id_,
- worker_devtools_agent_route_id_);
+ if (devtools_proxy_)
+ devtools_proxy_->NotifyWorkerReadyForInspection();
}
void EmbeddedWorkerInstance::OnScriptLoaded(int thread_id) {
+ starting_phase_ = SCRIPT_LOADED;
+ if (!start_timing_.is_null()) {
+ if (network_accessed_for_script_) {
+ UMA_HISTOGRAM_TIMES("EmbeddedWorkerInstance.ScriptLoadWithNetworkAccess",
+ base::TimeTicks::Now() - start_timing_);
+ } else {
+ UMA_HISTOGRAM_TIMES(
+ "EmbeddedWorkerInstance.ScriptLoadWithoutNetworkAccess",
+ base::TimeTicks::Now() - start_timing_);
+ }
+ // Reset |start_timing_| to measure the time excluding the process
+ // allocation time and the script loading time.
+ start_timing_ = base::TimeTicks::Now();
+ }
thread_id_ = thread_id;
+ FOR_EACH_OBSERVER(Listener, listener_list_, OnScriptLoaded());
}
void EmbeddedWorkerInstance::OnScriptLoadFailed() {
}
void EmbeddedWorkerInstance::OnScriptEvaluated(bool success) {
- DCHECK(!start_callback_.is_null());
+ starting_phase_ = SCRIPT_EVALUATED;
+ if (start_callback_.is_null()) {
+ DVLOG(1) << "Received unexpected OnScriptEvaluated message.";
+ return;
+ }
+ if (success && !start_timing_.is_null()) {
+ UMA_HISTOGRAM_TIMES("EmbeddedWorkerInstance.ScriptEvaluate",
+ base::TimeTicks::Now() - start_timing_);
+ }
start_callback_.Run(success ? SERVICE_WORKER_OK
- : SERVICE_WORKER_ERROR_START_WORKER_FAILED);
+ : SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED);
start_callback_.Reset();
}
@@ -287,16 +377,15 @@ void EmbeddedWorkerInstance::OnStarted() {
}
void EmbeddedWorkerInstance::OnStopped() {
- if (worker_devtools_agent_route_id_ != MSG_ROUTING_NONE)
- NotifyWorkerDestroyed(process_id_, worker_devtools_agent_route_id_);
+ devtools_proxy_.reset();
if (context_)
context_->process_manager()->ReleaseWorkerProcess(embedded_worker_id_);
+ Status old_status = status_;
status_ = STOPPED;
process_id_ = -1;
thread_id_ = -1;
- worker_devtools_agent_route_id_ = MSG_ROUTING_NONE;
start_callback_.Reset();
- FOR_EACH_OBSERVER(Listener, listener_list_, OnStopped());
+ FOR_EACH_OBSERVER(Listener, listener_list_, OnStopped(old_status));
}
void EmbeddedWorkerInstance::OnPausedAfterDownload() {
@@ -308,7 +397,7 @@ void EmbeddedWorkerInstance::OnPausedAfterDownload() {
}
bool EmbeddedWorkerInstance::OnMessageReceived(const IPC::Message& message) {
- ListenerList::Iterator it(listener_list_);
+ ListenerList::Iterator it(&listener_list_);
while (Listener* listener = it.GetNext()) {
if (listener->OnMessageReceived(message))
return true;
@@ -340,6 +429,17 @@ void EmbeddedWorkerInstance::OnReportConsoleMessage(
source_identifier, message_level, message, line_number, source_url));
}
+int EmbeddedWorkerInstance::worker_devtools_agent_route_id() const {
+ if (devtools_proxy_)
+ return devtools_proxy_->agent_route_id();
+ return MSG_ROUTING_NONE;
+}
+
+MessagePortMessageFilter* EmbeddedWorkerInstance::message_port_message_filter()
+ const {
+ return registry_->MessagePortMessageFilterForProcess(process_id_);
+}
+
void EmbeddedWorkerInstance::AddListener(Listener* listener) {
listener_list_.AddObserver(listener);
}
@@ -348,4 +448,49 @@ void EmbeddedWorkerInstance::RemoveListener(Listener* listener) {
listener_list_.RemoveObserver(listener);
}
+void EmbeddedWorkerInstance::OnNetworkAccessedForScriptLoad() {
+ starting_phase_ = SCRIPT_DOWNLOADING;
+ network_accessed_for_script_ = true;
+}
+
+// static
+std::string EmbeddedWorkerInstance::StatusToString(Status status) {
+ switch (status) {
+ case STOPPED:
+ return "STOPPED";
+ case STARTING:
+ return "STARTING";
+ case RUNNING:
+ return "RUNNING";
+ case STOPPING:
+ return "STOPPING";
+ }
+ NOTREACHED() << status;
+ return std::string();
+}
+
+// static
+std::string EmbeddedWorkerInstance::StartingPhaseToString(StartingPhase phase) {
+ switch (phase) {
+ case NOT_STARTING:
+ return "Not in STARTING status";
+ case ALLOCATING_PROCESS:
+ return "Allocating process";
+ case REGISTERING_TO_DEVTOOLS:
+ return "Registering to DevTools";
+ case SENT_START_WORKER:
+ return "Sent StartWorker message to renderer";
+ case SCRIPT_DOWNLOADING:
+ return "Script downloading";
+ case SCRIPT_LOADED:
+ return "Script loaded";
+ case SCRIPT_EVALUATED:
+ return "Script evaluated";
+ case STARTING_PHASE_MAX_VALUE:
+ NOTREACHED();
+ }
+ NOTREACHED() << phase;
+ return std::string();
+}
+
} // 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 75813248ff6..04ce412ad22 100644
--- a/chromium/content/browser/service_worker/embedded_worker_instance.h
+++ b/chromium/content/browser/service_worker/embedded_worker_instance.h
@@ -17,10 +17,16 @@
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/strings/string16.h"
+#include "base/time/time.h"
#include "content/common/content_export.h"
#include "content/common/service_worker/service_worker_status_code.h"
#include "url/gurl.h"
+// Windows headers will redefine SendMessage.
+#ifdef SendMessage
+#undef SendMessage
+#endif
+
struct EmbeddedWorkerMsg_StartWorker_Params;
namespace IPC {
@@ -30,6 +36,7 @@ class Message;
namespace content {
class EmbeddedWorkerRegistry;
+class MessagePortMessageFilter;
class ServiceWorkerContextCore;
struct ServiceWorkerFetchRequest;
@@ -46,11 +53,27 @@ class CONTENT_EXPORT EmbeddedWorkerInstance {
STOPPING,
};
+ // This enum is used in UMA histograms, so don't change the order or remove
+ // entries.
+ enum StartingPhase {
+ NOT_STARTING,
+ ALLOCATING_PROCESS,
+ REGISTERING_TO_DEVTOOLS,
+ SENT_START_WORKER,
+ SCRIPT_DOWNLOADING,
+ SCRIPT_LOADED,
+ SCRIPT_EVALUATED,
+ STARTING_PHASE_MAX_VALUE,
+ };
+
class Listener {
public:
virtual ~Listener() {}
+ virtual void OnScriptLoaded() {}
+ virtual void OnStarting() {}
virtual void OnStarted() {}
- virtual void OnStopped() {}
+ virtual void OnStopping() {}
+ virtual void OnStopped(Status old_status) {}
virtual void OnPausedAfterDownload() {}
virtual void OnReportException(const base::string16& error_message,
int line_number,
@@ -70,9 +93,8 @@ class CONTENT_EXPORT EmbeddedWorkerInstance {
~EmbeddedWorkerInstance();
// Starts the worker. It is invalid to call this when the worker is not in
- // STOPPED status. |callback| is invoked when the worker's process is created
- // if necessary and the IPC to evaluate the worker's script is sent.
- // Observer::OnStarted() is run when the worker is actually started.
+ // STOPPED status. |callback| is invoked after the worker script has been
+ // started and evaluated, or when an error occurs.
void Start(int64 service_worker_version_id,
const GURL& scope,
const GURL& script_url,
@@ -85,26 +107,44 @@ class CONTENT_EXPORT EmbeddedWorkerInstance {
// IPC couldn't be sent to the worker.
ServiceWorkerStatusCode Stop();
+ // Stops the worker if the worker is not being debugged (i.e. devtools is
+ // not attached). This method is called by a stop-worker timer to kill
+ // idle workers.
+ void StopIfIdle();
+
// Sends |message| to the embedded worker running in the child process.
- // It is invalid to call this while the worker is not in RUNNING status.
+ // It is invalid to call this while the worker is not in STARTING or RUNNING
+ // status.
ServiceWorkerStatusCode SendMessage(const IPC::Message& message);
void ResumeAfterDownload();
int embedded_worker_id() const { return embedded_worker_id_; }
Status status() const { return status_; }
+ StartingPhase starting_phase() const {
+ DCHECK_EQ(STARTING, status());
+ return starting_phase_;
+ }
int process_id() const { return process_id_; }
int thread_id() const { return thread_id_; }
- int worker_devtools_agent_route_id() const {
- return worker_devtools_agent_route_id_;
- }
+ int worker_devtools_agent_route_id() const;
+ MessagePortMessageFilter* message_port_message_filter() const;
void AddListener(Listener* listener);
void RemoveListener(Listener* listener);
+ void set_devtools_attached(bool attached) { devtools_attached_ = attached; }
+ bool devtools_attached() const { return devtools_attached_; }
+
+ // Called when the script load request accessed the network.
+ void OnNetworkAccessedForScriptLoad();
+
+ static std::string StatusToString(Status status);
+ static std::string StartingPhaseToString(StartingPhase phase);
+
private:
typedef ObserverList<Listener> ListenerList;
-
+ class DevToolsProxy;
friend class EmbeddedWorkerRegistry;
FRIEND_TEST_ALL_PREFIXES(EmbeddedWorkerInstanceTest, StartAndStop);
@@ -146,11 +186,12 @@ class CONTENT_EXPORT EmbeddedWorkerInstance {
void OnScriptLoadFailed();
// Called back from Registry when the worker instance has ack'ed that
- // it finished evaluating the script.
+ // it finished evaluating the script. This is called before OnStarted.
void OnScriptEvaluated(bool success);
- // Called back from Registry when the worker instance has ack'ed that
- // its WorkerGlobalScope is actually started and parsed.
+ // Called back from Registry when the worker instance has ack'ed that its
+ // WorkerGlobalScope has actually started and evaluated the script. This is
+ // called after OnScriptEvaluated.
// This will change the internal status from STARTING to RUNNING.
void OnStarted();
@@ -184,15 +225,24 @@ class CONTENT_EXPORT EmbeddedWorkerInstance {
scoped_refptr<EmbeddedWorkerRegistry> registry_;
const int embedded_worker_id_;
Status status_;
+ StartingPhase starting_phase_;
// Current running information. -1 indicates the worker is not running.
int process_id_;
int thread_id_;
- int worker_devtools_agent_route_id_;
- StatusCallback start_callback_;
+ // Whether devtools is attached or not.
+ bool devtools_attached_;
+ // True if the script load request accessed the network. If the script was
+ // served from HTTPCache or ServiceWorkerDatabase this value is false.
+ bool network_accessed_for_script_;
+
+ StatusCallback start_callback_;
ListenerList listener_list_;
+ scoped_ptr<DevToolsProxy> devtools_proxy_;
+
+ base::TimeTicks start_timing_;
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 c5f190eef42..fffd891a7cc 100644
--- a/chromium/content/browser/service_worker/embedded_worker_instance_unittest.cc
+++ b/chromium/content/browser/service_worker/embedded_worker_instance_unittest.cc
@@ -17,7 +17,18 @@
namespace content {
-static const int kRenderProcessId = 11;
+namespace {
+
+const int kRenderProcessId = 11;
+
+void SaveStatusAndCall(ServiceWorkerStatusCode* out,
+ const base::Closure& callback,
+ ServiceWorkerStatusCode status) {
+ *out = status;
+ callback.Run();
+}
+
+} // namespace
class EmbeddedWorkerInstanceTest : public testing::Test {
protected:
@@ -25,11 +36,24 @@ class EmbeddedWorkerInstanceTest : public testing::Test {
: thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
void SetUp() override {
- helper_.reset(new EmbeddedWorkerTestHelper(kRenderProcessId));
+ helper_.reset(
+ new EmbeddedWorkerTestHelper(base::FilePath(), kRenderProcessId));
}
void TearDown() override { helper_.reset(); }
+ ServiceWorkerStatusCode StartWorker(EmbeddedWorkerInstance* worker,
+ int id, const GURL& pattern,
+ const GURL& url) {
+ ServiceWorkerStatusCode status;
+ base::RunLoop run_loop;
+ worker->Start(id, pattern, url, false,
+ base::Bind(&SaveStatusAndCall, &status,
+ run_loop.QuitClosure()));
+ run_loop.Run();
+ return status;
+ }
+
ServiceWorkerContextCore* context() { return helper_->context(); }
EmbeddedWorkerRegistry* embedded_worker_registry() {
@@ -46,13 +70,6 @@ class EmbeddedWorkerInstanceTest : public testing::Test {
DISALLOW_COPY_AND_ASSIGN(EmbeddedWorkerInstanceTest);
};
-static void SaveStatusAndCall(ServiceWorkerStatusCode* out,
- const base::Closure& callback,
- ServiceWorkerStatusCode status) {
- *out = status;
- callback.Run();
-}
-
TEST_F(EmbeddedWorkerInstanceTest, StartAndStop) {
scoped_ptr<EmbeddedWorkerInstance> worker =
embedded_worker_registry()->CreateWorker();
@@ -99,6 +116,50 @@ TEST_F(EmbeddedWorkerInstanceTest, StartAndStop) {
EmbeddedWorkerMsg_StopWorker::ID));
}
+TEST_F(EmbeddedWorkerInstanceTest, StopWhenDevToolsAttached) {
+ scoped_ptr<EmbeddedWorkerInstance> worker =
+ embedded_worker_registry()->CreateWorker();
+ EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status());
+
+ const int64 service_worker_version_id = 55L;
+ const GURL pattern("http://example.com/");
+ const GURL url("http://example.com/worker.js");
+
+ // Simulate adding one process to the pattern.
+ helper_->SimulateAddProcessToPattern(pattern, kRenderProcessId);
+
+ // Start the worker and then call StopIfIdle().
+ EXPECT_EQ(SERVICE_WORKER_OK,
+ StartWorker(worker.get(), service_worker_version_id, pattern, url));
+ EXPECT_EQ(EmbeddedWorkerInstance::RUNNING, worker->status());
+ EXPECT_EQ(kRenderProcessId, worker->process_id());
+ worker->StopIfIdle();
+ EXPECT_EQ(EmbeddedWorkerInstance::STOPPING, worker->status());
+ base::RunLoop().RunUntilIdle();
+
+ // The worker must be stopped now.
+ EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status());
+
+ // Set devtools_attached to true, and do the same.
+ worker->set_devtools_attached(true);
+
+ EXPECT_EQ(SERVICE_WORKER_OK,
+ StartWorker(worker.get(), service_worker_version_id, pattern, url));
+ EXPECT_EQ(EmbeddedWorkerInstance::RUNNING, worker->status());
+ EXPECT_EQ(kRenderProcessId, worker->process_id());
+ worker->StopIfIdle();
+ base::RunLoop().RunUntilIdle();
+
+ // The worker must not be stopped this time.
+ EXPECT_EQ(EmbeddedWorkerInstance::RUNNING, worker->status());
+
+ // Calling Stop() actually stops the worker regardless of whether devtools
+ // is attached or not.
+ EXPECT_EQ(SERVICE_WORKER_OK, worker->Stop());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status());
+}
+
TEST_F(EmbeddedWorkerInstanceTest, InstanceDestroyedBeforeStartFinishes) {
scoped_ptr<EmbeddedWorkerInstance> worker =
embedded_worker_registry()->CreateWorker();
diff --git a/chromium/content/browser/service_worker/embedded_worker_registry.cc b/chromium/content/browser/service_worker/embedded_worker_registry.cc
index adf2579d733..0ff12fd8027 100644
--- a/chromium/content/browser/service_worker/embedded_worker_registry.cc
+++ b/chromium/content/browser/service_worker/embedded_worker_registry.cc
@@ -48,13 +48,14 @@ ServiceWorkerStatusCode EmbeddedWorkerRegistry::StopWorker(
new EmbeddedWorkerMsg_StopWorker(embedded_worker_id));
}
-bool EmbeddedWorkerRegistry::OnMessageReceived(const IPC::Message& message) {
+bool EmbeddedWorkerRegistry::OnMessageReceived(const IPC::Message& message,
+ int process_id) {
// TODO(kinuko): Move all EmbeddedWorker message handling from
// ServiceWorkerDispatcherHost.
WorkerInstanceMap::iterator found = worker_map_.find(message.routing_id());
DCHECK(found != worker_map_.end());
- if (found == worker_map_.end())
+ if (found == worker_map_.end() || found->second->process_id() != process_id)
return false;
return found->second->OnMessageReceived(message);
}
@@ -182,13 +183,18 @@ void EmbeddedWorkerRegistry::OnReportConsoleMessage(
}
void EmbeddedWorkerRegistry::AddChildProcessSender(
- int process_id, IPC::Sender* sender) {
+ int process_id,
+ IPC::Sender* sender,
+ MessagePortMessageFilter* message_port_message_filter) {
process_sender_map_[process_id] = sender;
+ process_message_port_message_filter_map_[process_id] =
+ message_port_message_filter;
DCHECK(!ContainsKey(worker_process_map_, process_id));
}
void EmbeddedWorkerRegistry::RemoveChildProcessSender(int process_id) {
process_sender_map_.erase(process_id);
+ process_message_port_message_filter_map_.erase(process_id);
std::map<int, std::set<int> >::iterator found =
worker_process_map_.find(process_id);
if (found != worker_process_map_.end()) {
@@ -220,6 +226,11 @@ bool EmbeddedWorkerRegistry::CanHandle(int embedded_worker_id) const {
return true;
}
+MessagePortMessageFilter*
+EmbeddedWorkerRegistry::MessagePortMessageFilterForProcess(int process_id) {
+ return process_message_port_message_filter_map_[process_id];
+}
+
EmbeddedWorkerRegistry::EmbeddedWorkerRegistry(
const base::WeakPtr<ServiceWorkerContextCore>& context,
int initial_embedded_worker_id)
@@ -235,6 +246,9 @@ EmbeddedWorkerRegistry::~EmbeddedWorkerRegistry() {
ServiceWorkerStatusCode EmbeddedWorkerRegistry::SendStartWorker(
scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params,
int process_id) {
+ if (!context_)
+ return SERVICE_WORKER_ERROR_ABORT;
+
// The ServiceWorkerDispatcherHost is supposed to be created when the process
// is created, and keep an entry in process_sender_map_ for its whole
// lifetime.
diff --git a/chromium/content/browser/service_worker/embedded_worker_registry.h b/chromium/content/browser/service_worker/embedded_worker_registry.h
index 31ed59d0020..f17f1c36392 100644
--- a/chromium/content/browser/service_worker/embedded_worker_registry.h
+++ b/chromium/content/browser/service_worker/embedded_worker_registry.h
@@ -28,6 +28,7 @@ class Sender;
namespace content {
class EmbeddedWorkerInstance;
+class MessagePortMessageFilter;
class ServiceWorkerContextCore;
// Acts as a thin stub between MessageFilter and each EmbeddedWorkerInstance,
@@ -49,7 +50,7 @@ class CONTENT_EXPORT EmbeddedWorkerRegistry
const base::WeakPtr<ServiceWorkerContextCore>& context,
EmbeddedWorkerRegistry* old_registry);
- bool OnMessageReceived(const IPC::Message& message);
+ bool OnMessageReceived(const IPC::Message& message, int process_id);
// Creates and removes a new worker instance entry for bookkeeping.
// This doesn't actually start or stop the worker.
@@ -91,7 +92,10 @@ class CONTENT_EXPORT EmbeddedWorkerRegistry
const GURL& source_url);
// Keeps a map from process_id to sender information.
- void AddChildProcessSender(int process_id, IPC::Sender* sender);
+ void AddChildProcessSender(
+ int process_id,
+ IPC::Sender* sender,
+ MessagePortMessageFilter* message_port_message_filter);
void RemoveChildProcessSender(int process_id);
// Returns an embedded worker instance for given |embedded_worker_id|.
@@ -100,12 +104,16 @@ class CONTENT_EXPORT EmbeddedWorkerRegistry
// Returns true if |embedded_worker_id| is managed by this registry.
bool CanHandle(int embedded_worker_id) const;
+ MessagePortMessageFilter* MessagePortMessageFilterForProcess(int process_id);
+
private:
friend class base::RefCounted<EmbeddedWorkerRegistry>;
friend class EmbeddedWorkerInstance;
typedef std::map<int, EmbeddedWorkerInstance*> WorkerInstanceMap;
typedef std::map<int, IPC::Sender*> ProcessToSenderMap;
+ typedef std::map<int, MessagePortMessageFilter*>
+ ProcessToMessagePortMessageFilterMap;
EmbeddedWorkerRegistry(
const base::WeakPtr<ServiceWorkerContextCore>& context,
@@ -122,6 +130,7 @@ class CONTENT_EXPORT EmbeddedWorkerRegistry
WorkerInstanceMap worker_map_;
ProcessToSenderMap process_sender_map_;
+ ProcessToMessagePortMessageFilterMap process_message_port_message_filter_map_;
// Map from process_id to embedded_worker_id.
// This map only contains starting and running workers.
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 abc0c2b5c88..3e512c1a88f 100644
--- a/chromium/content/browser/service_worker/embedded_worker_test_helper.cc
+++ b/chromium/content/browser/service_worker/embedded_worker_test_helper.cc
@@ -8,6 +8,7 @@
#include <string>
#include "base/bind.h"
+#include "base/thread_task_runner_handle.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"
@@ -18,22 +19,23 @@
namespace content {
-EmbeddedWorkerTestHelper::EmbeddedWorkerTestHelper(int mock_render_process_id)
+EmbeddedWorkerTestHelper::EmbeddedWorkerTestHelper(
+ const base::FilePath& user_data_directory,
+ 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(),
+ base::ThreadTaskRunnerHandle::Get()));
+ wrapper_->InitInternal(user_data_directory,
database_task_manager.Pass(),
- base::MessageLoopProxy::current(),
+ base::ThreadTaskRunnerHandle::Get(),
NULL,
NULL);
wrapper_->process_manager()->SetProcessIdForTest(mock_render_process_id);
- registry()->AddChildProcessSender(mock_render_process_id, this);
+ registry()->AddChildProcessSender(mock_render_process_id, this, nullptr);
}
EmbeddedWorkerTestHelper::~EmbeddedWorkerTestHelper() {
@@ -44,7 +46,7 @@ EmbeddedWorkerTestHelper::~EmbeddedWorkerTestHelper() {
void EmbeddedWorkerTestHelper::SimulateAddProcessToPattern(
const GURL& pattern,
int process_id) {
- registry()->AddChildProcessSender(process_id, this);
+ registry()->AddChildProcessSender(process_id, this, nullptr);
wrapper_->process_manager()->AddProcessReferenceToPattern(
pattern, process_id);
}
@@ -89,11 +91,14 @@ void EmbeddedWorkerTestHelper::OnStartWorker(
const GURL& scope,
const GURL& script_url,
bool pause_after_download) {
+ embedded_worker_id_service_worker_version_id_map_[embedded_worker_id] =
+ service_worker_version_id;
if (pause_after_download) {
SimulatePausedAfterDownload(embedded_worker_id);
return;
}
SimulateWorkerReadyForInspection(embedded_worker_id);
+ SimulateWorkerScriptCached(embedded_worker_id);
SimulateWorkerScriptLoaded(next_thread_id_++, embedded_worker_id);
SimulateWorkerScriptEvaluated(embedded_worker_id);
SimulateWorkerStarted(embedded_worker_id);
@@ -101,6 +106,7 @@ void EmbeddedWorkerTestHelper::OnStartWorker(
void EmbeddedWorkerTestHelper::OnResumeAfterDownload(int embedded_worker_id) {
SimulateWorkerReadyForInspection(embedded_worker_id);
+ SimulateWorkerScriptCached(embedded_worker_id);
SimulateWorkerScriptLoaded(next_thread_id_++, embedded_worker_id);
SimulateWorkerScriptEvaluated(embedded_worker_id);
SimulateWorkerStarted(embedded_worker_id);
@@ -137,8 +143,10 @@ void EmbeddedWorkerTestHelper::OnActivateEvent(int embedded_worker_id,
}
void EmbeddedWorkerTestHelper::OnInstallEvent(int embedded_worker_id,
- int request_id,
- int active_version_id) {
+ int request_id) {
+ // The installing worker may have been doomed and terminated.
+ if (!registry()->GetWorker(embedded_worker_id))
+ return;
SimulateSend(
new ServiceWorkerHostMsg_InstallEventFinished(
embedded_worker_id, request_id,
@@ -153,13 +161,14 @@ void EmbeddedWorkerTestHelper::OnFetchEvent(
embedded_worker_id,
request_id,
SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE,
- ServiceWorkerResponse(GURL(""),
+ ServiceWorkerResponse(GURL(),
200,
"OK",
blink::WebServiceWorkerResponseTypeDefault,
ServiceWorkerHeaderMap(),
std::string(),
- 0)));
+ 0,
+ GURL())));
}
void EmbeddedWorkerTestHelper::SimulatePausedAfterDownload(
@@ -177,6 +186,22 @@ void EmbeddedWorkerTestHelper::SimulateWorkerReadyForInspection(
embedded_worker_id);
}
+void EmbeddedWorkerTestHelper::SimulateWorkerScriptCached(
+ int embedded_worker_id) {
+ int64 version_id =
+ embedded_worker_id_service_worker_version_id_map_[embedded_worker_id];
+ ServiceWorkerVersion* version = context()->GetLiveVersion(version_id);
+ if (!version || version->script_cache_map()->size())
+ return;
+ std::vector<ServiceWorkerDatabase::ResourceRecord> records;
+ // Add a dummy ResourceRecord for the main script to the script cache map of
+ // the ServiceWorkerVersion. We use embedded_worker_id for resource_id to
+ // avoid ID collision.
+ records.push_back(ServiceWorkerDatabase::ResourceRecord(
+ embedded_worker_id, version->script_url(), 100));
+ version->script_cache_map()->SetResources(records);
+}
+
void EmbeddedWorkerTestHelper::SimulateWorkerScriptLoaded(
int thread_id, int embedded_worker_id) {
EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id);
@@ -211,7 +236,7 @@ void EmbeddedWorkerTestHelper::SimulateWorkerStopped(
void EmbeddedWorkerTestHelper::SimulateSend(
IPC::Message* message) {
- registry()->OnMessageReceived(*message);
+ registry()->OnMessageReceived(*message, mock_render_process_id_);
delete message;
}
@@ -221,22 +246,22 @@ void EmbeddedWorkerTestHelper::OnStartWorkerStub(
registry()->GetWorker(params.embedded_worker_id);
ASSERT_TRUE(worker != NULL);
EXPECT_EQ(EmbeddedWorkerInstance::STARTING, worker->status());
- base::MessageLoopProxy::current()->PostTask(
+ base::ThreadTaskRunnerHandle::Get()->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));
+ 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(
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(&EmbeddedWorkerTestHelper::OnResumeAfterDownload,
weak_factory_.GetWeakPtr(),
@@ -246,7 +271,7 @@ void EmbeddedWorkerTestHelper::OnResumeAfterDownloadStub(
void EmbeddedWorkerTestHelper::OnStopWorkerStub(int embedded_worker_id) {
EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id);
ASSERT_TRUE(worker != NULL);
- base::MessageLoopProxy::current()->PostTask(
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(&EmbeddedWorkerTestHelper::OnStopWorker,
weak_factory_.GetWeakPtr(),
@@ -260,7 +285,7 @@ void EmbeddedWorkerTestHelper::OnMessageToWorkerStub(
EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id);
ASSERT_TRUE(worker != NULL);
EXPECT_EQ(worker->thread_id(), thread_id);
- base::MessageLoopProxy::current()->PostTask(
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(
base::IgnoreResult(&EmbeddedWorkerTestHelper::OnMessageToWorker),
@@ -271,7 +296,7 @@ void EmbeddedWorkerTestHelper::OnMessageToWorkerStub(
}
void EmbeddedWorkerTestHelper::OnActivateEventStub(int request_id) {
- base::MessageLoopProxy::current()->PostTask(
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(&EmbeddedWorkerTestHelper::OnActivateEvent,
weak_factory_.GetWeakPtr(),
@@ -279,21 +304,19 @@ void EmbeddedWorkerTestHelper::OnActivateEventStub(int request_id) {
request_id));
}
-void EmbeddedWorkerTestHelper::OnInstallEventStub(int request_id,
- int active_version_id) {
- base::MessageLoopProxy::current()->PostTask(
+void EmbeddedWorkerTestHelper::OnInstallEventStub(int request_id) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(&EmbeddedWorkerTestHelper::OnInstallEvent,
weak_factory_.GetWeakPtr(),
current_embedded_worker_id_,
- request_id,
- active_version_id));
+ request_id));
}
void EmbeddedWorkerTestHelper::OnFetchEventStub(
int request_id,
const ServiceWorkerFetchRequest& request) {
- base::MessageLoopProxy::current()->PostTask(
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(&EmbeddedWorkerTestHelper::OnFetchEvent,
weak_factory_.GetWeakPtr(),
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 6640d853fd6..50df4c01934 100644
--- a/chromium/content/browser/service_worker/embedded_worker_test_helper.h
+++ b/chromium/content/browser/service_worker/embedded_worker_test_helper.h
@@ -44,8 +44,10 @@ class EmbeddedWorkerTestHelper : public IPC::Sender,
public IPC::Listener {
public:
// Initialize this helper for |context|, and enable this as an IPC
- // sender for |mock_render_process_id|.
- explicit EmbeddedWorkerTestHelper(int mock_render_process_id);
+ // sender for |mock_render_process_id|. If |user_data_directory| is empty,
+ // the context makes storage stuff in memory.
+ EmbeddedWorkerTestHelper(const base::FilePath& user_data_directory,
+ int mock_render_process_id);
~EmbeddedWorkerTestHelper() override;
// Call this to simulate add/associate a process to a pattern.
@@ -92,9 +94,7 @@ class EmbeddedWorkerTestHelper : public IPC::Sender,
// worker. By default they just return success via
// SimulateSendReplyToBrowser.
virtual void OnActivateEvent(int embedded_worker_id, int request_id);
- virtual void OnInstallEvent(int embedded_worker_id,
- int request_id,
- int active_version_id);
+ virtual void OnInstallEvent(int embedded_worker_id, int request_id);
virtual void OnFetchEvent(int embedded_worker_id,
int request_id,
const ServiceWorkerFetchRequest& request);
@@ -103,6 +103,7 @@ class EmbeddedWorkerTestHelper : public IPC::Sender,
// browser.
void SimulatePausedAfterDownload(int embedded_worker_id);
void SimulateWorkerReadyForInspection(int embedded_worker_id);
+ void SimulateWorkerScriptCached(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);
@@ -119,7 +120,7 @@ class EmbeddedWorkerTestHelper : public IPC::Sender,
int embedded_worker_id,
const IPC::Message& message);
void OnActivateEventStub(int request_id);
- void OnInstallEventStub(int request_id, int active_version_id);
+ void OnInstallEventStub(int request_id);
void OnFetchEventStub(int request_id,
const ServiceWorkerFetchRequest& request);
@@ -131,6 +132,8 @@ class EmbeddedWorkerTestHelper : public IPC::Sender,
int next_thread_id_;
int mock_render_process_id_;
+ std::map<int, int64> embedded_worker_id_service_worker_version_id_map_;
+
// 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 0a67c102206..03b2041533e 100644
--- a/chromium/content/browser/service_worker/service_worker_browsertest.cc
+++ b/chromium/content/browser/service_worker/service_worker_browsertest.cc
@@ -6,7 +6,9 @@
#include "base/callback.h"
#include "base/command_line.h"
#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.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"
@@ -21,14 +23,19 @@
#include "content/common/service_worker/service_worker_types.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_switches.h"
+#include "content/public/common/referrer.h"
+#include "content/public/common/security_style.h"
+#include "content/public/common/ssl_status.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/shell/browser/shell.h"
+#include "content/shell/browser/shell_content_browser_client.h"
#include "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"
@@ -36,8 +43,8 @@
#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_data_snapshot.h"
#include "storage/browser/blob/blob_storage_context.h"
-#include "storage/common/blob/blob_data.h"
namespace content {
@@ -52,26 +59,35 @@ struct FetchResult {
void RunAndQuit(const base::Closure& closure,
const base::Closure& quit,
- base::MessageLoopProxy* original_message_loop) {
+ base::SingleThreadTaskRunner* original_message_loop) {
closure.Run();
original_message_loop->PostTask(FROM_HERE, quit);
}
-void RunOnIOThread(const base::Closure& closure) {
+void RunOnIOThreadWithDelay(const base::Closure& closure,
+ base::TimeDelta delay) {
base::RunLoop run_loop;
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&RunAndQuit, closure, run_loop.QuitClosure(),
- base::MessageLoopProxy::current()));
+ BrowserThread::PostDelayedTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&RunAndQuit,
+ closure,
+ run_loop.QuitClosure(),
+ base::ThreadTaskRunnerHandle::Get()),
+ delay);
run_loop.Run();
}
+void RunOnIOThread(const base::Closure& closure) {
+ RunOnIOThreadWithDelay(closure, base::TimeDelta());
+}
+
void RunOnIOThread(
const base::Callback<void(const base::Closure& continuation)>& closure) {
base::RunLoop run_loop;
base::Closure quit_on_original_thread =
- base::Bind(base::IgnoreResult(&base::MessageLoopProxy::PostTask),
- base::MessageLoopProxy::current().get(),
+ base::Bind(base::IgnoreResult(&base::SingleThreadTaskRunner::PostTask),
+ base::ThreadTaskRunnerHandle::Get().get(),
FROM_HERE,
run_loop.QuitClosure());
BrowserThread::PostTask(BrowserThread::IO,
@@ -120,12 +136,32 @@ ServiceWorkerVersion::FetchCallback CreateResponseReceiver(
result);
}
+void ReceiveFindRegistrationStatus(
+ BrowserThread::ID run_quit_thread,
+ const base::Closure& quit,
+ ServiceWorkerStatusCode* out_status,
+ ServiceWorkerStatusCode status,
+ const scoped_refptr<ServiceWorkerRegistration>& registration) {
+ *out_status = status;
+ if (!quit.is_null())
+ BrowserThread::PostTask(run_quit_thread, FROM_HERE, quit);
+}
+
+ServiceWorkerStorage::FindRegistrationCallback CreateFindRegistrationReceiver(
+ BrowserThread::ID run_quit_thread,
+ const base::Closure& quit,
+ ServiceWorkerStatusCode* status) {
+ return base::Bind(&ReceiveFindRegistrationStatus, run_quit_thread, quit,
+ status);
+}
+
void ReadResponseBody(std::string* body,
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());
+ scoped_ptr<storage::BlobDataSnapshot> data =
+ blob_data_handle->CreateSnapshot();
+ ASSERT_EQ(1U, data->items().size());
+ *body = std::string(data->items()[0]->bytes(), data->items()[0]->length());
}
void ExpectResultAndRun(bool expected,
@@ -145,10 +181,10 @@ class WorkerActivatedObserver
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);
+ void OnVersionStateChanged(int64 version_id,
+ ServiceWorkerVersion::Status) override {
+ ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ const ServiceWorkerVersion* version = context_->GetLiveVersion(version_id);
if (version->status() == ServiceWorkerVersion::ACTIVATED) {
context_->RemoveObserver(this);
BrowserThread::PostTask(BrowserThread::UI,
@@ -215,7 +251,7 @@ class LongLivedResourceInterceptor : public net::URLRequestInterceptor {
void CreateLongLivedResourceInterceptors(
const GURL& worker_url, const GURL& import_url) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
scoped_ptr<net::URLRequestInterceptor> interceptor;
interceptor.reset(new LongLivedResourceInterceptor(
@@ -236,7 +272,7 @@ void CountScriptResources(
*num_resources = -1;
std::vector<ServiceWorkerRegistrationInfo> infos =
- wrapper->context()->GetAllLiveRegistrationInfo();
+ wrapper->GetAllLiveRegistrationInfo();
if (infos.empty())
return;
@@ -254,8 +290,7 @@ void CountScriptResources(
else
return;
- ServiceWorkerVersion* version =
- wrapper->context()->GetLiveVersion(version_id);
+ ServiceWorkerVersion* version = wrapper->GetLiveVersion(version_id);
*num_resources = static_cast<int>(version->script_cache_map()->size());
}
@@ -263,7 +298,7 @@ void CountScriptResources(
class ServiceWorkerBrowserTest : public ContentBrowserTest {
protected:
- typedef ServiceWorkerBrowserTest self;
+ using self = ServiceWorkerBrowserTest;
void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitch(
@@ -309,7 +344,7 @@ class ServiceWorkerBrowserTest : public ContentBrowserTest {
class EmbeddedWorkerBrowserTest : public ServiceWorkerBrowserTest,
public EmbeddedWorkerInstance::Listener {
public:
- typedef EmbeddedWorkerBrowserTest self;
+ using self = EmbeddedWorkerBrowserTest;
EmbeddedWorkerBrowserTest()
: last_worker_status_(EmbeddedWorkerInstance::STOPPED),
@@ -329,7 +364,6 @@ class EmbeddedWorkerBrowserTest : public ServiceWorkerBrowserTest,
EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker_->status());
worker_->AddListener(this);
-
const int64 service_worker_version_id = 33L;
const GURL pattern = embedded_test_server()->GetURL("/");
const GURL script_url = embedded_test_server()->GetURL(
@@ -376,7 +410,7 @@ class EmbeddedWorkerBrowserTest : public ServiceWorkerBrowserTest,
last_worker_status_ = worker_->status();
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, done_closure_);
}
- void OnStopped() override {
+ void OnStopped(EmbeddedWorkerInstance::Status old_status) override {
ASSERT_TRUE(worker_ != NULL);
ASSERT_FALSE(done_closure_.is_null());
last_worker_status_ = worker_->status();
@@ -415,9 +449,44 @@ class EmbeddedWorkerBrowserTest : public ServiceWorkerBrowserTest,
base::Closure done_closure_;
};
+class ConsoleListener : public EmbeddedWorkerInstance::Listener {
+ public:
+ void OnReportConsoleMessage(int source_identifier,
+ int message_level,
+ const base::string16& message,
+ int line_number,
+ const GURL& source_url) override {
+ messages_.push_back(message);
+ if (!quit_.is_null() && messages_.size() == expected_message_count_) {
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, quit_);
+ quit_.Reset();
+ }
+ }
+
+ void WaitForConsoleMessages(size_t expected_message_count) {
+ if (messages_.size() >= expected_message_count)
+ return;
+
+ expected_message_count_ = expected_message_count;
+ base::RunLoop console_run_loop;
+ quit_ = console_run_loop.QuitClosure();
+ console_run_loop.Run();
+
+ ASSERT_EQ(messages_.size(), expected_message_count);
+ }
+
+ bool OnMessageReceived(const IPC::Message& message) override { return false; }
+ const std::vector<base::string16>& messages() const { return messages_; }
+
+ private:
+ std::vector<base::string16> messages_;
+ size_t expected_message_count_;
+ base::Closure quit_;
+};
+
class ServiceWorkerVersionBrowserTest : public ServiceWorkerBrowserTest {
public:
- typedef ServiceWorkerVersionBrowserTest self;
+ using self = ServiceWorkerVersionBrowserTest;
~ServiceWorkerVersionBrowserTest() override {}
@@ -503,7 +572,8 @@ class ServiceWorkerVersionBrowserTest : public ServiceWorkerBrowserTest {
}
void SetUpRegistrationOnIOThread(const std::string& worker_url) {
- const GURL pattern = embedded_test_server()->GetURL("/");
+ ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ const GURL pattern = embedded_test_server()->GetURL("/service_worker/");
registration_ = new ServiceWorkerRegistration(
pattern,
wrapper()->context()->storage()->NewRegistrationId(),
@@ -513,9 +583,122 @@ class ServiceWorkerVersionBrowserTest : public ServiceWorkerBrowserTest {
embedded_test_server()->GetURL(worker_url),
wrapper()->context()->storage()->NewVersionId(),
wrapper()->context()->AsWeakPtr());
+
+ // Make the registration findable via storage functions.
+ wrapper()->context()->storage()->NotifyInstallingRegistration(
+ registration_.get());
+
AssociateRendererProcessToPattern(pattern);
}
+ void TimeoutWorkerOnIOThread() {
+ ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ version_->PingWorker();
+ version_->OnPingTimeout();
+ }
+
+ void AddControlleeOnIOThread() {
+ ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
+ 33 /* dummy render process id */,
+ MSG_ROUTING_NONE /* render_frame_id */, 1 /* dummy provider_id */,
+ SERVICE_WORKER_PROVIDER_FOR_WINDOW, wrapper()->context()->AsWeakPtr(),
+ NULL));
+ host->SetDocumentUrl(
+ embedded_test_server()->GetURL("/service_worker/host"));
+ host->AssociateRegistration(registration_.get(),
+ false /* notify_controllerchange */);
+ wrapper()->context()->AddProviderHost(host.Pass());
+ }
+
+ void AddWaitingWorkerOnIOThread(const std::string& worker_url) {
+ ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ scoped_refptr<ServiceWorkerVersion> waiting_version(
+ new ServiceWorkerVersion(
+ registration_.get(), embedded_test_server()->GetURL(worker_url),
+ wrapper()->context()->storage()->NewVersionId(),
+ wrapper()->context()->AsWeakPtr()));
+ waiting_version->SetStatus(ServiceWorkerVersion::INSTALLED);
+ registration_->SetWaitingVersion(waiting_version.get());
+ registration_->ActivateWaitingVersionWhenReady();
+ }
+
+ void StartWorker(ServiceWorkerStatusCode expected_status) {
+ ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
+ base::RunLoop start_run_loop;
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(&self::StartOnIOThread, this,
+ start_run_loop.QuitClosure(),
+ &status));
+ start_run_loop.Run();
+ ASSERT_EQ(expected_status, status);
+ }
+
+ void StopWorker(ServiceWorkerStatusCode expected_status) {
+ ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
+ base::RunLoop stop_run_loop;
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(&self::StopOnIOThread, this,
+ stop_run_loop.QuitClosure(),
+ &status));
+ stop_run_loop.Run();
+ ASSERT_EQ(expected_status, status);
+ }
+
+ void StoreRegistration(int64 version_id,
+ ServiceWorkerStatusCode expected_status) {
+ ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
+ base::RunLoop store_run_loop;
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&self::StoreOnIOThread, this, store_run_loop.QuitClosure(),
+ &status, version_id));
+ store_run_loop.Run();
+ ASSERT_EQ(expected_status, status);
+
+ RunOnIOThread(base::Bind(&self::NotifyDoneInstallingRegistrationOnIOThread,
+ this, status));
+ }
+
+ void FindRegistrationForId(int64 id,
+ const GURL& origin,
+ ServiceWorkerStatusCode expected_status) {
+ ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
+ base::RunLoop run_loop;
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&self::FindRegistrationForIdOnIOThread, this,
+ run_loop.QuitClosure(), &status, id, origin));
+ run_loop.Run();
+ ASSERT_EQ(expected_status, status);
+ }
+
+ void FindRegistrationForIdOnIOThread(const base::Closure& done,
+ ServiceWorkerStatusCode* result,
+ int64 id,
+ const GURL& origin) {
+ ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ wrapper()->context()->storage()->FindRegistrationForId(
+ id, origin,
+ CreateFindRegistrationReceiver(BrowserThread::UI, done, result));
+ }
+
+ void NotifyDoneInstallingRegistrationOnIOThread(
+ ServiceWorkerStatusCode status) {
+ ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ wrapper()->context()->storage()->NotifyDoneInstallingRegistration(
+ registration_.get(), version_.get(), status);
+ }
+
+ void RemoveLiveRegistrationOnIOThread(int64 id) {
+ ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ wrapper()->context()->RemoveLiveRegistration(id);
+ }
+
void StartOnIOThread(const base::Closure& done,
ServiceWorkerStatusCode* result) {
ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
@@ -527,13 +710,25 @@ class ServiceWorkerVersionBrowserTest : public ServiceWorkerBrowserTest {
ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
version_->SetStatus(ServiceWorkerVersion::INSTALLING);
version_->DispatchInstallEvent(
- -1, CreateReceiver(BrowserThread::UI, done, result));
+ CreateReceiver(BrowserThread::UI, done, result));
+ }
+
+ void StoreOnIOThread(const base::Closure& done,
+ ServiceWorkerStatusCode* result,
+ int64 version_id) {
+ ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ ServiceWorkerVersion* version =
+ wrapper()->context()->GetLiveVersion(version_id);
+ wrapper()->context()->storage()->StoreRegistration(
+ registration_.get(), version,
+ CreateReceiver(BrowserThread::UI, done, result));
}
void ActivateOnIOThread(const base::Closure& done,
ServiceWorkerStatusCode* result) {
ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
version_->SetStatus(ServiceWorkerVersion::ACTIVATING);
+ registration_->SetActiveVersion(version_.get());
version_->DispatchActivateEvent(
CreateReceiver(BrowserThread::UI, done, result));
}
@@ -546,7 +741,7 @@ class ServiceWorkerVersionBrowserTest : public ServiceWorkerBrowserTest {
embedded_test_server()->GetURL("/service_worker/empty.html"),
"GET",
ServiceWorkerHeaderMap(),
- GURL(""),
+ Referrer(),
false);
version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
version_->DispatchFetchEvent(
@@ -647,14 +842,80 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, StartNotFound) {
"/service_worker/nonexistent.js"));
// Start a worker for nonexistent URL.
+ StartWorker(SERVICE_WORKER_ERROR_NETWORK);
+}
+
+IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, ReadResourceFailure) {
+ // Create a registration.
+ RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
+ "/service_worker/worker.js"));
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
+
+ // Add a non-existent resource to the version.
+ std::vector<ServiceWorkerDatabase::ResourceRecord> records;
+ records.push_back(
+ ServiceWorkerDatabase::ResourceRecord(30, version_->script_url(), 100));
+ version_->script_cache_map()->SetResources(records);
+
+ // Store the registration.
+ StoreRegistration(version_->version_id(), SERVICE_WORKER_OK);
+
+ // Start the worker. We'll fail to read the resource.
+ StartWorker(SERVICE_WORKER_ERROR_DISK_CACHE);
+ EXPECT_EQ(ServiceWorkerVersion::REDUNDANT, version_->status());
+
+ // The registration should be deleted from storage since the broken worker was
+ // the stored one.
+ RunOnIOThread(base::Bind(&self::RemoveLiveRegistrationOnIOThread, this,
+ registration_->id()));
+ FindRegistrationForId(registration_->id(),
+ registration_->pattern().GetOrigin(),
+ SERVICE_WORKER_ERROR_NOT_FOUND);
+}
+
+IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
+ ReadResourceFailure_WaitingWorker) {
+ // Create a registration and active version.
+ RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
+ "/service_worker/worker.js"));
+ base::RunLoop activate_run_loop;
ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
- base::RunLoop start_run_loop;
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
- base::Bind(&self::StartOnIOThread, this,
- start_run_loop.QuitClosure(),
- &status));
- start_run_loop.Run();
- ASSERT_EQ(SERVICE_WORKER_ERROR_START_WORKER_FAILED, status);
+ base::Bind(&self::ActivateOnIOThread, this,
+ activate_run_loop.QuitClosure(), &status));
+ activate_run_loop.Run();
+ EXPECT_EQ(SERVICE_WORKER_OK, status);
+ ASSERT_TRUE(registration_->active_version());
+
+ // Give the version a controllee.
+ RunOnIOThread(base::Bind(&self::AddControlleeOnIOThread, this));
+
+ // Add a non-existent resource to the version.
+ std::vector<ServiceWorkerDatabase::ResourceRecord> records;
+ records.push_back(
+ ServiceWorkerDatabase::ResourceRecord(30, version_->script_url(), 100));
+ version_->script_cache_map()->SetResources(records);
+
+ // Make a waiting version and store it.
+ RunOnIOThread(base::Bind(&self::AddWaitingWorkerOnIOThread, this,
+ "/service_worker/worker.js"));
+ registration_->waiting_version()->script_cache_map()->SetResources(records);
+ StoreRegistration(registration_->waiting_version()->version_id(),
+ SERVICE_WORKER_OK);
+
+ // Start the broken worker. We'll fail to read from disk and the worker should
+ // be doomed.
+ StopWorker(SERVICE_WORKER_OK); // in case it's already running
+ StartWorker(SERVICE_WORKER_ERROR_DISK_CACHE);
+ EXPECT_EQ(ServiceWorkerVersion::REDUNDANT, version_->status());
+
+ // The registration should still be in storage since the waiting worker was
+ // the stored one.
+ RunOnIOThread(base::Bind(&self::RemoveLiveRegistrationOnIOThread, this,
+ registration_->id()));
+ FindRegistrationForId(registration_->id(),
+ registration_->pattern().GetOrigin(),
+ SERVICE_WORKER_OK);
}
IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, Install) {
@@ -693,6 +954,103 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED);
}
+IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
+ InstallWithWaitUntil_RejectConsoleMessage) {
+ RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
+ "/service_worker/worker_install_rejected.js"));
+
+ ConsoleListener console_listener;
+ version_->embedded_worker()->AddListener(&console_listener);
+
+ // Dispatch install on a worker.
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
+ base::RunLoop install_run_loop;
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(&self::InstallOnIOThread, this,
+ install_run_loop.QuitClosure(), &status));
+ install_run_loop.Run();
+ ASSERT_EQ(SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED, status);
+
+ const base::string16 expected =
+ base::ASCIIToUTF16("Rejecting oninstall event");
+ console_listener.WaitForConsoleMessages(1);
+ ASSERT_NE(base::string16::npos,
+ console_listener.messages()[0].find(expected));
+ version_->embedded_worker()->RemoveListener(&console_listener);
+}
+
+class WaitForLoaded : public EmbeddedWorkerInstance::Listener {
+ public:
+ WaitForLoaded(const base::Closure& quit) : quit_(quit) {}
+
+ void OnScriptLoaded() override {
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, quit_);
+ }
+ bool OnMessageReceived(const IPC::Message& message) override { return false; }
+
+ private:
+ base::Closure quit_;
+};
+
+IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, TimeoutStartingWorker) {
+ RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
+ "/service_worker/while_true_worker.js"));
+
+ // Start a worker, waiting until the script is loaded.
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
+ base::RunLoop start_run_loop;
+ base::RunLoop load_run_loop;
+ WaitForLoaded wait_for_load(load_run_loop.QuitClosure());
+ version_->embedded_worker()->AddListener(&wait_for_load);
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(&self::StartOnIOThread, this,
+ start_run_loop.QuitClosure(), &status));
+ load_run_loop.Run();
+ version_->embedded_worker()->RemoveListener(&wait_for_load);
+
+ // The script has loaded but start has not completed yet.
+ ASSERT_EQ(SERVICE_WORKER_ERROR_FAILED, status);
+ EXPECT_EQ(ServiceWorkerVersion::STARTING, version_->running_status());
+
+ // Simulate execution timeout. Use a delay to prevent killing the worker
+ // before it's started execution.
+ EXPECT_TRUE(version_->timeout_timer_.IsRunning());
+ RunOnIOThreadWithDelay(base::Bind(&self::TimeoutWorkerOnIOThread, this),
+ base::TimeDelta::FromMilliseconds(100));
+ start_run_loop.Run();
+
+ EXPECT_EQ(SERVICE_WORKER_ERROR_TIMEOUT, status);
+}
+
+IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, TimeoutWorkerInEvent) {
+ RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
+ "/service_worker/while_true_in_install_worker.js"));
+
+ // Start a worker.
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
+ base::RunLoop start_run_loop;
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(&self::StartOnIOThread, this,
+ start_run_loop.QuitClosure(), &status));
+ start_run_loop.Run();
+ ASSERT_EQ(SERVICE_WORKER_OK, status);
+
+ // Dispatch an event.
+ base::RunLoop install_run_loop;
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(&self::InstallOnIOThread, this,
+ install_run_loop.QuitClosure(), &status));
+
+ // Simulate execution timeout. Use a delay to prevent killing the worker
+ // before it's started execution.
+ EXPECT_TRUE(version_->timeout_timer_.IsRunning());
+ RunOnIOThreadWithDelay(base::Bind(&self::TimeoutWorkerOnIOThread, this),
+ base::TimeDelta::FromMilliseconds(100));
+ install_run_loop.Run();
+
+ EXPECT_EQ(SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED, status);
+}
+
IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, FetchEvent_Response) {
ServiceWorkerFetchEventResult result;
ServiceWorkerResponse response;
@@ -715,6 +1073,32 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, FetchEvent_Response) {
}
IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
+ FetchEvent_respondWithRejection) {
+ ServiceWorkerFetchEventResult result;
+ ServiceWorkerResponse response;
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle;
+
+ RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
+ "/service_worker/fetch_event_rejected.js"));
+
+ ConsoleListener console_listener;
+ version_->embedded_worker()->AddListener(&console_listener);
+
+ FetchOnRegisteredWorker(&result, &response, &blob_data_handle);
+ const base::string16 expected =
+ base::ASCIIToUTF16("Rejecting respondWith promise");
+ console_listener.WaitForConsoleMessages(1);
+ ASSERT_NE(base::string16::npos,
+ console_listener.messages()[0].find(expected));
+ version_->embedded_worker()->RemoveListener(&console_listener);
+
+ ASSERT_EQ(SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE, result);
+ EXPECT_EQ(0, response.status_code);
+
+ ASSERT_FALSE(blob_data_handle);
+}
+
+IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
SyncAbortedWithoutFlag) {
RunOnIOThread(base::Bind(
&self::SetUpRegistrationOnIOThread, this, "/service_worker/sync.js"));
@@ -763,45 +1147,110 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, SyncEventHandled) {
}
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());
- }
+ const char kPageUrl[] = "/service_worker/reload.html";
+ const char 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 title1 = base::ASCIIToUTF16("reload=false");
+ TitleWatcher title_watcher1(shell()->web_contents(), title1);
+ NavigateToURL(shell(), embedded_test_server()->GetURL(kPageUrl));
+ EXPECT_EQ(title1, title_watcher1.WaitAndGetTitle());
+
+ const base::string16 title2 = base::ASCIIToUTF16("reload=true");
+ TitleWatcher title_watcher2(shell()->web_contents(), title2);
+ ReloadBlockUntilNavigationsComplete(shell(), 1);
+ EXPECT_EQ(title2, title_watcher2.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();
- }
+
+ 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,
+ ResponseFromHTTPSServiceWorkerIsMarkedAsSecure) {
+ const char kPageUrl[] = "files/service_worker/fetch_event_blob.html";
+ const char kWorkerUrl[] = "files/service_worker/fetch_event_blob.js";
+ net::SpawnedTestServer https_server(
+ net::SpawnedTestServer::TYPE_HTTPS,
+ net::BaseTestServer::SSLOptions(
+ net::BaseTestServer::SSLOptions::CERT_OK),
+ base::FilePath(FILE_PATH_LITERAL("content/test/data/")));
+ ASSERT_TRUE(https_server.Start());
+
+ scoped_refptr<WorkerActivatedObserver> observer =
+ new WorkerActivatedObserver(wrapper());
+ observer->Init();
+ public_context()->RegisterServiceWorker(
+ https_server.GetURL(kPageUrl),
+ https_server.GetURL(kWorkerUrl),
+ base::Bind(&ExpectResultAndRun, true, base::Bind(&base::DoNothing)));
+ observer->Wait();
+
+ const base::string16 title = base::ASCIIToUTF16("Title");
+ TitleWatcher title_watcher(shell()->web_contents(), title);
+ NavigateToURL(shell(), https_server.GetURL(kPageUrl));
+ EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
+ EXPECT_FALSE(shell()->web_contents()->DisplayedInsecureContent());
+ NavigationEntry* entry =
+ shell()->web_contents()->GetController().GetVisibleEntry();
+ EXPECT_EQ(SECURITY_STYLE_AUTHENTICATED, entry->GetSSL().security_style);
+
+ shell()->Close();
+
+ base::RunLoop run_loop;
+ public_context()->UnregisterServiceWorker(
+ https_server.GetURL(kPageUrl),
+ base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
+ run_loop.Run();
+}
+
+IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest,
+ ResponseFromHTTPServiceWorkerIsNotMarkedAsSecure) {
+ const char kPageUrl[] = "/service_worker/fetch_event_blob.html";
+ const char kWorkerUrl[] = "/service_worker/fetch_event_blob.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("Title");
+ TitleWatcher title_watcher(shell()->web_contents(), title);
+ NavigateToURL(shell(), embedded_test_server()->GetURL(kPageUrl));
+ EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
+ EXPECT_FALSE(shell()->web_contents()->DisplayedInsecureContent());
+ NavigationEntry* entry =
+ shell()->web_contents()->GetController().GetVisibleEntry();
+ EXPECT_EQ(SECURITY_STYLE_UNAUTHENTICATED, entry->GetSSL().security_style);
+
+ 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 char kScopeUrl[] = "/service_worker/imports_bust_memcache_scope/";
+ const char kPageUrl[] = "/service_worker/imports_bust_memcache.html";
+ const char kScriptUrl[] = "/service_worker/worker_with_one_import.js";
+ const char kImportUrl[] = "/service_worker/long_lived_import.js";
const base::string16 kOKTitle(base::ASCIIToUTF16("OK"));
const base::string16 kFailTitle(base::ASCIIToUTF16("FAIL"));
@@ -829,17 +1278,15 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest, ImportsBustMemcache) {
class ServiceWorkerBlackBoxBrowserTest : public ServiceWorkerBrowserTest {
public:
- typedef ServiceWorkerBlackBoxBrowserTest self;
+ using self = ServiceWorkerBlackBoxBrowserTest;
void FindRegistrationOnIO(const GURL& document_url,
ServiceWorkerStatusCode* status,
const base::Closure& continuation) {
- wrapper()->context()->storage()->FindRegistrationForDocument(
+ wrapper()->FindRegistrationForDocument(
document_url,
base::Bind(&ServiceWorkerBlackBoxBrowserTest::FindRegistrationOnIO2,
- this,
- status,
- continuation));
+ this, status, continuation));
}
void FindRegistrationOnIO2(
@@ -864,8 +1311,8 @@ static int CountRenderProcessHosts() {
return result;
}
-// Flaky timeouts on CrOS: http://crbug.com/387045
-#if defined(OS_CHROMEOS)
+// Flaky timeouts on CrOS and crash on Android: http://crbug.com/387045
+#if defined(OS_CHROMEOS) || defined(ANDROID)
#define MAYBE_Registration DISABLED_Registration
#else
#define MAYBE_Registration Registration
@@ -875,7 +1322,8 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerBlackBoxBrowserTest, MAYBE_Registration) {
shell()->Close();
EXPECT_EQ(0, CountRenderProcessHosts());
- const std::string kWorkerUrl = "/service_worker/fetch_event.js";
+ const char kWorkerUrl[] = "/service_worker/fetch_event.js";
+ const char kScope[] = "/service_worker/";
// Unregistering nothing should return false.
{
@@ -890,7 +1338,7 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerBlackBoxBrowserTest, MAYBE_Registration) {
{
base::RunLoop run_loop;
public_context()->RegisterServiceWorker(
- embedded_test_server()->GetURL("/"),
+ embedded_test_server()->GetURL(kScope),
embedded_test_server()->GetURL("/does/not/exist"),
base::Bind(&ExpectResultAndRun, false, run_loop.QuitClosure()));
run_loop.Run();
@@ -901,7 +1349,7 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerBlackBoxBrowserTest, MAYBE_Registration) {
{
base::RunLoop run_loop;
public_context()->RegisterServiceWorker(
- embedded_test_server()->GetURL("/"),
+ embedded_test_server()->GetURL(kScope),
embedded_test_server()->GetURL(kWorkerUrl),
base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
run_loop.Run();
@@ -913,7 +1361,7 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerBlackBoxBrowserTest, MAYBE_Registration) {
{
base::RunLoop run_loop;
public_context()->RegisterServiceWorker(
- embedded_test_server()->GetURL("/"),
+ embedded_test_server()->GetURL(kScope),
embedded_test_server()->GetURL(kWorkerUrl),
base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
run_loop.Run();
@@ -927,7 +1375,7 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerBlackBoxBrowserTest, MAYBE_Registration) {
{
base::RunLoop run_loop;
public_context()->UnregisterServiceWorker(
- embedded_test_server()->GetURL("/"),
+ embedded_test_server()->GetURL(kScope),
base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
run_loop.Run();
}
@@ -947,4 +1395,94 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerBlackBoxBrowserTest, MAYBE_Registration) {
}
}
+#if defined(ANDROID)
+#define MAYBE_CrossSiteTransfer DISABLED_CrossSiteTransfer
+#else
+#define MAYBE_CrossSiteTransfer CrossSiteTransfer
+#endif
+IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest, MAYBE_CrossSiteTransfer) {
+ // The first page registers a service worker.
+ const char kRegisterPageUrl[] = "/service_worker/cross_site_xfer.html";
+ const base::string16 kOKTitle1(base::ASCIIToUTF16("OK_1"));
+ const base::string16 kFailTitle1(base::ASCIIToUTF16("FAIL_1"));
+ content::TitleWatcher title_watcher1(shell()->web_contents(), kOKTitle1);
+ title_watcher1.AlsoWaitForTitle(kFailTitle1);
+
+ NavigateToURL(shell(), embedded_test_server()->GetURL(kRegisterPageUrl));
+ ASSERT_EQ(kOKTitle1, title_watcher1.WaitAndGetTitle());
+
+ // Force process swapping behavior.
+ ShellContentBrowserClient::SetSwapProcessesForRedirect(true);
+
+ // The second pages loads via the serviceworker including a subresource.
+ const char kConfirmPageUrl[] =
+ "/service_worker/cross_site_xfer_scope/"
+ "cross_site_xfer_confirm_via_serviceworker.html";
+ const base::string16 kOKTitle2(base::ASCIIToUTF16("OK_2"));
+ const base::string16 kFailTitle2(base::ASCIIToUTF16("FAIL_2"));
+ content::TitleWatcher title_watcher2(shell()->web_contents(), kOKTitle2);
+ title_watcher2.AlsoWaitForTitle(kFailTitle2);
+
+ NavigateToURL(shell(), embedded_test_server()->GetURL(kConfirmPageUrl));
+ EXPECT_EQ(kOKTitle2, title_watcher2.WaitAndGetTitle());
+}
+
+class ServiceWorkerVersionBrowserV8CacheTest
+ : public ServiceWorkerVersionBrowserTest,
+ public ServiceWorkerVersion::Listener {
+ public:
+ using self = ServiceWorkerVersionBrowserV8CacheTest;
+ ~ServiceWorkerVersionBrowserV8CacheTest() override {
+ if (version_)
+ version_->RemoveListener(this);
+ }
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ ServiceWorkerBrowserTest::SetUpCommandLine(command_line);
+ command_line->AppendSwitchASCII(switches::kV8CacheOptions, "code");
+ }
+ void SetUpRegistrationAndListenerOnIOThread(const std::string& worker_url) {
+ SetUpRegistrationOnIOThread(worker_url);
+ version_->AddListener(this);
+ }
+
+ protected:
+ // ServiceWorkerVersion::Listener overrides
+ void OnCachedMetadataUpdated(ServiceWorkerVersion* version) override {
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ cache_updated_closure_);
+ }
+
+ base::Closure cache_updated_closure_;
+};
+
+IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserV8CacheTest, Restart) {
+ RunOnIOThread(base::Bind(&self::SetUpRegistrationAndListenerOnIOThread, this,
+ "/service_worker/worker.js"));
+
+ base::RunLoop cached_metadata_run_loop;
+ cache_updated_closure_ = cached_metadata_run_loop.QuitClosure();
+
+ // Start a worker.
+ StartWorker(SERVICE_WORKER_OK);
+
+ // Wait for the matadata is stored. This run loop should finish when
+ // OnCachedMetadataUpdated() is called.
+ cached_metadata_run_loop.Run();
+
+ // Activate the worker.
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
+ base::RunLoop activate_run_loop;
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(&self::ActivateOnIOThread, this,
+ activate_run_loop.QuitClosure(), &status));
+ activate_run_loop.Run();
+ ASSERT_EQ(SERVICE_WORKER_OK, status);
+ // Stop the worker.
+ StopWorker(SERVICE_WORKER_OK);
+ // Restart the worker.
+ StartWorker(SERVICE_WORKER_OK);
+ // Stop the worker.
+ StopWorker(SERVICE_WORKER_OK);
+}
+
} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_cache.cc b/chromium/content/browser/service_worker/service_worker_cache.cc
deleted file mode 100644
index c19793af49e..00000000000
--- a/chromium/content/browser/service_worker/service_worker_cache.cc
+++ /dev/null
@@ -1,1259 +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_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
deleted file mode 100644
index 6683797e992..00000000000
--- a/chromium/content/browser/service_worker/service_worker_cache.h
+++ /dev/null
@@ -1,195 +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_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
deleted file mode 100644
index 37b429b0618..00000000000
--- a/chromium/content/browser/service_worker/service_worker_cache.proto
+++ /dev/null
@@ -1,48 +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.
-
-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
deleted file mode 100644
index e52c940666d..00000000000
--- a/chromium/content/browser/service_worker/service_worker_cache_listener.cc
+++ /dev/null
@@ -1,459 +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_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
deleted file mode 100644
index d0364f36d94..00000000000
--- a/chromium/content/browser/service_worker/service_worker_cache_listener.h
+++ /dev/null
@@ -1,150 +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_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
deleted file mode 100644
index c7ed1c0cbd8..00000000000
--- a/chromium/content/browser/service_worker/service_worker_cache_quota_client.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/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
deleted file mode 100644
index 82111497b84..00000000000
--- a/chromium/content/browser/service_worker/service_worker_cache_quota_client.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_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
deleted file mode 100644
index 62adb60dfbc..00000000000
--- a/chromium/content/browser/service_worker/service_worker_cache_storage.cc
+++ /dev/null
@@ -1,683 +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_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
deleted file mode 100644
index a102707356f..00000000000
--- a/chromium/content/browser/service_worker/service_worker_cache_storage.h
+++ /dev/null
@@ -1,165 +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_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
deleted file mode 100644
index 3c3203dc507..00000000000
--- a/chromium/content/browser/service_worker/service_worker_cache_storage_manager.cc
+++ /dev/null
@@ -1,325 +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_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
deleted file mode 100644
index 79ac6c07a26..00000000000
--- a/chromium/content/browser/service_worker/service_worker_cache_storage_manager.h
+++ /dev/null
@@ -1,144 +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_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
deleted file mode 100644
index 8bfe7cce66d..00000000000
--- a/chromium/content/browser/service_worker/service_worker_cache_storage_manager_unittest.cc
+++ /dev/null
@@ -1,631 +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_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
deleted file mode 100644
index 0d1c8fad3a5..00000000000
--- a/chromium/content/browser/service_worker/service_worker_cache_unittest.cc
+++ /dev/null
@@ -1,796 +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_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 2272c95851b..f2a48dc54bc 100644
--- a/chromium/content/browser/service_worker/service_worker_context_core.cc
+++ b/chromium/content/browser/service_worker/service_worker_context_core.cc
@@ -11,7 +11,6 @@
#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"
@@ -23,11 +22,14 @@
#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 "net/http/http_response_headers.h"
+#include "net/http/http_response_info.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) {
@@ -45,6 +47,13 @@ void SuccessReportingCallback(
callback.Run(result ? ServiceWorkerStatusCode::SERVICE_WORKER_OK
: ServiceWorkerStatusCode::SERVICE_WORKER_ERROR_FAILED);
}
+
+bool IsSameOriginClientProviderHost(const GURL& origin,
+ ServiceWorkerProviderHost* host) {
+ return host->IsProviderForClient() &&
+ host->document_url().GetOrigin() == origin;
+}
+
} // namespace
const base::FilePath::CharType
@@ -66,7 +75,7 @@ void ServiceWorkerContextCore::ProviderHostIterator::Advance() {
// Advance the inner iterator. If an element is reached, we're done.
provider_host_iterator_->Advance();
- if (!provider_host_iterator_->IsAtEnd())
+ if (ForwardUntilMatchingProviderHost())
return;
// Advance the outer iterator until an element is reached, or end is hit.
@@ -76,7 +85,7 @@ void ServiceWorkerContextCore::ProviderHostIterator::Advance() {
return;
ProviderMap* provider_map = process_iterator_->GetCurrentValue();
provider_host_iterator_.reset(new ProviderMap::iterator(provider_map));
- if (!provider_host_iterator_->IsAtEnd())
+ if (ForwardUntilMatchingProviderHost())
return;
}
}
@@ -87,8 +96,9 @@ bool ServiceWorkerContextCore::ProviderHostIterator::IsAtEnd() {
}
ServiceWorkerContextCore::ProviderHostIterator::ProviderHostIterator(
- ProcessToProviderMap* map)
- : map_(map) {
+ ProcessToProviderMap* map,
+ const ProviderHostPredicate& predicate)
+ : map_(map), predicate_(predicate) {
DCHECK(map);
Initialize();
}
@@ -99,58 +109,66 @@ void ServiceWorkerContextCore::ProviderHostIterator::Initialize() {
while (!process_iterator_->IsAtEnd()) {
ProviderMap* provider_map = process_iterator_->GetCurrentValue();
provider_host_iterator_.reset(new ProviderMap::iterator(provider_map));
- if (!provider_host_iterator_->IsAtEnd())
+ if (ForwardUntilMatchingProviderHost())
return;
process_iterator_->Advance();
}
}
+bool ServiceWorkerContextCore::ProviderHostIterator::
+ ForwardUntilMatchingProviderHost() {
+ while (!provider_host_iterator_->IsAtEnd()) {
+ if (predicate_.is_null() || predicate_.Run(GetProviderHost()))
+ return true;
+ provider_host_iterator_->Advance();
+ }
+ return false;
+}
+
ServiceWorkerContextCore::ServiceWorkerContextCore(
const base::FilePath& path,
- 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),
+ : wrapper_(wrapper),
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())),
+ provider_by_uuid_(new ProviderByClientUUIDMap),
next_handle_id_(0),
next_registration_handle_id_(0),
- observer_list_(observer_list) {
+ observer_list_(observer_list),
+ weak_factory_(this) {
+ // These get a WeakPtr from weak_factory_, so must be set after weak_factory_
+ // is initialized.
+ storage_ = ServiceWorkerStorage::Create(path,
+ AsWeakPtr(),
+ database_task_manager.Pass(),
+ disk_cache_thread,
+ quota_manager_proxy,
+ special_storage_policy);
+ embedded_worker_registry_ = EmbeddedWorkerRegistry::Create(AsWeakPtr());
+ job_coordinator_.reset(new ServiceWorkerJobCoordinator(AsWeakPtr()));
}
ServiceWorkerContextCore::ServiceWorkerContextCore(
ServiceWorkerContextCore* old_context,
ServiceWorkerContextWrapper* wrapper)
- : weak_factory_(this),
- wrapper_(wrapper),
+ : 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())),
+ provider_by_uuid_(old_context->provider_by_uuid_.release()),
next_handle_id_(old_context->next_handle_id_),
next_registration_handle_id_(old_context->next_registration_handle_id_),
- observer_list_(old_context->observer_list_) {
+ observer_list_(old_context->observer_list_),
+ weak_factory_(this) {
+ // These get a WeakPtr from weak_factory_, so must be set after weak_factory_
+ // is initialized.
+ storage_ = ServiceWorkerStorage::Create(AsWeakPtr(), old_context->storage());
+ embedded_worker_registry_ = EmbeddedWorkerRegistry::Create(
+ AsWeakPtr(),
+ old_context->embedded_worker_registry());
+ job_coordinator_.reset(new ServiceWorkerJobCoordinator(AsWeakPtr()));
}
ServiceWorkerContextCore::~ServiceWorkerContextCore() {
@@ -196,7 +214,35 @@ void ServiceWorkerContextCore::RemoveAllProviderHostsForProcess(
scoped_ptr<ServiceWorkerContextCore::ProviderHostIterator>
ServiceWorkerContextCore::GetProviderHostIterator() {
- return make_scoped_ptr(new ProviderHostIterator(providers_.get()));
+ return make_scoped_ptr(new ProviderHostIterator(
+ providers_.get(), ProviderHostIterator::ProviderHostPredicate()));
+}
+
+scoped_ptr<ServiceWorkerContextCore::ProviderHostIterator>
+ServiceWorkerContextCore::GetClientProviderHostIterator(const GURL& origin) {
+ return make_scoped_ptr(new ProviderHostIterator(
+ providers_.get(), base::Bind(IsSameOriginClientProviderHost, origin)));
+}
+
+void ServiceWorkerContextCore::RegisterProviderHostByClientID(
+ const std::string& client_uuid,
+ ServiceWorkerProviderHost* provider_host) {
+ DCHECK(!ContainsKey(*provider_by_uuid_, client_uuid));
+ (*provider_by_uuid_)[client_uuid] = provider_host;
+}
+
+void ServiceWorkerContextCore::UnregisterProviderHostByClientID(
+ const std::string& client_uuid) {
+ DCHECK(ContainsKey(*provider_by_uuid_, client_uuid));
+ provider_by_uuid_->erase(client_uuid);
+}
+
+ServiceWorkerProviderHost* ServiceWorkerContextCore::GetProviderHostByClientID(
+ const std::string& client_uuid) {
+ auto found = provider_by_uuid_->find(client_uuid);
+ if (found == provider_by_uuid_->end())
+ return nullptr;
+ return found->second;
}
void ServiceWorkerContextCore::RegisterServiceWorker(
@@ -206,7 +252,7 @@ void ServiceWorkerContextCore::RegisterServiceWorker(
const RegistrationCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (storage()->IsDisabled()) {
- callback.Run(SERVICE_WORKER_ERROR_ABORT,
+ callback.Run(SERVICE_WORKER_ERROR_ABORT, std::string(),
kInvalidServiceWorkerRegistrationId);
return;
}
@@ -278,40 +324,45 @@ void ServiceWorkerContextCore::DidGetAllRegistrationsForUnregisterForOrigin(
}
void ServiceWorkerContextCore::UpdateServiceWorker(
- ServiceWorkerRegistration* registration) {
+ ServiceWorkerRegistration* registration,
+ bool force_bypass_cache) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (storage()->IsDisabled())
return;
- job_coordinator_->Update(registration);
+ job_coordinator_->Update(registration, force_bypass_cache);
}
void ServiceWorkerContextCore::RegistrationComplete(
const GURL& pattern,
const ServiceWorkerContextCore::RegistrationCallback& callback,
ServiceWorkerStatusCode status,
+ const std::string& status_message,
ServiceWorkerRegistration* registration) {
if (status != SERVICE_WORKER_OK) {
DCHECK(!registration);
- callback.Run(status, kInvalidServiceWorkerRegistrationId);
+ callback.Run(status, status_message, kInvalidServiceWorkerRegistrationId);
return;
}
DCHECK(registration);
- callback.Run(status, registration->id());
+ callback.Run(status, status_message, registration->id());
if (observer_list_.get()) {
- observer_list_->Notify(&ServiceWorkerContextObserver::OnRegistrationStored,
- pattern);
+ observer_list_->Notify(FROM_HERE,
+ &ServiceWorkerContextObserver::OnRegistrationStored,
+ registration->id(), pattern);
}
}
void ServiceWorkerContextCore::UnregistrationComplete(
const GURL& pattern,
const ServiceWorkerContextCore::UnregistrationCallback& callback,
+ int64 registration_id,
ServiceWorkerStatusCode status) {
callback.Run(status);
- if (observer_list_.get()) {
- observer_list_->Notify(&ServiceWorkerContextObserver::OnRegistrationDeleted,
- pattern);
+ if (status == SERVICE_WORKER_OK && observer_list_.get()) {
+ observer_list_->Notify(FROM_HERE,
+ &ServiceWorkerContextObserver::OnRegistrationDeleted,
+ registration_id, pattern);
}
}
@@ -325,6 +376,11 @@ void ServiceWorkerContextCore::AddLiveRegistration(
ServiceWorkerRegistration* registration) {
DCHECK(!GetLiveRegistration(registration->id()));
live_registrations_[registration->id()] = registration;
+ if (observer_list_.get()) {
+ observer_list_->Notify(FROM_HERE,
+ &ServiceWorkerContextObserver::OnNewLiveRegistration,
+ registration->id(), registration->pattern());
+ }
}
void ServiceWorkerContextCore::RemoveLiveRegistration(int64 id) {
@@ -341,6 +397,12 @@ void ServiceWorkerContextCore::AddLiveVersion(ServiceWorkerVersion* version) {
DCHECK(!GetLiveVersion(version->version_id()));
live_versions_[version->version_id()] = version;
version->AddListener(this);
+ if (observer_list_.get()) {
+ observer_list_->Notify(FROM_HERE,
+ &ServiceWorkerContextObserver::OnNewLiveVersion,
+ version->version_id(), version->registration_id(),
+ version->script_url());
+ }
}
void ServiceWorkerContextCore::RemoveLiveVersion(int64 id) {
@@ -392,39 +454,68 @@ void ServiceWorkerContextCore::DeleteAndStartOver(
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) {
+scoped_ptr<ServiceWorkerProviderHost>
+ServiceWorkerContextCore::TransferProviderHostOut(
+ int process_id, int provider_id) {
+ ProviderMap* map = GetProviderMapForProcess(process_id);
+ ServiceWorkerProviderHost* transferee = map->Lookup(provider_id);
+ ServiceWorkerProviderHost* replacement =
+ new ServiceWorkerProviderHost(process_id,
+ transferee->frame_id(),
+ provider_id,
+ transferee->provider_type(),
+ AsWeakPtr(),
+ transferee->dispatcher_host());
+ map->Replace(provider_id, replacement);
+ transferee->PrepareForCrossSiteTransfer();
+ return make_scoped_ptr(transferee);
+}
+
+void ServiceWorkerContextCore::TransferProviderHostIn(
+ int new_process_id, int new_provider_id,
+ scoped_ptr<ServiceWorkerProviderHost> transferee) {
+ ProviderMap* map = GetProviderMapForProcess(new_process_id);
+ ServiceWorkerProviderHost* temp = map->Lookup(new_provider_id);
+ DCHECK(temp->document_url().is_empty());
+ transferee->CompleteCrossSiteTransfer(new_process_id,
+ temp->frame_id(),
+ new_provider_id,
+ temp->provider_type(),
+ temp->dispatcher_host());
+ map->Replace(new_provider_id, transferee.release());
+ delete temp;
+}
+
+void ServiceWorkerContextCore::OnRunningStateChanged(
+ ServiceWorkerVersion* version) {
if (!observer_list_.get())
return;
- observer_list_->Notify(&ServiceWorkerContextObserver::OnWorkerStarted,
- version->version_id(),
- version->embedded_worker()->process_id(),
- version->embedded_worker()->thread_id());
+ observer_list_->Notify(FROM_HERE,
+ &ServiceWorkerContextObserver::OnRunningStateChanged,
+ version->version_id(), version->running_status());
}
-void ServiceWorkerContextCore::OnWorkerStopped(ServiceWorkerVersion* version) {
+void ServiceWorkerContextCore::OnVersionStateChanged(
+ ServiceWorkerVersion* version) {
if (!observer_list_.get())
return;
- observer_list_->Notify(&ServiceWorkerContextObserver::OnWorkerStopped,
- version->version_id(),
- version->embedded_worker()->process_id(),
- version->embedded_worker()->thread_id());
+ observer_list_->Notify(FROM_HERE,
+ &ServiceWorkerContextObserver::OnVersionStateChanged,
+ version->version_id(), version->status());
}
-void ServiceWorkerContextCore::OnVersionStateChanged(
+void ServiceWorkerContextCore::OnMainScriptHttpResponseInfoSet(
ServiceWorkerVersion* version) {
if (!observer_list_.get())
return;
- observer_list_->Notify(&ServiceWorkerContextObserver::OnVersionStateChanged,
- version->version_id());
+ const net::HttpResponseInfo* info = version->GetMainScriptHttpResponseInfo();
+ DCHECK(info);
+ base::Time lastModified;
+ if (info->headers)
+ info->headers->GetLastModifiedValue(&lastModified);
+ observer_list_->Notify(
+ FROM_HERE, &ServiceWorkerContextObserver::OnMainScriptHttpResponseInfoSet,
+ version->version_id(), info->response_time, lastModified);
}
void ServiceWorkerContextCore::OnErrorReported(
@@ -436,12 +527,11 @@ void ServiceWorkerContextCore::OnErrorReported(
if (!observer_list_.get())
return;
observer_list_->Notify(
- &ServiceWorkerContextObserver::OnErrorReported,
- version->version_id(),
- version->embedded_worker()->process_id(),
+ FROM_HERE, &ServiceWorkerContextObserver::OnErrorReported,
+ version->version_id(), version->embedded_worker()->process_id(),
version->embedded_worker()->thread_id(),
- ServiceWorkerContextObserver::ErrorInfo(
- error_message, line_number, column_number, source_url));
+ ServiceWorkerContextObserver::ErrorInfo(error_message, line_number,
+ column_number, source_url));
}
void ServiceWorkerContextCore::OnReportConsoleMessage(
@@ -454,18 +544,15 @@ void ServiceWorkerContextCore::OnReportConsoleMessage(
if (!observer_list_.get())
return;
observer_list_->Notify(
- &ServiceWorkerContextObserver::OnReportConsoleMessage,
- version->version_id(),
- version->embedded_worker()->process_id(),
+ FROM_HERE, &ServiceWorkerContextObserver::OnReportConsoleMessage,
+ version->version_id(), version->embedded_worker()->process_id(),
version->embedded_worker()->thread_id(),
ServiceWorkerContextObserver::ConsoleMessage(
source_identifier, message_level, message, line_number, source_url));
}
ServiceWorkerProcessManager* ServiceWorkerContextCore::process_manager() {
- if (wrapper_)
- return wrapper_->process_manager();
- return NULL;
+ return wrapper_->process_manager();
}
} // 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 63522ea3b39..c2aa08d6da1 100644
--- a/chromium/content/browser/service_worker/service_worker_context_core.h
+++ b/chromium/content/browser/service_worker/service_worker_context_core.h
@@ -29,10 +29,6 @@ class SequencedTaskRunner;
class SingleThreadTaskRunner;
}
-namespace net {
-class URLRequestContext;
-}
-
namespace storage {
class QuotaManagerProxy;
class SpecialStoragePolicy;
@@ -41,7 +37,6 @@ class SpecialStoragePolicy;
namespace content {
class EmbeddedWorkerRegistry;
-class ServiceWorkerCacheStorageManager;
class ServiceWorkerContextObserver;
class ServiceWorkerContextWrapper;
class ServiceWorkerDatabaseTaskManager;
@@ -61,17 +56,21 @@ class CONTENT_EXPORT ServiceWorkerContextCore
public:
typedef base::Callback<void(ServiceWorkerStatusCode status)> StatusCallback;
typedef base::Callback<void(ServiceWorkerStatusCode status,
+ const std::string& status_message,
int64 registration_id)> RegistrationCallback;
typedef base::Callback<
void(ServiceWorkerStatusCode status)> UnregistrationCallback;
typedef IDMap<ServiceWorkerProviderHost, IDMapOwnPointer> ProviderMap;
typedef IDMap<ProviderMap, IDMapOwnPointer> ProcessToProviderMap;
+ using ProviderByClientUUIDMap =
+ std::map<std::string, ServiceWorkerProviderHost*>;
+
// Directory for ServiceWorkerStorage and ServiceWorkerCacheManager.
static const base::FilePath::CharType kServiceWorkerDirectory[];
// Iterates over ServiceWorkerProviderHost objects in a ProcessToProviderMap.
- class ProviderHostIterator {
+ class CONTENT_EXPORT ProviderHostIterator {
public:
~ProviderHostIterator();
ServiceWorkerProviderHost* GetProviderHost();
@@ -80,10 +79,15 @@ class CONTENT_EXPORT ServiceWorkerContextCore
private:
friend class ServiceWorkerContextCore;
- explicit ProviderHostIterator(ProcessToProviderMap* map);
+ using ProviderHostPredicate =
+ base::Callback<bool(ServiceWorkerProviderHost*)>;
+ ProviderHostIterator(ProcessToProviderMap* map,
+ const ProviderHostPredicate& predicate);
void Initialize();
+ bool ForwardUntilMatchingProviderHost();
ProcessToProviderMap* map_;
+ ProviderHostPredicate predicate_;
scoped_ptr<ProcessToProviderMap::iterator> process_iterator_;
scoped_ptr<ProviderMap::iterator> provider_host_iterator_;
@@ -98,7 +102,6 @@ class CONTENT_EXPORT ServiceWorkerContextCore
// be called on the thread which called AddObserver() of |observer_list|.
ServiceWorkerContextCore(
const base::FilePath& user_data_directory,
- 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,
@@ -111,9 +114,9 @@ class CONTENT_EXPORT ServiceWorkerContextCore
~ServiceWorkerContextCore() override;
// ServiceWorkerVersion::Listener overrides.
- void OnWorkerStarted(ServiceWorkerVersion* version) override;
- void OnWorkerStopped(ServiceWorkerVersion* version) override;
+ void OnRunningStateChanged(ServiceWorkerVersion* version) override;
void OnVersionStateChanged(ServiceWorkerVersion* version) override;
+ void OnMainScriptHttpResponseInfoSet(ServiceWorkerVersion* version) override;
void OnErrorReported(ServiceWorkerVersion* version,
const base::string16& error_message,
int line_number,
@@ -126,10 +129,8 @@ class CONTENT_EXPORT ServiceWorkerContextCore
int line_number,
const GURL& source_url) override;
+ ServiceWorkerContextWrapper* wrapper() const { return wrapper_; }
ServiceWorkerStorage* storage() { return storage_.get(); }
- ServiceWorkerCacheStorageManager* cache_manager() {
- return cache_manager_.get();
- }
ServiceWorkerProcessManager* process_manager();
EmbeddedWorkerRegistry* embedded_worker_registry() {
return embedded_worker_registry_.get();
@@ -145,6 +146,22 @@ class CONTENT_EXPORT ServiceWorkerContextCore
void RemoveAllProviderHostsForProcess(int process_id);
scoped_ptr<ProviderHostIterator> GetProviderHostIterator();
+ // Returns a ProviderHost iterator for all ServiceWorker clients for
+ // the |origin|. This only returns ProviderHosts that are of CONTROLLEE
+ // and belong to the |origin|.
+ scoped_ptr<ProviderHostIterator> GetClientProviderHostIterator(
+ const GURL& origin);
+
+ // Maintains a map from Client UUID to ProviderHost.
+ // (Note: instead of maintaining 2 maps we might be able to uniformly use
+ // UUID instead of process_id+provider_id elsewhere. For now I'm leaving
+ // these as provider_id is deeply wired everywhere)
+ void RegisterProviderHostByClientID(const std::string& client_uuid,
+ ServiceWorkerProviderHost* provider_host);
+ void UnregisterProviderHostByClientID(const std::string& client_uuid);
+ ServiceWorkerProviderHost* GetProviderHostByClientID(
+ const std::string& client_uuid);
+
// 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.
@@ -159,7 +176,8 @@ class CONTENT_EXPORT ServiceWorkerContextCore
// if any did not succeed.
void UnregisterServiceWorkers(const GURL& origin,
const UnregistrationCallback& callback);
- void UpdateServiceWorker(ServiceWorkerRegistration* registration);
+ void UpdateServiceWorker(ServiceWorkerRegistration* registration,
+ bool force_bypass_cache);
// This class maintains collections of live instances, this class
// does not own these object or influence their lifetime.
@@ -183,15 +201,21 @@ class CONTENT_EXPORT ServiceWorkerContextCore
// 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);
+ // Methods to support cross site navigations.
+ scoped_ptr<ServiceWorkerProviderHost> TransferProviderHostOut(
+ int process_id,
+ int provider_id);
+ void TransferProviderHostIn(
+ int new_process_id,
+ int new_host_id,
+ scoped_ptr<ServiceWorkerProviderHost> provider_host);
base::WeakPtr<ServiceWorkerContextCore> AsWeakPtr() {
return weak_factory_.GetWeakPtr();
}
private:
+ friend class ServiceWorkerContext;
typedef std::map<int64, ServiceWorkerRegistration*> RegistrationsMap;
typedef std::map<int64, ServiceWorkerVersion*> VersionMap;
@@ -202,10 +226,12 @@ class CONTENT_EXPORT ServiceWorkerContextCore
void RegistrationComplete(const GURL& pattern,
const RegistrationCallback& callback,
ServiceWorkerStatusCode status,
+ const std::string& status_message,
ServiceWorkerRegistration* registration);
void UnregistrationComplete(const GURL& pattern,
const UnregistrationCallback& callback,
+ int64 registration_id,
ServiceWorkerStatusCode status);
void DidGetAllRegistrationsForUnregisterForOrigin(
@@ -213,14 +239,13 @@ class CONTENT_EXPORT ServiceWorkerContextCore
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_;
scoped_ptr<ProcessToProviderMap> providers_;
+ scoped_ptr<ProviderByClientUUIDMap> provider_by_uuid_;
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_;
@@ -229,6 +254,7 @@ class CONTENT_EXPORT ServiceWorkerContextCore
int next_registration_handle_id_;
scoped_refptr<ObserverListThreadSafe<ServiceWorkerContextObserver> >
observer_list_;
+ base::WeakPtrFactory<ServiceWorkerContextCore> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerContextCore);
};
diff --git a/chromium/content/browser/service_worker/service_worker_context_observer.h b/chromium/content/browser/service_worker/service_worker_context_observer.h
index 8bdaeea394f..049cbfa1918 100644
--- a/chromium/content/browser/service_worker/service_worker_context_observer.h
+++ b/chromium/content/browser/service_worker/service_worker_context_observer.h
@@ -6,6 +6,8 @@
#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CONTEXT_OBSERVER_H_
#include "base/strings/string16.h"
+#include "base/time/time.h"
+#include "content/browser/service_worker/service_worker_version.h"
#include "url/gurl.h"
namespace content {
@@ -43,13 +45,20 @@ class ServiceWorkerContextObserver {
const int line_number;
const GURL source_url;
};
- virtual void OnWorkerStarted(int64 version_id,
- int process_id,
- int thread_id) {}
- virtual void OnWorkerStopped(int64 version_id,
- int process_id,
- int thread_id) {}
- virtual void OnVersionStateChanged(int64 version_id) {}
+ virtual void OnNewLiveRegistration(int64 registration_id,
+ const GURL& pattern) {}
+ virtual void OnNewLiveVersion(int64 version_id,
+ int64 registration_id,
+ const GURL& script_url) {}
+ virtual void OnRunningStateChanged(
+ int64 version_id,
+ ServiceWorkerVersion::RunningStatus running_status) {}
+ virtual void OnVersionStateChanged(int64 version_id,
+ ServiceWorkerVersion::Status status) {}
+ virtual void OnMainScriptHttpResponseInfoSet(
+ int64 version_id,
+ base::Time script_response_time,
+ base::Time script_last_modified) {}
virtual void OnErrorReported(int64 version_id,
int process_id,
int thread_id,
@@ -58,8 +67,14 @@ class ServiceWorkerContextObserver {
int process_id,
int thread_id,
const ConsoleMessage& message) {}
- virtual void OnRegistrationStored(const GURL& pattern) {}
- virtual void OnRegistrationDeleted(const GURL& pattern) {}
+ virtual void OnRegistrationStored(int64 registration_id,
+ const GURL& pattern) {}
+ virtual void OnRegistrationDeleted(int64 registration_id,
+ const GURL& pattern) {}
+
+ // Notified when the storage corruption recovery is completed and all stored
+ // data is wiped out.
+ virtual void OnStorageWiped() {}
protected:
virtual ~ServiceWorkerContextObserver() {}
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 3bd8418c227..3b91496a08e 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
@@ -68,8 +68,10 @@ net::URLRequestJob* ServiceWorkerContextRequestHandler::MaybeCreateJob(
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))
+ if (time_since_last_check > base::TimeDelta::FromHours(24) ||
+ version_->force_bypass_cache_for_scripts()) {
extra_load_flags = net::LOAD_BYPASS_CACHE;
+ }
return new ServiceWorkerWriteToCacheJob(request,
network_delegate,
@@ -83,7 +85,7 @@ net::URLRequestJob* ServiceWorkerContextRequestHandler::MaybeCreateJob(
int64 response_id = kInvalidServiceWorkerResponseId;
if (ShouldReadFromScriptCache(request->url(), &response_id)) {
return new ServiceWorkerReadFromCacheJob(
- request, network_delegate, context_, response_id);
+ request, network_delegate, context_, version_, response_id);
}
// NULL means use the network.
diff --git a/chromium/content/browser/service_worker/service_worker_context_request_handler_unittest.cc b/chromium/content/browser/service_worker/service_worker_context_request_handler_unittest.cc
index c1063d726fa..b6cad7418c0 100644
--- a/chromium/content/browser/service_worker/service_worker_context_request_handler_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_context_request_handler_unittest.cc
@@ -35,7 +35,8 @@ class ServiceWorkerContextRequestHandlerTest : public testing::Test {
: browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
void SetUp() override {
- helper_.reset(new EmbeddedWorkerTestHelper(kMockRenderProcessId));
+ helper_.reset(
+ new EmbeddedWorkerTestHelper(base::FilePath(), kMockRenderProcessId));
// A new unstored registration/version.
scope_ = GURL("http://host/scope/");
@@ -47,8 +48,9 @@ class ServiceWorkerContextRequestHandlerTest : public testing::Test {
// An empty host.
scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
- kMockRenderProcessId, 1 /* provider_id */,
- context()->AsWeakPtr(), NULL));
+ kMockRenderProcessId, MSG_ROUTING_NONE /* render_frame_id */,
+ 1 /* provider_id */, SERVICE_WORKER_PROVIDER_FOR_WINDOW,
+ context()->AsWeakPtr(), nullptr));
provider_host_ = host->AsWeakPtr();
context()->AddProviderHost(host.Pass());
@@ -57,8 +59,8 @@ class ServiceWorkerContextRequestHandlerTest : public testing::Test {
}
void TearDown() override {
- version_ = NULL;
- registration_ = NULL;
+ version_ = nullptr;
+ registration_ = nullptr;
helper_.reset();
}
@@ -86,10 +88,7 @@ TEST_F(ServiceWorkerContextRequestHandlerTest, UpdateBefore24Hours) {
// 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);
+ kScriptUrl, net::DEFAULT_PRIORITY, &url_request_delegate_);
scoped_ptr<ServiceWorkerContextRequestHandler> handler(
new ServiceWorkerContextRequestHandler(
context()->AsWeakPtr(),
@@ -97,7 +96,7 @@ TEST_F(ServiceWorkerContextRequestHandlerTest, UpdateBefore24Hours) {
base::WeakPtr<storage::BlobStorageContext>(),
RESOURCE_TYPE_SERVICE_WORKER));
scoped_refptr<net::URLRequestJob> job =
- handler->MaybeCreateJob(request.get(), NULL, NULL);
+ handler->MaybeCreateJob(request.get(), nullptr, nullptr);
ASSERT_TRUE(job.get());
ServiceWorkerWriteToCacheJob* sw_job =
static_cast<ServiceWorkerWriteToCacheJob*>(job.get());
@@ -117,10 +116,7 @@ TEST_F(ServiceWorkerContextRequestHandlerTest, UpdateAfter24Hours) {
// 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);
+ kScriptUrl, net::DEFAULT_PRIORITY, &url_request_delegate_);
scoped_ptr<ServiceWorkerContextRequestHandler> handler(
new ServiceWorkerContextRequestHandler(
context()->AsWeakPtr(),
@@ -128,7 +124,34 @@ TEST_F(ServiceWorkerContextRequestHandlerTest, UpdateAfter24Hours) {
base::WeakPtr<storage::BlobStorageContext>(),
RESOURCE_TYPE_SERVICE_WORKER));
scoped_refptr<net::URLRequestJob> job =
- handler->MaybeCreateJob(request.get(), NULL, NULL);
+ handler->MaybeCreateJob(request.get(), nullptr, nullptr);
+ 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);
+}
+
+TEST_F(ServiceWorkerContextRequestHandlerTest, UpdateForceBypassCache) {
+ // 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);
+ version_->set_force_bypass_cache_for_scripts(true);
+ provider_host_->running_hosted_version_ = version_;
+
+ // Conduct a resource fetch for the main script.
+ const GURL kScriptUrl("http://host/script.js");
+ scoped_ptr<net::URLRequest> request = url_request_context_.CreateRequest(
+ kScriptUrl, net::DEFAULT_PRIORITY, &url_request_delegate_);
+ scoped_ptr<ServiceWorkerContextRequestHandler> handler(
+ new ServiceWorkerContextRequestHandler(
+ context()->AsWeakPtr(), provider_host_,
+ base::WeakPtr<storage::BlobStorageContext>(),
+ RESOURCE_TYPE_SERVICE_WORKER));
+ scoped_refptr<net::URLRequestJob> job =
+ handler->MaybeCreateJob(request.get(), nullptr, nullptr);
ASSERT_TRUE(job.get());
ServiceWorkerWriteToCacheJob* sw_job =
static_cast<ServiceWorkerWriteToCacheJob*>(job.get());
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 a5bba95facb..16a3233e5b1 100644
--- a/chromium/content/browser/service_worker/service_worker_context_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_context_unittest.cc
@@ -11,6 +11,9 @@
#include "content/browser/service_worker/embedded_worker_registry.h"
#include "content/browser/service_worker/embedded_worker_test_helper.h"
#include "content/browser/service_worker/service_worker_context_core.h"
+#include "content/browser/service_worker/service_worker_context_observer.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_storage.h"
#include "content/common/service_worker/embedded_worker_messages.h"
@@ -26,6 +29,7 @@ namespace {
void SaveResponseCallback(bool* called,
int64* store_registration_id,
ServiceWorkerStatusCode status,
+ const std::string& status_message,
int64 registration_id) {
EXPECT_EQ(SERVICE_WORKER_OK, status) << ServiceWorkerStatusToString(status);
*called = true;
@@ -75,11 +79,10 @@ void ExpectRegisteredWorkers(
class RejectInstallTestHelper : public EmbeddedWorkerTestHelper {
public:
explicit RejectInstallTestHelper(int mock_render_process_id)
- : EmbeddedWorkerTestHelper(mock_render_process_id) {}
+ : EmbeddedWorkerTestHelper(base::FilePath(), mock_render_process_id) {}
void OnInstallEvent(int embedded_worker_id,
- int request_id,
- int active_version_id) override {
+ int request_id) override {
SimulateSend(
new ServiceWorkerHostMsg_InstallEventFinished(
embedded_worker_id, request_id,
@@ -90,7 +93,7 @@ class RejectInstallTestHelper : public EmbeddedWorkerTestHelper {
class RejectActivateTestHelper : public EmbeddedWorkerTestHelper {
public:
explicit RejectActivateTestHelper(int mock_render_process_id)
- : EmbeddedWorkerTestHelper(mock_render_process_id) {}
+ : EmbeddedWorkerTestHelper(base::FilePath(), mock_render_process_id) {}
void OnActivateEvent(int embedded_worker_id, int request_id) override {
SimulateSend(
@@ -100,35 +103,77 @@ class RejectActivateTestHelper : public EmbeddedWorkerTestHelper {
}
};
+enum NotificationType {
+ REGISTRATION_STORED,
+ REGISTRATION_DELETED,
+ STORAGE_RECOVERED,
+};
+
+struct NotificationLog {
+ NotificationType type;
+ GURL pattern;
+ int64 registration_id;
+};
+
} // namespace
-class ServiceWorkerContextTest : public testing::Test {
+class ServiceWorkerContextTest : public ServiceWorkerContextObserver,
+ public testing::Test {
public:
ServiceWorkerContextTest()
: browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP),
render_process_id_(99) {}
void SetUp() override {
- helper_.reset(new EmbeddedWorkerTestHelper(render_process_id_));
+ helper_.reset(
+ new EmbeddedWorkerTestHelper(base::FilePath(), render_process_id_));
+ helper_->context_wrapper()->AddObserver(this);
}
void TearDown() override { helper_.reset(); }
+ // ServiceWorkerContextObserver overrides.
+ void OnRegistrationStored(int64 registration_id,
+ const GURL& pattern) override {
+ NotificationLog log;
+ log.type = REGISTRATION_STORED;
+ log.pattern = pattern;
+ log.registration_id = registration_id;
+ notifications_.push_back(log);
+ }
+ void OnRegistrationDeleted(int64 registration_id,
+ const GURL& pattern) override {
+ NotificationLog log;
+ log.type = REGISTRATION_DELETED;
+ log.pattern = pattern;
+ log.registration_id = registration_id;
+ notifications_.push_back(log);
+ }
+ void OnStorageWiped() override {
+ NotificationLog log;
+ log.type = STORAGE_RECOVERED;
+ notifications_.push_back(log);
+ }
+
ServiceWorkerContextCore* context() { return helper_->context(); }
protected:
TestBrowserThreadBundle browser_thread_bundle_;
scoped_ptr<EmbeddedWorkerTestHelper> helper_;
const int render_process_id_;
+ std::vector<NotificationLog> notifications_;
};
// Make sure basic registration is working.
TEST_F(ServiceWorkerContextTest, Register) {
+ GURL pattern("http://www.example.com/");
+ GURL script_url("http://www.example.com/service_worker.js");
+
int64 registration_id = kInvalidServiceWorkerRegistrationId;
bool called = false;
context()->RegisterServiceWorker(
- GURL("http://www.example.com/"),
- GURL("http://www.example.com/service_worker.js"),
+ pattern,
+ script_url,
NULL,
MakeRegisteredCallback(&called, &registration_id));
@@ -149,25 +194,33 @@ TEST_F(ServiceWorkerContextTest, Register) {
context()->storage()->FindRegistrationForId(
registration_id,
- GURL("http://www.example.com"),
+ pattern.GetOrigin(),
base::Bind(&ExpectRegisteredWorkers,
SERVICE_WORKER_OK,
false /* expect_waiting */,
true /* expect_active */));
base::RunLoop().RunUntilIdle();
+
+ ASSERT_EQ(1u, notifications_.size());
+ EXPECT_EQ(REGISTRATION_STORED, notifications_[0].type);
+ EXPECT_EQ(pattern, notifications_[0].pattern);
+ EXPECT_EQ(registration_id, notifications_[0].registration_id);
}
// Test registration when the service worker rejects the install event. The
// registration callback should indicate success, but there should be no waiting
// or active worker in the registration.
TEST_F(ServiceWorkerContextTest, Register_RejectInstall) {
+ GURL pattern("http://www.example.com/");
+ GURL script_url("http://www.example.com/service_worker.js");
+
helper_.reset(); // Make sure the process lookups stay overridden.
helper_.reset(new RejectInstallTestHelper(render_process_id_));
int64 registration_id = kInvalidServiceWorkerRegistrationId;
bool called = false;
context()->RegisterServiceWorker(
- GURL("http://www.example.com/"),
- GURL("http://www.example.com/service_worker.js"),
+ pattern,
+ script_url,
NULL,
MakeRegisteredCallback(&called, &registration_id));
@@ -188,12 +241,14 @@ TEST_F(ServiceWorkerContextTest, Register_RejectInstall) {
context()->storage()->FindRegistrationForId(
registration_id,
- GURL("http://www.example.com"),
+ pattern.GetOrigin(),
base::Bind(&ExpectRegisteredWorkers,
SERVICE_WORKER_ERROR_NOT_FOUND,
false /* expect_waiting */,
false /* expect_active */));
base::RunLoop().RunUntilIdle();
+
+ EXPECT_TRUE(notifications_.empty());
}
// Test registration when the service worker rejects the activate event. The
@@ -233,6 +288,8 @@ TEST_F(ServiceWorkerContextTest, Register_RejectActivate) {
false /* expect_waiting */,
false /* expect_active */));
base::RunLoop().RunUntilIdle();
+
+ EXPECT_TRUE(notifications_.empty());
}
// Make sure registrations are cleaned up when they are unregistered.
@@ -268,6 +325,14 @@ TEST_F(ServiceWorkerContextTest, Unregister) {
false /* expect_waiting */,
false /* expect_active */));
base::RunLoop().RunUntilIdle();
+
+ ASSERT_EQ(2u, notifications_.size());
+ EXPECT_EQ(REGISTRATION_STORED, notifications_[0].type);
+ EXPECT_EQ(pattern, notifications_[0].pattern);
+ EXPECT_EQ(registration_id, notifications_[0].registration_id);
+ EXPECT_EQ(REGISTRATION_DELETED, notifications_[1].type);
+ EXPECT_EQ(pattern, notifications_[1].pattern);
+ EXPECT_EQ(registration_id, notifications_[1].registration_id);
}
// Make sure registrations are cleaned up when they are unregistered in bulk.
@@ -351,6 +416,26 @@ TEST_F(ServiceWorkerContextTest, UnregisterMultiple) {
true /* expect_active */));
base::RunLoop().RunUntilIdle();
+
+ ASSERT_EQ(6u, notifications_.size());
+ EXPECT_EQ(REGISTRATION_STORED, notifications_[0].type);
+ EXPECT_EQ(registration_id1, notifications_[0].registration_id);
+ EXPECT_EQ(origin1_p1, notifications_[0].pattern);
+ EXPECT_EQ(REGISTRATION_STORED, notifications_[1].type);
+ EXPECT_EQ(origin1_p2, notifications_[1].pattern);
+ EXPECT_EQ(registration_id2, notifications_[1].registration_id);
+ EXPECT_EQ(REGISTRATION_STORED, notifications_[2].type);
+ EXPECT_EQ(origin2_p1, notifications_[2].pattern);
+ EXPECT_EQ(registration_id3, notifications_[2].registration_id);
+ EXPECT_EQ(REGISTRATION_STORED, notifications_[3].type);
+ EXPECT_EQ(origin3_p1, notifications_[3].pattern);
+ EXPECT_EQ(registration_id4, notifications_[3].registration_id);
+ EXPECT_EQ(REGISTRATION_DELETED, notifications_[4].type);
+ EXPECT_EQ(origin1_p2, notifications_[4].pattern);
+ EXPECT_EQ(registration_id2, notifications_[4].registration_id);
+ EXPECT_EQ(REGISTRATION_DELETED, notifications_[5].type);
+ EXPECT_EQ(origin1_p1, notifications_[5].pattern);
+ EXPECT_EQ(registration_id1, notifications_[5].registration_id);
}
// Make sure registering a new script shares an existing registration.
@@ -384,6 +469,14 @@ TEST_F(ServiceWorkerContextTest, RegisterNewScript) {
EXPECT_NE(kInvalidServiceWorkerRegistrationId, new_registration_id);
EXPECT_EQ(old_registration_id, new_registration_id);
+
+ ASSERT_EQ(2u, notifications_.size());
+ EXPECT_EQ(REGISTRATION_STORED, notifications_[0].type);
+ EXPECT_EQ(pattern, notifications_[0].pattern);
+ EXPECT_EQ(old_registration_id, notifications_[0].registration_id);
+ EXPECT_EQ(REGISTRATION_STORED, notifications_[1].type);
+ EXPECT_EQ(pattern, notifications_[1].pattern);
+ EXPECT_EQ(new_registration_id, notifications_[1].registration_id);
}
// Make sure that when registering a duplicate pattern+script_url
@@ -417,15 +510,32 @@ TEST_F(ServiceWorkerContextTest, RegisterDuplicateScript) {
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(called);
EXPECT_EQ(old_registration_id, new_registration_id);
+
+ ASSERT_EQ(2u, notifications_.size());
+ EXPECT_EQ(REGISTRATION_STORED, notifications_[0].type);
+ EXPECT_EQ(pattern, notifications_[0].pattern);
+ EXPECT_EQ(old_registration_id, notifications_[0].registration_id);
+ EXPECT_EQ(REGISTRATION_STORED, notifications_[1].type);
+ EXPECT_EQ(pattern, notifications_[1].pattern);
+ EXPECT_EQ(old_registration_id, notifications_[1].registration_id);
}
-// TODO(nhiroki): Test this for on-disk storage.
TEST_F(ServiceWorkerContextTest, DeleteAndStartOver) {
+ GURL pattern("http://www.example.com/");
+ GURL script_url("http://www.example.com/service_worker.js");
+
+ // Reinitialize the helper to test on-disk storage.
+ base::ScopedTempDir user_data_directory;
+ ASSERT_TRUE(user_data_directory.CreateUniqueTempDir());
+ helper_.reset(new EmbeddedWorkerTestHelper(user_data_directory.path(),
+ render_process_id_));
+ helper_->context_wrapper()->AddObserver(this);
+
int64 registration_id = kInvalidServiceWorkerRegistrationId;
bool called = false;
context()->RegisterServiceWorker(
- GURL("http://www.example.com/"),
- GURL("http://www.example.com/service_worker.js"),
+ pattern,
+ script_url,
NULL,
MakeRegisteredCallback(&called, &registration_id));
@@ -435,7 +545,7 @@ TEST_F(ServiceWorkerContextTest, DeleteAndStartOver) {
context()->storage()->FindRegistrationForId(
registration_id,
- GURL("http://www.example.com"),
+ pattern.GetOrigin(),
base::Bind(&ExpectRegisteredWorkers,
SERVICE_WORKER_OK,
false /* expect_waiting */,
@@ -452,7 +562,7 @@ TEST_F(ServiceWorkerContextTest, DeleteAndStartOver) {
// operation should be failed.
context()->storage()->FindRegistrationForId(
registration_id,
- GURL("http://www.example.com"),
+ pattern.GetOrigin(),
base::Bind(&ExpectRegisteredWorkers,
SERVICE_WORKER_ERROR_FAILED,
false /* expect_waiting */,
@@ -463,7 +573,7 @@ TEST_F(ServiceWorkerContextTest, DeleteAndStartOver) {
// registration should not be found.
context()->storage()->FindRegistrationForId(
registration_id,
- GURL("http://www.example.com"),
+ pattern.GetOrigin(),
base::Bind(&ExpectRegisteredWorkers,
SERVICE_WORKER_ERROR_NOT_FOUND,
false /* expect_waiting */,
@@ -472,8 +582,8 @@ TEST_F(ServiceWorkerContextTest, DeleteAndStartOver) {
called = false;
context()->RegisterServiceWorker(
- GURL("http://www.example.com/"),
- GURL("http://www.example.com/service_worker.js"),
+ pattern,
+ script_url,
NULL,
MakeRegisteredCallback(&called, &registration_id));
@@ -483,7 +593,7 @@ TEST_F(ServiceWorkerContextTest, DeleteAndStartOver) {
context()->storage()->FindRegistrationForId(
registration_id,
- GURL("http://www.example.com"),
+ pattern.GetOrigin(),
base::Bind(&ExpectRegisteredWorkers,
SERVICE_WORKER_OK,
false /* expect_waiting */,
@@ -493,6 +603,89 @@ TEST_F(ServiceWorkerContextTest, DeleteAndStartOver) {
// The new context should take over next handle ids.
EXPECT_EQ(1, context()->GetNewServiceWorkerHandleId());
EXPECT_EQ(1, context()->GetNewRegistrationHandleId());
+
+ ASSERT_EQ(3u, notifications_.size());
+ EXPECT_EQ(REGISTRATION_STORED, notifications_[0].type);
+ EXPECT_EQ(pattern, notifications_[0].pattern);
+ EXPECT_EQ(registration_id, notifications_[0].registration_id);
+ EXPECT_EQ(STORAGE_RECOVERED, notifications_[1].type);
+ EXPECT_EQ(REGISTRATION_STORED, notifications_[2].type);
+ EXPECT_EQ(pattern, notifications_[2].pattern);
+ EXPECT_EQ(registration_id, notifications_[2].registration_id);
+}
+
+TEST_F(ServiceWorkerContextTest, ProviderHostIterator) {
+ const int kRenderProcessId1 = 1;
+ const int kRenderProcessId2 = 2;
+ const GURL kOrigin1 = GURL("http://www.example.com/");
+ const GURL kOrigin2 = GURL("https://www.example.com/");
+ int provider_id = 1;
+
+ // Host1 (provider_id=1): process_id=1, origin1.
+ ServiceWorkerProviderHost* host1(new ServiceWorkerProviderHost(
+ kRenderProcessId1, MSG_ROUTING_NONE, provider_id++,
+ SERVICE_WORKER_PROVIDER_FOR_WINDOW, context()->AsWeakPtr(), nullptr));
+ host1->SetDocumentUrl(kOrigin1);
+
+ // Host2 (provider_id=2): process_id=2, origin2.
+ ServiceWorkerProviderHost* host2(new ServiceWorkerProviderHost(
+ kRenderProcessId2, MSG_ROUTING_NONE, provider_id++,
+ SERVICE_WORKER_PROVIDER_FOR_WINDOW, context()->AsWeakPtr(), nullptr));
+ host2->SetDocumentUrl(kOrigin2);
+
+ // Host3 (provider_id=3): process_id=2, origin1.
+ ServiceWorkerProviderHost* host3(new ServiceWorkerProviderHost(
+ kRenderProcessId2, MSG_ROUTING_NONE, provider_id++,
+ SERVICE_WORKER_PROVIDER_FOR_WINDOW, context()->AsWeakPtr(), nullptr));
+ host3->SetDocumentUrl(kOrigin1);
+
+ // Host4 (provider_id=4): process_id=2, origin2, for ServiceWorker.
+ ServiceWorkerProviderHost* host4(new ServiceWorkerProviderHost(
+ kRenderProcessId2, MSG_ROUTING_NONE, provider_id++,
+ SERVICE_WORKER_PROVIDER_FOR_CONTROLLER, context()->AsWeakPtr(), nullptr));
+ host4->SetDocumentUrl(kOrigin2);
+
+ context()->AddProviderHost(make_scoped_ptr(host1));
+ context()->AddProviderHost(make_scoped_ptr(host2));
+ context()->AddProviderHost(make_scoped_ptr(host3));
+ context()->AddProviderHost(make_scoped_ptr(host4));
+
+ // Iterate over all provider hosts.
+ std::set<ServiceWorkerProviderHost*> results;
+ for (auto it = context()->GetProviderHostIterator(); !it->IsAtEnd();
+ it->Advance()) {
+ results.insert(it->GetProviderHost());
+ }
+ EXPECT_EQ(4u, results.size());
+ EXPECT_TRUE(ContainsKey(results, host1));
+ EXPECT_TRUE(ContainsKey(results, host2));
+ EXPECT_TRUE(ContainsKey(results, host3));
+ EXPECT_TRUE(ContainsKey(results, host4));
+
+ // Iterate over the client provider hosts that belong to kOrigin1.
+ results.clear();
+ for (auto it = context()->GetClientProviderHostIterator(kOrigin1);
+ !it->IsAtEnd(); it->Advance()) {
+ results.insert(it->GetProviderHost());
+ }
+ EXPECT_EQ(2u, results.size());
+ EXPECT_TRUE(ContainsKey(results, host1));
+ EXPECT_TRUE(ContainsKey(results, host3));
+
+ // Iterate over the provider hosts that belong to kOrigin2.
+ // (This should not include host4 as it's not for controllee.)
+ results.clear();
+ for (auto it = context()->GetClientProviderHostIterator(kOrigin2);
+ !it->IsAtEnd(); it->Advance()) {
+ results.insert(it->GetProviderHost());
+ }
+ EXPECT_EQ(1u, results.size());
+ EXPECT_TRUE(ContainsKey(results, host2));
+
+ context()->RemoveProviderHost(kRenderProcessId1, 1);
+ context()->RemoveProviderHost(kRenderProcessId2, 2);
+ context()->RemoveProviderHost(kRenderProcessId2, 3);
+ context()->RemoveProviderHost(kRenderProcessId2, 4);
}
} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_context_watcher.cc b/chromium/content/browser/service_worker/service_worker_context_watcher.cc
new file mode 100644
index 00000000000..0bea44dd403
--- /dev/null
+++ b/chromium/content/browser/service_worker/service_worker_context_watcher.cc
@@ -0,0 +1,253 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/service_worker/service_worker_context_watcher.h"
+
+#include "base/bind.h"
+#include "base/containers/scoped_ptr_hash_map.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_version.h"
+#include "content/common/service_worker/service_worker_types.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/common/console_message_level.h"
+#include "url/gurl.h"
+
+namespace content {
+namespace {
+
+bool IsStoppedAndRedundant(const ServiceWorkerVersionInfo& version_info) {
+ return version_info.running_status ==
+ content::ServiceWorkerVersion::STOPPED &&
+ version_info.status == content::ServiceWorkerVersion::REDUNDANT;
+}
+
+} // namespace
+
+ServiceWorkerContextWatcher::ServiceWorkerContextWatcher(
+ scoped_refptr<ServiceWorkerContextWrapper> context,
+ const WorkerRegistrationUpdatedCallback& registration_callback,
+ const WorkerVersionUpdatedCallback& version_callback,
+ const WorkerErrorReportedCallback& error_callback)
+ : context_(context),
+ registration_callback_(registration_callback),
+ version_callback_(version_callback),
+ error_callback_(error_callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+}
+
+void ServiceWorkerContextWatcher::Start() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&ServiceWorkerContextWatcher::GetStoredRegistrationsOnIOThread,
+ this));
+}
+
+void ServiceWorkerContextWatcher::Stop() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&ServiceWorkerContextWatcher::StopOnIOThread, this));
+}
+
+void ServiceWorkerContextWatcher::GetStoredRegistrationsOnIOThread() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ context_->GetAllRegistrations(base::Bind(
+ &ServiceWorkerContextWatcher::OnStoredRegistrationsOnIOThread, this));
+}
+
+void ServiceWorkerContextWatcher::OnStoredRegistrationsOnIOThread(
+ const std::vector<ServiceWorkerRegistrationInfo>& stored_registrations) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ context_->AddObserver(this);
+
+ base::ScopedPtrHashMap<int64, scoped_ptr<ServiceWorkerRegistrationInfo>>
+ registration_info_map;
+ for (const auto& registration : stored_registrations)
+ StoreRegistrationInfo(registration, &registration_info_map);
+ for (const auto& registration : context_->GetAllLiveRegistrationInfo())
+ StoreRegistrationInfo(registration, &registration_info_map);
+ for (const auto& version : context_->GetAllLiveVersionInfo())
+ StoreVersionInfo(version);
+
+ std::vector<ServiceWorkerRegistrationInfo> registrations;
+ registrations.reserve(registration_info_map.size());
+ for (const auto& registration_id_info_pair : registration_info_map)
+ registrations.push_back(*registration_id_info_pair.second);
+
+ std::vector<ServiceWorkerVersionInfo> versions;
+ versions.reserve(version_info_map_.size());
+
+ for (auto version_it = version_info_map_.begin();
+ version_it != version_info_map_.end();) {
+ versions.push_back(*version_it->second);
+ if (IsStoppedAndRedundant(*version_it->second))
+ version_info_map_.erase(version_it++);
+ else
+ ++version_it;
+ }
+
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(registration_callback_, registrations));
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(version_callback_, versions));
+}
+
+void ServiceWorkerContextWatcher::StopOnIOThread() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ context_->RemoveObserver(this);
+}
+
+ServiceWorkerContextWatcher::~ServiceWorkerContextWatcher() {
+}
+
+void ServiceWorkerContextWatcher::StoreRegistrationInfo(
+ const ServiceWorkerRegistrationInfo& registration_info,
+ base::ScopedPtrHashMap<int64, scoped_ptr<ServiceWorkerRegistrationInfo>>*
+ info_map) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (registration_info.registration_id == kInvalidServiceWorkerRegistrationId)
+ return;
+ info_map->set(registration_info.registration_id,
+ scoped_ptr<ServiceWorkerRegistrationInfo>(
+ new ServiceWorkerRegistrationInfo(registration_info)));
+ StoreVersionInfo(registration_info.active_version);
+ StoreVersionInfo(registration_info.waiting_version);
+ StoreVersionInfo(registration_info.installing_version);
+}
+
+void ServiceWorkerContextWatcher::StoreVersionInfo(
+ const ServiceWorkerVersionInfo& version_info) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (version_info.version_id == kInvalidServiceWorkerVersionId)
+ return;
+ version_info_map_.set(version_info.version_id,
+ scoped_ptr<ServiceWorkerVersionInfo>(
+ new ServiceWorkerVersionInfo(version_info)));
+}
+
+void ServiceWorkerContextWatcher::SendRegistrationInfo(
+ int64 registration_id,
+ const GURL& pattern,
+ ServiceWorkerRegistrationInfo::DeleteFlag delete_flag) {
+ std::vector<ServiceWorkerRegistrationInfo> registrations;
+ registrations.push_back(
+ ServiceWorkerRegistrationInfo(pattern, registration_id, delete_flag));
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(registration_callback_, registrations));
+}
+
+void ServiceWorkerContextWatcher::SendVersionInfo(
+ const ServiceWorkerVersionInfo& version_info) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ std::vector<ServiceWorkerVersionInfo> versions;
+ versions.push_back(version_info);
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(version_callback_, versions));
+}
+
+void ServiceWorkerContextWatcher::OnNewLiveRegistration(int64 registration_id,
+ const GURL& pattern) {
+ SendRegistrationInfo(registration_id, pattern,
+ ServiceWorkerRegistrationInfo::IS_NOT_DELETED);
+}
+
+void ServiceWorkerContextWatcher::OnNewLiveVersion(int64 version_id,
+ int64 registration_id,
+ const GURL& script_url) {
+ if (ServiceWorkerVersionInfo* version = version_info_map_.get(version_id)) {
+ DCHECK_EQ(version->registration_id, registration_id);
+ DCHECK_EQ(version->script_url, script_url);
+ return;
+ }
+
+ scoped_ptr<ServiceWorkerVersionInfo> version(new ServiceWorkerVersionInfo());
+ version->version_id = version_id;
+ version->registration_id = registration_id;
+ version->script_url = script_url;
+ SendVersionInfo(*version);
+ if (!IsStoppedAndRedundant(*version))
+ version_info_map_.set(version_id, version.Pass());
+}
+
+void ServiceWorkerContextWatcher::OnRunningStateChanged(
+ int64 version_id,
+ content::ServiceWorkerVersion::RunningStatus running_status) {
+ ServiceWorkerVersionInfo* version = version_info_map_.get(version_id);
+ DCHECK(version);
+ if (version->running_status == running_status)
+ return;
+ version->running_status = running_status;
+ SendVersionInfo(*version);
+ if (IsStoppedAndRedundant(*version))
+ version_info_map_.erase(version_id);
+}
+
+void ServiceWorkerContextWatcher::OnVersionStateChanged(
+ int64 version_id,
+ content::ServiceWorkerVersion::Status status) {
+ ServiceWorkerVersionInfo* version = version_info_map_.get(version_id);
+ DCHECK(version);
+ if (version->status == status)
+ return;
+ version->status = status;
+ SendVersionInfo(*version);
+ if (IsStoppedAndRedundant(*version))
+ version_info_map_.erase(version_id);
+}
+
+void ServiceWorkerContextWatcher::OnMainScriptHttpResponseInfoSet(
+ int64 version_id,
+ base::Time script_response_time,
+ base::Time script_last_modified) {
+ ServiceWorkerVersionInfo* version = version_info_map_.get(version_id);
+ DCHECK(version);
+ version->script_response_time = script_response_time;
+ version->script_last_modified = script_last_modified;
+ SendVersionInfo(*version);
+}
+
+void ServiceWorkerContextWatcher::OnErrorReported(int64 version_id,
+ int process_id,
+ int thread_id,
+ const ErrorInfo& info) {
+ int64 registration_id = kInvalidServiceWorkerRegistrationId;
+ if (ServiceWorkerVersionInfo* version = version_info_map_.get(version_id))
+ registration_id = version->registration_id;
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(error_callback_, registration_id, version_id, info));
+}
+
+void ServiceWorkerContextWatcher::OnReportConsoleMessage(
+ int64 version_id,
+ int process_id,
+ int thread_id,
+ const ConsoleMessage& message) {
+ if (message.message_level != CONSOLE_MESSAGE_LEVEL_ERROR)
+ return;
+ int64 registration_id = kInvalidServiceWorkerRegistrationId;
+ if (ServiceWorkerVersionInfo* version = version_info_map_.get(version_id))
+ registration_id = version->registration_id;
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(error_callback_, registration_id, version_id,
+ ErrorInfo(message.message, message.line_number, -1,
+ message.source_url)));
+}
+
+void ServiceWorkerContextWatcher::OnRegistrationStored(int64 registration_id,
+ const GURL& pattern) {
+ SendRegistrationInfo(registration_id, pattern,
+ ServiceWorkerRegistrationInfo::IS_NOT_DELETED);
+}
+
+void ServiceWorkerContextWatcher::OnRegistrationDeleted(int64 registration_id,
+ const GURL& pattern) {
+ SendRegistrationInfo(registration_id, pattern,
+ ServiceWorkerRegistrationInfo::IS_DELETED);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_context_watcher.h b/chromium/content/browser/service_worker/service_worker_context_watcher.h
new file mode 100644
index 00000000000..9d4bf1f64d9
--- /dev/null
+++ b/chromium/content/browser/service_worker/service_worker_context_watcher.h
@@ -0,0 +1,102 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CONTEXT_WATCHER_H_
+#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CONTEXT_WATCHER_H_
+
+#include <vector>
+
+#include "base/callback.h"
+#include "base/containers/scoped_ptr_hash_map.h"
+#include "content/browser/service_worker/service_worker_context_observer.h"
+#include "content/browser/service_worker/service_worker_info.h"
+
+namespace content {
+
+class ServiceWorkerContextWrapper;
+
+// Used to monitor the status change of the ServiceWorker registrations and
+// versions in the ServiceWorkerContext from UI thread.
+class ServiceWorkerContextWatcher
+ : public ServiceWorkerContextObserver,
+ public base::RefCountedThreadSafe<ServiceWorkerContextWatcher> {
+ public:
+ typedef base::Callback<void(
+ const std::vector<ServiceWorkerRegistrationInfo>&)>
+ WorkerRegistrationUpdatedCallback;
+ typedef base::Callback<void(const std::vector<ServiceWorkerVersionInfo>&)>
+ WorkerVersionUpdatedCallback;
+ typedef base::Callback<void(int64 /* registration_id */,
+ int64 /* version_id */,
+ const ErrorInfo&)> WorkerErrorReportedCallback;
+
+ ServiceWorkerContextWatcher(
+ scoped_refptr<ServiceWorkerContextWrapper> context,
+ const WorkerRegistrationUpdatedCallback& registration_callback,
+ const WorkerVersionUpdatedCallback& version_callback,
+ const WorkerErrorReportedCallback& error_callback);
+ void Start();
+ void Stop();
+
+ private:
+ friend class base::RefCountedThreadSafe<ServiceWorkerContextWatcher>;
+ ~ServiceWorkerContextWatcher() override;
+
+ void GetStoredRegistrationsOnIOThread();
+ void OnStoredRegistrationsOnIOThread(
+ const std::vector<ServiceWorkerRegistrationInfo>& stored_registrations);
+ void StopOnIOThread();
+
+ void StoreRegistrationInfo(
+ const ServiceWorkerRegistrationInfo& registration,
+ base::ScopedPtrHashMap<int64, scoped_ptr<ServiceWorkerRegistrationInfo>>*
+ info_map);
+ void StoreVersionInfo(const ServiceWorkerVersionInfo& version);
+
+ void SendRegistrationInfo(
+ int64 registration_id,
+ const GURL& pattern,
+ ServiceWorkerRegistrationInfo::DeleteFlag delete_flag);
+ void SendVersionInfo(const ServiceWorkerVersionInfo& version);
+
+ // ServiceWorkerContextObserver implements
+ void OnNewLiveRegistration(int64 registration_id,
+ const GURL& pattern) override;
+ void OnNewLiveVersion(int64 version_id,
+ int64 registration_id,
+ const GURL& script_url) override;
+ void OnRunningStateChanged(
+ int64 version_id,
+ content::ServiceWorkerVersion::RunningStatus running_status) override;
+ void OnVersionStateChanged(
+ int64 version_id,
+ content::ServiceWorkerVersion::Status status) override;
+ void OnMainScriptHttpResponseInfoSet(
+ int64 version_id,
+ base::Time script_response_time,
+ base::Time script_last_modified) override;
+ void OnErrorReported(int64 version_id,
+ int process_id,
+ int thread_id,
+ const ErrorInfo& info) override;
+ void OnReportConsoleMessage(int64 version_id,
+ int process_id,
+ int thread_id,
+ const ConsoleMessage& message) override;
+ void OnRegistrationStored(int64 registration_id,
+ const GURL& pattern) override;
+ void OnRegistrationDeleted(int64 registration_id,
+ const GURL& pattern) override;
+
+ base::ScopedPtrHashMap<int64, scoped_ptr<ServiceWorkerVersionInfo>>
+ version_info_map_;
+ scoped_refptr<ServiceWorkerContextWrapper> context_;
+ WorkerRegistrationUpdatedCallback registration_callback_;
+ WorkerVersionUpdatedCallback version_callback_;
+ WorkerErrorReportedCallback error_callback_;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CONTEXT_WATCHER_H_
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 6a4fc0892ee..8df6f4297a8 100644
--- a/chromium/content/browser/service_worker/service_worker_context_wrapper.cc
+++ b/chromium/content/browser/service_worker/service_worker_context_wrapper.cc
@@ -14,17 +14,21 @@
#include "base/files/file_path.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
+#include "base/profiler/scoped_tracker.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/browser/service_worker/service_worker_request_handler.h"
+#include "content/browser/service_worker/service_worker_utils.h"
+#include "content/browser/service_worker/service_worker_version.h"
+#include "content/browser/storage_partition_impl.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.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 "net/base/net_errors.h"
+#include "net/base/net_util.h"
#include "storage/browser/quota/quota_manager_proxy.h"
#include "storage/browser/quota/special_storage_policy.h"
@@ -35,10 +39,43 @@ namespace {
typedef std::set<std::string> HeaderNameSet;
base::LazyInstance<HeaderNameSet> g_excluded_header_name_set =
LAZY_INSTANCE_INITIALIZER;
+
+void RunSoon(const base::Closure& closure) {
+ base::MessageLoop::current()->PostTask(FROM_HERE, closure);
+}
+
+void WorkerStarted(const ServiceWorkerContextWrapper::StatusCallback& callback,
+ ServiceWorkerStatusCode status) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(callback, status));
+}
+
+void StartActiveWorkerOnIO(
+ const ServiceWorkerContextWrapper::StatusCallback& callback,
+ ServiceWorkerStatusCode status,
+ const scoped_refptr<ServiceWorkerRegistration>& registration) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (status == SERVICE_WORKER_OK) {
+ // Pass the reference of |registration| to WorkerStarted callback to prevent
+ // it from being deleted while starting the worker. If the refcount of
+ // |registration| is 1, it will be deleted after WorkerStarted is called.
+ registration->active_version()->StartWorker(
+ base::Bind(WorkerStarted, callback));
+ return;
+ }
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(callback, SERVICE_WORKER_ERROR_NOT_FOUND));
}
+} // namespace
+
void ServiceWorkerContext::AddExcludedHeadersForFetchEvent(
const std::set<std::string>& header_names) {
+ // TODO(pkasting): Remove ScopedTracker below once crbug.com/477117 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "477117 ServiceWorkerContext::AddExcludedHeadersForFetchEvent"));
DCHECK_CURRENTLY_ON(BrowserThread::IO);
g_excluded_header_name_set.Get().insert(header_names.begin(),
header_names.end());
@@ -51,12 +88,24 @@ bool ServiceWorkerContext::IsExcludedHeaderNameForFetchEvent(
g_excluded_header_name_set.Get().end();
}
+ServiceWorkerContext* ServiceWorkerContext::GetServiceWorkerContext(
+ net::URLRequest* request) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ ServiceWorkerRequestHandler* handler =
+ ServiceWorkerRequestHandler::GetHandler(request);
+ if (!handler || !handler->context())
+ return nullptr;
+ return handler->context()->wrapper_;
+}
+
ServiceWorkerContextWrapper::ServiceWorkerContextWrapper(
BrowserContext* browser_context)
: observer_list_(
new ObserverListThreadSafe<ServiceWorkerContextObserver>()),
process_manager_(new ServiceWorkerProcessManager(browser_context)),
- is_incognito_(false) {
+ is_incognito_(false),
+ storage_partition_(nullptr) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
}
ServiceWorkerContextWrapper::~ServiceWorkerContextWrapper() {
@@ -66,18 +115,15 @@ void ServiceWorkerContextWrapper::Init(
const base::FilePath& user_data_directory,
storage::QuotaManagerProxy* quota_manager_proxy,
storage::SpecialStoragePolicy* special_storage_policy) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
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);
- 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,
@@ -86,6 +132,8 @@ void ServiceWorkerContextWrapper::Init(
void ServiceWorkerContextWrapper::Shutdown() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ storage_partition_ = nullptr;
process_manager_->Shutdown();
BrowserThread::PostTask(
BrowserThread::IO,
@@ -95,18 +143,32 @@ void ServiceWorkerContextWrapper::Shutdown() {
void ServiceWorkerContextWrapper::DeleteAndStartOver() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (!context_core_) {
+ // The context could be null due to system shutdown or restart failure. In
+ // either case, we should not have to recover the system, so just return
+ // here.
+ LOG(ERROR) << "ServiceWorkerContextCore is no longer alive.";
+ return;
+ }
context_core_->DeleteAndStartOver(
base::Bind(&ServiceWorkerContextWrapper::DidDeleteAndStartOver, this));
}
-ServiceWorkerContextCore* ServiceWorkerContextWrapper::context() {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- return context_core_.get();
+StoragePartitionImpl* ServiceWorkerContextWrapper::storage_partition() const {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ return storage_partition_;
+}
+
+void ServiceWorkerContextWrapper::set_storage_partition(
+ StoragePartitionImpl* storage_partition) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ storage_partition_ = storage_partition;
}
static void FinishRegistrationOnIO(
const ServiceWorkerContext::ResultCallback& continuation,
ServiceWorkerStatusCode status,
+ const std::string& status_message,
int64 registration_id) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
BrowserThread::PostTask(
@@ -182,6 +244,87 @@ void ServiceWorkerContextWrapper::UnregisterServiceWorker(
base::Bind(&FinishUnregistrationOnIO, continuation));
}
+void ServiceWorkerContextWrapper::UpdateRegistration(const GURL& pattern) {
+ if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&ServiceWorkerContextWrapper::UpdateRegistration, this,
+ pattern));
+ return;
+ }
+ if (!context_core_.get()) {
+ LOG(ERROR) << "ServiceWorkerContextCore is no longer alive.";
+ return;
+ }
+ context_core_->storage()->FindRegistrationForPattern(
+ pattern,
+ base::Bind(&ServiceWorkerContextWrapper::DidFindRegistrationForUpdate,
+ this));
+}
+
+void ServiceWorkerContextWrapper::StartServiceWorker(
+ const GURL& pattern,
+ const StatusCallback& callback) {
+ if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&ServiceWorkerContextWrapper::StartServiceWorker, this,
+ pattern, callback));
+ return;
+ }
+ if (!context_core_.get()) {
+ LOG(ERROR) << "ServiceWorkerContextCore is no longer alive.";
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(callback, SERVICE_WORKER_ERROR_ABORT));
+ return;
+ }
+ context_core_->storage()->FindRegistrationForPattern(
+ pattern, base::Bind(&StartActiveWorkerOnIO, callback));
+}
+
+void ServiceWorkerContextWrapper::SimulateSkipWaiting(int64_t version_id) {
+ if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&ServiceWorkerContextWrapper::SimulateSkipWaiting, this,
+ version_id));
+ return;
+ }
+ if (!context_core_.get()) {
+ LOG(ERROR) << "ServiceWorkerContextCore is no longer alive.";
+ return;
+ }
+ ServiceWorkerVersion* version = GetLiveVersion(version_id);
+ if (!version || version->skip_waiting())
+ return;
+ ServiceWorkerRegistration* registration =
+ GetLiveRegistration(version->registration_id());
+ if (!registration || version != registration->waiting_version())
+ return;
+ version->set_skip_waiting(true);
+ registration->ActivateWaitingVersionWhenReady();
+}
+
+static void DidFindRegistrationForDocument(
+ const net::CompletionCallback& callback,
+ ServiceWorkerStatusCode status,
+ const scoped_refptr<ServiceWorkerRegistration>& registration) {
+ int rv = registration ? net::OK : net::ERR_CACHE_MISS;
+ // Use RunSoon here because FindRegistrationForDocument can complete
+ // immediately but CanHandleMainResourceOffline must be async.
+ RunSoon(base::Bind(callback, rv));
+}
+
+void ServiceWorkerContextWrapper::CanHandleMainResourceOffline(
+ const GURL& url,
+ const GURL& first_party,
+ const net::CompletionCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ context()->storage()->FindRegistrationForDocument(
+ url,
+ base::Bind(&DidFindRegistrationForDocument, callback));
+}
+
void ServiceWorkerContextWrapper::GetAllOriginsInfo(
const GetUsageInfoCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -222,6 +365,43 @@ void ServiceWorkerContextWrapper::DidGetAllRegistrationsForGetAllOrigins(
callback.Run(usage_infos);
}
+void ServiceWorkerContextWrapper::DidFindRegistrationForCheckHasServiceWorker(
+ const GURL& other_url,
+ const CheckHasServiceWorkerCallback& callback,
+ ServiceWorkerStatusCode status,
+ const scoped_refptr<ServiceWorkerRegistration>& registration) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (status != SERVICE_WORKER_OK) {
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(callback, false));
+ return;
+ }
+
+ DCHECK(registration);
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(callback, registration->active_version() &&
+ ServiceWorkerUtils::ScopeMatches(
+ registration->pattern(), other_url)));
+}
+
+void ServiceWorkerContextWrapper::DidFindRegistrationForUpdate(
+ ServiceWorkerStatusCode status,
+ const scoped_refptr<ServiceWorkerRegistration>& registration) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (status != SERVICE_WORKER_OK)
+ return;
+ if (!context_core_.get()) {
+ LOG(ERROR) << "ServiceWorkerContextCore is no longer alive.";
+ return;
+ }
+ DCHECK(registration);
+ context_core_->UpdateServiceWorker(registration.get(),
+ true /* force_bypass_cache */);
+}
+
namespace {
void StatusCodeToBoolCallbackAdapter(
const ServiceWorkerContext::ResultCallback& callback,
@@ -253,6 +433,149 @@ void ServiceWorkerContextWrapper::DeleteForOrigin(const GURL& origin_url) {
DeleteForOrigin(origin_url, base::Bind(&EmptySuccessCallback));
}
+void ServiceWorkerContextWrapper::CheckHasServiceWorker(
+ const GURL& url,
+ const GURL& other_url,
+ const CheckHasServiceWorkerCallback& callback) {
+ if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&ServiceWorkerContextWrapper::CheckHasServiceWorker, this,
+ url, other_url, callback));
+ return;
+ }
+ if (!context_core_.get()) {
+ LOG(ERROR) << "ServiceWorkerContextCore is no longer alive.";
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(callback, false));
+ return;
+ }
+ GURL stripped_url = net::SimplifyUrlForRequest(url);
+ context()->storage()->FindRegistrationForDocument(
+ stripped_url, base::Bind(&ServiceWorkerContextWrapper::
+ DidFindRegistrationForCheckHasServiceWorker,
+ this, other_url, callback));
+}
+
+ServiceWorkerRegistration* ServiceWorkerContextWrapper::GetLiveRegistration(
+ int64_t registration_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (!context_core_)
+ return nullptr;
+ return context_core_->GetLiveRegistration(registration_id);
+}
+
+ServiceWorkerVersion* ServiceWorkerContextWrapper::GetLiveVersion(
+ int64_t version_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (!context_core_)
+ return nullptr;
+ return context_core_->GetLiveVersion(version_id);
+}
+
+std::vector<ServiceWorkerRegistrationInfo>
+ServiceWorkerContextWrapper::GetAllLiveRegistrationInfo() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (!context_core_)
+ return std::vector<ServiceWorkerRegistrationInfo>();
+ return context_core_->GetAllLiveRegistrationInfo();
+}
+
+std::vector<ServiceWorkerVersionInfo>
+ServiceWorkerContextWrapper::GetAllLiveVersionInfo() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (!context_core_)
+ return std::vector<ServiceWorkerVersionInfo>();
+ return context_core_->GetAllLiveVersionInfo();
+}
+
+void ServiceWorkerContextWrapper::FindRegistrationForDocument(
+ const GURL& document_url,
+ const FindRegistrationCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (!context_core_) {
+ // FindRegistrationForDocument() can run the callback synchronously.
+ callback.Run(SERVICE_WORKER_ERROR_ABORT, nullptr);
+ return;
+ }
+ context_core_->storage()->FindRegistrationForDocument(document_url, callback);
+}
+
+void ServiceWorkerContextWrapper::FindRegistrationForId(
+ int64_t registration_id,
+ const GURL& origin,
+ const FindRegistrationCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (!context_core_) {
+ // FindRegistrationForId() can run the callback synchronously.
+ callback.Run(SERVICE_WORKER_ERROR_ABORT, nullptr);
+ return;
+ }
+ context_core_->storage()->FindRegistrationForId(registration_id, origin,
+ callback);
+}
+
+void ServiceWorkerContextWrapper::GetAllRegistrations(
+ const GetRegistrationsInfosCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (!context_core_) {
+ RunSoon(base::Bind(callback, std::vector<ServiceWorkerRegistrationInfo>()));
+ return;
+ }
+ context_core_->storage()->GetAllRegistrations(callback);
+}
+
+void ServiceWorkerContextWrapper::GetRegistrationUserData(
+ int64_t registration_id,
+ const std::string& key,
+ const GetUserDataCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (!context_core_) {
+ RunSoon(base::Bind(callback, std::string(), SERVICE_WORKER_ERROR_ABORT));
+ return;
+ }
+ context_core_->storage()->GetUserData(registration_id, key, callback);
+}
+
+void ServiceWorkerContextWrapper::StoreRegistrationUserData(
+ int64_t registration_id,
+ const GURL& origin,
+ const std::string& key,
+ const std::string& data,
+ const StatusCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (!context_core_) {
+ RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_ABORT));
+ return;
+ }
+ context_core_->storage()->StoreUserData(registration_id, origin, key, data,
+ callback);
+}
+
+void ServiceWorkerContextWrapper::ClearRegistrationUserData(
+ int64_t registration_id,
+ const std::string& key,
+ const StatusCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (!context_core_) {
+ RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_ABORT));
+ return;
+ }
+ context_core_->storage()->ClearUserData(registration_id, key, callback);
+}
+
+void ServiceWorkerContextWrapper::GetUserDataForAllRegistrations(
+ const std::string& key,
+ const GetUserDataForAllRegistrationsCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (!context_core_) {
+ RunSoon(base::Bind(callback, std::vector<std::pair<int64_t, std::string>>(),
+ SERVICE_WORKER_ERROR_ABORT));
+ return;
+ }
+ context_core_->storage()->GetUserDataForAllRegistrations(key, callback);
+}
+
void ServiceWorkerContextWrapper::AddObserver(
ServiceWorkerContextObserver* observer) {
observer_list_->AddObserver(observer);
@@ -263,21 +586,8 @@ 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,
- 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,
@@ -289,19 +599,21 @@ void ServiceWorkerContextWrapper::InitInternal(
base::Bind(&ServiceWorkerContextWrapper::InitInternal,
this,
user_data_directory,
- stores_task_runner,
base::Passed(&database_task_manager),
disk_cache_thread,
make_scoped_refptr(quota_manager_proxy),
make_scoped_refptr(special_storage_policy)));
return;
}
+ // TODO(pkasting): Remove ScopedTracker below once crbug.com/477117 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "477117 ServiceWorkerContextWrapper::InitInternal"));
DCHECK(!context_core_);
if (quota_manager_proxy) {
quota_manager_proxy->RegisterClient(new ServiceWorkerQuotaClient(this));
}
context_core_.reset(new ServiceWorkerContextCore(user_data_directory,
- stores_task_runner,
database_task_manager.Pass(),
disk_cache_thread,
quota_manager_proxy,
@@ -324,6 +636,14 @@ void ServiceWorkerContextWrapper::DidDeleteAndStartOver(
}
context_core_.reset(new ServiceWorkerContextCore(context_core_.get(), this));
DVLOG(1) << "Restarted ServiceWorkerContextCore successfully.";
+
+ observer_list_->Notify(FROM_HERE,
+ &ServiceWorkerContextObserver::OnStorageWiped);
+}
+
+ServiceWorkerContextCore* ServiceWorkerContextWrapper::context() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ return context_core_.get();
}
} // 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 7df3cb093b1..6c3befa008f 100644
--- a/chromium/content/browser/service_worker/service_worker_context_wrapper.h
+++ b/chromium/content/browser/service_worker/service_worker_context_wrapper.h
@@ -20,10 +20,6 @@ class SequencedTaskRunner;
class SingleThreadTaskRunner;
}
-namespace net {
-class URLRequestContextGetter;
-}
-
namespace storage {
class QuotaManagerProxy;
class SpecialStoragePolicy;
@@ -32,9 +28,9 @@ class SpecialStoragePolicy;
namespace content {
class BrowserContext;
-class ChromeBlobStorageContext;
class ServiceWorkerContextCore;
class ServiceWorkerContextObserver;
+class StoragePartitionImpl;
// A refcounted wrapper class for our core object. Higher level content lib
// classes keep references to this class on mutliple threads. The inner core
@@ -44,6 +40,15 @@ class CONTENT_EXPORT ServiceWorkerContextWrapper
: NON_EXPORTED_BASE(public ServiceWorkerContext),
public base::RefCountedThreadSafe<ServiceWorkerContextWrapper> {
public:
+ using StatusCallback = base::Callback<void(ServiceWorkerStatusCode)>;
+ using FindRegistrationCallback =
+ ServiceWorkerStorage::FindRegistrationCallback;
+ using GetRegistrationsInfosCallback =
+ ServiceWorkerStorage::GetRegistrationsInfosCallback;
+ using GetUserDataCallback = ServiceWorkerStorage::GetUserDataCallback;
+ using GetUserDataForAllRegistrationsCallback =
+ ServiceWorkerStorage::GetUserDataForAllRegistrationsCallback;
+
ServiceWorkerContextWrapper(BrowserContext* browser_context);
// Init and Shutdown are for use on the UI thread when the profile,
@@ -58,8 +63,11 @@ class CONTENT_EXPORT ServiceWorkerContextWrapper
// called on the IO thread.
void DeleteAndStartOver();
- // The core context is only for use on the IO thread.
- ServiceWorkerContextCore* context();
+ // The StoragePartition should only be used on the UI thread.
+ // Can be null before/during init and during/after shutdown.
+ StoragePartitionImpl* storage_partition() const;
+
+ void set_storage_partition(StoragePartitionImpl* storage_partition);
// The process manager can be used on either UI or IO.
ServiceWorkerProcessManager* process_manager() {
@@ -72,40 +80,72 @@ class CONTENT_EXPORT ServiceWorkerContextWrapper
const ResultCallback& continuation) override;
void UnregisterServiceWorker(const GURL& pattern,
const ResultCallback& continuation) override;
+ void CanHandleMainResourceOffline(
+ const GURL& url,
+ const GURL& first_party,
+ const net::CompletionCallback& callback) override;
void GetAllOriginsInfo(const GetUsageInfoCallback& callback) override;
void DeleteForOrigin(const GURL& origin_url) override;
+ void CheckHasServiceWorker(
+ const GURL& url,
+ const GURL& other_url,
+ const CheckHasServiceWorkerCallback& callback) override;
+
+ ServiceWorkerRegistration* GetLiveRegistration(int64_t registration_id);
+ ServiceWorkerVersion* GetLiveVersion(int64_t version_id);
+ std::vector<ServiceWorkerRegistrationInfo> GetAllLiveRegistrationInfo();
+ std::vector<ServiceWorkerVersionInfo> GetAllLiveVersionInfo();
+
+ void FindRegistrationForDocument(const GURL& document_url,
+ const FindRegistrationCallback& callback);
+ void FindRegistrationForId(int64_t registration_id,
+ const GURL& origin,
+ const FindRegistrationCallback& callback);
+ void GetAllRegistrations(const GetRegistrationsInfosCallback& callback);
+ void GetRegistrationUserData(int64_t registration_id,
+ const std::string& key,
+ const GetUserDataCallback& callback);
+ void StoreRegistrationUserData(int64_t registration_id,
+ const GURL& origin,
+ const std::string& key,
+ const std::string& data,
+ const StatusCallback& callback);
+ void ClearRegistrationUserData(int64_t registration_id,
+ const std::string& key,
+ const StatusCallback& callback);
+ void GetUserDataForAllRegistrations(
+ const std::string& key,
+ const GetUserDataForAllRegistrationsCallback& callback);
// 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 StartServiceWorker(const GURL& pattern, const StatusCallback& callback);
+ void UpdateRegistration(const GURL& pattern);
+ void SimulateSkipWaiting(int64_t version_id);
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 BackgroundSyncManagerTest;
friend class base::RefCountedThreadSafe<ServiceWorkerContextWrapper>;
friend class EmbeddedWorkerTestHelper;
+ friend class EmbeddedWorkerBrowserTest;
+ friend class ServiceWorkerDispatcherHost;
+ friend class ServiceWorkerInternalsUI;
friend class ServiceWorkerProcessManager;
+ friend class ServiceWorkerRequestHandler;
+ friend class ServiceWorkerVersionBrowserTest;
friend class MockServiceWorkerContextWrapper;
~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,
@@ -118,6 +158,21 @@ class CONTENT_EXPORT ServiceWorkerContextWrapper
const GetUsageInfoCallback& callback,
const std::vector<ServiceWorkerRegistrationInfo>& registrations);
+ void DidFindRegistrationForCheckHasServiceWorker(
+ const GURL& other_url,
+ const CheckHasServiceWorkerCallback& callback,
+ ServiceWorkerStatusCode status,
+ const scoped_refptr<ServiceWorkerRegistration>& registration);
+
+ void DidFindRegistrationForUpdate(
+ ServiceWorkerStatusCode status,
+ const scoped_refptr<content::ServiceWorkerRegistration>& registration);
+
+ // The core context is only for use on the IO thread.
+ // Can be null before/during init, during/after shutdown, and after
+ // DeleteAndStartOver fails.
+ ServiceWorkerContextCore* context();
+
const scoped_refptr<ObserverListThreadSafe<ServiceWorkerContextObserver> >
observer_list_;
const scoped_ptr<ServiceWorkerProcessManager> process_manager_;
@@ -126,6 +181,9 @@ class CONTENT_EXPORT ServiceWorkerContextWrapper
// Initialized in Init(); true if the user data directory is empty.
bool is_incognito_;
+
+ // Raw pointer to the StoragePartitionImpl owning |this|.
+ StoragePartitionImpl* storage_partition_;
};
} // 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 da4bd123f23..4cf50cdf01f 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,7 +4,7 @@
#include "content/browser/service_worker/service_worker_controllee_request_handler.h"
-#include "base/debug/trace_event.h"
+#include "base/trace_event/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"
@@ -87,15 +87,10 @@ 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_,
- request_mode_,
- credentials_mode_,
- request_context_type_,
- frame_type_,
- body_);
+ job_ = new ServiceWorkerURLRequestJob(
+ request, network_delegate, provider_host_, blob_storage_context_,
+ resource_context, request_mode_, credentials_mode_,
+ is_main_resource_load_, request_context_type_, frame_type_, body_);
resource_context_ = resource_context;
if (is_main_resource_load_)
@@ -155,13 +150,12 @@ void ServiceWorkerControlleeRequestHandler::PrepareForMainResource(
// registration while we're finding an existing registration.
provider_host_->SetAllowAssociation(false);
- GURL stripped_url = net::SimplifyUrlForRequest(request->url());
- provider_host_->SetDocumentUrl(stripped_url);
+ 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,
- weak_factory_.GetWeakPtr()));
+ stripped_url_, base::Bind(&self::DidLookupRegistrationForMainResource,
+ weak_factory_.GetWeakPtr()));
}
void
@@ -183,9 +177,9 @@ ServiceWorkerControlleeRequestHandler::DidLookupRegistrationForMainResource(
DCHECK(registration.get());
if (!GetContentClient()->browser()->AllowServiceWorker(
- registration->pattern(),
- provider_host_->topmost_frame_url(),
- resource_context_)) {
+ registration->pattern(), provider_host_->topmost_frame_url(),
+ resource_context_, provider_host_->process_id(),
+ provider_host_->frame_id())) {
job_->FallbackToNetwork();
TRACE_EVENT_ASYNC_END2(
"ServiceWorker",
@@ -237,9 +231,10 @@ ServiceWorkerControlleeRequestHandler::DidLookupRegistrationForMainResource(
return;
}
- ServiceWorkerMetrics::CountControlledPageLoad();
+ ServiceWorkerMetrics::CountControlledPageLoad(stripped_url_);
- provider_host_->AssociateRegistration(registration.get());
+ provider_host_->AssociateRegistration(registration.get(),
+ false /* notify_controllerchange */);
job_->ForwardToServiceWorker();
TRACE_EVENT_ASYNC_END2(
"ServiceWorker",
@@ -262,9 +257,10 @@ void ServiceWorkerControlleeRequestHandler::OnVersionStatusChanged(
return;
}
- ServiceWorkerMetrics::CountControlledPageLoad();
+ ServiceWorkerMetrics::CountControlledPageLoad(stripped_url_);
- provider_host_->AssociateRegistration(registration);
+ provider_host_->AssociateRegistration(registration,
+ false /* notify_controllerchange */);
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 9c2beccba39..d8c328b62ef 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
@@ -12,6 +12,7 @@
#include "content/public/common/request_context_type.h"
#include "content/public/common/resource_type.h"
#include "third_party/WebKit/public/platform/WebServiceWorkerResponseType.h"
+#include "url/gurl.h"
namespace net {
class NetworkDelegate;
@@ -82,6 +83,7 @@ class CONTENT_EXPORT ServiceWorkerControlleeRequestHandler
RequestContextFrameType frame_type_;
scoped_refptr<ResourceRequestBody> body_;
ResourceContext* resource_context_;
+ GURL stripped_url_;
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
index 9a6835addb7..cc8ceaf29d1 100644
--- a/chromium/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
@@ -43,7 +43,8 @@ class ServiceWorkerControlleeRequestHandlerTest : public testing::Test {
: browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
void SetUp() override {
- helper_.reset(new EmbeddedWorkerTestHelper(kMockRenderProcessId));
+ helper_.reset(
+ new EmbeddedWorkerTestHelper(base::FilePath(), kMockRenderProcessId));
// A new unstored registration/version.
scope_ = GURL("http://host/scope/");
@@ -53,10 +54,15 @@ class ServiceWorkerControlleeRequestHandlerTest : public testing::Test {
version_ = new ServiceWorkerVersion(
registration_.get(), script_url_, 1L, context()->AsWeakPtr());
+ std::vector<ServiceWorkerDatabase::ResourceRecord> records;
+ records.push_back(
+ ServiceWorkerDatabase::ResourceRecord(10, version_->script_url(), 100));
+ version_->script_cache_map()->SetResources(records);
+
// An empty host.
scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
- kMockRenderProcessId, kMockProviderId,
- context()->AsWeakPtr(), NULL));
+ kMockRenderProcessId, MSG_ROUTING_NONE, kMockProviderId,
+ SERVICE_WORKER_PROVIDER_FOR_WINDOW, context()->AsWeakPtr(), NULL));
provider_host_ = host->AsWeakPtr();
context()->AddProviderHost(host.Pass());
@@ -90,7 +96,9 @@ class ServiceWorkerTestContentBrowserClient : public TestContentBrowserClient {
ServiceWorkerTestContentBrowserClient() {}
bool AllowServiceWorker(const GURL& scope,
const GURL& first_party,
- content::ResourceContext* context) override {
+ content::ResourceContext* context,
+ int render_process_id,
+ int render_frame_id) override {
return false;
}
};
@@ -102,7 +110,7 @@ TEST_F(ServiceWorkerControlleeRequestHandlerTest, DisallowServiceWorker) {
// Store an activated worker.
version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
- registration_->SetActiveVersion(version_.get());
+ registration_->SetActiveVersion(version_);
context()->storage()->StoreRegistration(
registration_.get(),
version_.get(),
@@ -112,7 +120,7 @@ TEST_F(ServiceWorkerControlleeRequestHandlerTest, DisallowServiceWorker) {
// 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);
+ kDocUrl, net::DEFAULT_PRIORITY, &url_request_delegate_);
scoped_ptr<ServiceWorkerControlleeRequestHandler> handler(
new ServiceWorkerControlleeRequestHandler(
context()->AsWeakPtr(),
@@ -145,7 +153,7 @@ TEST_F(ServiceWorkerControlleeRequestHandlerTest, DisallowServiceWorker) {
TEST_F(ServiceWorkerControlleeRequestHandlerTest, ActivateWaitingVersion) {
// Store a registration that is installed but not activated yet.
version_->SetStatus(ServiceWorkerVersion::INSTALLED);
- registration_->SetWaitingVersion(version_.get());
+ registration_->SetWaitingVersion(version_);
context()->storage()->StoreRegistration(
registration_.get(),
version_.get(),
@@ -155,10 +163,7 @@ TEST_F(ServiceWorkerControlleeRequestHandlerTest, ActivateWaitingVersion) {
// 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);
+ kDocUrl, net::DEFAULT_PRIORITY, &url_request_delegate_);
scoped_ptr<ServiceWorkerControlleeRequestHandler> handler(
new ServiceWorkerControlleeRequestHandler(
context()->AsWeakPtr(),
@@ -197,7 +202,7 @@ 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());
+ registration_->SetActiveVersion(version_);
context()->storage()->StoreRegistration(
registration_.get(),
version_.get(),
@@ -209,10 +214,7 @@ TEST_F(ServiceWorkerControlleeRequestHandlerTest, DeletedProviderHost) {
// 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);
+ kDocUrl, net::DEFAULT_PRIORITY, &url_request_delegate_);
scoped_ptr<ServiceWorkerControlleeRequestHandler> handler(
new ServiceWorkerControlleeRequestHandler(
context()->AsWeakPtr(),
diff --git a/chromium/content/browser/service_worker/service_worker_database.cc b/chromium/content/browser/service_worker/service_worker_database.cc
index 61b8659e77c..c928c38751c 100644
--- a/chromium/content/browser/service_worker/service_worker_database.cc
+++ b/chromium/content/browser/service_worker/service_worker_database.cc
@@ -4,8 +4,6 @@
#include "content/browser/service_worker/service_worker_database.h"
-#include <string>
-
#include "base/files/file_util.h"
#include "base/location.h"
#include "base/logging.h"
@@ -18,6 +16,7 @@
#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/env_chromium.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"
@@ -53,13 +52,26 @@
// (ex. "REG:http://example.com\x00123456")
// value: <ServiceWorkerRegistrationData serialized as a string>
//
+// key: "REG_HAS_USER_DATA:" + <std::string 'user_data_name'> + '\x00'
+// + <int64 'registration_id'>
+// value: <empty>
+//
+// key: "REG_USER_DATA:" + <int64 'registration_id'> + '\x00'
+// + <std::string user_data_name>
+// (ex. "REG_USER_DATA:123456\x00foo_bar")
+// value: <std::string user_data>
+//
// key: "RES:" + <int64 'version_id'> + '\x00' + <int64 'resource_id'>
// (ex. "RES:123456\x00654321")
// value: <ServiceWorkerResourceRecord serialized as a string>
//
// key: "URES:" + <int64 'uncommitted_resource_id'>
// value: <empty>
-
+//
+// Version 2
+//
+// key: "REGID_TO_ORIGIN:" + <int64 'registration_id'>
+// value: <GURL 'origin'>
namespace content {
namespace {
@@ -71,13 +83,16 @@ const char kNextVerIdKey[] = "INITDATA_NEXT_VERSION_ID";
const char kUniqueOriginKey[] = "INITDATA_UNIQUE_ORIGIN:";
const char kRegKeyPrefix[] = "REG:";
+const char kRegUserDataKeyPrefix[] = "REG_USER_DATA:";
+const char kRegHasUserDataKeyPrefix[] = "REG_HAS_USER_DATA:";
+const char kRegIdToOriginKeyPrefix[] = "REGID_TO_ORIGIN:";
const char kResKeyPrefix[] = "RES:";
const char kKeySeparator = '\x00';
const char kUncommittedResIdKeyPrefix[] = "URES:";
const char kPurgeableResIdKeyPrefix[] = "PRES:";
-const int64 kCurrentSchemaVersion = 1;
+const int64 kCurrentSchemaVersion = 2;
bool RemovePrefix(const std::string& str,
const std::string& prefix,
@@ -120,6 +135,34 @@ std::string CreateResourceIdKey(const char* key_prefix, int64 resource_id) {
"%s%s", key_prefix, base::Int64ToString(resource_id).c_str());
}
+std::string CreateUserDataKeyPrefix(int64 registration_id) {
+ return base::StringPrintf("%s%s%c",
+ kRegUserDataKeyPrefix,
+ base::Int64ToString(registration_id).c_str(),
+ kKeySeparator);
+}
+
+std::string CreateUserDataKey(int64 registration_id,
+ const std::string& user_data_name) {
+ return CreateUserDataKeyPrefix(registration_id).append(user_data_name);
+}
+
+std::string CreateHasUserDataKeyPrefix(const std::string& user_data_name) {
+ return base::StringPrintf("%s%s%c", kRegHasUserDataKeyPrefix,
+ user_data_name.c_str(), kKeySeparator);
+}
+
+std::string CreateHasUserDataKey(int64 registration_id,
+ const std::string& user_data_name) {
+ return CreateHasUserDataKeyPrefix(user_data_name)
+ .append(base::Int64ToString(registration_id));
+}
+
+std::string CreateRegistrationIdToOriginKey(int64 registration_id) {
+ return base::StringPrintf("%s%s", kRegIdToOriginKeyPrefix,
+ base::Int64ToString(registration_id).c_str());
+}
+
void PutRegistrationDataToBatch(
const ServiceWorkerDatabase::RegistrationData& input,
leveldb::WriteBatch* batch) {
@@ -271,6 +314,14 @@ ServiceWorkerDatabase::Status LevelDBStatusToStatus(
return ServiceWorkerDatabase::STATUS_ERROR_FAILED;
}
+int64_t AccumulateResourceSizeInBytes(
+ const std::vector<ServiceWorkerDatabase::ResourceRecord>& resources) {
+ int64_t total_size_bytes = 0;
+ for (const auto& resource : resources)
+ total_size_bytes += resource.size_bytes;
+ return total_size_bytes;
+}
+
} // namespace
const char* ServiceWorkerDatabase::StatusToString(
@@ -473,7 +524,9 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::ReadRegistration(
DCHECK(resources);
Status status = LazyOpen(false);
- if (IsNewOrNonexistentDatabase(status) || status != STATUS_OK)
+ if (IsNewOrNonexistentDatabase(status))
+ return STATUS_ERROR_NOT_FOUND;
+ if (status != STATUS_OK)
return status;
RegistrationData value;
@@ -485,10 +538,48 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::ReadRegistration(
if (status != STATUS_OK)
return status;
+ // ResourceRecord must contain the ServiceWorker's main script.
+ if (resources->empty())
+ return ServiceWorkerDatabase::STATUS_ERROR_CORRUPTED;
+
*registration = value;
return STATUS_OK;
}
+ServiceWorkerDatabase::Status ServiceWorkerDatabase::ReadRegistrationOrigin(
+ int64 registration_id,
+ GURL* origin) {
+ DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+ DCHECK(origin);
+
+ Status status = LazyOpen(true);
+ if (IsNewOrNonexistentDatabase(status))
+ return STATUS_ERROR_NOT_FOUND;
+ if (status != STATUS_OK)
+ return status;
+
+ std::string value;
+ status = LevelDBStatusToStatus(
+ db_->Get(leveldb::ReadOptions(),
+ CreateRegistrationIdToOriginKey(registration_id), &value));
+ if (status != STATUS_OK) {
+ HandleReadResult(FROM_HERE,
+ status == STATUS_ERROR_NOT_FOUND ? STATUS_OK : status);
+ return status;
+ }
+
+ GURL parsed(value);
+ if (!parsed.is_valid()) {
+ status = STATUS_ERROR_CORRUPTED;
+ HandleReadResult(FROM_HERE, status);
+ return status;
+ }
+
+ *origin = parsed;
+ HandleReadResult(FROM_HERE, STATUS_OK);
+ return STATUS_OK;
+}
+
ServiceWorkerDatabase::Status ServiceWorkerDatabase::WriteRegistration(
const RegistrationData& registration,
const std::vector<ResourceRecord>& resources,
@@ -496,6 +587,7 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::WriteRegistration(
std::vector<int64>* newly_purgeable_resources) {
DCHECK(sequence_checker_.CalledOnValidSequencedThread());
DCHECK(old_registration);
+ DCHECK(!resources.empty());
Status status = LazyOpen(true);
old_registration->version_id = kInvalidServiceWorkerVersionId;
if (status != STATUS_OK)
@@ -506,16 +598,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)
+
+ DCHECK_EQ(AccumulateResourceSizeInBytes(resources),
+ registration.resources_total_size_bytes)
<< "The total size in the registration must match the cumulative "
<< "sizes of the resources.";
-#endif
+
PutRegistrationDataToBatch(registration, &batch);
+ batch.Put(CreateRegistrationIdToOriginKey(registration.registration_id),
+ registration.scope.GetOrigin().spec());
// Used for avoiding multiple writes for the same resource id or url.
std::set<int64> pushed_resources;
@@ -646,8 +737,9 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::DeleteRegistration(
// Delete a registration specified by |registration_id|.
batch.Delete(CreateRegistrationKey(registration_id, origin));
+ batch.Delete(CreateRegistrationIdToOriginKey(registration_id));
- // Delete resource records associated with the registration.
+ // Delete resource records and user data associated with the registration.
for (const auto& registration : registrations) {
if (registration.registration_id == registration_id) {
*deleted_version = registration;
@@ -655,6 +747,10 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::DeleteRegistration(
registration.version_id, newly_purgeable_resources, &batch);
if (status != STATUS_OK)
return status;
+
+ status = DeleteUserDataForRegistration(registration_id, &batch);
+ if (status != STATUS_OK)
+ return status;
break;
}
}
@@ -662,6 +758,128 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::DeleteRegistration(
return WriteBatch(&batch);
}
+ServiceWorkerDatabase::Status ServiceWorkerDatabase::ReadUserData(
+ int64 registration_id,
+ const std::string& user_data_name,
+ std::string* user_data) {
+ DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+ DCHECK_NE(kInvalidServiceWorkerRegistrationId, registration_id);
+ DCHECK(!user_data_name.empty());
+ DCHECK(user_data);
+
+ Status status = LazyOpen(false);
+ if (IsNewOrNonexistentDatabase(status))
+ return STATUS_ERROR_NOT_FOUND;
+ if (status != STATUS_OK)
+ return status;
+
+ const std::string key = CreateUserDataKey(registration_id, user_data_name);
+ status = LevelDBStatusToStatus(
+ db_->Get(leveldb::ReadOptions(), key, user_data));
+ HandleReadResult(FROM_HERE,
+ status == STATUS_ERROR_NOT_FOUND ? STATUS_OK : status);
+ return status;
+}
+
+ServiceWorkerDatabase::Status ServiceWorkerDatabase::WriteUserData(
+ int64 registration_id,
+ const GURL& origin,
+ const std::string& user_data_name,
+ const std::string& user_data) {
+ DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+ DCHECK_NE(kInvalidServiceWorkerRegistrationId, registration_id);
+ DCHECK(!user_data_name.empty());
+
+ Status status = LazyOpen(false);
+ if (IsNewOrNonexistentDatabase(status))
+ return STATUS_ERROR_NOT_FOUND;
+ if (status != STATUS_OK)
+ return status;
+
+ // There should be the registration specified by |registration_id|.
+ RegistrationData registration;
+ status = ReadRegistrationData(registration_id, origin, &registration);
+ if (status != STATUS_OK)
+ return status;
+
+ leveldb::WriteBatch batch;
+ batch.Put(CreateUserDataKey(registration_id, user_data_name), user_data);
+ batch.Put(CreateHasUserDataKey(registration_id, user_data_name), "");
+ return WriteBatch(&batch);
+}
+
+ServiceWorkerDatabase::Status ServiceWorkerDatabase::DeleteUserData(
+ int64 registration_id,
+ const std::string& user_data_name) {
+ DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+ DCHECK_NE(kInvalidServiceWorkerRegistrationId, registration_id);
+ DCHECK(!user_data_name.empty());
+
+ Status status = LazyOpen(false);
+ if (IsNewOrNonexistentDatabase(status))
+ return STATUS_OK;
+ if (status != STATUS_OK)
+ return status;
+
+ leveldb::WriteBatch batch;
+ batch.Delete(CreateUserDataKey(registration_id, user_data_name));
+ batch.Delete(CreateHasUserDataKey(registration_id, user_data_name));
+ return WriteBatch(&batch);
+}
+
+ServiceWorkerDatabase::Status
+ServiceWorkerDatabase::ReadUserDataForAllRegistrations(
+ const std::string& user_data_name,
+ std::vector<std::pair<int64, std::string>>* user_data) {
+ DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+ DCHECK(user_data->empty());
+
+ Status status = LazyOpen(false);
+ if (IsNewOrNonexistentDatabase(status))
+ return STATUS_OK;
+ if (status != STATUS_OK)
+ return status;
+
+ std::string key_prefix = CreateHasUserDataKeyPrefix(user_data_name);
+ scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions()));
+ for (itr->Seek(key_prefix); itr->Valid(); itr->Next()) {
+ status = LevelDBStatusToStatus(itr->status());
+ if (status != STATUS_OK) {
+ HandleReadResult(FROM_HERE, status);
+ user_data->clear();
+ return status;
+ }
+
+ std::string registration_id_string;
+ if (!RemovePrefix(itr->key().ToString(), key_prefix,
+ &registration_id_string)) {
+ break;
+ }
+
+ int64 registration_id;
+ status = ParseId(registration_id_string, &registration_id);
+ if (status != STATUS_OK) {
+ HandleReadResult(FROM_HERE, status);
+ user_data->clear();
+ return status;
+ }
+
+ std::string value;
+ status = LevelDBStatusToStatus(
+ db_->Get(leveldb::ReadOptions(),
+ CreateUserDataKey(registration_id, user_data_name), &value));
+ if (status != STATUS_OK) {
+ HandleReadResult(FROM_HERE, status);
+ user_data->clear();
+ return status;
+ }
+ user_data->push_back(std::make_pair(registration_id, value));
+ }
+
+ HandleReadResult(FROM_HERE, status);
+ return status;
+}
+
ServiceWorkerDatabase::Status
ServiceWorkerDatabase::GetUncommittedResourceIds(std::set<int64>* ids) {
return ReadResourceIds(kUncommittedResIdKeyPrefix, ids);
@@ -729,13 +947,19 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::DeleteAllDataForOrigins(
if (status != STATUS_OK)
return status;
- // Delete registrations and resource records.
+ // Delete registrations, resource records and user data.
for (const RegistrationData& data : registrations) {
batch.Delete(CreateRegistrationKey(data.registration_id, origin));
+ batch.Delete(CreateRegistrationIdToOriginKey(data.registration_id));
+
status = DeleteResourceRecords(
data.version_id, newly_purgeable_resources, &batch);
if (status != STATUS_OK)
return status;
+
+ status = DeleteUserDataForRegistration(data.registration_id, &batch);
+ if (status != STATUS_OK)
+ return status;
}
}
@@ -756,8 +980,10 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::DestroyDatabase() {
}
}
- return LevelDBStatusToStatus(
- leveldb::DestroyDB(path_.AsUTF8Unsafe(), options));
+ Status status =
+ LevelDBStatusToStatus(leveldb::DestroyDB(path_.AsUTF8Unsafe(), options));
+ ServiceWorkerMetrics::RecordDestroyDatabaseResult(status);
+ return status;
}
ServiceWorkerDatabase::Status ServiceWorkerDatabase::LazyOpen(
@@ -784,6 +1010,7 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::LazyOpen(
leveldb::Options options;
options.create_if_missing = create_if_missing;
+ options.reuse_logs = leveldb_env::kDefaultLogReuseOptionValue;
if (use_in_memory_db) {
env_.reset(leveldb::NewMemEnv(leveldb::Env::Default()));
options.env = env_.get();
@@ -805,6 +1032,21 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::LazyOpen(
if (status != STATUS_OK)
return status;
DCHECK_LE(0, db_version);
+
+ if (db_version > 0 && db_version < kCurrentSchemaVersion) {
+ switch (db_version) {
+ case 1:
+ status = UpgradeDatabaseSchemaFromV1ToV2();
+ if (status != STATUS_OK)
+ return status;
+ db_version = 2;
+ // Intentionally fall-through to other version upgrade cases.
+ }
+ // Either the database got upgraded to the current schema version, or some
+ // upgrade step failed which would have caused this method to abort.
+ DCHECK_EQ(db_version, kCurrentSchemaVersion);
+ }
+
if (db_version > 0)
state_ = INITIALIZED;
return STATUS_OK;
@@ -819,6 +1061,51 @@ bool ServiceWorkerDatabase::IsNewOrNonexistentDatabase(
return false;
}
+ServiceWorkerDatabase::Status
+ServiceWorkerDatabase::UpgradeDatabaseSchemaFromV1ToV2() {
+ Status status = STATUS_OK;
+ leveldb::WriteBatch batch;
+
+ // Version 2 introduced REGID_TO_ORIGIN, add for all existing registrations.
+ scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions()));
+ for (itr->Seek(kRegKeyPrefix); itr->Valid(); itr->Next()) {
+ status = LevelDBStatusToStatus(itr->status());
+ if (status != STATUS_OK) {
+ HandleReadResult(FROM_HERE, status);
+ return status;
+ }
+
+ std::string key;
+ if (!RemovePrefix(itr->key().ToString(), kRegKeyPrefix, &key))
+ break;
+
+ std::vector<std::string> parts;
+ base::SplitStringDontTrim(key, kKeySeparator, &parts);
+ if (parts.size() != 2) {
+ status = STATUS_ERROR_CORRUPTED;
+ HandleReadResult(FROM_HERE, status);
+ return status;
+ }
+
+ int64 registration_id;
+ status = ParseId(parts[1], &registration_id);
+ if (status != STATUS_OK) {
+ HandleReadResult(FROM_HERE, status);
+ return status;
+ }
+
+ batch.Put(CreateRegistrationIdToOriginKey(registration_id), parts[0]);
+ }
+
+ // Update schema version manually instead of relying on WriteBatch to make
+ // sure each upgrade step only updates it to the actually correct version.
+ batch.Put(kDatabaseVersionKey, base::Int64ToString(2));
+ status = LevelDBStatusToStatus(
+ db_->Write(leveldb::WriteOptions(), &batch));
+ HandleWriteResult(FROM_HERE, status);
+ return status;
+}
+
ServiceWorkerDatabase::Status ServiceWorkerDatabase::ReadNextAvailableId(
const char* id_key,
int64* next_avail_id) {
@@ -1044,6 +1331,32 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::DeleteResourceIdsInBatch(
return STATUS_OK;
}
+ServiceWorkerDatabase::Status
+ServiceWorkerDatabase::DeleteUserDataForRegistration(
+ int64 registration_id,
+ leveldb::WriteBatch* batch) {
+ DCHECK(batch);
+ Status status = STATUS_OK;
+ const std::string prefix = CreateUserDataKeyPrefix(registration_id);
+
+ scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions()));
+ for (itr->Seek(prefix); itr->Valid(); itr->Next()) {
+ status = LevelDBStatusToStatus(itr->status());
+ if (status != STATUS_OK) {
+ HandleReadResult(FROM_HERE, status);
+ return status;
+ }
+
+ const std::string key = itr->key().ToString();
+ std::string user_data_name;
+ if (!RemovePrefix(key, prefix, &user_data_name))
+ break;
+ batch->Delete(key);
+ batch->Delete(CreateHasUserDataKey(registration_id, user_data_name));
+ }
+ return status;
+}
+
ServiceWorkerDatabase::Status ServiceWorkerDatabase::ReadDatabaseVersion(
int64* db_version) {
std::string value;
diff --git a/chromium/content/browser/service_worker/service_worker_database.h b/chromium/content/browser/service_worker/service_worker_database.h
index 96283c95bd6..13c0ed480a2 100644
--- a/chromium/content/browser/service_worker/service_worker_database.h
+++ b/chromium/content/browser/service_worker/service_worker_database.h
@@ -7,6 +7,7 @@
#include <map>
#include <set>
+#include <string>
#include <vector>
#include "base/files/file_path.h"
@@ -120,6 +121,11 @@ class CONTENT_EXPORT ServiceWorkerDatabase {
RegistrationData* registration,
std::vector<ResourceRecord>* resources);
+ // Looks up the origin for the registration with |registration_id|. Returns OK
+ // if a registration was found and read successfully. Otherwise, returns an
+ // error.
+ Status ReadRegistrationOrigin(int64 registration_id, GURL* origin);
+
// Writes |registration| and |resources| into the database and does following
// things:
// - If an old version of the registration exists, deletes it and sets
@@ -158,6 +164,31 @@ class CONTENT_EXPORT ServiceWorkerDatabase {
RegistrationData* deleted_version,
std::vector<int64>* newly_purgeable_resources);
+ // Reads user data for |registration_id| and |user_data_name| from the
+ // database.
+ Status ReadUserData(int64 registration_id,
+ const std::string& user_data_name,
+ std::string* user_data);
+
+ // Writes |user_data| into the database. Returns NOT_FOUND if the registration
+ // specified by |registration_id| does not exist in the database.
+ Status WriteUserData(int64 registration_id,
+ const GURL& origin,
+ const std::string& user_data_name,
+ const std::string& user_data);
+
+ // Deletes user data for |registration_id| and |user_data_name| from the
+ // database. Returns OK if it's successfully deleted or not found in the
+ // database.
+ Status DeleteUserData(int64 registration_id,
+ const std::string& user_data_name);
+
+ // Reads user data for all registrations that have data with |user_data_name|
+ // from the database. Returns OK if they are successfully read or not found.
+ Status ReadUserDataForAllRegistrations(
+ const std::string& user_data_name,
+ std::vector<std::pair<int64, std::string>>* user_data);
+
// 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
// removed from that list. When a resource no longer has any registrations or
@@ -216,6 +247,10 @@ class CONTENT_EXPORT ServiceWorkerDatabase {
// the database is new or nonexistent, that is, it has never been used.
bool IsNewOrNonexistentDatabase(Status status);
+ // Upgrades the database schema from version 1 to version 2. Called by
+ // LazyOpen() when the stored schema is older than version 2.
+ Status UpgradeDatabaseSchemaFromV1ToV2();
+
// Reads the next available id for |id_key|. Returns OK if it's successfully
// read. Fills |next_avail_id| with an initial value and returns OK if it's
// not found in the database. Otherwise, returns an error.
@@ -273,6 +308,12 @@ class CONTENT_EXPORT ServiceWorkerDatabase {
const std::set<int64>& ids,
leveldb::WriteBatch* batch);
+ // Deletes all user data for |registration_id| from the database. Returns OK
+ // if they are successfully deleted or not found in the database.
+ Status DeleteUserDataForRegistration(
+ int64 registration_id,
+ leveldb::WriteBatch* batch);
+
// Reads the current schema version from the database. If the database hasn't
// been written anything yet, sets |db_version| to 0 and returns OK.
Status ReadDatabaseVersion(int64* db_version);
@@ -330,7 +371,12 @@ class CONTENT_EXPORT ServiceWorkerDatabase {
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest, OpenDatabase_InMemory);
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest, DatabaseVersion);
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest, GetNextAvailableIds);
+ FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest,
+ Registration_UninitializedDatabase);
+ FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest,
+ UserData_UninitializedDatabase);
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest, DestroyDatabase);
+ FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest, UpgradeSchemaToVersion2);
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerDatabase);
};
diff --git a/chromium/content/browser/service_worker/service_worker_database_task_manager.h b/chromium/content/browser/service_worker/service_worker_database_task_manager.h
index fdf13f97228..a54b252accf 100644
--- a/chromium/content/browser/service_worker/service_worker_database_task_manager.h
+++ b/chromium/content/browser/service_worker/service_worker_database_task_manager.h
@@ -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_SERVICE_WORKER_SERVICE_WORKER_DATABASE_TASK_RUNNER_MANAGER_
-#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_DATABASE_TASK_RUNNER_MANAGER_
+#ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_DATABASE_TASK_MANAGER_H_
+#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_DATABASE_TASK_MANAGER_H_
#include "base/memory/ref_counted.h"
#include "content/common/content_export.h"
@@ -72,4 +72,4 @@ class CONTENT_EXPORT MockServiceWorkerDatabaseTaskManager
} // namespace content
-#endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_DATABASE_TASK_RUNNER_MANAGER_
+#endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_DATABASE_TASK_MANAGER_H_
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 0e052f5ff20..84424f7d980 100644
--- a/chromium/content/browser/service_worker/service_worker_database_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_database_unittest.cc
@@ -9,9 +9,11 @@
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.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"
+#include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
namespace content {
@@ -107,6 +109,7 @@ TEST(ServiceWorkerDatabaseTest, OpenDatabase_InMemory) {
}
TEST(ServiceWorkerDatabaseTest, DatabaseVersion) {
+ GURL origin("http://example.com");
scoped_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory());
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->LazyOpen(true));
@@ -120,9 +123,11 @@ TEST(ServiceWorkerDatabaseTest, DatabaseVersion) {
// First writing triggers database initialization and bumps the schema
// version.
std::vector<ServiceWorkerDatabase::ResourceRecord> resources;
+ resources.push_back(CreateResource(1, URL(origin, "/resource"), 10));
ServiceWorkerDatabase::RegistrationData deleted_version;
std::vector<int64> newly_purgeable_resources;
ServiceWorkerDatabase::RegistrationData data;
+ data.resources_total_size_bytes = 10;
ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
database->WriteRegistration(
data, resources, &deleted_version, &newly_purgeable_resources));
@@ -132,6 +137,64 @@ TEST(ServiceWorkerDatabaseTest, DatabaseVersion) {
EXPECT_LT(0, db_version);
}
+TEST(ServiceWorkerDatabaseTest, UpgradeSchemaToVersion2) {
+ base::ScopedTempDir database_dir;
+ ASSERT_TRUE(database_dir.CreateUniqueTempDir());
+ scoped_ptr<ServiceWorkerDatabase> database(
+ CreateDatabase(database_dir.path()));
+
+ GURL origin("http://example.com");
+
+ // Add a registration to the database.
+ std::vector<ServiceWorkerDatabase::ResourceRecord> resources;
+ ServiceWorkerDatabase::RegistrationData deleted_version;
+ std::vector<int64> newly_purgeable_resources;
+ ServiceWorkerDatabase::RegistrationData data;
+ data.registration_id = 100;
+ data.scope = URL(origin, "/foo");
+ data.script = URL(origin, "/script1.js");
+ data.version_id = 200;
+ data.resources_total_size_bytes = 300;
+ resources.push_back(CreateResource(1, data.script, 300));
+ ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(data, resources, &deleted_version,
+ &newly_purgeable_resources));
+
+ // Sanity check on current version.
+ int64 db_version = -1;
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->ReadDatabaseVersion(&db_version));
+ EXPECT_LE(2, db_version);
+
+ // Now delete the data that will be created in an upgrade to schema version 2,
+ // and reset the schema version to 1.
+ leveldb::WriteBatch batch;
+ batch.Delete("REGID_TO_ORIGIN:" + base::Int64ToString(data.registration_id));
+ batch.Put("INITDATA_DB_VERSION", base::Int64ToString(1));
+ ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, database->WriteBatch(&batch));
+
+ // Make sure correct data got deleted.
+ GURL origin_out;
+ EXPECT_EQ(
+ ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND,
+ database->ReadRegistrationOrigin(data.registration_id, &origin_out));
+
+ // Close and reopen the database to verify the schema got updated.
+ database.reset(CreateDatabase(database_dir.path()));
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->LazyOpen(true));
+
+ // Verify version number.
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->ReadDatabaseVersion(&db_version));
+ EXPECT_LE(2, db_version);
+
+ // And check that looking up origin for registration works.
+ EXPECT_EQ(
+ ServiceWorkerDatabase::STATUS_OK,
+ database->ReadRegistrationOrigin(data.registration_id, &origin_out));
+ EXPECT_EQ(origin, origin_out);
+}
+
TEST(ServiceWorkerDatabaseTest, GetNextAvailableIds) {
base::ScopedTempDir database_dir;
ASSERT_TRUE(database_dir.CreateUniqueTempDir());
@@ -156,7 +219,7 @@ TEST(ServiceWorkerDatabaseTest, GetNextAvailableIds) {
EXPECT_EQ(0, ids.res_id);
// Writing a registration bumps the next available ids.
- std::vector<Resource> resources;
+ std::vector<Resource> resources1;
RegistrationData data1;
ServiceWorkerDatabase::RegistrationData deleted_version;
std::vector<int64> newly_purgeable_resources;
@@ -164,10 +227,11 @@ TEST(ServiceWorkerDatabaseTest, GetNextAvailableIds) {
data1.scope = URL(origin, "/foo");
data1.script = URL(origin, "/script1.js");
data1.version_id = 200;
- ASSERT_EQ(
- ServiceWorkerDatabase::STATUS_OK,
- database->WriteRegistration(
- data1, resources, &deleted_version, &newly_purgeable_resources));
+ data1.resources_total_size_bytes = 300;
+ resources1.push_back(CreateResource(1, data1.script, 300));
+ ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(data1, resources1, &deleted_version,
+ &newly_purgeable_resources));
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->GetNextAvailableIds(
&ids.reg_id, &ids.ver_id, &ids.res_id));
@@ -207,10 +271,12 @@ 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, &deleted_version, &newly_purgeable_resources));
+ data2.resources_total_size_bytes = 400;
+ std::vector<Resource> resources2;
+ resources2.push_back(CreateResource(2, data2.script, 400));
+ ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(data2, resources2, &deleted_version,
+ &newly_purgeable_resources));
// Same with resources.
int64 kLowResourceId = 15;
@@ -236,7 +302,6 @@ TEST(ServiceWorkerDatabaseTest, GetOriginsWithRegistrations) {
database->GetOriginsWithRegistrations(&origins));
EXPECT_TRUE(origins.empty());
- std::vector<Resource> resources;
ServiceWorkerDatabase::RegistrationData deleted_version;
std::vector<int64> newly_purgeable_resources;
@@ -246,10 +311,12 @@ 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, &deleted_version, &newly_purgeable_resources));
+ data1.resources_total_size_bytes = 100;
+ std::vector<Resource> resources1;
+ resources1.push_back(CreateResource(1, data1.script, 100));
+ ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(data1, resources1, &deleted_version,
+ &newly_purgeable_resources));
GURL origin2("https://www.example.com");
RegistrationData data2;
@@ -257,10 +324,12 @@ 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, &deleted_version, &newly_purgeable_resources));
+ data2.resources_total_size_bytes = 200;
+ std::vector<Resource> resources2;
+ resources2.push_back(CreateResource(2, data2.script, 200));
+ ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(data2, resources2, &deleted_version,
+ &newly_purgeable_resources));
GURL origin3("https://example.org");
RegistrationData data3;
@@ -268,10 +337,12 @@ 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, &deleted_version, &newly_purgeable_resources));
+ data3.resources_total_size_bytes = 300;
+ std::vector<Resource> resources3;
+ resources3.push_back(CreateResource(3, data3.script, 300));
+ ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(data3, resources3, &deleted_version,
+ &newly_purgeable_resources));
// |origin3| has two registrations.
RegistrationData data4;
@@ -279,10 +350,12 @@ 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, &deleted_version, &newly_purgeable_resources));
+ data4.resources_total_size_bytes = 400;
+ std::vector<Resource> resources4;
+ resources4.push_back(CreateResource(4, data4.script, 400));
+ ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(data4, resources4, &deleted_version,
+ &newly_purgeable_resources));
origins.clear();
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
@@ -337,7 +410,6 @@ TEST(ServiceWorkerDatabaseTest, GetRegistrationsForOrigin) {
database->GetRegistrationsForOrigin(origin1, &registrations));
EXPECT_TRUE(registrations.empty());
- std::vector<Resource> resources;
ServiceWorkerDatabase::RegistrationData deleted_version;
std::vector<int64> newly_purgeable_resources;
@@ -346,30 +418,36 @@ 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, &deleted_version, &newly_purgeable_resources));
+ data1.resources_total_size_bytes = 100;
+ std::vector<Resource> resources1;
+ resources1.push_back(CreateResource(1, data1.script, 100));
+ ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(data1, resources1, &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, &deleted_version, &newly_purgeable_resources));
+ data2.resources_total_size_bytes = 200;
+ std::vector<Resource> resources2;
+ resources2.push_back(CreateResource(2, data2.script, 200));
+ ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(data2, resources2, &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, &deleted_version, &newly_purgeable_resources));
+ data3.resources_total_size_bytes = 300;
+ std::vector<Resource> resources3;
+ resources3.push_back(CreateResource(3, data3.script, 300));
+ ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(data3, resources3, &deleted_version,
+ &newly_purgeable_resources));
// |origin3| has two registrations.
RegistrationData data4;
@@ -377,10 +455,12 @@ 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, &deleted_version, &newly_purgeable_resources));
+ data4.resources_total_size_bytes = 400;
+ std::vector<Resource> resources4;
+ resources4.push_back(CreateResource(4, data4.script, 400));
+ ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(data4, resources4, &deleted_version,
+ &newly_purgeable_resources));
registrations.clear();
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
@@ -398,7 +478,6 @@ TEST(ServiceWorkerDatabaseTest, GetAllRegistrations) {
database->GetAllRegistrations(&registrations));
EXPECT_TRUE(registrations.empty());
- std::vector<Resource> resources;
ServiceWorkerDatabase::RegistrationData deleted_version;
std::vector<int64> newly_purgeable_resources;
@@ -408,10 +487,12 @@ 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, &deleted_version, &newly_purgeable_resources));
+ data1.resources_total_size_bytes = 100;
+ std::vector<Resource> resources1;
+ resources1.push_back(CreateResource(1, data1.script, 100));
+ ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(data1, resources1, &deleted_version,
+ &newly_purgeable_resources));
GURL origin2("http://www2.example.com");
RegistrationData data2;
@@ -419,10 +500,12 @@ 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, &deleted_version, &newly_purgeable_resources));
+ data2.resources_total_size_bytes = 200;
+ std::vector<Resource> resources2;
+ resources2.push_back(CreateResource(2, data2.script, 200));
+ ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(data2, resources2, &deleted_version,
+ &newly_purgeable_resources));
GURL origin3("http://www3.example.com");
RegistrationData data3;
@@ -430,10 +513,12 @@ 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, &deleted_version, &newly_purgeable_resources));
+ data3.resources_total_size_bytes = 300;
+ std::vector<Resource> resources3;
+ resources3.push_back(CreateResource(3, data3.script, 300));
+ ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(data3, resources3, &deleted_version,
+ &newly_purgeable_resources));
// |origin3| has two registrations.
RegistrationData data4;
@@ -441,10 +526,12 @@ 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, &deleted_version, &newly_purgeable_resources));
+ data4.resources_total_size_bytes = 400;
+ std::vector<Resource> resources4;
+ resources4.push_back(CreateResource(4, data4.script, 400));
+ ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(data4, resources4, &deleted_version,
+ &newly_purgeable_resources));
registrations.clear();
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
@@ -498,9 +585,14 @@ TEST(ServiceWorkerDatabaseTest, Registration_Basic) {
std::vector<Resource> resources_out;
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
database->ReadRegistration(
- data.registration_id, origin, &data_out, &resources_out));
+ data.registration_id, origin, &data_out, &resources_out));
VerifyRegistrationData(data, data_out);
VerifyResourceRecords(resources, resources_out);
+ GURL origin_out;
+ EXPECT_EQ(
+ ServiceWorkerDatabase::STATUS_OK,
+ database->ReadRegistrationOrigin(data.registration_id, &origin_out));
+ EXPECT_EQ(origin, origin_out);
// Make sure that the resource is removed from the uncommitted list.
uncommitted_ids_out.clear();
@@ -524,6 +616,9 @@ TEST(ServiceWorkerDatabaseTest, Registration_Basic) {
database->ReadRegistration(
data.registration_id, origin, &data_out, &resources_out));
EXPECT_TRUE(resources_out.empty());
+ EXPECT_EQ(
+ ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND,
+ database->ReadRegistrationOrigin(data.registration_id, &origin_out));
// Resources should be purgeable because these are no longer referred.
std::set<int64> purgeable_ids_out;
@@ -698,6 +793,11 @@ TEST(ServiceWorkerDatabaseTest, Registration_Multiple) {
data1.registration_id, origin, &data_out, &resources_out));
VerifyRegistrationData(data1, data_out);
VerifyResourceRecords(resources1, resources_out);
+ GURL origin_out;
+ EXPECT_EQ(
+ ServiceWorkerDatabase::STATUS_OK,
+ database->ReadRegistrationOrigin(data1.registration_id, &origin_out));
+ EXPECT_EQ(origin, origin_out);
// Make sure that registration2 is also stored.
resources_out.clear();
@@ -705,6 +805,10 @@ TEST(ServiceWorkerDatabaseTest, Registration_Multiple) {
data2.registration_id, origin, &data_out, &resources_out));
VerifyRegistrationData(data2, data_out);
VerifyResourceRecords(resources2, resources_out);
+ EXPECT_EQ(
+ ServiceWorkerDatabase::STATUS_OK,
+ database->ReadRegistrationOrigin(data2.registration_id, &origin_out));
+ EXPECT_EQ(origin, origin_out);
std::set<int64> purgeable_ids_out;
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
@@ -725,6 +829,9 @@ TEST(ServiceWorkerDatabaseTest, Registration_Multiple) {
database->ReadRegistration(
data1.registration_id, origin, &data_out, &resources_out));
EXPECT_TRUE(resources_out.empty());
+ EXPECT_EQ(
+ ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND,
+ database->ReadRegistrationOrigin(data1.registration_id, &origin_out));
purgeable_ids_out.clear();
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
@@ -739,6 +846,324 @@ TEST(ServiceWorkerDatabaseTest, Registration_Multiple) {
data2.registration_id, origin, &data_out, &resources_out));
VerifyRegistrationData(data2, data_out);
VerifyResourceRecords(resources2, resources_out);
+ EXPECT_EQ(
+ ServiceWorkerDatabase::STATUS_OK,
+ database->ReadRegistrationOrigin(data2.registration_id, &origin_out));
+ EXPECT_EQ(origin, origin_out);
+}
+
+TEST(ServiceWorkerDatabaseTest, Registration_UninitializedDatabase) {
+ scoped_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory());
+ const GURL origin("http://example.com");
+
+ // Should be failed because the database does not exist.
+ RegistrationData data_out;
+ std::vector<Resource> resources_out;
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND,
+ database->ReadRegistration(
+ 100, origin, &data_out, &resources_out));
+ EXPECT_EQ(kInvalidServiceWorkerRegistrationId, data_out.registration_id);
+ EXPECT_TRUE(resources_out.empty());
+ GURL origin_out;
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND,
+ database->ReadRegistrationOrigin(100, &origin_out));
+
+ // Deleting non-existent registration should succeed.
+ RegistrationData deleted_version;
+ std::vector<int64> newly_purgeable_resources;
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->DeleteRegistration(
+ 100, origin, &deleted_version, &newly_purgeable_resources));
+ EXPECT_EQ(kInvalidServiceWorkerVersionId, deleted_version.version_id);
+ EXPECT_TRUE(newly_purgeable_resources.empty());
+
+ // Actually create a new database, but not initialized yet.
+ database->LazyOpen(true);
+
+ // Should be failed because the database is not initialized.
+ ASSERT_EQ(ServiceWorkerDatabase::UNINITIALIZED, database->state_);
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND,
+ database->ReadRegistration(
+ 100, origin, &data_out, &resources_out));
+ EXPECT_EQ(kInvalidServiceWorkerRegistrationId, data_out.registration_id);
+ EXPECT_TRUE(resources_out.empty());
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND,
+ database->ReadRegistrationOrigin(100, &origin_out));
+
+ // Deleting non-existent registration should succeed.
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->DeleteRegistration(
+ 100, origin, &deleted_version, &newly_purgeable_resources));
+ EXPECT_EQ(kInvalidServiceWorkerVersionId, deleted_version.version_id);
+ EXPECT_TRUE(newly_purgeable_resources.empty());
+}
+
+TEST(ServiceWorkerDatabaseTest, UserData_Basic) {
+ scoped_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory());
+ const GURL kOrigin("http://example.com");
+
+ // Add a registration.
+ RegistrationData data;
+ data.registration_id = 100;
+ data.scope = URL(kOrigin, "/foo");
+ data.script = URL(kOrigin, "/script.js");
+ data.version_id = 200;
+ data.resources_total_size_bytes = 100;
+ std::vector<Resource> resources;
+ resources.push_back(CreateResource(1, data.script, 100));
+ ServiceWorkerDatabase::RegistrationData deleted_version;
+ std::vector<int64> newly_purgeable_resources;
+ ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(
+ data, resources, &deleted_version, &newly_purgeable_resources));
+
+ // Write user data associated with the stored registration.
+ std::string user_data_out;
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->WriteUserData(
+ data.registration_id, kOrigin, "key1", "data"));
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->ReadUserData(
+ data.registration_id, "key1", &user_data_out));
+ EXPECT_EQ("data", user_data_out);
+
+ // Writing user data not associated with the stored registration should be
+ // failed.
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND,
+ database->WriteUserData(300, kOrigin, "key1", "data"));
+
+ // Write empty user data for a different key.
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->WriteUserData(
+ data.registration_id, kOrigin, "key2", std::string()));
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->ReadUserData(
+ data.registration_id, "key2", &user_data_out));
+ EXPECT_EQ(std::string(), user_data_out);
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->ReadUserData(
+ data.registration_id, "key1", &user_data_out));
+ EXPECT_EQ("data", user_data_out);
+
+ // Overwrite the existing user data.
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->WriteUserData(
+ data.registration_id, kOrigin, "key1", "overwrite"));
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->ReadUserData(
+ data.registration_id, "key1", &user_data_out));
+ EXPECT_EQ("overwrite", user_data_out);
+
+ // Delete the user data.
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->DeleteUserData(data.registration_id, "key1"));
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND,
+ database->ReadUserData(
+ data.registration_id, "key1", &user_data_out));
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->ReadUserData(
+ data.registration_id, "key2", &user_data_out));
+ EXPECT_EQ(std::string(), user_data_out);
+}
+
+TEST(ServiceWorkerDatabaseTest, UserData_DataIsolation) {
+ scoped_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory());
+ const GURL kOrigin("http://example.com");
+
+ // Add registration 1.
+ RegistrationData data1;
+ data1.registration_id = 100;
+ data1.scope = URL(kOrigin, "/foo");
+ data1.script = URL(kOrigin, "/script1.js");
+ data1.version_id = 200;
+ data1.resources_total_size_bytes = 100;
+ std::vector<Resource> resources1;
+ resources1.push_back(CreateResource(1, data1.script, 100));
+
+ // Add registration 2.
+ RegistrationData data2;
+ data2.registration_id = 101;
+ data2.scope = URL(kOrigin, "/bar");
+ data2.script = URL(kOrigin, "/script2.js");
+ data2.version_id = 201;
+ data2.resources_total_size_bytes = 200;
+ std::vector<Resource> resources2;
+ resources2.push_back(CreateResource(2, data2.script, 200));
+
+ ServiceWorkerDatabase::RegistrationData deleted_version;
+ std::vector<int64> newly_purgeable_resources;
+ ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(data1, resources1, &deleted_version,
+ &newly_purgeable_resources));
+ ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(data2, resources2, &deleted_version,
+ &newly_purgeable_resources));
+
+ // Write user data associated with the registration1.
+ std::string user_data_out;
+ ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->WriteUserData(
+ data1.registration_id, kOrigin, "key", "data1"));
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->ReadUserData(
+ data1.registration_id, "key", &user_data_out));
+ EXPECT_EQ("data1", user_data_out);
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND,
+ database->ReadUserData(
+ data2.registration_id, "key", &user_data_out));
+
+ // Write user data associated with the registration2. This shouldn't overwrite
+ // the data associated with registration1.
+ ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->WriteUserData(
+ data2.registration_id, kOrigin, "key", "data2"));
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->ReadUserData(
+ data1.registration_id, "key", &user_data_out));
+ EXPECT_EQ("data1", user_data_out);
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->ReadUserData(
+ data2.registration_id, "key", &user_data_out));
+ EXPECT_EQ("data2", user_data_out);
+
+ // Get all registrations with user data.
+ std::vector<std::pair<int64, std::string>> user_data_list;
+ ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->ReadUserDataForAllRegistrations("key", &user_data_list));
+ EXPECT_EQ(2u, user_data_list.size());
+ EXPECT_EQ(data1.registration_id, user_data_list[0].first);
+ EXPECT_EQ("data1", user_data_list[0].second);
+ EXPECT_EQ(data2.registration_id, user_data_list[1].first);
+ EXPECT_EQ("data2", user_data_list[1].second);
+
+ // Delete the data associated with the registration2. This shouldn't delete
+ // the data associated with registration1.
+ ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->DeleteUserData(data2.registration_id, "key"));
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->ReadUserData(
+ data1.registration_id, "key", &user_data_out));
+ EXPECT_EQ("data1", user_data_out);
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND,
+ database->ReadUserData(
+ data2.registration_id, "key", &user_data_out));
+
+ // And again get all registrations with user data.
+ user_data_list.clear();
+ ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->ReadUserDataForAllRegistrations("key", &user_data_list));
+ EXPECT_EQ(1u, user_data_list.size());
+ EXPECT_EQ(data1.registration_id, user_data_list[0].first);
+ EXPECT_EQ("data1", user_data_list[0].second);
+}
+
+TEST(ServiceWorkerDatabaseTest, UserData_DeleteRegistration) {
+ scoped_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory());
+ const GURL kOrigin("http://example.com");
+
+ // Add registration 1.
+ RegistrationData data1;
+ data1.registration_id = 100;
+ data1.scope = URL(kOrigin, "/foo");
+ data1.script = URL(kOrigin, "/script1.js");
+ data1.version_id = 200;
+ data1.resources_total_size_bytes = 100;
+ std::vector<Resource> resources1;
+ resources1.push_back(CreateResource(1, data1.script, 100));
+
+ // Add registration 2.
+ RegistrationData data2;
+ data2.registration_id = 101;
+ data2.scope = URL(kOrigin, "/bar");
+ data2.script = URL(kOrigin, "/script2.js");
+ data2.version_id = 201;
+ data2.resources_total_size_bytes = 200;
+ std::vector<Resource> resources2;
+ resources2.push_back(CreateResource(2, data2.script, 200));
+
+ ServiceWorkerDatabase::RegistrationData deleted_version;
+ std::vector<int64> newly_purgeable_resources;
+ ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(data1, resources1, &deleted_version,
+ &newly_purgeable_resources));
+ ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(data2, resources2, &deleted_version,
+ &newly_purgeable_resources));
+
+ // Write user data associated with the registration1.
+ std::string user_data_out;
+ ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->WriteUserData(
+ data1.registration_id, kOrigin, "key1", "data1"));
+ ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->WriteUserData(
+ data1.registration_id, kOrigin, "key2", "data2"));
+ ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->ReadUserData(
+ data1.registration_id, "key1", &user_data_out));
+ ASSERT_EQ("data1", user_data_out);
+ ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->ReadUserData(
+ data1.registration_id, "key2", &user_data_out));
+ ASSERT_EQ("data2", user_data_out);
+
+ // Write user data associated with the registration2.
+ ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->WriteUserData(
+ data2.registration_id, kOrigin, "key3", "data3"));
+ ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->ReadUserData(
+ data2.registration_id, "key3", &user_data_out));
+ ASSERT_EQ("data3", user_data_out);
+
+ // Delete all data associated with the registration1. This shouldn't delete
+ // the data associated with registration2.
+ ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->DeleteRegistration(
+ data1.registration_id, kOrigin,
+ &deleted_version, &newly_purgeable_resources));
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND,
+ database->ReadUserData(
+ data1.registration_id, "key1", &user_data_out));
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND,
+ database->ReadUserData(
+ data1.registration_id, "key2", &user_data_out));
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->ReadUserData(
+ data2.registration_id, "key3", &user_data_out));
+ EXPECT_EQ("data3", user_data_out);
+}
+
+TEST(ServiceWorkerDatabaseTest, UserData_UninitializedDatabase) {
+ scoped_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory());
+ const GURL kOrigin("http://example.com");
+
+ // Should be failed because the database does not exist.
+ std::string user_data_out;
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND,
+ database->ReadUserData(100, "key", &user_data_out));
+
+ // Should be failed because the associated registration does not exist.
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND,
+ database->WriteUserData(100, kOrigin, "key", "data"));
+
+ // Deleting non-existent entry should succeed.
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->DeleteUserData(100, "key"));
+
+ // Actually create a new database, but not initialized yet.
+ database->LazyOpen(true);
+
+ // Should be failed because the database is not initialized.
+ ASSERT_EQ(ServiceWorkerDatabase::UNINITIALIZED, database->state_);
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND,
+ database->ReadUserData(100, "key", &user_data_out));
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND,
+ database->WriteUserData(100, kOrigin, "key", "data"));
+
+ // Deleting non-existent entry should succeed.
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->DeleteUserData(100, "key"));
}
TEST(ServiceWorkerDatabaseTest, UpdateVersionToActive) {
@@ -759,10 +1184,11 @@ TEST(ServiceWorkerDatabaseTest, UpdateVersionToActive) {
data.script = URL(origin, "/script.js");
data.version_id = 200;
data.is_active = false;
+ data.resources_total_size_bytes = 100;
+ std::vector<Resource> resources;
+ resources.push_back(CreateResource(1, data.script, 100));
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
- database->WriteRegistration(data,
- std::vector<Resource>(),
- &deleted_version,
+ database->WriteRegistration(data, resources, &deleted_version,
&newly_purgeable_resources));
// Make sure that the registration is stored.
@@ -772,7 +1198,7 @@ TEST(ServiceWorkerDatabaseTest, UpdateVersionToActive) {
database->ReadRegistration(
data.registration_id, origin, &data_out, &resources_out));
VerifyRegistrationData(data, data_out);
- EXPECT_TRUE(resources_out.empty());
+ EXPECT_EQ(1u, resources_out.size());
// Activate the registration.
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
@@ -786,7 +1212,7 @@ TEST(ServiceWorkerDatabaseTest, UpdateVersionToActive) {
RegistrationData expected_data = data;
expected_data.is_active = true;
VerifyRegistrationData(expected_data, data_out);
- EXPECT_TRUE(resources_out.empty());
+ EXPECT_EQ(1u, resources_out.size());
// Delete the registration.
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
@@ -818,10 +1244,11 @@ TEST(ServiceWorkerDatabaseTest, UpdateLastCheckTime) {
data.script = URL(origin, "/script.js");
data.version_id = 200;
data.last_update_check = base::Time::Now();
+ data.resources_total_size_bytes = 100;
+ std::vector<Resource> resources;
+ resources.push_back(CreateResource(1, data.script, 100));
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
- database->WriteRegistration(data,
- std::vector<Resource>(),
- &deleted_version,
+ database->WriteRegistration(data, resources, &deleted_version,
&newly_purgeable_resources));
// Make sure that the registration is stored.
@@ -831,7 +1258,7 @@ TEST(ServiceWorkerDatabaseTest, UpdateLastCheckTime) {
database->ReadRegistration(
data.registration_id, origin, &data_out, &resources_out));
VerifyRegistrationData(data, data_out);
- EXPECT_TRUE(resources_out.empty());
+ EXPECT_EQ(1u, resources_out.size());
// Update the last check time.
base::Time updated_time = base::Time::Now();
@@ -847,7 +1274,7 @@ TEST(ServiceWorkerDatabaseTest, UpdateLastCheckTime) {
RegistrationData expected_data = data;
expected_data.last_update_check = updated_time;
VerifyRegistrationData(expected_data, data_out);
- EXPECT_TRUE(resources_out.empty());
+ EXPECT_EQ(1u, resources_out.size());
// Delete the registration.
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
@@ -958,7 +1385,7 @@ TEST(ServiceWorkerDatabaseTest, DeleteAllDataForOrigin) {
GURL origin1("http://example.com");
GURL origin2("http://example.org");
- // |origin1| has two registrations.
+ // |origin1| has two registrations (registration1 and registration2).
RegistrationData data1;
data1.registration_id = 10;
data1.scope = URL(origin1, "/foo");
@@ -973,6 +1400,14 @@ TEST(ServiceWorkerDatabaseTest, DeleteAllDataForOrigin) {
ServiceWorkerDatabase::STATUS_OK,
database->WriteRegistration(
data1, resources1, &deleted_version, &newly_purgeable_resources));
+ ASSERT_EQ(
+ ServiceWorkerDatabase::STATUS_OK,
+ database->WriteUserData(
+ data1.registration_id, origin1, "key1", "data1"));
+ ASSERT_EQ(
+ ServiceWorkerDatabase::STATUS_OK,
+ database->WriteUserData(
+ data1.registration_id, origin1, "key2", "data2"));
RegistrationData data2;
data2.registration_id = 11;
@@ -988,8 +1423,16 @@ TEST(ServiceWorkerDatabaseTest, DeleteAllDataForOrigin) {
ServiceWorkerDatabase::STATUS_OK,
database->WriteRegistration(
data2, resources2, &deleted_version, &newly_purgeable_resources));
+ ASSERT_EQ(
+ ServiceWorkerDatabase::STATUS_OK,
+ database->WriteUserData(
+ data2.registration_id, origin1, "key3", "data3"));
+ ASSERT_EQ(
+ ServiceWorkerDatabase::STATUS_OK,
+ database->WriteUserData(
+ data2.registration_id, origin1, "key4", "data4"));
- // |origin2| has one registration.
+ // |origin2| has one registration (registration3).
RegistrationData data3;
data3.registration_id = 12;
data3.scope = URL(origin2, "/hoge");
@@ -1004,6 +1447,14 @@ TEST(ServiceWorkerDatabaseTest, DeleteAllDataForOrigin) {
ServiceWorkerDatabase::STATUS_OK,
database->WriteRegistration(
data3, resources3, &deleted_version, &newly_purgeable_resources));
+ ASSERT_EQ(
+ ServiceWorkerDatabase::STATUS_OK,
+ database->WriteUserData(
+ data3.registration_id, origin2, "key5", "data5"));
+ ASSERT_EQ(
+ ServiceWorkerDatabase::STATUS_OK,
+ database->WriteUserData(
+ data3.registration_id, origin2, "key6", "data6"));
std::set<GURL> origins_to_delete;
origins_to_delete.insert(origin1);
@@ -1023,6 +1474,10 @@ TEST(ServiceWorkerDatabaseTest, DeleteAllDataForOrigin) {
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
database->GetRegistrationsForOrigin(origin1, &registrations));
EXPECT_TRUE(registrations.empty());
+ GURL origin_out;
+ EXPECT_EQ(
+ ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND,
+ database->ReadRegistrationOrigin(data1.registration_id, &origin_out));
// The registration for |origin2| should not be removed.
RegistrationData data_out;
@@ -1031,6 +1486,10 @@ TEST(ServiceWorkerDatabaseTest, DeleteAllDataForOrigin) {
data3.registration_id, origin2, &data_out, &resources_out));
VerifyRegistrationData(data3, data_out);
VerifyResourceRecords(resources3, resources_out);
+ EXPECT_EQ(
+ ServiceWorkerDatabase::STATUS_OK,
+ database->ReadRegistrationOrigin(data3.registration_id, &origin_out));
+ EXPECT_EQ(origin2, origin_out);
// The resources associated with |origin1| should be purgeable.
std::set<int64> purgeable_ids_out;
@@ -1041,6 +1500,31 @@ TEST(ServiceWorkerDatabaseTest, DeleteAllDataForOrigin) {
EXPECT_TRUE(ContainsKey(purgeable_ids_out, 2));
EXPECT_TRUE(ContainsKey(purgeable_ids_out, 3));
EXPECT_TRUE(ContainsKey(purgeable_ids_out, 4));
+
+ // The user data associated with |origin1| should be removed.
+ std::string user_data_out;
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND,
+ database->ReadUserData(
+ data1.registration_id, "key1", &user_data_out));
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND,
+ database->ReadUserData(
+ data1.registration_id, "key2", &user_data_out));
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND,
+ database->ReadUserData(
+ data2.registration_id, "key3", &user_data_out));
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND,
+ database->ReadUserData(
+ data2.registration_id, "key4", &user_data_out));
+
+ // The user data associated with |origin2| should not be removed.
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->ReadUserData(
+ data3.registration_id, "key5", &user_data_out));
+ EXPECT_EQ("data5", user_data_out);
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->ReadUserData(
+ data3.registration_id, "key6", &user_data_out));
+ EXPECT_EQ("data6", user_data_out);
}
TEST(ServiceWorkerDatabaseTest, DestroyDatabase) {
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 d31f00c62ae..4b6237ff234 100644
--- a/chromium/content/browser/service_worker/service_worker_disk_cache.cc
+++ b/chromium/content/browser/service_worker/service_worker_disk_cache.cc
@@ -16,4 +16,10 @@ ServiceWorkerResponseWriter::ServiceWorkerResponseWriter(
: AppCacheResponseWriter(response_id, 0, disk_cache) {
}
+ServiceWorkerResponseMetadataWriter::ServiceWorkerResponseMetadataWriter(
+ int64 response_id,
+ ServiceWorkerDiskCache* disk_cache)
+ : AppCacheResponseMetadataWriter(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 7fa51eed634..7b9b4e44193 100644
--- a/chromium/content/browser/service_worker/service_worker_disk_cache.h
+++ b/chromium/content/browser/service_worker/service_worker_disk_cache.h
@@ -40,6 +40,15 @@ class CONTENT_EXPORT ServiceWorkerResponseWriter
ServiceWorkerDiskCache* disk_cache);
};
+class CONTENT_EXPORT ServiceWorkerResponseMetadataWriter
+ : public AppCacheResponseMetadataWriter {
+ protected:
+ // Should only be constructed by the storage class.
+ friend class ServiceWorkerStorage;
+ ServiceWorkerResponseMetadataWriter(int64 response_id,
+ ServiceWorkerDiskCache* disk_cache);
+};
+
} // 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 8f00707381f..d7e33c13952 100644
--- a/chromium/content/browser/service_worker/service_worker_dispatcher_host.cc
+++ b/chromium/content/browser/service_worker/service_worker_dispatcher_host.cc
@@ -4,9 +4,10 @@
#include "content/browser/service_worker/service_worker_dispatcher_host.h"
-#include "base/debug/trace_event.h"
#include "base/logging.h"
+#include "base/profiler/scoped_tracker.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/trace_event/trace_event.h"
#include "content/browser/message_port_message_filter.h"
#include "content/browser/message_port_service.h"
#include "content/browser/service_worker/embedded_worker_registry.h"
@@ -18,8 +19,10 @@
#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/common/service_worker/service_worker_types.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/common/content_client.h"
+#include "content/public/common/origin_util.h"
#include "ipc/ipc_message_macros.h"
#include "net/base/net_util.h"
#include "third_party/WebKit/public/platform/WebServiceWorkerError.h"
@@ -31,9 +34,12 @@ namespace content {
namespace {
+const char kNoDocumentURLErrorMessage[] =
+ "No URL is associated with the caller's document.";
const char kShutdownErrorMessage[] =
"The Service Worker system has shutdown.";
-const char kDisabledErrorMessage[] = "The browser has disabled Service Worker.";
+const char kUserDeniedPermissionMessage[] =
+ "The user denied permission to use Service Worker.";
const uint32 kFilteredMessageClasses[] = {
ServiceWorkerMsgStart,
@@ -45,20 +51,8 @@ bool AllOriginsMatch(const GURL& url_a, const GURL& url_b, const GURL& url_c) {
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;
+ return url.SchemeIsHTTPOrHTTPS() && IsOriginSecure(url);
}
bool CanRegisterServiceWorker(const GURL& document_url,
@@ -69,7 +63,8 @@ bool CanRegisterServiceWorker(const GURL& document_url,
DCHECK(script_url.is_valid());
return AllOriginsMatch(document_url, pattern, script_url) &&
OriginCanAccessServiceWorkers(document_url) &&
- CheckPatternIsUnderTheScriptDirectory(pattern, script_url);
+ OriginCanAccessServiceWorkers(pattern) &&
+ OriginCanAccessServiceWorkers(script_url);
}
bool CanUnregisterServiceWorker(const GURL& document_url,
@@ -77,7 +72,8 @@ bool CanUnregisterServiceWorker(const GURL& document_url,
DCHECK(document_url.is_valid());
DCHECK(pattern.is_valid());
return document_url.GetOrigin() == pattern.GetOrigin() &&
- OriginCanAccessServiceWorkers(document_url);
+ OriginCanAccessServiceWorkers(document_url) &&
+ OriginCanAccessServiceWorkers(pattern);
}
bool CanGetRegistration(const GURL& document_url,
@@ -85,7 +81,8 @@ bool CanGetRegistration(const GURL& document_url,
DCHECK(document_url.is_valid());
DCHECK(given_document_url.is_valid());
return document_url.GetOrigin() == given_document_url.GetOrigin() &&
- OriginCanAccessServiceWorkers(document_url);
+ OriginCanAccessServiceWorkers(document_url) &&
+ OriginCanAccessServiceWorkers(given_document_url);
}
} // namespace
@@ -121,8 +118,10 @@ void ServiceWorkerDispatcherHost::Init(
}
context_wrapper_ = context_wrapper;
+ if (!GetContext())
+ return;
GetContext()->embedded_worker_registry()->AddChildProcessSender(
- render_process_id_, this);
+ render_process_id_, this, message_port_message_filter_);
}
void ServiceWorkerDispatcherHost::OnFilterAdded(IPC::Sender* sender) {
@@ -162,6 +161,8 @@ bool ServiceWorkerDispatcherHost::OnMessageReceived(
OnUnregisterServiceWorker)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GetRegistration,
OnGetRegistration)
+ IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GetRegistrationForReady,
+ OnGetRegistrationForReady)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ProviderCreated,
OnProviderCreated)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ProviderDestroyed,
@@ -196,12 +197,13 @@ bool ServiceWorkerDispatcherHost::OnMessageReceived(
OnIncrementRegistrationRefCount)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_DecrementRegistrationRefCount,
OnDecrementRegistrationRefCount)
+ IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_TerminateWorker, OnTerminateWorker)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
if (!handled && GetContext()) {
- handled =
- GetContext()->embedded_worker_registry()->OnMessageReceived(message);
+ handled = GetContext()->embedded_worker_registry()->OnMessageReceived(
+ message, render_process_id_);
if (!handled)
BadMessageReceived();
}
@@ -220,12 +222,41 @@ bool ServiceWorkerDispatcherHost::Send(IPC::Message* message) {
return true;
}
+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);
+}
+
+ServiceWorkerHandle* ServiceWorkerDispatcherHost::FindServiceWorkerHandle(
+ int provider_id,
+ int64 version_id) {
+ for (IDMap<ServiceWorkerHandle, IDMapOwnPointer>::iterator iter(&handles_);
+ !iter.IsAtEnd(); iter.Advance()) {
+ ServiceWorkerHandle* handle = iter.GetCurrentValue();
+ DCHECK(handle);
+ DCHECK(handle->version());
+ if (handle->provider_id() == provider_id &&
+ handle->version()->version_id() == version_id) {
+ return handle;
+ }
+ }
+ return NULL;
+}
+
ServiceWorkerRegistrationHandle*
ServiceWorkerDispatcherHost::GetOrCreateRegistrationHandle(
- int provider_id,
+ base::WeakPtr<ServiceWorkerProviderHost> provider_host,
ServiceWorkerRegistration* registration) {
+ DCHECK(provider_host);
ServiceWorkerRegistrationHandle* handle =
- FindRegistrationHandle(provider_id, registration->id());
+ FindRegistrationHandle(provider_host->provider_id(), registration->id());
if (handle) {
handle->IncrementRefCount();
return handle;
@@ -233,24 +264,12 @@ ServiceWorkerDispatcherHost::GetOrCreateRegistrationHandle(
scoped_ptr<ServiceWorkerRegistrationHandle> new_handle(
new ServiceWorkerRegistrationHandle(
- GetContext()->AsWeakPtr(), this, provider_id, registration));
+ GetContext()->AsWeakPtr(), provider_host, 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,
@@ -261,10 +280,9 @@ void ServiceWorkerDispatcherHost::OnRegisterServiceWorker(
"ServiceWorkerDispatcherHost::OnRegisterServiceWorker");
if (!GetContext()) {
Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
- thread_id,
- request_id,
- WebServiceWorkerError::ErrorTypeAbort,
- base::ASCIIToUTF16(kShutdownErrorMessage)));
+ thread_id, request_id, WebServiceWorkerError::ErrorTypeAbort,
+ base::ASCIIToUTF16(kServiceWorkerRegisterErrorPrefix) +
+ base::ASCIIToUTF16(kShutdownErrorMessage)));
return;
}
if (!pattern.is_valid() || !script_url.is_valid()) {
@@ -280,10 +298,20 @@ void ServiceWorkerDispatcherHost::OnRegisterServiceWorker(
}
if (!provider_host->IsContextAlive()) {
Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
- thread_id,
- request_id,
- WebServiceWorkerError::ErrorTypeAbort,
- base::ASCIIToUTF16(kShutdownErrorMessage)));
+ thread_id, request_id, WebServiceWorkerError::ErrorTypeAbort,
+ base::ASCIIToUTF16(kServiceWorkerRegisterErrorPrefix) +
+ base::ASCIIToUTF16(kShutdownErrorMessage)));
+ return;
+ }
+
+ // TODO(ksakamoto): Currently, document_url is empty if the document is in an
+ // IFRAME using frame.contentDocument.write(...). We can remove this check
+ // once crbug.com/439697 is fixed.
+ if (provider_host->document_url().is_empty()) {
+ Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
+ thread_id, request_id, WebServiceWorkerError::ErrorTypeSecurity,
+ base::ASCIIToUTF16(kServiceWorkerRegisterErrorPrefix) +
+ base::ASCIIToUTF16(kNoDocumentURLErrorMessage)));
return;
}
@@ -293,13 +321,23 @@ void ServiceWorkerDispatcherHost::OnRegisterServiceWorker(
return;
}
+ std::string error_message;
+ if (ServiceWorkerUtils::ContainsDisallowedCharacter(pattern, script_url,
+ &error_message)) {
+ Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
+ thread_id, request_id, WebServiceWorkerError::ErrorTypeSecurity,
+ base::ASCIIToUTF16(kServiceWorkerRegisterErrorPrefix) +
+ base::UTF8ToUTF16(error_message)));
+ return;
+ }
+
if (!GetContentClient()->browser()->AllowServiceWorker(
- pattern, provider_host->topmost_frame_url(), resource_context_)) {
+ pattern, provider_host->topmost_frame_url(), resource_context_,
+ render_process_id_, provider_host->frame_id())) {
Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
- thread_id,
- request_id,
- WebServiceWorkerError::ErrorTypeDisabled,
- base::ASCIIToUTF16(kDisabledErrorMessage)));
+ thread_id, request_id, WebServiceWorkerError::ErrorTypeUnknown,
+ base::ASCIIToUTF16(kServiceWorkerRegisterErrorPrefix) +
+ base::ASCIIToUTF16(kUserDeniedPermissionMessage)));
return;
}
@@ -354,18 +392,29 @@ void ServiceWorkerDispatcherHost::OnUnregisterServiceWorker(
return;
}
+ // TODO(ksakamoto): This check can be removed once crbug.com/439697 is fixed.
+ if (provider_host->document_url().is_empty()) {
+ Send(new ServiceWorkerMsg_ServiceWorkerUnregistrationError(
+ thread_id,
+ request_id,
+ WebServiceWorkerError::ErrorTypeSecurity,
+ base::ASCIIToUTF16(kNoDocumentURLErrorMessage)));
+ return;
+ }
+
if (!CanUnregisterServiceWorker(provider_host->document_url(), pattern)) {
BadMessageReceived();
return;
}
if (!GetContentClient()->browser()->AllowServiceWorker(
- pattern, provider_host->topmost_frame_url(), resource_context_)) {
+ pattern, provider_host->topmost_frame_url(), resource_context_,
+ render_process_id_, provider_host->frame_id())) {
Send(new ServiceWorkerMsg_ServiceWorkerUnregistrationError(
thread_id,
request_id,
- WebServiceWorkerError::ErrorTypeDisabled,
- base::ASCIIToUTF16(kDisabledErrorMessage)));
+ WebServiceWorkerError::ErrorTypeUnknown,
+ base::ASCIIToUTF16(kUserDeniedPermissionMessage)));
return;
}
@@ -391,10 +440,9 @@ void ServiceWorkerDispatcherHost::OnGetRegistration(
"ServiceWorkerDispatcherHost::OnGetRegistration");
if (!GetContext()) {
Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationError(
- thread_id,
- request_id,
- blink::WebServiceWorkerError::ErrorTypeAbort,
- base::ASCIIToUTF16(kShutdownErrorMessage)));
+ thread_id, request_id, blink::WebServiceWorkerError::ErrorTypeAbort,
+ base::ASCIIToUTF16(kServiceWorkerGetRegistrationErrorPrefix) +
+ base::ASCIIToUTF16(kShutdownErrorMessage)));
return;
}
if (!document_url.is_valid()) {
@@ -410,10 +458,18 @@ void ServiceWorkerDispatcherHost::OnGetRegistration(
}
if (!provider_host->IsContextAlive()) {
Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationError(
- thread_id,
- request_id,
- blink::WebServiceWorkerError::ErrorTypeAbort,
- base::ASCIIToUTF16(kShutdownErrorMessage)));
+ thread_id, request_id, blink::WebServiceWorkerError::ErrorTypeAbort,
+ base::ASCIIToUTF16(kServiceWorkerGetRegistrationErrorPrefix) +
+ base::ASCIIToUTF16(kShutdownErrorMessage)));
+ return;
+ }
+
+ // TODO(ksakamoto): This check can be removed once crbug.com/439697 is fixed.
+ if (provider_host->document_url().is_empty()) {
+ Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationError(
+ thread_id, request_id, WebServiceWorkerError::ErrorTypeSecurity,
+ base::ASCIIToUTF16(kServiceWorkerGetRegistrationErrorPrefix) +
+ base::ASCIIToUTF16(kNoDocumentURLErrorMessage)));
return;
}
@@ -423,14 +479,12 @@ void ServiceWorkerDispatcherHost::OnGetRegistration(
}
if (!GetContentClient()->browser()->AllowServiceWorker(
- provider_host->document_url(),
- provider_host->topmost_frame_url(),
- resource_context_)) {
+ provider_host->document_url(), provider_host->topmost_frame_url(),
+ resource_context_, render_process_id_, provider_host->frame_id())) {
Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationError(
- thread_id,
- request_id,
- WebServiceWorkerError::ErrorTypeDisabled,
- base::ASCIIToUTF16(kDisabledErrorMessage)));
+ thread_id, request_id, WebServiceWorkerError::ErrorTypeUnknown,
+ base::ASCIIToUTF16(kServiceWorkerGetRegistrationErrorPrefix) +
+ base::ASCIIToUTF16(kUserDeniedPermissionMessage)));
return;
}
@@ -455,10 +509,39 @@ void ServiceWorkerDispatcherHost::OnGetRegistration(
request_id));
}
+void ServiceWorkerDispatcherHost::OnGetRegistrationForReady(
+ int thread_id,
+ int request_id,
+ int provider_id) {
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerDispatcherHost::OnGetRegistrationForReady");
+ if (!GetContext())
+ return;
+ ServiceWorkerProviderHost* provider_host =
+ GetContext()->GetProviderHost(render_process_id_, provider_id);
+ if (!provider_host) {
+ BadMessageReceived();
+ return;
+ }
+ if (!provider_host->IsContextAlive())
+ return;
+
+ TRACE_EVENT_ASYNC_BEGIN0(
+ "ServiceWorker",
+ "ServiceWorkerDispatcherHost::GetRegistrationForReady",
+ request_id);
+
+ if (!provider_host->GetRegistrationForReady(base::Bind(
+ &ServiceWorkerDispatcherHost::GetRegistrationForReadyComplete,
+ this, thread_id, request_id, provider_host->AsWeakPtr()))) {
+ BadMessageReceived();
+ }
+}
+
void ServiceWorkerDispatcherHost::OnPostMessageToWorker(
int handle_id,
const base::string16& message,
- const std::vector<int>& sent_message_port_ids) {
+ const std::vector<TransferredMessagePort>& sent_message_ports) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerDispatcherHost::OnPostMessageToWorker");
if (!GetContext())
@@ -470,17 +553,19 @@ void ServiceWorkerDispatcherHost::OnPostMessageToWorker(
return;
}
- std::vector<int> new_routing_ids;
- message_port_message_filter_->UpdateMessagePortsWithNewRoutes(
- sent_message_port_ids, &new_routing_ids);
- handle->version()->SendMessage(
- ServiceWorkerMsg_MessageToWorker(message,
- sent_message_port_ids,
- new_routing_ids),
+ handle->version()->DispatchMessageEvent(
+ message, sent_message_ports,
base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
}
-void ServiceWorkerDispatcherHost::OnProviderCreated(int provider_id) {
+void ServiceWorkerDispatcherHost::OnProviderCreated(
+ int provider_id,
+ int render_frame_id,
+ ServiceWorkerProviderType provider_type) {
+ // TODO(pkasting): Remove ScopedTracker below once crbug.com/477117 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "477117 ServiceWorkerDispatcherHost::OnProviderCreated"));
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerDispatcherHost::OnProviderCreated");
if (!GetContext())
@@ -490,8 +575,12 @@ void ServiceWorkerDispatcherHost::OnProviderCreated(int provider_id) {
return;
}
scoped_ptr<ServiceWorkerProviderHost> provider_host(
- new ServiceWorkerProviderHost(
- render_process_id_, provider_id, GetContext()->AsWeakPtr(), this));
+ new ServiceWorkerProviderHost(render_process_id_,
+ render_frame_id,
+ provider_id,
+ provider_type,
+ GetContext()->AsWeakPtr(),
+ this));
GetContext()->AddProviderHost(provider_host.Pass());
}
@@ -523,6 +612,31 @@ void ServiceWorkerDispatcherHost::OnSetHostedVersionId(
return;
if (!provider_host->SetHostedVersionId(version_id))
BadMessageReceived();
+
+ ServiceWorkerVersion* version = GetContext()->GetLiveVersion(version_id);
+ if (!version)
+ return;
+
+ // Retrieve the registration associated with |version|. The registration
+ // must be alive because the version keeps it during starting worker.
+ ServiceWorkerRegistration* registration =
+ GetContext()->GetLiveRegistration(version->registration_id());
+ DCHECK(registration);
+ // TODO(ksakamoto): This is a quick fix for crbug.com/459916.
+ if (!registration)
+ return;
+
+ // Set the document URL to the script url in order to allow
+ // register/unregister/getRegistration on ServiceWorkerGlobalScope.
+ provider_host->SetDocumentUrl(version->script_url());
+
+ ServiceWorkerRegistrationObjectInfo info;
+ ServiceWorkerVersionAttributes attrs;
+ GetRegistrationObjectInfoAndVersionAttributes(
+ provider_host->AsWeakPtr(), registration, &info, &attrs);
+
+ Send(new ServiceWorkerMsg_AssociateRegistrationWithServiceWorker(
+ kDocumentMainThreadId, provider_id, info, attrs));
}
ServiceWorkerRegistrationHandle*
@@ -534,7 +648,8 @@ ServiceWorkerDispatcherHost::FindRegistrationHandle(int provider_id,
iter.Advance()) {
ServiceWorkerRegistrationHandle* handle = iter.GetCurrentValue();
DCHECK(handle);
- if (handle->provider_id() == provider_id && handle->registration() &&
+ DCHECK(handle->registration());
+ if (handle->provider_id() == provider_id &&
handle->registration()->id() == registration_id) {
return handle;
}
@@ -543,19 +658,19 @@ ServiceWorkerDispatcherHost::FindRegistrationHandle(int provider_id,
}
void ServiceWorkerDispatcherHost::GetRegistrationObjectInfoAndVersionAttributes(
- int provider_id,
+ base::WeakPtr<ServiceWorkerProviderHost> provider_host,
ServiceWorkerRegistration* registration,
ServiceWorkerRegistrationObjectInfo* info,
ServiceWorkerVersionAttributes* attrs) {
ServiceWorkerRegistrationHandle* handle =
- GetOrCreateRegistrationHandle(provider_id, registration);
+ GetOrCreateRegistrationHandle(provider_host, registration);
*info = handle->GetObjectInfo();
- attrs->installing = handle->CreateServiceWorkerHandleAndPass(
+ attrs->installing = provider_host->GetOrCreateServiceWorkerHandle(
registration->installing_version());
- attrs->waiting = handle->CreateServiceWorkerHandleAndPass(
+ attrs->waiting = provider_host->GetOrCreateServiceWorkerHandle(
registration->waiting_version());
- attrs->active = handle->CreateServiceWorkerHandleAndPass(
+ attrs->active = provider_host->GetOrCreateServiceWorkerHandle(
registration->active_version());
}
@@ -564,12 +679,18 @@ void ServiceWorkerDispatcherHost::RegistrationComplete(
int provider_id,
int request_id,
ServiceWorkerStatusCode status,
+ const std::string& status_message,
int64 registration_id) {
if (!GetContext())
return;
+ ServiceWorkerProviderHost* provider_host =
+ GetContext()->GetProviderHost(render_process_id_, provider_id);
+ if (!provider_host)
+ return; // The provider has already been destroyed.
+
if (status != SERVICE_WORKER_OK) {
- SendRegistrationError(thread_id, request_id, status);
+ SendRegistrationError(thread_id, request_id, status, status_message);
return;
}
@@ -580,7 +701,7 @@ void ServiceWorkerDispatcherHost::RegistrationComplete(
ServiceWorkerRegistrationObjectInfo info;
ServiceWorkerVersionAttributes attrs;
GetRegistrationObjectInfoAndVersionAttributes(
- provider_id, registration, &info, &attrs);
+ provider_host->AsWeakPtr(), registration, &info, &attrs);
Send(new ServiceWorkerMsg_ServiceWorkerRegistered(
thread_id, request_id, info, attrs));
@@ -605,11 +726,22 @@ void ServiceWorkerDispatcherHost::OnWorkerReadyForInspection(
void ServiceWorkerDispatcherHost::OnWorkerScriptLoaded(
int embedded_worker_id,
- int thread_id) {
+ int thread_id,
+ int provider_id) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerDispatcherHost::OnWorkerScriptLoaded");
if (!GetContext())
return;
+
+ ServiceWorkerProviderHost* provider_host =
+ GetContext()->GetProviderHost(render_process_id_, provider_id);
+ if (!provider_host) {
+ BadMessageReceived();
+ return;
+ }
+
+ provider_host->SetReadyToSendMessagesToWorker(thread_id);
+
EmbeddedWorkerRegistry* registry = GetContext()->embedded_worker_registry();
if (!registry->CanHandle(embedded_worker_id))
return;
@@ -802,6 +934,11 @@ void ServiceWorkerDispatcherHost::GetRegistrationComplete(
if (!GetContext())
return;
+ ServiceWorkerProviderHost* provider_host =
+ GetContext()->GetProviderHost(render_process_id_, provider_id);
+ if (!provider_host)
+ return; // The provider has already been destroyed.
+
if (status != SERVICE_WORKER_OK && status != SERVICE_WORKER_ERROR_NOT_FOUND) {
SendGetRegistrationError(thread_id, request_id, status);
return;
@@ -813,7 +950,7 @@ void ServiceWorkerDispatcherHost::GetRegistrationComplete(
DCHECK(registration.get());
if (!registration->is_uninstalling()) {
GetRegistrationObjectInfoAndVersionAttributes(
- provider_id, registration.get(), &info, &attrs);
+ provider_host->AsWeakPtr(), registration.get(), &info, &attrs);
}
}
@@ -821,16 +958,42 @@ void ServiceWorkerDispatcherHost::GetRegistrationComplete(
thread_id, request_id, info, attrs));
}
+void ServiceWorkerDispatcherHost::GetRegistrationForReadyComplete(
+ int thread_id,
+ int request_id,
+ base::WeakPtr<ServiceWorkerProviderHost> provider_host,
+ ServiceWorkerRegistration* registration) {
+ DCHECK(registration);
+ TRACE_EVENT_ASYNC_END1("ServiceWorker",
+ "ServiceWorkerDispatcherHost::GetRegistrationForReady",
+ request_id,
+ "Registration ID",
+ registration ? registration->id()
+ : kInvalidServiceWorkerRegistrationId);
+
+ if (!GetContext())
+ return;
+
+ ServiceWorkerRegistrationObjectInfo info;
+ ServiceWorkerVersionAttributes attrs;
+ GetRegistrationObjectInfoAndVersionAttributes(
+ provider_host, registration, &info, &attrs);
+ Send(new ServiceWorkerMsg_DidGetRegistrationForReady(
+ thread_id, request_id, info, attrs));
+}
+
void ServiceWorkerDispatcherHost::SendRegistrationError(
int thread_id,
int request_id,
- ServiceWorkerStatusCode status) {
+ ServiceWorkerStatusCode status,
+ const std::string& status_message) {
base::string16 error_message;
blink::WebServiceWorkerError::ErrorType error_type;
- GetServiceWorkerRegistrationStatusResponse(
- status, &error_type, &error_message);
+ GetServiceWorkerRegistrationStatusResponse(status, status_message,
+ &error_type, &error_message);
Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
- thread_id, request_id, error_type, error_message));
+ thread_id, request_id, error_type,
+ base::ASCIIToUTF16(kServiceWorkerRegisterErrorPrefix) + error_message));
}
void ServiceWorkerDispatcherHost::SendUnregistrationError(
@@ -839,10 +1002,11 @@ void ServiceWorkerDispatcherHost::SendUnregistrationError(
ServiceWorkerStatusCode status) {
base::string16 error_message;
blink::WebServiceWorkerError::ErrorType error_type;
- GetServiceWorkerRegistrationStatusResponse(
- status, &error_type, &error_message);
+ GetServiceWorkerRegistrationStatusResponse(status, std::string(), &error_type,
+ &error_message);
Send(new ServiceWorkerMsg_ServiceWorkerUnregistrationError(
- thread_id, request_id, error_type, error_message));
+ thread_id, request_id, error_type,
+ base::ASCIIToUTF16(kServiceWorkerUnregisterErrorPrefix) + error_message));
}
void ServiceWorkerDispatcherHost::SendGetRegistrationError(
@@ -851,10 +1015,12 @@ void ServiceWorkerDispatcherHost::SendGetRegistrationError(
ServiceWorkerStatusCode status) {
base::string16 error_message;
blink::WebServiceWorkerError::ErrorType error_type;
- GetServiceWorkerRegistrationStatusResponse(
- status, &error_type, &error_message);
+ GetServiceWorkerRegistrationStatusResponse(status, std::string(), &error_type,
+ &error_message);
Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationError(
- thread_id, request_id, error_type, error_message));
+ thread_id, request_id, error_type,
+ base::ASCIIToUTF16(kServiceWorkerGetRegistrationErrorPrefix) +
+ error_message));
}
ServiceWorkerContextCore* ServiceWorkerDispatcherHost::GetContext() {
@@ -863,4 +1029,14 @@ ServiceWorkerContextCore* ServiceWorkerDispatcherHost::GetContext() {
return context_wrapper_->context();
}
+void ServiceWorkerDispatcherHost::OnTerminateWorker(int handle_id) {
+ ServiceWorkerHandle* handle = handles_.Lookup(handle_id);
+ if (!handle) {
+ BadMessageReceived();
+ return;
+ }
+ handle->version()->StopWorker(
+ base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
+}
+
} // namespace content
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 61126f9c3a8..d121e6bafa5 100644
--- a/chromium/content/browser/service_worker/service_worker_dispatcher_host.h
+++ b/chromium/content/browser/service_worker/service_worker_dispatcher_host.h
@@ -11,6 +11,7 @@
#include "base/memory/weak_ptr.h"
#include "base/strings/string16.h"
#include "content/browser/service_worker/service_worker_registration_status.h"
+#include "content/common/service_worker/service_worker_types.h"
#include "content/public/browser/browser_message_filter.h"
class GURL;
@@ -26,8 +27,11 @@ class ServiceWorkerHandle;
class ServiceWorkerProviderHost;
class ServiceWorkerRegistration;
class ServiceWorkerRegistrationHandle;
+class ServiceWorkerVersion;
+struct ServiceWorkerObjectInfo;
struct ServiceWorkerRegistrationObjectInfo;
struct ServiceWorkerVersionAttributes;
+struct TransferredMessagePort;
class CONTENT_EXPORT ServiceWorkerDispatcherHost : public BrowserMessageFilter {
public:
@@ -52,16 +56,19 @@ class CONTENT_EXPORT ServiceWorkerDispatcherHost : public BrowserMessageFilter {
// be destroyed.
bool Send(IPC::Message* message) override;
+ void RegisterServiceWorkerHandle(scoped_ptr<ServiceWorkerHandle> handle);
+ void RegisterServiceWorkerRegistrationHandle(
+ scoped_ptr<ServiceWorkerRegistrationHandle> handle);
+
+ ServiceWorkerHandle* FindServiceWorkerHandle(int provider_id,
+ int64 version_id);
+
// Returns the existing registration handle whose reference count is
// incremented or newly created one if it doesn't exist.
ServiceWorkerRegistrationHandle* GetOrCreateRegistrationHandle(
- int provider_id,
+ base::WeakPtr<ServiceWorkerProviderHost> provider_host,
ServiceWorkerRegistration* registration);
- void RegisterServiceWorkerHandle(scoped_ptr<ServiceWorkerHandle> handle);
- void RegisterServiceWorkerRegistrationHandle(
- scoped_ptr<ServiceWorkerRegistrationHandle> handle);
-
MessagePortMessageFilter* message_port_message_filter() {
return message_port_message_filter_;
}
@@ -88,11 +95,18 @@ class CONTENT_EXPORT ServiceWorkerDispatcherHost : public BrowserMessageFilter {
int request_id,
int provider_id,
const GURL& document_url);
- void OnProviderCreated(int provider_id);
+ void OnGetRegistrationForReady(int thread_id,
+ int request_id,
+ int provider_id);
+ void OnProviderCreated(int provider_id,
+ int render_frame_id,
+ ServiceWorkerProviderType provider_type);
void OnProviderDestroyed(int provider_id);
void OnSetHostedVersionId(int provider_id, int64 version_id);
void OnWorkerReadyForInspection(int embedded_worker_id);
- void OnWorkerScriptLoaded(int embedded_worker_id, int thread_id);
+ void OnWorkerScriptLoaded(int embedded_worker_id,
+ int thread_id,
+ int provider_id);
void OnWorkerScriptLoadFailed(int embedded_worker_id);
void OnWorkerScriptEvaluated(int embedded_worker_id, bool success);
void OnWorkerStarted(int embedded_worker_id);
@@ -106,24 +120,23 @@ class CONTENT_EXPORT ServiceWorkerDispatcherHost : public BrowserMessageFilter {
void OnReportConsoleMessage(
int embedded_worker_id,
const EmbeddedWorkerHostMsg_ReportConsoleMessage_Params& params);
- void OnPostMessage(int handle_id,
- const base::string16& message,
- 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 OnPostMessageToWorker(
+ int handle_id,
+ const base::string16& message,
+ const std::vector<TransferredMessagePort>& sent_message_ports);
void OnServiceWorkerObjectDestroyed(int handle_id);
+ void OnTerminateWorker(int handle_id);
ServiceWorkerRegistrationHandle* FindRegistrationHandle(
int provider_id,
int64 registration_id);
void GetRegistrationObjectInfoAndVersionAttributes(
- int provider_id,
+ base::WeakPtr<ServiceWorkerProviderHost> provider_host,
ServiceWorkerRegistration* registration,
ServiceWorkerRegistrationObjectInfo* info,
ServiceWorkerVersionAttributes* attrs);
@@ -133,6 +146,7 @@ class CONTENT_EXPORT ServiceWorkerDispatcherHost : public BrowserMessageFilter {
int provider_id,
int request_id,
ServiceWorkerStatusCode status,
+ const std::string& status_message,
int64 registration_id);
void UnregistrationComplete(int thread_id,
@@ -146,9 +160,16 @@ class CONTENT_EXPORT ServiceWorkerDispatcherHost : public BrowserMessageFilter {
ServiceWorkerStatusCode status,
const scoped_refptr<ServiceWorkerRegistration>& registration);
+ void GetRegistrationForReadyComplete(
+ int thread_id,
+ int request_id,
+ base::WeakPtr<ServiceWorkerProviderHost> provider_host,
+ ServiceWorkerRegistration* registration);
+
void SendRegistrationError(int thread_id,
int request_id,
- ServiceWorkerStatusCode status);
+ ServiceWorkerStatusCode status,
+ const std::string& status_message);
void SendUnregistrationError(int thread_id,
int request_id,
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 3f21c458832..8e925cd625d 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
@@ -35,6 +35,7 @@ static void SaveStatusCallback(bool* called,
}
static const int kRenderProcessId = 1;
+static const int kRenderFrameId = 1;
class TestingServiceWorkerDispatcherHost : public ServiceWorkerDispatcherHost {
public:
@@ -68,7 +69,8 @@ class ServiceWorkerDispatcherHostTest : public testing::Test {
: browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
void SetUp() override {
- helper_.reset(new EmbeddedWorkerTestHelper(kRenderProcessId));
+ helper_.reset(
+ new EmbeddedWorkerTestHelper(base::FilePath(), kRenderProcessId));
dispatcher_host_ = new TestingServiceWorkerDispatcherHost(
kRenderProcessId, context_wrapper(), &resource_context_, helper_.get());
}
@@ -127,6 +129,14 @@ class ServiceWorkerDispatcherHostTest : public testing::Test {
dispatcher_host_->ipc_sink()->ClearMessages();
}
+ ServiceWorkerProviderHost* CreateServiceWorkerProviderHost(int provider_id) {
+ return new ServiceWorkerProviderHost(
+ kRenderProcessId, kRenderFrameId, provider_id,
+ SERVICE_WORKER_PROVIDER_FOR_WINDOW, context()->AsWeakPtr(),
+ dispatcher_host_.get());
+ }
+
+
TestBrowserThreadBundle browser_thread_bundle_;
content::MockResourceContext resource_context_;
scoped_ptr<EmbeddedWorkerTestHelper> helper_;
@@ -138,7 +148,9 @@ class ServiceWorkerTestContentBrowserClient : public TestContentBrowserClient {
ServiceWorkerTestContentBrowserClient() {}
bool AllowServiceWorker(const GURL& scope,
const GURL& first_party,
- content::ResourceContext* context) override {
+ content::ResourceContext* context,
+ int render_process_id,
+ int render_frame_id) override {
return false;
}
};
@@ -150,8 +162,8 @@ TEST_F(ServiceWorkerDispatcherHostTest,
SetBrowserClientForTesting(&test_browser_client);
const int64 kProviderId = 99; // Dummy value
- scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
- kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
+ scoped_ptr<ServiceWorkerProviderHost> host(
+ CreateServiceWorkerProviderHost(kProviderId));
host->SetDocumentUrl(GURL("https://www.example.com/foo"));
context()->AddProviderHost(host.Pass());
@@ -171,8 +183,8 @@ TEST_F(ServiceWorkerDispatcherHostTest,
TEST_F(ServiceWorkerDispatcherHostTest, Register_HTTPS) {
const int64 kProviderId = 99; // Dummy value
- scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
- kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
+ scoped_ptr<ServiceWorkerProviderHost> host(
+ CreateServiceWorkerProviderHost(kProviderId));
host->SetDocumentUrl(GURL("https://www.example.com/foo"));
context()->AddProviderHost(host.Pass());
@@ -184,8 +196,8 @@ TEST_F(ServiceWorkerDispatcherHostTest, Register_HTTPS) {
TEST_F(ServiceWorkerDispatcherHostTest, Register_NonSecureTransportLocalhost) {
const int64 kProviderId = 99; // Dummy value
- scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
- kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
+ scoped_ptr<ServiceWorkerProviderHost> host(
+ CreateServiceWorkerProviderHost(kProviderId));
host->SetDocumentUrl(GURL("http://127.0.0.3:81/foo"));
context()->AddProviderHost(host.Pass());
@@ -195,50 +207,22 @@ TEST_F(ServiceWorkerDispatcherHostTest, Register_NonSecureTransportLocalhost) {
ServiceWorkerMsg_ServiceWorkerRegistered::ID);
}
-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));
+ scoped_ptr<ServiceWorkerProviderHost> host(
+ CreateServiceWorkerProviderHost(kProviderId));
host->SetDocumentUrl(GURL("https://www.example.com/foo"));
context()->AddProviderHost(host.Pass());
- SendRegister(
- kProviderId, GURL(""), GURL("https://www.example.com/bar/hoge.js"));
+ 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));
+ scoped_ptr<ServiceWorkerProviderHost> host(
+ CreateServiceWorkerProviderHost(kProviderId));
host->SetDocumentUrl(GURL("https://www.example.com/foo"));
context()->AddProviderHost(host.Pass());
@@ -248,8 +232,8 @@ TEST_F(ServiceWorkerDispatcherHostTest, Register_InvalidScriptShouldFail) {
TEST_F(ServiceWorkerDispatcherHostTest, Register_NonSecureOriginShouldFail) {
const int64 kProviderId = 99; // Dummy value
- scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
- kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
+ scoped_ptr<ServiceWorkerProviderHost> host(
+ CreateServiceWorkerProviderHost(kProviderId));
host->SetDocumentUrl(GURL("http://www.example.com/foo"));
context()->AddProviderHost(host.Pass());
@@ -261,8 +245,8 @@ TEST_F(ServiceWorkerDispatcherHostTest, Register_NonSecureOriginShouldFail) {
TEST_F(ServiceWorkerDispatcherHostTest, Register_CrossOriginShouldFail) {
const int64 kProviderId = 99; // Dummy value
- scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
- kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
+ scoped_ptr<ServiceWorkerProviderHost> host(
+ CreateServiceWorkerProviderHost(kProviderId));
host->SetDocumentUrl(GURL("https://www.example.com/foo"));
context()->AddProviderHost(host.Pass());
@@ -303,10 +287,58 @@ TEST_F(ServiceWorkerDispatcherHostTest, Register_CrossOriginShouldFail) {
EXPECT_EQ(6, dispatcher_host_->bad_messages_received_count_);
}
+TEST_F(ServiceWorkerDispatcherHostTest,
+ Register_FileSystemDocumentShouldFail) {
+ const int64 kProviderId = 99; // Dummy value
+ scoped_ptr<ServiceWorkerProviderHost> host(
+ CreateServiceWorkerProviderHost(kProviderId));
+ host->SetDocumentUrl(GURL("filesystem:https://www.example.com/temporary/a"));
+ context()->AddProviderHost(host.Pass());
+
+ SendRegister(kProviderId,
+ GURL("filesystem:https://www.example.com/temporary/"),
+ GURL("https://www.example.com/temporary/bar"));
+ EXPECT_EQ(1, dispatcher_host_->bad_messages_received_count_);
+
+ SendRegister(kProviderId,
+ GURL("https://www.example.com/temporary/"),
+ GURL("filesystem:https://www.example.com/temporary/bar"));
+ EXPECT_EQ(2, dispatcher_host_->bad_messages_received_count_);
+
+ SendRegister(kProviderId,
+ GURL("filesystem:https://www.example.com/temporary/"),
+ GURL("filesystem:https://www.example.com/temporary/bar"));
+ EXPECT_EQ(3, dispatcher_host_->bad_messages_received_count_);
+}
+
+TEST_F(ServiceWorkerDispatcherHostTest,
+ Register_FileSystemScriptOrScopeShouldFail) {
+ const int64 kProviderId = 99; // Dummy value
+ scoped_ptr<ServiceWorkerProviderHost> host(
+ CreateServiceWorkerProviderHost(kProviderId));
+ host->SetDocumentUrl(GURL("https://www.example.com/temporary/"));
+ context()->AddProviderHost(host.Pass());
+
+ SendRegister(kProviderId,
+ GURL("filesystem:https://www.example.com/temporary/"),
+ GURL("https://www.example.com/temporary/bar"));
+ EXPECT_EQ(1, dispatcher_host_->bad_messages_received_count_);
+
+ SendRegister(kProviderId,
+ GURL("https://www.example.com/temporary/"),
+ GURL("filesystem:https://www.example.com/temporary/bar"));
+ EXPECT_EQ(2, dispatcher_host_->bad_messages_received_count_);
+
+ SendRegister(kProviderId,
+ GURL("filesystem:https://www.example.com/temporary/"),
+ GURL("filesystem:https://www.example.com/temporary/bar"));
+ EXPECT_EQ(3, 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));
+ scoped_ptr<ServiceWorkerProviderHost> host(
+ CreateServiceWorkerProviderHost(kProviderId));
host->SetDocumentUrl(GURL("https://www.example.com/foo"));
context()->AddProviderHost(host.Pass());
@@ -316,10 +348,10 @@ TEST_F(ServiceWorkerDispatcherHostTest, Unregister_HTTPS) {
}
TEST_F(ServiceWorkerDispatcherHostTest,
- Unregister_NonSecureTransportLocalhost) {
+ Unregister_NotSecureTransportLocalhost) {
const int64 kProviderId = 99; // Dummy value
- scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
- kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
+ scoped_ptr<ServiceWorkerProviderHost> host(
+ CreateServiceWorkerProviderHost(kProviderId));
host->SetDocumentUrl(GURL("http://localhost/foo"));
context()->AddProviderHost(host.Pass());
@@ -330,8 +362,8 @@ TEST_F(ServiceWorkerDispatcherHostTest,
TEST_F(ServiceWorkerDispatcherHostTest, Unregister_CrossOriginShouldFail) {
const int64 kProviderId = 99; // Dummy value
- scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
- kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
+ scoped_ptr<ServiceWorkerProviderHost> host(
+ CreateServiceWorkerProviderHost(kProviderId));
host->SetDocumentUrl(GURL("https://www.example.com/foo"));
context()->AddProviderHost(host.Pass());
@@ -341,8 +373,8 @@ TEST_F(ServiceWorkerDispatcherHostTest, Unregister_CrossOriginShouldFail) {
TEST_F(ServiceWorkerDispatcherHostTest, Unregister_InvalidScopeShouldFail) {
const int64 kProviderId = 99; // Dummy value
- scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
- kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
+ scoped_ptr<ServiceWorkerProviderHost> host(
+ CreateServiceWorkerProviderHost(kProviderId));
host->SetDocumentUrl(GURL("https://www.example.com/foo"));
context()->AddProviderHost(host.Pass());
@@ -352,8 +384,8 @@ TEST_F(ServiceWorkerDispatcherHostTest, Unregister_InvalidScopeShouldFail) {
TEST_F(ServiceWorkerDispatcherHostTest, Unregister_NonSecureOriginShouldFail) {
const int64 kProviderId = 99; // Dummy value
- scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
- kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
+ scoped_ptr<ServiceWorkerProviderHost> host(
+ CreateServiceWorkerProviderHost(kProviderId));
host->SetDocumentUrl(GURL("http://www.example.com/foo"));
context()->AddProviderHost(host.Pass());
@@ -376,13 +408,13 @@ TEST_F(ServiceWorkerDispatcherHostTest, EarlyContextDeletion) {
TEST_F(ServiceWorkerDispatcherHostTest, ProviderCreatedAndDestroyed) {
const int kProviderId = 1001; // Test with a value != kRenderProcessId.
- dispatcher_host_->OnMessageReceived(
- ServiceWorkerHostMsg_ProviderCreated(kProviderId));
+ dispatcher_host_->OnMessageReceived(ServiceWorkerHostMsg_ProviderCreated(
+ kProviderId, MSG_ROUTING_NONE, SERVICE_WORKER_PROVIDER_FOR_WINDOW));
EXPECT_TRUE(context()->GetProviderHost(kRenderProcessId, kProviderId));
// Two with the same ID should be seen as a bad message.
- dispatcher_host_->OnMessageReceived(
- ServiceWorkerHostMsg_ProviderCreated(kProviderId));
+ dispatcher_host_->OnMessageReceived(ServiceWorkerHostMsg_ProviderCreated(
+ kProviderId, MSG_ROUTING_NONE, SERVICE_WORKER_PROVIDER_FOR_WINDOW));
EXPECT_EQ(1, dispatcher_host_->bad_messages_received_count_);
dispatcher_host_->OnMessageReceived(
@@ -396,8 +428,8 @@ TEST_F(ServiceWorkerDispatcherHostTest, ProviderCreatedAndDestroyed) {
// Deletion of the dispatcher_host should cause providers for that
// process to get deleted as well.
- dispatcher_host_->OnMessageReceived(
- ServiceWorkerHostMsg_ProviderCreated(kProviderId));
+ dispatcher_host_->OnMessageReceived(ServiceWorkerHostMsg_ProviderCreated(
+ kProviderId, MSG_ROUTING_NONE, SERVICE_WORKER_PROVIDER_FOR_WINDOW));
EXPECT_TRUE(context()->GetProviderHost(kRenderProcessId, kProviderId));
EXPECT_TRUE(dispatcher_host_->HasOneRef());
dispatcher_host_ = NULL;
@@ -406,8 +438,8 @@ TEST_F(ServiceWorkerDispatcherHostTest, ProviderCreatedAndDestroyed) {
TEST_F(ServiceWorkerDispatcherHostTest, GetRegistration_SameOrigin) {
const int64 kProviderId = 99; // Dummy value
- scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
- kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
+ scoped_ptr<ServiceWorkerProviderHost> host(
+ CreateServiceWorkerProviderHost(kProviderId));
host->SetDocumentUrl(GURL("https://www.example.com/foo"));
context()->AddProviderHost(host.Pass());
@@ -418,8 +450,8 @@ TEST_F(ServiceWorkerDispatcherHostTest, GetRegistration_SameOrigin) {
TEST_F(ServiceWorkerDispatcherHostTest, GetRegistration_CrossOriginShouldFail) {
const int64 kProviderId = 99; // Dummy value
- scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
- kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
+ scoped_ptr<ServiceWorkerProviderHost> host(
+ CreateServiceWorkerProviderHost(kProviderId));
host->SetDocumentUrl(GURL("https://www.example.com/foo"));
context()->AddProviderHost(host.Pass());
@@ -430,8 +462,8 @@ TEST_F(ServiceWorkerDispatcherHostTest, GetRegistration_CrossOriginShouldFail) {
TEST_F(ServiceWorkerDispatcherHostTest,
GetRegistration_InvalidScopeShouldFail) {
const int64 kProviderId = 99; // Dummy value
- scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
- kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
+ scoped_ptr<ServiceWorkerProviderHost> host(
+ CreateServiceWorkerProviderHost(kProviderId));
host->SetDocumentUrl(GURL("https://www.example.com/foo"));
context()->AddProviderHost(host.Pass());
@@ -440,10 +472,10 @@ TEST_F(ServiceWorkerDispatcherHostTest,
}
TEST_F(ServiceWorkerDispatcherHostTest,
- GetRegistration_NotSecureOriginShouldFail) {
+ GetRegistration_NonSecureOriginShouldFail) {
const int64 kProviderId = 99; // Dummy value
- scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
- kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
+ scoped_ptr<ServiceWorkerProviderHost> host(
+ CreateServiceWorkerProviderHost(kProviderId));
host->SetDocumentUrl(GURL("http://www.example.com/foo"));
context()->AddProviderHost(host.Pass());
@@ -465,8 +497,8 @@ TEST_F(ServiceWorkerDispatcherHostTest, GetRegistration_EarlyContextDeletion) {
TEST_F(ServiceWorkerDispatcherHostTest, CleanupOnRendererCrash) {
// Add a provider and worker.
const int64 kProviderId = 99; // Dummy value
- dispatcher_host_->OnMessageReceived(
- ServiceWorkerHostMsg_ProviderCreated(kProviderId));
+ dispatcher_host_->OnMessageReceived(ServiceWorkerHostMsg_ProviderCreated(
+ kProviderId, MSG_ROUTING_NONE, SERVICE_WORKER_PROVIDER_FOR_WINDOW));
GURL pattern = GURL("http://www.example.com/");
scoped_refptr<ServiceWorkerRegistration> registration(
@@ -478,11 +510,28 @@ TEST_F(ServiceWorkerDispatcherHostTest, CleanupOnRendererCrash) {
GURL("http://www.example.com/service_worker.js"),
1L,
helper_->context()->AsWeakPtr()));
+ std::vector<ServiceWorkerDatabase::ResourceRecord> records;
+ records.push_back(
+ ServiceWorkerDatabase::ResourceRecord(10, version->script_url(), 100));
+ version->script_cache_map()->SetResources(records);
+
+ // Make the registration findable via storage functions.
+ helper_->context()->storage()->LazyInitialize(base::Bind(&base::DoNothing));
+ base::RunLoop().RunUntilIdle();
+ bool called = false;
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_ABORT;
+ helper_->context()->storage()->StoreRegistration(
+ registration.get(),
+ version.get(),
+ base::Bind(&SaveStatusCallback, &called, &status));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(called);
+ ASSERT_EQ(SERVICE_WORKER_OK, status);
+
helper_->SimulateAddProcessToPattern(pattern, kRenderProcessId);
// Start up the worker.
- bool called;
- ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_ABORT;
+ status = SERVICE_WORKER_ERROR_ABORT;
version->StartWorker(base::Bind(&SaveStatusCallback, &called, &status));
base::RunLoop().RunUntilIdle();
@@ -511,8 +560,8 @@ TEST_F(ServiceWorkerDispatcherHostTest, CleanupOnRendererCrash) {
// 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));
+ new_dispatcher_host->OnMessageReceived(ServiceWorkerHostMsg_ProviderCreated(
+ kProviderId, MSG_ROUTING_NONE, SERVICE_WORKER_PROVIDER_FOR_WINDOW));
EXPECT_EQ(0, new_dispatcher_host->bad_messages_received_count_);
}
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 7ed3051e3f1..771cbb18707 100644
--- a/chromium/content/browser/service_worker/service_worker_fetch_dispatcher.cc
+++ b/chromium/content/browser/service_worker/service_worker_fetch_dispatcher.cc
@@ -5,7 +5,7 @@
#include "content/browser/service_worker/service_worker_fetch_dispatcher.h"
#include "base/bind.h"
-#include "base/debug/trace_event.h"
+#include "base/trace_event/trace_event.h"
#include "content/browser/service_worker/service_worker_version.h"
namespace content {
@@ -86,7 +86,7 @@ void ServiceWorkerFetchDispatcher::DidFinish(
request_.get());
DCHECK(!fetch_callback_.is_null());
FetchCallback fetch_callback = fetch_callback_;
- fetch_callback.Run(status, fetch_result, response);
+ fetch_callback.Run(status, fetch_result, response, version_);
}
} // 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 f20fb949548..f0165b6cccb 100644
--- a/chromium/content/browser/service_worker/service_worker_fetch_dispatcher.h
+++ b/chromium/content/browser/service_worker/service_worker_fetch_dispatcher.h
@@ -20,7 +20,9 @@ class ServiceWorkerFetchDispatcher {
public:
typedef base::Callback<void(ServiceWorkerStatusCode,
ServiceWorkerFetchEventResult,
- const ServiceWorkerResponse&)> FetchCallback;
+ const ServiceWorkerResponse&,
+ scoped_refptr<ServiceWorkerVersion>)>
+ FetchCallback;
ServiceWorkerFetchDispatcher(scoped_ptr<ServiceWorkerFetchRequest> request,
ServiceWorkerVersion* version,
diff --git a/chromium/content/browser/service_worker/service_worker_handle.cc b/chromium/content/browser/service_worker/service_worker_handle.cc
index f39904e4035..086135ba831 100644
--- a/chromium/content/browser/service_worker/service_worker_handle.cc
+++ b/chromium/content/browser/service_worker/service_worker_handle.cc
@@ -7,7 +7,7 @@
#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/browser/service_worker/service_worker_registration.h"
#include "content/common/service_worker/service_worker_messages.h"
-#include "ipc/ipc_sender.h"
+#include "content/common/service_worker/service_worker_types.h"
namespace content {
@@ -38,75 +38,43 @@ GetWebServiceWorkerState(ServiceWorkerVersion* version) {
scoped_ptr<ServiceWorkerHandle> ServiceWorkerHandle::Create(
base::WeakPtr<ServiceWorkerContextCore> context,
- IPC::Sender* sender,
- int thread_id,
- int provider_id,
+ base::WeakPtr<ServiceWorkerProviderHost> provider_host,
ServiceWorkerVersion* version) {
- if (!context || !version)
+ if (!context || !provider_host || !version)
return scoped_ptr<ServiceWorkerHandle>();
- ServiceWorkerRegistration* registration =
- context->GetLiveRegistration(version->registration_id());
+ DCHECK(context->GetLiveRegistration(version->registration_id()));
return make_scoped_ptr(new ServiceWorkerHandle(
- context, sender, thread_id, provider_id, registration, version));
+ context, provider_host, version));
}
ServiceWorkerHandle::ServiceWorkerHandle(
base::WeakPtr<ServiceWorkerContextCore> context,
- IPC::Sender* sender,
- int thread_id,
- int provider_id,
- ServiceWorkerRegistration* registration,
+ base::WeakPtr<ServiceWorkerProviderHost> provider_host,
ServiceWorkerVersion* version)
: context_(context),
- sender_(sender),
- thread_id_(thread_id),
- provider_id_(provider_id),
+ provider_host_(provider_host),
+ provider_id_(provider_host ? provider_host->provider_id()
+ : kInvalidServiceWorkerProviderId),
handle_id_(context.get() ? context->GetNewServiceWorkerHandleId() : -1),
ref_count_(1),
- registration_(registration),
version_(version) {
version_->AddListener(this);
}
ServiceWorkerHandle::~ServiceWorkerHandle() {
version_->RemoveListener(this);
- // TODO(kinuko): At this point we can discard the registration if
- // all documents/handles that have a reference to the registration is
- // closed or freed up, but could also keep it alive in cache
- // (e.g. in context_) for a while with some timer so that we don't
- // need to re-load the same registration from disk over and over.
-}
-
-void ServiceWorkerHandle::OnWorkerStarted(ServiceWorkerVersion* version) {
-}
-
-void ServiceWorkerHandle::OnWorkerStopped(ServiceWorkerVersion* version) {
-}
-
-void ServiceWorkerHandle::OnErrorReported(ServiceWorkerVersion* version,
- const base::string16& error_message,
- int line_number,
- int column_number,
- const GURL& source_url) {
-}
-
-void ServiceWorkerHandle::OnReportConsoleMessage(ServiceWorkerVersion* version,
- int source_identifier,
- int message_level,
- const base::string16& message,
- int line_number,
- const GURL& source_url) {
}
void ServiceWorkerHandle::OnVersionStateChanged(ServiceWorkerVersion* version) {
- sender_->Send(new ServiceWorkerMsg_ServiceWorkerStateChanged(
- thread_id_, handle_id_, GetWebServiceWorkerState(version)));
+ if (!provider_host_)
+ return;
+ provider_host_->SendServiceWorkerStateChangedMessage(
+ handle_id_, GetWebServiceWorkerState(version));
}
ServiceWorkerObjectInfo ServiceWorkerHandle::GetObjectInfo() {
ServiceWorkerObjectInfo info;
info.handle_id = handle_id_;
- info.scope = registration_->pattern();
info.url = version_->script_url();
info.state = GetWebServiceWorkerState(version_.get());
info.version_id = version_->version_id();
diff --git a/chromium/content/browser/service_worker/service_worker_handle.h b/chromium/content/browser/service_worker/service_worker_handle.h
index b7696407089..7dae8823fa7 100644
--- a/chromium/content/browser/service_worker/service_worker_handle.h
+++ b/chromium/content/browser/service_worker/service_worker_handle.h
@@ -20,59 +20,33 @@ class Sender;
namespace content {
class ServiceWorkerContextCore;
-class ServiceWorkerRegistration;
// Roughly corresponds to one ServiceWorker object in the renderer process
// (WebServiceWorkerImpl).
-// Has references to the corresponding ServiceWorkerVersion and
-// ServiceWorkerRegistration (therefore they're guaranteed to be alive while
-// this handle is around).
+// Has references to the corresponding ServiceWorkerVersion in order to ensure
+// that the version is alive while this handle is around.
class CONTENT_EXPORT ServiceWorkerHandle
: NON_EXPORTED_BASE(public ServiceWorkerVersion::Listener) {
public:
- // Creates a handle for a live version. The version's corresponding
- // registration must be also alive.
- // This may return NULL if |context|.get() or |version| is NULL.
- // |sender| and |thread_id| will be used to send messages to the
- // corresponding WebServiceWorkerImpl (which should live on |thread_id|
- // in the child process).
+ // Creates a handle for a live version. This may return nullptr if any of
+ // |context|, |provider_host| and |version| is nullptr.
static scoped_ptr<ServiceWorkerHandle> Create(
base::WeakPtr<ServiceWorkerContextCore> context,
- IPC::Sender* sender,
- int thread_id,
- int provider_id,
+ base::WeakPtr<ServiceWorkerProviderHost> provider_host,
ServiceWorkerVersion* version);
ServiceWorkerHandle(base::WeakPtr<ServiceWorkerContextCore> context,
- IPC::Sender* sender,
- int thread_id,
- int provider_id,
- ServiceWorkerRegistration* registration,
+ base::WeakPtr<ServiceWorkerProviderHost> provider_host,
ServiceWorkerVersion* version);
~ServiceWorkerHandle() override;
// ServiceWorkerVersion::Listener overrides.
- 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(); }
bool HasNoRefCount() const { return ref_count_ <= 0; }
@@ -81,12 +55,10 @@ class CONTENT_EXPORT ServiceWorkerHandle
private:
base::WeakPtr<ServiceWorkerContextCore> context_;
- IPC::Sender* sender_; // Not owned, it should always outlive this.
- const int thread_id_;
+ base::WeakPtr<ServiceWorkerProviderHost> provider_host_;
const int provider_id_;
const int handle_id_;
int ref_count_; // Created with 1.
- scoped_refptr<ServiceWorkerRegistration> registration_;
scoped_refptr<ServiceWorkerVersion> version_;
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerHandle);
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 8adf4f50bfe..375f6170d82 100644
--- a/chromium/content/browser/service_worker/service_worker_handle_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_handle_unittest.cc
@@ -7,12 +7,14 @@
#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_dispatcher_host.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_test_utils.h"
#include "content/browser/service_worker/service_worker_version.h"
#include "content/common/service_worker/embedded_worker_messages.h"
#include "content/common/service_worker/service_worker_messages.h"
+#include "content/public/test/mock_resource_context.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_test_sink.h"
@@ -24,6 +26,7 @@ namespace content {
namespace {
const int kRenderProcessId = 88; // A dummy ID for testing.
+const int kRenderFrameId = 44; // A dummy ID for testing.
void VerifyStateChangedMessage(int expected_handle_id,
blink::WebServiceWorkerState expected_state,
@@ -32,19 +35,48 @@ void VerifyStateChangedMessage(int expected_handle_id,
ServiceWorkerMsg_ServiceWorkerStateChanged::Param param;
ASSERT_TRUE(ServiceWorkerMsg_ServiceWorkerStateChanged::Read(
message, &param));
- EXPECT_EQ(expected_handle_id, param.b);
- EXPECT_EQ(expected_state, param.c);
+ EXPECT_EQ(expected_handle_id, get<1>(param));
+ EXPECT_EQ(expected_state, get<2>(param));
}
} // namespace
+class TestingServiceWorkerDispatcherHost : public ServiceWorkerDispatcherHost {
+ public:
+ TestingServiceWorkerDispatcherHost(
+ int process_id,
+ ServiceWorkerContextWrapper* context_wrapper,
+ ResourceContext* resource_context,
+ EmbeddedWorkerTestHelper* helper)
+ : ServiceWorkerDispatcherHost(process_id, nullptr, resource_context),
+ bad_message_received_count_(0),
+ helper_(helper) {
+ Init(context_wrapper);
+ }
+
+ bool Send(IPC::Message* message) override { return helper_->Send(message); }
+
+ void BadMessageReceived() override { ++bad_message_received_count_; }
+
+ int bad_message_received_count_;
+
+ protected:
+ EmbeddedWorkerTestHelper* helper_;
+ ~TestingServiceWorkerDispatcherHost() override {}
+};
+
class ServiceWorkerHandleTest : public testing::Test {
public:
ServiceWorkerHandleTest()
: browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
void SetUp() override {
- helper_.reset(new EmbeddedWorkerTestHelper(kRenderProcessId));
+ helper_.reset(
+ new EmbeddedWorkerTestHelper(base::FilePath(), kRenderProcessId));
+
+ dispatcher_host_ = new TestingServiceWorkerDispatcherHost(
+ kRenderProcessId, helper_->context_wrapper(),
+ &resource_context_, helper_.get());
const GURL pattern("http://www.example.com/");
registration_ = new ServiceWorkerRegistration(
@@ -56,22 +88,47 @@ class ServiceWorkerHandleTest : public testing::Test {
GURL("http://www.example.com/service_worker.js"),
1L,
helper_->context()->AsWeakPtr());
+ std::vector<ServiceWorkerDatabase::ResourceRecord> records;
+ records.push_back(
+ ServiceWorkerDatabase::ResourceRecord(10, version_->script_url(), 100));
+ version_->script_cache_map()->SetResources(records);
+
+ // Make the registration findable via storage functions.
+ helper_->context()->storage()->LazyInitialize(base::Bind(&base::DoNothing));
+ base::RunLoop().RunUntilIdle();
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
+ helper_->context()->storage()->StoreRegistration(
+ registration_.get(),
+ version_.get(),
+ CreateReceiverOnCurrentThread(&status));
+ base::RunLoop().RunUntilIdle();
+ ASSERT_EQ(SERVICE_WORKER_OK, status);
+
+ provider_host_.reset(new ServiceWorkerProviderHost(
+ kRenderProcessId, kRenderFrameId, 1, SERVICE_WORKER_PROVIDER_FOR_WINDOW,
+ helper_->context()->AsWeakPtr(), dispatcher_host_.get()));
helper_->SimulateAddProcessToPattern(pattern, kRenderProcessId);
}
void TearDown() override {
+ dispatcher_host_ = NULL;
registration_ = NULL;
version_ = NULL;
+ provider_host_.reset();
helper_.reset();
}
IPC::TestSink* ipc_sink() { return helper_->ipc_sink(); }
TestBrowserThreadBundle browser_thread_bundle_;
+ MockResourceContext resource_context_;
+
scoped_ptr<EmbeddedWorkerTestHelper> helper_;
+ scoped_ptr<ServiceWorkerProviderHost> provider_host_;
scoped_refptr<ServiceWorkerRegistration> registration_;
scoped_refptr<ServiceWorkerVersion> version_;
+ scoped_refptr<TestingServiceWorkerDispatcherHost> dispatcher_host_;
private:
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerHandleTest);
@@ -80,9 +137,7 @@ class ServiceWorkerHandleTest : public testing::Test {
TEST_F(ServiceWorkerHandleTest, OnVersionStateChanged) {
scoped_ptr<ServiceWorkerHandle> handle =
ServiceWorkerHandle::Create(helper_->context()->AsWeakPtr(),
- helper_.get(),
- 1 /* thread_id */,
- 33 /* provider_id */,
+ provider_host_->AsWeakPtr(),
version_.get());
// Start the worker, and then...
@@ -94,13 +149,14 @@ TEST_F(ServiceWorkerHandleTest, OnVersionStateChanged) {
// ...dispatch install event.
status = SERVICE_WORKER_ERROR_FAILED;
version_->SetStatus(ServiceWorkerVersion::INSTALLING);
- version_->DispatchInstallEvent(-1, CreateReceiverOnCurrentThread(&status));
+ version_->DispatchInstallEvent(CreateReceiverOnCurrentThread(&status));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(SERVICE_WORKER_OK, status);
version_->SetStatus(ServiceWorkerVersion::INSTALLED);
ASSERT_EQ(4UL, ipc_sink()->message_count());
+ ASSERT_EQ(0L, dispatcher_host_->bad_message_received_count_);
// We should be sending 1. StartWorker,
EXPECT_EQ(EmbeddedWorkerMsg_StartWorker::ID,
diff --git a/chromium/content/browser/service_worker/service_worker_info.cc b/chromium/content/browser/service_worker/service_worker_info.cc
index 1efe110c62f..8c5f774abd0 100644
--- a/chromium/content/browser/service_worker/service_worker_info.cc
+++ b/chromium/content/browser/service_worker/service_worker_info.cc
@@ -12,6 +12,7 @@ namespace content {
ServiceWorkerVersionInfo::ServiceWorkerVersionInfo()
: running_status(ServiceWorkerVersion::STOPPED),
status(ServiceWorkerVersion::NEW),
+ registration_id(kInvalidServiceWorkerRegistrationId),
version_id(kInvalidServiceWorkerVersionId),
process_id(-1),
thread_id(-1),
@@ -22,6 +23,7 @@ ServiceWorkerVersionInfo::ServiceWorkerVersionInfo(
ServiceWorkerVersion::RunningStatus running_status,
ServiceWorkerVersion::Status status,
const GURL& script_url,
+ int64 registration_id,
int64 version_id,
int process_id,
int thread_id,
@@ -29,6 +31,7 @@ ServiceWorkerVersionInfo::ServiceWorkerVersionInfo(
: running_status(running_status),
status(status),
script_url(script_url),
+ registration_id(registration_id),
version_id(version_id),
process_id(process_id),
thread_id(thread_id),
@@ -39,18 +42,31 @@ ServiceWorkerVersionInfo::~ServiceWorkerVersionInfo() {}
ServiceWorkerRegistrationInfo::ServiceWorkerRegistrationInfo()
: registration_id(kInvalidServiceWorkerRegistrationId),
+ delete_flag(IS_NOT_DELETED),
+ stored_version_size_bytes(0) {
+}
+
+ServiceWorkerRegistrationInfo::ServiceWorkerRegistrationInfo(
+ const GURL& pattern,
+ int64 registration_id,
+ DeleteFlag delete_flag)
+ : pattern(pattern),
+ registration_id(registration_id),
+ delete_flag(delete_flag),
stored_version_size_bytes(0) {
}
ServiceWorkerRegistrationInfo::ServiceWorkerRegistrationInfo(
const GURL& pattern,
int64 registration_id,
+ DeleteFlag delete_flag,
const ServiceWorkerVersionInfo& active_version,
const ServiceWorkerVersionInfo& waiting_version,
const ServiceWorkerVersionInfo& installing_version,
int64_t stored_version_size_bytes)
: pattern(pattern),
registration_id(registration_id),
+ delete_flag(delete_flag),
active_version(active_version),
waiting_version(waiting_version),
installing_version(installing_version),
diff --git a/chromium/content/browser/service_worker/service_worker_info.h b/chromium/content/browser/service_worker/service_worker_info.h
index 0e93bd0748b..fc77c859f02 100644
--- a/chromium/content/browser/service_worker/service_worker_info.h
+++ b/chromium/content/browser/service_worker/service_worker_info.h
@@ -7,18 +7,20 @@
#include <vector>
+#include "base/time/time.h"
#include "content/browser/service_worker/service_worker_version.h"
#include "content/common/content_export.h"
#include "url/gurl.h"
namespace content {
-class CONTENT_EXPORT ServiceWorkerVersionInfo {
+struct CONTENT_EXPORT ServiceWorkerVersionInfo {
public:
ServiceWorkerVersionInfo();
ServiceWorkerVersionInfo(ServiceWorkerVersion::RunningStatus running_status,
ServiceWorkerVersion::Status status,
const GURL& script_url,
+ int64 registration_id,
int64 version_id,
int process_id,
int thread_id,
@@ -28,18 +30,26 @@ class CONTENT_EXPORT ServiceWorkerVersionInfo {
ServiceWorkerVersion::RunningStatus running_status;
ServiceWorkerVersion::Status status;
GURL script_url;
+ int64 registration_id;
int64 version_id;
int process_id;
int thread_id;
int devtools_agent_route_id;
+ base::Time script_response_time;
+ base::Time script_last_modified;
};
-class CONTENT_EXPORT ServiceWorkerRegistrationInfo {
+struct CONTENT_EXPORT ServiceWorkerRegistrationInfo {
public:
+ enum DeleteFlag { IS_NOT_DELETED, IS_DELETED };
ServiceWorkerRegistrationInfo();
+ ServiceWorkerRegistrationInfo(const GURL& pattern,
+ int64 registration_id,
+ DeleteFlag delete_flag);
ServiceWorkerRegistrationInfo(
const GURL& pattern,
int64 registration_id,
+ DeleteFlag delete_flag,
const ServiceWorkerVersionInfo& active_version,
const ServiceWorkerVersionInfo& waiting_version,
const ServiceWorkerVersionInfo& installing_version,
@@ -48,7 +58,7 @@ class CONTENT_EXPORT ServiceWorkerRegistrationInfo {
GURL pattern;
int64 registration_id;
- ServiceWorkerVersionInfo controlling_version;
+ DeleteFlag delete_flag;
ServiceWorkerVersionInfo active_version;
ServiceWorkerVersionInfo waiting_version;
ServiceWorkerVersionInfo installing_version;
diff --git a/chromium/content/browser/service_worker/service_worker_internals_ui.cc b/chromium/content/browser/service_worker/service_worker_internals_ui.cc
index a7c8d716813..2176eb75946 100644
--- a/chromium/content/browser/service_worker/service_worker_internals_ui.cc
+++ b/chromium/content/browser/service_worker/service_worker_internals_ui.cc
@@ -12,7 +12,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/values.h"
#include "content/browser/devtools/devtools_agent_host_impl.h"
-#include "content/browser/devtools/embedded_worker_devtools_manager.h"
+#include "content/browser/devtools/service_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"
@@ -37,6 +37,11 @@ namespace content {
namespace {
+using GetRegistrationsCallback =
+ base::Callback<void(const std::vector<ServiceWorkerRegistrationInfo>&,
+ const std::vector<ServiceWorkerVersionInfo>&,
+ const std::vector<ServiceWorkerRegistrationInfo>&)>;
+
void OperationCompleteCallback(WeakPtr<ServiceWorkerInternalsUI> internals,
int callback_id,
ServiceWorkerStatusCode status) {
@@ -47,7 +52,7 @@ void OperationCompleteCallback(WeakPtr<ServiceWorkerInternalsUI> internals,
base::Bind(OperationCompleteCallback, internals, callback_id, status));
return;
}
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (internals) {
internals->web_ui()->CallJavascriptFunction(
"serviceworker.onOperationComplete",
@@ -72,9 +77,9 @@ void CallServiceWorkerVersionMethodWithVersionID(
callback));
return;
}
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
scoped_refptr<ServiceWorkerVersion> version =
- context->context()->GetLiveVersion(version_id);
+ context->GetLiveVersion(version_id);
if (!version.get()) {
callback.Run(SERVICE_WORKER_ERROR_NOT_FOUND);
return;
@@ -96,9 +101,9 @@ void DispatchPushEventWithVersionID(
callback));
return;
}
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
scoped_refptr<ServiceWorkerVersion> version =
- context->context()->GetLiveVersion(version_id);
+ context->GetLiveVersion(version_id);
if (!version.get()) {
callback.Run(SERVICE_WORKER_ERROR_NOT_FOUND);
return;
@@ -107,58 +112,6 @@ void DispatchPushEventWithVersionID(
version->DispatchPushEvent(callback, data);
}
-void UnregisterWithScope(
- scoped_refptr<ServiceWorkerContextWrapper> context,
- const GURL& scope,
- const ServiceWorkerInternalsUI::StatusCallback& callback) {
- if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
- BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(UnregisterWithScope, context, scope, callback));
- return;
- }
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- context->context()->UnregisterServiceWorker(scope, callback);
-}
-
-void WorkerStarted(const scoped_refptr<ServiceWorkerRegistration>& registration,
- const ServiceWorkerInternalsUI::StatusCallback& callback,
- ServiceWorkerStatusCode status) {
- callback.Run(status);
-}
-
-void StartActiveWorker(
- const ServiceWorkerInternalsUI::StatusCallback& callback,
- ServiceWorkerStatusCode status,
- const scoped_refptr<ServiceWorkerRegistration>& registration) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- if (status == SERVICE_WORKER_OK) {
- // Pass the reference of |registration| to WorkerStarted callback to prevent
- // it from being deleted while starting the worker. If the refcount of
- // |registration| is 1, it will be deleted after WorkerStarted is called.
- registration->active_version()->StartWorker(
- base::Bind(WorkerStarted, registration, callback));
- return;
- }
- callback.Run(SERVICE_WORKER_ERROR_NOT_FOUND);
-}
-
-void FindRegistrationForPattern(
- scoped_refptr<ServiceWorkerContextWrapper> context,
- const GURL& scope,
- const ServiceWorkerStorage::FindRegistrationCallback callback) {
- if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
- BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(FindRegistrationForPattern, context, scope, callback));
- return;
- }
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- context->context()->storage()->FindRegistrationForPattern(scope, callback);
-}
-
void UpdateVersionInfo(const ServiceWorkerVersionInfo& version,
DictionaryValue* info) {
switch (version.running_status) {
@@ -249,39 +202,33 @@ ListValue* GetVersionListValue(
return result;
}
-void GetRegistrationsOnIOThread(
+void DidGetStoredRegistrationsOnIOThread(
scoped_refptr<ServiceWorkerContextWrapper> context,
- base::Callback<void(const std::vector<ServiceWorkerRegistrationInfo>&)>
- callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- context->context()->storage()->GetAllRegistrations(callback);
+ const GetRegistrationsCallback& callback,
+ const std::vector<ServiceWorkerRegistrationInfo>& stored_registrations) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(callback, context->GetAllLiveRegistrationInfo(),
+ context->GetAllLiveVersionInfo(), stored_registrations));
}
-void OnStoredRegistrations(
+void GetRegistrationsOnIOThread(
scoped_refptr<ServiceWorkerContextWrapper> context,
- base::Callback<void(const std::vector<ServiceWorkerRegistrationInfo>&,
- const std::vector<ServiceWorkerVersionInfo>&,
- const std::vector<ServiceWorkerRegistrationInfo>&)>
- callback,
- const std::vector<ServiceWorkerRegistrationInfo>& stored_registrations) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(callback,
- context->context()->GetAllLiveRegistrationInfo(),
- context->context()->GetAllLiveVersionInfo(),
- stored_registrations));
+ const GetRegistrationsCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ context->GetAllRegistrations(
+ base::Bind(DidGetStoredRegistrationsOnIOThread, context, callback));
}
-void OnAllRegistrations(
+void DidGetRegistrations(
WeakPtr<ServiceWorkerInternalsUI> internals,
int partition_id,
const base::FilePath& context_path,
const std::vector<ServiceWorkerRegistrationInfo>& live_registrations,
const std::vector<ServiceWorkerVersionInfo>& live_versions,
const std::vector<ServiceWorkerRegistrationInfo>& stored_registrations) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!internals)
return;
@@ -304,30 +251,16 @@ class ServiceWorkerInternalsUI::PartitionObserver
: partition_id_(partition_id), web_ui_(web_ui) {}
~PartitionObserver() override {}
// ServiceWorkerContextObserver overrides:
- void OnWorkerStarted(int64 version_id,
- int process_id,
- int thread_id) override {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- web_ui_->CallJavascriptFunction(
- "serviceworker.onWorkerStarted",
- FundamentalValue(partition_id_),
- StringValue(base::Int64ToString(version_id)),
- FundamentalValue(process_id),
- FundamentalValue(thread_id));
- }
- void OnWorkerStopped(int64 version_id,
- int process_id,
- int thread_id) override {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ void OnRunningStateChanged(int64 version_id,
+ ServiceWorkerVersion::RunningStatus) override {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
web_ui_->CallJavascriptFunction(
- "serviceworker.onWorkerStopped",
- FundamentalValue(partition_id_),
- StringValue(base::Int64ToString(version_id)),
- FundamentalValue(process_id),
- FundamentalValue(thread_id));
+ "serviceworker.onRunningStateChanged", FundamentalValue(partition_id_),
+ StringValue(base::Int64ToString(version_id)));
}
- void OnVersionStateChanged(int64 version_id) override {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ void OnVersionStateChanged(int64 version_id,
+ ServiceWorkerVersion::Status) override {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
web_ui_->CallJavascriptFunction(
"serviceworker.onVersionStateChanged",
FundamentalValue(partition_id_),
@@ -337,7 +270,7 @@ class ServiceWorkerInternalsUI::PartitionObserver
int process_id,
int thread_id,
const ErrorInfo& info) override {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
ScopedVector<const Value> args;
args.push_back(new FundamentalValue(partition_id_));
args.push_back(new StringValue(base::Int64ToString(version_id)));
@@ -356,7 +289,7 @@ class ServiceWorkerInternalsUI::PartitionObserver
int process_id,
int thread_id,
const ConsoleMessage& message) override {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
ScopedVector<const Value> args;
args.push_back(new FundamentalValue(partition_id_));
args.push_back(new StringValue(base::Int64ToString(version_id)));
@@ -372,12 +305,14 @@ class ServiceWorkerInternalsUI::PartitionObserver
web_ui_->CallJavascriptFunction("serviceworker.onConsoleMessageReported",
args.get());
}
- void OnRegistrationStored(const GURL& pattern) override {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ void OnRegistrationStored(int64 registration_id,
+ const GURL& pattern) override {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
web_ui_->CallJavascriptFunction("serviceworker.onRegistrationStored",
StringValue(pattern.spec()));
}
- void OnRegistrationDeleted(const GURL& pattern) override {
+ void OnRegistrationDeleted(int64 registration_id,
+ const GURL& pattern) override {
web_ui_->CallJavascriptFunction("serviceworker.onRegistrationDeleted",
StringValue(pattern.spec()));
}
@@ -457,7 +392,7 @@ ServiceWorkerInternalsUI::~ServiceWorkerInternalsUI() {
void ServiceWorkerInternalsUI::GetOptions(const ListValue* args) {
DictionaryValue options;
options.SetBoolean("debug_on_start",
- EmbeddedWorkerDevToolsManager::GetInstance()
+ ServiceWorkerDevToolsManager::GetInstance()
->debug_service_worker_on_start());
web_ui()->CallJavascriptFunction("serviceworker.onOptions", options);
}
@@ -469,12 +404,12 @@ void ServiceWorkerInternalsUI::SetOption(const ListValue* args) {
!args->GetBoolean(1, &option_boolean)) {
return;
}
- EmbeddedWorkerDevToolsManager::GetInstance()
+ ServiceWorkerDevToolsManager::GetInstance()
->set_debug_service_worker_on_start(option_boolean);
}
void ServiceWorkerInternalsUI::GetAllRegistrations(const ListValue* args) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
BrowserContext* browser_context =
web_ui()->GetWebContents()->GetBrowserContext();
// Safe to use base::Unretained(this) because
@@ -503,18 +438,11 @@ void ServiceWorkerInternalsUI::AddContextFromStoragePartition(
}
BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(GetRegistrationsOnIOThread,
- context,
- base::Bind(OnStoredRegistrations,
- context,
- base::Bind(OnAllRegistrations,
- AsWeakPtr(),
- partition_id,
- context->is_incognito()
- ? base::FilePath()
- : partition->GetPath()))));
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(GetRegistrationsOnIOThread, context,
+ base::Bind(DidGetRegistrations, AsWeakPtr(), partition_id,
+ context->is_incognito() ? base::FilePath()
+ : partition->GetPath())));
}
void ServiceWorkerInternalsUI::RemoveObserverFromStoragePartition(
@@ -562,7 +490,7 @@ bool ServiceWorkerInternalsUI::GetServiceWorkerContext(
void ServiceWorkerInternalsUI::CallServiceWorkerVersionMethod(
ServiceWorkerVersionMethod method,
const ListValue* args) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
int callback_id;
const DictionaryValue* cmd_args = NULL;
int partition_id;
@@ -586,7 +514,7 @@ void ServiceWorkerInternalsUI::CallServiceWorkerVersionMethod(
void ServiceWorkerInternalsUI::DispatchPushEvent(
const ListValue* args) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
int callback_id;
int partition_id;
int64 version_id = 0;
@@ -608,7 +536,7 @@ void ServiceWorkerInternalsUI::DispatchPushEvent(
}
void ServiceWorkerInternalsUI::InspectWorker(const ListValue* args) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
int callback_id;
const DictionaryValue* cmd_args = NULL;
int process_id = 0;
@@ -623,7 +551,7 @@ void ServiceWorkerInternalsUI::InspectWorker(const ListValue* args) {
base::Callback<void(ServiceWorkerStatusCode)> callback =
base::Bind(OperationCompleteCallback, AsWeakPtr(), callback_id);
scoped_refptr<DevToolsAgentHostImpl> agent_host(
- EmbeddedWorkerDevToolsManager::GetInstance()
+ ServiceWorkerDevToolsManager::GetInstance()
->GetDevToolsAgentHostForWorker(process_id, devtools_agent_route_id));
if (!agent_host.get()) {
callback.Run(SERVICE_WORKER_ERROR_NOT_FOUND);
@@ -634,7 +562,7 @@ void ServiceWorkerInternalsUI::InspectWorker(const ListValue* args) {
}
void ServiceWorkerInternalsUI::Unregister(const ListValue* args) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
int callback_id;
int partition_id;
std::string scope_string;
@@ -654,7 +582,7 @@ void ServiceWorkerInternalsUI::Unregister(const ListValue* args) {
}
void ServiceWorkerInternalsUI::StartWorker(const ListValue* args) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
int callback_id;
int partition_id;
std::string scope_string;
@@ -667,11 +595,31 @@ void ServiceWorkerInternalsUI::StartWorker(const ListValue* args) {
!cmd_args->GetString("scope", &scope_string)) {
return;
}
-
base::Callback<void(ServiceWorkerStatusCode)> callback =
base::Bind(OperationCompleteCallback, AsWeakPtr(), callback_id);
- FindRegistrationForPattern(
- context, GURL(scope_string), base::Bind(StartActiveWorker, callback));
+ context->StartServiceWorker(GURL(scope_string), callback);
+}
+
+void ServiceWorkerInternalsUI::UnregisterWithScope(
+ scoped_refptr<ServiceWorkerContextWrapper> context,
+ const GURL& scope,
+ const ServiceWorkerInternalsUI::StatusCallback& callback) const {
+ if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&ServiceWorkerInternalsUI::UnregisterWithScope,
+ base::Unretained(this), context, scope, callback));
+ return;
+ }
+
+ if (!context->context()) {
+ callback.Run(SERVICE_WORKER_ERROR_ABORT);
+ return;
+ }
+
+ // ServiceWorkerContextWrapper::UnregisterServiceWorker doesn't work here
+ // because that reduces a status code to boolean.
+ context->context()->UnregisterServiceWorker(scope, callback);
}
} // namespace content
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 f0c09d68616..bc1c5b93511 100644
--- a/chromium/content/browser/service_worker/service_worker_internals_ui.h
+++ b/chromium/content/browser/service_worker/service_worker_internals_ui.h
@@ -25,7 +25,6 @@ namespace content {
class StoragePartition;
class ServiceWorkerContextWrapper;
-class ServiceWorkerRegistration;
class ServiceWorkerVersion;
class ServiceWorkerInternalsUI
@@ -65,7 +64,11 @@ class ServiceWorkerInternalsUI
StoragePartition** result_partition,
StoragePartition* storage_partition) const;
- base::ScopedPtrHashMap<uintptr_t, PartitionObserver> observers_;
+ void UnregisterWithScope(scoped_refptr<ServiceWorkerContextWrapper> context,
+ const GURL& scope,
+ const StatusCallback& callback) const;
+
+ base::ScopedPtrHashMap<uintptr_t, scoped_ptr<PartitionObserver>> observers_;
int next_partition_id_;
};
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 c3bfb396b4f..71cc1e1347e 100644
--- a/chromium/content/browser/service_worker/service_worker_job_coordinator.cc
+++ b/chromium/content/browser/service_worker/service_worker_job_coordinator.cc
@@ -10,6 +10,14 @@
namespace content {
+namespace {
+
+bool IsRegisterJob(const ServiceWorkerRegisterJobBase& job) {
+ return job.GetType() == ServiceWorkerRegisterJobBase::REGISTRATION_JOB;
+}
+
+}
+
ServiceWorkerJobCoordinator::JobQueue::JobQueue() {}
ServiceWorkerJobCoordinator::JobQueue::~JobQueue() {
@@ -21,10 +29,11 @@ ServiceWorkerJobCoordinator::JobQueue::~JobQueue() {
ServiceWorkerRegisterJobBase* ServiceWorkerJobCoordinator::JobQueue::Push(
scoped_ptr<ServiceWorkerRegisterJobBase> job) {
if (jobs_.empty()) {
- job->Start();
jobs_.push_back(job.release());
+ StartOneJob();
} else if (!job->Equals(jobs_.back())) {
jobs_.push_back(job.release());
+ DoomInstallingWorkerIfNeeded();
}
// Note we are releasing 'job' here.
@@ -38,7 +47,28 @@ void ServiceWorkerJobCoordinator::JobQueue::Pop(
jobs_.pop_front();
delete job;
if (!jobs_.empty())
- jobs_.front()->Start();
+ StartOneJob();
+}
+
+void ServiceWorkerJobCoordinator::JobQueue::DoomInstallingWorkerIfNeeded() {
+ DCHECK(!jobs_.empty());
+ if (!IsRegisterJob(*jobs_.front()))
+ return;
+ ServiceWorkerRegisterJob* job =
+ static_cast<ServiceWorkerRegisterJob*>(jobs_.front());
+ std::deque<ServiceWorkerRegisterJobBase*>::iterator it = jobs_.begin();
+ for (++it; it != jobs_.end(); ++it) {
+ if (IsRegisterJob(**it)) {
+ job->DoomInstallingWorker();
+ return;
+ }
+ }
+}
+
+void ServiceWorkerJobCoordinator::JobQueue::StartOneJob() {
+ DCHECK(!jobs_.empty());
+ jobs_.front()->Start();
+ DoomInstallingWorkerIfNeeded();
}
void ServiceWorkerJobCoordinator::JobQueue::AbortAll() {
@@ -93,12 +123,14 @@ void ServiceWorkerJobCoordinator::Unregister(
}
void ServiceWorkerJobCoordinator::Update(
- ServiceWorkerRegistration* registration) {
+ ServiceWorkerRegistration* registration,
+ bool force_bypass_cache) {
DCHECK(registration);
DCHECK(registration->GetNewestVersion());
job_queues_[registration->pattern()].Push(
make_scoped_ptr<ServiceWorkerRegisterJobBase>(
- new ServiceWorkerRegisterJob(context_, registration)));
+ new ServiceWorkerRegisterJob(context_, registration,
+ force_bypass_cache)));
}
void ServiceWorkerJobCoordinator::AbortAll() {
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 b85a84bc52c..af1a8d8cce6 100644
--- a/chromium/content/browser/service_worker/service_worker_job_coordinator.h
+++ b/chromium/content/browser/service_worker/service_worker_job_coordinator.h
@@ -36,7 +36,7 @@ class CONTENT_EXPORT ServiceWorkerJobCoordinator {
const GURL& pattern,
const ServiceWorkerUnregisterJob::UnregistrationCallback& callback);
- void Update(ServiceWorkerRegistration* registration);
+ void Update(ServiceWorkerRegistration* registration, bool force_bypass_cache);
// Calls ServiceWorkerRegisterJobBase::Abort() on all jobs and removes them.
void AbortAll();
@@ -51,12 +51,21 @@ class CONTENT_EXPORT ServiceWorkerJobCoordinator {
JobQueue();
~JobQueue();
- // Adds a job to the queue. If an identical job is already in the queue, no
- // new job is added. Returns the job in the queue, regardless of whether it
- // was newly added.
+ // Adds a job to the queue. If an identical job is already at the end of the
+ // queue, no new job is added. Returns the job in the queue, regardless of
+ // whether it was newly added.
ServiceWorkerRegisterJobBase* Push(
scoped_ptr<ServiceWorkerRegisterJobBase> job);
+ // Dooms the installing worker of the running register/update job if a
+ // register/update job is scheduled to run after it. This corresponds to
+ // the "Terminate installing worker" steps at the beginning of the spec's
+ // [[Update]] and [[Install]] algorithms.
+ void DoomInstallingWorkerIfNeeded();
+
+ // Starts the first job in the queue.
+ void StartOneJob();
+
// Removes a job from the queue.
void Pop(ServiceWorkerRegisterJobBase* job);
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 515e0f82fdc..18615ae4784 100644
--- a/chromium/content/browser/service_worker/service_worker_job_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_job_unittest.cc
@@ -14,6 +14,7 @@
#include "content/browser/service_worker/service_worker_registration.h"
#include "content/browser/service_worker/service_worker_registration_status.h"
#include "content/browser/service_worker/service_worker_test_utils.h"
+#include "content/common/service_worker/service_worker_messages.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "ipc/ipc_test_sink.h"
#include "net/base/io_buffer.h"
@@ -38,6 +39,7 @@ void SaveRegistrationCallback(
bool* called,
scoped_refptr<ServiceWorkerRegistration>* registration_out,
ServiceWorkerStatusCode status,
+ const std::string& status_message,
ServiceWorkerRegistration* registration) {
EXPECT_EQ(expected_status, status);
*called = true;
@@ -82,6 +84,7 @@ ServiceWorkerStorage::FindRegistrationCallback SaveFoundRegistration(
void SaveUnregistrationCallback(ServiceWorkerStatusCode expected_status,
bool* called,
+ int64 registration_id,
ServiceWorkerStatusCode status) {
EXPECT_EQ(expected_status, status);
*called = true;
@@ -103,7 +106,8 @@ class ServiceWorkerJobTest : public testing::Test {
render_process_id_(kMockRenderProcessId) {}
void SetUp() override {
- helper_.reset(new EmbeddedWorkerTestHelper(render_process_id_));
+ helper_.reset(
+ new EmbeddedWorkerTestHelper(base::FilePath(), render_process_id_));
}
void TearDown() override { helper_.reset(); }
@@ -116,23 +120,77 @@ class ServiceWorkerJobTest : public testing::Test {
ServiceWorkerStorage* storage() const { return context()->storage(); }
protected:
+ scoped_refptr<ServiceWorkerRegistration> RunRegisterJob(
+ const GURL& pattern,
+ const GURL& script_url,
+ ServiceWorkerStatusCode expected_status = SERVICE_WORKER_OK);
+ void RunUnregisterJob(
+ const GURL& pattern,
+ ServiceWorkerStatusCode expected_status = SERVICE_WORKER_OK);
+ scoped_refptr<ServiceWorkerRegistration> FindRegistrationForPattern(
+ const GURL& pattern,
+ ServiceWorkerStatusCode expected_status = SERVICE_WORKER_OK);
+ scoped_ptr<ServiceWorkerProviderHost> CreateControllee();
+
TestBrowserThreadBundle browser_thread_bundle_;
scoped_ptr<EmbeddedWorkerTestHelper> helper_;
int render_process_id_;
};
-TEST_F(ServiceWorkerJobTest, SameDocumentSameRegistration) {
- scoped_refptr<ServiceWorkerRegistration> original_registration;
+scoped_refptr<ServiceWorkerRegistration> ServiceWorkerJobTest::RunRegisterJob(
+ const GURL& pattern,
+ const GURL& script_url,
+ ServiceWorkerStatusCode expected_status) {
+ scoped_refptr<ServiceWorkerRegistration> registration;
bool called;
job_coordinator()->Register(
- GURL("http://www.example.com/"),
- GURL("http://www.example.com/service_worker.js"),
- NULL,
- SaveRegistration(SERVICE_WORKER_OK, &called, &original_registration));
+ pattern, script_url, NULL,
+ SaveRegistration(expected_status, &called, &registration));
EXPECT_FALSE(called);
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(called);
+ return registration;
+}
+void ServiceWorkerJobTest::RunUnregisterJob(
+ const GURL& pattern,
+ ServiceWorkerStatusCode expected_status) {
+ bool called;
+ job_coordinator()->Unregister(pattern,
+ SaveUnregistration(expected_status, &called));
+ EXPECT_FALSE(called);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(called);
+}
+
+scoped_refptr<ServiceWorkerRegistration>
+ServiceWorkerJobTest::FindRegistrationForPattern(
+ const GURL& pattern,
+ ServiceWorkerStatusCode expected_status) {
+ bool called;
+ scoped_refptr<ServiceWorkerRegistration> registration;
+ storage()->FindRegistrationForPattern(
+ pattern,
+ SaveFoundRegistration(expected_status, &called, &registration));
+
+ EXPECT_FALSE(called);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(called);
+ return registration;
+}
+
+scoped_ptr<ServiceWorkerProviderHost> ServiceWorkerJobTest::CreateControllee() {
+ return scoped_ptr<ServiceWorkerProviderHost>(new ServiceWorkerProviderHost(
+ 33 /* dummy render_process id */, MSG_ROUTING_NONE /* render_frame_id */,
+ 1 /* dummy provider_id */, SERVICE_WORKER_PROVIDER_FOR_WINDOW,
+ helper_->context()->AsWeakPtr(), NULL));
+}
+
+TEST_F(ServiceWorkerJobTest, SameDocumentSameRegistration) {
+ scoped_refptr<ServiceWorkerRegistration> original_registration =
+ RunRegisterJob(GURL("http://www.example.com/"),
+ GURL("http://www.example.com/service_worker.js"));
+ bool called;
scoped_refptr<ServiceWorkerRegistration> registration1;
storage()->FindRegistrationForDocument(
GURL("http://www.example.com/"),
@@ -150,15 +208,9 @@ TEST_F(ServiceWorkerJobTest, SameDocumentSameRegistration) {
TEST_F(ServiceWorkerJobTest, SameMatchSameRegistration) {
bool called;
- scoped_refptr<ServiceWorkerRegistration> original_registration;
- job_coordinator()->Register(
- GURL("http://www.example.com/"),
- GURL("http://www.example.com/service_worker.js"),
- NULL,
- SaveRegistration(SERVICE_WORKER_OK, &called, &original_registration));
- EXPECT_FALSE(called);
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(called);
+ scoped_refptr<ServiceWorkerRegistration> original_registration =
+ RunRegisterJob(GURL("http://www.example.com/"),
+ GURL("http://www.example.com/service_worker.js"));
ASSERT_NE(static_cast<ServiceWorkerRegistration*>(NULL),
original_registration.get());
@@ -219,17 +271,9 @@ TEST_F(ServiceWorkerJobTest, DifferentMatchDifferentRegistration) {
// Make sure basic registration is working.
TEST_F(ServiceWorkerJobTest, Register) {
- bool called = false;
- scoped_refptr<ServiceWorkerRegistration> registration;
- job_coordinator()->Register(
- GURL("http://www.example.com/"),
- GURL("http://www.example.com/service_worker.js"),
- NULL,
- SaveRegistration(SERVICE_WORKER_OK, &called, &registration));
-
- ASSERT_FALSE(called);
- base::RunLoop().RunUntilIdle();
- ASSERT_TRUE(called);
+ scoped_refptr<ServiceWorkerRegistration> registration =
+ RunRegisterJob(GURL("http://www.example.com/"),
+ GURL("http://www.example.com/service_worker.js"));
ASSERT_NE(scoped_refptr<ServiceWorkerRegistration>(NULL), registration);
}
@@ -238,35 +282,15 @@ TEST_F(ServiceWorkerJobTest, Register) {
TEST_F(ServiceWorkerJobTest, Unregister) {
GURL pattern("http://www.example.com/");
- bool called;
- scoped_refptr<ServiceWorkerRegistration> registration;
- job_coordinator()->Register(
- pattern,
- GURL("http://www.example.com/service_worker.js"),
- NULL,
- SaveRegistration(SERVICE_WORKER_OK, &called, &registration));
-
- ASSERT_FALSE(called);
- base::RunLoop().RunUntilIdle();
- ASSERT_TRUE(called);
-
- job_coordinator()->Unregister(pattern,
- SaveUnregistration(SERVICE_WORKER_OK, &called));
+ scoped_refptr<ServiceWorkerRegistration> registration =
+ RunRegisterJob(pattern, GURL("http://www.example.com/service_worker.js"));
- ASSERT_FALSE(called);
- base::RunLoop().RunUntilIdle();
- ASSERT_TRUE(called);
+ RunUnregisterJob(pattern);
ASSERT_TRUE(registration->HasOneRef());
- storage()->FindRegistrationForPattern(
- pattern,
- SaveFoundRegistration(SERVICE_WORKER_ERROR_NOT_FOUND,
- &called, &registration));
-
- ASSERT_FALSE(called);
- base::RunLoop().RunUntilIdle();
- ASSERT_TRUE(called);
+ registration = FindRegistrationForPattern(pattern,
+ SERVICE_WORKER_ERROR_NOT_FOUND);
ASSERT_EQ(scoped_refptr<ServiceWorkerRegistration>(NULL), registration);
}
@@ -274,14 +298,7 @@ TEST_F(ServiceWorkerJobTest, Unregister) {
TEST_F(ServiceWorkerJobTest, Unregister_NothingRegistered) {
GURL pattern("http://www.example.com/");
- bool called;
- job_coordinator()->Unregister(
- pattern,
- SaveUnregistration(SERVICE_WORKER_ERROR_NOT_FOUND, &called));
-
- ASSERT_FALSE(called);
- base::RunLoop().RunUntilIdle();
- ASSERT_TRUE(called);
+ RunUnregisterJob(pattern, SERVICE_WORKER_ERROR_NOT_FOUND);
}
// Make sure registering a new script creates a new version and shares an
@@ -289,55 +306,25 @@ TEST_F(ServiceWorkerJobTest, Unregister_NothingRegistered) {
TEST_F(ServiceWorkerJobTest, RegisterNewScript) {
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"),
- NULL,
- SaveRegistration(SERVICE_WORKER_OK, &called, &old_registration));
+ scoped_refptr<ServiceWorkerRegistration> old_registration =
+ RunRegisterJob(pattern, GURL("http://www.example.com/service_worker.js"));
- ASSERT_FALSE(called);
- base::RunLoop().RunUntilIdle();
- ASSERT_TRUE(called);
-
- scoped_refptr<ServiceWorkerRegistration> old_registration_by_pattern;
- storage()->FindRegistrationForPattern(
- pattern,
- SaveFoundRegistration(
- SERVICE_WORKER_OK, &called, &old_registration_by_pattern));
-
- ASSERT_FALSE(called);
- base::RunLoop().RunUntilIdle();
- ASSERT_TRUE(called);
+ scoped_refptr<ServiceWorkerRegistration> old_registration_by_pattern =
+ FindRegistrationForPattern(pattern);
ASSERT_EQ(old_registration, old_registration_by_pattern);
old_registration_by_pattern = NULL;
- scoped_refptr<ServiceWorkerRegistration> new_registration;
- job_coordinator()->Register(
- pattern,
- GURL("http://www.example.com/service_worker_new.js"),
- NULL,
- SaveRegistration(SERVICE_WORKER_OK, &called, &new_registration));
-
- ASSERT_FALSE(called);
- base::RunLoop().RunUntilIdle();
- ASSERT_TRUE(called);
+ scoped_refptr<ServiceWorkerRegistration> new_registration =
+ RunRegisterJob(pattern,
+ GURL("http://www.example.com/service_worker_new.js"));
ASSERT_EQ(old_registration, new_registration);
- scoped_refptr<ServiceWorkerRegistration> new_registration_by_pattern;
- storage()->FindRegistrationForPattern(
- pattern,
- SaveFoundRegistration(
- SERVICE_WORKER_OK, &called, &new_registration));
+ scoped_refptr<ServiceWorkerRegistration> new_registration_by_pattern =
+ FindRegistrationForPattern(pattern);
- ASSERT_FALSE(called);
- base::RunLoop().RunUntilIdle();
- ASSERT_TRUE(called);
-
- ASSERT_NE(new_registration_by_pattern, old_registration);
+ ASSERT_EQ(new_registration, new_registration_by_pattern);
}
// Make sure that when registering a duplicate pattern+script_url
@@ -346,53 +333,23 @@ TEST_F(ServiceWorkerJobTest, RegisterDuplicateScript) {
GURL pattern("http://www.example.com/");
GURL script_url("http://www.example.com/service_worker.js");
- bool called;
- scoped_refptr<ServiceWorkerRegistration> old_registration;
- job_coordinator()->Register(
- pattern,
- script_url,
- NULL,
- SaveRegistration(SERVICE_WORKER_OK, &called, &old_registration));
-
- ASSERT_FALSE(called);
- base::RunLoop().RunUntilIdle();
- ASSERT_TRUE(called);
+ scoped_refptr<ServiceWorkerRegistration> old_registration =
+ RunRegisterJob(pattern, script_url);
- scoped_refptr<ServiceWorkerRegistration> old_registration_by_pattern;
- storage()->FindRegistrationForPattern(
- pattern,
- SaveFoundRegistration(
- SERVICE_WORKER_OK, &called, &old_registration_by_pattern));
- ASSERT_FALSE(called);
- base::RunLoop().RunUntilIdle();
- ASSERT_TRUE(called);
+ scoped_refptr<ServiceWorkerRegistration> old_registration_by_pattern =
+ FindRegistrationForPattern(pattern);
ASSERT_TRUE(old_registration_by_pattern.get());
- scoped_refptr<ServiceWorkerRegistration> new_registration;
- job_coordinator()->Register(
- pattern,
- script_url,
- NULL,
- SaveRegistration(SERVICE_WORKER_OK, &called, &new_registration));
-
- ASSERT_FALSE(called);
- base::RunLoop().RunUntilIdle();
- ASSERT_TRUE(called);
+ scoped_refptr<ServiceWorkerRegistration> new_registration =
+ RunRegisterJob(pattern, script_url);
ASSERT_EQ(old_registration, new_registration);
ASSERT_FALSE(old_registration->HasOneRef());
- scoped_refptr<ServiceWorkerRegistration> new_registration_by_pattern;
- storage()->FindRegistrationForPattern(
- pattern,
- SaveFoundRegistration(
- SERVICE_WORKER_OK, &called, &new_registration_by_pattern));
-
- ASSERT_FALSE(called);
- base::RunLoop().RunUntilIdle();
- ASSERT_TRUE(called);
+ scoped_refptr<ServiceWorkerRegistration> new_registration_by_pattern =
+ FindRegistrationForPattern(pattern);
ASSERT_EQ(new_registration, old_registration);
}
@@ -400,7 +357,7 @@ TEST_F(ServiceWorkerJobTest, RegisterDuplicateScript) {
class FailToStartWorkerTestHelper : public EmbeddedWorkerTestHelper {
public:
explicit FailToStartWorkerTestHelper(int mock_render_process_id)
- : EmbeddedWorkerTestHelper(mock_render_process_id) {}
+ : EmbeddedWorkerTestHelper(base::FilePath(), mock_render_process_id) {}
void OnStartWorker(int embedded_worker_id,
int64 service_worker_version_id,
@@ -415,19 +372,11 @@ class FailToStartWorkerTestHelper : public EmbeddedWorkerTestHelper {
TEST_F(ServiceWorkerJobTest, Register_FailToStartWorker) {
helper_.reset(new FailToStartWorkerTestHelper(render_process_id_));
- bool called = false;
- scoped_refptr<ServiceWorkerRegistration> registration;
- job_coordinator()->Register(
- GURL("http://www.example.com/"),
- GURL("http://www.example.com/service_worker.js"),
- NULL,
- SaveRegistration(
- SERVICE_WORKER_ERROR_START_WORKER_FAILED, &called, &registration));
-
- ASSERT_FALSE(called);
- base::RunLoop().RunUntilIdle();
+ scoped_refptr<ServiceWorkerRegistration> registration =
+ RunRegisterJob(GURL("http://www.example.com/"),
+ GURL("http://www.example.com/service_worker.js"),
+ SERVICE_WORKER_ERROR_START_WORKER_FAILED);
- ASSERT_TRUE(called);
ASSERT_EQ(scoped_refptr<ServiceWorkerRegistration>(NULL), registration);
}
@@ -456,13 +405,8 @@ TEST_F(ServiceWorkerJobTest, ParallelRegUnreg) {
ASSERT_TRUE(registration_called);
ASSERT_TRUE(unregistration_called);
- bool find_called = false;
- storage()->FindRegistrationForPattern(
- pattern,
- SaveFoundRegistration(
- SERVICE_WORKER_ERROR_NOT_FOUND, &find_called, &registration));
-
- base::RunLoop().RunUntilIdle();
+ registration = FindRegistrationForPattern(pattern,
+ SERVICE_WORKER_ERROR_NOT_FOUND);
ASSERT_EQ(scoped_refptr<ServiceWorkerRegistration>(), registration);
}
@@ -499,14 +443,8 @@ TEST_F(ServiceWorkerJobTest, ParallelRegNewScript) {
ASSERT_TRUE(registration1_called);
ASSERT_TRUE(registration2_called);
- scoped_refptr<ServiceWorkerRegistration> registration;
- bool find_called = false;
- storage()->FindRegistrationForPattern(
- pattern,
- SaveFoundRegistration(
- SERVICE_WORKER_OK, &find_called, &registration));
-
- base::RunLoop().RunUntilIdle();
+ scoped_refptr<ServiceWorkerRegistration> registration =
+ FindRegistrationForPattern(pattern);
ASSERT_EQ(registration2, registration);
}
@@ -544,14 +482,9 @@ TEST_F(ServiceWorkerJobTest, ParallelRegSameScript) {
ASSERT_EQ(registration1, registration2);
- scoped_refptr<ServiceWorkerRegistration> registration;
- bool find_called = false;
- storage()->FindRegistrationForPattern(
- pattern,
- SaveFoundRegistration(
- SERVICE_WORKER_OK, &find_called, &registration));
+ scoped_refptr<ServiceWorkerRegistration> registration =
+ FindRegistrationForPattern(pattern);
- base::RunLoop().RunUntilIdle();
ASSERT_EQ(registration, registration1);
}
@@ -581,14 +514,9 @@ TEST_F(ServiceWorkerJobTest, ParallelUnreg) {
// There isn't really a way to test that they are being coalesced,
// but we can make sure they can exist simultaneously without
// crashing.
- scoped_refptr<ServiceWorkerRegistration> registration;
- bool find_called = false;
- storage()->FindRegistrationForPattern(
- pattern,
- SaveFoundRegistration(
- SERVICE_WORKER_ERROR_NOT_FOUND, &find_called, &registration));
+ scoped_refptr<ServiceWorkerRegistration> registration =
+ FindRegistrationForPattern(pattern, SERVICE_WORKER_ERROR_NOT_FOUND);
- base::RunLoop().RunUntilIdle();
ASSERT_EQ(scoped_refptr<ServiceWorkerRegistration>(), registration);
}
@@ -696,30 +624,18 @@ TEST_F(ServiceWorkerJobTest, AbortAll_RegUnreg) {
ASSERT_TRUE(registration_called);
ASSERT_TRUE(unregistration_called);
- bool find_called = false;
- storage()->FindRegistrationForPattern(
- pattern,
- SaveFoundRegistration(
- SERVICE_WORKER_ERROR_NOT_FOUND, &find_called, &registration));
+ registration = FindRegistrationForPattern(pattern,
+ SERVICE_WORKER_ERROR_NOT_FOUND);
- base::RunLoop().RunUntilIdle();
- ASSERT_TRUE(find_called);
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);
+ scoped_refptr<ServiceWorkerRegistration> registration =
+ RunRegisterJob(GURL("http://www.example.com/"), script_url);
ASSERT_TRUE(registration.get());
// Manually create the waiting worker since there is no way to become a
@@ -732,16 +648,12 @@ TEST_F(ServiceWorkerJobTest, UnregisterWaitingSetsRedundant) {
ASSERT_EQ(SERVICE_WORKER_OK, status);
version->SetStatus(ServiceWorkerVersion::INSTALLED);
- registration->SetWaitingVersion(version.get());
+ registration->SetWaitingVersion(version);
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);
+ RunUnregisterJob(GURL("http://www.example.com/"));
// The version should be stopped since there is no controllee after
// unregistration.
@@ -752,26 +664,16 @@ TEST_F(ServiceWorkerJobTest, UnregisterWaitingSetsRedundant) {
// 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);
+ scoped_refptr<ServiceWorkerRegistration> registration =
+ RunRegisterJob(GURL("http://www.example.com/"),
+ GURL("http://www.example.com/service_worker.js"));
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);
+ RunUnregisterJob(GURL("http://www.example.com/"));
// The version should be stopped since there is no controllee after
// unregistration.
@@ -783,33 +685,19 @@ TEST_F(ServiceWorkerJobTest, UnregisterActiveSetsRedundant) {
// 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);
+ scoped_refptr<ServiceWorkerRegistration> registration =
+ RunRegisterJob(GURL("http://www.example.com/"),
+ GURL("http://www.example.com/service_worker.js"));
ASSERT_TRUE(registration.get());
- scoped_ptr<ServiceWorkerProviderHost> host(
- new ServiceWorkerProviderHost(33 /* dummy render process id */,
- 1 /* dummy provider_id */,
- context()->AsWeakPtr(),
- NULL));
+ scoped_ptr<ServiceWorkerProviderHost> host = CreateControllee();
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);
+ RunUnregisterJob(GURL("http://www.example.com/"));
// The version should be running since there is still a controllee.
EXPECT_EQ(ServiceWorkerVersion::RUNNING, version->running_status());
@@ -893,7 +781,7 @@ class UpdateJobTestHelper
};
UpdateJobTestHelper(int mock_render_process_id)
- : EmbeddedWorkerTestHelper(mock_render_process_id),
+ : EmbeddedWorkerTestHelper(base::FilePath(), mock_render_process_id),
update_found_(false) {}
~UpdateJobTestHelper() override {
if (registration_.get())
@@ -942,7 +830,7 @@ class UpdateJobTestHelper
version->script_cache_map()->NotifyStartedCaching(script, resource_id);
WriteStringResponse(storage(), resource_id, kMockScriptBody);
version->script_cache_map()->NotifyFinishedCaching(
- script, kMockScriptSize, net::URLRequestStatus());
+ script, kMockScriptSize, net::URLRequestStatus(), std::string());
} else {
// Spoof caching the script for the new version.
int64 resource_id = storage()->NewResourceId();
@@ -952,7 +840,7 @@ class UpdateJobTestHelper
else
WriteStringResponse(storage(), resource_id, "mock_different_script");
version->script_cache_map()->NotifyFinishedCaching(
- script, kMockScriptSize, net::URLRequestStatus());
+ script, kMockScriptSize, net::URLRequestStatus(), std::string());
}
EmbeddedWorkerTestHelper::OnStartWorker(
embedded_worker_id, version_id, scope, script, pause_after_download);
@@ -974,11 +862,6 @@ class UpdateJobTestHelper
NOTREACHED();
}
- void OnRegistrationFinishedUninstalling(
- ServiceWorkerRegistration* registration) override {
- NOTREACHED();
- }
-
void OnUpdateFound(ServiceWorkerRegistration* registration) override {
ASSERT_FALSE(update_found_);
update_found_ = true;
@@ -999,6 +882,42 @@ class UpdateJobTestHelper
bool update_found_;
};
+// Helper class for update tests that evicts the active version when the update
+// worker is about to be started.
+class EvictIncumbentVersionHelper : public UpdateJobTestHelper {
+ public:
+ EvictIncumbentVersionHelper(int mock_render_process_id)
+ : UpdateJobTestHelper(mock_render_process_id) {}
+ ~EvictIncumbentVersionHelper() override {}
+
+ void OnStartWorker(int embedded_worker_id,
+ int64 version_id,
+ const GURL& scope,
+ const GURL& script,
+ bool pause_after_download) override {
+ if (pause_after_download) {
+ // Evict the incumbent worker.
+ ServiceWorkerVersion* version = context()->GetLiveVersion(version_id);
+ ASSERT_TRUE(version);
+ ServiceWorkerRegistration* registration =
+ context()->GetLiveRegistration(version->registration_id());
+ ASSERT_TRUE(registration);
+ ASSERT_TRUE(registration->active_version());
+ ASSERT_FALSE(registration->waiting_version());
+ registration->DeleteVersion(
+ make_scoped_refptr(registration->active_version()));
+ }
+ UpdateJobTestHelper::OnStartWorker(embedded_worker_id, version_id, scope,
+ script, pause_after_download);
+ }
+
+ void OnRegistrationFailed(ServiceWorkerRegistration* registration) override {
+ registration_failed_ = true;
+ }
+
+ bool registration_failed_ = false;
+};
+
} // namespace
TEST_F(ServiceWorkerJobTest, Update_NoChange) {
@@ -1132,21 +1051,14 @@ TEST_F(ServiceWorkerJobTest, Update_NewVersion) {
}
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));
+ scoped_refptr<ServiceWorkerRegistration> registration =
+ RunRegisterJob(GURL("http://www.example.com/one/"),
+ GURL("http://www.example.com/service_worker.js"));
- 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());
+ job_coordinator()->Update(registration.get(), false);
// Add a waiting version with new script.
scoped_refptr<ServiceWorkerVersion> version =
@@ -1154,7 +1066,7 @@ TEST_F(ServiceWorkerJobTest, Update_NewestVersionChanged) {
GURL("http://www.example.com/new_worker.js"),
2L /* dummy version id */,
helper_->context()->AsWeakPtr());
- registration->SetWaitingVersion(version.get());
+ registration->SetWaitingVersion(version);
base::RunLoop().RunUntilIdle();
@@ -1164,32 +1076,53 @@ TEST_F(ServiceWorkerJobTest, Update_NewestVersionChanged) {
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));
+// Test that update succeeds if the incumbent worker was evicted
+// during the update job (this can happen on disk cache failure).
+TEST_F(ServiceWorkerJobTest, Update_EvictedIncumbent) {
+ EvictIncumbentVersionHelper* update_helper =
+ new EvictIncumbentVersionHelper(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();
- EXPECT_FALSE(called);
+ // Run the update job.
+ registration->AddListener(update_helper);
+ scoped_refptr<ServiceWorkerVersion> first_version =
+ registration->active_version();
+ first_version->StartUpdate();
base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(called);
+
+ // 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());
+ EXPECT_EQ(ServiceWorkerVersion::REDUNDANT, first_version->status());
+ EXPECT_EQ(ServiceWorkerVersion::ACTIVATED,
+ registration->active_version()->status());
+ ASSERT_EQ(4u, update_helper->attribute_change_log_.size());
+ EXPECT_TRUE(update_helper->update_found_);
+ EXPECT_TRUE(update_helper->registration_failed_);
+ EXPECT_FALSE(registration->is_uninstalled());
+}
+
+TEST_F(ServiceWorkerJobTest, Update_UninstallingRegistration) {
+ bool called;
+ scoped_refptr<ServiceWorkerRegistration> registration =
+ RunRegisterJob(GURL("http://www.example.com/one/"),
+ GURL("http://www.example.com/service_worker.js"));
// 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));
+ scoped_ptr<ServiceWorkerProviderHost> host = CreateControllee();
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());
+ job_coordinator()->Update(registration.get(), false);
EXPECT_FALSE(called);
base::RunLoop().RunUntilIdle();
@@ -1202,4 +1135,337 @@ TEST_F(ServiceWorkerJobTest, Update_UninstallingRegistration) {
EXPECT_EQ(NULL, registration->installing_version());
}
+TEST_F(ServiceWorkerJobTest, RegisterWhileUninstalling) {
+ GURL pattern("http://www.example.com/one/");
+ GURL script1("http://www.example.com/service_worker.js");
+ GURL script2("http://www.example.com/service_worker.js?new");
+
+ scoped_refptr<ServiceWorkerRegistration> registration =
+ RunRegisterJob(pattern, script1);
+
+ // Add a controllee and queue an unregister to force the uninstalling state.
+ scoped_ptr<ServiceWorkerProviderHost> host = CreateControllee();
+ scoped_refptr<ServiceWorkerVersion> old_version =
+ registration->active_version();
+ old_version->AddControllee(host.get());
+ RunUnregisterJob(pattern);
+
+ // Register another script.
+ EXPECT_EQ(registration, RunRegisterJob(pattern, script2));
+
+ EXPECT_FALSE(registration->is_uninstalling());
+ EXPECT_EQ(old_version, registration->active_version());
+
+ scoped_refptr<ServiceWorkerVersion> new_version =
+ registration->waiting_version();
+
+ // Verify the new version is installed but not activated yet.
+ EXPECT_EQ(NULL, registration->installing_version());
+ EXPECT_TRUE(new_version);
+ EXPECT_EQ(ServiceWorkerVersion::RUNNING, new_version->running_status());
+ EXPECT_EQ(ServiceWorkerVersion::INSTALLED, new_version->status());
+
+ old_version->RemoveControllee(host.get());
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_FALSE(registration->is_uninstalling());
+ EXPECT_FALSE(registration->is_uninstalled());
+
+ // Verify the new version is activated.
+ EXPECT_EQ(NULL, registration->installing_version());
+ EXPECT_EQ(NULL, registration->waiting_version());
+ EXPECT_EQ(new_version, registration->active_version());
+ EXPECT_EQ(ServiceWorkerVersion::RUNNING, new_version->running_status());
+ EXPECT_EQ(ServiceWorkerVersion::ACTIVATED, new_version->status());
+}
+
+TEST_F(ServiceWorkerJobTest, RegisterAndUnregisterWhileUninstalling) {
+ GURL pattern("http://www.example.com/one/");
+ GURL script1("http://www.example.com/service_worker.js");
+ GURL script2("http://www.example.com/service_worker.js?new");
+
+ scoped_refptr<ServiceWorkerRegistration> registration =
+ RunRegisterJob(pattern, script1);
+
+ // Add a controllee and queue an unregister to force the uninstalling state.
+ scoped_ptr<ServiceWorkerProviderHost> host = CreateControllee();
+ scoped_refptr<ServiceWorkerVersion> old_version =
+ registration->active_version();
+ old_version->AddControllee(host.get());
+ RunUnregisterJob(pattern);
+
+ EXPECT_EQ(registration, RunRegisterJob(pattern, script2));
+
+ EXPECT_EQ(registration, FindRegistrationForPattern(pattern));
+ scoped_refptr<ServiceWorkerVersion> new_version =
+ registration->waiting_version();
+ ASSERT_TRUE(new_version);
+
+ // Unregister the registration (but it's still live).
+ RunUnregisterJob(pattern);
+ // Now it's not found in the storage.
+ RunUnregisterJob(pattern, SERVICE_WORKER_ERROR_NOT_FOUND);
+
+ FindRegistrationForPattern(pattern, SERVICE_WORKER_ERROR_NOT_FOUND);
+ EXPECT_TRUE(registration->is_uninstalling());
+ EXPECT_EQ(old_version, registration->active_version());
+
+ EXPECT_EQ(ServiceWorkerVersion::RUNNING, old_version->running_status());
+ EXPECT_EQ(ServiceWorkerVersion::ACTIVATED, old_version->status());
+ EXPECT_EQ(ServiceWorkerVersion::RUNNING, new_version->running_status());
+ EXPECT_EQ(ServiceWorkerVersion::INSTALLED, new_version->status());
+
+ old_version->RemoveControllee(host.get());
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_FALSE(registration->is_uninstalling());
+ EXPECT_TRUE(registration->is_uninstalled());
+
+ EXPECT_EQ(ServiceWorkerVersion::STOPPED, old_version->running_status());
+ EXPECT_EQ(ServiceWorkerVersion::REDUNDANT, old_version->status());
+ EXPECT_EQ(ServiceWorkerVersion::STOPPED, new_version->running_status());
+ EXPECT_EQ(ServiceWorkerVersion::REDUNDANT, new_version->status());
+}
+
+TEST_F(ServiceWorkerJobTest, RegisterSameScriptMultipleTimesWhileUninstalling) {
+ GURL pattern("http://www.example.com/one/");
+ GURL script1("http://www.example.com/service_worker.js");
+ GURL script2("http://www.example.com/service_worker.js?new");
+
+ scoped_refptr<ServiceWorkerRegistration> registration =
+ RunRegisterJob(pattern, script1);
+
+ // Add a controllee and queue an unregister to force the uninstalling state.
+ scoped_ptr<ServiceWorkerProviderHost> host = CreateControllee();
+ scoped_refptr<ServiceWorkerVersion> old_version =
+ registration->active_version();
+ old_version->AddControllee(host.get());
+ RunUnregisterJob(pattern);
+
+ EXPECT_EQ(registration, RunRegisterJob(pattern, script2));
+
+ scoped_refptr<ServiceWorkerVersion> new_version =
+ registration->waiting_version();
+ ASSERT_TRUE(new_version);
+
+ RunUnregisterJob(pattern);
+
+ EXPECT_TRUE(registration->is_uninstalling());
+
+ EXPECT_EQ(registration, RunRegisterJob(pattern, script2));
+
+ EXPECT_FALSE(registration->is_uninstalling());
+ EXPECT_EQ(new_version, registration->waiting_version());
+
+ old_version->RemoveControllee(host.get());
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_FALSE(registration->is_uninstalling());
+ EXPECT_FALSE(registration->is_uninstalled());
+
+ // Verify the new version is activated.
+ EXPECT_EQ(NULL, registration->installing_version());
+ EXPECT_EQ(NULL, registration->waiting_version());
+ EXPECT_EQ(new_version, registration->active_version());
+ EXPECT_EQ(ServiceWorkerVersion::RUNNING, new_version->running_status());
+ EXPECT_EQ(ServiceWorkerVersion::ACTIVATED, new_version->status());
+}
+
+TEST_F(ServiceWorkerJobTest, RegisterMultipleTimesWhileUninstalling) {
+ GURL pattern("http://www.example.com/one/");
+ GURL script1("http://www.example.com/service_worker.js?first");
+ GURL script2("http://www.example.com/service_worker.js?second");
+ GURL script3("http://www.example.com/service_worker.js?third");
+
+ scoped_refptr<ServiceWorkerRegistration> registration =
+ RunRegisterJob(pattern, script1);
+
+ // Add a controllee and queue an unregister to force the uninstalling state.
+ scoped_ptr<ServiceWorkerProviderHost> host = CreateControllee();
+ scoped_refptr<ServiceWorkerVersion> first_version =
+ registration->active_version();
+ first_version->AddControllee(host.get());
+ RunUnregisterJob(pattern);
+
+ EXPECT_EQ(registration, RunRegisterJob(pattern, script2));
+
+ scoped_refptr<ServiceWorkerVersion> second_version =
+ registration->waiting_version();
+ ASSERT_TRUE(second_version);
+
+ RunUnregisterJob(pattern);
+
+ EXPECT_TRUE(registration->is_uninstalling());
+
+ EXPECT_EQ(registration, RunRegisterJob(pattern, script3));
+
+ scoped_refptr<ServiceWorkerVersion> third_version =
+ registration->waiting_version();
+ ASSERT_TRUE(third_version);
+
+ EXPECT_FALSE(registration->is_uninstalling());
+ EXPECT_EQ(ServiceWorkerVersion::REDUNDANT, second_version->status());
+
+ first_version->RemoveControllee(host.get());
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_FALSE(registration->is_uninstalling());
+ EXPECT_FALSE(registration->is_uninstalled());
+
+ // Verify the new version is activated.
+ EXPECT_EQ(NULL, registration->installing_version());
+ EXPECT_EQ(NULL, registration->waiting_version());
+ EXPECT_EQ(third_version, registration->active_version());
+ EXPECT_EQ(ServiceWorkerVersion::RUNNING, third_version->running_status());
+ EXPECT_EQ(ServiceWorkerVersion::ACTIVATED, third_version->status());
+}
+
+class EventCallbackHelper : public EmbeddedWorkerTestHelper {
+ public:
+ explicit EventCallbackHelper(int mock_render_process_id)
+ : EmbeddedWorkerTestHelper(base::FilePath(), mock_render_process_id),
+ install_event_result_(blink::WebServiceWorkerEventResultCompleted),
+ activate_event_result_(blink::WebServiceWorkerEventResultCompleted) {}
+
+ void OnInstallEvent(int embedded_worker_id,
+ int request_id) override {
+ if (!install_callback_.is_null())
+ install_callback_.Run();
+ SimulateSend(
+ new ServiceWorkerHostMsg_InstallEventFinished(
+ embedded_worker_id, request_id, install_event_result_));
+ }
+ void OnActivateEvent(int embedded_worker_id, int request_id) override {
+ SimulateSend(
+ new ServiceWorkerHostMsg_ActivateEventFinished(
+ embedded_worker_id, request_id, activate_event_result_));
+ }
+
+ void set_install_callback(const base::Closure& callback) {
+ install_callback_ = callback;
+ }
+ void set_install_event_result(blink::WebServiceWorkerEventResult result) {
+ install_event_result_ = result;
+ }
+ void set_activate_event_result(blink::WebServiceWorkerEventResult result) {
+ activate_event_result_ = result;
+ }
+private:
+ base::Closure install_callback_;
+ blink::WebServiceWorkerEventResult install_event_result_;
+ blink::WebServiceWorkerEventResult activate_event_result_;
+};
+
+TEST_F(ServiceWorkerJobTest, RemoveControlleeDuringInstall) {
+ EventCallbackHelper* helper = new EventCallbackHelper(render_process_id_);
+ helper_.reset(helper);
+
+ GURL pattern("http://www.example.com/one/");
+ GURL script1("http://www.example.com/service_worker.js");
+ GURL script2("http://www.example.com/service_worker.js?new");
+
+ scoped_refptr<ServiceWorkerRegistration> registration =
+ RunRegisterJob(pattern, script1);
+
+ // Add a controllee and queue an unregister to force the uninstalling state.
+ scoped_ptr<ServiceWorkerProviderHost> host = CreateControllee();
+ scoped_refptr<ServiceWorkerVersion> old_version =
+ registration->active_version();
+ old_version->AddControllee(host.get());
+ RunUnregisterJob(pattern);
+
+ // Register another script. While installing, old_version loses controllee.
+ helper->set_install_callback(
+ base::Bind(&ServiceWorkerVersion::RemoveControllee,
+ old_version, host.get()));
+ EXPECT_EQ(registration, RunRegisterJob(pattern, script2));
+
+ EXPECT_FALSE(registration->is_uninstalling());
+ EXPECT_FALSE(registration->is_uninstalled());
+
+ // Verify the new version is activated.
+ scoped_refptr<ServiceWorkerVersion> new_version =
+ registration->active_version();
+ EXPECT_NE(old_version, new_version);
+ EXPECT_EQ(NULL, registration->installing_version());
+ EXPECT_EQ(NULL, registration->waiting_version());
+ EXPECT_EQ(new_version, registration->active_version());
+ EXPECT_EQ(ServiceWorkerVersion::RUNNING, new_version->running_status());
+ EXPECT_EQ(ServiceWorkerVersion::ACTIVATED, new_version->status());
+
+ EXPECT_EQ(registration, FindRegistrationForPattern(pattern));
+}
+
+TEST_F(ServiceWorkerJobTest, RemoveControlleeDuringRejectedInstall) {
+ EventCallbackHelper* helper = new EventCallbackHelper(render_process_id_);
+ helper_.reset(helper);
+
+ GURL pattern("http://www.example.com/one/");
+ GURL script1("http://www.example.com/service_worker.js");
+ GURL script2("http://www.example.com/service_worker.js?new");
+
+ scoped_refptr<ServiceWorkerRegistration> registration =
+ RunRegisterJob(pattern, script1);
+
+ // Add a controllee and queue an unregister to force the uninstalling state.
+ scoped_ptr<ServiceWorkerProviderHost> host = CreateControllee();
+ scoped_refptr<ServiceWorkerVersion> old_version =
+ registration->active_version();
+ old_version->AddControllee(host.get());
+ RunUnregisterJob(pattern);
+
+ // Register another script that fails to install. While installing,
+ // old_version loses controllee.
+ helper->set_install_callback(
+ base::Bind(&ServiceWorkerVersion::RemoveControllee,
+ old_version, host.get()));
+ helper->set_install_event_result(blink::WebServiceWorkerEventResultRejected);
+ EXPECT_EQ(registration, RunRegisterJob(pattern, script2));
+
+ // Verify the registration was uninstalled.
+ EXPECT_FALSE(registration->is_uninstalling());
+ EXPECT_TRUE(registration->is_uninstalled());
+
+ EXPECT_EQ(ServiceWorkerVersion::STOPPED, old_version->running_status());
+ EXPECT_EQ(ServiceWorkerVersion::REDUNDANT, old_version->status());
+
+ FindRegistrationForPattern(pattern, SERVICE_WORKER_ERROR_NOT_FOUND);
+}
+
+TEST_F(ServiceWorkerJobTest, RemoveControlleeDuringInstall_RejectActivate) {
+ EventCallbackHelper* helper = new EventCallbackHelper(render_process_id_);
+ helper_.reset(helper);
+
+ GURL pattern("http://www.example.com/one/");
+ GURL script1("http://www.example.com/service_worker.js");
+ GURL script2("http://www.example.com/service_worker.js?new");
+
+ scoped_refptr<ServiceWorkerRegistration> registration =
+ RunRegisterJob(pattern, script1);
+
+ // Add a controllee and queue an unregister to force the uninstalling state.
+ scoped_ptr<ServiceWorkerProviderHost> host = CreateControllee();
+ scoped_refptr<ServiceWorkerVersion> old_version =
+ registration->active_version();
+ old_version->AddControllee(host.get());
+ RunUnregisterJob(pattern);
+
+ // Register another script that fails to activate. While installing,
+ // old_version loses controllee.
+ helper->set_install_callback(
+ base::Bind(&ServiceWorkerVersion::RemoveControllee,
+ old_version, host.get()));
+ helper->set_activate_event_result(blink::WebServiceWorkerEventResultRejected);
+ EXPECT_EQ(registration, RunRegisterJob(pattern, script2));
+
+ // Verify the registration was uninstalled.
+ EXPECT_FALSE(registration->is_uninstalling());
+ EXPECT_TRUE(registration->is_uninstalled());
+
+ EXPECT_EQ(ServiceWorkerVersion::STOPPED, old_version->running_status());
+ EXPECT_EQ(ServiceWorkerVersion::REDUNDANT, old_version->status());
+
+ FindRegistrationForPattern(pattern, SERVICE_WORKER_ERROR_NOT_FOUND);
+}
+
} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_metrics.cc b/chromium/content/browser/service_worker/service_worker_metrics.cc
index 6e3ddf1d7aa..c0d882d3901 100644
--- a/chromium/content/browser/service_worker/service_worker_metrics.cc
+++ b/chromium/content/browser/service_worker/service_worker_metrics.cc
@@ -4,55 +4,116 @@
#include "content/browser/service_worker/service_worker_metrics.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
#include "base/metrics/user_metrics_action.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_client.h"
namespace content {
-// static
+namespace {
+
+void RecordURLMetricOnUI(const GURL& url) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ GetContentClient()->browser()->RecordURLMetric(
+ "ServiceWorker.ControlledPageUrl", url);
+}
+
+} // namespace
+
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() {
+void ServiceWorkerMetrics::RecordDestroyDatabaseResult(
+ ServiceWorkerDatabase::Status status) {
+ UMA_HISTOGRAM_ENUMERATION("ServiceWorker.Database.DestroyDatabaseResult",
+ status, ServiceWorkerDatabase::STATUS_ERROR_MAX);
+}
+
+void ServiceWorkerMetrics::RecordDeleteAndStartOverResult(
+ DeleteAndStartOverResult result) {
+ UMA_HISTOGRAM_ENUMERATION("ServiceWorker.Storage.DeleteAndStartOverResult",
+ result, NUM_DELETE_AND_START_OVER_RESULT_TYPES);
+}
+
+void ServiceWorkerMetrics::CountControlledPageLoad(const GURL& url) {
RecordAction(base::UserMetricsAction("ServiceWorker.ControlledPageLoad"));
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(&RecordURLMetricOnUI, url));
+}
+
+void ServiceWorkerMetrics::RecordStartWorkerStatus(
+ ServiceWorkerStatusCode status,
+ bool is_installed) {
+ if (is_installed) {
+ UMA_HISTOGRAM_ENUMERATION("ServiceWorker.StartWorker.Status", status,
+ SERVICE_WORKER_ERROR_MAX_VALUE);
+ } else {
+ UMA_HISTOGRAM_ENUMERATION("ServiceWorker.StartNewWorker.Status", status,
+ SERVICE_WORKER_ERROR_MAX_VALUE);
+ }
+}
+
+void ServiceWorkerMetrics::RecordStartWorkerTime(const base::TimeDelta& time,
+ bool is_installed) {
+ if (is_installed)
+ UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.StartWorker.Time", time);
+ else
+ UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.StartNewWorker.Time", time);
+}
+
+void ServiceWorkerMetrics::RecordActivateEventStatus(
+ ServiceWorkerStatusCode status) {
+ UMA_HISTOGRAM_ENUMERATION("ServiceWorker.ActivateEventStatus", status,
+ SERVICE_WORKER_ERROR_MAX_VALUE);
+}
+
+void ServiceWorkerMetrics::RecordInstallEventStatus(
+ ServiceWorkerStatusCode status) {
+ UMA_HISTOGRAM_ENUMERATION("ServiceWorker.InstallEventStatus", status,
+ SERVICE_WORKER_ERROR_MAX_VALUE);
+}
+
+void ServiceWorkerMetrics::RecordEventStatus(size_t fired_events,
+ size_t handled_events) {
+ if (!fired_events)
+ return;
+ int unhandled_ratio = (fired_events - handled_events) * 100 / fired_events;
+ UMA_HISTOGRAM_PERCENTAGE("ServiceWorker.UnhandledEventRatio",
+ unhandled_ratio);
}
} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_metrics.h b/chromium/content/browser/service_worker/service_worker_metrics.h
index deea3b3f1c4..400cd7eb7d4 100644
--- a/chromium/content/browser/service_worker/service_worker_metrics.h
+++ b/chromium/content/browser/service_worker/service_worker_metrics.h
@@ -8,6 +8,8 @@
#include "base/macros.h"
#include "content/browser/service_worker/service_worker_database.h"
+class GURL;
+
namespace content {
class ServiceWorkerMetrics {
@@ -26,6 +28,13 @@ class ServiceWorkerMetrics {
NUM_WRITE_RESPONSE_RESULT_TYPES,
};
+ enum DeleteAndStartOverResult {
+ DELETE_OK,
+ DELETE_DATABASE_ERROR,
+ DELETE_DISK_CACHE_ERROR,
+ NUM_DELETE_AND_START_OVER_RESULT_TYPES,
+ };
+
// Used for ServiceWorkerDiskCache.
static void CountInitDiskCacheResult(bool result);
static void CountReadResponseResult(ReadResponseResult result);
@@ -35,9 +44,30 @@ class ServiceWorkerMetrics {
static void CountOpenDatabaseResult(ServiceWorkerDatabase::Status status);
static void CountReadDatabaseResult(ServiceWorkerDatabase::Status status);
static void CountWriteDatabaseResult(ServiceWorkerDatabase::Status status);
+ static void RecordDestroyDatabaseResult(ServiceWorkerDatabase::Status status);
+
+ // Used for ServiceWorkerStorage.
+ static void RecordDeleteAndStartOverResult(DeleteAndStartOverResult result);
// Counts the number of page loads controlled by a Service Worker.
- static void CountControlledPageLoad();
+ static void CountControlledPageLoad(const GURL& url);
+
+ // Records the result of trying to start a worker. |is_installed| indicates
+ // whether the version has been installed.
+ static void RecordStartWorkerStatus(ServiceWorkerStatusCode status,
+ bool is_installed);
+
+ // Records the time taken to successfully start a worker. |is_installed|
+ // indicates whether the version has been installed.
+ static void RecordStartWorkerTime(const base::TimeDelta& time,
+ bool is_installed);
+
+ static void RecordActivateEventStatus(ServiceWorkerStatusCode status);
+ static void RecordInstallEventStatus(ServiceWorkerStatusCode status);
+
+ // Records the ratio of unhandled events to the all events fired during
+ // the lifetime of ServiceWorker.
+ static void RecordEventStatus(size_t fired_events, size_t handled_events);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(ServiceWorkerMetrics);
diff --git a/chromium/content/browser/service_worker/service_worker_process_manager.cc b/chromium/content/browser/service_worker/service_worker_process_manager.cc
index fe7e5e34f7d..c953129c8a4 100644
--- a/chromium/content/browser/service_worker/service_worker_process_manager.cc
+++ b/chromium/content/browser/service_worker/service_worker_process_manager.cc
@@ -50,8 +50,8 @@ ServiceWorkerProcessManager::ServiceWorkerProcessManager(
BrowserContext* browser_context)
: browser_context_(browser_context),
process_id_for_test_(-1),
- weak_this_factory_(this),
- weak_this_(weak_this_factory_.GetWeakPtr()) {
+ weak_this_factory_(this) {
+ weak_this_ = weak_this_factory_.GetWeakPtr();
}
ServiceWorkerProcessManager::~ServiceWorkerProcessManager() {
@@ -180,9 +180,8 @@ void ServiceWorkerProcessManager::AllocateWorkerProcess(
if (!browser_context_) {
// Shutdown has started.
BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED, -1));
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(callback, SERVICE_WORKER_ERROR_ABORT, -1));
return;
}
// No existing processes available; start a new one.
@@ -195,9 +194,8 @@ void ServiceWorkerProcessManager::AllocateWorkerProcess(
if (!rph->Init()) {
LOG(ERROR) << "Couldn't start a new process!";
BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED, -1));
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(callback, SERVICE_WORKER_ERROR_PROCESS_NOT_FOUND, -1));
return;
}
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 2a3bae1db3b..f1eda77c12a 100644
--- a/chromium/content/browser/service_worker/service_worker_process_manager.h
+++ b/chromium/content/browser/service_worker/service_worker_process_manager.h
@@ -42,7 +42,7 @@ class CONTENT_EXPORT ServiceWorkerProcessManager {
// 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
+ // Allocation can fail with SERVICE_WORKER_PROCESS_NOT_FOUND if
// RenderProcessHost::Init fails.
void AllocateWorkerProcess(
int embedded_worker_id,
@@ -123,8 +123,8 @@ class CONTENT_EXPORT ServiceWorkerProcessManager {
PatternProcessRefMap pattern_processes_;
// Used to double-check that we don't access *this after it's destroyed.
+ base::WeakPtr<ServiceWorkerProcessManager> weak_this_;
base::WeakPtrFactory<ServiceWorkerProcessManager> weak_this_factory_;
- const base::WeakPtr<ServiceWorkerProcessManager> weak_this_;
};
} // 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 aab5e63bb7f..aec787b4d72 100644
--- a/chromium/content/browser/service_worker/service_worker_proto.gyp
+++ b/chromium/content/browser/service_worker/service_worker_proto.gyp
@@ -1,11 +1,10 @@
{
'targets': [
{
- # GN version: //content/browser/service_worker:proto
- 'target_name': 'proto',
+ # GN version: //content/browser/service_worker:service_worker_proto
+ 'target_name': 'service_worker_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 e16454558e0..6a79c56d753 100644
--- a/chromium/content/browser/service_worker/service_worker_provider_host.cc
+++ b/chromium/content/browser/service_worker/service_worker_provider_host.cc
@@ -4,7 +4,11 @@
#include "content/browser/service_worker/service_worker_provider_host.h"
+#include "base/guid.h"
#include "base/stl_util.h"
+#include "content/browser/frame_host/frame_tree.h"
+#include "content/browser/frame_host/frame_tree_node.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/message_port_message_filter.h"
#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/browser/service_worker/service_worker_context_request_handler.h"
@@ -14,45 +18,140 @@
#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/browser/web_contents/web_contents_impl.h"
#include "content/common/resource_request_body.h"
#include "content/common/service_worker/service_worker_messages.h"
#include "content/common/service_worker/service_worker_types.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_widget_host_view.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/child_process_host.h"
namespace content {
-static const int kDocumentMainThreadId = 0;
+namespace {
+
+ServiceWorkerClientInfo FocusOnUIThread(
+ int render_process_id,
+ int render_frame_id) {
+ RenderFrameHostImpl* render_frame_host =
+ RenderFrameHostImpl::FromID(render_process_id, render_frame_id);
+ WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
+ WebContents::FromRenderFrameHost(render_frame_host));
+
+ if (!render_frame_host || !web_contents)
+ return ServiceWorkerClientInfo();
+
+ FrameTreeNode* frame_tree_node = render_frame_host->frame_tree_node();
+
+ // Focus the frame in the frame tree node, in case it has changed.
+ frame_tree_node->frame_tree()->SetFocusedFrame(frame_tree_node);
+
+ // Focus the frame's view to make sure the frame is now considered as focused.
+ render_frame_host->GetView()->Focus();
+
+ // Move the web contents to the foreground.
+ web_contents->Activate();
+
+ return ServiceWorkerProviderHost::GetWindowClientInfoOnUI(render_process_id,
+ render_frame_id);
+}
+
+} // anonymous namespace
+
+ServiceWorkerProviderHost::OneShotGetReadyCallback::OneShotGetReadyCallback(
+ const GetRegistrationForReadyCallback& callback)
+ : callback(callback),
+ called(false) {
+}
+
+ServiceWorkerProviderHost::OneShotGetReadyCallback::~OneShotGetReadyCallback() {
+}
ServiceWorkerProviderHost::ServiceWorkerProviderHost(
- int process_id, int provider_id,
+ int render_process_id,
+ int render_frame_id,
+ int provider_id,
+ ServiceWorkerProviderType provider_type,
base::WeakPtr<ServiceWorkerContextCore> context,
ServiceWorkerDispatcherHost* dispatcher_host)
- : process_id_(process_id),
+ : client_uuid_(base::GenerateGUID()),
+ render_process_id_(render_process_id),
+ render_frame_id_(render_frame_id),
+ render_thread_id_(kDocumentMainThreadId),
provider_id_(provider_id),
+ provider_type_(provider_type),
context_(context),
dispatcher_host_(dispatcher_host),
allow_association_(true) {
+ DCHECK_NE(ChildProcessHost::kInvalidUniqueID, render_process_id_);
+ DCHECK_NE(SERVICE_WORKER_PROVIDER_UNKNOWN, provider_type_);
+ if (provider_type_ == SERVICE_WORKER_PROVIDER_FOR_CONTROLLER) {
+ // Actual thread id is set when the service worker context gets started.
+ render_thread_id_ = kInvalidEmbeddedWorkerThreadId;
+ }
+ context_->RegisterProviderHostByClientID(client_uuid_, this);
}
ServiceWorkerProviderHost::~ServiceWorkerProviderHost() {
+ if (context_)
+ context_->UnregisterProviderHostByClientID(client_uuid_);
+
// 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 (auto& key_registration : matching_registrations_) {
+ DecreaseProcessReference(key_registration.second->pattern());
+ key_registration.second->RemoveListener(this);
}
- for (std::vector<GURL>::iterator it = associated_patterns_.begin();
- it != associated_patterns_.end(); ++it) {
- DecreaseProcessReference(*it);
+
+ for (const GURL& pattern : associated_patterns_)
+ DecreaseProcessReference(pattern);
+}
+
+void ServiceWorkerProviderHost::OnVersionAttributesChanged(
+ ServiceWorkerRegistration* registration,
+ ChangedVersionAttributesMask changed_mask,
+ const ServiceWorkerRegistrationInfo& info) {
+ if (!get_ready_callback_ || get_ready_callback_->called)
+ return;
+ if (changed_mask.active_changed() && registration->active_version()) {
+ // Wait until the state change so we don't send the get for ready
+ // registration complete message before set version attributes message.
+ registration->active_version()->RegisterStatusChangeCallback(base::Bind(
+ &ServiceWorkerProviderHost::ReturnRegistrationForReadyIfNeeded,
+ AsWeakPtr()));
}
}
void ServiceWorkerProviderHost::OnRegistrationFailed(
ServiceWorkerRegistration* registration) {
- DCHECK_EQ(associated_registration_.get(), registration);
- DisassociateRegistration();
+ if (associated_registration_ == registration)
+ DisassociateRegistration();
+ RemoveMatchingRegistration(registration);
+}
+
+void ServiceWorkerProviderHost::OnRegistrationFinishedUninstalling(
+ ServiceWorkerRegistration* registration) {
+ RemoveMatchingRegistration(registration);
+}
+
+void ServiceWorkerProviderHost::OnSkippedWaiting(
+ ServiceWorkerRegistration* registration) {
+ if (associated_registration_ != registration)
+ return;
+ // A client is "using" a registration if it is controlled by the active
+ // worker of the registration. skipWaiting doesn't cause a client to start
+ // using the registration.
+ if (!controlling_version_)
+ return;
+ ServiceWorkerVersion* active_version = registration->active_version();
+ DCHECK_EQ(active_version->status(), ServiceWorkerVersion::ACTIVATING);
+ SetControllerVersionAttribute(active_version,
+ true /* notify_controllerchange */);
}
void ServiceWorkerProviderHost::SetDocumentUrl(const GURL& url) {
@@ -65,7 +164,8 @@ void ServiceWorkerProviderHost::SetTopmostFrameUrl(const GURL& url) {
}
void ServiceWorkerProviderHost::SetControllerVersionAttribute(
- ServiceWorkerVersion* version) {
+ ServiceWorkerVersion* version,
+ bool notify_controllerchange) {
if (version == controlling_version_.get())
return;
@@ -79,8 +179,11 @@ void ServiceWorkerProviderHost::SetControllerVersionAttribute(
if (!dispatcher_host_)
return; // Could be NULL in some tests.
- dispatcher_host_->Send(new ServiceWorkerMsg_SetControllerServiceWorker(
- kDocumentMainThreadId, provider_id(), CreateHandleAndPass(version)));
+ // SetController message should be sent only for controllees.
+ DCHECK(IsProviderForClient());
+ Send(new ServiceWorkerMsg_SetControllerServiceWorker(
+ render_thread_id_, provider_id(), GetOrCreateServiceWorkerHandle(version),
+ notify_controllerchange));
}
bool ServiceWorkerProviderHost::SetHostedVersionId(int64 version_id) {
@@ -95,7 +198,7 @@ bool ServiceWorkerProviderHost::SetHostedVersionId(int64 version_id) {
ServiceWorkerVersionInfo info = live_version->GetInfo();
if (info.running_status != ServiceWorkerVersion::STARTING ||
- info.process_id != process_id_) {
+ info.process_id != render_process_id_) {
// If we aren't trying to start this version in our process
// something is amiss.
return false;
@@ -105,47 +208,102 @@ 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());
+bool ServiceWorkerProviderHost::IsProviderForClient() const {
+ switch (provider_type_) {
+ case SERVICE_WORKER_PROVIDER_FOR_WINDOW:
+ case SERVICE_WORKER_PROVIDER_FOR_WORKER:
+ case SERVICE_WORKER_PROVIDER_FOR_SHARED_WORKER:
+ return true;
+ case SERVICE_WORKER_PROVIDER_FOR_CONTROLLER:
+ case SERVICE_WORKER_PROVIDER_UNKNOWN:
+ return false;
+ }
+ NOTREACHED() << provider_type_;
+ return false;
+}
- dispatcher_host_->Send(new ServiceWorkerMsg_AssociateRegistration(
- kDocumentMainThreadId, provider_id(), handle->GetObjectInfo(), attrs));
+blink::WebServiceWorkerClientType ServiceWorkerProviderHost::client_type()
+ const {
+ switch (provider_type_) {
+ case SERVICE_WORKER_PROVIDER_FOR_WINDOW:
+ return blink::WebServiceWorkerClientTypeWindow;
+ case SERVICE_WORKER_PROVIDER_FOR_WORKER:
+ return blink::WebServiceWorkerClientTypeWorker;
+ case SERVICE_WORKER_PROVIDER_FOR_SHARED_WORKER:
+ return blink::WebServiceWorkerClientTypeSharedWorker;
+ case SERVICE_WORKER_PROVIDER_FOR_CONTROLLER:
+ case SERVICE_WORKER_PROVIDER_UNKNOWN:
+ NOTREACHED() << provider_type_;
}
+ NOTREACHED() << provider_type_;
+ return blink::WebServiceWorkerClientTypeWindow;
+}
+void ServiceWorkerProviderHost::AssociateRegistration(
+ ServiceWorkerRegistration* registration,
+ bool notify_controllerchange) {
+ DCHECK(CanAssociateRegistration(registration));
associated_registration_ = registration;
- associated_registration_->AddListener(this);
- SetControllerVersionAttribute(registration->active_version());
+ AddMatchingRegistration(registration);
+ SendAssociateRegistrationMessage();
+ SetControllerVersionAttribute(registration->active_version(),
+ notify_controllerchange);
}
void ServiceWorkerProviderHost::DisassociateRegistration() {
+ queued_events_.clear();
if (!associated_registration_.get())
return;
- DecreaseProcessReference(associated_registration_->pattern());
- associated_registration_->RemoveListener(this);
associated_registration_ = NULL;
- SetControllerVersionAttribute(NULL);
+ SetControllerVersionAttribute(NULL, false /* notify_controllerchange */);
+
+ if (!dispatcher_host_)
+ return;
+
+ // Disassociation message should be sent only for controllees.
+ DCHECK(IsProviderForClient());
+ Send(new ServiceWorkerMsg_DisassociateRegistration(
+ render_thread_id_, provider_id()));
+}
+
+void ServiceWorkerProviderHost::AddMatchingRegistration(
+ ServiceWorkerRegistration* registration) {
+ DCHECK(ServiceWorkerUtils::ScopeMatches(
+ registration->pattern(), document_url_));
+ size_t key = registration->pattern().spec().size();
+ if (ContainsKey(matching_registrations_, key))
+ return;
+ IncreaseProcessReference(registration->pattern());
+ registration->AddListener(this);
+ matching_registrations_[key] = registration;
+ ReturnRegistrationForReadyIfNeeded();
+}
+
+void ServiceWorkerProviderHost::RemoveMatchingRegistration(
+ ServiceWorkerRegistration* registration) {
+ size_t key = registration->pattern().spec().size();
+ DCHECK(ContainsKey(matching_registrations_, key));
+ DecreaseProcessReference(registration->pattern());
+ registration->RemoveListener(this);
+ matching_registrations_.erase(key);
+}
- if (dispatcher_host_) {
- dispatcher_host_->Send(new ServiceWorkerMsg_DisassociateRegistration(
- kDocumentMainThreadId, provider_id()));
+ServiceWorkerRegistration*
+ServiceWorkerProviderHost::MatchRegistration() const {
+ ServiceWorkerRegistrationMap::const_reverse_iterator it =
+ matching_registrations_.rbegin();
+ for (; it != matching_registrations_.rend(); ++it) {
+ if (it->second->is_uninstalled())
+ continue;
+ if (it->second->is_uninstalling())
+ return nullptr;
+ return it->second.get();
}
+ return nullptr;
+}
+
+void ServiceWorkerProviderHost::NotifyControllerActivationFailed() {
+ SetControllerVersionAttribute(nullptr, true /* notify_controllerchange */);
}
scoped_ptr<ServiceWorkerRequestHandler>
@@ -178,6 +336,26 @@ ServiceWorkerProviderHost::CreateRequestHandler(
return scoped_ptr<ServiceWorkerRequestHandler>();
}
+ServiceWorkerObjectInfo
+ServiceWorkerProviderHost::GetOrCreateServiceWorkerHandle(
+ ServiceWorkerVersion* version) {
+ DCHECK(dispatcher_host_);
+ if (!context_ || !version)
+ return ServiceWorkerObjectInfo();
+ ServiceWorkerHandle* handle = dispatcher_host_->FindServiceWorkerHandle(
+ provider_id(), version->version_id());
+ if (handle) {
+ handle->IncrementRefCount();
+ return handle->GetObjectInfo();
+ }
+
+ scoped_ptr<ServiceWorkerHandle> new_handle(
+ ServiceWorkerHandle::Create(context_, AsWeakPtr(), version));
+ handle = new_handle.get();
+ dispatcher_host_->RegisterServiceWorkerHandle(new_handle.Pass());
+ return handle->GetObjectInfo();
+}
+
bool ServiceWorkerProviderHost::CanAssociateRegistration(
ServiceWorkerRegistration* registration) {
if (!context_)
@@ -191,21 +369,59 @@ bool ServiceWorkerProviderHost::CanAssociateRegistration(
void ServiceWorkerProviderHost::PostMessage(
const base::string16& message,
- const std::vector<int>& sent_message_port_ids) {
+ const std::vector<TransferredMessagePort>& sent_message_ports) {
if (!dispatcher_host_)
return; // Could be NULL in some tests.
std::vector<int> new_routing_ids;
dispatcher_host_->message_port_message_filter()->
- UpdateMessagePortsWithNewRoutes(sent_message_port_ids,
+ UpdateMessagePortsWithNewRoutes(sent_message_ports,
&new_routing_ids);
- dispatcher_host_->Send(
- new ServiceWorkerMsg_MessageToDocument(
- kDocumentMainThreadId, provider_id(),
- message,
- sent_message_port_ids,
- new_routing_ids));
+ Send(new ServiceWorkerMsg_MessageToDocument(
+ kDocumentMainThreadId, provider_id(),
+ message,
+ sent_message_ports,
+ new_routing_ids));
+}
+
+void ServiceWorkerProviderHost::Focus(const GetClientInfoCallback& callback) {
+ BrowserThread::PostTaskAndReplyWithResult(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&FocusOnUIThread,
+ render_process_id_,
+ render_frame_id_),
+ callback);
+}
+
+void ServiceWorkerProviderHost::GetWindowClientInfo(
+ const GetClientInfoCallback& callback) const {
+ BrowserThread::PostTaskAndReplyWithResult(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&ServiceWorkerProviderHost::GetWindowClientInfoOnUI,
+ render_process_id_, render_frame_id_),
+ callback);
+}
+
+// static
+ServiceWorkerClientInfo ServiceWorkerProviderHost::GetWindowClientInfoOnUI(
+ int render_process_id,
+ int render_frame_id) {
+ RenderFrameHostImpl* render_frame_host =
+ RenderFrameHostImpl::FromID(render_process_id, render_frame_id);
+ if (!render_frame_host)
+ return ServiceWorkerClientInfo();
+
+ // TODO(mlamouri,michaeln): it is possible to end up collecting information
+ // for a frame that is actually being navigated and isn't exactly what we are
+ // expecting.
+ return ServiceWorkerClientInfo(
+ render_frame_host->GetVisibilityState(),
+ render_frame_host->IsFocused(),
+ render_frame_host->GetLastCommittedURL(),
+ render_frame_host->GetParent() ? REQUEST_CONTEXT_FRAME_TYPE_NESTED
+ : REQUEST_CONTEXT_FRAME_TYPE_TOP_LEVEL,
+ blink::WebServiceWorkerClientTypeWindow);
}
void ServiceWorkerProviderHost::AddScopedProcessReferenceToPattern(
@@ -214,27 +430,193 @@ void ServiceWorkerProviderHost::AddScopedProcessReferenceToPattern(
IncreaseProcessReference(pattern);
}
-ServiceWorkerObjectInfo ServiceWorkerProviderHost::CreateHandleAndPass(
- 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());
+void ServiceWorkerProviderHost::ClaimedByRegistration(
+ ServiceWorkerRegistration* registration) {
+ DCHECK(registration->active_version());
+ if (registration == associated_registration_) {
+ SetControllerVersionAttribute(registration->active_version(),
+ true /* notify_controllerchange */);
+ } else if (allow_association_) {
+ DisassociateRegistration();
+ AssociateRegistration(registration, true /* notify_controllerchange */);
+ }
+}
+
+bool ServiceWorkerProviderHost::GetRegistrationForReady(
+ const GetRegistrationForReadyCallback& callback) {
+ if (get_ready_callback_)
+ return false;
+ get_ready_callback_.reset(new OneShotGetReadyCallback(callback));
+ ReturnRegistrationForReadyIfNeeded();
+ return true;
+}
+
+void ServiceWorkerProviderHost::PrepareForCrossSiteTransfer() {
+ DCHECK_NE(ChildProcessHost::kInvalidUniqueID, render_process_id_);
+ DCHECK_NE(MSG_ROUTING_NONE, render_frame_id_);
+ DCHECK_EQ(kDocumentMainThreadId, render_thread_id_);
+ DCHECK_NE(SERVICE_WORKER_PROVIDER_UNKNOWN, provider_type_);
+
+ for (const GURL& pattern : associated_patterns_)
+ DecreaseProcessReference(pattern);
+
+ for (auto& key_registration : matching_registrations_)
+ DecreaseProcessReference(key_registration.second->pattern());
+
+ if (associated_registration_.get()) {
+ if (dispatcher_host_) {
+ Send(new ServiceWorkerMsg_DisassociateRegistration(
+ render_thread_id_, provider_id()));
+ }
}
- return info;
+
+ render_process_id_ = ChildProcessHost::kInvalidUniqueID;
+ render_frame_id_ = MSG_ROUTING_NONE;
+ render_thread_id_ = kInvalidEmbeddedWorkerThreadId;
+ provider_id_ = kInvalidServiceWorkerProviderId;
+ provider_type_ = SERVICE_WORKER_PROVIDER_UNKNOWN;
+ dispatcher_host_ = nullptr;
+}
+
+void ServiceWorkerProviderHost::CompleteCrossSiteTransfer(
+ int new_process_id,
+ int new_frame_id,
+ int new_provider_id,
+ ServiceWorkerProviderType new_provider_type,
+ ServiceWorkerDispatcherHost* new_dispatcher_host) {
+ DCHECK_EQ(ChildProcessHost::kInvalidUniqueID, render_process_id_);
+ DCHECK_NE(ChildProcessHost::kInvalidUniqueID, new_process_id);
+ DCHECK_NE(MSG_ROUTING_NONE, new_frame_id);
+
+ render_process_id_ = new_process_id;
+ render_frame_id_ = new_frame_id;
+ render_thread_id_ = kDocumentMainThreadId;
+ provider_id_ = new_provider_id;
+ provider_type_ = new_provider_type;
+ dispatcher_host_ = new_dispatcher_host;
+
+ for (const GURL& pattern : associated_patterns_)
+ IncreaseProcessReference(pattern);
+
+ for (auto& key_registration : matching_registrations_)
+ IncreaseProcessReference(key_registration.second->pattern());
+
+ if (associated_registration_.get()) {
+ SendAssociateRegistrationMessage();
+ if (dispatcher_host_ && associated_registration_->active_version()) {
+ Send(new ServiceWorkerMsg_SetControllerServiceWorker(
+ render_thread_id_, provider_id(),
+ GetOrCreateServiceWorkerHandle(
+ associated_registration_->active_version()),
+ false /* shouldNotifyControllerChange */));
+ }
+ }
+}
+
+void ServiceWorkerProviderHost::SendUpdateFoundMessage(
+ int registration_handle_id) {
+ if (!dispatcher_host_)
+ return; // Could be nullptr in some tests.
+
+ if (!IsReadyToSendMessages()) {
+ queued_events_.push_back(
+ base::Bind(&ServiceWorkerProviderHost::SendUpdateFoundMessage,
+ AsWeakPtr(), registration_handle_id));
+ return;
+ }
+
+ Send(new ServiceWorkerMsg_UpdateFound(
+ render_thread_id_, registration_handle_id));
+}
+
+void ServiceWorkerProviderHost::SendSetVersionAttributesMessage(
+ int registration_handle_id,
+ ChangedVersionAttributesMask changed_mask,
+ ServiceWorkerVersion* installing_version,
+ ServiceWorkerVersion* waiting_version,
+ ServiceWorkerVersion* active_version) {
+ if (!dispatcher_host_)
+ return; // Could be nullptr in some tests.
+ if (!changed_mask.changed())
+ return;
+
+ if (!IsReadyToSendMessages()) {
+ queued_events_.push_back(
+ base::Bind(&ServiceWorkerProviderHost::SendSetVersionAttributesMessage,
+ AsWeakPtr(), registration_handle_id, changed_mask,
+ make_scoped_refptr(installing_version),
+ make_scoped_refptr(waiting_version),
+ make_scoped_refptr(active_version)));
+ return;
+ }
+
+ ServiceWorkerVersionAttributes attrs;
+ if (changed_mask.installing_changed())
+ attrs.installing = GetOrCreateServiceWorkerHandle(installing_version);
+ if (changed_mask.waiting_changed())
+ attrs.waiting = GetOrCreateServiceWorkerHandle(waiting_version);
+ if (changed_mask.active_changed())
+ attrs.active = GetOrCreateServiceWorkerHandle(active_version);
+
+ Send(new ServiceWorkerMsg_SetVersionAttributes(
+ render_thread_id_, provider_id_, registration_handle_id,
+ changed_mask.changed(), attrs));
+}
+
+void ServiceWorkerProviderHost::SendServiceWorkerStateChangedMessage(
+ int worker_handle_id,
+ blink::WebServiceWorkerState state) {
+ if (!dispatcher_host_)
+ return;
+
+ if (!IsReadyToSendMessages()) {
+ queued_events_.push_back(base::Bind(
+ &ServiceWorkerProviderHost::SendServiceWorkerStateChangedMessage,
+ AsWeakPtr(), worker_handle_id, state));
+ return;
+ }
+
+ Send(new ServiceWorkerMsg_ServiceWorkerStateChanged(
+ render_thread_id_, worker_handle_id, state));
+}
+
+void ServiceWorkerProviderHost::SetReadyToSendMessagesToWorker(
+ int render_thread_id) {
+ DCHECK(!IsReadyToSendMessages());
+ render_thread_id_ = render_thread_id;
+
+ for (const auto& event : queued_events_)
+ event.Run();
+ queued_events_.clear();
+}
+
+void ServiceWorkerProviderHost::SendAssociateRegistrationMessage() {
+ if (!dispatcher_host_)
+ return;
+
+ ServiceWorkerRegistrationHandle* handle =
+ dispatcher_host_->GetOrCreateRegistrationHandle(
+ AsWeakPtr(), associated_registration_.get());
+
+ ServiceWorkerVersionAttributes attrs;
+ attrs.installing = GetOrCreateServiceWorkerHandle(
+ associated_registration_->installing_version());
+ attrs.waiting = GetOrCreateServiceWorkerHandle(
+ associated_registration_->waiting_version());
+ attrs.active = GetOrCreateServiceWorkerHandle(
+ associated_registration_->active_version());
+
+ // Association message should be sent only for controllees.
+ DCHECK(IsProviderForClient());
+ dispatcher_host_->Send(new ServiceWorkerMsg_AssociateRegistration(
+ render_thread_id_, provider_id(), handle->GetObjectInfo(), attrs));
}
void ServiceWorkerProviderHost::IncreaseProcessReference(
const GURL& pattern) {
if (context_ && context_->process_manager()) {
context_->process_manager()->AddProcessReferenceToPattern(
- pattern, process_id_);
+ pattern, render_process_id_);
}
}
@@ -242,12 +624,36 @@ void ServiceWorkerProviderHost::DecreaseProcessReference(
const GURL& pattern) {
if (context_ && context_->process_manager()) {
context_->process_manager()->RemoveProcessReferenceFromPattern(
- pattern, process_id_);
+ pattern, render_process_id_);
}
}
+void ServiceWorkerProviderHost::ReturnRegistrationForReadyIfNeeded() {
+ if (!get_ready_callback_ || get_ready_callback_->called)
+ return;
+ ServiceWorkerRegistration* registration = MatchRegistration();
+ if (!registration)
+ return;
+ if (registration->active_version()) {
+ get_ready_callback_->callback.Run(registration);
+ get_ready_callback_->callback.Reset();
+ get_ready_callback_->called = true;
+ return;
+ }
+}
+
+bool ServiceWorkerProviderHost::IsReadyToSendMessages() const {
+ return render_thread_id_ != kInvalidEmbeddedWorkerThreadId;
+}
+
bool ServiceWorkerProviderHost::IsContextAlive() {
return context_ != NULL;
}
+void ServiceWorkerProviderHost::Send(IPC::Message* message) const {
+ DCHECK(dispatcher_host_);
+ DCHECK(IsReadyToSendMessages());
+ dispatcher_host_->Send(message);
+}
+
} // namespace content
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 04fb21d0a2b..4aafd27ffd8 100644
--- a/chromium/content/browser/service_worker/service_worker_provider_host.h
+++ b/chromium/content/browser/service_worker/service_worker_provider_host.h
@@ -34,10 +34,11 @@ class ServiceWorkerRequestHandler;
class ServiceWorkerVersion;
// This class is the browser-process representation of a service worker
-// provider. There is a provider per document and the lifetime of this
-// object is tied to the lifetime of its document in the renderer process.
+// provider. There is a provider per document or a worker and the lifetime
+// of this object is tied to the lifetime of its document or the worker
+// in the renderer process.
// This class holds service worker state that is scoped to an individual
-// document.
+// document or a worker.
//
// Note this class can also host a running service worker, in which
// case it will observe resource loads made directly by the service worker.
@@ -45,14 +46,28 @@ class CONTENT_EXPORT ServiceWorkerProviderHost
: public NON_EXPORTED_BASE(ServiceWorkerRegistration::Listener),
public base::SupportsWeakPtr<ServiceWorkerProviderHost> {
public:
- ServiceWorkerProviderHost(int process_id,
+ using GetClientInfoCallback =
+ base::Callback<void(const ServiceWorkerClientInfo&)>;
+ using GetRegistrationForReadyCallback =
+ base::Callback<void(ServiceWorkerRegistration* reigstration)>;
+
+ // If |render_frame_id| is MSG_ROUTING_NONE, this provider host works for the
+ // worker context, i.e. ServiceWorker or SharedWorker.
+ // |provider_type| gives additional information whether the provider is
+ // created for controller (ServiceWorker) or controllee (Document or
+ // SharedWorker).
+ ServiceWorkerProviderHost(int render_process_id,
+ int render_frame_id,
int provider_id,
+ ServiceWorkerProviderType provider_type,
base::WeakPtr<ServiceWorkerContextCore> context,
ServiceWorkerDispatcherHost* dispatcher_host);
virtual ~ServiceWorkerProviderHost();
- int process_id() const { return process_id_; }
+ const std::string& client_uuid() const { return client_uuid_; }
+ int process_id() const { return render_process_id_; }
int provider_id() const { return provider_id_; }
+ int frame_id() const { return render_frame_id_; }
bool IsHostToRunningServiceWorker() {
return running_hosted_version_.get() != NULL;
@@ -90,8 +105,15 @@ class CONTENT_EXPORT ServiceWorkerProviderHost
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);
+ ServiceWorkerProviderType provider_type() const { return provider_type_; }
+ bool IsProviderForClient() const;
+ blink::WebServiceWorkerClientType client_type() const;
+
+ // Associates to |registration| to listen for its version change events and
+ // sets the controller. If |notify_controllerchange| is true, instructs the
+ // renderer to dispatch a 'controllerchange' event.
+ void AssociateRegistration(ServiceWorkerRegistration* registration,
+ bool notify_controllerchange);
// Clears the associated registration and stop listening to it.
void DisassociateRegistration();
@@ -111,6 +133,14 @@ class CONTENT_EXPORT ServiceWorkerProviderHost
base::WeakPtr<storage::BlobStorageContext> blob_storage_context,
scoped_refptr<ResourceRequestBody> body);
+ // Used to get a ServiceWorkerObjectInfo to send to the renderer. Finds an
+ // existing ServiceWorkerHandle, and increments its reference count, or else
+ // creates a new one (initialized to ref count 1). Returns the
+ // ServiceWorkerInfo from the handle. The renderer is expected to use
+ // ServiceWorkerHandleReference::Adopt to balance out the ref count.
+ ServiceWorkerObjectInfo GetOrCreateServiceWorkerHandle(
+ ServiceWorkerVersion* version);
+
// Returns true if |registration| can be associated with this provider.
bool CanAssociateRegistration(ServiceWorkerRegistration* registration);
@@ -124,13 +154,74 @@ class CONTENT_EXPORT ServiceWorkerProviderHost
bool IsContextAlive();
// Dispatches message event to the document.
- void PostMessage(const base::string16& message,
- const std::vector<int>& sent_message_port_ids);
+ void PostMessage(
+ const base::string16& message,
+ const std::vector<TransferredMessagePort>& sent_message_ports);
+
+ // Activates the WebContents associated with
+ // { render_process_id_, render_frame_id_ }.
+ // Runs the |callback| with the updated ServiceWorkerClientInfo in parameter.
+ void Focus(const GetClientInfoCallback& callback);
+
+ // Asks the renderer to send back the document information.
+ void GetWindowClientInfo(const GetClientInfoCallback& callback) const;
+
+ // Same as above but has to be called from the UI thread.
+ // It is taking the process and frame ids in parameter because |this| is meant
+ // to live on the IO thread.
+ static ServiceWorkerClientInfo GetWindowClientInfoOnUI(int render_process_id,
+ int render_frame_id);
// Adds reference of this host's process to the |pattern|, the reference will
// be removed in destructor.
void AddScopedProcessReferenceToPattern(const GURL& pattern);
+ // |registration| claims the document to be controlled.
+ void ClaimedByRegistration(ServiceWorkerRegistration* registration);
+
+ // Called by dispatcher host to get the registration for the "ready" property.
+ // Returns false if there's a completed or ongoing request for the document.
+ // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/#navigator-service-worker-ready
+ bool GetRegistrationForReady(const GetRegistrationForReadyCallback& callback);
+
+ // Methods to support cross site navigations.
+ void PrepareForCrossSiteTransfer();
+ void CompleteCrossSiteTransfer(
+ int new_process_id,
+ int new_frame_id,
+ int new_provider_id,
+ ServiceWorkerProviderType new_provider_type,
+ ServiceWorkerDispatcherHost* dispatcher_host);
+ ServiceWorkerDispatcherHost* dispatcher_host() const {
+ return dispatcher_host_;
+ }
+
+ // Sends event messages to the renderer. Events for the worker are queued up
+ // until the worker thread id is known via SetReadyToSendMessagesToWorker().
+ void SendUpdateFoundMessage(
+ int registration_handle_id);
+ void SendSetVersionAttributesMessage(
+ int registration_handle_id,
+ ChangedVersionAttributesMask changed_mask,
+ ServiceWorkerVersion* installing_version,
+ ServiceWorkerVersion* waiting_version,
+ ServiceWorkerVersion* active_version);
+ void SendServiceWorkerStateChangedMessage(
+ int worker_handle_id,
+ blink::WebServiceWorkerState state);
+
+ // Sets the worker thread id and flushes queued events.
+ void SetReadyToSendMessagesToWorker(int render_thread_id);
+
+ void AddMatchingRegistration(ServiceWorkerRegistration* registration);
+ void RemoveMatchingRegistration(ServiceWorkerRegistration* registration);
+
+ // An optimized implementation of [[Match Service Worker Registration]]
+ // for current document.
+ ServiceWorkerRegistration* MatchRegistration() const;
+
+ void NotifyControllerActivationFailed();
+
private:
friend class ServiceWorkerProviderHostTest;
friend class ServiceWorkerWriteToCacheJobTest;
@@ -138,37 +229,73 @@ class CONTENT_EXPORT ServiceWorkerProviderHost
UpdateBefore24Hours);
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerContextRequestHandlerTest,
UpdateAfter24Hours);
+ FRIEND_TEST_ALL_PREFIXES(ServiceWorkerContextRequestHandlerTest,
+ UpdateForceBypassCache);
+
+ struct OneShotGetReadyCallback {
+ GetRegistrationForReadyCallback callback;
+ bool called;
+
+ explicit OneShotGetReadyCallback(
+ const GetRegistrationForReadyCallback& callback);
+ ~OneShotGetReadyCallback();
+ };
// ServiceWorkerRegistration::Listener overrides.
+ void OnVersionAttributesChanged(
+ ServiceWorkerRegistration* registration,
+ ChangedVersionAttributesMask changed_mask,
+ const ServiceWorkerRegistrationInfo& info) override;
void OnRegistrationFailed(ServiceWorkerRegistration* registration) override;
+ void OnRegistrationFinishedUninstalling(
+ ServiceWorkerRegistration* registration) override;
+ void OnSkippedWaiting(ServiceWorkerRegistration* registration) override;
// Sets the controller version field to |version| or if |version| is NULL,
- // clears the field.
- void SetControllerVersionAttribute(ServiceWorkerVersion* version);
+ // clears the field. If |notify_controllerchange| is true, instructs the
+ // renderer to dispatch a 'controller' change event.
+ void SetControllerVersionAttribute(ServiceWorkerVersion* version,
+ bool notify_controllerchange);
- // 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);
+ void SendAssociateRegistrationMessage();
// 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_;
+ void ReturnRegistrationForReadyIfNeeded();
+
+ bool IsReadyToSendMessages() const;
+ void Send(IPC::Message* message) const;
+
+ std::string client_uuid_;
+ int render_process_id_;
+ int render_frame_id_;
+ int render_thread_id_;
+ int provider_id_;
+ ServiceWorkerProviderType provider_type_;
GURL document_url_;
GURL topmost_frame_url_;
std::vector<GURL> associated_patterns_;
scoped_refptr<ServiceWorkerRegistration> associated_registration_;
+ // Keyed by registration scope URL length.
+ typedef std::map<size_t, scoped_refptr<ServiceWorkerRegistration>>
+ ServiceWorkerRegistrationMap;
+ // Contains all living registrations which has pattern this document's
+ // URL starts with.
+ ServiceWorkerRegistrationMap matching_registrations_;
+
+ scoped_ptr<OneShotGetReadyCallback> get_ready_callback_;
scoped_refptr<ServiceWorkerVersion> controlling_version_;
scoped_refptr<ServiceWorkerVersion> running_hosted_version_;
base::WeakPtr<ServiceWorkerContextCore> context_;
ServiceWorkerDispatcherHost* dispatcher_host_;
bool allow_association_;
+ std::vector<base::Closure> queued_events_;
+
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 fac7cb734ab..79a8ac164eb 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
@@ -25,22 +25,24 @@ class ServiceWorkerProviderHostTest : public testing::Test {
~ServiceWorkerProviderHostTest() override {}
void SetUp() override {
- helper_.reset(new EmbeddedWorkerTestHelper(kRenderProcessId));
+ helper_.reset(
+ new EmbeddedWorkerTestHelper(base::FilePath(), kRenderProcessId));
context_ = helper_->context();
- pattern_ = GURL("http://www.example.com/");
script_url_ = GURL("http://www.example.com/service_worker.js");
- registration_ = new ServiceWorkerRegistration(
- pattern_, 1L, context_->AsWeakPtr());
- version_ = new ServiceWorkerVersion(
- registration_.get(), script_url_, 1L, context_->AsWeakPtr());
+ registration1_ = new ServiceWorkerRegistration(
+ GURL("http://www.example.com/"), 1L, context_->AsWeakPtr());
+ registration2_ = new ServiceWorkerRegistration(
+ GURL("http://www.example.com/example"), 2L, context_->AsWeakPtr());
// Prepare provider hosts (for the same process).
scoped_ptr<ServiceWorkerProviderHost> host1(new ServiceWorkerProviderHost(
- kRenderProcessId, 1 /* provider_id */,
- context_->AsWeakPtr(), NULL));
+ kRenderProcessId, MSG_ROUTING_NONE, 1 /* provider_id */,
+ SERVICE_WORKER_PROVIDER_FOR_WINDOW, context_->AsWeakPtr(), NULL));
+ host1->SetDocumentUrl(GURL("http://www.example.com/example1.html"));
scoped_ptr<ServiceWorkerProviderHost> host2(new ServiceWorkerProviderHost(
- kRenderProcessId, 2 /* provider_id */,
- context_->AsWeakPtr(), NULL));
+ kRenderProcessId, MSG_ROUTING_NONE, 2 /* provider_id */,
+ SERVICE_WORKER_PROVIDER_FOR_WINDOW, context_->AsWeakPtr(), NULL));
+ host2->SetDocumentUrl(GURL("http://www.example.com/example2.html"));
provider_host1_ = host1->AsWeakPtr();
provider_host2_ = host2->AsWeakPtr();
context_->AddProviderHost(make_scoped_ptr(host1.release()));
@@ -48,105 +50,79 @@ class ServiceWorkerProviderHostTest : public testing::Test {
}
void TearDown() override {
- version_ = 0;
- registration_ = 0;
+ registration1_ = 0;
+ registration2_ = 0;
helper_.reset();
}
- bool HasProcessToRun() const {
- return context_->process_manager()->PatternHasProcessToRun(pattern_);
+ bool PatternHasProcessToRun(const GURL& pattern) const {
+ return context_->process_manager()->PatternHasProcessToRun(pattern);
}
content::TestBrowserThreadBundle thread_bundle_;
scoped_ptr<EmbeddedWorkerTestHelper> helper_;
ServiceWorkerContextCore* context_;
- scoped_refptr<ServiceWorkerRegistration> registration_;
- scoped_refptr<ServiceWorkerVersion> version_;
+ scoped_refptr<ServiceWorkerRegistration> registration1_;
+ scoped_refptr<ServiceWorkerRegistration> registration2_;
base::WeakPtr<ServiceWorkerProviderHost> provider_host1_;
base::WeakPtr<ServiceWorkerProviderHost> provider_host2_;
- GURL pattern_;
GURL script_url_;
private:
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerProviderHostTest);
};
-TEST_F(ServiceWorkerProviderHostTest, SetActiveVersion_ProcessStatus) {
- 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.
- registration_->SetActiveVersion(version_.get());
- ASSERT_TRUE(HasProcessToRun());
-
- // Re-associating the same version and provider_host should just work too.
- registration_->SetActiveVersion(version_.get());
- ASSERT_TRUE(HasProcessToRun());
-
- // Resetting the provider_host's active version should remove process refs
- // from the version.
- provider_host1_->DisassociateRegistration();
- ASSERT_FALSE(HasProcessToRun());
-}
-
-TEST_F(ServiceWorkerProviderHostTest,
- SetActiveVersion_MultipleHostsForSameProcess) {
- provider_host1_->AssociateRegistration(registration_.get());
- provider_host2_->AssociateRegistration(registration_.get());
- ASSERT_TRUE(HasProcessToRun());
-
- // Associating version_ to two providers as active version.
- registration_->SetActiveVersion(version_.get());
- ASSERT_TRUE(HasProcessToRun());
-
- // Disassociating one provider_host shouldn't remove all process refs
- // from the version yet.
- provider_host1_->DisassociateRegistration();
- ASSERT_TRUE(HasProcessToRun());
-
- // Disassociating the other provider_host will remove all process refs.
- provider_host2_->DisassociateRegistration();
- ASSERT_FALSE(HasProcessToRun());
+TEST_F(ServiceWorkerProviderHostTest, PotentialRegistration_ProcessStatus) {
+ provider_host1_->AddMatchingRegistration(registration1_.get());
+ ASSERT_TRUE(PatternHasProcessToRun(registration1_->pattern()));
+
+ // Adding the same registration twice has no effect.
+ provider_host1_->AddMatchingRegistration(registration1_.get());
+ ASSERT_TRUE(PatternHasProcessToRun(registration1_->pattern()));
+
+ // Different matching registrations can be added.
+ provider_host1_->AddMatchingRegistration(registration2_.get());
+ ASSERT_TRUE(PatternHasProcessToRun(registration2_->pattern()));
+
+ // Removing a matching registration will decrease the process refs for its
+ // pattern.
+ provider_host1_->RemoveMatchingRegistration(registration1_.get());
+ ASSERT_FALSE(PatternHasProcessToRun(registration1_->pattern()));
+
+ // Multiple provider hosts could add the same matching registration.
+ // The process refs will become 0 after all provider hosts removed them.
+ provider_host2_->AddMatchingRegistration(registration2_.get());
+ provider_host1_->RemoveMatchingRegistration(registration2_.get());
+ ASSERT_TRUE(PatternHasProcessToRun(registration2_->pattern()));
+ provider_host2_->RemoveMatchingRegistration(registration2_.get());
+ ASSERT_FALSE(PatternHasProcessToRun(registration2_->pattern()));
}
-TEST_F(ServiceWorkerProviderHostTest, SetWaitingVersion_ProcessStatus) {
- 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.
- registration_->SetWaitingVersion(version_.get());
- ASSERT_TRUE(HasProcessToRun());
+TEST_F(ServiceWorkerProviderHostTest, AssociatedRegistration_ProcessStatus) {
+ // Associating the registration will also increase the process refs for
+ // the registration's pattern.
+ provider_host1_->AssociateRegistration(registration1_.get(),
+ false /* notify_controllerchange */);
+ ASSERT_TRUE(PatternHasProcessToRun(registration1_->pattern()));
- // Re-associating the same version and provider_host should just work too.
- registration_->SetWaitingVersion(version_.get());
- ASSERT_TRUE(HasProcessToRun());
-
- // Resetting the provider_host's waiting version should remove process refs
- // from the version.
+ // Disassociating the registration shouldn't affect the process refs for
+ // the registration's pattern.
provider_host1_->DisassociateRegistration();
- ASSERT_FALSE(HasProcessToRun());
+ ASSERT_TRUE(PatternHasProcessToRun(registration1_->pattern()));
}
-TEST_F(ServiceWorkerProviderHostTest,
- SetWaitingVersion_MultipleHostsForSameProcess) {
- provider_host1_->AssociateRegistration(registration_.get());
- provider_host2_->AssociateRegistration(registration_.get());
- ASSERT_TRUE(HasProcessToRun());
-
- // Associating version_ to two providers as waiting version.
- registration_->SetWaitingVersion(version_.get());
- ASSERT_TRUE(HasProcessToRun());
+TEST_F(ServiceWorkerProviderHostTest, MatchRegistration) {
+ provider_host1_->AddMatchingRegistration(registration1_.get());
+ provider_host1_->AddMatchingRegistration(registration2_.get());
- // Disassociating one provider_host shouldn't remove all process refs
- // from the version yet.
- provider_host1_->DisassociateRegistration();
- ASSERT_TRUE(HasProcessToRun());
+ // Match registration should return the longest matching one.
+ ASSERT_EQ(provider_host1_->MatchRegistration(), registration2_);
+ provider_host1_->RemoveMatchingRegistration(registration2_.get());
+ ASSERT_EQ(provider_host1_->MatchRegistration(), registration1_);
- // Disassociating the other provider_host will remove all process refs.
- provider_host2_->DisassociateRegistration();
- ASSERT_FALSE(HasProcessToRun());
+ // Should return nullptr after removing all matching registrations.
+ provider_host1_->RemoveMatchingRegistration(registration1_.get());
+ ASSERT_EQ(provider_host1_->MatchRegistration(), nullptr);
}
} // namespace content
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 07f47e11016..f6809dda66d 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
@@ -7,10 +7,11 @@
#include <string>
#include <vector>
-#include "base/debug/trace_event.h"
+#include "base/trace_event/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_metrics.h"
+#include "content/public/browser/browser_thread.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/http/http_request_headers.h"
@@ -25,9 +26,11 @@ ServiceWorkerReadFromCacheJob::ServiceWorkerReadFromCacheJob(
net::URLRequest* request,
net::NetworkDelegate* network_delegate,
base::WeakPtr<ServiceWorkerContextCore> context,
+ const scoped_refptr<ServiceWorkerVersion>& version,
int64 response_id)
: net::URLRequestJob(request, network_delegate),
context_(context),
+ version_(version),
response_id_(response_id),
has_been_killed_(false),
weak_factory_(this) {
@@ -149,7 +152,7 @@ void ServiceWorkerReadFromCacheJob::OnReadInfoComplete(int result) {
DCHECK_LT(result, 0);
ServiceWorkerMetrics::CountReadResponseResult(
ServiceWorkerMetrics::READ_HEADERS_ERROR);
- NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
+ Done(net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
return;
}
DCHECK_GE(result, 0);
@@ -158,6 +161,8 @@ void ServiceWorkerReadFromCacheJob::OnReadInfoComplete(int result) {
if (is_range_request())
SetupRangeResponse(http_info_io_buffer_->response_data_size);
http_info_io_buffer_ = NULL;
+ if (request_->url() == version_->script_url())
+ version_->SetMainScriptHttpResponseInfo(*http_info_);
TRACE_EVENT_ASYNC_END1("ServiceWorker",
"ServiceWorkerReadFromCacheJob::ReadInfo",
this,
@@ -188,14 +193,28 @@ void ServiceWorkerReadFromCacheJob::SetupRangeResponse(int resource_size) {
range_requested_, resource_size, true /* replace status line */);
}
+void ServiceWorkerReadFromCacheJob::Done(const net::URLRequestStatus& status) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (!status.is_success()) {
+ version_->SetStartWorkerStatusCode(SERVICE_WORKER_ERROR_DISK_CACHE);
+ // TODO(falken): Retry before evicting.
+ if (context_) {
+ ServiceWorkerRegistration* registration =
+ context_->GetLiveRegistration(version_->registration_id());
+ registration->DeleteVersion(version_);
+ }
+ }
+ NotifyDone(status);
+}
+
void ServiceWorkerReadFromCacheJob::OnReadComplete(int result) {
ServiceWorkerMetrics::ReadResponseResult check_result;
if (result == 0) {
check_result = ServiceWorkerMetrics::READ_OK;
- NotifyDone(net::URLRequestStatus());
+ Done(net::URLRequestStatus());
} else if (result < 0) {
check_result = ServiceWorkerMetrics::READ_DATA_ERROR;
- NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
+ Done(net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
} else {
check_result = ServiceWorkerMetrics::READ_OK;
SetStatus(net::URLRequestStatus()); // Clear the IO_PENDING status
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 2a290d3c84d..82d9d5f1779 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
@@ -18,6 +18,7 @@ namespace content {
class ServiceWorkerContextCore;
class ServiceWorkerResponseReader;
+class ServiceWorkerVersion;
// A URLRequestJob derivative used to retrieve script resources
// from the service workers script cache. It uses a response reader
@@ -29,6 +30,7 @@ class CONTENT_EXPORT ServiceWorkerReadFromCacheJob
net::URLRequest* request,
net::NetworkDelegate* network_delegate,
base::WeakPtr<ServiceWorkerContextCore> context,
+ const scoped_refptr<ServiceWorkerVersion>& version,
int64 response_id);
private:
@@ -53,8 +55,10 @@ class CONTENT_EXPORT ServiceWorkerReadFromCacheJob
const net::HttpResponseInfo* http_info() const;
bool is_range_request() const { return range_requested_.IsValid(); }
void SetupRangeResponse(int response_data_size);
+ void Done(const net::URLRequestStatus& status);
base::WeakPtr<ServiceWorkerContextCore> context_;
+ scoped_refptr<ServiceWorkerVersion> version_;
int64 response_id_;
scoped_ptr<ServiceWorkerResponseReader> reader_;
scoped_refptr<HttpResponseInfoIOBuffer> http_info_io_buffer_;
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 b68cd30f819..6ab1db63c53 100644
--- a/chromium/content/browser/service_worker/service_worker_register_job.cc
+++ b/chromium/content/browser/service_worker/service_worker_register_job.cc
@@ -9,9 +9,11 @@
#include "base/message_loop/message_loop.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_metrics.h"
#include "content/browser/service_worker/service_worker_registration.h"
#include "content/browser/service_worker/service_worker_storage.h"
#include "content/browser/service_worker/service_worker_utils.h"
+#include "content/common/service_worker/service_worker_types.h"
#include "net/base/net_errors.h"
namespace content {
@@ -35,19 +37,27 @@ ServiceWorkerRegisterJob::ServiceWorkerRegisterJob(
pattern_(pattern),
script_url_(script_url),
phase_(INITIAL),
+ doom_installing_worker_(false),
is_promise_resolved_(false),
+ should_uninstall_on_failure_(false),
+ force_bypass_cache_(false),
promise_resolved_status_(SERVICE_WORKER_OK),
- weak_factory_(this) {}
+ weak_factory_(this) {
+}
ServiceWorkerRegisterJob::ServiceWorkerRegisterJob(
base::WeakPtr<ServiceWorkerContextCore> context,
- ServiceWorkerRegistration* registration)
+ ServiceWorkerRegistration* registration,
+ bool force_bypass_cache)
: context_(context),
job_type_(UPDATE_JOB),
pattern_(registration->pattern()),
script_url_(registration->GetNewestVersion()->script_url()),
phase_(INITIAL),
+ doom_installing_worker_(false),
is_promise_resolved_(false),
+ should_uninstall_on_failure_(false),
+ force_bypass_cache_(force_bypass_cache),
promise_resolved_status_(SERVICE_WORKER_OK),
weak_factory_(this) {
internal_.registration = registration;
@@ -68,8 +78,9 @@ void ServiceWorkerRegisterJob::AddCallback(
provider_host->AddScopedProcessReferenceToPattern(pattern_);
return;
}
- RunSoon(base::Bind(
- callback, promise_resolved_status_, promise_resolved_registration_));
+ RunSoon(base::Bind(callback, promise_resolved_status_,
+ promise_resolved_status_message_,
+ promise_resolved_registration_));
}
void ServiceWorkerRegisterJob::Start() {
@@ -95,12 +106,12 @@ void ServiceWorkerRegisterJob::Start() {
void ServiceWorkerRegisterJob::Abort() {
SetPhase(ABORT);
- CompleteInternal(SERVICE_WORKER_ERROR_ABORT);
+ CompleteInternal(SERVICE_WORKER_ERROR_ABORT, std::string());
// Don't have to call FinishJob() because the caller takes care of removing
// the jobs from the queue.
}
-bool ServiceWorkerRegisterJob::Equals(ServiceWorkerRegisterJobBase* job) {
+bool ServiceWorkerRegisterJob::Equals(ServiceWorkerRegisterJobBase* job) const {
if (job->GetType() != GetType())
return false;
ServiceWorkerRegisterJob* register_job =
@@ -109,10 +120,16 @@ bool ServiceWorkerRegisterJob::Equals(ServiceWorkerRegisterJobBase* job) {
register_job->script_url_ == script_url_;
}
-RegistrationJobType ServiceWorkerRegisterJob::GetType() {
+RegistrationJobType ServiceWorkerRegisterJob::GetType() const {
return job_type_;
}
+void ServiceWorkerRegisterJob::DoomInstallingWorker() {
+ doom_installing_worker_ = true;
+ if (phase_ == INSTALL)
+ Complete(SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED, std::string());
+}
+
ServiceWorkerRegisterJob::Internal::Internal() {}
ServiceWorkerRegisterJob::Internal::~Internal() {}
@@ -141,18 +158,6 @@ ServiceWorkerVersion* ServiceWorkerRegisterJob::new_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) {
switch (phase) {
case INITIAL:
@@ -161,11 +166,8 @@ void ServiceWorkerRegisterJob::SetPhase(Phase phase) {
case START:
DCHECK(phase_ == INITIAL) << phase_;
break;
- case WAIT_FOR_UNINSTALL:
- DCHECK(phase_ == START) << phase_;
- break;
case REGISTER:
- DCHECK(phase_ == START || phase_ == WAIT_FOR_UNINSTALL) << phase_;
+ DCHECK(phase_ == START) << phase_;
break;
case UPDATE:
DCHECK(phase_ == START || phase_ == REGISTER) << phase_;
@@ -198,7 +200,7 @@ void ServiceWorkerRegisterJob::ContinueWithRegistration(
}
if (!existing_registration.get() || existing_registration->is_uninstalled()) {
- RegisterAndContinue(SERVICE_WORKER_OK);
+ RegisterAndContinue();
return;
}
@@ -214,16 +216,13 @@ void ServiceWorkerRegisterJob::ContinueWithRegistration(
}
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);
+ existing_registration->AbortPendingClear(base::Bind(
+ &ServiceWorkerRegisterJob::ContinueWithUninstallingRegistration,
+ weak_factory_.GetWeakPtr(),
+ 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);
@@ -260,26 +259,25 @@ void ServiceWorkerRegisterJob::ContinueWithUpdate(
}
// Creates a new ServiceWorkerRegistration.
-void ServiceWorkerRegisterJob::RegisterAndContinue(
- ServiceWorkerStatusCode status) {
+void ServiceWorkerRegisterJob::RegisterAndContinue() {
SetPhase(REGISTER);
- if (status != SERVICE_WORKER_OK) {
- // Abort this registration job.
- Complete(status);
- return;
- }
set_registration(new ServiceWorkerRegistration(
pattern_, context_->storage()->NewRegistrationId(), context_));
- AssociateProviderHostsToRegistration(registration());
+ AddRegistrationToMatchingProviderHosts(registration());
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::ContinueWithUninstallingRegistration(
+ const scoped_refptr<ServiceWorkerRegistration>& existing_registration,
+ ServiceWorkerStatusCode status) {
+ if (status != SERVICE_WORKER_OK) {
+ Complete(status);
+ return;
+ }
+ should_uninstall_on_failure_ = true;
+ set_registration(existing_registration);
+ UpdateAndContinue();
}
void ServiceWorkerRegisterJob::ContinueWithRegistrationForSameScriptUrl(
@@ -300,7 +298,7 @@ void ServiceWorkerRegisterJob::ContinueWithRegistrationForSameScriptUrl(
// either case.
DCHECK(!existing_registration->installing_version());
if (existing_registration->active_version()) {
- ResolvePromise(status, existing_registration.get());
+ ResolvePromise(status, std::string(), existing_registration.get());
Complete(SERVICE_WORKER_OK);
return;
}
@@ -321,7 +319,7 @@ void ServiceWorkerRegisterJob::UpdateAndContinue() {
script_url_,
context_->storage()->NewVersionId(),
context_));
-
+ new_version()->set_force_bypass_cache_for_scripts(force_bypass_cache_);
bool pause_after_download = job_type_ == UPDATE_JOB;
if (pause_after_download)
new_version()->embedded_worker()->AddListener(this);
@@ -339,24 +337,21 @@ void ServiceWorkerRegisterJob::OnStartWorkerFinished(
}
// "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.
+ // error and abort.
+ if (status == SERVICE_WORKER_ERROR_TIMEOUT) {
+ Complete(status, "Timed out while trying to start the Service Worker.");
+ return;
+ }
+
const net::URLRequestStatus& main_script_status =
new_version()->script_cache_map()->main_script_status();
+ std::string message;
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;
- }
+ message = new_version()->script_cache_map()->main_script_status_message();
+ if (message.empty())
+ message = kFetchScriptError;
}
- Complete(status);
+ Complete(status, message);
}
// This function corresponds to the spec's [[Install]] algorithm.
@@ -372,22 +367,27 @@ void ServiceWorkerRegisterJob::InstallAndContinue() {
new_version()->SetStatus(ServiceWorkerVersion::INSTALLING);
// "Resolve registrationPromise with registration."
- ResolvePromise(SERVICE_WORKER_OK, registration());
+ ResolvePromise(SERVICE_WORKER_OK, std::string(), 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()));
+
+ // A subsequent registration job may terminate our installing worker. It can
+ // only do so after we've started the worker and dispatched the install
+ // event, as those are atomic substeps in the [[Install]] algorithm.
+ if (doom_installing_worker_)
+ Complete(SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED);
}
void ServiceWorkerRegisterJob::OnInstallFinished(
ServiceWorkerStatusCode status) {
- // TODO(kinuko,falken): For some error cases (e.g. ServiceWorker is
- // unexpectedly terminated) we may want to retry sending the event again.
+ ServiceWorkerMetrics::RecordInstallEventStatus(status);
+
if (status != SERVICE_WORKER_OK) {
// "8. If installFailed is true, then:..."
Complete(status);
@@ -426,26 +426,37 @@ void ServiceWorkerRegisterJob::OnStoreRegistrationComplete(
// 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."
+ // "If registration's waiting worker's skip waiting flag is set:" then
+ // activate the worker immediately otherwise "wait until no service worker
+ // client is using registration as their service worker registration."
registration()->ActivateWaitingVersionWhenReady();
Complete(SERVICE_WORKER_OK);
}
void ServiceWorkerRegisterJob::Complete(ServiceWorkerStatusCode status) {
- CompleteInternal(status);
+ Complete(status, std::string());
+}
+
+void ServiceWorkerRegisterJob::Complete(ServiceWorkerStatusCode status,
+ const std::string& status_message) {
+ CompleteInternal(status, status_message);
context_->job_coordinator()->FinishJob(pattern_, this);
}
void ServiceWorkerRegisterJob::CompleteInternal(
- ServiceWorkerStatusCode status) {
+ ServiceWorkerStatusCode status,
+ const std::string& status_message) {
SetPhase(COMPLETE);
if (status != SERVICE_WORKER_OK) {
if (registration()) {
+ if (should_uninstall_on_failure_)
+ registration()->ClearWhenReady();
if (new_version()) {
+ if (status == SERVICE_WORKER_ERROR_EXISTS)
+ new_version()->SetStartWorkerStatusCode(SERVICE_WORKER_ERROR_EXISTS);
+ else
+ new_version()->ReportError(status, status_message);
registration()->UnsetVersion(new_version());
new_version()->Doom();
}
@@ -459,12 +470,14 @@ void ServiceWorkerRegisterJob::CompleteInternal(
}
}
if (!is_promise_resolved_)
- ResolvePromise(status, NULL);
+ ResolvePromise(status, status_message, NULL);
}
DCHECK(callbacks_.empty());
if (registration()) {
context_->storage()->NotifyDoneInstallingRegistration(
registration(), new_version(), status);
+ if (registration()->waiting_version() || registration()->active_version())
+ registration()->set_is_uninstalled(false);
}
if (new_version())
new_version()->embedded_worker()->RemoveListener(this);
@@ -472,15 +485,18 @@ void ServiceWorkerRegisterJob::CompleteInternal(
void ServiceWorkerRegisterJob::ResolvePromise(
ServiceWorkerStatusCode status,
+ const std::string& status_message,
ServiceWorkerRegistration* registration) {
DCHECK(!is_promise_resolved_);
+
is_promise_resolved_ = true;
promise_resolved_status_ = status;
+ promise_resolved_status_message_ = status_message,
promise_resolved_registration_ = registration;
for (std::vector<RegistrationCallback>::iterator it = callbacks_.begin();
it != callbacks_.end();
++it) {
- it->Run(status, registration);
+ it->Run(status, status_message, registration);
}
callbacks_.clear();
}
@@ -491,7 +507,12 @@ void ServiceWorkerRegisterJob::OnPausedAfterDownload() {
registration()->waiting_version() ?
registration()->waiting_version() :
registration()->active_version();
- DCHECK(most_recent_version.get());
+
+ if (!most_recent_version) {
+ OnCompareScriptResourcesComplete(SERVICE_WORKER_OK, false /* are_equal */);
+ return;
+ }
+
int64 most_recent_script_id =
most_recent_version->script_cache_map()->LookupResourceId(script_url_);
int64 new_script_id =
@@ -511,15 +532,6 @@ 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) {
@@ -527,12 +539,13 @@ void ServiceWorkerRegisterJob::OnCompareScriptResourcesComplete(
// 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)) {
+ if (time_since_last_check > base::TimeDelta::FromHours(24) ||
+ new_version()->force_bypass_cache_for_scripts()) {
registration()->set_last_update_check(base::Time::Now());
context_->storage()->UpdateLastUpdateCheckTime(registration());
}
- ResolvePromise(SERVICE_WORKER_OK, registration());
+ ResolvePromise(SERVICE_WORKER_OK, std::string(), registration());
Complete(SERVICE_WORKER_ERROR_EXISTS);
return;
}
@@ -542,18 +555,19 @@ void ServiceWorkerRegisterJob::OnCompareScriptResourcesComplete(
new_version()->embedded_worker()->RemoveListener(this);
}
-void ServiceWorkerRegisterJob::AssociateProviderHostsToRegistration(
+void ServiceWorkerRegisterJob::AddRegistrationToMatchingProviderHosts(
ServiceWorkerRegistration* registration) {
DCHECK(registration);
for (scoped_ptr<ServiceWorkerContextCore::ProviderHostIterator> it =
context_->GetProviderHostIterator();
!it->IsAtEnd(); it->Advance()) {
ServiceWorkerProviderHost* host = it->GetProviderHost();
- if (ServiceWorkerUtils::ScopeMatches(registration->pattern(),
- host->document_url())) {
- if (host->CanAssociateRegistration(registration))
- host->AssociateRegistration(registration);
- }
+ if (host->IsHostToRunningServiceWorker())
+ continue;
+ if (!ServiceWorkerUtils::ScopeMatches(registration->pattern(),
+ host->document_url()))
+ continue;
+ host->AddMatchingRegistration(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 167501b82cf..7f2693347d3 100644
--- a/chromium/content/browser/service_worker/service_worker_register_job.h
+++ b/chromium/content/browser/service_worker/service_worker_register_job.h
@@ -34,10 +34,10 @@ class ServiceWorkerStorage;
// - designating the new version to be the 'active' version
// - updating storage
class ServiceWorkerRegisterJob : public ServiceWorkerRegisterJobBase,
- public EmbeddedWorkerInstance::Listener,
- public ServiceWorkerRegistration::Listener {
+ public EmbeddedWorkerInstance::Listener {
public:
typedef base::Callback<void(ServiceWorkerStatusCode status,
+ const std::string& status_message,
ServiceWorkerRegistration* registration)>
RegistrationCallback;
@@ -50,7 +50,8 @@ class ServiceWorkerRegisterJob : public ServiceWorkerRegisterJobBase,
// For update jobs.
CONTENT_EXPORT ServiceWorkerRegisterJob(
base::WeakPtr<ServiceWorkerContextCore> context,
- ServiceWorkerRegistration* registration);
+ ServiceWorkerRegistration* registration,
+ bool force_bypass_cache);
~ServiceWorkerRegisterJob() override;
// Registers a callback to be called when the promise would resolve (whether
@@ -63,8 +64,10 @@ class ServiceWorkerRegisterJob : public ServiceWorkerRegisterJobBase,
// ServiceWorkerRegisterJobBase implementation:
void Start() override;
void Abort() override;
- bool Equals(ServiceWorkerRegisterJobBase* job) override;
- RegistrationJobType GetType() override;
+ bool Equals(ServiceWorkerRegisterJobBase* job) const override;
+ RegistrationJobType GetType() const override;
+
+ void DoomInstallingWorker();
private:
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerProviderHostWaitingVersionTest,
@@ -75,7 +78,6 @@ class ServiceWorkerRegisterJob : public ServiceWorkerRegisterJobBase,
enum Phase {
INITIAL,
START,
- WAIT_FOR_UNINSTALL,
REGISTER,
UPDATE,
INSTALL,
@@ -94,8 +96,6 @@ class ServiceWorkerRegisterJob : public ServiceWorkerRegisterJobBase,
// 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(
@@ -103,9 +103,6 @@ class ServiceWorkerRegisterJob : public ServiceWorkerRegisterJobBase,
ServiceWorkerRegistration* registration();
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);
@@ -115,9 +112,10 @@ class ServiceWorkerRegisterJob : public ServiceWorkerRegisterJobBase,
void ContinueWithUpdate(
ServiceWorkerStatusCode status,
const scoped_refptr<ServiceWorkerRegistration>& registration);
- void RegisterAndContinue(ServiceWorkerStatusCode status);
- void WaitForUninstall(
- const scoped_refptr<ServiceWorkerRegistration>& registration);
+ void RegisterAndContinue();
+ void ContinueWithUninstallingRegistration(
+ const scoped_refptr<ServiceWorkerRegistration>& existing_registration,
+ ServiceWorkerStatusCode status);
void ContinueWithRegistrationForSameScriptUrl(
const scoped_refptr<ServiceWorkerRegistration>& existing_registration,
ServiceWorkerStatusCode status);
@@ -129,23 +127,23 @@ class ServiceWorkerRegisterJob : public ServiceWorkerRegisterJobBase,
void ActivateAndContinue();
void OnActivateFinished(ServiceWorkerStatusCode status);
void Complete(ServiceWorkerStatusCode status);
- void CompleteInternal(ServiceWorkerStatusCode status);
+ void Complete(ServiceWorkerStatusCode status,
+ const std::string& status_message);
+ void CompleteInternal(ServiceWorkerStatusCode status,
+ const std::string& status_message);
void ResolvePromise(ServiceWorkerStatusCode status,
+ const std::string& status_message,
ServiceWorkerRegistration* registration);
// EmbeddedWorkerInstance::Listener override of OnPausedAfterDownload.
void OnPausedAfterDownload() override;
bool OnMessageReceived(const IPC::Message& message) override;
- // ServiceWorkerRegistration::Listener overrides
- void OnRegistrationFinishedUninstalling(
- ServiceWorkerRegistration* registration) override;
-
void OnCompareScriptResourcesComplete(
ServiceWorkerStatusCode status,
bool are_equal);
- void AssociateProviderHostsToRegistration(
+ void AddRegistrationToMatchingProviderHosts(
ServiceWorkerRegistration* registration);
// The ServiceWorkerContextCore object should always outlive this.
@@ -157,8 +155,12 @@ class ServiceWorkerRegisterJob : public ServiceWorkerRegisterJobBase,
std::vector<RegistrationCallback> callbacks_;
Phase phase_;
Internal internal_;
+ bool doom_installing_worker_;
bool is_promise_resolved_;
+ bool should_uninstall_on_failure_;
+ bool force_bypass_cache_;
ServiceWorkerStatusCode promise_resolved_status_;
+ std::string promise_resolved_status_message_;
scoped_refptr<ServiceWorkerRegistration> promise_resolved_registration_;
base::WeakPtrFactory<ServiceWorkerRegisterJob> weak_factory_;
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 9233e7c69af..a35162d7e0a 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
@@ -28,10 +28,10 @@ class ServiceWorkerRegisterJobBase {
// collapsing them together in a ServiceWorkerJobCoordinator queue.
// Registration jobs are equal if they are for the same pattern and script
// URL; unregistration jobs are equal if they are for the same pattern.
- virtual bool Equals(ServiceWorkerRegisterJobBase* job) = 0;
+ virtual bool Equals(ServiceWorkerRegisterJobBase* job) const = 0;
// Returns the type of this job.
- virtual RegistrationJobType GetType() = 0;
+ virtual RegistrationJobType GetType() const = 0;
};
} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_registration.cc b/chromium/content/browser/service_worker/service_worker_registration.cc
index 0445f08f7e6..48472219dee 100644
--- a/chromium/content/browser/service_worker/service_worker_registration.cc
+++ b/chromium/content/browser/service_worker/service_worker_registration.cc
@@ -6,6 +6,7 @@
#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_metrics.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"
@@ -34,13 +35,13 @@ ServiceWorkerRegistration::ServiceWorkerRegistration(
should_activate_when_ready_(false),
resources_total_size_bytes_(0),
context_(context) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(context_);
context_->AddLiveRegistration(this);
}
ServiceWorkerRegistration::~ServiceWorkerRegistration() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(!listeners_.might_have_observers());
if (context_)
context_->RemoveLiveRegistration(registration_id_);
@@ -73,34 +74,65 @@ void ServiceWorkerRegistration::NotifyUpdateFound() {
}
ServiceWorkerRegistrationInfo ServiceWorkerRegistration::GetInfo() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
return ServiceWorkerRegistrationInfo(
- pattern(),
- registration_id_,
+ pattern(), registration_id_,
+ is_deleted_ ? ServiceWorkerRegistrationInfo::IS_DELETED
+ : ServiceWorkerRegistrationInfo::IS_NOT_DELETED,
GetVersionInfo(active_version_.get()),
GetVersionInfo(waiting_version_.get()),
- GetVersionInfo(installing_version_.get()),
- resources_total_size_bytes_);
+ GetVersionInfo(installing_version_.get()), resources_total_size_bytes_);
}
void ServiceWorkerRegistration::SetActiveVersion(
- ServiceWorkerVersion* version) {
+ const scoped_refptr<ServiceWorkerVersion>& version) {
should_activate_when_ready_ = false;
- SetVersionInternal(version, &active_version_,
- ChangedVersionAttributesMask::ACTIVE_VERSION);
+ if (active_version_ == version)
+ return;
+
+ ChangedVersionAttributesMask mask;
+ if (version)
+ UnsetVersionInternal(version.get(), &mask);
+ if (active_version_)
+ active_version_->RemoveListener(this);
+ active_version_ = version;
+ if (active_version_)
+ active_version_->AddListener(this);
+ mask.add(ChangedVersionAttributesMask::ACTIVE_VERSION);
+
+ FOR_EACH_OBSERVER(Listener, listeners_,
+ OnVersionAttributesChanged(this, mask, GetInfo()));
}
void ServiceWorkerRegistration::SetWaitingVersion(
- ServiceWorkerVersion* version) {
+ const scoped_refptr<ServiceWorkerVersion>& version) {
should_activate_when_ready_ = false;
- SetVersionInternal(version, &waiting_version_,
- ChangedVersionAttributesMask::WAITING_VERSION);
+ if (waiting_version_ == version)
+ return;
+
+ ChangedVersionAttributesMask mask;
+ if (version)
+ UnsetVersionInternal(version.get(), &mask);
+ waiting_version_ = version;
+ mask.add(ChangedVersionAttributesMask::WAITING_VERSION);
+
+ FOR_EACH_OBSERVER(Listener, listeners_,
+ OnVersionAttributesChanged(this, mask, GetInfo()));
}
void ServiceWorkerRegistration::SetInstallingVersion(
- ServiceWorkerVersion* version) {
- SetVersionInternal(version, &installing_version_,
- ChangedVersionAttributesMask::INSTALLING_VERSION);
+ const scoped_refptr<ServiceWorkerVersion>& version) {
+ if (installing_version_ == version)
+ return;
+
+ ChangedVersionAttributesMask mask;
+ if (version)
+ UnsetVersionInternal(version.get(), &mask);
+ installing_version_ = version;
+ mask.add(ChangedVersionAttributesMask::INSTALLING_VERSION);
+
+ FOR_EACH_OBSERVER(Listener, listeners_,
+ OnVersionAttributesChanged(this, mask, GetInfo()));
}
void ServiceWorkerRegistration::UnsetVersion(ServiceWorkerVersion* version) {
@@ -115,25 +147,6 @@ void ServiceWorkerRegistration::UnsetVersion(ServiceWorkerVersion* version) {
}
}
-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) {
@@ -154,10 +167,29 @@ void ServiceWorkerRegistration::UnsetVersionInternal(
void ServiceWorkerRegistration::ActivateWaitingVersionWhenReady() {
DCHECK(waiting_version());
should_activate_when_ready_ = true;
- if (!active_version() || !active_version()->HasControllee())
+
+ if (!active_version() || !active_version()->HasControllee() ||
+ waiting_version()->skip_waiting())
ActivateWaitingVersion();
}
+void ServiceWorkerRegistration::ClaimClients() {
+ DCHECK(context_);
+ DCHECK(active_version());
+
+ for (scoped_ptr<ServiceWorkerContextCore::ProviderHostIterator> it =
+ context_->GetProviderHostIterator();
+ !it->IsAtEnd(); it->Advance()) {
+ ServiceWorkerProviderHost* host = it->GetProviderHost();
+ if (host->IsHostToRunningServiceWorker())
+ continue;
+ if (host->controlling_version() == active_version())
+ continue;
+ if (host->MatchRegistration() == this)
+ host->ClaimedByRegistration(this);
+ }
+}
+
void ServiceWorkerRegistration::ClearWhenReady() {
DCHECK(context_);
if (is_uninstalling_)
@@ -197,7 +229,32 @@ void ServiceWorkerRegistration::AbortPendingClear(
most_recent_version));
}
+void ServiceWorkerRegistration::GetUserData(
+ const std::string& key,
+ const GetUserDataCallback& callback) {
+ DCHECK(context_);
+ context_->storage()->GetUserData(registration_id_, key, callback);
+}
+
+void ServiceWorkerRegistration::StoreUserData(
+ const std::string& key,
+ const std::string& data,
+ const StatusCallback& callback) {
+ DCHECK(context_);
+ context_->storage()->StoreUserData(
+ registration_id_, pattern().GetOrigin(), key, data, callback);
+}
+
+void ServiceWorkerRegistration::ClearUserData(
+ const std::string& key,
+ const StatusCallback& callback) {
+ DCHECK(context_);
+ context_->storage()->ClearUserData(registration_id_, key, callback);
+}
+
void ServiceWorkerRegistration::OnNoControllees(ServiceWorkerVersion* version) {
+ if (!context_)
+ return;
DCHECK_EQ(active_version(), version);
if (is_uninstalling_)
Clear();
@@ -215,14 +272,11 @@ void ServiceWorkerRegistration::ActivateWaitingVersion() {
scoped_refptr<ServiceWorkerVersion> activating_version = waiting_version();
scoped_refptr<ServiceWorkerVersion> exiting_version = active_version();
- if (activating_version->is_doomed() ||
- activating_version->status() == ServiceWorkerVersion::REDUNDANT) {
+ if (activating_version->is_redundant())
return; // Activation is no longer relevant.
- }
- // "4. If exitingWorker is not null,
+ // "5. 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."
@@ -233,47 +287,79 @@ void ServiceWorkerRegistration::ActivateWaitingVersion() {
exiting_version->SetStatus(ServiceWorkerVersion::REDUNDANT);
}
- // "5. Set serviceWorkerRegistration.activeWorker to activatingWorker."
- // "6. Set serviceWorkerRegistration.waitingWorker to null."
- SetActiveVersion(activating_version.get());
+ // "6. Set serviceWorkerRegistration.activeWorker to activatingWorker."
+ // "7. Set serviceWorkerRegistration.waitingWorker to null."
+ SetActiveVersion(activating_version);
- // "7. Run the [[UpdateState]] algorithm passing registration.activeWorker and
+ // "8. Run the [[UpdateState]] algorithm passing registration.activeWorker and
// "activating" as arguments."
activating_version->SetStatus(ServiceWorkerVersion::ACTIVATING);
+ // "9. Fire a simple event named controllerchange..."
+ if (activating_version->skip_waiting())
+ FOR_EACH_OBSERVER(Listener, listeners_, OnSkippedWaiting(this));
- // TODO(nhiroki): "8. Fire a simple event named controllerchange..."
-
- // "9. Queue a task to fire an event named activate..."
+ // "10. Queue a task to fire an event named activate..."
activating_version->DispatchActivateEvent(
base::Bind(&ServiceWorkerRegistration::OnActivateEventFinished,
this, activating_version));
}
+void ServiceWorkerRegistration::DeleteVersion(
+ const scoped_refptr<ServiceWorkerVersion>& version) {
+ DCHECK_EQ(id(), version->registration_id());
+
+ // "Set registration's active worker to null." (The spec's step order may
+ // differ. It's OK because the other steps queue a task.)
+ UnsetVersion(version.get());
+
+ // "Run the Update State algorithm passing registration's active worker and
+ // 'redundant' as the arguments."
+ version->SetStatus(ServiceWorkerVersion::REDUNDANT);
+
+ // "For each service worker client client whose active worker is
+ // registration's active worker..." set the active worker to null.
+ for (scoped_ptr<ServiceWorkerContextCore::ProviderHostIterator> it =
+ context_->GetProviderHostIterator();
+ !it->IsAtEnd(); it->Advance()) {
+ ServiceWorkerProviderHost* host = it->GetProviderHost();
+ if (host->controlling_version() == version)
+ host->NotifyControllerActivationFailed();
+ }
+
+ version->Doom();
+
+ if (!active_version() && !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.
+ // TODO(falken): Fix this logic. There could be a running register job for
+ // this registration that hasn't set installing_version() yet.
+ if (installing_version()) {
+ is_deleted_ = false;
+ } else {
+ is_uninstalled_ = true;
+ FOR_EACH_OBSERVER(Listener, listeners_, OnRegistrationFailed(this));
+ }
+ }
+}
+
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.
+ ServiceWorkerMetrics::RecordActivateEventStatus(status);
+
+ // "If activateFailed is true, then:..."
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;
- }
+ DeleteVersion(make_scoped_refptr(activating_version));
return;
}
- // "12. Run the [[UpdateState]] algorithm passing registration.activeWorker
- // and "activated" as the arguments."
+ // "Run the Update State algorithm passing registration's active worker and
+ // 'activated' as the arguments."
activating_version->SetStatus(ServiceWorkerVersion::ACTIVATED);
if (context_) {
context_->storage()->UpdateToActiveState(
diff --git a/chromium/content/browser/service_worker/service_worker_registration.h b/chromium/content/browser/service_worker/service_worker_registration.h
index b386eecfad3..9ed212b4418 100644
--- a/chromium/content/browser/service_worker/service_worker_registration.h
+++ b/chromium/content/browser/service_worker/service_worker_registration.h
@@ -5,6 +5,8 @@
#ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_REGISTRATION_H_
#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_REGISTRATION_H_
+#include <string>
+
#include "base/basictypes.h"
#include "base/gtest_prod_util.h"
#include "base/logging.h"
@@ -17,8 +19,8 @@
namespace content {
-class ServiceWorkerRegistrationInfo;
class ServiceWorkerVersion;
+struct ServiceWorkerRegistrationInfo;
// This class represents a Service Worker registration. The scope is constant
// for the life of the persistent registration. It's refcounted to facilitate
@@ -28,6 +30,9 @@ class CONTENT_EXPORT ServiceWorkerRegistration
public ServiceWorkerVersion::Listener {
public:
typedef base::Callback<void(ServiceWorkerStatusCode status)> StatusCallback;
+ typedef base::Callback<void(
+ const std::string& data,
+ ServiceWorkerStatusCode status)> GetUserDataCallback;
class Listener {
public:
@@ -41,6 +46,7 @@ class CONTENT_EXPORT ServiceWorkerRegistration
ServiceWorkerRegistration* registration) {}
virtual void OnUpdateFound(
ServiceWorkerRegistration* registration) {}
+ virtual void OnSkippedWaiting(ServiceWorkerRegistration* registation) {}
};
ServiceWorkerRegistration(const GURL& pattern,
@@ -54,6 +60,8 @@ class CONTENT_EXPORT ServiceWorkerRegistration
void set_is_deleted(bool deleted) { is_deleted_ = deleted; }
bool is_uninstalling() const { return is_uninstalling_; }
+
+ void set_is_uninstalled(bool uninstalled) { is_uninstalled_ = uninstalled; }
bool is_uninstalled() const { return is_uninstalled_; }
int64_t resources_total_size_bytes() const {
@@ -88,9 +96,9 @@ class CONTENT_EXPORT ServiceWorkerRegistration
// 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);
+ void SetActiveVersion(const scoped_refptr<ServiceWorkerVersion>& version);
+ void SetWaitingVersion(const scoped_refptr<ServiceWorkerVersion>& version);
+ void SetInstallingVersion(const scoped_refptr<ServiceWorkerVersion>& version);
// If version is the installing, waiting, active version of this
// registation, the method will reset that field to NULL, and notify
@@ -99,9 +107,14 @@ class CONTENT_EXPORT ServiceWorkerRegistration
// 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.
+ // is called or when version's skip waiting flag is set, activation is
+ // initiated immediately.
void ActivateWaitingVersionWhenReady();
+ // Takes over control of provider hosts which are currently not controlled or
+ // controlled by other registrations.
+ void ClaimClients();
+
// Triggers the [[ClearRegistration]] algorithm when the currently
// active version has no controllees. Deletes this registration
// from storage immediately.
@@ -115,15 +128,26 @@ class CONTENT_EXPORT ServiceWorkerRegistration
base::Time last_update_check() const { return last_update_check_; }
void set_last_update_check(base::Time last) { last_update_check_ = last; }
+ // Provide a storage mechanism to read/write arbitrary data associated with
+ // this registration in the storage. Stored data is deleted when this
+ // registration is deleted from the storage.
+ void GetUserData(const std::string& key,
+ const GetUserDataCallback& callback);
+ void StoreUserData(const std::string& key,
+ const std::string& data,
+ const StatusCallback& callback);
+ void ClearUserData(const std::string& key,
+ const StatusCallback& callback);
+
+ // Unsets the version and deletes its resources. Also deletes this
+ // registration from storage if there is no longer a stored version.
+ void DeleteVersion(const scoped_refptr<ServiceWorkerVersion>& version);
+
private:
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);
diff --git a/chromium/content/browser/service_worker/service_worker_registration_handle.cc b/chromium/content/browser/service_worker/service_worker_registration_handle.cc
index 195a33a8235..42fe249dc2f 100644
--- a/chromium/content/browser/service_worker/service_worker_registration_handle.cc
+++ b/chromium/content/browser/service_worker/service_worker_registration_handle.cc
@@ -5,28 +5,34 @@
#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"
+#include "content/common/service_worker/service_worker_types.h"
namespace content {
-static const int kDocumentMainThreadId = 0;
-
ServiceWorkerRegistrationHandle::ServiceWorkerRegistrationHandle(
base::WeakPtr<ServiceWorkerContextCore> context,
- ServiceWorkerDispatcherHost* dispatcher_host,
- int provider_id,
+ base::WeakPtr<ServiceWorkerProviderHost> provider_host,
ServiceWorkerRegistration* registration)
: context_(context),
- dispatcher_host_(dispatcher_host),
- provider_id_(provider_id),
+ provider_host_(provider_host),
+ provider_id_(provider_host ? provider_host->provider_id()
+ : kInvalidServiceWorkerProviderId),
handle_id_(context ? context->GetNewRegistrationHandleId()
: kInvalidServiceWorkerRegistrationHandleId),
ref_count_(1),
registration_(registration) {
DCHECK(registration_.get());
- SetVersionAttributes(registration->installing_version(),
+ ChangedVersionAttributesMask changed_mask;
+ if (registration->installing_version())
+ changed_mask.add(ChangedVersionAttributesMask::INSTALLING_VERSION);
+ if (registration->waiting_version())
+ changed_mask.add(ChangedVersionAttributesMask::WAITING_VERSION);
+ if (registration->active_version())
+ changed_mask.add(ChangedVersionAttributesMask::ACTIVE_VERSION);
+ SetVersionAttributes(changed_mask,
+ registration->installing_version(),
registration->waiting_version(),
registration->active_version());
registration_->AddListener(this);
@@ -46,23 +52,6 @@ ServiceWorkerRegistrationHandle::GetObjectInfo() {
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_;
@@ -78,7 +67,8 @@ void ServiceWorkerRegistrationHandle::OnVersionAttributesChanged(
ChangedVersionAttributesMask changed_mask,
const ServiceWorkerRegistrationInfo& info) {
DCHECK_EQ(registration->id(), registration_->id());
- SetVersionAttributes(registration->installing_version(),
+ SetVersionAttributes(changed_mask,
+ registration->installing_version(),
registration->waiting_version(),
registration->active_version());
}
@@ -86,62 +76,32 @@ void ServiceWorkerRegistrationHandle::OnVersionAttributesChanged(
void ServiceWorkerRegistrationHandle::OnRegistrationFailed(
ServiceWorkerRegistration* registration) {
DCHECK_EQ(registration->id(), registration_->id());
- ClearVersionAttributes();
+ ChangedVersionAttributesMask changed_mask(
+ ChangedVersionAttributesMask::INSTALLING_VERSION |
+ ChangedVersionAttributesMask::WAITING_VERSION |
+ ChangedVersionAttributesMask::ACTIVE_VERSION);
+ SetVersionAttributes(changed_mask, nullptr, nullptr, nullptr);
}
void ServiceWorkerRegistrationHandle::OnUpdateFound(
ServiceWorkerRegistration* registration) {
- if (!dispatcher_host_)
- return; // Could be NULL in some tests.
- dispatcher_host_->Send(new ServiceWorkerMsg_UpdateFound(
- kDocumentMainThreadId, GetObjectInfo()));
+ if (!provider_host_)
+ return; // Could be nullptr in some tests.
+ provider_host_->SendUpdateFoundMessage(handle_id_);
}
void ServiceWorkerRegistrationHandle::SetVersionAttributes(
+ ChangedVersionAttributesMask changed_mask,
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);
+ if (!provider_host_)
+ return; // Could be nullptr in some tests.
+ provider_host_->SendSetVersionAttributesMessage(handle_id_,
+ changed_mask,
+ installing_version,
+ waiting_version,
+ active_version);
}
} // 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
index 9439027041b..882c7ccb0c6 100644
--- a/chromium/content/browser/service_worker/service_worker_registration_handle.h
+++ b/chromium/content/browser/service_worker/service_worker_registration_handle.h
@@ -28,14 +28,11 @@ class ServiceWorkerRegistrationHandle
public:
CONTENT_EXPORT ServiceWorkerRegistrationHandle(
base::WeakPtr<ServiceWorkerContextCore> context,
- ServiceWorkerDispatcherHost* dispatcher_host,
- int provider_id,
+ base::WeakPtr<ServiceWorkerProviderHost> provider_host,
ServiceWorkerRegistration* registration);
virtual ~ServiceWorkerRegistrationHandle();
ServiceWorkerRegistrationObjectInfo GetObjectInfo();
- ServiceWorkerObjectInfo CreateServiceWorkerHandleAndPass(
- ServiceWorkerVersion* version);
bool HasNoRefCount() const { return ref_count_ <= 0; }
void IncrementRefCount();
@@ -56,25 +53,20 @@ class ServiceWorkerRegistrationHandle
void OnUpdateFound(ServiceWorkerRegistration* registration) override;
// Sets the corresponding version field to the given version or if the given
- // version is NULL, clears the field.
+ // version is nullptr, clears the field.
void SetVersionAttributes(
+ ChangedVersionAttributesMask changed_mask,
ServiceWorkerVersion* installing_version,
ServiceWorkerVersion* waiting_version,
ServiceWorkerVersion* active_version);
- // Clears all version fields.
- void ClearVersionAttributes();
-
base::WeakPtr<ServiceWorkerContextCore> context_;
- ServiceWorkerDispatcherHost* dispatcher_host_;
+ base::WeakPtr<ServiceWorkerProviderHost> provider_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);
};
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 e67b833826d..cce28d7d9e1 100644
--- a/chromium/content/browser/service_worker/service_worker_registration_status.cc
+++ b/chromium/content/browser/service_worker/service_worker_registration_status.cc
@@ -13,10 +13,14 @@ using blink::WebServiceWorkerError;
void GetServiceWorkerRegistrationStatusResponse(
ServiceWorkerStatusCode status,
+ const std::string& status_message,
blink::WebServiceWorkerError::ErrorType* error_type,
base::string16* message) {
*error_type = WebServiceWorkerError::ErrorTypeUnknown;
- *message = base::ASCIIToUTF16(ServiceWorkerStatusToString(status));
+ if (!status_message.empty())
+ *message = base::UTF8ToUTF16(status_message);
+ else
+ *message = base::ASCIIToUTF16(ServiceWorkerStatusToString(status));
switch (status) {
case SERVICE_WORKER_OK:
NOTREACHED() << "Calling this when status == OK is not allowed";
@@ -24,13 +28,11 @@ void GetServiceWorkerRegistrationStatusResponse(
case SERVICE_WORKER_ERROR_START_WORKER_FAILED:
case SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED:
+ case SERVICE_WORKER_ERROR_PROCESS_NOT_FOUND:
+ case SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED:
*error_type = WebServiceWorkerError::ErrorTypeInstall;
return;
- case SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED:
- *error_type = WebServiceWorkerError::ErrorTypeActivate;
- return;
-
case SERVICE_WORKER_ERROR_NOT_FOUND:
*error_type = WebServiceWorkerError::ErrorTypeNotFound;
return;
@@ -43,11 +45,22 @@ void GetServiceWorkerRegistrationStatusResponse(
*error_type = WebServiceWorkerError::ErrorTypeSecurity;
return;
+ case SERVICE_WORKER_ERROR_TIMEOUT:
+ *error_type = WebServiceWorkerError::ErrorTypeTimeout;
+ return;
+
case SERVICE_WORKER_ERROR_ABORT:
+ *error_type = WebServiceWorkerError::ErrorTypeAbort;
+ return;
+
+ case SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED:
case SERVICE_WORKER_ERROR_IPC_FAILED:
case SERVICE_WORKER_ERROR_FAILED:
- case SERVICE_WORKER_ERROR_PROCESS_NOT_FOUND:
case SERVICE_WORKER_ERROR_EXISTS:
+ case SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED:
+ case SERVICE_WORKER_ERROR_STATE:
+ case SERVICE_WORKER_ERROR_DISK_CACHE:
+ case SERVICE_WORKER_ERROR_MAX_VALUE:
// Unexpected, or should have bailed out before calling this, or we don't
// have a corresponding blink error code yet.
break; // Fall through to NOTREACHED().
diff --git a/chromium/content/browser/service_worker/service_worker_registration_status.h b/chromium/content/browser/service_worker/service_worker_registration_status.h
index 8cffd5628e9..46cf5ab83f0 100644
--- a/chromium/content/browser/service_worker/service_worker_registration_status.h
+++ b/chromium/content/browser/service_worker/service_worker_registration_status.h
@@ -14,6 +14,7 @@ namespace content {
// This should only be called for errors, where status != OK.
void GetServiceWorkerRegistrationStatusResponse(
ServiceWorkerStatusCode status,
+ const std::string& status_message,
blink::WebServiceWorkerError::ErrorType* error_type,
base::string16* message);
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 cea4b47734b..d61ec06a0cb 100644
--- a/chromium/content/browser/service_worker/service_worker_registration_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_registration_unittest.cc
@@ -28,7 +28,6 @@ class ServiceWorkerRegistrationTest : public testing::Test {
base::ThreadTaskRunnerHandle::Get()));
context_.reset(
new ServiceWorkerContextCore(base::FilePath(),
- base::ThreadTaskRunnerHandle::Get(),
database_task_manager.Pass(),
base::ThreadTaskRunnerHandle::Get(),
NULL,
@@ -65,11 +64,6 @@ class ServiceWorkerRegistrationTest : public testing::Test {
NOTREACHED();
}
- void OnRegistrationFinishedUninstalling(
- ServiceWorkerRegistration* registration) override {
- NOTREACHED();
- }
-
void OnUpdateFound(ServiceWorkerRegistration* registration) override {
NOTREACHED();
}
@@ -111,7 +105,7 @@ TEST_F(ServiceWorkerRegistrationTest, SetAndUnsetVersions) {
RegistrationListener listener;
registration->AddListener(&listener);
- registration->SetActiveVersion(version_1.get());
+ registration->SetActiveVersion(version_1);
EXPECT_EQ(version_1.get(), registration->active_version());
EXPECT_EQ(registration, listener.observed_registration_);
@@ -124,11 +118,9 @@ TEST_F(ServiceWorkerRegistrationTest, SetAndUnsetVersions) {
kInvalidServiceWorkerVersionId);
EXPECT_EQ(listener.observed_info_.waiting_version.version_id,
kInvalidServiceWorkerVersionId);
- EXPECT_EQ(listener.observed_info_.controlling_version.version_id,
- kInvalidServiceWorkerVersionId);
listener.Reset();
- registration->SetInstallingVersion(version_2.get());
+ registration->SetInstallingVersion(version_2);
EXPECT_EQ(version_2.get(), registration->installing_version());
EXPECT_EQ(ChangedVersionAttributesMask::INSTALLING_VERSION,
@@ -138,11 +130,9 @@ TEST_F(ServiceWorkerRegistrationTest, SetAndUnsetVersions) {
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());
+ registration->SetWaitingVersion(version_2);
EXPECT_EQ(version_2.get(), registration->waiting_version());
EXPECT_FALSE(registration->installing_version());
@@ -152,8 +142,6 @@ TEST_F(ServiceWorkerRegistrationTest, SetAndUnsetVersions) {
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());
@@ -166,24 +154,21 @@ TEST_F(ServiceWorkerRegistrationTest, SetAndUnsetVersions) {
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()));
+ new ServiceWorkerRegistrationHandle(
+ context_ptr_,
+ base::WeakPtr<ServiceWorkerProviderHost>(),
+ registration.get()));
registration->NotifyRegistrationFailed();
// Don't crash when handle gets destructed.
}
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 6c871e6cd55..c70b3fd9b9e 100644
--- a/chromium/content/browser/service_worker/service_worker_request_handler.cc
+++ b/chromium/content/browser/service_worker/service_worker_request_handler.cc
@@ -48,13 +48,6 @@ class ServiceWorkerRequestInterceptor
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerRequestInterceptor);
};
-// 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
void ServiceWorkerRequestHandler::InitializeHandler(
@@ -70,10 +63,8 @@ void ServiceWorkerRequestHandler::InitializeHandler(
RequestContextType request_context_type,
RequestContextFrameType frame_type,
scoped_refptr<ResourceRequestBody> body) {
- if (!request->url().SchemeIsHTTPOrHTTPS() ||
- !IsMethodSupportedForServiceWorker(request->method())) {
+ if (!request->url().SchemeIsHTTPOrHTTPS())
return;
- }
if (!context_wrapper || !context_wrapper->context() ||
provider_id == kInvalidServiceWorkerProviderId) {
@@ -129,6 +120,39 @@ bool ServiceWorkerRequestHandler::IsControlledByServiceWorker(
handler->provider_host_->running_hosted_version();
}
+void ServiceWorkerRequestHandler::PrepareForCrossSiteTransfer(
+ int old_process_id) {
+ if (!provider_host_ || !context_)
+ return;
+ old_process_id_ = old_process_id;
+ old_provider_id_ = provider_host_->provider_id();
+ host_for_cross_site_transfer_ =
+ context_->TransferProviderHostOut(old_process_id,
+ provider_host_->provider_id());
+ DCHECK_EQ(provider_host_.get(), host_for_cross_site_transfer_.get());
+}
+
+void ServiceWorkerRequestHandler::CompleteCrossSiteTransfer(
+ int new_process_id, int new_provider_id) {
+ if (!host_for_cross_site_transfer_.get() || !context_)
+ return;
+ DCHECK_EQ(provider_host_.get(), host_for_cross_site_transfer_.get());
+ context_->TransferProviderHostIn(
+ new_process_id,
+ new_provider_id,
+ host_for_cross_site_transfer_.Pass());
+ DCHECK_EQ(provider_host_->provider_id(), new_provider_id);
+}
+
+void ServiceWorkerRequestHandler::MaybeCompleteCrossSiteTransferInOldProcess(
+ int old_process_id) {
+ if (!host_for_cross_site_transfer_.get() || !context_ ||
+ old_process_id_ != old_process_id) {
+ return;
+ }
+ CompleteCrossSiteTransfer(old_process_id_, old_provider_id_);
+}
+
ServiceWorkerRequestHandler::~ServiceWorkerRequestHandler() {
}
@@ -140,7 +164,9 @@ ServiceWorkerRequestHandler::ServiceWorkerRequestHandler(
: context_(context),
provider_host_(provider_host),
blob_storage_context_(blob_storage_context),
- resource_type_(resource_type) {
+ resource_type_(resource_type),
+ old_process_id_(0),
+ old_provider_id_(kInvalidServiceWorkerProviderId) {
}
} // namespace content
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 91afd2688e8..59bfb1c470d 100644
--- a/chromium/content/browser/service_worker/service_worker_request_handler.h
+++ b/chromium/content/browser/service_worker/service_worker_request_handler.h
@@ -93,6 +93,15 @@ class CONTENT_EXPORT ServiceWorkerRequestHandler
base::TimeTicks* fetch_ready_time,
base::TimeTicks* fetch_end_time) const = 0;
+ // Methods to support cross site navigations.
+ void PrepareForCrossSiteTransfer(int old_process_id);
+ void CompleteCrossSiteTransfer(int new_process_id,
+ int new_provider_id);
+ void MaybeCompleteCrossSiteTransferInOldProcess(
+ int old_process_id);
+
+ ServiceWorkerContextCore* context() const { return context_.get(); }
+
protected:
ServiceWorkerRequestHandler(
base::WeakPtr<ServiceWorkerContextCore> context,
@@ -106,6 +115,10 @@ class CONTENT_EXPORT ServiceWorkerRequestHandler
ResourceType resource_type_;
private:
+ scoped_ptr<ServiceWorkerProviderHost> host_for_cross_site_transfer_;
+ int old_process_id_;
+ int old_provider_id_;
+
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
index fe5483de70e..4d12e994a37 100644
--- a/chromium/content/browser/service_worker/service_worker_request_handler_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_request_handler_unittest.cc
@@ -38,7 +38,8 @@ class ServiceWorkerRequestHandlerTest : public testing::Test {
: browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
void SetUp() override {
- helper_.reset(new EmbeddedWorkerTestHelper(kMockRenderProcessId));
+ helper_.reset(
+ new EmbeddedWorkerTestHelper(base::FilePath(), kMockRenderProcessId));
// A new unstored registration/version.
registration_ = new ServiceWorkerRegistration(
@@ -50,7 +51,9 @@ class ServiceWorkerRequestHandlerTest : public testing::Test {
// An empty host.
scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
- kMockRenderProcessId, kMockProviderId, context()->AsWeakPtr(), NULL));
+ kMockRenderProcessId, MSG_ROUTING_NONE, kMockProviderId,
+ SERVICE_WORKER_PROVIDER_FOR_WINDOW, context()->AsWeakPtr(), nullptr));
+ host->SetDocumentUrl(GURL("http://host/scope/"));
provider_host_ = host->AsWeakPtr();
context()->AddProviderHost(host.Pass());
@@ -58,18 +61,19 @@ class ServiceWorkerRequestHandlerTest : public testing::Test {
base::RunLoop().RunUntilIdle();
version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
- registration_->SetActiveVersion(version_.get());
+ registration_->SetActiveVersion(version_);
context()->storage()->StoreRegistration(
registration_.get(),
version_.get(),
base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
- provider_host_->AssociateRegistration(registration_.get());
+ provider_host_->AssociateRegistration(registration_.get(),
+ false /* notify_controllerchange */);
base::RunLoop().RunUntilIdle();
}
void TearDown() override {
- version_ = NULL;
- registration_ = NULL;
+ version_ = nullptr;
+ registration_ = nullptr;
helper_.reset();
}
@@ -84,7 +88,7 @@ class ServiceWorkerRequestHandlerTest : public testing::Test {
ResourceType resource_type) {
const GURL kDocUrl(url);
scoped_ptr<net::URLRequest> request = url_request_context_.CreateRequest(
- kDocUrl, net::DEFAULT_PRIORITY, &url_request_delegate_, NULL);
+ kDocUrl, net::DEFAULT_PRIORITY, &url_request_delegate_);
request->set_method(method);
ServiceWorkerRequestHandler::InitializeHandler(
request.get(),
@@ -98,8 +102,8 @@ class ServiceWorkerRequestHandlerTest : public testing::Test {
resource_type,
REQUEST_CONTEXT_TYPE_HYPERLINK,
REQUEST_CONTEXT_FRAME_TYPE_TOP_LEVEL,
- NULL);
- return ServiceWorkerRequestHandler::GetHandler(request.get()) != NULL;
+ nullptr);
+ return ServiceWorkerRequestHandler::GetHandler(request.get()) != nullptr;
}
protected:
@@ -121,9 +125,9 @@ TEST_F(ServiceWorkerRequestHandlerTest, InitializeHandler) {
EXPECT_FALSE(InitializeHandlerCheck(
"ftp://host/scope/doc", "GET", false, RESOURCE_TYPE_MAIN_FRAME));
- EXPECT_FALSE(InitializeHandlerCheck(
+ EXPECT_TRUE(InitializeHandlerCheck(
"http://host/scope/doc", "OPTIONS", false, RESOURCE_TYPE_MAIN_FRAME));
- EXPECT_FALSE(InitializeHandlerCheck(
+ EXPECT_TRUE(InitializeHandlerCheck(
"https://host/scope/doc", "OPTIONS", false, RESOURCE_TYPE_MAIN_FRAME));
provider_host_->SetDocumentUrl(GURL(""));
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 062ae159a2a..16931391663 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
@@ -6,17 +6,19 @@
#include "base/logging.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_storage.h"
#include "content/browser/service_worker/service_worker_version.h"
#include "content/common/service_worker/service_worker_types.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
namespace content {
ServiceWorkerScriptCacheMap::ServiceWorkerScriptCacheMap(
ServiceWorkerVersion* owner,
base::WeakPtr<ServiceWorkerContextCore> context)
- : owner_(owner),
- context_(context) {
+ : owner_(owner), context_(context), weak_factory_(this) {
}
ServiceWorkerScriptCacheMap::~ServiceWorkerScriptCacheMap() {
@@ -40,7 +42,10 @@ void ServiceWorkerScriptCacheMap::NotifyStartedCaching(
const GURL& url, int64 resource_id) {
DCHECK_EQ(kInvalidServiceWorkerResponseId, LookupResourceId(url));
DCHECK(owner_->status() == ServiceWorkerVersion::NEW ||
- owner_->status() == ServiceWorkerVersion::INSTALLING);
+ owner_->status() == ServiceWorkerVersion::INSTALLING)
+ << owner_->status();
+ if (!context_)
+ return; // Our storage has been wiped via DeleteAndStartOver.
resource_map_[url] =
ServiceWorkerDatabase::ResourceRecord(resource_id, url, -1);
context_->storage()->StoreUncommittedResponseId(resource_id);
@@ -49,15 +54,21 @@ void ServiceWorkerScriptCacheMap::NotifyStartedCaching(
void ServiceWorkerScriptCacheMap::NotifyFinishedCaching(
const GURL& url,
int64 size_bytes,
- const net::URLRequestStatus& status) {
+ const net::URLRequestStatus& status,
+ const std::string& status_message) {
DCHECK_NE(kInvalidServiceWorkerResponseId, LookupResourceId(url));
DCHECK(owner_->status() == ServiceWorkerVersion::NEW ||
- owner_->status() == ServiceWorkerVersion::INSTALLING);
+ owner_->status() == ServiceWorkerVersion::INSTALLING ||
+ owner_->status() == ServiceWorkerVersion::REDUNDANT);
+ if (!context_)
+ return; // Our storage has been wiped via DeleteAndStartOver.
if (!status.is_success()) {
context_->storage()->DoomUncommittedResponse(LookupResourceId(url));
resource_map_.erase(url);
- if (owner_->script_url() == url)
+ if (owner_->script_url() == url) {
main_script_status_ = status;
+ main_script_status_message_ = status_message;
+ }
} else {
resource_map_[url].size_bytes = size_bytes;
}
@@ -83,4 +94,40 @@ void ServiceWorkerScriptCacheMap::SetResources(
}
}
+void ServiceWorkerScriptCacheMap::WriteMetadata(
+ const GURL& url,
+ const std::vector<char>& data,
+ const net::CompletionCallback& callback) {
+ ResourceMap::iterator found = resource_map_.find(url);
+ if (found == resource_map_.end() ||
+ found->second.resource_id == kInvalidServiceWorkerResponseId) {
+ callback.Run(net::ERR_FILE_NOT_FOUND);
+ return;
+ }
+ scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(data.size()));
+ if (data.size())
+ memmove(buffer->data(), &data[0], data.size());
+ scoped_ptr<ServiceWorkerResponseMetadataWriter> writer;
+ writer = context_->storage()->CreateResponseMetadataWriter(
+ found->second.resource_id);
+ ServiceWorkerResponseMetadataWriter* raw_writer = writer.get();
+ raw_writer->WriteMetadata(
+ buffer.get(), data.size(),
+ base::Bind(&ServiceWorkerScriptCacheMap::OnMetadataWritten,
+ weak_factory_.GetWeakPtr(), Passed(&writer), callback));
+}
+
+void ServiceWorkerScriptCacheMap::ClearMetadata(
+ const GURL& url,
+ const net::CompletionCallback& callback) {
+ WriteMetadata(url, std::vector<char>(), callback);
+}
+
+void ServiceWorkerScriptCacheMap::OnMetadataWritten(
+ scoped_ptr<ServiceWorkerResponseMetadataWriter> writer,
+ const net::CompletionCallback& callback,
+ int result) {
+ callback.Run(result);
+}
+
} // namespace content
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 de814c210b1..7d3366aa943 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
@@ -12,6 +12,7 @@
#include "base/memory/weak_ptr.h"
#include "content/browser/service_worker/service_worker_database.h"
#include "content/common/content_export.h"
+#include "net/base/completion_callback.h"
#include "net/url_request/url_request_status.h"
class GURL;
@@ -20,6 +21,7 @@ namespace content {
class ServiceWorkerContextCore;
class ServiceWorkerVersion;
+class ServiceWorkerResponseMetadataWriter;
// Class that maintains the mapping between urls and a resource id
// for a particular version's implicit script resources.
@@ -35,7 +37,8 @@ class CONTENT_EXPORT ServiceWorkerScriptCacheMap {
void NotifyStartedCaching(const GURL& url, int64 resource_id);
void NotifyFinishedCaching(const GURL& url,
int64 size_bytes,
- const net::URLRequestStatus& status);
+ const net::URLRequestStatus& status,
+ const std::string& status_message);
// Used to retrieve the results of the initial run of a new version.
void GetResources(
@@ -45,12 +48,23 @@ class CONTENT_EXPORT ServiceWorkerScriptCacheMap {
void SetResources(
const std::vector<ServiceWorkerDatabase::ResourceRecord>& resources);
+ // Writes the metadata of the existing script.
+ void WriteMetadata(const GURL& url,
+ const std::vector<char>& data,
+ const net::CompletionCallback& callback);
+ // Clears the metadata of the existing script.
+ void ClearMetadata(const GURL& url, const net::CompletionCallback& callback);
+
size_t size() const { return resource_map_.size(); }
const net::URLRequestStatus& main_script_status() const {
return main_script_status_;
}
+ const std::string& main_script_status_message() const {
+ return main_script_status_message_;
+ }
+
private:
typedef std::map<GURL, ServiceWorkerDatabase::ResourceRecord> ResourceMap;
@@ -61,10 +75,17 @@ class CONTENT_EXPORT ServiceWorkerScriptCacheMap {
base::WeakPtr<ServiceWorkerContextCore> context);
~ServiceWorkerScriptCacheMap();
+ void OnMetadataWritten(scoped_ptr<ServiceWorkerResponseMetadataWriter> writer,
+ const net::CompletionCallback& callback,
+ int result);
+
ServiceWorkerVersion* owner_;
base::WeakPtr<ServiceWorkerContextCore> context_;
ResourceMap resource_map_;
net::URLRequestStatus main_script_status_;
+ std::string main_script_status_message_;
+
+ base::WeakPtrFactory<ServiceWorkerScriptCacheMap> weak_factory_;
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 0a06823ca41..c5c61577b09 100644
--- a/chromium/content/browser/service_worker/service_worker_storage.cc
+++ b/chromium/content/browser/service_worker/service_worker_storage.cc
@@ -4,15 +4,14 @@
#include "content/browser/service_worker/service_worker_storage.h"
-#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 "base/thread_task_runner_handle.h"
+#include "base/trace_event/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_info.h"
@@ -34,13 +33,18 @@ namespace {
void RunSoon(const tracked_objects::Location& from_here,
const base::Closure& closure) {
- base::MessageLoop::current()->PostTask(from_here, closure);
+ base::ThreadTaskRunnerHandle::Get()->PostTask(from_here, closure);
}
void CompleteFindNow(
const scoped_refptr<ServiceWorkerRegistration>& registration,
ServiceWorkerStatusCode status,
const ServiceWorkerStorage::FindRegistrationCallback& callback) {
+ if (registration && registration->is_deleted()) {
+ // It's past the point of no return and no longer findable.
+ callback.Run(SERVICE_WORKER_ERROR_NOT_FOUND, nullptr);
+ return;
+ }
callback.Run(status, registration);
}
@@ -49,7 +53,8 @@ void CompleteFindSoon(
const scoped_refptr<ServiceWorkerRegistration>& registration,
ServiceWorkerStatusCode status,
const ServiceWorkerStorage::FindRegistrationCallback& callback) {
- RunSoon(from_here, base::Bind(callback, status, registration));
+ RunSoon(from_here,
+ base::Bind(&CompleteFindNow, registration, status, callback));
}
const base::FilePath::CharType kDatabaseName[] =
@@ -305,7 +310,7 @@ void ServiceWorkerStorage::FindRegistrationForDocument(
base::Bind(
&FindForDocumentInDB,
database_.get(),
- base::MessageLoopProxy::current(),
+ base::ThreadTaskRunnerHandle::Get(),
document_url,
base::Bind(&ServiceWorkerStorage::DidFindRegistrationForDocument,
weak_factory_.GetWeakPtr(),
@@ -347,10 +352,12 @@ void ServiceWorkerStorage::FindRegistrationForPattern(
base::Bind(
&FindForPatternInDB,
database_.get(),
- base::MessageLoopProxy::current(),
+ base::ThreadTaskRunnerHandle::Get(),
scope,
base::Bind(&ServiceWorkerStorage::DidFindRegistrationForPattern,
- weak_factory_.GetWeakPtr(), scope, callback)));
+ weak_factory_.GetWeakPtr(),
+ scope,
+ callback)));
}
ServiceWorkerRegistration* ServiceWorkerStorage::GetUninstallingRegistration(
@@ -408,14 +415,80 @@ void ServiceWorkerStorage::FindRegistrationForId(
FROM_HERE,
base::Bind(&FindForIdInDB,
database_.get(),
- base::MessageLoopProxy::current(),
- registration_id, origin,
+ base::ThreadTaskRunnerHandle::Get(),
+ registration_id,
+ origin,
+ base::Bind(&ServiceWorkerStorage::DidFindRegistrationForId,
+ weak_factory_.GetWeakPtr(),
+ callback)));
+}
+
+void ServiceWorkerStorage::FindRegistrationForIdOnly(
+ int64 registration_id,
+ const FindRegistrationCallback& callback) {
+ if (!LazyInitialize(
+ base::Bind(&ServiceWorkerStorage::FindRegistrationForIdOnly,
+ weak_factory_.GetWeakPtr(), registration_id, callback))) {
+ if (state_ != INITIALIZING || !context_) {
+ CompleteFindNow(nullptr, SERVICE_WORKER_ERROR_FAILED, callback);
+ }
+ return;
+ }
+ DCHECK_EQ(INITIALIZED, state_);
+
+ scoped_refptr<ServiceWorkerRegistration> registration =
+ context_->GetLiveRegistration(registration_id);
+ if (registration) {
+ // Delegate to FindRegistrationForId to make sure the same subset of live
+ // registrations is returned.
+ // TODO(mek): CompleteFindNow should really do all the required checks, so
+ // calling that directly here should be enough.
+ FindRegistrationForId(registration_id, registration->pattern().GetOrigin(),
+ callback);
+ return;
+ }
+
+ database_task_manager_->GetTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&FindForIdOnlyInDB,
+ database_.get(),
+ base::ThreadTaskRunnerHandle::Get(),
+ registration_id,
base::Bind(&ServiceWorkerStorage::DidFindRegistrationForId,
- weak_factory_.GetWeakPtr(), callback)));
+ weak_factory_.GetWeakPtr(),
+ callback)));
+}
+
+void ServiceWorkerStorage::GetRegistrationsForOrigin(
+ const GURL& origin, const GetRegistrationsInfosCallback& callback) {
+ if (!LazyInitialize(base::Bind(
+ &ServiceWorkerStorage::GetRegistrationsForOrigin,
+ weak_factory_.GetWeakPtr(), origin, callback))) {
+ if (state_ != INITIALIZING || !context_) {
+ RunSoon(FROM_HERE, base::Bind(
+ callback, std::vector<ServiceWorkerRegistrationInfo>()));
+ }
+ return;
+ }
+ DCHECK_EQ(INITIALIZED, state_);
+
+ RegistrationList* registrations = new RegistrationList;
+ PostTaskAndReplyWithResult(
+ database_task_manager_->GetTaskRunner(),
+ FROM_HERE,
+ base::Bind(&ServiceWorkerDatabase::GetRegistrationsForOrigin,
+ base::Unretained(database_.get()),
+ origin,
+ base::Unretained(registrations)),
+ base::Bind(&ServiceWorkerStorage::DidGetRegistrations,
+ weak_factory_.GetWeakPtr(),
+ callback,
+ base::Owned(registrations),
+ origin));
}
void ServiceWorkerStorage::GetAllRegistrations(
- const GetAllRegistrationInfosCallback& callback) {
+ const GetRegistrationsInfosCallback& callback) {
if (!LazyInitialize(base::Bind(
&ServiceWorkerStorage::GetAllRegistrations,
weak_factory_.GetWeakPtr(), callback))) {
@@ -434,10 +507,11 @@ void ServiceWorkerStorage::GetAllRegistrations(
base::Bind(&ServiceWorkerDatabase::GetAllRegistrations,
base::Unretained(database_.get()),
base::Unretained(registrations)),
- base::Bind(&ServiceWorkerStorage::DidGetAllRegistrations,
+ base::Bind(&ServiceWorkerStorage::DidGetRegistrations,
weak_factory_.GetWeakPtr(),
callback,
- base::Owned(registrations)));
+ base::Owned(registrations),
+ GURL()));
}
void ServiceWorkerStorage::StoreRegistration(
@@ -465,6 +539,11 @@ void ServiceWorkerStorage::StoreRegistration(
ResourceList resources;
version->script_cache_map()->GetResources(&resources);
+ if (resources.empty()) {
+ RunSoon(FROM_HERE, base::Bind(callback, SERVICE_WORKER_ERROR_FAILED));
+ return;
+ }
+
uint64 resources_total_size_bytes = 0;
for (const auto& resource : resources) {
resources_total_size_bytes += resource.size_bytes;
@@ -478,7 +557,7 @@ void ServiceWorkerStorage::StoreRegistration(
FROM_HERE,
base::Bind(&WriteRegistrationInDB,
database_.get(),
- base::MessageLoopProxy::current(),
+ base::ThreadTaskRunnerHandle::Get(),
data,
resources,
base::Bind(&ServiceWorkerStorage::DidStoreRegistration,
@@ -552,10 +631,12 @@ void ServiceWorkerStorage::DeleteRegistration(
FROM_HERE,
base::Bind(&DeleteRegistrationFromDB,
database_.get(),
- base::MessageLoopProxy::current(),
- registration_id, origin,
+ base::ThreadTaskRunnerHandle::Get(),
+ registration_id,
+ origin,
base::Bind(&ServiceWorkerStorage::DidDeleteRegistration,
- weak_factory_.GetWeakPtr(), params)));
+ weak_factory_.GetWeakPtr(),
+ params)));
// The registration should no longer be findable.
pending_deletions_.insert(registration_id);
@@ -577,6 +658,12 @@ ServiceWorkerStorage::CreateResponseWriter(int64 response_id) {
new ServiceWorkerResponseWriter(response_id, disk_cache()));
}
+scoped_ptr<ServiceWorkerResponseMetadataWriter>
+ServiceWorkerStorage::CreateResponseMetadataWriter(int64 response_id) {
+ return make_scoped_ptr(
+ new ServiceWorkerResponseMetadataWriter(response_id, disk_cache()));
+}
+
void ServiceWorkerStorage::StoreUncommittedResponseId(int64 id) {
DCHECK_NE(kInvalidServiceWorkerResponseId, id);
DCHECK_EQ(INITIALIZED, state_);
@@ -615,6 +702,124 @@ void ServiceWorkerStorage::CompareScriptResources(
comparer->Start(); // It deletes itself when done.
}
+void ServiceWorkerStorage::StoreUserData(
+ int64 registration_id,
+ const GURL& origin,
+ const std::string& key,
+ const std::string& data,
+ const StatusCallback& callback) {
+ DCHECK(state_ == INITIALIZED || state_ == DISABLED) << state_;
+ if (IsDisabled() || !context_) {
+ RunSoon(FROM_HERE, base::Bind(callback, SERVICE_WORKER_ERROR_FAILED));
+ return;
+ }
+
+ if (registration_id == kInvalidServiceWorkerRegistrationId || key.empty()) {
+ RunSoon(FROM_HERE, base::Bind(callback, SERVICE_WORKER_ERROR_FAILED));
+ return;
+ }
+
+ PostTaskAndReplyWithResult(
+ database_task_manager_->GetTaskRunner(),
+ FROM_HERE,
+ base::Bind(&ServiceWorkerDatabase::WriteUserData,
+ base::Unretained(database_.get()),
+ registration_id, origin, key, data),
+ base::Bind(&ServiceWorkerStorage::DidStoreUserData,
+ weak_factory_.GetWeakPtr(),
+ callback));
+}
+
+void ServiceWorkerStorage::GetUserData(
+ int64 registration_id,
+ const std::string& key,
+ const GetUserDataCallback& callback) {
+ DCHECK(state_ == INITIALIZED || state_ == DISABLED) << state_;
+ if (IsDisabled() || !context_) {
+ RunSoon(FROM_HERE,
+ base::Bind(callback, std::string(), SERVICE_WORKER_ERROR_FAILED));
+ return;
+ }
+
+ if (registration_id == kInvalidServiceWorkerRegistrationId || key.empty()) {
+ RunSoon(FROM_HERE,
+ base::Bind(callback, std::string(), SERVICE_WORKER_ERROR_FAILED));
+ return;
+ }
+
+ database_task_manager_->GetTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&ServiceWorkerStorage::GetUserDataInDB,
+ database_.get(),
+ base::ThreadTaskRunnerHandle::Get(),
+ registration_id,
+ key,
+ base::Bind(&ServiceWorkerStorage::DidGetUserData,
+ weak_factory_.GetWeakPtr(),
+ callback)));
+}
+
+void ServiceWorkerStorage::ClearUserData(
+ int64 registration_id,
+ const std::string& key,
+ const StatusCallback& callback) {
+ DCHECK(state_ == INITIALIZED || state_ == DISABLED) << state_;
+ if (IsDisabled() || !context_) {
+ RunSoon(FROM_HERE, base::Bind(callback, SERVICE_WORKER_ERROR_FAILED));
+ return;
+ }
+
+ if (registration_id == kInvalidServiceWorkerRegistrationId || key.empty()) {
+ RunSoon(FROM_HERE, base::Bind(callback, SERVICE_WORKER_ERROR_FAILED));
+ return;
+ }
+
+ PostTaskAndReplyWithResult(
+ database_task_manager_->GetTaskRunner(),
+ FROM_HERE,
+ base::Bind(&ServiceWorkerDatabase::DeleteUserData,
+ base::Unretained(database_.get()),
+ registration_id, key),
+ base::Bind(&ServiceWorkerStorage::DidDeleteUserData,
+ weak_factory_.GetWeakPtr(),
+ callback));
+}
+
+void ServiceWorkerStorage::GetUserDataForAllRegistrations(
+ const std::string& key,
+ const ServiceWorkerStorage::GetUserDataForAllRegistrationsCallback&
+ callback) {
+ if (!LazyInitialize(
+ base::Bind(&ServiceWorkerStorage::GetUserDataForAllRegistrations,
+ weak_factory_.GetWeakPtr(), key, callback))) {
+ if (state_ != INITIALIZING || !context_) {
+ RunSoon(FROM_HERE,
+ base::Bind(callback, std::vector<std::pair<int64, std::string>>(),
+ SERVICE_WORKER_ERROR_FAILED));
+ }
+ return;
+ }
+ DCHECK_EQ(INITIALIZED, state_);
+
+ if (key.empty()) {
+ RunSoon(FROM_HERE,
+ base::Bind(callback, std::vector<std::pair<int64, std::string>>(),
+ SERVICE_WORKER_ERROR_FAILED));
+ return;
+ }
+
+ database_task_manager_->GetTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &ServiceWorkerStorage::GetUserDataForAllRegistrationsInDB,
+ database_.get(),
+ base::ThreadTaskRunnerHandle::Get(),
+ key,
+ base::Bind(&ServiceWorkerStorage::DidGetUserDataForAllRegistrations,
+ weak_factory_.GetWeakPtr(),
+ callback)));
+}
+
void ServiceWorkerStorage::DeleteAndStartOver(const StatusCallback& callback) {
Disable();
@@ -766,7 +971,7 @@ bool ServiceWorkerStorage::LazyInitialize(const base::Closure& callback) {
FROM_HERE,
base::Bind(&ReadInitialDataFromDB,
database_.get(),
- base::MessageLoopProxy::current(),
+ base::ThreadTaskRunnerHandle::Get(),
base::Bind(&ServiceWorkerStorage::DidReadInitialData,
weak_factory_.GetWeakPtr())));
return false;
@@ -894,19 +1099,16 @@ void ServiceWorkerStorage::ReturnFoundRegistration(
const FindRegistrationCallback& callback,
const ServiceWorkerDatabase::RegistrationData& data,
const ResourceList& resources) {
+ DCHECK(!resources.empty());
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);
+ CompleteFindNow(registration, SERVICE_WORKER_OK, callback);
}
-void ServiceWorkerStorage::DidGetAllRegistrations(
- const GetAllRegistrationInfosCallback& callback,
+void ServiceWorkerStorage::DidGetRegistrations(
+ const GetRegistrationsInfosCallback& callback,
RegistrationList* registrations,
+ const GURL& origin_filter,
ServiceWorkerDatabase::Status status) {
DCHECK(registrations);
if (status != ServiceWorkerDatabase::STATUS_OK &&
@@ -948,10 +1150,14 @@ void ServiceWorkerStorage::DidGetAllRegistrations(
if (registration_data.is_active) {
info.active_version.status = ServiceWorkerVersion::ACTIVATED;
+ info.active_version.script_url = registration_data.script;
info.active_version.version_id = registration_data.version_id;
+ info.active_version.registration_id = registration_data.registration_id;
} else {
info.waiting_version.status = ServiceWorkerVersion::INSTALLED;
+ info.waiting_version.script_url = registration_data.script;
info.waiting_version.version_id = registration_data.version_id;
+ info.waiting_version.registration_id = registration_data.registration_id;
}
infos.push_back(info);
}
@@ -960,8 +1166,11 @@ void ServiceWorkerStorage::DidGetAllRegistrations(
for (RegistrationRefsById::const_iterator it =
installing_registrations_.begin();
it != installing_registrations_.end(); ++it) {
- if (pushed_registrations.insert(it->first).second)
+ if ((!origin_filter.is_valid() ||
+ it->second->pattern().GetOrigin() == origin_filter) &&
+ pushed_registrations.insert(it->first).second) {
infos.push_back(it->second->GetInfo());
+ }
}
callback.Run(infos);
@@ -1039,6 +1248,47 @@ void ServiceWorkerStorage::DidDeleteRegistration(
StartPurgingResources(newly_purgeable_resources);
}
+void ServiceWorkerStorage::DidStoreUserData(
+ const StatusCallback& callback,
+ ServiceWorkerDatabase::Status status) {
+ // |status| can be NOT_FOUND when the associated registration did not exist in
+ // the database. In the case, we don't have to schedule the corruption
+ // recovery.
+ if (status != ServiceWorkerDatabase::STATUS_OK &&
+ status != ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND) {
+ ScheduleDeleteAndStartOver();
+ }
+ callback.Run(DatabaseStatusToStatusCode(status));
+}
+
+void ServiceWorkerStorage::DidGetUserData(
+ const GetUserDataCallback& callback,
+ const std::string& data,
+ ServiceWorkerDatabase::Status status) {
+ if (status != ServiceWorkerDatabase::STATUS_OK &&
+ status != ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND) {
+ ScheduleDeleteAndStartOver();
+ }
+ callback.Run(data, DatabaseStatusToStatusCode(status));
+}
+
+void ServiceWorkerStorage::DidDeleteUserData(
+ const StatusCallback& callback,
+ ServiceWorkerDatabase::Status status) {
+ if (status != ServiceWorkerDatabase::STATUS_OK)
+ ScheduleDeleteAndStartOver();
+ callback.Run(DatabaseStatusToStatusCode(status));
+}
+
+void ServiceWorkerStorage::DidGetUserDataForAllRegistrations(
+ const GetUserDataForAllRegistrationsCallback& callback,
+ const std::vector<std::pair<int64, std::string>>& user_data,
+ ServiceWorkerDatabase::Status status) {
+ if (status != ServiceWorkerDatabase::STATUS_OK)
+ ScheduleDeleteAndStartOver();
+ callback.Run(user_data, DatabaseStatusToStatusCode(status));
+}
+
scoped_refptr<ServiceWorkerRegistration>
ServiceWorkerStorage::GetOrCreateRegistration(
const ServiceWorkerDatabase::RegistrationData& data,
@@ -1067,9 +1317,9 @@ ServiceWorkerStorage::GetOrCreateRegistration(
}
if (version->status() == ServiceWorkerVersion::ACTIVATED)
- registration->SetActiveVersion(version.get());
+ registration->SetActiveVersion(version);
else if (version->status() == ServiceWorkerVersion::INSTALLED)
- registration->SetWaitingVersion(version.get());
+ registration->SetWaitingVersion(version);
else
NOTREACHED();
@@ -1213,7 +1463,7 @@ void ServiceWorkerStorage::DeleteStaleResources() {
FROM_HERE,
base::Bind(&ServiceWorkerStorage::CollectStaleResourcesFromDB,
database_.get(),
- base::MessageLoopProxy::current(),
+ base::ThreadTaskRunnerHandle::Get(),
base::Bind(&ServiceWorkerStorage::DidCollectStaleResources,
weak_factory_.GetWeakPtr())));
}
@@ -1221,9 +1471,11 @@ void ServiceWorkerStorage::DeleteStaleResources() {
void ServiceWorkerStorage::DidCollectStaleResources(
const std::vector<int64>& stale_resource_ids,
ServiceWorkerDatabase::Status status) {
- DCHECK_EQ(ServiceWorkerDatabase::STATUS_OK, status);
- if (status != ServiceWorkerDatabase::STATUS_OK)
+ if (status != ServiceWorkerDatabase::STATUS_OK) {
+ DCHECK_NE(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, status);
+ ScheduleDeleteAndStartOver();
return;
+ }
StartPurgingResources(stale_resource_ids);
}
@@ -1452,6 +1704,50 @@ void ServiceWorkerStorage::FindForIdInDB(
FROM_HERE, base::Bind(callback, data, resources, status));
}
+void ServiceWorkerStorage::FindForIdOnlyInDB(
+ ServiceWorkerDatabase* database,
+ scoped_refptr<base::SequencedTaskRunner> original_task_runner,
+ int64 registration_id,
+ const FindInDBCallback& callback) {
+ GURL origin;
+ ServiceWorkerDatabase::Status status =
+ database->ReadRegistrationOrigin(registration_id, &origin);
+ if (status != ServiceWorkerDatabase::STATUS_OK) {
+ original_task_runner->PostTask(
+ FROM_HERE,
+ base::Bind(callback, ServiceWorkerDatabase::RegistrationData(),
+ ResourceList(), status));
+ return;
+ }
+ FindForIdInDB(database, original_task_runner, registration_id, origin,
+ callback);
+}
+
+void ServiceWorkerStorage::GetUserDataInDB(
+ ServiceWorkerDatabase* database,
+ scoped_refptr<base::SequencedTaskRunner> original_task_runner,
+ int64 registration_id,
+ const std::string& key,
+ const GetUserDataInDBCallback& callback) {
+ std::string data;
+ ServiceWorkerDatabase::Status status =
+ database->ReadUserData(registration_id, key, &data);
+ original_task_runner->PostTask(
+ FROM_HERE, base::Bind(callback, data, status));
+}
+
+void ServiceWorkerStorage::GetUserDataForAllRegistrationsInDB(
+ ServiceWorkerDatabase* database,
+ scoped_refptr<base::SequencedTaskRunner> original_task_runner,
+ const std::string& key,
+ const GetUserDataForAllRegistrationsInDBCallback& callback) {
+ std::vector<std::pair<int64, std::string>> user_data;
+ ServiceWorkerDatabase::Status status =
+ database->ReadUserDataForAllRegistrations(key, &user_data);
+ original_task_runner->PostTask(FROM_HERE,
+ base::Bind(callback, user_data, status));
+}
+
void ServiceWorkerStorage::DeleteAllDataForOriginsFromDB(
ServiceWorkerDatabase* database,
const std::set<GURL>& origins) {
@@ -1486,6 +1782,8 @@ void ServiceWorkerStorage::DidDeleteDatabase(
// Give up the corruption recovery until the browser restarts.
LOG(ERROR) << "Failed to delete the database: "
<< ServiceWorkerDatabase::StatusToString(status);
+ ServiceWorkerMetrics::RecordDeleteAndStartOverResult(
+ ServiceWorkerMetrics::DELETE_DATABASE_ERROR);
callback.Run(DatabaseStatusToStatusCode(status));
return;
}
@@ -1496,12 +1794,10 @@ void ServiceWorkerStorage::DidDeleteDatabase(
// 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,
+ disk_cache_thread_.get(), FROM_HERE,
base::Bind(&base::DeleteFile, GetDiskCachePath(), true),
base::Bind(&ServiceWorkerStorage::DidDeleteDiskCache,
- weak_factory_.GetWeakPtr(),
- callback));
+ weak_factory_.GetWeakPtr(), callback));
}
void ServiceWorkerStorage::DidDeleteDiskCache(
@@ -1510,10 +1806,14 @@ void ServiceWorkerStorage::DidDeleteDiskCache(
if (!result) {
// Give up the corruption recovery until the browser restarts.
LOG(ERROR) << "Failed to delete the diskcache.";
+ ServiceWorkerMetrics::RecordDeleteAndStartOverResult(
+ ServiceWorkerMetrics::DELETE_DISK_CACHE_ERROR);
callback.Run(SERVICE_WORKER_ERROR_FAILED);
return;
}
DVLOG(1) << "Deleted ServiceWorkerDiskCache successfully.";
+ ServiceWorkerMetrics::RecordDeleteAndStartOverResult(
+ ServiceWorkerMetrics::DELETE_OK);
callback.Run(SERVICE_WORKER_OK);
}
diff --git a/chromium/content/browser/service_worker/service_worker_storage.h b/chromium/content/browser/service_worker/service_worker_storage.h
index 0eda8bf540e..1bfa737d836 100644
--- a/chromium/content/browser/service_worker/service_worker_storage.h
+++ b/chromium/content/browser/service_worker/service_worker_storage.h
@@ -8,6 +8,7 @@
#include <deque>
#include <map>
#include <set>
+#include <string>
#include <vector>
#include "base/bind.h"
@@ -37,9 +38,10 @@ namespace content {
class ServiceWorkerContextCore;
class ServiceWorkerDiskCache;
class ServiceWorkerRegistration;
-class ServiceWorkerRegistrationInfo;
+class ServiceWorkerResponseMetadataWriter;
class ServiceWorkerResponseReader;
class ServiceWorkerResponseWriter;
+struct ServiceWorkerRegistrationInfo;
// This class provides an interface to store and retrieve ServiceWorker
// registration data.
@@ -53,10 +55,17 @@ class CONTENT_EXPORT ServiceWorkerStorage
registration)> FindRegistrationCallback;
typedef base::Callback<
void(const std::vector<ServiceWorkerRegistrationInfo>& registrations)>
- GetAllRegistrationInfosCallback;
+ GetRegistrationsInfosCallback;
typedef base::Callback<
void(ServiceWorkerStatusCode status, bool are_equal)>
CompareCallback;
+ typedef base::Callback<
+ void(const std::string& data, ServiceWorkerStatusCode status)>
+ GetUserDataCallback;
+ typedef base::Callback<void(
+ const std::vector<std::pair<int64, std::string>>& user_data,
+ ServiceWorkerStatusCode status)>
+ GetUserDataForAllRegistrationsCallback;
~ServiceWorkerStorage() override;
@@ -90,10 +99,23 @@ class CONTENT_EXPORT ServiceWorkerStorage
const GURL& origin,
const FindRegistrationCallback& callback);
+ // Generally |FindRegistrationForId| should be used to look up a registration
+ // by |registration_id| since it's more efficient. But if a |registration_id|
+ // is all that is available this method can be used instead.
+ // Like |FindRegistrationForId| this method may complete immediately (the
+ // callback may be called prior to the method returning) or asynchronously.
+ void FindRegistrationForIdOnly(int64 registration_id,
+ const FindRegistrationCallback& callback);
+
ServiceWorkerRegistration* GetUninstallingRegistration(const GURL& scope);
+ // Returns info about all stored and initially installing registrations for
+ // a given origin.
+ void GetRegistrationsForOrigin(
+ const GURL& origin, const GetRegistrationsInfosCallback& callback);
+
// Returns info about all stored and initially installing registrations.
- void GetAllRegistrations(const GetAllRegistrationInfosCallback& callback);
+ void GetAllRegistrations(const GetRegistrationsInfosCallback& callback);
// Commits |registration| with the installed but not activated |version|
// to storage, overwritting any pre-existing registration data for the scope.
@@ -123,6 +145,8 @@ class CONTENT_EXPORT ServiceWorkerStorage
int64 response_id);
scoped_ptr<ServiceWorkerResponseWriter> CreateResponseWriter(
int64 response_id);
+ scoped_ptr<ServiceWorkerResponseMetadataWriter> CreateResponseMetadataWriter(
+ int64 response_id);
// Adds |id| to the set of resources ids that are in the disk
// cache but not yet stored with a registration.
@@ -136,6 +160,26 @@ class CONTENT_EXPORT ServiceWorkerStorage
void CompareScriptResources(int64 lhs_id, int64 rhs_id,
const CompareCallback& callback);
+ // Provide a storage mechanism to read/write arbitrary data associated with
+ // a registration. Each registration has its own key namespace. Stored data
+ // is deleted when the associated registraton is deleted.
+ void GetUserData(int64 registration_id,
+ const std::string& key,
+ const GetUserDataCallback& callback);
+ void StoreUserData(int64 registration_id,
+ const GURL& origin,
+ const std::string& key,
+ const std::string& data,
+ const StatusCallback& callback);
+ void ClearUserData(int64 registration_id,
+ const std::string& key,
+ const StatusCallback& callback);
+ // Returns all registrations that have user data with a particular key, as
+ // well as that user data.
+ void GetUserDataForAllRegistrations(
+ const std::string& key,
+ const GetUserDataForAllRegistrationsCallback& callback);
+
// Deletes the storage and starts over.
void DeleteAndStartOver(const StatusCallback& callback);
@@ -163,11 +207,18 @@ class CONTENT_EXPORT ServiceWorkerStorage
void PurgeResources(const ResourceList& resources);
private:
+ friend class ServiceWorkerHandleTest;
+ friend class ServiceWorkerStorageTest;
friend class ServiceWorkerResourceStorageTest;
friend class ServiceWorkerControlleeRequestHandlerTest;
friend class ServiceWorkerContextRequestHandlerTest;
friend class ServiceWorkerRequestHandlerTest;
+ friend class ServiceWorkerURLRequestJobTest;
+ friend class ServiceWorkerVersionBrowserTest;
+ friend class ServiceWorkerVersionTest;
friend class ServiceWorkerWriteToCacheJobTest;
+ FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDispatcherHostTest,
+ CleanupOnRendererCrash);
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerResourceStorageTest,
DeleteRegistration_NoLiveVersion);
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerResourceStorageTest,
@@ -221,6 +272,13 @@ class CONTENT_EXPORT ServiceWorkerStorage
const ServiceWorkerDatabase::RegistrationData& data,
const ResourceList& resources,
ServiceWorkerDatabase::Status status)> FindInDBCallback;
+ typedef base::Callback<void(
+ const std::string& data,
+ ServiceWorkerDatabase::Status)> GetUserDataInDBCallback;
+ typedef base::Callback<void(
+ const std::vector<std::pair<int64, std::string>>& user_data,
+ ServiceWorkerDatabase::Status)>
+ GetUserDataForAllRegistrationsInDBCallback;
typedef base::Callback<void(const std::vector<int64>& resource_ids,
ServiceWorkerDatabase::Status status)>
GetResourcesCallback;
@@ -236,6 +294,8 @@ class CONTENT_EXPORT ServiceWorkerStorage
base::FilePath GetDatabasePath();
base::FilePath GetDiskCachePath();
+ // Loads the registration data from backend storage. This must be called
+ // before any method that requires registration data.
bool LazyInitialize(
const base::Closure& callback);
void DidReadInitialData(
@@ -259,9 +319,10 @@ class CONTENT_EXPORT ServiceWorkerStorage
const ServiceWorkerDatabase::RegistrationData& data,
const ResourceList& resources,
ServiceWorkerDatabase::Status status);
- void DidGetAllRegistrations(
- const GetAllRegistrationInfosCallback& callback,
+ void DidGetRegistrations(
+ const GetRegistrationsInfosCallback& callback,
RegistrationList* registrations,
+ const GURL& origin_filter,
ServiceWorkerDatabase::Status status);
void DidStoreRegistration(
const StatusCallback& callback,
@@ -279,6 +340,20 @@ class CONTENT_EXPORT ServiceWorkerStorage
const ServiceWorkerDatabase::RegistrationData& deleted_version,
const std::vector<int64>& newly_purgeable_resources,
ServiceWorkerDatabase::Status status);
+ void DidStoreUserData(
+ const StatusCallback& callback,
+ ServiceWorkerDatabase::Status status);
+ void DidGetUserData(
+ const GetUserDataCallback& callback,
+ const std::string& data,
+ ServiceWorkerDatabase::Status status);
+ void DidDeleteUserData(
+ const StatusCallback& callback,
+ ServiceWorkerDatabase::Status status);
+ void DidGetUserDataForAllRegistrations(
+ const GetUserDataForAllRegistrationsCallback& callback,
+ const std::vector<std::pair<int64, std::string>>& user_data,
+ ServiceWorkerDatabase::Status status);
void ReturnFoundRegistration(
const FindRegistrationCallback& callback,
const ServiceWorkerDatabase::RegistrationData& data,
@@ -350,6 +425,22 @@ class CONTENT_EXPORT ServiceWorkerStorage
int64 registration_id,
const GURL& origin,
const FindInDBCallback& callback);
+ static void FindForIdOnlyInDB(
+ ServiceWorkerDatabase* database,
+ scoped_refptr<base::SequencedTaskRunner> original_task_runner,
+ int64 registration_id,
+ const FindInDBCallback& callback);
+ static void GetUserDataInDB(
+ ServiceWorkerDatabase* database,
+ scoped_refptr<base::SequencedTaskRunner> original_task_runner,
+ int64 registration_id,
+ const std::string& key,
+ const GetUserDataInDBCallback& callback);
+ static void GetUserDataForAllRegistrationsInDB(
+ ServiceWorkerDatabase* database,
+ scoped_refptr<base::SequencedTaskRunner> original_task_runner,
+ const std::string& key,
+ const GetUserDataForAllRegistrationsInDBCallback& callback);
static void DeleteAllDataForOriginsFromDB(
ServiceWorkerDatabase* database,
const std::set<GURL>& origins);
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 e98b83dbc6c..aa2ceb56ebe 100644
--- a/chromium/content/browser/service_worker/service_worker_storage_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_storage_unittest.cc
@@ -17,6 +17,7 @@
#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 "ipc/ipc_message.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
@@ -73,12 +74,34 @@ void GetAllCallback(
*all_out = all;
}
-ServiceWorkerStorage::GetAllRegistrationInfosCallback MakeGetAllCallback(
- bool* was_called,
- std::vector<ServiceWorkerRegistrationInfo>* all) {
+ServiceWorkerStorage::GetRegistrationsInfosCallback
+MakeGetRegistrationsCallback(bool* was_called,
+ std::vector<ServiceWorkerRegistrationInfo>* all) {
return base::Bind(&GetAllCallback, was_called, all);
}
+void GetUserDataCallback(
+ bool* was_called,
+ std::string* data_out,
+ ServiceWorkerStatusCode* status_out,
+ const std::string& data,
+ ServiceWorkerStatusCode status) {
+ *was_called = true;
+ *data_out = data;
+ *status_out = status;
+}
+
+void GetUserDataForAllRegistrationsCallback(
+ bool* was_called,
+ std::vector<std::pair<int64, std::string>>* data_out,
+ ServiceWorkerStatusCode* status_out,
+ const std::vector<std::pair<int64, std::string>>& data,
+ ServiceWorkerStatusCode status) {
+ *was_called = true;
+ *data_out = data;
+ *status_out = status;
+}
+
void OnCompareComplete(
ServiceWorkerStatusCode* status_out, bool* are_equal_out,
ServiceWorkerStatusCode status, bool are_equal) {
@@ -181,6 +204,56 @@ void WriteResponseOfSize(ServiceWorkerStorage* storage, int64 id,
WriteResponse(storage, id, headers, buffer.get(), size);
}
+int WriteResponseMetadata(ServiceWorkerStorage* storage,
+ int64 id,
+ const std::string& metadata) {
+ scoped_refptr<IOBuffer> body_buffer(new WrappedIOBuffer(metadata.data()));
+ scoped_ptr<ServiceWorkerResponseMetadataWriter> metadata_writer =
+ storage->CreateResponseMetadataWriter(id);
+ TestCompletionCallback cb;
+ metadata_writer->WriteMetadata(body_buffer.get(), metadata.length(),
+ cb.callback());
+ return cb.WaitForResult();
+}
+
+int WriteMetadata(ServiceWorkerVersion* version,
+ const GURL& url,
+ const std::string& metadata) {
+ const std::vector<char> data(metadata.begin(), metadata.end());
+ EXPECT_TRUE(version);
+ TestCompletionCallback cb;
+ version->script_cache_map()->WriteMetadata(url, data, cb.callback());
+ return cb.WaitForResult();
+}
+
+int ClearMetadata(ServiceWorkerVersion* version, const GURL& url) {
+ EXPECT_TRUE(version);
+ TestCompletionCallback cb;
+ version->script_cache_map()->ClearMetadata(url, cb.callback());
+ return cb.WaitForResult();
+}
+
+bool VerifyResponseMetadata(ServiceWorkerStorage* storage,
+ int64 id,
+ const std::string& expected_metadata) {
+ scoped_ptr<ServiceWorkerResponseReader> reader =
+ storage->CreateResponseReader(id);
+ scoped_refptr<HttpResponseInfoIOBuffer> info_buffer =
+ new HttpResponseInfoIOBuffer();
+ {
+ TestCompletionCallback cb;
+ reader->ReadInfo(info_buffer.get(), cb.callback());
+ int rv = cb.WaitForResult();
+ EXPECT_LT(0, rv);
+ }
+ const net::HttpResponseInfo* read_head = info_buffer->http_info.get();
+ if (!read_head->metadata.get())
+ return false;
+ EXPECT_EQ(0, memcmp(expected_metadata.data(), read_head->metadata->data(),
+ expected_metadata.length()));
+ return true;
+}
+
} // namespace
class ServiceWorkerStorageTest : public testing::Test {
@@ -195,7 +268,6 @@ class ServiceWorkerStorageTest : public testing::Test {
base::ThreadTaskRunnerHandle::Get()));
context_.reset(
new ServiceWorkerContextCore(GetUserDataDirectory(),
- base::ThreadTaskRunnerHandle::Get(),
database_task_manager.Pass(),
base::ThreadTaskRunnerHandle::Get(),
NULL,
@@ -225,6 +297,11 @@ class ServiceWorkerStorageTest : public testing::Test {
}
protected:
+ void LazyInitialize() {
+ storage()->LazyInitialize(base::Bind(&base::DoNothing));
+ base::RunLoop().RunUntilIdle();
+ }
+
ServiceWorkerStatusCode StoreRegistration(
scoped_refptr<ServiceWorkerRegistration> registration,
scoped_refptr<ServiceWorkerVersion> version) {
@@ -256,12 +333,82 @@ class ServiceWorkerStorageTest : public testing::Test {
std::vector<ServiceWorkerRegistrationInfo>* registrations) {
bool was_called = false;
storage()->GetAllRegistrations(
- MakeGetAllCallback(&was_called, registrations));
+ MakeGetRegistrationsCallback(&was_called, registrations));
EXPECT_FALSE(was_called); // always async
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(was_called);
}
+ void GetRegistrationsForOrigin(
+ const GURL& origin,
+ std::vector<ServiceWorkerRegistrationInfo>* registrations) {
+ bool was_called = false;
+ storage()->GetRegistrationsForOrigin(
+ origin,
+ MakeGetRegistrationsCallback(&was_called, registrations));
+ EXPECT_FALSE(was_called); // always async
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(was_called);
+ }
+
+ ServiceWorkerStatusCode GetUserData(
+ int64 registration_id,
+ const std::string& key,
+ std::string* data) {
+ bool was_called = false;
+ ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
+ storage()->GetUserData(
+ registration_id, key,
+ base::Bind(&GetUserDataCallback, &was_called, data, &result));
+ EXPECT_FALSE(was_called); // always async
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(was_called);
+ return result;
+ }
+
+ ServiceWorkerStatusCode StoreUserData(
+ int64 registration_id,
+ const GURL& origin,
+ const std::string& key,
+ const std::string& data) {
+ bool was_called = false;
+ ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
+ storage()->StoreUserData(
+ registration_id, origin, key, data,
+ MakeStatusCallback(&was_called, &result));
+ EXPECT_FALSE(was_called); // always async
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(was_called);
+ return result;
+ }
+
+ ServiceWorkerStatusCode ClearUserData(
+ int64 registration_id,
+ const std::string& key) {
+ bool was_called = false;
+ ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
+ storage()->ClearUserData(
+ registration_id, key, MakeStatusCallback(&was_called, &result));
+ EXPECT_FALSE(was_called); // always async
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(was_called);
+ return result;
+ }
+
+ ServiceWorkerStatusCode GetUserDataForAllRegistrations(
+ const std::string& key,
+ std::vector<std::pair<int64, std::string>>* data) {
+ bool was_called = false;
+ ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
+ storage()->GetUserDataForAllRegistrations(
+ key, base::Bind(&GetUserDataForAllRegistrationsCallback, &was_called,
+ data, &result));
+ EXPECT_FALSE(was_called); // always async
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(was_called);
+ return result;
+ }
+
ServiceWorkerStatusCode UpdateToActiveState(
scoped_refptr<ServiceWorkerRegistration> registration) {
bool was_called = false;
@@ -318,6 +465,18 @@ class ServiceWorkerStorageTest : public testing::Test {
return result;
}
+ ServiceWorkerStatusCode FindRegistrationForIdOnly(
+ int64 registration_id,
+ scoped_refptr<ServiceWorkerRegistration>* registration) {
+ bool was_called = false;
+ ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
+ storage()->FindRegistrationForIdOnly(
+ registration_id, MakeFindCallback(&was_called, &result, registration));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(was_called);
+ return result;
+ }
+
scoped_ptr<ServiceWorkerContextCore> context_;
base::WeakPtr<ServiceWorkerContextCore> context_ptr_;
TestBrowserThreadBundle browser_thread_bundle_;
@@ -367,7 +526,7 @@ TEST_F(ServiceWorkerStorageTest, StoreFindUpdateDeleteRegistration) {
live_registration.get(), kScript, kVersionId, context_ptr_);
live_version->SetStatus(ServiceWorkerVersion::INSTALLED);
live_version->script_cache_map()->SetResources(resources);
- live_registration->SetWaitingVersion(live_version.get());
+ live_registration->SetWaitingVersion(live_version);
live_registration->set_last_update_check(kYesterday);
EXPECT_EQ(SERVICE_WORKER_OK,
StoreRegistration(live_registration, live_version));
@@ -397,6 +556,14 @@ TEST_F(ServiceWorkerStorageTest, StoreFindUpdateDeleteRegistration) {
EXPECT_EQ(live_registration, found_registration);
found_registration = NULL;
+ // Can be found by just the id too.
+ EXPECT_EQ(SERVICE_WORKER_OK,
+ FindRegistrationForIdOnly(kRegistrationId, &found_registration));
+ ASSERT_TRUE(found_registration.get());
+ EXPECT_EQ(kRegistrationId, found_registration->id());
+ EXPECT_EQ(live_registration, found_registration);
+ found_registration = NULL;
+
// Drop the live registration, but keep the version live.
live_registration = NULL;
@@ -418,6 +585,17 @@ TEST_F(ServiceWorkerStorageTest, StoreFindUpdateDeleteRegistration) {
EXPECT_EQ(kResource1Size + kResource2Size, info.stored_version_size_bytes);
all_registrations.clear();
+ // Finding by origin should provide the same result iif origin is kScope.
+ std::vector<ServiceWorkerRegistrationInfo> registrations_origin;
+ GetRegistrationsForOrigin(kScope.GetOrigin(), &registrations_origin);
+ EXPECT_EQ(1u, registrations_origin.size());
+ registrations_origin.clear();
+
+ GetRegistrationsForOrigin(
+ GURL("http://example.com/").GetOrigin(),
+ &registrations_origin);
+ EXPECT_TRUE(registrations_origin.empty());
+
found_registration = NULL;
// Drop the live version too.
@@ -439,7 +617,7 @@ TEST_F(ServiceWorkerStorageTest, StoreFindUpdateDeleteRegistration) {
scoped_refptr<ServiceWorkerVersion> temp_version =
found_registration->waiting_version();
temp_version->SetStatus(ServiceWorkerVersion::ACTIVATED);
- found_registration->SetActiveVersion(temp_version.get());
+ found_registration->SetActiveVersion(temp_version);
temp_version = NULL;
EXPECT_EQ(SERVICE_WORKER_OK, UpdateToActiveState(found_registration));
found_registration->set_last_update_check(kToday);
@@ -479,6 +657,9 @@ TEST_F(ServiceWorkerStorageTest, StoreFindUpdateDeleteRegistration) {
FindRegistrationForId(
kRegistrationId, kScope.GetOrigin(), &found_registration));
EXPECT_FALSE(found_registration.get());
+ EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
+ FindRegistrationForIdOnly(kRegistrationId, &found_registration));
+ EXPECT_FALSE(found_registration.get());
// Deleting an unstored registration should succeed.
EXPECT_EQ(SERVICE_WORKER_OK,
@@ -502,7 +683,7 @@ TEST_F(ServiceWorkerStorageTest, InstallingRegistrationsAreFindable) {
new ServiceWorkerVersion(
live_registration.get(), kScript, kVersionId, context_ptr_);
live_version->SetStatus(ServiceWorkerVersion::INSTALLING);
- live_registration->SetWaitingVersion(live_version.get());
+ live_registration->SetWaitingVersion(live_version);
// Should not be findable, including by GetAllRegistrations.
EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
@@ -511,6 +692,10 @@ TEST_F(ServiceWorkerStorageTest, InstallingRegistrationsAreFindable) {
EXPECT_FALSE(found_registration.get());
EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
+ FindRegistrationForIdOnly(kRegistrationId, &found_registration));
+ EXPECT_FALSE(found_registration.get());
+
+ EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
FindRegistrationForDocument(kDocumentUrl, &found_registration));
EXPECT_FALSE(found_registration.get());
@@ -522,6 +707,15 @@ TEST_F(ServiceWorkerStorageTest, InstallingRegistrationsAreFindable) {
GetAllRegistrations(&all_registrations);
EXPECT_TRUE(all_registrations.empty());
+ std::vector<ServiceWorkerRegistrationInfo> registrations_origin;
+ GetRegistrationsForOrigin(kScope.GetOrigin(), &registrations_origin);
+ EXPECT_TRUE(registrations_origin.empty());
+
+ GetRegistrationsForOrigin(
+ GURL("http://example.com/").GetOrigin(),
+ &registrations_origin);
+ EXPECT_TRUE(registrations_origin.empty());
+
// Notify storage of it being installed.
storage()->NotifyInstallingRegistration(live_registration.get());
@@ -533,6 +727,11 @@ TEST_F(ServiceWorkerStorageTest, InstallingRegistrationsAreFindable) {
found_registration = NULL;
EXPECT_EQ(SERVICE_WORKER_OK,
+ FindRegistrationForIdOnly(kRegistrationId, &found_registration));
+ EXPECT_EQ(live_registration, found_registration);
+ found_registration = NULL;
+
+ EXPECT_EQ(SERVICE_WORKER_OK,
FindRegistrationForDocument(kDocumentUrl, &found_registration));
EXPECT_EQ(live_registration, found_registration);
found_registration = NULL;
@@ -546,6 +745,16 @@ TEST_F(ServiceWorkerStorageTest, InstallingRegistrationsAreFindable) {
EXPECT_EQ(1u, all_registrations.size());
all_registrations.clear();
+ // Finding by origin should provide the same result iif origin is kScope.
+ GetRegistrationsForOrigin(kScope.GetOrigin(), &registrations_origin);
+ EXPECT_EQ(1u, registrations_origin.size());
+ registrations_origin.clear();
+
+ GetRegistrationsForOrigin(
+ GURL("http://example.com/").GetOrigin(),
+ &registrations_origin);
+ EXPECT_TRUE(registrations_origin.empty());
+
// Notify storage of installation no longer happening.
storage()->NotifyDoneInstallingRegistration(
live_registration.get(), NULL, SERVICE_WORKER_OK);
@@ -557,6 +766,10 @@ TEST_F(ServiceWorkerStorageTest, InstallingRegistrationsAreFindable) {
EXPECT_FALSE(found_registration.get());
EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
+ FindRegistrationForIdOnly(kRegistrationId, &found_registration));
+ EXPECT_FALSE(found_registration.get());
+
+ EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
FindRegistrationForDocument(kDocumentUrl, &found_registration));
EXPECT_FALSE(found_registration.get());
@@ -566,6 +779,98 @@ TEST_F(ServiceWorkerStorageTest, InstallingRegistrationsAreFindable) {
GetAllRegistrations(&all_registrations);
EXPECT_TRUE(all_registrations.empty());
+
+ GetRegistrationsForOrigin(kScope.GetOrigin(), &registrations_origin);
+ EXPECT_TRUE(registrations_origin.empty());
+
+ GetRegistrationsForOrigin(
+ GURL("http://example.com/").GetOrigin(),
+ &registrations_origin);
+ EXPECT_TRUE(registrations_origin.empty());
+}
+
+TEST_F(ServiceWorkerStorageTest, StoreUserData) {
+ const GURL kScope("http://www.test.not/scope/");
+ const GURL kScript("http://www.test.not/script.js");
+ const int64 kRegistrationId = 0;
+ const int64 kVersionId = 0;
+
+ LazyInitialize();
+
+ // Store a registration.
+ scoped_refptr<ServiceWorkerRegistration> live_registration =
+ new ServiceWorkerRegistration(
+ kScope, kRegistrationId, context_ptr_);
+ scoped_refptr<ServiceWorkerVersion> live_version =
+ new ServiceWorkerVersion(
+ live_registration.get(), kScript, kVersionId, context_ptr_);
+ std::vector<ServiceWorkerDatabase::ResourceRecord> records;
+ records.push_back(ServiceWorkerDatabase::ResourceRecord(
+ 1, live_version->script_url(), 100));
+ live_version->script_cache_map()->SetResources(records);
+ live_version->SetStatus(ServiceWorkerVersion::INSTALLED);
+ live_registration->SetWaitingVersion(live_version);
+ EXPECT_EQ(SERVICE_WORKER_OK,
+ StoreRegistration(live_registration, live_version));
+
+ // Store user data associated with the registration.
+ std::string data_out;
+ EXPECT_EQ(SERVICE_WORKER_OK,
+ StoreUserData(kRegistrationId, kScope.GetOrigin(), "key", "data"));
+ EXPECT_EQ(SERVICE_WORKER_OK, GetUserData(kRegistrationId, "key", &data_out));
+ EXPECT_EQ("data", data_out);
+ EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
+ GetUserData(kRegistrationId, "unknown_key", &data_out));
+ std::vector<std::pair<int64, std::string>> data_list_out;
+ EXPECT_EQ(SERVICE_WORKER_OK,
+ GetUserDataForAllRegistrations("key", &data_list_out));
+ ASSERT_EQ(1u, data_list_out.size());
+ EXPECT_EQ(kRegistrationId, data_list_out[0].first);
+ EXPECT_EQ("data", data_list_out[0].second);
+ data_list_out.clear();
+ EXPECT_EQ(SERVICE_WORKER_OK,
+ GetUserDataForAllRegistrations("unknown_key", &data_list_out));
+ EXPECT_EQ(0u, data_list_out.size());
+ EXPECT_EQ(SERVICE_WORKER_OK, ClearUserData(kRegistrationId, "key"));
+ EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
+ GetUserData(kRegistrationId, "key", &data_out));
+
+ // User data should be deleted when the associated registration is deleted.
+ ASSERT_EQ(SERVICE_WORKER_OK,
+ StoreUserData(kRegistrationId, kScope.GetOrigin(), "key", "data"));
+ ASSERT_EQ(SERVICE_WORKER_OK,
+ GetUserData(kRegistrationId, "key", &data_out));
+ ASSERT_EQ("data", data_out);
+
+ EXPECT_EQ(SERVICE_WORKER_OK,
+ DeleteRegistration(kRegistrationId, kScope.GetOrigin()));
+ EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
+ GetUserData(kRegistrationId, "key", &data_out));
+ data_list_out.clear();
+ EXPECT_EQ(SERVICE_WORKER_OK,
+ GetUserDataForAllRegistrations("key", &data_list_out));
+ EXPECT_EQ(0u, data_list_out.size());
+
+ // Data access with an invalid registration id should be failed.
+ EXPECT_EQ(SERVICE_WORKER_ERROR_FAILED,
+ StoreUserData(kInvalidServiceWorkerRegistrationId,
+ kScope.GetOrigin(), "key", "data"));
+ EXPECT_EQ(SERVICE_WORKER_ERROR_FAILED,
+ GetUserData(kInvalidServiceWorkerRegistrationId, "key", &data_out));
+ EXPECT_EQ(SERVICE_WORKER_ERROR_FAILED,
+ ClearUserData(kInvalidServiceWorkerRegistrationId, "key"));
+
+ // Data access with an empty key should be failed.
+ EXPECT_EQ(SERVICE_WORKER_ERROR_FAILED,
+ StoreUserData(
+ kRegistrationId, kScope.GetOrigin(), std::string(), "data"));
+ EXPECT_EQ(SERVICE_WORKER_ERROR_FAILED,
+ GetUserData(kRegistrationId, std::string(), &data_out));
+ EXPECT_EQ(SERVICE_WORKER_ERROR_FAILED,
+ ClearUserData(kRegistrationId, std::string()));
+ data_list_out.clear();
+ EXPECT_EQ(SERVICE_WORKER_ERROR_FAILED,
+ GetUserDataForAllRegistrations(std::string(), &data_list_out));
}
class ServiceWorkerResourceStorageTest : public ServiceWorkerStorageTest {
@@ -657,6 +962,65 @@ class ServiceWorkerResourceStorageDiskTest
base::ScopedTempDir user_data_directory_;
};
+TEST_F(ServiceWorkerResourceStorageTest,
+ WriteMetadataWithServiceWorkerResponseMetadataWriter) {
+ const char kMetadata1[] = "Test metadata";
+ const char kMetadata2[] = "small";
+ int64 new_resource_id_ = storage()->NewResourceId();
+ // Writing metadata to nonexistent resoirce ID must fail.
+ EXPECT_GE(0, WriteResponseMetadata(storage(), new_resource_id_, kMetadata1));
+
+ // Check metadata is written.
+ EXPECT_EQ(static_cast<int>(strlen(kMetadata1)),
+ WriteResponseMetadata(storage(), resource_id1_, kMetadata1));
+ EXPECT_TRUE(VerifyResponseMetadata(storage(), resource_id1_, kMetadata1));
+ EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_, true));
+
+ // Check metadata is written and truncated.
+ EXPECT_EQ(static_cast<int>(strlen(kMetadata2)),
+ WriteResponseMetadata(storage(), resource_id1_, kMetadata2));
+ EXPECT_TRUE(VerifyResponseMetadata(storage(), resource_id1_, kMetadata2));
+ EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_, true));
+
+ // Check metadata is deleted.
+ EXPECT_EQ(0, WriteResponseMetadata(storage(), resource_id1_, ""));
+ EXPECT_FALSE(VerifyResponseMetadata(storage(), resource_id1_, ""));
+ EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_, true));
+}
+
+TEST_F(ServiceWorkerResourceStorageTest,
+ WriteMetadataWithServiceWorkerScriptCacheMap) {
+ const char kMetadata1[] = "Test metadata";
+ const char kMetadata2[] = "small";
+ ServiceWorkerVersion* version = registration_->waiting_version();
+ EXPECT_TRUE(version);
+
+ // Writing metadata to nonexistent URL must fail.
+ EXPECT_GE(0,
+ WriteMetadata(version, GURL("http://www.test.not/nonexistent.js"),
+ kMetadata1));
+ // Clearing metadata of nonexistent URL must fail.
+ EXPECT_GE(0,
+ ClearMetadata(version, GURL("http://www.test.not/nonexistent.js")));
+
+ // Check metadata is written.
+ EXPECT_EQ(static_cast<int>(strlen(kMetadata1)),
+ WriteMetadata(version, script_, kMetadata1));
+ EXPECT_TRUE(VerifyResponseMetadata(storage(), resource_id1_, kMetadata1));
+ EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_, true));
+
+ // Check metadata is written and truncated.
+ EXPECT_EQ(static_cast<int>(strlen(kMetadata2)),
+ WriteMetadata(version, script_, kMetadata2));
+ EXPECT_TRUE(VerifyResponseMetadata(storage(), resource_id1_, kMetadata2));
+ EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_, true));
+
+ // Check metadata is deleted.
+ EXPECT_EQ(0, ClearMetadata(version, script_));
+ EXPECT_FALSE(VerifyResponseMetadata(storage(), resource_id1_, ""));
+ EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_, true));
+}
+
TEST_F(ServiceWorkerResourceStorageTest, DeleteRegistration_NoLiveVersion) {
bool was_called = false;
ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
@@ -736,11 +1100,10 @@ TEST_F(ServiceWorkerResourceStorageTest, DeleteRegistration_ActiveVersion) {
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));
+ scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
+ 33 /* dummy render process id */, MSG_ROUTING_NONE,
+ 1 /* dummy provider_id */, SERVICE_WORKER_PROVIDER_FOR_WINDOW,
+ context_->AsWeakPtr(), NULL));
registration_->active_version()->AddControllee(host.get());
bool was_called = false;
@@ -757,7 +1120,6 @@ TEST_F(ServiceWorkerResourceStorageTest, DeleteRegistration_ActiveVersion) {
&verify_ids,
&was_called,
&result));
- registration_->active_version()->Doom();
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(was_called);
EXPECT_EQ(SERVICE_WORKER_OK, result);
@@ -772,6 +1134,7 @@ TEST_F(ServiceWorkerResourceStorageTest, DeleteRegistration_ActiveVersion) {
// Removing the controllee should cause the resources to be deleted.
registration_->active_version()->RemoveControllee(host.get());
+ registration_->active_version()->Doom();
base::RunLoop().RunUntilIdle();
verify_ids.clear();
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
@@ -788,11 +1151,10 @@ TEST_F(ServiceWorkerResourceStorageDiskTest, CleanupOnRestart) {
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));
+ scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
+ 33 /* dummy render process id */, MSG_ROUTING_NONE,
+ 1 /* dummy provider_id */, SERVICE_WORKER_PROVIDER_FOR_WINDOW,
+ context_->AsWeakPtr(), NULL));
registration_->active_version()->AddControllee(host.get());
bool was_called = false;
@@ -841,7 +1203,6 @@ TEST_F(ServiceWorkerResourceStorageDiskTest, CleanupOnRestart) {
base::ThreadTaskRunnerHandle::Get()));
context_.reset(
new ServiceWorkerContextCore(GetUserDataDirectory(),
- base::ThreadTaskRunnerHandle::Get(),
database_task_manager.Pass(),
base::ThreadTaskRunnerHandle::Get(),
NULL,
@@ -885,11 +1246,10 @@ TEST_F(ServiceWorkerResourceStorageTest, UpdateRegistration) {
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));
+ scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
+ 33 /* dummy render process id */, MSG_ROUTING_NONE,
+ 1 /* dummy provider_id */, SERVICE_WORKER_PROVIDER_FOR_WINDOW,
+ context_->AsWeakPtr(), NULL));
registration_->active_version()->AddControllee(host.get());
bool was_called = false;
@@ -900,7 +1260,11 @@ TEST_F(ServiceWorkerResourceStorageTest, UpdateRegistration) {
scoped_refptr<ServiceWorkerVersion> live_version = new ServiceWorkerVersion(
registration_.get(), script_, storage()->NewVersionId(), context_ptr_);
live_version->SetStatus(ServiceWorkerVersion::NEW);
- registration_->SetWaitingVersion(live_version.get());
+ registration_->SetWaitingVersion(live_version);
+ std::vector<ServiceWorkerDatabase::ResourceRecord> records;
+ records.push_back(ServiceWorkerDatabase::ResourceRecord(
+ 10, live_version->script_url(), 100));
+ live_version->script_cache_map()->SetResources(records);
// Writing the registration should move the old version's resources to the
// purgeable list but keep them available.
@@ -912,7 +1276,6 @@ TEST_F(ServiceWorkerResourceStorageTest, UpdateRegistration) {
&verify_ids,
&was_called,
&result));
- registration_->active_version()->Doom();
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(was_called);
EXPECT_EQ(SERVICE_WORKER_OK, result);
@@ -928,6 +1291,7 @@ TEST_F(ServiceWorkerResourceStorageTest, UpdateRegistration) {
// Removing the controllee should cause the old version's resources to be
// deleted.
registration_->active_version()->RemoveControllee(host.get());
+ registration_->active_version()->Doom();
base::RunLoop().RunUntilIdle();
verify_ids.clear();
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
@@ -953,8 +1317,12 @@ TEST_F(ServiceWorkerStorageTest, FindRegistration_LongestScopeMatch) {
scoped_refptr<ServiceWorkerVersion> live_version1 =
new ServiceWorkerVersion(
live_registration1.get(), kScript1, kVersionId1, context_ptr_);
+ std::vector<ServiceWorkerDatabase::ResourceRecord> records1;
+ records1.push_back(ServiceWorkerDatabase::ResourceRecord(
+ 1, live_version1->script_url(), 100));
+ live_version1->script_cache_map()->SetResources(records1);
live_version1->SetStatus(ServiceWorkerVersion::INSTALLED);
- live_registration1->SetWaitingVersion(live_version1.get());
+ live_registration1->SetWaitingVersion(live_version1);
// Registration for "/scope/foo".
const GURL kScope2("http://www.example.com/scope/foo");
@@ -967,8 +1335,12 @@ TEST_F(ServiceWorkerStorageTest, FindRegistration_LongestScopeMatch) {
scoped_refptr<ServiceWorkerVersion> live_version2 =
new ServiceWorkerVersion(
live_registration2.get(), kScript2, kVersionId2, context_ptr_);
+ std::vector<ServiceWorkerDatabase::ResourceRecord> records2;
+ records2.push_back(ServiceWorkerDatabase::ResourceRecord(
+ 2, live_version2->script_url(), 100));
+ live_version2->script_cache_map()->SetResources(records2);
live_version2->SetStatus(ServiceWorkerVersion::INSTALLED);
- live_registration2->SetWaitingVersion(live_version2.get());
+ live_registration2->SetWaitingVersion(live_version2);
// Registration for "/scope/foobar".
const GURL kScope3("http://www.example.com/scope/foobar");
@@ -981,8 +1353,12 @@ TEST_F(ServiceWorkerStorageTest, FindRegistration_LongestScopeMatch) {
scoped_refptr<ServiceWorkerVersion> live_version3 =
new ServiceWorkerVersion(
live_registration3.get(), kScript3, kVersionId3, context_ptr_);
+ std::vector<ServiceWorkerDatabase::ResourceRecord> records3;
+ records3.push_back(ServiceWorkerDatabase::ResourceRecord(
+ 3, live_version3->script_url(), 100));
+ live_version3->script_cache_map()->SetResources(records3);
live_version3->SetStatus(ServiceWorkerVersion::INSTALLED);
- live_registration3->SetWaitingVersion(live_version3.get());
+ live_registration3->SetWaitingVersion(live_version3);
// Notify storage of they being installed.
storage()->NotifyInstallingRegistration(live_registration1.get());
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 8889039407a..ef2ba6febda 100644
--- a/chromium/content/browser/service_worker/service_worker_unregister_job.cc
+++ b/chromium/content/browser/service_worker/service_worker_unregister_job.cc
@@ -40,16 +40,18 @@ void ServiceWorkerUnregisterJob::Start() {
}
void ServiceWorkerUnregisterJob::Abort() {
- CompleteInternal(SERVICE_WORKER_ERROR_ABORT);
+ CompleteInternal(kInvalidServiceWorkerRegistrationId,
+ SERVICE_WORKER_ERROR_ABORT);
}
-bool ServiceWorkerUnregisterJob::Equals(ServiceWorkerRegisterJobBase* job) {
+bool ServiceWorkerUnregisterJob::Equals(
+ ServiceWorkerRegisterJobBase* job) const {
if (job->GetType() != GetType())
return false;
return static_cast<ServiceWorkerUnregisterJob*>(job)->pattern_ == pattern_;
}
-RegistrationJobType ServiceWorkerUnregisterJob::GetType() {
+RegistrationJobType ServiceWorkerUnregisterJob::GetType() const {
return UNREGISTRATION_JOB;
}
@@ -58,44 +60,48 @@ void ServiceWorkerUnregisterJob::OnRegistrationFound(
const scoped_refptr<ServiceWorkerRegistration>& registration) {
if (status == SERVICE_WORKER_ERROR_NOT_FOUND) {
DCHECK(!registration.get());
- Complete(SERVICE_WORKER_ERROR_NOT_FOUND);
+ Complete(kInvalidServiceWorkerRegistrationId,
+ SERVICE_WORKER_ERROR_NOT_FOUND);
return;
}
if (status != SERVICE_WORKER_OK || registration->is_uninstalling()) {
- Complete(status);
+ Complete(kInvalidServiceWorkerRegistrationId, status);
return;
}
// TODO: "7. If registration.updatePromise is not null..."
// "8. Resolve promise."
- ResolvePromise(SERVICE_WORKER_OK);
+ ResolvePromise(registration->id(), SERVICE_WORKER_OK);
registration->ClearWhenReady();
- Complete(SERVICE_WORKER_OK);
+ Complete(registration->id(), SERVICE_WORKER_OK);
}
-void ServiceWorkerUnregisterJob::Complete(ServiceWorkerStatusCode status) {
- CompleteInternal(status);
+void ServiceWorkerUnregisterJob::Complete(int64 registration_id,
+ ServiceWorkerStatusCode status) {
+ CompleteInternal(registration_id, status);
context_->job_coordinator()->FinishJob(pattern_, this);
}
void ServiceWorkerUnregisterJob::CompleteInternal(
+ int64 registration_id,
ServiceWorkerStatusCode status) {
if (!is_promise_resolved_)
- ResolvePromise(status);
+ ResolvePromise(registration_id, status);
}
void ServiceWorkerUnregisterJob::ResolvePromise(
+ int64 registration_id,
ServiceWorkerStatusCode status) {
DCHECK(!is_promise_resolved_);
is_promise_resolved_ = true;
for (std::vector<UnregistrationCallback>::iterator it = callbacks_.begin();
it != callbacks_.end();
++it) {
- it->Run(status);
+ it->Run(registration_id, status);
}
}
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 fef9c272de6..282167e9a95 100644
--- a/chromium/content/browser/service_worker/service_worker_unregister_job.h
+++ b/chromium/content/browser/service_worker/service_worker_unregister_job.h
@@ -27,7 +27,8 @@ class ServiceWorkerStorage;
// ServiceWorkerRegistration itself.
class ServiceWorkerUnregisterJob : public ServiceWorkerRegisterJobBase {
public:
- typedef base::Callback<void(ServiceWorkerStatusCode status)>
+ typedef base::Callback<void(int64 registration_id,
+ ServiceWorkerStatusCode status)>
UnregistrationCallback;
ServiceWorkerUnregisterJob(base::WeakPtr<ServiceWorkerContextCore> context,
@@ -41,16 +42,16 @@ class ServiceWorkerUnregisterJob : public ServiceWorkerRegisterJobBase {
// ServiceWorkerRegisterJobBase implementation:
void Start() override;
void Abort() override;
- bool Equals(ServiceWorkerRegisterJobBase* job) override;
- RegistrationJobType GetType() override;
+ bool Equals(ServiceWorkerRegisterJobBase* job) const override;
+ RegistrationJobType GetType() const override;
private:
void OnRegistrationFound(
ServiceWorkerStatusCode status,
const scoped_refptr<ServiceWorkerRegistration>& registration);
- void Complete(ServiceWorkerStatusCode status);
- void CompleteInternal(ServiceWorkerStatusCode status);
- void ResolvePromise(ServiceWorkerStatusCode status);
+ void Complete(int64 registration_id, ServiceWorkerStatusCode status);
+ void CompleteInternal(int64 registration_id, ServiceWorkerStatusCode status);
+ void ResolvePromise(int64 registration_id, ServiceWorkerStatusCode status);
base::WeakPtr<ServiceWorkerContextCore> context_;
const GURL pattern_;
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 0e6ef2b98fc..259c308ee79 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
@@ -10,20 +10,27 @@
#include "base/bind.h"
#include "base/guid.h"
+#include "base/memory/scoped_vector.h"
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
+#include "content/browser/resource_context_impl.h"
#include "content/browser/service_worker/service_worker_fetch_dispatcher.h"
#include "content/browser/service_worker/service_worker_provider_host.h"
+#include "content/browser/streams/stream.h"
+#include "content/browser/streams/stream_context.h"
+#include "content/browser/streams/stream_registry.h"
#include "content/common/resource_request_body.h"
#include "content/common/service_worker/service_worker_types.h"
#include "content/public/browser/blob_handle.h"
#include "content/public/browser/resource_request_info.h"
#include "content/public/browser/service_worker_context.h"
+#include "content/public/common/referrer.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 "storage/browser/blob/blob_data_builder.h"
#include "storage/browser/blob/blob_data_handle.h"
#include "storage/browser/blob/blob_storage_context.h"
#include "storage/browser/blob/blob_url_request_job_factory.h"
@@ -36,8 +43,10 @@ ServiceWorkerURLRequestJob::ServiceWorkerURLRequestJob(
net::NetworkDelegate* network_delegate,
base::WeakPtr<ServiceWorkerProviderHost> provider_host,
base::WeakPtr<storage::BlobStorageContext> blob_storage_context,
+ const ResourceContext* resource_context,
FetchRequestMode request_mode,
FetchCredentialsMode credentials_mode,
+ bool is_main_resource_load,
RequestContextType request_context_type,
RequestContextFrameType frame_type,
scoped_refptr<ResourceRequestBody> body)
@@ -47,8 +56,11 @@ ServiceWorkerURLRequestJob::ServiceWorkerURLRequestJob(
is_started_(false),
service_worker_response_type_(blink::WebServiceWorkerResponseTypeDefault),
blob_storage_context_(blob_storage_context),
+ resource_context_(resource_context),
+ stream_pending_buffer_size_(0),
request_mode_(request_mode),
credentials_mode_(credentials_mode),
+ is_main_resource_load_(is_main_resource_load),
request_context_type_(request_context_type),
frame_type_(frame_type),
fall_back_required_(false),
@@ -75,6 +87,7 @@ void ServiceWorkerURLRequestJob::Start() {
void ServiceWorkerURLRequestJob::Kill() {
net::URLRequestJob::Kill();
+ ClearStream();
fetch_dispatcher_.reset();
blob_request_.reset();
weak_factory_.InvalidateWeakPtrs();
@@ -100,7 +113,9 @@ bool ServiceWorkerURLRequestJob::GetMimeType(std::string* mime_type) const {
void ServiceWorkerURLRequestJob::GetResponseInfo(net::HttpResponseInfo* info) {
if (!http_info())
return;
+ const base::Time request_time = info->request_time;
*info = *http_info();
+ info->request_time = request_time;
info->response_time = response_time_;
}
@@ -131,11 +146,37 @@ void ServiceWorkerURLRequestJob::SetExtraRequestHeaders(
bool ServiceWorkerURLRequestJob::ReadRawData(
net::IOBuffer* buf, int buf_size, int *bytes_read) {
+ DCHECK(buf);
+ DCHECK_GE(buf_size, 0);
+ DCHECK(bytes_read);
+ DCHECK(waiting_stream_url_.is_empty());
+ if (stream_.get()) {
+ switch (stream_->ReadRawData(buf, buf_size, bytes_read)) {
+ case Stream::STREAM_HAS_DATA:
+ DCHECK_GT(*bytes_read, 0);
+ return true;
+ case Stream::STREAM_COMPLETE:
+ DCHECK(!*bytes_read);
+ return true;
+ case Stream::STREAM_EMPTY:
+ stream_pending_buffer_ = buf;
+ stream_pending_buffer_size_ = buf_size;
+ SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
+ return false;
+ case Stream::STREAM_ABORTED:
+ // Handle this as connection reset.
+ NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
+ net::ERR_CONNECTION_RESET));
+ return false;
+ }
+ NOTREACHED();
+ return false;
+ }
+
if (!blob_request_) {
*bytes_read = 0;
return true;
}
-
blob_request_->Read(buf, buf_size, bytes_read);
net::URLRequestStatus status = blob_request_->status();
SetStatus(status);
@@ -194,9 +235,57 @@ void ServiceWorkerURLRequestJob::OnReadCompleted(net::URLRequest* request,
NotifyDone(request->status());
}
+void ServiceWorkerURLRequestJob::OnDataAvailable(Stream* stream) {
+ // Clear the IO_PENDING status.
+ SetStatus(net::URLRequestStatus());
+ // Do nothing if stream_pending_buffer_ is empty, i.e. there's no ReadRawData
+ // operation waiting for IO completion.
+ if (!stream_pending_buffer_.get())
+ return;
+
+ // stream_pending_buffer_ is set to the IOBuffer instance provided to
+ // ReadRawData() by URLRequestJob.
+
+ int bytes_read = 0;
+ switch (stream_->ReadRawData(
+ stream_pending_buffer_.get(), stream_pending_buffer_size_, &bytes_read)) {
+ case Stream::STREAM_HAS_DATA:
+ DCHECK_GT(bytes_read, 0);
+ break;
+ case Stream::STREAM_COMPLETE:
+ // Calling NotifyReadComplete with 0 signals completion.
+ DCHECK(!bytes_read);
+ break;
+ case Stream::STREAM_EMPTY:
+ NOTREACHED();
+ break;
+ case Stream::STREAM_ABORTED:
+ // Handle this as connection reset.
+ NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
+ net::ERR_CONNECTION_RESET));
+ break;
+ }
+
+ // Clear the buffers before notifying the read is complete, so that it is
+ // safe for the observer to read.
+ stream_pending_buffer_ = nullptr;
+ stream_pending_buffer_size_ = 0;
+ NotifyReadComplete(bytes_read);
+}
+
+void ServiceWorkerURLRequestJob::OnStreamRegistered(Stream* stream) {
+ StreamContext* stream_context =
+ GetStreamContextForResourceContext(resource_context_);
+ stream_context->registry()->RemoveRegisterObserver(waiting_stream_url_);
+ waiting_stream_url_ = GURL();
+ stream_ = stream;
+ stream_->SetReadObserver(this);
+ CommitResponseHeader();
+}
+
const net::HttpResponseInfo* ServiceWorkerURLRequestJob::http_info() const {
if (!http_response_info_)
- return NULL;
+ return nullptr;
if (range_response_info_)
return range_response_info_.get();
return http_response_info_.get();
@@ -229,6 +318,7 @@ void ServiceWorkerURLRequestJob::GetExtraResponseInfo(
ServiceWorkerURLRequestJob::~ServiceWorkerURLRequestJob() {
+ ClearStream();
}
void ServiceWorkerURLRequestJob::MaybeStartRequest() {
@@ -249,13 +339,16 @@ void ServiceWorkerURLRequestJob::StartRequest() {
case FALLBACK_TO_NETWORK:
// Restart the request to create a new job. Our request handler will
- // return NULL, and the default job (which will hit network) should be
+ // return nullptr, and the default job (which will hit network) should be
// created.
NotifyRestartRequired();
return;
case FORWARD_TO_SERVICE_WORKER:
- DCHECK(provider_host_ && provider_host_->active_version());
+ if (!provider_host_ || !provider_host_->active_version()) {
+ DeliverErrorResponse();
+ return;
+ }
DCHECK(!fetch_dispatcher_);
// Send a fetch event to the ServiceWorker associated to the
// provider_host.
@@ -295,12 +388,19 @@ ServiceWorkerURLRequestJob::CreateFetchRequest() {
}
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);
+ request->referrer =
+ Referrer(GURL(request_->referrer()), info->GetReferrerPolicy());
+ } else {
+ CHECK(
+ request_->referrer_policy() ==
+ net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE);
+ request->referrer =
+ Referrer(GURL(request_->referrer()), blink::WebReferrerPolicyDefault);
}
return request.Pass();
}
@@ -310,27 +410,35 @@ bool ServiceWorkerURLRequestJob::CreateRequestBodyBlob(std::string* blob_uuid,
if (!body_.get() || !blob_storage_context_)
return false;
+ // To ensure the blobs stick around until the end of the reading.
+ ScopedVector<storage::BlobDataHandle> handles;
+ ScopedVector<storage::BlobDataSnapshot> snapshots;
+ // TODO(dmurph): Allow blobs to be added below, so that the context can
+ // efficiently re-use blob items for the new blob.
std::vector<const ResourceRequestBody::Element*> resolved_elements;
- for (size_t i = 0; i < body_->elements()->size(); ++i) {
- const ResourceRequestBody::Element& element = (*body_->elements())[i];
+ for (const ResourceRequestBody::Element& element : (*body_->elements())) {
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())
+ scoped_ptr<storage::BlobDataSnapshot> snapshot = handle->CreateSnapshot();
+ if (snapshot->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 auto& items = snapshot->items();
+ for (const auto& item : items) {
+ DCHECK_NE(storage::DataElement::TYPE_BLOB, item->type());
+ resolved_elements.push_back(item->data_element_ptr());
}
+ handles.push_back(handle.release());
+ snapshots.push_back(snapshot.release());
}
const std::string uuid(base::GenerateGUID());
uint64 total_size = 0;
- scoped_refptr<storage::BlobData> blob_data = new storage::BlobData(uuid);
+
+ storage::BlobDataBuilder blob_builder(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)
@@ -339,23 +447,21 @@ bool ServiceWorkerURLRequestJob::CreateRequestBodyBlob(std::string* blob_uuid,
total_size = kuint64max;
switch (element.type()) {
case ResourceRequestBody::Element::TYPE_BYTES:
- blob_data->AppendData(element.bytes(), element.length());
+ blob_builder.AppendData(element.bytes(), element.length());
break;
case ResourceRequestBody::Element::TYPE_FILE:
- blob_data->AppendFile(element.path(),
- element.offset(),
- element.length(),
- element.expected_modification_time());
+ blob_builder.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());
+ blob_builder.AppendFileSystemFile(element.filesystem_url(),
+ element.offset(), element.length(),
+ element.expected_modification_time());
break;
default:
NOTIMPLEMENTED();
@@ -363,7 +469,7 @@ bool ServiceWorkerURLRequestJob::CreateRequestBodyBlob(std::string* blob_uuid,
}
request_body_blob_data_handle_ =
- blob_storage_context_->AddFinishedBlob(blob_data.get());
+ blob_storage_context_->AddFinishedBlob(&blob_builder);
*blob_uuid = uuid;
*blob_size = total_size;
return true;
@@ -376,7 +482,8 @@ void ServiceWorkerURLRequestJob::DidPrepareFetchEvent() {
void ServiceWorkerURLRequestJob::DidDispatchFetchEvent(
ServiceWorkerStatusCode status,
ServiceWorkerFetchEventResult fetch_result,
- const ServiceWorkerResponse& response) {
+ const ServiceWorkerResponse& response,
+ scoped_refptr<ServiceWorkerVersion> version) {
fetch_dispatcher_.reset();
// Check if we're not orphaned.
@@ -384,13 +491,13 @@ void ServiceWorkerURLRequestJob::DidDispatchFetchEvent(
return;
if (status != SERVICE_WORKER_OK) {
- // Dispatching event has been failed, falling back to the network.
- // (Tentative behavior described on github)
- // TODO(kinuko): consider returning error if we've come here because
- // unexpected worker termination etc (so that we could fix bugs).
- // TODO(kinuko): Would be nice to log the error case.
- response_type_ = FALLBACK_TO_NETWORK;
- NotifyRestartRequired();
+ // TODO(falken): Add UMA and the report error to the version.
+ if (is_main_resource_load_) {
+ response_type_ = FALLBACK_TO_NETWORK;
+ NotifyRestartRequired();
+ } else {
+ DeliverErrorResponse();
+ }
return;
}
@@ -427,6 +534,48 @@ void ServiceWorkerURLRequestJob::DidDispatchFetchEvent(
fetch_end_time_ = base::TimeTicks::Now();
load_timing_info_.send_end = fetch_end_time_;
+ // Creates a new HttpResponseInfo using the the ServiceWorker script's
+ // HttpResponseInfo to show HTTPS padlock.
+ // TODO(horo): When we support mixed-content (HTTP) no-cors requests from a
+ // ServiceWorker, we have to check the security level of the responses.
+ DCHECK(!http_response_info_);
+ DCHECK(version);
+ const net::HttpResponseInfo* main_script_http_info =
+ version->GetMainScriptHttpResponseInfo();
+ if (main_script_http_info) {
+ // In normal case |main_script_http_info| must be set while starting the
+ // ServiceWorker. But when the ServiceWorker registration database was not
+ // written correctly, it may be null.
+ // TODO(horo): Change this line to DCHECK when crbug.com/485900 is fixed.
+ http_response_info_.reset(
+ new net::HttpResponseInfo(*main_script_http_info));
+ }
+
+ // Set up a request for reading the stream.
+ if (response.stream_url.is_valid()) {
+ DCHECK(response.blob_uuid.empty());
+ streaming_version_ = version;
+ streaming_version_->AddStreamingURLRequestJob(this);
+ 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();
+ StreamContext* stream_context =
+ GetStreamContextForResourceContext(resource_context_);
+ stream_ =
+ stream_context->registry()->GetStream(response.stream_url);
+ if (!stream_.get()) {
+ waiting_stream_url_ = response.stream_url;
+ // Wait for StreamHostMsg_StartBuilding message from the ServiceWorker.
+ stream_context->registry()->SetRegisterObserver(waiting_stream_url_,
+ this);
+ return;
+ }
+ stream_->SetReadObserver(this);
+ CommitResponseHeader();
+ return;
+ }
// Set up a request for reading the blob.
if (!response.blob_uuid.empty() && blob_storage_context_) {
scoped_ptr<storage::BlobDataHandle> blob_data_handle =
@@ -473,8 +622,11 @@ void ServiceWorkerURLRequestJob::CreateResponseHeader(
}
void ServiceWorkerURLRequestJob::CommitResponseHeader() {
- http_response_info_.reset(new net::HttpResponseInfo());
+ if (!http_response_info_)
+ http_response_info_.reset(new net::HttpResponseInfo());
http_response_info_->headers.swap(http_response_headers_);
+ http_response_info_->vary_data = net::HttpVaryData();
+ http_response_info_->metadata = nullptr;
NotifyHeadersComplete();
}
@@ -486,4 +638,22 @@ void ServiceWorkerURLRequestJob::DeliverErrorResponse() {
CommitResponseHeader();
}
+void ServiceWorkerURLRequestJob::ClearStream() {
+ if (streaming_version_) {
+ streaming_version_->RemoveStreamingURLRequestJob(this);
+ streaming_version_ = nullptr;
+ }
+ if (stream_) {
+ stream_->RemoveReadObserver(this);
+ stream_->Abort();
+ stream_ = nullptr;
+ }
+ if (!waiting_stream_url_.is_empty()) {
+ StreamRegistry* stream_registry =
+ GetStreamContextForResourceContext(resource_context_)->registry();
+ stream_registry->RemoveRegisterObserver(waiting_stream_url_);
+ stream_registry->AbortPendingStream(waiting_stream_url_);
+ }
+}
+
} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_url_request_job.h b/chromium/content/browser/service_worker/service_worker_url_request_job.h
index e8f0f0b2f7d..e29183a11f5 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
@@ -8,8 +8,11 @@
#include <map>
#include <string>
+#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
+#include "content/browser/streams/stream_read_observer.h"
+#include "content/browser/streams/stream_register_observer.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"
@@ -20,6 +23,11 @@
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_job.h"
#include "third_party/WebKit/public/platform/WebServiceWorkerResponseType.h"
+#include "url/gurl.h"
+
+namespace net {
+class IOBuffer;
+}
namespace storage {
class BlobDataHandle;
@@ -28,22 +36,29 @@ class BlobStorageContext;
namespace content {
+class ResourceContext;
class ResourceRequestBody;
class ServiceWorkerContextCore;
class ServiceWorkerFetchDispatcher;
class ServiceWorkerProviderHost;
+class ServiceWorkerVersion;
+class Stream;
class CONTENT_EXPORT ServiceWorkerURLRequestJob
: public net::URLRequestJob,
- public net::URLRequest::Delegate {
+ public net::URLRequest::Delegate,
+ public StreamReadObserver,
+ public StreamRegisterObserver {
public:
ServiceWorkerURLRequestJob(
net::URLRequest* request,
net::NetworkDelegate* network_delegate,
base::WeakPtr<ServiceWorkerProviderHost> provider_host,
base::WeakPtr<storage::BlobStorageContext> blob_storage_context,
+ const ResourceContext* resource_context,
FetchRequestMode request_mode,
FetchCredentialsMode credentials_mode,
+ bool is_main_resource_load,
RequestContextType request_context_type,
RequestContextFrameType frame_type,
scoped_refptr<ResourceRequestBody> body);
@@ -88,7 +103,11 @@ class CONTENT_EXPORT ServiceWorkerURLRequestJob
void OnResponseStarted(net::URLRequest* request) override;
void OnReadCompleted(net::URLRequest* request, int bytes_read) override;
- const net::HttpResponseInfo* http_info() const;
+ // StreamObserver override:
+ void OnDataAvailable(Stream* stream) override;
+
+ // StreamRegisterObserver override:
+ void OnStreamRegistered(Stream* stream) override;
void GetExtraResponseInfo(
bool* was_fetched_via_service_worker,
@@ -126,7 +145,8 @@ class CONTENT_EXPORT ServiceWorkerURLRequestJob
void DidPrepareFetchEvent();
void DidDispatchFetchEvent(ServiceWorkerStatusCode status,
ServiceWorkerFetchEventResult fetch_result,
- const ServiceWorkerResponse& response);
+ const ServiceWorkerResponse& response,
+ scoped_refptr<ServiceWorkerVersion> version);
// Populates |http_response_headers_|.
void CreateResponseHeader(int status_code,
@@ -140,6 +160,11 @@ class CONTENT_EXPORT ServiceWorkerURLRequestJob
// Creates and commits a response header indicating error.
void DeliverErrorResponse();
+ // Releases the resources for streaming.
+ void ClearStream();
+
+ const net::HttpResponseInfo* http_info() const;
+
base::WeakPtr<ServiceWorkerProviderHost> provider_host_;
// Timing info to show on the popup in Devtools' Network tab.
@@ -163,9 +188,16 @@ class CONTENT_EXPORT ServiceWorkerURLRequestJob
// Used when response type is FORWARD_TO_SERVICE_WORKER.
scoped_ptr<ServiceWorkerFetchDispatcher> fetch_dispatcher_;
base::WeakPtr<storage::BlobStorageContext> blob_storage_context_;
+ const ResourceContext* resource_context_;
scoped_ptr<net::URLRequest> blob_request_;
+ scoped_refptr<Stream> stream_;
+ GURL waiting_stream_url_;
+ scoped_refptr<net::IOBuffer> stream_pending_buffer_;
+ int stream_pending_buffer_size_;
+
FetchRequestMode request_mode_;
FetchCredentialsMode credentials_mode_;
+ bool is_main_resource_load_;
RequestContextType request_context_type_;
RequestContextFrameType frame_type_;
bool fall_back_required_;
@@ -173,6 +205,7 @@ class CONTENT_EXPORT ServiceWorkerURLRequestJob
// 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_;
+ scoped_refptr<ServiceWorkerVersion> streaming_version_;
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 76f718e27dc..9e8462ae726 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
@@ -7,8 +7,10 @@
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
+#include "base/thread_task_runner_handle.h"
#include "content/browser/fileapi/chrome_blob_storage_context.h"
#include "content/browser/fileapi/mock_url_request_delegate.h"
+#include "content/browser/resource_context_impl.h"
#include "content/browser/service_worker/embedded_worker_registry.h"
#include "content/browser/service_worker/embedded_worker_test_helper.h"
#include "content/browser/service_worker/service_worker_context_core.h"
@@ -17,24 +19,32 @@
#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/browser/streams/stream.h"
+#include "content/browser/streams/stream_context.h"
+#include "content/browser/streams/stream_registry.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/mock_resource_context.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "net/base/io_buffer.h"
+#include "net/base/test_data_directory.h"
#include "net/http/http_request_headers.h"
#include "net/http/http_response_headers.h"
+#include "net/ssl/ssl_info.h"
+#include "net/test/cert_test_util.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 "storage/browser/blob/blob_data_builder.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"
namespace content {
@@ -52,31 +62,39 @@ class MockHttpProtocolHandler
public:
MockHttpProtocolHandler(
base::WeakPtr<ServiceWorkerProviderHost> provider_host,
+ const ResourceContext* resource_context,
base::WeakPtr<storage::BlobStorageContext> blob_storage_context)
: provider_host_(provider_host),
- blob_storage_context_(blob_storage_context) {}
+ resource_context_(resource_context),
+ blob_storage_context_(blob_storage_context),
+ job_(nullptr) {}
~MockHttpProtocolHandler() override {}
net::URLRequestJob* MaybeCreateJob(
net::URLRequest* request,
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;
+ if (job_ && job_->ShouldFallbackToNetwork()) {
+ // Simulate fallback to network by constructing a valid response.
+ return new net::URLRequestTestJob(request, network_delegate,
+ net::URLRequestTestJob::test_headers(),
+ "PASS", true);
+ }
+
+ job_ = new ServiceWorkerURLRequestJob(
+ request, network_delegate, provider_host_, blob_storage_context_,
+ resource_context_, FETCH_REQUEST_MODE_NO_CORS,
+ FETCH_CREDENTIALS_MODE_OMIT, true /* is_main_resource_load */,
+ REQUEST_CONTEXT_TYPE_HYPERLINK, REQUEST_CONTEXT_FRAME_TYPE_TOP_LEVEL,
+ scoped_refptr<ResourceRequestBody>());
+ job_->ForwardToServiceWorker();
+ return job_;
}
private:
base::WeakPtr<ServiceWorkerProviderHost> provider_host_;
+ const ResourceContext* resource_context_;
base::WeakPtr<storage::BlobStorageContext> blob_storage_context_;
+ mutable ServiceWorkerURLRequestJob* job_;
};
// Returns a BlobProtocolHandler that uses |blob_storage_context|. Caller owns
@@ -86,7 +104,7 @@ storage::BlobProtocolHandler* CreateMockBlobProtocolHandler(
// 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());
+ blob_storage_context, nullptr, base::ThreadTaskRunnerHandle::Get().get());
}
} // namespace
@@ -95,15 +113,17 @@ class ServiceWorkerURLRequestJobTest : public testing::Test {
protected:
ServiceWorkerURLRequestJobTest()
: thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP),
- blob_data_(new storage::BlobData("blob-id:myblob")) {}
+ blob_data_(new storage::BlobDataBuilder("blob-id:myblob")) {}
~ServiceWorkerURLRequestJobTest() override {}
void SetUp() override {
browser_context_.reset(new TestBrowserContext);
- SetUpWithHelper(new EmbeddedWorkerTestHelper(kProcessID));
+ InitializeResourceContext(browser_context_.get());
+ SetUpWithHelper(new EmbeddedWorkerTestHelper(base::FilePath(), kProcessID));
}
- void SetUpWithHelper(EmbeddedWorkerTestHelper* helper) {
+ void SetUpWithHelper(EmbeddedWorkerTestHelper* helper,
+ bool set_main_script_http_response_info = true) {
helper_.reset(helper);
registration_ = new ServiceWorkerRegistration(
@@ -115,12 +135,42 @@ class ServiceWorkerURLRequestJobTest : public testing::Test {
GURL("http://example.com/service_worker.js"),
1L,
helper_->context()->AsWeakPtr());
+ std::vector<ServiceWorkerDatabase::ResourceRecord> records;
+ records.push_back(
+ ServiceWorkerDatabase::ResourceRecord(10, version_->script_url(), 100));
+ version_->script_cache_map()->SetResources(records);
+
+ // Make the registration findable via storage functions.
+ helper_->context()->storage()->LazyInitialize(base::Bind(&base::DoNothing));
+ base::RunLoop().RunUntilIdle();
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
+ helper_->context()->storage()->StoreRegistration(
+ registration_.get(),
+ version_.get(),
+ CreateReceiverOnCurrentThread(&status));
+ base::RunLoop().RunUntilIdle();
+ ASSERT_EQ(SERVICE_WORKER_OK, status);
+
+ if (set_main_script_http_response_info) {
+ net::HttpResponseInfo http_info;
+ http_info.ssl_info.cert =
+ net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem");
+ EXPECT_TRUE(http_info.ssl_info.is_valid());
+ http_info.ssl_info.security_bits = 0x100;
+ // SSL3 TLS_DHE_RSA_WITH_AES_256_CBC_SHA
+ http_info.ssl_info.connection_status = 0x300039;
+ version_->SetMainScriptHttpResponseInfo(http_info);
+ }
scoped_ptr<ServiceWorkerProviderHost> provider_host(
- new ServiceWorkerProviderHost(
- kProcessID, kProviderID, helper_->context()->AsWeakPtr(), NULL));
- provider_host->AssociateRegistration(registration_.get());
- registration_->SetActiveVersion(version_.get());
+ new ServiceWorkerProviderHost(kProcessID, MSG_ROUTING_NONE, kProviderID,
+ SERVICE_WORKER_PROVIDER_FOR_WINDOW,
+ helper_->context()->AsWeakPtr(),
+ nullptr));
+ provider_host->SetDocumentUrl(GURL("http://example.com/"));
+ provider_host->AssociateRegistration(registration_.get(),
+ false /* notify_controllerchange */);
+ registration_->SetActiveVersion(version_);
ChromeBlobStorageContext* chrome_blob_storage_context =
ChromeBlobStorageContext::GetFor(browser_context_.get());
@@ -133,6 +183,7 @@ class ServiceWorkerURLRequestJobTest : public testing::Test {
url_request_job_factory_->SetProtocolHandler(
"http",
new MockHttpProtocolHandler(provider_host->AsWeakPtr(),
+ browser_context_->GetResourceContext(),
blob_storage_context->AsWeakPtr()));
url_request_job_factory_->SetProtocolHandler(
"blob", CreateMockBlobProtocolHandler(blob_storage_context));
@@ -142,8 +193,8 @@ class ServiceWorkerURLRequestJobTest : public testing::Test {
}
void TearDown() override {
- version_ = NULL;
- registration_ = NULL;
+ version_ = nullptr;
+ registration_ = nullptr;
helper_.reset();
}
@@ -151,10 +202,8 @@ class ServiceWorkerURLRequestJobTest : public testing::Test {
const std::string& expected_status_text,
const std::string& expected_response) {
request_ = url_request_context_.CreateRequest(
- GURL("http://example.com/foo.html"),
- net::DEFAULT_PRIORITY,
- &url_request_delegate_,
- NULL);
+ GURL("http://example.com/foo.html"), net::DEFAULT_PRIORITY,
+ &url_request_delegate_);
request_->set_method("GET");
request_->Start();
@@ -165,6 +214,14 @@ class ServiceWorkerURLRequestJobTest : public testing::Test {
EXPECT_EQ(expected_status_text,
request_->response_headers()->GetStatusText());
EXPECT_EQ(expected_response, url_request_delegate_.response_data());
+ const net::SSLInfo& ssl_info = request_->response_info().ssl_info;
+ EXPECT_TRUE(ssl_info.is_valid());
+ EXPECT_EQ(ssl_info.security_bits, 0x100);
+ EXPECT_EQ(ssl_info.connection_status, 0x300039);
+ }
+
+ bool HasInflightRequests() {
+ return version_->HasInflightRequests();
}
TestBrowserThreadBundle thread_bundle_;
@@ -179,7 +236,7 @@ class ServiceWorkerURLRequestJobTest : public testing::Test {
MockURLRequestDelegate url_request_delegate_;
scoped_ptr<net::URLRequest> request_;
- scoped_refptr<storage::BlobData> blob_data_;
+ scoped_ptr<storage::BlobDataBuilder> blob_data_;
private:
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerURLRequestJobTest);
@@ -190,13 +247,63 @@ TEST_F(ServiceWorkerURLRequestJobTest, Simple) {
TestRequest(200, "OK", std::string());
}
+class ProviderDeleteHelper : public EmbeddedWorkerTestHelper {
+ public:
+ ProviderDeleteHelper(int mock_render_process_id)
+ : EmbeddedWorkerTestHelper(base::FilePath(), mock_render_process_id) {}
+ ~ProviderDeleteHelper() override {}
+
+ protected:
+ void OnFetchEvent(int embedded_worker_id,
+ int request_id,
+ const ServiceWorkerFetchRequest& request) override {
+ context()->RemoveProviderHost(kProcessID, kProviderID);
+ 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, GURL())));
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ProviderDeleteHelper);
+};
+
+TEST_F(ServiceWorkerURLRequestJobTest, DeletedProviderHostOnFetchEvent) {
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
+ // Shouldn't crash if the ProviderHost is deleted prior to completion of
+ // the fetch event.
+ SetUpWithHelper(new ProviderDeleteHelper(kProcessID));
+
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
+ TestRequest(200, "OK", std::string());
+}
+
+TEST_F(ServiceWorkerURLRequestJobTest, DeletedProviderHostBeforeFetchEvent) {
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
+ request_ = url_request_context_.CreateRequest(
+ GURL("http://example.com/foo.html"), net::DEFAULT_PRIORITY,
+ &url_request_delegate_);
+
+ request_->set_method("GET");
+ request_->Start();
+ helper_->context()->RemoveProviderHost(kProcessID, kProviderID);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(request_->status().is_success());
+ EXPECT_EQ(500, request_->response_headers()->response_code());
+ EXPECT_EQ("Service Worker Response Error",
+ request_->response_headers()->GetStatusText());
+ EXPECT_EQ(std::string(), url_request_delegate_.response_data());
+}
+
// Responds to fetch events with a blob.
class BlobResponder : public EmbeddedWorkerTestHelper {
public:
BlobResponder(int mock_render_process_id,
const std::string& blob_uuid,
uint64 blob_size)
- : EmbeddedWorkerTestHelper(mock_render_process_id),
+ : EmbeddedWorkerTestHelper(base::FilePath(), mock_render_process_id),
blob_uuid_(blob_uuid),
blob_size_(blob_size) {}
~BlobResponder() override {}
@@ -209,13 +316,14 @@ class BlobResponder : public EmbeddedWorkerTestHelper {
embedded_worker_id,
request_id,
SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE,
- ServiceWorkerResponse(GURL(""),
+ ServiceWorkerResponse(GURL(),
200,
"OK",
blink::WebServiceWorkerResponseTypeDefault,
ServiceWorkerHeaderMap(),
blob_uuid_,
- blob_size_)));
+ blob_size_,
+ GURL())));
}
std::string blob_uuid_;
@@ -229,6 +337,7 @@ TEST_F(ServiceWorkerURLRequestJobTest, BlobResponse) {
ChromeBlobStorageContext* blob_storage_context =
ChromeBlobStorageContext::GetFor(browser_context_.get());
std::string expected_response;
+ expected_response.reserve((sizeof(kTestData) - 1) * 1024);
for (int i = 0; i < 1024; ++i) {
blob_data_->AppendData(kTestData);
expected_response += kTestData;
@@ -248,6 +357,308 @@ TEST_F(ServiceWorkerURLRequestJobTest, NonExistentBlobUUIDResponse) {
TestRequest(500, "Service Worker Response Error", std::string());
}
+// Responds to fetch events with a stream.
+class StreamResponder : public EmbeddedWorkerTestHelper {
+ public:
+ StreamResponder(int mock_render_process_id, const GURL& stream_url)
+ : EmbeddedWorkerTestHelper(base::FilePath(), mock_render_process_id),
+ stream_url_(stream_url) {}
+ ~StreamResponder() override {}
+
+ protected:
+ 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(GURL(),
+ 200,
+ "OK",
+ blink::WebServiceWorkerResponseTypeDefault,
+ ServiceWorkerHeaderMap(),
+ "",
+ 0,
+ stream_url_)));
+ }
+
+ const GURL stream_url_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(StreamResponder);
+};
+
+TEST_F(ServiceWorkerURLRequestJobTest, StreamResponse) {
+ const GURL stream_url("blob://stream");
+ StreamContext* stream_context =
+ GetStreamContextForResourceContext(
+ browser_context_->GetResourceContext());
+ scoped_refptr<Stream> stream =
+ new Stream(stream_context->registry(), nullptr, stream_url);
+ SetUpWithHelper(new StreamResponder(kProcessID, stream_url));
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
+ request_ = url_request_context_.CreateRequest(
+ GURL("http://example.com/foo.html"), net::DEFAULT_PRIORITY,
+ &url_request_delegate_);
+ request_->set_method("GET");
+ request_->Start();
+
+ std::string expected_response;
+ expected_response.reserve((sizeof(kTestData) - 1) * 1024);
+ for (int i = 0; i < 1024; ++i) {
+ expected_response += kTestData;
+ stream->AddData(kTestData, sizeof(kTestData) - 1);
+ }
+ stream->Finalize();
+
+ EXPECT_FALSE(HasInflightRequests());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(HasInflightRequests());
+ EXPECT_TRUE(request_->status().is_success());
+ EXPECT_EQ(200,
+ request_->response_headers()->response_code());
+ EXPECT_EQ("OK",
+ request_->response_headers()->GetStatusText());
+ EXPECT_EQ(expected_response, url_request_delegate_.response_data());
+ request_.reset();
+ EXPECT_FALSE(HasInflightRequests());
+}
+
+TEST_F(ServiceWorkerURLRequestJobTest, StreamResponse_DelayedRegistration) {
+ const GURL stream_url("blob://stream");
+ StreamContext* stream_context =
+ GetStreamContextForResourceContext(
+ browser_context_->GetResourceContext());
+ SetUpWithHelper(new StreamResponder(kProcessID, stream_url));
+
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
+ request_ = url_request_context_.CreateRequest(
+ GURL("http://example.com/foo.html"), net::DEFAULT_PRIORITY,
+ &url_request_delegate_);
+ request_->set_method("GET");
+ request_->Start();
+
+ scoped_refptr<Stream> stream =
+ new Stream(stream_context->registry(), nullptr, stream_url);
+ std::string expected_response;
+ expected_response.reserve((sizeof(kTestData) - 1) * 1024);
+ for (int i = 0; i < 1024; ++i) {
+ expected_response += kTestData;
+ stream->AddData(kTestData, sizeof(kTestData) - 1);
+ }
+ stream->Finalize();
+
+ EXPECT_FALSE(HasInflightRequests());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(HasInflightRequests());
+ EXPECT_TRUE(request_->status().is_success());
+ EXPECT_EQ(200,
+ request_->response_headers()->response_code());
+ EXPECT_EQ("OK",
+ request_->response_headers()->GetStatusText());
+ EXPECT_EQ(expected_response, url_request_delegate_.response_data());
+ request_.reset();
+ EXPECT_FALSE(HasInflightRequests());
+}
+
+
+TEST_F(ServiceWorkerURLRequestJobTest, StreamResponse_QuickFinalize) {
+ const GURL stream_url("blob://stream");
+ StreamContext* stream_context =
+ GetStreamContextForResourceContext(
+ browser_context_->GetResourceContext());
+ scoped_refptr<Stream> stream =
+ new Stream(stream_context->registry(), nullptr, stream_url);
+ std::string expected_response;
+ expected_response.reserve((sizeof(kTestData) - 1) * 1024);
+ for (int i = 0; i < 1024; ++i) {
+ expected_response += kTestData;
+ stream->AddData(kTestData, sizeof(kTestData) - 1);
+ }
+ stream->Finalize();
+ SetUpWithHelper(new StreamResponder(kProcessID, stream_url));
+
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
+ request_ = url_request_context_.CreateRequest(
+ GURL("http://example.com/foo.html"), net::DEFAULT_PRIORITY,
+ &url_request_delegate_);
+ request_->set_method("GET");
+ request_->Start();
+ EXPECT_FALSE(HasInflightRequests());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(HasInflightRequests());
+ EXPECT_TRUE(request_->status().is_success());
+ EXPECT_EQ(200,
+ request_->response_headers()->response_code());
+ EXPECT_EQ("OK",
+ request_->response_headers()->GetStatusText());
+ EXPECT_EQ(expected_response, url_request_delegate_.response_data());
+ request_.reset();
+ EXPECT_FALSE(HasInflightRequests());
+}
+
+
+TEST_F(ServiceWorkerURLRequestJobTest, StreamResponse_Flush) {
+ const GURL stream_url("blob://stream");
+ StreamContext* stream_context =
+ GetStreamContextForResourceContext(
+ browser_context_->GetResourceContext());
+ scoped_refptr<Stream> stream =
+ new Stream(stream_context->registry(), nullptr, stream_url);
+ SetUpWithHelper(new StreamResponder(kProcessID, stream_url));
+
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
+ request_ = url_request_context_.CreateRequest(
+ GURL("http://example.com/foo.html"), net::DEFAULT_PRIORITY,
+ &url_request_delegate_);
+ request_->set_method("GET");
+ request_->Start();
+ std::string expected_response;
+ expected_response.reserve((sizeof(kTestData) - 1) * 1024);
+ for (int i = 0; i < 1024; ++i) {
+ expected_response += kTestData;
+ stream->AddData(kTestData, sizeof(kTestData) - 1);;
+ stream->Flush();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(expected_response, url_request_delegate_.response_data());
+ }
+ stream->Finalize();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(request_->status().is_success());
+ EXPECT_EQ(200,
+ request_->response_headers()->response_code());
+ EXPECT_EQ("OK",
+ request_->response_headers()->GetStatusText());
+ EXPECT_EQ(expected_response, url_request_delegate_.response_data());
+}
+
+TEST_F(ServiceWorkerURLRequestJobTest, StreamResponseAndCancel) {
+ const GURL stream_url("blob://stream");
+ StreamContext* stream_context =
+ GetStreamContextForResourceContext(
+ browser_context_->GetResourceContext());
+ scoped_refptr<Stream> stream =
+ new Stream(stream_context->registry(), nullptr, stream_url);
+ ASSERT_EQ(stream.get(),
+ stream_context->registry()->GetStream(stream_url).get());
+ SetUpWithHelper(new StreamResponder(kProcessID, stream_url));
+
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
+ request_ = url_request_context_.CreateRequest(
+ GURL("http://example.com/foo.html"), net::DEFAULT_PRIORITY,
+ &url_request_delegate_);
+ request_->set_method("GET");
+ request_->Start();
+ EXPECT_FALSE(HasInflightRequests());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(HasInflightRequests());
+
+ std::string expected_response;
+ expected_response.reserve((sizeof(kTestData) - 1) * 1024);
+ for (int i = 0; i < 512; ++i) {
+ expected_response += kTestData;
+ stream->AddData(kTestData, sizeof(kTestData) - 1);
+ }
+ ASSERT_TRUE(stream_context->registry()->GetStream(stream_url).get());
+ request_->Cancel();
+ EXPECT_FALSE(HasInflightRequests());
+ ASSERT_FALSE(stream_context->registry()->GetStream(stream_url).get());
+ for (int i = 0; i < 512; ++i) {
+ expected_response += kTestData;
+ stream->AddData(kTestData, sizeof(kTestData) - 1);
+ }
+ stream->Finalize();
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(request_->status().is_success());
+}
+
+TEST_F(ServiceWorkerURLRequestJobTest,
+ StreamResponse_DelayedRegistrationAndCancel) {
+ const GURL stream_url("blob://stream");
+ StreamContext* stream_context =
+ GetStreamContextForResourceContext(
+ browser_context_->GetResourceContext());
+ SetUpWithHelper(new StreamResponder(kProcessID, stream_url));
+
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
+ request_ = url_request_context_.CreateRequest(
+ GURL("http://example.com/foo.html"), net::DEFAULT_PRIORITY,
+ &url_request_delegate_);
+ request_->set_method("GET");
+ request_->Start();
+ EXPECT_FALSE(HasInflightRequests());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(HasInflightRequests());
+ request_->Cancel();
+ EXPECT_FALSE(HasInflightRequests());
+
+ scoped_refptr<Stream> stream =
+ new Stream(stream_context->registry(), nullptr, stream_url);
+ // The stream should not be registered to the stream registry.
+ ASSERT_FALSE(stream_context->registry()->GetStream(stream_url).get());
+ for (int i = 0; i < 1024; ++i)
+ stream->AddData(kTestData, sizeof(kTestData) - 1);
+ stream->Finalize();
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(request_->status().is_success());
+}
+
+// Helper to simulate failing to dispatch a fetch event to a worker.
+class FailFetchHelper : public EmbeddedWorkerTestHelper {
+ public:
+ FailFetchHelper(int mock_render_process_id)
+ : EmbeddedWorkerTestHelper(base::FilePath(), mock_render_process_id) {}
+ ~FailFetchHelper() override {}
+
+ protected:
+ void OnFetchEvent(int embedded_worker_id,
+ int request_id,
+ const ServiceWorkerFetchRequest& request) override {
+ SimulateWorkerStopped(embedded_worker_id);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FailFetchHelper);
+};
+
+TEST_F(ServiceWorkerURLRequestJobTest, FailFetchDispatch) {
+ SetUpWithHelper(new FailFetchHelper(kProcessID));
+
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
+ request_ = url_request_context_.CreateRequest(
+ GURL("http://example.com/foo.html"), net::DEFAULT_PRIORITY,
+ &url_request_delegate_);
+ request_->set_method("GET");
+ request_->Start();
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(request_->status().is_success());
+ // We should have fallen back to network.
+ EXPECT_EQ(200, request_->GetResponseCode());
+ EXPECT_EQ("PASS", url_request_delegate_.response_data());
+ EXPECT_FALSE(HasInflightRequests());
+}
+
+// TODO(horo): Remove this test when crbug.com/485900 is fixed.
+TEST_F(ServiceWorkerURLRequestJobTest, MainScriptHTTPResponseInfoNotSet) {
+ // Shouldn't crash if MainScriptHttpResponseInfo is not set.
+ SetUpWithHelper(new EmbeddedWorkerTestHelper(base::FilePath(), kProcessID),
+ false);
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
+ request_ = url_request_context_.CreateRequest(
+ GURL("http://example.com/foo.html"), net::DEFAULT_PRIORITY,
+ &url_request_delegate_);
+ request_->set_method("GET");
+ request_->Start();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(request_->status().is_success());
+ EXPECT_EQ(200, request_->GetResponseCode());
+ EXPECT_EQ("", url_request_delegate_.response_data());
+}
+
// TODO(kinuko): Add more tests with different response data and also for
// FallbackToNetwork case.
diff --git a/chromium/content/browser/service_worker/service_worker_utils.cc b/chromium/content/browser/service_worker/service_worker_utils.cc
index edbe9f97b22..59748ee3a83 100644
--- a/chromium/content/browser/service_worker/service_worker_utils.cc
+++ b/chromium/content/browser/service_worker/service_worker_utils.cc
@@ -11,6 +11,27 @@
namespace content {
+namespace {
+
+bool PathContainsDisallowedCharacter(const GURL& url) {
+ std::string path = url.path();
+ DCHECK(base::IsStringUTF8(path));
+
+ // We should avoid these escaped characters in the path component because
+ // these can be handled differently depending on server implementation.
+ if (path.find("%2f") != std::string::npos ||
+ path.find("%2F") != std::string::npos) {
+ return true;
+ }
+ if (path.find("%5c") != std::string::npos ||
+ path.find("%5C") != std::string::npos) {
+ return true;
+ }
+ return false;
+}
+
+} // namespace
+
// static
bool ServiceWorkerUtils::ScopeMatches(const GURL& scope, const GURL& url) {
DCHECK(!scope.has_ref());
@@ -18,6 +39,69 @@ bool ServiceWorkerUtils::ScopeMatches(const GURL& scope, const GURL& url) {
return StartsWithASCII(url.spec(), scope.spec(), true);
}
+// static
+bool ServiceWorkerUtils::IsPathRestrictionSatisfied(
+ const GURL& scope,
+ const GURL& script_url,
+ const std::string* service_worker_allowed_header_value,
+ std::string* error_message) {
+ DCHECK(scope.is_valid());
+ DCHECK(!scope.has_ref());
+ DCHECK(script_url.is_valid());
+ DCHECK(!script_url.has_ref());
+ DCHECK(error_message);
+
+ if (ContainsDisallowedCharacter(scope, script_url, error_message))
+ return false;
+
+ std::string max_scope_string;
+ if (service_worker_allowed_header_value) {
+ GURL max_scope = script_url.Resolve(*service_worker_allowed_header_value);
+ if (!max_scope.is_valid()) {
+ *error_message = "An invalid Service-Worker-Allowed header value ('";
+ error_message->append(*service_worker_allowed_header_value);
+ error_message->append("') was received when fetching the script.");
+ return false;
+ }
+ max_scope_string = max_scope.path();
+ } else {
+ max_scope_string = script_url.Resolve(".").path();
+ }
+
+ std::string scope_string = scope.path();
+ if (!StartsWithASCII(scope_string, max_scope_string, true)) {
+ *error_message = "The path of the provided scope ('";
+ error_message->append(scope_string);
+ error_message->append("') is not under the max scope allowed (");
+ if (service_worker_allowed_header_value)
+ error_message->append("set by Service-Worker-Allowed: ");
+ error_message->append("'");
+ error_message->append(max_scope_string);
+ error_message->append(
+ "'). Adjust the scope, move the Service Worker script, or use the "
+ "Service-Worker-Allowed HTTP header to allow the scope.");
+ return false;
+ }
+ return true;
+}
+
+// static
+bool ServiceWorkerUtils::ContainsDisallowedCharacter(
+ const GURL& scope,
+ const GURL& script_url,
+ std::string* error_message) {
+ if (PathContainsDisallowedCharacter(scope) ||
+ PathContainsDisallowedCharacter(script_url)) {
+ *error_message = "The provided scope ('";
+ error_message->append(scope.spec());
+ error_message->append("') or scriptURL ('");
+ error_message->append(script_url.spec());
+ error_message->append("') includes a disallowed escape character.");
+ return true;
+ }
+ return false;
+}
+
bool LongestScopeMatcher::MatchLongest(const GURL& scope) {
if (!ServiceWorkerUtils::ScopeMatches(scope, url_))
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 81d6c44f17c..c03f4f2dccd 100644
--- a/chromium/content/browser/service_worker/service_worker_utils.h
+++ b/chromium/content/browser/service_worker/service_worker_utils.h
@@ -24,6 +24,20 @@ class ServiceWorkerUtils {
// Returns true if |scope| matches |url|.
CONTENT_EXPORT static bool ScopeMatches(const GURL& scope, const GURL& url);
+
+ // Returns true if the script at |script_url| is allowed to control |scope|
+ // according to Service Worker's path restriction policy. If
+ // |service_worker_allowed| is not null, it points to the
+ // Service-Worker-Allowed header value.
+ CONTENT_EXPORT static bool IsPathRestrictionSatisfied(
+ const GURL& scope,
+ const GURL& script_url,
+ const std::string* service_worker_allowed_header_value,
+ std::string* error_message);
+
+ static bool ContainsDisallowedCharacter(const GURL& scope,
+ const GURL& script_url,
+ std::string* error_message);
};
class CONTENT_EXPORT LongestScopeMatcher {
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 30e26b49d43..d7895a43bcd 100644
--- a/chromium/content/browser/service_worker/service_worker_utils_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_utils_unittest.cc
@@ -7,6 +7,26 @@
namespace content {
+namespace {
+
+bool IsPathRestrictionSatisfied(
+ const GURL& scope, const GURL& script_url) {
+ std::string error_message;
+ return ServiceWorkerUtils::IsPathRestrictionSatisfied(
+ scope, script_url, nullptr, &error_message);
+}
+
+bool IsPathRestrictionSatisfiedWithServiceWorkerAllowedHeader(
+ const GURL& scope,
+ const GURL& script_url,
+ const std::string& service_worker_allowed) {
+ std::string error_message;
+ return ServiceWorkerUtils::IsPathRestrictionSatisfied(
+ scope, script_url, &service_worker_allowed, &error_message);
+}
+
+} // namespace
+
TEST(ServiceWorkerUtilsTest, ScopeMatches) {
ASSERT_TRUE(ServiceWorkerUtils::ScopeMatches(
GURL("http://www.example.com/"), GURL("http://www.example.com/")));
@@ -82,7 +102,313 @@ TEST(ServiceWorkerUtilsTest, FindLongestScopeMatch) {
// "/xxx" should be matched longer than "/xx".
ASSERT_TRUE(matcher.MatchLongest(GURL("http://www.example.com/xxx")));
+ // The second call with the same URL should return false.
+ ASSERT_FALSE(matcher.MatchLongest(GURL("http://www.example.com/xxx")));
+
ASSERT_FALSE(matcher.MatchLongest(GURL("http://www.example.com/xxxx")));
}
+TEST(ServiceWorkerUtilsTest, PathRestriction_Basic) {
+ EXPECT_TRUE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/"),
+ GURL("http://example.com/sw.js")));
+ EXPECT_TRUE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/"),
+ GURL("http://example.com/sw.js")));
+ EXPECT_TRUE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/"),
+ GURL("http://example.com/foo/sw.js")));
+ EXPECT_TRUE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/bar"),
+ GURL("http://example.com/foo/sw.js")));
+ EXPECT_FALSE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/"),
+ GURL("http://example.com/foo/sw.js")));
+ EXPECT_FALSE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/bar/"),
+ GURL("http://example.com/foo/sw.js")));
+
+ // The scope is under the script directory, but that doesn't have the trailing
+ // slash. In this case, the check should be failed.
+ EXPECT_FALSE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo"),
+ GURL("http://example.com/foo/sw.js")));
+
+ // Query parameters should not affect the path restriction.
+ EXPECT_TRUE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/?query"),
+ GURL("http://example.com/sw.js")));
+ EXPECT_TRUE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/?query"),
+ GURL("http://example.com/sw.js")));
+ EXPECT_TRUE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/?query"),
+ GURL("http://example.com/foo/sw.js")));
+ EXPECT_FALSE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/?query"),
+ GURL("http://example.com/foo/sw.js")));
+ EXPECT_FALSE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/bar/query?"),
+ GURL("http://example.com/foo/sw.js")));
+
+ EXPECT_TRUE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/"),
+ GURL("http://example.com/sw.js?query")));
+ EXPECT_TRUE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/"),
+ GURL("http://example.com/sw.js?query")));
+ EXPECT_TRUE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/"),
+ GURL("http://example.com/foo/sw.js?query")));
+ EXPECT_FALSE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/"),
+ GURL("http://example.com/foo/sw.js?query")));
+ EXPECT_FALSE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/bar/"),
+ GURL("http://example.com/foo/sw.js?query")));
+
+ // Query parameter including a slash should not affect.
+ EXPECT_TRUE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/bar?key/value"),
+ GURL("http://example.com/foo/sw.js?key=value")));
+ EXPECT_TRUE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/bar?key=value"),
+ GURL("http://example.com/foo/sw.js?key/value")));
+}
+
+TEST(ServiceWorkerUtils, PathRestriction_SelfReference) {
+ // Self reference is canonicalized.
+ ASSERT_EQ(GURL("http://example.com/foo/bar"),
+ GURL("http://example.com/././foo/bar"));
+ EXPECT_TRUE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/"),
+ GURL("http://example.com/././foo/sw.js")));
+ EXPECT_TRUE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/././foo/"),
+ GURL("http://example.com/foo/sw.js")));
+ EXPECT_TRUE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/./"),
+ GURL("http://example.com/./foo/sw.js")));
+
+ // URL-encoded dot ('%2e') is also canonicalized.
+ ASSERT_EQ(GURL("http://example.com/foo/././bar"),
+ GURL("http://example.com/foo/%2e/%2e/bar"));
+ EXPECT_TRUE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/%2e/%2e/bar"),
+ GURL("http://example.com/foo/%2e/%2e/sw.js")));
+ EXPECT_TRUE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/bar"),
+ GURL("http://example.com/foo/%2e/%2e/sw.js")));
+ EXPECT_TRUE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/%2e/%2e/bar"),
+ GURL("http://example.com/foo/sw.js")));
+ EXPECT_TRUE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/%2e/bar"),
+ GURL("http://example.com/%2e/foo/sw.js")));
+
+ // URL-encoded dot ('%2E') is also canonicalized.
+ ASSERT_EQ(GURL("http://example.com/foo/././bar"),
+ GURL("http://example.com/foo/%2E/%2e/bar"));
+}
+
+TEST(ServiceWorkerUtilsTest, PathRestriction_ParentReference) {
+ // Parent reference is canonicalized.
+ ASSERT_EQ(GURL("http://example.com/foo/bar"),
+ GURL("http://example.com/foo/../foo/bar"));
+ EXPECT_TRUE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/bar"),
+ GURL("http://example.com/foo/../foo/sw.js")));
+ EXPECT_TRUE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/../foo/bar"),
+ GURL("http://example.com/foo/sw.js")));
+ EXPECT_TRUE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/bar/../bar"),
+ GURL("http://example.com/../foo/sw.js")));
+ EXPECT_TRUE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/../../../foo/bar"),
+ GURL("http://example.com/foo/sw.js")));
+ EXPECT_FALSE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/../bar"),
+ GURL("http://example.com/foo/sw.js")));
+
+ // URL-encoded dot ('%2e') is also canonicalized.
+ ASSERT_EQ(GURL("http://example.com/foo/../foo/bar"),
+ GURL("http://example.com/foo/%2e%2e/foo/bar"));
+ EXPECT_TRUE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/bar"),
+ GURL("http://example.com/foo/%2e%2e/foo/sw.js")));
+ EXPECT_TRUE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/%2e%2e/foo/bar"),
+ GURL("http://example.com/foo/sw.js")));
+ EXPECT_TRUE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/%2e%2e/foo/bar"),
+ GURL("http://example.com/%2e%2e/foo/sw.js")));
+ EXPECT_TRUE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/%2e%2e/%2e%2e/%2e%2e/foo/bar"),
+ GURL("http://example.com/foo/sw.js")));
+ EXPECT_FALSE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/%2e%2e/bar"),
+ GURL("http://example.com/foo/sw.js")));
+
+ // URL-encoded dot ('%2E') is also canonicalized.
+ ASSERT_EQ(GURL("http://example.com/foo/../foo/bar"),
+ GURL("http://example.com/foo/%2E%2E/foo/bar"));
+}
+
+TEST(ServiceWorkerUtilsTest, PathRestriction_ConsecutiveSlashes) {
+ // Consecutive slashes are not unified.
+ ASSERT_NE(GURL("http://example.com/foo/bar"),
+ GURL("http://example.com/foo///bar"));
+ EXPECT_FALSE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/bar"),
+ GURL("http://example.com/foo///sw.js")));
+ EXPECT_TRUE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo///bar"),
+ GURL("http://example.com/foo/sw.js")));
+ EXPECT_TRUE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo///bar"),
+ GURL("http://example.com/foo///sw.js")));
+}
+
+TEST(ServiceWorkerUtilsTest, PathRestriction_BackSlash) {
+ // A backslash is converted to a slash.
+ ASSERT_EQ(GURL("http://example.com/foo/bar"),
+ GURL("http://example.com/foo\\bar"));
+ EXPECT_TRUE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo\\bar"),
+ GURL("http://example.com/foo/sw.js")));
+
+ // Consecutive back slashes should not unified.
+ ASSERT_NE(GURL("http://example.com/foo\\\\\\bar"),
+ GURL("http://example.com/foo\\bar"));
+ EXPECT_FALSE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo\\bar"),
+ GURL("http://example.com/foo\\\\\\sw.js")));
+ EXPECT_TRUE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo\\\\\\bar"),
+ GURL("http://example.com/foo\\sw.js")));
+}
+
+TEST(ServiceWorkerUtilsTest, PathRestriction_DisallowedCharacter) {
+ // URL-encoded slash ('%2f') is not canonicalized.
+ ASSERT_NE(GURL("http://example.com/foo///bar"),
+ GURL("http://example.com/foo/%2f/bar"));
+ EXPECT_FALSE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo%2fbar/"),
+ GURL("http://example.com/foo/bar/sw.js")));
+ EXPECT_FALSE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/bar%2f"),
+ GURL("http://example.com/foo/bar/sw.js")));
+ EXPECT_FALSE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/bar/"),
+ GURL("http://example.com/foo/bar%2fsw.js")));
+ EXPECT_FALSE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/"),
+ GURL("http://example.com/foo/bar%2fsw.js")));
+
+ // URL-encoded slash ('%2F') is also not canonicalized.
+ ASSERT_NE(GURL("http://example.com/foo///bar"),
+ GURL("http://example.com/foo/%2F/bar"));
+ EXPECT_FALSE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo%2Fbar/"),
+ GURL("http://example.com/foo/bar/sw.js")));
+ EXPECT_FALSE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/bar%2F"),
+ GURL("http://example.com/foo/bar/sw.js")));
+ EXPECT_FALSE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/bar/"),
+ GURL("http://example.com/foo/bar%2Fsw.js")));
+ EXPECT_FALSE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/"),
+ GURL("http://example.com/foo/bar%2Fsw.js")));
+
+ // URL-encoded backslash ('%5c') is not canonicalized.
+ ASSERT_NE(GURL("http://example.com/foo/\\/bar"),
+ GURL("http://example.com/foo/%5c/bar"));
+ EXPECT_FALSE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo%5cbar/"),
+ GURL("http://example.com/foo/bar/sw.js")));
+ EXPECT_FALSE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/bar%5c"),
+ GURL("http://example.com/foo/bar/sw.js")));
+ EXPECT_FALSE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/bar/"),
+ GURL("http://example.com/foo/bar%5csw.js")));
+ EXPECT_FALSE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/"),
+ GURL("http://example.com/foo/bar%5csw.js")));
+
+ // URL-encoded backslash ('%5C') is also not canonicalized.
+ ASSERT_NE(GURL("http://example.com/foo/\\/bar"),
+ GURL("http://example.com/foo/%5C/bar"));
+ EXPECT_FALSE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo%5Cbar/"),
+ GURL("http://example.com/foo/bar/sw.js")));
+ EXPECT_FALSE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/bar%5C"),
+ GURL("http://example.com/foo/bar/sw.js")));
+ EXPECT_FALSE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/bar/"),
+ GURL("http://example.com/foo/bar%5Csw.js")));
+ EXPECT_FALSE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/"),
+ GURL("http://example.com/foo/bar%5Csw.js")));
+
+ // Query parameter should be able to have escaped characters.
+ EXPECT_TRUE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/bar?key%2fvalue"),
+ GURL("http://example.com/foo/sw.js?key/value")));
+ EXPECT_TRUE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/bar?key/value"),
+ GURL("http://example.com/foo/sw.js?key%2fvalue")));
+ EXPECT_TRUE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/bar?key%5cvalue"),
+ GURL("http://example.com/foo/sw.js?key\\value")));
+ EXPECT_TRUE(IsPathRestrictionSatisfied(
+ GURL("http://example.com/foo/bar?key\\value"),
+ GURL("http://example.com/foo/sw.js?key%5cvalue")));
+}
+
+TEST(ServiceWorkerUtils, PathRestriction_ServiceWorkerAllowed) {
+ // Setting header to default max scope changes nothing.
+ EXPECT_TRUE(IsPathRestrictionSatisfiedWithServiceWorkerAllowedHeader(
+ GURL("http://example.com/"), GURL("http://example.com/sw.js"),
+ "http://example.com/"));
+ EXPECT_FALSE(IsPathRestrictionSatisfiedWithServiceWorkerAllowedHeader(
+ GURL("http://example.com/"), GURL("http://example.com/foo/sw.js"),
+ "http://example.com/foo/"));
+
+ // Using the header to widen allowed scope.
+ EXPECT_TRUE(IsPathRestrictionSatisfiedWithServiceWorkerAllowedHeader(
+ GURL("http://example.com/"), GURL("http://example.com/foo/sw.js"),
+ "http://example.com/"));
+ EXPECT_TRUE(IsPathRestrictionSatisfiedWithServiceWorkerAllowedHeader(
+ GURL("http://example.com/"), GURL("http://example.com/foo/sw.js"), "/"));
+ EXPECT_TRUE(IsPathRestrictionSatisfiedWithServiceWorkerAllowedHeader(
+ GURL("http://example.com/"), GURL("http://example.com/foo/sw.js"), ".."));
+ EXPECT_TRUE(IsPathRestrictionSatisfiedWithServiceWorkerAllowedHeader(
+ GURL("http://example.com/bar/"), GURL("http://example.com/foo/sw.js"),
+ "../b"));
+ EXPECT_FALSE(IsPathRestrictionSatisfiedWithServiceWorkerAllowedHeader(
+ GURL("http://example.com/bar/"), GURL("http://example.com/foo/sw.js"),
+ "../c"));
+
+ // Using the header to restrict allowed scope.
+ EXPECT_FALSE(IsPathRestrictionSatisfiedWithServiceWorkerAllowedHeader(
+ GURL("http://example.com/"), GURL("http://example.com/sw.js"),
+ "http://example.com/foo/"));
+ EXPECT_FALSE(IsPathRestrictionSatisfiedWithServiceWorkerAllowedHeader(
+ GURL("http://example.com/"), GURL("http://example.com/sw.js"), "foo"));
+ EXPECT_TRUE(IsPathRestrictionSatisfiedWithServiceWorkerAllowedHeader(
+ GURL("http://example.com/foo/"), GURL("http://example.com/sw.js"),
+ "foo"));
+
+ // Empty string resolves to max scope of "http://www.example.com/sw.js".
+ EXPECT_FALSE(IsPathRestrictionSatisfiedWithServiceWorkerAllowedHeader(
+ GURL("http://example.com/"), GURL("http://example.com/sw.js"), ""));
+ EXPECT_TRUE(IsPathRestrictionSatisfiedWithServiceWorkerAllowedHeader(
+ GURL("http://example.com/sw.js/hi"), GURL("http://example.com/sw.js"),
+ ""));
+}
+
} // 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 30d9fd5a0a1..4299a26cbd2 100644
--- a/chromium/content/browser/service_worker/service_worker_version.cc
+++ b/chromium/content/browser/service_worker/service_worker_version.cc
@@ -5,32 +5,70 @@
#include "content/browser/service_worker/service_worker_version.h"
#include "base/command_line.h"
+#include "base/memory/ref_counted.h"
+#include "base/metrics/histogram_macros.h"
#include "base/stl_util.h"
#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
+#include "content/browser/bad_message.h"
+#include "content/browser/child_process_security_policy_impl.h"
+#include "content/browser/message_port_message_filter.h"
+#include "content/browser/message_port_service.h"
#include "content/browser/service_worker/embedded_worker_instance.h"
#include "content/browser/service_worker/embedded_worker_registry.h"
#include "content/browser/service_worker/service_worker_context_core.h"
+#include "content/browser/service_worker/service_worker_context_wrapper.h"
+#include "content/browser/service_worker/service_worker_metrics.h"
#include "content/browser/service_worker/service_worker_registration.h"
#include "content/browser/service_worker/service_worker_utils.h"
+#include "content/browser/storage_partition_impl.h"
#include "content/common/service_worker/service_worker_messages.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/page_navigator.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/common/child_process_host.h"
+#include "content/public/common/content_client.h"
#include "content/public/common/content_switches.h"
+#include "content/public/common/result_codes.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_response_info.h"
namespace content {
-typedef ServiceWorkerVersion::StatusCallback StatusCallback;
-typedef ServiceWorkerVersion::MessageCallback MessageCallback;
+using StatusCallback = ServiceWorkerVersion::StatusCallback;
+using ServiceWorkerClients = std::vector<ServiceWorkerClientInfo>;
+using GetClientsCallback =
+ base::Callback<void(scoped_ptr<ServiceWorkerClients>)>;
namespace {
-// 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.
+// Delay between the timeout timer firing.
+const int kTimeoutTimerDelaySeconds = 30;
+
+// Time to wait until stopping an idle worker.
+const int kIdleWorkerTimeoutSeconds = 30;
// Default delay for scheduled update.
const int kUpdateDelaySeconds = 1;
+// Timeout for waiting for a response to a ping.
+const int kPingTimeoutSeconds = 30;
+
+// If the SW was destructed while starting up, how many seconds it
+// had to start up for this to be considered a timeout occurrence.
+const int kDestructedStartingWorkerTimeoutThresholdSeconds = 5;
+
+const char kClaimClientsStateErrorMesage[] =
+ "Only the active worker can claim clients.";
+
+const char kClaimClientsShutdownErrorMesage[] =
+ "Failed to claim clients due to Service Worker system shutdown.";
+
void RunSoon(const base::Closure& callback) {
if (!callback.is_null())
base::MessageLoop::current()->PostTask(FROM_HERE, callback);
@@ -43,21 +81,40 @@ void RunCallbacks(ServiceWorkerVersion* version,
CallbackArray callbacks;
callbacks.swap(*callbacks_ptr);
scoped_refptr<ServiceWorkerVersion> protect(version);
- for (typename CallbackArray::const_iterator i = callbacks.begin();
- i != callbacks.end(); ++i)
- (*i).Run(arg);
+ for (const auto& callback : callbacks)
+ callback.Run(arg);
}
-template <typename IDMAP, typename Method, typename Params>
-void RunIDMapCallbacks(IDMAP* callbacks, Method method, const Params& params) {
+template <typename IDMAP, typename... Params>
+void RunIDMapCallbacks(IDMAP* callbacks, const Params&... params) {
typename IDMAP::iterator iter(callbacks);
while (!iter.IsAtEnd()) {
- DispatchToMethod(iter.GetCurrentValue(), method, params);
+ iter.GetCurrentValue()->Run(params...);
iter.Advance();
}
callbacks->Clear();
}
+template <typename CallbackType, typename... Params>
+bool RunIDMapCallback(IDMap<CallbackType, IDMapOwnPointer>* callbacks,
+ int request_id,
+ const Params&... params) {
+ CallbackType* callback = callbacks->Lookup(request_id);
+ if (!callback)
+ return false;
+
+ callback->Run(params...);
+ callbacks->Remove(request_id);
+ return true;
+}
+
+void RunStartWorkerCallback(
+ const StatusCallback& callback,
+ scoped_refptr<ServiceWorkerRegistration> protect,
+ ServiceWorkerStatusCode status) {
+ callback.Run(status);
+}
+
// A callback adapter to start a |task| after StartWorker.
void RunTaskAfterStartWorker(
base::WeakPtr<ServiceWorkerVersion> version,
@@ -87,33 +144,279 @@ void RunErrorFetchCallback(const ServiceWorkerVersion::FetchCallback& callback,
ServiceWorkerResponse());
}
+void RunErrorMessageCallback(
+ const std::vector<TransferredMessagePort>& sent_message_ports,
+ const ServiceWorkerVersion::StatusCallback& callback,
+ ServiceWorkerStatusCode status) {
+ // Transfering the message ports failed, so destroy the ports.
+ for (const TransferredMessagePort& port : sent_message_ports) {
+ MessagePortService::GetInstance()->ClosePort(port.id);
+ }
+ callback.Run(status);
+}
+
+void RunErrorCrossOriginConnectCallback(
+ const ServiceWorkerVersion::CrossOriginConnectCallback& callback,
+ ServiceWorkerStatusCode status) {
+ callback.Run(status, false /* accept_connection */);
+}
+
+using WindowOpenedCallback = base::Callback<void(int, int)>;
+
+// The WindowOpenedObserver class is a WebContentsObserver that will wait for a
+// new Window's WebContents to be initialized, run the |callback| passed to its
+// constructor then self destroy.
+// The callback will receive the process and frame ids. If something went wrong
+// those will be (kInvalidUniqueID, MSG_ROUTING_NONE).
+// The callback will be called in the IO thread.
+class WindowOpenedObserver : public WebContentsObserver {
+ public:
+ WindowOpenedObserver(WebContents* web_contents,
+ const WindowOpenedCallback& callback)
+ : WebContentsObserver(web_contents),
+ callback_(callback)
+ {}
+
+ void DidCommitProvisionalLoadForFrame(
+ RenderFrameHost* render_frame_host,
+ const GURL& validated_url,
+ ui::PageTransition transition_type) override {
+ DCHECK(web_contents());
+
+ if (render_frame_host != web_contents()->GetMainFrame())
+ return;
+
+ RunCallback(render_frame_host->GetProcess()->GetID(),
+ render_frame_host->GetRoutingID());
+ }
+
+ void RenderProcessGone(base::TerminationStatus status) override {
+ RunCallback(ChildProcessHost::kInvalidUniqueID, MSG_ROUTING_NONE);
+ }
+
+ void WebContentsDestroyed() override {
+ RunCallback(ChildProcessHost::kInvalidUniqueID, MSG_ROUTING_NONE);
+ }
+
+ private:
+ void RunCallback(int render_process_id, int render_frame_id) {
+ // After running the callback, |this| will stop observing, thus
+ // web_contents() should return nullptr and |RunCallback| should no longer
+ // be called. Then, |this| will self destroy.
+ DCHECK(web_contents());
+
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(callback_,
+ render_process_id,
+ render_frame_id));
+ Observe(nullptr);
+ base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
+ }
+
+ const WindowOpenedCallback callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(WindowOpenedObserver);
+};
+
+void DidOpenURL(const WindowOpenedCallback& callback,
+ WebContents* web_contents) {
+ DCHECK(web_contents);
+
+ new WindowOpenedObserver(web_contents, callback);
+}
+
+void OpenWindowOnUI(
+ const GURL& url,
+ const GURL& script_url,
+ int process_id,
+ const scoped_refptr<ServiceWorkerContextWrapper>& context_wrapper,
+ const WindowOpenedCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ BrowserContext* browser_context = context_wrapper->storage_partition()
+ ? context_wrapper->storage_partition()->browser_context()
+ : nullptr;
+ // We are shutting down.
+ if (!browser_context)
+ return;
+
+ RenderProcessHost* render_process_host =
+ RenderProcessHost::FromID(process_id);
+ if (render_process_host->IsIsolatedGuest()) {
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(callback,
+ ChildProcessHost::kInvalidUniqueID,
+ MSG_ROUTING_NONE));
+ return;
+ }
+
+ OpenURLParams params(
+ url, Referrer::SanitizeForRequest(
+ url, Referrer(script_url, blink::WebReferrerPolicyDefault)),
+ NEW_FOREGROUND_TAB, ui::PAGE_TRANSITION_AUTO_TOPLEVEL,
+ true /* is_renderer_initiated */);
+
+ GetContentClient()->browser()->OpenURL(
+ browser_context, params,
+ base::Bind(&DidOpenURL, callback));
+}
+
+void KillEmbeddedWorkerProcess(int process_id, ResultCode code) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ RenderProcessHost* render_process_host =
+ RenderProcessHost::FromID(process_id);
+ if (render_process_host->GetHandle() != base::kNullProcessHandle) {
+ bad_message::ReceivedBadMessage(render_process_host,
+ bad_message::SERVICE_WORKER_BAD_URL);
+ }
+}
+
+void ClearTick(base::TimeTicks* time) {
+ *time = base::TimeTicks();
+}
+
+void RestartTick(base::TimeTicks* time) {
+ *time = base::TimeTicks().Now();
+}
+
+base::TimeDelta GetTickDuration(const base::TimeTicks& time) {
+ if (time.is_null())
+ return base::TimeDelta();
+ return base::TimeTicks().Now() - time;
+}
+
+void OnGetWindowClientsFromUI(
+ // The tuple contains process_id, frame_id, client_uuid.
+ const std::vector<Tuple<int, int, std::string>>& clients_info,
+ const GURL& script_url,
+ const GetClientsCallback& callback) {
+ scoped_ptr<ServiceWorkerClients> clients(new ServiceWorkerClients);
+
+ for (const auto& it : clients_info) {
+ ServiceWorkerClientInfo info =
+ ServiceWorkerProviderHost::GetWindowClientInfoOnUI(get<0>(it),
+ get<1>(it));
+
+ // If the request to the provider_host returned an empty
+ // ServiceWorkerClientInfo, that means that it wasn't possible to associate
+ // it with a valid RenderFrameHost. It might be because the frame was killed
+ // or navigated in between.
+ if (info.IsEmpty())
+ continue;
+
+ // We can get info for a frame that was navigating end ended up with a
+ // different URL than expected. In such case, we should make sure to not
+ // expose cross-origin WindowClient.
+ if (info.url.GetOrigin() != script_url.GetOrigin())
+ continue;
+
+ info.client_uuid = get<2>(it);
+ clients->push_back(info);
+ }
+
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(callback, base::Passed(&clients)));
+}
+
+void AddWindowClient(ServiceWorkerProviderHost* host,
+ std::vector<Tuple<int, int, std::string>>* client_info) {
+ if (host->client_type() != blink::WebServiceWorkerClientTypeWindow)
+ return;
+ client_info->push_back(
+ MakeTuple(host->process_id(), host->frame_id(), host->client_uuid()));
+}
+
+void AddNonWindowClient(ServiceWorkerProviderHost* host,
+ const ServiceWorkerClientQueryOptions& options,
+ ServiceWorkerClients* clients) {
+ blink::WebServiceWorkerClientType host_client_type = host->client_type();
+ if (host_client_type == blink::WebServiceWorkerClientTypeWindow)
+ return;
+ if (options.client_type != blink::WebServiceWorkerClientTypeAll &&
+ options.client_type != host_client_type)
+ return;
+
+ ServiceWorkerClientInfo client_info(
+ blink::WebPageVisibilityStateHidden,
+ false, // is_focused
+ host->document_url(), REQUEST_CONTEXT_FRAME_TYPE_NONE, host_client_type);
+ client_info.client_uuid = host->client_uuid();
+ clients->push_back(client_info);
+}
+
+bool IsInstalled(ServiceWorkerVersion::Status status) {
+ switch (status) {
+ case ServiceWorkerVersion::NEW:
+ case ServiceWorkerVersion::INSTALLING:
+ return false;
+ case ServiceWorkerVersion::INSTALLED:
+ case ServiceWorkerVersion::ACTIVATING:
+ case ServiceWorkerVersion::ACTIVATED:
+ return true;
+ case ServiceWorkerVersion::REDUNDANT:
+ NOTREACHED() << "Cannot use REDUNDANT here.";
+ return false;
+ }
+ NOTREACHED() << "Unexpected status: " << status;
+ return false;
+}
+
} // namespace
+const int ServiceWorkerVersion::kStartWorkerTimeoutMinutes = 5;
+const int ServiceWorkerVersion::kRequestTimeoutMinutes = 5;
+
+class ServiceWorkerVersion::ServiceWorkerEventMetrics {
+ public:
+ ServiceWorkerEventMetrics() {}
+ ~ServiceWorkerEventMetrics() {
+ ServiceWorkerMetrics::RecordEventStatus(fired_events, handled_events);
+ }
+
+ void RecordEventStatus(bool handled) {
+ ++fired_events;
+ if (handled)
+ ++handled_events;
+ }
+
+ private:
+ size_t fired_events = 0;
+ size_t handled_events = 0;
+ DISALLOW_COPY_AND_ASSIGN(ServiceWorkerEventMetrics);
+};
+
ServiceWorkerVersion::ServiceWorkerVersion(
ServiceWorkerRegistration* registration,
const GURL& script_url,
int64 version_id,
base::WeakPtr<ServiceWorkerContextCore> context)
: version_id_(version_id),
- registration_id_(kInvalidServiceWorkerVersionId),
+ registration_id_(registration->id()),
script_url_(script_url),
+ scope_(registration->pattern()),
status_(NEW),
context_(context),
script_cache_map_(this, context),
- is_doomed_(false),
+ ping_state_(NOT_PINGING),
+ metrics_(new ServiceWorkerEventMetrics),
weak_factory_(this) {
DCHECK(context_);
DCHECK(registration);
- if (registration) {
- registration_id_ = registration->id();
- scope_ = registration->pattern();
- }
context_->AddLiveVersion(this);
embedded_worker_ = context_->embedded_worker_registry()->CreateWorker();
embedded_worker_->AddListener(this);
}
ServiceWorkerVersion::~ServiceWorkerVersion() {
+ // The user may have closed the tab waiting for SW to start up.
+ if (GetTickDuration(start_time_) >
+ base::TimeDelta::FromSeconds(
+ kDestructedStartingWorkerTimeoutThresholdSeconds)) {
+ DCHECK(timeout_timer_.IsRunning());
+ DCHECK(!embedded_worker_->devtools_attached());
+ RecordStartWorkerResult(SERVICE_WORKER_ERROR_TIMEOUT);
+ }
+
embedded_worker_->RemoveListener(this);
if (context_)
context_->RemoveLiveVersion(version_id_);
@@ -124,18 +427,18 @@ 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;
+ if (skip_waiting_ && status_ == ACTIVATED) {
+ for (int request_id : pending_skip_waiting_requests_)
+ DidSkipWaiting(request_id);
+ pending_skip_waiting_requests_.clear();
+ }
+
std::vector<base::Closure> callbacks;
callbacks.swap(status_change_callbacks_);
- for (std::vector<base::Closure>::const_iterator i = callbacks.begin();
- i != callbacks.end(); ++i) {
- (*i).Run();
- }
+ for (const auto& callback : callbacks)
+ callback.Run();
FOR_EACH_OBSERVER(Listener, listeners_, OnVersionStateChanged(this));
}
@@ -146,15 +449,18 @@ void ServiceWorkerVersion::RegisterStatusChangeCallback(
}
ServiceWorkerVersionInfo ServiceWorkerVersion::GetInfo() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- return ServiceWorkerVersionInfo(
- running_status(),
- status(),
- script_url(),
- version_id(),
- embedded_worker()->process_id(),
- embedded_worker()->thread_id(),
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ ServiceWorkerVersionInfo info(
+ running_status(), status(), script_url(), registration_id(), version_id(),
+ embedded_worker()->process_id(), embedded_worker()->thread_id(),
embedded_worker()->worker_devtools_agent_route_id());
+ if (!main_script_http_info_)
+ return info;
+ info.script_response_time = main_script_http_info_->response_time;
+ if (main_script_http_info_->headers)
+ main_script_http_info_->headers->GetLastModifiedValue(
+ &info.script_last_modified);
+ return info;
}
void ServiceWorkerVersion::StartWorker(const StatusCallback& callback) {
@@ -164,29 +470,25 @@ void ServiceWorkerVersion::StartWorker(const StatusCallback& callback) {
void ServiceWorkerVersion::StartWorker(
bool pause_after_download,
const StatusCallback& callback) {
- switch (running_status()) {
- case RUNNING:
- RunSoon(base::Bind(callback, SERVICE_WORKER_OK));
- return;
- case STOPPING:
- RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED));
- return;
- case STOPPED:
- 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_,
- pause_after_download,
- base::Bind(&ServiceWorkerVersion::OnStartMessageSent,
- weak_factory_.GetWeakPtr()));
- }
- return;
+ if (!context_) {
+ RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_ABORT));
+ return;
+ }
+ if (status_ == REDUNDANT) {
+ RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED));
+ return;
}
+ prestart_status_ = status_;
+
+ // Ensure the live registration during starting worker so that the worker can
+ // get associated with it in SWDispatcherHost::OnSetHostedVersionId().
+ context_->storage()->FindRegistrationForId(
+ registration_id_,
+ scope_.GetOrigin(),
+ base::Bind(&ServiceWorkerVersion::DidEnsureLiveRegistrationForStartWorker,
+ weak_factory_.GetWeakPtr(),
+ pause_after_download,
+ callback));
}
void ServiceWorkerVersion::StopWorker(const StatusCallback& callback) {
@@ -228,27 +530,46 @@ void ServiceWorkerVersion::StartUpdate() {
context_->GetLiveRegistration(registration_id_);
if (!registration || !registration->GetNewestVersion())
return;
- context_->UpdateServiceWorker(registration);
+ context_->UpdateServiceWorker(registration, false /* force_bypass_cache */);
}
-void ServiceWorkerVersion::SendMessage(
- const IPC::Message& message, const StatusCallback& callback) {
+void ServiceWorkerVersion::DispatchMessageEvent(
+ const base::string16& message,
+ const std::vector<TransferredMessagePort>& sent_message_ports,
+ const StatusCallback& callback) {
+ for (const TransferredMessagePort& port : sent_message_ports) {
+ MessagePortService::GetInstance()->HoldMessages(port.id);
+ }
+
+ DispatchMessageEventInternal(message, sent_message_ports, callback);
+}
+
+void ServiceWorkerVersion::DispatchMessageEventInternal(
+ const base::string16& message,
+ const std::vector<TransferredMessagePort>& sent_message_ports,
+ const StatusCallback& callback) {
if (running_status() != RUNNING) {
// Schedule calling this method after starting the worker.
- StartWorker(base::Bind(&RunTaskAfterStartWorker,
- weak_factory_.GetWeakPtr(), callback,
- base::Bind(&self::SendMessage,
- weak_factory_.GetWeakPtr(),
- message, callback)));
+ StartWorker(base::Bind(
+ &RunTaskAfterStartWorker, weak_factory_.GetWeakPtr(),
+ base::Bind(&RunErrorMessageCallback, sent_message_ports, callback),
+ base::Bind(&self::DispatchMessageEventInternal,
+ weak_factory_.GetWeakPtr(), message, sent_message_ports,
+ callback)));
return;
}
- ServiceWorkerStatusCode status = embedded_worker_->SendMessage(message);
+ MessagePortMessageFilter* filter =
+ embedded_worker_->message_port_message_filter();
+ std::vector<int> new_routing_ids;
+ filter->UpdateMessagePortsWithNewRoutes(sent_message_ports, &new_routing_ids);
+ ServiceWorkerStatusCode status =
+ embedded_worker_->SendMessage(ServiceWorkerMsg_MessageToWorker(
+ message, sent_message_ports, new_routing_ids));
RunSoon(base::Bind(callback, status));
}
void ServiceWorkerVersion::DispatchInstallEvent(
- int active_version_id,
const StatusCallback& callback) {
DCHECK_EQ(INSTALLING, status()) << status();
@@ -260,10 +581,9 @@ void ServiceWorkerVersion::DispatchInstallEvent(
callback,
base::Bind(&self::DispatchInstallEventAfterStartWorker,
weak_factory_.GetWeakPtr(),
- active_version_id,
callback)));
} else {
- DispatchInstallEventAfterStartWorker(active_version_id, callback);
+ DispatchInstallEventAfterStartWorker(callback);
}
}
@@ -306,7 +626,7 @@ void ServiceWorkerVersion::DispatchFetchEvent(
prepare_callback.Run();
- int request_id = fetch_callbacks_.Add(new FetchCallback(fetch_callback));
+ int request_id = AddRequest(fetch_callback, &fetch_callbacks_, REQUEST_FETCH);
ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
ServiceWorkerMsg_FetchEvent(request_id, request));
if (status != SERVICE_WORKER_OK) {
@@ -320,7 +640,7 @@ void ServiceWorkerVersion::DispatchFetchEvent(
void ServiceWorkerVersion::DispatchSyncEvent(const StatusCallback& callback) {
DCHECK_EQ(ACTIVATED, status()) << status();
- if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableServiceWorkerSync)) {
callback.Run(SERVICE_WORKER_ERROR_ABORT);
return;
@@ -336,7 +656,7 @@ void ServiceWorkerVersion::DispatchSyncEvent(const StatusCallback& callback) {
return;
}
- int request_id = sync_callbacks_.Add(new StatusCallback(callback));
+ int request_id = AddRequest(callback, &sync_callbacks_, REQUEST_SYNC);
ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
ServiceWorkerMsg_SyncEvent(request_id));
if (status != SERVICE_WORKER_OK) {
@@ -345,16 +665,35 @@ void ServiceWorkerVersion::DispatchSyncEvent(const StatusCallback& callback) {
}
}
-void ServiceWorkerVersion::DispatchPushEvent(const StatusCallback& callback,
- const std::string& data) {
+void ServiceWorkerVersion::DispatchNotificationClickEvent(
+ const StatusCallback& callback,
+ int64_t persistent_notification_id,
+ const PlatformNotificationData& notification_data) {
DCHECK_EQ(ACTIVATED, status()) << status();
-
- if (!CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableExperimentalWebPlatformFeatures)) {
- callback.Run(SERVICE_WORKER_ERROR_ABORT);
+ if (running_status() != RUNNING) {
+ // Schedule calling this method after starting the worker.
+ StartWorker(base::Bind(
+ &RunTaskAfterStartWorker, weak_factory_.GetWeakPtr(), callback,
+ base::Bind(&self::DispatchNotificationClickEvent,
+ weak_factory_.GetWeakPtr(), callback,
+ persistent_notification_id, notification_data)));
return;
}
+ int request_id = AddRequest(callback, &notification_click_callbacks_,
+ REQUEST_NOTIFICATION_CLICK);
+ ServiceWorkerStatusCode status =
+ embedded_worker_->SendMessage(ServiceWorkerMsg_NotificationClickEvent(
+ request_id, persistent_notification_id, notification_data));
+ if (status != SERVICE_WORKER_OK) {
+ notification_click_callbacks_.Remove(request_id);
+ RunSoon(base::Bind(callback, status));
+ }
+}
+
+void ServiceWorkerVersion::DispatchPushEvent(const StatusCallback& callback,
+ const std::string& data) {
+ DCHECK_EQ(ACTIVATED, status()) << status();
if (running_status() != RUNNING) {
// Schedule calling this method after starting the worker.
StartWorker(base::Bind(&RunTaskAfterStartWorker,
@@ -365,7 +704,7 @@ void ServiceWorkerVersion::DispatchPushEvent(const StatusCallback& callback,
return;
}
- int request_id = push_callbacks_.Add(new StatusCallback(callback));
+ int request_id = AddRequest(callback, &push_callbacks_, REQUEST_PUSH);
ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
ServiceWorkerMsg_PushEvent(request_id, data));
if (status != SERVICE_WORKER_OK) {
@@ -381,7 +720,7 @@ void ServiceWorkerVersion::DispatchGeofencingEvent(
const blink::WebCircularGeofencingRegion& region) {
DCHECK_EQ(ACTIVATED, status()) << status();
- if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableExperimentalWebPlatformFeatures)) {
callback.Run(SERVICE_WORKER_ERROR_ABORT);
return;
@@ -401,7 +740,8 @@ void ServiceWorkerVersion::DispatchGeofencingEvent(
return;
}
- int request_id = geofencing_callbacks_.Add(new StatusCallback(callback));
+ int request_id =
+ AddRequest(callback, &geofencing_callbacks_, REQUEST_GEOFENCING);
ServiceWorkerStatusCode status =
embedded_worker_->SendMessage(ServiceWorkerMsg_GeofencingEvent(
request_id, event_type, region_id, region));
@@ -411,29 +751,99 @@ void ServiceWorkerVersion::DispatchGeofencingEvent(
}
}
+void ServiceWorkerVersion::DispatchCrossOriginConnectEvent(
+ const CrossOriginConnectCallback& callback,
+ const NavigatorConnectClient& client) {
+ DCHECK_EQ(ACTIVATED, status()) << status();
+
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableExperimentalWebPlatformFeatures)) {
+ callback.Run(SERVICE_WORKER_ERROR_ABORT, false);
+ return;
+ }
+
+ if (running_status() != RUNNING) {
+ // Schedule calling this method after starting the worker.
+ StartWorker(
+ base::Bind(&RunTaskAfterStartWorker, weak_factory_.GetWeakPtr(),
+ base::Bind(&RunErrorCrossOriginConnectCallback, callback),
+ base::Bind(&self::DispatchCrossOriginConnectEvent,
+ weak_factory_.GetWeakPtr(), callback, client)));
+ return;
+ }
+
+ int request_id = AddRequest(callback, &cross_origin_connect_callbacks_,
+ REQUEST_CROSS_ORIGIN_CONNECT);
+ ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
+ ServiceWorkerMsg_CrossOriginConnectEvent(request_id, client));
+ if (status != SERVICE_WORKER_OK) {
+ cross_origin_connect_callbacks_.Remove(request_id);
+ RunSoon(base::Bind(callback, status, false));
+ }
+}
+
+void ServiceWorkerVersion::DispatchCrossOriginMessageEvent(
+ const NavigatorConnectClient& client,
+ const base::string16& message,
+ const std::vector<TransferredMessagePort>& sent_message_ports,
+ const StatusCallback& callback) {
+ // Unlike in the case of DispatchMessageEvent, here the caller is assumed to
+ // have already put all the sent message ports on hold. So no need to do that
+ // here again.
+
+ if (running_status() != RUNNING) {
+ // Schedule calling this method after starting the worker.
+ StartWorker(base::Bind(
+ &RunTaskAfterStartWorker, weak_factory_.GetWeakPtr(),
+ base::Bind(&RunErrorMessageCallback, sent_message_ports, callback),
+ base::Bind(&self::DispatchCrossOriginMessageEvent,
+ weak_factory_.GetWeakPtr(), client, message,
+ sent_message_ports, callback)));
+ return;
+ }
+
+ MessagePortMessageFilter* filter =
+ embedded_worker_->message_port_message_filter();
+ std::vector<int> new_routing_ids;
+ filter->UpdateMessagePortsWithNewRoutes(sent_message_ports, &new_routing_ids);
+ ServiceWorkerStatusCode status =
+ embedded_worker_->SendMessage(ServiceWorkerMsg_CrossOriginMessageToWorker(
+ client, message, sent_message_ports, new_routing_ids));
+ RunSoon(base::Bind(callback, status));
+}
+
void ServiceWorkerVersion::AddControllee(
ServiceWorkerProviderHost* provider_host) {
- DCHECK(!ContainsKey(controllee_map_, provider_host));
- int controllee_id = controllee_by_id_.Add(provider_host);
- controllee_map_[provider_host] = controllee_id;
- if (stop_worker_timer_.IsRunning())
- stop_worker_timer_.Stop();
+ const std::string& uuid = provider_host->client_uuid();
+ CHECK(!provider_host->client_uuid().empty());
+ DCHECK(!ContainsKey(controllee_map_, uuid));
+ controllee_map_[uuid] = provider_host;
+ // Keep the worker alive a bit longer right after a new controllee is added.
+ RestartTick(&idle_time_);
}
void ServiceWorkerVersion::RemoveControllee(
ServiceWorkerProviderHost* provider_host) {
- ControlleeMap::iterator found = controllee_map_.find(provider_host);
- DCHECK(found != controllee_map_.end());
- controllee_by_id_.Remove(found->second);
- controllee_map_.erase(found);
+ const std::string& uuid = provider_host->client_uuid();
+ DCHECK(ContainsKey(controllee_map_, uuid));
+ controllee_map_.erase(uuid);
if (HasControllee())
return;
FOR_EACH_OBSERVER(Listener, listeners_, OnNoControllees(this));
- if (is_doomed_) {
- DoomInternal();
- return;
- }
- ScheduleStopWorker();
+}
+
+void ServiceWorkerVersion::AddStreamingURLRequestJob(
+ const ServiceWorkerURLRequestJob* request_job) {
+ DCHECK(streaming_url_request_jobs_.find(request_job) ==
+ streaming_url_request_jobs_.end());
+ streaming_url_request_jobs_.insert(request_job);
+}
+
+void ServiceWorkerVersion::RemoveStreamingURLRequestJob(
+ const ServiceWorkerURLRequestJob* request_job) {
+ streaming_url_request_jobs_.erase(request_job);
+ if (is_redundant())
+ StopWorkerIfIdle();
}
void ServiceWorkerVersion::AddListener(Listener* listener) {
@@ -444,65 +854,153 @@ void ServiceWorkerVersion::RemoveListener(Listener* listener) {
listeners_.RemoveObserver(listener);
}
+void ServiceWorkerVersion::ReportError(ServiceWorkerStatusCode status,
+ const std::string& status_message) {
+ if (status_message.empty()) {
+ OnReportException(base::UTF8ToUTF16(ServiceWorkerStatusToString(status)),
+ -1, -1, GURL());
+ } else {
+ OnReportException(base::UTF8ToUTF16(status_message), -1, -1, GURL());
+ }
+}
+
+void ServiceWorkerVersion::SetStartWorkerStatusCode(
+ ServiceWorkerStatusCode status) {
+ start_worker_status_ = status;
+}
+
void ServiceWorkerVersion::Doom() {
- if (is_doomed_)
+ DCHECK(!HasControllee());
+ SetStatus(REDUNDANT);
+ StopWorkerIfIdle();
+ if (!context_)
+ return;
+ std::vector<ServiceWorkerDatabase::ResourceRecord> resources;
+ script_cache_map_.GetResources(&resources);
+ context_->storage()->PurgeResources(resources);
+}
+
+void ServiceWorkerVersion::SetDevToolsAttached(bool attached) {
+ embedded_worker()->set_devtools_attached(attached);
+ if (attached) {
+ // TODO(falken): Canceling the timeouts when debugging could cause
+ // heisenbugs; we should instead run them as normal show an educational
+ // message in DevTools when they occur. crbug.com/470419
+
+ // Don't record the startup time metric once DevTools is attached.
+ ClearTick(&start_time_);
+ skip_recording_startup_time_ = true;
+
+ // Cancel request timeouts.
+ SetAllRequestTimes(base::TimeTicks());
return;
- is_doomed_ = true;
- if (!HasControllee())
- DoomInternal();
+ }
+ if (!start_callbacks_.empty()) {
+ // Reactivate the timer for start timeout.
+ DCHECK(timeout_timer_.IsRunning());
+ DCHECK(running_status() == STARTING || running_status() == STOPPING)
+ << running_status();
+ RestartTick(&start_time_);
+ }
+
+ // Reactivate request timeouts.
+ SetAllRequestTimes(base::TimeTicks::Now());
+}
+
+void ServiceWorkerVersion::SetMainScriptHttpResponseInfo(
+ const net::HttpResponseInfo& http_info) {
+ main_script_http_info_.reset(new net::HttpResponseInfo(http_info));
+ FOR_EACH_OBSERVER(Listener, listeners_,
+ OnMainScriptHttpResponseInfoSet(this));
+}
+
+const net::HttpResponseInfo*
+ServiceWorkerVersion::GetMainScriptHttpResponseInfo() {
+ return main_script_http_info_.get();
+}
+
+ServiceWorkerVersion::RequestInfo::RequestInfo(int id, RequestType type)
+ : id(id), type(type), time(base::TimeTicks::Now()) {
+}
+
+ServiceWorkerVersion::RequestInfo::~RequestInfo() {
+}
+
+void ServiceWorkerVersion::OnScriptLoaded() {
+ DCHECK_EQ(STARTING, running_status());
+ // Activate ping/pong now that JavaScript execution will start.
+ ping_state_ = PINGING;
+}
+
+void ServiceWorkerVersion::OnStarting() {
+ FOR_EACH_OBSERVER(Listener, listeners_, OnRunningStateChanged(this));
}
void ServiceWorkerVersion::OnStarted() {
DCHECK_EQ(RUNNING, running_status());
- DCHECK(cache_listener_.get());
- if (status() == ACTIVATED && !HasControllee())
- ScheduleStopWorker();
+ RestartTick(&idle_time_);
+
// Fire all start callbacks.
+ scoped_refptr<ServiceWorkerVersion> protect(this);
RunCallbacks(this, &start_callbacks_, SERVICE_WORKER_OK);
- FOR_EACH_OBSERVER(Listener, listeners_, OnWorkerStarted(this));
+ FOR_EACH_OBSERVER(Listener, listeners_, OnRunningStateChanged(this));
+}
+
+void ServiceWorkerVersion::OnStopping() {
+ FOR_EACH_OBSERVER(Listener, listeners_, OnRunningStateChanged(this));
}
-void ServiceWorkerVersion::OnStopped() {
+void ServiceWorkerVersion::OnStopped(
+ EmbeddedWorkerInstance::Status old_status) {
DCHECK_EQ(STOPPED, running_status());
scoped_refptr<ServiceWorkerVersion> protect(this);
+ bool should_restart = !is_redundant() && !start_callbacks_.empty() &&
+ (old_status != EmbeddedWorkerInstance::STARTING);
+
+ StopTimeoutTimer();
+ if (ping_state_ == PING_TIMED_OUT)
+ should_restart = false;
+
// Fire all stop callbacks.
RunCallbacks(this, &stop_callbacks_, SERVICE_WORKER_OK);
- // Let all start callbacks fail.
- RunCallbacks(
- this, &start_callbacks_, SERVICE_WORKER_ERROR_START_WORKER_FAILED);
+ if (!should_restart) {
+ // Let all start callbacks fail.
+ RunCallbacks(this, &start_callbacks_,
+ DeduceStartWorkerFailureReason(
+ SERVICE_WORKER_ERROR_START_WORKER_FAILED));
+ }
// Let all message callbacks fail (this will also fire and clear all
// callbacks for events).
// TODO(kinuko): Consider if we want to add queue+resend mechanism here.
RunIDMapCallbacks(&activate_callbacks_,
- &StatusCallback::Run,
- MakeTuple(SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED));
+ SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED);
RunIDMapCallbacks(&install_callbacks_,
- &StatusCallback::Run,
- MakeTuple(SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED));
+ SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED);
RunIDMapCallbacks(&fetch_callbacks_,
- &FetchCallback::Run,
- MakeTuple(SERVICE_WORKER_ERROR_FAILED,
- SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK,
- ServiceWorkerResponse()));
+ SERVICE_WORKER_ERROR_FAILED,
+ SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK,
+ ServiceWorkerResponse());
RunIDMapCallbacks(&sync_callbacks_,
- &StatusCallback::Run,
- MakeTuple(SERVICE_WORKER_ERROR_FAILED));
+ SERVICE_WORKER_ERROR_FAILED);
+ RunIDMapCallbacks(&notification_click_callbacks_,
+ SERVICE_WORKER_ERROR_FAILED);
RunIDMapCallbacks(&push_callbacks_,
- &StatusCallback::Run,
- MakeTuple(SERVICE_WORKER_ERROR_FAILED));
+ SERVICE_WORKER_ERROR_FAILED);
RunIDMapCallbacks(&geofencing_callbacks_,
- &StatusCallback::Run,
- MakeTuple(SERVICE_WORKER_ERROR_FAILED));
+ SERVICE_WORKER_ERROR_FAILED);
+ RunIDMapCallbacks(&cross_origin_connect_callbacks_,
+ SERVICE_WORKER_ERROR_FAILED,
+ false);
+
+ streaming_url_request_jobs_.clear();
- FOR_EACH_OBSERVER(Listener, listeners_, OnWorkerStopped(this));
+ FOR_EACH_OBSERVER(Listener, listeners_, OnRunningStateChanged(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();
+ if (should_restart)
+ StartWorkerInternal(false /* pause_after_download */);
}
void ServiceWorkerVersion::OnReportException(
@@ -535,8 +1033,8 @@ void ServiceWorkerVersion::OnReportConsoleMessage(int source_identifier,
bool ServiceWorkerVersion::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(ServiceWorkerVersion, message)
- IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GetClientDocuments,
- OnGetClientDocuments)
+ IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GetClients,
+ OnGetClients)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ActivateEventFinished,
OnActivateEventFinished)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_InstallEventFinished,
@@ -545,32 +1043,50 @@ bool ServiceWorkerVersion::OnMessageReceived(const IPC::Message& message) {
OnFetchEventFinished)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SyncEventFinished,
OnSyncEventFinished)
+ IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_NotificationClickEventFinished,
+ OnNotificationClickEventFinished)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PushEventFinished,
OnPushEventFinished)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GeofencingEventFinished,
OnGeofencingEventFinished)
- IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToDocument,
- OnPostMessageToDocument)
+ IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CrossOriginConnectEventFinished,
+ OnCrossOriginConnectEventFinished)
+ IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_OpenWindow,
+ OnOpenWindow)
+ IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SetCachedMetadata,
+ OnSetCachedMetadata)
+ IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ClearCachedMetadata,
+ OnClearCachedMetadata)
+ IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToClient,
+ OnPostMessageToClient)
+ IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_FocusClient,
+ OnFocusClient)
+ IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SkipWaiting,
+ OnSkipWaiting)
+ IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ClaimClients,
+ OnClaimClients)
+ IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_Pong, OnPongFromWorker)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
-void ServiceWorkerVersion::OnStartMessageSent(
+void ServiceWorkerVersion::OnStartSentAndScriptEvaluated(
ServiceWorkerStatusCode status) {
- if (status != SERVICE_WORKER_OK)
- RunCallbacks(this, &start_callbacks_, status);
+ if (status != SERVICE_WORKER_OK) {
+ RunCallbacks(this, &start_callbacks_,
+ DeduceStartWorkerFailureReason(status));
+ }
}
void ServiceWorkerVersion::DispatchInstallEventAfterStartWorker(
- int active_version_id,
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));
+ int request_id = AddRequest(callback, &install_callbacks_, REQUEST_INSTALL);
ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
- ServiceWorkerMsg_InstallEvent(request_id, active_version_id));
+ ServiceWorkerMsg_InstallEvent(request_id));
if (status != SERVICE_WORKER_OK) {
install_callbacks_.Remove(request_id);
RunSoon(base::Bind(callback, status));
@@ -582,7 +1098,7 @@ void ServiceWorkerVersion::DispatchActivateEventAfterStartWorker(
DCHECK_EQ(RUNNING, running_status())
<< "Worker stopped too soon after it was started.";
- int request_id = activate_callbacks_.Add(new StatusCallback(callback));
+ int request_id = AddRequest(callback, &activate_callbacks_, REQUEST_ACTIVATE);
ServiceWorkerStatusCode status =
embedded_worker_->SendMessage(ServiceWorkerMsg_ActivateEvent(request_id));
if (status != SERVICE_WORKER_OK) {
@@ -591,20 +1107,42 @@ 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();
+void ServiceWorkerVersion::OnGetClients(
+ int request_id,
+ const ServiceWorkerClientQueryOptions& options) {
+ TRACE_EVENT_ASYNC_BEGIN2(
+ "ServiceWorker", "ServiceWorkerVersion::OnGetClients", request_id,
+ "client_type", options.client_type, "include_uncontrolled",
+ options.include_uncontrolled);
+
+ if (controllee_map_.empty() && !options.include_uncontrolled) {
+ OnGetClientsFinished(request_id, std::vector<ServiceWorkerClientInfo>());
+ return;
}
- // Don't bother if it's no longer running.
- if (running_status() == RUNNING) {
- embedded_worker_->SendMessage(
- ServiceWorkerMsg_DidGetClientDocuments(request_id, client_ids));
+
+ // For Window clients we want to query the info on the UI thread first.
+ if (options.client_type == blink::WebServiceWorkerClientTypeWindow ||
+ options.client_type == blink::WebServiceWorkerClientTypeAll) {
+ GetWindowClients(request_id, options);
+ return;
}
+
+ ServiceWorkerClients clients;
+ GetNonWindowClients(request_id, options, &clients);
+ OnGetClientsFinished(request_id, clients);
+}
+
+void ServiceWorkerVersion::OnGetClientsFinished(
+ int request_id,
+ const ServiceWorkerClients& clients) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ TRACE_EVENT_ASYNC_END1("ServiceWorker", "ServiceWorkerVersion::OnGetClients",
+ request_id, "The number of clients", clients.size());
+
+ if (running_status() != RUNNING)
+ return;
+ embedded_worker_->SendMessage(
+ ServiceWorkerMsg_DidGetClients(request_id, clients));
}
void ServiceWorkerVersion::OnActivateEventFinished(
@@ -628,13 +1166,15 @@ void ServiceWorkerVersion::OnActivateEventFinished(
scoped_refptr<ServiceWorkerVersion> protect(this);
callback->Run(rv);
- activate_callbacks_.Remove(request_id);
+ RemoveCallbackAndStopIfRedundant(&activate_callbacks_, request_id);
}
void ServiceWorkerVersion::OnInstallEventFinished(
int request_id,
blink::WebServiceWorkerEventResult result) {
- DCHECK_EQ(INSTALLING, status()) << status();
+ // Status is REDUNDANT if the worker was doomed while handling the install
+ // event, and finished handling before being terminated.
+ DCHECK(status() == INSTALLING || status() == REDUNDANT) << status();
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerVersion::OnInstallEventFinished");
@@ -649,7 +1189,7 @@ void ServiceWorkerVersion::OnInstallEventFinished(
scoped_refptr<ServiceWorkerVersion> protect(this);
callback->Run(status);
- install_callbacks_.Remove(request_id);
+ RemoveCallbackAndStopIfRedundant(&install_callbacks_, request_id);
}
void ServiceWorkerVersion::OnFetchEventFinished(
@@ -665,9 +1205,13 @@ void ServiceWorkerVersion::OnFetchEventFinished(
return;
}
+ // TODO(kinuko): Record other event statuses too.
+ const bool handled = (result == SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE);
+ metrics_->RecordEventStatus(handled);
+
scoped_refptr<ServiceWorkerVersion> protect(this);
callback->Run(SERVICE_WORKER_OK, result, response);
- fetch_callbacks_.Remove(request_id);
+ RemoveCallbackAndStopIfRedundant(&fetch_callbacks_, request_id);
}
void ServiceWorkerVersion::OnSyncEventFinished(
@@ -683,12 +1227,29 @@ void ServiceWorkerVersion::OnSyncEventFinished(
scoped_refptr<ServiceWorkerVersion> protect(this);
callback->Run(SERVICE_WORKER_OK);
- sync_callbacks_.Remove(request_id);
+ RemoveCallbackAndStopIfRedundant(&sync_callbacks_, request_id);
}
-void ServiceWorkerVersion::OnPushEventFinished(
+void ServiceWorkerVersion::OnNotificationClickEventFinished(
int request_id) {
TRACE_EVENT1("ServiceWorker",
+ "ServiceWorkerVersion::OnNotificationClickEventFinished",
+ "Request id", request_id);
+ StatusCallback* callback = notification_click_callbacks_.Lookup(request_id);
+ if (!callback) {
+ NOTREACHED() << "Got unexpected message: " << request_id;
+ return;
+ }
+
+ scoped_refptr<ServiceWorkerVersion> protect(this);
+ callback->Run(SERVICE_WORKER_OK);
+ RemoveCallbackAndStopIfRedundant(&notification_click_callbacks_, request_id);
+}
+
+void ServiceWorkerVersion::OnPushEventFinished(
+ int request_id,
+ blink::WebServiceWorkerEventResult result) {
+ TRACE_EVENT1("ServiceWorker",
"ServiceWorkerVersion::OnPushEventFinished",
"Request id", request_id);
StatusCallback* callback = push_callbacks_.Lookup(request_id);
@@ -696,10 +1257,13 @@ void ServiceWorkerVersion::OnPushEventFinished(
NOTREACHED() << "Got unexpected message: " << request_id;
return;
}
+ ServiceWorkerStatusCode status = SERVICE_WORKER_OK;
+ if (result == blink::WebServiceWorkerEventResultRejected)
+ status = SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED;
scoped_refptr<ServiceWorkerVersion> protect(this);
- callback->Run(SERVICE_WORKER_OK);
- push_callbacks_.Remove(request_id);
+ callback->Run(status);
+ RemoveCallbackAndStopIfRedundant(&push_callbacks_, request_id);
}
void ServiceWorkerVersion::OnGeofencingEventFinished(int request_id) {
@@ -715,48 +1279,633 @@ void ServiceWorkerVersion::OnGeofencingEventFinished(int request_id) {
scoped_refptr<ServiceWorkerVersion> protect(this);
callback->Run(SERVICE_WORKER_OK);
- geofencing_callbacks_.Remove(request_id);
+ RemoveCallbackAndStopIfRedundant(&geofencing_callbacks_, request_id);
+}
+
+void ServiceWorkerVersion::OnCrossOriginConnectEventFinished(
+ int request_id,
+ bool accept_connection) {
+ TRACE_EVENT1("ServiceWorker",
+ "ServiceWorkerVersion::OnCrossOriginConnectEventFinished",
+ "Request id", request_id);
+ CrossOriginConnectCallback* callback =
+ cross_origin_connect_callbacks_.Lookup(request_id);
+ if (!callback) {
+ NOTREACHED() << "Got unexpected message: " << request_id;
+ return;
+ }
+
+ scoped_refptr<ServiceWorkerVersion> protect(this);
+ callback->Run(SERVICE_WORKER_OK, accept_connection);
+ RemoveCallbackAndStopIfRedundant(&cross_origin_connect_callbacks_,
+ request_id);
+}
+
+void ServiceWorkerVersion::OnOpenWindow(int request_id, GURL url) {
+ // Just abort if we are shutting down.
+ if (!context_)
+ return;
+
+ if (!url.is_valid()) {
+ DVLOG(1) << "Received unexpected invalid URL from renderer process.";
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(&KillEmbeddedWorkerProcess,
+ embedded_worker_->process_id(),
+ RESULT_CODE_KILLED_BAD_MESSAGE));
+ return;
+ }
+
+ // The renderer treats all URLs in the about: scheme as being about:blank.
+ // Canonicalize about: URLs to about:blank.
+ if (url.SchemeIs(url::kAboutScheme))
+ url = GURL(url::kAboutBlankURL);
+
+ // Reject requests for URLs that the process is not allowed to access. It's
+ // possible to receive such requests since the renderer-side checks are
+ // slightly different. For example, the view-source scheme will not be
+ // filtered out by Blink.
+ if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanRequestURL(
+ embedded_worker_->process_id(), url)) {
+ embedded_worker_->SendMessage(ServiceWorkerMsg_OpenWindowError(
+ request_id, url.spec() + " cannot be opened."));
+ return;
+ }
+
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&OpenWindowOnUI,
+ url,
+ script_url_,
+ embedded_worker_->process_id(),
+ make_scoped_refptr(context_->wrapper()),
+ base::Bind(&ServiceWorkerVersion::DidOpenWindow,
+ weak_factory_.GetWeakPtr(),
+ request_id)));
+}
+
+void ServiceWorkerVersion::DidOpenWindow(int request_id,
+ int render_process_id,
+ int render_frame_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (running_status() != RUNNING)
+ return;
+
+ if (render_process_id == ChildProcessHost::kInvalidUniqueID &&
+ render_frame_id == MSG_ROUTING_NONE) {
+ embedded_worker_->SendMessage(ServiceWorkerMsg_OpenWindowError(
+ request_id, "Something went wrong while trying to open the window."));
+ return;
+ }
+
+ for (auto it =
+ context_->GetClientProviderHostIterator(script_url_.GetOrigin());
+ !it->IsAtEnd(); it->Advance()) {
+ ServiceWorkerProviderHost* provider_host = it->GetProviderHost();
+ if (provider_host->process_id() != render_process_id ||
+ provider_host->frame_id() != render_frame_id) {
+ continue;
+ }
+ provider_host->GetWindowClientInfo(base::Bind(
+ &ServiceWorkerVersion::OnOpenWindowFinished, weak_factory_.GetWeakPtr(),
+ request_id, provider_host->client_uuid()));
+ return;
+ }
+
+ // If here, it means that no provider_host was found, in which case, the
+ // renderer should still be informed that the window was opened.
+ OnOpenWindowFinished(request_id, std::string(), ServiceWorkerClientInfo());
+}
+
+void ServiceWorkerVersion::OnOpenWindowFinished(
+ int request_id,
+ const std::string& client_uuid,
+ const ServiceWorkerClientInfo& client_info) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (running_status() != RUNNING)
+ return;
+
+ ServiceWorkerClientInfo client(client_info);
+
+ // If the |client_info| is empty, it means that the opened window wasn't
+ // controlled but the action still succeeded. The renderer process is
+ // expecting an empty client in such case.
+ if (!client.IsEmpty())
+ client.client_uuid = client_uuid;
+
+ embedded_worker_->SendMessage(ServiceWorkerMsg_OpenWindowResponse(
+ request_id, client));
+}
+
+void ServiceWorkerVersion::OnSetCachedMetadata(const GURL& url,
+ const std::vector<char>& data) {
+ int64 callback_id = base::TimeTicks::Now().ToInternalValue();
+ TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker",
+ "ServiceWorkerVersion::OnSetCachedMetadata",
+ callback_id, "URL", url.spec());
+ script_cache_map_.WriteMetadata(
+ url, data, base::Bind(&ServiceWorkerVersion::OnSetCachedMetadataFinished,
+ weak_factory_.GetWeakPtr(), callback_id));
+}
+
+void ServiceWorkerVersion::OnSetCachedMetadataFinished(int64 callback_id,
+ int result) {
+ TRACE_EVENT_ASYNC_END1("ServiceWorker",
+ "ServiceWorkerVersion::OnSetCachedMetadata",
+ callback_id, "result", result);
+ FOR_EACH_OBSERVER(Listener, listeners_, OnCachedMetadataUpdated(this));
+}
+
+void ServiceWorkerVersion::OnClearCachedMetadata(const GURL& url) {
+ int64 callback_id = base::TimeTicks::Now().ToInternalValue();
+ TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker",
+ "ServiceWorkerVersion::OnClearCachedMetadata",
+ callback_id, "URL", url.spec());
+ script_cache_map_.ClearMetadata(
+ url, base::Bind(&ServiceWorkerVersion::OnClearCachedMetadataFinished,
+ weak_factory_.GetWeakPtr(), callback_id));
}
-void ServiceWorkerVersion::OnPostMessageToDocument(
- int client_id,
+void ServiceWorkerVersion::OnClearCachedMetadataFinished(int64 callback_id,
+ int result) {
+ TRACE_EVENT_ASYNC_END1("ServiceWorker",
+ "ServiceWorkerVersion::OnClearCachedMetadata",
+ callback_id, "result", result);
+ FOR_EACH_OBSERVER(Listener, listeners_, OnCachedMetadataUpdated(this));
+}
+
+void ServiceWorkerVersion::OnPostMessageToClient(
+ const std::string& client_uuid,
const base::string16& message,
- const std::vector<int>& sent_message_port_ids) {
+ const std::vector<TransferredMessagePort>& sent_message_ports) {
+ if (!context_)
+ return;
TRACE_EVENT1("ServiceWorker",
"ServiceWorkerVersion::OnPostMessageToDocument",
- "Client id", client_id);
+ "Client id", client_uuid);
ServiceWorkerProviderHost* provider_host =
- controllee_by_id_.Lookup(client_id);
+ context_->GetProviderHostByClientID(client_uuid);
if (!provider_host) {
// The client may already have been closed, just ignore.
return;
}
- provider_host->PostMessage(message, sent_message_port_ids);
+ if (provider_host->document_url().GetOrigin() != script_url_.GetOrigin()) {
+ // The client does not belong to the same origin as this ServiceWorker,
+ // possibly due to timing issue or bad message.
+ return;
+ }
+ provider_host->PostMessage(message, sent_message_ports);
}
-void ServiceWorkerVersion::ScheduleStopWorker() {
- if (running_status() != RUNNING)
+void ServiceWorkerVersion::OnFocusClient(int request_id,
+ const std::string& client_uuid) {
+ if (!context_)
+ return;
+ TRACE_EVENT2("ServiceWorker",
+ "ServiceWorkerVersion::OnFocusClient",
+ "Request id", request_id,
+ "Client id", client_uuid);
+ ServiceWorkerProviderHost* provider_host =
+ context_->GetProviderHostByClientID(client_uuid);
+ if (!provider_host) {
+ // The client may already have been closed, just ignore.
return;
- if (stop_worker_timer_.IsRunning()) {
- stop_worker_timer_.Reset();
+ }
+ if (provider_host->document_url().GetOrigin() != script_url_.GetOrigin()) {
+ // The client does not belong to the same origin as this ServiceWorker,
+ // possibly due to timing issue or bad message.
return;
}
- stop_worker_timer_.Start(
- FROM_HERE, base::TimeDelta::FromSeconds(kStopWorkerDelay),
- base::Bind(&ServiceWorkerVersion::StopWorker,
- weak_factory_.GetWeakPtr(),
- base::Bind(&ServiceWorkerUtils::NoOpStatusCallback)));
+ provider_host->Focus(base::Bind(&ServiceWorkerVersion::OnFocusClientFinished,
+ weak_factory_.GetWeakPtr(), request_id,
+ client_uuid));
}
-void ServiceWorkerVersion::DoomInternal() {
- DCHECK(!HasControllee());
- SetStatus(REDUNDANT);
- StopWorker(base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
+void ServiceWorkerVersion::OnFocusClientFinished(
+ int request_id,
+ const std::string& client_uuid,
+ const ServiceWorkerClientInfo& client) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (running_status() != RUNNING)
+ return;
+
+ ServiceWorkerClientInfo client_info(client);
+ client_info.client_uuid = client_uuid;
+
+ embedded_worker_->SendMessage(ServiceWorkerMsg_FocusClientResponse(
+ request_id, client_info));
+}
+
+void ServiceWorkerVersion::OnSkipWaiting(int request_id) {
+ skip_waiting_ = true;
+ if (status_ != INSTALLED)
+ return DidSkipWaiting(request_id);
+
if (!context_)
return;
- std::vector<ServiceWorkerDatabase::ResourceRecord> resources;
- script_cache_map_.GetResources(&resources);
- context_->storage()->PurgeResources(resources);
+ ServiceWorkerRegistration* registration =
+ context_->GetLiveRegistration(registration_id_);
+ if (!registration)
+ return;
+ pending_skip_waiting_requests_.push_back(request_id);
+ if (pending_skip_waiting_requests_.size() == 1)
+ registration->ActivateWaitingVersionWhenReady();
+}
+
+void ServiceWorkerVersion::DidSkipWaiting(int request_id) {
+ if (running_status() == STARTING || running_status() == RUNNING)
+ embedded_worker_->SendMessage(ServiceWorkerMsg_DidSkipWaiting(request_id));
+}
+
+void ServiceWorkerVersion::OnClaimClients(int request_id) {
+ if (status_ != ACTIVATING && status_ != ACTIVATED) {
+ embedded_worker_->SendMessage(ServiceWorkerMsg_ClaimClientsError(
+ request_id, blink::WebServiceWorkerError::ErrorTypeState,
+ base::ASCIIToUTF16(kClaimClientsStateErrorMesage)));
+ return;
+ }
+ if (context_) {
+ if (ServiceWorkerRegistration* registration =
+ context_->GetLiveRegistration(registration_id_)) {
+ registration->ClaimClients();
+ embedded_worker_->SendMessage(
+ ServiceWorkerMsg_DidClaimClients(request_id));
+ return;
+ }
+ }
+
+ embedded_worker_->SendMessage(ServiceWorkerMsg_ClaimClientsError(
+ request_id, blink::WebServiceWorkerError::ErrorTypeAbort,
+ base::ASCIIToUTF16(kClaimClientsShutdownErrorMesage)));
+}
+
+void ServiceWorkerVersion::OnPongFromWorker() {
+ ClearTick(&ping_time_);
+}
+
+void ServiceWorkerVersion::DidEnsureLiveRegistrationForStartWorker(
+ bool pause_after_download,
+ const StatusCallback& callback,
+ ServiceWorkerStatusCode status,
+ const scoped_refptr<ServiceWorkerRegistration>& protect) {
+ if (status != SERVICE_WORKER_OK) {
+ RecordStartWorkerResult(status);
+ RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED));
+ return;
+ }
+ if (is_redundant()) {
+ RecordStartWorkerResult(SERVICE_WORKER_ERROR_NOT_FOUND);
+ RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED));
+ return;
+ }
+
+ switch (running_status()) {
+ case RUNNING:
+ RunSoon(base::Bind(callback, SERVICE_WORKER_OK));
+ return;
+ case STOPPING:
+ case STOPPED:
+ case STARTING:
+ if (start_callbacks_.empty()) {
+ start_callbacks_.push_back(
+ base::Bind(&ServiceWorkerVersion::RecordStartWorkerResult,
+ weak_factory_.GetWeakPtr()));
+ }
+ // Keep the live registration while starting the worker.
+ start_callbacks_.push_back(
+ base::Bind(&RunStartWorkerCallback, callback, protect));
+ StartWorkerInternal(pause_after_download);
+ return;
+ }
+}
+
+void ServiceWorkerVersion::StartWorkerInternal(bool pause_after_download) {
+ if (!timeout_timer_.IsRunning())
+ StartTimeoutTimer();
+ if (running_status() == STOPPED) {
+ embedded_worker_->Start(
+ version_id_, scope_, script_url_, pause_after_download,
+ base::Bind(&ServiceWorkerVersion::OnStartSentAndScriptEvaluated,
+ weak_factory_.GetWeakPtr()));
+ }
+}
+
+void ServiceWorkerVersion::GetWindowClients(
+ int request_id,
+ const ServiceWorkerClientQueryOptions& options) {
+ DCHECK(options.client_type == blink::WebServiceWorkerClientTypeWindow ||
+ options.client_type == blink::WebServiceWorkerClientTypeAll);
+ std::vector<Tuple<int, int, std::string>> clients_info;
+ if (!options.include_uncontrolled) {
+ for (auto& controllee : controllee_map_)
+ AddWindowClient(controllee.second, &clients_info);
+ } else {
+ for (auto it =
+ context_->GetClientProviderHostIterator(script_url_.GetOrigin());
+ !it->IsAtEnd(); it->Advance()) {
+ AddWindowClient(it->GetProviderHost(), &clients_info);
+ }
+ }
+
+ if (clients_info.empty()) {
+ DidGetWindowClients(request_id, options,
+ make_scoped_ptr(new ServiceWorkerClients));
+ return;
+ }
+
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&OnGetWindowClientsFromUI, clients_info, script_url_,
+ base::Bind(&ServiceWorkerVersion::DidGetWindowClients,
+ weak_factory_.GetWeakPtr(), request_id, options)));
+}
+
+void ServiceWorkerVersion::DidGetWindowClients(
+ int request_id,
+ const ServiceWorkerClientQueryOptions& options,
+ scoped_ptr<ServiceWorkerClients> clients) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (options.client_type == blink::WebServiceWorkerClientTypeAll)
+ GetNonWindowClients(request_id, options, clients.get());
+ OnGetClientsFinished(request_id, *clients);
+}
+
+void ServiceWorkerVersion::GetNonWindowClients(
+ int request_id,
+ const ServiceWorkerClientQueryOptions& options,
+ ServiceWorkerClients* clients) {
+ if (!options.include_uncontrolled) {
+ for (auto& controllee : controllee_map_) {
+ AddNonWindowClient(controllee.second, options, clients);
+ }
+ } else {
+ for (auto it =
+ context_->GetClientProviderHostIterator(script_url_.GetOrigin());
+ !it->IsAtEnd(); it->Advance()) {
+ AddNonWindowClient(it->GetProviderHost(), options, clients);
+ }
+ }
+}
+
+void ServiceWorkerVersion::StartTimeoutTimer() {
+ DCHECK(!timeout_timer_.IsRunning());
+
+ if (embedded_worker_->devtools_attached()) {
+ // Don't record the startup time metric once DevTools is attached.
+ ClearTick(&start_time_);
+ skip_recording_startup_time_ = true;
+ } else {
+ RestartTick(&start_time_);
+ skip_recording_startup_time_ = false;
+ }
+
+ ClearTick(&idle_time_);
+ ClearTick(&ping_time_);
+ ping_state_ = NOT_PINGING;
+
+ timeout_timer_.Start(FROM_HERE,
+ base::TimeDelta::FromSeconds(kTimeoutTimerDelaySeconds),
+ this, &ServiceWorkerVersion::OnTimeoutTimer);
+}
+
+void ServiceWorkerVersion::StopTimeoutTimer() {
+ timeout_timer_.Stop();
+}
+
+void ServiceWorkerVersion::OnTimeoutTimer() {
+ DCHECK(running_status() == STARTING || running_status() == RUNNING ||
+ running_status() == STOPPING)
+ << running_status();
+
+ // Starting a worker hasn't finished within a certain period.
+ if (GetTickDuration(start_time_) >
+ base::TimeDelta::FromMinutes(kStartWorkerTimeoutMinutes)) {
+ DCHECK(running_status() == STARTING || running_status() == STOPPING)
+ << running_status();
+ scoped_refptr<ServiceWorkerVersion> protect(this);
+ RunCallbacks(this, &start_callbacks_, SERVICE_WORKER_ERROR_TIMEOUT);
+ if (running_status() == STARTING)
+ embedded_worker_->Stop();
+ return;
+ }
+
+ // Requests have not finished within a certain period.
+ bool request_timed_out = false;
+ while (!requests_.empty()) {
+ RequestInfo info = requests_.front();
+ if (GetTickDuration(info.time) <
+ base::TimeDelta::FromMinutes(kRequestTimeoutMinutes))
+ break;
+ if (OnRequestTimeout(info))
+ request_timed_out = true;
+ requests_.pop();
+ }
+ if (request_timed_out && running_status() != STOPPING)
+ embedded_worker_->Stop();
+
+ // For the timeouts below, there are no callbacks to timeout so there is
+ // nothing more to do if the worker is already stopping.
+ if (running_status() == STOPPING)
+ return;
+
+ // The worker has been idle for longer than a certain period.
+ if (GetTickDuration(idle_time_) >
+ base::TimeDelta::FromSeconds(kIdleWorkerTimeoutSeconds)) {
+ StopWorkerIfIdle();
+ return;
+ }
+
+ // The worker hasn't responded to ping within a certain period.
+ if (GetTickDuration(ping_time_) >
+ base::TimeDelta::FromSeconds(kPingTimeoutSeconds)) {
+ OnPingTimeout();
+ return;
+ }
+
+ if (ping_state_ == PINGING && ping_time_.is_null())
+ PingWorker();
+}
+
+void ServiceWorkerVersion::PingWorker() {
+ DCHECK(running_status() == STARTING || running_status() == RUNNING);
+ DCHECK_EQ(PINGING, ping_state_);
+ ServiceWorkerStatusCode status =
+ embedded_worker_->SendMessage(ServiceWorkerMsg_Ping());
+ if (status != SERVICE_WORKER_OK) {
+ // TODO(falken): Maybe try resending Ping a few times first?
+ ping_state_ = PING_TIMED_OUT;
+ StopWorkerIfIdle();
+ return;
+ }
+ RestartTick(&ping_time_);
+}
+
+void ServiceWorkerVersion::OnPingTimeout() {
+ DCHECK(running_status() == STARTING || running_status() == RUNNING);
+ ping_state_ = PING_TIMED_OUT;
+ // TODO(falken): Show a message to the developer that the SW was stopped due
+ // to timeout (crbug.com/457968). Also, change the error code to
+ // SERVICE_WORKER_ERROR_TIMEOUT.
+ StopWorkerIfIdle();
+}
+
+void ServiceWorkerVersion::StopWorkerIfIdle() {
+ if (HasInflightRequests() && ping_state_ != PING_TIMED_OUT)
+ return;
+ if (running_status() == STOPPED || running_status() == STOPPING ||
+ !stop_callbacks_.empty()) {
+ return;
+ }
+
+ // TODO(falken): We may need to handle StopIfIdle failure and
+ // forcibly fail pending callbacks so no one is stuck waiting
+ // for the worker.
+ embedded_worker_->StopIfIdle();
+}
+
+bool ServiceWorkerVersion::HasInflightRequests() const {
+ return
+ !activate_callbacks_.IsEmpty() ||
+ !install_callbacks_.IsEmpty() ||
+ !fetch_callbacks_.IsEmpty() ||
+ !sync_callbacks_.IsEmpty() ||
+ !notification_click_callbacks_.IsEmpty() ||
+ !push_callbacks_.IsEmpty() ||
+ !geofencing_callbacks_.IsEmpty() ||
+ !cross_origin_connect_callbacks_.IsEmpty() ||
+ !streaming_url_request_jobs_.empty();
+}
+
+void ServiceWorkerVersion::RecordStartWorkerResult(
+ ServiceWorkerStatusCode status) {
+ base::TimeTicks start_time = start_time_;
+ ClearTick(&start_time_);
+
+ ServiceWorkerMetrics::RecordStartWorkerStatus(status,
+ IsInstalled(prestart_status_));
+
+ if (status == SERVICE_WORKER_OK && !start_time.is_null() &&
+ !skip_recording_startup_time_) {
+ ServiceWorkerMetrics::RecordStartWorkerTime(GetTickDuration(start_time),
+ IsInstalled(prestart_status_));
+ }
+
+ if (status != SERVICE_WORKER_ERROR_TIMEOUT)
+ return;
+ EmbeddedWorkerInstance::StartingPhase phase =
+ EmbeddedWorkerInstance::NOT_STARTING;
+ EmbeddedWorkerInstance::Status running_status = embedded_worker_->status();
+ // Build an artifical JavaScript exception to show in the ServiceWorker
+ // log for developers; it's not user-facing so it's not a localized resource.
+ std::string message = "ServiceWorker startup timed out. ";
+ if (running_status != EmbeddedWorkerInstance::STARTING) {
+ message.append("The worker had unexpected status: ");
+ message.append(EmbeddedWorkerInstance::StatusToString(running_status));
+ } else {
+ phase = embedded_worker_->starting_phase();
+ message.append("The worker was in startup phase: ");
+ message.append(EmbeddedWorkerInstance::StartingPhaseToString(phase));
+ }
+ message.append(".");
+ OnReportException(base::UTF8ToUTF16(message), -1, -1, GURL());
+ DVLOG(1) << message;
+ UMA_HISTOGRAM_ENUMERATION("ServiceWorker.StartWorker.TimeoutPhase",
+ phase,
+ EmbeddedWorkerInstance::STARTING_PHASE_MAX_VALUE);
+}
+
+template <typename IDMAP>
+void ServiceWorkerVersion::RemoveCallbackAndStopIfRedundant(IDMAP* callbacks,
+ int request_id) {
+ RestartTick(&idle_time_);
+ callbacks->Remove(request_id);
+ if (is_redundant()) {
+ // The stop should be already scheduled, but try to stop immediately, in
+ // order to release worker resources soon.
+ StopWorkerIfIdle();
+ }
+}
+
+template <typename CallbackType>
+int ServiceWorkerVersion::AddRequest(
+ const CallbackType& callback,
+ IDMap<CallbackType, IDMapOwnPointer>* callback_map,
+ RequestType request_type) {
+ int request_id = callback_map->Add(new CallbackType(callback));
+ requests_.push(RequestInfo(request_id, request_type));
+ return request_id;
+}
+
+bool ServiceWorkerVersion::OnRequestTimeout(const RequestInfo& info) {
+ switch (info.type) {
+ case REQUEST_ACTIVATE:
+ return RunIDMapCallback(&activate_callbacks_, info.id,
+ SERVICE_WORKER_ERROR_TIMEOUT);
+ case REQUEST_INSTALL:
+ return RunIDMapCallback(&install_callbacks_, info.id,
+ SERVICE_WORKER_ERROR_TIMEOUT);
+ case REQUEST_FETCH:
+ return RunIDMapCallback(
+ &fetch_callbacks_, info.id, SERVICE_WORKER_ERROR_TIMEOUT,
+ /* The other args are ignored for non-OK status. */
+ SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK, ServiceWorkerResponse());
+ case REQUEST_SYNC:
+ return RunIDMapCallback(&sync_callbacks_, info.id,
+ SERVICE_WORKER_ERROR_TIMEOUT);
+ case REQUEST_NOTIFICATION_CLICK:
+ return RunIDMapCallback(&notification_click_callbacks_, info.id,
+ SERVICE_WORKER_ERROR_TIMEOUT);
+ case REQUEST_PUSH:
+ return RunIDMapCallback(&push_callbacks_, info.id,
+ SERVICE_WORKER_ERROR_TIMEOUT);
+ case REQUEST_GEOFENCING:
+ return RunIDMapCallback(&geofencing_callbacks_, info.id,
+ SERVICE_WORKER_ERROR_TIMEOUT);
+ case REQUEST_CROSS_ORIGIN_CONNECT:
+ return RunIDMapCallback(&cross_origin_connect_callbacks_, info.id,
+ SERVICE_WORKER_ERROR_TIMEOUT,
+ false /* accept_connection */);
+ }
+ NOTREACHED() << "Got unexpected request type: " << info.type;
+ return false;
+}
+
+void ServiceWorkerVersion::SetAllRequestTimes(const base::TimeTicks& ticks) {
+ std::queue<RequestInfo> new_requests;
+ while (!requests_.empty()) {
+ RequestInfo info = requests_.front();
+ info.time = ticks;
+ new_requests.push(info);
+ requests_.pop();
+ }
+ requests_ = new_requests;
+}
+
+ServiceWorkerStatusCode ServiceWorkerVersion::DeduceStartWorkerFailureReason(
+ ServiceWorkerStatusCode default_code) {
+ if (ping_state_ == PING_TIMED_OUT)
+ return SERVICE_WORKER_ERROR_TIMEOUT;
+
+ if (start_worker_status_ != SERVICE_WORKER_OK)
+ return start_worker_status_;
+
+ const net::URLRequestStatus& main_script_status =
+ 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:
+ return SERVICE_WORKER_ERROR_SECURITY;
+ case net::ERR_ABORTED:
+ return SERVICE_WORKER_ERROR_ABORT;
+ default:
+ return SERVICE_WORKER_ERROR_NETWORK;
+ }
+ }
+
+ return default_code;
}
} // 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 0dcf9a4c912..af011e56366 100644
--- a/chromium/content/browser/service_worker/service_worker_version.h
+++ b/chromium/content/browser/service_worker/service_worker_version.h
@@ -6,6 +6,8 @@
#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_VERSION_H_
#include <map>
+#include <queue>
+#include <set>
#include <string>
#include <vector>
@@ -18,7 +20,6 @@
#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"
@@ -26,19 +27,33 @@
#include "third_party/WebKit/public/platform/WebGeofencingEventType.h"
#include "third_party/WebKit/public/platform/WebServiceWorkerEventResult.h"
+// Windows headers will redefine SendMessage.
+#ifdef SendMessage
+#undef SendMessage
+#endif
+
class GURL;
namespace blink {
struct WebCircularGeofencingRegion;
}
+namespace net {
+class HttpResponseInfo;
+}
+
namespace content {
class EmbeddedWorkerRegistry;
class ServiceWorkerContextCore;
class ServiceWorkerProviderHost;
class ServiceWorkerRegistration;
-class ServiceWorkerVersionInfo;
+class ServiceWorkerURLRequestJob;
+struct NavigatorConnectClient;
+struct PlatformNotificationData;
+struct ServiceWorkerClientInfo;
+struct ServiceWorkerVersionInfo;
+struct TransferredMessagePort;
// This class corresponds to a specific version of a ServiceWorker
// script for a given pattern. When a script is upgraded, there may be
@@ -51,10 +66,11 @@ class CONTENT_EXPORT ServiceWorkerVersion
public:
typedef base::Callback<void(ServiceWorkerStatusCode)> StatusCallback;
typedef base::Callback<void(ServiceWorkerStatusCode,
- const IPC::Message& message)> MessageCallback;
- typedef base::Callback<void(ServiceWorkerStatusCode,
ServiceWorkerFetchEventResult,
const ServiceWorkerResponse&)> FetchCallback;
+ typedef base::Callback<void(ServiceWorkerStatusCode,
+ bool /* accept_connction */)>
+ CrossOriginConnectCallback;
enum RunningStatus {
STOPPED = EmbeddedWorkerInstance::STOPPED,
@@ -77,9 +93,10 @@ class CONTENT_EXPORT ServiceWorkerVersion
class Listener {
public:
- virtual void OnWorkerStarted(ServiceWorkerVersion* version) {}
- virtual void OnWorkerStopped(ServiceWorkerVersion* version) {}
+ virtual void OnRunningStateChanged(ServiceWorkerVersion* version) {}
virtual void OnVersionStateChanged(ServiceWorkerVersion* version) {}
+ virtual void OnMainScriptHttpResponseInfoSet(
+ ServiceWorkerVersion* version) {}
virtual void OnErrorReported(ServiceWorkerVersion* version,
const base::string16& error_message,
int line_number,
@@ -93,6 +110,7 @@ class CONTENT_EXPORT ServiceWorkerVersion
const GURL& source_url) {}
// Fires when a version transitions from having a controllee to not.
virtual void OnNoControllees(ServiceWorkerVersion* version) {}
+ virtual void OnCachedMetadataUpdated(ServiceWorkerVersion* version) {}
protected:
virtual ~Listener() {}
@@ -148,25 +166,21 @@ class CONTENT_EXPORT ServiceWorkerVersion
// 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.
- // |callback| can be null if the sender does not need to know if the
- // message is successfully sent or not.
- void SendMessage(const IPC::Message& message, const StatusCallback& callback);
+ // Sends a message event to the associated embedded worker.
+ void DispatchMessageEvent(
+ const base::string16& message,
+ const std::vector<TransferredMessagePort>& sent_message_ports,
+ const StatusCallback& callback);
// Sends install event to the associated embedded worker and asynchronously
// calls |callback| when it errors out or it gets a response from the worker
// to notify install completion.
- // |active_version_id| must be a valid positive ID
- // 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.
// Upon completion, the version's status will be changed to INSTALLED
// on success, or back to NEW on failure.
- void DispatchInstallEvent(int active_version_id,
- const StatusCallback& callback);
+ void DispatchInstallEvent(const StatusCallback& callback);
// Sends activate event to the associated embedded worker and asynchronously
// calls |callback| when it errors out or it gets a response from the worker
@@ -194,6 +208,16 @@ class CONTENT_EXPORT ServiceWorkerVersion
// This must be called when the status() is ACTIVATED.
void DispatchSyncEvent(const StatusCallback& callback);
+ // Sends notificationclick event to the associated embedded worker and
+ // asynchronously calls |callback| when it errors out or it gets a response
+ // from the worker to notify completion.
+ //
+ // This must be called when the status() is ACTIVATED.
+ void DispatchNotificationClickEvent(
+ const StatusCallback& callback,
+ int64_t persistent_notification_id,
+ const PlatformNotificationData& notification_data);
+
// Sends push event to the associated embedded worker and asynchronously calls
// |callback| when it errors out or it gets a response from the worker to
// notify completion.
@@ -213,6 +237,28 @@ class CONTENT_EXPORT ServiceWorkerVersion
const std::string& region_id,
const blink::WebCircularGeofencingRegion& region);
+ // Sends a cross origin connect event to the associated embedded worker and
+ // asynchronously calls |callback| with the response from the worker.
+ //
+ // This must be called when the status() is ACTIVATED.
+ void DispatchCrossOriginConnectEvent(
+ const CrossOriginConnectCallback& callback,
+ const NavigatorConnectClient& client);
+
+ // Sends a cross origin message event to the associated embedded worker and
+ // asynchronously calls |callback| when the message was sent (or failed to
+ // sent).
+ // It is the responsibility of the code calling this method to make sure that
+ // any transferred message ports are put on hold while potentially a process
+ // for the service worker is spun up.
+ //
+ // This must be called when the status() is ACTIVATED.
+ void DispatchCrossOriginMessageEvent(
+ const NavigatorConnectClient& client,
+ const base::string16& message,
+ const std::vector<TransferredMessagePort>& sent_message_ports,
+ const StatusCallback& callback);
+
// Adds and removes |provider_host| as a controllee of this ServiceWorker.
// A potential controllee is a host having the version as its .installing
// or .waiting version.
@@ -222,6 +268,13 @@ class CONTENT_EXPORT ServiceWorkerVersion
// Returns if it has controllee.
bool HasControllee() const { return !controllee_map_.empty(); }
+ // Adds and removes |request_job| as a dependent job not to stop the
+ // ServiceWorker while |request_job| is reading the stream of the fetch event
+ // response from the ServiceWorker.
+ void AddStreamingURLRequestJob(const ServiceWorkerURLRequestJob* request_job);
+ void RemoveStreamingURLRequestJob(
+ const ServiceWorkerURLRequestJob* request_job);
+
// Adds and removes Listeners.
void AddListener(Listener* listener);
void RemoveListener(Listener* listener);
@@ -229,27 +282,91 @@ 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.
+ // Reports the error message to |listeners_|.
+ void ReportError(ServiceWorkerStatusCode status,
+ const std::string& status_message);
+
+ // Sets the status code to pass to StartWorker callbacks if start fails.
+ void SetStartWorkerStatusCode(ServiceWorkerStatusCode status);
+
+ // Sets this version's status to REDUNDANT and deletes its resources.
+ // The version must not have controllees.
void Doom();
- bool is_doomed() const { return is_doomed_; }
+ bool is_redundant() const { return status_ == REDUNDANT; }
+
+ bool skip_waiting() const { return skip_waiting_; }
+ void set_skip_waiting(bool skip_waiting) { skip_waiting_ = skip_waiting; }
+
+ bool force_bypass_cache_for_scripts() {
+ return force_bypass_cache_for_scripts_;
+ }
+ void set_force_bypass_cache_for_scripts(bool force_bypass_cache_for_scripts) {
+ force_bypass_cache_for_scripts_ = force_bypass_cache_for_scripts;
+ }
+
+ void SetDevToolsAttached(bool attached);
+
+ // Sets the HttpResponseInfo used to load the main script.
+ // This HttpResponseInfo will be used for all responses sent back from the
+ // service worker, as the effective security of these responses is equivalent
+ // to that of the ServiceWorker.
+ void SetMainScriptHttpResponseInfo(const net::HttpResponseInfo& http_info);
+ const net::HttpResponseInfo* GetMainScriptHttpResponseInfo();
private:
friend class base::RefCounted<ServiceWorkerVersion>;
+ friend class ServiceWorkerURLRequestJobTest;
+ friend class ServiceWorkerVersionBrowserTest;
+
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerControlleeRequestHandlerTest,
ActivateWaitingVersion);
- FRIEND_TEST_ALL_PREFIXES(ServiceWorkerVersionTest, ScheduleStopWorker);
- FRIEND_TEST_ALL_PREFIXES(ServiceWorkerVersionTest, ListenerAvailability);
+ FRIEND_TEST_ALL_PREFIXES(ServiceWorkerVersionTest, IdleTimeout);
+ FRIEND_TEST_ALL_PREFIXES(ServiceWorkerVersionTest, SetDevToolsAttached);
+ FRIEND_TEST_ALL_PREFIXES(ServiceWorkerWaitForeverInFetchTest, RequestTimeout);
+ FRIEND_TEST_ALL_PREFIXES(ServiceWorkerFailToStartTest, Timeout);
+ FRIEND_TEST_ALL_PREFIXES(ServiceWorkerVersionBrowserTest,
+ TimeoutStartingWorker);
+ FRIEND_TEST_ALL_PREFIXES(ServiceWorkerVersionBrowserTest,
+ TimeoutWorkerInEvent);
+
+ class ServiceWorkerEventMetrics;
+
typedef ServiceWorkerVersion self;
- typedef std::map<ServiceWorkerProviderHost*, int> ControlleeMap;
- typedef IDMap<ServiceWorkerProviderHost> ControlleeByIDMap;
+ using ServiceWorkerClients = std::vector<ServiceWorkerClientInfo>;
+
+ enum RequestType {
+ REQUEST_ACTIVATE,
+ REQUEST_INSTALL,
+ REQUEST_FETCH,
+ REQUEST_SYNC,
+ REQUEST_NOTIFICATION_CLICK,
+ REQUEST_PUSH,
+ REQUEST_GEOFENCING,
+ REQUEST_CROSS_ORIGIN_CONNECT
+ };
+ enum PingState { NOT_PINGING, PINGING, PING_TIMED_OUT };
+
+ struct RequestInfo {
+ RequestInfo(int id, RequestType type);
+ ~RequestInfo();
+ int id;
+ RequestType type;
+ base::TimeTicks time;
+ };
+
+ // Timeout for the worker to start.
+ static const int kStartWorkerTimeoutMinutes;
+ // Timeout for a request to be handled.
+ static const int kRequestTimeoutMinutes;
~ServiceWorkerVersion() override;
// EmbeddedWorkerInstance::Listener overrides:
+ void OnScriptLoaded() override;
+ void OnStarting() override;
void OnStarted() override;
- void OnStopped() override;
+ void OnStopping() override;
+ void OnStopped(EmbeddedWorkerInstance::Status old_status) override;
void OnReportException(const base::string16& error_message,
int line_number,
int column_number,
@@ -261,14 +378,22 @@ class CONTENT_EXPORT ServiceWorkerVersion
const GURL& source_url) override;
bool OnMessageReceived(const IPC::Message& message) override;
- void OnStartMessageSent(ServiceWorkerStatusCode status);
+ void OnStartSentAndScriptEvaluated(ServiceWorkerStatusCode status);
- void DispatchInstallEventAfterStartWorker(int active_version_id,
- const StatusCallback& callback);
+ void DispatchInstallEventAfterStartWorker(const StatusCallback& callback);
void DispatchActivateEventAfterStartWorker(const StatusCallback& callback);
+ void DispatchMessageEventInternal(
+ const base::string16& message,
+ const std::vector<TransferredMessagePort>& sent_message_ports,
+ const StatusCallback& callback);
+
// Message handlers.
- void OnGetClientDocuments(int request_id);
+
+ // This corresponds to the spec's matchAll(options) steps.
+ void OnGetClients(int request_id,
+ const ServiceWorkerClientQueryOptions& options);
+
void OnActivateEventFinished(int request_id,
blink::WebServiceWorkerEventResult result);
void OnInstallEventFinished(int request_id,
@@ -277,42 +402,160 @@ class CONTENT_EXPORT ServiceWorkerVersion
ServiceWorkerFetchEventResult result,
const ServiceWorkerResponse& response);
void OnSyncEventFinished(int request_id);
- void OnPushEventFinished(int request_id);
+ void OnNotificationClickEventFinished(int request_id);
+ void OnPushEventFinished(int request_id,
+ blink::WebServiceWorkerEventResult result);
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();
+ void OnCrossOriginConnectEventFinished(int request_id,
+ bool accept_connection);
+ void OnOpenWindow(int request_id, GURL url);
+ void DidOpenWindow(int request_id,
+ int render_process_id,
+ int render_frame_id);
+ void OnOpenWindowFinished(int request_id,
+ const std::string& client_uuid,
+ const ServiceWorkerClientInfo& client_info);
+
+ void OnSetCachedMetadata(const GURL& url, const std::vector<char>& data);
+ void OnSetCachedMetadataFinished(int64 callback_id, int result);
+ void OnClearCachedMetadata(const GURL& url);
+ void OnClearCachedMetadataFinished(int64 callback_id, int result);
+
+ void OnPostMessageToClient(
+ const std::string& client_uuid,
+ const base::string16& message,
+ const std::vector<TransferredMessagePort>& sent_message_ports);
+ void OnFocusClient(int request_id, const std::string& client_uuid);
+ void OnSkipWaiting(int request_id);
+ void OnClaimClients(int request_id);
+ void OnPongFromWorker();
+
+ void OnFocusClientFinished(int request_id,
+ const std::string& client_uuid,
+ const ServiceWorkerClientInfo& client);
+
+ void DidEnsureLiveRegistrationForStartWorker(
+ bool pause_after_download,
+ const StatusCallback& callback,
+ ServiceWorkerStatusCode status,
+ const scoped_refptr<ServiceWorkerRegistration>& protect);
+ void StartWorkerInternal(bool pause_after_download);
+
+ void DidSkipWaiting(int request_id);
+
+ void GetWindowClients(int request_id,
+ const ServiceWorkerClientQueryOptions& options);
+ void DidGetWindowClients(int request_id,
+ const ServiceWorkerClientQueryOptions& options,
+ scoped_ptr<ServiceWorkerClients> clients);
+ void GetNonWindowClients(int request_id,
+ const ServiceWorkerClientQueryOptions& options,
+ ServiceWorkerClients* clients);
+ void OnGetClientsFinished(int request_id,
+ const ServiceWorkerClients& clients);
+
+ // The timeout timer periodically calls OnTimeoutTimer, which stops the worker
+ // if it is excessively idle or unresponsive to ping.
+ void StartTimeoutTimer();
+ void StopTimeoutTimer();
+ void OnTimeoutTimer();
+
+ // The ping protocol is for terminating workers that are taking excessively
+ // long executing JavaScript (e.g., stuck in while(true) {}). Periodically a
+ // ping IPC is sent to the worker context and if we timeout waiting for a
+ // pong, the worker is terminated. Pinging starts after the script is loaded.
+ void PingWorker();
+ void OnPingTimeout();
+
+ // Stops the worker if it is idle (has no in-flight requests) or timed out
+ // ping.
+ void StopWorkerIfIdle();
+ bool HasInflightRequests() const;
+
+ // RecordStartWorkerResult is added as a start callback by StartTimeoutTimer
+ // and records metrics about startup.
+ void RecordStartWorkerResult(ServiceWorkerStatusCode status);
+
+ template <typename IDMAP>
+ void RemoveCallbackAndStopIfRedundant(IDMAP* callbacks, int request_id);
+
+ template <typename CallbackType>
+ int AddRequest(const CallbackType& callback,
+ IDMap<CallbackType, IDMapOwnPointer>* callback_map,
+ RequestType request_type);
+
+ bool OnRequestTimeout(const RequestInfo& info);
+ void SetAllRequestTimes(const base::TimeTicks& ticks);
+
+ // Returns the reason the embedded worker failed to start, using information
+ // inaccessible to EmbeddedWorkerInstance. Returns |default_code| if it can't
+ // deduce a reason.
+ ServiceWorkerStatusCode DeduceStartWorkerFailureReason(
+ ServiceWorkerStatusCode default_code);
const int64 version_id_;
- int64 registration_id_;
- GURL script_url_;
- GURL scope_;
+ const int64 registration_id_;
+ const GURL script_url_;
+ const 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_;
- // Message callbacks.
+ // Message callbacks. (Update HasInflightRequests() too when you update this
+ // list.)
IDMap<StatusCallback, IDMapOwnPointer> activate_callbacks_;
IDMap<StatusCallback, IDMapOwnPointer> install_callbacks_;
IDMap<FetchCallback, IDMapOwnPointer> fetch_callbacks_;
IDMap<StatusCallback, IDMapOwnPointer> sync_callbacks_;
+ IDMap<StatusCallback, IDMapOwnPointer> notification_click_callbacks_;
IDMap<StatusCallback, IDMapOwnPointer> push_callbacks_;
IDMap<StatusCallback, IDMapOwnPointer> geofencing_callbacks_;
+ IDMap<CrossOriginConnectCallback, IDMapOwnPointer>
+ cross_origin_connect_callbacks_;
- ControlleeMap controllee_map_;
- ControlleeByIDMap controllee_by_id_;
+ std::set<const ServiceWorkerURLRequestJob*> streaming_url_request_jobs_;
+
+ std::map<std::string, ServiceWorkerProviderHost*> controllee_map_;
+ // Will be null while shutting down.
base::WeakPtr<ServiceWorkerContextCore> context_;
ObserverList<Listener> listeners_;
ServiceWorkerScriptCacheMap script_cache_map_;
- base::OneShotTimer<ServiceWorkerVersion> stop_worker_timer_;
base::OneShotTimer<ServiceWorkerVersion> update_timer_;
- bool is_doomed_;
+
+ // Starts running in StartWorker and continues until the worker is stopped.
+ base::RepeatingTimer<ServiceWorkerVersion> timeout_timer_;
+ // Holds the time the worker last started being considered idle.
+ base::TimeTicks idle_time_;
+ // Holds the time that an outstanding ping was sent to the worker.
+ base::TimeTicks ping_time_;
+ // The state of the ping protocol.
+ PingState ping_state_;
+ // Holds the time that the outstanding StartWorker() request started.
+ base::TimeTicks start_time_;
+
+ // New requests are added to |requests_| along with their entry in a callback
+ // map. The timeout timer periodically checks |requests_| for entries that
+ // should time out or have already been fulfilled (i.e., removed from the
+ // callback map).
+ std::queue<RequestInfo> requests_;
+
+ bool skip_waiting_ = false;
+ bool skip_recording_startup_time_ = false;
+ bool force_bypass_cache_for_scripts_ = false;
+
+ std::vector<int> pending_skip_waiting_requests_;
+ scoped_ptr<net::HttpResponseInfo> main_script_http_info_;
+
+ // The status when StartWorker was invoked. Used for UMA.
+ Status prestart_status_ = NEW;
+ // If not OK, the reason that StartWorker failed. Used for
+ // running |start_callbacks_|.
+ ServiceWorkerStatusCode start_worker_status_ = SERVICE_WORKER_OK;
+
+ scoped_ptr<ServiceWorkerEventMetrics> metrics_;
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 31225e96357..1b40881f78f 100644
--- a/chromium/content/browser/service_worker/service_worker_version_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_version_unittest.cc
@@ -9,6 +9,7 @@
#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/browser/service_worker/service_worker_registration.h"
#include "content/browser/service_worker/service_worker_test_utils.h"
+#include "content/browser/service_worker/service_worker_utils.h"
#include "content/browser/service_worker/service_worker_version.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -34,7 +35,7 @@ static const int kRenderProcessId = 1;
class MessageReceiver : public EmbeddedWorkerTestHelper {
public:
MessageReceiver()
- : EmbeddedWorkerTestHelper(kRenderProcessId),
+ : EmbeddedWorkerTestHelper(base::FilePath(), kRenderProcessId),
current_embedded_worker_id_(0) {}
~MessageReceiver() override {}
@@ -78,6 +79,13 @@ void ObserveStatusChanges(ServiceWorkerVersion* version,
base::Bind(&ObserveStatusChanges, base::Unretained(version), statuses));
}
+void ReceiveFetchResult(ServiceWorkerStatusCode* status,
+ ServiceWorkerStatusCode actual_status,
+ ServiceWorkerFetchEventResult actual_result,
+ const ServiceWorkerResponse& response) {
+ *status = actual_status;
+}
+
// A specialized listener class to receive test messages from a worker.
class MessageReceiverFromWorker : public EmbeddedWorkerInstance::Listener {
public:
@@ -88,7 +96,9 @@ class MessageReceiverFromWorker : public EmbeddedWorkerInstance::Listener {
~MessageReceiverFromWorker() override { instance_->RemoveListener(this); }
void OnStarted() override { NOTREACHED(); }
- void OnStopped() override { NOTREACHED(); }
+ void OnStopped(EmbeddedWorkerInstance::Status old_status) override {
+ NOTREACHED();
+ }
bool OnMessageReceived(const IPC::Message& message) override {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(MessageReceiverFromWorker, message)
@@ -127,6 +137,21 @@ class ServiceWorkerVersionTest : public testing::Test {
GURL("http://www.example.com/service_worker.js"),
1L,
helper_->context()->AsWeakPtr());
+ std::vector<ServiceWorkerDatabase::ResourceRecord> records;
+ records.push_back(
+ ServiceWorkerDatabase::ResourceRecord(10, version_->script_url(), 100));
+ version_->script_cache_map()->SetResources(records);
+
+ // Make the registration findable via storage functions.
+ helper_->context()->storage()->LazyInitialize(base::Bind(&base::DoNothing));
+ base::RunLoop().RunUntilIdle();
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
+ helper_->context()->storage()->StoreRegistration(
+ registration_.get(),
+ version_.get(),
+ CreateReceiverOnCurrentThread(&status));
+ base::RunLoop().RunUntilIdle();
+ ASSERT_EQ(SERVICE_WORKER_OK, status);
// Simulate adding one process to the pattern.
helper_->SimulateAddProcessToPattern(pattern_, kRenderProcessId);
@@ -177,7 +202,7 @@ class ServiceWorkerFailToStartTest : public ServiceWorkerVersionTest {
ServiceWorkerFailToStartTest()
: ServiceWorkerVersionTest() {}
- virtual scoped_ptr<MessageReceiver> GetMessageReceiver() override {
+ scoped_ptr<MessageReceiver> GetMessageReceiver() override {
return make_scoped_ptr(new MessageReceiverDisallowStart());
}
@@ -185,6 +210,33 @@ class ServiceWorkerFailToStartTest : public ServiceWorkerVersionTest {
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerFailToStartTest);
};
+class MessageReceiverDisallowFetch : public MessageReceiver {
+ public:
+ MessageReceiverDisallowFetch() : MessageReceiver() {}
+ ~MessageReceiverDisallowFetch() override {}
+
+ void OnFetchEvent(int embedded_worker_id,
+ int request_id,
+ const ServiceWorkerFetchRequest& request) override {
+ // Do nothing.
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MessageReceiverDisallowFetch);
+};
+
+class ServiceWorkerWaitForeverInFetchTest : public ServiceWorkerVersionTest {
+ protected:
+ ServiceWorkerWaitForeverInFetchTest() : ServiceWorkerVersionTest() {}
+
+ scoped_ptr<MessageReceiver> GetMessageReceiver() override {
+ return make_scoped_ptr(new MessageReceiverDisallowFetch());
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ServiceWorkerWaitForeverInFetchTest);
+};
+
TEST_F(ServiceWorkerVersionTest, ConcurrentStartAndStop) {
// Call StartWorker() multiple times.
ServiceWorkerStatusCode status1 = SERVICE_WORKER_ERROR_FAILED;
@@ -209,82 +261,83 @@ TEST_F(ServiceWorkerVersionTest, ConcurrentStartAndStop) {
// Call StopWorker() multiple times.
status1 = SERVICE_WORKER_ERROR_FAILED;
status2 = SERVICE_WORKER_ERROR_FAILED;
- status3 = SERVICE_WORKER_ERROR_FAILED;
version_->StopWorker(CreateReceiverOnCurrentThread(&status1));
version_->StopWorker(CreateReceiverOnCurrentThread(&status2));
- // Also try calling StartWorker while StopWorker is in queue.
- version_->StartWorker(CreateReceiverOnCurrentThread(&status3));
-
EXPECT_EQ(ServiceWorkerVersion::STOPPING, version_->running_status());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(ServiceWorkerVersion::STOPPED, version_->running_status());
- // All StopWorker should just succeed, while StartWorker fails.
+ // All StopWorker should just succeed.
EXPECT_EQ(SERVICE_WORKER_OK, status1);
EXPECT_EQ(SERVICE_WORKER_OK, status2);
- EXPECT_EQ(SERVICE_WORKER_ERROR_START_WORKER_FAILED, status3);
-}
-TEST_F(ServiceWorkerVersionTest, SendMessage) {
- EXPECT_EQ(ServiceWorkerVersion::STOPPED, version_->running_status());
+ // Start worker again.
+ status1 = SERVICE_WORKER_ERROR_FAILED;
+ status2 = SERVICE_WORKER_ERROR_FAILED;
+ status3 = SERVICE_WORKER_ERROR_FAILED;
- // Send a message without starting the worker.
- ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
- version_->SendMessage(TestMsg_Message(),
- CreateReceiverOnCurrentThread(&status));
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(SERVICE_WORKER_OK, status);
+ version_->StartWorker(CreateReceiverOnCurrentThread(&status1));
- // The worker should be now started.
+ EXPECT_EQ(ServiceWorkerVersion::STARTING, version_->running_status());
+ base::RunLoop().RunUntilIdle();
EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
- // Stop the worker, and then send the message immediately.
- ServiceWorkerStatusCode msg_status = SERVICE_WORKER_ERROR_FAILED;
- ServiceWorkerStatusCode stop_status = SERVICE_WORKER_ERROR_FAILED;
- version_->StopWorker(CreateReceiverOnCurrentThread(&stop_status));
- version_->SendMessage(TestMsg_Message(),
- CreateReceiverOnCurrentThread(&msg_status));
+ // Call StopWorker()
+ status2 = SERVICE_WORKER_ERROR_FAILED;
+ version_->StopWorker(CreateReceiverOnCurrentThread(&status2));
+
+ // And try calling StartWorker while StopWorker is in queue.
+ version_->StartWorker(CreateReceiverOnCurrentThread(&status3));
+
+ EXPECT_EQ(ServiceWorkerVersion::STOPPING, version_->running_status());
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(SERVICE_WORKER_OK, stop_status);
+ EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
- // SendMessage should return START_WORKER_FAILED error since it tried to
- // start a worker while it was stopping.
- EXPECT_EQ(SERVICE_WORKER_ERROR_START_WORKER_FAILED, msg_status);
+ // All should just succeed.
+ EXPECT_EQ(SERVICE_WORKER_OK, status1);
+ EXPECT_EQ(SERVICE_WORKER_OK, status2);
+ EXPECT_EQ(SERVICE_WORKER_OK, status3);
}
-TEST_F(ServiceWorkerVersionTest, ReSendMessageAfterStop) {
+TEST_F(ServiceWorkerVersionTest, DispatchEventToStoppedWorker) {
EXPECT_EQ(ServiceWorkerVersion::STOPPED, version_->running_status());
- // Start the worker.
- ServiceWorkerStatusCode start_status = SERVICE_WORKER_ERROR_FAILED;
- version_->StartWorker(CreateReceiverOnCurrentThread(&start_status));
+ // Dispatch an event without starting the worker.
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
+ version_->SetStatus(ServiceWorkerVersion::INSTALLING);
+ version_->DispatchInstallEvent(CreateReceiverOnCurrentThread(&status));
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(SERVICE_WORKER_OK, start_status);
+ EXPECT_EQ(SERVICE_WORKER_OK, status);
+
+ // The worker should be now started.
EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
- // Stop the worker, and then send the message immediately.
- ServiceWorkerStatusCode msg_status = SERVICE_WORKER_ERROR_FAILED;
+ // Stop the worker, and then dispatch an event immediately after that.
+ status = SERVICE_WORKER_ERROR_FAILED;
ServiceWorkerStatusCode stop_status = SERVICE_WORKER_ERROR_FAILED;
version_->StopWorker(CreateReceiverOnCurrentThread(&stop_status));
- version_->SendMessage(TestMsg_Message(),
- CreateReceiverOnCurrentThread(&msg_status));
+ version_->DispatchInstallEvent(CreateReceiverOnCurrentThread(&status));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(SERVICE_WORKER_OK, stop_status);
- // SendMessage should return START_WORKER_FAILED error since it tried to
- // start a worker while it was stopping.
- EXPECT_EQ(SERVICE_WORKER_ERROR_START_WORKER_FAILED, msg_status);
+ // Dispatch an event should return SERVICE_WORKER_OK since the worker
+ // should have been restarted to dispatch the event.
+ EXPECT_EQ(SERVICE_WORKER_OK, status);
- // Resend the message, which should succeed and restart the worker.
- version_->SendMessage(TestMsg_Message(),
- CreateReceiverOnCurrentThread(&msg_status));
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(SERVICE_WORKER_OK, msg_status);
+ // The worker should be now started again.
EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
}
TEST_F(ServiceWorkerVersionTest, ReceiveMessageFromWorker) {
+ // Start worker.
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
+ version_->StartWorker(CreateReceiverOnCurrentThread(&status));
+ EXPECT_EQ(ServiceWorkerVersion::STARTING, version_->running_status());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(SERVICE_WORKER_OK, status);
+ EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
+
MessageReceiverFromWorker receiver(version_->embedded_worker());
// Simulate sending some dummy values from the worker.
@@ -304,7 +357,7 @@ TEST_F(ServiceWorkerVersionTest, InstallAndWaitCompletion) {
// Dispatch an install event.
ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
- version_->DispatchInstallEvent(-1, CreateReceiverOnCurrentThread(&status));
+ version_->DispatchInstallEvent(CreateReceiverOnCurrentThread(&status));
// Wait for the completion.
bool status_change_called = false;
@@ -362,23 +415,28 @@ TEST_F(ServiceWorkerVersionTest, RepeatedlyObserveStatusChanges) {
ASSERT_EQ(ServiceWorkerVersion::REDUNDANT, statuses[4]);
}
-TEST_F(ServiceWorkerVersionTest, ScheduleStopWorker) {
+TEST_F(ServiceWorkerVersionTest, IdleTimeout) {
+ // Used to reliably test when the idle time gets reset regardless of clock
+ // granularity.
+ const base::TimeDelta kOneSecond = base::TimeDelta::FromSeconds(1);
+
// Verify the timer is not running when version initializes its status.
version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
- EXPECT_FALSE(version_->stop_worker_timer_.IsRunning());
+ EXPECT_FALSE(version_->timeout_timer_.IsRunning());
- // Verify the timer is running when version status changes frome ACTIVATING
- // to ACTIVATED.
+ // Verify the timer is running after the worker is started.
ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
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());
+ EXPECT_TRUE(version_->timeout_timer_.IsRunning());
+ EXPECT_FALSE(version_->idle_time_.is_null());
- // The timer should be running if the worker is restarted without controllee.
+ // The idle time should be reset if the worker is restarted without
+ // controllee.
status = SERVICE_WORKER_ERROR_FAILED;
+ version_->idle_time_ -= kOneSecond;
+ base::TimeTicks idle_time = version_->idle_time_;
version_->StopWorker(CreateReceiverOnCurrentThread(&status));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(SERVICE_WORKER_OK, status);
@@ -386,47 +444,86 @@ TEST_F(ServiceWorkerVersionTest, ScheduleStopWorker) {
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));
+ EXPECT_TRUE(version_->timeout_timer_.IsRunning());
+ EXPECT_LT(idle_time, version_->idle_time_);
+
+ // Adding a controllee resets the idle time.
+ version_->idle_time_ -= kOneSecond;
+ idle_time = version_->idle_time_;
+ scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
+ 33 /* dummy render process id */, MSG_ROUTING_NONE /* render_frame_id */,
+ 1 /* dummy provider_id */, SERVICE_WORKER_PROVIDER_FOR_WINDOW,
+ helper_->context()->AsWeakPtr(), NULL));
version_->AddControllee(host.get());
- EXPECT_FALSE(version_->stop_worker_timer_.IsRunning());
+ EXPECT_TRUE(version_->timeout_timer_.IsRunning());
+ EXPECT_LT(idle_time, version_->idle_time_);
- // The timer should be running if the controllee is removed.
- version_->RemoveControllee(host.get());
- EXPECT_TRUE(version_->stop_worker_timer_.IsRunning());
+ // Completing an event resets the idle time.
+ status = SERVICE_WORKER_ERROR_FAILED;
+ version_->idle_time_ -= kOneSecond;
+ idle_time = version_->idle_time_;
+ version_->DispatchFetchEvent(ServiceWorkerFetchRequest(),
+ base::Bind(&base::DoNothing),
+ base::Bind(&ReceiveFetchResult, &status));
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(SERVICE_WORKER_OK, status);
+ EXPECT_LT(idle_time, version_->idle_time_);
}
-TEST_F(ServiceWorkerVersionTest, ListenerAvailability) {
- // Initially the worker is not running. There should be no cache_listener_.
- EXPECT_FALSE(version_->cache_listener_.get());
+TEST_F(ServiceWorkerVersionTest, SetDevToolsAttached) {
ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
- version_->StartWorker(
- CreateReceiverOnCurrentThread(&status));
- base::RunLoop().RunUntilIdle();
+ version_->StartWorker(CreateReceiverOnCurrentThread(&status));
- // A new cache listener should be available once the worker starts.
- EXPECT_TRUE(version_->cache_listener_.get());
+ ASSERT_EQ(ServiceWorkerVersion::STARTING, version_->running_status());
+
+ ASSERT_TRUE(version_->timeout_timer_.IsRunning());
+ ASSERT_FALSE(version_->start_time_.is_null());
+ ASSERT_FALSE(version_->skip_recording_startup_time_);
+
+ // Simulate DevTools is attached. This should deactivate the timer for start
+ // timeout, but not stop the timer itself.
+ version_->SetDevToolsAttached(true);
+ EXPECT_TRUE(version_->timeout_timer_.IsRunning());
+ EXPECT_TRUE(version_->start_time_.is_null());
+ EXPECT_TRUE(version_->skip_recording_startup_time_);
+
+ // Simulate DevTools is detached. This should reactivate the timer for start
+ // timeout.
+ version_->SetDevToolsAttached(false);
+ EXPECT_TRUE(version_->timeout_timer_.IsRunning());
+ EXPECT_FALSE(version_->start_time_.is_null());
+ EXPECT_TRUE(version_->skip_recording_startup_time_);
- version_->StopWorker(
- CreateReceiverOnCurrentThread(&status));
base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(SERVICE_WORKER_OK, status);
+ EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
+}
- // Should be destroyed when the worker stops.
- EXPECT_FALSE(version_->cache_listener_.get());
+TEST_F(ServiceWorkerWaitForeverInFetchTest, RequestTimeout) {
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_NETWORK; // dummy value
- version_->StartWorker(
- CreateReceiverOnCurrentThread(&status));
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
+ version_->DispatchFetchEvent(ServiceWorkerFetchRequest(),
+ base::Bind(&base::DoNothing),
+ base::Bind(&ReceiveFetchResult, &status));
base::RunLoop().RunUntilIdle();
- // Recreated when the worker starts again.
- EXPECT_TRUE(version_->cache_listener_.get());
+ // Callback has not completed yet.
+ EXPECT_EQ(SERVICE_WORKER_ERROR_NETWORK, status);
+ EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
+
+ // Simulate timeout.
+ EXPECT_TRUE(version_->timeout_timer_.IsRunning());
+ version_->SetAllRequestTimes(
+ base::TimeTicks::Now() -
+ base::TimeDelta::FromMinutes(
+ ServiceWorkerVersion::kRequestTimeoutMinutes + 1));
+ version_->timeout_timer_.user_task().Run();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(SERVICE_WORKER_ERROR_TIMEOUT, status);
+ EXPECT_EQ(ServiceWorkerVersion::STOPPED, version_->running_status());
}
TEST_F(ServiceWorkerFailToStartTest, RendererCrash) {
@@ -452,4 +549,29 @@ TEST_F(ServiceWorkerFailToStartTest, RendererCrash) {
EXPECT_EQ(ServiceWorkerVersion::STOPPED, version_->running_status());
}
+TEST_F(ServiceWorkerFailToStartTest, Timeout) {
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_NETWORK; // dummy value
+
+ // We could just call StartWorker but make it interesting and test
+ // starting the worker as part of dispatching an event.
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATING);
+ version_->DispatchActivateEvent(CreateReceiverOnCurrentThread(&status));
+ base::RunLoop().RunUntilIdle();
+
+ // Callback has not completed yet.
+ EXPECT_EQ(SERVICE_WORKER_ERROR_NETWORK, status);
+ EXPECT_EQ(ServiceWorkerVersion::STARTING, version_->running_status());
+
+ // Simulate timeout.
+ EXPECT_TRUE(version_->timeout_timer_.IsRunning());
+ version_->start_time_ =
+ base::TimeTicks::Now() -
+ base::TimeDelta::FromMinutes(
+ ServiceWorkerVersion::kStartWorkerTimeoutMinutes + 1);
+ version_->timeout_timer_.user_task().Run();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(SERVICE_WORKER_ERROR_TIMEOUT, 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 0baf702a259..b04e98b3c15 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,10 +4,14 @@
#include "content/browser/service_worker/service_worker_write_to_cache_job.h"
-#include "base/debug/trace_event.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/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_metrics.h"
+#include "content/browser/service_worker/service_worker_utils.h"
+#include "content/common/service_worker/service_worker_types.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/http/http_network_session.h"
@@ -20,6 +24,23 @@
namespace content {
+namespace {
+
+const char kKilledError[] = "The request to fetch the script was interrupted.";
+const char kBadHTTPResponseError[] =
+ "A bad HTTP response code (%d) was received when fetching the script.";
+const char kSSLError[] =
+ "An SSL certificate error occurred when fetching the script.";
+const char kBadMIMEError[] = "The script has an unsupported MIME type ('%s').";
+const char kNoMIMEError[] = "The script does not have a MIME type.";
+const char kClientAuthenticationError[] =
+ "Client authentication was required to fetch the script.";
+const char kRedirectError[] =
+ "The script resource is behind a redirect, which is disallowed.";
+const char kServiceWorkerAllowed[] = "Service-Worker-Allowed";
+
+}
+
ServiceWorkerWriteToCacheJob::ServiceWorkerWriteToCacheJob(
net::URLRequest* request,
net::NetworkDelegate* network_delegate,
@@ -69,9 +90,9 @@ void ServiceWorkerWriteToCacheJob::Kill() {
net_request_.reset();
if (did_notify_started_ && !did_notify_finished_) {
version_->script_cache_map()->NotifyFinishedCaching(
- url_,
- -1,
- net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_ABORTED));
+ url_, -1,
+ net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_ABORTED),
+ kKilledError);
did_notify_finished_ = true;
}
writer_.reset();
@@ -131,7 +152,7 @@ bool ServiceWorkerWriteToCacheJob::ReadRawData(
// No more data to process, the job is complete.
io_buffer_ = NULL;
version_->script_cache_map()->NotifyFinishedCaching(
- url_, writer_->amount_written(), status);
+ url_, writer_->amount_written(), status, std::string());
did_notify_finished_ = true;
return status.is_success();
}
@@ -144,10 +165,7 @@ void ServiceWorkerWriteToCacheJob::InitNetRequest(
int extra_load_flags) {
DCHECK(request());
net_request_ = request()->context()->CreateRequest(
- request()->url(),
- request()->priority(),
- this,
- this->GetCookieStore());
+ request()->url(), request()->priority(), this);
net_request_->set_first_party_for_cookies(
request()->first_party_for_cookies());
net_request_->SetReferrer(request()->referrer());
@@ -198,8 +216,9 @@ net::URLRequestStatus ServiceWorkerWriteToCacheJob::ReadNetData(
void ServiceWorkerWriteToCacheJob::WriteHeadersToCache() {
if (!context_) {
- AsyncNotifyDoneHelper(net::URLRequestStatus(
- net::URLRequestStatus::FAILED, net::ERR_FAILED));
+ AsyncNotifyDoneHelper(
+ net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED),
+ kFetchScriptError);
return;
}
TRACE_EVENT_ASYNC_STEP_INTO0("ServiceWorker",
@@ -221,8 +240,9 @@ void ServiceWorkerWriteToCacheJob::OnWriteHeadersComplete(int result) {
if (result < 0) {
ServiceWorkerMetrics::CountWriteResponseResult(
ServiceWorkerMetrics::WRITE_HEADERS_ERROR);
- AsyncNotifyDoneHelper(net::URLRequestStatus(
- net::URLRequestStatus::FAILED, result));
+ AsyncNotifyDoneHelper(
+ net::URLRequestStatus(net::URLRequestStatus::FAILED, result),
+ kFetchScriptError);
return;
}
http_info_.reset(info_buffer_->http_info.release());
@@ -253,15 +273,17 @@ void ServiceWorkerWriteToCacheJob::OnWriteDataComplete(int result) {
DCHECK_NE(0, result);
io_buffer_ = NULL;
if (!context_) {
- AsyncNotifyDoneHelper(net::URLRequestStatus(
- net::URLRequestStatus::FAILED, net::ERR_FAILED));
+ AsyncNotifyDoneHelper(
+ net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED),
+ kFetchScriptError);
return;
}
if (result < 0) {
ServiceWorkerMetrics::CountWriteResponseResult(
ServiceWorkerMetrics::WRITE_DATA_ERROR);
- AsyncNotifyDoneHelper(net::URLRequestStatus(
- net::URLRequestStatus::FAILED, result));
+ AsyncNotifyDoneHelper(
+ net::URLRequestStatus(net::URLRequestStatus::FAILED, result),
+ kFetchScriptError);
return;
}
ServiceWorkerMetrics::CountWriteResponseResult(
@@ -281,8 +303,9 @@ void ServiceWorkerWriteToCacheJob::OnReceivedRedirect(
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerWriteToCacheJob::OnReceivedRedirect");
// Script resources can't redirect.
- AsyncNotifyDoneHelper(net::URLRequestStatus(
- net::URLRequestStatus::FAILED, net::ERR_UNSAFE_REDIRECT));
+ AsyncNotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
+ net::ERR_UNSAFE_REDIRECT),
+ kRedirectError);
}
void ServiceWorkerWriteToCacheJob::OnAuthRequired(
@@ -292,8 +315,9 @@ void ServiceWorkerWriteToCacheJob::OnAuthRequired(
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerWriteToCacheJob::OnAuthRequired");
// TODO(michaeln): Pass this thru to our jobs client.
- AsyncNotifyDoneHelper(net::URLRequestStatus(
- net::URLRequestStatus::FAILED, net::ERR_FAILED));
+ AsyncNotifyDoneHelper(
+ net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED),
+ kClientAuthenticationError);
}
void ServiceWorkerWriteToCacheJob::OnCertificateRequested(
@@ -304,8 +328,9 @@ void ServiceWorkerWriteToCacheJob::OnCertificateRequested(
"ServiceWorkerWriteToCacheJob::OnCertificateRequested");
// TODO(michaeln): Pass this thru to our jobs client.
// see NotifyCertificateRequested.
- AsyncNotifyDoneHelper(net::URLRequestStatus(
- net::URLRequestStatus::FAILED, net::ERR_FAILED));
+ AsyncNotifyDoneHelper(
+ net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED),
+ kClientAuthenticationError);
}
void ServiceWorkerWriteToCacheJob::OnSSLCertificateError(
@@ -317,8 +342,9 @@ void ServiceWorkerWriteToCacheJob::OnSSLCertificateError(
"ServiceWorkerWriteToCacheJob::OnSSLCertificateError");
// TODO(michaeln): Pass this thru to our jobs client,
// see NotifySSLCertificateError.
- AsyncNotifyDoneHelper(net::URLRequestStatus(
- net::URLRequestStatus::FAILED, net::ERR_INSECURE_RESPONSE));
+ AsyncNotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
+ net::ERR_INSECURE_RESPONSE),
+ kSSLError);
}
void ServiceWorkerWriteToCacheJob::OnBeforeNetworkStart(
@@ -334,12 +360,15 @@ void ServiceWorkerWriteToCacheJob::OnResponseStarted(
net::URLRequest* request) {
DCHECK_EQ(net_request_, request);
if (!request->status().is_success()) {
- AsyncNotifyDoneHelper(request->status());
+ AsyncNotifyDoneHelper(request->status(), kFetchScriptError);
return;
}
if (request->GetResponseCode() / 100 != 2) {
- AsyncNotifyDoneHelper(net::URLRequestStatus(
- net::URLRequestStatus::FAILED, net::ERR_FAILED));
+ std::string error_message =
+ base::StringPrintf(kBadHTTPResponseError, request->GetResponseCode());
+ AsyncNotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
+ net::ERR_INVALID_RESPONSE),
+ error_message);
// TODO(michaeln): Instead of error'ing immediately, send the net
// response to our consumer, just don't cache it?
return;
@@ -351,22 +380,37 @@ void ServiceWorkerWriteToCacheJob::OnResponseStarted(
request->context()->GetNetworkSessionParams();
if (!session_params || !session_params->ignore_certificate_errors) {
AsyncNotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
- net::ERR_INSECURE_RESPONSE));
+ net::ERR_INSECURE_RESPONSE),
+ kSSLError);
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));
+ std::string error_message =
+ mime_type.empty()
+ ? kNoMIMEError
+ : base::StringPrintf(kBadMIMEError, mime_type.c_str());
+ AsyncNotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
+ net::ERR_INSECURE_RESPONSE),
+ error_message);
return;
}
+
+ if (!CheckPathRestriction(request))
+ return;
+
+ version_->SetMainScriptHttpResponseInfo(net_request_->response_info());
}
+
+ if (net_request_->response_info().network_accessed)
+ version_->embedded_worker()->OnNetworkAccessedForScriptLoad();
+
WriteHeadersToCache();
}
@@ -376,7 +420,7 @@ void ServiceWorkerWriteToCacheJob::OnReadCompleted(
DCHECK_EQ(net_request_, request);
if (bytes_read < 0) {
DCHECK(!request->status().is_success());
- AsyncNotifyDoneHelper(request->status());
+ AsyncNotifyDoneHelper(request->status(), kFetchScriptError);
return;
}
if (bytes_read > 0) {
@@ -387,21 +431,42 @@ void ServiceWorkerWriteToCacheJob::OnReadCompleted(
DCHECK(request->status().is_success());
io_buffer_ = NULL;
version_->script_cache_map()->NotifyFinishedCaching(
- url_, writer_->amount_written(), net::URLRequestStatus());
+ url_, writer_->amount_written(), net::URLRequestStatus(), std::string());
did_notify_finished_ = true;
SetStatus(net::URLRequestStatus()); // Clear the IO_PENDING status
NotifyReadComplete(0);
}
+bool ServiceWorkerWriteToCacheJob::CheckPathRestriction(
+ net::URLRequest* request) {
+ std::string service_worker_allowed;
+ const net::HttpResponseHeaders* headers = request->response_headers();
+ bool has_header = headers->EnumerateHeader(nullptr, kServiceWorkerAllowed,
+ &service_worker_allowed);
+
+ std::string error_message;
+ if (!ServiceWorkerUtils::IsPathRestrictionSatisfied(
+ version_->scope(), url_,
+ has_header ? &service_worker_allowed : nullptr, &error_message)) {
+ AsyncNotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
+ net::ERR_INSECURE_RESPONSE),
+ error_message);
+ return false;
+ }
+ return true;
+}
+
void ServiceWorkerWriteToCacheJob::AsyncNotifyDoneHelper(
- const net::URLRequestStatus& status) {
+ const net::URLRequestStatus& status,
+ const std::string& status_message) {
DCHECK(!status.is_io_pending());
DCHECK(!did_notify_finished_);
int size = -1;
if (writer_.get()) {
size = writer_->amount_written();
}
- version_->script_cache_map()->NotifyFinishedCaching(url_, size, status);
+ version_->script_cache_map()->NotifyFinishedCaching(url_, size, status,
+ status_message);
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 ec3bfa7464b..507b78b50a4 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
@@ -48,6 +48,8 @@ class CONTENT_EXPORT ServiceWorkerWriteToCacheJob
UpdateBefore24Hours);
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerContextRequestHandlerTest,
UpdateAfter24Hours);
+ FRIEND_TEST_ALL_PREFIXES(ServiceWorkerContextRequestHandlerTest,
+ UpdateForceBypassCache);
~ServiceWorkerWriteToCacheJob() override;
@@ -93,7 +95,10 @@ class CONTENT_EXPORT ServiceWorkerWriteToCacheJob
void OnResponseStarted(net::URLRequest* request) override;
void OnReadCompleted(net::URLRequest* request, int bytes_read) override;
- void AsyncNotifyDoneHelper(const net::URLRequestStatus& status);
+ bool CheckPathRestriction(net::URLRequest* request);
+
+ void AsyncNotifyDoneHelper(const net::URLRequestStatus& status,
+ const std::string& status_message);
ResourceType resource_type_; // Differentiate main script and imports
scoped_refptr<net::IOBuffer> io_buffer_;
diff --git a/chromium/content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc b/chromium/content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc
index 7c6ad3282a7..cd90d45f731 100644
--- a/chromium/content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc
@@ -170,11 +170,12 @@ class ServiceWorkerWriteToCacheJobTest : public testing::Test {
public:
ServiceWorkerWriteToCacheJobTest()
: browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP),
- mock_protocol_handler_(NULL) {}
+ mock_protocol_handler_(nullptr) {}
~ServiceWorkerWriteToCacheJobTest() override {}
void SetUp() override {
- helper_.reset(new EmbeddedWorkerTestHelper(kMockRenderProcessId));
+ helper_.reset(
+ new EmbeddedWorkerTestHelper(base::FilePath(), kMockRenderProcessId));
// A new unstored registration/version.
scope_ = GURL("https://host/scope/");
@@ -186,7 +187,8 @@ class ServiceWorkerWriteToCacheJobTest : public testing::Test {
// An empty host.
scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
- kMockRenderProcessId, kMockProviderId, context()->AsWeakPtr(), NULL));
+ kMockRenderProcessId, MSG_ROUTING_NONE, kMockProviderId,
+ SERVICE_WORKER_PROVIDER_FOR_WINDOW, context()->AsWeakPtr(), nullptr));
provider_host_ = host->AsWeakPtr();
context()->AddProviderHost(host.Pass());
provider_host_->running_hosted_version_ = version_;
@@ -202,7 +204,7 @@ class ServiceWorkerWriteToCacheJobTest : public testing::Test {
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);
+ script_url_, net::DEFAULT_PRIORITY, &url_request_delegate_);
ServiceWorkerRequestHandler::InitializeHandler(
request_.get(),
context_wrapper(),
@@ -222,9 +224,9 @@ class ServiceWorkerWriteToCacheJobTest : public testing::Test {
request_.reset();
url_request_context_.reset();
url_request_job_factory_.reset();
- mock_protocol_handler_ = NULL;
- version_ = NULL;
- registration_ = NULL;
+ mock_protocol_handler_ = nullptr;
+ version_ = nullptr;
+ registration_ = nullptr;
helper_.reset();
// URLRequestJobs may post clean-up tasks on destruction.
base::RunLoop().RunUntilIdle();
diff --git a/chromium/content/browser/shareable_file_reference_unittest.cc b/chromium/content/browser/shareable_file_reference_unittest.cc
new file mode 100644
index 00000000000..84d035fd43d
--- /dev/null
+++ b/chromium/content/browser/shareable_file_reference_unittest.cc
@@ -0,0 +1,61 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "storage/browser/blob/shareable_file_reference.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 "testing/gtest/include/gtest/gtest.h"
+
+using storage::ShareableFileReference;
+
+namespace content {
+
+TEST(ShareableFileReferenceTest, TestReferences) {
+ base::MessageLoop message_loop;
+ scoped_refptr<base::MessageLoopProxy> loop_proxy =
+ base::MessageLoopProxy::current();
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+
+ // Create a file.
+ base::FilePath file;
+ base::CreateTemporaryFileInDir(temp_dir.path(), &file);
+ EXPECT_TRUE(base::PathExists(file));
+
+ // Create a first reference to that file.
+ scoped_refptr<ShareableFileReference> reference1;
+ reference1 = ShareableFileReference::Get(file);
+ EXPECT_FALSE(reference1.get());
+ reference1 = ShareableFileReference::GetOrCreate(
+ file, ShareableFileReference::DELETE_ON_FINAL_RELEASE, loop_proxy.get());
+ EXPECT_TRUE(reference1.get());
+ EXPECT_TRUE(file == reference1->path());
+
+ // Get a second reference to that file.
+ scoped_refptr<ShareableFileReference> reference2;
+ reference2 = ShareableFileReference::Get(file);
+ EXPECT_EQ(reference1.get(), reference2.get());
+ reference2 = ShareableFileReference::GetOrCreate(
+ file, ShareableFileReference::DELETE_ON_FINAL_RELEASE, loop_proxy.get());
+ EXPECT_EQ(reference1.get(), reference2.get());
+
+ // Drop the first reference, the file and reference should still be there.
+ reference1 = NULL;
+ EXPECT_TRUE(ShareableFileReference::Get(file).get());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(base::PathExists(file));
+
+ // Drop the second reference, the file and reference should get deleted.
+ reference2 = NULL;
+ EXPECT_FALSE(ShareableFileReference::Get(file).get());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(base::PathExists(file));
+
+ // TODO(michaeln): add a test for files that aren't deletable behavior.
+}
+
+} // namespace content
diff --git a/chromium/content/browser/shared_worker/shared_worker_host.cc b/chromium/content/browser/shared_worker/shared_worker_host.cc
index 40499930675..d9b6d9fb104 100644
--- a/chromium/content/browser/shared_worker/shared_worker_host.cc
+++ b/chromium/content/browser/shared_worker/shared_worker_host.cc
@@ -5,9 +5,10 @@
#include "content/browser/shared_worker/shared_worker_host.h"
#include "base/metrics/histogram.h"
-#include "content/browser/devtools/embedded_worker_devtools_manager.h"
+#include "content/browser/devtools/shared_worker_devtools_manager.h"
#include "content/browser/frame_host/render_frame_host_delegate.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
+#include "content/browser/message_port_message_filter.h"
#include "content/browser/message_port_service.h"
#include "content/browser/shared_worker/shared_worker_instance.h"
#include "content/browser/shared_worker/shared_worker_message_filter.h"
@@ -41,7 +42,7 @@ void NotifyWorkerReadyForInspection(int worker_process_id,
worker_route_id));
return;
}
- EmbeddedWorkerDevToolsManager::GetInstance()->WorkerReadyForInspection(
+ SharedWorkerDevToolsManager::GetInstance()->WorkerReadyForInspection(
worker_process_id, worker_route_id);
}
@@ -53,7 +54,7 @@ void NotifyWorkerDestroyed(int worker_process_id, int worker_route_id) {
base::Bind(NotifyWorkerDestroyed, worker_process_id, worker_route_id));
return;
}
- EmbeddedWorkerDevToolsManager::GetInstance()->WorkerDestroyed(
+ SharedWorkerDevToolsManager::GetInstance()->WorkerDestroyed(
worker_process_id, worker_route_id);
}
@@ -71,11 +72,11 @@ SharedWorkerHost::SharedWorkerHost(SharedWorkerInstance* instance,
closed_(false),
creation_time_(base::TimeTicks::Now()),
weak_factory_(this) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
}
SharedWorkerHost::~SharedWorkerHost() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
UMA_HISTOGRAM_LONG_TIMES("SharedWorker.TimeToDeleted",
base::TimeTicks::Now() - creation_time_);
// If we crashed, tell the RenderViewHosts.
@@ -266,8 +267,8 @@ void SharedWorkerHost::RelayMessage(
WorkerMsg_Connect::Param param;
if (!WorkerMsg_Connect::Read(&message, &param))
return;
- int sent_message_port_id = param.a;
- int new_routing_id = param.b;
+ int sent_message_port_id = get<0>(param);
+ int new_routing_id = get<1>(param);
DCHECK(container_render_filter_);
new_routing_id = container_render_filter_->GetNextRoutingID();
diff --git a/chromium/content/browser/shared_worker/shared_worker_instance.h b/chromium/content/browser/shared_worker/shared_worker_instance.h
index b7c5fdb2d70..5d650e5cad9 100644
--- a/chromium/content/browser/shared_worker/shared_worker_instance.h
+++ b/chromium/content/browser/shared_worker/shared_worker_instance.h
@@ -17,7 +17,7 @@ namespace content {
class ResourceContext;
// SharedWorkerInstance is copyable value-type data type. It could be passed to
-// the UI thread and be used for comparison in EmbeddedWorkerDevToolsManager.
+// the UI thread and be used for comparison in SharedWorkerDevToolsManager.
class CONTENT_EXPORT SharedWorkerInstance {
public:
SharedWorkerInstance(const GURL& url,
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 20e2526899b..9f75967517c 100644
--- a/chromium/content/browser/shared_worker/shared_worker_message_filter.cc
+++ b/chromium/content/browser/shared_worker/shared_worker_message_filter.cc
@@ -32,7 +32,7 @@ SharedWorkerMessageFilter::SharedWorkerMessageFilter(
}
SharedWorkerMessageFilter::~SharedWorkerMessageFilter() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
}
void SharedWorkerMessageFilter::OnChannelClosing() {
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 b773127db63..0f6958b8176 100644
--- a/chromium/content/browser/shared_worker/shared_worker_service_impl.cc
+++ b/chromium/content/browser/shared_worker/shared_worker_service_impl.cc
@@ -11,7 +11,7 @@
#include "base/callback.h"
#include "base/memory/ref_counted.h"
-#include "content/browser/devtools/embedded_worker_devtools_manager.h"
+#include "content/browser/devtools/shared_worker_devtools_manager.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/browser/shared_worker/shared_worker_host.h"
#include "content/browser/shared_worker/shared_worker_instance.h"
@@ -190,7 +190,7 @@ class SharedWorkerServiceImpl::SharedWorkerReserver
void TryReserve(const base::Callback<void(bool)>& success_cb,
const base::Closure& failure_cb,
bool (*try_increment_worker_ref_count)(int)) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!try_increment_worker_ref_count(worker_process_id_)) {
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, failure_cb);
return;
@@ -198,7 +198,7 @@ class SharedWorkerServiceImpl::SharedWorkerReserver
bool pause_on_start = false;
if (is_new_worker_) {
pause_on_start =
- EmbeddedWorkerDevToolsManager::GetInstance()->SharedWorkerCreated(
+ SharedWorkerDevToolsManager::GetInstance()->WorkerCreated(
worker_process_id_, worker_route_id_, instance_);
}
BrowserThread::PostTask(
@@ -220,7 +220,7 @@ bool (*SharedWorkerServiceImpl::s_try_increment_worker_ref_count_)(int) =
TryIncrementWorkerRefCount;
SharedWorkerServiceImpl* SharedWorkerServiceImpl::GetInstance() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
return Singleton<SharedWorkerServiceImpl>::get();
}
@@ -269,12 +269,12 @@ std::vector<WorkerService::WorkerInfo> SharedWorkerServiceImpl::GetWorkers() {
}
void SharedWorkerServiceImpl::AddObserver(WorkerServiceObserver* observer) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
observers_.AddObserver(observer);
}
void SharedWorkerServiceImpl::RemoveObserver(WorkerServiceObserver* observer) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
observers_.RemoveObserver(observer);
}
@@ -285,7 +285,7 @@ void SharedWorkerServiceImpl::CreateWorker(
ResourceContext* resource_context,
const WorkerStoragePartitionId& partition_id,
bool* url_mismatch) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
*url_mismatch = false;
scoped_ptr<SharedWorkerInstance> instance(
new SharedWorkerInstance(params.url,
@@ -401,6 +401,8 @@ void SharedWorkerServiceImpl::AllowDatabase(
SharedWorkerMessageFilter* filter) {
if (SharedWorkerHost* host = FindSharedWorkerHost(filter, worker_route_id))
host->AllowDatabase(url, name, display_name, estimated_size, result);
+ else
+ *result = false;
}
void SharedWorkerServiceImpl::AllowFileSystem(
@@ -424,6 +426,8 @@ void SharedWorkerServiceImpl::AllowIndexedDB(
SharedWorkerMessageFilter* filter) {
if (SharedWorkerHost* host = FindSharedWorkerHost(filter, worker_route_id))
host->AllowIndexedDB(url, name, result);
+ else
+ *result = false;
}
void SharedWorkerServiceImpl::OnSharedWorkerMessageFilterClosing(
@@ -464,7 +468,7 @@ void SharedWorkerServiceImpl::NotifyWorkerDestroyed(int worker_process_id,
void SharedWorkerServiceImpl::ReserveRenderProcessToCreateWorker(
scoped_ptr<SharedWorkerPendingInstance> pending_instance,
bool* url_mismatch) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(!FindPendingInstance(*pending_instance->instance()));
if (url_mismatch)
*url_mismatch = false;
@@ -525,7 +529,7 @@ void SharedWorkerServiceImpl::RenderProcessReservedCallback(
int worker_route_id,
bool is_new_worker,
bool pause_on_start) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
// To offset the TryIncrementWorkerRefCount called for the reservation,
// calls DecrementWorkerRefCount after CheckWorkerDependency in
// ScopeWorkerDependencyChecker's destructor.
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 b09d58345a9..f1fa702dcc8 100644
--- a/chromium/content/browser/shared_worker/shared_worker_service_impl.h
+++ b/chromium/content/browser/shared_worker/shared_worker_service_impl.h
@@ -109,9 +109,9 @@ class CONTENT_EXPORT SharedWorkerServiceImpl
typedef bool (*TryIncrementWorkerRefCountFunc)(bool);
// Pair of render_process_id and worker_route_id.
typedef std::pair<int, int> ProcessRouteIdPair;
- typedef base::ScopedPtrHashMap<ProcessRouteIdPair, SharedWorkerHost>
- WorkerHostMap;
- typedef base::ScopedPtrHashMap<int, SharedWorkerPendingInstance>
+ typedef base::ScopedPtrHashMap<ProcessRouteIdPair,
+ scoped_ptr<SharedWorkerHost>> WorkerHostMap;
+ typedef base::ScopedPtrHashMap<int, scoped_ptr<SharedWorkerPendingInstance>>
PendingInstaneMap;
SharedWorkerServiceImpl();
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 8e1dd80104d..7ca585ea2cd 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
@@ -285,10 +285,11 @@ class MockSharedWorkerConnector {
new MessagePortHostMsg_QueueMessages(remote_port_id_)));
}
void SendPostMessage(std::string data) {
- const std::vector<int> empty_ids;
+ const std::vector<TransferredMessagePort> empty_ports;
EXPECT_TRUE(
renderer_host_->OnMessageReceived(new MessagePortHostMsg_PostMessage(
- local_port_id_, base::ASCIIToUTF16(data), empty_ids)));
+ local_port_id_,
+ MessagePortMessage(base::ASCIIToUTF16(data)), empty_ports)));
}
void SendConnect() {
EXPECT_TRUE(
@@ -326,12 +327,12 @@ void CheckWorkerProcessMsgCreateWorker(
int* route_id) {
scoped_ptr<IPC::Message> msg(renderer_host->PopMessage());
EXPECT_EQ(WorkerProcessMsg_CreateWorker::ID, msg->type());
- Tuple1<WorkerProcessMsg_CreateWorker_Params> param;
+ Tuple<WorkerProcessMsg_CreateWorker_Params> param;
EXPECT_TRUE(WorkerProcessMsg_CreateWorker::Read(msg.get(), &param));
- EXPECT_EQ(GURL(expected_url), param.a.url);
- EXPECT_EQ(base::ASCIIToUTF16(expected_name), param.a.name);
- EXPECT_EQ(expected_security_policy_type, param.a.security_policy_type);
- *route_id = param.a.route_id;
+ EXPECT_EQ(GURL(expected_url), get<0>(param).url);
+ EXPECT_EQ(base::ASCIIToUTF16(expected_name), get<0>(param).name);
+ EXPECT_EQ(expected_security_policy_type, get<0>(param).security_policy_type);
+ *route_id = get<0>(param).route_id;
}
void CheckViewMsgWorkerCreated(MockRendererProcessHost* renderer_host,
@@ -357,8 +358,8 @@ void CheckWorkerMsgConnect(MockRendererProcessHost* renderer_host,
EXPECT_EQ(expected_msg_route_id, msg->routing_id());
WorkerMsg_Connect::Param params;
EXPECT_TRUE(WorkerMsg_Connect::Read(msg.get(), &params));
- int port_id = params.a;
- *routing_id = params.b;
+ int port_id = get<0>(params);
+ *routing_id = get<1>(params);
EXPECT_EQ(expected_sent_message_port_id, port_id);
}
@@ -370,7 +371,7 @@ void CheckMessagePortMsgMessage(MockRendererProcessHost* renderer_host,
EXPECT_EQ(expected_msg_route_id, msg->routing_id());
MessagePortMsg_Message::Param params;
EXPECT_TRUE(MessagePortMsg_Message::Read(msg.get(), &params));
- base::string16 data = params.a;
+ base::string16 data = get<0>(params).message_as_string;
EXPECT_EQ(base::ASCIIToUTF16(expected_data), data);
}
@@ -466,11 +467,11 @@ TEST_F(SharedWorkerServiceImplTest, BasicTest) {
// When SharedWorker side sends MessagePortHostMsg_PostMessage,
// SharedWorkerConnector side shuold receive MessagePortMsg_Message.
- const std::vector<int> empty_ids;
- EXPECT_TRUE(renderer_host->OnMessageReceived(
- new MessagePortHostMsg_PostMessage(connector->remote_port_id(),
- base::ASCIIToUTF16("test2"),
- empty_ids)));
+ const std::vector<TransferredMessagePort> empty_ports;
+ EXPECT_TRUE(
+ renderer_host->OnMessageReceived(new MessagePortHostMsg_PostMessage(
+ connector->remote_port_id(),
+ MessagePortMessage(base::ASCIIToUTF16("test2")), empty_ports)));
EXPECT_EQ(1U, renderer_host->QueuedMessageCount());
CheckMessagePortMsgMessage(
renderer_host.get(), connector->local_port_route_id(), "test2");
@@ -563,11 +564,11 @@ TEST_F(SharedWorkerServiceImplTest, TwoRendererTest) {
// When SharedWorker side sends MessagePortHostMsg_PostMessage,
// SharedWorkerConnector side shuold receive MessagePortMsg_Message.
- const std::vector<int> empty_ids;
- EXPECT_TRUE(renderer_host0->OnMessageReceived(
- new MessagePortHostMsg_PostMessage(connector0->remote_port_id(),
- base::ASCIIToUTF16("test2"),
- empty_ids)));
+ const std::vector<TransferredMessagePort> empty_ports;
+ EXPECT_TRUE(
+ renderer_host0->OnMessageReceived(new MessagePortHostMsg_PostMessage(
+ connector0->remote_port_id(),
+ MessagePortMessage(base::ASCIIToUTF16("test2")), empty_ports)));
EXPECT_EQ(1U, renderer_host0->QueuedMessageCount());
CheckMessagePortMsgMessage(
renderer_host0.get(), connector0->local_port_route_id(), "test2");
@@ -643,10 +644,10 @@ TEST_F(SharedWorkerServiceImplTest, TwoRendererTest) {
// When SharedWorker side sends MessagePortHostMsg_PostMessage,
// SharedWorkerConnector side shuold receive MessagePortMsg_Message.
- EXPECT_TRUE(renderer_host0->OnMessageReceived(
- new MessagePortHostMsg_PostMessage(connector1->remote_port_id(),
- base::ASCIIToUTF16("test4"),
- empty_ids)));
+ EXPECT_TRUE(
+ renderer_host0->OnMessageReceived(new MessagePortHostMsg_PostMessage(
+ connector1->remote_port_id(),
+ MessagePortMessage(base::ASCIIToUTF16("test4")), empty_ports)));
EXPECT_EQ(1U, renderer_host1->QueuedMessageCount());
CheckMessagePortMsgMessage(
renderer_host1.get(), connector1->local_port_route_id(), "test4");
diff --git a/chromium/content/browser/shared_worker/worker_browsertest.cc b/chromium/content/browser/shared_worker/worker_browsertest.cc
index ce39df5788c..0a9c34cd8d9 100644
--- a/chromium/content/browser/shared_worker/worker_browsertest.cc
+++ b/chromium/content/browser/shared_worker/worker_browsertest.cc
@@ -11,6 +11,7 @@
#include "base/sys_info.h"
#include "base/test/test_timeouts.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/client_certificate_delegate.h"
#include "content/public/common/content_paths.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
@@ -19,15 +20,45 @@
#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/escape.h"
#include "net/base/test_data_directory.h"
#include "net/test/spawned_test_server/spawned_test_server.h"
#include "url/gurl.h"
namespace content {
+namespace {
+
+bool SupportsSharedWorker() {
+#if defined(OS_ANDROID)
+ // SharedWorkers are not enabled on Android. https://crbug.com/154571
+ //
+ // TODO(davidben): Move other SharedWorker exclusions from
+ // build/android/pylib/gtest/filter/ inline.
+ return false;
+#else
+ return true;
+#endif
+}
+
+} // namespace
+
class WorkerTest : public ContentBrowserTest {
public:
- WorkerTest() {}
+ WorkerTest() : select_certificate_count_(0) {}
+
+ void SetUpOnMainThread() override {
+ ShellContentBrowserClient::Get()->set_select_client_certificate_callback(
+ base::Bind(&WorkerTest::OnSelectClientCertificate,
+ base::Unretained(this)));
+ }
+
+ void TearDownOnMainThread() override {
+ ShellContentBrowserClient::Get()->set_select_client_certificate_callback(
+ base::Closure());
+ }
+
+ int select_certificate_count() const { return select_certificate_count_; }
GURL GetTestURL(const std::string& test_case, const std::string& query) {
base::FilePath test_file_path = GetTestFilePath(
@@ -64,6 +95,11 @@ class WorkerTest : public ContentBrowserTest {
shell()->LoadURL(url);
runner->Run();
}
+
+ private:
+ void OnSelectClientCertificate() { select_certificate_count_++; }
+
+ int select_certificate_count_;
};
IN_PROC_BROWSER_TEST_F(WorkerTest, SingleWorker) {
@@ -75,17 +111,26 @@ IN_PROC_BROWSER_TEST_F(WorkerTest, MultipleWorkers) {
}
IN_PROC_BROWSER_TEST_F(WorkerTest, SingleSharedWorker) {
+ if (!SupportsSharedWorker())
+ return;
+
RunTest("single_worker.html", "shared=true");
}
// http://crbug.com/96435
IN_PROC_BROWSER_TEST_F(WorkerTest, MultipleSharedWorkers) {
+ if (!SupportsSharedWorker())
+ return;
+
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) {
+ if (!SupportsSharedWorker())
+ return;
+
// Load a non-incognito tab and have it create a shared worker
RunTest("incognito_worker.html", std::string());
@@ -102,15 +147,62 @@ IN_PROC_BROWSER_TEST_F(WorkerTest, WorkerHttpAuth) {
NavigateAndWaitForAuth(url);
}
-// Make sure that auth dialog is displayed from shared worker context.
+// Make sure that HTTP auth dialog is displayed from shared worker context.
// http://crbug.com/33344
+//
+// TODO(davidben): HTTP auth dialogs are no longer displayed on shared workers,
+// but this test only tests that the delegate is called. Move handling the
+// WebContentsless case from chrome/ to content/ and adjust the test
+// accordingly.
IN_PROC_BROWSER_TEST_F(WorkerTest, SharedWorkerHttpAuth) {
+ if (!SupportsSharedWorker())
+ return;
+
ASSERT_TRUE(test_server()->Start());
GURL url = test_server()->GetURL("files/workers/shared_worker_auth.html");
NavigateAndWaitForAuth(url);
}
+// Tests that TLS client auth prompts for normal workers.
+IN_PROC_BROWSER_TEST_F(WorkerTest, WorkerTlsClientAuth) {
+ // Launch HTTPS server.
+ net::SpawnedTestServer::SSLOptions ssl_options;
+ ssl_options.request_client_certificate = true;
+ net::SpawnedTestServer https_server(
+ net::SpawnedTestServer::TYPE_HTTPS, ssl_options,
+ base::FilePath(FILE_PATH_LITERAL("content/test/data")));
+ ASSERT_TRUE(https_server.Start());
+
+ RunTest("worker_tls_client_auth.html",
+ "url=" +
+ net::EscapeQueryParamValue(https_server.GetURL("").spec(), true));
+ EXPECT_EQ(1, select_certificate_count());
+}
+
+// Tests that TLS client auth does not prompt for a shared worker; shared
+// workers are not associated with a WebContents.
+IN_PROC_BROWSER_TEST_F(WorkerTest, SharedWorkerTlsClientAuth) {
+ if (!SupportsSharedWorker())
+ return;
+
+ // Launch HTTPS server.
+ net::SpawnedTestServer::SSLOptions ssl_options;
+ ssl_options.request_client_certificate = true;
+ net::SpawnedTestServer https_server(
+ net::SpawnedTestServer::TYPE_HTTPS, ssl_options,
+ base::FilePath(FILE_PATH_LITERAL("content/test/data")));
+ ASSERT_TRUE(https_server.Start());
+
+ RunTest("worker_tls_client_auth.html",
+ "shared=true&url=" +
+ net::EscapeQueryParamValue(https_server.GetURL("").spec(), true));
+ EXPECT_EQ(0, select_certificate_count());
+}
+
IN_PROC_BROWSER_TEST_F(WorkerTest, WebSocketSharedWorker) {
+ if (!SupportsSharedWorker())
+ return;
+
// Launch WebSocket server.
net::SpawnedTestServer ws_server(net::SpawnedTestServer::TYPE_WS,
net::SpawnedTestServer::kLocalhost,
@@ -118,9 +210,8 @@ IN_PROC_BROWSER_TEST_F(WorkerTest, WebSocketSharedWorker) {
ASSERT_TRUE(ws_server.Start());
// Generate test URL.
- std::string scheme("http");
GURL::Replacements replacements;
- replacements.SetSchemeStr(scheme);
+ replacements.SetSchemeStr("http");
GURL url = ws_server.GetURL(
"websocket_shared_worker.html").ReplaceComponents(replacements);
@@ -134,11 +225,17 @@ IN_PROC_BROWSER_TEST_F(WorkerTest, WebSocketSharedWorker) {
}
IN_PROC_BROWSER_TEST_F(WorkerTest, PassMessagePortToSharedWorker) {
+ if (!SupportsSharedWorker())
+ return;
+
RunTest("pass_messageport_to_sharedworker.html", "");
}
IN_PROC_BROWSER_TEST_F(WorkerTest,
PassMessagePortToSharedWorkerDontWaitForConnect) {
+ if (!SupportsSharedWorker())
+ return;
+
RunTest("pass_messageport_to_sharedworker_dont_wait_for_connect.html", "");
}
diff --git a/chromium/content/browser/shared_worker/worker_storage_partition.h b/chromium/content/browser/shared_worker/worker_storage_partition.h
index 2f595b0e72f..aa35e192be3 100644
--- a/chromium/content/browser/shared_worker/worker_storage_partition.h
+++ b/chromium/content/browser/shared_worker/worker_storage_partition.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_SHARED_WORKERT_WORKER_STORAGE_PARTITION_H_
-#define CONTENT_BROWSER_SHARED_WORKERT_WORKER_STORAGE_PARTITION_H_
+#ifndef CONTENT_BROWSER_SHARED_WORKER_WORKER_STORAGE_PARTITION_H_
+#define CONTENT_BROWSER_SHARED_WORKER_WORKER_STORAGE_PARTITION_H_
#include "base/memory/ref_counted.h"
#include "content/common/content_export.h"
@@ -129,4 +129,4 @@ class CONTENT_EXPORT WorkerStoragePartitionId {
} // namespace content
-#endif // CONTENT_BROWSER_SHARED_WORKERT_WORKER_STORAGE_PARTITION_H_
+#endif // CONTENT_BROWSER_SHARED_WORKER_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 b2f728a57dd..8eba0350022 100644
--- a/chromium/content/browser/signed_certificate_timestamp_store_impl.h
+++ b/chromium/content/browser/signed_certificate_timestamp_store_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_SIGNED_CERTIFICATE_STORE_IMPL_H_
-#define CONTENT_BROWSER_SIGNED_CERTIFICATE_STORE_IMPL_H_
+#ifndef CONTENT_BROWSER_SIGNED_CERTIFICATE_TIMESTAMP_STORE_IMPL_H_
+#define CONTENT_BROWSER_SIGNED_CERTIFICATE_TIMESTAMP_STORE_IMPL_H_
#include "content/browser/renderer_data_memoizing_store.h"
#include "content/public/browser/signed_certificate_timestamp_store.h"
@@ -39,4 +39,4 @@ class SignedCertificateTimestampStoreImpl
} // namespace content
-#endif // CONTENT_BROWSER_SIGNED_CERTIFICATE_STORE_IMPL_H_
+#endif // CONTENT_BROWSER_SIGNED_CERTIFICATE_TIMESTAMP_STORE_IMPL_H_
diff --git a/chromium/content/browser/site_instance_impl.cc b/chromium/content/browser/site_instance_impl.cc
index f1555dc1af8..5930d830430 100644
--- a/chromium/content/browser/site_instance_impl.cc
+++ b/chromium/content/browser/site_instance_impl.cc
@@ -236,8 +236,7 @@ SiteInstance* SiteInstance::Create(BrowserContext* browser_context) {
/*static*/
SiteInstance* SiteInstance::CreateForURL(BrowserContext* browser_context,
const GURL& url) {
- // This BrowsingInstance may be deleted if it returns an existing
- // SiteInstance.
+ // This will create a new SiteInstance and BrowsingInstance.
scoped_refptr<BrowsingInstance> instance(
new BrowsingInstance(browser_context));
return instance->GetSiteInstanceForURL(url);
@@ -292,17 +291,11 @@ GURL SiteInstance::GetSiteForURL(BrowserContext* browser_context,
GURL url = SiteInstanceImpl::GetEffectiveURL(browser_context, real_url);
- // URLs with no host should have an empty site.
- GURL site;
-
- // TODO(creis): For many protocols, we should just treat the scheme as the
- // site, since there is no host. e.g., file:, about:, chrome:
-
// If the url has a host, then determine the site.
if (url.has_host()) {
// Only keep the scheme and registered domain as given by GetOrigin. This
// may also include a port, which we need to drop.
- site = url.GetOrigin();
+ GURL site = url.GetOrigin();
// Remove port, if any.
if (site.has_port()) {
@@ -321,8 +314,17 @@ GURL SiteInstance::GetSiteForURL(BrowserContext* browser_context,
rep.SetHostStr(domain);
site = site.ReplaceComponents(rep);
}
+ return site;
}
- return site;
+
+ // If there is no host but there is a scheme, return the scheme.
+ // This is useful for cases like file URLs.
+ if (url.has_scheme())
+ return GURL(url.scheme() + ":");
+
+ // Otherwise the URL should be invalid; return an empty site.
+ DCHECK(!url.is_valid());
+ return GURL();
}
/*static*/
diff --git a/chromium/content/browser/site_instance_impl_unittest.cc b/chromium/content/browser/site_instance_impl_unittest.cc
index 993ef35179a..ff32c384158 100644
--- a/chromium/content/browser/site_instance_impl_unittest.cc
+++ b/chromium/content/browser/site_instance_impl_unittest.cc
@@ -14,6 +14,7 @@
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/site_instance_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/browser/webui/content_web_ui_controller_factory.h"
#include "content/browser/webui/web_ui_controller_factory_registry.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_constants.h"
@@ -34,35 +35,17 @@ namespace {
const char kPrivilegedScheme[] = "privileged";
-class SiteInstanceTestWebUIControllerFactory : public WebUIControllerFactory {
- public:
- WebUIController* CreateWebUIControllerForURL(WebUI* web_ui,
- const GURL& url) const override {
- return NULL;
- }
- WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
- const GURL& url) const override {
- return WebUI::kNoWebUI;
- }
- bool UseWebUIForURL(BrowserContext* browser_context,
- const GURL& url) const override {
- return HasWebUIScheme(url);
- }
- bool UseWebUIBindingsForURL(BrowserContext* browser_context,
- const GURL& url) const override {
- return HasWebUIScheme(url);
- }
-};
-
class SiteInstanceTestBrowserClient : public TestContentBrowserClient {
public:
SiteInstanceTestBrowserClient()
: privileged_process_id_(-1) {
- WebUIControllerFactory::RegisterFactory(&factory_);
+ WebUIControllerFactory::RegisterFactory(
+ ContentWebUIControllerFactory::GetInstance());
}
~SiteInstanceTestBrowserClient() override {
- WebUIControllerFactory::UnregisterFactoryForTesting(&factory_);
+ WebUIControllerFactory::UnregisterFactoryForTesting(
+ ContentWebUIControllerFactory::GetInstance());
}
bool IsSuitableHost(RenderProcessHost* process_host,
@@ -76,7 +59,6 @@ class SiteInstanceTestBrowserClient : public TestContentBrowserClient {
}
private:
- SiteInstanceTestWebUIControllerFactory factory_;
int privileged_process_id_;
};
@@ -265,7 +247,7 @@ TEST_F(SiteInstanceTest, CloneNavigationEntry) {
instance1, 0, url, Referrer(), base::string16(), ui::PAGE_TRANSITION_LINK,
false);
// Clone the entry
- NavigationEntryImpl* e2 = new NavigationEntryImpl(*e1);
+ NavigationEntryImpl* e2 = e1->Clone();
// Should be able to change the SiteInstance of the cloned entry.
e2->set_site_instance(instance2);
@@ -326,35 +308,56 @@ TEST_F(SiteInstanceTest, SetSite) {
TEST_F(SiteInstanceTest, GetSiteForURL) {
// Pages are irrelevant.
GURL test_url = GURL("http://www.google.com/index.html");
- EXPECT_EQ(GURL("http://google.com"),
- SiteInstanceImpl::GetSiteForURL(NULL, test_url));
+ GURL site_url = SiteInstanceImpl::GetSiteForURL(NULL, test_url);
+ EXPECT_EQ(GURL("http://google.com"), site_url);
+ EXPECT_EQ("http", site_url.scheme());
+ EXPECT_EQ("google.com", site_url.host());
// Ports are irrlevant.
test_url = GURL("https://www.google.com:8080");
- EXPECT_EQ(GURL("https://google.com"),
- SiteInstanceImpl::GetSiteForURL(NULL, test_url));
-
- // Javascript URLs have no site.
- test_url = GURL("javascript:foo();");
- EXPECT_EQ(GURL(), SiteInstanceImpl::GetSiteForURL(NULL, test_url));
+ site_url = SiteInstanceImpl::GetSiteForURL(NULL, test_url);
+ EXPECT_EQ(GURL("https://google.com"), site_url);
+ // Hostnames without TLDs are ok.
test_url = GURL("http://foo/a.html");
- EXPECT_EQ(GURL("http://foo"), SiteInstanceImpl::GetSiteForURL(
- NULL, test_url));
+ site_url = SiteInstanceImpl::GetSiteForURL(NULL, test_url);
+ EXPECT_EQ(GURL("http://foo"), site_url);
+ EXPECT_EQ("foo", site_url.host());
+ // File URLs should include the scheme.
test_url = GURL("file:///C:/Downloads/");
- EXPECT_EQ(GURL(), SiteInstanceImpl::GetSiteForURL(NULL, test_url));
+ site_url = SiteInstanceImpl::GetSiteForURL(NULL, test_url);
+ EXPECT_EQ(GURL("file:"), site_url);
+ EXPECT_EQ("file", site_url.scheme());
+ EXPECT_FALSE(site_url.has_host());
+
+ // Some file URLs have hosts in the path.
+ test_url = GURL("file://server/path");
+ site_url = SiteInstanceImpl::GetSiteForURL(NULL, test_url);
+ EXPECT_EQ(GURL("file://server"), site_url);
+ EXPECT_EQ("server", site_url.host());
+
+ // Data URLs should include the scheme.
+ test_url = GURL("data:text/html,foo");
+ site_url = SiteInstanceImpl::GetSiteForURL(NULL, test_url);
+ EXPECT_EQ(GURL("data:"), site_url);
+ EXPECT_EQ("data", site_url.scheme());
+ EXPECT_FALSE(site_url.has_host());
+
+ // Javascript URLs should include the scheme.
+ test_url = GURL("javascript:foo();");
+ site_url = SiteInstanceImpl::GetSiteForURL(NULL, test_url);
+ EXPECT_EQ(GURL("javascript:"), site_url);
+ EXPECT_EQ("javascript", site_url.scheme());
+ EXPECT_FALSE(site_url.has_host());
+ // Guest URLs are special and need to have the path in the site as well,
+ // since it affects the StoragePartition configuration.
std::string guest_url(kGuestScheme);
- guest_url.append("://abc123");
+ guest_url.append("://abc123/path");
test_url = GURL(guest_url);
- EXPECT_EQ(test_url, SiteInstanceImpl::GetSiteForURL(NULL, test_url));
-
- // TODO(creis): Do we want to special case file URLs to ensure they have
- // either no site or a special "file://" site? We currently return
- // "file://home/" as the site, which seems broken.
- // test_url = GURL("file://home/");
- // EXPECT_EQ(GURL(), SiteInstanceImpl::GetSiteForURL(NULL, test_url));
+ site_url = SiteInstanceImpl::GetSiteForURL(NULL, test_url);
+ EXPECT_EQ(test_url, site_url);
DrainMessageLoops();
}
@@ -604,12 +607,12 @@ TEST_F(SiteInstanceTest, ProcessSharingByType) {
// Create some WebUI instances and make sure they share a process.
scoped_refptr<SiteInstanceImpl> webui1_instance(CreateSiteInstance(
- browser_context.get(), GURL(kChromeUIScheme + std::string("://newtab"))));
+ browser_context.get(), GURL(kChromeUIScheme + std::string("://gpu"))));
policy->GrantWebUIBindings(webui1_instance->GetProcess()->GetID());
- scoped_refptr<SiteInstanceImpl> webui2_instance(
- CreateSiteInstance(browser_context.get(),
- GURL(kChromeUIScheme + std::string("://history"))));
+ scoped_refptr<SiteInstanceImpl> webui2_instance(CreateSiteInstance(
+ browser_context.get(),
+ GURL(kChromeUIScheme + std::string("://media-internals"))));
scoped_ptr<RenderProcessHost> dom_host(webui1_instance->GetProcess());
EXPECT_EQ(webui1_instance->GetProcess(), webui2_instance->GetProcess());
@@ -656,10 +659,10 @@ TEST_F(SiteInstanceTest, HasWrongProcessForURL) {
EXPECT_FALSE(instance->HasWrongProcessForURL(
GURL("javascript:alert(document.location.href);")));
- EXPECT_TRUE(instance->HasWrongProcessForURL(GURL("chrome://settings")));
+ EXPECT_TRUE(instance->HasWrongProcessForURL(GURL("chrome://gpu")));
// Test that WebUI SiteInstances reject normal web URLs.
- const GURL webui_url("chrome://settings");
+ const GURL webui_url("chrome://gpu");
scoped_refptr<SiteInstanceImpl> webui_instance(static_cast<SiteInstanceImpl*>(
SiteInstance::Create(browser_context.get())));
webui_instance->SetSite(webui_url);
@@ -672,6 +675,7 @@ TEST_F(SiteInstanceTest, HasWrongProcessForURL) {
EXPECT_TRUE(webui_instance->HasProcess());
EXPECT_FALSE(webui_instance->HasWrongProcessForURL(webui_url));
EXPECT_TRUE(webui_instance->HasWrongProcessForURL(GURL("http://google.com")));
+ EXPECT_TRUE(webui_instance->HasWrongProcessForURL(GURL("http://gpu")));
// WebUI uses process-per-site, so another instance will use the same process
// even if we haven't called GetProcess yet. Make sure HasWrongProcessForURL
@@ -715,7 +719,7 @@ TEST_F(SiteInstanceTest, HasWrongProcessForURLInSitePerProcess) {
EXPECT_FALSE(instance->HasWrongProcessForURL(
GURL("javascript:alert(document.location.href);")));
- EXPECT_TRUE(instance->HasWrongProcessForURL(GURL("chrome://settings")));
+ EXPECT_TRUE(instance->HasWrongProcessForURL(GURL("chrome://gpu")));
DrainMessageLoops();
}
@@ -734,7 +738,7 @@ TEST_F(SiteInstanceTest, ProcessPerSiteWithWrongBindings) {
// Simulate navigating to a WebUI URL in a process that does not have WebUI
// bindings. This already requires bypassing security checks.
- const GURL webui_url("chrome://settings");
+ const GURL webui_url("chrome://gpu");
instance->SetSite(webui_url);
EXPECT_TRUE(instance->HasSite());
diff --git a/chromium/content/browser/site_per_process_browsertest.cc b/chromium/content/browser/site_per_process_browsertest.cc
index 145a24989e3..c09d4297e59 100644
--- a/chromium/content/browser/site_per_process_browsertest.cc
+++ b/chromium/content/browser/site_per_process_browsertest.cc
@@ -4,8 +4,12 @@
#include "content/browser/site_per_process_browsertest.h"
+#include <algorithm>
+#include <vector>
+
#include "base/command_line.h"
#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.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"
@@ -13,65 +17,49 @@
#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/web_contents/web_contents_impl.h"
+#include "content/common/frame_messages.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_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/test/content_browser_test_utils_internal.h"
#include "content/test/test_frame_navigation_observer.h"
+#include "ipc/ipc_security_test_util.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
namespace content {
-class SitePerProcessWebContentsObserver: public WebContentsObserver {
- public:
- explicit SitePerProcessWebContentsObserver(WebContents* web_contents)
- : WebContentsObserver(web_contents),
- navigation_succeeded_(false) {}
- ~SitePerProcessWebContentsObserver() override {}
-
- void DidStartProvisionalLoadForFrame(RenderFrameHost* render_frame_host,
- const GURL& validated_url,
- bool is_error_page,
- bool is_iframe_srcdoc) override {
- navigation_succeeded_ = false;
- }
-
- void DidFailProvisionalLoad(
- RenderFrameHost* render_frame_host,
- const GURL& validated_url,
- int error_code,
- const base::string16& error_description) override {
- navigation_url_ = validated_url;
- navigation_succeeded_ = false;
- }
-
- void DidCommitProvisionalLoadForFrame(
- RenderFrameHost* render_frame_host,
- const GURL& url,
- ui::PageTransition transition_type) override {
- navigation_url_ = url;
- navigation_succeeded_ = true;
+namespace {
+
+// Helper function to send a postMessage and wait for a reply message. The
+// |post_message_script| is executed on the |sender_ftn| frame, and the sender
+// frame is expected to post |reply_status| from the DOMAutomationController
+// when it receives a reply.
+void PostMessageAndWaitForReply(FrameTreeNode* sender_ftn,
+ const std::string& post_message_script,
+ const std::string& reply_status) {
+ bool success = false;
+ EXPECT_TRUE(ExecuteScriptAndExtractBool(
+ sender_ftn->current_frame_host(),
+ "window.domAutomationController.send(" + post_message_script + ");",
+ &success));
+ EXPECT_TRUE(success);
+
+ content::DOMMessageQueue msg_queue;
+ std::string status;
+ while (msg_queue.WaitForMessage(&status)) {
+ if (status == reply_status)
+ break;
}
+}
- const GURL& navigation_url() const {
- return navigation_url_;
- }
-
- int navigation_succeeded() const { return navigation_succeeded_; }
-
- private:
- GURL navigation_url_;
- bool navigation_succeeded_;
-
- DISALLOW_COPY_AND_ASSIGN(SitePerProcessWebContentsObserver);
-};
+} // anonymous namespace
class RedirectNotificationObserver : public NotificationObserver {
public:
@@ -151,6 +139,107 @@ void RedirectNotificationObserver::Observe(
running_ = false;
}
+// This observer keeps track of the number of created RenderFrameHosts. Tests
+// can use this to ensure that a certain number of child frames has been
+// created after navigating.
+class RenderFrameHostCreatedObserver : public WebContentsObserver {
+ public:
+ RenderFrameHostCreatedObserver(WebContents* web_contents,
+ int expected_frame_count)
+ : WebContentsObserver(web_contents),
+ expected_frame_count_(expected_frame_count),
+ frames_created_(0),
+ message_loop_runner_(new MessageLoopRunner) {}
+
+ ~RenderFrameHostCreatedObserver() override;
+
+ // Runs a nested message loop and blocks until the expected number of
+ // RenderFrameHosts is created.
+ void Wait();
+
+ private:
+ // WebContentsObserver
+ void RenderFrameCreated(RenderFrameHost* render_frame_host) override;
+
+ // The number of RenderFrameHosts to wait for.
+ int expected_frame_count_;
+
+ // The number of RenderFrameHosts that have been created.
+ int frames_created_;
+
+ // The MessageLoopRunner used to spin the message loop.
+ scoped_refptr<MessageLoopRunner> message_loop_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(RenderFrameHostCreatedObserver);
+};
+
+RenderFrameHostCreatedObserver::~RenderFrameHostCreatedObserver() {
+}
+
+void RenderFrameHostCreatedObserver::Wait() {
+ message_loop_runner_->Run();
+}
+
+void RenderFrameHostCreatedObserver::RenderFrameCreated(
+ RenderFrameHost* render_frame_host) {
+ frames_created_++;
+ if (frames_created_ == expected_frame_count_) {
+ message_loop_runner_->Quit();
+ }
+}
+
+// A WebContentsDelegate that catches messages sent to the console.
+class ConsoleObserverDelegate : public WebContentsDelegate {
+ public:
+ ConsoleObserverDelegate(WebContents* web_contents, const std::string& filter)
+ : web_contents_(web_contents),
+ filter_(filter),
+ message_(""),
+ message_loop_runner_(new MessageLoopRunner) {}
+
+ ~ConsoleObserverDelegate() override {}
+
+ bool AddMessageToConsole(WebContents* source,
+ int32 level,
+ const base::string16& message,
+ int32 line_no,
+ const base::string16& source_id) override;
+
+ std::string message() { return message_; }
+
+ void Wait();
+
+ private:
+ WebContents* web_contents_;
+ std::string filter_;
+ std::string message_;
+
+ // The MessageLoopRunner used to spin the message loop.
+ scoped_refptr<MessageLoopRunner> message_loop_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(ConsoleObserverDelegate);
+};
+
+void ConsoleObserverDelegate::Wait() {
+ message_loop_runner_->Run();
+}
+
+bool ConsoleObserverDelegate::AddMessageToConsole(
+ WebContents* source,
+ int32 level,
+ const base::string16& message,
+ int32 line_no,
+ const base::string16& source_id) {
+ DCHECK(source == web_contents_);
+
+ std::string ascii_message = base::UTF16ToASCII(message);
+ if (MatchPattern(ascii_message, filter_)) {
+ message_ = ascii_message;
+ message_loop_runner_->Quit();
+ }
+ return false;
+}
+
//
// SitePerProcessBrowserTest
//
@@ -158,6 +247,10 @@ void RedirectNotificationObserver::Observe(
SitePerProcessBrowserTest::SitePerProcessBrowserTest() {
};
+std::string SitePerProcessBrowserTest::DepictFrameTree(FrameTreeNode* node) {
+ return visualizer_.DepictFrameTree(node);
+}
+
void SitePerProcessBrowserTest::StartFrameAtDataURL() {
std::string data_url_script =
"var iframes = document.getElementById('test');iframes.src="
@@ -165,29 +258,8 @@ void SitePerProcessBrowserTest::StartFrameAtDataURL() {
ASSERT_TRUE(ExecuteScript(shell()->web_contents(), data_url_script));
}
-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;
-}
-
-void SitePerProcessBrowserTest::SetUpCommandLine(CommandLine* command_line) {
+void SitePerProcessBrowserTest::SetUpCommandLine(
+ base::CommandLine* command_line) {
command_line->AppendSwitch(switches::kSitePerProcess);
};
@@ -208,14 +280,14 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteIframe) {
static_cast<WebContentsImpl*>(shell()->web_contents())->
GetFrameTree()->root();
- SitePerProcessWebContentsObserver observer(shell()->web_contents());
+ TestNavigationObserver 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());
+ EXPECT_EQ(http_url, observer.last_navigation_url());
+ EXPECT_TRUE(observer.last_navigation_succeeded());
{
// There should be only one RenderWidgetHost when there are no
// cross-process iframes.
@@ -224,17 +296,23 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteIframe) {
->GetRenderWidgetHostViewsInTree();
EXPECT_EQ(1U, views_set.size());
}
- RenderFrameProxyHost* proxy_to_parent =
- child->render_manager()->GetRenderFrameProxyHost(
- shell()->web_contents()->GetSiteInstance());
- EXPECT_FALSE(proxy_to_parent);
+
+ EXPECT_EQ(
+ " Site A\n"
+ " |--Site A\n"
+ " +--Site A\n"
+ " |--Site A\n"
+ " +--Site A\n"
+ " +--Site A\n"
+ "Where A = http://127.0.0.1/",
+ DepictFrameTree(root));
// Load cross-site page into iframe.
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());
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ EXPECT_EQ(url, observer.last_navigation_url());
// Ensure that we have created a new process for the subframe.
ASSERT_EQ(2U, root->child_count());
@@ -252,18 +330,33 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteIframe) {
->GetRenderWidgetHostViewsInTree();
EXPECT_EQ(2U, views_set.size());
}
- proxy_to_parent = child->render_manager()->GetProxyToParent();
+ RenderFrameProxyHost* proxy_to_parent =
+ child->render_manager()->GetProxyToParent();
EXPECT_TRUE(proxy_to_parent);
EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector());
- EXPECT_EQ(
+ // The out-of-process iframe should have its own RenderWidgetHost,
+ // independent of any RenderViewHost.
+ EXPECT_NE(
rvh->GetView(),
proxy_to_parent->cross_process_frame_connector()->get_view_for_testing());
+ EXPECT_TRUE(child->current_frame_host()->GetRenderWidgetHost());
+
+ EXPECT_EQ(
+ " Site A ------------ proxies for B\n"
+ " |--Site B ------- proxies for A\n"
+ " +--Site A ------- proxies for B\n"
+ " |--Site A -- proxies for B\n"
+ " +--Site A -- proxies for B\n"
+ " +--Site A -- proxies for B\n"
+ "Where A = http://127.0.0.1/\n"
+ " B = http://foo.com/",
+ DepictFrameTree(root));
// Load another cross-site page into the same iframe.
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());
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ EXPECT_EQ(url, observer.last_navigation_url());
// Check again that a new process is created and is different from the
// top level one and the previous one.
@@ -287,12 +380,65 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteIframe) {
}
EXPECT_EQ(proxy_to_parent, child->render_manager()->GetProxyToParent());
EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector());
- EXPECT_EQ(
+ EXPECT_NE(
child->current_frame_host()->render_view_host()->GetView(),
proxy_to_parent->cross_process_frame_connector()->get_view_for_testing());
+ EXPECT_TRUE(child->current_frame_host()->GetRenderWidgetHost());
+
+ EXPECT_EQ(
+ " Site A ------------ proxies for C\n"
+ " |--Site C ------- proxies for A\n"
+ " +--Site A ------- proxies for C\n"
+ " |--Site A -- proxies for C\n"
+ " +--Site A -- proxies for C\n"
+ " +--Site A -- proxies for C\n"
+ "Where A = http://127.0.0.1/\n"
+ " C = http://bar.com/",
+ DepictFrameTree(root));
+}
+
+// Tests OOPIF rendering by checking that the RWH of the iframe generates
+// OnSwapCompositorFrame message.
+#if defined(OS_ANDROID)
+// http://crbug.com/471850
+#define MAYBE_CompositorFrameSwapped DISABLED_CompositorFrameSwapped
+#else
+#define MAYBE_CompositorFrameSwapped CompositorFrameSwapped
+#endif
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+ MAYBE_CompositorFrameSwapped) {
+ GURL main_url(
+ embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html"));
+ NavigateToURL(shell(), main_url);
+
+ // It is safe to obtain the root frame tree node here, as it doesn't change.
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+ ASSERT_EQ(1U, root->child_count());
+
+ FrameTreeNode* child_node = root->child_at(0);
+ GURL site_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
+ EXPECT_EQ(site_url, child_node->current_url());
+ EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
+ child_node->current_frame_host()->GetSiteInstance());
+ RenderWidgetHostViewBase* rwhv_base = static_cast<RenderWidgetHostViewBase*>(
+ child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
+
+ // Wait for OnSwapCompositorFrame message.
+ while (rwhv_base->RendererFrameNumber() <= 0) {
+ // TODO(lazyboy): Find a better way to avoid sleeping like this. See
+ // http://crbug.com/405282 for details.
+ base::RunLoop run_loop;
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE, run_loop.QuitClosure(),
+ base::TimeDelta::FromMilliseconds(10));
+ run_loop.Run();
+ }
}
-IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, NavigateRemoteFrame) {
+// Ensure that OOPIFs are deleted after navigating to a new main frame.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CleanupCrossSiteIframe) {
GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
NavigateToURL(shell(), main_url);
@@ -301,20 +447,126 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, NavigateRemoteFrame) {
static_cast<WebContentsImpl*>(shell()->web_contents())->
GetFrameTree()->root();
- SitePerProcessWebContentsObserver observer(shell()->web_contents());
+ TestNavigationObserver observer(shell()->web_contents());
+
+ // Load a cross-site page into both iframes.
+ GURL foo_url = embedded_test_server()->GetURL("foo.com", "/title2.html");
+ NavigateFrameToURL(root->child_at(0), foo_url);
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ EXPECT_EQ(foo_url, observer.last_navigation_url());
+ NavigateFrameToURL(root->child_at(1), foo_url);
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ EXPECT_EQ(foo_url, observer.last_navigation_url());
+
+ // Ensure that we have created a new process for the subframes.
+ ASSERT_EQ(2U, root->child_count());
+ EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
+ root->child_at(0)->current_frame_host()->GetSiteInstance());
+ EXPECT_EQ(root->child_at(0)->current_frame_host()->GetSiteInstance(),
+ root->child_at(1)->current_frame_host()->GetSiteInstance());
+
+ // Use Javascript in the parent to remove one of the frames and ensure that
+ // the subframe goes away.
+ EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
+ "document.body.removeChild("
+ "document.querySelectorAll('iframe')[0])"));
+ ASSERT_EQ(1U, root->child_count());
+
+ // Load a new same-site page in the top-level frame and ensure the other
+ // subframe goes away.
+ GURL new_url(embedded_test_server()->GetURL("/title1.html"));
+ NavigateToURL(shell(), new_url);
+ ASSERT_EQ(0U, root->child_count());
+}
+
+// Ensure that root frames cannot be detached.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, RestrictFrameDetach) {
+ 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();
+
+ TestNavigationObserver observer(shell()->web_contents());
+
+ // Load cross-site pages into both iframes.
+ GURL foo_url = embedded_test_server()->GetURL("foo.com", "/title2.html");
+ NavigateFrameToURL(root->child_at(0), foo_url);
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ EXPECT_EQ(foo_url, observer.last_navigation_url());
+ GURL bar_url = embedded_test_server()->GetURL("bar.com", "/title2.html");
+ NavigateFrameToURL(root->child_at(1), bar_url);
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ EXPECT_EQ(bar_url, observer.last_navigation_url());
+
+ // Ensure that we have created new processes for the subframes.
+ ASSERT_EQ(2U, root->child_count());
+ FrameTreeNode* foo_child = root->child_at(0);
+ SiteInstance* foo_site_instance =
+ foo_child->current_frame_host()->GetSiteInstance();
+ EXPECT_NE(shell()->web_contents()->GetSiteInstance(), foo_site_instance);
+ FrameTreeNode* bar_child = root->child_at(1);
+ SiteInstance* bar_site_instance =
+ bar_child->current_frame_host()->GetSiteInstance();
+ EXPECT_NE(shell()->web_contents()->GetSiteInstance(), bar_site_instance);
+
+ EXPECT_EQ(
+ " Site A ------------ proxies for B C\n"
+ " |--Site B ------- proxies for A C\n"
+ " +--Site C ------- proxies for A B\n"
+ "Where A = http://127.0.0.1/\n"
+ " B = http://foo.com/\n"
+ " C = http://bar.com/",
+ DepictFrameTree(root));
+
+ // Simulate an attempt to detach the root frame from foo_site_instance. This
+ // should kill foo_site_instance's process.
+ RenderFrameProxyHost* foo_mainframe_rfph =
+ root->render_manager()->GetRenderFrameProxyHost(foo_site_instance);
+ content::RenderProcessHostWatcher foo_terminated(
+ foo_mainframe_rfph->GetProcess(),
+ content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+ FrameHostMsg_Detach evil_msg2(foo_mainframe_rfph->GetRoutingID());
+ IPC::IpcSecurityTestUtil::PwnMessageReceived(
+ foo_mainframe_rfph->GetProcess()->GetChannel(), evil_msg2);
+ foo_terminated.Wait();
+
+ EXPECT_EQ(
+ " Site A ------------ proxies for B C\n"
+ " |--Site B ------- proxies for A C\n"
+ " +--Site C ------- proxies for A B\n"
+ "Where A = http://127.0.0.1/\n"
+ " B = http://foo.com/ (no process)\n"
+ " C = http://bar.com/",
+ DepictFrameTree(root));
+}
+
+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();
+
+ TestNavigationObserver 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());
+ EXPECT_EQ(http_url, observer.last_navigation_url());
+ EXPECT_TRUE(observer.last_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());
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ EXPECT_EQ(url, observer.last_navigation_url());
// Ensure that we have created a new process for the subframe.
ASSERT_EQ(2U, root->child_count());
@@ -324,9 +576,9 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, NavigateRemoteFrame) {
// 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());
+ NavigateIframeToURL(shell()->web_contents(), "test", url);
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ EXPECT_EQ(url, observer.last_navigation_url());
// Check again that a new process is created and is different from the
// top level one and the previous one.
@@ -340,16 +592,469 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, NavigateRemoteFrame) {
// 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(http_url, observer.last_navigation_url());
+ EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
child->current_frame_host()->GetSiteInstance());
}
+#if defined(OS_WIN)
+// http://crbug.com/465722
+#define MAYBE_NavigateRemoteFrameToBlankAndDataURLs \
+ DISABLED_NavigateRemoteFrameToBlankAndDataURLs
+#else
+#define MAYBE_NavigateRemoteFrameToBlankAndDataURLs \
+ NavigateRemoteFrameToBlankAndDataURLs
+#endif
+
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+ MAYBE_NavigateRemoteFrameToBlankAndDataURLs) {
+ 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();
+
+ TestNavigationObserver 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.last_navigation_url());
+ EXPECT_TRUE(observer.last_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.last_navigation_succeeded());
+ EXPECT_EQ(url, observer.last_navigation_url());
+ ASSERT_EQ(2U, root->child_count());
+ EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
+ root->child_at(0)->current_frame_host()->GetSiteInstance());
+
+ // Navigate iframe to a data URL. The navigation happens from a script in the
+ // parent frame, so the data URL should be committed in the same SiteInstance
+ // as the parent frame.
+ GURL data_url("data:text/html,dataurl");
+ NavigateIframeToURL(shell()->web_contents(), "test", data_url);
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ EXPECT_EQ(data_url, observer.last_navigation_url());
+
+ // Ensure that we have navigated using the top level process.
+ EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
+ root->child_at(0)->current_frame_host()->GetSiteInstance());
+
+ // Load cross-site page into iframe.
+ url = embedded_test_server()->GetURL("bar.com", "/title2.html");
+ NavigateFrameToURL(root->child_at(0), url);
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ EXPECT_EQ(url, observer.last_navigation_url());
+ ASSERT_EQ(2U, root->child_count());
+ EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
+ root->child_at(0)->current_frame_host()->GetSiteInstance());
+
+ // Navigate iframe to about:blank. The navigation happens from a script in the
+ // parent frame, so it should be committed in the same SiteInstance as the
+ // parent frame.
+ GURL about_blank_url("about:blank");
+ NavigateIframeToURL(shell()->web_contents(), "test", about_blank_url);
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ EXPECT_EQ(about_blank_url, observer.last_navigation_url());
+
+ // Ensure that we have navigated using the top level process.
+ EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
+ root->child_at(0)->current_frame_host()->GetSiteInstance());
+}
+
+// This test checks that killing a renderer process of a remote frame
+// and then navigating some other frame to the same SiteInstance of the killed
+// process works properly.
+// This can be illustrated as follows,
+// where 1/2/3 are FrameTreeNode-s and A/B are processes and B* is the killed
+// B process:
+//
+// 1 A A A
+// / \ -> / \ -> Kill B -> / \ -> Navigate 3 to B -> / \ .
+// 2 3 B A B* A B* B
+//
+// Initially, node1.proxy_hosts_ = {B}
+// After we kill B, we make sure B stays in node1.proxy_hosts_, then we navigate
+// 3 to B and we expect that to complete normally.
+// See http://crbug.com/432107.
+//
+// Note that due to http://crbug.com/450681, node2 cannot be re-navigated to
+// site B and stays in not rendered state.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+ NavigateRemoteFrameToKilledProcess) {
+ GURL main_url(embedded_test_server()->GetURL(
+ "/frame_tree/page_with_two_frames.html"));
+ NavigateToURL(shell(), main_url);
+
+ // It is safe to obtain the root frame tree node here, as it doesn't change.
+ FrameTreeNode* root =
+ static_cast<WebContentsImpl*>(shell()->web_contents())->
+ GetFrameTree()->root();
+
+ TestNavigationObserver observer(shell()->web_contents());
+ ASSERT_EQ(2U, root->child_count());
+
+ // Make sure node2 points to the correct cross-site page.
+ GURL site_b_url = embedded_test_server()->GetURL("bar.com", "/title1.html");
+ FrameTreeNode* node2 = root->child_at(0);
+ EXPECT_EQ(site_b_url, node2->current_url());
+
+ // Kill that cross-site renderer.
+ RenderProcessHost* child_process =
+ node2->current_frame_host()->GetProcess();
+ RenderProcessHostWatcher crash_observer(
+ child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+ child_process->Shutdown(0, false);
+ crash_observer.Wait();
+
+ // Now navigate the second iframe (node3) to the same site as the node2.
+ FrameTreeNode* node3 = root->child_at(1);
+ NavigateFrameToURL(node3, site_b_url);
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ EXPECT_EQ(site_b_url, observer.last_navigation_url());
+}
+
+// This test is similar to
+// SitePerProcessBrowserTest.NavigateRemoteFrameToKilledProcess with
+// addition that node2 also has a cross-origin frame to site C.
+//
+// 1 A A A
+// / \ / \ / \ / \ .
+// 2 3 -> B A -> Kill B -> B* A -> Navigate 3 -> B* B
+// / /
+// 4 C
+//
+// Initially, node1.proxy_hosts_ = {B, C}
+// After we kill B, we make sure B stays in node1.proxy_hosts_, but
+// C gets cleared from node1.proxy_hosts_.
+//
+// Note that due to http://crbug.com/450681, node2 cannot be re-navigated to
+// site B and stays in not rendered state.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+ NavigateRemoteFrameToKilledProcessWithSubtree) {
+ GURL main_url(embedded_test_server()->GetURL(
+ "a.com", "/frame_tree/page_with_two_frames_nested.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();
+ TestNavigationObserver observer(shell()->web_contents());
+
+ ASSERT_EQ(2U, root->child_count());
+
+ GURL site_b_url(
+ embedded_test_server()->GetURL(
+ "bar.com", "/frame_tree/page_with_one_frame.html"));
+ // We can't use a TestNavigationObserver to verify the URL here,
+ // since the frame has children that may have clobbered it in the observer.
+ EXPECT_EQ(site_b_url, root->child_at(0)->current_url());
+
+ // Ensure that a new process is created for node2.
+ EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
+ root->child_at(0)->current_frame_host()->GetSiteInstance());
+ // Ensure that a new process is *not* created for node3.
+ EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
+ root->child_at(1)->current_frame_host()->GetSiteInstance());
+
+ ASSERT_EQ(1U, root->child_at(0)->child_count());
+
+ // Make sure node4 points to the correct cross-site page.
+ FrameTreeNode* node4 = root->child_at(0)->child_at(0);
+ GURL site_c_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
+ EXPECT_EQ(site_c_url, node4->current_url());
+
+ // |site_instance_c| is expected to go away once we kill |child_process_b|
+ // below, so create a local scope so we can extend the lifetime of
+ // |site_instance_c| with a refptr.
+ {
+ // Initially each frame has proxies for the other sites.
+ EXPECT_EQ(
+ " Site A ------------ proxies for B C\n"
+ " |--Site B ------- proxies for A C\n"
+ " | +--Site C -- proxies for A B\n"
+ " +--Site A ------- proxies for B C\n"
+ "Where A = http://a.com/\n"
+ " B = http://bar.com/\n"
+ " C = http://baz.com/",
+ DepictFrameTree(root));
+
+ // Kill the render process for Site B.
+ RenderProcessHost* child_process_b =
+ root->child_at(0)->current_frame_host()->GetProcess();
+ RenderProcessHostWatcher crash_observer(
+ child_process_b, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+ child_process_b->Shutdown(0, false);
+ crash_observer.Wait();
+
+ // The Site C frame (a child of the crashed Site B frame) should go away,
+ // and there should be no remaining proxies for site C anywhere.
+ EXPECT_EQ(
+ " Site A ------------ proxies for B\n"
+ " |--Site B ------- proxies for A\n"
+ " +--Site A ------- proxies for B\n"
+ "Where A = http://a.com/\n"
+ " B = http://bar.com/ (no process)",
+ DepictFrameTree(root));
+ }
+
+ // Now navigate the second iframe (node3) to Site B also.
+ FrameTreeNode* node3 = root->child_at(1);
+ GURL url = embedded_test_server()->GetURL("bar.com", "/title1.html");
+ NavigateFrameToURL(node3, url);
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ EXPECT_EQ(url, observer.last_navigation_url());
+
+ EXPECT_EQ(
+ " Site A ------------ proxies for B\n"
+ " |--Site B ------- proxies for A\n"
+ " +--Site B ------- proxies for A\n"
+ "Where A = http://a.com/\n"
+ " B = http://bar.com/",
+ DepictFrameTree(root));
+}
+
+// Verify that killing a cross-site frame's process B and then navigating a
+// frame to B correctly recreates all proxies in B.
+//
+// 1 A A A
+// / | \ / | \ / | \ / | \ .
+// 2 3 4 -> B A A -> Kill B -> B* A A -> B* B A
+//
+// After the last step, the test sends a postMessage from node 3 to node 4,
+// verifying that a proxy for node 4 has been recreated in process B. This
+// verifies the fix for https://crbug.com/478892.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+ NavigatingToKilledProcessRestoresAllProxies) {
+ // Navigate to a page with three frames: one cross-site and two same-site.
+ GURL main_url(embedded_test_server()->GetURL(
+ "a.com", "/frame_tree/page_with_three_frames.html"));
+ NavigateToURL(shell(), main_url);
+
+ // It is safe to obtain the root frame tree node here, as it doesn't change.
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+ TestNavigationObserver observer(shell()->web_contents());
+
+ EXPECT_EQ(
+ " Site A ------------ proxies for B\n"
+ " |--Site B ------- proxies for A\n"
+ " |--Site A ------- proxies for B\n"
+ " +--Site A ------- proxies for B\n"
+ "Where A = http://a.com/\n"
+ " B = http://b.com/",
+ DepictFrameTree(root));
+
+ // Kill the first subframe's b.com renderer.
+ RenderProcessHost* child_process =
+ root->child_at(0)->current_frame_host()->GetProcess();
+ RenderProcessHostWatcher crash_observer(
+ child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+ child_process->Shutdown(0, false);
+ crash_observer.Wait();
+
+ // Navigate the second subframe to b.com to recreate the b.com process.
+ GURL b_url = embedded_test_server()->GetURL("b.com", "/post_message.html");
+ NavigateFrameToURL(root->child_at(1), b_url);
+ // TODO(alexmos): This can be removed once TestFrameNavigationObserver is
+ // fixed to use DidFinishLoad.
+ EXPECT_TRUE(
+ WaitForRenderFrameReady(root->child_at(1)->current_frame_host()));
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ EXPECT_EQ(b_url, observer.last_navigation_url());
+ EXPECT_TRUE(root->child_at(1)->current_frame_host()->IsRenderFrameLive());
+
+ EXPECT_EQ(
+ " Site A ------------ proxies for B\n"
+ " |--Site B ------- proxies for A\n"
+ " |--Site B ------- proxies for A\n"
+ " +--Site A ------- proxies for B\n"
+ "Where A = http://a.com/\n"
+ " B = http://b.com/",
+ DepictFrameTree(root));
+
+ // Check that third subframe's proxy is available in the b.com process by
+ // sending it a postMessage from second subframe, and waiting for a reply.
+ PostMessageAndWaitForReply(root->child_at(1),
+ "postToSibling('subframe-msg','frame3')",
+ "\"done-frame2\"");
+}
+
+// Verify that proxy creation doesn't recreate a crashed process if no frame
+// will be created in it.
+//
+// 1 A A A
+// / | \ / | \ / | \ / | \ .
+// 2 3 4 -> B A A -> Kill B -> B* A A -> B* A A
+// \ .
+// A
+//
+// The test kills process B (node 2), creates a child frame of node 4 in
+// process A, and then checks that process B isn't resurrected to create a
+// proxy for the new child frame. See https://crbug.com/476846.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+ CreateChildFrameAfterKillingProcess) {
+ // Navigate to a page with three frames: one cross-site and two same-site.
+ GURL main_url(embedded_test_server()->GetURL(
+ "a.com", "/frame_tree/page_with_three_frames.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ // It is safe to obtain the root frame tree node here, as it doesn't change.
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+
+ EXPECT_EQ(
+ " Site A ------------ proxies for B\n"
+ " |--Site B ------- proxies for A\n"
+ " |--Site A ------- proxies for B\n"
+ " +--Site A ------- proxies for B\n"
+ "Where A = http://a.com/\n"
+ " B = http://b.com/",
+ DepictFrameTree(root));
+ SiteInstance* b_site_instance =
+ root->child_at(0)->current_frame_host()->GetSiteInstance();
+
+ // Kill the first subframe's renderer (B).
+ RenderProcessHost* child_process =
+ root->child_at(0)->current_frame_host()->GetProcess();
+ RenderProcessHostWatcher crash_observer(
+ child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+ child_process->Shutdown(0, false);
+ crash_observer.Wait();
+
+ // Add a new child frame to the third subframe.
+ RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 1);
+ EXPECT_TRUE(ExecuteScript(
+ root->child_at(2)->current_frame_host(),
+ "document.body.appendChild(document.createElement('iframe'));"));
+ frame_observer.Wait();
+
+ // The new frame should have a RenderFrameProxyHost for B, but it should not
+ // be alive, and B should still not have a process (verified by last line of
+ // expected DepictFrameTree output).
+ EXPECT_EQ(
+ " Site A ------------ proxies for B\n"
+ " |--Site B ------- proxies for A\n"
+ " |--Site A ------- proxies for B\n"
+ " +--Site A ------- proxies for B\n"
+ " +--Site A -- proxies for B\n"
+ "Where A = http://a.com/\n"
+ " B = http://b.com/ (no process)",
+ DepictFrameTree(root));
+ FrameTreeNode* grandchild = root->child_at(2)->child_at(0);
+ RenderFrameProxyHost* grandchild_rfph =
+ grandchild->render_manager()->GetRenderFrameProxyHost(b_site_instance);
+ EXPECT_FALSE(grandchild_rfph->is_render_frame_proxy_live());
+
+ // Navigate the second subframe to b.com to recreate process B.
+ TestNavigationObserver observer(shell()->web_contents());
+ GURL b_url = embedded_test_server()->GetURL("b.com", "/title1.html");
+ NavigateFrameToURL(root->child_at(1), b_url);
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ EXPECT_EQ(b_url, observer.last_navigation_url());
+
+ // Ensure that the grandchild RenderFrameProxy in B was created when process
+ // B was restored.
+ EXPECT_TRUE(grandchild_rfph->is_render_frame_proxy_live());
+}
+
+// In A-embed-B-embed-C scenario, verify that killing process B clears proxies
+// of C from the tree.
+//
+// 1 A A
+// / \ / \ / \ .
+// 2 3 -> B A -> Kill B -> B* A
+// / /
+// 4 C
+//
+// node1 is the root.
+// Initially, both node1.proxy_hosts_ and node3.proxy_hosts_ contain C.
+// After we kill B, make sure proxies for C are cleared.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+ KillingRendererClearsDescendantProxies) {
+ GURL main_url(embedded_test_server()->GetURL(
+ "a.com", "/frame_tree/page_with_two_frames_nested.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();
+ TestNavigationObserver observer(shell()->web_contents());
+
+ ASSERT_EQ(2U, root->child_count());
+
+ GURL site_b_url(
+ embedded_test_server()->GetURL(
+ "bar.com", "/frame_tree/page_with_one_frame.html"));
+ // We can't use a TestNavigationObserver to verify the URL here,
+ // since the frame has children that may have clobbered it in the observer.
+ EXPECT_EQ(site_b_url, root->child_at(0)->current_url());
+
+ // Ensure that a new process is created for node2.
+ EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
+ root->child_at(0)->current_frame_host()->GetSiteInstance());
+ // Ensure that a new process is *not* created for node3.
+ EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
+ root->child_at(1)->current_frame_host()->GetSiteInstance());
+
+ ASSERT_EQ(1U, root->child_at(0)->child_count());
+
+ // Make sure node4 points to the correct cross-site-page.
+ FrameTreeNode* node4 = root->child_at(0)->child_at(0);
+ GURL site_c_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
+ EXPECT_EQ(site_c_url, node4->current_url());
+
+ // |site_instance_c| is expected to go away once we kill |child_process_b|
+ // below; refcount it to extend the lifetime.
+ scoped_refptr<SiteInstanceImpl> site_instance_c =
+ node4->current_frame_host()->GetSiteInstance();
+
+ // Initially proxies for both B and C will be present in the root.
+ EXPECT_EQ(
+ " Site A ------------ proxies for B C\n"
+ " |--Site B ------- proxies for A C\n"
+ " | +--Site C -- proxies for A B\n"
+ " +--Site A ------- proxies for B C\n"
+ "Where A = http://a.com/\n"
+ " B = http://bar.com/\n"
+ " C = http://baz.com/",
+ DepictFrameTree(root));
+ // Kill process B.
+ RenderProcessHost* child_process_b =
+ root->child_at(0)->current_frame_host()->GetProcess();
+ RenderProcessHostWatcher crash_observer(
+ child_process_b, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+ child_process_b->Shutdown(0, false);
+ crash_observer.Wait();
+
+ // Make sure proxy C has gone from root.
+ // Make sure proxy C has gone from node3 as well.
+ // Make sure proxy B stays around in root and node3.
+ EXPECT_EQ(
+ " Site A ------------ proxies for B\n"
+ " |--Site B ------- proxies for A\n"
+ " +--Site A ------- proxies for B\n"
+ "Where A = http://a.com/\n"
+ " B = http://bar.com/ (no process)",
+ DepictFrameTree(root));
+
+ EXPECT_TRUE(site_instance_c->HasOneRef());
+}
+
// 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.
IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DISABLED_CrashSubframe) {
GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
NavigateToURL(shell(), main_url);
@@ -362,15 +1067,14 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DISABLED_CrashSubframe) {
// Load cross-site page into iframe.
EXPECT_TRUE(NavigateIframeToURL(
- shell(),
- embedded_test_server()->GetURL("/cross-site/foo.com/title2.html"),
- "test"));
+ shell()->web_contents(), "test",
+ embedded_test_server()->GetURL("/cross-site/foo.com/title2.html")));
// Check the subframe process.
FrameTreeNode* root =
static_cast<WebContentsImpl*>(shell()->web_contents())->
GetFrameTree()->root();
- ASSERT_EQ(1U, root->child_count());
+ ASSERT_EQ(2U, root->child_count());
FrameTreeNode* child = root->child_at(0);
EXPECT_EQ(main_url, root->current_url());
EXPECT_EQ("foo.com", child->current_url().host());
@@ -387,12 +1091,12 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DISABLED_CrashSubframe) {
RenderProcessHostWatcher crash_observer(
child_process,
RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
- base::KillProcess(child_process->GetHandle(), 0, false);
+ child_process->Shutdown(0, false);
crash_observer.Wait();
}
// Ensure that the child frame still exists but has been cleared.
- EXPECT_EQ(1U, root->child_count());
+ EXPECT_EQ(2U, root->child_count());
EXPECT_EQ(main_url, root->current_url());
EXPECT_EQ(GURL(), child->current_url());
@@ -406,13 +1110,56 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DISABLED_CrashSubframe) {
RenderProcessHostWatcher crash_observer(
root_process,
RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
- base::KillProcess(root_process->GetHandle(), 0, false);
+ root_process->Shutdown(0, false);
crash_observer.Wait();
}
EXPECT_EQ(0U, root->child_count());
EXPECT_EQ(GURL(), root->current_url());
}
+// When a new subframe is added, related SiteInstances that can reach the
+// subframe should create proxies for it (https://crbug.com/423587). This test
+// checks that if A embeds B and later adds a new subframe A2, A2 gets a proxy
+// in B's process.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CreateProxiesForNewFrames) {
+ GURL main_url(embedded_test_server()->GetURL(
+ "b.com", "/frame_tree/page_with_one_frame.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ // It is safe to obtain the root frame tree node here, as it doesn't change.
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+ ASSERT_EQ(1U, root->child_count());
+
+ // Make sure the frame starts out at the correct cross-site URL.
+ EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title1.html"),
+ root->child_at(0)->current_url());
+
+ EXPECT_EQ(
+ " Site A ------------ proxies for B\n"
+ " +--Site B ------- proxies for A\n"
+ "Where A = http://b.com/\n"
+ " B = http://baz.com/",
+ DepictFrameTree(root));
+
+ // Add a new child frame to the top-level frame.
+ RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 1);
+ EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
+ "window.domAutomationController.send("
+ " addFrame('data:text/html,foo'));"));
+ frame_observer.Wait();
+
+ // The new frame should have a proxy in Site B, for use by the old frame.
+ EXPECT_EQ(
+ " Site A ------------ proxies for B\n"
+ " |--Site B ------- proxies for A\n"
+ " +--Site A ------- proxies for B\n"
+ "Where A = http://b.com/\n"
+ " B = http://baz.com/",
+ DepictFrameTree(root));
+}
+
// TODO(nasko): Disable this test until out-of-process iframes is ready and the
// security checks are back in place.
// TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
@@ -432,17 +1179,17 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
NavigateToURL(shell(), main_url);
- SitePerProcessWebContentsObserver observer(shell()->web_contents());
+ TestNavigationObserver observer(shell()->web_contents());
{
// Load cross-site client-redirect page into Iframe.
// Should be blocked.
GURL client_redirect_https_url(https_server.GetURL(
"client-redirect?files/title1.html"));
- EXPECT_TRUE(NavigateIframeToURL(shell(),
- client_redirect_https_url, "test"));
+ EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
+ client_redirect_https_url));
// DidFailProvisionalLoad when navigating to client_redirect_https_url.
- EXPECT_EQ(observer.navigation_url(), client_redirect_https_url);
- EXPECT_FALSE(observer.navigation_succeeded());
+ EXPECT_EQ(observer.last_navigation_url(), client_redirect_https_url);
+ EXPECT_FALSE(observer.last_navigation_succeeded());
}
{
@@ -450,10 +1197,10 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
// which redirects to same-site page.
GURL server_redirect_http_url(https_server.GetURL(
"server-redirect?" + http_url.spec()));
- EXPECT_TRUE(NavigateIframeToURL(shell(),
- server_redirect_http_url, "test"));
- EXPECT_EQ(observer.navigation_url(), http_url);
- EXPECT_TRUE(observer.navigation_succeeded());
+ EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
+ server_redirect_http_url));
+ EXPECT_EQ(observer.last_navigation_url(), http_url);
+ EXPECT_TRUE(observer.last_navigation_succeeded());
}
{
@@ -461,11 +1208,11 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
// which redirects to cross-site page.
GURL server_redirect_http_url(https_server.GetURL(
"server-redirect?files/title1.html"));
- EXPECT_TRUE(NavigateIframeToURL(shell(),
- server_redirect_http_url, "test"));
+ EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
+ server_redirect_http_url));
// DidFailProvisionalLoad when navigating to https_url.
- EXPECT_EQ(observer.navigation_url(), https_url);
- EXPECT_FALSE(observer.navigation_succeeded());
+ EXPECT_EQ(observer.last_navigation_url(), https_url);
+ EXPECT_FALSE(observer.last_navigation_succeeded());
}
{
@@ -473,11 +1220,11 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
// which redirects to cross-site page.
GURL server_redirect_http_url(test_server()->GetURL(
"server-redirect?" + https_url.spec()));
- EXPECT_TRUE(NavigateIframeToURL(shell(),
- server_redirect_http_url, "test"));
+ EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
+ server_redirect_http_url));
- EXPECT_EQ(observer.navigation_url(), https_url);
- EXPECT_FALSE(observer.navigation_succeeded());
+ EXPECT_EQ(observer.last_navigation_url(), https_url);
+ EXPECT_FALSE(observer.last_navigation_succeeded());
}
{
@@ -491,17 +1238,17 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
Source<NavigationController>(
&shell()->web_contents()->GetController()));
- EXPECT_TRUE(NavigateIframeToURL(shell(),
- client_redirect_http_url, "test"));
+ EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
+ client_redirect_http_url));
// Same-site Client-Redirect Page should be loaded successfully.
- EXPECT_EQ(observer.navigation_url(), client_redirect_http_url);
- EXPECT_TRUE(observer.navigation_succeeded());
+ EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url);
+ EXPECT_TRUE(observer.last_navigation_succeeded());
// Redirecting to Cross-site Page should be blocked.
load_observer2.Wait();
- EXPECT_EQ(observer.navigation_url(), https_url);
- EXPECT_FALSE(observer.navigation_succeeded());
+ EXPECT_EQ(observer.last_navigation_url(), https_url);
+ EXPECT_FALSE(observer.last_navigation_succeeded());
}
{
@@ -509,10 +1256,10 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
// which redirects to same-site page.
GURL server_redirect_http_url(test_server()->GetURL(
"server-redirect?files/title1.html"));
- EXPECT_TRUE(NavigateIframeToURL(shell(),
- server_redirect_http_url, "test"));
- EXPECT_EQ(observer.navigation_url(), http_url);
- EXPECT_TRUE(observer.navigation_succeeded());
+ EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
+ server_redirect_http_url));
+ EXPECT_EQ(observer.last_navigation_url(), http_url);
+ EXPECT_TRUE(observer.last_navigation_succeeded());
}
{
@@ -525,17 +1272,17 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
Source<NavigationController>(
&shell()->web_contents()->GetController()));
- EXPECT_TRUE(NavigateIframeToURL(shell(),
- client_redirect_http_url, "test"));
+ EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
+ client_redirect_http_url));
// Same-site Client-Redirect Page should be loaded successfully.
- EXPECT_EQ(observer.navigation_url(), client_redirect_http_url);
- EXPECT_TRUE(observer.navigation_succeeded());
+ EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url);
+ EXPECT_TRUE(observer.last_navigation_succeeded());
// Redirecting to Same-site Page should be loaded successfully.
load_observer2.Wait();
- EXPECT_EQ(observer.navigation_url(), http_url);
- EXPECT_TRUE(observer.navigation_succeeded());
+ EXPECT_EQ(observer.last_navigation_url(), http_url);
+ EXPECT_TRUE(observer.last_navigation_succeeded());
}
}
@@ -558,7 +1305,7 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
NavigateToURL(shell(), main_url);
- SitePerProcessWebContentsObserver observer(shell()->web_contents());
+ TestNavigationObserver observer(shell()->web_contents());
{
// Load client-redirect page pointing to a cross-site client-redirect page,
// which eventually redirects back to same-site page.
@@ -573,12 +1320,13 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
Source<NavigationController>(
&shell()->web_contents()->GetController()));
- EXPECT_TRUE(NavigateIframeToURL(shell(), client_redirect_http_url, "test"));
+ EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
+ client_redirect_http_url));
// DidFailProvisionalLoad when navigating to client_redirect_https_url.
load_observer2.Wait();
- EXPECT_EQ(observer.navigation_url(), client_redirect_https_url);
- EXPECT_FALSE(observer.navigation_succeeded());
+ EXPECT_EQ(observer.last_navigation_url(), client_redirect_https_url);
+ EXPECT_FALSE(observer.last_navigation_succeeded());
}
{
@@ -588,10 +1336,10 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
"server-redirect?" + http_url.spec()));
GURL server_redirect_http_url(test_server()->GetURL(
"server-redirect?" + server_redirect_https_url.spec()));
- EXPECT_TRUE(NavigateIframeToURL(shell(),
- server_redirect_http_url, "test"));
- EXPECT_EQ(observer.navigation_url(), http_url);
- EXPECT_TRUE(observer.navigation_succeeded());
+ EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
+ server_redirect_http_url));
+ EXPECT_EQ(observer.last_navigation_url(), http_url);
+ EXPECT_TRUE(observer.last_navigation_succeeded());
}
{
@@ -601,11 +1349,12 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
"server-redirect?" + https_url.spec()));
GURL server_redirect_http_url(test_server()->GetURL(
"server-redirect?" + server_redirect_https_url.spec()));
- EXPECT_TRUE(NavigateIframeToURL(shell(), server_redirect_http_url, "test"));
+ EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
+ server_redirect_http_url));
// DidFailProvisionalLoad when navigating to https_url.
- EXPECT_EQ(observer.navigation_url(), https_url);
- EXPECT_FALSE(observer.navigation_succeeded());
+ EXPECT_EQ(observer.last_navigation_url(), https_url);
+ EXPECT_FALSE(observer.last_navigation_succeeded());
}
{
@@ -615,25 +1364,19 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
"client-redirect?" + http_url.spec()));
GURL server_redirect_http_url(test_server()->GetURL(
"server-redirect?" + client_redirect_http_url.spec()));
- EXPECT_TRUE(NavigateIframeToURL(shell(), server_redirect_http_url, "test"));
+ EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
+ server_redirect_http_url));
// DidFailProvisionalLoad when navigating to client_redirect_http_url.
- EXPECT_EQ(observer.navigation_url(), client_redirect_http_url);
- EXPECT_FALSE(observer.navigation_succeeded());
+ EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url);
+ EXPECT_FALSE(observer.last_navigation_succeeded());
}
}
// 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) {
+ ProxyCreationSkipsSubtree) {
GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
NavigateToURL(shell(), main_url);
@@ -647,15 +1390,20 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
{
// Load same-site page into iframe.
- SitePerProcessWebContentsObserver observer(shell()->web_contents());
+ TestNavigationObserver 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);
+ EXPECT_EQ(http_url, observer.last_navigation_url());
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ EXPECT_EQ(
+ " Site A\n"
+ " |--Site A\n"
+ " +--Site A\n"
+ " |--Site A\n"
+ " +--Site A\n"
+ " +--Site A\n"
+ "Where A = http://127.0.0.1/",
+ DepictFrameTree(root));
}
// Create the cross-site URL to navigate to.
@@ -670,31 +1418,41 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
FrameTreeNode* child = root->child_at(1);
SiteInstance* site = NULL;
{
- SitePerProcessWebContentsObserver observer(shell()->web_contents());
+ TestNavigationObserver 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));
- }
+ EXPECT_EQ(
+ " Site A ------------ proxies for B\n"
+ " |--Site A ------- proxies for B\n"
+ " +--Site A (B pending)\n"
+ " |--Site A\n"
+ " +--Site A\n"
+ " +--Site A\n"
+ "Where A = http://127.0.0.1/\n"
+ " B = http://foo.com/",
+ DepictFrameTree(root));
+
// 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());
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ EXPECT_EQ(cross_site_url, observer.last_navigation_url());
+
+ EXPECT_EQ(
+ " Site A ------------ proxies for B\n"
+ " |--Site A ------- proxies for B\n"
+ " +--Site B ------- proxies for A\n"
+ "Where A = http://127.0.0.1/\n"
+ " B = http://foo.com/",
+ DepictFrameTree(root));
}
// Load another cross-site page into the same iframe.
@@ -706,33 +1464,1006 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
// 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());
+ TestNavigationObserver 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));
- }
+ EXPECT_EQ(
+ " Site A ------------ proxies for B C\n"
+ " |--Site A ------- proxies for B C\n"
+ " +--Site B (C pending) -- proxies for A\n"
+ "Where A = http://127.0.0.1/\n"
+ " B = http://foo.com/\n"
+ " C = http://bar.com/",
+ DepictFrameTree(root));
navigation_observer.Wait();
- EXPECT_TRUE(observer.navigation_succeeded());
- EXPECT_EQ(cross_site_url, observer.navigation_url());
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ EXPECT_EQ(cross_site_url, observer.last_navigation_url());
EXPECT_EQ(0U, child->child_count());
}
}
+// Verify that origin replication works for an A-embed-B-embed-C hierarchy.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OriginReplication) {
+ GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ // It is safe to obtain the root frame tree node here, as it doesn't change.
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+
+ TestNavigationObserver observer(shell()->web_contents());
+
+ // Navigate the first subframe to a cross-site page with two subframes.
+ GURL foo_url(
+ embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html"));
+ NavigateFrameToURL(root->child_at(0), foo_url);
+ EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+
+ // We can't use a TestNavigationObserver to verify the URL here,
+ // since the frame has children that may have clobbered it in the observer.
+ EXPECT_EQ(foo_url, root->child_at(0)->current_url());
+
+ // Ensure that a new process is created for the subframe.
+ EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
+ root->child_at(0)->current_frame_host()->GetSiteInstance());
+
+ // Load cross-site page into subframe's subframe.
+ ASSERT_EQ(2U, root->child_at(0)->child_count());
+ GURL bar_url(embedded_test_server()->GetURL("bar.com", "/title1.html"));
+ NavigateFrameToURL(root->child_at(0)->child_at(0), bar_url);
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ EXPECT_EQ(bar_url, observer.last_navigation_url());
+
+ // Check that a new process is created and is different from the top one and
+ // the middle one.
+ FrameTreeNode* bottom_child = root->child_at(0)->child_at(0);
+ EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
+ bottom_child->current_frame_host()->GetSiteInstance());
+ EXPECT_NE(root->child_at(0)->current_frame_host()->GetSiteInstance(),
+ bottom_child->current_frame_host()->GetSiteInstance());
+
+ // Check that foo.com frame's location.ancestorOrigins contains the correct
+ // origin for the parent. The origin should have been replicated as part of
+ // the ViewMsg_New message that created the parent's RenderFrameProxy in
+ // foo.com's process.
+ int ancestor_origins_length = 0;
+ EXPECT_TRUE(ExecuteScriptAndExtractInt(
+ root->child_at(0)->current_frame_host(),
+ "window.domAutomationController.send(location.ancestorOrigins.length);",
+ &ancestor_origins_length));
+ EXPECT_EQ(1, ancestor_origins_length);
+ std::string result;
+ EXPECT_TRUE(ExecuteScriptAndExtractString(
+ root->child_at(0)->current_frame_host(),
+ "window.domAutomationController.send(location.ancestorOrigins[0]);",
+ &result));
+ EXPECT_EQ(result + "/", main_url.GetOrigin().spec());
+
+ // Check that bar.com frame's location.ancestorOrigins contains the correct
+ // origin for its two ancestors. The topmost parent origin should be
+ // replicated as part of ViewMsg_New, and the middle frame (foo.com's) origin
+ // should be replicated as part of FrameMsg_NewFrameProxy sent for foo.com's
+ // frame in bar.com's process.
+ EXPECT_TRUE(ExecuteScriptAndExtractInt(
+ bottom_child->current_frame_host(),
+ "window.domAutomationController.send(location.ancestorOrigins.length);",
+ &ancestor_origins_length));
+ EXPECT_EQ(2, ancestor_origins_length);
+ EXPECT_TRUE(ExecuteScriptAndExtractString(
+ bottom_child->current_frame_host(),
+ "window.domAutomationController.send(location.ancestorOrigins[0]);",
+ &result));
+ EXPECT_EQ(result + "/", foo_url.GetOrigin().spec());
+ EXPECT_TRUE(ExecuteScriptAndExtractString(
+ bottom_child->current_frame_host(),
+ "window.domAutomationController.send(location.ancestorOrigins[1]);",
+ &result));
+ EXPECT_EQ(result + "/", main_url.GetOrigin().spec());
+}
+
+// Check that iframe sandbox flags are replicated correctly.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, SandboxFlagsReplication) {
+ GURL main_url(embedded_test_server()->GetURL("/sandboxed_frames.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ // It is safe to obtain the root frame tree node here, as it doesn't change.
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+
+ TestNavigationObserver observer(shell()->web_contents());
+
+ // Navigate the second (sandboxed) subframe to a cross-site page with a
+ // subframe.
+ GURL foo_url(
+ embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html"));
+ NavigateFrameToURL(root->child_at(1), foo_url);
+ EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+
+ // We can't use a TestNavigationObserver to verify the URL here,
+ // since the frame has children that may have clobbered it in the observer.
+ EXPECT_EQ(foo_url, root->child_at(1)->current_url());
+
+ // Load cross-site page into subframe's subframe.
+ ASSERT_EQ(2U, root->child_at(1)->child_count());
+ GURL bar_url(embedded_test_server()->GetURL("bar.com", "/title1.html"));
+ NavigateFrameToURL(root->child_at(1)->child_at(0), bar_url);
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ EXPECT_EQ(bar_url, observer.last_navigation_url());
+
+ // Opening a popup in the sandboxed foo.com iframe should fail.
+ bool success = false;
+ EXPECT_TRUE(
+ ExecuteScriptAndExtractBool(root->child_at(1)->current_frame_host(),
+ "window.domAutomationController.send("
+ "!window.open('data:text/html,dataurl'));",
+ &success));
+ EXPECT_TRUE(success);
+ EXPECT_EQ(1u, Shell::windows().size());
+
+ // Opening a popup in a frame whose parent is sandboxed should also fail.
+ // Here, bar.com frame's sandboxed parent frame is a remote frame in
+ // bar.com's process.
+ success = false;
+ EXPECT_TRUE(ExecuteScriptAndExtractBool(
+ root->child_at(1)->child_at(0)->current_frame_host(),
+ "window.domAutomationController.send("
+ "!window.open('data:text/html,dataurl'));",
+ &success));
+ EXPECT_TRUE(success);
+ EXPECT_EQ(1u, Shell::windows().size());
+
+ // Same, but now try the case where bar.com frame's sandboxed parent is a
+ // local frame in bar.com's process.
+ success = false;
+ EXPECT_TRUE(ExecuteScriptAndExtractBool(
+ root->child_at(2)->child_at(0)->current_frame_host(),
+ "window.domAutomationController.send("
+ "!window.open('data:text/html,dataurl'));",
+ &success));
+ EXPECT_TRUE(success);
+ EXPECT_EQ(1u, Shell::windows().size());
+
+ // Check that foo.com frame's location.ancestorOrigins contains the correct
+ // origin for the parent, which should be unaffected by sandboxing.
+ int ancestor_origins_length = 0;
+ EXPECT_TRUE(ExecuteScriptAndExtractInt(
+ root->child_at(1)->current_frame_host(),
+ "window.domAutomationController.send(location.ancestorOrigins.length);",
+ &ancestor_origins_length));
+ EXPECT_EQ(1, ancestor_origins_length);
+ std::string result;
+ EXPECT_TRUE(ExecuteScriptAndExtractString(
+ root->child_at(1)->current_frame_host(),
+ "window.domAutomationController.send(location.ancestorOrigins[0]);",
+ &result));
+ EXPECT_EQ(result + "/", main_url.GetOrigin().spec());
+
+ // Now check location.ancestorOrigins for the bar.com frame. The middle frame
+ // (foo.com's) origin should be unique, since that frame is sandboxed, and
+ // the top frame should match |main_url|.
+ FrameTreeNode* bottom_child = root->child_at(1)->child_at(0);
+ EXPECT_TRUE(ExecuteScriptAndExtractInt(
+ bottom_child->current_frame_host(),
+ "window.domAutomationController.send(location.ancestorOrigins.length);",
+ &ancestor_origins_length));
+ EXPECT_EQ(2, ancestor_origins_length);
+ EXPECT_TRUE(ExecuteScriptAndExtractString(
+ bottom_child->current_frame_host(),
+ "window.domAutomationController.send(location.ancestorOrigins[0]);",
+ &result));
+ EXPECT_EQ("null", result);
+ EXPECT_TRUE(ExecuteScriptAndExtractString(
+ bottom_child->current_frame_host(),
+ "window.domAutomationController.send(location.ancestorOrigins[1]);",
+ &result));
+ EXPECT_EQ(main_url.GetOrigin().spec(), result + "/");
+}
+
+// Check that dynamic updates to iframe sandbox flags are propagated correctly.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DynamicSandboxFlags) {
+ GURL main_url(
+ embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ // It is safe to obtain the root frame tree node here, as it doesn't change.
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+
+ TestNavigationObserver observer(shell()->web_contents());
+ ASSERT_EQ(2U, root->child_count());
+
+ // Make sure first frame starts out at the correct cross-site page.
+ EXPECT_EQ(embedded_test_server()->GetURL("bar.com", "/title1.html"),
+ root->child_at(0)->current_url());
+
+ // Navigate second frame to another cross-site page.
+ GURL baz_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
+ NavigateFrameToURL(root->child_at(1), baz_url);
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ EXPECT_EQ(baz_url, observer.last_navigation_url());
+
+ // Both frames should not be sandboxed to start with.
+ EXPECT_EQ(SandboxFlags::NONE,
+ root->child_at(0)->current_replication_state().sandbox_flags);
+ EXPECT_EQ(SandboxFlags::NONE, root->child_at(0)->effective_sandbox_flags());
+ EXPECT_EQ(SandboxFlags::NONE,
+ root->child_at(1)->current_replication_state().sandbox_flags);
+ EXPECT_EQ(SandboxFlags::NONE, root->child_at(1)->effective_sandbox_flags());
+
+ // Dynamically update sandbox flags for the first frame.
+ EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
+ "window.domAutomationController.send("
+ "document.querySelector('iframe').sandbox="
+ "'allow-scripts');"));
+
+ // Check that updated sandbox flags are propagated to browser process.
+ // The new flags should be set in current_replication_state(), while
+ // effective_sandbox_flags() should still reflect the old flags, because
+ // sandbox flag updates take place only after navigations. "allow-scripts"
+ // resets both SandboxFlags::Scripts and SandboxFlags::AutomaticFeatures bits
+ // per blink::parseSandboxPolicy().
+ SandboxFlags expected_flags = SandboxFlags::ALL & ~SandboxFlags::SCRIPTS &
+ ~SandboxFlags::AUTOMATIC_FEATURES;
+ EXPECT_EQ(expected_flags,
+ root->child_at(0)->current_replication_state().sandbox_flags);
+ EXPECT_EQ(SandboxFlags::NONE, root->child_at(0)->effective_sandbox_flags());
+
+ // Navigate the first frame to a page on the same site. The new sandbox
+ // flags should take effect. The new page has a child frame, so use
+ // TestFrameNavigationObserver to wait for it to be loaded.
+ TestFrameNavigationObserver frame_observer(root->child_at(0), 2);
+ GURL bar_url(
+ embedded_test_server()->GetURL("bar.com", "/frame_tree/2-4.html"));
+ NavigateFrameToURL(root->child_at(0), bar_url);
+ frame_observer.Wait();
+ EXPECT_EQ(bar_url, root->child_at(0)->current_url());
+ ASSERT_EQ(1U, root->child_at(0)->child_count());
+
+ // Confirm that the browser process has updated the frame's current sandbox
+ // flags.
+ EXPECT_EQ(expected_flags,
+ root->child_at(0)->current_replication_state().sandbox_flags);
+ EXPECT_EQ(expected_flags, root->child_at(0)->effective_sandbox_flags());
+
+ // Opening a popup in the now-sandboxed frame should fail.
+ bool success = false;
+ EXPECT_TRUE(
+ ExecuteScriptAndExtractBool(root->child_at(0)->current_frame_host(),
+ "window.domAutomationController.send("
+ "!window.open('data:text/html,dataurl'));",
+ &success));
+ EXPECT_TRUE(success);
+ EXPECT_EQ(1u, Shell::windows().size());
+
+ // Navigate the child of the now-sandboxed frame to a page on baz.com. The
+ // child should inherit the latest sandbox flags from its parent frame, which
+ // is currently a proxy in baz.com's renderer process. This checks that the
+ // proxies of |root->child_at(0)| were also updated with the latest sandbox
+ // flags.
+ GURL baz_child_url(embedded_test_server()->GetURL("baz.com", "/title2.html"));
+ NavigateFrameToURL(root->child_at(0)->child_at(0), baz_child_url);
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ EXPECT_EQ(baz_child_url, observer.last_navigation_url());
+
+ // Opening a popup in the child of a sandboxed frame should fail.
+ success = false;
+ EXPECT_TRUE(ExecuteScriptAndExtractBool(
+ root->child_at(0)->child_at(0)->current_frame_host(),
+ "window.domAutomationController.send("
+ "!window.open('data:text/html,dataurl'));",
+ &success));
+ EXPECT_TRUE(success);
+ EXPECT_EQ(1u, Shell::windows().size());
+}
+
+// Check that dynamic updates to iframe sandbox flags are propagated correctly.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+ DynamicSandboxFlagsRemoteToLocal) {
+ GURL main_url(
+ embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ // It is safe to obtain the root frame tree node here, as it doesn't change.
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+
+ TestNavigationObserver observer(shell()->web_contents());
+ ASSERT_EQ(2U, root->child_count());
+
+ // Make sure the two frames starts out at correct URLs.
+ EXPECT_EQ(embedded_test_server()->GetURL("bar.com", "/title1.html"),
+ root->child_at(0)->current_url());
+ EXPECT_EQ(embedded_test_server()->GetURL("/title1.html"),
+ root->child_at(1)->current_url());
+
+ // Update the second frame's sandbox flags.
+ EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
+ "window.domAutomationController.send("
+ "document.querySelectorAll('iframe')[1].sandbox="
+ "'allow-scripts');"));
+
+ // Check that the current sandbox flags are updated but the effective
+ // sandbox flags are not.
+ SandboxFlags expected_flags = SandboxFlags::ALL & ~SandboxFlags::SCRIPTS &
+ ~SandboxFlags::AUTOMATIC_FEATURES;
+ EXPECT_EQ(expected_flags,
+ root->child_at(1)->current_replication_state().sandbox_flags);
+ EXPECT_EQ(SandboxFlags::NONE, root->child_at(1)->effective_sandbox_flags());
+
+ // Navigate the second subframe to a page on bar.com. This will trigger a
+ // remote-to-local frame swap in bar.com's process. The target page has
+ // another frame, so use TestFrameNavigationObserver to wait for all frames
+ // to be loaded.
+ TestFrameNavigationObserver frame_observer(root->child_at(1), 2);
+ GURL bar_url(embedded_test_server()->GetURL(
+ "bar.com", "/frame_tree/page_with_one_frame.html"));
+ NavigateFrameToURL(root->child_at(1), bar_url);
+ frame_observer.Wait();
+ EXPECT_EQ(bar_url, root->child_at(1)->current_url());
+ ASSERT_EQ(1U, root->child_at(1)->child_count());
+
+ // Confirm that the browser process has updated the current sandbox flags.
+ EXPECT_EQ(expected_flags,
+ root->child_at(1)->current_replication_state().sandbox_flags);
+ EXPECT_EQ(expected_flags, root->child_at(1)->effective_sandbox_flags());
+
+ // Opening a popup in the sandboxed second frame should fail.
+ bool success = false;
+ EXPECT_TRUE(
+ ExecuteScriptAndExtractBool(root->child_at(1)->current_frame_host(),
+ "window.domAutomationController.send("
+ "!window.open('data:text/html,dataurl'));",
+ &success));
+ EXPECT_TRUE(success);
+ EXPECT_EQ(1u, Shell::windows().size());
+
+ // Make sure that the child frame inherits the sandbox flags of its
+ // now-sandboxed parent frame.
+ success = false;
+ EXPECT_TRUE(ExecuteScriptAndExtractBool(
+ root->child_at(1)->child_at(0)->current_frame_host(),
+ "window.domAutomationController.send("
+ "!window.open('data:text/html,dataurl'));",
+ &success));
+ EXPECT_TRUE(success);
+ EXPECT_EQ(1u, Shell::windows().size());
+}
+
+// Check that dynamic updates to iframe sandbox flags are propagated correctly.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+ DynamicSandboxFlagsRendererInitiatedNavigation) {
+ GURL main_url(
+ embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ // It is safe to obtain the root frame tree node here, as it doesn't change.
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+
+ TestNavigationObserver observer(shell()->web_contents());
+ ASSERT_EQ(1U, root->child_count());
+
+ // Make sure the frame starts out at the correct cross-site page.
+ EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title1.html"),
+ root->child_at(0)->current_url());
+
+ // The frame should not be sandboxed to start with.
+ EXPECT_EQ(SandboxFlags::NONE,
+ root->child_at(0)->current_replication_state().sandbox_flags);
+ EXPECT_EQ(SandboxFlags::NONE, root->child_at(0)->effective_sandbox_flags());
+
+ // Dynamically update the frame's sandbox flags.
+ EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
+ "window.domAutomationController.send("
+ "document.querySelector('iframe').sandbox="
+ "'allow-scripts');"));
+
+ // Check that updated sandbox flags are propagated to browser process.
+ // The new flags should be set in current_replication_state(), while
+ // effective_sandbox_flags() should still reflect the old flags, because
+ // sandbox flag updates take place only after navigations. "allow-scripts"
+ // resets both SandboxFlags::Scripts and SandboxFlags::AutomaticFeatures bits
+ // per blink::parseSandboxPolicy().
+ SandboxFlags expected_flags = SandboxFlags::ALL & ~SandboxFlags::SCRIPTS &
+ ~SandboxFlags::AUTOMATIC_FEATURES;
+ EXPECT_EQ(expected_flags,
+ root->child_at(0)->current_replication_state().sandbox_flags);
+ EXPECT_EQ(SandboxFlags::NONE, root->child_at(0)->effective_sandbox_flags());
+
+ // Perform a renderer-initiated same-site navigation in the first frame. The
+ // new sandbox flags should take effect.
+ TestFrameNavigationObserver frame_observer(root->child_at(0));
+ ASSERT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(),
+ "window.location.href='/title2.html'"));
+ frame_observer.Wait();
+ EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title2.html"),
+ root->child_at(0)->current_url());
+
+ // Confirm that the browser process has updated the frame's current sandbox
+ // flags.
+ EXPECT_EQ(expected_flags,
+ root->child_at(0)->current_replication_state().sandbox_flags);
+ EXPECT_EQ(expected_flags, root->child_at(0)->effective_sandbox_flags());
+
+ // Opening a popup in the now-sandboxed frame should fail.
+ bool success = false;
+ EXPECT_TRUE(
+ ExecuteScriptAndExtractBool(root->child_at(0)->current_frame_host(),
+ "window.domAutomationController.send("
+ "!window.open('data:text/html,dataurl'));",
+ &success));
+ EXPECT_TRUE(success);
+ EXPECT_EQ(1u, Shell::windows().size());
+}
+
+// Verify that when a new child frame is added, the proxies created for it in
+// other SiteInstances have correct sandbox flags and origin.
+//
+// A A A
+// / / \ / \ .
+// B -> B A -> B A
+// \ .
+// B
+//
+// The test checks sandbox flags and origin for the proxy added in step 2, by
+// checking whether the grandchild frame added in step 3 sees proper sandbox
+// flags and origin for its (remote) parent. This wasn't addressed when
+// https://crbug.com/423587 was fixed.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+ ProxiesForNewChildFramesHaveCorrectReplicationState) {
+ GURL main_url(
+ embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ // It is safe to obtain the root frame tree node here, as it doesn't change.
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+ TestNavigationObserver observer(shell()->web_contents());
+
+ EXPECT_EQ(
+ " Site A ------------ proxies for B\n"
+ " +--Site B ------- proxies for A\n"
+ "Where A = http://127.0.0.1/\n"
+ " B = http://baz.com/",
+ DepictFrameTree(root));
+
+ // In the root frame, add a new sandboxed local frame, which itself has a
+ // child frame on baz.com. Wait for three RenderFrameHosts to be created:
+ // the new sandboxed local frame, its child (while it's still local), and a
+ // pending RFH when starting the cross-site navigation to baz.com.
+ RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 3);
+ EXPECT_TRUE(
+ ExecuteScript(root->current_frame_host(),
+ "window.domAutomationController.send("
+ " addFrame('/frame_tree/page_with_one_frame.html',"
+ " 'allow-scripts allow-same-origin'))"));
+ frame_observer.Wait();
+
+ // Wait for the cross-site navigation to baz.com in the grandchild to finish.
+ FrameTreeNode* bottom_child = root->child_at(1)->child_at(0);
+ TestFrameNavigationObserver navigation_observer(bottom_child);
+ navigation_observer.Wait();
+
+ EXPECT_EQ(
+ " Site A ------------ proxies for B\n"
+ " |--Site B ------- proxies for A\n"
+ " +--Site A ------- proxies for B\n"
+ " +--Site B -- proxies for A\n"
+ "Where A = http://127.0.0.1/\n"
+ " B = http://baz.com/",
+ DepictFrameTree(root));
+
+ // Use location.ancestorOrigins to check that the grandchild on baz.com sees
+ // correct origin for its parent.
+ int ancestor_origins_length = 0;
+ EXPECT_TRUE(ExecuteScriptAndExtractInt(
+ bottom_child->current_frame_host(),
+ "window.domAutomationController.send(location.ancestorOrigins.length);",
+ &ancestor_origins_length));
+ EXPECT_EQ(2, ancestor_origins_length);
+ std::string parent_origin;
+ EXPECT_TRUE(ExecuteScriptAndExtractString(
+ bottom_child->current_frame_host(),
+ "window.domAutomationController.send(location.ancestorOrigins[0]);",
+ &parent_origin));
+ EXPECT_EQ(main_url.GetOrigin().spec(), parent_origin + "/");
+
+ // Check that the sandbox flags in the browser process are correct.
+ // "allow-scripts" resets both SandboxFlags::Scripts and
+ // SandboxFlags::AutomaticFeatures bits per blink::parseSandboxPolicy().
+ SandboxFlags expected_flags = SandboxFlags::ALL & ~SandboxFlags::SCRIPTS &
+ ~SandboxFlags::AUTOMATIC_FEATURES &
+ ~SandboxFlags::ORIGIN;
+ EXPECT_EQ(expected_flags,
+ root->child_at(1)->current_replication_state().sandbox_flags);
+
+ // The child of the sandboxed frame should've inherited sandbox flags, so it
+ // should not be able to create popups.
+ bool success = false;
+ EXPECT_TRUE(
+ ExecuteScriptAndExtractBool(bottom_child->current_frame_host(),
+ "window.domAutomationController.send("
+ "!window.open('data:text/html,dataurl'));",
+ &success));
+ EXPECT_TRUE(success);
+ EXPECT_EQ(1u, Shell::windows().size());
+}
+
+// Verify that a child frame can retrieve the name property set by its parent.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, WindowNameReplication) {
+ GURL main_url(embedded_test_server()->GetURL("/frame_tree/2-4.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ // It is safe to obtain the root frame tree node here, as it doesn't change.
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+
+ TestNavigationObserver observer(shell()->web_contents());
+
+ // Load cross-site page into iframe.
+ GURL frame_url =
+ embedded_test_server()->GetURL("foo.com", "/frame_tree/3-1.html");
+ NavigateFrameToURL(root->child_at(0), frame_url);
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ EXPECT_EQ(frame_url, observer.last_navigation_url());
+
+ // Ensure that a new process is created for the subframe.
+ EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
+ root->child_at(0)->current_frame_host()->GetSiteInstance());
+
+ // Check that the window.name seen by the frame matches the name attribute
+ // specified by its parent in the iframe tag.
+ std::string result;
+ EXPECT_TRUE(ExecuteScriptAndExtractString(
+ root->child_at(0)->current_frame_host(),
+ "window.domAutomationController.send(window.name);", &result));
+ EXPECT_EQ("3-1-name", result);
+}
+
+// Verify that dynamic updates to a frame's window.name propagate to the
+// frame's proxies, so that the latest frame names can be used in navigations.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DynamicWindowName) {
+ GURL main_url(embedded_test_server()->GetURL("/frame_tree/2-4.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ // It is safe to obtain the root frame tree node here, as it doesn't change.
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+ TestNavigationObserver observer(shell()->web_contents());
+
+ // Load cross-site page into iframe.
+ GURL frame_url =
+ embedded_test_server()->GetURL("foo.com", "/frame_tree/3-1.html");
+ NavigateFrameToURL(root->child_at(0), frame_url);
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ EXPECT_EQ(frame_url, observer.last_navigation_url());
+
+ // Browser process should know the child frame's original window.name
+ // specified in the iframe element.
+ EXPECT_EQ(root->child_at(0)->frame_name(), "3-1-name");
+
+ // Update the child frame's window.name.
+ EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(),
+ "window.domAutomationController.send("
+ "window.name = 'updated-name');"));
+
+ // The change should propagate to the browser process.
+ EXPECT_EQ(root->child_at(0)->frame_name(), "updated-name");
+
+ // The proxy in the parent process should also receive the updated name.
+ // Check that it can reference the child frame by its new name.
+ bool success = false;
+ EXPECT_TRUE(
+ ExecuteScriptAndExtractBool(shell()->web_contents(),
+ "window.domAutomationController.send("
+ "frames['updated-name'] == frames[0]);",
+ &success));
+ EXPECT_TRUE(success);
+
+ // Issue a renderer-initiated navigation from the root frame to the child
+ // frame using the frame's name. Make sure correct frame is navigated.
+ //
+ // TODO(alexmos): When blink::createWindow is refactored to handle
+ // RemoteFrames, this should also be tested via window.open(url, frame_name)
+ // and a more complicated frame hierarchy (https://crbug.com/463742)
+ TestFrameNavigationObserver frame_observer(root->child_at(0));
+ GURL foo_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
+ std::string script = base::StringPrintf(
+ "window.domAutomationController.send("
+ "frames['updated-name'].location.href = '%s');",
+ foo_url.spec().c_str());
+ EXPECT_TRUE(ExecuteScript(shell()->web_contents(), script));
+ frame_observer.Wait();
+ EXPECT_EQ(foo_url, root->child_at(0)->current_url());
+}
+
+// Verify that when a frame is navigated to a new origin, the origin update
+// propagates to the frame's proxies.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OriginUpdatesReachProxies) {
+ GURL main_url(
+ embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ // It is safe to obtain the root frame tree node here, as it doesn't change.
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+ TestNavigationObserver observer(shell()->web_contents());
+
+ EXPECT_EQ(
+ " Site A ------------ proxies for B\n"
+ " |--Site B ------- proxies for A\n"
+ " +--Site A ------- proxies for B\n"
+ "Where A = http://127.0.0.1/\n"
+ " B = http://bar.com/",
+ DepictFrameTree(root));
+
+ // Navigate second subframe to a baz.com. This should send an origin update
+ // to the frame's proxy in the bar.com (first frame's) process.
+ GURL frame_url = embedded_test_server()->GetURL("baz.com", "/title2.html");
+ NavigateFrameToURL(root->child_at(1), frame_url);
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ EXPECT_EQ(frame_url, observer.last_navigation_url());
+
+ // The first frame can't directly observe the second frame's origin with
+ // JavaScript. Instead, try to navigate the second frame from the first
+ // frame. This should fail with a console error message, which should
+ // contain the second frame's updated origin (see blink::Frame::canNavigate).
+ scoped_ptr<ConsoleObserverDelegate> console_delegate(
+ new ConsoleObserverDelegate(
+ shell()->web_contents(),
+ "Unsafe JavaScript attempt to initiate navigation*"));
+ shell()->web_contents()->SetDelegate(console_delegate.get());
+
+ // frames[1] can't be used due to a bug where RemoteFrames are created out of
+ // order (https://crbug.com/478792). Instead, target second frame by name.
+ EXPECT_TRUE(ExecuteScript(
+ root->child_at(0)->current_frame_host(),
+ "window.domAutomationController.send("
+ " parent.frames['frame2'].location.href = 'data:text/html,foo');"));
+ console_delegate->Wait();
+
+ std::string frame_origin =
+ root->child_at(1)->current_replication_state().origin.string();
+ EXPECT_EQ(frame_origin + "/", frame_url.GetOrigin().spec());
+ EXPECT_TRUE(
+ MatchPattern(console_delegate->message(), "*" + frame_origin + "*"))
+ << "Error message does not contain the frame's latest origin ("
+ << frame_origin << ")";
+}
+
+// Ensure that navigating subframes in --site-per-process mode properly fires
+// the DidStopLoading event on WebContentsObserver.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteDidStopLoading) {
+ 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();
+
+ TestNavigationObserver 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.last_navigation_url());
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+
+ // Load cross-site page into iframe.
+ TestNavigationObserver nav_observer(shell()->web_contents(), 1);
+ GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
+ NavigationController::LoadURLParams params(url);
+ params.transition_type = ui::PAGE_TRANSITION_LINK;
+ params.frame_tree_node_id = child->frame_tree_node_id();
+ child->navigator()->GetController()->LoadURLWithParams(params);
+ nav_observer.Wait();
+
+ // Verify that the navigation succeeded and the expected URL was loaded.
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ EXPECT_EQ(url, observer.last_navigation_url());
+}
+
+// Ensure that the renderer does not crash when navigating a frame that has a
+// sibling RemoteFrame. See https://crbug.com/426953.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+ NavigateWithSiblingRemoteFrame) {
+ GURL main_url(
+ embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
+ NavigateToURL(shell(), main_url);
+
+ // It is safe to obtain the root frame tree node here, as it doesn't change.
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+ TestNavigationObserver observer(shell()->web_contents());
+
+ // Make sure the first frame is out of process.
+ ASSERT_EQ(2U, root->child_count());
+ FrameTreeNode* node2 = root->child_at(0);
+ EXPECT_NE(root->current_frame_host()->GetSiteInstance(),
+ node2->current_frame_host()->GetSiteInstance());
+
+ // Make sure the second frame is in the parent's process.
+ FrameTreeNode* node3 = root->child_at(1);
+ EXPECT_EQ(root->current_frame_host()->GetSiteInstance(),
+ node3->current_frame_host()->GetSiteInstance());
+
+ // Navigate the second iframe (node3) to a URL in its own process.
+ GURL title_url = embedded_test_server()->GetURL("/title2.html");
+ NavigateFrameToURL(node3, title_url);
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ EXPECT_EQ(title_url, observer.last_navigation_url());
+ EXPECT_EQ(root->current_frame_host()->GetSiteInstance(),
+ node3->current_frame_host()->GetSiteInstance());
+ EXPECT_TRUE(node3->current_frame_host()->IsRenderFrameLive());
+}
+
+// Verify that load events for iframe elements work when the child frame is
+// out-of-process. In such cases, the load event is forwarded from the child
+// frame to the parent frame via the browser process.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, LoadEventForwarding) {
+ // Load a page with a cross-site frame. The parent page has an onload
+ // handler in the iframe element that appends "LOADED" to the document title.
+ {
+ GURL main_url(
+ embedded_test_server()->GetURL("/frame_with_load_event.html"));
+ base::string16 expected_title(base::UTF8ToUTF16("LOADED"));
+ TitleWatcher title_watcher(shell()->web_contents(), expected_title);
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+ EXPECT_EQ(title_watcher.WaitAndGetTitle(), expected_title);
+ }
+
+ // 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 another cross-site page into the iframe and check that the load event
+ // is fired.
+ {
+ GURL foo_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
+ base::string16 expected_title(base::UTF8ToUTF16("LOADEDLOADED"));
+ TitleWatcher title_watcher(shell()->web_contents(), expected_title);
+ TestNavigationObserver observer(shell()->web_contents());
+ NavigateFrameToURL(root->child_at(0), foo_url);
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ EXPECT_EQ(foo_url, observer.last_navigation_url());
+ EXPECT_EQ(title_watcher.WaitAndGetTitle(), expected_title);
+ }
+}
+
+// Check that postMessage can be routed between cross-site iframes.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, SubframePostMessage) {
+ GURL main_url(embedded_test_server()->GetURL(
+ "/frame_tree/page_with_post_message_frames.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ // It is safe to obtain the root frame tree node here, as it doesn't change.
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+
+ TestNavigationObserver observer(shell()->web_contents());
+ ASSERT_EQ(2U, root->child_count());
+
+ // Verify the frames start at correct URLs. First frame should be
+ // same-site; second frame should be cross-site.
+ GURL same_site_url(embedded_test_server()->GetURL("/post_message.html"));
+ EXPECT_EQ(same_site_url, root->child_at(0)->current_url());
+ GURL foo_url(embedded_test_server()->GetURL("foo.com",
+ "/post_message.html"));
+ EXPECT_EQ(foo_url, root->child_at(1)->current_url());
+ EXPECT_NE(root->child_at(0)->current_frame_host()->GetSiteInstance(),
+ root->child_at(1)->current_frame_host()->GetSiteInstance());
+
+ // Send a message from first, same-site frame to second, cross-site frame.
+ // Expect the second frame to reply back to the first frame.
+ PostMessageAndWaitForReply(root->child_at(0),
+ "postToSibling('subframe-msg','subframe2')",
+ "\"done-subframe1\"");
+
+ // Send a postMessage from second, cross-site frame to its parent. Expect
+ // parent to send a reply to the frame.
+ base::string16 expected_title(base::ASCIIToUTF16("subframe-msg"));
+ TitleWatcher title_watcher(shell()->web_contents(), expected_title);
+ PostMessageAndWaitForReply(root->child_at(1), "postToParent('subframe-msg')",
+ "\"done-subframe2\"");
+ EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
+
+ // Verify the total number of received messages for each subframe. First
+ // frame should have one message (reply from second frame), and second frame
+ // should have two messages (message from first frame and reply from parent).
+ int subframe1_received_messages = 0;
+ int subframe2_received_messages = 0;
+ EXPECT_TRUE(ExecuteScriptAndExtractInt(
+ root->child_at(0)->current_frame_host(),
+ "window.domAutomationController.send(window.receivedMessages);",
+ &subframe1_received_messages));
+ EXPECT_EQ(1, subframe1_received_messages);
+ EXPECT_TRUE(ExecuteScriptAndExtractInt(
+ root->child_at(1)->current_frame_host(),
+ "window.domAutomationController.send(window.receivedMessages);",
+ &subframe2_received_messages));
+ EXPECT_EQ(2, subframe2_received_messages);
+}
+
+// Check that parent.frames[num] references correct sibling frames when the
+// parent is remote. See https://crbug.com/478792.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, IndexedFrameAccess) {
+ // Start on a page with three same-site subframes.
+ GURL main_url(
+ embedded_test_server()->GetURL("a.com", "/frame_tree/top.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ // It is safe to obtain the root frame tree node here, as it doesn't change.
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+ ASSERT_EQ(3U, root->child_count());
+ FrameTreeNode* child0 = root->child_at(0);
+ FrameTreeNode* child1 = root->child_at(1);
+ FrameTreeNode* child2 = root->child_at(2);
+
+ // Send each of the frames to a different site. Each new renderer will first
+ // create proxies for the parent and two sibling subframes and then create
+ // and insert the new RenderFrame into the frame tree.
+ GURL b_url(embedded_test_server()->GetURL("b.com", "/post_message.html"));
+ GURL c_url(embedded_test_server()->GetURL("c.com", "/post_message.html"));
+ GURL d_url(embedded_test_server()->GetURL("d.com", "/post_message.html"));
+ NavigateFrameToURL(child0, b_url);
+ // TODO(alexmos): The calls to WaitForRenderFrameReady can be removed once
+ // TestFrameNavigationObserver is fixed to use DidFinishLoad.
+ EXPECT_TRUE(WaitForRenderFrameReady(child0->current_frame_host()));
+ NavigateFrameToURL(child1, c_url);
+ EXPECT_TRUE(WaitForRenderFrameReady(child1->current_frame_host()));
+ NavigateFrameToURL(child2, d_url);
+ EXPECT_TRUE(WaitForRenderFrameReady(child2->current_frame_host()));
+
+ EXPECT_EQ(
+ " Site A ------------ proxies for B C D\n"
+ " |--Site B ------- proxies for A C D\n"
+ " |--Site C ------- proxies for A B D\n"
+ " +--Site D ------- proxies for A B C\n"
+ "Where A = http://a.com/\n"
+ " B = http://b.com/\n"
+ " C = http://c.com/\n"
+ " D = http://d.com/",
+ DepictFrameTree(root));
+
+ // Check that each subframe sees itself at correct index in parent.frames.
+ bool success = false;
+ EXPECT_TRUE(ExecuteScriptAndExtractBool(
+ child0->current_frame_host(),
+ "window.domAutomationController.send(window === parent.frames[0]);",
+ &success));
+ EXPECT_TRUE(success);
+
+ success = false;
+ EXPECT_TRUE(ExecuteScriptAndExtractBool(
+ child1->current_frame_host(),
+ "window.domAutomationController.send(window === parent.frames[1]);",
+ &success));
+ EXPECT_TRUE(success);
+
+ success = false;
+ EXPECT_TRUE(ExecuteScriptAndExtractBool(
+ child2->current_frame_host(),
+ "window.domAutomationController.send(window === parent.frames[2]);",
+ &success));
+ EXPECT_TRUE(success);
+
+ // Send a postMessage from B to parent.frames[1], which should go to C, and
+ // wait for reply.
+ PostMessageAndWaitForReply(child0, "postToSibling('subframe-msg', 1)",
+ "\"done-1-1-name\"");
+
+ // Send a postMessage from C to parent.frames[2], which should go to D, and
+ // wait for reply.
+ PostMessageAndWaitForReply(child1, "postToSibling('subframe-msg', 2)",
+ "\"done-1-2-name\"");
+
+ // Verify the total number of received messages for each subframe.
+ int child0_received_messages = 0;
+ EXPECT_TRUE(ExecuteScriptAndExtractInt(
+ child0->current_frame_host(),
+ "window.domAutomationController.send(window.receivedMessages);",
+ &child0_received_messages));
+ EXPECT_EQ(1, child0_received_messages);
+
+ int child1_received_messages = 0;
+ EXPECT_TRUE(ExecuteScriptAndExtractInt(
+ child1->current_frame_host(),
+ "window.domAutomationController.send(window.receivedMessages);",
+ &child1_received_messages));
+ EXPECT_EQ(2, child1_received_messages);
+
+ int child2_received_messages = 0;
+ EXPECT_TRUE(ExecuteScriptAndExtractInt(
+ child2->current_frame_host(),
+ "window.domAutomationController.send(window.receivedMessages);",
+ &child2_received_messages));
+ EXPECT_EQ(1, child2_received_messages);
+}
+
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, RFPHDestruction) {
+ 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();
+
+ TestNavigationObserver observer(shell()->web_contents());
+
+ // Load cross-site page into iframe.
+ FrameTreeNode* child = root->child_at(0);
+ GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
+ NavigateFrameToURL(root->child_at(0), url);
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ EXPECT_EQ(url, observer.last_navigation_url());
+ EXPECT_EQ(
+ " Site A ------------ proxies for B\n"
+ " |--Site B ------- proxies for A\n"
+ " +--Site A ------- proxies for B\n"
+ " |--Site A -- proxies for B\n"
+ " +--Site A -- proxies for B\n"
+ " +--Site A -- proxies for B\n"
+ "Where A = http://127.0.0.1/\n"
+ " B = http://foo.com/",
+ DepictFrameTree(root));
+
+ // Load another cross-site page.
+ url = embedded_test_server()->GetURL("bar.com", "/title3.html");
+ NavigateIframeToURL(shell()->web_contents(), "test", url);
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ EXPECT_EQ(url, observer.last_navigation_url());
+ EXPECT_EQ(
+ " Site A ------------ proxies for C\n"
+ " |--Site C ------- proxies for A\n"
+ " +--Site A ------- proxies for C\n"
+ " |--Site A -- proxies for C\n"
+ " +--Site A -- proxies for C\n"
+ " +--Site A -- proxies for C\n"
+ "Where A = http://127.0.0.1/\n"
+ " C = http://bar.com/",
+ DepictFrameTree(root));
+
+ // Navigate back to the parent's origin.
+ url = embedded_test_server()->GetURL("/title1.html");
+ NavigateFrameToURL(child, url);
+ EXPECT_EQ(url, observer.last_navigation_url());
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ EXPECT_EQ(
+ " Site A\n"
+ " |--Site A\n"
+ " +--Site A\n"
+ " |--Site A\n"
+ " +--Site A\n"
+ " +--Site A\n"
+ "Where A = http://127.0.0.1/",
+ DepictFrameTree(root));
+}
+
} // namespace content
diff --git a/chromium/content/browser/site_per_process_browsertest.h b/chromium/content/browser/site_per_process_browsertest.h
index 19dfc01c598..9e74bd70ee0 100644
--- a/chromium/content/browser/site_per_process_browsertest.h
+++ b/chromium/content/browser/site_per_process_browsertest.h
@@ -2,11 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#ifndef CONTENT_BROWSER_SITE_PER_PROCESS_BROWSERTEST_H_
+#define CONTENT_BROWSER_SITE_PER_PROCESS_BROWSERTEST_H_
+
+#include <string>
+
#include "content/public/test/content_browser_test.h"
+#include "content/test/content_browser_test_utils_internal.h"
#include "url/gurl.h"
namespace content {
+class FrameTreeNode;
class Shell;
class SitePerProcessBrowserTest : public ContentBrowserTest {
@@ -19,12 +26,15 @@ class SitePerProcessBrowserTest : public ContentBrowserTest {
// 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);
+ std::string DepictFrameTree(FrameTreeNode* node);
void SetUpCommandLine(base::CommandLine* command_line) override;
void SetUpOnMainThread() override;
+
+ private:
+ FrameTreeVisualizer visualizer_;
};
} // namespace content
+
+#endif // CONTENT_BROWSER_SITE_PER_PROCESS_BROWSERTEST_H_
diff --git a/chromium/content/browser/speech/OWNERS b/chromium/content/browser/speech/OWNERS
index b38caa6f1ff..1dede2088d2 100644
--- a/chromium/content/browser/speech/OWNERS
+++ b/chromium/content/browser/speech/OWNERS
@@ -1,3 +1 @@
-hans@chromium.org
tommi@chromium.org
-xians@chromium.org
diff --git a/chromium/content/browser/speech/audio_buffer.cc b/chromium/content/browser/speech/audio_buffer.cc
index 3e7d2a4a68e..823fff5291f 100644
--- a/chromium/content/browser/speech/audio_buffer.cc
+++ b/chromium/content/browser/speech/audio_buffer.cc
@@ -5,7 +5,6 @@
#include "content/browser/speech/audio_buffer.h"
#include "base/logging.h"
-#include "base/stl_util.h"
namespace content {
@@ -13,6 +12,11 @@ AudioChunk::AudioChunk(int bytes_per_sample)
: bytes_per_sample_(bytes_per_sample) {
}
+AudioChunk::AudioChunk(size_t length, int bytes_per_sample)
+ : data_string_(length, '\0'), bytes_per_sample_(bytes_per_sample) {
+ DCHECK_EQ(length % bytes_per_sample, 0U);
+}
+
AudioChunk::AudioChunk(const uint8* data, size_t length, int bytes_per_sample)
: data_string_(reinterpret_cast<const char*>(data), length),
bytes_per_sample_(bytes_per_sample) {
@@ -40,7 +44,6 @@ const int16* AudioChunk::SamplesData16() const {
return reinterpret_cast<const int16*>(data_string_.data());
}
-
AudioBuffer::AudioBuffer(int bytes_per_sample)
: bytes_per_sample_(bytes_per_sample) {
DCHECK(bytes_per_sample == 1 ||
@@ -64,17 +67,19 @@ scoped_refptr<AudioChunk> AudioBuffer::DequeueSingleChunk() {
}
scoped_refptr<AudioChunk> AudioBuffer::DequeueAll() {
- scoped_refptr<AudioChunk> chunk(new AudioChunk(bytes_per_sample_));
size_t resulting_length = 0;
ChunksContainer::const_iterator it;
// In order to improve performance, calulate in advance the total length
// and then copy the chunks.
for (it = chunks_.begin(); it != chunks_.end(); ++it) {
- resulting_length += (*it)->data_string_.length();
+ resulting_length += (*it)->AsString().length();
}
- chunk->data_string_.reserve(resulting_length);
+ scoped_refptr<AudioChunk> chunk(
+ new AudioChunk(resulting_length, bytes_per_sample_));
+ uint8* dest = chunk->writable_data();
for (it = chunks_.begin(); it != chunks_.end(); ++it) {
- chunk->data_string_.append((*it)->data_string_);
+ memcpy(dest, (*it)->AsString().data(), (*it)->AsString().length());
+ dest += (*it)->AsString().length();
}
Clear();
return chunk;
diff --git a/chromium/content/browser/speech/audio_buffer.h b/chromium/content/browser/speech/audio_buffer.h
index 783ae6679f3..7b0fd7e19df 100644
--- a/chromium/content/browser/speech/audio_buffer.h
+++ b/chromium/content/browser/speech/audio_buffer.h
@@ -19,6 +19,8 @@ class CONTENT_EXPORT AudioChunk :
public base::RefCountedThreadSafe<AudioChunk> {
public:
explicit AudioChunk(int bytes_per_sample);
+ // Creates a chunk of |length| bytes, initialized to zeros.
+ AudioChunk(size_t length, int bytes_per_sample);
AudioChunk(const uint8* data, size_t length, int bytes_per_sample);
bool IsEmpty() const;
@@ -27,14 +29,14 @@ class CONTENT_EXPORT AudioChunk :
const std::string& AsString() const;
int16 GetSample16(size_t index) const;
const int16* SamplesData16() const;
- friend class AudioBuffer;
+ uint8* writable_data() { return reinterpret_cast<uint8*>(&data_string_[0]); }
private:
- ~AudioChunk() {}
friend class base::RefCountedThreadSafe<AudioChunk>;
+ ~AudioChunk() {}
std::string data_string_;
- int bytes_per_sample_;
+ const int bytes_per_sample_;
DISALLOW_COPY_AND_ASSIGN(AudioChunk);
};
@@ -51,7 +53,8 @@ class AudioBuffer {
// Dequeues, in FIFO order, a single chunk respecting the length of the
// corresponding Enqueue call (in a nutshell: multiple Enqueue calls followed
- // by Dequeue calls will return the individual chunks without merging them).
+ // by DequeueSingleChunk calls will return the individual chunks without
+ // merging them).
scoped_refptr<AudioChunk> DequeueSingleChunk();
// Dequeues all previously enqueued chunks, merging them in a single chunk.
@@ -66,7 +69,7 @@ class AudioBuffer {
private:
typedef std::deque<scoped_refptr<AudioChunk> > ChunksContainer;
ChunksContainer chunks_;
- int bytes_per_sample_;
+ const int bytes_per_sample_;
DISALLOW_COPY_AND_ASSIGN(AudioBuffer);
};
diff --git a/chromium/content/browser/speech/audio_encoder.cc b/chromium/content/browser/speech/audio_encoder.cc
index 09b5dca287d..e145ddaba40 100644
--- a/chromium/content/browser/speech/audio_encoder.cc
+++ b/chromium/content/browser/speech/audio_encoder.cc
@@ -108,7 +108,7 @@ const int kMaxSpeexFrameLength = 110; // (44kbps rate sampled at 32kHz).
// Since the frame length gets written out as a byte in the encoded packet,
// make sure it is within the byte range.
-COMPILE_ASSERT(kMaxSpeexFrameLength <= 0xFF, invalidLength);
+static_assert(kMaxSpeexFrameLength <= 0xFF, "invalid length");
class SpeexEncoder : public AudioEncoder {
public:
diff --git a/chromium/content/browser/speech/chunked_byte_buffer.cc b/chromium/content/browser/speech/chunked_byte_buffer.cc
index ae8a6ce8245..5fcf5d18fe6 100644
--- a/chromium/content/browser/speech/chunked_byte_buffer.cc
+++ b/chromium/content/browser/speech/chunked_byte_buffer.cc
@@ -14,8 +14,8 @@ namespace {
static const size_t kHeaderLength = sizeof(uint32);
-COMPILE_ASSERT(sizeof(size_t) >= kHeaderLength,
- ChunkedByteBufferNotSupportedOnThisArchitecture);
+static_assert(sizeof(size_t) >= kHeaderLength,
+ "chunked byte buffer not supported on this architecture");
uint32 ReadBigEndian32(const uint8* buffer) {
return (static_cast<uint32>(buffer[3])) |
diff --git a/chromium/content/browser/speech/endpointer/endpointer_unittest.cc b/chromium/content/browser/speech/endpointer/endpointer_unittest.cc
index 807b6f68287..c65a7c9b4e1 100644
--- a/chromium/content/browser/speech/endpointer/endpointer_unittest.cc
+++ b/chromium/content/browser/speech/endpointer/endpointer_unittest.cc
@@ -13,7 +13,7 @@ const int kSampleRate = 8000; // 8 k samples per second for AMR encoding.
// At 8 sample per second a 20 ms frame is 160 samples, which corrsponds
// to the AMR codec.
const int kFrameSize = kSampleRate / kFrameRate; // 160 samples.
-COMPILE_ASSERT(kFrameSize == 160, invalid_frame_size);
+static_assert(kFrameSize == 160, "invalid frame size");
}
namespace content {
diff --git a/chromium/content/browser/speech/google_one_shot_remote_engine.cc b/chromium/content/browser/speech/google_one_shot_remote_engine.cc
index e52e713deb5..77f5c2cb6f6 100644
--- a/chromium/content/browser/speech/google_one_shot_remote_engine.cc
+++ b/chromium/content/browser/speech/google_one_shot_remote_engine.cc
@@ -55,7 +55,7 @@ bool ParseServerResponse(const std::string& response_body,
}
if (!response_value->IsType(base::Value::TYPE_DICTIONARY)) {
- VLOG(1) << "ParseServerResponse: Unexpected response type "
+ DVLOG(1) << "ParseServerResponse: Unexpected response type "
<< response_value->GetType();
return false;
}
@@ -65,7 +65,7 @@ bool ParseServerResponse(const std::string& response_body,
// Get the status.
int status;
if (!response_object->GetInteger(kStatusString, &status)) {
- VLOG(1) << "ParseServerResponse: " << kStatusString
+ DVLOG(1) << "ParseServerResponse: " << kStatusString
<< " is not a valid integer value.";
return false;
}
@@ -83,21 +83,21 @@ bool ParseServerResponse(const std::string& response_body,
default:
error->code = SPEECH_RECOGNITION_ERROR_NETWORK;
// Other status codes should not be returned by the server.
- VLOG(1) << "ParseServerResponse: unexpected status code " << status;
+ DVLOG(1) << "ParseServerResponse: unexpected status code " << status;
return false;
}
// Get the hypotheses.
const base::Value* hypotheses_value = NULL;
if (!response_object->Get(kHypothesesString, &hypotheses_value)) {
- VLOG(1) << "ParseServerResponse: Missing hypotheses attribute.";
+ DVLOG(1) << "ParseServerResponse: Missing hypotheses attribute.";
return false;
}
DCHECK(hypotheses_value);
if (!hypotheses_value->IsType(base::Value::TYPE_LIST)) {
- VLOG(1) << "ParseServerResponse: Unexpected hypotheses type "
- << hypotheses_value->GetType();
+ DVLOG(1) << "ParseServerResponse: Unexpected hypotheses type "
+ << hypotheses_value->GetType();
return false;
}
@@ -210,10 +210,8 @@ void GoogleOneShotRemoteEngine::StartRecognition() {
config_.audio_sample_rate,
config_.audio_num_bits_per_sample));
DCHECK(encoder_.get());
- url_fetcher_.reset(net::URLFetcher::Create(url_fetcher_id_for_tests,
- url,
- net::URLFetcher::POST,
- this));
+ url_fetcher_ = net::URLFetcher::Create(url_fetcher_id_for_tests, url,
+ net::URLFetcher::POST, this);
url_fetcher_->SetChunkedUpload(encoder_->mime_type());
url_fetcher_->SetRequestContext(url_context_.get());
url_fetcher_->SetReferrer(config_.origin_url);
@@ -247,12 +245,10 @@ void GoogleOneShotRemoteEngine::AudioChunksEnded() {
// UploadAudioChunk requires a non-empty final buffer. So we encode a packet
// of silence in case encoder had no data already.
- std::vector<int16> samples(
- config_.audio_sample_rate * kAudioPacketIntervalMs / 1000);
- scoped_refptr<AudioChunk> dummy_chunk(
- new AudioChunk(reinterpret_cast<uint8*>(&samples[0]),
- samples.size() * sizeof(int16),
- encoder_->bits_per_sample() / 8));
+ size_t sample_count =
+ config_.audio_sample_rate * kAudioPacketIntervalMs / 1000;
+ scoped_refptr<AudioChunk> dummy_chunk(new AudioChunk(
+ sample_count * sizeof(int16), encoder_->bits_per_sample() / 8));
encoder_->Encode(*dummy_chunk.get());
encoder_->Flush();
scoped_refptr<AudioChunk> encoded_dummy_data(
diff --git a/chromium/content/browser/speech/google_streaming_remote_engine.cc b/chromium/content/browser/speech/google_streaming_remote_engine.cc
index 7fea0fa90a6..fc8c6d24254 100644
--- a/chromium/content/browser/speech/google_streaming_remote_engine.cc
+++ b/chromium/content/browser/speech/google_streaming_remote_engine.cc
@@ -4,8 +4,10 @@
#include "content/browser/speech/google_streaming_remote_engine.h"
+#include <algorithm>
#include <vector>
+#include "base/big_endian.h"
#include "base/bind.h"
#include "base/rand_util.h"
#include "base/strings/string_number_conversions.h"
@@ -81,6 +83,7 @@ GoogleStreamingRemoteEngine::GoogleStreamingRemoteEngine(
previous_response_length_(0),
got_last_definitive_result_(false),
is_dispatching_event_(false),
+ use_framed_post_data_(false),
state_(STATE_IDLE) {}
GoogleStreamingRemoteEngine::~GoogleStreamingRemoteEngine() {}
@@ -297,6 +300,18 @@ GoogleStreamingRemoteEngine::ConnectBothStreams(const FSMEventArgs&) {
DCHECK(encoder_.get());
const std::string request_key = GenerateRequestKey();
+ // Only use the framed post data format when a preamble needs to be logged.
+ use_framed_post_data_ = (config_.preamble &&
+ !config_.preamble->sample_data.empty() &&
+ !config_.auth_token.empty() &&
+ !config_.auth_scope.empty());
+ if (use_framed_post_data_) {
+ preamble_encoder_.reset(AudioEncoder::Create(
+ kDefaultAudioCodec,
+ config_.preamble->sample_rate,
+ config_.preamble->sample_depth * 8));
+ }
+
// Setup downstream fetcher.
std::vector<std::string> downstream_args;
downstream_args.push_back(
@@ -307,9 +322,8 @@ GoogleStreamingRemoteEngine::ConnectBothStreams(const FSMEventArgs&) {
std::string(kDownstreamUrl) +
JoinString(downstream_args, '&'));
- downstream_fetcher_.reset(URLFetcher::Create(
- kDownstreamUrlFetcherIdForTesting, downstream_url, URLFetcher::GET,
- this));
+ downstream_fetcher_ = URLFetcher::Create(
+ kDownstreamUrlFetcherIdForTesting, downstream_url, URLFetcher::GET, this);
downstream_fetcher_->SetRequestContext(url_context_.get());
downstream_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES |
net::LOAD_DO_NOT_SEND_COOKIES |
@@ -342,14 +356,30 @@ GoogleStreamingRemoteEngine::ConnectBothStreams(const FSMEventArgs&) {
upstream_args.push_back("continuous");
if (config_.interim_results)
upstream_args.push_back("interim");
-
+ if (!config_.auth_token.empty() && !config_.auth_scope.empty()) {
+ upstream_args.push_back(
+ "authScope=" + net::EscapeQueryParamValue(config_.auth_scope, true));
+ upstream_args.push_back(
+ "authToken=" + net::EscapeQueryParamValue(config_.auth_token, true));
+ }
+ if (use_framed_post_data_) {
+ std::string audio_format;
+ if (preamble_encoder_)
+ audio_format = preamble_encoder_->mime_type() + ",";
+ audio_format += encoder_->mime_type();
+ upstream_args.push_back(
+ "audioFormat=" + net::EscapeQueryParamValue(audio_format, true));
+ }
GURL upstream_url(std::string(kWebServiceBaseUrl) +
std::string(kUpstreamUrl) +
JoinString(upstream_args, '&'));
- upstream_fetcher_.reset(URLFetcher::Create(
- kUpstreamUrlFetcherIdForTesting, upstream_url, URLFetcher::POST, this));
- upstream_fetcher_->SetChunkedUpload(encoder_->mime_type());
+ upstream_fetcher_ = URLFetcher::Create(kUpstreamUrlFetcherIdForTesting,
+ upstream_url, URLFetcher::POST, this);
+ if (use_framed_post_data_)
+ upstream_fetcher_->SetChunkedUpload("application/octet-stream");
+ else
+ upstream_fetcher_->SetChunkedUpload(encoder_->mime_type());
upstream_fetcher_->SetRequestContext(url_context_.get());
upstream_fetcher_->SetReferrer(config_.origin_url);
upstream_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES |
@@ -357,6 +387,19 @@ GoogleStreamingRemoteEngine::ConnectBothStreams(const FSMEventArgs&) {
net::LOAD_DO_NOT_SEND_AUTH_DATA);
upstream_fetcher_->Start();
previous_response_length_ = 0;
+
+ if (preamble_encoder_) {
+ // Encode and send preamble right away.
+ scoped_refptr<AudioChunk> chunk = new AudioChunk(
+ reinterpret_cast<const uint8*>(config_.preamble->sample_data.data()),
+ config_.preamble->sample_data.size(),
+ config_.preamble->sample_depth);
+ preamble_encoder_->Encode(*chunk);
+ preamble_encoder_->Flush();
+ scoped_refptr<AudioChunk> encoded_data(
+ preamble_encoder_->GetEncodedDataAndClear());
+ UploadAudioChunk(encoded_data->AsString(), FRAME_PREAMBLE_AUDIO, false);
+ }
return STATE_BOTH_STREAMS_CONNECTED;
}
@@ -370,7 +413,7 @@ GoogleStreamingRemoteEngine::TransmitAudioUpstream(
DCHECK_EQ(audio.bytes_per_sample(), config_.audio_num_bits_per_sample / 8);
encoder_->Encode(audio);
scoped_refptr<AudioChunk> encoded_data(encoder_->GetEncodedDataAndClear());
- upstream_fetcher_->AppendChunkToUpload(encoded_data->AsString(), false);
+ UploadAudioChunk(encoded_data->AsString(), FRAME_RECOGNITION_AUDIO, false);
return state_;
}
@@ -401,20 +444,17 @@ GoogleStreamingRemoteEngine::ProcessDownstreamResponse(
case proto::SpeechRecognitionEvent::STATUS_ABORTED:
return Abort(SPEECH_RECOGNITION_ERROR_ABORTED);
case proto::SpeechRecognitionEvent::STATUS_AUDIO_CAPTURE:
- return Abort(SPEECH_RECOGNITION_ERROR_AUDIO);
+ return Abort(SPEECH_RECOGNITION_ERROR_AUDIO_CAPTURE);
case proto::SpeechRecognitionEvent::STATUS_NETWORK:
return Abort(SPEECH_RECOGNITION_ERROR_NETWORK);
case proto::SpeechRecognitionEvent::STATUS_NOT_ALLOWED:
- // TODO(hans): We need a better error code for this.
- return Abort(SPEECH_RECOGNITION_ERROR_ABORTED);
+ return Abort(SPEECH_RECOGNITION_ERROR_NOT_ALLOWED);
case proto::SpeechRecognitionEvent::STATUS_SERVICE_NOT_ALLOWED:
- // TODO(hans): We need a better error code for this.
- return Abort(SPEECH_RECOGNITION_ERROR_ABORTED);
+ return Abort(SPEECH_RECOGNITION_ERROR_SERVICE_NOT_ALLOWED);
case proto::SpeechRecognitionEvent::STATUS_BAD_GRAMMAR:
return Abort(SPEECH_RECOGNITION_ERROR_BAD_GRAMMAR);
case proto::SpeechRecognitionEvent::STATUS_LANGUAGE_NOT_SUPPORTED:
- // TODO(hans): We need a better error code for this.
- return Abort(SPEECH_RECOGNITION_ERROR_ABORTED);
+ return Abort(SPEECH_RECOGNITION_ERROR_LANGUAGE_NOT_SUPPORTED);
}
}
@@ -471,12 +511,10 @@ GoogleStreamingRemoteEngine::CloseUpstreamAndWaitForResults(
// The encoder requires a non-empty final buffer. So we encode a packet
// of silence in case encoder had no data already.
- std::vector<short> samples(
- config_.audio_sample_rate * kAudioPacketIntervalMs / 1000);
- scoped_refptr<AudioChunk> dummy_chunk =
- new AudioChunk(reinterpret_cast<uint8*>(&samples[0]),
- samples.size() * sizeof(short),
- encoder_->bits_per_sample() / 8);
+ size_t sample_count =
+ config_.audio_sample_rate * kAudioPacketIntervalMs / 1000;
+ scoped_refptr<AudioChunk> dummy_chunk = new AudioChunk(
+ sample_count * sizeof(int16), encoder_->bits_per_sample() / 8);
encoder_->Encode(*dummy_chunk.get());
encoder_->Flush();
scoped_refptr<AudioChunk> encoded_dummy_data =
@@ -484,7 +522,9 @@ GoogleStreamingRemoteEngine::CloseUpstreamAndWaitForResults(
DCHECK(!encoded_dummy_data->IsEmpty());
encoder_.reset();
- upstream_fetcher_->AppendChunkToUpload(encoded_dummy_data->AsString(), true);
+ UploadAudioChunk(encoded_dummy_data->AsString(),
+ FRAME_RECOGNITION_AUDIO,
+ true);
got_last_definitive_result_ = false;
return STATE_WAITING_DOWNSTREAM_RESULTS;
}
@@ -572,6 +612,20 @@ std::string GoogleStreamingRemoteEngine::GenerateRequestKey() const {
return base::HexEncode(reinterpret_cast<void*>(&key), sizeof(key));
}
+void GoogleStreamingRemoteEngine::UploadAudioChunk(const std::string& data,
+ FrameType type,
+ bool is_final) {
+ if (use_framed_post_data_) {
+ std::string frame(data.size() + 8, 0);
+ base::WriteBigEndian(&frame[0], static_cast<uint32_t>(data.size()));
+ base::WriteBigEndian(&frame[4], static_cast<uint32_t>(type));
+ frame.replace(8, data.size(), data);
+ upstream_fetcher_->AppendChunkToUpload(frame, is_final);
+ } else {
+ upstream_fetcher_->AppendChunkToUpload(data, is_final);
+ }
+}
+
GoogleStreamingRemoteEngine::FSMEventArgs::FSMEventArgs(FSMEvent event_value)
: event(event_value) {
}
diff --git a/chromium/content/browser/speech/google_streaming_remote_engine.h b/chromium/content/browser/speech/google_streaming_remote_engine.h
index 961ef0877db..15b866ba63b 100644
--- a/chromium/content/browser/speech/google_streaming_remote_engine.h
+++ b/chromium/content/browser/speech/google_streaming_remote_engine.h
@@ -79,6 +79,13 @@ class CONTENT_EXPORT GoogleStreamingRemoteEngine
static const int kWebserviceStatusNoError;
static const int kWebserviceStatusErrorNoMatch;
+ // Frame type for framed POST data. Do NOT change these. They must match
+ // values the server expects.
+ enum FrameType {
+ FRAME_PREAMBLE_AUDIO = 0,
+ FRAME_RECOGNITION_AUDIO = 1
+ };
+
// Data types for the internal Finite State Machine (FSM).
enum FSMState {
STATE_IDLE = 0,
@@ -143,15 +150,21 @@ class CONTENT_EXPORT GoogleStreamingRemoteEngine
std::string GetAcceptedLanguages() const;
std::string GenerateRequestKey() const;
+ // Upload a single chunk of audio data. Handles both unframed and framed
+ // upload formats, and uses the appropriate one.
+ void UploadAudioChunk(const std::string& data, FrameType type, bool is_final);
+
SpeechRecognitionEngineConfig config_;
scoped_ptr<net::URLFetcher> upstream_fetcher_;
scoped_ptr<net::URLFetcher> downstream_fetcher_;
scoped_refptr<net::URLRequestContextGetter> url_context_;
scoped_ptr<AudioEncoder> encoder_;
+ scoped_ptr<AudioEncoder> preamble_encoder_;
ChunkedByteBuffer chunked_byte_buffer_;
size_t previous_response_length_;
bool got_last_definitive_result_;
bool is_dispatching_event_;
+ bool use_framed_post_data_;
FSMState state_;
DISALLOW_COPY_AND_ASSIGN(GoogleStreamingRemoteEngine);
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 57947e61e5d..c3d7ce5c4e1 100644
--- a/chromium/content/browser/speech/google_streaming_remote_engine_unittest.cc
+++ b/chromium/content/browser/speech/google_streaming_remote_engine_unittest.cc
@@ -4,6 +4,7 @@
#include <queue>
+#include "base/big_endian.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/numerics/safe_conversions.h"
@@ -27,6 +28,10 @@ using net::TestURLFetcherFactory;
namespace content {
+// Frame types for framed POST data.
+static const uint32_t kFrameTypePreamble = 0;
+static const uint32_t kFrameTypeRecognitionAudio = 1;
+
// Note: the terms upstream and downstream are from the point-of-view of the
// client (engine_under_test_).
@@ -73,10 +78,12 @@ class GoogleStreamingRemoteEngineTest : public SpeechRecognitionEngineDelegate,
void EndMockRecognition();
void InjectDummyAudioChunk();
size_t UpstreamChunksUploadedFromLastCall();
+ std::string LastUpstreamChunkUploaded();
void ProvideMockProtoResultDownstream(
const proto::SpeechRecognitionEvent& result);
void ProvideMockResultDownstream(const SpeechRecognitionResult& result);
void ExpectResultsReceived(const SpeechRecognitionResults& result);
+ void ExpectFramedChunk(const std::string& chunk, uint32_t type);
void CloseMockDownstream(DownstreamError error);
scoped_ptr<GoogleStreamingRemoteEngine> engine_under_test_;
@@ -325,6 +332,56 @@ TEST_F(GoogleStreamingRemoteEngineTest, Stability) {
ASSERT_EQ(0U, results_.size());
}
+TEST_F(GoogleStreamingRemoteEngineTest, SendPreamble) {
+ const size_t kPreambleLength = 100;
+ scoped_refptr<SpeechRecognitionSessionPreamble> preamble =
+ new SpeechRecognitionSessionPreamble();
+ preamble->sample_rate = 16000;
+ preamble->sample_depth = 2;
+ preamble->sample_data.assign(kPreambleLength, 0);
+ SpeechRecognitionEngine::Config config;
+ config.auth_token = "foo";
+ config.auth_scope = "bar";
+ config.preamble = preamble;
+ engine_under_test_->SetConfig(config);
+
+ StartMockRecognition();
+ ASSERT_TRUE(GetUpstreamFetcher());
+ // First chunk uploaded should be the preamble.
+ ASSERT_EQ(1U, UpstreamChunksUploadedFromLastCall());
+ std::string chunk = LastUpstreamChunkUploaded();
+ ExpectFramedChunk(chunk, kFrameTypePreamble);
+
+ for (int i = 0; i < 3; ++i) {
+ InjectDummyAudioChunk();
+ ASSERT_EQ(1U, UpstreamChunksUploadedFromLastCall());
+ chunk = LastUpstreamChunkUploaded();
+ ExpectFramedChunk(chunk, kFrameTypeRecognitionAudio);
+ }
+ engine_under_test_->AudioChunksEnded();
+ ASSERT_TRUE(engine_under_test_->IsRecognitionPending());
+
+ // Simulate a protobuf message streamed from the server containing a single
+ // result with one hypotheses.
+ SpeechRecognitionResults results;
+ results.push_back(SpeechRecognitionResult());
+ SpeechRecognitionResult& result = results.back();
+ result.is_provisional = false;
+ result.hypotheses.push_back(
+ SpeechRecognitionHypothesis(base::UTF8ToUTF16("hypothesis 1"), 0.1F));
+
+ ProvideMockResultDownstream(result);
+ ExpectResultsReceived(results);
+ ASSERT_TRUE(engine_under_test_->IsRecognitionPending());
+
+ // Ensure everything is closed cleanly after the downstream is closed.
+ CloseMockDownstream(DOWNSTREAM_ERROR_NONE);
+ ASSERT_FALSE(engine_under_test_->IsRecognitionPending());
+ EndMockRecognition();
+ ASSERT_EQ(SPEECH_RECOGNITION_ERROR_NONE, error_);
+ ASSERT_EQ(0U, results_.size());
+}
+
void GoogleStreamingRemoteEngineTest::SetUp() {
engine_under_test_.reset(
new GoogleStreamingRemoteEngine(NULL /*URLRequestContextGetter*/));
@@ -397,6 +454,13 @@ size_t GoogleStreamingRemoteEngineTest::UpstreamChunksUploadedFromLastCall() {
return new_chunks;
}
+std::string GoogleStreamingRemoteEngineTest::LastUpstreamChunkUploaded() {
+ TestURLFetcher* upstream_fetcher = GetUpstreamFetcher();
+ DCHECK(upstream_fetcher);
+ DCHECK(!upstream_fetcher->upload_chunks().empty());
+ return upstream_fetcher->upload_chunks().back();
+}
+
void GoogleStreamingRemoteEngineTest::ProvideMockProtoResultDownstream(
const proto::SpeechRecognitionEvent& result) {
TestURLFetcher* downstream_fetcher = GetDownstreamFetcher();
@@ -483,6 +547,15 @@ bool GoogleStreamingRemoteEngineTest::ResultsAreEqual(
return true;
}
+void GoogleStreamingRemoteEngineTest::ExpectFramedChunk(
+ const std::string& chunk, uint32_t type) {
+ uint32_t value;
+ base::ReadBigEndian(&chunk[0], &value);
+ EXPECT_EQ(chunk.size() - 8, value);
+ base::ReadBigEndian(&chunk[4], &value);
+ EXPECT_EQ(type, value);
+}
+
std::string GoogleStreamingRemoteEngineTest::SerializeProtobufResponse(
const proto::SpeechRecognitionEvent& msg) {
std::string msg_string;
diff --git a/chromium/content/browser/speech/speech_recognition_browsertest.cc b/chromium/content/browser/speech/speech_recognition_browsertest.cc
index 02671a4786f..8bc0749f40e 100644
--- a/chromium/content/browser/speech/speech_recognition_browsertest.cc
+++ b/chromium/content/browser/speech/speech_recognition_browsertest.cc
@@ -94,7 +94,7 @@ class SpeechRecognitionBrowserTest :
}
std::string GetPageFragment() {
- return shell()->web_contents()->GetURL().ref();
+ return shell()->web_contents()->GetLastCommittedURL().ref();
}
const StreamingServerState &streaming_server_state() {
@@ -188,13 +188,8 @@ 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.
-// 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) {
+// Flaky on all platforms. http://crbug.com/396414.
+IN_PROC_BROWSER_TEST_F(SpeechRecognitionBrowserTest, DISABLED_Precheck) {
NavigateToURLBlockUntilNavigationsComplete(
shell(), GetTestUrlFromFragment("precheck"), 2);
diff --git a/chromium/content/browser/speech/speech_recognition_engine.h b/chromium/content/browser/speech/speech_recognition_engine.h
index 73ba26ec7e5..4f945b510ec 100644
--- a/chromium/content/browser/speech/speech_recognition_engine.h
+++ b/chromium/content/browser/speech/speech_recognition_engine.h
@@ -9,6 +9,7 @@
#include "base/basictypes.h"
#include "content/common/content_export.h"
+#include "content/public/browser/speech_recognition_session_preamble.h"
#include "content/public/common/speech_recognition_grammar.h"
#include "content/public/common/speech_recognition_result.h"
@@ -59,6 +60,9 @@ class SpeechRecognitionEngine {
std::string origin_url;
int audio_sample_rate;
int audio_num_bits_per_sample;
+ std::string auth_token;
+ std::string auth_scope;
+ scoped_refptr<SpeechRecognitionSessionPreamble> preamble;
};
virtual ~SpeechRecognitionEngine() {}
diff --git a/chromium/content/browser/speech/speech_recognition_manager_impl.cc b/chromium/content/browser/speech/speech_recognition_manager_impl.cc
index 1a054204c44..f02c29f1dd4 100644
--- a/chromium/content/browser/speech/speech_recognition_manager_impl.cc
+++ b/chromium/content/browser/speech/speech_recognition_manager_impl.cc
@@ -39,7 +39,7 @@ namespace {
SpeechRecognitionManagerImpl* g_speech_recognition_manager_impl;
void ShowAudioInputSettingsOnFileThread(media::AudioManager* audio_manager) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
audio_manager->ShowAudioInputSettings();
}
@@ -69,7 +69,7 @@ SpeechRecognitionManagerImpl::SpeechRecognitionManagerImpl(
last_session_id_(kSessionIDInvalid),
is_dispatching_event_(false),
delegate_(GetContentClient()->browser()->
- GetSpeechRecognitionManagerDelegate()),
+ CreateSpeechRecognitionManagerDelegate()),
weak_factory_(this) {
DCHECK(!g_speech_recognition_manager_impl);
g_speech_recognition_manager_impl = this;
@@ -91,7 +91,7 @@ SpeechRecognitionManagerImpl::~SpeechRecognitionManagerImpl() {
int SpeechRecognitionManagerImpl::CreateSession(
const SpeechRecognitionSessionConfig& config) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
const int session_id = GetNextSessionID();
DCHECK(!SessionExists(session_id));
@@ -132,6 +132,9 @@ int SpeechRecognitionManagerImpl::CreateSession(
remote_engine_config.hardware_info = hardware_info;
remote_engine_config.origin_url =
can_report_metrics ? config.origin_url : std::string();
+ remote_engine_config.auth_token = config.auth_token;
+ remote_engine_config.auth_scope = config.auth_scope;
+ remote_engine_config.preamble = config.preamble;
SpeechRecognitionEngine* google_remote_engine;
if (config.is_legacy_api) {
@@ -157,7 +160,7 @@ int SpeechRecognitionManagerImpl::CreateSession(
}
void SpeechRecognitionManagerImpl::StartSession(int session_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!SessionExists(session_id))
return;
@@ -181,7 +184,7 @@ void SpeechRecognitionManagerImpl::StartSession(int session_id) {
void SpeechRecognitionManagerImpl::RecognitionAllowedCallback(int session_id,
bool ask_user,
bool is_allowed) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!SessionExists(session_id))
return;
@@ -229,7 +232,7 @@ void SpeechRecognitionManagerImpl::MediaRequestPermissionCallback(
int session_id,
const MediaStreamDevices& devices,
scoped_ptr<MediaStreamUIProxy> stream_ui) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
SessionsTable::iterator iter = sessions_.find(session_id);
if (iter == sessions_.end())
@@ -252,7 +255,7 @@ void SpeechRecognitionManagerImpl::MediaRequestPermissionCallback(
}
void SpeechRecognitionManagerImpl::AbortSession(int session_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!SessionExists(session_id))
return;
@@ -273,7 +276,7 @@ void SpeechRecognitionManagerImpl::AbortSession(int session_id) {
}
void SpeechRecognitionManagerImpl::StopAudioCaptureForSession(int session_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!SessionExists(session_id))
return;
@@ -294,7 +297,7 @@ void SpeechRecognitionManagerImpl::StopAudioCaptureForSession(int session_id) {
// (if any).
void SpeechRecognitionManagerImpl::OnRecognitionStart(int session_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!SessionExists(session_id))
return;
@@ -313,7 +316,7 @@ void SpeechRecognitionManagerImpl::OnRecognitionStart(int session_id) {
}
void SpeechRecognitionManagerImpl::OnAudioStart(int session_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!SessionExists(session_id))
return;
@@ -326,7 +329,7 @@ void SpeechRecognitionManagerImpl::OnAudioStart(int session_id) {
void SpeechRecognitionManagerImpl::OnEnvironmentEstimationComplete(
int session_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!SessionExists(session_id))
return;
@@ -338,7 +341,7 @@ void SpeechRecognitionManagerImpl::OnEnvironmentEstimationComplete(
}
void SpeechRecognitionManagerImpl::OnSoundStart(int session_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!SessionExists(session_id))
return;
@@ -350,7 +353,7 @@ void SpeechRecognitionManagerImpl::OnSoundStart(int session_id) {
}
void SpeechRecognitionManagerImpl::OnSoundEnd(int session_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!SessionExists(session_id))
return;
@@ -361,7 +364,7 @@ void SpeechRecognitionManagerImpl::OnSoundEnd(int session_id) {
}
void SpeechRecognitionManagerImpl::OnAudioEnd(int session_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!SessionExists(session_id))
return;
@@ -379,7 +382,7 @@ void SpeechRecognitionManagerImpl::OnAudioEnd(int session_id) {
void SpeechRecognitionManagerImpl::OnRecognitionResults(
int session_id, const SpeechRecognitionResults& results) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!SessionExists(session_id))
return;
@@ -391,7 +394,7 @@ void SpeechRecognitionManagerImpl::OnRecognitionResults(
void SpeechRecognitionManagerImpl::OnRecognitionError(
int session_id, const SpeechRecognitionError& error) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!SessionExists(session_id))
return;
@@ -403,7 +406,7 @@ void SpeechRecognitionManagerImpl::OnRecognitionError(
void SpeechRecognitionManagerImpl::OnAudioLevelsChange(
int session_id, float volume, float noise_volume) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!SessionExists(session_id))
return;
@@ -414,7 +417,7 @@ void SpeechRecognitionManagerImpl::OnAudioLevelsChange(
}
void SpeechRecognitionManagerImpl::OnRecognitionEnd(int session_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!SessionExists(session_id))
return;
@@ -432,9 +435,9 @@ void SpeechRecognitionManagerImpl::OnRecognitionEnd(int session_id) {
int SpeechRecognitionManagerImpl::GetSession(
int render_process_id, int render_view_id, int request_id) const {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
SessionsTable::const_iterator iter;
- for(iter = sessions_.begin(); iter != sessions_.end(); ++iter) {
+ for (iter = sessions_.begin(); iter != sessions_.end(); ++iter) {
const int session_id = iter->first;
const SpeechRecognitionSessionContext& context = iter->second->context;
if (context.render_process_id == render_process_id &&
@@ -456,7 +459,7 @@ void SpeechRecognitionManagerImpl::AbortAllSessionsForRenderProcess(
// This method gracefully destroys sessions for the listener. However, since
// the listener itself is likely to be destroyed after this call, we avoid
// dispatching further events to it, marking the |listener_is_active| flag.
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
for (SessionsTable::iterator it = sessions_.begin(); it != sessions_.end();
++it) {
Session* session = it->second;
@@ -470,7 +473,7 @@ void SpeechRecognitionManagerImpl::AbortAllSessionsForRenderProcess(
void SpeechRecognitionManagerImpl::AbortAllSessionsForRenderView(
int render_process_id,
int render_view_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
for (SessionsTable::iterator it = sessions_.begin(); it != sessions_.end();
++it) {
Session* session = it->second;
@@ -484,7 +487,7 @@ void SpeechRecognitionManagerImpl::AbortAllSessionsForRenderView(
// ----------------------- Core FSM implementation ---------------------------
void SpeechRecognitionManagerImpl::DispatchEvent(int session_id,
FSMEvent event) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
// There are some corner cases in which the session might be deleted (due to
// an EndRecognition event) between a request (e.g. Abort) and its dispatch.
@@ -648,7 +651,7 @@ bool SpeechRecognitionManagerImpl::SessionExists(int session_id) const {
SpeechRecognitionManagerImpl::Session*
SpeechRecognitionManagerImpl::GetSession(int session_id) const {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
SessionsTable::const_iterator iter = sessions_.find(session_id);
DCHECK(iter != sessions_.end());
return iter->second;
diff --git a/chromium/content/browser/speech/speech_recognizer_impl.cc b/chromium/content/browser/speech/speech_recognizer_impl.cc
index f6fb3900a5e..a08ffe17661 100644
--- a/chromium/content/browser/speech/speech_recognizer_impl.cc
+++ b/chromium/content/browser/speech/speech_recognizer_impl.cc
@@ -13,7 +13,6 @@
#include "content/browser/speech/google_one_shot_remote_engine.h"
#include "content/public/browser/speech_recognition_event_listener.h"
#include "media/base/audio_converter.h"
-#include "net/url_request/url_request_context_getter.h"
#if defined(OS_WIN)
#include "media/audio/win/core_audio_util_win.h"
@@ -56,7 +55,6 @@ class SpeechRecognizerImpl::OnDataConverter
const AudioParameters input_parameters_;
const AudioParameters output_parameters_;
bool waiting_for_input_;
- scoped_ptr<uint8[]> converted_data_;
DISALLOW_COPY_AND_ASSIGN(OnDataConverter);
};
@@ -108,20 +106,20 @@ const int SpeechRecognizerImpl::kNoSpeechTimeoutMs = 8000;
const int SpeechRecognizerImpl::kEndpointerEstimationTimeMs = 300;
media::AudioManager* SpeechRecognizerImpl::audio_manager_for_tests_ = NULL;
-COMPILE_ASSERT(SpeechRecognizerImpl::kNumBitsPerAudioSample % 8 == 0,
- kNumBitsPerAudioSample_must_be_a_multiple_of_8);
+static_assert(SpeechRecognizerImpl::kNumBitsPerAudioSample % 8 == 0,
+ "kNumBitsPerAudioSample must be a multiple of 8");
// SpeechRecognizerImpl::OnDataConverter implementation
SpeechRecognizerImpl::OnDataConverter::OnDataConverter(
- const AudioParameters& input_params, const AudioParameters& output_params)
+ const AudioParameters& input_params,
+ const AudioParameters& output_params)
: audio_converter_(input_params, output_params, false),
input_bus_(AudioBus::Create(input_params)),
output_bus_(AudioBus::Create(output_params)),
input_parameters_(input_params),
output_parameters_(output_params),
- waiting_for_input_(false),
- converted_data_(new uint8[output_parameters_.GetBytesPerBuffer()]) {
+ waiting_for_input_(false) {
audio_converter_.AddInput(this);
}
@@ -140,16 +138,13 @@ scoped_refptr<AudioChunk> SpeechRecognizerImpl::OnDataConverter::Convert(
waiting_for_input_ = true;
audio_converter_.Convert(output_bus_.get());
- output_bus_->ToInterleaved(
- output_bus_->frames(), output_parameters_.bits_per_sample() / 8,
- converted_data_.get());
-
- // TODO(primiano): Refactor AudioChunk to avoid the extra-copy here
- // (see http://crbug.com/249316 for details).
- return scoped_refptr<AudioChunk>(new AudioChunk(
- converted_data_.get(),
- output_parameters_.GetBytesPerBuffer(),
- output_parameters_.bits_per_sample() / 8));
+ scoped_refptr<AudioChunk> chunk(
+ new AudioChunk(output_parameters_.GetBytesPerBuffer(),
+ output_parameters_.bits_per_sample() / 8));
+ output_bus_->ToInterleaved(output_bus_->frames(),
+ output_parameters_.bits_per_sample() / 8,
+ chunk->writable_data());
+ return chunk;
}
double SpeechRecognizerImpl::OnDataConverter::ProvideInput(
@@ -236,12 +231,12 @@ void SpeechRecognizerImpl::StopAudioCapture() {
bool SpeechRecognizerImpl::IsActive() const {
// Checking the FSM state from another thread (thus, while the FSM is
// potentially concurrently evolving) is meaningless.
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
return state_ != STATE_IDLE && state_ != STATE_ENDED;
}
bool SpeechRecognizerImpl::IsCapturingAudio() const {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); // See IsActive().
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); // See IsActive().
const bool is_capturing_audio = state_ >= STATE_STARTING &&
state_ <= STATE_RECOGNIZING;
DCHECK((is_capturing_audio && (audio_controller_.get() != NULL)) ||
@@ -255,7 +250,7 @@ SpeechRecognizerImpl::recognition_engine() const {
}
SpeechRecognizerImpl::~SpeechRecognizerImpl() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
endpointer_.EndSession();
if (audio_controller_.get()) {
audio_controller_->Close(
@@ -317,7 +312,7 @@ void SpeechRecognizerImpl::OnSpeechRecognitionEngineError(
// does, but they will become flaky if TestAudioInputController will be fixed.
void SpeechRecognizerImpl::DispatchEvent(const FSMEventArgs& event_args) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK_LE(event_args.event, EVENT_MAX_VALUE);
DCHECK_LE(state_, STATE_MAX_VALUE);
@@ -508,7 +503,7 @@ SpeechRecognizerImpl::StartRecording(const FSMEventArgs&) {
// TODO(xians): Check if the OS has the device with |device_id_|, return
// |SPEECH_AUDIO_ERROR_DETAILS_NO_MIC| if the target device does not exist.
if (!audio_manager->HasAudioInputDevices()) {
- return Abort(SpeechRecognitionError(SPEECH_RECOGNITION_ERROR_AUDIO,
+ return Abort(SpeechRecognitionError(SPEECH_RECOGNITION_ERROR_AUDIO_CAPTURE,
SPEECH_AUDIO_ERROR_DETAILS_NO_MIC));
}
@@ -518,7 +513,8 @@ SpeechRecognizerImpl::StartRecording(const FSMEventArgs&) {
device_id_);
if (!in_params.IsValid() && !unit_test_is_active) {
DLOG(ERROR) << "Invalid native audio input parameters";
- return Abort(SpeechRecognitionError(SPEECH_RECOGNITION_ERROR_AUDIO));
+ return Abort(
+ SpeechRecognitionError(SPEECH_RECOGNITION_ERROR_AUDIO_CAPTURE));
}
// Audio converter shall provide audio based on these parameters as output.
@@ -569,7 +565,8 @@ SpeechRecognizerImpl::StartRecording(const FSMEventArgs&) {
audio_manager, this, input_parameters, device_id_, NULL);
if (!audio_controller_.get()) {
- return Abort(SpeechRecognitionError(SPEECH_RECOGNITION_ERROR_AUDIO));
+ return Abort(
+ SpeechRecognitionError(SPEECH_RECOGNITION_ERROR_AUDIO_CAPTURE));
}
audio_log_->OnCreated(0, input_parameters, device_id_);
@@ -654,7 +651,8 @@ SpeechRecognizerImpl::AbortSilently(const FSMEventArgs& event_args) {
SpeechRecognizerImpl::FSMState
SpeechRecognizerImpl::AbortWithError(const FSMEventArgs& event_args) {
if (event_args.event == EVENT_AUDIO_ERROR) {
- return Abort(SpeechRecognitionError(SPEECH_RECOGNITION_ERROR_AUDIO));
+ return Abort(
+ SpeechRecognitionError(SPEECH_RECOGNITION_ERROR_AUDIO_CAPTURE));
} else if (event_args.event == EVENT_ENGINE_ERROR) {
return Abort(event_args.engine_error);
}
diff --git a/chromium/content/browser/speech/speech_recognizer_impl_android.cc b/chromium/content/browser/speech/speech_recognizer_impl_android.cc
index 2e8c57e87b2..0a43def06b3 100644
--- a/chromium/content/browser/speech/speech_recognizer_impl_android.cc
+++ b/chromium/content/browser/speech/speech_recognizer_impl_android.cc
@@ -37,7 +37,7 @@ SpeechRecognizerImplAndroid::~SpeechRecognizerImplAndroid() { }
void SpeechRecognizerImplAndroid::StartRecognition(
const std::string& device_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
// TODO(xians): Open the correct device for speech on Android.
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
&SpeechRecognitionEventListener::OnRecognitionStart,
@@ -52,7 +52,7 @@ void SpeechRecognizerImplAndroid::StartRecognition(
void SpeechRecognizerImplAndroid::StartRecognitionOnUIThread(
std::string language, bool continuous, bool interim_results) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
JNIEnv* env = AttachCurrentThread();
j_recognition_.Reset(Java_SpeechRecognition_createSpeechRecognition(env,
GetApplicationContext(), reinterpret_cast<intptr_t>(this)));
@@ -68,7 +68,7 @@ void SpeechRecognizerImplAndroid::AbortRecognition() {
&content::SpeechRecognizerImplAndroid::AbortRecognition, this));
return;
}
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
JNIEnv* env = AttachCurrentThread();
if (!j_recognition_.is_null())
Java_SpeechRecognition_abortRecognition(env, j_recognition_.obj());
@@ -80,19 +80,19 @@ void SpeechRecognizerImplAndroid::StopAudioCapture() {
&content::SpeechRecognizerImplAndroid::StopAudioCapture, this));
return;
}
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
JNIEnv* env = AttachCurrentThread();
if (!j_recognition_.is_null())
Java_SpeechRecognition_stopRecognition(env, j_recognition_.obj());
}
bool SpeechRecognizerImplAndroid::IsActive() const {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
return state_ != STATE_IDLE;
}
bool SpeechRecognizerImplAndroid::IsCapturingAudio() const {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
return state_ == STATE_CAPTURING_AUDIO;
}
@@ -103,7 +103,7 @@ void SpeechRecognizerImplAndroid::OnAudioStart(JNIEnv* env, jobject obj) {
static_cast<JNIEnv*>(NULL), static_cast<jobject>(NULL)));
return;
}
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
state_ = STATE_CAPTURING_AUDIO;
listener()->OnAudioStart(session_id());
}
@@ -115,7 +115,7 @@ void SpeechRecognizerImplAndroid::OnSoundStart(JNIEnv* env, jobject obj) {
static_cast<JNIEnv*>(NULL), static_cast<jobject>(NULL)));
return;
}
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
listener()->OnSoundStart(session_id());
}
@@ -126,7 +126,7 @@ void SpeechRecognizerImplAndroid::OnSoundEnd(JNIEnv* env, jobject obj) {
static_cast<JNIEnv*>(NULL), static_cast<jobject>(NULL)));
return;
}
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
listener()->OnSoundEnd(session_id());
}
@@ -137,7 +137,7 @@ void SpeechRecognizerImplAndroid::OnAudioEnd(JNIEnv* env, jobject obj) {
static_cast<JNIEnv*>(NULL), static_cast<jobject>(NULL)));
return;
}
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (state_ == STATE_CAPTURING_AUDIO)
state_ = STATE_AWAITING_FINAL_RESULT;
listener()->OnAudioEnd(session_id());
@@ -145,7 +145,7 @@ void SpeechRecognizerImplAndroid::OnAudioEnd(JNIEnv* env, jobject obj) {
void SpeechRecognizerImplAndroid::OnRecognitionResults(JNIEnv* env, jobject obj,
jobjectArray strings, jfloatArray floats, jboolean provisional) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
std::vector<base::string16> options;
AppendJavaStringArrayToStringVector(env, strings, &options);
std::vector<float> scores(options.size(), 0.0);
@@ -167,7 +167,7 @@ void SpeechRecognizerImplAndroid::OnRecognitionResults(JNIEnv* env, jobject obj,
void SpeechRecognizerImplAndroid::OnRecognitionResultsOnIOThread(
SpeechRecognitionResults const &results) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
listener()->OnRecognitionResults(session_id(), results);
}
@@ -179,7 +179,7 @@ void SpeechRecognizerImplAndroid::OnRecognitionError(JNIEnv* env,
static_cast<JNIEnv*>(NULL), static_cast<jobject>(NULL), error));
return;
}
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
SpeechRecognitionErrorCode code =
static_cast<SpeechRecognitionErrorCode>(error);
listener()->OnRecognitionError(session_id(), SpeechRecognitionError(code));
@@ -193,7 +193,7 @@ void SpeechRecognizerImplAndroid::OnRecognitionEnd(JNIEnv* env,
static_cast<JNIEnv*>(NULL), static_cast<jobject>(NULL)));
return;
}
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
state_ = STATE_IDLE;
listener()->OnRecognitionEnd(session_id());
}
diff --git a/chromium/content/browser/speech/speech_recognizer_impl_android.h b/chromium/content/browser/speech/speech_recognizer_impl_android.h
index cdf0b4db6d8..11895c441fe 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;
+ void StartRecognition(const std::string& device_id) override;
+ void AbortRecognition() override;
+ void StopAudioCapture() override;
+ bool IsActive() const override;
+ bool IsCapturingAudio() const override;
// Called from Java methods via JNI.
void OnAudioStart(JNIEnv* env, jobject obj);
@@ -53,7 +53,7 @@ class CONTENT_EXPORT SpeechRecognizerImplAndroid : public SpeechRecognizer {
std::string language, bool continuous, bool interim_results);
void OnRecognitionResultsOnIOThread(SpeechRecognitionResults const &results);
- virtual ~SpeechRecognizerImplAndroid();
+ ~SpeechRecognizerImplAndroid() override;
base::android::ScopedJavaGlobalRef<jobject> j_recognition_;
State state_;
diff --git a/chromium/content/browser/speech/speech_recognizer_impl_unittest.cc b/chromium/content/browser/speech/speech_recognizer_impl_unittest.cc
index 7168fb64973..3e8ef284287 100644
--- a/chromium/content/browser/speech/speech_recognizer_impl_unittest.cc
+++ b/chromium/content/browser/speech/speech_recognizer_impl_unittest.cc
@@ -380,7 +380,7 @@ TEST_F(SpeechRecognizerImplTest, AudioControllerErrorNoData) {
EXPECT_TRUE(recognition_started_);
EXPECT_FALSE(audio_started_);
EXPECT_FALSE(result_received_);
- EXPECT_EQ(SPEECH_RECOGNITION_ERROR_AUDIO, error_);
+ EXPECT_EQ(SPEECH_RECOGNITION_ERROR_AUDIO_CAPTURE, error_);
CheckFinalEventsConsistency();
}
@@ -400,7 +400,7 @@ TEST_F(SpeechRecognizerImplTest, AudioControllerErrorWithData) {
EXPECT_TRUE(recognition_started_);
EXPECT_TRUE(audio_started_);
EXPECT_FALSE(result_received_);
- EXPECT_EQ(SPEECH_RECOGNITION_ERROR_AUDIO, error_);
+ EXPECT_EQ(SPEECH_RECOGNITION_ERROR_AUDIO_CAPTURE, error_);
CheckFinalEventsConsistency();
}
diff --git a/chromium/content/browser/ssl/OWNERS b/chromium/content/browser/ssl/OWNERS
index cf00f7132d6..56ac0aaa068 100644
--- a/chromium/content/browser/ssl/OWNERS
+++ b/chromium/content/browser/ssl/OWNERS
@@ -1 +1,4 @@
-abarth@chromium.org
+agl@chromium.org
+felt@chromium.org
+palmer@chromium.org
+rsleevi@chromium.org
diff --git a/chromium/content/browser/ssl/ssl_client_auth_handler.cc b/chromium/content/browser/ssl/ssl_client_auth_handler.cc
index 8cab2c75229..e52864398b9 100644
--- a/chromium/content/browser/ssl/ssl_client_auth_handler.cc
+++ b/chromium/content/browser/ssl/ssl_client_auth_handler.cc
@@ -6,9 +6,12 @@
#include "base/bind.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/client_certificate_delegate.h"
#include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/resource_request_info.h"
+#include "content/public/browser/web_contents.h"
#include "net/cert/x509_certificate.h"
#include "net/ssl/client_cert_store.h"
#include "net/url_request/url_request.h"
@@ -17,100 +20,183 @@ namespace content {
namespace {
-typedef base::Callback<void(net::X509Certificate*)> CertificateCallback;
+class ClientCertificateDelegateImpl : public ClientCertificateDelegate {
+ public:
+ explicit ClientCertificateDelegateImpl(
+ const base::WeakPtr<SSLClientAuthHandler>& handler)
+ : handler_(handler), continue_called_(false) {}
+
+ ~ClientCertificateDelegateImpl() override {
+ if (!continue_called_) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&SSLClientAuthHandler::CancelCertificateSelection,
+ handler_));
+ }
+ }
-void CertificateSelectedOnUIThread(
- const CertificateCallback& io_thread_callback,
- net::X509Certificate* cert) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ // ClientCertificateDelegate implementation:
+ void ContinueWithCertificate(net::X509Certificate* cert) override {
+ DCHECK(!continue_called_);
+ continue_called_ = true;
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&SSLClientAuthHandler::ContinueWithCertificate, handler_,
+ make_scoped_refptr(cert)));
+ }
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(io_thread_callback, make_scoped_refptr(cert)));
-}
+ private:
+ base::WeakPtr<SSLClientAuthHandler> handler_;
+ bool continue_called_;
+
+ DISALLOW_COPY_AND_ASSIGN(ClientCertificateDelegateImpl);
+};
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));
+ const base::WeakPtr<SSLClientAuthHandler>& handler) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ scoped_ptr<ClientCertificateDelegate> delegate(
+ new ClientCertificateDelegateImpl(handler));
+
+ RenderFrameHost* rfh =
+ RenderFrameHost::FromID(render_process_host_id, render_frame_host_id);
+ WebContents* web_contents = WebContents::FromRenderFrameHost(rfh);
+ if (!web_contents)
+ return;
GetContentClient()->browser()->SelectClientCertificate(
- render_process_host_id, render_frame_host_id, cert_request_info,
- base::Bind(&CertificateSelectedOnUIThread, io_thread_callback));
+ web_contents, cert_request_info, delegate.Pass());
}
} // namespace
+// A reference-counted core to allow the ClientCertStore and SSLCertRequestInfo
+// to outlive SSLClientAuthHandler if needbe.
+class SSLClientAuthHandler::Core : public base::RefCountedThreadSafe<Core> {
+ public:
+ Core(const base::WeakPtr<SSLClientAuthHandler>& handler,
+ scoped_ptr<net::ClientCertStore> client_cert_store,
+ net::SSLCertRequestInfo* cert_request_info)
+ : handler_(handler),
+ client_cert_store_(client_cert_store.Pass()),
+ cert_request_info_(cert_request_info) {}
+
+ bool has_client_cert_store() const { return client_cert_store_; }
+
+ void GetClientCerts() {
+ if (client_cert_store_) {
+ // TODO(davidben): This is still a cyclical ownership where
+ // GetClientCerts' requirement that |client_cert_store_| remains alive
+ // until the call completes is maintained by the reference held in the
+ // callback.
+ client_cert_store_->GetClientCerts(
+ *cert_request_info_, &cert_request_info_->client_certs,
+ base::Bind(&SSLClientAuthHandler::Core::DidGetClientCerts, this));
+ } else {
+ DidGetClientCerts();
+ }
+ }
+
+ private:
+ friend class base::RefCountedThreadSafe<Core>;
+
+ ~Core() {}
+
+ // Called when |client_cert_store_| is done retrieving the cert list.
+ void DidGetClientCerts() {
+ if (handler_)
+ handler_->DidGetClientCerts();
+ }
+
+ base::WeakPtr<SSLClientAuthHandler> handler_;
+ scoped_ptr<net::ClientCertStore> client_cert_store_;
+ scoped_refptr<net::SSLCertRequestInfo> cert_request_info_;
+};
+
SSLClientAuthHandler::SSLClientAuthHandler(
scoped_ptr<net::ClientCertStore> client_cert_store,
net::URLRequest* request,
net::SSLCertRequestInfo* cert_request_info,
- const SSLClientAuthHandler::CertificateCallback& callback)
+ SSLClientAuthHandler::Delegate* delegate)
: request_(request),
cert_request_info_(cert_request_info),
- client_cert_store_(client_cert_store.Pass()),
- callback_(callback),
+ delegate_(delegate),
weak_factory_(this) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ core_ = new Core(weak_factory_.GetWeakPtr(), client_cert_store.Pass(),
+ cert_request_info_.get());
}
SSLClientAuthHandler::~SSLClientAuthHandler() {
}
void SSLClientAuthHandler::SelectCertificate() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (client_cert_store_) {
- client_cert_store_->GetClientCerts(
- *cert_request_info_,
- &cert_request_info_->client_certs,
- base::Bind(&SSLClientAuthHandler::DidGetClientCerts,
- weak_factory_.GetWeakPtr()));
- } else {
- DidGetClientCerts();
- }
+ // |core_| will call DidGetClientCerts when done.
+ core_->GetClientCerts();
+}
+
+// static
+void SSLClientAuthHandler::ContinueWithCertificate(
+ const base::WeakPtr<SSLClientAuthHandler>& handler,
+ net::X509Certificate* cert) {
+ if (handler)
+ handler->delegate_->ContinueWithCertificate(cert);
+}
+
+// static
+void SSLClientAuthHandler::CancelCertificateSelection(
+ const base::WeakPtr<SSLClientAuthHandler>& handler) {
+ if (handler)
+ handler->delegate_->CancelCertificateSelection();
}
void SSLClientAuthHandler::DidGetClientCerts() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
// 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. Those platforms handle the cert matching before
- // showing the dialog.
- if (client_cert_store_ && cert_request_info_->client_certs.empty()) {
+ // SelectCertificateOnUIThread. This is for platforms where the client cert
+ // matching is not performed by Chrome. Those platforms handle the cert
+ // matching before showing the dialog.
+ if (core_->has_client_cert_store() &&
+ cert_request_info_->client_certs.empty()) {
// No need to query the user if there are no certs to choose from.
- CertificateSelected(NULL);
+ //
+ // TODO(davidben): The WebContents-less check on the UI thread should come
+ // before checking ClientCertStore; ClientCertStore itself should probably
+ // be handled by the embedder (https://crbug.com/394131), especially since
+ // this doesn't work on Android (https://crbug.com/345641).
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&SSLClientAuthHandler::ContinueWithCertificate,
+ weak_factory_.GetWeakPtr(),
+ scoped_refptr<net::X509Certificate>()));
return;
}
int render_process_host_id;
int render_frame_host_id;
if (!ResourceRequestInfo::ForRequest(request_)->GetAssociatedRenderFrame(
- &render_process_host_id,
- &render_frame_host_id)) {
+ &render_process_host_id, &render_frame_host_id)) {
NOTREACHED();
- CertificateSelected(NULL);
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&SSLClientAuthHandler::CancelCertificateSelection,
+ weak_factory_.GetWeakPtr()));
return;
}
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
- base::Bind(&SelectCertificateOnUIThread,
- render_process_host_id, render_frame_host_id,
- cert_request_info_,
- base::Bind(&SSLClientAuthHandler::CertificateSelected,
- weak_factory_.GetWeakPtr())));
-}
-
-void SSLClientAuthHandler::CertificateSelected(net::X509Certificate* cert) {
- VLOG(1) << this << " DoCertificateSelected " << cert;
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
- callback_.Run(cert);
- // |this| may be deleted at this point.
+ base::Bind(&SelectCertificateOnUIThread, render_process_host_id,
+ render_frame_host_id, cert_request_info_,
+ weak_factory_.GetWeakPtr()));
}
} // 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 f95e65d71bb..b9c2447c7f4 100644
--- a/chromium/content/browser/ssl/ssl_client_auth_handler.h
+++ b/chromium/content/browser/ssl/ssl_client_auth_handler.h
@@ -7,8 +7,10 @@
#include "base/basictypes.h"
#include "base/callback.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
+#include "content/common/content_export.h"
#include "content/public/browser/browser_thread.h"
#include "net/ssl/ssl_cert_request_info.h"
@@ -23,26 +25,60 @@ namespace content {
// This class handles the approval and selection of a certificate for SSL client
// 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.
+// selection is canceled and the delegate never called.
class SSLClientAuthHandler {
public:
- typedef base::Callback<void(net::X509Certificate*)> CertificateCallback;
+ // Delegate interface for SSLClientAuthHandler. Method implementations may
+ // delete the handler when called.
+ class CONTENT_EXPORT Delegate {
+ public:
+ Delegate() {}
+ // Called to continue the request with |cert|. |cert| may be nullptr.
+ virtual void ContinueWithCertificate(net::X509Certificate* cert) = 0;
+
+ // Called to cancel the certificate selection and abort the request.
+ virtual void CancelCertificateSelection() = 0;
+
+ protected:
+ virtual ~Delegate() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Delegate);
+ };
+
+ // Creates a new SSLClientAuthHandler. The caller ensures that the handler
+ // does not outlive |request| or |delegate|.
SSLClientAuthHandler(scoped_ptr<net::ClientCertStore> client_cert_store,
net::URLRequest* request,
net::SSLCertRequestInfo* cert_request_info,
- const CertificateCallback& callback);
+ Delegate* delegate);
~SSLClientAuthHandler();
// Selects a certificate and resumes the URL request with that certificate.
void SelectCertificate();
+ // Called to continue the request associated with |handler| using |cert|. This
+ // is static to avoid deleting |handler| while it is on the stack.
+ static void ContinueWithCertificate(
+ const base::WeakPtr<SSLClientAuthHandler>& handler,
+ net::X509Certificate* cert);
+
+ // Called to abort the request associated with |handler|. This is static to
+ // avoid deleting |handler| while it is on the stack.
+ static void CancelCertificateSelection(
+ const base::WeakPtr<SSLClientAuthHandler>& handler);
+
private:
- // Called when ClientCertStore is done retrieving the cert list.
+ class Core;
+
+ // Called when |core_| is done retrieving the cert list.
void DidGetClientCerts();
- // Called when the user has selected a cert.
- void CertificateSelected(net::X509Certificate* cert);
+ // A reference-counted core so the ClientCertStore may outlive
+ // SSLClientAuthHandler if the handler is destroyed while an operation on the
+ // ClientCertStore is in progress.
+ scoped_refptr<Core> core_;
// The net::URLRequest that triggered this client auth.
net::URLRequest* request_;
@@ -50,10 +86,8 @@ class SSLClientAuthHandler {
// 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_;
+ // The delegate to call back with the result.
+ Delegate* delegate_;
base::WeakPtrFactory<SSLClientAuthHandler> weak_factory_;
diff --git a/chromium/content/browser/ssl/ssl_error_handler.cc b/chromium/content/browser/ssl/ssl_error_handler.cc
index f8deb75e534..45b6dfd830c 100644
--- a/chromium/content/browser/ssl/ssl_error_handler.cc
+++ b/chromium/content/browser/ssl/ssl_error_handler.cc
@@ -56,7 +56,7 @@ SSLCertErrorHandler* SSLErrorHandler::AsSSLCertErrorHandler() {
}
void SSLErrorHandler::Dispatch() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
WebContents* web_contents = NULL;
RenderFrameHost* render_frame_host =
@@ -78,7 +78,7 @@ void SSLErrorHandler::Dispatch() {
}
void SSLErrorHandler::CancelRequest() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
// We need to complete this task on the IO thread.
BrowserThread::PostTask(
@@ -88,7 +88,7 @@ void SSLErrorHandler::CancelRequest() {
}
void SSLErrorHandler::DenyRequest() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
// We need to complete this task on the IO thread.
BrowserThread::PostTask(
@@ -99,7 +99,7 @@ void SSLErrorHandler::DenyRequest() {
}
void SSLErrorHandler::ContinueRequest() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
// We need to complete this task on the IO thread.
BrowserThread::PostTask(
@@ -108,7 +108,7 @@ void SSLErrorHandler::ContinueRequest() {
}
void SSLErrorHandler::TakeNoAction() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
// We need to complete this task on the IO thread.
BrowserThread::PostTask(
@@ -117,7 +117,7 @@ void SSLErrorHandler::TakeNoAction() {
}
void SSLErrorHandler::CompleteCancelRequest(int error) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
// It is important that we notify the net::URLRequest only once. If we try
// to notify the request twice, it may no longer exist and |this| might have
@@ -139,7 +139,7 @@ void SSLErrorHandler::CompleteCancelRequest(int error) {
}
void SSLErrorHandler::CompleteContinueRequest() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
// It is important that we notify the net::URLRequest only once. If we try to
// notify the request twice, it may no longer exist and |this| might have
@@ -157,7 +157,7 @@ void SSLErrorHandler::CompleteContinueRequest() {
}
void SSLErrorHandler::CompleteTakeNoAction() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
// It is important that we notify the net::URLRequest only once. If we try to
// notify the request twice, it may no longer exist and |this| might have
diff --git a/chromium/content/browser/ssl/ssl_manager.cc b/chromium/content/browser/ssl/ssl_manager.cc
index ccaf9cf2062..865ca6027a2 100644
--- a/chromium/content/browser/ssl/ssl_manager.cc
+++ b/chromium/content/browser/ssl/ssl_manager.cc
@@ -85,8 +85,7 @@ void SSLManager::NotifySSLInternalStateChanged(BrowserContext* context) {
for (std::set<SSLManager*>::iterator i = managers->get().begin();
i != managers->get().end(); ++i) {
- (*i)->UpdateEntry(NavigationEntryImpl::FromNavigationEntry(
- (*i)->controller()->GetLastCommittedEntry()));
+ (*i)->UpdateEntry((*i)->controller()->GetLastCommittedEntry());
}
}
@@ -112,9 +111,7 @@ SSLManager::~SSLManager() {
}
void SSLManager::DidCommitProvisionalLoad(const LoadCommittedDetails& details) {
- NavigationEntryImpl* entry =
- NavigationEntryImpl::FromNavigationEntry(
- controller_->GetLastCommittedEntry());
+ NavigationEntryImpl* entry = controller_->GetLastCommittedEntry();
if (details.is_main_frame) {
if (entry) {
@@ -148,15 +145,11 @@ void SSLManager::DidCommitProvisionalLoad(const LoadCommittedDetails& details) {
}
void SSLManager::DidDisplayInsecureContent() {
- UpdateEntry(
- NavigationEntryImpl::FromNavigationEntry(
- controller_->GetLastCommittedEntry()));
+ UpdateEntry(controller_->GetLastCommittedEntry());
}
void SSLManager::DidRunInsecureContent(const std::string& security_origin) {
- NavigationEntryImpl* navigation_entry =
- NavigationEntryImpl::FromNavigationEntry(
- controller_->GetLastCommittedEntry());
+ NavigationEntryImpl* navigation_entry = controller_->GetLastCommittedEntry();
policy()->DidRunInsecureContent(navigation_entry, security_origin);
UpdateEntry(navigation_entry);
}
diff --git a/chromium/content/browser/ssl/ssl_policy.cc b/chromium/content/browser/ssl/ssl_policy.cc
index 51ae7b2a1c8..9cb80cd3c6b 100644
--- a/chromium/content/browser/ssl/ssl_policy.cc
+++ b/chromium/content/browser/ssl/ssl_policy.cc
@@ -8,6 +8,7 @@
#include "base/bind.h"
#include "base/command_line.h"
#include "base/memory/singleton.h"
+#include "base/metrics/histogram_macros.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "content/browser/frame_host/navigation_entry_impl.h"
@@ -26,6 +27,16 @@
namespace content {
+namespace {
+
+// Events for UMA. Do not reorder or change!
+enum SSLGoodCertSeenEvent {
+ NO_PREVIOUS_EXCEPTION = 0,
+ HAD_PREVIOUS_EXCEPTION = 1,
+ SSL_GOOD_CERT_SEEN_EVENT_MAX = 2
+};
+}
+
SSLPolicy::SSLPolicy(SSLPolicyBackend* backend)
: backend_(backend) {
DCHECK(backend_);
@@ -56,6 +67,7 @@ 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:
+ case net::ERR_CERT_VALIDITY_TOO_LONG:
if (!handler->fatal())
options_mask |= OVERRIDABLE;
else
@@ -109,8 +121,20 @@ void SSLPolicy::OnRequestStarted(SSLRequestInfo* info) {
// this information back through WebKit and out some FrameLoaderClient
// methods.
- if (net::IsCertStatusError(info->ssl_cert_status()))
+ if (net::IsCertStatusError(info->ssl_cert_status())) {
backend_->HostRanInsecureContent(info->url().host(), info->child_id());
+ } else {
+ SSLGoodCertSeenEvent event = NO_PREVIOUS_EXCEPTION;
+ if (backend_->HasAllowException(info->url().host())) {
+ // If there's no certificate error, a good certificate has been seen, so
+ // clear out any exceptions that were made by the user for bad
+ // certificates.
+ backend_->RevokeUserAllowExceptions(info->url().host());
+ event = HAD_PREVIOUS_EXCEPTION;
+ }
+ UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.good_cert_seen", event,
+ SSL_GOOD_CERT_SEEN_EVENT_MAX);
+ }
}
void SSLPolicy::UpdateEntry(NavigationEntryImpl* entry,
@@ -119,7 +143,7 @@ void SSLPolicy::UpdateEntry(NavigationEntryImpl* entry,
InitializeEntryIfNeeded(entry);
- if (!entry->GetURL().SchemeIsSecure())
+ if (!entry->GetURL().SchemeIsCryptographic())
return;
if (!web_contents->DisplayedInsecureContent())
@@ -227,13 +251,14 @@ void SSLPolicy::InitializeEntryIfNeeded(NavigationEntryImpl* entry) {
if (entry->GetSSL().security_style != SECURITY_STYLE_UNKNOWN)
return;
- entry->GetSSL().security_style = entry->GetURL().SchemeIsSecure() ?
- SECURITY_STYLE_AUTHENTICATED : SECURITY_STYLE_UNAUTHENTICATED;
+ entry->GetSSL().security_style = entry->GetURL().SchemeIsCryptographic()
+ ? SECURITY_STYLE_AUTHENTICATED
+ : SECURITY_STYLE_UNAUTHENTICATED;
}
void SSLPolicy::OriginRanInsecureContent(const std::string& origin, int pid) {
GURL parsed_origin(origin);
- if (parsed_origin.SchemeIsSecure())
+ if (parsed_origin.SchemeIsCryptographic())
backend_->HostRanInsecureContent(parsed_origin.host(), pid);
}
diff --git a/chromium/content/browser/ssl/ssl_policy_backend.cc b/chromium/content/browser/ssl/ssl_policy_backend.cc
index 5c658748219..a2626dac383 100644
--- a/chromium/content/browser/ssl/ssl_policy_backend.cc
+++ b/chromium/content/browser/ssl/ssl_policy_backend.cc
@@ -31,6 +31,20 @@ bool SSLPolicyBackend::DidHostRunInsecureContent(const std::string& host,
return ssl_host_state_delegate_->DidHostRunInsecureContent(host, pid);
}
+void SSLPolicyBackend::RevokeUserAllowExceptions(const std::string& host) {
+ if (!ssl_host_state_delegate_)
+ return;
+
+ ssl_host_state_delegate_->RevokeUserAllowExceptions(host);
+}
+
+bool SSLPolicyBackend::HasAllowException(const std::string& host) {
+ if (!ssl_host_state_delegate_)
+ return false;
+
+ return ssl_host_state_delegate_->HasAllowException(host);
+}
+
void SSLPolicyBackend::AllowCertForHost(const net::X509Certificate& cert,
const std::string& host,
net::CertStatus error) {
diff --git a/chromium/content/browser/ssl/ssl_policy_backend.h b/chromium/content/browser/ssl/ssl_policy_backend.h
index 15ebe310a0e..ed50c24de29 100644
--- a/chromium/content/browser/ssl/ssl_policy_backend.h
+++ b/chromium/content/browser/ssl/ssl_policy_backend.h
@@ -27,6 +27,13 @@ class SSLPolicyBackend {
// Returns whether the specified host ran insecure content.
bool DidHostRunInsecureContent(const std::string& host, int pid) const;
+ // Revokes all allow exceptions by the user for |host|.
+ void RevokeUserAllowExceptions(const std::string& host);
+
+ // Returns true if and only if a user exception has previously been made for
+ // |host|.
+ bool HasAllowException(const std::string& host);
+
// Records that |cert| is permitted to be used for |host| in the future, for
// a specific error type.
void AllowCertForHost(const net::X509Certificate& cert,
diff --git a/chromium/content/browser/storage_partition_impl.cc b/chromium/content/browser/storage_partition_impl.cc
index d4e49f60f13..dc4f55d7037 100644
--- a/chromium/content/browser/storage_partition_impl.cc
+++ b/chromium/content/browser/storage_partition_impl.cc
@@ -4,12 +4,19 @@
#include "content/browser/storage_partition_impl.h"
+#include <set>
+#include <vector>
+
#include "base/sequenced_task_runner.h"
#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/browser/host_zoom_map_impl.h"
+#include "content/browser/navigator_connect/navigator_connect_context_impl.h"
+#include "content/browser/navigator_connect/navigator_connect_service_worker_service_factory.h"
+#include "content/browser/notifications/platform_notification_context_impl.h"
#include "content/common/dom_storage/dom_storage_types.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
@@ -47,7 +54,7 @@ void ClearCookiesOnIOThread(
const base::Time end,
const GURL& storage_origin,
const base::Closure& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
net::CookieStore* cookie_store = rq_context->
GetURLRequestContext()->cookie_store();
if (storage_origin.is_empty()) {
@@ -65,7 +72,7 @@ void ClearCookiesOnIOThread(
void CheckQuotaManagedDataDeletionStatus(size_t* deletion_task_count,
const base::Closure& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (*deletion_task_count == 0) {
delete deletion_task_count;
callback.Run();
@@ -77,7 +84,7 @@ void OnQuotaManagedOriginDeleted(const GURL& origin,
size_t* deletion_task_count,
const base::Closure& callback,
storage::QuotaStatusCode status) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK_GT(*deletion_task_count, 0u);
if (status != storage::kQuotaStatusOk) {
DLOG(ERROR) << "Couldn't remove data of type " << type << " for origin "
@@ -102,7 +109,7 @@ void ClearShaderCacheOnIOThread(const base::FilePath& path,
const base::Time begin,
const base::Time end,
const base::Closure& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
ShaderCacheFactory::GetInstance()->ClearByPath(
path, begin, end, base::Bind(&ClearedShaderCache, callback));
}
@@ -115,7 +122,7 @@ void OnLocalStorageUsageInfo(
const base::Time delete_end,
const base::Closure& callback,
const std::vector<LocalStorageUsageInfo>& infos) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
for (size_t i = 0; i < infos.size(); ++i) {
if (!origin_matcher.is_null() &&
@@ -137,7 +144,7 @@ void OnSessionStorageUsageInfo(
const StoragePartition::OriginMatcherFunction& origin_matcher,
const base::Closure& callback,
const std::vector<SessionStorageUsageInfo>& infos) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
for (size_t i = 0; i < infos.size(); ++i) {
if (!origin_matcher.is_null() &&
@@ -158,7 +165,7 @@ void ClearLocalStorageOnUIThread(
const base::Time begin,
const base::Time end,
const base::Closure& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!storage_origin.is_empty()) {
bool can_delete = origin_matcher.is_null() ||
@@ -182,7 +189,7 @@ void ClearSessionStorageOnUIThread(
const scoped_refptr<storage::SpecialStoragePolicy>& special_storage_policy,
const StoragePartition::OriginMatcherFunction& origin_matcher,
const base::Closure& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
dom_storage_context->GetSessionStorageUsage(
base::Bind(&OnSessionStorageUsageInfo, dom_storage_context,
@@ -345,7 +352,7 @@ void StoragePartitionImpl::DataDeletionHelper::ClearQuotaManagedDataOnIOThread(
const scoped_refptr<storage::SpecialStoragePolicy>& special_storage_policy,
const StoragePartition::OriginMatcherFunction& origin_matcher,
const base::Closure& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
StoragePartitionImpl::QuotaManagedDataDeletionHelper* helper =
new StoragePartitionImpl::QuotaManagedDataDeletionHelper(
@@ -358,6 +365,7 @@ void StoragePartitionImpl::DataDeletionHelper::ClearQuotaManagedDataOnIOThread(
}
StoragePartitionImpl::StoragePartitionImpl(
+ BrowserContext* browser_context,
const base::FilePath& partition_path,
storage::QuotaManager* quota_manager,
ChromeAppCacheService* appcache_service,
@@ -365,10 +373,15 @@ StoragePartitionImpl::StoragePartitionImpl(
storage::DatabaseTracker* database_tracker,
DOMStorageContextWrapper* dom_storage_context,
IndexedDBContextImpl* indexed_db_context,
+ CacheStorageContextImpl* cache_storage_context,
ServiceWorkerContextWrapper* service_worker_context,
WebRTCIdentityStore* webrtc_identity_store,
storage::SpecialStoragePolicy* special_storage_policy,
- GeofencingManager* geofencing_manager)
+ GeofencingManager* geofencing_manager,
+ HostZoomLevelContext* host_zoom_level_context,
+ NavigatorConnectContextImpl* navigator_connect_context,
+ PlatformNotificationContextImpl* platform_notification_context,
+ BackgroundSyncContextImpl* background_sync_context)
: partition_path_(partition_path),
quota_manager_(quota_manager),
appcache_service_(appcache_service),
@@ -376,13 +389,21 @@ StoragePartitionImpl::StoragePartitionImpl(
database_tracker_(database_tracker),
dom_storage_context_(dom_storage_context),
indexed_db_context_(indexed_db_context),
+ cache_storage_context_(cache_storage_context),
service_worker_context_(service_worker_context),
webrtc_identity_store_(webrtc_identity_store),
special_storage_policy_(special_storage_policy),
- geofencing_manager_(geofencing_manager) {
+ geofencing_manager_(geofencing_manager),
+ host_zoom_level_context_(host_zoom_level_context),
+ navigator_connect_context_(navigator_connect_context),
+ platform_notification_context_(platform_notification_context),
+ background_sync_context_(background_sync_context),
+ browser_context_(browser_context) {
}
StoragePartitionImpl::~StoragePartitionImpl() {
+ browser_context_ = nullptr;
+
// These message loop checks are just to avoid leaks in unittests.
if (GetDatabaseTracker() &&
BrowserThread::IsMessageLoopValid(BrowserThread::FILE)) {
@@ -401,12 +422,19 @@ StoragePartitionImpl::~StoragePartitionImpl() {
if (GetServiceWorkerContext())
GetServiceWorkerContext()->Shutdown();
+ if (GetCacheStorageContext())
+ GetCacheStorageContext()->Shutdown();
+
if (GetGeofencingManager())
GetGeofencingManager()->Shutdown();
+
+ if (GetPlatformNotificationContext())
+ GetPlatformNotificationContext()->Shutdown();
+
+ if (GetBackgroundSyncContext())
+ GetBackgroundSyncContext()->Shutdown();
}
-// TODO(ajwong): Break the direct dependency on |context|. We only
-// need 3 pieces of info from it.
StoragePartitionImpl* StoragePartitionImpl::Create(
BrowserContext* context,
bool in_memory,
@@ -460,10 +488,15 @@ StoragePartitionImpl* StoragePartitionImpl::Create(
quota_manager->proxy(),
idb_task_runner);
+ scoped_refptr<CacheStorageContextImpl> cache_storage_context =
+ new CacheStorageContextImpl(context);
+ cache_storage_context->Init(path, quota_manager->proxy(),
+ context->GetSpecialStoragePolicy());
+
scoped_refptr<ServiceWorkerContextWrapper> service_worker_context =
new ServiceWorkerContextWrapper(context);
- service_worker_context->Init(
- path, quota_manager->proxy(), context->GetSpecialStoragePolicy());
+ service_worker_context->Init(path, quota_manager->proxy(),
+ context->GetSpecialStoragePolicy());
scoped_refptr<ChromeAppCacheService> appcache_service =
new ChromeAppCacheService(quota_manager->proxy());
@@ -478,17 +511,37 @@ StoragePartitionImpl* StoragePartitionImpl::Create(
new GeofencingManager(service_worker_context);
geofencing_manager->Init();
- return new StoragePartitionImpl(partition_path,
- quota_manager.get(),
- appcache_service.get(),
- filesystem_context.get(),
- database_tracker.get(),
- dom_storage_context.get(),
- indexed_db_context.get(),
- service_worker_context.get(),
- webrtc_identity_store.get(),
- special_storage_policy.get(),
- geofencing_manager.get());
+ scoped_refptr<HostZoomLevelContext> host_zoom_level_context(
+ new HostZoomLevelContext(
+ context->CreateZoomLevelDelegate(partition_path)));
+
+ scoped_refptr<NavigatorConnectContextImpl> navigator_connect_context =
+ new NavigatorConnectContextImpl();
+ navigator_connect_context->AddFactory(make_scoped_ptr(
+ new NavigatorConnectServiceWorkerServiceFactory(service_worker_context)));
+
+ scoped_refptr<PlatformNotificationContextImpl> platform_notification_context =
+ new PlatformNotificationContextImpl(path, context,
+ service_worker_context);
+ platform_notification_context->Initialize();
+
+ scoped_refptr<BackgroundSyncContextImpl> background_sync_context =
+ new BackgroundSyncContextImpl();
+ background_sync_context->Init(service_worker_context);
+
+ StoragePartitionImpl* storage_partition = new StoragePartitionImpl(
+ context, partition_path, quota_manager.get(), appcache_service.get(),
+ filesystem_context.get(), database_tracker.get(),
+ dom_storage_context.get(), indexed_db_context.get(),
+ cache_storage_context.get(), service_worker_context.get(),
+ webrtc_identity_store.get(), special_storage_policy.get(),
+ geofencing_manager.get(), host_zoom_level_context.get(),
+ navigator_connect_context.get(), platform_notification_context.get(),
+ background_sync_context.get());
+
+ service_worker_context->set_storage_partition(storage_partition);
+
+ return storage_partition;
}
base::FilePath StoragePartitionImpl::GetPath() {
@@ -528,6 +581,10 @@ IndexedDBContextImpl* StoragePartitionImpl::GetIndexedDBContext() {
return indexed_db_context_.get();
}
+CacheStorageContextImpl* StoragePartitionImpl::GetCacheStorageContext() {
+ return cache_storage_context_.get();
+}
+
ServiceWorkerContextWrapper* StoragePartitionImpl::GetServiceWorkerContext() {
return service_worker_context_.get();
}
@@ -536,6 +593,34 @@ GeofencingManager* StoragePartitionImpl::GetGeofencingManager() {
return geofencing_manager_.get();
}
+HostZoomMap* StoragePartitionImpl::GetHostZoomMap() {
+ DCHECK(host_zoom_level_context_.get());
+ return host_zoom_level_context_->GetHostZoomMap();
+}
+
+HostZoomLevelContext* StoragePartitionImpl::GetHostZoomLevelContext() {
+ return host_zoom_level_context_.get();
+}
+
+ZoomLevelDelegate* StoragePartitionImpl::GetZoomLevelDelegate() {
+ DCHECK(host_zoom_level_context_.get());
+ return host_zoom_level_context_->GetZoomLevelDelegate();
+}
+
+NavigatorConnectContextImpl*
+StoragePartitionImpl::GetNavigatorConnectContext() {
+ return navigator_connect_context_.get();
+}
+
+PlatformNotificationContextImpl*
+StoragePartitionImpl::GetPlatformNotificationContext() {
+ return platform_notification_context_.get();
+}
+
+BackgroundSyncContextImpl* StoragePartitionImpl::GetBackgroundSyncContext() {
+ return background_sync_context_.get();
+}
+
void StoragePartitionImpl::ClearDataImpl(
uint32 remove_mask,
uint32 quota_storage_remove_mask,
@@ -545,7 +630,7 @@ void StoragePartitionImpl::ClearDataImpl(
const base::Time begin,
const base::Time end,
const base::Closure& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DataDeletionHelper* helper = new DataDeletionHelper(remove_mask,
quota_storage_remove_mask,
callback);
@@ -565,13 +650,13 @@ void StoragePartitionImpl::ClearDataImpl(
void StoragePartitionImpl::
QuotaManagedDataDeletionHelper::IncrementTaskCountOnIO() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
++task_count;
}
void StoragePartitionImpl::
QuotaManagedDataDeletionHelper::DecrementTaskCountOnIO() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK_GT(task_count, 0);
--task_count;
if (task_count)
@@ -649,7 +734,7 @@ StoragePartitionImpl::QuotaManagedDataDeletionHelper::ClearOriginsOnIOThread(
// The QuotaManager manages all storage other than cookies, LocalStorage,
// and SessionStorage. This loop wipes out most HTML5 storage for the given
// origins.
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!origins.size()) {
callback.Run();
return;
@@ -682,7 +767,7 @@ StoragePartitionImpl::QuotaManagedDataDeletionHelper::ClearOriginsOnIOThread(
}
void StoragePartitionImpl::DataDeletionHelper::IncrementTaskCountOnUI() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
++task_count;
}
@@ -799,7 +884,7 @@ void StoragePartitionImpl::ClearDataForOrigin(
const GURL& storage_origin,
net::URLRequestContextGetter* request_context_getter,
const base::Closure& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
ClearDataImpl(remove_mask,
quota_storage_remove_mask,
storage_origin,
@@ -822,10 +907,20 @@ void StoragePartitionImpl::ClearData(
origin_matcher, GetURLRequestContext(), begin, end, callback);
}
+void StoragePartitionImpl::Flush() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (GetDOMStorageContext())
+ GetDOMStorageContext()->Flush();
+}
+
WebRTCIdentityStore* StoragePartitionImpl::GetWebRTCIdentityStore() {
return webrtc_identity_store_.get();
}
+BrowserContext* StoragePartitionImpl::browser_context() const {
+ return browser_context_;
+}
+
void StoragePartitionImpl::OverrideQuotaManagerForTesting(
storage::QuotaManager* quota_manager) {
quota_manager_ = quota_manager;
diff --git a/chromium/content/browser/storage_partition_impl.h b/chromium/content/browser/storage_partition_impl.h
index 30377392100..0aeb104e046 100644
--- a/chromium/content/browser/storage_partition_impl.h
+++ b/chromium/content/browser/storage_partition_impl.h
@@ -9,9 +9,14 @@
#include "base/files/file_path.h"
#include "base/memory/ref_counted.h"
#include "content/browser/appcache/chrome_appcache_service.h"
+#include "content/browser/background_sync/background_sync_context_impl.h"
+#include "content/browser/cache_storage/cache_storage_context_impl.h"
#include "content/browser/dom_storage/dom_storage_context_wrapper.h"
+#include "content/browser/host_zoom_level_context.h"
#include "content/browser/indexed_db/indexed_db_context_impl.h"
#include "content/browser/media/webrtc_identity_store.h"
+#include "content/browser/navigator_connect/navigator_connect_context_impl.h"
+#include "content/browser/notifications/platform_notification_context_impl.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/common/content_export.h"
#include "content/public/browser/storage_partition.h"
@@ -42,8 +47,16 @@ class StoragePartitionImpl : public StoragePartition {
storage::DatabaseTracker* GetDatabaseTracker() override;
DOMStorageContextWrapper* GetDOMStorageContext() override;
IndexedDBContextImpl* GetIndexedDBContext() override;
+ // TODO(jsbell): Expose this on the public API as well. crbug.com/466371
+ CacheStorageContextImpl* GetCacheStorageContext();
ServiceWorkerContextWrapper* GetServiceWorkerContext() override;
GeofencingManager* GetGeofencingManager() override;
+ HostZoomMap* GetHostZoomMap() override;
+ HostZoomLevelContext* GetHostZoomLevelContext() override;
+ ZoomLevelDelegate* GetZoomLevelDelegate() override;
+ NavigatorConnectContextImpl* GetNavigatorConnectContext() override;
+ PlatformNotificationContextImpl* GetPlatformNotificationContext() override;
+ BackgroundSyncContextImpl* GetBackgroundSyncContext();
void ClearDataForOrigin(uint32 remove_mask,
uint32 quota_storage_remove_mask,
@@ -58,8 +71,13 @@ class StoragePartitionImpl : public StoragePartition {
const base::Time end,
const base::Closure& callback) override;
+ void Flush() override;
+
WebRTCIdentityStore* GetWebRTCIdentityStore();
+ // Can return nullptr while |this| is being destroyed.
+ BrowserContext* browser_context() const;
+
struct DataDeletionHelper;
struct QuotaManagedDataDeletionHelper;
@@ -108,6 +126,7 @@ class StoragePartitionImpl : public StoragePartition {
const base::FilePath& profile_path);
CONTENT_EXPORT StoragePartitionImpl(
+ BrowserContext* browser_context,
const base::FilePath& partition_path,
storage::QuotaManager* quota_manager,
ChromeAppCacheService* appcache_service,
@@ -115,10 +134,15 @@ class StoragePartitionImpl : public StoragePartition {
storage::DatabaseTracker* database_tracker,
DOMStorageContextWrapper* dom_storage_context,
IndexedDBContextImpl* indexed_db_context,
+ CacheStorageContextImpl* cache_storage_context,
ServiceWorkerContextWrapper* service_worker_context,
WebRTCIdentityStore* webrtc_identity_store,
storage::SpecialStoragePolicy* special_storage_policy,
- GeofencingManager* geofencing_manager);
+ GeofencingManager* geofencing_manager,
+ HostZoomLevelContext* host_zoom_level_context,
+ NavigatorConnectContextImpl* navigator_connect_context,
+ PlatformNotificationContextImpl* platform_notification_context,
+ BackgroundSyncContextImpl* background_sync_context);
void ClearDataImpl(uint32 remove_mask,
uint32 quota_storage_remove_mask,
@@ -155,10 +179,20 @@ class StoragePartitionImpl : public StoragePartition {
scoped_refptr<storage::DatabaseTracker> database_tracker_;
scoped_refptr<DOMStorageContextWrapper> dom_storage_context_;
scoped_refptr<IndexedDBContextImpl> indexed_db_context_;
+ scoped_refptr<CacheStorageContextImpl> cache_storage_context_;
scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_;
scoped_refptr<WebRTCIdentityStore> webrtc_identity_store_;
scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy_;
scoped_refptr<GeofencingManager> geofencing_manager_;
+ scoped_refptr<HostZoomLevelContext> host_zoom_level_context_;
+ scoped_refptr<NavigatorConnectContextImpl> navigator_connect_context_;
+ scoped_refptr<PlatformNotificationContextImpl> platform_notification_context_;
+ scoped_refptr<BackgroundSyncContextImpl> background_sync_context_;
+
+ // Raw pointer that should always be valid. The BrowserContext owns the
+ // StoragePartitionImplMap which then owns StoragePartitionImpl. When the
+ // BrowserContext is destroyed, |this| will be destroyed too.
+ BrowserContext* browser_context_;
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 d36968b9e28..7ba28d7c664 100644
--- a/chromium/content/browser/storage_partition_impl_map.cc
+++ b/chromium/content/browser/storage_partition_impl_map.cc
@@ -30,6 +30,8 @@
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/navigator_connect_context.h"
+#include "content/public/browser/navigator_connect_service_factory.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/common/content_constants.h"
#include "content/public/common/url_constants.h"
@@ -39,7 +41,6 @@
#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 storage::FileSystemContext;
using storage::BlobStorageContext;
@@ -437,8 +438,7 @@ StoragePartitionImpl* StoragePartitionImplMap::Get(
request_interceptors.push_back(
ServiceWorkerRequestHandler::CreateInterceptor(
browser_context_->GetResourceContext()).release());
- request_interceptors.push_back(
- AppCacheInterceptor::CreateStartInterceptor().release());
+ request_interceptors.push_back(new AppCacheInterceptor());
// These calls must happen after StoragePartitionImpl::Create().
if (partition_domain.empty()) {
@@ -462,6 +462,9 @@ StoragePartitionImpl* StoragePartitionImplMap::Get(
browser_context_->GetMediaRequestContextForStoragePartition(
partition->GetPath(), in_memory));
+ GetContentClient()->browser()->GetAdditionalNavigatorConnectServices(
+ partition->GetNavigatorConnectContext());
+
PostCreateInitialization(partition, in_memory);
return partition;
@@ -582,10 +585,9 @@ void StoragePartitionImplMap::PostCreateInitialization(
browser_context_->GetSpecialStoragePolicy())));
BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(&ServiceWorkerContextWrapper::SetBlobParametersForCache,
- partition->GetServiceWorkerContext(),
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&CacheStorageContextImpl::SetBlobParametersForCache,
+ partition->GetCacheStorageContext(),
make_scoped_refptr(partition->GetURLRequestContext()),
make_scoped_refptr(
ChromeBlobStorageContext::GetFor(browser_context_))));
diff --git a/chromium/content/browser/storage_partition_impl_map.h b/chromium/content/browser/storage_partition_impl_map.h
index 6536621e544..92427f87c41 100644
--- a/chromium/content/browser/storage_partition_impl_map.h
+++ b/chromium/content/browser/storage_partition_impl_map.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_STORAGE_PARTITION_MAP_H_
-#define CONTENT_BROWSER_STORAGE_PARTITION_MAP_H_
+#ifndef CONTENT_BROWSER_STORAGE_PARTITION_IMPL_MAP_H_
+#define CONTENT_BROWSER_STORAGE_PARTITION_IMPL_MAP_H_
#include <map>
#include <string>
@@ -131,4 +131,4 @@ class CONTENT_EXPORT StoragePartitionImplMap
} // namespace content
-#endif // CONTENT_BROWSER_STORAGE_PARTITION_MAP_H_
+#endif // CONTENT_BROWSER_STORAGE_PARTITION_IMPL_MAP_H_
diff --git a/chromium/content/browser/streams/stream.cc b/chromium/content/browser/streams/stream.cc
index 966313cc45d..fb36ad9057a 100644
--- a/chromium/content/browser/streams/stream.cc
+++ b/chromium/content/browser/streams/stream.cc
@@ -108,6 +108,12 @@ void Stream::AddData(const char* data, size_t size) {
AddData(io_buffer, size);
}
+void Stream::Flush() {
+ if (!writer_.get())
+ return;
+ writer_->Flush();
+}
+
void Stream::Finalize() {
if (!writer_.get())
return;
diff --git a/chromium/content/browser/streams/stream.h b/chromium/content/browser/streams/stream.h
index 7c938b87c47..27788b305a2 100644
--- a/chromium/content/browser/streams/stream.h
+++ b/chromium/content/browser/streams/stream.h
@@ -68,6 +68,9 @@ class CONTENT_EXPORT Stream : public base::RefCountedThreadSafe<Stream> {
// of the data, and then passes it to |writer_|.
void AddData(const char* data, size_t size);
+ // Flushes contents buffered in the stream to the corresponding reader.
+ void Flush();
+
// Notifies this stream that it will not be receiving any more data.
void Finalize();
diff --git a/chromium/content/browser/streams/stream_context.cc b/chromium/content/browser/streams/stream_context.cc
index 357e68cae58..e338396ca33 100644
--- a/chromium/content/browser/streams/stream_context.cc
+++ b/chromium/content/browser/streams/stream_context.cc
@@ -36,7 +36,7 @@ StreamContext* StreamContext::GetFor(BrowserContext* context) {
}
void StreamContext::InitializeOnIOThread() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
registry_.reset(new StreamRegistry());
}
diff --git a/chromium/content/browser/streams/stream_register_observer.h b/chromium/content/browser/streams/stream_register_observer.h
new file mode 100644
index 00000000000..ed6a29989e0
--- /dev/null
+++ b/chromium/content/browser/streams/stream_register_observer.h
@@ -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.
+
+#ifndef CONTENT_BROWSER_STREAMS_STREAM_REGISTER_OBSERVER_H_
+#define CONTENT_BROWSER_STREAMS_STREAM_REGISTER_OBSERVER_H_
+
+#include "content/common/content_export.h"
+
+namespace content {
+
+class Stream;
+
+class CONTENT_EXPORT StreamRegisterObserver {
+ public:
+ // Sent when the stream is registered.
+ virtual void OnStreamRegistered(Stream* stream) = 0;
+
+ protected:
+ virtual ~StreamRegisterObserver() {}
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_STREAMS_STREAM_REGISTER_OBSERVER_H_
diff --git a/chromium/content/browser/streams/stream_registry.cc b/chromium/content/browser/streams/stream_registry.cc
index f722f57d03c..63c413b1632 100644
--- a/chromium/content/browser/streams/stream_registry.cc
+++ b/chromium/content/browser/streams/stream_registry.cc
@@ -20,13 +20,24 @@ StreamRegistry::StreamRegistry()
}
StreamRegistry::~StreamRegistry() {
+ DCHECK(register_observers_.empty());
}
-void StreamRegistry::RegisterStream(scoped_refptr<Stream> stream) {
+void StreamRegistry::RegisterStream(Stream* stream) {
DCHECK(CalledOnValidThread());
- DCHECK(stream.get());
+ DCHECK(stream);
DCHECK(!stream->url().is_empty());
+
+ auto aborted_url_itr = reader_aborted_urls_.find(stream->url());
+ if (aborted_url_itr != reader_aborted_urls_.end()) {
+ reader_aborted_urls_.erase(aborted_url_itr);
+ return;
+ }
streams_[stream->url()] = stream;
+
+ auto itr = register_observers_.find(stream->url());
+ if (itr != register_observers_.end())
+ itr->second->OnStreamRegistered(stream);
}
scoped_refptr<Stream> StreamRegistry::GetStream(const GURL& url) {
@@ -89,4 +100,22 @@ bool StreamRegistry::UpdateMemoryUsage(const GURL& url,
return true;
}
+
+void StreamRegistry::SetRegisterObserver(const GURL& url,
+ StreamRegisterObserver* observer) {
+ DCHECK(CalledOnValidThread());
+ DCHECK(register_observers_.find(url) == register_observers_.end());
+ register_observers_[url] = observer;
+}
+
+void StreamRegistry::RemoveRegisterObserver(const GURL& url) {
+ DCHECK(CalledOnValidThread());
+ register_observers_.erase(url);
+}
+
+void StreamRegistry::AbortPendingStream(const GURL& url) {
+ DCHECK(CalledOnValidThread());
+ reader_aborted_urls_.insert(url);
+}
+
} // namespace content
diff --git a/chromium/content/browser/streams/stream_registry.h b/chromium/content/browser/streams/stream_registry.h
index a359411d2ae..05c53100f04 100644
--- a/chromium/content/browser/streams/stream_registry.h
+++ b/chromium/content/browser/streams/stream_registry.h
@@ -6,10 +6,12 @@
#define CONTENT_BROWSER_STREAMS_STREAM_REGISTRY_H_
#include <map>
+#include <set>
#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
#include "base/threading/non_thread_safe.h"
+#include "content/browser/streams/stream_register_observer.h"
#include "content/common/content_export.h"
#include "url/gurl.h"
@@ -24,7 +26,7 @@ class CONTENT_EXPORT StreamRegistry : public base::NonThreadSafe {
virtual ~StreamRegistry();
// Registers a stream, and sets its URL.
- void RegisterStream(scoped_refptr<Stream> stream);
+ void RegisterStream(Stream* stream);
// Clones a stream. Returns true on success, or false if |src_url| doesn't
// exist.
@@ -49,10 +51,20 @@ class CONTENT_EXPORT StreamRegistry : public base::NonThreadSafe {
max_memory_usage_ = size;
}
+ void SetRegisterObserver(const GURL& url, StreamRegisterObserver* observer);
+ void RemoveRegisterObserver(const GURL& url);
+
+ // If the reader is aborted before the stream is registered, call this method
+ // to reduce the memory consumption. After this method is called,
+ // RegisterStream doesn't register the stream of the URL.
+ void AbortPendingStream(const GURL& url);
+
private:
typedef std::map<GURL, scoped_refptr<Stream> > StreamMap;
StreamMap streams_;
+ std::map<GURL, StreamRegisterObserver*> register_observers_;
+ std::set<GURL> reader_aborted_urls_;
size_t total_memory_usage_;
diff --git a/chromium/content/browser/streams/stream_unittest.cc b/chromium/content/browser/streams/stream_unittest.cc
index e0346e5a76e..eb83357f9fe 100644
--- a/chromium/content/browser/streams/stream_unittest.cc
+++ b/chromium/content/browser/streams/stream_unittest.cc
@@ -6,6 +6,7 @@
#include "base/test/test_simple_task_runner.h"
#include "content/browser/streams/stream.h"
#include "content/browser/streams/stream_read_observer.h"
+#include "content/browser/streams/stream_register_observer.h"
#include "content/browser/streams/stream_registry.h"
#include "content/browser/streams/stream_write_observer.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -103,6 +104,45 @@ class TestStreamWriter : public StreamWriteObserver {
void OnClose(Stream* stream) override {}
};
+class TestStreamObserver : public StreamRegisterObserver {
+ public:
+ TestStreamObserver(const GURL& url, StreamRegistry* registry)
+ : url_(url), registry_(registry), registered_(false), stream_(nullptr) {
+ registry->SetRegisterObserver(url, this);
+ }
+ ~TestStreamObserver() override { registry_->RemoveRegisterObserver(url_); }
+ void OnStreamRegistered(Stream* stream) override {
+ registered_ = true;
+ stream_ = stream;
+ }
+ bool registered() const { return registered_; }
+ Stream* stream() const { return stream_; }
+
+ private:
+ const GURL url_;
+ StreamRegistry* registry_;
+ bool registered_;
+ Stream* stream_;
+};
+
+TEST_F(StreamTest, SetAndRemoveRegisterObserver) {
+ TestStreamWriter writer1;
+ TestStreamWriter writer2;
+ GURL url1("blob://stream1");
+ GURL url2("blob://stream2");
+ scoped_ptr<TestStreamObserver> observer1(
+ new TestStreamObserver(url1, registry_.get()));
+ scoped_ptr<TestStreamObserver> observer2(
+ new TestStreamObserver(url2, registry_.get()));
+ scoped_refptr<Stream> stream1(new Stream(registry_.get(), &writer1, url1));
+ EXPECT_TRUE(observer1->registered());
+ EXPECT_EQ(observer1->stream(), stream1.get());
+ EXPECT_FALSE(observer2->registered());
+
+ observer2.reset();
+ scoped_refptr<Stream> stream2(new Stream(registry_.get(), &writer2, url2));
+}
+
TEST_F(StreamTest, SetReadObserver) {
TestStreamReader reader;
TestStreamWriter writer;
@@ -272,12 +312,12 @@ TEST_F(StreamTest, MemoryExceedMemoryUsageLimit) {
// Written data (1000000 * 2) exceeded limit (1500000). |stream2| should be
// unregistered with |registry_|.
- EXPECT_EQ(NULL, registry_->GetStream(url2).get());
+ EXPECT_EQ(nullptr, registry_->GetStream(url2).get());
writer1.Write(stream1.get(), buffer, kMaxMemoryUsage - kBufferSize);
// Should be accepted since stream2 is unregistered and the new data is not
// so big to exceed the limit.
- EXPECT_FALSE(registry_->GetStream(url1).get() == NULL);
+ EXPECT_FALSE(registry_->GetStream(url1).get() == nullptr);
}
TEST_F(StreamTest, UnderMemoryUsageLimit) {
@@ -302,4 +342,41 @@ TEST_F(StreamTest, UnderMemoryUsageLimit) {
EXPECT_EQ(stream.get(), registry_->GetStream(url).get());
}
+TEST_F(StreamTest, Flush) {
+ TestStreamWriter writer;
+ TestStreamReader reader;
+
+ GURL url("blob://stream");
+ scoped_refptr<Stream> stream(new Stream(registry_.get(), &writer, url));
+ EXPECT_TRUE(stream->SetReadObserver(&reader));
+
+ // If the written data size is smaller than ByteStreamWriter's (total size /
+ // kFractionBufferBeforeSending), StreamReadObserver::OnDataAvailable is not
+ // called.
+ const int kBufferSize = 1;
+ scoped_refptr<net::IOBuffer> buffer(NewIOBuffer(kBufferSize));
+ writer.Write(stream.get(), buffer, kBufferSize);
+
+ // Run loop to make |reader| consume the data.
+ base::MessageLoop::current()->RunUntilIdle();
+ EXPECT_EQ(0, reader.buffer()->capacity());
+
+ stream->Flush();
+
+ // Run loop to make |reader| consume the data.
+ base::MessageLoop::current()->RunUntilIdle();
+ EXPECT_EQ(kBufferSize, reader.buffer()->capacity());
+
+ EXPECT_EQ(stream.get(), registry_->GetStream(url).get());
+}
+
+TEST_F(StreamTest, AbortPendingStream) {
+ TestStreamWriter writer;
+
+ GURL url("blob://stream");
+ registry_->AbortPendingStream(url);
+ scoped_refptr<Stream> stream1(new Stream(registry_.get(), &writer, url));
+ ASSERT_EQ(nullptr, registry_->GetStream(url).get());
+}
+
} // namespace content
diff --git a/chromium/content/browser/streams/stream_url_request_job.cc b/chromium/content/browser/streams/stream_url_request_job.cc
index 6d70eefa515..3d4ac7f77f0 100644
--- a/chromium/content/browser/streams/stream_url_request_job.cc
+++ b/chromium/content/browser/streams/stream_url_request_job.cc
@@ -21,13 +21,13 @@ StreamURLRequestJob::StreamURLRequestJob(
net::NetworkDelegate* network_delegate,
scoped_refptr<Stream> stream)
: net::URLRequestJob(request, network_delegate),
- weak_factory_(this),
stream_(stream),
headers_set_(false),
pending_buffer_size_(0),
total_bytes_read_(0),
max_range_(0),
- request_failed_(false) {
+ request_failed_(false),
+ weak_factory_(this) {
DCHECK(stream_.get());
stream_->SetReadObserver(this);
}
diff --git a/chromium/content/browser/streams/stream_url_request_job.h b/chromium/content/browser/streams/stream_url_request_job.h
index 17e7eb2e3da..05c95515c16 100644
--- a/chromium/content/browser/streams/stream_url_request_job.h
+++ b/chromium/content/browser/streams/stream_url_request_job.h
@@ -44,7 +44,6 @@ class CONTENT_EXPORT StreamURLRequestJob
void HeadersCompleted(net::HttpStatusCode status_code);
void ClearStream();
- base::WeakPtrFactory<StreamURLRequestJob> weak_factory_;
scoped_refptr<content::Stream> stream_;
bool headers_set_;
scoped_refptr<net::IOBuffer> pending_buffer_;
@@ -55,6 +54,8 @@ class CONTENT_EXPORT StreamURLRequestJob
int max_range_;
bool request_failed_;
+ base::WeakPtrFactory<StreamURLRequestJob> weak_factory_;
+
DISALLOW_COPY_AND_ASSIGN(StreamURLRequestJob);
};
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 ad33f938a71..871b1aff9c8 100644
--- a/chromium/content/browser/streams/stream_url_request_job_unittest.cc
+++ b/chromium/content/browser/streams/stream_url_request_job_unittest.cc
@@ -75,7 +75,7 @@ class StreamURLRequestJobTest : public testing::Test {
const std::string& expected_response) {
net::TestDelegate delegate;
request_ = url_request_context_.CreateRequest(
- url, net::DEFAULT_PRIORITY, &delegate, NULL);
+ url, net::DEFAULT_PRIORITY, &delegate);
request_->set_method(method);
if (!extra_headers.IsEmpty())
request_->SetExtraRequestHeaders(extra_headers);
@@ -133,7 +133,7 @@ TEST_F(StreamURLRequestJobTest, TestGetLargeStreamRequest) {
TEST_F(StreamURLRequestJobTest, TestGetNonExistentStreamRequest) {
net::TestDelegate delegate;
request_ = url_request_context_.CreateRequest(
- kStreamURL, net::DEFAULT_PRIORITY, &delegate, NULL);
+ kStreamURL, net::DEFAULT_PRIORITY, &delegate);
request_->set_method("GET");
request_->Start();
diff --git a/chromium/content/browser/system_message_window_win.h b/chromium/content/browser/system_message_window_win.h
index b29bad57c89..a067e253b63 100644
--- a/chromium/content/browser/system_message_window_win.h
+++ b/chromium/content/browser/system_message_window_win.h
@@ -9,6 +9,7 @@
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
+#include "base/profiler/scoped_tracker.h"
#include "content/common/content_export.h"
namespace content {
@@ -31,6 +32,11 @@ class CONTENT_EXPORT SystemMessageWindowWin {
UINT message,
WPARAM wparam,
LPARAM lparam) {
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "440919 SystemMessageWindowWin::WndProcThunk"));
+
SystemMessageWindowWin* msg_wnd = reinterpret_cast<SystemMessageWindowWin*>(
GetWindowLongPtr(hwnd, GWLP_USERDATA));
if (msg_wnd)
diff --git a/chromium/content/browser/system_message_window_win_unittest.cc b/chromium/content/browser/system_message_window_win_unittest.cc
index f317f7be7cc..fac8f2baafd 100644
--- a/chromium/content/browser/system_message_window_win_unittest.cc
+++ b/chromium/content/browser/system_message_window_win_unittest.cc
@@ -18,10 +18,10 @@ namespace content {
class SystemMessageWindowWinTest : public testing::Test {
public:
- virtual ~SystemMessageWindowWinTest() { }
+ ~SystemMessageWindowWinTest() override {}
protected:
- virtual void SetUp() override {
+ 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 750eae35868..85ec2ed1c92 100644
--- a/chromium/content/browser/tcmalloc_internals_request_job.cc
+++ b/chromium/content/browser/tcmalloc_internals_request_job.cc
@@ -5,7 +5,6 @@
#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"
@@ -34,13 +33,13 @@ void AboutTcmallocOutputs::OnStatsForChildProcess(
void AboutTcmallocOutputs::SetOutput(const std::string& header,
const std::string& output) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
outputs_[header] = output;
}
void AboutTcmallocOutputs::DumpToHTMLTable(std::string* data) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
data->append("<table width=\"100%\">\n");
for (AboutTcmallocOutputsType::const_iterator oit = outputs_.begin();
@@ -109,11 +108,6 @@ 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/theme_helper_mac.mm b/chromium/content/browser/theme_helper_mac.mm
index 9f0f86d1a59..3abe515d4fd 100644
--- a/chromium/content/browser/theme_helper_mac.mm
+++ b/chromium/content/browser/theme_helper_mac.mm
@@ -15,15 +15,6 @@
#include "content/public/browser/render_process_host.h"
#include "content/public/common/content_switches.h"
-// Declare notification names from the 10.7 SDK.
-#if !defined(MAC_OS_X_VERSION_10_7) || \
- MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
-
-NSString* NSPreferredScrollerStyleDidChangeNotification =
- @"NSPreferredScrollerStyleDidChangeNotification";
-
-#endif
-
@interface ScrollbarPrefsObserver : NSObject
+ (void)registerAsObserver;
@@ -53,7 +44,8 @@ suspensionBehavior:NSNotificationSuspensionBehaviorCoalesce];
// In single-process mode, renderers will catch these notifications
// themselves and listening for them here may trigger the DCHECK in Observe().
if ([NSScroller respondsToSelector:@selector(preferredScrollerStyle)] &&
- !CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess)) {
+ !base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSingleProcess)) {
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(behaviorPrefsChanged:)
@@ -71,7 +63,7 @@ suspensionBehavior:NSNotificationSuspensionBehaviorCoalesce];
}
+ (void)notifyPrefsChangedWithRedraw:(BOOL)redraw {
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
[defaults synchronize];
@@ -134,7 +126,7 @@ void ThemeHelperMac::Observe(int type,
const NotificationDetails& details) {
DCHECK_EQ(NOTIFICATION_RENDERER_PROCESS_CREATED, type);
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
[defaults synchronize];
diff --git a/chromium/content/browser/time_zone_monitor.cc b/chromium/content/browser/time_zone_monitor.cc
index 0c17f8e5206..f414e979ab9 100644
--- a/chromium/content/browser/time_zone_monitor.cc
+++ b/chromium/content/browser/time_zone_monitor.cc
@@ -7,24 +7,48 @@
#include "base/logging.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h"
+#include "third_party/icu/source/common/unicode/unistr.h"
+#include "third_party/icu/source/i18n/unicode/timezone.h"
namespace content {
TimeZoneMonitor::TimeZoneMonitor() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
}
TimeZoneMonitor::~TimeZoneMonitor() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
}
void TimeZoneMonitor::NotifyRenderers() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+#if defined(OS_CHROMEOS)
+ // On CrOS, ICU's default tz is already set to a new zone. No
+ // need to redetect it with detectHostTimeZone().
+ scoped_ptr<icu::TimeZone> new_zone(icu::TimeZone::createDefault());
+#else
+ icu::TimeZone* new_zone = icu::TimeZone::detectHostTimeZone();
+#if defined(OS_LINUX)
+ // We get here multiple times on Linux per a single tz change, but
+ // want to update the ICU default zone and notify renderer only once.
+ scoped_ptr<icu::TimeZone> current_zone(icu::TimeZone::createDefault());
+ if (*current_zone == *new_zone) {
+ VLOG(1) << "timezone already updated";
+ delete new_zone;
+ return;
+ }
+#endif
+ icu::TimeZone::adoptDefault(new_zone);
+#endif
+ icu::UnicodeString zone_id;
+ std::string zone_id_str;
+ new_zone->getID(zone_id).toUTF8String(zone_id_str);
+ VLOG(1) << "timezone reset to " << zone_id_str;
for (RenderProcessHost::iterator iterator =
RenderProcessHost::AllHostsIterator();
!iterator.IsAtEnd();
iterator.Advance()) {
- iterator.GetCurrentValue()->NotifyTimezoneChange();
+ iterator.GetCurrentValue()->NotifyTimezoneChange(zone_id_str);
}
}
diff --git a/chromium/content/browser/time_zone_monitor_android.h b/chromium/content/browser/time_zone_monitor_android.h
index a462eb5a2de..cb3cb9f216e 100644
--- a/chromium/content/browser/time_zone_monitor_android.h
+++ b/chromium/content/browser/time_zone_monitor_android.h
@@ -17,7 +17,7 @@ namespace content {
class TimeZoneMonitorAndroid : public TimeZoneMonitor {
public:
TimeZoneMonitorAndroid();
- virtual ~TimeZoneMonitorAndroid();
+ ~TimeZoneMonitorAndroid() override;
// Must be called at startup.
static bool Register(JNIEnv* env);
diff --git a/chromium/content/browser/time_zone_monitor_chromeos.cc b/chromium/content/browser/time_zone_monitor_chromeos.cc
index 8c6aa0bd0a3..7ad81789bca 100644
--- a/chromium/content/browser/time_zone_monitor_chromeos.cc
+++ b/chromium/content/browser/time_zone_monitor_chromeos.cc
@@ -16,12 +16,12 @@ class TimeZoneMonitorChromeOS
chromeos::system::TimezoneSettings::GetInstance()->AddObserver(this);
}
- virtual ~TimeZoneMonitorChromeOS() {
+ ~TimeZoneMonitorChromeOS() override {
chromeos::system::TimezoneSettings::GetInstance()->RemoveObserver(this);
}
// chromeos::system::TimezoneSettings::Observer implementation.
- virtual void TimezoneChanged(const icu::TimeZone& time_zone) override {
+ 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 0836d5b8398..dd0a26f27f6 100644
--- a/chromium/content/browser/time_zone_monitor_linux.cc
+++ b/chromium/content/browser/time_zone_monitor_linux.cc
@@ -51,7 +51,7 @@ class TimeZoneMonitorLinuxImpl
: base::RefCountedThreadSafe<TimeZoneMonitorLinuxImpl>(),
file_path_watchers_(),
owner_(owner) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
BrowserThread::PostTask(
BrowserThread::FILE,
FROM_HERE,
@@ -59,7 +59,7 @@ class TimeZoneMonitorLinuxImpl
}
void StopWatching() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
owner_ = NULL;
BrowserThread::PostTask(
BrowserThread::FILE,
@@ -76,7 +76,7 @@ class TimeZoneMonitorLinuxImpl
}
void StartWatchingOnFileThread() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
// There is no true standard for where time zone information is actually
// stored. glibc uses /etc/localtime, uClibc uses /etc/TZ, and some older
@@ -101,12 +101,12 @@ class TimeZoneMonitorLinuxImpl
}
void StopWatchingOnFileThread() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
STLDeleteElements(&file_path_watchers_);
}
void OnTimeZoneFileChanged(const base::FilePath& path, bool error) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
BrowserThread::PostTask(
BrowserThread::UI,
FROM_HERE,
@@ -115,7 +115,7 @@ class TimeZoneMonitorLinuxImpl
}
void OnTimeZoneFileChangedOnUIThread() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (owner_) {
owner_->NotifyRenderersFromImpl();
}
diff --git a/chromium/content/browser/time_zone_monitor_win.cc b/chromium/content/browser/time_zone_monitor_win.cc
index 2e8f9a56ed1..abeaafff81c 100644
--- a/chromium/content/browser/time_zone_monitor_win.cc
+++ b/chromium/content/browser/time_zone_monitor_win.cc
@@ -7,26 +7,25 @@
#include <windows.h>
#include "base/basictypes.h"
-#include "ui/gfx/win/singleton_hwnd.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/gfx/win/singleton_hwnd_observer.h"
namespace content {
-class TimeZoneMonitorWin : public TimeZoneMonitor,
- public gfx::SingletonHwnd::Observer {
+class TimeZoneMonitorWin : public TimeZoneMonitor {
public:
- TimeZoneMonitorWin() : TimeZoneMonitor() {
- gfx::SingletonHwnd::GetInstance()->AddObserver(this);
- }
+ TimeZoneMonitorWin()
+ : TimeZoneMonitor(),
+ singleton_hwnd_observer_(
+ new gfx::SingletonHwndObserver(base::Bind(
+ &TimeZoneMonitorWin::OnWndProc, base::Unretained(this)))) {}
- virtual ~TimeZoneMonitorWin() {
- gfx::SingletonHwnd::GetInstance()->RemoveObserver(this);
- }
+ ~TimeZoneMonitorWin() override {}
- // gfx::SingletonHwnd::Observer implementation.
- virtual void OnWndProc(HWND hwnd,
- UINT message,
- WPARAM wparam,
- LPARAM lparam) override {
+ private:
+ void OnWndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) {
if (message != WM_TIMECHANGE) {
return;
}
@@ -34,7 +33,8 @@ class TimeZoneMonitorWin : public TimeZoneMonitor,
NotifyRenderers();
}
- private:
+ scoped_ptr<gfx::SingletonHwndObserver> singleton_hwnd_observer_;
+
DISALLOW_COPY_AND_ASSIGN(TimeZoneMonitorWin);
};
diff --git a/chromium/content/browser/tracing/BUILD.gn b/chromium/content/browser/tracing/BUILD.gn
index ae9c7dfaf3c..9cd28e13183 100644
--- a/chromium/content/browser/tracing/BUILD.gn
+++ b/chromium/content/browser/tracing/BUILD.gn
@@ -20,11 +20,14 @@ action("generate_tracing_grd") {
"$tracing_gen_dir/about_tracing.js",
]
inputs = input_pages
- outputs = [ tracing_grd ]
+ outputs = [
+ tracing_grd,
+ ]
args = rebase_path(input_pages, target_gen_dir) + [
- "--output", rebase_path(tracing_grd, root_build_dir),
- ]
+ "--output",
+ rebase_path(tracing_grd, root_build_dir),
+ ]
deps = [
"//third_party/trace-viewer:generate_about_tracing",
@@ -41,9 +44,10 @@ grit("resources") {
# 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),
- ]
+ defines =
+ [ "SHARED_INTERMEDIATE_DIR=" + rebase_path(root_gen_dir, root_build_dir) ]
- deps = [ ":generate_tracing_grd" ]
+ deps = [
+ ":generate_tracing_grd",
+ ]
}
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 fc3522fd81e..b03a26a771a 100644
--- a/chromium/content/browser/tracing/etw_system_event_consumer_win.cc
+++ b/chromium/content/browser/tracing/etw_system_event_consumer_win.cc
@@ -5,12 +5,12 @@
#include "content/browser/tracing/etw_system_event_consumer_win.h"
#include "base/base64.h"
-#include "base/debug/trace_event_impl.h"
#include "base/json/json_string_value_serializer.h"
#include "base/lazy_instance.h"
#include "base/memory/singleton.h"
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
+#include "base/trace_event/trace_event_impl.h"
#include "content/public/browser/browser_thread.h"
namespace content {
@@ -96,8 +96,25 @@ bool EtwSystemEventConsumer::StartKernelSessionTracing() {
HRESULT hr = base::win::EtwTraceController::Start(
KERNEL_LOGGER_NAME, &properties_, &session_handle_);
+
+ // It's possible that a previous tracing session has been orphaned. If so
+ // try stopping and restarting it.
+ if (hr == HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS)) {
+ VLOG(1) << "Session already exists, stopping and restarting it.";
+ hr = base::win::EtwTraceController::Stop(
+ KERNEL_LOGGER_NAME, &properties_);
+ if (FAILED(hr)) {
+ VLOG(1) << "EtwTraceController::Stop failed with " << hr << ".";
+ return false;
+ }
+
+ // The session was successfully shutdown so try to restart it.
+ hr = base::win::EtwTraceController::Start(
+ KERNEL_LOGGER_NAME, &properties_, &session_handle_);
+ }
+
if (FAILED(hr)) {
- VLOG(1) << "StartRealtimeSession() failed with " << hr << ".";
+ VLOG(1) << "EtwTraceController::Start failed with " << hr << ".";
return false;
}
diff --git a/chromium/content/browser/tracing/etw_system_event_consumer_win.h b/chromium/content/browser/tracing/etw_system_event_consumer_win.h
index 8d1764f8de0..3611bee7c60 100644
--- a/chromium/content/browser/tracing/etw_system_event_consumer_win.h
+++ b/chromium/content/browser/tracing/etw_system_event_consumer_win.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_TRACING_TRACING_CONSUMER_WIN_H_
-#define CONTENT_BROWSER_TRACING_TRACING_CONSUMER_WIN_H_
+#ifndef CONTENT_BROWSER_TRACING_ETW_SYSTEM_EVENT_CONSUMER_WIN_H_
+#define CONTENT_BROWSER_TRACING_ETW_SYSTEM_EVENT_CONSUMER_WIN_H_
#include "base/bind.h"
#include "base/memory/ref_counted_memory.h"
@@ -72,4 +72,4 @@ class EtwSystemEventConsumer :
} // namespace content
-#endif // CONTENT_BROWSER_TRACING_TRACING_CONSUMER_WIN_H_
+#endif // CONTENT_BROWSER_TRACING_ETW_SYSTEM_EVENT_CONSUMER_WIN_H_
diff --git a/chromium/content/browser/tracing/file_tracing_provider_impl.cc b/chromium/content/browser/tracing/file_tracing_provider_impl.cc
new file mode 100644
index 00000000000..21fcf07b5d9
--- /dev/null
+++ b/chromium/content/browser/tracing/file_tracing_provider_impl.cc
@@ -0,0 +1,55 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/tracing/file_tracing_provider_impl.h"
+
+#include "base/files/file_path.h"
+#include "base/trace_event/trace_event.h"
+
+namespace content {
+
+const char kFileTracingEventCategoryGroup[] = TRACE_DISABLED_BY_DEFAULT("file");
+
+FileTracingProviderImpl::FileTracingProviderImpl() {}
+FileTracingProviderImpl::~FileTracingProviderImpl() {}
+
+bool FileTracingProviderImpl::FileTracingCategoryIsEnabled() const {
+ bool enabled;
+ TRACE_EVENT_CATEGORY_GROUP_ENABLED(kFileTracingEventCategoryGroup, &enabled);
+ return enabled;
+}
+
+void FileTracingProviderImpl::FileTracingEnable(void* id) {
+ TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
+ kFileTracingEventCategoryGroup, FILE_TRACING_PREFIX, id);
+}
+
+void FileTracingProviderImpl::FileTracingDisable(void* id) {
+ TRACE_EVENT_NESTABLE_ASYNC_END0(
+ kFileTracingEventCategoryGroup, FILE_TRACING_PREFIX, id);
+}
+
+void FileTracingProviderImpl::FileTracingEventBegin(
+ const char* name, void* id, const base::FilePath& path, int64 size) {
+ if (size) {
+ TRACE_EVENT_NESTABLE_ASYNC_BEGIN2(kFileTracingEventCategoryGroup, name, id,
+ "path", path.AsUTF8Unsafe(), "size", size);
+ } else {
+ TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(kFileTracingEventCategoryGroup, name, id,
+ "path", path.AsUTF8Unsafe());
+ }
+}
+
+void FileTracingProviderImpl::FileTracingEventEnd(
+ const char* name, void* id, const base::FilePath& path, int64 size) {
+ if (size) {
+ TRACE_EVENT_NESTABLE_ASYNC_END2(kFileTracingEventCategoryGroup, name, id,
+ "path", path.AsUTF8Unsafe(), "size", size);
+ } else {
+ TRACE_EVENT_NESTABLE_ASYNC_END1(kFileTracingEventCategoryGroup, name, id,
+ "path", path.AsUTF8Unsafe());
+ }
+}
+
+} // namespace content
diff --git a/chromium/content/browser/tracing/file_tracing_provider_impl.h b/chromium/content/browser/tracing/file_tracing_provider_impl.h
new file mode 100644
index 00000000000..e9daf9582ec
--- /dev/null
+++ b/chromium/content/browser/tracing/file_tracing_provider_impl.h
@@ -0,0 +1,35 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_TRACING_FILE_TRACING_PROVIDER_IMPL_H_
+#define CONTENT_BROWSER_TRACING_FILE_TRACING_PROVIDER_IMPL_H_
+
+#include "base/files/file_tracing.h"
+#include "base/macros.h"
+
+namespace content {
+
+extern const char kFileTracingEventCategoryGroup[];
+
+class FileTracingProviderImpl : public base::FileTracing::Provider {
+ public:
+ FileTracingProviderImpl();
+ ~FileTracingProviderImpl();
+
+ // base::FileTracing::Provider:
+ bool FileTracingCategoryIsEnabled() const override;
+ void FileTracingEnable(void* id) override;
+ void FileTracingDisable(void* id) override;
+ void FileTracingEventBegin(const char* name, void* id,
+ const base::FilePath& path, int64 size) override;
+ void FileTracingEventEnd(const char* name, void* id,
+ const base::FilePath& path, int64 size) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FileTracingProviderImpl);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_TRACING_FILE_TRACING_PROVIDER_IMPL_H_
diff --git a/chromium/content/browser/tracing/trace_message_filter.cc b/chromium/content/browser/tracing/trace_message_filter.cc
index e74ca96caa6..98757279f36 100644
--- a/chromium/content/browser/tracing/trace_message_filter.cc
+++ b/chromium/content/browser/tracing/trace_message_filter.cc
@@ -28,7 +28,7 @@ void TraceMessageFilter::OnChannelClosing() {
OnCaptureMonitoringSnapshotAcked();
if (is_awaiting_buffer_percent_full_ack_)
- OnTraceBufferPercentFullReply(0.0f);
+ OnTraceLogStatusReply(base::trace_event::TraceLogStatus());
TracingControllerImpl::GetInstance()->RemoveTraceMessageFilter(this);
}
@@ -49,55 +49,59 @@ bool TraceMessageFilter::OnMessageReceived(const IPC::Message& message) {
OnMonitoringTraceDataCollected)
IPC_MESSAGE_HANDLER(TracingHostMsg_WatchEventMatched,
OnWatchEventMatched)
- IPC_MESSAGE_HANDLER(TracingHostMsg_TraceBufferPercentFullReply,
- OnTraceBufferPercentFullReply)
+ IPC_MESSAGE_HANDLER(TracingHostMsg_TraceLogStatusReply,
+ OnTraceLogStatusReply)
+ IPC_MESSAGE_HANDLER(TracingHostMsg_GlobalMemoryDumpRequest,
+ OnGlobalMemoryDumpRequest)
+ IPC_MESSAGE_HANDLER(TracingHostMsg_ProcessMemoryDumpResponse,
+ OnProcessMemoryDumpResponse)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void TraceMessageFilter::SendBeginTracing(
- const base::debug::CategoryFilter& category_filter,
- const base::debug::TraceOptions& options) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ const base::trace_event::CategoryFilter& category_filter,
+ const base::trace_event::TraceOptions& options) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
Send(new TracingMsg_BeginTracing(category_filter.ToString(),
base::TimeTicks::NowFromSystemTraceTime(),
options.ToString()));
}
void TraceMessageFilter::SendEndTracing() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(!is_awaiting_end_ack_);
is_awaiting_end_ack_ = true;
Send(new TracingMsg_EndTracing);
}
void TraceMessageFilter::SendEnableMonitoring(
- const base::debug::CategoryFilter& category_filter,
- const base::debug::TraceOptions& options) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ const base::trace_event::CategoryFilter& category_filter,
+ const base::trace_event::TraceOptions& options) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
Send(new TracingMsg_EnableMonitoring(category_filter.ToString(),
base::TimeTicks::NowFromSystemTraceTime(),
options.ToString()));
}
void TraceMessageFilter::SendDisableMonitoring() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
Send(new TracingMsg_DisableMonitoring);
}
void TraceMessageFilter::SendCaptureMonitoringSnapshot() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(!is_awaiting_capture_monitoring_snapshot_ack_);
is_awaiting_capture_monitoring_snapshot_ack_ = true;
Send(new TracingMsg_CaptureMonitoringSnapshot);
}
-void TraceMessageFilter::SendGetTraceBufferPercentFull() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+void TraceMessageFilter::SendGetTraceLogStatus() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(!is_awaiting_buffer_percent_full_ack_);
is_awaiting_buffer_percent_full_ack_ = true;
- Send(new TracingMsg_GetTraceBufferPercentFull);
+ Send(new TracingMsg_GetTraceLogStatus);
}
void TraceMessageFilter::SendSetWatchEvent(const std::string& category_name,
@@ -109,6 +113,18 @@ void TraceMessageFilter::SendCancelWatchEvent() {
Send(new TracingMsg_CancelWatchEvent);
}
+// Called by TracingControllerImpl, which handles the multiprocess coordination.
+void TraceMessageFilter::SendProcessMemoryDumpRequest(
+ const base::trace_event::MemoryDumpRequestArgs& args) {
+ Send(new TracingMsg_ProcessMemoryDumpRequest(args));
+}
+
+// Called by TracingControllerImpl, which handles the multiprocess coordination.
+void TraceMessageFilter::SendGlobalMemoryDumpResponse(uint64 dump_guid,
+ bool success) {
+ Send(new TracingMsg_GlobalMemoryDumpResponse(dump_guid, success));
+}
+
void TraceMessageFilter::OnChildSupportsTracing() {
has_child_ = true;
TracingControllerImpl::GetInstance()->AddTraceMessageFilter(this);
@@ -157,14 +173,27 @@ void TraceMessageFilter::OnWatchEventMatched() {
TracingControllerImpl::GetInstance()->OnWatchEventMatched();
}
-void TraceMessageFilter::OnTraceBufferPercentFullReply(float percent_full) {
+void TraceMessageFilter::OnTraceLogStatusReply(
+ const base::trace_event::TraceLogStatus& status) {
if (is_awaiting_buffer_percent_full_ack_) {
is_awaiting_buffer_percent_full_ack_ = false;
- TracingControllerImpl::GetInstance()->OnTraceBufferPercentFullReply(
- this, percent_full);
+ TracingControllerImpl::GetInstance()->OnTraceLogStatusReply(this, status);
} else {
NOTREACHED();
}
}
+void TraceMessageFilter::OnGlobalMemoryDumpRequest(
+ const base::trace_event::MemoryDumpRequestArgs& args) {
+ TracingControllerImpl::GetInstance()->RequestGlobalMemoryDump(
+ args,
+ base::Bind(&TraceMessageFilter::SendGlobalMemoryDumpResponse, this));
+}
+
+void TraceMessageFilter::OnProcessMemoryDumpResponse(uint64 dump_guid,
+ bool success) {
+ TracingControllerImpl::GetInstance()->OnProcessMemoryDumpResponse(
+ this, dump_guid, success);
+}
+
} // namespace content
diff --git a/chromium/content/browser/tracing/trace_message_filter.h b/chromium/content/browser/tracing/trace_message_filter.h
index 3d12d76d300..fdaebcf4aea 100644
--- a/chromium/content/browser/tracing/trace_message_filter.h
+++ b/chromium/content/browser/tracing/trace_message_filter.h
@@ -8,7 +8,8 @@
#include <string>
#include <vector>
-#include "base/debug/trace_event.h"
+#include "base/trace_event/memory_dump_request_args.h"
+#include "base/trace_event/trace_event.h"
#include "content/public/browser/browser_message_filter.h"
namespace content {
@@ -24,17 +25,21 @@ class TraceMessageFilter : public BrowserMessageFilter {
void OnChannelClosing() override;
bool OnMessageReceived(const IPC::Message& message) override;
- void SendBeginTracing(const base::debug::CategoryFilter& category_filter_str,
- const base::debug::TraceOptions& options);
+ void SendBeginTracing(
+ const base::trace_event::CategoryFilter& category_filter_str,
+ const base::trace_event::TraceOptions& options);
void SendEndTracing();
- void SendEnableMonitoring(const base::debug::CategoryFilter& category_filter,
- const base::debug::TraceOptions& options);
+ void SendEnableMonitoring(
+ const base::trace_event::CategoryFilter& category_filter,
+ const base::trace_event::TraceOptions& options);
void SendDisableMonitoring();
void SendCaptureMonitoringSnapshot();
- void SendGetTraceBufferPercentFull();
+ void SendGetTraceLogStatus();
void SendSetWatchEvent(const std::string& category_name,
const std::string& event_name);
void SendCancelWatchEvent();
+ void SendProcessMemoryDumpRequest(
+ const base::trace_event::MemoryDumpRequestArgs& args);
protected:
~TraceMessageFilter() override;
@@ -45,9 +50,14 @@ class TraceMessageFilter : public BrowserMessageFilter {
void OnEndTracingAck(const std::vector<std::string>& known_categories);
void OnCaptureMonitoringSnapshotAcked();
void OnWatchEventMatched();
- void OnTraceBufferPercentFullReply(float percent_full);
+ void OnTraceLogStatusReply(const base::trace_event::TraceLogStatus& status);
void OnTraceDataCollected(const std::string& data);
void OnMonitoringTraceDataCollected(const std::string& data);
+ void OnGlobalMemoryDumpRequest(
+ const base::trace_event::MemoryDumpRequestArgs& args);
+ void OnProcessMemoryDumpResponse(uint64 dump_guid, bool success);
+
+ void SendGlobalMemoryDumpResponse(uint64 dump_guid, bool success);
// ChildTraceMessageFilter exists:
bool has_child_;
@@ -56,7 +66,7 @@ class TraceMessageFilter : public BrowserMessageFilter {
bool is_awaiting_end_ack_;
// Awaiting ack for previously sent SendCaptureMonitoringSnapshot
bool is_awaiting_capture_monitoring_snapshot_ack_;
- // Awaiting ack for previously sent SendGetTraceBufferPercentFull
+ // Awaiting ack for previously sent SendGetTraceLogStatus
bool is_awaiting_buffer_percent_full_ack_;
DISALLOW_COPY_AND_ASSIGN(TraceMessageFilter);
diff --git a/chromium/content/browser/tracing/trace_uploader.cc b/chromium/content/browser/tracing/trace_uploader.cc
deleted file mode 100644
index 3bcc1872817..00000000000
--- a/chromium/content/browser/tracing/trace_uploader.cc
+++ /dev/null
@@ -1,210 +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/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
deleted file mode 100644
index 323a4c54668..00000000000
--- a/chromium/content/browser/tracing/trace_uploader.h
+++ /dev/null
@@ -1,92 +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_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 cb74923afc1..239b36cf386 100644
--- a/chromium/content/browser/tracing/tracing_controller_browsertest.cc
+++ b/chromium/content/browser/tracing/tracing_controller_browsertest.cc
@@ -5,19 +5,51 @@
#include "base/files/file_util.h"
#include "base/memory/ref_counted_memory.h"
#include "base/run_loop.h"
+#include "content/public/browser/browser_thread.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;
+using base::trace_event::CategoryFilter;
+using base::trace_event::TraceOptions;
+using base::trace_event::RECORD_CONTINUOUSLY;
+using base::trace_event::RECORD_UNTIL_FULL;
namespace content {
+class TracingControllerTestEndpoint
+ : public TracingController::TraceDataEndpoint {
+ public:
+ TracingControllerTestEndpoint(
+ base::Callback<void(base::RefCountedString*)> done_callback)
+ : done_callback_(done_callback) {}
+
+ void ReceiveTraceChunk(const std::string& chunk) override {
+ EXPECT_FALSE(chunk.empty());
+ trace_ += chunk;
+ }
+
+ void ReceiveTraceFinalContents(const std::string& contents) override {
+ EXPECT_EQ(trace_, contents);
+
+ std::string tmp = contents;
+ scoped_refptr<base::RefCountedString> chunk_ptr =
+ base::RefCountedString::TakeString(&tmp);
+
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(done_callback_, chunk_ptr));
+ }
+
+ protected:
+ ~TracingControllerTestEndpoint() override {}
+
+ std::string trace_;
+ base::Callback<void(base::RefCountedString*)> done_callback_;
+};
+
class TracingControllerTest : public ContentBrowserTest {
public:
TracingControllerTest() {}
@@ -153,6 +185,70 @@ class TracingControllerTest : public ContentBrowserTest {
}
}
+ void TestEnableAndDisableRecordingCompressed() {
+ 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->EnableRecording(CategoryFilter(),
+ TraceOptions(), callback);
+ ASSERT_TRUE(result);
+ run_loop.Run();
+ EXPECT_EQ(enable_recording_done_callback_count(), 1);
+ }
+
+ {
+ base::RunLoop run_loop;
+ base::Callback<void(base::RefCountedString*)> callback = base::Bind(
+ &TracingControllerTest::DisableRecordingStringDoneCallbackTest,
+ base::Unretained(this), run_loop.QuitClosure());
+ bool result = controller->DisableRecording(
+ TracingController::CreateCompressedStringSink(
+ new TracingControllerTestEndpoint(callback)));
+ ASSERT_TRUE(result);
+ run_loop.Run();
+ EXPECT_EQ(disable_recording_done_callback_count(), 1);
+ }
+ }
+
+ void TestEnableAndDisableRecordingCompressedFile(
+ 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->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::CreateCompressedStringSink(
+ TracingController::CreateFileEndpoint(result_file_path,
+ 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());
@@ -317,6 +413,19 @@ IN_PROC_BROWSER_TEST_F(TracingControllerTest,
}
IN_PROC_BROWSER_TEST_F(TracingControllerTest,
+ EnableAndDisableRecordingWithCompression) {
+ TestEnableAndDisableRecordingCompressed();
+}
+
+IN_PROC_BROWSER_TEST_F(TracingControllerTest,
+ EnableAndDisableRecordingToFileWithCompression) {
+ base::FilePath file_path;
+ base::CreateTemporaryFile(&file_path);
+ TestEnableAndDisableRecordingCompressedFile(file_path);
+ EXPECT_EQ(file_path.value(), last_actual_recording_file_path().value());
+}
+
+IN_PROC_BROWSER_TEST_F(TracingControllerTest,
EnableAndDisableRecordingWithEmptyFileAndNullCallback) {
Navigate(shell());
diff --git a/chromium/content/browser/tracing/tracing_controller_impl.cc b/chromium/content/browser/tracing/tracing_controller_impl.cc
index 3e8e1ac7cd1..f063aa3f57e 100644
--- a/chromium/content/browser/tracing/tracing_controller_impl.cc
+++ b/chromium/content/browser/tracing/tracing_controller_impl.cc
@@ -4,11 +4,12 @@
#include "content/browser/tracing/tracing_controller_impl.h"
#include "base/bind.h"
-#include "base/debug/trace_event.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 "base/trace_event/trace_event.h"
+#include "content/browser/tracing/file_tracing_provider_impl.h"
#include "content/browser/tracing/trace_message_filter.h"
#include "content/browser/tracing/tracing_ui.h"
#include "content/common/child_process_messages.h"
@@ -24,9 +25,9 @@
#include "content/browser/tracing/etw_system_event_consumer_win.h"
#endif
-using base::debug::TraceLog;
-using base::debug::TraceOptions;
-using base::debug::CategoryFilter;
+using base::trace_event::TraceLog;
+using base::trace_event::TraceOptions;
+using base::trace_event::CategoryFilter;
namespace content {
@@ -35,145 +36,31 @@ namespace {
base::LazyInstance<TracingControllerImpl>::Leaky g_controller =
LAZY_INSTANCE_INITIALIZER;
-class FileTraceDataSink : public TracingController::TraceDataSink {
- public:
- 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 SetSystemTrace(const std::string& data) override {
- system_trace_ = data;
- }
- void Close() override {
- BrowserThread::PostTask(
- BrowserThread::FILE,
- FROM_HERE,
- base::Bind(&FileTraceDataSink::CloseOnFileThread, this));
- }
-
- private:
- ~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_;
- std::string system_trace_;
-
- DISALLOW_COPY_AND_ASSIGN(FileTraceDataSink);
-};
-
-class StringTraceDataSink : public TracingController::TraceDataSink {
- public:
- typedef base::Callback<void(base::RefCountedString*)> CompletionCallback;
-
- explicit StringTraceDataSink(CompletionCallback callback)
- : completion_callback_(callback) {}
-
- // TracingController::TraceDataSink implementation
- void AddTraceChunk(const std::string& chunk) override {
- if (!trace_.empty())
- trace_ += ",";
- trace_ += chunk;
- }
- 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 += "}";
-
- scoped_refptr<base::RefCountedString> str =
- base::RefCountedString::TakeString(&result);
- completion_callback_.Run(str.get());
- }
-
- private:
- ~StringTraceDataSink() override {}
-
- std::string trace_;
- std::string system_trace_;
- CompletionCallback completion_callback_;
-
- DISALLOW_COPY_AND_ASSIGN(StringTraceDataSink);
-};
-
} // namespace
TracingController* TracingController::GetInstance() {
return TracingControllerImpl::GetInstance();
}
-TracingControllerImpl::TracingControllerImpl() :
- pending_disable_recording_ack_count_(0),
- pending_capture_monitoring_snapshot_ack_count_(0),
- pending_trace_buffer_percent_full_ack_count_(0),
- maximum_trace_buffer_percent_full_(0),
+TracingControllerImpl::TracingControllerImpl()
+ : pending_disable_recording_ack_count_(0),
+ pending_capture_monitoring_snapshot_ack_count_(0),
+ pending_trace_log_status_ack_count_(0),
+ maximum_trace_buffer_usage_(0),
+ approximate_event_count_(0),
+ pending_memory_dump_ack_count_(0),
+ failed_memory_dump_count_(0),
// Tracing may have been enabled by ContentMainRunner if kTraceStartup
// is specified in command line.
#if defined(OS_CHROMEOS) || defined(OS_WIN)
- is_system_tracing_(false),
+ is_system_tracing_(false),
#endif
- is_recording_(TraceLog::GetInstance()->IsEnabled()),
- is_monitoring_(false) {
+ is_recording_(TraceLog::GetInstance()->IsEnabled()),
+ is_monitoring_(false) {
+ base::trace_event::MemoryDumpManager::GetInstance()->SetDelegate(this);
+
+ // Deliberately leaked, like this class.
+ base::FileTracing::SetProvider(new FileTracingProviderImpl);
}
TracingControllerImpl::~TracingControllerImpl() {
@@ -187,7 +74,7 @@ TracingControllerImpl* TracingControllerImpl::GetInstance() {
bool TracingControllerImpl::GetCategories(
const GetCategoriesDoneCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
// Known categories come back from child processes with the EndTracingAck
// message. So to get known categories, just begin and end tracing immediately
@@ -209,7 +96,7 @@ void TracingControllerImpl::SetEnabledOnFileThread(
int mode,
const TraceOptions& trace_options,
const base::Closure& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
TraceLog::GetInstance()->SetEnabled(
category_filter, static_cast<TraceLog::Mode>(mode), trace_options);
@@ -218,7 +105,7 @@ void TracingControllerImpl::SetEnabledOnFileThread(
void TracingControllerImpl::SetDisabledOnFileThread(
const base::Closure& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
TraceLog::GetInstance()->SetDisabled();
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
@@ -228,7 +115,7 @@ bool TracingControllerImpl::EnableRecording(
const CategoryFilter& category_filter,
const TraceOptions& trace_options,
const EnableRecordingDoneCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!can_enable_recording())
return false;
@@ -263,7 +150,7 @@ bool TracingControllerImpl::EnableRecording(
base::Bind(&TracingControllerImpl::SetEnabledOnFileThread,
base::Unretained(this),
category_filter,
- base::debug::TraceLog::RECORDING_MODE,
+ base::trace_event::TraceLog::RECORDING_MODE,
trace_options,
on_enable_recording_done_callback));
return true;
@@ -273,7 +160,7 @@ void TracingControllerImpl::OnEnableRecordingDone(
const CategoryFilter& category_filter,
const TraceOptions& trace_options,
const EnableRecordingDoneCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
// Notify all child processes.
for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
@@ -287,7 +174,7 @@ void TracingControllerImpl::OnEnableRecordingDone(
bool TracingControllerImpl::DisableRecording(
const scoped_refptr<TraceDataSink>& trace_data_sink) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!can_disable_recording())
return false;
@@ -306,7 +193,7 @@ bool TracingControllerImpl::DisableRecording(
}
void TracingControllerImpl::OnDisableRecordingDone() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
#if defined(OS_ANDROID)
if (pending_get_categories_done_callback_.is_null())
@@ -348,7 +235,8 @@ void TracingControllerImpl::OnDisableRecordingDone() {
// Flush asynchronously now, because we don't have any children to wait for.
TraceLog::GetInstance()->Flush(
base::Bind(&TracingControllerImpl::OnLocalTraceDataCollected,
- base::Unretained(this)));
+ base::Unretained(this)),
+ true);
}
// Notify all child processes.
@@ -362,7 +250,7 @@ bool TracingControllerImpl::EnableMonitoring(
const CategoryFilter& category_filter,
const TraceOptions& trace_options,
const EnableMonitoringDoneCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!can_enable_monitoring())
return false;
@@ -382,7 +270,7 @@ bool TracingControllerImpl::EnableMonitoring(
base::Bind(&TracingControllerImpl::SetEnabledOnFileThread,
base::Unretained(this),
category_filter,
- base::debug::TraceLog::MONITORING_MODE,
+ base::trace_event::TraceLog::MONITORING_MODE,
trace_options,
on_enable_monitoring_done_callback));
return true;
@@ -392,7 +280,7 @@ void TracingControllerImpl::OnEnableMonitoringDone(
const CategoryFilter& category_filter,
const TraceOptions& trace_options,
const EnableMonitoringDoneCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
// Notify all child processes.
for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
@@ -406,7 +294,7 @@ void TracingControllerImpl::OnEnableMonitoringDone(
bool TracingControllerImpl::DisableMonitoring(
const DisableMonitoringDoneCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!can_disable_monitoring())
return false;
@@ -422,21 +310,9 @@ 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));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
OnMonitoringStateChanged(false);
@@ -460,7 +336,7 @@ void TracingControllerImpl::GetMonitoringStatus(
bool TracingControllerImpl::CaptureMonitoringSnapshot(
const scoped_refptr<TraceDataSink>& monitoring_data_sink) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!can_disable_monitoring())
return false;
@@ -499,34 +375,36 @@ bool TracingControllerImpl::CaptureMonitoringSnapshot(
return true;
}
-bool TracingControllerImpl::GetTraceBufferPercentFull(
- const GetTraceBufferPercentFullCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+bool TracingControllerImpl::GetTraceBufferUsage(
+ const GetTraceBufferUsageCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
- if (!can_get_trace_buffer_percent_full() || callback.is_null())
+ if (!can_get_trace_buffer_usage() || callback.is_null())
return false;
- pending_trace_buffer_percent_full_callback_ = callback;
+ pending_trace_buffer_usage_callback_ = callback;
- // Count myself in pending_trace_buffer_percent_full_ack_count_, acked below.
- pending_trace_buffer_percent_full_ack_count_ =
- trace_message_filters_.size() + 1;
- pending_trace_buffer_percent_full_filters_ = trace_message_filters_;
- maximum_trace_buffer_percent_full_ = 0;
+ // Count myself in pending_trace_log_status_ack_count_, acked below.
+ pending_trace_log_status_ack_count_ = trace_message_filters_.size() + 1;
+ pending_trace_log_status_filters_ = trace_message_filters_;
+ maximum_trace_buffer_usage_ = 0;
+ approximate_event_count_ = 0;
- // Call OnTraceBufferPercentFullReply unconditionally for the browser process.
+ base::trace_event::TraceLogStatus status =
+ TraceLog::GetInstance()->GetStatus();
+ // Call OnTraceLogStatusReply unconditionally for the browser process.
// This will result in immediate execution of the callback if there are no
// child processes.
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(&TracingControllerImpl::OnTraceBufferPercentFullReply,
- base::Unretained(this),
- scoped_refptr<TraceMessageFilter>(),
- TraceLog::GetInstance()->GetBufferPercentFull()));
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&TracingControllerImpl::OnTraceLogStatusReply,
+ base::Unretained(this), scoped_refptr<TraceMessageFilter>(),
+ status));
// Notify all child processes.
for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
it != trace_message_filters_.end(); ++it) {
- it->get()->SendGetTraceBufferPercentFull();
+ it->get()->SendGetTraceLogStatus();
}
return true;
}
@@ -535,7 +413,7 @@ bool TracingControllerImpl::SetWatchEvent(
const std::string& category_name,
const std::string& event_name,
const WatchEventCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (callback.is_null())
return false;
@@ -557,7 +435,7 @@ bool TracingControllerImpl::SetWatchEvent(
}
bool TracingControllerImpl::CancelWatchEvent() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!can_cancel_watch_event())
return false;
@@ -632,18 +510,30 @@ void TracingControllerImpl::RemoveTraceMessageFilter(
make_scoped_refptr(trace_message_filter)));
}
}
- if (pending_trace_buffer_percent_full_ack_count_ > 0) {
+ if (pending_trace_log_status_ack_count_ > 0) {
TraceMessageFilterSet::const_iterator it =
- pending_trace_buffer_percent_full_filters_.find(trace_message_filter);
- if (it != pending_trace_buffer_percent_full_filters_.end()) {
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(&TracingControllerImpl::OnTraceBufferPercentFullReply,
+ pending_trace_log_status_filters_.find(trace_message_filter);
+ if (it != pending_trace_log_status_filters_.end()) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&TracingControllerImpl::OnTraceLogStatusReply,
base::Unretained(this),
make_scoped_refptr(trace_message_filter),
- 0));
+ base::trace_event::TraceLogStatus()));
+ }
+ }
+ if (pending_memory_dump_ack_count_ > 0) {
+ TraceMessageFilterSet::const_iterator it =
+ pending_memory_dump_filters_.find(trace_message_filter);
+ if (it != pending_memory_dump_filters_.end()) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&TracingControllerImpl::OnProcessMemoryDumpResponse,
+ base::Unretained(this),
+ make_scoped_refptr(trace_message_filter),
+ pending_memory_dump_guid_, false /* success */));
}
}
-
trace_message_filters_.erase(trace_message_filter);
}
@@ -678,7 +568,8 @@ void TracingControllerImpl::OnDisableRecordingAcked(
// called with the last of the local trace data.
TraceLog::GetInstance()->Flush(
base::Bind(&TracingControllerImpl::OnLocalTraceDataCollected,
- base::Unretained(this)));
+ base::Unretained(this)),
+ true);
return;
}
@@ -702,7 +593,7 @@ void TracingControllerImpl::OnDisableRecordingAcked(
#if defined(OS_CHROMEOS) || defined(OS_WIN)
void TracingControllerImpl::OnEndSystemTracingAcked(
const scoped_refptr<base::RefCountedString>& events_str_ptr) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (trace_data_sink_.get()) {
#if defined(OS_WIN)
@@ -815,35 +706,38 @@ void TracingControllerImpl::OnLocalMonitoringTraceDataCollected(
OnCaptureMonitoringSnapshotAcked(NULL);
}
-void TracingControllerImpl::OnTraceBufferPercentFullReply(
+void TracingControllerImpl::OnTraceLogStatusReply(
TraceMessageFilter* trace_message_filter,
- float percent_full) {
+ const base::trace_event::TraceLogStatus& status) {
if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(&TracingControllerImpl::OnTraceBufferPercentFullReply,
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&TracingControllerImpl::OnTraceLogStatusReply,
base::Unretained(this),
- make_scoped_refptr(trace_message_filter),
- percent_full));
+ make_scoped_refptr(trace_message_filter), status));
return;
}
- if (pending_trace_buffer_percent_full_ack_count_ == 0)
+ if (pending_trace_log_status_ack_count_ == 0)
return;
if (trace_message_filter &&
- !pending_trace_buffer_percent_full_filters_.erase(trace_message_filter)) {
+ !pending_trace_log_status_filters_.erase(trace_message_filter)) {
// The response from the specified message filter has already been received.
return;
}
- maximum_trace_buffer_percent_full_ =
- std::max(maximum_trace_buffer_percent_full_, percent_full);
+ float percent_full = static_cast<float>(
+ static_cast<double>(status.event_count) / status.event_capacity);
+ maximum_trace_buffer_usage_ =
+ std::max(maximum_trace_buffer_usage_, percent_full);
+ approximate_event_count_ += status.event_count;
- if (--pending_trace_buffer_percent_full_ack_count_ == 0) {
+ if (--pending_trace_log_status_ack_count_ == 0) {
// Trigger callback if one is set.
- pending_trace_buffer_percent_full_callback_.Run(
- maximum_trace_buffer_percent_full_);
- pending_trace_buffer_percent_full_callback_.Reset();
+ pending_trace_buffer_usage_callback_.Run(maximum_trace_buffer_usage_,
+ approximate_event_count_);
+ pending_trace_buffer_usage_callback_.Reset();
}
}
@@ -870,6 +764,109 @@ void TracingControllerImpl::UnregisterTracingUI(TracingUI* tracing_ui) {
tracing_uis_.erase(it);
}
+void TracingControllerImpl::RequestGlobalMemoryDump(
+ const base::trace_event::MemoryDumpRequestArgs& args,
+ const base::trace_event::MemoryDumpCallback& callback) {
+ if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&TracingControllerImpl::RequestGlobalMemoryDump,
+ base::Unretained(this), args, callback));
+ return;
+ }
+ // Abort if another dump is already in progress.
+ if (pending_memory_dump_guid_) {
+ DVLOG(1) << "Requested memory dump " << args.dump_guid
+ << " while waiting for " << pending_memory_dump_guid_;
+ if (!callback.is_null())
+ callback.Run(args.dump_guid, false /* success */);
+ return;
+ }
+
+ // Count myself (local trace) in pending_memory_dump_ack_count_, acked by
+ // OnBrowserProcessMemoryDumpDone().
+ pending_memory_dump_ack_count_ = trace_message_filters_.size() + 1;
+ pending_memory_dump_filters_.clear();
+ failed_memory_dump_count_ = 0;
+
+ MemoryDumpManagerDelegate::CreateProcessDump(
+ args, base::Bind(&TracingControllerImpl::OnBrowserProcessMemoryDumpDone,
+ base::Unretained(this)));
+
+ // If there are no child processes we are just done.
+ if (pending_memory_dump_ack_count_ == 1) {
+ if (!callback.is_null())
+ callback.Run(args.dump_guid, true /* success */);
+ return;
+ }
+
+ pending_memory_dump_guid_ = args.dump_guid;
+ pending_memory_dump_callback_ = callback;
+ pending_memory_dump_filters_ = trace_message_filters_;
+
+ for (const scoped_refptr<TraceMessageFilter>& tmf : trace_message_filters_)
+ tmf->SendProcessMemoryDumpRequest(args);
+}
+
+bool TracingControllerImpl::IsCoordinatorProcess() const {
+ return true;
+}
+
+void TracingControllerImpl::OnProcessMemoryDumpResponse(
+ TraceMessageFilter* trace_message_filter,
+ uint64 dump_guid,
+ bool success) {
+ if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&TracingControllerImpl::OnProcessMemoryDumpResponse,
+ base::Unretained(this),
+ make_scoped_refptr(trace_message_filter), dump_guid,
+ success));
+ return;
+ }
+
+ TraceMessageFilterSet::iterator it =
+ pending_memory_dump_filters_.find(trace_message_filter);
+
+ if (pending_memory_dump_guid_ != dump_guid ||
+ it == pending_memory_dump_filters_.end()) {
+ DLOG(WARNING) << "Received unexpected memory dump response: " << dump_guid;
+ return;
+ }
+
+ DCHECK_GT(pending_memory_dump_ack_count_, 0);
+ --pending_memory_dump_ack_count_;
+ pending_memory_dump_filters_.erase(it);
+ if (!success) {
+ ++failed_memory_dump_count_;
+ DLOG(WARNING) << "Global memory dump failed because of NACK from child "
+ << trace_message_filter->peer_pid();
+ }
+ FinalizeGlobalMemoryDumpIfAllProcessesReplied();
+}
+
+void TracingControllerImpl::OnBrowserProcessMemoryDumpDone(uint64 dump_guid,
+ bool success) {
+ DCHECK_GT(pending_memory_dump_ack_count_, 0);
+ --pending_memory_dump_ack_count_;
+ FinalizeGlobalMemoryDumpIfAllProcessesReplied();
+}
+
+void TracingControllerImpl::FinalizeGlobalMemoryDumpIfAllProcessesReplied() {
+ if (pending_memory_dump_ack_count_ > 0)
+ return;
+
+ DCHECK_NE(0u, pending_memory_dump_guid_);
+ const bool global_success = failed_memory_dump_count_ == 0;
+ if (!pending_memory_dump_callback_.is_null()) {
+ pending_memory_dump_callback_.Run(pending_memory_dump_guid_,
+ global_success);
+ pending_memory_dump_callback_.Reset();
+ }
+ pending_memory_dump_guid_ = 0;
+}
+
void TracingControllerImpl::OnMonitoringStateChanged(bool is_monitoring) {
if (is_monitoring_ == is_monitoring)
return;
diff --git a/chromium/content/browser/tracing/tracing_controller_impl.h b/chromium/content/browser/tracing/tracing_controller_impl.h
index 9bd84200d45..fb54da66548 100644
--- a/chromium/content/browser/tracing/tracing_controller_impl.h
+++ b/chromium/content/browser/tracing/tracing_controller_impl.h
@@ -10,6 +10,7 @@
#include <vector>
#include "base/lazy_instance.h"
+#include "base/trace_event/memory_dump_manager.h"
#include "content/public/browser/tracing_controller.h"
namespace base {
@@ -22,29 +23,32 @@ namespace content {
class TraceMessageFilter;
class TracingUI;
-class TracingControllerImpl : public TracingController {
+class TracingControllerImpl
+ : public TracingController,
+ public base::trace_event::MemoryDumpManagerDelegate {
public:
static TracingControllerImpl* GetInstance();
// TracingController implementation.
bool GetCategories(const GetCategoriesDoneCallback& callback) override;
- bool EnableRecording(const base::debug::CategoryFilter& category_filter,
- const base::debug::TraceOptions& trace_options,
+ bool EnableRecording(const base::trace_event::CategoryFilter& category_filter,
+ const base::trace_event::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 EnableMonitoring(
+ const base::trace_event::CategoryFilter& category_filter,
+ const base::trace_event::TraceOptions& trace_options,
+ const EnableMonitoringDoneCallback& callback) override;
bool DisableMonitoring(
const DisableMonitoringDoneCallback& callback) override;
void GetMonitoringStatus(
bool* out_enabled,
- base::debug::CategoryFilter* out_category_filter,
- base::debug::TraceOptions* out_trace_options) override;
+ base::trace_event::CategoryFilter* out_category_filter,
+ base::trace_event::TraceOptions* out_trace_options) override;
bool CaptureMonitoringSnapshot(
const scoped_refptr<TraceDataSink>& sink) override;
- bool GetTraceBufferPercentFull(
- const GetTraceBufferPercentFullCallback& callback) override;
+ bool GetTraceBufferUsage(
+ const GetTraceBufferUsageCallback& callback) override;
bool SetWatchEvent(const std::string& category_name,
const std::string& event_name,
const WatchEventCallback& callback) override;
@@ -53,6 +57,12 @@ class TracingControllerImpl : public TracingController {
void RegisterTracingUI(TracingUI* tracing_ui);
void UnregisterTracingUI(TracingUI* tracing_ui);
+ // base::trace_event::MemoryDumpManagerDelegate implementation.
+ void RequestGlobalMemoryDump(
+ const base::trace_event::MemoryDumpRequestArgs& args,
+ const base::trace_event::MemoryDumpCallback& callback) override;
+ bool IsCoordinatorProcess() const override;
+
private:
typedef std::set<scoped_refptr<TraceMessageFilter> > TraceMessageFilterSet;
@@ -78,8 +88,8 @@ class TracingControllerImpl : public TracingController {
return is_monitoring_ && !monitoring_data_sink_.get();
}
- bool can_get_trace_buffer_percent_full() const {
- return pending_trace_buffer_percent_full_callback_.is_null();
+ bool can_get_trace_buffer_usage() const {
+ return pending_trace_buffer_usage_callback_.is_null();
}
bool can_cancel_watch_event() const {
@@ -116,25 +126,33 @@ class TracingControllerImpl : public TracingController {
void OnCaptureMonitoringSnapshotAcked(
TraceMessageFilter* trace_message_filter);
- void OnTraceBufferPercentFullReply(
- TraceMessageFilter* trace_message_filter,
- float percent_full);
+ void OnTraceLogStatusReply(TraceMessageFilter* trace_message_filter,
+ const base::trace_event::TraceLogStatus& status);
+ void OnProcessMemoryDumpResponse(TraceMessageFilter* trace_message_filter,
+ uint64 dump_guid,
+ bool success);
+
+ // Callback of MemoryDumpManager::CreateProcessDump().
+ void OnBrowserProcessMemoryDumpDone(uint64 dump_guid, bool success);
+
+ void FinalizeGlobalMemoryDumpIfAllProcessesReplied();
void OnWatchEventMatched();
void SetEnabledOnFileThread(
- const base::debug::CategoryFilter& category_filter,
+ const base::trace_event::CategoryFilter& category_filter,
int mode,
- const base::debug::TraceOptions& trace_options,
+ const base::trace_event::TraceOptions& trace_options,
const base::Closure& callback);
void SetDisabledOnFileThread(const base::Closure& callback);
- void OnEnableRecordingDone(const base::debug::CategoryFilter& category_filter,
- const base::debug::TraceOptions& trace_options,
- const EnableRecordingDoneCallback& callback);
+ void OnEnableRecordingDone(
+ const base::trace_event::CategoryFilter& category_filter,
+ const base::trace_event::TraceOptions& trace_options,
+ const EnableRecordingDoneCallback& callback);
void OnDisableRecordingDone();
void OnEnableMonitoringDone(
- const base::debug::CategoryFilter& category_filter,
- const base::debug::TraceOptions& trace_options,
+ const base::trace_event::CategoryFilter& category_filter,
+ const base::trace_event::TraceOptions& trace_options,
const EnableMonitoringDoneCallback& callback);
void OnDisableMonitoringDone(const DisableMonitoringDoneCallback& callback);
@@ -145,23 +163,33 @@ class TracingControllerImpl : public TracingController {
// Pending acks for DisableRecording.
int pending_disable_recording_ack_count_;
TraceMessageFilterSet pending_disable_recording_filters_;
+
// Pending acks for CaptureMonitoringSnapshot.
int pending_capture_monitoring_snapshot_ack_count_;
TraceMessageFilterSet pending_capture_monitoring_filters_;
- // Pending acks for GetTraceBufferPercentFull.
- int pending_trace_buffer_percent_full_ack_count_;
- TraceMessageFilterSet pending_trace_buffer_percent_full_filters_;
- float maximum_trace_buffer_percent_full_;
+
+ // Pending acks for GetTraceLogStatus.
+ int pending_trace_log_status_ack_count_;
+ TraceMessageFilterSet pending_trace_log_status_filters_;
+ float maximum_trace_buffer_usage_;
+ size_t approximate_event_count_;
+
+ // Pending acks for memory RequestGlobalDumpPoint.
+ int pending_memory_dump_ack_count_;
+ int failed_memory_dump_count_;
+ TraceMessageFilterSet pending_memory_dump_filters_;
+ uint64 pending_memory_dump_guid_;
+ base::trace_event::MemoryDumpCallback pending_memory_dump_callback_;
#if defined(OS_CHROMEOS) || defined(OS_WIN)
bool is_system_tracing_;
#endif
bool is_recording_;
bool is_monitoring_;
- base::debug::TraceOptions trace_options_;
+ base::trace_event::TraceOptions trace_options_;
GetCategoriesDoneCallback pending_get_categories_done_callback_;
- GetTraceBufferPercentFullCallback pending_trace_buffer_percent_full_callback_;
+ GetTraceBufferUsageCallback pending_trace_buffer_usage_callback_;
std::string watch_category_name_;
std::string watch_event_name_;
@@ -171,6 +199,7 @@ class TracingControllerImpl : public TracingController {
std::set<TracingUI*> tracing_uis_;
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_controller_impl_data_sinks.cc b/chromium/content/browser/tracing/tracing_controller_impl_data_sinks.cc
new file mode 100644
index 00000000000..a6d6e37ad13
--- /dev/null
+++ b/chromium/content/browser/tracing/tracing_controller_impl_data_sinks.cc
@@ -0,0 +1,302 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#include "content/browser/tracing/tracing_controller_impl.h"
+
+#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "content/public/browser/browser_thread.h"
+#include "third_party/zlib/zlib.h"
+
+namespace content {
+
+namespace {
+
+class StringTraceDataEndpoint : public TracingController::TraceDataEndpoint {
+ public:
+ typedef base::Callback<void(base::RefCountedString*)> CompletionCallback;
+
+ explicit StringTraceDataEndpoint(CompletionCallback callback)
+ : completion_callback_(callback) {}
+
+ void ReceiveTraceFinalContents(const std::string& contents) override {
+ std::string tmp = contents;
+ scoped_refptr<base::RefCountedString> str =
+ base::RefCountedString::TakeString(&tmp);
+
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(completion_callback_, str));
+ }
+
+ private:
+ ~StringTraceDataEndpoint() override {}
+
+ CompletionCallback completion_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(StringTraceDataEndpoint);
+};
+
+class FileTraceDataEndpoint : public TracingController::TraceDataEndpoint {
+ public:
+ explicit FileTraceDataEndpoint(const base::FilePath& trace_file_path,
+ const base::Closure& callback)
+ : file_path_(trace_file_path),
+ completion_callback_(callback),
+ file_(NULL) {}
+
+ void ReceiveTraceChunk(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(&FileTraceDataEndpoint::ReceiveTraceChunkOnFileThread, this,
+ chunk_ptr));
+ }
+
+ void ReceiveTraceFinalContents(const std::string& contents) override {
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ base::Bind(&FileTraceDataEndpoint::CloseOnFileThread, this));
+ }
+
+ private:
+ ~FileTraceDataEndpoint() override { DCHECK(file_ == NULL); }
+
+ void ReceiveTraceChunkOnFileThread(
+ const scoped_refptr<base::RefCountedString> chunk) {
+ if (!OpenFileIfNeededOnFileThread())
+ return;
+ ignore_result(
+ fwrite(chunk->data().c_str(), chunk->data().size(), 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;
+ }
+ return true;
+ }
+
+ void CloseOnFileThread() {
+ if (OpenFileIfNeededOnFileThread()) {
+ base::CloseFile(file_);
+ file_ = NULL;
+ }
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&FileTraceDataEndpoint::FinalizeOnUIThread, this));
+ }
+
+ void FinalizeOnUIThread() { completion_callback_.Run(); }
+
+ base::FilePath file_path_;
+ base::Closure completion_callback_;
+ FILE* file_;
+
+ DISALLOW_COPY_AND_ASSIGN(FileTraceDataEndpoint);
+};
+
+class StringTraceDataSink : public TracingController::TraceDataSink {
+ public:
+ explicit StringTraceDataSink(
+ scoped_refptr<TracingController::TraceDataEndpoint> endpoint)
+ : endpoint_(endpoint) {}
+
+ void AddTraceChunk(const std::string& chunk) override {
+ std::string trace_string;
+ if (trace_.empty())
+ trace_string = "{\"traceEvents\":[";
+ else
+ trace_string = ",";
+ trace_string += chunk;
+
+ AddTraceChunkAndPassToEndpoint(trace_string);
+ }
+
+ void AddTraceChunkAndPassToEndpoint(const std::string& chunk) {
+ trace_ += chunk;
+
+ endpoint_->ReceiveTraceChunk(chunk);
+ }
+
+ void SetSystemTrace(const std::string& data) override {
+ system_trace_ = data;
+ }
+
+ void Close() override {
+ AddTraceChunkAndPassToEndpoint("]");
+ if (!system_trace_.empty())
+ AddTraceChunkAndPassToEndpoint(",\"systemTraceEvents\": " +
+ system_trace_);
+ AddTraceChunkAndPassToEndpoint("}");
+
+ endpoint_->ReceiveTraceFinalContents(trace_);
+ }
+
+ private:
+ ~StringTraceDataSink() override {}
+
+ scoped_refptr<TracingController::TraceDataEndpoint> endpoint_;
+ std::string trace_;
+ std::string system_trace_;
+
+ DISALLOW_COPY_AND_ASSIGN(StringTraceDataSink);
+};
+
+class CompressedStringTraceDataSink : public TracingController::TraceDataSink {
+ public:
+ explicit CompressedStringTraceDataSink(
+ scoped_refptr<TracingController::TraceDataEndpoint> endpoint)
+ : endpoint_(endpoint), already_tried_open_(false) {}
+
+ 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(&CompressedStringTraceDataSink::AddTraceChunkOnFileThread,
+ this, chunk_ptr));
+ }
+
+ void SetSystemTrace(const std::string& data) override {
+ system_trace_ = data;
+ }
+
+ void Close() override {
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ base::Bind(&CompressedStringTraceDataSink::CloseOnFileThread, this));
+ }
+
+ private:
+ ~CompressedStringTraceDataSink() override {}
+
+ bool OpenZStreamOnFileThread() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ if (stream_)
+ return true;
+
+ if (already_tried_open_)
+ return false;
+
+ already_tried_open_ = true;
+ stream_.reset(new z_stream);
+ *stream_ = {0};
+ stream_->zalloc = Z_NULL;
+ stream_->zfree = Z_NULL;
+ stream_->opaque = Z_NULL;
+
+ int result = deflateInit2(stream_.get(), 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);
+ return result == 0;
+ }
+
+ void AddTraceChunkOnFileThread(
+ const scoped_refptr<base::RefCountedString> chunk_ptr) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ std::string trace;
+ if (compressed_trace_data_.empty())
+ trace = "{\"traceEvents\":[";
+ else
+ trace = ",";
+ trace += chunk_ptr->data();
+ AddTraceChunkAndCompressOnFileThread(trace, false);
+ }
+
+ void AddTraceChunkAndCompressOnFileThread(const std::string& chunk,
+ bool finished) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ if (!OpenZStreamOnFileThread())
+ return;
+
+ const int kChunkSize = 0x4000;
+
+ char buffer[kChunkSize];
+ int err;
+ stream_->avail_in = chunk.size();
+ stream_->next_in = (unsigned char*)chunk.data();
+ do {
+ stream_->avail_out = kChunkSize;
+ stream_->next_out = (unsigned char*)buffer;
+ err = deflate(stream_.get(), finished ? Z_FINISH : Z_NO_FLUSH);
+ if (err != Z_OK && (err != Z_STREAM_END && finished)) {
+ stream_.reset();
+ return;
+ }
+
+ int bytes = kChunkSize - stream_->avail_out;
+ if (bytes) {
+ std::string compressed_chunk = std::string(buffer, bytes);
+ compressed_trace_data_ += compressed_chunk;
+ endpoint_->ReceiveTraceChunk(compressed_chunk);
+ }
+ } while (stream_->avail_out == 0);
+ }
+
+ void CloseOnFileThread() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ if (!OpenZStreamOnFileThread())
+ return;
+
+ if (compressed_trace_data_.empty())
+ AddTraceChunkAndCompressOnFileThread("{\"traceEvents\":[", false);
+
+ AddTraceChunkAndCompressOnFileThread("]", false);
+ if (!system_trace_.empty()) {
+ AddTraceChunkAndCompressOnFileThread(
+ ",\"systemTraceEvents\": " + system_trace_, false);
+ }
+ AddTraceChunkAndCompressOnFileThread("}", true);
+
+ deflateEnd(stream_.get());
+ stream_.reset();
+
+ endpoint_->ReceiveTraceFinalContents(compressed_trace_data_);
+ }
+
+ scoped_refptr<TracingController::TraceDataEndpoint> endpoint_;
+ scoped_ptr<z_stream> stream_;
+ bool already_tried_open_;
+ std::string compressed_trace_data_;
+ std::string system_trace_;
+
+ DISALLOW_COPY_AND_ASSIGN(CompressedStringTraceDataSink);
+};
+
+} // namespace
+
+scoped_refptr<TracingController::TraceDataSink>
+TracingController::CreateStringSink(
+ const base::Callback<void(base::RefCountedString*)>& callback) {
+ return new StringTraceDataSink(new StringTraceDataEndpoint(callback));
+}
+
+scoped_refptr<TracingController::TraceDataSink>
+TracingController::CreateCompressedStringSink(
+ scoped_refptr<TracingController::TraceDataEndpoint> endpoint) {
+ return new CompressedStringTraceDataSink(endpoint);
+}
+
+scoped_refptr<TracingController::TraceDataSink>
+TracingController::CreateFileSink(const base::FilePath& file_path,
+ const base::Closure& callback) {
+ return new StringTraceDataSink(
+ CreateFileEndpoint(file_path, callback));
+}
+
+scoped_refptr<TracingController::TraceDataEndpoint>
+TracingController::CreateFileEndpoint(const base::FilePath& file_path,
+ const base::Closure& callback) {
+ return new FileTraceDataEndpoint(file_path, callback);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/tracing/tracing_resources.gyp b/chromium/content/browser/tracing/tracing_resources.gyp
index 1efc0ad72c6..fcd132fadd4 100644
--- a/chromium/content/browser/tracing/tracing_resources.gyp
+++ b/chromium/content/browser/tracing/tracing_resources.gyp
@@ -58,6 +58,21 @@
'grit_cmd': ['python', '../../../tools/grit/grit.py'],
'grit_grd_file': '<(SHARED_INTERMEDIATE_DIR)/content/browser/tracing/tracing_resources.grd',
'grit_rc_header_format%': '',
+
+ 'conditions': [
+ # These scripts can skip writing generated files if they are
+ # identical to the already existing files, which avoids further
+ # build steps, like recompilation. However, a dependency (earlier
+ # build step) having a newer timestamp than an output (later
+ # build step) confuses some build systems, so only use this on
+ # ninja, which explicitly supports this use case (gyp turns all
+ # actions into ninja restat rules).
+ ['"<(GENERATOR)"=="ninja"', {
+ 'write_only_new': '1',
+ }, {
+ 'write_only_new': '0',
+ }],
+ ],
},
'inputs': [
'<(grit_grd_file)',
@@ -71,6 +86,7 @@
'-i', '<(grit_grd_file)', 'build',
'-f', '<(DEPTH)/tools/gritsettings/resource_ids',
'-o', '<(grit_out_dir)',
+ '--write-only-new=<(write_only_new)',
'-D', 'SHARED_INTERMEDIATE_DIR=<(SHARED_INTERMEDIATE_DIR)',
'<@(grit_defines)',
'<@(grit_rc_header_format)'],
diff --git a/chromium/content/browser/tracing/tracing_ui.cc b/chromium/content/browser/tracing/tracing_ui.cc
index 95e3ab92cde..58fbb753116 100644
--- a/chromium/content/browser/tracing/tracing_ui.cc
+++ b/chromium/content/browser/tracing/tracing_ui.cc
@@ -11,8 +11,6 @@
#include "base/base64.h"
#include "base/bind.h"
#include "base/bind_helpers.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"
@@ -21,25 +19,25 @@
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event.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/content_browser_client.h"
+#include "content/public/browser/trace_uploader.h"
#include "content/public/browser/tracing_controller.h"
+#include "content/public/browser/tracing_delegate.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());
@@ -54,8 +52,8 @@ void OnGotCategories(const WebUIDataSource::GotDataCallback& callback,
}
bool GetTracingOptions(const std::string& data64,
- base::debug::CategoryFilter* category_filter,
- base::debug::TraceOptions* tracing_options) {
+ base::trace_event::CategoryFilter* category_filter,
+ base::trace_event::TraceOptions* tracing_options) {
std::string data;
if (!base::Base64Decode(data64, &data)) {
LOG(ERROR) << "Options were not base64 encoded.";
@@ -86,22 +84,18 @@ bool GetTracingOptions(const std::string& data64,
bool options_ok = true;
std::string category_filter_string;
options_ok &= options->GetString("categoryFilter", &category_filter_string);
- *category_filter = base::debug::CategoryFilter(category_filter_string);
+ *category_filter = base::trace_event::CategoryFilter(category_filter_string);
+
+ std::string record_mode;
+ options_ok &=
+ options->GetString("tracingRecordMode", &record_mode);
+ options_ok &= tracing_options->SetFromString(record_mode);
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;
@@ -113,8 +107,8 @@ void OnRecordingEnabledAck(const WebUIDataSource::GotDataCallback& callback);
bool BeginRecording(const std::string& data64,
const WebUIDataSource::GotDataCallback& callback) {
- base::debug::CategoryFilter category_filter("");
- base::debug::TraceOptions tracing_options;
+ base::trace_event::CategoryFilter category_filter("");
+ base::trace_event::TraceOptions tracing_options;
if (!GetTracingOptions(data64, &category_filter, &tracing_options))
return false;
@@ -129,18 +123,34 @@ void OnRecordingEnabledAck(const WebUIDataSource::GotDataCallback& callback) {
callback.Run(res);
}
-void OnTraceBufferPercentFullResult(
- const WebUIDataSource::GotDataCallback& callback, float result) {
- std::string str = base::DoubleToString(result);
+void OnTraceBufferUsageResult(const WebUIDataSource::GotDataCallback& callback,
+ float percent_full,
+ size_t approximate_event_count) {
+ std::string str = base::DoubleToString(percent_full);
callback.Run(base::RefCountedString::TakeString(&str));
}
+void OnTraceBufferStatusResult(const WebUIDataSource::GotDataCallback& callback,
+ float percent_full,
+ size_t approximate_event_count) {
+ scoped_ptr<base::DictionaryValue> status(new base::DictionaryValue());
+ status->SetDouble("percentFull", percent_full);
+ status->SetInteger("approximateEventCount", approximate_event_count);
+
+ std::string status_json;
+ base::JSONWriter::Write(status.get(), &status_json);
+
+ base::RefCountedString* status_base64 = new base::RefCountedString();
+ base::Base64Encode(status_json, &status_base64->data());
+ callback.Run(status_base64);
+}
+
void OnMonitoringEnabledAck(const WebUIDataSource::GotDataCallback& callback);
bool EnableMonitoring(const std::string& data64,
const WebUIDataSource::GotDataCallback& callback) {
- base::debug::TraceOptions tracing_options;
- base::debug::CategoryFilter category_filter("");
+ base::trace_event::TraceOptions tracing_options;
+ base::trace_event::CategoryFilter category_filter("");
if (!GetTracingOptions(data64, &category_filter, &tracing_options))
return false;
@@ -162,8 +172,8 @@ void OnMonitoringDisabled(const WebUIDataSource::GotDataCallback& callback) {
void GetMonitoringStatus(const WebUIDataSource::GotDataCallback& callback) {
bool is_monitoring;
- base::debug::CategoryFilter category_filter("");
- base::debug::TraceOptions options;
+ base::trace_event::CategoryFilter category_filter("");
+ base::trace_event::TraceOptions options;
TracingController::GetInstance()->GetMonitoringStatus(
&is_monitoring, &category_filter, &options);
@@ -174,7 +184,7 @@ void GetMonitoringStatus(const WebUIDataSource::GotDataCallback& callback) {
monitoring_options->SetBoolean("useSystemTracing", options.enable_systrace);
monitoring_options->SetBoolean(
"useContinuousTracing",
- options.record_mode == base::debug::RECORD_CONTINUOUSLY);
+ options.record_mode == base::trace_event::RECORD_CONTINUOUSLY);
monitoring_options->SetBoolean("useSampling", options.enable_sampling);
std::string monitoring_options_json;
@@ -205,8 +215,12 @@ bool OnBeginJSONRequest(const std::string& path,
return BeginRecording(data, callback);
}
if (path == "json/get_buffer_percent_full") {
- return TracingController::GetInstance()->GetTraceBufferPercentFull(
- base::Bind(OnTraceBufferPercentFullResult, callback));
+ return TracingController::GetInstance()->GetTraceBufferUsage(
+ base::Bind(OnTraceBufferUsageResult, callback));
+ }
+ if (path == "json/get_buffer_status") {
+ return TracingController::GetInstance()->GetTraceBufferUsage(
+ base::Bind(OnTraceBufferStatusResult, callback));
}
if (path == "json/end_recording") {
return TracingController::GetInstance()->DisableRecording(
@@ -261,6 +275,7 @@ bool OnTracingRequest(const std::string& path,
TracingUI::TracingUI(WebUI* web_ui)
: WebUIController(web_ui),
+ delegate_(GetContentClient()->browser()->GetTracingDelegate()),
weak_factory_(this) {
web_ui->RegisterMessageCallback(
"doUpload",
@@ -289,27 +304,22 @@ void TracingUI::OnMonitoringStateChanged(bool 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();
+ std::string file_contents;
+ if (!args || args->empty() || !args->GetString(0, &file_contents)) {
+ web_ui()->CallJavascriptFunction("onUploadError",
+ base::StringValue("Missing data"));
+ return;
}
- if (upload_url.empty()) {
+ if (!delegate_) {
web_ui()->CallJavascriptFunction("onUploadError",
- base::StringValue("Upload URL empty or invalid"));
+ base::StringValue("Not implemented"));
return;
}
- std::string file_contents;
- if (!args || args->empty() || !args->GetString(0, &file_contents)) {
+ if (trace_uploader_) {
web_ui()->CallJavascriptFunction("onUploadError",
- base::StringValue("Missing data"));
+ base::StringValue("Upload in progress"));
return;
}
@@ -320,44 +330,10 @@ void TracingUI::DoUpload(const base::ListValue* args) {
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));
+ trace_uploader_ = delegate_->GetTraceUploader(
+ web_ui()->GetWebContents()->GetBrowserContext()->GetRequestContext());
+ DCHECK(trace_uploader_);
+ trace_uploader_->DoUpload(file_contents, progress_callback, done_callback);
// TODO(mmandlis): Add support for stopping the upload in progress.
}
@@ -372,15 +348,15 @@ void TracingUI::OnTraceUploadProgress(int64 current, int64 total) {
}
void TracingUI::OnTraceUploadComplete(bool success,
- const std::string& report_id,
- const std::string& error_message) {
+ const std::string& feedback) {
if (success) {
web_ui()->CallJavascriptFunction("onUploadComplete",
- base::StringValue(report_id));
+ base::StringValue(feedback));
} else {
web_ui()->CallJavascriptFunction("onUploadError",
- base::StringValue(error_message));
+ base::StringValue(feedback));
}
+ trace_uploader_.reset();
}
} // namespace content
diff --git a/chromium/content/browser/tracing/tracing_ui.h b/chromium/content/browser/tracing/tracing_ui.h
index 7b69337c091..4378154d36c 100644
--- a/chromium/content/browser/tracing/tracing_ui.h
+++ b/chromium/content/browser/tracing/tracing_ui.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CONTENT_BROWSER_TRACING_UI_H_
-#define CONTENT_BROWSER_TRACING_UI_H_
+#ifndef CONTENT_BROWSER_TRACING_TRACING_UI_H_
+#define CONTENT_BROWSER_TRACING_TRACING_UI_H_
#include <map>
#include <string>
@@ -13,6 +13,9 @@
namespace content {
+class TraceUploader;
+class TracingDelegate;
+
// The C++ back-end for the chrome://tracing webui page.
class CONTENT_EXPORT TracingUI : public WebUIController {
public:
@@ -21,11 +24,11 @@ class CONTENT_EXPORT TracingUI : public WebUIController {
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);
+ void OnTraceUploadComplete(bool success, const std::string& feedback);
private:
+ scoped_ptr<TracingDelegate> delegate_;
+ scoped_ptr<TraceUploader> trace_uploader_;
base::WeakPtrFactory<TracingUI> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(TracingUI);
@@ -33,4 +36,4 @@ class CONTENT_EXPORT TracingUI : public WebUIController {
} // namespace content
-#endif // CONTENT_BROWSER_TRACING_UI_H_
+#endif // CONTENT_BROWSER_TRACING_TRACING_UI_H_
diff --git a/chromium/content/browser/transition_browsertest.cc b/chromium/content/browser/transition_browsertest.cc
index 1fba073174c..6b2eba35006 100644
--- a/chromium/content/browser/transition_browsertest.cc
+++ b/chromium/content/browser/transition_browsertest.cc
@@ -26,7 +26,7 @@ class TransitionBrowserTest : public ContentBrowserTest {
public:
TransitionBrowserTest() {}
- void SetUpCommandLine(CommandLine* command_line) override {
+ void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitch(
switches::kEnableExperimentalWebPlatformFeatures);
}
diff --git a/chromium/content/browser/transition_request_manager.cc b/chromium/content/browser/transition_request_manager.cc
index e3f4317695f..f5f1e9762a4 100644
--- a/chromium/content/browser/transition_request_manager.cc
+++ b/chromium/content/browser/transition_request_manager.cc
@@ -139,18 +139,33 @@ bool TransitionRequestManager::TransitionRequestData::FindEntry(
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(
+ CHECK(base::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;
+ base::FieldTrialList::FindFullName("NavigationTransitions") ==
+ "Enabled");
+
+ for (const AllowedEntry& allowed_entry : allowed_entries_) {
+ // Note: This is a small subset of the CSP source-list standard; once the
+ // full CSP support is moved from the renderer to the browser, we should
+ // use that instead.
+ bool is_valid = (allowed_entry.allowed_destination_host_pattern == "*");
+ if (!is_valid) {
+ GURL allowed_host(allowed_entry.allowed_destination_host_pattern);
+ if (allowed_host.is_valid() &&
+ (allowed_host.GetOrigin() == request_url.GetOrigin())) {
+ is_valid = true;
+ }
+ }
+
+ if (is_valid) {
+ transition_data->markup = allowed_entry.markup;
+ transition_data->css_selector = allowed_entry.css_selector;
+ transition_data->elements = allowed_entry.elements;
+ return true;
+ }
+ }
+
+ return false;
}
bool TransitionRequestManager::GetPendingTransitionRequest(
diff --git a/chromium/content/browser/transition_request_manager_unittest.cc b/chromium/content/browser/transition_request_manager_unittest.cc
index 95bc01e0242..02978b7e43a 100644
--- a/chromium/content/browser/transition_request_manager_unittest.cc
+++ b/chromium/content/browser/transition_request_manager_unittest.cc
@@ -2,7 +2,10 @@
// 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/transition_request_manager.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/test/test_browser_thread_bundle.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -11,7 +14,14 @@ namespace content {
class TransitionRequestManagerTest : public testing::Test {
public:
+ TransitionRequestManagerTest()
+ : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableExperimentalWebPlatformFeatures);
+ }
+
~TransitionRequestManagerTest() override {}
+ TestBrowserThreadBundle thread_bundle_;
};
TEST_F(TransitionRequestManagerTest,
@@ -103,4 +113,60 @@ TEST_F(TransitionRequestManagerTest,
entering_stylesheets[2].spec().c_str());
}
+// Tests that the TransitionRequestManager correctly performs origin checks
+// and fetches the correct transition data.
+//
+// We add data for http://www.foo.com and http://www.test.com URLs, then check
+// that a navigation to test.com gives the latter data. A third URL should
+// give no fallback data, before we add a fallback and check that it's now
+// provided for the third URL.
+TEST_F(TransitionRequestManagerTest, AllowedHostCheck) {
+ TransitionRequestManager* request_manager =
+ TransitionRequestManager::GetInstance();
+
+ const int render_process_id = 42;
+ const int render_frame_id = 4242;
+
+ const std::string test_dot_com_css_selector("#correctTransitionElement");
+ const std::string fallback_css_selector("#fallbackTransitionElement");
+ const GURL test_dot_com_url("http://www.test.com");
+ const std::string markup("<b>Hello World</b>");
+
+ // 1. Add transition data for http://www.foo.com URLs.
+ request_manager->AddPendingTransitionRequestData(
+ render_process_id, render_frame_id, "http://www.foo.com",
+ "#wrongTransition", markup, std::vector<TransitionElement>());
+ // 2. Add transition data for http://www.test.com URLs
+ request_manager->AddPendingTransitionRequestData(
+ render_process_id, render_frame_id, test_dot_com_url.spec(),
+ test_dot_com_css_selector, markup, std::vector<TransitionElement>());
+
+ // 3. Check that a navigation to http://www.test.com finds the data from 2).
+ TransitionLayerData transition_layer_data;
+ bool found = request_manager->GetPendingTransitionRequest(
+ render_process_id, render_frame_id, test_dot_com_url,
+ &transition_layer_data);
+ ASSERT_TRUE(found);
+ EXPECT_TRUE(transition_layer_data.css_selector == test_dot_com_css_selector);
+
+ // 4. Check that a navigation to http://www.unrelated.com finds no data.
+ const GURL unrelated_dot_com_url("http://www.unrelated.com");
+ found = request_manager->GetPendingTransitionRequest(
+ render_process_id, render_frame_id, unrelated_dot_com_url,
+ &transition_layer_data);
+ EXPECT_FALSE(found);
+
+ // 5. Add transition data for '*', i.e. matching any navigation.
+ request_manager->AddPendingTransitionRequestData(
+ render_process_id, render_frame_id, "*", fallback_css_selector, markup,
+ std::vector<TransitionElement>());
+
+ // 6. Check that a navigation to http://wwww.unrelated.com now finds an entry.
+ found = request_manager->GetPendingTransitionRequest(
+ render_process_id, render_frame_id, unrelated_dot_com_url,
+ &transition_layer_data);
+ ASSERT_TRUE(found);
+ EXPECT_TRUE(transition_layer_data.css_selector == fallback_css_selector);
+}
+
} // namespace content
diff --git a/chromium/content/browser/udev_linux.cc b/chromium/content/browser/udev_linux.cc
index 80c929bf0ec..dfcb52b9f2e 100644
--- a/chromium/content/browser/udev_linux.cc
+++ b/chromium/content/browser/udev_linux.cc
@@ -4,30 +4,28 @@
#include "content/browser/udev_linux.h"
-#include <libudev.h>
-
#include "base/message_loop/message_loop.h"
namespace content {
UdevLinux::UdevLinux(const std::vector<UdevMonitorFilter>& filters,
const UdevNotificationCallback& callback)
- : udev_(udev_new()),
- monitor_(udev_monitor_new_from_netlink(udev_.get(), "udev")),
+ : udev_(device::udev_new()),
+ monitor_(device::udev_monitor_new_from_netlink(udev_.get(), "udev")),
monitor_fd_(-1),
callback_(callback) {
CHECK(udev_);
CHECK(monitor_);
for (size_t i = 0; i < filters.size(); ++i) {
- int ret = udev_monitor_filter_add_match_subsystem_devtype(
+ int ret = device::udev_monitor_filter_add_match_subsystem_devtype(
monitor_.get(), filters[i].subsystem, filters[i].devtype);
CHECK_EQ(0, ret);
}
- int ret = udev_monitor_enable_receiving(monitor_.get());
+ int ret = device::udev_monitor_enable_receiving(monitor_.get());
CHECK_EQ(0, ret);
- monitor_fd_ = udev_monitor_get_fd(monitor_.get());
+ monitor_fd_ = device::udev_monitor_get_fd(monitor_.get());
CHECK_GE(monitor_fd_, 0);
bool success = base::MessageLoopForIO::current()->WatchFileDescriptor(
@@ -53,7 +51,7 @@ void UdevLinux::OnFileCanReadWithoutBlocking(int fd) {
// representing the device which changed and what type of change occured.
DCHECK_EQ(monitor_fd_, fd);
device::ScopedUdevDevicePtr dev(
- udev_monitor_receive_device(monitor_.get()));
+ device::udev_monitor_receive_device(monitor_.get()));
if (!dev)
return;
diff --git a/chromium/content/browser/utility_process_host_impl.cc b/chromium/content/browser/utility_process_host_impl.cc
index 0d24e3a5e69..f6b43bec6aa 100644
--- a/chromium/content/browser/utility_process_host_impl.cc
+++ b/chromium/content/browser/utility_process_host_impl.cc
@@ -4,19 +4,23 @@
#include "content/browser/utility_process_host_impl.h"
+#include "base/base_switches.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/command_line.h"
#include "base/lazy_instance.h"
#include "base/message_loop/message_loop.h"
+#include "base/process/process_handle.h"
#include "base/run_loop.h"
#include "base/sequenced_task_runner.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
#include "content/browser/browser_child_process_host_impl.h"
+#include "content/browser/mojo/mojo_application_host.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/common/child_process_host_impl.h"
+#include "content/common/in_process_child_thread_params.h"
#include "content/common/utility_messages.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
@@ -34,8 +38,9 @@ class UtilitySandboxedProcessLauncherDelegate
: public SandboxedProcessLauncherDelegate {
public:
UtilitySandboxedProcessLauncherDelegate(const base::FilePath& exposed_dir,
- bool launch_elevated, bool no_sandbox,
- base::EnvironmentMap& env,
+ bool launch_elevated,
+ bool no_sandbox,
+ const base::EnvironmentMap& env,
ChildProcessHost* host)
: exposed_dir_(exposed_dir),
#if defined(OS_WIN)
@@ -50,11 +55,9 @@ class UtilitySandboxedProcessLauncherDelegate
~UtilitySandboxedProcessLauncherDelegate() override {}
#if defined(OS_WIN)
- virtual bool ShouldLaunchElevated() override {
- return launch_elevated_;
- }
- virtual void PreSandbox(bool* disable_default_policy,
- base::FilePath* exposed_dir) override {
+ bool ShouldLaunchElevated() override { return launch_elevated_; }
+ void PreSandbox(bool* disable_default_policy,
+ base::FilePath* exposed_dir) override {
*exposed_dir = exposed_dir_;
}
#elif defined(OS_POSIX)
@@ -67,8 +70,7 @@ class UtilitySandboxedProcessLauncherDelegate
#endif // OS_WIN
private:
-
- base::FilePath exposed_dir_;
+ base::FilePath exposed_dir_;
#if defined(OS_WIN)
bool launch_elevated_;
@@ -106,13 +108,21 @@ UtilityProcessHostImpl::UtilityProcessHostImpl(
#else
child_flags_(ChildProcessHost::CHILD_NORMAL),
#endif
- started_(false) {
+ started_(false),
+ name_(base::ASCIIToUTF16("utility process")) {
}
UtilityProcessHostImpl::~UtilityProcessHostImpl() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (is_batch_mode_)
EndBatchMode();
+
+ // We could be destroyed as a result of Chrome shutdown. When that happens,
+ // the Mojo channel doesn't get the opportunity to shut down cleanly because
+ // it posts to the IO thread (the current thread) which is being destroyed.
+ // To guarantee proper shutdown of the Mojo channel, do it explicitly here.
+ if (mojo_application_host_)
+ mojo_application_host_->ShutdownOnIOThread();
}
bool UtilityProcessHostImpl::Send(IPC::Message* message) {
@@ -166,6 +176,26 @@ void UtilityProcessHostImpl::SetEnv(const base::EnvironmentMap& env) {
#endif // OS_POSIX
+bool UtilityProcessHostImpl::StartMojoMode() {
+ CHECK(!mojo_application_host_);
+ mojo_application_host_.reset(new MojoApplicationHost);
+
+ bool mojo_result = mojo_application_host_->Init();
+ if (!mojo_result)
+ return false;
+
+ return StartProcess();
+}
+
+ServiceRegistry* UtilityProcessHostImpl::GetServiceRegistry() {
+ DCHECK(mojo_application_host_);
+ return mojo_application_host_->service_registry();
+}
+
+void UtilityProcessHostImpl::SetName(const base::string16& name) {
+ name_ = name;
+}
+
bool UtilityProcessHostImpl::StartProcess() {
if (started_)
return true;
@@ -177,7 +207,7 @@ bool UtilityProcessHostImpl::StartProcess() {
// Name must be set or metrics_service will crash in any test which
// launches a UtilityProcessHost.
process_.reset(new BrowserChildProcessHostImpl(PROCESS_TYPE_UTILITY, this));
- process_->SetName(base::ASCIIToUTF16("utility process"));
+ process_->SetName(name_);
std::string channel_id = process_->GetHost()->CreateChannel();
if (channel_id.empty())
@@ -187,14 +217,16 @@ bool UtilityProcessHostImpl::StartProcess() {
DCHECK(g_utility_main_thread_factory);
// See comment in RenderProcessHostImpl::Init() for the background on why we
// support single process mode this way.
- in_process_thread_.reset(g_utility_main_thread_factory(channel_id));
+ in_process_thread_.reset(
+ g_utility_main_thread_factory(InProcessChildThreadParams(
+ channel_id, BrowserThread::UnsafeGetMessageLoopForThread(
+ BrowserThread::IO)->task_runner())));
in_process_thread_->Start();
} else {
const base::CommandLine& browser_command_line =
*base::CommandLine::ForCurrentProcess();
int child_flags = child_flags_;
-#if defined(OS_POSIX)
bool has_cmd_prefix = browser_command_line.HasSwitch(
switches::kUtilityCmdPrefix);
@@ -205,7 +237,6 @@ bool UtilityProcessHostImpl::StartProcess() {
// a similar case with Valgrind.
if (has_cmd_prefix)
child_flags = ChildProcessHost::CHILD_NORMAL;
-#endif
base::FilePath exe_path = ChildProcessHost::GetChildPath(child_flags);
if (exe_path.empty()) {
@@ -220,16 +251,21 @@ bool UtilityProcessHostImpl::StartProcess() {
std::string locale = GetContentClient()->browser()->GetApplicationLocale();
cmd_line->AppendSwitchASCII(switches::kLang, locale);
- if (no_sandbox_ || browser_command_line.HasSwitch(switches::kNoSandbox))
+ if (no_sandbox_)
cmd_line->AppendSwitch(switches::kNoSandbox);
+
+ // Browser command-line switches to propagate to the utility process.
+ static const char* const kSwitchNames[] = {
+ switches::kDebugPluginLoading,
+ switches::kNoSandbox,
+ switches::kProfilerTiming,
#if defined(OS_MACOSX)
- if (browser_command_line.HasSwitch(switches::kEnableSandboxLogging))
- cmd_line->AppendSwitch(switches::kEnableSandboxLogging);
+ switches::kEnableSandboxLogging,
#endif
- if (browser_command_line.HasSwitch(switches::kDebugPluginLoading))
- cmd_line->AppendSwitch(switches::kDebugPluginLoading);
+ };
+ cmd_line->CopySwitchesFrom(browser_command_line, kSwitchNames,
+ arraysize(kSwitchNames));
-#if defined(OS_POSIX)
if (has_cmd_prefix) {
// Launch the utility child process with some prefix
// (usually "xterm -e gdb --args").
@@ -241,7 +277,6 @@ bool UtilityProcessHostImpl::StartProcess() {
cmd_line->AppendSwitchPath(switches::kUtilityProcessAllowedDir,
exposed_dir_);
}
-#endif
if (is_mdns_enabled_)
cmd_line->AppendSwitch(switches::kUtilityProcessEnableMDns);
@@ -257,7 +292,8 @@ bool UtilityProcessHostImpl::StartProcess() {
run_elevated_,
no_sandbox_, env_,
process_->GetHost()),
- cmd_line);
+ cmd_line,
+ true);
}
return true;
@@ -297,4 +333,16 @@ void UtilityProcessHostImpl::OnProcessCrashed(int exit_code) {
exit_code));
}
+void UtilityProcessHostImpl::OnProcessLaunched() {
+ if (mojo_application_host_) {
+ base::ProcessHandle handle;
+ if (RenderProcessHost::run_renderer_in_process())
+ handle = base::GetCurrentProcessHandle();
+ else
+ handle = process_->GetData().handle;
+
+ mojo_application_host_->Activate(this, handle);
+ }
+}
+
} // namespace content
diff --git a/chromium/content/browser/utility_process_host_impl.h b/chromium/content/browser/utility_process_host_impl.h
index c310e9b4bf0..f988b8a96cd 100644
--- a/chromium/content/browser/utility_process_host_impl.h
+++ b/chromium/content/browser/utility_process_host_impl.h
@@ -24,9 +24,11 @@ class Thread;
namespace content {
class BrowserChildProcessHostImpl;
+class InProcessChildThreadParams;
+class MojoApplicationHost;
typedef base::Thread* (*UtilityMainThreadFactoryFunction)(
- const std::string& id);
+ const InProcessChildThreadParams&);
class CONTENT_EXPORT UtilityProcessHostImpl
: public NON_EXPORTED_BASE(UtilityProcessHost),
@@ -48,12 +50,15 @@ class CONTENT_EXPORT UtilityProcessHostImpl
void EnableMDns() override;
void DisableSandbox() override;
#if defined(OS_WIN)
- virtual void ElevatePrivileges() override;
+ void ElevatePrivileges() override;
#endif
const ChildProcessData& GetData() override;
#if defined(OS_POSIX)
void SetEnv(const base::EnvironmentMap& env) override;
#endif
+ bool StartMojoMode() override;
+ ServiceRegistry* GetServiceRegistry() override;
+ void SetName(const base::string16& name) override;
void set_child_flags(int flags) { child_flags_ = flags; }
@@ -66,6 +71,7 @@ class CONTENT_EXPORT UtilityProcessHostImpl
bool OnMessageReceived(const IPC::Message& message) override;
void OnProcessLaunchFailed() override;
void OnProcessCrashed(int exit_code) override;
+ void OnProcessLaunched() override;
// A pointer to our client interface, who will be informed of progress.
scoped_refptr<UtilityProcessHostClient> client_;
@@ -93,11 +99,19 @@ class CONTENT_EXPORT UtilityProcessHostImpl
bool started_;
+ // A user-visible name identifying this process. Used to indentify this
+ // process in the task manager.
+ base::string16 name_;
+
scoped_ptr<BrowserChildProcessHostImpl> process_;
// Used in single-process mode instead of process_.
scoped_ptr<base::Thread> in_process_thread_;
+ // Browser-side Mojo endpoint which sets up a Mojo channel with the child
+ // process and contains the browser's ServiceRegistry.
+ scoped_ptr<MojoApplicationHost> mojo_application_host_;
+
DISALLOW_COPY_AND_ASSIGN(UtilityProcessHostImpl);
};
diff --git a/chromium/content/browser/vibration/vibration_message_filter.cc b/chromium/content/browser/vibration/vibration_message_filter.cc
deleted file mode 100644
index fbc9041c71f..00000000000
--- a/chromium/content/browser/vibration/vibration_message_filter.cc
+++ /dev/null
@@ -1,67 +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/vibration/vibration_message_filter.h"
-
-#include <algorithm>
-
-#include "base/numerics/safe_conversions.h"
-#include "content/common/view_messages.h"
-#include "content/public/browser/content_browser_client.h"
-#include "content/public/browser/vibration_provider.h"
-#include "content/public/common/content_client.h"
-#include "third_party/WebKit/public/platform/WebVibration.h"
-
-namespace content {
-
-// Minimum duration of a vibration is 1 millisecond.
-const int64 kMinimumVibrationDurationMs = 1;
-
-VibrationMessageFilter::VibrationMessageFilter()
- : BrowserMessageFilter(ViewMsgStart) {
- provider_.reset(GetContentClient()->browser()->OverrideVibrationProvider());
- if (!provider_.get())
- provider_.reset(CreateProvider());
-}
-
-VibrationMessageFilter::~VibrationMessageFilter() {
-}
-
-bool VibrationMessageFilter::OnMessageReceived(
- const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(VibrationMessageFilter, message)
- IPC_MESSAGE_HANDLER(ViewHostMsg_Vibrate, OnVibrate)
- IPC_MESSAGE_HANDLER(ViewHostMsg_CancelVibration, OnCancelVibration)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-void VibrationMessageFilter::OnVibrate(int64 milliseconds) {
- if (!provider_.get())
- return;
-
- // Though the Blink implementation already sanitizes vibration times, don't
- // trust any values passed from the renderer.
- milliseconds = std::max(kMinimumVibrationDurationMs, std::min(milliseconds,
- base::checked_cast<int64>(blink::kVibrationDurationMax)));
-
- provider_->Vibrate(milliseconds);
-}
-
-void VibrationMessageFilter::OnCancelVibration() {
- if (!provider_.get())
- return;
-
- provider_->CancelVibration();
-}
-
-#if !defined(OS_ANDROID)
-// static
-VibrationProvider* VibrationMessageFilter::CreateProvider() {
- return NULL;
-}
-#endif
-} // namespace content
diff --git a/chromium/content/browser/vibration/vibration_message_filter.h b/chromium/content/browser/vibration/vibration_message_filter.h
deleted file mode 100644
index 19e0e6121db..00000000000
--- a/chromium/content/browser/vibration/vibration_message_filter.h
+++ /dev/null
@@ -1,34 +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_VIBRATION_VIBRATION_MESSAGE_FILTER_H_
-#define CONTENT_BROWSER_VIBRATION_VIBRATION_MESSAGE_FILTER_H_
-
-#include "content/public/browser/browser_message_filter.h"
-
-namespace content {
-
-class VibrationProvider;
-
-// VibrationMessageFilter is a browser filter for Vibration messages.
-class VibrationMessageFilter : public BrowserMessageFilter {
- public:
- VibrationMessageFilter();
-
- private:
- ~VibrationMessageFilter() override;
- // BrowserMessageFilter implementation.
- bool OnMessageReceived(const IPC::Message& message) override;
-
- void OnVibrate(int64 milliseconds);
- void OnCancelVibration();
- static VibrationProvider* CreateProvider();
-
- scoped_ptr<VibrationProvider> provider_;
- DISALLOW_COPY_AND_ASSIGN(VibrationMessageFilter);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_VIBRATION_VIBRATION_MESSAGE_FILTER_H_
diff --git a/chromium/content/browser/vibration/vibration_provider_android.cc b/chromium/content/browser/vibration/vibration_provider_android.cc
deleted file mode 100644
index 4694f4ea6d0..00000000000
--- a/chromium/content/browser/vibration/vibration_provider_android.cc
+++ /dev/null
@@ -1,56 +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/vibration/vibration_provider_android.h"
-
-#include <algorithm>
-
-#include "content/browser/vibration/vibration_message_filter.h"
-#include "content/common/view_messages.h"
-#include "jni/VibrationProvider_jni.h"
-#include "third_party/WebKit/public/platform/WebVibration.h"
-
-using base::android::AttachCurrentThread;
-
-namespace content {
-
-VibrationProviderAndroid::VibrationProviderAndroid() {
-}
-
-VibrationProviderAndroid::~VibrationProviderAndroid() {
-}
-
-// static
-bool VibrationProviderAndroid::Register(JNIEnv* env) {
- return RegisterNativesImpl(env);
-}
-
-void VibrationProviderAndroid::Vibrate(int64 milliseconds) {
- if (j_vibration_provider_.is_null()) {
- j_vibration_provider_.Reset(
- Java_VibrationProvider_create(
- AttachCurrentThread(),
- base::android::GetApplicationContext()));
- }
- Java_VibrationProvider_vibrate(AttachCurrentThread(),
- j_vibration_provider_.obj(),
- milliseconds);
-}
-
-void VibrationProviderAndroid::CancelVibration() {
- // If somehow a cancel message is received before this object was
- // instantiated, it means there is no current vibration anyway. Just return.
- if (j_vibration_provider_.is_null())
- return;
-
- Java_VibrationProvider_cancelVibration(AttachCurrentThread(),
- j_vibration_provider_.obj());
-}
-
-// static
-VibrationProvider* VibrationMessageFilter::CreateProvider() {
- return new VibrationProviderAndroid();
-}
-
-} // namespace content
diff --git a/chromium/content/browser/vibration/vibration_provider_android.h b/chromium/content/browser/vibration/vibration_provider_android.h
deleted file mode 100644
index e0bd1c1d7cb..00000000000
--- a/chromium/content/browser/vibration/vibration_provider_android.h
+++ /dev/null
@@ -1,30 +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_VIBRATION_VIBRATION_PROVIDER_ANDROID_H_
-#define CONTENT_BROWSER_VIBRATION_VIBRATION_PROVIDER_ANDROID_H_
-
-#include "base/android/jni_android.h"
-#include "content/public/browser/vibration_provider.h"
-
-namespace content {
-
-class VibrationProviderAndroid : public VibrationProvider {
- public:
- VibrationProviderAndroid();
-
- static bool Register(JNIEnv* env);
-
- private:
- virtual ~VibrationProviderAndroid();
-
- virtual void Vibrate(int64 milliseconds) override;
- virtual void CancelVibration() override;
-
- base::android::ScopedJavaGlobalRef<jobject> j_vibration_provider_;
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_VIBRATION_VIBRATION_PROVIDER_ANDROID_H_
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 406f5545e28..46ff45adc4a 100644
--- a/chromium/content/browser/web_contents/aura/gesture_nav_simple.cc
+++ b/chromium/content/browser/web_contents/aura/gesture_nav_simple.cc
@@ -16,6 +16,7 @@
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/compositor/layer_delegate.h"
+#include "ui/compositor/paint_recorder.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/gfx/animation/tween.h"
#include "ui/gfx/canvas.h"
@@ -53,10 +54,10 @@ class DeleteAfterAnimation : public ui::ImplicitAnimationObserver {
private:
friend class base::DeleteHelper<DeleteAfterAnimation<T> >;
- virtual ~DeleteAfterAnimation() {}
+ ~DeleteAfterAnimation() override {}
// ui::ImplicitAnimationObserver:
- virtual void OnImplicitAnimationsCompleted() override {
+ 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.
@@ -84,19 +85,19 @@ class ArrowLayerDelegate : public ui::LayerDelegate {
private:
// ui::LayerDelegate:
- void OnPaintLayer(gfx::Canvas* canvas) override {
+ void OnPaintLayer(const ui::PaintContext& context) override {
SkPaint paint;
paint.setColor(SkColorSetARGB(0xa0, 0, 0, 0));
paint.setStyle(SkPaint::kFill_Style);
paint.setAntiAlias(true);
- canvas->DrawCircle(
+ ui::PaintRecorder recorder(context);
+ recorder.canvas()->DrawCircle(
gfx::Point(left_arrow_ ? 0 : kArrowWidth, kArrowHeight / 2),
- kArrowWidth,
- paint);
- canvas->DrawImageInt(*image_.ToImageSkia(),
- left_arrow_ ? 0 : kArrowWidth - image_.Width(),
- (kArrowHeight - image_.Height()) / 2);
+ kArrowWidth, paint);
+ recorder.canvas()->DrawImageInt(
+ *image_.ToImageSkia(), left_arrow_ ? 0 : kArrowWidth - image_.Width(),
+ (kArrowHeight - image_.Height()) / 2);
}
void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override {}
diff --git a/chromium/content/browser/web_contents/aura/image_window_delegate.cc b/chromium/content/browser/web_contents/aura/image_window_delegate.cc
deleted file mode 100644
index ccfd2c5bcb9..00000000000
--- a/chromium/content/browser/web_contents/aura/image_window_delegate.cc
+++ /dev/null
@@ -1,97 +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/web_contents/aura/image_window_delegate.h"
-
-#include "ui/base/cursor/cursor.h"
-#include "ui/base/hit_test.h"
-#include "ui/compositor/compositor.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/image/image.h"
-#include "ui/gfx/image/image_skia.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/size.h"
-
-namespace content {
-
-ImageWindowDelegate::ImageWindowDelegate()
- : size_mismatch_(false) {
-}
-
-ImageWindowDelegate::~ImageWindowDelegate() {
-}
-
-void ImageWindowDelegate::SetImage(const gfx::Image& image) {
- image_ = image;
- if (!window_size_.IsEmpty() && !image_.IsEmpty())
- size_mismatch_ = window_size_ != image_.AsImageSkia().size();
-}
-
-gfx::Size ImageWindowDelegate::GetMinimumSize() const {
- return gfx::Size();
-}
-
-gfx::Size ImageWindowDelegate::GetMaximumSize() const {
- return gfx::Size();
-}
-
-void ImageWindowDelegate::OnBoundsChanged(const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds) {
- window_size_ = new_bounds.size();
- if (!image_.IsEmpty())
- size_mismatch_ = window_size_ != image_.AsImageSkia().size();
-}
-
-gfx::NativeCursor ImageWindowDelegate::GetCursor(const gfx::Point& point) {
- return gfx::kNullCursor;
-}
-
-int ImageWindowDelegate::GetNonClientComponent(const gfx::Point& point) const {
- return HTNOWHERE;
-}
-
-bool ImageWindowDelegate::ShouldDescendIntoChildForEventHandling(
- aura::Window* child,
- const gfx::Point& location) {
- return false;
-}
-
-bool ImageWindowDelegate::CanFocus() {
- return false;
-}
-
-void ImageWindowDelegate::OnCaptureLost() {
-}
-
-void ImageWindowDelegate::OnPaint(gfx::Canvas* canvas) {
- if (image_.IsEmpty()) {
- canvas->DrawColor(SK_ColorWHITE);
- } else {
- if (size_mismatch_)
- canvas->DrawColor(SK_ColorWHITE);
- canvas->DrawImageInt(image_.AsImageSkia(), 0, 0);
- }
-}
-
-void ImageWindowDelegate::OnDeviceScaleFactorChanged(float scale_factor) {
-}
-
-void ImageWindowDelegate::OnWindowDestroying(aura::Window* window) {
-}
-
-void ImageWindowDelegate::OnWindowDestroyed(aura::Window* window) {
- delete this;
-}
-
-void ImageWindowDelegate::OnWindowTargetVisibilityChanged(bool visible) {
-}
-
-bool ImageWindowDelegate::HasHitTestMask() const {
- return false;
-}
-
-void ImageWindowDelegate::GetHitTestMask(gfx::Path* mask) const {
-}
-
-} // namespace content
diff --git a/chromium/content/browser/web_contents/aura/image_window_delegate.h b/chromium/content/browser/web_contents/aura/image_window_delegate.h
deleted file mode 100644
index 53cf88e79eb..00000000000
--- a/chromium/content/browser/web_contents/aura/image_window_delegate.h
+++ /dev/null
@@ -1,61 +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_WEB_CONTENTS_AURA_IMAGE_WINDOW_DELEGATE_H_
-#define CONTENT_BROWSER_WEB_CONTENTS_AURA_IMAGE_WINDOW_DELEGATE_H_
-
-#include "content/common/content_export.h"
-#include "ui/aura/window_delegate.h"
-#include "ui/gfx/image/image.h"
-#include "ui/gfx/size.h"
-
-namespace content {
-
-// An ImageWindowDelegate paints an image for a Window. The delegate destroys
-// itself when the Window is destroyed. The delegate does not consume any event.
-class CONTENT_EXPORT ImageWindowDelegate : public aura::WindowDelegate {
- public:
- ImageWindowDelegate();
-
- void SetImage(const gfx::Image& image);
- bool has_image() const { return !image_.IsEmpty(); }
-
- protected:
- ~ImageWindowDelegate() override;
-
- // Overridden from aura::WindowDelegate:
- 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;
- 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_;
- gfx::Size window_size_;
-
- // Keeps track of whether the window size matches the image size or not. If
- // the image size is smaller than the window size, then the delegate paints a
- // white background for the missing regions.
- bool size_mismatch_;
-
- DISALLOW_COPY_AND_ASSIGN(ImageWindowDelegate);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_WEB_CONTENTS_AURA_IMAGE_WINDOW_DELEGATE_H_
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 3660897dab3..14b23752fda 100644
--- a/chromium/content/browser/web_contents/aura/overscroll_navigation_overlay.cc
+++ b/chromium/content/browser/web_contents/aura/overscroll_navigation_overlay.cc
@@ -4,9 +4,13 @@
#include "content/browser/web_contents/aura/overscroll_navigation_overlay.h"
+#include <vector>
+
+#include "base/i18n/rtl.h"
+#include "base/metrics/histogram_macros.h"
#include "content/browser/frame_host/navigation_entry_impl.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
-#include "content/browser/web_contents/aura/image_window_delegate.h"
+#include "content/browser/web_contents/aura/overscroll_window_delegate.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/common/view_messages.h"
#include "content/public/browser/browser_thread.h"
@@ -15,10 +19,10 @@
#include "ui/base/layout.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animation_observer.h"
+#include "ui/compositor/paint_recorder.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/image/image_png_rep.h"
-#include "ui/gfx/image/image_skia.h"
namespace content {
namespace {
@@ -26,6 +30,8 @@ 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)
+ return false;
if (entry->GetURL() == url)
return true;
const std::vector<GURL>& redirect_chain = entry->GetRedirectChain();
@@ -40,51 +46,6 @@ bool DoesEntryMatchURL(NavigationEntry* entry, const GURL& url) {
} // namespace
-// A LayerDelegate that paints an image for the layer.
-class ImageLayerDelegate : public ui::LayerDelegate {
- public:
- ImageLayerDelegate() {}
-
- ~ImageLayerDelegate() override {}
-
- void SetImage(const gfx::Image& image) {
- image_ = image;
- image_size_ = image.AsImageSkia().size();
- }
- const gfx::Image& image() const { return image_; }
-
- private:
- // Overridden from ui::LayerDelegate:
- void OnPaintLayer(gfx::Canvas* canvas) override {
- if (image_.IsEmpty()) {
- canvas->DrawColor(SK_ColorWHITE);
- } else {
- SkISize size = canvas->sk_canvas()->getDeviceSize();
- if (size.width() != image_size_.width() ||
- size.height() != image_size_.height()) {
- canvas->DrawColor(SK_ColorWHITE);
- }
- canvas->DrawImageInt(image_.AsImageSkia(), 0, 0);
- }
- }
-
- void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override {}
-
- // Called when the layer's device scale factor has changed.
- void OnDeviceScaleFactorChanged(float device_scale_factor) override {}
-
- // Invoked prior to the bounds changing. The returned closured is run after
- // the bounds change.
- base::Closure PrepareForLayerBoundsChange() override {
- return base::Closure();
- }
-
- gfx::Image image_;
- gfx::Size image_size_;
-
- DISALLOW_COPY_AND_ASSIGN(ImageLayerDelegate);
-};
-
// Responsible for fading out and deleting the layer of the overlay window.
class OverlayDismissAnimator
: public ui::LayerAnimationObserver {
@@ -128,27 +89,27 @@ class OverlayDismissAnimator
};
OverscrollNavigationOverlay::OverscrollNavigationOverlay(
- WebContentsImpl* web_contents)
- : web_contents_(web_contents),
- image_delegate_(NULL),
+ WebContentsImpl* web_contents,
+ aura::Window* web_contents_window)
+ : direction_(NONE),
+ web_contents_(web_contents),
loading_complete_(false),
received_paint_update_(false),
- slide_direction_(SLIDE_UNKNOWN) {
+ owa_(new OverscrollWindowAnimation(this)),
+ web_contents_window_(web_contents_window) {
}
OverscrollNavigationOverlay::~OverscrollNavigationOverlay() {
+ aura::Window* event_window = GetMainWindow();
+ if (owa_->is_active() && event_window)
+ event_window->ReleaseCapture();
}
void OverscrollNavigationOverlay::StartObserving() {
loading_complete_ = false;
received_paint_update_ = false;
- overlay_dismiss_layer_.reset();
Observe(web_contents_);
- // Make sure the overlay window is on top.
- if (window_.get() && window_->parent())
- window_->parent()->StackChildAtTop(window_.get());
-
// Assumes the navigation has been initiated.
NavigationEntry* pending_entry =
web_contents_->GetController().GetPendingEntry();
@@ -158,139 +119,152 @@ void OverscrollNavigationOverlay::StartObserving() {
pending_entry_url_ = pending_entry ? pending_entry->GetURL() : GURL();
}
-void OverscrollNavigationOverlay::SetOverlayWindow(
- scoped_ptr<aura::Window> window,
- ImageWindowDelegate* delegate) {
- window_ = window.Pass();
- if (window_.get() && window_->parent())
- window_->parent()->StackChildAtTop(window_.get());
- image_delegate_ = delegate;
-
- if (window_.get() && delegate->has_image()) {
- window_slider_.reset(new WindowSlider(this,
- window_->parent(),
- window_.get()));
- slide_direction_ = SLIDE_UNKNOWN;
- } else {
- window_slider_.reset();
- }
-}
-
void OverscrollNavigationOverlay::StopObservingIfDone() {
// Normally we dismiss the overlay once we receive a paint update, however
// for in-page navigations DidFirstVisuallyNonEmptyPaint() does not get
// called, and we rely on loading_complete_ for those cases.
- if (!received_paint_update_ && !loading_complete_)
- return;
-
- // If a slide is in progress, then do not destroy the window or the slide.
- if (window_slider_.get() && window_slider_->IsSlideInProgress())
+ // If an overscroll gesture is in progress, then do not destroy the window.
+ if (!window_ || !(loading_complete_ || received_paint_update_) ||
+ owa_->is_active()) {
return;
+ }
- // The layer to be animated by OverlayDismissAnimator
- scoped_ptr<ui::Layer> overlay_dismiss_layer;
- if (overlay_dismiss_layer_)
- overlay_dismiss_layer = overlay_dismiss_layer_.Pass();
- else if (window_.get())
- overlay_dismiss_layer = window_->AcquireLayer();
- Observe(NULL);
- window_slider_.reset();
+ // OverlayDismissAnimator deletes the dismiss layer and itself when the
+ // animation completes.
+ scoped_ptr<ui::Layer> dismiss_layer = window_->AcquireLayer();
window_.reset();
- image_delegate_ = NULL;
- if (overlay_dismiss_layer.get()) {
- // OverlayDismissAnimator deletes overlay_dismiss_layer and itself when the
- // animation completes.
- (new OverlayDismissAnimator(overlay_dismiss_layer.Pass()))->Animate();
- }
+ (new OverlayDismissAnimator(dismiss_layer.Pass()))->Animate();
+ Observe(nullptr);
+ received_paint_update_ = false;
+ loading_complete_ = false;
+}
+
+scoped_ptr<aura::Window> OverscrollNavigationOverlay::CreateOverlayWindow(
+ const gfx::Rect& bounds) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "Overscroll.Started2", direction_, NAVIGATION_COUNT);
+ OverscrollWindowDelegate* overscroll_delegate = new OverscrollWindowDelegate(
+ owa_.get(), GetImageForDirection(direction_));
+ scoped_ptr<aura::Window> window(new aura::Window(overscroll_delegate));
+ window->set_owned_by_parent(false);
+ window->SetTransparent(true);
+ window->Init(ui::LAYER_TEXTURED);
+ window->layer()->SetMasksToBounds(false);
+ window->SetName("OverscrollOverlay");
+ web_contents_window_->AddChild(window.get());
+ aura::Window* event_window = GetMainWindow();
+ if (direction_ == FORWARD)
+ web_contents_window_->StackChildAbove(window.get(), event_window);
+ else
+ web_contents_window_->StackChildBelow(window.get(), event_window);
+ window->SetBounds(bounds);
+ // Set capture on the window that is receiving the overscroll events so that
+ // trackpad scroll gestures keep targetting it even if the mouse pointer moves
+ // off its bounds.
+ event_window->SetCapture();
+ window->Show();
+ return window.Pass();
}
-ui::Layer* OverscrollNavigationOverlay::CreateSlideLayer(int offset) {
+const gfx::Image OverscrollNavigationOverlay::GetImageForDirection(
+ NavigationDirection direction) const {
const NavigationControllerImpl& controller = web_contents_->GetController();
const NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
- controller.GetEntryAtOffset(offset));
+ controller.GetEntryAtOffset(direction == FORWARD ? 1 : -1));
- gfx::Image image;
if (entry && entry->screenshot().get()) {
std::vector<gfx::ImagePNGRep> image_reps;
image_reps.push_back(gfx::ImagePNGRep(entry->screenshot(), 1.0f));
- image = gfx::Image(image_reps);
+ return gfx::Image(image_reps);
}
- if (!layer_delegate_)
- layer_delegate_.reset(new ImageLayerDelegate());
- layer_delegate_->SetImage(image);
+ return gfx::Image();
+}
- ui::Layer* layer = new ui::Layer(ui::LAYER_TEXTURED);
- layer->set_delegate(layer_delegate_.get());
- return layer;
+scoped_ptr<aura::Window> OverscrollNavigationOverlay::CreateFrontWindow(
+ const gfx::Rect& bounds) {
+ if (!web_contents_->GetController().CanGoForward())
+ return nullptr;
+ direction_ = FORWARD;
+ return CreateOverlayWindow(bounds);
}
-ui::Layer* OverscrollNavigationOverlay::CreateBackLayer() {
+scoped_ptr<aura::Window> OverscrollNavigationOverlay::CreateBackWindow(
+ const gfx::Rect& bounds) {
if (!web_contents_->GetController().CanGoBack())
- return NULL;
- slide_direction_ = SLIDE_BACK;
- return CreateSlideLayer(-1);
+ return nullptr;
+ direction_ = BACK;
+ return CreateOverlayWindow(bounds);
}
-ui::Layer* OverscrollNavigationOverlay::CreateFrontLayer() {
- if (!web_contents_->GetController().CanGoForward())
- return NULL;
- slide_direction_ = SLIDE_FRONT;
- return CreateSlideLayer(1);
+aura::Window* OverscrollNavigationOverlay::GetMainWindow() const {
+ if (window_)
+ return window_.get();
+ return web_contents_->IsBeingDestroyed()
+ ? nullptr
+ : web_contents_->GetContentNativeView();
}
-void OverscrollNavigationOverlay::OnWindowSlideCompleting() {
- if (slide_direction_ == SLIDE_UNKNOWN)
+void OverscrollNavigationOverlay::OnOverscrollCompleting() {
+ aura::Window* main_window = GetMainWindow();
+ if (!main_window)
return;
-
- // Perform the navigation.
- if (slide_direction_ == SLIDE_BACK)
- web_contents_->GetController().GoBack();
- else if (slide_direction_ == SLIDE_FRONT)
- web_contents_->GetController().GoForward();
- else
- NOTREACHED();
-
- // Reset state and wait for the new navigation page to complete
- // loading/painting.
- StartObserving();
+ main_window->ReleaseCapture();
}
-void OverscrollNavigationOverlay::OnWindowSlideCompleted(
- scoped_ptr<ui::Layer> layer) {
- if (slide_direction_ == SLIDE_UNKNOWN) {
- window_slider_.reset();
- StopObservingIfDone();
+void OverscrollNavigationOverlay::OnOverscrollCompleted(
+ scoped_ptr<aura::Window> window) {
+ DCHECK(direction_ != NONE);
+ aura::Window* main_window = GetMainWindow();
+ if (!main_window) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "Overscroll.Cancelled", direction_, NAVIGATION_COUNT);
return;
}
- // Change the image used for the overlay window.
- image_delegate_->SetImage(layer_delegate_->image());
- window_->layer()->SetTransform(gfx::Transform());
- window_->SchedulePaintInRect(gfx::Rect(window_->bounds().size()));
- slide_direction_ = SLIDE_UNKNOWN;
- // We may end up dismissing the overlay before it has a chance to repaint, so
- // set the slider layer to be the one animated by OverlayDismissAnimator.
- if (layer.get())
- overlay_dismiss_layer_ = layer.Pass();
- StopObservingIfDone();
-}
+ // Make sure we can navigate first, as other factors can trigger a navigation
+ // during an overscroll gesture and navigating without history produces a
+ // crash.
+ bool navigated = false;
+ if (direction_ == FORWARD && web_contents_->GetController().CanGoForward()) {
+ web_contents_->GetController().GoForward();
+ navigated = true;
+ } else if (direction_ == BACK && web_contents_->GetController().CanGoBack()) {
+ web_contents_->GetController().GoBack();
+ navigated = true;
+ } else {
+ // We need to dismiss the overlay without navigating as soon as the
+ // overscroll finishes.
+ UMA_HISTOGRAM_ENUMERATION(
+ "Overscroll.Cancelled", direction_, NAVIGATION_COUNT);
+ loading_complete_ = true;
+ }
+
+ if (navigated) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "Overscroll.Navigated2", direction_, NAVIGATION_COUNT);
+ StartObserving();
+ }
-void OverscrollNavigationOverlay::OnWindowSlideAborted() {
+ main_window->SetTransform(gfx::Transform());
+ window_ = window.Pass();
+ // Make sure the window is in its default position.
+ window_->SetBounds(gfx::Rect(web_contents_window_->bounds().size()));
+ window_->SetTransform(gfx::Transform());
+ // Make sure the overlay window is on top.
+ web_contents_window_->StackChildAtTop(window_.get());
+ direction_ = NONE;
StopObservingIfDone();
}
-void OverscrollNavigationOverlay::OnWindowSliderDestroyed() {
- // We only want to take an action here if WindowSlider is being destroyed
- // outside of OverscrollNavigationOverlay. If window_slider_.get() is NULL,
- // then OverscrollNavigationOverlay is the one destroying WindowSlider, and
- // we don't need to do anything.
- // This check prevents StopObservingIfDone() being called multiple times
- // (including recursively) for a single event.
- if (window_slider_.get()) {
- // The slider has just been destroyed. Release the ownership.
- ignore_result(window_slider_.release());
- StopObservingIfDone();
- }
+void OverscrollNavigationOverlay::OnOverscrollCancelled() {
+ UMA_HISTOGRAM_ENUMERATION(
+ "Overscroll.Cancelled", direction_, NAVIGATION_COUNT);
+ aura::Window* main_window = GetMainWindow();
+ if (!main_window)
+ return;
+ main_window->ReleaseCapture();
+ direction_ = NONE;
+ StopObservingIfDone();
}
void OverscrollNavigationOverlay::DidFirstVisuallyNonEmptyPaint() {
@@ -303,10 +277,10 @@ void OverscrollNavigationOverlay::DidFirstVisuallyNonEmptyPaint() {
}
}
-void OverscrollNavigationOverlay::DidStopLoading(RenderViewHost* host) {
+void OverscrollNavigationOverlay::DidStopLoading() {
// 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).
+ // navigation (e.g., from a script, or from a bookmark).
loading_complete_ = true;
StopObservingIfDone();
}
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 d65d374a848..32c9409b70e 100644
--- a/chromium/content/browser/web_contents/aura/overscroll_navigation_overlay.h
+++ b/chromium/content/browser/web_contents/aura/overscroll_navigation_overlay.h
@@ -7,31 +7,57 @@
#include "base/gtest_prod_util.h"
#include "base/macros.h"
-#include "content/browser/web_contents/aura/window_slider.h"
+#include "content/browser/web_contents/aura/overscroll_window_animation.h"
+#include "content/browser/web_contents/web_contents_view_aura.h"
#include "content/common/content_export.h"
#include "content/public/browser/web_contents_observer.h"
+#include "ui/gfx/image/image.h"
struct ViewHostMsg_UpdateRect_Params;
namespace content {
-class ImageLayerDelegate;
-class ImageWindowDelegate;
+class OverscrollWindowDelegate;
class OverscrollNavigationOverlayTest;
// When a history navigation is triggered at the end of an overscroll
// navigation, it is necessary to show the history-screenshot until the page is
-// done navigating and painting. This class accomplishes this by showing the
-// screenshot window on top of the page until the page has completed loading and
-// painting.
+// done navigating and painting. This class accomplishes this by calling the
+// navigation and creating, showing and destroying the screenshot window on top
+// of the page until the page has completed loading and painting. When the
+// overscroll completes, this screenshot window is returned by
+// OnOverscrollComplete and |window_| is set to own it.
+// There are two overscroll cases, for the first one the main window is the web
+// contents window. At this stage, |window_| is null. The second case is
+// triggered if the user overscrolls after |window_| is set, before the page
+// finishes loading. When this happens, |window_| is the main window.
class CONTENT_EXPORT OverscrollNavigationOverlay
: public WebContentsObserver,
- public WindowSlider::Delegate {
+ public OverscrollWindowAnimation::Delegate {
public:
- explicit OverscrollNavigationOverlay(WebContentsImpl* web_contents);
+ // Note that this enum is used to back an UMA histogram, so it should be
+ // treated as append-only.
+ enum NavigationDirection { NONE, FORWARD, BACK, NAVIGATION_COUNT };
+
+ OverscrollNavigationOverlay(WebContentsImpl* web_contents,
+ aura::Window* web_contents_window);
+
~OverscrollNavigationOverlay() override;
- bool has_window() const { return !!window_.get(); }
+ // Returns a pointer to the relay delegate we own.
+ OverscrollControllerDelegate* relay_delegate() { return owa_.get(); }
+
+ private:
+ friend class OverscrollNavigationOverlayTest;
+ FRIEND_TEST_ALL_PREFIXES(OverscrollNavigationOverlayTest, WithScreenshot);
+ FRIEND_TEST_ALL_PREFIXES(OverscrollNavigationOverlayTest, WithoutScreenshot);
+ FRIEND_TEST_ALL_PREFIXES(OverscrollNavigationOverlayTest, CannotNavigate);
+ FRIEND_TEST_ALL_PREFIXES(OverscrollNavigationOverlayTest, CancelNavigation);
+ FRIEND_TEST_ALL_PREFIXES(OverscrollNavigationOverlayTest,
+ CancelAfterSuccessfulNavigation);
+ FRIEND_TEST_ALL_PREFIXES(OverscrollNavigationOverlayTest, OverlayWindowSwap);
+ FRIEND_TEST_ALL_PREFIXES(OverscrollNavigationOverlayTest,
+ CloseDuringAnimation);
// Resets state and starts observing |web_contents_| for page load/paint
// updates. This function makes sure that the screenshot window is stacked
@@ -41,63 +67,40 @@ class CONTENT_EXPORT OverscrollNavigationOverlay
// otherwise the overlay may be dismissed prematurely.
void StartObserving();
- // Sets the screenshot window and the delegate. This takes ownership of
- // |window|.
- // Note that ImageWindowDelegate manages its own lifetime, so this function
- // does not take ownership of |delegate|.
- void SetOverlayWindow(scoped_ptr<aura::Window> window,
- ImageWindowDelegate* delegate);
-
- private:
- friend class OverscrollNavigationOverlayTest;
- FRIEND_TEST_ALL_PREFIXES(OverscrollNavigationOverlayTest,
- FirstVisuallyNonEmptyPaint_NoImage);
- FRIEND_TEST_ALL_PREFIXES(OverscrollNavigationOverlayTest,
- FirstVisuallyNonEmptyPaint_WithImage);
- FRIEND_TEST_ALL_PREFIXES(OverscrollNavigationOverlayTest,
- LoadUpdateWithoutNonEmptyPaint);
- FRIEND_TEST_ALL_PREFIXES(OverscrollNavigationOverlayTest,
- MultiNavigation_LoadingUpdate);
- FRIEND_TEST_ALL_PREFIXES(OverscrollNavigationOverlayTest,
- MultiNavigation_PaintUpdate);
-
- enum SlideDirection {
- SLIDE_UNKNOWN,
- SLIDE_BACK,
- SLIDE_FRONT
- };
-
// Stop observing the page and start the final overlay fade-out animation if
- // a window-slide isn't in progress and either the page has been painted or
- // the page-load has completed.
+ // there's no active overscroll window animation.
void StopObservingIfDone();
- // Creates a layer to be used for window-slide. |offset| is the offset of the
- // NavigationEntry for the screenshot image to display.
- ui::Layer* CreateSlideLayer(int offset);
+ // Creates a window that shows a history-screenshot and is stacked relative to
+ // the current overscroll |direction_| with the given |bounds|.
+ scoped_ptr<aura::Window> CreateOverlayWindow(const gfx::Rect& bounds);
- // Overridden from WindowSlider::Delegate:
- 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;
+ // Returns an image with the history-screenshot for the previous or next page,
+ // according to the given |direction|.
+ const gfx::Image GetImageForDirection(NavigationDirection direction) const;
+
+ // Overridden from OverscrollWindowAnimation::Delegate:
+ scoped_ptr<aura::Window> CreateFrontWindow(const gfx::Rect& bounds) override;
+ scoped_ptr<aura::Window> CreateBackWindow(const gfx::Rect& bounds) override;
+ aura::Window* GetMainWindow() const override;
+ void OnOverscrollCompleting() override;
+ void OnOverscrollCompleted(scoped_ptr<aura::Window> window) override;
+ void OnOverscrollCancelled() override;
// Overridden from WebContentsObserver:
void DidFirstVisuallyNonEmptyPaint() override;
- void DidStopLoading(RenderViewHost* host) override;
+ void DidStopLoading() override;
+
+ // The current overscroll direction.
+ NavigationDirection direction_;
- // The WebContents which is being navigated.
+ // The web contents that are being navigated.
WebContentsImpl* web_contents_;
- // The screenshot overlay window.
+ // The overlay window that shows a screenshot during an overscroll gesture and
+ // handles overscroll events during the second overscroll case.
scoped_ptr<aura::Window> window_;
- // This is the WindowDelegate of |window_|. The delegate manages its own
- // lifetime (destroys itself when |window_| is destroyed).
- ImageWindowDelegate* image_delegate_;
-
bool loading_complete_;
bool received_paint_update_;
@@ -106,19 +109,11 @@ class CONTENT_EXPORT OverscrollNavigationOverlay
// when the relevant page loads and paints.
GURL pending_entry_url_;
- // The |WindowSlider| that allows sliding history layers while the page is
- // being reloaded.
- scoped_ptr<WindowSlider> window_slider_;
-
- // Layer to be used for the final overlay fadeout animation when the overlay
- // is being dismissed.
- scoped_ptr<ui::Layer> overlay_dismiss_layer_;
-
- // The direction of the in-progress slide (if any).
- SlideDirection slide_direction_;
+ // Manages the overscroll animations.
+ scoped_ptr<OverscrollWindowAnimation> owa_;
- // The LayerDelegate used for the back/front layers during a slide.
- scoped_ptr<ImageLayerDelegate> layer_delegate_;
+ // The window that hosts the web contents.
+ aura::Window* web_contents_window_;
DISALLOW_COPY_AND_ASSIGN(OverscrollNavigationOverlay);
};
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 0e9eb4ef65a..eabdefdf551 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
@@ -4,33 +4,86 @@
#include "content/browser/web_contents/aura/overscroll_navigation_overlay.h"
+#include <vector>
#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/browser/overscroll_configuration.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"
#include "ui/aura/window.h"
+#include "ui/aura_extra/image_window_delegate.h"
+#include "ui/compositor/scoped_animation_duration_scale_mode.h"
+#include "ui/compositor/scoped_layer_animation_settings.h"
+#include "ui/compositor/test/layer_animator_test_controller.h"
+#include "ui/events/gesture_detection/gesture_configuration.h"
+#include "ui/events/test/event_generator.h"
#include "ui/gfx/codec/png_codec.h"
+#include "ui/gfx/frame_time.h"
namespace content {
-class OverscrollNavigationOverlayTest : public RenderViewHostImplTestHarness {
+// A subclass of TestWebContents that offers a fake content window.
+class OverscrollTestWebContents : public TestWebContents {
public:
- OverscrollNavigationOverlayTest() {}
- ~OverscrollNavigationOverlayTest() override {}
+ ~OverscrollTestWebContents() override {}
+
+ static OverscrollTestWebContents* Create(
+ BrowserContext* browser_context,
+ SiteInstance* instance,
+ scoped_ptr<aura::Window> fake_native_view,
+ scoped_ptr<aura::Window> fake_contents_window) {
+ OverscrollTestWebContents* web_contents = new OverscrollTestWebContents(
+ browser_context, fake_native_view.Pass(), fake_contents_window.Pass());
+ web_contents->Init(WebContents::CreateParams(browser_context, instance));
+ web_contents->RenderFrameCreated(web_contents->GetMainFrame());
+ return web_contents;
+ }
- gfx::Image CreateDummyScreenshot() {
- SkBitmap bitmap;
- bitmap.allocN32Pixels(1, 1);
- bitmap.eraseColor(SK_ColorWHITE);
- return gfx::Image::CreateFrom1xBitmap(bitmap);
+ void ResetNativeView() { fake_native_view_.reset(); }
+
+ void ResetContentNativeView() { fake_contents_window_.reset(); }
+
+ void set_is_being_destroyed(bool val) { is_being_destroyed_ = val; }
+
+ gfx::NativeView GetNativeView() override { return fake_native_view_.get(); }
+
+ gfx::NativeView GetContentNativeView() override {
+ return fake_contents_window_.get();
}
+ bool IsBeingDestroyed() const override { return is_being_destroyed_; }
+
+ protected:
+ explicit OverscrollTestWebContents(
+ BrowserContext* browser_context,
+ scoped_ptr<aura::Window> fake_native_view,
+ scoped_ptr<aura::Window> fake_contents_window)
+ : TestWebContents(browser_context),
+ fake_native_view_(fake_native_view.Pass()),
+ fake_contents_window_(fake_contents_window.Pass()),
+ is_being_destroyed_(false) {}
+
+ private:
+ scoped_ptr<aura::Window> fake_native_view_;
+ scoped_ptr<aura::Window> fake_contents_window_;
+ bool is_being_destroyed_;
+};
+
+class OverscrollNavigationOverlayTest : public RenderViewHostImplTestHarness {
+ public:
+ OverscrollNavigationOverlayTest()
+ : first_("https://www.google.com"),
+ second_("http://www.chromium.org"),
+ third_("https://www.kernel.org/"),
+ fourth_("https://github.com/") {}
+
+ ~OverscrollNavigationOverlayTest() override {}
+
void SetDummyScreenshotOnNavEntry(NavigationEntry* entry) {
SkBitmap bitmap;
bitmap.allocN32Pixels(1, 1);
@@ -51,29 +104,81 @@ class OverscrollNavigationOverlayTest : public RenderViewHostImplTestHarness {
}
void PerformBackNavigationViaSliderCallbacks() {
- // Sets slide direction to SLIDE_BACK, sets screenshot from NavEntry at
+ // Sets slide direction to BACK, sets screenshot from NavEntry at
// offset -1 on layer_delegate_.
- delete GetOverlay()->CreateBackLayer();
+ scoped_ptr<aura::Window> window(
+ GetOverlay()->CreateBackWindow(GetBackSlideWindowBounds()));
+ bool window_created = window;
// Performs BACK navigation, sets image from layer_delegate_ on
// image_delegate_.
- GetOverlay()->OnWindowSlideCompleting();
- GetOverlay()->OnWindowSlideCompleted(scoped_ptr<ui::Layer>());
+ GetOverlay()->OnOverscrollCompleting();
+ if (window_created)
+ EXPECT_EQ(GetOverlay()->direction_, OverscrollNavigationOverlay::BACK);
+ else
+ EXPECT_EQ(GetOverlay()->direction_, OverscrollNavigationOverlay::NONE);
+ window->SetBounds(gfx::Rect(root_window()->bounds().size()));
+ GetOverlay()->OnOverscrollCompleted(window.Pass());
+ main_test_rfh()->PrepareForCommit();
+ if (window_created)
+ EXPECT_TRUE(contents()->CrossProcessNavigationPending());
+ else
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
+ }
+
+ gfx::Rect GetFrontSlideWindowBounds() {
+ gfx::Rect bounds = gfx::Rect(root_window()->bounds().size());
+ bounds.Offset(root_window()->bounds().size().width(), 0);
+ return bounds;
}
+ gfx::Rect GetBackSlideWindowBounds() {
+ return gfx::Rect(root_window()->bounds().size());
+ }
+
+ // Const accessors.
+ const GURL first() { return first_; }
+ const GURL second() { return second_; }
+ const GURL third() { return third_; }
+ const GURL fourth() { return fourth_; }
+
protected:
// RenderViewHostImplTestHarness:
void SetUp() override {
RenderViewHostImplTestHarness::SetUp();
- const GURL first("https://www.google.com");
- contents()->NavigateAndCommit(first);
+ // Set up the fake web contents native view.
+ scoped_ptr<aura::Window> fake_native_view(new aura::Window(nullptr));
+ fake_native_view->Init(ui::LAYER_SOLID_COLOR);
+ root_window()->AddChild(fake_native_view.get());
+ fake_native_view->SetBounds(gfx::Rect(root_window()->bounds().size()));
+
+ // Set up the fake contents window.
+ scoped_ptr<aura::Window> fake_contents_window(new aura::Window(nullptr));
+ fake_contents_window->Init(ui::LAYER_SOLID_COLOR);
+ root_window()->AddChild(fake_contents_window.get());
+ fake_contents_window->SetBounds(gfx::Rect(root_window()->bounds().size()));
+
+ // Replace the default test web contents with our custom class.
+ SetContents(OverscrollTestWebContents::Create(
+ browser_context(),
+ SiteInstance::Create(browser_context()),
+ fake_native_view.Pass(),
+ fake_contents_window.Pass()));
+
+ contents()->NavigateAndCommit(first());
EXPECT_TRUE(controller().GetVisibleEntry());
EXPECT_FALSE(controller().CanGoBack());
- const GURL second("http://www.chromium.org");
- contents()->NavigateAndCommit(second);
+ contents()->NavigateAndCommit(second());
+ EXPECT_TRUE(controller().CanGoBack());
+
+ contents()->NavigateAndCommit(third());
EXPECT_TRUE(controller().CanGoBack());
+ contents()->NavigateAndCommit(fourth_);
+ EXPECT_TRUE(controller().CanGoBack());
+ EXPECT_FALSE(controller().CanGoForward());
+
// Receive a paint update. This is necessary to make sure the size is set
// correctly in RenderWidgetHostImpl.
ViewHostMsg_UpdateRect_Params params;
@@ -86,21 +191,7 @@ class OverscrollNavigationOverlayTest : public RenderViewHostImplTestHarness {
test_rvh()->ResetSizeAndRepaintPendingFlags();
// Create the overlay, and set the contents of the overlay window.
- overlay_.reset(new OverscrollNavigationOverlay(contents()));
- ImageWindowDelegate* image_delegate = new ImageWindowDelegate();
- scoped_ptr<aura::Window> overlay_window(
- aura::test::CreateTestWindowWithDelegate(
- image_delegate,
- 0,
- gfx::Rect(root_window()->bounds().size()),
- root_window()));
-
- overlay_->SetOverlayWindow(overlay_window.Pass(), image_delegate);
- overlay_->StartObserving();
-
- EXPECT_TRUE(overlay_->web_contents());
- EXPECT_FALSE(overlay_->loading_complete_);
- EXPECT_FALSE(overlay_->received_paint_update_);
+ overlay_.reset(new OverscrollNavigationOverlay(contents(), root_window()));
}
void TearDown() override {
@@ -113,72 +204,99 @@ class OverscrollNavigationOverlayTest : public RenderViewHostImplTestHarness {
}
private:
+ // Tests URLs.
+ const GURL first_;
+ const GURL second_;
+ const GURL third_;
+ const GURL fourth_;
+
scoped_ptr<OverscrollNavigationOverlay> overlay_;
DISALLOW_COPY_AND_ASSIGN(OverscrollNavigationOverlayTest);
};
-TEST_F(OverscrollNavigationOverlayTest, FirstVisuallyNonEmptyPaint_NoImage) {
- ReceivePaintUpdate();
- EXPECT_TRUE(GetOverlay()->received_paint_update_);
- EXPECT_FALSE(GetOverlay()->loading_complete_);
- // The paint update will hide the overlay.
- EXPECT_FALSE(GetOverlay()->web_contents());
+// Tests that if a screenshot is available, it is set in the overlay window
+// delegate.
+TEST_F(OverscrollNavigationOverlayTest, WithScreenshot) {
+ SetDummyScreenshotOnNavEntry(controller().GetEntryAtOffset(-1));
+ PerformBackNavigationViaSliderCallbacks();
+ // Screenshot was set on NavEntry at offset -1.
+ EXPECT_TRUE(static_cast<aura_extra::ImageWindowDelegate*>(
+ GetOverlay()->window_->delegate())->has_image());
}
-TEST_F(OverscrollNavigationOverlayTest, FirstVisuallyNonEmptyPaint_WithImage) {
- GetOverlay()->image_delegate_->SetImage(CreateDummyScreenshot());
+// Tests that if a screenshot is not available, no image is set in the overlay
+// window delegate.
+TEST_F(OverscrollNavigationOverlayTest, WithoutScreenshot) {
+ PerformBackNavigationViaSliderCallbacks();
+ // No screenshot was set on NavEntry at offset -1.
+ EXPECT_FALSE(static_cast<aura_extra::ImageWindowDelegate*>(
+ GetOverlay()->window_->delegate())->has_image());
+}
- ReceivePaintUpdate();
- EXPECT_TRUE(GetOverlay()->received_paint_update_);
- EXPECT_FALSE(GetOverlay()->loading_complete_);
- // The paint update will hide the overlay.
- EXPECT_FALSE(GetOverlay()->web_contents());
+// Tests that if a navigation is attempted but there is nothing to navigate to,
+// we return a null window.
+TEST_F(OverscrollNavigationOverlayTest, CannotNavigate) {
+ EXPECT_EQ(GetOverlay()->CreateFrontWindow(GetFrontSlideWindowBounds()),
+ nullptr);
}
-TEST_F(OverscrollNavigationOverlayTest, LoadUpdateWithoutNonEmptyPaint) {
- GetOverlay()->image_delegate_->SetImage(CreateDummyScreenshot());
- process()->sink().ClearMessages();
+// Tests that if a navigation is cancelled, no navigation is performed and the
+// state is restored.
+TEST_F(OverscrollNavigationOverlayTest, CancelNavigation) {
+ scoped_ptr<aura::Window> window =
+ GetOverlay()->CreateBackWindow(GetBackSlideWindowBounds());
+ EXPECT_EQ(GetOverlay()->direction_, OverscrollNavigationOverlay::BACK);
- contents()->TestSetIsLoading(false);
- EXPECT_TRUE(GetOverlay()->loading_complete_);
- EXPECT_FALSE(GetOverlay()->received_paint_update_);
- // The page load should hide the overlay.
- EXPECT_FALSE(GetOverlay()->web_contents());
+ GetOverlay()->OnOverscrollCancelled();
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
+ EXPECT_EQ(GetOverlay()->direction_, OverscrollNavigationOverlay::NONE);
}
-TEST_F(OverscrollNavigationOverlayTest, MultiNavigation_PaintUpdate) {
- GetOverlay()->image_delegate_->SetImage(CreateDummyScreenshot());
- SetDummyScreenshotOnNavEntry(controller().GetEntryAtOffset(-1));
-
+// Performs two navigations. The second navigation is cancelled, tests that the
+// first one worked correctly.
+TEST_F(OverscrollNavigationOverlayTest, CancelAfterSuccessfulNavigation) {
PerformBackNavigationViaSliderCallbacks();
- // Screenshot was set on NavEntry at offset -1.
- EXPECT_TRUE(GetOverlay()->image_delegate_->has_image());
- EXPECT_FALSE(GetOverlay()->received_paint_update_);
+ scoped_ptr<aura::Window> wrapper =
+ GetOverlay()->CreateBackWindow(GetBackSlideWindowBounds());
+ EXPECT_EQ(GetOverlay()->direction_, OverscrollNavigationOverlay::BACK);
+
+ GetOverlay()->OnOverscrollCancelled();
+ EXPECT_EQ(GetOverlay()->direction_, OverscrollNavigationOverlay::NONE);
+
+ EXPECT_TRUE(contents()->CrossProcessNavigationPending());
+ NavigationEntry* pending = contents()->GetController().GetPendingEntry();
+ main_test_rfh()->SendNavigate(
+ 0, pending->GetUniqueID(), false, pending->GetURL());
+ EXPECT_EQ(contents()->GetURL(), third());
+}
+// Tests that an overscroll navigation that receives a paint update actually
+// stops observing.
+TEST_F(OverscrollNavigationOverlayTest, Navigation_PaintUpdate) {
+ PerformBackNavigationViaSliderCallbacks();
ReceivePaintUpdate();
+
// 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_);
+ // for the previous page, so we should still be observing.
+ EXPECT_TRUE(GetOverlay()->web_contents());
- contents()->CommitPendingNavigation();
+ NavigationEntry* pending = contents()->GetController().GetPendingEntry();
+ main_test_rfh()->SendNavigate(
+ 0, pending->GetUniqueID(), false, pending->GetURL());
ReceivePaintUpdate();
- // Navigation was committed and the paint update was received - the flag
- // should now be updated.
- EXPECT_TRUE(GetOverlay()->received_paint_update_);
+ // Navigation was committed and the paint update was received - we should no
+ // longer be observing.
EXPECT_FALSE(GetOverlay()->web_contents());
+ EXPECT_EQ(contents()->GetURL(), third());
}
-TEST_F(OverscrollNavigationOverlayTest, MultiNavigation_LoadingUpdate) {
- GetOverlay()->image_delegate_->SetImage(CreateDummyScreenshot());
-
+// Tests that an overscroll navigation that receives a loading update actually
+// stops observing.
+TEST_F(OverscrollNavigationOverlayTest, Navigation_LoadingUpdate) {
PerformBackNavigationViaSliderCallbacks();
- // No screenshot was set on NavEntry at offset -1.
- EXPECT_FALSE(GetOverlay()->image_delegate_->has_image());
- // Navigation was started, so the loading status flag should be reset.
- EXPECT_FALSE(GetOverlay()->loading_complete_);
-
+ EXPECT_TRUE(GetOverlay()->web_contents());
// 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
@@ -186,9 +304,106 @@ TEST_F(OverscrollNavigationOverlayTest, MultiNavigation_LoadingUpdate) {
// navigation is in progress).
contents()->TestSetIsLoading(true);
contents()->TestSetIsLoading(false);
- EXPECT_TRUE(GetOverlay()->loading_complete_);
-
EXPECT_FALSE(GetOverlay()->web_contents());
+ NavigationEntry* pending = contents()->GetController().GetPendingEntry();
+ main_test_rfh()->SendNavigate(
+ 0, pending->GetUniqueID(), false, pending->GetURL());
+ EXPECT_EQ(contents()->GetURL(), third());
+}
+
+TEST_F(OverscrollNavigationOverlayTest, CloseDuringAnimation) {
+ ui::ScopedAnimationDurationScaleMode normal_duration_(
+ ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
+ GetOverlay()->owa_->OnOverscrollModeChange(OVERSCROLL_NONE, OVERSCROLL_EAST);
+ GetOverlay()->owa_->OnOverscrollComplete(OVERSCROLL_EAST);
+ EXPECT_EQ(GetOverlay()->direction_, OverscrollNavigationOverlay::BACK);
+ OverscrollTestWebContents* test_web_contents =
+ static_cast<OverscrollTestWebContents*>(web_contents());
+ test_web_contents->set_is_being_destroyed(true);
+ test_web_contents->ResetContentNativeView();
+ test_web_contents->ResetNativeView();
+ // Ensure a clean close.
+}
+
+
+// Tests that swapping the overlay window at the end of a gesture caused by the
+// start of a new overscroll does not crash and the events still reach the new
+// overlay window.
+TEST_F(OverscrollNavigationOverlayTest, OverlayWindowSwap) {
+ PerformBackNavigationViaSliderCallbacks();
+ aura::Window* first_overlay_window = GetOverlay()->window_.get();
+ EXPECT_TRUE(GetOverlay()->web_contents());
+ EXPECT_TRUE(first_overlay_window);
+
+ // At this stage, the overlay window is covering the web contents. Configure
+ // the animator of the overlay window for the test.
+ ui::ScopedAnimationDurationScaleMode normal_duration(
+ ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
+ ui::LayerAnimator* animator = GetOverlay()->window_->layer()->GetAnimator();
+ animator->set_disable_timer_for_test(true);
+ ui::LayerAnimatorTestController test_controller(animator);
+
+ int overscroll_complete_distance =
+ root_window()->bounds().size().width() *
+ content::GetOverscrollConfig(
+ content::OVERSCROLL_CONFIG_HORIZ_THRESHOLD_COMPLETE) +
+ ui::GestureConfiguration::GetInstance()
+ ->max_touch_move_in_pixels_for_click() + 1;
+
+ // Start and complete a back navigation via a gesture.
+ ui::test::EventGenerator generator(root_window());
+ generator.GestureScrollSequence(gfx::Point(0, 0),
+ gfx::Point(overscroll_complete_distance, 0),
+ base::TimeDelta::FromMilliseconds(10),
+ 10);
+
+ ui::ScopedLayerAnimationSettings settings(animator);
+ test_controller.StartThreadedAnimationsIfNeeded();
+
+ // The overlay window should now be being animated to the edge of the screen.
+ // |first()overlay_window| is the back window.
+ // This is what the screen should look like. The X indicates where the next
+ // gesture starts for the test.
+ // +---------root_window--------+
+ // |+-back window--+--front window--+
+ // || | | |
+ // || 1 |X 2 | |
+ // || | | |
+ // |+--------------+------------|---+
+ // +----------------------------+
+ // | overscroll ||
+ // | complete ||
+ // | distance ||
+ // |<------------->||
+ // | second |
+ // | overscroll |
+ // | start distance |
+ // |<-------------->|
+ EXPECT_EQ(GetOverlay()->window_.get(), first_overlay_window);
+
+ // The overlay window is halfway through, start another animation that will
+ // cancel the first one. The event that cancels the animation will go to
+ // the slide window, which will be used as the overlay window when the new
+ // overscroll starts.
+ int second_overscroll_start_distance = overscroll_complete_distance + 1;
+ generator.GestureScrollSequence(
+ gfx::Point(second_overscroll_start_distance, 0),
+ gfx::Point(
+ second_overscroll_start_distance + overscroll_complete_distance, 0),
+ base::TimeDelta::FromMilliseconds(10), 10);
+ EXPECT_TRUE(GetOverlay()->window_.get());
+ // The overlay window should be a new window.
+ EXPECT_NE(GetOverlay()->window_.get(), first_overlay_window);
+
+ // Complete the animation.
+ GetOverlay()->window_->layer()->GetAnimator()->StopAnimating();
+ EXPECT_TRUE(GetOverlay()->window_.get());
+
+ // Load the page.
+ contents()->CommitPendingNavigation();
+ ReceivePaintUpdate();
+ EXPECT_FALSE(GetOverlay()->window_.get());
+ EXPECT_EQ(contents()->GetURL(), first());
}
} // namespace content
diff --git a/chromium/content/browser/web_contents/aura/overscroll_window_animation.cc b/chromium/content/browser/web_contents/aura/overscroll_window_animation.cc
new file mode 100644
index 00000000000..c89faa08b08
--- /dev/null
+++ b/chromium/content/browser/web_contents/aura/overscroll_window_animation.cc
@@ -0,0 +1,177 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/web_contents/aura/overscroll_window_animation.h"
+
+#include <algorithm>
+
+#include "base/i18n/rtl.h"
+#include "content/browser/web_contents/aura/shadow_layer_delegate.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "ui/aura/window.h"
+#include "ui/compositor/layer_animation_observer.h"
+#include "ui/compositor/scoped_layer_animation_settings.h"
+
+namespace content {
+
+namespace {
+
+OverscrollWindowAnimation::Direction GetDirectionForMode(OverscrollMode mode) {
+ if (mode == (base::i18n::IsRTL() ? OVERSCROLL_EAST : OVERSCROLL_WEST))
+ return OverscrollWindowAnimation::SLIDE_FRONT;
+ if (mode == (base::i18n::IsRTL() ? OVERSCROLL_WEST : OVERSCROLL_EAST))
+ return OverscrollWindowAnimation::SLIDE_BACK;
+ return OverscrollWindowAnimation::SLIDE_NONE;
+}
+
+} // namespace
+
+OverscrollWindowAnimation::OverscrollWindowAnimation(Delegate* delegate)
+ : delegate_(delegate),
+ direction_(SLIDE_NONE),
+ overscroll_cancelled_(false) {
+ DCHECK(delegate_);
+}
+
+OverscrollWindowAnimation::~OverscrollWindowAnimation() {
+}
+
+void OverscrollWindowAnimation::CancelSlide() {
+ overscroll_cancelled_ = true;
+ // Listen to the animation of the main window.
+ bool main_window_is_front = direction_ == SLIDE_BACK;
+ AnimateTranslation(GetBackLayer(), 0, !main_window_is_front);
+ AnimateTranslation(GetFrontLayer(), 0, main_window_is_front);
+}
+
+float OverscrollWindowAnimation::GetTranslationForOverscroll(float delta_x) {
+ DCHECK(direction_ != SLIDE_NONE);
+ const float bounds_width = GetVisibleBounds().width();
+ if (direction_ == SLIDE_FRONT)
+ return std::max(-bounds_width, delta_x);
+ else
+ return std::min(bounds_width, delta_x);
+}
+
+gfx::Rect OverscrollWindowAnimation::GetVisibleBounds() const {
+ return delegate_->GetMainWindow()->bounds();
+}
+
+bool OverscrollWindowAnimation::OnOverscrollUpdate(float delta_x,
+ float delta_y) {
+ if (direction_ == SLIDE_NONE)
+ return false;
+ gfx::Transform front_transform;
+ gfx::Transform back_transform;
+ float translate_x = GetTranslationForOverscroll(delta_x);
+ front_transform.Translate(translate_x, 0);
+ back_transform.Translate(translate_x / 2, 0);
+ GetFrontLayer()->SetTransform(front_transform);
+ GetBackLayer()->SetTransform(back_transform);
+ return true;
+}
+
+void OverscrollWindowAnimation::OnImplicitAnimationsCompleted() {
+ if (overscroll_cancelled_) {
+ slide_window_.reset();
+ delegate_->OnOverscrollCancelled();
+ overscroll_cancelled_ = false;
+ } else {
+ delegate_->OnOverscrollCompleted(slide_window_.Pass());
+ }
+ direction_ = SLIDE_NONE;
+}
+
+void OverscrollWindowAnimation::OnOverscrollModeChange(
+ OverscrollMode old_mode,
+ OverscrollMode new_mode) {
+ DCHECK_NE(old_mode, new_mode);
+ Direction new_direction = GetDirectionForMode(new_mode);
+ if (new_direction == SLIDE_NONE) {
+ // The user cancelled the in progress animation.
+ if (is_active())
+ CancelSlide();
+ return;
+ }
+ if (is_active()) {
+ slide_window_->layer()->GetAnimator()->StopAnimating();
+ delegate_->GetMainWindow()->layer()->GetAnimator()->StopAnimating();
+ }
+ gfx::Rect slide_window_bounds = gfx::Rect(GetVisibleBounds().size());
+ if (new_direction == SLIDE_FRONT) {
+ slide_window_bounds.Offset(base::i18n::IsRTL()
+ ? -slide_window_bounds.width()
+ : slide_window_bounds.width(),
+ 0);
+ } else {
+ slide_window_bounds.Offset(base::i18n::IsRTL()
+ ? slide_window_bounds.width() / 2
+ : -slide_window_bounds.width() / 2,
+ 0);
+ }
+ slide_window_ = new_direction == SLIDE_FRONT
+ ? delegate_->CreateFrontWindow(slide_window_bounds)
+ : delegate_->CreateBackWindow(slide_window_bounds);
+ if (!slide_window_) {
+ // Cannot navigate, do not start an overscroll gesture.
+ direction_ = SLIDE_NONE;
+ return;
+ }
+ overscroll_cancelled_ = false;
+ direction_ = new_direction;
+ shadow_.reset(new ShadowLayerDelegate(GetFrontLayer()));
+}
+
+void OverscrollWindowAnimation::OnOverscrollComplete(
+ OverscrollMode overscroll_mode) {
+ if (!is_active())
+ return;
+ delegate_->OnOverscrollCompleting();
+ int content_width = GetVisibleBounds().width();
+ float translate_x;
+ if ((base::i18n::IsRTL() && direction_ == SLIDE_FRONT) ||
+ (!base::i18n::IsRTL() && direction_ == SLIDE_BACK)) {
+ translate_x = content_width;
+ } else {
+ translate_x = -content_width;
+ }
+ // Listen to the animation of the main window.
+ bool main_window_is_front = direction_ == SLIDE_BACK;
+ AnimateTranslation(GetBackLayer(), translate_x / 2, !main_window_is_front);
+ AnimateTranslation(GetFrontLayer(), translate_x, main_window_is_front);
+}
+
+void OverscrollWindowAnimation::AnimateTranslation(ui::Layer* layer,
+ float translate_x,
+ bool listen_for_completion) {
+ gfx::Transform transform;
+ transform.Translate(translate_x, 0);
+ ui::ScopedLayerAnimationSettings settings(layer->GetAnimator());
+ settings.SetPreemptionStrategy(
+ ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
+ settings.SetTweenType(gfx::Tween::EASE_OUT);
+ if (listen_for_completion)
+ settings.AddObserver(this);
+ layer->SetTransform(transform);
+}
+
+ui::Layer* OverscrollWindowAnimation::GetFrontLayer() const {
+ DCHECK(direction_ != SLIDE_NONE);
+ if (direction_ == SLIDE_FRONT) {
+ DCHECK(slide_window_);
+ return slide_window_->layer();
+ }
+ return delegate_->GetMainWindow()->layer();
+}
+
+ui::Layer* OverscrollWindowAnimation::GetBackLayer() const {
+ DCHECK(direction_ != SLIDE_NONE);
+ if (direction_ == SLIDE_BACK) {
+ DCHECK(slide_window_);
+ return slide_window_->layer();
+ }
+ return delegate_->GetMainWindow()->layer();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/web_contents/aura/overscroll_window_animation.h b/chromium/content/browser/web_contents/aura/overscroll_window_animation.h
new file mode 100644
index 00000000000..876368d3f98
--- /dev/null
+++ b/chromium/content/browser/web_contents/aura/overscroll_window_animation.h
@@ -0,0 +1,130 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_WEB_CONTENTS_AURA_OVERSCROLL_WINDOW_ANIMATION_H_
+#define CONTENT_BROWSER_WEB_CONTENTS_AURA_OVERSCROLL_WINDOW_ANIMATION_H_
+
+#include "base/gtest_prod_util.h"
+#include "content/browser/renderer_host/overscroll_controller_delegate.h"
+#include "content/common/content_export.h"
+#include "ui/compositor/layer_animation_observer.h"
+
+namespace aura {
+class Window;
+}
+
+namespace ui {
+class Layer;
+class LayerAnimator;
+}
+
+namespace content {
+
+class ShadowLayerDelegate;
+class WebContentsImpl;
+
+// Manages the animation of a window sliding on top or behind another one. The
+// main window, which is the one displayed before the animation starts, is not
+// owned by OverscrollWindowAnimation, while the slide window, created at the
+// start of the animation, is owned by us for its duration.
+class CONTENT_EXPORT OverscrollWindowAnimation
+ : public OverscrollControllerDelegate,
+ ui::ImplicitAnimationObserver {
+ public:
+ // The direction of this animation. SLIDE_FRONT indicates that the slide
+ // window moves on top of the main window, entering the screen from the right.
+ // SLIDE_BACK means that the main window is animated to the right, revealing
+ // the slide window in the back. SLIDE_NONE means we are not animating yet.
+ // Both windows are animated at the same time but at different speeds,
+ // creating a parallax scrolling effect. Left and right are reversed for RTL
+ // languages, but stack order remains unchanged.
+ enum Direction { SLIDE_FRONT, SLIDE_BACK, SLIDE_NONE };
+
+ // Delegate class that interfaces with the window animation.
+ class CONTENT_EXPORT Delegate {
+ public:
+ virtual ~Delegate() {}
+
+ // Create a slide window with the given |bounds| relative to its parent.
+ virtual scoped_ptr<aura::Window> CreateFrontWindow(
+ const gfx::Rect& bounds) = 0;
+ virtual scoped_ptr<aura::Window> CreateBackWindow(
+ const gfx::Rect& bounds) = 0;
+
+ // Returns the main window that participates in the animation. The delegate
+ // does not own this window.
+ virtual aura::Window* GetMainWindow() const = 0;
+
+ // Called when we know the animation is going to complete successfully, but
+ // before it actually completes.
+ virtual void OnOverscrollCompleting() = 0;
+
+ // Called when the animation has been completed. The slide window is
+ // transferred to the delegate.
+ virtual void OnOverscrollCompleted(scoped_ptr<aura::Window> window) = 0;
+
+ // Called when the overscroll gesture has been cancelled, after the cancel
+ // animation finishes.
+ virtual void OnOverscrollCancelled() = 0;
+ };
+
+ explicit OverscrollWindowAnimation(Delegate* delegate);
+
+ ~OverscrollWindowAnimation() override;
+
+ // Returns true if we are currently animating.
+ bool is_active() const { return !!slide_window_; }
+
+ // OverscrollControllerDelegate:
+ 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;
+
+ private:
+ // Cancels the slide, animating the front and back window to their original
+ // positions.
+ void CancelSlide();
+
+ // Returns a translation on the x axis for the given overscroll.
+ float GetTranslationForOverscroll(float delta_x);
+
+ // Animates a translation of the given |layer|. If |listen_for_completion| is
+ // true, adds |this| as observer of the animation.
+ void AnimateTranslation(ui::Layer* layer,
+ float translate_x,
+ bool listen_for_completion);
+
+ // Return the front/back layer that is involved in the animation. The caller
+ // does not own it.
+ ui::Layer* GetFrontLayer() const;
+ ui::Layer* GetBackLayer() const;
+
+ // ui::ImplicitAnimationObserver:
+ void OnImplicitAnimationsCompleted() override;
+
+ // We own the window created for the animation.
+ scoped_ptr<aura::Window> slide_window_;
+
+ // Shadow shown under the animated layer.
+ scoped_ptr<ShadowLayerDelegate> shadow_;
+
+ // Delegate that provides the animation target and is notified of the
+ // animation state.
+ Delegate* delegate_;
+
+ // The current animation direction.
+ Direction direction_;
+
+ // Indicates if the current slide has been cancelled. True while the cancel
+ // animation is in progress.
+ bool overscroll_cancelled_;
+
+ DISALLOW_COPY_AND_ASSIGN(OverscrollWindowAnimation);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_WEB_CONTENTS_AURA_OVERSCROLL_WINDOW_ANIMATION_H_
diff --git a/chromium/content/browser/web_contents/aura/overscroll_window_animation_unittest.cc b/chromium/content/browser/web_contents/aura/overscroll_window_animation_unittest.cc
new file mode 100644
index 00000000000..527b0c7bd6e
--- /dev/null
+++ b/chromium/content/browser/web_contents/aura/overscroll_window_animation_unittest.cc
@@ -0,0 +1,226 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/web_contents/aura/overscroll_window_animation.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/aura/test/aura_test_base.h"
+#include "ui/aura/window.h"
+#include "ui/compositor/scoped_animation_duration_scale_mode.h"
+#include "ui/compositor/scoped_layer_animation_settings.h"
+#include "ui/compositor/test/layer_animator_test_controller.h"
+#include "ui/gfx/frame_time.h"
+
+namespace content {
+
+class OverscrollWindowAnimationTest
+ : public OverscrollWindowAnimation::Delegate,
+ public aura::test::AuraTestBase {
+ public:
+ OverscrollWindowAnimationTest()
+ : create_window_(true),
+ overscroll_started_(false),
+ overscroll_completing_(false),
+ overscroll_completed_(false),
+ overscroll_aborted_(false),
+ main_window_(nullptr) {}
+
+ ~OverscrollWindowAnimationTest() override {}
+
+ OverscrollWindowAnimation* owa() { return owa_.get(); }
+
+ // Set to true to return a window in the Create*Window functions, false to
+ // return null.
+ void set_create_window(bool create_window) { create_window_ = create_window; }
+
+ // The following functions indicate if the events have been called on this
+ // delegate.
+ bool overscroll_started() { return overscroll_started_; }
+ bool overscroll_completing() { return overscroll_completing_; }
+ bool overscroll_completed() { return overscroll_completed_; }
+ bool overscroll_aborted() { return overscroll_aborted_; }
+
+ void ResetFlags() {
+ overscroll_started_ = false;
+ overscroll_completing_ = false;
+ overscroll_completed_ = false;
+ overscroll_aborted_ = false;
+ }
+
+ protected:
+ // aura::test::AuraTestBase:
+ void SetUp() override {
+ aura::test::AuraTestBase::SetUp();
+ main_window_.reset(CreateNormalWindow(0, root_window(), nullptr));
+ ResetFlags();
+ create_window_ = true;
+ last_window_id_ = 0;
+ owa_.reset(new OverscrollWindowAnimation(this));
+ }
+
+ void TearDown() override {
+ owa_.reset();
+ main_window_.reset();
+ aura::test::AuraTestBase::TearDown();
+ }
+
+ // OverscrollWindowAnimation::Delegate:
+ scoped_ptr<aura::Window> CreateFrontWindow(const gfx::Rect& bounds) override {
+ return CreateSlideWindow(bounds);
+ }
+
+ scoped_ptr<aura::Window> CreateBackWindow(const gfx::Rect& bounds) override {
+ return CreateSlideWindow(bounds);
+ }
+
+ aura::Window* GetMainWindow() const override { return main_window_.get(); }
+
+ void OnOverscrollCompleting() override { overscroll_completing_ = true; }
+
+ void OnOverscrollCompleted(scoped_ptr<aura::Window> window) override {
+ overscroll_completed_ = true;
+ }
+
+ void OnOverscrollCancelled() override { overscroll_aborted_ = true; }
+
+ private:
+ // The overscroll window animation under test.
+ scoped_ptr<OverscrollWindowAnimation> owa_;
+
+ scoped_ptr<aura::Window> CreateSlideWindow(const gfx::Rect& bounds) {
+ overscroll_started_ = true;
+ if (create_window_) {
+ scoped_ptr<aura::Window> window(
+ CreateNormalWindow(++last_window_id_, root_window(), nullptr));
+ window->SetBounds(bounds);
+ return window.Pass();
+ }
+ return nullptr;
+ }
+
+ // Controls if we return a window for the window creation callbacks or not.
+ bool create_window_;
+
+ // State flags.
+ bool overscroll_started_;
+ bool overscroll_completing_;
+ bool overscroll_completed_;
+ bool overscroll_aborted_;
+
+ int last_window_id_;
+
+ // The dummy target window we provide.
+ scoped_ptr<aura::Window> main_window_;
+
+ DISALLOW_COPY_AND_ASSIGN(OverscrollWindowAnimationTest);
+};
+
+// Tests a simple overscroll gesture.
+TEST_F(OverscrollWindowAnimationTest, BasicOverscroll) {
+ EXPECT_FALSE(owa()->is_active());
+ EXPECT_FALSE(overscroll_started());
+ EXPECT_FALSE(overscroll_completing());
+ EXPECT_FALSE(overscroll_completed());
+ EXPECT_FALSE(overscroll_aborted());
+
+ // Start an OVERSCROLL_EAST gesture.
+ owa()->OnOverscrollModeChange(OVERSCROLL_NONE, OVERSCROLL_EAST);
+ EXPECT_TRUE(owa()->is_active());
+ EXPECT_TRUE(overscroll_started());
+ EXPECT_FALSE(overscroll_completing());
+ EXPECT_FALSE(overscroll_completed());
+ EXPECT_FALSE(overscroll_aborted());
+
+ // Complete the overscroll.
+ owa()->OnOverscrollComplete(OVERSCROLL_EAST);
+ EXPECT_FALSE(owa()->is_active());
+ EXPECT_TRUE(overscroll_started());
+ EXPECT_TRUE(overscroll_completing());
+ EXPECT_TRUE(overscroll_completed());
+ EXPECT_FALSE(overscroll_aborted());
+}
+
+// Tests aborting an overscroll gesture.
+TEST_F(OverscrollWindowAnimationTest, BasicAbort) {
+ // Start an OVERSCROLL_EAST gesture.
+ owa()->OnOverscrollModeChange(OVERSCROLL_NONE, OVERSCROLL_EAST);
+ // Abort the overscroll.
+ owa()->OnOverscrollModeChange(OVERSCROLL_EAST, OVERSCROLL_NONE);
+ EXPECT_FALSE(owa()->is_active());
+ EXPECT_TRUE(overscroll_started());
+ EXPECT_FALSE(overscroll_completing());
+ EXPECT_FALSE(overscroll_completed());
+ EXPECT_TRUE(overscroll_aborted());
+}
+
+// Tests starting an overscroll gesture when the slide window cannot be created.
+TEST_F(OverscrollWindowAnimationTest, BasicCannotNavigate) {
+ set_create_window(false);
+ // Start an OVERSCROLL_EAST gesture.
+ owa()->OnOverscrollModeChange(OVERSCROLL_NONE, OVERSCROLL_EAST);
+ EXPECT_FALSE(owa()->is_active());
+ EXPECT_TRUE(overscroll_started());
+ EXPECT_FALSE(overscroll_completing());
+ EXPECT_FALSE(overscroll_completed());
+ EXPECT_FALSE(overscroll_aborted());
+}
+
+// Tests starting an overscroll gesture while another one was in progress
+// completes the first one.
+TEST_F(OverscrollWindowAnimationTest, NewOverscrollCompletesPreviousGesture) {
+ // This test requires a normal animation duration so that
+ // OnImplicitAnimationsCancelled is not called as soon as the first overscroll
+ // finishes.
+ ui::ScopedAnimationDurationScaleMode normal_duration(
+ ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
+ ui::LayerAnimator* animator = GetMainWindow()->layer()->GetAnimator();
+ ui::ScopedLayerAnimationSettings settings(animator);
+ animator->set_disable_timer_for_test(true);
+ ui::LayerAnimatorTestController test_controller(animator);
+ // Start an OVERSCROLL_EAST gesture.
+ owa()->OnOverscrollModeChange(OVERSCROLL_NONE, OVERSCROLL_EAST);
+
+ // Finishes the OVERSCROLL_EAST gesture. At this point the window should be
+ // being animated to its final position.
+ owa()->OnOverscrollComplete(OVERSCROLL_EAST);
+ EXPECT_TRUE(owa()->is_active());
+ EXPECT_TRUE(overscroll_started());
+ EXPECT_TRUE(overscroll_completing());
+ EXPECT_FALSE(overscroll_completed());
+ EXPECT_FALSE(overscroll_aborted());
+
+ // Start another OVERSCROLL_EAST gesture.
+ owa()->OnOverscrollModeChange(OVERSCROLL_NONE, OVERSCROLL_EAST);
+ EXPECT_TRUE(owa()->is_active());
+ EXPECT_TRUE(overscroll_started());
+ EXPECT_TRUE(overscroll_completing());
+ EXPECT_TRUE(overscroll_completed());
+ EXPECT_FALSE(overscroll_aborted());
+
+ // Complete the overscroll gesture.
+ ResetFlags();
+ owa()->OnOverscrollComplete(OVERSCROLL_EAST);
+
+ base::TimeDelta duration = settings.GetTransitionDuration();
+ test_controller.StartThreadedAnimationsIfNeeded();
+ base::TimeTicks start_time = gfx::FrameTime::Now();
+
+ // Halfway through the animation, OverscrollCompleting should have been fired.
+ animator->Step(start_time + duration / 2);
+ EXPECT_TRUE(owa()->is_active());
+ EXPECT_FALSE(overscroll_started());
+ EXPECT_TRUE(overscroll_completing());
+ EXPECT_FALSE(overscroll_completed());
+ EXPECT_FALSE(overscroll_aborted());
+
+ // The animation has finished, OverscrollCompleted should have been fired.
+ animator->Step(start_time + duration);
+ EXPECT_FALSE(owa()->is_active());
+ EXPECT_FALSE(overscroll_started());
+ EXPECT_TRUE(overscroll_completing());
+ EXPECT_TRUE(overscroll_completed());
+ EXPECT_FALSE(overscroll_aborted());
+}
+
+} // namespace content
diff --git a/chromium/content/browser/web_contents/aura/overscroll_window_delegate.cc b/chromium/content/browser/web_contents/aura/overscroll_window_delegate.cc
new file mode 100644
index 00000000000..d8ce8b6beed
--- /dev/null
+++ b/chromium/content/browser/web_contents/aura/overscroll_window_delegate.cc
@@ -0,0 +1,131 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/web_contents/aura/overscroll_window_delegate.h"
+
+#include "base/i18n/rtl.h"
+#include "content/browser/frame_host/navigation_controller_impl.h"
+#include "content/browser/frame_host/navigation_entry_impl.h"
+#include "content/browser/renderer_host/overscroll_controller_delegate.h"
+#include "content/public/browser/overscroll_configuration.h"
+#include "ui/aura/window.h"
+#include "ui/gfx/image/image_png_rep.h"
+
+namespace content {
+
+OverscrollWindowDelegate::OverscrollWindowDelegate(
+ OverscrollControllerDelegate* delegate,
+ const gfx::Image& image)
+ : delegate_(delegate),
+ overscroll_mode_(OVERSCROLL_NONE),
+ delta_x_(0.f),
+ complete_threshold_ratio_(content::GetOverscrollConfig(
+ content::OVERSCROLL_CONFIG_HORIZ_THRESHOLD_COMPLETE)),
+ start_threshold_touchscreen_(content::GetOverscrollConfig(
+ content::OVERSCROLL_CONFIG_HORIZ_THRESHOLD_START_TOUCHSCREEN)),
+ start_threshold_touchpad_(content::GetOverscrollConfig(
+ content::OVERSCROLL_CONFIG_HORIZ_THRESHOLD_START_TOUCHPAD)),
+ active_start_threshold_(0.f) {
+ SetImage(image);
+}
+
+OverscrollWindowDelegate::~OverscrollWindowDelegate() {
+}
+
+void OverscrollWindowDelegate::StartOverscroll() {
+ OverscrollMode old_mode = overscroll_mode_;
+ if (delta_x_ > 0)
+ overscroll_mode_ = OVERSCROLL_EAST;
+ else
+ overscroll_mode_ = OVERSCROLL_WEST;
+ delegate_->OnOverscrollModeChange(old_mode, overscroll_mode_);
+}
+
+void OverscrollWindowDelegate::ResetOverscroll() {
+ if (overscroll_mode_ == OVERSCROLL_NONE)
+ return;
+ delegate_->OnOverscrollModeChange(overscroll_mode_, OVERSCROLL_NONE);
+ overscroll_mode_ = OVERSCROLL_NONE;
+ delta_x_ = 0;
+}
+
+void OverscrollWindowDelegate::CompleteOrResetOverscroll() {
+ if (overscroll_mode_ == OVERSCROLL_NONE)
+ return;
+ int width = delegate_->GetVisibleBounds().width();
+ float ratio = (fabs(delta_x_)) / width;
+ if (ratio < complete_threshold_ratio_) {
+ ResetOverscroll();
+ return;
+ }
+ delegate_->OnOverscrollComplete(overscroll_mode_);
+ overscroll_mode_ = OVERSCROLL_NONE;
+ delta_x_ = 0;
+}
+
+void OverscrollWindowDelegate::UpdateOverscroll(float delta_x) {
+ float old_delta_x = delta_x_;
+ delta_x_ += delta_x;
+ if (overscroll_mode_ == OVERSCROLL_NONE) {
+ if (fabs(delta_x_) > active_start_threshold_)
+ StartOverscroll();
+ return;
+ }
+ if ((old_delta_x < 0 && delta_x_ > 0) || (old_delta_x > 0 && delta_x_ < 0)) {
+ ResetOverscroll();
+ return;
+ }
+ delegate_->OnOverscrollUpdate(delta_x_, 0.f);
+}
+
+void OverscrollWindowDelegate::OnKeyEvent(ui::KeyEvent* event) {
+ ResetOverscroll();
+}
+
+void OverscrollWindowDelegate::OnMouseEvent(ui::MouseEvent* event) {
+ if (!(event->flags() & ui::EF_IS_SYNTHESIZED) &&
+ event->type() != ui::ET_MOUSE_CAPTURE_CHANGED) {
+ ResetOverscroll();
+ }
+}
+
+void OverscrollWindowDelegate::OnScrollEvent(ui::ScrollEvent* event) {
+ active_start_threshold_ = start_threshold_touchpad_;
+ if (event->type() == ui::ET_SCROLL)
+ UpdateOverscroll(event->x_offset_ordinal());
+ else if (event->type() == ui::ET_SCROLL_FLING_START)
+ CompleteOrResetOverscroll();
+ else
+ ResetOverscroll();
+ event->SetHandled();
+}
+
+void OverscrollWindowDelegate::OnGestureEvent(ui::GestureEvent* event) {
+ active_start_threshold_ = start_threshold_touchscreen_;
+ switch (event->type()) {
+ case ui::ET_GESTURE_SCROLL_UPDATE:
+ UpdateOverscroll(event->details().scroll_x());
+ break;
+
+ case ui::ET_GESTURE_SCROLL_END:
+ CompleteOrResetOverscroll();
+ break;
+
+ case ui::ET_SCROLL_FLING_START:
+ CompleteOrResetOverscroll();
+ break;
+
+ case ui::ET_GESTURE_PINCH_BEGIN:
+ case ui::ET_GESTURE_PINCH_UPDATE:
+ case ui::ET_GESTURE_PINCH_END:
+ ResetOverscroll();
+ break;
+
+ default:
+ break;
+ }
+ event->SetHandled();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/web_contents/aura/overscroll_window_delegate.h b/chromium/content/browser/web_contents/aura/overscroll_window_delegate.h
new file mode 100644
index 00000000000..aeca347cfd8
--- /dev/null
+++ b/chromium/content/browser/web_contents/aura/overscroll_window_delegate.h
@@ -0,0 +1,73 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_WEB_CONTENTS_AURA_OVERSCROLL_WINDOW_DELEGATE_H_
+#define CONTENT_BROWSER_WEB_CONTENTS_AURA_OVERSCROLL_WINDOW_DELEGATE_H_
+
+#include "content/browser/renderer_host/overscroll_controller.h"
+#include "content/browser/web_contents/aura/overscroll_navigation_overlay.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "ui/aura_extra/image_window_delegate.h"
+
+namespace content {
+
+// The window delegate for the overscroll window. This processes UI trackpad and
+// touch events and converts them to overscroll event. The delegate destroys
+// itself when the window is destroyed.
+class CONTENT_EXPORT OverscrollWindowDelegate
+ : public aura_extra::ImageWindowDelegate {
+ public:
+ OverscrollWindowDelegate(OverscrollControllerDelegate* delegate,
+ const gfx::Image& image);
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(OverscrollWindowDelegateTest, BasicOverscrollModes);
+
+ ~OverscrollWindowDelegate() override;
+
+ // Starts the overscroll gesture.
+ void StartOverscroll();
+
+ // Resets the overscroll state.
+ void ResetOverscroll();
+
+ // Completes or resets the overscroll from the current state.
+ void CompleteOrResetOverscroll();
+
+ // Updates the current horizontal overscroll.
+ void UpdateOverscroll(float delta_x);
+
+ // Overridden from ui::EventHandler.
+ void OnKeyEvent(ui::KeyEvent* event) override;
+ void OnMouseEvent(ui::MouseEvent* event) override;
+ void OnScrollEvent(ui::ScrollEvent* event) override;
+ void OnGestureEvent(ui::GestureEvent* event) override;
+
+ // Delegate to which we forward overscroll events.
+ OverscrollControllerDelegate* delegate_;
+
+ // The current overscroll mode.
+ OverscrollMode overscroll_mode_;
+
+ // The latest delta_x scroll update.
+ float delta_x_;
+
+ // The ratio of overscroll at which we consider the overscroll completed.
+ const float complete_threshold_ratio_;
+
+ // The threshold for starting the overscroll gesture, for touchscreen or
+ // touchpads.
+ const float start_threshold_touchscreen_;
+ const float start_threshold_touchpad_;
+
+ // The threshold for starting the overscroll gesture for the current touch
+ // input.
+ float active_start_threshold_;
+
+ DISALLOW_COPY_AND_ASSIGN(OverscrollWindowDelegate);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_WEB_CONTENTS_AURA_OVERSCROLL_WINDOW_DELEGATE_H_
diff --git a/chromium/content/browser/web_contents/aura/overscroll_window_delegate_unittest.cc b/chromium/content/browser/web_contents/aura/overscroll_window_delegate_unittest.cc
new file mode 100644
index 00000000000..13382a8656f
--- /dev/null
+++ b/chromium/content/browser/web_contents/aura/overscroll_window_delegate_unittest.cc
@@ -0,0 +1,253 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/web_contents/aura/overscroll_window_delegate.h"
+
+#include "content/browser/renderer_host/overscroll_controller_delegate.h"
+#include "content/public/browser/overscroll_configuration.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/aura/test/aura_test_base.h"
+#include "ui/aura/window.h"
+#include "ui/events/gesture_detection/gesture_configuration.h"
+#include "ui/events/test/event_generator.h"
+
+namespace content {
+
+namespace {
+const int kTestWindowWidth = 600;
+}
+
+class OverscrollWindowDelegateTest : public aura::test::AuraTestBase,
+ public OverscrollControllerDelegate {
+ public:
+ OverscrollWindowDelegateTest()
+ : window_(nullptr),
+ overscroll_complete_(false),
+ overscroll_started_(false),
+ mode_changed_(false),
+ current_mode_(OVERSCROLL_NONE),
+ touch_start_threshold_(content::GetOverscrollConfig(
+ content::OVERSCROLL_CONFIG_HORIZ_THRESHOLD_START_TOUCHSCREEN)),
+ touch_complete_threshold_(content::GetOverscrollConfig(
+ content::OVERSCROLL_CONFIG_HORIZ_THRESHOLD_COMPLETE)) {
+ }
+
+ ~OverscrollWindowDelegateTest() override {}
+
+ void Reset() {
+ overscroll_complete_ = false;
+ overscroll_started_ = false;
+ mode_changed_ = false;
+ current_mode_ = OVERSCROLL_NONE;
+ window_.reset(CreateNormalWindow(
+ 0, root_window(), new OverscrollWindowDelegate(this, gfx::Image())));
+ window_->SetBounds(gfx::Rect(0, 0, kTestWindowWidth, kTestWindowWidth));
+ }
+
+ // Accessors.
+ aura::Window* window() { return window_.get(); }
+
+ bool overscroll_complete() { return overscroll_complete_; }
+ bool overscroll_started() { return overscroll_started_; }
+ bool mode_changed() { return mode_changed_; }
+
+ OverscrollMode current_mode() { return current_mode_; }
+
+ const float touch_start_threshold() {
+ return touch_start_threshold_;
+ }
+
+ const float touch_complete_threshold() {
+ return kTestWindowWidth * touch_complete_threshold_;
+ }
+
+ protected:
+ // aura::test::AuraTestBase:
+ void SetUp() override {
+ aura::test::AuraTestBase::SetUp();
+ Reset();
+ ui::GestureConfiguration::GetInstance()
+ ->set_max_touch_move_in_pixels_for_click(0);
+ }
+
+ void TearDown() override {
+ window_.reset();
+ aura::test::AuraTestBase::TearDown();
+ }
+
+ private:
+ // OverscrollControllerDelegate:
+ gfx::Rect GetVisibleBounds() const override {
+ return gfx::Rect(kTestWindowWidth, kTestWindowWidth);
+ }
+
+ bool OnOverscrollUpdate(float delta_x, float delta_y) override {
+ return true;
+ }
+
+ void OnOverscrollComplete(OverscrollMode overscroll_mode) override {
+ overscroll_complete_ = true;
+ }
+
+ void OnOverscrollModeChange(OverscrollMode old_mode,
+ OverscrollMode new_mode) override {
+ mode_changed_ = true;
+ current_mode_ = new_mode;
+ if (current_mode_ != OVERSCROLL_NONE)
+ overscroll_started_ = true;
+ }
+
+ // Window in which the overscroll window delegate is installed.
+ scoped_ptr<aura::Window> window_;
+
+ // State flags.
+ bool overscroll_complete_;
+ bool overscroll_started_;
+ bool mode_changed_;
+ OverscrollMode current_mode_;
+
+ // Config defined constants.
+ const float touch_start_threshold_;
+ const float touch_complete_threshold_;
+
+ DISALLOW_COPY_AND_ASSIGN(OverscrollWindowDelegateTest);
+};
+
+// Tests that the basic overscroll gesture works and sends updates to the
+// delegate.
+TEST_F(OverscrollWindowDelegateTest, BasicOverscroll) {
+ ui::test::EventGenerator generator(root_window());
+
+ // Start an OVERSCROLL_EAST gesture.
+ generator.GestureScrollSequence(
+ gfx::Point(0, 0), gfx::Point(touch_complete_threshold() + 1, 10),
+ base::TimeDelta::FromMilliseconds(10), 10);
+ EXPECT_TRUE(overscroll_started());
+ EXPECT_EQ(current_mode(), OVERSCROLL_EAST);
+ EXPECT_TRUE(overscroll_complete());
+
+ Reset();
+ // Start an OVERSCROLL_WEST gesture.
+ generator.GestureScrollSequence(gfx::Point(touch_complete_threshold() + 1, 0),
+ gfx::Point(0, 0),
+ base::TimeDelta::FromMilliseconds(10), 10);
+ EXPECT_TRUE(overscroll_started());
+ EXPECT_EQ(current_mode(), OVERSCROLL_WEST);
+ EXPECT_TRUE(overscroll_complete());
+}
+
+// Verifies that the OverscrollWindowDelegate direction is set correctly during
+// an overscroll.
+TEST_F(OverscrollWindowDelegateTest, BasicOverscrollModes) {
+ ui::test::EventGenerator generator(root_window());
+ OverscrollWindowDelegate* delegate =
+ static_cast<OverscrollWindowDelegate*>(window()->delegate());
+
+ // Start pressing a touch, but do not start the gesture yet.
+ generator.MoveTouch(gfx::Point(0, 0));
+ generator.PressTouch();
+ EXPECT_EQ(delegate->overscroll_mode_, OVERSCROLL_NONE);
+
+ // Slide the touch to the right.
+ generator.MoveTouch(gfx::Point(touch_complete_threshold() + 1, 0));
+ EXPECT_EQ(delegate->overscroll_mode_, OVERSCROLL_EAST);
+
+ // Complete the gesture.
+ generator.ReleaseTouch();
+ EXPECT_EQ(delegate->overscroll_mode_, OVERSCROLL_NONE);
+ EXPECT_TRUE(overscroll_complete());
+
+ // Start another overscroll.
+ generator.MoveTouch(gfx::Point(touch_complete_threshold() + 1, 0));
+ generator.PressTouch();
+ EXPECT_EQ(delegate->overscroll_mode_, OVERSCROLL_NONE);
+
+ // Slide the touch to the left.
+ generator.MoveTouch(gfx::Point(0, 0));
+ EXPECT_EQ(delegate->overscroll_mode_, OVERSCROLL_WEST);
+
+ // Complete the gesture.
+ generator.ReleaseTouch();
+ EXPECT_EQ(delegate->overscroll_mode_, OVERSCROLL_NONE);
+ EXPECT_TRUE(overscroll_complete());
+
+ // Generate a mouse events which normally cancel the overscroll. Confirm
+ // that superfluous mode changed events are not dispatched.
+ Reset();
+ generator.PressLeftButton();
+ generator.MoveMouseTo(gfx::Point(10, 10));
+ EXPECT_FALSE(mode_changed());
+}
+
+// Tests that the overscroll does not start until the gesture gets past a
+// particular threshold.
+TEST_F(OverscrollWindowDelegateTest, OverscrollThreshold) {
+ ui::test::EventGenerator generator(root_window());
+
+ // Start an OVERSCROLL_EAST gesture.
+ generator.GestureScrollSequence(gfx::Point(0, 0),
+ gfx::Point(touch_start_threshold(), 0),
+ base::TimeDelta::FromMilliseconds(10), 10);
+ EXPECT_FALSE(overscroll_started());
+ EXPECT_EQ(current_mode(), OVERSCROLL_NONE);
+ EXPECT_FALSE(overscroll_complete());
+
+ Reset();
+ // Start an OVERSCROLL_WEST gesture.
+ generator.GestureScrollSequence(gfx::Point(touch_start_threshold(), 0),
+ gfx::Point(0, 0),
+ base::TimeDelta::FromMilliseconds(10), 10);
+ EXPECT_FALSE(overscroll_started());
+ EXPECT_EQ(current_mode(), OVERSCROLL_NONE);
+ EXPECT_FALSE(overscroll_complete());
+}
+
+// Tests that the overscroll is aborted if the gesture does not get past the
+// completion threshold.
+TEST_F(OverscrollWindowDelegateTest, AbortOverscrollThreshold) {
+ ui::test::EventGenerator generator(root_window());
+
+ // Start an OVERSCROLL_EAST gesture.
+ generator.GestureScrollSequence(gfx::Point(0, 0),
+ gfx::Point(touch_start_threshold() + 1, 0),
+ base::TimeDelta::FromMilliseconds(10), 10);
+ EXPECT_TRUE(overscroll_started());
+ EXPECT_EQ(current_mode(), OVERSCROLL_NONE);
+ EXPECT_FALSE(overscroll_complete());
+
+ Reset();
+ // Start an OVERSCROLL_WEST gesture.
+ generator.GestureScrollSequence(gfx::Point(touch_start_threshold() + 1, 0),
+ gfx::Point(0, 0),
+ base::TimeDelta::FromMilliseconds(10), 10);
+ EXPECT_TRUE(overscroll_started());
+ EXPECT_EQ(current_mode(), OVERSCROLL_NONE);
+ EXPECT_FALSE(overscroll_complete());
+}
+
+// Tests that the overscroll is aborted if the delegate receives some other
+// event.
+TEST_F(OverscrollWindowDelegateTest, EventAbortsOverscroll) {
+ ui::test::EventGenerator generator(root_window());
+ // Start an OVERSCROLL_EAST gesture, without releasing touch.
+ generator.set_current_location(gfx::Point(0, 0));
+ generator.PressTouch();
+ int touch_x = touch_start_threshold() + 1;
+ generator.MoveTouch(gfx::Point(touch_x, 0));
+ EXPECT_TRUE(overscroll_started());
+ EXPECT_EQ(current_mode(), OVERSCROLL_EAST);
+ EXPECT_FALSE(overscroll_complete());
+
+ // Dispatch a mouse event, the overscroll should be cancelled.
+ generator.PressLeftButton();
+ EXPECT_EQ(current_mode(), OVERSCROLL_NONE);
+ EXPECT_FALSE(overscroll_complete());
+
+ // We should be able to restart the overscroll without lifting the finger.
+ generator.MoveTouch(gfx::Point(touch_x + touch_start_threshold() + 1, 0));
+ EXPECT_EQ(current_mode(), OVERSCROLL_EAST);
+ EXPECT_FALSE(overscroll_complete());
+}
+
+} // namespace content
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 83e403b00b2..a38d5ca2b57 100644
--- a/chromium/content/browser/web_contents/aura/shadow_layer_delegate.cc
+++ b/chromium/content/browser/web_contents/aura/shadow_layer_delegate.cc
@@ -8,6 +8,7 @@
#include "third_party/skia/include/effects/SkGradientShader.h"
#include "ui/aura/window.h"
#include "ui/compositor/layer.h"
+#include "ui/compositor/paint_recorder.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/skia_util.h"
@@ -33,7 +34,7 @@ ShadowLayerDelegate::ShadowLayerDelegate(ui::Layer* shadow_for)
ShadowLayerDelegate::~ShadowLayerDelegate() {
}
-void ShadowLayerDelegate::OnPaintLayer(gfx::Canvas* canvas) {
+void ShadowLayerDelegate::OnPaintLayer(const ui::PaintContext& context) {
SkPoint points[2];
const SkColor kShadowColors[2] = { kShadowLightColor, kShadowDarkColor };
@@ -48,7 +49,8 @@ void ShadowLayerDelegate::OnPaintLayer(gfx::Canvas* canvas) {
layer_->bounds().height());
SkPaint paint;
paint.setShader(shader.get());
- canvas->sk_canvas()->drawRect(gfx::RectToSkRect(paint_rect), paint);
+ ui::PaintRecorder recorder(context);
+ recorder.canvas()->DrawRect(paint_rect, paint);
}
void ShadowLayerDelegate::OnDelegatedFrameDamage(
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 69c2dcbc7da..c9a0b7ed7d1 100644
--- a/chromium/content/browser/web_contents/aura/shadow_layer_delegate.h
+++ b/chromium/content/browser/web_contents/aura/shadow_layer_delegate.h
@@ -32,7 +32,7 @@ class ShadowLayerDelegate : public ui::LayerDelegate {
private:
// Overridden from ui::LayerDelegate:
- void OnPaintLayer(gfx::Canvas* canvas) override;
+ void OnPaintLayer(const ui::PaintContext& context) override;
void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override;
void OnDeviceScaleFactorChanged(float device_scale_factor) override;
base::Closure PrepareForLayerBoundsChange() override;
@@ -44,4 +44,4 @@ class ShadowLayerDelegate : public ui::LayerDelegate {
} // namespace content
-#endif // CONTENT_BROWSER_WEB_CONTENTS_AURA_SHADOW_LAYER_DELEGATE_H_
+#endif // CONTENT_BROWSER_WEB_CONTENTS_AURA_SHADOW_LAYER_DELEGATE_H_
diff --git a/chromium/content/browser/web_contents/aura/window_slider.cc b/chromium/content/browser/web_contents/aura/window_slider.cc
deleted file mode 100644
index f7ffa7e3839..00000000000
--- a/chromium/content/browser/web_contents/aura/window_slider.cc
+++ /dev/null
@@ -1,309 +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/web_contents/aura/window_slider.h"
-
-#include <algorithm>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "content/browser/web_contents/aura/shadow_layer_delegate.h"
-#include "content/public/browser/overscroll_configuration.h"
-#include "ui/aura/window.h"
-#include "ui/compositor/layer_animation_observer.h"
-#include "ui/compositor/scoped_layer_animation_settings.h"
-#include "ui/events/event.h"
-
-namespace content {
-
-namespace {
-
-// An animation observer that runs a callback at the end of the animation, and
-// destroys itself.
-class CallbackAnimationObserver : public ui::ImplicitAnimationObserver {
- public:
- CallbackAnimationObserver(const base::Closure& closure)
- : closure_(closure) {
- }
-
- ~CallbackAnimationObserver() override {}
-
- private:
- // Overridden from ui::ImplicitAnimationObserver:
- void OnImplicitAnimationsCompleted() override {
- if (!closure_.is_null())
- closure_.Run();
- base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
- }
-
- const base::Closure closure_;
-
- DISALLOW_COPY_AND_ASSIGN(CallbackAnimationObserver);
-};
-
-} // namespace
-
-WindowSlider::WindowSlider(Delegate* delegate,
- aura::Window* event_window,
- aura::Window* owner)
- : delegate_(delegate),
- event_window_(event_window),
- owner_(owner),
- active_animator_(NULL),
- delta_x_(0.f),
- 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)),
- weak_factory_(this) {
- event_window_->AddPreTargetHandler(this);
-
- event_window_->AddObserver(this);
- owner_->AddObserver(this);
-}
-
-WindowSlider::~WindowSlider() {
- if (event_window_) {
- event_window_->RemovePreTargetHandler(this);
- event_window_->RemoveObserver(this);
- }
- if (owner_)
- owner_->RemoveObserver(this);
- delegate_->OnWindowSliderDestroyed();
-}
-
-void WindowSlider::ChangeOwner(aura::Window* new_owner) {
- if (owner_)
- owner_->RemoveObserver(this);
- owner_ = new_owner;
- if (owner_) {
- owner_->AddObserver(this);
- UpdateForScroll(0.f, 0.f);
- }
-}
-
-bool WindowSlider::IsSlideInProgress() const {
- // if active_start_threshold_ is 0, it means that sliding hasn't been started
- return active_start_threshold_ != 0 && (slider_.get() || active_animator_);
-}
-
-void WindowSlider::SetupSliderLayer() {
- ui::Layer* parent = owner_->layer()->parent();
- parent->Add(slider_.get());
- if (delta_x_ < 0)
- parent->StackAbove(slider_.get(), owner_->layer());
- else
- parent->StackBelow(slider_.get(), owner_->layer());
- slider_->SetBounds(owner_->layer()->bounds());
- slider_->SetVisible(true);
-}
-
-void WindowSlider::UpdateForScroll(float x_offset, float y_offset) {
- if (active_animator_) {
- // If there is an active animation, complete it before processing the scroll
- // so that the callbacks that are invoked on the Delegate are consistent.
- // Completing the animation may destroy WindowSlider through the animation
- // callback, so we can't continue processing the scroll event here.
- delta_x_ += x_offset;
- CompleteActiveAnimations();
- return;
- }
-
- float old_delta = delta_x_;
- delta_x_ += x_offset;
- if (fabs(delta_x_) < active_start_threshold_ && !slider_.get())
- return;
-
- if ((old_delta < 0 && delta_x_ > 0) ||
- (old_delta > 0 && delta_x_ < 0)) {
- slider_.reset();
- shadow_.reset();
- }
-
- float translate = 0.f;
- ui::Layer* translate_layer = NULL;
-
- if (!slider_.get()) {
- slider_.reset(delta_x_ < 0 ? delegate_->CreateFrontLayer() :
- delegate_->CreateBackLayer());
- if (!slider_.get())
- return;
- SetupSliderLayer();
- }
-
- if (delta_x_ <= -active_start_threshold_) {
- translate = owner_->bounds().width() +
- std::max(delta_x_ + active_start_threshold_,
- static_cast<float>(-owner_->bounds().width()));
- translate_layer = slider_.get();
- } else if (delta_x_ >= active_start_threshold_) {
- translate = std::min(delta_x_ - active_start_threshold_,
- static_cast<float>(owner_->bounds().width()));
- translate_layer = owner_->layer();
- } else {
- return;
- }
-
- if (!shadow_.get())
- shadow_.reset(new ShadowLayerDelegate(translate_layer));
-
- gfx::Transform transform;
- transform.Translate(translate, 0);
- translate_layer->SetTransform(transform);
-}
-
-void WindowSlider::CompleteOrResetSlide() {
- if (!slider_.get())
- return;
-
- int width = owner_->bounds().width();
- float ratio = (fabs(delta_x_) - active_start_threshold_) / width;
- if (ratio < complete_threshold_) {
- ResetSlide();
- return;
- }
-
- ui::Layer* sliding = delta_x_ < 0 ? slider_.get() : owner_->layer();
- active_animator_ = sliding->GetAnimator();
-
- ui::ScopedLayerAnimationSettings settings(active_animator_);
- settings.SetPreemptionStrategy(
- ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
- settings.SetTweenType(gfx::Tween::EASE_OUT);
- settings.AddObserver(new CallbackAnimationObserver(
- base::Bind(&WindowSlider::SlideAnimationCompleted,
- weak_factory_.GetWeakPtr(),
- base::Passed(&slider_),
- base::Passed(&shadow_))));
-
- gfx::Transform transform;
- transform.Translate(delta_x_ < 0 ? 0 : width, 0);
- delta_x_ = 0;
- delegate_->OnWindowSlideCompleting();
- sliding->SetTransform(transform);
-}
-
-void WindowSlider::CompleteActiveAnimations() {
- if (active_animator_)
- active_animator_->StopAnimating();
-}
-
-void WindowSlider::ResetSlide() {
- if (!slider_.get())
- return;
-
- // Reset the state of the sliding layer.
- if (slider_.get()) {
- ui::Layer* translate_layer;
- gfx::Transform transform;
- if (delta_x_ < 0) {
- translate_layer = slider_.get();
- transform.Translate(translate_layer->bounds().width(), 0);
- } else {
- translate_layer = owner_->layer();
- }
-
- active_animator_ = translate_layer->GetAnimator();
- ui::ScopedLayerAnimationSettings settings(active_animator_);
- settings.SetPreemptionStrategy(
- ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
- settings.SetTweenType(gfx::Tween::EASE_OUT);
- settings.AddObserver(new CallbackAnimationObserver(
- base::Bind(&WindowSlider::ResetSlideAnimationCompleted,
- weak_factory_.GetWeakPtr(),
- base::Passed(&slider_),
- base::Passed(&shadow_))));
- translate_layer->SetTransform(transform);
- }
-
- delta_x_ = 0.f;
-}
-
-void WindowSlider::SlideAnimationCompleted(
- scoped_ptr<ui::Layer> layer, scoped_ptr<ShadowLayerDelegate> shadow) {
- active_animator_ = NULL;
- shadow.reset();
- delegate_->OnWindowSlideCompleted(layer.Pass());
-}
-
-void WindowSlider::ResetSlideAnimationCompleted(
- scoped_ptr<ui::Layer> layer, scoped_ptr<ShadowLayerDelegate> shadow) {
- active_animator_ = NULL;
- shadow.reset();
- layer.reset();
- delegate_->OnWindowSlideAborted();
-}
-
-void WindowSlider::OnKeyEvent(ui::KeyEvent* event) {
- ResetSlide();
-}
-
-void WindowSlider::OnMouseEvent(ui::MouseEvent* event) {
- if (!(event->flags() & ui::EF_IS_SYNTHESIZED))
- ResetSlide();
-}
-
-void WindowSlider::OnScrollEvent(ui::ScrollEvent* event) {
- active_start_threshold_ = start_threshold_touchpad_;
- if (event->type() == ui::ET_SCROLL)
- UpdateForScroll(event->x_offset_ordinal(), event->y_offset_ordinal());
- else if (event->type() == ui::ET_SCROLL_FLING_START)
- CompleteOrResetSlide();
- else
- ResetSlide();
- event->SetHandled();
-}
-
-void WindowSlider::OnGestureEvent(ui::GestureEvent* event) {
- active_start_threshold_ = start_threshold_touchscreen_;
- const ui::GestureEventDetails& details = event->details();
- switch (event->type()) {
- case ui::ET_GESTURE_SCROLL_BEGIN:
- CompleteActiveAnimations();
- break;
-
- case ui::ET_GESTURE_SCROLL_UPDATE:
- UpdateForScroll(details.scroll_x(), details.scroll_y());
- break;
-
- case ui::ET_GESTURE_SCROLL_END:
- CompleteOrResetSlide();
- break;
-
- case ui::ET_SCROLL_FLING_START:
- CompleteOrResetSlide();
- break;
-
- case ui::ET_GESTURE_PINCH_BEGIN:
- case ui::ET_GESTURE_PINCH_UPDATE:
- case ui::ET_GESTURE_PINCH_END:
- ResetSlide();
- break;
-
- default:
- break;
- }
-
- event->SetHandled();
-}
-
-void WindowSlider::OnWindowRemovingFromRootWindow(aura::Window* window,
- aura::Window* new_root) {
- if (window == event_window_) {
- window->RemoveObserver(this);
- window->RemovePreTargetHandler(this);
- event_window_ = NULL;
- } else if (window == owner_) {
- window->RemoveObserver(this);
- owner_ = NULL;
- delete this;
- } else {
- NOTREACHED();
- }
-}
-
-} // namespace content
diff --git a/chromium/content/browser/web_contents/aura/window_slider.h b/chromium/content/browser/web_contents/aura/window_slider.h
deleted file mode 100644
index 3263aadadf5..00000000000
--- a/chromium/content/browser/web_contents/aura/window_slider.h
+++ /dev/null
@@ -1,156 +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_WEB_CONTENTS_AURA_WINDOW_SLIDER_H_
-#define CONTENT_BROWSER_WEB_CONTENTS_AURA_WINDOW_SLIDER_H_
-
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "content/common/content_export.h"
-#include "ui/aura/window_observer.h"
-#include "ui/compositor/layer_animator.h"
-#include "ui/events/event_handler.h"
-
-namespace ui {
-class Layer;
-}
-
-namespace content {
-
-class ShadowLayerDelegate;
-
-// A class for sliding the layer in a Window on top of other layers.
-class CONTENT_EXPORT WindowSlider : public ui::EventHandler,
- public aura::WindowObserver {
- public:
- class CONTENT_EXPORT Delegate {
- public:
- virtual ~Delegate() {}
-
- // Creates a layer to show behind the window-layer. Called when the
- // window-layer starts sliding out to reveal the layer underneath.
- // The WindowSlider takes ownership of the created layer.
- virtual ui::Layer* CreateBackLayer() = 0;
-
- // Creates a layer to show on top of the window-layer. Called when the new
- // layer needs to start sliding in on top of the window-layer.
- // The WindowSlider takes ownership of the created layer.
- virtual ui::Layer* CreateFrontLayer() = 0;
-
- // Called when the slide is aborted. Note that when the slide is aborted,
- // the WindowSlider resets any transform it applied on the window-layer.
- virtual void OnWindowSlideAborted() = 0;
-
- // Called when the slide is about to be complete. The delegate can take
- // action with the assumption that slide will complete soon (within the
- // duration of the final transition animation effect).
- // This callback is always preceeded by CreateBackLayer() or by
- // CreateFrontLayer() callback, and is guaranteed to be followed by the
- // OnWindowSlideCompleted() callback.
- virtual void OnWindowSlideCompleting() = 0;
-
- // Called when the window slide completes. Note that at the end the
- // window-layer may have been transformed. The callback here should reset
- // the transform if necessary. |layer| is the slider's layer (previously
- // created via CreateBackLayer() or CreateFrontLayer()).
- virtual void OnWindowSlideCompleted(scoped_ptr<ui::Layer> layer) = 0;
-
- // Called when the slider is destroyed.
- virtual void OnWindowSliderDestroyed() = 0;
- };
-
- // The WindowSlider slides the layers in the |owner| window. It starts
- // intercepting scroll events on |event_window|, and uses those events to
- // control the layer-slide. The lifetime of the slider is managed by the
- // lifetime of |owner|, i.e. if |owner| is destroyed, then the slider also
- // destroys itself.
- WindowSlider(Delegate* delegate,
- aura::Window* event_window,
- aura::Window* owner);
-
- ~WindowSlider() override;
-
- // Changes the owner of the slider.
- void ChangeOwner(aura::Window* new_owner);
-
- bool IsSlideInProgress() const;
-
- private:
- // Sets up the slider layer correctly (sets the correct bounds of the layer,
- // parents it to the right layer, and sets up the correct stacking order).
- void SetupSliderLayer();
-
- void UpdateForScroll(float x_offset, float y_offset);
-
- // Completes or resets the slide depending on whether the sliding layer
- // passed the "complete slide threshold".
- void CompleteOrResetSlide();
-
- // Stops all slider-owned animations, progressing them to their end-points.
- // Note that depending on the sate of the Delegate and the WindowSlider, this
- // may destroy the WindowSlider through animation callbacks.
- void CompleteActiveAnimations();
-
- // Resets in-progress slide if any, and starts the animation of the slidden
- // window to its original position.
- void ResetSlide();
-
- // The following callbacks are triggered after an animation.
- void SlideAnimationCompleted(scoped_ptr<ui::Layer> layer,
- scoped_ptr<ShadowLayerDelegate> shadow);
-
- void ResetSlideAnimationCompleted(scoped_ptr<ui::Layer> layer,
- scoped_ptr<ShadowLayerDelegate> shadow);
-
- // Overridden from ui::EventHandler:
- 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:
- void OnWindowRemovingFromRootWindow(aura::Window* window,
- aura::Window* new_root) override;
-
- Delegate* delegate_;
-
- // The slider intercepts scroll events from this window. The slider does not
- // own |event_window_|. If |event_window_| is destroyed, then the slider stops
- // listening for events, but it doesn't destroy itself.
- aura::Window* event_window_;
-
- // The window the slider operates on. The lifetime of the slider is bound to
- // this window (i.e. if |owner_| does, the slider destroys itself). The slider
- // can also delete itself when a slide gesture is completed. This does not
- // destroy |owner_|.
- aura::Window* owner_;
-
- // Set to the Animator of the currently active animation. If no animation is
- // active, this is set to NULL.
- ui::LayerAnimator* active_animator_;
-
- // The accumulated amount of horizontal scroll.
- float delta_x_;
-
- // This keeps track of the layer created by the delegate.
- scoped_ptr<ui::Layer> slider_;
-
- // This manages the shadow for the layers.
- scoped_ptr<ShadowLayerDelegate> shadow_;
-
- 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);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_WEB_CONTENTS_AURA_WINDOW_SLIDER_H_
diff --git a/chromium/content/browser/web_contents/aura/window_slider_unittest.cc b/chromium/content/browser/web_contents/aura/window_slider_unittest.cc
deleted file mode 100644
index a1988d4990b..00000000000
--- a/chromium/content/browser/web_contents/aura/window_slider_unittest.cc
+++ /dev/null
@@ -1,642 +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/web_contents/aura/window_slider.h"
-
-#include "base/bind.h"
-#include "base/time/time.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/aura/test/aura_test_base.h"
-#include "ui/aura/test/test_window_delegate.h"
-#include "ui/aura/window.h"
-#include "ui/base/hit_test.h"
-#include "ui/compositor/scoped_animation_duration_scale_mode.h"
-#include "ui/compositor/scoped_layer_animation_settings.h"
-#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 {
-
-void DispatchEventDuringScrollCallback(ui::EventProcessor* dispatcher,
- ui::Event* event,
- ui::EventType type,
- const gfx::Vector2dF& delta) {
- if (type != ui::ET_GESTURE_SCROLL_UPDATE)
- return;
- ui::EventDispatchDetails details = dispatcher->OnEventFromSource(event);
- CHECK(!details.dispatcher_destroyed);
-}
-
-void ChangeSliderOwnerDuringScrollCallback(scoped_ptr<aura::Window>* window,
- WindowSlider* slider,
- ui::EventType type,
- const gfx::Vector2dF& delta) {
- if (type != ui::ET_GESTURE_SCROLL_UPDATE)
- return;
- aura::Window* new_window = new aura::Window(NULL);
- new_window->Init(aura::WINDOW_LAYER_TEXTURED);
- new_window->Show();
- slider->ChangeOwner(new_window);
- (*window)->parent()->AddChild(new_window);
- window->reset(new_window);
-}
-
-void ConfirmSlideDuringScrollCallback(WindowSlider* slider,
- ui::EventType type,
- const gfx::Vector2dF& delta) {
- static float total_delta_x = 0;
- if (type == ui::ET_GESTURE_SCROLL_BEGIN)
- total_delta_x = 0;
-
- if (type == ui::ET_GESTURE_SCROLL_UPDATE) {
- total_delta_x += delta.x();
- if (total_delta_x >= 70)
- EXPECT_TRUE(slider->IsSlideInProgress());
- } else {
- EXPECT_FALSE(slider->IsSlideInProgress());
- }
-}
-
-void ConfirmNoSlideDuringScrollCallback(WindowSlider* slider,
- ui::EventType type,
- const gfx::Vector2dF& delta) {
- EXPECT_FALSE(slider->IsSlideInProgress());
-}
-
-// The window delegate does not receive any events.
-class NoEventWindowDelegate : public aura::test::TestWindowDelegate {
- public:
- NoEventWindowDelegate() {
- }
- ~NoEventWindowDelegate() override {}
-
- private:
- // Overridden from aura::WindowDelegate:
- bool HasHitTestMask() const override { return true; }
-
- DISALLOW_COPY_AND_ASSIGN(NoEventWindowDelegate);
-};
-
-class WindowSliderDelegateTest : public WindowSlider::Delegate {
- public:
- WindowSliderDelegateTest()
- : can_create_layer_(true),
- created_back_layer_(false),
- created_front_layer_(false),
- slide_completing_(false),
- slide_completed_(false),
- slide_aborted_(false),
- slider_destroyed_(false) {
- }
- ~WindowSliderDelegateTest() override {
- // Make sure slide_completed() gets called if slide_completing() was called.
- CHECK(!slide_completing_ || slide_completed_);
- }
-
- void Reset() {
- can_create_layer_ = true;
- created_back_layer_ = false;
- created_front_layer_ = false;
- slide_completing_ = false;
- slide_completed_ = false;
- slide_aborted_ = false;
- slider_destroyed_ = false;
- }
-
- void SetCanCreateLayer(bool can_create_layer) {
- can_create_layer_ = can_create_layer;
- }
-
- bool created_back_layer() const { return created_back_layer_; }
- bool created_front_layer() const { return created_front_layer_; }
- bool slide_completing() const { return slide_completing_; }
- bool slide_completed() const { return slide_completed_; }
- bool slide_aborted() const { return slide_aborted_; }
- bool slider_destroyed() const { return slider_destroyed_; }
-
- protected:
- ui::Layer* CreateLayerForTest() {
- CHECK(can_create_layer_);
- ui::Layer* layer = new ui::Layer(ui::LAYER_SOLID_COLOR);
- layer->SetColor(SK_ColorRED);
- return layer;
- }
-
- // Overridden from WindowSlider::Delegate:
- ui::Layer* CreateBackLayer() override {
- if (!can_create_layer_)
- return NULL;
- created_back_layer_ = true;
- return CreateLayerForTest();
- }
-
- ui::Layer* CreateFrontLayer() override {
- if (!can_create_layer_)
- return NULL;
- created_front_layer_ = true;
- return CreateLayerForTest();
- }
-
- void OnWindowSlideCompleted(scoped_ptr<ui::Layer> layer) override {
- slide_completed_ = true;
- }
-
- void OnWindowSlideCompleting() override { slide_completing_ = true; }
-
- void OnWindowSlideAborted() override { slide_aborted_ = true; }
-
- void OnWindowSliderDestroyed() override { slider_destroyed_ = true; }
-
- private:
- bool can_create_layer_;
- bool created_back_layer_;
- bool created_front_layer_;
- bool slide_completing_;
- bool slide_completed_;
- bool slide_aborted_;
- bool slider_destroyed_;
-
- DISALLOW_COPY_AND_ASSIGN(WindowSliderDelegateTest);
-};
-
-// This delegate destroys the owner window when the slider is destroyed.
-class WindowSliderDeleteOwnerOnDestroy : public WindowSliderDelegateTest {
- public:
- explicit WindowSliderDeleteOwnerOnDestroy(aura::Window* owner)
- : owner_(owner) {
- }
- ~WindowSliderDeleteOwnerOnDestroy() override {}
-
- private:
- // Overridden from WindowSlider::Delegate:
- void OnWindowSliderDestroyed() override {
- WindowSliderDelegateTest::OnWindowSliderDestroyed();
- delete owner_;
- }
-
- aura::Window* owner_;
- DISALLOW_COPY_AND_ASSIGN(WindowSliderDeleteOwnerOnDestroy);
-};
-
-// This delegate destroyes the owner window when a slide is completed.
-class WindowSliderDeleteOwnerOnComplete : public WindowSliderDelegateTest {
- public:
- explicit WindowSliderDeleteOwnerOnComplete(aura::Window* owner)
- : owner_(owner) {
- }
- ~WindowSliderDeleteOwnerOnComplete() override {}
-
- private:
- // Overridden from WindowSlider::Delegate:
- void OnWindowSlideCompleted(scoped_ptr<ui::Layer> layer) override {
- WindowSliderDelegateTest::OnWindowSlideCompleted(layer.Pass());
- delete owner_;
- }
-
- aura::Window* owner_;
- DISALLOW_COPY_AND_ASSIGN(WindowSliderDeleteOwnerOnComplete);
-};
-
-typedef aura::test::AuraTestBase WindowSliderTest;
-
-TEST_F(WindowSliderTest, WindowSlideUsingGesture) {
- scoped_ptr<aura::Window> window(CreateNormalWindow(0, root_window(), NULL));
- window->SetBounds(gfx::Rect(0, 0, 400, 400));
- WindowSliderDelegateTest slider_delegate;
-
- ui::test::EventGenerator generator(root_window());
-
- // Generate a horizontal overscroll.
- WindowSlider* slider =
- new WindowSlider(&slider_delegate, root_window(), window.get());
- generator.GestureScrollSequenceWithCallback(
- gfx::Point(10, 10),
- gfx::Point(180, 10),
- base::TimeDelta::FromMilliseconds(10),
- 10,
- base::Bind(&ConfirmSlideDuringScrollCallback, slider));
- EXPECT_TRUE(slider_delegate.created_back_layer());
- EXPECT_TRUE(slider_delegate.slide_completing());
- EXPECT_TRUE(slider_delegate.slide_completed());
- EXPECT_FALSE(slider_delegate.created_front_layer());
- EXPECT_FALSE(slider_delegate.slide_aborted());
- EXPECT_FALSE(slider_delegate.slider_destroyed());
- EXPECT_FALSE(slider->IsSlideInProgress());
- slider_delegate.Reset();
- window->SetTransform(gfx::Transform());
-
- // Generate a horizontal overscroll in the reverse direction.
- generator.GestureScrollSequenceWithCallback(
- gfx::Point(180, 10),
- gfx::Point(10, 10),
- base::TimeDelta::FromMilliseconds(10),
- 10,
- base::Bind(&ConfirmSlideDuringScrollCallback, slider));
- EXPECT_TRUE(slider_delegate.created_front_layer());
- EXPECT_TRUE(slider_delegate.slide_completing());
- EXPECT_TRUE(slider_delegate.slide_completed());
- EXPECT_FALSE(slider_delegate.created_back_layer());
- EXPECT_FALSE(slider_delegate.slide_aborted());
- EXPECT_FALSE(slider_delegate.slider_destroyed());
- EXPECT_FALSE(slider->IsSlideInProgress());
- slider_delegate.Reset();
-
- // Generate a vertical overscroll.
- generator.GestureScrollSequenceWithCallback(
- gfx::Point(10, 10),
- gfx::Point(10, 80),
- base::TimeDelta::FromMilliseconds(10),
- 10,
- base::Bind(&ConfirmNoSlideDuringScrollCallback, slider));
- EXPECT_FALSE(slider_delegate.created_back_layer());
- EXPECT_FALSE(slider_delegate.slide_completing());
- EXPECT_FALSE(slider_delegate.slide_completed());
- EXPECT_FALSE(slider_delegate.created_front_layer());
- EXPECT_FALSE(slider_delegate.slide_aborted());
- EXPECT_FALSE(slider->IsSlideInProgress());
- slider_delegate.Reset();
-
- // Generate a horizontal scroll that starts overscroll, but doesn't scroll
- // enough to complete it.
- generator.GestureScrollSequenceWithCallback(
- gfx::Point(10, 10),
- gfx::Point(80, 10),
- base::TimeDelta::FromMilliseconds(10),
- 10,
- base::Bind(&ConfirmSlideDuringScrollCallback, slider));
- EXPECT_TRUE(slider_delegate.created_back_layer());
- EXPECT_TRUE(slider_delegate.slide_aborted());
- EXPECT_FALSE(slider_delegate.created_front_layer());
- EXPECT_FALSE(slider_delegate.slide_completing());
- EXPECT_FALSE(slider_delegate.slide_completed());
- EXPECT_FALSE(slider_delegate.slider_destroyed());
- EXPECT_FALSE(slider->IsSlideInProgress());
- slider_delegate.Reset();
-
- // Destroy the window. This should destroy the slider.
- window.reset();
- EXPECT_TRUE(slider_delegate.slider_destroyed());
-}
-
-// Tests that the window slide is interrupted when a different type of event
-// happens.
-TEST_F(WindowSliderTest, WindowSlideIsCancelledOnEvent) {
- scoped_ptr<aura::Window> window(CreateNormalWindow(0, root_window(), NULL));
- window->SetBounds(gfx::Rect(0, 0, 400, 400));
- WindowSliderDelegateTest slider_delegate;
-
- ui::Event* events[] = {
- new ui::MouseEvent(ui::ET_MOUSE_MOVED,
- gfx::Point(55, 10),
- gfx::Point(55, 10),
- 0, 0),
- 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.
- ui::test::EventGenerator generator(root_window());
- generator.GestureScrollSequenceWithCallback(
- gfx::Point(10, 10),
- gfx::Point(80, 10),
- base::TimeDelta::FromMilliseconds(10),
- 1,
- base::Bind(&DispatchEventDuringScrollCallback,
- root_window()->GetHost()->event_processor(),
- base::Owned(events[i])));
- EXPECT_TRUE(slider_delegate.created_back_layer());
- EXPECT_TRUE(slider_delegate.slide_aborted());
- EXPECT_FALSE(slider_delegate.created_front_layer());
- EXPECT_FALSE(slider_delegate.slide_completing());
- EXPECT_FALSE(slider_delegate.slide_completed());
- EXPECT_FALSE(slider_delegate.slider_destroyed());
- slider_delegate.Reset();
- }
- window.reset();
- EXPECT_TRUE(slider_delegate.slider_destroyed());
-}
-
-// Tests that the window slide can continue after it is interrupted by another
-// event if the user continues scrolling.
-TEST_F(WindowSliderTest, WindowSlideInterruptedThenContinues) {
- scoped_ptr<aura::Window> window(CreateNormalWindow(0, root_window(), NULL));
- window->SetBounds(gfx::Rect(0, 0, 400, 400));
- WindowSliderDelegateTest slider_delegate;
-
- 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);
-
- WindowSlider* slider =
- new WindowSlider(&slider_delegate, root_window(), window.get());
-
- ui::MouseEvent interrupt_event(ui::ET_MOUSE_MOVED,
- gfx::Point(55, 10),
- gfx::Point(55, 10),
- 0, 0);
-
- ui::test::EventGenerator generator(root_window());
-
- // Start the scroll sequence. Scroll forward so that |window|'s layer is the
- // one animating.
- const int kTouchId = 5;
- ui::TouchEvent press(ui::ET_TOUCH_PRESSED,
- gfx::Point(10, 10),
- kTouchId,
- ui::EventTimeForNow());
- generator.Dispatch(&press);
-
- // First scroll event of the sequence.
- ui::TouchEvent move1(ui::ET_TOUCH_MOVED,
- gfx::Point(100, 10),
- kTouchId,
- ui::EventTimeForNow());
- generator.Dispatch(&move1);
- EXPECT_TRUE(slider->IsSlideInProgress());
- EXPECT_FALSE(animator->is_animating());
- // Dispatch the event after the first scroll and confirm it interrupts the
- // scroll and starts the "reset slide" animation.
- generator.Dispatch(&interrupt_event);
- EXPECT_TRUE(slider->IsSlideInProgress());
- EXPECT_TRUE(animator->is_animating());
- EXPECT_TRUE(slider_delegate.created_back_layer());
- // slide_aborted() should be false because the 'reset slide' animation
- // hasn't completed yet.
- EXPECT_FALSE(slider_delegate.slide_aborted());
- EXPECT_FALSE(slider_delegate.created_front_layer());
- EXPECT_FALSE(slider_delegate.slide_completing());
- EXPECT_FALSE(slider_delegate.slide_completed());
- EXPECT_FALSE(slider_delegate.slider_destroyed());
- slider_delegate.Reset();
-
- // Second scroll event of the sequence.
- ui::TouchEvent move2(ui::ET_TOUCH_MOVED,
- gfx::Point(200, 10),
- kTouchId,
- ui::EventTimeForNow());
- generator.Dispatch(&move2);
- // The second scroll should instantly cause the animation to complete.
- EXPECT_FALSE(animator->is_animating());
- EXPECT_FALSE(slider_delegate.created_back_layer());
- // The ResetScroll() animation was completed, so now slide_aborted()
- // should be true.
- EXPECT_TRUE(slider_delegate.slide_aborted());
-
- // Third scroll event of the sequence.
- ui::TouchEvent move3(ui::ET_TOUCH_MOVED,
- gfx::Point(300, 10),
- kTouchId,
- ui::EventTimeForNow());
- generator.Dispatch(&move3);
- // The third scroll should re-start the sliding.
- EXPECT_TRUE(slider->IsSlideInProgress());
- EXPECT_TRUE(slider_delegate.created_back_layer());
-
- // Generate the release event, finishing the scroll sequence.
- ui::TouchEvent release(ui::ET_TOUCH_RELEASED,
- gfx::Point(300, 10),
- kTouchId,
- ui::EventTimeForNow());
- generator.Dispatch(&release);
- // When the scroll gesture ends, the slide animation should start.
- EXPECT_TRUE(slider->IsSlideInProgress());
- EXPECT_TRUE(animator->is_animating());
- EXPECT_TRUE(slider_delegate.slide_completing());
- EXPECT_FALSE(slider_delegate.created_front_layer());
- EXPECT_FALSE(slider_delegate.slide_completed());
- EXPECT_FALSE(slider_delegate.slider_destroyed());
-
- // Progress the animator to complete the slide animation.
- ui::ScopedLayerAnimationSettings settings(animator);
- base::TimeDelta duration = settings.GetTransitionDuration();
- test_controller.StartThreadedAnimationsIfNeeded();
- animator->Step(gfx::FrameTime::Now() + duration);
-
- EXPECT_TRUE(slider_delegate.slide_completed());
- EXPECT_FALSE(slider_delegate.slider_destroyed());
-
- window.reset();
- EXPECT_TRUE(slider_delegate.slider_destroyed());
-}
-
-// Tests that the slide works correctly when the owner of the window changes
-// during the duration of the slide.
-TEST_F(WindowSliderTest, OwnerWindowChangesDuringWindowSlide) {
- scoped_ptr<aura::Window> parent(CreateNormalWindow(0, root_window(), NULL));
-
- NoEventWindowDelegate window_delegate;
- window_delegate.set_window_component(HTNOWHERE);
- scoped_ptr<aura::Window> window(CreateNormalWindow(1, parent.get(),
- &window_delegate));
-
- WindowSliderDelegateTest slider_delegate;
- scoped_ptr<WindowSlider> slider(
- new WindowSlider(&slider_delegate, parent.get(), window.get()));
-
- // Generate a horizontal scroll, and change the owner in the middle of the
- // scroll.
- ui::test::EventGenerator generator(root_window());
- aura::Window* old_window = window.get();
- generator.GestureScrollSequenceWithCallback(
- gfx::Point(10, 10),
- gfx::Point(80, 10),
- base::TimeDelta::FromMilliseconds(10),
- 1,
- base::Bind(&ChangeSliderOwnerDuringScrollCallback,
- base::Unretained(&window),
- slider.get()));
- aura::Window* new_window = window.get();
- EXPECT_NE(old_window, new_window);
-
- EXPECT_TRUE(slider_delegate.created_back_layer());
- EXPECT_TRUE(slider_delegate.slide_completing());
- EXPECT_TRUE(slider_delegate.slide_completed());
- EXPECT_FALSE(slider_delegate.created_front_layer());
- EXPECT_FALSE(slider_delegate.slide_aborted());
- EXPECT_FALSE(slider_delegate.slider_destroyed());
-}
-
-// If the delegate doesn't create the layer to show while sliding, WindowSlider
-// shouldn't start the slide or change delegate's state in any way in response
-// to user input.
-TEST_F(WindowSliderTest, NoSlideWhenLayerCantBeCreated) {
- scoped_ptr<aura::Window> window(CreateNormalWindow(0, root_window(), NULL));
- window->SetBounds(gfx::Rect(0, 0, 400, 400));
- WindowSliderDelegateTest slider_delegate;
- slider_delegate.SetCanCreateLayer(false);
- WindowSlider* slider =
- new WindowSlider(&slider_delegate, root_window(), window.get());
-
- ui::test::EventGenerator generator(root_window());
-
- // No slide in progress should be reported during scroll since the layer
- // wasn't created.
- generator.GestureScrollSequenceWithCallback(
- gfx::Point(10, 10),
- gfx::Point(180, 10),
- base::TimeDelta::FromMilliseconds(10),
- 1,
- base::Bind(&ConfirmNoSlideDuringScrollCallback, slider));
-
- EXPECT_FALSE(slider_delegate.created_back_layer());
- EXPECT_FALSE(slider_delegate.slide_completing());
- EXPECT_FALSE(slider_delegate.slide_completed());
- EXPECT_FALSE(slider_delegate.created_front_layer());
- EXPECT_FALSE(slider_delegate.slide_aborted());
- EXPECT_FALSE(slider_delegate.slider_destroyed());
- window->SetTransform(gfx::Transform());
-
- slider_delegate.SetCanCreateLayer(true);
- generator.GestureScrollSequenceWithCallback(
- gfx::Point(10, 10),
- gfx::Point(180, 10),
- base::TimeDelta::FromMilliseconds(10),
- 10,
- base::Bind(&ConfirmSlideDuringScrollCallback, slider));
- EXPECT_TRUE(slider_delegate.created_back_layer());
- EXPECT_TRUE(slider_delegate.slide_completing());
- EXPECT_TRUE(slider_delegate.slide_completed());
- EXPECT_FALSE(slider_delegate.created_front_layer());
- EXPECT_FALSE(slider_delegate.slide_aborted());
- EXPECT_FALSE(slider_delegate.slider_destroyed());
-
- window.reset();
- EXPECT_TRUE(slider_delegate.slider_destroyed());
-}
-
-// Tests that the owner window can be destroyed from |OnWindowSliderDestroyed()|
-// delegate callback without causing a crash.
-TEST_F(WindowSliderTest, OwnerIsDestroyedOnSliderDestroy) {
- size_t child_windows = root_window()->children().size();
- aura::Window* window = CreateNormalWindow(0, root_window(), NULL);
- window->SetBounds(gfx::Rect(0, 0, 400, 400));
- EXPECT_EQ(child_windows + 1, root_window()->children().size());
-
- WindowSliderDeleteOwnerOnDestroy slider_delegate(window);
- ui::test::EventGenerator generator(root_window());
-
- // Generate a horizontal overscroll.
- scoped_ptr<WindowSlider> slider(
- new WindowSlider(&slider_delegate, root_window(), window));
- generator.GestureScrollSequence(gfx::Point(10, 10),
- gfx::Point(180, 10),
- base::TimeDelta::FromMilliseconds(10),
- 10);
- EXPECT_TRUE(slider_delegate.created_back_layer());
- EXPECT_TRUE(slider_delegate.slide_completing());
- EXPECT_TRUE(slider_delegate.slide_completed());
- EXPECT_FALSE(slider_delegate.created_front_layer());
- EXPECT_FALSE(slider_delegate.slide_aborted());
- EXPECT_FALSE(slider_delegate.slider_destroyed());
-
- slider.reset();
- // Destroying the slider would have destroyed |window| too. So |window| should
- // not need to be destroyed here.
- EXPECT_EQ(child_windows, root_window()->children().size());
-}
-
-// Tests that the owner window can be destroyed from |OnWindowSlideComplete()|
-// delegate callback without causing a crash.
-TEST_F(WindowSliderTest, OwnerIsDestroyedOnSlideComplete) {
- size_t child_windows = root_window()->children().size();
- aura::Window* window = CreateNormalWindow(0, root_window(), NULL);
- window->SetBounds(gfx::Rect(0, 0, 400, 400));
- EXPECT_EQ(child_windows + 1, root_window()->children().size());
-
- WindowSliderDeleteOwnerOnComplete slider_delegate(window);
- ui::test::EventGenerator generator(root_window());
-
- // Generate a horizontal overscroll.
- new WindowSlider(&slider_delegate, root_window(), window);
- generator.GestureScrollSequence(gfx::Point(10, 10),
- gfx::Point(180, 10),
- base::TimeDelta::FromMilliseconds(10),
- 10);
- EXPECT_TRUE(slider_delegate.created_back_layer());
- EXPECT_TRUE(slider_delegate.slide_completing());
- EXPECT_TRUE(slider_delegate.slide_completed());
- EXPECT_FALSE(slider_delegate.created_front_layer());
- EXPECT_FALSE(slider_delegate.slide_aborted());
- EXPECT_TRUE(slider_delegate.slider_destroyed());
-
- // Destroying the slider would have destroyed |window| too. So |window| should
- // not need to be destroyed here.
- EXPECT_EQ(child_windows, root_window()->children().size());
-}
-
-// Test the scenario when two swipe gesture occur quickly one after another so
-// that the second swipe occurs while the transition animation triggered by the
-// first swipe is in progress.
-// The second swipe is supposed to instantly complete the animation caused by
-// the first swipe, ask the delegate to create a new layer, and animate it.
-TEST_F(WindowSliderTest, SwipeDuringSwipeAnimation) {
- scoped_ptr<aura::Window> window(CreateNormalWindow(0, root_window(), NULL));
- window->SetBounds(gfx::Rect(0, 0, 400, 400));
- WindowSliderDelegateTest slider_delegate;
- new WindowSlider(&slider_delegate, root_window(), window.get());
-
- // 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);
-
- ui::test::EventGenerator generator(root_window());
-
- // Swipe forward so that |window|'s layer is the one animating.
- generator.GestureScrollSequence(
- gfx::Point(10, 10),
- gfx::Point(180, 10),
- base::TimeDelta::FromMilliseconds(10),
- 2);
- EXPECT_TRUE(slider_delegate.created_back_layer());
- EXPECT_FALSE(slider_delegate.slide_aborted());
- EXPECT_FALSE(slider_delegate.created_front_layer());
- EXPECT_TRUE(slider_delegate.slide_completing());
- EXPECT_FALSE(slider_delegate.slide_completed());
- EXPECT_FALSE(slider_delegate.slider_destroyed());
- ui::ScopedLayerAnimationSettings settings(animator);
- base::TimeDelta duration = settings.GetTransitionDuration();
- test_controller.StartThreadedAnimationsIfNeeded();
- base::TimeTicks start_time1 = gfx::FrameTime::Now();
-
- animator->Step(start_time1 + duration / 2);
- EXPECT_FALSE(slider_delegate.slide_completed());
- slider_delegate.Reset();
- // Generate another horizontal swipe while the animation from the previous
- // swipe is in progress.
- generator.GestureScrollSequence(
- gfx::Point(10, 10),
- gfx::Point(180, 10),
- base::TimeDelta::FromMilliseconds(10),
- 2);
- // Performing the second swipe should instantly complete the slide started
- // by the first swipe and create a new layer.
- EXPECT_TRUE(slider_delegate.created_back_layer());
- EXPECT_FALSE(slider_delegate.slide_aborted());
- EXPECT_FALSE(slider_delegate.created_front_layer());
- EXPECT_TRUE(slider_delegate.slide_completing());
- EXPECT_TRUE(slider_delegate.slide_completed());
- EXPECT_FALSE(slider_delegate.slider_destroyed());
- test_controller.StartThreadedAnimationsIfNeeded();
- base::TimeTicks start_time2 = gfx::FrameTime::Now();
- slider_delegate.Reset();
- animator->Step(start_time2 + duration);
- // The animation for the second slide should now be completed.
- EXPECT_TRUE(slider_delegate.slide_completed());
- slider_delegate.Reset();
-
- window.reset();
- EXPECT_TRUE(slider_delegate.slider_destroyed());
-}
-
-} // namespace content
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 0a89f7189bd..dab6eb8d318 100644
--- a/chromium/content/browser/web_contents/opened_by_dom_browsertest.cc
+++ b/chromium/content/browser/web_contents/opened_by_dom_browsertest.cc
@@ -42,7 +42,7 @@ class CloseTrackingDelegate : public WebContentsDelegate {
class OpenedByDOMTest : public ContentBrowserTest {
protected:
- void SetUpCommandLine(CommandLine* command_line) override {
+ void SetUpCommandLine(base::CommandLine* command_line) override {
// Use --site-per-process to force process swaps on cross-site navigations.
command_line->AppendSwitch(switches::kSitePerProcess);
}
@@ -123,8 +123,7 @@ IN_PROC_BROWSER_TEST_F(OpenedByDOMTest, DISABLED_CrossProcessPopup) {
GURL url2 = test_server()->GetURL("files/site_isolation/blank.html?2");
GURL::Replacements replace_host;
- std::string foo_com("foo.com");
- replace_host.SetHostStr(foo_com);
+ replace_host.SetHostStr("foo.com");
url2 = url2.ReplaceComponents(replace_host);
GURL url3 = test_server()->GetURL("files/site_isolation/blank.html?3");
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 bef8ff7c6f9..622b49045ec 100644
--- a/chromium/content/browser/web_contents/touch_editable_impl_aura.cc
+++ b/chromium/content/browser/web_contents/touch_editable_impl_aura.cc
@@ -14,6 +14,7 @@
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/clipboard/clipboard.h"
+#include "ui/base/touch/selection_bound.h"
#include "ui/base/ui_base_switches_util.h"
#include "ui/gfx/range/range.h"
#include "ui/strings/grit/ui_strings.h"
@@ -52,7 +53,7 @@ void TouchEditableImplAura::UpdateEditingController() {
return;
if (text_input_type_ != ui::TEXT_INPUT_TYPE_NONE ||
- selection_anchor_rect_ != selection_focus_rect_) {
+ selection_anchor_ != selection_focus_) {
if (touch_selection_controller_)
touch_selection_controller_->SelectionChanged();
} else {
@@ -61,11 +62,12 @@ void TouchEditableImplAura::UpdateEditingController() {
}
void TouchEditableImplAura::OverscrollStarted() {
- scrolls_in_progress_++;
+ overscroll_in_progress_ = true;
}
void TouchEditableImplAura::OverscrollCompleted() {
- ScrollEnded();
+ overscroll_in_progress_ = false;
+ StartTouchEditingIfNecessary();
}
////////////////////////////////////////////////////////////////////////////////
@@ -78,7 +80,7 @@ void TouchEditableImplAura::StartTouchEditing() {
if (!touch_selection_controller_) {
touch_selection_controller_.reset(
- ui::TouchSelectionController::create(this));
+ ui::TouchEditingControllerDeprecated::Create(this));
}
if (touch_selection_controller_)
touch_selection_controller_->SelectionChanged();
@@ -96,16 +98,17 @@ void TouchEditableImplAura::EndTouchEditing(bool quick) {
}
}
-void TouchEditableImplAura::OnSelectionOrCursorChanged(const gfx::Rect& anchor,
- const gfx::Rect& focus) {
- selection_anchor_rect_ = anchor;
- selection_focus_rect_ = focus;
+void TouchEditableImplAura::OnSelectionOrCursorChanged(
+ const ui::SelectionBound& anchor,
+ const ui::SelectionBound& focus) {
+ selection_anchor_ = anchor;
+ selection_focus_ = focus;
// 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_) {
+ if (selection_gesture_in_process_ && !scroll_in_progress_ &&
+ !overscroll_in_progress_ && selection_anchor_ != selection_focus_) {
StartTouchEditing();
selection_gesture_in_process_ = false;
}
@@ -132,14 +135,16 @@ bool TouchEditableImplAura::HandleInputEvent(const ui::Event* event) {
// When the user taps, we want to show touch editing handles if user
// tapped on selected text.
if (gesture_event->details().tap_count() == 1 &&
- selection_anchor_rect_ != selection_focus_rect_) {
- // UnionRects only works for rects with non-zero width.
- gfx::Rect anchor(selection_anchor_rect_.origin(),
- gfx::Size(1, selection_anchor_rect_.height()));
- gfx::Rect focus(selection_focus_rect_.origin(),
- gfx::Size(1, selection_focus_rect_.height()));
- gfx::Rect selection_rect = gfx::UnionRects(anchor, focus);
- if (selection_rect.Contains(gesture_event->location())) {
+ selection_anchor_ != selection_focus_) {
+ gfx::Rect selection_rect =
+ ui::RectBetweenSelectionBounds(selection_anchor_, selection_focus_);
+ // When tap is on selection, show handles and mark event as handled only
+ // if handles are not present or text is not editable. Otherwise, do not
+ // set event as handles so that event is forwarded to the renderer to
+ // update selection/cursor.
+ if (selection_rect.Contains(gesture_event->location()) &&
+ (text_input_type_ == ui::TEXT_INPUT_TYPE_NONE ||
+ !touch_selection_controller_)) {
StartTouchEditing();
return true;
}
@@ -154,7 +159,7 @@ bool TouchEditableImplAura::HandleInputEvent(const ui::Event* event) {
selection_gesture_in_process_ = true;
break;
case ui::ET_GESTURE_SCROLL_BEGIN:
- scrolls_in_progress_++;
+ scroll_in_progress_ = true;;
// 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
@@ -168,7 +173,8 @@ bool TouchEditableImplAura::HandleInputEvent(const ui::Event* event) {
EndTouchEditing(true);
break;
case ui::ET_GESTURE_SCROLL_END:
- ScrollEnded();
+ scroll_in_progress_ = false;
+ StartTouchEditingIfNecessary();
break;
default:
break;
@@ -187,7 +193,8 @@ void TouchEditableImplAura::GestureEventAck(int gesture_event_type) {
}
void TouchEditableImplAura::DidStopFlinging() {
- ScrollEnded();
+ scroll_in_progress_ = false;
+ StartTouchEditingIfNecessary();
}
void TouchEditableImplAura::OnViewDestroyed() {
@@ -215,10 +222,10 @@ void TouchEditableImplAura::MoveCaretTo(const gfx::Point& point) {
host->MoveCaret(point);
}
-void TouchEditableImplAura::GetSelectionEndPoints(gfx::Rect* p1,
- gfx::Rect* p2) {
- *p1 = selection_anchor_rect_;
- *p2 = selection_focus_rect_;
+void TouchEditableImplAura::GetSelectionEndPoints(ui::SelectionBound* anchor,
+ ui::SelectionBound* focus) {
+ *anchor = selection_anchor_;
+ *focus = selection_focus_;
}
gfx::Rect TouchEditableImplAura::GetBounds() {
@@ -344,16 +351,17 @@ TouchEditableImplAura::TouchEditableImplAura()
rwhva_(NULL),
selection_gesture_in_process_(false),
handles_hidden_due_to_scroll_(false),
- scrolls_in_progress_(0),
+ scroll_in_progress_(false),
+ overscroll_in_progress_(false),
textfield_was_focused_on_tap_(false) {
}
-void TouchEditableImplAura::ScrollEnded() {
- scrolls_in_progress_--;
+void TouchEditableImplAura::StartTouchEditingIfNecessary() {
// 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_ ||
+ if (!scroll_in_progress_ && !overscroll_in_progress_ &&
+ handles_hidden_due_to_scroll_ &&
+ (selection_anchor_ != selection_focus_ ||
text_input_type_ != ui::TEXT_INPUT_TYPE_NONE)) {
StartTouchEditing();
UpdateEditingController();
@@ -370,7 +378,8 @@ void TouchEditableImplAura::Cleanup() {
EndTouchEditing(true);
selection_gesture_in_process_ = false;
handles_hidden_due_to_scroll_ = false;
- scrolls_in_progress_ = 0;
+ scroll_in_progress_ = false;
+ overscroll_in_progress_ = false;
}
} // 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 050d559124b..d7516f67b48 100644
--- a/chromium/content/browser/web_contents/touch_editable_impl_aura.h
+++ b/chromium/content/browser/web_contents/touch_editable_impl_aura.h
@@ -12,9 +12,9 @@
#include "content/browser/renderer_host/render_widget_host_view_aura.h"
#include "ui/aura/window_observer.h"
#include "ui/base/touch/touch_editing_controller.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/point.h"
-#include "ui/gfx/rect.h"
namespace ui {
class Accelerator;
@@ -38,14 +38,14 @@ class CONTENT_EXPORT TouchEditableImplAura
// depending on the current selection and cursor state.
void UpdateEditingController();
- void OverscrollStarted();
- void OverscrollCompleted();
+ virtual void OverscrollStarted();
+ virtual void OverscrollCompleted();
// Overridden from RenderWidgetHostViewAura::TouchEditingClient.
void StartTouchEditing() override;
void EndTouchEditing(bool quick) override;
- void OnSelectionOrCursorChanged(const gfx::Rect& anchor,
- const gfx::Rect& focus) override;
+ void OnSelectionOrCursorChanged(const ui::SelectionBound& anchor,
+ const ui::SelectionBound& focus) override;
void OnTextInputTypeChanged(ui::TextInputType type) override;
bool HandleInputEvent(const ui::Event* event) override;
void GestureEventAck(int gesture_event_type) override;
@@ -55,7 +55,8 @@ class CONTENT_EXPORT TouchEditableImplAura
// Overridden from ui::TouchEditable:
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;
+ void GetSelectionEndPoints(ui::SelectionBound* anchor,
+ ui::SelectionBound* focus) override;
gfx::Rect GetBounds() override;
gfx::NativeView GetNativeView() const override;
void ConvertPointToScreen(gfx::Point* point) override;
@@ -77,19 +78,19 @@ class CONTENT_EXPORT TouchEditableImplAura
// A convenience function that is called after scroll/fling/overscroll ends to
// re-activate touch selection if necessary.
- void ScrollEnded();
+ void StartTouchEditingIfNecessary();
void Cleanup();
- // Rectangles for the selection anchor and focus.
- gfx::Rect selection_anchor_rect_;
- gfx::Rect selection_focus_rect_;
+ // Bounds for the selection.
+ ui::SelectionBound selection_anchor_;
+ ui::SelectionBound selection_focus_;
// The current text input type.
ui::TextInputType text_input_type_;
RenderWidgetHostViewAura* rwhva_;
- scoped_ptr<ui::TouchSelectionController> touch_selection_controller_;
+ scoped_ptr<ui::TouchEditingControllerDeprecated> touch_selection_controller_;
// True if |rwhva_| is currently handling a gesture that could result in a
// change in selection (long press, double tap or triple tap).
@@ -99,8 +100,9 @@ class CONTENT_EXPORT TouchEditableImplAura
// whether to re-show handles after a scrolling session.
bool handles_hidden_due_to_scroll_;
- // Keeps track of number of scrolls/flings/overscrolls in progress.
- int scrolls_in_progress_;
+ // Keep track of scrolls/overscrolls in progress.
+ bool scroll_in_progress_;
+ bool overscroll_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 a35f28165b3..9ee1bbf7bf2 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
@@ -25,6 +25,7 @@
#include "ui/compositor/scoped_animation_duration_scale_mode.h"
#include "ui/events/event_utils.h"
#include "ui/events/test/event_generator.h"
+#include "ui/wm/core/default_screen_position_client.h"
using blink::WebInputEvent;
@@ -33,7 +34,11 @@ namespace content {
class TestTouchEditableImplAura : public TouchEditableImplAura {
public:
TestTouchEditableImplAura()
- : selection_changed_callback_arrived_(false),
+ : overscroll_started_callback_arrived_(false),
+ waiting_for_overscroll_started_callback_(false),
+ overscroll_completed_callback_arrived_(false),
+ waiting_for_overscroll_completed_callback_(false),
+ selection_changed_callback_arrived_(false),
waiting_for_selection_changed_callback_(false),
waiting_for_gesture_ack_type_(WebInputEvent::Undefined),
last_gesture_ack_type_(WebInputEvent::Undefined),
@@ -41,6 +46,10 @@ class TestTouchEditableImplAura : public TouchEditableImplAura {
waiting_for_fling_stop_callback_(false) {}
virtual void Reset() {
+ overscroll_started_callback_arrived_ = false;
+ waiting_for_overscroll_started_callback_ = false;
+ overscroll_completed_callback_arrived_ = false;
+ waiting_for_overscroll_completed_callback_ = false;
selection_changed_callback_arrived_ = false;
waiting_for_selection_changed_callback_ = false;
waiting_for_gesture_ack_type_ = WebInputEvent::Undefined;
@@ -49,15 +58,49 @@ class TestTouchEditableImplAura : public TouchEditableImplAura {
waiting_for_fling_stop_callback_ = false;
}
- virtual void OnSelectionOrCursorChanged(const gfx::Rect& anchor,
- const gfx::Rect& focus) override {
+ void OverscrollStarted() override {
+ overscroll_started_callback_arrived_ = true;
+ TouchEditableImplAura::OverscrollStarted();
+ if (waiting_for_overscroll_started_callback_)
+ overscroll_started_wait_run_loop_->Quit();
+}
+
+ void WaitForOverscrollStartedCallback() {
+ // Doesn't make sense to call more that once without resetting.
+ CHECK(!waiting_for_overscroll_started_callback_);
+ waiting_for_overscroll_started_callback_ = true;
+ if (overscroll_started_callback_arrived_)
+ return;
+ overscroll_started_wait_run_loop_.reset(new base::RunLoop());
+ overscroll_started_wait_run_loop_->Run();
+ }
+
+ void OverscrollCompleted() override {
+ overscroll_completed_callback_arrived_ = true;
+ TouchEditableImplAura::OverscrollCompleted();
+ if (waiting_for_overscroll_completed_callback_)
+ overscroll_completed_wait_run_loop_->Quit();
+ }
+
+ void WaitForOverscrollCompletedCallback() {
+ // Doesn't make sense to call more that once without resetting.
+ CHECK(!waiting_for_overscroll_completed_callback_);
+ waiting_for_overscroll_completed_callback_ = true;
+ if (overscroll_completed_callback_arrived_)
+ return;
+ overscroll_completed_wait_run_loop_.reset(new base::RunLoop());
+ overscroll_completed_wait_run_loop_->Run();
+ }
+
+ void OnSelectionOrCursorChanged(const ui::SelectionBound& anchor,
+ const ui::SelectionBound& 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 {
+ void GestureEventAck(int gesture_event_type) override {
last_gesture_ack_type_ =
static_cast<WebInputEvent::Type>(gesture_event_type);
TouchEditableImplAura::GestureEventAck(gesture_event_type);
@@ -65,47 +108,59 @@ class TestTouchEditableImplAura : public TouchEditableImplAura {
gesture_ack_wait_run_loop_->Quit();
}
- virtual void DidStopFlinging() override {
+ 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() {
+ void WaitForSelectionChangeCallback() {
+ // Doesn't make sense to call more that once without resetting.
+ CHECK(!waiting_for_selection_changed_callback_);
+ waiting_for_selection_changed_callback_ = true;
if (selection_changed_callback_arrived_)
return;
- waiting_for_selection_changed_callback_ = true;
selection_changed_wait_run_loop_.reset(new base::RunLoop());
selection_changed_wait_run_loop_->Run();
}
- virtual void WaitForGestureAck(WebInputEvent::Type gesture_event_type) {
+ void WaitForGestureAck(WebInputEvent::Type gesture_event_type) {
+ // Doesn't make sense to call more that once without resetting.
+ CHECK_EQ(waiting_for_gesture_ack_type_, WebInputEvent::Undefined);
+ waiting_for_gesture_ack_type_ = gesture_event_type;
if (last_gesture_ack_type_ == gesture_event_type)
return;
- waiting_for_gesture_ack_type_ = gesture_event_type;
gesture_ack_wait_run_loop_.reset(new base::RunLoop());
gesture_ack_wait_run_loop_->Run();
}
- virtual void WaitForFlingStopCallback() {
+ void WaitForFlingStopCallback() {
+ // Doesn't make sense to call more that once without resetting.
+ CHECK(!waiting_for_fling_stop_callback_);
+ waiting_for_fling_stop_callback_ = true;
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() {}
+ ~TestTouchEditableImplAura() override {}
private:
+ bool overscroll_started_callback_arrived_;
+ bool waiting_for_overscroll_started_callback_;
+ bool overscroll_completed_callback_arrived_;
+ bool waiting_for_overscroll_completed_callback_;
bool selection_changed_callback_arrived_;
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> overscroll_started_wait_run_loop_;
+ scoped_ptr<base::RunLoop> overscroll_completed_wait_run_loop_;
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_;
@@ -118,7 +173,13 @@ class TouchEditableImplAuraTest : public ContentBrowserTest {
TouchEditableImplAuraTest() {}
protected:
- virtual void SetUpCommandLine(CommandLine* command_line) override {
+ void SetUpOnMainThread() override {
+ ContentBrowserTest::SetUpOnMainThread();
+ aura::client::SetScreenPositionClient(shell()->window()->GetRootWindow(),
+ &screen_position_client_);
+ }
+
+ void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitch(switches::kEnableTouchEditing);
}
@@ -145,7 +206,7 @@ class TouchEditableImplAuraTest : public ContentBrowserTest {
return touch_editable->rwhva_;
}
- ui::TouchSelectionController* GetTouchSelectionController(
+ ui::TouchEditingControllerDeprecated* GetTouchSelectionController(
TouchEditableImplAura* touch_editable) {
return touch_editable->touch_selection_controller_.get();
}
@@ -155,6 +216,8 @@ class TouchEditableImplAuraTest : public ContentBrowserTest {
}
private:
+ wm::DefaultScreenPositionClient screen_position_client_;
+
DISALLOW_COPY_AND_ASSIGN(TouchEditableImplAuraTest);
};
@@ -193,9 +256,17 @@ IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest,
// Lets move the handles a bit to modify the selection
touch_editable->Reset();
+ ui::SelectionBound anchor, focus;
+ touch_editable->GetSelectionEndPoints(&anchor, &focus);
+ // The distance by which a handle image is offset from the bottom of the
+ // selection/text baseline.
+ const int kSelectionHandleVerticalVisualOffset = 2;
+ int handle_grab_x = bounds.x() + anchor.edge_bottom_rounded().x();
+ int handle_grab_y = bounds.y() + anchor.edge_bottom_rounded().y() +
+ kSelectionHandleVerticalVisualOffset + 1;
generator.GestureScrollSequence(
- gfx::Point(10, 47),
- gfx::Point(30, 47),
+ gfx::Point(handle_grab_x, handle_grab_y),
+ gfx::Point(handle_grab_x + 20, handle_grab_y),
base::TimeDelta::FromMilliseconds(20),
5);
touch_editable->WaitForSelectionChangeCallback();
@@ -321,6 +392,122 @@ IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest,
}
IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest,
+ TestTouchSelectionWhenOverscrolling) {
+ 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());
+
+ 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));
+
+ // Then overscroll starts. OverscrollStarted callback should be called and
+ // handles should remain hidden.
+ ui::GestureEvent scroll_update(
+ 210,
+ 10,
+ 0,
+ ui::EventTimeForNow(),
+ ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 200, 0));
+ rwhva->OnGestureEvent(&scroll_update);
+ touch_editable->WaitForOverscrollStartedCallback();
+ EXPECT_FALSE(GetTouchSelectionController(touch_editable));
+
+ // We might have multiple overscroll-starts in one overscroll session. Handles
+ // should still remain hidden.
+ touch_editable->OverscrollStarted();
+ EXPECT_FALSE(GetTouchSelectionController(touch_editable));
+
+ // And, finally a scroll-end. An OverscrollCompleted callback should be
+ // called and handles should come back.
+ ui::GestureEvent scroll_end(
+ 10,
+ 210,
+ 0,
+ ui::EventTimeForNow(),
+ ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END));
+ rwhva->OnGestureEvent(&scroll_end);
+ touch_editable->WaitForOverscrollCompletedCallback();
+ EXPECT_TRUE(GetTouchSelectionController(touch_editable));
+
+ // Now repeat the same sequence, but abort the overscroll by scrolling back
+ // before ending the scroll.
+ touch_editable->Reset();
+ scroll_begin = ui::GestureEvent(
+ 10,
+ 10,
+ 0,
+ ui::EventTimeForNow(),
+ ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN, 0, 0));
+ rwhva->OnGestureEvent(&scroll_begin);
+
+ scroll_update = ui::GestureEvent(
+ 210,
+ 10,
+ 0,
+ ui::EventTimeForNow(),
+ ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 200, 0));
+ rwhva->OnGestureEvent(&scroll_update);
+ touch_editable->WaitForOverscrollStartedCallback();
+
+ // Scroll back.
+ ui::GestureEvent scroll_update2(
+ 10,
+ 10,
+ 0,
+ ui::EventTimeForNow(),
+ ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, -200, 0));
+ rwhva->OnGestureEvent(&scroll_update2);
+ // Handles should remain hidden.
+ EXPECT_FALSE(GetTouchSelectionController(touch_editable));
+
+ // End the scroll - the overscroll should be cancelled, and we should still
+ // receive OverscrollCompleted callback
+ scroll_end = ui::GestureEvent(
+ 10,
+ 10,
+ 0,
+ ui::EventTimeForNow(),
+ ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END));
+ rwhva->OnGestureEvent(&scroll_end);
+ touch_editable->WaitForOverscrollCompletedCallback();
+ EXPECT_TRUE(GetTouchSelectionController(touch_editable));
+}
+
+IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest,
TouchSelectionOnLongPressTest) {
ASSERT_NO_FATAL_FAILURE(StartTestWithPage("files/touch_selection.html"));
WebContentsImpl* web_contents =
diff --git a/chromium/content/browser/web_contents/web_contents_android.cc b/chromium/content/browser/web_contents/web_contents_android.cc
index 85490c178b8..0c1b279502e 100644
--- a/chromium/content/browser/web_contents/web_contents_android.cc
+++ b/chromium/content/browser/web_contents/web_contents_android.cc
@@ -5,16 +5,20 @@
#include "content/browser/web_contents/web_contents_android.h"
#include "base/android/jni_android.h"
+#include "base/android/jni_array.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/accessibility/browser_accessibility_android.h"
+#include "content/browser/accessibility/browser_accessibility_manager.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/devtools_messages.h"
#include "content/common/frame_messages.h"
#include "content/common/input_messages.h"
#include "content/common/view_messages.h"
@@ -23,12 +27,18 @@
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_switches.h"
#include "jni/WebContentsImpl_jni.h"
+#include "net/android/network_library.h"
+#include "ui/accessibility/ax_node_data.h"
using base::android::AttachCurrentThread;
using base::android::ConvertJavaStringToUTF8;
using base::android::ConvertJavaStringToUTF16;
using base::android::ConvertUTF8ToJavaString;
+using base::android::ConvertUTF16ToJavaString;
using base::android::ScopedJavaGlobalRef;
+using base::android::ToJavaIntArray;
+
+namespace content {
namespace {
@@ -38,18 +48,81 @@ void JavaScriptResultCallback(const ScopedJavaGlobalRef<jobject>& callback,
std::string json;
base::JSONWriter::Write(result, &json);
ScopedJavaLocalRef<jstring> j_json = ConvertUTF8ToJavaString(env, json);
- content::Java_WebContentsImpl_onEvaluateJavaScriptResult(
+ Java_WebContentsImpl_onEvaluateJavaScriptResult(
env, j_json.obj(), callback.obj());
}
-} // namespace
+ScopedJavaLocalRef<jobject> WalkAXTreeDepthFirst(JNIEnv* env,
+ BrowserAccessibilityAndroid* node) {
+
+ ScopedJavaLocalRef<jstring> j_text =
+ ConvertUTF16ToJavaString(env, node->GetText());
+ ScopedJavaLocalRef<jstring> j_class =
+ ConvertUTF8ToJavaString(env, node->GetClassName());
+ const gfx::Rect& location = node->GetLocation();
+ // The style attributes exists and valid if size attribute exists. Otherwise,
+ // they are not. Use a negative size information to indicate the existence
+ // of style information.
+ float size = -1.0;
+ int color = 0;
+ int bgcolor = 0;
+ int text_style = 0;
+ if (node->HasFloatAttribute(ui::AX_ATTR_FONT_SIZE)) {
+ color = node->GetIntAttribute(ui::AX_ATTR_COLOR);
+ bgcolor = node->GetIntAttribute(ui::AX_ATTR_BACKGROUND_COLOR);
+ size = node->GetFloatAttribute(ui::AX_ATTR_FONT_SIZE);
+ text_style = node->GetIntAttribute(ui::AX_ATTR_TEXT_STYLE);
+ }
-namespace content {
+ ScopedJavaLocalRef<jobject> j_node =
+ Java_WebContentsImpl_createAccessibilitySnapshotNode(env,
+ location.x(), location.y(), node->GetScrollX(),
+ node->GetScrollY(), location.width(), location.height(),
+ j_text.obj(), color, bgcolor, size, text_style, j_class.obj());
+
+ for(uint32 i = 0; i < node->PlatformChildCount(); i++) {
+ BrowserAccessibilityAndroid* child =
+ static_cast<BrowserAccessibilityAndroid*>(
+ node->PlatformGetChild(i));
+ Java_WebContentsImpl_addAccessibilityNodeAsChild(env,
+ j_node.obj(), WalkAXTreeDepthFirst(env, child).obj());
+ }
+ return j_node;
+}
+
+// Walks over the AXTreeUpdate and creates a light weight snapshot.
+void AXTreeSnapshotCallback(const ScopedJavaGlobalRef<jobject>& callback,
+ const ui::AXTreeUpdate& result) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ if (result.nodes.empty()) {
+ Java_WebContentsImpl_onAccessibilitySnapshot(env, nullptr, callback.obj());
+ return;
+ }
+ scoped_ptr<BrowserAccessibilityManager> manager(
+ BrowserAccessibilityManager::Create(result, nullptr));
+ BrowserAccessibilityAndroid* root =
+ static_cast<BrowserAccessibilityAndroid*>(manager->GetRoot());
+ ScopedJavaLocalRef<jobject> j_root = WalkAXTreeDepthFirst(env, root);
+ Java_WebContentsImpl_onAccessibilitySnapshot(
+ env, j_root.obj(), callback.obj());
+}
+
+void ReleaseAllMediaPlayers(WebContents* web_contents,
+ RenderFrameHost* render_frame_host) {
+ BrowserMediaPlayerManager* manager =
+ static_cast<WebContentsImpl*>(web_contents)->
+ media_web_contents_observer()->GetMediaPlayerManager(
+ render_frame_host);
+ if (manager)
+ manager->ReleaseAllMediaPlayers();
+}
+
+} // namespace
// static
WebContents* WebContents::FromJavaWebContents(
jobject jweb_contents_android) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!jweb_contents_android)
return NULL;
@@ -63,23 +136,46 @@ WebContents* WebContents::FromJavaWebContents(
}
// static
+static void DestroyWebContents(JNIEnv* env,
+ jclass clazz,
+ jlong jweb_contents_android_ptr) {
+ WebContentsAndroid* web_contents_android =
+ reinterpret_cast<WebContentsAndroid*>(jweb_contents_android_ptr);
+ if (!web_contents_android)
+ return;
+
+ WebContents* web_contents = web_contents_android->web_contents();
+ if (!web_contents)
+ return;
+
+ delete web_contents;
+}
+
+// static
bool WebContentsAndroid::Register(JNIEnv* env) {
return RegisterNativesImpl(env);
}
WebContentsAndroid::WebContentsAndroid(WebContents* web_contents)
: web_contents_(web_contents),
- navigation_controller_(&(web_contents->GetController())) {
+ navigation_controller_(&(web_contents->GetController())),
+ weak_factory_(this) {
JNIEnv* env = AttachCurrentThread();
obj_.Reset(env,
Java_WebContentsImpl_create(
env,
reinterpret_cast<intptr_t>(this),
navigation_controller_.GetJavaObject().obj()).obj());
+ RendererPreferences* prefs = web_contents_->GetMutableRendererPrefs();
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ prefs->network_contry_iso =
+ command_line->HasSwitch(switches::kNetworkCountryIso) ?
+ command_line->GetSwitchValueASCII(switches::kNetworkCountryIso)
+ : net::android::GetTelephonyNetworkCountryIso();
}
WebContentsAndroid::~WebContentsAndroid() {
- Java_WebContentsImpl_destroy(AttachCurrentThread(), obj_.obj());
+ Java_WebContentsImpl_clearNativePtr(AttachCurrentThread(), obj_.obj());
}
base::android::ScopedJavaLocalRef<jobject>
@@ -122,9 +218,10 @@ RenderWidgetHostViewAndroid*
RenderWidgetHostView* rwhv = NULL;
rwhv = web_contents_->GetRenderWidgetHostView();
if (web_contents_->ShowingInterstitialPage()) {
- rwhv = static_cast<InterstitialPageImpl*>(
- web_contents_->GetInterstitialPage())->
- GetRenderViewHost()->GetView();
+ rwhv = web_contents_->GetInterstitialPage()
+ ->GetMainFrame()
+ ->GetRenderViewHost()
+ ->GetView();
}
return static_cast<RenderWidgetHostViewAndroid*>(rwhv);
}
@@ -141,6 +238,14 @@ ScopedJavaLocalRef<jstring> WebContentsAndroid::GetURL(JNIEnv* env,
return ConvertUTF8ToJavaString(env, web_contents_->GetURL().spec());
}
+ScopedJavaLocalRef<jstring> WebContentsAndroid::GetLastCommittedURL(
+ JNIEnv* env,
+ jobject) const {
+ return ConvertUTF8ToJavaString(env,
+ web_contents_->GetLastCommittedURL().spec());
+}
+
+
jboolean WebContentsAndroid::IsIncognito(JNIEnv* env, jobject obj) {
return web_contents_->GetBrowserContext()->IsOffTheRecord();
}
@@ -150,10 +255,15 @@ void WebContentsAndroid::ResumeResponseDeferredAtStart(JNIEnv* env,
static_cast<WebContentsImpl*>(web_contents_)->ResumeResponseDeferredAtStart();
}
+void WebContentsAndroid::ResumeLoadingCreatedWebContents(JNIEnv* env,
+ jobject obj) {
+ web_contents_->ResumeLoadingCreatedWebContents();
+}
+
void WebContentsAndroid::SetHasPendingNavigationTransitionForTesting(
JNIEnv* env,
jobject obj) {
- CommandLine::ForCurrentProcess()->AppendSwitch(
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableExperimentalWebPlatformFeatures);
RenderFrameHost* frame =
static_cast<WebContentsImpl*>(web_contents_)->GetMainFrame();
@@ -177,17 +287,89 @@ void WebContentsAndroid::SetupTransitionView(JNIEnv* env,
void WebContentsAndroid::BeginExitTransition(JNIEnv* env,
jobject jobj,
- jstring css_selector) {
+ jstring css_selector,
+ jboolean exit_to_native_app) {
web_contents_->GetMainFrame()->Send(new FrameMsg_BeginExitTransition(
web_contents_->GetMainFrame()->GetRoutingID(),
- ConvertJavaStringToUTF8(env, css_selector)));
+ ConvertJavaStringToUTF8(env, css_selector),
+ exit_to_native_app));
+}
+
+void WebContentsAndroid::RevertExitTransition(JNIEnv* env,
+ jobject jobj) {
+ web_contents_->GetMainFrame()->Send(new FrameMsg_RevertExitTransition(
+ web_contents_->GetMainFrame()->GetRoutingID()));
+}
+
+void WebContentsAndroid::HideTransitionElements(JNIEnv* env,
+ jobject jobj,
+ jstring css_selector) {
+ web_contents_->GetMainFrame()->Send(
+ new FrameMsg_HideTransitionElements(
+ web_contents_->GetMainFrame()->GetRoutingID(),
+ ConvertJavaStringToUTF8(env, css_selector)));
}
+void WebContentsAndroid::ShowTransitionElements(JNIEnv* env,
+ jobject jobj,
+ jstring css_selector) {
+ web_contents_->GetMainFrame()->Send(
+ new FrameMsg_ShowTransitionElements(
+ web_contents_->GetMainFrame()->GetRoutingID(),
+ ConvertJavaStringToUTF8(env, css_selector)));
+}
+
+
void WebContentsAndroid::ClearNavigationTransitionData(JNIEnv* env,
jobject jobj) {
static_cast<WebContentsImpl*>(web_contents_)->ClearNavigationTransitionData();
}
+void WebContentsAndroid::FetchTransitionElements(JNIEnv* env,
+ jobject jobj,
+ jstring jurl) {
+ GURL url(base::android::ConvertJavaStringToUTF8(env, jurl));
+ RenderFrameHost* frame = web_contents_->GetMainFrame();
+
+ scoped_ptr<TransitionLayerData> transition_data(new TransitionLayerData());
+ BrowserThread::PostTaskAndReplyWithResult(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&TransitionRequestManager::GetPendingTransitionRequest,
+ base::Unretained(TransitionRequestManager::GetInstance()),
+ frame->GetProcess()->GetID(),
+ frame->GetRoutingID(),
+ url,
+ transition_data.get()),
+ base::Bind(&WebContentsAndroid::OnTransitionElementsFetched,
+ weak_factory_.GetWeakPtr(),
+ base::Passed(&transition_data)));
+}
+
+void WebContentsAndroid::OnTransitionElementsFetched(
+ scoped_ptr<const TransitionLayerData> transition_data,
+ bool has_transition_data) {
+ // FetchTransitionElements is called after the navigation transition state
+ // machine starts, which means there must be transition data.
+ DCHECK(has_transition_data);
+ JNIEnv* env = AttachCurrentThread();
+
+ std::vector<TransitionElement>::const_iterator it =
+ transition_data->elements.begin();
+ for (; it != transition_data->elements.end(); ++it) {
+ ScopedJavaLocalRef<jstring> jstring_name(ConvertUTF8ToJavaString(env,
+ it->id));
+ Java_WebContentsImpl_addNavigationTransitionElements(
+ env, obj_.obj(), jstring_name.obj(),
+ it->rect.x(), it->rect.y(), it->rect.width(), it->rect.height());
+ }
+
+ ScopedJavaLocalRef<jstring> jstring_css_selector(
+ ConvertUTF8ToJavaString(env, transition_data->css_selector));
+ Java_WebContentsImpl_onTransitionElementsFetched(
+ env, obj_.obj(), jstring_css_selector.obj());
+}
+
void WebContentsAndroid::OnHide(JNIEnv* env, jobject obj) {
web_contents_->WasHidden();
}
@@ -198,16 +380,8 @@ void WebContentsAndroid::OnShow(JNIEnv* env, jobject obj) {
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();
+ web_contents_->ForEachFrame(
+ base::Bind(&ReleaseAllMediaPlayers, base::Unretained(web_contents_)));
#endif // defined(ENABLE_BROWSER_CDMS)
}
@@ -247,10 +421,7 @@ jboolean WebContentsAndroid::IsRenderWidgetHostViewReady(
}
void WebContentsAndroid::ExitFullscreen(JNIEnv* env, jobject obj) {
- RenderViewHost* host = web_contents_->GetRenderViewHost();
- if (!host)
- return;
- host->ExitFullscreen();
+ web_contents_->ExitFullscreen();
}
void WebContentsAndroid::UpdateTopControlsState(
@@ -370,30 +541,49 @@ void WebContentsAndroid::EvaluateJavaScript(JNIEnv* env,
// base::Callback.
ScopedJavaGlobalRef<jobject> j_callback;
j_callback.Reset(env, callback);
- content::RenderFrameHost::JavaScriptResultCallback js_callback =
+ 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) {
+void WebContentsAndroid::AddMessageToDevToolsConsole(JNIEnv* env,
+ jobject jobj,
+ jint level,
+ jstring message) {
+ DCHECK_GE(level, 0);
+ DCHECK_LE(level, CONSOLE_MESSAGE_LEVEL_LAST);
- 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));
+ web_contents_->GetMainFrame()->Send(new DevToolsAgentMsg_AddMessageToConsole(
+ web_contents_->GetMainFrame()->GetRoutingID(),
+ static_cast<ConsoleMessageLevel>(level),
+ ConvertJavaStringToUTF8(env, message)));
+}
+
+jboolean WebContentsAndroid::HasAccessedInitialDocument(
+ JNIEnv* env,
+ jobject jobj) {
+ return static_cast<WebContentsImpl*>(web_contents_)->
+ HasAccessedInitialDocument();
+}
+
+jint WebContentsAndroid::GetThemeColor(JNIEnv* env, jobject obj) {
+ return web_contents_->GetThemeColor();
+}
+
+void WebContentsAndroid::RequestAccessibilitySnapshot(JNIEnv* env,
+ jobject obj,
+ jobject callback) {
+ // Secure the Java callback in a scoped object and give ownership of it to the
+ // base::Callback.
+ ScopedJavaGlobalRef<jobject> j_callback;
+ j_callback.Reset(env, callback);
+ WebContentsImpl::AXTreeSnapshotCallback snapshot_callback =
+ base::Bind(&AXTreeSnapshotCallback, j_callback);
+
+ static_cast<WebContentsImpl*>(web_contents_)->RequestAXTreeSnapshot(
+ snapshot_callback);
}
} // 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 4b79231c005..12c36c1f775 100644
--- a/chromium/content/browser/web_contents/web_contents_android.h
+++ b/chromium/content/browser/web_contents/web_contents_android.h
@@ -10,6 +10,8 @@
#include "base/android/scoped_java_ref.h"
#include "base/basictypes.h"
#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.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"
@@ -30,7 +32,7 @@ class CONTENT_EXPORT WebContentsAndroid
static bool Register(JNIEnv* env);
explicit WebContentsAndroid(WebContents* web_contents);
- virtual ~WebContentsAndroid();
+ ~WebContentsAndroid() override;
WebContents* web_contents() const { return web_contents_; }
@@ -48,13 +50,24 @@ class CONTENT_EXPORT WebContentsAndroid
void Stop(JNIEnv* env, jobject obj);
jint GetBackgroundColor(JNIEnv* env, jobject obj);
base::android::ScopedJavaLocalRef<jstring> GetURL(JNIEnv* env, jobject) const;
+ base::android::ScopedJavaLocalRef<jstring> GetLastCommittedURL(JNIEnv* env,
+ jobject) const;
jboolean IsIncognito(JNIEnv* env, jobject obj);
void ResumeResponseDeferredAtStart(JNIEnv* env, jobject obj);
+ void ResumeLoadingCreatedWebContents(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 BeginExitTransition(JNIEnv* env, jobject jobj, jstring css_selector,
+ jboolean exit_to_native_app);
+ void RevertExitTransition(JNIEnv* env, jobject jobj);
+ void HideTransitionElements(JNIEnv* env, jobject jobj, jstring css_selector);
+ void ShowTransitionElements(JNIEnv* env, jobject jobj, jstring css_selector);
void ClearNavigationTransitionData(JNIEnv* env, jobject jobj);
+ void FetchTransitionElements(JNIEnv* env, jobject jobj, jstring jurl);
+ void OnTransitionElementsFetched(
+ scoped_ptr<const TransitionLayerData> transition_data,
+ bool has_transition_data);
// This method is invoked when the request is deferred immediately after
// receiving response headers.
@@ -93,8 +106,19 @@ class CONTENT_EXPORT WebContentsAndroid
jobject obj,
jstring script,
jobject callback);
- void PostMessageToFrame(JNIEnv* env, jobject obj, jstring frame_id,
- jstring message, jstring source_origin, jstring target_origin);
+
+ void AddMessageToDevToolsConsole(JNIEnv* env,
+ jobject jobj,
+ jint level,
+ jstring message);
+
+ jboolean HasAccessedInitialDocument(JNIEnv* env, jobject jobj);
+
+ jint GetThemeColor(JNIEnv* env, jobject obj);
+
+ void RequestAccessibilitySnapshot(JNIEnv* env,
+ jobject obj,
+ jobject callback);
private:
RenderWidgetHostViewAndroid* GetRenderWidgetHostViewAndroid();
@@ -102,6 +126,8 @@ class CONTENT_EXPORT WebContentsAndroid
NavigationControllerAndroid navigation_controller_;
base::android::ScopedJavaGlobalRef<jobject> obj_;
+ base::WeakPtrFactory<WebContentsAndroid> weak_factory_;
+
DISALLOW_COPY_AND_ASSIGN(WebContentsAndroid);
};
diff --git a/chromium/content/browser/web_contents/web_contents_impl.cc b/chromium/content/browser/web_contents/web_contents_impl.cc
index d3e8b13b9d3..c8a5ec59dc1 100644
--- a/chromium/content/browser/web_contents/web_contents_impl.cc
+++ b/chromium/content/browser/web_contents/web_contents_impl.cc
@@ -7,23 +7,24 @@
#include <utility>
#include "base/command_line.h"
-#include "base/debug/trace_event.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
-#include "base/metrics/stats_counters.h"
#include "base/process/process.h"
+#include "base/profiler/scoped_tracker.h"
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
+#include "components/mime_util/mime_util.h"
#include "content/browser/accessibility/accessibility_mode_helper.h"
#include "content/browser/accessibility/browser_accessibility_state_impl.h"
+#include "content/browser/bad_message.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/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"
@@ -35,16 +36,13 @@
#include "content/browser/frame_host/navigator_impl.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/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"
@@ -94,7 +92,6 @@
#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"
#include "net/http/http_transaction_factory.h"
@@ -105,8 +102,14 @@
#include "ui/gfx/screen.h"
#include "ui/gl/gl_switches.h"
+#if defined(ENABLE_BROWSER_CDMS)
+#include "content/browser/media/media_web_contents_observer.h"
+#endif
+
#if defined(OS_ANDROID)
+#include "content/browser/android/content_video_view.h"
#include "content/browser/android/date_time_chooser_android.h"
+#include "content/browser/android/media_players_observer.h"
#include "content/browser/media/android/browser_media_player_manager.h"
#include "content/browser/web_contents/web_contents_android.h"
#endif
@@ -119,11 +122,6 @@ namespace content {
namespace {
const int kMinimumDelayBetweenLoadingUpdatesMS = 100;
-
-// This matches what Blink's ProgressTracker has traditionally used for a
-// minimum progress value.
-const double kMinimumLoadingProgress = 0.1;
-
const char kDotGoogleDotCom[] = ".google.com";
#if defined(OS_ANDROID)
@@ -136,13 +134,15 @@ g_created_callbacks = LAZY_INSTANCE_INITIALIZER;
static int StartDownload(RenderFrameHost* rfh,
const GURL& url,
bool is_favicon,
- uint32_t max_bitmap_size) {
+ uint32_t max_bitmap_size,
+ bool bypass_cache) {
static int g_next_image_download_id = 0;
rfh->Send(new ImageMsg_DownloadImage(rfh->GetRoutingID(),
++g_next_image_download_id,
url,
is_favicon,
- max_bitmap_size));
+ max_bitmap_size,
+ bypass_cache));
return g_next_image_download_id;
}
@@ -150,8 +150,10 @@ void NotifyCacheOnIO(
scoped_refptr<net::URLRequestContextGetter> request_context,
const GURL& url,
const std::string& http_method) {
- request_context->GetURLRequestContext()->http_transaction_factory()->
- GetCache()->OnExternalCacheHit(url, http_method);
+ net::HttpCache* cache = request_context->GetURLRequestContext()->
+ http_transaction_factory()->GetCache();
+ if (cache)
+ cache->OnExternalCacheHit(url, http_method);
}
// Helper function for retrieving all the sites in a frame tree.
@@ -224,11 +226,13 @@ WebContents* WebContents::CreateWithSessionStorage(
return new_contents;
}
-void WebContentsImpl::AddCreatedCallback(const CreatedCallback& callback) {
+void WebContentsImpl::FriendZone::AddCreatedCallbackForTesting(
+ const CreatedCallback& callback) {
g_created_callbacks.Get().push_back(callback);
}
-void WebContentsImpl::RemoveCreatedCallback(const CreatedCallback& callback) {
+void WebContentsImpl::FriendZone::RemoveCreatedCallbackForTesting(
+ const CreatedCallback& callback) {
for (size_t i = 0; i < g_created_callbacks.Get().size(); ++i) {
if (g_created_callbacks.Get().at(i).Equals(callback)) {
g_created_callbacks.Get().erase(g_created_callbacks.Get().begin() + i);
@@ -305,12 +309,12 @@ WebContentsImpl::WebContentsImpl(BrowserContext* browser_context,
crashed_error_code_(0),
waiting_for_response_(false),
load_state_(net::LOAD_STATE_IDLE, base::string16()),
- loading_total_progress_(0.0),
- loading_frames_in_progress_(0),
upload_size_(0),
upload_position_(0),
displayed_insecure_content_(false),
has_accessed_initial_document_(false),
+ theme_color_(SK_ColorTRANSPARENT),
+ last_sent_theme_color_(SK_ColorTRANSPARENT),
capturer_count_(0),
should_normally_be_visible_(true),
is_being_destroyed_(false),
@@ -321,9 +325,8 @@ WebContentsImpl::WebContentsImpl(BrowserContext* browser_context,
closed_by_user_gesture_(false),
minimum_zoom_percent_(static_cast<int>(kMinimumZoomFactor * 100)),
maximum_zoom_percent_(static_cast<int>(kMaximumZoomFactor * 100)),
- totalPinchGestureAmount_(0),
- currentPinchZoomStepDelta_(0),
render_view_message_source_(NULL),
+ render_frame_message_source_(NULL),
fullscreen_widget_routing_id_(MSG_ROUTING_NONE),
fullscreen_widget_had_focus_at_shutdown_(false),
is_subframe_(false),
@@ -332,13 +335,20 @@ WebContentsImpl::WebContentsImpl(BrowserContext* browser_context,
geolocation_service_context_(new GeolocationServiceContext()),
accessibility_mode_(
BrowserAccessibilityStateImpl::GetInstance()->accessibility_mode()),
- audio_stream_monitor_(this),
+ virtual_keyboard_requested_(false),
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(
base::Bind(&WebContentsImpl::OnFrameRemoved,
base::Unretained(this)));
+#if defined(ENABLE_BROWSER_CDMS)
+ media_web_contents_observer_.reset(new MediaWebContentsObserver(this));
+#endif
+
+#if defined(OS_ANDROID)
+ audio_state_provider_.reset(new MediaPlayersObserver(this));
+#else
+ audio_state_provider_.reset(new AudioStreamMonitor(this));
+#endif
}
WebContentsImpl::~WebContentsImpl() {
@@ -359,7 +369,7 @@ WebContentsImpl::~WebContentsImpl() {
// Clear out any JavaScript state.
if (dialog_manager_)
- dialog_manager_->WebContentsDestroyed(this);
+ dialog_manager_->ResetDialogState(this);
if (color_chooser_info_.get())
color_chooser_info_->chooser->End();
@@ -373,19 +383,18 @@ WebContentsImpl::~WebContentsImpl() {
NotificationService::NoDetails());
// Destroy all frame tree nodes except for the root; this notifies observers.
- frame_tree_.ResetForMainFrameSwap();
+ frame_tree_.root()->ResetForNewProcess();
GetRenderManager()->ResetProxyHosts();
// Manually call the observer methods for the root frame tree node.
RenderFrameHostManager* root = GetRenderManager();
- if (root->pending_frame_host()) {
- FOR_EACH_OBSERVER(WebContentsObserver,
- observers_,
- RenderFrameDeleted(root->pending_frame_host()));
- }
- FOR_EACH_OBSERVER(WebContentsObserver,
- observers_,
- RenderFrameDeleted(root->current_frame_host()));
+
+ if (root->pending_frame_host())
+ root->pending_frame_host()->SetRenderFrameCreated(false);
+ root->current_frame_host()->SetRenderFrameCreated(false);
+
+ FOR_EACH_OBSERVER(WebContentsObserver, observers_,
+ FrameDeleted(root->current_frame_host()));
if (root->pending_render_view_host()) {
FOR_EACH_OBSERVER(WebContentsObserver,
@@ -472,7 +481,7 @@ bool WebContentsImpl::OnMessageReceived(RenderViewHost* render_view_host,
return true;
}
- ObserverListBase<WebContentsObserver>::Iterator it(observers_);
+ ObserverListBase<WebContentsObserver>::Iterator it(&observers_);
WebContentsObserver* observer;
if (render_frame_host) {
while ((observer = it.GetNext()) != NULL)
@@ -501,10 +510,6 @@ bool WebContentsImpl::OnMessageReceived(RenderViewHost* render_view_host,
IPC_MESSAGE_HANDLER(FrameHostMsg_DidFinishDocumentLoad,
OnDocumentLoadedInFrame)
IPC_MESSAGE_HANDLER(FrameHostMsg_DidFinishLoad, OnDidFinishLoad)
- IPC_MESSAGE_HANDLER(FrameHostMsg_DidStartLoading, OnDidStartLoading)
- IPC_MESSAGE_HANDLER(FrameHostMsg_DidStopLoading, OnDidStopLoading)
- IPC_MESSAGE_HANDLER(FrameHostMsg_DidChangeLoadProgress,
- OnDidChangeLoadProgress)
IPC_MESSAGE_HANDLER(FrameHostMsg_OpenColorChooser, OnOpenColorChooser)
IPC_MESSAGE_HANDLER(FrameHostMsg_EndColorChooser, OnEndColorChooser)
IPC_MESSAGE_HANDLER(FrameHostMsg_SetSelectedColorInColorChooser,
@@ -537,7 +542,8 @@ bool WebContentsImpl::OnMessageReceived(RenderViewHost* render_view_host,
IPC_MESSAGE_HANDLER(ViewHostMsg_RequestPpapiBrokerPermission,
OnRequestPpapiBrokerPermission)
IPC_MESSAGE_HANDLER_GENERIC(BrowserPluginHostMsg_Attach,
- OnBrowserPluginMessage(message))
+ OnBrowserPluginMessage(render_frame_host,
+ message))
#endif
IPC_MESSAGE_HANDLER(ImageHostMsg_DidDownloadImage, OnDidDownloadImage)
IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateFaviconURL, OnUpdateFaviconURL)
@@ -561,6 +567,17 @@ bool WebContentsImpl::OnMessageReceived(RenderViewHost* render_view_host,
return handled;
}
+bool WebContentsImpl::HasValidFrameSource() {
+ if (!render_frame_message_source_) {
+ DCHECK(render_view_message_source_);
+ bad_message::ReceivedBadMessage(GetRenderProcessHost(),
+ bad_message::WC_INVALID_FRAME_SOURCE);
+ return false;
+ }
+
+ return true;
+}
+
void WebContentsImpl::RunFileChooser(
RenderViewHost* render_view_host,
const FileChooserParams& params) {
@@ -622,14 +639,15 @@ RenderProcessHost* WebContentsImpl::GetRenderProcessHost() const {
return host ? host->GetProcess() : NULL;
}
-RenderFrameHost* WebContentsImpl::GetMainFrame() {
+RenderFrameHostImpl* WebContentsImpl::GetMainFrame() {
return frame_tree_.root()->current_frame_host();
}
-RenderFrameHost* WebContentsImpl::GetFocusedFrame() {
- if (!frame_tree_.GetFocusedFrame())
- return NULL;
- return frame_tree_.GetFocusedFrame()->current_frame_host();
+RenderFrameHostImpl* WebContentsImpl::GetFocusedFrame() {
+ FrameTreeNode* focused_node = frame_tree_.GetFocusedFrame();
+ if (!focused_node)
+ return nullptr;
+ return focused_node->current_frame_host();
}
void WebContentsImpl::ForEachFrame(
@@ -642,7 +660,7 @@ void WebContentsImpl::SendToAllFrames(IPC::Message* message) {
delete message;
}
-RenderViewHost* WebContentsImpl::GetRenderViewHost() const {
+RenderViewHostImpl* WebContentsImpl::GetRenderViewHost() const {
return GetRenderManager()->current_host();
}
@@ -653,10 +671,21 @@ int WebContentsImpl::GetRoutingID() const {
return GetRenderViewHost()->GetRoutingID();
}
+void WebContentsImpl::CancelActiveAndPendingDialogs() {
+ if (dialog_manager_)
+ dialog_manager_->CancelActiveAndPendingDialogs(this);
+ if (browser_plugin_embedder_)
+ browser_plugin_embedder_->CancelGuestDialogs();
+}
+
int WebContentsImpl::GetFullscreenWidgetRoutingID() const {
return fullscreen_widget_routing_id_;
}
+void WebContentsImpl::ClosePage() {
+ GetRenderViewHost()->ClosePage();
+}
+
RenderWidgetHostView* WebContentsImpl::GetRenderWidgetHostView() const {
return GetRenderManager()->GetRenderWidgetHostView();
}
@@ -673,6 +702,10 @@ WebContentsView* WebContentsImpl::GetView() const {
return view_.get();
}
+SkColor WebContentsImpl::GetThemeColor() const {
+ return theme_color_;
+}
+
void WebContentsImpl::SetAccessibilityMode(AccessibilityMode mode) {
if (mode == accessibility_mode_)
return;
@@ -694,6 +727,13 @@ void WebContentsImpl::RemoveAccessibilityMode(AccessibilityMode mode) {
SetAccessibilityMode(RemoveAccessibilityModeFrom(accessibility_mode_, mode));
}
+void WebContentsImpl::RequestAXTreeSnapshot(AXTreeSnapshotCallback callback) {
+ // TODO(dmazzoni): http://crbug.com/475608 This only returns the
+ // accessibility tree from the main frame and everything in the
+ // same site instance.
+ GetMainFrame()->RequestAXTreeSnapshot(callback);
+}
+
void WebContentsImpl::ClearNavigationTransitionData() {
FrameTreeNode* node = frame_tree_.root();
node->render_manager()->ClearNavigationTransitionData();
@@ -763,7 +803,7 @@ bool WebContentsImpl::IsFullAccessibilityModeForTesting() const {
void WebContentsImpl::SetParentNativeViewAccessible(
gfx::NativeViewAccessible accessible_parent) {
accessible_parent_ = accessible_parent;
- RenderFrameHostImpl* rfh = static_cast<RenderFrameHostImpl*>(GetMainFrame());
+ RenderFrameHostImpl* rfh = GetMainFrame();
if (rfh)
rfh->SetParentNativeViewAccessible(accessible_parent);
}
@@ -919,6 +959,9 @@ void WebContentsImpl::IncrementCapturerCount(const gfx::Size& capture_size) {
preferred_size_for_capture_ = capture_size;
OnPreferredSizeChanged(preferred_size_);
}
+
+ // Ensure that all views are un-occluded before capture begins.
+ WasUnOccluded();
}
void WebContentsImpl::DecrementCapturerCount() {
@@ -996,10 +1039,15 @@ bool WebContentsImpl::IsBeingDestroyed() const {
void WebContentsImpl::NotifyNavigationStateChanged(
InvalidateTypes changed_flags) {
+ // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466285
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "466285 WebContentsImpl::NotifyNavigationStateChanged"));
// 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 ((changed_flags & INVALIDATE_TYPE_TAB) &&
+ audio_state_provider_->IsAudioStateAvailable()) {
if (WasRecentlyAudible()) {
if (!audio_power_save_blocker_)
CreateAudioPowerSaveBlocker();
@@ -1016,17 +1064,18 @@ base::TimeTicks WebContentsImpl::GetLastActiveTime() const {
return last_active_time_;
}
+void WebContentsImpl::SetLastActiveTime(base::TimeTicks last_active_time) {
+ last_active_time_ = last_active_time;
+}
+
void WebContentsImpl::WasShown() {
controller_.SetActive(true);
- std::set<RenderWidgetHostView*> widgets = GetRenderWidgetHostViewsInTree();
- for (std::set<RenderWidgetHostView*>::iterator iter = widgets.begin();
- iter != widgets.end();
- iter++) {
- if (*iter) {
- (*iter)->Show();
+ for (RenderWidgetHostView* view : GetRenderWidgetHostViewsInTree()) {
+ if (view) {
+ view->Show();
#if defined(OS_MACOSX)
- (*iter)->SetActive(true);
+ view->SetActive(true);
#endif
}
}
@@ -1035,11 +1084,9 @@ void WebContentsImpl::WasShown() {
// The resize rect might have changed while this was inactive -- send the new
// one to make sure it's up to date.
- RenderViewHostImpl* rvh =
- static_cast<RenderViewHostImpl*>(GetRenderViewHost());
- if (rvh) {
+ RenderViewHostImpl* rvh = GetRenderViewHost();
+ if (rvh)
rvh->ResizeRectChanged(GetRootWindowResizerRect());
- }
// Restore power save blocker if there are active video players running.
if (!active_video_players_.empty() && !video_power_save_blocker_)
@@ -1060,12 +1107,9 @@ void WebContentsImpl::WasHidden() {
// removes the |GetRenderViewHost()|; then when we actually destroy the
// window, OnWindowPosChanged() notices and calls WasHidden() (which
// calls us).
- std::set<RenderWidgetHostView*> widgets = GetRenderWidgetHostViewsInTree();
- for (std::set<RenderWidgetHostView*>::iterator iter = widgets.begin();
- iter != widgets.end();
- iter++) {
- if (*iter)
- (*iter)->Hide();
+ for (RenderWidgetHostView* view : GetRenderWidgetHostViewsInTree()) {
+ if (view)
+ view->Hide();
}
// Release any video power save blockers held as video is not visible.
@@ -1077,17 +1121,31 @@ void WebContentsImpl::WasHidden() {
should_normally_be_visible_ = false;
}
+void WebContentsImpl::WasOccluded() {
+ if (capturer_count_ > 0)
+ return;
+
+ for (RenderWidgetHostView* view : GetRenderWidgetHostViewsInTree()) {
+ if (view)
+ view->WasOccluded();
+ }
+}
+
+void WebContentsImpl::WasUnOccluded() {
+ for (RenderWidgetHostView* view : GetRenderWidgetHostViewsInTree()) {
+ if (view)
+ view->WasUnOccluded();
+ }
+}
+
bool WebContentsImpl::NeedToFireBeforeUnload() {
// TODO(creis): Should we fire even for interstitial pages?
- return WillNotifyDisconnection() &&
- !ShowingInterstitialPage() &&
- !static_cast<RenderViewHostImpl*>(
- GetRenderViewHost())->SuddenTerminationAllowed();
+ return WillNotifyDisconnection() && !ShowingInterstitialPage() &&
+ !GetRenderViewHost()->SuddenTerminationAllowed();
}
void WebContentsImpl::DispatchBeforeUnload(bool for_cross_site_transition) {
- static_cast<RenderFrameHostImpl*>(GetMainFrame())->DispatchBeforeUnload(
- for_cross_site_transition);
+ GetMainFrame()->DispatchBeforeUnload(for_cross_site_transition);
}
void WebContentsImpl::Stop() {
@@ -1149,9 +1207,15 @@ void WebContentsImpl::Init(const WebContents::CreateParams& params) {
// it should be hidden.
should_normally_be_visible_ = !params.initially_hidden;
+ // Either both routing ids can be given, or neither can be.
+ DCHECK((params.routing_id == MSG_ROUTING_NONE &&
+ params.main_frame_routing_id == MSG_ROUTING_NONE) ||
+ (params.routing_id != MSG_ROUTING_NONE &&
+ params.main_frame_routing_id != MSG_ROUTING_NONE));
GetRenderManager()->Init(
params.browser_context, params.site_instance, params.routing_id,
params.main_frame_routing_id);
+ frame_tree_.root()->SetFrameName(params.main_frame_name);
WebContentsViewDelegate* delegate =
GetContentClient()->browser()->GetWebContentsViewDelegate(this);
@@ -1189,9 +1253,6 @@ void WebContentsImpl::Init(const WebContents::CreateParams& params) {
NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED,
NotificationService::AllBrowserContextsAndSources());
- geolocation_dispatcher_host_.reset(new GeolocationDispatcherHost(this));
- midi_dispatcher_host_.reset(new MidiDispatcherHost(this));
-
screen_orientation_dispatcher_host_.reset(
new ScreenOrientationDispatcherHostImpl(this));
@@ -1200,6 +1261,29 @@ void WebContentsImpl::Init(const WebContents::CreateParams& params) {
#if defined(OS_ANDROID)
date_time_chooser_.reset(new DateTimeChooserAndroid());
#endif
+
+ // BrowserPluginGuest::Init needs to be called after this WebContents has
+ // a RenderWidgetHostViewGuest. That is, |view_->CreateView| above.
+ if (browser_plugin_guest_)
+ browser_plugin_guest_->Init();
+
+ for (size_t i = 0; i < g_created_callbacks.Get().size(); i++)
+ g_created_callbacks.Get().at(i).Run(this);
+
+ // If the WebContents creation was renderer-initiated, it means that the
+ // corresponding RenderView and main RenderFrame have already been created.
+ // Ensure observers are notified about this.
+ if (params.renderer_initiated_creation) {
+ RenderViewCreated(GetRenderViewHost());
+ GetRenderManager()->current_frame_host()->SetRenderFrameCreated(true);
+ }
+
+ // Ensure that observers are notified of the creation of this WebContents's
+ // main RenderFrameHost. It must be done here for main frames, since the
+ // NotifySwappedFromRenderManager expects view_ to already be created and that
+ // happens after RenderFrameHostManager::Init.
+ NotifySwappedFromRenderManager(
+ nullptr, GetRenderManager()->current_frame_host(), true);
}
void WebContentsImpl::OnWebContentsDestroyed(WebContentsImpl* web_contents) {
@@ -1288,7 +1372,7 @@ void WebContentsImpl::RenderWidgetDeleted(
if (render_widget_host &&
render_widget_host->GetRoutingID() == fullscreen_widget_routing_id_) {
if (delegate_ && delegate_->EmbedsFullscreenWidget())
- delegate_->ToggleFullscreenModeForTab(this, false);
+ delegate_->ExitFullscreenModeForTab(this);
FOR_EACH_OBSERVER(WebContentsObserver,
observers_,
DidDestroyFullscreenWidget(
@@ -1301,11 +1385,27 @@ void WebContentsImpl::RenderWidgetDeleted(
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);
+ // Notify the observers if an embedded fullscreen widget was focused.
+ if (delegate_ && render_widget_host && delegate_->EmbedsFullscreenWidget() &&
+ render_widget_host->GetView() == GetFullscreenRenderWidgetHostView()) {
+ NotifyWebContentsFocused();
+ }
+}
+
+void WebContentsImpl::RenderWidgetWasResized(
+ RenderWidgetHostImpl* render_widget_host,
+ bool width_changed) {
+ RenderFrameHostImpl* rfh = GetMainFrame();
+ if (!rfh || render_widget_host != rfh->GetRenderWidgetHost())
+ return;
+
+ FOR_EACH_OBSERVER(WebContentsObserver, observers_,
+ MainFrameWasResized(width_changed));
+}
+
+void WebContentsImpl::ScreenInfoChanged() {
+ if (browser_plugin_embedder_)
+ browser_plugin_embedder_->ScreenInfoChanged();
}
bool WebContentsImpl::PreHandleKeyboardEvent(
@@ -1327,18 +1427,15 @@ void WebContentsImpl::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {
bool WebContentsImpl::HandleWheelEvent(
const blink::WebMouseWheelEvent& event) {
#if !defined(OS_MACOSX)
- // On platforms other than Mac, control+mousewheel changes zoom. On Mac, this
- // isn't done for two reasons:
+ // On platforms other than Mac, control+mousewheel may change zoom. On Mac,
+ // this isn't done for two reasons:
// -the OS already has a gesture to do this through pinch-zoom
// -if a user starts an inertial scroll, let's go, and presses control
// (i.e. control+tab) then the OS's buffered scroll events will come in
// with control key set which isn't what the user wants
- if (delegate_ &&
- event.wheelTicksY &&
+ if (delegate_ && event.wheelTicksY &&
(event.modifiers & blink::WebInputEvent::ControlKey) &&
- // Avoid adjusting the zoom in response to two-finger-scrolling touchpad
- // gestures, which are regrettably easy to trigger accidentally.
- !event.hasPreciseScrollingDeltas) {
+ !event.canScroll) {
delegate_->ContentsZoomChange(event.wheelTicksY > 0);
return true;
}
@@ -1351,81 +1448,46 @@ bool WebContentsImpl::PreHandleGestureEvent(
return delegate_ && delegate_->PreHandleGestureEvent(this, event);
}
-bool WebContentsImpl::HandleGestureEvent(
- const blink::WebGestureEvent& event) {
- // Some platforms (eg. Mac) send GesturePinch events for trackpad pinch-zoom.
- // Use them to implement browser zoom, as for HandleWheelEvent above.
- if (event.type == blink::WebInputEvent::GesturePinchUpdate &&
- event.sourceDevice == blink::WebGestureDeviceTouchpad) {
- // The scale difference necessary to trigger a zoom action. Derived from
- // experimentation to find a value that feels reasonable.
- const float kZoomStepValue = 0.6f;
-
- // Find the (absolute) thresholds on either side of the current zoom factor,
- // then convert those to actual numbers to trigger a zoom in or out.
- // This logic deliberately makes the range around the starting zoom value
- // for the gesture twice as large as the other ranges (i.e., the notches are
- // at ..., -3*step, -2*step, -step, step, 2*step, 3*step, ... but not at 0)
- // so that it's easier to get back to your starting point than it is to
- // overshoot.
- float nextStep = (abs(currentPinchZoomStepDelta_) + 1) * kZoomStepValue;
- float backStep = abs(currentPinchZoomStepDelta_) * kZoomStepValue;
- float zoomInThreshold = (currentPinchZoomStepDelta_ >= 0) ? nextStep
- : -backStep;
- float zoomOutThreshold = (currentPinchZoomStepDelta_ <= 0) ? -nextStep
- : backStep;
-
- totalPinchGestureAmount_ += (event.data.pinchUpdate.scale - 1.0);
- if (totalPinchGestureAmount_ > zoomInThreshold) {
- currentPinchZoomStepDelta_++;
- if (delegate_)
- delegate_->ContentsZoomChange(true);
- } else if (totalPinchGestureAmount_ < zoomOutThreshold) {
- currentPinchZoomStepDelta_--;
- if (delegate_)
- delegate_->ContentsZoomChange(false);
- }
- return true;
- }
-
- return false;
-}
-
-void WebContentsImpl::HandleMouseDown() {
- if (delegate_)
- delegate_->HandleMouseDown();
-}
-
-void WebContentsImpl::HandleMouseUp() {
- if (delegate_)
- delegate_->HandleMouseUp();
-}
-
-void WebContentsImpl::HandlePointerActivate() {
- if (delegate_)
- delegate_->HandlePointerActivate();
-}
+void WebContentsImpl::EnterFullscreenMode(const GURL& origin) {
+ // This method is being called to enter renderer-initiated fullscreen mode.
+ // Make sure any existing fullscreen widget is shut down first.
+ RenderWidgetHostView* const widget_view = GetFullscreenRenderWidgetHostView();
+ if (widget_view)
+ RenderWidgetHostImpl::From(widget_view->GetRenderWidgetHost())->Shutdown();
-void WebContentsImpl::HandleGestureBegin() {
if (delegate_)
- delegate_->HandleGestureBegin();
-}
+ delegate_->EnterFullscreenModeForTab(this, origin);
-void WebContentsImpl::HandleGestureEnd() {
- if (delegate_)
- delegate_->HandleGestureEnd();
+ FOR_EACH_OBSERVER(WebContentsObserver, observers_,
+ DidToggleFullscreenModeForTab(IsFullscreenForCurrentTab()));
}
-void WebContentsImpl::ToggleFullscreenMode(bool enter_fullscreen) {
- // This method is being called to enter or leave renderer-initiated fullscreen
- // mode. Either way, make sure any existing fullscreen widget is shut down
- // first.
+void WebContentsImpl::ExitFullscreenMode() {
+ // This method is being called to leave renderer-initiated fullscreen mode.
+ // Make sure any existing fullscreen widget is shut down first.
RenderWidgetHostView* const widget_view = GetFullscreenRenderWidgetHostView();
if (widget_view)
RenderWidgetHostImpl::From(widget_view->GetRenderWidgetHost())->Shutdown();
+#if defined(OS_ANDROID)
+ ContentVideoView* video_view = ContentVideoView::GetInstance();
+ if (video_view != NULL)
+ video_view->OnExitFullscreen();
+#endif
+
if (delegate_)
- delegate_->ToggleFullscreenModeForTab(this, enter_fullscreen);
+ delegate_->ExitFullscreenModeForTab(this);
+
+ // Ensure web contents exit fullscreen state by sending a resize message,
+ // which includes the fullscreen state. This is required for the situation
+ // of the browser moving the view into a fullscreen state "browser fullscreen"
+ // and then the contents entering "tab fullscreen". Exiting the contents
+ // "tab fullscreen" then won't have the side effect of the view resizing,
+ // hence the explicit call here is required.
+ if (RenderWidgetHostView* rwh_view = GetRenderWidgetHostView()) {
+ if (RenderWidgetHost* render_widget_host = rwh_view->GetRenderWidgetHost())
+ render_widget_host->WasResized();
+ }
FOR_EACH_OBSERVER(WebContentsObserver,
observers_,
@@ -1436,6 +1498,11 @@ bool WebContentsImpl::IsFullscreenForCurrentTab() const {
return delegate_ ? delegate_->IsFullscreenForTabOrPending(this) : false;
}
+blink::WebDisplayMode WebContentsImpl::GetDisplayMode() const {
+ return delegate_ ? delegate_->GetDisplayMode(this)
+ : blink::WebDisplayModeBrowser;
+}
+
void WebContentsImpl::RequestToLockMouse(bool user_gesture,
bool last_unlocked_by_target) {
if (delegate_) {
@@ -1476,12 +1543,12 @@ void WebContentsImpl::CreateNewWindow(
// this WebContentsImpl instance. If any other process sends the request,
// it is invalid and the process must be terminated.
if (GetRenderProcessHost()->GetID() != render_process_id) {
- base::ProcessHandle process_handle =
- RenderProcessHost::FromID(render_process_id)->GetHandle();
+ RenderProcessHost* rph = RenderProcessHost::FromID(render_process_id);
+ base::ProcessHandle process_handle = rph->GetHandle();
if (process_handle != base::kNullProcessHandle) {
RecordAction(
base::UserMetricsAction("Terminate_ProcessMismatch_CreateNewWindow"));
- base::KillProcess(process_handle, RESULT_CODE_KILLED, false);
+ rph->Shutdown(RESULT_CODE_KILLED, false);
}
return;
}
@@ -1504,6 +1571,7 @@ void WebContentsImpl::CreateNewWindow(
if (delegate_ &&
!delegate_->ShouldCreateWebContents(this,
route_id,
+ main_frame_route_id,
params.window_container_type,
params.frame_name,
params.target_url,
@@ -1526,10 +1594,12 @@ void WebContentsImpl::CreateNewWindow(
CreateParams create_params(GetBrowserContext(), site_instance.get());
create_params.routing_id = route_id;
create_params.main_frame_routing_id = main_frame_route_id;
+ create_params.main_frame_name = base::UTF16ToUTF8(params.frame_name);
create_params.opener = this;
create_params.opener_suppressed = params.opener_suppressed;
if (params.disposition == NEW_BACKGROUND_TAB)
create_params.initially_hidden = true;
+ create_params.renderer_initiated_creation = true;
WebContentsImpl* new_contents = NULL;
if (!is_guest) {
@@ -1543,7 +1613,6 @@ void WebContentsImpl::CreateNewWindow(
new_contents->GetController().SetSessionStorageNamespace(
partition_id,
session_storage_namespace);
- new_contents->RenderViewCreated(new_contents->GetRenderViewHost());
// Save the window for later if we're not suppressing the opener (since it
// will be shown immediately).
@@ -1573,9 +1642,9 @@ void WebContentsImpl::CreateNewWindow(
// new window. As a result, we need to show and navigate the window here.
bool was_blocked = false;
if (delegate_) {
- gfx::Rect initial_pos;
+ gfx::Rect initial_rect;
delegate_->AddNewContents(
- this, new_contents, params.disposition, initial_pos,
+ this, new_contents, params.disposition, initial_rect,
params.user_gesture, &was_blocked);
}
if (!was_blocked) {
@@ -1610,12 +1679,12 @@ void WebContentsImpl::CreateNewWidget(int render_process_id,
// this WebContentsImpl instance. If any other process sends the request,
// it is invalid and the process must be terminated.
if (process->GetID() != render_process_id) {
- base::ProcessHandle process_handle =
- RenderProcessHost::FromID(render_process_id)->GetHandle();
+ RenderProcessHost* rph = RenderProcessHost::FromID(render_process_id);
+ base::ProcessHandle process_handle = rph->GetHandle();
if (process_handle != base::kNullProcessHandle) {
RecordAction(
base::UserMetricsAction("Terminate_ProcessMismatch_CreateNewWidget"));
- base::KillProcess(process_handle, RESULT_CODE_KILLED, false);
+ rph->Shutdown(RESULT_CODE_KILLED, false);
}
return;
}
@@ -1645,21 +1714,24 @@ void WebContentsImpl::CreateNewWidget(int render_process_id,
void WebContentsImpl::ShowCreatedWindow(int route_id,
WindowOpenDisposition disposition,
- const gfx::Rect& initial_pos,
+ const gfx::Rect& initial_rect,
bool user_gesture) {
WebContentsImpl* contents = GetCreatedWindow(route_id);
if (contents) {
WebContentsDelegate* delegate = GetDelegate();
+ if (!delegate || delegate->ShouldResumeRequestsForCreatedWindow())
+ contents->ResumeLoadingCreatedWebContents();
+
if (delegate) {
delegate->AddNewContents(
- this, contents, disposition, initial_pos, user_gesture, NULL);
+ this, contents, disposition, initial_rect, user_gesture, NULL);
}
}
}
void WebContentsImpl::ShowCreatedWidget(int route_id,
- const gfx::Rect& initial_pos) {
- ShowCreatedWidget(route_id, false, initial_pos);
+ const gfx::Rect& initial_rect) {
+ ShowCreatedWidget(route_id, false, initial_rect);
}
void WebContentsImpl::ShowCreatedFullscreenWidget(int route_id) {
@@ -1668,7 +1740,7 @@ void WebContentsImpl::ShowCreatedFullscreenWidget(int route_id) {
void WebContentsImpl::ShowCreatedWidget(int route_id,
bool is_fullscreen,
- const gfx::Rect& initial_pos) {
+ const gfx::Rect& initial_rect) {
RenderWidgetHostViewBase* widget_host_view =
static_cast<RenderWidgetHostViewBase*>(GetCreatedWidget(route_id));
if (!widget_host_view)
@@ -1688,7 +1760,7 @@ void WebContentsImpl::ShowCreatedWidget(int route_id,
fullscreen_widget_routing_id_ = route_id;
if (delegate_ && delegate_->EmbedsFullscreenWidget()) {
widget_host_view->InitAsChild(GetRenderWidgetHostView()->GetNativeView());
- delegate_->ToggleFullscreenModeForTab(this, true);
+ delegate_->EnterFullscreenModeForTab(this, GURL());
} else {
widget_host_view->InitAsFullscreen(view);
}
@@ -1698,7 +1770,7 @@ void WebContentsImpl::ShowCreatedWidget(int route_id,
if (!widget_host_view->HasFocus())
widget_host_view->Focus();
} else {
- widget_host_view->InitAsPopup(view, initial_pos);
+ widget_host_view->InitAsPopup(view, initial_rect);
}
RenderWidgetHostImpl* render_widget_host_impl =
@@ -1737,11 +1809,6 @@ 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;
}
@@ -1797,6 +1864,14 @@ FrameTree* WebContentsImpl::GetFrameTree() {
return &frame_tree_;
}
+void WebContentsImpl::SetIsVirtualKeyboardRequested(bool requested) {
+ virtual_keyboard_requested_ = requested;
+}
+
+bool WebContentsImpl::IsVirtualKeyboardRequested() {
+ return virtual_keyboard_requested_;
+}
+
AccessibilityMode WebContentsImpl::GetAccessibilityMode() const {
return accessibility_mode_;
}
@@ -1808,13 +1883,18 @@ void WebContentsImpl::AccessibilityEventReceived(
}
RenderFrameHost* WebContentsImpl::GetGuestByInstanceID(
+ RenderFrameHost* render_frame_host,
int browser_plugin_instance_id) {
BrowserPluginGuestManager* guest_manager =
GetBrowserContext()->GetGuestManager();
+ if (!guest_manager)
+ return nullptr;
+
WebContents* guest = guest_manager->GetGuestByInstanceID(
- this, browser_plugin_instance_id);
+ render_frame_host->GetProcess()->GetID(), browser_plugin_instance_id);
if (!guest)
- return NULL;
+ return nullptr;
+
return guest->GetMainFrame();
}
@@ -1849,14 +1929,14 @@ void WebContentsImpl::DidSendScreenRects(RenderWidgetHostImpl* rwh) {
BrowserAccessibilityManager*
WebContentsImpl::GetRootBrowserAccessibilityManager() {
- RenderFrameHostImpl* rfh = static_cast<RenderFrameHostImpl*>(GetMainFrame());
- return rfh ? rfh->browser_accessibility_manager() : NULL;
+ RenderFrameHostImpl* rfh = GetMainFrame();
+ return rfh ? rfh->browser_accessibility_manager() : nullptr;
}
BrowserAccessibilityManager*
WebContentsImpl::GetOrCreateRootBrowserAccessibilityManager() {
- RenderFrameHostImpl* rfh = static_cast<RenderFrameHostImpl*>(GetMainFrame());
- return rfh ? rfh->GetOrCreateBrowserAccessibilityManager() : NULL;
+ RenderFrameHostImpl* rfh = GetMainFrame();
+ return rfh ? rfh->GetOrCreateBrowserAccessibilityManager() : nullptr;
}
void WebContentsImpl::UpdatePreferredSize(const gfx::Size& pref_size) {
@@ -1893,8 +1973,9 @@ bool WebContentsImpl::NavigateToPendingEntry(
// 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());
+ // TODO(creis): Remove this method and NavigationEntryImpl::frame_tree_node_id
+ // by using FrameNavigationEntries instead. See https://crbug.com/236848.
+ NavigationEntryImpl* pending_entry = controller_.GetPendingEntry();
if (pending_entry->frame_tree_node_id() != -1) {
FrameTreeNode* subframe =
frame_tree_.FindByID(pending_entry->frame_tree_node_id());
@@ -1903,8 +1984,7 @@ bool WebContentsImpl::NavigateToPendingEntry(
node = subframe;
}
- return node->navigator()->NavigateToPendingEntry(
- node->current_frame_host(), reload_type);
+ return node->navigator()->NavigateToPendingEntry(node, reload_type);
}
void WebContentsImpl::RenderFrameForInterstitialPageCreated(
@@ -1920,8 +2000,7 @@ void WebContentsImpl::AttachInterstitialPage(
// Cancel any visible dialogs so that they don't interfere with the
// interstitial.
- if (dialog_manager_)
- dialog_manager_->CancelActiveAndPendingDialogs(this);
+ CancelActiveAndPendingDialogs();
FOR_EACH_OBSERVER(WebContentsObserver, observers_,
DidAttachInterstitialPage());
@@ -1934,28 +2013,18 @@ void WebContentsImpl::DetachInterstitialPage() {
DidDetachInterstitialPage());
}
-void WebContentsImpl::SetHistoryLengthAndPrune(
- const SiteInstance* site_instance,
- int history_length,
- int32 minimum_page_id) {
- // SetHistoryLengthAndPrune doesn't work when there are pending cross-site
- // navigations. Callers should ensure that this is the case.
- if (GetRenderManager()->pending_render_view_host()) {
- NOTREACHED();
- return;
- }
- RenderViewHostImpl* rvh = GetRenderViewHostImpl();
- if (!rvh) {
- NOTREACHED();
- return;
- }
- if (site_instance && rvh->GetSiteInstance() != site_instance) {
- NOTREACHED();
- return;
- }
- Send(new ViewMsg_SetHistoryLengthAndPrune(GetRoutingID(),
- history_length,
- minimum_page_id));
+void WebContentsImpl::SetHistoryOffsetAndLength(int history_offset,
+ int history_length) {
+ SetHistoryOffsetAndLengthForView(
+ GetRenderViewHost(), history_offset, history_length);
+}
+
+void WebContentsImpl::SetHistoryOffsetAndLengthForView(
+ RenderViewHost* render_view_host,
+ int history_offset,
+ int history_length) {
+ render_view_host->Send(new ViewMsg_SetHistoryOffsetAndLength(
+ render_view_host->GetRoutingID(), history_offset, history_length));
}
void WebContentsImpl::ReloadFocusedFrame(bool ignore_cache) {
@@ -2152,7 +2221,7 @@ void WebContentsImpl::FocusThroughTabTraversal(bool reverse) {
fullscreen_view->Focus();
return;
}
- GetRenderViewHostImpl()->SetInitialFocus(reverse);
+ GetRenderViewHost()->SetInitialFocus(reverse);
}
bool WebContentsImpl::ShowingInterstitialPage() const {
@@ -2171,14 +2240,14 @@ bool WebContentsImpl::IsSavable() {
contents_mime_type_ == "application/xhtml+xml" ||
contents_mime_type_ == "text/plain" ||
contents_mime_type_ == "text/css" ||
- net::IsSupportedJavascriptMimeType(contents_mime_type_.c_str());
+ mime_util::IsSupportedJavascriptMimeType(contents_mime_type_);
}
void WebContentsImpl::OnSavePage() {
// If we can not save the page, try to download it.
if (!IsSavable()) {
RecordDownloadSource(INITIATED_BY_SAVE_PACKAGE_ON_NON_HTML);
- SaveFrame(GetURL(), Referrer());
+ SaveFrame(GetLastCommittedURL(), Referrer());
return;
}
@@ -2206,9 +2275,20 @@ bool WebContentsImpl::SavePage(const base::FilePath& main_file,
void WebContentsImpl::SaveFrame(const GURL& url,
const Referrer& referrer) {
- if (!GetURL().is_valid())
+ SaveFrameWithHeaders(url, referrer, std::string());
+}
+
+void WebContentsImpl::SaveFrameWithHeaders(const GURL& url,
+ const Referrer& referrer,
+ const std::string& headers) {
+ if (!GetLastCommittedURL().is_valid())
+ return;
+ if (delegate_ && delegate_->SaveFrame(url, referrer))
return;
- bool is_main_frame = (url == GetURL());
+
+ // TODO(nasko): This check for main frame is incorrect and should be fixed
+ // by explicitly passing in which frame this method should target.
+ bool is_main_frame = (url == GetLastCommittedURL());
DownloadManager* dlm =
BrowserContext::GetDownloadManager(GetBrowserContext());
@@ -2224,10 +2304,22 @@ void WebContentsImpl::SaveFrame(const GURL& url,
DownloadUrlParameters::FromWebContents(this, url));
params->set_referrer(referrer);
params->set_post_id(post_id);
- params->set_prefer_cache(true);
if (post_id >= 0)
params->set_method("POST");
params->set_prompt(true);
+
+ if (headers.empty()) {
+ params->set_prefer_cache(true);
+ } else {
+ std::vector<std::string> key_value_list;
+ base::SplitString(headers, '\n', &key_value_list);
+ for (const auto& key_value : key_value_list) {
+ std::vector<std::string> pair;
+ base::SplitString(key_value, ':', &pair);
+ DCHECK_EQ(2ul, pair.size());
+ params->add_request_header(pair[0], pair[1]);
+ }
+ }
dlm->DownloadUrl(params.Pass());
}
@@ -2269,8 +2361,8 @@ void WebContentsImpl::DragSourceEndedAt(int client_x, int client_y,
browser_plugin_embedder_->DragSourceEndedAt(client_x, client_y,
screen_x, screen_y, operation);
if (GetRenderViewHost())
- GetRenderViewHostImpl()->DragSourceEndedAt(client_x, client_y,
- screen_x, screen_y, operation);
+ GetRenderViewHost()->DragSourceEndedAt(client_x, client_y, screen_x,
+ screen_y, operation);
}
void WebContentsImpl::DidGetResourceResponseStart(
@@ -2288,14 +2380,14 @@ void WebContentsImpl::DidGetResourceResponseStart(
}
void WebContentsImpl::DidGetRedirectForResourceRequest(
- RenderViewHost* render_view_host,
+ RenderFrameHost* render_frame_host,
const ResourceRedirectDetails& details) {
controller_.ssl_manager()->DidReceiveResourceRedirect(details);
FOR_EACH_OBSERVER(
WebContentsObserver,
observers_,
- DidGetRedirectForResourceRequest(render_view_host, details));
+ DidGetRedirectForResourceRequest(render_frame_host, details));
// TODO(avi): Remove. http://crbug.com/170921
NotificationService::current()->Notify(
@@ -2304,11 +2396,13 @@ void WebContentsImpl::DidGetRedirectForResourceRequest(
Details<const ResourceRedirectDetails>(&details));
}
+void WebContentsImpl::NotifyWebContentsFocused() {
+ FOR_EACH_OBSERVER(WebContentsObserver, observers_, OnWebContentsFocused());
+}
+
void WebContentsImpl::SystemDragEnded() {
if (GetRenderViewHost())
- GetRenderViewHostImpl()->DragSourceSystemDragEnded();
- if (delegate_)
- delegate_->DragEnded();
+ GetRenderViewHost()->DragSourceSystemDragEnded();
if (browser_plugin_embedder_.get())
browser_plugin_embedder_->SystemDragEnded();
}
@@ -2352,6 +2446,10 @@ int WebContentsImpl::GetMaximumZoomPercent() const {
return maximum_zoom_percent_;
}
+void WebContentsImpl::ResetPageScale() {
+ Send(new ViewMsg_ResetPageScale(GetRoutingID()));
+}
+
gfx::Size WebContentsImpl::GetPreferredSize() const {
return capturer_count_ == 0 ? preferred_size_ : preferred_size_for_capture_;
}
@@ -2360,14 +2458,19 @@ bool WebContentsImpl::GotResponseToLockMouseRequest(bool allowed) {
if (GetBrowserPluginGuest())
return GetBrowserPluginGuest()->LockMouse(allowed);
- return GetRenderViewHost() ?
- GetRenderViewHostImpl()->GotResponseToLockMouseRequest(allowed) : false;
+ return GetRenderViewHost()
+ ? GetRenderViewHost()->GotResponseToLockMouseRequest(allowed)
+ : false;
}
bool WebContentsImpl::HasOpener() const {
return opener_ != NULL;
}
+WebContents* WebContentsImpl::GetOpener() const {
+ return static_cast<WebContents*>(opener_);
+}
+
void WebContentsImpl::DidChooseColorInColorChooser(SkColor color) {
if (!color_chooser_info_.get())
return;
@@ -2398,8 +2501,10 @@ void WebContentsImpl::DidEndColorChooser() {
int WebContentsImpl::DownloadImage(const GURL& url,
bool is_favicon,
uint32_t max_bitmap_size,
+ bool bypass_cache,
const ImageDownloadCallback& callback) {
- int id = StartDownload(GetMainFrame(), url, is_favicon, max_bitmap_size);
+ int id = StartDownload(GetMainFrame(), url, is_favicon, max_bitmap_size,
+ bypass_cache);
image_download_map_[id] = callback;
return id;
}
@@ -2412,14 +2517,21 @@ 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;
+ if (browser_plugin_embedder_) {
+ BrowserPluginGuest* guest = browser_plugin_embedder_->GetFullPageGuest();
+ if (guest && guest->Find(request_id, search_text, options))
+ return;
}
Send(new ViewMsg_Find(GetRoutingID(), request_id, search_text, options));
}
void WebContentsImpl::StopFinding(StopFindAction action) {
+ // See if a top level browser plugin handles the stop finding request first.
+ if (browser_plugin_embedder_) {
+ BrowserPluginGuest* guest = browser_plugin_embedder_->GetFullPageGuest();
+ if (guest && guest->StopFinding(action))
+ return;
+ }
Send(new ViewMsg_StopFinding(GetRoutingID(), action));
}
@@ -2429,13 +2541,26 @@ void WebContentsImpl::InsertCSS(const std::string& css) {
}
bool WebContentsImpl::WasRecentlyAudible() {
- return audio_stream_monitor_.WasRecentlyAudible();
+ return audio_state_provider_->WasRecentlyAudible();
}
void WebContentsImpl::GetManifest(const GetManifestCallback& callback) {
manifest_manager_host_->GetManifest(GetMainFrame(), callback);
}
+void WebContentsImpl::ExitFullscreen() {
+ // Clean up related state and initiate the fullscreen exit.
+ GetRenderViewHost()->RejectMouseLockOrUnlockIfNecessary();
+ ExitFullscreenMode();
+}
+
+void WebContentsImpl::ResumeLoadingCreatedWebContents() {
+ // Resume blocked requests for both the RenderViewHost and RenderFrameHost.
+ // TODO(brettw): It seems bogus to reach into here and initialize the host.
+ GetRenderViewHost()->Init();
+ GetMainFrame()->Init();
+}
+
bool WebContentsImpl::FocusLocationBarByDefault() {
NavigationEntry* entry = controller_.GetVisibleEntry();
if (entry && entry->GetURL() == GURL(url::kAboutBlankURL))
@@ -2459,6 +2584,17 @@ void WebContentsImpl::DidStartProvisionalLoad(
observers_,
DidStartProvisionalLoadForFrame(
render_frame_host, validated_url, is_error_page, is_iframe_srcdoc));
+
+ // Notify accessibility if this is a reload.
+ NavigationEntry* entry = controller_.GetVisibleEntry();
+ if (entry && ui::PageTransitionCoreTypeIs(
+ entry->GetTransitionType(), ui::PAGE_TRANSITION_RELOAD)) {
+ FrameTreeNode* ftn = render_frame_host->frame_tree_node();
+ BrowserAccessibilityManager* manager =
+ ftn->current_frame_host()->browser_accessibility_manager();
+ if (manager)
+ manager->UserIsReloading();
+ }
}
void WebContentsImpl::DidStartNavigationTransition(
@@ -2480,6 +2616,12 @@ void WebContentsImpl::DidFailProvisionalLoadWithError(
validated_url,
params.error_code,
params.error_description));
+
+ FrameTreeNode* ftn = render_frame_host->frame_tree_node();
+ BrowserAccessibilityManager* manager =
+ ftn->current_frame_host()->browser_accessibility_manager();
+ if (manager)
+ manager->NavigationFailed();
}
void WebContentsImpl::DidFailLoadWithError(
@@ -2499,17 +2641,16 @@ void WebContentsImpl::NotifyChangedNavigationState(
}
void WebContentsImpl::AboutToNavigateRenderFrame(
- RenderFrameHostImpl* render_frame_host) {
- // Notify observers that we will navigate in this RenderView.
- RenderViewHost* render_view_host = render_frame_host->render_view_host();
+ RenderFrameHostImpl* old_host,
+ RenderFrameHostImpl* new_host) {
+ // Notify observers that we will navigate in this RenderFrame.
FOR_EACH_OBSERVER(
WebContentsObserver,
observers_,
- AboutToNavigateRenderView(render_view_host));
+ AboutToNavigateRenderFrame(old_host, new_host));
}
void WebContentsImpl::DidStartNavigationToPendingEntry(
- RenderFrameHostImpl* render_frame_host,
const GURL& url,
NavigationController::ReloadType reload_type) {
// Notify observers about navigation.
@@ -2521,18 +2662,22 @@ void WebContentsImpl::DidStartNavigationToPendingEntry(
void WebContentsImpl::RequestOpenURL(RenderFrameHostImpl* render_frame_host,
const OpenURLParams& params) {
- int source_render_frame_id = render_frame_host->GetRoutingID();
+ // OpenURL can blow away the source RFH. Use the process/frame routing ID as a
+ // weak pointer of sorts.
+ const int32_t process_id = render_frame_host->GetProcess()->GetID();
+ const int32_t frame_id = render_frame_host->GetRoutingID();
+
WebContents* new_contents = OpenURL(params);
- if (new_contents) {
+ if (new_contents && RenderFrameHost::FromID(process_id, frame_id)) {
// Notify observers.
FOR_EACH_OBSERVER(WebContentsObserver, observers_,
DidOpenRequestedURL(new_contents,
+ render_frame_host,
params.url,
params.referrer,
params.disposition,
- params.transition,
- source_render_frame_id));
+ params.transition));
}
}
@@ -2551,6 +2696,11 @@ void WebContentsImpl::DidCommitProvisionalLoad(
observers_,
DidCommitProvisionalLoadForFrame(
render_frame_host, url, transition_type));
+
+ BrowserAccessibilityManager* manager =
+ render_frame_host->browser_accessibility_manager();
+ if (manager)
+ manager->NavigationSucceeded();
}
void WebContentsImpl::DidNavigateMainFramePreCommit(
@@ -2563,11 +2713,12 @@ void WebContentsImpl::DidNavigateMainFramePreCommit(
return;
}
if (IsFullscreenForCurrentTab())
- GetRenderViewHost()->ExitFullscreen();
+ ExitFullscreen();
DCHECK(!IsFullscreenForCurrentTab());
}
void WebContentsImpl::DidNavigateMainFramePostCommit(
+ RenderFrameHostImpl* render_frame_host,
const LoadCommittedDetails& details,
const FrameHostMsg_DidCommitProvisionalLoad_Params& params) {
if (details.is_navigation_to_different_page()) {
@@ -2577,7 +2728,15 @@ 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(GURL());
+ UpdateTargetURL(render_frame_host->GetRenderViewHost(), GURL());
+
+ RenderWidgetHostViewBase* rwhvb =
+ static_cast<RenderWidgetHostViewBase*>(GetRenderWidgetHostView());
+ if (rwhvb)
+ rwhvb->OnDidNavigateMainFrameToNewPage();
+
+ // Reset theme color on navigation to new page.
+ theme_color_ = SK_ColorTRANSPARENT;
}
if (!details.is_in_page) {
@@ -2606,8 +2765,8 @@ void WebContentsImpl::DidNavigateAnyFramePostCommit(
has_accessed_initial_document_ = false;
// If we navigate off the page, close all JavaScript dialogs.
- if (dialog_manager_ && !details.is_in_page)
- dialog_manager_->CancelActiveAndPendingDialogs(this);
+ if (!details.is_in_page)
+ CancelActiveAndPendingDialogs();
// Notify observers about navigation.
FOR_EACH_OBSERVER(WebContentsObserver, observers_,
@@ -2630,8 +2789,9 @@ bool WebContentsImpl::CanOverscrollContent() const {
}
void WebContentsImpl::OnThemeColorChanged(SkColor theme_color) {
- FOR_EACH_OBSERVER(WebContentsObserver, observers_,
- DidChangeThemeColor(theme_color));
+ // Update the theme color. This is to be published to observers on visually
+ // non empty paint.
+ theme_color_ = theme_color;
}
void WebContentsImpl::OnDidLoadResourceFromMemoryCache(
@@ -2640,8 +2800,6 @@ void WebContentsImpl::OnDidLoadResourceFromMemoryCache(
const std::string& http_method,
const std::string& mime_type,
ResourceType resource_type) {
- base::StatsCounter cache("WebKit.CacheHit");
- cache.Increment();
// Send out a notification that we loaded a resource from our memory cache.
int cert_id = 0;
@@ -2697,21 +2855,18 @@ void WebContentsImpl::OnDidRunInsecureContent(
}
void WebContentsImpl::OnDocumentLoadedInFrame() {
- CHECK(render_frame_message_source_);
- CHECK(!render_view_message_source_);
+ if (!HasValidFrameSource())
+ return;
+
RenderFrameHostImpl* rfh =
static_cast<RenderFrameHostImpl*>(render_frame_message_source_);
FOR_EACH_OBSERVER(
WebContentsObserver, observers_, DocumentLoadedInFrame(rfh));
}
-void WebContentsImpl::OnDidFinishLoad(
- const GURL& url) {
- if (!render_frame_message_source_) {
- RecordAction(base::UserMetricsAction("BadMessageTerminate_RVD2"));
- GetRenderProcessHost()->ReceivedBadMessage();
+void WebContentsImpl::OnDidFinishLoad(const GURL& url) {
+ if (!HasValidFrameSource())
return;
- }
GURL validated_url(url);
RenderProcessHost* render_process_host =
@@ -2724,91 +2879,6 @@ void WebContentsImpl::OnDidFinishLoad(
WebContentsObserver, observers_, DidFinishLoad(rfh, validated_url));
}
-void WebContentsImpl::OnDidStartLoading(bool to_different_document) {
- RenderFrameHostImpl* rfh =
- static_cast<RenderFrameHostImpl*>(render_frame_message_source_);
- int64 render_frame_id = rfh->frame_tree_node()->frame_tree_node_id();
-
- // It is possible to get multiple calls to OnDidStartLoading that don't have
- // corresponding calls to OnDidStopLoading:
- // - With "swappedout://" URLs, this happens when a RenderView gets swapped
- // out for a cross-process navigation, and it turns into a placeholder for
- // one being rendered in a different process.
- // - Also, there might be more than one RenderFrameHost sharing the same
- // FrameTreeNode (and thus sharing its ID) each sending a start.
- // - But in the future, once clamy@ moves navigation network requests to the
- // browser process, there's a good chance that callbacks about starting and
- // stopping will all be handled by the browser. When that happens, there
- // should no longer be a start/stop call imbalance. TODO(avi): When this
- // future arrives, update this code to not allow this case.
- DCHECK_GE(loading_frames_in_progress_, 0);
- if (loading_progresses_.find(render_frame_id) == loading_progresses_.end()) {
- if (loading_frames_in_progress_ == 0)
- DidStartLoading(rfh, to_different_document);
- ++loading_frames_in_progress_;
- }
-
- loading_progresses_[render_frame_id] = kMinimumLoadingProgress;
- SendLoadProgressChanged();
-}
-
-void WebContentsImpl::OnDidStopLoading() {
- RenderFrameHostImpl* rfh =
- static_cast<RenderFrameHostImpl*>(render_frame_message_source_);
- int64 render_frame_id = rfh->frame_tree_node()->frame_tree_node_id();
-
- if (loading_progresses_.find(render_frame_id) != loading_progresses_.end()) {
- // Load stopped while we were still tracking load. Make sure we update
- // progress based on this frame's completion.
- loading_progresses_[render_frame_id] = 1.0;
- SendLoadProgressChanged();
- // Then we clean-up our states.
- if (loading_total_progress_ == 1.0)
- ResetLoadProgressState();
- }
-
- // TODO(japhet): This should be a DCHECK, but the pdf plugin sometimes
- // calls DidStopLoading() without a matching DidStartLoading().
- if (loading_frames_in_progress_ == 0)
- return;
- --loading_frames_in_progress_;
- if (loading_frames_in_progress_ == 0)
- DidStopLoading(rfh);
-}
-
-void WebContentsImpl::OnDidChangeLoadProgress(double load_progress) {
- RenderFrameHostImpl* rfh =
- static_cast<RenderFrameHostImpl*>(render_frame_message_source_);
- int64 render_frame_id = rfh->frame_tree_node()->frame_tree_node_id();
-
- loading_progresses_[render_frame_id] = load_progress;
-
- // We notify progress change immediately for the first and last updates.
- // Also, since the message loop may be pretty busy when a page is loaded, it
- // might not execute a posted task in a timely manner so we make sure to
- // immediately send progress report if enough time has passed.
- base::TimeDelta min_delay =
- base::TimeDelta::FromMilliseconds(kMinimumDelayBetweenLoadingUpdatesMS);
- if (load_progress == 1.0 || loading_last_progress_update_.is_null() ||
- base::TimeTicks::Now() - loading_last_progress_update_ > min_delay) {
- // If there is a pending task to send progress, it is now obsolete.
- loading_weak_factory_.InvalidateWeakPtrs();
- SendLoadProgressChanged();
- if (loading_total_progress_ == 1.0)
- ResetLoadProgressState();
- return;
- }
-
- if (loading_weak_factory_.HasWeakPtrs())
- return;
-
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&WebContentsImpl::SendLoadProgressChanged,
- loading_weak_factory_.GetWeakPtr()),
- min_delay);
-}
-
void WebContentsImpl::OnGoToEntryAtOffset(int offset) {
if (!delegate_ || delegate_->OnGoToEntryOffset(offset))
controller_.GoToOffset(offset);
@@ -2913,6 +2983,9 @@ void WebContentsImpl::OnOpenColorChooser(
int color_chooser_id,
SkColor color,
const std::vector<ColorSuggestion>& suggestions) {
+ if (!HasValidFrameSource())
+ return;
+
ColorChooser* new_color_chooser = delegate_ ?
delegate_->OpenColorChooser(this, color, suggestions) :
NULL;
@@ -2989,15 +3062,11 @@ void WebContentsImpl::OnPpapiBrokerPermissionResult(int routing_id,
Send(new ViewMsg_PpapiBrokerPermissionResult(routing_id, result));
}
-void WebContentsImpl::OnBrowserPluginMessage(const IPC::Message& message) {
- // This creates a BrowserPluginEmbedder, which handles all the BrowserPlugin
- // specific messages for this WebContents. This means that any message from
- // a BrowserPlugin prior to this will be ignored.
- // For more info, see comment above classes BrowserPluginEmbedder and
- // BrowserPluginGuest.
+void WebContentsImpl::OnBrowserPluginMessage(RenderFrameHost* render_frame_host,
+ const IPC::Message& message) {
CHECK(!browser_plugin_embedder_.get());
- browser_plugin_embedder_.reset(BrowserPluginEmbedder::Create(this));
- browser_plugin_embedder_->OnMessageReceived(message);
+ CreateBrowserPluginEmbedderIfNecessary();
+ browser_plugin_embedder_->OnMessageReceived(message, render_frame_host);
}
#endif // defined(ENABLE_PLUGINS)
@@ -3025,30 +3094,35 @@ void WebContentsImpl::OnDidDownloadImage(
void WebContentsImpl::OnUpdateFaviconURL(
const std::vector<FaviconURL>& candidates) {
+ // We get updated favicon URLs after the page stops loading. If a cross-site
+ // navigation occurs while a page is still loading, the initial page
+ // may stop loading and send us updated favicon URLs after the navigation
+ // for the new page has committed.
+ RenderViewHostImpl* rvhi =
+ static_cast<RenderViewHostImpl*>(render_view_message_source_);
+ if (!rvhi->is_active())
+ return;
+
FOR_EACH_OBSERVER(WebContentsObserver, observers_,
DidUpdateFaviconURL(candidates));
}
void WebContentsImpl::CreateAudioPowerSaveBlocker() {
- // ChromeOS has its own way of handling power save blocks for media.
-#if !defined(OS_CHROMEOS)
DCHECK(!audio_power_save_blocker_);
audio_power_save_blocker_ = PowerSaveBlocker::Create(
- PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension, "Playing Audio");
-#endif
+ PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
+ PowerSaveBlocker::kReasonAudioPlayback, "Playing audio");
}
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");
+ PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
+ PowerSaveBlocker::kReasonVideoPlayback, "Playing video");
#if defined(OS_ANDROID)
static_cast<PowerSaveBlockerImpl*>(video_power_save_blocker_.get())
- ->InitDisplaySleepBlocker(GetView()->GetNativeView());
-#endif
+ ->InitDisplaySleepBlocker(this);
#endif
}
@@ -3057,7 +3131,7 @@ void WebContentsImpl::MaybeReleasePowerSaveBlockers() {
// monitoring, release the audio power save blocker here instead of during
// NotifyNavigationStateChanged().
if (active_audio_players_.empty() &&
- !AudioStreamMonitor::monitoring_available()) {
+ !audio_state_provider_->IsAudioStateAvailable()) {
audio_power_save_blocker_.reset();
}
@@ -3080,7 +3154,7 @@ void WebContentsImpl::OnMediaPlayingNotification(int64 player_cookie,
// 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()) {
+ !audio_state_provider_->IsAudioStateAvailable()) {
CreateAudioPowerSaveBlocker();
}
}
@@ -3092,17 +3166,28 @@ void WebContentsImpl::OnMediaPlayingNotification(int64 player_cookie,
if (!video_power_save_blocker_ && !IsHidden())
CreateVideoPowerSaveBlocker();
}
+
+ FOR_EACH_OBSERVER(WebContentsObserver, observers_, MediaStartedPlaying());
}
void WebContentsImpl::OnMediaPausedNotification(int64 player_cookie) {
RemoveMediaPlayerEntry(player_cookie, &active_audio_players_);
RemoveMediaPlayerEntry(player_cookie, &active_video_players_);
MaybeReleasePowerSaveBlockers();
+
+ FOR_EACH_OBSERVER(WebContentsObserver, observers_, MediaPaused());
}
void WebContentsImpl::OnFirstVisuallyNonEmptyPaint() {
FOR_EACH_OBSERVER(WebContentsObserver, observers_,
DidFirstVisuallyNonEmptyPaint());
+
+ if (theme_color_ != last_sent_theme_color_) {
+ // Theme color should have updated by now if there was one.
+ FOR_EACH_OBSERVER(WebContentsObserver, observers_,
+ DidChangeThemeColor(theme_color_));
+ last_sent_theme_color_ = theme_color_;
+ }
}
void WebContentsImpl::DidChangeVisibleSSLState() {
@@ -3127,8 +3212,7 @@ bool WebContentsImpl::HasAccessedInitialDocument() {
// Notifies the RenderWidgetHost instance about the fact that the page is
// loading, or done loading.
-void WebContentsImpl::SetIsLoading(RenderViewHost* render_view_host,
- bool is_loading,
+void WebContentsImpl::SetIsLoading(bool is_loading,
bool to_different_document,
LoadNotificationDetails* details) {
if (is_loading == is_loading_)
@@ -3156,13 +3240,11 @@ void WebContentsImpl::SetIsLoading(RenderViewHost* render_view_host,
if (is_loading) {
TRACE_EVENT_ASYNC_BEGIN1("browser,navigation", "WebContentsImpl Loading",
this, "URL", url);
- FOR_EACH_OBSERVER(WebContentsObserver, observers_,
- DidStartLoading(render_view_host));
+ FOR_EACH_OBSERVER(WebContentsObserver, observers_, DidStartLoading());
} else {
TRACE_EVENT_ASYNC_END1("browser,navigation", "WebContentsImpl Loading",
this, "URL", url);
- FOR_EACH_OBSERVER(WebContentsObserver, observers_,
- DidStopLoading(render_view_host));
+ FOR_EACH_OBSERVER(WebContentsObserver, observers_, DidStopLoading());
}
// TODO(avi): Remove. http://crbug.com/170921
@@ -3254,33 +3336,14 @@ bool WebContentsImpl::UpdateTitleForEntry(NavigationEntryImpl* entry,
return true;
}
-void WebContentsImpl::SendLoadProgressChanged() {
+void WebContentsImpl::SendChangeLoadProgress() {
loading_last_progress_update_ = base::TimeTicks::Now();
- double progress = 0.0;
- int frame_count = 0;
-
- for (LoadingProgressMap::iterator it = loading_progresses_.begin();
- it != loading_progresses_.end();
- ++it) {
- progress += it->second;
- ++frame_count;
- }
- if (frame_count == 0)
- return;
- progress /= frame_count;
- DCHECK(progress <= 1.0);
-
- if (progress <= loading_total_progress_)
- return;
- loading_total_progress_ = progress;
-
if (delegate_)
- delegate_->LoadProgressChanged(this, progress);
+ delegate_->LoadProgressChanged(this, frame_tree_.load_progress());
}
void WebContentsImpl::ResetLoadProgressState() {
- loading_progresses_.clear();
- loading_total_progress_ = 0.0;
+ frame_tree_.ResetLoadProgress();
loading_weak_factory_.InvalidateWeakPtrs();
loading_last_progress_update_ = base::TimeTicks();
}
@@ -3294,14 +3357,6 @@ void WebContentsImpl::NotifyViewSwapped(RenderViewHost* old_host,
FOR_EACH_OBSERVER(WebContentsObserver, observers_,
RenderViewHostChanged(old_host, new_host));
- // TODO(avi): Remove. http://crbug.com/170921
- std::pair<RenderViewHost*, RenderViewHost*> details =
- std::make_pair(old_host, new_host);
- NotificationService::current()->Notify(
- NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
- Source<WebContents>(this),
- Details<std::pair<RenderViewHost*, RenderViewHost*> >(&details));
-
// Ensure that the associated embedder gets cleared after a RenderViewHost
// gets swapped, so we don't reuse the same embedder next time a
// RenderViewHost is attached to this WebContents.
@@ -3368,11 +3423,6 @@ void WebContentsImpl::ShowContextMenu(RenderFrameHost* render_frame_host,
const ContextMenuParams& params) {
ContextMenuParams context_menu_params(params);
// Allow WebContentsDelegates to handle the context menu operation first.
- if (GetBrowserPluginGuest()) {
- WebContentsViewGuest* view_guest =
- static_cast<WebContentsViewGuest*>(GetView());
- context_menu_params = view_guest->ConvertContextMenuParams(params);
- }
if (delegate_ && delegate_->HandleContextMenu(context_menu_params))
return;
@@ -3392,15 +3442,14 @@ void WebContentsImpl::RunJavaScriptMessage(
// want the hidden page's dialogs to interfere with the interstitial.
bool suppress_this_message =
static_cast<RenderFrameHostImpl*>(render_frame_host)->is_swapped_out() ||
- ShowingInterstitialPage() ||
- !delegate_ ||
- delegate_->ShouldSuppressDialogs() ||
- !delegate_->GetJavaScriptDialogManager();
+ ShowingInterstitialPage() || !delegate_ ||
+ delegate_->ShouldSuppressDialogs(this) ||
+ !delegate_->GetJavaScriptDialogManager(this);
if (!suppress_this_message) {
std::string accept_lang = GetContentClient()->browser()->
GetAcceptLangs(GetBrowserContext());
- dialog_manager_ = delegate_->GetJavaScriptDialogManager();
+ dialog_manager_ = delegate_->GetJavaScriptDialogManager(this);
dialog_manager_->RunJavaScriptDialog(
this,
frame_url.GetOrigin(),
@@ -3440,17 +3489,16 @@ void WebContentsImpl::RunBeforeUnloadConfirm(
delegate_->WillRunBeforeUnloadConfirm();
bool suppress_this_message =
- rfhi->rfh_state() != RenderFrameHostImpl::STATE_DEFAULT ||
- !delegate_ ||
- delegate_->ShouldSuppressDialogs() ||
- !delegate_->GetJavaScriptDialogManager();
+ rfhi->rfh_state() != RenderFrameHostImpl::STATE_DEFAULT || !delegate_ ||
+ delegate_->ShouldSuppressDialogs(this) ||
+ !delegate_->GetJavaScriptDialogManager(this);
if (suppress_this_message) {
rfhi->JavaScriptDialogClosed(reply_msg, true, base::string16(), true);
return;
}
is_showing_before_unload_dialog_ = true;
- dialog_manager_ = delegate_->GetJavaScriptDialogManager();
+ dialog_manager_ = delegate_->GetJavaScriptDialogManager(this);
dialog_manager_->RunBeforeUnloadDialog(
this, message, is_reload,
base::Bind(&WebContentsImpl::OnDialogClosed, base::Unretained(this),
@@ -3526,16 +3574,6 @@ void WebContentsImpl::RenderViewCreated(RenderViewHost* render_view_host) {
FOR_EACH_OBSERVER(
WebContentsObserver, observers_, RenderViewCreated(render_view_host));
-
- // We tell the observers now instead of when the main RenderFrameHostImpl is
- // constructed because otherwise it would be too early (i.e. IPCs sent to the
- // frame would be dropped because it's not created yet).
- 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) {
@@ -3576,16 +3614,15 @@ void WebContentsImpl::RenderViewTerminated(RenderViewHost* rvh,
// Ensure fullscreen mode is exited in the |delegate_| since a crashed
// renderer may not have made a clean exit.
if (IsFullscreenForCurrentTab())
- ToggleFullscreenMode(false);
+ ExitFullscreenMode();
// Cancel any visible dialogs so they are not left dangling over the sad tab.
- if (dialog_manager_)
- dialog_manager_->CancelActiveAndPendingDialogs(this);
+ CancelActiveAndPendingDialogs();
if (delegate_)
delegate_->HideValidationMessage(this);
- SetIsLoading(rvh, false, true, NULL);
+ SetIsLoading(false, true, nullptr);
NotifyDisconnected();
SetIsCrashed(status, error_code);
@@ -3594,7 +3631,6 @@ void WebContentsImpl::RenderViewTerminated(RenderViewHost* rvh,
// webpage? Once this function is called at a more granular frame level, we
// probably will need to more granularly reset the state here.
ResetLoadProgressState();
- loading_frames_in_progress_ = 0;
FOR_EACH_OBSERVER(WebContentsObserver,
observers_,
@@ -3608,14 +3644,12 @@ void WebContentsImpl::RenderViewDeleted(RenderViewHost* rvh) {
void WebContentsImpl::UpdateState(RenderViewHost* rvh,
int32 page_id,
const PageState& page_state) {
- // Ensure that this state update comes from either the active RVH or one of
- // the swapped out RVHs. We don't expect to hear from any other RVHs.
+ // Ensure that this state update comes from a RenderViewHost that belongs to
+ // this WebContents.
// TODO(nasko): This should go through RenderFrameHost.
// TODO(creis): We can't update state for cross-process subframes until we
// have FrameNavigationEntries. Once we do, this should be a DCHECK.
- if (rvh != GetRenderViewHost() &&
- !GetRenderManager()->IsRVHOnSwappedOutList(
- static_cast<RenderViewHostImpl*>(rvh)))
+ if (rvh->GetDelegate()->GetAsWebContents() != this)
return;
// We must be prepared to handle state updates for any page, these occur
@@ -3636,7 +3670,15 @@ void WebContentsImpl::UpdateState(RenderViewHost* rvh,
controller_.NotifyEntryChanged(entry, entry_index);
}
-void WebContentsImpl::UpdateTargetURL(const GURL& url) {
+void WebContentsImpl::UpdateTargetURL(RenderViewHost* render_view_host,
+ const GURL& url) {
+ if (fullscreen_widget_routing_id_ != MSG_ROUTING_NONE) {
+ // If we're fullscreen only update the url if it's from the fullscreen
+ // renderer.
+ RenderWidgetHostView* fs = GetFullscreenRenderWidgetHostView();
+ if (fs && fs->GetRenderWidgetHost() != render_view_host)
+ return;
+ }
if (delegate_)
delegate_->UpdateTargetURL(this, url);
}
@@ -3686,13 +3728,21 @@ void WebContentsImpl::RequestMove(const gfx::Rect& new_bounds) {
delegate_->MoveContents(this, new_bounds);
}
-void WebContentsImpl::DidStartLoading(RenderFrameHost* render_frame_host,
+void WebContentsImpl::DidStartLoading(FrameTreeNode* frame_tree_node,
bool to_different_document) {
- SetIsLoading(render_frame_host->GetRenderViewHost(), true,
- to_different_document, NULL);
+ SetIsLoading(true, to_different_document, nullptr);
+
+ // Notify accessibility that the user is navigating away from the
+ // current document.
+ //
+ // TODO(dmazzoni): do this using a WebContentsObserver.
+ BrowserAccessibilityManager* manager =
+ frame_tree_node->current_frame_host()->browser_accessibility_manager();
+ if (manager)
+ manager->UserIsNavigatingAway();
}
-void WebContentsImpl::DidStopLoading(RenderFrameHost* render_frame_host) {
+void WebContentsImpl::DidStopLoading() {
scoped_ptr<LoadNotificationDetails> details;
// Use the last committed entry rather than the active one, in case a
@@ -3714,8 +3764,42 @@ void WebContentsImpl::DidStopLoading(RenderFrameHost* render_frame_host) {
controller_.GetCurrentEntryIndex()));
}
- SetIsLoading(render_frame_host->GetRenderViewHost(), false, true,
- details.get());
+ SetIsLoading(false, true, details.get());
+}
+
+void WebContentsImpl::DidChangeLoadProgress() {
+ double load_progress = frame_tree_.load_progress();
+
+ // The delegate is notified immediately for the first and last updates. Also,
+ // since the message loop may be pretty busy when a page is loaded, it might
+ // not execute a posted task in a timely manner so the progress report is sent
+ // immediately if enough time has passed.
+ base::TimeDelta min_delay =
+ base::TimeDelta::FromMilliseconds(kMinimumDelayBetweenLoadingUpdatesMS);
+ bool delay_elapsed = loading_last_progress_update_.is_null() ||
+ base::TimeTicks::Now() - loading_last_progress_update_ > min_delay;
+
+ if (load_progress == 0.0 || load_progress == 1.0 || delay_elapsed) {
+ // If there is a pending task to send progress, it is now obsolete.
+ loading_weak_factory_.InvalidateWeakPtrs();
+
+ // Notify the load progress change.
+ SendChangeLoadProgress();
+
+ // Clean-up the states if needed.
+ if (load_progress == 1.0)
+ ResetLoadProgressState();
+ return;
+ }
+
+ if (loading_weak_factory_.HasWeakPtrs())
+ return;
+
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&WebContentsImpl::SendChangeLoadProgress,
+ loading_weak_factory_.GetWeakPtr()),
+ min_delay);
}
void WebContentsImpl::DidCancelLoading() {
@@ -3732,12 +3816,18 @@ void WebContentsImpl::DidAccessInitialDocument() {
// to let the user edit it and try again. Clear it now that content might
// show up underneath it.
if (!IsLoading() && controller_.GetPendingEntry())
- controller_.DiscardPendingEntry();
+ controller_.DiscardPendingEntry(false);
// Update the URL display.
NotifyNavigationStateChanged(INVALIDATE_TYPE_URL);
}
+void WebContentsImpl::DidChangeName(RenderFrameHost* render_frame_host,
+ const std::string& name) {
+ FOR_EACH_OBSERVER(WebContentsObserver, observers_,
+ FrameNameChanged(render_frame_host, name));
+}
+
void WebContentsImpl::DidDisownOpener(RenderFrameHost* render_frame_host) {
// No action is necessary if the opener has already been cleared.
if (!opener_)
@@ -3807,6 +3897,7 @@ void WebContentsImpl::DocumentAvailableInMainFrame(
FOR_EACH_OBSERVER(WebContentsObserver, observers_,
DocumentAvailableInMainFrame());
}
+
void WebContentsImpl::RouteCloseEvent(RenderViewHost* rvh) {
// Tell the active RenderViewHost to run unload handlers and close, as long
// as the request came from a RenderViewHost in the same BrowsingInstance.
@@ -3814,69 +3905,39 @@ void WebContentsImpl::RouteCloseEvent(RenderViewHost* rvh) {
// It is possible to receive it from one that has just been swapped in,
// in which case we might as well deliver the message anyway.
if (rvh->GetSiteInstance()->IsRelatedSiteInstance(GetSiteInstance()))
- GetRenderViewHost()->ClosePage();
+ ClosePage();
}
-void WebContentsImpl::RouteMessageEvent(
- RenderViewHost* rvh,
- const ViewMsg_PostMessage_Params& params) {
- // Only deliver the message to the active RenderViewHost if the request
- // came from a RenderViewHost in the same BrowsingInstance or if this
- // WebContents is dedicated to a browser plugin guest.
+bool WebContentsImpl::ShouldRouteMessageEvent(
+ RenderFrameHost* target_rfh,
+ SiteInstance* source_site_instance) const {
+ // Allow the message if this WebContents is dedicated to a browser plugin
+ // guest.
// Note: This check means that an embedder could theoretically receive a
// postMessage from anyone (not just its own guests). However, this is
// probably not a risk for apps since other pages won't have references
// to App windows.
- if (!rvh->GetSiteInstance()->IsRelatedSiteInstance(GetSiteInstance()) &&
- !GetBrowserPluginGuest() && !GetBrowserPluginEmbedder())
- return;
-
- ViewMsg_PostMessage_Params new_params(params);
-
- if (!params.message_port_ids.empty()) {
- MessagePortMessageFilter* message_port_message_filter =
- static_cast<RenderProcessHostImpl*>(GetRenderProcessHost())
- ->message_port_message_filter();
- message_port_message_filter->UpdateMessagePortsWithNewRoutes(
- params.message_port_ids,
- &new_params.new_routing_ids);
- }
+ return GetBrowserPluginGuest() || GetBrowserPluginEmbedder();
+}
- // If there is a source_routing_id, translate it to the routing ID for
- // the equivalent swapped out RVH in the target process. If we need
- // to create a swapped out RVH for the source tab, we create its opener
- // chain as well, since those will also be accessible to the target page.
- if (new_params.source_routing_id != MSG_ROUTING_NONE) {
- // Try to look up the WebContents for the source page.
- WebContentsImpl* source_contents = NULL;
- RenderViewHostImpl* source_rvh = RenderViewHostImpl::FromID(
- rvh->GetProcess()->GetID(), params.source_routing_id);
- if (source_rvh) {
- source_contents = static_cast<WebContentsImpl*>(
- source_rvh->GetDelegate()->GetAsWebContents());
- }
+int WebContentsImpl::EnsureOpenerRenderViewsExist(
+ RenderFrameHost* source_rfh) {
+ WebContentsImpl* source_web_contents = static_cast<WebContentsImpl*>(
+ WebContents::FromRenderFrameHost(source_rfh));
- if (source_contents) {
- if (GetBrowserPluginGuest()) {
- // We create a swapped out RenderView for the embedder in the guest's
- // render process but we intentionally do not expose the embedder's
- // opener chain to it.
- new_params.source_routing_id =
- source_contents->CreateSwappedOutRenderView(GetSiteInstance());
- } else {
- new_params.source_routing_id =
- source_contents->CreateOpenerRenderViews(GetSiteInstance());
- }
+ if (source_web_contents) {
+ if (GetBrowserPluginGuest()) {
+ // We create a swapped out RenderView for the embedder in the guest's
+ // render process but we intentionally do not expose the embedder's
+ // opener chain to it.
+ return
+ source_web_contents->CreateSwappedOutRenderView(GetSiteInstance());
} else {
- // We couldn't find it, so don't pass a source frame.
- new_params.source_routing_id = MSG_ROUTING_NONE;
+ return source_web_contents->CreateOpenerRenderViews(GetSiteInstance());
}
}
- // In most cases, we receive this from a swapped out RenderViewHost.
- // It is possible to receive it from one that has just been swapped in,
- // in which case we might as well deliver the message anyway.
- Send(new ViewMsg_PostMessageEvent(GetRoutingID(), new_params));
+ return MSG_ROUTING_NONE;
}
bool WebContentsImpl::AddMessageToConsole(int32 level,
@@ -3889,21 +3950,15 @@ bool WebContentsImpl::AddMessageToConsole(int32 level,
source_id);
}
-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,
- // as it is deprecated and can be out of sync with GetRenderViewHost().
- GURL url = controller_.GetActiveEntry()
- ? controller_.GetActiveEntry()->GetURL() : GURL::EmptyGURL();
-
- return GetRenderManager()->current_host()->ComputeWebkitPrefs(url);
-}
-
int WebContentsImpl::CreateSwappedOutRenderView(
SiteInstance* instance) {
- return GetRenderManager()->CreateRenderFrame(
- instance, MSG_ROUTING_NONE, true, true, true);
+ int render_view_routing_id = MSG_ROUTING_NONE;
+ GetRenderManager()->CreateRenderFrame(
+ instance, nullptr, MSG_ROUTING_NONE,
+ CREATE_RF_SWAPPED_OUT | CREATE_RF_FOR_MAIN_FRAME_NAVIGATION |
+ CREATE_RF_HIDDEN,
+ &render_view_routing_id);
+ return render_view_routing_id;
}
void WebContentsImpl::OnUserGesture() {
@@ -3935,7 +3990,7 @@ void WebContentsImpl::RendererUnresponsive(RenderViewHost* render_view_host) {
if (DevToolsAgentHost::IsDebuggerAttached(this))
return;
- if (rfhi->is_waiting_for_beforeunload_ack() ||
+ if (rfhi->IsWaitingForBeforeUnloadACK() ||
rfhi->IsWaitingForUnloadACK()) {
// Hang occurred while firing the beforeunload/unload handler.
// Pretend the handler fired so tab closing continues as if it had.
@@ -3951,7 +4006,7 @@ void WebContentsImpl::RendererUnresponsive(RenderViewHost* render_view_host) {
// close. Otherwise, pretend the unload listeners have all fired and close
// the tab.
bool close = true;
- if (rfhi->is_waiting_for_beforeunload_ack() && delegate_) {
+ if (rfhi->IsWaitingForBeforeUnloadACK() && delegate_) {
delegate_->BeforeUnloadFired(this, true, &close);
}
if (close)
@@ -3959,7 +4014,7 @@ void WebContentsImpl::RendererUnresponsive(RenderViewHost* render_view_host) {
return;
}
- if (!GetRenderViewHostImpl() || !GetRenderViewHostImpl()->IsRenderViewLive())
+ if (!GetRenderViewHost() || !GetRenderViewHost()->IsRenderViewLive())
return;
if (delegate_)
@@ -3976,6 +4031,11 @@ void WebContentsImpl::LoadStateChanged(
const net::LoadStateWithParam& load_state,
uint64 upload_position,
uint64 upload_size) {
+ // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466285
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile1(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "466285 WebContentsImpl::LoadStateChanged::Start"));
load_state_ = load_state;
upload_position_ = upload_position;
upload_size_ = upload_size;
@@ -4019,16 +4079,22 @@ void WebContentsImpl::UpdateRenderViewSizeForRenderManager() {
void WebContentsImpl::CancelModalDialogsForRenderManager() {
// We need to cancel modal dialogs when doing a process swap, since the load
- // deferrer would prevent us from swapping out.
+ // deferrer would prevent us from swapping out. We also clear the state
+ // because this is a cross-process navigation, which means that it's a new
+ // site that should not have to pay for the sins of its predecessor.
+ //
+ // Note that we don't bother telling browser_plugin_embedder_ because the
+ // cross-process navigation will either destroy the browser plugins or not
+ // require their dialogs to close.
if (dialog_manager_)
- dialog_manager_->CancelActiveAndPendingDialogs(this);
+ dialog_manager_->ResetDialogState(this);
}
void WebContentsImpl::NotifySwappedFromRenderManager(RenderFrameHost* old_host,
RenderFrameHost* new_host,
bool is_main_frame) {
if (is_main_frame) {
- NotifyViewSwapped(old_host ? old_host->GetRenderViewHost() : NULL,
+ NotifyViewSwapped(old_host ? old_host->GetRenderViewHost() : nullptr,
new_host->GetRenderViewHost());
// Make sure the visible RVH reflects the new delegate's preferences.
@@ -4041,6 +4107,12 @@ void WebContentsImpl::NotifySwappedFromRenderManager(RenderFrameHost* old_host,
NotifyFrameSwapped(old_host, new_host);
}
+void WebContentsImpl::NotifyMainFrameSwappedFromRenderManager(
+ RenderViewHost* old_host,
+ RenderViewHost* new_host) {
+ NotifyViewSwapped(old_host, new_host);
+}
+
int WebContentsImpl::CreateOpenerRenderViewsForRenderManager(
SiteInstance* instance) {
if (!opener_)
@@ -4075,16 +4147,22 @@ 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, true);
+ int render_view_routing_id = MSG_ROUTING_NONE;
+ GetRenderManager()->CreateRenderFrame(instance, nullptr, opener_route_id,
+ CREATE_RF_FOR_MAIN_FRAME_NAVIGATION |
+ CREATE_RF_SWAPPED_OUT |
+ CREATE_RF_HIDDEN,
+ &render_view_routing_id);
+ return render_view_routing_id;
}
NavigationControllerImpl& WebContentsImpl::GetControllerForRenderManager() {
return GetController();
}
-WebUIImpl* WebContentsImpl::CreateWebUIForRenderManager(const GURL& url) {
- return static_cast<WebUIImpl*>(CreateWebUI(url));
+scoped_ptr<WebUIImpl> WebContentsImpl::CreateWebUIForRenderManager(
+ const GURL& url) {
+ return scoped_ptr<WebUIImpl>(static_cast<WebUIImpl*>(CreateWebUI(url)));
}
NavigationEntry*
@@ -4131,6 +4209,10 @@ bool WebContentsImpl::CreateRenderViewForRenderManager(
return false;
}
+ SetHistoryOffsetAndLengthForView(render_view_host,
+ controller_.GetLastCommittedEntryIndex(),
+ controller_.GetEntryCount());
+
#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
// Force a ViewMsg_Resize to be sent, needed to make plugins show up on
// linux. See crbug.com/83941.
@@ -4146,13 +4228,15 @@ bool WebContentsImpl::CreateRenderViewForRenderManager(
bool WebContentsImpl::CreateRenderFrameForRenderManager(
RenderFrameHost* render_frame_host,
int parent_routing_id,
+ int previous_sibling_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))
+ if (!rfh->CreateRenderFrame(parent_routing_id, previous_sibling_routing_id,
+ proxy_routing_id))
return false;
// TODO(nasko): When RenderWidgetHost is owned by RenderFrameHost, the passed
@@ -4166,7 +4250,7 @@ bool WebContentsImpl::CreateRenderFrameForRenderManager(
base::android::ScopedJavaLocalRef<jobject>
WebContentsImpl::GetJavaWebContents() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
return GetWebContentsAndroid()->GetJavaObject();
}
@@ -4213,7 +4297,7 @@ void WebContentsImpl::OnDialogClosed(int render_process_id,
// If a beforeunload dialog is canceled, we need to stop the throbber from
// spinning, since we forced it to start spinning in Navigate.
if (rfh)
- DidStopLoading(rfh);
+ DidStopLoading();
controller_.DiscardNonCommittedEntries();
FOR_EACH_OBSERVER(WebContentsObserver, observers_,
@@ -4247,10 +4331,6 @@ RenderFrameHostManager* WebContentsImpl::GetRenderManager() const {
return frame_tree_.root()->render_manager();
}
-RenderViewHostImpl* WebContentsImpl::GetRenderViewHostImpl() {
- return static_cast<RenderViewHostImpl*>(GetRenderViewHost());
-}
-
BrowserPluginGuest* WebContentsImpl::GetBrowserPluginGuest() const {
return browser_plugin_guest_.get();
}
@@ -4264,6 +4344,12 @@ BrowserPluginEmbedder* WebContentsImpl::GetBrowserPluginEmbedder() const {
return browser_plugin_embedder_.get();
}
+void WebContentsImpl::CreateBrowserPluginEmbedderIfNecessary() {
+ if (browser_plugin_embedder_)
+ return;
+ browser_plugin_embedder_.reset(BrowserPluginEmbedder::Create(this));
+}
+
void WebContentsImpl::ClearPowerSaveBlockers(
RenderFrameHost* render_frame_host) {
RemoveAllMediaPlayerEntries(render_frame_host, &active_audio_players_);
@@ -4289,7 +4375,7 @@ gfx::Size WebContentsImpl::GetSizeForNewRenderView() {
void WebContentsImpl::OnFrameRemoved(RenderFrameHost* render_frame_host) {
FOR_EACH_OBSERVER(
- WebContentsObserver, observers_, FrameDetached(render_frame_host));
+ WebContentsObserver, observers_, FrameDeleted(render_frame_host));
}
void WebContentsImpl::OnPreferredSizeChanged(const gfx::Size& old_size) {
@@ -4302,6 +4388,9 @@ void WebContentsImpl::OnPreferredSizeChanged(const gfx::Size& old_size) {
void WebContentsImpl::AddMediaPlayerEntry(int64 player_cookie,
ActiveMediaPlayerMap* player_map) {
+ if (!HasValidFrameSource())
+ return;
+
const uintptr_t key =
reinterpret_cast<uintptr_t>(render_frame_message_source_);
DCHECK(std::find((*player_map)[key].begin(),
@@ -4312,6 +4401,9 @@ void WebContentsImpl::AddMediaPlayerEntry(int64 player_cookie,
void WebContentsImpl::RemoveMediaPlayerEntry(int64 player_cookie,
ActiveMediaPlayerMap* player_map) {
+ if (!HasValidFrameSource())
+ return;
+
const uintptr_t key =
reinterpret_cast<uintptr_t>(render_frame_message_source_);
ActiveMediaPlayerMap::iterator it = player_map->find(key);
diff --git a/chromium/content/browser/web_contents/web_contents_impl.h b/chromium/content/browser/web_contents/web_contents_impl.h
index 7869292bdb0..4bc8fd108de 100644
--- a/chromium/content/browser/web_contents/web_contents_impl.h
+++ b/chromium/content/browser/web_contents/web_contents_impl.h
@@ -22,8 +22,9 @@
#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/media/audio_state_provider.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_delegate.h"
#include "content/common/accessibility_mode_enums.h"
#include "content/common/content_export.h"
@@ -38,12 +39,11 @@
#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 "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/geometry/size.h"
struct BrowserPluginHostMsg_ResizeGuest_Params;
struct ViewHostMsg_DateTimeDialogValue_Params;
-struct ViewMsg_PostMessage_Params;
namespace content {
class BrowserPluginEmbedder;
@@ -51,17 +51,15 @@ class BrowserPluginGuest;
class BrowserPluginGuestManager;
class DateTimeChooserAndroid;
class DownloadItem;
-class GeolocationDispatcherHost;
class GeolocationServiceContext;
class InterstitialPageImpl;
class JavaScriptDialogManager;
class ManifestManagerHost;
-class MidiDispatcherHost;
+class MediaWebContentsObserver;
class PluginContentOriginWhitelist;
class PowerSaveBlocker;
class RenderViewHost;
class RenderViewHostDelegateView;
-class RenderViewHostImpl;
class RenderWidgetHostImpl;
class SavePackage;
class ScreenOrientationDispatcherHost;
@@ -101,6 +99,8 @@ class CONTENT_EXPORT WebContentsImpl
public NON_EXPORTED_BASE(NavigationControllerDelegate),
public NON_EXPORTED_BASE(NavigatorDelegate) {
public:
+ class FriendZone;
+
~WebContentsImpl() override;
static WebContentsImpl* CreateWithOpener(
@@ -152,6 +152,14 @@ class CONTENT_EXPORT WebContentsImpl
// an embedder.
BrowserPluginEmbedder* GetBrowserPluginEmbedder() const;
+ // Creates a BrowserPluginEmbedder object for this WebContents if one doesn't
+ // already exist.
+ void CreateBrowserPluginEmbedderIfNecessary();
+
+ // Cancels modal dialogs in this WebContents, as well as in any browser
+ // plugins it is hosting.
+ void CancelActiveAndPendingDialogs();
+
// Gets the current fullscreen render widget's routing ID. Returns
// MSG_ROUTING_NONE when there is no fullscreen render widget.
int GetFullscreenWidgetRoutingID() const;
@@ -170,9 +178,12 @@ class CONTENT_EXPORT WebContentsImpl
// A redirect was received while requesting a resource.
void DidGetRedirectForResourceRequest(
- RenderViewHost* render_view_host,
+ RenderFrameHost* render_frame_host,
const ResourceRedirectDetails& details);
+ // Notify observers that the web contents has been focused.
+ void NotifyWebContentsFocused();
+
WebContentsView* GetView() const;
ScreenOrientationDispatcherHost* screen_orientation_dispatcher_host() {
@@ -181,6 +192,12 @@ class CONTENT_EXPORT WebContentsImpl
bool should_normally_be_visible() { return should_normally_be_visible_; }
+ // Indicate if the window has been occluded, and pass this to the views, only
+ // if there is no active capture going on (otherwise it is dropped on the
+ // floor).
+ void WasOccluded();
+ void WasUnOccluded();
+
// Broadcasts the mode change to all frames.
void SetAccessibilityMode(AccessibilityMode mode);
@@ -194,6 +211,12 @@ class CONTENT_EXPORT WebContentsImpl
// have been removed.
void RemoveAccessibilityMode(AccessibilityMode mode);
+ // Request a one-time snapshot of the accessibility tree without changing
+ // the accessibility mode.
+ typedef base::Callback<void(const ui::AXTreeUpdate&)>
+ AXTreeSnapshotCallback;
+ void RequestAXTreeSnapshot(AXTreeSnapshotCallback callback);
+
// Clear the navigation transition data when the user navigates back to Chrome
// from a native app.
void ClearNavigationTransitionData();
@@ -208,15 +231,17 @@ class CONTENT_EXPORT WebContentsImpl
const GURL& GetVisibleURL() const override;
const GURL& GetLastCommittedURL() const override;
RenderProcessHost* GetRenderProcessHost() const override;
- RenderFrameHost* GetMainFrame() override;
- RenderFrameHost* GetFocusedFrame() override;
+ RenderFrameHostImpl* GetMainFrame() override;
+ RenderFrameHostImpl* GetFocusedFrame() override;
void ForEachFrame(
const base::Callback<void(RenderFrameHost*)>& on_frame) override;
void SendToAllFrames(IPC::Message* message) override;
- RenderViewHost* GetRenderViewHost() const override;
+ RenderViewHostImpl* GetRenderViewHost() const override;
int GetRoutingID() const override;
RenderWidgetHostView* GetRenderWidgetHostView() const override;
+ void ClosePage() override;
RenderWidgetHostView* GetFullscreenRenderWidgetHostView() const override;
+ SkColor GetThemeColor() const override;
WebUI* CreateWebUI(const GURL& url) override;
WebUI* GetWebUI() const override;
WebUI* GetCommittedWebUI() const override;
@@ -226,7 +251,7 @@ class CONTENT_EXPORT WebContentsImpl
bool IsTreeOnlyAccessibilityModeForTesting() const override;
bool IsFullAccessibilityModeForTesting() const override;
#if defined(OS_WIN)
- virtual void SetParentNativeViewAccessible(
+ void SetParentNativeViewAccessible(
gfx::NativeViewAccessible accessible_parent) override;
#endif
const base::string16& GetTitle() const override;
@@ -255,6 +280,7 @@ class CONTENT_EXPORT WebContentsImpl
bool IsBeingDestroyed() const override;
void NotifyNavigationStateChanged(InvalidateTypes changed_flags) override;
base::TimeTicks GetLastActiveTime() const override;
+ void SetLastActiveTime(base::TimeTicks last_active_time) override;
void WasShown() override;
void WasHidden() override;
bool NeedToFireBeforeUnload() override;
@@ -298,6 +324,9 @@ class CONTENT_EXPORT WebContentsImpl
const base::FilePath& dir_path,
SavePageType save_type) override;
void SaveFrame(const GURL& url, const Referrer& referrer) override;
+ void SaveFrameWithHeaders(const GURL& url,
+ const Referrer& referrer,
+ const std::string& headers) override;
void GenerateMHTML(const base::FilePath& file,
const base::Callback<void(int64)>& callback) override;
const std::string& GetContentsMimeType() const override;
@@ -314,14 +343,17 @@ class CONTENT_EXPORT WebContentsImpl
void ViewFrameSource(const GURL& url, const PageState& page_state) override;
int GetMinimumZoomPercent() const override;
int GetMaximumZoomPercent() const override;
+ void ResetPageScale() override;
gfx::Size GetPreferredSize() const override;
bool GotResponseToLockMouseRequest(bool allowed) override;
bool HasOpener() const override;
+ WebContents* GetOpener() const override;
void DidChooseColorInColorChooser(SkColor color) override;
void DidEndColorChooser() override;
int DownloadImage(const GURL& url,
bool is_favicon,
uint32_t max_bitmap_size,
+ bool bypass_cache,
const ImageDownloadCallback& callback) override;
bool IsSubframe() const override;
void Find(int request_id,
@@ -331,9 +363,10 @@ class CONTENT_EXPORT WebContentsImpl
void InsertCSS(const std::string& css) override;
bool WasRecentlyAudible() override;
void GetManifest(const GetManifestCallback&) override;
+ void ExitFullscreen() override;
+ void ResumeLoadingCreatedWebContents() override;
#if defined(OS_ANDROID)
- virtual base::android::ScopedJavaLocalRef<jobject> GetJavaWebContents()
- override;
+ base::android::ScopedJavaLocalRef<jobject> GetJavaWebContents() override;
virtual WebContentsAndroid* GetWebContentsAndroid();
#elif defined(OS_MACOSX)
void SetAllowOtherViews(bool allow) override;
@@ -352,8 +385,6 @@ class CONTENT_EXPORT WebContentsImpl
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;
@@ -372,6 +403,8 @@ class CONTENT_EXPORT WebContentsImpl
bool is_reload,
IPC::Message* reply_msg) override;
void DidAccessInitialDocument() override;
+ void DidChangeName(RenderFrameHost* render_frame_host,
+ const std::string& name) override;
void DidDisownOpener(RenderFrameHost* render_frame_host) override;
void DocumentOnLoadCompleted(RenderFrameHost* render_frame_host) override;
void UpdateTitle(RenderFrameHost* render_frame_host,
@@ -386,8 +419,15 @@ class CONTENT_EXPORT WebContentsImpl
void AccessibilityEventReceived(
const std::vector<AXEventNotificationDetails>& details) override;
RenderFrameHost* GetGuestByInstanceID(
+ RenderFrameHost* render_frame_host,
int browser_plugin_instance_id) override;
GeolocationServiceContext* GetGeolocationServiceContext() override;
+ void EnterFullscreenMode(const GURL& origin) override;
+ void ExitFullscreenMode() override;
+ bool ShouldRouteMessageEvent(
+ RenderFrameHost* target_rfh,
+ SiteInstance* source_site_instance) const override;
+ int EnsureOpenerRenderViewsExist(RenderFrameHost* source_rfh) override;
#if defined(OS_WIN)
gfx::NativeViewAccessible GetParentNativeViewAccessible() override;
#endif
@@ -398,7 +438,7 @@ class CONTENT_EXPORT WebContentsImpl
const IPC::Message& message) override;
// RenderFrameHostDelegate has the same method, so list it there because this
// interface is going away.
- // virtual WebContents* GetAsWebContents() override;
+ // WebContents* GetAsWebContents() override;
gfx::Rect GetRootWindowResizerRect() const override;
void RenderViewCreated(RenderViewHost* render_view_host) override;
void RenderViewReady(RenderViewHost* render_view_host) override;
@@ -409,21 +449,19 @@ class CONTENT_EXPORT WebContentsImpl
void UpdateState(RenderViewHost* render_view_host,
int32 page_id,
const PageState& page_state) override;
- void UpdateTargetURL(const GURL& url) override;
+ void UpdateTargetURL(RenderViewHost* render_view_host,
+ 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;
@@ -435,15 +473,10 @@ class CONTENT_EXPORT WebContentsImpl
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;
+ blink::WebDisplayMode GetDisplayMode() const override;
void UpdatePreferredSize(const gfx::Size& pref_size) override;
void ResizeDueToAutoResize(const gfx::Size& new_size) override;
void RequestToLockMouse(bool user_gesture,
@@ -461,9 +494,9 @@ class CONTENT_EXPORT WebContentsImpl
void CreateNewFullscreenWidget(int render_process_id, int route_id) override;
void ShowCreatedWindow(int route_id,
WindowOpenDisposition disposition,
- const gfx::Rect& initial_pos,
+ const gfx::Rect& initial_rect,
bool user_gesture) override;
- void ShowCreatedWidget(int route_id, const gfx::Rect& initial_pos) override;
+ void ShowCreatedWidget(int route_id, const gfx::Rect& initial_rect) override;
void ShowCreatedFullscreenWidget(int route_id) override;
void RequestMediaAccessPermission(
const MediaStreamRequest& request,
@@ -474,6 +507,9 @@ class CONTENT_EXPORT WebContentsImpl
SiteInstance* instance) override;
SessionStorageNamespaceMap GetSessionStorageNamespaceMap() override;
FrameTree* GetFrameTree() override;
+ void SetIsVirtualKeyboardRequested(bool requested) override;
+ bool IsVirtualKeyboardRequested() override;
+
// NavigatorDelegate ---------------------------------------------------------
@@ -496,6 +532,7 @@ class CONTENT_EXPORT WebContentsImpl
ui::PageTransition transition_type) override;
void DidNavigateMainFramePreCommit(bool navigation_is_within_page) override;
void DidNavigateMainFramePostCommit(
+ RenderFrameHostImpl* render_frame_host,
const LoadCommittedDetails& details,
const FrameHostMsg_DidCommitProvisionalLoad_Params& params) override;
void DidNavigateAnyFramePostCommit(
@@ -506,25 +543,31 @@ class CONTENT_EXPORT WebContentsImpl
bool CanOverscrollContent() const override;
void NotifyChangedNavigationState(InvalidateTypes changed_flags) override;
void AboutToNavigateRenderFrame(
- RenderFrameHostImpl* render_frame_host) override;
+ RenderFrameHostImpl* old_host,
+ RenderFrameHostImpl* new_host) override;
void DidStartNavigationToPendingEntry(
- RenderFrameHostImpl* render_frame_host,
const GURL& url,
NavigationController::ReloadType reload_type) override;
void RequestOpenURL(RenderFrameHostImpl* render_frame_host,
const OpenURLParams& params) override;
bool ShouldPreserveAbortedURLs() override;
+ void DidStartLoading(FrameTreeNode* frame_tree_node,
+ bool to_different_document) override;
+ void DidStopLoading() override;
+ void DidChangeLoadProgress() override;
// RenderWidgetHostDelegate --------------------------------------------------
void RenderWidgetDeleted(RenderWidgetHostImpl* render_widget_host) override;
void RenderWidgetGotFocus(RenderWidgetHostImpl* render_widget_host) override;
+ void RenderWidgetWasResized(RenderWidgetHostImpl* render_widget_host,
+ bool width_changed) override;
+ void ScreenInfoChanged() 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()
@@ -539,6 +582,7 @@ class CONTENT_EXPORT WebContentsImpl
bool for_main_frame_navigation) override;
bool CreateRenderFrameForRenderManager(RenderFrameHost* render_frame_host,
int parent_routing_id,
+ int previous_sibling_routing_id,
int proxy_routing_id) override;
void BeforeUnloadFiredFromRenderManager(
bool proceed,
@@ -551,9 +595,12 @@ class CONTENT_EXPORT WebContentsImpl
void NotifySwappedFromRenderManager(RenderFrameHost* old_host,
RenderFrameHost* new_host,
bool is_main_frame) override;
+ void NotifyMainFrameSwappedFromRenderManager(
+ RenderViewHost* old_host,
+ RenderViewHost* new_host) override;
int CreateOpenerRenderViewsForRenderManager(SiteInstance* instance) override;
NavigationControllerImpl& GetControllerForRenderManager() override;
- WebUIImpl* CreateWebUIForRenderManager(const GURL& url) override;
+ scoped_ptr<WebUIImpl> CreateWebUIForRenderManager(const GURL& url) override;
NavigationEntry* GetLastCommittedNavigationEntryForRenderManager() override;
bool FocusLocationBarByDefault() override;
void SetFocusToLocationBar(bool select_all) override;
@@ -609,13 +656,10 @@ class CONTENT_EXPORT WebContentsImpl
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.
- void SetHistoryLengthAndPrune(const SiteInstance* site_instance,
- int merge_history_length,
- int32 minimum_page_id) override;
+ // Sets the history for this WebContentsImpl to |history_length| entries, with
+ // an offset of |history_offset|.
+ void SetHistoryOffsetAndLength(int history_offset,
+ int history_length) override;
// Called by InterstitialPageImpl when it creates a RenderFrameHost.
void RenderFrameForInterstitialPageCreated(
@@ -631,8 +675,7 @@ class CONTENT_EXPORT WebContentsImpl
// Changes the IsLoading state and notifies the delegate as needed.
// |details| is used to provide details on the load that just finished
// (but can be null if not applicable).
- void SetIsLoading(RenderViewHost* render_view_host,
- bool is_loading,
+ void SetIsLoading(bool is_loading,
bool to_different_document,
LoadNotificationDetails* details) override;
@@ -652,8 +695,8 @@ class CONTENT_EXPORT WebContentsImpl
// Forces overscroll to be disabled (used by touch emulation).
void SetForceDisableOverscrollContent(bool force_disable);
- AudioStreamMonitor* audio_stream_monitor() {
- return &audio_stream_monitor_;
+ AudioStateProvider* audio_state_provider() {
+ return audio_state_provider_.get();
}
bool has_audio_power_save_blocker_for_testing() const {
@@ -664,9 +707,13 @@ class CONTENT_EXPORT WebContentsImpl
return video_power_save_blocker_;
}
+#if defined(ENABLE_BROWSER_CDMS)
+ MediaWebContentsObserver* media_web_contents_observer() {
+ return media_web_contents_observer_.get();
+ }
+#endif
+
private:
- friend class TestNavigationObserver;
- friend class WebContentsAddedObserver;
friend class WebContentsObserver;
friend class WebContents; // To implement factory methods.
@@ -732,6 +779,10 @@ class CONTENT_EXPORT WebContentsImpl
RenderFrameHost* render_frame_host,
const IPC::Message& message);
+ // Checks whether render_frame_message_source_ is set to non-null value,
+ // otherwise it terminates the main frame renderer process.
+ bool HasValidFrameSource();
+
// IPC message handlers.
void OnThemeColorChanged(SkColor theme_color);
void OnDidLoadResourceFromMemoryCache(const GURL& url,
@@ -744,9 +795,6 @@ class CONTENT_EXPORT WebContentsImpl
const GURL& target_url);
void OnDocumentLoadedInFrame();
void OnDidFinishLoad(const GURL& url);
- void OnDidStartLoading(bool to_different_document);
- void OnDidStopLoading();
- void OnDidChangeLoadProgress(double load_progress);
void OnGoToEntryAtOffset(int offset);
void OnUpdateZoomLimits(int minimum_percent,
int maximum_percent);
@@ -797,7 +845,8 @@ class CONTENT_EXPORT WebContentsImpl
// |result| is true if permission was granted.
void OnPpapiBrokerPermissionResult(int routing_id, bool result);
- void OnBrowserPluginMessage(const IPC::Message& message);
+ void OnBrowserPluginMessage(RenderFrameHost* render_frame_host,
+ const IPC::Message& message);
#endif // defined(ENABLE_PLUGINS)
void OnDidDownloadImage(int id,
int http_status_code,
@@ -863,7 +912,7 @@ class CONTENT_EXPORT WebContentsImpl
// Helper for ShowCreatedWidget/ShowCreatedFullscreenWidget.
void ShowCreatedWidget(int route_id,
bool is_fullscreen,
- const gfx::Rect& initial_pos);
+ const gfx::Rect& initial_rect);
// Finds the new RenderWidgetHost and returns it. Note that this can only be
// called once as this call also removes it from the internal map.
@@ -876,17 +925,20 @@ class CONTENT_EXPORT WebContentsImpl
// Tracking loading progress -------------------------------------------------
- // Resets the tracking state of the current load.
+ // Resets the tracking state of the current load progress.
void ResetLoadProgressState();
- // Calculates the progress of the current load and notifies the delegate.
- void SendLoadProgressChanged();
-
- // Called once when the last frame on the page has stopped loading.
- void DidStopLoading(RenderFrameHost* render_frame_host);
+ // Notifies the delegate that the load progress was updated.
+ void SendChangeLoadProgress();
// Misc non-view stuff -------------------------------------------------------
+ // Sets the history for a specified RenderViewHost to |history_length|
+ // entries, with an offset of |history_offset|.
+ void SetHistoryOffsetAndLengthForView(RenderViewHost* render_view_host,
+ int history_offset,
+ int history_length);
+
// Helper functions for sending notifications.
void NotifyViewSwapped(RenderViewHost* old_host, RenderViewHost* new_host);
void NotifyFrameSwapped(RenderFrameHost* old_host, RenderFrameHost* new_host);
@@ -898,8 +950,6 @@ class CONTENT_EXPORT WebContentsImpl
// render manager to return. For now, we just return the root's.
RenderFrameHostManager* GetRenderManager() const;
- RenderViewHostImpl* GetRenderViewHostImpl();
-
// Removes browser plugin embedder if there is one.
void RemoveBrowserPluginEmbedder();
@@ -941,11 +991,6 @@ class CONTENT_EXPORT WebContentsImpl
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);
- static void RemoveCreatedCallback(const CreatedCallback& callback);
-
// Data for core operation ---------------------------------------------------
// Delegate for notifying our owner about stuff. Not owned by us.
@@ -1001,6 +1046,11 @@ class CONTENT_EXPORT WebContentsImpl
scoped_ptr<PowerSaveBlocker> audio_power_save_blocker_;
scoped_ptr<PowerSaveBlocker> video_power_save_blocker_;
+ // Tells whether this WebContents is actively producing sound.
+ // Order is important: the |frame_tree_| destruction uses
+ // |audio_state_provider_|.
+ scoped_ptr<AudioStateProvider> audio_state_provider_;
+
// Manages the frame tree of the page and process swaps in each node.
FrameTree frame_tree_;
@@ -1034,18 +1084,8 @@ class CONTENT_EXPORT WebContentsImpl
net::LoadStateWithParam load_state_;
base::string16 load_state_host_;
- // LoadingProgressMap maps FrameTreeNode IDs to a double representing that
- // frame's completion (from 0 to 1).
- typedef base::hash_map<int64, double> LoadingProgressMap;
- LoadingProgressMap loading_progresses_;
- double loading_total_progress_;
-
base::TimeTicks loading_last_progress_update_;
- // Counter to track how many frames have sent start notifications but not
- // stop notifications.
- int loading_frames_in_progress_;
-
// Upload progress, for displaying in the status bar.
// Set to zero when there is no significant upload happening.
uint64 upload_size_;
@@ -1074,6 +1114,13 @@ class CONTENT_EXPORT WebContentsImpl
// to modify the blank page. Always false after the first commit.
bool has_accessed_initial_document_;
+ // The theme color for the underlying document as specified
+ // by theme-color meta tag.
+ SkColor theme_color_;
+
+ // The last published theme color.
+ SkColor last_sent_theme_color_;
+
// Data for misc internal state ----------------------------------------------
// When > 0, the WebContents is currently being captured (e.g., for
@@ -1116,11 +1163,6 @@ class CONTENT_EXPORT WebContentsImpl
int minimum_zoom_percent_;
int maximum_zoom_percent_;
- // The raw accumulated zoom value and the actual zoom increments made for an
- // an in-progress pinch gesture.
- float totalPinchGestureAmount_;
- int currentPinchZoomStepDelta_;
-
// The intrinsic size of the page.
gfx::Size preferred_size_;
@@ -1211,10 +1253,6 @@ class CONTENT_EXPORT WebContentsImpl
scoped_ptr<GeolocationServiceContext> geolocation_service_context_;
- scoped_ptr<GeolocationDispatcherHost> geolocation_dispatcher_host_;
-
- scoped_ptr<MidiDispatcherHost> midi_dispatcher_host_;
-
scoped_ptr<ScreenOrientationDispatcherHost>
screen_orientation_dispatcher_host_;
@@ -1224,17 +1262,38 @@ class CONTENT_EXPORT WebContentsImpl
// 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_;
+ bool virtual_keyboard_requested_;
+
+#if defined(ENABLE_BROWSER_CDMS)
+ // Manages all the media player and CDM managers and forwards IPCs to them.
+ scoped_ptr<MediaWebContentsObserver> media_web_contents_observer_;
+#endif
+
base::WeakPtrFactory<WebContentsImpl> loading_weak_factory_;
DISALLOW_COPY_AND_ASSIGN(WebContentsImpl);
};
+// Dangerous methods which should never be made part of the public API, so we
+// grant their use only to an explicit friend list (c++ attorney/client idiom).
+class CONTENT_EXPORT WebContentsImpl::FriendZone {
+ private:
+ friend class TestNavigationObserver;
+ friend class WebContentsAddedObserver;
+ friend class ContentBrowserSanityChecker;
+
+ FriendZone(); // Not instantiable.
+
+ // Adds/removes a callback called on creation of each new WebContents.
+ static void AddCreatedCallbackForTesting(const CreatedCallback& callback);
+ static void RemoveCreatedCallbackForTesting(const CreatedCallback& callback);
+
+ DISALLOW_COPY_AND_ASSIGN(FriendZone);
+};
+
} // namespace content
#endif // CONTENT_BROWSER_WEB_CONTENTS_WEB_CONTENTS_IMPL_H_
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 349af0e73e5..a343fa4fe27 100644
--- a/chromium/content/browser/web_contents/web_contents_impl_browsertest.cc
+++ b/chromium/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -5,8 +5,10 @@
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "content/browser/frame_host/navigation_entry_impl.h"
+#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/browser/web_contents/web_contents_view.h"
+#include "content/common/frame_messages.h"
#include "content/public/browser/load_notification_details.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/notification_details.h"
@@ -19,6 +21,7 @@
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
+#include "content/public/test/test_navigation_observer.h"
#include "content/public/test/test_utils.h"
#include "content/shell/browser/shell.h"
#include "net/dns/mock_host_resolver.h"
@@ -48,6 +51,10 @@ void ResizeWebContentsView(Shell* shell, const gfx::Size& size,
class WebContentsImplBrowserTest : public ContentBrowserTest {
public:
WebContentsImplBrowserTest() {}
+ void SetUp() override {
+ RenderWidgetHostImpl::DisableResizeAckCheckForTesting();
+ ContentBrowserTest::SetUp();
+ }
private:
DISALLOW_COPY_AND_ASSIGN(WebContentsImplBrowserTest);
@@ -177,7 +184,7 @@ class LoadingStateChangedDelegate : public WebContentsDelegate {
};
// See: http://crbug.com/298193
-#if defined(OS_WIN)
+#if defined(OS_WIN) || defined(OS_LINUX)
#define MAYBE_DidStopLoadingDetails DISABLED_DidStopLoadingDetails
#else
#define MAYBE_DidStopLoadingDetails DidStopLoadingDetails
@@ -200,7 +207,7 @@ IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
}
// See: http://crbug.com/298193
-#if defined(OS_WIN)
+#if defined(OS_WIN) || defined(OS_LINUX)
#define MAYBE_DidStopLoadingDetailsWithPending \
DISABLED_DidStopLoadingDetailsWithPending
#else
@@ -345,7 +352,7 @@ IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, OpenURLSubframe) {
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();
+ int 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.
@@ -400,7 +407,7 @@ class RenderFrameCreatedObserver : public WebContentsObserver {
// to the WebContentObservers. See http://crbug.com/347339.
IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
RenderFrameCreatedCorrectProcessForObservers) {
- std::string foo_com("foo.com");
+ static const char kFooCom[] = "foo.com";
GURL::Replacements replace_host;
net::HostPortPair foo_host_port;
GURL cross_site_url;
@@ -411,12 +418,12 @@ IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
ASSERT_TRUE(test_server()->Start());
foo_host_port = test_server()->host_port_pair();
- foo_host_port.set_host(foo_com);
+ foo_host_port.set_host(kFooCom);
GURL initial_url(test_server()->GetURL("/title1.html"));
cross_site_url = test_server()->GetURL("/title2.html");
- replace_host.SetHostStr(foo_com);
+ replace_host.SetHostStr(kFooCom);
cross_site_url = cross_site_url.ReplaceComponents(replace_host);
// Navigate to the initial URL and capture the RenderFrameHost for later
@@ -454,7 +461,7 @@ IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
// initial load of push_state.html, and start and stop for the "navigation"
// triggered by history.pushState(). However, the start notification for the
// history.pushState() navigation should set to_different_document to false.
- EXPECT_EQ("pushState", shell()->web_contents()->GetURL().ref());
+ EXPECT_EQ("pushState", shell()->web_contents()->GetLastCommittedURL().ref());
EXPECT_EQ(4, delegate->loadingStateChangedCount());
EXPECT_EQ(3, delegate->loadingStateToDifferentDocumentCount());
}
@@ -495,14 +502,14 @@ struct LoadProgressDelegateAndObserver : public WebContentsDelegate,
}
// WebContentsObserver:
- void DidStartLoading(RenderViewHost* render_view_host) override {
+ void DidStartLoading() override {
EXPECT_FALSE(did_start_loading);
EXPECT_EQ(0U, progresses.size());
EXPECT_FALSE(did_stop_loading);
did_start_loading = true;
}
- void DidStopLoading(RenderViewHost* render_view_host) override {
+ void DidStopLoading() override {
EXPECT_TRUE(did_start_loading);
EXPECT_GE(progresses.size(), 1U);
EXPECT_FALSE(did_stop_loading);
@@ -536,6 +543,67 @@ IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, LoadProgress) {
EXPECT_EQ(1.0, *progresses.rbegin());
}
+IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, LoadProgressWithFrames) {
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+ scoped_ptr<LoadProgressDelegateAndObserver> delegate(
+ new LoadProgressDelegateAndObserver(shell()));
+
+ NavigateToURL(shell(),
+ embedded_test_server()->GetURL("/frame_tree/top.html"));
+
+ const std::vector<double>& progresses = delegate->progresses;
+ // All updates should be in order ...
+ if (std::adjacent_find(progresses.begin(),
+ progresses.end(),
+ std::greater<double>()) != progresses.end()) {
+ ADD_FAILURE() << "Progress values should be in order: "
+ << ::testing::PrintToString(progresses);
+ }
+
+ // ... and the last one should be 1.0, meaning complete.
+ ASSERT_GE(progresses.size(), 1U)
+ << "There should be at least one progress update";
+ EXPECT_EQ(1.0, *progresses.rbegin());
+}
+
+// Ensure that a new navigation that interrupts a pending one will still fire
+// a DidStopLoading. See http://crbug.com/429399.
+IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
+ LoadProgressAfterInterruptedNav) {
+ host_resolver()->AddRule("*", "127.0.0.1");
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
+ // Start at a real page.
+ NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
+
+ // Simulate a navigation that has not completed.
+ scoped_ptr<LoadProgressDelegateAndObserver> delegate(
+ new LoadProgressDelegateAndObserver(shell()));
+ RenderFrameHost* main_frame = shell()->web_contents()->GetMainFrame();
+ FrameHostMsg_DidStartLoading start_msg(main_frame->GetRoutingID(), true);
+ static_cast<RenderFrameHostImpl*>(main_frame)->OnMessageReceived(start_msg);
+ EXPECT_TRUE(delegate->did_start_loading);
+ EXPECT_FALSE(delegate->did_stop_loading);
+
+ // Also simulate a DidChangeLoadProgress, but not a DidStopLoading.
+ FrameHostMsg_DidChangeLoadProgress progress_msg(main_frame->GetRoutingID(),
+ 1.0);
+ static_cast<RenderFrameHostImpl*>(main_frame)->OnMessageReceived(
+ progress_msg);
+ EXPECT_TRUE(delegate->did_start_loading);
+ EXPECT_FALSE(delegate->did_stop_loading);
+
+ // Now interrupt with a new cross-process navigation.
+ TestNavigationObserver tab_observer(shell()->web_contents(), 1);
+ GURL url(embedded_test_server()->GetURL("foo.com", "/title2.html"));
+ shell()->LoadURL(url);
+ tab_observer.Wait();
+ EXPECT_EQ(url, shell()->web_contents()->GetLastCommittedURL());
+
+ // We should have gotten to DidStopLoading.
+ EXPECT_TRUE(delegate->did_stop_loading);
+}
+
struct FirstVisuallyNonEmptyPaintObserver : public WebContentsObserver {
FirstVisuallyNonEmptyPaintObserver(Shell* shell)
: WebContentsObserver(shell->web_contents()),
@@ -577,5 +645,94 @@ IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
ASSERT_TRUE(observer->did_fist_visually_non_empty_paint_);
}
-} // namespace content
+namespace {
+class WebDisplayModeDelegate : public WebContentsDelegate {
+ public:
+ explicit WebDisplayModeDelegate(blink::WebDisplayMode mode) : mode_(mode) { }
+ ~WebDisplayModeDelegate() override { }
+
+ blink::WebDisplayMode GetDisplayMode(
+ const WebContents* source) const override { return mode_; }
+ void set_mode(blink::WebDisplayMode mode) { mode_ = mode; }
+ private:
+ blink::WebDisplayMode mode_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebDisplayModeDelegate);
+};
+
+}
+
+IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, ChangeDisplayMode) {
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+ WebDisplayModeDelegate delegate(blink::WebDisplayModeMinimalUi);
+ shell()->web_contents()->SetDelegate(&delegate);
+
+ NavigateToURL(shell(), GURL("about://blank"));
+
+ ASSERT_TRUE(ExecuteScript(shell()->web_contents(),
+ "document.title = "
+ " window.matchMedia('(display-mode:"
+ " minimal-ui)').matches"));
+ EXPECT_EQ(base::ASCIIToUTF16("true"), shell()->web_contents()->GetTitle());
+
+ delegate.set_mode(blink::WebDisplayModeFullscreen);
+ // Simulate widget is entering fullscreen (changing size is enough).
+ shell()->web_contents()->GetRenderViewHost()->WasResized();
+
+ ASSERT_TRUE(ExecuteScript(shell()->web_contents(),
+ "document.title = "
+ " window.matchMedia('(display-mode:"
+ " fullscreen)').matches"));
+ EXPECT_EQ(base::ASCIIToUTF16("true"), shell()->web_contents()->GetTitle());
+}
+
+IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, NewNamedWindow) {
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
+ GURL url = embedded_test_server()->GetURL("/click-noreferrer-links.html");
+ EXPECT_TRUE(NavigateToURL(shell(), url));
+
+ {
+ ShellAddedObserver new_shell_observer;
+
+ // Open a new, named window.
+ EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
+ "window.open('about:blank','new_window');"));
+
+ Shell* new_shell = new_shell_observer.GetShell();
+ WaitForLoadStop(new_shell->web_contents());
+
+ EXPECT_EQ("new_window",
+ static_cast<WebContentsImpl*>(new_shell->web_contents())
+ ->GetFrameTree()->root()->frame_name());
+
+ bool success = false;
+ EXPECT_TRUE(ExecuteScriptAndExtractBool(
+ new_shell->web_contents(),
+ "window.domAutomationController.send(window.name == 'new_window');",
+ &success));
+ EXPECT_TRUE(success);
+ }
+
+ {
+ ShellAddedObserver new_shell_observer;
+
+ // Test clicking a target=foo link.
+ bool success = false;
+ EXPECT_TRUE(ExecuteScriptAndExtractBool(
+ shell()->web_contents(),
+ "window.domAutomationController.send(clickSameSiteTargetedLink());",
+ &success));
+ EXPECT_TRUE(success);
+
+ Shell* new_shell = new_shell_observer.GetShell();
+ WaitForLoadStop(new_shell->web_contents());
+
+ EXPECT_EQ("foo",
+ static_cast<WebContentsImpl*>(new_shell->web_contents())
+ ->GetFrameTree()->root()->frame_name());
+ }
+}
+
+} // 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 a361553dd25..6a3f6e0174b 100644
--- a/chromium/content/browser/web_contents/web_contents_impl_unittest.cc
+++ b/chromium/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -2,14 +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/logging.h"
#include "base/strings/utf_string_conversions.h"
#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/frame_host/render_frame_host_impl.h"
+#include "content/browser/media/audio_state_provider.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/site_instance_impl.h"
+#include "content/browser/webui/content_web_ui_controller_factory.h"
#include "content/browser/webui/web_ui_controller_factory_registry.h"
#include "content/common/frame_messages.h"
#include "content/common/input/synthetic_web_input_event_builders.h"
@@ -25,6 +28,7 @@
#include "content/public/browser/web_ui_controller.h"
#include "content/public/common/bindings_policy.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 "content/public/test/mock_render_process_host.h"
@@ -39,39 +43,6 @@
namespace content {
namespace {
-const char kTestWebUIUrl[] = "chrome://blah";
-
-class WebContentsImplTestWebUIControllerFactory
- : public WebUIControllerFactory {
- public:
- WebUIController* CreateWebUIControllerForURL(WebUI* web_ui,
- const GURL& url) const override {
- if (!UseWebUI(url))
- return NULL;
- return new WebUIController(web_ui);
- }
-
- WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
- const GURL& url) const override {
- return WebUI::kNoWebUI;
- }
-
- bool UseWebUIForURL(BrowserContext* browser_context,
- const GURL& url) const override {
- return UseWebUI(url);
- }
-
- bool UseWebUIBindingsForURL(BrowserContext* browser_context,
- const GURL& url) const override {
- return UseWebUI(url);
- }
-
- private:
- bool UseWebUI(const GURL& url) const {
- return url == GURL(kTestWebUIUrl);
- }
-};
-
class TestInterstitialPage;
class TestInterstitialPageDelegate : public InterstitialPageDelegate {
@@ -126,7 +97,7 @@ class TestInterstitialPage : public InterstitialPageImpl {
state_(state),
deleted_(deleted),
command_received_count_(0),
- delegate_(NULL) {
+ delegate_(nullptr) {
*state_ = UNDECIDED;
*deleted_ = false;
}
@@ -156,26 +127,31 @@ class TestInterstitialPage : public InterstitialPageImpl {
CommandReceived();
}
- void TestDidNavigate(int page_id, const GURL& url) {
+ void TestDidNavigate(int page_id,
+ int nav_entry_id,
+ bool did_create_new_entry,
+ const GURL& url) {
FrameHostMsg_DidCommitProvisionalLoad_Params params;
- InitNavigateParams(&params, page_id, url, ui::PAGE_TRANSITION_TYPED);
- DidNavigate(GetRenderViewHostForTesting(), params);
+ InitNavigateParams(&params, page_id, nav_entry_id, did_create_new_entry,
+ url, ui::PAGE_TRANSITION_TYPED);
+ DidNavigate(GetMainFrame()->GetRenderViewHost(), params);
}
void TestRenderViewTerminated(base::TerminationStatus status,
int error_code) {
- RenderViewTerminated(GetRenderViewHostForTesting(), status, error_code);
+ RenderViewTerminated(GetMainFrame()->GetRenderViewHost(), status,
+ error_code);
}
bool is_showing() const {
return static_cast<TestRenderWidgetHostView*>(
- GetRenderViewHostForTesting()->GetView())->is_showing();
+ GetMainFrame()->GetRenderViewHost()->GetView())->is_showing();
}
void ClearStates() {
- state_ = NULL;
- deleted_ = NULL;
- delegate_ = NULL;
+ state_ = nullptr;
+ deleted_ = nullptr;
+ delegate_ = nullptr;
}
void CommandReceived() {
@@ -187,7 +163,7 @@ class TestInterstitialPage : public InterstitialPageImpl {
}
protected:
- WebContentsView* CreateWebContentsView() override { return NULL; }
+ WebContentsView* CreateWebContentsView() override { return nullptr; }
private:
InterstitialState* state_;
@@ -224,7 +200,7 @@ class TestInterstitialPageStateGuard : public TestInterstitialPage::Delegate {
void TestInterstitialPageDeleted(
TestInterstitialPage* interstitial) override {
DCHECK(interstitial_page_ == interstitial);
- interstitial_page_ = NULL;
+ interstitial_page_ = nullptr;
}
private:
@@ -254,16 +230,15 @@ class WebContentsImplTest : public RenderViewHostImplTestHarness {
public:
void SetUp() override {
RenderViewHostImplTestHarness::SetUp();
- WebUIControllerFactory::RegisterFactory(&factory_);
+ WebUIControllerFactory::RegisterFactory(
+ ContentWebUIControllerFactory::GetInstance());
}
void TearDown() override {
- WebUIControllerFactory::UnregisterFactoryForTesting(&factory_);
+ WebUIControllerFactory::UnregisterFactoryForTesting(
+ ContentWebUIControllerFactory::GetInstance());
RenderViewHostImplTestHarness::TearDown();
}
-
- private:
- WebContentsImplTestWebUIControllerFactory factory_;
};
class TestWebContentsObserver : public WebContentsObserver {
@@ -296,12 +271,16 @@ class TestWebContentsObserver : public WebContentsObserver {
// a fullscreened state.
class FakeFullscreenDelegate : public WebContentsDelegate {
public:
- FakeFullscreenDelegate() : fullscreened_contents_(NULL) {}
+ FakeFullscreenDelegate() : fullscreened_contents_(nullptr) {}
~FakeFullscreenDelegate() override {}
- void ToggleFullscreenModeForTab(WebContents* web_contents,
- bool enter_fullscreen) override {
- fullscreened_contents_ = enter_fullscreen ? web_contents : NULL;
+ void EnterFullscreenModeForTab(WebContents* web_contents,
+ const GURL& origin) override {
+ fullscreened_contents_ = web_contents;
+ }
+
+ void ExitFullscreenModeForTab(WebContents* web_contents) override {
+ fullscreened_contents_ = nullptr;
}
bool IsFullscreenForTabOrPending(
@@ -342,8 +321,8 @@ TEST_F(WebContentsImplTest, UpdateTitle) {
NavigationControllerImpl& cont =
static_cast<NavigationControllerImpl&>(controller());
FrameHostMsg_DidCommitProvisionalLoad_Params params;
- InitNavigateParams(
- &params, 0, GURL(url::kAboutBlankURL), ui::PAGE_TRANSITION_TYPED);
+ InitNavigateParams(&params, 0, 0, true, GURL(url::kAboutBlankURL),
+ ui::PAGE_TRANSITION_TYPED);
LoadCommittedDetails details;
cont.RendererDidNavigate(contents()->GetMainFrame(), params, &details);
@@ -385,13 +364,15 @@ TEST_F(WebContentsImplTest, NTPViewSource) {
cont.LoadURL(
kGURL, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ int entry_id = cont.GetPendingEntry()->GetUniqueID();
rvh()->GetDelegate()->RenderViewCreated(rvh());
// Did we get the expected message?
EXPECT_TRUE(process()->sink().GetFirstMessageMatching(
ViewMsg_EnableViewSourceMode::ID));
FrameHostMsg_DidCommitProvisionalLoad_Params params;
- InitNavigateParams(&params, 0, kGURL, ui::PAGE_TRANSITION_TYPED);
+ InitNavigateParams(&params, 0, entry_id, true, kGURL,
+ ui::PAGE_TRANSITION_TYPED);
LoadCommittedDetails details;
cont.RendererDidNavigate(contents()->GetMainFrame(), params, &details);
// Also check title and url.
@@ -401,7 +382,7 @@ TEST_F(WebContentsImplTest, NTPViewSource) {
// Test to ensure UpdateMaxPageID is working properly.
TEST_F(WebContentsImplTest, UpdateMaxPageID) {
SiteInstance* instance1 = contents()->GetSiteInstance();
- scoped_refptr<SiteInstance> instance2(SiteInstance::Create(NULL));
+ scoped_refptr<SiteInstance> instance2(SiteInstance::Create(nullptr));
// Starts at -1.
EXPECT_EQ(-1, contents()->GetMaxPageID());
@@ -425,23 +406,27 @@ TEST_F(WebContentsImplTest, UpdateMaxPageID) {
TEST_F(WebContentsImplTest, SimpleNavigation) {
TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
SiteInstance* instance1 = contents()->GetSiteInstance();
- EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL);
+ EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
// Navigate to URL
const GURL url("http://www.google.com");
controller().LoadURL(
url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- EXPECT_FALSE(contents()->cross_navigation_pending());
+ int entry_id = controller().GetPendingEntry()->GetUniqueID();
+ main_test_rfh()->PrepareForCommit();
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
EXPECT_EQ(instance1, orig_rfh->GetSiteInstance());
- // Controller's pending entry will have a NULL site instance until we assign
+ // Controller's pending entry will have a null site instance until we assign
// it in DidNavigate.
- EXPECT_TRUE(
+ EXPECT_EQ(
+ nullptr,
NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
- site_instance() == NULL);
+ site_instance());
// DidNavigate from the page
- contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
- EXPECT_FALSE(contents()->cross_navigation_pending());
+ contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, url,
+ ui::PAGE_TRANSITION_TYPED);
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
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
@@ -460,7 +445,7 @@ TEST_F(WebContentsImplTest, NavigateToExcessivelyLongURL) {
controller().LoadURL(
url, Referrer(), ui::PAGE_TRANSITION_GENERATED, std::string());
- EXPECT_TRUE(controller().GetVisibleEntry() == NULL);
+ EXPECT_EQ(nullptr, controller().GetVisibleEntry());
}
// Test that navigating across a site boundary creates a new RenderViewHost
@@ -475,13 +460,16 @@ TEST_F(WebContentsImplTest, CrossSiteBoundaries) {
const GURL url("http://www.google.com");
controller().LoadURL(
url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
+ int entry_id = controller().GetPendingEntry()->GetUniqueID();
+ orig_rfh->PrepareForCommit();
+ contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, url,
+ ui::PAGE_TRANSITION_TYPED);
// 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_FALSE(contents()->CrossProcessNavigationPending());
EXPECT_EQ(orig_rfh->GetRenderViewHost(), contents()->GetRenderViewHost());
EXPECT_EQ(url, contents()->GetLastCommittedURL());
EXPECT_EQ(url, contents()->GetVisibleURL());
@@ -490,7 +478,12 @@ TEST_F(WebContentsImplTest, CrossSiteBoundaries) {
const GURL url2("http://www.yahoo.com");
controller().LoadURL(
url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- EXPECT_TRUE(contents()->cross_navigation_pending());
+ entry_id = controller().GetPendingEntry()->GetUniqueID();
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation)) {
+ orig_rfh->PrepareForCommit();
+ }
+ EXPECT_TRUE(contents()->CrossProcessNavigationPending());
EXPECT_EQ(url, contents()->GetLastCommittedURL());
EXPECT_EQ(url2, contents()->GetVisibleURL());
TestRenderFrameHost* pending_rfh = contents()->GetPendingMainFrame();
@@ -499,13 +492,16 @@ TEST_F(WebContentsImplTest, CrossSiteBoundaries) {
&pending_rvh_delete_count);
// 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());
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation)) {
+ 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_rfh, 1, url2, ui::PAGE_TRANSITION_TYPED);
+ contents()->TestDidNavigate(pending_rfh, 1, entry_id, true, url2,
+ ui::PAGE_TRANSITION_TYPED);
SiteInstance* instance2 = contents()->GetSiteInstance();
// Keep the number of active frames in pending_rfh's SiteInstance
@@ -513,12 +509,12 @@ TEST_F(WebContentsImplTest, CrossSiteBoundaries) {
// swapped out.
pending_rfh->GetSiteInstance()->increment_active_frame_count();
- EXPECT_FALSE(contents()->cross_navigation_pending());
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
EXPECT_EQ(pending_rfh, contents()->GetMainFrame());
EXPECT_EQ(url2, contents()->GetLastCommittedURL());
EXPECT_EQ(url2, contents()->GetVisibleURL());
EXPECT_NE(instance1, instance2);
- EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL);
+ EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
// We keep the original RFH around, swapped out.
EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
orig_rfh));
@@ -528,18 +524,27 @@ TEST_F(WebContentsImplTest, CrossSiteBoundaries) {
// stored in the NavigationEntry, so it should be the same as at the start.
// We should use the same RFH as before, swapping it back in.
controller().GoBack();
+ entry_id = controller().GetPendingEntry()->GetUniqueID();
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation)) {
+ contents()->GetMainFrame()->PrepareForCommit();
+ }
TestRenderFrameHost* goback_rfh = contents()->GetPendingMainFrame();
EXPECT_EQ(orig_rfh, goback_rfh);
- EXPECT_TRUE(contents()->cross_navigation_pending());
+ EXPECT_TRUE(contents()->CrossProcessNavigationPending());
// 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());
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation)) {
+ 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_rfh, 1, url2, ui::PAGE_TRANSITION_TYPED);
- EXPECT_FALSE(contents()->cross_navigation_pending());
+ contents()->TestDidNavigate(goback_rfh, 1, entry_id, false, url2,
+ ui::PAGE_TRANSITION_TYPED);
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
EXPECT_EQ(goback_rfh, contents()->GetMainFrame());
EXPECT_EQ(instance1, contents()->GetSiteInstance());
// The pending RFH should now be swapped out, not deleted.
@@ -567,33 +572,40 @@ TEST_F(WebContentsImplTest, CrossSiteBoundariesAfterCrash) {
const GURL url("http://www.google.com");
controller().LoadURL(
url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
+ int entry_id = controller().GetPendingEntry()->GetUniqueID();
+ contents()->GetMainFrame()->PrepareForCommit();
+ contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, url,
+ ui::PAGE_TRANSITION_TYPED);
- EXPECT_FALSE(contents()->cross_navigation_pending());
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
EXPECT_EQ(orig_rfh->GetRenderViewHost(), contents()->GetRenderViewHost());
// Simulate a renderer crash.
- orig_rfh->GetRenderViewHost()->set_render_view_created(false);
- orig_rfh->set_render_frame_created(false);
+ EXPECT_TRUE(orig_rfh->IsRenderFrameLive());
+ orig_rfh->GetProcess()->SimulateCrash();
+ EXPECT_FALSE(orig_rfh->IsRenderFrameLive());
// Navigate to new site. We should not go into PENDING.
const GURL url2("http://www.yahoo.com");
controller().LoadURL(
url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ entry_id = controller().GetPendingEntry()->GetUniqueID();
+ contents()->GetMainFrame()->PrepareForCommit();
TestRenderFrameHost* new_rfh = contents()->GetMainFrame();
- EXPECT_FALSE(contents()->cross_navigation_pending());
- EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL);
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
+ EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
EXPECT_NE(orig_rfh, new_rfh);
EXPECT_EQ(orig_rvh_delete_count, 1);
// DidNavigate from the new page
- contents()->TestDidNavigate(new_rfh, 1, url2, ui::PAGE_TRANSITION_TYPED);
+ contents()->TestDidNavigate(new_rfh, 1, entry_id, true, url2,
+ ui::PAGE_TRANSITION_TYPED);
SiteInstance* instance2 = contents()->GetSiteInstance();
- EXPECT_FALSE(contents()->cross_navigation_pending());
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
EXPECT_EQ(new_rfh, main_rfh());
EXPECT_NE(instance1, instance2);
- EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL);
+ EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
// Close contents and ensure RVHs are deleted.
DeleteContents();
@@ -611,7 +623,10 @@ TEST_F(WebContentsImplTest, NavigateTwoTabsCrossSite) {
const GURL url("http://www.google.com");
controller().LoadURL(
url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
+ int entry_id = controller().GetPendingEntry()->GetUniqueID();
+ contents()->GetMainFrame()->PrepareForCommit();
+ contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, url,
+ ui::PAGE_TRANSITION_TYPED);
// Open a new contents with the same SiteInstance, navigated to the same site.
scoped_ptr<TestWebContents> contents2(
@@ -619,19 +634,22 @@ TEST_F(WebContentsImplTest, NavigateTwoTabsCrossSite) {
contents2->GetController().LoadURL(url, Referrer(),
ui::PAGE_TRANSITION_TYPED,
std::string());
+ entry_id = contents2->GetController().GetPendingEntry()->GetUniqueID();
+ contents2->GetMainFrame()->PrepareForCommit();
// 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->GetMainFrame(), 2, url, ui::PAGE_TRANSITION_TYPED);
+ contents2->TestDidNavigate(contents2->GetMainFrame(), 2, entry_id, true, url,
+ ui::PAGE_TRANSITION_TYPED);
// Navigate first contents to a new site.
const GURL url2a("http://www.yahoo.com");
controller().LoadURL(
url2a, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- orig_rfh->SendBeforeUnloadACK(true);
+ entry_id = controller().GetPendingEntry()->GetUniqueID();
+ orig_rfh->PrepareForCommit();
TestRenderFrameHost* pending_rfh_a = contents()->GetPendingMainFrame();
- contents()->TestDidNavigate(
- pending_rfh_a, 1, url2a, ui::PAGE_TRANSITION_TYPED);
+ contents()->TestDidNavigate(pending_rfh_a, 1, entry_id, true, url2a,
+ ui::PAGE_TRANSITION_TYPED);
SiteInstance* instance2a = contents()->GetSiteInstance();
EXPECT_NE(instance1, instance2a);
@@ -640,17 +658,18 @@ TEST_F(WebContentsImplTest, NavigateTwoTabsCrossSite) {
contents2->GetController().LoadURL(url2b, Referrer(),
ui::PAGE_TRANSITION_TYPED,
std::string());
+ entry_id = contents2->GetController().GetPendingEntry()->GetUniqueID();
TestRenderFrameHost* rfh2 = contents2->GetMainFrame();
- rfh2->SendBeforeUnloadACK(true);
+ rfh2->PrepareForCommit();
TestRenderFrameHost* pending_rfh_b = contents2->GetPendingMainFrame();
- EXPECT_TRUE(pending_rfh_b != NULL);
- EXPECT_TRUE(contents2->cross_navigation_pending());
+ EXPECT_NE(nullptr, pending_rfh_b);
+ EXPECT_TRUE(contents2->CrossProcessNavigationPending());
// 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_rfh_b, 2, url2b, ui::PAGE_TRANSITION_TYPED);
+ contents2->TestDidNavigate(pending_rfh_b, 2, entry_id, true, url2b,
+ ui::PAGE_TRANSITION_TYPED);
SiteInstance* instance2b = contents2->GetSiteInstance();
EXPECT_NE(instance1, instance2b);
@@ -676,10 +695,12 @@ TEST_F(WebContentsImplTest, NavigateFromSitelessUrl) {
const GURL native_url("non-site-url://stuffandthings");
controller().LoadURL(
native_url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- contents()->TestDidNavigate(
- orig_rfh, 1, native_url, ui::PAGE_TRANSITION_TYPED);
+ int entry_id = controller().GetPendingEntry()->GetUniqueID();
+ contents()->GetMainFrame()->PrepareForCommit();
+ contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, native_url,
+ ui::PAGE_TRANSITION_TYPED);
- EXPECT_FALSE(contents()->cross_navigation_pending());
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
EXPECT_EQ(native_url, contents()->GetLastCommittedURL());
EXPECT_EQ(native_url, contents()->GetVisibleURL());
@@ -692,11 +713,14 @@ TEST_F(WebContentsImplTest, NavigateFromSitelessUrl) {
const GURL url("http://www.google.com");
controller().LoadURL(
url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- EXPECT_FALSE(contents()->cross_navigation_pending());
+ entry_id = controller().GetPendingEntry()->GetUniqueID();
+ contents()->GetMainFrame()->PrepareForCommit();
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
EXPECT_EQ(native_url, contents()->GetLastCommittedURL());
EXPECT_EQ(url, contents()->GetVisibleURL());
EXPECT_FALSE(contents()->GetPendingMainFrame());
- contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
+ contents()->TestDidNavigate(orig_rfh, 2, entry_id, true, url,
+ ui::PAGE_TRANSITION_TYPED);
// Keep the number of active frames in orig_rfh's SiteInstance
// non-zero so that orig_rfh doesn't get deleted when it gets
@@ -712,7 +736,12 @@ TEST_F(WebContentsImplTest, NavigateFromSitelessUrl) {
const GURL url2("http://www.yahoo.com");
controller().LoadURL(
url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- EXPECT_TRUE(contents()->cross_navigation_pending());
+ entry_id = controller().GetPendingEntry()->GetUniqueID();
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation)) {
+ orig_rfh->PrepareForCommit();
+ }
+ EXPECT_TRUE(contents()->CrossProcessNavigationPending());
EXPECT_EQ(url, contents()->GetLastCommittedURL());
EXPECT_EQ(url2, contents()->GetVisibleURL());
TestRenderFrameHost* pending_rfh = contents()->GetPendingMainFrame();
@@ -721,16 +750,19 @@ TEST_F(WebContentsImplTest, NavigateFromSitelessUrl) {
&pending_rvh_delete_count);
// Navigations should be suspended in pending_rvh until BeforeUnloadACK.
- EXPECT_TRUE(pending_rfh->are_navigations_suspended());
- orig_rfh->SendBeforeUnloadACK(true);
- EXPECT_FALSE(pending_rfh->are_navigations_suspended());
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation)) {
+ 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_rfh, 1, url2, ui::PAGE_TRANSITION_TYPED);
+ contents()->TestDidNavigate(pending_rfh, 1, entry_id, true, url2,
+ ui::PAGE_TRANSITION_TYPED);
SiteInstance* new_instance = contents()->GetSiteInstance();
- EXPECT_FALSE(contents()->cross_navigation_pending());
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
EXPECT_EQ(pending_rfh, contents()->GetMainFrame());
EXPECT_EQ(url2, contents()->GetLastCommittedURL());
EXPECT_EQ(url2, contents()->GetVisibleURL());
@@ -774,8 +806,10 @@ TEST_F(WebContentsImplTest, NavigateFromRestoredSitelessUrl) {
ASSERT_EQ(0u, entries.size());
ASSERT_EQ(1, controller().GetEntryCount());
controller().GoToIndex(0);
- contents()->TestDidNavigate(
- orig_rfh, 0, native_url, ui::PAGE_TRANSITION_RELOAD);
+ entry = controller().GetPendingEntry();
+ orig_rfh->PrepareForCommit();
+ contents()->TestDidNavigate(orig_rfh, 0, entry->GetUniqueID(), false,
+ native_url, ui::PAGE_TRANSITION_RELOAD);
EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
EXPECT_FALSE(orig_instance->HasSite());
@@ -785,7 +819,10 @@ TEST_F(WebContentsImplTest, NavigateFromRestoredSitelessUrl) {
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);
+ entry = controller().GetPendingEntry();
+ orig_rfh->PrepareForCommit();
+ contents()->TestDidNavigate(orig_rfh, 2, entry->GetUniqueID(), true, url,
+ ui::PAGE_TRANSITION_TYPED);
EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
// Cleanup.
@@ -817,8 +854,10 @@ TEST_F(WebContentsImplTest, NavigateFromRestoredRegularUrl) {
ASSERT_EQ(0u, entries.size());
ASSERT_EQ(1, controller().GetEntryCount());
controller().GoToIndex(0);
- contents()->TestDidNavigate(
- orig_rfh, 0, regular_url, ui::PAGE_TRANSITION_RELOAD);
+ entry = controller().GetPendingEntry();
+ orig_rfh->PrepareForCommit();
+ contents()->TestDidNavigate(orig_rfh, 0, entry->GetUniqueID(), false,
+ regular_url, ui::PAGE_TRANSITION_RELOAD);
EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
EXPECT_TRUE(orig_instance->HasSite());
@@ -826,8 +865,11 @@ TEST_F(WebContentsImplTest, NavigateFromRestoredRegularUrl) {
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);
+ entry = controller().GetPendingEntry();
+ orig_rfh->PrepareForCommit();
+ contents()->TestDidNavigate(contents()->GetPendingMainFrame(), 2,
+ entry->GetUniqueID(), true, url,
+ ui::PAGE_TRANSITION_TYPED);
EXPECT_NE(orig_instance, contents()->GetSiteInstance());
// Cleanup.
@@ -843,13 +885,16 @@ TEST_F(WebContentsImplTest, FindOpenerRVHWhenPending) {
const GURL url("http://www.google.com");
controller().LoadURL(
url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
+ int entry_id = controller().GetPendingEntry()->GetUniqueID();
+ orig_rfh->PrepareForCommit();
+ contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, 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(), ui::PAGE_TRANSITION_TYPED, std::string());
- orig_rfh->SendBeforeUnloadACK(true);
+ orig_rfh->PrepareForCommit();
TestRenderFrameHost* pending_rfh = contents()->GetPendingMainFrame();
// While it is still pending, simulate opening a new tab with the first tab
@@ -873,8 +918,10 @@ TEST_F(WebContentsImplTest, CrossSiteComparesAgainstCurrentPage) {
const GURL url("http://www.google.com");
controller().LoadURL(
url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- contents()->TestDidNavigate(
- orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
+ int entry_id = controller().GetPendingEntry()->GetUniqueID();
+ contents()->GetMainFrame()->PrepareForCommit();
+ contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, url,
+ ui::PAGE_TRANSITION_TYPED);
// Open a related contents to a second site.
scoped_ptr<TestWebContents> contents2(
@@ -883,31 +930,39 @@ TEST_F(WebContentsImplTest, CrossSiteComparesAgainstCurrentPage) {
contents2->GetController().LoadURL(url2, Referrer(),
ui::PAGE_TRANSITION_TYPED,
std::string());
+ entry_id = contents2->GetController().GetPendingEntry()->GetUniqueID();
+ contents2->GetMainFrame()->PrepareForCommit();
+
// The first RVH in contents2 isn't live yet, so we shortcut the cross site
// pending.
TestRenderFrameHost* rfh2 = contents2->GetMainFrame();
- EXPECT_FALSE(contents2->cross_navigation_pending());
- contents2->TestDidNavigate(rfh2, 2, url2, ui::PAGE_TRANSITION_TYPED);
+ EXPECT_FALSE(contents2->CrossProcessNavigationPending());
+ contents2->TestDidNavigate(rfh2, 2, entry_id, true, url2,
+ ui::PAGE_TRANSITION_TYPED);
SiteInstance* instance2 = contents2->GetSiteInstance();
EXPECT_NE(instance1, instance2);
- EXPECT_FALSE(contents2->cross_navigation_pending());
+ EXPECT_FALSE(contents2->CrossProcessNavigationPending());
// Simulate a link click in first contents to second site. Doesn't switch
- // SiteInstances, because we don't intercept WebKit navigations.
- contents()->TestDidNavigate(
- orig_rfh, 2, url2, ui::PAGE_TRANSITION_TYPED);
+ // SiteInstances, because we don't intercept Blink navigations.
+ orig_rfh->SendRendererInitiatedNavigationRequest(url2, true);
+ orig_rfh->PrepareForCommit();
+ contents()->TestDidNavigate(orig_rfh, 2, 0, true, url2,
+ ui::PAGE_TRANSITION_TYPED);
SiteInstance* instance3 = contents()->GetSiteInstance();
EXPECT_EQ(instance1, instance3);
- EXPECT_FALSE(contents()->cross_navigation_pending());
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
// Navigate to the new site. Doesn't switch SiteInstancees, because we
// compare against the current URL, not the SiteInstance's site.
const GURL url3("http://mail.yahoo.com");
controller().LoadURL(
url3, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- EXPECT_FALSE(contents()->cross_navigation_pending());
- contents()->TestDidNavigate(
- orig_rfh, 3, url3, ui::PAGE_TRANSITION_TYPED);
+ entry_id = controller().GetPendingEntry()->GetUniqueID();
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
+ contents()->GetMainFrame()->PrepareForCommit();
+ contents()->TestDidNavigate(orig_rfh, 3, entry_id, true, url3,
+ ui::PAGE_TRANSITION_TYPED);
SiteInstance* instance4 = contents()->GetSiteInstance();
EXPECT_EQ(instance1, instance4);
}
@@ -922,43 +977,46 @@ TEST_F(WebContentsImplTest, CrossSiteUnloadHandlers) {
const GURL url("http://www.google.com");
controller().LoadURL(
url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
- EXPECT_FALSE(contents()->cross_navigation_pending());
+ int entry_id = controller().GetPendingEntry()->GetUniqueID();
+ contents()->GetMainFrame()->PrepareForCommit();
+ contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, url,
+ ui::PAGE_TRANSITION_TYPED);
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
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(), ui::PAGE_TRANSITION_TYPED, std::string());
- EXPECT_TRUE(orig_rfh->is_waiting_for_beforeunload_ack());
+ EXPECT_TRUE(orig_rfh->IsWaitingForBeforeUnloadACK());
base::TimeTicks now = base::TimeTicks::Now();
orig_rfh->OnMessageReceived(
FrameHostMsg_BeforeUnload_ACK(0, false, now, now));
- EXPECT_FALSE(orig_rfh->is_waiting_for_beforeunload_ack());
- EXPECT_FALSE(contents()->cross_navigation_pending());
+ EXPECT_FALSE(orig_rfh->IsWaitingForBeforeUnloadACK());
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
// Navigate again, but simulate an onbeforeunload approval.
controller().LoadURL(
url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- EXPECT_TRUE(orig_rfh->is_waiting_for_beforeunload_ack());
+ entry_id = controller().GetPendingEntry()->GetUniqueID();
+ EXPECT_TRUE(orig_rfh->IsWaitingForBeforeUnloadACK());
now = base::TimeTicks::Now();
- orig_rfh->OnMessageReceived(
- FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
- EXPECT_FALSE(orig_rfh->is_waiting_for_beforeunload_ack());
- EXPECT_TRUE(contents()->cross_navigation_pending());
+ orig_rfh->PrepareForCommit();
+ EXPECT_FALSE(orig_rfh->IsWaitingForBeforeUnloadACK());
+ EXPECT_TRUE(contents()->CrossProcessNavigationPending());
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_rfh, 1, url2, ui::PAGE_TRANSITION_TYPED);
+ contents()->TestDidNavigate(pending_rfh, 1, entry_id, true, url2,
+ ui::PAGE_TRANSITION_TYPED);
SiteInstance* instance2 = contents()->GetSiteInstance();
- EXPECT_FALSE(contents()->cross_navigation_pending());
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
EXPECT_EQ(pending_rfh, contents()->GetMainFrame());
EXPECT_NE(instance1, instance2);
- EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL);
+ EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
}
// Test that during a slow cross-site navigation, the original renderer can
@@ -972,42 +1030,47 @@ TEST_F(WebContentsImplTest, CrossSiteNavigationPreempted) {
const GURL url("http://www.google.com");
controller().LoadURL(
url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
- EXPECT_FALSE(contents()->cross_navigation_pending());
+ int entry_id = controller().GetPendingEntry()->GetUniqueID();
+ contents()->GetMainFrame()->PrepareForCommit();
+ contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, url,
+ ui::PAGE_TRANSITION_TYPED);
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
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(), ui::PAGE_TRANSITION_TYPED, std::string());
- EXPECT_TRUE(orig_rfh->is_waiting_for_beforeunload_ack());
- base::TimeTicks now = base::TimeTicks::Now();
- orig_rfh->OnMessageReceived(FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
- EXPECT_TRUE(contents()->cross_navigation_pending());
+ EXPECT_TRUE(orig_rfh->IsWaitingForBeforeUnloadACK());
+ orig_rfh->PrepareForCommit();
+ EXPECT_TRUE(contents()->CrossProcessNavigationPending());
// Suppose the original renderer navigates before the new one is ready.
- orig_rfh->SendNavigate(2, GURL("http://www.google.com/foo"));
+ orig_rfh->SendNavigate(2, 0, true, GURL("http://www.google.com/foo"));
// Verify that the pending navigation is cancelled.
- EXPECT_FALSE(orig_rfh->is_waiting_for_beforeunload_ack());
+ EXPECT_FALSE(orig_rfh->IsWaitingForBeforeUnloadACK());
SiteInstance* instance2 = contents()->GetSiteInstance();
- EXPECT_FALSE(contents()->cross_navigation_pending());
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
EXPECT_EQ(instance1, instance2);
- EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL);
+ EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
}
TEST_F(WebContentsImplTest, CrossSiteNavigationBackPreempted) {
// Start with a web ui page, which gets a new RVH with WebUI bindings.
- const GURL url1("chrome://blah");
+ const GURL url1("chrome://gpu");
controller().LoadURL(
url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ int entry_id = controller().GetPendingEntry()->GetUniqueID();
TestRenderFrameHost* ntp_rfh = contents()->GetMainFrame();
- contents()->TestDidNavigate(ntp_rfh, 1, url1, ui::PAGE_TRANSITION_TYPED);
+ ntp_rfh->PrepareForCommit();
+ contents()->TestDidNavigate(ntp_rfh, 1, entry_id, true, url1,
+ ui::PAGE_TRANSITION_TYPED);
NavigationEntry* entry1 = controller().GetLastCommittedEntry();
SiteInstance* instance1 = contents()->GetSiteInstance();
- EXPECT_FALSE(contents()->cross_navigation_pending());
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
EXPECT_EQ(ntp_rfh, contents()->GetMainFrame());
EXPECT_EQ(url1, entry1->GetURL());
EXPECT_EQ(instance1,
@@ -1019,22 +1082,22 @@ TEST_F(WebContentsImplTest, CrossSiteNavigationBackPreempted) {
const GURL url2("http://www.google.com");
controller().LoadURL(
url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- EXPECT_TRUE(contents()->cross_navigation_pending());
+ entry_id = controller().GetPendingEntry()->GetUniqueID();
+ EXPECT_TRUE(contents()->CrossProcessNavigationPending());
TestRenderFrameHost* google_rfh = contents()->GetPendingMainFrame();
// Simulate beforeunload approval.
- EXPECT_TRUE(ntp_rfh->is_waiting_for_beforeunload_ack());
+ EXPECT_TRUE(ntp_rfh->IsWaitingForBeforeUnloadACK());
base::TimeTicks now = base::TimeTicks::Now();
- ntp_rfh->OnMessageReceived(
- FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
+ ntp_rfh->PrepareForCommit();
// DidNavigate from the pending page.
- contents()->TestDidNavigate(
- google_rfh, 1, url2, ui::PAGE_TRANSITION_TYPED);
+ contents()->TestDidNavigate(google_rfh, 1, entry_id, true, url2,
+ ui::PAGE_TRANSITION_TYPED);
NavigationEntry* entry2 = controller().GetLastCommittedEntry();
SiteInstance* instance2 = contents()->GetSiteInstance();
- EXPECT_FALSE(contents()->cross_navigation_pending());
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
EXPECT_EQ(google_rfh, contents()->GetMainFrame());
EXPECT_NE(instance1, instance2);
EXPECT_FALSE(contents()->GetPendingMainFrame());
@@ -1048,13 +1111,15 @@ TEST_F(WebContentsImplTest, CrossSiteNavigationBackPreempted) {
const GURL url3("http://news.google.com");
controller().LoadURL(
url3, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- EXPECT_FALSE(contents()->cross_navigation_pending());
- contents()->TestDidNavigate(
- google_rfh, 2, url3, ui::PAGE_TRANSITION_TYPED);
+ entry_id = controller().GetPendingEntry()->GetUniqueID();
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
+ contents()->GetMainFrame()->PrepareForCommit();
+ contents()->TestDidNavigate(google_rfh, 2, entry_id, true, url3,
+ ui::PAGE_TRANSITION_TYPED);
NavigationEntry* entry3 = controller().GetLastCommittedEntry();
SiteInstance* instance3 = contents()->GetSiteInstance();
- EXPECT_FALSE(contents()->cross_navigation_pending());
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
EXPECT_EQ(google_rfh, contents()->GetMainFrame());
EXPECT_EQ(instance2, instance3);
EXPECT_FALSE(contents()->GetPendingMainFrame());
@@ -1064,26 +1129,29 @@ TEST_F(WebContentsImplTest, CrossSiteNavigationBackPreempted) {
// Go back within the site.
controller().GoBack();
- EXPECT_FALSE(contents()->cross_navigation_pending());
+ NavigationEntry* goback_entry = controller().GetPendingEntry();
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
EXPECT_EQ(entry2, controller().GetPendingEntry());
// Before that commits, go back again.
controller().GoBack();
- EXPECT_TRUE(contents()->cross_navigation_pending());
+ EXPECT_TRUE(contents()->CrossProcessNavigationPending());
EXPECT_TRUE(contents()->GetPendingMainFrame());
EXPECT_EQ(entry1, controller().GetPendingEntry());
// Simulate beforeunload approval.
- EXPECT_TRUE(google_rfh->is_waiting_for_beforeunload_ack());
+ EXPECT_TRUE(google_rfh->IsWaitingForBeforeUnloadACK());
now = base::TimeTicks::Now();
+ google_rfh->PrepareForCommit();
google_rfh->OnMessageReceived(
FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
// DidNavigate from the first back. This aborts the second back's pending RFH.
- contents()->TestDidNavigate(google_rfh, 1, url2, ui::PAGE_TRANSITION_TYPED);
+ contents()->TestDidNavigate(google_rfh, 1, goback_entry->GetUniqueID(), false,
+ url2, ui::PAGE_TRANSITION_TYPED);
// We should commit this page and forget about the second back.
- EXPECT_FALSE(contents()->cross_navigation_pending());
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
EXPECT_FALSE(controller().GetPendingEntry());
EXPECT_EQ(google_rfh, contents()->GetMainFrame());
EXPECT_EQ(url2, controller().GetLastCommittedEntry()->GetURL());
@@ -1107,8 +1175,11 @@ TEST_F(WebContentsImplTest, CrossSiteNavigationNotPreemptedByFrame) {
const GURL url("http://www.google.com");
controller().LoadURL(
url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
- EXPECT_FALSE(contents()->cross_navigation_pending());
+ int entry_id = controller().GetPendingEntry()->GetUniqueID();
+ contents()->GetMainFrame()->PrepareForCommit();
+ contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, url,
+ ui::PAGE_TRANSITION_TYPED);
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
// Start navigating to new site.
@@ -1119,17 +1190,16 @@ TEST_F(WebContentsImplTest, CrossSiteNavigationNotPreemptedByFrame) {
// Simulate a sub-frame navigation arriving and ensure the RVH is still
// waiting for a before unload response.
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());
+ child_rfh->SendNavigateWithTransition(1, 0, false,
+ GURL("http://google.com/frame"),
+ ui::PAGE_TRANSITION_AUTO_SUBFRAME);
+ EXPECT_TRUE(orig_rfh->IsWaitingForBeforeUnloadACK());
// Now simulate the onbeforeunload approval and verify the navigation is
// not canceled.
- base::TimeTicks now = base::TimeTicks::Now();
- orig_rfh->OnMessageReceived(
- FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
- EXPECT_FALSE(orig_rfh->is_waiting_for_beforeunload_ack());
- EXPECT_TRUE(contents()->cross_navigation_pending());
+ orig_rfh->PrepareForCommit();
+ EXPECT_FALSE(orig_rfh->IsWaitingForBeforeUnloadACK());
+ EXPECT_TRUE(contents()->CrossProcessNavigationPending());
}
// Test that a cross-site navigation is not preempted if the previous
@@ -1137,78 +1207,38 @@ TEST_F(WebContentsImplTest, CrossSiteNavigationNotPreemptedByFrame) {
// We should only preempt the cross-site navigation if the previous renderer
// has started a new navigation. See http://crbug.com/79176.
TEST_F(WebContentsImplTest, CrossSiteNotPreemptedDuringBeforeUnload) {
- // Navigate to NTP URL.
- const GURL url("chrome://blah");
+ // Navigate to WebUI URL.
+ const GURL url("chrome://gpu");
controller().LoadURL(
url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ int entry1_id = controller().GetPendingEntry()->GetUniqueID();
TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
- EXPECT_FALSE(contents()->cross_navigation_pending());
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
// Navigate to new site, with the beforeunload request in flight.
const GURL url2("http://www.yahoo.com");
controller().LoadURL(
url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ int entry2_id = controller().GetPendingEntry()->GetUniqueID();
TestRenderFrameHost* pending_rfh = contents()->GetPendingMainFrame();
- EXPECT_TRUE(contents()->cross_navigation_pending());
- EXPECT_TRUE(orig_rfh->is_waiting_for_beforeunload_ack());
+ EXPECT_TRUE(contents()->CrossProcessNavigationPending());
+ EXPECT_TRUE(orig_rfh->IsWaitingForBeforeUnloadACK());
// Suppose the first navigation tries to commit now, with a
// FrameMsg_Stop in flight. This should not cancel the pending navigation,
// but it should act as if the beforeunload ack arrived.
- orig_rfh->SendNavigate(1, GURL("chrome://blah"));
- EXPECT_TRUE(contents()->cross_navigation_pending());
+ orig_rfh->SendNavigate(1, entry1_id, true, GURL("chrome://gpu"));
+ EXPECT_TRUE(contents()->CrossProcessNavigationPending());
EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
- EXPECT_FALSE(orig_rfh->is_waiting_for_beforeunload_ack());
+ EXPECT_FALSE(orig_rfh->IsWaitingForBeforeUnloadACK());
// The pending navigation should be able to commit successfully.
- contents()->TestDidNavigate(pending_rfh, 1, url2, ui::PAGE_TRANSITION_TYPED);
- EXPECT_FALSE(contents()->cross_navigation_pending());
+ contents()->TestDidNavigate(pending_rfh, 1, entry2_id, true, url2,
+ ui::PAGE_TRANSITION_TYPED);
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
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) {
- TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
- SiteInstance* instance1 = contents()->GetSiteInstance();
-
- // Navigate to URL. First URL should use original RenderFrameHost.
- const GURL url("http://www.google.com");
- controller().LoadURL(
- 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_rfh, contents()->GetMainFrame());
-
- // Navigate to new site, simulating an onbeforeunload approval.
- const GURL url2("http://www.yahoo.com");
- 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_rfh->OnMessageReceived(
- FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
- EXPECT_TRUE(contents()->cross_navigation_pending());
-
- // Simulate swap out message when the response arrives.
- orig_rfh->OnSwappedOut();
-
- // Suppose the navigation doesn't get a chance to commit, and the user
- // 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_rfh->is_waiting_for_beforeunload_ack());
- SiteInstance* instance2 = contents()->GetSiteInstance();
- EXPECT_FALSE(contents()->cross_navigation_pending());
- EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
- EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, orig_rfh->rfh_state());
- EXPECT_EQ(instance1, instance2);
- 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) {
@@ -1218,11 +1248,14 @@ TEST_F(WebContentsImplTest, NavigationEntryContentState) {
const GURL url("http://www.google.com");
controller().LoadURL(
url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ int entry_id = controller().GetPendingEntry()->GetUniqueID();
NavigationEntry* entry = controller().GetLastCommittedEntry();
- EXPECT_TRUE(entry == NULL);
+ EXPECT_EQ(nullptr, entry);
// Committed entry should have page state after DidNavigate.
- contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
+ orig_rfh->PrepareForCommit();
+ contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, url,
+ ui::PAGE_TRANSITION_TYPED);
entry = controller().GetLastCommittedEntry();
EXPECT_TRUE(entry->GetPageState().IsValid());
@@ -1230,17 +1263,23 @@ TEST_F(WebContentsImplTest, NavigationEntryContentState) {
const GURL url2("http://images.google.com");
controller().LoadURL(
url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ entry_id = controller().GetPendingEntry()->GetUniqueID();
entry = controller().GetLastCommittedEntry();
EXPECT_TRUE(entry->GetPageState().IsValid());
// Committed entry should have page state after DidNavigate.
- contents()->TestDidNavigate(orig_rfh, 2, url2, ui::PAGE_TRANSITION_TYPED);
+ orig_rfh->PrepareForCommit();
+ contents()->TestDidNavigate(orig_rfh, 2, entry_id, true, 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_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
+ entry_id = controller().GetPendingEntry()->GetUniqueID();
+ orig_rfh->PrepareForCommit();
+ contents()->TestDidNavigate(orig_rfh, 1, entry_id, false, url,
+ ui::PAGE_TRANSITION_TYPED);
entry = controller().GetLastCommittedEntry();
EXPECT_TRUE(entry->GetPageState().IsValid());
}
@@ -1251,11 +1290,12 @@ TEST_F(WebContentsImplTest, NavigationEntryContentState) {
TEST_F(WebContentsImplTest, NavigationEntryContentStateNewWindow) {
TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
- // When opening a new window, it is navigated to about:blank internally.
- // Currently, this results in two DidNavigate events.
+ // Navigate to about:blank.
const GURL url(url::kAboutBlankURL);
- contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
- contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
+ orig_rfh->SendRendererInitiatedNavigationRequest(url, false);
+ orig_rfh->PrepareForCommit();
+ contents()->TestDidNavigate(orig_rfh, 1, 0, true, url,
+ ui::PAGE_TRANSITION_TYPED);
// Should have a page state here.
NavigationEntry* entry = controller().GetLastCommittedEntry();
@@ -1271,9 +1311,12 @@ TEST_F(WebContentsImplTest, NavigationEntryContentStateNewWindow) {
const GURL new_url("http://www.google.com");
controller().LoadURL(new_url, Referrer(),
ui::PAGE_TRANSITION_TYPED, std::string());
- EXPECT_FALSE(contents()->cross_navigation_pending());
+ entry = controller().GetPendingEntry();
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
- contents()->TestDidNavigate(orig_rfh, 1, new_url, ui::PAGE_TRANSITION_TYPED);
+ orig_rfh->PrepareForCommit();
+ contents()->TestDidNavigate(orig_rfh, 2, entry->GetUniqueID(), true, new_url,
+ ui::PAGE_TRANSITION_TYPED);
NavigationEntryImpl* entry_impl2 = NavigationEntryImpl::FromNavigationEntry(
controller().GetLastCommittedEntry());
EXPECT_EQ(site_instance_id, entry_impl2->site_instance()->GetId());
@@ -1292,16 +1335,19 @@ TEST_F(WebContentsImplTest, NavigationExitsFullscreen) {
const GURL url("http://www.google.com");
controller().LoadURL(
url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
+ int entry_id = controller().GetPendingEntry()->GetUniqueID();
+ contents()->GetMainFrame()->PrepareForCommit();
+ contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, 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());
+ EXPECT_FALSE(orig_rvh->IsFullscreenGranted());
EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
- orig_rvh->OnMessageReceived(
- ViewHostMsg_ToggleFullscreen(orig_rvh->GetRoutingID(), true));
- EXPECT_TRUE(orig_rvh->IsFullscreen());
+ orig_rfh->OnMessageReceived(
+ FrameHostMsg_ToggleFullscreen(orig_rfh->GetRoutingID(), true));
+ EXPECT_TRUE(orig_rvh->IsFullscreenGranted());
EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents()));
@@ -1309,16 +1355,18 @@ TEST_F(WebContentsImplTest, NavigationExitsFullscreen) {
const GURL url2("http://www.yahoo.com");
controller().LoadURL(
url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ entry_id = controller().GetPendingEntry()->GetUniqueID();
+ contents()->GetMainFrame()->PrepareForCommit();
TestRenderFrameHost* const pending_rfh = contents()->GetPendingMainFrame();
- contents()->TestDidNavigate(
- pending_rfh, 1, url2, ui::PAGE_TRANSITION_TYPED);
+ contents()->TestDidNavigate(pending_rfh, 1, entry_id, true, url2,
+ ui::PAGE_TRANSITION_TYPED);
// Confirm fullscreen has exited.
- EXPECT_FALSE(orig_rvh->IsFullscreen());
+ EXPECT_FALSE(orig_rvh->IsFullscreenGranted());
EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
- contents()->SetDelegate(NULL);
+ contents()->SetDelegate(nullptr);
}
// Tests that fullscreen is exited throughout the object hierarchy when
@@ -1333,27 +1381,33 @@ TEST_F(WebContentsImplTest, HistoryNavigationExitsFullscreen) {
const GURL url("http://www.google.com");
controller().LoadURL(
url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
+ int entry_id = controller().GetPendingEntry()->GetUniqueID();
+ orig_rfh->PrepareForCommit();
+ contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, 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(), ui::PAGE_TRANSITION_TYPED, std::string());
- EXPECT_FALSE(contents()->cross_navigation_pending());
- contents()->TestDidNavigate(orig_rfh, 2, url2, ui::PAGE_TRANSITION_TYPED);
+ entry_id = controller().GetPendingEntry()->GetUniqueID();
+ orig_rfh->PrepareForCommit();
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
+ contents()->TestDidNavigate(orig_rfh, 2, entry_id, true, 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());
+ EXPECT_FALSE(orig_rvh->IsFullscreenGranted());
EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
for (int i = 0; i < 2; ++i) {
// Toggle fullscreen mode on (as if initiated via IPC from renderer).
- orig_rvh->OnMessageReceived(
- ViewHostMsg_ToggleFullscreen(orig_rvh->GetRoutingID(), true));
- EXPECT_TRUE(orig_rvh->IsFullscreen());
+ orig_rfh->OnMessageReceived(
+ FrameHostMsg_ToggleFullscreen(orig_rfh->GetRoutingID(), true));
+ EXPECT_TRUE(orig_rvh->IsFullscreenGranted());
EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents()));
@@ -1362,18 +1416,20 @@ TEST_F(WebContentsImplTest, HistoryNavigationExitsFullscreen) {
controller().GoBack();
else
controller().GoForward();
- EXPECT_FALSE(contents()->cross_navigation_pending());
+ entry_id = controller().GetPendingEntry()->GetUniqueID();
+ orig_rfh->PrepareForCommit();
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
- contents()->TestDidNavigate(
- orig_rfh, i + 1, url, ui::PAGE_TRANSITION_FORWARD_BACK);
+ contents()->TestDidNavigate(orig_rfh, i + 1, entry_id, false, url,
+ ui::PAGE_TRANSITION_FORWARD_BACK);
// Confirm fullscreen has exited.
- EXPECT_FALSE(orig_rvh->IsFullscreen());
+ EXPECT_FALSE(orig_rvh->IsFullscreenGranted());
EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
}
- contents()->SetDelegate(NULL);
+ contents()->SetDelegate(nullptr);
}
TEST_F(WebContentsImplTest, TerminateHidesValidationMessage) {
@@ -1382,14 +1438,12 @@ TEST_F(WebContentsImplTest, TerminateHidesValidationMessage) {
EXPECT_FALSE(fake_delegate.hide_validation_message_was_called());
// Crash the renderer.
- contents()->GetMainFrame()->GetRenderViewHost()->OnMessageReceived(
- ViewHostMsg_RenderProcessGone(
- 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
+ contents()->GetMainFrame()->GetProcess()->SimulateCrash();
// Confirm HideValidationMessage was called.
EXPECT_TRUE(fake_delegate.hide_validation_message_was_called());
- contents()->SetDelegate(NULL);
+ contents()->SetDelegate(nullptr);
}
// Tests that fullscreen is exited throughout the object hierarchy on a renderer
@@ -1402,30 +1456,30 @@ TEST_F(WebContentsImplTest, CrashExitsFullscreen) {
const GURL url("http://www.google.com");
controller().LoadURL(
url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
- contents()->TestDidNavigate(
- contents()->GetMainFrame(), 1, url, ui::PAGE_TRANSITION_TYPED);
+ int entry_id = controller().GetPendingEntry()->GetUniqueID();
+ main_test_rfh()->PrepareForCommit();
+ contents()->TestDidNavigate(contents()->GetMainFrame(), 1, entry_id, true,
+ url, ui::PAGE_TRANSITION_TYPED);
// Toggle fullscreen mode on (as if initiated via IPC from renderer).
- EXPECT_FALSE(test_rvh()->IsFullscreen());
+ EXPECT_FALSE(test_rvh()->IsFullscreenGranted());
EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
- test_rvh()->OnMessageReceived(
- ViewHostMsg_ToggleFullscreen(test_rvh()->GetRoutingID(), true));
- EXPECT_TRUE(test_rvh()->IsFullscreen());
+ contents()->GetMainFrame()->OnMessageReceived(FrameHostMsg_ToggleFullscreen(
+ contents()->GetMainFrame()->GetRoutingID(), true));
+ EXPECT_TRUE(test_rvh()->IsFullscreenGranted());
EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents()));
// Crash the renderer.
- test_rvh()->OnMessageReceived(
- ViewHostMsg_RenderProcessGone(
- 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
+ main_test_rfh()->GetProcess()->SimulateCrash();
// Confirm fullscreen has exited.
- EXPECT_FALSE(test_rvh()->IsFullscreen());
+ EXPECT_FALSE(test_rvh()->IsFullscreenGranted());
EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
- contents()->SetDelegate(NULL);
+ contents()->SetDelegate(nullptr);
}
////////////////////////////////////////////////////////////////////////////////
@@ -1439,12 +1493,13 @@ TEST_F(WebContentsImplTest,
ShowInterstitialFromBrowserWithNewNavigationDontProceed) {
// Navigate to a page.
GURL url1("http://www.google.com");
- contents()->GetMainFrame()->SendNavigate(1, url1);
+ main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1);
EXPECT_EQ(1, controller().GetEntryCount());
- // Initiate a browser navigation that will trigger the interstitial
+ // Initiate a browser navigation that will trigger the interstitial.
controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
ui::PAGE_TRANSITION_TYPED, std::string());
+ NavigationEntry* entry = controller().GetPendingEntry();
// Show an interstitial.
TestInterstitialPage::InterstitialState state =
@@ -1455,26 +1510,27 @@ TEST_F(WebContentsImplTest,
new TestInterstitialPage(contents(), true, url2, &state, &deleted);
TestInterstitialPageStateGuard state_guard(interstitial);
interstitial->Show();
+ int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
// The interstitial should not show until its navigation has committed.
EXPECT_FALSE(interstitial->is_showing());
EXPECT_FALSE(contents()->ShowingInterstitialPage());
- EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
+ EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
// Let's commit the interstitial navigation.
- interstitial->TestDidNavigate(1, url2);
+ interstitial->TestDidNavigate(1, interstitial_entry_id, true, url2);
EXPECT_TRUE(interstitial->is_showing());
EXPECT_TRUE(contents()->ShowingInterstitialPage());
EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
- NavigationEntry* entry = controller().GetVisibleEntry();
- ASSERT_TRUE(entry != NULL);
+ entry = controller().GetVisibleEntry();
+ ASSERT_NE(nullptr, entry);
EXPECT_TRUE(entry->GetURL() == url2);
// Now don't proceed.
interstitial->DontProceed();
EXPECT_EQ(TestInterstitialPage::CANCELED, state);
EXPECT_FALSE(contents()->ShowingInterstitialPage());
- EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
+ EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
entry = controller().GetVisibleEntry();
- ASSERT_TRUE(entry != NULL);
+ ASSERT_NE(nullptr, entry);
EXPECT_TRUE(entry->GetURL() == url1);
EXPECT_EQ(1, controller().GetEntryCount());
@@ -1486,10 +1542,10 @@ TEST_F(WebContentsImplTest,
// as when clicking on a link in the page) that shows an interstitial and
// creates a new navigation entry, then hiding it without proceeding.
TEST_F(WebContentsImplTest,
- ShowInterstitiaFromRendererlWithNewNavigationDontProceed) {
+ ShowInterstitialFromRendererWithNewNavigationDontProceed) {
// Navigate to a page.
GURL url1("http://www.google.com");
- contents()->GetMainFrame()->SendNavigate(1, url1);
+ main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1);
EXPECT_EQ(1, controller().GetEntryCount());
// Show an interstitial (no pending entry, the interstitial would have been
@@ -1502,26 +1558,27 @@ TEST_F(WebContentsImplTest,
new TestInterstitialPage(contents(), true, url2, &state, &deleted);
TestInterstitialPageStateGuard state_guard(interstitial);
interstitial->Show();
+ int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
// The interstitial should not show until its navigation has committed.
EXPECT_FALSE(interstitial->is_showing());
EXPECT_FALSE(contents()->ShowingInterstitialPage());
- EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
+ EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
// Let's commit the interstitial navigation.
- interstitial->TestDidNavigate(1, url2);
+ interstitial->TestDidNavigate(1, interstitial_entry_id, true, url2);
EXPECT_TRUE(interstitial->is_showing());
EXPECT_TRUE(contents()->ShowingInterstitialPage());
EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
NavigationEntry* entry = controller().GetVisibleEntry();
- ASSERT_TRUE(entry != NULL);
+ ASSERT_NE(nullptr, entry);
EXPECT_TRUE(entry->GetURL() == url2);
// Now don't proceed.
interstitial->DontProceed();
EXPECT_EQ(TestInterstitialPage::CANCELED, state);
EXPECT_FALSE(contents()->ShowingInterstitialPage());
- EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
+ EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
entry = controller().GetVisibleEntry();
- ASSERT_TRUE(entry != NULL);
+ ASSERT_NE(nullptr, entry);
EXPECT_TRUE(entry->GetURL() == url1);
EXPECT_EQ(1, controller().GetEntryCount());
@@ -1535,7 +1592,7 @@ TEST_F(WebContentsImplTest,
TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationDontProceed) {
// Navigate to a page.
GURL url1("http://www.google.com");
- contents()->GetMainFrame()->SendNavigate(1, url1);
+ main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1);
EXPECT_EQ(1, controller().GetEntryCount());
// Show an interstitial.
@@ -1550,14 +1607,14 @@ TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationDontProceed) {
// The interstitial should not show until its navigation has committed.
EXPECT_FALSE(interstitial->is_showing());
EXPECT_FALSE(contents()->ShowingInterstitialPage());
- EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
+ EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
// Let's commit the interstitial navigation.
- interstitial->TestDidNavigate(1, url2);
+ interstitial->TestDidNavigate(1, 0, true, url2);
EXPECT_TRUE(interstitial->is_showing());
EXPECT_TRUE(contents()->ShowingInterstitialPage());
EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
NavigationEntry* entry = controller().GetVisibleEntry();
- ASSERT_TRUE(entry != NULL);
+ ASSERT_NE(nullptr, entry);
// The URL specified to the interstitial should have been ignored.
EXPECT_TRUE(entry->GetURL() == url1);
@@ -1565,9 +1622,9 @@ TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationDontProceed) {
interstitial->DontProceed();
EXPECT_EQ(TestInterstitialPage::CANCELED, state);
EXPECT_FALSE(contents()->ShowingInterstitialPage());
- EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
+ EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
entry = controller().GetVisibleEntry();
- ASSERT_TRUE(entry != NULL);
+ ASSERT_NE(nullptr, entry);
EXPECT_TRUE(entry->GetURL() == url1);
EXPECT_EQ(1, controller().GetEntryCount());
@@ -1582,7 +1639,7 @@ TEST_F(WebContentsImplTest,
ShowInterstitialFromBrowserNewNavigationProceed) {
// Navigate to a page.
GURL url1("http://www.google.com");
- contents()->GetMainFrame()->SendNavigate(1, url1);
+ main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1);
EXPECT_EQ(1, controller().GetEntryCount());
// Initiate a browser navigation that will trigger the interstitial
@@ -1598,17 +1655,18 @@ TEST_F(WebContentsImplTest,
new TestInterstitialPage(contents(), true, url2, &state, &deleted);
TestInterstitialPageStateGuard state_guard(interstitial);
interstitial->Show();
+ int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
// The interstitial should not show until its navigation has committed.
EXPECT_FALSE(interstitial->is_showing());
EXPECT_FALSE(contents()->ShowingInterstitialPage());
- EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
+ EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
// Let's commit the interstitial navigation.
- interstitial->TestDidNavigate(1, url2);
+ interstitial->TestDidNavigate(1, interstitial_entry_id, true, url2);
EXPECT_TRUE(interstitial->is_showing());
EXPECT_TRUE(contents()->ShowingInterstitialPage());
EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
NavigationEntry* entry = controller().GetVisibleEntry();
- ASSERT_TRUE(entry != NULL);
+ ASSERT_NE(nullptr, entry);
EXPECT_TRUE(entry->GetURL() == url2);
// Then proceed.
@@ -1623,12 +1681,12 @@ TEST_F(WebContentsImplTest,
// Simulate the navigation to the page, that's when the interstitial gets
// hidden.
GURL url3("http://www.thepage.com");
- contents()->GetMainFrame()->SendNavigate(2, url3);
+ contents()->GetMainFrame()->SendNavigate(2, 0, true, url3);
EXPECT_FALSE(contents()->ShowingInterstitialPage());
- EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
+ EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
entry = controller().GetVisibleEntry();
- ASSERT_TRUE(entry != NULL);
+ ASSERT_NE(nullptr, entry);
EXPECT_TRUE(entry->GetURL() == url3);
EXPECT_EQ(2, controller().GetEntryCount());
@@ -1644,7 +1702,7 @@ TEST_F(WebContentsImplTest,
ShowInterstitialFromRendererNewNavigationProceed) {
// Navigate to a page.
GURL url1("http://www.google.com");
- contents()->GetMainFrame()->SendNavigate(1, url1);
+ main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1);
EXPECT_EQ(1, controller().GetEntryCount());
// Show an interstitial.
@@ -1656,17 +1714,18 @@ TEST_F(WebContentsImplTest,
new TestInterstitialPage(contents(), true, url2, &state, &deleted);
TestInterstitialPageStateGuard state_guard(interstitial);
interstitial->Show();
+ int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
// The interstitial should not show until its navigation has committed.
EXPECT_FALSE(interstitial->is_showing());
EXPECT_FALSE(contents()->ShowingInterstitialPage());
- EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
+ EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
// Let's commit the interstitial navigation.
- interstitial->TestDidNavigate(1, url2);
+ interstitial->TestDidNavigate(1, interstitial_entry_id, true, url2);
EXPECT_TRUE(interstitial->is_showing());
EXPECT_TRUE(contents()->ShowingInterstitialPage());
EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
NavigationEntry* entry = controller().GetVisibleEntry();
- ASSERT_TRUE(entry != NULL);
+ ASSERT_NE(nullptr, entry);
EXPECT_TRUE(entry->GetURL() == url2);
// Then proceed.
@@ -1681,12 +1740,12 @@ TEST_F(WebContentsImplTest,
// Simulate the navigation to the page, that's when the interstitial gets
// hidden.
GURL url3("http://www.thepage.com");
- contents()->GetMainFrame()->SendNavigate(2, url3);
+ main_test_rfh()->NavigateAndCommitRendererInitiated(2, true, url3);
EXPECT_FALSE(contents()->ShowingInterstitialPage());
- EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
+ EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
entry = controller().GetVisibleEntry();
- ASSERT_TRUE(entry != NULL);
+ ASSERT_NE(nullptr, entry);
EXPECT_TRUE(entry->GetURL() == url3);
EXPECT_EQ(2, controller().GetEntryCount());
@@ -1701,7 +1760,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");
- contents()->GetMainFrame()->SendNavigate(1, url1);
+ main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1);
EXPECT_EQ(1, controller().GetEntryCount());
// Show an interstitial.
@@ -1716,14 +1775,14 @@ TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationProceed) {
// The interstitial should not show until its navigation has committed.
EXPECT_FALSE(interstitial->is_showing());
EXPECT_FALSE(contents()->ShowingInterstitialPage());
- EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
+ EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
// Let's commit the interstitial navigation.
- interstitial->TestDidNavigate(1, url2);
+ interstitial->TestDidNavigate(1, 0, true, url2);
EXPECT_TRUE(interstitial->is_showing());
EXPECT_TRUE(contents()->ShowingInterstitialPage());
EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
NavigationEntry* entry = controller().GetVisibleEntry();
- ASSERT_TRUE(entry != NULL);
+ ASSERT_NE(nullptr, entry);
// The URL specified to the interstitial should have been ignored.
EXPECT_TRUE(entry->GetURL() == url1);
@@ -1733,9 +1792,9 @@ TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationProceed) {
// away and shows the original page.
EXPECT_EQ(TestInterstitialPage::OKED, state);
EXPECT_FALSE(contents()->ShowingInterstitialPage());
- EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
+ EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
entry = controller().GetVisibleEntry();
- ASSERT_TRUE(entry != NULL);
+ ASSERT_NE(nullptr, entry);
EXPECT_TRUE(entry->GetURL() == url1);
EXPECT_EQ(1, controller().GetEntryCount());
@@ -1755,11 +1814,12 @@ TEST_F(WebContentsImplTest, ShowInterstitialThenNavigate) {
new TestInterstitialPage(contents(), true, url, &state, &deleted);
TestInterstitialPageStateGuard state_guard(interstitial);
interstitial->Show();
- interstitial->TestDidNavigate(1, url);
+ int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
+ interstitial->TestDidNavigate(1, interstitial_entry_id, true, url);
// While interstitial showing, navigate to a new URL.
const GURL url2("http://www.yahoo.com");
- contents()->GetMainFrame()->SendNavigate(1, url2);
+ main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url2);
EXPECT_EQ(TestInterstitialPage::CANCELED, state);
@@ -1771,8 +1831,9 @@ 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");
- contents()->GetMainFrame()->SendNavigate(1, url1);
+ main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1);
EXPECT_EQ(1, controller().GetEntryCount());
+ NavigationEntry* entry = controller().GetLastCommittedEntry();
// Show interstitial.
TestInterstitialPage::InterstitialState state =
@@ -1784,16 +1845,20 @@ TEST_F(WebContentsImplTest, ShowInterstitialThenGoBack) {
&state, &deleted);
TestInterstitialPageStateGuard state_guard(interstitial);
interstitial->Show();
- interstitial->TestDidNavigate(2, interstitial_url);
+ int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
+ interstitial->TestDidNavigate(2, interstitial_entry_id, true,
+ interstitial_url);
// While the interstitial is showing, go back.
controller().GoBack();
- contents()->GetMainFrame()->SendNavigate(1, url1);
+ main_test_rfh()->PrepareForCommit();
+ contents()->GetMainFrame()->SendNavigate(1, entry->GetUniqueID(), false,
+ url1);
// Make sure we are back to the original page and that the interstitial is
// gone.
EXPECT_EQ(TestInterstitialPage::CANCELED, state);
- NavigationEntry* entry = controller().GetVisibleEntry();
+ entry = controller().GetVisibleEntry();
ASSERT_TRUE(entry);
EXPECT_EQ(url1.spec(), entry->GetURL().spec());
@@ -1806,8 +1871,9 @@ 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");
- contents()->GetMainFrame()->SendNavigate(1, url1);
+ main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1);
EXPECT_EQ(1, controller().GetEntryCount());
+ NavigationEntry* entry = controller().GetLastCommittedEntry();
// Show interstitial.
TestInterstitialPage::InterstitialState state =
@@ -1819,21 +1885,23 @@ TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenGoBack) {
&state, &deleted);
TestInterstitialPageStateGuard state_guard(interstitial);
interstitial->Show();
- interstitial->TestDidNavigate(2, interstitial_url);
+ int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
+ interstitial->TestDidNavigate(2, interstitial_entry_id, true,
+ interstitial_url);
// Crash the renderer
- test_rvh()->OnMessageReceived(
- ViewHostMsg_RenderProcessGone(
- 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
+ contents()->GetMainFrame()->GetProcess()->SimulateCrash();
// While the interstitial is showing, go back.
controller().GoBack();
- contents()->GetMainFrame()->SendNavigate(1, url1);
+ main_test_rfh()->PrepareForCommit();
+ contents()->GetMainFrame()->SendNavigate(1, entry->GetUniqueID(), false,
+ url1);
// Make sure we are back to the original page and that the interstitial is
// gone.
EXPECT_EQ(TestInterstitialPage::CANCELED, state);
- NavigationEntry* entry = controller().GetVisibleEntry();
+ entry = controller().GetVisibleEntry();
ASSERT_TRUE(entry);
EXPECT_EQ(url1.spec(), entry->GetURL().spec());
@@ -1846,7 +1914,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");
- contents()->GetMainFrame()->SendNavigate(1, url1);
+ main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1);
EXPECT_EQ(1, controller().GetEntryCount());
// Show interstitial.
@@ -1859,13 +1927,13 @@ TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenNavigate) {
&state, &deleted);
TestInterstitialPageStateGuard state_guard(interstitial);
interstitial->Show();
+ int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
// Crash the renderer
- test_rvh()->OnMessageReceived(
- ViewHostMsg_RenderProcessGone(
- 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
+ contents()->GetMainFrame()->GetProcess()->SimulateCrash();
- interstitial->TestDidNavigate(2, interstitial_url);
+ interstitial->TestDidNavigate(2, interstitial_entry_id, true,
+ interstitial_url);
}
// Test navigating to a page that shows an interstitial, then close the
@@ -1880,7 +1948,8 @@ TEST_F(WebContentsImplTest, ShowInterstitialThenCloseTab) {
new TestInterstitialPage(contents(), true, url, &state, &deleted);
TestInterstitialPageStateGuard state_guard(interstitial);
interstitial->Show();
- interstitial->TestDidNavigate(1, url);
+ int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
+ interstitial->TestDidNavigate(1, interstitial_entry_id, true, url);
// Now close the contents.
DeleteContents();
@@ -1902,9 +1971,10 @@ TEST_F(WebContentsImplTest, ShowInterstitialThenCloseAndShutdown) {
new TestInterstitialPage(contents(), true, url, &state, &deleted);
TestInterstitialPageStateGuard state_guard(interstitial);
interstitial->Show();
- interstitial->TestDidNavigate(1, url);
- RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
- interstitial->GetRenderViewHostForTesting());
+ int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
+ interstitial->TestDidNavigate(1, interstitial_entry_id, true, url);
+ TestRenderFrameHost* rfh =
+ static_cast<TestRenderFrameHost*>(interstitial->GetMainFrame());
// Now close the contents.
DeleteContents();
@@ -1913,8 +1983,7 @@ TEST_F(WebContentsImplTest, ShowInterstitialThenCloseAndShutdown) {
// Before the interstitial has a chance to process its shutdown task,
// simulate quitting the browser. This goes through all processes and
// tells them to destruct.
- rvh->OnMessageReceived(
- ViewHostMsg_RenderProcessGone(0, 0, 0));
+ rfh->GetProcess()->SimulateCrash();
RunAllPendingInMessageLoop();
EXPECT_TRUE(deleted);
@@ -1925,7 +1994,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");
- contents()->GetMainFrame()->SendNavigate(1, url1);
+ main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1);
EXPECT_EQ(1, controller().GetEntryCount());
// Show an interstitial.
@@ -1937,7 +2006,8 @@ TEST_F(WebContentsImplTest, ShowInterstitialProceedMultipleCommands) {
new TestInterstitialPage(contents(), true, url2, &state, &deleted);
TestInterstitialPageStateGuard state_guard(interstitial);
interstitial->Show();
- interstitial->TestDidNavigate(1, url2);
+ int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
+ interstitial->TestDidNavigate(1, interstitial_entry_id, true, url2);
// Run a command.
EXPECT_EQ(0, interstitial->command_received_count());
@@ -1960,7 +2030,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");
- contents()->GetMainFrame()->SendNavigate(1, start_url);
+ main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, start_url);
EXPECT_EQ(1, controller().GetEntryCount());
// Show an interstitial.
@@ -1972,7 +2042,8 @@ TEST_F(WebContentsImplTest, ShowInterstitialOnInterstitial) {
new TestInterstitialPage(contents(), true, url1, &state1, &deleted1);
TestInterstitialPageStateGuard state_guard1(interstitial1);
interstitial1->Show();
- interstitial1->TestDidNavigate(1, url1);
+ int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
+ interstitial1->TestDidNavigate(1, interstitial_entry_id, true, url1);
// Now show another interstitial.
TestInterstitialPage::InterstitialState state2 =
@@ -1983,7 +2054,8 @@ TEST_F(WebContentsImplTest, ShowInterstitialOnInterstitial) {
new TestInterstitialPage(contents(), true, url2, &state2, &deleted2);
TestInterstitialPageStateGuard state_guard2(interstitial2);
interstitial2->Show();
- interstitial2->TestDidNavigate(1, url2);
+ interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
+ interstitial2->TestDidNavigate(1, interstitial_entry_id, true, url2);
// Showing interstitial2 should have caused interstitial1 to go away.
EXPECT_EQ(TestInterstitialPage::CANCELED, state1);
@@ -1996,12 +2068,12 @@ TEST_F(WebContentsImplTest, ShowInterstitialOnInterstitial) {
// Let's make sure interstitial2 is working as intended.
interstitial2->Proceed();
GURL landing_url("http://www.thepage.com");
- contents()->GetMainFrame()->SendNavigate(2, landing_url);
+ contents()->GetMainFrame()->SendNavigate(2, 0, true, landing_url);
EXPECT_FALSE(contents()->ShowingInterstitialPage());
- EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
+ EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
NavigationEntry* entry = controller().GetVisibleEntry();
- ASSERT_TRUE(entry != NULL);
+ ASSERT_NE(nullptr, entry);
EXPECT_TRUE(entry->GetURL() == landing_url);
EXPECT_EQ(2, controller().GetEntryCount());
RunAllPendingInMessageLoop();
@@ -2013,7 +2085,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");
- contents()->GetMainFrame()->SendNavigate(1, start_url);
+ main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, start_url);
EXPECT_EQ(1, controller().GetEntryCount());
// Show an interstitial.
@@ -2025,7 +2097,8 @@ TEST_F(WebContentsImplTest, ShowInterstitialProceedShowInterstitial) {
new TestInterstitialPage(contents(), true, url1, &state1, &deleted1);
TestInterstitialPageStateGuard state_guard1(interstitial1);
interstitial1->Show();
- interstitial1->TestDidNavigate(1, url1);
+ int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
+ interstitial1->TestDidNavigate(1, interstitial_entry_id, true, url1);
// Take action. The interstitial won't be hidden until the navigation is
// committed.
@@ -2042,7 +2115,8 @@ TEST_F(WebContentsImplTest, ShowInterstitialProceedShowInterstitial) {
new TestInterstitialPage(contents(), true, url2, &state2, &deleted2);
TestInterstitialPageStateGuard state_guard2(interstitial2);
interstitial2->Show();
- interstitial2->TestDidNavigate(1, url2);
+ interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
+ interstitial2->TestDidNavigate(1, interstitial_entry_id, true, url2);
// Showing interstitial2 should have caused interstitial1 to go away.
EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
@@ -2053,14 +2127,14 @@ TEST_F(WebContentsImplTest, ShowInterstitialProceedShowInterstitial) {
// Let's make sure interstitial2 is working as intended.
interstitial2->Proceed();
GURL landing_url("http://www.thepage.com");
- contents()->GetMainFrame()->SendNavigate(2, landing_url);
+ contents()->GetMainFrame()->SendNavigate(2, 0, true, landing_url);
RunAllPendingInMessageLoop();
EXPECT_TRUE(deleted2);
EXPECT_FALSE(contents()->ShowingInterstitialPage());
- EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
+ EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
NavigationEntry* entry = controller().GetVisibleEntry();
- ASSERT_TRUE(entry != NULL);
+ ASSERT_NE(nullptr, entry);
EXPECT_TRUE(entry->GetURL() == landing_url);
EXPECT_EQ(2, controller().GetEntryCount());
}
@@ -2078,6 +2152,7 @@ TEST_F(WebContentsImplTest, NavigateBeforeInterstitialShows) {
&state, &deleted);
TestInterstitialPageStateGuard state_guard(interstitial);
interstitial->Show();
+ int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
// Let's simulate a navigation initiated from the browser before the
// interstitial finishes loading.
@@ -2089,7 +2164,8 @@ TEST_F(WebContentsImplTest, NavigateBeforeInterstitialShows) {
ASSERT_FALSE(deleted);
// Now let's make the interstitial navigation commit.
- interstitial->TestDidNavigate(1, interstitial_url);
+ interstitial->TestDidNavigate(1, interstitial_entry_id, true,
+ interstitial_url);
// After it loaded the interstitial should be gone.
EXPECT_EQ(TestInterstitialPage::CANCELED, state);
@@ -2123,6 +2199,7 @@ TEST_F(WebContentsImplTest, TwoQuickInterstitials) {
&state2, &deleted2);
TestInterstitialPageStateGuard state_guard2(interstitial2);
interstitial2->Show();
+ int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
// The first interstitial should have been closed and deleted.
EXPECT_EQ(TestInterstitialPage::CANCELED, state1);
@@ -2134,7 +2211,8 @@ TEST_F(WebContentsImplTest, TwoQuickInterstitials) {
ASSERT_FALSE(deleted2);
// Make the interstitial navigation commit it should be showing.
- interstitial2->TestDidNavigate(1, interstitial_url);
+ interstitial2->TestDidNavigate(1, interstitial_entry_id, true,
+ interstitial_url);
EXPECT_EQ(interstitial2, contents()->GetInterstitialPage());
}
@@ -2161,7 +2239,8 @@ TEST_F(WebContentsImplTest, InterstitialCrasher) {
interstitial =
new TestInterstitialPage(contents(), true, url, &state, &deleted);
interstitial->Show();
- interstitial->TestDidNavigate(1, url);
+ int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
+ interstitial->TestDidNavigate(1, interstitial_entry_id, true, url);
// Simulate a renderer crash.
interstitial->TestRenderViewTerminated(
base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
@@ -2190,7 +2269,8 @@ TEST_F(WebContentsImplTest, NewInterstitialDoesNotCancelPendingEntry) {
new TestInterstitialPage(contents(), true, kGURL, &state, &deleted);
TestInterstitialPageStateGuard state_guard(interstitial);
interstitial->Show();
- interstitial->TestDidNavigate(1, kGURL);
+ int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
+ interstitial->TestDidNavigate(1, interstitial_entry_id, true, kGURL);
// Initiate a new navigation from the browser that also triggers an
// interstitial.
@@ -2203,7 +2283,8 @@ TEST_F(WebContentsImplTest, NewInterstitialDoesNotCancelPendingEntry) {
new TestInterstitialPage(contents(), true, kGURL, &state2, &deleted2);
TestInterstitialPageStateGuard state_guard2(interstitial2);
interstitial2->Show();
- interstitial2->TestDidNavigate(1, kGURL);
+ interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
+ interstitial2->TestDidNavigate(1, interstitial_entry_id, true, kGURL);
// Make sure we still have an entry.
NavigationEntry* entry = contents()->GetController().GetPendingEntry();
@@ -2227,9 +2308,11 @@ TEST_F(WebContentsImplTest, NoJSMessageOnInterstitials) {
// Start a navigation to a page
contents()->GetController().LoadURL(
kGURL, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ int entry_id = controller().GetPendingEntry()->GetUniqueID();
+ main_test_rfh()->PrepareForCommit();
// DidNavigate from the page
- contents()->TestDidNavigate(
- contents()->GetMainFrame(), 1, kGURL, ui::PAGE_TRANSITION_TYPED);
+ contents()->TestDidNavigate(contents()->GetMainFrame(), 1, entry_id, true,
+ kGURL, ui::PAGE_TRANSITION_TYPED);
// Simulate showing an interstitial while the page is showing.
TestInterstitialPage::InterstitialState state =
@@ -2239,7 +2322,8 @@ TEST_F(WebContentsImplTest, NoJSMessageOnInterstitials) {
new TestInterstitialPage(contents(), true, kGURL, &state, &deleted);
TestInterstitialPageStateGuard state_guard(interstitial);
interstitial->Show();
- interstitial->TestDidNavigate(1, kGURL);
+ int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
+ interstitial->TestDidNavigate(1, interstitial_entry_id, true, kGURL);
// While the interstitial is showing, let's simulate the hidden page
// attempting to show a JS message.
@@ -2256,7 +2340,7 @@ TEST_F(WebContentsImplTest, NoJSMessageOnInterstitials) {
TEST_F(WebContentsImplTest, CopyStateFromAndPruneSourceInterstitial) {
// Navigate to a page.
GURL url1("http://www.google.com");
- contents()->GetMainFrame()->SendNavigate(1, url1);
+ main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1);
EXPECT_EQ(1, controller().GetEntryCount());
// Initiate a browser navigation that will trigger the interstitial
@@ -2272,7 +2356,8 @@ TEST_F(WebContentsImplTest, CopyStateFromAndPruneSourceInterstitial) {
new TestInterstitialPage(contents(), true, url2, &state, &deleted);
TestInterstitialPageStateGuard state_guard(interstitial);
interstitial->Show();
- interstitial->TestDidNavigate(1, url2);
+ int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
+ interstitial->TestDidNavigate(1, interstitial_entry_id, true, url2);
EXPECT_TRUE(interstitial->is_showing());
EXPECT_EQ(2, controller().GetEntryCount());
@@ -2282,10 +2367,7 @@ TEST_F(WebContentsImplTest, CopyStateFromAndPruneSourceInterstitial) {
static_cast<TestWebContents*>(CreateTestWebContents()));
NavigationControllerImpl& other_controller = other_contents->GetController();
other_contents->NavigateAndCommit(url3);
- other_contents->ExpectSetHistoryLengthAndPrune(
- NavigationEntryImpl::FromNavigationEntry(
- other_controller.GetEntryAtIndex(0))->site_instance(), 1,
- other_controller.GetEntryAtIndex(0)->GetPageID());
+ other_contents->ExpectSetHistoryOffsetAndLength(1, 2);
other_controller.CopyStateFromAndPrune(&controller(), false);
// The merged controller should only have two entries: url1 and url2.
@@ -2324,7 +2406,9 @@ TEST_F(WebContentsImplTest, CopyStateFromAndPruneTargetInterstitial) {
&deleted);
TestInterstitialPageStateGuard state_guard(interstitial);
interstitial->Show();
- interstitial->TestDidNavigate(1, url3);
+ int interstitial_entry_id =
+ other_controller.GetTransientEntry()->GetUniqueID();
+ interstitial->TestDidNavigate(1, interstitial_entry_id, true, url3);
EXPECT_TRUE(interstitial->is_showing());
EXPECT_EQ(2, other_controller.GetEntryCount());
@@ -2373,7 +2457,7 @@ TEST_F(WebContentsImplTest, PendingContents) {
contents()->AddPendingContents(other_contents.get());
int route_id = other_contents->GetRenderViewHost()->GetRoutingID();
other_contents.reset();
- EXPECT_EQ(NULL, contents()->GetCreatedWindow(route_id));
+ EXPECT_EQ(nullptr, contents()->GetCreatedWindow(route_id));
}
TEST_F(WebContentsImplTest, CapturerOverridesPreferredSize) {
@@ -2419,6 +2503,66 @@ TEST_F(WebContentsImplTest, CapturerOverridesPreferredSize) {
EXPECT_EQ(original_preferred_size, contents()->GetPreferredSize());
}
+TEST_F(WebContentsImplTest, CapturerPreventsHiding) {
+ const gfx::Size original_preferred_size(1024, 768);
+ contents()->UpdatePreferredSize(original_preferred_size);
+
+ TestRenderWidgetHostView* view = static_cast<TestRenderWidgetHostView*>(
+ contents()->GetMainFrame()->GetRenderViewHost()->GetView());
+
+ // With no capturers, setting and un-setting occlusion should change the
+ // view's occlusion state.
+ EXPECT_FALSE(view->is_showing());
+ contents()->WasShown();
+ EXPECT_TRUE(view->is_showing());
+ contents()->WasHidden();
+ EXPECT_FALSE(view->is_showing());
+ contents()->WasShown();
+ EXPECT_TRUE(view->is_showing());
+
+ // Add a capturer and try to hide the contents. The view will remain visible.
+ contents()->IncrementCapturerCount(gfx::Size());
+ contents()->WasHidden();
+ EXPECT_TRUE(view->is_showing());
+
+ // Remove the capturer, and the WasHidden should take effect.
+ contents()->DecrementCapturerCount();
+ EXPECT_FALSE(view->is_showing());
+}
+
+TEST_F(WebContentsImplTest, CapturerPreventsOcclusion) {
+ const gfx::Size original_preferred_size(1024, 768);
+ contents()->UpdatePreferredSize(original_preferred_size);
+
+ TestRenderWidgetHostView* view = static_cast<TestRenderWidgetHostView*>(
+ contents()->GetMainFrame()->GetRenderViewHost()->GetView());
+
+ // With no capturers, setting and un-setting occlusion should change the
+ // view's occlusion state.
+ EXPECT_FALSE(view->is_occluded());
+ contents()->WasOccluded();
+ EXPECT_TRUE(view->is_occluded());
+ contents()->WasUnOccluded();
+ EXPECT_FALSE(view->is_occluded());
+ contents()->WasOccluded();
+ EXPECT_TRUE(view->is_occluded());
+
+ // Add a capturer. This should cause the view to be un-occluded.
+ contents()->IncrementCapturerCount(gfx::Size());
+ EXPECT_FALSE(view->is_occluded());
+
+ // Try to occlude the view. This will fail to propagate because of the
+ // active capturer.
+ contents()->WasOccluded();
+ EXPECT_FALSE(view->is_occluded());
+
+ // Remove the capturer and try again.
+ contents()->DecrementCapturerCount();
+ EXPECT_FALSE(view->is_occluded());
+ contents()->WasOccluded();
+ EXPECT_TRUE(view->is_occluded());
+}
+
// Tests that GetLastActiveTime starts with a real, non-zero time and updates
// on activity.
TEST_F(WebContentsImplTest, GetLastActiveTime) {
@@ -2479,15 +2623,18 @@ TEST_F(WebContentsImplTest, HandleWheelEvent) {
EXPECT_FALSE(contents()->HandleWheelEvent(event));
EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
- modifiers = WebInputEvent::ShiftKey | WebInputEvent::AltKey;
+ modifiers = WebInputEvent::ShiftKey | WebInputEvent::AltKey |
+ WebInputEvent::ControlKey;
event = SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers, false);
EXPECT_FALSE(contents()->HandleWheelEvent(event));
EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
- // But whenever the ctrl modifier is applied, they can increase/decrease zoom.
- // Except on MacOS where we never want to adjust zoom with mousewheel.
+ // But whenever the ctrl modifier is applied with canScroll=false, they can
+ // increase/decrease zoom. Except on MacOS where we never want to adjust zoom
+ // with mousewheel.
modifiers = WebInputEvent::ControlKey;
event = SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers, false);
+ event.canScroll = false;
bool handled = contents()->HandleWheelEvent(event);
#if defined(OS_MACOSX)
EXPECT_FALSE(handled);
@@ -2501,6 +2648,7 @@ TEST_F(WebContentsImplTest, HandleWheelEvent) {
modifiers = WebInputEvent::ControlKey | WebInputEvent::ShiftKey |
WebInputEvent::AltKey;
event = SyntheticWebMouseWheelEventBuilder::Build(2, -5, modifiers, false);
+ event.canScroll = false;
handled = contents()->HandleWheelEvent(event);
#if defined(OS_MACOSX)
EXPECT_FALSE(handled);
@@ -2525,57 +2673,7 @@ TEST_F(WebContentsImplTest, HandleWheelEvent) {
EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
// Ensure pointers to the delegate aren't kept beyond its lifetime.
- contents()->SetDelegate(NULL);
-}
-
-// Tests that trackpad GesturePinchUpdate events get turned into browser zoom.
-TEST_F(WebContentsImplTest, HandleGestureEvent) {
- using blink::WebGestureEvent;
- using blink::WebInputEvent;
-
- scoped_ptr<ContentsZoomChangedDelegate> delegate(
- new ContentsZoomChangedDelegate());
- contents()->SetDelegate(delegate.get());
-
- const float kZoomStepValue = 0.6f;
- blink::WebGestureEvent event = SyntheticWebGestureEventBuilder::Build(
- WebInputEvent::GesturePinchUpdate, blink::WebGestureDeviceTouchpad);
-
- // A pinch less than the step value doesn't change the zoom level.
- event.data.pinchUpdate.scale = 1.0f + kZoomStepValue * 0.8f;
- EXPECT_TRUE(contents()->HandleGestureEvent(event));
- EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
-
- // But repeating the event so the combined scale is greater does.
- EXPECT_TRUE(contents()->HandleGestureEvent(event));
- EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
- EXPECT_TRUE(delegate->last_zoom_in());
-
- // Pinching back out one step goes back to 100%.
- event.data.pinchUpdate.scale = 1.0f - kZoomStepValue;
- EXPECT_TRUE(contents()->HandleGestureEvent(event));
- EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
- EXPECT_FALSE(delegate->last_zoom_in());
-
- // Pinching out again doesn't zoom (step is twice as large around 100%).
- EXPECT_TRUE(contents()->HandleGestureEvent(event));
- EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
-
- // And again now it zooms once per step.
- EXPECT_TRUE(contents()->HandleGestureEvent(event));
- EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
- EXPECT_FALSE(delegate->last_zoom_in());
-
- // No other type of gesture event is handled by WebContentsImpl (for example
- // a touchscreen pinch gesture).
- event = SyntheticWebGestureEventBuilder::Build(
- WebInputEvent::GesturePinchUpdate, blink::WebGestureDeviceTouchscreen);
- event.data.pinchUpdate.scale = 1.0f + kZoomStepValue * 3;
- EXPECT_FALSE(contents()->HandleGestureEvent(event));
- EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
-
- // Ensure pointers to the delegate aren't kept beyond it's lifetime.
- contents()->SetDelegate(NULL);
+ contents()->SetDelegate(nullptr);
}
// Tests that GetRelatedActiveContentsCount is shared between related
@@ -2639,13 +2737,19 @@ TEST_F(WebContentsImplTest, ActiveContentsCountNavigate) {
EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
// Navigate to a URL in a different site.
- contents->GetController().LoadURL(GURL("http://b.com"),
+ const GURL kUrl = GURL("http://b.com");
+ contents->GetController().LoadURL(kUrl,
Referrer(),
ui::PAGE_TRANSITION_TYPED,
std::string());
- EXPECT_TRUE(contents->cross_navigation_pending());
+ int entry_id = contents->GetController().GetPendingEntry()->GetUniqueID();
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation)) {
+ contents->GetMainFrame()->PrepareForCommit();
+ }
+ EXPECT_TRUE(contents->CrossProcessNavigationPending());
EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
- contents->CommitPendingNavigation();
+ contents->GetPendingMainFrame()->SendNavigate(1, entry_id, true, kUrl);
EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
contents.reset();
@@ -2668,12 +2772,19 @@ TEST_F(WebContentsImplTest, ActiveContentsCountChangeBrowsingInstance) {
contents->NavigateAndCommit(GURL("http://a.com"));
EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
+ // Navigate to a URL which sort of looks like a chrome:// url.
+ contents->NavigateAndCommit(GURL("http://gpu"));
+ EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
+
// Navigate to a URL with WebUI. This will change BrowsingInstances.
- contents->GetController().LoadURL(GURL(kTestWebUIUrl),
+ const GURL kWebUIUrl = GURL("chrome://gpu");
+ contents->GetController().LoadURL(kWebUIUrl,
Referrer(),
ui::PAGE_TRANSITION_TYPED,
std::string());
- EXPECT_TRUE(contents->cross_navigation_pending());
+ int entry_id = contents->GetController().GetPendingEntry()->GetUniqueID();
+ contents->GetMainFrame()->PrepareForCommit();
+ EXPECT_TRUE(contents->CrossProcessNavigationPending());
scoped_refptr<SiteInstance> instance_webui(
contents->GetPendingMainFrame()->GetSiteInstance());
EXPECT_FALSE(instance->IsRelatedSiteInstance(instance_webui.get()));
@@ -2683,7 +2794,7 @@ TEST_F(WebContentsImplTest, ActiveContentsCountChangeBrowsingInstance) {
EXPECT_EQ(0u, instance_webui->GetRelatedActiveContentsCount());
// Commit and contents counts for the new one.
- contents->CommitPendingNavigation();
+ contents->GetPendingMainFrame()->SendNavigate(1, entry_id, true, kWebUIUrl);
EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
EXPECT_EQ(1u, instance_webui->GetRelatedActiveContentsCount());
@@ -2692,8 +2803,205 @@ TEST_F(WebContentsImplTest, ActiveContentsCountChangeBrowsingInstance) {
EXPECT_EQ(0u, instance_webui->GetRelatedActiveContentsCount());
}
-// ChromeOS doesn't use WebContents based power save blocking.
-#if !defined(OS_CHROMEOS)
+class LoadingWebContentsObserver : public WebContentsObserver {
+ public:
+ explicit LoadingWebContentsObserver(WebContents* contents)
+ : WebContentsObserver(contents),
+ is_loading_(false) {
+ }
+ ~LoadingWebContentsObserver() override {}
+
+ void DidStartLoading() override { is_loading_ = true; }
+ void DidStopLoading() override { is_loading_ = false; }
+
+ bool is_loading() const { return is_loading_; }
+
+ private:
+ bool is_loading_;
+
+ DISALLOW_COPY_AND_ASSIGN(LoadingWebContentsObserver);
+};
+
+// Ensure that DidStartLoading/DidStopLoading events balance out properly with
+// interleaving cross-process navigations in multiple subframes.
+// See https://crbug.com/448601 for details of the underlying issue. The
+// sequence of events that reproduce it are as follows:
+// * Navigate top-level frame with one subframe.
+// * Subframe navigates more than once before the top-level frame has had a
+// chance to complete the load.
+// The subframe navigations cause the loading_frames_in_progress_ to drop down
+// to 0, while the loading_progresses_ map is not reset.
+TEST_F(WebContentsImplTest, StartStopEventsBalance) {
+ // The bug manifests itself in regular mode as well, but browser-initiated
+ // navigation of subframes is only possible in --site-per-process mode within
+ // unit tests.
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kSitePerProcess);
+ const GURL initial_url("about:blank");
+ const GURL main_url("http://www.chromium.org");
+ const GURL foo_url("http://foo.chromium.org");
+ const GURL bar_url("http://bar.chromium.org");
+ TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
+
+ // Use a WebContentsObserver to approximate the behavior of the tab's spinner.
+ LoadingWebContentsObserver observer(contents());
+
+ // Navigate the main RenderFrame, simulate the DidStartLoading, and commit.
+ // The frame should still be loading.
+ controller().LoadURL(
+ main_url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ int entry_id = controller().GetPendingEntry()->GetUniqueID();
+ orig_rfh->PrepareForCommit();
+ orig_rfh->OnMessageReceived(
+ FrameHostMsg_DidStartLoading(orig_rfh->GetRoutingID(), false));
+ contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, main_url,
+ ui::PAGE_TRANSITION_TYPED);
+ EXPECT_FALSE(contents()->CrossProcessNavigationPending());
+ EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
+ EXPECT_TRUE(contents()->IsLoading());
+ EXPECT_TRUE(observer.is_loading());
+
+ // Create a child frame to navigate multiple times.
+ TestRenderFrameHost* subframe = orig_rfh->AppendChild("subframe");
+
+ // Navigate the child frame to about:blank, which will send both
+ // DidStartLoading and DidStopLoading messages.
+ {
+ subframe->SendRendererInitiatedNavigationRequest(initial_url, false);
+ subframe->PrepareForCommit();
+ subframe->OnMessageReceived(
+ FrameHostMsg_DidStartLoading(subframe->GetRoutingID(), true));
+ subframe->SendNavigateWithTransition(1, 0, false, initial_url,
+ ui::PAGE_TRANSITION_AUTO_SUBFRAME);
+ subframe->OnMessageReceived(
+ FrameHostMsg_DidStopLoading(subframe->GetRoutingID()));
+ }
+
+ // Navigate the frame to another URL, which will send again
+ // DidStartLoading and DidStopLoading messages.
+ {
+ subframe->SendRendererInitiatedNavigationRequest(foo_url, false);
+ subframe->PrepareForCommit();
+ subframe->OnMessageReceived(
+ FrameHostMsg_DidStartLoading(subframe->GetRoutingID(), true));
+ subframe->SendNavigateWithTransition(1, 0, false, foo_url,
+ ui::PAGE_TRANSITION_AUTO_SUBFRAME);
+ subframe->OnMessageReceived(
+ FrameHostMsg_DidStopLoading(subframe->GetRoutingID()));
+ }
+
+ // Since the main frame hasn't sent any DidStopLoading messages, it is
+ // expected that the WebContents is still in loading state.
+ EXPECT_TRUE(contents()->IsLoading());
+ EXPECT_TRUE(observer.is_loading());
+
+ // Navigate the frame again, this time using LoadURLWithParams. This causes
+ // RenderFrameHost to call into WebContents::DidStartLoading, which starts
+ // the spinner.
+ {
+ NavigationController::LoadURLParams load_params(bar_url);
+ load_params.referrer =
+ Referrer(GURL("http://referrer"), blink::WebReferrerPolicyDefault);
+ 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 = false;
+ load_params.override_user_agent = NavigationController::UA_OVERRIDE_TRUE;
+ load_params.frame_tree_node_id =
+ subframe->frame_tree_node()->frame_tree_node_id();
+ controller().LoadURLWithParams(load_params);
+ entry_id = controller().GetPendingEntry()->GetUniqueID();
+
+ subframe->OnMessageReceived(
+ FrameHostMsg_DidStartLoading(subframe->GetRoutingID(), true));
+
+ // Commit the navigation in the child frame and send the DidStopLoading
+ // message.
+ subframe->PrepareForCommit();
+ contents()->TestDidNavigate(subframe, 3, entry_id, true, bar_url,
+ ui::PAGE_TRANSITION_MANUAL_SUBFRAME);
+ subframe->OnMessageReceived(
+ FrameHostMsg_DidStopLoading(subframe->GetRoutingID()));
+ }
+
+ // At this point the status should still be loading, since the main frame
+ // hasn't sent the DidstopLoading message yet.
+ EXPECT_TRUE(contents()->IsLoading());
+ EXPECT_TRUE(observer.is_loading());
+
+ // Send the DidStopLoading for the main frame and ensure it isn't loading
+ // anymore.
+ orig_rfh->OnMessageReceived(
+ FrameHostMsg_DidStopLoading(orig_rfh->GetRoutingID()));
+ EXPECT_FALSE(contents()->IsLoading());
+ EXPECT_FALSE(observer.is_loading());
+}
+
+// Ensure that WebContentsImpl does not stop loading too early when there still
+// is a pending renderer. This can happen if a same-process non user-initiated
+// navigation completes while there is an ongoing cross-process navigation.
+// TODO(fdegans): Rewrite the test for PlzNavigate when DidStartLoading and
+// DidStopLoading are properly called.
+TEST_F(WebContentsImplTest, NoEarlyStop) {
+ const GURL kUrl1("http://www.chromium.org");
+ const GURL kUrl2("http://www.google.com");
+ const GURL kUrl3("http://www.wikipedia.org");
+
+ contents()->NavigateAndCommit(kUrl1);
+
+ TestRenderFrameHost* current_rfh = contents()->GetMainFrame();
+
+ // Start a browser-initiated cross-process navigation to |kUrl2|. There should
+ // be a pending RenderFrameHost and the WebContents should be loading.
+ controller().LoadURL(
+ kUrl2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ int entry_id = controller().GetPendingEntry()->GetUniqueID();
+ EXPECT_TRUE(contents()->CrossProcessNavigationPending());
+ TestRenderFrameHost* pending_rfh = contents()->GetPendingMainFrame();
+ ASSERT_TRUE(pending_rfh);
+ EXPECT_TRUE(contents()->IsLoading());
+
+ // The current RenderFrameHost starts a non user-initiated render-initiated
+ // navigation and sends a DidStartLoading IPC. The WebContents should still be
+ // loading.
+ current_rfh->OnMessageReceived(
+ FrameHostMsg_DidStartLoading(current_rfh->GetRoutingID(), false));
+ EXPECT_TRUE(contents()->IsLoading());
+
+ // Simulate the pending RenderFrameHost DidStartLoading. There should still be
+ // a pending RenderFrameHost and the WebContents should still be loading.
+ pending_rfh->PrepareForCommit();
+ pending_rfh->OnMessageReceived(
+ FrameHostMsg_DidStartLoading(pending_rfh->GetRoutingID(), false));
+ EXPECT_EQ(contents()->GetPendingMainFrame(), pending_rfh);
+ EXPECT_TRUE(contents()->IsLoading());
+
+ // Simulate the commit and DidStopLoading from the renderer-initiated
+ // navigation in the current RenderFrameHost. There should still be a pending
+ // RenderFrameHost and the WebContents should still be loading.
+ current_rfh->SendNavigate(1, 0, true, kUrl3);
+ current_rfh->OnMessageReceived(
+ FrameHostMsg_DidStopLoading(current_rfh->GetRoutingID()));
+ EXPECT_EQ(contents()->GetPendingMainFrame(), pending_rfh);
+ EXPECT_TRUE(contents()->IsLoading());
+
+ // Commit the navigation. The formerly pending RenderFrameHost should now be
+ // the current RenderFrameHost and the WebContents should still be loading.
+ contents()->TestDidNavigate(pending_rfh, 1, entry_id, true, kUrl2,
+ ui::PAGE_TRANSITION_TYPED);
+ EXPECT_FALSE(contents()->GetPendingMainFrame());
+ TestRenderFrameHost* new_current_rfh = contents()->GetMainFrame();
+ EXPECT_EQ(new_current_rfh, pending_rfh);
+ EXPECT_TRUE(contents()->IsLoading());
+
+ // Simulate the new current RenderFrameHost DidStopLoading. The WebContents
+ // should now have stopped loading.
+ new_current_rfh->OnMessageReceived(
+ FrameHostMsg_DidStopLoading(new_current_rfh->GetRoutingID()));
+ EXPECT_EQ(contents()->GetMainFrame(), new_current_rfh);
+ EXPECT_FALSE(contents()->IsLoading());
+}
+
TEST_F(WebContentsImplTest, MediaPowerSaveBlocking) {
// PlayerIDs are actually pointers cast to int64, so verify that both negative
// and positive player ids don't blow up.
@@ -2706,20 +3014,20 @@ TEST_F(WebContentsImplTest, MediaPowerSaveBlocking) {
EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
TestRenderFrameHost* rfh = contents()->GetMainFrame();
- AudioStreamMonitor* monitor = contents()->audio_stream_monitor();
+ AudioStateProvider* audio_state = contents()->audio_state_provider();
// The audio power save blocker should not be based on having a media player
// when audio stream monitoring is available.
- if (AudioStreamMonitor::monitoring_available()) {
+ if (audio_state->IsAudioStateAvailable()) {
// Send a fake audio stream monitor notification. The audio power save
// blocker should be created.
- monitor->set_was_recently_audible_for_testing(true);
+ audio_state->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);
+ audio_state->set_was_recently_audible_for_testing(false);
contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB);
EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
}
@@ -2731,7 +3039,7 @@ TEST_F(WebContentsImplTest, MediaPowerSaveBlocking) {
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());
+ !audio_state->IsAudioStateAvailable());
// Upon hiding the video power save blocker should be released.
contents()->WasHidden();
@@ -2744,7 +3052,7 @@ TEST_F(WebContentsImplTest, MediaPowerSaveBlocking) {
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());
+ !audio_state->IsAudioStateAvailable());
// Showing the WebContents should result in the creation of the blocker.
contents()->WasShown();
@@ -2756,7 +3064,7 @@ TEST_F(WebContentsImplTest, MediaPowerSaveBlocking) {
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());
+ !audio_state->IsAudioStateAvailable());
// Start a remote player. There should be no change in the power save
// blockers.
@@ -2764,7 +3072,7 @@ TEST_F(WebContentsImplTest, MediaPowerSaveBlocking) {
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());
+ !audio_state->IsAudioStateAvailable());
// Destroy the original audio video player. Both power save blockers should
// remain.
@@ -2772,7 +3080,7 @@ TEST_F(WebContentsImplTest, MediaPowerSaveBlocking) {
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());
+ !audio_state->IsAudioStateAvailable());
// Destroy the audio only player. The video power save blocker should remain.
rfh->OnMessageReceived(
@@ -2791,7 +3099,22 @@ TEST_F(WebContentsImplTest, MediaPowerSaveBlocking) {
FrameHostMsg_MediaPausedNotification(0, kPlayerRemoteId));
EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
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(),
+ !audio_state->IsAudioStateAvailable());
+
+ // Crash the renderer.
+ contents()->GetMainFrame()->GetProcess()->SimulateCrash();
+
+ // Verify that all the power save blockers have been released.
+ 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_view.h b/chromium/content/browser/web_contents/web_contents_view.h
index 47daee9bac8..439dda4fbcf 100644
--- a/chromium/content/browser/web_contents/web_contents_view.h
+++ b/chromium/content/browser/web_contents/web_contents_view.h
@@ -10,9 +10,9 @@
#include "base/basictypes.h"
#include "base/strings/string16.h"
#include "content/common/content_export.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/size.h"
namespace content {
class RenderViewHost;
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 b276b191409..c7e1cbbf1aa 100644
--- a/chromium/content/browser/web_contents/web_contents_view_android.cc
+++ b/chromium/content/browser/web_contents/web_contents_view_android.cc
@@ -45,9 +45,10 @@ void WebContentsViewAndroid::SetContentViewCore(
if (web_contents_->ShowingInterstitialPage()) {
rwhv = static_cast<RenderWidgetHostViewAndroid*>(
- static_cast<InterstitialPageImpl*>(
- web_contents_->GetInterstitialPage())->
- GetRenderViewHost()->GetView());
+ web_contents_->GetInterstitialPage()
+ ->GetMainFrame()
+ ->GetRenderViewHost()
+ ->GetView());
if (rwhv)
rwhv->SetContentViewCore(content_view_core_);
}
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 c480c0e9bd9..9f7216f6577 100644
--- a/chromium/content/browser/web_contents/web_contents_view_android.h
+++ b/chromium/content/browser/web_contents/web_contents_view_android.h
@@ -10,7 +10,7 @@
#include "content/browser/web_contents/web_contents_view.h"
#include "content/public/browser/web_contents_view_delegate.h"
#include "content/public/common/context_menu_params.h"
-#include "ui/gfx/rect_f.h"
+#include "ui/gfx/geometry/rect_f.h"
namespace content {
class ContentViewCoreImpl;
@@ -22,7 +22,7 @@ class WebContentsViewAndroid : public WebContentsView,
public:
WebContentsViewAndroid(WebContentsImpl* web_contents,
WebContentsViewDelegate* delegate);
- virtual ~WebContentsViewAndroid();
+ ~WebContentsViewAndroid() override;
// Sets the interface to the view system. ContentViewCoreImpl is owned
// by its Java ContentViewCore counterpart, whose lifetime is managed
@@ -30,48 +30,49 @@ 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 void CreateView(
- const gfx::Size& initial_size, gfx::NativeView context) override;
- virtual RenderWidgetHostViewBase* CreateViewForWidget(
- RenderWidgetHost* render_widget_host, bool is_guest_view_hack) override;
- virtual RenderWidgetHostViewBase* CreateViewForPopupWidget(
+ 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;
- 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;
+ void SetPageTitle(const base::string16& title) override;
+ void RenderViewCreated(RenderViewHost* host) override;
+ void RenderViewSwappedIn(RenderViewHost* host) override;
+ void SetOverscrollControllerEnabled(bool enabled) override;
// Backend implementation of RenderViewHostDelegateView.
- virtual void ShowContextMenu(RenderFrameHost* render_frame_host,
- 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;
- 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 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_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 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 056bb3e3cc3..705fbb912c3 100644
--- a/chromium/content/browser/web_contents/web_contents_view_aura.cc
+++ b/chromium/content/browser/web_contents/web_contents_view_aura.cc
@@ -7,7 +7,6 @@
#include "base/auto_reset.h"
#include "base/command_line.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"
#include "content/browser/download/drag_download_util.h"
@@ -21,10 +20,7 @@
#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"
-#include "content/browser/web_contents/aura/shadow_layer_delegate.h"
-#include "content/browser/web_contents/aura/window_slider.h"
#include "content/browser/web_contents/touch_editable_impl_aura.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/content_browser_client.h"
@@ -60,24 +56,16 @@
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/base/hit_test.h"
#include "ui/compositor/layer.h"
-#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/events/event.h"
#include "ui/events/event_utils.h"
#include "ui/gfx/canvas.h"
#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,
@@ -95,18 +83,6 @@ bool IsScrollEndEffectEnabled() {
switches::kScrollEndEffect) == "1";
}
-bool ShouldNavigateForward(const NavigationController& controller,
- OverscrollMode mode) {
- return mode == (base::i18n::IsRTL() ? OVERSCROLL_EAST : OVERSCROLL_WEST) &&
- controller.CanGoForward();
-}
-
-bool ShouldNavigateBack(const NavigationController& controller,
- OverscrollMode mode) {
- return mode == (base::i18n::IsRTL() ? OVERSCROLL_WEST : OVERSCROLL_EAST) &&
- controller.CanGoBack();
-}
-
RenderWidgetHostViewAura* ToRenderWidgetHostViewAura(
RenderWidgetHostView* view) {
if (!view || RenderViewHostFactory::has_factory())
@@ -120,67 +96,6 @@ RenderWidgetHostViewAura* ToRenderWidgetHostViewAura(
return static_cast<RenderWidgetHostViewAura*>(view);
}
-// The window delegate for the overscroll window. This redirects trackpad events
-// to the web-contents window. The delegate destroys itself when the window is
-// destroyed.
-class OverscrollWindowDelegate : public ImageWindowDelegate {
- public:
- OverscrollWindowDelegate(WebContentsImpl* web_contents,
- OverscrollMode overscroll_mode)
- : web_contents_(web_contents),
- forward_events_(true) {
- const NavigationControllerImpl& controller = web_contents->GetController();
- const NavigationEntryImpl* entry = NULL;
- if (ShouldNavigateForward(controller, overscroll_mode)) {
- entry = NavigationEntryImpl::FromNavigationEntry(
- controller.GetEntryAtOffset(1));
- } else if (ShouldNavigateBack(controller, overscroll_mode)) {
- entry = NavigationEntryImpl::FromNavigationEntry(
- controller.GetEntryAtOffset(-1));
- }
-
- gfx::Image image;
- if (entry && entry->screenshot().get()) {
- std::vector<gfx::ImagePNGRep> image_reps;
- image_reps.push_back(gfx::ImagePNGRep(entry->screenshot(), 1.0f));
- image = gfx::Image(image_reps);
- }
- SetImage(image);
- }
-
- void stop_forwarding_events() { forward_events_ = false; }
-
- private:
- ~OverscrollWindowDelegate() override {}
-
- aura::Window* web_contents_window() {
- return web_contents_->GetView()->GetContentNativeView();
- }
-
- // Overridden from ui::EventHandler.
- void OnScrollEvent(ui::ScrollEvent* event) override {
- if (forward_events_ && web_contents_window())
- web_contents_window()->delegate()->OnScrollEvent(event);
- }
-
- void OnGestureEvent(ui::GestureEvent* event) override {
- if (forward_events_ && web_contents_window())
- web_contents_window()->delegate()->OnGestureEvent(event);
- }
-
- WebContentsImpl* web_contents_;
-
- // The window is displayed both during the gesture, and after the gesture
- // while the navigation is in progress. During the gesture, it is necessary to
- // forward input events to the content page (e.g. when the overscroll window
- // slides under the cursor and starts receiving scroll events). However, once
- // the gesture is complete, and the window is being displayed as an overlay
- // window during navigation, events should not be forwarded anymore.
- bool forward_events_;
-
- DISALLOW_COPY_AND_ASSIGN(OverscrollWindowDelegate);
-};
-
// Listens to all mouse drag events during a drag and drop and sends them to
// the renderer.
class WebDragSourceAura : public NotificationObserver {
@@ -329,15 +244,14 @@ bool ReadFileSystemFilesFromPickle(
PickleIterator iter(pickle);
size_t num_files = 0;
- if (!pickle.ReadSizeT(&iter, &num_files))
+ if (!iter.ReadSizeT(&num_files))
return false;
file_system_files->resize(num_files);
for (size_t i = 0; i < num_files; ++i) {
std::string url_string;
int64 size = 0;
- if (!pickle.ReadString(&iter, &url_string) ||
- !pickle.ReadInt64(&iter, &size))
+ if (!iter.ReadString(&url_string) || !iter.ReadInt64(&size))
return false;
GURL url(url_string);
@@ -466,6 +380,12 @@ int ConvertAuraEventFlagsToWebInputEventModifiers(int aura_event_flags) {
web_input_event_modifiers |= blink::WebInputEvent::AltKey;
if (aura_event_flags & ui::EF_COMMAND_DOWN)
web_input_event_modifiers |= blink::WebInputEvent::MetaKey;
+ if (aura_event_flags & ui::EF_LEFT_MOUSE_BUTTON)
+ web_input_event_modifiers |= blink::WebInputEvent::LeftButtonDown;
+ if (aura_event_flags & ui::EF_MIDDLE_MOUSE_BUTTON)
+ web_input_event_modifiers |= blink::WebInputEvent::MiddleButtonDown;
+ if (aura_event_flags & ui::EF_RIGHT_MOUSE_BUTTON)
+ web_input_event_modifiers |= blink::WebInputEvent::RightButtonDown;
return web_input_event_modifiers;
}
@@ -508,21 +428,6 @@ class WebContentsViewAura::WindowObserver
#endif
}
- // 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
@@ -530,7 +435,7 @@ 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 {
+ void OnWindowAdded(aura::Window* new_window) override {
if (!new_window->Contains(view_->window_.get())) {
// Skip the case when the parent moves to the root window.
if (new_window != host_window_) {
@@ -548,7 +453,7 @@ class WebContentsViewAura::WindowObserver
}
}
- virtual void OnWillRemoveWindow(aura::Window* window) override {
+ void OnWillRemoveWindow(aura::Window* window) override {
if (window == view_->window_)
return;
@@ -556,8 +461,7 @@ class WebContentsViewAura::WindowObserver
UpdateConstrainedWindows(window);
}
- virtual void OnWindowVisibilityChanged(aura::Window* window,
- bool visible) override {
+ void OnWindowVisibilityChanged(aura::Window* window, bool visible) override {
if (window == view_->window_ ||
window->parent() == host_window_ ||
window->parent() == view_->window_->GetRootWindow()) {
@@ -648,10 +552,6 @@ class WebContentsViewAura::WindowObserver
#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
}
}
@@ -671,9 +571,6 @@ class WebContentsViewAura::WindowObserver
root_children[i]->RemoveObserver(this);
}
}
-
- if (view_->legacy_hwnd_)
- view_->legacy_hwnd_->UpdateParent(ui::GetHiddenWindow());
#endif
}
}
@@ -742,17 +639,16 @@ class WebContentsViewAura::WindowObserver
////////////////////////////////////////////////////////////////////////////////
// WebContentsViewAura, public:
-WebContentsViewAura::WebContentsViewAura(
- WebContentsImpl* web_contents,
- WebContentsViewDelegate* delegate)
+WebContentsViewAura::WebContentsViewAura(WebContentsImpl* web_contents,
+ WebContentsViewDelegate* delegate)
: web_contents_(web_contents),
delegate_(delegate),
current_drag_op_(blink::WebDragOperationNone),
drag_dest_delegate_(NULL),
current_rvh_for_drag_(NULL),
- overscroll_change_brightness_(false),
current_overscroll_gesture_(OVERSCROLL_NONE),
completed_overscroll_gesture_(OVERSCROLL_NONE),
+ navigation_overlay_(nullptr),
touch_editable_(TouchEditableImplAura::Create()),
is_or_was_visible_(false) {
}
@@ -817,178 +713,18 @@ void WebContentsViewAura::InstallOverscrollControllerDelegate(
return;
}
view->overscroll_controller()->set_delegate(this);
- if (!navigation_overlay_)
- navigation_overlay_.reset(new OverscrollNavigationOverlay(web_contents_));
-}
-
-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 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_) {
- base::AutoReset<OverscrollMode> reset_state(&current_overscroll_gesture_,
- current_overscroll_gesture_);
- scoped_ptr<aura::Window> reset_window(overscroll_window_.release());
- }
-
- OverscrollWindowDelegate* overscroll_delegate = new OverscrollWindowDelegate(
- web_contents_,
- current_overscroll_gesture_);
- overscroll_window_.reset(new aura::Window(overscroll_delegate));
- overscroll_window_->SetType(ui::wm::WINDOW_TYPE_CONTROL);
- overscroll_window_->SetTransparent(true);
- overscroll_window_->Init(aura::WINDOW_LAYER_TEXTURED);
- overscroll_window_->layer()->SetMasksToBounds(false);
- overscroll_window_->SetName("OverscrollOverlay");
-
- overscroll_change_brightness_ = overscroll_delegate->has_image();
- window_->AddChild(overscroll_window_.get());
-
- gfx::Rect bounds = gfx::Rect(window_->bounds().size());
- if (ShouldNavigateForward(web_contents_->GetController(),
- current_overscroll_gesture_)) {
- // The overlay will be sliding in from the right edge towards the left in
- // non-RTL, or sliding in from the left edge towards the right in RTL.
- // So position the overlay window accordingly.
- bounds.Offset(base::i18n::IsRTL() ? -bounds.width() : bounds.width(), 0);
- }
-
- aura::Window* animate_window = GetWindowToAnimateForOverscroll();
- if (animate_window == overscroll_window_)
- window_->StackChildAbove(overscroll_window_.get(), GetContentNativeView());
- else
- window_->StackChildBelow(overscroll_window_.get(), GetContentNativeView());
-
- UpdateOverscrollWindowBrightness(0.f);
-
- overscroll_window_->SetBounds(bounds);
- overscroll_window_->Show();
-
- overscroll_shadow_.reset(new ShadowLayerDelegate(animate_window->layer()));
-}
-
-void WebContentsViewAura::PrepareContentWindowForOverscroll() {
- StopObservingImplicitAnimations();
- aura::Window* content = GetContentNativeView();
- content->layer()->GetAnimator()->AbortAllAnimations();
- content->SetTransform(gfx::Transform());
- content->layer()->SetLayerBrightness(0.f);
-}
-
-void WebContentsViewAura::ResetOverscrollTransform() {
- if (!web_contents_->GetRenderWidgetHostView())
- return;
- aura::Window* target = GetWindowToAnimateForOverscroll();
- if (!target)
- return;
- {
- ui::ScopedLayerAnimationSettings settings(target->layer()->GetAnimator());
- settings.SetPreemptionStrategy(
- ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
- settings.SetTweenType(gfx::Tween::EASE_OUT);
- settings.AddObserver(this);
- target->SetTransform(gfx::Transform());
- }
- {
- ui::ScopedLayerAnimationSettings settings(target->layer()->GetAnimator());
- settings.SetPreemptionStrategy(
- ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
- settings.SetTweenType(gfx::Tween::EASE_OUT);
- UpdateOverscrollWindowBrightness(0.f);
+ if (!navigation_overlay_) {
+ navigation_overlay_.reset(
+ new OverscrollNavigationOverlay(web_contents_, window_.get()));
}
}
void WebContentsViewAura::CompleteOverscrollNavigation(OverscrollMode mode) {
if (!web_contents_->GetRenderWidgetHostView())
return;
-
- // Animate out the current view first. Navigate to the requested history at
- // the end of the animation.
- if (current_overscroll_gesture_ == OVERSCROLL_NONE)
- return;
-
- UMA_HISTOGRAM_ENUMERATION("Overscroll.Navigated",
- current_overscroll_gesture_, OVERSCROLL_COUNT);
- OverscrollWindowDelegate* delegate = static_cast<OverscrollWindowDelegate*>(
- overscroll_window_->delegate());
- delegate->stop_forwarding_events();
-
- completed_overscroll_gesture_ = mode;
- aura::Window* target = GetWindowToAnimateForOverscroll();
- ui::ScopedLayerAnimationSettings settings(target->layer()->GetAnimator());
- settings.SetPreemptionStrategy(
- ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
- settings.SetTweenType(gfx::Tween::EASE_OUT);
- settings.AddObserver(this);
- gfx::Transform transform;
- int content_width =
- web_contents_->GetRenderWidgetHostView()->GetViewBounds().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);
-}
-
-aura::Window* WebContentsViewAura::GetWindowToAnimateForOverscroll() {
- if (current_overscroll_gesture_ == OVERSCROLL_NONE)
- return NULL;
-
- return ShouldNavigateForward(web_contents_->GetController(),
- current_overscroll_gesture_) ?
- overscroll_window_.get() : GetContentNativeView();
-}
-
-gfx::Vector2dF WebContentsViewAura::GetTranslationForOverscroll(float delta_x,
- float delta_y) {
- if (current_overscroll_gesture_ == OVERSCROLL_NORTH ||
- current_overscroll_gesture_ == OVERSCROLL_SOUTH) {
- 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::Vector2dF(std::max(-bounds_width, delta_x), 0);
- else if (ShouldNavigateBack(controller, current_overscroll_gesture_))
- return gfx::Vector2dF(std::min(bounds_width, delta_x), 0);
- return gfx::Vector2dF();
-}
-
-void WebContentsViewAura::PrepareOverscrollNavigationOverlay() {
- OverscrollWindowDelegate* delegate = static_cast<OverscrollWindowDelegate*>(
- overscroll_window_->delegate());
- overscroll_window_->SchedulePaintInRect(
- gfx::Rect(overscroll_window_->bounds().size()));
- overscroll_window_->SetBounds(gfx::Rect(window_->bounds().size()));
- overscroll_window_->SetTransform(gfx::Transform());
- navigation_overlay_->SetOverlayWindow(overscroll_window_.Pass(),
- delegate);
- navigation_overlay_->StartObserving();
-}
-
-void WebContentsViewAura::UpdateOverscrollWindowBrightness(float delta_x) {
- if (!overscroll_change_brightness_)
- return;
-
- const float kBrightnessMin = -.1f;
- const float kBrightnessMax = -.01f;
-
- float ratio = fabs(delta_x) / GetViewBounds().width();
- ratio = std::min(1.f, ratio);
- if (base::i18n::IsRTL())
- ratio = 1.f - ratio;
- float brightness = current_overscroll_gesture_ == OVERSCROLL_WEST ?
- kBrightnessMin + ratio * (kBrightnessMax - kBrightnessMin) :
- kBrightnessMax - ratio * (kBrightnessMax - kBrightnessMin);
- brightness = std::max(kBrightnessMin, brightness);
- brightness = std::min(kBrightnessMax, brightness);
- aura::Window* window = GetWindowToAnimateForOverscroll();
- window->layer()->SetLayerBrightness(brightness);
+ navigation_overlay_->relay_delegate()->OnOverscrollComplete(mode);
+ if (touch_editable_)
+ touch_editable_->OverscrollCompleted();
}
void WebContentsViewAura::AttachTouchEditableToRenderView() {
@@ -1018,7 +754,8 @@ gfx::NativeView WebContentsViewAura::GetContentNativeView() const {
}
gfx::NativeWindow WebContentsViewAura::GetTopLevelNativeWindow() const {
- return window_->GetToplevelWindow();
+ gfx::NativeWindow window = window_->GetToplevelWindow();
+ return window ? window : delegate_->GetNativeWindow();
}
void WebContentsViewAura::GetContainerBounds(gfx::Rect *out) const {
@@ -1030,10 +767,6 @@ 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.
@@ -1097,7 +830,7 @@ void WebContentsViewAura::CreateView(
window_->set_owned_by_parent(false);
window_->SetType(ui::wm::WINDOW_TYPE_CONTROL);
window_->SetTransparent(false);
- window_->Init(aura::WINDOW_LAYER_NOT_DRAWN);
+ window_->Init(ui::LAYER_NOT_DRAWN);
window_->AddObserver(this);
aura::Window* root_window = context ? context->GetRootWindow() : NULL;
if (root_window) {
@@ -1130,14 +863,6 @@ 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(
@@ -1158,10 +883,6 @@ RenderWidgetHostViewBase* WebContentsViewAura::CreateViewForWidget(
view->InitAsChild(NULL);
GetNativeView()->AddChild(view->GetNativeView());
- if (navigation_overlay_.get() && navigation_overlay_->has_window()) {
- navigation_overlay_->StartObserving();
- }
-
RenderWidgetHostImpl* host_impl =
RenderWidgetHostImpl::From(render_widget_host);
@@ -1178,24 +899,12 @@ 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) {
- RenderWidgetHostViewAura* view =
- new RenderWidgetHostViewAura(render_widget_host, false);
-#if defined(OS_WIN)
- if (legacy_hwnd_)
- view->SetLegacyRenderWidgetHostHWND(legacy_hwnd_.get());
-#endif
- return view;
+ return new RenderWidgetHostViewAura(render_widget_host, false);
}
void WebContentsViewAura::SetPageTitle(const base::string16& title) {
@@ -1206,8 +915,6 @@ void WebContentsViewAura::RenderViewCreated(RenderViewHost* host) {
}
void WebContentsViewAura::RenderViewSwappedIn(RenderViewHost* host) {
- if (navigation_overlay_.get() && navigation_overlay_->has_window())
- navigation_overlay_->StartObserving();
AttachTouchEditableToRenderView();
}
@@ -1220,10 +927,12 @@ void WebContentsViewAura::SetOverscrollControllerEnabled(bool enabled) {
InstallOverscrollControllerDelegate(view);
}
- if (!enabled)
+ if (!enabled) {
navigation_overlay_.reset();
- else if (!navigation_overlay_)
- navigation_overlay_.reset(new OverscrollNavigationOverlay(web_contents_));
+ } else if (!navigation_overlay_) {
+ navigation_overlay_.reset(
+ new OverscrollNavigationOverlay(web_contents_, window_.get()));
+ }
}
////////////////////////////////////////////////////////////////////////////////
@@ -1235,6 +944,11 @@ void WebContentsViewAura::ShowContextMenu(RenderFrameHost* render_frame_host,
touch_editable_->EndTouchEditing(false);
}
if (delegate_) {
+ RenderWidgetHostViewAura* view = ToRenderWidgetHostViewAura(
+ web_contents_->GetRenderWidgetHostView());
+ if (view)
+ view->OnShowContextMenu();
+
delegate_->ShowContextMenu(render_frame_host, params);
// WARNING: we may have been deleted during the call to ShowContextMenu().
}
@@ -1301,8 +1015,7 @@ void WebContentsViewAura::UpdateDragCursor(blink::WebDragOperation operation) {
}
void WebContentsViewAura::GotFocus() {
- if (web_contents_->GetDelegate())
- web_contents_->GetDelegate()->WebContentsFocused(web_contents_);
+ web_contents_->NotifyWebContentsFocused();
}
void WebContentsViewAura::TakeFocus(bool reverse) {
@@ -1344,103 +1057,40 @@ bool WebContentsViewAura::OnOverscrollUpdate(float delta_x, float delta_y) {
if (current_overscroll_gesture_ == OVERSCROLL_NONE)
return false;
- aura::Window* target = GetWindowToAnimateForOverscroll();
- gfx::Vector2dF translate = GetTranslationForOverscroll(delta_x, delta_y);
- gfx::Transform transform;
-
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(delta_y);
+ return delta_y != 0;
}
-
- return !translate.IsZero();
+ return navigation_overlay_->relay_delegate()->OnOverscrollUpdate(delta_x,
+ delta_y);
}
void WebContentsViewAura::OnOverscrollComplete(OverscrollMode mode) {
- UMA_HISTOGRAM_ENUMERATION("Overscroll.Completed", mode, OVERSCROLL_COUNT);
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)) {
- CompleteOverscrollNavigation(mode);
- return;
- }
-
- ResetOverscrollTransform();
+ CompleteOverscrollNavigation(mode);
}
void WebContentsViewAura::OnOverscrollModeChange(OverscrollMode old_mode,
OverscrollMode new_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();
-
- if (new_mode == OVERSCROLL_NONE ||
- !GetContentNativeView() ||
- ((new_mode == OVERSCROLL_EAST || new_mode == OVERSCROLL_WEST) &&
- navigation_overlay_.get() && navigation_overlay_->has_window())) {
- current_overscroll_gesture_ = OVERSCROLL_NONE;
- } else {
- aura::Window* target = GetWindowToAnimateForOverscroll();
- if (target) {
- StopObservingImplicitAnimations();
- target->layer()->GetAnimator()->AbortAllAnimations();
- }
- // Cleanup state of the content window first, because that can reset the
- // value of |current_overscroll_gesture_|.
- PrepareContentWindowForOverscroll();
-
- current_overscroll_gesture_ = new_mode;
- if (current_overscroll_gesture_ == OVERSCROLL_EAST ||
- current_overscroll_gesture_ == OVERSCROLL_WEST)
- PrepareOverscrollWindow();
-
- UMA_HISTOGRAM_ENUMERATION("Overscroll.Started", new_mode, OVERSCROLL_COUNT);
- }
- completed_overscroll_gesture_ = OVERSCROLL_NONE;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// WebContentsViewAura, ui::ImplicitAnimationObserver implementation:
-
-void WebContentsViewAura::OnImplicitAnimationsCompleted() {
- overscroll_shadow_.reset();
-
- if (ShouldNavigateForward(web_contents_->GetController(),
- completed_overscroll_gesture_)) {
- web_contents_->GetController().GoForward();
- PrepareOverscrollNavigationOverlay();
- } else if (ShouldNavigateBack(web_contents_->GetController(),
- completed_overscroll_gesture_)) {
- web_contents_->GetController().GoBack();
- PrepareOverscrollNavigationOverlay();
- } else {
- if (touch_editable_)
+ if (touch_editable_) {
+ if (new_mode == OVERSCROLL_NONE)
touch_editable_->OverscrollCompleted();
+ else
+ touch_editable_->OverscrollStarted();
}
- aura::Window* content = GetContentNativeView();
- if (content) {
- content->SetTransform(gfx::Transform());
- content->layer()->SetLayerBrightness(0.f);
- }
- current_overscroll_gesture_ = OVERSCROLL_NONE;
+ current_overscroll_gesture_ = new_mode;
+ navigation_overlay_->relay_delegate()->OnOverscrollModeChange(old_mode,
+ new_mode);
completed_overscroll_gesture_ = OVERSCROLL_NONE;
- overscroll_window_.reset();
}
////////////////////////////////////////////////////////////////////////////////
@@ -1473,6 +1123,10 @@ void WebContentsViewAura::OnBoundsChanged(const gfx::Rect& old_bounds,
}
}
+ui::TextInputClient* WebContentsViewAura::GetFocusedTextInputClient() {
+ return nullptr;
+}
+
gfx::NativeCursor WebContentsViewAura::GetCursor(const gfx::Point& point) {
return gfx::kNullCursor;
}
@@ -1502,7 +1156,7 @@ bool WebContentsViewAura::CanFocus() {
void WebContentsViewAura::OnCaptureLost() {
}
-void WebContentsViewAura::OnPaint(gfx::Canvas* canvas) {
+void WebContentsViewAura::OnPaint(const ui::PaintContext& context) {
}
void WebContentsViewAura::OnDeviceScaleFactorChanged(
@@ -1516,7 +1170,6 @@ void WebContentsViewAura::OnWindowDestroying(aura::Window* window) {
// virtual functions to be called (e.g. OnImplicitAnimationsCompleted()). So
// destroy the overscroll window here.
navigation_overlay_.reset();
- overscroll_window_.reset();
}
void WebContentsViewAura::OnWindowDestroyed(aura::Window* window) {
@@ -1675,35 +1328,6 @@ void WebContentsViewAura::UpdateWebContentsVisibility(bool visible) {
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 cf5177662ae..f184fb226b2 100644
--- a/chromium/content/browser/web_contents/web_contents_view_aura.h
+++ b/chromium/content/browser/web_contents/web_contents_view_aura.h
@@ -15,14 +15,8 @@
#include "content/common/content_export.h"
#include "ui/aura/window_delegate.h"
#include "ui/aura/window_observer.h"
-#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;
}
@@ -42,18 +36,10 @@ 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,
public aura::WindowDelegate,
public aura::client::DragDropDelegate,
public aura::WindowObserver {
@@ -75,41 +61,15 @@ class WebContentsViewAura
void InstallOverscrollControllerDelegate(RenderWidgetHostViewAura* view);
- // Creates and sets up the overlay window that will be displayed during the
- // overscroll gesture.
- void PrepareOverscrollWindow();
-
// Sets up the content window in preparation for starting an overscroll
// gesture.
void PrepareContentWindowForOverscroll();
- // Resets any in-progress animation for the overscroll gesture. Note that this
- // doesn't immediately reset the internal states; that happens after an
- // animation.
- void ResetOverscrollTransform();
-
// Completes the navigation in response to a completed overscroll gesture.
// The navigation happens after an animation (either the overlay window
// animates in, or the content window animates out).
void CompleteOverscrollNavigation(OverscrollMode mode);
- // Returns the window that should be animated for the overscroll gesture.
- // (note that during the overscroll gesture, either the overlay window or the
- // content window can be animated).
- aura::Window* GetWindowToAnimateForOverscroll();
-
- // Returns the amount the animating window should be translated in response to
- // the overscroll gesture.
- 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.
- void PrepareOverscrollNavigationOverlay();
-
- // Changes the brightness of the layer depending on the amount of horizontal
- // overscroll (|delta_x|, in pixels).
- void UpdateOverscrollWindowBrightness(float delta_x);
-
void AttachTouchEditableToRenderView();
void OverscrollUpdateForWebContentsDelegate(float delta_y);
@@ -163,14 +123,12 @@ class WebContentsViewAura
void OnOverscrollModeChange(OverscrollMode old_mode,
OverscrollMode new_mode) override;
- // Overridden from ui::ImplicitAnimationObserver:
- void OnImplicitAnimationsCompleted() override;
-
// Overridden from aura::WindowDelegate:
gfx::Size GetMinimumSize() const override;
gfx::Size GetMaximumSize() const override;
void OnBoundsChanged(const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds) override;
+ ui::TextInputClient* GetFocusedTextInputClient() override;
gfx::NativeCursor GetCursor(const gfx::Point& point) override;
int GetNonClientComponent(const gfx::Point& point) const override;
bool ShouldDescendIntoChildForEventHandling(
@@ -178,7 +136,7 @@ class WebContentsViewAura
const gfx::Point& location) override;
bool CanFocus() override;
void OnCaptureLost() override;
- void OnPaint(gfx::Canvas* canvas) override;
+ void OnPaint(const ui::PaintContext& context) override;
void OnDeviceScaleFactorChanged(float device_scale_factor) override;
void OnWindowDestroying(aura::Window* window) override;
void OnWindowDestroyed(aura::Window* window) override;
@@ -202,17 +160,8 @@ class WebContentsViewAura
// 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_;
- // The window that shows the screenshot of the history page during an
- // overscroll navigation gesture.
- scoped_ptr<aura::Window> overscroll_window_;
-
scoped_ptr<WindowObserver> window_observer_;
// The WebContentsImpl whose contents we display.
@@ -232,8 +181,6 @@ class WebContentsViewAura
// pointers.
void* current_rvh_for_drag_;
- bool overscroll_change_brightness_;
-
// The overscroll gesture currently in progress.
OverscrollMode current_overscroll_gesture_;
@@ -245,19 +192,9 @@ class WebContentsViewAura
// navigation triggered by the overscroll gesture.
scoped_ptr<OverscrollNavigationOverlay> navigation_overlay_;
- scoped_ptr<ShadowLayerDelegate> overscroll_shadow_;
-
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_;
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 2687376c109..a715b464000 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
@@ -167,7 +167,9 @@ class NavigationWatcher : public WebContentsObserver {
private:
// Overridden from WebContentsObserver:
- void AboutToNavigateRenderView(RenderViewHost* host) override {
+ void DidStartNavigationToPendingEntry(
+ const GURL& validated_url,
+ NavigationController::ReloadType reload_type) override {
navigated_ = true;
if (should_quit_loop_)
base::MessageLoop::current()->Quit();
@@ -212,8 +214,8 @@ class InputEventMessageFilterWaitsForAcks : public BrowserMessageFilter {
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;
+ blink::WebInputEvent::Type type = get<0>(params).type;
+ InputEventAckState ack = get<0>(params).state;
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(&InputEventMessageFilterWaitsForAcks::ReceivedEventAck,
this, type, ack));
@@ -257,7 +259,7 @@ class WebContentsViewAuraTest : public ContentBrowserTest {
controller->SetScreenshotManager(screenshot_manager_);
}
- void SetUpCommandLine(CommandLine* cmd) override {
+ void SetUpCommandLine(base::CommandLine* cmd) override {
cmd->AppendSwitchASCII(switches::kTouchEvents,
switches::kTouchEventsEnabled);
}
@@ -423,7 +425,8 @@ class WebContentsViewAuraTest : public ContentBrowserTest {
};
// Flaky on Windows: http://crbug.com/305722
-#if defined(OS_WIN)
+// The test frequently times out on Linux, too. See crbug.com/440043.
+#if defined(OS_WIN) || defined(OS_LINUX)
#define MAYBE_OverscrollNavigation DISABLED_OverscrollNavigation
#else
#define MAYBE_OverscrollNavigation OverscrollNavigation
@@ -435,7 +438,8 @@ IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, MAYBE_OverscrollNavigation) {
// Flaky on Windows (might be related to the above test):
// http://crbug.com/305722
-#if defined(OS_WIN)
+// On Linux, the test frequently times out. (See crbug.com/440043).
+#if defined(OS_WIN) || defined(OS_LINUX)
#define MAYBE_OverscrollNavigationWithTouchHandler \
DISABLED_OverscrollNavigationWithTouchHandler
#else
@@ -449,7 +453,8 @@ IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
// Disabled because the test always fails the first time it runs on the Win Aura
// bots, and usually but not always passes second-try (See crbug.com/179532).
-#if defined(OS_WIN)
+// On Linux, the test frequently times out. (See crbug.com/440043).
+#if defined(OS_WIN) || defined(OS_LINUX)
#define MAYBE_QuickOverscrollDirectionChange \
DISABLED_QuickOverscrollDirectionChange
#else
@@ -572,27 +577,22 @@ IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, MAYBE_OverscrollScreenshot) {
EXPECT_EQ(2, GetCurrentIndex());
screenshot_manager()->WaitUntilScreenshotIsReady();
- NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
- web_contents->GetController().GetEntryAtIndex(2));
+ NavigationEntryImpl* entry = web_contents->GetController().GetEntryAtIndex(2);
EXPECT_FALSE(entry->screenshot().get());
- entry = NavigationEntryImpl::FromNavigationEntry(
- web_contents->GetController().GetEntryAtIndex(1));
+ entry = web_contents->GetController().GetEntryAtIndex(1);
EXPECT_FALSE(screenshot_manager()->ScreenshotSetForEntry(entry));
- entry = NavigationEntryImpl::FromNavigationEntry(
- web_contents->GetController().GetEntryAtIndex(0));
+ entry = web_contents->GetController().GetEntryAtIndex(0);
EXPECT_FALSE(screenshot_manager()->ScreenshotSetForEntry(entry));
ExecuteSyncJSFunction(main_frame, "navigate_next()");
screenshot_manager()->WaitUntilScreenshotIsReady();
- entry = NavigationEntryImpl::FromNavigationEntry(
- web_contents->GetController().GetEntryAtIndex(2));
+ entry = web_contents->GetController().GetEntryAtIndex(2);
EXPECT_FALSE(screenshot_manager()->ScreenshotSetForEntry(entry));
- entry = NavigationEntryImpl::FromNavigationEntry(
- web_contents->GetController().GetEntryAtIndex(3));
+ entry = web_contents->GetController().GetEntryAtIndex(3);
EXPECT_FALSE(entry->screenshot().get());
{
// Now, swipe right to navigate backwards. This should navigate away from
@@ -611,8 +611,7 @@ IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, MAYBE_OverscrollScreenshot) {
EXPECT_EQ(expected_title, actual_title);
EXPECT_EQ(2, GetCurrentIndex());
screenshot_manager()->WaitUntilScreenshotIsReady();
- entry = NavigationEntryImpl::FromNavigationEntry(
- web_contents->GetController().GetEntryAtIndex(3));
+ entry = web_contents->GetController().GetEntryAtIndex(3);
EXPECT_FALSE(screenshot_manager()->ScreenshotSetForEntry(entry));
}
@@ -622,8 +621,7 @@ IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, MAYBE_OverscrollScreenshot) {
ExecuteSyncJSFunction(main_frame, "navigate_next()");
EXPECT_EQ(4, GetCurrentIndex());
screenshot_manager()->WaitUntilScreenshotIsReady();
- entry = NavigationEntryImpl::FromNavigationEntry(
- web_contents->GetController().GetEntryAtIndex(4));
+ entry = web_contents->GetController().GetEntryAtIndex(4);
EXPECT_FALSE(entry->screenshot().get());
{
@@ -635,8 +633,7 @@ IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, MAYBE_OverscrollScreenshot) {
EXPECT_EQ(expected_title, actual_title);
EXPECT_EQ(3, GetCurrentIndex());
screenshot_manager()->WaitUntilScreenshotIsReady();
- entry = NavigationEntryImpl::FromNavigationEntry(
- web_contents->GetController().GetEntryAtIndex(4));
+ entry = web_contents->GetController().GetEntryAtIndex(4);
EXPECT_FALSE(screenshot_manager()->ScreenshotSetForEntry(entry));
}
}
@@ -695,12 +692,11 @@ IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
<< navigations[i].url.spec();
EXPECT_EQ(old_host, screenshot_manager()->screenshot_taken_for());
- NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
- web_contents->GetController().GetEntryAtOffset(-1));
+ NavigationEntryImpl* entry =
+ web_contents->GetController().GetEntryAtOffset(-1);
EXPECT_TRUE(screenshot_manager()->ScreenshotSetForEntry(entry));
- entry = NavigationEntryImpl::FromNavigationEntry(
- web_contents->GetController().GetLastCommittedEntry());
+ entry = web_contents->GetController().GetLastCommittedEntry();
EXPECT_FALSE(screenshot_manager()->ScreenshotSetForEntry(entry));
EXPECT_FALSE(entry->screenshot().get());
screenshot_manager()->Reset();
@@ -766,7 +762,7 @@ IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
StartTestWithPage("files/overscroll_navigation.html"));
scoped_ptr<aura::Window> window(new aura::Window(NULL));
- window->Init(aura::WINDOW_LAYER_NOT_DRAWN);
+ window->Init(ui::LAYER_NOT_DRAWN);
WebContentsImpl* web_contents =
static_cast<WebContentsImpl*>(shell()->web_contents());
@@ -892,7 +888,7 @@ IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, WebContentsViewReparent) {
StartTestWithPage("files/overscroll_navigation.html"));
scoped_ptr<aura::Window> window(new aura::Window(NULL));
- window->Init(aura::WINDOW_LAYER_NOT_DRAWN);
+ window->Init(ui::LAYER_NOT_DRAWN);
RenderWidgetHostViewAura* rwhva =
static_cast<RenderWidgetHostViewAura*>(
@@ -976,7 +972,8 @@ IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
WaitAFrame();
blink::WebGestureEvent scroll_update =
- SyntheticWebGestureEventBuilder::BuildScrollUpdate(dx, 5, 0);
+ SyntheticWebGestureEventBuilder::BuildScrollUpdate(
+ dx, 5, 0, blink::WebGestureDeviceTouchscreen);
GetRenderWidgetHost()->ForwardGestureEventWithLatencyInfo(
scroll_update, ui::LatencyInfo());
@@ -1055,7 +1052,7 @@ IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, MAYBE_VerticalOverscroll) {
}
ui::TouchEvent release(ui::ET_TOUCH_RELEASED, location, 0, timestamp);
- details = dispatcher->OnEventFromSource(&press);
+ details = dispatcher->OnEventFromSource(&release);
ASSERT_FALSE(details.dispatcher_destroyed);
WaitAFrame();
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 6cc1581e6a3..940b4209b1e 100644
--- a/chromium/content/browser/web_contents/web_contents_view_guest.cc
+++ b/chromium/content/browser/web_contents/web_contents_view_guest.cc
@@ -17,10 +17,10 @@
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/common/context_menu_params.h"
#include "content/public/common/drop_data.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
#include "ui/gfx/image/image_skia.h"
-#include "ui/gfx/point.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/size.h"
#if defined(USE_AURA)
#include "ui/aura/window.h"
@@ -78,23 +78,6 @@ void WebContentsViewGuest::OnGuestDetached(WebContentsView* old_parent_view) {
#endif // defined(USE_AURA)
}
-ContextMenuParams WebContentsViewGuest::ConvertContextMenuParams(
- const ContextMenuParams& params) const {
- // 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);
- gfx::Rect guest_bounds;
- GetContainerBounds(&guest_bounds);
-
- gfx::Vector2d offset = guest_bounds.origin() - embedder_bounds.origin();
- ContextMenuParams params_in_embedder = params;
- params_in_embedder.x += offset.x();
- params_in_embedder.y += offset.y();
- return params_in_embedder;
-}
-
void WebContentsViewGuest::GetContainerBounds(gfx::Rect* out) const {
if (guest_->embedder_web_contents()) {
// We need embedder container's bounds to calculate our bounds.
@@ -229,8 +212,7 @@ void WebContentsViewGuest::TakeFocus(bool reverse) {
void WebContentsViewGuest::ShowContextMenu(RenderFrameHost* render_frame_host,
const ContextMenuParams& params) {
- platform_view_delegate_view_->ShowContextMenu(
- render_frame_host, ConvertContextMenuParams(params));
+ platform_view_delegate_view_->ShowContextMenu(render_frame_host, params);
}
void WebContentsViewGuest::StartDragging(
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 e21f19a6956..f2a10c86816 100644
--- a/chromium/content/browser/web_contents/web_contents_view_guest.h
+++ b/chromium/content/browser/web_contents/web_contents_view_guest.h
@@ -39,11 +39,6 @@ class WebContentsViewGuest : public WebContentsView,
void OnGuestDetached(WebContentsView* old_parent_view);
- // Converts the guest specific coordinates in |params| to embedder specific
- // ones.
- ContextMenuParams ConvertContextMenuParams(
- const ContextMenuParams& params) const;
-
// WebContentsView implementation --------------------------------------------
gfx::NativeView GetNativeView() const override;
gfx::NativeView GetContentNativeView() const override;
diff --git a/chromium/content/browser/web_contents/web_contents_view_mac.h b/chromium/content/browser/web_contents/web_contents_view_mac.h
index 93c1eaff906..d116d7d2a33 100644
--- a/chromium/content/browser/web_contents/web_contents_view_mac.h
+++ b/chromium/content/browser/web_contents/web_contents_view_mac.h
@@ -17,7 +17,7 @@
#include "content/common/content_export.h"
#include "content/common/drag_event_source_info.h"
#include "ui/base/cocoa/base_view.h"
-#include "ui/gfx/size.h"
+#include "ui/gfx/geometry/size.h"
@class FocusTracker;
class SkBitmap;
@@ -45,6 +45,7 @@ CONTENT_EXPORT
}
- (void)setMouseDownCanMoveWindow:(BOOL)canMove;
+- (void)setOpaque:(BOOL)opaque;
// Expose this, since sometimes one needs both the NSView and the
// WebContentsImpl.
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 3c99ac330cc..9e1f7925e21 100644
--- a/chromium/content/browser/web_contents/web_contents_view_mac.mm
+++ b/chromium/content/browser/web_contents/web_contents_view_mac.mm
@@ -43,16 +43,16 @@ using content::WebContentsViewMac;
// Ensure that the blink::WebDragOperation enum values stay in sync with
// NSDragOperation constants, since the code below static_casts between 'em.
-#define COMPILE_ASSERT_MATCHING_ENUM(name) \
- COMPILE_ASSERT(int(NS##name) == int(blink::Web##name), enum_mismatch_##name)
-COMPILE_ASSERT_MATCHING_ENUM(DragOperationNone);
-COMPILE_ASSERT_MATCHING_ENUM(DragOperationCopy);
-COMPILE_ASSERT_MATCHING_ENUM(DragOperationLink);
-COMPILE_ASSERT_MATCHING_ENUM(DragOperationGeneric);
-COMPILE_ASSERT_MATCHING_ENUM(DragOperationPrivate);
-COMPILE_ASSERT_MATCHING_ENUM(DragOperationMove);
-COMPILE_ASSERT_MATCHING_ENUM(DragOperationDelete);
-COMPILE_ASSERT_MATCHING_ENUM(DragOperationEvery);
+#define STATIC_ASSERT_MATCHING_ENUM(name) \
+ static_assert(int(NS##name) == int(blink::Web##name), "enum mismatch: " #name)
+STATIC_ASSERT_MATCHING_ENUM(DragOperationNone);
+STATIC_ASSERT_MATCHING_ENUM(DragOperationCopy);
+STATIC_ASSERT_MATCHING_ENUM(DragOperationLink);
+STATIC_ASSERT_MATCHING_ENUM(DragOperationGeneric);
+STATIC_ASSERT_MATCHING_ENUM(DragOperationPrivate);
+STATIC_ASSERT_MATCHING_ENUM(DragOperationMove);
+STATIC_ASSERT_MATCHING_ENUM(DragOperationDelete);
+STATIC_ASSERT_MATCHING_ENUM(DragOperationEvery);
@interface WebContentsViewCocoa (Private)
- (id)initWithWebContentsViewMac:(WebContentsViewMac*)w;
@@ -108,7 +108,8 @@ gfx::NativeView WebContentsViewMac::GetContentNativeView() const {
}
gfx::NativeWindow WebContentsViewMac::GetTopLevelNativeWindow() const {
- return [cocoa_view_.get() window];
+ NSWindow* window = [cocoa_view_.get() window];
+ return window ? window : delegate_->GetNativeWindow();
}
void WebContentsViewMac::GetContainerBounds(gfx::Rect* out) const {
@@ -422,6 +423,14 @@ void WebContentsViewMac::CloseTab() {
[super dealloc];
}
+- (BOOL)allowsVibrancy {
+ // Returning YES will allow rendering this view with vibrancy effect if it is
+ // incorporated into a view hierarchy that uses vibrancy, it will have no
+ // effect otherwise.
+ // For details see Apple documentation on NSView and NSVisualEffectView.
+ return YES;
+}
+
// Registers for the view for the appropriate drag types.
- (void)registerDragTypes {
NSArray* types = [NSArray arrayWithObjects:
@@ -478,6 +487,13 @@ void WebContentsViewMac::CloseTab() {
return mouseDownCanMoveWindow_;
}
+- (void)setOpaque:(BOOL)opaque {
+ RenderWidgetHostViewMac* view = static_cast<RenderWidgetHostViewMac*>(
+ webContentsView_->web_contents()->GetRenderWidgetHostView());
+ DCHECK(view);
+ [view->cocoa_view() setOpaque:opaque];
+}
+
- (void)pasteboard:(NSPasteboard*)sender provideDataForType:(NSString*)type {
[dragSource_ lazyWriteToPasteboard:sender
forType:type];
@@ -578,8 +594,8 @@ void WebContentsViewMac::CloseTab() {
return;
NSSelectionDirection direction =
- [[[notification userInfo] objectForKey:kSelectionDirection]
- unsignedIntegerValue];
+ static_cast<NSSelectionDirection>([[[notification userInfo]
+ objectForKey:kSelectionDirection] unsignedIntegerValue]);
if (direction == NSDirectSelection)
return;
@@ -605,12 +621,6 @@ void WebContentsViewMac::CloseTab() {
// 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
@@ -632,13 +642,11 @@ void WebContentsViewMac::CloseTab() {
DCHECK(base::mac::IsOSMavericksOrLater());
NSWindow* window = [notification object];
WebContentsImpl* webContents = [self webContents];
- if (window && webContents) {
+ if (window && webContents && !webContents->IsBeingDestroyed()) {
if ([window occlusionState] & NSWindowOcclusionStateVisible) {
- if (!webContents->should_normally_be_visible())
- webContents->WasShown();
+ webContents->WasUnOccluded();
} else {
- if (webContents->should_normally_be_visible())
- webContents->WasHidden();
+ webContents->WasOccluded();
}
}
}
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 5d21e7293b1..b614fb13dea 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 {
+ 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 0e57d4fffde..bc41d43a49a 100644
--- a/chromium/content/browser/web_contents/web_drag_dest_mac.mm
+++ b/chromium/content/browser/web_contents/web_drag_dest_mac.mm
@@ -24,6 +24,8 @@ using content::OpenURLParams;
using content::Referrer;
using content::WebContentsImpl;
+namespace {
+
int GetModifierFlags() {
int modifier_state = 0;
UInt32 currentModifiers = GetCurrentKeyModifiers();
@@ -35,9 +37,24 @@ int GetModifierFlags() {
modifier_state |= blink::WebInputEvent::AltKey;
if (currentModifiers & ::cmdKey)
modifier_state |= blink::WebInputEvent::MetaKey;
+
+ // The return value of 1 << 0 corresponds to the left mouse button,
+ // 1 << 1 corresponds to the right mouse button,
+ // 1 << n, n >= 2 correspond to other mouse buttons.
+ NSUInteger pressedButtons = [NSEvent pressedMouseButtons];
+
+ if (pressedButtons & (1 << 0))
+ modifier_state |= blink::WebInputEvent::LeftButtonDown;
+ if (pressedButtons & (1 << 1))
+ modifier_state |= blink::WebInputEvent::RightButtonDown;
+ if (pressedButtons & (1 << 2))
+ modifier_state |= blink::WebInputEvent::MiddleButtonDown;
+
return modifier_state;
}
+} // namespace
+
@implementation WebDragDest
// |contents| is the WebContentsImpl representing this tab, used to communicate
diff --git a/chromium/content/browser/web_contents/web_drag_dest_mac_unittest.mm b/chromium/content/browser/web_contents/web_drag_dest_mac_unittest.mm
index 90c565c46dd..efa6452e267 100644
--- a/chromium/content/browser/web_contents/web_drag_dest_mac_unittest.mm
+++ b/chromium/content/browser/web_contents/web_drag_dest_mac_unittest.mm
@@ -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/mac/mac_util.h"
#include "base/mac/scoped_nsautorelease_pool.h"
#import "base/mac/scoped_nsobject.h"
#include "base/strings/sys_string_conversions.h"
@@ -27,7 +28,7 @@ NSString* const kCrCorePasteboardFlavorType_urln =
class WebDragDestTest : public RenderViewHostImplTestHarness {
public:
- virtual void SetUp() {
+ void SetUp() override {
RenderViewHostImplTestHarness::SetUp();
drag_dest_.reset([[WebDragDest alloc] initWithWebContentsImpl:contents()]);
}
@@ -139,7 +140,10 @@ TEST_F(WebDragDestTest, URL) {
&result_url, &result_title, pboard, NO));
EXPECT_TRUE(ui::PopulateURLAndTitleFromPasteboard(
&result_url, &result_title, pboard, YES));
- EXPECT_EQ("file://localhost/bin/sh", result_url.spec());
+ base::scoped_nsobject<NSURL> expected_output(
+ [[NSURL alloc] initFileURLWithPath:url isDirectory:NO]);
+ EXPECT_EQ([[expected_output absoluteString] UTF8String], result_url.spec());
+
EXPECT_EQ("sh", base::UTF16ToUTF8(result_title));
[pboard releaseGlobally];
}
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 f8b639c434f..57e12a0b04c 100644
--- a/chromium/content/browser/web_contents/web_drag_source_mac.mm
+++ b/chromium/content/browser/web_contents/web_drag_source_mac.mm
@@ -9,7 +9,7 @@
#include "base/bind.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
-#include "base/mac/mac_util.h"
+#include "base/mac/foundation_util.h"
#include "base/pickle.h"
#include "base/strings/string_util.h"
#include "base/strings/sys_string_conversions.h"
diff --git a/chromium/content/browser/webui/content_web_ui_controller_factory.cc b/chromium/content/browser/webui/content_web_ui_controller_factory.cc
index 7a9263111f3..95dedcb0dd4 100644
--- a/chromium/content/browser/webui/content_web_ui_controller_factory.cc
+++ b/chromium/content/browser/webui/content_web_ui_controller_factory.cc
@@ -23,6 +23,9 @@ namespace content {
WebUI::TypeID ContentWebUIControllerFactory::GetWebUIType(
BrowserContext* browser_context, const GURL& url) const {
+ if (!url.SchemeIs(kChromeUIScheme))
+ return WebUI::kNoWebUI;
+
if (url.host() == kChromeUIWebRTCInternalsHost ||
#if !defined(OS_ANDROID)
url.host() == kChromeUITracingHost ||
@@ -49,6 +52,9 @@ bool ContentWebUIControllerFactory::UseWebUIBindingsForURL(
WebUIController* ContentWebUIControllerFactory::CreateWebUIControllerForURL(
WebUI* web_ui, const GURL& url) const {
+ if (!url.SchemeIs(kChromeUIScheme))
+ return nullptr;
+
if (url.host() == kChromeUIGpuHost)
return new GpuInternalsUI(web_ui);
if (url.host() == kChromeUIIndexedDBInternalsHost)
@@ -69,7 +75,7 @@ WebUIController* ContentWebUIControllerFactory::CreateWebUIControllerForURL(
return new WebRTCInternalsUI(web_ui);
#endif
- return NULL;
+ return nullptr;
}
// static
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 f2638117720..d8e7a1c7f7d 100644
--- a/chromium/content/browser/webui/content_web_ui_controller_factory.h
+++ b/chromium/content/browser/webui/content_web_ui_controller_factory.h
@@ -12,7 +12,8 @@
namespace content {
-class ContentWebUIControllerFactory : public WebUIControllerFactory {
+class CONTENT_EXPORT ContentWebUIControllerFactory
+ : public WebUIControllerFactory {
public:
WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
const GURL& url) const override;
diff --git a/chromium/content/browser/webui/generic_handler.h b/chromium/content/browser/webui/generic_handler.h
index dd352555d0d..62f0e42021c 100644
--- a/chromium/content/browser/webui/generic_handler.h
+++ b/chromium/content/browser/webui/generic_handler.h
@@ -31,4 +31,4 @@ class GenericHandler : public WebUIMessageHandler {
} // namespace content
-#endif // namespace content
+#endif // CONTENT_BROWSER_WEBUI_GENERIC_HANDLER_H_
diff --git a/chromium/content/browser/webui/shared_resources_data_source.cc b/chromium/content/browser/webui/shared_resources_data_source.cc
index 2ce6e147b09..3f96e76ffd6 100644
--- a/chromium/content/browser/webui/shared_resources_data_source.cc
+++ b/chromium/content/browser/webui/shared_resources_data_source.cc
@@ -4,54 +4,64 @@
#include "content/browser/webui/shared_resources_data_source.h"
+#include "base/containers/hash_tables.h"
#include "base/logging.h"
#include "base/memory/ref_counted_memory.h"
+#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/threading/thread_restrictions.h"
#include "content/public/common/content_client.h"
#include "content/public/common/url_constants.h"
#include "net/base/mime_util.h"
+#include "ui/base/layout.h"
+#include "ui/base/webui/web_ui_util.h"
+#include "ui/resources/grit/webui_resources.h"
#include "ui/resources/grit/webui_resources_map.h"
+namespace content {
+
namespace {
-const char kAppImagesPath[] = "images/apps/";
-const char kAppImagesPath2x[] = "images/2x/apps/";
-
-const char kReplacement[] = "../../resources/default_100_percent/common/";
-const char kReplacement2x[] = "../../resources/default_200_percent/common/";
-
-// This entire method is a hack introduced to be able to handle apps images
-// that exist in the ui/resources directory. From JS/CSS, we still load the
-// image as if it were chrome://resources/images/apps/myappimage.png, if that
-// path doesn't exist, we check to see if it that image exists in the relative
-// path to ui/resources instead.
-// TODO(rkc): Once we have a separate source for apps, remove this code.
-bool AppsRelativePathMatch(const std::string& path,
- const std::string& compareto) {
- if (StartsWithASCII(path, kAppImagesPath, false)) {
- if (compareto ==
- (kReplacement + path.substr(arraysize(kAppImagesPath) - 1)))
- return true;
- } else if (StartsWithASCII(path, kAppImagesPath2x, false)) {
- if (compareto ==
- (kReplacement2x + path.substr(arraysize(kAppImagesPath2x) - 1)))
- return true;
- }
- return false;
+using ResourcesMap = base::hash_map<std::string, int>;
+
+// TODO(rkc): Once we have a separate source for apps, remove '*/apps/' aliases.
+const char* kPathAliases[][2] = {
+ {"../../../third_party/polymer/components-chromium/", "polymer/"},
+ {"../../../third_party/polymer/v0_8/components-chromium/", "polymer/v0_8/"},
+ {"../../../third_party/web-animations-js/sources/",
+ "polymer/web-animations-js/"},
+ {"../../resources/default_100_percent/common/", "images/apps/"},
+ {"../../resources/default_200_percent/common/", "images/2x/apps/"},
+ {"../../webui/resources/cr_elements/", "cr_elements/"}};
+
+void AddResource(const std::string& path,
+ int resource_id,
+ ResourcesMap* resources_map) {
+ if (!resources_map->insert(std::make_pair(path, resource_id)).second)
+ NOTREACHED() << "Redefinition of '" << path << "'";
}
-int PathToIDR(const std::string& path) {
- int idr = -1;
+const ResourcesMap* CreateResourcesMap() {
+ ResourcesMap* result = new ResourcesMap();
for (size_t i = 0; i < kWebuiResourcesSize; ++i) {
- if ((path == kWebuiResources[i].name) ||
- AppsRelativePathMatch(path, kWebuiResources[i].name)) {
- idr = kWebuiResources[i].value;
- break;
+ const std::string resource_name = kWebuiResources[i].name;
+ const int resource_id = kWebuiResources[i].value;
+ AddResource(resource_name, resource_id, result);
+ for (const char* (&alias)[2]: kPathAliases) {
+ if (StartsWithASCII(resource_name, alias[0], true)) {
+ AddResource(alias[1] + resource_name.substr(strlen(alias[0])),
+ resource_id, result);
+ }
}
}
- return idr;
+ return result;
+}
+
+const ResourcesMap& GetResourcesMap() {
+ // This pointer will be intentionally leaked on shutdown.
+ static const ResourcesMap* resources_map = CreateResourcesMap();
+ return *resources_map;
}
} // namespace
@@ -63,18 +73,26 @@ SharedResourcesDataSource::~SharedResourcesDataSource() {
}
std::string SharedResourcesDataSource::GetSource() const {
- return content::kChromeUIResourcesHost;
+ return kChromeUIResourcesHost;
}
void SharedResourcesDataSource::StartDataRequest(
const std::string& path,
int render_process_id,
int render_frame_id,
- const content::URLDataSource::GotDataCallback& callback) {
- int idr = PathToIDR(path);
+ const URLDataSource::GotDataCallback& callback) {
+ const ResourcesMap& resources_map = GetResourcesMap();
+ auto it = resources_map.find(path);
+ int idr = (it != resources_map.end()) ? it->second : -1;
DCHECK_NE(-1, idr) << " path: " << path;
- scoped_refptr<base::RefCountedStaticMemory> bytes(
- content::GetContentClient()->GetDataResourceBytes(idr));
+ scoped_refptr<base::RefCountedMemory> bytes;
+
+ if (idr == IDR_WEBUI_CSS_TEXT_DEFAULTS) {
+ std::string css = webui::GetWebUiCssTextDefaults();
+ bytes = base::RefCountedString::TakeString(&css);
+ } else {
+ bytes = GetContentClient()->GetDataResourceBytes(idr);
+ }
callback.Run(bytes.get());
}
@@ -97,9 +115,11 @@ SharedResourcesDataSource::GetAccessControlAllowOriginForOrigin(
// 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;
+ std::string allowed_origin_prefix = kChromeUIScheme;
allowed_origin_prefix += "://";
if (origin.find(allowed_origin_prefix) != 0)
- return "none";
+ return "null";
return origin;
}
+
+} // namespace content
diff --git a/chromium/content/browser/webui/shared_resources_data_source.h b/chromium/content/browser/webui/shared_resources_data_source.h
index 87b5121ad22..5c300ef68ec 100644
--- a/chromium/content/browser/webui/shared_resources_data_source.h
+++ b/chromium/content/browser/webui/shared_resources_data_source.h
@@ -9,18 +9,20 @@
#include "base/compiler_specific.h"
#include "content/public/browser/url_data_source.h"
+namespace content {
+
// A DataSource for chrome://resources/ URLs.
-class SharedResourcesDataSource : public content::URLDataSource {
+class SharedResourcesDataSource : public URLDataSource {
public:
SharedResourcesDataSource();
- // content::URLDataSource implementation.
+ // URLDataSource implementation.
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;
+ const URLDataSource::GotDataCallback& callback) override;
std::string GetMimeType(const std::string&) const override;
std::string GetAccessControlAllowOriginForOrigin(
const std::string& origin) const override;
@@ -31,4 +33,6 @@ class SharedResourcesDataSource : public content::URLDataSource {
DISALLOW_COPY_AND_ASSIGN(SharedResourcesDataSource);
};
+} // namespace content
+
#endif // CONTENT_BROWSER_WEBUI_SHARED_RESOURCES_DATA_SOURCE_H_
diff --git a/chromium/content/browser/webui/url_data_manager.cc b/chromium/content/browser/webui/url_data_manager.cc
index 74fa0a67e1d..ffd992e1463 100644
--- a/chromium/content/browser/webui/url_data_manager.cc
+++ b/chromium/content/browser/webui/url_data_manager.cc
@@ -39,7 +39,7 @@ URLDataManager* GetFromBrowserContext(BrowserContext* context) {
static void AddDataSourceOnIOThread(
ResourceContext* resource_context,
scoped_refptr<URLDataSourceImpl> data_source) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
GetURLDataManagerForResourceContext(resource_context)->AddDataSource(
data_source.get());
}
@@ -57,7 +57,7 @@ URLDataManager::~URLDataManager() {
}
void URLDataManager::AddDataSource(URLDataSourceImpl* source) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&AddDataSourceOnIOThread,
@@ -67,7 +67,7 @@ void URLDataManager::AddDataSource(URLDataSourceImpl* source) {
// static
void URLDataManager::DeleteDataSources() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
URLDataSources sources;
{
base::AutoLock lock(g_delete_lock.Get());
diff --git a/chromium/content/browser/webui/url_data_manager_backend.cc b/chromium/content/browser/webui/url_data_manager_backend.cc
index 9e12864b322..1c171c2645e 100644
--- a/chromium/content/browser/webui/url_data_manager_backend.cc
+++ b/chromium/content/browser/webui/url_data_manager_backend.cc
@@ -11,14 +11,15 @@
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/debug/alias.h"
-#include "base/debug/trace_event.h"
#include "base/lazy_instance.h"
#include "base/memory/ref_counted.h"
#include "base/memory/ref_counted_memory.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
+#include "base/profiler/scoped_tracker.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event.h"
#include "content/browser/appcache/view_appcache_internals_job.h"
#include "content/browser/fileapi/chrome_blob_storage_context.h"
#include "content/browser/histogram_internals_request_job.h"
@@ -365,15 +366,15 @@ bool URLRequestChromeJob::ReadRawData(net::IOBuffer* buf, int buf_size,
void URLRequestChromeJob::CompleteRead(net::IOBuffer* buf, int buf_size,
int* bytes_read) {
- // http://crbug.com/373841
- char url_buf[128];
- base::strlcpy(url_buf, request_->url().spec().c_str(), arraysize(url_buf));
- base::debug::Alias(url_buf);
-
int remaining = static_cast<int>(data_->size()) - data_offset_;
if (buf_size > remaining)
buf_size = remaining;
if (buf_size > 0) {
+ // TODO(pkasting): Remove ScopedTracker below once crbug.com/455423 is
+ // fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "455423 URLRequestChromeJob::CompleteRead memcpy"));
memcpy(buf->data(), data_->front() + data_offset_, buf_size);
data_offset_ += buf_size;
}
@@ -434,7 +435,7 @@ namespace {
void GetMimeTypeOnUI(URLDataSourceImpl* source,
const std::string& path,
const base::WeakPtr<URLRequestChromeJob>& job) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
std::string mime_type = source->source()->GetMimeType(path);
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
@@ -550,7 +551,7 @@ URLDataManagerBackend::CreateProtocolHandler(
void URLDataManagerBackend::AddDataSource(
URLDataSourceImpl* source) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
DataSourceMap::iterator i = data_sources_.find(source->source_name());
if (i != data_sources_.end()) {
if (!source->source()->ShouldReplaceExistingSource())
@@ -713,7 +714,7 @@ void URLDataManagerBackend::DataAvailable(RequestID request_id,
// Forward this data on to the pending net::URLRequest, if it exists.
PendingRequestMap::iterator i = pending_requests_.find(request_id);
if (i != pending_requests_.end()) {
- URLRequestChromeJob* job(i->second);
+ URLRequestChromeJob* job = i->second;
pending_requests_.erase(i);
job->DataAvailable(bytes);
}
diff --git a/chromium/content/browser/webui/url_data_manager_backend.h b/chromium/content/browser/webui/url_data_manager_backend.h
index 19d6bd24aec..e0af605e8a7 100644
--- a/chromium/content/browser/webui/url_data_manager_backend.h
+++ b/chromium/content/browser/webui/url_data_manager_backend.h
@@ -43,11 +43,11 @@ class URLDataManagerBackend : public base::SupportsUserData::Data {
// 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,
- AppCacheServiceImpl* appcache_service,
- ChromeBlobStorageContext* blob_storage_context);
+ CONTENT_EXPORT static net::URLRequestJobFactory::ProtocolHandler*
+ CreateProtocolHandler(content::ResourceContext* resource_context,
+ bool is_incognito,
+ AppCacheServiceImpl* appcache_service,
+ ChromeBlobStorageContext* blob_storage_context);
// Adds a DataSource to the collection of data sources.
void AddDataSource(URLDataSourceImpl* source);
diff --git a/chromium/content/browser/webui/url_data_manager_backend_unittest.cc b/chromium/content/browser/webui/url_data_manager_backend_unittest.cc
new file mode 100644
index 00000000000..d18186da763
--- /dev/null
+++ b/chromium/content/browser/webui/url_data_manager_backend_unittest.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 "base/memory/scoped_ptr.h"
+#include "base/run_loop.h"
+#include "content/browser/webui/url_data_manager_backend.h"
+#include "content/public/test/mock_resource_context.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_response_info.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_job.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+namespace {
+
+// Create a request for a chrome://resource URL passing the supplied |origin|
+// header and checking that the response header Access-Control-Allow-Origin has
+// value |expected_access_control_allow_origin_value|.
+void RunAccessControlAllowOriginTest(
+ const std::string& origin,
+ const std::string& expected_access_control_allow_origin_value) {
+ TestBrowserThreadBundle thread_bundle;
+ MockResourceContext resource_context;
+ scoped_ptr<net::URLRequestJobFactory::ProtocolHandler> protocol_handler(
+ URLDataManagerBackend::CreateProtocolHandler(&resource_context, false,
+ nullptr, nullptr));
+ net::URLRequestContext url_request_context;
+ scoped_ptr<net::URLRequest> request = url_request_context.CreateRequest(
+ GURL("chrome://resources/polymer/polymer/polymer.js"), net::HIGHEST,
+ nullptr);
+ request->SetExtraRequestHeaderByName("Origin", origin, true);
+ scoped_refptr<net::URLRequestJob> job =
+ protocol_handler->MaybeCreateJob(request.get(), nullptr);
+ ASSERT_TRUE(job);
+ job->Start();
+ base::RunLoop().RunUntilIdle();
+ net::HttpResponseInfo response;
+ job->GetResponseInfo(&response);
+ EXPECT_TRUE(response.headers->HasHeaderValue(
+ "Access-Control-Allow-Origin",
+ expected_access_control_allow_origin_value));
+}
+
+} // namespace
+
+TEST(UrlDataManagerBackendTest, AccessControlAllowOriginChromeUrl) {
+ RunAccessControlAllowOriginTest("chrome://webui", "chrome://webui");
+}
+
+TEST(UrlDataManagerBackendTest, AccessControlAllowOriginNonChromeUrl) {
+ RunAccessControlAllowOriginTest("http://www.example.com", "null");
+}
+
+} // namespace content
diff --git a/chromium/content/browser/webui/url_data_source_impl.cc b/chromium/content/browser/webui/url_data_source_impl.cc
index 31e45adcd2a..10b88ec7d45 100644
--- a/chromium/content/browser/webui/url_data_source_impl.cc
+++ b/chromium/content/browser/webui/url_data_source_impl.cc
@@ -51,7 +51,7 @@ void URLDataSourceImpl::SendResponse(
void URLDataSourceImpl::SendResponseOnIOThread(
int request_id,
scoped_refptr<base::RefCountedMemory> bytes) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (backend_)
backend_->DataAvailable(request_id, bytes.get());
}
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 caa8f9ad858..f3a5777d3da 100644
--- a/chromium/content/browser/webui/web_ui_data_source_impl.cc
+++ b/chromium/content/browser/webui/web_ui_data_source_impl.cc
@@ -10,8 +10,9 @@
#include "base/memory/ref_counted_memory.h"
#include "base/strings/string_util.h"
#include "content/grit/content_resources.h"
+#include "content/public/browser/content_browser_client.h"
#include "content/public/common/content_client.h"
-#include "mojo/public/js/constants.h"
+#include "third_party/mojo/src/mojo/public/js/constants.h"
#include "ui/base/webui/jstemplate_builder.h"
#include "ui/base/webui/web_ui_util.h"
@@ -31,6 +32,7 @@ WebUIDataSource* WebUIDataSource::AddMojoDataSource(
const char* path;
int id;
} resources[] = {
+ { mojo::kBindingsModuleName, IDR_MOJO_BINDINGS_JS },
{ mojo::kBufferModuleName, IDR_MOJO_BUFFER_JS },
{ mojo::kCodecModuleName, IDR_MOJO_CODEC_JS },
{ mojo::kConnectionModuleName, IDR_MOJO_CONNECTION_JS },
@@ -230,8 +232,10 @@ void WebUIDataSourceImpl::StartDataRequest(
void WebUIDataSourceImpl::SendLocalizedStringsAsJSON(
const URLDataSource::GotDataCallback& callback) {
std::string template_data;
- if (!disable_set_font_strings_)
- webui::SetFontAndTextDirection(&localized_strings_);
+ if (!disable_set_font_strings_) {
+ std::string locale = GetContentClient()->browser()->GetApplicationLocale();
+ webui::SetLoadTimeDataDefaults(locale, &localized_strings_);
+ }
webui::AppendJsonJS(&localized_strings_, &template_data);
callback.Run(base::RefCountedString::TakeString(&template_data));
diff --git a/chromium/content/browser/webui/web_ui_mojo_browsertest.cc b/chromium/content/browser/webui/web_ui_mojo_browsertest.cc
index 9830f1df006..847e39e7598 100644
--- a/chromium/content/browser/webui/web_ui_mojo_browsertest.cc
+++ b/chromium/content/browser/webui/web_ui_mojo_browsertest.cc
@@ -25,10 +25,10 @@
#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 "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"
+#include "third_party/mojo/src/mojo/edk/test/test_utils.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/interface_impl.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h"
+#include "third_party/mojo/src/mojo/public/js/constants.h"
namespace content {
namespace {
@@ -40,7 +40,8 @@ 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::kBufferModuleName ||
+ if (id == mojo::kBindingsModuleName ||
+ id == mojo::kBufferModuleName ||
id == mojo::kCodecModuleName ||
id == mojo::kConnectionModuleName ||
id == mojo::kConnectorModuleName ||
@@ -66,7 +67,13 @@ class BrowserTargetImpl : public mojo::InterfaceImpl<BrowserTarget> {
~BrowserTargetImpl() override {}
// mojo::InterfaceImpl<BrowserTarget> overrides:
- void PingResponse() override { NOTREACHED(); }
+ void Start(const mojo::Closure& closure) override {
+ closure.Run();
+ }
+ void Stop() override {
+ got_message = true;
+ run_loop_->Quit();
+ }
protected:
base::RunLoop* run_loop_;
@@ -75,26 +82,6 @@ class BrowserTargetImpl : public mojo::InterfaceImpl<BrowserTarget> {
DISALLOW_COPY_AND_ASSIGN(BrowserTargetImpl);
};
-class PingBrowserTargetImpl : public BrowserTargetImpl {
- public:
- explicit PingBrowserTargetImpl(base::RunLoop* run_loop)
- : BrowserTargetImpl(run_loop) {}
-
- ~PingBrowserTargetImpl() override {}
-
- // mojo::InterfaceImpl<BrowserTarget> overrides:
- void OnConnectionEstablished() override { client()->Ping(); }
-
- // Quit the RunLoop when called.
- void PingResponse() override {
- got_message = true;
- run_loop_->Quit();
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(PingBrowserTargetImpl);
-};
-
// WebUIController that sets up mojo bindings.
class TestWebUIController : public WebUIController {
public:
@@ -125,7 +112,7 @@ class PingTestWebUIController : public TestWebUIController {
~PingTestWebUIController() override {}
// WebUIController overrides:
- void RenderViewCreated(RenderViewHost* render_view_host) override {
+ void RenderViewCreated(RenderViewHost* render_view_host) override {
render_view_host->GetMainFrame()->GetServiceRegistry()->
AddService<BrowserTarget>(base::Bind(
&PingTestWebUIController::CreateHandler, base::Unretained(this)));
@@ -133,7 +120,7 @@ class PingTestWebUIController : public TestWebUIController {
void CreateHandler(mojo::InterfaceRequest<BrowserTarget> request) {
browser_target_.reset(mojo::WeakBindToRequest(
- new PingBrowserTargetImpl(run_loop_), &request));
+ new BrowserTargetImpl(run_loop_), &request));
}
private:
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 c2f1c908c0a..3506207247e 100644
--- a/chromium/content/browser/zygote_host/zygote_host_impl_linux.cc
+++ b/chromium/content/browser/zygote_host/zygote_host_impl_linux.cc
@@ -22,6 +22,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "base/metrics/histogram.h"
+#include "base/metrics/sparse_histogram.h"
#include "base/path_service.h"
#include "base/posix/eintr_wrapper.h"
#include "base/posix/unix_domain_socket_linux.h"
@@ -38,7 +39,10 @@
#include "content/public/browser/content_browser_client.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/result_codes.h"
-#include "sandbox/linux/suid/client/setuid_sandbox_client.h"
+#include "sandbox/linux/services/credentials.h"
+#include "sandbox/linux/services/namespace_sandbox.h"
+#include "sandbox/linux/services/namespace_utils.h"
+#include "sandbox/linux/suid/client/setuid_sandbox_host.h"
#include "sandbox/linux/suid/common/sandbox.h"
#include "ui/base/ui_base_switches.h"
#include "ui/gfx/switches.h"
@@ -49,12 +53,14 @@
namespace content {
+namespace {
+
// Receive a fixed message on fd and return the sender's PID.
// Returns true if the message received matches the expected message.
-static bool ReceiveFixedMessage(int fd,
- const char* expect_msg,
- size_t expect_len,
- base::ProcessId* sender_pid) {
+bool ReceiveFixedMessage(int fd,
+ const char* expect_msg,
+ size_t expect_len,
+ base::ProcessId* sender_pid) {
char buf[expect_len + 1];
ScopedVector<base::ScopedFD> fds_vec;
@@ -69,6 +75,8 @@ static bool ReceiveFixedMessage(int fd,
return true;
}
+} // namespace
+
// static
ZygoteHost* ZygoteHost::GetInstance() {
return ZygoteHostImpl::GetInstance();
@@ -79,7 +87,7 @@ ZygoteHostImpl::ZygoteHostImpl()
control_lock_(),
pid_(-1),
init_(false),
- using_suid_sandbox_(false),
+ use_suid_sandbox_for_adj_oom_score_(false),
sandbox_binary_(),
have_read_sandbox_status_word_(false),
sandbox_status_(0),
@@ -141,8 +149,16 @@ void ZygoteHostImpl::Init(const std::string& sandbox_cmd) {
sandbox_binary_ = sandbox_cmd.c_str();
+ const bool using_namespace_sandbox = ShouldUseNamespaceSandbox();
// A non empty sandbox_cmd means we want a SUID sandbox.
- using_suid_sandbox_ = !sandbox_cmd.empty();
+ const bool using_suid_sandbox =
+ !sandbox_cmd.empty() && !using_namespace_sandbox;
+
+ // Use the SUID sandbox for adjusting OOM scores when we are using the setuid
+ // or namespace sandbox. This is needed beacuse the processes are
+ // non-dumpable, so /proc/pid/oom_score_adj can only be written by root.
+ use_suid_sandbox_for_adj_oom_score_ =
+ using_namespace_sandbox || using_suid_sandbox;
// Start up the sandbox host process and get the file descriptor for the
// renderers to talk to it.
@@ -150,21 +166,24 @@ void ZygoteHostImpl::Init(const std::string& sandbox_cmd) {
fds_to_map.push_back(std::make_pair(sfd, GetSandboxFD()));
base::ScopedFD dummy_fd;
- if (using_suid_sandbox_) {
- scoped_ptr<sandbox::SetuidSandboxClient>
- sandbox_client(sandbox::SetuidSandboxClient::Create());
- sandbox_client->PrependWrapper(&cmd_line);
- sandbox_client->SetupLaunchOptions(&options, &fds_to_map, &dummy_fd);
- sandbox_client->SetupLaunchEnvironment();
+ if (using_suid_sandbox) {
+ scoped_ptr<sandbox::SetuidSandboxHost> sandbox_host(
+ sandbox::SetuidSandboxHost::Create());
+ sandbox_host->PrependWrapper(&cmd_line);
+ sandbox_host->SetupLaunchOptions(&options, &fds_to_map, &dummy_fd);
+ sandbox_host->SetupLaunchEnvironment();
}
- base::ProcessHandle process = -1;
options.fds_to_remap = &fds_to_map;
- base::LaunchProcess(cmd_line.argv(), options, &process);
- CHECK(process != -1) << "Failed to launch zygote process";
+ base::Process process =
+ using_namespace_sandbox
+ ? sandbox::NamespaceSandbox::LaunchProcess(cmd_line, options)
+ : base::LaunchProcess(cmd_line, options);
+ CHECK(process.IsValid()) << "Failed to launch zygote process";
+
dummy_fd.reset();
- if (using_suid_sandbox_) {
+ if (using_suid_sandbox || using_namespace_sandbox) {
// The SUID sandbox will execute the zygote in a new PID namespace, and
// the main zygote process will then fork from there. Watch now our
// elaborate dance to find and validate the zygote's PID.
@@ -188,13 +207,15 @@ void ZygoteHostImpl::Init(const std::string& sandbox_cmd) {
fds[0], kZygoteHelloMessage, sizeof(kZygoteHelloMessage), &pid_));
CHECK_GT(pid_, 1);
- if (process != pid_) {
+ if (process.Pid() != pid_) {
// Reap the sandbox.
- base::EnsureProcessGetsReaped(process);
+ base::EnsureProcessGetsReaped(process.Pid());
}
} else {
// Not using the SUID sandbox.
- pid_ = process;
+ // Note that ~base::Process() will reset the internal value, but there's no
+ // real "handle" on POSIX so that is safe.
+ pid_ = process.Pid();
}
close(fds[1]);
@@ -281,7 +302,9 @@ ssize_t ZygoteHostImpl::ReadReply(void* buf, size_t buf_len) {
sizeof(sandbox_status_)) {
return -1;
}
+
have_read_sandbox_status_word_ = true;
+ UMA_HISTOGRAM_SPARSE_SLOWLY("Linux.SandboxStatus", sandbox_status_);
}
return HANDLE_EINTR(read(control_fd_, buf, buf_len));
@@ -369,7 +392,7 @@ pid_t ZygoteHostImpl::ForkRequest(const std::vector<std::string>& argv,
Pickle reply_pickle(buf, len);
PickleIterator iter(reply_pickle);
- if (len <= 0 || !reply_pickle.ReadInt(&iter, &pid))
+ if (len <= 0 || !iter.ReadInt(&pid))
return base::kNullProcessHandle;
// If there is a nonempty UMA name string, then there is a UMA
@@ -377,10 +400,10 @@ pid_t ZygoteHostImpl::ForkRequest(const std::vector<std::string>& argv,
std::string uma_name;
int uma_sample;
int uma_boundary_value;
- if (reply_pickle.ReadString(&iter, &uma_name) &&
+ if (iter.ReadString(&uma_name) &&
!uma_name.empty() &&
- reply_pickle.ReadInt(&iter, &uma_sample) &&
- reply_pickle.ReadInt(&iter, &uma_boundary_value)) {
+ iter.ReadInt(&uma_sample) &&
+ iter.ReadInt(&uma_boundary_value)) {
// We cannot use the UMA_HISTOGRAM_ENUMERATION macro here,
// because that's only for when the name is the same every time.
// Here we're using whatever name we got from the other side.
@@ -457,7 +480,7 @@ void ZygoteHostImpl::AdjustRendererOOMScore(base::ProcessHandle pid,
selinux_valid = true;
}
- if (using_suid_sandbox_ && !selinux) {
+ if (use_suid_sandbox_for_adj_oom_score_ && !selinux) {
#if defined(USE_TCMALLOC)
// If heap profiling is running, these processes are not exiting, at least
// on ChromeOS. The easiest thing to do is not launch them when profiling.
@@ -471,17 +494,17 @@ void ZygoteHostImpl::AdjustRendererOOMScore(base::ProcessHandle pid,
adj_oom_score_cmdline.push_back(base::Int64ToString(pid));
adj_oom_score_cmdline.push_back(base::IntToString(score));
- base::ProcessHandle sandbox_helper_process;
+ base::Process sandbox_helper_process;
base::LaunchOptions options;
// sandbox_helper_process is a setuid binary.
options.allow_new_privs = true;
- if (base::LaunchProcess(adj_oom_score_cmdline, options,
- &sandbox_helper_process)) {
- base::EnsureProcessGetsReaped(sandbox_helper_process);
- }
- } else if (!using_suid_sandbox_) {
+ sandbox_helper_process =
+ base::LaunchProcess(adj_oom_score_cmdline, options);
+ if (sandbox_helper_process.IsValid())
+ base::EnsureProcessGetsReaped(sandbox_helper_process.Pid());
+ } else if (!use_suid_sandbox_for_adj_oom_score_) {
if (!base::AdjustOOMScore(pid, score))
PLOG(ERROR) << "Failed to adjust OOM score of renderer with pid " << pid;
}
@@ -532,8 +555,7 @@ base::TerminationStatus ZygoteHostImpl::GetTerminationStatus(
Pickle read_pickle(buf, len);
int tmp_status, tmp_exit_code;
PickleIterator iter(read_pickle);
- if (!read_pickle.ReadInt(&iter, &tmp_status) ||
- !read_pickle.ReadInt(&iter, &tmp_exit_code)) {
+ if (!iter.ReadInt(&tmp_status) || !iter.ReadInt(&tmp_exit_code)) {
LOG(WARNING)
<< "Error parsing GetTerminationStatus response from zygote.";
} else {
@@ -559,4 +581,22 @@ int ZygoteHostImpl::GetSandboxStatus() const {
return 0;
}
+bool ZygoteHostImpl::ShouldUseNamespaceSandbox() {
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
+ if (command_line.HasSwitch(switches::kNoSandbox)) {
+ return false;
+ }
+
+ if (command_line.HasSwitch(switches::kDisableNamespaceSandbox)) {
+ return false;
+ }
+
+ if (!sandbox::Credentials::CanCreateProcessInNewUserNS()) {
+ return false;
+ }
+
+ return true;
+}
+
} // namespace content
diff --git a/chromium/content/browser/zygote_host/zygote_host_impl_linux.h b/chromium/content/browser/zygote_host/zygote_host_impl_linux.h
index e18e098088b..643989f07ee 100644
--- a/chromium/content/browser/zygote_host/zygote_host_impl_linux.h
+++ b/chromium/content/browser/zygote_host/zygote_host_impl_linux.h
@@ -82,6 +82,9 @@ class CONTENT_EXPORT ZygoteHostImpl : public ZygoteHost {
ssize_t ReadReply(void* buf, size_t buflen);
+ // Whether we should use the namespace sandbox instead of the setuid sandbox.
+ bool ShouldUseNamespaceSandbox();
+
int control_fd_; // the socket to the zygote
// A lock protecting all communication with the zygote. This lock must be
// acquired before sending a command and released after the result has been
@@ -89,7 +92,7 @@ class CONTENT_EXPORT ZygoteHostImpl : public ZygoteHost {
base::Lock control_lock_;
pid_t pid_;
bool init_;
- bool using_suid_sandbox_;
+ bool use_suid_sandbox_for_adj_oom_score_;
std::string sandbox_binary_;
bool have_read_sandbox_status_word_;
int sandbox_status_;
diff --git a/chromium/content/child/BUILD.gn b/chromium/content/child/BUILD.gn
index 8e400c3cd7a..4bbcb9262b5 100644
--- a/chromium/content/child/BUILD.gn
+++ b/chromium/content/child/BUILD.gn
@@ -13,19 +13,29 @@ source_set("child") {
visibility = [ "//content/public/child:child_sources" ]
sources = rebase_path(content_child_gypi_values.private_child_sources,
- ".", "//content")
+ ".",
+ "//content")
+
+ public_deps = [
+ "//third_party/mojo/src/mojo/edk/system",
+ ]
deps = [
"//base",
+ "//components/mime_util",
"//components/tracing",
+ "//components/webcrypto",
+ "//content/common:mojo_bindings",
+ "//mojo/application/public/interfaces",
"//mojo/common",
"//mojo/environment:chromium",
- "//mojo/public/interfaces/application",
"//skia",
"//third_party/icu",
"//ui/base",
+ "//ui/events/gestures/blink",
"//ui/gfx",
"//ui/gfx/geometry",
+ "//ui/native_theme",
"//url",
]
@@ -37,12 +47,12 @@ source_set("child") {
}
if (is_android) {
- deps += [
- "//third_party/android_tools:cpu_features",
- ]
+ deps += [ "//third_party/android_tools:cpu_features" ]
}
- if (!enable_plugins) {
+ if (enable_plugins) {
+ deps += [ "//ppapi/proxy" ]
+ } else {
sources -= [
"browser_font_resource_trusted.cc",
"npapi/plugin_host.cc",
@@ -83,19 +93,16 @@ source_set("child") {
"npapi/webplugin_ime_win.h",
]
} else if (is_android) {
- sources -= [
- "npapi/webplugin_delegate_impl_android.cc",
- ]
+ sources -= [ "npapi/webplugin_delegate_impl_android.cc" ]
}
if (use_aura) {
- sources -= [
- "npapi/webplugin_delegate_impl_aura.cc",
- ]
+ sources -= [ "npapi/webplugin_delegate_impl_aura.cc" ]
}
}
configs += [
"//content:content_implementation",
+ "//build/config/compiler:no_size_t_to_int_warning",
]
if (is_ios) {
@@ -104,11 +111,13 @@ source_set("child") {
sources = []
} else {
deps += [
+ "//components/scheduler:scheduler",
"//content/app/resources",
"//content/app/strings",
"//crypto:platform",
"//storage/common",
"//third_party/WebKit/public:blink",
+ "//third_party/WebKit/public:image_resources",
"//third_party/WebKit/public:resources",
"//third_party/npapi",
]
@@ -122,12 +131,4 @@ source_set("child") {
if (is_win || !use_aura) {
sources -= [ "npapi/webplugin_delegate_impl_aura.cc" ]
}
-
- if (!use_openssl) {
- sources += rebase_path(content_child_gypi_values.webcrypto_nss_sources,
- ".", "//content")
- } else {
- sources += rebase_path(content_child_gypi_values.webcrypto_openssl_sources,
- ".", "//content")
- }
}
diff --git a/chromium/content/child/DEPS b/chromium/content/child/DEPS
index be1e09fb539..6670427c8d3 100644
--- a/chromium/content/child/DEPS
+++ b/chromium/content/child/DEPS
@@ -1,12 +1,14 @@
include_rules = [
+ # Allow inclusion of specific components that we depend on. We may only
+ # depend on components which we share with the mojo html_viewer.
+ "+components/mime_util",
+ "+components/scheduler/child",
+ "+components/scheduler/common",
"+components/tracing",
+ "+components/webcrypto",
+
"+content/app/strings/grit", # For generated headers
"+content/public/child",
"+media/base/android",
+ "+v8/include/v8.h"
]
-
-specific_include_rules = {
- "content_child_helpers\.cc": [
- "+v8/include/v8.h"
- ]
-}
diff --git a/chromium/content/child/appcache/appcache_frontend_impl.cc b/chromium/content/child/appcache/appcache_frontend_impl.cc
index 8ede37a21ba..76b4b1f4e54 100644
--- a/chromium/content/child/appcache/appcache_frontend_impl.cc
+++ b/chromium/content/child/appcache/appcache_frontend_impl.cc
@@ -89,68 +89,46 @@ void AppCacheFrontendImpl::OnContentBlocked(int host_id,
// Ensure that enum values never get out of sync with the
// ones declared for use within the WebKit api
-COMPILE_ASSERT((int)WebApplicationCacheHost::Uncached ==
- (int)APPCACHE_STATUS_UNCACHED, Uncached);
-COMPILE_ASSERT((int)WebApplicationCacheHost::Idle ==
- (int)APPCACHE_STATUS_IDLE, Idle);
-COMPILE_ASSERT((int)WebApplicationCacheHost::Checking ==
- (int)APPCACHE_STATUS_CHECKING, Checking);
-COMPILE_ASSERT((int)WebApplicationCacheHost::Downloading ==
- (int)APPCACHE_STATUS_DOWNLOADING, Downloading);
-COMPILE_ASSERT((int)WebApplicationCacheHost::UpdateReady ==
- (int)APPCACHE_STATUS_UPDATE_READY, UpdateReady);
-COMPILE_ASSERT((int)WebApplicationCacheHost::Obsolete ==
- (int)APPCACHE_STATUS_OBSOLETE, Obsolete);
-
-COMPILE_ASSERT((int)WebApplicationCacheHost::CheckingEvent ==
- (int)APPCACHE_CHECKING_EVENT, CheckingEvent);
-COMPILE_ASSERT((int)WebApplicationCacheHost::ErrorEvent ==
- (int)APPCACHE_ERROR_EVENT, ErrorEvent);
-COMPILE_ASSERT((int)WebApplicationCacheHost::NoUpdateEvent ==
- (int)APPCACHE_NO_UPDATE_EVENT, NoUpdateEvent);
-COMPILE_ASSERT((int)WebApplicationCacheHost::DownloadingEvent ==
- (int)APPCACHE_DOWNLOADING_EVENT, DownloadingEvent);
-COMPILE_ASSERT((int)WebApplicationCacheHost::ProgressEvent ==
- (int)APPCACHE_PROGRESS_EVENT, ProgressEvent);
-COMPILE_ASSERT((int)WebApplicationCacheHost::UpdateReadyEvent ==
- (int)APPCACHE_UPDATE_READY_EVENT, UpdateReadyEvent);
-COMPILE_ASSERT((int)WebApplicationCacheHost::CachedEvent ==
- (int)APPCACHE_CACHED_EVENT, CachedEvent);
-COMPILE_ASSERT((int)WebApplicationCacheHost::ObsoleteEvent ==
- (int)APPCACHE_OBSOLETE_EVENT, ObsoleteEvent);
-
-COMPILE_ASSERT((int)WebConsoleMessage::LevelDebug ==
- (int)APPCACHE_LOG_DEBUG, LevelDebug);
-COMPILE_ASSERT((int)WebConsoleMessage::LevelLog ==
- (int)APPCACHE_LOG_INFO, LevelLog);
-COMPILE_ASSERT((int)WebConsoleMessage::LevelWarning ==
- (int)APPCACHE_LOG_WARNING, LevelWarning);
-COMPILE_ASSERT((int)WebConsoleMessage::LevelError ==
- (int)APPCACHE_LOG_ERROR, LevelError);
-
-COMPILE_ASSERT((int)WebApplicationCacheHost::ManifestError ==
- (int)APPCACHE_MANIFEST_ERROR,
- ManifestError);
-COMPILE_ASSERT((int)WebApplicationCacheHost::SignatureError ==
- (int)APPCACHE_SIGNATURE_ERROR,
- SignatureError);
-COMPILE_ASSERT((int)WebApplicationCacheHost::ResourceError ==
- (int)APPCACHE_RESOURCE_ERROR,
- ResourceError);
-COMPILE_ASSERT((int)WebApplicationCacheHost::ChangedError ==
- (int)APPCACHE_CHANGED_ERROR,
- ChangedError);
-COMPILE_ASSERT((int)WebApplicationCacheHost::AbortError ==
- (int)APPCACHE_ABORT_ERROR,
- AbortError);
-COMPILE_ASSERT((int)WebApplicationCacheHost::QuotaError ==
- (int)APPCACHE_QUOTA_ERROR,
- QuotaError);
-COMPILE_ASSERT((int)WebApplicationCacheHost::PolicyError ==
- (int)APPCACHE_POLICY_ERROR,
- PolicyError);
-COMPILE_ASSERT((int)WebApplicationCacheHost::UnknownError ==
- (int)APPCACHE_UNKNOWN_ERROR,
- UnknownError);
+
+#define STATIC_ASSERT_ENUM(a, b, desc) \
+ static_assert((int)a == (int)b, desc)
+
+// Confirm that WebApplicationCacheHost::<a> == APPCACHE_<b>.
+#define STATIC_ASSERT_WAC_ENUM(a, b) \
+ STATIC_ASSERT_ENUM(WebApplicationCacheHost:: a, APPCACHE_##b, #a)
+
+STATIC_ASSERT_WAC_ENUM(Uncached, STATUS_UNCACHED);
+STATIC_ASSERT_WAC_ENUM(Idle, STATUS_IDLE);
+STATIC_ASSERT_WAC_ENUM(Checking, STATUS_CHECKING);
+STATIC_ASSERT_WAC_ENUM(Downloading, STATUS_DOWNLOADING);
+STATIC_ASSERT_WAC_ENUM(UpdateReady, STATUS_UPDATE_READY);
+STATIC_ASSERT_WAC_ENUM(Obsolete, STATUS_OBSOLETE);
+
+STATIC_ASSERT_WAC_ENUM(CheckingEvent, CHECKING_EVENT);
+STATIC_ASSERT_WAC_ENUM(ErrorEvent, ERROR_EVENT);
+STATIC_ASSERT_WAC_ENUM(NoUpdateEvent, NO_UPDATE_EVENT);
+STATIC_ASSERT_WAC_ENUM(DownloadingEvent, DOWNLOADING_EVENT);
+STATIC_ASSERT_WAC_ENUM(ProgressEvent, PROGRESS_EVENT);
+STATIC_ASSERT_WAC_ENUM(UpdateReadyEvent, UPDATE_READY_EVENT);
+STATIC_ASSERT_WAC_ENUM(CachedEvent, CACHED_EVENT);
+STATIC_ASSERT_WAC_ENUM(ObsoleteEvent, OBSOLETE_EVENT);
+
+STATIC_ASSERT_WAC_ENUM(ManifestError, MANIFEST_ERROR);
+STATIC_ASSERT_WAC_ENUM(SignatureError, SIGNATURE_ERROR);
+STATIC_ASSERT_WAC_ENUM(ResourceError, RESOURCE_ERROR);
+STATIC_ASSERT_WAC_ENUM(ChangedError, CHANGED_ERROR);
+STATIC_ASSERT_WAC_ENUM(AbortError, ABORT_ERROR);
+STATIC_ASSERT_WAC_ENUM(QuotaError, QUOTA_ERROR);
+STATIC_ASSERT_WAC_ENUM(PolicyError, POLICY_ERROR);
+STATIC_ASSERT_WAC_ENUM(UnknownError, UNKNOWN_ERROR);
+
+// Confirm that WebConsoleMessage::<a> == APPCACHE_<b>.
+#define STATIC_ASSERT_WCM_ENUM(a, b) \
+ STATIC_ASSERT_ENUM(WebConsoleMessage:: a, APPCACHE_##b, #a)
+
+STATIC_ASSERT_WCM_ENUM(LevelDebug, LOG_DEBUG);
+STATIC_ASSERT_WCM_ENUM(LevelLog, LOG_INFO);
+STATIC_ASSERT_WCM_ENUM(LevelWarning, LOG_WARNING);
+STATIC_ASSERT_WCM_ENUM(LevelError, LOG_ERROR);
} // namespace content
diff --git a/chromium/content/child/assert_matching_enums.cc b/chromium/content/child/assert_matching_enums.cc
index 89ff842d483..0d087edac9a 100644
--- a/chromium/content/child/assert_matching_enums.cc
+++ b/chromium/content/child/assert_matching_enums.cc
@@ -15,49 +15,48 @@
namespace content {
-#define COMPILE_ASSERT_MATCHING_ENUM(expected, actual) \
- COMPILE_ASSERT(int(expected) == int(actual), mismatching_enums)
+#define STATIC_ASSERT_MATCHING_ENUM(expected, actual) \
+ static_assert(int(expected) == int(actual), "mismatching enums: " #expected)
// ScreenOrientationValues
-COMPILE_ASSERT_MATCHING_ENUM(blink::WebScreenOrientationLockDefault,
+STATIC_ASSERT_MATCHING_ENUM(blink::WebScreenOrientationLockDefault,
SCREEN_ORIENTATION_VALUES_DEFAULT);
-COMPILE_ASSERT_MATCHING_ENUM(blink::WebScreenOrientationLockPortraitPrimary,
+STATIC_ASSERT_MATCHING_ENUM(blink::WebScreenOrientationLockPortraitPrimary,
SCREEN_ORIENTATION_VALUES_PORTRAIT_PRIMARY);
-COMPILE_ASSERT_MATCHING_ENUM(blink::WebScreenOrientationLockPortraitSecondary,
+STATIC_ASSERT_MATCHING_ENUM(blink::WebScreenOrientationLockPortraitSecondary,
SCREEN_ORIENTATION_VALUES_PORTRAIT_SECONDARY);
-COMPILE_ASSERT_MATCHING_ENUM(blink::WebScreenOrientationLockLandscapePrimary,
+STATIC_ASSERT_MATCHING_ENUM(blink::WebScreenOrientationLockLandscapePrimary,
SCREEN_ORIENTATION_VALUES_LANDSCAPE_PRIMARY);
-COMPILE_ASSERT_MATCHING_ENUM(blink::WebScreenOrientationLockLandscapeSecondary,
+STATIC_ASSERT_MATCHING_ENUM(blink::WebScreenOrientationLockLandscapeSecondary,
SCREEN_ORIENTATION_VALUES_LANDSCAPE_SECONDARY);
-COMPILE_ASSERT_MATCHING_ENUM(blink::WebScreenOrientationLockAny,
+STATIC_ASSERT_MATCHING_ENUM(blink::WebScreenOrientationLockAny,
SCREEN_ORIENTATION_VALUES_ANY);
-COMPILE_ASSERT_MATCHING_ENUM(blink::WebScreenOrientationLockLandscape,
+STATIC_ASSERT_MATCHING_ENUM(blink::WebScreenOrientationLockLandscape,
SCREEN_ORIENTATION_VALUES_LANDSCAPE);
-COMPILE_ASSERT_MATCHING_ENUM(blink::WebScreenOrientationLockPortrait,
+STATIC_ASSERT_MATCHING_ENUM(blink::WebScreenOrientationLockPortrait,
SCREEN_ORIENTATION_VALUES_PORTRAIT);
-COMPILE_ASSERT_MATCHING_ENUM(blink::WebScreenOrientationLockNatural,
+STATIC_ASSERT_MATCHING_ENUM(blink::WebScreenOrientationLockNatural,
SCREEN_ORIENTATION_VALUES_NATURAL);
// SupportsType
-COMPILE_ASSERT_MATCHING_ENUM(blink::WebMimeRegistry::IsNotSupported,
+STATIC_ASSERT_MATCHING_ENUM(blink::WebMimeRegistry::IsNotSupported,
net::IsNotSupported);
-COMPILE_ASSERT_MATCHING_ENUM(blink::WebMimeRegistry::IsSupported,
+STATIC_ASSERT_MATCHING_ENUM(blink::WebMimeRegistry::IsSupported,
net::IsSupported);
-COMPILE_ASSERT_MATCHING_ENUM(blink::WebMimeRegistry::MayBeSupported,
+STATIC_ASSERT_MATCHING_ENUM(blink::WebMimeRegistry::MayBeSupported,
net::MayBeSupported);
// TargetProperty
-COMPILE_ASSERT_MATCHING_ENUM(
+STATIC_ASSERT_MATCHING_ENUM(
blink::WebCompositorAnimation::TargetPropertyTransform,
- cc::Animation::Transform);
-COMPILE_ASSERT_MATCHING_ENUM(
+ cc::Animation::TRANSFORM);
+STATIC_ASSERT_MATCHING_ENUM(
blink::WebCompositorAnimation::TargetPropertyOpacity,
- cc::Animation::Opacity);
-COMPILE_ASSERT_MATCHING_ENUM(
- blink::WebCompositorAnimation::TargetPropertyFilter,
- cc::Animation::Filter);
-COMPILE_ASSERT_MATCHING_ENUM(
+ cc::Animation::OPACITY);
+STATIC_ASSERT_MATCHING_ENUM(blink::WebCompositorAnimation::TargetPropertyFilter,
+ cc::Animation::FILTER);
+STATIC_ASSERT_MATCHING_ENUM(
blink::WebCompositorAnimation::TargetPropertyScrollOffset,
- cc::Animation::ScrollOffset);
+ cc::Animation::SCROLL_OFFSET);
} // namespace content
diff --git a/chromium/content/child/background_sync/OWNERS b/chromium/content/child/background_sync/OWNERS
new file mode 100644
index 00000000000..1e6deee91b7
--- /dev/null
+++ b/chromium/content/child/background_sync/OWNERS
@@ -0,0 +1 @@
+jkarlin@chromium.org
diff --git a/chromium/content/child/background_sync/PRESUBMIT.py b/chromium/content/child/background_sync/PRESUBMIT.py
new file mode 100644
index 00000000000..0d969d30a31
--- /dev/null
+++ b/chromium/content/child/background_sync/PRESUBMIT.py
@@ -0,0 +1,12 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Top-level presubmit script for src/content/child/background_sync/
+
+See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
+for more details about the presubmit API built into depot_tools.
+"""
+
+def CheckChangeOnUpload(input_api, output_api):
+ return input_api.canned_checks.CheckPatchFormatted(input_api, output_api)
diff --git a/chromium/content/child/background_sync/background_sync_provider.cc b/chromium/content/child/background_sync/background_sync_provider.cc
new file mode 100644
index 00000000000..cdf0353be23
--- /dev/null
+++ b/chromium/content/child/background_sync/background_sync_provider.cc
@@ -0,0 +1,242 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/child/background_sync/background_sync_provider.h"
+
+#include "base/bind.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/child/background_sync/background_sync_type_converters.h"
+#include "content/child/service_worker/web_service_worker_registration_impl.h"
+#include "content/child/worker_task_runner.h"
+#include "content/public/common/service_registry.h"
+#include "third_party/WebKit/public/platform/modules/background_sync/WebSyncError.h"
+#include "third_party/WebKit/public/platform/modules/background_sync/WebSyncRegistration.h"
+
+namespace content {
+namespace {
+
+// Returns the id of the given |service_worker_registration|, which
+// is only available on the implementation of the interface.
+int64 GetServiceWorkerRegistrationId(
+ blink::WebServiceWorkerRegistration* service_worker_registration) {
+ return static_cast<WebServiceWorkerRegistrationImpl*>(
+ service_worker_registration)->registration_id();
+}
+
+} // namespace
+
+BackgroundSyncProvider::BackgroundSyncProvider(
+ ServiceRegistry* service_registry)
+ : service_registry_(service_registry) {
+ DCHECK(service_registry);
+}
+
+BackgroundSyncProvider::~BackgroundSyncProvider() {
+}
+
+void BackgroundSyncProvider::registerBackgroundSync(
+ const blink::WebSyncRegistration* options,
+ blink::WebServiceWorkerRegistration* service_worker_registration,
+ blink::WebSyncRegistrationCallbacks* callbacks) {
+ DCHECK(options);
+ DCHECK(service_worker_registration);
+ DCHECK(callbacks);
+ int64 service_worker_registration_id =
+ GetServiceWorkerRegistrationId(service_worker_registration);
+ scoped_ptr<const blink::WebSyncRegistration> optionsPtr(options);
+ scoped_ptr<blink::WebSyncRegistrationCallbacks> callbacksPtr(callbacks);
+
+ // base::Unretained is safe here, as the mojo channel will be deleted (and
+ // will wipe its callbacks) before 'this' is deleted.
+ GetBackgroundSyncServicePtr()->Register(
+ mojo::ConvertTo<SyncRegistrationPtr>(*(optionsPtr.get())),
+ service_worker_registration_id,
+ base::Bind(&BackgroundSyncProvider::RegisterCallback,
+ base::Unretained(this), base::Passed(callbacksPtr.Pass())));
+}
+
+void BackgroundSyncProvider::unregisterBackgroundSync(
+ blink::WebSyncRegistration::Periodicity periodicity,
+ int64_t id,
+ const blink::WebString& tag,
+ blink::WebServiceWorkerRegistration* service_worker_registration,
+ blink::WebSyncUnregistrationCallbacks* callbacks) {
+ DCHECK(service_worker_registration);
+ DCHECK(callbacks);
+ int64 service_worker_registration_id =
+ GetServiceWorkerRegistrationId(service_worker_registration);
+ scoped_ptr<blink::WebSyncUnregistrationCallbacks> callbacksPtr(callbacks);
+
+ // base::Unretained is safe here, as the mojo channel will be deleted (and
+ // will wipe its callbacks) before 'this' is deleted.
+ GetBackgroundSyncServicePtr()->Unregister(
+ mojo::ConvertTo<BackgroundSyncPeriodicity>(periodicity), id, tag.utf8(),
+ service_worker_registration_id,
+ base::Bind(&BackgroundSyncProvider::UnregisterCallback,
+ base::Unretained(this), base::Passed(callbacksPtr.Pass())));
+}
+
+void BackgroundSyncProvider::getRegistration(
+ blink::WebSyncRegistration::Periodicity periodicity,
+ const blink::WebString& tag,
+ blink::WebServiceWorkerRegistration* service_worker_registration,
+ blink::WebSyncRegistrationCallbacks* callbacks) {
+ DCHECK(service_worker_registration);
+ DCHECK(callbacks);
+ int64 service_worker_registration_id =
+ GetServiceWorkerRegistrationId(service_worker_registration);
+ scoped_ptr<blink::WebSyncRegistrationCallbacks> callbacksPtr(callbacks);
+
+ // base::Unretained is safe here, as the mojo channel will be deleted (and
+ // will wipe its callbacks) before 'this' is deleted.
+ GetBackgroundSyncServicePtr()->GetRegistration(
+ mojo::ConvertTo<BackgroundSyncPeriodicity>(periodicity), tag.utf8(),
+ service_worker_registration_id,
+ base::Bind(&BackgroundSyncProvider::GetRegistrationCallback,
+ base::Unretained(this), base::Passed(callbacksPtr.Pass())));
+}
+
+void BackgroundSyncProvider::getRegistrations(
+ blink::WebSyncRegistration::Periodicity periodicity,
+ blink::WebServiceWorkerRegistration* service_worker_registration,
+ blink::WebSyncGetRegistrationsCallbacks* callbacks) {
+ DCHECK(service_worker_registration);
+ DCHECK(callbacks);
+ int64 service_worker_registration_id =
+ GetServiceWorkerRegistrationId(service_worker_registration);
+ scoped_ptr<blink::WebSyncGetRegistrationsCallbacks> callbacksPtr(callbacks);
+
+ // base::Unretained is safe here, as the mojo channel will be deleted (and
+ // will wipe its callbacks) before 'this' is deleted.
+ GetBackgroundSyncServicePtr()->GetRegistrations(
+ mojo::ConvertTo<BackgroundSyncPeriodicity>(periodicity),
+ service_worker_registration_id,
+ base::Bind(&BackgroundSyncProvider::GetRegistrationsCallback,
+ base::Unretained(this), base::Passed(callbacksPtr.Pass())));
+}
+
+void BackgroundSyncProvider::RegisterCallback(
+ scoped_ptr<blink::WebSyncRegistrationCallbacks> callbacks,
+ BackgroundSyncError error,
+ const SyncRegistrationPtr& options) {
+ // TODO(iclelland): Determine the correct error message to return in each case
+ scoped_ptr<blink::WebSyncRegistration> result;
+ switch (error) {
+ case BACKGROUND_SYNC_ERROR_NONE:
+ if (!options.is_null())
+ result =
+ mojo::ConvertTo<scoped_ptr<blink::WebSyncRegistration>>(options);
+ callbacks->onSuccess(result.release());
+ break;
+ case BACKGROUND_SYNC_ERROR_NOT_FOUND:
+ NOTREACHED();
+ break;
+ case BACKGROUND_SYNC_ERROR_STORAGE:
+ callbacks->onError(
+ new blink::WebSyncError(blink::WebSyncError::ErrorTypeUnknown,
+ "Background Sync is disabled."));
+ break;
+ case BACKGROUND_SYNC_ERROR_NO_SERVICE_WORKER:
+ callbacks->onError(
+ new blink::WebSyncError(blink::WebSyncError::ErrorTypeUnknown,
+ "No service worker is active."));
+ break;
+ }
+}
+
+void BackgroundSyncProvider::UnregisterCallback(
+ scoped_ptr<blink::WebSyncUnregistrationCallbacks> callbacks,
+ BackgroundSyncError error) {
+ // TODO(iclelland): Determine the correct error message to return in each case
+ switch (error) {
+ case BACKGROUND_SYNC_ERROR_NONE:
+ callbacks->onSuccess(new bool(true));
+ break;
+ case BACKGROUND_SYNC_ERROR_NOT_FOUND:
+ callbacks->onSuccess(new bool(false));
+ break;
+ case BACKGROUND_SYNC_ERROR_STORAGE:
+ callbacks->onError(
+ new blink::WebSyncError(blink::WebSyncError::ErrorTypeUnknown,
+ "Background Sync is disabled."));
+ break;
+ case BACKGROUND_SYNC_ERROR_NO_SERVICE_WORKER:
+ callbacks->onError(
+ new blink::WebSyncError(blink::WebSyncError::ErrorTypeUnknown,
+ "No service worker is active."));
+ break;
+ }
+}
+
+void BackgroundSyncProvider::GetRegistrationCallback(
+ scoped_ptr<blink::WebSyncRegistrationCallbacks> callbacks,
+ BackgroundSyncError error,
+ const SyncRegistrationPtr& options) {
+ // TODO(iclelland): Determine the correct error message to return in each case
+ scoped_ptr<blink::WebSyncRegistration> result;
+ switch (error) {
+ case BACKGROUND_SYNC_ERROR_NONE:
+ if (!options.is_null())
+ result =
+ mojo::ConvertTo<scoped_ptr<blink::WebSyncRegistration>>(options);
+ callbacks->onSuccess(result.release());
+ break;
+ case BACKGROUND_SYNC_ERROR_NOT_FOUND:
+ callbacks->onSuccess(nullptr);
+ break;
+ case BACKGROUND_SYNC_ERROR_STORAGE:
+ callbacks->onError(
+ new blink::WebSyncError(blink::WebSyncError::ErrorTypeUnknown,
+ "Background Sync is disabled."));
+ break;
+ case BACKGROUND_SYNC_ERROR_NO_SERVICE_WORKER:
+ callbacks->onError(
+ new blink::WebSyncError(blink::WebSyncError::ErrorTypeUnknown,
+ "No service worker is active."));
+ break;
+ }
+}
+
+void BackgroundSyncProvider::GetRegistrationsCallback(
+ scoped_ptr<blink::WebSyncGetRegistrationsCallbacks> callbacks,
+ BackgroundSyncError error,
+ const mojo::Array<SyncRegistrationPtr>& registrations) {
+ // TODO(iclelland): Determine the correct error message to return in each case
+ blink::WebVector<blink::WebSyncRegistration*>* results;
+ switch (error) {
+ case BACKGROUND_SYNC_ERROR_NONE:
+ results = new blink::WebVector<blink::WebSyncRegistration*>(
+ registrations.size());
+ for (size_t i = 0; i < registrations.size(); ++i) {
+ (*results)[i] = mojo::ConvertTo<scoped_ptr<blink::WebSyncRegistration>>(
+ registrations[i]).release();
+ }
+ callbacks->onSuccess(results);
+ break;
+ case BACKGROUND_SYNC_ERROR_NOT_FOUND:
+ // This error should never be returned from
+ // BackgroundSyncManager::GetRegistrations
+ NOTREACHED();
+ break;
+ case BACKGROUND_SYNC_ERROR_STORAGE:
+ callbacks->onError(
+ new blink::WebSyncError(blink::WebSyncError::ErrorTypeUnknown,
+ "Background Sync is disabled."));
+ break;
+ case BACKGROUND_SYNC_ERROR_NO_SERVICE_WORKER:
+ callbacks->onError(
+ new blink::WebSyncError(blink::WebSyncError::ErrorTypeUnknown,
+ "No service worker is active."));
+ break;
+ }
+}
+
+BackgroundSyncServicePtr&
+BackgroundSyncProvider::GetBackgroundSyncServicePtr() {
+ if (!background_sync_service_.get())
+ service_registry_->ConnectToRemoteService(&background_sync_service_);
+ return background_sync_service_;
+}
+
+} // namespace content
diff --git a/chromium/content/child/background_sync/background_sync_provider.h b/chromium/content/child/background_sync/background_sync_provider.h
new file mode 100644
index 00000000000..25d6f28ddb2
--- /dev/null
+++ b/chromium/content/child/background_sync/background_sync_provider.h
@@ -0,0 +1,80 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_CHILD_BACKGROUND_SYNC_BACKGROUND_SYNC_PROVIDER_H_
+#define CONTENT_CHILD_BACKGROUND_SYNC_BACKGROUND_SYNC_PROVIDER_H_
+
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "content/child/worker_task_runner.h"
+#include "content/common/background_sync_service.mojom.h"
+#include "third_party/WebKit/public/platform/modules/background_sync/WebSyncProvider.h"
+
+namespace content {
+
+class ServiceRegistry;
+
+// The BackgroundSyncProvider is called by the SyncManager and SyncRegistration
+// objects (and their Periodic counterparts) and communicates with the
+// BackgroundSyncManager object in the browser process. This class is
+// instantiated on the main thread by BlinkPlatformImpl, and its methods can be
+// called directly from the main thread.
+class BackgroundSyncProvider : public blink::WebSyncProvider {
+ public:
+ explicit BackgroundSyncProvider(ServiceRegistry* service_registry);
+
+ ~BackgroundSyncProvider() override;
+
+ // blink::WebSyncProvider implementation
+ void registerBackgroundSync(
+ const blink::WebSyncRegistration* options,
+ blink::WebServiceWorkerRegistration* service_worker_registration,
+ blink::WebSyncRegistrationCallbacks* callbacks);
+ void unregisterBackgroundSync(
+ blink::WebSyncRegistration::Periodicity periodicity,
+ int64_t id,
+ const blink::WebString& tag,
+ blink::WebServiceWorkerRegistration* service_worker_registration,
+ blink::WebSyncUnregistrationCallbacks* callbacks);
+ void getRegistration(
+ blink::WebSyncRegistration::Periodicity,
+ const blink::WebString& tag,
+ blink::WebServiceWorkerRegistration* service_worker_registration,
+ blink::WebSyncRegistrationCallbacks* callbacks);
+ void getRegistrations(
+ blink::WebSyncRegistration::Periodicity periodicity,
+ blink::WebServiceWorkerRegistration* service_worker_registration,
+ blink::WebSyncGetRegistrationsCallbacks* callbacks);
+
+ private:
+ // Callback handlers
+ void RegisterCallback(
+ scoped_ptr<blink::WebSyncRegistrationCallbacks> callbacks,
+ BackgroundSyncError error,
+ const SyncRegistrationPtr& options);
+ void UnregisterCallback(
+ scoped_ptr<blink::WebSyncUnregistrationCallbacks> callbacks,
+ BackgroundSyncError error);
+ void GetRegistrationCallback(
+ scoped_ptr<blink::WebSyncRegistrationCallbacks> callbacks,
+ BackgroundSyncError error,
+ const SyncRegistrationPtr& options);
+ void GetRegistrationsCallback(
+ scoped_ptr<blink::WebSyncGetRegistrationsCallbacks> callbacks,
+ BackgroundSyncError error,
+ const mojo::Array<SyncRegistrationPtr>& registrations);
+
+ // Helper method that returns an initialized BackgroundSyncServicePtr.
+ BackgroundSyncServicePtr& GetBackgroundSyncServicePtr();
+
+ ServiceRegistry* service_registry_;
+ BackgroundSyncServicePtr background_sync_service_;
+
+ DISALLOW_COPY_AND_ASSIGN(BackgroundSyncProvider);
+};
+
+} // namespace content
+
+#endif // CONTENT_CHILD_BACKGROUND_SYNC_BACKGROUND_SYNC_PROVIDER_H_
diff --git a/chromium/content/child/background_sync/background_sync_provider_thread_proxy.cc b/chromium/content/child/background_sync/background_sync_provider_thread_proxy.cc
new file mode 100644
index 00000000000..378c45c2cd4
--- /dev/null
+++ b/chromium/content/child/background_sync/background_sync_provider_thread_proxy.cc
@@ -0,0 +1,168 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/child/background_sync/background_sync_provider_thread_proxy.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/lazy_instance.h"
+#include "base/location.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread_local.h"
+#include "content/child/background_sync/background_sync_provider.h"
+
+using base::LazyInstance;
+using base::ThreadLocalPointer;
+
+namespace content {
+
+namespace {
+
+// CallbackThreadAdapter<S,T> is a wrapper for WebCallbacks<S,T> which
+// switches to a specific thread before calling the wrapped callback's
+// onSuccess or onError methods.
+//
+// Takes ownership of the WebCallbacks object which it wraps.
+template <typename S, typename T>
+class CallbackThreadAdapter : public blink::WebCallbacks<S, T> {
+ public:
+ CallbackThreadAdapter(scoped_ptr<blink::WebCallbacks<S, T>> callbacks,
+ int worker_thread_id)
+ : worker_thread_id_(worker_thread_id) {
+ callbacks_.reset(callbacks.release());
+ }
+
+ virtual void onSuccess(S* results) {
+ // If the worker thread has been destroyed, then this task will be
+ // silently discarded.
+ WorkerTaskRunner::Instance()->PostTask(
+ worker_thread_id_,
+ base::Bind(&blink::WebCallbacks<S, T>::onSuccess,
+ base::Owned(callbacks_.release()), results));
+ }
+
+ virtual void onError(T* error) {
+ // If the worker thread has been destroyed, then this task will be
+ // silently discarded.
+ WorkerTaskRunner::Instance()->PostTask(
+ worker_thread_id_,
+ base::Bind(&blink::WebCallbacks<S, T>::onError,
+ base::Owned(callbacks_.release()), error));
+ }
+
+ private:
+ scoped_ptr<blink::WebCallbacks<S, T>> callbacks_;
+ int worker_thread_id_;
+};
+
+LazyInstance<ThreadLocalPointer<BackgroundSyncProviderThreadProxy>>::Leaky
+ g_sync_provider_tls = LAZY_INSTANCE_INITIALIZER;
+
+} // anonymous namespace
+
+BackgroundSyncProviderThreadProxy*
+BackgroundSyncProviderThreadProxy::GetThreadInstance(
+ base::SingleThreadTaskRunner* main_thread_task_runner,
+ BackgroundSyncProvider* sync_provider) {
+ if (g_sync_provider_tls.Pointer()->Get())
+ return g_sync_provider_tls.Pointer()->Get();
+
+ BackgroundSyncProviderThreadProxy* instance =
+ new BackgroundSyncProviderThreadProxy(main_thread_task_runner,
+ sync_provider);
+ DCHECK(WorkerTaskRunner::Instance()->CurrentWorkerId());
+ WorkerTaskRunner::Instance()->AddStopObserver(instance);
+ return instance;
+}
+
+void BackgroundSyncProviderThreadProxy::registerBackgroundSync(
+ const blink::WebSyncRegistration* options,
+ blink::WebServiceWorkerRegistration* service_worker_registration,
+ blink::WebSyncRegistrationCallbacks* callbacks) {
+ DCHECK(options);
+ DCHECK(service_worker_registration);
+ DCHECK(callbacks);
+ main_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&BackgroundSyncProvider::registerBackgroundSync,
+ base::Unretained(sync_provider_), options,
+ service_worker_registration,
+ new CallbackThreadAdapter<blink::WebSyncRegistration,
+ blink::WebSyncError>(
+ make_scoped_ptr(callbacks),
+ WorkerTaskRunner::Instance()->CurrentWorkerId())));
+}
+
+void BackgroundSyncProviderThreadProxy::unregisterBackgroundSync(
+ blink::WebSyncRegistration::Periodicity periodicity,
+ int64_t id,
+ const blink::WebString& tag,
+ blink::WebServiceWorkerRegistration* service_worker_registration,
+ blink::WebSyncUnregistrationCallbacks* callbacks) {
+ DCHECK(service_worker_registration);
+ DCHECK(callbacks);
+ main_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&BackgroundSyncProvider::unregisterBackgroundSync,
+ base::Unretained(sync_provider_), periodicity, id, tag,
+ service_worker_registration,
+ new CallbackThreadAdapter<bool, blink::WebSyncError>(
+ make_scoped_ptr(callbacks),
+ WorkerTaskRunner::Instance()->CurrentWorkerId())));
+}
+
+void BackgroundSyncProviderThreadProxy::getRegistration(
+ blink::WebSyncRegistration::Periodicity periodicity,
+ const blink::WebString& tag,
+ blink::WebServiceWorkerRegistration* service_worker_registration,
+ blink::WebSyncRegistrationCallbacks* callbacks) {
+ DCHECK(service_worker_registration);
+ DCHECK(callbacks);
+ main_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&BackgroundSyncProvider::getRegistration,
+ base::Unretained(sync_provider_), periodicity, tag,
+ service_worker_registration,
+ new CallbackThreadAdapter<blink::WebSyncRegistration,
+ blink::WebSyncError>(
+ make_scoped_ptr(callbacks),
+ WorkerTaskRunner::Instance()->CurrentWorkerId())));
+}
+
+void BackgroundSyncProviderThreadProxy::getRegistrations(
+ blink::WebSyncRegistration::Periodicity periodicity,
+ blink::WebServiceWorkerRegistration* service_worker_registration,
+ blink::WebSyncGetRegistrationsCallbacks* callbacks) {
+ DCHECK(service_worker_registration);
+ DCHECK(callbacks);
+ main_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&BackgroundSyncProvider::getRegistrations,
+ base::Unretained(sync_provider_), periodicity,
+ service_worker_registration,
+ new CallbackThreadAdapter<
+ blink::WebVector<blink::WebSyncRegistration*>,
+ blink::WebSyncError>(
+ make_scoped_ptr(callbacks),
+ WorkerTaskRunner::Instance()->CurrentWorkerId())));
+}
+
+void BackgroundSyncProviderThreadProxy::OnWorkerRunLoopStopped() {
+ delete this;
+}
+
+BackgroundSyncProviderThreadProxy::BackgroundSyncProviderThreadProxy(
+ base::SingleThreadTaskRunner* main_thread_task_runner,
+ BackgroundSyncProvider* sync_provider)
+ : main_thread_task_runner_(main_thread_task_runner),
+ sync_provider_(sync_provider) {
+ g_sync_provider_tls.Pointer()->Set(this);
+}
+
+BackgroundSyncProviderThreadProxy::~BackgroundSyncProviderThreadProxy() {
+ g_sync_provider_tls.Pointer()->Set(nullptr);
+}
+
+} // namespace content
diff --git a/chromium/content/child/background_sync/background_sync_provider_thread_proxy.h b/chromium/content/child/background_sync/background_sync_provider_thread_proxy.h
new file mode 100644
index 00000000000..f19190437cb
--- /dev/null
+++ b/chromium/content/child/background_sync/background_sync_provider_thread_proxy.h
@@ -0,0 +1,77 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_CHILD_BACKGROUND_SYNC_BACKGROUND_SYNC_PROVIDER_THREAD_PROXY_H_
+#define CONTENT_CHILD_BACKGROUND_SYNC_BACKGROUND_SYNC_PROVIDER_THREAD_PROXY_H_
+
+#include "base/macros.h"
+#include "content/child/worker_task_runner.h"
+#include "third_party/WebKit/public/platform/modules/background_sync/WebSyncProvider.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+}
+
+namespace content {
+
+class BackgroundSyncProvider;
+
+// BackgroundSyncProviderThreadProxy is a proxy to the BackgroundSyncProvider
+// for callers running on a different thread than the main thread. There is one
+// instance per worker thread.
+//
+// This class handles all of the thread switching, jumping to the main thread to
+// call the WebSyncProvider methods, and wrapping the callbacks passed in with
+// code to switch back to the original calling thread.
+class BackgroundSyncProviderThreadProxy : public blink::WebSyncProvider,
+ public WorkerTaskRunner::Observer {
+ public:
+ static BackgroundSyncProviderThreadProxy* GetThreadInstance(
+ base::SingleThreadTaskRunner* main_thread_task_runner,
+ BackgroundSyncProvider* permissions_dispatcher);
+
+ // blink::WebSyncProvider implementation
+ void registerBackgroundSync(
+ const blink::WebSyncRegistration* options,
+ blink::WebServiceWorkerRegistration* service_worker_registration,
+ blink::WebSyncRegistrationCallbacks* callbacks);
+ void unregisterBackgroundSync(
+ blink::WebSyncRegistration::Periodicity periodicity,
+ int64_t id,
+ const blink::WebString& tag,
+ blink::WebServiceWorkerRegistration* service_worker_registration,
+ blink::WebSyncUnregistrationCallbacks* callbacks);
+ void getRegistration(
+ blink::WebSyncRegistration::Periodicity,
+ const blink::WebString& tag,
+ blink::WebServiceWorkerRegistration* service_worker_registration,
+ blink::WebSyncRegistrationCallbacks* callbacks);
+ void getRegistrations(
+ blink::WebSyncRegistration::Periodicity periodicity,
+ blink::WebServiceWorkerRegistration* service_worker_registration,
+ blink::WebSyncGetRegistrationsCallbacks* callbacks);
+
+ // WorkerTaskRunner::Observer implementation.
+ void OnWorkerRunLoopStopped() override;
+
+ private:
+ BackgroundSyncProviderThreadProxy(
+ base::SingleThreadTaskRunner* main_thread_task_runner,
+ BackgroundSyncProvider* sync_provider);
+
+ virtual ~BackgroundSyncProviderThreadProxy();
+
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
+
+ // This belongs to the renderer main thread, (created by BlinkPlatformImpl)
+ // and so should outlive the BackgroundSyncProviderThreadProxy, which is
+ // created for a worker thread.
+ BackgroundSyncProvider* sync_provider_;
+
+ DISALLOW_COPY_AND_ASSIGN(BackgroundSyncProviderThreadProxy);
+};
+
+} // namespace content
+
+#endif // CONTENT_CHILD_BACKGROUND_SYNC_BACKGROUND_SYNC_PROVIDER_THREAD_PROXY_H_
diff --git a/chromium/content/child/background_sync/background_sync_type_converters.cc b/chromium/content/child/background_sync/background_sync_type_converters.cc
new file mode 100644
index 00000000000..72eddb73d5f
--- /dev/null
+++ b/chromium/content/child/background_sync/background_sync_type_converters.cc
@@ -0,0 +1,129 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/child/background_sync/background_sync_type_converters.h"
+
+#include "base/logging.h"
+
+namespace mojo {
+
+#define COMPILE_ASSERT_MATCHING_ENUM(mojo_name, blink_name) \
+ COMPILE_ASSERT(static_cast<int>(content::mojo_name) == \
+ static_cast<int>(blink::WebSyncRegistration::blink_name), \
+ mismatching_enums)
+
+COMPILE_ASSERT_MATCHING_ENUM(BACKGROUND_SYNC_PERIODICITY_PERIODIC,
+ PeriodicityPeriodic);
+COMPILE_ASSERT_MATCHING_ENUM(BACKGROUND_SYNC_PERIODICITY_ONE_SHOT,
+ PeriodicityOneShot);
+COMPILE_ASSERT_MATCHING_ENUM(BACKGROUND_SYNC_PERIODICITY_MAX,
+ PeriodicityOneShot);
+COMPILE_ASSERT_MATCHING_ENUM(BACKGROUND_SYNC_PERIODICITY_MAX,
+ PeriodicityLast);
+COMPILE_ASSERT_MATCHING_ENUM(BACKGROUND_SYNC_NETWORK_STATE_ANY,
+ NetworkStateAny);
+COMPILE_ASSERT_MATCHING_ENUM(BACKGROUND_SYNC_NETWORK_STATE_AVOID_CELLULAR,
+ NetworkStateAvoidCellular);
+COMPILE_ASSERT_MATCHING_ENUM(BACKGROUND_SYNC_NETWORK_STATE_ONLINE,
+ NetworkStateOnline);
+COMPILE_ASSERT_MATCHING_ENUM(BACKGROUND_SYNC_NETWORK_STATE_MAX,
+ NetworkStateOnline);
+COMPILE_ASSERT_MATCHING_ENUM(BACKGROUND_SYNC_NETWORK_STATE_MAX,
+ NetworkStateLast);
+COMPILE_ASSERT_MATCHING_ENUM(BACKGROUND_SYNC_POWER_STATE_AUTO,
+ PowerStateAuto);
+COMPILE_ASSERT_MATCHING_ENUM(BACKGROUND_SYNC_POWER_STATE_AVOID_DRAINING,
+ PowerStateAvoidDraining);
+COMPILE_ASSERT_MATCHING_ENUM(BACKGROUND_SYNC_POWER_STATE_MAX,
+ PowerStateAvoidDraining);
+COMPILE_ASSERT_MATCHING_ENUM(BACKGROUND_SYNC_POWER_STATE_MAX,
+ PowerStateLast);
+
+// static
+blink::WebSyncRegistration::Periodicity
+ TypeConverter<blink::WebSyncRegistration::Periodicity,
+ content::BackgroundSyncPeriodicity>::Convert(
+ content::BackgroundSyncPeriodicity input) {
+ return static_cast<blink::WebSyncRegistration::Periodicity>(input);
+}
+
+// static
+content::BackgroundSyncPeriodicity
+ TypeConverter<content::BackgroundSyncPeriodicity,
+ blink::WebSyncRegistration::Periodicity>::Convert(
+ blink::WebSyncRegistration::Periodicity input) {
+ return static_cast<content::BackgroundSyncPeriodicity>(input);
+}
+
+// static
+blink::WebSyncRegistration::NetworkState
+ TypeConverter<blink::WebSyncRegistration::NetworkState,
+ content::BackgroundSyncNetworkState>::Convert(
+ content::BackgroundSyncNetworkState input) {
+ return static_cast<blink::WebSyncRegistration::NetworkState>(input);
+}
+
+// static
+content::BackgroundSyncNetworkState
+ TypeConverter<content::BackgroundSyncNetworkState,
+ blink::WebSyncRegistration::NetworkState>::Convert(
+ blink::WebSyncRegistration::NetworkState input) {
+ return static_cast<content::BackgroundSyncNetworkState>(input);
+}
+
+// static
+blink::WebSyncRegistration::PowerState
+ TypeConverter<blink::WebSyncRegistration::PowerState,
+ content::BackgroundSyncPowerState>::Convert(
+ content::BackgroundSyncPowerState input) {
+ return static_cast<blink::WebSyncRegistration::PowerState>(input);
+}
+
+// static
+content::BackgroundSyncPowerState
+ TypeConverter<content::BackgroundSyncPowerState,
+ blink::WebSyncRegistration::PowerState>::Convert(
+ blink::WebSyncRegistration::PowerState input) {
+ return static_cast<content::BackgroundSyncPowerState>(input);
+}
+
+// static
+scoped_ptr<blink::WebSyncRegistration> TypeConverter<
+ scoped_ptr<blink::WebSyncRegistration>,
+ content::SyncRegistrationPtr>::Convert(
+ const content::SyncRegistrationPtr& input) {
+ scoped_ptr<blink::WebSyncRegistration> result(
+ new blink::WebSyncRegistration());
+ result->id = input->id;
+ result->periodicity =
+ ConvertTo<blink::WebSyncRegistration::Periodicity>(input->periodicity);
+ result->tag = blink::WebString::fromUTF8(input->tag);
+ result->minPeriodMs = input->min_period_ms;
+ result->networkState =
+ ConvertTo<blink::WebSyncRegistration::NetworkState>(input->network_state);
+ result->powerState =
+ ConvertTo<blink::WebSyncRegistration::PowerState>(input->power_state);
+ return result;
+}
+
+// static
+content::SyncRegistrationPtr TypeConverter<
+ content::SyncRegistrationPtr,
+ blink::WebSyncRegistration>::Convert(
+ const blink::WebSyncRegistration& input) {
+ content::SyncRegistrationPtr result(
+ content::SyncRegistration::New());
+ result->id = input.id;
+ result->periodicity =
+ ConvertTo<content::BackgroundSyncPeriodicity>(input.periodicity);
+ result->tag = input.tag.utf8();
+ result->min_period_ms = input.minPeriodMs;
+ result->network_state =
+ ConvertTo<content::BackgroundSyncNetworkState>(input.networkState);
+ result->power_state =
+ ConvertTo<content::BackgroundSyncPowerState>(input.powerState);
+ return result.Pass();
+}
+
+} // namespace mojo
diff --git a/chromium/content/child/background_sync/background_sync_type_converters.h b/chromium/content/child/background_sync/background_sync_type_converters.h
new file mode 100644
index 00000000000..ea1c9a915d9
--- /dev/null
+++ b/chromium/content/child/background_sync/background_sync_type_converters.h
@@ -0,0 +1,87 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_CHILD_BACKGROUND_SYNC_BACKGROUND_SYNC_TYPE_CONVERTERS_H_
+#define CONTENT_CHILD_BACKGROUND_SYNC_BACKGROUND_SYNC_TYPE_CONVERTERS_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "content/common/background_sync_service.mojom.h"
+#include "content/common/content_export.h"
+#include "third_party/WebKit/public/platform/modules/background_sync/WebSyncError.h"
+#include "third_party/WebKit/public/platform/modules/background_sync/WebSyncRegistration.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/type_converter.h"
+
+namespace mojo {
+
+// blink::WebSyngRegistration::Periodicity <=>
+// content::BackgroundSyncPeriodicity
+
+template <>
+struct CONTENT_EXPORT TypeConverter<blink::WebSyncRegistration::Periodicity,
+ content::BackgroundSyncPeriodicity> {
+ static blink::WebSyncRegistration::Periodicity Convert(
+ content::BackgroundSyncPeriodicity input);
+};
+
+template <>
+struct CONTENT_EXPORT TypeConverter<content::BackgroundSyncPeriodicity,
+ blink::WebSyncRegistration::Periodicity> {
+ static content::BackgroundSyncPeriodicity Convert(
+ blink::WebSyncRegistration::Periodicity input);
+};
+
+// blink::WebSyncRegistration::NetworkState <=>
+// content::BackgroundSyncNetworkState
+
+template <>
+struct CONTENT_EXPORT TypeConverter<blink::WebSyncRegistration::NetworkState,
+ content::BackgroundSyncNetworkState> {
+ static blink::WebSyncRegistration::NetworkState Convert(
+ content::BackgroundSyncNetworkState input);
+};
+
+template <>
+struct CONTENT_EXPORT TypeConverter<content::BackgroundSyncNetworkState,
+ blink::WebSyncRegistration::NetworkState> {
+ static content::BackgroundSyncNetworkState Convert(
+ blink::WebSyncRegistration::NetworkState input);
+};
+
+// blink::WebSyncRegistration::PowerState <=>
+// content::BackgroundSyncPowerState
+
+template <>
+struct CONTENT_EXPORT TypeConverter<blink::WebSyncRegistration::PowerState,
+ content::BackgroundSyncPowerState> {
+ static blink::WebSyncRegistration::PowerState Convert(
+ content::BackgroundSyncPowerState input);
+};
+
+template <>
+struct CONTENT_EXPORT TypeConverter<content::BackgroundSyncPowerState,
+ blink::WebSyncRegistration::PowerState> {
+ static content::BackgroundSyncPowerState Convert(
+ blink::WebSyncRegistration::PowerState input);
+};
+
+// blink::WebSyncRegistration <=>
+// content::SyncRegistration
+
+template <>
+struct CONTENT_EXPORT TypeConverter<scoped_ptr<blink::WebSyncRegistration>,
+ content::SyncRegistrationPtr> {
+ static scoped_ptr<blink::WebSyncRegistration> Convert(
+ const content::SyncRegistrationPtr& input);
+};
+
+template <>
+struct CONTENT_EXPORT TypeConverter<content::SyncRegistrationPtr,
+ blink::WebSyncRegistration> {
+ static content::SyncRegistrationPtr Convert(
+ const blink::WebSyncRegistration& input);
+};
+
+} // namespace mojo
+
+#endif // CONTENT_CHILD_BACKGROUND_SYNC_BACKGROUND_SYNC_TYPE_CONVERTERS_H_
diff --git a/chromium/content/child/background_sync/background_sync_type_converters_unittest.cc b/chromium/content/child/background_sync/background_sync_type_converters_unittest.cc
new file mode 100644
index 00000000000..189dc117cfc
--- /dev/null
+++ b/chromium/content/child/background_sync/background_sync_type_converters_unittest.cc
@@ -0,0 +1,181 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/child/background_sync/background_sync_type_converters.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace {
+
+TEST(BackgroundSyncTypeConverterTest, TestBlinkToMojoPeriodicityConversions) {
+ ASSERT_EQ(blink::WebSyncRegistration::PeriodicityPeriodic,
+ ConvertTo<blink::WebSyncRegistration::Periodicity>(
+ content::BACKGROUND_SYNC_PERIODICITY_PERIODIC));
+ ASSERT_EQ(blink::WebSyncRegistration::PeriodicityOneShot,
+ ConvertTo<blink::WebSyncRegistration::Periodicity>(
+ content::BACKGROUND_SYNC_PERIODICITY_ONE_SHOT));
+}
+
+TEST(BackgroundSyncTypeConverterTest, TestMojoToBlinkPeriodicityConversions) {
+ ASSERT_EQ(content::BACKGROUND_SYNC_PERIODICITY_PERIODIC,
+ ConvertTo<content::BackgroundSyncPeriodicity>(
+ blink::WebSyncRegistration::PeriodicityPeriodic));
+ ASSERT_EQ(content::BACKGROUND_SYNC_PERIODICITY_ONE_SHOT,
+ ConvertTo<content::BackgroundSyncPeriodicity>(
+ blink::WebSyncRegistration::PeriodicityOneShot));
+}
+
+TEST(BackgroundSyncTypeConverterTest, TestBlinkToMojoNetworkStateConversions) {
+ ASSERT_EQ(blink::WebSyncRegistration::NetworkStateAny,
+ ConvertTo<blink::WebSyncRegistration::NetworkState>(
+ content::BACKGROUND_SYNC_NETWORK_STATE_ANY));
+ ASSERT_EQ(blink::WebSyncRegistration::NetworkStateAvoidCellular,
+ ConvertTo<blink::WebSyncRegistration::NetworkState>(
+ content::BACKGROUND_SYNC_NETWORK_STATE_AVOID_CELLULAR));
+ ASSERT_EQ(blink::WebSyncRegistration::NetworkStateOnline,
+ ConvertTo<blink::WebSyncRegistration::NetworkState>(
+ content::BACKGROUND_SYNC_NETWORK_STATE_ONLINE));
+}
+
+TEST(BackgroundSyncTypeConverterTest, TestMojoToBlinkNetworkStateConversions) {
+ ASSERT_EQ(content::BACKGROUND_SYNC_NETWORK_STATE_ANY,
+ ConvertTo<content::BackgroundSyncNetworkState>(
+ blink::WebSyncRegistration::NetworkStateAny));
+ ASSERT_EQ(content::BACKGROUND_SYNC_NETWORK_STATE_AVOID_CELLULAR,
+ ConvertTo<content::BackgroundSyncNetworkState>(
+ blink::WebSyncRegistration::NetworkStateAvoidCellular));
+ ASSERT_EQ(content::BACKGROUND_SYNC_NETWORK_STATE_ONLINE,
+ ConvertTo<content::BackgroundSyncNetworkState>(
+ blink::WebSyncRegistration::NetworkStateOnline));
+}
+
+TEST(BackgroundSyncTypeConverterTest, TestBlinkToMojoPowerStateConversions) {
+ ASSERT_EQ(blink::WebSyncRegistration::PowerStateAuto,
+ ConvertTo<blink::WebSyncRegistration::PowerState>(
+ content::BACKGROUND_SYNC_POWER_STATE_AUTO));
+ ASSERT_EQ(blink::WebSyncRegistration::PowerStateAvoidDraining,
+ ConvertTo<blink::WebSyncRegistration::PowerState>(
+ content::BACKGROUND_SYNC_POWER_STATE_AVOID_DRAINING));
+}
+
+TEST(BackgroundSyncTypeConverterTest, TestMojoToBlinkPowerStateConversions) {
+ ASSERT_EQ(content::BACKGROUND_SYNC_POWER_STATE_AUTO,
+ ConvertTo<content::BackgroundSyncPowerState>(
+ blink::WebSyncRegistration::PowerStateAuto));
+ ASSERT_EQ(content::BACKGROUND_SYNC_POWER_STATE_AVOID_DRAINING,
+ ConvertTo<content::BackgroundSyncPowerState>(
+ blink::WebSyncRegistration::PowerStateAvoidDraining));
+}
+
+TEST(BackgroundSyncTypeConverterTest, TestDefaultBlinkToMojoConversion) {
+ blink::WebSyncRegistration in;
+ content::SyncRegistrationPtr out =
+ ConvertTo<content::SyncRegistrationPtr>(in);
+
+ ASSERT_EQ(blink::WebSyncRegistration::UNREGISTERED_SYNC_ID, out->id);
+ ASSERT_EQ(content::BACKGROUND_SYNC_PERIODICITY_ONE_SHOT, out->periodicity);
+ ASSERT_EQ("", out->tag);
+ ASSERT_EQ(0UL, out->min_period_ms);
+ ASSERT_EQ(content::BACKGROUND_SYNC_NETWORK_STATE_ONLINE, out->network_state);
+ ASSERT_EQ(content::BACKGROUND_SYNC_POWER_STATE_AUTO, out->power_state);
+}
+
+TEST(BackgroundSyncTypeConverterTest, TestFullPeriodicBlinkToMojoConversion) {
+ blink::WebSyncRegistration in(
+ 7, blink::WebSyncRegistration::PeriodicityPeriodic, "BlinkToMojo",
+ 12340000, blink::WebSyncRegistration::NetworkStateAvoidCellular,
+ blink::WebSyncRegistration::PowerStateAvoidDraining);
+ content::SyncRegistrationPtr out =
+ ConvertTo<content::SyncRegistrationPtr>(in);
+
+ ASSERT_EQ(7, out->id);
+ ASSERT_EQ(content::BACKGROUND_SYNC_PERIODICITY_PERIODIC, out->periodicity);
+ ASSERT_EQ("BlinkToMojo", out->tag);
+ ASSERT_EQ(12340000UL, out->min_period_ms);
+ ASSERT_EQ(content::BACKGROUND_SYNC_NETWORK_STATE_AVOID_CELLULAR,
+ out->network_state);
+ ASSERT_EQ(content::BACKGROUND_SYNC_POWER_STATE_AVOID_DRAINING,
+ out->power_state);
+}
+
+TEST(BackgroundSyncTypeConverterTest, TestFullOneShotBlinkToMojoConversion) {
+ blink::WebSyncRegistration in(
+ 7, blink::WebSyncRegistration::PeriodicityOneShot, "BlinkToMojo",
+ 12340000, blink::WebSyncRegistration::NetworkStateAvoidCellular,
+ blink::WebSyncRegistration::PowerStateAvoidDraining);
+ content::SyncRegistrationPtr out =
+ ConvertTo<content::SyncRegistrationPtr>(in);
+
+ ASSERT_EQ(7, out->id);
+ ASSERT_EQ(content::BACKGROUND_SYNC_PERIODICITY_ONE_SHOT, out->periodicity);
+ ASSERT_EQ("BlinkToMojo", out->tag);
+ ASSERT_EQ(12340000UL, out->min_period_ms);
+ ASSERT_EQ(content::BACKGROUND_SYNC_NETWORK_STATE_AVOID_CELLULAR,
+ out->network_state);
+ ASSERT_EQ(content::BACKGROUND_SYNC_POWER_STATE_AVOID_DRAINING,
+ out->power_state);
+}
+
+TEST(BackgroundSyncTypeConverterTest, TestDefaultMojoToBlinkConversion) {
+ content::SyncRegistrationPtr in(
+ content::SyncRegistration::New());
+ scoped_ptr<blink::WebSyncRegistration> out =
+ ConvertTo<scoped_ptr<blink::WebSyncRegistration>>(in);
+
+ ASSERT_EQ(blink::WebSyncRegistration::UNREGISTERED_SYNC_ID, out->id);
+ ASSERT_EQ(blink::WebSyncRegistration::PeriodicityOneShot, out->periodicity);
+ ASSERT_EQ("",out->tag);
+ ASSERT_EQ(0UL, out->minPeriodMs);
+ ASSERT_EQ(blink::WebSyncRegistration::NetworkStateOnline, out->networkState);
+ ASSERT_EQ(blink::WebSyncRegistration::PowerStateAuto, out->powerState);
+}
+
+TEST(BackgroundSyncTypeConverterTest, TestFullPeriodicMojoToBlinkConversion) {
+ content::SyncRegistrationPtr in(
+ content::SyncRegistration::New());
+ in->id = 41;
+ in->periodicity = content::BACKGROUND_SYNC_PERIODICITY_PERIODIC;
+ in->tag = mojo::String("MojoToBlink");
+ in->min_period_ms = 43210000;
+ in->network_state = content::BACKGROUND_SYNC_NETWORK_STATE_AVOID_CELLULAR;
+ in->power_state = content::BACKGROUND_SYNC_POWER_STATE_AVOID_DRAINING;
+ scoped_ptr<blink::WebSyncRegistration> out =
+ ConvertTo<scoped_ptr<blink::WebSyncRegistration>>(in);
+
+ ASSERT_EQ(41, out->id);
+ ASSERT_EQ(blink::WebSyncRegistration::PeriodicityPeriodic, out->periodicity);
+ ASSERT_EQ("MojoToBlink", out->tag.utf8());
+ ASSERT_EQ(43210000UL, out->minPeriodMs);
+ ASSERT_EQ(blink::WebSyncRegistration::NetworkStateAvoidCellular,
+ out->networkState);
+ ASSERT_EQ(blink::WebSyncRegistration::PowerStateAvoidDraining,
+ out->powerState);
+}
+
+TEST(BackgroundSyncTypeConverterTest, TestFullOneShotMojoToBlinkConversion) {
+ content::SyncRegistrationPtr in(
+ content::SyncRegistration::New());
+ in->id = 41;
+ in->periodicity = content::BACKGROUND_SYNC_PERIODICITY_ONE_SHOT;
+ in->tag = mojo::String("MojoToBlink");
+ in->min_period_ms = 43210000;
+ in->network_state = content::BACKGROUND_SYNC_NETWORK_STATE_AVOID_CELLULAR;
+ in->power_state = content::BACKGROUND_SYNC_POWER_STATE_AVOID_DRAINING;
+ scoped_ptr<blink::WebSyncRegistration> out =
+ ConvertTo<scoped_ptr<blink::WebSyncRegistration>>(in);
+
+ ASSERT_EQ(41, out->id);
+ ASSERT_EQ(blink::WebSyncRegistration::PeriodicityOneShot, out->periodicity);
+ ASSERT_EQ("MojoToBlink", out->tag.utf8());
+ ASSERT_EQ(43210000UL, out->minPeriodMs);
+ ASSERT_EQ(blink::WebSyncRegistration::NetworkStateAvoidCellular,
+ out->networkState);
+ ASSERT_EQ(blink::WebSyncRegistration::PowerStateAvoidDraining,
+ out->powerState);
+}
+
+} // anonymous namespace
+} // namespace mojo
+
diff --git a/chromium/content/child/blink_platform_impl.cc b/chromium/content/child/blink_platform_impl.cc
index 144a98314ee..73b4825e754 100644
--- a/chromium/content/child/blink_platform_impl.cc
+++ b/chromium/content/child/blink_platform_impl.cc
@@ -13,10 +13,8 @@
#include "base/files/file_path.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h"
-#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram.h"
#include "base/metrics/sparse_histogram.h"
-#include "base/metrics/stats_counters.h"
#include "base/process/process_metrics.h"
#include "base/rand_util.h"
#include "base/strings/string_number_conversions.h"
@@ -25,40 +23,51 @@
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
#include "base/sys_info.h"
+#include "base/thread_task_runner_handle.h"
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
+#include "base/trace_event/memory_dump_manager.h"
+#include "blink/public/resources/grit/blink_image_resources.h"
#include "blink/public/resources/grit/blink_resources.h"
+#include "components/mime_util/mime_util.h"
+#include "components/scheduler/child/webthread_impl_for_worker_scheduler.h"
#include "content/app/resources/grit/content_resources.h"
#include "content/app/strings/grit/content_strings.h"
-#include "content/child/child_thread.h"
+#include "content/child/background_sync/background_sync_provider.h"
+#include "content/child/background_sync/background_sync_provider_thread_proxy.h"
+#include "content/child/bluetooth/web_bluetooth_impl.h"
+#include "content/child/child_thread_impl.h"
#include "content/child/content_child_helpers.h"
#include "content/child/geofencing/web_geofencing_provider_impl.h"
+#include "content/child/navigator_connect/navigator_connect_provider.h"
#include "content/child/notifications/notification_dispatcher.h"
#include "content/child/notifications/notification_manager.h"
+#include "content/child/permissions/permission_dispatcher.h"
+#include "content/child/permissions/permission_dispatcher_thread_proxy.h"
+#include "content/child/push_messaging/push_dispatcher.h"
+#include "content/child/push_messaging/push_provider.h"
#include "content/child/thread_safe_sender.h"
#include "content/child/web_discardable_memory_impl.h"
-#include "content/child/web_gesture_curve_impl.h"
+#include "content/child/web_memory_dump_provider_adapter.h"
#include "content/child/web_url_loader_impl.h"
+#include "content/child/web_url_request_util.h"
#include "content/child/websocket_bridge.h"
-#include "content/child/webthread_impl.h"
#include "content/child/worker_task_runner.h"
#include "content/public/common/content_client.h"
#include "net/base/data_url.h"
-#include "net/base/mime_util.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
#include "third_party/WebKit/public/platform/WebConvertableToTraceFormat.h"
#include "third_party/WebKit/public/platform/WebData.h"
#include "third_party/WebKit/public/platform/WebFloatPoint.h"
+#include "third_party/WebKit/public/platform/WebMemoryDumpProvider.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/platform/WebURL.h"
#include "third_party/WebKit/public/platform/WebWaitableEvent.h"
#include "third_party/WebKit/public/web/WebSecurityOrigin.h"
#include "ui/base/layout.h"
-
-#if !defined(NO_TCMALLOC) && defined(USE_TCMALLOC) && !defined(OS_WIN)
-#include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h"
-#endif
+#include "ui/events/gestures/blink/web_gesture_curve_impl.h"
+#include "ui/events/keycodes/dom/keycode_converter.h"
using blink::WebData;
using blink::WebFallbackThemeEngine;
@@ -139,11 +148,14 @@ class MemoryUsageCache {
};
class ConvertableToTraceFormatWrapper
- : public base::debug::ConvertableToTraceFormat {
+ : public base::trace_event::ConvertableToTraceFormat {
public:
+ // We move a reference pointer from |convertable| to |convertable_|,
+ // rather than copying, for thread safety. https://crbug.com/478149
explicit ConvertableToTraceFormatWrapper(
- const blink::WebConvertableToTraceFormat& convertable)
- : convertable_(convertable) {}
+ blink::WebConvertableToTraceFormat& convertable) {
+ convertable_.moveFrom(convertable);
+ }
void AppendAsTraceFormat(std::string* out) const override {
*out += convertable_.asTraceFormat().utf8();
}
@@ -154,13 +166,6 @@ class ConvertableToTraceFormatWrapper
blink::WebConvertableToTraceFormat convertable_;
};
-bool isHostnameReservedIPAddress(const std::string& host) {
- net::IPAddressNumber address;
- if (!net::ParseURLHostnameToNumber(host, &address))
- return false;
- return net::IsIPAddressReserved(address);
-}
-
} // namespace
static int ToMessageID(WebLocalizedString::Name name) {
@@ -243,8 +248,10 @@ static int ToMessageID(WebLocalizedString::Name name) {
return IDS_AX_MEDIA_PLAY_BUTTON_HELP;
case WebLocalizedString::AXMediaPauseButtonHelp:
return IDS_AX_MEDIA_PAUSE_BUTTON_HELP;
- case WebLocalizedString::AXMediaSliderHelp:
- return IDS_AX_MEDIA_SLIDER_HELP;
+ case WebLocalizedString::AXMediaAudioSliderHelp:
+ return IDS_AX_MEDIA_AUDIO_SLIDER_HELP;
+ case WebLocalizedString::AXMediaVideoSliderHelp:
+ return IDS_AX_MEDIA_VIDEO_SLIDER_HELP;
case WebLocalizedString::AXMediaSliderThumbHelp:
return IDS_AX_MEDIA_SLIDER_THUMB_HELP;
case WebLocalizedString::AXMediaCurrentTimeDisplayHelp:
@@ -418,31 +425,62 @@ static int ToMessageID(WebLocalizedString::Name name) {
}
BlinkPlatformImpl::BlinkPlatformImpl()
- : main_loop_(base::MessageLoop::current()),
+ : main_thread_task_runner_(base::MessageLoopProxy::current()),
+ shared_timer_func_(NULL),
+ shared_timer_fire_time_(0.0),
+ shared_timer_fire_time_was_set_while_suspended_(false),
+ shared_timer_suspended_(0) {
+ InternalInit();
+}
+
+BlinkPlatformImpl::BlinkPlatformImpl(
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner)
+ : main_thread_task_runner_(main_thread_task_runner),
shared_timer_func_(NULL),
shared_timer_fire_time_(0.0),
shared_timer_fire_time_was_set_while_suspended_(false),
- shared_timer_suspended_(0),
- current_thread_slot_(&DestroyCurrentThread) {
+ shared_timer_suspended_(0) {
+ // TODO(alexclarke): Use c++11 delegated constructors when allowed.
+ InternalInit();
+}
+
+void BlinkPlatformImpl::InternalInit() {
// ChildThread may not exist in some tests.
- if (ChildThread::current()) {
+ if (ChildThreadImpl::current()) {
geofencing_provider_.reset(new WebGeofencingProviderImpl(
- ChildThread::current()->thread_safe_sender()));
- thread_safe_sender_ = ChildThread::current()->thread_safe_sender();
+ ChildThreadImpl::current()->thread_safe_sender()));
+ bluetooth_.reset(
+ new WebBluetoothImpl(ChildThreadImpl::current()->thread_safe_sender()));
+ thread_safe_sender_ = ChildThreadImpl::current()->thread_safe_sender();
notification_dispatcher_ =
- ChildThread::current()->notification_dispatcher();
+ ChildThreadImpl::current()->notification_dispatcher();
+ push_dispatcher_ = ChildThreadImpl::current()->push_dispatcher();
+ permission_client_.reset(new PermissionDispatcher(
+ ChildThreadImpl::current()->service_registry()));
+ sync_provider_.reset(new BackgroundSyncProvider(
+ ChildThreadImpl::current()->service_registry()));
+ }
+
+ if (main_thread_task_runner_.get()) {
+ shared_timer_.SetTaskRunner(main_thread_task_runner_);
}
}
+void BlinkPlatformImpl::UpdateWebThreadTLS(blink::WebThread* thread) {
+ DCHECK(!current_thread_slot_.Get());
+ current_thread_slot_.Set(thread);
+}
+
BlinkPlatformImpl::~BlinkPlatformImpl() {
}
WebURLLoader* BlinkPlatformImpl::createURLLoader() {
- ChildThread* child_thread = ChildThread::current();
+ ChildThreadImpl* child_thread = ChildThreadImpl::current();
// There may be no child thread in RenderViewTests. These tests can still use
// data URLs to bypass the ResourceDispatcher.
return new WebURLLoaderImpl(
- child_thread ? child_thread->resource_dispatcher() : NULL);
+ child_thread ? child_thread->resource_dispatcher() : NULL,
+ MainTaskRunnerForCurrentThread());
}
blink::WebSocketHandle* BlinkPlatformImpl::createWebSocketHandle() {
@@ -457,8 +495,8 @@ WebData BlinkPlatformImpl::parseDataURL(const WebURL& url,
WebString& mimetype_out,
WebString& charset_out) {
std::string mime_type, char_set, data;
- if (net::DataURL::Parse(url, &mime_type, &char_set, &data)
- && net::IsSupportedMimeType(mime_type)) {
+ if (net::DataURL::Parse(url, &mime_type, &char_set, &data) &&
+ mime_util::IsSupportedMimeType(mime_type)) {
mimetype_out = WebString::fromUTF8(mime_type);
charset_out = WebString::fromUTF8(char_set);
return data;
@@ -468,36 +506,40 @@ WebData BlinkPlatformImpl::parseDataURL(const WebURL& url,
WebURLError BlinkPlatformImpl::cancelledError(
const WebURL& unreachableURL) const {
- return WebURLLoaderImpl::CreateError(unreachableURL, false, net::ERR_ABORTED);
+ return CreateWebURLError(unreachableURL, false, net::ERR_ABORTED);
}
bool BlinkPlatformImpl::isReservedIPAddress(
- const blink::WebSecurityOrigin& securityOrigin) const {
- return isHostnameReservedIPAddress(securityOrigin.host().utf8());
+ const blink::WebString& host) const {
+ net::IPAddressNumber address;
+ if (!net::ParseURLHostnameToNumber(host.utf8(), &address))
+ return false;
+ return net::IsIPAddressReserved(address);
}
-bool BlinkPlatformImpl::isReservedIPAddress(const blink::WebURL& url) const {
- return isHostnameReservedIPAddress(GURL(url).host());
+bool BlinkPlatformImpl::portAllowed(const blink::WebURL& url) const {
+ GURL gurl = GURL(url);
+ if (!gurl.has_port())
+ return true;
+ int port = gurl.IntPort();
+ if (net::IsPortAllowedByOverride(port))
+ return true;
+ if (gurl.SchemeIs("ftp"))
+ return net::IsPortAllowedByFtp(port);
+ return net::IsPortAllowedByDefault(port);
}
blink::WebThread* BlinkPlatformImpl::createThread(const char* name) {
- return new WebThreadImpl(name);
+ scheduler::WebThreadImplForWorkerScheduler* thread =
+ new scheduler::WebThreadImplForWorkerScheduler(name);
+ thread->TaskRunner()->PostTask(
+ FROM_HERE, base::Bind(&BlinkPlatformImpl::UpdateWebThreadTLS,
+ base::Unretained(this), thread));
+ return thread;
}
blink::WebThread* BlinkPlatformImpl::currentThread() {
- WebThreadImplForMessageLoop* thread =
- static_cast<WebThreadImplForMessageLoop*>(current_thread_slot_.Get());
- if (thread)
- return (thread);
-
- scoped_refptr<base::MessageLoopProxy> message_loop =
- base::MessageLoopProxy::current();
- if (!message_loop.get())
- return NULL;
-
- thread = new WebThreadImplForMessageLoop(message_loop.get());
- current_thread_slot_.Set(thread);
- return thread;
+ return static_cast<blink::WebThread*>(current_thread_slot_.Get());
}
void BlinkPlatformImpl::yieldCurrentThread() {
@@ -520,11 +562,9 @@ blink::WebWaitableEvent* BlinkPlatformImpl::waitMultipleEvents(
}
void BlinkPlatformImpl::decrementStatsCounter(const char* name) {
- base::StatsCounter(name).Decrement();
}
void BlinkPlatformImpl::incrementStatsCounter(const char* name) {
- base::StatsCounter(name).Increment();
}
void BlinkPlatformImpl::histogramCustomCounts(
@@ -560,39 +600,48 @@ const unsigned char* BlinkPlatformImpl::getTraceCategoryEnabledFlag(
return TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(category_group);
}
-long* BlinkPlatformImpl::getTraceSamplingState(
- const unsigned thread_bucket) {
+blink::Platform::TraceEventAPIAtomicWord*
+BlinkPlatformImpl::getTraceSamplingState(const unsigned thread_bucket) {
switch (thread_bucket) {
case 0:
- return reinterpret_cast<long*>(&TRACE_EVENT_API_THREAD_BUCKET(0));
+ return reinterpret_cast<blink::Platform::TraceEventAPIAtomicWord*>(
+ &TRACE_EVENT_API_THREAD_BUCKET(0));
case 1:
- return reinterpret_cast<long*>(&TRACE_EVENT_API_THREAD_BUCKET(1));
+ return reinterpret_cast<blink::Platform::TraceEventAPIAtomicWord*>(
+ &TRACE_EVENT_API_THREAD_BUCKET(1));
case 2:
- return reinterpret_cast<long*>(&TRACE_EVENT_API_THREAD_BUCKET(2));
+ return reinterpret_cast<blink::Platform::TraceEventAPIAtomicWord*>(
+ &TRACE_EVENT_API_THREAD_BUCKET(2));
default:
NOTREACHED() << "Unknown thread bucket type.";
}
return NULL;
}
-COMPILE_ASSERT(
+static_assert(
sizeof(blink::Platform::TraceEventHandle) ==
- sizeof(base::debug::TraceEventHandle),
- TraceEventHandle_types_must_be_same_size);
+ sizeof(base::trace_event::TraceEventHandle),
+ "TraceEventHandle types must be same size");
blink::Platform::TraceEventHandle BlinkPlatformImpl::addTraceEvent(
char phase,
const unsigned char* category_group_enabled,
const char* name,
unsigned long long id,
+ double timestamp,
int num_args,
const char** arg_names,
const unsigned char* arg_types,
const unsigned long long* arg_values,
unsigned char flags) {
- base::debug::TraceEventHandle handle = TRACE_EVENT_API_ADD_TRACE_EVENT(
- phase, category_group_enabled, name, id,
- num_args, arg_names, arg_types, arg_values, NULL, flags);
+ base::TimeTicks timestamp_tt = base::TimeTicks::FromInternalValue(
+ static_cast<int64>(timestamp * base::Time::kMicrosecondsPerSecond));
+ base::trace_event::TraceEventHandle handle =
+ TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
+ phase, category_group_enabled, name, id,
+ base::PlatformThread::CurrentId(),
+ timestamp_tt,
+ num_args, arg_names, arg_types, arg_values, NULL, flags);
blink::Platform::TraceEventHandle result;
memcpy(&result, &handle, sizeof(result));
return result;
@@ -603,13 +652,15 @@ blink::Platform::TraceEventHandle BlinkPlatformImpl::addTraceEvent(
const unsigned char* category_group_enabled,
const char* name,
unsigned long long id,
+ double timestamp,
int num_args,
const char** arg_names,
const unsigned char* arg_types,
const unsigned long long* arg_values,
- const blink::WebConvertableToTraceFormat* convertable_values,
+ blink::WebConvertableToTraceFormat* convertable_values,
unsigned char flags) {
- scoped_refptr<base::debug::ConvertableToTraceFormat> convertable_wrappers[2];
+ scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+ convertable_wrappers[2];
if (convertable_values) {
size_t size = std::min(static_cast<size_t>(num_args),
arraysize(convertable_wrappers));
@@ -620,11 +671,15 @@ blink::Platform::TraceEventHandle BlinkPlatformImpl::addTraceEvent(
}
}
}
- base::debug::TraceEventHandle handle =
- TRACE_EVENT_API_ADD_TRACE_EVENT(phase,
+ base::TimeTicks timestamp_tt = base::TimeTicks::FromInternalValue(
+ static_cast<int64>(timestamp * base::Time::kMicrosecondsPerSecond));
+ base::trace_event::TraceEventHandle handle =
+ TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(phase,
category_group_enabled,
name,
id,
+ base::PlatformThread::CurrentId(),
+ timestamp_tt,
num_args,
arg_names,
arg_types,
@@ -640,12 +695,36 @@ void BlinkPlatformImpl::updateTraceEventDuration(
const unsigned char* category_group_enabled,
const char* name,
TraceEventHandle handle) {
- base::debug::TraceEventHandle traceEventHandle;
+ base::trace_event::TraceEventHandle traceEventHandle;
memcpy(&traceEventHandle, &handle, sizeof(handle));
TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(
category_group_enabled, name, traceEventHandle);
}
+void BlinkPlatformImpl::registerMemoryDumpProvider(
+ blink::WebMemoryDumpProvider* wmdp) {
+ WebMemoryDumpProviderAdapter* wmdp_adapter =
+ new WebMemoryDumpProviderAdapter(wmdp);
+ bool did_insert =
+ memory_dump_providers_.add(wmdp, make_scoped_ptr(wmdp_adapter)).second;
+ if (!did_insert)
+ return;
+ wmdp_adapter->set_is_registered(true);
+ base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
+ wmdp_adapter, base::ThreadTaskRunnerHandle::Get());
+}
+
+void BlinkPlatformImpl::unregisterMemoryDumpProvider(
+ blink::WebMemoryDumpProvider* wmdp) {
+ scoped_ptr<WebMemoryDumpProviderAdapter> wmdp_adapter =
+ memory_dump_providers_.take_and_erase(wmdp);
+ if (!wmdp_adapter)
+ return;
+ base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
+ wmdp_adapter.get());
+ wmdp_adapter->set_is_registered(false);
+}
+
namespace {
WebData loadAudioSpatializationResource(const char* name) {
@@ -712,165 +791,222 @@ struct DataResource {
};
const DataResource kDataResources[] = {
- { "missingImage", IDR_BROKENIMAGE, ui::SCALE_FACTOR_100P },
- { "missingImage@2x", IDR_BROKENIMAGE, ui::SCALE_FACTOR_200P },
- { "mediaplayerPause", IDR_MEDIAPLAYER_PAUSE_BUTTON, ui::SCALE_FACTOR_100P },
- { "mediaplayerPauseHover",
- IDR_MEDIAPLAYER_PAUSE_BUTTON_HOVER, ui::SCALE_FACTOR_100P },
- { "mediaplayerPauseDown",
- IDR_MEDIAPLAYER_PAUSE_BUTTON_DOWN, ui::SCALE_FACTOR_100P },
- { "mediaplayerPlay", IDR_MEDIAPLAYER_PLAY_BUTTON, ui::SCALE_FACTOR_100P },
- { "mediaplayerPlayHover",
- IDR_MEDIAPLAYER_PLAY_BUTTON_HOVER, ui::SCALE_FACTOR_100P },
- { "mediaplayerPlayDown",
- IDR_MEDIAPLAYER_PLAY_BUTTON_DOWN, ui::SCALE_FACTOR_100P },
- { "mediaplayerPlayDisabled",
- IDR_MEDIAPLAYER_PLAY_BUTTON_DISABLED, ui::SCALE_FACTOR_100P },
- { "mediaplayerSoundLevel3",
- IDR_MEDIAPLAYER_SOUND_LEVEL3_BUTTON, ui::SCALE_FACTOR_100P },
- { "mediaplayerSoundLevel3Hover",
- IDR_MEDIAPLAYER_SOUND_LEVEL3_BUTTON_HOVER, ui::SCALE_FACTOR_100P },
- { "mediaplayerSoundLevel3Down",
- IDR_MEDIAPLAYER_SOUND_LEVEL3_BUTTON_DOWN, ui::SCALE_FACTOR_100P },
- { "mediaplayerSoundLevel2",
- IDR_MEDIAPLAYER_SOUND_LEVEL2_BUTTON, ui::SCALE_FACTOR_100P },
- { "mediaplayerSoundLevel2Hover",
- IDR_MEDIAPLAYER_SOUND_LEVEL2_BUTTON_HOVER, ui::SCALE_FACTOR_100P },
- { "mediaplayerSoundLevel2Down",
- IDR_MEDIAPLAYER_SOUND_LEVEL2_BUTTON_DOWN, ui::SCALE_FACTOR_100P },
- { "mediaplayerSoundLevel1",
- IDR_MEDIAPLAYER_SOUND_LEVEL1_BUTTON, ui::SCALE_FACTOR_100P },
- { "mediaplayerSoundLevel1Hover",
- IDR_MEDIAPLAYER_SOUND_LEVEL1_BUTTON_HOVER, ui::SCALE_FACTOR_100P },
- { "mediaplayerSoundLevel1Down",
- IDR_MEDIAPLAYER_SOUND_LEVEL1_BUTTON_DOWN, ui::SCALE_FACTOR_100P },
- { "mediaplayerSoundLevel0",
- IDR_MEDIAPLAYER_SOUND_LEVEL0_BUTTON, ui::SCALE_FACTOR_100P },
- { "mediaplayerSoundLevel0Hover",
- IDR_MEDIAPLAYER_SOUND_LEVEL0_BUTTON_HOVER, ui::SCALE_FACTOR_100P },
- { "mediaplayerSoundLevel0Down",
- IDR_MEDIAPLAYER_SOUND_LEVEL0_BUTTON_DOWN, ui::SCALE_FACTOR_100P },
- { "mediaplayerSoundDisabled",
- IDR_MEDIAPLAYER_SOUND_DISABLED, ui::SCALE_FACTOR_100P },
- { "mediaplayerSliderThumb",
- IDR_MEDIAPLAYER_SLIDER_THUMB, ui::SCALE_FACTOR_100P },
- { "mediaplayerSliderThumbHover",
- IDR_MEDIAPLAYER_SLIDER_THUMB_HOVER, ui::SCALE_FACTOR_100P },
- { "mediaplayerSliderThumbDown",
- IDR_MEDIAPLAYER_SLIDER_THUMB_DOWN, ui::SCALE_FACTOR_100P },
- { "mediaplayerVolumeSliderThumb",
- IDR_MEDIAPLAYER_VOLUME_SLIDER_THUMB, ui::SCALE_FACTOR_100P },
- { "mediaplayerVolumeSliderThumbHover",
- IDR_MEDIAPLAYER_VOLUME_SLIDER_THUMB_HOVER, ui::SCALE_FACTOR_100P },
- { "mediaplayerVolumeSliderThumbDown",
- IDR_MEDIAPLAYER_VOLUME_SLIDER_THUMB_DOWN, ui::SCALE_FACTOR_100P },
- { "mediaplayerVolumeSliderThumbDisabled",
- IDR_MEDIAPLAYER_VOLUME_SLIDER_THUMB_DISABLED, ui::SCALE_FACTOR_100P },
- { "mediaplayerClosedCaption",
- IDR_MEDIAPLAYER_CLOSEDCAPTION_BUTTON, ui::SCALE_FACTOR_100P },
- { "mediaplayerClosedCaptionHover",
- IDR_MEDIAPLAYER_CLOSEDCAPTION_BUTTON_HOVER, ui::SCALE_FACTOR_100P },
- { "mediaplayerClosedCaptionDown",
- IDR_MEDIAPLAYER_CLOSEDCAPTION_BUTTON_DOWN, ui::SCALE_FACTOR_100P },
- { "mediaplayerClosedCaptionDisabled",
- IDR_MEDIAPLAYER_CLOSEDCAPTION_BUTTON_DISABLED, ui::SCALE_FACTOR_100P },
- { "mediaplayerFullscreen",
- IDR_MEDIAPLAYER_FULLSCREEN_BUTTON, ui::SCALE_FACTOR_100P },
- { "mediaplayerFullscreenHover",
- IDR_MEDIAPLAYER_FULLSCREEN_BUTTON_HOVER, ui::SCALE_FACTOR_100P },
- { "mediaplayerFullscreenDown",
- IDR_MEDIAPLAYER_FULLSCREEN_BUTTON_DOWN, ui::SCALE_FACTOR_100P },
- { "mediaplayerCastOff",
- IDR_MEDIAPLAYER_CAST_BUTTON_OFF, ui::SCALE_FACTOR_100P },
- { "mediaplayerCastOn",
- IDR_MEDIAPLAYER_CAST_BUTTON_ON, ui::SCALE_FACTOR_100P },
- { "mediaplayerFullscreenDisabled",
- IDR_MEDIAPLAYER_FULLSCREEN_BUTTON_DISABLED, ui::SCALE_FACTOR_100P },
- { "mediaplayerOverlayCastOff",
- IDR_MEDIAPLAYER_OVERLAY_CAST_BUTTON_OFF, ui::SCALE_FACTOR_100P },
- { "mediaplayerOverlayPlay",
- IDR_MEDIAPLAYER_OVERLAY_PLAY_BUTTON, ui::SCALE_FACTOR_100P },
-#if defined(OS_MACOSX)
- { "overhangPattern", IDR_OVERHANG_PATTERN, ui::SCALE_FACTOR_100P },
- { "overhangShadow", IDR_OVERHANG_SHADOW, ui::SCALE_FACTOR_100P },
-#endif
- { "panIcon", IDR_PAN_SCROLL_ICON, ui::SCALE_FACTOR_100P },
- { "searchCancel", IDR_SEARCH_CANCEL, ui::SCALE_FACTOR_100P },
- { "searchCancelPressed", IDR_SEARCH_CANCEL_PRESSED, ui::SCALE_FACTOR_100P },
- { "searchMagnifier", IDR_SEARCH_MAGNIFIER, ui::SCALE_FACTOR_100P },
- { "searchMagnifierResults",
- IDR_SEARCH_MAGNIFIER_RESULTS, ui::SCALE_FACTOR_100P },
- { "textAreaResizeCorner", IDR_TEXTAREA_RESIZER, ui::SCALE_FACTOR_100P },
- { "textAreaResizeCorner@2x", IDR_TEXTAREA_RESIZER, ui::SCALE_FACTOR_200P },
- { "generatePassword", IDR_PASSWORD_GENERATION_ICON, ui::SCALE_FACTOR_100P },
- { "generatePasswordHover",
- IDR_PASSWORD_GENERATION_ICON_HOVER, ui::SCALE_FACTOR_100P },
- { "html.css", IDR_UASTYLE_HTML_CSS, ui::SCALE_FACTOR_NONE },
- { "quirks.css", IDR_UASTYLE_QUIRKS_CSS, ui::SCALE_FACTOR_NONE },
- { "view-source.css", IDR_UASTYLE_VIEW_SOURCE_CSS, ui::SCALE_FACTOR_NONE },
- { "themeChromium.css", IDR_UASTYLE_THEME_CHROMIUM_CSS,
- ui::SCALE_FACTOR_NONE },
+ {"missingImage", IDR_BROKENIMAGE, ui::SCALE_FACTOR_100P},
+ {"missingImage@2x", IDR_BROKENIMAGE, ui::SCALE_FACTOR_200P},
+ {"mediaplayerPause", IDR_MEDIAPLAYER_PAUSE_BUTTON, ui::SCALE_FACTOR_100P},
+ {"mediaplayerPauseHover",
+ IDR_MEDIAPLAYER_PAUSE_BUTTON_HOVER,
+ ui::SCALE_FACTOR_100P},
+ {"mediaplayerPauseDown",
+ IDR_MEDIAPLAYER_PAUSE_BUTTON_DOWN,
+ ui::SCALE_FACTOR_100P},
+ {"mediaplayerPlay", IDR_MEDIAPLAYER_PLAY_BUTTON, ui::SCALE_FACTOR_100P},
+ {"mediaplayerPlayHover",
+ IDR_MEDIAPLAYER_PLAY_BUTTON_HOVER,
+ ui::SCALE_FACTOR_100P},
+ {"mediaplayerPlayDown",
+ IDR_MEDIAPLAYER_PLAY_BUTTON_DOWN,
+ ui::SCALE_FACTOR_100P},
+ {"mediaplayerPlayDisabled",
+ IDR_MEDIAPLAYER_PLAY_BUTTON_DISABLED,
+ ui::SCALE_FACTOR_100P},
+ {"mediaplayerSoundLevel3",
+ IDR_MEDIAPLAYER_SOUND_LEVEL3_BUTTON,
+ ui::SCALE_FACTOR_100P},
+ {"mediaplayerSoundLevel3Hover",
+ IDR_MEDIAPLAYER_SOUND_LEVEL3_BUTTON_HOVER,
+ ui::SCALE_FACTOR_100P},
+ {"mediaplayerSoundLevel3Down",
+ IDR_MEDIAPLAYER_SOUND_LEVEL3_BUTTON_DOWN,
+ ui::SCALE_FACTOR_100P},
+ {"mediaplayerSoundLevel2",
+ IDR_MEDIAPLAYER_SOUND_LEVEL2_BUTTON,
+ ui::SCALE_FACTOR_100P},
+ {"mediaplayerSoundLevel2Hover",
+ IDR_MEDIAPLAYER_SOUND_LEVEL2_BUTTON_HOVER,
+ ui::SCALE_FACTOR_100P},
+ {"mediaplayerSoundLevel2Down",
+ IDR_MEDIAPLAYER_SOUND_LEVEL2_BUTTON_DOWN,
+ ui::SCALE_FACTOR_100P},
+ {"mediaplayerSoundLevel1",
+ IDR_MEDIAPLAYER_SOUND_LEVEL1_BUTTON,
+ ui::SCALE_FACTOR_100P},
+ {"mediaplayerSoundLevel1Hover",
+ IDR_MEDIAPLAYER_SOUND_LEVEL1_BUTTON_HOVER,
+ ui::SCALE_FACTOR_100P},
+ {"mediaplayerSoundLevel1Down",
+ IDR_MEDIAPLAYER_SOUND_LEVEL1_BUTTON_DOWN,
+ ui::SCALE_FACTOR_100P},
+ {"mediaplayerSoundLevel0",
+ IDR_MEDIAPLAYER_SOUND_LEVEL0_BUTTON,
+ ui::SCALE_FACTOR_100P},
+ {"mediaplayerSoundLevel0Hover",
+ IDR_MEDIAPLAYER_SOUND_LEVEL0_BUTTON_HOVER,
+ ui::SCALE_FACTOR_100P},
+ {"mediaplayerSoundLevel0Down",
+ IDR_MEDIAPLAYER_SOUND_LEVEL0_BUTTON_DOWN,
+ ui::SCALE_FACTOR_100P},
+ {"mediaplayerSoundDisabled",
+ IDR_MEDIAPLAYER_SOUND_DISABLED,
+ ui::SCALE_FACTOR_100P},
+ {"mediaplayerSliderThumb",
+ IDR_MEDIAPLAYER_SLIDER_THUMB,
+ ui::SCALE_FACTOR_100P},
+ {"mediaplayerSliderThumbHover",
+ IDR_MEDIAPLAYER_SLIDER_THUMB_HOVER,
+ ui::SCALE_FACTOR_100P},
+ {"mediaplayerSliderThumbDown",
+ IDR_MEDIAPLAYER_SLIDER_THUMB_DOWN,
+ ui::SCALE_FACTOR_100P},
+ {"mediaplayerVolumeSliderThumb",
+ IDR_MEDIAPLAYER_VOLUME_SLIDER_THUMB,
+ ui::SCALE_FACTOR_100P},
+ {"mediaplayerVolumeSliderThumbHover",
+ IDR_MEDIAPLAYER_VOLUME_SLIDER_THUMB_HOVER,
+ ui::SCALE_FACTOR_100P},
+ {"mediaplayerVolumeSliderThumbDown",
+ IDR_MEDIAPLAYER_VOLUME_SLIDER_THUMB_DOWN,
+ ui::SCALE_FACTOR_100P},
+ {"mediaplayerVolumeSliderThumbDisabled",
+ IDR_MEDIAPLAYER_VOLUME_SLIDER_THUMB_DISABLED,
+ ui::SCALE_FACTOR_100P},
+ {"mediaplayerClosedCaption",
+ IDR_MEDIAPLAYER_CLOSEDCAPTION_BUTTON,
+ ui::SCALE_FACTOR_100P},
+ {"mediaplayerClosedCaptionHover",
+ IDR_MEDIAPLAYER_CLOSEDCAPTION_BUTTON_HOVER,
+ ui::SCALE_FACTOR_100P},
+ {"mediaplayerClosedCaptionDown",
+ IDR_MEDIAPLAYER_CLOSEDCAPTION_BUTTON_DOWN,
+ ui::SCALE_FACTOR_100P},
+ {"mediaplayerClosedCaptionDisabled",
+ IDR_MEDIAPLAYER_CLOSEDCAPTION_BUTTON_DISABLED,
+ ui::SCALE_FACTOR_100P},
+ {"mediaplayerFullscreen",
+ IDR_MEDIAPLAYER_FULLSCREEN_BUTTON,
+ ui::SCALE_FACTOR_100P},
+ {"mediaplayerFullscreenHover",
+ IDR_MEDIAPLAYER_FULLSCREEN_BUTTON_HOVER,
+ ui::SCALE_FACTOR_100P},
+ {"mediaplayerFullscreenDown",
+ IDR_MEDIAPLAYER_FULLSCREEN_BUTTON_DOWN,
+ ui::SCALE_FACTOR_100P},
+ {"mediaplayerCastOff",
+ IDR_MEDIAPLAYER_CAST_BUTTON_OFF,
+ ui::SCALE_FACTOR_100P},
+ {"mediaplayerCastOn",
+ IDR_MEDIAPLAYER_CAST_BUTTON_ON,
+ ui::SCALE_FACTOR_100P},
+ {"mediaplayerFullscreenDisabled",
+ IDR_MEDIAPLAYER_FULLSCREEN_BUTTON_DISABLED,
+ ui::SCALE_FACTOR_100P},
+ {"mediaplayerOverlayCastOff",
+ IDR_MEDIAPLAYER_OVERLAY_CAST_BUTTON_OFF,
+ ui::SCALE_FACTOR_100P},
+ {"mediaplayerOverlayPlay",
+ IDR_MEDIAPLAYER_OVERLAY_PLAY_BUTTON,
+ ui::SCALE_FACTOR_100P},
+ {"panIcon", IDR_PAN_SCROLL_ICON, ui::SCALE_FACTOR_100P},
+ {"searchCancel", IDR_SEARCH_CANCEL, ui::SCALE_FACTOR_100P},
+ {"searchCancelPressed", IDR_SEARCH_CANCEL_PRESSED, ui::SCALE_FACTOR_100P},
+ {"searchMagnifier", IDR_SEARCH_MAGNIFIER, ui::SCALE_FACTOR_100P},
+ {"searchMagnifierResults",
+ IDR_SEARCH_MAGNIFIER_RESULTS,
+ ui::SCALE_FACTOR_100P},
+ {"textAreaResizeCorner", IDR_TEXTAREA_RESIZER, ui::SCALE_FACTOR_100P},
+ {"textAreaResizeCorner@2x", IDR_TEXTAREA_RESIZER, ui::SCALE_FACTOR_200P},
+ {"generatePassword", IDR_PASSWORD_GENERATION_ICON, ui::SCALE_FACTOR_100P},
+ {"generatePasswordHover",
+ IDR_PASSWORD_GENERATION_ICON_HOVER,
+ ui::SCALE_FACTOR_100P},
+ {"html.css", IDR_UASTYLE_HTML_CSS, ui::SCALE_FACTOR_NONE},
+ {"quirks.css", IDR_UASTYLE_QUIRKS_CSS, ui::SCALE_FACTOR_NONE},
+ {"view-source.css", IDR_UASTYLE_VIEW_SOURCE_CSS, ui::SCALE_FACTOR_NONE},
+ {"themeChromium.css",
+ IDR_UASTYLE_THEME_CHROMIUM_CSS,
+ ui::SCALE_FACTOR_NONE},
#if defined(OS_ANDROID)
- { "themeChromiumAndroid.css", IDR_UASTYLE_THEME_CHROMIUM_ANDROID_CSS,
- ui::SCALE_FACTOR_NONE },
- { "mediaControlsAndroid.css", IDR_UASTYLE_MEDIA_CONTROLS_ANDROID_CSS,
- ui::SCALE_FACTOR_NONE },
+ {"themeChromiumAndroid.css",
+ IDR_UASTYLE_THEME_CHROMIUM_ANDROID_CSS,
+ ui::SCALE_FACTOR_NONE},
+ {"mediaControlsAndroid.css",
+ IDR_UASTYLE_MEDIA_CONTROLS_ANDROID_CSS,
+ ui::SCALE_FACTOR_NONE},
#endif
#if !defined(OS_WIN)
- { "themeChromiumLinux.css", IDR_UASTYLE_THEME_CHROMIUM_LINUX_CSS,
- ui::SCALE_FACTOR_NONE },
+ {"themeChromiumLinux.css",
+ IDR_UASTYLE_THEME_CHROMIUM_LINUX_CSS,
+ ui::SCALE_FACTOR_NONE},
#endif
- { "themeChromiumSkia.css", IDR_UASTYLE_THEME_CHROMIUM_SKIA_CSS,
- ui::SCALE_FACTOR_NONE },
- { "themeInputMultipleFields.css",
- IDR_UASTYLE_THEME_INPUT_MULTIPLE_FIELDS_CSS, ui::SCALE_FACTOR_NONE },
+ {"themeChromiumSkia.css",
+ IDR_UASTYLE_THEME_CHROMIUM_SKIA_CSS,
+ ui::SCALE_FACTOR_NONE},
+ {"themeInputMultipleFields.css",
+ IDR_UASTYLE_THEME_INPUT_MULTIPLE_FIELDS_CSS,
+ ui::SCALE_FACTOR_NONE},
#if defined(OS_MACOSX)
- { "themeMac.css", IDR_UASTYLE_THEME_MAC_CSS, ui::SCALE_FACTOR_NONE },
+ {"themeMac.css", IDR_UASTYLE_THEME_MAC_CSS, ui::SCALE_FACTOR_NONE},
#endif
- { "themeWin.css", IDR_UASTYLE_THEME_WIN_CSS, ui::SCALE_FACTOR_NONE },
- { "themeWinQuirks.css", IDR_UASTYLE_THEME_WIN_QUIRKS_CSS,
- ui::SCALE_FACTOR_NONE },
- { "svg.css", IDR_UASTYLE_SVG_CSS, ui::SCALE_FACTOR_NONE},
- { "navigationTransitions.css", IDR_UASTYLE_NAVIGATION_TRANSITIONS_CSS,
- ui::SCALE_FACTOR_NONE },
- { "mathml.css", IDR_UASTYLE_MATHML_CSS, ui::SCALE_FACTOR_NONE},
- { "mediaControls.css", IDR_UASTYLE_MEDIA_CONTROLS_CSS,
- ui::SCALE_FACTOR_NONE },
- { "fullscreen.css", IDR_UASTYLE_FULLSCREEN_CSS, ui::SCALE_FACTOR_NONE},
- { "xhtmlmp.css", IDR_UASTYLE_XHTMLMP_CSS, ui::SCALE_FACTOR_NONE},
- { "viewportAndroid.css", IDR_UASTYLE_VIEWPORT_ANDROID_CSS,
- ui::SCALE_FACTOR_NONE},
- { "InspectorOverlayPage.html", IDR_INSPECTOR_OVERLAY_PAGE_HTML,
- ui::SCALE_FACTOR_NONE },
- { "InjectedScriptCanvasModuleSource.js",
- IDR_INSPECTOR_INJECTED_SCRIPT_CANVAS_MODULE_SOURCE_JS,
- ui::SCALE_FACTOR_NONE },
- { "InjectedScriptSource.js", IDR_INSPECTOR_INJECTED_SCRIPT_SOURCE_JS,
- ui::SCALE_FACTOR_NONE },
- { "DebuggerScriptSource.js", IDR_INSPECTOR_DEBUGGER_SCRIPT_SOURCE_JS,
- ui::SCALE_FACTOR_NONE },
- { "DocumentExecCommand.js", IDR_PRIVATE_SCRIPT_DOCUMENTEXECCOMMAND_JS,
- ui::SCALE_FACTOR_NONE },
- { "DocumentXMLTreeViewer.js", IDR_PRIVATE_SCRIPT_DOCUMENTXMLTREEVIEWER_JS,
- ui::SCALE_FACTOR_NONE },
- { "HTMLMarqueeElement.js", IDR_PRIVATE_SCRIPT_HTMLMARQUEEELEMENT_JS,
- ui::SCALE_FACTOR_NONE },
- { "PluginPlaceholderElement.js",
- IDR_PRIVATE_SCRIPT_PLUGINPLACEHOLDERELEMENT_JS, ui::SCALE_FACTOR_NONE },
- { "PrivateScriptRunner.js", IDR_PRIVATE_SCRIPT_PRIVATESCRIPTRUNNER_JS,
- ui::SCALE_FACTOR_NONE },
+ {"themeWin.css", IDR_UASTYLE_THEME_WIN_CSS, ui::SCALE_FACTOR_NONE},
+ {"themeWinQuirks.css",
+ IDR_UASTYLE_THEME_WIN_QUIRKS_CSS,
+ ui::SCALE_FACTOR_NONE},
+ {"svg.css", IDR_UASTYLE_SVG_CSS, ui::SCALE_FACTOR_NONE},
+ {"navigationTransitions.css",
+ IDR_UASTYLE_NAVIGATION_TRANSITIONS_CSS,
+ ui::SCALE_FACTOR_NONE},
+ {"mathml.css", IDR_UASTYLE_MATHML_CSS, ui::SCALE_FACTOR_NONE},
+ {"mediaControls.css",
+ IDR_UASTYLE_MEDIA_CONTROLS_CSS,
+ ui::SCALE_FACTOR_NONE},
+ {"fullscreen.css", IDR_UASTYLE_FULLSCREEN_CSS, ui::SCALE_FACTOR_NONE},
+ {"xhtmlmp.css", IDR_UASTYLE_XHTMLMP_CSS, ui::SCALE_FACTOR_NONE},
+ {"viewportAndroid.css",
+ IDR_UASTYLE_VIEWPORT_ANDROID_CSS,
+ ui::SCALE_FACTOR_NONE},
+ {"InspectorOverlayPage.html",
+ IDR_INSPECTOR_OVERLAY_PAGE_HTML,
+ ui::SCALE_FACTOR_NONE},
+ {"InjectedScriptSource.js",
+ IDR_INSPECTOR_INJECTED_SCRIPT_SOURCE_JS,
+ ui::SCALE_FACTOR_NONE},
+ {"DebuggerScriptSource.js",
+ IDR_INSPECTOR_DEBUGGER_SCRIPT_SOURCE_JS,
+ ui::SCALE_FACTOR_NONE},
+ {"DocumentExecCommand.js",
+ IDR_PRIVATE_SCRIPT_DOCUMENTEXECCOMMAND_JS,
+ ui::SCALE_FACTOR_NONE},
+ {"DocumentXMLTreeViewer.css",
+ IDR_PRIVATE_SCRIPT_DOCUMENTXMLTREEVIEWER_CSS,
+ ui::SCALE_FACTOR_NONE},
+ {"DocumentXMLTreeViewer.js",
+ IDR_PRIVATE_SCRIPT_DOCUMENTXMLTREEVIEWER_JS,
+ ui::SCALE_FACTOR_NONE},
+ {"HTMLMarqueeElement.js",
+ IDR_PRIVATE_SCRIPT_HTMLMARQUEEELEMENT_JS,
+ ui::SCALE_FACTOR_NONE},
+ {"PluginPlaceholderElement.js",
+ IDR_PRIVATE_SCRIPT_PLUGINPLACEHOLDERELEMENT_JS,
+ ui::SCALE_FACTOR_NONE},
+ {"PrivateScriptRunner.js",
+ IDR_PRIVATE_SCRIPT_PRIVATESCRIPTRUNNER_JS,
+ ui::SCALE_FACTOR_NONE},
#ifdef IDR_PICKER_COMMON_JS
- { "pickerCommon.js", IDR_PICKER_COMMON_JS, ui::SCALE_FACTOR_NONE },
- { "pickerCommon.css", IDR_PICKER_COMMON_CSS, ui::SCALE_FACTOR_NONE },
- { "calendarPicker.js", IDR_CALENDAR_PICKER_JS, ui::SCALE_FACTOR_NONE },
- { "calendarPicker.css", IDR_CALENDAR_PICKER_CSS, ui::SCALE_FACTOR_NONE },
- { "pickerButton.css", IDR_PICKER_BUTTON_CSS, ui::SCALE_FACTOR_NONE },
- { "suggestionPicker.js", IDR_SUGGESTION_PICKER_JS, ui::SCALE_FACTOR_NONE },
- { "suggestionPicker.css", IDR_SUGGESTION_PICKER_CSS, ui::SCALE_FACTOR_NONE },
- { "colorSuggestionPicker.js",
- IDR_COLOR_SUGGESTION_PICKER_JS, ui::SCALE_FACTOR_NONE },
- { "colorSuggestionPicker.css",
- IDR_COLOR_SUGGESTION_PICKER_CSS, ui::SCALE_FACTOR_NONE },
+ {"pickerCommon.js", IDR_PICKER_COMMON_JS, ui::SCALE_FACTOR_NONE},
+ {"pickerCommon.css", IDR_PICKER_COMMON_CSS, ui::SCALE_FACTOR_NONE},
+ {"calendarPicker.js", IDR_CALENDAR_PICKER_JS, ui::SCALE_FACTOR_NONE},
+ {"calendarPicker.css", IDR_CALENDAR_PICKER_CSS, ui::SCALE_FACTOR_NONE},
+ {"listPicker.js", IDR_LIST_PICKER_JS, ui::SCALE_FACTOR_NONE},
+ {"listPicker.css", IDR_LIST_PICKER_CSS, ui::SCALE_FACTOR_NONE},
+ {"pickerButton.css", IDR_PICKER_BUTTON_CSS, ui::SCALE_FACTOR_NONE},
+ {"suggestionPicker.js", IDR_SUGGESTION_PICKER_JS, ui::SCALE_FACTOR_NONE},
+ {"suggestionPicker.css", IDR_SUGGESTION_PICKER_CSS, ui::SCALE_FACTOR_NONE},
+ {"colorSuggestionPicker.js",
+ IDR_COLOR_SUGGESTION_PICKER_JS,
+ ui::SCALE_FACTOR_NONE},
+ {"colorSuggestionPicker.css",
+ IDR_COLOR_SUGGESTION_PICKER_CSS,
+ ui::SCALE_FACTOR_NONE},
#endif
};
@@ -948,6 +1084,11 @@ double BlinkPlatformImpl::monotonicallyIncreasingTime() {
static_cast<double>(base::Time::kMicrosecondsPerSecond);
}
+double BlinkPlatformImpl::systemTraceTime() {
+ return base::TimeTicks::NowFromSystemTraceTime().ToInternalValue() /
+ static_cast<double>(base::Time::kMicrosecondsPerSecond);
+}
+
void BlinkPlatformImpl::cryptographicallyRandomValues(
unsigned char* buffer, size_t length) {
base::RandBytes(buffer, length);
@@ -992,31 +1133,24 @@ void BlinkPlatformImpl::stopSharedTimer() {
shared_timer_.Stop();
}
-void BlinkPlatformImpl::callOnMainThread(
- void (*func)(void*), void* context) {
- main_loop_->PostTask(FROM_HERE, base::Bind(func, context));
-}
-
blink::WebGestureCurve* BlinkPlatformImpl::createFlingAnimationCurve(
blink::WebGestureDevice device_source,
const blink::WebFloatPoint& velocity,
const blink::WebSize& cumulative_scroll) {
- auto curve = WebGestureCurveImpl::CreateFromDefaultPlatformCurve(
- gfx::Vector2dF(velocity.x, velocity.y),
- gfx::Vector2dF(cumulative_scroll.width, cumulative_scroll.height));
- return curve.release();
+ return ui::WebGestureCurveImpl::CreateFromDefaultPlatformCurve(
+ gfx::Vector2dF(velocity.x, velocity.y),
+ gfx::Vector2dF(cumulative_scroll.width, cumulative_scroll.height),
+ IsMainThread()).release();
}
-void BlinkPlatformImpl::didStartWorkerRunLoop(
- const blink::WebWorkerRunLoop& runLoop) {
+void BlinkPlatformImpl::didStartWorkerRunLoop() {
WorkerTaskRunner* worker_task_runner = WorkerTaskRunner::Instance();
- worker_task_runner->OnWorkerRunLoopStarted(runLoop);
+ worker_task_runner->OnWorkerRunLoopStarted();
}
-void BlinkPlatformImpl::didStopWorkerRunLoop(
- const blink::WebWorkerRunLoop& runLoop) {
+void BlinkPlatformImpl::didStopWorkerRunLoop() {
WorkerTaskRunner* worker_task_runner = WorkerTaskRunner::Instance();
- worker_task_runner->OnWorkerRunLoopStopped(runLoop);
+ worker_task_runner->OnWorkerRunLoopStopped();
}
blink::WebCrypto* BlinkPlatformImpl::crypto() {
@@ -1027,6 +1161,10 @@ blink::WebGeofencingProvider* BlinkPlatformImpl::geofencingProvider() {
return geofencing_provider_.get();
}
+blink::WebBluetooth* BlinkPlatformImpl::bluetooth() {
+ return bluetooth_.get();
+}
+
blink::WebNotificationManager*
BlinkPlatformImpl::notificationManager() {
if (!thread_safe_sender_.get() || !notification_dispatcher_.get())
@@ -1034,9 +1172,49 @@ BlinkPlatformImpl::notificationManager() {
return NotificationManager::ThreadSpecificInstance(
thread_safe_sender_.get(),
+ main_thread_task_runner_.get(),
notification_dispatcher_.get());
}
+blink::WebPushProvider* BlinkPlatformImpl::pushProvider() {
+ if (!thread_safe_sender_.get() || !push_dispatcher_.get())
+ return nullptr;
+
+ return PushProvider::ThreadSpecificInstance(thread_safe_sender_.get(),
+ push_dispatcher_.get());
+}
+
+blink::WebNavigatorConnectProvider*
+BlinkPlatformImpl::navigatorConnectProvider() {
+ if (!thread_safe_sender_.get())
+ return nullptr;
+
+ return NavigatorConnectProvider::ThreadSpecificInstance(
+ thread_safe_sender_.get(), main_thread_task_runner_);
+}
+
+blink::WebPermissionClient* BlinkPlatformImpl::permissionClient() {
+ if (!permission_client_.get())
+ return nullptr;
+
+ if (IsMainThread())
+ return permission_client_.get();
+
+ return PermissionDispatcherThreadProxy::GetThreadInstance(
+ main_thread_task_runner_.get(), permission_client_.get());
+}
+
+blink::WebSyncProvider* BlinkPlatformImpl::backgroundSyncProvider() {
+ if (!sync_provider_.get())
+ return nullptr;
+
+ if (IsMainThread())
+ return sync_provider_.get();
+
+ return BackgroundSyncProviderThreadProxy::GetThreadInstance(
+ main_thread_task_runner_.get(), sync_provider_.get());
+}
+
WebThemeEngine* BlinkPlatformImpl::themeEngine() {
return &native_theme_engine_;
}
@@ -1074,6 +1252,11 @@ long long BlinkPlatformImpl::databaseGetSpaceAvailableForOrigin(
return 0;
}
+bool BlinkPlatformImpl::databaseSetFileSize(
+ const blink::WebString& vfs_file_name, long long size) {
+ return false;
+}
+
blink::WebString BlinkPlatformImpl::signedPublicKeyAndChallengeString(
unsigned key_size_index,
const blink::WebString& challenge,
@@ -1127,38 +1310,6 @@ size_t BlinkPlatformImpl::numberOfProcessors() {
return static_cast<size_t>(base::SysInfo::NumberOfProcessors());
}
-void BlinkPlatformImpl::startHeapProfiling(
- const blink::WebString& prefix) {
- // FIXME(morrita): Make this built on windows.
-#if !defined(NO_TCMALLOC) && defined(USE_TCMALLOC) && !defined(OS_WIN)
- HeapProfilerStart(prefix.utf8().data());
-#endif
-}
-
-void BlinkPlatformImpl::stopHeapProfiling() {
-#if !defined(NO_TCMALLOC) && defined(USE_TCMALLOC) && !defined(OS_WIN)
- HeapProfilerStop();
-#endif
-}
-
-void BlinkPlatformImpl::dumpHeapProfiling(
- const blink::WebString& reason) {
-#if !defined(NO_TCMALLOC) && defined(USE_TCMALLOC) && !defined(OS_WIN)
- HeapProfilerDump(reason.utf8().data());
-#endif
-}
-
-WebString BlinkPlatformImpl::getHeapProfile() {
-#if !defined(NO_TCMALLOC) && defined(USE_TCMALLOC) && !defined(OS_WIN)
- char* data = GetHeapProfile();
- WebString result = WebString::fromUTF8(std::string(data));
- free(data);
- return result;
-#else
- return WebString();
-#endif
-}
-
bool BlinkPlatformImpl::processMemorySizesInBytes(
size_t* private_bytes,
size_t* shared_bytes) {
@@ -1171,10 +1322,6 @@ bool BlinkPlatformImpl::memoryAllocatorWasteInBytes(size_t* size) {
blink::WebDiscardableMemory*
BlinkPlatformImpl::allocateAndLockDiscardableMemory(size_t bytes) {
- base::DiscardableMemoryType type =
- base::DiscardableMemory::GetPreferredType();
- if (type == base::DISCARDABLE_MEMORY_TYPE_EMULATED)
- return NULL;
return content::WebDiscardableMemoryImpl::CreateLockedMemory(bytes).release();
}
@@ -1215,11 +1362,29 @@ void BlinkPlatformImpl::ResumeSharedTimer() {
}
}
-// static
-void BlinkPlatformImpl::DestroyCurrentThread(void* thread) {
- WebThreadImplForMessageLoop* impl =
- static_cast<WebThreadImplForMessageLoop*>(thread);
- delete impl;
+scoped_refptr<base::SingleThreadTaskRunner>
+BlinkPlatformImpl::MainTaskRunnerForCurrentThread() {
+ if (main_thread_task_runner_.get() &&
+ main_thread_task_runner_->BelongsToCurrentThread()) {
+ return main_thread_task_runner_;
+ } else {
+ return base::MessageLoopProxy::current();
+ }
+}
+
+bool BlinkPlatformImpl::IsMainThread() const {
+ return main_thread_task_runner_.get() &&
+ main_thread_task_runner_->BelongsToCurrentThread();
+}
+
+WebString BlinkPlatformImpl::domCodeStringFromEnum(int dom_code) {
+ return WebString::fromUTF8(ui::KeycodeConverter::DomCodeToCodeString(
+ static_cast<ui::DomCode>(dom_code)));
+}
+
+int BlinkPlatformImpl::domEnumFromCodeString(const WebString& code) {
+ return static_cast<int>(ui::KeycodeConverter::CodeStringToDomCode(
+ code.utf8().data()));
}
} // namespace content
diff --git a/chromium/content/child/blink_platform_impl.h b/chromium/content/child/blink_platform_impl.h
index 785b0d6418a..8ca60eae4f6 100644
--- a/chromium/content/child/blink_platform_impl.h
+++ b/chromium/content/child/blink_platform_impl.h
@@ -6,10 +6,11 @@
#define CONTENT_CHILD_BLINK_PLATFORM_IMPL_H_
#include "base/compiler_specific.h"
-#include "base/debug/trace_event.h"
+#include "base/containers/scoped_ptr_hash_map.h"
#include "base/threading/thread_local_storage.h"
#include "base/timer/timer.h"
-#include "content/child/webcrypto/webcrypto_impl.h"
+#include "base/trace_event/trace_event.h"
+#include "components/webcrypto/webcrypto_impl.h"
#include "content/child/webfallbackthemeengine_impl.h"
#include "content/common/content_export.h"
#include "third_party/WebKit/public/platform/Platform.h"
@@ -32,16 +33,23 @@ class MessageLoop;
}
namespace content {
+class BackgroundSyncProvider;
class FlingCurveConfiguration;
class NotificationDispatcher;
+class PermissionDispatcher;
+class PushDispatcher;
class ThreadSafeSender;
+class WebBluetoothImpl;
class WebCryptoImpl;
class WebGeofencingProviderImpl;
+class WebMemoryDumpProviderAdapter;
class CONTENT_EXPORT BlinkPlatformImpl
: NON_EXPORTED_BASE(public blink::Platform) {
public:
BlinkPlatformImpl();
+ explicit BlinkPlatformImpl(
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner);
virtual ~BlinkPlatformImpl();
// Platform methods (partial implementation):
@@ -56,6 +64,8 @@ class CONTENT_EXPORT BlinkPlatformImpl
virtual long long databaseGetFileSize(const blink::WebString& vfs_file_name);
virtual long long databaseGetSpaceAvailableForOrigin(
const blink::WebString& origin_identifier);
+ virtual bool databaseSetFileSize(
+ const blink::WebString& vfs_file_name, long long size);
virtual blink::WebString signedPublicKeyAndChallengeString(
unsigned key_size_index, const blink::WebString& challenge,
const blink::WebURL& url);
@@ -65,11 +75,6 @@ class CONTENT_EXPORT BlinkPlatformImpl
virtual size_t virtualMemoryLimitMB();
virtual size_t numberOfProcessors();
- virtual void startHeapProfiling(const blink::WebString& prefix);
- virtual void stopHeapProfiling();
- virtual void dumpHeapProfiling(const blink::WebString& reason);
- virtual blink::WebString getHeapProfile();
-
virtual bool processMemorySizesInBytes(size_t* private_bytes,
size_t* shared_bytes);
virtual bool memoryAllocatorWasteInBytes(size_t* size);
@@ -83,9 +88,8 @@ class CONTENT_EXPORT BlinkPlatformImpl
const blink::WebURL& url, blink::WebString& mimetype,
blink::WebString& charset);
virtual blink::WebURLError cancelledError(const blink::WebURL& url) const;
- virtual bool isReservedIPAddress(
- const blink::WebSecurityOrigin&) const;
- virtual bool isReservedIPAddress(const blink::WebURL&) const;
+ virtual bool isReservedIPAddress(const blink::WebString& host) const;
+ virtual bool portAllowed(const blink::WebURL& url) const;
virtual blink::WebThread* createThread(const char* name);
virtual blink::WebThread* currentThread();
virtual void yieldCurrentThread();
@@ -101,12 +105,14 @@ class CONTENT_EXPORT BlinkPlatformImpl
virtual void histogramSparse(const char* name, int sample);
virtual const unsigned char* getTraceCategoryEnabledFlag(
const char* category_name);
- virtual long* getTraceSamplingState(const unsigned thread_bucket);
+ virtual TraceEventAPIAtomicWord* getTraceSamplingState(
+ const unsigned thread_bucket);
virtual TraceEventHandle addTraceEvent(
char phase,
const unsigned char* category_group_enabled,
const char* name,
unsigned long long id,
+ double timestamp,
int num_args,
const char** arg_names,
const unsigned char* arg_types,
@@ -117,16 +123,19 @@ class CONTENT_EXPORT BlinkPlatformImpl
const unsigned char* category_group_enabled,
const char* name,
unsigned long long id,
+ double timestamp,
int num_args,
const char** arg_names,
const unsigned char* arg_types,
const unsigned long long* arg_values,
- const blink::WebConvertableToTraceFormat* convertable_values,
+ blink::WebConvertableToTraceFormat* convertable_values,
unsigned char flags);
virtual void updateTraceEventDuration(
const unsigned char* category_group_enabled,
const char* name,
TraceEventHandle);
+ virtual void registerMemoryDumpProvider(blink::WebMemoryDumpProvider* wmdp);
+ virtual void unregisterMemoryDumpProvider(blink::WebMemoryDumpProvider* wmdp);
virtual blink::WebData loadResource(const char* name);
virtual blink::WebString queryLocalizedString(
blink::WebLocalizedString::Name name);
@@ -140,50 +149,70 @@ class CONTENT_EXPORT BlinkPlatformImpl
virtual void suddenTerminationChanged(bool enabled) { }
virtual double currentTime();
virtual double monotonicallyIncreasingTime();
+ virtual double systemTraceTime();
virtual void cryptographicallyRandomValues(
unsigned char* buffer, size_t length);
virtual void setSharedTimerFiredFunction(void (*func)());
virtual void setSharedTimerFireInterval(double interval_seconds);
virtual void stopSharedTimer();
- virtual void callOnMainThread(void (*func)(void*), void* context);
virtual blink::WebGestureCurve* createFlingAnimationCurve(
blink::WebGestureDevice device_source,
const blink::WebFloatPoint& velocity,
const blink::WebSize& cumulative_scroll);
- virtual void didStartWorkerRunLoop(
- const blink::WebWorkerRunLoop& runLoop);
- virtual void didStopWorkerRunLoop(
- const blink::WebWorkerRunLoop& runLoop);
+ virtual void didStartWorkerRunLoop();
+ virtual void didStopWorkerRunLoop();
virtual blink::WebCrypto* crypto();
virtual blink::WebGeofencingProvider* geofencingProvider();
+ virtual blink::WebBluetooth* bluetooth();
virtual blink::WebNotificationManager* notificationManager();
+ virtual blink::WebPushProvider* pushProvider();
+ virtual blink::WebNavigatorConnectProvider* navigatorConnectProvider();
+ virtual blink::WebPermissionClient* permissionClient();
+ virtual blink::WebSyncProvider* backgroundSyncProvider();
void SuspendSharedTimer();
void ResumeSharedTimer();
virtual void OnStartSharedTimer(base::TimeDelta delay) {}
- private:
- static void DestroyCurrentThread(void*);
+ WebBluetoothImpl* BluetoothImplForTesting() { return bluetooth_.get(); }
+ virtual blink::WebString domCodeStringFromEnum(int dom_code);
+ virtual int domEnumFromCodeString(const blink::WebString& codeString);
+
+ private:
void DoTimeout() {
if (shared_timer_func_ && !shared_timer_suspended_)
shared_timer_func_();
}
+ void InternalInit();
+ void UpdateWebThreadTLS(blink::WebThread* thread);
+
+ bool IsMainThread() const;
+
+ scoped_refptr<base::SingleThreadTaskRunner> MainTaskRunnerForCurrentThread();
+
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
WebThemeEngineImpl native_theme_engine_;
WebFallbackThemeEngineImpl fallback_theme_engine_;
- base::MessageLoop* main_loop_;
base::OneShotTimer<BlinkPlatformImpl> shared_timer_;
void (*shared_timer_func_)();
double shared_timer_fire_time_;
bool shared_timer_fire_time_was_set_while_suspended_;
int shared_timer_suspended_; // counter
base::ThreadLocalStorage::Slot current_thread_slot_;
- WebCryptoImpl web_crypto_;
+ webcrypto::WebCryptoImpl web_crypto_;
scoped_ptr<WebGeofencingProviderImpl> geofencing_provider_;
+ scoped_ptr<WebBluetoothImpl> bluetooth_;
+ base::ScopedPtrHashMap<blink::WebMemoryDumpProvider*,
+ scoped_ptr<WebMemoryDumpProviderAdapter>>
+ memory_dump_providers_;
scoped_refptr<ThreadSafeSender> thread_safe_sender_;
scoped_refptr<NotificationDispatcher> notification_dispatcher_;
+ scoped_refptr<PushDispatcher> push_dispatcher_;
+ scoped_ptr<PermissionDispatcher> permission_client_;
+ scoped_ptr<BackgroundSyncProvider> sync_provider_;
};
} // namespace content
diff --git a/chromium/content/child/blink_platform_impl_unittest.cc b/chromium/content/child/blink_platform_impl_unittest.cc
index 661ce192e9a..01a3b9180be 100644
--- a/chromium/content/child/blink_platform_impl_unittest.cc
+++ b/chromium/content/child/blink_platform_impl_unittest.cc
@@ -19,7 +19,7 @@ class TestBlinkPlatformImpl : public BlinkPlatformImpl {
TestBlinkPlatformImpl() : mock_monotonically_increasing_time_(0) {}
// Returns mock time when enabled.
- virtual double monotonicallyIncreasingTime() override {
+ double monotonicallyIncreasingTime() override {
if (mock_monotonically_increasing_time_ > 0.0)
return mock_monotonically_increasing_time_;
return BlinkPlatformImpl::monotonicallyIncreasingTime();
@@ -68,42 +68,41 @@ TEST(BlinkPlatformTest, SuspendResumeSharedTimer) {
EXPECT_TRUE(base::TimeDelta() == platform_impl.shared_timer_delay());
}
-TEST(BlinkPlatformTest, IsReservedIPAddress_WebURL) {
+TEST(BlinkPlatformTest, IsReservedIPAddress) {
TestBlinkPlatformImpl platform_impl;
// Unreserved IPv4 addresses (in various forms).
- EXPECT_FALSE(platform_impl.isReservedIPAddress(GURL("http://8.8.8.8/")));
- EXPECT_FALSE(platform_impl.isReservedIPAddress(GURL("http://99.64.0.0/")));
- EXPECT_FALSE(platform_impl.isReservedIPAddress(GURL("http://212.15.0.0/")));
- EXPECT_FALSE(platform_impl.isReservedIPAddress(GURL("http://212.15/")));
- EXPECT_FALSE(platform_impl.isReservedIPAddress(GURL("http://212.15.0/")));
- EXPECT_FALSE(platform_impl.isReservedIPAddress(GURL("http://3557752832/")));
+ EXPECT_FALSE(platform_impl.isReservedIPAddress("8.8.8.8"));
+ EXPECT_FALSE(platform_impl.isReservedIPAddress("99.64.0.0"));
+ EXPECT_FALSE(platform_impl.isReservedIPAddress("212.15.0.0"));
+ EXPECT_FALSE(platform_impl.isReservedIPAddress("212.15"));
+ EXPECT_FALSE(platform_impl.isReservedIPAddress("212.15.0"));
+ EXPECT_FALSE(platform_impl.isReservedIPAddress("3557752832"));
// Reserved IPv4 addresses (in various forms).
- EXPECT_TRUE(platform_impl.isReservedIPAddress(GURL("http://192.168.0.0/")));
- EXPECT_TRUE(platform_impl.isReservedIPAddress(GURL("http://192.168.0.6/")));
- EXPECT_TRUE(platform_impl.isReservedIPAddress(GURL("http://10.0.0.5/")));
- EXPECT_TRUE(platform_impl.isReservedIPAddress(GURL("http://10.0.0/")));
- EXPECT_TRUE(platform_impl.isReservedIPAddress(GURL("http://10.0/")));
- EXPECT_TRUE(platform_impl.isReservedIPAddress(GURL("http://3232235526/")));
+ EXPECT_TRUE(platform_impl.isReservedIPAddress("192.168.0.0"));
+ EXPECT_TRUE(platform_impl.isReservedIPAddress("192.168.0.6"));
+ EXPECT_TRUE(platform_impl.isReservedIPAddress("10.0.0.5"));
+ EXPECT_TRUE(platform_impl.isReservedIPAddress("10.0.0"));
+ EXPECT_TRUE(platform_impl.isReservedIPAddress("10.0"));
+ EXPECT_TRUE(platform_impl.isReservedIPAddress("3232235526"));
// Unreserved IPv6 addresses.
EXPECT_FALSE(platform_impl.isReservedIPAddress(
- GURL("http://[FFC0:ba98:7654:3210:FEDC:BA98:7654:3210]/")));
+ "[FFC0:ba98:7654:3210:FEDC:BA98:7654:3210]"));
EXPECT_FALSE(platform_impl.isReservedIPAddress(
- GURL("http://[2000:ba98:7654:2301:EFCD:BA98:7654:3210]/")));
+ "[2000:ba98:7654:2301:EFCD:BA98:7654:3210]"));
// Reserved IPv6 addresses.
- EXPECT_TRUE(platform_impl.isReservedIPAddress(GURL("http://[::1]/")));
- EXPECT_TRUE(platform_impl.isReservedIPAddress(GURL("http://[::192.9.5.5]/")));
- EXPECT_TRUE(platform_impl.isReservedIPAddress(GURL("http://[FEED::BEEF]/")));
+ EXPECT_TRUE(platform_impl.isReservedIPAddress("[::1]"));
+ EXPECT_TRUE(platform_impl.isReservedIPAddress("[::192.9.5.5]"));
+ EXPECT_TRUE(platform_impl.isReservedIPAddress("[FEED::BEEF]"));
EXPECT_TRUE(platform_impl.isReservedIPAddress(
- GURL("http://[FEC0:ba98:7654:3210:FEDC:BA98:7654:3210]/")));
+ "[FEC0:ba98:7654:3210:FEDC:BA98:7654:3210]"));
// Not IP addresses at all.
- EXPECT_FALSE(platform_impl.isReservedIPAddress(GURL("http://example.com/")));
- EXPECT_FALSE(
- platform_impl.isReservedIPAddress(GURL("http://127.0.0.1.example.com/")));
+ EXPECT_FALSE(platform_impl.isReservedIPAddress("example.com"));
+ EXPECT_FALSE(platform_impl.isReservedIPAddress("127.0.0.1.example.com"));
// Moar IPv4
uint8 address[4] = {0, 0, 0, 1};
@@ -112,86 +111,25 @@ TEST(BlinkPlatformTest, IsReservedIPAddress_WebURL) {
std::string addressString =
net::IPAddressToString(address, sizeof(address));
if (i == 0 || i == 10 || i == 127 || i > 223) {
- EXPECT_TRUE(
- platform_impl.isReservedIPAddress(GURL("http://" + addressString)));
+ EXPECT_TRUE(platform_impl.isReservedIPAddress(
+ blink::WebString::fromUTF8(addressString)));
} else {
- EXPECT_FALSE(
- platform_impl.isReservedIPAddress(GURL("http://" + addressString)));
+ EXPECT_FALSE(platform_impl.isReservedIPAddress(
+ blink::WebString::fromUTF8(addressString)));
}
}
}
-TEST(BlinkPlatformTest, IsReservedIPAddress_WebSecurityOrigin) {
+TEST(BlinkPlatformTest, portAllowed) {
TestBlinkPlatformImpl platform_impl;
-
- // Unreserved IPv4 addresses (in various forms).
- EXPECT_FALSE(platform_impl.isReservedIPAddress(
- blink::WebSecurityOrigin::createFromString("http://8.8.8.8/")));
- EXPECT_FALSE(platform_impl.isReservedIPAddress(
- blink::WebSecurityOrigin::createFromString("http://99.64.0.0/")));
- EXPECT_FALSE(platform_impl.isReservedIPAddress(
- blink::WebSecurityOrigin::createFromString("http://212.15.0.0/")));
- EXPECT_FALSE(platform_impl.isReservedIPAddress(
- blink::WebSecurityOrigin::createFromString("http://212.15/")));
- EXPECT_FALSE(platform_impl.isReservedIPAddress(
- blink::WebSecurityOrigin::createFromString("http://212.15.0/")));
- EXPECT_FALSE(platform_impl.isReservedIPAddress(
- blink::WebSecurityOrigin::createFromString("http://3557752832/")));
-
- // Reserved IPv4 addresses (in various forms).
- EXPECT_TRUE(platform_impl.isReservedIPAddress(
- blink::WebSecurityOrigin::createFromString("http://192.168.0.0/")));
- EXPECT_TRUE(platform_impl.isReservedIPAddress(
- blink::WebSecurityOrigin::createFromString("http://192.168.0.6/")));
- EXPECT_TRUE(platform_impl.isReservedIPAddress(
- blink::WebSecurityOrigin::createFromString("http://10.0.0.5/")));
- EXPECT_TRUE(platform_impl.isReservedIPAddress(
- blink::WebSecurityOrigin::createFromString("http://10.0.0/")));
- EXPECT_TRUE(platform_impl.isReservedIPAddress(
- blink::WebSecurityOrigin::createFromString("http://10.0/")));
- EXPECT_TRUE(platform_impl.isReservedIPAddress(
- blink::WebSecurityOrigin::createFromString("http://3232235526/")));
-
- // Unreserved IPv6 addresses.
- EXPECT_FALSE(platform_impl.isReservedIPAddress(
- blink::WebSecurityOrigin::createFromString(
- "http://[FFC0:ba98:7654:3210:FEDC:BA98:7654:3210]/")));
- EXPECT_FALSE(platform_impl.isReservedIPAddress(
- blink::WebSecurityOrigin::createFromString(
- "http://[2000:ba98:7654:2301:EFCD:BA98:7654:3210]/")));
-
- // Reserved IPv6 addresses.
- EXPECT_TRUE(platform_impl.isReservedIPAddress(
- blink::WebSecurityOrigin::createFromString("http://[::1]/")));
- EXPECT_TRUE(platform_impl.isReservedIPAddress(
- blink::WebSecurityOrigin::createFromString("http://[::192.9.5.5]/")));
- EXPECT_TRUE(platform_impl.isReservedIPAddress(
- blink::WebSecurityOrigin::createFromString("http://[FEED::BEEF]/")));
- EXPECT_TRUE(platform_impl.isReservedIPAddress(
- blink::WebSecurityOrigin::createFromString(
- "http://[FEC0:ba98:7654:3210:FEDC:BA98:7654:3210]/")));
-
- // Not IP addresses at all.
- EXPECT_FALSE(platform_impl.isReservedIPAddress(
- blink::WebSecurityOrigin::createFromString("http://example.com/")));
- EXPECT_FALSE(platform_impl.isReservedIPAddress(
- blink::WebSecurityOrigin::createFromString(
- "http://127.0.0.1.example.com/")));
-
- // Moar IPv4
- uint8 address[4] = {0, 0, 0, 1};
- for (int i = 0; i < 256; i++) {
- address[0] = i;
- blink::WebString addressString = blink::WebString::fromUTF8(
- "http://" + net::IPAddressToString(address, sizeof(address)) + "/");
- if (i == 0 || i == 10 || i == 127 || i > 223) {
- EXPECT_TRUE(platform_impl.isReservedIPAddress(
- blink::WebSecurityOrigin::createFromString(addressString)));
- } else {
- EXPECT_FALSE(platform_impl.isReservedIPAddress(
- blink::WebSecurityOrigin::createFromString(addressString)));
- }
- }
+ EXPECT_TRUE(platform_impl.portAllowed(GURL("http://example.com")));
+ EXPECT_TRUE(platform_impl.portAllowed(GURL("file://example.com")));
+ EXPECT_TRUE(platform_impl.portAllowed(GURL("file://example.com:87")));
+ EXPECT_TRUE(platform_impl.portAllowed(GURL("ftp://example.com:21")));
+ EXPECT_FALSE(platform_impl.portAllowed(GURL("ftp://example.com:87")));
+ EXPECT_FALSE(platform_impl.portAllowed(GURL("ws://example.com:21")));
+ EXPECT_TRUE(platform_impl.portAllowed(GURL("http://example.com:80")));
+ EXPECT_TRUE(platform_impl.portAllowed(GURL("http://example.com:8889")));
}
} // namespace content
diff --git a/chromium/content/child/bluetooth/OWNERS b/chromium/content/child/bluetooth/OWNERS
new file mode 100644
index 00000000000..673aeda7145
--- /dev/null
+++ b/chromium/content/child/bluetooth/OWNERS
@@ -0,0 +1 @@
+scheib@chromium.org
diff --git a/chromium/content/child/bluetooth/PRESUBMIT.py b/chromium/content/child/bluetooth/PRESUBMIT.py
new file mode 100644
index 00000000000..3f9babedbd6
--- /dev/null
+++ b/chromium/content/child/bluetooth/PRESUBMIT.py
@@ -0,0 +1,14 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Presubmit script.
+
+See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
+for more details about the presubmit API built into depot_tools.
+"""
+
+def CheckChangeOnUpload(input_api, output_api):
+ results = []
+ results += input_api.canned_checks.CheckPatchFormatted(input_api, output_api)
+ return results
diff --git a/chromium/content/child/bluetooth/bluetooth_dispatcher.cc b/chromium/content/child/bluetooth/bluetooth_dispatcher.cc
new file mode 100644
index 00000000000..47d2531cc16
--- /dev/null
+++ b/chromium/content/child/bluetooth/bluetooth_dispatcher.cc
@@ -0,0 +1,172 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/child/bluetooth/bluetooth_dispatcher.h"
+
+#include "base/lazy_instance.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/thread_task_runner_handle.h"
+#include "content/child/thread_safe_sender.h"
+#include "content/common/bluetooth/bluetooth_messages.h"
+#include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothDevice.h"
+#include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothError.h"
+#include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothGATTRemoteServer.h"
+
+using blink::WebBluetoothConnectGATTCallbacks;
+using blink::WebBluetoothDevice;
+using blink::WebBluetoothError;
+using blink::WebBluetoothGATTRemoteServer;
+using blink::WebBluetoothRequestDeviceCallbacks;
+using blink::WebString;
+using blink::WebVector;
+
+namespace content {
+
+namespace {
+
+base::LazyInstance<base::ThreadLocalPointer<BluetoothDispatcher>>::Leaky
+ g_dispatcher_tls = LAZY_INSTANCE_INITIALIZER;
+
+BluetoothDispatcher* const kHasBeenDeleted =
+ reinterpret_cast<BluetoothDispatcher*>(0x1);
+
+int CurrentWorkerId() {
+ return WorkerTaskRunner::Instance()->CurrentWorkerId();
+}
+
+WebBluetoothError::ErrorType WebBluetoothErrorFromBluetoothError(
+ BluetoothError error_type) {
+ switch (error_type) {
+ case BluetoothError::NETWORK_ERROR:
+ return WebBluetoothError::NetworkError;
+ case BluetoothError::NOT_FOUND:
+ return WebBluetoothError::NotFoundError;
+ case BluetoothError::SECURITY:
+ return WebBluetoothError::SecurityError;
+ }
+ NOTIMPLEMENTED();
+ return WebBluetoothError::NotFoundError;
+}
+
+WebBluetoothDevice::VendorIDSource GetWebVendorIdSource(
+ device::BluetoothDevice::VendorIDSource vendor_id_source) {
+ switch (vendor_id_source) {
+ case device::BluetoothDevice::VENDOR_ID_UNKNOWN:
+ return WebBluetoothDevice::VendorIDSource::Unknown;
+ case device::BluetoothDevice::VENDOR_ID_BLUETOOTH:
+ return WebBluetoothDevice::VendorIDSource::Bluetooth;
+ case device::BluetoothDevice::VENDOR_ID_USB:
+ return WebBluetoothDevice::VendorIDSource::USB;
+ }
+ NOTREACHED();
+ return WebBluetoothDevice::VendorIDSource::Unknown;
+}
+
+} // namespace
+
+BluetoothDispatcher::BluetoothDispatcher(ThreadSafeSender* sender)
+ : thread_safe_sender_(sender) {
+ g_dispatcher_tls.Pointer()->Set(this);
+}
+
+BluetoothDispatcher::~BluetoothDispatcher() {
+ g_dispatcher_tls.Pointer()->Set(kHasBeenDeleted);
+}
+
+BluetoothDispatcher* BluetoothDispatcher::GetOrCreateThreadSpecificInstance(
+ ThreadSafeSender* thread_safe_sender) {
+ if (g_dispatcher_tls.Pointer()->Get() == kHasBeenDeleted) {
+ NOTREACHED() << "Re-instantiating TLS BluetoothDispatcher.";
+ g_dispatcher_tls.Pointer()->Set(NULL);
+ }
+ if (g_dispatcher_tls.Pointer()->Get())
+ return g_dispatcher_tls.Pointer()->Get();
+
+ BluetoothDispatcher* dispatcher = new BluetoothDispatcher(thread_safe_sender);
+ if (CurrentWorkerId())
+ WorkerTaskRunner::Instance()->AddStopObserver(dispatcher);
+ return dispatcher;
+}
+
+bool BluetoothDispatcher::Send(IPC::Message* msg) {
+ return thread_safe_sender_->Send(msg);
+}
+
+void BluetoothDispatcher::OnMessageReceived(const IPC::Message& msg) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(BluetoothDispatcher, msg)
+ IPC_MESSAGE_HANDLER(BluetoothMsg_RequestDeviceSuccess,
+ OnRequestDeviceSuccess);
+ IPC_MESSAGE_HANDLER(BluetoothMsg_RequestDeviceError, OnRequestDeviceError);
+ IPC_MESSAGE_HANDLER(BluetoothMsg_ConnectGATTSuccess, OnConnectGATTSuccess);
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ DCHECK(handled) << "Unhandled message:" << msg.type();
+}
+
+void BluetoothDispatcher::requestDevice(
+ blink::WebBluetoothRequestDeviceCallbacks* callbacks) {
+ int request_id = pending_requests_.Add(callbacks);
+ Send(new BluetoothHostMsg_RequestDevice(CurrentWorkerId(), request_id));
+}
+
+void BluetoothDispatcher::connectGATT(
+ const blink::WebString& device_instance_id,
+ blink::WebBluetoothConnectGATTCallbacks* callbacks) {
+ int request_id = pending_connect_requests_.Add(callbacks);
+ Send(new BluetoothHostMsg_ConnectGATT(CurrentWorkerId(), request_id,
+ device_instance_id.utf8()));
+}
+
+void BluetoothDispatcher::SetBluetoothMockDataSetForTesting(
+ const std::string& name) {
+ Send(new BluetoothHostMsg_SetBluetoothMockDataSetForTesting(name));
+}
+
+void BluetoothDispatcher::OnWorkerRunLoopStopped() {
+ delete this;
+}
+
+void BluetoothDispatcher::OnRequestDeviceSuccess(
+ int thread_id,
+ int request_id,
+ const BluetoothDevice& device) {
+ DCHECK(pending_requests_.Lookup(request_id)) << request_id;
+
+ WebVector<WebString> uuids(device.uuids.size());
+ for (size_t i = 0; i < device.uuids.size(); ++i)
+ uuids[i] = WebString::fromUTF8(device.uuids[i].c_str());
+
+ pending_requests_.Lookup(request_id)
+ ->onSuccess(new WebBluetoothDevice(
+ WebString::fromUTF8(device.instance_id), WebString(device.name),
+ device.device_class, GetWebVendorIdSource(device.vendor_id_source),
+ device.vendor_id, device.product_id, device.product_version,
+ device.paired, uuids));
+ pending_requests_.Remove(request_id);
+}
+
+void BluetoothDispatcher::OnConnectGATTSuccess(
+ int thread_id,
+ int request_id,
+ const std::string& device_instance_id) {
+ DCHECK(pending_connect_requests_.Lookup(request_id)) << request_id;
+ pending_connect_requests_.Lookup(request_id)
+ ->onSuccess(new WebBluetoothGATTRemoteServer(
+ WebString::fromUTF8(device_instance_id), true /* connected */));
+ pending_connect_requests_.Remove(request_id);
+}
+
+void BluetoothDispatcher::OnRequestDeviceError(int thread_id,
+ int request_id,
+ BluetoothError error_type) {
+ DCHECK(pending_requests_.Lookup(request_id)) << request_id;
+ pending_requests_.Lookup(request_id)
+ ->onError(new WebBluetoothError(
+ WebBluetoothErrorFromBluetoothError(error_type), ""));
+ pending_requests_.Remove(request_id);
+}
+
+} // namespace content
diff --git a/chromium/content/child/bluetooth/bluetooth_dispatcher.h b/chromium/content/child/bluetooth/bluetooth_dispatcher.h
new file mode 100644
index 00000000000..86057d8ad87
--- /dev/null
+++ b/chromium/content/child/bluetooth/bluetooth_dispatcher.h
@@ -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.
+
+#ifndef CONTENT_CHILD_BLUETOOTH_BLUETOOTH_DISPATCHER_H_
+#define CONTENT_CHILD_BLUETOOTH_BLUETOOTH_DISPATCHER_H_
+
+#include "base/id_map.h"
+#include "base/memory/ref_counted.h"
+#include "content/child/worker_task_runner.h"
+#include "content/common/bluetooth/bluetooth_device.h"
+#include "content/common/bluetooth/bluetooth_error.h"
+#include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetooth.h"
+
+namespace base {
+class MessageLoop;
+class TaskRunner;
+}
+
+namespace IPC {
+class Message;
+}
+
+namespace content {
+class ThreadSafeSender;
+
+// Dispatcher for child process threads which communicates to the browser's
+// BluetoothDispatcherHost.
+//
+// Instances are created for each thread as necessary by WebBluetoothImpl.
+//
+// Incoming IPC messages are received by the BluetoothMessageFilter and
+// directed to the thread specific instance of this class.
+// Outgoing messages come from WebBluetoothImpl.
+class BluetoothDispatcher : public WorkerTaskRunner::Observer {
+ public:
+ explicit BluetoothDispatcher(ThreadSafeSender* sender);
+ ~BluetoothDispatcher() override;
+
+ // Gets or Creates a BluetoothDispatcher for the current thread.
+ // |thread_safe_sender| is required when constructing a BluetoothDispatcher.
+ static BluetoothDispatcher* GetOrCreateThreadSpecificInstance(
+ ThreadSafeSender* thread_safe_sender);
+
+ // IPC Send and Receiving interface, see IPC::Sender and IPC::Listener.
+ bool Send(IPC::Message* msg);
+ void OnMessageReceived(const IPC::Message& msg);
+
+ // Corresponding to WebBluetoothImpl methods.
+ void requestDevice(blink::WebBluetoothRequestDeviceCallbacks* callbacks);
+ void connectGATT(const blink::WebString& device_instance_id,
+ blink::WebBluetoothConnectGATTCallbacks* callbacks);
+ void SetBluetoothMockDataSetForTesting(const std::string& name);
+
+ // WorkerTaskRunner::Observer implementation.
+ void OnWorkerRunLoopStopped() override;
+
+ private:
+ // IPC Handlers, see definitions in bluetooth_messages.h.
+ void OnRequestDeviceSuccess(int thread_id,
+ int request_id,
+ const BluetoothDevice& device);
+ void OnRequestDeviceError(int thread_id,
+ int request_id,
+ BluetoothError error_type);
+
+ void OnConnectGATTSuccess(int thread_id,
+ int request_id,
+ const std::string& message);
+
+ scoped_refptr<ThreadSafeSender> thread_safe_sender_;
+
+ // Tracks device requests sent to browser to match replies with callbacks.
+ // Owns callback objects.
+ IDMap<blink::WebBluetoothRequestDeviceCallbacks, IDMapOwnPointer>
+ pending_requests_;
+ // Tracks requests to connect to a device.
+ // Owns callback objects.
+ IDMap<blink::WebBluetoothConnectGATTCallbacks, IDMapOwnPointer>
+ pending_connect_requests_;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothDispatcher);
+};
+
+} // namespace content
+
+#endif // CONTENT_CHILD_BLUETOOTH_BLUETOOTH_DISPATCHER_H_
diff --git a/chromium/content/child/bluetooth/bluetooth_message_filter.cc b/chromium/content/child/bluetooth/bluetooth_message_filter.cc
new file mode 100644
index 00000000000..554e3c30711
--- /dev/null
+++ b/chromium/content/child/bluetooth/bluetooth_message_filter.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/child/bluetooth/bluetooth_message_filter.h"
+
+#include "content/child/bluetooth/bluetooth_dispatcher.h"
+#include "content/child/thread_safe_sender.h"
+#include "ipc/ipc_message_macros.h"
+
+namespace content {
+
+BluetoothMessageFilter::BluetoothMessageFilter(ThreadSafeSender* sender)
+ : WorkerThreadMessageFilter(sender) {
+}
+
+BluetoothMessageFilter::~BluetoothMessageFilter() {
+}
+
+bool BluetoothMessageFilter::ShouldHandleMessage(
+ const IPC::Message& msg) const {
+ return IPC_MESSAGE_CLASS(msg) == BluetoothMsgStart;
+}
+
+void BluetoothMessageFilter::OnFilteredMessageReceived(
+ const IPC::Message& msg) {
+ BluetoothDispatcher::GetOrCreateThreadSpecificInstance(thread_safe_sender())
+ ->OnMessageReceived(msg);
+}
+
+bool BluetoothMessageFilter::GetWorkerThreadIdForMessage(
+ const IPC::Message& msg,
+ int* ipc_thread_id) {
+ return PickleIterator(msg).ReadInt(ipc_thread_id);
+}
+
+} // namespace content
diff --git a/chromium/content/child/bluetooth/bluetooth_message_filter.h b/chromium/content/child/bluetooth/bluetooth_message_filter.h
new file mode 100644
index 00000000000..5692dcce095
--- /dev/null
+++ b/chromium/content/child/bluetooth/bluetooth_message_filter.h
@@ -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.
+
+#ifndef CONTENT_CHILD_BLUETOOTH_BLUETOOTH_MESSAGE_FILTER_H_
+#define CONTENT_CHILD_BLUETOOTH_BLUETOOTH_MESSAGE_FILTER_H_
+
+#include "content/child/worker_thread_message_filter.h"
+
+namespace content {
+
+class BluetoothMessageFilter : public WorkerThreadMessageFilter {
+ public:
+ explicit BluetoothMessageFilter(ThreadSafeSender* thread_safe_sender);
+
+ private:
+ ~BluetoothMessageFilter() override;
+
+ // WorkerThreadMessageFilter:
+ bool ShouldHandleMessage(const IPC::Message& msg) const override;
+ void OnFilteredMessageReceived(const IPC::Message& msg) override;
+ bool GetWorkerThreadIdForMessage(const IPC::Message& msg,
+ int* ipc_thread_id) override;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothMessageFilter);
+};
+
+} // namespace content
+
+#endif // CONTENT_CHILD_BLUETOOTH_BLUETOOTH_MESSAGE_FILTER_H_
diff --git a/chromium/content/child/bluetooth/web_bluetooth_impl.cc b/chromium/content/child/bluetooth/web_bluetooth_impl.cc
index 406ae7d3a59..d8b5813be6d 100644
--- a/chromium/content/child/bluetooth/web_bluetooth_impl.cc
+++ b/chromium/content/child/bluetooth/web_bluetooth_impl.cc
@@ -4,53 +4,36 @@
#include "content/child/bluetooth/web_bluetooth_impl.h"
+#include "content/child/bluetooth/bluetooth_dispatcher.h"
+#include "content/child/thread_safe_sender.h"
+
namespace content {
-WebBluetoothImpl::WebBluetoothImpl()
- : m_bluetoothMockDataSet(MockData::NOT_MOCKING),
- m_bluetoothRequestDeviceRejectType(
- blink::WebBluetoothError::NotFoundError) {
+WebBluetoothImpl::WebBluetoothImpl(ThreadSafeSender* thread_safe_sender)
+ : thread_safe_sender_(thread_safe_sender) {
+}
+
+WebBluetoothImpl::~WebBluetoothImpl() {
}
void WebBluetoothImpl::requestDevice(
blink::WebBluetoothRequestDeviceCallbacks* callbacks) {
- // Mock implementation of blink::WebBluetooth until a more complete
- // implementation is built out.
- switch (m_bluetoothMockDataSet) {
- case MockData::NOT_MOCKING: {
- blink::WebBluetoothError* error = new blink::WebBluetoothError(
- blink::WebBluetoothError::NotFoundError, "");
- callbacks->onError(error);
- break;
- }
- case MockData::REJECT: {
- blink::WebBluetoothError* error =
- new blink::WebBluetoothError(m_bluetoothRequestDeviceRejectType, "");
- callbacks->onError(error);
- break;
- }
- case MockData::RESOLVE: {
- callbacks->onSuccess();
- break;
- }
- }
+ GetDispatcher()->requestDevice(callbacks);
+}
+
+void WebBluetoothImpl::connectGATT(const blink::WebString& device_instance_id,
+ blink::WebBluetoothConnectGATTCallbacks* callbacks) {
+ GetDispatcher()->connectGATT(device_instance_id, callbacks);
}
void WebBluetoothImpl::SetBluetoothMockDataSetForTesting(
const std::string& name) {
- if (name == "RejectRequestDevice_NotFoundError") {
- m_bluetoothMockDataSet = MockData::REJECT;
- m_bluetoothRequestDeviceRejectType =
- blink::WebBluetoothError::NotFoundError;
- } else if (name == "RejectRequestDevice_SecurityError") {
- m_bluetoothMockDataSet = MockData::REJECT;
- m_bluetoothRequestDeviceRejectType =
- blink::WebBluetoothError::SecurityError;
- } else if (name == "ResolveRequestDevice_Empty") {
- m_bluetoothMockDataSet = MockData::RESOLVE;
- } else {
- m_bluetoothMockDataSet = MockData::NOT_MOCKING;
- }
+ GetDispatcher()->SetBluetoothMockDataSetForTesting(name);
+}
+
+BluetoothDispatcher* WebBluetoothImpl::GetDispatcher() {
+ return BluetoothDispatcher::GetOrCreateThreadSpecificInstance(
+ thread_safe_sender_.get());
}
} // namespace content
diff --git a/chromium/content/child/bluetooth/web_bluetooth_impl.h b/chromium/content/child/bluetooth/web_bluetooth_impl.h
index e338cc5cf05..11403c08802 100644
--- a/chromium/content/child/bluetooth/web_bluetooth_impl.h
+++ b/chromium/content/child/bluetooth/web_bluetooth_impl.h
@@ -5,29 +5,42 @@
#ifndef CONTENT_CHILD_BLUETOOTH_WEB_BLUETOOTH_IMPL_H_
#define CONTENT_CHILD_BLUETOOTH_WEB_BLUETOOTH_IMPL_H_
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
#include "content/common/content_export.h"
-#include "third_party/WebKit/public/platform/WebBluetooth.h"
-#include "third_party/WebKit/public/platform/WebBluetoothError.h"
+#include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetooth.h"
namespace content {
-// Mock implementation of blink::WebBluetooth until a more complete
-// implementation is built out.
+class BluetoothDispatcher;
+class ThreadSafeSender;
+
+// Implementation of blink::WebBluetooth. Passes calls through to the thread
+// specific BluetoothDispatcher.
class CONTENT_EXPORT WebBluetoothImpl
: NON_EXPORTED_BASE(public blink::WebBluetooth) {
public:
- WebBluetoothImpl();
+ explicit WebBluetoothImpl(ThreadSafeSender* thread_safe_sender);
+ ~WebBluetoothImpl();
+
+ // blink::WebBluetooth interface:
+ void requestDevice(
+ blink::WebBluetoothRequestDeviceCallbacks* callbacks) override;
- // WebBluetooth interface:
- void requestDevice(blink::WebBluetoothRequestDeviceCallbacks*) override;
+ void connectGATT(const blink::WebString& device_instance_id,
+ blink::WebBluetoothConnectGATTCallbacks* callbacks) override;
// Testing interface:
void SetBluetoothMockDataSetForTesting(const std::string& name);
private:
- enum class MockData { NOT_MOCKING, REJECT, RESOLVE };
- MockData m_bluetoothMockDataSet;
- blink::WebBluetoothError::ErrorType m_bluetoothRequestDeviceRejectType;
+ BluetoothDispatcher* GetDispatcher();
+
+ scoped_refptr<ThreadSafeSender> thread_safe_sender_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebBluetoothImpl);
};
} // namespace content
diff --git a/chromium/content/child/browser_font_resource_trusted.cc b/chromium/content/child/browser_font_resource_trusted.cc
index 37e428304b5..b75c79d4ea1 100644
--- a/chromium/content/child/browser_font_resource_trusted.cc
+++ b/chromium/content/child/browser_font_resource_trusted.cc
@@ -135,7 +135,7 @@ bool PPTextRunToWebTextRun(const PP_BrowserFont_Trusted_TextRun& text,
// The PP_* version lacks "None", so is just one value shifted from the
// WebFontDescription version. These values are checked in
// PPFontDescToWebFontDesc to make sure the conversion is correct. This is a
-// macro so it can also be used in the COMPILE_ASSERTS.
+// macro so it can also be used in the static_asserts.
#define PP_FAMILY_TO_WEB_FAMILY(f) \
static_cast<WebFontDescription::GenericFamily>(f + 1)
@@ -144,24 +144,24 @@ WebFontDescription PPFontDescToWebFontDesc(
const PP_BrowserFont_Trusted_Description& font,
const ppapi::Preferences& prefs) {
// Verify that the enums match so we can just static cast.
- COMPILE_ASSERT(static_cast<int>(WebFontDescription::Weight100) ==
- static_cast<int>(PP_BROWSERFONT_TRUSTED_WEIGHT_100),
- FontWeight100);
- COMPILE_ASSERT(static_cast<int>(WebFontDescription::Weight900) ==
- static_cast<int>(PP_BROWSERFONT_TRUSTED_WEIGHT_900),
- FontWeight900);
- COMPILE_ASSERT(WebFontDescription::GenericFamilyStandard ==
- PP_FAMILY_TO_WEB_FAMILY(PP_FONTFAMILY_DEFAULT),
- StandardFamily);
- COMPILE_ASSERT(WebFontDescription::GenericFamilySerif ==
- PP_FAMILY_TO_WEB_FAMILY(PP_FONTFAMILY_SERIF),
- SerifFamily);
- COMPILE_ASSERT(WebFontDescription::GenericFamilySansSerif ==
- PP_FAMILY_TO_WEB_FAMILY(PP_FONTFAMILY_SANSSERIF),
- SansSerifFamily);
- COMPILE_ASSERT(WebFontDescription::GenericFamilyMonospace ==
- PP_FAMILY_TO_WEB_FAMILY(PP_FONTFAMILY_MONOSPACE),
- MonospaceFamily);
+ static_assert(static_cast<int>(WebFontDescription::Weight100) ==
+ static_cast<int>(PP_BROWSERFONT_TRUSTED_WEIGHT_100),
+ "font Weight100");
+ static_assert(static_cast<int>(WebFontDescription::Weight900) ==
+ static_cast<int>(PP_BROWSERFONT_TRUSTED_WEIGHT_900),
+ "font Weight900");
+ static_assert(WebFontDescription::GenericFamilyStandard ==
+ PP_FAMILY_TO_WEB_FAMILY(PP_FONTFAMILY_DEFAULT),
+ "FamilyStandard");
+ static_assert(WebFontDescription::GenericFamilySerif ==
+ PP_FAMILY_TO_WEB_FAMILY(PP_FONTFAMILY_SERIF),
+ "FamilySerif");
+ static_assert(WebFontDescription::GenericFamilySansSerif ==
+ PP_FAMILY_TO_WEB_FAMILY(PP_FONTFAMILY_SANSSERIF),
+ "FamilySansSerif");
+ static_assert(WebFontDescription::GenericFamilyMonospace ==
+ PP_FAMILY_TO_WEB_FAMILY(PP_FONTFAMILY_MONOSPACE),
+ "FamilyMonospace");
StringVar* face_name = StringVar::FromPPVar(font.face); // Possibly null.
@@ -319,7 +319,28 @@ PP_Bool BrowserFontResource_Trusted::DrawTextAt(
return result; // Failure mapping.
}
- DrawTextToCanvas(canvas, *text, position, color, clip, image_data_is_opaque);
+ if (!PP_ToBool(image_data_is_opaque)) {
+ // Ideally, LCD text should be configured at canvas creation time using
+ // SkSurfaceProps. But because the API exposes image_data_is_opaque per
+ // draw text call (allowing clients to essentially change their mind),
+ // we have to handle it here.
+ SkImageInfo info;
+ size_t row_bytes;
+ void* pixels = canvas->accessTopLayerPixels(&info, &row_bytes);
+ if (!pixels)
+ return result;
+
+ SkBitmap bm;
+ if (!bm.installPixels(info, pixels, row_bytes))
+ return result;
+
+ SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
+ SkCanvas temp_canvas(bm, props);
+
+ DrawTextToCanvas(&temp_canvas, *text, position, color, clip);
+ } else {
+ DrawTextToCanvas(canvas, *text, position, color, clip);
+ }
if (needs_unmapping)
image->Unmap();
@@ -391,8 +412,7 @@ void BrowserFontResource_Trusted::DrawTextToCanvas(
const PP_BrowserFont_Trusted_TextRun& text,
const PP_Point* position,
uint32_t color,
- const PP_Rect* clip,
- PP_Bool image_data_is_opaque) {
+ const PP_Rect* clip) {
// Convert position and clip.
WebFloatPoint web_position(static_cast<float>(position->x),
static_cast<float>(position->y));
@@ -414,8 +434,7 @@ void BrowserFontResource_Trusted::DrawTextToCanvas(
int32_t run_begin = 0;
int32_t run_len = 0;
WebTextRun run = runs.GetRunAt(i, &run_begin, &run_len);
- font_->drawText(destination, run, web_position, color, web_clip,
- PP_ToBool(image_data_is_opaque));
+ font_->drawText(destination, run, web_position, color, web_clip);
// Advance to the next run. Note that we avoid doing this for the last run
// since it's unnecessary, measuring text is slow, and most of the time
diff --git a/chromium/content/child/browser_font_resource_trusted.h b/chromium/content/child/browser_font_resource_trusted.h
index f29e51fa1a5..1a83732c0ca 100644
--- a/chromium/content/child/browser_font_resource_trusted.h
+++ b/chromium/content/child/browser_font_resource_trusted.h
@@ -65,8 +65,7 @@ class BrowserFontResource_Trusted
const PP_BrowserFont_Trusted_TextRun& text,
const PP_Point* position,
uint32_t color,
- const PP_Rect* clip,
- PP_Bool image_data_is_opaque);
+ const PP_Rect* clip);
private:
scoped_ptr<blink::WebFont> font_;
diff --git a/chromium/content/child/child.gni b/chromium/content/child/child.gni
index a2ff699ea42..f619e22e250 100644
--- a/chromium/content/child/child.gni
+++ b/chromium/content/child/child.gni
@@ -6,10 +6,11 @@
# cached, which is a performance optimization that allows us to share the
# results of parsing the .gypi file between the public and private BUILD.gn
# files. It also saves us from duplicating this exec_script call.
-content_child_gypi_values = exec_script(
- "//build/gypi_to_gn.py",
- [ rebase_path("../content_child.gypi"),
- "--replace=<(SHARED_INTERMEDIATE_DIR)=$root_gen_dir" ],
- "scope",
- [ "../content_child.gypi" ])
-
+content_child_gypi_values =
+ exec_script("//build/gypi_to_gn.py",
+ [
+ rebase_path("../content_child.gypi"),
+ "--replace=<(SHARED_INTERMEDIATE_DIR)=$root_gen_dir",
+ ],
+ "scope",
+ [ "../content_child.gypi" ])
diff --git a/chromium/content/child/child_discardable_shared_memory_manager.cc b/chromium/content/child/child_discardable_shared_memory_manager.cc
index 606ca6ceb06..7c0f4d6201d 100644
--- a/chromium/content/child/child_discardable_shared_memory_manager.cc
+++ b/chromium/content/child/child_discardable_shared_memory_manager.cc
@@ -4,37 +4,295 @@
#include "content/child/child_discardable_shared_memory_manager.h"
+#include "base/atomic_sequence_num.h"
+#include "base/bind.h"
+#include "base/debug/crash_logging.h"
+#include "base/memory/discardable_memory.h"
#include "base/memory/discardable_shared_memory.h"
-#include "content/child/child_thread.h"
+#include "base/metrics/histogram.h"
+#include "base/process/memory.h"
+#include "base/process/process_metrics.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/trace_event/memory_dump_manager.h"
+#include "base/trace_event/trace_event.h"
#include "content/common/child_process_messages.h"
namespace content {
+namespace {
+
+// Default allocation size.
+const size_t kAllocationSize = 4 * 1024 * 1024;
+
+// Global atomic to generate unique discardable shared memory IDs.
+base::StaticAtomicSequenceNumber g_next_discardable_shared_memory_id;
+
+class DiscardableMemoryImpl : public base::DiscardableMemory {
+ public:
+ DiscardableMemoryImpl(ChildDiscardableSharedMemoryManager* manager,
+ scoped_ptr<DiscardableSharedMemoryHeap::Span> span)
+ : manager_(manager), span_(span.Pass()), is_locked_(true) {}
+
+ ~DiscardableMemoryImpl() override {
+ if (is_locked_)
+ manager_->UnlockSpan(span_.get());
+
+ manager_->ReleaseSpan(span_.Pass());
+ }
+
+ // Overridden from base::DiscardableMemory:
+ bool Lock() override {
+ DCHECK(!is_locked_);
+
+ if (!manager_->LockSpan(span_.get()))
+ return false;
+
+ is_locked_ = true;
+ return true;
+ }
+ void Unlock() override {
+ DCHECK(is_locked_);
+
+ manager_->UnlockSpan(span_.get());
+ is_locked_ = false;
+ }
+ void* data() const override {
+ DCHECK(is_locked_);
+ return reinterpret_cast<void*>(span_->start() * base::GetPageSize());
+ }
+
+ private:
+ ChildDiscardableSharedMemoryManager* const manager_;
+ scoped_ptr<DiscardableSharedMemoryHeap::Span> span_;
+ bool is_locked_;
+
+ DISALLOW_COPY_AND_ASSIGN(DiscardableMemoryImpl);
+};
+
+void SendDeletedDiscardableSharedMemoryMessage(
+ scoped_refptr<ThreadSafeSender> sender,
+ DiscardableSharedMemoryId id) {
+ sender->Send(new ChildProcessHostMsg_DeletedDiscardableSharedMemory(id));
+}
+
+} // namespace
ChildDiscardableSharedMemoryManager::ChildDiscardableSharedMemoryManager(
ThreadSafeSender* sender)
- : sender_(sender) {
+ : heap_(base::GetPageSize()), sender_(sender) {
+ base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
+ this, base::ThreadTaskRunnerHandle::Get());
}
ChildDiscardableSharedMemoryManager::~ChildDiscardableSharedMemoryManager() {
+ base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
+ this);
+ // TODO(reveman): Determine if this DCHECK can be enabled. crbug.com/430533
+ // DCHECK_EQ(heap_.GetSize(), heap_.GetSizeOfFreeLists());
+ if (heap_.GetSize())
+ MemoryUsageChanged(0, 0);
+}
+
+scoped_ptr<base::DiscardableMemory>
+ChildDiscardableSharedMemoryManager::AllocateLockedDiscardableMemory(
+ size_t size) {
+ base::AutoLock lock(lock_);
+
+ DCHECK_NE(size, 0u);
+
+ UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.DiscardableAllocationSize",
+ size / 1024, // In KB
+ 1,
+ 4 * 1024 * 1024, // 4 GB
+ 50);
+
+ // Round up to multiple of page size.
+ size_t pages = (size + base::GetPageSize() - 1) / base::GetPageSize();
+
+ // Default allocation size in pages.
+ size_t allocation_pages = kAllocationSize / base::GetPageSize();
+
+ size_t slack = 0;
+ // When searching the free lists, allow a slack between required size and
+ // free span size that is less or equal to kAllocationSize. This is to
+ // avoid segments larger then kAllocationSize unless they are a perfect
+ // fit. The result is that large allocations can be reused without reducing
+ // the ability to discard memory.
+ if (pages < allocation_pages)
+ slack = allocation_pages - pages;
+
+ size_t heap_size_prior_to_releasing_purged_memory = heap_.GetSize();
+ for (;;) {
+ // Search free lists for suitable span.
+ scoped_ptr<DiscardableSharedMemoryHeap::Span> free_span =
+ heap_.SearchFreeLists(pages, slack);
+ if (!free_span.get())
+ break;
+
+ // Attempt to lock |free_span|. Delete span and search free lists again
+ // if locking failed.
+ if (free_span->shared_memory()->Lock(
+ free_span->start() * base::GetPageSize() -
+ reinterpret_cast<size_t>(free_span->shared_memory()->memory()),
+ free_span->length() * base::GetPageSize()) ==
+ base::DiscardableSharedMemory::FAILED) {
+ DCHECK(!free_span->shared_memory()->IsMemoryResident());
+ // We have to release purged memory before |free_span| can be destroyed.
+ heap_.ReleasePurgedMemory();
+ DCHECK(!free_span->shared_memory());
+ continue;
+ }
+
+ // Memory usage is guaranteed to have changed after having removed
+ // at least one span from the free lists.
+ MemoryUsageChanged(heap_.GetSize(), heap_.GetSizeOfFreeLists());
+
+ return make_scoped_ptr(new DiscardableMemoryImpl(this, free_span.Pass()));
+ }
+
+ // Release purged memory to free up the address space before we attempt to
+ // allocate more memory.
+ heap_.ReleasePurgedMemory();
+
+ // Make sure crash keys are up to date in case allocation fails.
+ if (heap_.GetSize() != heap_size_prior_to_releasing_purged_memory)
+ MemoryUsageChanged(heap_.GetSize(), heap_.GetSizeOfFreeLists());
+
+ size_t pages_to_allocate =
+ std::max(kAllocationSize / base::GetPageSize(), pages);
+ size_t allocation_size_in_bytes = pages_to_allocate * base::GetPageSize();
+
+ DiscardableSharedMemoryId new_id =
+ g_next_discardable_shared_memory_id.GetNext();
+
+ // Ask parent process to allocate a new discardable shared memory segment.
+ scoped_ptr<base::DiscardableSharedMemory> shared_memory(
+ AllocateLockedDiscardableSharedMemory(allocation_size_in_bytes, new_id));
+
+ // Create span for allocated memory.
+ scoped_ptr<DiscardableSharedMemoryHeap::Span> new_span(heap_.Grow(
+ shared_memory.Pass(), allocation_size_in_bytes, new_id,
+ base::Bind(&SendDeletedDiscardableSharedMemoryMessage, sender_, new_id)));
+
+ // Unlock and insert any left over memory into free lists.
+ if (pages < pages_to_allocate) {
+ scoped_ptr<DiscardableSharedMemoryHeap::Span> leftover =
+ heap_.Split(new_span.get(), pages);
+ leftover->shared_memory()->Unlock(
+ leftover->start() * base::GetPageSize() -
+ reinterpret_cast<size_t>(leftover->shared_memory()->memory()),
+ leftover->length() * base::GetPageSize());
+ heap_.MergeIntoFreeLists(leftover.Pass());
+ }
+
+ MemoryUsageChanged(heap_.GetSize(), heap_.GetSizeOfFreeLists());
+
+ return make_scoped_ptr(new DiscardableMemoryImpl(this, new_span.Pass()));
+}
+
+bool ChildDiscardableSharedMemoryManager::OnMemoryDump(
+ base::trace_event::ProcessMemoryDump* pmd) {
+ return heap_.OnMemoryDump(pmd);
+}
+
+void ChildDiscardableSharedMemoryManager::ReleaseFreeMemory() {
+ base::AutoLock lock(lock_);
+
+ size_t heap_size_prior_to_releasing_memory = heap_.GetSize();
+
+ // Release both purged and free memory.
+ heap_.ReleasePurgedMemory();
+ heap_.ReleaseFreeMemory();
+
+ if (heap_.GetSize() != heap_size_prior_to_releasing_memory)
+ MemoryUsageChanged(heap_.GetSize(), heap_.GetSizeOfFreeLists());
+}
+
+bool ChildDiscardableSharedMemoryManager::LockSpan(
+ DiscardableSharedMemoryHeap::Span* span) {
+ base::AutoLock lock(lock_);
+
+ if (!span->shared_memory())
+ return false;
+
+ size_t offset = span->start() * base::GetPageSize() -
+ reinterpret_cast<size_t>(span->shared_memory()->memory());
+ size_t length = span->length() * base::GetPageSize();
+
+ switch (span->shared_memory()->Lock(offset, length)) {
+ case base::DiscardableSharedMemory::SUCCESS:
+ return true;
+ case base::DiscardableSharedMemory::PURGED:
+ span->shared_memory()->Unlock(offset, length);
+ return false;
+ case base::DiscardableSharedMemory::FAILED:
+ return false;
+ }
+
+ NOTREACHED();
+ return false;
+}
+
+void ChildDiscardableSharedMemoryManager::UnlockSpan(
+ DiscardableSharedMemoryHeap::Span* span) {
+ base::AutoLock lock(lock_);
+
+ DCHECK(span->shared_memory());
+ size_t offset = span->start() * base::GetPageSize() -
+ reinterpret_cast<size_t>(span->shared_memory()->memory());
+ size_t length = span->length() * base::GetPageSize();
+
+ return span->shared_memory()->Unlock(offset, length);
+}
+
+void ChildDiscardableSharedMemoryManager::ReleaseSpan(
+ scoped_ptr<DiscardableSharedMemoryHeap::Span> span) {
+ base::AutoLock lock(lock_);
+
+ // Delete span instead of merging it into free lists if memory is gone.
+ if (!span->shared_memory())
+ return;
+
+ heap_.MergeIntoFreeLists(span.Pass());
+
+ // Bytes of free memory changed.
+ MemoryUsageChanged(heap_.GetSize(), heap_.GetSizeOfFreeLists());
}
scoped_ptr<base::DiscardableSharedMemory>
ChildDiscardableSharedMemoryManager::AllocateLockedDiscardableSharedMemory(
- size_t size) {
- TRACE_EVENT1("renderer",
+ size_t size,
+ DiscardableSharedMemoryId id) {
+ TRACE_EVENT2("renderer",
"ChildDiscardableSharedMemoryManager::"
"AllocateLockedDiscardableSharedMemory",
- "size",
- size);
+ "size", size, "id", id);
base::SharedMemoryHandle handle = base::SharedMemory::NULLHandle();
sender_->Send(
new ChildProcessHostMsg_SyncAllocateLockedDiscardableSharedMemory(
- size, &handle));
+ size, id, &handle));
scoped_ptr<base::DiscardableSharedMemory> memory(
new base::DiscardableSharedMemory(handle));
- CHECK(memory->Map(size));
+ if (!memory->Map(size))
+ base::TerminateBecauseOutOfMemory(size);
return memory.Pass();
}
+void ChildDiscardableSharedMemoryManager::MemoryUsageChanged(
+ size_t new_bytes_total,
+ size_t new_bytes_free) const {
+ TRACE_COUNTER2("renderer", "DiscardableMemoryUsage", "allocated",
+ new_bytes_total - new_bytes_free, "free", new_bytes_free);
+
+ static const char kDiscardableMemoryAllocatedKey[] =
+ "discardable-memory-allocated";
+ base::debug::SetCrashKeyValue(kDiscardableMemoryAllocatedKey,
+ base::Uint64ToString(new_bytes_total));
+
+ static const char kDiscardableMemoryFreeKey[] = "discardable-memory-free";
+ base::debug::SetCrashKeyValue(kDiscardableMemoryFreeKey,
+ base::Uint64ToString(new_bytes_free));
+}
+
} // namespace content
diff --git a/chromium/content/child/child_discardable_shared_memory_manager.h b/chromium/content/child/child_discardable_shared_memory_manager.h
index e35c57b4a26..27f5f5e3034 100644
--- a/chromium/content/child/child_discardable_shared_memory_manager.h
+++ b/chromium/content/child/child_discardable_shared_memory_manager.h
@@ -5,25 +5,49 @@
#ifndef CONTENT_CHILD_CHILD_DISCARDABLE_SHARED_MEMORY_MANAGER_H_
#define CONTENT_CHILD_CHILD_DISCARDABLE_SHARED_MEMORY_MANAGER_H_
-#include "base/memory/discardable_memory_shmem_allocator.h"
+#include "base/memory/discardable_memory_allocator.h"
#include "base/memory/ref_counted.h"
+#include "base/synchronization/lock.h"
+#include "base/trace_event/memory_dump_provider.h"
#include "content/child/thread_safe_sender.h"
+#include "content/common/content_export.h"
+#include "content/common/discardable_shared_memory_heap.h"
+#include "content/common/host_discardable_shared_memory_manager.h"
namespace content {
-// Implementation of DiscardableMemoryShmemAllocator that allocates
+// Implementation of DiscardableMemoryAllocator that allocates
// discardable memory segments through the browser process.
-class ChildDiscardableSharedMemoryManager
- : public base::DiscardableMemoryShmemAllocator {
+class CONTENT_EXPORT ChildDiscardableSharedMemoryManager
+ : public base::DiscardableMemoryAllocator,
+ public base::trace_event::MemoryDumpProvider {
public:
explicit ChildDiscardableSharedMemoryManager(ThreadSafeSender* sender);
~ChildDiscardableSharedMemoryManager() override;
- // Overridden from base::DiscardableMemoryShmemAllocator:
- scoped_ptr<base::DiscardableSharedMemory>
- AllocateLockedDiscardableSharedMemory(size_t size) override;
+ // Overridden from base::DiscardableMemoryAllocator:
+ scoped_ptr<base::DiscardableMemory> AllocateLockedDiscardableMemory(
+ size_t size) override;
+
+ // Overridden from base::trace_event::MemoryDumpProvider:
+ bool OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd) override;
+
+ // Release memory and associated resources that have been purged.
+ void ReleaseFreeMemory();
+
+ bool LockSpan(DiscardableSharedMemoryHeap::Span* span);
+ void UnlockSpan(DiscardableSharedMemoryHeap::Span* span);
+ void ReleaseSpan(scoped_ptr<DiscardableSharedMemoryHeap::Span> span);
private:
+ scoped_ptr<base::DiscardableSharedMemory>
+ AllocateLockedDiscardableSharedMemory(size_t size,
+ DiscardableSharedMemoryId id);
+ void MemoryUsageChanged(size_t new_bytes_allocated,
+ size_t new_bytes_free) const;
+
+ mutable base::Lock lock_;
+ DiscardableSharedMemoryHeap heap_;
scoped_refptr<ThreadSafeSender> sender_;
DISALLOW_COPY_AND_ASSIGN(ChildDiscardableSharedMemoryManager);
diff --git a/chromium/content/child/child_gpu_memory_buffer_manager.cc b/chromium/content/child/child_gpu_memory_buffer_manager.cc
index 7cb793d5240..0e1c312ad1c 100644
--- a/chromium/content/child/child_gpu_memory_buffer_manager.cc
+++ b/chromium/content/child/child_gpu_memory_buffer_manager.cc
@@ -4,7 +4,6 @@
#include "content/child/child_gpu_memory_buffer_manager.h"
-#include "content/child/child_thread.h"
#include "content/common/child_process_messages.h"
#include "content/common/gpu/client/gpu_memory_buffer_impl.h"
diff --git a/chromium/content/child/child_histogram_message_filter.cc b/chromium/content/child/child_histogram_message_filter.cc
index 3e895fcfe8d..3e778d57b3b 100644
--- a/chromium/content/child/child_histogram_message_filter.cc
+++ b/chromium/content/child/child_histogram_message_filter.cc
@@ -10,7 +10,6 @@
#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram_delta_serialization.h"
#include "content/child/child_process.h"
-#include "content/child/child_thread.h"
#include "content/common/child_process_messages.h"
#include "ipc/ipc_sender.h"
diff --git a/chromium/content/child/child_histogram_message_filter.h b/chromium/content/child/child_histogram_message_filter.h
index 072e2c60679..ed01890ac1c 100644
--- a/chromium/content/child/child_histogram_message_filter.h
+++ b/chromium/content/child/child_histogram_message_filter.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_CHILD_HISTOGRAM_MESSAGE_FILTER_H_
-#define CONTENT_CHILD_HISTOGRAM_MESSAGE_FILTER_H_
+#ifndef CONTENT_CHILD_CHILD_HISTOGRAM_MESSAGE_FILTER_H_
+#define CONTENT_CHILD_CHILD_HISTOGRAM_MESSAGE_FILTER_H_
#include <string>
#include <vector>
@@ -54,4 +54,4 @@ class ChildHistogramMessageFilter : public IPC::MessageFilter {
} // namespace content
-#endif // CONTENT_CHILD_HISTOGRAM_MESSAGE_FILTER_H_
+#endif // CONTENT_CHILD_CHILD_HISTOGRAM_MESSAGE_FILTER_H_
diff --git a/chromium/content/child/child_message_filter.cc b/chromium/content/child/child_message_filter.cc
index 9e5ff63e99a..66b7555b376 100644
--- a/chromium/content/child/child_message_filter.cc
+++ b/chromium/content/child/child_message_filter.cc
@@ -8,7 +8,7 @@
#include "base/bind_helpers.h"
#include "base/location.h"
#include "base/task_runner.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
#include "content/child/thread_safe_sender.h"
#include "ipc/message_filter.h"
@@ -52,7 +52,7 @@ base::TaskRunner* ChildMessageFilter::OverrideTaskRunnerForMessage(
ChildMessageFilter::ChildMessageFilter()
: internal_(NULL),
- thread_safe_sender_(ChildThread::current()->thread_safe_sender()) {}
+ thread_safe_sender_(ChildThreadImpl::current()->thread_safe_sender()) {}
ChildMessageFilter::~ChildMessageFilter() {}
diff --git a/chromium/content/child/child_message_filter.h b/chromium/content/child/child_message_filter.h
index a79ceecf2de..73002e7b260 100644
--- a/chromium/content/child/child_message_filter.h
+++ b/chromium/content/child/child_message_filter.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_CHILD_CROSS_MESSAGE_FILTER_H_
-#define CONTENT_CHILD_CROSS_MESSAGE_FILTER_H_
+#ifndef CONTENT_CHILD_CHILD_MESSAGE_FILTER_H_
+#define CONTENT_CHILD_CHILD_MESSAGE_FILTER_H_
#include "base/memory/ref_counted.h"
#include "ipc/ipc_sender.h"
@@ -51,7 +51,7 @@ class ChildMessageFilter
private:
class Internal;
- friend class ChildThread;
+ friend class ChildThreadImpl;
friend class RenderThreadImpl;
friend class WorkerThread;
@@ -70,4 +70,4 @@ class ChildMessageFilter
} // namespace content
-#endif // CONTENT_CHILD_CROSS_MESSAGE_FILTER_H_
+#endif // CONTENT_CHILD_CHILD_MESSAGE_FILTER_H_
diff --git a/chromium/content/child/child_process.cc b/chromium/content/child/child_process.cc
index 42eff930af4..e4da8563e4e 100644
--- a/chromium/content/child/child_process.cc
+++ b/chromium/content/child/child_process.cc
@@ -16,7 +16,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread.h"
#include "base/threading/thread_local.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
#if defined(OS_ANDROID)
#include "base/debug/debugger.h"
@@ -48,7 +48,7 @@ ChildProcess::ChildProcess()
base::Thread::Options(base::MessageLoop::TYPE_IO, 0)));
#if defined(OS_ANDROID)
- io_thread_.SetPriority(base::kThreadPriority_Display);
+ io_thread_.SetPriority(base::ThreadPriority::DISPLAY);
#endif
}
@@ -72,11 +72,11 @@ ChildProcess::~ChildProcess() {
io_thread_.Stop();
}
-ChildThread* ChildProcess::main_thread() {
+ChildThreadImpl* ChildProcess::main_thread() {
return main_thread_.get();
}
-void ChildProcess::set_main_thread(ChildThread* thread) {
+void ChildProcess::set_main_thread(ChildThreadImpl* thread) {
main_thread_.reset(thread);
}
diff --git a/chromium/content/child/child_process.h b/chromium/content/child/child_process.h
index 1aedcb688a1..cf3173f7132 100644
--- a/chromium/content/child/child_process.h
+++ b/chromium/content/child/child_process.h
@@ -12,7 +12,7 @@
#include "content/common/content_export.h"
namespace content {
-class ChildThread;
+class ChildThreadImpl;
// Base class for child processes of the browser process (i.e. renderer and
// plugin host). This is a singleton object for each child process.
@@ -22,12 +22,12 @@ class ChildThread;
//
// 1. ChildProcess::~ChildProcess() is called.
// 2. Shutdown event is fired. Background threads should stop.
-// 3. ChildThread::Shutdown() is called. ChildThread is also deleted.
+// 3. ChildThreadImpl::Shutdown() is called. ChildThread is also deleted.
// 4. IO thread is stopped.
// 5. Main message loop exits.
// 6. Child process is now fully stopped.
//
-// Note: IO thread outlives the ChildThread object.
+// Note: IO thread outlives the ChildThreadImpl object.
class CONTENT_EXPORT ChildProcess {
public:
// Child processes should have an object that derives from this class.
@@ -36,11 +36,11 @@ class CONTENT_EXPORT ChildProcess {
virtual ~ChildProcess();
// May be NULL if the main thread hasn't been set explicitly.
- ChildThread* main_thread();
+ ChildThreadImpl* main_thread();
// Sets the object associated with the main thread of this process.
// Takes ownership of the pointer.
- void set_main_thread(ChildThread* thread);
+ void set_main_thread(ChildThreadImpl* thread);
base::MessageLoop* io_message_loop() { return io_thread_.message_loop(); }
base::MessageLoopProxy* io_message_loop_proxy() {
@@ -81,7 +81,7 @@ class CONTENT_EXPORT ChildProcess {
// NOTE: make sure that main_thread_ is listed after shutdown_event_, since
// it depends on it (indirectly through IPC::SyncChannel). Same for
// io_thread_.
- scoped_ptr<ChildThread> main_thread_;
+ scoped_ptr<ChildThreadImpl> main_thread_;
DISALLOW_COPY_AND_ASSIGN(ChildProcess);
};
diff --git a/chromium/content/child/child_resource_message_filter.h b/chromium/content/child/child_resource_message_filter.h
index 0037eab5d09..2a92fcc5fb8 100644
--- a/chromium/content/child/child_resource_message_filter.h
+++ b/chromium/content/child/child_resource_message_filter.h
@@ -34,6 +34,11 @@ class ChildResourceMessageFilter : public IPC::MessageFilter {
// IPC::MessageFilter implementation.
bool OnMessageReceived(const IPC::Message& message) override;
+ void SetMainThreadTaskRunner(
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner) {
+ main_thread_task_runner_ = main_thread_task_runner;
+ }
+
private:
~ChildResourceMessageFilter() override;
diff --git a/chromium/content/child/child_shared_bitmap_manager.cc b/chromium/content/child/child_shared_bitmap_manager.cc
index 41c22610c4a..334a7ea8e4f 100644
--- a/chromium/content/child/child_shared_bitmap_manager.cc
+++ b/chromium/content/child/child_shared_bitmap_manager.cc
@@ -4,29 +4,75 @@
#include "content/child/child_shared_bitmap_manager.h"
-#include "content/child/child_thread.h"
+#include "base/debug/alias.h"
+#include "base/process/memory.h"
+#include "base/process/process_metrics.h"
+#include "content/child/child_thread_impl.h"
#include "content/common/child_process_messages.h"
-#include "ui/gfx/size.h"
+#include "ui/gfx/geometry/size.h"
namespace content {
namespace {
-void FreeSharedMemory(scoped_refptr<ThreadSafeSender> sender,
- cc::SharedBitmap* bitmap) {
- TRACE_EVENT0("renderer", "ChildSharedBitmapManager::FreeSharedMemory");
- sender->Send(new ChildProcessHostMsg_DeletedSharedBitmap(bitmap->id()));
- delete bitmap->memory();
-}
+class ChildSharedBitmap : public SharedMemoryBitmap {
+ public:
+ ChildSharedBitmap(scoped_refptr<ThreadSafeSender> sender,
+ base::SharedMemory* shared_memory,
+ const cc::SharedBitmapId& id)
+ : SharedMemoryBitmap(static_cast<uint8*>(shared_memory->memory()),
+ id,
+ shared_memory),
+ sender_(sender) {}
+
+ ChildSharedBitmap(scoped_refptr<ThreadSafeSender> sender,
+ scoped_ptr<base::SharedMemory> shared_memory_holder,
+ const cc::SharedBitmapId& id)
+ : ChildSharedBitmap(sender, shared_memory_holder.get(), id) {
+ shared_memory_holder_ = shared_memory_holder.Pass();
+ }
+
+ ~ChildSharedBitmap() override {
+ sender_->Send(new ChildProcessHostMsg_DeletedSharedBitmap(id()));
+ }
+
+ private:
+ scoped_refptr<ThreadSafeSender> sender_;
+ scoped_ptr<base::SharedMemory> shared_memory_holder_;
+};
+
+// Collect extra information for debugging bitmap creation failures.
+void CollectMemoryUsageAndDie(const gfx::Size& size, size_t alloc_size) {
+#if defined(OS_WIN)
+ int width = size.width();
+ int height = size.height();
+ DWORD last_error = GetLastError();
-void ReleaseSharedBitmap(scoped_refptr<ThreadSafeSender> sender,
- cc::SharedBitmap* handle) {
- TRACE_EVENT0("renderer", "ChildSharedBitmapManager::ReleaseSharedBitmap");
- sender->Send(new ChildProcessHostMsg_DeletedSharedBitmap(handle->id()));
+ scoped_ptr<base::ProcessMetrics> metrics(
+ base::ProcessMetrics::CreateProcessMetrics(
+ base::GetCurrentProcessHandle()));
+
+ size_t private_bytes = 0;
+ size_t shared_bytes = 0;
+ metrics->GetMemoryBytes(&private_bytes, &shared_bytes);
+
+ base::debug::Alias(&width);
+ base::debug::Alias(&height);
+ base::debug::Alias(&last_error);
+ base::debug::Alias(&private_bytes);
+ base::debug::Alias(&shared_bytes);
+#endif
+ base::TerminateBecauseOutOfMemory(alloc_size);
}
} // namespace
+SharedMemoryBitmap::SharedMemoryBitmap(uint8* pixels,
+ const cc::SharedBitmapId& id,
+ base::SharedMemory* shared_memory)
+ : SharedBitmap(pixels, id), shared_memory_(shared_memory) {
+}
+
ChildSharedBitmapManager::ChildSharedBitmapManager(
scoped_refptr<ThreadSafeSender> sender)
: sender_(sender) {
@@ -36,15 +82,23 @@ ChildSharedBitmapManager::~ChildSharedBitmapManager() {}
scoped_ptr<cc::SharedBitmap> ChildSharedBitmapManager::AllocateSharedBitmap(
const gfx::Size& size) {
+ scoped_ptr<SharedMemoryBitmap> bitmap = AllocateSharedMemoryBitmap(size);
+#if defined(OS_POSIX)
+ // Close file descriptor to avoid running out.
+ if (bitmap)
+ bitmap->shared_memory()->Close();
+#endif
+ return bitmap.Pass();
+}
+
+scoped_ptr<SharedMemoryBitmap>
+ChildSharedBitmapManager::AllocateSharedMemoryBitmap(const gfx::Size& size) {
TRACE_EVENT2("renderer",
- "ChildSharedBitmapManager::AllocateSharedMemory",
- "width",
- size.width(),
- "height",
- size.height());
+ "ChildSharedBitmapManager::AllocateSharedMemoryBitmap", "width",
+ size.width(), "height", size.height());
size_t memory_size;
if (!cc::SharedBitmap::SizeInBytes(size, &memory_size))
- return scoped_ptr<cc::SharedBitmap>();
+ return scoped_ptr<SharedMemoryBitmap>();
cc::SharedBitmapId id = cc::SharedBitmap::GenerateId();
scoped_ptr<base::SharedMemory> memory;
#if defined(OS_POSIX)
@@ -52,16 +106,21 @@ scoped_ptr<cc::SharedBitmap> ChildSharedBitmapManager::AllocateSharedBitmap(
sender_->Send(new ChildProcessHostMsg_SyncAllocateSharedBitmap(
memory_size, id, &handle));
memory = make_scoped_ptr(new base::SharedMemory(handle, false));
- CHECK(memory->Map(memory_size));
+ if (!memory->Map(memory_size))
+ CollectMemoryUsageAndDie(size, memory_size);
#else
- memory.reset(ChildThread::AllocateSharedMemory(memory_size, sender_));
- CHECK(memory);
+ memory = ChildThreadImpl::AllocateSharedMemory(memory_size, sender_.get());
+ if (!memory)
+ CollectMemoryUsageAndDie(size, memory_size);
+
+ if (!memory->Map(memory_size))
+ CollectMemoryUsageAndDie(size, memory_size);
+
base::SharedMemoryHandle handle_to_send = memory->handle();
sender_->Send(new ChildProcessHostMsg_AllocatedSharedBitmap(
memory_size, handle_to_send, id));
#endif
- return scoped_ptr<cc::SharedBitmap>(new cc::SharedBitmap(
- memory.release(), id, base::Bind(&FreeSharedMemory, sender_)));
+ return make_scoped_ptr(new ChildSharedBitmap(sender_, memory.Pass(), id));
}
scoped_ptr<cc::SharedBitmap> ChildSharedBitmapManager::GetSharedBitmapFromId(
@@ -81,10 +140,8 @@ scoped_ptr<cc::SharedBitmap> ChildSharedBitmapManager::GetBitmapForSharedMemory(
#endif
sender_->Send(new ChildProcessHostMsg_AllocatedSharedBitmap(
mem->mapped_size(), handle_to_send, id));
- // The compositor owning the SharedBitmap will be closed before the
- // ChildThread containng this, making the use of base::Unretained safe.
- return scoped_ptr<cc::SharedBitmap>(
- new cc::SharedBitmap(mem, id, base::Bind(&ReleaseSharedBitmap, sender_)));
+
+ return make_scoped_ptr(new ChildSharedBitmap(sender_, mem, id));
}
} // namespace content
diff --git a/chromium/content/child/child_shared_bitmap_manager.h b/chromium/content/child/child_shared_bitmap_manager.h
index e4d6b4989fd..83a0a5a99d3 100644
--- a/chromium/content/child/child_shared_bitmap_manager.h
+++ b/chromium/content/child/child_shared_bitmap_manager.h
@@ -13,18 +13,34 @@
namespace content {
+class SharedMemoryBitmap : public cc::SharedBitmap {
+ public:
+ base::SharedMemory* shared_memory() { return shared_memory_; }
+
+ protected:
+ SharedMemoryBitmap(uint8* pixels,
+ const cc::SharedBitmapId& id,
+ base::SharedMemory* shared_memory);
+
+ base::SharedMemory* shared_memory_;
+};
+
class ChildSharedBitmapManager : public cc::SharedBitmapManager {
public:
ChildSharedBitmapManager(scoped_refptr<ThreadSafeSender> sender);
~ChildSharedBitmapManager() override;
+ // cc::SharedBitmapManager implementation.
scoped_ptr<cc::SharedBitmap> AllocateSharedBitmap(
const gfx::Size& size) override;
scoped_ptr<cc::SharedBitmap> GetSharedBitmapFromId(
const gfx::Size&,
const cc::SharedBitmapId&) override;
+
scoped_ptr<cc::SharedBitmap> GetBitmapForSharedMemory(
- base::SharedMemory* mem) override;
+ base::SharedMemory* mem);
+ scoped_ptr<SharedMemoryBitmap> AllocateSharedMemoryBitmap(
+ const gfx::Size& size);
private:
scoped_refptr<ThreadSafeSender> sender_;
diff --git a/chromium/content/child/child_thread.cc b/chromium/content/child/child_thread.cc
deleted file mode 100644
index b665e8914ad..00000000000
--- a/chromium/content/child/child_thread.cc
+++ /dev/null
@@ -1,606 +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/child/child_thread.h"
-
-#include <signal.h>
-
-#include <string>
-
-#include "base/allocator/allocator_extension.h"
-#include "base/base_switches.h"
-#include "base/basictypes.h"
-#include "base/command_line.h"
-#include "base/debug/leak_annotations.h"
-#include "base/lazy_instance.h"
-#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/timer_slack.h"
-#include "base/process/kill.h"
-#include "base/process/process_handle.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "base/synchronization/condition_variable.h"
-#include "base/synchronization/lock.h"
-#include "base/threading/thread_local.h"
-#include "base/tracked_objects.h"
-#include "components/tracing/child_trace_message_filter.h"
-#include "content/child/child_discardable_shared_memory_manager.h"
-#include "content/child/child_gpu_memory_buffer_manager.h"
-#include "content/child/child_histogram_message_filter.h"
-#include "content/child/child_process.h"
-#include "content/child/child_resource_message_filter.h"
-#include "content/child/child_shared_bitmap_manager.h"
-#include "content/child/fileapi/file_system_dispatcher.h"
-#include "content/child/fileapi/webfilesystem_impl.h"
-#include "content/child/geofencing/geofencing_message_filter.h"
-#include "content/child/mojo/mojo_application.h"
-#include "content/child/notifications/notification_dispatcher.h"
-#include "content/child/power_monitor_broadcast_source.h"
-#include "content/child/quota_dispatcher.h"
-#include "content/child/quota_message_filter.h"
-#include "content/child/resource_dispatcher.h"
-#include "content/child/service_worker/service_worker_message_filter.h"
-#include "content/child/thread_safe_sender.h"
-#include "content/child/websocket_dispatcher.h"
-#include "content/common/child_process_messages.h"
-#include "content/public/common/content_switches.h"
-#include "ipc/ipc_logging.h"
-#include "ipc/ipc_switches.h"
-#include "ipc/ipc_sync_channel.h"
-#include "ipc/ipc_sync_message_filter.h"
-#include "ipc/mojo/ipc_channel_mojo.h"
-
-#if defined(OS_WIN)
-#include "content/common/handle_enumerator_win.h"
-#endif
-
-#if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED)
-#include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h"
-#endif
-
-using tracked_objects::ThreadData;
-
-namespace content {
-namespace {
-
-// How long to wait for a connection to the browser process before giving up.
-const int kConnectionTimeoutS = 15;
-
-base::LazyInstance<base::ThreadLocalPointer<ChildThread> > g_lazy_tls =
- LAZY_INSTANCE_INITIALIZER;
-
-// This isn't needed on Windows because there the sandbox's job object
-// terminates child processes automatically. For unsandboxed processes (i.e.
-// plugins), PluginThread has EnsureTerminateMessageFilter.
-#if defined(OS_POSIX)
-
-// TODO(earthdok): Re-enable on CrOS http://crbug.com/360622
-#if (defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \
- defined(THREAD_SANITIZER)) && !defined(OS_CHROMEOS)
-// A thread delegate that waits for |duration| and then exits the process with
-// _exit(0).
-class WaitAndExitDelegate : public base::PlatformThread::Delegate {
- public:
- explicit WaitAndExitDelegate(base::TimeDelta duration)
- : duration_(duration) {}
- virtual ~WaitAndExitDelegate() override {}
-
- virtual void ThreadMain() override {
- base::PlatformThread::Sleep(duration_);
- _exit(0);
- }
-
- private:
- const base::TimeDelta duration_;
- DISALLOW_COPY_AND_ASSIGN(WaitAndExitDelegate);
-};
-
-bool CreateWaitAndExitThread(base::TimeDelta duration) {
- scoped_ptr<WaitAndExitDelegate> delegate(new WaitAndExitDelegate(duration));
-
- const bool thread_created =
- base::PlatformThread::CreateNonJoinable(0, delegate.get());
- if (!thread_created)
- return false;
-
- // A non joinable thread has been created. The thread will either terminate
- // the process or will be terminated by the process. Therefore, keep the
- // delegate object alive for the lifetime of the process.
- WaitAndExitDelegate* leaking_delegate = delegate.release();
- ANNOTATE_LEAKING_OBJECT_PTR(leaking_delegate);
- ignore_result(leaking_delegate);
- return true;
-}
-#endif
-
-class SuicideOnChannelErrorFilter : public IPC::MessageFilter {
- public:
- // IPC::MessageFilter
- void OnChannelError() override {
- // For renderer/worker processes:
- // On POSIX, at least, one can install an unload handler which loops
- // forever and leave behind a renderer process which eats 100% CPU forever.
- //
- // This is because the terminate signals (ViewMsg_ShouldClose and the error
- // from the IPC sender) are routed to the main message loop but never
- // processed (because that message loop is stuck in V8).
- //
- // One could make the browser SIGKILL the renderers, but that leaves open a
- // large window where a browser failure (or a user, manually terminating
- // the browser because "it's stuck") will leave behind a process eating all
- // the CPU.
- //
- // So, we install a filter on the sender so that we can process this event
- // here and kill the process.
- // TODO(earthdok): Re-enable on CrOS http://crbug.com/360622
-#if (defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \
- defined(THREAD_SANITIZER)) && !defined(OS_CHROMEOS)
- // Some sanitizer tools rely on exit handlers (e.g. to run leak detection,
- // or dump code coverage data to disk). Instead of exiting the process
- // immediately, we give it 60 seconds to run exit handlers.
- CHECK(CreateWaitAndExitThread(base::TimeDelta::FromSeconds(60)));
-#if defined(LEAK_SANITIZER)
- // Invoke LeakSanitizer early to avoid detecting shutdown-only leaks. If
- // leaks are found, the process will exit here.
- __lsan_do_leak_check();
-#endif
-#else
- _exit(0);
-#endif
- }
-
- protected:
- ~SuicideOnChannelErrorFilter() override {}
-};
-
-#endif // OS(POSIX)
-
-#if defined(OS_ANDROID)
-ChildThread* g_child_thread = NULL;
-
-// A lock protects g_child_thread.
-base::LazyInstance<base::Lock> g_lazy_child_thread_lock =
- LAZY_INSTANCE_INITIALIZER;
-
-// base::ConditionVariable has an explicit constructor that takes
-// a base::Lock pointer as parameter. The base::DefaultLazyInstanceTraits
-// doesn't handle the case. Thus, we need our own class here.
-struct CondVarLazyInstanceTraits {
- static const bool kRegisterOnExit = true;
-#ifndef NDEBUG
- static const bool kAllowedToAccessOnNonjoinableThread = false;
-#endif
-
- static base::ConditionVariable* New(void* instance) {
- return new (instance) base::ConditionVariable(
- g_lazy_child_thread_lock.Pointer());
- }
- static void Delete(base::ConditionVariable* instance) {
- instance->~ConditionVariable();
- }
-};
-
-// A condition variable that synchronize threads initializing and waiting
-// for g_child_thread.
-base::LazyInstance<base::ConditionVariable, CondVarLazyInstanceTraits>
- g_lazy_child_thread_cv = LAZY_INSTANCE_INITIALIZER;
-
-void QuitMainThreadMessageLoop() {
- base::MessageLoop::current()->Quit();
-}
-
-#endif
-
-} // namespace
-
-ChildThread::Options::Options()
- : channel_name(base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kProcessChannelID)),
- use_mojo_channel(false) {}
-
-ChildThread::Options::Options(bool mojo)
- : channel_name(base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kProcessChannelID)),
- use_mojo_channel(mojo) {}
-
-
-ChildThread::ChildThreadMessageRouter::ChildThreadMessageRouter(
- IPC::Sender* sender)
- : sender_(sender) {}
-
-bool ChildThread::ChildThreadMessageRouter::Send(IPC::Message* msg) {
- return sender_->Send(msg);
-}
-
-ChildThread::ChildThread()
- : router_(this),
- in_browser_process_(false),
- channel_connected_factory_(this) {
- Init(Options());
-}
-
-ChildThread::ChildThread(const Options& options)
- : router_(this),
- in_browser_process_(true),
- channel_connected_factory_(this) {
- Init(options);
-}
-
-scoped_ptr<IPC::SyncChannel> ChildThread::CreateChannel(bool use_mojo_channel) {
- if (use_mojo_channel) {
- VLOG(1) << "Mojo is enabled on child";
- return IPC::SyncChannel::Create(
- IPC::ChannelMojo::CreateClientFactory(channel_name_),
- this,
- ChildProcess::current()->io_message_loop_proxy(),
- true,
- ChildProcess::current()->GetShutDownEvent());
- }
-
- VLOG(1) << "Mojo is disabled on child";
- return IPC::SyncChannel::Create(
- channel_name_,
- IPC::Channel::MODE_CLIENT,
- this,
- ChildProcess::current()->io_message_loop_proxy(),
- true,
- ChildProcess::current()->GetShutDownEvent());
-}
-
-void ChildThread::Init(const Options& options) {
- channel_name_ = options.channel_name;
-
- g_lazy_tls.Pointer()->Set(this);
- on_channel_error_called_ = false;
- message_loop_ = base::MessageLoop::current();
-#ifdef IPC_MESSAGE_LOG_ENABLED
- // We must make sure to instantiate the IPC Logger *before* we create the
- // channel, otherwise we can get a callback on the IO thread which creates
- // the logger, and the logger does not like being created on the IO thread.
- IPC::Logging::GetInstance();
-#endif
- channel_ = CreateChannel(options.use_mojo_channel);
-#ifdef IPC_MESSAGE_LOG_ENABLED
- if (!in_browser_process_)
- IPC::Logging::GetInstance()->SetIPCSender(this);
-#endif
-
- mojo_application_.reset(new MojoApplication);
-
- sync_message_filter_ =
- new IPC::SyncMessageFilter(ChildProcess::current()->GetShutDownEvent());
- thread_safe_sender_ = new ThreadSafeSender(
- base::MessageLoopProxy::current().get(), sync_message_filter_.get());
-
- resource_dispatcher_.reset(new ResourceDispatcher(this));
- websocket_dispatcher_.reset(new WebSocketDispatcher);
- file_system_dispatcher_.reset(new FileSystemDispatcher());
-
- histogram_message_filter_ = new ChildHistogramMessageFilter();
- resource_message_filter_ =
- new ChildResourceMessageFilter(resource_dispatcher());
-
- service_worker_message_filter_ =
- new ServiceWorkerMessageFilter(thread_safe_sender_.get());
-
- quota_message_filter_ =
- new QuotaMessageFilter(thread_safe_sender_.get());
- quota_dispatcher_.reset(new QuotaDispatcher(thread_safe_sender_.get(),
- quota_message_filter_.get()));
- geofencing_message_filter_ =
- new GeofencingMessageFilter(thread_safe_sender_.get());
- notification_dispatcher_ =
- new NotificationDispatcher(thread_safe_sender_.get());
- channel_->AddFilter(histogram_message_filter_.get());
- channel_->AddFilter(sync_message_filter_.get());
- channel_->AddFilter(resource_message_filter_.get());
- channel_->AddFilter(quota_message_filter_->GetFilter());
- channel_->AddFilter(notification_dispatcher_->GetFilter());
- channel_->AddFilter(service_worker_message_filter_->GetFilter());
- channel_->AddFilter(geofencing_message_filter_->GetFilter());
-
- if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kSingleProcess)) {
- // In single process mode, browser-side tracing will cover the whole
- // process including renderers.
- channel_->AddFilter(new tracing::ChildTraceMessageFilter(
- ChildProcess::current()->io_message_loop_proxy()));
- }
-
- // In single process mode we may already have a power monitor
- if (!base::PowerMonitor::Get()) {
- scoped_ptr<PowerMonitorBroadcastSource> power_monitor_source(
- new PowerMonitorBroadcastSource());
- channel_->AddFilter(power_monitor_source->GetMessageFilter());
-
- power_monitor_.reset(new base::PowerMonitor(
- power_monitor_source.Pass()));
- }
-
-#if defined(OS_POSIX)
- // Check that --process-type is specified so we don't do this in unit tests
- // and single-process mode.
- if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kProcessType))
- channel_->AddFilter(new SuicideOnChannelErrorFilter());
-#endif
-
- int connection_timeout = kConnectionTimeoutS;
- std::string connection_override =
- base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kIPCConnectionTimeout);
- if (!connection_override.empty()) {
- int temp;
- if (base::StringToInt(connection_override, &temp))
- connection_timeout = temp;
- }
-
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&ChildThread::EnsureConnected,
- channel_connected_factory_.GetWeakPtr()),
- base::TimeDelta::FromSeconds(connection_timeout));
-
-#if defined(OS_ANDROID)
- {
- base::AutoLock lock(g_lazy_child_thread_lock.Get());
- g_child_thread = this;
- }
- // Signalling without locking is fine here because only
- // one thread can wait on the condition variable.
- g_lazy_child_thread_cv.Get().Signal();
-#endif
-
-#if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED)
- trace_memory_controller_.reset(new base::debug::TraceMemoryController(
- message_loop_->message_loop_proxy(),
- ::HeapProfilerWithPseudoStackStart,
- ::HeapProfilerStop,
- ::GetHeapProfile));
-#endif
-
- shared_bitmap_manager_.reset(
- new ChildSharedBitmapManager(thread_safe_sender()));
-
- gpu_memory_buffer_manager_.reset(
- new ChildGpuMemoryBufferManager(thread_safe_sender()));
-
- discardable_shared_memory_manager_.reset(
- new ChildDiscardableSharedMemoryManager(thread_safe_sender()));
-}
-
-ChildThread::~ChildThread() {
-#ifdef IPC_MESSAGE_LOG_ENABLED
- IPC::Logging::GetInstance()->SetIPCSender(NULL);
-#endif
-
- channel_->RemoveFilter(histogram_message_filter_.get());
- channel_->RemoveFilter(sync_message_filter_.get());
-
- // The ChannelProxy object caches a pointer to the IPC thread, so need to
- // reset it as it's not guaranteed to outlive this object.
- // NOTE: this also has the side-effect of not closing the main IPC channel to
- // the browser process. This is needed because this is the signal that the
- // browser uses to know that this process has died, so we need it to be alive
- // until this process is shut down, and the OS closes the handle
- // automatically. We used to watch the object handle on Windows to do this,
- // but it wasn't possible to do so on POSIX.
- channel_->ClearIPCTaskRunner();
- g_lazy_tls.Pointer()->Set(NULL);
-}
-
-void ChildThread::Shutdown() {
- // Delete objects that hold references to blink so derived classes can
- // safely shutdown blink in their Shutdown implementation.
- file_system_dispatcher_.reset();
- quota_dispatcher_.reset();
- WebFileSystemImpl::DeleteThreadSpecificInstance();
-}
-
-void ChildThread::OnChannelConnected(int32 peer_pid) {
- channel_connected_factory_.InvalidateWeakPtrs();
-}
-
-void ChildThread::OnChannelError() {
- set_on_channel_error_called(true);
- base::MessageLoop::current()->Quit();
-}
-
-bool ChildThread::Send(IPC::Message* msg) {
- DCHECK(base::MessageLoop::current() == message_loop());
- if (!channel_) {
- delete msg;
- return false;
- }
-
- return channel_->Send(msg);
-}
-
-MessageRouter* ChildThread::GetRouter() {
- DCHECK(base::MessageLoop::current() == message_loop());
- return &router_;
-}
-
-base::SharedMemory* ChildThread::AllocateSharedMemory(size_t buf_size) {
- return AllocateSharedMemory(buf_size, this);
-}
-
-// static
-base::SharedMemory* ChildThread::AllocateSharedMemory(
- size_t buf_size,
- IPC::Sender* sender) {
- scoped_ptr<base::SharedMemory> shared_buf;
-#if defined(OS_WIN)
- shared_buf.reset(new base::SharedMemory);
- if (!shared_buf->CreateAndMapAnonymous(buf_size)) {
- NOTREACHED();
- return NULL;
- }
-#else
- // On POSIX, we need to ask the browser to create the shared memory for us,
- // since this is blocked by the sandbox.
- base::SharedMemoryHandle shared_mem_handle;
- if (sender->Send(new ChildProcessHostMsg_SyncAllocateSharedMemory(
- buf_size, &shared_mem_handle))) {
- if (base::SharedMemory::IsHandleValid(shared_mem_handle)) {
- shared_buf.reset(new base::SharedMemory(shared_mem_handle, false));
- if (!shared_buf->Map(buf_size)) {
- NOTREACHED() << "Map failed";
- return NULL;
- }
- } else {
- NOTREACHED() << "Browser failed to allocate shared memory";
- return NULL;
- }
- } else {
- NOTREACHED() << "Browser allocation request message failed";
- return NULL;
- }
-#endif
- return shared_buf.release();
-}
-
-bool ChildThread::OnMessageReceived(const IPC::Message& msg) {
- if (mojo_application_->OnMessageReceived(msg))
- return true;
-
- // Resource responses are sent to the resource dispatcher.
- if (resource_dispatcher_->OnMessageReceived(msg))
- return true;
- if (websocket_dispatcher_->OnMessageReceived(msg))
- return true;
- if (file_system_dispatcher_->OnMessageReceived(msg))
- return true;
-
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(ChildThread, msg)
- IPC_MESSAGE_HANDLER(ChildProcessMsg_Shutdown, OnShutdown)
-#if defined(IPC_MESSAGE_LOG_ENABLED)
- IPC_MESSAGE_HANDLER(ChildProcessMsg_SetIPCLoggingEnabled,
- OnSetIPCLoggingEnabled)
-#endif
- IPC_MESSAGE_HANDLER(ChildProcessMsg_SetProfilerStatus,
- OnSetProfilerStatus)
- IPC_MESSAGE_HANDLER(ChildProcessMsg_GetChildProfilerData,
- OnGetChildProfilerData)
- IPC_MESSAGE_HANDLER(ChildProcessMsg_DumpHandles, OnDumpHandles)
- IPC_MESSAGE_HANDLER(ChildProcessMsg_SetProcessBackgrounded,
- OnProcessBackgrounded)
-#if defined(USE_TCMALLOC)
- IPC_MESSAGE_HANDLER(ChildProcessMsg_GetTcmallocStats, OnGetTcmallocStats)
-#endif
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
-
- if (handled)
- return true;
-
- if (msg.routing_id() == MSG_ROUTING_CONTROL)
- return OnControlMessageReceived(msg);
-
- return router_.OnMessageReceived(msg);
-}
-
-bool ChildThread::OnControlMessageReceived(const IPC::Message& msg) {
- return false;
-}
-
-void ChildThread::OnShutdown() {
- base::MessageLoop::current()->Quit();
-}
-
-#if defined(IPC_MESSAGE_LOG_ENABLED)
-void ChildThread::OnSetIPCLoggingEnabled(bool enable) {
- if (enable)
- IPC::Logging::GetInstance()->Enable();
- else
- IPC::Logging::GetInstance()->Disable();
-}
-#endif // IPC_MESSAGE_LOG_ENABLED
-
-void ChildThread::OnSetProfilerStatus(ThreadData::Status status) {
- ThreadData::InitializeAndSetTrackingStatus(status);
-}
-
-void ChildThread::OnGetChildProfilerData(int sequence_number) {
- tracked_objects::ProcessDataSnapshot process_data;
- ThreadData::Snapshot(false, &process_data);
-
- Send(new ChildProcessHostMsg_ChildProfilerData(sequence_number,
- process_data));
-}
-
-void ChildThread::OnDumpHandles() {
-#if defined(OS_WIN)
- scoped_refptr<HandleEnumerator> handle_enum(
- new HandleEnumerator(
- base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kAuditAllHandles)));
- handle_enum->EnumerateHandles();
- Send(new ChildProcessHostMsg_DumpHandlesDone);
-#else
- NOTIMPLEMENTED();
-#endif
-}
-
-#if defined(USE_TCMALLOC)
-void ChildThread::OnGetTcmallocStats() {
- std::string result;
- char buffer[1024 * 32];
- base::allocator::GetStats(buffer, sizeof(buffer));
- result.append(buffer);
- Send(new ChildProcessHostMsg_TcmallocStats(result));
-}
-#endif
-
-ChildThread* ChildThread::current() {
- return g_lazy_tls.Pointer()->Get();
-}
-
-#if defined(OS_ANDROID)
-// The method must NOT be called on the child thread itself.
-// It may block the child thread if so.
-void ChildThread::ShutdownThread() {
- DCHECK(!ChildThread::current()) <<
- "this method should NOT be called from child thread itself";
- {
- base::AutoLock lock(g_lazy_child_thread_lock.Get());
- while (!g_child_thread)
- g_lazy_child_thread_cv.Get().Wait();
- }
- DCHECK_NE(base::MessageLoop::current(), g_child_thread->message_loop());
- g_child_thread->message_loop()->PostTask(
- FROM_HERE, base::Bind(&QuitMainThreadMessageLoop));
-}
-#endif
-
-void ChildThread::OnProcessFinalRelease() {
- if (on_channel_error_called_) {
- base::MessageLoop::current()->Quit();
- return;
- }
-
- // The child process shutdown sequence is a request response based mechanism,
- // where we send out an initial feeler request to the child process host
- // instance in the browser to verify if it's ok to shutdown the child process.
- // The browser then sends back a response if it's ok to shutdown. This avoids
- // race conditions if the process refcount is 0 but there's an IPC message
- // inflight that would addref it.
- Send(new ChildProcessHostMsg_ShutdownRequest);
-}
-
-void ChildThread::EnsureConnected() {
- VLOG(0) << "ChildThread::EnsureConnected()";
- base::KillProcess(base::GetCurrentProcessHandle(), 0, false);
-}
-
-void ChildThread::OnProcessBackgrounded(bool background) {
- // Set timer slack to maximum on main thread when in background.
- base::TimerSlack timer_slack = base::TIMER_SLACK_NONE;
- if (background)
- timer_slack = base::TIMER_SLACK_MAXIMUM;
- base::MessageLoop::current()->SetTimerSlack(timer_slack);
-}
-
-} // namespace content
diff --git a/chromium/content/child/child_thread.h b/chromium/content/child/child_thread.h
deleted file mode 100644
index 969194e8a3f..00000000000
--- a/chromium/content/child/child_thread.h
+++ /dev/null
@@ -1,277 +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_CHILD_CHILD_THREAD_H_
-#define CONTENT_CHILD_CHILD_THREAD_H_
-
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/shared_memory.h"
-#include "base/memory/weak_ptr.h"
-#include "base/power_monitor/power_monitor.h"
-#include "base/tracked_objects.h"
-#include "content/child/mojo/mojo_application.h"
-#include "content/common/content_export.h"
-#include "content/common/message_router.h"
-#include "ipc/ipc_message.h" // For IPC_MESSAGE_LOG_ENABLED.
-
-namespace base {
-class MessageLoop;
-
-namespace debug {
-class TraceMemoryController;
-} // namespace debug
-} // namespace base
-
-namespace IPC {
-class SyncChannel;
-class SyncMessageFilter;
-} // namespace IPC
-
-namespace blink {
-class WebFrame;
-} // namespace blink
-
-namespace content {
-class ChildDiscardableSharedMemoryManager;
-class ChildGpuMemoryBufferManager;
-class ChildHistogramMessageFilter;
-class ChildResourceMessageFilter;
-class ChildSharedBitmapManager;
-class FileSystemDispatcher;
-class GeofencingMessageFilter;
-class NotificationDispatcher;
-class ServiceWorkerMessageFilter;
-class QuotaDispatcher;
-class QuotaMessageFilter;
-class ResourceDispatcher;
-class ThreadSafeSender;
-class WebSocketDispatcher;
-struct RequestInfo;
-
-// The main thread of a child process derives from this class.
-class CONTENT_EXPORT ChildThread : public IPC::Listener, public IPC::Sender {
- public:
- struct CONTENT_EXPORT Options {
- Options();
- explicit Options(bool mojo);
- Options(std::string name, bool mojo)
- : channel_name(name), use_mojo_channel(mojo) {}
-
- std::string channel_name;
- bool use_mojo_channel;
- };
-
- // Creates the thread.
- ChildThread();
- // Used for single-process mode and for in process gpu mode.
- explicit ChildThread(const Options& options);
- // ChildProcess::main_thread() is reset after Shutdown(), and before the
- // destructor, so any subsystem that relies on ChildProcess::main_thread()
- // must be terminated before Shutdown returns. In particular, if a subsystem
- // has a thread that post tasks to ChildProcess::main_thread(), that thread
- // should be joined in Shutdown().
- ~ChildThread() override;
- virtual void Shutdown();
-
- // IPC::Sender implementation:
- bool Send(IPC::Message* msg) override;
-
- IPC::SyncChannel* channel() { return channel_.get(); }
-
- MessageRouter* GetRouter();
-
- // Allocates a block of shared memory of the given size and
- // maps in into the address space. Returns NULL of failure.
- // Note: On posix, this requires a sync IPC to the browser process,
- // but on windows the child process directly allocates the block.
- base::SharedMemory* AllocateSharedMemory(size_t buf_size);
-
- // A static variant that can be called on background threads provided
- // the |sender| passed in is safe to use on background threads.
- static base::SharedMemory* AllocateSharedMemory(size_t buf_size,
- IPC::Sender* sender);
-
- ChildSharedBitmapManager* shared_bitmap_manager() const {
- return shared_bitmap_manager_.get();
- }
-
- ChildGpuMemoryBufferManager* gpu_memory_buffer_manager() const {
- return gpu_memory_buffer_manager_.get();
- }
-
- ChildDiscardableSharedMemoryManager* discardable_shared_memory_manager()
- const {
- return discardable_shared_memory_manager_.get();
- }
-
- ResourceDispatcher* resource_dispatcher() const {
- return resource_dispatcher_.get();
- }
-
- WebSocketDispatcher* websocket_dispatcher() const {
- return websocket_dispatcher_.get();
- }
-
- FileSystemDispatcher* file_system_dispatcher() const {
- return file_system_dispatcher_.get();
- }
-
- QuotaDispatcher* quota_dispatcher() const {
- return quota_dispatcher_.get();
- }
-
- NotificationDispatcher* notification_dispatcher() const {
- return notification_dispatcher_.get();
- }
-
- IPC::SyncMessageFilter* sync_message_filter() const {
- return sync_message_filter_.get();
- }
-
- // The getter should only be called on the main thread, however the
- // IPC::Sender it returns may be safely called on any thread including
- // the main thread.
- ThreadSafeSender* thread_safe_sender() const {
- return thread_safe_sender_.get();
- }
-
- ChildHistogramMessageFilter* child_histogram_message_filter() const {
- return histogram_message_filter_.get();
- }
-
- ServiceWorkerMessageFilter* service_worker_message_filter() const {
- return service_worker_message_filter_.get();
- }
-
- QuotaMessageFilter* quota_message_filter() const {
- return quota_message_filter_.get();
- }
-
- base::MessageLoop* message_loop() const { return message_loop_; }
-
- // Returns the one child thread. Can only be called on the main thread.
- static ChildThread* current();
-
-#if defined(OS_ANDROID)
- // Called on Android's service thread to shutdown the main thread of this
- // process.
- static void ShutdownThread();
-#endif
-
- ServiceRegistry* service_registry() const {
- return mojo_application_->service_registry();
- }
-
- protected:
- friend class ChildProcess;
-
- // Called when the process refcount is 0.
- void OnProcessFinalRelease();
-
- virtual bool OnControlMessageReceived(const IPC::Message& msg);
-
- void set_on_channel_error_called(bool on_channel_error_called) {
- on_channel_error_called_ = on_channel_error_called;
- }
-
- // IPC::Listener implementation:
- bool OnMessageReceived(const IPC::Message& msg) override;
- void OnChannelConnected(int32 peer_pid) override;
- void OnChannelError() override;
-
- private:
- class ChildThreadMessageRouter : public MessageRouter {
- public:
- // |sender| must outlive this object.
- explicit ChildThreadMessageRouter(IPC::Sender* sender);
- bool Send(IPC::Message* msg) override;
-
- private:
- IPC::Sender* const sender_;
- };
-
- void Init(const Options& options);
- scoped_ptr<IPC::SyncChannel> CreateChannel(bool use_mojo_channel);
-
- // IPC message handlers.
- void OnShutdown();
- void OnSetProfilerStatus(tracked_objects::ThreadData::Status status);
- void OnGetChildProfilerData(int sequence_number);
- void OnDumpHandles();
- void OnProcessBackgrounded(bool background);
-#ifdef IPC_MESSAGE_LOG_ENABLED
- void OnSetIPCLoggingEnabled(bool enable);
-#endif
-#if defined(USE_TCMALLOC)
- void OnGetTcmallocStats();
-#endif
-
- void EnsureConnected();
-
- scoped_ptr<MojoApplication> mojo_application_;
-
- std::string channel_name_;
- scoped_ptr<IPC::SyncChannel> channel_;
-
- // Allows threads other than the main thread to send sync messages.
- scoped_refptr<IPC::SyncMessageFilter> sync_message_filter_;
-
- scoped_refptr<ThreadSafeSender> thread_safe_sender_;
-
- // Implements message routing functionality to the consumers of ChildThread.
- ChildThreadMessageRouter router_;
-
- // Handles resource loads for this process.
- scoped_ptr<ResourceDispatcher> resource_dispatcher_;
-
- scoped_ptr<WebSocketDispatcher> websocket_dispatcher_;
-
- // The OnChannelError() callback was invoked - the channel is dead, don't
- // attempt to communicate.
- bool on_channel_error_called_;
-
- base::MessageLoop* message_loop_;
-
- scoped_ptr<FileSystemDispatcher> file_system_dispatcher_;
-
- scoped_ptr<QuotaDispatcher> quota_dispatcher_;
-
- scoped_refptr<ChildHistogramMessageFilter> histogram_message_filter_;
-
- scoped_refptr<ChildResourceMessageFilter> resource_message_filter_;
-
- scoped_refptr<ServiceWorkerMessageFilter> service_worker_message_filter_;
-
- scoped_refptr<QuotaMessageFilter> quota_message_filter_;
-
- scoped_refptr<NotificationDispatcher> notification_dispatcher_;
-
- scoped_ptr<ChildSharedBitmapManager> shared_bitmap_manager_;
-
- scoped_ptr<ChildGpuMemoryBufferManager> gpu_memory_buffer_manager_;
-
- scoped_ptr<ChildDiscardableSharedMemoryManager>
- discardable_shared_memory_manager_;
-
- // Observes the trace event system. When tracing is enabled, optionally
- // starts profiling the tcmalloc heap.
- scoped_ptr<base::debug::TraceMemoryController> trace_memory_controller_;
-
- scoped_ptr<base::PowerMonitor> power_monitor_;
-
- scoped_refptr<GeofencingMessageFilter> geofencing_message_filter_;
-
- bool in_browser_process_;
-
- base::WeakPtrFactory<ChildThread> channel_connected_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(ChildThread);
-};
-
-} // namespace content
-
-#endif // CONTENT_CHILD_CHILD_THREAD_H_
diff --git a/chromium/content/child/child_thread_impl.cc b/chromium/content/child/child_thread_impl.cc
new file mode 100644
index 00000000000..cc13a5bf0a5
--- /dev/null
+++ b/chromium/content/child/child_thread_impl.cc
@@ -0,0 +1,688 @@
+// 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/child/child_thread_impl.h"
+
+#include <signal.h>
+
+#include <string>
+
+#include "base/allocator/allocator_extension.h"
+#include "base/base_switches.h"
+#include "base/basictypes.h"
+#include "base/command_line.h"
+#include "base/debug/leak_annotations.h"
+#include "base/debug/profiler.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "base/message_loop/timer_slack.h"
+#include "base/metrics/field_trial.h"
+#include "base/process/process.h"
+#include "base/process/process_handle.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread_local.h"
+#include "base/trace_event/memory_dump_manager.h"
+#include "base/tracked_objects.h"
+#include "components/tracing/child_trace_message_filter.h"
+#include "content/child/bluetooth/bluetooth_message_filter.h"
+#include "content/child/child_discardable_shared_memory_manager.h"
+#include "content/child/child_gpu_memory_buffer_manager.h"
+#include "content/child/child_histogram_message_filter.h"
+#include "content/child/child_process.h"
+#include "content/child/child_resource_message_filter.h"
+#include "content/child/child_shared_bitmap_manager.h"
+#include "content/child/fileapi/file_system_dispatcher.h"
+#include "content/child/fileapi/webfilesystem_impl.h"
+#include "content/child/geofencing/geofencing_message_filter.h"
+#include "content/child/mojo/mojo_application.h"
+#include "content/child/navigator_connect/navigator_connect_dispatcher.h"
+#include "content/child/notifications/notification_dispatcher.h"
+#include "content/child/power_monitor_broadcast_source.h"
+#include "content/child/push_messaging/push_dispatcher.h"
+#include "content/child/quota_dispatcher.h"
+#include "content/child/quota_message_filter.h"
+#include "content/child/resource_dispatcher.h"
+#include "content/child/service_worker/service_worker_message_filter.h"
+#include "content/child/thread_safe_sender.h"
+#include "content/child/websocket_dispatcher.h"
+#include "content/common/child_process_messages.h"
+#include "content/common/in_process_child_thread_params.h"
+#include "content/public/common/content_switches.h"
+#include "ipc/ipc_logging.h"
+#include "ipc/ipc_switches.h"
+#include "ipc/ipc_sync_channel.h"
+#include "ipc/ipc_sync_message_filter.h"
+#include "ipc/mojo/ipc_channel_mojo.h"
+
+#if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED)
+#include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h"
+#endif
+
+using tracked_objects::ThreadData;
+
+namespace content {
+namespace {
+
+// How long to wait for a connection to the browser process before giving up.
+const int kConnectionTimeoutS = 15;
+
+base::LazyInstance<base::ThreadLocalPointer<ChildThreadImpl> > g_lazy_tls =
+ LAZY_INSTANCE_INITIALIZER;
+
+// This isn't needed on Windows because there the sandbox's job object
+// terminates child processes automatically. For unsandboxed processes (i.e.
+// plugins), PluginThread has EnsureTerminateMessageFilter.
+#if defined(OS_POSIX)
+
+#if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \
+ defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \
+ defined(UNDEFINED_SANITIZER)
+// A thread delegate that waits for |duration| and then exits the process with
+// _exit(0).
+class WaitAndExitDelegate : public base::PlatformThread::Delegate {
+ public:
+ explicit WaitAndExitDelegate(base::TimeDelta duration)
+ : duration_(duration) {}
+
+ void ThreadMain() override {
+ base::PlatformThread::Sleep(duration_);
+ _exit(0);
+ }
+
+ private:
+ const base::TimeDelta duration_;
+ DISALLOW_COPY_AND_ASSIGN(WaitAndExitDelegate);
+};
+
+bool CreateWaitAndExitThread(base::TimeDelta duration) {
+ scoped_ptr<WaitAndExitDelegate> delegate(new WaitAndExitDelegate(duration));
+
+ const bool thread_created =
+ base::PlatformThread::CreateNonJoinable(0, delegate.get());
+ if (!thread_created)
+ return false;
+
+ // A non joinable thread has been created. The thread will either terminate
+ // the process or will be terminated by the process. Therefore, keep the
+ // delegate object alive for the lifetime of the process.
+ WaitAndExitDelegate* leaking_delegate = delegate.release();
+ ANNOTATE_LEAKING_OBJECT_PTR(leaking_delegate);
+ ignore_result(leaking_delegate);
+ return true;
+}
+#endif
+
+class SuicideOnChannelErrorFilter : public IPC::MessageFilter {
+ public:
+ // IPC::MessageFilter
+ void OnChannelError() override {
+ // For renderer/worker processes:
+ // On POSIX, at least, one can install an unload handler which loops
+ // forever and leave behind a renderer process which eats 100% CPU forever.
+ //
+ // This is because the terminate signals (ViewMsg_ShouldClose and the error
+ // from the IPC sender) are routed to the main message loop but never
+ // processed (because that message loop is stuck in V8).
+ //
+ // One could make the browser SIGKILL the renderers, but that leaves open a
+ // large window where a browser failure (or a user, manually terminating
+ // the browser because "it's stuck") will leave behind a process eating all
+ // the CPU.
+ //
+ // So, we install a filter on the sender so that we can process this event
+ // here and kill the process.
+ base::debug::StopProfiling();
+#if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \
+ defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \
+ defined(UNDEFINED_SANITIZER)
+ // Some sanitizer tools rely on exit handlers (e.g. to run leak detection,
+ // or dump code coverage data to disk). Instead of exiting the process
+ // immediately, we give it 60 seconds to run exit handlers.
+ CHECK(CreateWaitAndExitThread(base::TimeDelta::FromSeconds(60)));
+#if defined(LEAK_SANITIZER)
+ // Invoke LeakSanitizer early to avoid detecting shutdown-only leaks. If
+ // leaks are found, the process will exit here.
+ __lsan_do_leak_check();
+#endif
+#else
+ _exit(0);
+#endif
+ }
+
+ protected:
+ ~SuicideOnChannelErrorFilter() override {}
+};
+
+#endif // OS(POSIX)
+
+#if defined(OS_ANDROID)
+ChildThreadImpl* g_child_thread = NULL;
+bool g_child_thread_initialized = false;
+
+// A lock protects g_child_thread.
+base::LazyInstance<base::Lock>::Leaky g_lazy_child_thread_lock =
+ LAZY_INSTANCE_INITIALIZER;
+
+// base::ConditionVariable has an explicit constructor that takes
+// a base::Lock pointer as parameter. The base::DefaultLazyInstanceTraits
+// doesn't handle the case. Thus, we need our own class here.
+struct CondVarLazyInstanceTraits {
+ static const bool kRegisterOnExit = false;
+#ifndef NDEBUG
+ static const bool kAllowedToAccessOnNonjoinableThread = true;
+#endif
+
+ static base::ConditionVariable* New(void* instance) {
+ return new (instance) base::ConditionVariable(
+ g_lazy_child_thread_lock.Pointer());
+ }
+ static void Delete(base::ConditionVariable* instance) {
+ instance->~ConditionVariable();
+ }
+};
+
+// A condition variable that synchronize threads initializing and waiting
+// for g_child_thread.
+base::LazyInstance<base::ConditionVariable, CondVarLazyInstanceTraits>
+ g_lazy_child_thread_cv = LAZY_INSTANCE_INITIALIZER;
+
+void QuitMainThreadMessageLoop() {
+ base::MessageLoop::current()->Quit();
+}
+
+#endif
+
+} // namespace
+
+ChildThread* ChildThread::Get() {
+ return ChildThreadImpl::current();
+}
+
+ChildThreadImpl::Options::Options()
+ : channel_name(base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kProcessChannelID)),
+ use_mojo_channel(false) {
+}
+
+ChildThreadImpl::Options::~Options() {
+}
+
+ChildThreadImpl::Options::Builder::Builder() {
+}
+
+ChildThreadImpl::Options::Builder&
+ChildThreadImpl::Options::Builder::InBrowserProcess(
+ const InProcessChildThreadParams& params) {
+ options_.browser_process_io_runner = params.io_runner();
+ options_.channel_name = params.channel_name();
+ return *this;
+}
+
+ChildThreadImpl::Options::Builder&
+ChildThreadImpl::Options::Builder::UseMojoChannel(bool use_mojo_channel) {
+ options_.use_mojo_channel = use_mojo_channel;
+ return *this;
+}
+
+ChildThreadImpl::Options::Builder&
+ChildThreadImpl::Options::Builder::WithChannelName(
+ const std::string& channel_name) {
+ options_.channel_name = channel_name;
+ return *this;
+}
+
+ChildThreadImpl::Options::Builder&
+ChildThreadImpl::Options::Builder::AddStartupFilter(
+ IPC::MessageFilter* filter) {
+ options_.startup_filters.push_back(filter);
+ return *this;
+}
+
+ChildThreadImpl::Options ChildThreadImpl::Options::Builder::Build() {
+ return options_;
+}
+
+ChildThreadImpl::ChildThreadMessageRouter::ChildThreadMessageRouter(
+ IPC::Sender* sender)
+ : sender_(sender) {}
+
+bool ChildThreadImpl::ChildThreadMessageRouter::Send(IPC::Message* msg) {
+ return sender_->Send(msg);
+}
+
+ChildThreadImpl::ChildThreadImpl()
+ : router_(this),
+ channel_connected_factory_(this) {
+ Init(Options::Builder().Build());
+}
+
+ChildThreadImpl::ChildThreadImpl(const Options& options)
+ : router_(this),
+ browser_process_io_runner_(options.browser_process_io_runner),
+ channel_connected_factory_(this) {
+ Init(options);
+}
+
+scoped_refptr<base::SequencedTaskRunner> ChildThreadImpl::GetIOTaskRunner() {
+ if (IsInBrowserProcess())
+ return browser_process_io_runner_;
+ return ChildProcess::current()->io_message_loop_proxy();
+}
+
+void ChildThreadImpl::ConnectChannel(bool use_mojo_channel) {
+ bool create_pipe_now = true;
+ if (use_mojo_channel) {
+ VLOG(1) << "Mojo is enabled on child";
+ scoped_refptr<base::SequencedTaskRunner> io_task_runner = GetIOTaskRunner();
+ DCHECK(io_task_runner);
+ channel_->Init(IPC::ChannelMojo::CreateClientFactory(
+ nullptr, io_task_runner, channel_name_),
+ create_pipe_now);
+ return;
+ }
+
+ VLOG(1) << "Mojo is disabled on child";
+ channel_->Init(channel_name_, IPC::Channel::MODE_CLIENT, create_pipe_now);
+}
+
+void ChildThreadImpl::Init(const Options& options) {
+ channel_name_ = options.channel_name;
+
+ g_lazy_tls.Pointer()->Set(this);
+ on_channel_error_called_ = false;
+ message_loop_ = base::MessageLoop::current();
+#ifdef IPC_MESSAGE_LOG_ENABLED
+ // We must make sure to instantiate the IPC Logger *before* we create the
+ // channel, otherwise we can get a callback on the IO thread which creates
+ // the logger, and the logger does not like being created on the IO thread.
+ IPC::Logging::GetInstance();
+#endif
+ channel_ = IPC::SyncChannel::Create(
+ this, ChildProcess::current()->io_message_loop_proxy(),
+ ChildProcess::current()->GetShutDownEvent());
+#ifdef IPC_MESSAGE_LOG_ENABLED
+ if (!IsInBrowserProcess())
+ IPC::Logging::GetInstance()->SetIPCSender(this);
+#endif
+
+ mojo_application_.reset(new MojoApplication(GetIOTaskRunner()));
+
+ sync_message_filter_ =
+ new IPC::SyncMessageFilter(ChildProcess::current()->GetShutDownEvent());
+ thread_safe_sender_ = new ThreadSafeSender(
+ base::MessageLoopProxy::current().get(), sync_message_filter_.get());
+
+ resource_dispatcher_.reset(new ResourceDispatcher(
+ this, message_loop()->task_runner()));
+ websocket_dispatcher_.reset(new WebSocketDispatcher);
+ file_system_dispatcher_.reset(new FileSystemDispatcher());
+
+ histogram_message_filter_ = new ChildHistogramMessageFilter();
+ resource_message_filter_ =
+ new ChildResourceMessageFilter(resource_dispatcher());
+
+ service_worker_message_filter_ =
+ new ServiceWorkerMessageFilter(thread_safe_sender_.get());
+
+ quota_message_filter_ =
+ new QuotaMessageFilter(thread_safe_sender_.get());
+ quota_dispatcher_.reset(new QuotaDispatcher(thread_safe_sender_.get(),
+ quota_message_filter_.get()));
+ geofencing_message_filter_ =
+ new GeofencingMessageFilter(thread_safe_sender_.get());
+ bluetooth_message_filter_ =
+ new BluetoothMessageFilter(thread_safe_sender_.get());
+ notification_dispatcher_ =
+ new NotificationDispatcher(thread_safe_sender_.get());
+ push_dispatcher_ = new PushDispatcher(thread_safe_sender_.get());
+ navigator_connect_dispatcher_ =
+ new NavigatorConnectDispatcher(thread_safe_sender_.get());
+
+ channel_->AddFilter(histogram_message_filter_.get());
+ channel_->AddFilter(sync_message_filter_.get());
+ channel_->AddFilter(resource_message_filter_.get());
+ channel_->AddFilter(quota_message_filter_->GetFilter());
+ channel_->AddFilter(notification_dispatcher_->GetFilter());
+ channel_->AddFilter(push_dispatcher_->GetFilter());
+ channel_->AddFilter(service_worker_message_filter_->GetFilter());
+ channel_->AddFilter(geofencing_message_filter_->GetFilter());
+ channel_->AddFilter(bluetooth_message_filter_->GetFilter());
+ channel_->AddFilter(navigator_connect_dispatcher_->GetFilter());
+
+ if (!IsInBrowserProcess()) {
+ // In single process mode, browser-side tracing will cover the whole
+ // process including renderers.
+ channel_->AddFilter(new tracing::ChildTraceMessageFilter(
+ ChildProcess::current()->io_message_loop_proxy()));
+ }
+
+ // In single process mode we may already have a power monitor
+ if (!base::PowerMonitor::Get()) {
+ scoped_ptr<PowerMonitorBroadcastSource> power_monitor_source(
+ new PowerMonitorBroadcastSource());
+ channel_->AddFilter(power_monitor_source->GetMessageFilter());
+
+ power_monitor_.reset(new base::PowerMonitor(
+ power_monitor_source.Pass()));
+ }
+
+#if defined(OS_POSIX)
+ // Check that --process-type is specified so we don't do this in unit tests
+ // and single-process mode.
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kProcessType))
+ channel_->AddFilter(new SuicideOnChannelErrorFilter());
+#endif
+
+ // Add filters passed here via options.
+ for (auto startup_filter : options.startup_filters) {
+ channel_->AddFilter(startup_filter);
+ }
+
+ ConnectChannel(options.use_mojo_channel);
+
+ int connection_timeout = kConnectionTimeoutS;
+ std::string connection_override =
+ base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kIPCConnectionTimeout);
+ if (!connection_override.empty()) {
+ int temp;
+ if (base::StringToInt(connection_override, &temp))
+ connection_timeout = temp;
+ }
+
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&ChildThreadImpl::EnsureConnected,
+ channel_connected_factory_.GetWeakPtr()),
+ base::TimeDelta::FromSeconds(connection_timeout));
+
+#if defined(OS_ANDROID)
+ {
+ base::AutoLock lock(g_lazy_child_thread_lock.Get());
+ g_child_thread = this;
+ g_child_thread_initialized = true;
+ }
+ // Signalling without locking is fine here because only
+ // one thread can wait on the condition variable.
+ g_lazy_child_thread_cv.Get().Signal();
+#endif
+
+#if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED)
+ trace_memory_controller_.reset(new base::trace_event::TraceMemoryController(
+ message_loop_->message_loop_proxy(), ::HeapProfilerWithPseudoStackStart,
+ ::HeapProfilerStop, ::GetHeapProfile));
+#endif
+
+ base::trace_event::MemoryDumpManager::GetInstance()->Initialize();
+
+ shared_bitmap_manager_.reset(
+ new ChildSharedBitmapManager(thread_safe_sender()));
+
+ gpu_memory_buffer_manager_.reset(
+ new ChildGpuMemoryBufferManager(thread_safe_sender()));
+
+ discardable_shared_memory_manager_.reset(
+ new ChildDiscardableSharedMemoryManager(thread_safe_sender()));
+}
+
+ChildThreadImpl::~ChildThreadImpl() {
+ // ChildDiscardableSharedMemoryManager has to be destroyed while
+ // |thread_safe_sender_| is still valid.
+ discardable_shared_memory_manager_.reset();
+
+#if defined(OS_ANDROID)
+ {
+ base::AutoLock lock(g_lazy_child_thread_lock.Get());
+ g_child_thread = nullptr;
+ }
+#endif
+
+#ifdef IPC_MESSAGE_LOG_ENABLED
+ IPC::Logging::GetInstance()->SetIPCSender(NULL);
+#endif
+
+ channel_->RemoveFilter(histogram_message_filter_.get());
+ channel_->RemoveFilter(sync_message_filter_.get());
+
+ // The ChannelProxy object caches a pointer to the IPC thread, so need to
+ // reset it as it's not guaranteed to outlive this object.
+ // NOTE: this also has the side-effect of not closing the main IPC channel to
+ // the browser process. This is needed because this is the signal that the
+ // browser uses to know that this process has died, so we need it to be alive
+ // until this process is shut down, and the OS closes the handle
+ // automatically. We used to watch the object handle on Windows to do this,
+ // but it wasn't possible to do so on POSIX.
+ channel_->ClearIPCTaskRunner();
+ g_lazy_tls.Pointer()->Set(NULL);
+}
+
+void ChildThreadImpl::Shutdown() {
+ // Delete objects that hold references to blink so derived classes can
+ // safely shutdown blink in their Shutdown implementation.
+ file_system_dispatcher_.reset();
+ quota_dispatcher_.reset();
+ WebFileSystemImpl::DeleteThreadSpecificInstance();
+}
+
+void ChildThreadImpl::OnChannelConnected(int32 peer_pid) {
+ channel_connected_factory_.InvalidateWeakPtrs();
+}
+
+void ChildThreadImpl::OnChannelError() {
+ set_on_channel_error_called(true);
+ base::MessageLoop::current()->Quit();
+}
+
+bool ChildThreadImpl::Send(IPC::Message* msg) {
+ DCHECK(base::MessageLoop::current() == message_loop());
+ if (!channel_) {
+ delete msg;
+ return false;
+ }
+
+ return channel_->Send(msg);
+}
+
+#if defined(OS_WIN)
+void ChildThreadImpl::PreCacheFont(const LOGFONT& log_font) {
+ Send(new ChildProcessHostMsg_PreCacheFont(log_font));
+}
+
+void ChildThreadImpl::ReleaseCachedFonts() {
+ Send(new ChildProcessHostMsg_ReleaseCachedFonts());
+}
+#endif
+
+MessageRouter* ChildThreadImpl::GetRouter() {
+ DCHECK(base::MessageLoop::current() == message_loop());
+ return &router_;
+}
+
+scoped_ptr<base::SharedMemory> ChildThreadImpl::AllocateSharedMemory(
+ size_t buf_size) {
+ DCHECK(base::MessageLoop::current() == message_loop());
+ return AllocateSharedMemory(buf_size, this);
+}
+
+// static
+scoped_ptr<base::SharedMemory> ChildThreadImpl::AllocateSharedMemory(
+ size_t buf_size,
+ IPC::Sender* sender) {
+ scoped_ptr<base::SharedMemory> shared_buf;
+#if defined(OS_WIN)
+ shared_buf.reset(new base::SharedMemory);
+ if (!shared_buf->CreateAnonymous(buf_size)) {
+ NOTREACHED();
+ return NULL;
+ }
+#else
+ // On POSIX, we need to ask the browser to create the shared memory for us,
+ // since this is blocked by the sandbox.
+ base::SharedMemoryHandle shared_mem_handle;
+ if (sender->Send(new ChildProcessHostMsg_SyncAllocateSharedMemory(
+ buf_size, &shared_mem_handle))) {
+ if (base::SharedMemory::IsHandleValid(shared_mem_handle)) {
+ shared_buf.reset(new base::SharedMemory(shared_mem_handle, false));
+ } else {
+ NOTREACHED() << "Browser failed to allocate shared memory";
+ return NULL;
+ }
+ } else {
+ NOTREACHED() << "Browser allocation request message failed";
+ return NULL;
+ }
+#endif
+ return shared_buf;
+}
+
+bool ChildThreadImpl::OnMessageReceived(const IPC::Message& msg) {
+ if (mojo_application_->OnMessageReceived(msg))
+ return true;
+
+ // Resource responses are sent to the resource dispatcher.
+ if (resource_dispatcher_->OnMessageReceived(msg))
+ return true;
+ if (websocket_dispatcher_->OnMessageReceived(msg))
+ return true;
+ if (file_system_dispatcher_->OnMessageReceived(msg))
+ return true;
+
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(ChildThreadImpl, msg)
+ IPC_MESSAGE_HANDLER(ChildProcessMsg_Shutdown, OnShutdown)
+#if defined(IPC_MESSAGE_LOG_ENABLED)
+ IPC_MESSAGE_HANDLER(ChildProcessMsg_SetIPCLoggingEnabled,
+ OnSetIPCLoggingEnabled)
+#endif
+ IPC_MESSAGE_HANDLER(ChildProcessMsg_SetProfilerStatus,
+ OnSetProfilerStatus)
+ IPC_MESSAGE_HANDLER(ChildProcessMsg_GetChildProfilerData,
+ OnGetChildProfilerData)
+ IPC_MESSAGE_HANDLER(ChildProcessMsg_ProfilingPhaseCompleted,
+ OnProfilingPhaseCompleted)
+ IPC_MESSAGE_HANDLER(ChildProcessMsg_SetProcessBackgrounded,
+ OnProcessBackgrounded)
+#if defined(USE_TCMALLOC)
+ IPC_MESSAGE_HANDLER(ChildProcessMsg_GetTcmallocStats, OnGetTcmallocStats)
+#endif
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+
+ if (handled)
+ return true;
+
+ if (msg.routing_id() == MSG_ROUTING_CONTROL)
+ return OnControlMessageReceived(msg);
+
+ return router_.OnMessageReceived(msg);
+}
+
+bool ChildThreadImpl::OnControlMessageReceived(const IPC::Message& msg) {
+ return false;
+}
+
+void ChildThreadImpl::OnShutdown() {
+ base::MessageLoop::current()->Quit();
+}
+
+#if defined(IPC_MESSAGE_LOG_ENABLED)
+void ChildThreadImpl::OnSetIPCLoggingEnabled(bool enable) {
+ if (enable)
+ IPC::Logging::GetInstance()->Enable();
+ else
+ IPC::Logging::GetInstance()->Disable();
+}
+#endif // IPC_MESSAGE_LOG_ENABLED
+
+void ChildThreadImpl::OnSetProfilerStatus(ThreadData::Status status) {
+ ThreadData::InitializeAndSetTrackingStatus(status);
+}
+
+void ChildThreadImpl::OnGetChildProfilerData(int sequence_number,
+ int current_profiling_phase) {
+ tracked_objects::ProcessDataSnapshot process_data;
+ ThreadData::Snapshot(current_profiling_phase, &process_data);
+
+ Send(
+ new ChildProcessHostMsg_ChildProfilerData(sequence_number, process_data));
+}
+
+void ChildThreadImpl::OnProfilingPhaseCompleted(int profiling_phase) {
+ ThreadData::OnProfilingPhaseCompleted(profiling_phase);
+}
+
+#if defined(USE_TCMALLOC)
+void ChildThreadImpl::OnGetTcmallocStats() {
+ std::string result;
+ char buffer[1024 * 32];
+ base::allocator::GetStats(buffer, sizeof(buffer));
+ result.append(buffer);
+ Send(new ChildProcessHostMsg_TcmallocStats(result));
+}
+#endif
+
+ChildThreadImpl* ChildThreadImpl::current() {
+ return g_lazy_tls.Pointer()->Get();
+}
+
+#if defined(OS_ANDROID)
+// The method must NOT be called on the child thread itself.
+// It may block the child thread if so.
+void ChildThreadImpl::ShutdownThread() {
+ DCHECK(!ChildThreadImpl::current()) <<
+ "this method should NOT be called from child thread itself";
+ {
+ base::AutoLock lock(g_lazy_child_thread_lock.Get());
+ while (!g_child_thread_initialized)
+ g_lazy_child_thread_cv.Get().Wait();
+
+ // g_child_thread may already have been destructed while we didn't hold the
+ // lock.
+ if (!g_child_thread)
+ return;
+
+ DCHECK_NE(base::MessageLoop::current(), g_child_thread->message_loop());
+ g_child_thread->message_loop()->PostTask(
+ FROM_HERE, base::Bind(&QuitMainThreadMessageLoop));
+ }
+}
+#endif
+
+void ChildThreadImpl::OnProcessFinalRelease() {
+ if (on_channel_error_called_) {
+ base::MessageLoop::current()->Quit();
+ return;
+ }
+
+ // The child process shutdown sequence is a request response based mechanism,
+ // where we send out an initial feeler request to the child process host
+ // instance in the browser to verify if it's ok to shutdown the child process.
+ // The browser then sends back a response if it's ok to shutdown. This avoids
+ // race conditions if the process refcount is 0 but there's an IPC message
+ // inflight that would addref it.
+ Send(new ChildProcessHostMsg_ShutdownRequest);
+}
+
+void ChildThreadImpl::EnsureConnected() {
+ VLOG(0) << "ChildThreadImpl::EnsureConnected()";
+ base::Process::Current().Terminate(0, false);
+}
+
+bool ChildThreadImpl::IsInBrowserProcess() const {
+ return browser_process_io_runner_;
+}
+
+void ChildThreadImpl::OnProcessBackgrounded(bool background) {
+ // Set timer slack to maximum on main thread when in background.
+ base::TimerSlack timer_slack = base::TIMER_SLACK_NONE;
+ if (background)
+ timer_slack = base::TIMER_SLACK_MAXIMUM;
+ base::MessageLoop::current()->SetTimerSlack(timer_slack);
+}
+
+} // namespace content
diff --git a/chromium/content/child/child_thread_impl.h b/chromium/content/child/child_thread_impl.h
new file mode 100644
index 00000000000..b9efc4d2a5f
--- /dev/null
+++ b/chromium/content/child/child_thread_impl.h
@@ -0,0 +1,337 @@
+// 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_CHILD_CHILD_THREAD_IMPL_H_
+#define CONTENT_CHILD_CHILD_THREAD_IMPL_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/shared_memory.h"
+#include "base/memory/weak_ptr.h"
+#include "base/power_monitor/power_monitor.h"
+#include "base/sequenced_task_runner.h"
+#include "base/tracked_objects.h"
+#include "content/child/mojo/mojo_application.h"
+#include "content/common/content_export.h"
+#include "content/common/message_router.h"
+#include "content/public/child/child_thread.h"
+#include "ipc/ipc_message.h" // For IPC_MESSAGE_LOG_ENABLED.
+
+namespace base {
+class MessageLoop;
+
+namespace trace_event {
+class TraceMemoryController;
+} // namespace trace_event
+} // namespace base
+
+namespace IPC {
+class MessageFilter;
+class ScopedIPCSupport;
+class SyncChannel;
+class SyncMessageFilter;
+} // namespace IPC
+
+namespace blink {
+class WebFrame;
+} // namespace blink
+
+namespace content {
+class ChildMessageFilter;
+class ChildDiscardableSharedMemoryManager;
+class ChildGpuMemoryBufferManager;
+class ChildHistogramMessageFilter;
+class ChildResourceMessageFilter;
+class ChildSharedBitmapManager;
+class FileSystemDispatcher;
+class InProcessChildThreadParams;
+class NavigatorConnectDispatcher;
+class NotificationDispatcher;
+class PushDispatcher;
+class ServiceWorkerMessageFilter;
+class QuotaDispatcher;
+class QuotaMessageFilter;
+class ResourceDispatcher;
+class ThreadSafeSender;
+class WebSocketDispatcher;
+struct RequestInfo;
+
+// The main thread of a child process derives from this class.
+class CONTENT_EXPORT ChildThreadImpl
+ : public IPC::Listener,
+ virtual public ChildThread {
+ public:
+ struct CONTENT_EXPORT Options;
+
+ // Creates the thread.
+ ChildThreadImpl();
+ // Allow to be used for single-process mode and for in process gpu mode via
+ // options.
+ explicit ChildThreadImpl(const Options& options);
+ // ChildProcess::main_thread() is reset after Shutdown(), and before the
+ // destructor, so any subsystem that relies on ChildProcess::main_thread()
+ // must be terminated before Shutdown returns. In particular, if a subsystem
+ // has a thread that post tasks to ChildProcess::main_thread(), that thread
+ // should be joined in Shutdown().
+ ~ChildThreadImpl() override;
+ virtual void Shutdown();
+
+ // IPC::Sender implementation:
+ bool Send(IPC::Message* msg) override;
+
+ // ChildThread implementation:
+#if defined(OS_WIN)
+ void PreCacheFont(const LOGFONT& log_font) override;
+ void ReleaseCachedFonts() override;
+#endif
+
+ IPC::SyncChannel* channel() { return channel_.get(); }
+
+ MessageRouter* GetRouter();
+
+ // Allocates a block of shared memory of the given size. Returns NULL on
+ // failure.
+ // Note: On posix, this requires a sync IPC to the browser process,
+ // but on windows the child process directly allocates the block.
+ scoped_ptr<base::SharedMemory> AllocateSharedMemory(size_t buf_size);
+
+ // A static variant that can be called on background threads provided
+ // the |sender| passed in is safe to use on background threads.
+ static scoped_ptr<base::SharedMemory> AllocateSharedMemory(
+ size_t buf_size,
+ IPC::Sender* sender);
+
+ ChildSharedBitmapManager* shared_bitmap_manager() const {
+ return shared_bitmap_manager_.get();
+ }
+
+ ChildGpuMemoryBufferManager* gpu_memory_buffer_manager() const {
+ return gpu_memory_buffer_manager_.get();
+ }
+
+ ChildDiscardableSharedMemoryManager* discardable_shared_memory_manager()
+ const {
+ return discardable_shared_memory_manager_.get();
+ }
+
+ ResourceDispatcher* resource_dispatcher() const {
+ return resource_dispatcher_.get();
+ }
+
+ WebSocketDispatcher* websocket_dispatcher() const {
+ return websocket_dispatcher_.get();
+ }
+
+ FileSystemDispatcher* file_system_dispatcher() const {
+ return file_system_dispatcher_.get();
+ }
+
+ QuotaDispatcher* quota_dispatcher() const {
+ return quota_dispatcher_.get();
+ }
+
+ NotificationDispatcher* notification_dispatcher() const {
+ return notification_dispatcher_.get();
+ }
+
+ PushDispatcher* push_dispatcher() const {
+ return push_dispatcher_.get();
+ }
+
+ IPC::SyncMessageFilter* sync_message_filter() const {
+ return sync_message_filter_.get();
+ }
+
+ // The getter should only be called on the main thread, however the
+ // IPC::Sender it returns may be safely called on any thread including
+ // the main thread.
+ ThreadSafeSender* thread_safe_sender() const {
+ return thread_safe_sender_.get();
+ }
+
+ ChildHistogramMessageFilter* child_histogram_message_filter() const {
+ return histogram_message_filter_.get();
+ }
+
+ ServiceWorkerMessageFilter* service_worker_message_filter() const {
+ return service_worker_message_filter_.get();
+ }
+
+ QuotaMessageFilter* quota_message_filter() const {
+ return quota_message_filter_.get();
+ }
+
+ ChildResourceMessageFilter* child_resource_message_filter() const {
+ return resource_message_filter_.get();
+ }
+
+ base::MessageLoop* message_loop() const { return message_loop_; }
+
+ // Returns the one child thread. Can only be called on the main thread.
+ static ChildThreadImpl* current();
+
+#if defined(OS_ANDROID)
+ // Called on Android's service thread to shutdown the main thread of this
+ // process.
+ static void ShutdownThread();
+#endif
+
+ ServiceRegistry* service_registry() const {
+ return mojo_application_->service_registry();
+ }
+
+ protected:
+ friend class ChildProcess;
+
+ // Called when the process refcount is 0.
+ void OnProcessFinalRelease();
+
+ virtual bool OnControlMessageReceived(const IPC::Message& msg);
+
+ void set_on_channel_error_called(bool on_channel_error_called) {
+ on_channel_error_called_ = on_channel_error_called;
+ }
+
+ // IPC::Listener implementation:
+ bool OnMessageReceived(const IPC::Message& msg) override;
+ void OnChannelConnected(int32 peer_pid) override;
+ void OnChannelError() override;
+
+ bool IsInBrowserProcess() const;
+ scoped_refptr<base::SequencedTaskRunner> GetIOTaskRunner();
+
+ private:
+ class ChildThreadMessageRouter : public MessageRouter {
+ public:
+ // |sender| must outlive this object.
+ explicit ChildThreadMessageRouter(IPC::Sender* sender);
+ bool Send(IPC::Message* msg) override;
+
+ private:
+ IPC::Sender* const sender_;
+ };
+
+ void Init(const Options& options);
+
+ // We create the channel first without connecting it so we can add filters
+ // prior to any messages being received, then connect it afterwards.
+ void ConnectChannel(bool use_mojo_channel);
+
+ // IPC message handlers.
+ void OnShutdown();
+ void OnSetProfilerStatus(tracked_objects::ThreadData::Status status);
+ void OnGetChildProfilerData(int sequence_number, int current_profiling_phase);
+ void OnProfilingPhaseCompleted(int profiling_phase);
+ void OnProcessBackgrounded(bool background);
+#ifdef IPC_MESSAGE_LOG_ENABLED
+ void OnSetIPCLoggingEnabled(bool enable);
+#endif
+#if defined(USE_TCMALLOC)
+ void OnGetTcmallocStats();
+#endif
+
+ void EnsureConnected();
+
+ scoped_ptr<MojoApplication> mojo_application_;
+
+ std::string channel_name_;
+ scoped_ptr<IPC::SyncChannel> channel_;
+
+ // Allows threads other than the main thread to send sync messages.
+ scoped_refptr<IPC::SyncMessageFilter> sync_message_filter_;
+
+ scoped_refptr<ThreadSafeSender> thread_safe_sender_;
+
+ // Implements message routing functionality to the consumers of
+ // ChildThreadImpl.
+ ChildThreadMessageRouter router_;
+
+ // Handles resource loads for this process.
+ scoped_ptr<ResourceDispatcher> resource_dispatcher_;
+
+ scoped_ptr<WebSocketDispatcher> websocket_dispatcher_;
+
+ // The OnChannelError() callback was invoked - the channel is dead, don't
+ // attempt to communicate.
+ bool on_channel_error_called_;
+
+ base::MessageLoop* message_loop_;
+
+ scoped_ptr<FileSystemDispatcher> file_system_dispatcher_;
+
+ scoped_ptr<QuotaDispatcher> quota_dispatcher_;
+
+ scoped_refptr<ChildHistogramMessageFilter> histogram_message_filter_;
+
+ scoped_refptr<ChildResourceMessageFilter> resource_message_filter_;
+
+ scoped_refptr<ServiceWorkerMessageFilter> service_worker_message_filter_;
+
+ scoped_refptr<QuotaMessageFilter> quota_message_filter_;
+
+ scoped_refptr<NotificationDispatcher> notification_dispatcher_;
+
+ scoped_refptr<PushDispatcher> push_dispatcher_;
+
+ scoped_ptr<ChildSharedBitmapManager> shared_bitmap_manager_;
+
+ scoped_ptr<ChildGpuMemoryBufferManager> gpu_memory_buffer_manager_;
+
+ scoped_ptr<ChildDiscardableSharedMemoryManager>
+ discardable_shared_memory_manager_;
+
+ // Observes the trace event system. When tracing is enabled, optionally
+ // starts profiling the tcmalloc heap.
+ scoped_ptr<base::trace_event::TraceMemoryController> trace_memory_controller_;
+
+ scoped_ptr<base::PowerMonitor> power_monitor_;
+
+ scoped_refptr<ChildMessageFilter> geofencing_message_filter_;
+ scoped_refptr<ChildMessageFilter> bluetooth_message_filter_;
+
+ scoped_refptr<NavigatorConnectDispatcher> navigator_connect_dispatcher_;
+
+ scoped_refptr<base::SequencedTaskRunner> browser_process_io_runner_;
+
+ base::WeakPtrFactory<ChildThreadImpl> channel_connected_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ChildThreadImpl);
+};
+
+struct ChildThreadImpl::Options {
+ ~Options();
+
+ class Builder;
+
+ std::string channel_name;
+ bool use_mojo_channel;
+ scoped_refptr<base::SequencedTaskRunner> browser_process_io_runner;
+ std::vector<IPC::MessageFilter*> startup_filters;
+
+ private:
+ Options();
+};
+
+class ChildThreadImpl::Options::Builder {
+ public:
+ Builder();
+
+ Builder& InBrowserProcess(const InProcessChildThreadParams& params);
+ Builder& UseMojoChannel(bool use_mojo_channel);
+ Builder& WithChannelName(const std::string& channel_name);
+ Builder& AddStartupFilter(IPC::MessageFilter* filter);
+
+ Options Build();
+
+ private:
+ struct Options options_;
+
+ DISALLOW_COPY_AND_ASSIGN(Builder);
+};
+
+} // namespace content
+
+#endif // CONTENT_CHILD_CHILD_THREAD_IMPL_H_
diff --git a/chromium/content/child/child_thread_impl_browsertest.cc b/chromium/content/child/child_thread_impl_browsertest.cc
new file mode 100644
index 00000000000..4a37196d77d
--- /dev/null
+++ b/chromium/content/child/child_thread_impl_browsertest.cc
@@ -0,0 +1,116 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/memory/discardable_memory.h"
+#include "base/memory/scoped_vector.h"
+#include "base/time/time.h"
+#include "content/child/child_discardable_shared_memory_manager.h"
+#include "content/child/child_thread_impl.h"
+#include "content/common/host_discardable_shared_memory_manager.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"
+#include "content/shell/browser/shell.h"
+#include "url/gurl.h"
+
+namespace content {
+
+class ChildThreadImplBrowserTest : public ContentBrowserTest {
+ public:
+ ChildThreadImplBrowserTest()
+ : child_discardable_shared_memory_manager_(nullptr) {}
+
+ // Overridden from BrowserTestBase:
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ command_line->AppendSwitch(switches::kSingleProcess);
+ }
+ void SetUpOnMainThread() override {
+ NavigateToURL(shell(), GURL(url::kAboutBlankURL));
+ PostTaskToInProcessRendererAndWait(
+ base::Bind(&ChildThreadImplBrowserTest::SetUpOnChildThread, this));
+ }
+
+ ChildDiscardableSharedMemoryManager*
+ child_discardable_shared_memory_manager() {
+ return child_discardable_shared_memory_manager_;
+ }
+
+ private:
+ void SetUpOnChildThread() {
+ child_discardable_shared_memory_manager_ =
+ ChildThreadImpl::current()->discardable_shared_memory_manager();
+ }
+
+ ChildDiscardableSharedMemoryManager* child_discardable_shared_memory_manager_;
+};
+
+IN_PROC_BROWSER_TEST_F(ChildThreadImplBrowserTest,
+ DISABLED_LockDiscardableMemory) {
+ const size_t kSize = 1024 * 1024; // 1MiB.
+
+ scoped_ptr<base::DiscardableMemory> memory =
+ child_discardable_shared_memory_manager()
+ ->AllocateLockedDiscardableMemory(kSize);
+
+ ASSERT_TRUE(memory);
+ void* addr = memory->data();
+ ASSERT_NE(nullptr, addr);
+
+ memory->Unlock();
+
+ // Purge all unlocked memory.
+ HostDiscardableSharedMemoryManager::current()->SetMemoryLimit(0);
+
+ // Should fail as memory should have been purged.
+ EXPECT_FALSE(memory->Lock());
+}
+
+IN_PROC_BROWSER_TEST_F(ChildThreadImplBrowserTest,
+ DISABLED_DiscardableMemoryAddressSpace) {
+ const size_t kLargeSize = 4 * 1024 * 1024; // 4MiB.
+ const size_t kNumberOfInstances = 1024 + 1; // >4GiB total.
+
+ ScopedVector<base::DiscardableMemory> instances;
+ for (size_t i = 0; i < kNumberOfInstances; ++i) {
+ scoped_ptr<base::DiscardableMemory> memory =
+ child_discardable_shared_memory_manager()
+ ->AllocateLockedDiscardableMemory(kLargeSize);
+ ASSERT_TRUE(memory);
+ void* addr = memory->data();
+ ASSERT_NE(nullptr, addr);
+ memory->Unlock();
+ instances.push_back(memory.Pass());
+ }
+}
+
+IN_PROC_BROWSER_TEST_F(ChildThreadImplBrowserTest,
+ DISABLED_ReleaseFreeDiscardableMemory) {
+ const size_t kSize = 1024 * 1024; // 1MiB.
+
+ scoped_ptr<base::DiscardableMemory> memory =
+ child_discardable_shared_memory_manager()
+ ->AllocateLockedDiscardableMemory(kSize);
+
+ EXPECT_TRUE(memory);
+ memory.reset();
+
+ EXPECT_GE(HostDiscardableSharedMemoryManager::current()->GetBytesAllocated(),
+ kSize);
+
+ child_discardable_shared_memory_manager()->ReleaseFreeMemory();
+
+ // Busy wait for host memory usage to be reduced.
+ base::TimeTicks end =
+ base::TimeTicks::Now() + base::TimeDelta::FromSeconds(5);
+ while (base::TimeTicks::Now() < end) {
+ if (!HostDiscardableSharedMemoryManager::current()->GetBytesAllocated())
+ break;
+ }
+
+ EXPECT_LT(base::TimeTicks::Now(), end);
+}
+
+} // content
diff --git a/chromium/content/child/database_util.cc b/chromium/content/child/database_util.cc
index 34cf1575a38..3a0e80b266a 100644
--- a/chromium/content/child/database_util.cc
+++ b/chromium/content/child/database_util.cc
@@ -21,8 +21,7 @@ Platform::FileHandle DatabaseUtil::DatabaseOpenFile(
IPC::PlatformFileForTransit file_handle =
IPC::InvalidPlatformFileForTransit();
- scoped_refptr<IPC::SyncMessageFilter> filter(sync_message_filter);
- filter->Send(new DatabaseHostMsg_OpenFile(
+ sync_message_filter->Send(new DatabaseHostMsg_OpenFile(
vfs_file_name, desired_flags, &file_handle));
return IPC::PlatformFileForTransitToPlatformFile(file_handle);
@@ -33,9 +32,8 @@ int DatabaseUtil::DatabaseDeleteFile(
bool sync_dir,
IPC::SyncMessageFilter* sync_message_filter) {
int rv = SQLITE_IOERR_DELETE;
- scoped_refptr<IPC::SyncMessageFilter> filter(sync_message_filter);
- filter->Send(new DatabaseHostMsg_DeleteFile(
- vfs_file_name, sync_dir, &rv));
+ sync_message_filter->Send(
+ new DatabaseHostMsg_DeleteFile(vfs_file_name, sync_dir, &rv));
return rv;
}
@@ -43,8 +41,8 @@ long DatabaseUtil::DatabaseGetFileAttributes(
const WebString& vfs_file_name,
IPC::SyncMessageFilter* sync_message_filter) {
int32 rv = -1;
- scoped_refptr<IPC::SyncMessageFilter> filter(sync_message_filter);
- filter->Send(new DatabaseHostMsg_GetFileAttributes(vfs_file_name, &rv));
+ sync_message_filter->Send(
+ new DatabaseHostMsg_GetFileAttributes(vfs_file_name, &rv));
return rv;
}
@@ -52,8 +50,8 @@ long long DatabaseUtil::DatabaseGetFileSize(
const WebString& vfs_file_name,
IPC::SyncMessageFilter* sync_message_filter) {
int64 rv = 0LL;
- scoped_refptr<IPC::SyncMessageFilter> filter(sync_message_filter);
- filter->Send(new DatabaseHostMsg_GetFileSize(vfs_file_name, &rv));
+ sync_message_filter->Send(
+ new DatabaseHostMsg_GetFileSize(vfs_file_name, &rv));
return rv;
}
@@ -61,9 +59,18 @@ long long DatabaseUtil::DatabaseGetSpaceAvailable(
const WebString& origin_identifier,
IPC::SyncMessageFilter* sync_message_filter) {
int64 rv = 0LL;
- scoped_refptr<IPC::SyncMessageFilter> filter(sync_message_filter);
- filter->Send(new DatabaseHostMsg_GetSpaceAvailable(origin_identifier.utf8(),
- &rv));
+ sync_message_filter->Send(
+ new DatabaseHostMsg_GetSpaceAvailable(origin_identifier.utf8(), &rv));
+ return rv;
+}
+
+bool DatabaseUtil::DatabaseSetFileSize(
+ const WebString& vfs_file_name,
+ int64 size,
+ IPC::SyncMessageFilter* sync_message_filter) {
+ bool rv = false;
+ sync_message_filter->Send(
+ new DatabaseHostMsg_SetFileSize(vfs_file_name, size, &rv));
return rv;
}
diff --git a/chromium/content/child/database_util.h b/chromium/content/child/database_util.h
index c53e7cef732..1449d6bf0e8 100644
--- a/chromium/content/child/database_util.h
+++ b/chromium/content/child/database_util.h
@@ -34,6 +34,10 @@ class DatabaseUtil {
static long long DatabaseGetSpaceAvailable(
const blink::WebString& origin_identifier,
IPC::SyncMessageFilter* sync_message_filter);
+ static bool DatabaseSetFileSize(
+ const blink::WebString& vfs_file_name,
+ int64 size,
+ IPC::SyncMessageFilter* sync_message_filter);
};
} // namespace content
diff --git a/chromium/content/child/file_info_util.cc b/chromium/content/child/file_info_util.cc
index c605adfd6cf..40a11fbce5a 100644
--- a/chromium/content/child/file_info_util.cc
+++ b/chromium/content/child/file_info_util.cc
@@ -12,11 +12,11 @@ namespace content {
void FileInfoToWebFileInfo(const base::File::Info& file_info,
blink::WebFileInfo* web_file_info) {
DCHECK(web_file_info);
- // WebKit now expects NaN as uninitialized/null Date.
+ // Blink now expects NaN as uninitialized/null Date.
if (file_info.last_modified.is_null())
web_file_info->modificationTime = std::numeric_limits<double>::quiet_NaN();
else
- web_file_info->modificationTime = file_info.last_modified.ToDoubleT();
+ web_file_info->modificationTime = file_info.last_modified.ToJsTime();
web_file_info->length = file_info.size;
if (file_info.is_directory)
web_file_info->type = blink::WebFileInfo::TypeDirectory;
@@ -24,6 +24,7 @@ void FileInfoToWebFileInfo(const base::File::Info& file_info,
web_file_info->type = blink::WebFileInfo::TypeFile;
}
-COMPILE_ASSERT(std::numeric_limits<double>::has_quiet_NaN, has_quiet_NaN);
+static_assert(std::numeric_limits<double>::has_quiet_NaN,
+ "should have quiet NaN");
} // namespace content
diff --git a/chromium/content/child/fileapi/file_system_dispatcher.cc b/chromium/content/child/fileapi/file_system_dispatcher.cc
index 8ba8764ead4..1a742db2631 100644
--- a/chromium/content/child/fileapi/file_system_dispatcher.cc
+++ b/chromium/content/child/fileapi/file_system_dispatcher.cc
@@ -8,7 +8,7 @@
#include "base/files/file_util.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/process/process.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
#include "content/common/fileapi/file_system_messages.h"
#include "storage/common/fileapi/file_system_info.h"
@@ -171,7 +171,7 @@ void FileSystemDispatcher::OpenFileSystem(
const StatusCallback& error_callback) {
int request_id = dispatchers_.Add(
CallbackDispatcher::Create(success_callback, error_callback));
- ChildThread::current()->Send(new FileSystemHostMsg_OpenFileSystem(
+ ChildThreadImpl::current()->Send(new FileSystemHostMsg_OpenFileSystem(
request_id, origin_url, type));
}
@@ -181,7 +181,7 @@ void FileSystemDispatcher::ResolveURL(
const StatusCallback& error_callback) {
int request_id = dispatchers_.Add(
CallbackDispatcher::Create(success_callback, error_callback));
- ChildThread::current()->Send(new FileSystemHostMsg_ResolveURL(
+ ChildThreadImpl::current()->Send(new FileSystemHostMsg_ResolveURL(
request_id, filesystem_url));
}
@@ -189,7 +189,7 @@ void FileSystemDispatcher::DeleteFileSystem(const GURL& origin_url,
storage::FileSystemType type,
const StatusCallback& callback) {
int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback));
- ChildThread::current()->Send(new FileSystemHostMsg_DeleteFileSystem(
+ ChildThreadImpl::current()->Send(new FileSystemHostMsg_DeleteFileSystem(
request_id, origin_url, type));
}
@@ -198,7 +198,7 @@ void FileSystemDispatcher::Move(
const GURL& dest_path,
const StatusCallback& callback) {
int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback));
- ChildThread::current()->Send(new FileSystemHostMsg_Move(
+ ChildThreadImpl::current()->Send(new FileSystemHostMsg_Move(
request_id, src_path, dest_path));
}
@@ -207,7 +207,7 @@ void FileSystemDispatcher::Copy(
const GURL& dest_path,
const StatusCallback& callback) {
int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback));
- ChildThread::current()->Send(new FileSystemHostMsg_Copy(
+ ChildThreadImpl::current()->Send(new FileSystemHostMsg_Copy(
request_id, src_path, dest_path));
}
@@ -216,7 +216,7 @@ void FileSystemDispatcher::Remove(
bool recursive,
const StatusCallback& callback) {
int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback));
- ChildThread::current()->Send(
+ ChildThreadImpl::current()->Send(
new FileSystemHostMsg_Remove(request_id, path, recursive));
}
@@ -226,7 +226,7 @@ void FileSystemDispatcher::ReadMetadata(
const StatusCallback& error_callback) {
int request_id = dispatchers_.Add(
CallbackDispatcher::Create(success_callback, error_callback));
- ChildThread::current()->Send(
+ ChildThreadImpl::current()->Send(
new FileSystemHostMsg_ReadMetadata(request_id, path));
}
@@ -235,7 +235,7 @@ void FileSystemDispatcher::CreateFile(
bool exclusive,
const StatusCallback& callback) {
int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback));
- ChildThread::current()->Send(new FileSystemHostMsg_Create(
+ ChildThreadImpl::current()->Send(new FileSystemHostMsg_Create(
request_id, path, exclusive,
false /* is_directory */, false /* recursive */));
}
@@ -246,7 +246,7 @@ void FileSystemDispatcher::CreateDirectory(
bool recursive,
const StatusCallback& callback) {
int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback));
- ChildThread::current()->Send(new FileSystemHostMsg_Create(
+ ChildThreadImpl::current()->Send(new FileSystemHostMsg_Create(
request_id, path, exclusive, true /* is_directory */, recursive));
}
@@ -255,7 +255,7 @@ void FileSystemDispatcher::Exists(
bool is_directory,
const StatusCallback& callback) {
int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback));
- ChildThread::current()->Send(
+ ChildThreadImpl::current()->Send(
new FileSystemHostMsg_Exists(request_id, path, is_directory));
}
@@ -265,7 +265,7 @@ void FileSystemDispatcher::ReadDirectory(
const StatusCallback& error_callback) {
int request_id = dispatchers_.Add(
CallbackDispatcher::Create(success_callback, error_callback));
- ChildThread::current()->Send(
+ ChildThreadImpl::current()->Send(
new FileSystemHostMsg_ReadDirectory(request_id, path));
}
@@ -275,7 +275,7 @@ void FileSystemDispatcher::Truncate(
int* request_id_out,
const StatusCallback& callback) {
int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback));
- ChildThread::current()->Send(
+ ChildThreadImpl::current()->Send(
new FileSystemHostMsg_Truncate(request_id, path, offset));
if (request_id_out)
@@ -291,7 +291,7 @@ void FileSystemDispatcher::Write(
const StatusCallback& error_callback) {
int request_id = dispatchers_.Add(
CallbackDispatcher::Create(success_callback, error_callback));
- ChildThread::current()->Send(
+ ChildThreadImpl::current()->Send(
new FileSystemHostMsg_Write(request_id, path, blob_id, offset));
if (request_id_out)
@@ -302,7 +302,7 @@ void FileSystemDispatcher::Cancel(
int request_id_to_cancel,
const StatusCallback& callback) {
int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback));
- ChildThread::current()->Send(new FileSystemHostMsg_CancelWrite(
+ ChildThreadImpl::current()->Send(new FileSystemHostMsg_CancelWrite(
request_id, request_id_to_cancel));
}
@@ -312,7 +312,7 @@ void FileSystemDispatcher::TouchFile(
const base::Time& last_modified_time,
const StatusCallback& callback) {
int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback));
- ChildThread::current()->Send(
+ ChildThreadImpl::current()->Send(
new FileSystemHostMsg_TouchFile(
request_id, path, last_access_time, last_modified_time));
}
@@ -323,7 +323,7 @@ void FileSystemDispatcher::CreateSnapshotFile(
const StatusCallback& error_callback) {
int request_id = dispatchers_.Add(
CallbackDispatcher::Create(success_callback, error_callback));
- ChildThread::current()->Send(
+ ChildThreadImpl::current()->Send(
new FileSystemHostMsg_CreateSnapshotFile(
request_id, file_path));
}
diff --git a/chromium/content/child/fileapi/webfilesystem_impl.cc b/chromium/content/child/fileapi/webfilesystem_impl.cc
index 6bc18eeca06..c791e8d01ac 100644
--- a/chromium/content/child/fileapi/webfilesystem_impl.cc
+++ b/chromium/content/child/fileapi/webfilesystem_impl.cc
@@ -10,12 +10,12 @@
#include "base/message_loop/message_loop_proxy.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/waitable_event.h"
+#include "base/thread_task_runner_handle.h"
#include "base/threading/thread_local.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
#include "content/child/file_info_util.h"
#include "content/child/fileapi/file_system_dispatcher.h"
#include "content/child/fileapi/webfilewriter_impl.h"
-#include "content/child/worker_task_runner.h"
#include "content/common/fileapi/file_system_messages.h"
#include "storage/common/fileapi/directory_entry.h"
#include "storage/common/fileapi/file_system_util.h"
@@ -86,35 +86,32 @@ base::LazyInstance<base::ThreadLocalPointer<WebFileSystemImpl> >::Leaky
g_webfilesystem_tls = LAZY_INSTANCE_INITIALIZER;
void DidReceiveSnapshotFile(int request_id) {
- if (ChildThread::current())
- ChildThread::current()->Send(
+ if (ChildThreadImpl::current())
+ ChildThreadImpl::current()->Send(
new FileSystemHostMsg_DidReceiveSnapshotFile(request_id));
}
-int CurrentWorkerId() {
- return WorkerTaskRunner::Instance()->CurrentWorkerId();
-}
-
template <typename Method, typename Params>
void CallDispatcherOnMainThread(
- base::MessageLoopProxy* loop,
+ const scoped_refptr<base::SingleThreadTaskRunner>& main_thread_task_runner,
Method method, const Params& params,
WaitableCallbackResults* waitable_results) {
- if (!loop->RunsTasksOnCurrentThread()) {
- loop->PostTask(FROM_HERE,
- base::Bind(&CallDispatcherOnMainThread<Method, Params>,
- make_scoped_refptr(loop), method, params,
- scoped_refptr<WaitableCallbackResults>()));
+ if (!main_thread_task_runner->RunsTasksOnCurrentThread()) {
+ main_thread_task_runner->PostTask(
+ FROM_HERE,
+ base::Bind(&CallDispatcherOnMainThread<Method, Params>,
+ main_thread_task_runner, method, params,
+ scoped_refptr<WaitableCallbackResults>()));
if (!waitable_results)
return;
waitable_results->WaitAndRun();
}
- if (!ChildThread::current() ||
- !ChildThread::current()->file_system_dispatcher())
+ if (!ChildThreadImpl::current() ||
+ !ChildThreadImpl::current()->file_system_dispatcher())
return;
DCHECK(!waitable_results);
- DispatchToMethod(ChildThread::current()->file_system_dispatcher(),
+ DispatchToMethod(ChildThreadImpl::current()->file_system_dispatcher(),
method, params);
}
@@ -190,35 +187,37 @@ void RunCallbacks(
callback.Run(&callbacks);
}
-void DispatchResultsClosure(int thread_id, int callbacks_id,
- WaitableCallbackResults* waitable_results,
- const base::Closure& results_closure) {
- if (thread_id != CurrentWorkerId()) {
- if (waitable_results) {
- // If someone is waiting, this should result in running the closure.
- waitable_results->AddResultsAndSignal(results_closure);
- // In case no one is waiting, post a task to run the closure.
- WorkerTaskRunner::Instance()->PostTask(
- thread_id,
- base::Bind(&WaitableCallbackResults::Run,
- make_scoped_refptr(waitable_results)));
- return;
- }
- WorkerTaskRunner::Instance()->PostTask(thread_id, results_closure);
+void DispatchResultsClosure(
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+ int callbacks_id,
+ WaitableCallbackResults* waitable_results,
+ const base::Closure& results_closure) {
+ if (task_runner->BelongsToCurrentThread()) {
+ results_closure.Run();
return;
}
- results_closure.Run();
+
+ if (waitable_results) {
+ // If someone is waiting, this should result in running the closure.
+ waitable_results->AddResultsAndSignal(results_closure);
+ // In case no one is waiting, post a task to run the closure.
+ task_runner->PostTask(FROM_HERE,
+ base::Bind(&WaitableCallbackResults::Run,
+ make_scoped_refptr(waitable_results)));
+ return;
+ }
+ task_runner->PostTask(FROM_HERE, results_closure);
}
void CallbackFileSystemCallbacks(
- int thread_id, int callbacks_id,
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+ int callbacks_id,
WaitableCallbackResults* waitable_results,
const base::Callback<void(WebFileSystemCallbacks*)>& callback,
CallbacksUnregisterMode callbacksunregister_mode) {
- DispatchResultsClosure(
- thread_id, callbacks_id, waitable_results,
- base::Bind(&RunCallbacks, callbacks_id, callback,
- callbacksunregister_mode));
+ DispatchResultsClosure(task_runner, callbacks_id, waitable_results,
+ base::Bind(&RunCallbacks, callbacks_id, callback,
+ callbacksunregister_mode));
}
//-----------------------------------------------------------------------------
@@ -227,64 +226,67 @@ void CallbackFileSystemCallbacks(
// if necessary.
void OpenFileSystemCallbackAdapter(
- int thread_id, int callbacks_id,
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+ int callbacks_id,
WaitableCallbackResults* waitable_results,
- const std::string& name, const GURL& root) {
+ const std::string& name,
+ const GURL& root) {
CallbackFileSystemCallbacks(
- thread_id, callbacks_id, waitable_results,
+ task_runner, callbacks_id, waitable_results,
base::Bind(&DidOpenFileSystem, base::UTF8ToUTF16(name), root),
UNREGISTER_CALLBACKS);
}
-void ResolveURLCallbackAdapter(int thread_id,
- int callbacks_id,
- WaitableCallbackResults* waitable_results,
- const storage::FileSystemInfo& info,
- const base::FilePath& file_path,
- bool is_directory) {
+void ResolveURLCallbackAdapter(
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+ int callbacks_id,
+ WaitableCallbackResults* waitable_results,
+ const storage::FileSystemInfo& info,
+ const base::FilePath& file_path,
+ bool is_directory) {
base::FilePath normalized_path(
storage::VirtualPath::GetNormalizedFilePath(file_path));
CallbackFileSystemCallbacks(
- thread_id, callbacks_id, waitable_results,
+ task_runner, callbacks_id, waitable_results,
base::Bind(&DidResolveURL, base::UTF8ToUTF16(info.name), info.root_url,
- info.mount_type,
- normalized_path.AsUTF16Unsafe(), is_directory),
+ info.mount_type, normalized_path.AsUTF16Unsafe(),
+ is_directory),
UNREGISTER_CALLBACKS);
}
-void StatusCallbackAdapter(int thread_id, int callbacks_id,
- WaitableCallbackResults* waitable_results,
- base::File::Error error) {
+void StatusCallbackAdapter(
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+ int callbacks_id,
+ WaitableCallbackResults* waitable_results,
+ base::File::Error error) {
if (error == base::File::FILE_OK) {
- CallbackFileSystemCallbacks(
- thread_id, callbacks_id, waitable_results,
- base::Bind(&DidSucceed),
- UNREGISTER_CALLBACKS);
+ CallbackFileSystemCallbacks(task_runner, callbacks_id, waitable_results,
+ base::Bind(&DidSucceed), UNREGISTER_CALLBACKS);
} else {
- CallbackFileSystemCallbacks(
- thread_id, callbacks_id, waitable_results,
- base::Bind(&DidFail, error),
- UNREGISTER_CALLBACKS);
+ CallbackFileSystemCallbacks(task_runner, callbacks_id, waitable_results,
+ base::Bind(&DidFail, error),
+ UNREGISTER_CALLBACKS);
}
}
-void ReadMetadataCallbackAdapter(int thread_id, int callbacks_id,
- WaitableCallbackResults* waitable_results,
- const base::File::Info& file_info) {
- CallbackFileSystemCallbacks(
- thread_id, callbacks_id, waitable_results,
- base::Bind(&DidReadMetadata, file_info),
- UNREGISTER_CALLBACKS);
+void ReadMetadataCallbackAdapter(
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+ int callbacks_id,
+ WaitableCallbackResults* waitable_results,
+ const base::File::Info& file_info) {
+ CallbackFileSystemCallbacks(task_runner, callbacks_id, waitable_results,
+ base::Bind(&DidReadMetadata, file_info),
+ UNREGISTER_CALLBACKS);
}
void ReadDirectoryCallbackAdapter(
- int thread_id,
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
int callbacks_id,
WaitableCallbackResults* waitable_results,
const std::vector<storage::DirectoryEntry>& entries,
bool has_more) {
CallbackFileSystemCallbacks(
- thread_id, callbacks_id, waitable_results,
+ task_runner, callbacks_id, waitable_results,
base::Bind(&DidReadDirectory, entries, has_more),
has_more ? DO_NOT_UNREGISTER_CALLBACKS : UNREGISTER_CALLBACKS);
}
@@ -293,7 +295,7 @@ void DidCreateFileWriter(
int callbacks_id,
const GURL& path,
blink::WebFileWriterClient* client,
- base::MessageLoopProxy* main_thread_loop,
+ const scoped_refptr<base::SingleThreadTaskRunner>& main_thread_task_runner,
const base::File::Info& file_info) {
WebFileSystemImpl* filesystem =
WebFileSystemImpl::ThreadSpecificInstance(NULL);
@@ -311,26 +313,27 @@ void DidCreateFileWriter(
callbacks.shouldBlockUntilCompletion() ?
WebFileWriterImpl::TYPE_SYNC : WebFileWriterImpl::TYPE_ASYNC;
callbacks.didCreateFileWriter(
- new WebFileWriterImpl(path, client, type, main_thread_loop),
+ new WebFileWriterImpl(path, client, type, main_thread_task_runner),
file_info.size);
}
void CreateFileWriterCallbackAdapter(
- int thread_id, int callbacks_id,
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+ int callbacks_id,
WaitableCallbackResults* waitable_results,
- base::MessageLoopProxy* main_thread_loop,
+ const scoped_refptr<base::SingleThreadTaskRunner>& main_thread_task_runner,
const GURL& path,
blink::WebFileWriterClient* client,
const base::File::Info& file_info) {
DispatchResultsClosure(
- thread_id, callbacks_id, waitable_results,
+ task_runner, callbacks_id, waitable_results,
base::Bind(&DidCreateFileWriter, callbacks_id, path, client,
- make_scoped_refptr(main_thread_loop), file_info));
+ main_thread_task_runner, file_info));
}
void DidCreateSnapshotFile(
int callbacks_id,
- base::MessageLoopProxy* main_thread_loop,
+ const scoped_refptr<base::SingleThreadTaskRunner>& main_thread_task_runner,
const base::File::Info& file_info,
const base::FilePath& platform_path,
int request_id) {
@@ -349,21 +352,21 @@ void DidCreateSnapshotFile(
// TODO(michaeln,kinuko): Use ThreadSafeSender when Blob becomes
// non-bridge model.
- main_thread_loop->PostTask(
+ main_thread_task_runner->PostTask(
FROM_HERE, base::Bind(&DidReceiveSnapshotFile, request_id));
}
void CreateSnapshotFileCallbackAdapter(
- int thread_id, int callbacks_id,
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+ int callbacks_id,
WaitableCallbackResults* waitable_results,
- base::MessageLoopProxy* main_thread_loop,
+ const scoped_refptr<base::SingleThreadTaskRunner>& main_thread_task_runner,
const base::File::Info& file_info,
const base::FilePath& platform_path,
int request_id) {
DispatchResultsClosure(
- thread_id, callbacks_id, waitable_results,
- base::Bind(&DidCreateSnapshotFile, callbacks_id,
- make_scoped_refptr(main_thread_loop),
+ task_runner, callbacks_id, waitable_results,
+ base::Bind(&DidCreateSnapshotFile, callbacks_id, main_thread_task_runner,
file_info, platform_path, request_id));
}
@@ -373,10 +376,12 @@ void CreateSnapshotFileCallbackAdapter(
// WebFileSystemImpl
WebFileSystemImpl* WebFileSystemImpl::ThreadSpecificInstance(
- base::MessageLoopProxy* main_thread_loop) {
- if (g_webfilesystem_tls.Pointer()->Get() || !main_thread_loop)
+ const scoped_refptr<base::SingleThreadTaskRunner>&
+ main_thread_task_runner) {
+ if (g_webfilesystem_tls.Pointer()->Get() || !main_thread_task_runner.get())
return g_webfilesystem_tls.Pointer()->Get();
- WebFileSystemImpl* filesystem = new WebFileSystemImpl(main_thread_loop);
+ WebFileSystemImpl* filesystem =
+ new WebFileSystemImpl(main_thread_task_runner);
if (WorkerTaskRunner::Instance()->CurrentWorkerId())
WorkerTaskRunner::Instance()->AddStopObserver(filesystem);
return filesystem;
@@ -388,8 +393,9 @@ void WebFileSystemImpl::DeleteThreadSpecificInstance() {
delete g_webfilesystem_tls.Pointer()->Get();
}
-WebFileSystemImpl::WebFileSystemImpl(base::MessageLoopProxy* main_thread_loop)
- : main_thread_loop_(main_thread_loop),
+WebFileSystemImpl::WebFileSystemImpl(
+ const scoped_refptr<base::SingleThreadTaskRunner>& main_thread_task_runner)
+ : main_thread_task_runner_(main_thread_task_runner),
next_callbacks_id_(1) {
g_webfilesystem_tls.Pointer()->Set(this);
}
@@ -410,17 +416,14 @@ void WebFileSystemImpl::openFileSystem(
scoped_refptr<WaitableCallbackResults> waitable_results =
MaybeCreateWaitableResults(callbacks, callbacks_id);
CallDispatcherOnMainThread(
- main_thread_loop_.get(),
- &FileSystemDispatcher::OpenFileSystem,
+ main_thread_task_runner_, &FileSystemDispatcher::OpenFileSystem,
MakeTuple(GURL(storage_partition),
static_cast<storage::FileSystemType>(type),
base::Bind(&OpenFileSystemCallbackAdapter,
- CurrentWorkerId(),
- callbacks_id,
+ base::ThreadTaskRunnerHandle::Get(), callbacks_id,
waitable_results),
base::Bind(&StatusCallbackAdapter,
- CurrentWorkerId(),
- callbacks_id,
+ base::ThreadTaskRunnerHandle::Get(), callbacks_id,
waitable_results)),
waitable_results.get());
}
@@ -432,13 +435,14 @@ void WebFileSystemImpl::resolveURL(
scoped_refptr<WaitableCallbackResults> waitable_results =
MaybeCreateWaitableResults(callbacks, callbacks_id);
CallDispatcherOnMainThread(
- main_thread_loop_.get(),
- &FileSystemDispatcher::ResolveURL,
+ main_thread_task_runner_, &FileSystemDispatcher::ResolveURL,
MakeTuple(GURL(filesystem_url),
base::Bind(&ResolveURLCallbackAdapter,
- CurrentWorkerId(), callbacks_id, waitable_results),
+ base::ThreadTaskRunnerHandle::Get(), callbacks_id,
+ waitable_results),
base::Bind(&StatusCallbackAdapter,
- CurrentWorkerId(), callbacks_id, waitable_results)),
+ base::ThreadTaskRunnerHandle::Get(), callbacks_id,
+ waitable_results)),
waitable_results.get());
}
@@ -450,13 +454,11 @@ void WebFileSystemImpl::deleteFileSystem(
scoped_refptr<WaitableCallbackResults> waitable_results =
MaybeCreateWaitableResults(callbacks, callbacks_id);
CallDispatcherOnMainThread(
- main_thread_loop_.get(),
- &FileSystemDispatcher::DeleteFileSystem,
+ main_thread_task_runner_, &FileSystemDispatcher::DeleteFileSystem,
MakeTuple(GURL(storage_partition),
static_cast<storage::FileSystemType>(type),
base::Bind(&StatusCallbackAdapter,
- CurrentWorkerId(),
- callbacks_id,
+ base::ThreadTaskRunnerHandle::Get(), callbacks_id,
waitable_results)),
waitable_results.get());
}
@@ -469,11 +471,11 @@ void WebFileSystemImpl::move(
scoped_refptr<WaitableCallbackResults> waitable_results =
MaybeCreateWaitableResults(callbacks, callbacks_id);
CallDispatcherOnMainThread(
- main_thread_loop_.get(),
- &FileSystemDispatcher::Move,
+ main_thread_task_runner_, &FileSystemDispatcher::Move,
MakeTuple(GURL(src_path), GURL(dest_path),
base::Bind(&StatusCallbackAdapter,
- CurrentWorkerId(), callbacks_id, waitable_results)),
+ base::ThreadTaskRunnerHandle::Get(), callbacks_id,
+ waitable_results)),
waitable_results.get());
}
@@ -485,11 +487,11 @@ void WebFileSystemImpl::copy(
scoped_refptr<WaitableCallbackResults> waitable_results =
MaybeCreateWaitableResults(callbacks, callbacks_id);
CallDispatcherOnMainThread(
- main_thread_loop_.get(),
- &FileSystemDispatcher::Copy,
+ main_thread_task_runner_, &FileSystemDispatcher::Copy,
MakeTuple(GURL(src_path), GURL(dest_path),
base::Bind(&StatusCallbackAdapter,
- CurrentWorkerId(), callbacks_id, waitable_results)),
+ base::ThreadTaskRunnerHandle::Get(), callbacks_id,
+ waitable_results)),
waitable_results.get());
}
@@ -500,11 +502,11 @@ void WebFileSystemImpl::remove(
scoped_refptr<WaitableCallbackResults> waitable_results =
MaybeCreateWaitableResults(callbacks, callbacks_id);
CallDispatcherOnMainThread(
- main_thread_loop_.get(),
- &FileSystemDispatcher::Remove,
+ main_thread_task_runner_, &FileSystemDispatcher::Remove,
MakeTuple(GURL(path), false /* recursive */,
base::Bind(&StatusCallbackAdapter,
- CurrentWorkerId(), callbacks_id, waitable_results)),
+ base::ThreadTaskRunnerHandle::Get(), callbacks_id,
+ waitable_results)),
waitable_results.get());
}
@@ -515,11 +517,11 @@ void WebFileSystemImpl::removeRecursively(
scoped_refptr<WaitableCallbackResults> waitable_results =
MaybeCreateWaitableResults(callbacks, callbacks_id);
CallDispatcherOnMainThread(
- main_thread_loop_.get(),
- &FileSystemDispatcher::Remove,
+ main_thread_task_runner_, &FileSystemDispatcher::Remove,
MakeTuple(GURL(path), true /* recursive */,
base::Bind(&StatusCallbackAdapter,
- CurrentWorkerId(), callbacks_id, waitable_results)),
+ base::ThreadTaskRunnerHandle::Get(), callbacks_id,
+ waitable_results)),
waitable_results.get());
}
@@ -530,13 +532,13 @@ void WebFileSystemImpl::readMetadata(
scoped_refptr<WaitableCallbackResults> waitable_results =
MaybeCreateWaitableResults(callbacks, callbacks_id);
CallDispatcherOnMainThread(
- main_thread_loop_.get(),
- &FileSystemDispatcher::ReadMetadata,
- MakeTuple(GURL(path),
- base::Bind(&ReadMetadataCallbackAdapter,
- CurrentWorkerId(), callbacks_id, waitable_results),
+ main_thread_task_runner_, &FileSystemDispatcher::ReadMetadata,
+ MakeTuple(GURL(path), base::Bind(&ReadMetadataCallbackAdapter,
+ base::ThreadTaskRunnerHandle::Get(),
+ callbacks_id, waitable_results),
base::Bind(&StatusCallbackAdapter,
- CurrentWorkerId(), callbacks_id, waitable_results)),
+ base::ThreadTaskRunnerHandle::Get(), callbacks_id,
+ waitable_results)),
waitable_results.get());
}
@@ -548,11 +550,11 @@ void WebFileSystemImpl::createFile(
scoped_refptr<WaitableCallbackResults> waitable_results =
MaybeCreateWaitableResults(callbacks, callbacks_id);
CallDispatcherOnMainThread(
- main_thread_loop_.get(),
- &FileSystemDispatcher::CreateFile,
+ main_thread_task_runner_, &FileSystemDispatcher::CreateFile,
MakeTuple(GURL(path), exclusive,
base::Bind(&StatusCallbackAdapter,
- CurrentWorkerId(), callbacks_id, waitable_results)),
+ base::ThreadTaskRunnerHandle::Get(), callbacks_id,
+ waitable_results)),
waitable_results.get());
}
@@ -564,11 +566,11 @@ void WebFileSystemImpl::createDirectory(
scoped_refptr<WaitableCallbackResults> waitable_results =
MaybeCreateWaitableResults(callbacks, callbacks_id);
CallDispatcherOnMainThread(
- main_thread_loop_.get(),
- &FileSystemDispatcher::CreateDirectory,
+ main_thread_task_runner_, &FileSystemDispatcher::CreateDirectory,
MakeTuple(GURL(path), exclusive, false /* recursive */,
base::Bind(&StatusCallbackAdapter,
- CurrentWorkerId(), callbacks_id, waitable_results)),
+ base::ThreadTaskRunnerHandle::Get(), callbacks_id,
+ waitable_results)),
waitable_results.get());
}
@@ -579,11 +581,11 @@ void WebFileSystemImpl::fileExists(
scoped_refptr<WaitableCallbackResults> waitable_results =
MaybeCreateWaitableResults(callbacks, callbacks_id);
CallDispatcherOnMainThread(
- main_thread_loop_.get(),
- &FileSystemDispatcher::Exists,
+ main_thread_task_runner_, &FileSystemDispatcher::Exists,
MakeTuple(GURL(path), false /* directory */,
base::Bind(&StatusCallbackAdapter,
- CurrentWorkerId(), callbacks_id, waitable_results)),
+ base::ThreadTaskRunnerHandle::Get(), callbacks_id,
+ waitable_results)),
waitable_results.get());
}
@@ -594,11 +596,11 @@ void WebFileSystemImpl::directoryExists(
scoped_refptr<WaitableCallbackResults> waitable_results =
MaybeCreateWaitableResults(callbacks, callbacks_id);
CallDispatcherOnMainThread(
- main_thread_loop_.get(),
- &FileSystemDispatcher::Exists,
+ main_thread_task_runner_, &FileSystemDispatcher::Exists,
MakeTuple(GURL(path), true /* directory */,
base::Bind(&StatusCallbackAdapter,
- CurrentWorkerId(), callbacks_id, waitable_results)),
+ base::ThreadTaskRunnerHandle::Get(), callbacks_id,
+ waitable_results)),
waitable_results.get());
}
@@ -609,13 +611,13 @@ int WebFileSystemImpl::readDirectory(
scoped_refptr<WaitableCallbackResults> waitable_results =
MaybeCreateWaitableResults(callbacks, callbacks_id);
CallDispatcherOnMainThread(
- main_thread_loop_.get(),
- &FileSystemDispatcher::ReadDirectory,
- MakeTuple(GURL(path),
- base::Bind(&ReadDirectoryCallbackAdapter,
- CurrentWorkerId(), callbacks_id, waitable_results),
+ main_thread_task_runner_, &FileSystemDispatcher::ReadDirectory,
+ MakeTuple(GURL(path), base::Bind(&ReadDirectoryCallbackAdapter,
+ base::ThreadTaskRunnerHandle::Get(),
+ callbacks_id, waitable_results),
base::Bind(&StatusCallbackAdapter,
- CurrentWorkerId(), callbacks_id, waitable_results)),
+ base::ThreadTaskRunnerHandle::Get(), callbacks_id,
+ waitable_results)),
waitable_results.get());
return callbacks_id;
}
@@ -628,14 +630,15 @@ void WebFileSystemImpl::createFileWriter(
scoped_refptr<WaitableCallbackResults> waitable_results =
MaybeCreateWaitableResults(callbacks, callbacks_id);
CallDispatcherOnMainThread(
- main_thread_loop_.get(),
- &FileSystemDispatcher::ReadMetadata,
+ main_thread_task_runner_, &FileSystemDispatcher::ReadMetadata,
MakeTuple(GURL(path),
base::Bind(&CreateFileWriterCallbackAdapter,
- CurrentWorkerId(), callbacks_id, waitable_results,
- main_thread_loop_, GURL(path), client),
+ base::ThreadTaskRunnerHandle::Get(), callbacks_id,
+ waitable_results, main_thread_task_runner_,
+ GURL(path), client),
base::Bind(&StatusCallbackAdapter,
- CurrentWorkerId(), callbacks_id, waitable_results)),
+ base::ThreadTaskRunnerHandle::Get(), callbacks_id,
+ waitable_results)),
waitable_results.get());
}
@@ -646,14 +649,14 @@ void WebFileSystemImpl::createSnapshotFileAndReadMetadata(
scoped_refptr<WaitableCallbackResults> waitable_results =
MaybeCreateWaitableResults(callbacks, callbacks_id);
CallDispatcherOnMainThread(
- main_thread_loop_.get(),
- &FileSystemDispatcher::CreateSnapshotFile,
+ main_thread_task_runner_, &FileSystemDispatcher::CreateSnapshotFile,
MakeTuple(GURL(path),
base::Bind(&CreateSnapshotFileCallbackAdapter,
- CurrentWorkerId(), callbacks_id, waitable_results,
- main_thread_loop_),
+ base::ThreadTaskRunnerHandle::Get(), callbacks_id,
+ waitable_results, main_thread_task_runner_),
base::Bind(&StatusCallbackAdapter,
- CurrentWorkerId(), callbacks_id, waitable_results)),
+ base::ThreadTaskRunnerHandle::Get(), callbacks_id,
+ waitable_results)),
waitable_results.get());
}
diff --git a/chromium/content/child/fileapi/webfilesystem_impl.h b/chromium/content/child/fileapi/webfilesystem_impl.h
index b10a57fbea5..66c78267d8e 100644
--- a/chromium/content/child/fileapi/webfilesystem_impl.h
+++ b/chromium/content/child/fileapi/webfilesystem_impl.h
@@ -15,8 +15,8 @@
#include "third_party/WebKit/public/platform/WebFileSystem.h"
namespace base {
-class MessageLoopProxy;
class WaitableEvent;
+class SingleThreadTaskRunner;
}
namespace blink {
@@ -37,14 +37,17 @@ class WebFileSystemImpl : public blink::WebFileSystem,
// is given and no thread-specific instance has been created it may
// create a new instance.
static WebFileSystemImpl* ThreadSpecificInstance(
- base::MessageLoopProxy* main_thread_loop);
+ const scoped_refptr<base::SingleThreadTaskRunner>&
+ main_thread_task_runner);
// Deletes thread-specific instance (if exists). For workers it deletes
// itself in OnWorkerRunLoopStopped(), but for an instance created on the
// main thread this method must be called.
static void DeleteThreadSpecificInstance();
- explicit WebFileSystemImpl(base::MessageLoopProxy* main_thread_loop);
+ explicit WebFileSystemImpl(
+ const scoped_refptr<base::SingleThreadTaskRunner>&
+ main_thread_task_runner);
virtual ~WebFileSystemImpl();
// WorkerTaskRunner::Observer implementation.
@@ -117,7 +120,7 @@ class WebFileSystemImpl : public blink::WebFileSystem,
WaitableCallbackResults* MaybeCreateWaitableResults(
const blink::WebFileSystemCallbacks& callbacks, int callbacks_id);
- scoped_refptr<base::MessageLoopProxy> main_thread_loop_;
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
CallbacksMap callbacks_;
int next_callbacks_id_;
diff --git a/chromium/content/child/fileapi/webfilewriter_impl.cc b/chromium/content/child/fileapi/webfilewriter_impl.cc
index 7ae6c285d0f..ef16def19a7 100644
--- a/chromium/content/child/fileapi/webfilewriter_impl.cc
+++ b/chromium/content/child/fileapi/webfilewriter_impl.cc
@@ -6,7 +6,8 @@
#include "base/bind.h"
#include "base/synchronization/waitable_event.h"
-#include "content/child/child_thread.h"
+#include "base/thread_task_runner_handle.h"
+#include "content/child/child_thread_impl.h"
#include "content/child/fileapi/file_system_dispatcher.h"
#include "content/child/worker_task_runner.h"
@@ -15,8 +16,8 @@ namespace content {
namespace {
FileSystemDispatcher* GetFileSystemDispatcher() {
- return ChildThread::current() ?
- ChildThread::current()->file_system_dispatcher() : NULL;
+ return ChildThreadImpl::current() ?
+ ChildThreadImpl::current()->file_system_dispatcher() : NULL;
}
} // namespace
@@ -31,7 +32,9 @@ class WebFileWriterImpl::WriterBridge
public:
WriterBridge(WebFileWriterImpl::Type type)
: request_id_(0),
- thread_id_(WorkerTaskRunner::Instance()->CurrentWorkerId()),
+ running_on_worker_(WorkerTaskRunner::Instance()->CurrentWorkerId() > 0),
+ task_runner_(running_on_worker_ ? base::ThreadTaskRunnerHandle::Get()
+ : nullptr),
written_bytes_(0) {
if (type == WebFileWriterImpl::TYPE_SYNC)
waitable_event_.reset(new base::WaitableEvent(false, false));
@@ -42,7 +45,7 @@ class WebFileWriterImpl::WriterBridge
status_callback_ = status_callback;
if (!GetFileSystemDispatcher())
return;
- ChildThread::current()->file_system_dispatcher()->Truncate(
+ ChildThreadImpl::current()->file_system_dispatcher()->Truncate(
path, offset, &request_id_,
base::Bind(&WriterBridge::DidFinish, this));
}
@@ -54,7 +57,7 @@ class WebFileWriterImpl::WriterBridge
status_callback_ = error_callback;
if (!GetFileSystemDispatcher())
return;
- ChildThread::current()->file_system_dispatcher()->Write(
+ ChildThreadImpl::current()->file_system_dispatcher()->Write(
path, id, offset, &request_id_,
base::Bind(&WriterBridge::DidWrite, this),
base::Bind(&WriterBridge::DidFinish, this));
@@ -64,7 +67,7 @@ class WebFileWriterImpl::WriterBridge
status_callback_ = status_callback;
if (!GetFileSystemDispatcher())
return;
- ChildThread::current()->file_system_dispatcher()->Cancel(
+ ChildThreadImpl::current()->file_system_dispatcher()->Cancel(
request_id_,
base::Bind(&WriterBridge::DidFinish, this));
}
@@ -96,23 +99,25 @@ class WebFileWriterImpl::WriterBridge
void PostTaskToWorker(const base::Closure& closure) {
written_bytes_ = 0;
- if (!thread_id_) {
+ if (!running_on_worker_) {
DCHECK(!waitable_event_);
closure.Run();
return;
}
+ DCHECK(task_runner_);
if (waitable_event_) {
results_closure_ = closure;
waitable_event_->Signal();
return;
}
- WorkerTaskRunner::Instance()->PostTask(thread_id_, closure);
+ task_runner_->PostTask(FROM_HERE, closure);
}
StatusCallback status_callback_;
WriteCallback write_callback_;
int request_id_;
- int thread_id_;
+ const bool running_on_worker_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
int written_bytes_;
scoped_ptr<base::WaitableEvent> waitable_event_;
base::Closure results_closure_;
@@ -121,9 +126,9 @@ class WebFileWriterImpl::WriterBridge
WebFileWriterImpl::WebFileWriterImpl(
const GURL& path, blink::WebFileWriterClient* client,
Type type,
- base::MessageLoopProxy* main_thread_loop)
+ const scoped_refptr<base::SingleThreadTaskRunner>& main_thread_task_runner)
: WebFileWriterBase(path, client),
- main_thread_loop_(main_thread_loop),
+ main_thread_task_runner_(main_thread_task_runner),
bridge_(new WriterBridge(type)) {
}
@@ -150,12 +155,12 @@ void WebFileWriterImpl::DoCancel() {
}
void WebFileWriterImpl::RunOnMainThread(const base::Closure& closure) {
- if (main_thread_loop_->RunsTasksOnCurrentThread()) {
+ if (main_thread_task_runner_->RunsTasksOnCurrentThread()) {
DCHECK(!bridge_->waitable_event());
closure.Run();
return;
}
- main_thread_loop_->PostTask(FROM_HERE, closure);
+ main_thread_task_runner_->PostTask(FROM_HERE, closure);
if (bridge_->waitable_event())
bridge_->WaitAndRun();
}
diff --git a/chromium/content/child/fileapi/webfilewriter_impl.h b/chromium/content/child/fileapi/webfilewriter_impl.h
index 8aefaf51698..40ef0a3fbd2 100644
--- a/chromium/content/child/fileapi/webfilewriter_impl.h
+++ b/chromium/content/child/fileapi/webfilewriter_impl.h
@@ -26,7 +26,8 @@ class WebFileWriterImpl : public WebFileWriterBase,
WebFileWriterImpl(const GURL& path,
blink::WebFileWriterClient* client,
Type type,
- base::MessageLoopProxy* main_thread_loop);
+ const scoped_refptr<base::SingleThreadTaskRunner>&
+ main_thread_task_runner);
virtual ~WebFileWriterImpl();
protected:
@@ -42,7 +43,7 @@ class WebFileWriterImpl : public WebFileWriterBase,
void RunOnMainThread(const base::Closure& closure);
- scoped_refptr<base::MessageLoopProxy> main_thread_loop_;
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
scoped_refptr<WriterBridge> bridge_;
};
diff --git a/chromium/content/child/geofencing/geofencing_dispatcher.cc b/chromium/content/child/geofencing/geofencing_dispatcher.cc
index eec721faf97..37ba161aa28 100644
--- a/chromium/content/child/geofencing/geofencing_dispatcher.cc
+++ b/chromium/content/child/geofencing/geofencing_dispatcher.cc
@@ -10,7 +10,6 @@
#include "base/thread_task_runner_handle.h"
#include "content/child/service_worker/web_service_worker_registration_impl.h"
#include "content/child/thread_safe_sender.h"
-#include "content/child/worker_thread_task_runner.h"
#include "content/common/geofencing_messages.h"
#include "content/common/service_worker/service_worker_types.h"
#include "third_party/WebKit/public/platform/WebCircularGeofencingRegion.h"
@@ -121,6 +120,20 @@ void GeofencingDispatcher::GetRegisteredRegions(
CurrentWorkerId(), request_id, serviceworker_registration_id));
}
+void GeofencingDispatcher::SetMockProvider(bool service_available) {
+ Send(new GeofencingHostMsg_SetMockProvider(
+ service_available ? GeofencingMockState::SERVICE_AVAILABLE
+ : GeofencingMockState::SERVICE_UNAVAILABLE));
+}
+
+void GeofencingDispatcher::ClearMockProvider() {
+ Send(new GeofencingHostMsg_SetMockProvider(GeofencingMockState::NONE));
+}
+
+void GeofencingDispatcher::SetMockPosition(double latitude, double longitude) {
+ Send(new GeofencingHostMsg_SetMockPosition(latitude, longitude));
+}
+
GeofencingDispatcher* GeofencingDispatcher::GetOrCreateThreadSpecificInstance(
ThreadSafeSender* thread_safe_sender) {
if (g_dispatcher_tls.Pointer()->Get() == kHasBeenDeleted) {
@@ -149,8 +162,6 @@ void GeofencingDispatcher::OnRegisterRegionComplete(int thread_id,
blink::WebGeofencingCallbacks* callbacks =
region_registration_requests_.Lookup(request_id);
DCHECK(callbacks);
- if (!callbacks)
- return;
if (status == GEOFENCING_STATUS_OK) {
callbacks->onSuccess();
@@ -168,8 +179,6 @@ void GeofencingDispatcher::OnUnregisterRegionComplete(int thread_id,
blink::WebGeofencingCallbacks* callbacks =
region_unregistration_requests_.Lookup(request_id);
DCHECK(callbacks);
- if (!callbacks)
- return;
if (status == GEOFENCING_STATUS_OK) {
callbacks->onSuccess();
@@ -189,8 +198,6 @@ void GeofencingDispatcher::OnGetRegisteredRegionsComplete(
blink::WebGeofencingRegionsCallbacks* callbacks =
get_registered_regions_requests_.Lookup(request_id);
DCHECK(callbacks);
- if (!callbacks)
- return;
if (status == GEOFENCING_STATUS_OK) {
scoped_ptr<blink::WebVector<blink::WebGeofencingRegistration>> result(
diff --git a/chromium/content/child/geofencing/geofencing_dispatcher.h b/chromium/content/child/geofencing/geofencing_dispatcher.h
index 57a2a437b5d..269dfe7c031 100644
--- a/chromium/content/child/geofencing/geofencing_dispatcher.h
+++ b/chromium/content/child/geofencing/geofencing_dispatcher.h
@@ -9,7 +9,7 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "content/child/worker_task_runner.h"
-#include "content/common/geofencing_status.h"
+#include "content/common/geofencing_types.h"
#include "third_party/WebKit/public/platform/WebGeofencingProvider.h"
namespace base {
@@ -46,6 +46,14 @@ class GeofencingDispatcher : public WorkerTaskRunner::Observer {
blink::WebServiceWorkerRegistration* service_worker_registration,
blink::WebGeofencingRegionsCallbacks* callbacks);
+ // Enables mock geofencing service. |service_available| indicates if the
+ // mock service should mock geofencing being available or not.
+ void SetMockProvider(bool service_available);
+ // Disables mock geofencing service.
+ void ClearMockProvider();
+ // Set the mock geofencing position.
+ void SetMockPosition(double latitude, double longitude);
+
// |thread_safe_sender| needs to be passed in because if the call leads to
// construction it will be needed.
static GeofencingDispatcher* GetOrCreateThreadSpecificInstance(
diff --git a/chromium/content/child/geofencing/geofencing_message_filter.cc b/chromium/content/child/geofencing/geofencing_message_filter.cc
index a8334571d5b..a866b378f39 100644
--- a/chromium/content/child/geofencing/geofencing_message_filter.cc
+++ b/chromium/content/child/geofencing/geofencing_message_filter.cc
@@ -4,40 +4,33 @@
#include "content/child/geofencing/geofencing_message_filter.h"
-#include "base/message_loop/message_loop_proxy.h"
#include "content/child/geofencing/geofencing_dispatcher.h"
-#include "content/child/thread_safe_sender.h"
-#include "content/child/worker_thread_task_runner.h"
#include "ipc/ipc_message_macros.h"
namespace content {
GeofencingMessageFilter::GeofencingMessageFilter(ThreadSafeSender* sender)
- : main_thread_loop_proxy_(base::MessageLoopProxy::current()),
- thread_safe_sender_(sender) {
+ : WorkerThreadMessageFilter(sender) {
}
GeofencingMessageFilter::~GeofencingMessageFilter() {
}
-base::TaskRunner* GeofencingMessageFilter::OverrideTaskRunnerForMessage(
+bool GeofencingMessageFilter::ShouldHandleMessage(
+ const IPC::Message& msg) const {
+ return IPC_MESSAGE_CLASS(msg) == GeofencingMsgStart;
+}
+
+void GeofencingMessageFilter::OnFilteredMessageReceived(
const IPC::Message& msg) {
- if (IPC_MESSAGE_CLASS(msg) != GeofencingMsgStart)
- return NULL;
- int ipc_thread_id = 0;
- const bool success = PickleIterator(msg).ReadInt(&ipc_thread_id);
- DCHECK(success);
- if (!ipc_thread_id)
- return main_thread_loop_proxy_.get();
- return new WorkerThreadTaskRunner(ipc_thread_id);
+ GeofencingDispatcher::GetOrCreateThreadSpecificInstance(thread_safe_sender())
+ ->OnMessageReceived(msg);
}
-bool GeofencingMessageFilter::OnMessageReceived(const IPC::Message& msg) {
- if (IPC_MESSAGE_CLASS(msg) != GeofencingMsgStart)
- return false;
- GeofencingDispatcher::GetOrCreateThreadSpecificInstance(
- thread_safe_sender_.get())->OnMessageReceived(msg);
- return true;
+bool GeofencingMessageFilter::GetWorkerThreadIdForMessage(
+ const IPC::Message& msg,
+ int* ipc_thread_id) {
+ return PickleIterator(msg).ReadInt(ipc_thread_id);
}
} // namespace content
diff --git a/chromium/content/child/geofencing/geofencing_message_filter.h b/chromium/content/child/geofencing/geofencing_message_filter.h
index 3a95d423ccd..34a05c2a386 100644
--- a/chromium/content/child/geofencing/geofencing_message_filter.h
+++ b/chromium/content/child/geofencing/geofencing_message_filter.h
@@ -5,30 +5,22 @@
#ifndef CONTENT_CHILD_GEOFENCING_GEOFENCING_MESSAGE_FILTER_H_
#define CONTENT_CHILD_GEOFENCING_GEOFENCING_MESSAGE_FILTER_H_
-#include "content/child/child_message_filter.h"
-
-namespace base {
-class MessageLoopProxy;
-}
+#include "content/child/worker_thread_message_filter.h"
namespace content {
-class ThreadSafeSender;
-
-class GeofencingMessageFilter : public ChildMessageFilter {
+class GeofencingMessageFilter : public WorkerThreadMessageFilter {
public:
explicit GeofencingMessageFilter(ThreadSafeSender* thread_safe_sender);
private:
~GeofencingMessageFilter() override;
- // ChildMessageFilter implementation:
- base::TaskRunner* OverrideTaskRunnerForMessage(
- const IPC::Message& msg) override;
- bool OnMessageReceived(const IPC::Message& msg) override;
-
- scoped_refptr<base::MessageLoopProxy> main_thread_loop_proxy_;
- scoped_refptr<ThreadSafeSender> thread_safe_sender_;
+ // WorkerThreadMessageFilter:
+ bool ShouldHandleMessage(const IPC::Message& msg) const override;
+ void OnFilteredMessageReceived(const IPC::Message& msg) override;
+ bool GetWorkerThreadIdForMessage(const IPC::Message& msg,
+ int* ipc_thread_id) override;
DISALLOW_COPY_AND_ASSIGN(GeofencingMessageFilter);
};
diff --git a/chromium/content/child/geofencing/web_geofencing_provider_impl.cc b/chromium/content/child/geofencing/web_geofencing_provider_impl.cc
index 5d78b9810b8..5a475a4ebce 100644
--- a/chromium/content/child/geofencing/web_geofencing_provider_impl.cc
+++ b/chromium/content/child/geofencing/web_geofencing_provider_impl.cc
@@ -17,6 +17,19 @@ WebGeofencingProviderImpl::WebGeofencingProviderImpl(
WebGeofencingProviderImpl::~WebGeofencingProviderImpl() {
}
+void WebGeofencingProviderImpl::SetMockProvider(bool service_available) {
+ GetDispatcher()->SetMockProvider(service_available);
+}
+
+void WebGeofencingProviderImpl::ClearMockProvider() {
+ GetDispatcher()->ClearMockProvider();
+}
+
+void WebGeofencingProviderImpl::SetMockPosition(double latitude,
+ double longitude) {
+ GetDispatcher()->SetMockPosition(latitude, longitude);
+}
+
void WebGeofencingProviderImpl::registerRegion(
const blink::WebString& regionId,
const blink::WebCircularGeofencingRegion& region,
diff --git a/chromium/content/child/geofencing/web_geofencing_provider_impl.h b/chromium/content/child/geofencing/web_geofencing_provider_impl.h
index 9aac7951731..f10981885ea 100644
--- a/chromium/content/child/geofencing/web_geofencing_provider_impl.h
+++ b/chromium/content/child/geofencing/web_geofencing_provider_impl.h
@@ -7,18 +7,27 @@
#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
+#include "content/common/content_export.h"
#include "third_party/WebKit/public/platform/WebGeofencingProvider.h"
namespace content {
class GeofencingDispatcher;
class ThreadSafeSender;
-class WebGeofencingProviderImpl
+class CONTENT_EXPORT WebGeofencingProviderImpl
: NON_EXPORTED_BASE(public blink::WebGeofencingProvider) {
public:
explicit WebGeofencingProviderImpl(ThreadSafeSender* thread_safe_sender);
virtual ~WebGeofencingProviderImpl();
+ // Enables mock geofencing service. |service_available| indicates if the
+ // mock service should mock geofencing being available or not.
+ void SetMockProvider(bool service_available);
+ // Disables mock geofencing service.
+ void ClearMockProvider();
+ // Set the mock geofencing position.
+ void SetMockPosition(double latitude, double longitude);
+
private:
// WebGeofencingProvider implementation.
virtual void registerRegion(
diff --git a/chromium/content/child/image_decoder.h b/chromium/content/child/image_decoder.h
index 70e1b7fd58e..535c4231c90 100644
--- a/chromium/content/child/image_decoder.h
+++ b/chromium/content/child/image_decoder.h
@@ -5,7 +5,7 @@
#include <vector>
#include "base/basictypes.h"
-#include "ui/gfx/size.h"
+#include "ui/gfx/geometry/size.h"
class SkBitmap;
diff --git a/chromium/content/child/indexed_db/indexed_db_dispatcher.cc b/chromium/content/child/indexed_db/indexed_db_dispatcher.cc
index 9cd48e2c1ce..5e524e7379b 100644
--- a/chromium/content/child/indexed_db/indexed_db_dispatcher.cc
+++ b/chromium/content/child/indexed_db/indexed_db_dispatcher.cc
@@ -17,9 +17,10 @@
#include "content/common/indexed_db/indexed_db_constants.h"
#include "content/common/indexed_db/indexed_db_messages.h"
#include "ipc/ipc_channel.h"
-#include "third_party/WebKit/public/platform/WebIDBDatabaseCallbacks.h"
-#include "third_party/WebKit/public/platform/WebIDBDatabaseError.h"
-#include "third_party/WebKit/public/platform/WebIDBDatabaseException.h"
+#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBDatabaseCallbacks.h"
+#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBDatabaseError.h"
+#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBDatabaseException.h"
+#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBValue.h"
using blink::WebBlobInfo;
using blink::WebData;
@@ -30,6 +31,7 @@ using blink::WebIDBDatabaseCallbacks;
using blink::WebIDBDatabaseError;
using blink::WebIDBKey;
using blink::WebIDBMetadata;
+using blink::WebIDBValue;
using blink::WebString;
using blink::WebVector;
using base::ThreadLocalPointer;
@@ -45,7 +47,6 @@ IndexedDBDispatcher* const kHasBeenDeleted =
} // unnamed namespace
-const size_t kMaxIDBMessageOverhead = 1024 * 1024; // 1MB; arbitrarily chosen.
const size_t kMaxIDBValueSizeInBytes =
IPC::Channel::kMaximumMessageSize - kMaxIDBMessageOverhead;
@@ -103,8 +104,8 @@ WebIDBMetadata IndexedDBDispatcher::ConvertMetadata(
web_store_metadata.id = idb_store_metadata.id;
web_store_metadata.name = idb_store_metadata.name;
web_store_metadata.keyPath =
- WebIDBKeyPathBuilder::Build(idb_store_metadata.keyPath);
- web_store_metadata.autoIncrement = idb_store_metadata.autoIncrement;
+ WebIDBKeyPathBuilder::Build(idb_store_metadata.key_path);
+ web_store_metadata.autoIncrement = idb_store_metadata.auto_increment;
web_store_metadata.maxIndexId = idb_store_metadata.max_index_id;
web_store_metadata.indexes =
WebVector<WebIDBMetadata::Index>(idb_store_metadata.indexes.size());
@@ -117,9 +118,9 @@ WebIDBMetadata IndexedDBDispatcher::ConvertMetadata(
web_index_metadata.id = idb_index_metadata.id;
web_index_metadata.name = idb_index_metadata.name;
web_index_metadata.keyPath =
- WebIDBKeyPathBuilder::Build(idb_index_metadata.keyPath);
+ WebIDBKeyPathBuilder::Build(idb_index_metadata.key_path);
web_index_metadata.unique = idb_index_metadata.unique;
- web_index_metadata.multiEntry = idb_index_metadata.multiEntry;
+ web_index_metadata.multiEntry = idb_index_metadata.multi_entry;
}
}
@@ -143,9 +144,8 @@ void IndexedDBDispatcher::OnMessageReceived(const IPC::Message& msg) {
OnSuccessIndexedDBKey)
IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessStringList,
OnSuccessStringList)
+ IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessArray, OnSuccessArray)
IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessValue, OnSuccessValue)
- IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessValueWithKey,
- OnSuccessValueWithKey)
IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessInteger, OnSuccessInteger)
IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessUndefined,
OnSuccessUndefined)
@@ -325,6 +325,24 @@ void IndexedDBDispatcher::RequestIDBDatabaseGet(
Send(new IndexedDBHostMsg_DatabaseGet(params));
}
+void IndexedDBDispatcher::RequestIDBDatabaseGetAll(
+ int32 ipc_database_id,
+ int64 transaction_id,
+ int64 object_store_id,
+ const IndexedDBKeyRange& key_range,
+ int64 max_count,
+ WebIDBCallbacks* callbacks) {
+ ResetCursorPrefetchCaches(transaction_id, kAllCursors);
+ IndexedDBHostMsg_DatabaseGetAll_Params params;
+ init_params(&params, callbacks);
+ params.ipc_database_id = ipc_database_id;
+ params.transaction_id = transaction_id;
+ params.object_store_id = object_store_id;
+ params.key_range = key_range;
+ params.max_count = max_count;
+ Send(new IndexedDBHostMsg_DatabaseGetAll(params));
+}
+
void IndexedDBDispatcher::RequestIDBDatabasePut(
int32 ipc_database_id,
int64 transaction_id,
@@ -354,7 +372,7 @@ void IndexedDBDispatcher::RequestIDBDatabasePut(
params.transaction_id = transaction_id;
params.object_store_id = object_store_id;
- params.value.assign(value.data(), value.data() + value.size());
+ params.value.bits.assign(value.data(), value.data() + value.size());
params.key = key;
params.put_mode = put_mode;
@@ -369,11 +387,11 @@ void IndexedDBDispatcher::RequestIDBDatabasePut(
}
}
- params.blob_or_file_info.resize(web_blob_info.size());
+ params.value.blob_or_file_info.resize(web_blob_info.size());
for (size_t i = 0; i < web_blob_info.size(); ++i) {
const WebBlobInfo& info = web_blob_info[i];
IndexedDBMsg_BlobOrFileInfo& blob_or_file_info =
- params.blob_or_file_info[i];
+ params.value.blob_or_file_info[i];
blob_or_file_info.is_file = info.isFile();
if (info.isFile()) {
blob_or_file_info.file_path = info.filePath();
@@ -524,19 +542,41 @@ void IndexedDBDispatcher::OnSuccessStringList(
pending_callbacks_.Remove(ipc_callbacks_id);
}
+static void PrepareWebValue(const IndexedDBMsg_ReturnValue& value,
+ WebIDBValue* web_value) {
+ if (value.bits.empty())
+ return;
+
+ web_value->data.assign(&*value.bits.begin(), value.bits.size());
+ blink::WebVector<WebBlobInfo> local_blob_info(value.blob_or_file_info.size());
+ for (size_t i = 0; i < value.blob_or_file_info.size(); ++i) {
+ const IndexedDBMsg_BlobOrFileInfo& info = value.blob_or_file_info[i];
+ if (info.is_file) {
+ local_blob_info[i] = WebBlobInfo(
+ WebString::fromUTF8(info.uuid.c_str()), info.file_path,
+ info.file_name, info.mime_type, info.last_modified, info.size);
+ } else {
+ local_blob_info[i] = WebBlobInfo(WebString::fromUTF8(info.uuid.c_str()),
+ info.mime_type, info.size);
+ }
+ }
+
+ web_value->webBlobInfo.swap(local_blob_info);
+ web_value->primaryKey = WebIDBKeyBuilder::Build(value.primary_key);
+ web_value->keyPath = WebIDBKeyPathBuilder::Build(value.key_path);
+}
+
static void PrepareWebValueAndBlobInfo(
- const std::string& value,
- const std::vector<IndexedDBMsg_BlobOrFileInfo>& blob_info,
+ const IndexedDBMsg_Value& value,
WebData* web_value,
blink::WebVector<WebBlobInfo>* web_blob_info) {
-
- if (value.empty())
+ if (value.bits.empty())
return;
- web_value->assign(&*value.begin(), value.size());
- blink::WebVector<WebBlobInfo> local_blob_info(blob_info.size());
- for (size_t i = 0; i < blob_info.size(); ++i) {
- const IndexedDBMsg_BlobOrFileInfo& info = blob_info[i];
+ web_value->assign(&*value.bits.begin(), value.bits.size());
+ blink::WebVector<WebBlobInfo> local_blob_info(value.blob_or_file_info.size());
+ for (size_t i = 0; i < value.blob_or_file_info.size(); ++i) {
+ const IndexedDBMsg_BlobOrFileInfo& info = value.blob_or_file_info[i];
if (info.is_file) {
local_blob_info[i] = WebBlobInfo(WebString::fromUTF8(info.uuid.c_str()),
info.file_path,
@@ -552,6 +592,19 @@ static void PrepareWebValueAndBlobInfo(
web_blob_info->swap(local_blob_info);
}
+void IndexedDBDispatcher::OnSuccessArray(
+ const IndexedDBMsg_CallbacksSuccessArray_Params& p) {
+ DCHECK_EQ(p.ipc_thread_id, CurrentWorkerId());
+ int32 ipc_callbacks_id = p.ipc_callbacks_id;
+ blink::WebVector<WebIDBValue> web_values(p.values.size());
+ for (size_t i = 0; i < p.values.size(); ++i)
+ PrepareWebValue(p.values[i], &web_values[i]);
+ WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id);
+ DCHECK(callbacks);
+ callbacks->onSuccess(web_values);
+ pending_callbacks_.Remove(ipc_callbacks_id);
+}
+
void IndexedDBDispatcher::OnSuccessValue(
const IndexedDBMsg_CallbacksSuccessValue_Params& params) {
DCHECK_EQ(params.ipc_thread_id, CurrentWorkerId());
@@ -559,30 +612,14 @@ void IndexedDBDispatcher::OnSuccessValue(
pending_callbacks_.Lookup(params.ipc_callbacks_id);
if (!callbacks)
return;
- WebData web_value;
- WebVector<WebBlobInfo> web_blob_info;
- PrepareWebValueAndBlobInfo(
- params.value, params.blob_or_file_info, &web_value, &web_blob_info);
- callbacks->onSuccess(web_value, web_blob_info);
- pending_callbacks_.Remove(params.ipc_callbacks_id);
+ WebIDBValue web_value;
+ PrepareWebValue(params.value, &web_value);
+ if (params.value.primary_key.IsValid()) {
+ web_value.primaryKey = WebIDBKeyBuilder::Build(params.value.primary_key);
+ web_value.keyPath = WebIDBKeyPathBuilder::Build(params.value.key_path);
+ }
+ callbacks->onSuccess(web_value);
cursor_transaction_ids_.erase(params.ipc_callbacks_id);
-}
-
-void IndexedDBDispatcher::OnSuccessValueWithKey(
- const IndexedDBMsg_CallbacksSuccessValueWithKey_Params& params) {
- DCHECK_EQ(params.ipc_thread_id, CurrentWorkerId());
- WebIDBCallbacks* callbacks =
- pending_callbacks_.Lookup(params.ipc_callbacks_id);
- if (!callbacks)
- return;
- WebData web_value;
- WebVector<WebBlobInfo> web_blob_info;
- PrepareWebValueAndBlobInfo(
- params.value, params.blob_or_file_info, &web_value, &web_blob_info);
- callbacks->onSuccess(web_value,
- web_blob_info,
- WebIDBKeyBuilder::Build(params.primary_key),
- WebIDBKeyPathBuilder::Build(params.key_path));
pending_callbacks_.Remove(params.ipc_callbacks_id);
}
@@ -616,8 +653,7 @@ void IndexedDBDispatcher::OnSuccessOpenCursor(
const IndexedDBKey& primary_key = p.primary_key;
WebData web_value;
WebVector<WebBlobInfo> web_blob_info;
- PrepareWebValueAndBlobInfo(
- p.value, p.blob_or_file_info, &web_value, &web_blob_info);
+ PrepareWebValueAndBlobInfo(p.value, &web_value, &web_blob_info);
DCHECK(cursor_transaction_ids_.find(ipc_callbacks_id) !=
cursor_transaction_ids_.end());
@@ -647,7 +683,6 @@ void IndexedDBDispatcher::OnSuccessCursorContinue(
int32 ipc_cursor_id = p.ipc_cursor_id;
const IndexedDBKey& key = p.key;
const IndexedDBKey& primary_key = p.primary_key;
- const std::string& value = p.value;
if (cursors_.find(ipc_cursor_id) == cursors_.end())
return;
@@ -658,8 +693,7 @@ void IndexedDBDispatcher::OnSuccessCursorContinue(
WebData web_value;
WebVector<WebBlobInfo> web_blob_info;
- PrepareWebValueAndBlobInfo(
- value, p.blob_or_file_info, &web_value, &web_blob_info);
+ PrepareWebValueAndBlobInfo(p.value, &web_value, &web_blob_info);
callbacks->onSuccess(WebIDBKeyBuilder::Build(key),
WebIDBKeyBuilder::Build(primary_key),
web_value,
@@ -676,12 +710,9 @@ void IndexedDBDispatcher::OnSuccessCursorPrefetch(
const std::vector<IndexedDBKey>& keys = p.keys;
const std::vector<IndexedDBKey>& primary_keys = p.primary_keys;
std::vector<WebData> values(p.values.size());
- DCHECK_EQ(p.values.size(), p.blob_or_file_infos.size());
- std::vector<WebVector<WebBlobInfo> > blob_infos(p.blob_or_file_infos.size());
- for (size_t i = 0; i < p.values.size(); ++i) {
- PrepareWebValueAndBlobInfo(
- p.values[i], p.blob_or_file_infos[i], &values[i], &blob_infos[i]);
- }
+ std::vector<WebVector<WebBlobInfo>> blob_infos(p.values.size());
+ for (size_t i = 0; i < p.values.size(); ++i)
+ PrepareWebValueAndBlobInfo(p.values[i], &values[i], &blob_infos[i]);
std::map<int32, WebIDBCursorImpl*>::const_iterator cur_iter =
cursors_.find(ipc_cursor_id);
if (cur_iter == cursors_.end())
diff --git a/chromium/content/child/indexed_db/indexed_db_dispatcher.h b/chromium/content/child/indexed_db/indexed_db_dispatcher.h
index e2df2893bdb..fa69ffb9a85 100644
--- a/chromium/content/child/indexed_db/indexed_db_dispatcher.h
+++ b/chromium/content/child/indexed_db/indexed_db_dispatcher.h
@@ -17,16 +17,16 @@
#include "content/common/content_export.h"
#include "ipc/ipc_sync_message_filter.h"
#include "third_party/WebKit/public/platform/WebBlobInfo.h"
-#include "third_party/WebKit/public/platform/WebIDBCallbacks.h"
-#include "third_party/WebKit/public/platform/WebIDBDatabaseCallbacks.h"
-#include "third_party/WebKit/public/platform/WebIDBTypes.h"
+#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBCallbacks.h"
+#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBDatabaseCallbacks.h"
+#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBTypes.h"
struct IndexedDBDatabaseMetadata;
struct IndexedDBMsg_CallbacksSuccessCursorContinue_Params;
struct IndexedDBMsg_CallbacksSuccessCursorPrefetch_Params;
struct IndexedDBMsg_CallbacksSuccessIDBCursor_Params;
+struct IndexedDBMsg_CallbacksSuccessArray_Params;
struct IndexedDBMsg_CallbacksSuccessValue_Params;
-struct IndexedDBMsg_CallbacksSuccessValueWithKey_Params;
struct IndexedDBMsg_CallbacksUpgradeNeeded_Params;
namespace blink {
@@ -129,6 +129,13 @@ class CONTENT_EXPORT IndexedDBDispatcher : public WorkerTaskRunner::Observer {
bool key_only,
blink::WebIDBCallbacks* callbacks);
+ void RequestIDBDatabaseGetAll(int32 ipc_database_id,
+ int64 transaction_id,
+ int64 object_store_id,
+ const IndexedDBKeyRange& key_range,
+ int64 max_count,
+ blink::WebIDBCallbacks* callbacks);
+
void RequestIDBDatabasePut(
int32 ipc_database_id,
int64 transaction_id,
@@ -210,8 +217,7 @@ class CONTENT_EXPORT IndexedDBDispatcher : public WorkerTaskRunner::Observer {
int32 ipc_callbacks_id,
const std::vector<base::string16>& value);
void OnSuccessValue(const IndexedDBMsg_CallbacksSuccessValue_Params& p);
- void OnSuccessValueWithKey(
- const IndexedDBMsg_CallbacksSuccessValueWithKey_Params& p);
+ void OnSuccessArray(const IndexedDBMsg_CallbacksSuccessArray_Params& p);
void OnSuccessInteger(int32 ipc_thread_id,
int32 ipc_callbacks_id,
int64 value);
diff --git a/chromium/content/child/indexed_db/indexed_db_dispatcher_unittest.cc b/chromium/content/child/indexed_db/indexed_db_dispatcher_unittest.cc
index 4f29998f02c..94b9ccac08f 100644
--- a/chromium/content/child/indexed_db/indexed_db_dispatcher_unittest.cc
+++ b/chromium/content/child/indexed_db/indexed_db_dispatcher_unittest.cc
@@ -15,7 +15,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/public/platform/WebBlobInfo.h"
#include "third_party/WebKit/public/platform/WebData.h"
-#include "third_party/WebKit/public/platform/WebIDBCallbacks.h"
+#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBCallbacks.h"
#include "third_party/WebKit/public/web/WebHeap.h"
using blink::WebBlobInfo;
@@ -25,6 +25,7 @@ using blink::WebIDBCursor;
using blink::WebIDBDatabase;
using blink::WebIDBDatabaseError;
using blink::WebIDBKey;
+using blink::WebIDBValue;
using blink::WebVector;
namespace content {
@@ -71,6 +72,7 @@ class IndexedDBDispatcherTest : public testing::Test {
void TearDown() override { blink::WebHeap::collectAllGarbageForTesting(); }
protected:
+ base::MessageLoop message_loop_;
scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
scoped_refptr<IPC::SyncMessageFilter> sync_message_filter_;
scoped_refptr<ThreadSafeSender> thread_safe_sender_;
@@ -140,13 +142,12 @@ class CursorCallbacks : public WebIDBCallbacks {
explicit CursorCallbacks(scoped_ptr<WebIDBCursor>* cursor)
: cursor_(cursor) {}
- virtual void onSuccess(const WebData&,
- const WebVector<WebBlobInfo>&) override {}
- virtual void onSuccess(WebIDBCursor* cursor,
- const WebIDBKey& key,
- const WebIDBKey& primaryKey,
- const WebData& value,
- const WebVector<WebBlobInfo>&) override {
+ void onSuccess(const WebIDBValue&) override {}
+ void onSuccess(WebIDBCursor* cursor,
+ const WebIDBKey& key,
+ const WebIDBKey& primaryKey,
+ const WebData& value,
+ const WebVector<WebBlobInfo>&) override {
cursor_->reset(cursor);
}
diff --git a/chromium/content/child/indexed_db/indexed_db_key_builders.h b/chromium/content/child/indexed_db/indexed_db_key_builders.h
index fb299c0dd78..194560631c2 100644
--- a/chromium/content/child/indexed_db/indexed_db_key_builders.h
+++ b/chromium/content/child/indexed_db/indexed_db_key_builders.h
@@ -9,9 +9,9 @@
#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 "third_party/WebKit/public/platform/WebIDBKey.h"
-#include "third_party/WebKit/public/platform/WebIDBKeyPath.h"
-#include "third_party/WebKit/public/platform/WebIDBKeyRange.h"
+#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBKey.h"
+#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBKeyPath.h"
+#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBKeyRange.h"
namespace blink {
class WebIDBKey;
diff --git a/chromium/content/child/indexed_db/indexed_db_message_filter.cc b/chromium/content/child/indexed_db/indexed_db_message_filter.cc
index bce3817072b..60c1bea6807 100644
--- a/chromium/content/child/indexed_db/indexed_db_message_filter.cc
+++ b/chromium/content/child/indexed_db/indexed_db_message_filter.cc
@@ -4,10 +4,8 @@
#include "content/child/indexed_db/indexed_db_message_filter.h"
-#include "base/message_loop/message_loop_proxy.h"
#include "content/child/indexed_db/indexed_db_dispatcher.h"
#include "content/child/thread_safe_sender.h"
-#include "content/child/worker_thread_task_runner.h"
#include "content/common/indexed_db/indexed_db_constants.h"
#include "content/common/indexed_db/indexed_db_messages.h"
@@ -15,29 +13,26 @@ namespace content {
IndexedDBMessageFilter::IndexedDBMessageFilter(
ThreadSafeSender* thread_safe_sender)
- : main_thread_loop_(base::MessageLoopProxy::current()),
- thread_safe_sender_(thread_safe_sender) {}
+ : WorkerThreadMessageFilter(thread_safe_sender) {
+}
IndexedDBMessageFilter::~IndexedDBMessageFilter() {}
-base::TaskRunner* IndexedDBMessageFilter::OverrideTaskRunnerForMessage(
- const IPC::Message& msg) {
- if (IPC_MESSAGE_CLASS(msg) != IndexedDBMsgStart)
- return NULL;
- int ipc_thread_id = 0;
- const bool success = PickleIterator(msg).ReadInt(&ipc_thread_id);
- DCHECK(success);
- if (!ipc_thread_id)
- return main_thread_loop_.get();
- return new WorkerThreadTaskRunner(ipc_thread_id);
+bool IndexedDBMessageFilter::ShouldHandleMessage(
+ const IPC::Message& msg) const {
+ return IPC_MESSAGE_CLASS(msg) == IndexedDBMsgStart;
}
-bool IndexedDBMessageFilter::OnMessageReceived(const IPC::Message& msg) {
- if (IPC_MESSAGE_CLASS(msg) != IndexedDBMsgStart)
- return false;
- IndexedDBDispatcher::ThreadSpecificInstance(thread_safe_sender_.get())
+void IndexedDBMessageFilter::OnFilteredMessageReceived(
+ const IPC::Message& msg) {
+ IndexedDBDispatcher::ThreadSpecificInstance(thread_safe_sender())
->OnMessageReceived(msg);
- return true;
+}
+
+bool IndexedDBMessageFilter::GetWorkerThreadIdForMessage(
+ const IPC::Message& msg,
+ int* ipc_thread_id) {
+ return PickleIterator(msg).ReadInt(ipc_thread_id);
}
void IndexedDBMessageFilter::OnStaleMessageReceived(const IPC::Message& msg) {
@@ -57,13 +52,13 @@ void IndexedDBMessageFilter::OnStaleSuccessIDBDatabase(
const IndexedDBDatabaseMetadata& idb_metadata) {
if (ipc_database_id == kNoDatabase)
return;
- thread_safe_sender_->Send(
+ thread_safe_sender()->Send(
new IndexedDBHostMsg_DatabaseClose(ipc_database_id));
}
void IndexedDBMessageFilter::OnStaleUpgradeNeeded(
const IndexedDBMsg_CallbacksUpgradeNeeded_Params& p) {
- thread_safe_sender_->Send(
+ thread_safe_sender()->Send(
new IndexedDBHostMsg_DatabaseClose(p.ipc_database_id));
}
diff --git a/chromium/content/child/indexed_db/indexed_db_message_filter.h b/chromium/content/child/indexed_db/indexed_db_message_filter.h
index e2d1ed541d7..08e3998280e 100644
--- a/chromium/content/child/indexed_db/indexed_db_message_filter.h
+++ b/chromium/content/child/indexed_db/indexed_db_message_filter.h
@@ -6,7 +6,7 @@
#define CONTENT_CHILD_INDEXED_DB_INDEXED_DB_MESSAGE_FILTER_H_
#include "base/memory/ref_counted.h"
-#include "content/child/child_message_filter.h"
+#include "content/child/worker_thread_message_filter.h"
struct IndexedDBDatabaseMetadata;
struct IndexedDBMsg_CallbacksUpgradeNeeded_Params;
@@ -15,15 +15,9 @@ namespace base {
class MessageLoopProxy;
}
-namespace IPC {
-class Message;
-}
-
namespace content {
-class ThreadSafeSender;
-
-class IndexedDBMessageFilter : public ChildMessageFilter {
+class IndexedDBMessageFilter : public WorkerThreadMessageFilter {
public:
explicit IndexedDBMessageFilter(ThreadSafeSender* thread_safe_sender);
@@ -31,10 +25,13 @@ class IndexedDBMessageFilter : public ChildMessageFilter {
~IndexedDBMessageFilter() override;
private:
- // ChildMessageFilter implementation:
- base::TaskRunner* OverrideTaskRunnerForMessage(
- const IPC::Message& msg) override;
- bool OnMessageReceived(const IPC::Message& msg) override;
+ // WorkerThreadMessageFilter:
+ bool ShouldHandleMessage(const IPC::Message& msg) const override;
+ void OnFilteredMessageReceived(const IPC::Message& msg) override;
+ bool GetWorkerThreadIdForMessage(const IPC::Message& msg,
+ int* ipc_thread_id) override;
+
+ // ChildMessageFilter:
void OnStaleMessageReceived(const IPC::Message& msg) override;
void OnStaleSuccessIDBDatabase(int32 ipc_thread_id,
@@ -44,9 +41,6 @@ class IndexedDBMessageFilter : public ChildMessageFilter {
const IndexedDBDatabaseMetadata&);
void OnStaleUpgradeNeeded(const IndexedDBMsg_CallbacksUpgradeNeeded_Params&);
- scoped_refptr<base::MessageLoopProxy> main_thread_loop_;
- scoped_refptr<ThreadSafeSender> thread_safe_sender_;
-
DISALLOW_COPY_AND_ASSIGN(IndexedDBMessageFilter);
};
diff --git a/chromium/content/child/indexed_db/webidbcursor_impl.cc b/chromium/content/child/indexed_db/webidbcursor_impl.cc
index c3d97ba3eca..4f458050f82 100644
--- a/chromium/content/child/indexed_db/webidbcursor_impl.cc
+++ b/chromium/content/child/indexed_db/webidbcursor_impl.cc
@@ -4,6 +4,7 @@
#include "content/child/indexed_db/webidbcursor_impl.h"
+#include <string>
#include <vector>
#include "content/child/indexed_db/indexed_db_dispatcher.h"
@@ -194,10 +195,22 @@ void WebIDBCursorImpl::ResetPrefetchCache() {
return;
}
+ // Ack any unused blobs.
+ std::vector<std::string> uuids;
+ for (const auto& blobs : prefetch_blob_info_) {
+ for (size_t i = 0, size = blobs.size(); i < size; ++i)
+ uuids.push_back(blobs[i].uuid().latin1());
+ }
+ if (!uuids.empty())
+ thread_safe_sender_->Send(new IndexedDBHostMsg_AckReceivedBlobs(uuids));
+
+ // Reset the back-end cursor.
IndexedDBDispatcher* dispatcher =
IndexedDBDispatcher::ThreadSpecificInstance(thread_safe_sender_.get());
dispatcher->RequestIDBCursorPrefetchReset(
used_prefetches_, prefetch_keys_.size(), ipc_cursor_id_);
+
+ // Reset the prefetch cache.
prefetch_keys_.clear();
prefetch_primary_keys_.clear();
prefetch_values_.clear();
diff --git a/chromium/content/child/indexed_db/webidbcursor_impl.h b/chromium/content/child/indexed_db/webidbcursor_impl.h
index 604cf42bcd1..39282ea002a 100644
--- a/chromium/content/child/indexed_db/webidbcursor_impl.h
+++ b/chromium/content/child/indexed_db/webidbcursor_impl.h
@@ -15,9 +15,9 @@
#include "content/common/content_export.h"
#include "content/common/indexed_db/indexed_db_key.h"
#include "third_party/WebKit/public/platform/WebData.h"
-#include "third_party/WebKit/public/platform/WebIDBCallbacks.h"
-#include "third_party/WebKit/public/platform/WebIDBCursor.h"
-#include "third_party/WebKit/public/platform/WebIDBKey.h"
+#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBCallbacks.h"
+#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBCursor.h"
+#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBKey.h"
namespace content {
class ThreadSafeSender;
diff --git a/chromium/content/child/indexed_db/webidbcursor_impl_unittest.cc b/chromium/content/child/indexed_db/webidbcursor_impl_unittest.cc
index ab56cd2d330..dfc277e95e8 100644
--- a/chromium/content/child/indexed_db/webidbcursor_impl_unittest.cc
+++ b/chromium/content/child/indexed_db/webidbcursor_impl_unittest.cc
@@ -12,7 +12,7 @@
#include "ipc/ipc_sync_message_filter.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/public/platform/WebData.h"
-#include "third_party/WebKit/public/platform/WebIDBCallbacks.h"
+#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBCallbacks.h"
using blink::WebBlobInfo;
using blink::WebData;
@@ -97,21 +97,21 @@ class MockContinueCallbacks : public WebIDBCallbacks {
public:
MockContinueCallbacks(IndexedDBKey* key = 0,
WebVector<WebBlobInfo>* webBlobInfo = 0)
- : key_(key), webBlobInfo_(webBlobInfo) {}
+ : key_(key), web_blob_info_(webBlobInfo) {}
- virtual void onSuccess(const WebIDBKey& key,
- const WebIDBKey& primaryKey,
- const WebData& value,
- const WebVector<WebBlobInfo>& webBlobInfo) override {
+ void onSuccess(const WebIDBKey& key,
+ const WebIDBKey& primaryKey,
+ const WebData& value,
+ const WebVector<WebBlobInfo>& webBlobInfo) override {
if (key_)
*key_ = IndexedDBKeyBuilder::Build(key);
- if (webBlobInfo_)
- *webBlobInfo_ = webBlobInfo;
+ if (web_blob_info_)
+ *web_blob_info_ = webBlobInfo;
}
private:
IndexedDBKey* key_;
- WebVector<WebBlobInfo>* webBlobInfo_;
+ WebVector<WebBlobInfo>* web_blob_info_;
};
} // namespace
@@ -128,6 +128,7 @@ class WebIDBCursorImplTest : public testing::Test {
}
protected:
+ base::MessageLoop message_loop_;
WebIDBKey null_key_;
scoped_refptr<ThreadSafeSender> thread_safe_sender_;
scoped_ptr<MockDispatcher> dispatcher_;
diff --git a/chromium/content/child/indexed_db/webidbdatabase_impl.cc b/chromium/content/child/indexed_db/webidbdatabase_impl.cc
index 55d69c1e65a..81ce98a5822 100644
--- a/chromium/content/child/indexed_db/webidbdatabase_impl.cc
+++ b/chromium/content/child/indexed_db/webidbdatabase_impl.cc
@@ -13,10 +13,10 @@
#include "content/child/worker_task_runner.h"
#include "content/common/indexed_db/indexed_db_messages.h"
#include "third_party/WebKit/public/platform/WebBlobInfo.h"
-#include "third_party/WebKit/public/platform/WebIDBKeyPath.h"
-#include "third_party/WebKit/public/platform/WebIDBMetadata.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/platform/WebVector.h"
+#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBKeyPath.h"
+#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBMetadata.h"
using blink::WebBlobInfo;
using blink::WebIDBCallbacks;
@@ -115,6 +115,25 @@ void WebIDBDatabaseImpl::get(long long transaction_id,
callbacks);
}
+void WebIDBDatabaseImpl::getAll(long long transaction_id,
+ long long object_store_id,
+ long long index_id,
+ const WebIDBKeyRange& key_range,
+ long long max_count,
+ bool key_only,
+ WebIDBCallbacks* callbacks) {
+ // TODO(cmumford): Remove DCHECK's for index_id/key_only once IDBIndex.getAll
+ // is implemented.
+ static const int64 kInvalidId = -1;
+ DCHECK_EQ(kInvalidId, index_id);
+ DCHECK(!key_only);
+ IndexedDBDispatcher* dispatcher =
+ IndexedDBDispatcher::ThreadSpecificInstance(thread_safe_sender_.get());
+ dispatcher->RequestIDBDatabaseGetAll(
+ ipc_database_id_, transaction_id, object_store_id,
+ IndexedDBKeyRangeBuilder::Build(key_range), max_count, callbacks);
+}
+
void WebIDBDatabaseImpl::put(long long transaction_id,
long long object_store_id,
const blink::WebData& value,
diff --git a/chromium/content/child/indexed_db/webidbdatabase_impl.h b/chromium/content/child/indexed_db/webidbdatabase_impl.h
index 61f20018636..0d9d7abeb88 100644
--- a/chromium/content/child/indexed_db/webidbdatabase_impl.h
+++ b/chromium/content/child/indexed_db/webidbdatabase_impl.h
@@ -7,9 +7,9 @@
#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
-#include "third_party/WebKit/public/platform/WebIDBCursor.h"
-#include "third_party/WebKit/public/platform/WebIDBDatabase.h"
-#include "third_party/WebKit/public/platform/WebIDBTypes.h"
+#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBCursor.h"
+#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBDatabase.h"
+#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBTypes.h"
namespace blink {
class WebBlobInfo;
@@ -50,6 +50,13 @@ class WebIDBDatabaseImpl : public blink::WebIDBDatabase {
const blink::WebIDBKeyRange&,
bool keyOnly,
blink::WebIDBCallbacks*);
+ virtual void getAll(long long transactionId,
+ long long objectStoreId,
+ long long indexId,
+ const blink::WebIDBKeyRange&,
+ long long maxCount,
+ bool keyOnly,
+ blink::WebIDBCallbacks*);
virtual void put(long long transactionId,
long long objectStoreId,
const blink::WebData& value,
diff --git a/chromium/content/child/indexed_db/webidbfactory_impl.h b/chromium/content/child/indexed_db/webidbfactory_impl.h
index cc11bba7c28..cfff5e15361 100644
--- a/chromium/content/child/indexed_db/webidbfactory_impl.h
+++ b/chromium/content/child/indexed_db/webidbfactory_impl.h
@@ -6,10 +6,10 @@
#define CONTENT_CHILD_INDEXED_DB_WEBIDBFACTORY_IMPL_H_
#include "base/memory/ref_counted.h"
-#include "third_party/WebKit/public/platform/WebIDBCallbacks.h"
-#include "third_party/WebKit/public/platform/WebIDBDatabaseCallbacks.h"
-#include "third_party/WebKit/public/platform/WebIDBFactory.h"
#include "third_party/WebKit/public/platform/WebVector.h"
+#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBCallbacks.h"
+#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBDatabaseCallbacks.h"
+#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBFactory.h"
namespace blink {
class WebString;
diff --git a/chromium/content/child/mojo/mojo_application.cc b/chromium/content/child/mojo/mojo_application.cc
index bc1426ff3e1..fc2e989723a 100644
--- a/chromium/content/child/mojo/mojo_application.cc
+++ b/chromium/content/child/mojo/mojo_application.cc
@@ -5,12 +5,18 @@
#include "content/child/mojo/mojo_application.h"
#include "content/child/child_process.h"
+#include "content/common/application_setup.mojom.h"
+#include "content/common/mojo/channel_init.h"
#include "content/common/mojo/mojo_messages.h"
#include "ipc/ipc_message.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/interface_ptr.h"
namespace content {
-MojoApplication::MojoApplication() {
+MojoApplication::MojoApplication(
+ scoped_refptr<base::SequencedTaskRunner> io_task_runner)
+ : io_task_runner_(io_task_runner) {
+ DCHECK(io_task_runner_);
}
MojoApplication::~MojoApplication() {
@@ -32,11 +38,21 @@ void MojoApplication::OnActivate(
#elif defined(OS_WIN)
base::PlatformFile handle = file;
#endif
+
mojo::ScopedMessagePipeHandle message_pipe =
- channel_init_.Init(handle,
- ChildProcess::current()->io_message_loop_proxy());
+ channel_init_.Init(handle, io_task_runner_);
DCHECK(message_pipe.is_valid());
- service_registry_.BindRemoteServiceProvider(message_pipe.Pass());
+
+ ApplicationSetupPtr application_setup;
+ application_setup.Bind(
+ mojo::InterfacePtrInfo<ApplicationSetup>(message_pipe.Pass(), 0u));
+
+ mojo::ServiceProviderPtr services;
+ mojo::ServiceProviderPtr exposed_services;
+ service_registry_.Bind(GetProxy(&exposed_services));
+ application_setup->ExchangeServiceProviders(GetProxy(&services),
+ exposed_services.Pass());
+ service_registry_.BindRemoteServiceProvider(services.Pass());
}
} // namespace content
diff --git a/chromium/content/child/mojo/mojo_application.h b/chromium/content/child/mojo/mojo_application.h
index 8aee2e869c7..5c207f2ccd5 100644
--- a/chromium/content/child/mojo/mojo_application.h
+++ b/chromium/content/child/mojo/mojo_application.h
@@ -5,9 +5,13 @@
#ifndef CONTENT_CHILD_MOJO_MOJO_APPLICATION_H_
#define CONTENT_CHILD_MOJO_MOJO_APPLICATION_H_
+#include "content/common/mojo/channel_init.h"
#include "content/common/mojo/service_registry_impl.h"
#include "ipc/ipc_platform_file.h"
-#include "mojo/edk/embedder/channel_init.h"
+
+namespace base {
+class SequencedTaskRunner;
+}
namespace IPC {
class Message;
@@ -21,7 +25,8 @@ namespace content {
// It makes the ServiceRegistry interface available.
class MojoApplication {
public:
- MojoApplication();
+ explicit MojoApplication(
+ scoped_refptr<base::SequencedTaskRunner> io_task_runner);
virtual ~MojoApplication();
bool OnMessageReceived(const IPC::Message& msg);
@@ -31,7 +36,9 @@ class MojoApplication {
private:
void OnActivate(const IPC::PlatformFileForTransit& file);
- mojo::embedder::ChannelInit channel_init_;
+ scoped_refptr<base::SequencedTaskRunner> io_task_runner_;
+
+ ChannelInit channel_init_;
ServiceRegistryImpl service_registry_;
diff --git a/chromium/content/child/navigator_connect/OWNERS b/chromium/content/child/navigator_connect/OWNERS
new file mode 100644
index 00000000000..1b10b3436d9
--- /dev/null
+++ b/chromium/content/child/navigator_connect/OWNERS
@@ -0,0 +1 @@
+mek@chromium.org
diff --git a/chromium/content/child/navigator_connect/navigator_connect_dispatcher.cc b/chromium/content/child/navigator_connect/navigator_connect_dispatcher.cc
new file mode 100644
index 00000000000..1a30433ac81
--- /dev/null
+++ b/chromium/content/child/navigator_connect/navigator_connect_dispatcher.cc
@@ -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.
+
+#include "content/child/navigator_connect/navigator_connect_dispatcher.h"
+
+#include "content/child/navigator_connect/navigator_connect_provider.h"
+#include "content/common/navigator_connect_messages.h"
+
+namespace content {
+
+NavigatorConnectDispatcher::NavigatorConnectDispatcher(ThreadSafeSender* sender)
+ : WorkerThreadMessageFilter(sender) {
+}
+
+NavigatorConnectDispatcher::~NavigatorConnectDispatcher() {
+}
+
+bool NavigatorConnectDispatcher::ShouldHandleMessage(
+ const IPC::Message& msg) const {
+ return IPC_MESSAGE_CLASS(msg) == NavigatorConnectMsgStart;
+}
+
+void NavigatorConnectDispatcher::OnFilteredMessageReceived(
+ const IPC::Message& msg) {
+ NavigatorConnectProvider::ThreadSpecificInstance(
+ thread_safe_sender(), main_thread_task_runner())->OnMessageReceived(msg);
+}
+
+bool NavigatorConnectDispatcher::GetWorkerThreadIdForMessage(
+ const IPC::Message& msg,
+ int* ipc_thread_id) {
+ return PickleIterator(msg).ReadInt(ipc_thread_id);
+}
+
+} // namespace content
diff --git a/chromium/content/child/navigator_connect/navigator_connect_dispatcher.h b/chromium/content/child/navigator_connect/navigator_connect_dispatcher.h
new file mode 100644
index 00000000000..0044b515db6
--- /dev/null
+++ b/chromium/content/child/navigator_connect/navigator_connect_dispatcher.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_CHILD_NAVIGATOR_CONNECT_NAVIGATOR_CONNECT_DISPATCHER_H_
+#define CONTENT_CHILD_NAVIGATOR_CONNECT_NAVIGATOR_CONNECT_DISPATCHER_H_
+
+#include "content/child/worker_thread_message_filter.h"
+
+namespace content {
+
+// Receives IPC messages from the browser process and dispatches them to the
+// correct thread specific NavigatorConnectProvider.
+class NavigatorConnectDispatcher : public WorkerThreadMessageFilter {
+ public:
+ explicit NavigatorConnectDispatcher(ThreadSafeSender* thread_safe_sender);
+
+ private:
+ ~NavigatorConnectDispatcher() override;
+
+ // WorkerThreadMessageFilter:
+ bool ShouldHandleMessage(const IPC::Message& msg) const override;
+ void OnFilteredMessageReceived(const IPC::Message& msg) override;
+ bool GetWorkerThreadIdForMessage(const IPC::Message& msg,
+ int* ipc_thread_id) override;
+
+ DISALLOW_COPY_AND_ASSIGN(NavigatorConnectDispatcher);
+};
+
+} // namespace content
+
+#endif // CONTENT_CHILD_NAVIGATOR_CONNECT_NAVIGATOR_CONNECT_DISPATCHER_H_
diff --git a/chromium/content/child/navigator_connect/navigator_connect_provider.cc b/chromium/content/child/navigator_connect/navigator_connect_provider.cc
new file mode 100644
index 00000000000..78c3fdad7fd
--- /dev/null
+++ b/chromium/content/child/navigator_connect/navigator_connect_provider.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/child/navigator_connect/navigator_connect_provider.h"
+
+#include "base/lazy_instance.h"
+#include "base/single_thread_task_runner.h"
+#include "base/task_runner_util.h"
+#include "content/child/thread_safe_sender.h"
+#include "content/child/webmessageportchannel_impl.h"
+#include "content/common/navigator_connect_messages.h"
+#include "content/public/common/navigator_connect_client.h"
+#include "third_party/WebKit/public/platform/WebURL.h"
+
+namespace content {
+
+namespace {
+
+base::LazyInstance<base::ThreadLocalPointer<NavigatorConnectProvider>>::Leaky
+ g_provider_tls = LAZY_INSTANCE_INITIALIZER;
+
+NavigatorConnectProvider* const kHasBeenDeleted =
+ reinterpret_cast<NavigatorConnectProvider*>(0x1);
+
+int CurrentWorkerId() {
+ return WorkerTaskRunner::Instance()->CurrentWorkerId();
+}
+
+} // namespace
+
+NavigatorConnectProvider::NavigatorConnectProvider(
+ ThreadSafeSender* thread_safe_sender,
+ const scoped_refptr<base::SingleThreadTaskRunner>& main_loop)
+ : thread_safe_sender_(thread_safe_sender), main_loop_(main_loop) {
+ g_provider_tls.Pointer()->Set(this);
+}
+
+NavigatorConnectProvider::~NavigatorConnectProvider() {
+ g_provider_tls.Pointer()->Set(kHasBeenDeleted);
+}
+
+void NavigatorConnectProvider::connect(
+ const blink::WebURL& target_url,
+ const blink::WebString& origin,
+ blink::WebNavigatorConnectPortCallbacks* callbacks) {
+ int request_id = requests_.Add(callbacks);
+
+ thread_safe_sender_->Send(new NavigatorConnectHostMsg_Connect(
+ CurrentWorkerId(), request_id,
+ NavigatorConnectClient(target_url, GURL(origin), MSG_ROUTING_NONE)));
+}
+
+void NavigatorConnectProvider::OnMessageReceived(const IPC::Message& msg) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(NavigatorConnectProvider, msg)
+ IPC_MESSAGE_HANDLER(NavigatorConnectMsg_ConnectResult, OnConnectResult)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ DCHECK(handled) << "Unhandled message:" << msg.type();
+}
+
+NavigatorConnectProvider* NavigatorConnectProvider::ThreadSpecificInstance(
+ ThreadSafeSender* thread_safe_sender,
+ const scoped_refptr<base::SingleThreadTaskRunner>& main_loop) {
+ if (g_provider_tls.Pointer()->Get() == kHasBeenDeleted) {
+ NOTREACHED() << "Re-instantiating TLS NavigatorConnectProvider.";
+ g_provider_tls.Pointer()->Set(NULL);
+ }
+ if (g_provider_tls.Pointer()->Get())
+ return g_provider_tls.Pointer()->Get();
+
+ NavigatorConnectProvider* provider =
+ new NavigatorConnectProvider(thread_safe_sender, main_loop);
+ if (WorkerTaskRunner::Instance()->CurrentWorkerId())
+ WorkerTaskRunner::Instance()->AddStopObserver(provider);
+ return provider;
+}
+
+void NavigatorConnectProvider::OnConnectResult(
+ int thread_id,
+ int request_id,
+ const TransferredMessagePort& message_port,
+ int message_port_route_id,
+ bool allow_connect) {
+ blink::WebNavigatorConnectPortCallbacks* callbacks =
+ requests_.Lookup(request_id);
+ DCHECK(callbacks);
+
+ if (allow_connect) {
+ WebMessagePortChannelImpl* channel = new WebMessagePortChannelImpl(
+ message_port_route_id, message_port, main_loop_);
+ callbacks->onSuccess(channel);
+ } else {
+ callbacks->onError();
+ }
+ requests_.Remove(request_id);
+}
+
+void NavigatorConnectProvider::OnWorkerRunLoopStopped() {
+ delete this;
+}
+
+} // namespace content
diff --git a/chromium/content/child/navigator_connect/navigator_connect_provider.h b/chromium/content/child/navigator_connect/navigator_connect_provider.h
new file mode 100644
index 00000000000..f21b0c4a97e
--- /dev/null
+++ b/chromium/content/child/navigator_connect/navigator_connect_provider.h
@@ -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.
+
+#ifndef CONTENT_CHILD_NAVIGATOR_CONNECT_NAVIGATOR_CONNECT_PROVIDER_H_
+#define CONTENT_CHILD_NAVIGATOR_CONNECT_NAVIGATOR_CONNECT_PROVIDER_H_
+
+#include "base/compiler_specific.h"
+#include "base/id_map.h"
+#include "base/memory/ref_counted.h"
+#include "content/child/worker_task_runner.h"
+#include "third_party/WebKit/public/platform/WebNavigatorConnectProvider.h"
+
+class GURL;
+
+namespace base {
+class SingleThreadTaskRunner;
+}
+
+namespace blink {
+class WebMessagePortChannel;
+class WebString;
+}
+
+namespace IPC {
+class Message;
+}
+
+namespace content {
+class ThreadSafeSender;
+struct TransferredMessagePort;
+
+// Main entry point for the navigator.connect API in a child process. This
+// implements the blink API and passes connect calls on to the browser process.
+// NavigatorConnectDispatcher receives IPCs from the browser process and passes
+// them on to the correct thread specific instance of this class.
+// The ThreadSpecificInstance method will return an instance of this class for
+// the current thread, or create one if no instance exists yet for this thread.
+// This class deletes itself if the worker thread it belongs to quits.
+class NavigatorConnectProvider : public blink::WebNavigatorConnectProvider,
+ public WorkerTaskRunner::Observer {
+ public:
+ NavigatorConnectProvider(
+ ThreadSafeSender* thread_safe_sender,
+ const scoped_refptr<base::SingleThreadTaskRunner>& main_loop);
+ ~NavigatorConnectProvider();
+
+ // WebNavigatorConnectProvider implementation.
+ virtual void connect(const blink::WebURL& target_url,
+ const blink::WebString& origin,
+ blink::WebNavigatorConnectPortCallbacks* callbacks);
+
+ void OnMessageReceived(const IPC::Message& msg);
+
+ // |thread_safe_sender| and |main_loop| need to be passed in because if the
+ // call leads to construction they will be needed.
+ static NavigatorConnectProvider* ThreadSpecificInstance(
+ ThreadSafeSender* thread_safe_sender,
+ const scoped_refptr<base::SingleThreadTaskRunner>& main_loop);
+
+ private:
+ void OnConnectResult(int thread_id,
+ int request_id,
+ const TransferredMessagePort& message_port,
+ int message_port_route_id,
+ bool allow_connect);
+
+ // WorkerTaskRunner::Observer implementation.
+ void OnWorkerRunLoopStopped() override;
+
+ scoped_refptr<ThreadSafeSender> thread_safe_sender_;
+ scoped_refptr<base::SingleThreadTaskRunner> main_loop_;
+ IDMap<blink::WebNavigatorConnectPortCallbacks, IDMapOwnPointer> requests_;
+
+ DISALLOW_COPY_AND_ASSIGN(NavigatorConnectProvider);
+};
+
+} // namespace content
+
+#endif // CONTENT_CHILD_NAVIGATOR_CONNECT_NAVIGATOR_CONNECT_PROVIDER_H_
diff --git a/chromium/content/child/notifications/OWNERS b/chromium/content/child/notifications/OWNERS
index 2fca67fdfda..e0a6572eb52 100644
--- a/chromium/content/child/notifications/OWNERS
+++ b/chromium/content/child/notifications/OWNERS
@@ -1 +1,4 @@
+johnme@chromium.org
+mkwst@chromium.org
+mvanouwerkerk@chromium.org
peter@chromium.org \ No newline at end of file
diff --git a/chromium/content/child/notifications/notification_data_conversions.cc b/chromium/content/child/notifications/notification_data_conversions.cc
new file mode 100644
index 00000000000..f5fe5bb12ef
--- /dev/null
+++ b/chromium/content/child/notifications/notification_data_conversions.cc
@@ -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.
+
+#include "content/child/notifications/notification_data_conversions.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/platform/WebURL.h"
+
+using blink::WebNotificationData;
+
+namespace content {
+
+PlatformNotificationData ToPlatformNotificationData(
+ const WebNotificationData& web_data) {
+ PlatformNotificationData platform_data;
+ platform_data.title = web_data.title;
+ platform_data.direction =
+ web_data.direction == WebNotificationData::DirectionLeftToRight
+ ? PlatformNotificationData::NotificationDirectionLeftToRight
+ : PlatformNotificationData::NotificationDirectionRightToLeft;
+ platform_data.lang = base::UTF16ToUTF8(web_data.lang);
+ platform_data.body = web_data.body;
+ platform_data.tag = base::UTF16ToUTF8(web_data.tag);
+ platform_data.icon = GURL(web_data.icon.string());
+ platform_data.vibration_pattern.assign(web_data.vibrate.begin(),
+ web_data.vibrate.end());
+ platform_data.silent = web_data.silent;
+ platform_data.data.assign(web_data.data.begin(), web_data.data.end());
+
+ return platform_data;
+}
+
+WebNotificationData ToWebNotificationData(
+ const PlatformNotificationData& platform_data) {
+ WebNotificationData web_data;
+ web_data.title = platform_data.title;
+ web_data.direction =
+ platform_data.direction ==
+ PlatformNotificationData::NotificationDirectionLeftToRight
+ ? WebNotificationData::DirectionLeftToRight
+ : WebNotificationData::DirectionRightToLeft;
+ web_data.lang = blink::WebString::fromUTF8(platform_data.lang);
+ web_data.body = platform_data.body;
+ web_data.tag = blink::WebString::fromUTF8(platform_data.tag);
+ web_data.icon = blink::WebURL(platform_data.icon);
+ web_data.vibrate = platform_data.vibration_pattern;
+ web_data.silent = platform_data.silent;
+ web_data.data = platform_data.data;
+
+ return web_data;
+}
+
+} // namespace content
diff --git a/chromium/content/child/notifications/notification_data_conversions.h b/chromium/content/child/notifications/notification_data_conversions.h
new file mode 100644
index 00000000000..24a8bab1000
--- /dev/null
+++ b/chromium/content/child/notifications/notification_data_conversions.h
@@ -0,0 +1,24 @@
+// Copyright 2014 The Chromium Authors. 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_CHILD_NOTIFICATIONS_NOTIFICATION_DATA_CONVERSIONS_H_
+#define CONTENT_CHILD_NOTIFICATIONS_NOTIFICATION_DATA_CONVERSIONS_H_
+
+#include "content/common/content_export.h"
+#include "content/public/common/platform_notification_data.h"
+#include "third_party/WebKit/public/platform/modules/notifications/WebNotificationData.h"
+
+namespace content {
+
+// Converts Blink WebNotificationData to PlatformNotificationData.
+CONTENT_EXPORT PlatformNotificationData ToPlatformNotificationData(
+ const blink::WebNotificationData& web_data);
+
+// Converts PlatformNotificationData to Blink WebNotificationData.
+CONTENT_EXPORT blink::WebNotificationData ToWebNotificationData(
+ const PlatformNotificationData& platform_data);
+
+} // namespace content
+
+#endif // CONTENT_CHILD_NOTIFICATIONS_NOTIFICATION_DATA_CONVERSIONS_H_
diff --git a/chromium/content/child/notifications/notification_data_conversions_unittest.cc b/chromium/content/child/notifications/notification_data_conversions_unittest.cc
new file mode 100644
index 00000000000..c124e4f0e3e
--- /dev/null
+++ b/chromium/content/child/notifications/notification_data_conversions_unittest.cc
@@ -0,0 +1,137 @@
+// Copyright 2014 The Chromium Authors. 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/child/notifications/notification_data_conversions.h"
+
+#include <stdint.h>
+
+#include "base/strings/utf_string_conversions.h"
+#include "content/public/common/platform_notification_data.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/platform/WebURL.h"
+#include "third_party/WebKit/public/platform/modules/notifications/WebNotificationData.h"
+
+namespace content {
+
+const char kNotificationTitle[] = "My Notification";
+const char kNotificationLang[] = "nl";
+const char kNotificationBody[] = "Hello, world!";
+const char kNotificationTag[] = "my_tag";
+const char kNotificationIconUrl[] = "https://example.com/icon.png";
+const int kNotificationVibrationPattern[] = { 100, 200, 300 };
+const unsigned char kNotificationData[] = { 0xdf, 0xff, 0x0, 0x0, 0xff, 0xdf };
+
+TEST(NotificationDataConversionsTest, ToPlatformNotificationData) {
+ std::vector<int> vibration_pattern(
+ kNotificationVibrationPattern,
+ kNotificationVibrationPattern + arraysize(kNotificationVibrationPattern));
+
+ std::vector<char> developer_data(
+ kNotificationData, kNotificationData + arraysize(kNotificationData));
+
+ blink::WebNotificationData web_data(
+ blink::WebString::fromUTF8(kNotificationTitle),
+ blink::WebNotificationData::DirectionLeftToRight,
+ blink::WebString::fromUTF8(kNotificationLang),
+ blink::WebString::fromUTF8(kNotificationBody),
+ blink::WebString::fromUTF8(kNotificationTag),
+ blink::WebURL(GURL(kNotificationIconUrl)),
+ blink::WebVector<int>(vibration_pattern),
+ true /* silent */,
+ blink::WebVector<char>(developer_data));
+
+ PlatformNotificationData platform_data = ToPlatformNotificationData(web_data);
+ EXPECT_EQ(base::ASCIIToUTF16(kNotificationTitle), platform_data.title);
+ EXPECT_EQ(PlatformNotificationData::NotificationDirectionLeftToRight,
+ platform_data.direction);
+ EXPECT_EQ(kNotificationLang, platform_data.lang);
+ EXPECT_EQ(base::ASCIIToUTF16(kNotificationBody), platform_data.body);
+ EXPECT_EQ(kNotificationTag, platform_data.tag);
+ EXPECT_EQ(kNotificationIconUrl, platform_data.icon.spec());
+ EXPECT_TRUE(platform_data.silent);
+
+ EXPECT_THAT(platform_data.vibration_pattern,
+ testing::ElementsAreArray(kNotificationVibrationPattern));
+
+ ASSERT_EQ(developer_data.size(), platform_data.data.size());
+ for (size_t i = 0; i < developer_data.size(); ++i)
+ EXPECT_EQ(developer_data[i], platform_data.data[i]);
+}
+
+TEST(NotificationDataConversionsTest,
+ ToPlatformNotificationDataDirectionality) {
+ blink::WebNotificationData web_data;
+ web_data.direction = blink::WebNotificationData::DirectionLeftToRight;
+
+ PlatformNotificationData platform_data = ToPlatformNotificationData(web_data);
+ EXPECT_EQ(PlatformNotificationData::NotificationDirectionLeftToRight,
+ platform_data.direction);
+
+ web_data.direction = blink::WebNotificationData::DirectionRightToLeft;
+
+ platform_data = ToPlatformNotificationData(web_data);
+ EXPECT_EQ(PlatformNotificationData::NotificationDirectionRightToLeft,
+ platform_data.direction);
+}
+
+TEST(NotificationDataConversionsTest, ToWebNotificationData) {
+ std::vector<int> vibration_pattern(
+ kNotificationVibrationPattern,
+ kNotificationVibrationPattern + arraysize(kNotificationVibrationPattern));
+
+ std::vector<char> developer_data(
+ kNotificationData, kNotificationData + arraysize(kNotificationData));
+
+ PlatformNotificationData platform_data;
+ platform_data.title = base::ASCIIToUTF16(kNotificationTitle);
+ platform_data.direction =
+ PlatformNotificationData::NotificationDirectionLeftToRight;
+ platform_data.lang = kNotificationLang;
+ platform_data.body = base::ASCIIToUTF16(kNotificationBody);
+ platform_data.tag = kNotificationTag;
+ platform_data.icon = GURL(kNotificationIconUrl);
+ platform_data.vibration_pattern = vibration_pattern;
+ platform_data.silent = true;
+ platform_data.data = developer_data;
+
+ blink::WebNotificationData web_data = ToWebNotificationData(platform_data);
+ EXPECT_EQ(kNotificationTitle, web_data.title);
+ EXPECT_EQ(blink::WebNotificationData::DirectionLeftToRight,
+ web_data.direction);
+ EXPECT_EQ(kNotificationLang, web_data.lang);
+ EXPECT_EQ(kNotificationBody, web_data.body);
+ EXPECT_EQ(kNotificationTag, web_data.tag);
+ EXPECT_EQ(kNotificationIconUrl, web_data.icon.string());
+
+ ASSERT_EQ(vibration_pattern.size(), web_data.vibrate.size());
+ for (size_t i = 0; i < vibration_pattern.size(); ++i)
+ EXPECT_EQ(vibration_pattern[i], web_data.vibrate[i]);
+
+ EXPECT_TRUE(web_data.silent);
+
+ ASSERT_EQ(developer_data.size(), web_data.data.size());
+ for (size_t i = 0; i < developer_data.size(); ++i)
+ EXPECT_EQ(developer_data[i], web_data.data[i]);
+}
+
+TEST(NotificationDataConversionsTest, ToWebNotificationDataDirectionality) {
+ PlatformNotificationData platform_data;
+ platform_data.direction =
+ PlatformNotificationData::NotificationDirectionLeftToRight;
+
+ blink::WebNotificationData web_data = ToWebNotificationData(platform_data);
+ EXPECT_EQ(blink::WebNotificationData::DirectionLeftToRight,
+ web_data.direction);
+
+ platform_data.direction =
+ PlatformNotificationData::NotificationDirectionRightToLeft;
+
+ web_data = ToWebNotificationData(platform_data);
+ EXPECT_EQ(blink::WebNotificationData::DirectionRightToLeft,
+ web_data.direction);
+}
+
+} // namespace content
diff --git a/chromium/content/child/notifications/notification_dispatcher.cc b/chromium/content/child/notifications/notification_dispatcher.cc
index 45f6df01719..e99ddc43da5 100644
--- a/chromium/content/child/notifications/notification_dispatcher.cc
+++ b/chromium/content/child/notifications/notification_dispatcher.cc
@@ -4,67 +4,53 @@
#include "content/child/notifications/notification_dispatcher.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include <limits>
+
#include "content/child/notifications/notification_manager.h"
-#include "content/child/thread_safe_sender.h"
-#include "content/child/worker_thread_task_runner.h"
-#include "content/common/platform_notification_messages.h"
namespace content {
NotificationDispatcher::NotificationDispatcher(
ThreadSafeSender* thread_safe_sender)
- : main_thread_loop_proxy_(base::MessageLoopProxy::current()),
- thread_safe_sender_(thread_safe_sender) {
+ : WorkerThreadMessageFilter(thread_safe_sender) {
}
NotificationDispatcher::~NotificationDispatcher() {}
int NotificationDispatcher::GenerateNotificationId(int thread_id) {
base::AutoLock lock(notification_id_map_lock_);
+ CHECK_LT(next_notification_id_, std::numeric_limits<int>::max());
+
notification_id_map_[next_notification_id_] = thread_id;
return next_notification_id_++;
}
-base::TaskRunner* NotificationDispatcher::OverrideTaskRunnerForMessage(
- const IPC::Message& msg) {
- if (!ShouldHandleMessage(msg))
- return NULL;
+bool NotificationDispatcher::ShouldHandleMessage(
+ const IPC::Message& msg) const {
+ return IPC_MESSAGE_CLASS(msg) == PlatformNotificationMsgStart;
+}
- int notification_id = -1,
- thread_id = 0;
+void NotificationDispatcher::OnFilteredMessageReceived(
+ const IPC::Message& msg) {
+ NotificationManager::ThreadSpecificInstance(thread_safe_sender(),
+ main_thread_task_runner(),
+ this)->OnMessageReceived(msg);
+}
+bool NotificationDispatcher::GetWorkerThreadIdForMessage(
+ const IPC::Message& msg,
+ int* ipc_thread_id) {
+ int notification_id = -1;
const bool success = PickleIterator(msg).ReadInt(&notification_id);
DCHECK(success);
- {
- base::AutoLock lock(notification_id_map_lock_);
- auto iterator = notification_id_map_.find(notification_id);
- if (iterator != notification_id_map_.end())
- thread_id = iterator->second;
+ base::AutoLock lock(notification_id_map_lock_);
+ auto iterator = notification_id_map_.find(notification_id);
+ if (iterator != notification_id_map_.end()) {
+ *ipc_thread_id = iterator->second;
+ return true;
}
-
- if (!thread_id)
- return main_thread_loop_proxy_.get();
-
- return new WorkerThreadTaskRunner(thread_id);
-}
-
-bool NotificationDispatcher::OnMessageReceived(const IPC::Message& msg) {
- if (!ShouldHandleMessage(msg))
- return false;
-
- NotificationManager::ThreadSpecificInstance(thread_safe_sender_.get(), this)
- ->OnMessageReceived(msg);
- return true;
-}
-
-bool NotificationDispatcher::ShouldHandleMessage(const IPC::Message& msg) {
- // The thread-safe message filter is responsible for handling all the messages
- // except for the routed permission-request-completed message, which will be
- // picked up by the RenderFrameImpl instead.
- return IPC_MESSAGE_CLASS(msg) == PlatformNotificationMsgStart &&
- msg.type() != PlatformNotificationMsg_PermissionRequestComplete::ID;
+ return false;
}
} // namespace content
diff --git a/chromium/content/child/notifications/notification_dispatcher.h b/chromium/content/child/notifications/notification_dispatcher.h
index be4ada94f24..297f38b6b28 100644
--- a/chromium/content/child/notifications/notification_dispatcher.h
+++ b/chromium/content/child/notifications/notification_dispatcher.h
@@ -7,19 +7,12 @@
#include <map>
-#include "base/memory/ref_counted.h"
#include "base/synchronization/lock.h"
-#include "content/child/child_message_filter.h"
-
-namespace base {
-class MessageLoopProxy;
-}
+#include "content/child/worker_thread_message_filter.h"
namespace content {
-class ThreadSafeSender;
-
-class NotificationDispatcher : public ChildMessageFilter {
+class NotificationDispatcher : public WorkerThreadMessageFilter {
public:
explicit NotificationDispatcher(ThreadSafeSender* thread_safe_sender);
@@ -31,21 +24,17 @@ class NotificationDispatcher : public ChildMessageFilter {
~NotificationDispatcher() override;
private:
- bool ShouldHandleMessage(const IPC::Message& msg);
-
- // ChildMessageFilter implementation.
- base::TaskRunner* OverrideTaskRunnerForMessage(const IPC::Message& msg)
- override;
- bool OnMessageReceived(const IPC::Message& msg) override;
-
- scoped_refptr<base::MessageLoopProxy> main_thread_loop_proxy_;
- scoped_refptr<ThreadSafeSender> thread_safe_sender_;
+ // WorkerThreadMessageFilter:
+ bool ShouldHandleMessage(const IPC::Message& msg) const override;
+ void OnFilteredMessageReceived(const IPC::Message& msg) override;
+ bool GetWorkerThreadIdForMessage(const IPC::Message& msg,
+ int* ipc_thread_id) override;
using NotificationIdToThreadId = std::map<int, int>;
base::Lock notification_id_map_lock_;
NotificationIdToThreadId notification_id_map_;
- int next_notification_id_;
+ int next_notification_id_ = 0;
DISALLOW_COPY_AND_ASSIGN(NotificationDispatcher);
};
diff --git a/chromium/content/child/notifications/notification_image_loader.cc b/chromium/content/child/notifications/notification_image_loader.cc
new file mode 100644
index 00000000000..0478188de4f
--- /dev/null
+++ b/chromium/content/child/notifications/notification_image_loader.cc
@@ -0,0 +1,113 @@
+// Copyright 2014 The Chromium Authors. 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/child/notifications/notification_image_loader.h"
+
+#include "base/logging.h"
+#include "base/thread_task_runner_handle.h"
+#include "content/child/child_thread_impl.h"
+#include "content/child/image_decoder.h"
+#include "third_party/WebKit/public/platform/Platform.h"
+#include "third_party/WebKit/public/platform/WebURL.h"
+#include "third_party/WebKit/public/platform/WebURLLoader.h"
+#include "third_party/WebKit/public/platform/WebURLRequest.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+using blink::WebURL;
+using blink::WebURLError;
+using blink::WebURLLoader;
+using blink::WebURLRequest;
+
+namespace content {
+
+NotificationImageLoader::NotificationImageLoader(
+ const ImageLoadCompletedCallback& callback,
+ const scoped_refptr<base::SingleThreadTaskRunner>& worker_task_runner)
+ : callback_(callback),
+ worker_task_runner_(worker_task_runner),
+ notification_id_(0),
+ completed_(false) {}
+
+NotificationImageLoader::~NotificationImageLoader() {
+ if (main_thread_task_runner_)
+ DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
+}
+
+void NotificationImageLoader::StartOnMainThread(int notification_id,
+ const GURL& image_url) {
+ DCHECK(ChildThreadImpl::current());
+ DCHECK(!url_loader_);
+
+ main_thread_task_runner_ = base::ThreadTaskRunnerHandle::Get();
+ notification_id_ = notification_id;
+
+ WebURL image_web_url(image_url);
+ WebURLRequest request(image_web_url);
+ request.setRequestContext(WebURLRequest::RequestContextImage);
+
+ url_loader_.reset(blink::Platform::current()->createURLLoader());
+ url_loader_->loadAsynchronously(request, this);
+}
+
+void NotificationImageLoader::didReceiveData(
+ WebURLLoader* loader,
+ const char* data,
+ int data_length,
+ int encoded_data_length) {
+ DCHECK(!completed_);
+ DCHECK_GT(data_length, 0);
+
+ buffer_.insert(buffer_.end(), data, data + data_length);
+}
+
+void NotificationImageLoader::didFinishLoading(
+ WebURLLoader* loader,
+ double finish_time,
+ int64_t total_encoded_data_length) {
+ DCHECK(!completed_);
+
+ RunCallbackOnWorkerThread();
+}
+
+void NotificationImageLoader::didFail(WebURLLoader* loader,
+ const WebURLError& error) {
+ if (completed_)
+ return;
+
+ RunCallbackOnWorkerThread();
+}
+
+void NotificationImageLoader::RunCallbackOnWorkerThread() {
+ url_loader_.reset();
+
+ completed_ = true;
+ SkBitmap icon = GetDecodedImage();
+
+ if (worker_task_runner_->BelongsToCurrentThread()) {
+ callback_.Run(notification_id_, icon);
+ } else {
+ worker_task_runner_->PostTask(
+ FROM_HERE, base::Bind(callback_, notification_id_, icon));
+ }
+}
+
+SkBitmap NotificationImageLoader::GetDecodedImage() const {
+ DCHECK(completed_);
+ if (buffer_.empty())
+ return SkBitmap();
+
+ ImageDecoder decoder;
+ return decoder.Decode(&buffer_[0], buffer_.size());
+}
+
+void NotificationImageLoader::DeleteOnCorrectThread() const {
+ if (!ChildThreadImpl::current()) {
+ main_thread_task_runner_->DeleteSoon(FROM_HERE, this);
+ return;
+ }
+
+ delete this;
+}
+
+} // namespace content
diff --git a/chromium/content/child/notifications/notification_image_loader.h b/chromium/content/child/notifications/notification_image_loader.h
new file mode 100644
index 00000000000..33a38f065a9
--- /dev/null
+++ b/chromium/content/child/notifications/notification_image_loader.h
@@ -0,0 +1,108 @@
+// Copyright 2014 The Chromium Authors. 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_CHILD_NOTIFICATIONS_NOTIFICATION_IMAGE_LOADER_H_
+#define CONTENT_CHILD_NOTIFICATIONS_NOTIFICATION_IMAGE_LOADER_H_
+
+#include <vector>
+
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/sequenced_task_runner_helpers.h"
+#include "third_party/WebKit/public/platform/WebURLLoaderClient.h"
+
+class GURL;
+class SkBitmap;
+
+namespace base {
+class SingleThreadTaskRunner;
+}
+
+namespace blink {
+class WebURL;
+struct WebURLError;
+class WebURLLoader;
+}
+
+namespace content {
+
+struct NotificationImageLoaderDeleter;
+
+// Downloads the image associated with a notification and decodes the received
+// image. This must be completed before notifications are shown to the user.
+// Image downloaders must not be re-used for multiple notifications.
+//
+// All methods, except for the constructor, are expected to be used on the
+// renderer main thread.
+class NotificationImageLoader
+ : public blink::WebURLLoaderClient,
+ public base::RefCountedThreadSafe<NotificationImageLoader,
+ NotificationImageLoaderDeleter> {
+ using ImageLoadCompletedCallback = base::Callback<void(int, const SkBitmap&)>;
+
+ public:
+ NotificationImageLoader(
+ const ImageLoadCompletedCallback& callback,
+ const scoped_refptr<base::SingleThreadTaskRunner>& worker_task_runner);
+
+ // Asynchronously starts loading |image_url| using a Blink WebURLLoader. Must
+ // only be called on the main thread.
+ void StartOnMainThread(int notification_id, const GURL& image_url);
+
+ // blink::WebURLLoaderClient implementation.
+ virtual void didReceiveData(blink::WebURLLoader* loader,
+ const char* data,
+ int data_length,
+ int encoded_data_length);
+ virtual void didFinishLoading(blink::WebURLLoader* loader,
+ double finish_time,
+ int64_t total_encoded_data_length);
+ virtual void didFail(blink::WebURLLoader* loader,
+ const blink::WebURLError& error);
+
+ private:
+ friend class base::DeleteHelper<NotificationImageLoader>;
+ friend class base::RefCountedThreadSafe<NotificationImageLoader,
+ NotificationImageLoaderDeleter>;
+ friend struct NotificationImageLoaderDeleter;
+
+ virtual ~NotificationImageLoader();
+
+ // Invokes the callback on the thread this image loader was started for. When
+ // the thread id is zero (the main document), it will be executed immediately.
+ // For all other threads a task will be posted to the appropriate task runner.
+ void RunCallbackOnWorkerThread();
+
+ // Returns a Skia bitmap, empty if buffer_ was empty or could not be decoded
+ // as an image, or a valid bitmap otherwise.
+ SkBitmap GetDecodedImage() const;
+
+ // Ensures that we delete the image loader on the main thread.
+ void DeleteOnCorrectThread() const;
+
+ ImageLoadCompletedCallback callback_;
+
+ scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner_;
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
+
+ int notification_id_;
+ bool completed_;
+
+ scoped_ptr<blink::WebURLLoader> url_loader_;
+
+ std::vector<uint8_t> buffer_;
+
+ DISALLOW_COPY_AND_ASSIGN(NotificationImageLoader);
+};
+
+struct NotificationImageLoaderDeleter {
+ static void Destruct(const NotificationImageLoader* context) {
+ context->DeleteOnCorrectThread();
+ }
+};
+
+} // namespace content
+
+#endif // CONTENT_CHILD_NOTIFICATIONS_NOTIFICATION_IMAGE_LOADER_H_
diff --git a/chromium/content/child/notifications/notification_manager.cc b/chromium/content/child/notifications/notification_manager.cc
index 4ffc890718f..e39588e44ab 100644
--- a/chromium/content/child/notifications/notification_manager.cc
+++ b/chromium/content/child/notifications/notification_manager.cc
@@ -4,16 +4,21 @@
#include "content/child/notifications/notification_manager.h"
+#include <cmath>
+
#include "base/lazy_instance.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
#include "base/threading/thread_local.h"
+#include "content/child/notifications/notification_data_conversions.h"
#include "content/child/notifications/notification_dispatcher.h"
+#include "content/child/service_worker/web_service_worker_registration_impl.h"
#include "content/child/thread_safe_sender.h"
#include "content/child/worker_task_runner.h"
-#include "content/common/platform_notification_messages.h"
-#include "content/public/common/show_desktop_notification_params.h"
-#include "third_party/WebKit/public/platform/WebNotificationData.h"
-#include "third_party/WebKit/public/platform/WebNotificationDelegate.h"
+#include "content/public/common/platform_notification_data.h"
#include "third_party/WebKit/public/platform/WebSerializedOrigin.h"
+#include "third_party/WebKit/public/platform/modules/notifications/WebNotificationDelegate.h"
#include "third_party/skia/include/core/SkBitmap.h"
using blink::WebNotificationPermission;
@@ -32,9 +37,11 @@ static base::LazyInstance<base::ThreadLocalPointer<NotificationManager>>::Leaky
NotificationManager::NotificationManager(
ThreadSafeSender* thread_safe_sender,
+ base::SingleThreadTaskRunner* main_thread_task_runner,
NotificationDispatcher* notification_dispatcher)
: thread_safe_sender_(thread_safe_sender),
- notification_dispatcher_(notification_dispatcher) {
+ notification_dispatcher_(notification_dispatcher),
+ pending_notifications_(main_thread_task_runner) {
g_notification_manager_tls.Pointer()->Set(this);
}
@@ -44,13 +51,14 @@ NotificationManager::~NotificationManager() {
NotificationManager* NotificationManager::ThreadSpecificInstance(
ThreadSafeSender* thread_safe_sender,
+ base::SingleThreadTaskRunner* main_thread_task_runner,
NotificationDispatcher* notification_dispatcher) {
if (g_notification_manager_tls.Pointer()->Get())
return g_notification_manager_tls.Pointer()->Get();
NotificationManager* manager = new NotificationManager(
- thread_safe_sender, notification_dispatcher);
- if (WorkerTaskRunner::Instance()->CurrentWorkerId())
+ thread_safe_sender, main_thread_task_runner, notification_dispatcher);
+ if (CurrentWorkerId())
WorkerTaskRunner::Instance()->AddStopObserver(manager);
return manager;
}
@@ -63,56 +71,136 @@ void NotificationManager::show(
const blink::WebSerializedOrigin& origin,
const blink::WebNotificationData& notification_data,
blink::WebNotificationDelegate* delegate) {
- int notification_id =
- notification_dispatcher_->GenerateNotificationId(CurrentWorkerId());
+ if (notification_data.icon.isEmpty()) {
+ DisplayPageNotification(origin, notification_data, delegate, SkBitmap());
+ return;
+ }
+
+ pending_notifications_.FetchPageNotificationResources(
+ notification_data,
+ delegate,
+ base::Bind(&NotificationManager::DisplayPageNotification,
+ base::Unretained(this), // this owns |pending_notifications_|
+ origin,
+ notification_data,
+ delegate));
+}
+
+void NotificationManager::showPersistent(
+ const blink::WebSerializedOrigin& origin,
+ const blink::WebNotificationData& notification_data,
+ blink::WebServiceWorkerRegistration* service_worker_registration,
+ blink::WebNotificationShowCallbacks* callbacks) {
+ DCHECK(service_worker_registration);
+ int64_t service_worker_registration_id =
+ static_cast<WebServiceWorkerRegistrationImpl*>(
+ service_worker_registration)->registration_id();
+
+ scoped_ptr<blink::WebNotificationShowCallbacks> owned_callbacks(callbacks);
+
+ // Verify that the author-provided payload size does not exceed our limit.
+ // This is an implementation-defined limit to prevent abuse of notification
+ // data as a storage mechanism. A UMA histogram records the requested sizes,
+ // which enables us to track how much data authors are attempting to store.
+ //
+ // If the size exceeds this limit, reject the showNotification() promise. This
+ // is outside of the boundaries set by the specification, but it gives authors
+ // an indication that something has gone wrong.
+ size_t author_data_size = notification_data.data.size();
+ UMA_HISTOGRAM_MEMORY_KB("Notifications.AuthorDataSizeKB",
+ static_cast<int>(ceil(author_data_size / 1024.0)));
+
+ if (author_data_size > PlatformNotificationData::kMaximumDeveloperDataSize) {
+ owned_callbacks->onError();
+ return;
+ }
+
+ if (notification_data.icon.isEmpty()) {
+ DisplayPersistentNotification(origin,
+ notification_data,
+ service_worker_registration_id,
+ owned_callbacks.Pass(),
+ SkBitmap());
+ return;
+ }
+
+ pending_notifications_.FetchPersistentNotificationResources(
+ notification_data,
+ base::Bind(&NotificationManager::DisplayPersistentNotification,
+ base::Unretained(this), // this owns |pending_notifications_|
+ origin,
+ notification_data,
+ service_worker_registration_id,
+ base::Passed(&owned_callbacks)));
+}
- active_notifications_[notification_id] = delegate;
+void NotificationManager::getNotifications(
+ const blink::WebString& filter_tag,
+ blink::WebServiceWorkerRegistration* service_worker_registration,
+ blink::WebNotificationGetCallbacks* callbacks) {
+ DCHECK(service_worker_registration);
+ DCHECK(callbacks);
- ShowDesktopNotificationHostMsgParams params;
- params.origin = GURL(origin.string());
+ WebServiceWorkerRegistrationImpl* service_worker_registration_impl =
+ static_cast<WebServiceWorkerRegistrationImpl*>(
+ service_worker_registration);
- // TODO(peter): Move the notification_icon_loader to //content/child/ and use
- // it to download Notification icons here.
- params.icon = SkBitmap();
- params.title = notification_data.title;
- params.body = notification_data.body;
+ GURL origin = GURL(service_worker_registration_impl->scope()).GetOrigin();
+ int64_t service_worker_registration_id =
+ service_worker_registration_impl->registration_id();
- // TODO(peter): Remove the usage of the Blink WebTextDirection enumeration for
- // the text direction of notifications throughout Chrome.
- params.direction = blink::WebTextDirectionLeftToRight;
- params.replace_id = notification_data.tag;
+ // TODO(peter): GenerateNotificationId is more of a request id. Consider
+ // renaming the method in the NotificationDispatcher if this makes sense.
+ int request_id =
+ notification_dispatcher_->GenerateNotificationId(CurrentWorkerId());
- thread_safe_sender_->Send(new PlatformNotificationHostMsg_Show(
- notification_id, params));
+ pending_get_notification_requests_.AddWithID(callbacks, request_id);
+
+ thread_safe_sender_->Send(
+ new PlatformNotificationHostMsg_GetNotifications(
+ request_id,
+ service_worker_registration_id,
+ origin,
+ base::UTF16ToUTF8(filter_tag)));
}
void NotificationManager::close(blink::WebNotificationDelegate* delegate) {
- auto iter = active_notifications_.begin();
- for (; iter != active_notifications_.end(); ++iter) {
- if (iter->second != delegate)
+ if (pending_notifications_.CancelPageNotificationFetches(delegate))
+ return;
+
+ for (auto& iter : active_page_notifications_) {
+ if (iter.second != delegate)
continue;
thread_safe_sender_->Send(
- new PlatformNotificationHostMsg_Close(iter->first));
- active_notifications_.erase(iter);
-
- delegate->dispatchCloseEvent();
+ new PlatformNotificationHostMsg_Close(iter.first));
+ active_page_notifications_.erase(iter.first);
return;
}
// It should not be possible for Blink to call close() on a Notification which
- // does not exist anymore in the manager.
+ // does not exist in either the pending or active notification lists.
NOTREACHED();
}
+void NotificationManager::closePersistent(
+ const blink::WebSerializedOrigin& origin,
+ int64_t persistent_notification_id) {
+ thread_safe_sender_->Send(new PlatformNotificationHostMsg_ClosePersistent(
+ GURL(origin.string()),
+ persistent_notification_id));
+}
+
void NotificationManager::notifyDelegateDestroyed(
blink::WebNotificationDelegate* delegate) {
- auto iter = active_notifications_.begin();
- for (; iter != active_notifications_.end(); ++iter) {
- if (iter->second != delegate)
+ if (pending_notifications_.CancelPageNotificationFetches(delegate))
+ return;
+
+ for (auto& iter : active_page_notifications_) {
+ if (iter.second != delegate)
continue;
- active_notifications_.erase(iter);
+ active_page_notifications_.erase(iter.first);
return;
}
}
@@ -130,38 +218,125 @@ WebNotificationPermission NotificationManager::checkPermission(
bool NotificationManager::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(NotificationManager, message)
- IPC_MESSAGE_HANDLER(PlatformNotificationMsg_DidShow, OnShow);
- IPC_MESSAGE_HANDLER(PlatformNotificationMsg_DidClose, OnClose);
- IPC_MESSAGE_HANDLER(PlatformNotificationMsg_DidClick, OnClick);
+ IPC_MESSAGE_HANDLER(PlatformNotificationMsg_DidShow, OnDidShow);
+ IPC_MESSAGE_HANDLER(PlatformNotificationMsg_DidShowPersistent,
+ OnDidShowPersistent)
+ IPC_MESSAGE_HANDLER(PlatformNotificationMsg_DidClose, OnDidClose);
+ IPC_MESSAGE_HANDLER(PlatformNotificationMsg_DidClick, OnDidClick);
+ IPC_MESSAGE_HANDLER(PlatformNotificationMsg_DidGetNotifications,
+ OnDidGetNotifications)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
-void NotificationManager::OnShow(int id) {
- const auto& iter = active_notifications_.find(id);
- if (iter == active_notifications_.end())
+void NotificationManager::OnDidShow(int notification_id) {
+ const auto& iter = active_page_notifications_.find(notification_id);
+ if (iter == active_page_notifications_.end())
return;
iter->second->dispatchShowEvent();
}
-void NotificationManager::OnClose(int id) {
- const auto& iter = active_notifications_.find(id);
- if (iter == active_notifications_.end())
+void NotificationManager::OnDidShowPersistent(int request_id, bool success) {
+ blink::WebNotificationShowCallbacks* callbacks =
+ pending_show_notification_requests_.Lookup(request_id);
+ DCHECK(callbacks);
+
+ if (!callbacks)
+ return;
+
+ if (success)
+ callbacks->onSuccess();
+ else
+ callbacks->onError();
+
+ pending_show_notification_requests_.Remove(request_id);
+}
+
+void NotificationManager::OnDidClose(int notification_id) {
+ const auto& iter = active_page_notifications_.find(notification_id);
+ if (iter == active_page_notifications_.end())
return;
iter->second->dispatchCloseEvent();
- active_notifications_.erase(iter);
+ active_page_notifications_.erase(iter);
}
-void NotificationManager::OnClick(int id) {
- const auto& iter = active_notifications_.find(id);
- if (iter == active_notifications_.end())
+void NotificationManager::OnDidClick(int notification_id) {
+ const auto& iter = active_page_notifications_.find(notification_id);
+ if (iter == active_page_notifications_.end())
return;
iter->second->dispatchClickEvent();
}
+void NotificationManager::OnDidGetNotifications(
+ int request_id,
+ const std::vector<PersistentNotificationInfo>& notification_infos) {
+ blink::WebNotificationGetCallbacks* callbacks =
+ pending_get_notification_requests_.Lookup(request_id);
+ DCHECK(callbacks);
+ if (!callbacks)
+ return;
+
+ scoped_ptr<blink::WebVector<blink::WebPersistentNotificationInfo>>
+ notifications(new blink::WebVector<blink::WebPersistentNotificationInfo>(
+ notification_infos.size()));
+
+ for (size_t i = 0; i < notification_infos.size(); ++i) {
+ blink::WebPersistentNotificationInfo web_notification_info;
+ web_notification_info.persistentId = notification_infos[i].first;
+ web_notification_info.data =
+ ToWebNotificationData(notification_infos[i].second);
+
+ (*notifications)[i] = web_notification_info;
+ }
+
+ callbacks->onSuccess(notifications.release());
+
+ pending_get_notification_requests_.Remove(request_id);
+}
+
+void NotificationManager::DisplayPageNotification(
+ const blink::WebSerializedOrigin& origin,
+ const blink::WebNotificationData& notification_data,
+ blink::WebNotificationDelegate* delegate,
+ const SkBitmap& icon) {
+ int notification_id =
+ notification_dispatcher_->GenerateNotificationId(CurrentWorkerId());
+
+ active_page_notifications_[notification_id] = delegate;
+ thread_safe_sender_->Send(
+ new PlatformNotificationHostMsg_Show(
+ notification_id,
+ GURL(origin.string()),
+ icon,
+ ToPlatformNotificationData(notification_data)));
+}
+
+void NotificationManager::DisplayPersistentNotification(
+ const blink::WebSerializedOrigin& origin,
+ const blink::WebNotificationData& notification_data,
+ int64_t service_worker_registration_id,
+ scoped_ptr<blink::WebNotificationShowCallbacks> callbacks,
+ const SkBitmap& icon) {
+ // TODO(peter): GenerateNotificationId is more of a request id. Consider
+ // renaming the method in the NotificationDispatcher if this makes sense.
+ int request_id =
+ notification_dispatcher_->GenerateNotificationId(CurrentWorkerId());
+
+ pending_show_notification_requests_.AddWithID(callbacks.release(),
+ request_id);
+
+ thread_safe_sender_->Send(
+ new PlatformNotificationHostMsg_ShowPersistent(
+ request_id,
+ service_worker_registration_id,
+ GURL(origin.string()),
+ icon,
+ ToPlatformNotificationData(notification_data)));
+}
+
} // namespace content
diff --git a/chromium/content/child/notifications/notification_manager.h b/chromium/content/child/notifications/notification_manager.h
index 53013487d82..21769b5adff 100644
--- a/chromium/content/child/notifications/notification_manager.h
+++ b/chromium/content/child/notifications/notification_manager.h
@@ -6,16 +6,23 @@
#define CONTENT_CHILD_NOTIFICATIONS_NOTIFICATION_MANAGER_H_
#include <map>
+#include <set>
+#include <vector>
+#include "base/id_map.h"
#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
#include "content/child/notifications/notification_dispatcher.h"
+#include "content/child/notifications/pending_notifications_tracker.h"
#include "content/child/worker_task_runner.h"
-#include "third_party/WebKit/public/platform/WebNotificationManager.h"
+#include "content/common/platform_notification_messages.h"
+#include "third_party/WebKit/public/platform/modules/notifications/WebNotificationManager.h"
class SkBitmap;
namespace content {
+struct PlatformNotificationData;
class ThreadSafeSender;
class NotificationManager : public blink::WebNotificationManager,
@@ -27,6 +34,7 @@ class NotificationManager : public blink::WebNotificationManager,
// calling this leads to construction.
static NotificationManager* ThreadSpecificInstance(
ThreadSafeSender* thread_safe_sender,
+ base::SingleThreadTaskRunner* main_thread_task_runner,
NotificationDispatcher* notification_dispatcher);
// WorkerTaskRunner::Observer implementation.
@@ -36,7 +44,19 @@ class NotificationManager : public blink::WebNotificationManager,
virtual void show(const blink::WebSerializedOrigin& origin,
const blink::WebNotificationData& notification_data,
blink::WebNotificationDelegate* delegate);
+ virtual void showPersistent(
+ const blink::WebSerializedOrigin& origin,
+ const blink::WebNotificationData& notification_data,
+ blink::WebServiceWorkerRegistration* service_worker_registration,
+ blink::WebNotificationShowCallbacks* callbacks);
+ virtual void getNotifications(
+ const blink::WebString& filter_tag,
+ blink::WebServiceWorkerRegistration* service_worker_registration,
+ blink::WebNotificationGetCallbacks* callbacks);
virtual void close(blink::WebNotificationDelegate* delegate);
+ virtual void closePersistent(
+ const blink::WebSerializedOrigin& origin,
+ int64_t persistent_notification_id);
virtual void notifyDelegateDestroyed(
blink::WebNotificationDelegate* delegate);
virtual blink::WebNotificationPermission checkPermission(
@@ -48,18 +68,56 @@ class NotificationManager : public blink::WebNotificationManager,
private:
NotificationManager(
ThreadSafeSender* thread_safe_sender,
+ base::SingleThreadTaskRunner* main_thread_task_runner,
NotificationDispatcher* notification_dispatcher);
// IPC message handlers.
- void OnShow(int id);
- void OnClose(int id);
- void OnClick(int id);
+ void OnDidShow(int notification_id);
+ void OnDidShowPersistent(int request_id, bool success);
+ void OnDidClose(int notification_id);
+ void OnDidClick(int notification_id);
+ void OnDidGetNotifications(
+ int request_id,
+ const std::vector<PersistentNotificationInfo>& notification_infos);
+
+ // To be called when a page notification is ready to be displayed. Will
+ // inform the browser process about all available data. The |delegate|,
+ // owned by Blink, will be used to feed back events associated with the
+ // notification to the JavaScript object.
+ void DisplayPageNotification(
+ const blink::WebSerializedOrigin& origin,
+ const blink::WebNotificationData& notification_data,
+ blink::WebNotificationDelegate* delegate,
+ const SkBitmap& icon);
+
+ // To be called when a persistent notification is ready to be displayed. Will
+ // inform the browser process about all available data. The |callbacks| will
+ // be used to inform the Promise pending in Blink that the notification has
+ // been send to the browser process to be displayed.
+ void DisplayPersistentNotification(
+ const blink::WebSerializedOrigin& origin,
+ const blink::WebNotificationData& notification_data,
+ int64 service_worker_registration_id,
+ scoped_ptr<blink::WebNotificationShowCallbacks> callbacks,
+ const SkBitmap& icon);
scoped_refptr<ThreadSafeSender> thread_safe_sender_;
scoped_refptr<NotificationDispatcher> notification_dispatcher_;
+ // Tracker which stores all pending Notifications, both page and persistent
+ // ones, until all their associated resources have been fetched.
+ PendingNotificationsTracker pending_notifications_;
+
+ // Tracks pending requests for getting a list of notifications.
+ IDMap<blink::WebNotificationGetCallbacks, IDMapOwnPointer>
+ pending_get_notification_requests_;
+
+ // Tracks pending requests for displaying persistent notifications.
+ IDMap<blink::WebNotificationShowCallbacks, IDMapOwnPointer>
+ pending_show_notification_requests_;
+
// Map to store the delegate associated with a notification request Id.
- std::map<int, blink::WebNotificationDelegate*> active_notifications_;
+ std::map<int, blink::WebNotificationDelegate*> active_page_notifications_;
DISALLOW_COPY_AND_ASSIGN(NotificationManager);
};
diff --git a/chromium/content/child/notifications/pending_notifications_tracker.cc b/chromium/content/child/notifications/pending_notifications_tracker.cc
new file mode 100644
index 00000000000..69b5c8e90b7
--- /dev/null
+++ b/chromium/content/child/notifications/pending_notifications_tracker.cc
@@ -0,0 +1,116 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/child/notifications/pending_notifications_tracker.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/thread_task_runner_handle.h"
+#include "content/child/notifications/notification_image_loader.h"
+#include "content/child/notifications/notification_manager.h"
+#include "third_party/WebKit/public/platform/WebSerializedOrigin.h"
+#include "third_party/WebKit/public/platform/modules/notifications/WebNotificationData.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+namespace content {
+
+// Stores the information associated with a pending notification.
+struct PendingNotificationsTracker::PendingNotification {
+ PendingNotification(
+ const scoped_refptr<NotificationImageLoader>& image_loader,
+ const NotificationResourcesFetchedCallback& callback)
+ : image_loader(image_loader),
+ callback(callback) {}
+
+ scoped_refptr<NotificationImageLoader> image_loader;
+ NotificationResourcesFetchedCallback callback;
+};
+
+PendingNotificationsTracker::PendingNotificationsTracker(
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner)
+ : main_thread_task_runner_(main_thread_task_runner),
+ weak_factory_(this) {}
+
+PendingNotificationsTracker::~PendingNotificationsTracker() {}
+
+void PendingNotificationsTracker::FetchPageNotificationResources(
+ const blink::WebNotificationData& notification_data,
+ blink::WebNotificationDelegate* delegate,
+ const NotificationResourcesFetchedCallback& callback) {
+ delegate_to_pending_id_map_[delegate] = FetchNotificationResources(
+ notification_data,
+ callback,
+ new NotificationImageLoader(
+ base::Bind(
+ &PendingNotificationsTracker::DidFetchPageNotification,
+ weak_factory_.GetWeakPtr(), delegate),
+ base::ThreadTaskRunnerHandle::Get()));
+}
+
+void PendingNotificationsTracker::FetchPersistentNotificationResources(
+ const blink::WebNotificationData& notification_data,
+ const NotificationResourcesFetchedCallback& callback) {
+ FetchNotificationResources(
+ notification_data,
+ callback,
+ new NotificationImageLoader(
+ base::Bind(
+ &PendingNotificationsTracker::DidFetchPersistentNotification,
+ weak_factory_.GetWeakPtr()),
+ base::ThreadTaskRunnerHandle::Get()));
+}
+
+bool PendingNotificationsTracker::CancelPageNotificationFetches(
+ blink::WebNotificationDelegate* delegate) {
+ auto iter = delegate_to_pending_id_map_.find(delegate);
+ if (iter == delegate_to_pending_id_map_.end())
+ return false;
+
+ pending_notifications_.Remove(iter->second);
+ delegate_to_pending_id_map_.erase(iter);
+
+ return true;
+}
+
+void PendingNotificationsTracker::DidFetchPageNotification(
+ blink::WebNotificationDelegate* delegate,
+ int notification_id,
+ const SkBitmap& icon) {
+ PendingNotification* pending_notification =
+ pending_notifications_.Lookup(notification_id);
+ DCHECK(pending_notification);
+
+ pending_notification->callback.Run(icon);
+
+ delegate_to_pending_id_map_.erase(delegate);
+ pending_notifications_.Remove(notification_id);
+}
+
+void PendingNotificationsTracker::DidFetchPersistentNotification(
+ int notification_id, const SkBitmap& icon) {
+ PendingNotification* pending_notification =
+ pending_notifications_.Lookup(notification_id);
+ DCHECK(pending_notification);
+
+ pending_notification->callback.Run(icon);
+
+ pending_notifications_.Remove(notification_id);
+}
+
+int PendingNotificationsTracker::FetchNotificationResources(
+ const blink::WebNotificationData& notification_data,
+ const NotificationResourcesFetchedCallback& callback,
+ const scoped_refptr<NotificationImageLoader>& image_loader) {
+ int notification_id = pending_notifications_.Add(
+ new PendingNotification(image_loader, callback));
+
+ main_thread_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&NotificationImageLoader::StartOnMainThread,
+ image_loader, notification_id,
+ GURL(notification_data.icon.spec())));
+
+ return notification_id;
+}
+
+} // namespace content
diff --git a/chromium/content/child/notifications/pending_notifications_tracker.h b/chromium/content/child/notifications/pending_notifications_tracker.h
new file mode 100644
index 00000000000..2d9d3b5b317
--- /dev/null
+++ b/chromium/content/child/notifications/pending_notifications_tracker.h
@@ -0,0 +1,107 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_CHILD_NOTIFICATIONS_PENDING_NOTIFICATIONS_TRACKER_H_
+#define CONTENT_CHILD_NOTIFICATIONS_PENDING_NOTIFICATIONS_TRACKER_H_
+
+#include <map>
+
+#include "base/id_map.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "third_party/WebKit/public/platform/modules/notifications/WebNotificationManager.h"
+
+class SkBitmap;
+
+namespace base {
+class SingleThreadTaskRunner;
+}
+
+namespace blink {
+struct WebNotificationData;
+class WebNotificationDelegate;
+class WebSerializedOrigin;
+}
+
+namespace content {
+
+class NotificationImageLoader;
+class NotificationManager;
+
+// Type definition for the callback signature which is to be invoked when the
+// resources associated with a notification have been fetched.
+using NotificationResourcesFetchedCallback =
+ base::Callback<void(const SkBitmap&)>;
+
+// Tracks all aspects of all pending Web Notifications. Most notably, it's in
+// charge of ensuring that all resource fetches associated with the notification
+// are completed as expected. The data associated with the notifications is
+// stored in this class, to maintain thread integrity of their members.
+//
+// The pending notification tracker is owned by the NotificationManager, and
+// lives on the thread that manager has been associated with.
+class PendingNotificationsTracker {
+ public:
+ explicit PendingNotificationsTracker(
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner);
+ ~PendingNotificationsTracker();
+
+ // Adds a page notification to the tracker. Resource fetches for the
+ // notification will be started on asynchronously the main thread.
+ void FetchPageNotificationResources(
+ const blink::WebNotificationData& notification_data,
+ blink::WebNotificationDelegate* delegate,
+ const NotificationResourcesFetchedCallback& callback);
+
+ // Adds a persistent notification to the tracker. Resource fetches for the
+ // notification will be started asynchronously on the main thread.
+ void FetchPersistentNotificationResources(
+ const blink::WebNotificationData& notification_data,
+ const NotificationResourcesFetchedCallback& callback);
+
+ // Cancels all pending and in-fligth fetches for the page notification
+ // identified by |delegate|. Returns if the notification was cancelled.
+ bool CancelPageNotificationFetches(blink::WebNotificationDelegate* delegate);
+
+ private:
+ // To be called on the worker thread when the pending page notification
+ // identified by |notification_id| has finished fetching the icon.
+ void DidFetchPageNotification(blink::WebNotificationDelegate* delegate,
+ int notification_id,
+ const SkBitmap& icon);
+
+ // To be called on the worker thread when the pending persistent notification
+ // identified by |notification_id| has finished fetching the icon.
+ void DidFetchPersistentNotification(int notification_id,
+ const SkBitmap& icon);
+
+ // Common code for starting to fetch resources associated with any kind of
+ // notification. Will return the id of the pending notification as allocated
+ // in the |pending_notifications_| map.
+ int FetchNotificationResources(
+ const blink::WebNotificationData& notification_data,
+ const NotificationResourcesFetchedCallback& callback,
+ const scoped_refptr<NotificationImageLoader>& image_loader);
+
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
+
+ struct PendingNotification;
+
+ // List of the notifications whose resources are still being fetched.
+ IDMap<PendingNotification, IDMapOwnPointer> pending_notifications_;
+
+ // In order to be able to cancel pending page notifications by delegate, store
+ // a mapping of the delegate to the pending notification id as well.
+ std::map<blink::WebNotificationDelegate*, int> delegate_to_pending_id_map_;
+
+ base::WeakPtrFactory<PendingNotificationsTracker> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(PendingNotificationsTracker);
+};
+
+} // namespace content
+
+#endif // CONTENT_CHILD_NOTIFICATIONS_PENDING_NOTIFICATIONS_TRACKER_H_
diff --git a/chromium/content/child/npapi/npobject_util.h b/chromium/content/child/npapi/npobject_util.h
index 511a7cf84f7..97a848289c2 100644
--- a/chromium/content/child/npapi/npobject_util.h
+++ b/chromium/content/child/npapi/npobject_util.h
@@ -4,8 +4,8 @@
//
// Helper functions that are used by the NPObject proxy and stub.
-#ifndef CONTENT_NPAPI_CHILD_NPOBJECT_UTIL_H_
-#define CONTENT_NPAPI_CHILD_NPOBJECT_UTIL_H_
+#ifndef CONTENT_CHILD_NPAPI_NPOBJECT_UTIL_H_
+#define CONTENT_CHILD_NPAPI_NPOBJECT_UTIL_H_
#include "build/build_config.h"
@@ -71,4 +71,4 @@ HANDLE GetMessageBoxEvent(HWND hwnd);
} // namespace content
-#endif // CONTENT_NPAPI_CHILD_NPOBJECT_UTIL_H_
+#endif // CONTENT_CHILD_NPAPI_NPOBJECT_UTIL_H_
diff --git a/chromium/content/child/npapi/plugin_host.cc b/chromium/content/child/npapi/plugin_host.cc
index b32f8ddc185..cdda9e41578 100644
--- a/chromium/content/child/npapi/plugin_host.cc
+++ b/chromium/content/child/npapi/plugin_host.cc
@@ -29,10 +29,6 @@
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_surface.h"
-#if defined(OS_MACOSX)
-#include "base/mac/mac_util.h"
-#endif
-
using blink::WebBindings;
// Declarations for stub implementations of deprecated functions, which are no
@@ -58,8 +54,8 @@ static PluginInstance* FindInstance(NPP id) {
// OS supports shared accelerated surfaces via IOSurface. This is true on Snow
// Leopard and higher.
static bool SupportsCoreAnimationPlugins() {
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableCoreAnimationPlugins))
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableCoreAnimationPlugins))
return false;
// We also need to be running with desktop GL and not the software
// OSMesa renderer in order to share accelerated surfaces between
@@ -622,12 +618,12 @@ void NPN_InvalidateRect(NPP id, NPRect *invalidRect) {
// Before a windowless plugin can refresh part of its drawing area, it must
// first invalidate it. This function causes the NPP_HandleEvent method to
- // pass an update event or a paint message to the plug-in. After calling
- // this method, the plug-in receives a paint message asynchronously.
+ // pass an update event or a paint message to the plugin. After calling
+ // this method, the plugin receives a paint message asynchronously.
// The browser redraws invalid areas of the document and any windowless
- // plug-ins at regularly timed intervals. To force a paint message, the
- // plug-in can call NPN_ForceRedraw after calling this method.
+ // plugins at regularly timed intervals. To force a paint message, the
+ // plugin can call NPN_ForceRedraw after calling this method.
scoped_refptr<PluginInstance> plugin(FindInstance(id));
if (plugin.get() && plugin->webplugin()) {
@@ -669,7 +665,7 @@ void NPN_InvalidateRegion(NPP id, NPRegion invalidRegion) {
}
void NPN_ForceRedraw(NPP id) {
- // Forces repaint for a windowless plug-in.
+ // Forces repaint for a windowless plugin.
//
// We deliberately do not implement this; we don't want plugins forcing
// synchronous paints.
@@ -682,7 +678,7 @@ NPError NPN_GetValue(NPP id, NPNVariable variable, void* value) {
// NPNVxDisplay (unix only)
// NPNVxtAppContext (unix only)
// NPNVnetscapeWindow (win only) - Gets the native window on which the
- // plug-in drawing occurs, returns HWND
+ // plugin drawing occurs, returns HWND
// NPNVjavascriptEnabledBool: tells whether Javascript is enabled
// NPNVasdEnabledBool: tells whether SmartUpdate is enabled
// NPNVOfflineBool: tells whether offline-mode is enabled
diff --git a/chromium/content/child/npapi/plugin_instance.cc b/chromium/content/child/npapi/plugin_instance.cc
index 4555f01c187..6a10cc826dd 100644
--- a/chromium/content/child/npapi/plugin_instance.cc
+++ b/chromium/content/child/npapi/plugin_instance.cc
@@ -560,7 +560,7 @@ void PluginInstance::RequestRead(NPStream* stream, NPByteRange* range_list) {
// is called on it.
plugin_stream->set_seekable(true);
- if (CommandLine::ForCurrentProcess()->HasSwitch(
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableDirectNPAPIRequests)) {
pending_range_requests_[++next_range_request_id_] = plugin_stream;
webplugin_->InitiateHTTPRangeRequest(
diff --git a/chromium/content/child/npapi/plugin_instance.h b/chromium/content/child/npapi/plugin_instance.h
index a776a1559ee..16fe60c057c 100644
--- a/chromium/content/child/npapi/plugin_instance.h
+++ b/chromium/content/child/npapi/plugin_instance.h
@@ -18,9 +18,9 @@
#include "base/memory/ref_counted.h"
#include "third_party/npapi/bindings/npapi.h"
#include "third_party/npapi/bindings/nphostapi.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/point.h"
-#include "ui/gfx/rect.h"
#include "url/gurl.h"
namespace base {
diff --git a/chromium/content/child/npapi/plugin_lib.cc b/chromium/content/child/npapi/plugin_lib.cc
index 9df2f589bb7..1d7ebe95766 100644
--- a/chromium/content/child/npapi/plugin_lib.cc
+++ b/chromium/content/child/npapi/plugin_lib.cc
@@ -7,7 +7,6 @@
#include "base/bind.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
-#include "base/metrics/stats_counters.h"
#include "base/strings/string_util.h"
#include "content/child/npapi/plugin_host.h"
#include "content/child/npapi/plugin_instance.h"
@@ -15,9 +14,6 @@
namespace content {
-const char kPluginLibrariesLoadedCounter[] = "PluginLibrariesLoaded";
-const char kPluginInstancesActiveCounter[] = "PluginInstancesActive";
-
// A list of all the instantiated plugins.
static std::vector<scoped_refptr<PluginLib> >* g_loaded_libs;
@@ -71,7 +67,6 @@ PluginLib::PluginLib(const WebPluginInfo& info)
instance_count_(0),
skip_unload_(false),
defer_unload_(false) {
- base::StatsCounter(kPluginLibrariesLoadedCounter).Increment();
memset(static_cast<void*>(&plugin_funcs_), 0, sizeof(plugin_funcs_));
g_loaded_libs->push_back(make_scoped_refptr(this));
@@ -79,7 +74,6 @@ PluginLib::PluginLib(const WebPluginInfo& info)
}
PluginLib::~PluginLib() {
- base::StatsCounter(kPluginLibrariesLoadedCounter).Decrement();
if (saved_data_ != 0) {
// TODO - delete the savedData object here
}
@@ -151,13 +145,11 @@ void PluginLib::PreventLibraryUnload() {
PluginInstance* PluginLib::CreateInstance(const std::string& mime_type) {
PluginInstance* new_instance = new PluginInstance(this, mime_type);
instance_count_++;
- base::StatsCounter(kPluginInstancesActiveCounter).Increment();
DCHECK_NE(static_cast<PluginInstance*>(NULL), new_instance);
return new_instance;
}
void PluginLib::CloseInstance() {
- base::StatsCounter(kPluginInstancesActiveCounter).Decrement();
instance_count_--;
// If a plugin is running in its own process it will get unloaded on process
// shutdown.
diff --git a/chromium/content/child/npapi/plugin_stream_url.h b/chromium/content/child/npapi/plugin_stream_url.h
index c43f7892c72..dea2fe4d52c 100644
--- a/chromium/content/child/npapi/plugin_stream_url.h
+++ b/chromium/content/child/npapi/plugin_stream_url.h
@@ -90,4 +90,4 @@ class PluginStreamUrl : public PluginStream,
} // namespace content
-#endif // CONTENT_CHILD_NPAPI_PLUGIN_STREAM_URL_H_
+#endif // CONTENT_CHILD_NPAPI_PLUGIN_STREAM_URL_H_
diff --git a/chromium/content/child/npapi/plugin_string_stream.h b/chromium/content/child/npapi/plugin_string_stream.h
index fff88639ca6..73dac441898 100644
--- a/chromium/content/child/npapi/plugin_string_stream.h
+++ b/chromium/content/child/npapi/plugin_string_stream.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_CHILD_PLUGIN_STRING_STREAM_H_
-#define CONTENT_CHILD_PLUGIN_STRING_STREAM_H_
+#ifndef CONTENT_CHILD_NPAPI_PLUGIN_STRING_STREAM_H_
+#define CONTENT_CHILD_NPAPI_PLUGIN_STRING_STREAM_H_
#include "content/child/npapi/plugin_stream.h"
@@ -37,4 +37,4 @@ class PluginStringStream : public PluginStream {
} // namespace content
-#endif // CONTENT_CHILD_PLUGIN_STRING_STREAM_H_
+#endif // CONTENT_CHILD_NPAPI_PLUGIN_STRING_STREAM_H_
diff --git a/chromium/content/child/npapi/plugin_url_fetcher.cc b/chromium/content/child/npapi/plugin_url_fetcher.cc
index ff3e79884df..b4ef6772913 100644
--- a/chromium/content/child/npapi/plugin_url_fetcher.cc
+++ b/chromium/content/child/npapi/plugin_url_fetcher.cc
@@ -5,7 +5,7 @@
#include "content/child/npapi/plugin_url_fetcher.h"
#include "base/memory/scoped_ptr.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
#include "content/child/multipart_response_delegate.h"
#include "content/child/npapi/plugin_host.h"
#include "content/child/npapi/plugin_instance.h"
@@ -16,7 +16,6 @@
#include "content/child/request_extra_data.h"
#include "content/child/request_info.h"
#include "content/child/resource_dispatcher.h"
-#include "content/child/resource_loader_bridge.h"
#include "content/child/web_url_loader_impl.h"
#include "content/common/resource_request_body.h"
#include "content/common/service_worker/service_worker_types.h"
@@ -44,9 +43,8 @@ class MultiPartResponseClient : public blink::WebURLLoaderClient {
: byte_range_lower_bound_(0), plugin_stream_(plugin_stream) {}
// blink::WebURLLoaderClient implementation:
- virtual void didReceiveResponse(
- blink::WebURLLoader* loader,
- const blink::WebURLResponse& response) override {
+ void didReceiveResponse(blink::WebURLLoader* loader,
+ const blink::WebURLResponse& response) override {
int64 byte_range_upper_bound, instance_size;
if (!MultipartResponseDelegate::ReadContentRanges(response,
&byte_range_lower_bound_,
@@ -55,10 +53,10 @@ class MultiPartResponseClient : public blink::WebURLLoaderClient {
NOTREACHED();
}
}
- virtual void didReceiveData(blink::WebURLLoader* loader,
- const char* data,
- int data_length,
- int encoded_data_length) override {
+ void didReceiveData(blink::WebURLLoader* loader,
+ const char* data,
+ int data_length,
+ int encoded_data_length) override {
// TODO(ananta)
// We should defer further loads on multipart resources on the same lines
// as regular resources requested by plugins to prevent reentrancy.
@@ -83,7 +81,7 @@ PluginURLFetcher::PluginURLFetcher(PluginStreamUrl* plugin_stream,
const std::string& method,
const char* buf,
unsigned int len,
- const GURL& referrer,
+ const Referrer& referrer,
const std::string& range,
bool notify_redirects,
bool is_plugin_src_load,
@@ -104,7 +102,8 @@ PluginURLFetcher::PluginURLFetcher(PluginStreamUrl* plugin_stream,
resource_id_(resource_id),
copy_stream_data_(copy_stream_data),
data_offset_(0),
- pending_failure_notification_(false) {
+ pending_failure_notification_(false),
+ request_id_(-1) {
RequestInfo request_info;
request_info.method = method;
request_info.url = url;
@@ -146,25 +145,25 @@ PluginURLFetcher::PluginURLFetcher(PluginStreamUrl* plugin_stream,
request_info.headers = std::string("Range: ") + range;
}
- bridge_.reset(ChildThread::current()->resource_dispatcher()->CreateBridge(
- request_info));
- if (!body.empty()) {
- scoped_refptr<ResourceRequestBody> request_body =
- new ResourceRequestBody;
+ scoped_refptr<ResourceRequestBody> request_body = new ResourceRequestBody;
+ if (!body.empty())
request_body->AppendBytes(&body[0], body.size());
- bridge_->SetRequestBody(request_body.get());
- }
- bridge_->Start(this);
+ request_id_ = ChildThreadImpl::current()->resource_dispatcher()->StartAsync(
+ request_info, request_body.get(), this);
// TODO(jam): range requests
}
PluginURLFetcher::~PluginURLFetcher() {
+ if (request_id_ >= 0) {
+ ChildThreadImpl::current()->resource_dispatcher()->RemovePendingRequest(
+ request_id_);
+ }
}
void PluginURLFetcher::Cancel() {
- bridge_->Cancel();
+ ChildThreadImpl::current()->resource_dispatcher()->Cancel(request_id_);
// Due to races and nested event loops, PluginURLFetcher may still receive
// events from the bridge before being destroyed. Do not forward additional
@@ -181,9 +180,10 @@ void PluginURLFetcher::URLRedirectResponse(bool allow) {
return;
if (allow) {
- bridge_->SetDefersLoading(false);
+ ChildThreadImpl::current()->resource_dispatcher()->SetDefersLoading(
+ request_id_, false);
} else {
- bridge_->Cancel();
+ ChildThreadImpl::current()->resource_dispatcher()->Cancel(request_id_);
plugin_stream_->DidFail(resource_id_); // That will delete |this|.
}
}
@@ -203,7 +203,7 @@ bool PluginURLFetcher::OnReceivedRedirect(
// Currently this check is just to catch an https -> http redirect when
// loading the main plugin src URL. Longer term, we could investigate
// firing mixed diplay or scripting issues for subresource loads
- // initiated by plug-ins.
+ // initiated by plugins.
if (is_plugin_src_load_ &&
!plugin_stream_->instance()->webplugin()->CheckIfRunInsecureContent(
redirect_info.new_url)) {
@@ -226,7 +226,8 @@ bool PluginURLFetcher::OnReceivedRedirect(
}
} else {
// Pause the request while we ask the plugin what to do about the redirect.
- bridge_->SetDefersLoading(true);
+ ChildThreadImpl::current()->resource_dispatcher()->SetDefersLoading(
+ request_id_, true);
plugin_stream_->WillSendRequest(url_, redirect_info.status_code);
}
diff --git a/chromium/content/child/npapi/plugin_url_fetcher.h b/chromium/content/child/npapi/plugin_url_fetcher.h
index 57eb5a5beba..237c0b6411b 100644
--- a/chromium/content/child/npapi/plugin_url_fetcher.h
+++ b/chromium/content/child/npapi/plugin_url_fetcher.h
@@ -2,19 +2,19 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CONTENT_CHILD_NPAPI_URL_FETCHER_H_
-#define CONTENT_CHILD_NPAPI_URL_FETCHER_H_
+#ifndef CONTENT_CHILD_NPAPI_PLUGIN_URL_FETCHER_H_
+#define CONTENT_CHILD_NPAPI_PLUGIN_URL_FETCHER_H_
#include <string>
#include "base/memory/scoped_ptr.h"
#include "content/public/child/request_peer.h"
+#include "content/public/common/referrer.h"
#include "url/gurl.h"
namespace content {
class MultipartResponseDelegate;
class PluginStreamUrl;
-class ResourceLoaderBridge;
// Fetches URLS for a plugin using ResourceDispatcher.
class PluginURLFetcher : public RequestPeer {
@@ -25,7 +25,7 @@ class PluginURLFetcher : public RequestPeer {
const std::string& method,
const char* buf,
unsigned int len,
- const GURL& referrer,
+ const Referrer& referrer,
const std::string& range,
bool notify_redirects,
bool is_plugin_src_load,
@@ -43,7 +43,7 @@ class PluginURLFetcher : public RequestPeer {
void URLRedirectResponse(bool allow);
GURL first_party_for_cookies() { return first_party_for_cookies_; }
- GURL referrer() { return referrer_; }
+ Referrer referrer() { return referrer_; }
int origin_pid() { return origin_pid_; }
int render_frame_id() { return render_frame_id_; }
int render_view_id() { return render_view_id_; }
@@ -72,7 +72,7 @@ class PluginURLFetcher : public RequestPeer {
PluginStreamUrl* plugin_stream_;
GURL url_;
GURL first_party_for_cookies_;
- GURL referrer_;
+ Referrer referrer_;
bool notify_redirects_;
bool is_plugin_src_load_;
int origin_pid_;
@@ -82,14 +82,13 @@ class PluginURLFetcher : public RequestPeer {
bool copy_stream_data_;
int64 data_offset_;
bool pending_failure_notification_;
+ int request_id_;
scoped_ptr<MultipartResponseDelegate> multipart_delegate_;
- scoped_ptr<ResourceLoaderBridge> bridge_;
-
DISALLOW_COPY_AND_ASSIGN(PluginURLFetcher);
};
} // namespace content
-#endif // CONTENT_CHILD_NPAPI_URL_FETCHER_H_
+#endif // CONTENT_CHILD_NPAPI_PLUGIN_URL_FETCHER_H_
diff --git a/chromium/content/child/npapi/webplugin.h b/chromium/content/child/npapi/webplugin.h
index 5db1989ac8e..c1281f14d24 100644
--- a/chromium/content/child/npapi/webplugin.h
+++ b/chromium/content/child/npapi/webplugin.h
@@ -9,8 +9,8 @@
#include <vector>
#include "base/basictypes.h"
+#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/rect.h"
#include "ui/gl/gpu_preference.h"
// TODO(port): this typedef is obviously incorrect on non-Windows
diff --git a/chromium/content/child/npapi/webplugin_accelerated_surface_mac.h b/chromium/content/child/npapi/webplugin_accelerated_surface_mac.h
index f0e6d6f6268..d91f8f21c2c 100644
--- a/chromium/content/child/npapi/webplugin_accelerated_surface_mac.h
+++ b/chromium/content/child/npapi/webplugin_accelerated_surface_mac.h
@@ -5,8 +5,8 @@
#ifndef CONTENT_CHILD_NPAPI_WEBPLUGIN_ACCELERATED_SURFACE_MAC_H_
#define CONTENT_CHILD_NPAPI_WEBPLUGIN_ACCELERATED_SURFACE_MAC_H_
+#include "ui/gfx/geometry/size.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/size.h"
// Avoid having to include OpenGL headers here.
typedef struct _CGLContextObject* CGLContextObj;
diff --git a/chromium/content/child/npapi/webplugin_delegate.h b/chromium/content/child/npapi/webplugin_delegate.h
index eaef885a38c..8f13c8d80d2 100644
--- a/chromium/content/child/npapi/webplugin_delegate.h
+++ b/chromium/content/child/npapi/webplugin_delegate.h
@@ -28,6 +28,7 @@ class Rect;
namespace content {
+struct Referrer;
class WebPluginResourceClient;
// This is the interface that a plugin implementation needs to provide.
@@ -138,7 +139,7 @@ class WebPluginDelegate {
const std::string& method,
const char* buf,
unsigned int len,
- const GURL& referrer,
+ const Referrer& referrer,
bool notify_redirects,
bool is_plugin_src_load,
int origin_pid,
diff --git a/chromium/content/child/npapi/webplugin_delegate_impl.cc b/chromium/content/child/npapi/webplugin_delegate_impl.cc
index e53cbc382c1..9d760549acf 100644
--- a/chromium/content/child/npapi/webplugin_delegate_impl.cc
+++ b/chromium/content/child/npapi/webplugin_delegate_impl.cc
@@ -81,14 +81,14 @@ bool WebPluginDelegateImpl::Initialize(
creation_succeeded_ = instance_->Start(
url, argn.get(), argv.get(), argc, load_manually);
if (!creation_succeeded_) {
- VLOG(1) << "Couldn't start plug-in instance";
+ VLOG(1) << "Couldn't start plugin instance";
return false;
}
windowless_ = instance_->windowless();
if (!windowless_) {
if (!WindowedCreatePlugin()) {
- VLOG(1) << "Couldn't create windowed plug-in";
+ VLOG(1) << "Couldn't create windowed plugin";
return false;
}
}
@@ -311,7 +311,7 @@ void WebPluginDelegateImpl::FetchURL(unsigned long resource_id,
const std::string& method,
const char* buf,
unsigned int len,
- const GURL& referrer,
+ const Referrer& referrer,
bool notify_redirects,
bool is_plugin_src_load,
int origin_pid,
diff --git a/chromium/content/child/npapi/webplugin_delegate_impl.h b/chromium/content/child/npapi/webplugin_delegate_impl.h
index e37a651a1e4..96d4a1e2515 100644
--- a/chromium/content/child/npapi/webplugin_delegate_impl.h
+++ b/chromium/content/child/npapi/webplugin_delegate_impl.h
@@ -17,8 +17,8 @@
#include "content/child/npapi/webplugin_delegate.h"
#include "content/common/cursors/webcursor.h"
#include "third_party/npapi/bindings/npapi.h"
+#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/rect.h"
namespace base {
class FilePath;
@@ -121,7 +121,7 @@ class WebPluginDelegateImpl : public WebPluginDelegate {
const std::string& method,
const char* buf,
unsigned int len,
- const GURL& referrer,
+ const Referrer& referrer,
bool notify_redirects,
bool is_plugin_src_load,
int origin_pid,
@@ -145,7 +145,7 @@ class WebPluginDelegateImpl : public WebPluginDelegate {
void SetContentAreaHasFocus(bool has_focus);
#if defined(OS_WIN)
- // Informs the plug-in that an IME has changed its status.
+ // Informs the plugin that an IME has changed its status.
void ImeCompositionUpdated(const base::string16& text,
const std::vector<int>& clauses,
const std::vector<int>& target,
@@ -155,7 +155,7 @@ class WebPluginDelegateImpl : public WebPluginDelegate {
// IME was cancelled.
void ImeCompositionCompleted(const base::string16& text);
- // Returns the IME status retrieved from a plug-in.
+ // Returns the IME status retrieved from a plugin.
bool GetIMEStatus(int* input_type, gfx::Rect* caret_rect);
#endif
@@ -304,7 +304,7 @@ class WebPluginDelegateImpl : public WebPluginDelegate {
uint32 last_message_;
bool is_calling_wndproc;
- // An IME emulator used by a windowless plug-in to retrieve IME data through
+ // An IME emulator used by a windowless plugin to retrieve IME data through
// IMM32 functions.
scoped_ptr<WebPluginIMEWin> plugin_ime_;
#endif // defined(OS_WIN)
@@ -386,13 +386,13 @@ class WebPluginDelegateImpl : public WebPluginDelegate {
// Informs the browser about the updated accelerated drawing surface.
void UpdateAcceleratedSurface();
- // Uses a CARenderer to draw the plug-in's layer in our OpenGL surface.
+ // Uses a CARenderer to draw the plugin's layer in our OpenGL surface.
void DrawLayerInSurface();
bool use_buffer_context_;
CGContextRef buffer_context_; // Weak ref.
- CALayer* layer_; // Used for CA drawing mode. Weak, retained by plug-in.
+ CALayer* layer_; // Used for CA drawing mode. Weak, retained by plugin.
WebPluginAcceleratedSurface* surface_; // Weak ref.
CARenderer* renderer_; // Renders layer_ to surface_.
scoped_ptr<base::RepeatingTimer<WebPluginDelegateImpl> > redraw_timer_;
@@ -437,10 +437,6 @@ class WebPluginDelegateImpl : public WebPluginDelegate {
// This flag indicates whether we started tracking a user gesture message.
bool user_gesture_message_posted_;
- // Runnable Method Factory used to invoke the OnUserGestureEnd method
- // asynchronously.
- base::WeakPtrFactory<WebPluginDelegateImpl> user_gesture_msg_factory_;
-
// Handle to the mouse hook installed for certain windowed plugins like
// flash.
HHOOK mouse_hook_;
@@ -470,6 +466,12 @@ class WebPluginDelegateImpl : public WebPluginDelegate {
// True if NPP_New did not return an error.
bool creation_succeeded_;
+#if defined(OS_WIN)
+ // Runnable Method Factory used to invoke the OnUserGestureEnd method
+ // asynchronously.
+ base::WeakPtrFactory<WebPluginDelegateImpl> user_gesture_msg_factory_;
+#endif
+
DISALLOW_COPY_AND_ASSIGN(WebPluginDelegateImpl);
};
diff --git a/chromium/content/child/npapi/webplugin_delegate_impl_mac.mm b/chromium/content/child/npapi/webplugin_delegate_impl_mac.mm
index 9b1d5030fed..4dad1172653 100644
--- a/chromium/content/child/npapi/webplugin_delegate_impl_mac.mm
+++ b/chromium/content/child/npapi/webplugin_delegate_impl_mac.mm
@@ -11,9 +11,7 @@
#include <set>
#include <string>
-#include "base/mac/mac_util.h"
#include "base/memory/scoped_ptr.h"
-#include "base/metrics/stats_counters.h"
#include "base/strings/string_util.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
@@ -207,7 +205,7 @@ bool WebPluginDelegateImpl::PlatformInitialize() {
break;
case NPDrawingModelCoreAnimation:
case NPDrawingModelInvalidatingCoreAnimation: {
- // Ask the plug-in for the CALayer it created for rendering content.
+ // Ask the plugin for the CALayer it created for rendering content.
// Create a surface to host it, and request a "window" handle to identify
// the surface.
CALayer* layer = nil;
@@ -437,9 +435,6 @@ void WebPluginDelegateImpl::WindowlessPaint(gfx::NativeDrawingContext context,
return;
DCHECK(!use_buffer_context_ || buffer_context_ == context);
- base::StatsRate plugin_paint("Plugin.Paint");
- base::StatsScope<base::StatsRate> scope(plugin_paint);
-
gfx::Rect paint_rect = damage_rect;
if (use_buffer_context_) {
// Plugin invalidates trigger asynchronous paints with the original
@@ -707,7 +702,7 @@ void WebPluginDelegateImpl::DrawLayerInSurface() {
surface_->EndDrawing();
}
-// Update the size of the surface to match the current size of the plug-in.
+// Update the size of the surface to match the current size of the plugin.
void WebPluginDelegateImpl::UpdateAcceleratedSurface() {
if (!surface_ || !layer_)
return;
diff --git a/chromium/content/child/npapi/webplugin_delegate_impl_win.cc b/chromium/content/child/npapi/webplugin_delegate_impl_win.cc
index f570c7c29de..897745b86d2 100644
--- a/chromium/content/child/npapi/webplugin_delegate_impl_win.cc
+++ b/chromium/content/child/npapi/webplugin_delegate_impl_win.cc
@@ -14,7 +14,6 @@
#include "base/lazy_instance.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
-#include "base/metrics/stats_counters.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/lock.h"
@@ -188,11 +187,11 @@ std::wstring GetKeyPath(HKEY key) {
return std::wstring(info->Name, info->NameLength / sizeof(wchar_t));
}
-int GetPluginMajorVersion(const WebPluginInfo& plugin_info) {
+uint32_t GetPluginMajorVersion(const WebPluginInfo& plugin_info) {
Version plugin_version;
WebPluginInfo::CreateVersionFromString(plugin_info.version, &plugin_version);
- int major_version = 0;
+ uint32_t major_version = 0;
if (plugin_version.IsValid())
major_version = plugin_version.components()[0];
@@ -240,14 +239,14 @@ WebPluginDelegateImpl::WebPluginDelegateImpl(
handle_event_message_filter_hook_(NULL),
handle_event_pump_messages_event_(NULL),
user_gesture_message_posted_(false),
- user_gesture_msg_factory_(this),
handle_event_depth_(0),
mouse_hook_(NULL),
first_set_window_call_(true),
plugin_has_focus_(false),
has_webkit_focus_(false),
containing_view_has_focus_(true),
- creation_succeeded_(false) {
+ creation_succeeded_(false),
+ user_gesture_msg_factory_(this) {
memset(&window_, 0, sizeof(window_));
const WebPluginInfo& plugin_info = instance_->plugin_lib()->plugin_info();
@@ -267,7 +266,7 @@ WebPluginDelegateImpl::WebPluginDelegateImpl(
quirks_ |= PLUGIN_QUIRK_FAKE_WINDOW_FROM_POINT;
} else if (filename == kAcrobatReaderPlugin) {
// Check for the version number above or equal 9.
- int major_version = GetPluginMajorVersion(plugin_info);
+ uint32_t major_version = GetPluginMajorVersion(plugin_info);
if (major_version >= 9) {
quirks_ |= PLUGIN_QUIRK_DIE_AFTER_UNLOAD;
// 9.2 needs this.
@@ -301,7 +300,7 @@ WebPluginDelegateImpl::WebPluginDelegateImpl(
// VLC hangs on NPP_Destroy if we call NPP_SetWindow with a null window
// handle
quirks_ |= PLUGIN_QUIRK_DONT_SET_NULL_WINDOW_HANDLE_ON_DESTROY;
- int major_version = GetPluginMajorVersion(plugin_info);
+ uint32_t major_version = GetPluginMajorVersion(plugin_info);
if (major_version == 0) {
// VLC 0.8.6d and 0.8.6e crash if multiple instances are created.
quirks_ |= PLUGIN_QUIRK_DONT_ALLOW_MULTIPLE_INSTANCES;
@@ -501,7 +500,7 @@ bool WebPluginDelegateImpl::WindowedCreatePlugin() {
DCHECK(result == TRUE) << "SetProp failed, last error = " << GetLastError();
// Calling SetWindowLongPtrA here makes the window proc ASCII, which is
- // required by at least the Shockwave Director plug-in.
+ // required by at least the Shockwave Director plugin.
SetWindowLongPtrA(windowed_handle_,
GWLP_WNDPROC,
reinterpret_cast<LONG_PTR>(DefWindowProcA));
@@ -796,7 +795,7 @@ bool WebPluginDelegateImpl::WindowedReposition(
}
void WebPluginDelegateImpl::WindowedSetWindow() {
- if (!instance_)
+ if (!instance_.get())
return;
if (!windowed_handle_) {
@@ -823,7 +822,7 @@ void WebPluginDelegateImpl::WindowedSetWindow() {
// Reset this flag before entering the instance in case of side-effects.
windowed_did_set_window_ = true;
- NPError err = instance()->NPP_SetWindow(&window_);
+ instance()->NPP_SetWindow(&window_);
if (quirks_ & PLUGIN_QUIRK_SETWINDOW_TWICE)
instance()->NPP_SetWindow(&window_);
@@ -873,7 +872,7 @@ LRESULT CALLBACK WebPluginDelegateImpl::WrapperWindowProc(
// window messages when its first parameter is a handle representing the
// DefWindowProc() function. To avoid this problem, this code creates a
// wrapper function which just encapsulates the DefWindowProc() function
- // and set it as the window procedure of a windowed plug-in.
+ // and set it as the window procedure of a windowed plugin.
return DefWindowProc(hWnd, message, wParam, lParam);
}
@@ -1053,8 +1052,6 @@ void WebPluginDelegateImpl::WindowlessPaint(HDC hdc,
paint_event.event = WM_PAINT;
paint_event.wParam = PtrToUlong(hdc);
paint_event.lParam = reinterpret_cast<uintptr_t>(&damage_rect_win);
- base::StatsRate plugin_paint("Plugin.Paint");
- base::StatsScope<base::StatsRate> scope(plugin_paint);
instance()->NPP_HandleEvent(&paint_event);
window_.window = old_dc;
}
@@ -1210,8 +1207,8 @@ bool WebPluginDelegateImpl::PlatformHandleInputEvent(
return false;
}
- // Allow this plug-in to access this IME emulator through IMM32 API while the
- // plug-in is processing this event.
+ // Allow this plugin to access this IME emulator through IMM32 API while the
+ // plugin is processing this event.
if (GetQuirks() & PLUGIN_QUIRK_EMULATE_IME) {
if (!plugin_ime_)
plugin_ime_.reset(new WebPluginIMEWin);
diff --git a/chromium/content/child/npapi/webplugin_ime_win.cc b/chromium/content/child/npapi/webplugin_ime_win.cc
index 9b03ab765ea..7ff6a5d7515 100644
--- a/chromium/content/child/npapi/webplugin_ime_win.cc
+++ b/chromium/content/child/npapi/webplugin_ime_win.cc
@@ -19,7 +19,7 @@
namespace content {
-// A critical section that prevents two or more plug-ins from accessing a
+// A critical section that prevents two or more plugins from accessing a
// WebPluginIMEWin instance through our patch function.
base::LazyInstance<base::Lock>::Leaky
g_webplugin_ime_lock = LAZY_INSTANCE_INITIALIZER;
@@ -65,10 +65,10 @@ void WebPluginIMEWin::CompositionUpdated(const base::string16& text,
events_.push_back(np_event);
// Converts this event to the IMM32 data so we do not have to convert it every
- // time when a plug-in call an IMM32 function.
+ // time when a plugin call an IMM32 function.
composition_text_ = text;
- // Create the composition clauses returned when a plug-in calls
+ // Create the composition clauses returned when a plugin calls
// ImmGetCompositionString() with GCS_COMPCLAUSE.
composition_clauses_.clear();
for (size_t i = 0; i < clauses.size(); ++i)
@@ -107,8 +107,8 @@ void WebPluginIMEWin::CompositionCompleted(const base::string16& text) {
np_event.lParam = 0;
events_.push_back(np_event);
- // If the target plug-in does not seem to support IME messages, we send
- // each character in IME text with a WM_CHAR message so the plug-in can
+ // If the target plugin does not seem to support IME messages, we send
+ // each character in IME text with a WM_CHAR message so the plugin can
// insert the IME text.
if (!support_ime_messages_) {
np_event.event = WM_CHAR;
@@ -133,7 +133,7 @@ void WebPluginIMEWin::CompositionCompleted(const base::string16& text) {
bool WebPluginIMEWin::SendEvents(PluginInstance* instance) {
// We allow the patch functions to access this WebPluginIMEWin instance only
- // while we send IME events to the plug-in.
+ // while we send IME events to the plugin.
ScopedLock lock(this);
bool ret = true;
@@ -266,8 +266,8 @@ HIMC WINAPI WebPluginIMEWin::ImmGetContext(HWND window) {
// Call the original ImmGetContext() function if the given window is the one
// created in WebPluginDelegateImpl::WindowedCreatePlugin(). (We attached IME
// context only with the windows created in this function.) On the other hand,
- // some windowless plug-ins (such as Flash) call this function with a dummy
- // window handle. We return our dummy IME context for these plug-ins so they
+ // some windowless plugins (such as Flash) call this function with a dummy
+ // window handle. We return our dummy IME context for these plugins so they
// can use our IME emulator.
if (IsWindow(window)) {
wchar_t name[128];
diff --git a/chromium/content/child/npapi/webplugin_ime_win.h b/chromium/content/child/npapi/webplugin_ime_win.h
index 3a4083c4c8e..b24e75a5389 100644
--- a/chromium/content/child/npapi/webplugin_ime_win.h
+++ b/chromium/content/child/npapi/webplugin_ime_win.h
@@ -11,20 +11,20 @@
#include "base/basictypes.h"
#include "base/strings/string16.h"
#include "third_party/npapi/bindings/npapi.h"
-#include "ui/gfx/rect.h"
+#include "ui/gfx/geometry/rect.h"
namespace content {
class PluginInstance;
-// A class that emulates an IME for windowless plug-ins. A windowless plug-in
+// A class that emulates an IME for windowless plugins. A windowless plugin
// does not have a window. Therefore, we cannot attach an IME to a windowless
-// plug-in. To allow such windowless plug-ins to use IMEs without any changes to
+// plugin. To allow such windowless plugins to use IMEs without any changes to
// them, this class receives the IME data from a browser and patches IMM32
-// functions to return the IME data when a windowless plug-in calls IMM32
+// functions to return the IME data when a windowless plugin calls IMM32
// functions. I would not Flash retrieves pointers to IMM32 functions with
// GetProcAddress(), this class also needs a hook to GetProcAddress() to
-// dispatch IMM32 function calls from a plug-in to this class as listed in the
+// dispatch IMM32 function calls from a plugin to this class as listed in the
// following snippet.
//
// FARPROC WINAPI GetProcAddressPatch(HMODULE module, LPCSTR name) {
@@ -39,13 +39,13 @@ class PluginInstance;
// GetPluginPath().value().c_str(), "kernel32.dll", "GetProcAddress",
// GetProcAddressPatch);
//
-// After we successfuly dispatch IMM32 calls from a plug-in to this class, we
-// need to update its IME data so the class can return it to the plug-in through
+// After we successfuly dispatch IMM32 calls from a plugin to this class, we
+// need to update its IME data so the class can return it to the plugin through
// its IMM32 calls. To update the IME data, we call CompositionUpdated() or
// CompositionCompleted() BEFORE sending an IMM32 Window message to the plugin
-// with a SendEvents() call as listed in the following snippet. (Plug-ins call
+// with a SendEvents() call as listed in the following snippet. (Plugins call
// IMM32 functions when it receives IMM32 window messages. We need to update the
-// IME data of this class before sending IMM32 messages so the plug-ins can get
+// IME data of this class before sending IMM32 messages so the plugins can get
// the latest data.)
//
// WebPluginIMEWin ime;
@@ -63,12 +63,12 @@ class PluginInstance;
// ime.SendEvents(instance());
//
// This class also provides GetStatus() so we can retrieve the IME status
-// changed by a plug-in with IMM32 functions. This function is mainly used for
+// changed by a plugin with IMM32 functions. This function is mainly used for
// retrieving the position of a caret.
//
class WebPluginIMEWin {
public:
- // A simple class that allows a plug-in to access a WebPluginIMEWin instance
+ // A simple class that allows a plugin to access a WebPluginIMEWin instance
// only in a scope.
class ScopedLock {
public:
@@ -89,17 +89,17 @@ class WebPluginIMEWin {
~WebPluginIMEWin();
// Sends raw IME events sent from a browser to this IME emulator and updates
- // the list of Windows events to be sent to a plug-in. A raw IME event is
+ // the list of Windows events to be sent to a plugin. A raw IME event is
// mapped to two or more Windows events and it is not so trivial to send these
- // Windows events to a plug-in. This function inserts Windows events in the
- // order expected by a plug-in.
+ // Windows events to a plugin. This function inserts Windows events in the
+ // order expected by a plugin.
void CompositionUpdated(const base::string16& text,
std::vector<int> clauses,
std::vector<int> target,
int cursor_position);
void CompositionCompleted(const base::string16& text);
- // Send all the events added in Update() to a plug-in.
+ // Send all the events added in Update() to a plugin.
bool SendEvents(PluginInstance* instance);
// Retrieves the status of this IME emulator.
@@ -114,7 +114,7 @@ class WebPluginIMEWin {
// Allow (or disallow) the patch functions to use this WebPluginIMEWin
// instance through our patch functions. Our patch functions need a static
// member variable |instance_| to access a WebPluginIMEWIn instance. We lock
- // this static variable to prevent two or more plug-ins from accessing a
+ // this static variable to prevent two or more plugins from accessing a
// WebPluginIMEWin instance.
void Lock();
void Unlock();
@@ -136,7 +136,7 @@ class WebPluginIMEWin {
CANDIDATEFORM* candidate);
static BOOL WINAPI ImmSetOpenStatus(HIMC context, BOOL open);
- // a list of NPEvents to be sent to a plug-in.
+ // a list of NPEvents to be sent to a plugin.
std::vector<NPEvent> events_;
// The return value for GCS_COMPSTR.
@@ -164,12 +164,12 @@ class WebPluginIMEWin {
// WM_IME_STARTCOMPOSITION message when we start composing IME text.
bool composing_text_;
- // Whether a plug-in supports IME messages. When a plug-in cannot handle
+ // Whether a plugin supports IME messages. When a plugin cannot handle
// IME messages, we need to send the IME text with WM_CHAR messages as Windows
// does.
bool support_ime_messages_;
- // The IME status received from a plug-in.
+ // The IME status received from a plugin.
bool status_updated_;
int input_type_;
gfx::Rect caret_rect_;
diff --git a/chromium/content/child/permissions/OWNERS b/chromium/content/child/permissions/OWNERS
new file mode 100644
index 00000000000..2d282460822
--- /dev/null
+++ b/chromium/content/child/permissions/OWNERS
@@ -0,0 +1 @@
+mlamouri@chromium.org
diff --git a/chromium/content/child/permissions/permission_dispatcher.cc b/chromium/content/child/permissions/permission_dispatcher.cc
new file mode 100644
index 00000000000..2b0278fb954
--- /dev/null
+++ b/chromium/content/child/permissions/permission_dispatcher.cc
@@ -0,0 +1,284 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/child/permissions/permission_dispatcher.h"
+
+#include "base/callback.h"
+#include "content/child/worker_task_runner.h"
+#include "content/public/common/service_registry.h"
+#include "third_party/WebKit/public/platform/WebURL.h"
+#include "third_party/WebKit/public/platform/modules/permissions/WebPermissionObserver.h"
+
+using blink::WebPermissionObserver;
+
+namespace content {
+
+namespace {
+
+PermissionName GetPermissionName(blink::WebPermissionType type) {
+ switch (type) {
+ case blink::WebPermissionTypeGeolocation:
+ return PERMISSION_NAME_GEOLOCATION;
+ case blink::WebPermissionTypeNotifications:
+ return PERMISSION_NAME_NOTIFICATIONS;
+ case blink::WebPermissionTypePushNotifications:
+ return PERMISSION_NAME_PUSH_NOTIFICATIONS;
+ case blink::WebPermissionTypeMidiSysEx:
+ return PERMISSION_NAME_MIDI_SYSEX;
+ default:
+ // The default statement is only there to prevent compilation failures if
+ // WebPermissionType enum gets extended.
+ NOTREACHED();
+ return PERMISSION_NAME_GEOLOCATION;
+ }
+}
+
+PermissionStatus GetPermissionStatus(blink::WebPermissionStatus status) {
+ switch (status) {
+ case blink::WebPermissionStatusGranted:
+ return PERMISSION_STATUS_GRANTED;
+ case blink::WebPermissionStatusDenied:
+ return PERMISSION_STATUS_DENIED;
+ case blink::WebPermissionStatusPrompt:
+ return PERMISSION_STATUS_ASK;
+ }
+
+ NOTREACHED();
+ return PERMISSION_STATUS_DENIED;
+}
+
+blink::WebPermissionStatus GetWebPermissionStatus(PermissionStatus status) {
+ switch (status) {
+ case PERMISSION_STATUS_GRANTED:
+ return blink::WebPermissionStatusGranted;
+ case PERMISSION_STATUS_DENIED:
+ return blink::WebPermissionStatusDenied;
+ case PERMISSION_STATUS_ASK:
+ return blink::WebPermissionStatusPrompt;
+ }
+
+ NOTREACHED();
+ return blink::WebPermissionStatusDenied;
+}
+
+const int kNoWorkerThread = 0;
+
+} // anonymous namespace
+
+// static
+bool PermissionDispatcher::IsObservable(blink::WebPermissionType type) {
+ return type == blink::WebPermissionTypeGeolocation ||
+ type == blink::WebPermissionTypeNotifications ||
+ type == blink::WebPermissionTypePushNotifications ||
+ type == blink::WebPermissionTypeMidiSysEx;
+}
+
+PermissionDispatcher::CallbackInformation::CallbackInformation(
+ blink::WebPermissionQueryCallback* callback,
+ int worker_thread_id)
+ : callback_(callback),
+ worker_thread_id_(worker_thread_id) {
+}
+
+blink::WebPermissionQueryCallback*
+PermissionDispatcher::CallbackInformation::callback() const {
+ return callback_.get();
+}
+
+int PermissionDispatcher::CallbackInformation::worker_thread_id() const {
+ return worker_thread_id_;
+}
+
+blink::WebPermissionQueryCallback*
+PermissionDispatcher::CallbackInformation::ReleaseCallback() {
+ return callback_.release();
+}
+
+PermissionDispatcher::CallbackInformation::~CallbackInformation() {
+}
+
+PermissionDispatcher::PermissionDispatcher(ServiceRegistry* service_registry)
+ : service_registry_(service_registry) {
+}
+
+PermissionDispatcher::~PermissionDispatcher() {
+}
+
+void PermissionDispatcher::queryPermission(
+ blink::WebPermissionType type,
+ const blink::WebURL& origin,
+ blink::WebPermissionQueryCallback* callback) {
+ QueryPermissionInternal(
+ type, origin.string().utf8(), callback, kNoWorkerThread);
+}
+
+void PermissionDispatcher::startListening(
+ blink::WebPermissionType type,
+ const blink::WebURL& origin,
+ WebPermissionObserver* observer) {
+ if (!IsObservable(type))
+ return;
+
+ RegisterObserver(observer);
+
+ GetNextPermissionChange(type,
+ origin.string().utf8(),
+ observer,
+ // We initialize with an arbitrary value because the
+ // mojo service wants a value. Worst case, the
+ // observer will get notified about a non-change which
+ // should be a no-op. After the first notification,
+ // GetNextPermissionChange will be called with the
+ // latest known value.
+ PERMISSION_STATUS_ASK);
+}
+
+void PermissionDispatcher::stopListening(WebPermissionObserver* observer) {
+ UnregisterObserver(observer);
+}
+
+void PermissionDispatcher::QueryPermissionForWorker(
+ blink::WebPermissionType type,
+ const std::string& origin,
+ blink::WebPermissionQueryCallback* callback,
+ int worker_thread_id) {
+ QueryPermissionInternal(type, origin, callback, worker_thread_id);
+}
+
+void PermissionDispatcher::StartListeningForWorker(
+ blink::WebPermissionType type,
+ const std::string& origin,
+ int worker_thread_id,
+ const base::Callback<void(blink::WebPermissionStatus)>& callback) {
+ GetPermissionServicePtr()->GetNextPermissionChange(
+ GetPermissionName(type),
+ origin,
+ // We initialize with an arbitrary value because the mojo service wants a
+ // value. Worst case, the observer will get notified about a non-change
+ // which should be a no-op. After the first notification,
+ // GetNextPermissionChange will be called with the latest known value.
+ PERMISSION_STATUS_ASK,
+ base::Bind(&PermissionDispatcher::OnPermissionChangedForWorker,
+ base::Unretained(this),
+ worker_thread_id,
+ callback));
+}
+
+void PermissionDispatcher::GetNextPermissionChangeForWorker(
+ blink::WebPermissionType type,
+ const std::string& origin,
+ blink::WebPermissionStatus status,
+ int worker_thread_id,
+ const base::Callback<void(blink::WebPermissionStatus)>& callback) {
+ GetPermissionServicePtr()->GetNextPermissionChange(
+ GetPermissionName(type),
+ origin,
+ GetPermissionStatus(status),
+ base::Bind(&PermissionDispatcher::OnPermissionChangedForWorker,
+ base::Unretained(this),
+ worker_thread_id,
+ callback));
+}
+
+// static
+void PermissionDispatcher::RunCallbackOnWorkerThread(
+ blink::WebPermissionQueryCallback* callback,
+ scoped_ptr<blink::WebPermissionStatus> status) {
+ callback->onSuccess(status.release());
+ delete callback;
+}
+
+PermissionServicePtr& PermissionDispatcher::GetPermissionServicePtr() {
+ if (!permission_service_.get())
+ service_registry_->ConnectToRemoteService(&permission_service_);
+ return permission_service_;
+}
+
+void PermissionDispatcher::QueryPermissionInternal(
+ blink::WebPermissionType type,
+ const std::string& origin,
+ blink::WebPermissionQueryCallback* callback,
+ int worker_thread_id) {
+ // We need to save the |callback| in an IDMap so if |this| gets deleted, the
+ // callback will not leak. In the case of |this| gets deleted, the
+ // |permission_service_| pipe will be destroyed too so OnQueryPermission will
+ // not be called.
+ int request_id = pending_callbacks_.Add(
+ new CallbackInformation(callback, worker_thread_id));
+ GetPermissionServicePtr()->HasPermission(
+ GetPermissionName(type),
+ origin,
+ base::Bind(&PermissionDispatcher::OnQueryPermission,
+ base::Unretained(this),
+ request_id));
+}
+
+void PermissionDispatcher::OnQueryPermission(int request_id,
+ PermissionStatus result) {
+ CallbackInformation* callback_information =
+ pending_callbacks_.Lookup(request_id);
+ DCHECK(callback_information && callback_information->callback());
+ scoped_ptr<blink::WebPermissionStatus> status(
+ new blink::WebPermissionStatus(GetWebPermissionStatus(result)));
+
+ if (callback_information->worker_thread_id() != kNoWorkerThread) {
+ blink::WebPermissionQueryCallback* callback =
+ callback_information->ReleaseCallback();
+ int worker_thread_id = callback_information->worker_thread_id();
+ pending_callbacks_.Remove(request_id);
+
+ // If the worker is no longer running, ::PostTask() will return false and
+ // gracefully fail, destroying the callback too.
+ WorkerTaskRunner::Instance()->PostTask(
+ worker_thread_id,
+ base::Bind(&PermissionDispatcher::RunCallbackOnWorkerThread,
+ base::Unretained(callback),
+ base::Passed(&status)));
+ return;
+ }
+
+ callback_information->callback()->onSuccess(status.release());
+ pending_callbacks_.Remove(request_id);
+}
+
+void PermissionDispatcher::OnPermissionChanged(
+ blink::WebPermissionType type,
+ const std::string& origin,
+ WebPermissionObserver* observer,
+ PermissionStatus status) {
+ if (!IsObserverRegistered(observer))
+ return;
+
+ observer->permissionChanged(type, GetWebPermissionStatus(status));
+
+ GetNextPermissionChange(type, origin, observer, status);
+}
+
+void PermissionDispatcher::OnPermissionChangedForWorker(
+ int worker_thread_id,
+ const base::Callback<void(blink::WebPermissionStatus)>& callback,
+ PermissionStatus status) {
+ DCHECK(worker_thread_id != kNoWorkerThread);
+
+ WorkerTaskRunner::Instance()->PostTask(
+ worker_thread_id, base::Bind(callback, GetWebPermissionStatus(status)));
+}
+
+void PermissionDispatcher::GetNextPermissionChange(
+ blink::WebPermissionType type,
+ const std::string& origin,
+ WebPermissionObserver* observer,
+ PermissionStatus current_status) {
+ GetPermissionServicePtr()->GetNextPermissionChange(
+ GetPermissionName(type),
+ origin,
+ current_status,
+ base::Bind(&PermissionDispatcher::OnPermissionChanged,
+ base::Unretained(this),
+ type,
+ origin,
+ base::Unretained(observer)));
+}
+
+} // namespace content
diff --git a/chromium/content/child/permissions/permission_dispatcher.h b/chromium/content/child/permissions/permission_dispatcher.h
new file mode 100644
index 00000000000..17410e6b821
--- /dev/null
+++ b/chromium/content/child/permissions/permission_dispatcher.h
@@ -0,0 +1,125 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_CHILD_PERMISSIONS_PERMISSION_DISPATCHER_H_
+#define CONTENT_CHILD_PERMISSIONS_PERMISSION_DISPATCHER_H_
+
+#include <string>
+
+#include "base/callback_forward.h"
+#include "base/id_map.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/child/permissions/permission_observers_registry.h"
+#include "content/common/permission_service.mojom.h"
+#include "third_party/WebKit/public/platform/modules/permissions/WebPermissionClient.h"
+
+namespace content {
+
+class ServiceRegistry;
+
+// The PermissionDispatcher is a layer between Blink and the Mojo
+// PermissionService. It implements blink::WebPermissionClient. It is being used
+// from workers and frames independently. When called outside of the main
+// thread, QueryPermissionForWorker is meant to be called. It will handle the
+// thread jumping.
+class PermissionDispatcher : public blink::WebPermissionClient,
+ public PermissionObserversRegistry {
+ public:
+ // Returns whether the given WebPermissionType is observable. Some types have
+ // static values that never changes.
+ static bool IsObservable(blink::WebPermissionType type);
+
+ // The caller must guarantee that |service_registry| will have a lifetime
+ // larger than this instance of PermissionDispatcher.
+ explicit PermissionDispatcher(ServiceRegistry* service_registry);
+ virtual ~PermissionDispatcher();
+
+ // blink::WebPermissionClient implementation.
+ virtual void queryPermission(blink::WebPermissionType type,
+ const blink::WebURL& origin,
+ blink::WebPermissionQueryCallback* callback);
+ virtual void startListening(blink::WebPermissionType type,
+ const blink::WebURL& origin,
+ blink::WebPermissionObserver* observer);
+ virtual void stopListening(blink::WebPermissionObserver* observer);
+
+ // The following methods must be called by workers on the main thread.
+ void QueryPermissionForWorker(blink::WebPermissionType type,
+ const std::string& origin,
+ blink::WebPermissionQueryCallback* callback,
+ int worker_thread_id);
+ void StartListeningForWorker(
+ blink::WebPermissionType type,
+ const std::string& origin,
+ int worker_thread_id,
+ const base::Callback<void(blink::WebPermissionStatus)>& callback);
+ void GetNextPermissionChangeForWorker(
+ blink::WebPermissionType type,
+ const std::string& origin,
+ blink::WebPermissionStatus status,
+ int worker_thread_id,
+ const base::Callback<void(blink::WebPermissionStatus)>& callback);
+
+ private:
+ // Runs the given |callback| with |status| as a parameter. It has to be run
+ // on a worker thread.
+ static void RunCallbackOnWorkerThread(
+ blink::WebPermissionQueryCallback* callback,
+ scoped_ptr<blink::WebPermissionStatus> status);
+
+ // Helper method that returns an initialized PermissionServicePtr.
+ PermissionServicePtr& GetPermissionServicePtr();
+
+ void QueryPermissionInternal(blink::WebPermissionType type,
+ const std::string& origin,
+ blink::WebPermissionQueryCallback* callback,
+ int worker_thread_id);
+
+ void OnQueryPermission(int request_id, PermissionStatus status);
+ void OnPermissionChanged(blink::WebPermissionType type,
+ const std::string& origin,
+ blink::WebPermissionObserver* observer,
+ PermissionStatus status);
+ void OnPermissionChangedForWorker(
+ int worker_thread_id,
+ const base::Callback<void(blink::WebPermissionStatus)>& callback,
+ PermissionStatus status);
+
+ void GetNextPermissionChange(blink::WebPermissionType type,
+ const std::string& origin,
+ blink::WebPermissionObserver* observer,
+ PermissionStatus current_status);
+
+ // Saves some basic information about the callback in order to be able to run
+ // it in the right thread.
+ class CallbackInformation {
+ public:
+ CallbackInformation(blink::WebPermissionQueryCallback* callback,
+ int worker_thread_id);
+ ~CallbackInformation();
+
+ blink::WebPermissionQueryCallback* callback() const;
+ int worker_thread_id() const;
+
+ blink::WebPermissionQueryCallback* ReleaseCallback();
+
+ private:
+ scoped_ptr<blink::WebPermissionQueryCallback> callback_;
+ int worker_thread_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(CallbackInformation);
+ };
+ using CallbackMap = IDMap<CallbackInformation, IDMapOwnPointer>;
+ CallbackMap pending_callbacks_;
+
+ ServiceRegistry* service_registry_;
+ PermissionServicePtr permission_service_;
+
+ DISALLOW_COPY_AND_ASSIGN(PermissionDispatcher);
+};
+
+} // namespace content
+
+#endif // CONTENT_CHILD_PERMISSIONS_PERMISSION_DISPATCHER_H_
diff --git a/chromium/content/child/permissions/permission_dispatcher_thread_proxy.cc b/chromium/content/child/permissions/permission_dispatcher_thread_proxy.cc
new file mode 100644
index 00000000000..0ecdfa48a8d
--- /dev/null
+++ b/chromium/content/child/permissions/permission_dispatcher_thread_proxy.cc
@@ -0,0 +1,126 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/child/permissions/permission_dispatcher_thread_proxy.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/lazy_instance.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread_local.h"
+#include "content/child/permissions/permission_dispatcher.h"
+#include "content/child/worker_task_runner.h"
+#include "third_party/WebKit/public/platform/WebURL.h"
+#include "third_party/WebKit/public/platform/modules/permissions/WebPermissionObserver.h"
+
+using base::LazyInstance;
+using base::ThreadLocalPointer;
+
+namespace content {
+
+namespace {
+
+LazyInstance<ThreadLocalPointer<PermissionDispatcherThreadProxy>>::Leaky
+ g_permission_dispatcher_tls = LAZY_INSTANCE_INITIALIZER;
+
+} // anonymous namespace
+
+PermissionDispatcherThreadProxy*
+PermissionDispatcherThreadProxy::GetThreadInstance(
+ base::SingleThreadTaskRunner* main_thread_task_runner,
+ PermissionDispatcher* permission_dispatcher) {
+ if (g_permission_dispatcher_tls.Pointer()->Get())
+ return g_permission_dispatcher_tls.Pointer()->Get();
+
+ PermissionDispatcherThreadProxy* instance =
+ new PermissionDispatcherThreadProxy(main_thread_task_runner,
+ permission_dispatcher);
+ DCHECK(WorkerTaskRunner::Instance()->CurrentWorkerId());
+ WorkerTaskRunner::Instance()->AddStopObserver(instance);
+ return instance;
+}
+
+PermissionDispatcherThreadProxy::PermissionDispatcherThreadProxy(
+ base::SingleThreadTaskRunner* main_thread_task_runner,
+ PermissionDispatcher* permission_dispatcher)
+ : main_thread_task_runner_(main_thread_task_runner),
+ permission_dispatcher_(permission_dispatcher) {
+ g_permission_dispatcher_tls.Pointer()->Set(this);
+}
+
+PermissionDispatcherThreadProxy::~PermissionDispatcherThreadProxy() {
+ g_permission_dispatcher_tls.Pointer()->Set(nullptr);
+}
+
+void PermissionDispatcherThreadProxy::queryPermission(
+ blink::WebPermissionType type,
+ const blink::WebURL& origin,
+ blink::WebPermissionQueryCallback* callback) {
+ main_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&PermissionDispatcher::QueryPermissionForWorker,
+ base::Unretained(permission_dispatcher_),
+ type,
+ origin.string().utf8(),
+ base::Unretained(callback),
+ WorkerTaskRunner::Instance()->CurrentWorkerId()));
+}
+
+void PermissionDispatcherThreadProxy::startListening(
+ blink::WebPermissionType type,
+ const blink::WebURL& origin,
+ blink::WebPermissionObserver* observer) {
+ if (!PermissionDispatcher::IsObservable(type))
+ return;
+
+ RegisterObserver(observer);
+
+ main_thread_task_runner_->PostTask(FROM_HERE,
+ base::Bind(&PermissionDispatcher::StartListeningForWorker,
+ base::Unretained(permission_dispatcher_),
+ type,
+ origin.string().utf8(),
+ WorkerTaskRunner::Instance()->CurrentWorkerId(),
+ base::Bind(&PermissionDispatcherThreadProxy::OnPermissionChanged,
+ base::Unretained(this),
+ type,
+ origin.string().utf8(),
+ base::Unretained(observer))));
+}
+
+void PermissionDispatcherThreadProxy::stopListening(
+ blink::WebPermissionObserver* observer) {
+ UnregisterObserver(observer);
+}
+
+void PermissionDispatcherThreadProxy::OnPermissionChanged(
+ blink::WebPermissionType type,
+ const std::string& origin,
+ blink::WebPermissionObserver* observer,
+ blink::WebPermissionStatus status) {
+ if (!IsObserverRegistered(observer))
+ return;
+
+ observer->permissionChanged(type, status);
+
+ main_thread_task_runner_->PostTask(FROM_HERE,
+ base::Bind(&PermissionDispatcher::GetNextPermissionChangeForWorker,
+ base::Unretained(permission_dispatcher_),
+ type,
+ origin,
+ status,
+ WorkerTaskRunner::Instance()->CurrentWorkerId(),
+ base::Bind(&PermissionDispatcherThreadProxy::OnPermissionChanged,
+ base::Unretained(this),
+ type,
+ origin,
+ base::Unretained(observer))));
+}
+
+void PermissionDispatcherThreadProxy::OnWorkerRunLoopStopped() {
+ delete this;
+}
+
+} // namespace content
diff --git a/chromium/content/child/permissions/permission_dispatcher_thread_proxy.h b/chromium/content/child/permissions/permission_dispatcher_thread_proxy.h
new file mode 100644
index 00000000000..65d07eb514b
--- /dev/null
+++ b/chromium/content/child/permissions/permission_dispatcher_thread_proxy.h
@@ -0,0 +1,68 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_CHILD_PERMISSIONS_PERMISSION_DISPATCHER_THREAD_PROXY_H_
+#define CONTENT_CHILD_PERMISSIONS_PERMISSION_DISPATCHER_THREAD_PROXY_H_
+
+#include "base/id_map.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "content/child/permissions/permission_observers_registry.h"
+#include "content/child/worker_task_runner.h"
+#include "third_party/WebKit/public/platform/modules/permissions/WebPermissionClient.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+}
+
+namespace content {
+
+class PermissionDispatcher;
+
+// PermissionDispatcherThreadProxy is a a proxy to the PermissionDispatcher for
+// callers running on a different thread than the main thread. There is one
+// instance of that class per thread.
+class PermissionDispatcherThreadProxy :
+ public blink::WebPermissionClient,
+ public PermissionObserversRegistry,
+ public WorkerTaskRunner::Observer {
+ public:
+ static PermissionDispatcherThreadProxy* GetThreadInstance(
+ base::SingleThreadTaskRunner* main_thread_task_runner,
+ PermissionDispatcher* permissions_dispatcher);
+
+ // blink::WebPermissionClient implementation.
+ virtual void queryPermission(blink::WebPermissionType type,
+ const blink::WebURL& origin,
+ blink::WebPermissionQueryCallback* callback);
+ virtual void startListening(blink::WebPermissionType type,
+ const blink::WebURL& origin,
+ blink::WebPermissionObserver* observer);
+ virtual void stopListening(blink::WebPermissionObserver* observer);
+
+ // WorkerTaskRunner::Observer implementation.
+ void OnWorkerRunLoopStopped() override;
+
+ private:
+ PermissionDispatcherThreadProxy(
+ base::SingleThreadTaskRunner* main_thread_task_runner,
+ PermissionDispatcher* permissions_dispatcher);
+
+ // Callback when an observed permission changes.
+ void OnPermissionChanged(blink::WebPermissionType type,
+ const std::string& origin,
+ blink::WebPermissionObserver* observer,
+ blink::WebPermissionStatus status);
+
+ virtual ~PermissionDispatcherThreadProxy();
+
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
+ PermissionDispatcher* permission_dispatcher_;
+
+ DISALLOW_COPY_AND_ASSIGN(PermissionDispatcherThreadProxy);
+};
+
+} // namespace content
+
+#endif // CONTENT_CHILD_PERMISSIONS_PERMISSION_DISPATCHER_THREAD_PROXY_H_
diff --git a/chromium/content/child/permissions/permission_observers_registry.cc b/chromium/content/child/permissions/permission_observers_registry.cc
new file mode 100644
index 00000000000..f8a2f1b6d61
--- /dev/null
+++ b/chromium/content/child/permissions/permission_observers_registry.cc
@@ -0,0 +1,32 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/child/permissions/permission_observers_registry.h"
+
+#include "third_party/WebKit/public/platform/modules/permissions/WebPermissionObserver.h"
+
+namespace content {
+
+PermissionObserversRegistry::PermissionObserversRegistry() {
+}
+
+PermissionObserversRegistry::~PermissionObserversRegistry() {
+}
+
+void PermissionObserversRegistry::RegisterObserver(
+ blink::WebPermissionObserver* observer) {
+ observers_.insert(observer);
+}
+
+void PermissionObserversRegistry::UnregisterObserver(
+ blink::WebPermissionObserver* observer) {
+ observers_.erase(observer);
+}
+
+bool PermissionObserversRegistry::IsObserverRegistered(
+ blink::WebPermissionObserver* observer) const {
+ return observers_.find(observer) != observers_.end();
+}
+
+} // namespace content
diff --git a/chromium/content/child/permissions/permission_observers_registry.h b/chromium/content/child/permissions/permission_observers_registry.h
new file mode 100644
index 00000000000..5565bf88009
--- /dev/null
+++ b/chromium/content/child/permissions/permission_observers_registry.h
@@ -0,0 +1,35 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_CHILD_PERMISSIONS_PERMISSION_OBSERVERS_REGISTRY_H_
+#define CONTENT_CHILD_PERMISSIONS_PERMISSION_OBSERVERS_REGISTRY_H_
+
+#include <set>
+
+namespace blink {
+class WebPermissionObserver;
+}
+
+namespace content {
+
+// PermissionObserversRegistry keeps a list of WebPermissionObserver with basic
+// methods to add/removed/check. It is being used by PermissionDispatcher and
+// PermissionDispatcherThreadProxy.
+// This is not thread-safe.
+class PermissionObserversRegistry {
+ public:
+ PermissionObserversRegistry();
+ ~PermissionObserversRegistry();
+
+ void RegisterObserver(blink::WebPermissionObserver* observer);
+ void UnregisterObserver(blink::WebPermissionObserver* observer);
+ bool IsObserverRegistered(blink::WebPermissionObserver* observer) const;
+
+ private:
+ std::set<blink::WebPermissionObserver*> observers_;
+};
+
+} // namespace content
+
+#endif // CONTENT_CHILD_PERMISSIONS_PERMISSION_OBSERVERS_REGISTRY_H_
diff --git a/chromium/content/child/plugin_messages.h b/chromium/content/child/plugin_messages.h
index 2e17c98a4a8..25d4545f683 100644
--- a/chromium/content/child/plugin_messages.h
+++ b/chromium/content/child/plugin_messages.h
@@ -12,9 +12,9 @@
#include "content/public/common/common_param_traits.h"
#include "ipc/ipc_channel_handle.h"
#include "ipc/ipc_message_macros.h"
+#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/ipc/gfx_param_traits.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/rect.h"
#if defined(OS_POSIX)
#include "base/file_descriptor_posix.h"
@@ -61,6 +61,7 @@ IPC_STRUCT_BEGIN(PluginMsg_FetchURL_Params)
IPC_STRUCT_MEMBER(std::string, method)
IPC_STRUCT_MEMBER(std::vector<char>, post_data)
IPC_STRUCT_MEMBER(GURL, referrer)
+ IPC_STRUCT_MEMBER(blink::WebReferrerPolicy, referrer_policy)
IPC_STRUCT_MEMBER(bool, notify_redirect)
IPC_STRUCT_MEMBER(bool, is_plugin_src_load)
IPC_STRUCT_MEMBER(int, render_frame_id)
@@ -304,11 +305,11 @@ IPC_SYNC_MESSAGE_ROUTED2_0(PluginHostMsg_SetWindowlessData,
HANDLE /* modal_loop_pump_messages_event */,
gfx::NativeViewId /* dummy_activation_window*/)
-// Send the IME status retrieved from a windowless plug-in. A windowless plug-in
-// uses the IME attached to a browser process as a renderer does. A plug-in
+// Send the IME status retrieved from a windowless plugin. A windowless plugin
+// uses the IME attached to a browser process as a renderer does. A plugin
// sends this message to control the IME status of a browser process. I would
-// note that a plug-in sends this message to a renderer process that hosts this
-// plug-in (not directly to a browser process) so the renderer process can
+// note that a plugin sends this message to a renderer process that hosts this
+// plugin (not directly to a browser process) so the renderer process can
// update its IME status.
IPC_MESSAGE_ROUTED2(PluginHostMsg_NotifyIMEStatus,
int /* input_type */,
diff --git a/chromium/content/child/power_monitor_broadcast_source.h b/chromium/content/child/power_monitor_broadcast_source.h
index b0d34162fbb..4f2a4fad2f4 100644
--- a/chromium/content/child/power_monitor_broadcast_source.h
+++ b/chromium/content/child/power_monitor_broadcast_source.h
@@ -44,4 +44,4 @@ class CONTENT_EXPORT PowerMonitorBroadcastSource :
} // namespace content
-#endif // CONTENT_CHILD_POWER_MONITOR_MESSAGE_FILTER_H_
+#endif // CONTENT_CHILD_POWER_MONITOR_BROADCAST_SOURCE_H_
diff --git a/chromium/content/child/push_messaging/OWNERS b/chromium/content/child/push_messaging/OWNERS
new file mode 100644
index 00000000000..d09ffef01de
--- /dev/null
+++ b/chromium/content/child/push_messaging/OWNERS
@@ -0,0 +1 @@
+file://content/browser/push_messaging/OWNERS
diff --git a/chromium/content/child/push_messaging/push_dispatcher.cc b/chromium/content/child/push_messaging/push_dispatcher.cc
new file mode 100644
index 00000000000..8cc33fc0dd2
--- /dev/null
+++ b/chromium/content/child/push_messaging/push_dispatcher.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/child/push_messaging/push_dispatcher.h"
+
+#include "content/child/push_messaging/push_provider.h"
+#include "content/common/push_messaging_messages.h"
+
+namespace content {
+
+PushDispatcher::PushDispatcher(ThreadSafeSender* thread_safe_sender)
+ : WorkerThreadMessageFilter(thread_safe_sender), next_request_id_(0) {
+}
+
+PushDispatcher::~PushDispatcher() {
+}
+
+int PushDispatcher::GenerateRequestId(int thread_id) {
+ base::AutoLock lock(request_id_map_lock_);
+ request_id_map_[next_request_id_] = thread_id;
+ return next_request_id_++;
+}
+
+bool PushDispatcher::ShouldHandleMessage(const IPC::Message& msg) const {
+ // Note that not all Push API IPC messages flow through this class. A subset
+ // of the API functionality requires a direct association with a document and
+ // a frame, and for those cases the IPC messages are handled by a
+ // RenderFrameObserver.
+ return msg.type() == PushMessagingMsg_RegisterFromWorkerSuccess::ID ||
+ msg.type() == PushMessagingMsg_RegisterFromWorkerError::ID ||
+ msg.type() == PushMessagingMsg_GetRegistrationSuccess::ID ||
+ msg.type() == PushMessagingMsg_GetRegistrationError::ID ||
+ msg.type() == PushMessagingMsg_GetPermissionStatusSuccess::ID ||
+ msg.type() == PushMessagingMsg_GetPermissionStatusError::ID ||
+ msg.type() == PushMessagingMsg_UnregisterSuccess::ID ||
+ msg.type() == PushMessagingMsg_UnregisterError::ID;
+}
+
+void PushDispatcher::OnFilteredMessageReceived(const IPC::Message& msg) {
+ bool handled = PushProvider::ThreadSpecificInstance(
+ thread_safe_sender(), this)->OnMessageReceived(msg);
+ DCHECK(handled);
+}
+
+bool PushDispatcher::GetWorkerThreadIdForMessage(const IPC::Message& msg,
+ int* ipc_thread_id) {
+ int request_id = -1;
+
+ const bool success = PickleIterator(msg).ReadInt(&request_id);
+ DCHECK(success);
+
+ base::AutoLock lock(request_id_map_lock_);
+ auto it = request_id_map_.find(request_id);
+ if (it != request_id_map_.end()) {
+ *ipc_thread_id = it->second;
+ request_id_map_.erase(it);
+ return true;
+ }
+ return false;
+}
+
+} // namespace content
diff --git a/chromium/content/child/push_messaging/push_dispatcher.h b/chromium/content/child/push_messaging/push_dispatcher.h
new file mode 100644
index 00000000000..5eaf550c2f7
--- /dev/null
+++ b/chromium/content/child/push_messaging/push_dispatcher.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_CHILD_PUSH_MESSAGING_PUSH_DISPATCHER_H_
+#define CONTENT_CHILD_PUSH_MESSAGING_PUSH_DISPATCHER_H_
+
+#include <map>
+
+#include "base/synchronization/lock.h"
+#include "content/child/worker_thread_message_filter.h"
+
+namespace content {
+
+class PushDispatcher : public WorkerThreadMessageFilter {
+ public:
+ explicit PushDispatcher(ThreadSafeSender* thread_safe_sender);
+
+ // Generates a process-unique new request id. Stores it in a map as key to
+ // |thread_id| and returns it. This method can be called on any thread.
+ // Note that the registration requests from document contexts do not go via
+ // this class and their request ids may overlap with the ones generated here.
+ int GenerateRequestId(int thread_id);
+
+ protected:
+ ~PushDispatcher() override;
+
+ private:
+ // WorkerThreadMessageFilter:
+ bool ShouldHandleMessage(const IPC::Message& msg) const override;
+ void OnFilteredMessageReceived(const IPC::Message& msg) override;
+ bool GetWorkerThreadIdForMessage(const IPC::Message& msg,
+ int* ipc_thread_id) override;
+
+ base::Lock request_id_map_lock_;
+ std::map<int, int> request_id_map_; // Maps request id to thread id.
+ int next_request_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(PushDispatcher);
+};
+
+} // namespace content
+
+#endif // CONTENT_CHILD_PUSH_MESSAGING_PUSH_DISPATCHER_H_
diff --git a/chromium/content/child/push_messaging/push_provider.cc b/chromium/content/child/push_messaging/push_provider.cc
new file mode 100644
index 00000000000..40741eb2371
--- /dev/null
+++ b/chromium/content/child/push_messaging/push_provider.cc
@@ -0,0 +1,277 @@
+// Copyright 2014 The Chromium Authors. 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/child/push_messaging/push_provider.h"
+
+#include "base/lazy_instance.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/stl_util.h"
+#include "base/threading/thread_local.h"
+#include "content/child/push_messaging/push_dispatcher.h"
+#include "content/child/service_worker/web_service_worker_registration_impl.h"
+#include "content/child/thread_safe_sender.h"
+#include "content/child/worker_task_runner.h"
+#include "content/common/push_messaging_messages.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/platform/modules/push_messaging/WebPushSubscription.h"
+#include "third_party/WebKit/public/platform/modules/push_messaging/WebPushSubscriptionOptions.h"
+
+namespace content {
+namespace {
+
+int CurrentWorkerId() {
+ return WorkerTaskRunner::Instance()->CurrentWorkerId();
+}
+
+// Returns the id of the given |service_worker_registration|, which
+// is only available on the implementation of the interface.
+int64 GetServiceWorkerRegistrationId(
+ blink::WebServiceWorkerRegistration* service_worker_registration) {
+ return static_cast<WebServiceWorkerRegistrationImpl*>(
+ service_worker_registration)->registration_id();
+}
+
+} // namespace
+
+static base::LazyInstance<base::ThreadLocalPointer<PushProvider>>::Leaky
+ g_push_provider_tls = LAZY_INSTANCE_INITIALIZER;
+
+PushProvider::PushProvider(ThreadSafeSender* thread_safe_sender,
+ PushDispatcher* push_dispatcher)
+ : thread_safe_sender_(thread_safe_sender),
+ push_dispatcher_(push_dispatcher) {
+ g_push_provider_tls.Pointer()->Set(this);
+}
+
+PushProvider::~PushProvider() {
+ g_push_provider_tls.Pointer()->Set(nullptr);
+}
+
+PushProvider* PushProvider::ThreadSpecificInstance(
+ ThreadSafeSender* thread_safe_sender,
+ PushDispatcher* push_dispatcher) {
+ if (g_push_provider_tls.Pointer()->Get())
+ return g_push_provider_tls.Pointer()->Get();
+
+ PushProvider* provider =
+ new PushProvider(thread_safe_sender, push_dispatcher);
+ if (CurrentWorkerId())
+ WorkerTaskRunner::Instance()->AddStopObserver(provider);
+ return provider;
+}
+
+void PushProvider::OnWorkerRunLoopStopped() {
+ delete this;
+}
+
+void PushProvider::subscribe(
+ blink::WebServiceWorkerRegistration* service_worker_registration,
+ const blink::WebPushSubscriptionOptions& options,
+ blink::WebPushSubscriptionCallbacks* callbacks) {
+ DCHECK(service_worker_registration);
+ DCHECK(callbacks);
+ int request_id = push_dispatcher_->GenerateRequestId(CurrentWorkerId());
+ subscription_callbacks_.AddWithID(callbacks, request_id);
+ int64 service_worker_registration_id =
+ GetServiceWorkerRegistrationId(service_worker_registration);
+ thread_safe_sender_->Send(new PushMessagingHostMsg_RegisterFromWorker(
+ request_id, service_worker_registration_id, options.userVisibleOnly));
+}
+
+void PushProvider::unsubscribe(
+ blink::WebServiceWorkerRegistration* service_worker_registration,
+ blink::WebPushUnsubscribeCallbacks* callbacks) {
+ DCHECK(service_worker_registration);
+ DCHECK(callbacks);
+
+ int request_id = push_dispatcher_->GenerateRequestId(CurrentWorkerId());
+ unsubscribe_callbacks_.AddWithID(callbacks, request_id);
+
+ int64 service_worker_registration_id =
+ GetServiceWorkerRegistrationId(service_worker_registration);
+ thread_safe_sender_->Send(new PushMessagingHostMsg_Unregister(
+ request_id, service_worker_registration_id));
+}
+
+void PushProvider::getSubscription(
+ blink::WebServiceWorkerRegistration* service_worker_registration,
+ blink::WebPushSubscriptionCallbacks* callbacks) {
+ DCHECK(service_worker_registration);
+ DCHECK(callbacks);
+ int request_id = push_dispatcher_->GenerateRequestId(CurrentWorkerId());
+ subscription_callbacks_.AddWithID(callbacks, request_id);
+ int64 service_worker_registration_id =
+ GetServiceWorkerRegistrationId(service_worker_registration);
+ thread_safe_sender_->Send(new PushMessagingHostMsg_GetRegistration(
+ request_id, service_worker_registration_id));
+}
+
+void PushProvider::getPermissionStatus(
+ blink::WebServiceWorkerRegistration* service_worker_registration,
+ const blink::WebPushSubscriptionOptions& options,
+ blink::WebPushPermissionStatusCallbacks* callbacks) {
+ DCHECK(service_worker_registration);
+ DCHECK(callbacks);
+ int request_id = push_dispatcher_->GenerateRequestId(CurrentWorkerId());
+ permission_status_callbacks_.AddWithID(callbacks, request_id);
+ int64 service_worker_registration_id =
+ GetServiceWorkerRegistrationId(service_worker_registration);
+ thread_safe_sender_->Send(new PushMessagingHostMsg_GetPermissionStatus(
+ request_id, service_worker_registration_id, options.userVisibleOnly));
+}
+
+bool PushProvider::OnMessageReceived(const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(PushProvider, message)
+ IPC_MESSAGE_HANDLER(PushMessagingMsg_RegisterFromWorkerSuccess,
+ OnRegisterFromWorkerSuccess);
+ IPC_MESSAGE_HANDLER(PushMessagingMsg_RegisterFromWorkerError,
+ OnRegisterFromWorkerError);
+ IPC_MESSAGE_HANDLER(PushMessagingMsg_UnregisterSuccess,
+ OnUnregisterSuccess);
+ IPC_MESSAGE_HANDLER(PushMessagingMsg_UnregisterError,
+ OnUnregisterError);
+ IPC_MESSAGE_HANDLER(PushMessagingMsg_GetRegistrationSuccess,
+ OnGetRegistrationSuccess);
+ IPC_MESSAGE_HANDLER(PushMessagingMsg_GetRegistrationError,
+ OnGetRegistrationError);
+ IPC_MESSAGE_HANDLER(PushMessagingMsg_GetPermissionStatusSuccess,
+ OnGetPermissionStatusSuccess);
+ IPC_MESSAGE_HANDLER(PushMessagingMsg_GetPermissionStatusError,
+ OnGetPermissionStatusError);
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+
+ return handled;
+}
+
+void PushProvider::OnRegisterFromWorkerSuccess(
+ int request_id,
+ const GURL& endpoint,
+ const std::string& registration_id) {
+ blink::WebPushSubscriptionCallbacks* callbacks =
+ subscription_callbacks_.Lookup(request_id);
+ if (!callbacks)
+ return;
+
+ scoped_ptr<blink::WebPushSubscription> subscription(
+ new blink::WebPushSubscription(
+ blink::WebString::fromUTF8(endpoint.spec()),
+ blink::WebString::fromUTF8(registration_id)));
+ callbacks->onSuccess(subscription.release());
+
+ subscription_callbacks_.Remove(request_id);
+}
+
+void PushProvider::OnRegisterFromWorkerError(int request_id,
+ PushRegistrationStatus status) {
+ blink::WebPushSubscriptionCallbacks* callbacks =
+ subscription_callbacks_.Lookup(request_id);
+ if (!callbacks)
+ return;
+
+ scoped_ptr<blink::WebPushError> error(new blink::WebPushError(
+ blink::WebPushError::ErrorTypeAbort,
+ blink::WebString::fromUTF8(PushRegistrationStatusToString(status))));
+ callbacks->onError(error.release());
+
+ subscription_callbacks_.Remove(request_id);
+}
+
+void PushProvider::OnUnregisterSuccess(int request_id, bool did_unregister) {
+ blink::WebPushUnsubscribeCallbacks* callbacks =
+ unsubscribe_callbacks_.Lookup(request_id);
+ if (!callbacks)
+ return;
+
+ callbacks->onSuccess(&did_unregister);
+
+ unsubscribe_callbacks_.Remove(request_id);
+}
+
+void PushProvider::OnUnregisterError(
+ int request_id,
+ blink::WebPushError::ErrorType error_type,
+ const std::string& error_message) {
+ blink::WebPushUnsubscribeCallbacks* callbacks =
+ unsubscribe_callbacks_.Lookup(request_id);
+ if (!callbacks)
+ return;
+
+ scoped_ptr<blink::WebPushError> error(new blink::WebPushError(
+ error_type, blink::WebString::fromUTF8(error_message)));
+ callbacks->onError(error.release());
+
+ unsubscribe_callbacks_.Remove(request_id);
+}
+
+void PushProvider::OnGetRegistrationSuccess(
+ int request_id,
+ const GURL& endpoint,
+ const std::string& registration_id) {
+ blink::WebPushSubscriptionCallbacks* callbacks =
+ subscription_callbacks_.Lookup(request_id);
+ if (!callbacks)
+ return;
+
+ scoped_ptr<blink::WebPushSubscription> subscription(
+ new blink::WebPushSubscription(
+ blink::WebString::fromUTF8(endpoint.spec()),
+ blink::WebString::fromUTF8(registration_id)));
+ callbacks->onSuccess(subscription.release());
+
+ subscription_callbacks_.Remove(request_id);
+}
+
+void PushProvider::OnGetRegistrationError(
+ int request_id,
+ PushGetRegistrationStatus status) {
+ blink::WebPushSubscriptionCallbacks* callbacks =
+ subscription_callbacks_.Lookup(request_id);
+ if (!callbacks)
+ return;
+
+ // We are only expecting an error if we can't find a registration.
+ callbacks->onSuccess(nullptr);
+
+ subscription_callbacks_.Remove(request_id);
+}
+
+void PushProvider::OnGetPermissionStatusSuccess(
+ int request_id,
+ blink::WebPushPermissionStatus status) {
+ blink::WebPushPermissionStatusCallbacks* callbacks =
+ permission_status_callbacks_.Lookup(request_id);
+ if (!callbacks)
+ return;
+
+ callbacks->onSuccess(&status);
+
+ permission_status_callbacks_.Remove(request_id);
+}
+
+void PushProvider::OnGetPermissionStatusError(
+ int request_id,
+ blink::WebPushError::ErrorType error) {
+ blink::WebPushPermissionStatusCallbacks* callbacks =
+ permission_status_callbacks_.Lookup(request_id);
+ if (!callbacks)
+ return;
+
+ std::string error_message;
+ if (error == blink::WebPushError::ErrorTypeNotSupported) {
+ error_message =
+ "Push subscriptions that don't enable userVisibleOnly are not "
+ "supported.";
+ }
+
+ scoped_ptr<blink::WebPushError> web_error(new blink::WebPushError(
+ error, blink::WebString::fromUTF8(error_message)));
+
+ callbacks->onError(web_error.release());
+
+ permission_status_callbacks_.Remove(request_id);
+}
+
+} // namespace content
diff --git a/chromium/content/child/push_messaging/push_provider.h b/chromium/content/child/push_messaging/push_provider.h
new file mode 100644
index 00000000000..47442ae0230
--- /dev/null
+++ b/chromium/content/child/push_messaging/push_provider.h
@@ -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.
+
+#ifndef CONTENT_CHILD_PUSH_MESSAGING_PUSH_PROVIDER_H_
+#define CONTENT_CHILD_PUSH_MESSAGING_PUSH_PROVIDER_H_
+
+#include <string>
+
+#include "base/id_map.h"
+#include "base/memory/ref_counted.h"
+#include "content/child/push_messaging/push_dispatcher.h"
+#include "content/child/worker_task_runner.h"
+#include "content/public/common/push_messaging_status.h"
+#include "third_party/WebKit/public/platform/modules/push_messaging/WebPushError.h"
+#include "third_party/WebKit/public/platform/modules/push_messaging/WebPushProvider.h"
+
+class GURL;
+
+namespace blink {
+struct WebPushSubscriptionOptions;
+}
+
+namespace content {
+
+class ThreadSafeSender;
+
+class PushProvider : public blink::WebPushProvider,
+ public WorkerTaskRunner::Observer {
+ public:
+ ~PushProvider() override;
+
+ // The |thread_safe_sender| and |push_dispatcher| are used if calling this
+ // leads to construction.
+ static PushProvider* ThreadSpecificInstance(
+ ThreadSafeSender* thread_safe_sender,
+ PushDispatcher* push_dispatcher);
+
+ // WorkerTaskRunner::Observer implementation.
+ void OnWorkerRunLoopStopped() override;
+
+ // blink::WebPushProvider implementation.
+ virtual void subscribe(
+ blink::WebServiceWorkerRegistration* service_worker_registration,
+ const blink::WebPushSubscriptionOptions& options,
+ blink::WebPushSubscriptionCallbacks* callbacks);
+ virtual void unsubscribe(
+ blink::WebServiceWorkerRegistration* service_worker_registration,
+ blink::WebPushUnsubscribeCallbacks* callbacks);
+ virtual void getSubscription(
+ blink::WebServiceWorkerRegistration* service_worker_registration,
+ blink::WebPushSubscriptionCallbacks* callbacks);
+ virtual void getPermissionStatus(
+ blink::WebServiceWorkerRegistration* service_worker_registration,
+ const blink::WebPushSubscriptionOptions& options,
+ blink::WebPushPermissionStatusCallbacks* callbacks);
+
+ // Called by the PushDispatcher.
+ bool OnMessageReceived(const IPC::Message& message);
+
+ private:
+ PushProvider(ThreadSafeSender* thread_safe_sender,
+ PushDispatcher* push_dispatcher);
+
+ // IPC message handlers.
+ void OnRegisterFromWorkerSuccess(int request_id,
+ const GURL& endpoint,
+ const std::string& registration_id);
+ void OnRegisterFromWorkerError(int request_id, PushRegistrationStatus status);
+ void OnUnregisterSuccess(int request_id, bool did_unregister);
+ void OnUnregisterError(int request_id,
+ blink::WebPushError::ErrorType error_type,
+ const std::string& error_message);
+ void OnGetRegistrationSuccess(int request_id,
+ const GURL& endpoint,
+ const std::string& registration_id);
+ void OnGetRegistrationError(int request_id, PushGetRegistrationStatus status);
+ void OnGetPermissionStatusSuccess(int request_id,
+ blink::WebPushPermissionStatus status);
+ void OnGetPermissionStatusError(int request_id,
+ blink::WebPushError::ErrorType error);
+
+ scoped_refptr<ThreadSafeSender> thread_safe_sender_;
+ scoped_refptr<PushDispatcher> push_dispatcher_;
+
+ // Stores the subscription callbacks with their request ids. This class owns
+ // the callbacks.
+ IDMap<blink::WebPushSubscriptionCallbacks, IDMapOwnPointer>
+ subscription_callbacks_;
+
+ // Stores the permission status callbacks with their request ids. This class
+ // owns the callbacks.
+ IDMap<blink::WebPushPermissionStatusCallbacks, IDMapOwnPointer>
+ permission_status_callbacks_;
+
+ // Stores the unsubscription callbacks with their request ids. This class owns
+ // the callbacks.
+ IDMap<blink::WebPushUnsubscribeCallbacks, IDMapOwnPointer>
+ unsubscribe_callbacks_;
+
+ DISALLOW_COPY_AND_ASSIGN(PushProvider);
+};
+
+} // namespace content
+
+#endif // CONTENT_CHILD_PUSH_MESSAGING_PUSH_PROVIDER_H_
diff --git a/chromium/content/child/quota_dispatcher.cc b/chromium/content/child/quota_dispatcher.cc
index 5862783768f..fa766dba127 100644
--- a/chromium/content/child/quota_dispatcher.cc
+++ b/chromium/content/child/quota_dispatcher.cc
@@ -7,7 +7,6 @@
#include "base/basictypes.h"
#include "base/lazy_instance.h"
#include "base/threading/thread_local.h"
-#include "content/child/child_thread.h"
#include "content/child/quota_message_filter.h"
#include "content/child/thread_safe_sender.h"
#include "content/common/quota_messages.h"
@@ -175,18 +174,18 @@ void QuotaDispatcher::DidFail(
pending_quota_callbacks_.Remove(request_id);
}
-COMPILE_ASSERT(int(blink::WebStorageQuotaTypeTemporary) ==
- int(storage::kStorageTypeTemporary),
- mismatching_enums);
-COMPILE_ASSERT(int(blink::WebStorageQuotaTypePersistent) ==
- int(storage::kStorageTypePersistent),
- mismatching_enums);
-
-COMPILE_ASSERT(int(blink::WebStorageQuotaErrorNotSupported) ==
- int(storage::kQuotaErrorNotSupported),
- mismatching_enums);
-COMPILE_ASSERT(int(blink::WebStorageQuotaErrorAbort) ==
- int(storage::kQuotaErrorAbort),
- mismatching_enums);
+static_assert(int(blink::WebStorageQuotaTypeTemporary) ==
+ int(storage::kStorageTypeTemporary),
+ "mismatching enums: kStorageTypeTemporary");
+static_assert(int(blink::WebStorageQuotaTypePersistent) ==
+ int(storage::kStorageTypePersistent),
+ "mismatching enums: kStorageTypePersistent");
+
+static_assert(int(blink::WebStorageQuotaErrorNotSupported) ==
+ int(storage::kQuotaErrorNotSupported),
+ "mismatching enums: kQuotaErrorNotSupported");
+static_assert(int(blink::WebStorageQuotaErrorAbort) ==
+ int(storage::kQuotaErrorAbort),
+ "mismatching enums: kQuotaErrorAbort");
} // namespace content
diff --git a/chromium/content/child/quota_message_filter.cc b/chromium/content/child/quota_message_filter.cc
index 139be2550de..e9290e489d9 100644
--- a/chromium/content/child/quota_message_filter.cc
+++ b/chromium/content/child/quota_message_filter.cc
@@ -4,19 +4,13 @@
#include "content/child/quota_message_filter.h"
-#include "base/message_loop/message_loop_proxy.h"
#include "content/child/quota_dispatcher.h"
-#include "content/child/thread_safe_sender.h"
-#include "content/child/worker_thread_task_runner.h"
#include "content/common/quota_messages.h"
namespace content {
-QuotaMessageFilter::QuotaMessageFilter(
- ThreadSafeSender* thread_safe_sender)
- : main_thread_loop_proxy_(base::MessageLoopProxy::current()),
- thread_safe_sender_(thread_safe_sender),
- next_request_id_(0) {
+QuotaMessageFilter::QuotaMessageFilter(ThreadSafeSender* thread_safe_sender)
+ : WorkerThreadMessageFilter(thread_safe_sender), next_request_id_(0) {
}
QuotaMessageFilter::~QuotaMessageFilter() {}
@@ -38,35 +32,29 @@ void QuotaMessageFilter::ClearThreadRequests(int thread_id) {
}
}
-base::TaskRunner* QuotaMessageFilter::OverrideTaskRunnerForMessage(
- const IPC::Message& msg) {
- if (IPC_MESSAGE_CLASS(msg) != QuotaMsgStart)
- return NULL;
+bool QuotaMessageFilter::ShouldHandleMessage(const IPC::Message& msg) const {
+ return IPC_MESSAGE_CLASS(msg) == QuotaMsgStart;
+}
- int request_id = -1, thread_id = 0;
+void QuotaMessageFilter::OnFilteredMessageReceived(const IPC::Message& msg) {
+ QuotaDispatcher::ThreadSpecificInstance(thread_safe_sender(), this)
+ ->OnMessageReceived(msg);
+}
+
+bool QuotaMessageFilter::GetWorkerThreadIdForMessage(const IPC::Message& msg,
+ int* ipc_thread_id) {
+ int request_id = -1;
const bool success = PickleIterator(msg).ReadInt(&request_id);
DCHECK(success);
- {
- base::AutoLock lock(request_id_map_lock_);
- RequestIdToThreadId::iterator found = request_id_map_.find(request_id);
- if (found != request_id_map_.end()) {
- thread_id = found->second;
- request_id_map_.erase(found);
- }
+ base::AutoLock lock(request_id_map_lock_);
+ RequestIdToThreadId::iterator found = request_id_map_.find(request_id);
+ if (found != request_id_map_.end()) {
+ *ipc_thread_id = found->second;
+ request_id_map_.erase(found);
+ return true;
}
-
- if (!thread_id)
- return main_thread_loop_proxy_.get();
- return new WorkerThreadTaskRunner(thread_id);
-}
-
-bool QuotaMessageFilter::OnMessageReceived(const IPC::Message& msg) {
- if (IPC_MESSAGE_CLASS(msg) != QuotaMsgStart)
- return false;
- QuotaDispatcher::ThreadSpecificInstance(thread_safe_sender_.get(), this)
- ->OnMessageReceived(msg);
- return true;
+ return false;
}
} // namespace content
diff --git a/chromium/content/child/quota_message_filter.h b/chromium/content/child/quota_message_filter.h
index b13e705e920..d6135849201 100644
--- a/chromium/content/child/quota_message_filter.h
+++ b/chromium/content/child/quota_message_filter.h
@@ -7,19 +7,12 @@
#include <map>
-#include "base/memory/ref_counted.h"
#include "base/synchronization/lock.h"
-#include "content/child/child_message_filter.h"
-
-namespace base {
-class MessageLoopProxy;
-}
+#include "content/child/worker_thread_message_filter.h"
namespace content {
-class ThreadSafeSender;
-
-class QuotaMessageFilter : public ChildMessageFilter {
+class QuotaMessageFilter : public WorkerThreadMessageFilter {
public:
explicit QuotaMessageFilter(ThreadSafeSender* thread_safe_sender);
@@ -35,16 +28,14 @@ class QuotaMessageFilter : public ChildMessageFilter {
~QuotaMessageFilter() override;
private:
- // ChildMessageFilter implementation:
- base::TaskRunner* OverrideTaskRunnerForMessage(
- const IPC::Message& msg) override;
- bool OnMessageReceived(const IPC::Message& msg) override;
+ // WorkerThreadMessageFilter:
+ bool ShouldHandleMessage(const IPC::Message& msg) const override;
+ void OnFilteredMessageReceived(const IPC::Message& msg) override;
+ bool GetWorkerThreadIdForMessage(const IPC::Message& msg,
+ int* ipc_thread_id) override;
typedef std::map<int, int> RequestIdToThreadId;
- scoped_refptr<base::MessageLoopProxy> main_thread_loop_proxy_;
- scoped_refptr<ThreadSafeSender> thread_safe_sender_;
-
base::Lock request_id_map_lock_;
RequestIdToThreadId request_id_map_;
int next_request_id_;
diff --git a/chromium/content/child/request_extra_data.h b/chromium/content/child/request_extra_data.h
index 4ba5fbcb790..614d9fc321c 100644
--- a/chromium/content/child/request_extra_data.h
+++ b/chromium/content/child/request_extra_data.h
@@ -8,9 +8,9 @@
#include "base/compiler_specific.h"
#include "content/child/web_url_loader_impl.h"
#include "content/common/content_export.h"
+#include "third_party/WebKit/public/platform/WebPageVisibilityState.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/platform/WebURLRequest.h"
-#include "third_party/WebKit/public/web/WebPageVisibilityState.h"
#include "ui/base/page_transition_types.h"
namespace content {
diff --git a/chromium/content/child/request_info.cc b/chromium/content/child/request_info.cc
index e52f2aa688f..37189237207 100644
--- a/chromium/content/child/request_info.cc
+++ b/chromium/content/child/request_info.cc
@@ -7,8 +7,7 @@
namespace content {
RequestInfo::RequestInfo()
- : referrer_policy(blink::WebReferrerPolicyDefault),
- load_flags(0),
+ : load_flags(0),
requestor_pid(0),
request_type(RESOURCE_TYPE_MAIN_FRAME),
fetch_request_context_type(REQUEST_CONTEXT_TYPE_UNSPECIFIED),
@@ -20,10 +19,12 @@ RequestInfo::RequestInfo()
download_to_file(false),
has_user_gesture(false),
skip_service_worker(false),
+ should_reset_appcache(false),
fetch_request_mode(FETCH_REQUEST_MODE_NO_CORS),
fetch_credentials_mode(FETCH_CREDENTIALS_MODE_OMIT),
enable_load_timing(false),
enable_upload_progress(false),
+ do_not_prompt_for_login(false),
extra_data(NULL) {
}
diff --git a/chromium/content/child/request_info.h b/chromium/content/child/request_info.h
index 6861741905b..feb34375fab 100644
--- a/chromium/content/child/request_info.h
+++ b/chromium/content/child/request_info.h
@@ -11,6 +11,7 @@
#include "content/common/content_export.h"
#include "content/common/service_worker/service_worker_types.h"
+#include "content/public/common/referrer.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"
@@ -36,12 +37,8 @@ struct CONTENT_EXPORT RequestInfo {
// third-party cookie blocking policy.
GURL first_party_for_cookies;
- // Optional parameter, a URL with similar constraints in how it must be
- // encoded as the url member.
- GURL referrer;
-
- // The referrer policy that applies to the referrer.
- blink::WebReferrerPolicy referrer_policy;
+ // Optional parameter, the referrer to use for the request for the url member.
+ Referrer referrer;
// For HTTP(S) requests, the headers parameter can be a \r\n-delimited and
// \r\n-terminated list of MIME headers. They should be ASCII-encoded using
@@ -83,6 +80,9 @@ struct CONTENT_EXPORT RequestInfo {
// True if the request should not be handled by the ServiceWorker.
bool skip_service_worker;
+ // True if corresponding AppCache group should be resetted.
+ bool should_reset_appcache;
+
// The request mode passed to the ServiceWorker.
FetchRequestMode fetch_request_mode;
@@ -96,6 +96,10 @@ struct CONTENT_EXPORT RequestInfo {
// True if upload progress should be available.
bool enable_upload_progress;
+ // True if login prompts for this request should be supressed. Cached
+ // credentials or default credentials may still be used for authentication.
+ bool do_not_prompt_for_login;
+
// Extra data associated with this request. We do not own this pointer.
blink::WebURLRequest::ExtraData* extra_data;
diff --git a/chromium/content/child/resource_dispatcher.cc b/chromium/content/child/resource_dispatcher.cc
index ac2ff3b5f01..baa6f6f65fc 100644
--- a/chromium/content/child/resource_dispatcher.cc
+++ b/chromium/content/child/resource_dispatcher.cc
@@ -10,6 +10,7 @@
#include "base/bind.h"
#include "base/compiler_specific.h"
#include "base/debug/alias.h"
+#include "base/debug/dump_without_crashing.h"
#include "base/files/file_path.h"
#include "base/memory/shared_memory.h"
#include "base/message_loop/message_loop.h"
@@ -17,7 +18,6 @@
#include "base/strings/string_util.h"
#include "content/child/request_extra_data.h"
#include "content/child/request_info.h"
-#include "content/child/resource_loader_bridge.h"
#include "content/child/site_isolation_policy.h"
#include "content/child/sync_load_response.h"
#include "content/child/threaded_data_provider.h"
@@ -64,226 +64,19 @@ int MakeRequestID() {
} // namespace
-// ResourceLoaderBridge implementation ----------------------------------------
-
-class IPCResourceLoaderBridge : public ResourceLoaderBridge {
- public:
- IPCResourceLoaderBridge(ResourceDispatcher* dispatcher,
- const RequestInfo& request_info);
- ~IPCResourceLoaderBridge() override;
-
- // ResourceLoaderBridge
- void SetRequestBody(ResourceRequestBody* request_body) override;
- bool Start(RequestPeer* peer) override;
- void Cancel() override;
- void SetDefersLoading(bool value) override;
- void DidChangePriority(net::RequestPriority new_priority,
- int intra_priority_value) override;
- bool AttachThreadedDataReceiver(
- blink::WebThreadedDataReceiver* threaded_data_receiver) override;
- void SyncLoad(SyncLoadResponse* response) override;
-
- private:
- // The resource dispatcher for this loader. The bridge doesn't own it, but
- // it's guaranteed to outlive the bridge.
- ResourceDispatcher* dispatcher_;
-
- // The request to send, created on initialization for modification and
- // appending data.
- ResourceHostMsg_Request request_;
-
- // ID for the request, valid once Start()ed, -1 if not valid yet.
- int request_id_;
-
- // The routing id used when sending IPC messages.
- int routing_id_;
-
- // The security origin of the frame that initiates this request.
- GURL frame_origin_;
-
- bool is_synchronous_request_;
-};
-
-IPCResourceLoaderBridge::IPCResourceLoaderBridge(
- ResourceDispatcher* dispatcher,
- const RequestInfo& request_info)
- : dispatcher_(dispatcher),
- request_id_(-1),
- routing_id_(request_info.routing_id),
- is_synchronous_request_(false) {
- DCHECK(dispatcher_) << "no resource dispatcher";
- request_.method = request_info.method;
- request_.url = request_info.url;
- request_.first_party_for_cookies = request_info.first_party_for_cookies;
- request_.referrer = request_info.referrer;
- request_.referrer_policy = request_info.referrer_policy;
- request_.headers = request_info.headers;
- request_.load_flags = request_info.load_flags;
- request_.origin_pid = request_info.requestor_pid;
- request_.resource_type = request_info.request_type;
- request_.priority = request_info.priority;
- request_.request_context = request_info.request_context;
- request_.appcache_host_id = request_info.appcache_host_id;
- request_.download_to_file = request_info.download_to_file;
- request_.has_user_gesture = request_info.has_user_gesture;
- request_.skip_service_worker = request_info.skip_service_worker;
- request_.fetch_request_mode = request_info.fetch_request_mode;
- request_.fetch_credentials_mode = request_info.fetch_credentials_mode;
- request_.fetch_request_context_type = request_info.fetch_request_context_type;
- request_.fetch_frame_type = request_info.fetch_frame_type;
- request_.enable_load_timing = request_info.enable_load_timing;
- request_.enable_upload_progress = request_info.enable_upload_progress;
-
- const RequestExtraData kEmptyData;
- const RequestExtraData* extra_data;
- if (request_info.extra_data)
- extra_data = static_cast<RequestExtraData*>(request_info.extra_data);
- else
- extra_data = &kEmptyData;
- request_.visiblity_state = extra_data->visibility_state();
- request_.render_frame_id = extra_data->render_frame_id();
- request_.is_main_frame = extra_data->is_main_frame();
- request_.parent_is_main_frame = extra_data->parent_is_main_frame();
- request_.parent_render_frame_id = extra_data->parent_render_frame_id();
- request_.allow_download = extra_data->allow_download();
- request_.transition_type = extra_data->transition_type();
- request_.should_replace_current_entry =
- extra_data->should_replace_current_entry();
- request_.transferred_request_child_id =
- extra_data->transferred_request_child_id();
- request_.transferred_request_request_id =
- extra_data->transferred_request_request_id();
- request_.service_worker_provider_id =
- extra_data->service_worker_provider_id();
- frame_origin_ = extra_data->frame_origin();
-}
-
-IPCResourceLoaderBridge::~IPCResourceLoaderBridge() {
- // we remove our hook for the resource dispatcher only when going away, since
- // it doesn't keep track of whether we've force terminated the request
- if (request_id_ >= 0) {
- // this operation may fail, as the dispatcher will have preemptively
- // removed us when the renderer sends the ReceivedAllData message.
- dispatcher_->RemovePendingRequest(request_id_);
- }
-}
-
-void IPCResourceLoaderBridge::SetRequestBody(
- ResourceRequestBody* request_body) {
- DCHECK(request_id_ == -1) << "request already started";
- request_.request_body = request_body;
-}
-
-// Writes a footer on the message and sends it
-bool IPCResourceLoaderBridge::Start(RequestPeer* peer) {
- if (request_id_ != -1) {
- NOTREACHED() << "Starting a request twice";
- return false;
- }
-
- // generate the request ID, and append it to the message
- request_id_ = dispatcher_->AddPendingRequest(peer,
- request_.resource_type,
- request_.origin_pid,
- frame_origin_,
- request_.url,
- request_.download_to_file);
-
- return dispatcher_->message_sender()->Send(
- new ResourceHostMsg_RequestResource(routing_id_, request_id_, request_));
-}
-
-void IPCResourceLoaderBridge::Cancel() {
- if (request_id_ < 0) {
- NOTREACHED() << "Trying to cancel an unstarted request";
- return;
- }
-
- if (!is_synchronous_request_) {
- // This also removes the the request from the dispatcher.
- dispatcher_->CancelPendingRequest(request_id_);
- }
-}
-
-void IPCResourceLoaderBridge::SetDefersLoading(bool value) {
- if (request_id_ < 0) {
- NOTREACHED() << "Trying to (un)defer an unstarted request";
- return;
- }
-
- dispatcher_->SetDefersLoading(request_id_, value);
-}
-
-void IPCResourceLoaderBridge::DidChangePriority(
- net::RequestPriority new_priority,
- int intra_priority_value) {
- if (request_id_ < 0) {
- NOTREACHED() << "Trying to change priority of an unstarted request";
- return;
- }
-
- dispatcher_->DidChangePriority(
- request_id_, new_priority, intra_priority_value);
-}
-
-bool IPCResourceLoaderBridge::AttachThreadedDataReceiver(
- blink::WebThreadedDataReceiver* threaded_data_receiver) {
- if (request_id_ < 0) {
- NOTREACHED() << "Trying to attach threaded receiver on unstarted request";
- return false;
- }
-
- return dispatcher_->AttachThreadedDataReceiver(request_id_,
- threaded_data_receiver);
-}
-
-void IPCResourceLoaderBridge::SyncLoad(SyncLoadResponse* response) {
- if (request_id_ != -1) {
- NOTREACHED() << "Starting a request twice";
- response->error_code = net::ERR_FAILED;
- return;
- }
-
- request_id_ = MakeRequestID();
- is_synchronous_request_ = true;
-
- SyncLoadResult result;
- IPC::SyncMessage* msg = new ResourceHostMsg_SyncLoad(routing_id_, request_id_,
- request_, &result);
- // NOTE: This may pump events (see RenderThread::Send).
- if (!dispatcher_->message_sender()->Send(msg)) {
- response->error_code = net::ERR_FAILED;
- return;
- }
-
- response->error_code = result.error_code;
- response->url = result.final_url;
- response->headers = result.headers;
- response->mime_type = result.mime_type;
- response->charset = result.charset;
- response->request_time = result.request_time;
- response->response_time = result.response_time;
- response->encoded_data_length = result.encoded_data_length;
- response->load_timing = result.load_timing;
- response->devtools_info = result.devtools_info;
- response->data.swap(result.data);
- response->download_file_path = result.download_file_path;
-}
-
-// ResourceDispatcher ---------------------------------------------------------
-
-ResourceDispatcher::ResourceDispatcher(IPC::Sender* sender)
+ResourceDispatcher::ResourceDispatcher(
+ IPC::Sender* sender,
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner)
: message_sender_(sender),
delegate_(NULL),
io_timestamp_(base::TimeTicks()),
+ main_thread_task_runner_(main_thread_task_runner),
weak_factory_(this) {
}
ResourceDispatcher::~ResourceDispatcher() {
}
-// ResourceDispatcher implementation ------------------------------------------
-
bool ResourceDispatcher::OnMessageReceived(const IPC::Message& message) {
if (!IsResourceDispatcherMessage(message)) {
return false;
@@ -292,7 +85,7 @@ bool ResourceDispatcher::OnMessageReceived(const IPC::Message& message) {
int request_id;
PickleIterator iter(message);
- if (!message.ReadInt(&iter, &request_id)) {
+ if (!iter.ReadInt(&request_id)) {
NOTREACHED() << "malformed resource message";
return true;
}
@@ -363,13 +156,6 @@ void ResourceDispatcher::OnReceivedResponse(
request_info->peer = new_peer;
}
- // Updates the response_url if the response was fetched by a ServiceWorker,
- // and it was not generated inside the ServiceWorker.
- if (response_head.was_fetched_via_service_worker &&
- !response_head.original_url_via_service_worker.is_empty()) {
- request_info->response_url = response_head.original_url_via_service_worker;
- }
-
ResourceResponseInfo renderer_response_info;
ToResourceResponseInfo(*request_info, response_head, &renderer_response_info);
request_info->site_isolation_metadata =
@@ -435,8 +221,7 @@ void ResourceDispatcher::OnReceivedData(int request_id,
CHECK_GE(request_info->buffer_size, data_offset + data_length);
// Ensure that the SHM buffer remains valid for the duration of this scope.
- // It is possible for CancelPendingRequest() to be called before we exit
- // this scope.
+ // It is possible for Cancel() to be called before we exit this scope.
linked_ptr<base::SharedMemory> retain_buffer(request_info->buffer);
base::TimeTicks time_start = base::TimeTicks::Now();
@@ -529,7 +314,7 @@ void ResourceDispatcher::OnReceivedRedirect(
FollowPendingRedirect(request_id, *request_info);
}
} else {
- CancelPendingRequest(request_id);
+ Cancel(request_id);
}
}
@@ -566,6 +351,17 @@ void ResourceDispatcher::OnRequestComplete(
base::TimeTicks renderer_completion_time = ToRendererCompletionTime(
*request_info, request_complete_data.completion_time);
+
+ // If we have a threaded data provider, this message needs to bounce off the
+ // background thread before it's returned to this thread and handled,
+ // to make sure it's processed after all incoming data.
+ if (request_info->threaded_data_provider) {
+ request_info->threaded_data_provider->OnRequestCompleteForegroundThread(
+ weak_factory_.GetWeakPtr(), request_complete_data,
+ renderer_completion_time);
+ return;
+ }
+
// The request ID will be removed from our pending list in the destructor.
// Normally, dispatching this message causes the reference-counted request to
// die immediately.
@@ -577,21 +373,21 @@ void ResourceDispatcher::OnRequestComplete(
request_complete_data.encoded_data_length);
}
-int ResourceDispatcher::AddPendingRequest(RequestPeer* callback,
- ResourceType resource_type,
- int origin_pid,
- const GURL& frame_origin,
- const GURL& request_url,
- bool download_to_file) {
- // Compute a unique request_id for this renderer process.
- int id = MakeRequestID();
- pending_requests_[id] = PendingRequestInfo(callback,
- resource_type,
- origin_pid,
- frame_origin,
- request_url,
- download_to_file);
- return id;
+void ResourceDispatcher::CompletedRequestAfterBackgroundThreadFlush(
+ int request_id,
+ const ResourceMsg_RequestCompleteData& request_complete_data,
+ const base::TimeTicks& renderer_completion_time) {
+ PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
+ if (!request_info)
+ return;
+
+ RequestPeer* peer = request_info->peer;
+ peer->OnCompletedRequest(request_complete_data.error_code,
+ request_complete_data.was_ignored_by_handler,
+ request_complete_data.exists_in_cache,
+ request_complete_data.security_info,
+ renderer_completion_time,
+ request_complete_data.encoded_data_length);
}
bool ResourceDispatcher::RemovePendingRequest(int request_id) {
@@ -614,7 +410,7 @@ bool ResourceDispatcher::RemovePendingRequest(int request_id) {
return true;
}
-void ResourceDispatcher::CancelPendingRequest(int request_id) {
+void ResourceDispatcher::Cancel(int request_id) {
PendingRequestList::iterator it = pending_requests_.find(request_id);
if (it == pending_requests_.end()) {
DVLOG(1) << "unknown request";
@@ -641,11 +437,9 @@ void ResourceDispatcher::SetDefersLoading(int request_id, bool value) {
FollowPendingRedirect(request_id, request_info);
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&ResourceDispatcher::FlushDeferredMessages,
- weak_factory_.GetWeakPtr(),
- request_id));
+ main_thread_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&ResourceDispatcher::FlushDeferredMessages,
+ weak_factory_.GetWeakPtr(), request_id));
}
}
@@ -666,7 +460,7 @@ bool ResourceDispatcher::AttachThreadedDataReceiver(
DCHECK(!request_info->threaded_data_provider);
request_info->threaded_data_provider = new ThreadedDataProvider(
request_id, threaded_data_receiver, request_info->buffer,
- request_info->buffer_size);
+ request_info->buffer_size, main_thread_task_runner_);
return true;
}
@@ -752,9 +546,57 @@ void ResourceDispatcher::FlushDeferredMessages(int request_id) {
}
}
-ResourceLoaderBridge* ResourceDispatcher::CreateBridge(
- const RequestInfo& request_info) {
- return new IPCResourceLoaderBridge(this, request_info);
+void ResourceDispatcher::StartSync(const RequestInfo& request_info,
+ ResourceRequestBody* request_body,
+ SyncLoadResponse* response) {
+ scoped_ptr<ResourceHostMsg_Request> request =
+ CreateRequest(request_info, request_body, NULL);
+
+ SyncLoadResult result;
+ IPC::SyncMessage* msg = new ResourceHostMsg_SyncLoad(
+ request_info.routing_id, MakeRequestID(), *request, &result);
+
+ // NOTE: This may pump events (see RenderThread::Send).
+ if (!message_sender_->Send(msg)) {
+ response->error_code = net::ERR_FAILED;
+ return;
+ }
+
+ response->error_code = result.error_code;
+ response->url = result.final_url;
+ response->headers = result.headers;
+ response->mime_type = result.mime_type;
+ response->charset = result.charset;
+ response->request_time = result.request_time;
+ response->response_time = result.response_time;
+ response->encoded_data_length = result.encoded_data_length;
+ response->load_timing = result.load_timing;
+ response->devtools_info = result.devtools_info;
+ response->data.swap(result.data);
+ response->download_file_path = result.download_file_path;
+}
+
+int ResourceDispatcher::StartAsync(const RequestInfo& request_info,
+ ResourceRequestBody* request_body,
+ RequestPeer* peer) {
+ GURL frame_origin;
+ scoped_ptr<ResourceHostMsg_Request> request =
+ CreateRequest(request_info, request_body, &frame_origin);
+
+ // Compute a unique request_id for this renderer process.
+ int request_id = MakeRequestID();
+ pending_requests_[request_id] =
+ PendingRequestInfo(peer,
+ request->resource_type,
+ request->origin_pid,
+ frame_origin,
+ request->url,
+ request_info.download_to_file);
+
+ message_sender_->Send(new ResourceHostMsg_RequestResource(
+ request_info.routing_id, request_id, *request));
+
+ return request_id;
}
void ResourceDispatcher::ToResourceResponseInfo(
@@ -864,7 +706,7 @@ void ResourceDispatcher::ReleaseResourcesInDataMessage(
const IPC::Message& message) {
PickleIterator iter(message);
int request_id;
- if (!message.ReadInt(&iter, &request_id)) {
+ if (!iter.ReadInt(&request_id)) {
NOTREACHED() << "malformed resource message";
return;
}
@@ -892,4 +734,71 @@ void ResourceDispatcher::ReleaseResourcesInMessageQueue(MessageQueue* queue) {
}
}
+scoped_ptr<ResourceHostMsg_Request> ResourceDispatcher::CreateRequest(
+ const RequestInfo& request_info,
+ ResourceRequestBody* request_body,
+ GURL* frame_origin) {
+ scoped_ptr<ResourceHostMsg_Request> request(new ResourceHostMsg_Request);
+ request->method = request_info.method;
+ request->url = request_info.url;
+ request->first_party_for_cookies = request_info.first_party_for_cookies;
+ request->referrer = request_info.referrer.url;
+ request->referrer_policy = request_info.referrer.policy;
+ request->headers = request_info.headers;
+ request->load_flags = request_info.load_flags;
+ request->origin_pid = request_info.requestor_pid;
+ request->resource_type = request_info.request_type;
+ request->priority = request_info.priority;
+ request->request_context = request_info.request_context;
+ request->appcache_host_id = request_info.appcache_host_id;
+ request->download_to_file = request_info.download_to_file;
+ request->has_user_gesture = request_info.has_user_gesture;
+ request->skip_service_worker = request_info.skip_service_worker;
+ request->should_reset_appcache = request_info.should_reset_appcache;
+ request->fetch_request_mode = request_info.fetch_request_mode;
+ request->fetch_credentials_mode = request_info.fetch_credentials_mode;
+ request->fetch_request_context_type = request_info.fetch_request_context_type;
+ request->fetch_frame_type = request_info.fetch_frame_type;
+ request->enable_load_timing = request_info.enable_load_timing;
+ request->enable_upload_progress = request_info.enable_upload_progress;
+ request->do_not_prompt_for_login = request_info.do_not_prompt_for_login;
+
+ if ((request_info.referrer.policy == blink::WebReferrerPolicyDefault ||
+ request_info.referrer.policy ==
+ blink::WebReferrerPolicyNoReferrerWhenDowngrade) &&
+ request_info.referrer.url.SchemeIsCryptographic() &&
+ !request_info.url.SchemeIsCryptographic()) {
+ LOG(FATAL) << "Trying to send secure referrer for insecure request "
+ << "without an appropriate referrer policy.\n"
+ << "URL = " << request_info.url << "\n"
+ << "Referrer = " << request_info.referrer.url;
+ }
+
+ const RequestExtraData kEmptyData;
+ const RequestExtraData* extra_data;
+ if (request_info.extra_data)
+ extra_data = static_cast<RequestExtraData*>(request_info.extra_data);
+ else
+ extra_data = &kEmptyData;
+ request->visiblity_state = extra_data->visibility_state();
+ request->render_frame_id = extra_data->render_frame_id();
+ request->is_main_frame = extra_data->is_main_frame();
+ request->parent_is_main_frame = extra_data->parent_is_main_frame();
+ request->parent_render_frame_id = extra_data->parent_render_frame_id();
+ request->allow_download = extra_data->allow_download();
+ request->transition_type = extra_data->transition_type();
+ request->should_replace_current_entry =
+ extra_data->should_replace_current_entry();
+ request->transferred_request_child_id =
+ extra_data->transferred_request_child_id();
+ request->transferred_request_request_id =
+ extra_data->transferred_request_request_id();
+ request->service_worker_provider_id =
+ extra_data->service_worker_provider_id();
+ request->request_body = request_body;
+ if (frame_origin)
+ *frame_origin = extra_data->frame_origin();
+ return request.Pass();
+}
+
} // namespace content
diff --git a/chromium/content/child/resource_dispatcher.h b/chromium/content/child/resource_dispatcher.h
index ac6fbda9cc1..769eae2589f 100644
--- a/chromium/content/child/resource_dispatcher.h
+++ b/chromium/content/child/resource_dispatcher.h
@@ -12,8 +12,10 @@
#include "base/containers/hash_tables.h"
#include "base/memory/linked_ptr.h"
+#include "base/memory/scoped_ptr.h"
#include "base/memory/shared_memory.h"
#include "base/memory/weak_ptr.h"
+#include "base/single_thread_task_runner.h"
#include "base/time/time.h"
#include "content/common/content_export.h"
#include "content/public/common/resource_type.h"
@@ -22,6 +24,7 @@
#include "net/base/request_priority.h"
#include "url/gurl.h"
+struct ResourceHostMsg_Request;
struct ResourceMsg_RequestCompleteData;
namespace blink {
@@ -35,37 +38,44 @@ struct RedirectInfo;
namespace content {
class RequestPeer;
class ResourceDispatcherDelegate;
-class ResourceLoaderBridge;
+class ResourceRequestBody;
class ThreadedDataProvider;
struct ResourceResponseInfo;
struct RequestInfo;
struct ResourceResponseHead;
struct SiteIsolationResponseMetaData;
+struct SyncLoadResponse;
-// This class serves as a communication interface between the
-// ResourceDispatcherHost in the browser process and the ResourceLoaderBridge in
-// the child process. It can be used from any child process.
+// This class serves as a communication interface to the ResourceDispatcherHost
+// in the browser process. It can be used from any child process.
+// Virtual methods are for tests.
class CONTENT_EXPORT ResourceDispatcher : public IPC::Listener {
public:
- explicit ResourceDispatcher(IPC::Sender* sender);
+ ResourceDispatcher(
+ IPC::Sender* sender,
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner);
~ResourceDispatcher() override;
// IPC::Listener implementation.
bool OnMessageReceived(const IPC::Message& message) override;
- // Creates a ResourceLoaderBridge for this type of dispatcher, this is so
- // this can be tested regardless of the ResourceLoaderBridge::Create
- // implementation. Virtual for tests.
- virtual ResourceLoaderBridge* CreateBridge(const RequestInfo& request_info);
-
- // Adds a request from the |pending_requests_| list, returning the new
- // requests' ID.
- int AddPendingRequest(RequestPeer* callback,
- ResourceType resource_type,
- int origin_pid,
- const GURL& frame_origin,
- const GURL& request_url,
- bool download_to_file);
+ // Call this method to load the resource synchronously (i.e., in one shot).
+ // This is an alternative to the StartAsync method. Be warned that this method
+ // will block the calling thread until the resource is fully downloaded or an
+ // error occurs. It could block the calling thread for a long time, so only
+ // use this if you really need it! There is also no way for the caller to
+ // interrupt this method. Errors are reported via the status field of the
+ // response parameter.
+ void StartSync(const RequestInfo& request_info,
+ ResourceRequestBody* request_body,
+ SyncLoadResponse* response);
+
+ // Call this method to initiate the request. If this method succeeds, then
+ // the peer's methods will be called asynchronously to report various events.
+ // Returns the request id.
+ virtual int StartAsync(const RequestInfo& request_info,
+ ResourceRequestBody* request_body,
+ RequestPeer* peer);
// Removes a request from the |pending_requests_| list, returning true if the
// request was found and removed.
@@ -73,7 +83,7 @@ class CONTENT_EXPORT ResourceDispatcher : public IPC::Listener {
// Cancels a request in the |pending_requests_| list. The request will be
// removed from the dispatcher as well.
- void CancelPendingRequest(int request_id);
+ virtual void Cancel(int request_id);
// Toggles the is_deferred attribute for the specified request.
void SetDefersLoading(int request_id, bool value);
@@ -88,7 +98,19 @@ class CONTENT_EXPORT ResourceDispatcher : public IPC::Listener {
bool AttachThreadedDataReceiver(
int request_id, blink::WebThreadedDataReceiver* threaded_data_receiver);
- IPC::Sender* message_sender() const { return message_sender_; }
+ // If we have a ThreadedDataProvider attached, an OnRequestComplete message
+ // will get bounced via the background thread and then passed to this function
+ // to resume processing.
+ void CompletedRequestAfterBackgroundThreadFlush(
+ int request_id,
+ const ResourceMsg_RequestCompleteData& request_complete_data,
+ const base::TimeTicks& renderer_completion_time);
+
+ void set_message_sender(IPC::Sender* sender) {
+ DCHECK(sender);
+ DCHECK(pending_requests_.empty());
+ message_sender_ = sender;
+ }
// This does not take ownership of the delegate. It is expected that the
// delegate have a longer lifetime than the ResourceDispatcher.
@@ -101,6 +123,11 @@ class CONTENT_EXPORT ResourceDispatcher : public IPC::Listener {
io_timestamp_ = io_timestamp;
}
+ void SetMainThreadTaskRunner(
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner) {
+ main_thread_task_runner_ = main_thread_task_runner;
+ }
+
private:
friend class ResourceDispatcherTest;
@@ -205,6 +232,11 @@ class CONTENT_EXPORT ResourceDispatcher : public IPC::Listener {
// for use on deferred message queues that are no longer needed.
static void ReleaseResourcesInMessageQueue(MessageQueue* queue);
+ scoped_ptr<ResourceHostMsg_Request> CreateRequest(
+ const RequestInfo& request_info,
+ ResourceRequestBody* request_body,
+ GURL* frame_origin);
+
IPC::Sender* message_sender_;
// All pending requests issued to the host
@@ -215,6 +247,8 @@ class CONTENT_EXPORT ResourceDispatcher : public IPC::Listener {
// IO thread timestamp for ongoing IPC message.
base::TimeTicks io_timestamp_;
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
+
base::WeakPtrFactory<ResourceDispatcher> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ResourceDispatcher);
diff --git a/chromium/content/child/resource_dispatcher_unittest.cc b/chromium/content/child/resource_dispatcher_unittest.cc
index 434433eced7..e0938d1aad6 100644
--- a/chromium/content/child/resource_dispatcher_unittest.cc
+++ b/chromium/content/child/resource_dispatcher_unittest.cc
@@ -15,7 +15,6 @@
#include "content/child/request_extra_data.h"
#include "content/child/request_info.h"
#include "content/child/resource_dispatcher.h"
-#include "content/child/resource_loader_bridge.h"
#include "content/common/appcache_interfaces.h"
#include "content/common/resource_messages.h"
#include "content/common/service_worker/service_worker_types.h"
@@ -41,7 +40,7 @@ static const char kTestRedirectHeaders[] =
// to the reference data.
class TestRequestPeer : public RequestPeer {
public:
- TestRequestPeer(ResourceLoaderBridge* bridge)
+ TestRequestPeer(ResourceDispatcher* dispatcher)
: follow_redirects_(true),
defer_on_redirect_(false),
seen_redirects_(0),
@@ -50,16 +49,19 @@ class TestRequestPeer : public RequestPeer {
total_encoded_data_length_(0),
total_downloaded_data_length_(0),
complete_(false),
- bridge_(bridge) {
+ dispatcher_(dispatcher),
+ request_id_(0) {
}
+ void set_request_id(int request_id) { request_id_ = request_id; }
+
void OnUploadProgress(uint64 position, uint64 size) override {}
bool OnReceivedRedirect(const net::RedirectInfo& redirect_info,
const ResourceResponseInfo& info) override {
++seen_redirects_;
if (defer_on_redirect_)
- bridge_->SetDefersLoading(true);
+ dispatcher_->SetDefersLoading(request_id_, true);
return follow_redirects_;
}
@@ -67,7 +69,7 @@ class TestRequestPeer : public RequestPeer {
EXPECT_FALSE(received_response_);
received_response_ = true;
if (cancel_on_receive_response_)
- bridge_->Cancel();
+ dispatcher_->Cancel(request_id_);
}
void OnDownloadedData(int len, int encoded_data_length) override {
@@ -144,7 +146,8 @@ class TestRequestPeer : public RequestPeer {
bool complete_;
- ResourceLoaderBridge* bridge_;
+ ResourceDispatcher* dispatcher_;
+ int request_id_;
DISALLOW_COPY_AND_ASSIGN(TestRequestPeer);
};
@@ -152,7 +155,7 @@ class TestRequestPeer : public RequestPeer {
// Sets up the message sender override for the unit test.
class ResourceDispatcherTest : public testing::Test, public IPC::Sender {
public:
- ResourceDispatcherTest() : dispatcher_(this) {}
+ ResourceDispatcherTest() : dispatcher_(this, message_loop_.task_runner()) {}
~ResourceDispatcherTest() override {
STLDeleteContainerPairSecondPointers(shared_memory_map_.begin(),
@@ -183,60 +186,60 @@ class ResourceDispatcherTest : public testing::Test, public IPC::Sender {
ADD_FAILURE() << "Expected ResourceHostMsg_RequestResource message";
return -1;
}
- ResourceHostMsg_Request request = params.c;
+ ResourceHostMsg_Request request = get<2>(params);
EXPECT_EQ(kTestPageUrl, request.url.spec());
message_queue_.erase(message_queue_.begin());
- return params.b;
+ return get<1>(params);
}
void ConsumeFollowRedirect(int expected_request_id) {
ASSERT_FALSE(message_queue_.empty());
- Tuple1<int> args;
+ Tuple<int> args;
ASSERT_EQ(ResourceHostMsg_FollowRedirect::ID, message_queue_[0].type());
ASSERT_TRUE(ResourceHostMsg_FollowRedirect::Read(
&message_queue_[0], &args));
- EXPECT_EQ(expected_request_id, args.a);
+ EXPECT_EQ(expected_request_id, get<0>(args));
message_queue_.erase(message_queue_.begin());
}
void ConsumeDataReceived_ACK(int expected_request_id) {
ASSERT_FALSE(message_queue_.empty());
- Tuple1<int> args;
+ Tuple<int> args;
ASSERT_EQ(ResourceHostMsg_DataReceived_ACK::ID, message_queue_[0].type());
ASSERT_TRUE(ResourceHostMsg_DataReceived_ACK::Read(
&message_queue_[0], &args));
- EXPECT_EQ(expected_request_id, args.a);
+ EXPECT_EQ(expected_request_id, get<0>(args));
message_queue_.erase(message_queue_.begin());
}
void ConsumeDataDownloaded_ACK(int expected_request_id) {
ASSERT_FALSE(message_queue_.empty());
- Tuple1<int> args;
+ Tuple<int> args;
ASSERT_EQ(ResourceHostMsg_DataDownloaded_ACK::ID, message_queue_[0].type());
ASSERT_TRUE(ResourceHostMsg_DataDownloaded_ACK::Read(
&message_queue_[0], &args));
- EXPECT_EQ(expected_request_id, args.a);
+ EXPECT_EQ(expected_request_id, get<0>(args));
message_queue_.erase(message_queue_.begin());
}
void ConsumeReleaseDownloadedFile(int expected_request_id) {
ASSERT_FALSE(message_queue_.empty());
- Tuple1<int> args;
+ Tuple<int> args;
ASSERT_EQ(ResourceHostMsg_ReleaseDownloadedFile::ID,
message_queue_[0].type());
ASSERT_TRUE(ResourceHostMsg_ReleaseDownloadedFile::Read(
&message_queue_[0], &args));
- EXPECT_EQ(expected_request_id, args.a);
+ EXPECT_EQ(expected_request_id, get<0>(args));
message_queue_.erase(message_queue_.begin());
}
void ConsumeCancelRequest(int expected_request_id) {
ASSERT_FALSE(message_queue_.empty());
- Tuple1<int> args;
+ Tuple<int> args;
ASSERT_EQ(ResourceHostMsg_CancelRequest::ID, message_queue_[0].type());
ASSERT_TRUE(ResourceHostMsg_CancelRequest::Read(
&message_queue_[0], &args));
- EXPECT_EQ(expected_request_id, args.a);
+ EXPECT_EQ(expected_request_id, get<0>(args));
message_queue_.erase(message_queue_.begin());
}
@@ -306,42 +309,34 @@ class ResourceDispatcherTest : public testing::Test, public IPC::Sender {
ResourceMsg_RequestComplete(request_id, request_complete_data)));
}
- ResourceLoaderBridge* CreateBridge() {
- return CreateBridgeInternal(false);
- }
+ RequestInfo* CreateRequestInfo(bool download_to_file) {
+ RequestInfo* request_info = new RequestInfo();
+ request_info->method = "GET";
+ request_info->url = GURL(kTestPageUrl);
+ request_info->first_party_for_cookies = GURL(kTestPageUrl);
+ request_info->referrer = Referrer();
+ request_info->headers = std::string();
+ request_info->load_flags = 0;
+ request_info->requestor_pid = 0;
+ request_info->request_type = RESOURCE_TYPE_SUB_RESOURCE;
+ request_info->appcache_host_id = kAppCacheNoHostId;
+ request_info->should_reset_appcache = false;
+ request_info->routing_id = 0;
+ request_info->download_to_file = download_to_file;
+ RequestExtraData extra_data;
- ResourceLoaderBridge* CreateBridgeForDownloadToFile() {
- return CreateBridgeInternal(true);
+ return request_info;
}
ResourceDispatcher* dispatcher() { return &dispatcher_; }
private:
- ResourceLoaderBridge* CreateBridgeInternal(bool download_to_file) {
- RequestInfo request_info;
- request_info.method = "GET";
- request_info.url = GURL(kTestPageUrl);
- request_info.first_party_for_cookies = GURL(kTestPageUrl);
- request_info.referrer = GURL();
- request_info.headers = std::string();
- request_info.load_flags = 0;
- request_info.requestor_pid = 0;
- request_info.request_type = RESOURCE_TYPE_SUB_RESOURCE;
- request_info.appcache_host_id = kAppCacheNoHostId;
- request_info.routing_id = 0;
- request_info.download_to_file = download_to_file;
- RequestExtraData extra_data;
- request_info.extra_data = &extra_data;
-
- return dispatcher_.CreateBridge(request_info);
- }
-
// Map of request IDs to shared memory.
std::map<int, base::SharedMemory*> shared_memory_map_;
std::vector<IPC::Message> message_queue_;
- ResourceDispatcher dispatcher_;
base::MessageLoop message_loop_;
+ ResourceDispatcher dispatcher_;
};
// Does a simple request and tests that the correct data is received. Simulates
@@ -351,10 +346,11 @@ TEST_F(ResourceDispatcherTest, RoundTrip) {
const size_t kFirstReceiveSize = 2;
ASSERT_LT(kFirstReceiveSize, strlen(kTestPageContents));
- scoped_ptr<ResourceLoaderBridge> bridge(CreateBridge());
- TestRequestPeer peer(bridge.get());
+ scoped_ptr<RequestInfo> request_info(CreateRequestInfo(false));
+ TestRequestPeer peer(dispatcher());
+ int request_id = dispatcher()->StartAsync(*request_info.get(), NULL, &peer);
+ peer.set_request_id(request_id);
- EXPECT_TRUE(bridge->Start(&peer));
int id = ConsumeRequestResource();
EXPECT_EQ(0u, queued_messages());
@@ -382,14 +378,18 @@ TEST_F(ResourceDispatcherTest, RoundTrip) {
TEST_F(ResourceDispatcherTest, MultipleRequests) {
const char kTestPageContents2[] = "Not kTestPageContents";
- scoped_ptr<ResourceLoaderBridge> bridge1(CreateBridge());
- TestRequestPeer peer1(bridge1.get());
- scoped_ptr<ResourceLoaderBridge> bridge2(CreateBridge());
- TestRequestPeer peer2(bridge2.get());
+ scoped_ptr<RequestInfo> request_info1(CreateRequestInfo(false));
+ TestRequestPeer peer1(dispatcher());
+ int request_id1 = dispatcher()->StartAsync(
+ *request_info1.get(), NULL, &peer1);
+ peer1.set_request_id(request_id1);
+ scoped_ptr<RequestInfo> request_info2(CreateRequestInfo(false));
+ TestRequestPeer peer2(dispatcher());
+ int request_id2 = dispatcher()->StartAsync(
+ *request_info1.get(), NULL, &peer2);
+ peer2.set_request_id(request_id2);
- EXPECT_TRUE(bridge1->Start(&peer1));
int id1 = ConsumeRequestResource();
- EXPECT_TRUE(bridge2->Start(&peer2));
int id2 = ConsumeRequestResource();
EXPECT_EQ(0u, queued_messages());
@@ -422,15 +422,16 @@ TEST_F(ResourceDispatcherTest, MultipleRequests) {
// Tests that the cancel method prevents other messages from being received.
TEST_F(ResourceDispatcherTest, Cancel) {
- scoped_ptr<ResourceLoaderBridge> bridge(CreateBridge());
- TestRequestPeer peer(bridge.get());
+ scoped_ptr<RequestInfo> request_info(CreateRequestInfo(false));
+ TestRequestPeer peer(dispatcher());
+ int request_id = dispatcher()->StartAsync(*request_info.get(), NULL, &peer);
+ peer.set_request_id(request_id);
- EXPECT_TRUE(bridge->Start(&peer));
int id = ConsumeRequestResource();
EXPECT_EQ(0u, queued_messages());
// Cancel the request.
- bridge->Cancel();
+ dispatcher()->Cancel(request_id);
ConsumeCancelRequest(id);
// Any future messages related to the request should be ignored.
@@ -447,11 +448,12 @@ TEST_F(ResourceDispatcherTest, Cancel) {
// Tests that calling cancel during a callback works as expected.
TEST_F(ResourceDispatcherTest, CancelDuringCallback) {
- scoped_ptr<ResourceLoaderBridge> bridge(CreateBridge());
- TestRequestPeer peer(bridge.get());
+ scoped_ptr<RequestInfo> request_info(CreateRequestInfo(false));
+ TestRequestPeer peer(dispatcher());
+ int request_id = dispatcher()->StartAsync(*request_info.get(), NULL, &peer);
+ peer.set_request_id(request_id);
peer.set_cancel_on_receive_response(true);
- EXPECT_TRUE(bridge->Start(&peer));
int id = ConsumeRequestResource();
EXPECT_EQ(0u, queued_messages());
@@ -472,10 +474,11 @@ TEST_F(ResourceDispatcherTest, CancelDuringCallback) {
// Checks that redirects work as expected.
TEST_F(ResourceDispatcherTest, Redirect) {
- scoped_ptr<ResourceLoaderBridge> bridge(CreateBridge());
- TestRequestPeer peer(bridge.get());
+ scoped_ptr<RequestInfo> request_info(CreateRequestInfo(false));
+ TestRequestPeer peer(dispatcher());
+ int request_id = dispatcher()->StartAsync(*request_info.get(), NULL, &peer);
+ peer.set_request_id(request_id);
- EXPECT_TRUE(bridge->Start(&peer));
int id = ConsumeRequestResource();
NotifyReceivedRedirect(id);
@@ -503,11 +506,12 @@ TEST_F(ResourceDispatcherTest, Redirect) {
// Tests that that cancelling during a redirect method prevents other messages
// from being received.
TEST_F(ResourceDispatcherTest, CancelDuringRedirect) {
- scoped_ptr<ResourceLoaderBridge> bridge(CreateBridge());
- TestRequestPeer peer(bridge.get());
+ scoped_ptr<RequestInfo> request_info(CreateRequestInfo(false));
+ TestRequestPeer peer(dispatcher());
+ int request_id = dispatcher()->StartAsync(*request_info.get(), NULL, &peer);
+ peer.set_request_id(request_id);
peer.set_follow_redirects(false);
- EXPECT_TRUE(bridge->Start(&peer));
int id = ConsumeRequestResource();
EXPECT_EQ(0u, queued_messages());
@@ -533,14 +537,15 @@ TEST_F(ResourceDispatcherTest, CancelDuringRedirect) {
// Checks that deferring a request delays messages until it's resumed.
TEST_F(ResourceDispatcherTest, Defer) {
- scoped_ptr<ResourceLoaderBridge> bridge(CreateBridge());
- TestRequestPeer peer(bridge.get());
+ scoped_ptr<RequestInfo> request_info(CreateRequestInfo(false));
+ TestRequestPeer peer(dispatcher());
+ int request_id = dispatcher()->StartAsync(*request_info.get(), NULL, &peer);
+ peer.set_request_id(request_id);
- EXPECT_TRUE(bridge->Start(&peer));
int id = ConsumeRequestResource();
EXPECT_EQ(0u, queued_messages());
- bridge->SetDefersLoading(true);
+ dispatcher()->SetDefersLoading(request_id, true);
NotifyReceivedResponse(id);
NotifySetDataBuffer(id, strlen(kTestPageContents));
NotifyDataReceived(id, kTestPageContents);
@@ -554,7 +559,7 @@ TEST_F(ResourceDispatcherTest, Defer) {
EXPECT_EQ(0, peer.seen_redirects());
// Resuming the request should asynchronously unleash the deferred messages.
- bridge->SetDefersLoading(false);
+ dispatcher()->SetDefersLoading(request_id, false);
base::RunLoop().RunUntilIdle();
ConsumeDataReceived_ACK(id);
@@ -567,11 +572,12 @@ TEST_F(ResourceDispatcherTest, Defer) {
// Checks that deferring a request during a redirect delays messages until it's
// resumed.
TEST_F(ResourceDispatcherTest, DeferOnRedirect) {
- scoped_ptr<ResourceLoaderBridge> bridge(CreateBridge());
- TestRequestPeer peer(bridge.get());
+ scoped_ptr<RequestInfo> request_info(CreateRequestInfo(false));
+ TestRequestPeer peer(dispatcher());
+ int request_id = dispatcher()->StartAsync(*request_info.get(), NULL, &peer);
+ peer.set_request_id(request_id);
peer.set_defer_on_redirect(true);
- EXPECT_TRUE(bridge->Start(&peer));
int id = ConsumeRequestResource();
EXPECT_EQ(0u, queued_messages());
@@ -591,7 +597,7 @@ TEST_F(ResourceDispatcherTest, DeferOnRedirect) {
EXPECT_EQ(1, peer.seen_redirects());
// Resuming the request should asynchronously unleash the deferred messages.
- bridge->SetDefersLoading(false);
+ dispatcher()->SetDefersLoading(request_id, false);
base::RunLoop().RunUntilIdle();
ConsumeFollowRedirect(id);
@@ -606,16 +612,17 @@ TEST_F(ResourceDispatcherTest, DeferOnRedirect) {
// Checks that a deferred request that's cancelled doesn't receive any messages.
TEST_F(ResourceDispatcherTest, CancelDeferredRequest) {
- scoped_ptr<ResourceLoaderBridge> bridge(CreateBridge());
- TestRequestPeer peer(bridge.get());
+ scoped_ptr<RequestInfo> request_info(CreateRequestInfo(false));
+ TestRequestPeer peer(dispatcher());
+ int request_id = dispatcher()->StartAsync(*request_info.get(), NULL, &peer);
+ peer.set_request_id(request_id);
- EXPECT_TRUE(bridge->Start(&peer));
int id = ConsumeRequestResource();
EXPECT_EQ(0u, queued_messages());
- bridge->SetDefersLoading(true);
+ dispatcher()->SetDefersLoading(request_id, true);
NotifyReceivedRedirect(id);
- bridge->Cancel();
+ dispatcher()->Cancel(request_id);
ConsumeCancelRequest(id);
NotifyRequestComplete(id, 0);
@@ -629,12 +636,13 @@ TEST_F(ResourceDispatcherTest, CancelDeferredRequest) {
}
TEST_F(ResourceDispatcherTest, DownloadToFile) {
- scoped_ptr<ResourceLoaderBridge> bridge(CreateBridgeForDownloadToFile());
- TestRequestPeer peer(bridge.get());
+ scoped_ptr<RequestInfo> request_info(CreateRequestInfo(true));
+ TestRequestPeer peer(dispatcher());
+ int request_id = dispatcher()->StartAsync(*request_info.get(), NULL, &peer);
+ peer.set_request_id(request_id);
const int kDownloadedIncrement = 100;
const int kEncodedIncrement = 50;
- EXPECT_TRUE(bridge->Start(&peer));
int id = ConsumeRequestResource();
EXPECT_EQ(0u, queued_messages());
@@ -659,7 +667,7 @@ TEST_F(ResourceDispatcherTest, DownloadToFile) {
EXPECT_TRUE(peer.complete());
EXPECT_EQ(0u, queued_messages());
- bridge.reset();
+ dispatcher()->RemovePendingRequest(request_id);
ConsumeReleaseDownloadedFile(id);
EXPECT_EQ(0u, queued_messages());
EXPECT_EQ(expected_total_downloaded_length,
@@ -669,10 +677,11 @@ TEST_F(ResourceDispatcherTest, DownloadToFile) {
// Make sure that when a download to file is cancelled, the file is destroyed.
TEST_F(ResourceDispatcherTest, CancelDownloadToFile) {
- scoped_ptr<ResourceLoaderBridge> bridge(CreateBridgeForDownloadToFile());
- TestRequestPeer peer(bridge.get());
+ scoped_ptr<RequestInfo> request_info(CreateRequestInfo(true));
+ TestRequestPeer peer(dispatcher());
+ int request_id = dispatcher()->StartAsync(*request_info.get(), NULL, &peer);
+ peer.set_request_id(request_id);
- EXPECT_TRUE(bridge->Start(&peer));
int id = ConsumeRequestResource();
EXPECT_EQ(0u, queued_messages());
@@ -681,13 +690,9 @@ TEST_F(ResourceDispatcherTest, CancelDownloadToFile) {
EXPECT_TRUE(peer.received_response());
// Cancelling the request deletes the file.
- bridge->Cancel();
+ dispatcher()->Cancel(request_id);
ConsumeCancelRequest(id);
ConsumeReleaseDownloadedFile(id);
-
- // Deleting the bridge shouldn't send another message to delete the file.
- bridge.reset();
- EXPECT_EQ(0u, queued_messages());
}
TEST_F(ResourceDispatcherTest, Cookies) {
@@ -707,8 +712,9 @@ class TimeConversionTest : public ResourceDispatcherTest,
}
void PerformTest(const ResourceResponseHead& response_head) {
- scoped_ptr<ResourceLoaderBridge> bridge(CreateBridge());
- bridge->Start(this);
+ scoped_ptr<RequestInfo> request_info(CreateRequestInfo(false));
+ TestRequestPeer peer(dispatcher());
+ dispatcher()->StartAsync(*request_info.get(), NULL, &peer);
dispatcher()->OnMessageReceived(
ResourceMsg_ReceivedResponse(0, response_head));
diff --git a/chromium/content/child/resource_loader_bridge.cc b/chromium/content/child/resource_loader_bridge.cc
deleted file mode 100644
index dd68ccbbcc6..00000000000
--- a/chromium/content/child/resource_loader_bridge.cc
+++ /dev/null
@@ -1,13 +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/child/resource_loader_bridge.h"
-
-namespace content {
-
-ResourceLoaderBridge::ResourceLoaderBridge() {}
-
-ResourceLoaderBridge::~ResourceLoaderBridge() {}
-
-} // namespace content
diff --git a/chromium/content/child/resource_loader_bridge.h b/chromium/content/child/resource_loader_bridge.h
deleted file mode 100644
index 759f832737b..00000000000
--- a/chromium/content/child/resource_loader_bridge.h
+++ /dev/null
@@ -1,92 +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.
-//
-// The intent of this file is to provide a type-neutral abstraction between
-// Chrome and WebKit for resource loading. This pure-virtual interface is
-// implemented by the embedder.
-//
-// One of these objects will be created by WebKit for each request. WebKit
-// will own the pointer to the bridge, and will delete it when the request is
-// no longer needed.
-//
-// In turn, the bridge's owner on the WebKit end will implement the
-// RequestPeer interface, which we will use to communicate notifications
-// back.
-
-#ifndef CONTENT_CHILD_RESOURCE_LOADER_BRIDGE_H_
-#define CONTENT_CHILD_RESOURCE_LOADER_BRIDGE_H_
-
-#include "base/macros.h"
-#include "content/common/content_export.h"
-#include "net/base/request_priority.h"
-
-namespace blink {
-class WebThreadedDataReceiver;
-}
-
-namespace content {
-
-class RequestPeer;
-class ResourceRequestBody;
-struct SyncLoadResponse;
-
-// TODO(tfarina): Refactor code that uses this class. This shouldn't be needed
-// now that it lives in content/.
-class CONTENT_EXPORT ResourceLoaderBridge {
- public:
- // use BlinkPlatformImpl::CreateResourceLoader() for construction, but
- // anybody can delete at any time, INCLUDING during processing of callbacks.
- virtual ~ResourceLoaderBridge();
-
- // Call this method before calling Start() to set the request body.
- // May only be used with HTTP(S) POST requests.
- virtual void SetRequestBody(ResourceRequestBody* request_body) = 0;
-
- // Call this method to initiate the request. If this method succeeds, then
- // the peer's methods will be called asynchronously to report various events.
- virtual bool Start(RequestPeer* peer) = 0;
-
- // Call this method to cancel a request that is in progress. This method
- // causes the request to immediately transition into the 'done' state. The
- // OnCompletedRequest method will be called asynchronously; this assumes
- // the peer is still valid.
- virtual void Cancel() = 0;
-
- // Call this method to suspend or resume a load that is in progress. This
- // method may only be called after a successful call to the Start method.
- virtual void SetDefersLoading(bool value) = 0;
-
- // Call this method when the priority of the requested resource changes after
- // Start() has been called. This method may only be called after a successful
- // call to the Start method.
- virtual void DidChangePriority(net::RequestPriority new_priority,
- int intra_priority_value) = 0;
-
- // Call this method to attach a data receiver which will receive resource data
- // on its own thread.
- virtual bool AttachThreadedDataReceiver(
- blink::WebThreadedDataReceiver* threaded_data_receiver) = 0;
-
- // Call this method to load the resource synchronously (i.e., in one shot).
- // This is an alternative to the Start method. Be warned that this method
- // will block the calling thread until the resource is fully downloaded or an
- // error occurs. It could block the calling thread for a long time, so only
- // use this if you really need it! There is also no way for the caller to
- // interrupt this method. Errors are reported via the status field of the
- // response parameter.
- virtual void SyncLoad(SyncLoadResponse* response) = 0;
-
- protected:
- // Construction must go through BlinkPlatformImpl::CreateResourceLoader().
- // For HTTP(S) POST requests, the AppendDataToUpload and AppendFileToUpload
- // methods may be called to construct the body of the request.
- ResourceLoaderBridge();
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ResourceLoaderBridge);
-};
-
-} // namespace content
-
-#endif // CONTENT_CHILD_RESOURCE_LOADER_BRIDGE_H_
diff --git a/chromium/content/child/resource_scheduling_filter.cc b/chromium/content/child/resource_scheduling_filter.cc
new file mode 100644
index 00000000000..843cd8713f4
--- /dev/null
+++ b/chromium/content/child/resource_scheduling_filter.cc
@@ -0,0 +1,45 @@
+// 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/child/resource_scheduling_filter.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "content/child/resource_dispatcher.h"
+#include "ipc/ipc_message.h"
+#include "ipc/ipc_message_start.h"
+
+namespace content {
+
+ResourceSchedulingFilter::ResourceSchedulingFilter(
+ const scoped_refptr<base::SingleThreadTaskRunner>& main_thread_task_runner,
+ ResourceDispatcher* resource_dispatcher)
+ : main_thread_task_runner_(main_thread_task_runner),
+ resource_dispatcher_(resource_dispatcher),
+ weak_ptr_factory_(this) {
+ DCHECK(main_thread_task_runner_.get());
+ DCHECK(resource_dispatcher_);
+}
+
+ResourceSchedulingFilter::~ResourceSchedulingFilter() {
+}
+
+bool ResourceSchedulingFilter::OnMessageReceived(const IPC::Message& message) {
+ main_thread_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&ResourceSchedulingFilter::DispatchMessage,
+ weak_ptr_factory_.GetWeakPtr(), message));
+ return true;
+}
+
+bool ResourceSchedulingFilter::GetSupportedMessageClasses(
+ std::vector<uint32>* supported_message_classes) const {
+ supported_message_classes->push_back(ResourceMsgStart);
+ return true;
+}
+
+void ResourceSchedulingFilter::DispatchMessage(const IPC::Message& message) {
+ resource_dispatcher_->OnMessageReceived(message);
+}
+
+} // namespace content
diff --git a/chromium/content/child/resource_scheduling_filter.h b/chromium/content/child/resource_scheduling_filter.h
new file mode 100644
index 00000000000..7ea73c90724
--- /dev/null
+++ b/chromium/content/child/resource_scheduling_filter.h
@@ -0,0 +1,46 @@
+// 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_CHILD_RESOURCE_SCHEDULING_FILTER_H_
+#define CONTENT_CHILD_RESOURCE_SCHEDULING_FILTER_H_
+
+#include "base/containers/hash_tables.h"
+#include "base/memory/weak_ptr.h"
+#include "base/single_thread_task_runner.h"
+#include "content/common/content_export.h"
+#include "ipc/message_filter.h"
+
+namespace content {
+class ResourceDispatcher;
+
+// This filter is used to dispatch resource messages on a specific
+// SingleThreadTaskRunner to facilitate task scheduling.
+class CONTENT_EXPORT ResourceSchedulingFilter : public IPC::MessageFilter {
+ public:
+ ResourceSchedulingFilter(const scoped_refptr<base::SingleThreadTaskRunner>&
+ main_thread_task_runner,
+ ResourceDispatcher* resource_dispatcher);
+
+ // IPC::MessageFilter overrides:
+ bool OnMessageReceived(const IPC::Message& message) override;
+
+ bool GetSupportedMessageClasses(
+ std::vector<uint32>* supported_message_classes) const override;
+
+ protected:
+ ~ResourceSchedulingFilter() override;
+
+ void DispatchMessage(const IPC::Message& message);
+
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
+ ResourceDispatcher* resource_dispatcher_; // NOT OWNED
+ base::WeakPtrFactory<ResourceSchedulingFilter> weak_ptr_factory_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ResourceSchedulingFilter);
+};
+
+} // namespace content
+
+#endif // CONTENT_CHILD_RESOURCE_SCHEDULING_FILTER_H_
diff --git a/chromium/content/child/runtime_features.cc b/chromium/content/child/runtime_features.cc
index 891e22b295e..69f560447e2 100644
--- a/chromium/content/child/runtime_features.cc
+++ b/chromium/content/child/runtime_features.cc
@@ -4,11 +4,16 @@
#include "content/child/runtime_features.h"
+#include <vector>
+
#include "base/command_line.h"
#include "base/metrics/field_trial.h"
+#include "base/strings/string_split.h"
+#include "components/scheduler/common/scheduler_switches.h"
#include "content/common/content_switches_internal.h"
#include "content/public/common/content_switches.h"
#include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
+#include "ui/gl/gl_switches.h"
#include "ui/native_theme/native_theme_switches.h"
#if defined(OS_ANDROID)
@@ -25,6 +30,9 @@ using blink::WebRuntimeFeatures;
namespace content {
static void SetRuntimeFeatureDefaultsForPlatform() {
+ // Enable non-standard "apple-touch-icon" and "apple-touch-icon-precomposed".
+ WebRuntimeFeatures::enableTouchIconLoading(true);
+
#if defined(OS_ANDROID)
// MSE/EME implementation needs Android MediaCodec API.
if (!media::MediaCodecBridge::IsAvailable()) {
@@ -44,13 +52,10 @@ static void SetRuntimeFeatureDefaultsForPlatform() {
// Android does not have support for PagePopup
WebRuntimeFeatures::enablePagePopup(false);
- // Android does not yet support the Web Notification API. crbug.com/115320
- WebRuntimeFeatures::enableNotifications(false);
// Android does not yet support SharedWorker. crbug.com/154571
WebRuntimeFeatures::enableSharedWorker(false);
// Android does not yet support NavigatorContentUtils.
WebRuntimeFeatures::enableNavigatorContentUtils(false);
- WebRuntimeFeatures::enableTouchIconLoading(true);
WebRuntimeFeatures::enableOrientationEvent(true);
WebRuntimeFeatures::enableFastMobileScrolling(true);
WebRuntimeFeatures::enableMediaCapture(true);
@@ -60,6 +65,9 @@ static void SetRuntimeFeatureDefaultsForPlatform() {
// the feature via experimental web platform features.
if (base::FieldTrialList::FindFullName("NavigationTransitions") == "Enabled")
WebRuntimeFeatures::enableNavigationTransitions(true);
+ // Android won't be able to reliably support non-persistent notifications, the
+ // intended behavior for which is in flux by itself.
+ WebRuntimeFeatures::enableNotificationConstructor(false);
#else
WebRuntimeFeatures::enableNavigatorContentUtils(true);
#endif // defined(OS_ANDROID)
@@ -89,34 +97,23 @@ void SetRuntimeFeaturesDefaultsAndUpdateFromArgs(
if (command_line.HasSwitch(switches::kDisableDatabases))
WebRuntimeFeatures::enableDatabase(false);
- if (command_line.HasSwitch(switches::kDisableApplicationCache))
- WebRuntimeFeatures::enableApplicationCache(false);
-
- if (command_line.HasSwitch(switches::kDisableBlinkScheduler))
+ if (command_line.HasSwitch(scheduler::switches::kDisableBlinkScheduler))
WebRuntimeFeatures::enableBlinkScheduler(false);
- if (command_line.HasSwitch(switches::kDisableLocalStorage))
- WebRuntimeFeatures::enableLocalStorage(false);
-
- if (command_line.HasSwitch(switches::kDisableSessionStorage))
- WebRuntimeFeatures::enableSessionStorage(false);
-
if (command_line.HasSwitch(switches::kDisableMediaSource))
WebRuntimeFeatures::enableMediaSource(false);
+ if (command_line.HasSwitch(switches::kDisableNotifications)) {
+ WebRuntimeFeatures::enableNotifications(false);
+
+ // Chrome's Push Messaging implementation relies on Web Notifications.
+ WebRuntimeFeatures::enablePushMessaging(false);
+ }
+
if (command_line.HasSwitch(switches::kDisableSharedWorkers))
WebRuntimeFeatures::enableSharedWorker(false);
#if defined(OS_ANDROID)
- if (command_line.HasSwitch(switches::kDisableWebRTC))
- WebRuntimeFeatures::enablePeerConnection(false);
-
- if (!command_line.HasSwitch(switches::kEnableSpeechRecognition))
- WebRuntimeFeatures::enableScriptedSpeech(false);
-
- if (command_line.HasSwitch(switches::kEnableExperimentalWebPlatformFeatures))
- WebRuntimeFeatures::enableNotifications(true);
-
// WebAudio is enabled by default on ARM and X86, if the MediaCodec
// API is available.
WebRuntimeFeatures::enableWebAudio(
@@ -127,33 +124,32 @@ void SetRuntimeFeaturesDefaultsAndUpdateFromArgs(
WebRuntimeFeatures::enableWebAudio(false);
#endif
- if (command_line.HasSwitch(switches::kEnableEncryptedMedia))
- WebRuntimeFeatures::enableEncryptedMedia(true);
+ if (command_line.HasSwitch(switches::kDisableSpeechAPI))
+ WebRuntimeFeatures::enableScriptedSpeech(false);
+
+ if (command_line.HasSwitch(switches::kDisableEncryptedMedia))
+ WebRuntimeFeatures::enableEncryptedMedia(false);
if (command_line.HasSwitch(switches::kDisablePrefixedEncryptedMedia))
WebRuntimeFeatures::enablePrefixedEncryptedMedia(false);
- if (command_line.HasSwitch(switches::kEnableWebMIDI))
- WebRuntimeFeatures::enableWebMIDI(true);
-
if (command_line.HasSwitch(switches::kDisableFileSystem))
WebRuntimeFeatures::enableFileSystem(false);
if (command_line.HasSwitch(switches::kEnableExperimentalCanvasFeatures))
WebRuntimeFeatures::enableExperimentalCanvasFeatures(true);
- if (command_line.HasSwitch(switches::kEnableAcceleratedJpegDecoding))
+ if (!command_line.HasSwitch(switches::kDisableAcceleratedJpegDecoding))
WebRuntimeFeatures::enableDecodeToYUV(true);
- if (command_line.HasSwitch(switches::kDisableDisplayList2dCanvas)) {
- WebRuntimeFeatures::enableDisplayList2dCanvas(false);
- } else if (command_line.HasSwitch(switches::kEnableDisplayList2dCanvas)) {
+ if (command_line.HasSwitch(switches::kEnableDisplayList2dCanvas))
WebRuntimeFeatures::enableDisplayList2dCanvas(true);
- } else {
- WebRuntimeFeatures::enableDisplayList2dCanvas(
- base::FieldTrialList::FindFullName("DisplayList2dCanvas") == "Enabled"
- );
- }
+
+ if (command_line.HasSwitch(switches::kDisableDisplayList2dCanvas))
+ WebRuntimeFeatures::enableDisplayList2dCanvas(false);
+
+ if (command_line.HasSwitch(switches::kForceDisplayList2dCanvas))
+ WebRuntimeFeatures::forceDisplayList2dCanvas(true);
if (command_line.HasSwitch(switches::kEnableWebGLDraftExtensions))
WebRuntimeFeatures::enableWebGLDraftExtensions(true);
@@ -173,9 +169,6 @@ void SetRuntimeFeaturesDefaultsAndUpdateFromArgs(
if (command_line.HasSwitch(switches::kEnablePreciseMemoryInfo))
WebRuntimeFeatures::enablePreciseMemoryInfo(true);
- if (command_line.HasSwitch(switches::kEnableLayerSquashing))
- WebRuntimeFeatures::enableLayerSquashing(true);
-
if (command_line.HasSwitch(switches::kEnableNetworkInformation) ||
command_line.HasSwitch(
switches::kEnableExperimentalWebPlatformFeatures)) {
@@ -185,12 +178,55 @@ void SetRuntimeFeaturesDefaultsAndUpdateFromArgs(
if (command_line.HasSwitch(switches::kEnableCredentialManagerAPI))
WebRuntimeFeatures::enableCredentialManagerAPI(true);
- if (command_line.HasSwitch(switches::kEnableViewport))
- WebRuntimeFeatures::enableCSSViewport(true);
-
if (command_line.HasSwitch(switches::kDisableSVG1DOM)) {
WebRuntimeFeatures::enableSVG1DOM(false);
}
+
+ if (command_line.HasSwitch(switches::kReducedReferrerGranularity))
+ WebRuntimeFeatures::enableReducedReferrerGranularity(true);
+
+ if (command_line.HasSwitch(switches::kEnablePushMessagePayload))
+ WebRuntimeFeatures::enablePushMessagingData(true);
+
+ if (command_line.HasSwitch(switches::kDisablePermissionsAPI))
+ WebRuntimeFeatures::enablePermissionsAPI(false);
+
+ // Delete "StaleWhileRevalidate" line from chrome_browser_field_trials.cc
+ // when this experiment is done.
+ if (base::FieldTrialList::FindFullName("StaleWhileRevalidate") == "Enabled" ||
+ command_line.HasSwitch(switches::kEnableStaleWhileRevalidate))
+ WebRuntimeFeatures::enableStaleWhileRevalidateCacheControl(true);
+
+ if (command_line.HasSwitch(switches::kDisableV8IdleTasks))
+ WebRuntimeFeatures::enableV8IdleTasks(false);
+ else
+ WebRuntimeFeatures::enableV8IdleTasks(true);
+
+ if (command_line.HasSwitch(switches::kEnableUnsafeES3APIs))
+ WebRuntimeFeatures::enableUnsafeES3APIs(true);
+
+ // Enable explicitly enabled features, and then disable explicitly disabled
+ // ones.
+ if (command_line.HasSwitch(switches::kEnableBlinkFeatures)) {
+ std::vector<std::string> enabled_features;
+ base::SplitString(
+ command_line.GetSwitchValueASCII(switches::kEnableBlinkFeatures), ',',
+ &enabled_features);
+ for (const std::string& feature : enabled_features) {
+ WebRuntimeFeatures::enableFeatureFromString(
+ blink::WebString::fromLatin1(feature), true);
+ }
+ }
+ if (command_line.HasSwitch(switches::kDisableBlinkFeatures)) {
+ std::vector<std::string> disabled_features;
+ base::SplitString(
+ command_line.GetSwitchValueASCII(switches::kDisableBlinkFeatures), ',',
+ &disabled_features);
+ for (const std::string& feature : disabled_features) {
+ WebRuntimeFeatures::enableFeatureFromString(
+ blink::WebString::fromLatin1(feature), false);
+ }
+ }
}
} // namespace content
diff --git a/chromium/content/child/service_worker/service_worker_dispatcher.cc b/chromium/content/child/service_worker/service_worker_dispatcher.cc
index 7e38a3efd8e..dfbcfc18f6c 100644
--- a/chromium/content/child/service_worker/service_worker_dispatcher.cc
+++ b/chromium/content/child/service_worker/service_worker_dispatcher.cc
@@ -4,11 +4,11 @@
#include "content/child/service_worker/service_worker_dispatcher.h"
-#include "base/debug/trace_event.h"
#include "base/lazy_instance.h"
#include "base/stl_util.h"
#include "base/threading/thread_local.h"
-#include "content/child/child_thread.h"
+#include "base/trace_event/trace_event.h"
+#include "content/child/child_thread_impl.h"
#include "content/child/service_worker/service_worker_handle_reference.h"
#include "content/child/service_worker/service_worker_provider_context.h"
#include "content/child/service_worker/service_worker_registration_handle_reference.h"
@@ -17,8 +17,11 @@
#include "content/child/thread_safe_sender.h"
#include "content/child/webmessageportchannel_impl.h"
#include "content/common/service_worker/service_worker_messages.h"
+#include "content/common/service_worker/service_worker_types.h"
#include "content/public/common/url_utils.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerClientsInfo.h"
#include "third_party/WebKit/public/platform/WebServiceWorkerProviderClient.h"
+#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/web/WebSecurityOrigin.h"
using blink::WebServiceWorkerError;
@@ -54,6 +57,8 @@ ServiceWorkerDispatcher::~ServiceWorkerDispatcher() {
void ServiceWorkerDispatcher::OnMessageReceived(const IPC::Message& msg) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(ServiceWorkerDispatcher, msg)
+ IPC_MESSAGE_HANDLER(ServiceWorkerMsg_AssociateRegistrationWithServiceWorker,
+ OnAssociateRegistrationWithServiceWorker)
IPC_MESSAGE_HANDLER(ServiceWorkerMsg_AssociateRegistration,
OnAssociateRegistration)
IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DisassociateRegistration,
@@ -63,6 +68,8 @@ void ServiceWorkerDispatcher::OnMessageReceived(const IPC::Message& msg) {
OnUnregistered)
IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DidGetRegistration,
OnDidGetRegistration)
+ IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DidGetRegistrationForReady,
+ OnDidGetRegistrationForReady)
IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerRegistrationError,
OnRegistrationError)
IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerUnregistrationError,
@@ -99,8 +106,11 @@ void ServiceWorkerDispatcher::RegisterServiceWorker(
script_url.possibly_invalid_spec().size() > GetMaxURLChars()) {
scoped_ptr<WebServiceWorkerRegistrationCallbacks>
owned_callbacks(callbacks);
- scoped_ptr<WebServiceWorkerError> error(new WebServiceWorkerError(
- WebServiceWorkerError::ErrorTypeSecurity, "URL too long"));
+ std::string error_message(kServiceWorkerRegisterErrorPrefix);
+ error_message += "The provided scriptURL or scope is too long.";
+ scoped_ptr<WebServiceWorkerError> error(
+ new WebServiceWorkerError(WebServiceWorkerError::ErrorTypeSecurity,
+ blink::WebString::fromUTF8(error_message)));
callbacks->onError(error.release());
return;
}
@@ -124,8 +134,11 @@ void ServiceWorkerDispatcher::UnregisterServiceWorker(
if (pattern.possibly_invalid_spec().size() > GetMaxURLChars()) {
scoped_ptr<WebServiceWorkerUnregistrationCallbacks>
owned_callbacks(callbacks);
- scoped_ptr<WebServiceWorkerError> error(new WebServiceWorkerError(
- WebServiceWorkerError::ErrorTypeSecurity, "URL too long"));
+ std::string error_message(kServiceWorkerUnregisterErrorPrefix);
+ error_message += "The provided scope is too long.";
+ scoped_ptr<WebServiceWorkerError> error(
+ new WebServiceWorkerError(WebServiceWorkerError::ErrorTypeSecurity,
+ blink::WebString::fromUTF8(error_message)));
callbacks->onError(error.release());
return;
}
@@ -148,8 +161,11 @@ void ServiceWorkerDispatcher::GetRegistration(
if (document_url.possibly_invalid_spec().size() > GetMaxURLChars()) {
scoped_ptr<WebServiceWorkerRegistrationCallbacks>
owned_callbacks(callbacks);
- scoped_ptr<WebServiceWorkerError> error(new WebServiceWorkerError(
- WebServiceWorkerError::ErrorTypeSecurity, "URL too long"));
+ std::string error_message(kServiceWorkerGetRegistrationErrorPrefix);
+ error_message += "The provided documentURL is too long.";
+ scoped_ptr<WebServiceWorkerError> error(
+ new WebServiceWorkerError(WebServiceWorkerError::ErrorTypeSecurity,
+ blink::WebString::fromUTF8(error_message)));
callbacks->onError(error.release());
return;
}
@@ -163,6 +179,17 @@ void ServiceWorkerDispatcher::GetRegistration(
CurrentWorkerId(), request_id, provider_id, document_url));
}
+void ServiceWorkerDispatcher::GetRegistrationForReady(
+ int provider_id,
+ WebServiceWorkerGetRegistrationForReadyCallbacks* callbacks) {
+ int request_id = get_for_ready_callbacks_.Add(callbacks);
+ TRACE_EVENT_ASYNC_BEGIN0("ServiceWorker",
+ "ServiceWorkerDispatcher::GetRegistrationForReady",
+ request_id);
+ thread_safe_sender_->Send(new ServiceWorkerHostMsg_GetRegistrationForReady(
+ CurrentWorkerId(), request_id, provider_id));
+}
+
void ServiceWorkerDispatcher::AddProviderContext(
ServiceWorkerProviderContext* provider_context) {
DCHECK(provider_context);
@@ -182,18 +209,18 @@ void ServiceWorkerDispatcher::RemoveProviderContext(
worker_to_provider_.erase(provider_context->controller_handle_id());
}
-void ServiceWorkerDispatcher::AddScriptClient(
+void ServiceWorkerDispatcher::AddProviderClient(
int provider_id,
blink::WebServiceWorkerProviderClient* client) {
DCHECK(client);
- DCHECK(!ContainsKey(script_clients_, provider_id));
- script_clients_[provider_id] = client;
+ DCHECK(!ContainsKey(provider_clients_, provider_id));
+ provider_clients_[provider_id] = client;
}
-void ServiceWorkerDispatcher::RemoveScriptClient(int provider_id) {
+void ServiceWorkerDispatcher::RemoveProviderClient(int provider_id) {
// This could be possibly called multiple times to ensure termination.
- if (ContainsKey(script_clients_, provider_id))
- script_clients_.erase(provider_id);
+ if (ContainsKey(provider_clients_, provider_id))
+ provider_clients_.erase(provider_id);
}
ServiceWorkerDispatcher*
@@ -251,27 +278,10 @@ WebServiceWorkerImpl* ServiceWorkerDispatcher::GetServiceWorker(
}
WebServiceWorkerRegistrationImpl*
-ServiceWorkerDispatcher::FindServiceWorkerRegistration(
- const ServiceWorkerRegistrationObjectInfo& info,
- bool adopt_handle) {
- RegistrationObjectMap::iterator registration =
- registrations_.find(info.handle_id);
- if (registration == registrations_.end())
- return NULL;
- if (adopt_handle) {
- // We are instructed to adopt a handle but we already have one, so
- // adopt and destroy a handle ref.
- ServiceWorkerRegistrationHandleReference::Adopt(
- info, thread_safe_sender_.get());
- }
- return registration->second;
-}
-
-WebServiceWorkerRegistrationImpl*
ServiceWorkerDispatcher::CreateServiceWorkerRegistration(
const ServiceWorkerRegistrationObjectInfo& info,
bool adopt_handle) {
- DCHECK(!FindServiceWorkerRegistration(info, adopt_handle));
+ DCHECK(!ContainsKey(registrations_, info.handle_id));
if (info.handle_id == kInvalidServiceWorkerRegistrationHandleId)
return NULL;
@@ -286,6 +296,27 @@ ServiceWorkerDispatcher::CreateServiceWorkerRegistration(
return new WebServiceWorkerRegistrationImpl(handle_ref.Pass());
}
+// We can assume that this message handler is called before the worker context
+// starts because script loading happens after this association.
+// TODO(nhiroki): This association information could be pushed into
+// EmbeddedWorkerMsg_StartWorker message and handed over to the worker thread
+// without a lock in ServiceWorkerProviderContext.
+void ServiceWorkerDispatcher::OnAssociateRegistrationWithServiceWorker(
+ int thread_id,
+ int provider_id,
+ const ServiceWorkerRegistrationObjectInfo& info,
+ const ServiceWorkerVersionAttributes& attrs) {
+ DCHECK_EQ(kDocumentMainThreadId, thread_id);
+
+ ProviderContextMap::iterator context = provider_contexts_.find(provider_id);
+ if (context == provider_contexts_.end())
+ return;
+ context->second->OnAssociateRegistration(info, attrs);
+
+ // We don't have to add entries into |worker_to_provider_| because state
+ // change events for the workers will be notified on the worker thread.
+}
+
void ServiceWorkerDispatcher::OnAssociateRegistration(
int thread_id,
int provider_id,
@@ -309,11 +340,11 @@ void ServiceWorkerDispatcher::OnDisassociateRegistration(
ProviderContextMap::iterator provider = provider_contexts_.find(provider_id);
if (provider == provider_contexts_.end())
return;
- provider->second->OnDisassociateRegistration();
worker_to_provider_.erase(provider->second->installing_handle_id());
worker_to_provider_.erase(provider->second->waiting_handle_id());
worker_to_provider_.erase(provider->second->active_handle_id());
worker_to_provider_.erase(provider->second->controller_handle_id());
+ provider->second->OnDisassociateRegistration();
}
void ServiceWorkerDispatcher::OnRegistered(
@@ -385,6 +416,32 @@ void ServiceWorkerDispatcher::OnDidGetRegistration(
pending_get_registration_callbacks_.Remove(request_id);
}
+void ServiceWorkerDispatcher::OnDidGetRegistrationForReady(
+ int thread_id,
+ int request_id,
+ const ServiceWorkerRegistrationObjectInfo& info,
+ const ServiceWorkerVersionAttributes& attrs) {
+ TRACE_EVENT_ASYNC_STEP_INTO0(
+ "ServiceWorker",
+ "ServiceWorkerDispatcher::GetRegistrationForReady",
+ request_id,
+ "OnDidGetRegistrationForReady");
+ TRACE_EVENT_ASYNC_END0("ServiceWorker",
+ "ServiceWorkerDispatcher::GetRegistrationForReady",
+ request_id);
+ WebServiceWorkerGetRegistrationForReadyCallbacks* callbacks =
+ get_for_ready_callbacks_.Lookup(request_id);
+ DCHECK(callbacks);
+ if (!callbacks)
+ return;
+
+ WebServiceWorkerRegistrationImpl* registration = NULL;
+ DCHECK(info.handle_id != kInvalidServiceWorkerHandleId);
+ registration = FindOrCreateRegistration(info, attrs);
+ callbacks->onSuccess(registration);
+ get_for_ready_callbacks_.Remove(request_id);
+}
+
void ServiceWorkerDispatcher::OnRegistrationError(
int thread_id,
int request_id,
@@ -481,177 +538,80 @@ void ServiceWorkerDispatcher::OnSetVersionAttributes(
int provider_id,
int registration_handle_id,
int changed_mask,
- const ServiceWorkerVersionAttributes& attributes) {
+ const ServiceWorkerVersionAttributes& attrs) {
TRACE_EVENT1("ServiceWorker",
"ServiceWorkerDispatcher::OnSetVersionAttributes",
"Thread ID", thread_id);
- ChangedVersionAttributesMask mask(changed_mask);
- if (mask.installing_changed()) {
- SetInstallingServiceWorker(provider_id,
- registration_handle_id,
- attributes.installing);
- }
- if (mask.waiting_changed()) {
- SetWaitingServiceWorker(provider_id,
- registration_handle_id,
- attributes.waiting);
- }
- if (mask.active_changed()) {
- SetActiveServiceWorker(provider_id,
- registration_handle_id,
- attributes.active);
- SetReadyRegistration(provider_id, registration_handle_id);
- }
-}
-void ServiceWorkerDispatcher::OnUpdateFound(
- int thread_id,
- const ServiceWorkerRegistrationObjectInfo& info) {
- TRACE_EVENT0("ServiceWorker",
- "ServiceWorkerDispatcher::OnUpdateFound");
- RegistrationObjectMap::iterator found = registrations_.find(info.handle_id);
- if (found != registrations_.end())
- found->second->OnUpdateFound();
-}
-
-void ServiceWorkerDispatcher::SetInstallingServiceWorker(
- int provider_id,
- int registration_handle_id,
- const ServiceWorkerObjectInfo& info) {
+ ChangedVersionAttributesMask mask(changed_mask);
ProviderContextMap::iterator provider = provider_contexts_.find(provider_id);
if (provider != provider_contexts_.end() &&
provider->second->registration_handle_id() == registration_handle_id) {
- int existing_installing_id = provider->second->installing_handle_id();
- if (existing_installing_id != info.handle_id &&
- existing_installing_id != kInvalidServiceWorkerHandleId) {
- WorkerToProviderMap::iterator associated_provider =
- worker_to_provider_.find(existing_installing_id);
- DCHECK(associated_provider != worker_to_provider_.end());
- DCHECK(associated_provider->second->provider_id() == provider_id);
- worker_to_provider_.erase(associated_provider);
+ if (mask.installing_changed()) {
+ worker_to_provider_.erase(provider->second->installing_handle_id());
+ if (attrs.installing.handle_id != kInvalidServiceWorkerHandleId)
+ worker_to_provider_[attrs.installing.handle_id] = provider->second;
}
- provider->second->OnSetInstallingServiceWorker(
- registration_handle_id, info);
- if (info.handle_id != kInvalidServiceWorkerHandleId)
- worker_to_provider_[info.handle_id] = provider->second;
- }
-
- RegistrationObjectMap::iterator found =
- registrations_.find(registration_handle_id);
- if (found != registrations_.end()) {
- // Populate the .installing field with the new worker object.
- found->second->SetInstalling(GetServiceWorker(info, false));
- }
-}
-
-void ServiceWorkerDispatcher::SetWaitingServiceWorker(
- int provider_id,
- int registration_handle_id,
- const ServiceWorkerObjectInfo& info) {
- ProviderContextMap::iterator provider = provider_contexts_.find(provider_id);
- if (provider != provider_contexts_.end() &&
- provider->second->registration_handle_id() == registration_handle_id) {
- int existing_waiting_id = provider->second->waiting_handle_id();
- if (existing_waiting_id != info.handle_id &&
- existing_waiting_id != kInvalidServiceWorkerHandleId) {
- WorkerToProviderMap::iterator associated_provider =
- worker_to_provider_.find(existing_waiting_id);
- DCHECK(associated_provider != worker_to_provider_.end());
- DCHECK(associated_provider->second->provider_id() == provider_id);
- worker_to_provider_.erase(associated_provider);
+ if (mask.waiting_changed()) {
+ worker_to_provider_.erase(provider->second->waiting_handle_id());
+ if (attrs.waiting.handle_id != kInvalidServiceWorkerHandleId)
+ worker_to_provider_[attrs.waiting.handle_id] = provider->second;
}
- provider->second->OnSetWaitingServiceWorker(registration_handle_id, info);
- if (info.handle_id != kInvalidServiceWorkerHandleId)
- worker_to_provider_[info.handle_id] = provider->second;
- }
-
- RegistrationObjectMap::iterator found =
- registrations_.find(registration_handle_id);
- if (found != registrations_.end()) {
- // Populate the .waiting field with the new worker object.
- found->second->SetWaiting(GetServiceWorker(info, false));
- }
-}
-
-void ServiceWorkerDispatcher::SetActiveServiceWorker(
- int provider_id,
- int registration_handle_id,
- const ServiceWorkerObjectInfo& info) {
- ProviderContextMap::iterator provider = provider_contexts_.find(provider_id);
- if (provider != provider_contexts_.end() &&
- provider->second->registration_handle_id() == registration_handle_id) {
- int existing_active_id = provider->second->active_handle_id();
- if (existing_active_id != info.handle_id &&
- existing_active_id != kInvalidServiceWorkerHandleId) {
- WorkerToProviderMap::iterator associated_provider =
- worker_to_provider_.find(existing_active_id);
- DCHECK(associated_provider != worker_to_provider_.end());
- DCHECK(associated_provider->second->provider_id() == provider_id);
- worker_to_provider_.erase(associated_provider);
+ if (mask.active_changed()) {
+ worker_to_provider_.erase(provider->second->active_handle_id());
+ if (attrs.active.handle_id != kInvalidServiceWorkerHandleId)
+ worker_to_provider_[attrs.active.handle_id] = provider->second;
}
- provider->second->OnSetActiveServiceWorker(registration_handle_id, info);
- if (info.handle_id != kInvalidServiceWorkerHandleId)
- worker_to_provider_[info.handle_id] = provider->second;
+ provider->second->SetVersionAttributes(mask, attrs);
}
RegistrationObjectMap::iterator found =
registrations_.find(registration_handle_id);
if (found != registrations_.end()) {
- // Populate the .active field with the new worker object.
- found->second->SetActive(GetServiceWorker(info, false));
+ // Populate the version fields (eg. .installing) with new worker objects.
+ if (mask.installing_changed())
+ found->second->SetInstalling(GetServiceWorker(attrs.installing, false));
+ if (mask.waiting_changed())
+ found->second->SetWaiting(GetServiceWorker(attrs.waiting, false));
+ if (mask.active_changed())
+ found->second->SetActive(GetServiceWorker(attrs.active, false));
}
}
-void ServiceWorkerDispatcher::SetReadyRegistration(
- int provider_id,
+void ServiceWorkerDispatcher::OnUpdateFound(
+ int thread_id,
int registration_handle_id) {
- ProviderContextMap::iterator provider = provider_contexts_.find(provider_id);
- if (provider == provider_contexts_.end() ||
- provider->second->registration_handle_id() != registration_handle_id ||
- provider->second->active_handle_id() == kInvalidServiceWorkerHandleId) {
- return;
- }
-
- ScriptClientMap::iterator client = script_clients_.find(provider_id);
- if (client == script_clients_.end())
- return;
-
- ServiceWorkerRegistrationObjectInfo info =
- provider->second->registration()->info();
- WebServiceWorkerRegistrationImpl* registration =
- FindServiceWorkerRegistration(info, false);
- if (!registration) {
- registration = CreateServiceWorkerRegistration(info, false);
- ServiceWorkerVersionAttributes attrs =
- provider->second->GetVersionAttributes();
- registration->SetInstalling(GetServiceWorker(attrs.installing, false));
- registration->SetWaiting(GetServiceWorker(attrs.waiting, false));
- registration->SetActive(GetServiceWorker(attrs.active, false));
- }
-
- // Resolve the .ready promise with the registration object.
- client->second->setReadyRegistration(registration);
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerDispatcher::OnUpdateFound");
+ RegistrationObjectMap::iterator found =
+ registrations_.find(registration_handle_id);
+ if (found != registrations_.end())
+ found->second->OnUpdateFound();
}
void ServiceWorkerDispatcher::OnSetControllerServiceWorker(
int thread_id,
int provider_id,
- const ServiceWorkerObjectInfo& info) {
+ const ServiceWorkerObjectInfo& info,
+ bool should_notify_controllerchange) {
TRACE_EVENT2("ServiceWorker",
"ServiceWorkerDispatcher::OnSetControllerServiceWorker",
"Thread ID", thread_id,
"Provider ID", provider_id);
+
ProviderContextMap::iterator provider = provider_contexts_.find(provider_id);
if (provider != provider_contexts_.end()) {
- provider->second->OnSetControllerServiceWorker(
- provider->second->registration_handle_id(), info);
- worker_to_provider_[info.handle_id] = provider->second;
+ worker_to_provider_.erase(provider->second->controller_handle_id());
+ if (info.handle_id != kInvalidServiceWorkerHandleId)
+ worker_to_provider_[info.handle_id] = provider->second;
+ provider->second->OnSetControllerServiceWorker(info);
}
- ScriptClientMap::iterator found = script_clients_.find(provider_id);
- if (found != script_clients_.end()) {
+ ProviderClientMap::iterator found = provider_clients_.find(provider_id);
+ if (found != provider_clients_.end()) {
// Populate the .controller field with the new worker object.
- found->second->setController(GetServiceWorker(info, false));
+ found->second->setController(GetServiceWorker(info, false),
+ should_notify_controllerchange);
}
}
@@ -659,31 +619,26 @@ void ServiceWorkerDispatcher::OnPostMessage(
int thread_id,
int provider_id,
const base::string16& message,
- const std::vector<int>& sent_message_port_ids,
+ const std::vector<TransferredMessagePort>& sent_message_ports,
const std::vector<int>& new_routing_ids) {
// Make sure we're on the main document thread. (That must be the only
// thread we get this message)
- DCHECK(ChildThread::current());
+ DCHECK(ChildThreadImpl::current());
TRACE_EVENT1("ServiceWorker",
"ServiceWorkerDispatcher::OnPostMessage",
"Thread ID", thread_id);
- ScriptClientMap::iterator found = script_clients_.find(provider_id);
- if (found == script_clients_.end()) {
+ ProviderClientMap::iterator found = provider_clients_.find(provider_id);
+ if (found == provider_clients_.end()) {
// For now we do no queueing for messages sent to nonexistent / unattached
// client.
return;
}
- std::vector<WebMessagePortChannelImpl*> ports;
- if (!sent_message_port_ids.empty()) {
- ports.resize(sent_message_port_ids.size());
- for (size_t i = 0; i < sent_message_port_ids.size(); ++i) {
- ports[i] = new WebMessagePortChannelImpl(
- new_routing_ids[i], sent_message_port_ids[i],
- base::MessageLoopProxy::current());
- }
- }
+ blink::WebMessagePortChannelArray ports =
+ WebMessagePortChannelImpl::CreatePorts(sent_message_ports,
+ new_routing_ids,
+ base::MessageLoopProxy::current());
found->second->dispatchMessageEvent(message, ports);
}
@@ -716,23 +671,25 @@ WebServiceWorkerRegistrationImpl*
ServiceWorkerDispatcher::FindOrCreateRegistration(
const ServiceWorkerRegistrationObjectInfo& info,
const ServiceWorkerVersionAttributes& attrs) {
- WebServiceWorkerRegistrationImpl* registration =
- FindServiceWorkerRegistration(info, true);
- if (!registration) {
- registration = CreateServiceWorkerRegistration(info, true);
- registration->SetInstalling(GetServiceWorker(attrs.installing, true));
- registration->SetWaiting(GetServiceWorker(attrs.waiting, true));
- registration->SetActive(GetServiceWorker(attrs.active, true));
- } else {
- // |registration| must already have version attributes, so adopt and destroy
- // handle refs for them.
- ServiceWorkerHandleReference::Adopt(
- attrs.installing, thread_safe_sender_.get());
- ServiceWorkerHandleReference::Adopt(
- attrs.waiting, thread_safe_sender_.get());
- ServiceWorkerHandleReference::Adopt(
- attrs.active, thread_safe_sender_.get());
+ RegistrationObjectMap::iterator found = registrations_.find(info.handle_id);
+ if (found != registrations_.end()) {
+ ServiceWorkerRegistrationHandleReference::Adopt(info,
+ thread_safe_sender_.get());
+ ServiceWorkerHandleReference::Adopt(attrs.installing,
+ thread_safe_sender_.get());
+ ServiceWorkerHandleReference::Adopt(attrs.waiting,
+ thread_safe_sender_.get());
+ ServiceWorkerHandleReference::Adopt(attrs.active,
+ thread_safe_sender_.get());
+ return found->second;
}
+
+ bool adopt_handle = true;
+ WebServiceWorkerRegistrationImpl* registration =
+ CreateServiceWorkerRegistration(info, adopt_handle);
+ registration->SetInstalling(GetServiceWorker(attrs.installing, adopt_handle));
+ registration->SetWaiting(GetServiceWorker(attrs.waiting, adopt_handle));
+ registration->SetActive(GetServiceWorker(attrs.active, adopt_handle));
return registration;
}
diff --git a/chromium/content/child/service_worker/service_worker_dispatcher.h b/chromium/content/child/service_worker/service_worker_dispatcher.h
index 2d01452fa69..28b9f4f9867 100644
--- a/chromium/content/child/service_worker/service_worker_dispatcher.h
+++ b/chromium/content/child/service_worker/service_worker_dispatcher.h
@@ -36,11 +36,13 @@ class WebServiceWorkerRegistrationImpl;
struct ServiceWorkerObjectInfo;
struct ServiceWorkerRegistrationObjectInfo;
struct ServiceWorkerVersionAttributes;
+struct TransferredMessagePort;
// This class manages communication with the browser process about
// registration of the service worker, exposed to renderer and worker
// scripts through methods like navigator.registerServiceWorker().
-class ServiceWorkerDispatcher : public WorkerTaskRunner::Observer {
+class CONTENT_EXPORT ServiceWorkerDispatcher
+ : public WorkerTaskRunner::Observer {
public:
typedef blink::WebServiceWorkerProvider::WebServiceWorkerRegistrationCallbacks
WebServiceWorkerRegistrationCallbacks;
@@ -50,6 +52,9 @@ class ServiceWorkerDispatcher : public WorkerTaskRunner::Observer {
typedef
blink::WebServiceWorkerProvider::WebServiceWorkerGetRegistrationCallbacks
WebServiceWorkerGetRegistrationCallbacks;
+ typedef blink::WebServiceWorkerProvider::
+ WebServiceWorkerGetRegistrationForReadyCallbacks
+ WebServiceWorkerGetRegistrationForReadyCallbacks;
explicit ServiceWorkerDispatcher(ThreadSafeSender* thread_safe_sender);
~ServiceWorkerDispatcher() override;
@@ -74,6 +79,10 @@ class ServiceWorkerDispatcher : public WorkerTaskRunner::Observer {
const GURL& document_url,
WebServiceWorkerRegistrationCallbacks* callbacks);
+ void GetRegistrationForReady(
+ int provider_id,
+ WebServiceWorkerGetRegistrationForReadyCallbacks* callbacks);
+
// Called when a new provider context for a document is created. Usually
// this happens when a new document is being loaded, and is called much
// earlier than AddScriptClient.
@@ -83,9 +92,9 @@ class ServiceWorkerDispatcher : public WorkerTaskRunner::Observer {
// Called when navigator.serviceWorker is instantiated or detached
// for a document whose provider can be identified by |provider_id|.
- void AddScriptClient(int provider_id,
- blink::WebServiceWorkerProviderClient* client);
- void RemoveScriptClient(int provider_id);
+ void AddProviderClient(int provider_id,
+ blink::WebServiceWorkerProviderClient* client);
+ void RemoveProviderClient(int provider_id);
// If an existing WebServiceWorkerImpl exists for the Service
// Worker, it is returned; otherwise a WebServiceWorkerImpl is
@@ -104,14 +113,6 @@ class ServiceWorkerDispatcher : public WorkerTaskRunner::Observer {
const ServiceWorkerObjectInfo& info,
bool adopt_handle);
- // Finds a WebServiceWorkerRegistrationImpl for the specified registration.
- // If it's not found, returns NULL. If |adopt_handle| is true,
- // a ServiceWorkerRegistrationHandleReference will be adopted for the
- // registration.
- WebServiceWorkerRegistrationImpl* FindServiceWorkerRegistration(
- const ServiceWorkerRegistrationObjectInfo& info,
- bool adopt_handle);
-
// Creates a WebServiceWorkerRegistrationImpl for the specified registration
// and transfers its ownership to the caller. If |adopt_handle| is true, a
// ServiceWorkerRegistrationHandleReference will be adopted for the
@@ -136,19 +137,29 @@ class ServiceWorkerDispatcher : public WorkerTaskRunner::Observer {
IDMapOwnPointer> UnregistrationCallbackMap;
typedef IDMap<WebServiceWorkerGetRegistrationCallbacks,
IDMapOwnPointer> GetRegistrationCallbackMap;
- typedef std::map<int, blink::WebServiceWorkerProviderClient*> ScriptClientMap;
+ typedef IDMap<WebServiceWorkerGetRegistrationForReadyCallbacks,
+ IDMapOwnPointer> GetRegistrationForReadyCallbackMap;
+
+ typedef std::map<int, blink::WebServiceWorkerProviderClient*>
+ ProviderClientMap;
typedef std::map<int, ServiceWorkerProviderContext*> ProviderContextMap;
- typedef std::map<int, WebServiceWorkerImpl*> WorkerObjectMap;
typedef std::map<int, ServiceWorkerProviderContext*> WorkerToProviderMap;
+ typedef std::map<int, WebServiceWorkerImpl*> WorkerObjectMap;
typedef std::map<int, WebServiceWorkerRegistrationImpl*>
RegistrationObjectMap;
+ friend class ServiceWorkerDispatcherTest;
friend class WebServiceWorkerImpl;
friend class WebServiceWorkerRegistrationImpl;
// WorkerTaskRunner::Observer implementation.
void OnWorkerRunLoopStopped() override;
+ void OnAssociateRegistrationWithServiceWorker(
+ int thread_id,
+ int provider_id,
+ const ServiceWorkerRegistrationObjectInfo& info,
+ const ServiceWorkerVersionAttributes& attrs);
void OnAssociateRegistration(int thread_id,
int provider_id,
const ServiceWorkerRegistrationObjectInfo& info,
@@ -166,6 +177,11 @@ class ServiceWorkerDispatcher : public WorkerTaskRunner::Observer {
int request_id,
const ServiceWorkerRegistrationObjectInfo& info,
const ServiceWorkerVersionAttributes& attrs);
+ void OnDidGetRegistrationForReady(
+ int thread_id,
+ int request_id,
+ const ServiceWorkerRegistrationObjectInfo& info,
+ const ServiceWorkerVersionAttributes& attrs);
void OnRegistrationError(int thread_id,
int request_id,
blink::WebServiceWorkerError::ErrorType error_type,
@@ -188,31 +204,17 @@ class ServiceWorkerDispatcher : public WorkerTaskRunner::Observer {
int changed_mask,
const ServiceWorkerVersionAttributes& attributes);
void OnUpdateFound(int thread_id,
- const ServiceWorkerRegistrationObjectInfo& info);
+ int registration_handle_id);
void OnSetControllerServiceWorker(int thread_id,
int provider_id,
- const ServiceWorkerObjectInfo& info);
- void OnPostMessage(int thread_id,
- int provider_id,
- const base::string16& message,
- const std::vector<int>& sent_message_port_ids,
- const std::vector<int>& new_routing_ids);
-
- void SetInstallingServiceWorker(
- int provider_id,
- int registration_handle_id,
- const ServiceWorkerObjectInfo& info);
- void SetWaitingServiceWorker(
- int provider_id,
- int registration_handle_id,
- const ServiceWorkerObjectInfo& info);
- void SetActiveServiceWorker(
- int provider_id,
- int registration_handle_id,
- const ServiceWorkerObjectInfo& info);
- void SetReadyRegistration(
+ const ServiceWorkerObjectInfo& info,
+ bool should_notify_controllerchange);
+ void OnPostMessage(
+ int thread_id,
int provider_id,
- int registration_handle_id);
+ const base::string16& message,
+ const std::vector<TransferredMessagePort>& sent_message_ports,
+ const std::vector<int>& new_routing_ids);
// Keeps map from handle_id to ServiceWorker object.
void AddServiceWorker(int handle_id, WebServiceWorkerImpl* worker);
@@ -225,6 +227,11 @@ class ServiceWorkerDispatcher : public WorkerTaskRunner::Observer {
void RemoveServiceWorkerRegistration(
int registration_handle_id);
+ // Returns an existing registration or new one filled in with version
+ // attributes. This function assumes given |info| and |attrs| retain handle
+ // references and always adopts them.
+ // TODO(nhiroki): This assumption seems to impair readability. We could
+ // explictly pass ServiceWorker(Registration)HandleReference instead.
WebServiceWorkerRegistrationImpl* FindOrCreateRegistration(
const ServiceWorkerRegistrationObjectInfo& info,
const ServiceWorkerVersionAttributes& attrs);
@@ -232,8 +239,11 @@ class ServiceWorkerDispatcher : public WorkerTaskRunner::Observer {
RegistrationCallbackMap pending_registration_callbacks_;
UnregistrationCallbackMap pending_unregistration_callbacks_;
GetRegistrationCallbackMap pending_get_registration_callbacks_;
- ScriptClientMap script_clients_;
+ GetRegistrationForReadyCallbackMap get_for_ready_callbacks_;
+
+ ProviderClientMap provider_clients_;
ProviderContextMap provider_contexts_;
+
WorkerObjectMap service_workers_;
RegistrationObjectMap registrations_;
diff --git a/chromium/content/child/service_worker/service_worker_dispatcher_unittest.cc b/chromium/content/child/service_worker/service_worker_dispatcher_unittest.cc
new file mode 100644
index 00000000000..9b8a33a69d5
--- /dev/null
+++ b/chromium/content/child/service_worker/service_worker_dispatcher_unittest.cc
@@ -0,0 +1,219 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_loop_proxy.h"
+#include "content/child/service_worker/service_worker_dispatcher.h"
+#include "content/child/service_worker/web_service_worker_impl.h"
+#include "content/child/service_worker/web_service_worker_registration_impl.h"
+#include "content/child/thread_safe_sender.h"
+#include "content/common/service_worker/service_worker_messages.h"
+#include "content/common/service_worker/service_worker_types.h"
+#include "ipc/ipc_sync_message_filter.h"
+#include "ipc/ipc_test_sink.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+class ServiceWorkerTestSender : public ThreadSafeSender {
+ public:
+ explicit ServiceWorkerTestSender(IPC::TestSink* ipc_sink)
+ : ThreadSafeSender(nullptr, nullptr),
+ ipc_sink_(ipc_sink) {}
+
+ bool Send(IPC::Message* message) override {
+ return ipc_sink_->Send(message);
+ }
+
+ private:
+ ~ServiceWorkerTestSender() override {}
+
+ IPC::TestSink* ipc_sink_;
+
+ DISALLOW_COPY_AND_ASSIGN(ServiceWorkerTestSender);
+};
+
+class ServiceWorkerDispatcherTest : public testing::Test {
+ public:
+ ServiceWorkerDispatcherTest() {}
+
+ void SetUp() override {
+ sender_ = new ServiceWorkerTestSender(&ipc_sink_);
+ dispatcher_.reset(new ServiceWorkerDispatcher(sender_.get()));
+ }
+
+ void CreateObjectInfoAndVersionAttributes(
+ ServiceWorkerRegistrationObjectInfo* info,
+ ServiceWorkerVersionAttributes* attrs) {
+ info->handle_id = 10;
+ info->registration_id = 20;
+
+ attrs->active.handle_id = 100;
+ attrs->active.version_id = 200;
+ attrs->waiting.handle_id = 101;
+ attrs->waiting.version_id = 201;
+ attrs->installing.handle_id = 102;
+ attrs->installing.version_id = 202;
+ }
+
+ WebServiceWorkerRegistrationImpl* FindOrCreateRegistration(
+ const ServiceWorkerRegistrationObjectInfo& info,
+ const ServiceWorkerVersionAttributes& attrs) {
+ return dispatcher_->FindOrCreateRegistration(info, attrs);
+ }
+
+ bool ContainsServiceWorker(int handle_id) {
+ return ContainsKey(dispatcher_->service_workers_, handle_id);
+ }
+
+ bool ContainsRegistration(int registration_handle_id) {
+ return ContainsKey(dispatcher_->registrations_, registration_handle_id);
+ }
+
+ ServiceWorkerDispatcher* dispatcher() { return dispatcher_.get(); }
+ IPC::TestSink* ipc_sink() { return &ipc_sink_; }
+
+ private:
+ IPC::TestSink ipc_sink_;
+ scoped_ptr<ServiceWorkerDispatcher> dispatcher_;
+ scoped_refptr<ServiceWorkerTestSender> sender_;
+
+ DISALLOW_COPY_AND_ASSIGN(ServiceWorkerDispatcherTest);
+};
+
+// TODO(nhiroki): Add tests for message handlers especially to receive reference
+// counts like OnAssociateRegistration().
+TEST_F(ServiceWorkerDispatcherTest, GetServiceWorker) {
+ ServiceWorkerRegistrationObjectInfo info;
+ ServiceWorkerVersionAttributes attrs;
+ CreateObjectInfoAndVersionAttributes(&info, &attrs);
+
+ // Should return a worker object newly created with incrementing refcount.
+ bool adopt_handle = false;
+ scoped_ptr<WebServiceWorkerImpl> worker(
+ dispatcher()->GetServiceWorker(attrs.installing, adopt_handle));
+ EXPECT_TRUE(worker);
+ EXPECT_TRUE(ContainsServiceWorker(attrs.installing.handle_id));
+ EXPECT_EQ(1UL, ipc_sink()->message_count());
+ EXPECT_EQ(ServiceWorkerHostMsg_IncrementServiceWorkerRefCount::ID,
+ ipc_sink()->GetMessageAt(0)->type());
+
+ ipc_sink()->ClearMessages();
+
+ // Should return the existing worker object.
+ adopt_handle = false;
+ WebServiceWorkerImpl* existing_worker =
+ dispatcher()->GetServiceWorker(attrs.installing, adopt_handle);
+ EXPECT_EQ(worker, existing_worker);
+ EXPECT_EQ(0UL, ipc_sink()->message_count());
+
+ // Should return the existing worker object with adopting refcount.
+ adopt_handle = true;
+ existing_worker =
+ dispatcher()->GetServiceWorker(attrs.installing, adopt_handle);
+ EXPECT_EQ(worker, existing_worker);
+ ASSERT_EQ(1UL, ipc_sink()->message_count());
+ EXPECT_EQ(ServiceWorkerHostMsg_DecrementServiceWorkerRefCount::ID,
+ ipc_sink()->GetMessageAt(0)->type());
+
+ ipc_sink()->ClearMessages();
+
+ // Should return another worker object newly created with adopting refcount.
+ adopt_handle = true;
+ scoped_ptr<WebServiceWorkerImpl> another_worker(
+ dispatcher()->GetServiceWorker(attrs.waiting, adopt_handle));
+ EXPECT_NE(worker.get(), another_worker.get());
+ EXPECT_TRUE(ContainsServiceWorker(attrs.waiting.handle_id));
+ EXPECT_EQ(0UL, ipc_sink()->message_count());
+
+ // Should return nullptr when a given object info is invalid.
+ adopt_handle = false;
+ WebServiceWorkerImpl* invalid_worker =
+ dispatcher()->GetServiceWorker(ServiceWorkerObjectInfo(), adopt_handle);
+ EXPECT_FALSE(invalid_worker);
+ EXPECT_EQ(0UL, ipc_sink()->message_count());
+
+ adopt_handle = true;
+ invalid_worker =
+ dispatcher()->GetServiceWorker(ServiceWorkerObjectInfo(), adopt_handle);
+ EXPECT_FALSE(invalid_worker);
+ EXPECT_EQ(0UL, ipc_sink()->message_count());
+}
+
+TEST_F(ServiceWorkerDispatcherTest, CreateServiceWorkerRegistration) {
+ ServiceWorkerRegistrationObjectInfo info;
+ ServiceWorkerVersionAttributes attrs;
+ CreateObjectInfoAndVersionAttributes(&info, &attrs);
+
+ // Should return a registration object newly created with incrementing
+ // refcount.
+ bool adopt_handle = false;
+ scoped_ptr<WebServiceWorkerRegistrationImpl> registration(
+ dispatcher()->CreateServiceWorkerRegistration(info, adopt_handle));
+ EXPECT_TRUE(registration);
+ EXPECT_TRUE(ContainsRegistration(info.handle_id));
+ ASSERT_EQ(1UL, ipc_sink()->message_count());
+ EXPECT_EQ(ServiceWorkerHostMsg_IncrementRegistrationRefCount::ID,
+ ipc_sink()->GetMessageAt(0)->type());
+
+ registration.reset();
+ EXPECT_FALSE(ContainsRegistration(info.handle_id));
+ ipc_sink()->ClearMessages();
+
+ // Should return another registration object newly created with adopting
+ // refcount.
+ adopt_handle = true;
+ scoped_ptr<WebServiceWorkerRegistrationImpl> another_registration(
+ dispatcher()->CreateServiceWorkerRegistration(info, adopt_handle));
+ EXPECT_TRUE(another_registration);
+ EXPECT_TRUE(ContainsRegistration(info.handle_id));
+ EXPECT_EQ(0UL, ipc_sink()->message_count());
+
+ another_registration.reset();
+ ipc_sink()->ClearMessages();
+
+ // should return nullptr when a given object info is invalid.
+ adopt_handle = false;
+ scoped_ptr<WebServiceWorkerRegistrationImpl> invalid_registration(
+ dispatcher()->CreateServiceWorkerRegistration(
+ ServiceWorkerRegistrationObjectInfo(), adopt_handle));
+ EXPECT_FALSE(invalid_registration);
+ EXPECT_FALSE(ContainsRegistration(info.handle_id));
+ EXPECT_EQ(0UL, ipc_sink()->message_count());
+
+ adopt_handle = true;
+ invalid_registration.reset(dispatcher()->CreateServiceWorkerRegistration(
+ ServiceWorkerRegistrationObjectInfo(), adopt_handle));
+ EXPECT_FALSE(invalid_registration);
+ EXPECT_FALSE(ContainsRegistration(info.handle_id));
+ EXPECT_EQ(0UL, ipc_sink()->message_count());
+}
+
+TEST_F(ServiceWorkerDispatcherTest, FindOrCreateRegistration) {
+ ServiceWorkerRegistrationObjectInfo info;
+ ServiceWorkerVersionAttributes attrs;
+ CreateObjectInfoAndVersionAttributes(&info, &attrs);
+
+ // Should return a registration object newly created with adopting refcounts.
+ scoped_ptr<WebServiceWorkerRegistrationImpl> registration(
+ FindOrCreateRegistration(info, attrs));
+ EXPECT_TRUE(registration);
+ EXPECT_EQ(info.registration_id, registration->registration_id());
+ EXPECT_EQ(0UL, ipc_sink()->message_count());
+
+ // Should return the existing registration object with adopting refcounts.
+ WebServiceWorkerRegistrationImpl* existing_registration =
+ FindOrCreateRegistration(info, attrs);
+ EXPECT_EQ(registration, existing_registration);
+ ASSERT_EQ(4UL, ipc_sink()->message_count());
+ EXPECT_EQ(ServiceWorkerHostMsg_DecrementRegistrationRefCount::ID,
+ ipc_sink()->GetMessageAt(0)->type());
+ EXPECT_EQ(ServiceWorkerHostMsg_DecrementServiceWorkerRefCount::ID,
+ ipc_sink()->GetMessageAt(1)->type());
+ EXPECT_EQ(ServiceWorkerHostMsg_DecrementServiceWorkerRefCount::ID,
+ ipc_sink()->GetMessageAt(2)->type());
+ EXPECT_EQ(ServiceWorkerHostMsg_DecrementServiceWorkerRefCount::ID,
+ ipc_sink()->GetMessageAt(3)->type());
+}
+
+} // namespace content
diff --git a/chromium/content/child/service_worker/service_worker_handle_reference.h b/chromium/content/child/service_worker/service_worker_handle_reference.h
index d70d665c625..9417b0ba9da 100644
--- a/chromium/content/child/service_worker/service_worker_handle_reference.h
+++ b/chromium/content/child/service_worker/service_worker_handle_reference.h
@@ -35,7 +35,6 @@ class ServiceWorkerHandleReference {
const ServiceWorkerObjectInfo& info() const { return info_; }
int handle_id() const { return info_.handle_id; }
- const GURL& scope() const { return info_.scope; }
const GURL& url() const { return info_.url; }
blink::WebServiceWorkerState state() const { return info_.state; }
void set_state(blink::WebServiceWorkerState state) { info_.state = state; }
diff --git a/chromium/content/child/service_worker/service_worker_message_filter.cc b/chromium/content/child/service_worker/service_worker_message_filter.cc
index 72cf320084a..3568ad77e5b 100644
--- a/chromium/content/child/service_worker/service_worker_message_filter.cc
+++ b/chromium/content/child/service_worker/service_worker_message_filter.cc
@@ -4,10 +4,8 @@
#include "content/child/service_worker/service_worker_message_filter.h"
-#include "base/message_loop/message_loop_proxy.h"
#include "content/child/service_worker/service_worker_dispatcher.h"
#include "content/child/thread_safe_sender.h"
-#include "content/child/worker_thread_task_runner.h"
#include "content/common/service_worker/service_worker_messages.h"
#include "content/common/service_worker/service_worker_types.h"
#include "ipc/ipc_message_macros.h"
@@ -39,29 +37,26 @@ void SendRegistrationObjectDestroyed(
} // namespace
ServiceWorkerMessageFilter::ServiceWorkerMessageFilter(ThreadSafeSender* sender)
- : main_thread_loop_proxy_(base::MessageLoopProxy::current()),
- thread_safe_sender_(sender) {}
+ : WorkerThreadMessageFilter(sender) {
+}
ServiceWorkerMessageFilter::~ServiceWorkerMessageFilter() {}
-base::TaskRunner* ServiceWorkerMessageFilter::OverrideTaskRunnerForMessage(
- const IPC::Message& msg) {
- if (IPC_MESSAGE_CLASS(msg) != ServiceWorkerMsgStart)
- return NULL;
- int ipc_thread_id = 0;
- const bool success = PickleIterator(msg).ReadInt(&ipc_thread_id);
- DCHECK(success);
- if (!ipc_thread_id)
- return main_thread_loop_proxy_.get();
- return new WorkerThreadTaskRunner(ipc_thread_id);
+bool ServiceWorkerMessageFilter::ShouldHandleMessage(
+ const IPC::Message& msg) const {
+ return IPC_MESSAGE_CLASS(msg) == ServiceWorkerMsgStart;
}
-bool ServiceWorkerMessageFilter::OnMessageReceived(const IPC::Message& msg) {
- if (IPC_MESSAGE_CLASS(msg) != ServiceWorkerMsgStart)
- return false;
+void ServiceWorkerMessageFilter::OnFilteredMessageReceived(
+ const IPC::Message& msg) {
ServiceWorkerDispatcher::GetOrCreateThreadSpecificInstance(
- thread_safe_sender_.get())->OnMessageReceived(msg);
- return true;
+ thread_safe_sender())->OnMessageReceived(msg);
+}
+
+bool ServiceWorkerMessageFilter::GetWorkerThreadIdForMessage(
+ const IPC::Message& msg,
+ int* ipc_thread_id) {
+ return PickleIterator(msg).ReadInt(ipc_thread_id);
}
void ServiceWorkerMessageFilter::OnStaleMessageReceived(
@@ -83,13 +78,13 @@ void ServiceWorkerMessageFilter::OnStaleRegistered(
int request_id,
const ServiceWorkerRegistrationObjectInfo& info,
const ServiceWorkerVersionAttributes& attrs) {
- SendServiceWorkerObjectDestroyed(thread_safe_sender_.get(),
+ SendServiceWorkerObjectDestroyed(thread_safe_sender(),
attrs.installing.handle_id);
- SendServiceWorkerObjectDestroyed(thread_safe_sender_.get(),
+ SendServiceWorkerObjectDestroyed(thread_safe_sender(),
attrs.waiting.handle_id);
- SendServiceWorkerObjectDestroyed(thread_safe_sender_.get(),
+ SendServiceWorkerObjectDestroyed(thread_safe_sender(),
attrs.active.handle_id);
- SendRegistrationObjectDestroyed(thread_safe_sender_.get(), info.handle_id);
+ SendRegistrationObjectDestroyed(thread_safe_sender(), info.handle_id);
}
void ServiceWorkerMessageFilter::OnStaleSetVersionAttributes(
@@ -98,21 +93,22 @@ void ServiceWorkerMessageFilter::OnStaleSetVersionAttributes(
int registration_handle_id,
int changed_mask,
const ServiceWorkerVersionAttributes& attrs) {
- SendServiceWorkerObjectDestroyed(thread_safe_sender_.get(),
+ SendServiceWorkerObjectDestroyed(thread_safe_sender(),
attrs.installing.handle_id);
- SendServiceWorkerObjectDestroyed(thread_safe_sender_.get(),
+ SendServiceWorkerObjectDestroyed(thread_safe_sender(),
attrs.waiting.handle_id);
- SendServiceWorkerObjectDestroyed(thread_safe_sender_.get(),
+ SendServiceWorkerObjectDestroyed(thread_safe_sender(),
attrs.active.handle_id);
- SendRegistrationObjectDestroyed(thread_safe_sender_.get(),
- registration_handle_id);
+ // Don't have to decrement registration refcount because the sender of the
+ // SetVersionAttributes message doesn't increment it.
}
void ServiceWorkerMessageFilter::OnStaleSetControllerServiceWorker(
int thread_id,
int provider_id,
- const ServiceWorkerObjectInfo& info) {
- SendServiceWorkerObjectDestroyed(thread_safe_sender_.get(), info.handle_id);
+ const ServiceWorkerObjectInfo& info,
+ bool should_notify_controllerchange) {
+ SendServiceWorkerObjectDestroyed(thread_safe_sender(), info.handle_id);
}
} // namespace content
diff --git a/chromium/content/child/service_worker/service_worker_message_filter.h b/chromium/content/child/service_worker/service_worker_message_filter.h
index 8581f8de588..d6fdeb9bb7d 100644
--- a/chromium/content/child/service_worker/service_worker_message_filter.h
+++ b/chromium/content/child/service_worker/service_worker_message_filter.h
@@ -5,22 +5,17 @@
#ifndef CONTENT_CHILD_SERVICE_WORKER_SERVICE_WORKER_MESSAGE_FILTER_H_
#define CONTENT_CHILD_SERVICE_WORKER_SERVICE_WORKER_MESSAGE_FILTER_H_
-#include "content/child/child_message_filter.h"
+#include "content/child/worker_thread_message_filter.h"
#include "content/common/content_export.h"
-namespace base {
-class MessageLoopProxy;
-}
-
namespace content {
-class ThreadSafeSender;
struct ServiceWorkerObjectInfo;
struct ServiceWorkerRegistrationObjectInfo;
struct ServiceWorkerVersionAttributes;
class CONTENT_EXPORT ServiceWorkerMessageFilter
- : public NON_EXPORTED_BASE(ChildMessageFilter) {
+ : public NON_EXPORTED_BASE(WorkerThreadMessageFilter) {
public:
explicit ServiceWorkerMessageFilter(ThreadSafeSender* thread_safe_sender);
@@ -28,10 +23,13 @@ class CONTENT_EXPORT ServiceWorkerMessageFilter
~ServiceWorkerMessageFilter() override;
private:
- // ChildMessageFilter implementation:
- base::TaskRunner* OverrideTaskRunnerForMessage(
- const IPC::Message& msg) override;
- bool OnMessageReceived(const IPC::Message& msg) override;
+ // WorkerThreadMessageFilter:
+ bool ShouldHandleMessage(const IPC::Message& msg) const override;
+ void OnFilteredMessageReceived(const IPC::Message& msg) override;
+ bool GetWorkerThreadIdForMessage(const IPC::Message& msg,
+ int* ipc_thread_id) override;
+
+ // ChildMessageFilter:
void OnStaleMessageReceived(const IPC::Message& msg) override;
// Message handlers for stale messages.
@@ -49,10 +47,8 @@ class CONTENT_EXPORT ServiceWorkerMessageFilter
void OnStaleSetControllerServiceWorker(
int thread_id,
int provider_id,
- const ServiceWorkerObjectInfo& info);
-
- scoped_refptr<base::MessageLoopProxy> main_thread_loop_proxy_;
- scoped_refptr<ThreadSafeSender> thread_safe_sender_;
+ const ServiceWorkerObjectInfo& info,
+ bool should_notify_controllerchange);
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerMessageFilter);
};
diff --git a/chromium/content/child/service_worker/service_worker_network_provider.cc b/chromium/content/child/service_worker/service_worker_network_provider.cc
index 2f2ede6f4bf..85c20688a1f 100644
--- a/chromium/content/child/service_worker/service_worker_network_provider.cc
+++ b/chromium/content/child/service_worker/service_worker_network_provider.cc
@@ -5,7 +5,7 @@
#include "content/child/service_worker/service_worker_network_provider.h"
#include "base/atomic_sequence_num.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
#include "content/child/service_worker/service_worker_provider_context.h"
#include "content/common/service_worker/service_worker_messages.h"
@@ -35,27 +35,30 @@ ServiceWorkerNetworkProvider* ServiceWorkerNetworkProvider::FromDocumentState(
datasource_userdata->GetUserData(&kUserDataKey));
}
-ServiceWorkerNetworkProvider::ServiceWorkerNetworkProvider()
+ServiceWorkerNetworkProvider::ServiceWorkerNetworkProvider(
+ int render_frame_id,
+ ServiceWorkerProviderType provider_type)
: provider_id_(GetNextProviderId()),
context_(new ServiceWorkerProviderContext(provider_id_)) {
- if (!ChildThread::current())
+ if (!ChildThreadImpl::current())
return; // May be null in some tests.
- ChildThread::current()->Send(
- new ServiceWorkerHostMsg_ProviderCreated(provider_id_));
+ ChildThreadImpl::current()->Send(
+ new ServiceWorkerHostMsg_ProviderCreated(
+ provider_id_, render_frame_id, provider_type));
}
ServiceWorkerNetworkProvider::~ServiceWorkerNetworkProvider() {
- if (!ChildThread::current())
+ if (!ChildThreadImpl::current())
return; // May be null in some tests.
- ChildThread::current()->Send(
+ ChildThreadImpl::current()->Send(
new ServiceWorkerHostMsg_ProviderDestroyed(provider_id_));
}
void ServiceWorkerNetworkProvider::SetServiceWorkerVersionId(
int64 version_id) {
- if (!ChildThread::current())
+ if (!ChildThreadImpl::current())
return; // May be null in some tests.
- ChildThread::current()->Send(
+ ChildThreadImpl::current()->Send(
new ServiceWorkerHostMsg_SetVersionId(provider_id_, version_id));
}
diff --git a/chromium/content/child/service_worker/service_worker_network_provider.h b/chromium/content/child/service_worker/service_worker_network_provider.h
index 85030c390de..460b7b3bd9e 100644
--- a/chromium/content/child/service_worker/service_worker_network_provider.h
+++ b/chromium/content/child/service_worker/service_worker_network_provider.h
@@ -10,6 +10,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/supports_user_data.h"
#include "content/common/content_export.h"
+#include "content/common/service_worker/service_worker_types.h"
namespace content {
@@ -36,7 +37,8 @@ class CONTENT_EXPORT ServiceWorkerNetworkProvider
static ServiceWorkerNetworkProvider* FromDocumentState(
base::SupportsUserData* document_state);
- ServiceWorkerNetworkProvider();
+ ServiceWorkerNetworkProvider(int render_frame_id,
+ ServiceWorkerProviderType type);
~ServiceWorkerNetworkProvider() override;
int provider_id() const { return provider_id_; }
diff --git a/chromium/content/child/service_worker/service_worker_provider_context.cc b/chromium/content/child/service_worker/service_worker_provider_context.cc
index cb86fa56050..d8273aaef46 100644
--- a/chromium/content/child/service_worker/service_worker_provider_context.cc
+++ b/chromium/content/child/service_worker/service_worker_provider_context.cc
@@ -7,7 +7,7 @@
#include "base/bind.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/stl_util.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
#include "content/child/service_worker/service_worker_dispatcher.h"
#include "content/child/service_worker/service_worker_handle_reference.h"
#include "content/child/service_worker/service_worker_registration_handle_reference.h"
@@ -20,9 +20,9 @@ namespace content {
ServiceWorkerProviderContext::ServiceWorkerProviderContext(int provider_id)
: provider_id_(provider_id),
main_thread_loop_proxy_(base::MessageLoopProxy::current()) {
- if (!ChildThread::current())
+ if (!ChildThreadImpl::current())
return; // May be null in some tests.
- thread_safe_sender_ = ChildThread::current()->thread_safe_sender();
+ thread_safe_sender_ = ChildThreadImpl::current()->thread_safe_sender();
ServiceWorkerDispatcher* dispatcher =
ServiceWorkerDispatcher::GetOrCreateThreadSpecificInstance(
thread_safe_sender_.get());
@@ -33,53 +33,63 @@ ServiceWorkerProviderContext::ServiceWorkerProviderContext(int provider_id)
ServiceWorkerProviderContext::~ServiceWorkerProviderContext() {
if (ServiceWorkerDispatcher* dispatcher =
ServiceWorkerDispatcher::GetThreadSpecificInstance()) {
+ // Remove this context from the dispatcher living on the main thread.
dispatcher->RemoveProviderContext(this);
}
}
-ServiceWorkerHandleReference* ServiceWorkerProviderContext::installing() {
- DCHECK(main_thread_loop_proxy_->RunsTasksOnCurrentThread());
- return installing_.get();
-}
-
-ServiceWorkerHandleReference* ServiceWorkerProviderContext::waiting() {
+ServiceWorkerHandleReference* ServiceWorkerProviderContext::controller() {
DCHECK(main_thread_loop_proxy_->RunsTasksOnCurrentThread());
- return waiting_.get();
+ return controller_.get();
}
-ServiceWorkerHandleReference* ServiceWorkerProviderContext::active() {
- DCHECK(main_thread_loop_proxy_->RunsTasksOnCurrentThread());
- return active_.get();
-}
+bool ServiceWorkerProviderContext::GetRegistrationInfoAndVersionAttributes(
+ ServiceWorkerRegistrationObjectInfo* info,
+ ServiceWorkerVersionAttributes* attrs) {
+ base::AutoLock lock(lock_);
+ if (!registration_)
+ return false;
-ServiceWorkerHandleReference* ServiceWorkerProviderContext::controller() {
- DCHECK(main_thread_loop_proxy_->RunsTasksOnCurrentThread());
- return controller_.get();
+ *info = registration_->info();
+ if (installing_)
+ attrs->installing = installing_->info();
+ if (waiting_)
+ attrs->waiting = waiting_->info();
+ if (active_)
+ attrs->active = active_->info();
+ return true;
}
-ServiceWorkerRegistrationHandleReference*
-ServiceWorkerProviderContext::registration() {
+void ServiceWorkerProviderContext::SetVersionAttributes(
+ ChangedVersionAttributesMask mask,
+ const ServiceWorkerVersionAttributes& attrs) {
+ base::AutoLock lock(lock_);
DCHECK(main_thread_loop_proxy_->RunsTasksOnCurrentThread());
- return registration_.get();
-}
+ DCHECK(registration_);
-ServiceWorkerVersionAttributes
-ServiceWorkerProviderContext::GetVersionAttributes() {
- ServiceWorkerVersionAttributes attrs;
- if (installing())
- attrs.installing = installing()->info();
- if (waiting())
- attrs.waiting = waiting()->info();
- if (active())
- attrs.active = active()->info();
- return attrs;
+ if (mask.installing_changed()) {
+ installing_ = ServiceWorkerHandleReference::Adopt(
+ attrs.installing, thread_safe_sender_.get());
+ }
+ if (mask.waiting_changed()) {
+ waiting_ = ServiceWorkerHandleReference::Adopt(
+ attrs.waiting, thread_safe_sender_.get());
+ }
+ if (mask.active_changed()) {
+ active_ = ServiceWorkerHandleReference::Adopt(
+ attrs.active, thread_safe_sender_.get());
+ }
}
void ServiceWorkerProviderContext::OnAssociateRegistration(
const ServiceWorkerRegistrationObjectInfo& info,
const ServiceWorkerVersionAttributes& attrs) {
+ base::AutoLock lock(lock_);
+ DCHECK(main_thread_loop_proxy_->RunsTasksOnCurrentThread());
DCHECK(!registration_);
+ DCHECK_NE(kInvalidServiceWorkerRegistrationId, info.registration_id);
DCHECK_NE(kInvalidServiceWorkerRegistrationHandleId, info.handle_id);
+
registration_ = ServiceWorkerRegistrationHandleReference::Adopt(
info, thread_safe_sender_.get());
installing_ = ServiceWorkerHandleReference::Adopt(
@@ -91,6 +101,9 @@ void ServiceWorkerProviderContext::OnAssociateRegistration(
}
void ServiceWorkerProviderContext::OnDisassociateRegistration() {
+ base::AutoLock lock(lock_);
+ DCHECK(main_thread_loop_proxy_->RunsTasksOnCurrentThread());
+
controller_.reset();
active_.reset();
waiting_.reset();
@@ -101,6 +114,9 @@ void ServiceWorkerProviderContext::OnDisassociateRegistration() {
void ServiceWorkerProviderContext::OnServiceWorkerStateChanged(
int handle_id,
blink::WebServiceWorkerState state) {
+ base::AutoLock lock(lock_);
+ DCHECK(main_thread_loop_proxy_->RunsTasksOnCurrentThread());
+
ServiceWorkerHandleReference* which = NULL;
if (handle_id == controller_handle_id())
which = controller_.get();
@@ -121,34 +137,10 @@ void ServiceWorkerProviderContext::OnServiceWorkerStateChanged(
// when we support navigator.serviceWorker in dedicated workers.
}
-void ServiceWorkerProviderContext::OnSetInstallingServiceWorker(
- int registration_handle_id,
- const ServiceWorkerObjectInfo& info) {
- DCHECK(IsAssociatedWithRegistration(registration_handle_id));
- installing_ =
- ServiceWorkerHandleReference::Adopt(info, thread_safe_sender_.get());
-}
-
-void ServiceWorkerProviderContext::OnSetWaitingServiceWorker(
- int registration_handle_id,
- const ServiceWorkerObjectInfo& info) {
- DCHECK(IsAssociatedWithRegistration(registration_handle_id));
- waiting_ =
- ServiceWorkerHandleReference::Adopt(info, thread_safe_sender_.get());
-}
-
-void ServiceWorkerProviderContext::OnSetActiveServiceWorker(
- int registration_handle_id,
- const ServiceWorkerObjectInfo& info) {
- DCHECK(IsAssociatedWithRegistration(registration_handle_id));
- active_ =
- ServiceWorkerHandleReference::Adopt(info, thread_safe_sender_.get());
-}
-
void ServiceWorkerProviderContext::OnSetControllerServiceWorker(
- int registration_handle_id,
const ServiceWorkerObjectInfo& info) {
- DCHECK(IsAssociatedWithRegistration(registration_handle_id));
+ DCHECK(main_thread_loop_proxy_->RunsTasksOnCurrentThread());
+ DCHECK(registration_);
// This context is is the primary owner of this handle, keeps the
// initial reference until it goes away.
@@ -189,13 +181,12 @@ int ServiceWorkerProviderContext::registration_handle_id() const {
: kInvalidServiceWorkerRegistrationHandleId;
}
-bool ServiceWorkerProviderContext::IsAssociatedWithRegistration(
- int registration_handle_id) const {
- if (!registration_)
- return false;
- if (registration_handle_id == kInvalidServiceWorkerRegistrationHandleId)
- return false;
- return registration_->info().handle_id == registration_handle_id;
+void ServiceWorkerProviderContext::DestructOnMainThread() const {
+ if (!main_thread_loop_proxy_->RunsTasksOnCurrentThread() &&
+ main_thread_loop_proxy_->DeleteSoon(FROM_HERE, this)) {
+ return;
+ }
+ delete this;
}
} // namespace content
diff --git a/chromium/content/child/service_worker/service_worker_provider_context.h b/chromium/content/child/service_worker/service_worker_provider_context.h
index 75348bb95fa..b54c7993ff1 100644
--- a/chromium/content/child/service_worker/service_worker_provider_context.h
+++ b/chromium/content/child/service_worker/service_worker_provider_context.h
@@ -28,13 +28,12 @@ class ServiceWorkerRegistrationHandleReference;
struct ServiceWorkerProviderContextDeleter;
class ThreadSafeSender;
-// An instance of this class holds document-related information (e.g.
-// .controller). Created and destructed on the main thread.
-// TODO(kinuko): To support navigator.serviceWorker in dedicated workers
-// this needs to be RefCountedThreadSafe and .controller info needs to be
-// handled in a thread-safe manner (e.g. by a lock etc).
+// An instance of this class holds information related to Document/Worker.
+// Created and destructed on the main thread. Some functions can be called
+// on the worker thread (eg. GetVersionAttributes).
class ServiceWorkerProviderContext
- : public base::RefCounted<ServiceWorkerProviderContext> {
+ : public base::RefCountedThreadSafe<ServiceWorkerProviderContext,
+ ServiceWorkerProviderContextDeleter> {
public:
explicit ServiceWorkerProviderContext(int provider_id);
@@ -44,24 +43,17 @@ class ServiceWorkerProviderContext
void OnDisassociateRegistration();
void OnServiceWorkerStateChanged(int handle_id,
blink::WebServiceWorkerState state);
- void OnSetInstallingServiceWorker(int registration_handle_id,
- const ServiceWorkerObjectInfo& info);
- void OnSetWaitingServiceWorker(int registration_handle_id,
- const ServiceWorkerObjectInfo& info);
- void OnSetActiveServiceWorker(int registration_handle_id,
- const ServiceWorkerObjectInfo& info);
- void OnSetControllerServiceWorker(int registration_handle_id,
- const ServiceWorkerObjectInfo& info);
+ void OnSetControllerServiceWorker(const ServiceWorkerObjectInfo& info);
int provider_id() const { return provider_id_; }
- ServiceWorkerHandleReference* installing();
- ServiceWorkerHandleReference* waiting();
- ServiceWorkerHandleReference* active();
ServiceWorkerHandleReference* controller();
- ServiceWorkerRegistrationHandleReference* registration();
- ServiceWorkerVersionAttributes GetVersionAttributes();
+ bool GetRegistrationInfoAndVersionAttributes(
+ ServiceWorkerRegistrationObjectInfo* info,
+ ServiceWorkerVersionAttributes* attrs);
+ void SetVersionAttributes(ChangedVersionAttributesMask mask,
+ const ServiceWorkerVersionAttributes& attrs);
// Gets the handle ID of the installing Service Worker, or
// kInvalidServiceWorkerHandleId if the provider does not have a
@@ -89,23 +81,39 @@ class ServiceWorkerProviderContext
int registration_handle_id() const;
private:
- friend class base::RefCounted<ServiceWorkerProviderContext>;
- ~ServiceWorkerProviderContext();
+ friend class base::DeleteHelper<ServiceWorkerProviderContext>;
+ friend class base::RefCountedThreadSafe<ServiceWorkerProviderContext,
+ ServiceWorkerProviderContextDeleter>;
+ friend struct ServiceWorkerProviderContextDeleter;
- bool IsAssociatedWithRegistration(int registration_handle_id) const;
+ ~ServiceWorkerProviderContext();
+ void DestructOnMainThread() const;
const int provider_id_;
scoped_refptr<base::MessageLoopProxy> main_thread_loop_proxy_;
scoped_refptr<ThreadSafeSender> thread_safe_sender_;
+
+ // Protects (installing, waiting, active) worker and registration references.
+ base::Lock lock_;
+
+ // Used on both the main thread and the worker thread.
scoped_ptr<ServiceWorkerHandleReference> installing_;
scoped_ptr<ServiceWorkerHandleReference> waiting_;
scoped_ptr<ServiceWorkerHandleReference> active_;
- scoped_ptr<ServiceWorkerHandleReference> controller_;
scoped_ptr<ServiceWorkerRegistrationHandleReference> registration_;
+ // Used only on the main thread.
+ scoped_ptr<ServiceWorkerHandleReference> controller_;
+
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerProviderContext);
};
+struct ServiceWorkerProviderContextDeleter {
+ static void Destruct(const ServiceWorkerProviderContext* context) {
+ context->DestructOnMainThread();
+ }
+};
+
} // namespace content
#endif // CONTENT_CHILD_SERVICE_WORKER_SERVICE_WORKER_PROVIDER_CONTEXT_H_
diff --git a/chromium/content/child/service_worker/service_worker_registration_handle_reference.cc b/chromium/content/child/service_worker/service_worker_registration_handle_reference.cc
index 438bce486c0..7a9e2847ae0 100644
--- a/chromium/content/child/service_worker/service_worker_registration_handle_reference.cc
+++ b/chromium/content/child/service_worker/service_worker_registration_handle_reference.cc
@@ -34,7 +34,7 @@ ServiceWorkerRegistrationHandleReference(
sender_(sender) {
DCHECK_NE(kInvalidServiceWorkerRegistrationHandleId, info_.handle_id);
DCHECK(sender_.get());
- if (increment_ref_in_ctor)
+ if (!increment_ref_in_ctor)
return;
sender_->Send(
new ServiceWorkerHostMsg_IncrementRegistrationRefCount(info_.handle_id));
diff --git a/chromium/content/child/service_worker/web_service_worker_impl.cc b/chromium/content/child/service_worker/web_service_worker_impl.cc
index dcd69ca8a90..0939aaa7b6d 100644
--- a/chromium/content/child/service_worker/web_service_worker_impl.cc
+++ b/chromium/content/child/service_worker/web_service_worker_impl.cc
@@ -43,10 +43,8 @@ WebServiceWorkerImpl::~WebServiceWorkerImpl() {
void WebServiceWorkerImpl::OnStateChanged(
blink::WebServiceWorkerState new_state) {
- if (proxy_ && proxy_->isReady())
- CommitState(new_state);
- else
- queued_states_.push_back(new_state);
+ state_ = new_state;
+ proxy_->dispatchStateChangeEvent();
}
void WebServiceWorkerImpl::setProxy(blink::WebServiceWorkerProxy* proxy) {
@@ -57,22 +55,6 @@ blink::WebServiceWorkerProxy* WebServiceWorkerImpl::proxy() {
return proxy_;
}
-void WebServiceWorkerImpl::proxyReadyChanged() {
- if (!proxy_->isReady())
- return;
- for (std::vector<blink::WebServiceWorkerState>::iterator it =
- queued_states_.begin();
- it != queued_states_.end();
- ++it) {
- CommitState(*it);
- }
- queued_states_.clear();
-}
-
-blink::WebURL WebServiceWorkerImpl::scope() const {
- return handle_ref_->scope();
-}
-
blink::WebURL WebServiceWorkerImpl::url() const {
return handle_ref_->url();
}
@@ -89,11 +71,9 @@ void WebServiceWorkerImpl::postMessage(const WebString& message,
WebMessagePortChannelImpl::ExtractMessagePortIDs(channels)));
}
-void WebServiceWorkerImpl::CommitState(blink::WebServiceWorkerState new_state) {
- DCHECK(proxy_);
- DCHECK(proxy_->isReady());
- state_ = new_state;
- proxy_->dispatchStateChangeEvent();
+void WebServiceWorkerImpl::terminate() {
+ thread_safe_sender_->Send(
+ new ServiceWorkerHostMsg_TerminateWorker(handle_ref_->handle_id()));
}
} // namespace content
diff --git a/chromium/content/child/service_worker/web_service_worker_impl.h b/chromium/content/child/service_worker/web_service_worker_impl.h
index b1ede903677..e3f2cb6efa0 100644
--- a/chromium/content/child/service_worker/web_service_worker_impl.h
+++ b/chromium/content/child/service_worker/web_service_worker_impl.h
@@ -39,29 +39,21 @@ class WebServiceWorkerImpl
ThreadSafeSender* thread_safe_sender);
virtual ~WebServiceWorkerImpl();
- // Notifies that the service worker's state changed. This function may queue
- // the state change for later processing, if the proxy is not yet ready to
- // handle state changes.
void OnStateChanged(blink::WebServiceWorkerState new_state);
virtual void setProxy(blink::WebServiceWorkerProxy* proxy);
virtual blink::WebServiceWorkerProxy* proxy();
- virtual void proxyReadyChanged();
- virtual blink::WebURL scope() const;
virtual blink::WebURL url() const;
virtual blink::WebServiceWorkerState state() const;
virtual void postMessage(const blink::WebString& message,
blink::WebMessagePortChannelArray* channels);
+ virtual void terminate();
private:
- // Commits the new state internally and notifies the proxy of the change.
- void CommitState(blink::WebServiceWorkerState new_state);
-
scoped_ptr<ServiceWorkerHandleReference> handle_ref_;
blink::WebServiceWorkerState state_;
scoped_refptr<ThreadSafeSender> thread_safe_sender_;
blink::WebServiceWorkerProxy* proxy_;
- std::vector<blink::WebServiceWorkerState> queued_states_;
DISALLOW_COPY_AND_ASSIGN(WebServiceWorkerImpl);
};
diff --git a/chromium/content/child/service_worker/web_service_worker_provider_impl.cc b/chromium/content/child/service_worker/web_service_worker_provider_impl.cc
index ef46bf8cc19..96185668c0e 100644
--- a/chromium/content/child/service_worker/web_service_worker_provider_impl.cc
+++ b/chromium/content/child/service_worker/web_service_worker_provider_impl.cc
@@ -4,17 +4,11 @@
#include "content/child/service_worker/web_service_worker_provider_impl.h"
-#include "base/atomic_sequence_num.h"
-#include "base/logging.h"
-#include "content/child/child_thread.h"
#include "content/child/service_worker/service_worker_dispatcher.h"
#include "content/child/service_worker/service_worker_handle_reference.h"
#include "content/child/service_worker/service_worker_provider_context.h"
-#include "content/child/service_worker/service_worker_registration_handle_reference.h"
#include "content/child/service_worker/web_service_worker_impl.h"
-#include "content/child/service_worker/web_service_worker_registration_impl.h"
#include "content/child/thread_safe_sender.h"
-#include "content/common/service_worker/service_worker_messages.h"
#include "third_party/WebKit/public/platform/WebServiceWorkerProviderClient.h"
#include "third_party/WebKit/public/platform/WebURL.h"
@@ -26,19 +20,18 @@ WebServiceWorkerProviderImpl::WebServiceWorkerProviderImpl(
ThreadSafeSender* thread_safe_sender,
ServiceWorkerProviderContext* context)
: thread_safe_sender_(thread_safe_sender),
- context_(context),
- provider_id_(context->provider_id()) {
+ context_(context) {
}
WebServiceWorkerProviderImpl::~WebServiceWorkerProviderImpl() {
- // Make sure the script client is removed.
- RemoveScriptClient();
+ // Make sure the provider client is removed.
+ RemoveProviderClient();
}
void WebServiceWorkerProviderImpl::setClient(
blink::WebServiceWorkerProviderClient* client) {
if (!client) {
- RemoveScriptClient();
+ RemoveProviderClient();
return;
}
@@ -47,36 +40,13 @@ void WebServiceWorkerProviderImpl::setClient(
// (e.g. on document and on dedicated workers) can properly share
// the single provider context across threads. (http://crbug.com/366538
// for more context)
- GetDispatcher()->AddScriptClient(provider_id_, client);
+ GetDispatcher()->AddProviderClient(context_->provider_id(), client);
- if (!context_->registration()) {
- // This provider is not associated with any registration.
+ if (!context_->controller())
return;
- }
-
- // Set .ready if the associated registration has the active service worker.
- if (context_->active_handle_id() != kInvalidServiceWorkerHandleId) {
- WebServiceWorkerRegistrationImpl* registration =
- GetDispatcher()->FindServiceWorkerRegistration(
- context_->registration()->info(), false);
- if (!registration) {
- registration = GetDispatcher()->CreateServiceWorkerRegistration(
- context_->registration()->info(), false);
- ServiceWorkerVersionAttributes attrs = context_->GetVersionAttributes();
- registration->SetInstalling(
- GetDispatcher()->GetServiceWorker(attrs.installing, false));
- registration->SetWaiting(
- GetDispatcher()->GetServiceWorker(attrs.waiting, false));
- registration->SetActive(
- GetDispatcher()->GetServiceWorker(attrs.active, false));
- }
- client->setReadyRegistration(registration);
- }
-
- if (context_->controller_handle_id() != kInvalidServiceWorkerHandleId) {
- client->setController(GetDispatcher()->GetServiceWorker(
- context_->controller()->info(), false));
- }
+ client->setController(
+ GetDispatcher()->GetServiceWorker(context_->controller()->info(), false),
+ false /* shouldNotifyControllerChange */);
}
void WebServiceWorkerProviderImpl::registerServiceWorker(
@@ -84,29 +54,35 @@ void WebServiceWorkerProviderImpl::registerServiceWorker(
const WebURL& script_url,
WebServiceWorkerRegistrationCallbacks* callbacks) {
GetDispatcher()->RegisterServiceWorker(
- provider_id_, pattern, script_url, callbacks);
+ context_->provider_id(), pattern, script_url, callbacks);
}
void WebServiceWorkerProviderImpl::unregisterServiceWorker(
const WebURL& pattern,
WebServiceWorkerUnregistrationCallbacks* callbacks) {
GetDispatcher()->UnregisterServiceWorker(
- provider_id_, pattern, callbacks);
+ context_->provider_id(), pattern, callbacks);
}
void WebServiceWorkerProviderImpl::getRegistration(
const blink::WebURL& document_url,
WebServiceWorkerRegistrationCallbacks* callbacks) {
- GetDispatcher()->GetRegistration(provider_id_, document_url, callbacks);
+ GetDispatcher()->GetRegistration(
+ context_->provider_id(), document_url, callbacks);
+}
+
+void WebServiceWorkerProviderImpl::getRegistrationForReady(
+ WebServiceWorkerGetRegistrationForReadyCallbacks* callbacks) {
+ GetDispatcher()->GetRegistrationForReady(context_->provider_id(), callbacks);
}
-void WebServiceWorkerProviderImpl::RemoveScriptClient() {
- // Remove the script client, but only if the dispatcher is still there.
+void WebServiceWorkerProviderImpl::RemoveProviderClient() {
+ // Remove the provider client, but only if the dispatcher is still there.
// (For cleanup path we don't need to bother creating a new dispatcher)
ServiceWorkerDispatcher* dispatcher =
ServiceWorkerDispatcher::GetThreadSpecificInstance();
if (dispatcher)
- dispatcher->RemoveScriptClient(provider_id_);
+ dispatcher->RemoveProviderClient(context_->provider_id());
}
ServiceWorkerDispatcher* WebServiceWorkerProviderImpl::GetDispatcher() {
diff --git a/chromium/content/child/service_worker/web_service_worker_provider_impl.h b/chromium/content/child/service_worker/web_service_worker_provider_impl.h
index e56f913c360..37e99b1ae0f 100644
--- a/chromium/content/child/service_worker/web_service_worker_provider_impl.h
+++ b/chromium/content/child/service_worker/web_service_worker_provider_impl.h
@@ -7,7 +7,6 @@
#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
#include "third_party/WebKit/public/platform/WebServiceWorkerProvider.h"
namespace blink {
@@ -42,18 +41,15 @@ class WebServiceWorkerProviderImpl
virtual void getRegistration(const blink::WebURL& document_url,
WebServiceWorkerGetRegistrationCallbacks*);
-
- ServiceWorkerProviderContext* context() { return context_.get(); }
-
- int provider_id() const { return provider_id_; }
+ virtual void getRegistrationForReady(
+ WebServiceWorkerGetRegistrationForReadyCallbacks*);
private:
- void RemoveScriptClient();
+ void RemoveProviderClient();
ServiceWorkerDispatcher* GetDispatcher();
scoped_refptr<ThreadSafeSender> thread_safe_sender_;
scoped_refptr<ServiceWorkerProviderContext> context_;
- const int provider_id_;
DISALLOW_COPY_AND_ASSIGN(WebServiceWorkerProviderImpl);
};
diff --git a/chromium/content/child/service_worker/web_service_worker_registration_impl.h b/chromium/content/child/service_worker/web_service_worker_registration_impl.h
index 52ee1029ddf..3feb71b40c5 100644
--- a/chromium/content/child/service_worker/web_service_worker_registration_impl.h
+++ b/chromium/content/child/service_worker/web_service_worker_registration_impl.h
@@ -8,6 +8,7 @@
#include <vector>
#include "base/compiler_specific.h"
+#include "content/common/content_export.h"
#include "third_party/WebKit/public/platform/WebServiceWorkerRegistration.h"
namespace blink {
@@ -21,7 +22,7 @@ class ServiceWorkerRegistrationHandleReference;
class ThreadSafeSender;
struct ServiceWorkerObjectInfo;
-class WebServiceWorkerRegistrationImpl
+class CONTENT_EXPORT WebServiceWorkerRegistrationImpl
: NON_EXPORTED_BASE(public blink::WebServiceWorkerRegistration) {
public:
explicit WebServiceWorkerRegistrationImpl(
diff --git a/chromium/content/child/shared_worker_devtools_agent.cc b/chromium/content/child/shared_worker_devtools_agent.cc
index 5d127378fb9..26a51edf6dd 100644
--- a/chromium/content/child/shared_worker_devtools_agent.cc
+++ b/chromium/content/child/shared_worker_devtools_agent.cc
@@ -4,7 +4,7 @@
#include "content/child/shared_worker_devtools_agent.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
#include "content/common/devtools_messages.h"
#include "ipc/ipc_channel.h"
#include "third_party/WebKit/public/platform/WebCString.h"
@@ -44,28 +44,37 @@ bool SharedWorkerDevToolsAgent::OnMessageReceived(const IPC::Message& message) {
}
void SharedWorkerDevToolsAgent::SendDevToolsMessage(
- const blink::WebString& message) {
- std::string msg(message.utf8());
+ int call_id,
+ const blink::WebString& msg,
+ const blink::WebString& state) {
+ std::string message = msg.utf8();
+ std::string post_state = state.utf8();
+ DevToolsMessageChunk chunk;
+ chunk.message_size = message.size();
+ chunk.is_first = true;
+
if (message.length() < kMaxMessageChunkSize) {
+ chunk.data.swap(message);
+ chunk.call_id = call_id;
+ chunk.post_state = post_state;
+ chunk.is_last = true;
Send(new DevToolsClientMsg_DispatchOnInspectorFrontend(
- route_id_, msg, msg.size()));
+ route_id_, chunk));
return;
}
- for (size_t pos = 0; pos < msg.length(); pos += kMaxMessageChunkSize) {
+ for (size_t pos = 0; pos < message.length(); pos += kMaxMessageChunkSize) {
+ chunk.is_last = pos + kMaxMessageChunkSize >= message.length();
+ chunk.call_id = chunk.is_last ? call_id : 0;
+ chunk.post_state = chunk.is_last ? post_state : std::string();
+ chunk.data = message.substr(pos, kMaxMessageChunkSize);
Send(new DevToolsClientMsg_DispatchOnInspectorFrontend(
- route_id_,
- msg.substr(pos, kMaxMessageChunkSize),
- pos ? 0 : msg.size()));
+ route_id_, chunk));
+ chunk.is_first = false;
+ chunk.message_size = 0;
}
}
-void SharedWorkerDevToolsAgent::SaveDevToolsAgentState(
- const blink::WebString& state) {
- Send(new DevToolsHostMsg_SaveAgentRuntimeState(route_id_,
- state.utf8()));
-}
-
void SharedWorkerDevToolsAgent::OnAttach(const std::string& host_id) {
webworker_->attachDevTools(WebString::fromUTF8(host_id));
}
@@ -86,7 +95,7 @@ void SharedWorkerDevToolsAgent::OnDispatchOnInspectorBackend(
}
bool SharedWorkerDevToolsAgent::Send(IPC::Message* message) {
- return ChildThread::current()->Send(message);
+ return ChildThreadImpl::current()->Send(message);
}
} // namespace content
diff --git a/chromium/content/child/shared_worker_devtools_agent.h b/chromium/content/child/shared_worker_devtools_agent.h
index a2d028e7d4e..2d6a732a330 100644
--- a/chromium/content/child/shared_worker_devtools_agent.h
+++ b/chromium/content/child/shared_worker_devtools_agent.h
@@ -27,8 +27,9 @@ class SharedWorkerDevToolsAgent {
// Called on the Worker thread.
bool OnMessageReceived(const IPC::Message& message);
- void SendDevToolsMessage(const blink::WebString&);
- void SaveDevToolsAgentState(const blink::WebString& state);
+ void SendDevToolsMessage(int call_id,
+ const blink::WebString& message,
+ const blink::WebString& post_state);
private:
void OnAttach(const std::string& host_id);
diff --git a/chromium/content/child/simple_webmimeregistry_impl.cc b/chromium/content/child/simple_webmimeregistry_impl.cc
index 510b25b7341..d3276e4fc5d 100644
--- a/chromium/content/child/simple_webmimeregistry_impl.cc
+++ b/chromium/content/child/simple_webmimeregistry_impl.cc
@@ -8,6 +8,7 @@
#include "base/strings/string_util.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
+#include "components/mime_util/mime_util.h"
#include "net/base/mime_util.h"
#include "third_party/WebKit/public/platform/WebString.h"
@@ -24,31 +25,35 @@ std::string SimpleWebMimeRegistryImpl::ToASCIIOrEmpty(const WebString& string) {
WebMimeRegistry::SupportsType SimpleWebMimeRegistryImpl::supportsMIMEType(
const WebString& mime_type) {
- return net::IsSupportedMimeType(ToASCIIOrEmpty(mime_type)) ?
- WebMimeRegistry::IsSupported : WebMimeRegistry::IsNotSupported;
+ return mime_util::IsSupportedMimeType(ToASCIIOrEmpty(mime_type))
+ ? WebMimeRegistry::IsSupported
+ : WebMimeRegistry::IsNotSupported;
}
WebMimeRegistry::SupportsType SimpleWebMimeRegistryImpl::supportsImageMIMEType(
const WebString& mime_type) {
- return net::IsSupportedImageMimeType(ToASCIIOrEmpty(mime_type)) ?
- WebMimeRegistry::IsSupported : WebMimeRegistry::IsNotSupported;
+ return mime_util::IsSupportedImageMimeType(ToASCIIOrEmpty(mime_type))
+ ? WebMimeRegistry::IsSupported
+ : WebMimeRegistry::IsNotSupported;
}
WebMimeRegistry::SupportsType
SimpleWebMimeRegistryImpl::supportsImagePrefixedMIMEType(
const WebString& mime_type) {
std::string ascii_mime_type = ToASCIIOrEmpty(mime_type);
- return (net::IsSupportedImageMimeType(ascii_mime_type) ||
- (StartsWithASCII(ascii_mime_type, "image/", true) &&
- net::IsSupportedNonImageMimeType(ascii_mime_type))) ?
- WebMimeRegistry::IsSupported : WebMimeRegistry::IsNotSupported;
+ return (mime_util::IsSupportedImageMimeType(ascii_mime_type) ||
+ (StartsWithASCII(ascii_mime_type, "image/", true) &&
+ mime_util::IsSupportedNonImageMimeType(ascii_mime_type)))
+ ? WebMimeRegistry::IsSupported
+ : WebMimeRegistry::IsNotSupported;
}
WebMimeRegistry::SupportsType
SimpleWebMimeRegistryImpl::supportsJavaScriptMIMEType(
const WebString& mime_type) {
- return net::IsSupportedJavascriptMimeType(ToASCIIOrEmpty(mime_type)) ?
- WebMimeRegistry::IsSupported : WebMimeRegistry::IsNotSupported;
+ return mime_util::IsSupportedJavascriptMimeType(ToASCIIOrEmpty(mime_type))
+ ? WebMimeRegistry::IsSupported
+ : WebMimeRegistry::IsNotSupported;
}
// When debugging layout tests failures in the test shell,
@@ -68,19 +73,12 @@ bool SimpleWebMimeRegistryImpl::supportsMediaSourceMIMEType(
return false;
}
-bool SimpleWebMimeRegistryImpl::supportsEncryptedMediaMIMEType(
- const blink::WebString& key_system,
- const blink::WebString& mime_type,
- const blink::WebString& codecs) {
- // Media features are only supported at the content/renderer layer.
- return false;
-}
-
WebMimeRegistry::SupportsType
SimpleWebMimeRegistryImpl::supportsNonImageMIMEType(
const WebString& mime_type) {
- return net::IsSupportedNonImageMimeType(ToASCIIOrEmpty(mime_type)) ?
- WebMimeRegistry::IsSupported : WebMimeRegistry::IsNotSupported;
+ return mime_util::IsSupportedNonImageMimeType(ToASCIIOrEmpty(mime_type))
+ ? WebMimeRegistry::IsSupported
+ : WebMimeRegistry::IsNotSupported;
}
WebString SimpleWebMimeRegistryImpl::mimeTypeForExtension(
diff --git a/chromium/content/child/simple_webmimeregistry_impl.h b/chromium/content/child/simple_webmimeregistry_impl.h
index 3e9b95e37db..10156c5918f 100644
--- a/chromium/content/child/simple_webmimeregistry_impl.h
+++ b/chromium/content/child/simple_webmimeregistry_impl.h
@@ -38,9 +38,6 @@ class CONTENT_EXPORT SimpleWebMimeRegistryImpl :
const blink::WebString&);
virtual bool supportsMediaSourceMIMEType(const blink::WebString&,
const blink::WebString&);
- virtual bool supportsEncryptedMediaMIMEType(const blink::WebString&,
- const blink::WebString&,
- const blink::WebString&);
virtual blink::WebMimeRegistry::SupportsType supportsNonImageMIMEType(
const blink::WebString&);
virtual blink::WebString mimeTypeForExtension(const blink::WebString&);
diff --git a/chromium/content/child/site_isolation_policy.cc b/chromium/content/child/site_isolation_policy.cc
index 87ac9cc849c..2320e0e3437 100644
--- a/chromium/content/child/site_isolation_policy.cc
+++ b/chromium/content/child/site_isolation_policy.cc
@@ -290,8 +290,8 @@ bool SiteIsolationPolicy::ShouldBlockResponse(
}
}
- if (!CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kBlockCrossSiteDocuments))
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kBlockCrossSiteDocuments))
is_blocked = false;
if (is_blocked) {
diff --git a/chromium/content/child/site_isolation_policy_browsertest.cc b/chromium/content/child/site_isolation_policy_browsertest.cc
index c23b9b98759..2bf0b9a200f 100644
--- a/chromium/content/child/site_isolation_policy_browsertest.cc
+++ b/chromium/content/child/site_isolation_policy_browsertest.cc
@@ -19,7 +19,7 @@ class SiteIsolationPolicyBrowserTest : public ContentBrowserTest {
SiteIsolationPolicyBrowserTest() {}
~SiteIsolationPolicyBrowserTest() override {}
- void SetUpCommandLine(CommandLine* command_line) override {
+ void SetUpCommandLine(base::CommandLine* command_line) override {
ASSERT_TRUE(test_server()->Start());
net::SpawnedTestServer https_server(
net::SpawnedTestServer::TYPE_HTTPS,
@@ -93,6 +93,13 @@ IN_PROC_BROWSER_TEST_F(SiteIsolationPolicyBrowserTest,
IN_PROC_BROWSER_TEST_F(SiteIsolationPolicyBrowserTest,
MAYBE_CrossSiteDocumentBlockingForDifferentTargets) {
+ // TODO(creis): Re-enable this test in --site-per-process mode once we support
+ // sibling frames from the same site with correct DidStopLoading behavior.
+ // See http://crbug.com/419087 and http://crbug.com/436250.
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess))
+ return;
+
// This webpage loads a cross-site HTML page in different targets such as
// <img>,<link>,<embed>, etc. Since the requested document is blocked, and one
// character string (' ') is returned instead, this tests that the renderer
diff --git a/chromium/content/child/thread_safe_sender.cc b/chromium/content/child/thread_safe_sender.cc
index d9ecfd1ca30..95f97132ddd 100644
--- a/chromium/content/child/thread_safe_sender.cc
+++ b/chromium/content/child/thread_safe_sender.cc
@@ -5,23 +5,23 @@
#include "content/child/thread_safe_sender.h"
#include "base/message_loop/message_loop_proxy.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
#include "ipc/ipc_sync_message_filter.h"
namespace content {
+ThreadSafeSender::~ThreadSafeSender() {
+}
+
ThreadSafeSender::ThreadSafeSender(
const scoped_refptr<base::MessageLoopProxy>& main_loop,
const scoped_refptr<IPC::SyncMessageFilter>& sync_filter)
: main_loop_(main_loop), sync_filter_(sync_filter) {
}
-ThreadSafeSender::~ThreadSafeSender() {
-}
-
bool ThreadSafeSender::Send(IPC::Message* msg) {
if (main_loop_->BelongsToCurrentThread())
- return ChildThread::current()->Send(msg);
+ return ChildThreadImpl::current()->Send(msg);
return sync_filter_->Send(msg);
}
diff --git a/chromium/content/child/thread_safe_sender.h b/chromium/content/child/thread_safe_sender.h
index 443e20a720a..a6605aaa349 100644
--- a/chromium/content/child/thread_safe_sender.h
+++ b/chromium/content/child/thread_safe_sender.h
@@ -19,25 +19,26 @@ class SyncMessageFilter;
}
namespace content {
-class ChildThread;
+class ChildThreadImpl;
-// The class of Sender returned by ChildThread::thread_safe_sender().
+// The class of Sender returned by ChildThreadImpl::thread_safe_sender().
class CONTENT_EXPORT ThreadSafeSender
: public IPC::Sender,
public base::RefCountedThreadSafe<ThreadSafeSender> {
public:
bool Send(IPC::Message* msg) override;
+ protected:
+ ThreadSafeSender(const scoped_refptr<base::MessageLoopProxy>& main_loop,
+ const scoped_refptr<IPC::SyncMessageFilter>& sync_filter);
+ ~ThreadSafeSender() override;
+
private:
- friend class ChildThread; // for construction
+ friend class ChildThreadImpl; // for construction
friend class IndexedDBDispatcherTest;
friend class WebIDBCursorImplTest;
friend class base::RefCountedThreadSafe<ThreadSafeSender>;
- ThreadSafeSender(const scoped_refptr<base::MessageLoopProxy>& main_loop,
- const scoped_refptr<IPC::SyncMessageFilter>& sync_filter);
- ~ThreadSafeSender() override;
-
scoped_refptr<base::MessageLoopProxy> main_loop_;
scoped_refptr<IPC::SyncMessageFilter> sync_filter_;
diff --git a/chromium/content/child/threaded_data_provider.cc b/chromium/content/child/threaded_data_provider.cc
index f7a6c66f1dd..eea420a44a1 100644
--- a/chromium/content/child/threaded_data_provider.cc
+++ b/chromium/content/child/threaded_data_provider.cc
@@ -4,11 +4,11 @@
#include "content/child/threaded_data_provider.h"
+#include "components/scheduler/child/webthread_impl_for_worker_scheduler.h"
#include "content/child/child_process.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
#include "content/child/resource_dispatcher.h"
#include "content/child/thread_safe_sender.h"
-#include "content/child/webthread_impl.h"
#include "content/common/resource_messages.h"
#include "ipc/ipc_sync_channel.h"
#include "third_party/WebKit/public/platform/WebThread.h"
@@ -22,12 +22,11 @@ class DataProviderMessageFilter : public IPC::MessageFilter {
public:
DataProviderMessageFilter(
const scoped_refptr<base::MessageLoopProxy>& io_message_loop,
- base::MessageLoop* main_thread_message_loop,
- const WebThreadImpl& background_thread,
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner,
+ const scheduler::WebThreadImplForWorkerScheduler& background_thread,
const base::WeakPtr<ThreadedDataProvider>&
background_thread_resource_provider,
- const base::WeakPtr<ThreadedDataProvider>&
- main_thread_resource_provider,
+ const base::WeakPtr<ThreadedDataProvider>& main_thread_resource_provider,
int request_id);
// IPC::ChannelProxy::MessageFilter
@@ -41,8 +40,8 @@ class DataProviderMessageFilter : public IPC::MessageFilter {
int encoded_data_length);
const scoped_refptr<base::MessageLoopProxy> io_message_loop_;
- base::MessageLoop* main_thread_message_loop_;
- const WebThreadImpl& background_thread_;
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
+ const scheduler::WebThreadImplForWorkerScheduler& background_thread_;
// This weakptr can only be dereferenced on the background thread.
base::WeakPtr<ThreadedDataProvider>
background_thread_resource_provider_;
@@ -54,29 +53,28 @@ class DataProviderMessageFilter : public IPC::MessageFilter {
DataProviderMessageFilter::DataProviderMessageFilter(
const scoped_refptr<base::MessageLoopProxy>& io_message_loop,
- base::MessageLoop* main_thread_message_loop,
- const WebThreadImpl& background_thread,
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner,
+ const scheduler::WebThreadImplForWorkerScheduler& background_thread,
const base::WeakPtr<ThreadedDataProvider>&
background_thread_resource_provider,
- const base::WeakPtr<ThreadedDataProvider>&
- main_thread_resource_provider,
+ const base::WeakPtr<ThreadedDataProvider>& main_thread_resource_provider,
int request_id)
: io_message_loop_(io_message_loop),
- main_thread_message_loop_(main_thread_message_loop),
+ main_thread_task_runner_(main_thread_task_runner),
background_thread_(background_thread),
background_thread_resource_provider_(background_thread_resource_provider),
main_thread_resource_provider_(main_thread_resource_provider),
request_id_(request_id) {
- DCHECK(main_thread_message_loop != NULL);
+ DCHECK(main_thread_task_runner_.get());
}
void DataProviderMessageFilter::OnFilterAdded(IPC::Sender* sender) {
DCHECK(io_message_loop_->BelongsToCurrentThread());
- main_thread_message_loop_->PostTask(FROM_HERE,
- base::Bind(
- &ThreadedDataProvider::OnResourceMessageFilterAddedMainThread,
- main_thread_resource_provider_));
+ main_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&ThreadedDataProvider::OnResourceMessageFilterAddedMainThread,
+ main_thread_resource_provider_));
}
bool DataProviderMessageFilter::OnMessageReceived(
@@ -89,7 +87,7 @@ bool DataProviderMessageFilter::OnMessageReceived(
int request_id;
PickleIterator iter(message);
- if (!message.ReadInt(&iter, &request_id)) {
+ if (!iter.ReadInt(&request_id)) {
NOTREACHED() << "malformed resource message";
return true;
}
@@ -97,7 +95,7 @@ bool DataProviderMessageFilter::OnMessageReceived(
if (request_id == request_id_) {
ResourceMsg_DataReceived::Schema::Param arg;
if (ResourceMsg_DataReceived::Read(&message, &arg)) {
- OnReceivedData(arg.a, arg.b, arg.c, arg.d);
+ OnReceivedData(get<0>(arg), get<1>(arg), get<2>(arg), get<3>(arg));
return true;
}
}
@@ -110,66 +108,68 @@ void DataProviderMessageFilter::OnReceivedData(int request_id,
int data_length,
int encoded_data_length) {
DCHECK(io_message_loop_->BelongsToCurrentThread());
- background_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
- &ThreadedDataProvider::OnReceivedDataOnBackgroundThread,
- background_thread_resource_provider_,
- data_offset, data_length, encoded_data_length));
+ background_thread_.TaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&ThreadedDataProvider::OnReceivedDataOnBackgroundThread,
+ background_thread_resource_provider_, data_offset, data_length,
+ encoded_data_length));
}
} // anonymous namespace
ThreadedDataProvider::ThreadedDataProvider(
- int request_id, blink::WebThreadedDataReceiver* threaded_data_receiver,
- linked_ptr<base::SharedMemory> shm_buffer, int shm_size)
+ int request_id,
+ blink::WebThreadedDataReceiver* threaded_data_receiver,
+ linked_ptr<base::SharedMemory> shm_buffer,
+ int shm_size,
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner)
: request_id_(request_id),
shm_buffer_(shm_buffer),
shm_size_(shm_size),
background_thread_(
- static_cast<WebThreadImpl&>(
+ static_cast<scheduler::WebThreadImplForWorkerScheduler&>(
*threaded_data_receiver->backgroundThread())),
- ipc_channel_(ChildThread::current()->channel()),
+ ipc_channel_(ChildThreadImpl::current()->channel()),
threaded_data_receiver_(threaded_data_receiver),
resource_filter_active_(false),
- main_thread_message_loop_(ChildThread::current()->message_loop()),
+ main_thread_task_runner_(main_thread_task_runner),
main_thread_weak_factory_(this) {
- DCHECK(ChildThread::current());
+ DCHECK(ChildThreadImpl::current());
DCHECK(ipc_channel_);
DCHECK(threaded_data_receiver_);
- DCHECK(main_thread_message_loop_);
+ DCHECK(main_thread_task_runner_.get());
background_thread_weak_factory_.reset(
new base::WeakPtrFactory<ThreadedDataProvider>(this));
filter_ = new DataProviderMessageFilter(
ChildProcess::current()->io_message_loop_proxy(),
- main_thread_message_loop_,
- background_thread_,
+ main_thread_task_runner_, background_thread_,
background_thread_weak_factory_->GetWeakPtr(),
- main_thread_weak_factory_.GetWeakPtr(),
- request_id);
+ main_thread_weak_factory_.GetWeakPtr(), request_id);
- ChildThread::current()->channel()->AddFilter(filter_.get());
+ ChildThreadImpl::current()->channel()->AddFilter(filter_.get());
}
ThreadedDataProvider::~ThreadedDataProvider() {
- DCHECK(ChildThread::current());
+ DCHECK(ChildThreadImpl::current());
- ChildThread::current()->channel()->RemoveFilter(filter_.get());
+ ChildThreadImpl::current()->channel()->RemoveFilter(filter_.get());
delete threaded_data_receiver_;
}
-void DestructOnMainThread(ThreadedDataProvider* data_provider) {
- DCHECK(ChildThread::current());
+void ThreadedDataProvider::DestructOnMainThread() {
+ DCHECK(ChildThreadImpl::current());
// The ThreadedDataProvider must be destructed on the main thread to
// be threadsafe when removing the message filter and releasing the shared
// memory buffer.
- delete data_provider;
+ delete this;
}
void ThreadedDataProvider::Stop() {
- DCHECK(ChildThread::current());
+ DCHECK(ChildThreadImpl::current());
// Make sure we don't get called by on the main thread anymore via weak
// pointers we've passed to the filter.
@@ -187,10 +187,11 @@ void ThreadedDataProvider::Stop() {
// We should never end up with a different parser thread than from when the
// ThreadedDataProvider gets created.
DCHECK(current_background_thread ==
- static_cast<WebThreadImpl*>(&background_thread_));
- background_thread_.message_loop()->PostTask(FROM_HERE,
- base::Bind(&ThreadedDataProvider::StopOnBackgroundThread,
- base::Unretained(this)));
+ static_cast<scheduler::WebThreadImplForWorkerScheduler*>(
+ &background_thread_));
+ background_thread_.TaskRunner()->PostTask(
+ FROM_HERE, base::Bind(&ThreadedDataProvider::StopOnBackgroundThread,
+ base::Unretained(this)));
}
}
@@ -204,18 +205,48 @@ void ThreadedDataProvider::StopOnBackgroundThread() {
// which means no callbacks from the filter will happen and nothing else will
// use this instance on the background thread.
background_thread_weak_factory_.reset(NULL);
- main_thread_message_loop_->PostTask(FROM_HERE,
- base::Bind(&DestructOnMainThread, this));
+ main_thread_task_runner_->PostTask(FROM_HERE,
+ base::Bind(&ThreadedDataProvider::DestructOnMainThread,
+ base::Unretained(this)));
+}
+
+void ThreadedDataProvider::OnRequestCompleteForegroundThread(
+ base::WeakPtr<ResourceDispatcher> resource_dispatcher,
+ const ResourceMsg_RequestCompleteData& request_complete_data,
+ const base::TimeTicks& renderer_completion_time) {
+ DCHECK(ChildThreadImpl::current());
+
+ background_thread_.TaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&ThreadedDataProvider::OnRequestCompleteBackgroundThread,
+ base::Unretained(this), resource_dispatcher,
+ request_complete_data, renderer_completion_time));
+}
+
+void ThreadedDataProvider::OnRequestCompleteBackgroundThread(
+ base::WeakPtr<ResourceDispatcher> resource_dispatcher,
+ const ResourceMsg_RequestCompleteData& request_complete_data,
+ const base::TimeTicks& renderer_completion_time) {
+ DCHECK(background_thread_.isCurrentThread());
+
+ main_thread_task_runner_->PostTask(FROM_HERE,
+ base::Bind(
+ &ResourceDispatcher::CompletedRequestAfterBackgroundThreadFlush,
+ resource_dispatcher,
+ request_id_,
+ request_complete_data,
+ renderer_completion_time));
}
void ThreadedDataProvider::OnResourceMessageFilterAddedMainThread() {
- DCHECK(ChildThread::current());
+ DCHECK(ChildThreadImpl::current());
DCHECK(background_thread_weak_factory_);
// We bounce this message from the I/O thread via the main thread and then
// to our background thread, following the same path as incoming data before
// our filter gets added, to make sure there's nothing still incoming.
- background_thread_.message_loop()->PostTask(FROM_HERE,
+ background_thread_.TaskRunner()->PostTask(
+ FROM_HERE,
base::Bind(
&ThreadedDataProvider::OnResourceMessageFilterAddedBackgroundThread,
background_thread_weak_factory_->GetWeakPtr()));
@@ -231,7 +262,7 @@ void ThreadedDataProvider::OnResourceMessageFilterAddedBackgroundThread() {
if (!queued_data_.empty()) {
std::vector<QueuedSharedMemoryData>::iterator iter = queued_data_.begin();
for (; iter != queued_data_.end(); ++iter) {
- ForwardAndACKData(iter->data, iter->length);
+ ForwardAndACKData(iter->data, iter->length, iter->encoded_length);
}
queued_data_.clear();
@@ -249,7 +280,7 @@ void ThreadedDataProvider::OnReceivedDataOnBackgroundThread(
CHECK(data_ptr + data_offset);
if (resource_filter_active_) {
- ForwardAndACKData(data_ptr + data_offset, data_length);
+ ForwardAndACKData(data_ptr + data_offset, data_length, encoded_data_length);
} else {
// There's a brief interval between the point where we know the filter
// has been installed on the I/O thread, and when we know for sure there's
@@ -260,22 +291,24 @@ void ThreadedDataProvider::OnReceivedDataOnBackgroundThread(
QueuedSharedMemoryData queued_data;
queued_data.data = data_ptr + data_offset;
queued_data.length = data_length;
+ queued_data.encoded_length = encoded_data_length;
queued_data_.push_back(queued_data);
}
}
void ThreadedDataProvider::OnReceivedDataOnForegroundThread(
const char* data, int data_length, int encoded_data_length) {
- DCHECK(ChildThread::current());
+ DCHECK(ChildThreadImpl::current());
- background_thread_.message_loop()->PostTask(FROM_HERE,
- base::Bind(&ThreadedDataProvider::ForwardAndACKData,
- base::Unretained(this),
- data, data_length));
+ background_thread_.TaskRunner()->PostTask(
+ FROM_HERE, base::Bind(&ThreadedDataProvider::ForwardAndACKData,
+ base::Unretained(this), data, data_length,
+ encoded_data_length));
}
void ThreadedDataProvider::ForwardAndACKData(const char* data,
- int data_length) {
+ int data_length,
+ int encoded_data_length) {
DCHECK(background_thread_.isCurrentThread());
// TODO(oysteine): SiteIsolationPolicy needs to be be checked
@@ -283,7 +316,34 @@ void ThreadedDataProvider::ForwardAndACKData(const char* data,
// (or earlier on the I/O thread), otherwise once SiteIsolationPolicy does
// actual blocking as opposed to just UMA logging this will bypass it.
threaded_data_receiver_->acceptData(data, data_length);
+
+ scoped_ptr<std::vector<char>> data_copy;
+ if (threaded_data_receiver_->needsMainthreadDataCopy()) {
+ data_copy.reset(new std::vector<char>(data, data + data_length));
+ }
+
+ main_thread_task_runner_->PostTask(FROM_HERE,
+ base::Bind(&ThreadedDataProvider::DataNotifyForegroundThread,
+ base::Unretained(this),
+ base::Passed(&data_copy),
+ data_length,
+ encoded_data_length));
+
ipc_channel_->Send(new ResourceHostMsg_DataReceived_ACK(request_id_));
}
+void ThreadedDataProvider::DataNotifyForegroundThread(
+ scoped_ptr<std::vector<char> > data_copy,
+ int data_length,
+ int encoded_data_length) {
+ if (data_copy) {
+ DCHECK(threaded_data_receiver_->needsMainthreadDataCopy());
+ DCHECK_EQ((size_t)data_length, data_copy->size());
+ }
+
+ threaded_data_receiver_->acceptMainthreadDataNotification(
+ (data_copy && !data_copy->empty()) ? &data_copy->front() : NULL,
+ data_length, encoded_data_length);
+}
+
} // namespace content
diff --git a/chromium/content/child/threaded_data_provider.h b/chromium/content/child/threaded_data_provider.h
index 27e6d6062e7..5cd7433021a 100644
--- a/chromium/content/child/threaded_data_provider.h
+++ b/chromium/content/child/threaded_data_provider.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_CHILD_THREADEDDATAPROVIDER_IMPL_H_
-#define CONTENT_CHILD_THREADEDDATAPROVIDER_IMPL_H_
+#ifndef CONTENT_CHILD_THREADED_DATA_PROVIDER_H_
+#define CONTENT_CHILD_THREADED_DATA_PROVIDER_H_
#include "base/compiler_specific.h"
#include "base/memory/linked_ptr.h"
@@ -14,6 +14,8 @@
#include "ipc/ipc_channel.h"
#include "ipc/message_filter.h"
+struct ResourceMsg_RequestCompleteData;
+
namespace blink {
class WebThreadedDataReceiver;
}
@@ -22,8 +24,12 @@ namespace IPC {
class SyncChannel;
}
+namespace scheduler {
+class WebThreadImplForWorkerScheduler;
+}
+
namespace content {
-class WebThreadImpl;
+class ResourceDispatcher;
class ThreadedDataProvider {
public:
@@ -31,9 +37,11 @@ class ThreadedDataProvider {
int request_id,
blink::WebThreadedDataReceiver* threaded_data_receiver,
linked_ptr<base::SharedMemory> shm_buffer,
- int shm_size);
- virtual ~ThreadedDataProvider();
+ int shm_size,
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_);
+ // Any destruction of this class has to bounce via the background thread to
+ // ensure all data is flushed; call Stop() to start this process.
void Stop();
void OnReceivedDataOnBackgroundThread(int data_offset,
int data_length,
@@ -44,11 +52,28 @@ class ThreadedDataProvider {
int encoded_data_length);
void OnResourceMessageFilterAddedMainThread();
+ void OnRequestCompleteForegroundThread(
+ base::WeakPtr<ResourceDispatcher> resource_dispatcher,
+ const ResourceMsg_RequestCompleteData& request_complete_data,
+ const base::TimeTicks& renderer_completion_time);
private:
+ ~ThreadedDataProvider();
+ void DestructOnMainThread();
+
void StopOnBackgroundThread();
void OnResourceMessageFilterAddedBackgroundThread();
- void ForwardAndACKData(const char* data, int data_length);
+ void OnRequestCompleteBackgroundThread(
+ base::WeakPtr<ResourceDispatcher> resource_dispatcher,
+ const ResourceMsg_RequestCompleteData& request_complete_data,
+ const base::TimeTicks& renderer_completion_time);
+ void ForwardAndACKData(const char* data,
+ int data_length,
+ int encoded_data_length);
+ void DataNotifyForegroundThread(
+ scoped_ptr<std::vector<char> > data_copy,
+ int data_length,
+ int encoded_data_length);
scoped_refptr<IPC::MessageFilter> filter_;
int request_id_;
@@ -56,15 +81,16 @@ class ThreadedDataProvider {
int shm_size_;
scoped_ptr<base::WeakPtrFactory<ThreadedDataProvider> >
background_thread_weak_factory_;
- WebThreadImpl& background_thread_;
+ scheduler::WebThreadImplForWorkerScheduler& background_thread_;
IPC::SyncChannel* ipc_channel_;
blink::WebThreadedDataReceiver* threaded_data_receiver_;
bool resource_filter_active_;
- base::MessageLoop* main_thread_message_loop_;
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
struct QueuedSharedMemoryData {
const char* data;
int length;
+ int encoded_length;
};
std::vector<QueuedSharedMemoryData> queued_data_;
@@ -76,4 +102,4 @@ class ThreadedDataProvider {
} // namespace content
-#endif // CONTENT_CHILD_THREADEDDATAPROVIDER_IMPL_H_
+#endif // CONTENT_CHILD_THREADED_DATA_PROVIDER_H_
diff --git a/chromium/content/child/v8_value_converter_impl.cc b/chromium/content/child/v8_value_converter_impl.cc
new file mode 100644
index 00000000000..fd36cf287c5
--- /dev/null
+++ b/chromium/content/child/v8_value_converter_impl.cc
@@ -0,0 +1,557 @@
+// 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/child/v8_value_converter_impl.h"
+
+#include <cmath>
+#include <string>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+#include "third_party/WebKit/public/web/WebArrayBuffer.h"
+#include "third_party/WebKit/public/web/WebArrayBufferConverter.h"
+#include "third_party/WebKit/public/web/WebArrayBufferView.h"
+#include "v8/include/v8.h"
+
+namespace content {
+
+// Default implementation of V8ValueConverter::Strategy
+
+bool V8ValueConverter::Strategy::FromV8Object(
+ v8::Local<v8::Object> value,
+ base::Value** out,
+ v8::Isolate* isolate,
+ const FromV8ValueCallback& callback) const {
+ return false;
+}
+
+bool V8ValueConverter::Strategy::FromV8Array(
+ v8::Local<v8::Array> value,
+ base::Value** out,
+ v8::Isolate* isolate,
+ const FromV8ValueCallback& callback) const {
+ return false;
+}
+
+bool V8ValueConverter::Strategy::FromV8ArrayBuffer(v8::Local<v8::Object> value,
+ base::Value** out,
+ v8::Isolate* isolate) const {
+ return false;
+}
+
+bool V8ValueConverter::Strategy::FromV8Number(v8::Local<v8::Number> value,
+ base::Value** out) const {
+ return false;
+}
+
+bool V8ValueConverter::Strategy::FromV8Undefined(base::Value** out) const {
+ return false;
+}
+
+
+namespace {
+
+// For the sake of the storage API, make this quite large.
+const int kMaxRecursionDepth = 100;
+
+} // namespace
+
+// The state of a call to FromV8Value.
+class V8ValueConverterImpl::FromV8ValueState {
+ public:
+ // Level scope which updates the current depth of some FromV8ValueState.
+ class Level {
+ public:
+ explicit Level(FromV8ValueState* state) : state_(state) {
+ state_->max_recursion_depth_--;
+ }
+ ~Level() {
+ state_->max_recursion_depth_++;
+ }
+
+ private:
+ FromV8ValueState* state_;
+ };
+
+ explicit FromV8ValueState(bool avoid_identity_hash_for_testing)
+ : max_recursion_depth_(kMaxRecursionDepth),
+ avoid_identity_hash_for_testing_(avoid_identity_hash_for_testing) {}
+
+ // If |handle| is not in |unique_map_|, then add it to |unique_map_| and
+ // return true.
+ //
+ // Otherwise do nothing and return false. Here "A is unique" means that no
+ // other handle B in the map points to the same object as A. Note that A can
+ // be unique even if there already is another handle with the same identity
+ // hash (key) in the map, because two objects can have the same hash.
+ bool UpdateAndCheckUniqueness(v8::Local<v8::Object> handle) {
+ typedef HashToHandleMap::const_iterator Iterator;
+ int hash = avoid_identity_hash_for_testing_ ? 0 : handle->GetIdentityHash();
+ // We only compare using == with handles to objects with the same identity
+ // hash. Different hash obviously means different objects, but two objects
+ // in a couple of thousands could have the same identity hash.
+ std::pair<Iterator, Iterator> range = unique_map_.equal_range(hash);
+ for (Iterator it = range.first; it != range.second; ++it) {
+ // Operator == for handles actually compares the underlying objects.
+ if (it->second == handle)
+ return false;
+ }
+ unique_map_.insert(std::make_pair(hash, handle));
+ return true;
+ }
+
+ bool HasReachedMaxRecursionDepth() {
+ return max_recursion_depth_ < 0;
+ }
+
+ private:
+ typedef std::multimap<int, v8::Local<v8::Object> > HashToHandleMap;
+ HashToHandleMap unique_map_;
+
+ int max_recursion_depth_;
+
+ bool avoid_identity_hash_for_testing_;
+};
+
+V8ValueConverter* V8ValueConverter::create() {
+ return new V8ValueConverterImpl();
+}
+
+V8ValueConverterImpl::V8ValueConverterImpl()
+ : date_allowed_(false),
+ reg_exp_allowed_(false),
+ function_allowed_(false),
+ strip_null_from_objects_(false),
+ avoid_identity_hash_for_testing_(false),
+ strategy_(NULL) {}
+
+void V8ValueConverterImpl::SetDateAllowed(bool val) {
+ date_allowed_ = val;
+}
+
+void V8ValueConverterImpl::SetRegExpAllowed(bool val) {
+ reg_exp_allowed_ = val;
+}
+
+void V8ValueConverterImpl::SetFunctionAllowed(bool val) {
+ function_allowed_ = val;
+}
+
+void V8ValueConverterImpl::SetStripNullFromObjects(bool val) {
+ strip_null_from_objects_ = val;
+}
+
+void V8ValueConverterImpl::SetStrategy(Strategy* strategy) {
+ strategy_ = strategy;
+}
+
+v8::Local<v8::Value> V8ValueConverterImpl::ToV8Value(
+ const base::Value* value, v8::Local<v8::Context> context) const {
+ v8::Context::Scope context_scope(context);
+ v8::EscapableHandleScope handle_scope(context->GetIsolate());
+ return handle_scope.Escape(
+ ToV8ValueImpl(context->GetIsolate(), context->Global(), value));
+}
+
+base::Value* V8ValueConverterImpl::FromV8Value(
+ v8::Local<v8::Value> val,
+ v8::Local<v8::Context> context) const {
+ v8::Context::Scope context_scope(context);
+ v8::HandleScope handle_scope(context->GetIsolate());
+ FromV8ValueState state(avoid_identity_hash_for_testing_);
+ return FromV8ValueImpl(&state, val, context->GetIsolate());
+}
+
+v8::Local<v8::Value> V8ValueConverterImpl::ToV8ValueImpl(
+ v8::Isolate* isolate,
+ v8::Local<v8::Object> creation_context,
+ const base::Value* value) const {
+ CHECK(value);
+ switch (value->GetType()) {
+ case base::Value::TYPE_NULL:
+ return v8::Null(isolate);
+
+ case base::Value::TYPE_BOOLEAN: {
+ bool val = false;
+ CHECK(value->GetAsBoolean(&val));
+ return v8::Boolean::New(isolate, val);
+ }
+
+ case base::Value::TYPE_INTEGER: {
+ int val = 0;
+ CHECK(value->GetAsInteger(&val));
+ return v8::Integer::New(isolate, val);
+ }
+
+ case base::Value::TYPE_DOUBLE: {
+ double val = 0.0;
+ CHECK(value->GetAsDouble(&val));
+ return v8::Number::New(isolate, val);
+ }
+
+ case base::Value::TYPE_STRING: {
+ std::string val;
+ CHECK(value->GetAsString(&val));
+ return v8::String::NewFromUtf8(
+ isolate, val.c_str(), v8::String::kNormalString, val.length());
+ }
+
+ case base::Value::TYPE_LIST:
+ return ToV8Array(isolate,
+ creation_context,
+ static_cast<const base::ListValue*>(value));
+
+ case base::Value::TYPE_DICTIONARY:
+ return ToV8Object(isolate,
+ creation_context,
+ static_cast<const base::DictionaryValue*>(value));
+
+ case base::Value::TYPE_BINARY:
+ return ToArrayBuffer(isolate,
+ creation_context,
+ static_cast<const base::BinaryValue*>(value));
+
+ default:
+ LOG(ERROR) << "Unexpected value type: " << value->GetType();
+ return v8::Null(isolate);
+ }
+}
+
+v8::Local<v8::Value> V8ValueConverterImpl::ToV8Array(
+ v8::Isolate* isolate,
+ v8::Local<v8::Object> creation_context,
+ const base::ListValue* val) const {
+ v8::Local<v8::Array> result(v8::Array::New(isolate, val->GetSize()));
+
+ for (size_t i = 0; i < val->GetSize(); ++i) {
+ const base::Value* child = NULL;
+ CHECK(val->Get(i, &child));
+
+ v8::Local<v8::Value> child_v8 =
+ ToV8ValueImpl(isolate, creation_context, child);
+ CHECK(!child_v8.IsEmpty());
+
+ v8::TryCatch try_catch;
+ result->Set(static_cast<uint32>(i), child_v8);
+ if (try_catch.HasCaught())
+ LOG(ERROR) << "Setter for index " << i << " threw an exception.";
+ }
+
+ return result;
+}
+
+v8::Local<v8::Value> V8ValueConverterImpl::ToV8Object(
+ v8::Isolate* isolate,
+ v8::Local<v8::Object> creation_context,
+ const base::DictionaryValue* val) const {
+ v8::Local<v8::Object> result(v8::Object::New(isolate));
+
+ for (base::DictionaryValue::Iterator iter(*val);
+ !iter.IsAtEnd(); iter.Advance()) {
+ const std::string& key = iter.key();
+ v8::Local<v8::Value> child_v8 =
+ ToV8ValueImpl(isolate, creation_context, &iter.value());
+ CHECK(!child_v8.IsEmpty());
+
+ v8::TryCatch try_catch;
+ result->Set(
+ v8::String::NewFromUtf8(
+ isolate, key.c_str(), v8::String::kNormalString, key.length()),
+ child_v8);
+ if (try_catch.HasCaught()) {
+ LOG(ERROR) << "Setter for property " << key.c_str() << " threw an "
+ << "exception.";
+ }
+ }
+
+ return result;
+}
+
+v8::Local<v8::Value> V8ValueConverterImpl::ToArrayBuffer(
+ v8::Isolate* isolate,
+ v8::Local<v8::Object> creation_context,
+ const base::BinaryValue* value) const {
+ blink::WebArrayBuffer buffer =
+ blink::WebArrayBuffer::create(value->GetSize(), 1);
+ memcpy(buffer.data(), value->GetBuffer(), value->GetSize());
+ return blink::WebArrayBufferConverter::toV8Value(
+ &buffer, creation_context, isolate);
+}
+
+base::Value* V8ValueConverterImpl::FromV8ValueImpl(
+ FromV8ValueState* state,
+ v8::Local<v8::Value> val,
+ v8::Isolate* isolate) const {
+ CHECK(!val.IsEmpty());
+
+ FromV8ValueState::Level state_level(state);
+ if (state->HasReachedMaxRecursionDepth())
+ return NULL;
+
+ if (val->IsNull())
+ return base::Value::CreateNullValue().release();
+
+ if (val->IsBoolean())
+ return new base::FundamentalValue(val->ToBoolean(isolate)->Value());
+
+ if (val->IsNumber() && strategy_) {
+ base::Value* out = NULL;
+ if (strategy_->FromV8Number(val.As<v8::Number>(), &out))
+ return out;
+ }
+
+ if (val->IsInt32())
+ return new base::FundamentalValue(val->ToInt32(isolate)->Value());
+
+ if (val->IsNumber()) {
+ double val_as_double = val.As<v8::Number>()->Value();
+ if (!std::isfinite(val_as_double))
+ return NULL;
+ return new base::FundamentalValue(val_as_double);
+ }
+
+ if (val->IsString()) {
+ v8::String::Utf8Value utf8(val);
+ return new base::StringValue(std::string(*utf8, utf8.length()));
+ }
+
+ if (val->IsUndefined()) {
+ if (strategy_) {
+ base::Value* out = NULL;
+ if (strategy_->FromV8Undefined(&out))
+ return out;
+ }
+ // JSON.stringify ignores undefined.
+ return NULL;
+ }
+
+ if (val->IsDate()) {
+ if (!date_allowed_)
+ // JSON.stringify would convert this to a string, but an object is more
+ // consistent within this class.
+ return FromV8Object(val->ToObject(isolate), state, isolate);
+ v8::Date* date = v8::Date::Cast(*val);
+ return new base::FundamentalValue(date->ValueOf() / 1000.0);
+ }
+
+ if (val->IsRegExp()) {
+ if (!reg_exp_allowed_)
+ // JSON.stringify converts to an object.
+ return FromV8Object(val.As<v8::Object>(), state, isolate);
+ return new base::StringValue(*v8::String::Utf8Value(val));
+ }
+
+ // v8::Value doesn't have a ToArray() method for some reason.
+ if (val->IsArray())
+ return FromV8Array(val.As<v8::Array>(), state, isolate);
+
+ if (val->IsFunction()) {
+ if (!function_allowed_)
+ // JSON.stringify refuses to convert function(){}.
+ return NULL;
+ return FromV8Object(val.As<v8::Object>(), state, isolate);
+ }
+
+ if (val->IsArrayBuffer() || val->IsArrayBufferView())
+ return FromV8ArrayBuffer(val.As<v8::Object>(), isolate);
+
+ if (val->IsObject())
+ return FromV8Object(val.As<v8::Object>(), state, isolate);
+
+ LOG(ERROR) << "Unexpected v8 value type encountered.";
+ return NULL;
+}
+
+base::Value* V8ValueConverterImpl::FromV8Array(
+ v8::Local<v8::Array> val,
+ FromV8ValueState* state,
+ v8::Isolate* isolate) const {
+ if (!state->UpdateAndCheckUniqueness(val))
+ return base::Value::CreateNullValue().release();
+
+ scoped_ptr<v8::Context::Scope> scope;
+ // If val was created in a different context than our current one, change to
+ // that context, but change back after val is converted.
+ if (!val->CreationContext().IsEmpty() &&
+ val->CreationContext() != isolate->GetCurrentContext())
+ scope.reset(new v8::Context::Scope(val->CreationContext()));
+
+ if (strategy_) {
+ // These base::Unretained's are safe, because Strategy::FromV8Value should
+ // be synchronous, so this object can't be out of scope.
+ V8ValueConverter::Strategy::FromV8ValueCallback callback =
+ base::Bind(&V8ValueConverterImpl::FromV8ValueImpl,
+ base::Unretained(this),
+ base::Unretained(state));
+ base::Value* out = NULL;
+ if (strategy_->FromV8Array(val, &out, isolate, callback))
+ return out;
+ }
+
+ base::ListValue* result = new base::ListValue();
+
+ // Only fields with integer keys are carried over to the ListValue.
+ for (uint32 i = 0; i < val->Length(); ++i) {
+ v8::TryCatch try_catch;
+ v8::Local<v8::Value> child_v8 = val->Get(i);
+ if (try_catch.HasCaught()) {
+ LOG(ERROR) << "Getter for index " << i << " threw an exception.";
+ child_v8 = v8::Null(isolate);
+ }
+
+ if (!val->HasRealIndexedProperty(i)) {
+ result->Append(base::Value::CreateNullValue());
+ continue;
+ }
+
+ base::Value* child = FromV8ValueImpl(state, child_v8, isolate);
+ if (child)
+ result->Append(child);
+ else
+ // JSON.stringify puts null in places where values don't serialize, for
+ // example undefined and functions. Emulate that behavior.
+ result->Append(base::Value::CreateNullValue());
+ }
+ return result;
+}
+
+base::Value* V8ValueConverterImpl::FromV8ArrayBuffer(
+ v8::Local<v8::Object> val,
+ v8::Isolate* isolate) const {
+ if (strategy_) {
+ base::Value* out = NULL;
+ if (strategy_->FromV8ArrayBuffer(val, &out, isolate))
+ return out;
+ }
+
+ char* data = NULL;
+ size_t length = 0;
+
+ scoped_ptr<blink::WebArrayBuffer> array_buffer(
+ blink::WebArrayBufferConverter::createFromV8Value(val, isolate));
+ scoped_ptr<blink::WebArrayBufferView> view;
+ if (array_buffer) {
+ data = reinterpret_cast<char*>(array_buffer->data());
+ length = array_buffer->byteLength();
+ } else {
+ view.reset(blink::WebArrayBufferView::createFromV8Value(val));
+ if (view) {
+ data = reinterpret_cast<char*>(view->baseAddress()) + view->byteOffset();
+ length = view->byteLength();
+ }
+ }
+
+ if (data)
+ return base::BinaryValue::CreateWithCopiedBuffer(data, length);
+ else
+ return NULL;
+}
+
+base::Value* V8ValueConverterImpl::FromV8Object(
+ v8::Local<v8::Object> val,
+ FromV8ValueState* state,
+ v8::Isolate* isolate) const {
+ if (!state->UpdateAndCheckUniqueness(val))
+ return base::Value::CreateNullValue().release();
+
+ scoped_ptr<v8::Context::Scope> scope;
+ // If val was created in a different context than our current one, change to
+ // that context, but change back after val is converted.
+ if (!val->CreationContext().IsEmpty() &&
+ val->CreationContext() != isolate->GetCurrentContext())
+ scope.reset(new v8::Context::Scope(val->CreationContext()));
+
+ if (strategy_) {
+ // These base::Unretained's are safe, because Strategy::FromV8Value should
+ // be synchronous, so this object can't be out of scope.
+ V8ValueConverter::Strategy::FromV8ValueCallback callback =
+ base::Bind(&V8ValueConverterImpl::FromV8ValueImpl,
+ base::Unretained(this),
+ base::Unretained(state));
+ base::Value* out = NULL;
+ if (strategy_->FromV8Object(val, &out, isolate, callback))
+ return out;
+ }
+
+ // Don't consider DOM objects. This check matches isHostObject() in Blink's
+ // bindings/v8/V8Binding.h used in structured cloning. It reads:
+ //
+ // If the object has any internal fields, then we won't be able to serialize
+ // or deserialize them; conveniently, this is also a quick way to detect DOM
+ // wrapper objects, because the mechanism for these relies on data stored in
+ // these fields.
+ //
+ // NOTE: check this after |strategy_| so that callers have a chance to
+ // do something else, such as convert to the node's name rather than NULL.
+ //
+ // ANOTHER NOTE: returning an empty dictionary here to minimise surprise.
+ // See also http://crbug.com/330559.
+ if (val->InternalFieldCount())
+ return new base::DictionaryValue();
+
+ scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue());
+ v8::Local<v8::Array> property_names(val->GetOwnPropertyNames());
+
+ for (uint32 i = 0; i < property_names->Length(); ++i) {
+ v8::Local<v8::Value> key(property_names->Get(i));
+
+ // Extend this test to cover more types as necessary and if sensible.
+ if (!key->IsString() &&
+ !key->IsNumber()) {
+ NOTREACHED() << "Key \"" << *v8::String::Utf8Value(key) << "\" "
+ "is neither a string nor a number";
+ continue;
+ }
+
+ v8::String::Utf8Value name_utf8(key);
+
+ v8::TryCatch try_catch;
+ v8::Local<v8::Value> child_v8 = val->Get(key);
+
+ if (try_catch.HasCaught()) {
+ LOG(WARNING) << "Getter for property " << *name_utf8
+ << " threw an exception.";
+ child_v8 = v8::Null(isolate);
+ }
+
+ scoped_ptr<base::Value> child(FromV8ValueImpl(state, child_v8, isolate));
+ if (!child)
+ // JSON.stringify skips properties whose values don't serialize, for
+ // example undefined and functions. Emulate that behavior.
+ continue;
+
+ // Strip null if asked (and since undefined is turned into null, undefined
+ // too). The use case for supporting this is JSON-schema support,
+ // specifically for extensions, where "optional" JSON properties may be
+ // represented as null, yet due to buggy legacy code elsewhere isn't
+ // treated as such (potentially causing crashes). For example, the
+ // "tabs.create" function takes an object as its first argument with an
+ // optional "windowId" property.
+ //
+ // Given just
+ //
+ // tabs.create({})
+ //
+ // this will work as expected on code that only checks for the existence of
+ // a "windowId" property (such as that legacy code). However given
+ //
+ // tabs.create({windowId: null})
+ //
+ // there *is* a "windowId" property, but since it should be an int, code
+ // on the browser which doesn't additionally check for null will fail.
+ // We can avoid all bugs related to this by stripping null.
+ if (strip_null_from_objects_ && child->IsType(base::Value::TYPE_NULL))
+ continue;
+
+ result->SetWithoutPathExpansion(std::string(*name_utf8, name_utf8.length()),
+ child.release());
+ }
+
+ return result.release();
+}
+
+} // namespace content
diff --git a/chromium/content/child/v8_value_converter_impl.h b/chromium/content/child/v8_value_converter_impl.h
new file mode 100644
index 00000000000..dcb4fff9966
--- /dev/null
+++ b/chromium/content/child/v8_value_converter_impl.h
@@ -0,0 +1,98 @@
+// 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_CHILD_V8_VALUE_CONVERTER_IMPL_H_
+#define CONTENT_CHILD_V8_VALUE_CONVERTER_IMPL_H_
+
+#include <map>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "content/common/content_export.h"
+#include "content/public/child/v8_value_converter.h"
+
+namespace base {
+class BinaryValue;
+class DictionaryValue;
+class ListValue;
+class Value;
+}
+
+namespace content {
+
+class CONTENT_EXPORT V8ValueConverterImpl : public V8ValueConverter {
+ public:
+ V8ValueConverterImpl();
+
+ // V8ValueConverter implementation.
+ void SetDateAllowed(bool val) override;
+ void SetRegExpAllowed(bool val) override;
+ void SetFunctionAllowed(bool val) override;
+ void SetStripNullFromObjects(bool val) override;
+ void SetStrategy(Strategy* strategy) override;
+ v8::Local<v8::Value> ToV8Value(
+ const base::Value* value,
+ v8::Local<v8::Context> context) const override;
+ base::Value* FromV8Value(v8::Local<v8::Value> value,
+ v8::Local<v8::Context> context) const override;
+
+ private:
+ friend class ScopedAvoidIdentityHashForTesting;
+
+ class FromV8ValueState;
+
+ v8::Local<v8::Value> ToV8ValueImpl(v8::Isolate* isolate,
+ v8::Local<v8::Object> creation_context,
+ const base::Value* value) const;
+ v8::Local<v8::Value> ToV8Array(v8::Isolate* isolate,
+ v8::Local<v8::Object> creation_context,
+ const base::ListValue* list) const;
+ v8::Local<v8::Value> ToV8Object(
+ v8::Isolate* isolate,
+ v8::Local<v8::Object> creation_context,
+ const base::DictionaryValue* dictionary) const;
+ v8::Local<v8::Value> ToArrayBuffer(v8::Isolate* isolate,
+ v8::Local<v8::Object> creation_context,
+ const base::BinaryValue* value) const;
+
+ base::Value* FromV8ValueImpl(FromV8ValueState* state,
+ v8::Local<v8::Value> value,
+ v8::Isolate* isolate) const;
+ base::Value* FromV8Array(v8::Local<v8::Array> array,
+ FromV8ValueState* state,
+ v8::Isolate* isolate) const;
+
+ // This will convert objects of type ArrayBuffer or any of the
+ // ArrayBufferView subclasses.
+ base::Value* FromV8ArrayBuffer(v8::Local<v8::Object> val,
+ v8::Isolate* isolate) const;
+
+ base::Value* FromV8Object(v8::Local<v8::Object> object,
+ FromV8ValueState* state,
+ v8::Isolate* isolate) const;
+
+ // If true, we will convert Date JavaScript objects to doubles.
+ bool date_allowed_;
+
+ // If true, we will convert RegExp JavaScript objects to string.
+ bool reg_exp_allowed_;
+
+ // If true, we will convert Function JavaScript objects to dictionaries.
+ bool function_allowed_;
+
+ // If true, undefined and null values are ignored when converting v8 objects
+ // into Values.
+ bool strip_null_from_objects_;
+
+ bool avoid_identity_hash_for_testing_;
+
+ // Strategy object that changes the converter's behavior.
+ Strategy* strategy_;
+
+ DISALLOW_COPY_AND_ASSIGN(V8ValueConverterImpl);
+};
+
+} // namespace content
+
+#endif // CONTENT_CHILD_V8_VALUE_CONVERTER_IMPL_H_
diff --git a/chromium/content/child/v8_value_converter_impl_unittest.cc b/chromium/content/child/v8_value_converter_impl_unittest.cc
new file mode 100644
index 00000000000..349dbe9ac9f
--- /dev/null
+++ b/chromium/content/child/v8_value_converter_impl_unittest.cc
@@ -0,0 +1,875 @@
+// 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 <cmath>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/stl_util.h"
+#include "base/test/values_test_util.h"
+#include "base/values.h"
+#include "content/child/v8_value_converter_impl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "v8/include/v8.h"
+
+namespace content {
+
+// To improve the performance of
+// V8ValueConverterImpl::UpdateAndCheckUniqueness, identity hashes of objects
+// are used during checking for duplicates. For testing purposes we need to
+// ignore the hash sometimes. Create this helper object to avoid using identity
+// hashes for the lifetime of the helper.
+class ScopedAvoidIdentityHashForTesting {
+ public:
+ // The hashes will be ignored in |converter|, which must not be NULL and it
+ // must outlive the created instance of this helper.
+ explicit ScopedAvoidIdentityHashForTesting(
+ content::V8ValueConverterImpl* converter);
+ ~ScopedAvoidIdentityHashForTesting();
+
+ private:
+ content::V8ValueConverterImpl* converter_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedAvoidIdentityHashForTesting);
+};
+
+ScopedAvoidIdentityHashForTesting::ScopedAvoidIdentityHashForTesting(
+ content::V8ValueConverterImpl* converter)
+ : converter_(converter) {
+ CHECK(converter_);
+ converter_->avoid_identity_hash_for_testing_ = true;
+}
+
+ScopedAvoidIdentityHashForTesting::~ScopedAvoidIdentityHashForTesting() {
+ converter_->avoid_identity_hash_for_testing_ = false;
+}
+
+class V8ValueConverterImplTest : public testing::Test {
+ public:
+ V8ValueConverterImplTest()
+ : isolate_(v8::Isolate::GetCurrent()) {
+ }
+
+ protected:
+ void SetUp() override {
+ v8::HandleScope handle_scope(isolate_);
+ v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate_);
+ context_.Reset(isolate_, v8::Context::New(isolate_, NULL, global));
+ }
+
+ void TearDown() override { context_.Reset(); }
+
+ std::string GetString(base::DictionaryValue* value, const std::string& key) {
+ std::string temp;
+ if (!value->GetString(key, &temp)) {
+ ADD_FAILURE();
+ return std::string();
+ }
+ return temp;
+ }
+
+ std::string GetString(v8::Local<v8::Object> value, const std::string& key) {
+ v8::Local<v8::String> temp =
+ value->Get(v8::String::NewFromUtf8(isolate_, key.c_str()))
+ .As<v8::String>();
+ if (temp.IsEmpty()) {
+ ADD_FAILURE();
+ return std::string();
+ }
+ v8::String::Utf8Value utf8(temp);
+ return std::string(*utf8, utf8.length());
+ }
+
+ std::string GetString(base::ListValue* value, uint32 index) {
+ std::string temp;
+ if (!value->GetString(static_cast<size_t>(index), &temp)) {
+ ADD_FAILURE();
+ return std::string();
+ }
+ return temp;
+ }
+
+ std::string GetString(v8::Local<v8::Array> value, uint32 index) {
+ v8::Local<v8::String> temp = value->Get(index).As<v8::String>();
+ if (temp.IsEmpty()) {
+ ADD_FAILURE();
+ return std::string();
+ }
+ v8::String::Utf8Value utf8(temp);
+ return std::string(*utf8, utf8.length());
+ }
+
+ bool IsNull(base::DictionaryValue* value, const std::string& key) {
+ base::Value* child = NULL;
+ if (!value->Get(key, &child)) {
+ ADD_FAILURE();
+ return false;
+ }
+ return child->GetType() == base::Value::TYPE_NULL;
+ }
+
+ bool IsNull(v8::Local<v8::Object> value, const std::string& key) {
+ v8::Local<v8::Value> child =
+ value->Get(v8::String::NewFromUtf8(isolate_, key.c_str()));
+ if (child.IsEmpty()) {
+ ADD_FAILURE();
+ return false;
+ }
+ return child->IsNull();
+ }
+
+ bool IsNull(base::ListValue* value, uint32 index) {
+ base::Value* child = NULL;
+ if (!value->Get(static_cast<size_t>(index), &child)) {
+ ADD_FAILURE();
+ return false;
+ }
+ return child->GetType() == base::Value::TYPE_NULL;
+ }
+
+ bool IsNull(v8::Local<v8::Array> value, uint32 index) {
+ v8::Local<v8::Value> child = value->Get(index);
+ if (child.IsEmpty()) {
+ ADD_FAILURE();
+ return false;
+ }
+ return child->IsNull();
+ }
+
+ void TestWeirdType(const V8ValueConverterImpl& converter,
+ v8::Local<v8::Value> val,
+ base::Value::Type expected_type,
+ scoped_ptr<base::Value> expected_value) {
+ v8::Local<v8::Context> context =
+ v8::Local<v8::Context>::New(isolate_, context_);
+ scoped_ptr<base::Value> raw(converter.FromV8Value(val, context));
+
+ if (expected_value) {
+ ASSERT_TRUE(raw.get());
+ EXPECT_TRUE(expected_value->Equals(raw.get()));
+ EXPECT_EQ(expected_type, raw->GetType());
+ } else {
+ EXPECT_FALSE(raw.get());
+ }
+
+ v8::Local<v8::Object> object(v8::Object::New(isolate_));
+ object->Set(v8::String::NewFromUtf8(isolate_, "test"), val);
+ scoped_ptr<base::DictionaryValue> dictionary(
+ static_cast<base::DictionaryValue*>(
+ converter.FromV8Value(object, context)));
+ ASSERT_TRUE(dictionary.get());
+
+ if (expected_value) {
+ base::Value* temp = NULL;
+ ASSERT_TRUE(dictionary->Get("test", &temp));
+ EXPECT_EQ(expected_type, temp->GetType());
+ EXPECT_TRUE(expected_value->Equals(temp));
+ } else {
+ EXPECT_FALSE(dictionary->HasKey("test"));
+ }
+
+ v8::Local<v8::Array> array(v8::Array::New(isolate_));
+ array->Set(0, val);
+ scoped_ptr<base::ListValue> list(
+ static_cast<base::ListValue*>(converter.FromV8Value(array, context)));
+ ASSERT_TRUE(list.get());
+ if (expected_value) {
+ base::Value* temp = NULL;
+ ASSERT_TRUE(list->Get(0, &temp));
+ EXPECT_EQ(expected_type, temp->GetType());
+ EXPECT_TRUE(expected_value->Equals(temp));
+ } else {
+ // Arrays should preserve their length, and convert unconvertible
+ // types into null.
+ base::Value* temp = NULL;
+ ASSERT_TRUE(list->Get(0, &temp));
+ EXPECT_EQ(base::Value::TYPE_NULL, temp->GetType());
+ }
+ }
+
+ v8::Isolate* isolate_;
+
+ // Context for the JavaScript in the test.
+ v8::Persistent<v8::Context> context_;
+};
+
+TEST_F(V8ValueConverterImplTest, BasicRoundTrip) {
+ scoped_ptr<base::Value> original_root = base::test::ParseJson(
+ "{ \n"
+ " \"null\": null, \n"
+ " \"true\": true, \n"
+ " \"false\": false, \n"
+ " \"positive-int\": 42, \n"
+ " \"negative-int\": -42, \n"
+ " \"zero\": 0, \n"
+ " \"double\": 88.8, \n"
+ " \"big-integral-double\": 9007199254740992.0, \n" // 2.0^53
+ " \"string\": \"foobar\", \n"
+ " \"empty-string\": \"\", \n"
+ " \"dictionary\": { \n"
+ " \"foo\": \"bar\",\n"
+ " \"hot\": \"dog\",\n"
+ " }, \n"
+ " \"empty-dictionary\": {}, \n"
+ " \"list\": [ \"monkey\", \"balls\" ], \n"
+ " \"empty-list\": [], \n"
+ "}");
+
+ v8::HandleScope handle_scope(isolate_);
+ v8::Local<v8::Context> context =
+ v8::Local<v8::Context>::New(isolate_, context_);
+ v8::Context::Scope context_scope(context);
+
+ V8ValueConverterImpl converter;
+ v8::Local<v8::Object> v8_object =
+ converter.ToV8Value(original_root.get(), context).As<v8::Object>();
+ ASSERT_FALSE(v8_object.IsEmpty());
+
+ EXPECT_EQ(static_cast<const base::DictionaryValue&>(*original_root).size(),
+ v8_object->GetPropertyNames()->Length());
+ EXPECT_TRUE(
+ v8_object->Get(v8::String::NewFromUtf8(isolate_, "null"))->IsNull());
+ EXPECT_TRUE(
+ v8_object->Get(v8::String::NewFromUtf8(isolate_, "true"))->IsTrue());
+ EXPECT_TRUE(
+ v8_object->Get(v8::String::NewFromUtf8(isolate_, "false"))->IsFalse());
+ EXPECT_TRUE(v8_object->Get(v8::String::NewFromUtf8(isolate_, "positive-int"))
+ ->IsInt32());
+ EXPECT_TRUE(v8_object->Get(v8::String::NewFromUtf8(isolate_, "negative-int"))
+ ->IsInt32());
+ EXPECT_TRUE(
+ v8_object->Get(v8::String::NewFromUtf8(isolate_, "zero"))->IsInt32());
+ EXPECT_TRUE(
+ v8_object->Get(v8::String::NewFromUtf8(isolate_, "double"))->IsNumber());
+ EXPECT_TRUE(v8_object->Get(v8::String::NewFromUtf8(
+ isolate_, "big-integral-double"))->IsNumber());
+ EXPECT_TRUE(
+ v8_object->Get(v8::String::NewFromUtf8(isolate_, "string"))->IsString());
+ EXPECT_TRUE(v8_object->Get(v8::String::NewFromUtf8(isolate_, "empty-string"))
+ ->IsString());
+ EXPECT_TRUE(v8_object->Get(v8::String::NewFromUtf8(isolate_, "dictionary"))
+ ->IsObject());
+ EXPECT_TRUE(v8_object->Get(v8::String::NewFromUtf8(
+ isolate_, "empty-dictionary"))->IsObject());
+ EXPECT_TRUE(
+ v8_object->Get(v8::String::NewFromUtf8(isolate_, "list"))->IsArray());
+ EXPECT_TRUE(v8_object->Get(v8::String::NewFromUtf8(isolate_, "empty-list"))
+ ->IsArray());
+
+ scoped_ptr<base::Value> new_root(converter.FromV8Value(v8_object, context));
+ EXPECT_NE(original_root.get(), new_root.get());
+ EXPECT_TRUE(original_root->Equals(new_root.get()));
+}
+
+TEST_F(V8ValueConverterImplTest, KeysWithDots) {
+ scoped_ptr<base::Value> original =
+ base::test::ParseJson("{ \"foo.bar\": \"baz\" }");
+
+ v8::HandleScope handle_scope(isolate_);
+ v8::Local<v8::Context> context =
+ v8::Local<v8::Context>::New(isolate_, context_);
+ v8::Context::Scope context_scope(context);
+
+ V8ValueConverterImpl converter;
+ scoped_ptr<base::Value> copy(
+ converter.FromV8Value(
+ converter.ToV8Value(original.get(), context), context));
+
+ EXPECT_TRUE(original->Equals(copy.get()));
+}
+
+TEST_F(V8ValueConverterImplTest, ObjectExceptions) {
+ v8::HandleScope handle_scope(isolate_);
+ v8::Local<v8::Context> context =
+ v8::Local<v8::Context>::New(isolate_, context_);
+ v8::Context::Scope context_scope(context);
+
+ // Set up objects to throw when reading or writing 'foo'.
+ const char* source =
+ "Object.prototype.__defineSetter__('foo', "
+ " function() { throw new Error('muah!'); });"
+ "Object.prototype.__defineGetter__('foo', "
+ " function() { throw new Error('muah!'); });";
+
+ v8::Local<v8::Script> script(
+ v8::Script::Compile(v8::String::NewFromUtf8(isolate_, source)));
+ script->Run();
+
+ v8::Local<v8::Object> object(v8::Object::New(isolate_));
+ object->Set(v8::String::NewFromUtf8(isolate_, "bar"),
+ v8::String::NewFromUtf8(isolate_, "bar"));
+
+ // Converting from v8 value should replace the foo property with null.
+ V8ValueConverterImpl converter;
+ scoped_ptr<base::DictionaryValue> converted(
+ static_cast<base::DictionaryValue*>(
+ converter.FromV8Value(object, context)));
+ EXPECT_TRUE(converted.get());
+ // http://code.google.com/p/v8/issues/detail?id=1342
+ // EXPECT_EQ(2u, converted->size());
+ // EXPECT_TRUE(IsNull(converted.get(), "foo"));
+ EXPECT_EQ(1u, converted->size());
+ EXPECT_EQ("bar", GetString(converted.get(), "bar"));
+
+ // Converting to v8 value should drop the foo property.
+ converted->SetString("foo", "foo");
+ v8::Local<v8::Object> copy =
+ converter.ToV8Value(converted.get(), context).As<v8::Object>();
+ EXPECT_FALSE(copy.IsEmpty());
+ EXPECT_EQ(2u, copy->GetPropertyNames()->Length());
+ EXPECT_EQ("bar", GetString(copy, "bar"));
+}
+
+TEST_F(V8ValueConverterImplTest, ArrayExceptions) {
+ v8::HandleScope handle_scope(isolate_);
+ v8::Local<v8::Context> context =
+ v8::Local<v8::Context>::New(isolate_, context_);
+ v8::Context::Scope context_scope(context);
+
+ const char* source = "(function() {"
+ "var arr = [];"
+ "arr.__defineSetter__(0, "
+ " function() { throw new Error('muah!'); });"
+ "arr.__defineGetter__(0, "
+ " function() { throw new Error('muah!'); });"
+ "arr[1] = 'bar';"
+ "return arr;"
+ "})();";
+
+ v8::Local<v8::Script> script(
+ v8::Script::Compile(v8::String::NewFromUtf8(isolate_, source)));
+ v8::Local<v8::Array> array = script->Run().As<v8::Array>();
+ ASSERT_FALSE(array.IsEmpty());
+
+ // Converting from v8 value should replace the first item with null.
+ V8ValueConverterImpl converter;
+ scoped_ptr<base::ListValue> converted(static_cast<base::ListValue*>(
+ converter.FromV8Value(array, context)));
+ ASSERT_TRUE(converted.get());
+ // http://code.google.com/p/v8/issues/detail?id=1342
+ EXPECT_EQ(2u, converted->GetSize());
+ EXPECT_TRUE(IsNull(converted.get(), 0));
+
+ // Converting to v8 value should drop the first item and leave a hole.
+ converted.reset(static_cast<base::ListValue*>(
+ base::test::ParseJson("[ \"foo\", \"bar\" ]").release()));
+ v8::Local<v8::Array> copy =
+ converter.ToV8Value(converted.get(), context).As<v8::Array>();
+ ASSERT_FALSE(copy.IsEmpty());
+ EXPECT_EQ(2u, copy->Length());
+ EXPECT_EQ("bar", GetString(copy, 1));
+}
+
+TEST_F(V8ValueConverterImplTest, WeirdTypes) {
+ v8::HandleScope handle_scope(isolate_);
+ v8::Local<v8::Context> context =
+ v8::Local<v8::Context>::New(isolate_, context_);
+ v8::Context::Scope context_scope(context);
+
+ v8::Local<v8::RegExp> regex(v8::RegExp::New(
+ v8::String::NewFromUtf8(isolate_, "."), v8::RegExp::kNone));
+
+ V8ValueConverterImpl converter;
+ TestWeirdType(converter,
+ v8::Undefined(isolate_),
+ base::Value::TYPE_NULL, // Arbitrary type, result is NULL.
+ scoped_ptr<base::Value>());
+ TestWeirdType(converter,
+ v8::Date::New(isolate_, 1000),
+ base::Value::TYPE_DICTIONARY,
+ scoped_ptr<base::Value>(new base::DictionaryValue()));
+ TestWeirdType(converter,
+ regex,
+ base::Value::TYPE_DICTIONARY,
+ scoped_ptr<base::Value>(new base::DictionaryValue()));
+
+ converter.SetDateAllowed(true);
+ TestWeirdType(converter,
+ v8::Date::New(isolate_, 1000),
+ base::Value::TYPE_DOUBLE,
+ scoped_ptr<base::Value>(new base::FundamentalValue(1.0)));
+
+ converter.SetRegExpAllowed(true);
+ TestWeirdType(converter,
+ regex,
+ base::Value::TYPE_STRING,
+ scoped_ptr<base::Value>(new base::StringValue("/./")));
+}
+
+TEST_F(V8ValueConverterImplTest, Prototype) {
+ v8::HandleScope handle_scope(isolate_);
+ v8::Local<v8::Context> context =
+ v8::Local<v8::Context>::New(isolate_, context_);
+ v8::Context::Scope context_scope(context);
+
+ const char* source = "(function() {"
+ "Object.prototype.foo = 'foo';"
+ "return {};"
+ "})();";
+
+ v8::Local<v8::Script> script(
+ v8::Script::Compile(v8::String::NewFromUtf8(isolate_, source)));
+ v8::Local<v8::Object> object = script->Run().As<v8::Object>();
+ ASSERT_FALSE(object.IsEmpty());
+
+ V8ValueConverterImpl converter;
+ scoped_ptr<base::DictionaryValue> result(
+ static_cast<base::DictionaryValue*>(
+ converter.FromV8Value(object, context)));
+ ASSERT_TRUE(result.get());
+ EXPECT_EQ(0u, result->size());
+}
+
+TEST_F(V8ValueConverterImplTest, StripNullFromObjects) {
+ v8::HandleScope handle_scope(isolate_);
+ v8::Local<v8::Context> context =
+ v8::Local<v8::Context>::New(isolate_, context_);
+ v8::Context::Scope context_scope(context);
+
+ const char* source = "(function() {"
+ "return { foo: undefined, bar: null };"
+ "})();";
+
+ v8::Local<v8::Script> script(
+ v8::Script::Compile(v8::String::NewFromUtf8(isolate_, source)));
+ v8::Local<v8::Object> object = script->Run().As<v8::Object>();
+ ASSERT_FALSE(object.IsEmpty());
+
+ V8ValueConverterImpl converter;
+ converter.SetStripNullFromObjects(true);
+
+ scoped_ptr<base::DictionaryValue> result(
+ static_cast<base::DictionaryValue*>(
+ converter.FromV8Value(object, context)));
+ ASSERT_TRUE(result.get());
+ EXPECT_EQ(0u, result->size());
+}
+
+TEST_F(V8ValueConverterImplTest, RecursiveObjects) {
+ v8::HandleScope handle_scope(isolate_);
+ v8::Local<v8::Context> context =
+ v8::Local<v8::Context>::New(isolate_, context_);
+ v8::Context::Scope context_scope(context);
+
+ V8ValueConverterImpl converter;
+
+ v8::Local<v8::Object> object = v8::Object::New(isolate_).As<v8::Object>();
+ ASSERT_FALSE(object.IsEmpty());
+ object->Set(v8::String::NewFromUtf8(isolate_, "foo"),
+ v8::String::NewFromUtf8(isolate_, "bar"));
+ object->Set(v8::String::NewFromUtf8(isolate_, "obj"), object);
+
+ scoped_ptr<base::DictionaryValue> object_result(
+ static_cast<base::DictionaryValue*>(
+ converter.FromV8Value(object, context)));
+ ASSERT_TRUE(object_result.get());
+ EXPECT_EQ(2u, object_result->size());
+ EXPECT_TRUE(IsNull(object_result.get(), "obj"));
+
+ v8::Local<v8::Array> array = v8::Array::New(isolate_).As<v8::Array>();
+ ASSERT_FALSE(array.IsEmpty());
+ array->Set(0, v8::String::NewFromUtf8(isolate_, "1"));
+ array->Set(1, array);
+
+ scoped_ptr<base::ListValue> list_result(
+ static_cast<base::ListValue*>(converter.FromV8Value(array, context)));
+ ASSERT_TRUE(list_result.get());
+ EXPECT_EQ(2u, list_result->GetSize());
+ EXPECT_TRUE(IsNull(list_result.get(), 1));
+}
+
+TEST_F(V8ValueConverterImplTest, WeirdProperties) {
+ v8::HandleScope handle_scope(isolate_);
+ v8::Local<v8::Context> context =
+ v8::Local<v8::Context>::New(isolate_, context_);
+ v8::Context::Scope context_scope(context);
+
+ const char* source = "(function() {"
+ "return {"
+ "1: 'foo',"
+ "'2': 'bar',"
+ "true: 'baz',"
+ "false: 'qux',"
+ "null: 'quux',"
+ "undefined: 'oops'"
+ "};"
+ "})();";
+
+ v8::Local<v8::Script> script(
+ v8::Script::Compile(v8::String::NewFromUtf8(isolate_, source)));
+ v8::Local<v8::Object> object = script->Run().As<v8::Object>();
+ ASSERT_FALSE(object.IsEmpty());
+
+ V8ValueConverterImpl converter;
+ scoped_ptr<base::Value> actual(converter.FromV8Value(object, context));
+
+ scoped_ptr<base::Value> expected = base::test::ParseJson(
+ "{ \n"
+ " \"1\": \"foo\", \n"
+ " \"2\": \"bar\", \n"
+ " \"true\": \"baz\", \n"
+ " \"false\": \"qux\", \n"
+ " \"null\": \"quux\", \n"
+ " \"undefined\": \"oops\", \n"
+ "}");
+
+ EXPECT_TRUE(expected->Equals(actual.get()));
+}
+
+TEST_F(V8ValueConverterImplTest, ArrayGetters) {
+ v8::HandleScope handle_scope(isolate_);
+ v8::Local<v8::Context> context =
+ v8::Local<v8::Context>::New(isolate_, context_);
+ v8::Context::Scope context_scope(context);
+
+ const char* source = "(function() {"
+ "var a = [0];"
+ "a.__defineGetter__(1, function() { return 'bar'; });"
+ "return a;"
+ "})();";
+
+ v8::Local<v8::Script> script(
+ v8::Script::Compile(v8::String::NewFromUtf8(isolate_, source)));
+ v8::Local<v8::Array> array = script->Run().As<v8::Array>();
+ ASSERT_FALSE(array.IsEmpty());
+
+ V8ValueConverterImpl converter;
+ scoped_ptr<base::ListValue> result(
+ static_cast<base::ListValue*>(converter.FromV8Value(array, context)));
+ ASSERT_TRUE(result.get());
+ EXPECT_EQ(2u, result->GetSize());
+}
+
+TEST_F(V8ValueConverterImplTest, UndefinedValueBehavior) {
+ v8::HandleScope handle_scope(isolate_);
+ v8::Local<v8::Context> context =
+ v8::Local<v8::Context>::New(isolate_, context_);
+ v8::Context::Scope context_scope(context);
+
+ v8::Local<v8::Object> object;
+ {
+ const char* source = "(function() {"
+ "return { foo: undefined, bar: null, baz: function(){} };"
+ "})();";
+ v8::Local<v8::Script> script(
+ v8::Script::Compile(v8::String::NewFromUtf8(isolate_, source)));
+ object = script->Run().As<v8::Object>();
+ ASSERT_FALSE(object.IsEmpty());
+ }
+
+ v8::Local<v8::Array> array;
+ {
+ const char* source = "(function() {"
+ "return [ undefined, null, function(){} ];"
+ "})();";
+ v8::Local<v8::Script> script(
+ v8::Script::Compile(v8::String::NewFromUtf8(isolate_, source)));
+ array = script->Run().As<v8::Array>();
+ ASSERT_FALSE(array.IsEmpty());
+ }
+
+ v8::Local<v8::Array> sparse_array;
+ {
+ const char* source = "(function() {"
+ "return new Array(3);"
+ "})();";
+ v8::Local<v8::Script> script(
+ v8::Script::Compile(v8::String::NewFromUtf8(isolate_, source)));
+ sparse_array = script->Run().As<v8::Array>();
+ ASSERT_FALSE(sparse_array.IsEmpty());
+ }
+
+ V8ValueConverterImpl converter;
+
+ scoped_ptr<base::Value> actual_object(
+ converter.FromV8Value(object, context));
+ EXPECT_TRUE(base::Value::Equals(
+ base::test::ParseJson("{ \"bar\": null }").get(), actual_object.get()));
+
+ // Everything is null because JSON stringification preserves array length.
+ scoped_ptr<base::Value> actual_array(converter.FromV8Value(array, context));
+ EXPECT_TRUE(base::Value::Equals(
+ base::test::ParseJson("[ null, null, null ]").get(), actual_array.get()));
+
+ scoped_ptr<base::Value> actual_sparse_array(
+ converter.FromV8Value(sparse_array, context));
+ EXPECT_TRUE(
+ base::Value::Equals(base::test::ParseJson("[ null, null, null ]").get(),
+ actual_sparse_array.get()));
+}
+
+TEST_F(V8ValueConverterImplTest, ObjectsWithClashingIdentityHash) {
+ v8::HandleScope handle_scope(isolate_);
+ v8::Local<v8::Context> context =
+ v8::Local<v8::Context>::New(isolate_, context_);
+ v8::Context::Scope context_scope(context);
+ V8ValueConverterImpl converter;
+
+ // We check that the converter checks identity correctly by disabling the
+ // optimization of using identity hashes.
+ ScopedAvoidIdentityHashForTesting scoped_hash_avoider(&converter);
+
+ // Create the v8::Object to be converted.
+ v8::Local<v8::Array> root(v8::Array::New(isolate_, 4));
+ root->Set(0, v8::Local<v8::Object>(v8::Object::New(isolate_)));
+ root->Set(1, v8::Local<v8::Object>(v8::Object::New(isolate_)));
+ root->Set(2, v8::Local<v8::Object>(v8::Array::New(isolate_, 0)));
+ root->Set(3, v8::Local<v8::Object>(v8::Array::New(isolate_, 0)));
+
+ // The expected base::Value result.
+ scoped_ptr<base::Value> expected = base::test::ParseJson("[{},{},[],[]]");
+ ASSERT_TRUE(expected.get());
+
+ // The actual result.
+ scoped_ptr<base::Value> value(converter.FromV8Value(root, context));
+ ASSERT_TRUE(value.get());
+
+ EXPECT_TRUE(expected->Equals(value.get()));
+}
+
+TEST_F(V8ValueConverterImplTest, DetectCycles) {
+ v8::HandleScope handle_scope(isolate_);
+ v8::Local<v8::Context> context =
+ v8::Local<v8::Context>::New(isolate_, context_);
+ v8::Context::Scope context_scope(context);
+ V8ValueConverterImpl converter;
+
+ // Create a recursive array.
+ v8::Local<v8::Array> recursive_array(v8::Array::New(isolate_, 1));
+ recursive_array->Set(0, recursive_array);
+
+ // The first repetition should be trimmed and replaced by a null value.
+ base::ListValue expected_list;
+ expected_list.Append(base::Value::CreateNullValue());
+
+ // The actual result.
+ scoped_ptr<base::Value> actual_list(
+ converter.FromV8Value(recursive_array, context));
+ ASSERT_TRUE(actual_list.get());
+
+ EXPECT_TRUE(expected_list.Equals(actual_list.get()));
+
+ // Now create a recursive object
+ const std::string key("key");
+ v8::Local<v8::Object> recursive_object(v8::Object::New(isolate_));
+ v8::TryCatch try_catch;
+ recursive_object->Set(
+ v8::String::NewFromUtf8(
+ isolate_, key.c_str(), v8::String::kNormalString, key.length()),
+ recursive_object);
+ ASSERT_FALSE(try_catch.HasCaught());
+
+ // The first repetition should be trimmed and replaced by a null value.
+ base::DictionaryValue expected_dictionary;
+ expected_dictionary.Set(key, base::Value::CreateNullValue());
+
+ // The actual result.
+ scoped_ptr<base::Value> actual_dictionary(
+ converter.FromV8Value(recursive_object, context));
+ ASSERT_TRUE(actual_dictionary.get());
+
+ EXPECT_TRUE(expected_dictionary.Equals(actual_dictionary.get()));
+}
+
+TEST_F(V8ValueConverterImplTest, MaxRecursionDepth) {
+ v8::HandleScope handle_scope(isolate_);
+ v8::Local<v8::Context> context =
+ v8::Local<v8::Context>::New(isolate_, context_);
+ v8::Context::Scope context_scope(context);
+
+ // Must larger than kMaxRecursionDepth in v8_value_converter_impl.cc.
+ int kDepth = 1000;
+ const char kKey[] = "key";
+
+ v8::Local<v8::Object> deep_object = v8::Object::New(isolate_);
+
+ v8::Local<v8::Object> leaf = deep_object;
+ for (int i = 0; i < kDepth; ++i) {
+ v8::Local<v8::Object> new_object = v8::Object::New(isolate_);
+ leaf->Set(v8::String::NewFromUtf8(isolate_, kKey), new_object);
+ leaf = new_object;
+ }
+
+ V8ValueConverterImpl converter;
+ scoped_ptr<base::Value> value(converter.FromV8Value(deep_object, context));
+ ASSERT_TRUE(value);
+
+ // Expected depth is kMaxRecursionDepth in v8_value_converter_impl.cc.
+ int kExpectedDepth = 100;
+
+ base::Value* current = value.get();
+ for (int i = 1; i < kExpectedDepth; ++i) {
+ base::DictionaryValue* current_as_object = NULL;
+ ASSERT_TRUE(current->GetAsDictionary(&current_as_object)) << i;
+ ASSERT_TRUE(current_as_object->Get(kKey, &current)) << i;
+ }
+
+ // The leaf node shouldn't have any properties.
+ base::DictionaryValue empty;
+ EXPECT_TRUE(base::Value::Equals(&empty, current)) << *current;
+}
+
+class V8ValueConverterOverridingStrategyForTesting
+ : public V8ValueConverter::Strategy {
+ public:
+ V8ValueConverterOverridingStrategyForTesting()
+ : reference_value_(NewReferenceValue()) {}
+ bool FromV8Object(v8::Local<v8::Object> value,
+ base::Value** out,
+ v8::Isolate* isolate,
+ const FromV8ValueCallback& callback) const override {
+ *out = NewReferenceValue();
+ return true;
+ }
+ bool FromV8Array(v8::Local<v8::Array> value,
+ base::Value** out,
+ v8::Isolate* isolate,
+ const FromV8ValueCallback& callback) const override {
+ *out = NewReferenceValue();
+ return true;
+ }
+ bool FromV8ArrayBuffer(v8::Local<v8::Object> value,
+ base::Value** out,
+ v8::Isolate* isolate) const override {
+ *out = NewReferenceValue();
+ return true;
+ }
+ bool FromV8Number(v8::Local<v8::Number> value,
+ base::Value** out) const override {
+ *out = NewReferenceValue();
+ return true;
+ }
+ bool FromV8Undefined(base::Value** out) const override {
+ *out = NewReferenceValue();
+ return true;
+ }
+ base::Value* reference_value() const { return reference_value_.get(); }
+
+ private:
+ static base::Value* NewReferenceValue() {
+ return new base::StringValue("strategy");
+ }
+ scoped_ptr<base::Value> reference_value_;
+};
+
+TEST_F(V8ValueConverterImplTest, StrategyOverrides) {
+ v8::HandleScope handle_scope(isolate_);
+ v8::Local<v8::Context> context =
+ v8::Local<v8::Context>::New(isolate_, context_);
+ v8::Context::Scope context_scope(context);
+
+ V8ValueConverterImpl converter;
+ V8ValueConverterOverridingStrategyForTesting strategy;
+ converter.SetStrategy(&strategy);
+
+ v8::Local<v8::Object> object(v8::Object::New(isolate_));
+ scoped_ptr<base::Value> object_value(converter.FromV8Value(object, context));
+ ASSERT_TRUE(object_value);
+ EXPECT_TRUE(
+ base::Value::Equals(strategy.reference_value(), object_value.get()));
+
+ v8::Local<v8::Array> array(v8::Array::New(isolate_));
+ scoped_ptr<base::Value> array_value(converter.FromV8Value(array, context));
+ ASSERT_TRUE(array_value);
+ EXPECT_TRUE(
+ base::Value::Equals(strategy.reference_value(), array_value.get()));
+
+ v8::Local<v8::ArrayBuffer> array_buffer(v8::ArrayBuffer::New(isolate_, 0));
+ scoped_ptr<base::Value> array_buffer_value(
+ converter.FromV8Value(array_buffer, context));
+ ASSERT_TRUE(array_buffer_value);
+ EXPECT_TRUE(base::Value::Equals(strategy.reference_value(),
+ array_buffer_value.get()));
+
+ v8::Local<v8::ArrayBufferView> array_buffer_view(
+ v8::Uint8Array::New(array_buffer, 0, 0));
+ scoped_ptr<base::Value> array_buffer_view_value(
+ converter.FromV8Value(array_buffer_view, context));
+ ASSERT_TRUE(array_buffer_view_value);
+ EXPECT_TRUE(base::Value::Equals(strategy.reference_value(),
+ array_buffer_view_value.get()));
+
+ v8::Local<v8::Number> number(v8::Number::New(isolate_, 0.0));
+ scoped_ptr<base::Value> number_value(converter.FromV8Value(number, context));
+ ASSERT_TRUE(number_value);
+ EXPECT_TRUE(
+ base::Value::Equals(strategy.reference_value(), number_value.get()));
+
+ v8::Local<v8::Primitive> undefined(v8::Undefined(isolate_));
+ scoped_ptr<base::Value> undefined_value(
+ converter.FromV8Value(undefined, context));
+ ASSERT_TRUE(undefined_value);
+ EXPECT_TRUE(
+ base::Value::Equals(strategy.reference_value(), undefined_value.get()));
+}
+
+class V8ValueConverterBypassStrategyForTesting
+ : public V8ValueConverter::Strategy {
+ public:
+ bool FromV8Object(v8::Local<v8::Object> value,
+ base::Value** out,
+ v8::Isolate* isolate,
+ const FromV8ValueCallback& callback) const override {
+ return false;
+ }
+ bool FromV8Array(v8::Local<v8::Array> value,
+ base::Value** out,
+ v8::Isolate* isolate,
+ const FromV8ValueCallback& callback) const override {
+ return false;
+ }
+ bool FromV8ArrayBuffer(v8::Local<v8::Object> value,
+ base::Value** out,
+ v8::Isolate* isolate) const override {
+ return false;
+ }
+ bool FromV8Number(v8::Local<v8::Number> value,
+ base::Value** out) const override {
+ return false;
+ }
+ bool FromV8Undefined(base::Value** out) const override { return false; }
+};
+
+// Verify that having a strategy that fallbacks to default behaviour
+// actually preserves it.
+TEST_F(V8ValueConverterImplTest, StrategyBypass) {
+ v8::HandleScope handle_scope(isolate_);
+ v8::Local<v8::Context> context =
+ v8::Local<v8::Context>::New(isolate_, context_);
+ v8::Context::Scope context_scope(context);
+
+ V8ValueConverterImpl converter;
+ V8ValueConverterBypassStrategyForTesting strategy;
+ converter.SetStrategy(&strategy);
+
+ v8::Local<v8::Object> object(v8::Object::New(isolate_));
+ scoped_ptr<base::Value> object_value(converter.FromV8Value(object, context));
+ ASSERT_TRUE(object_value);
+ scoped_ptr<base::Value> reference_object_value(base::test::ParseJson("{}"));
+ EXPECT_TRUE(
+ base::Value::Equals(reference_object_value.get(), object_value.get()));
+
+ v8::Local<v8::Array> array(v8::Array::New(isolate_));
+ scoped_ptr<base::Value> array_value(converter.FromV8Value(array, context));
+ ASSERT_TRUE(array_value);
+ scoped_ptr<base::Value> reference_array_value(base::test::ParseJson("[]"));
+ EXPECT_TRUE(
+ base::Value::Equals(reference_array_value.get(), array_value.get()));
+
+ // Not testing ArrayBuffers as V8ValueConverter uses blink helpers and
+ // this requires having blink to be initialized.
+
+ v8::Local<v8::Number> number(v8::Number::New(isolate_, 0.0));
+ scoped_ptr<base::Value> number_value(converter.FromV8Value(number, context));
+ ASSERT_TRUE(number_value);
+ scoped_ptr<base::Value> reference_number_value(base::test::ParseJson("0"));
+ EXPECT_TRUE(
+ base::Value::Equals(reference_number_value.get(), number_value.get()));
+
+ v8::Local<v8::Primitive> undefined(v8::Undefined(isolate_));
+ scoped_ptr<base::Value> undefined_value(
+ converter.FromV8Value(undefined, context));
+ EXPECT_FALSE(undefined_value);
+}
+
+} // namespace content
diff --git a/chromium/content/child/web_data_consumer_handle_impl.cc b/chromium/content/child/web_data_consumer_handle_impl.cc
index ab97b57e361..a26656ed310 100644
--- a/chromium/content/child/web_data_consumer_handle_impl.cc
+++ b/chromium/content/child/web_data_consumer_handle_impl.cc
@@ -7,7 +7,7 @@
#include <limits>
#include "base/bind.h"
#include "base/logging.h"
-#include "mojo/public/c/system/types.h"
+#include "third_party/mojo/src/mojo/public/c/system/types.h"
namespace content {
diff --git a/chromium/content/child/web_data_consumer_handle_impl.h b/chromium/content/child/web_data_consumer_handle_impl.h
index 5edef3f21a5..530387586f4 100644
--- a/chromium/content/child/web_data_consumer_handle_impl.h
+++ b/chromium/content/child/web_data_consumer_handle_impl.h
@@ -8,8 +8,8 @@
#include "base/memory/scoped_ptr.h"
#include "content/common/content_export.h"
#include "mojo/common/handle_watcher.h"
-#include "mojo/public/cpp/system/data_pipe.h"
#include "third_party/WebKit/public/platform/WebDataConsumerHandle.h"
+#include "third_party/mojo/src/mojo/public/cpp/system/data_pipe.h"
namespace content {
diff --git a/chromium/content/child/web_data_consumer_handle_impl_unittest.cc b/chromium/content/child/web_data_consumer_handle_impl_unittest.cc
index 7ad9d400973..4aaa4dc69c4 100644
--- a/chromium/content/child/web_data_consumer_handle_impl_unittest.cc
+++ b/chromium/content/child/web_data_consumer_handle_impl_unittest.cc
@@ -12,8 +12,8 @@
#include "base/run_loop.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
-#include "mojo/public/cpp/system/data_pipe.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/mojo/src/mojo/public/cpp/system/data_pipe.h"
namespace content {
diff --git a/chromium/content/child/web_discardable_memory_impl.cc b/chromium/content/child/web_discardable_memory_impl.cc
index 684d440427e..e2ea7a2a0d4 100644
--- a/chromium/content/child/web_discardable_memory_impl.cc
+++ b/chromium/content/child/web_discardable_memory_impl.cc
@@ -4,6 +4,9 @@
#include "content/child/web_discardable_memory_impl.h"
+#include "base/memory/discardable_memory.h"
+#include "base/memory/discardable_memory_allocator.h"
+
namespace content {
WebDiscardableMemoryImpl::~WebDiscardableMemoryImpl() {}
@@ -11,25 +14,13 @@ WebDiscardableMemoryImpl::~WebDiscardableMemoryImpl() {}
// static
scoped_ptr<WebDiscardableMemoryImpl>
WebDiscardableMemoryImpl::CreateLockedMemory(size_t size) {
- scoped_ptr<base::DiscardableMemory> memory(
- base::DiscardableMemory::CreateLockedMemory(size));
- if (!memory)
- return scoped_ptr<WebDiscardableMemoryImpl>();
- return make_scoped_ptr(new WebDiscardableMemoryImpl(memory.Pass()));
+ return make_scoped_ptr(new WebDiscardableMemoryImpl(
+ base::DiscardableMemoryAllocator::GetInstance()
+ ->AllocateLockedDiscardableMemory(size)));
}
bool WebDiscardableMemoryImpl::lock() {
- base::DiscardableMemoryLockStatus status = discardable_->Lock();
- switch (status) {
- case base::DISCARDABLE_MEMORY_LOCK_STATUS_SUCCESS:
- return true;
- case base::DISCARDABLE_MEMORY_LOCK_STATUS_PURGED:
- discardable_->Unlock();
- return false;
- default:
- discardable_.reset();
- return false;
- }
+ return discardable_->Lock();
}
void WebDiscardableMemoryImpl::unlock() {
@@ -37,7 +28,7 @@ void WebDiscardableMemoryImpl::unlock() {
}
void* WebDiscardableMemoryImpl::data() {
- return discardable_->Memory();
+ return discardable_->data();
}
WebDiscardableMemoryImpl::WebDiscardableMemoryImpl(
diff --git a/chromium/content/child/web_discardable_memory_impl.h b/chromium/content/child/web_discardable_memory_impl.h
index 7eaefb4dadf..d83b1c0706f 100644
--- a/chromium/content/child/web_discardable_memory_impl.h
+++ b/chromium/content/child/web_discardable_memory_impl.h
@@ -6,12 +6,11 @@
#define CONTENT_CHILD_WEB_DISCARDABLE_MEMORY_IMPL_H_
#include "base/basictypes.h"
-#include "base/memory/discardable_memory.h"
#include "base/memory/scoped_ptr.h"
#include "third_party/WebKit/public/platform/WebDiscardableMemory.h"
-namespace blink {
-class WebDiscardableMemory;
+namespace base {
+class DiscardableMemory;
}
namespace content {
diff --git a/chromium/content/child/web_gesture_curve_impl.cc b/chromium/content/child/web_gesture_curve_impl.cc
deleted file mode 100644
index 5324b363969..00000000000
--- a/chromium/content/child/web_gesture_curve_impl.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/child/web_gesture_curve_impl.h"
-
-#include "base/logging.h"
-#include "third_party/WebKit/public/platform/WebFloatSize.h"
-#include "third_party/WebKit/public/platform/WebGestureCurveTarget.h"
-#include "ui/events/gestures/fling_curve.h"
-#include "ui/gfx/vector2d.h"
-
-#if defined(OS_ANDROID)
-#include "ui/events/android/scroller.h"
-#endif
-
-using blink::WebGestureCurve;
-
-namespace content {
-namespace {
-
-scoped_ptr<ui::GestureCurve> CreateDefaultPlatformCurve(
- const gfx::Vector2dF& initial_velocity) {
- DCHECK(!initial_velocity.IsZero());
-#if defined(OS_ANDROID)
- auto scroller = make_scoped_ptr(new ui::Scroller(ui::Scroller::Config()));
- scroller->Fling(0,
- 0,
- initial_velocity.x(),
- initial_velocity.y(),
- INT_MIN,
- INT_MAX,
- INT_MIN,
- INT_MAX,
- base::TimeTicks());
- return scroller.Pass();
-#else
- return make_scoped_ptr(
- new ui::FlingCurve(initial_velocity, base::TimeTicks()));
-#endif
-}
-
-} // namespace
-
-// static
-scoped_ptr<WebGestureCurve> WebGestureCurveImpl::CreateFromDefaultPlatformCurve(
- const gfx::Vector2dF& initial_velocity,
- const gfx::Vector2dF& initial_offset) {
- return CreateFrom(CreateDefaultPlatformCurve(initial_velocity),
- initial_offset);
-}
-
-// static
-scoped_ptr<WebGestureCurve> WebGestureCurveImpl::CreateFrom(
- scoped_ptr<ui::GestureCurve> curve,
- const gfx::Vector2dF& initial_offset) {
- return scoped_ptr<WebGestureCurve>(
- new WebGestureCurveImpl(curve.Pass(), initial_offset));
-}
-
-WebGestureCurveImpl::WebGestureCurveImpl(scoped_ptr<ui::GestureCurve> curve,
- const gfx::Vector2dF& initial_offset)
- : curve_(curve.Pass()), last_offset_(initial_offset) {
-}
-
-WebGestureCurveImpl::~WebGestureCurveImpl() {
-}
-
-bool WebGestureCurveImpl::apply(double time,
- blink::WebGestureCurveTarget* target) {
- // If the fling has yet to start, simply return and report true to prevent
- // fling termination.
- if (time <= 0)
- return true;
-
- const base::TimeTicks time_ticks =
- base::TimeTicks() + base::TimeDelta::FromSecondsD(time);
- gfx::Vector2dF offset, velocity;
- bool still_active =
- curve_->ComputeScrollOffset(time_ticks, &offset, &velocity);
-
- gfx::Vector2dF delta = offset - last_offset_;
- last_offset_ = offset;
-
- // As successive timestamps can be arbitrarily close (but monotonic!), don't
- // assume that a zero delta means the curve has terminated.
- if (delta.IsZero())
- return still_active;
-
- // scrollBy() could delete this curve if the animation is over, so don't touch
- // any member variables after making that call.
- bool did_scroll = target->scrollBy(blink::WebFloatSize(delta),
- blink::WebFloatSize(velocity));
- return did_scroll && still_active;
-}
-
-} // namespace content
diff --git a/chromium/content/child/web_gesture_curve_impl.h b/chromium/content/child/web_gesture_curve_impl.h
deleted file mode 100644
index cb0d0bfeef5..00000000000
--- a/chromium/content/child/web_gesture_curve_impl.h
+++ /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.
-
-#ifndef CONTENT_CHILD_WEB_GESTURE_CURVE_IMPL_H_
-#define CONTENT_CHILD_WEB_GESTURE_CURVE_IMPL_H_
-
-#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
-#include "content/common/content_export.h"
-#include "third_party/WebKit/public/platform/WebGestureCurve.h"
-#include "ui/gfx/geometry/vector2d_f.h"
-
-namespace blink {
-class WebGestureCurveTarget;
-}
-
-namespace ui {
-class GestureCurve;
-}
-
-namespace content {
-
-class CONTENT_EXPORT WebGestureCurveImpl
- : public NON_EXPORTED_BASE(blink::WebGestureCurve) {
- public:
- static scoped_ptr<blink::WebGestureCurve> CreateFromDefaultPlatformCurve(
- const gfx::Vector2dF& initial_velocity,
- const gfx::Vector2dF& initial_offset);
- static scoped_ptr<blink::WebGestureCurve> CreateFrom(
- scoped_ptr<ui::GestureCurve> curve,
- const gfx::Vector2dF& initial_offset);
-
- virtual ~WebGestureCurveImpl();
-
- // WebGestureCurve implementation.
- virtual bool apply(double time,
- blink::WebGestureCurveTarget* target) override;
-
- private:
- WebGestureCurveImpl(scoped_ptr<ui::GestureCurve> curve,
- const gfx::Vector2dF& initial_offset);
-
- scoped_ptr<ui::GestureCurve> curve_;
-
- gfx::Vector2dF last_offset_;
-
- DISALLOW_COPY_AND_ASSIGN(WebGestureCurveImpl);
-};
-
-} // namespace content
-
-#endif // CONTENT_CHILD_WEB_GESTURE_CURVE_IMPL_H_
diff --git a/chromium/content/child/web_gesture_curve_impl_unittest.cc b/chromium/content/child/web_gesture_curve_impl_unittest.cc
deleted file mode 100644
index 787aa8f1145..00000000000
--- a/chromium/content/child/web_gesture_curve_impl_unittest.cc
+++ /dev/null
@@ -1,72 +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/child/web_gesture_curve_impl.h"
-
-#include "base/memory/scoped_ptr.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/public/platform/WebFloatSize.h"
-#include "third_party/WebKit/public/platform/WebGestureCurve.h"
-#include "third_party/WebKit/public/platform/WebGestureCurveTarget.h"
-#include "ui/events/gestures/fling_curve.h"
-
-using blink::WebFloatSize;
-using blink::WebGestureCurve;
-using blink::WebGestureCurveTarget;
-
-namespace content {
-namespace {
-
-class MockGestureCurveTarget : public WebGestureCurveTarget {
- public:
- virtual bool scrollBy(const WebFloatSize& delta,
- const WebFloatSize& velocity) override {
- cumulative_delta_.width += delta.width;
- cumulative_delta_.height += delta.height;
- current_velocity_ = velocity;
- return true;
- }
-
- const WebFloatSize& cumulative_delta() const { return cumulative_delta_; }
- const WebFloatSize& current_velocity() const { return current_velocity_; }
-
- private:
- WebFloatSize cumulative_delta_;
- WebFloatSize current_velocity_;
-};
-
-} // namespace anonymous
-
-TEST(WebGestureCurveImplTest, Basic) {
- gfx::Vector2dF velocity(5000, 0);
- gfx::Vector2dF offset;
- base::TimeTicks time;
- auto curve = WebGestureCurveImpl::CreateFrom(
- scoped_ptr<ui::GestureCurve>(new ui::FlingCurve(velocity, time)), offset);
-
- // coded into the create call above.
- MockGestureCurveTarget target;
- EXPECT_TRUE(curve->apply(0, &target));
- EXPECT_TRUE(curve->apply(0.25, &target));
- EXPECT_NEAR(target.current_velocity().width, 1878, 1);
- EXPECT_EQ(target.current_velocity().height, 0);
- EXPECT_GT(target.cumulative_delta().width, 0);
- EXPECT_TRUE(curve->apply(0.45, &target)); // Use non-uniform tick spacing.
-
- // Ensure fling persists even if successive timestamps are identical.
- gfx::Vector2dF cumulative_delta = target.cumulative_delta();
- gfx::Vector2dF current_velocity = target.current_velocity();
- EXPECT_TRUE(curve->apply(0.45, &target));
- EXPECT_EQ(cumulative_delta, gfx::Vector2dF(target.cumulative_delta()));
- EXPECT_EQ(current_velocity, gfx::Vector2dF(target.current_velocity()));
-
- EXPECT_TRUE(curve->apply(0.75, &target));
- EXPECT_FALSE(curve->apply(1.5, &target));
- EXPECT_NEAR(target.cumulative_delta().width, 1193, 1);
- EXPECT_EQ(target.cumulative_delta().height, 0);
- EXPECT_EQ(target.current_velocity().width, 0);
- EXPECT_EQ(target.current_velocity().height, 0);
-}
-
-} // namespace content
diff --git a/chromium/content/child/web_memory_allocator_dump_impl.cc b/chromium/content/child/web_memory_allocator_dump_impl.cc
new file mode 100644
index 00000000000..dbd529914e5
--- /dev/null
+++ b/chromium/content/child/web_memory_allocator_dump_impl.cc
@@ -0,0 +1,30 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/child/web_memory_allocator_dump_impl.h"
+
+#include "base/trace_event/memory_allocator_dump.h"
+
+namespace content {
+
+WebMemoryAllocatorDumpImpl::WebMemoryAllocatorDumpImpl(
+ base::trace_event::MemoryAllocatorDump* memory_allocator_dump)
+ : memory_allocator_dump_(memory_allocator_dump) {
+}
+
+WebMemoryAllocatorDumpImpl::~WebMemoryAllocatorDumpImpl() {
+}
+
+void WebMemoryAllocatorDumpImpl::AddScalar(const blink::WebString& name,
+ const char* units,
+ uint64 value) {
+ memory_allocator_dump_->AddScalar(name.utf8(), units, value);
+}
+
+void WebMemoryAllocatorDumpImpl::AddString(const blink::WebString& name,
+ const char* units,
+ const blink::WebString& value) {
+ memory_allocator_dump_->AddString(name.utf8(), units, value.utf8());
+}
+} // namespace content
diff --git a/chromium/content/child/web_memory_allocator_dump_impl.h b/chromium/content/child/web_memory_allocator_dump_impl.h
new file mode 100644
index 00000000000..6291174b278
--- /dev/null
+++ b/chromium/content/child/web_memory_allocator_dump_impl.h
@@ -0,0 +1,44 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_CHILD_WEB_MEMORY_ALLOCATOR_DUMP_IMPL_H_
+#define CONTENT_CHILD_WEB_MEMORY_ALLOCATOR_DUMP_IMPL_H_
+
+#include "base/memory/scoped_vector.h"
+#include "third_party/WebKit/public/platform/WebMemoryAllocatorDump.h"
+
+namespace base {
+namespace trace_event {
+class MemoryAllocatorDump;
+} // namespace base
+} // namespace trace_event
+
+namespace content {
+
+// Implements the blink::WebMemoryAllocatorDump interface by means of proxying
+// the Add*() calls to the underlying base::trace_event::MemoryAllocatorDump
+// instance.
+class WebMemoryAllocatorDumpImpl : public blink::WebMemoryAllocatorDump {
+ public:
+ explicit WebMemoryAllocatorDumpImpl(
+ base::trace_event::MemoryAllocatorDump* memory_allocator_dump);
+ virtual ~WebMemoryAllocatorDumpImpl();
+
+ // blink::WebMemoryAllocatorDump implementation.
+ virtual void AddScalar(const blink::WebString& name,
+ const char* units,
+ uint64 value);
+ virtual void AddString(const blink::WebString& name,
+ const char* units,
+ const blink::WebString& value);
+
+ private:
+ base::trace_event::MemoryAllocatorDump* memory_allocator_dump_; // Not owned.
+
+ DISALLOW_COPY_AND_ASSIGN(WebMemoryAllocatorDumpImpl);
+};
+
+} // namespace content
+
+#endif // CONTENT_CHILD_WEB_MEMORY_ALLOCATOR_DUMP_IMPL_H_
diff --git a/chromium/content/child/web_memory_dump_provider_adapter.cc b/chromium/content/child/web_memory_dump_provider_adapter.cc
new file mode 100644
index 00000000000..dcb015f02b9
--- /dev/null
+++ b/chromium/content/child/web_memory_dump_provider_adapter.cc
@@ -0,0 +1,27 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/child/web_memory_dump_provider_adapter.h"
+
+#include "content/child/web_process_memory_dump_impl.h"
+#include "third_party/WebKit/public/platform/WebMemoryDumpProvider.h"
+
+namespace content {
+
+WebMemoryDumpProviderAdapter::WebMemoryDumpProviderAdapter(
+ blink::WebMemoryDumpProvider* wmdp)
+ : web_memory_dump_provider_(wmdp), is_registered_(false) {
+}
+
+WebMemoryDumpProviderAdapter::~WebMemoryDumpProviderAdapter() {
+ DCHECK(!is_registered_);
+}
+
+bool WebMemoryDumpProviderAdapter::OnMemoryDump(
+ base::trace_event::ProcessMemoryDump* pmd) {
+ WebProcessMemoryDumpImpl web_pmd_impl(pmd);
+ return web_memory_dump_provider_->onMemoryDump(&web_pmd_impl);
+}
+
+} // namespace content
diff --git a/chromium/content/child/web_memory_dump_provider_adapter.h b/chromium/content/child/web_memory_dump_provider_adapter.h
new file mode 100644
index 00000000000..c0bf693accd
--- /dev/null
+++ b/chromium/content/child/web_memory_dump_provider_adapter.h
@@ -0,0 +1,46 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_CHILD_WEB_MEMORY_DUMP_PROVIDER_ADAPTER_H_
+#define CONTENT_CHILD_WEB_MEMORY_DUMP_PROVIDER_ADAPTER_H_
+
+#include "base/macros.h"
+#include "base/trace_event/memory_dump_provider.h"
+
+namespace blink {
+class WebMemoryDumpProvider;
+} // namespace blink
+
+namespace content {
+
+// Adapter class which makes it possible to register a WebMemoryDumpProvider (
+// from blink) to base::trace_event::MemoryDumpManager, which expects a
+// MemoryDumpProvider instead.
+// This is essentially proxying the OnMemoryDump from chromium base to blink.
+class WebMemoryDumpProviderAdapter
+ : public base::trace_event::MemoryDumpProvider {
+ public:
+ explicit WebMemoryDumpProviderAdapter(blink::WebMemoryDumpProvider* wmdp);
+ ~WebMemoryDumpProviderAdapter() override;
+
+ // base::trace_event::MemoryDumpProvider implementation.
+ bool OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd) override;
+
+ bool is_registered() const { return is_registered_; }
+ void set_is_registered(bool is_registered) { is_registered_ = is_registered; }
+
+ private:
+ // The underlying WebMemoryDumpProvider instance to which the OnMemoryDump()
+ // calls will be proxied to.
+ blink::WebMemoryDumpProvider* web_memory_dump_provider_; // Not owned.
+
+ // True iff this has been registered with the MDM (and not unregistered yet).
+ bool is_registered_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebMemoryDumpProviderAdapter);
+};
+
+} // namespace content
+
+#endif // CONTENT_CHILD_WEB_MEMORY_DUMP_PROVIDER_ADAPTER_H_
diff --git a/chromium/content/child/web_process_memory_dump_impl.cc b/chromium/content/child/web_process_memory_dump_impl.cc
new file mode 100644
index 00000000000..0bc6a6febf1
--- /dev/null
+++ b/chromium/content/child/web_process_memory_dump_impl.cc
@@ -0,0 +1,38 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/child/web_process_memory_dump_impl.h"
+
+#include "base/trace_event/process_memory_dump.h"
+#include "content/child/web_memory_allocator_dump_impl.h"
+
+namespace content {
+
+WebProcessMemoryDumpImpl::WebProcessMemoryDumpImpl(
+ base::trace_event::ProcessMemoryDump* process_memory_dump)
+ : process_memory_dump_(process_memory_dump) {
+}
+
+WebProcessMemoryDumpImpl::~WebProcessMemoryDumpImpl() {
+}
+
+blink::WebMemoryAllocatorDump*
+WebProcessMemoryDumpImpl::createMemoryAllocatorDump(
+ const blink::WebString& absolute_name) {
+ // Get a MemoryAllocatorDump from the base/ object.
+ base::trace_event::MemoryAllocatorDump* mad =
+ process_memory_dump_->CreateAllocatorDump(absolute_name.utf8());
+ if (!mad)
+ return nullptr;
+
+ // Wrap it and return to blink.
+ WebMemoryAllocatorDumpImpl* web_mad_impl =
+ new WebMemoryAllocatorDumpImpl(mad);
+
+ // memory_allocator_dumps_ will take ownership of |web_mad_impl|.
+ memory_allocator_dumps_.push_back(web_mad_impl);
+ return web_mad_impl;
+}
+
+} // namespace content
diff --git a/chromium/content/child/web_process_memory_dump_impl.h b/chromium/content/child/web_process_memory_dump_impl.h
new file mode 100644
index 00000000000..19cc5633858
--- /dev/null
+++ b/chromium/content/child/web_process_memory_dump_impl.h
@@ -0,0 +1,50 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_CHILD_WEB_PROCESS_MEMORY_DUMP_IMPL_H_
+#define CONTENT_CHILD_WEB_PROCESS_MEMORY_DUMP_IMPL_H_
+
+#include "base/memory/scoped_vector.h"
+#include "third_party/WebKit/public/platform/WebProcessMemoryDump.h"
+
+namespace base {
+namespace trace_event {
+class ProcessMemoryDump;
+} // namespace base
+} // namespace trace_event
+
+namespace content {
+
+class WebMemoryAllocatorDumpImpl;
+
+// Implements the blink::WebProcessMemoryDump interface by means of proxying the
+// calls to createMemoryAllocatorDump() to the underlying
+// base::trace_event::ProcessMemoryDump instance.
+class WebProcessMemoryDumpImpl : public blink::WebProcessMemoryDump {
+ public:
+ explicit WebProcessMemoryDumpImpl(
+ base::trace_event::ProcessMemoryDump* process_memory_dump);
+ virtual ~WebProcessMemoryDumpImpl();
+
+ // blink::WebProcessMemoryDump implementation.
+ virtual blink::WebMemoryAllocatorDump* createMemoryAllocatorDump(
+ const blink::WebString& absolute_name);
+
+ private:
+ // The underlying ProcessMemoryDump instance to which the
+ // createMemoryAllocatorDump() calls will be proxied to.
+ base::trace_event::ProcessMemoryDump* process_memory_dump_; // Not owned.
+
+ // By design WebMemoryDumpProvider(s) are not supposed to hold the pointer
+ // to the WebProcessMemoryDump passed as argument of the onMemoryDump() call.
+ // Those pointers are valid only within the scope of the call and can be
+ // safely torn down once the WebProcessMemoryDumpImpl itself is destroyed.
+ ScopedVector<WebMemoryAllocatorDumpImpl> memory_allocator_dumps_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebProcessMemoryDumpImpl);
+};
+
+} // namespace content
+
+#endif // CONTENT_CHILD_WEB_PROCESS_MEMORY_DUMP_IMPL_H_
diff --git a/chromium/content/child/web_url_loader_impl.cc b/chromium/content/child/web_url_loader_impl.cc
index b51d799047c..818f5d525e3 100644
--- a/chromium/content/child/web_url_loader_impl.cc
+++ b/chromium/content/child/web_url_loader_impl.cc
@@ -2,33 +2,37 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// An implementation of WebURLLoader in terms of ResourceLoaderBridge.
-
#include "content/child/web_url_loader_impl.h"
+#include <algorithm>
+#include <deque>
+#include <string>
+
#include "base/bind.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
#include "base/strings/string_util.h"
#include "base/time/time.h"
+#include "components/mime_util/mime_util.h"
+#include "content/child/child_thread_impl.h"
#include "content/child/ftp_directory_listing_response_delegate.h"
#include "content/child/multipart_response_delegate.h"
#include "content/child/request_extra_data.h"
#include "content/child/request_info.h"
#include "content/child/resource_dispatcher.h"
-#include "content/child/resource_loader_bridge.h"
#include "content/child/sync_load_response.h"
+#include "content/child/web_data_consumer_handle_impl.h"
#include "content/child/web_url_request_util.h"
#include "content/child/weburlresponse_extradata_impl.h"
+#include "content/common/resource_messages.h"
#include "content/common/resource_request_body.h"
#include "content/common/service_worker/service_worker_types.h"
#include "content/public/child/request_peer.h"
#include "content/public/common/content_switches.h"
#include "net/base/data_url.h"
#include "net/base/filename_util.h"
-#include "net/base/mime_util.h"
#include "net/base/net_errors.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
@@ -42,6 +46,7 @@
#include "third_party/WebKit/public/platform/WebURLRequest.h"
#include "third_party/WebKit/public/platform/WebURLResponse.h"
#include "third_party/WebKit/public/web/WebSecurityPolicy.h"
+#include "third_party/mojo/src/mojo/public/cpp/system/data_pipe.h"
using base::Time;
using base::TimeTicks;
@@ -66,9 +71,7 @@ namespace content {
namespace {
-const char kThrottledErrorDescription[] =
- "Request throttled. Visit http://dev.chromium.org/throttling for more "
- "information.";
+const size_t kBodyStreamPipeCapacity = 4 * 1024;
typedef ResourceDevToolsInfo::HeadersVector HeadersVector;
@@ -161,18 +164,18 @@ int GetInfoFromDataURL(const GURL& url,
return net::OK;
}
-#define COMPILE_ASSERT_MATCHING_ENUMS(content_name, blink_name) \
- COMPILE_ASSERT( \
+#define STATIC_ASSERT_MATCHING_ENUMS(content_name, blink_name) \
+ static_assert( \
static_cast<int>(content_name) == static_cast<int>(blink_name), \
- mismatching_enums)
-
-COMPILE_ASSERT_MATCHING_ENUMS(FETCH_REQUEST_MODE_SAME_ORIGIN,
- WebURLRequest::FetchRequestModeSameOrigin);
-COMPILE_ASSERT_MATCHING_ENUMS(FETCH_REQUEST_MODE_NO_CORS,
- WebURLRequest::FetchRequestModeNoCORS);
-COMPILE_ASSERT_MATCHING_ENUMS(FETCH_REQUEST_MODE_CORS,
- WebURLRequest::FetchRequestModeCORS);
-COMPILE_ASSERT_MATCHING_ENUMS(
+ "mismatching enums: " #content_name)
+
+STATIC_ASSERT_MATCHING_ENUMS(FETCH_REQUEST_MODE_SAME_ORIGIN,
+ WebURLRequest::FetchRequestModeSameOrigin);
+STATIC_ASSERT_MATCHING_ENUMS(FETCH_REQUEST_MODE_NO_CORS,
+ WebURLRequest::FetchRequestModeNoCORS);
+STATIC_ASSERT_MATCHING_ENUMS(FETCH_REQUEST_MODE_CORS,
+ WebURLRequest::FetchRequestModeCORS);
+STATIC_ASSERT_MATCHING_ENUMS(
FETCH_REQUEST_MODE_CORS_WITH_FORCED_PREFLIGHT,
WebURLRequest::FetchRequestModeCORSWithForcedPreflight);
@@ -180,99 +183,99 @@ FetchRequestMode GetFetchRequestMode(const WebURLRequest& request) {
return static_cast<FetchRequestMode>(request.fetchRequestMode());
}
-COMPILE_ASSERT_MATCHING_ENUMS(FETCH_CREDENTIALS_MODE_OMIT,
- WebURLRequest::FetchCredentialsModeOmit);
-COMPILE_ASSERT_MATCHING_ENUMS(FETCH_CREDENTIALS_MODE_SAME_ORIGIN,
- WebURLRequest::FetchCredentialsModeSameOrigin);
-COMPILE_ASSERT_MATCHING_ENUMS(FETCH_CREDENTIALS_MODE_INCLUDE,
- WebURLRequest::FetchCredentialsModeInclude);
+STATIC_ASSERT_MATCHING_ENUMS(FETCH_CREDENTIALS_MODE_OMIT,
+ WebURLRequest::FetchCredentialsModeOmit);
+STATIC_ASSERT_MATCHING_ENUMS(FETCH_CREDENTIALS_MODE_SAME_ORIGIN,
+ WebURLRequest::FetchCredentialsModeSameOrigin);
+STATIC_ASSERT_MATCHING_ENUMS(FETCH_CREDENTIALS_MODE_INCLUDE,
+ WebURLRequest::FetchCredentialsModeInclude);
FetchCredentialsMode GetFetchCredentialsMode(const WebURLRequest& request) {
return static_cast<FetchCredentialsMode>(request.fetchCredentialsMode());
}
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_FRAME_TYPE_AUXILIARY,
- WebURLRequest::FrameTypeAuxiliary);
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_FRAME_TYPE_NESTED,
- WebURLRequest::FrameTypeNested);
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_FRAME_TYPE_NONE,
- WebURLRequest::FrameTypeNone);
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_FRAME_TYPE_TOP_LEVEL,
- WebURLRequest::FrameTypeTopLevel);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_FRAME_TYPE_AUXILIARY,
+ WebURLRequest::FrameTypeAuxiliary);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_FRAME_TYPE_NESTED,
+ WebURLRequest::FrameTypeNested);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_FRAME_TYPE_NONE,
+ WebURLRequest::FrameTypeNone);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_FRAME_TYPE_TOP_LEVEL,
+ WebURLRequest::FrameTypeTopLevel);
RequestContextFrameType GetRequestContextFrameType(
const WebURLRequest& request) {
return static_cast<RequestContextFrameType>(request.frameType());
}
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_UNSPECIFIED,
- WebURLRequest::RequestContextUnspecified);
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_AUDIO,
- WebURLRequest::RequestContextAudio);
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_BEACON,
- WebURLRequest::RequestContextBeacon);
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_CSP_REPORT,
- WebURLRequest::RequestContextCSPReport);
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_DOWNLOAD,
- WebURLRequest::RequestContextDownload);
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_EMBED,
- WebURLRequest::RequestContextEmbed);
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_EVENT_SOURCE,
- WebURLRequest::RequestContextEventSource);
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_FAVICON,
- WebURLRequest::RequestContextFavicon);
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_FETCH,
- WebURLRequest::RequestContextFetch);
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_FONT,
- WebURLRequest::RequestContextFont);
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_FORM,
- WebURLRequest::RequestContextForm);
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_FRAME,
- WebURLRequest::RequestContextFrame);
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_HYPERLINK,
- WebURLRequest::RequestContextHyperlink);
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_IFRAME,
- WebURLRequest::RequestContextIframe);
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_IMAGE,
- WebURLRequest::RequestContextImage);
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_IMAGE_SET,
- WebURLRequest::RequestContextImageSet);
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_IMPORT,
- WebURLRequest::RequestContextImport);
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_INTERNAL,
- WebURLRequest::RequestContextInternal);
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_LOCATION,
- WebURLRequest::RequestContextLocation);
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_MANIFEST,
- WebURLRequest::RequestContextManifest);
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_OBJECT,
- WebURLRequest::RequestContextObject);
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_PING,
- WebURLRequest::RequestContextPing);
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_PLUGIN,
- WebURLRequest::RequestContextPlugin);
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_PREFETCH,
- WebURLRequest::RequestContextPrefetch);
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_SCRIPT,
- WebURLRequest::RequestContextScript);
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_SERVICE_WORKER,
- WebURLRequest::RequestContextServiceWorker);
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_SHARED_WORKER,
- WebURLRequest::RequestContextSharedWorker);
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_SUBRESOURCE,
- WebURLRequest::RequestContextSubresource);
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_STYLE,
- WebURLRequest::RequestContextStyle);
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_TRACK,
- WebURLRequest::RequestContextTrack);
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_VIDEO,
- WebURLRequest::RequestContextVideo);
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_WORKER,
- WebURLRequest::RequestContextWorker);
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_XML_HTTP_REQUEST,
- WebURLRequest::RequestContextXMLHttpRequest);
-COMPILE_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_XSLT,
- WebURLRequest::RequestContextXSLT);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_UNSPECIFIED,
+ WebURLRequest::RequestContextUnspecified);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_AUDIO,
+ WebURLRequest::RequestContextAudio);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_BEACON,
+ WebURLRequest::RequestContextBeacon);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_CSP_REPORT,
+ WebURLRequest::RequestContextCSPReport);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_DOWNLOAD,
+ WebURLRequest::RequestContextDownload);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_EMBED,
+ WebURLRequest::RequestContextEmbed);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_EVENT_SOURCE,
+ WebURLRequest::RequestContextEventSource);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_FAVICON,
+ WebURLRequest::RequestContextFavicon);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_FETCH,
+ WebURLRequest::RequestContextFetch);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_FONT,
+ WebURLRequest::RequestContextFont);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_FORM,
+ WebURLRequest::RequestContextForm);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_FRAME,
+ WebURLRequest::RequestContextFrame);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_HYPERLINK,
+ WebURLRequest::RequestContextHyperlink);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_IFRAME,
+ WebURLRequest::RequestContextIframe);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_IMAGE,
+ WebURLRequest::RequestContextImage);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_IMAGE_SET,
+ WebURLRequest::RequestContextImageSet);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_IMPORT,
+ WebURLRequest::RequestContextImport);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_INTERNAL,
+ WebURLRequest::RequestContextInternal);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_LOCATION,
+ WebURLRequest::RequestContextLocation);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_MANIFEST,
+ WebURLRequest::RequestContextManifest);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_OBJECT,
+ WebURLRequest::RequestContextObject);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_PING,
+ WebURLRequest::RequestContextPing);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_PLUGIN,
+ WebURLRequest::RequestContextPlugin);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_PREFETCH,
+ WebURLRequest::RequestContextPrefetch);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_SCRIPT,
+ WebURLRequest::RequestContextScript);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_SERVICE_WORKER,
+ WebURLRequest::RequestContextServiceWorker);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_SHARED_WORKER,
+ WebURLRequest::RequestContextSharedWorker);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_SUBRESOURCE,
+ WebURLRequest::RequestContextSubresource);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_STYLE,
+ WebURLRequest::RequestContextStyle);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_TRACK,
+ WebURLRequest::RequestContextTrack);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_VIDEO,
+ WebURLRequest::RequestContextVideo);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_WORKER,
+ WebURLRequest::RequestContextWorker);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_XML_HTTP_REQUEST,
+ WebURLRequest::RequestContextXMLHttpRequest);
+STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_XSLT,
+ WebURLRequest::RequestContextXSLT);
RequestContextType GetRequestContextType(const WebURLRequest& request) {
return static_cast<RequestContextType>(request.requestContext());
@@ -288,7 +291,9 @@ RequestContextType GetRequestContextType(const WebURLRequest& request) {
class WebURLLoaderImpl::Context : public base::RefCounted<Context>,
public RequestPeer {
public:
- Context(WebURLLoaderImpl* loader, ResourceDispatcher* resource_dispatcher);
+ Context(WebURLLoaderImpl* loader,
+ ResourceDispatcher* resource_dispatcher,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner);
WebURLLoaderClient* client() const { return client_; }
void set_client(WebURLLoaderClient* client) { client_ = client; }
@@ -321,36 +326,53 @@ class WebURLLoaderImpl::Context : public base::RefCounted<Context>,
private:
friend class base::RefCounted<Context>;
- ~Context() override {}
+ ~Context() override;
// We can optimize the handling of data URLs in most cases.
bool CanHandleDataURLRequestLocally() const;
void HandleDataURL();
+ MojoResult WriteDataOnBodyStream(const char* data, size_t size);
+ void OnHandleGotWritable(MojoResult);
WebURLLoaderImpl* loader_;
WebURLRequest request_;
WebURLLoaderClient* client_;
ResourceDispatcher* resource_dispatcher_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
WebReferrerPolicy referrer_policy_;
- scoped_ptr<ResourceLoaderBridge> bridge_;
scoped_ptr<FtpDirectoryListingResponseDelegate> ftp_listing_delegate_;
scoped_ptr<MultipartResponseDelegate> multipart_delegate_;
- scoped_ptr<ResourceLoaderBridge> completed_bridge_;
scoped_ptr<StreamOverrideParameters> stream_override_;
+ mojo::ScopedDataPipeProducerHandle body_stream_writer_;
+ mojo::common::HandleWatcher body_stream_writer_watcher_;
+ // TODO(yhirano): Delete this buffer after implementing the back-pressure
+ // mechanism.
+ std::deque<char> body_stream_buffer_;
+ bool got_all_stream_body_data_;
+ enum DeferState {NOT_DEFERRING, SHOULD_DEFER, DEFERRED_DATA};
+ DeferState defers_loading_;
+ int request_id_;
};
-WebURLLoaderImpl::Context::Context(WebURLLoaderImpl* loader,
- ResourceDispatcher* resource_dispatcher)
+WebURLLoaderImpl::Context::Context(
+ WebURLLoaderImpl* loader,
+ ResourceDispatcher* resource_dispatcher,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner)
: loader_(loader),
client_(NULL),
resource_dispatcher_(resource_dispatcher),
- referrer_policy_(blink::WebReferrerPolicyDefault) {
+ task_runner_(task_runner),
+ referrer_policy_(blink::WebReferrerPolicyDefault),
+ got_all_stream_body_data_(false),
+ defers_loading_(NOT_DEFERRING),
+ request_id_(-1) {
}
void WebURLLoaderImpl::Context::Cancel() {
- if (bridge_) {
- bridge_->Cancel();
- bridge_.reset();
+ if (resource_dispatcher_ && // NULL in unittest.
+ request_id_ != -1) {
+ resource_dispatcher_->Cancel(request_id_);
+ request_id_ = -1;
}
// Ensure that we do not notify the multipart delegate anymore as it has
@@ -367,29 +389,42 @@ void WebURLLoaderImpl::Context::Cancel() {
}
void WebURLLoaderImpl::Context::SetDefersLoading(bool value) {
- if (bridge_)
- bridge_->SetDefersLoading(value);
+ if (request_id_ != -1)
+ resource_dispatcher_->SetDefersLoading(request_id_, value);
+ if (value && defers_loading_ == NOT_DEFERRING) {
+ defers_loading_ = SHOULD_DEFER;
+ } else if (!value && defers_loading_ != NOT_DEFERRING) {
+ if (defers_loading_ == DEFERRED_DATA) {
+ task_runner_->PostTask(FROM_HERE,
+ base::Bind(&Context::HandleDataURL, this));
+ }
+ defers_loading_ = NOT_DEFERRING;
+ }
}
void WebURLLoaderImpl::Context::DidChangePriority(
WebURLRequest::Priority new_priority, int intra_priority_value) {
- if (bridge_)
- bridge_->DidChangePriority(
- ConvertWebKitPriorityToNetPriority(new_priority), intra_priority_value);
+ if (request_id_ != -1) {
+ resource_dispatcher_->DidChangePriority(
+ request_id_,
+ ConvertWebKitPriorityToNetPriority(new_priority),
+ intra_priority_value);
+ }
}
bool WebURLLoaderImpl::Context::AttachThreadedDataReceiver(
blink::WebThreadedDataReceiver* threaded_data_receiver) {
- if (bridge_)
- return bridge_->AttachThreadedDataReceiver(threaded_data_receiver);
+ if (request_id_ != -1) {
+ return resource_dispatcher_->AttachThreadedDataReceiver(
+ request_id_, threaded_data_receiver);
+ }
return false;
}
void WebURLLoaderImpl::Context::Start(const WebURLRequest& request,
SyncLoadResponse* sync_load_response) {
- DCHECK(!bridge_.get());
-
+ DCHECK(request_id_ == -1);
request_ = request; // Save the request.
if (request.extraData()) {
RequestExtraData* extra_data =
@@ -403,7 +438,7 @@ void WebURLLoaderImpl::Context::Start(const WebURLRequest& request,
// contains the body of the response. The request has already been made by the
// browser.
if (stream_override_.get()) {
- CHECK(CommandLine::ForCurrentProcess()->HasSwitch(
+ CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableBrowserSideNavigation));
DCHECK(!sync_load_response);
DCHECK_NE(WebURLRequest::FrameTypeNone, request.frameType());
@@ -419,12 +454,21 @@ void WebURLLoaderImpl::Context::Start(const WebURLRequest& request,
GetInfoFromDataURL(sync_load_response->url, sync_load_response,
&sync_load_response->data);
} else {
- base::MessageLoop::current()->PostTask(
- FROM_HERE, base::Bind(&Context::HandleDataURL, this));
+ task_runner_->PostTask(FROM_HERE,
+ base::Bind(&Context::HandleDataURL, this));
}
return;
}
+ // PlzNavigate: outside of tests, the only navigation requests going through
+ // the WebURLLoader are the ones created by CommitNavigation. Several browser
+ // tests load HTML directly through a data url which will be handled by the
+ // block above.
+ DCHECK_IMPLIES(base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation),
+ stream_override_.get() ||
+ request.frameType() == WebURLRequest::FrameTypeNone);
+
GURL referrer_url(
request.httpHeaderField(WebString::fromUTF8("Referer")).latin1());
const std::string& method = request.httpMethod().latin1();
@@ -439,11 +483,16 @@ void WebURLLoaderImpl::Context::Start(const WebURLRequest& request,
request_info.method = method;
request_info.url = url;
request_info.first_party_for_cookies = request.firstPartyForCookies();
- request_info.referrer = referrer_url;
+ referrer_policy_ = request.referrerPolicy();
+ request_info.referrer = Referrer(referrer_url, referrer_policy_);
request_info.headers = GetWebURLRequestHeaders(request);
request_info.load_flags = GetLoadFlagsForWebURLRequest(request);
request_info.enable_load_timing = true;
request_info.enable_upload_progress = request.reportUploadProgress();
+ if (request.requestContext() == WebURLRequest::RequestContextXMLHttpRequest &&
+ (url.has_username() || url.has_password())) {
+ request_info.do_not_prompt_for_login = true;
+ }
// requestor_pid only needs to be non-zero if the request originates outside
// the render process, so we can use requestorProcessID even for requests
// from in-process plugins.
@@ -456,76 +505,24 @@ void WebURLLoaderImpl::Context::Start(const WebURLRequest& request,
request_info.download_to_file = request.downloadToFile();
request_info.has_user_gesture = request.hasUserGesture();
request_info.skip_service_worker = request.skipServiceWorker();
+ request_info.should_reset_appcache = request.shouldResetAppCache();
request_info.fetch_request_mode = GetFetchRequestMode(request);
request_info.fetch_credentials_mode = GetFetchCredentialsMode(request);
request_info.fetch_request_context_type = GetRequestContextType(request);
request_info.fetch_frame_type = GetRequestContextFrameType(request);
request_info.extra_data = request.extraData();
- referrer_policy_ = request.referrerPolicy();
- request_info.referrer_policy = request.referrerPolicy();
- bridge_.reset(resource_dispatcher_->CreateBridge(request_info));
-
- if (!request.httpBody().isNull()) {
- // GET and HEAD requests shouldn't have http bodies.
- DCHECK(method != "GET" && method != "HEAD");
- const WebHTTPBody& httpBody = request.httpBody();
- size_t i = 0;
- WebHTTPBody::Element element;
- scoped_refptr<ResourceRequestBody> request_body = new ResourceRequestBody;
- while (httpBody.elementAt(i++, element)) {
- switch (element.type) {
- case WebHTTPBody::Element::TypeData:
- if (!element.data.isEmpty()) {
- // WebKit sometimes gives up empty data to append. These aren't
- // necessary so we just optimize those out here.
- request_body->AppendBytes(
- element.data.data(), static_cast<int>(element.data.size()));
- }
- break;
- case WebHTTPBody::Element::TypeFile:
- if (element.fileLength == -1) {
- request_body->AppendFileRange(
- base::FilePath::FromUTF16Unsafe(element.filePath),
- 0, kuint64max, base::Time());
- } else {
- request_body->AppendFileRange(
- base::FilePath::FromUTF16Unsafe(element.filePath),
- static_cast<uint64>(element.fileStart),
- static_cast<uint64>(element.fileLength),
- base::Time::FromDoubleT(element.modificationTime));
- }
- break;
- case WebHTTPBody::Element::TypeFileSystemURL: {
- GURL file_system_url = element.fileSystemURL;
- DCHECK(file_system_url.SchemeIsFileSystem());
- request_body->AppendFileSystemFileRange(
- file_system_url,
- static_cast<uint64>(element.fileStart),
- static_cast<uint64>(element.fileLength),
- base::Time::FromDoubleT(element.modificationTime));
- break;
- }
- case WebHTTPBody::Element::TypeBlob:
- request_body->AppendBlob(element.blobUUID.utf8());
- break;
- default:
- NOTREACHED();
- }
- }
- request_body->set_identifier(request.httpBody().identifier());
- bridge_->SetRequestBody(request_body.get());
- }
+
+ scoped_refptr<ResourceRequestBody> request_body =
+ GetRequestBodyForWebURLRequest(request).get();
if (sync_load_response) {
- bridge_->SyncLoad(sync_load_response);
+ resource_dispatcher_->StartSync(
+ request_info, request_body.get(), sync_load_response);
return;
}
- // TODO(mmenke): This case probably never happens, anyways. Probably should
- // not handle this case at all. If it's worth handling, this code currently
- // results in the request just hanging, which should be fixed.
- if (!bridge_->Start(this))
- bridge_.reset();
+ request_id_ = resource_dispatcher_->StartAsync(
+ request_info, request_body.get(), this);
}
void WebURLLoaderImpl::Context::OnUploadProgress(uint64 position, uint64 size) {
@@ -552,6 +549,7 @@ bool WebURLLoaderImpl::Context::OnReceivedRedirect(
new_request.setRequestContext(request_.requestContext());
new_request.setFrameType(request_.frameType());
new_request.setSkipServiceWorker(request_.skipServiceWorker());
+ new_request.setShouldResetAppCache(request_.shouldResetAppCache());
new_request.setFetchRequestMode(request_.fetchRequestMode());
new_request.setFetchCredentialsMode(request_.fetchCredentialsMode());
@@ -595,19 +593,13 @@ void WebURLLoaderImpl::Context::OnReceivedResponse(
// PlzNavigate: during navigations, the ResourceResponse has already been
// received on the browser side, and has been passed down to the renderer.
if (stream_override_.get()) {
- CHECK(CommandLine::ForCurrentProcess()->HasSwitch(
+ CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableBrowserSideNavigation));
info = stream_override_->response;
}
WebURLResponse response;
response.initialize();
- // Updates the request url if the response was fetched by a ServiceWorker,
- // and it was not generated inside the ServiceWorker.
- if (info.was_fetched_via_service_worker &&
- !info.original_url_via_service_worker.is_empty()) {
- request_.setURL(info.original_url_via_service_worker);
- }
PopulateURLResponse(request_.url(), info, &response);
bool show_raw_listing = (GURL(request_.url()).query() == "raw");
@@ -626,7 +618,27 @@ void WebURLLoaderImpl::Context::OnReceivedResponse(
// ether in didReceiveResponse, or when the multipart/ftp delegate calls into
// it.
scoped_refptr<Context> protect(this);
- client_->didReceiveResponse(loader_, response);
+
+ if (request_.useStreamOnResponse()) {
+ MojoCreateDataPipeOptions options;
+ options.struct_size = sizeof(MojoCreateDataPipeOptions);
+ options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE;
+ options.element_num_bytes = 1;
+ options.capacity_num_bytes = kBodyStreamPipeCapacity;
+
+ mojo::ScopedDataPipeConsumerHandle consumer;
+ MojoResult result = mojo::CreateDataPipe(&options,
+ &body_stream_writer_,
+ &consumer);
+ if (result != MOJO_RESULT_OK) {
+ // TODO(yhirano): Handle the error.
+ return;
+ }
+ client_->didReceiveResponse(
+ loader_, response, new WebDataConsumerHandleImpl(consumer.Pass()));
+ } else {
+ client_->didReceiveResponse(loader_, response);
+ }
// We may have been cancelled after didReceiveResponse, which would leave us
// without a client and therefore without much need to do further handling.
@@ -672,7 +684,15 @@ void WebURLLoaderImpl::Context::OnReceivedData(const char* data,
if (!client_)
return;
- if (ftp_listing_delegate_) {
+ if (request_.useStreamOnResponse()) {
+ // We don't support ftp_listening_delegate_ and multipart_delegate_ for now.
+ // TODO(yhirano): Support ftp listening and multipart.
+ MojoResult rv = WriteDataOnBodyStream(data, data_length);
+ if (rv != MOJO_RESULT_OK && client_) {
+ client_->didFail(
+ loader_, CreateWebURLError(request_.url(), false, net::ERR_FAILED));
+ }
+ } else if (ftp_listing_delegate_) {
// The FTP listing delegate will make the appropriate calls to
// client_->didReceiveData and client_->didReceiveResponse. Since the
// delegate may want to do work after sending data to the delegate, keep
@@ -718,24 +738,36 @@ void WebURLLoaderImpl::Context::OnCompletedRequest(
multipart_delegate_.reset(NULL);
}
- // Prevent any further IPC to the browser now that we're complete, but
- // don't delete it to keep any downloaded temp files alive.
- DCHECK(!completed_bridge_.get());
- completed_bridge_.swap(bridge_);
-
if (client_) {
if (error_code != net::OK) {
- client_->didFail(loader_, CreateError(request_.url(),
- stale_copy_in_cache,
- error_code));
+ client_->didFail(
+ loader_,
+ CreateWebURLError(request_.url(), stale_copy_in_cache, error_code));
} else {
- client_->didFinishLoading(
- loader_, (completion_time - TimeTicks()).InSecondsF(),
- total_transfer_size);
+ if (request_.useStreamOnResponse()) {
+ got_all_stream_body_data_ = true;
+ if (body_stream_buffer_.empty()) {
+ // Close the handle to notify the end of data.
+ body_stream_writer_.reset();
+ client_->didFinishLoading(
+ loader_, (completion_time - TimeTicks()).InSecondsF(),
+ total_transfer_size);
+ }
+ } else {
+ client_->didFinishLoading(
+ loader_, (completion_time - TimeTicks()).InSecondsF(),
+ total_transfer_size);
+ }
}
}
}
+WebURLLoaderImpl::Context::~Context() {
+ if (request_id_ >= 0) {
+ resource_dispatcher_->RemovePendingRequest(request_id_);
+ }
+}
+
bool WebURLLoaderImpl::Context::CanHandleDataURLRequestLocally() const {
GURL url = request_.url();
if (!url.SchemeIs(url::kDataScheme))
@@ -746,13 +778,17 @@ bool WebURLLoaderImpl::Context::CanHandleDataURLRequestLocally() const {
if (request_.downloadToFile())
return false;
+ // Data url requests from object tags may need to be intercepted as streams
+ // and so need to be sent to the browser.
+ if (request_.requestContext() == WebURLRequest::RequestContextObject)
+ return false;
+
// Optimize for the case where we can handle a data URL locally. We must
// skip this for data URLs targetted at frames since those could trigger a
// download.
//
// NOTE: We special case MIME types we can render both for performance
- // reasons as well as to support unit tests, which do not have an underlying
- // ResourceLoaderBridge implementation.
+ // reasons as well as to support unit tests.
#if defined(OS_ANDROID)
// For compatibility reasons on Android we need to expose top-level data://
@@ -767,13 +803,19 @@ bool WebURLLoaderImpl::Context::CanHandleDataURLRequestLocally() const {
std::string mime_type, unused_charset;
if (net::DataURL::Parse(request_.url(), &mime_type, &unused_charset, NULL) &&
- net::IsSupportedMimeType(mime_type))
+ mime_util::IsSupportedMimeType(mime_type))
return true;
return false;
}
void WebURLLoaderImpl::Context::HandleDataURL() {
+ DCHECK_NE(defers_loading_, DEFERRED_DATA);
+ if (defers_loading_ == SHOULD_DEFER) {
+ defers_loading_ = DEFERRED_DATA;
+ return;
+ }
+
ResourceResponseInfo info;
std::string data;
@@ -789,41 +831,125 @@ void WebURLLoaderImpl::Context::HandleDataURL() {
base::TimeTicks::Now(), 0);
}
-// WebURLLoaderImpl -----------------------------------------------------------
+MojoResult WebURLLoaderImpl::Context::WriteDataOnBodyStream(const char* data,
+ size_t size) {
+ if (body_stream_buffer_.empty() && size == 0) {
+ // Nothing to do.
+ return MOJO_RESULT_OK;
+ }
-WebURLLoaderImpl::WebURLLoaderImpl(ResourceDispatcher* resource_dispatcher)
- : context_(new Context(this, resource_dispatcher)) {
-}
+ if (!body_stream_writer_.is_valid()) {
+ // The handle is already cleared.
+ return MOJO_RESULT_OK;
+ }
-WebURLLoaderImpl::~WebURLLoaderImpl() {
- cancel();
+ char* buffer = nullptr;
+ uint32_t num_bytes_writable = 0;
+ MojoResult rv = mojo::BeginWriteDataRaw(body_stream_writer_.get(),
+ reinterpret_cast<void**>(&buffer),
+ &num_bytes_writable,
+ MOJO_WRITE_DATA_FLAG_NONE);
+ if (rv == MOJO_RESULT_SHOULD_WAIT) {
+ body_stream_buffer_.insert(body_stream_buffer_.end(), data, data + size);
+ body_stream_writer_watcher_.Start(
+ body_stream_writer_.get(),
+ MOJO_HANDLE_SIGNAL_WRITABLE,
+ MOJO_DEADLINE_INDEFINITE,
+ base::Bind(&WebURLLoaderImpl::Context::OnHandleGotWritable,
+ base::Unretained(this)));
+ return MOJO_RESULT_OK;
+ }
+
+ if (rv != MOJO_RESULT_OK)
+ return rv;
+
+ uint32_t num_bytes_to_write = 0;
+ if (num_bytes_writable < body_stream_buffer_.size()) {
+ auto begin = body_stream_buffer_.begin();
+ auto end = body_stream_buffer_.begin() + num_bytes_writable;
+
+ std::copy(begin, end, buffer);
+ num_bytes_to_write = num_bytes_writable;
+ body_stream_buffer_.erase(begin, end);
+ body_stream_buffer_.insert(body_stream_buffer_.end(), data, data + size);
+ } else {
+ std::copy(body_stream_buffer_.begin(), body_stream_buffer_.end(), buffer);
+ num_bytes_writable -= body_stream_buffer_.size();
+ num_bytes_to_write += body_stream_buffer_.size();
+ buffer += body_stream_buffer_.size();
+ body_stream_buffer_.clear();
+
+ size_t num_newbytes_to_write =
+ std::min(size, static_cast<size_t>(num_bytes_writable));
+ std::copy(data, data + num_newbytes_to_write, buffer);
+ num_bytes_to_write += num_newbytes_to_write;
+ body_stream_buffer_.insert(body_stream_buffer_.end(),
+ data + num_newbytes_to_write,
+ data + size);
+ }
+
+ rv = mojo::EndWriteDataRaw(body_stream_writer_.get(), num_bytes_to_write);
+ if (rv == MOJO_RESULT_OK && !body_stream_buffer_.empty()) {
+ body_stream_writer_watcher_.Start(
+ body_stream_writer_.get(),
+ MOJO_HANDLE_SIGNAL_WRITABLE,
+ MOJO_DEADLINE_INDEFINITE,
+ base::Bind(&WebURLLoaderImpl::Context::OnHandleGotWritable,
+ base::Unretained(this)));
+ }
+ return rv;
}
-WebURLError WebURLLoaderImpl::CreateError(const WebURL& unreachable_url,
- bool stale_copy_in_cache,
- int reason) {
- WebURLError error;
- error.domain = WebString::fromUTF8(net::kErrorDomain);
- error.reason = reason;
- error.unreachableURL = unreachable_url;
- error.staleCopyInCache = stale_copy_in_cache;
- if (reason == net::ERR_ABORTED) {
- error.isCancellation = true;
- } else if (reason == net::ERR_TEMPORARILY_THROTTLED) {
- error.localizedDescription = WebString::fromUTF8(
- kThrottledErrorDescription);
+void WebURLLoaderImpl::Context::OnHandleGotWritable(MojoResult result) {
+ if (result != MOJO_RESULT_OK) {
+ if (client_) {
+ client_->didFail(
+ loader_, CreateWebURLError(request_.url(), false, net::ERR_FAILED));
+ // |this| can be deleted here.
+ }
+ return;
+ }
+
+ if (body_stream_buffer_.empty())
+ return;
+
+ MojoResult rv = WriteDataOnBodyStream(nullptr, 0);
+ if (rv == MOJO_RESULT_OK) {
+ if (got_all_stream_body_data_ && body_stream_buffer_.empty()) {
+ // Close the handle to notify the end of data.
+ body_stream_writer_.reset();
+ if (client_) {
+ // TODO(yhirano): Pass appropriate arguments.
+ client_->didFinishLoading(loader_, 0, 0);
+ // |this| can be deleted here.
+ }
+ }
} else {
- error.localizedDescription = WebString::fromUTF8(
- net::ErrorToString(reason));
+ if (client_) {
+ client_->didFail(
+ loader_, CreateWebURLError(request_.url(), false, net::ERR_FAILED));
+ // |this| can be deleted here.
+ }
}
- return error;
+}
+
+// WebURLLoaderImpl -----------------------------------------------------------
+
+WebURLLoaderImpl::WebURLLoaderImpl(
+ ResourceDispatcher* resource_dispatcher,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+ : context_(new Context(this, resource_dispatcher, task_runner)) {
+}
+
+WebURLLoaderImpl::~WebURLLoaderImpl() {
+ cancel();
}
void WebURLLoaderImpl::PopulateURLResponse(const GURL& url,
const ResourceResponseInfo& info,
WebURLResponse* response) {
response->setURL(url);
- response->setResponseTime(info.response_time.ToDoubleT());
+ response->setResponseTime(info.response_time.ToInternalValue());
response->setMIMEType(WebString::fromUTF8(info.mime_type));
response->setTextEncodingName(WebString::fromUTF8(info.charset));
response->setExpectedContentLength(info.content_length);
@@ -838,10 +964,14 @@ void WebURLLoaderImpl::PopulateURLResponse(const GURL& url,
response->setConnectionID(info.load_timing.socket_log_id);
response->setConnectionReused(info.load_timing.socket_reused);
response->setDownloadFilePath(info.download_file_path.AsUTF16Unsafe());
+ response->setWasFetchedViaSPDY(info.was_fetched_via_spdy);
response->setWasFetchedViaServiceWorker(info.was_fetched_via_service_worker);
response->setWasFallbackRequiredByServiceWorker(
info.was_fallback_required_by_service_worker);
response->setServiceWorkerResponseType(info.response_type_via_service_worker);
+ response->setOriginalURLViaServiceWorker(
+ info.original_url_via_service_worker);
+
WebURLResponseExtraDataImpl* extra_data =
new WebURLResponseExtraDataImpl(info.npn_negotiated_protocol);
response->setExtraData(extra_data);
@@ -894,6 +1024,8 @@ void WebURLLoaderImpl::PopulateURLResponse(const GURL& url,
load_info.addResponseHeader(WebString::fromLatin1(it->first),
WebString::fromLatin1(it->second));
}
+ load_info.setNPNNegotiatedProtocol(WebString::fromLatin1(
+ info.npn_negotiated_protocol));
response->setHTTPLoadInfo(load_info);
}
diff --git a/chromium/content/child/web_url_loader_impl.h b/chromium/content/child/web_url_loader_impl.h
index 36aafa633ae..9d85d06a152 100644
--- a/chromium/content/child/web_url_loader_impl.h
+++ b/chromium/content/child/web_url_loader_impl.h
@@ -12,6 +12,12 @@
#include "third_party/WebKit/public/platform/WebURLLoader.h"
#include "url/gurl.h"
+namespace base {
+
+class SingleThreadTaskRunner;
+
+} // namespace base
+
namespace content {
class ResourceDispatcher;
@@ -29,31 +35,30 @@ struct StreamOverrideParameters {
class CONTENT_EXPORT WebURLLoaderImpl
: public NON_EXPORTED_BASE(blink::WebURLLoader) {
public:
- explicit WebURLLoaderImpl(ResourceDispatcher* resource_dispatcher);
- virtual ~WebURLLoaderImpl();
+ explicit WebURLLoaderImpl(
+ ResourceDispatcher* resource_dispatcher,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+ ~WebURLLoaderImpl() override;
- static blink::WebURLError CreateError(const blink::WebURL& unreachable_url,
- bool stale_copy_in_cache,
- int reason);
static void PopulateURLResponse(
const GURL& url,
const ResourceResponseInfo& info,
blink::WebURLResponse* response);
// WebURLLoader methods:
- virtual void loadSynchronously(
+ void loadSynchronously(
const blink::WebURLRequest& request,
blink::WebURLResponse& response,
blink::WebURLError& error,
blink::WebData& data) override;
- virtual void loadAsynchronously(
+ void loadAsynchronously(
const blink::WebURLRequest& request,
blink::WebURLLoaderClient* client) override;
- virtual void cancel() override;
- virtual void setDefersLoading(bool value) override;
- virtual void didChangePriority(blink::WebURLRequest::Priority new_priority,
- int intra_priority_value) override;
- virtual bool attachThreadedDataReceiver(
+ void cancel() override;
+ void setDefersLoading(bool value) override;
+ void didChangePriority(blink::WebURLRequest::Priority new_priority,
+ int intra_priority_value) override;
+ bool attachThreadedDataReceiver(
blink::WebThreadedDataReceiver* threaded_data_receiver) override;
private:
diff --git a/chromium/content/child/web_url_loader_impl_unittest.cc b/chromium/content/child/web_url_loader_impl_unittest.cc
index 50cff38b7c7..7a48565e315 100644
--- a/chromium/content/child/web_url_loader_impl_unittest.cc
+++ b/chromium/content/child/web_url_loader_impl_unittest.cc
@@ -10,11 +10,11 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
#include "base/time/time.h"
#include "content/child/request_extra_data.h"
#include "content/child/request_info.h"
#include "content/child/resource_dispatcher.h"
-#include "content/child/resource_loader_bridge.h"
#include "content/public/child/request_peer.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/resource_response_info.h"
@@ -59,44 +59,32 @@ const char kMultipartResponse[] =
"Content-type: text/html\n\n"
"ah!";
-class TestBridge : public ResourceLoaderBridge,
- public base::SupportsWeakPtr<TestBridge> {
+class TestResourceDispatcher : public ResourceDispatcher {
public:
- TestBridge(const RequestInfo& info) :
- peer_(NULL),
- canceled_(false),
- url_(info.url) {
+ TestResourceDispatcher() :
+ ResourceDispatcher(nullptr, nullptr),
+ peer_(NULL),
+ canceled_(false) {
}
- ~TestBridge() override {}
+ ~TestResourceDispatcher() override {}
- // ResourceLoaderBridge implementation:
- void SetRequestBody(ResourceRequestBody* request_body) override {}
+ // TestDispatcher implementation:
- bool Start(RequestPeer* peer) override {
+ int StartAsync(const RequestInfo& request_info,
+ ResourceRequestBody* request_body,
+ RequestPeer* peer) override {
EXPECT_FALSE(peer_);
peer_ = peer;
- return true;
+ url_ = request_info.url;
+ return 1;
}
- void Cancel() override {
+ void Cancel(int request_id) override {
EXPECT_FALSE(canceled_);
canceled_ = true;
}
- void SetDefersLoading(bool value) override {}
-
- void DidChangePriority(net::RequestPriority new_priority,
- int intra_priority_value) override {}
-
- bool AttachThreadedDataReceiver(
- blink::WebThreadedDataReceiver* threaded_data_receiver) override {
- NOTREACHED();
- return false;
- }
-
- void SyncLoad(SyncLoadResponse* response) override {}
-
RequestPeer* peer() { return peer_; }
bool canceled() { return canceled_; }
@@ -108,34 +96,15 @@ class TestBridge : public ResourceLoaderBridge,
bool canceled_;
GURL url_;
- DISALLOW_COPY_AND_ASSIGN(TestBridge);
-};
-
-class TestResourceDispatcher : public ResourceDispatcher {
- public:
- TestResourceDispatcher() : ResourceDispatcher(NULL) {}
- ~TestResourceDispatcher() override {}
-
- // ResourceDispatcher implementation:
- ResourceLoaderBridge* CreateBridge(const RequestInfo& request_info) override {
- EXPECT_FALSE(bridge_.get());
- TestBridge* bridge = new TestBridge(request_info);
- bridge_ = bridge->AsWeakPtr();
- return bridge;
- }
-
- TestBridge* bridge() { return bridge_.get(); }
-
- private:
- base::WeakPtr<TestBridge> bridge_;
-
DISALLOW_COPY_AND_ASSIGN(TestResourceDispatcher);
};
class TestWebURLLoaderClient : public blink::WebURLLoaderClient {
public:
- TestWebURLLoaderClient(ResourceDispatcher* dispatcher)
- : loader_(new WebURLLoaderImpl(dispatcher)),
+ TestWebURLLoaderClient(
+ ResourceDispatcher* dispatcher,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+ : loader_(new WebURLLoaderImpl(dispatcher, task_runner)),
expect_multipart_response_(false),
delete_on_receive_redirect_(false),
delete_on_receive_response_(false),
@@ -144,13 +113,12 @@ class TestWebURLLoaderClient : public blink::WebURLLoaderClient {
delete_on_fail_(false),
did_receive_redirect_(false),
did_receive_response_(false),
- did_finish_(false) {
- }
+ did_finish_(false) {}
- virtual ~TestWebURLLoaderClient() {}
+ ~TestWebURLLoaderClient() override {}
// blink::WebURLLoaderClient implementation:
- virtual void willSendRequest(
+ void willSendRequest(
blink::WebURLLoader* loader,
blink::WebURLRequest& newRequest,
const blink::WebURLResponse& redirectResponse) override {
@@ -164,14 +132,14 @@ class TestWebURLLoaderClient : public blink::WebURLLoaderClient {
loader_.reset();
}
- virtual void didSendData(blink::WebURLLoader* loader,
- unsigned long long bytesSent,
- unsigned long long totalBytesToBeSent) override {
+ void didSendData(blink::WebURLLoader* loader,
+ unsigned long long bytesSent,
+ unsigned long long totalBytesToBeSent) override {
EXPECT_TRUE(loader_);
EXPECT_EQ(loader_.get(), loader);
}
- virtual void didReceiveResponse(
+ void didReceiveResponse(
blink::WebURLLoader* loader,
const blink::WebURLResponse& response) override {
EXPECT_TRUE(loader_);
@@ -186,17 +154,17 @@ class TestWebURLLoaderClient : public blink::WebURLLoaderClient {
loader_.reset();
}
- virtual void didDownloadData(blink::WebURLLoader* loader,
- int dataLength,
- int encodedDataLength) override {
+ void didDownloadData(blink::WebURLLoader* loader,
+ int dataLength,
+ int encodedDataLength) override {
EXPECT_TRUE(loader_);
EXPECT_EQ(loader_.get(), loader);
}
- virtual void didReceiveData(blink::WebURLLoader* loader,
- const char* data,
- int dataLength,
- int encodedDataLength) override {
+ void didReceiveData(blink::WebURLLoader* loader,
+ const char* data,
+ int dataLength,
+ int encodedDataLength) override {
EXPECT_TRUE(loader_);
EXPECT_EQ(loader_.get(), loader);
// The response should have started, but must not have finished, or failed.
@@ -211,15 +179,15 @@ class TestWebURLLoaderClient : public blink::WebURLLoaderClient {
loader_.reset();
}
- virtual void didReceiveCachedMetadata(blink::WebURLLoader* loader,
- const char* data,
- int dataLength) override {
+ void didReceiveCachedMetadata(blink::WebURLLoader* loader,
+ const char* data,
+ int dataLength) override {
EXPECT_EQ(loader_.get(), loader);
}
- virtual void didFinishLoading(blink::WebURLLoader* loader,
- double finishTime,
- int64_t totalEncodedDataLength) override {
+ void didFinishLoading(blink::WebURLLoader* loader,
+ double finishTime,
+ int64_t totalEncodedDataLength) override {
EXPECT_TRUE(loader_);
EXPECT_EQ(loader_.get(), loader);
EXPECT_TRUE(did_receive_response_);
@@ -230,8 +198,8 @@ class TestWebURLLoaderClient : public blink::WebURLLoaderClient {
loader_.reset();
}
- virtual void didFail(blink::WebURLLoader* loader,
- const blink::WebURLError& error) override {
+ void didFail(blink::WebURLLoader* loader,
+ const blink::WebURLError& error) override {
EXPECT_TRUE(loader_);
EXPECT_EQ(loader_.get(), loader);
EXPECT_FALSE(did_finish_);
@@ -284,7 +252,8 @@ class TestWebURLLoaderClient : public blink::WebURLLoaderClient {
class WebURLLoaderImplTest : public testing::Test {
public:
- explicit WebURLLoaderImplTest() : client_(&dispatcher_) {}
+ explicit WebURLLoaderImplTest()
+ : client_(&dispatcher_, message_loop_.task_runner()) {}
~WebURLLoaderImplTest() override {}
void DoStartAsyncRequest() {
@@ -292,7 +261,6 @@ class WebURLLoaderImplTest : public testing::Test {
request.initialize();
request.setURL(GURL(kTestURL));
client()->loader()->loadAsynchronously(request, client());
- ASSERT_TRUE(bridge());
ASSERT_TRUE(peer());
}
@@ -374,15 +342,14 @@ class WebURLLoaderImplTest : public testing::Test {
}
TestWebURLLoaderClient* client() { return &client_; }
- TestBridge* bridge() { return dispatcher_.bridge(); }
- RequestPeer* peer() { return bridge()->peer(); }
+ TestResourceDispatcher* dispatcher() { return &dispatcher_; }
+ RequestPeer* peer() { return dispatcher()->peer(); }
base::MessageLoop* message_loop() { return &message_loop_; }
private:
+ base::MessageLoop message_loop_;
TestResourceDispatcher dispatcher_;
TestWebURLLoaderClient client_;
-
- base::MessageLoop message_loop_;
};
TEST_F(WebURLLoaderImplTest, Success) {
@@ -390,7 +357,7 @@ TEST_F(WebURLLoaderImplTest, Success) {
DoReceiveResponse();
DoReceiveData();
DoCompleteRequest();
- EXPECT_FALSE(bridge()->canceled());
+ EXPECT_FALSE(dispatcher()->canceled());
EXPECT_EQ(kTestData, client()->received_data());
}
@@ -400,7 +367,7 @@ TEST_F(WebURLLoaderImplTest, Redirect) {
DoReceiveResponse();
DoReceiveData();
DoCompleteRequest();
- EXPECT_FALSE(bridge()->canceled());
+ EXPECT_FALSE(dispatcher()->canceled());
EXPECT_EQ(kTestData, client()->received_data());
}
@@ -409,7 +376,7 @@ TEST_F(WebURLLoaderImplTest, Failure) {
DoReceiveResponse();
DoReceiveData();
DoFailRequest();
- EXPECT_FALSE(bridge()->canceled());
+ EXPECT_FALSE(dispatcher()->canceled());
}
// The client may delete the WebURLLoader during any callback from the loader.
@@ -418,14 +385,12 @@ TEST_F(WebURLLoaderImplTest, DeleteOnReceiveRedirect) {
client()->set_delete_on_receive_redirect();
DoStartAsyncRequest();
DoReceiveRedirect();
- EXPECT_FALSE(bridge());
}
TEST_F(WebURLLoaderImplTest, DeleteOnReceiveResponse) {
client()->set_delete_on_receive_response();
DoStartAsyncRequest();
DoReceiveResponse();
- EXPECT_FALSE(bridge());
}
TEST_F(WebURLLoaderImplTest, DeleteOnReceiveData) {
@@ -433,7 +398,6 @@ TEST_F(WebURLLoaderImplTest, DeleteOnReceiveData) {
DoStartAsyncRequest();
DoReceiveResponse();
DoReceiveData();
- EXPECT_FALSE(bridge());
}
TEST_F(WebURLLoaderImplTest, DeleteOnFinish) {
@@ -442,7 +406,6 @@ TEST_F(WebURLLoaderImplTest, DeleteOnFinish) {
DoReceiveResponse();
DoReceiveData();
DoCompleteRequest();
- EXPECT_FALSE(bridge());
}
TEST_F(WebURLLoaderImplTest, DeleteOnFail) {
@@ -451,7 +414,6 @@ TEST_F(WebURLLoaderImplTest, DeleteOnFail) {
DoReceiveResponse();
DoReceiveData();
DoFailRequest();
- EXPECT_FALSE(bridge());
}
TEST_F(WebURLLoaderImplTest, DeleteBeforeResponseDataURL) {
@@ -462,7 +424,6 @@ TEST_F(WebURLLoaderImplTest, DeleteBeforeResponseDataURL) {
client()->DeleteLoader();
message_loop()->RunUntilIdle();
EXPECT_FALSE(client()->did_receive_response());
- EXPECT_FALSE(bridge());
}
// Data URL tests.
@@ -489,7 +450,6 @@ TEST_F(WebURLLoaderImplTest, DataURLDeleteOnReceiveResponse) {
EXPECT_TRUE(client()->did_receive_response());
EXPECT_EQ("", client()->received_data());
EXPECT_FALSE(client()->did_finish());
- EXPECT_FALSE(bridge());
}
TEST_F(WebURLLoaderImplTest, DataURLDeleteOnReceiveData) {
@@ -502,10 +462,9 @@ TEST_F(WebURLLoaderImplTest, DataURLDeleteOnReceiveData) {
EXPECT_TRUE(client()->did_receive_response());
EXPECT_EQ("blah!", client()->received_data());
EXPECT_FALSE(client()->did_finish());
- EXPECT_FALSE(bridge());
}
-TEST_F(WebURLLoaderImplTest, DataURLDeleteOnFinisha) {
+TEST_F(WebURLLoaderImplTest, DataURLDeleteOnFinish) {
blink::WebURLRequest request;
request.initialize();
request.setURL(GURL("data:text/html;charset=utf-8,blah!"));
@@ -515,7 +474,44 @@ TEST_F(WebURLLoaderImplTest, DataURLDeleteOnFinisha) {
EXPECT_TRUE(client()->did_receive_response());
EXPECT_EQ("blah!", client()->received_data());
EXPECT_TRUE(client()->did_finish());
- EXPECT_FALSE(bridge());
+}
+
+TEST_F(WebURLLoaderImplTest, DataURLDefersLoading) {
+ blink::WebURLRequest request;
+ request.initialize();
+ request.setURL(GURL("data:text/html;charset=utf-8,blah!"));
+ client()->loader()->loadAsynchronously(request, client());
+
+ // setDefersLoading() might be called with either false or true in no
+ // specific order. The user of the API will not have sufficient information
+ // about the WebURLLoader's internal state, so the latter gracefully needs to
+ // handle calling setDefersLoading any number of times with any values from
+ // any point in time.
+
+ client()->loader()->setDefersLoading(false);
+ client()->loader()->setDefersLoading(true);
+ client()->loader()->setDefersLoading(true);
+ message_loop()->RunUntilIdle();
+ EXPECT_FALSE(client()->did_finish());
+
+ client()->loader()->setDefersLoading(false);
+ client()->loader()->setDefersLoading(true);
+ message_loop()->RunUntilIdle();
+ EXPECT_FALSE(client()->did_finish());
+
+ client()->loader()->setDefersLoading(false);
+ message_loop()->RunUntilIdle();
+ EXPECT_TRUE(client()->did_finish());
+
+ client()->loader()->setDefersLoading(true);
+ client()->loader()->setDefersLoading(false);
+ client()->loader()->setDefersLoading(false);
+ message_loop()->RunUntilIdle();
+ EXPECT_TRUE(client()->did_finish());
+
+ EXPECT_EQ("blah!", client()->received_data());
+ EXPECT_EQ(net::OK, client()->error().reason);
+ EXPECT_EQ("", client()->error().domain.utf8());
}
// FTP integration tests. These are focused more on safe deletion than correct
@@ -526,7 +522,7 @@ TEST_F(WebURLLoaderImplTest, Ftp) {
DoReceiveResponseFtp();
DoReceiveDataFtp();
DoCompleteRequest();
- EXPECT_FALSE(bridge()->canceled());
+ EXPECT_FALSE(dispatcher()->canceled());
}
TEST_F(WebURLLoaderImplTest, FtpDeleteOnReceiveResponse) {
@@ -536,18 +532,14 @@ TEST_F(WebURLLoaderImplTest, FtpDeleteOnReceiveResponse) {
// No data should have been received.
EXPECT_EQ("", client()->received_data());
- EXPECT_FALSE(bridge());
}
TEST_F(WebURLLoaderImplTest, FtpDeleteOnReceiveFirstData) {
client()->set_delete_on_receive_data();
DoStartAsyncRequest();
- // Some data is sent in ReceiveResponse for FTP requests, so the bridge should
- // be deleted here.
DoReceiveResponseFtp();
EXPECT_NE("", client()->received_data());
- EXPECT_FALSE(bridge());
}
TEST_F(WebURLLoaderImplTest, FtpDeleteOnReceiveMoreData) {
@@ -561,8 +553,6 @@ TEST_F(WebURLLoaderImplTest, FtpDeleteOnReceiveMoreData) {
peer()->OnCompletedRequest(net::OK, false, false, "", base::TimeTicks(),
strlen(kTestData));
EXPECT_FALSE(client()->did_finish());
-
- EXPECT_FALSE(bridge());
}
TEST_F(WebURLLoaderImplTest, FtpDeleteOnFinish) {
@@ -571,7 +561,6 @@ TEST_F(WebURLLoaderImplTest, FtpDeleteOnFinish) {
DoReceiveResponseFtp();
DoReceiveDataFtp();
DoCompleteRequest();
- EXPECT_FALSE(bridge());
}
TEST_F(WebURLLoaderImplTest, FtpDeleteOnFail) {
@@ -580,7 +569,6 @@ TEST_F(WebURLLoaderImplTest, FtpDeleteOnFail) {
DoReceiveResponseFtp();
DoReceiveDataFtp();
DoFailRequest();
- EXPECT_FALSE(bridge());
}
// Multipart integration tests. These are focused more on safe deletion than
@@ -593,7 +581,7 @@ TEST_F(WebURLLoaderImplTest, Multipart) {
DoReceiveDataMultipart();
DoCompleteRequest();
EXPECT_EQ(kTestData, client()->received_data());
- EXPECT_FALSE(bridge()->canceled());
+ EXPECT_FALSE(dispatcher()->canceled());
}
TEST_F(WebURLLoaderImplTest, MultipartDeleteOnReceiveFirstResponse) {
@@ -602,7 +590,6 @@ TEST_F(WebURLLoaderImplTest, MultipartDeleteOnReceiveFirstResponse) {
DoStartAsyncRequest();
DoReceiveResponseMultipart();
EXPECT_EQ("", client()->received_data());
- EXPECT_FALSE(bridge());
}
TEST_F(WebURLLoaderImplTest, MultipartDeleteOnReceiveSecondResponse) {
@@ -612,7 +599,6 @@ TEST_F(WebURLLoaderImplTest, MultipartDeleteOnReceiveSecondResponse) {
client()->set_delete_on_receive_response();
DoReceiveDataMultipart();
EXPECT_EQ("", client()->received_data());
- EXPECT_FALSE(bridge());
}
TEST_F(WebURLLoaderImplTest, MultipartDeleteOnReceiveFirstData) {
@@ -622,7 +608,6 @@ TEST_F(WebURLLoaderImplTest, MultipartDeleteOnReceiveFirstData) {
DoReceiveResponseMultipart();
DoReceiveDataMultipart();
EXPECT_EQ("bl", client()->received_data());
- EXPECT_FALSE(bridge());
}
TEST_F(WebURLLoaderImplTest, MultipartDeleteOnReceiveMoreData) {
@@ -637,7 +622,6 @@ TEST_F(WebURLLoaderImplTest, MultipartDeleteOnReceiveMoreData) {
strlen(kTestData));
EXPECT_FALSE(client()->did_finish());
EXPECT_EQ(kTestData, client()->received_data());
- EXPECT_FALSE(bridge());
}
TEST_F(WebURLLoaderImplTest, MultipartDeleteFinish) {
@@ -648,7 +632,6 @@ TEST_F(WebURLLoaderImplTest, MultipartDeleteFinish) {
DoReceiveDataMultipart();
DoCompleteRequest();
EXPECT_EQ(kTestData, client()->received_data());
- EXPECT_FALSE(bridge());
}
TEST_F(WebURLLoaderImplTest, MultipartDeleteFail) {
@@ -658,7 +641,6 @@ TEST_F(WebURLLoaderImplTest, MultipartDeleteFail) {
DoReceiveResponseMultipart();
DoReceiveDataMultipart();
DoFailRequest();
- EXPECT_FALSE(bridge());
}
// PlzNavigate: checks that the stream override parameters provided on
@@ -679,15 +661,14 @@ TEST_F(WebURLLoaderImplTest, BrowserSideNavigationCommit) {
RequestExtraData* extra_data = new RequestExtraData();
extra_data->set_stream_override(stream_override.Pass());
request.setExtraData(extra_data);
- CommandLine::ForCurrentProcess()->AppendSwitch(
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableBrowserSideNavigation);
client()->loader()->loadAsynchronously(request, client());
// The stream url should have been requestead instead of the request url.
- ASSERT_TRUE(bridge());
ASSERT_TRUE(peer());
- EXPECT_EQ(kStreamURL, bridge()->url());
+ EXPECT_EQ(kStreamURL, dispatcher()->url());
EXPECT_FALSE(client()->did_receive_response());
peer()->OnReceivedResponse(content::ResourceResponseInfo());
@@ -699,7 +680,7 @@ TEST_F(WebURLLoaderImplTest, BrowserSideNavigationCommit) {
DoReceiveData();
DoCompleteRequest();
- EXPECT_FALSE(bridge()->canceled());
+ EXPECT_FALSE(dispatcher()->canceled());
EXPECT_EQ(kTestData, client()->received_data());
}
diff --git a/chromium/content/child/web_url_request_util.cc b/chromium/content/child/web_url_request_util.cc
index 6f03e998b97..6737307c744 100644
--- a/chromium/content/child/web_url_request_util.cc
+++ b/chromium/content/child/web_url_request_util.cc
@@ -7,17 +7,25 @@
#include "base/logging.h"
#include "base/strings/string_util.h"
#include "net/base/load_flags.h"
+#include "net/base/net_errors.h"
#include "third_party/WebKit/public/platform/WebHTTPHeaderVisitor.h"
#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/platform/WebURL.h"
+#include "third_party/WebKit/public/platform/WebURLError.h"
#include "third_party/WebKit/public/platform/WebURLRequest.h"
-using blink::WebURLRequest;
+using blink::WebHTTPBody;
using blink::WebString;
+using blink::WebURLRequest;
namespace content {
namespace {
+const char kThrottledErrorDescription[] =
+ "Request throttled. Visit http://dev.chromium.org/throttling for more "
+ "information.";
+
class HeaderFlattener : public blink::WebHTTPHeaderVisitor {
public:
HeaderFlattener() : has_accept_header_(false) {}
@@ -208,11 +216,87 @@ int GetLoadFlagsForWebURLRequest(const blink::WebURLRequest& request) {
if (!request.allowStoredCredentials())
load_flags |= net::LOAD_DO_NOT_SEND_AUTH_DATA;
- if (request.requestContext() == WebURLRequest::RequestContextXMLHttpRequest &&
- (url.has_username() || url.has_password())) {
- load_flags |= net::LOAD_DO_NOT_PROMPT_FOR_LOGIN;
- }
return load_flags;
}
+scoped_refptr<ResourceRequestBody> GetRequestBodyForWebURLRequest(
+ const blink::WebURLRequest& request) {
+ scoped_refptr<ResourceRequestBody> request_body;
+
+ if (request.httpBody().isNull()) {
+ return request_body;
+ }
+
+ const std::string& method = request.httpMethod().latin1();
+ // GET and HEAD requests shouldn't have http bodies.
+ DCHECK(method != "GET" && method != "HEAD");
+
+ const WebHTTPBody& httpBody = request.httpBody();
+ request_body = new ResourceRequestBody();
+ size_t i = 0;
+ WebHTTPBody::Element element;
+ while (httpBody.elementAt(i++, element)) {
+ switch (element.type) {
+ case WebHTTPBody::Element::TypeData:
+ if (!element.data.isEmpty()) {
+ // Blink sometimes gives empty data to append. These aren't
+ // necessary so they are just optimized out here.
+ request_body->AppendBytes(
+ element.data.data(), static_cast<int>(element.data.size()));
+ }
+ break;
+ case WebHTTPBody::Element::TypeFile:
+ if (element.fileLength == -1) {
+ request_body->AppendFileRange(
+ base::FilePath::FromUTF16Unsafe(element.filePath),
+ 0, kuint64max, base::Time());
+ } else {
+ request_body->AppendFileRange(
+ base::FilePath::FromUTF16Unsafe(element.filePath),
+ static_cast<uint64>(element.fileStart),
+ static_cast<uint64>(element.fileLength),
+ base::Time::FromDoubleT(element.modificationTime));
+ }
+ break;
+ case WebHTTPBody::Element::TypeFileSystemURL: {
+ GURL file_system_url = element.fileSystemURL;
+ DCHECK(file_system_url.SchemeIsFileSystem());
+ request_body->AppendFileSystemFileRange(
+ file_system_url,
+ static_cast<uint64>(element.fileStart),
+ static_cast<uint64>(element.fileLength),
+ base::Time::FromDoubleT(element.modificationTime));
+ break;
+ }
+ case WebHTTPBody::Element::TypeBlob:
+ request_body->AppendBlob(element.blobUUID.utf8());
+ break;
+ default:
+ NOTREACHED();
+ }
+ }
+ request_body->set_identifier(request.httpBody().identifier());
+ return request_body;
+}
+
+blink::WebURLError CreateWebURLError(const blink::WebURL& unreachable_url,
+ bool stale_copy_in_cache,
+ int reason) {
+ blink::WebURLError error;
+ error.domain = WebString::fromUTF8(net::kErrorDomain);
+ error.reason = reason;
+ error.unreachableURL = unreachable_url;
+ error.staleCopyInCache = stale_copy_in_cache;
+ if (reason == net::ERR_ABORTED) {
+ error.isCancellation = true;
+ } else if (reason == net::ERR_TEMPORARILY_THROTTLED) {
+ error.localizedDescription =
+ WebString::fromUTF8(kThrottledErrorDescription);
+ } else {
+ error.localizedDescription =
+ WebString::fromUTF8(net::ErrorToString(reason));
+ }
+ return error;
+}
+
} // namespace content
diff --git a/chromium/content/child/web_url_request_util.h b/chromium/content/child/web_url_request_util.h
index b746d8067d2..f12b5401377 100644
--- a/chromium/content/child/web_url_request_util.h
+++ b/chromium/content/child/web_url_request_util.h
@@ -2,16 +2,19 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CONTENT_CHILD_TARGET_TYPE_CONVERSION_H_
-#define CONTENT_CHILD_TARGET_TYPE_CONVERSION_H_
+#ifndef CONTENT_CHILD_WEB_URL_REQUEST_UTIL_H_
+#define CONTENT_CHILD_WEB_URL_REQUEST_UTIL_H_
#include <string>
#include "content/common/content_export.h"
+#include "content/common/resource_request_body.h"
#include "content/public/common/resource_type.h"
namespace blink {
+class WebURL;
class WebURLRequest;
+struct WebURLError;
}
namespace content {
@@ -23,6 +26,17 @@ std::string GetWebURLRequestHeaders(const blink::WebURLRequest& request);
int GetLoadFlagsForWebURLRequest(const blink::WebURLRequest& request);
+// Takes a WebURLRequest and sets the appropriate information
+// in a ResourceRequestBody structure. Returns an empty scoped_refptr
+// if the request body is not present.
+scoped_refptr<ResourceRequestBody> GetRequestBodyForWebURLRequest(
+ const blink::WebURLRequest& request);
+
+// Generates a WebURLError based on |reason|.
+blink::WebURLError CreateWebURLError(const blink::WebURL& unreachable_url,
+ bool stale_copy_in_cache,
+ int reason);
+
} // namespace content
-#endif // CONTENT_CHILD_TARGET_TYPE_CONVERSION_H_
+#endif // CONTENT_CHILD_WEB_URL_REQUEST_UTIL_H_
diff --git a/chromium/content/child/webblobregistry_impl.cc b/chromium/content/child/webblobregistry_impl.cc
index 9503ec5a6e6..22f6f43acdc 100644
--- a/chromium/content/child/webblobregistry_impl.cc
+++ b/chromium/content/child/webblobregistry_impl.cc
@@ -9,10 +9,10 @@
#include "base/memory/ref_counted.h"
#include "base/memory/shared_memory.h"
#include "base/message_loop/message_loop.h"
-#include "content/child/child_thread.h"
+#include "base/trace_event/trace_event.h"
+#include "content/child/child_thread_impl.h"
#include "content/child/thread_safe_sender.h"
#include "content/common/fileapi/webblob_messages.h"
-#include "storage/common/blob/blob_data.h"
#include "third_party/WebKit/public/platform/WebBlobData.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/platform/WebThreadSafeData.h"
@@ -34,6 +34,9 @@ const size_t kMaxSharedMemoryBytes = 10 * 1024 * 1024;
WebBlobRegistryImpl::WebBlobRegistryImpl(ThreadSafeSender* sender)
: sender_(sender) {
+ // Record a dummy trace event on startup so the 'Storage' category shows up
+ // in the chrome://tracing viewer.
+ TRACE_EVENT0("Blob", "Init");
}
WebBlobRegistryImpl::~WebBlobRegistryImpl() {
@@ -41,60 +44,75 @@ WebBlobRegistryImpl::~WebBlobRegistryImpl() {
void WebBlobRegistryImpl::registerBlobData(
const blink::WebString& uuid, const blink::WebBlobData& data) {
+ TRACE_EVENT0("Blob", "Registry::RegisterBlob");
const std::string uuid_str(uuid.utf8());
+ storage::DataElement data_buffer;
+ data_buffer.SetToEmptyBytes();
+
sender_->Send(new BlobHostMsg_StartBuilding(uuid_str));
size_t i = 0;
WebBlobData::Item data_item;
while (data.itemAt(i++, data_item)) {
+ // NOTE: data_item.length == -1 when we want to use the whole file. This
+ // only happens when we are creating a file object in Blink, and the file
+ // object is the only item in the 'blob'. If we use that file blob to
+ // create another blob, it is sent here as a 'file' item and not a blob,
+ // and the correct size is populated.
+ // static_cast<uint64>(-1) == kuint64max, which is what DataElement uses
+ // to specificy "use the whole file".
+ if (data_item.length == 0) {
+ continue;
+ }
+ if (data_item.type != WebBlobData::Item::TypeData &&
+ data_buffer.length() != 0) {
+ FlushBlobItemBuffer(uuid_str, &data_buffer);
+ }
+ storage::DataElement item;
switch (data_item.type) {
case WebBlobData::Item::TypeData: {
// WebBlobData does not allow partial data items.
DCHECK(!data_item.offset && data_item.length == -1);
- SendDataForBlob(uuid_str, data_item.data);
+ if (data_item.data.size() == 0) {
+ continue;
+ }
+ BufferBlobData(uuid_str, data_item.data, &data_buffer);
break;
}
case WebBlobData::Item::TypeFile:
- if (data_item.length) {
- storage::BlobData::Item item;
- item.SetToFilePathRange(
- base::FilePath::FromUTF16Unsafe(data_item.filePath),
- static_cast<uint64>(data_item.offset),
- static_cast<uint64>(data_item.length),
- base::Time::FromDoubleT(data_item.expectedModificationTime));
- sender_->Send(
- new BlobHostMsg_AppendBlobDataItem(uuid_str, item));
- }
+ item.SetToFilePathRange(
+ base::FilePath::FromUTF16Unsafe(data_item.filePath),
+ static_cast<uint64>(data_item.offset),
+ static_cast<uint64>(data_item.length),
+ base::Time::FromDoubleT(data_item.expectedModificationTime));
+ sender_->Send(new BlobHostMsg_AppendBlobDataItem(uuid_str, item));
break;
case WebBlobData::Item::TypeBlob:
- if (data_item.length) {
- storage::BlobData::Item item;
- item.SetToBlobRange(
- data_item.blobUUID.utf8(),
- static_cast<uint64>(data_item.offset),
- static_cast<uint64>(data_item.length));
- sender_->Send(
- new BlobHostMsg_AppendBlobDataItem(uuid_str, item));
- }
+ item.SetToBlobRange(
+ data_item.blobUUID.utf8(),
+ static_cast<uint64>(data_item.offset),
+ static_cast<uint64>(data_item.length));
+ sender_->Send(
+ new BlobHostMsg_AppendBlobDataItem(uuid_str, item));
break;
case WebBlobData::Item::TypeFileSystemURL:
- if (data_item.length) {
- // We only support filesystem URL as of now.
- DCHECK(GURL(data_item.fileSystemURL).SchemeIsFileSystem());
- storage::BlobData::Item item;
- item.SetToFileSystemUrlRange(
- data_item.fileSystemURL,
- static_cast<uint64>(data_item.offset),
- static_cast<uint64>(data_item.length),
- base::Time::FromDoubleT(data_item.expectedModificationTime));
- sender_->Send(
- new BlobHostMsg_AppendBlobDataItem(uuid_str, item));
- }
+ // We only support filesystem URL as of now.
+ DCHECK(GURL(data_item.fileSystemURL).SchemeIsFileSystem());
+ item.SetToFileSystemUrlRange(
+ data_item.fileSystemURL,
+ static_cast<uint64>(data_item.offset),
+ static_cast<uint64>(data_item.length),
+ base::Time::FromDoubleT(data_item.expectedModificationTime));
+ sender_->Send(
+ new BlobHostMsg_AppendBlobDataItem(uuid_str, item));
break;
default:
NOTREACHED();
}
}
+ if (data_buffer.length() != 0) {
+ FlushBlobItemBuffer(uuid_str, &data_buffer);
+ }
sender_->Send(new BlobHostMsg_FinishBuilding(
uuid_str, data.contentType().utf8().data()));
}
@@ -116,35 +134,57 @@ void WebBlobRegistryImpl::revokePublicBlobURL(const WebURL& url) {
sender_->Send(new BlobHostMsg_RevokePublicURL(url));
}
-void WebBlobRegistryImpl::SendDataForBlob(const std::string& uuid_str,
- const WebThreadSafeData& data) {
+void WebBlobRegistryImpl::FlushBlobItemBuffer(
+ const std::string& uuid_str,
+ storage::DataElement* data_buffer) const {
+ DCHECK_NE(data_buffer->length(), 0ul);
+ DCHECK_LT(data_buffer->length(), kLargeThresholdBytes);
+ sender_->Send(new BlobHostMsg_AppendBlobDataItem(uuid_str, *data_buffer));
+ data_buffer->SetToEmptyBytes();
+}
- if (data.size() == 0)
- return;
- if (data.size() < kLargeThresholdBytes) {
- storage::BlobData::Item item;
- item.SetToBytes(data.data(), data.size());
- sender_->Send(new BlobHostMsg_AppendBlobDataItem(uuid_str, item));
+void WebBlobRegistryImpl::BufferBlobData(const std::string& uuid_str,
+ const blink::WebThreadSafeData& data,
+ storage::DataElement* data_buffer) {
+ size_t buffer_size = data_buffer->length();
+ size_t data_size = data.size();
+ DCHECK_NE(data_size, 0ul);
+ if (buffer_size != 0 && buffer_size + data_size >= kLargeThresholdBytes) {
+ FlushBlobItemBuffer(uuid_str, data_buffer);
+ buffer_size = 0;
+ }
+ if (data_size >= kLargeThresholdBytes) {
+ TRACE_EVENT0("Blob", "Registry::SendOversizedBlobData");
+ SendOversizedDataForBlob(uuid_str, data);
} else {
- // We handle larger amounts of data via SharedMemory instead of
- // writing it directly to the IPC channel.
- size_t shared_memory_size = std::min(
- data.size(), kMaxSharedMemoryBytes);
- scoped_ptr<base::SharedMemory> shared_memory(
- ChildThread::AllocateSharedMemory(shared_memory_size,
- sender_.get()));
- CHECK(shared_memory.get());
+ DCHECK_LT(buffer_size + data_size, kLargeThresholdBytes);
+ data_buffer->AppendBytes(data.data(), data_size);
+ }
+}
- size_t data_size = data.size();
- const char* data_ptr = data.data();
- while (data_size) {
- size_t chunk_size = std::min(data_size, shared_memory_size);
- memcpy(shared_memory->memory(), data_ptr, chunk_size);
- sender_->Send(new BlobHostMsg_SyncAppendSharedMemory(
- uuid_str, shared_memory->handle(), chunk_size));
- data_size -= chunk_size;
- data_ptr += chunk_size;
- }
+void WebBlobRegistryImpl::SendOversizedDataForBlob(
+ const std::string& uuid_str,
+ const blink::WebThreadSafeData& data) {
+ DCHECK_GE(data.size(), kLargeThresholdBytes);
+ // We handle larger amounts of data via SharedMemory instead of
+ // writing it directly to the IPC channel.
+ size_t shared_memory_size = std::min(data.size(), kMaxSharedMemoryBytes);
+ scoped_ptr<base::SharedMemory> shared_memory(
+ ChildThreadImpl::AllocateSharedMemory(shared_memory_size, sender_.get()));
+ CHECK(shared_memory.get());
+ if (!shared_memory->Map(shared_memory_size))
+ CHECK(false);
+
+ size_t data_size = data.size();
+ const char* data_ptr = data.data();
+ while (data_size) {
+ TRACE_EVENT0("Blob", "Registry::SendOversizedBlobItem");
+ size_t chunk_size = std::min(data_size, shared_memory_size);
+ memcpy(shared_memory->memory(), data_ptr, chunk_size);
+ sender_->Send(new BlobHostMsg_SyncAppendSharedMemory(
+ uuid_str, shared_memory->handle(), chunk_size));
+ data_size -= chunk_size;
+ data_ptr += chunk_size;
}
}
@@ -152,23 +192,23 @@ void WebBlobRegistryImpl::SendDataForBlob(const std::string& uuid_str,
void WebBlobRegistryImpl::registerStreamURL(
const WebURL& url, const WebString& content_type) {
- DCHECK(ChildThread::current());
+ DCHECK(ChildThreadImpl::current());
sender_->Send(new StreamHostMsg_StartBuilding(url, content_type.utf8()));
}
void WebBlobRegistryImpl::registerStreamURL(
const WebURL& url, const WebURL& src_url) {
- DCHECK(ChildThread::current());
+ DCHECK(ChildThreadImpl::current());
sender_->Send(new StreamHostMsg_Clone(url, src_url));
}
void WebBlobRegistryImpl::addDataToStream(const WebURL& url,
const char* data, size_t length) {
- DCHECK(ChildThread::current());
+ DCHECK(ChildThreadImpl::current());
if (length == 0)
return;
if (length < kLargeThresholdBytes) {
- storage::BlobData::Item item;
+ storage::DataElement item;
item.SetToBytes(data, length);
sender_->Send(new StreamHostMsg_AppendBlobDataItem(url, item));
} else {
@@ -177,9 +217,11 @@ void WebBlobRegistryImpl::addDataToStream(const WebURL& url,
size_t shared_memory_size = std::min(
length, kMaxSharedMemoryBytes);
scoped_ptr<base::SharedMemory> shared_memory(
- ChildThread::AllocateSharedMemory(shared_memory_size,
- sender_.get()));
+ ChildThreadImpl::AllocateSharedMemory(shared_memory_size,
+ sender_.get()));
CHECK(shared_memory.get());
+ if (!shared_memory->Map(shared_memory_size))
+ CHECK(false);
size_t remaining_bytes = length;
const char* current_ptr = data;
@@ -194,18 +236,23 @@ void WebBlobRegistryImpl::addDataToStream(const WebURL& url,
}
}
+void WebBlobRegistryImpl::flushStream(const WebURL& url) {
+ DCHECK(ChildThreadImpl::current());
+ sender_->Send(new StreamHostMsg_Flush(url));
+}
+
void WebBlobRegistryImpl::finalizeStream(const WebURL& url) {
- DCHECK(ChildThread::current());
+ DCHECK(ChildThreadImpl::current());
sender_->Send(new StreamHostMsg_FinishBuilding(url));
}
void WebBlobRegistryImpl::abortStream(const WebURL& url) {
- DCHECK(ChildThread::current());
+ DCHECK(ChildThreadImpl::current());
sender_->Send(new StreamHostMsg_AbortBuilding(url));
}
void WebBlobRegistryImpl::unregisterStreamURL(const WebURL& url) {
- DCHECK(ChildThread::current());
+ DCHECK(ChildThreadImpl::current());
sender_->Send(new StreamHostMsg_Remove(url));
}
diff --git a/chromium/content/child/webblobregistry_impl.h b/chromium/content/child/webblobregistry_impl.h
index 8fa967d9de7..c9d7989e2c4 100644
--- a/chromium/content/child/webblobregistry_impl.h
+++ b/chromium/content/child/webblobregistry_impl.h
@@ -6,6 +6,7 @@
#define CONTENT_CHILD_WEBBLOBREGISTRY_IMPL_H_
#include <string>
+#include <vector>
#include "base/memory/ref_counted.h"
#include "third_party/WebKit/public/platform/WebBlobRegistry.h"
@@ -14,6 +15,10 @@ namespace blink {
class WebThreadSafeData;
} // namespace blink
+namespace storage {
+class DataElement;
+}
+
namespace content {
class ThreadSafeSender;
@@ -37,17 +42,29 @@ class WebBlobRegistryImpl : public blink::WebBlobRegistry {
const blink::WebURL& src_url);
virtual void addDataToStream(const blink::WebURL& url,
const char* data, size_t length);
+ virtual void flushStream(const blink::WebURL& url);
virtual void finalizeStream(const blink::WebURL& url);
virtual void abortStream(const blink::WebURL& url);
virtual void unregisterStreamURL(const blink::WebURL& url);
private:
- void SendDataForBlob(const std::string& uuid_str,
- const blink::WebThreadSafeData& data);
+ // Sends the data in the buffer as a blob item, then resets the buffer size.
+ void FlushBlobItemBuffer(const std::string& uuid_str,
+ storage::DataElement* data_buffer) const;
+
+ // Adds the item to the consolidating buffer, flushing the buffer if needed.
+ // If the item is too big for the buffer, it is sent as Sync messages in
+ // shared memory instead.
+ void BufferBlobData(const std::string& uuid_str,
+ const blink::WebThreadSafeData& data,
+ storage::DataElement* data_buffer);
+ // Sends data that is larger than the threshold.
+ void SendOversizedDataForBlob(const std::string& uuid_str,
+ const blink::WebThreadSafeData& data);
scoped_refptr<ThreadSafeSender> sender_;
};
} // namespace content
-#endif // CONTENT_CHILD_FILEAPI_WEBBLOBREGISTRY_IMPL_H_
+#endif // CONTENT_CHILD_WEBBLOBREGISTRY_IMPL_H_
diff --git a/chromium/content/child/webcrypto/OWNERS b/chromium/content/child/webcrypto/OWNERS
deleted file mode 100644
index 6b60858e6e8..00000000000
--- a/chromium/content/child/webcrypto/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-eroman@chromium.org
-rsleevi@chromium.org
diff --git a/chromium/content/child/webcrypto/algorithm_dispatch.cc b/chromium/content/child/webcrypto/algorithm_dispatch.cc
deleted file mode 100644
index f8d7933c8fc..00000000000
--- a/chromium/content/child/webcrypto/algorithm_dispatch.cc
+++ /dev/null
@@ -1,253 +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/child/webcrypto/algorithm_dispatch.h"
-
-#include "base/logging.h"
-#include "content/child/webcrypto/algorithm_implementation.h"
-#include "content/child/webcrypto/algorithm_registry.h"
-#include "content/child/webcrypto/crypto_data.h"
-#include "content/child/webcrypto/platform_crypto.h"
-#include "content/child/webcrypto/status.h"
-#include "content/child/webcrypto/webcrypto_util.h"
-#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
-
-namespace content {
-
-namespace webcrypto {
-
-namespace {
-
-Status DecryptDontCheckKeyUsage(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) {
- if (algorithm.id() != key.algorithm().id())
- return Status::ErrorUnexpected();
-
- const AlgorithmImplementation* impl = NULL;
- Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
- if (status.IsError())
- return status;
-
- return impl->Decrypt(algorithm, key, data, buffer);
-}
-
-Status EncryptDontCheckUsage(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) {
- if (algorithm.id() != key.algorithm().id())
- return Status::ErrorUnexpected();
-
- const AlgorithmImplementation* impl = NULL;
- Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
- if (status.IsError())
- return status;
-
- return impl->Encrypt(algorithm, key, data, buffer);
-}
-
-Status ExportKeyDontCheckExtractability(blink::WebCryptoKeyFormat format,
- const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) {
- const AlgorithmImplementation* impl = NULL;
- Status status = GetAlgorithmImplementation(key.algorithm().id(), &impl);
- if (status.IsError())
- return status;
-
- switch (format) {
- case blink::WebCryptoKeyFormatRaw:
- return impl->ExportKeyRaw(key, buffer);
- case blink::WebCryptoKeyFormatSpki:
- return impl->ExportKeySpki(key, buffer);
- case blink::WebCryptoKeyFormatPkcs8:
- return impl->ExportKeyPkcs8(key, buffer);
- case blink::WebCryptoKeyFormatJwk:
- return impl->ExportKeyJwk(key, buffer);
- default:
- return Status::ErrorUnsupported();
- }
-}
-
-} // namespace
-
-Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) {
- if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageEncrypt))
- return Status::ErrorUnexpected();
- return EncryptDontCheckUsage(algorithm, key, data, buffer);
-}
-
-Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) {
- if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageDecrypt))
- return Status::ErrorUnexpected();
- return DecryptDontCheckKeyUsage(algorithm, key, data, buffer);
-}
-
-Status Digest(const blink::WebCryptoAlgorithm& algorithm,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) {
- const AlgorithmImplementation* impl = NULL;
- Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
- if (status.IsError())
- return status;
-
- return impl->Digest(algorithm, data, buffer);
-}
-
-Status GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- GenerateKeyResult* result) {
- const AlgorithmImplementation* impl = NULL;
- Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
- if (status.IsError())
- return status;
-
- return impl->GenerateKey(algorithm, extractable, usages, result);
-}
-
-// Note that this function may be called from the target Blink thread.
-Status ImportKey(blink::WebCryptoKeyFormat format,
- const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) {
- const AlgorithmImplementation* impl = NULL;
- Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
- if (status.IsError())
- return status;
-
- status = impl->VerifyKeyUsagesBeforeImportKey(format, usages);
- if (status.IsError())
- return status;
-
- switch (format) {
- case blink::WebCryptoKeyFormatRaw:
- return impl->ImportKeyRaw(key_data, algorithm, extractable, usages, key);
- case blink::WebCryptoKeyFormatSpki:
- return impl->ImportKeySpki(key_data, algorithm, extractable, usages, key);
- case blink::WebCryptoKeyFormatPkcs8:
- return impl->ImportKeyPkcs8(
- key_data, algorithm, extractable, usages, key);
- case blink::WebCryptoKeyFormatJwk:
- return impl->ImportKeyJwk(key_data, algorithm, extractable, usages, key);
- default:
- return Status::ErrorUnsupported();
- }
-}
-
-Status ExportKey(blink::WebCryptoKeyFormat format,
- const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) {
- if (!key.extractable())
- return Status::ErrorKeyNotExtractable();
- return ExportKeyDontCheckExtractability(format, key, buffer);
-}
-
-Status Sign(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) {
- if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageSign))
- return Status::ErrorUnexpected();
- if (algorithm.id() != key.algorithm().id())
- return Status::ErrorUnexpected();
-
- const AlgorithmImplementation* impl = NULL;
- Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
- if (status.IsError())
- return status;
-
- return impl->Sign(algorithm, key, data, buffer);
-}
-
-Status Verify(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& signature,
- const CryptoData& data,
- bool* signature_match) {
- if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageVerify))
- return Status::ErrorUnexpected();
- if (algorithm.id() != key.algorithm().id())
- return Status::ErrorUnexpected();
-
- const AlgorithmImplementation* impl = NULL;
- Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
- if (status.IsError())
- return status;
-
- return impl->Verify(algorithm, key, signature, data, signature_match);
-}
-
-Status WrapKey(blink::WebCryptoKeyFormat format,
- const blink::WebCryptoKey& key_to_wrap,
- const blink::WebCryptoKey& wrapping_key,
- const blink::WebCryptoAlgorithm& wrapping_algorithm,
- std::vector<uint8_t>* buffer) {
- if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageWrapKey))
- return Status::ErrorUnexpected();
-
- std::vector<uint8_t> exported_data;
- Status status = ExportKey(format, key_to_wrap, &exported_data);
- if (status.IsError())
- return status;
- return EncryptDontCheckUsage(
- wrapping_algorithm, wrapping_key, CryptoData(exported_data), buffer);
-}
-
-Status UnwrapKey(blink::WebCryptoKeyFormat format,
- const CryptoData& wrapped_key_data,
- const blink::WebCryptoKey& wrapping_key,
- const blink::WebCryptoAlgorithm& wrapping_algorithm,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) {
- if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageUnwrapKey))
- return Status::ErrorUnexpected();
- if (wrapping_algorithm.id() != wrapping_key.algorithm().id())
- return Status::ErrorUnexpected();
-
- // Fail fast if the import is doomed to fail.
- const AlgorithmImplementation* import_impl = NULL;
- Status status = GetAlgorithmImplementation(algorithm.id(), &import_impl);
- if (status.IsError())
- return status;
-
- status = import_impl->VerifyKeyUsagesBeforeImportKey(format, usages);
- if (status.IsError())
- return status;
-
- std::vector<uint8_t> buffer;
- status = DecryptDontCheckKeyUsage(
- wrapping_algorithm, wrapping_key, wrapped_key_data, &buffer);
- if (status.IsError())
- return status;
-
- // NOTE that returning the details of ImportKey() failures may leak
- // information about the plaintext of the encrypted key (for instance the JWK
- // key_ops). As long as the ImportKey error messages don't describe actual
- // key bytes however this should be OK. For more discussion see
- // http://crubg.com/372040
- return ImportKey(
- format, CryptoData(buffer), algorithm, extractable, usages, key);
-}
-
-scoped_ptr<blink::WebCryptoDigestor> CreateDigestor(
- blink::WebCryptoAlgorithmId algorithm) {
- PlatformInit();
- return CreatePlatformDigestor(algorithm);
-}
-
-} // namespace webcrypto
-
-} // namespace content
diff --git a/chromium/content/child/webcrypto/algorithm_dispatch.h b/chromium/content/child/webcrypto/algorithm_dispatch.h
deleted file mode 100644
index 3eefb46de5d..00000000000
--- a/chromium/content/child/webcrypto/algorithm_dispatch.h
+++ /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.
-
-#ifndef CONTENT_CHILD_WEBCRYPTO_ALGORITHM_DISPATCH_H_
-#define CONTENT_CHILD_WEBCRYPTO_ALGORITHM_DISPATCH_H_
-
-#include <stdint.h>
-#include <vector>
-
-#include "base/memory/scoped_ptr.h"
-#include "content/common/content_export.h"
-#include "third_party/WebKit/public/platform/WebCrypto.h"
-
-namespace content {
-
-namespace webcrypto {
-
-class AlgorithmImplementation;
-class CryptoData;
-class GenerateKeyResult;
-class Status;
-
-// These functions provide an entry point for synchronous webcrypto operations.
-//
-// The inputs to these methods come from Blink, and hence the validations done
-// by Blink can be assumed:
-//
-// * The algorithm parameters are consistent with the algorithm
-// * The key contains the required usage for the operation
-
-CONTENT_EXPORT Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer);
-
-CONTENT_EXPORT Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer);
-
-CONTENT_EXPORT Status Digest(const blink::WebCryptoAlgorithm& algorithm,
- const CryptoData& data,
- std::vector<uint8_t>* buffer);
-
-CONTENT_EXPORT Status GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- GenerateKeyResult* result);
-
-CONTENT_EXPORT Status ImportKey(blink::WebCryptoKeyFormat format,
- const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key);
-
-CONTENT_EXPORT Status ExportKey(blink::WebCryptoKeyFormat format,
- const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer);
-
-CONTENT_EXPORT Status Sign(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer);
-
-CONTENT_EXPORT Status Verify(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& signature,
- const CryptoData& data,
- bool* signature_match);
-
-CONTENT_EXPORT Status
- WrapKey(blink::WebCryptoKeyFormat format,
- const blink::WebCryptoKey& key_to_wrap,
- const blink::WebCryptoKey& wrapping_key,
- const blink::WebCryptoAlgorithm& wrapping_algorithm,
- std::vector<uint8_t>* buffer);
-
-CONTENT_EXPORT Status
- UnwrapKey(blink::WebCryptoKeyFormat format,
- const CryptoData& wrapped_key_data,
- const blink::WebCryptoKey& wrapping_key,
- const blink::WebCryptoAlgorithm& wrapping_algorithm,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key);
-
-CONTENT_EXPORT scoped_ptr<blink::WebCryptoDigestor> CreateDigestor(
- blink::WebCryptoAlgorithmId algorithm);
-
-} // namespace webcrypto
-
-} // namespace content
-
-#endif // CONTENT_CHILD_WEBCRYPTO_ALGORITHM_DISPATCH_H_
diff --git a/chromium/content/child/webcrypto/algorithm_implementation.cc b/chromium/content/child/webcrypto/algorithm_implementation.cc
deleted file mode 100644
index b815a527cf6..00000000000
--- a/chromium/content/child/webcrypto/algorithm_implementation.cc
+++ /dev/null
@@ -1,131 +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/child/webcrypto/algorithm_implementation.h"
-
-#include "content/child/webcrypto/status.h"
-
-namespace content {
-
-namespace webcrypto {
-
-AlgorithmImplementation::~AlgorithmImplementation() {
-}
-
-Status AlgorithmImplementation::Encrypt(
- const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const {
- return Status::ErrorUnsupported();
-}
-
-Status AlgorithmImplementation::Decrypt(
- const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const {
- return Status::ErrorUnsupported();
-}
-
-Status AlgorithmImplementation::Sign(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const {
- return Status::ErrorUnsupported();
-}
-
-Status AlgorithmImplementation::Verify(
- const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& signature,
- const CryptoData& data,
- bool* signature_match) const {
- return Status::ErrorUnsupported();
-}
-
-Status AlgorithmImplementation::Digest(
- const blink::WebCryptoAlgorithm& algorithm,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const {
- return Status::ErrorUnsupported();
-}
-
-Status AlgorithmImplementation::GenerateKey(
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- GenerateKeyResult* result) const {
- return Status::ErrorUnsupported();
-}
-
-Status AlgorithmImplementation::VerifyKeyUsagesBeforeImportKey(
- blink::WebCryptoKeyFormat format,
- blink::WebCryptoKeyUsageMask usages) const {
- return Status::ErrorUnsupportedImportKeyFormat();
-}
-
-Status AlgorithmImplementation::ImportKeyRaw(
- const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const {
- return Status::ErrorUnsupportedImportKeyFormat();
-}
-
-Status AlgorithmImplementation::ImportKeyPkcs8(
- const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const {
- return Status::ErrorUnsupportedImportKeyFormat();
-}
-
-Status AlgorithmImplementation::ImportKeySpki(
- const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const {
- return Status::ErrorUnsupportedImportKeyFormat();
-}
-
-Status AlgorithmImplementation::ImportKeyJwk(
- const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const {
- return Status::ErrorUnsupportedImportKeyFormat();
-}
-
-Status AlgorithmImplementation::ExportKeyRaw(
- const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const {
- return Status::ErrorUnsupportedExportKeyFormat();
-}
-
-Status AlgorithmImplementation::ExportKeyPkcs8(
- const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const {
- return Status::ErrorUnsupportedExportKeyFormat();
-}
-
-Status AlgorithmImplementation::ExportKeySpki(
- const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const {
- return Status::ErrorUnsupportedExportKeyFormat();
-}
-
-Status AlgorithmImplementation::ExportKeyJwk(
- const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const {
- return Status::ErrorUnsupportedExportKeyFormat();
-}
-
-} // namespace webcrypto
-
-} // namespace content
diff --git a/chromium/content/child/webcrypto/algorithm_implementation.h b/chromium/content/child/webcrypto/algorithm_implementation.h
deleted file mode 100644
index e926ad0324d..00000000000
--- a/chromium/content/child/webcrypto/algorithm_implementation.h
+++ /dev/null
@@ -1,157 +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_CHILD_WEBCRYPTO_ALGORITHM_IMPLEMENTATION_H_
-#define CONTENT_CHILD_WEBCRYPTO_ALGORITHM_IMPLEMENTATION_H_
-
-#include <stdint.h>
-#include <vector>
-
-#include "base/memory/scoped_ptr.h"
-#include "third_party/WebKit/public/platform/WebCrypto.h"
-
-namespace content {
-
-namespace webcrypto {
-
-class CryptoData;
-class GenerateKeyResult;
-class Status;
-
-// AlgorithmImplementation is a base class for *executing* the operations of an
-// algorithm (generating keys, encrypting, signing, etc.).
-//
-// This is in contrast to blink::WebCryptoAlgorithm which instead *describes*
-// the operation and its parameters.
-//
-// AlgorithmImplementation has reasonable default implementations for all
-// methods which behave as if the operation is it is unsupported, so
-// implementations need only override the applicable methods.
-//
-// Unless stated otherwise methods of AlgorithmImplementation are responsible
-// for sanitizing their inputs. The following can be assumed:
-//
-// * |algorithm.id()| and |key.algorithm.id()| matches the algorithm under
-// which the implementation was registerd.
-// * |algorithm| has the correct parameters type for the operation.
-// * The key usages have already been verified. In fact in the case of calls
-// to Encrypt()/Decrypt() the corresponding key usages may not be present
-// (when wrapping/unwrapping).
-class AlgorithmImplementation {
- public:
- virtual ~AlgorithmImplementation();
-
- // This method corresponds to Web Crypto's crypto.subtle.encrypt().
- virtual Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const;
-
- // This method corresponds to Web Crypto's crypto.subtle.decrypt().
- virtual Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const;
-
- // This method corresponds to Web Crypto's crypto.subtle.sign().
- virtual Status Sign(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const;
-
- // This method corresponds to Web Crypto's crypto.subtle.verify().
- virtual Status Verify(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& signature,
- const CryptoData& data,
- bool* signature_match) const;
-
- // This method corresponds to Web Crypto's crypto.subtle.digest().
- virtual Status Digest(const blink::WebCryptoAlgorithm& algorithm,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const;
-
- // This method corresponds to Web Crypto's crypto.subtle.generateKey().
- //
- // Implementations MUST verify |usages| and return an error if it is not
- // appropriate.
- virtual Status GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- GenerateKeyResult* result) const;
-
- // -----------------------------------------------
- // Key import
- // -----------------------------------------------
-
- // VerifyKeyUsagesBeforeImportKey() must be called before either
- // importing a key, or unwrapping a key.
- //
- // Implementations should return an error if the requested usages are invalid
- // when importing for the specified format.
- //
- // For instance, importing an RSA-SSA key with 'spki' format and Sign usage
- // is invalid. The 'spki' format implies it will be a public key, and public
- // keys do not support signing.
- //
- // When called with format=JWK the key type may be unknown. The
- // ImportKeyJwk() must do the final usage check.
- virtual Status VerifyKeyUsagesBeforeImportKey(
- blink::WebCryptoKeyFormat format,
- blink::WebCryptoKeyUsageMask usages) const;
-
- // This method corresponds to Web Crypto's
- // crypto.subtle.importKey(format='raw').
- virtual Status ImportKeyRaw(const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const;
-
- // This method corresponds to Web Crypto's
- // crypto.subtle.importKey(format='pkcs8').
- virtual Status ImportKeyPkcs8(const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const;
-
- // This method corresponds to Web Crypto's
- // crypto.subtle.importKey(format='spki').
- virtual Status ImportKeySpki(const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const;
-
- // This method corresponds to Web Crypto's
- // crypto.subtle.importKey(format='jwk').
- virtual Status ImportKeyJwk(const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const;
-
- // -----------------------------------------------
- // Key export
- // -----------------------------------------------
-
- virtual Status ExportKeyRaw(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const;
-
- virtual Status ExportKeyPkcs8(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const;
-
- virtual Status ExportKeySpki(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const;
-
- virtual Status ExportKeyJwk(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const;
-};
-
-} // namespace webcrypto
-
-} // namespace content
-
-#endif // CONTENT_CHILD_WEBCRYPTO_ALGORITHM_IMPLEMENTATION_H_
diff --git a/chromium/content/child/webcrypto/algorithm_registry.cc b/chromium/content/child/webcrypto/algorithm_registry.cc
deleted file mode 100644
index 7f674db0bbe..00000000000
--- a/chromium/content/child/webcrypto/algorithm_registry.cc
+++ /dev/null
@@ -1,90 +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/child/webcrypto/algorithm_registry.h"
-
-#include "base/lazy_instance.h"
-#include "content/child/webcrypto/algorithm_implementation.h"
-#include "content/child/webcrypto/platform_crypto.h"
-#include "content/child/webcrypto/status.h"
-
-namespace content {
-
-namespace webcrypto {
-
-namespace {
-
-// This class is used as a singleton. All methods must be threadsafe.
-class AlgorithmRegistry {
- public:
- AlgorithmRegistry()
- : sha_(CreatePlatformShaImplementation()),
- aes_gcm_(CreatePlatformAesGcmImplementation()),
- aes_cbc_(CreatePlatformAesCbcImplementation()),
- aes_ctr_(CreatePlatformAesCtrImplementation()),
- aes_kw_(CreatePlatformAesKwImplementation()),
- hmac_(CreatePlatformHmacImplementation()),
- rsa_ssa_(CreatePlatformRsaSsaImplementation()),
- rsa_oaep_(CreatePlatformRsaOaepImplementation()),
- rsa_pss_(CreatePlatformRsaPssImplementation()) {
- PlatformInit();
- }
-
- const AlgorithmImplementation* GetAlgorithm(
- blink::WebCryptoAlgorithmId id) const {
- switch (id) {
- case blink::WebCryptoAlgorithmIdSha1:
- case blink::WebCryptoAlgorithmIdSha256:
- case blink::WebCryptoAlgorithmIdSha384:
- case blink::WebCryptoAlgorithmIdSha512:
- return sha_.get();
- case blink::WebCryptoAlgorithmIdAesGcm:
- return aes_gcm_.get();
- case blink::WebCryptoAlgorithmIdAesCbc:
- return aes_cbc_.get();
- case blink::WebCryptoAlgorithmIdAesCtr:
- return aes_ctr_.get();
- case blink::WebCryptoAlgorithmIdAesKw:
- return aes_kw_.get();
- case blink::WebCryptoAlgorithmIdHmac:
- return hmac_.get();
- case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5:
- return rsa_ssa_.get();
- case blink::WebCryptoAlgorithmIdRsaOaep:
- return rsa_oaep_.get();
- case blink::WebCryptoAlgorithmIdRsaPss:
- return rsa_pss_.get();
- default:
- return NULL;
- }
- }
-
- private:
- const scoped_ptr<AlgorithmImplementation> sha_;
- const scoped_ptr<AlgorithmImplementation> aes_gcm_;
- const scoped_ptr<AlgorithmImplementation> aes_cbc_;
- const scoped_ptr<AlgorithmImplementation> aes_ctr_;
- const scoped_ptr<AlgorithmImplementation> aes_kw_;
- const scoped_ptr<AlgorithmImplementation> hmac_;
- const scoped_ptr<AlgorithmImplementation> rsa_ssa_;
- const scoped_ptr<AlgorithmImplementation> rsa_oaep_;
- const scoped_ptr<AlgorithmImplementation> rsa_pss_;
-};
-
-} // namespace
-
-base::LazyInstance<AlgorithmRegistry>::Leaky g_algorithm_registry =
- LAZY_INSTANCE_INITIALIZER;
-
-Status GetAlgorithmImplementation(blink::WebCryptoAlgorithmId id,
- const AlgorithmImplementation** impl) {
- *impl = g_algorithm_registry.Get().GetAlgorithm(id);
- if (*impl)
- return Status::Success();
- return Status::ErrorUnsupported();
-}
-
-} // namespace webcrypto
-
-} // namespace content
diff --git a/chromium/content/child/webcrypto/algorithm_registry.h b/chromium/content/child/webcrypto/algorithm_registry.h
deleted file mode 100644
index 6db5f5f56dd..00000000000
--- a/chromium/content/child/webcrypto/algorithm_registry.h
+++ /dev/null
@@ -1,32 +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_CHILD_WEBCRYPTO_ALGORITHM_REGISTRY_H_
-#define CONTENT_CHILD_WEBCRYPTO_ALGORITHM_REGISTRY_H_
-
-#include "third_party/WebKit/public/platform/WebCrypto.h"
-
-namespace content {
-
-namespace webcrypto {
-
-class AlgorithmImplementation;
-class Status;
-
-// Retrieves the AlgorithmImplementation applicable for |id|.
-//
-// If there is no available implementation, then an error is returned, and
-// *impl is set to NULL.
-//
-// Otherwise Success is returned and *impl is set to a non-NULL value. The
-// AlgorithmImplementation pointer will remain valid until the program's
-// termination.
-Status GetAlgorithmImplementation(blink::WebCryptoAlgorithmId id,
- const AlgorithmImplementation** impl);
-
-} // namespace webcrypto
-
-} // namespace content
-
-#endif // CONTENT_CHILD_WEBCRYPTO_ALGORITHM_REGISTRY_H_
diff --git a/chromium/content/child/webcrypto/crypto_data.cc b/chromium/content/child/webcrypto/crypto_data.cc
deleted file mode 100644
index 29736418ae5..00000000000
--- a/chromium/content/child/webcrypto/crypto_data.cc
+++ /dev/null
@@ -1,29 +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/child/webcrypto/crypto_data.h"
-
-namespace content {
-
-namespace webcrypto {
-
-CryptoData::CryptoData() : bytes_(NULL), byte_length_(0) {}
-
-CryptoData::CryptoData(const unsigned char* bytes, unsigned int byte_length)
- : bytes_(bytes), byte_length_(byte_length) {}
-
-CryptoData::CryptoData(const std::vector<unsigned char>& bytes)
- : bytes_(bytes.size() ? &bytes[0] : NULL), byte_length_(bytes.size()) {}
-
-CryptoData::CryptoData(const std::string& bytes)
- : bytes_(bytes.size() ? reinterpret_cast<const unsigned char*>(bytes.data())
- : NULL),
- byte_length_(bytes.size()) {}
-
-CryptoData::CryptoData(const blink::WebVector<unsigned char>& bytes)
- : bytes_(bytes.data()), byte_length_(bytes.size()) {}
-
-} // namespace webcrypto
-
-} // namespace content
diff --git a/chromium/content/child/webcrypto/crypto_data.h b/chromium/content/child/webcrypto/crypto_data.h
deleted file mode 100644
index 2433dd7ea1c..00000000000
--- a/chromium/content/child/webcrypto/crypto_data.h
+++ /dev/null
@@ -1,49 +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_CHILD_WEBCRYPTO_CRYPTO_DATA_H_
-#define CONTENT_CHILD_WEBCRYPTO_CRYPTO_DATA_H_
-
-#include <string>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "content/common/content_export.h"
-#include "third_party/WebKit/public/platform/WebVector.h"
-
-namespace content {
-
-namespace webcrypto {
-
-// Helper to pass around a range of immutable bytes. This is conceptually
-// similar to base::StringPiece, but for crypto byte data.
-//
-// The data used at construction is NOT owned, and should remain valid as long
-// as the CryptoData is being used.
-class CONTENT_EXPORT CryptoData {
- public:
- // Constructs empty data.
- CryptoData();
-
- CryptoData(const unsigned char* bytes, unsigned int byte_length);
-
- // These constructors do NOT copy the data. Hence the base pointer should
- // remain valid for the lifetime of CryptoData.
- explicit CryptoData(const std::vector<unsigned char>& bytes);
- explicit CryptoData(const std::string& bytes);
- explicit CryptoData(const blink::WebVector<unsigned char>& bytes);
-
- const unsigned char* bytes() const { return bytes_; }
- unsigned int byte_length() const { return byte_length_; }
-
- private:
- const unsigned char* const bytes_;
- const unsigned int byte_length_;
-};
-
-} // namespace webcrypto
-
-} // namespace content
-
-#endif // CONTENT_CHILD_WEBCRYPTO_CRYPTO_DATA_H_
diff --git a/chromium/content/child/webcrypto/generate_key_result.cc b/chromium/content/child/webcrypto/generate_key_result.cc
deleted file mode 100644
index 3c61657eb55..00000000000
--- a/chromium/content/child/webcrypto/generate_key_result.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/child/webcrypto/generate_key_result.h"
-
-#include "base/logging.h"
-
-namespace content {
-
-namespace webcrypto {
-
-GenerateKeyResult::GenerateKeyResult() : type_(TYPE_NULL) {
-}
-
-GenerateKeyResult::Type GenerateKeyResult::type() const {
- return type_;
-}
-
-const blink::WebCryptoKey& GenerateKeyResult::secret_key() const {
- DCHECK_EQ(TYPE_SECRET_KEY, type_);
- return secret_key_;
-}
-
-const blink::WebCryptoKey& GenerateKeyResult::public_key() const {
- DCHECK_EQ(TYPE_PUBLIC_PRIVATE_KEY_PAIR, type_);
- return public_key_;
-}
-
-const blink::WebCryptoKey& GenerateKeyResult::private_key() const {
- DCHECK_EQ(TYPE_PUBLIC_PRIVATE_KEY_PAIR, type_);
- return private_key_;
-}
-
-void GenerateKeyResult::AssignSecretKey(const blink::WebCryptoKey& key) {
- type_ = TYPE_SECRET_KEY;
- secret_key_ = key;
-}
-
-void GenerateKeyResult::AssignKeyPair(const blink::WebCryptoKey& public_key,
- const blink::WebCryptoKey& private_key) {
- type_ = TYPE_PUBLIC_PRIVATE_KEY_PAIR;
- public_key_ = public_key;
- private_key_ = private_key;
-}
-
-void GenerateKeyResult::Complete(blink::WebCryptoResult* out) const {
- switch (type_) {
- case TYPE_NULL:
- NOTREACHED();
- break;
- case TYPE_SECRET_KEY:
- out->completeWithKey(secret_key());
- break;
- case TYPE_PUBLIC_PRIVATE_KEY_PAIR:
- out->completeWithKeyPair(public_key(), private_key());
- break;
- }
-}
-
-} // namespace webcrypto
-
-} // namespace content
diff --git a/chromium/content/child/webcrypto/generate_key_result.h b/chromium/content/child/webcrypto/generate_key_result.h
deleted file mode 100644
index fcc13f80855..00000000000
--- a/chromium/content/child/webcrypto/generate_key_result.h
+++ /dev/null
@@ -1,60 +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_CHILD_WEBCRYPTO_GENERATE_KEY_RESULT_H_
-#define CONTENT_CHILD_WEBCRYPTO_GENERATE_KEY_RESULT_H_
-
-#include "content/common/content_export.h"
-#include "third_party/WebKit/public/platform/WebCrypto.h"
-
-namespace content {
-
-namespace webcrypto {
-
-// This is the result object when generating keys. It encapsulates either a
-// secret key, or a public/private key pair.
-class CONTENT_EXPORT GenerateKeyResult {
- public:
- enum Type {
- // An empty (or "null") result.
- TYPE_NULL,
-
- // The result is a secret key, accessible through secret_key()
- TYPE_SECRET_KEY,
-
- // The result is a public/private key pair, accessible through public_key()
- // and private_key()
- TYPE_PUBLIC_PRIVATE_KEY_PAIR
- };
-
- // Initializes a "null" instance.
- GenerateKeyResult();
-
- Type type() const;
-
- const blink::WebCryptoKey& secret_key() const;
- const blink::WebCryptoKey& public_key() const;
- const blink::WebCryptoKey& private_key() const;
-
- void AssignSecretKey(const blink::WebCryptoKey& key);
- void AssignKeyPair(const blink::WebCryptoKey& public_key,
- const blink::WebCryptoKey& private_key);
-
- // Sends the key(s) to the Blink result. Should not be called for "null"
- // results.
- void Complete(blink::WebCryptoResult* out) const;
-
- private:
- Type type_;
-
- blink::WebCryptoKey secret_key_;
- blink::WebCryptoKey public_key_;
- blink::WebCryptoKey private_key_;
-};
-
-} // namespace webcrypto
-
-} // namespace content
-
-#endif // CONTENT_CHILD_WEBCRYPTO_GENERATE_KEY_RESULT_H_
diff --git a/chromium/content/child/webcrypto/jwk.cc b/chromium/content/child/webcrypto/jwk.cc
deleted file mode 100644
index b0073cc1b8f..00000000000
--- a/chromium/content/child/webcrypto/jwk.cc
+++ /dev/null
@@ -1,711 +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/child/webcrypto/jwk.h"
-
-#include "base/base64.h"
-#include "base/json/json_reader.h"
-#include "base/json/json_writer.h"
-#include "base/stl_util.h"
-#include "base/strings/string_piece.h"
-#include "content/child/webcrypto/crypto_data.h"
-#include "content/child/webcrypto/status.h"
-#include "content/child/webcrypto/webcrypto_util.h"
-
-// TODO(eroman): The algorithm-specific logic in this file for AES and RSA
-// should be moved into the corresponding AlgorithmImplementation file. It
-// exists in this file to avoid duplication between OpenSSL and NSS
-// implementations.
-
-// JSON Web Key Format (JWK)
-// http://tools.ietf.org/html/draft-ietf-jose-json-web-key-21
-//
-// A JWK is a simple JSON dictionary with the following entries
-// - "kty" (Key Type) Parameter, REQUIRED
-// - <kty-specific parameters, see below>, REQUIRED
-// - "use" (Key Use) Parameter, OPTIONAL
-// - "key_ops" (Key Operations) Parameter, OPTIONAL
-// - "alg" (Algorithm) Parameter, OPTIONAL
-// - "ext" (Key Exportability), OPTIONAL
-// (all other entries are ignored)
-//
-// OPTIONAL here means that this code does not require the entry to be present
-// in the incoming JWK, because the method input parameters contain similar
-// information. If the optional JWK entry is present, it will be validated
-// against the corresponding input parameter for consistency and combined with
-// it according to rules defined below.
-//
-// Input 'key_data' contains the JWK. To build a Web Crypto Key, the JWK
-// values are parsed out and combined with the method input parameters to
-// build a Web Crypto Key:
-// Web Crypto Key type <-- (deduced)
-// Web Crypto Key extractable <-- JWK ext + input extractable
-// Web Crypto Key algorithm <-- JWK alg + input algorithm
-// Web Crypto Key keyUsage <-- JWK use, key_ops + input usages
-// Web Crypto Key keying material <-- kty-specific parameters
-//
-// Values for each JWK entry are case-sensitive and defined in
-// http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18.
-// Note that not all values specified by JOSE are handled by this code. Only
-// handled values are listed.
-// - kty (Key Type)
-// +-------+--------------------------------------------------------------+
-// | "RSA" | RSA [RFC3447] |
-// | "oct" | Octet sequence (used to represent symmetric keys) |
-// +-------+--------------------------------------------------------------+
-//
-// - key_ops (Key Use Details)
-// The key_ops field is an array that contains one or more strings from
-// the table below, and describes the operations for which this key may be
-// used.
-// +-------+--------------------------------------------------------------+
-// | "encrypt" | encrypt operations |
-// | "decrypt" | decrypt operations |
-// | "sign" | sign (MAC) operations |
-// | "verify" | verify (MAC) operations |
-// | "wrapKey" | key wrap |
-// | "unwrapKey" | key unwrap |
-// | "deriveKey" | key derivation |
-// | "deriveBits" | key derivation |
-// +-------+--------------------------------------------------------------+
-//
-// - use (Key Use)
-// The use field contains a single entry from the table below.
-// +-------+--------------------------------------------------------------+
-// | "sig" | equivalent to key_ops of [sign, verify] |
-// | "enc" | equivalent to key_ops of [encrypt, decrypt, wrapKey, |
-// | | unwrapKey, deriveKey, deriveBits] |
-// +-------+--------------------------------------------------------------+
-//
-// NOTE: If both "use" and "key_ops" JWK members are present, the usages
-// specified by them MUST be consistent. In particular, the "use" value
-// "sig" corresponds to "sign" and/or "verify". The "use" value "enc"
-// corresponds to all other values defined above. If "key_ops" values
-// corresponding to both "sig" and "enc" "use" values are present, the "use"
-// member SHOULD NOT be present, and if present, its value MUST NOT be
-// either "sig" or "enc".
-//
-// - ext (Key Exportability)
-// +-------+--------------------------------------------------------------+
-// | true | Key may be exported from the trusted environment |
-// | false | Key cannot exit the trusted environment |
-// +-------+--------------------------------------------------------------+
-//
-// - alg (Algorithm)
-// See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18
-// +--------------+-------------------------------------------------------+
-// | Digital Signature or MAC Algorithm |
-// +--------------+-------------------------------------------------------+
-// | "HS1" | HMAC using SHA-1 hash algorithm |
-// | "HS256" | HMAC using SHA-256 hash algorithm |
-// | "HS384" | HMAC using SHA-384 hash algorithm |
-// | "HS512" | HMAC using SHA-512 hash algorithm |
-// | "RS1" | RSASSA using SHA-1 hash algorithm
-// | "RS256" | RSASSA using SHA-256 hash algorithm |
-// | "RS384" | RSASSA using SHA-384 hash algorithm |
-// | "RS512" | RSASSA using SHA-512 hash algorithm |
-// +--------------+-------------------------------------------------------|
-// | Key Management Algorithm |
-// +--------------+-------------------------------------------------------+
-// | "RSA-OAEP" | RSAES using Optimal Asymmetric Encryption Padding |
-// | | (OAEP) [RFC3447], with the default parameters |
-// | | specified by RFC3447 in Section A.2.1 |
-// | "A128KW" | Advanced Encryption Standard (AES) Key Wrap Algorithm |
-// | | [RFC3394] using 128 bit keys |
-// | "A192KW" | AES Key Wrap Algorithm using 192 bit keys |
-// | "A256KW" | AES Key Wrap Algorithm using 256 bit keys |
-// | "A128GCM" | AES in Galois/Counter Mode (GCM) [NIST.800-38D] using |
-// | | 128 bit keys |
-// | "A192GCM" | AES GCM using 192 bit keys |
-// | "A256GCM" | AES GCM using 256 bit keys |
-// | "A128CBC" | AES in Cipher Block Chaining Mode (CBC) with PKCS #5 |
-// | | padding [NIST.800-38A] |
-// | "A192CBC" | AES CBC using 192 bit keys |
-// | "A256CBC" | AES CBC using 256 bit keys |
-// +--------------+-------------------------------------------------------+
-//
-// kty-specific parameters
-// The value of kty determines the type and content of the keying material
-// carried in the JWK to be imported.
-// // - kty == "oct" (symmetric or other raw key)
-// +-------+--------------------------------------------------------------+
-// | "k" | Contains the value of the symmetric (or other single-valued) |
-// | | key. It is represented as the base64url encoding of the |
-// | | octet sequence containing the key value. |
-// +-------+--------------------------------------------------------------+
-// - kty == "RSA" (RSA public key)
-// +-------+--------------------------------------------------------------+
-// | "n" | Contains the modulus value for the RSA public key. It is |
-// | | represented as the base64url encoding of the value's |
-// | | unsigned big endian representation as an octet sequence. |
-// +-------+--------------------------------------------------------------+
-// | "e" | Contains the exponent value for the RSA public key. It is |
-// | | represented as the base64url encoding of the value's |
-// | | unsigned big endian representation as an octet sequence. |
-// +-------+--------------------------------------------------------------+
-// - If key == "RSA" and the "d" parameter is present then it is a private key.
-// All the parameters above for public keys apply, as well as the following.
-// (Note that except for "d", all of these are optional):
-// +-------+--------------------------------------------------------------+
-// | "d" | Contains the private exponent value for the RSA private key. |
-// | | It is represented as the base64url encoding of the value's |
-// | | unsigned big endian representation as an octet sequence. |
-// +-------+--------------------------------------------------------------+
-// | "p" | Contains the first prime factor value for the RSA private |
-// | | key. It is represented as the base64url encoding of the |
-// | | value's |
-// | | unsigned big endian representation as an octet sequence. |
-// +-------+--------------------------------------------------------------+
-// | "q" | Contains the second prime factor value for the RSA private |
-// | | key. It is represented as the base64url encoding of the |
-// | | value's unsigned big endian representation as an octet |
-// | | sequence. |
-// +-------+--------------------------------------------------------------+
-// | "dp" | Contains the first factor CRT exponent value for the RSA |
-// | | private key. It is represented as the base64url encoding of |
-// | | the value's unsigned big endian representation as an octet |
-// | | sequence. |
-// +-------+--------------------------------------------------------------+
-// | "dq" | Contains the second factor CRT exponent value for the RSA |
-// | | private key. It is represented as the base64url encoding of |
-// | | the value's unsigned big endian representation as an octet |
-// | | sequence. |
-// +-------+--------------------------------------------------------------+
-// | "dq" | Contains the first CRT coefficient value for the RSA private |
-// | | key. It is represented as the base64url encoding of the |
-// | | value's unsigned big endian representation as an octet |
-// | | sequence. |
-// +-------+--------------------------------------------------------------+
-//
-// Consistency and conflict resolution
-// The 'algorithm', 'extractable', and 'usages' input parameters
-// may be different than the corresponding values inside the JWK. The Web
-// Crypto spec says that if a JWK value is present but is inconsistent with
-// the input value, it is an error and the operation must fail. If no
-// inconsistency is found then the input parameters are used.
-//
-// algorithm
-// If the JWK algorithm is provided, it must match the web crypto input
-// algorithm (both the algorithm ID and inner hash if applicable).
-//
-// extractable
-// If the JWK ext field is true but the input parameter is false, make the
-// Web Crypto Key non-extractable. Conversely, if the JWK ext field is
-// false but the input parameter is true, it is an inconsistency. If both
-// are true or both are false, use that value.
-//
-// usages
-// The input usages must be a strict subset of the interpreted JWK use
-// value, else it is judged inconsistent. In all cases the input usages
-// is used as the final usages.
-//
-
-namespace content {
-
-namespace webcrypto {
-
-namespace {
-
-// Web Crypto equivalent usage mask for JWK 'use' = 'enc'.
-const blink::WebCryptoKeyUsageMask kJwkEncUsage =
- blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt |
- blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey |
- blink::WebCryptoKeyUsageDeriveKey | blink::WebCryptoKeyUsageDeriveBits;
-// Web Crypto equivalent usage mask for JWK 'use' = 'sig'.
-const blink::WebCryptoKeyUsageMask kJwkSigUsage =
- blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify;
-
-// Checks that the "ext" member of the JWK is consistent with
-// "expected_extractable".
-Status VerifyExt(const JwkReader& jwk, bool expected_extractable) {
- // JWK "ext" (optional) --> extractable parameter
- bool jwk_ext_value = false;
- bool has_jwk_ext;
- Status status = jwk.GetOptionalBool("ext", &jwk_ext_value, &has_jwk_ext);
- if (status.IsError())
- return status;
- if (has_jwk_ext && expected_extractable && !jwk_ext_value)
- return Status::ErrorJwkExtInconsistent();
- return Status::Success();
-}
-
-// Checks that the usages ("use" and "key_ops") of the JWK is consistent with
-// "expected_usages".
-Status VerifyUsages(const JwkReader& jwk,
- blink::WebCryptoKeyUsageMask expected_usages) {
- // JWK "key_ops" (optional) --> usages parameter
- base::ListValue* jwk_key_ops_value = NULL;
- bool has_jwk_key_ops;
- Status status =
- jwk.GetOptionalList("key_ops", &jwk_key_ops_value, &has_jwk_key_ops);
- if (status.IsError())
- return status;
- blink::WebCryptoKeyUsageMask jwk_key_ops_mask = 0;
- if (has_jwk_key_ops) {
- status =
- GetWebCryptoUsagesFromJwkKeyOps(jwk_key_ops_value, &jwk_key_ops_mask);
- if (status.IsError())
- return status;
- // The input usages must be a subset of jwk_key_ops_mask.
- if (!ContainsKeyUsages(jwk_key_ops_mask, expected_usages))
- return Status::ErrorJwkKeyopsInconsistent();
- }
-
- // JWK "use" (optional) --> usages parameter
- std::string jwk_use_value;
- bool has_jwk_use;
- status = jwk.GetOptionalString("use", &jwk_use_value, &has_jwk_use);
- if (status.IsError())
- return status;
- blink::WebCryptoKeyUsageMask jwk_use_mask = 0;
- if (has_jwk_use) {
- if (jwk_use_value == "enc")
- jwk_use_mask = kJwkEncUsage;
- else if (jwk_use_value == "sig")
- jwk_use_mask = kJwkSigUsage;
- else
- return Status::ErrorJwkUnrecognizedUse();
- // The input usages must be a subset of jwk_use_mask.
- if (!ContainsKeyUsages(jwk_use_mask, expected_usages))
- return Status::ErrorJwkUseInconsistent();
- }
-
- // If both 'key_ops' and 'use' are present, ensure they are consistent.
- if (has_jwk_key_ops && has_jwk_use &&
- !ContainsKeyUsages(jwk_use_mask, jwk_key_ops_mask))
- return Status::ErrorJwkUseAndKeyopsInconsistent();
-
- return Status::Success();
-}
-
-} // namespace
-
-JwkReader::JwkReader() {
-}
-
-JwkReader::~JwkReader() {
-}
-
-Status JwkReader::Init(const CryptoData& bytes,
- bool expected_extractable,
- blink::WebCryptoKeyUsageMask expected_usages,
- const std::string& expected_kty,
- const std::string& expected_alg) {
- if (!bytes.byte_length())
- return Status::ErrorImportEmptyKeyData();
-
- // Parse the incoming JWK JSON.
- base::StringPiece json_string(reinterpret_cast<const char*>(bytes.bytes()),
- bytes.byte_length());
-
- scoped_ptr<base::Value> value(base::JSONReader::Read(json_string));
- base::DictionaryValue* dict_value = NULL;
-
- if (!value.get() || !value->GetAsDictionary(&dict_value) || !dict_value)
- return Status::ErrorJwkNotDictionary();
-
- // Release |value|, as ownership will be transferred to |dict| via
- // |dict_value|, which points to the same object as |value|.
- ignore_result(value.release());
- dict_.reset(dict_value);
-
- // JWK "kty". Exit early if this required JWK parameter is missing.
- std::string kty;
- Status status = GetString("kty", &kty);
- if (status.IsError())
- return status;
-
- if (kty != expected_kty)
- return Status::ErrorJwkUnexpectedKty(expected_kty);
-
- status = VerifyExt(*this, expected_extractable);
- if (status.IsError())
- return status;
-
- status = VerifyUsages(*this, expected_usages);
- if (status.IsError())
- return status;
-
- // Verify the algorithm if an expectation was provided.
- if (!expected_alg.empty()) {
- status = VerifyAlg(expected_alg);
- if (status.IsError())
- return status;
- }
-
- return Status::Success();
-}
-
-bool JwkReader::HasMember(const std::string& member_name) const {
- return dict_->HasKey(member_name);
-}
-
-Status JwkReader::GetString(const std::string& member_name,
- std::string* result) const {
- base::Value* value = NULL;
- if (!dict_->Get(member_name, &value))
- return Status::ErrorJwkPropertyMissing(member_name);
- if (!value->GetAsString(result))
- return Status::ErrorJwkPropertyWrongType(member_name, "string");
- return Status::Success();
-}
-
-Status JwkReader::GetOptionalString(const std::string& member_name,
- std::string* result,
- bool* member_exists) const {
- *member_exists = false;
- base::Value* value = NULL;
- if (!dict_->Get(member_name, &value))
- return Status::Success();
-
- if (!value->GetAsString(result))
- return Status::ErrorJwkPropertyWrongType(member_name, "string");
-
- *member_exists = true;
- return Status::Success();
-}
-
-Status JwkReader::GetOptionalList(const std::string& member_name,
- base::ListValue** result,
- bool* member_exists) const {
- *member_exists = false;
- base::Value* value = NULL;
- if (!dict_->Get(member_name, &value))
- return Status::Success();
-
- if (!value->GetAsList(result))
- return Status::ErrorJwkPropertyWrongType(member_name, "list");
-
- *member_exists = true;
- return Status::Success();
-}
-
-Status JwkReader::GetBytes(const std::string& member_name,
- std::string* result) const {
- std::string base64_string;
- Status status = GetString(member_name, &base64_string);
- if (status.IsError())
- return status;
-
- if (!Base64DecodeUrlSafe(base64_string, result))
- return Status::ErrorJwkBase64Decode(member_name);
-
- return Status::Success();
-}
-
-Status JwkReader::GetBigInteger(const std::string& member_name,
- std::string* result) const {
- Status status = GetBytes(member_name, result);
- if (status.IsError())
- return status;
-
- if (result->empty())
- return Status::ErrorJwkEmptyBigInteger(member_name);
-
- // The JWA spec says that "The octet sequence MUST utilize the minimum number
- // of octets to represent the value." This means there shouldn't be any
- // leading zeros.
- if (result->size() > 1 && (*result)[0] == 0)
- return Status::ErrorJwkBigIntegerHasLeadingZero(member_name);
-
- return Status::Success();
-}
-
-Status JwkReader::GetOptionalBool(const std::string& member_name,
- bool* result,
- bool* member_exists) const {
- *member_exists = false;
- base::Value* value = NULL;
- if (!dict_->Get(member_name, &value))
- return Status::Success();
-
- if (!value->GetAsBoolean(result))
- return Status::ErrorJwkPropertyWrongType(member_name, "boolean");
-
- *member_exists = true;
- return Status::Success();
-}
-
-Status JwkReader::GetAlg(std::string* alg, bool* has_alg) const {
- return GetOptionalString("alg", alg, has_alg);
-}
-
-Status JwkReader::VerifyAlg(const std::string& expected_alg) const {
- bool has_jwk_alg;
- std::string jwk_alg_value;
- Status status = GetAlg(&jwk_alg_value, &has_jwk_alg);
- if (status.IsError())
- return status;
-
- if (has_jwk_alg && jwk_alg_value != expected_alg)
- return Status::ErrorJwkAlgorithmInconsistent();
-
- return Status::Success();
-}
-
-JwkWriter::JwkWriter(const std::string& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- const std::string& kty) {
- dict_.SetString("alg", algorithm);
- dict_.Set("key_ops", CreateJwkKeyOpsFromWebCryptoUsages(usages));
- dict_.SetBoolean("ext", extractable);
- dict_.SetString("kty", kty);
-}
-
-void JwkWriter::SetString(const std::string& member_name,
- const std::string& value) {
- dict_.SetString(member_name, value);
-}
-
-void JwkWriter::SetBytes(const std::string& member_name,
- const CryptoData& value) {
- dict_.SetString(
- member_name,
- Base64EncodeUrlSafe(base::StringPiece(
- reinterpret_cast<const char*>(value.bytes()), value.byte_length())));
-}
-
-void JwkWriter::ToJson(std::vector<uint8_t>* utf8_bytes) const {
- std::string json;
- base::JSONWriter::Write(&dict_, &json);
- utf8_bytes->assign(json.begin(), json.end());
-}
-
-Status ReadSecretKeyNoExpectedAlg(const CryptoData& key_data,
- bool expected_extractable,
- blink::WebCryptoKeyUsageMask expected_usages,
- std::vector<uint8_t>* raw_key_data,
- JwkReader* jwk) {
- Status status = jwk->Init(
- key_data, expected_extractable, expected_usages, "oct", std::string());
- if (status.IsError())
- return status;
-
- std::string jwk_k_value;
- status = jwk->GetBytes("k", &jwk_k_value);
- if (status.IsError())
- return status;
- raw_key_data->assign(jwk_k_value.begin(), jwk_k_value.end());
-
- return Status::Success();
-}
-
-void WriteSecretKeyJwk(const CryptoData& raw_key_data,
- const std::string& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- std::vector<uint8_t>* jwk_key_data) {
- JwkWriter writer(algorithm, extractable, usages, "oct");
- writer.SetBytes("k", raw_key_data);
- writer.ToJson(jwk_key_data);
-}
-
-Status ReadSecretKeyJwk(const CryptoData& key_data,
- const std::string& expected_alg,
- bool expected_extractable,
- blink::WebCryptoKeyUsageMask expected_usages,
- std::vector<uint8_t>* raw_key_data) {
- JwkReader jwk;
- Status status = ReadSecretKeyNoExpectedAlg(
- key_data, expected_extractable, expected_usages, raw_key_data, &jwk);
- if (status.IsError())
- return status;
- return jwk.VerifyAlg(expected_alg);
-}
-
-std::string MakeJwkAesAlgorithmName(const std::string& suffix,
- unsigned int keylen_bytes) {
- if (keylen_bytes == 16)
- return std::string("A128") + suffix;
- if (keylen_bytes == 24)
- return std::string("A192") + suffix;
- if (keylen_bytes == 32)
- return std::string("A256") + suffix;
- return std::string();
-}
-
-Status ReadAesSecretKeyJwk(const CryptoData& key_data,
- const std::string& algorithm_name_suffix,
- bool expected_extractable,
- blink::WebCryptoKeyUsageMask expected_usages,
- std::vector<uint8_t>* raw_key_data) {
- JwkReader jwk;
- Status status = ReadSecretKeyNoExpectedAlg(
- key_data, expected_extractable, expected_usages, raw_key_data, &jwk);
- if (status.IsError())
- return status;
-
- bool has_jwk_alg;
- std::string jwk_alg;
- status = jwk.GetAlg(&jwk_alg, &has_jwk_alg);
- if (status.IsError())
- return status;
-
- if (has_jwk_alg) {
- std::string expected_algorithm_name =
- MakeJwkAesAlgorithmName(algorithm_name_suffix, raw_key_data->size());
-
- if (jwk_alg != expected_algorithm_name) {
- // Give a different error message if the key length was wrong.
- if (jwk_alg == MakeJwkAesAlgorithmName(algorithm_name_suffix, 16) ||
- jwk_alg == MakeJwkAesAlgorithmName(algorithm_name_suffix, 24) ||
- jwk_alg == MakeJwkAesAlgorithmName(algorithm_name_suffix, 32)) {
- return Status::ErrorJwkIncorrectKeyLength();
- }
- return Status::ErrorJwkAlgorithmInconsistent();
- }
- }
-
- return Status::Success();
-}
-
-// Writes an RSA public key to a JWK dictionary
-void WriteRsaPublicKeyJwk(const CryptoData& n,
- const CryptoData& e,
- const std::string& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- std::vector<uint8_t>* jwk_key_data) {
- JwkWriter writer(algorithm, extractable, usages, "RSA");
- writer.SetBytes("n", n);
- writer.SetBytes("e", e);
- writer.ToJson(jwk_key_data);
-}
-
-// Writes an RSA private key to a JWK dictionary
-void WriteRsaPrivateKeyJwk(const CryptoData& n,
- const CryptoData& e,
- const CryptoData& d,
- const CryptoData& p,
- const CryptoData& q,
- const CryptoData& dp,
- const CryptoData& dq,
- const CryptoData& qi,
- const std::string& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- std::vector<uint8_t>* jwk_key_data) {
- JwkWriter writer(algorithm, extractable, usages, "RSA");
-
- writer.SetBytes("n", n);
- writer.SetBytes("e", e);
- writer.SetBytes("d", d);
- // Although these are "optional" in the JWA, WebCrypto spec requires them to
- // be emitted.
- writer.SetBytes("p", p);
- writer.SetBytes("q", q);
- writer.SetBytes("dp", dp);
- writer.SetBytes("dq", dq);
- writer.SetBytes("qi", qi);
- writer.ToJson(jwk_key_data);
-}
-
-JwkRsaInfo::JwkRsaInfo() : is_private_key(false) {
-}
-
-JwkRsaInfo::~JwkRsaInfo() {
-}
-
-Status ReadRsaKeyJwk(const CryptoData& key_data,
- const std::string& expected_alg,
- bool expected_extractable,
- blink::WebCryptoKeyUsageMask expected_usages,
- JwkRsaInfo* result) {
- JwkReader jwk;
- Status status = jwk.Init(
- key_data, expected_extractable, expected_usages, "RSA", expected_alg);
- if (status.IsError())
- return status;
-
- // An RSA public key must have an "n" (modulus) and an "e" (exponent) entry
- // in the JWK, while an RSA private key must have those, plus at least a "d"
- // (private exponent) entry.
- // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18,
- // section 6.3.
- status = jwk.GetBigInteger("n", &result->n);
- if (status.IsError())
- return status;
- status = jwk.GetBigInteger("e", &result->e);
- if (status.IsError())
- return status;
-
- result->is_private_key = jwk.HasMember("d");
- if (!result->is_private_key)
- return Status::Success();
-
- status = jwk.GetBigInteger("d", &result->d);
- if (status.IsError())
- return status;
-
- // The "p", "q", "dp", "dq", and "qi" properties are optional in the JWA
- // spec. However they are required by Chromium's WebCrypto implementation.
-
- status = jwk.GetBigInteger("p", &result->p);
- if (status.IsError())
- return status;
-
- status = jwk.GetBigInteger("q", &result->q);
- if (status.IsError())
- return status;
-
- status = jwk.GetBigInteger("dp", &result->dp);
- if (status.IsError())
- return status;
-
- status = jwk.GetBigInteger("dq", &result->dq);
- if (status.IsError())
- return status;
-
- status = jwk.GetBigInteger("qi", &result->qi);
- if (status.IsError())
- return status;
-
- return Status::Success();
-}
-
-const char* GetJwkHmacAlgorithmName(blink::WebCryptoAlgorithmId hash) {
- switch (hash) {
- case blink::WebCryptoAlgorithmIdSha1:
- return "HS1";
- case blink::WebCryptoAlgorithmIdSha256:
- return "HS256";
- case blink::WebCryptoAlgorithmIdSha384:
- return "HS384";
- case blink::WebCryptoAlgorithmIdSha512:
- return "HS512";
- default:
- return NULL;
- }
-}
-
-// TODO(eroman): This accepts invalid inputs. http://crbug.com/378034
-bool Base64DecodeUrlSafe(const std::string& input, std::string* output) {
- std::string base64_encoded_text(input);
- std::replace(
- base64_encoded_text.begin(), base64_encoded_text.end(), '-', '+');
- std::replace(
- base64_encoded_text.begin(), base64_encoded_text.end(), '_', '/');
- base64_encoded_text.append((4 - base64_encoded_text.size() % 4) % 4, '=');
- return base::Base64Decode(base64_encoded_text, output);
-}
-
-std::string Base64EncodeUrlSafe(const base::StringPiece& input) {
- std::string output;
- base::Base64Encode(input, &output);
- std::replace(output.begin(), output.end(), '+', '-');
- std::replace(output.begin(), output.end(), '/', '_');
- output.erase(std::remove(output.begin(), output.end(), '='), output.end());
- return output;
-}
-
-std::string Base64EncodeUrlSafe(const std::vector<uint8_t>& input) {
- const base::StringPiece string_piece(
- reinterpret_cast<const char*>(vector_as_array(&input)), input.size());
- return Base64EncodeUrlSafe(string_piece);
-}
-
-} // namespace webcrypto
-
-} // namespace content
diff --git a/chromium/content/child/webcrypto/jwk.h b/chromium/content/child/webcrypto/jwk.h
deleted file mode 100644
index cb6866df178..00000000000
--- a/chromium/content/child/webcrypto/jwk.h
+++ /dev/null
@@ -1,245 +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_CHILD_WEBCRYPTO_JWK_H_
-#define CONTENT_CHILD_WEBCRYPTO_JWK_H_
-
-#include <stdint.h>
-#include <vector>
-
-#include "base/strings/string_piece.h"
-#include "base/values.h"
-#include "content/common/content_export.h"
-#include "third_party/WebKit/public/platform/WebCrypto.h"
-
-namespace content {
-
-namespace webcrypto {
-
-class CryptoData;
-class Status;
-
-// Helper class for parsing a JWK from JSON.
-//
-// This primarily exists to ensure strict enforcement of the JWK schema, as the
-// type and presence of particular members is security relevant. For example,
-// GetString() will ensure a given JSON member is present and is a string type,
-// and will fail if these conditions aren't met.
-//
-// Users of JwkReader must call Init() successfully before any other method can
-// be called.
-class JwkReader {
- public:
- JwkReader();
- ~JwkReader();
-
- // Initializes a JWK reader by parsing the JSON |bytes|. To succeed, the JWK
- // must:
- // * Have "kty" matching |expected_kty|
- // * Have "ext" compatible with |expected_extractable|
- // * Have usages ("use", "key_ops") compatible with |expected_usages|
- // * Have an "alg" matching |expected_alg|
- //
- // NOTE: If |expected_alg| is empty, then the test on "alg" is skipped.
- Status Init(const CryptoData& bytes,
- bool expected_extractable,
- blink::WebCryptoKeyUsageMask expected_usages,
- const std::string& expected_kty,
- const std::string& expected_alg);
-
- // Returns true if the member |member_name| is present.
- bool HasMember(const std::string& member_name) const;
-
- // Extracts the required string member |member_name| and saves the result to
- // |*result|. If the member does not exist or is not a string, returns an
- // error.
- Status GetString(const std::string& member_name, std::string* result) const;
-
- // Extracts the optional string member |member_name| and saves the result to
- // |*result| if it was found. If the member exists and is not a string,
- // returns an error. Otherwise returns success, and sets |*member_exists| if
- // it was found.
- Status GetOptionalString(const std::string& member_name,
- std::string* result,
- bool* member_exists) const;
-
- // Extracts the optional array member |member_name| and saves the result to
- // |*result| if it was found. If the member exists and is not an array,
- // returns an error. Otherwise returns success, and sets |*member_exists| if
- // it was found.
- //
- // NOTE: |*result| is owned by the JwkReader.
- Status GetOptionalList(const std::string& member_name,
- base::ListValue** result,
- bool* member_exists) const;
-
- // Extracts the required string member |member_name| and saves the
- // base64url-decoded bytes to |*result|. If the member does not exist or is
- // not a string, or could not be base64url-decoded, returns an error.
- Status GetBytes(const std::string& member_name, std::string* result) const;
-
- // Extracts the required base64url member, which is interpreted as being a
- // big-endian unsigned integer.
- //
- // Sequences that contain leading zeros will be rejected.
- Status GetBigInteger(const std::string& member_name,
- std::string* result) const;
-
- // Extracts the optional boolean member |member_name| and saves the result to
- // |*result| if it was found. If the member exists and is not a boolean,
- // returns an error. Otherwise returns success, and sets |*member_exists| if
- // it was found.
- Status GetOptionalBool(const std::string& member_name,
- bool* result,
- bool* member_exists) const;
-
- // Gets the optional algorithm ("alg") string.
- Status GetAlg(std::string* alg, bool* has_alg) const;
-
- // Checks if the "alg" member matches |expected_alg|.
- Status VerifyAlg(const std::string& expected_alg) const;
-
- private:
- scoped_ptr<base::DictionaryValue> dict_;
-};
-
-// Helper class for building the JSON for a JWK.
-class JwkWriter {
- public:
- // Initializes a writer, and sets the standard JWK members as indicated.
- JwkWriter(const std::string& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- const std::string& kty);
-
- // Sets a string member |member_name| to |value|.
- void SetString(const std::string& member_name, const std::string& value);
-
- // Sets a bytes member |value| to |value| by base64 url-safe encoding it.
- void SetBytes(const std::string& member_name, const CryptoData& value);
-
- // Flattens the JWK to JSON (UTF-8 encoded if necessary, however in practice
- // it will be ASCII).
- void ToJson(std::vector<uint8_t>* utf8_bytes) const;
-
- private:
- base::DictionaryValue dict_;
-};
-
-// Writes a JWK-formatted symmetric key to |jwk_key_data|.
-// * raw_key_data: The actual key data
-// * algorithm: The JWK algorithm name (i.e. "alg")
-// * extractable: The JWK extractability (i.e. "ext")
-// * usages: The JWK usages (i.e. "key_ops")
-void WriteSecretKeyJwk(const CryptoData& raw_key_data,
- const std::string& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- std::vector<uint8_t>* jwk_key_data);
-
-// Parses a UTF-8 encoded JWK (key_data), and extracts the key material to
-// |*raw_key_data|. Returns Status::Success() on success, otherwise an error.
-// In order for this to succeed:
-// * expected_alg must match the JWK's "alg", if present.
-// * expected_extractable must be consistent with the JWK's "ext", if
-// present.
-// * expected_usages must be a subset of the JWK's "key_ops" if present.
-Status ReadSecretKeyJwk(const CryptoData& key_data,
- const std::string& expected_alg,
- bool expected_extractable,
- blink::WebCryptoKeyUsageMask expected_usages,
- std::vector<uint8_t>* raw_key_data);
-
-// Creates an AES algorithm name for the given key size (in bytes). For
-// instance "A128CBC" is the result of suffix="CBC", keylen_bytes=16.
-std::string MakeJwkAesAlgorithmName(const std::string& suffix,
- unsigned int keylen_bytes);
-
-// This is very similar to ReadSecretKeyJwk(), except instead of specifying an
-// absolute "expected_alg", the suffix for an AES algorithm name is given
-// (See MakeJwkAesAlgorithmName() for an explanation of what the suffix is).
-//
-// This is because the algorithm name for AES keys is dependent on the length
-// of the key. This function expects key lengths to be either 128, 192, or 256
-// bits.
-Status ReadAesSecretKeyJwk(const CryptoData& key_data,
- const std::string& algorithm_name_suffix,
- bool expected_extractable,
- blink::WebCryptoKeyUsageMask expected_usages,
- std::vector<uint8_t>* raw_key_data);
-
-// Writes a JWK-formated RSA public key and saves the result to
-// |*jwk_key_data|.
-void WriteRsaPublicKeyJwk(const CryptoData& n,
- const CryptoData& e,
- const std::string& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- std::vector<uint8_t>* jwk_key_data);
-
-// Writes a JWK-formated RSA private key and saves the result to
-// |*jwk_key_data|.
-void WriteRsaPrivateKeyJwk(const CryptoData& n,
- const CryptoData& e,
- const CryptoData& d,
- const CryptoData& p,
- const CryptoData& q,
- const CryptoData& dp,
- const CryptoData& dq,
- const CryptoData& qi,
- const std::string& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- std::vector<uint8_t>* jwk_key_data);
-
-// Describes the RSA components for a parsed key. The names of the properties
-// correspond with those from the JWK spec. Note that Chromium's WebCrypto
-// implementation does not support multi-primes, so there is no parsed field
-// for othinfo.
-struct JwkRsaInfo {
- JwkRsaInfo();
- ~JwkRsaInfo();
-
- bool is_private_key;
- std::string n;
- std::string e;
- std::string d;
- std::string p;
- std::string q;
- std::string dp;
- std::string dq;
- std::string qi;
-};
-
-// Parses a UTF-8 encoded JWK (key_data), and extracts the RSA components to
-// |*result|. Returns Status::Success() on success, otherwise an error.
-// In order for this to succeed:
-// * expected_alg must match the JWK's "alg", if present.
-// * expected_extractable must be consistent with the JWK's "ext", if
-// present.
-// * expected_usages must be a subset of the JWK's "key_ops" if present.
-Status ReadRsaKeyJwk(const CryptoData& key_data,
- const std::string& expected_alg,
- bool expected_extractable,
- blink::WebCryptoKeyUsageMask expected_usages,
- JwkRsaInfo* result);
-
-const char* GetJwkHmacAlgorithmName(blink::WebCryptoAlgorithmId hash);
-
-// This function decodes unpadded 'base64url' encoded data, as described in
-// RFC4648 (http://www.ietf.org/rfc/rfc4648.txt) Section 5.
-CONTENT_EXPORT bool Base64DecodeUrlSafe(const std::string& input,
- std::string* output);
-
-// Returns an unpadded 'base64url' encoding of the input data, the opposite of
-// Base64DecodeUrlSafe() above.
-CONTENT_EXPORT std::string Base64EncodeUrlSafe(const base::StringPiece& input);
-CONTENT_EXPORT std::string Base64EncodeUrlSafe(
- const std::vector<uint8_t>& input);
-
-} // namespace webcrypto
-
-} // namespace content
-
-#endif // CONTENT_CHILD_WEBCRYPTO_JWK_H_
diff --git a/chromium/content/child/webcrypto/nss/aes_cbc_nss.cc b/chromium/content/child/webcrypto/nss/aes_cbc_nss.cc
deleted file mode 100644
index abe371802b2..00000000000
--- a/chromium/content/child/webcrypto/nss/aes_cbc_nss.cc
+++ /dev/null
@@ -1,128 +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 <cryptohi.h>
-
-#include "base/numerics/safe_math.h"
-#include "base/stl_util.h"
-#include "content/child/webcrypto/crypto_data.h"
-#include "content/child/webcrypto/nss/aes_key_nss.h"
-#include "content/child/webcrypto/nss/key_nss.h"
-#include "content/child/webcrypto/nss/util_nss.h"
-#include "content/child/webcrypto/status.h"
-#include "content/child/webcrypto/webcrypto_util.h"
-#include "crypto/scoped_nss_types.h"
-#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
-
-namespace content {
-
-namespace webcrypto {
-
-namespace {
-
-Status AesCbcEncryptDecrypt(EncryptOrDecrypt mode,
- const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) {
- const blink::WebCryptoAesCbcParams* params = algorithm.aesCbcParams();
- if (!params)
- return Status::ErrorUnexpected();
-
- CryptoData iv(params->iv().data(), params->iv().size());
- if (iv.byte_length() != 16)
- return Status::ErrorIncorrectSizeAesCbcIv();
-
- PK11SymKey* sym_key = SymKeyNss::Cast(key)->key();
-
- CK_ATTRIBUTE_TYPE operation = (mode == ENCRYPT) ? CKA_ENCRYPT : CKA_DECRYPT;
-
- SECItem iv_item = MakeSECItemForBuffer(iv);
-
- crypto::ScopedSECItem param(PK11_ParamFromIV(CKM_AES_CBC_PAD, &iv_item));
- if (!param)
- return Status::OperationError();
-
- crypto::ScopedPK11Context context(PK11_CreateContextBySymKey(
- CKM_AES_CBC_PAD, operation, sym_key, param.get()));
-
- if (!context.get())
- return Status::OperationError();
-
- // Oddly PK11_CipherOp takes input and output lengths as "int" rather than
- // "unsigned int". Do some checks now to avoid integer overflowing.
- base::CheckedNumeric<int> output_max_len = data.byte_length();
- output_max_len += AES_BLOCK_SIZE;
- if (!output_max_len.IsValid()) {
- // TODO(eroman): Handle this by chunking the input fed into NSS. Right now
- // it doesn't make much difference since the one-shot API would end up
- // blowing out the memory and crashing anyway.
- return Status::ErrorDataTooLarge();
- }
-
- // PK11_CipherOp does an invalid memory access when given empty decryption
- // input, or input which is not a multiple of the block size. See also
- // https://bugzilla.mozilla.com/show_bug.cgi?id=921687.
- if (operation == CKA_DECRYPT &&
- (data.byte_length() == 0 || (data.byte_length() % AES_BLOCK_SIZE != 0))) {
- return Status::OperationError();
- }
-
- // TODO(eroman): Refine the output buffer size. It can be computed exactly for
- // encryption, and can be smaller for decryption.
- buffer->resize(output_max_len.ValueOrDie());
-
- unsigned char* buffer_data = vector_as_array(buffer);
-
- int output_len;
- if (SECSuccess != PK11_CipherOp(context.get(),
- buffer_data,
- &output_len,
- buffer->size(),
- data.bytes(),
- data.byte_length())) {
- return Status::OperationError();
- }
-
- unsigned int final_output_chunk_len;
- if (SECSuccess !=
- PK11_DigestFinal(context.get(),
- buffer_data + output_len,
- &final_output_chunk_len,
- (output_max_len - output_len).ValueOrDie())) {
- return Status::OperationError();
- }
-
- buffer->resize(final_output_chunk_len + output_len);
- return Status::Success();
-}
-
-class AesCbcImplementation : public AesAlgorithm {
- public:
- AesCbcImplementation() : AesAlgorithm(CKM_AES_CBC, "CBC") {}
-
- Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const override {
- return AesCbcEncryptDecrypt(ENCRYPT, algorithm, key, data, buffer);
- }
-
- Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const override {
- return AesCbcEncryptDecrypt(DECRYPT, algorithm, key, data, buffer);
- }
-};
-
-} // namespace
-
-AlgorithmImplementation* CreatePlatformAesCbcImplementation() {
- return new AesCbcImplementation;
-}
-
-} // namespace webcrypto
-
-} // namespace content
diff --git a/chromium/content/child/webcrypto/nss/aes_gcm_nss.cc b/chromium/content/child/webcrypto/nss/aes_gcm_nss.cc
deleted file mode 100644
index 242fdfd48c4..00000000000
--- a/chromium/content/child/webcrypto/nss/aes_gcm_nss.cc
+++ /dev/null
@@ -1,191 +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 "base/numerics/safe_math.h"
-#include "base/stl_util.h"
-#include "content/child/webcrypto/crypto_data.h"
-#include "content/child/webcrypto/nss/aes_key_nss.h"
-#include "content/child/webcrypto/nss/key_nss.h"
-#include "content/child/webcrypto/nss/util_nss.h"
-#include "content/child/webcrypto/status.h"
-#include "content/child/webcrypto/webcrypto_util.h"
-#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
-
-// At the time of this writing:
-// * Windows and Mac builds ship with their own copy of NSS (3.15+)
-// * Linux builds use the system's libnss, which is 3.14 on Debian (but 3.15+
-// on other distros).
-//
-// Since NSS provides AES-GCM support starting in version 3.15, it may be
-// unavailable for Linux Chrome users.
-//
-// * !defined(CKM_AES_GCM)
-//
-// This means that at build time, the NSS header pkcs11t.h is older than
-// 3.15. However at runtime support may be present.
-//
-// TODO(eroman): Simplify this once 3.15+ is required by Linux builds.
-#if !defined(CKM_AES_GCM)
-#define CKM_AES_GCM 0x00001087
-
-struct CK_GCM_PARAMS {
- CK_BYTE_PTR pIv;
- CK_ULONG ulIvLen;
- CK_BYTE_PTR pAAD;
- CK_ULONG ulAADLen;
- CK_ULONG ulTagBits;
-};
-#endif // !defined(CKM_AES_GCM)
-
-namespace content {
-
-namespace webcrypto {
-
-namespace {
-
-Status NssSupportsAesGcm() {
- if (NssRuntimeSupport::Get()->IsAesGcmSupported())
- return Status::Success();
- return Status::ErrorUnsupported(
- "NSS version doesn't support AES-GCM. Try using version 3.15 or later");
-}
-
-// Helper to either encrypt or decrypt for AES-GCM. The result of encryption is
-// the concatenation of the ciphertext and the authentication tag. Similarly,
-// this is the expectation for the input to decryption.
-Status AesGcmEncryptDecrypt(EncryptOrDecrypt mode,
- const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) {
- Status status = NssSupportsAesGcm();
- if (status.IsError())
- return status;
-
- PK11SymKey* sym_key = SymKeyNss::Cast(key)->key();
- const blink::WebCryptoAesGcmParams* params = algorithm.aesGcmParams();
- if (!params)
- return Status::ErrorUnexpected();
-
- unsigned int tag_length_bits;
- status = GetAesGcmTagLengthInBits(params, &tag_length_bits);
- if (status.IsError())
- return status;
- unsigned int tag_length_bytes = tag_length_bits / 8;
-
- CryptoData iv(params->iv());
- CryptoData additional_data(params->optionalAdditionalData());
-
- CK_GCM_PARAMS gcm_params = {0};
- gcm_params.pIv = const_cast<unsigned char*>(iv.bytes());
- gcm_params.ulIvLen = iv.byte_length();
-
- gcm_params.pAAD = const_cast<unsigned char*>(additional_data.bytes());
- gcm_params.ulAADLen = additional_data.byte_length();
-
- gcm_params.ulTagBits = tag_length_bits;
-
- SECItem param;
- param.type = siBuffer;
- param.data = reinterpret_cast<unsigned char*>(&gcm_params);
- param.len = sizeof(gcm_params);
-
- base::CheckedNumeric<unsigned int> buffer_size(data.byte_length());
-
- // Calculate the output buffer size.
- if (mode == ENCRYPT) {
- buffer_size += tag_length_bytes;
- if (!buffer_size.IsValid())
- return Status::ErrorDataTooLarge();
- }
-
- // TODO(eroman): In theory the buffer allocated for the plain text should be
- // sized as |data.byte_length() - tag_length_bytes|.
- //
- // However NSS has a bug whereby it will fail if the output buffer size is
- // not at least as large as the ciphertext:
- //
- // https://bugzilla.mozilla.org/show_bug.cgi?id=%20853674
- //
- // From the analysis of that bug it looks like it might be safe to pass a
- // correctly sized buffer but lie about its size. Since resizing the
- // WebCryptoArrayBuffer is expensive that hack may be worth looking into.
-
- buffer->resize(buffer_size.ValueOrDie());
- unsigned char* buffer_data = vector_as_array(buffer);
-
- PK11_EncryptDecryptFunction encrypt_or_decrypt_func =
- (mode == ENCRYPT) ? NssRuntimeSupport::Get()->pk11_encrypt_func()
- : NssRuntimeSupport::Get()->pk11_decrypt_func();
-
- unsigned int output_len = 0;
- SECStatus result = encrypt_or_decrypt_func(sym_key,
- CKM_AES_GCM,
- &param,
- buffer_data,
- &output_len,
- buffer->size(),
- data.bytes(),
- data.byte_length());
-
- if (result != SECSuccess)
- return Status::OperationError();
-
- // Unfortunately the buffer needs to be shrunk for decryption (see the NSS bug
- // above).
- buffer->resize(output_len);
-
- return Status::Success();
-}
-
-class AesGcmImplementation : public AesAlgorithm {
- public:
- AesGcmImplementation() : AesAlgorithm(CKM_AES_GCM, "GCM") {}
-
- Status VerifyKeyUsagesBeforeImportKey(
- blink::WebCryptoKeyFormat format,
- blink::WebCryptoKeyUsageMask usages) const override {
- // Prevent importing AES-GCM keys if it is unavailable.
- Status status = NssSupportsAesGcm();
- if (status.IsError())
- return status;
- return AesAlgorithm::VerifyKeyUsagesBeforeImportKey(format, usages);
- }
-
- Status GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- GenerateKeyResult* result) const override {
- // Prevent generating AES-GCM keys if it is unavailable.
- Status status = NssSupportsAesGcm();
- if (status.IsError())
- return status;
-
- return AesAlgorithm::GenerateKey(algorithm, extractable, usages, result);
- }
-
- Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const override {
- return AesGcmEncryptDecrypt(ENCRYPT, algorithm, key, data, buffer);
- }
-
- Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const override {
- return AesGcmEncryptDecrypt(DECRYPT, algorithm, key, data, buffer);
- }
-};
-
-} // namespace
-
-AlgorithmImplementation* CreatePlatformAesGcmImplementation() {
- return new AesGcmImplementation;
-}
-
-} // namespace webcrypto
-
-} // namespace content
diff --git a/chromium/content/child/webcrypto/nss/aes_key_nss.cc b/chromium/content/child/webcrypto/nss/aes_key_nss.cc
deleted file mode 100644
index 2bd0c57e396..00000000000
--- a/chromium/content/child/webcrypto/nss/aes_key_nss.cc
+++ /dev/null
@@ -1,134 +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/child/webcrypto/nss/aes_key_nss.h"
-
-#include "base/logging.h"
-#include "content/child/webcrypto/crypto_data.h"
-#include "content/child/webcrypto/jwk.h"
-#include "content/child/webcrypto/nss/key_nss.h"
-#include "content/child/webcrypto/nss/sym_key_nss.h"
-#include "content/child/webcrypto/status.h"
-#include "content/child/webcrypto/webcrypto_util.h"
-#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
-
-namespace content {
-
-namespace webcrypto {
-
-AesAlgorithm::AesAlgorithm(CK_MECHANISM_TYPE import_mechanism,
- CK_FLAGS import_flags,
- blink::WebCryptoKeyUsageMask all_key_usages,
- const std::string& jwk_suffix)
- : import_mechanism_(import_mechanism),
- import_flags_(import_flags),
- all_key_usages_(all_key_usages),
- jwk_suffix_(jwk_suffix) {
-}
-
-AesAlgorithm::AesAlgorithm(CK_MECHANISM_TYPE import_mechanism,
- const std::string& jwk_suffix)
- : import_mechanism_(import_mechanism),
- import_flags_(CKF_ENCRYPT | CKF_DECRYPT),
- all_key_usages_(blink::WebCryptoKeyUsageEncrypt |
- blink::WebCryptoKeyUsageDecrypt |
- blink::WebCryptoKeyUsageWrapKey |
- blink::WebCryptoKeyUsageUnwrapKey),
- jwk_suffix_(jwk_suffix) {
-}
-
-Status AesAlgorithm::GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- GenerateKeyResult* result) const {
- Status status = CheckKeyCreationUsages(all_key_usages_, usages);
- if (status.IsError())
- return status;
-
- unsigned int keylen_bits;
- status = GetAesKeyGenLengthInBits(algorithm.aesKeyGenParams(), &keylen_bits);
- if (status.IsError())
- return status;
-
- return GenerateSecretKeyNss(
- blink::WebCryptoKeyAlgorithm::createAes(algorithm.id(), keylen_bits),
- extractable,
- usages,
- keylen_bits / 8,
- CKM_AES_KEY_GEN,
- result);
-}
-
-Status AesAlgorithm::VerifyKeyUsagesBeforeImportKey(
- blink::WebCryptoKeyFormat format,
- blink::WebCryptoKeyUsageMask usages) const {
- switch (format) {
- case blink::WebCryptoKeyFormatRaw:
- case blink::WebCryptoKeyFormatJwk:
- return CheckKeyCreationUsages(all_key_usages_, usages);
- default:
- return Status::ErrorUnsupportedImportKeyFormat();
- }
-}
-Status AesAlgorithm::ImportKeyRaw(const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const {
- const unsigned int keylen_bytes = key_data.byte_length();
- Status status = VerifyAesKeyLengthForImport(keylen_bytes);
- if (status.IsError())
- return status;
-
- // No possibility of overflow.
- unsigned int keylen_bits = keylen_bytes * 8;
-
- return ImportKeyRawNss(
- key_data,
- blink::WebCryptoKeyAlgorithm::createAes(algorithm.id(), keylen_bits),
- extractable,
- usages,
- import_mechanism_,
- import_flags_,
- key);
-}
-
-Status AesAlgorithm::ImportKeyJwk(const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const {
- std::vector<uint8_t> raw_data;
- Status status = ReadAesSecretKeyJwk(
- key_data, jwk_suffix_, extractable, usages, &raw_data);
- if (status.IsError())
- return status;
-
- return ImportKeyRaw(
- CryptoData(raw_data), algorithm, extractable, usages, key);
-}
-
-Status AesAlgorithm::ExportKeyRaw(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const {
- *buffer = SymKeyNss::Cast(key)->raw_key_data();
- return Status::Success();
-}
-
-Status AesAlgorithm::ExportKeyJwk(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const {
- SymKeyNss* sym_key = SymKeyNss::Cast(key);
- const std::vector<uint8_t>& raw_data = sym_key->raw_key_data();
-
- WriteSecretKeyJwk(CryptoData(raw_data),
- MakeJwkAesAlgorithmName(jwk_suffix_, raw_data.size()),
- key.extractable(),
- key.usages(),
- buffer);
-
- return Status::Success();
-}
-
-} // namespace webcrypto
-
-} // namespace content
diff --git a/chromium/content/child/webcrypto/nss/aes_key_nss.h b/chromium/content/child/webcrypto/nss/aes_key_nss.h
deleted file mode 100644
index 5e4cba35e42..00000000000
--- a/chromium/content/child/webcrypto/nss/aes_key_nss.h
+++ /dev/null
@@ -1,77 +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_CHILD_WEBCRYPTO_NSS_AES_NSS_H_
-#define CONTENT_CHILD_WEBCRYPTO_NSS_AES_NSS_H_
-
-#include <pkcs11t.h>
-
-#include "content/child/webcrypto/algorithm_implementation.h"
-
-namespace content {
-
-namespace webcrypto {
-
-// Base class for AES algorithms that provides the implementation for key
-// creation and export.
-class AesAlgorithm : public AlgorithmImplementation {
- public:
- // Constructs an AES algorithm whose keys will be imported using the NSS
- // mechanism |import_mechanism| and NSS flags |import_flags|.
- // |all_key_usages| is the set of all WebCrypto key usages that are
- // allowed for imported or generated keys. |jwk_suffix| is the suffix
- // used when constructing JWK names for the algorithm. For instance A128CBC
- // is the JWK name for 128-bit AES-CBC. The |jwk_suffix| in this case would
- // be "CBC".
- AesAlgorithm(CK_MECHANISM_TYPE import_mechanism,
- CK_FLAGS import_flags,
- blink::WebCryptoKeyUsageMask all_key_usages,
- const std::string& jwk_suffix);
-
- // This is the same as the other AesAlgorithm constructor, however
- // |import_flags| and |all_key_usages| are pre-filled to values for
- // encryption/decryption algorithms (supports usages for: encrypt, decrypt,
- // wrap, unwrap).
- AesAlgorithm(CK_MECHANISM_TYPE import_mechanism,
- const std::string& jwk_suffix);
-
- Status GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- GenerateKeyResult* result) const override;
-
- Status VerifyKeyUsagesBeforeImportKey(
- blink::WebCryptoKeyFormat format,
- blink::WebCryptoKeyUsageMask usages) const override;
-
- Status ImportKeyRaw(const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const override;
-
- Status ImportKeyJwk(const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const override;
-
- Status ExportKeyRaw(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const override;
-
- Status ExportKeyJwk(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const override;
-
- private:
- const CK_MECHANISM_TYPE import_mechanism_;
- const CK_FLAGS import_flags_;
- const blink::WebCryptoKeyUsageMask all_key_usages_;
- const std::string jwk_suffix_;
-};
-
-} // namespace webcrypto
-
-} // namespace content
-
-#endif // CONTENT_CHILD_WEBCRYPTO_NSS_AES_NSS_H_
diff --git a/chromium/content/child/webcrypto/nss/aes_kw_nss.cc b/chromium/content/child/webcrypto/nss/aes_kw_nss.cc
deleted file mode 100644
index 76d3337d51b..00000000000
--- a/chromium/content/child/webcrypto/nss/aes_kw_nss.cc
+++ /dev/null
@@ -1,206 +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 <secerr.h>
-
-#include "base/numerics/safe_math.h"
-#include "content/child/webcrypto/crypto_data.h"
-#include "content/child/webcrypto/nss/aes_key_nss.h"
-#include "content/child/webcrypto/nss/key_nss.h"
-#include "content/child/webcrypto/nss/sym_key_nss.h"
-#include "content/child/webcrypto/nss/util_nss.h"
-#include "content/child/webcrypto/status.h"
-#include "content/child/webcrypto/webcrypto_util.h"
-#include "crypto/scoped_nss_types.h"
-#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
-#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
-
-namespace content {
-
-namespace webcrypto {
-
-namespace {
-
-// The Default IV for AES-KW. See http://www.ietf.org/rfc/rfc3394.txt
-// Section 2.2.3.1.
-const unsigned char kAesIv[] = {0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6};
-
-// The result of unwrapping is a SymKey rather than a buffer. This is a
-// consequence of how NSS exposes AES-KW. Subsequent code can extract the value
-// of the sym key to interpret it as key bytes in another format.
-Status DoUnwrapSymKeyAesKw(const CryptoData& wrapped_key_data,
- PK11SymKey* wrapping_key,
- CK_MECHANISM_TYPE mechanism,
- CK_FLAGS flags,
- crypto::ScopedPK11SymKey* unwrapped_key) {
- DCHECK_GE(wrapped_key_data.byte_length(), 24u);
- DCHECK_EQ(wrapped_key_data.byte_length() % 8, 0u);
-
- SECItem iv_item = MakeSECItemForBuffer(CryptoData(kAesIv, sizeof(kAesIv)));
- crypto::ScopedSECItem param_item(
- PK11_ParamFromIV(CKM_NSS_AES_KEY_WRAP, &iv_item));
- if (!param_item)
- return Status::ErrorUnexpected();
-
- SECItem cipher_text = MakeSECItemForBuffer(wrapped_key_data);
-
- // The plaintext length is always 64 bits less than the data size.
- const unsigned int plaintext_length = wrapped_key_data.byte_length() - 8;
-
-#if defined(USE_NSS)
- // Part of workaround for
- // https://bugzilla.mozilla.org/show_bug.cgi?id=981170. See the explanation
- // later in this function.
- PORT_SetError(0);
-#endif
-
- crypto::ScopedPK11SymKey new_key(
- PK11_UnwrapSymKeyWithFlags(wrapping_key,
- CKM_NSS_AES_KEY_WRAP,
- param_item.get(),
- &cipher_text,
- mechanism,
- CKA_FLAGS_ONLY,
- plaintext_length,
- flags));
-
- // TODO(padolph): Use NSS PORT_GetError() and friends to report a more
- // accurate error, providing if doesn't leak any information to web pages
- // about other web crypto users, key details, etc.
- if (!new_key)
- return Status::OperationError();
-
-#if defined(USE_NSS)
- // Workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=981170
- // which was fixed in NSS 3.16.0.
- // If unwrap fails, NSS nevertheless returns a valid-looking PK11SymKey,
- // with a reasonable length but with key data pointing to uninitialized
- // memory.
- // To understand this workaround see the fix for 981170:
- // https://hg.mozilla.org/projects/nss/rev/753bb69e543c
- if (!NSS_VersionCheck("3.16") && PORT_GetError() == SEC_ERROR_BAD_DATA)
- return Status::OperationError();
-#endif
-
- *unwrapped_key = new_key.Pass();
- return Status::Success();
-}
-
-Status WrapSymKeyAesKw(PK11SymKey* key,
- PK11SymKey* wrapping_key,
- std::vector<uint8_t>* buffer) {
- // The data size must be at least 16 bytes and a multiple of 8 bytes.
- // RFC 3394 does not specify a maximum allowed data length, but since only
- // keys are being wrapped in this application (which are small), a reasonable
- // max limit is whatever will fit into an unsigned. For the max size test,
- // note that AES Key Wrap always adds 8 bytes to the input data size.
- const unsigned int input_length = PK11_GetKeyLength(key);
- DCHECK_GE(input_length, 16u);
- DCHECK((input_length % 8) == 0);
-
- SECItem iv_item = MakeSECItemForBuffer(CryptoData(kAesIv, sizeof(kAesIv)));
- crypto::ScopedSECItem param_item(
- PK11_ParamFromIV(CKM_NSS_AES_KEY_WRAP, &iv_item));
- if (!param_item)
- return Status::ErrorUnexpected();
-
- base::CheckedNumeric<unsigned int> output_length = input_length;
- output_length += 8;
- if (!output_length.IsValid())
- return Status::ErrorDataTooLarge();
-
- buffer->resize(output_length.ValueOrDie());
- SECItem wrapped_key_item = MakeSECItemForBuffer(CryptoData(*buffer));
-
- if (SECSuccess != PK11_WrapSymKey(CKM_NSS_AES_KEY_WRAP,
- param_item.get(),
- wrapping_key,
- key,
- &wrapped_key_item)) {
- return Status::OperationError();
- }
- if (output_length.ValueOrDie() != wrapped_key_item.len)
- return Status::ErrorUnexpected();
-
- return Status::Success();
-}
-
-class AesKwCryptoAlgorithmNss : public AesAlgorithm {
- public:
- AesKwCryptoAlgorithmNss()
- : AesAlgorithm(
- CKM_NSS_AES_KEY_WRAP,
- CKF_WRAP | CKF_WRAP,
- blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey,
- "KW") {}
-
- Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& wrapping_key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const override {
- if (data.byte_length() < 16)
- return Status::ErrorDataTooSmall();
- if (data.byte_length() % 8)
- return Status::ErrorInvalidAesKwDataLength();
-
- // Due to limitations in the NSS API for the AES-KW algorithm, |data| must
- // be temporarily viewed as a symmetric key to be wrapped (encrypted).
- SECItem data_item = MakeSECItemForBuffer(data);
- crypto::ScopedPK11Slot slot(PK11_GetInternalSlot());
- crypto::ScopedPK11SymKey data_as_sym_key(
- PK11_ImportSymKey(slot.get(),
- CKK_GENERIC_SECRET,
- PK11_OriginUnwrap,
- CKA_SIGN,
- &data_item,
- NULL));
- if (!data_as_sym_key)
- return Status::OperationError();
-
- return WrapSymKeyAesKw(
- data_as_sym_key.get(), SymKeyNss::Cast(wrapping_key)->key(), buffer);
- }
-
- Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& wrapping_key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const override {
- if (data.byte_length() < 24)
- return Status::ErrorDataTooSmall();
- if (data.byte_length() % 8)
- return Status::ErrorInvalidAesKwDataLength();
-
- // Due to limitations in the NSS API for the AES-KW algorithm, |data| must
- // be temporarily viewed as a symmetric key to be unwrapped (decrypted).
- crypto::ScopedPK11SymKey decrypted;
- Status status = DoUnwrapSymKeyAesKw(data,
- SymKeyNss::Cast(wrapping_key)->key(),
- CKK_GENERIC_SECRET,
- 0,
- &decrypted);
- if (status.IsError())
- return status;
-
- // Once the decrypt is complete, extract the resultant raw bytes from NSS
- // and return them to the caller.
- if (PK11_ExtractKeyValue(decrypted.get()) != SECSuccess)
- return Status::OperationError();
- const SECItem* const key_data = PK11_GetKeyData(decrypted.get());
- if (!key_data)
- return Status::OperationError();
- buffer->assign(key_data->data, key_data->data + key_data->len);
-
- return Status::Success();
- }
-};
-
-} // namespace
-
-AlgorithmImplementation* CreatePlatformAesKwImplementation() {
- return new AesKwCryptoAlgorithmNss;
-}
-
-} // namespace webcrypto
-
-} // namespace content
diff --git a/chromium/content/child/webcrypto/nss/hmac_nss.cc b/chromium/content/child/webcrypto/nss/hmac_nss.cc
deleted file mode 100644
index c3424fb94f4..00000000000
--- a/chromium/content/child/webcrypto/nss/hmac_nss.cc
+++ /dev/null
@@ -1,240 +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 <cryptohi.h>
-#include <pk11pub.h>
-#include <secerr.h>
-#include <sechash.h>
-
-#include "base/logging.h"
-#include "base/numerics/safe_math.h"
-#include "base/stl_util.h"
-#include "content/child/webcrypto/algorithm_implementation.h"
-#include "content/child/webcrypto/crypto_data.h"
-#include "content/child/webcrypto/jwk.h"
-#include "content/child/webcrypto/nss/key_nss.h"
-#include "content/child/webcrypto/nss/sym_key_nss.h"
-#include "content/child/webcrypto/nss/util_nss.h"
-#include "content/child/webcrypto/status.h"
-#include "content/child/webcrypto/webcrypto_util.h"
-#include "crypto/secure_util.h"
-#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
-#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
-
-namespace content {
-
-namespace webcrypto {
-
-namespace {
-
-const blink::WebCryptoKeyUsageMask kAllKeyUsages =
- blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify;
-
-bool WebCryptoHashToHMACMechanism(const blink::WebCryptoAlgorithm& algorithm,
- CK_MECHANISM_TYPE* mechanism) {
- switch (algorithm.id()) {
- case blink::WebCryptoAlgorithmIdSha1:
- *mechanism = CKM_SHA_1_HMAC;
- return true;
- case blink::WebCryptoAlgorithmIdSha256:
- *mechanism = CKM_SHA256_HMAC;
- return true;
- case blink::WebCryptoAlgorithmIdSha384:
- *mechanism = CKM_SHA384_HMAC;
- return true;
- case blink::WebCryptoAlgorithmIdSha512:
- *mechanism = CKM_SHA512_HMAC;
- return true;
- default:
- return false;
- }
-}
-
-class HmacImplementation : public AlgorithmImplementation {
- public:
- HmacImplementation() {}
-
- Status GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- GenerateKeyResult* result) const override {
- Status status = CheckKeyCreationUsages(kAllKeyUsages, usages);
- if (status.IsError())
- return status;
-
- const blink::WebCryptoHmacKeyGenParams* params =
- algorithm.hmacKeyGenParams();
-
- const blink::WebCryptoAlgorithm& hash = params->hash();
- CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
- if (!WebCryptoHashToHMACMechanism(hash, &mechanism))
- return Status::ErrorUnsupported();
-
- unsigned int keylen_bits = 0;
- status = GetHmacKeyGenLengthInBits(params, &keylen_bits);
- if (status.IsError())
- return status;
-
- return GenerateSecretKeyNss(
- blink::WebCryptoKeyAlgorithm::createHmac(hash.id(), keylen_bits),
- extractable,
- usages,
- keylen_bits / 8,
- mechanism,
- result);
- }
-
- Status VerifyKeyUsagesBeforeImportKey(
- blink::WebCryptoKeyFormat format,
- blink::WebCryptoKeyUsageMask usages) const override {
- switch (format) {
- case blink::WebCryptoKeyFormatRaw:
- case blink::WebCryptoKeyFormatJwk:
- return CheckKeyCreationUsages(kAllKeyUsages, usages);
- default:
- return Status::ErrorUnsupportedImportKeyFormat();
- }
- }
-
- Status ImportKeyRaw(const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const override {
- const blink::WebCryptoAlgorithm& hash =
- algorithm.hmacImportParams()->hash();
-
- CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
- if (!WebCryptoHashToHMACMechanism(hash, &mechanism))
- return Status::ErrorUnsupported();
-
- base::CheckedNumeric<unsigned int> keylen_bits(key_data.byte_length());
- keylen_bits *= 8;
-
- if (!keylen_bits.IsValid())
- return Status::ErrorDataTooLarge();
-
- return ImportKeyRawNss(key_data,
- blink::WebCryptoKeyAlgorithm::createHmac(
- hash.id(), keylen_bits.ValueOrDie()),
- extractable,
- usages,
- mechanism,
- CKF_SIGN | CKF_VERIFY,
- key);
- }
-
- Status ImportKeyJwk(const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const override {
- const char* algorithm_name =
- GetJwkHmacAlgorithmName(algorithm.hmacImportParams()->hash().id());
- if (!algorithm_name)
- return Status::ErrorUnexpected();
-
- std::vector<uint8_t> raw_data;
- Status status = ReadSecretKeyJwk(
- key_data, algorithm_name, extractable, usages, &raw_data);
- if (status.IsError())
- return status;
-
- return ImportKeyRaw(
- CryptoData(raw_data), algorithm, extractable, usages, key);
- }
-
- Status ExportKeyRaw(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const override {
- *buffer = SymKeyNss::Cast(key)->raw_key_data();
- return Status::Success();
- }
-
- Status ExportKeyJwk(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const override {
- SymKeyNss* sym_key = SymKeyNss::Cast(key);
- const std::vector<uint8_t>& raw_data = sym_key->raw_key_data();
-
- const char* algorithm_name =
- GetJwkHmacAlgorithmName(key.algorithm().hmacParams()->hash().id());
- if (!algorithm_name)
- return Status::ErrorUnexpected();
-
- WriteSecretKeyJwk(CryptoData(raw_data),
- algorithm_name,
- key.extractable(),
- key.usages(),
- buffer);
-
- return Status::Success();
- }
-
- Status Sign(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const override {
- const blink::WebCryptoAlgorithm& hash =
- key.algorithm().hmacParams()->hash();
- PK11SymKey* sym_key = SymKeyNss::Cast(key)->key();
-
- CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
- if (!WebCryptoHashToHMACMechanism(hash, &mechanism))
- return Status::ErrorUnexpected();
-
- SECItem param_item = {siBuffer, NULL, 0};
- SECItem data_item = MakeSECItemForBuffer(data);
- // First call is to figure out the length.
- SECItem signature_item = {siBuffer, NULL, 0};
-
- if (PK11_SignWithSymKey(
- sym_key, mechanism, &param_item, &signature_item, &data_item) !=
- SECSuccess) {
- return Status::OperationError();
- }
-
- DCHECK_NE(0u, signature_item.len);
-
- buffer->resize(signature_item.len);
- signature_item.data = vector_as_array(buffer);
-
- if (PK11_SignWithSymKey(
- sym_key, mechanism, &param_item, &signature_item, &data_item) !=
- SECSuccess) {
- return Status::OperationError();
- }
-
- CHECK_EQ(buffer->size(), signature_item.len);
- return Status::Success();
- }
-
- Status Verify(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& signature,
- const CryptoData& data,
- bool* signature_match) const override {
- std::vector<uint8_t> result;
- Status status = Sign(algorithm, key, data, &result);
-
- if (status.IsError())
- return status;
-
- // Do not allow verification of truncated MACs.
- *signature_match = result.size() == signature.byte_length() &&
- crypto::SecureMemEqual(vector_as_array(&result),
- signature.bytes(),
- signature.byte_length());
-
- return Status::Success();
- }
-};
-
-} // namespace
-
-AlgorithmImplementation* CreatePlatformHmacImplementation() {
- return new HmacImplementation;
-}
-
-} // namespace webcrypto
-
-} // namespace content
diff --git a/chromium/content/child/webcrypto/nss/key_nss.cc b/chromium/content/child/webcrypto/nss/key_nss.cc
deleted file mode 100644
index 9193963fb59..00000000000
--- a/chromium/content/child/webcrypto/nss/key_nss.cc
+++ /dev/null
@@ -1,96 +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/child/webcrypto/nss/key_nss.h"
-
-#include "content/child/webcrypto/crypto_data.h"
-#include "content/child/webcrypto/status.h"
-#include "content/child/webcrypto/webcrypto_util.h"
-
-namespace content {
-
-namespace webcrypto {
-
-KeyNss::KeyNss(const CryptoData& serialized_key_data)
- : serialized_key_data_(
- serialized_key_data.bytes(),
- serialized_key_data.bytes() + serialized_key_data.byte_length()) {
-}
-
-KeyNss::~KeyNss() {
-}
-
-SymKeyNss* KeyNss::AsSymKey() {
- return NULL;
-}
-
-PublicKeyNss* KeyNss::AsPublicKey() {
- return NULL;
-}
-
-PrivateKeyNss* KeyNss::AsPrivateKey() {
- return NULL;
-}
-
-SymKeyNss::~SymKeyNss() {
-}
-
-SymKeyNss* SymKeyNss::Cast(const blink::WebCryptoKey& key) {
- KeyNss* platform_key = reinterpret_cast<KeyNss*>(key.handle());
- return platform_key->AsSymKey();
-}
-
-SymKeyNss* SymKeyNss::AsSymKey() {
- return this;
-}
-
-SymKeyNss::SymKeyNss(crypto::ScopedPK11SymKey key,
- const CryptoData& raw_key_data)
- : KeyNss(raw_key_data), key_(key.Pass()) {
-}
-
-PublicKeyNss::~PublicKeyNss() {
-}
-
-PublicKeyNss* PublicKeyNss::Cast(const blink::WebCryptoKey& key) {
- KeyNss* platform_key = reinterpret_cast<KeyNss*>(key.handle());
- return platform_key->AsPublicKey();
-}
-
-PublicKeyNss* PublicKeyNss::AsPublicKey() {
- return this;
-}
-
-PublicKeyNss::PublicKeyNss(crypto::ScopedSECKEYPublicKey key,
- const CryptoData& spki_data)
- : KeyNss(spki_data), key_(key.Pass()) {
-}
-
-PrivateKeyNss::~PrivateKeyNss() {
-}
-
-PrivateKeyNss* PrivateKeyNss::Cast(const blink::WebCryptoKey& key) {
- KeyNss* platform_key = reinterpret_cast<KeyNss*>(key.handle());
- return platform_key->AsPrivateKey();
-}
-
-PrivateKeyNss* PrivateKeyNss::AsPrivateKey() {
- return this;
-}
-
-PrivateKeyNss::PrivateKeyNss(crypto::ScopedSECKEYPrivateKey key,
- const CryptoData& pkcs8_data)
- : KeyNss(pkcs8_data), key_(key.Pass()) {
-}
-
-bool PlatformSerializeKeyForClone(const blink::WebCryptoKey& key,
- blink::WebVector<uint8_t>* key_data) {
- const KeyNss* nss_key = static_cast<KeyNss*>(key.handle());
- *key_data = nss_key->serialized_key_data();
- return true;
-}
-
-} // namespace webcrypto
-
-} // namespace content
diff --git a/chromium/content/child/webcrypto/nss/key_nss.h b/chromium/content/child/webcrypto/nss/key_nss.h
deleted file mode 100644
index 9eaf7c427b0..00000000000
--- a/chromium/content/child/webcrypto/nss/key_nss.h
+++ /dev/null
@@ -1,109 +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_CHILD_WEBCRYPTO_NSS_KEY_NSS_H_
-#define CONTENT_CHILD_WEBCRYPTO_NSS_KEY_NSS_H_
-
-#include <stdint.h>
-#include <vector>
-
-#include "crypto/scoped_nss_types.h"
-#include "third_party/WebKit/public/platform/WebCryptoKey.h"
-
-namespace content {
-
-namespace webcrypto {
-
-class CryptoData;
-class PrivateKeyNss;
-class PublicKeyNss;
-class SymKeyNss;
-
-// Base key class for all NSS keys, used to safely cast between types. Each key
-// maintains a copy of its serialized form in either 'raw', 'pkcs8', or 'spki'
-// format. This is to allow structured cloning of keys synchronously from the
-// target Blink thread without having to lock access to the key.
-class KeyNss : public blink::WebCryptoKeyHandle {
- public:
- explicit KeyNss(const CryptoData& serialized_key_data);
- ~KeyNss() override;
-
- virtual SymKeyNss* AsSymKey();
- virtual PublicKeyNss* AsPublicKey();
- virtual PrivateKeyNss* AsPrivateKey();
-
- const std::vector<uint8_t>& serialized_key_data() const {
- return serialized_key_data_;
- }
-
- private:
- const std::vector<uint8_t> serialized_key_data_;
-};
-
-class SymKeyNss : public KeyNss {
- public:
- ~SymKeyNss() override;
- SymKeyNss(crypto::ScopedPK11SymKey key, const CryptoData& raw_key_data);
-
- static SymKeyNss* Cast(const blink::WebCryptoKey& key);
-
- PK11SymKey* key() { return key_.get(); }
- SymKeyNss* AsSymKey() override;
-
- const std::vector<uint8_t>& raw_key_data() const {
- return serialized_key_data();
- }
-
- private:
- crypto::ScopedPK11SymKey key_;
-
- DISALLOW_COPY_AND_ASSIGN(SymKeyNss);
-};
-
-class PublicKeyNss : public KeyNss {
- public:
- ~PublicKeyNss() override;
- PublicKeyNss(crypto::ScopedSECKEYPublicKey key, const CryptoData& spki_data);
-
- static PublicKeyNss* Cast(const blink::WebCryptoKey& key);
-
- SECKEYPublicKey* key() { return key_.get(); }
- PublicKeyNss* AsPublicKey() override;
-
- const std::vector<uint8_t>& spki_data() const {
- return serialized_key_data();
- }
-
- private:
- crypto::ScopedSECKEYPublicKey key_;
-
- DISALLOW_COPY_AND_ASSIGN(PublicKeyNss);
-};
-
-class PrivateKeyNss : public KeyNss {
- public:
- ~PrivateKeyNss() override;
- PrivateKeyNss(crypto::ScopedSECKEYPrivateKey key,
- const CryptoData& pkcs8_data);
-
- static PrivateKeyNss* Cast(const blink::WebCryptoKey& key);
-
- SECKEYPrivateKey* key() { return key_.get(); }
- PrivateKeyNss* AsPrivateKey() override;
-
- const std::vector<uint8_t>& pkcs8_data() const {
- return serialized_key_data();
- }
-
- private:
- crypto::ScopedSECKEYPrivateKey key_;
-
- DISALLOW_COPY_AND_ASSIGN(PrivateKeyNss);
-};
-
-} // namespace webcrypto
-
-} // namespace content
-
-#endif // CONTENT_CHILD_WEBCRYPTO_NSS_KEY_NSS_H_
diff --git a/chromium/content/child/webcrypto/nss/rsa_key_nss.cc b/chromium/content/child/webcrypto/nss/rsa_key_nss.cc
deleted file mode 100644
index f9619a62a16..00000000000
--- a/chromium/content/child/webcrypto/nss/rsa_key_nss.cc
+++ /dev/null
@@ -1,852 +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/child/webcrypto/nss/rsa_key_nss.h"
-
-#include "base/logging.h"
-#include "content/child/webcrypto/crypto_data.h"
-#include "content/child/webcrypto/generate_key_result.h"
-#include "content/child/webcrypto/jwk.h"
-#include "content/child/webcrypto/nss/key_nss.h"
-#include "content/child/webcrypto/nss/util_nss.h"
-#include "content/child/webcrypto/status.h"
-#include "content/child/webcrypto/webcrypto_util.h"
-#include "crypto/scoped_nss_types.h"
-#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
-#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
-
-namespace content {
-
-namespace webcrypto {
-
-namespace {
-
-#if defined(USE_NSS) && !defined(OS_CHROMEOS)
-Status ErrorRsaPrivateKeyImportNotSupported() {
- return Status::ErrorUnsupported(
- "NSS version must be at least 3.16.2 for RSA private key import. See "
- "http://crbug.com/380424");
-}
-
-// Prior to NSS 3.16.2 RSA key parameters were not validated. This is
-// a security problem for RSA private key import from JWK which uses a
-// CKA_ID based on the public modulus to retrieve the private key.
-Status NssSupportsRsaPrivateKeyImport() {
- if (!NSS_VersionCheck("3.16.2"))
- return ErrorRsaPrivateKeyImportNotSupported();
-
- // Also ensure that the version of Softoken is 3.16.2 or later.
- crypto::ScopedPK11Slot slot(PK11_GetInternalSlot());
- CK_SLOT_INFO info = {};
- if (PK11_GetSlotInfo(slot.get(), &info) != SECSuccess)
- return ErrorRsaPrivateKeyImportNotSupported();
-
- // CK_SLOT_INFO.hardwareVersion contains the major.minor
- // version info for Softoken in the corresponding .major/.minor
- // fields, and .firmwareVersion contains the patch.build
- // version info (in the .major/.minor fields)
- if ((info.hardwareVersion.major > 3) ||
- (info.hardwareVersion.major == 3 &&
- (info.hardwareVersion.minor > 16 ||
- (info.hardwareVersion.minor == 16 &&
- info.firmwareVersion.major >= 2)))) {
- return Status::Success();
- }
-
- return ErrorRsaPrivateKeyImportNotSupported();
-}
-#else
-Status NssSupportsRsaPrivateKeyImport() {
- return Status::Success();
-}
-#endif
-
-bool CreateRsaHashedPublicKeyAlgorithm(
- blink::WebCryptoAlgorithmId rsa_algorithm,
- blink::WebCryptoAlgorithmId hash_algorithm,
- SECKEYPublicKey* key,
- blink::WebCryptoKeyAlgorithm* key_algorithm) {
- // TODO(eroman): What about other key types rsaPss, rsaOaep.
- if (!key || key->keyType != rsaKey)
- return false;
-
- unsigned int modulus_length_bits = SECKEY_PublicKeyStrength(key) * 8;
- CryptoData public_exponent(key->u.rsa.publicExponent.data,
- key->u.rsa.publicExponent.len);
-
- *key_algorithm = blink::WebCryptoKeyAlgorithm::createRsaHashed(
- rsa_algorithm,
- modulus_length_bits,
- public_exponent.bytes(),
- public_exponent.byte_length(),
- hash_algorithm);
- return true;
-}
-
-bool CreateRsaHashedPrivateKeyAlgorithm(
- blink::WebCryptoAlgorithmId rsa_algorithm,
- blink::WebCryptoAlgorithmId hash_algorithm,
- SECKEYPrivateKey* key,
- blink::WebCryptoKeyAlgorithm* key_algorithm) {
- crypto::ScopedSECKEYPublicKey public_key(SECKEY_ConvertToPublicKey(key));
- if (!public_key)
- return false;
- return CreateRsaHashedPublicKeyAlgorithm(
- rsa_algorithm, hash_algorithm, public_key.get(), key_algorithm);
-}
-
-// From PKCS#1 [http://tools.ietf.org/html/rfc3447]:
-//
-// RSAPrivateKey ::= SEQUENCE {
-// version Version,
-// modulus INTEGER, -- n
-// publicExponent INTEGER, -- e
-// privateExponent INTEGER, -- d
-// prime1 INTEGER, -- p
-// prime2 INTEGER, -- q
-// exponent1 INTEGER, -- d mod (p-1)
-// exponent2 INTEGER, -- d mod (q-1)
-// coefficient INTEGER, -- (inverse of q) mod p
-// otherPrimeInfos OtherPrimeInfos OPTIONAL
-// }
-//
-// Note that otherPrimeInfos is only applicable for version=1. Since NSS
-// doesn't use multi-prime can safely use version=0.
-struct RSAPrivateKey {
- SECItem version;
- SECItem modulus;
- SECItem public_exponent;
- SECItem private_exponent;
- SECItem prime1;
- SECItem prime2;
- SECItem exponent1;
- SECItem exponent2;
- SECItem coefficient;
-};
-
-// The system NSS library doesn't have the new PK11_ExportDERPrivateKeyInfo
-// function yet (https://bugzilla.mozilla.org/show_bug.cgi?id=519255). So we
-// provide a fallback implementation.
-#if defined(USE_NSS)
-const SEC_ASN1Template RSAPrivateKeyTemplate[] = {
- {SEC_ASN1_SEQUENCE, 0, NULL, sizeof(RSAPrivateKey)},
- {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, version)},
- {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, modulus)},
- {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, public_exponent)},
- {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, private_exponent)},
- {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, prime1)},
- {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, prime2)},
- {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, exponent1)},
- {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, exponent2)},
- {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, coefficient)},
- {0}};
-#endif // defined(USE_NSS)
-
-// On success |value| will be filled with data which must be freed by
-// SECITEM_FreeItem(value, PR_FALSE);
-bool ReadUint(SECKEYPrivateKey* key,
- CK_ATTRIBUTE_TYPE attribute,
- SECItem* value) {
- SECStatus rv = PK11_ReadRawAttribute(PK11_TypePrivKey, key, attribute, value);
-
- // PK11_ReadRawAttribute() returns items of type siBuffer. However in order
- // for the ASN.1 encoding to be correct, the items must be of type
- // siUnsignedInteger.
- value->type = siUnsignedInteger;
-
- return rv == SECSuccess;
-}
-
-// Fills |out| with the RSA private key properties. Returns true on success.
-// Regardless of the return value, the caller must invoke FreeRSAPrivateKey()
-// to free up any allocated memory.
-//
-// The passed in RSAPrivateKey must be zero-initialized.
-bool InitRSAPrivateKey(SECKEYPrivateKey* key, RSAPrivateKey* out) {
- if (key->keyType != rsaKey)
- return false;
-
- // Everything should be zero-ed out. These are just some spot checks.
- DCHECK(!out->version.data);
- DCHECK(!out->version.len);
- DCHECK(!out->modulus.data);
- DCHECK(!out->modulus.len);
-
- // Always use version=0 since not using multi-prime.
- if (!SEC_ASN1EncodeInteger(NULL, &out->version, 0))
- return false;
-
- if (!ReadUint(key, CKA_MODULUS, &out->modulus))
- return false;
- if (!ReadUint(key, CKA_PUBLIC_EXPONENT, &out->public_exponent))
- return false;
- if (!ReadUint(key, CKA_PRIVATE_EXPONENT, &out->private_exponent))
- return false;
- if (!ReadUint(key, CKA_PRIME_1, &out->prime1))
- return false;
- if (!ReadUint(key, CKA_PRIME_2, &out->prime2))
- return false;
- if (!ReadUint(key, CKA_EXPONENT_1, &out->exponent1))
- return false;
- if (!ReadUint(key, CKA_EXPONENT_2, &out->exponent2))
- return false;
- if (!ReadUint(key, CKA_COEFFICIENT, &out->coefficient))
- return false;
-
- return true;
-}
-
-struct FreeRsaPrivateKey {
- void operator()(RSAPrivateKey* out) {
- SECITEM_FreeItem(&out->version, PR_FALSE);
- SECITEM_FreeItem(&out->modulus, PR_FALSE);
- SECITEM_FreeItem(&out->public_exponent, PR_FALSE);
- SECITEM_FreeItem(&out->private_exponent, PR_FALSE);
- SECITEM_FreeItem(&out->prime1, PR_FALSE);
- SECITEM_FreeItem(&out->prime2, PR_FALSE);
- SECITEM_FreeItem(&out->exponent1, PR_FALSE);
- SECITEM_FreeItem(&out->exponent2, PR_FALSE);
- SECITEM_FreeItem(&out->coefficient, PR_FALSE);
- }
-};
-
-typedef scoped_ptr<CERTSubjectPublicKeyInfo,
- crypto::NSSDestroyer<CERTSubjectPublicKeyInfo,
- SECKEY_DestroySubjectPublicKeyInfo> >
- ScopedCERTSubjectPublicKeyInfo;
-
-struct DestroyGenericObject {
- void operator()(PK11GenericObject* o) const {
- if (o)
- PK11_DestroyGenericObject(o);
- }
-};
-
-typedef scoped_ptr<PK11GenericObject, DestroyGenericObject>
- ScopedPK11GenericObject;
-
-// Helper to add an attribute to a template.
-void AddAttribute(CK_ATTRIBUTE_TYPE type,
- void* value,
- unsigned long length,
- std::vector<CK_ATTRIBUTE>* templ) {
- CK_ATTRIBUTE attribute = {type, value, length};
- templ->push_back(attribute);
-}
-
-void AddAttribute(CK_ATTRIBUTE_TYPE type,
- const CryptoData& data,
- std::vector<CK_ATTRIBUTE>* templ) {
- CK_ATTRIBUTE attribute = {type, const_cast<unsigned char*>(data.bytes()),
- data.byte_length()};
- templ->push_back(attribute);
-}
-
-void AddAttribute(CK_ATTRIBUTE_TYPE type,
- const std::string& data,
- std::vector<CK_ATTRIBUTE>* templ) {
- AddAttribute(type, CryptoData(data), templ);
-}
-
-Status ExportKeyPkcs8Nss(SECKEYPrivateKey* key, std::vector<uint8_t>* buffer) {
- if (key->keyType != rsaKey)
- return Status::ErrorUnsupported();
-
-// TODO(rsleevi): Implement OAEP support according to the spec.
-
-#if defined(USE_NSS)
- // PK11_ExportDERPrivateKeyInfo isn't available. Use our fallback code.
- const SECOidTag algorithm = SEC_OID_PKCS1_RSA_ENCRYPTION;
- const int kPrivateKeyInfoVersion = 0;
-
- SECKEYPrivateKeyInfo private_key_info = {};
- RSAPrivateKey rsa_private_key = {};
- scoped_ptr<RSAPrivateKey, FreeRsaPrivateKey> free_private_key(
- &rsa_private_key);
-
- // http://crbug.com/366427: the spec does not define any other failures for
- // exporting, so none of the subsequent errors are spec compliant.
- if (!InitRSAPrivateKey(key, &rsa_private_key))
- return Status::OperationError();
-
- crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
- if (!arena.get())
- return Status::OperationError();
-
- if (!SEC_ASN1EncodeItem(arena.get(),
- &private_key_info.privateKey,
- &rsa_private_key,
- RSAPrivateKeyTemplate))
- return Status::OperationError();
-
- if (SECSuccess !=
- SECOID_SetAlgorithmID(
- arena.get(), &private_key_info.algorithm, algorithm, NULL))
- return Status::OperationError();
-
- if (!SEC_ASN1EncodeInteger(
- arena.get(), &private_key_info.version, kPrivateKeyInfoVersion))
- return Status::OperationError();
-
- crypto::ScopedSECItem encoded_key(
- SEC_ASN1EncodeItem(NULL,
- NULL,
- &private_key_info,
- SEC_ASN1_GET(SECKEY_PrivateKeyInfoTemplate)));
-#else // defined(USE_NSS)
- crypto::ScopedSECItem encoded_key(PK11_ExportDERPrivateKeyInfo(key, NULL));
-#endif // defined(USE_NSS)
-
- if (!encoded_key.get())
- return Status::OperationError();
-
- buffer->assign(encoded_key->data, encoded_key->data + encoded_key->len);
- return Status::Success();
-}
-
-Status ImportRsaPrivateKey(const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- const JwkRsaInfo& params,
- blink::WebCryptoKey* key) {
- Status status = NssSupportsRsaPrivateKeyImport();
- if (status.IsError())
- return status;
-
- CK_OBJECT_CLASS obj_class = CKO_PRIVATE_KEY;
- CK_KEY_TYPE key_type = CKK_RSA;
- CK_BBOOL ck_false = CK_FALSE;
-
- std::vector<CK_ATTRIBUTE> key_template;
-
- AddAttribute(CKA_CLASS, &obj_class, sizeof(obj_class), &key_template);
- AddAttribute(CKA_KEY_TYPE, &key_type, sizeof(key_type), &key_template);
- AddAttribute(CKA_TOKEN, &ck_false, sizeof(ck_false), &key_template);
- AddAttribute(CKA_SENSITIVE, &ck_false, sizeof(ck_false), &key_template);
- AddAttribute(CKA_PRIVATE, &ck_false, sizeof(ck_false), &key_template);
-
- // Required properties by JWA.
- AddAttribute(CKA_MODULUS, params.n, &key_template);
- AddAttribute(CKA_PUBLIC_EXPONENT, params.e, &key_template);
- AddAttribute(CKA_PRIVATE_EXPONENT, params.d, &key_template);
-
- // Manufacture a CKA_ID so the created key can be retrieved later as a
- // SECKEYPrivateKey using FindKeyByKeyID(). Unfortunately there isn't a more
- // direct way to do this in NSS.
- //
- // For consistency with other NSS key creation methods, set the CKA_ID to
- // PK11_MakeIDFromPubKey(). There are some problems with
- // this approach:
- //
- // (1) Prior to NSS 3.16.2, there is no parameter validation when creating
- // private keys. It is therefore possible to construct a key using the
- // known public modulus, and where all the other parameters are bogus.
- // FindKeyByKeyID() returns the first key matching the ID. So this would
- // effectively allow an attacker to retrieve a private key of their
- // choice.
- //
- // (2) The ID space is shared by different key types. So theoretically
- // possible to retrieve a key of the wrong type which has a matching
- // CKA_ID. In practice I am told this is not likely except for small key
- // sizes, since would require constructing keys with the same public
- // data.
- //
- // (3) FindKeyByKeyID() doesn't necessarily return the object that was just
- // created by CreateGenericObject. If the pre-existing key was
- // provisioned with flags incompatible with WebCrypto (for instance
- // marked sensitive) then this will break things.
- SECItem modulus_item = MakeSECItemForBuffer(CryptoData(params.n));
- crypto::ScopedSECItem object_id(PK11_MakeIDFromPubKey(&modulus_item));
- AddAttribute(
- CKA_ID, CryptoData(object_id->data, object_id->len), &key_template);
-
- // Optional properties by JWA, however guaranteed to be present by Chromium's
- // implementation.
- AddAttribute(CKA_PRIME_1, params.p, &key_template);
- AddAttribute(CKA_PRIME_2, params.q, &key_template);
- AddAttribute(CKA_EXPONENT_1, params.dp, &key_template);
- AddAttribute(CKA_EXPONENT_2, params.dq, &key_template);
- AddAttribute(CKA_COEFFICIENT, params.qi, &key_template);
-
- crypto::ScopedPK11Slot slot(PK11_GetInternalSlot());
-
- ScopedPK11GenericObject key_object(PK11_CreateGenericObject(
- slot.get(), &key_template[0], key_template.size(), PR_FALSE));
-
- if (!key_object)
- return Status::OperationError();
-
- crypto::ScopedSECKEYPrivateKey private_key_tmp(
- PK11_FindKeyByKeyID(slot.get(), object_id.get(), NULL));
-
- // PK11_FindKeyByKeyID() may return a handle to an existing key, rather than
- // the object created by PK11_CreateGenericObject().
- crypto::ScopedSECKEYPrivateKey private_key(
- SECKEY_CopyPrivateKey(private_key_tmp.get()));
-
- if (!private_key)
- return Status::OperationError();
-
- blink::WebCryptoKeyAlgorithm key_algorithm;
- if (!CreateRsaHashedPrivateKeyAlgorithm(
- algorithm.id(),
- algorithm.rsaHashedImportParams()->hash().id(),
- private_key.get(),
- &key_algorithm)) {
- return Status::ErrorUnexpected();
- }
-
- std::vector<uint8_t> pkcs8_data;
- status = ExportKeyPkcs8Nss(private_key.get(), &pkcs8_data);
- if (status.IsError())
- return status;
-
- scoped_ptr<PrivateKeyNss> key_handle(
- new PrivateKeyNss(private_key.Pass(), CryptoData(pkcs8_data)));
-
- *key = blink::WebCryptoKey::create(key_handle.release(),
- blink::WebCryptoKeyTypePrivate,
- extractable,
- key_algorithm,
- usages);
- return Status::Success();
-}
-
-Status ExportKeySpkiNss(SECKEYPublicKey* key, std::vector<uint8_t>* buffer) {
- const crypto::ScopedSECItem spki_der(
- SECKEY_EncodeDERSubjectPublicKeyInfo(key));
- if (!spki_der)
- return Status::OperationError();
-
- buffer->assign(spki_der->data, spki_der->data + spki_der->len);
- return Status::Success();
-}
-
-Status ImportRsaPublicKey(const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- const CryptoData& modulus_data,
- const CryptoData& exponent_data,
- blink::WebCryptoKey* key) {
- if (!modulus_data.byte_length())
- return Status::ErrorImportRsaEmptyModulus();
-
- if (!exponent_data.byte_length())
- return Status::ErrorImportRsaEmptyExponent();
-
- DCHECK(modulus_data.bytes());
- DCHECK(exponent_data.bytes());
-
- // NSS does not provide a way to create an RSA public key directly from the
- // modulus and exponent values, but it can import an DER-encoded ASN.1 blob
- // with these values and create the public key from that. The code below
- // follows the recommendation described in
- // https://developer.mozilla.org/en-US/docs/NSS/NSS_Tech_Notes/nss_tech_note7
-
- // Pack the input values into a struct compatible with NSS ASN.1 encoding, and
- // set up an ASN.1 encoder template for it.
- struct RsaPublicKeyData {
- SECItem modulus;
- SECItem exponent;
- };
- const RsaPublicKeyData pubkey_in = {
- {siUnsignedInteger, const_cast<unsigned char*>(modulus_data.bytes()),
- modulus_data.byte_length()},
- {siUnsignedInteger, const_cast<unsigned char*>(exponent_data.bytes()),
- exponent_data.byte_length()}};
- const SEC_ASN1Template rsa_public_key_template[] = {
- {SEC_ASN1_SEQUENCE, 0, NULL, sizeof(RsaPublicKeyData)},
- {
- SEC_ASN1_INTEGER, offsetof(RsaPublicKeyData, modulus),
- },
- {
- SEC_ASN1_INTEGER, offsetof(RsaPublicKeyData, exponent),
- },
- {
- 0,
- }};
-
- // DER-encode the public key.
- crypto::ScopedSECItem pubkey_der(
- SEC_ASN1EncodeItem(NULL, NULL, &pubkey_in, rsa_public_key_template));
- if (!pubkey_der)
- return Status::OperationError();
-
- // Import the DER-encoded public key to create an RSA SECKEYPublicKey.
- crypto::ScopedSECKEYPublicKey pubkey(
- SECKEY_ImportDERPublicKey(pubkey_der.get(), CKK_RSA));
- if (!pubkey)
- return Status::OperationError();
-
- blink::WebCryptoKeyAlgorithm key_algorithm;
- if (!CreateRsaHashedPublicKeyAlgorithm(
- algorithm.id(),
- algorithm.rsaHashedImportParams()->hash().id(),
- pubkey.get(),
- &key_algorithm)) {
- return Status::ErrorUnexpected();
- }
-
- std::vector<uint8_t> spki_data;
- Status status = ExportKeySpkiNss(pubkey.get(), &spki_data);
- if (status.IsError())
- return status;
-
- scoped_ptr<PublicKeyNss> key_handle(
- new PublicKeyNss(pubkey.Pass(), CryptoData(spki_data)));
-
- *key = blink::WebCryptoKey::create(key_handle.release(),
- blink::WebCryptoKeyTypePublic,
- extractable,
- key_algorithm,
- usages);
- return Status::Success();
-}
-
-} // namespace
-
-Status RsaHashedAlgorithm::GenerateKey(
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask combined_usages,
- GenerateKeyResult* result) const {
- Status status = CheckKeyCreationUsages(
- all_public_key_usages_ | all_private_key_usages_, combined_usages);
- if (status.IsError())
- return status;
-
- const blink::WebCryptoKeyUsageMask public_usages =
- combined_usages & all_public_key_usages_;
- const blink::WebCryptoKeyUsageMask private_usages =
- combined_usages & all_private_key_usages_;
-
- unsigned int public_exponent = 0;
- unsigned int modulus_length_bits = 0;
- status = GetRsaKeyGenParameters(algorithm.rsaHashedKeyGenParams(),
- &public_exponent,
- &modulus_length_bits);
- if (status.IsError())
- return status;
-
- crypto::ScopedPK11Slot slot(PK11_GetInternalKeySlot());
- if (!slot)
- return Status::OperationError();
-
- PK11RSAGenParams rsa_gen_params;
- rsa_gen_params.keySizeInBits = modulus_length_bits;
- rsa_gen_params.pe = public_exponent;
-
- const CK_FLAGS operation_flags_mask =
- CKF_ENCRYPT | CKF_DECRYPT | CKF_SIGN | CKF_VERIFY | CKF_WRAP | CKF_UNWRAP;
-
- // The private key must be marked as insensitive and extractable, otherwise it
- // cannot later be exported in unencrypted form or structured-cloned.
- const PK11AttrFlags attribute_flags =
- PK11_ATTR_INSENSITIVE | PK11_ATTR_EXTRACTABLE;
-
- // Note: NSS does not generate an sec_public_key if the call below fails,
- // so there is no danger of a leaked sec_public_key.
- SECKEYPublicKey* sec_public_key;
- crypto::ScopedSECKEYPrivateKey scoped_sec_private_key(
- PK11_GenerateKeyPairWithOpFlags(slot.get(),
- CKM_RSA_PKCS_KEY_PAIR_GEN,
- &rsa_gen_params,
- &sec_public_key,
- attribute_flags,
- generate_flags_,
- operation_flags_mask,
- NULL));
- if (!scoped_sec_private_key)
- return Status::OperationError();
-
- blink::WebCryptoKeyAlgorithm key_algorithm;
- if (!CreateRsaHashedPublicKeyAlgorithm(
- algorithm.id(),
- algorithm.rsaHashedKeyGenParams()->hash().id(),
- sec_public_key,
- &key_algorithm)) {
- return Status::ErrorUnexpected();
- }
-
- std::vector<uint8_t> spki_data;
- status = ExportKeySpkiNss(sec_public_key, &spki_data);
- if (status.IsError())
- return status;
-
- scoped_ptr<PublicKeyNss> public_key_handle(new PublicKeyNss(
- crypto::ScopedSECKEYPublicKey(sec_public_key), CryptoData(spki_data)));
-
- std::vector<uint8_t> pkcs8_data;
- status = ExportKeyPkcs8Nss(scoped_sec_private_key.get(), &pkcs8_data);
- if (status.IsError())
- return status;
-
- scoped_ptr<PrivateKeyNss> private_key_handle(
- new PrivateKeyNss(scoped_sec_private_key.Pass(), CryptoData(pkcs8_data)));
-
- blink::WebCryptoKey public_key =
- blink::WebCryptoKey::create(public_key_handle.release(),
- blink::WebCryptoKeyTypePublic,
- true,
- key_algorithm,
- public_usages);
-
- blink::WebCryptoKey private_key =
- blink::WebCryptoKey::create(private_key_handle.release(),
- blink::WebCryptoKeyTypePrivate,
- extractable,
- key_algorithm,
- private_usages);
-
- result->AssignKeyPair(public_key, private_key);
- return Status::Success();
-}
-
-Status RsaHashedAlgorithm::VerifyKeyUsagesBeforeImportKey(
- blink::WebCryptoKeyFormat format,
- blink::WebCryptoKeyUsageMask usages) const {
- switch (format) {
- case blink::WebCryptoKeyFormatSpki:
- return CheckKeyCreationUsages(all_public_key_usages_, usages);
- case blink::WebCryptoKeyFormatPkcs8:
- return CheckKeyCreationUsages(all_private_key_usages_, usages);
- case blink::WebCryptoKeyFormatJwk:
- // The JWK could represent either a public key or private key. The usages
- // must make sense for one of the two. The usages will be checked again by
- // ImportKeyJwk() once the key type has been determined.
- if (CheckKeyCreationUsages(all_private_key_usages_, usages)
- .IsSuccess() ||
- CheckKeyCreationUsages(all_public_key_usages_, usages)
- .IsSuccess()) {
- return Status::Success();
- }
- return Status::ErrorCreateKeyBadUsages();
- default:
- return Status::ErrorUnsupportedImportKeyFormat();
- }
-}
-
-Status RsaHashedAlgorithm::ImportKeyPkcs8(
- const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const {
- Status status = NssSupportsRsaPrivateKeyImport();
- if (status.IsError())
- return status;
-
- if (!key_data.byte_length())
- return Status::ErrorImportEmptyKeyData();
-
- // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 PKCS#8
- // private key info object.
- SECItem pki_der = MakeSECItemForBuffer(key_data);
-
- SECKEYPrivateKey* seckey_private_key = NULL;
- crypto::ScopedPK11Slot slot(PK11_GetInternalSlot());
- if (PK11_ImportDERPrivateKeyInfoAndReturnKey(slot.get(),
- &pki_der,
- NULL, // nickname
- NULL, // publicValue
- false, // isPerm
- false, // isPrivate
- KU_ALL, // usage
- &seckey_private_key,
- NULL) != SECSuccess) {
- return Status::DataError();
- }
- DCHECK(seckey_private_key);
- crypto::ScopedSECKEYPrivateKey private_key(seckey_private_key);
-
- const KeyType sec_key_type = SECKEY_GetPrivateKeyType(private_key.get());
- if (sec_key_type != rsaKey)
- return Status::DataError();
-
- blink::WebCryptoKeyAlgorithm key_algorithm;
- if (!CreateRsaHashedPrivateKeyAlgorithm(
- algorithm.id(),
- algorithm.rsaHashedImportParams()->hash().id(),
- private_key.get(),
- &key_algorithm)) {
- return Status::ErrorUnexpected();
- }
-
- // TODO(eroman): This is probably going to be the same as the input.
- std::vector<uint8_t> pkcs8_data;
- status = ExportKeyPkcs8Nss(private_key.get(), &pkcs8_data);
- if (status.IsError())
- return status;
-
- scoped_ptr<PrivateKeyNss> key_handle(
- new PrivateKeyNss(private_key.Pass(), CryptoData(pkcs8_data)));
-
- *key = blink::WebCryptoKey::create(key_handle.release(),
- blink::WebCryptoKeyTypePrivate,
- extractable,
- key_algorithm,
- usages);
-
- return Status::Success();
-}
-
-Status RsaHashedAlgorithm::ImportKeySpki(
- const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const {
- if (!key_data.byte_length())
- return Status::ErrorImportEmptyKeyData();
-
- // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 Subject
- // Public Key Info. Decode this to a CERTSubjectPublicKeyInfo.
- SECItem spki_item = MakeSECItemForBuffer(key_data);
- const ScopedCERTSubjectPublicKeyInfo spki(
- SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item));
- if (!spki)
- return Status::DataError();
-
- crypto::ScopedSECKEYPublicKey sec_public_key(
- SECKEY_ExtractPublicKey(spki.get()));
- if (!sec_public_key)
- return Status::DataError();
-
- const KeyType sec_key_type = SECKEY_GetPublicKeyType(sec_public_key.get());
- if (sec_key_type != rsaKey)
- return Status::DataError();
-
- blink::WebCryptoKeyAlgorithm key_algorithm;
- if (!CreateRsaHashedPublicKeyAlgorithm(
- algorithm.id(),
- algorithm.rsaHashedImportParams()->hash().id(),
- sec_public_key.get(),
- &key_algorithm)) {
- return Status::ErrorUnexpected();
- }
-
- // TODO(eroman): This is probably going to be the same as the input.
- std::vector<uint8_t> spki_data;
- Status status = ExportKeySpkiNss(sec_public_key.get(), &spki_data);
- if (status.IsError())
- return status;
-
- scoped_ptr<PublicKeyNss> key_handle(
- new PublicKeyNss(sec_public_key.Pass(), CryptoData(spki_data)));
-
- *key = blink::WebCryptoKey::create(key_handle.release(),
- blink::WebCryptoKeyTypePublic,
- extractable,
- key_algorithm,
- usages);
-
- return Status::Success();
-}
-
-Status RsaHashedAlgorithm::ExportKeyPkcs8(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const {
- if (key.type() != blink::WebCryptoKeyTypePrivate)
- return Status::ErrorUnexpectedKeyType();
- *buffer = PrivateKeyNss::Cast(key)->pkcs8_data();
- return Status::Success();
-}
-
-Status RsaHashedAlgorithm::ExportKeySpki(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const {
- if (key.type() != blink::WebCryptoKeyTypePublic)
- return Status::ErrorUnexpectedKeyType();
- *buffer = PublicKeyNss::Cast(key)->spki_data();
- return Status::Success();
-}
-
-Status RsaHashedAlgorithm::ImportKeyJwk(
- const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const {
- const char* jwk_algorithm =
- GetJwkAlgorithm(algorithm.rsaHashedImportParams()->hash().id());
-
- if (!jwk_algorithm)
- return Status::ErrorUnexpected();
-
- JwkRsaInfo jwk;
- Status status =
- ReadRsaKeyJwk(key_data, jwk_algorithm, extractable, usages, &jwk);
- if (status.IsError())
- return status;
-
- // Once the key type is known, verify the usages.
- status = CheckKeyCreationUsages(
- jwk.is_private_key ? all_private_key_usages_ : all_public_key_usages_,
- usages);
- if (status.IsError())
- return Status::ErrorCreateKeyBadUsages();
-
- return jwk.is_private_key
- ? ImportRsaPrivateKey(algorithm, extractable, usages, jwk, key)
- : ImportRsaPublicKey(algorithm,
- extractable,
- usages,
- CryptoData(jwk.n),
- CryptoData(jwk.e),
- key);
-}
-
-Status RsaHashedAlgorithm::ExportKeyJwk(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const {
- const char* jwk_algorithm =
- GetJwkAlgorithm(key.algorithm().rsaHashedParams()->hash().id());
-
- if (!jwk_algorithm)
- return Status::ErrorUnexpected();
-
- switch (key.type()) {
- case blink::WebCryptoKeyTypePublic: {
- SECKEYPublicKey* nss_key = PublicKeyNss::Cast(key)->key();
- if (nss_key->keyType != rsaKey)
- return Status::ErrorUnsupported();
-
- WriteRsaPublicKeyJwk(SECItemToCryptoData(nss_key->u.rsa.modulus),
- SECItemToCryptoData(nss_key->u.rsa.publicExponent),
- jwk_algorithm,
- key.extractable(),
- key.usages(),
- buffer);
-
- return Status::Success();
- }
-
- case blink::WebCryptoKeyTypePrivate: {
- SECKEYPrivateKey* nss_key = PrivateKeyNss::Cast(key)->key();
- RSAPrivateKey key_props = {};
- scoped_ptr<RSAPrivateKey, FreeRsaPrivateKey> free_private_key(&key_props);
-
- if (!InitRSAPrivateKey(nss_key, &key_props))
- return Status::OperationError();
-
- WriteRsaPrivateKeyJwk(SECItemToCryptoData(key_props.modulus),
- SECItemToCryptoData(key_props.public_exponent),
- SECItemToCryptoData(key_props.private_exponent),
- SECItemToCryptoData(key_props.prime1),
- SECItemToCryptoData(key_props.prime2),
- SECItemToCryptoData(key_props.exponent1),
- SECItemToCryptoData(key_props.exponent2),
- SECItemToCryptoData(key_props.coefficient),
- jwk_algorithm,
- key.extractable(),
- key.usages(),
- buffer);
-
- return Status::Success();
- }
- default:
- return Status::ErrorUnexpected();
- }
-}
-
-} // namespace webcrypto
-
-} // namespace content
diff --git a/chromium/content/child/webcrypto/nss/rsa_key_nss.h b/chromium/content/child/webcrypto/nss/rsa_key_nss.h
deleted file mode 100644
index 725a25e837b..00000000000
--- a/chromium/content/child/webcrypto/nss/rsa_key_nss.h
+++ /dev/null
@@ -1,92 +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_CHILD_WEBCRYPTO_NSS_RSA_KEY_NSS_H_
-#define CONTENT_CHILD_WEBCRYPTO_NSS_RSA_KEY_NSS_H_
-
-#include <pkcs11t.h>
-
-#include "content/child/webcrypto/algorithm_implementation.h"
-
-namespace content {
-
-namespace webcrypto {
-
-class PublicKeyNss;
-class PrivateKeyNss;
-
-// Base class for an RSA algorithm whose keys additionaly have a hash parameter
-// bound to them. Provides functionality for generating, importing, and
-// exporting keys.
-class RsaHashedAlgorithm : public AlgorithmImplementation {
- public:
- // Constructs an RSA algorithm which will use the NSS flags |generate_flags|
- // when generating keys. |all_public_key_usages| and |all_private_key_usages|
- // are the set of WebCrypto key usages that are valid for created keys
- // (public and private respectively).
- //
- // For instance if public keys support encryption and wrapping, and private
- // keys support decryption and unwrapping callers should set:
- // all_public_key_usages = UsageEncrypt | UsageWrap
- // all_private_key_usages = UsageDecrypt | UsageUnwrap
- // This information is used when importing or generating keys, to enforce
- // that valid key usages are allowed.
- RsaHashedAlgorithm(CK_FLAGS generate_flags,
- blink::WebCryptoKeyUsageMask all_public_key_usages,
- blink::WebCryptoKeyUsageMask all_private_key_usages)
- : generate_flags_(generate_flags),
- all_public_key_usages_(all_public_key_usages),
- all_private_key_usages_(all_private_key_usages) {}
-
- // For instance "RSA-OAEP-256".
- virtual const char* GetJwkAlgorithm(
- const blink::WebCryptoAlgorithmId hash) const = 0;
-
- Status GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- GenerateKeyResult* result) const override;
-
- Status VerifyKeyUsagesBeforeImportKey(
- blink::WebCryptoKeyFormat format,
- blink::WebCryptoKeyUsageMask usages) const override;
-
- Status ImportKeyPkcs8(const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const override;
-
- Status ImportKeySpki(const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const override;
-
- Status ExportKeyPkcs8(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const override;
-
- Status ExportKeySpki(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const override;
-
- Status ImportKeyJwk(const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const override;
-
- Status ExportKeyJwk(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const override;
-
- private:
- CK_FLAGS generate_flags_;
- blink::WebCryptoKeyUsageMask all_public_key_usages_;
- blink::WebCryptoKeyUsageMask all_private_key_usages_;
-};
-
-} // namespace webcrypto
-
-} // namespace content
-
-#endif // CONTENT_CHILD_WEBCRYPTO_NSS_RSA_KEY_NSS_H_
diff --git a/chromium/content/child/webcrypto/nss/rsa_oaep_nss.cc b/chromium/content/child/webcrypto/nss/rsa_oaep_nss.cc
deleted file mode 100644
index f7484f6503a..00000000000
--- a/chromium/content/child/webcrypto/nss/rsa_oaep_nss.cc
+++ /dev/null
@@ -1,246 +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 <cryptohi.h>
-#include <keyhi.h>
-#include <pk11pub.h>
-#include <secerr.h>
-#include <sechash.h>
-
-#include "base/stl_util.h"
-#include "content/child/webcrypto/crypto_data.h"
-#include "content/child/webcrypto/nss/key_nss.h"
-#include "content/child/webcrypto/nss/rsa_key_nss.h"
-#include "content/child/webcrypto/nss/util_nss.h"
-#include "content/child/webcrypto/status.h"
-#include "content/child/webcrypto/webcrypto_util.h"
-#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
-#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
-
-namespace content {
-
-namespace webcrypto {
-
-namespace {
-
-Status NssSupportsRsaOaep() {
- if (NssRuntimeSupport::Get()->IsRsaOaepSupported())
- return Status::Success();
- return Status::ErrorUnsupported(
- "NSS version doesn't support RSA-OAEP. Try using version 3.16.2 or "
- "later");
-}
-
-CK_MECHANISM_TYPE WebCryptoHashToMGFMechanism(
- const blink::WebCryptoAlgorithm& algorithm) {
- switch (algorithm.id()) {
- case blink::WebCryptoAlgorithmIdSha1:
- return CKG_MGF1_SHA1;
- case blink::WebCryptoAlgorithmIdSha256:
- return CKG_MGF1_SHA256;
- case blink::WebCryptoAlgorithmIdSha384:
- return CKG_MGF1_SHA384;
- case blink::WebCryptoAlgorithmIdSha512:
- return CKG_MGF1_SHA512;
- default:
- return CKM_INVALID_MECHANISM;
- }
-}
-
-CK_MECHANISM_TYPE WebCryptoHashToDigestMechanism(
- const blink::WebCryptoAlgorithm& algorithm) {
- switch (algorithm.id()) {
- case blink::WebCryptoAlgorithmIdSha1:
- return CKM_SHA_1;
- case blink::WebCryptoAlgorithmIdSha256:
- return CKM_SHA256;
- case blink::WebCryptoAlgorithmIdSha384:
- return CKM_SHA384;
- case blink::WebCryptoAlgorithmIdSha512:
- return CKM_SHA512;
- default:
- // Not a supported algorithm.
- return CKM_INVALID_MECHANISM;
- }
-}
-
-bool InitializeRsaOaepParams(const blink::WebCryptoAlgorithm& hash,
- const CryptoData& label,
- CK_RSA_PKCS_OAEP_PARAMS* oaep_params) {
- oaep_params->source = CKZ_DATA_SPECIFIED;
- oaep_params->pSourceData = const_cast<unsigned char*>(label.bytes());
- oaep_params->ulSourceDataLen = label.byte_length();
- oaep_params->mgf = WebCryptoHashToMGFMechanism(hash);
- oaep_params->hashAlg = WebCryptoHashToDigestMechanism(hash);
-
- if (oaep_params->mgf == CKM_INVALID_MECHANISM ||
- oaep_params->hashAlg == CKM_INVALID_MECHANISM) {
- return false;
- }
-
- return true;
-}
-
-Status EncryptRsaOaep(SECKEYPublicKey* key,
- const blink::WebCryptoAlgorithm& hash,
- const CryptoData& label,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) {
- CK_RSA_PKCS_OAEP_PARAMS oaep_params = {0};
- if (!InitializeRsaOaepParams(hash, label, &oaep_params))
- return Status::ErrorUnsupported();
-
- SECItem param;
- param.type = siBuffer;
- param.data = reinterpret_cast<unsigned char*>(&oaep_params);
- param.len = sizeof(oaep_params);
-
- buffer->resize(SECKEY_PublicKeyStrength(key));
- unsigned char* buffer_data = vector_as_array(buffer);
- unsigned int output_len;
- if (NssRuntimeSupport::Get()->pk11_pub_encrypt_func()(key,
- CKM_RSA_PKCS_OAEP,
- &param,
- buffer_data,
- &output_len,
- buffer->size(),
- data.bytes(),
- data.byte_length(),
- NULL) != SECSuccess) {
- return Status::OperationError();
- }
-
- CHECK_LE(output_len, buffer->size());
- buffer->resize(output_len);
- return Status::Success();
-}
-
-Status DecryptRsaOaep(SECKEYPrivateKey* key,
- const blink::WebCryptoAlgorithm& hash,
- const CryptoData& label,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) {
- Status status = NssSupportsRsaOaep();
- if (status.IsError())
- return status;
-
- CK_RSA_PKCS_OAEP_PARAMS oaep_params = {0};
- if (!InitializeRsaOaepParams(hash, label, &oaep_params))
- return Status::ErrorUnsupported();
-
- SECItem param;
- param.type = siBuffer;
- param.data = reinterpret_cast<unsigned char*>(&oaep_params);
- param.len = sizeof(oaep_params);
-
- const int modulus_length_bytes = PK11_GetPrivateModulusLen(key);
- if (modulus_length_bytes <= 0)
- return Status::ErrorUnexpected();
-
- buffer->resize(modulus_length_bytes);
-
- unsigned char* buffer_data = vector_as_array(buffer);
- unsigned int output_len;
- if (NssRuntimeSupport::Get()->pk11_priv_decrypt_func()(key,
- CKM_RSA_PKCS_OAEP,
- &param,
- buffer_data,
- &output_len,
- buffer->size(),
- data.bytes(),
- data.byte_length()) !=
- SECSuccess) {
- return Status::OperationError();
- }
-
- CHECK_LE(output_len, buffer->size());
- buffer->resize(output_len);
- return Status::Success();
-}
-
-class RsaOaepImplementation : public RsaHashedAlgorithm {
- public:
- RsaOaepImplementation()
- : RsaHashedAlgorithm(
- CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP,
- blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageWrapKey,
- blink::WebCryptoKeyUsageDecrypt |
- blink::WebCryptoKeyUsageUnwrapKey) {}
-
- Status GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- GenerateKeyResult* result) const override {
- Status status = NssSupportsRsaOaep();
- if (status.IsError())
- return status;
- return RsaHashedAlgorithm::GenerateKey(
- algorithm, extractable, usages, result);
- }
-
- Status VerifyKeyUsagesBeforeImportKey(
- blink::WebCryptoKeyFormat format,
- blink::WebCryptoKeyUsageMask usages) const override {
- Status status = NssSupportsRsaOaep();
- if (status.IsError())
- return status;
- return RsaHashedAlgorithm::VerifyKeyUsagesBeforeImportKey(format, usages);
- }
-
- const char* GetJwkAlgorithm(
- const blink::WebCryptoAlgorithmId hash) const override {
- switch (hash) {
- case blink::WebCryptoAlgorithmIdSha1:
- return "RSA-OAEP";
- case blink::WebCryptoAlgorithmIdSha256:
- return "RSA-OAEP-256";
- case blink::WebCryptoAlgorithmIdSha384:
- return "RSA-OAEP-384";
- case blink::WebCryptoAlgorithmIdSha512:
- return "RSA-OAEP-512";
- default:
- return NULL;
- }
- }
-
- Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const override {
- if (key.type() != blink::WebCryptoKeyTypePublic)
- return Status::ErrorUnexpectedKeyType();
-
- return EncryptRsaOaep(
- PublicKeyNss::Cast(key)->key(),
- key.algorithm().rsaHashedParams()->hash(),
- CryptoData(algorithm.rsaOaepParams()->optionalLabel()),
- data,
- buffer);
- }
-
- Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const override {
- if (key.type() != blink::WebCryptoKeyTypePrivate)
- return Status::ErrorUnexpectedKeyType();
-
- return DecryptRsaOaep(
- PrivateKeyNss::Cast(key)->key(),
- key.algorithm().rsaHashedParams()->hash(),
- CryptoData(algorithm.rsaOaepParams()->optionalLabel()),
- data,
- buffer);
- }
-};
-
-} // namespace
-
-AlgorithmImplementation* CreatePlatformRsaOaepImplementation() {
- return new RsaOaepImplementation;
-}
-
-} // namespace webcrypto
-
-} // namespace content
diff --git a/chromium/content/child/webcrypto/nss/rsa_ssa_nss.cc b/chromium/content/child/webcrypto/nss/rsa_ssa_nss.cc
deleted file mode 100644
index 471aaedb4b3..00000000000
--- a/chromium/content/child/webcrypto/nss/rsa_ssa_nss.cc
+++ /dev/null
@@ -1,144 +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 <cryptohi.h>
-
-#include "content/child/webcrypto/crypto_data.h"
-#include "content/child/webcrypto/nss/key_nss.h"
-#include "content/child/webcrypto/nss/rsa_key_nss.h"
-#include "content/child/webcrypto/nss/util_nss.h"
-#include "content/child/webcrypto/status.h"
-#include "crypto/scoped_nss_types.h"
-#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
-
-namespace content {
-
-namespace webcrypto {
-
-namespace {
-
-class RsaSsaImplementation : public RsaHashedAlgorithm {
- public:
- RsaSsaImplementation()
- : RsaHashedAlgorithm(CKF_SIGN | CKF_VERIFY,
- blink::WebCryptoKeyUsageVerify,
- blink::WebCryptoKeyUsageSign) {}
-
- const char* GetJwkAlgorithm(
- const blink::WebCryptoAlgorithmId hash) const override {
- switch (hash) {
- case blink::WebCryptoAlgorithmIdSha1:
- return "RS1";
- case blink::WebCryptoAlgorithmIdSha256:
- return "RS256";
- case blink::WebCryptoAlgorithmIdSha384:
- return "RS384";
- case blink::WebCryptoAlgorithmIdSha512:
- return "RS512";
- default:
- return NULL;
- }
- }
-
- Status Sign(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const override {
- if (key.type() != blink::WebCryptoKeyTypePrivate)
- return Status::ErrorUnexpectedKeyType();
-
- SECKEYPrivateKey* private_key = PrivateKeyNss::Cast(key)->key();
-
- const blink::WebCryptoAlgorithm& hash =
- key.algorithm().rsaHashedParams()->hash();
-
- // Pick the NSS signing algorithm by combining RSA-SSA (RSA PKCS1) and the
- // inner hash of the input Web Crypto algorithm.
- SECOidTag sign_alg_tag;
- switch (hash.id()) {
- case blink::WebCryptoAlgorithmIdSha1:
- sign_alg_tag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
- break;
- case blink::WebCryptoAlgorithmIdSha256:
- sign_alg_tag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION;
- break;
- case blink::WebCryptoAlgorithmIdSha384:
- sign_alg_tag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION;
- break;
- case blink::WebCryptoAlgorithmIdSha512:
- sign_alg_tag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION;
- break;
- default:
- return Status::ErrorUnsupported();
- }
-
- crypto::ScopedSECItem signature_item(SECITEM_AllocItem(NULL, NULL, 0));
- if (SEC_SignData(signature_item.get(),
- data.bytes(),
- data.byte_length(),
- private_key,
- sign_alg_tag) != SECSuccess) {
- return Status::OperationError();
- }
-
- buffer->assign(signature_item->data,
- signature_item->data + signature_item->len);
- return Status::Success();
- }
-
- Status Verify(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& signature,
- const CryptoData& data,
- bool* signature_match) const override {
- if (key.type() != blink::WebCryptoKeyTypePublic)
- return Status::ErrorUnexpectedKeyType();
-
- SECKEYPublicKey* public_key = PublicKeyNss::Cast(key)->key();
-
- const blink::WebCryptoAlgorithm& hash =
- key.algorithm().rsaHashedParams()->hash();
-
- const SECItem signature_item = MakeSECItemForBuffer(signature);
-
- SECOidTag hash_alg_tag;
- switch (hash.id()) {
- case blink::WebCryptoAlgorithmIdSha1:
- hash_alg_tag = SEC_OID_SHA1;
- break;
- case blink::WebCryptoAlgorithmIdSha256:
- hash_alg_tag = SEC_OID_SHA256;
- break;
- case blink::WebCryptoAlgorithmIdSha384:
- hash_alg_tag = SEC_OID_SHA384;
- break;
- case blink::WebCryptoAlgorithmIdSha512:
- hash_alg_tag = SEC_OID_SHA512;
- break;
- default:
- return Status::ErrorUnsupported();
- }
-
- *signature_match =
- SECSuccess == VFY_VerifyDataDirect(data.bytes(),
- data.byte_length(),
- public_key,
- &signature_item,
- SEC_OID_PKCS1_RSA_ENCRYPTION,
- hash_alg_tag,
- NULL,
- NULL);
- return Status::Success();
- }
-};
-
-} // namespace
-
-AlgorithmImplementation* CreatePlatformRsaSsaImplementation() {
- return new RsaSsaImplementation;
-}
-
-} // namespace webcrypto
-
-} // namespace content
diff --git a/chromium/content/child/webcrypto/nss/sha_nss.cc b/chromium/content/child/webcrypto/nss/sha_nss.cc
deleted file mode 100644
index 78a2ea04114..00000000000
--- a/chromium/content/child/webcrypto/nss/sha_nss.cc
+++ /dev/null
@@ -1,160 +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 <sechash.h>
-#include <vector>
-
-#include "base/stl_util.h"
-#include "content/child/webcrypto/algorithm_implementation.h"
-#include "content/child/webcrypto/crypto_data.h"
-#include "content/child/webcrypto/nss/util_nss.h"
-#include "content/child/webcrypto/status.h"
-#include "content/child/webcrypto/webcrypto_util.h"
-#include "crypto/nss_util.h"
-#include "crypto/scoped_nss_types.h"
-
-namespace content {
-
-namespace webcrypto {
-
-namespace {
-
-HASH_HashType WebCryptoAlgorithmToNSSHashType(
- blink::WebCryptoAlgorithmId algorithm) {
- switch (algorithm) {
- case blink::WebCryptoAlgorithmIdSha1:
- return HASH_AlgSHA1;
- case blink::WebCryptoAlgorithmIdSha256:
- return HASH_AlgSHA256;
- case blink::WebCryptoAlgorithmIdSha384:
- return HASH_AlgSHA384;
- case blink::WebCryptoAlgorithmIdSha512:
- return HASH_AlgSHA512;
- default:
- // Not a digest algorithm.
- return HASH_AlgNULL;
- }
-}
-
-// Implementation of blink::WebCryptoDigester, an internal Blink detail not
-// part of WebCrypto, that allows chunks of data to be streamed in before
-// computing a SHA-* digest (as opposed to ShaImplementation, which computes
-// digests over complete messages)
-class DigestorNSS : public blink::WebCryptoDigestor {
- public:
- explicit DigestorNSS(blink::WebCryptoAlgorithmId algorithm_id)
- : hash_context_(NULL), algorithm_id_(algorithm_id) {}
-
- ~DigestorNSS() override {
- if (!hash_context_)
- return;
-
- HASH_Destroy(hash_context_);
- hash_context_ = NULL;
- }
-
- bool consume(const unsigned char* data, unsigned int size) override {
- return ConsumeWithStatus(data, size).IsSuccess();
- }
-
- Status ConsumeWithStatus(const unsigned char* data, unsigned int size) {
- // Initialize everything if the object hasn't been initialized yet.
- if (!hash_context_) {
- Status error = Init();
- if (!error.IsSuccess())
- return error;
- }
-
- HASH_Update(hash_context_, data, size);
-
- return Status::Success();
- }
-
- bool finish(unsigned char*& result_data,
- unsigned int& result_data_size) override {
- Status error = FinishInternal(result_, &result_data_size);
- if (!error.IsSuccess())
- return false;
- result_data = result_;
- return true;
- }
-
- Status FinishWithVectorAndStatus(std::vector<uint8_t>* result) {
- if (!hash_context_)
- return Status::ErrorUnexpected();
-
- unsigned int result_length = HASH_ResultLenContext(hash_context_);
- result->resize(result_length);
- unsigned char* digest = vector_as_array(result);
- unsigned int digest_size; // ignored
- return FinishInternal(digest, &digest_size);
- }
-
- private:
- Status Init() {
- HASH_HashType hash_type = WebCryptoAlgorithmToNSSHashType(algorithm_id_);
-
- if (hash_type == HASH_AlgNULL)
- return Status::ErrorUnsupported();
-
- hash_context_ = HASH_Create(hash_type);
- if (!hash_context_)
- return Status::OperationError();
-
- HASH_Begin(hash_context_);
-
- return Status::Success();
- }
-
- Status FinishInternal(unsigned char* result, unsigned int* result_size) {
- if (!hash_context_) {
- Status error = Init();
- if (!error.IsSuccess())
- return error;
- }
-
- unsigned int hash_result_length = HASH_ResultLenContext(hash_context_);
- DCHECK_LE(hash_result_length, static_cast<size_t>(HASH_LENGTH_MAX));
-
- HASH_End(hash_context_, result, result_size, hash_result_length);
-
- if (*result_size != hash_result_length)
- return Status::ErrorUnexpected();
- return Status::Success();
- }
-
- HASHContext* hash_context_;
- blink::WebCryptoAlgorithmId algorithm_id_;
- unsigned char result_[HASH_LENGTH_MAX];
-};
-
-class ShaImplementation : public AlgorithmImplementation {
- public:
- Status Digest(const blink::WebCryptoAlgorithm& algorithm,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const override {
- DigestorNSS digestor(algorithm.id());
- Status error = digestor.ConsumeWithStatus(data.bytes(), data.byte_length());
- // http://crbug.com/366427: the spec does not define any other failures for
- // digest, so none of the subsequent errors are spec compliant.
- if (!error.IsSuccess())
- return error;
- return digestor.FinishWithVectorAndStatus(buffer);
- }
-};
-
-} // namespace
-
-AlgorithmImplementation* CreatePlatformShaImplementation() {
- return new ShaImplementation();
-}
-
-scoped_ptr<blink::WebCryptoDigestor> CreatePlatformDigestor(
- blink::WebCryptoAlgorithmId algorithm) {
- return scoped_ptr<blink::WebCryptoDigestor>(new DigestorNSS(algorithm));
-}
-
-} // namespace webcrypto
-
-} // namespace content
diff --git a/chromium/content/child/webcrypto/nss/sym_key_nss.cc b/chromium/content/child/webcrypto/nss/sym_key_nss.cc
deleted file mode 100644
index 5066d5d91d2..00000000000
--- a/chromium/content/child/webcrypto/nss/sym_key_nss.cc
+++ /dev/null
@@ -1,94 +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/child/webcrypto/nss/sym_key_nss.h"
-
-#include "base/logging.h"
-#include "content/child/webcrypto/crypto_data.h"
-#include "content/child/webcrypto/generate_key_result.h"
-#include "content/child/webcrypto/nss/key_nss.h"
-#include "content/child/webcrypto/nss/util_nss.h"
-#include "content/child/webcrypto/status.h"
-#include "content/child/webcrypto/webcrypto_util.h"
-#include "crypto/scoped_nss_types.h"
-#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
-
-namespace content {
-
-namespace webcrypto {
-
-Status GenerateSecretKeyNss(const blink::WebCryptoKeyAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- unsigned keylen_bytes,
- CK_MECHANISM_TYPE mechanism,
- GenerateKeyResult* result) {
- DCHECK_NE(CKM_INVALID_MECHANISM, mechanism);
-
- crypto::ScopedPK11Slot slot(PK11_GetInternalKeySlot());
- if (!slot)
- return Status::OperationError();
-
- crypto::ScopedPK11SymKey pk11_key(
- PK11_KeyGen(slot.get(), mechanism, NULL, keylen_bytes, NULL));
-
- if (!pk11_key)
- return Status::OperationError();
-
- if (PK11_ExtractKeyValue(pk11_key.get()) != SECSuccess)
- return Status::OperationError();
-
- const SECItem* key_data = PK11_GetKeyData(pk11_key.get());
- if (!key_data)
- return Status::OperationError();
-
- scoped_ptr<SymKeyNss> handle(new SymKeyNss(
- pk11_key.Pass(), CryptoData(key_data->data, key_data->len)));
-
- result->AssignSecretKey(
- blink::WebCryptoKey::create(handle.release(),
- blink::WebCryptoKeyTypeSecret,
- extractable,
- algorithm,
- usages));
-
- return Status::Success();
-}
-
-Status ImportKeyRawNss(const CryptoData& key_data,
- const blink::WebCryptoKeyAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- CK_MECHANISM_TYPE mechanism,
- CK_FLAGS flags,
- blink::WebCryptoKey* key) {
- DCHECK(!algorithm.isNull());
- SECItem key_item = MakeSECItemForBuffer(key_data);
-
- crypto::ScopedPK11Slot slot(PK11_GetInternalSlot());
- crypto::ScopedPK11SymKey pk11_sym_key(
- PK11_ImportSymKeyWithFlags(slot.get(),
- mechanism,
- PK11_OriginUnwrap,
- CKA_FLAGS_ONLY,
- &key_item,
- flags,
- false,
- NULL));
- if (!pk11_sym_key.get())
- return Status::OperationError();
-
- scoped_ptr<SymKeyNss> handle(new SymKeyNss(pk11_sym_key.Pass(), key_data));
-
- *key = blink::WebCryptoKey::create(handle.release(),
- blink::WebCryptoKeyTypeSecret,
- extractable,
- algorithm,
- usages);
- return Status::Success();
-}
-
-} // namespace webcrypto
-
-} // namespace content
diff --git a/chromium/content/child/webcrypto/nss/sym_key_nss.h b/chromium/content/child/webcrypto/nss/sym_key_nss.h
deleted file mode 100644
index 7f1e067ac1d..00000000000
--- a/chromium/content/child/webcrypto/nss/sym_key_nss.h
+++ /dev/null
@@ -1,39 +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_CHILD_WEBCRYPTO_NSS_SYM_KEY_NSS_H_
-#define CONTENT_CHILD_WEBCRYPTO_NSS_SYM_KEY_NSS_H_
-
-#include <pkcs11t.h>
-
-#include "third_party/WebKit/public/platform/WebCrypto.h"
-
-namespace content {
-
-namespace webcrypto {
-
-class CryptoData;
-class GenerateKeyResult;
-class Status;
-
-Status GenerateSecretKeyNss(const blink::WebCryptoKeyAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- unsigned keylen_bytes,
- CK_MECHANISM_TYPE mechanism,
- GenerateKeyResult* result);
-
-Status ImportKeyRawNss(const CryptoData& key_data,
- const blink::WebCryptoKeyAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- CK_MECHANISM_TYPE mechanism,
- CK_FLAGS flags,
- blink::WebCryptoKey* key);
-
-} // namespace webcrypto
-
-} // namespace content
-
-#endif // CONTENT_CHILD_WEBCRYPTO_NSS_SYM_KEY_NSS_H_
diff --git a/chromium/content/child/webcrypto/nss/util_nss.cc b/chromium/content/child/webcrypto/nss/util_nss.cc
deleted file mode 100644
index 58201cb47dc..00000000000
--- a/chromium/content/child/webcrypto/nss/util_nss.cc
+++ /dev/null
@@ -1,95 +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/child/webcrypto/nss/util_nss.h"
-
-#include "base/lazy_instance.h"
-#include "content/child/webcrypto/crypto_data.h"
-#include "content/child/webcrypto/platform_crypto.h"
-#include "crypto/nss_util.h"
-#include "crypto/scoped_nss_types.h"
-
-#if defined(USE_NSS)
-#include <dlfcn.h>
-#include <secoid.h>
-#endif
-
-namespace content {
-
-namespace webcrypto {
-
-namespace {
-base::LazyInstance<NssRuntimeSupport>::Leaky g_nss_runtime_support =
- LAZY_INSTANCE_INITIALIZER;
-} // namespace
-
-// Creates a SECItem for the data in |buffer|. This does NOT make a copy, so
-// |buffer| should outlive the SECItem.
-SECItem MakeSECItemForBuffer(const CryptoData& buffer) {
- SECItem item = {
- siBuffer,
- // NSS requires non-const data even though it is just for input.
- const_cast<unsigned char*>(buffer.bytes()), buffer.byte_length()};
- return item;
-}
-
-CryptoData SECItemToCryptoData(const SECItem& item) {
- return CryptoData(item.data, item.len);
-}
-
-NssRuntimeSupport* NssRuntimeSupport::Get() {
- return &g_nss_runtime_support.Get();
-}
-
-NssRuntimeSupport::NssRuntimeSupport() : internal_slot_does_oaep_(false) {
-#if !defined(USE_NSS)
- // Using a bundled version of NSS that is guaranteed to have this symbol.
- pk11_encrypt_func_ = PK11_Encrypt;
- pk11_decrypt_func_ = PK11_Decrypt;
- pk11_pub_encrypt_func_ = PK11_PubEncrypt;
- pk11_priv_decrypt_func_ = PK11_PrivDecrypt;
- internal_slot_does_oaep_ = true;
-#else
- // Using system NSS libraries and PCKS #11 modules, which may not have the
- // necessary function (PK11_Encrypt) or mechanism support (CKM_AES_GCM).
-
- // If PK11_Encrypt() was successfully resolved, then NSS will support
- // AES-GCM directly. This was introduced in NSS 3.15.
- pk11_encrypt_func_ = reinterpret_cast<PK11_EncryptDecryptFunction>(
- dlsym(RTLD_DEFAULT, "PK11_Encrypt"));
- pk11_decrypt_func_ = reinterpret_cast<PK11_EncryptDecryptFunction>(
- dlsym(RTLD_DEFAULT, "PK11_Decrypt"));
-
- // Even though NSS's pk11wrap layer may support
- // PK11_PubEncrypt/PK11_PubDecrypt (introduced in NSS 3.16.2), it may have
- // loaded a softoken that does not include OAEP support.
- pk11_pub_encrypt_func_ = reinterpret_cast<PK11_PubEncryptFunction>(
- dlsym(RTLD_DEFAULT, "PK11_PubEncrypt"));
- pk11_priv_decrypt_func_ = reinterpret_cast<PK11_PrivDecryptFunction>(
- dlsym(RTLD_DEFAULT, "PK11_PrivDecrypt"));
- if (pk11_priv_decrypt_func_ && pk11_pub_encrypt_func_) {
- crypto::ScopedPK11Slot slot(PK11_GetInternalKeySlot());
- internal_slot_does_oaep_ =
- !!PK11_DoesMechanism(slot.get(), CKM_RSA_PKCS_OAEP);
- }
-#endif
-}
-
-void PlatformInit() {
- crypto::EnsureNSSInit();
-}
-
-AlgorithmImplementation* CreatePlatformAesCtrImplementation() {
- // TODO(eroman): http://crbug.com/399084
- return NULL;
-}
-
-AlgorithmImplementation* CreatePlatformRsaPssImplementation() {
- // TODO(eroman): http://crbug.com/399090
- return NULL;
-}
-
-} // namespace webcrypto
-
-} // namespace content
diff --git a/chromium/content/child/webcrypto/nss/util_nss.h b/chromium/content/child/webcrypto/nss/util_nss.h
deleted file mode 100644
index 0b50178be8a..00000000000
--- a/chromium/content/child/webcrypto/nss/util_nss.h
+++ /dev/null
@@ -1,113 +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_CHILD_WEBCRYPTO_NSS_UTIL_NSS_H_
-#define CONTENT_CHILD_WEBCRYPTO_NSS_UTIL_NSS_H_
-
-#include <keythi.h>
-#include <pkcs11t.h>
-#include <seccomon.h>
-#include <secmodt.h>
-
-#include "base/lazy_instance.h"
-
-namespace content {
-
-namespace webcrypto {
-
-class CryptoData;
-
-SECItem MakeSECItemForBuffer(const CryptoData& buffer);
-enum EncryptOrDecrypt { ENCRYPT, DECRYPT };
-
-CryptoData SECItemToCryptoData(const SECItem& item);
-
-// Signature for PK11_Encrypt and PK11_Decrypt.
-typedef SECStatus (*PK11_EncryptDecryptFunction)(PK11SymKey*,
- CK_MECHANISM_TYPE,
- SECItem*,
- unsigned char*,
- unsigned int*,
- unsigned int,
- const unsigned char*,
- unsigned int);
-
-// Signature for PK11_PubEncrypt
-typedef SECStatus (*PK11_PubEncryptFunction)(SECKEYPublicKey*,
- CK_MECHANISM_TYPE,
- SECItem*,
- unsigned char*,
- unsigned int*,
- unsigned int,
- const unsigned char*,
- unsigned int,
- void*);
-
-// Signature for PK11_PrivDecrypt
-typedef SECStatus (*PK11_PrivDecryptFunction)(SECKEYPrivateKey*,
- CK_MECHANISM_TYPE,
- SECItem*,
- unsigned char*,
- unsigned int*,
- unsigned int,
- const unsigned char*,
- unsigned int);
-
-// Singleton that detects whether or not AES-GCM and
-// RSA-OAEP are supported by the version of NSS being used.
-// On non-Linux platforms, Chromium embedders ship with a
-// fixed version of NSS, and these are always available.
-// However, on Linux (and ChromeOS), NSS is provided by the
-// system, and thus not all algorithms may be available
-// or be safe to use.
-class NssRuntimeSupport {
- public:
- bool IsAesGcmSupported() const {
- return pk11_encrypt_func_ && pk11_decrypt_func_;
- }
-
- bool IsRsaOaepSupported() const {
- return pk11_pub_encrypt_func_ && pk11_priv_decrypt_func_ &&
- internal_slot_does_oaep_;
- }
-
- // Returns NULL if unsupported.
- PK11_EncryptDecryptFunction pk11_encrypt_func() const {
- return pk11_encrypt_func_;
- }
-
- // Returns NULL if unsupported.
- PK11_EncryptDecryptFunction pk11_decrypt_func() const {
- return pk11_decrypt_func_;
- }
-
- // Returns NULL if unsupported.
- PK11_PubEncryptFunction pk11_pub_encrypt_func() const {
- return pk11_pub_encrypt_func_;
- }
-
- // Returns NULL if unsupported.
- PK11_PrivDecryptFunction pk11_priv_decrypt_func() const {
- return pk11_priv_decrypt_func_;
- }
-
- static NssRuntimeSupport* Get();
-
- private:
- friend struct base::DefaultLazyInstanceTraits<NssRuntimeSupport>;
-
- NssRuntimeSupport();
-
- PK11_EncryptDecryptFunction pk11_encrypt_func_;
- PK11_EncryptDecryptFunction pk11_decrypt_func_;
- PK11_PubEncryptFunction pk11_pub_encrypt_func_;
- PK11_PrivDecryptFunction pk11_priv_decrypt_func_;
- bool internal_slot_does_oaep_;
-};
-
-} // namespace webcrypto
-
-} // namespace content
-
-#endif // CONTENT_CHILD_WEBCRYPTO_NSS_UTIL_NSS_H_
diff --git a/chromium/content/child/webcrypto/openssl/aes_cbc_openssl.cc b/chromium/content/child/webcrypto/openssl/aes_cbc_openssl.cc
deleted file mode 100644
index 860acc45d3b..00000000000
--- a/chromium/content/child/webcrypto/openssl/aes_cbc_openssl.cc
+++ /dev/null
@@ -1,139 +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 <openssl/aes.h>
-#include <openssl/evp.h>
-
-#include "base/logging.h"
-#include "base/numerics/safe_math.h"
-#include "base/stl_util.h"
-#include "content/child/webcrypto/crypto_data.h"
-#include "content/child/webcrypto/openssl/aes_key_openssl.h"
-#include "content/child/webcrypto/openssl/key_openssl.h"
-#include "content/child/webcrypto/openssl/util_openssl.h"
-#include "content/child/webcrypto/status.h"
-#include "content/child/webcrypto/webcrypto_util.h"
-#include "crypto/openssl_util.h"
-#include "crypto/scoped_openssl_types.h"
-#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
-
-namespace content {
-
-namespace webcrypto {
-
-namespace {
-
-const EVP_CIPHER* GetAESCipherByKeyLength(unsigned int key_length_bytes) {
- // BoringSSL does not support 192-bit AES keys.
- switch (key_length_bytes) {
- case 16:
- return EVP_aes_128_cbc();
- case 32:
- return EVP_aes_256_cbc();
- default:
- return NULL;
- }
-}
-
-Status AesCbcEncryptDecrypt(EncryptOrDecrypt cipher_operation,
- const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) {
- crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
-
- const blink::WebCryptoAesCbcParams* params = algorithm.aesCbcParams();
- const std::vector<uint8_t>& raw_key =
- SymKeyOpenSsl::Cast(key)->raw_key_data();
-
- if (params->iv().size() != 16)
- return Status::ErrorIncorrectSizeAesCbcIv();
-
- // According to the openssl docs, the amount of data written may be as large
- // as (data_size + cipher_block_size - 1), constrained to a multiple of
- // cipher_block_size.
- base::CheckedNumeric<int> output_max_len = data.byte_length();
- output_max_len += AES_BLOCK_SIZE - 1;
- if (!output_max_len.IsValid())
- return Status::ErrorDataTooLarge();
-
- const unsigned remainder = output_max_len.ValueOrDie() % AES_BLOCK_SIZE;
- if (remainder != 0)
- output_max_len += AES_BLOCK_SIZE - remainder;
- if (!output_max_len.IsValid())
- return Status::ErrorDataTooLarge();
-
- // Note: PKCS padding is enabled by default
- crypto::ScopedOpenSSL<EVP_CIPHER_CTX, EVP_CIPHER_CTX_free>::Type context(
- EVP_CIPHER_CTX_new());
-
- if (!context.get())
- return Status::OperationError();
-
- const EVP_CIPHER* const cipher = GetAESCipherByKeyLength(raw_key.size());
- DCHECK(cipher);
-
- if (!EVP_CipherInit_ex(context.get(),
- cipher,
- NULL,
- &raw_key[0],
- params->iv().data(),
- cipher_operation)) {
- return Status::OperationError();
- }
-
- buffer->resize(output_max_len.ValueOrDie());
-
- unsigned char* const buffer_data = vector_as_array(buffer);
-
- int output_len = 0;
- if (!EVP_CipherUpdate(context.get(),
- buffer_data,
- &output_len,
- data.bytes(),
- data.byte_length()))
- return Status::OperationError();
- int final_output_chunk_len = 0;
- if (!EVP_CipherFinal_ex(
- context.get(), buffer_data + output_len, &final_output_chunk_len)) {
- return Status::OperationError();
- }
-
- const unsigned int final_output_len =
- static_cast<unsigned int>(output_len) +
- static_cast<unsigned int>(final_output_chunk_len);
-
- buffer->resize(final_output_len);
-
- return Status::Success();
-}
-
-class AesCbcImplementation : public AesAlgorithm {
- public:
- AesCbcImplementation() : AesAlgorithm("CBC") {}
-
- Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const override {
- return AesCbcEncryptDecrypt(ENCRYPT, algorithm, key, data, buffer);
- }
-
- Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const override {
- return AesCbcEncryptDecrypt(DECRYPT, algorithm, key, data, buffer);
- }
-};
-
-} // namespace
-
-AlgorithmImplementation* CreatePlatformAesCbcImplementation() {
- return new AesCbcImplementation;
-}
-
-} // namespace webcrypto
-
-} // namespace content
diff --git a/chromium/content/child/webcrypto/openssl/aes_ctr_openssl.cc b/chromium/content/child/webcrypto/openssl/aes_ctr_openssl.cc
deleted file mode 100644
index 82408b2559a..00000000000
--- a/chromium/content/child/webcrypto/openssl/aes_ctr_openssl.cc
+++ /dev/null
@@ -1,288 +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 <openssl/aes.h>
-#include <openssl/evp.h>
-
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/numerics/safe_math.h"
-#include "base/stl_util.h"
-#include "content/child/webcrypto/crypto_data.h"
-#include "content/child/webcrypto/openssl/aes_key_openssl.h"
-#include "content/child/webcrypto/openssl/key_openssl.h"
-#include "content/child/webcrypto/openssl/util_openssl.h"
-#include "content/child/webcrypto/status.h"
-#include "content/child/webcrypto/webcrypto_util.h"
-#include "crypto/openssl_util.h"
-#include "crypto/scoped_openssl_types.h"
-#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
-
-namespace content {
-
-namespace webcrypto {
-
-namespace {
-
-const EVP_CIPHER* GetAESCipherByKeyLength(unsigned int key_length_bytes) {
- // BoringSSL does not support 192-bit AES keys.
- switch (key_length_bytes) {
- case 16:
- return EVP_aes_128_ctr();
- case 32:
- return EVP_aes_256_ctr();
- default:
- return NULL;
- }
-}
-
-// Encrypts/decrypts given a 128-bit counter.
-//
-// |output| must be a pointer to a buffer which has a length of at least
-// |input.byte_length()|.
-Status AesCtrEncrypt128BitCounter(const EVP_CIPHER* cipher,
- const CryptoData& raw_key,
- const CryptoData& input,
- const CryptoData& counter,
- uint8_t* output) {
- DCHECK(cipher);
- DCHECK_EQ(16u, counter.byte_length());
-
- crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
- crypto::ScopedOpenSSL<EVP_CIPHER_CTX, EVP_CIPHER_CTX_free>::Type context(
- EVP_CIPHER_CTX_new());
-
- if (!context.get())
- return Status::OperationError();
-
- if (!EVP_CipherInit_ex(context.get(),
- cipher,
- NULL,
- raw_key.bytes(),
- counter.bytes(),
- ENCRYPT)) {
- return Status::OperationError();
- }
-
- int output_len = 0;
- if (!EVP_CipherUpdate(context.get(),
- output,
- &output_len,
- input.bytes(),
- input.byte_length())) {
- return Status::OperationError();
- }
- int final_output_chunk_len = 0;
- if (!EVP_CipherFinal_ex(
- context.get(), output + output_len, &final_output_chunk_len)) {
- return Status::OperationError();
- }
-
- output_len += final_output_chunk_len;
- if (static_cast<unsigned int>(output_len) != input.byte_length())
- return Status::ErrorUnexpected();
-
- return Status::Success();
-}
-
-// Returns ceil(a/b), where a and b are integers.
-template <typename T>
-T CeilDiv(T a, T b) {
- return a == 0 ? 0 : 1 + (a - 1) / b;
-}
-
-// Extracts the counter as a BIGNUM. The counter is the rightmost
-// "counter_length_bits" of the block, interpreted as a big-endian number.
-crypto::ScopedBIGNUM GetCounter(const CryptoData& counter_block,
- unsigned int counter_length_bits) {
- unsigned int counter_length_remainder_bits = (counter_length_bits % 8);
-
- // If the counter is a multiple of 8 bits then can call BN_bin2bn() directly.
- if (counter_length_remainder_bits == 0) {
- unsigned int byte_length = counter_length_bits / 8;
- return crypto::ScopedBIGNUM(BN_bin2bn(
- counter_block.bytes() + counter_block.byte_length() - byte_length,
- byte_length,
- NULL));
- }
-
- // Otherwise make a copy of the counter and zero out the topmost bits so
- // BN_bin2bn() can be called with a byte stream.
- unsigned int byte_length = CeilDiv(counter_length_bits, 8u);
- std::vector<uint8_t> counter(
- counter_block.bytes() + counter_block.byte_length() - byte_length,
- counter_block.bytes() + counter_block.byte_length());
- counter[0] &= ~(0xFF << counter_length_remainder_bits);
-
- return crypto::ScopedBIGNUM(
- BN_bin2bn(&counter.front(), counter.size(), NULL));
-}
-
-// Returns a counter block with the counter bits all set all zero.
-std::vector<uint8_t> BlockWithZeroedCounter(const CryptoData& counter_block,
- unsigned int counter_length_bits) {
- unsigned int counter_length_bytes = counter_length_bits / 8;
- unsigned int counter_length_bits_remainder = counter_length_bits % 8;
-
- std::vector<uint8_t> new_counter_block(
- counter_block.bytes(),
- counter_block.bytes() + counter_block.byte_length());
-
- unsigned int index = new_counter_block.size() - counter_length_bytes;
- memset(&new_counter_block.front() + index, 0, counter_length_bytes);
-
- if (counter_length_bits_remainder) {
- new_counter_block[index - 1] &= 0xFF << counter_length_bits_remainder;
- }
-
- return new_counter_block;
-}
-
-// This function does encryption/decryption for AES-CTR (encryption and
-// decryption are the same).
-//
-// BoringSSL's interface for AES-CTR differs from that of WebCrypto. In
-// WebCrypto the caller specifies a 16-byte counter block and designates how
-// many of the right-most X bits to use as a big-endian counter. Whereas in
-// BoringSSL the entire counter block is interpreted as a 128-bit counter.
-//
-// In AES-CTR, the counter block MUST be unique across all messages that are
-// encrypted/decrypted. WebCrypto expects that the counter can start at any
-// value, and is therefore permitted to wrap around to zero on overflow.
-//
-// Some care is taken to fail if the counter wraps back to an earlier value.
-// However this protection is only enforced during a *single* call to
-// encrypt/decrypt.
-Status AesCtrEncryptDecrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) {
- const blink::WebCryptoAesCtrParams* params = algorithm.aesCtrParams();
- const std::vector<uint8_t>& raw_key =
- SymKeyOpenSsl::Cast(key)->raw_key_data();
-
- if (params->counter().size() != 16)
- return Status::ErrorIncorrectSizeAesCtrCounter();
-
- unsigned int counter_length_bits = params->lengthBits();
- if (counter_length_bits < 1 || counter_length_bits > 128)
- return Status::ErrorInvalidAesCtrCounterLength();
-
- // The output of AES-CTR is the same size as the input. However BoringSSL
- // expects buffer sizes as an "int".
- base::CheckedNumeric<int> output_max_len = data.byte_length();
- if (!output_max_len.IsValid())
- return Status::ErrorDataTooLarge();
-
- const EVP_CIPHER* const cipher = GetAESCipherByKeyLength(raw_key.size());
- if (!cipher)
- return Status::ErrorUnexpected();
-
- const CryptoData counter_block(params->counter());
- buffer->resize(output_max_len.ValueOrDie());
-
- // The total number of possible counter values is pow(2, counter_length_bits)
- crypto::ScopedBIGNUM num_counter_values(BN_new());
- if (!BN_lshift(num_counter_values.get(), BN_value_one(), counter_length_bits))
- return Status::ErrorUnexpected();
-
- crypto::ScopedBIGNUM current_counter =
- GetCounter(counter_block, counter_length_bits);
-
- // The number of AES blocks needed for encryption/decryption. The counter is
- // incremented this many times.
- crypto::ScopedBIGNUM num_output_blocks(BN_new());
- if (!BN_set_word(
- num_output_blocks.get(),
- CeilDiv(buffer->size(), static_cast<size_t>(AES_BLOCK_SIZE)))) {
- return Status::ErrorUnexpected();
- }
-
- // If the counter is going to be incremented more times than there are counter
- // values, fail. (Repeating values of the counter block is bad).
- if (BN_cmp(num_output_blocks.get(), num_counter_values.get()) > 0)
- return Status::ErrorAesCtrInputTooLongCounterRepeated();
-
- // This is the number of blocks that can be successfully encrypted without
- // overflowing the counter. Encrypting the subsequent block will need to
- // reset the counter to zero.
- crypto::ScopedBIGNUM num_blocks_until_reset(BN_new());
-
- if (!BN_sub(num_blocks_until_reset.get(),
- num_counter_values.get(),
- current_counter.get())) {
- return Status::ErrorUnexpected();
- }
-
- // If the counter can be incremented for the entire input without
- // wrapping-around, do it as a single call into BoringSSL.
- if (BN_cmp(num_blocks_until_reset.get(), num_output_blocks.get()) >= 0) {
- return AesCtrEncrypt128BitCounter(cipher,
- CryptoData(raw_key),
- data,
- counter_block,
- vector_as_array(buffer));
- }
-
- // Otherwise the encryption needs to be done in 2 parts. The first part using
- // the current counter_block, and the next part resetting the counter portion
- // of the block to zero.
-
- // This is guaranteed to fit in an "unsigned int" because input size in bytes
- // fits in an "unsigned int".
- BN_ULONG num_blocks_part1 = BN_get_word(num_blocks_until_reset.get());
- BN_ULONG input_size_part1 = num_blocks_part1 * AES_BLOCK_SIZE;
- DCHECK_LT(input_size_part1, data.byte_length());
-
- // Encrypt the first part (before wrap-around).
- Status status =
- AesCtrEncrypt128BitCounter(cipher,
- CryptoData(raw_key),
- CryptoData(data.bytes(), input_size_part1),
- counter_block,
- vector_as_array(buffer));
- if (status.IsError())
- return status;
-
- // Encrypt the second part (after wrap-around).
- std::vector<uint8_t> counter_block_part2 =
- BlockWithZeroedCounter(counter_block, counter_length_bits);
-
- return AesCtrEncrypt128BitCounter(
- cipher,
- CryptoData(raw_key),
- CryptoData(data.bytes() + input_size_part1,
- data.byte_length() - input_size_part1),
- CryptoData(counter_block_part2),
- vector_as_array(buffer) + input_size_part1);
-}
-
-class AesCtrImplementation : public AesAlgorithm {
- public:
- AesCtrImplementation() : AesAlgorithm("CTR") {}
-
- Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const override {
- return AesCtrEncryptDecrypt(algorithm, key, data, buffer);
- }
-
- Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const override {
- return AesCtrEncryptDecrypt(algorithm, key, data, buffer);
- }
-};
-
-} // namespace
-
-AlgorithmImplementation* CreatePlatformAesCtrImplementation() {
- return new AesCtrImplementation;
-}
-
-} // namespace webcrypto
-
-} // namespace content
diff --git a/chromium/content/child/webcrypto/openssl/aes_gcm_openssl.cc b/chromium/content/child/webcrypto/openssl/aes_gcm_openssl.cc
deleted file mode 100644
index 7c783c9bdcf..00000000000
--- a/chromium/content/child/webcrypto/openssl/aes_gcm_openssl.cc
+++ /dev/null
@@ -1,88 +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 <vector>
-#include <openssl/evp.h>
-
-#include "base/logging.h"
-#include "base/stl_util.h"
-#include "content/child/webcrypto/crypto_data.h"
-#include "content/child/webcrypto/openssl/aes_key_openssl.h"
-#include "content/child/webcrypto/openssl/key_openssl.h"
-#include "content/child/webcrypto/openssl/util_openssl.h"
-#include "content/child/webcrypto/status.h"
-#include "content/child/webcrypto/webcrypto_util.h"
-#include "crypto/openssl_util.h"
-#include "crypto/scoped_openssl_types.h"
-#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
-
-namespace content {
-
-namespace webcrypto {
-
-namespace {
-
-const EVP_AEAD* GetAesGcmAlgorithmFromKeySize(unsigned int key_size_bytes) {
- switch (key_size_bytes) {
- case 16:
- return EVP_aead_aes_128_gcm();
- case 32:
- return EVP_aead_aes_256_gcm();
- default:
- return NULL;
- }
-}
-
-Status AesGcmEncryptDecrypt(EncryptOrDecrypt mode,
- const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) {
- const std::vector<uint8_t>& raw_key =
- SymKeyOpenSsl::Cast(key)->raw_key_data();
- const blink::WebCryptoAesGcmParams* params = algorithm.aesGcmParams();
-
- unsigned int tag_length_bits;
- Status status = GetAesGcmTagLengthInBits(params, &tag_length_bits);
- if (status.IsError())
- return status;
-
- return AeadEncryptDecrypt(mode,
- raw_key,
- data,
- tag_length_bits / 8,
- CryptoData(params->iv()),
- CryptoData(params->optionalAdditionalData()),
- GetAesGcmAlgorithmFromKeySize(raw_key.size()),
- buffer);
-}
-
-class AesGcmImplementation : public AesAlgorithm {
- public:
- AesGcmImplementation() : AesAlgorithm("GCM") {}
-
- Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const override {
- return AesGcmEncryptDecrypt(ENCRYPT, algorithm, key, data, buffer);
- }
-
- Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const override {
- return AesGcmEncryptDecrypt(DECRYPT, algorithm, key, data, buffer);
- }
-};
-
-} // namespace
-
-AlgorithmImplementation* CreatePlatformAesGcmImplementation() {
- return new AesGcmImplementation;
-}
-
-} // namespace webcrypto
-
-} // namespace content
diff --git a/chromium/content/child/webcrypto/openssl/aes_key_openssl.cc b/chromium/content/child/webcrypto/openssl/aes_key_openssl.cc
deleted file mode 100644
index 14fa24e35c2..00000000000
--- a/chromium/content/child/webcrypto/openssl/aes_key_openssl.cc
+++ /dev/null
@@ -1,124 +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/child/webcrypto/openssl/aes_key_openssl.h"
-
-#include "base/logging.h"
-#include "content/child/webcrypto/crypto_data.h"
-#include "content/child/webcrypto/jwk.h"
-#include "content/child/webcrypto/openssl/key_openssl.h"
-#include "content/child/webcrypto/openssl/sym_key_openssl.h"
-#include "content/child/webcrypto/status.h"
-#include "content/child/webcrypto/webcrypto_util.h"
-#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
-
-namespace content {
-
-namespace webcrypto {
-
-AesAlgorithm::AesAlgorithm(blink::WebCryptoKeyUsageMask all_key_usages,
- const std::string& jwk_suffix)
- : all_key_usages_(all_key_usages), jwk_suffix_(jwk_suffix) {
-}
-
-AesAlgorithm::AesAlgorithm(const std::string& jwk_suffix)
- : all_key_usages_(blink::WebCryptoKeyUsageEncrypt |
- blink::WebCryptoKeyUsageDecrypt |
- blink::WebCryptoKeyUsageWrapKey |
- blink::WebCryptoKeyUsageUnwrapKey),
- jwk_suffix_(jwk_suffix) {
-}
-
-Status AesAlgorithm::GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- GenerateKeyResult* result) const {
- Status status = CheckKeyCreationUsages(all_key_usages_, usages);
- if (status.IsError())
- return status;
-
- unsigned int keylen_bits;
- status = GetAesKeyGenLengthInBits(algorithm.aesKeyGenParams(), &keylen_bits);
- if (status.IsError())
- return status;
-
- return GenerateSecretKeyOpenSsl(
- blink::WebCryptoKeyAlgorithm::createAes(algorithm.id(), keylen_bits),
- extractable,
- usages,
- keylen_bits / 8,
- result);
-}
-
-Status AesAlgorithm::VerifyKeyUsagesBeforeImportKey(
- blink::WebCryptoKeyFormat format,
- blink::WebCryptoKeyUsageMask usages) const {
- switch (format) {
- case blink::WebCryptoKeyFormatRaw:
- case blink::WebCryptoKeyFormatJwk:
- return CheckKeyCreationUsages(all_key_usages_, usages);
- default:
- return Status::ErrorUnsupportedImportKeyFormat();
- }
-}
-
-Status AesAlgorithm::ImportKeyRaw(const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const {
- const unsigned int keylen_bytes = key_data.byte_length();
- Status status = VerifyAesKeyLengthForImport(keylen_bytes);
- if (status.IsError())
- return status;
-
- // No possibility of overflow.
- unsigned int keylen_bits = keylen_bytes * 8;
-
- return ImportKeyRawOpenSsl(
- key_data,
- blink::WebCryptoKeyAlgorithm::createAes(algorithm.id(), keylen_bits),
- extractable,
- usages,
- key);
-}
-
-Status AesAlgorithm::ImportKeyJwk(const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const {
- std::vector<uint8_t> raw_data;
- Status status = ReadAesSecretKeyJwk(
- key_data, jwk_suffix_, extractable, usages, &raw_data);
- if (status.IsError())
- return status;
-
- return ImportKeyRaw(
- CryptoData(raw_data), algorithm, extractable, usages, key);
-}
-
-Status AesAlgorithm::ExportKeyRaw(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const {
- *buffer = SymKeyOpenSsl::Cast(key)->raw_key_data();
- return Status::Success();
-}
-
-Status AesAlgorithm::ExportKeyJwk(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const {
- const std::vector<uint8_t>& raw_data =
- SymKeyOpenSsl::Cast(key)->raw_key_data();
-
- WriteSecretKeyJwk(CryptoData(raw_data),
- MakeJwkAesAlgorithmName(jwk_suffix_, raw_data.size()),
- key.extractable(),
- key.usages(),
- buffer);
-
- return Status::Success();
-}
-
-} // namespace webcrypto
-
-} // namespace content
diff --git a/chromium/content/child/webcrypto/openssl/aes_key_openssl.h b/chromium/content/child/webcrypto/openssl/aes_key_openssl.h
deleted file mode 100644
index 206a1e2bcfc..00000000000
--- a/chromium/content/child/webcrypto/openssl/aes_key_openssl.h
+++ /dev/null
@@ -1,67 +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_CHILD_WEBCRYPTO_OPENSSL_AES_OPENSSL_H_
-#define CONTENT_CHILD_WEBCRYPTO_OPENSSL_AES_OPENSSL_H_
-
-#include "content/child/webcrypto/algorithm_implementation.h"
-
-namespace content {
-
-namespace webcrypto {
-
-// Base class for AES algorithms that provides the implementation for key
-// creation and export.
-class AesAlgorithm : public AlgorithmImplementation {
- public:
- // |all_key_usages| is the set of all WebCrypto key usages that are
- // allowed for imported or generated keys. |jwk_suffix| is the suffix
- // used when constructing JWK names for the algorithm. For instance A128CBC
- // is the JWK name for 128-bit AES-CBC. The |jwk_suffix| in this case would
- // be "CBC".
- AesAlgorithm(blink::WebCryptoKeyUsageMask all_key_usages,
- const std::string& jwk_suffix);
-
- // This is the same as the other AesAlgorithm constructor where
- // |all_key_usages| is pre-filled to values for encryption/decryption
- // algorithms (supports usages for: encrypt, decrypt, wrap, unwrap).
- explicit AesAlgorithm(const std::string& jwk_suffix);
-
- Status GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- GenerateKeyResult* result) const override;
-
- Status VerifyKeyUsagesBeforeImportKey(
- blink::WebCryptoKeyFormat format,
- blink::WebCryptoKeyUsageMask usages) const override;
-
- Status ImportKeyRaw(const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const override;
-
- Status ImportKeyJwk(const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const override;
-
- Status ExportKeyRaw(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const override;
-
- Status ExportKeyJwk(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const override;
-
- private:
- const blink::WebCryptoKeyUsageMask all_key_usages_;
- const std::string jwk_suffix_;
-};
-
-} // namespace webcrypto
-
-} // namespace content
-
-#endif // CONTENT_CHILD_WEBCRYPTO_OPENSSL_AES_OPENSSL_H_
diff --git a/chromium/content/child/webcrypto/openssl/aes_kw_openssl.cc b/chromium/content/child/webcrypto/openssl/aes_kw_openssl.cc
deleted file mode 100644
index c612d53dc96..00000000000
--- a/chromium/content/child/webcrypto/openssl/aes_kw_openssl.cc
+++ /dev/null
@@ -1,94 +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 <vector>
-#include <openssl/evp.h>
-
-#include "base/logging.h"
-#include "base/numerics/safe_math.h"
-#include "base/stl_util.h"
-#include "content/child/webcrypto/crypto_data.h"
-#include "content/child/webcrypto/openssl/aes_key_openssl.h"
-#include "content/child/webcrypto/openssl/key_openssl.h"
-#include "content/child/webcrypto/openssl/util_openssl.h"
-#include "content/child/webcrypto/status.h"
-#include "crypto/openssl_util.h"
-#include "crypto/scoped_openssl_types.h"
-
-namespace content {
-
-namespace webcrypto {
-
-namespace {
-
-const EVP_AEAD* GetAesKwAlgorithmFromKeySize(unsigned int key_size_bytes) {
- switch (key_size_bytes) {
- case 16:
- return EVP_aead_aes_128_key_wrap();
- case 32:
- return EVP_aead_aes_256_key_wrap();
- default:
- return NULL;
- }
-}
-
-Status AesKwEncryptDecrypt(EncryptOrDecrypt mode,
- const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) {
- // These length checks are done so the returned error matches that of NSS
- // implementation. Other than giving a more specific error, these are not
- // required.
- if ((mode == ENCRYPT && data.byte_length() < 16) ||
- (mode == DECRYPT && data.byte_length() < 24)) {
- return Status::ErrorDataTooSmall();
- }
- if (data.byte_length() % 8)
- return Status::ErrorInvalidAesKwDataLength();
-
- const std::vector<uint8_t>& raw_key =
- SymKeyOpenSsl::Cast(key)->raw_key_data();
-
- return AeadEncryptDecrypt(mode,
- raw_key,
- data,
- 8, // tag_length_bytes
- CryptoData(), // iv
- CryptoData(), // additional_data
- GetAesKwAlgorithmFromKeySize(raw_key.size()),
- buffer);
-}
-
-class AesKwImplementation : public AesAlgorithm {
- public:
- AesKwImplementation()
- : AesAlgorithm(
- blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey,
- "KW") {}
-
- Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const override {
- return AesKwEncryptDecrypt(ENCRYPT, algorithm, key, data, buffer);
- }
-
- Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const override {
- return AesKwEncryptDecrypt(DECRYPT, algorithm, key, data, buffer);
- }
-};
-
-} // namespace
-
-AlgorithmImplementation* CreatePlatformAesKwImplementation() {
- return new AesKwImplementation;
-}
-
-} // namespace webcrypto
-
-} // namespace content
diff --git a/chromium/content/child/webcrypto/openssl/hmac_openssl.cc b/chromium/content/child/webcrypto/openssl/hmac_openssl.cc
deleted file mode 100644
index 77b5ccfcf93..00000000000
--- a/chromium/content/child/webcrypto/openssl/hmac_openssl.cc
+++ /dev/null
@@ -1,216 +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 <openssl/hmac.h>
-
-#include "base/logging.h"
-#include "base/numerics/safe_math.h"
-#include "base/stl_util.h"
-#include "content/child/webcrypto/algorithm_implementation.h"
-#include "content/child/webcrypto/crypto_data.h"
-#include "content/child/webcrypto/jwk.h"
-#include "content/child/webcrypto/openssl/key_openssl.h"
-#include "content/child/webcrypto/openssl/sym_key_openssl.h"
-#include "content/child/webcrypto/openssl/util_openssl.h"
-#include "content/child/webcrypto/status.h"
-#include "content/child/webcrypto/webcrypto_util.h"
-#include "crypto/openssl_util.h"
-#include "crypto/secure_util.h"
-#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
-#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
-
-namespace content {
-
-namespace webcrypto {
-
-namespace {
-
-const blink::WebCryptoKeyUsageMask kAllKeyUsages =
- blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify;
-
-Status SignHmac(const std::vector<uint8_t>& raw_key,
- const blink::WebCryptoAlgorithm& hash,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) {
- crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
-
- const EVP_MD* digest_algorithm = GetDigest(hash.id());
- if (!digest_algorithm)
- return Status::ErrorUnsupported();
- unsigned int hmac_expected_length = EVP_MD_size(digest_algorithm);
-
- // OpenSSL wierdness here.
- // First, HMAC() needs a void* for the key data, so make one up front as a
- // cosmetic to avoid a cast. Second, OpenSSL does not like a NULL key,
- // which will result if the raw_key vector is empty; an entirely valid
- // case. Handle this specific case by pointing to a fresh array.
- const unsigned char null_key[] = {0};
- const void* const raw_key_voidp = raw_key.size() ? &raw_key[0] : null_key;
-
- buffer->resize(hmac_expected_length);
- crypto::ScopedOpenSSLSafeSizeBuffer<EVP_MAX_MD_SIZE> hmac_result(
- vector_as_array(buffer), hmac_expected_length);
-
- unsigned int hmac_actual_length;
- unsigned char* const success = HMAC(digest_algorithm,
- raw_key_voidp,
- raw_key.size(),
- data.bytes(),
- data.byte_length(),
- hmac_result.safe_buffer(),
- &hmac_actual_length);
- if (!success || hmac_actual_length != hmac_expected_length)
- return Status::OperationError();
-
- return Status::Success();
-}
-
-class HmacImplementation : public AlgorithmImplementation {
- public:
- HmacImplementation() {}
-
- Status GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- GenerateKeyResult* result) const override {
- Status status = CheckKeyCreationUsages(kAllKeyUsages, usages);
- if (status.IsError())
- return status;
-
- const blink::WebCryptoHmacKeyGenParams* params =
- algorithm.hmacKeyGenParams();
-
- unsigned int keylen_bits = 0;
- status = GetHmacKeyGenLengthInBits(params, &keylen_bits);
- if (status.IsError())
- return status;
-
- return GenerateSecretKeyOpenSsl(blink::WebCryptoKeyAlgorithm::createHmac(
- params->hash().id(), keylen_bits),
- extractable,
- usages,
- keylen_bits / 8,
- result);
- }
-
- Status VerifyKeyUsagesBeforeImportKey(
- blink::WebCryptoKeyFormat format,
- blink::WebCryptoKeyUsageMask usages) const override {
- switch (format) {
- case blink::WebCryptoKeyFormatRaw:
- case blink::WebCryptoKeyFormatJwk:
- return CheckKeyCreationUsages(kAllKeyUsages, usages);
- default:
- return Status::ErrorUnsupportedImportKeyFormat();
- }
- }
-
- Status ImportKeyRaw(const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const override {
- const blink::WebCryptoAlgorithm& hash =
- algorithm.hmacImportParams()->hash();
-
- base::CheckedNumeric<unsigned int> keylen_bits(key_data.byte_length());
- keylen_bits *= 8;
-
- if (!keylen_bits.IsValid())
- return Status::ErrorDataTooLarge();
-
- return ImportKeyRawOpenSsl(key_data,
- blink::WebCryptoKeyAlgorithm::createHmac(
- hash.id(), keylen_bits.ValueOrDie()),
- extractable,
- usages,
- key);
- }
-
- Status ImportKeyJwk(const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const override {
- const char* algorithm_name =
- GetJwkHmacAlgorithmName(algorithm.hmacImportParams()->hash().id());
- if (!algorithm_name)
- return Status::ErrorUnexpected();
-
- std::vector<uint8_t> raw_data;
- Status status = ReadSecretKeyJwk(
- key_data, algorithm_name, extractable, usages, &raw_data);
- if (status.IsError())
- return status;
-
- return ImportKeyRaw(
- CryptoData(raw_data), algorithm, extractable, usages, key);
- }
-
- Status ExportKeyRaw(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const override {
- *buffer = SymKeyOpenSsl::Cast(key)->raw_key_data();
- return Status::Success();
- }
-
- Status ExportKeyJwk(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const override {
- SymKeyOpenSsl* sym_key = SymKeyOpenSsl::Cast(key);
- const std::vector<uint8_t>& raw_data = sym_key->raw_key_data();
-
- const char* algorithm_name =
- GetJwkHmacAlgorithmName(key.algorithm().hmacParams()->hash().id());
- if (!algorithm_name)
- return Status::ErrorUnexpected();
-
- WriteSecretKeyJwk(CryptoData(raw_data),
- algorithm_name,
- key.extractable(),
- key.usages(),
- buffer);
-
- return Status::Success();
- }
-
- Status Sign(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const override {
- const blink::WebCryptoAlgorithm& hash =
- key.algorithm().hmacParams()->hash();
-
- return SignHmac(
- SymKeyOpenSsl::Cast(key)->raw_key_data(), hash, data, buffer);
- }
-
- Status Verify(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& signature,
- const CryptoData& data,
- bool* signature_match) const override {
- std::vector<uint8_t> result;
- Status status = Sign(algorithm, key, data, &result);
-
- if (status.IsError())
- return status;
-
- // Do not allow verification of truncated MACs.
- *signature_match = result.size() == signature.byte_length() &&
- crypto::SecureMemEqual(vector_as_array(&result),
- signature.bytes(),
- signature.byte_length());
-
- return Status::Success();
- }
-};
-
-} // namespace
-
-AlgorithmImplementation* CreatePlatformHmacImplementation() {
- return new HmacImplementation;
-}
-
-} // namespace webcrypto
-
-} // namespace content
diff --git a/chromium/content/child/webcrypto/openssl/key_openssl.cc b/chromium/content/child/webcrypto/openssl/key_openssl.cc
deleted file mode 100644
index 9ea1f20428c..00000000000
--- a/chromium/content/child/webcrypto/openssl/key_openssl.cc
+++ /dev/null
@@ -1,73 +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/child/webcrypto/openssl/key_openssl.h"
-
-#include "content/child/webcrypto/crypto_data.h"
-#include "content/child/webcrypto/status.h"
-#include "content/child/webcrypto/webcrypto_util.h"
-
-namespace content {
-
-namespace webcrypto {
-
-KeyOpenSsl::KeyOpenSsl(const CryptoData& serialized_key_data)
- : serialized_key_data_(
- serialized_key_data.bytes(),
- serialized_key_data.bytes() + serialized_key_data.byte_length()) {
-}
-
-KeyOpenSsl::~KeyOpenSsl() {
-}
-
-SymKeyOpenSsl* KeyOpenSsl::AsSymKey() {
- return NULL;
-}
-
-AsymKeyOpenSsl* KeyOpenSsl::AsAsymKey() {
- return NULL;
-}
-
-SymKeyOpenSsl::~SymKeyOpenSsl() {
-}
-
-SymKeyOpenSsl* SymKeyOpenSsl::Cast(const blink::WebCryptoKey& key) {
- KeyOpenSsl* platform_key = reinterpret_cast<KeyOpenSsl*>(key.handle());
- return platform_key->AsSymKey();
-}
-
-SymKeyOpenSsl* SymKeyOpenSsl::AsSymKey() {
- return this;
-}
-
-SymKeyOpenSsl::SymKeyOpenSsl(const CryptoData& raw_key_data)
- : KeyOpenSsl(raw_key_data) {
-}
-
-AsymKeyOpenSsl::~AsymKeyOpenSsl() {
-}
-
-AsymKeyOpenSsl* AsymKeyOpenSsl::Cast(const blink::WebCryptoKey& key) {
- return reinterpret_cast<KeyOpenSsl*>(key.handle())->AsAsymKey();
-}
-
-AsymKeyOpenSsl* AsymKeyOpenSsl::AsAsymKey() {
- return this;
-}
-
-AsymKeyOpenSsl::AsymKeyOpenSsl(crypto::ScopedEVP_PKEY key,
- const CryptoData& serialized_key_data)
- : KeyOpenSsl(serialized_key_data), key_(key.Pass()) {
-}
-
-bool PlatformSerializeKeyForClone(const blink::WebCryptoKey& key,
- blink::WebVector<uint8_t>* key_data) {
- const KeyOpenSsl* openssl_key = static_cast<KeyOpenSsl*>(key.handle());
- *key_data = openssl_key->serialized_key_data();
- return true;
-}
-
-} // namespace webcrypto
-
-} // namespace content
diff --git a/chromium/content/child/webcrypto/openssl/key_openssl.h b/chromium/content/child/webcrypto/openssl/key_openssl.h
deleted file mode 100644
index 48163c18ac0..00000000000
--- a/chromium/content/child/webcrypto/openssl/key_openssl.h
+++ /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.
-
-#ifndef CONTENT_CHILD_WEBCRYPTO_OPENSSL_KEY_OPENSSL_H_
-#define CONTENT_CHILD_WEBCRYPTO_OPENSSL_KEY_OPENSSL_H_
-
-#include <openssl/ossl_typ.h>
-#include <stdint.h>
-#include <vector>
-
-#include "base/macros.h"
-#include "crypto/scoped_openssl_types.h"
-#include "third_party/WebKit/public/platform/WebCryptoKey.h"
-
-namespace content {
-
-namespace webcrypto {
-
-class CryptoData;
-class AsymKeyOpenSsl;
-class SymKeyOpenSsl;
-
-// Base key class for all OpenSSL keys, used to safely cast between types. Each
-// key maintains a copy of its serialized form in either 'raw', 'pkcs8', or
-// 'spki' format. This is to allow structured cloning of keys synchronously from
-// the target Blink thread without having to lock access to the key.
-class KeyOpenSsl : public blink::WebCryptoKeyHandle {
- public:
- explicit KeyOpenSsl(const CryptoData& serialized_key_data);
- ~KeyOpenSsl() override;
-
- virtual SymKeyOpenSsl* AsSymKey();
- virtual AsymKeyOpenSsl* AsAsymKey();
-
- const std::vector<uint8_t>& serialized_key_data() const {
- return serialized_key_data_;
- }
-
- private:
- const std::vector<uint8_t> serialized_key_data_;
-};
-
-class SymKeyOpenSsl : public KeyOpenSsl {
- public:
- ~SymKeyOpenSsl() override;
- explicit SymKeyOpenSsl(const CryptoData& raw_key_data);
-
- static SymKeyOpenSsl* Cast(const blink::WebCryptoKey& key);
-
- SymKeyOpenSsl* AsSymKey() override;
-
- const std::vector<uint8_t>& raw_key_data() const {
- return serialized_key_data();
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(SymKeyOpenSsl);
-};
-
-class AsymKeyOpenSsl : public KeyOpenSsl {
- public:
- ~AsymKeyOpenSsl() override;
- AsymKeyOpenSsl(crypto::ScopedEVP_PKEY key,
- const CryptoData& serialized_key_data);
-
- static AsymKeyOpenSsl* Cast(const blink::WebCryptoKey& key);
-
- AsymKeyOpenSsl* AsAsymKey() override;
-
- EVP_PKEY* key() { return key_.get(); }
-
- private:
- crypto::ScopedEVP_PKEY key_;
-
- DISALLOW_COPY_AND_ASSIGN(AsymKeyOpenSsl);
-};
-
-} // namespace webcrypto
-
-} // namespace content
-
-#endif // CONTENT_CHILD_WEBCRYPTO_OPENSSL_KEY_OPENSSL_H_
diff --git a/chromium/content/child/webcrypto/openssl/rsa_key_openssl.cc b/chromium/content/child/webcrypto/openssl/rsa_key_openssl.cc
deleted file mode 100644
index 6710c31b0ca..00000000000
--- a/chromium/content/child/webcrypto/openssl/rsa_key_openssl.cc
+++ /dev/null
@@ -1,389 +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/child/webcrypto/openssl/rsa_key_openssl.h"
-
-#include <openssl/evp.h>
-
-#include "base/logging.h"
-#include "base/stl_util.h"
-#include "content/child/webcrypto/crypto_data.h"
-#include "content/child/webcrypto/generate_key_result.h"
-#include "content/child/webcrypto/jwk.h"
-#include "content/child/webcrypto/openssl/key_openssl.h"
-#include "content/child/webcrypto/openssl/util_openssl.h"
-#include "content/child/webcrypto/status.h"
-#include "content/child/webcrypto/webcrypto_util.h"
-#include "crypto/openssl_util.h"
-#include "crypto/scoped_openssl_types.h"
-#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
-#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
-
-namespace content {
-
-namespace webcrypto {
-
-namespace {
-
-// Creates a blink::WebCryptoAlgorithm having the modulus length and public
-// exponent of |key|.
-Status CreateRsaHashedKeyAlgorithm(
- blink::WebCryptoAlgorithmId rsa_algorithm,
- blink::WebCryptoAlgorithmId hash_algorithm,
- EVP_PKEY* key,
- blink::WebCryptoKeyAlgorithm* key_algorithm) {
- DCHECK_EQ(EVP_PKEY_RSA, EVP_PKEY_id(key));
-
- crypto::ScopedRSA rsa(EVP_PKEY_get1_RSA(key));
- if (!rsa.get())
- return Status::ErrorUnexpected();
-
- unsigned int modulus_length_bits = BN_num_bits(rsa.get()->n);
-
- // Convert the public exponent to big-endian representation.
- std::vector<uint8_t> e(BN_num_bytes(rsa.get()->e));
- if (e.size() == 0)
- return Status::ErrorUnexpected();
- if (e.size() != BN_bn2bin(rsa.get()->e, &e[0]))
- return Status::ErrorUnexpected();
-
- *key_algorithm = blink::WebCryptoKeyAlgorithm::createRsaHashed(
- rsa_algorithm, modulus_length_bits, &e[0], e.size(), hash_algorithm);
-
- return Status::Success();
-}
-
-// Creates a WebCryptoKey that wraps |private_key|.
-Status CreateWebCryptoRsaPrivateKey(
- crypto::ScopedEVP_PKEY private_key,
- const blink::WebCryptoAlgorithmId rsa_algorithm_id,
- const blink::WebCryptoAlgorithm& hash,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) {
- blink::WebCryptoKeyAlgorithm key_algorithm;
- Status status = CreateRsaHashedKeyAlgorithm(
- rsa_algorithm_id, hash.id(), private_key.get(), &key_algorithm);
- if (status.IsError())
- return status;
-
- return CreateWebCryptoPrivateKey(private_key.Pass(), key_algorithm,
- extractable, usages, key);
-}
-
-// Creates a WebCryptoKey that wraps |public_key|.
-Status CreateWebCryptoRsaPublicKey(
- crypto::ScopedEVP_PKEY public_key,
- const blink::WebCryptoAlgorithmId rsa_algorithm_id,
- const blink::WebCryptoAlgorithm& hash,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) {
- blink::WebCryptoKeyAlgorithm key_algorithm;
- Status status = CreateRsaHashedKeyAlgorithm(
- rsa_algorithm_id, hash.id(), public_key.get(), &key_algorithm);
- if (status.IsError())
- return status;
-
- return CreateWebCryptoPublicKey(public_key.Pass(), key_algorithm, extractable,
- usages, key);
-}
-
-Status ImportRsaPrivateKey(const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- const JwkRsaInfo& params,
- blink::WebCryptoKey* key) {
- crypto::ScopedRSA rsa(RSA_new());
-
- rsa->n = CreateBIGNUM(params.n);
- rsa->e = CreateBIGNUM(params.e);
- rsa->d = CreateBIGNUM(params.d);
- rsa->p = CreateBIGNUM(params.p);
- rsa->q = CreateBIGNUM(params.q);
- rsa->dmp1 = CreateBIGNUM(params.dp);
- rsa->dmq1 = CreateBIGNUM(params.dq);
- rsa->iqmp = CreateBIGNUM(params.qi);
-
- if (!rsa->n || !rsa->e || !rsa->d || !rsa->p || !rsa->q || !rsa->dmp1 ||
- !rsa->dmq1 || !rsa->iqmp) {
- return Status::OperationError();
- }
-
- // TODO(eroman): This should really be a DataError, however for compatibility
- // with NSS it is an OperationError.
- if (!RSA_check_key(rsa.get()))
- return Status::OperationError();
-
- // Create a corresponding EVP_PKEY.
- crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new());
- if (!pkey || !EVP_PKEY_set1_RSA(pkey.get(), rsa.get()))
- return Status::OperationError();
-
- return CreateWebCryptoRsaPrivateKey(pkey.Pass(), algorithm.id(),
- algorithm.rsaHashedImportParams()->hash(),
- extractable, usages, key);
-}
-
-Status ImportRsaPublicKey(const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- const CryptoData& n,
- const CryptoData& e,
- blink::WebCryptoKey* key) {
- crypto::ScopedRSA rsa(RSA_new());
-
- rsa->n = BN_bin2bn(n.bytes(), n.byte_length(), NULL);
- rsa->e = BN_bin2bn(e.bytes(), e.byte_length(), NULL);
-
- if (!rsa->n || !rsa->e)
- return Status::OperationError();
-
- // Create a corresponding EVP_PKEY.
- crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new());
- if (!pkey || !EVP_PKEY_set1_RSA(pkey.get(), rsa.get()))
- return Status::OperationError();
-
- return CreateWebCryptoRsaPublicKey(pkey.Pass(), algorithm.id(),
- algorithm.rsaHashedImportParams()->hash(),
- extractable, usages, key);
-}
-
-} // namespace
-
-Status RsaHashedAlgorithm::GenerateKey(
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask combined_usages,
- GenerateKeyResult* result) const {
- Status status = CheckKeyCreationUsages(
- all_public_key_usages_ | all_private_key_usages_, combined_usages);
- if (status.IsError())
- return status;
-
- const blink::WebCryptoKeyUsageMask public_usages =
- combined_usages & all_public_key_usages_;
- const blink::WebCryptoKeyUsageMask private_usages =
- combined_usages & all_private_key_usages_;
-
- const blink::WebCryptoRsaHashedKeyGenParams* params =
- algorithm.rsaHashedKeyGenParams();
-
- unsigned int public_exponent = 0;
- unsigned int modulus_length_bits = 0;
- status =
- GetRsaKeyGenParameters(params, &public_exponent, &modulus_length_bits);
- if (status.IsError())
- return status;
-
- crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
-
- // Generate an RSA key pair.
- crypto::ScopedRSA rsa_private_key(RSA_new());
- crypto::ScopedBIGNUM bn(BN_new());
- if (!rsa_private_key.get() || !bn.get() ||
- !BN_set_word(bn.get(), public_exponent)) {
- return Status::OperationError();
- }
-
- if (!RSA_generate_key_ex(
- rsa_private_key.get(), modulus_length_bits, bn.get(), NULL)) {
- return Status::OperationError();
- }
-
- // Construct an EVP_PKEY for the private key.
- crypto::ScopedEVP_PKEY private_pkey(EVP_PKEY_new());
- if (!private_pkey ||
- !EVP_PKEY_set1_RSA(private_pkey.get(), rsa_private_key.get())) {
- return Status::OperationError();
- }
-
- // Construct an EVP_PKEY for the public key.
- crypto::ScopedRSA rsa_public_key(RSAPublicKey_dup(rsa_private_key.get()));
- crypto::ScopedEVP_PKEY public_pkey(EVP_PKEY_new());
- if (!public_pkey ||
- !EVP_PKEY_set1_RSA(public_pkey.get(), rsa_public_key.get())) {
- return Status::OperationError();
- }
-
- blink::WebCryptoKey public_key;
- blink::WebCryptoKey private_key;
-
- // Note that extractable is unconditionally set to true. This is because per
- // the WebCrypto spec generated public keys are always public.
- status = CreateWebCryptoRsaPublicKey(public_pkey.Pass(), algorithm.id(),
- params->hash(), true, public_usages,
- &public_key);
- if (status.IsError())
- return status;
-
- status = CreateWebCryptoRsaPrivateKey(private_pkey.Pass(), algorithm.id(),
- params->hash(), extractable,
- private_usages, &private_key);
- if (status.IsError())
- return status;
-
- result->AssignKeyPair(public_key, private_key);
- return Status::Success();
-}
-
-Status RsaHashedAlgorithm::VerifyKeyUsagesBeforeImportKey(
- blink::WebCryptoKeyFormat format,
- blink::WebCryptoKeyUsageMask usages) const {
- switch (format) {
- case blink::WebCryptoKeyFormatSpki:
- return CheckKeyCreationUsages(all_public_key_usages_, usages);
- case blink::WebCryptoKeyFormatPkcs8:
- return CheckKeyCreationUsages(all_private_key_usages_, usages);
- case blink::WebCryptoKeyFormatJwk:
- // The JWK could represent either a public key or private key. The usages
- // must make sense for one of the two. The usages will be checked again by
- // ImportKeyJwk() once the key type has been determined.
- if (CheckKeyCreationUsages(all_private_key_usages_, usages).IsSuccess() ||
- CheckKeyCreationUsages(all_public_key_usages_, usages).IsSuccess()) {
- return Status::Success();
- }
- return Status::ErrorCreateKeyBadUsages();
- default:
- return Status::ErrorUnsupportedImportKeyFormat();
- }
-}
-
-Status RsaHashedAlgorithm::ImportKeyPkcs8(
- const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const {
- crypto::ScopedEVP_PKEY private_key;
- Status status =
- ImportUnverifiedPkeyFromPkcs8(key_data, EVP_PKEY_RSA, &private_key);
- if (status.IsError())
- return status;
-
- // Verify the parameters of the key.
- crypto::ScopedRSA rsa(EVP_PKEY_get1_RSA(private_key.get()));
- if (!rsa.get())
- return Status::ErrorUnexpected();
- if (!RSA_check_key(rsa.get()))
- return Status::DataError();
-
- // TODO(eroman): Validate the algorithm OID against the webcrypto provided
- // hash. http://crbug.com/389400
-
- return CreateWebCryptoRsaPrivateKey(private_key.Pass(), algorithm.id(),
- algorithm.rsaHashedImportParams()->hash(),
- extractable, usages, key);
-}
-
-Status RsaHashedAlgorithm::ImportKeySpki(
- const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const {
- crypto::ScopedEVP_PKEY public_key;
- Status status =
- ImportUnverifiedPkeyFromSpki(key_data, EVP_PKEY_RSA, &public_key);
- if (status.IsError())
- return status;
-
- // TODO(eroman): Validate the algorithm OID against the webcrypto provided
- // hash. http://crbug.com/389400
-
- return CreateWebCryptoRsaPublicKey(public_key.Pass(), algorithm.id(),
- algorithm.rsaHashedImportParams()->hash(),
- extractable, usages, key);
-}
-
-Status RsaHashedAlgorithm::ImportKeyJwk(
- const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const {
- crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
-
- const char* jwk_algorithm =
- GetJwkAlgorithm(algorithm.rsaHashedImportParams()->hash().id());
-
- if (!jwk_algorithm)
- return Status::ErrorUnexpected();
-
- JwkRsaInfo jwk;
- Status status =
- ReadRsaKeyJwk(key_data, jwk_algorithm, extractable, usages, &jwk);
- if (status.IsError())
- return status;
-
- // Once the key type is known, verify the usages.
- status = CheckKeyCreationUsages(
- jwk.is_private_key ? all_private_key_usages_ : all_public_key_usages_,
- usages);
- if (status.IsError())
- return status;
-
- return jwk.is_private_key
- ? ImportRsaPrivateKey(algorithm, extractable, usages, jwk, key)
- : ImportRsaPublicKey(algorithm, extractable, usages,
- CryptoData(jwk.n), CryptoData(jwk.e), key);
-}
-
-Status RsaHashedAlgorithm::ExportKeyPkcs8(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const {
- if (key.type() != blink::WebCryptoKeyTypePrivate)
- return Status::ErrorUnexpectedKeyType();
- *buffer = AsymKeyOpenSsl::Cast(key)->serialized_key_data();
- return Status::Success();
-}
-
-Status RsaHashedAlgorithm::ExportKeySpki(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const {
- if (key.type() != blink::WebCryptoKeyTypePublic)
- return Status::ErrorUnexpectedKeyType();
- *buffer = AsymKeyOpenSsl::Cast(key)->serialized_key_data();
- return Status::Success();
-}
-
-Status RsaHashedAlgorithm::ExportKeyJwk(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const {
- crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
-
- EVP_PKEY* pkey = AsymKeyOpenSsl::Cast(key)->key();
- crypto::ScopedRSA rsa(EVP_PKEY_get1_RSA(pkey));
- if (!rsa.get())
- return Status::ErrorUnexpected();
-
- const char* jwk_algorithm =
- GetJwkAlgorithm(key.algorithm().rsaHashedParams()->hash().id());
- if (!jwk_algorithm)
- return Status::ErrorUnexpected();
-
- switch (key.type()) {
- case blink::WebCryptoKeyTypePublic:
- WriteRsaPublicKeyJwk(CryptoData(BIGNUMToVector(rsa->n)),
- CryptoData(BIGNUMToVector(rsa->e)), jwk_algorithm,
- key.extractable(), key.usages(), buffer);
- return Status::Success();
- case blink::WebCryptoKeyTypePrivate:
- WriteRsaPrivateKeyJwk(CryptoData(BIGNUMToVector(rsa->n)),
- CryptoData(BIGNUMToVector(rsa->e)),
- CryptoData(BIGNUMToVector(rsa->d)),
- CryptoData(BIGNUMToVector(rsa->p)),
- CryptoData(BIGNUMToVector(rsa->q)),
- CryptoData(BIGNUMToVector(rsa->dmp1)),
- CryptoData(BIGNUMToVector(rsa->dmq1)),
- CryptoData(BIGNUMToVector(rsa->iqmp)),
- jwk_algorithm, key.extractable(), key.usages(),
- buffer);
- return Status::Success();
-
- default:
- return Status::ErrorUnexpected();
- }
-}
-
-} // namespace webcrypto
-
-} // namespace content
diff --git a/chromium/content/child/webcrypto/openssl/rsa_key_openssl.h b/chromium/content/child/webcrypto/openssl/rsa_key_openssl.h
deleted file mode 100644
index d7935052dc7..00000000000
--- a/chromium/content/child/webcrypto/openssl/rsa_key_openssl.h
+++ /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.
-
-#ifndef CONTENT_CHILD_WEBCRYPTO_OPENSSL_RSA_KEY_OPENSSL_H_
-#define CONTENT_CHILD_WEBCRYPTO_OPENSSL_RSA_KEY_OPENSSL_H_
-
-#include "content/child/webcrypto/algorithm_implementation.h"
-
-namespace content {
-
-namespace webcrypto {
-
-// Base class for an RSA algorithm whose keys additionaly have a hash parameter
-// bound to them. Provides functionality for generating, importing, and
-// exporting keys.
-class RsaHashedAlgorithm : public AlgorithmImplementation {
- public:
- // |all_public_key_usages| and |all_private_key_usages| are the set of
- // WebCrypto key usages that are valid for created keys (public and private
- // respectively).
- //
- // For instance if public keys support encryption and wrapping, and private
- // keys support decryption and unwrapping callers should set:
- // all_public_key_usages = UsageEncrypt | UsageWrap
- // all_private_key_usages = UsageDecrypt | UsageUnwrap
- // This information is used when importing or generating keys, to enforce
- // that valid key usages are allowed.
- RsaHashedAlgorithm(blink::WebCryptoKeyUsageMask all_public_key_usages,
- blink::WebCryptoKeyUsageMask all_private_key_usages)
- : all_public_key_usages_(all_public_key_usages),
- all_private_key_usages_(all_private_key_usages) {}
-
- // For instance "RSA-OAEP-256".
- virtual const char* GetJwkAlgorithm(
- const blink::WebCryptoAlgorithmId hash) const = 0;
-
- Status GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- GenerateKeyResult* result) const override;
-
- Status VerifyKeyUsagesBeforeImportKey(
- blink::WebCryptoKeyFormat format,
- blink::WebCryptoKeyUsageMask usages) const override;
-
- Status ImportKeyPkcs8(const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const override;
-
- Status ImportKeySpki(const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const override;
-
- Status ImportKeyJwk(const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const override;
-
- Status ExportKeyPkcs8(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const override;
-
- Status ExportKeySpki(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const override;
-
- Status ExportKeyJwk(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const override;
-
- private:
- blink::WebCryptoKeyUsageMask all_public_key_usages_;
- blink::WebCryptoKeyUsageMask all_private_key_usages_;
-};
-
-} // namespace webcrypto
-
-} // namespace content
-
-#endif // CONTENT_CHILD_WEBCRYPTO_OPENSSL_RSA_KEY_OPENSSL_H_
diff --git a/chromium/content/child/webcrypto/openssl/rsa_oaep_openssl.cc b/chromium/content/child/webcrypto/openssl/rsa_oaep_openssl.cc
deleted file mode 100644
index b1e40174fa5..00000000000
--- a/chromium/content/child/webcrypto/openssl/rsa_oaep_openssl.cc
+++ /dev/null
@@ -1,153 +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 <openssl/evp.h>
-
-#include "base/stl_util.h"
-#include "content/child/webcrypto/crypto_data.h"
-#include "content/child/webcrypto/openssl/key_openssl.h"
-#include "content/child/webcrypto/openssl/rsa_key_openssl.h"
-#include "content/child/webcrypto/openssl/util_openssl.h"
-#include "content/child/webcrypto/status.h"
-#include "crypto/openssl_util.h"
-#include "crypto/scoped_openssl_types.h"
-#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
-#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
-
-namespace content {
-
-namespace webcrypto {
-
-namespace {
-
-typedef int (*InitFunc)(EVP_PKEY_CTX* ctx);
-typedef int (*EncryptDecryptFunc)(EVP_PKEY_CTX* ctx,
- unsigned char* out,
- size_t* outlen,
- const unsigned char* in,
- size_t inlen);
-
-// Helper for doing either RSA-OAEP encryption or decryption.
-//
-// To encrypt call with:
-// init_func=EVP_PKEY_encrypt_init, encrypt_decrypt_func=EVP_PKEY_encrypt
-//
-// To decrypt call with:
-// init_func=EVP_PKEY_decrypt_init, encrypt_decrypt_func=EVP_PKEY_decrypt
-Status CommonEncryptDecrypt(InitFunc init_func,
- EncryptDecryptFunc encrypt_decrypt_func,
- const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) {
- crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
-
- EVP_PKEY* pkey = AsymKeyOpenSsl::Cast(key)->key();
- const EVP_MD* digest =
- GetDigest(key.algorithm().rsaHashedParams()->hash().id());
- if (!digest)
- return Status::ErrorUnsupported();
-
- crypto::ScopedEVP_PKEY_CTX ctx(EVP_PKEY_CTX_new(pkey, NULL));
-
- if (!init_func(ctx.get()) ||
- 1 != EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_OAEP_PADDING) ||
- 1 != EVP_PKEY_CTX_set_rsa_oaep_md(ctx.get(), digest) ||
- 1 != EVP_PKEY_CTX_set_rsa_mgf1_md(ctx.get(), digest)) {
- return Status::OperationError();
- }
-
- const blink::WebVector<uint8_t>& label =
- algorithm.rsaOaepParams()->optionalLabel();
-
- if (label.size()) {
- // Make a copy of the label, since the ctx takes ownership of it when
- // calling set0_rsa_oaep_label().
- crypto::ScopedOpenSSLBytes label_copy;
- label_copy.reset(static_cast<uint8_t*>(OPENSSL_malloc(label.size())));
- memcpy(label_copy.get(), label.data(), label.size());
-
- if (1 != EVP_PKEY_CTX_set0_rsa_oaep_label(
- ctx.get(), label_copy.release(), label.size())) {
- return Status::OperationError();
- }
- }
-
- // Determine the maximum length of the output.
- size_t outlen = 0;
- if (!encrypt_decrypt_func(
- ctx.get(), NULL, &outlen, data.bytes(), data.byte_length())) {
- return Status::OperationError();
- }
- buffer->resize(outlen);
-
- // Do the actual encryption/decryption.
- if (!encrypt_decrypt_func(ctx.get(),
- vector_as_array(buffer),
- &outlen,
- data.bytes(),
- data.byte_length())) {
- return Status::OperationError();
- }
- buffer->resize(outlen);
-
- return Status::Success();
-}
-
-class RsaOaepImplementation : public RsaHashedAlgorithm {
- public:
- RsaOaepImplementation()
- : RsaHashedAlgorithm(
- blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageWrapKey,
- blink::WebCryptoKeyUsageDecrypt |
- blink::WebCryptoKeyUsageUnwrapKey) {}
-
- const char* GetJwkAlgorithm(
- const blink::WebCryptoAlgorithmId hash) const override {
- switch (hash) {
- case blink::WebCryptoAlgorithmIdSha1:
- return "RSA-OAEP";
- case blink::WebCryptoAlgorithmIdSha256:
- return "RSA-OAEP-256";
- case blink::WebCryptoAlgorithmIdSha384:
- return "RSA-OAEP-384";
- case blink::WebCryptoAlgorithmIdSha512:
- return "RSA-OAEP-512";
- default:
- return NULL;
- }
- }
-
- Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const override {
- if (key.type() != blink::WebCryptoKeyTypePublic)
- return Status::ErrorUnexpectedKeyType();
-
- return CommonEncryptDecrypt(
- EVP_PKEY_encrypt_init, EVP_PKEY_encrypt, algorithm, key, data, buffer);
- }
-
- Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const override {
- if (key.type() != blink::WebCryptoKeyTypePrivate)
- return Status::ErrorUnexpectedKeyType();
-
- return CommonEncryptDecrypt(
- EVP_PKEY_decrypt_init, EVP_PKEY_decrypt, algorithm, key, data, buffer);
- }
-};
-
-} // namespace
-
-AlgorithmImplementation* CreatePlatformRsaOaepImplementation() {
- return new RsaOaepImplementation;
-}
-
-} // namespace webcrypto
-
-} // namespace content
diff --git a/chromium/content/child/webcrypto/openssl/rsa_pss_openssl.cc b/chromium/content/child/webcrypto/openssl/rsa_pss_openssl.cc
deleted file mode 100644
index a6bf4d55a69..00000000000
--- a/chromium/content/child/webcrypto/openssl/rsa_pss_openssl.cc
+++ /dev/null
@@ -1,67 +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/child/webcrypto/openssl/rsa_key_openssl.h"
-#include "content/child/webcrypto/openssl/rsa_sign_openssl.h"
-#include "content/child/webcrypto/status.h"
-#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
-
-namespace content {
-
-namespace webcrypto {
-
-namespace {
-
-class RsaPssImplementation : public RsaHashedAlgorithm {
- public:
- RsaPssImplementation()
- : RsaHashedAlgorithm(blink::WebCryptoKeyUsageVerify,
- blink::WebCryptoKeyUsageSign) {}
-
- const char* GetJwkAlgorithm(
- const blink::WebCryptoAlgorithmId hash) const override {
- switch (hash) {
- case blink::WebCryptoAlgorithmIdSha1:
- return "PS1";
- case blink::WebCryptoAlgorithmIdSha256:
- return "PS256";
- case blink::WebCryptoAlgorithmIdSha384:
- return "PS384";
- case blink::WebCryptoAlgorithmIdSha512:
- return "PS512";
- default:
- return NULL;
- }
- }
-
- Status Sign(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const override {
- return RsaSign(
- key, algorithm.rsaPssParams()->saltLengthBytes(), data, buffer);
- }
-
- Status Verify(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& signature,
- const CryptoData& data,
- bool* signature_match) const override {
- return RsaVerify(key,
- algorithm.rsaPssParams()->saltLengthBytes(),
- signature,
- data,
- signature_match);
- }
-};
-
-} // namespace
-
-AlgorithmImplementation* CreatePlatformRsaPssImplementation() {
- return new RsaPssImplementation;
-}
-
-} // namespace webcrypto
-
-} // namespace content
diff --git a/chromium/content/child/webcrypto/openssl/rsa_sign_openssl.cc b/chromium/content/child/webcrypto/openssl/rsa_sign_openssl.cc
deleted file mode 100644
index 1410aabb25b..00000000000
--- a/chromium/content/child/webcrypto/openssl/rsa_sign_openssl.cc
+++ /dev/null
@@ -1,155 +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 "base/numerics/safe_math.h"
-#include "content/child/webcrypto/crypto_data.h"
-#include "content/child/webcrypto/openssl/key_openssl.h"
-#include "content/child/webcrypto/openssl/rsa_key_openssl.h"
-#include "content/child/webcrypto/openssl/rsa_sign_openssl.h"
-#include "content/child/webcrypto/openssl/util_openssl.h"
-#include "content/child/webcrypto/status.h"
-#include "crypto/openssl_util.h"
-#include "crypto/scoped_openssl_types.h"
-#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
-
-namespace content {
-
-namespace webcrypto {
-
-namespace {
-
-// Extracts the OpenSSL key and digest from a WebCrypto key. The returned
-// pointers will remain valid as long as |key| is alive.
-Status GetPKeyAndDigest(const blink::WebCryptoKey& key,
- EVP_PKEY** pkey,
- const EVP_MD** digest) {
- *pkey = AsymKeyOpenSsl::Cast(key)->key();
-
- *digest = GetDigest(key.algorithm().rsaHashedParams()->hash().id());
- if (!*digest)
- return Status::ErrorUnsupported();
-
- return Status::Success();
-}
-
-// Sets the PSS parameters on |pctx| if the key is for RSA-PSS.
-//
-// Otherwise returns Success without doing anything.
-Status ApplyRsaPssOptions(const blink::WebCryptoKey& key,
- const EVP_MD* const mgf_digest,
- unsigned int salt_length_bytes,
- EVP_PKEY_CTX* pctx) {
- // Only apply RSA-PSS options if the key is for RSA-PSS.
- if (key.algorithm().id() != blink::WebCryptoAlgorithmIdRsaPss) {
- DCHECK_EQ(0u, salt_length_bytes);
- DCHECK_EQ(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, key.algorithm().id());
- return Status::Success();
- }
-
- // BoringSSL takes a signed int for the salt length, and interprets
- // negative values in a special manner. Make sure not to silently underflow.
- base::CheckedNumeric<int> salt_length_bytes_int(salt_length_bytes);
- if (!salt_length_bytes_int.IsValid()) {
- // TODO(eroman): Give a better error message.
- return Status::OperationError();
- }
-
- if (1 != EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) ||
- 1 != EVP_PKEY_CTX_set_rsa_mgf1_md(pctx, mgf_digest) ||
- 1 != EVP_PKEY_CTX_set_rsa_pss_saltlen(
- pctx, salt_length_bytes_int.ValueOrDie())) {
- return Status::OperationError();
- }
-
- return Status::Success();
-}
-
-} // namespace
-
-Status RsaSign(const blink::WebCryptoKey& key,
- unsigned int pss_salt_length_bytes,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) {
- if (key.type() != blink::WebCryptoKeyTypePrivate)
- return Status::ErrorUnexpectedKeyType();
-
- crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
- crypto::ScopedEVP_MD_CTX ctx(EVP_MD_CTX_create());
- EVP_PKEY_CTX* pctx = NULL; // Owned by |ctx|.
-
- EVP_PKEY* private_key = NULL;
- const EVP_MD* digest = NULL;
- Status status = GetPKeyAndDigest(key, &private_key, &digest);
- if (status.IsError())
- return status;
-
- // NOTE: A call to EVP_DigestSignFinal() with a NULL second parameter
- // returns a maximum allocation size, while the call without a NULL returns
- // the real one, which may be smaller.
- size_t sig_len = 0;
- if (!ctx.get() ||
- !EVP_DigestSignInit(ctx.get(), &pctx, digest, NULL, private_key)) {
- return Status::OperationError();
- }
-
- // Set PSS-specific options (if applicable).
- status = ApplyRsaPssOptions(key, digest, pss_salt_length_bytes, pctx);
- if (status.IsError())
- return status;
-
- if (!EVP_DigestSignUpdate(ctx.get(), data.bytes(), data.byte_length()) ||
- !EVP_DigestSignFinal(ctx.get(), NULL, &sig_len)) {
- return Status::OperationError();
- }
-
- buffer->resize(sig_len);
- if (!EVP_DigestSignFinal(ctx.get(), &buffer->front(), &sig_len))
- return Status::OperationError();
-
- buffer->resize(sig_len);
- return Status::Success();
-}
-
-Status RsaVerify(const blink::WebCryptoKey& key,
- unsigned int pss_salt_length_bytes,
- const CryptoData& signature,
- const CryptoData& data,
- bool* signature_match) {
- if (key.type() != blink::WebCryptoKeyTypePublic)
- return Status::ErrorUnexpectedKeyType();
-
- crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
- crypto::ScopedEVP_MD_CTX ctx(EVP_MD_CTX_create());
- EVP_PKEY_CTX* pctx = NULL; // Owned by |ctx|.
-
- EVP_PKEY* public_key = NULL;
- const EVP_MD* digest = NULL;
- Status status = GetPKeyAndDigest(key, &public_key, &digest);
- if (status.IsError())
- return status;
-
- if (!EVP_DigestVerifyInit(ctx.get(), &pctx, digest, NULL, public_key))
- return Status::OperationError();
-
- // Set PSS-specific options (if applicable).
- status = ApplyRsaPssOptions(key, digest, pss_salt_length_bytes, pctx);
- if (status.IsError())
- return status;
-
- if (!EVP_DigestVerifyUpdate(ctx.get(), data.bytes(), data.byte_length()))
- return Status::OperationError();
-
- // Note that the return value can be:
- // 1 --> Success
- // 0 --> Verification failed
- // <0 --> Operation error
- int rv = EVP_DigestVerifyFinal(
- ctx.get(), signature.bytes(), signature.byte_length());
- *signature_match = rv == 1;
- return rv >= 0 ? Status::Success() : Status::OperationError();
-}
-
-} // namespace webcrypto
-
-} // namespace content
diff --git a/chromium/content/child/webcrypto/openssl/rsa_sign_openssl.h b/chromium/content/child/webcrypto/openssl/rsa_sign_openssl.h
deleted file mode 100644
index c750ee2e57c..00000000000
--- a/chromium/content/child/webcrypto/openssl/rsa_sign_openssl.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_CHILD_WEBCRYPTO_OPENSSL_RSA_SIGN_OPENSSL_H_
-#define CONTENT_CHILD_WEBCRYPTO_OPENSSL_RSA_SIGN_OPENSSL_H_
-
-#include <stdint.h>
-
-#include <vector>
-
-namespace blink {
-class WebCryptoKey;
-}
-
-namespace content {
-
-namespace webcrypto {
-
-class CryptoData;
-class Status;
-
-// Helper functions for doing RSA-SSA signing and verification
-// (both PKCS1-v1_5 and PSS flavor).
-//
-// The salt length parameter is only relevant when the key is for RSA-PSS. In
-// other cases it should be set to zero.
-
-Status RsaSign(const blink::WebCryptoKey& key,
- unsigned int pss_salt_length_bytes,
- const CryptoData& data,
- std::vector<uint8_t>* buffer);
-
-Status RsaVerify(const blink::WebCryptoKey& key,
- unsigned int pss_salt_length_bytes,
- const CryptoData& signature,
- const CryptoData& data,
- bool* signature_match);
-
-} // namespace webcrypto
-
-} // namespace content
-
-#endif // CONTENT_CHILD_WEBCRYPTO_OPENSSL_RSA_SIGN_OPENSSL_H_
diff --git a/chromium/content/child/webcrypto/openssl/rsa_ssa_openssl.cc b/chromium/content/child/webcrypto/openssl/rsa_ssa_openssl.cc
deleted file mode 100644
index 1d3b834fc79..00000000000
--- a/chromium/content/child/webcrypto/openssl/rsa_ssa_openssl.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/child/webcrypto/openssl/rsa_key_openssl.h"
-#include "content/child/webcrypto/openssl/rsa_sign_openssl.h"
-#include "content/child/webcrypto/status.h"
-
-namespace content {
-
-namespace webcrypto {
-
-namespace {
-
-class RsaSsaImplementation : public RsaHashedAlgorithm {
- public:
- RsaSsaImplementation()
- : RsaHashedAlgorithm(blink::WebCryptoKeyUsageVerify,
- blink::WebCryptoKeyUsageSign) {}
-
- const char* GetJwkAlgorithm(
- const blink::WebCryptoAlgorithmId hash) const override {
- switch (hash) {
- case blink::WebCryptoAlgorithmIdSha1:
- return "RS1";
- case blink::WebCryptoAlgorithmIdSha256:
- return "RS256";
- case blink::WebCryptoAlgorithmIdSha384:
- return "RS384";
- case blink::WebCryptoAlgorithmIdSha512:
- return "RS512";
- default:
- return NULL;
- }
- }
-
- Status Sign(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const override {
- return RsaSign(key, 0, data, buffer);
- }
-
- Status Verify(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& signature,
- const CryptoData& data,
- bool* signature_match) const override {
- return RsaVerify(key, 0, signature, data, signature_match);
- }
-};
-
-} // namespace
-
-AlgorithmImplementation* CreatePlatformRsaSsaImplementation() {
- return new RsaSsaImplementation;
-}
-
-} // namespace webcrypto
-
-} // namespace content
diff --git a/chromium/content/child/webcrypto/openssl/sha_openssl.cc b/chromium/content/child/webcrypto/openssl/sha_openssl.cc
deleted file mode 100644
index e7ee049fefd..00000000000
--- a/chromium/content/child/webcrypto/openssl/sha_openssl.cc
+++ /dev/null
@@ -1,140 +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 <vector>
-#include <openssl/evp.h>
-#include <openssl/sha.h>
-
-#include "base/logging.h"
-#include "base/stl_util.h"
-#include "content/child/webcrypto/algorithm_implementation.h"
-#include "content/child/webcrypto/crypto_data.h"
-#include "content/child/webcrypto/openssl/util_openssl.h"
-#include "content/child/webcrypto/status.h"
-#include "content/child/webcrypto/webcrypto_util.h"
-#include "crypto/openssl_util.h"
-#include "crypto/scoped_openssl_types.h"
-
-namespace content {
-
-namespace webcrypto {
-
-namespace {
-
-// Implementation of blink::WebCryptoDigester, an internal Blink detail not
-// part of WebCrypto, that allows chunks of data to be streamed in before
-// computing a SHA-* digest (as opposed to ShaImplementation, which computes
-// digests over complete messages)
-class DigestorOpenSsl : public blink::WebCryptoDigestor {
- public:
- explicit DigestorOpenSsl(blink::WebCryptoAlgorithmId algorithm_id)
- : initialized_(false),
- digest_context_(EVP_MD_CTX_create()),
- algorithm_id_(algorithm_id) {}
-
- bool consume(const unsigned char* data, unsigned int size) override {
- return ConsumeWithStatus(data, size).IsSuccess();
- }
-
- Status ConsumeWithStatus(const unsigned char* data, unsigned int size) {
- crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
- Status error = Init();
- if (!error.IsSuccess())
- return error;
-
- if (!EVP_DigestUpdate(digest_context_.get(), data, size))
- return Status::OperationError();
-
- return Status::Success();
- }
-
- bool finish(unsigned char*& result_data,
- unsigned int& result_data_size) override {
- Status error = FinishInternal(result_, &result_data_size);
- if (!error.IsSuccess())
- return false;
- result_data = result_;
- return true;
- }
-
- Status FinishWithVectorAndStatus(std::vector<uint8_t>* result) {
- const int hash_expected_size = EVP_MD_CTX_size(digest_context_.get());
- result->resize(hash_expected_size);
- unsigned char* const hash_buffer = vector_as_array(result);
- unsigned int hash_buffer_size; // ignored
- return FinishInternal(hash_buffer, &hash_buffer_size);
- }
-
- private:
- Status Init() {
- if (initialized_)
- return Status::Success();
-
- const EVP_MD* digest_algorithm = GetDigest(algorithm_id_);
- if (!digest_algorithm)
- return Status::ErrorUnexpected();
-
- if (!digest_context_.get())
- return Status::OperationError();
-
- if (!EVP_DigestInit_ex(digest_context_.get(), digest_algorithm, NULL))
- return Status::OperationError();
-
- initialized_ = true;
- return Status::Success();
- }
-
- Status FinishInternal(unsigned char* result, unsigned int* result_size) {
- crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
- Status error = Init();
- if (!error.IsSuccess())
- return error;
-
- const int hash_expected_size = EVP_MD_CTX_size(digest_context_.get());
- if (hash_expected_size <= 0)
- return Status::ErrorUnexpected();
- DCHECK_LE(hash_expected_size, EVP_MAX_MD_SIZE);
-
- if (!EVP_DigestFinal_ex(digest_context_.get(), result, result_size) ||
- static_cast<int>(*result_size) != hash_expected_size)
- return Status::OperationError();
-
- return Status::Success();
- }
-
- bool initialized_;
- crypto::ScopedEVP_MD_CTX digest_context_;
- blink::WebCryptoAlgorithmId algorithm_id_;
- unsigned char result_[EVP_MAX_MD_SIZE];
-};
-
-class ShaImplementation : public AlgorithmImplementation {
- public:
- Status Digest(const blink::WebCryptoAlgorithm& algorithm,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const override {
- DigestorOpenSsl digestor(algorithm.id());
- Status error = digestor.ConsumeWithStatus(data.bytes(), data.byte_length());
- // http://crbug.com/366427: the spec does not define any other failures for
- // digest, so none of the subsequent errors are spec compliant.
- if (!error.IsSuccess())
- return error;
- return digestor.FinishWithVectorAndStatus(buffer);
- }
-};
-
-} // namespace
-
-AlgorithmImplementation* CreatePlatformShaImplementation() {
- return new ShaImplementation();
-}
-
-scoped_ptr<blink::WebCryptoDigestor> CreatePlatformDigestor(
- blink::WebCryptoAlgorithmId algorithm) {
- return scoped_ptr<blink::WebCryptoDigestor>(new DigestorOpenSsl(algorithm));
-}
-
-} // namespace webcrypto
-
-} // namespace content
diff --git a/chromium/content/child/webcrypto/openssl/sym_key_openssl.cc b/chromium/content/child/webcrypto/openssl/sym_key_openssl.cc
deleted file mode 100644
index 39238335a26..00000000000
--- a/chromium/content/child/webcrypto/openssl/sym_key_openssl.cc
+++ /dev/null
@@ -1,60 +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/child/webcrypto/openssl/sym_key_openssl.h"
-
-#include <vector>
-#include <openssl/rand.h>
-
-#include "content/child/webcrypto/crypto_data.h"
-#include "content/child/webcrypto/generate_key_result.h"
-#include "content/child/webcrypto/openssl/key_openssl.h"
-#include "content/child/webcrypto/status.h"
-#include "crypto/openssl_util.h"
-#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
-
-namespace content {
-
-namespace webcrypto {
-
-Status GenerateSecretKeyOpenSsl(const blink::WebCryptoKeyAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- unsigned keylen_bytes,
- GenerateKeyResult* result) {
- crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
-
- std::vector<unsigned char> random_bytes(keylen_bytes, 0);
-
- if (keylen_bytes > 0) {
- if (!(RAND_bytes(&random_bytes[0], keylen_bytes)))
- return Status::OperationError();
- }
-
- result->AssignSecretKey(
- blink::WebCryptoKey::create(new SymKeyOpenSsl(CryptoData(random_bytes)),
- blink::WebCryptoKeyTypeSecret,
- extractable,
- algorithm,
- usages));
-
- return Status::Success();
-}
-
-Status ImportKeyRawOpenSsl(const CryptoData& key_data,
- const blink::WebCryptoKeyAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) {
- *key = blink::WebCryptoKey::create(new SymKeyOpenSsl(key_data),
- blink::WebCryptoKeyTypeSecret,
- extractable,
- algorithm,
- usages);
- return Status::Success();
-}
-
-} // namespace webcrypto
-
-} // namespace content
diff --git a/chromium/content/child/webcrypto/openssl/sym_key_openssl.h b/chromium/content/child/webcrypto/openssl/sym_key_openssl.h
deleted file mode 100644
index bb5def4704f..00000000000
--- a/chromium/content/child/webcrypto/openssl/sym_key_openssl.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_CHILD_WEBCRYPTO_OPENSSL_SYM_KEY_OPENSSL_H_
-#define CONTENT_CHILD_WEBCRYPTO_OPENSSL_SYM_KEY_OPENSSL_H_
-
-#include "third_party/WebKit/public/platform/WebCrypto.h"
-
-namespace content {
-
-namespace webcrypto {
-
-class CryptoData;
-class GenerateKeyResult;
-class Status;
-
-Status GenerateSecretKeyOpenSsl(const blink::WebCryptoKeyAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- unsigned keylen_bytes,
- GenerateKeyResult* result);
-
-Status ImportKeyRawOpenSsl(const CryptoData& key_data,
- const blink::WebCryptoKeyAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key);
-
-} // namespace webcrypto
-
-} // namespace content
-
-#endif // CONTENT_CHILD_WEBCRYPTO_OPENSSL_SYM_KEY_OPENSSL_H_
diff --git a/chromium/content/child/webcrypto/openssl/util_openssl.cc b/chromium/content/child/webcrypto/openssl/util_openssl.cc
deleted file mode 100644
index 4abf04278bf..00000000000
--- a/chromium/content/child/webcrypto/openssl/util_openssl.cc
+++ /dev/null
@@ -1,249 +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/child/webcrypto/openssl/util_openssl.h"
-
-#include <openssl/evp.h>
-#include <openssl/pkcs12.h>
-
-#include "base/stl_util.h"
-#include "content/child/webcrypto/crypto_data.h"
-#include "content/child/webcrypto/openssl/key_openssl.h"
-#include "content/child/webcrypto/platform_crypto.h"
-#include "content/child/webcrypto/status.h"
-#include "crypto/openssl_util.h"
-
-namespace content {
-
-namespace webcrypto {
-
-namespace {
-
-// Exports an EVP_PKEY public key to the SPKI format.
-Status ExportPKeySpki(EVP_PKEY* key, std::vector<uint8_t>* buffer) {
- crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
- crypto::ScopedBIO bio(BIO_new(BIO_s_mem()));
-
- // TODO(eroman): Use the OID specified by webcrypto spec.
- // http://crbug.com/373545
- if (!i2d_PUBKEY_bio(bio.get(), key))
- return Status::ErrorUnexpected();
-
- char* data = NULL;
- long len = BIO_get_mem_data(bio.get(), &data);
- if (!data || len < 0)
- return Status::ErrorUnexpected();
-
- buffer->assign(data, data + len);
- return Status::Success();
-}
-
-// Exports an EVP_PKEY private key to the PKCS8 format.
-Status ExportPKeyPkcs8(EVP_PKEY* key, std::vector<uint8_t>* buffer) {
- crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
- crypto::ScopedBIO bio(BIO_new(BIO_s_mem()));
-
- // TODO(eroman): Use the OID specified by webcrypto spec.
- // http://crbug.com/373545
- if (!i2d_PKCS8PrivateKeyInfo_bio(bio.get(), key))
- return Status::ErrorUnexpected();
-
- char* data = NULL;
- long len = BIO_get_mem_data(bio.get(), &data);
- if (!data || len < 0)
- return Status::ErrorUnexpected();
-
- buffer->assign(data, data + len);
- return Status::Success();
-}
-
-} // namespace
-
-void PlatformInit() {
- crypto::EnsureOpenSSLInit();
-}
-
-const EVP_MD* GetDigest(blink::WebCryptoAlgorithmId id) {
- switch (id) {
- case blink::WebCryptoAlgorithmIdSha1:
- return EVP_sha1();
- case blink::WebCryptoAlgorithmIdSha256:
- return EVP_sha256();
- case blink::WebCryptoAlgorithmIdSha384:
- return EVP_sha384();
- case blink::WebCryptoAlgorithmIdSha512:
- return EVP_sha512();
- default:
- return NULL;
- }
-}
-
-Status AeadEncryptDecrypt(EncryptOrDecrypt mode,
- const std::vector<uint8_t>& raw_key,
- const CryptoData& data,
- unsigned int tag_length_bytes,
- const CryptoData& iv,
- const CryptoData& additional_data,
- const EVP_AEAD* aead_alg,
- std::vector<uint8_t>* buffer) {
- crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
- EVP_AEAD_CTX ctx;
-
- if (!aead_alg)
- return Status::ErrorUnexpected();
-
- if (!EVP_AEAD_CTX_init(&ctx,
- aead_alg,
- vector_as_array(&raw_key),
- raw_key.size(),
- tag_length_bytes,
- NULL)) {
- return Status::OperationError();
- }
-
- crypto::ScopedOpenSSL<EVP_AEAD_CTX, EVP_AEAD_CTX_cleanup>::Type ctx_cleanup(
- &ctx);
-
- size_t len;
- int ok;
-
- if (mode == DECRYPT) {
- if (data.byte_length() < tag_length_bytes)
- return Status::ErrorDataTooSmall();
-
- buffer->resize(data.byte_length() - tag_length_bytes);
-
- ok = EVP_AEAD_CTX_open(&ctx,
- vector_as_array(buffer),
- &len,
- buffer->size(),
- iv.bytes(),
- iv.byte_length(),
- data.bytes(),
- data.byte_length(),
- additional_data.bytes(),
- additional_data.byte_length());
- } else {
- // No need to check for unsigned integer overflow here (seal fails if
- // the output buffer is too small).
- buffer->resize(data.byte_length() + EVP_AEAD_max_overhead(aead_alg));
-
- ok = EVP_AEAD_CTX_seal(&ctx,
- vector_as_array(buffer),
- &len,
- buffer->size(),
- iv.bytes(),
- iv.byte_length(),
- data.bytes(),
- data.byte_length(),
- additional_data.bytes(),
- additional_data.byte_length());
- }
-
- if (!ok)
- return Status::OperationError();
- buffer->resize(len);
- return Status::Success();
-}
-
-Status CreateWebCryptoPublicKey(crypto::ScopedEVP_PKEY public_key,
- const blink::WebCryptoKeyAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) {
- // Serialize the key at creation time so that if structured cloning is
- // requested it can be done synchronously from the Blink thread.
- std::vector<uint8_t> spki_data;
- Status status = ExportPKeySpki(public_key.get(), &spki_data);
- if (status.IsError())
- return status;
-
- *key = blink::WebCryptoKey::create(
- new AsymKeyOpenSsl(public_key.Pass(), CryptoData(spki_data)),
- blink::WebCryptoKeyTypePublic, extractable, algorithm, usages);
- return Status::Success();
-}
-
-Status CreateWebCryptoPrivateKey(crypto::ScopedEVP_PKEY private_key,
- const blink::WebCryptoKeyAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) {
- // Serialize the key at creation time so that if structured cloning is
- // requested it can be done synchronously from the Blink thread.
- std::vector<uint8_t> pkcs8_data;
- Status status = ExportPKeyPkcs8(private_key.get(), &pkcs8_data);
- if (status.IsError())
- return status;
-
- *key = blink::WebCryptoKey::create(
- new AsymKeyOpenSsl(private_key.Pass(), CryptoData(pkcs8_data)),
- blink::WebCryptoKeyTypePrivate, extractable, algorithm, usages);
- return Status::Success();
-}
-
-Status ImportUnverifiedPkeyFromSpki(const CryptoData& key_data,
- int expected_pkey_id,
- crypto::ScopedEVP_PKEY* pkey) {
- if (!key_data.byte_length())
- return Status::ErrorImportEmptyKeyData();
-
- crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
-
- crypto::ScopedBIO bio(BIO_new_mem_buf(const_cast<uint8_t*>(key_data.bytes()),
- key_data.byte_length()));
- if (!bio.get())
- return Status::ErrorUnexpected();
-
- pkey->reset(d2i_PUBKEY_bio(bio.get(), NULL));
- if (!pkey->get())
- return Status::DataError();
-
- if (EVP_PKEY_id(pkey->get()) != expected_pkey_id)
- return Status::DataError(); // Data did not define expected key type.
-
- return Status::Success();
-}
-
-Status ImportUnverifiedPkeyFromPkcs8(const CryptoData& key_data,
- int expected_pkey_id,
- crypto::ScopedEVP_PKEY* pkey) {
- if (!key_data.byte_length())
- return Status::ErrorImportEmptyKeyData();
-
- crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
-
- crypto::ScopedBIO bio(BIO_new_mem_buf(const_cast<uint8_t*>(key_data.bytes()),
- key_data.byte_length()));
- if (!bio.get())
- return Status::ErrorUnexpected();
-
- crypto::ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>::Type
- p8inf(d2i_PKCS8_PRIV_KEY_INFO_bio(bio.get(), NULL));
- if (!p8inf.get())
- return Status::DataError();
-
- pkey->reset(EVP_PKCS82PKEY(p8inf.get()));
- if (!pkey->get())
- return Status::DataError();
-
- if (EVP_PKEY_id(pkey->get()) != expected_pkey_id)
- return Status::DataError(); // Data did not define expected key type.
-
- return Status::Success();
-}
-
-BIGNUM* CreateBIGNUM(const std::string& n) {
- return BN_bin2bn(reinterpret_cast<const uint8_t*>(n.data()), n.size(), NULL);
-}
-
-std::vector<uint8_t> BIGNUMToVector(const BIGNUM* n) {
- std::vector<uint8_t> v(BN_num_bytes(n));
- BN_bn2bin(n, vector_as_array(&v));
- return v;
-}
-
-} // namespace webcrypto
-
-} // namespace content
diff --git a/chromium/content/child/webcrypto/openssl/util_openssl.h b/chromium/content/child/webcrypto/openssl/util_openssl.h
deleted file mode 100644
index 5031cf27e9b..00000000000
--- a/chromium/content/child/webcrypto/openssl/util_openssl.h
+++ /dev/null
@@ -1,87 +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_CHILD_WEBCRYPTO_OPENSSL_UTIL_OPENSSL_H_
-#define CONTENT_CHILD_WEBCRYPTO_OPENSSL_UTIL_OPENSSL_H_
-
-#include <string>
-#include <vector>
-
-#include <openssl/ossl_typ.h>
-
-#include "crypto/scoped_openssl_types.h"
-#include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
-#include "third_party/WebKit/public/platform/WebCryptoKey.h"
-
-namespace content {
-
-namespace webcrypto {
-
-class CryptoData;
-class Status;
-
-// The values of these constants correspond with the "enc" parameter of
-// EVP_CipherInit_ex(), do not change.
-enum EncryptOrDecrypt { DECRYPT=0, ENCRYPT=1 };
-
-const EVP_MD* GetDigest(blink::WebCryptoAlgorithmId id);
-
-// Does either encryption or decryption for an AEAD algorithm.
-// * |mode| controls whether encryption or decryption is done
-// * |aead_alg| the algorithm (for instance AES-GCM)
-// * |buffer| where the ciphertext or plaintext is written to.
-Status AeadEncryptDecrypt(EncryptOrDecrypt mode,
- const std::vector<uint8_t>& raw_key,
- const CryptoData& data,
- unsigned int tag_length_bytes,
- const CryptoData& iv,
- const CryptoData& additional_data,
- const EVP_AEAD* aead_alg,
- std::vector<uint8_t>* buffer);
-
-// Creates a WebCrypto public key given an EVP_PKEY. This step includes
-// exporting the key to SPKI format, for use by serialization later.
-Status CreateWebCryptoPublicKey(
- crypto::ScopedEVP_PKEY public_key,
- const blink::WebCryptoKeyAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key);
-
-// Creates a WebCrypto private key given an EVP_PKEY. This step includes
-// exporting the key to PKCS8 format, for use by serialization later.
-Status CreateWebCryptoPrivateKey(
- crypto::ScopedEVP_PKEY private_key,
- const blink::WebCryptoKeyAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key);
-
-// Imports SPKI bytes to an EVP_PKEY for a public key. The resulting asymmetric
-// key may be invalid, and should be verified using something like
-// RSA_check_key(). The only validation performed by this function is to ensure
-// the key type matched |expected_pkey_id|.
-Status ImportUnverifiedPkeyFromSpki(const CryptoData& key_data,
- int expected_pkey_id,
- crypto::ScopedEVP_PKEY* pkey);
-
-// Imports PKCS8 bytes to an EVP_PKEY for a private key. The resulting
-// asymmetric key may be invalid, and should be verified using something like
-// RSA_check_key(). The only validation performed by this function is to ensure
-// the key type matched |expected_pkey_id|.
-Status ImportUnverifiedPkeyFromPkcs8(const CryptoData& key_data,
- int expected_pkey_id,
- crypto::ScopedEVP_PKEY* pkey);
-
-// Allocates a new BIGNUM given a std::string big-endian representation.
-BIGNUM* CreateBIGNUM(const std::string& n);
-
-// Converts a BIGNUM to a big endian byte array.
-std::vector<uint8_t> BIGNUMToVector(const BIGNUM* n);
-
-} // namespace webcrypto
-
-} // namespace content
-
-#endif // CONTENT_CHILD_WEBCRYPTO_OPENSSL_UTIL_OPENSSL_H_
diff --git a/chromium/content/child/webcrypto/platform_crypto.h b/chromium/content/child/webcrypto/platform_crypto.h
deleted file mode 100644
index 2977b9c97f5..00000000000
--- a/chromium/content/child/webcrypto/platform_crypto.h
+++ /dev/null
@@ -1,43 +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_CHILD_WEBCRYPTO_PLATFORM_CRYPTO_H_
-#define CONTENT_CHILD_WEBCRYPTO_PLATFORM_CRYPTO_H_
-
-#include <stdint.h>
-#include <vector>
-
-#include "base/memory/scoped_ptr.h"
-#include "third_party/WebKit/public/platform/WebCrypto.h"
-
-// The definitions for these methods lives in either nss/ or openssl/
-namespace content {
-
-namespace webcrypto {
-
-class AlgorithmImplementation;
-
-void PlatformInit();
-
-scoped_ptr<blink::WebCryptoDigestor> CreatePlatformDigestor(
- blink::WebCryptoAlgorithmId algorithm);
-
-AlgorithmImplementation* CreatePlatformShaImplementation();
-AlgorithmImplementation* CreatePlatformAesCbcImplementation();
-AlgorithmImplementation* CreatePlatformAesCtrImplementation();
-AlgorithmImplementation* CreatePlatformAesGcmImplementation();
-AlgorithmImplementation* CreatePlatformAesKwImplementation();
-AlgorithmImplementation* CreatePlatformHmacImplementation();
-AlgorithmImplementation* CreatePlatformRsaOaepImplementation();
-AlgorithmImplementation* CreatePlatformRsaSsaImplementation();
-AlgorithmImplementation* CreatePlatformRsaPssImplementation();
-
-bool PlatformSerializeKeyForClone(const blink::WebCryptoKey& key,
- blink::WebVector<uint8_t>* key_data);
-
-} // namespace webcrypto
-
-} // namespace content
-
-#endif // CONTENT_CHILD_WEBCRYPTO_PLATFORM_CRYPTO_H_
diff --git a/chromium/content/child/webcrypto/status.cc b/chromium/content/child/webcrypto/status.cc
deleted file mode 100644
index a7afdb3c063..00000000000
--- a/chromium/content/child/webcrypto/status.cc
+++ /dev/null
@@ -1,258 +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/child/webcrypto/status.h"
-
-namespace content {
-
-namespace webcrypto {
-
-bool Status::IsError() const {
- return type_ == TYPE_ERROR;
-}
-
-bool Status::IsSuccess() const {
- return type_ == TYPE_SUCCESS;
-}
-
-Status Status::Success() {
- return Status(TYPE_SUCCESS);
-}
-
-Status Status::OperationError() {
- return Status(blink::WebCryptoErrorTypeOperation, "");
-}
-
-Status Status::DataError() {
- return Status(blink::WebCryptoErrorTypeData, "");
-}
-
-Status Status::ErrorJwkNotDictionary() {
- return Status(blink::WebCryptoErrorTypeData,
- "JWK input could not be parsed to a JSON dictionary");
-}
-
-Status Status::ErrorJwkPropertyMissing(const std::string& property) {
- return Status(blink::WebCryptoErrorTypeData,
- "The required JWK property \"" + property + "\" was missing");
-}
-
-Status Status::ErrorJwkPropertyWrongType(const std::string& property,
- const std::string& expected_type) {
- return Status(
- blink::WebCryptoErrorTypeData,
- "The JWK property \"" + property + "\" must be a " + expected_type);
-}
-
-Status Status::ErrorJwkBase64Decode(const std::string& property) {
- return Status(
- blink::WebCryptoErrorTypeData,
- "The JWK property \"" + property + "\" could not be base64 decoded");
-}
-
-Status Status::ErrorJwkExtInconsistent() {
- return Status(
- blink::WebCryptoErrorTypeData,
- "The \"ext\" property of the JWK dictionary is inconsistent what that "
- "specified by the Web Crypto call");
-}
-
-Status Status::ErrorJwkAlgorithmInconsistent() {
- return Status(blink::WebCryptoErrorTypeData,
- "The JWK \"alg\" property was inconsistent with that specified "
- "by the Web Crypto call");
-}
-
-Status Status::ErrorJwkUnrecognizedUse() {
- return Status(blink::WebCryptoErrorTypeData,
- "The JWK \"use\" property could not be parsed");
-}
-
-Status Status::ErrorJwkUnrecognizedKeyop() {
- return Status(blink::WebCryptoErrorTypeData,
- "The JWK \"key_ops\" property could not be parsed");
-}
-
-Status Status::ErrorJwkUseInconsistent() {
- return Status(blink::WebCryptoErrorTypeData,
- "The JWK \"use\" property was inconsistent with that specified "
- "by the Web Crypto call. The JWK usage must be a superset of "
- "those requested");
-}
-
-Status Status::ErrorJwkKeyopsInconsistent() {
- return Status(blink::WebCryptoErrorTypeData,
- "The JWK \"key_ops\" property was inconsistent with that "
- "specified by the Web Crypto call. The JWK usage must be a "
- "superset of those requested");
-}
-
-Status Status::ErrorJwkUseAndKeyopsInconsistent() {
- return Status(blink::WebCryptoErrorTypeData,
- "The JWK \"use\" and \"key_ops\" properties were both found "
- "but are inconsistent with each other.");
-}
-
-Status Status::ErrorJwkUnexpectedKty(const std::string& expected) {
- return Status(blink::WebCryptoErrorTypeData,
- "The JWK \"kty\" property was not \"" + expected + "\"");
-}
-
-Status Status::ErrorJwkIncorrectKeyLength() {
- return Status(blink::WebCryptoErrorTypeData,
- "The JWK \"k\" property did not include the right length "
- "of key data for the given algorithm.");
-}
-
-Status Status::ErrorJwkEmptyBigInteger(const std::string& property) {
- return Status(blink::WebCryptoErrorTypeData,
- "The JWK \"" + property + "\" property was empty.");
-}
-
-Status Status::ErrorJwkBigIntegerHasLeadingZero(const std::string& property) {
- return Status(
- blink::WebCryptoErrorTypeData,
- "The JWK \"" + property + "\" property contained a leading zero.");
-}
-
-Status Status::ErrorJwkDuplicateKeyOps() {
- return Status(blink::WebCryptoErrorTypeData,
- "The \"key_ops\" property of the JWK dictionary contains "
- "duplicate usages.");
-}
-
-Status Status::ErrorImportEmptyKeyData() {
- return Status(blink::WebCryptoErrorTypeData, "No key data was provided");
-}
-
-Status Status::ErrorUnsupportedImportKeyFormat() {
- return Status(blink::WebCryptoErrorTypeNotSupported,
- "Unsupported import key format for algorithm");
-}
-
-Status Status::ErrorUnsupportedExportKeyFormat() {
- return Status(blink::WebCryptoErrorTypeNotSupported,
- "Unsupported export key format for algorithm");
-}
-
-Status Status::ErrorImportAesKeyLength() {
- return Status(blink::WebCryptoErrorTypeData,
- "AES key data must be 128, 192 or 256 bits");
-}
-
-Status Status::ErrorAes192BitUnsupported() {
- return Status(blink::WebCryptoErrorTypeNotSupported,
- "192-bit AES keys are not supported");
-}
-
-Status Status::ErrorUnexpectedKeyType() {
- return Status(blink::WebCryptoErrorTypeInvalidAccess,
- "The key is not of the expected type");
-}
-
-Status Status::ErrorIncorrectSizeAesCbcIv() {
- return Status(blink::WebCryptoErrorTypeData,
- "The \"iv\" has an unexpected length -- must be 16 bytes");
-}
-
-Status Status::ErrorIncorrectSizeAesCtrCounter() {
- return Status(blink::WebCryptoErrorTypeData,
- "The \"counter\" has an unexpected length -- must be 16 bytes");
-}
-
-Status Status::ErrorInvalidAesCtrCounterLength() {
- return Status(blink::WebCryptoErrorTypeData,
- "The \"length\" property must be >= 1 and <= 128");
-}
-
-Status Status::ErrorAesCtrInputTooLongCounterRepeated() {
- return Status(blink::WebCryptoErrorTypeData,
- "The input is too large for the counter length.");
-}
-
-Status Status::ErrorDataTooLarge() {
- return Status(blink::WebCryptoErrorTypeData,
- "The provided data is too large");
-}
-
-Status Status::ErrorDataTooSmall() {
- return Status(blink::WebCryptoErrorTypeData,
- "The provided data is too small");
-}
-
-Status Status::ErrorUnsupported() {
- return ErrorUnsupported("The requested operation is unsupported");
-}
-
-Status Status::ErrorUnsupported(const std::string& message) {
- return Status(blink::WebCryptoErrorTypeNotSupported, message);
-}
-
-Status Status::ErrorUnexpected() {
- return Status(blink::WebCryptoErrorTypeUnknown,
- "Something unexpected happened...");
-}
-
-Status Status::ErrorInvalidAesGcmTagLength() {
- return Status(
- blink::WebCryptoErrorTypeData,
- "The tag length is invalid: Must be 32, 64, 96, 104, 112, 120, or 128 "
- "bits");
-}
-
-Status Status::ErrorInvalidAesKwDataLength() {
- return Status(blink::WebCryptoErrorTypeData,
- "The AES-KW input data length is invalid: not a multiple of 8 "
- "bytes");
-}
-
-Status Status::ErrorGenerateKeyPublicExponent() {
- return Status(blink::WebCryptoErrorTypeData,
- "The \"publicExponent\" must be either 3 or 65537");
-}
-
-Status Status::ErrorImportRsaEmptyModulus() {
- return Status(blink::WebCryptoErrorTypeData, "The modulus is empty");
-}
-
-Status Status::ErrorGenerateRsaUnsupportedModulus() {
- return Status(blink::WebCryptoErrorTypeNotSupported,
- "The modulus length must be a multiple of 8 bits and >= 256 "
- "and <= 16384");
-}
-
-Status Status::ErrorImportRsaEmptyExponent() {
- return Status(blink::WebCryptoErrorTypeData,
- "No bytes for the exponent were provided");
-}
-
-Status Status::ErrorKeyNotExtractable() {
- return Status(blink::WebCryptoErrorTypeInvalidAccess,
- "They key is not extractable");
-}
-
-Status Status::ErrorGenerateKeyLength() {
- return Status(blink::WebCryptoErrorTypeData,
- "Invalid key length: it is either zero or not a multiple of 8 "
- "bits");
-}
-
-Status Status::ErrorCreateKeyBadUsages() {
- return Status(blink::WebCryptoErrorTypeSyntax,
- "Cannot create a key using the specified key usages.");
-}
-
-Status::Status(blink::WebCryptoErrorType error_type,
- const std::string& error_details_utf8)
- : type_(TYPE_ERROR),
- error_type_(error_type),
- error_details_(error_details_utf8) {
-}
-
-Status::Status(Type type) : type_(type) {
-}
-
-} // namespace webcrypto
-
-} // namespace content
diff --git a/chromium/content/child/webcrypto/status.h b/chromium/content/child/webcrypto/status.h
deleted file mode 100644
index 4c1aae6e185..00000000000
--- a/chromium/content/child/webcrypto/status.h
+++ /dev/null
@@ -1,235 +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_CHILD_WEBCRYPTO_STATUS_H_
-#define CONTENT_CHILD_WEBCRYPTO_STATUS_H_
-
-#include <string>
-#include "content/common/content_export.h"
-#include "third_party/WebKit/public/platform/WebCrypto.h"
-
-namespace content {
-
-namespace webcrypto {
-
-// Status indicates whether an operation completed successfully, or with an
-// error. The error is used for verification in unit-tests, as well as for
-// display to the user.
-//
-// As such, it is important that errors DO NOT reveal any sensitive material
-// (like key bytes).
-class CONTENT_EXPORT Status {
- public:
- Status() : type_(TYPE_ERROR) {}
-
- // Returns true if the Status represents an error (any one of them).
- bool IsError() const;
-
- // Returns true if the Status represent success.
- bool IsSuccess() const;
-
- // Returns a UTF-8 error message (non-localized) describing the error.
- const std::string& error_details() const { return error_details_; }
-
- blink::WebCryptoErrorType error_type() const { return error_type_; }
-
- // Constructs a status representing success.
- static Status Success();
-
- // Constructs a status representing a generic operation error. It contains no
- // extra details.
- static Status OperationError();
-
- // Constructs a status representing a generic data error. It contains no
- // extra details.
- static Status DataError();
-
- // ------------------------------------
- // Errors when importing a JWK formatted key
- // ------------------------------------
-
- // The key bytes could not parsed as JSON dictionary. This either
- // means there was a parsing error, or the JSON object was not
- // convertable to a dictionary.
- static Status ErrorJwkNotDictionary();
-
- // The required property |property| was missing.
- static Status ErrorJwkPropertyMissing(const std::string& property);
-
- // The property |property| was not of type |expected_type|.
- static Status ErrorJwkPropertyWrongType(const std::string& property,
- const std::string& expected_type);
-
- // The property |property| was a string, however could not be successfully
- // base64 decoded.
- static Status ErrorJwkBase64Decode(const std::string& property);
-
- // The "ext" parameter was specified but was
- // incompatible with the value requested by the Web Crypto call.
- static Status ErrorJwkExtInconsistent();
-
- // The "alg" parameter is incompatible with the (optional) Algorithm
- // specified by the Web Crypto import operation.
- static Status ErrorJwkAlgorithmInconsistent();
-
- // The "use" parameter was specified, however it couldn't be converted to an
- // equivalent Web Crypto usage.
- static Status ErrorJwkUnrecognizedUse();
-
- // The "key_ops" parameter was specified, however one of the values in the
- // array couldn't be converted to an equivalent Web Crypto usage.
- static Status ErrorJwkUnrecognizedKeyop();
-
- // The "use" parameter was specified, however it is incompatible with that
- // specified by the Web Crypto import operation.
- static Status ErrorJwkUseInconsistent();
-
- // The "key_ops" parameter was specified, however it is incompatible with that
- // specified by the Web Crypto import operation.
- static Status ErrorJwkKeyopsInconsistent();
-
- // Both the "key_ops" and the "use" parameters were specified, however they
- // are incompatible with each other.
- static Status ErrorJwkUseAndKeyopsInconsistent();
-
- // The "kty" parameter was given and was a string, however it was not the
- // expected value.
- static Status ErrorJwkUnexpectedKty(const std::string& expected);
-
- // The amount of key data provided was incompatible with the selected
- // algorithm. For instance if the algorith name was A128CBC then EXACTLY
- // 128-bits of key data must have been provided. If 192-bits of key data were
- // given that is an error.
- static Status ErrorJwkIncorrectKeyLength();
-
- // The JWK property |property| is supposed to represent a big-endian unsigned
- // integer, however was the empty string.
- static Status ErrorJwkEmptyBigInteger(const std::string& property);
-
- // The big-endian unsigned integer |property| contained leading zeros. This
- // violates the JWA requirement that such octet strings be minimal.
- static Status ErrorJwkBigIntegerHasLeadingZero(const std::string& property);
-
- // The key_ops lists a usage more than once.
- static Status ErrorJwkDuplicateKeyOps();
-
- // ------------------------------------
- // Other errors
- // ------------------------------------
-
- // No key data was provided when importing an spki, pkcs8, or jwk formatted
- // key. This does not apply to raw format, since it is possible to have empty
- // key data there.
- static Status ErrorImportEmptyKeyData();
-
- // Tried importing a key using an unsupported format for the key type (for
- // instance importing an HMAC key using format=spki).
- static Status ErrorUnsupportedImportKeyFormat();
-
- // Tried exporting a key using an unsupported format for the key type (for
- // instance exporting an HMAC key using format=spki).
- static Status ErrorUnsupportedExportKeyFormat();
-
- // The key data buffer provided for importKey() is an incorrect length for
- // AES.
- static Status ErrorImportAesKeyLength();
-
- // 192-bit AES keys are valid, however unsupported.
- static Status ErrorAes192BitUnsupported();
-
- // The wrong key was used for the operation. For instance, a public key was
- // used to verify a RsaSsaPkcs1v1_5 signature, or tried exporting a private
- // key using spki format.
- static Status ErrorUnexpectedKeyType();
-
- // When doing an AES-CBC encryption/decryption, the "iv" parameter was not 16
- // bytes.
- static Status ErrorIncorrectSizeAesCbcIv();
-
- // When doing AES-CTR encryption/decryption, the "counter" parameter was not
- // 16 bytes.
- static Status ErrorIncorrectSizeAesCtrCounter();
-
- // When doing AES-CTR encryption/decryption, the "length" parameter for the
- // counter was out of range.
- static Status ErrorInvalidAesCtrCounterLength();
-
- // The input to encrypt/decrypt was too large. Based on the counter size, it
- // would cause the counter to wraparound and repeat earlier values.
- static Status ErrorAesCtrInputTooLongCounterRepeated();
-
- // The data provided to an encrypt/decrypt/sign/verify operation was too
- // large. This can either represent an internal limitation (for instance
- // representing buffer lengths as uints).
- static Status ErrorDataTooLarge();
-
- // The data provided to an encrypt/decrypt/sign/verify operation was too
- // small. This usually represents an algorithm restriction (for instance
- // AES-KW requires a minimum of 24 bytes input data).
- static Status ErrorDataTooSmall();
-
- // Something was unsupported or unimplemented. This can mean the algorithm in
- // question was unsupported, some parameter combination was unsupported, or
- // something has not yet been implemented.
- static Status ErrorUnsupported();
- static Status ErrorUnsupported(const std::string& message);
-
- // Something unexpected happened in the code, which implies there is a
- // source-level bug. These should not happen, but safer to fail than simply
- // DCHECK.
- static Status ErrorUnexpected();
-
- // The authentication tag length specified for AES-GCM encrypt/decrypt was
- // not 32, 64, 96, 104, 112, 120, or 128.
- static Status ErrorInvalidAesGcmTagLength();
-
- // The input data given to an AES-KW encrypt/decrypt operation was not a
- // multiple of 8 bytes, as required by RFC 3394.
- static Status ErrorInvalidAesKwDataLength();
-
- // The "publicExponent" used to generate a key was invalid or unsupported.
- // Only values of 3 and 65537 are allowed.
- static Status ErrorGenerateKeyPublicExponent();
-
- // The modulus bytes were empty when importing an RSA public key.
- static Status ErrorImportRsaEmptyModulus();
-
- // The modulus length was unsupported when generating an RSA key pair.
- static Status ErrorGenerateRsaUnsupportedModulus();
-
- // The exponent bytes were empty when importing an RSA public key.
- static Status ErrorImportRsaEmptyExponent();
-
- // An unextractable key was used by an operation which exports the key data.
- static Status ErrorKeyNotExtractable();
-
- // The key length specified when generating a key was invalid. Either it was
- // zero, or it was not a multiple of 8 bits.
- static Status ErrorGenerateKeyLength();
-
- // Attempted to create a key (either by importKey(), generateKey(), or
- // unwrapKey()) however the key usages were not applicable for the key type
- // and algorithm.
- static Status ErrorCreateKeyBadUsages();
-
- private:
- enum Type { TYPE_ERROR, TYPE_SUCCESS };
-
- // Constructs an error with the specified error type and message.
- Status(blink::WebCryptoErrorType error_type,
- const std::string& error_details_utf8);
-
- // Constructs a success or error without any details.
- explicit Status(Type type);
-
- Type type_;
- blink::WebCryptoErrorType error_type_;
- std::string error_details_;
-};
-
-} // namespace webcrypto
-
-} // namespace content
-
-#endif // CONTENT_CHILD_WEBCRYPTO_STATUS_H_
diff --git a/chromium/content/child/webcrypto/structured_clone.cc b/chromium/content/child/webcrypto/structured_clone.cc
deleted file mode 100644
index 68d449a065e..00000000000
--- a/chromium/content/child/webcrypto/structured_clone.cc
+++ /dev/null
@@ -1,136 +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/child/webcrypto/structured_clone.h"
-
-#include "base/logging.h"
-#include "content/child/webcrypto/algorithm_dispatch.h"
-#include "content/child/webcrypto/platform_crypto.h"
-#include "content/child/webcrypto/status.h"
-#include "content/child/webcrypto/webcrypto_util.h"
-#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
-
-namespace content {
-
-namespace webcrypto {
-
-namespace {
-
-// Returns the key format to use for structured cloning.
-blink::WebCryptoKeyFormat GetCloneFormatForKeyType(
- blink::WebCryptoKeyType type) {
- switch (type) {
- case blink::WebCryptoKeyTypeSecret:
- return blink::WebCryptoKeyFormatRaw;
- case blink::WebCryptoKeyTypePublic:
- return blink::WebCryptoKeyFormatSpki;
- case blink::WebCryptoKeyTypePrivate:
- return blink::WebCryptoKeyFormatPkcs8;
- }
-
- NOTREACHED();
- return blink::WebCryptoKeyFormatRaw;
-}
-
-// Converts a KeyAlgorithm into an equivalent Algorithm for import.
-blink::WebCryptoAlgorithm KeyAlgorithmToImportAlgorithm(
- const blink::WebCryptoKeyAlgorithm& algorithm) {
- switch (algorithm.paramsType()) {
- case blink::WebCryptoKeyAlgorithmParamsTypeAes:
- return CreateAlgorithm(algorithm.id());
- case blink::WebCryptoKeyAlgorithmParamsTypeHmac:
- return CreateHmacImportAlgorithm(algorithm.hmacParams()->hash().id());
- case blink::WebCryptoKeyAlgorithmParamsTypeRsaHashed:
- return CreateRsaHashedImportAlgorithm(
- algorithm.id(), algorithm.rsaHashedParams()->hash().id());
- case blink::WebCryptoKeyAlgorithmParamsTypeNone:
- break;
- default:
- break;
- }
- return blink::WebCryptoAlgorithm::createNull();
-}
-
-// There is some duplicated information in the serialized format used by
-// structured clone (since the KeyAlgorithm is serialized separately from the
-// key data). Use this extra information to further validate what was
-// deserialized from the key data.
-//
-// A failure here implies either a bug in the code, or that the serialized data
-// was corrupted.
-bool ValidateDeserializedKey(const blink::WebCryptoKey& key,
- const blink::WebCryptoKeyAlgorithm& algorithm,
- blink::WebCryptoKeyType type) {
- if (algorithm.id() != key.algorithm().id())
- return false;
-
- if (key.type() != type)
- return false;
-
- switch (algorithm.paramsType()) {
- case blink::WebCryptoKeyAlgorithmParamsTypeAes:
- if (algorithm.aesParams()->lengthBits() !=
- key.algorithm().aesParams()->lengthBits())
- return false;
- break;
- case blink::WebCryptoKeyAlgorithmParamsTypeRsaHashed:
- if (algorithm.rsaHashedParams()->modulusLengthBits() !=
- key.algorithm().rsaHashedParams()->modulusLengthBits())
- return false;
- if (algorithm.rsaHashedParams()->publicExponent().size() !=
- key.algorithm().rsaHashedParams()->publicExponent().size())
- return false;
- if (memcmp(algorithm.rsaHashedParams()->publicExponent().data(),
- key.algorithm().rsaHashedParams()->publicExponent().data(),
- key.algorithm().rsaHashedParams()->publicExponent().size()) !=
- 0)
- return false;
- break;
- case blink::WebCryptoKeyAlgorithmParamsTypeNone:
- case blink::WebCryptoKeyAlgorithmParamsTypeHmac:
- break;
- default:
- return false;
- }
-
- return true;
-}
-
-} // namespace
-
-// Note that this function is called from the target Blink thread.
-bool SerializeKeyForClone(const blink::WebCryptoKey& key,
- blink::WebVector<uint8_t>* key_data) {
- return PlatformSerializeKeyForClone(key, key_data);
-}
-
-// Note that this function is called from the target Blink thread.
-bool DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm,
- blink::WebCryptoKeyType type,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- const CryptoData& key_data,
- blink::WebCryptoKey* key) {
- // TODO(eroman): This should not call into the platform crypto layer.
- // Otherwise it runs the risk of stalling while the NSS/OpenSSL global locks
- // are held.
- //
- // An alternate approach is to defer the key import until the key is used.
- // However this means that any deserialization errors would have to be
- // surfaced as WebCrypto errors, leading to slightly different behaviors. For
- // instance you could clone a key which fails to be deserialized.
- Status status = ImportKey(GetCloneFormatForKeyType(type),
- key_data,
- KeyAlgorithmToImportAlgorithm(algorithm),
- extractable,
- usages,
- key);
- if (status.IsError())
- return false;
- return ValidateDeserializedKey(*key, algorithm, type);
-}
-
-} // namespace webcrypto
-
-} // namespace content
diff --git a/chromium/content/child/webcrypto/structured_clone.h b/chromium/content/child/webcrypto/structured_clone.h
deleted file mode 100644
index 3e218c85a80..00000000000
--- a/chromium/content/child/webcrypto/structured_clone.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_CHILD_WEBCRYPTO_STRUCTURED_CLONE_H_
-#define CONTENT_CHILD_WEBCRYPTO_STRUCTURED_CLONE_H_
-
-#include <stdint.h>
-
-#include "third_party/WebKit/public/platform/WebCrypto.h"
-
-namespace content {
-
-namespace webcrypto {
-
-class CryptoData;
-
-// Called on the target Blink thread.
-bool SerializeKeyForClone(const blink::WebCryptoKey& key,
- blink::WebVector<uint8_t>* key_data);
-
-// Called on the target Blink thread.
-bool DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm,
- blink::WebCryptoKeyType type,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- const CryptoData& key_data,
- blink::WebCryptoKey* key);
-
-} // namespace webcrypto
-
-} // namespace content
-
-#endif // CONTENT_CHILD_WEBCRYPTO_STRUCTURED_CLONE_H_
diff --git a/chromium/content/child/webcrypto/webcrypto_impl.cc b/chromium/content/child/webcrypto/webcrypto_impl.cc
deleted file mode 100644
index 2099a901073..00000000000
--- a/chromium/content/child/webcrypto/webcrypto_impl.cc
+++ /dev/null
@@ -1,727 +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/child/webcrypto/webcrypto_impl.h"
-
-#include "base/bind.h"
-#include "base/lazy_instance.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/single_thread_task_runner.h"
-#include "base/stl_util.h"
-#include "base/task_runner.h"
-#include "base/thread_task_runner_handle.h"
-#include "base/threading/sequenced_worker_pool.h"
-#include "base/threading/worker_pool.h"
-#include "content/child/webcrypto/algorithm_dispatch.h"
-#include "content/child/webcrypto/crypto_data.h"
-#include "content/child/webcrypto/generate_key_result.h"
-#include "content/child/webcrypto/status.h"
-#include "content/child/webcrypto/structured_clone.h"
-#include "content/child/webcrypto/webcrypto_util.h"
-#include "content/child/worker_thread_task_runner.h"
-#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
-#include "third_party/WebKit/public/platform/WebString.h"
-
-namespace content {
-
-using webcrypto::Status;
-
-namespace {
-
-// ---------------------
-// Threading
-// ---------------------
-//
-// WebCrypto operations can be slow. For instance generating an RSA key can
-// take hundreds of milliseconds to several seconds.
-//
-// Moreover the underlying crypto libraries are not threadsafe when operating
-// on the same key.
-//
-// The strategy used here is to run a sequenced worker pool for all WebCrypto
-// operations. This pool (of 1 threads) is also used by requests started from
-// Blink Web Workers.
-//
-// A few notes to keep in mind:
-//
-// * PostTaskAndReply() cannot be used for two reasons:
-//
-// (1) Blink web worker threads do not have an associated message loop so
-// construction of the reply callback will crash.
-//
-// (2) PostTaskAndReply() handles failure posting the reply by leaking the
-// callback, rather than destroying it. In the case of Web Workers this
-// condition is reachable via normal execution, since Web Workers can
-// be stopped before the WebCrypto operation has finished. A policy of
-// leaking would therefore be problematic.
-//
-// * blink::WebArrayBuffer is NOT threadsafe, and should therefore be allocated
-// on the target Blink thread.
-//
-// TODO(eroman): Is there any way around this? Copying the result between
-// threads is silly.
-//
-// * WebCryptoAlgorithm and WebCryptoKey are threadsafe (however the key's
-// handle(), which wraps an NSS/OpenSSL type, may not be and should only be
-// used from the webcrypto thread).
-//
-// * blink::WebCryptoResult is not threadsafe and should only be operated on
-// the target Blink thread. HOWEVER, it is safe to delete it from any thread.
-// This can happen if by the time the operation has completed in the crypto
-// worker pool, the Blink worker thread that initiated the request is gone.
-// Posting back to the origin thread will fail, and the WebCryptoResult will
-// be deleted while running in the crypto worker pool.
-class CryptoThreadPool {
- public:
- CryptoThreadPool()
- : worker_pool_(new base::SequencedWorkerPool(1, "WebCrypto")),
- task_runner_(worker_pool_->GetSequencedTaskRunnerWithShutdownBehavior(
- worker_pool_->GetSequenceToken(),
- base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN)) {}
-
- static bool PostTask(const tracked_objects::Location& from_here,
- const base::Closure& task);
-
- private:
- scoped_refptr<base::SequencedWorkerPool> worker_pool_;
- scoped_refptr<base::SequencedTaskRunner> task_runner_;
-};
-
-base::LazyInstance<CryptoThreadPool>::Leaky crypto_thread_pool =
- LAZY_INSTANCE_INITIALIZER;
-
-bool CryptoThreadPool::PostTask(const tracked_objects::Location& from_here,
- const base::Closure& task) {
- return crypto_thread_pool.Get().task_runner_->PostTask(from_here, task);
-}
-
-void CompleteWithThreadPoolError(blink::WebCryptoResult* result) {
- result->completeWithError(blink::WebCryptoErrorTypeOperation,
- "Failed posting to crypto worker pool");
-}
-
-void CompleteWithError(const Status& status, blink::WebCryptoResult* result) {
- DCHECK(status.IsError());
-
- result->completeWithError(status.error_type(),
- blink::WebString::fromUTF8(status.error_details()));
-}
-
-void CompleteWithBufferOrError(const Status& status,
- const std::vector<uint8_t>& buffer,
- blink::WebCryptoResult* result) {
- if (status.IsError()) {
- CompleteWithError(status, result);
- } else {
- if (buffer.size() > UINT_MAX) {
- // WebArrayBuffers have a smaller range than std::vector<>, so
- // theoretically this could overflow.
- CompleteWithError(Status::ErrorUnexpected(), result);
- } else {
- result->completeWithBuffer(vector_as_array(&buffer), buffer.size());
- }
- }
-}
-
-void CompleteWithKeyOrError(const Status& status,
- const blink::WebCryptoKey& key,
- blink::WebCryptoResult* result) {
- if (status.IsError()) {
- CompleteWithError(status, result);
- } else {
- result->completeWithKey(key);
- }
-}
-
-// Gets a task runner for the current thread. The current thread is either:
-//
-// * The main Blink thread
-// * A Blink web worker thread
-//
-// A different mechanism is needed for posting to these threads. The main
-// thread has an associated message loop and can simply use
-// base::ThreadTaskRunnerHandle. Whereas the web worker threads are managed by
-// Blink and need to be indirected through WorkerThreadTaskRunner.
-scoped_refptr<base::TaskRunner> GetCurrentBlinkThread() {
- if (base::ThreadTaskRunnerHandle::IsSet())
- return base::ThreadTaskRunnerHandle::Get();
- return WorkerThreadTaskRunner::current();
-}
-
-// --------------------------------------------------------------------
-// State
-// --------------------------------------------------------------------
-//
-// Explicit state classes are used rather than base::Bind(). This is done
-// both for clarity, but also to avoid extraneous allocations for things
-// like passing buffers and result objects between threads.
-//
-// BaseState is the base class common to all of the async operations, and
-// keeps track of the thread to complete on, the error state, and the
-// callback into Blink.
-//
-// Ownership of the State object is passed between the crypto thread and the
-// Blink thread. Under normal completion it is destroyed on the Blink thread.
-// However it may also be destroyed on the crypto thread if the Blink thread
-// has vanished (which can happen for Blink web worker threads).
-
-struct BaseState {
- explicit BaseState(const blink::WebCryptoResult& result)
- : origin_thread(GetCurrentBlinkThread()), result(result) {}
-
- bool cancelled() {
- return result.cancelled();
- }
-
- scoped_refptr<base::TaskRunner> origin_thread;
-
- webcrypto::Status status;
- blink::WebCryptoResult result;
-
- protected:
- // Since there is no virtual destructor, must not delete directly as a
- // BaseState.
- ~BaseState() {}
-};
-
-struct EncryptState : public BaseState {
- EncryptState(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const unsigned char* data,
- unsigned int data_size,
- const blink::WebCryptoResult& result)
- : BaseState(result),
- algorithm(algorithm),
- key(key),
- data(data, data + data_size) {}
-
- const blink::WebCryptoAlgorithm algorithm;
- const blink::WebCryptoKey key;
- const std::vector<uint8_t> data;
-
- std::vector<uint8_t> buffer;
-};
-
-typedef EncryptState DecryptState;
-typedef EncryptState DigestState;
-
-struct GenerateKeyState : public BaseState {
- GenerateKeyState(const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- const blink::WebCryptoResult& result)
- : BaseState(result),
- algorithm(algorithm),
- extractable(extractable),
- usages(usages) {}
-
- const blink::WebCryptoAlgorithm algorithm;
- const bool extractable;
- const blink::WebCryptoKeyUsageMask usages;
-
- webcrypto::GenerateKeyResult generate_key_result;
-};
-
-struct ImportKeyState : public BaseState {
- ImportKeyState(blink::WebCryptoKeyFormat format,
- const unsigned char* key_data,
- unsigned int key_data_size,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- const blink::WebCryptoResult& result)
- : BaseState(result),
- format(format),
- key_data(key_data, key_data + key_data_size),
- algorithm(algorithm),
- extractable(extractable),
- usages(usages) {}
-
- const blink::WebCryptoKeyFormat format;
- const std::vector<uint8_t> key_data;
- const blink::WebCryptoAlgorithm algorithm;
- const bool extractable;
- const blink::WebCryptoKeyUsageMask usages;
-
- blink::WebCryptoKey key;
-};
-
-struct ExportKeyState : public BaseState {
- ExportKeyState(blink::WebCryptoKeyFormat format,
- const blink::WebCryptoKey& key,
- const blink::WebCryptoResult& result)
- : BaseState(result), format(format), key(key) {}
-
- const blink::WebCryptoKeyFormat format;
- const blink::WebCryptoKey key;
-
- std::vector<uint8_t> buffer;
-};
-
-typedef EncryptState SignState;
-
-struct VerifySignatureState : public BaseState {
- VerifySignatureState(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const unsigned char* signature,
- unsigned int signature_size,
- const unsigned char* data,
- unsigned int data_size,
- const blink::WebCryptoResult& result)
- : BaseState(result),
- algorithm(algorithm),
- key(key),
- signature(signature, signature + signature_size),
- data(data, data + data_size),
- verify_result(false) {}
-
- const blink::WebCryptoAlgorithm algorithm;
- const blink::WebCryptoKey key;
- const std::vector<uint8_t> signature;
- const std::vector<uint8_t> data;
-
- bool verify_result;
-};
-
-struct WrapKeyState : public BaseState {
- WrapKeyState(blink::WebCryptoKeyFormat format,
- const blink::WebCryptoKey& key,
- const blink::WebCryptoKey& wrapping_key,
- const blink::WebCryptoAlgorithm& wrap_algorithm,
- const blink::WebCryptoResult& result)
- : BaseState(result),
- format(format),
- key(key),
- wrapping_key(wrapping_key),
- wrap_algorithm(wrap_algorithm) {}
-
- const blink::WebCryptoKeyFormat format;
- const blink::WebCryptoKey key;
- const blink::WebCryptoKey wrapping_key;
- const blink::WebCryptoAlgorithm wrap_algorithm;
-
- std::vector<uint8_t> buffer;
-};
-
-struct UnwrapKeyState : public BaseState {
- UnwrapKeyState(blink::WebCryptoKeyFormat format,
- const unsigned char* wrapped_key,
- unsigned wrapped_key_size,
- const blink::WebCryptoKey& wrapping_key,
- const blink::WebCryptoAlgorithm& unwrap_algorithm,
- const blink::WebCryptoAlgorithm& unwrapped_key_algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- const blink::WebCryptoResult& result)
- : BaseState(result),
- format(format),
- wrapped_key(wrapped_key, wrapped_key + wrapped_key_size),
- wrapping_key(wrapping_key),
- unwrap_algorithm(unwrap_algorithm),
- unwrapped_key_algorithm(unwrapped_key_algorithm),
- extractable(extractable),
- usages(usages) {}
-
- const blink::WebCryptoKeyFormat format;
- const std::vector<uint8_t> wrapped_key;
- const blink::WebCryptoKey wrapping_key;
- const blink::WebCryptoAlgorithm unwrap_algorithm;
- const blink::WebCryptoAlgorithm unwrapped_key_algorithm;
- const bool extractable;
- const blink::WebCryptoKeyUsageMask usages;
-
- blink::WebCryptoKey unwrapped_key;
-};
-
-// --------------------------------------------------------------------
-// Wrapper functions
-// --------------------------------------------------------------------
-//
-// * The methods named Do*() run on the crypto thread.
-// * The methods named Do*Reply() run on the target Blink thread
-
-void DoEncryptReply(scoped_ptr<EncryptState> state) {
- CompleteWithBufferOrError(state->status, state->buffer, &state->result);
-}
-
-void DoEncrypt(scoped_ptr<EncryptState> passed_state) {
- EncryptState* state = passed_state.get();
- if (state->cancelled())
- return;
- state->status = webcrypto::Encrypt(state->algorithm,
- state->key,
- webcrypto::CryptoData(state->data),
- &state->buffer);
- state->origin_thread->PostTask(
- FROM_HERE, base::Bind(DoEncryptReply, Passed(&passed_state)));
-}
-
-void DoDecryptReply(scoped_ptr<DecryptState> state) {
- CompleteWithBufferOrError(state->status, state->buffer, &state->result);
-}
-
-void DoDecrypt(scoped_ptr<DecryptState> passed_state) {
- DecryptState* state = passed_state.get();
- if (state->cancelled())
- return;
- state->status = webcrypto::Decrypt(state->algorithm,
- state->key,
- webcrypto::CryptoData(state->data),
- &state->buffer);
- state->origin_thread->PostTask(
- FROM_HERE, base::Bind(DoDecryptReply, Passed(&passed_state)));
-}
-
-void DoDigestReply(scoped_ptr<DigestState> state) {
- CompleteWithBufferOrError(state->status, state->buffer, &state->result);
-}
-
-void DoDigest(scoped_ptr<DigestState> passed_state) {
- DigestState* state = passed_state.get();
- if (state->cancelled())
- return;
- state->status = webcrypto::Digest(
- state->algorithm, webcrypto::CryptoData(state->data), &state->buffer);
- state->origin_thread->PostTask(
- FROM_HERE, base::Bind(DoDigestReply, Passed(&passed_state)));
-}
-
-void DoGenerateKeyReply(scoped_ptr<GenerateKeyState> state) {
- if (state->status.IsError()) {
- CompleteWithError(state->status, &state->result);
- } else {
- state->generate_key_result.Complete(&state->result);
- }
-}
-
-void DoGenerateKey(scoped_ptr<GenerateKeyState> passed_state) {
- GenerateKeyState* state = passed_state.get();
- if (state->cancelled())
- return;
- state->status = webcrypto::GenerateKey(state->algorithm,
- state->extractable,
- state->usages,
- &state->generate_key_result);
- state->origin_thread->PostTask(
- FROM_HERE, base::Bind(DoGenerateKeyReply, Passed(&passed_state)));
-}
-
-void DoImportKeyReply(scoped_ptr<ImportKeyState> state) {
- CompleteWithKeyOrError(state->status, state->key, &state->result);
-}
-
-void DoImportKey(scoped_ptr<ImportKeyState> passed_state) {
- ImportKeyState* state = passed_state.get();
- if (state->cancelled())
- return;
- state->status = webcrypto::ImportKey(state->format,
- webcrypto::CryptoData(state->key_data),
- state->algorithm,
- state->extractable,
- state->usages,
- &state->key);
- if (state->status.IsSuccess()) {
- DCHECK(state->key.handle());
- DCHECK(!state->key.algorithm().isNull());
- DCHECK_EQ(state->extractable, state->key.extractable());
- }
-
- state->origin_thread->PostTask(
- FROM_HERE, base::Bind(DoImportKeyReply, Passed(&passed_state)));
-}
-
-void DoExportKeyReply(scoped_ptr<ExportKeyState> state) {
- if (state->format != blink::WebCryptoKeyFormatJwk) {
- CompleteWithBufferOrError(state->status, state->buffer, &state->result);
- return;
- }
-
- if (state->status.IsError()) {
- CompleteWithError(state->status, &state->result);
- } else {
- state->result.completeWithJson(
- reinterpret_cast<const char*>(vector_as_array(&state->buffer)),
- state->buffer.size());
- }
-}
-
-void DoExportKey(scoped_ptr<ExportKeyState> passed_state) {
- ExportKeyState* state = passed_state.get();
- if (state->cancelled())
- return;
- state->status =
- webcrypto::ExportKey(state->format, state->key, &state->buffer);
- state->origin_thread->PostTask(
- FROM_HERE, base::Bind(DoExportKeyReply, Passed(&passed_state)));
-}
-
-void DoSignReply(scoped_ptr<SignState> state) {
- CompleteWithBufferOrError(state->status, state->buffer, &state->result);
-}
-
-void DoSign(scoped_ptr<SignState> passed_state) {
- SignState* state = passed_state.get();
- if (state->cancelled())
- return;
- state->status = webcrypto::Sign(state->algorithm,
- state->key,
- webcrypto::CryptoData(state->data),
- &state->buffer);
-
- state->origin_thread->PostTask(
- FROM_HERE, base::Bind(DoSignReply, Passed(&passed_state)));
-}
-
-void DoVerifyReply(scoped_ptr<VerifySignatureState> state) {
- if (state->status.IsError()) {
- CompleteWithError(state->status, &state->result);
- } else {
- state->result.completeWithBoolean(state->verify_result);
- }
-}
-
-void DoVerify(scoped_ptr<VerifySignatureState> passed_state) {
- VerifySignatureState* state = passed_state.get();
- if (state->cancelled())
- return;
- state->status = webcrypto::Verify(state->algorithm,
- state->key,
- webcrypto::CryptoData(state->signature),
- webcrypto::CryptoData(state->data),
- &state->verify_result);
-
- state->origin_thread->PostTask(
- FROM_HERE, base::Bind(DoVerifyReply, Passed(&passed_state)));
-}
-
-void DoWrapKeyReply(scoped_ptr<WrapKeyState> state) {
- CompleteWithBufferOrError(state->status, state->buffer, &state->result);
-}
-
-void DoWrapKey(scoped_ptr<WrapKeyState> passed_state) {
- WrapKeyState* state = passed_state.get();
- if (state->cancelled())
- return;
- state->status = webcrypto::WrapKey(state->format,
- state->key,
- state->wrapping_key,
- state->wrap_algorithm,
- &state->buffer);
-
- state->origin_thread->PostTask(
- FROM_HERE, base::Bind(DoWrapKeyReply, Passed(&passed_state)));
-}
-
-void DoUnwrapKeyReply(scoped_ptr<UnwrapKeyState> state) {
- CompleteWithKeyOrError(state->status, state->unwrapped_key, &state->result);
-}
-
-void DoUnwrapKey(scoped_ptr<UnwrapKeyState> passed_state) {
- UnwrapKeyState* state = passed_state.get();
- if (state->cancelled())
- return;
- state->status =
- webcrypto::UnwrapKey(state->format,
- webcrypto::CryptoData(state->wrapped_key),
- state->wrapping_key,
- state->unwrap_algorithm,
- state->unwrapped_key_algorithm,
- state->extractable,
- state->usages,
- &state->unwrapped_key);
-
- state->origin_thread->PostTask(
- FROM_HERE, base::Bind(DoUnwrapKeyReply, Passed(&passed_state)));
-}
-
-} // namespace
-
-WebCryptoImpl::WebCryptoImpl() {
-}
-
-WebCryptoImpl::~WebCryptoImpl() {
-}
-
-void WebCryptoImpl::encrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const unsigned char* data,
- unsigned int data_size,
- blink::WebCryptoResult result) {
- DCHECK(!algorithm.isNull());
-
- scoped_ptr<EncryptState> state(
- new EncryptState(algorithm, key, data, data_size, result));
- if (!CryptoThreadPool::PostTask(FROM_HERE,
- base::Bind(DoEncrypt, Passed(&state)))) {
- CompleteWithThreadPoolError(&result);
- }
-}
-
-void WebCryptoImpl::decrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const unsigned char* data,
- unsigned int data_size,
- blink::WebCryptoResult result) {
- DCHECK(!algorithm.isNull());
-
- scoped_ptr<DecryptState> state(
- new DecryptState(algorithm, key, data, data_size, result));
- if (!CryptoThreadPool::PostTask(FROM_HERE,
- base::Bind(DoDecrypt, Passed(&state)))) {
- CompleteWithThreadPoolError(&result);
- }
-}
-
-void WebCryptoImpl::digest(const blink::WebCryptoAlgorithm& algorithm,
- const unsigned char* data,
- unsigned int data_size,
- blink::WebCryptoResult result) {
- DCHECK(!algorithm.isNull());
-
- scoped_ptr<DigestState> state(new DigestState(
- algorithm, blink::WebCryptoKey::createNull(), data, data_size, result));
- if (!CryptoThreadPool::PostTask(FROM_HERE,
- base::Bind(DoDigest, Passed(&state)))) {
- CompleteWithThreadPoolError(&result);
- }
-}
-
-void WebCryptoImpl::generateKey(const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoResult result) {
- DCHECK(!algorithm.isNull());
-
- scoped_ptr<GenerateKeyState> state(
- new GenerateKeyState(algorithm, extractable, usages, result));
- if (!CryptoThreadPool::PostTask(FROM_HERE,
- base::Bind(DoGenerateKey, Passed(&state)))) {
- CompleteWithThreadPoolError(&result);
- }
-}
-
-void WebCryptoImpl::importKey(blink::WebCryptoKeyFormat format,
- const unsigned char* key_data,
- unsigned int key_data_size,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoResult result) {
- scoped_ptr<ImportKeyState> state(new ImportKeyState(
- format, key_data, key_data_size, algorithm, extractable, usages, result));
- if (!CryptoThreadPool::PostTask(FROM_HERE,
- base::Bind(DoImportKey, Passed(&state)))) {
- CompleteWithThreadPoolError(&result);
- }
-}
-
-void WebCryptoImpl::exportKey(blink::WebCryptoKeyFormat format,
- const blink::WebCryptoKey& key,
- blink::WebCryptoResult result) {
- scoped_ptr<ExportKeyState> state(new ExportKeyState(format, key, result));
- if (!CryptoThreadPool::PostTask(FROM_HERE,
- base::Bind(DoExportKey, Passed(&state)))) {
- CompleteWithThreadPoolError(&result);
- }
-}
-
-void WebCryptoImpl::sign(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const unsigned char* data,
- unsigned int data_size,
- blink::WebCryptoResult result) {
- scoped_ptr<SignState> state(
- new SignState(algorithm, key, data, data_size, result));
- if (!CryptoThreadPool::PostTask(FROM_HERE,
- base::Bind(DoSign, Passed(&state)))) {
- CompleteWithThreadPoolError(&result);
- }
-}
-
-void WebCryptoImpl::verifySignature(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const unsigned char* signature,
- unsigned int signature_size,
- const unsigned char* data,
- unsigned int data_size,
- blink::WebCryptoResult result) {
- scoped_ptr<VerifySignatureState> state(new VerifySignatureState(
- algorithm, key, signature, signature_size, data, data_size, result));
- if (!CryptoThreadPool::PostTask(FROM_HERE,
- base::Bind(DoVerify, Passed(&state)))) {
- CompleteWithThreadPoolError(&result);
- }
-}
-
-void WebCryptoImpl::wrapKey(blink::WebCryptoKeyFormat format,
- const blink::WebCryptoKey& key,
- const blink::WebCryptoKey& wrapping_key,
- const blink::WebCryptoAlgorithm& wrap_algorithm,
- blink::WebCryptoResult result) {
- scoped_ptr<WrapKeyState> state(
- new WrapKeyState(format, key, wrapping_key, wrap_algorithm, result));
- if (!CryptoThreadPool::PostTask(FROM_HERE,
- base::Bind(DoWrapKey, Passed(&state)))) {
- CompleteWithThreadPoolError(&result);
- }
-}
-
-void WebCryptoImpl::unwrapKey(
- blink::WebCryptoKeyFormat format,
- const unsigned char* wrapped_key,
- unsigned wrapped_key_size,
- const blink::WebCryptoKey& wrapping_key,
- const blink::WebCryptoAlgorithm& unwrap_algorithm,
- const blink::WebCryptoAlgorithm& unwrapped_key_algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoResult result) {
- scoped_ptr<UnwrapKeyState> state(new UnwrapKeyState(format,
- wrapped_key,
- wrapped_key_size,
- wrapping_key,
- unwrap_algorithm,
- unwrapped_key_algorithm,
- extractable,
- usages,
- result));
- if (!CryptoThreadPool::PostTask(FROM_HERE,
- base::Bind(DoUnwrapKey, Passed(&state)))) {
- CompleteWithThreadPoolError(&result);
- }
-}
-
-blink::WebCryptoDigestor* WebCryptoImpl::createDigestor(
- blink::WebCryptoAlgorithmId algorithm_id) {
- return webcrypto::CreateDigestor(algorithm_id).release();
-}
-
-bool WebCryptoImpl::deserializeKeyForClone(
- const blink::WebCryptoKeyAlgorithm& algorithm,
- blink::WebCryptoKeyType type,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- const unsigned char* key_data,
- unsigned key_data_size,
- blink::WebCryptoKey& key) {
- // TODO(eroman): Rather than do the import immediately on the current thread,
- // it could defer to the crypto thread.
- return webcrypto::DeserializeKeyForClone(
- algorithm,
- type,
- extractable,
- usages,
- webcrypto::CryptoData(key_data, key_data_size),
- &key);
-}
-
-bool WebCryptoImpl::serializeKeyForClone(
- const blink::WebCryptoKey& key,
- blink::WebVector<unsigned char>& key_data) {
- return webcrypto::SerializeKeyForClone(key, &key_data);
-}
-
-} // namespace content
diff --git a/chromium/content/child/webcrypto/webcrypto_impl.h b/chromium/content/child/webcrypto/webcrypto_impl.h
deleted file mode 100644
index 9263f6eefa1..00000000000
--- a/chromium/content/child/webcrypto/webcrypto_impl.h
+++ /dev/null
@@ -1,114 +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_CHILD_WEBCRYPTO_WEBCRYPTO_IMPL_H_
-#define CONTENT_CHILD_WEBCRYPTO_WEBCRYPTO_IMPL_H_
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "third_party/WebKit/public/platform/WebCrypto.h"
-#include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
-#include "third_party/WebKit/public/platform/WebVector.h"
-
-namespace content {
-
-// Wrapper around the Blink WebCrypto asynchronous interface, which forwards to
-// the synchronous platform (NSS or OpenSSL) implementation.
-//
-// WebCryptoImpl is threadsafe.
-//
-// EnsureInit() must be called prior to using methods on WebCryptoImpl().
-class WebCryptoImpl : public blink::WebCrypto {
- public:
- WebCryptoImpl();
-
- // TODO(eroman): Once Blink and Chromium repositories are merged, use
- // "override" in place of virtual.
-
- virtual ~WebCryptoImpl();
-
- virtual void encrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const unsigned char* data,
- unsigned int data_size,
- blink::WebCryptoResult result);
- virtual void decrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const unsigned char* data,
- unsigned int data_size,
- blink::WebCryptoResult result);
- virtual void digest(const blink::WebCryptoAlgorithm& algorithm,
- const unsigned char* data,
- unsigned int data_size,
- blink::WebCryptoResult result);
- virtual void generateKey(const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoResult result);
- virtual void importKey(blink::WebCryptoKeyFormat format,
- const unsigned char* key_data,
- unsigned int key_data_size,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoResult result);
- virtual void exportKey(blink::WebCryptoKeyFormat format,
- const blink::WebCryptoKey& key,
- blink::WebCryptoResult result);
- virtual void sign(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const unsigned char* data,
- unsigned int data_size,
- blink::WebCryptoResult result);
- virtual void verifySignature(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const unsigned char* signature,
- unsigned int signature_size,
- const unsigned char* data,
- unsigned int data_size,
- blink::WebCryptoResult result);
- virtual void wrapKey(blink::WebCryptoKeyFormat format,
- const blink::WebCryptoKey& key,
- const blink::WebCryptoKey& wrapping_key,
- const blink::WebCryptoAlgorithm& wrap_algorithm,
- blink::WebCryptoResult result);
- virtual void unwrapKey(
- blink::WebCryptoKeyFormat format,
- const unsigned char* wrapped_key,
- unsigned wrapped_key_size,
- const blink::WebCryptoKey& wrapping_key,
- const blink::WebCryptoAlgorithm& unwrap_algorithm,
- const blink::WebCryptoAlgorithm& unwrapped_key_algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoResult result);
-
- // This method returns a digestor object that can be used to synchronously
- // compute a digest one chunk at a time. Thus, the consume does not need to
- // hold onto a large buffer with all the data to digest. Chunks can be given
- // one at a time and the digest will be computed piecemeal. The allocated
- // WebCrytpoDigestor that is returned by createDigestor must be freed by the
- // caller.
- virtual blink::WebCryptoDigestor* createDigestor(
- blink::WebCryptoAlgorithmId algorithm_id);
-
- virtual bool deserializeKeyForClone(
- const blink::WebCryptoKeyAlgorithm& algorithm,
- blink::WebCryptoKeyType type,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- const unsigned char* key_data,
- unsigned key_data_size,
- blink::WebCryptoKey& key);
-
- virtual bool serializeKeyForClone(const blink::WebCryptoKey& key,
- blink::WebVector<unsigned char>& key_data);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(WebCryptoImpl);
-};
-
-} // namespace content
-
-#endif // CONTENT_CHILD_WEBCRYPTO_WEBCRYPTO_IMPL_H_
diff --git a/chromium/content/child/webcrypto/webcrypto_util.cc b/chromium/content/child/webcrypto/webcrypto_util.cc
deleted file mode 100644
index 410acdda738..00000000000
--- a/chromium/content/child/webcrypto/webcrypto_util.cc
+++ /dev/null
@@ -1,259 +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/child/webcrypto/webcrypto_util.h"
-
-#include <set>
-
-#include "base/logging.h"
-#include "base/strings/stringprintf.h"
-#include "content/child/webcrypto/status.h"
-#include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
-#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
-#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
-
-namespace content {
-
-namespace webcrypto {
-
-namespace {
-
-// Converts a (big-endian) WebCrypto BigInteger, with or without leading zeros,
-// to unsigned int.
-bool BigIntegerToUint(const uint8_t* data,
- unsigned int data_size,
- unsigned int* result) {
- if (data_size == 0)
- return false;
-
- *result = 0;
- for (size_t i = 0; i < data_size; ++i) {
- size_t reverse_i = data_size - i - 1;
-
- if (reverse_i >= sizeof(*result) && data[i])
- return false; // Too large for a uint.
-
- *result |= data[i] << 8 * reverse_i;
- }
- return true;
-}
-
-} // namespace
-
-struct JwkToWebCryptoUsage {
- const char* const jwk_key_op;
- const blink::WebCryptoKeyUsage webcrypto_usage;
-};
-
-// Keep this ordered according to the definition
-// order of WebCrypto's "recognized key usage
-// values".
-//
-// This is not required for spec compliance,
-// however it makes the ordering of key_ops match
-// that of WebCrypto's Key.usages.
-const JwkToWebCryptoUsage kJwkWebCryptoUsageMap[] = {
- {"encrypt", blink::WebCryptoKeyUsageEncrypt},
- {"decrypt", blink::WebCryptoKeyUsageDecrypt},
- {"sign", blink::WebCryptoKeyUsageSign},
- {"verify", blink::WebCryptoKeyUsageVerify},
- {"deriveKey", blink::WebCryptoKeyUsageDeriveKey},
- {"deriveBits", blink::WebCryptoKeyUsageDeriveBits},
- {"wrapKey", blink::WebCryptoKeyUsageWrapKey},
- {"unwrapKey", blink::WebCryptoKeyUsageUnwrapKey}};
-
-bool JwkKeyOpToWebCryptoUsage(const std::string& key_op,
- blink::WebCryptoKeyUsage* usage) {
- for (size_t i = 0; i < arraysize(kJwkWebCryptoUsageMap); ++i) {
- if (kJwkWebCryptoUsageMap[i].jwk_key_op == key_op) {
- *usage = kJwkWebCryptoUsageMap[i].webcrypto_usage;
- return true;
- }
- }
- return false;
-}
-
-// Composes a Web Crypto usage mask from an array of JWK key_ops values.
-Status GetWebCryptoUsagesFromJwkKeyOps(const base::ListValue* key_ops,
- blink::WebCryptoKeyUsageMask* usages) {
- // This set keeps track of all unrecognized key_ops values.
- std::set<std::string> unrecognized_usages;
-
- *usages = 0;
- for (size_t i = 0; i < key_ops->GetSize(); ++i) {
- std::string key_op;
- if (!key_ops->GetString(i, &key_op)) {
- return Status::ErrorJwkPropertyWrongType(
- base::StringPrintf("key_ops[%d]", static_cast<int>(i)), "string");
- }
-
- blink::WebCryptoKeyUsage usage;
- if (JwkKeyOpToWebCryptoUsage(key_op, &usage)) {
- // Ensure there are no duplicate usages.
- if (*usages & usage)
- return Status::ErrorJwkDuplicateKeyOps();
- *usages |= usage;
- }
-
- // Reaching here means the usage was unrecognized. Such usages are skipped
- // over, however they are kept track of in a set to ensure there were no
- // duplicates.
- if (!unrecognized_usages.insert(key_op).second)
- return Status::ErrorJwkDuplicateKeyOps();
- }
- return Status::Success();
-}
-
-// Composes a JWK key_ops List from a Web Crypto usage mask.
-// Note: Caller must assume ownership of returned instance.
-base::ListValue* CreateJwkKeyOpsFromWebCryptoUsages(
- blink::WebCryptoKeyUsageMask usages) {
- base::ListValue* jwk_key_ops = new base::ListValue();
- for (size_t i = 0; i < arraysize(kJwkWebCryptoUsageMap); ++i) {
- if (usages & kJwkWebCryptoUsageMap[i].webcrypto_usage)
- jwk_key_ops->AppendString(kJwkWebCryptoUsageMap[i].jwk_key_op);
- }
- return jwk_key_ops;
-}
-
-blink::WebCryptoAlgorithm CreateAlgorithm(blink::WebCryptoAlgorithmId id) {
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate(id, NULL);
-}
-
-blink::WebCryptoAlgorithm CreateHmacImportAlgorithm(
- blink::WebCryptoAlgorithmId hash_id) {
- DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id));
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
- blink::WebCryptoAlgorithmIdHmac,
- new blink::WebCryptoHmacImportParams(CreateAlgorithm(hash_id)));
-}
-
-blink::WebCryptoAlgorithm CreateRsaHashedImportAlgorithm(
- blink::WebCryptoAlgorithmId id,
- blink::WebCryptoAlgorithmId hash_id) {
- DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id));
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
- id, new blink::WebCryptoRsaHashedImportParams(CreateAlgorithm(hash_id)));
-}
-
-bool ContainsKeyUsages(blink::WebCryptoKeyUsageMask a,
- blink::WebCryptoKeyUsageMask b) {
- return (a & b) == b;
-}
-
-// TODO(eroman): Move this helper to WebCryptoKey.
-bool KeyUsageAllows(const blink::WebCryptoKey& key,
- const blink::WebCryptoKeyUsage usage) {
- return ((key.usages() & usage) != 0);
-}
-
-// The WebCrypto spec defines the default value for the tag length, as well as
-// the allowed values for tag length.
-Status GetAesGcmTagLengthInBits(const blink::WebCryptoAesGcmParams* params,
- unsigned int* tag_length_bits) {
- *tag_length_bits = 128;
- if (params->hasTagLengthBits())
- *tag_length_bits = params->optionalTagLengthBits();
-
- if (*tag_length_bits != 32 && *tag_length_bits != 64 &&
- *tag_length_bits != 96 && *tag_length_bits != 104 &&
- *tag_length_bits != 112 && *tag_length_bits != 120 &&
- *tag_length_bits != 128)
- return Status::ErrorInvalidAesGcmTagLength();
-
- return Status::Success();
-}
-
-Status GetAesKeyGenLengthInBits(const blink::WebCryptoAesKeyGenParams* params,
- unsigned int* keylen_bits) {
- *keylen_bits = params->lengthBits();
-
- if (*keylen_bits == 128 || *keylen_bits == 256)
- return Status::Success();
-
- // BoringSSL does not support 192-bit AES.
- if (*keylen_bits == 192)
- return Status::ErrorAes192BitUnsupported();
-
- return Status::ErrorGenerateKeyLength();
-}
-
-Status GetHmacKeyGenLengthInBits(const blink::WebCryptoHmacKeyGenParams* params,
- unsigned int* keylen_bits) {
- if (!params->hasLengthBits()) {
- switch (params->hash().id()) {
- case blink::WebCryptoAlgorithmIdSha1:
- case blink::WebCryptoAlgorithmIdSha256:
- *keylen_bits = 512;
- return Status::Success();
- case blink::WebCryptoAlgorithmIdSha384:
- case blink::WebCryptoAlgorithmIdSha512:
- *keylen_bits = 1024;
- return Status::Success();
- default:
- return Status::ErrorUnsupported();
- }
- }
-
- if (params->optionalLengthBits() % 8)
- return Status::ErrorGenerateKeyLength();
-
- *keylen_bits = params->optionalLengthBits();
-
- // TODO(eroman): NSS fails when generating a zero-length secret key.
- if (*keylen_bits == 0)
- return Status::ErrorGenerateKeyLength();
-
- return Status::Success();
-}
-
-Status VerifyAesKeyLengthForImport(unsigned int keylen_bytes) {
- if (keylen_bytes == 16 || keylen_bytes == 32)
- return Status::Success();
-
- // BoringSSL does not support 192-bit AES.
- if (keylen_bytes == 24)
- return Status::ErrorAes192BitUnsupported();
-
- return Status::ErrorImportAesKeyLength();
-}
-
-Status CheckKeyCreationUsages(blink::WebCryptoKeyUsageMask all_possible_usages,
- blink::WebCryptoKeyUsageMask actual_usages) {
- if (!ContainsKeyUsages(all_possible_usages, actual_usages))
- return Status::ErrorCreateKeyBadUsages();
- return Status::Success();
-}
-
-Status GetRsaKeyGenParameters(
- const blink::WebCryptoRsaHashedKeyGenParams* params,
- unsigned int* public_exponent,
- unsigned int* modulus_length_bits) {
- *modulus_length_bits = params->modulusLengthBits();
-
- // Limit key sizes to those supported by NSS:
- // * Multiple of 8 bits
- // * 256 bits to 16K bits
- if (*modulus_length_bits < 256 || *modulus_length_bits > 16384 ||
- (*modulus_length_bits % 8) != 0) {
- return Status::ErrorGenerateRsaUnsupportedModulus();
- }
-
- if (!BigIntegerToUint(params->publicExponent().data(),
- params->publicExponent().size(),
- public_exponent)) {
- return Status::ErrorGenerateKeyPublicExponent();
- }
-
- // OpenSSL hangs when given bad public exponents, whereas NSS simply fails. To
- // avoid feeding OpenSSL data that will hang use a whitelist.
- if (*public_exponent != 3 && *public_exponent != 65537)
- return Status::ErrorGenerateKeyPublicExponent();
-
- return Status::Success();
-}
-
-} // namespace webcrypto
-
-} // namespace content
diff --git a/chromium/content/child/webcrypto/webcrypto_util.h b/chromium/content/child/webcrypto/webcrypto_util.h
deleted file mode 100644
index 26b4675f059..00000000000
--- a/chromium/content/child/webcrypto/webcrypto_util.h
+++ /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.
-
-#ifndef CONTENT_CHILD_WEBCRYPTO_WEBCRYPTO_UTIL_H_
-#define CONTENT_CHILD_WEBCRYPTO_WEBCRYPTO_UTIL_H_
-
-#include <stdint.h>
-#include <string>
-
-#include "base/values.h"
-#include "content/common/content_export.h"
-#include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
-#include "third_party/WebKit/public/platform/WebCryptoKey.h"
-
-namespace content {
-
-namespace webcrypto {
-
-class Status;
-
-// Converts a JWK "key_ops" array to the corresponding WebCrypto usages.
-CONTENT_EXPORT Status
- GetWebCryptoUsagesFromJwkKeyOps(const base::ListValue* key_ops,
- blink::WebCryptoKeyUsageMask* usages);
-
-// Composes a JWK key_ops array from a Web Crypto usage mask.
-base::ListValue* CreateJwkKeyOpsFromWebCryptoUsages(
- blink::WebCryptoKeyUsageMask usages);
-
-// Creates a WebCryptoAlgorithm without any parameters.
-CONTENT_EXPORT blink::WebCryptoAlgorithm CreateAlgorithm(
- blink::WebCryptoAlgorithmId id);
-
-// Creates an HMAC import algorithm whose inner hash algorithm is determined by
-// the specified algorithm ID. It is an error to call this method with a hash
-// algorithm that is not SHA*.
-CONTENT_EXPORT blink::WebCryptoAlgorithm CreateHmacImportAlgorithm(
- blink::WebCryptoAlgorithmId hash_id);
-
-// Creates an import algorithm for RSA algorithms that take a hash.
-// It is an error to call this with a hash_id that is not a SHA*.
-CONTENT_EXPORT blink::WebCryptoAlgorithm CreateRsaHashedImportAlgorithm(
- blink::WebCryptoAlgorithmId id,
- blink::WebCryptoAlgorithmId hash_id);
-
-// Returns true if the set bits in b make up a subset of the set bits in a.
-bool ContainsKeyUsages(blink::WebCryptoKeyUsageMask a,
- blink::WebCryptoKeyUsageMask b);
-
-bool KeyUsageAllows(const blink::WebCryptoKey& key,
- const blink::WebCryptoKeyUsage usage);
-
-Status GetAesGcmTagLengthInBits(const blink::WebCryptoAesGcmParams* params,
- unsigned int* tag_length_bits);
-
-Status GetAesKeyGenLengthInBits(const blink::WebCryptoAesKeyGenParams* params,
- unsigned int* keylen_bits);
-
-Status GetHmacKeyGenLengthInBits(const blink::WebCryptoHmacKeyGenParams* params,
- unsigned int* keylen_bits);
-
-Status VerifyAesKeyLengthForImport(unsigned int keylen_bytes);
-
-Status CheckKeyCreationUsages(blink::WebCryptoKeyUsageMask all_possible_usages,
- blink::WebCryptoKeyUsageMask actual_usages);
-
-// Extracts the public exponent and modulus length from the Blink parameters.
-// On success it is guaranteed that:
-// * public_exponent is either 3 or 65537
-// * modulus_length_bits is a multiple of 8
-// * modulus_length is >= 256
-// * modulus_length is <= 16K
-Status GetRsaKeyGenParameters(
- const blink::WebCryptoRsaHashedKeyGenParams* params,
- unsigned int* public_exponent,
- unsigned int* modulus_length_bits);
-
-} // namespace webcrypto
-
-} // namespace content
-
-#endif // CONTENT_CHILD_WEBCRYPTO_WEBCRYPTO_UTIL_H_
diff --git a/chromium/content/child/webmessageportchannel_impl.cc b/chromium/content/child/webmessageportchannel_impl.cc
index dbdc2f38eb6..332959f25b3 100644
--- a/chromium/content/child/webmessageportchannel_impl.cc
+++ b/chromium/content/child/webmessageportchannel_impl.cc
@@ -6,11 +6,15 @@
#include "base/bind.h"
#include "base/message_loop/message_loop_proxy.h"
+#include "base/values.h"
#include "content/child/child_process.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
#include "content/common/message_port_messages.h"
+#include "content/public/child/v8_value_converter.h"
#include "third_party/WebKit/public/platform/WebMessagePortChannelClient.h"
#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/web/WebSerializedScriptValue.h"
+#include "v8/include/v8.h"
using blink::WebMessagePortChannel;
using blink::WebMessagePortChannelArray;
@@ -20,23 +24,25 @@ using blink::WebString;
namespace content {
WebMessagePortChannelImpl::WebMessagePortChannelImpl(
- const scoped_refptr<base::MessageLoopProxy>& child_thread_loop)
+ const scoped_refptr<base::SingleThreadTaskRunner>& main_thread_task_runner)
: client_(NULL),
route_id_(MSG_ROUTING_NONE),
message_port_id_(MSG_ROUTING_NONE),
- child_thread_loop_(child_thread_loop) {
+ send_messages_as_values_(false),
+ main_thread_task_runner_(main_thread_task_runner) {
AddRef();
Init();
}
WebMessagePortChannelImpl::WebMessagePortChannelImpl(
int route_id,
- int message_port_id,
- const scoped_refptr<base::MessageLoopProxy>& child_thread_loop)
+ const TransferredMessagePort& port,
+ const scoped_refptr<base::SingleThreadTaskRunner>& main_thread_task_runner)
: client_(NULL),
route_id_(route_id),
- message_port_id_(message_port_id),
- child_thread_loop_(child_thread_loop) {
+ message_port_id_(port.id),
+ send_messages_as_values_(port.send_messages_as_values),
+ main_thread_task_runner_(main_thread_task_runner) {
AddRef();
Init();
}
@@ -44,7 +50,7 @@ WebMessagePortChannelImpl::WebMessagePortChannelImpl(
WebMessagePortChannelImpl::~WebMessagePortChannelImpl() {
// If we have any queued messages with attached ports, manually destroy them.
while (!message_queue_.empty()) {
- const std::vector<WebMessagePortChannelImpl*>& channel_array =
+ const WebMessagePortChannelArray& channel_array =
message_queue_.front().ports;
for (size_t i = 0; i < channel_array.size(); i++) {
channel_array[i]->destroy();
@@ -56,18 +62,18 @@ WebMessagePortChannelImpl::~WebMessagePortChannelImpl() {
Send(new MessagePortHostMsg_DestroyMessagePort(message_port_id_));
if (route_id_ != MSG_ROUTING_NONE)
- ChildThread::current()->GetRouter()->RemoveRoute(route_id_);
+ ChildThreadImpl::current()->GetRouter()->RemoveRoute(route_id_);
}
// static
void WebMessagePortChannelImpl::CreatePair(
- const scoped_refptr<base::MessageLoopProxy>& child_thread_loop,
+ const scoped_refptr<base::SingleThreadTaskRunner>& main_thread_task_runner,
blink::WebMessagePortChannel** channel1,
blink::WebMessagePortChannel** channel2) {
WebMessagePortChannelImpl* impl1 =
- new WebMessagePortChannelImpl(child_thread_loop);
+ new WebMessagePortChannelImpl(main_thread_task_runner);
WebMessagePortChannelImpl* impl2 =
- new WebMessagePortChannelImpl(child_thread_loop);
+ new WebMessagePortChannelImpl(main_thread_task_runner);
impl1->Entangle(impl2);
impl2->Entangle(impl1);
@@ -77,25 +83,53 @@ void WebMessagePortChannelImpl::CreatePair(
}
// static
-std::vector<int> WebMessagePortChannelImpl::ExtractMessagePortIDs(
+std::vector<TransferredMessagePort>
+WebMessagePortChannelImpl::ExtractMessagePortIDs(
WebMessagePortChannelArray* channels) {
- std::vector<int> message_port_ids;
+ std::vector<TransferredMessagePort> message_ports;
if (channels) {
- message_port_ids.resize(channels->size());
// Extract the port IDs from the source array, then free it.
- for (size_t i = 0; i < channels->size(); ++i) {
- WebMessagePortChannelImpl* webchannel =
- static_cast<WebMessagePortChannelImpl*>((*channels)[i]);
- // The message port ids might not be set up yet if this channel
- // wasn't created on the main thread.
- DCHECK(webchannel->child_thread_loop_->BelongsToCurrentThread());
- message_port_ids[i] = webchannel->message_port_id();
- webchannel->QueueMessages();
- DCHECK(message_port_ids[i] != MSG_ROUTING_NONE);
- }
+ message_ports = ExtractMessagePortIDs(*channels);
delete channels;
}
- return message_port_ids;
+ return message_ports;
+}
+
+// static
+std::vector<TransferredMessagePort>
+WebMessagePortChannelImpl::ExtractMessagePortIDs(
+ const WebMessagePortChannelArray& channels) {
+ std::vector<TransferredMessagePort> message_ports(channels.size());
+ for (size_t i = 0; i < channels.size(); ++i) {
+ WebMessagePortChannelImpl* webchannel =
+ static_cast<WebMessagePortChannelImpl*>(channels[i]);
+ // The message port ids might not be set up yet if this channel
+ // wasn't created on the main thread.
+ DCHECK(webchannel->main_thread_task_runner_->BelongsToCurrentThread());
+ message_ports[i].id = webchannel->message_port_id();
+ message_ports[i].send_messages_as_values =
+ webchannel->send_messages_as_values_;
+ webchannel->QueueMessages();
+ DCHECK(message_ports[i].id != MSG_ROUTING_NONE);
+ }
+ return message_ports;
+}
+
+// static
+WebMessagePortChannelArray WebMessagePortChannelImpl::CreatePorts(
+ const std::vector<TransferredMessagePort>& message_ports,
+ const std::vector<int>& new_routing_ids,
+ const scoped_refptr<base::SingleThreadTaskRunner>&
+ main_thread_task_runner) {
+ DCHECK_EQ(message_ports.size(), new_routing_ids.size());
+ WebMessagePortChannelArray channels(message_ports.size());
+ for (size_t i = 0; i < message_ports.size() && i < new_routing_ids.size();
+ ++i) {
+ channels[i] = new WebMessagePortChannelImpl(
+ new_routing_ids[i], message_ports[i],
+ main_thread_task_runner);
+ }
+ return channels;
}
void WebMessagePortChannelImpl::setClient(WebMessagePortChannelClient* client) {
@@ -109,25 +143,35 @@ void WebMessagePortChannelImpl::destroy() {
// Release the object on the main thread, since the destructor might want to
// send an IPC, and that has to happen on the main thread.
- child_thread_loop_->ReleaseSoon(FROM_HERE, this);
+ main_thread_task_runner_->ReleaseSoon(FROM_HERE, this);
}
void WebMessagePortChannelImpl::postMessage(
- const WebString& message,
+ const WebString& message_as_string,
WebMessagePortChannelArray* channels) {
- if (!child_thread_loop_->BelongsToCurrentThread()) {
- child_thread_loop_->PostTask(
- FROM_HERE,
- base::Bind(
- &WebMessagePortChannelImpl::PostMessage, this,
- static_cast<base::string16>(message), channels));
+ MessagePortMessage message(message_as_string);
+ if (send_messages_as_values_) {
+ blink::WebSerializedScriptValue serialized_value =
+ blink::WebSerializedScriptValue::fromString(message_as_string);
+ v8::Local<v8::Value> v8_value = serialized_value.deserialize();
+ scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
+ converter->SetDateAllowed(true);
+ converter->SetRegExpAllowed(true);
+ scoped_ptr<base::Value> message_as_value(converter->FromV8Value(
+ v8_value, v8::Isolate::GetCurrent()->GetCurrentContext()));
+ message = MessagePortMessage(message_as_value.Pass());
+ }
+ if (!main_thread_task_runner_->BelongsToCurrentThread()) {
+ main_thread_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&WebMessagePortChannelImpl::PostMessage, this,
+ message, channels));
} else {
PostMessage(message, channels);
}
}
void WebMessagePortChannelImpl::PostMessage(
- const base::string16& message,
+ const MessagePortMessage& message,
WebMessagePortChannelArray* channels) {
IPC::Message* msg = new MessagePortHostMsg_PostMessage(
message_port_id_, message, ExtractMessagePortIDs(channels));
@@ -141,22 +185,31 @@ bool WebMessagePortChannelImpl::tryGetMessage(
if (message_queue_.empty())
return false;
- *message = message_queue_.front().message;
- const std::vector<WebMessagePortChannelImpl*>& channel_array =
- message_queue_.front().ports;
- WebMessagePortChannelArray result_ports(channel_array.size());
- for (size_t i = 0; i < channel_array.size(); i++) {
- result_ports[i] = channel_array[i];
+ const MessagePortMessage& data = message_queue_.front().message;
+ DCHECK(data.is_string() != data.is_value());
+ if (data.is_value()) {
+ v8::HandleScope handle_scope(client_->scriptIsolate());
+ v8::Context::Scope context_scope(
+ client_->scriptContextForMessageConversion());
+ scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
+ converter->SetDateAllowed(true);
+ converter->SetRegExpAllowed(true);
+ v8::Local<v8::Value> v8_value = converter->ToV8Value(
+ data.as_value(), client_->scriptContextForMessageConversion());
+ blink::WebSerializedScriptValue serialized_value =
+ blink::WebSerializedScriptValue::serialize(v8_value);
+ *message = serialized_value.toString();
+ } else {
+ *message = message_queue_.front().message.message_as_string;
}
-
- channels.swap(result_ports);
+ channels = message_queue_.front().ports;
message_queue_.pop();
return true;
}
void WebMessagePortChannelImpl::Init() {
- if (!child_thread_loop_->BelongsToCurrentThread()) {
- child_thread_loop_->PostTask(
+ if (!main_thread_task_runner_->BelongsToCurrentThread()) {
+ main_thread_task_runner_->PostTask(
FROM_HERE, base::Bind(&WebMessagePortChannelImpl::Init, this));
return;
}
@@ -165,9 +218,11 @@ void WebMessagePortChannelImpl::Init() {
DCHECK(message_port_id_ == MSG_ROUTING_NONE);
Send(new MessagePortHostMsg_CreateMessagePort(
&route_id_, &message_port_id_));
+ } else if (message_port_id_ != MSG_ROUTING_NONE) {
+ Send(new MessagePortHostMsg_ReleaseMessages(message_port_id_));
}
- ChildThread::current()->GetRouter()->AddRoute(route_id_, this);
+ ChildThreadImpl::current()->GetRouter()->AddRoute(route_id_, this);
}
void WebMessagePortChannelImpl::Entangle(
@@ -175,8 +230,8 @@ void WebMessagePortChannelImpl::Entangle(
// The message port ids might not be set up yet, if this channel wasn't
// created on the main thread. So need to wait until we're on the main thread
// before getting the other message port id.
- if (!child_thread_loop_->BelongsToCurrentThread()) {
- child_thread_loop_->PostTask(
+ if (!main_thread_task_runner_->BelongsToCurrentThread()) {
+ main_thread_task_runner_->PostTask(
FROM_HERE,
base::Bind(&WebMessagePortChannelImpl::Entangle, this, channel));
return;
@@ -187,8 +242,8 @@ void WebMessagePortChannelImpl::Entangle(
}
void WebMessagePortChannelImpl::QueueMessages() {
- if (!child_thread_loop_->BelongsToCurrentThread()) {
- child_thread_loop_->PostTask(
+ if (!main_thread_task_runner_->BelongsToCurrentThread()) {
+ main_thread_task_runner_->PostTask(
FROM_HERE, base::Bind(&WebMessagePortChannelImpl::QueueMessages, this));
return;
}
@@ -206,15 +261,15 @@ void WebMessagePortChannelImpl::QueueMessages() {
}
void WebMessagePortChannelImpl::Send(IPC::Message* message) {
- if (!child_thread_loop_->BelongsToCurrentThread()) {
+ if (!main_thread_task_runner_->BelongsToCurrentThread()) {
DCHECK(!message->is_sync());
- child_thread_loop_->PostTask(
+ main_thread_task_runner_->PostTask(
FROM_HERE,
base::Bind(&WebMessagePortChannelImpl::Send, this, message));
return;
}
- ChildThread::current()->GetRouter()->Send(message);
+ ChildThreadImpl::current()->GetRouter()->Send(message);
}
bool WebMessagePortChannelImpl::OnMessageReceived(const IPC::Message& message) {
@@ -228,20 +283,14 @@ bool WebMessagePortChannelImpl::OnMessageReceived(const IPC::Message& message) {
}
void WebMessagePortChannelImpl::OnMessage(
- const base::string16& message,
- const std::vector<int>& sent_message_port_ids,
+ const MessagePortMessage& message,
+ const std::vector<TransferredMessagePort>& sent_message_ports,
const std::vector<int>& new_routing_ids) {
base::AutoLock auto_lock(lock_);
Message msg;
msg.message = message;
- if (!sent_message_port_ids.empty()) {
- msg.ports.resize(sent_message_port_ids.size());
- for (size_t i = 0; i < sent_message_port_ids.size(); ++i) {
- msg.ports[i] = new WebMessagePortChannelImpl(new_routing_ids[i],
- sent_message_port_ids[i],
- child_thread_loop_.get());
- }
- }
+ msg.ports = CreatePorts(sent_message_ports, new_routing_ids,
+ main_thread_task_runner_.get());
bool was_empty = message_queue_.empty();
message_queue_.push(msg);
@@ -256,15 +305,10 @@ void WebMessagePortChannelImpl::OnMessagesQueued() {
base::AutoLock auto_lock(lock_);
queued_messages.reserve(message_queue_.size());
while (!message_queue_.empty()) {
- base::string16 message = message_queue_.front().message;
- const std::vector<WebMessagePortChannelImpl*>& channel_array =
- message_queue_.front().ports;
- std::vector<int> port_ids(channel_array.size());
- for (size_t i = 0; i < channel_array.size(); ++i) {
- port_ids[i] = channel_array[i]->message_port_id();
- channel_array[i]->QueueMessages();
- }
- queued_messages.push_back(std::make_pair(message, port_ids));
+ MessagePortMessage message = message_queue_.front().message;
+ std::vector<TransferredMessagePort> ports =
+ ExtractMessagePortIDs(message_queue_.front().ports);
+ queued_messages.push_back(std::make_pair(message, ports));
message_queue_.pop();
}
}
diff --git a/chromium/content/child/webmessageportchannel_impl.h b/chromium/content/child/webmessageportchannel_impl.h
index e33ccc4d94c..4b9c273d01d 100644
--- a/chromium/content/child/webmessageportchannel_impl.h
+++ b/chromium/content/child/webmessageportchannel_impl.h
@@ -10,13 +10,16 @@
#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
#include "base/strings/string16.h"
#include "base/synchronization/lock.h"
+#include "content/public/common/message_port_types.h"
#include "ipc/ipc_listener.h"
#include "third_party/WebKit/public/platform/WebMessagePortChannel.h"
namespace base {
-class MessageLoopProxy;
+class SingleThreadTaskRunner;
+class Value;
}
namespace content {
@@ -29,22 +32,38 @@ class WebMessagePortChannelImpl
public base::RefCountedThreadSafe<WebMessagePortChannelImpl> {
public:
explicit WebMessagePortChannelImpl(
- const scoped_refptr<base::MessageLoopProxy>& child_thread_loop);
+ const scoped_refptr<base::SingleThreadTaskRunner>&
+ main_thread_task_runner);
WebMessagePortChannelImpl(
int route_id,
- int message_port_id,
- const scoped_refptr<base::MessageLoopProxy>& child_thread_loop);
+ const TransferredMessagePort& port,
+ const scoped_refptr<base::SingleThreadTaskRunner>&
+ main_thread_task_runner);
static void CreatePair(
- const scoped_refptr<base::MessageLoopProxy>& child_thread_loop,
+ const scoped_refptr<base::SingleThreadTaskRunner>&
+ main_thread_task_runner,
blink::WebMessagePortChannel** channel1,
blink::WebMessagePortChannel** channel2);
// Extracts port IDs for passing on to the browser process, and queues any
// received messages. Takes ownership of the passed array (and deletes it).
- static std::vector<int> ExtractMessagePortIDs(
+ static std::vector<TransferredMessagePort> ExtractMessagePortIDs(
blink::WebMessagePortChannelArray* channels);
+ // Extracts port IDs for passing on to the browser process, and queues any
+ // received messages.
+ static std::vector<TransferredMessagePort> ExtractMessagePortIDs(
+ const blink::WebMessagePortChannelArray& channels);
+
+ // Creates WebMessagePortChannelImpl instances for port IDs passed in from the
+ // browser process.
+ static blink::WebMessagePortChannelArray CreatePorts(
+ const std::vector<TransferredMessagePort>& message_ports,
+ const std::vector<int>& new_routing_ids,
+ const scoped_refptr<base::SingleThreadTaskRunner>&
+ main_thread_task_runner);
+
// Queues received and incoming messages until there are no more in-flight
// messages, then sends all of them to the browser process.
void QueueMessages();
@@ -65,14 +84,14 @@ class WebMessagePortChannelImpl
void Init();
void Entangle(scoped_refptr<WebMessagePortChannelImpl> channel);
void Send(IPC::Message* message);
- void PostMessage(const base::string16& message,
+ void PostMessage(const MessagePortMessage& message,
blink::WebMessagePortChannelArray* channels);
// IPC::Listener implementation.
bool OnMessageReceived(const IPC::Message& message) override;
- void OnMessage(const base::string16& message,
- const std::vector<int>& sent_message_port_ids,
+ void OnMessage(const MessagePortMessage& message,
+ const std::vector<TransferredMessagePort>& sent_message_ports,
const std::vector<int>& new_routing_ids);
void OnMessagesQueued();
@@ -80,8 +99,8 @@ class WebMessagePortChannelImpl
Message();
~Message();
- base::string16 message;
- std::vector<WebMessagePortChannelImpl*> ports;
+ MessagePortMessage message;
+ blink::WebMessagePortChannelArray ports;
};
typedef std::queue<Message> MessageQueue;
@@ -92,7 +111,11 @@ class WebMessagePortChannelImpl
int route_id_; // The routing id for this object.
int message_port_id_; // A globally unique identifier for this message port.
- scoped_refptr<base::MessageLoopProxy> child_thread_loop_;
+ // Flag to indicate if messages should be sent to the browser process as
+ // base::Value instances as opposed to being serialized using the default
+ // blink::WebSerializedScriptValue.
+ bool send_messages_as_values_;
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
DISALLOW_COPY_AND_ASSIGN(WebMessagePortChannelImpl);
};
diff --git a/chromium/content/child/websocket_bridge.cc b/chromium/content/child/websocket_bridge.cc
index 5b327024313..2af6e8ece84 100644
--- a/chromium/content/child/websocket_bridge.cc
+++ b/chromium/content/child/websocket_bridge.cc
@@ -11,7 +11,7 @@
#include "base/logging.h"
#include "base/strings/string_util.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
#include "content/child/websocket_dispatcher.h"
#include "content/common/websocket.h"
#include "content/common/websocket_messages.h"
@@ -52,7 +52,7 @@ WebSocketBridge::~WebSocketBridge() {
if (channel_id_ != kInvalidChannelId) {
// The connection is abruptly disconnected by the renderer without
// closing handshake.
- ChildThread::current()->Send(
+ ChildThreadImpl::current()->Send(
new WebSocketMsg_DropChannel(channel_id_,
false,
kAbnormalShutdownOpCode,
@@ -80,22 +80,18 @@ bool WebSocketBridge::OnMessageReceived(const IPC::Message& msg) {
return handled;
}
-void WebSocketBridge::DidConnect(bool fail,
- const std::string& selected_protocol,
+void WebSocketBridge::DidConnect(const std::string& selected_protocol,
const std::string& extensions) {
WebSocketHandleClient* client = client_;
DVLOG(1) << "WebSocketBridge::DidConnect("
- << fail << ", "
<< selected_protocol << ", "
<< extensions << ")";
- if (fail)
- Disconnect();
if (!client)
return;
WebString protocol_to_pass = WebString::fromUTF8(selected_protocol);
WebString extensions_to_pass = WebString::fromUTF8(extensions);
- client->didConnect(this, fail, protocol_to_pass, extensions_to_pass);
+ client->didConnect(this, protocol_to_pass, extensions_to_pass);
// |this| can be deleted here.
}
@@ -214,7 +210,7 @@ void WebSocketBridge::connect(
WebSocketHandleClient* client) {
DCHECK_EQ(kInvalidChannelId, channel_id_);
WebSocketDispatcher* dispatcher =
- ChildThread::current()->websocket_dispatcher();
+ ChildThreadImpl::current()->websocket_dispatcher();
channel_id_ = dispatcher->AddBridge(this);
client_ = client;
@@ -227,7 +223,7 @@ void WebSocketBridge::connect(
<< JoinString(protocols_to_pass, ", ") << "), "
<< origin_to_pass.string() << ")";
- ChildThread::current()->Send(new WebSocketHostMsg_AddChannelRequest(
+ ChildThreadImpl::current()->Send(new WebSocketHostMsg_AddChannelRequest(
channel_id_, url, protocols_to_pass, origin_to_pass, render_frame_id_));
}
@@ -255,7 +251,7 @@ void WebSocketBridge::send(bool fin,
<< fin << ", " << type_to_pass << ", "
<< "(data size = " << size << "))";
- ChildThread::current()->Send(
+ ChildThreadImpl::current()->Send(
new WebSocketMsg_SendFrame(channel_id_,
fin,
type_to_pass,
@@ -268,7 +264,7 @@ void WebSocketBridge::flowControl(int64_t quota) {
DVLOG(1) << "Bridge #" << channel_id_ << " FlowControl(" << quota << ")";
- ChildThread::current()->Send(
+ ChildThreadImpl::current()->Send(
new WebSocketMsg_FlowControl(channel_id_, quota));
}
@@ -281,7 +277,7 @@ void WebSocketBridge::close(unsigned short code,
DVLOG(1) << "Bridge #" << channel_id_ << " Close("
<< code << ", " << reason_to_pass << ")";
// This method is for closing handshake and hence |was_clean| shall be true.
- ChildThread::current()->Send(
+ ChildThreadImpl::current()->Send(
new WebSocketMsg_DropChannel(channel_id_, true, code, reason_to_pass));
}
@@ -289,7 +285,7 @@ void WebSocketBridge::Disconnect() {
if (channel_id_ == kInvalidChannelId)
return;
WebSocketDispatcher* dispatcher =
- ChildThread::current()->websocket_dispatcher();
+ ChildThreadImpl::current()->websocket_dispatcher();
dispatcher->RemoveBridge(channel_id_);
channel_id_ = kInvalidChannelId;
diff --git a/chromium/content/child/websocket_bridge.h b/chromium/content/child/websocket_bridge.h
index 0fe5ae29466..cff76f45ddc 100644
--- a/chromium/content/child/websocket_bridge.h
+++ b/chromium/content/child/websocket_bridge.h
@@ -31,29 +31,27 @@ class WebSocketBridge : public blink::WebSocketHandle {
bool OnMessageReceived(const IPC::Message& message);
// WebSocketHandle functions.
- virtual void connect(const blink::WebURL& url,
- const blink::WebVector<blink::WebString>& protocols,
- const blink::WebSerializedOrigin& origin,
- blink::WebSocketHandleClient* client) override;
- virtual void send(bool fin,
- WebSocketHandle::MessageType type,
- const char* data,
- size_t size) override;
- virtual void flowControl(int64_t quota) override;
- virtual void close(unsigned short code,
- const blink::WebString& reason) override;
-
- virtual void Disconnect();
+ void connect(const blink::WebURL& url,
+ const blink::WebVector<blink::WebString>& protocols,
+ const blink::WebSerializedOrigin& origin,
+ blink::WebSocketHandleClient* client) override;
+ void send(bool fin,
+ WebSocketHandle::MessageType type,
+ const char* data,
+ size_t size) override;
+ void flowControl(int64_t quota) override;
+ void close(unsigned short code, const blink::WebString& reason) override;
+
+ void Disconnect();
void set_render_frame_id(int id) {
render_frame_id_ = id;
}
private:
- virtual ~WebSocketBridge();
+ ~WebSocketBridge() override;
- void DidConnect(bool fail,
- const std::string& selected_protocol,
+ void DidConnect(const std::string& selected_protocol,
const std::string& extensions);
void DidStartOpeningHandshake(const WebSocketHandshakeRequest& request);
void DidFinishOpeningHandshake(const WebSocketHandshakeResponse& response);
diff --git a/chromium/content/child/webthemeengine_impl_default.cc b/chromium/content/child/webthemeengine_impl_default.cc
index 4f78f1c9da2..1235494d6ff 100644
--- a/chromium/content/child/webthemeengine_impl_default.cc
+++ b/chromium/content/child/webthemeengine_impl_default.cc
@@ -15,6 +15,24 @@ using blink::WebRect;
using blink::WebThemeEngine;
namespace content {
+namespace {
+
+#if defined(OS_WIN)
+// The scrollbar metrics default to 17 dips which is the default value on
+// Windows in most cases.
+int32 g_vertical_scroll_bar_width = 17;
+
+// The height of a horizontal scroll bar in dips.
+int32 g_horizontal_scroll_bar_height = 17;
+
+// The height of the arrow bitmap on a vertical scroll bar in dips.
+int32 g_vertical_arrow_bitmap_height = 17;
+
+// The width of the arrow bitmap on a horizontal scroll bar in dips.
+int32 g_horizontal_arrow_bitmap_width = 17;
+#endif
+
+} // namespace
static ui::NativeTheme::Part NativeThemePart(
WebThemeEngine::Part part) {
@@ -162,9 +180,28 @@ static void GetNativeThemeExtraParams(
blink::WebSize WebThemeEngineImpl::getSize(WebThemeEngine::Part part) {
ui::NativeTheme::ExtraParams extra;
- return ui::NativeTheme::instance()->GetPartSize(NativeThemePart(part),
- ui::NativeTheme::kNormal,
- extra);
+ ui::NativeTheme::Part native_theme_part = NativeThemePart(part);
+#if defined(OS_WIN)
+ switch (native_theme_part) {
+ case ui::NativeTheme::kScrollbarDownArrow:
+ case ui::NativeTheme::kScrollbarLeftArrow:
+ case ui::NativeTheme::kScrollbarRightArrow:
+ case ui::NativeTheme::kScrollbarUpArrow:
+ case ui::NativeTheme::kScrollbarHorizontalThumb:
+ case ui::NativeTheme::kScrollbarVerticalThumb:
+ case ui::NativeTheme::kScrollbarHorizontalTrack:
+ case ui::NativeTheme::kScrollbarVerticalTrack: {
+ return gfx::Size(g_vertical_scroll_bar_width,
+ g_vertical_scroll_bar_width);
+ }
+
+ default:
+ break;
+ }
+#endif
+ return ui::NativeTheme::instance()->GetPartSize(native_theme_part,
+ ui::NativeTheme::kNormal,
+ extra);
}
void WebThemeEngineImpl::paint(
@@ -199,4 +236,18 @@ void WebThemeEngineImpl::paintStateTransition(blink::WebCanvas* canvas,
gfx::Rect(rect));
}
+#if defined(OS_WIN)
+// static
+void WebThemeEngineImpl::cacheScrollBarMetrics(
+ int32 vertical_scroll_bar_width,
+ int32 horizontal_scroll_bar_height,
+ int32 vertical_arrow_bitmap_height,
+ int32 horizontal_arrow_bitmap_width) {
+ g_vertical_scroll_bar_width = vertical_scroll_bar_width;
+ g_horizontal_scroll_bar_height = horizontal_scroll_bar_height;
+ g_vertical_arrow_bitmap_height = vertical_arrow_bitmap_height;
+ g_horizontal_arrow_bitmap_width = horizontal_arrow_bitmap_width;
+}
+#endif
+
} // namespace content
diff --git a/chromium/content/child/webthemeengine_impl_default.h b/chromium/content/child/webthemeengine_impl_default.h
index b757d441b39..a05313aad98 100644
--- a/chromium/content/child/webthemeengine_impl_default.h
+++ b/chromium/content/child/webthemeengine_impl_default.h
@@ -25,6 +25,14 @@ class WebThemeEngineImpl : public blink::WebThemeEngine {
blink::WebThemeEngine::State endState,
double progress,
const blink::WebRect& rect);
+
+#if defined(OS_WIN)
+ // Caches the scrollbar metrics.
+ static void cacheScrollBarMetrics(int32 vertical_scroll_bar_width,
+ int32 horizontal_scroll_bar_height,
+ int32 vertical_arrow_bitmap_height,
+ int32 horizontal_arrow_bitmap_width);
+#endif
};
} // namespace content
diff --git a/chromium/content/child/webthread_impl.cc b/chromium/content/child/webthread_impl.cc
deleted file mode 100644
index ec80b70e86e..00000000000
--- a/chromium/content/child/webthread_impl.cc
+++ /dev/null
@@ -1,140 +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.
-
-// An implementation of WebThread in terms of base::MessageLoop and
-// base::Thread
-
-#include "content/child/webthread_impl.h"
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/message_loop/message_loop.h"
-#include "base/pending_task.h"
-#include "base/threading/platform_thread.h"
-
-namespace content {
-
-WebThreadBase::WebThreadBase() {}
-WebThreadBase::~WebThreadBase() {}
-
-class WebThreadBase::TaskObserverAdapter
- : public base::MessageLoop::TaskObserver {
- public:
- TaskObserverAdapter(WebThread::TaskObserver* observer)
- : observer_(observer) {}
-
- void WillProcessTask(const base::PendingTask& pending_task) override {
- observer_->willProcessTask();
- }
-
- void DidProcessTask(const base::PendingTask& pending_task) override {
- observer_->didProcessTask();
- }
-
-private:
- WebThread::TaskObserver* observer_;
-};
-
-void WebThreadBase::addTaskObserver(TaskObserver* observer) {
- CHECK(isCurrentThread());
- std::pair<TaskObserverMap::iterator, bool> result = task_observer_map_.insert(
- std::make_pair(observer, static_cast<TaskObserverAdapter*>(NULL)));
- if (result.second)
- result.first->second = new TaskObserverAdapter(observer);
- base::MessageLoop::current()->AddTaskObserver(result.first->second);
-}
-
-void WebThreadBase::removeTaskObserver(TaskObserver* observer) {
- CHECK(isCurrentThread());
- TaskObserverMap::iterator iter = task_observer_map_.find(observer);
- if (iter == task_observer_map_.end())
- return;
- base::MessageLoop::current()->RemoveTaskObserver(iter->second);
- delete iter->second;
- task_observer_map_.erase(iter);
-}
-
-WebThreadImpl::WebThreadImpl(const char* name)
- : thread_(new base::Thread(name)) {
- thread_->Start();
-}
-
-void WebThreadImpl::postTask(Task* task) {
- thread_->message_loop()->PostTask(
- FROM_HERE, base::Bind(&blink::WebThread::Task::run, base::Owned(task)));
-}
-
-void WebThreadImpl::postDelayedTask(Task* task, long long delay_ms) {
- thread_->message_loop()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&blink::WebThread::Task::run, base::Owned(task)),
- base::TimeDelta::FromMilliseconds(delay_ms));
-}
-
-void WebThreadImpl::enterRunLoop() {
- CHECK(isCurrentThread());
- CHECK(!thread_->message_loop()->is_running()); // We don't support nesting.
- thread_->message_loop()->Run();
-}
-
-void WebThreadImpl::exitRunLoop() {
- CHECK(isCurrentThread());
- CHECK(thread_->message_loop()->is_running());
- thread_->message_loop()->Quit();
-}
-
-bool WebThreadImpl::isCurrentThread() const {
- return thread_->thread_id() == base::PlatformThread::CurrentId();
-}
-
-blink::PlatformThreadId WebThreadImpl::threadId() const {
- return thread_->thread_id();
-}
-
-WebThreadImpl::~WebThreadImpl() {
- thread_->Stop();
-}
-
-WebThreadImplForMessageLoop::WebThreadImplForMessageLoop(
- base::MessageLoopProxy* message_loop)
- : message_loop_(message_loop),
- thread_id_(base::PlatformThread::CurrentId()) {}
-
-void WebThreadImplForMessageLoop::postTask(Task* task) {
- message_loop_->PostTask(
- FROM_HERE, base::Bind(&blink::WebThread::Task::run, base::Owned(task)));
-}
-
-void WebThreadImplForMessageLoop::postDelayedTask(Task* task,
- long long delay_ms) {
- message_loop_->PostDelayedTask(
- FROM_HERE,
- base::Bind(&blink::WebThread::Task::run, base::Owned(task)),
- base::TimeDelta::FromMilliseconds(delay_ms));
-}
-
-void WebThreadImplForMessageLoop::enterRunLoop() {
- CHECK(isCurrentThread());
- // We don't support nesting.
- CHECK(!base::MessageLoop::current()->is_running());
- base::MessageLoop::current()->Run();
-}
-
-void WebThreadImplForMessageLoop::exitRunLoop() {
- CHECK(isCurrentThread());
- CHECK(base::MessageLoop::current()->is_running());
- base::MessageLoop::current()->Quit();
-}
-
-bool WebThreadImplForMessageLoop::isCurrentThread() const {
- return message_loop_->BelongsToCurrentThread();
-}
-
-blink::PlatformThreadId WebThreadImplForMessageLoop::threadId() const {
- return thread_id_;
-}
-
-WebThreadImplForMessageLoop::~WebThreadImplForMessageLoop() {}
-
-} // namespace content
diff --git a/chromium/content/child/webthread_impl.h b/chromium/content/child/webthread_impl.h
deleted file mode 100644
index 8ebbd97d02c..00000000000
--- a/chromium/content/child/webthread_impl.h
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_CHILD_WEBTHREAD_IMPL_H_
-#define CONTENT_CHILD_WEBTHREAD_IMPL_H_
-
-#include <map>
-
-#include "base/memory/scoped_ptr.h"
-#include "base/threading/thread.h"
-#include "content/common/content_export.h"
-#include "third_party/WebKit/public/platform/WebThread.h"
-
-namespace content {
-
-class CONTENT_EXPORT WebThreadBase : public blink::WebThread {
- public:
- virtual ~WebThreadBase();
-
- virtual void addTaskObserver(TaskObserver* observer);
- virtual void removeTaskObserver(TaskObserver* observer);
-
- virtual bool isCurrentThread() const = 0;
- virtual blink::PlatformThreadId threadId() const = 0;
-
- protected:
- WebThreadBase();
-
- private:
- class TaskObserverAdapter;
-
- typedef std::map<TaskObserver*, TaskObserverAdapter*> TaskObserverMap;
- TaskObserverMap task_observer_map_;
-};
-
-class CONTENT_EXPORT WebThreadImpl : public WebThreadBase {
- public:
- explicit WebThreadImpl(const char* name);
- virtual ~WebThreadImpl();
-
- virtual void postTask(Task* task);
- virtual void postDelayedTask(Task* task, long long delay_ms);
-
- virtual void enterRunLoop();
- virtual void exitRunLoop();
-
- base::MessageLoop* message_loop() const { return thread_->message_loop(); }
-
- virtual bool isCurrentThread() const override;
- virtual blink::PlatformThreadId threadId() const override;
-
- private:
- scoped_ptr<base::Thread> thread_;
-};
-
-class WebThreadImplForMessageLoop : public WebThreadBase {
- public:
- CONTENT_EXPORT explicit WebThreadImplForMessageLoop(
- base::MessageLoopProxy* message_loop);
- CONTENT_EXPORT virtual ~WebThreadImplForMessageLoop();
-
- virtual void postTask(Task* task) override;
- virtual void postDelayedTask(Task* task, long long delay_ms) override;
-
- virtual void enterRunLoop() override;
- virtual void exitRunLoop() override;
-
- private:
- virtual bool isCurrentThread() const override;
- virtual blink::PlatformThreadId threadId() const override;
-
- scoped_refptr<base::MessageLoopProxy> message_loop_;
- blink::PlatformThreadId thread_id_;
-};
-
-} // namespace content
-
-#endif // CONTENT_CHILD_WEBTHREAD_IMPL_H_
diff --git a/chromium/content/child/worker_task_runner.cc b/chromium/content/child/worker_task_runner.cc
index 02c4bab320f..17b4e1654b5 100644
--- a/chromium/content/child/worker_task_runner.cc
+++ b/chromium/content/child/worker_task_runner.cc
@@ -6,66 +6,67 @@
#include "base/callback.h"
#include "base/lazy_instance.h"
+#include "base/location.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/observer_list.h"
-
-using blink::WebWorkerRunLoop;
+#include "base/single_thread_task_runner.h"
+#include "base/stl_util.h"
+#include "base/thread_task_runner_handle.h"
namespace content {
namespace {
-class RunClosureTask : public WebWorkerRunLoop::Task {
+// A task-runner that refuses to run any tasks.
+class DoNothingTaskRunner : public base::TaskRunner {
public:
- RunClosureTask(const base::Closure& task) : task_(task) {}
- virtual ~RunClosureTask() {}
- virtual void Run() {
- task_.Run();
- }
+ DoNothingTaskRunner() {}
+
private:
- base::Closure task_;
+ ~DoNothingTaskRunner() override {}
+
+ bool PostDelayedTask(const tracked_objects::Location& from_here,
+ const base::Closure& task,
+ base::TimeDelta delay) override {
+ return false;
+ }
+
+ bool RunsTasksOnCurrentThread() const override { return false; }
};
-} // namespace
+} // namespace
struct WorkerTaskRunner::ThreadLocalState {
- ThreadLocalState(int id, const WebWorkerRunLoop& loop)
- : id_(id), run_loop_(loop) {
- }
- int id_;
- WebWorkerRunLoop run_loop_;
+ ThreadLocalState() {}
ObserverList<WorkerTaskRunner::Observer> stop_observers_;
};
-WorkerTaskRunner::WorkerTaskRunner() {
- // Start worker ids at 1, 0 is reserved for the main thread.
- int id = id_sequence_.GetNext();
- DCHECK(!id);
+WorkerTaskRunner::WorkerTaskRunner()
+ : task_runner_for_dead_worker_(new DoNothingTaskRunner()) {
}
bool WorkerTaskRunner::PostTask(
int id, const base::Closure& closure) {
DCHECK(id > 0);
- base::AutoLock locker(loop_map_lock_);
- IDToLoopMap::iterator found = loop_map_.find(id);
- if (found == loop_map_.end())
+ base::AutoLock locker(task_runner_map_lock_);
+ IDToTaskRunnerMap::iterator found = task_runner_map_.find(id);
+ if (found == task_runner_map_.end())
return false;
- return found->second.postTask(new RunClosureTask(closure));
+ return found->second->PostTask(FROM_HERE, closure);
}
int WorkerTaskRunner::PostTaskToAllThreads(const base::Closure& closure) {
- base::AutoLock locker(loop_map_lock_);
- IDToLoopMap::iterator it;
- for (it = loop_map_.begin(); it != loop_map_.end(); ++it)
- it->second.postTask(new RunClosureTask(closure));
- return static_cast<int>(loop_map_.size());
+ base::AutoLock locker(task_runner_map_lock_);
+ for (const auto& it : task_runner_map_)
+ it.second->PostTask(FROM_HERE, closure);
+ return static_cast<int>(task_runner_map_.size());
}
int WorkerTaskRunner::CurrentWorkerId() {
if (!current_tls_.Get())
return 0;
- return current_tls_.Get()->id_;
+ return base::PlatformThread::CurrentId();
}
WorkerTaskRunner* WorkerTaskRunner::Instance() {
@@ -87,26 +88,33 @@ void WorkerTaskRunner::RemoveStopObserver(Observer* obs) {
WorkerTaskRunner::~WorkerTaskRunner() {
}
-void WorkerTaskRunner::OnWorkerRunLoopStarted(const WebWorkerRunLoop& loop) {
+void WorkerTaskRunner::OnWorkerRunLoopStarted() {
DCHECK(!current_tls_.Get());
- int id = id_sequence_.GetNext();
- current_tls_.Set(new ThreadLocalState(id, loop));
+ DCHECK(!base::PlatformThread::CurrentRef().is_null());
+ current_tls_.Set(new ThreadLocalState());
- base::AutoLock locker_(loop_map_lock_);
- loop_map_[id] = loop;
+ int id = base::PlatformThread::CurrentId();
+ base::AutoLock locker_(task_runner_map_lock_);
+ task_runner_map_[id] = base::ThreadTaskRunnerHandle::Get().get();
+ CHECK(task_runner_map_[id]);
}
-void WorkerTaskRunner::OnWorkerRunLoopStopped(const WebWorkerRunLoop& loop) {
+void WorkerTaskRunner::OnWorkerRunLoopStopped() {
DCHECK(current_tls_.Get());
FOR_EACH_OBSERVER(Observer, current_tls_.Get()->stop_observers_,
OnWorkerRunLoopStopped());
{
- base::AutoLock locker(loop_map_lock_);
- DCHECK(loop_map_[CurrentWorkerId()] == loop);
- loop_map_.erase(CurrentWorkerId());
+ base::AutoLock locker(task_runner_map_lock_);
+ task_runner_map_.erase(CurrentWorkerId());
}
delete current_tls_.Get();
current_tls_.Set(NULL);
}
+base::TaskRunner* WorkerTaskRunner::GetTaskRunnerFor(int worker_id) {
+ base::AutoLock locker(task_runner_map_lock_);
+ return ContainsKey(task_runner_map_, worker_id) ? task_runner_map_[worker_id]
+ : task_runner_for_dead_worker_.get();
+}
+
} // namespace content
diff --git a/chromium/content/child/worker_task_runner.h b/chromium/content/child/worker_task_runner.h
index 6230551989b..c3797bc93ef 100644
--- a/chromium/content/child/worker_task_runner.h
+++ b/chromium/content/child/worker_task_runner.h
@@ -7,12 +7,16 @@
#include <map>
-#include "base/atomic_sequence_num.h"
#include "base/callback_forward.h"
+#include "base/memory/ref_counted.h"
#include "base/synchronization/lock.h"
+#include "base/threading/platform_thread.h"
#include "base/threading/thread_local.h"
#include "content/common/content_export.h"
-#include "third_party/WebKit/public/platform/WebWorkerRunLoop.h"
+
+namespace base {
+class TaskRunner;
+}
namespace content {
@@ -36,24 +40,33 @@ class CONTENT_EXPORT WorkerTaskRunner {
void AddStopObserver(Observer* observer);
void RemoveStopObserver(Observer* observer);
- void OnWorkerRunLoopStarted(const blink::WebWorkerRunLoop& loop);
- void OnWorkerRunLoopStopped(const blink::WebWorkerRunLoop& loop);
+ void OnWorkerRunLoopStarted();
+ void OnWorkerRunLoopStopped();
+
+ base::TaskRunner* GetTaskRunnerFor(int worker_id);
private:
friend class WorkerTaskRunnerTest;
- typedef std::map<int, blink::WebWorkerRunLoop> IDToLoopMap;
+ using IDToTaskRunnerMap = std::map<base::PlatformThreadId, base::TaskRunner*>;
~WorkerTaskRunner();
+ // It is possible for an IPC message to arrive for a worker thread that has
+ // already gone away. In such cases, it is still necessary to provide a
+ // task-runner for that particular thread, because otherwise the message will
+ // end up being handled as per usual in the main-thread, causing incorrect
+ // results. |task_runner_for_dead_worker_| is used to handle such messages,
+ // which silently discards all the tasks it receives.
+ scoped_refptr<base::TaskRunner> task_runner_for_dead_worker_;
+
struct ThreadLocalState;
base::ThreadLocalPointer<ThreadLocalState> current_tls_;
- base::AtomicSequenceNumber id_sequence_;
- IDToLoopMap loop_map_;
- base::Lock loop_map_lock_;
+ IDToTaskRunnerMap task_runner_map_;
+ base::Lock task_runner_map_lock_;
};
} // namespace content
-#endif // CONTENT_CHILD_WORKER_TASK_RUNNER_H_
+#endif // CONTENT_CHILD_WORKER_TASK_RUNNER_H_
diff --git a/chromium/content/child/worker_task_runner_unittest.cc b/chromium/content/child/worker_task_runner_unittest.cc
index 530c8a2f178..20eddfb9c47 100644
--- a/chromium/content/child/worker_task_runner_unittest.cc
+++ b/chromium/content/child/worker_task_runner_unittest.cc
@@ -5,6 +5,7 @@
#include "content/child/worker_task_runner.h"
#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -13,12 +14,15 @@ namespace content {
class WorkerTaskRunnerTest : public testing::Test {
public:
void FakeStart() {
- task_runner_.OnWorkerRunLoopStarted(blink::WebWorkerRunLoop());
+ task_runner_.OnWorkerRunLoopStarted();
}
void FakeStop() {
- task_runner_.OnWorkerRunLoopStopped(blink::WebWorkerRunLoop());
+ task_runner_.OnWorkerRunLoopStopped();
}
WorkerTaskRunner task_runner_;
+
+ private:
+ base::MessageLoop message_loop_;
};
class MockObserver : public WorkerTaskRunner::Observer {
diff --git a/chromium/content/child/worker_thread_message_filter.cc b/chromium/content/child/worker_thread_message_filter.cc
new file mode 100644
index 00000000000..aa11b3bb707
--- /dev/null
+++ b/chromium/content/child/worker_thread_message_filter.cc
@@ -0,0 +1,48 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/child/worker_thread_message_filter.h"
+
+#include "base/thread_task_runner_handle.h"
+#include "content/child/thread_safe_sender.h"
+#include "content/child/worker_task_runner.h"
+#include "ipc/ipc_message_macros.h"
+
+namespace content {
+
+WorkerThreadMessageFilter::WorkerThreadMessageFilter(
+ ThreadSafeSender* thread_safe_sender)
+ : main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
+ thread_safe_sender_(thread_safe_sender) {
+}
+
+WorkerThreadMessageFilter::~WorkerThreadMessageFilter() {
+}
+
+base::TaskRunner* WorkerThreadMessageFilter::OverrideTaskRunnerForMessage(
+ const IPC::Message& msg) {
+ if (!ShouldHandleMessage(msg))
+ return nullptr;
+ int ipc_thread_id = 0;
+ const bool success = GetWorkerThreadIdForMessage(msg, &ipc_thread_id);
+ DCHECK(success);
+ if (!ipc_thread_id)
+ return main_thread_task_runner_.get();
+ return WorkerTaskRunner::Instance()->GetTaskRunnerFor(ipc_thread_id);
+}
+
+bool WorkerThreadMessageFilter::OnMessageReceived(const IPC::Message& msg) {
+ if (!ShouldHandleMessage(msg))
+ return false;
+ // If the IPC message is received in a worker thread, but it has already been
+ // stopped, then drop the message.
+ if (!main_thread_task_runner_->BelongsToCurrentThread() &&
+ !WorkerTaskRunner::Instance()->CurrentWorkerId()) {
+ return false;
+ }
+ OnFilteredMessageReceived(msg);
+ return true;
+}
+
+} // namespace content
diff --git a/chromium/content/child/worker_thread_message_filter.h b/chromium/content/child/worker_thread_message_filter.h
new file mode 100644
index 00000000000..56db521b6fa
--- /dev/null
+++ b/chromium/content/child/worker_thread_message_filter.h
@@ -0,0 +1,58 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_CHILD_WORKER_THREAD_MESSAGE_FILTER_H_
+#define CONTENT_CHILD_WORKER_THREAD_MESSAGE_FILTER_H_
+
+#include "content/child/child_message_filter.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+}
+
+namespace content {
+
+class ThreadSafeSender;
+
+// A base class for filtering IPC messages targeted for worker threads.
+class WorkerThreadMessageFilter : public ChildMessageFilter {
+ public:
+ explicit WorkerThreadMessageFilter(ThreadSafeSender* thread_safe_sender);
+
+ protected:
+ ~WorkerThreadMessageFilter() override;
+
+ base::SingleThreadTaskRunner* main_thread_task_runner() {
+ return main_thread_task_runner_.get();
+ }
+ ThreadSafeSender* thread_safe_sender() { return thread_safe_sender_.get(); }
+
+ private:
+ // Returns whether this filter should process |msg|.
+ virtual bool ShouldHandleMessage(const IPC::Message& msg) const = 0;
+
+ // Processes the IPC message in the worker thread, if the filter could extract
+ // its thread id. Otherwise, runs in the main thread. It only receives a
+ // message if ShouldHandleMessage() returns true for it.
+ virtual void OnFilteredMessageReceived(const IPC::Message& msg) = 0;
+
+ // Attempts to extract the thread-id of the worker-thread that should process
+ // the IPC message. Returns whether the thread-id could be determined and set
+ // in |ipc_thread_id|.
+ virtual bool GetWorkerThreadIdForMessage(const IPC::Message& msg,
+ int* ipc_thread_id) = 0;
+
+ // ChildMessageFilter implementation:
+ base::TaskRunner* OverrideTaskRunnerForMessage(const IPC::Message& msg) final;
+ bool OnMessageReceived(const IPC::Message& msg) final;
+
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
+ scoped_refptr<ThreadSafeSender> thread_safe_sender_;
+
+ DISALLOW_COPY_AND_ASSIGN(WorkerThreadMessageFilter);
+};
+
+} // namespace content
+
+#endif // CONTENT_CHILD_WORKER_THREAD_MESSAGE_FILTER_H_
diff --git a/chromium/content/child/worker_thread_task_runner.cc b/chromium/content/child/worker_thread_task_runner.cc
deleted file mode 100644
index 8e5b2e75a4e..00000000000
--- a/chromium/content/child/worker_thread_task_runner.cc
+++ /dev/null
@@ -1,38 +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/child/worker_thread_task_runner.h"
-
-#include "base/logging.h"
-#include "content/child/worker_task_runner.h"
-
-namespace content {
-
-WorkerThreadTaskRunner::WorkerThreadTaskRunner(int worker_thread_id)
- : worker_thread_id_(worker_thread_id) {
-}
-
-scoped_refptr<WorkerThreadTaskRunner> WorkerThreadTaskRunner::current() {
- int worker_thread_id = WorkerTaskRunner::Instance()->CurrentWorkerId();
- if (!worker_thread_id)
- return scoped_refptr<WorkerThreadTaskRunner>();
- return make_scoped_refptr(new WorkerThreadTaskRunner(worker_thread_id));
-}
-
-bool WorkerThreadTaskRunner::PostDelayedTask(
- const tracked_objects::Location& /* from_here */,
- const base::Closure& task,
- base::TimeDelta delay) {
- // Currently non-zero delay is not supported.
- DCHECK(!delay.ToInternalValue());
- return WorkerTaskRunner::Instance()->PostTask(worker_thread_id_, task);
-}
-
-bool WorkerThreadTaskRunner::RunsTasksOnCurrentThread() const {
- return worker_thread_id_ == WorkerTaskRunner::Instance()->CurrentWorkerId();
-}
-
-WorkerThreadTaskRunner::~WorkerThreadTaskRunner() {}
-
-} // namespace content
diff --git a/chromium/content/child/worker_thread_task_runner.h b/chromium/content/child/worker_thread_task_runner.h
deleted file mode 100644
index 5acafbd81e5..00000000000
--- a/chromium/content/child/worker_thread_task_runner.h
+++ /dev/null
@@ -1,39 +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_CHILD_WORKER_THREAD_TASK_RUNNER_H_
-#define CONTENT_CHILD_WORKER_THREAD_TASK_RUNNER_H_
-
-#include "base/task_runner.h"
-
-namespace content {
-
-// A task runner that runs tasks on a single webkit worker thread which
-// is managed by WorkerTaskRunner.
-// Note that this implementation ignores the delay duration for PostDelayedTask
-// and have it behave the same as PostTask.
-class WorkerThreadTaskRunner : public base::TaskRunner {
- public:
- explicit WorkerThreadTaskRunner(int worker_thread_id);
-
- // Gets the WorkerThreadTaskRunner for the current worker thread.
- // This returns non-null value only when it is called on a worker thread.
- static scoped_refptr<WorkerThreadTaskRunner> current();
-
- // TaskRunner overrides.
- bool PostDelayedTask(const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta delay) override;
- bool RunsTasksOnCurrentThread() const override;
-
- protected:
- ~WorkerThreadTaskRunner() override;
-
- private:
- const int worker_thread_id_;
-};
-
-} // namespace content
-
-#endif // CONTENT_CHILD_WORKER_THREAD_TASK_RUNNER_H_
diff --git a/chromium/content/common/BUILD.gn b/chromium/content/common/BUILD.gn
index cfe291b724f..ecfe362c95b 100644
--- a/chromium/content/common/BUILD.gn
+++ b/chromium/content/common/BUILD.gn
@@ -5,15 +5,25 @@
import("//build/config/features.gni")
import("//build/config/ui.gni")
import("//content/common/common.gni")
-import("//mojo/public/tools/bindings/mojom.gni")
+import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni")
-if (is_chromeos && use_x11 && cpu_arch != "arm") {
+if (is_chromeos && current_cpu != "arm") {
action("libva_generate_stubs") {
extra_header = "gpu/media/va_stub_header.fragment"
script = "../../tools/generate_stubs/generate_stubs.py"
- sources = [ "gpu/media/va.sigs" ]
- source_prereqs = [ extra_header ]
+ sources = [
+ "gpu/media/va.sigs",
+ ]
+ inputs = [
+ extra_header,
+ ]
+ if (use_x11) {
+ sources += [ "gpu/media/va_x11.sigs" ]
+ }
+ if (use_ozone) {
+ sources += [ "gpu/media/va_drm.sigs" ]
+ }
stubs_filename_root = "va_stubs"
outputs = [
@@ -21,12 +31,90 @@ if (is_chromeos && use_x11 && cpu_arch != "arm") {
"$target_gen_dir/gpu/media/$stubs_filename_root.h",
]
args = [
- "-i", rebase_path("$target_gen_dir/gpu/media", root_build_dir),
- "-o", rebase_path("$target_gen_dir/gpu/media", root_build_dir),
- "-t", "posix_stubs",
- "-e", rebase_path(extra_header, root_build_dir),
- "-s", stubs_filename_root,
- "-p", "content/common/gpu/media",
+ "-i",
+ rebase_path("$target_gen_dir/gpu/media", root_build_dir),
+ "-o",
+ rebase_path("$target_gen_dir/gpu/media", root_build_dir),
+ "-t",
+ "posix_stubs",
+ "-e",
+ rebase_path(extra_header, root_build_dir),
+ "-s",
+ stubs_filename_root,
+ "-p",
+ "content/common/gpu/media",
+ ]
+
+ args += rebase_path(sources, root_build_dir)
+ }
+}
+
+if (is_chromeos && use_v4lplugin) {
+ action("libv4l2_generate_stubs") {
+ extra_header = "gpu/media/v4l2_stub_header.fragment"
+
+ script = "../../tools/generate_stubs/generate_stubs.py"
+ sources = [
+ "gpu/media/v4l2.sig",
+ ]
+ inputs = [
+ extra_header,
+ ]
+ stubs_filename_root = "v4l2_stubs"
+
+ outputs = [
+ "$target_gen_dir/gpu/media/$stubs_filename_root.cc",
+ "$target_gen_dir/gpu/media/$stubs_filename_root.h",
+ ]
+ args = [
+ "-i",
+ rebase_path("$target_gen_dir/gpu/media", root_build_dir),
+ "-o",
+ rebase_path("$target_gen_dir/gpu/media", root_build_dir),
+ "-t",
+ "posix_stubs",
+ "-e",
+ rebase_path(extra_header, root_build_dir),
+ "-s",
+ stubs_filename_root,
+ "-p",
+ "content/common/gpu/media",
+ ]
+
+ args += rebase_path(sources, root_build_dir)
+ }
+}
+
+if (is_mac) {
+ action("libvt_generate_stubs") {
+ extra_header = "gpu/media/vt_stubs_header.fragment"
+
+ script = "../../tools/generate_stubs/generate_stubs.py"
+ sources = [
+ "gpu/media/vt.sig",
+ ]
+ inputs = [
+ extra_header,
+ ]
+ stubs_filename_root = "vt_stubs"
+
+ outputs = [
+ "$target_gen_dir/gpu/media/$stubs_filename_root.cc",
+ "$target_gen_dir/gpu/media/$stubs_filename_root.h",
+ ]
+ args = [
+ "-i",
+ rebase_path("$target_gen_dir/gpu/media", root_build_dir),
+ "-o",
+ rebase_path("$target_gen_dir/gpu/media", root_build_dir),
+ "-t",
+ "posix_stubs",
+ "-e",
+ rebase_path(extra_header, root_build_dir),
+ "-s",
+ stubs_filename_root,
+ "-p",
+ "content/common/gpu/media",
]
args += rebase_path(sources, root_build_dir)
@@ -39,10 +127,12 @@ source_set("common") {
visibility = [ "//content/public/common:common_sources" ]
sources = rebase_path(content_common_gypi_values.private_common_sources,
- ".", "//content")
+ ".",
+ "//content")
configs += [
"//content:content_implementation",
+ "//build/config/compiler:no_size_t_to_int_warning",
]
public_deps = [
@@ -54,12 +144,13 @@ source_set("common") {
"//build/util:webkit_version",
"//components/tracing",
"//gpu/command_buffer/client:gles2_interface",
- "//gpu/command_buffer/client:gpu_memory_buffer_manager",
+ "//gpu/command_buffer/common:gles2_utils",
"//net",
"//skia",
"//third_party/icu",
"//ui/accessibility",
"//ui/base",
+ "//ui/base/ime",
"//ui/events/ipc",
"//ui/gfx",
"//ui/gfx/geometry",
@@ -74,8 +165,10 @@ source_set("common") {
"//cc",
"//ipc",
"//ipc/mojo",
+
# TODO: the dependency on gl_in_process_context should be decoupled from
# content and moved to android_webview. See crbug.com/365797.
+ "//gpu/blink",
"//gpu/command_buffer/client:gl_in_process_context",
"//gpu/command_buffer/client:gles2_c_lib",
"//gpu/command_buffer/client:gles2_cmd_helper",
@@ -84,16 +177,15 @@ source_set("common") {
"//gpu/ipc",
"//gpu/skia_bindings",
"//media",
+ "//media/midi",
"//media:shared_memory_support",
- "//mojo/edk/system",
+ "//mojo/application/public/interfaces",
"//mojo/environment:chromium",
- "//mojo/public/interfaces/application",
"//sandbox",
- "//storage/browser",
"//storage/common",
"//third_party/WebKit/public:blink",
+ "//third_party/mojo/src/mojo/edk/system",
"//ui/gl",
- "//webkit/common/gpu",
]
}
@@ -113,19 +205,30 @@ source_set("common") {
if (is_mac) {
sources += [
- "gpu/client/gpu_memory_buffer_impl_io_surface.cc",
- "gpu/client/gpu_memory_buffer_impl_io_surface.h",
- ]
- sources -= [
- "plugin_list_posix.cc",
- ]
+ "gpu/client/gpu_memory_buffer_impl_io_surface.cc",
+ "gpu/client/gpu_memory_buffer_impl_io_surface.h",
+ "gpu/gpu_memory_buffer_factory_io_surface.cc",
+ "gpu/gpu_memory_buffer_factory_io_surface.h",
+ "gpu/media/vt.h",
+ "gpu/media/vt_video_decode_accelerator.cc",
+ "gpu/media/vt_video_decode_accelerator.h",
+ ] + get_target_outputs(":libvt_generate_stubs")
+
+ sources -= [ "plugin_list_posix.cc" ]
deps += [
+ ":libvt_generate_stubs",
"//content/app/resources",
"//content:resources",
+ "//third_party/WebKit/public:image_resources",
"//third_party/WebKit/public:resources",
+ "//ui/accelerated_widget_mac",
+ ]
+ libs += [
+ "IOSurface.framework",
+ "OpenGL.framework",
+ "QuartzCore.framework",
]
- libs += [ "QuartzCore.framework" ]
}
if (is_android) {
@@ -144,23 +247,32 @@ source_set("common") {
libs += [ "android" ]
}
+ if (is_debug && !is_component_build) {
+ # Content depends on the PPAPI message logging stuff; if this isn't here,
+ # some unit test binaries won't compile. This only worked in release mode
+ # because logging is disabled there.
+ deps += [ "//ppapi/proxy:ipc_sources" ]
+ }
+
if (is_ios) {
sources -= [ "user_agent.cc" ]
assert(false, "Need to add lots of conditions here")
}
- if (!use_ozone) {
- sources -= [
- "cursors/webcursor_ozone.cc",
- "font_list_ozone.cc",
- "gpu/gpu_memory_buffer_factory_ozone.cc",
+ if (use_ozone) {
+ deps += [
+ "//ui/ozone:ozone",
+ "//ui/ozone:ozone_base",
+ "//ui/ozone/gpu",
]
} else {
sources -= [
- "gpu/gpu_memory_buffer_factory_linux.cc",
- ]
- deps += [
- "//ui/ozone/gpu",
+ "cursors/webcursor_ozone.cc",
+ "font_list_ozone.cc",
+ "gpu/client/gpu_memory_buffer_impl_ozone_native_buffer.cc",
+ "gpu/client/gpu_memory_buffer_impl_ozone_native_buffer.h",
+ "gpu/gpu_memory_buffer_factory_ozone_native_buffer.cc",
+ "gpu/gpu_memory_buffer_factory_ozone_native_buffer.h",
]
}
@@ -180,27 +292,22 @@ source_set("common") {
sources -= [ "font_list_ozone.cc" ]
}
} else {
- sources -= [
- "font_list_pango.cc",
- ]
+ sources -= [ "font_list_pango.cc" ]
}
if (use_x11) {
- include_dirs += [ "//third_party/khronos" ]
- configs += [ "//build/config/linux:xcomposite" ]
+ configs += [
+ "//build/config/linux:xcomposite",
+ "//third_party/khronos:khronos_headers",
+ ]
- if (cpu_arch != "arm" || !is_chromeos) {
- sources +=[
- "gpu/x_util.cc",
- "gpu/x_util.h",
- ]
+ if (current_cpu != "arm" || !is_chromeos) {
+ sources += [ "gpu/x_util.h" ]
}
}
if (enable_plugins) {
- deps += [
- "//ppapi:ppapi_shared",
- ]
+ deps += [ "//ppapi/shared_impl" ]
} else {
sources -= [
"pepper_file_util.cc",
@@ -228,37 +335,62 @@ source_set("common") {
}
}
- if (is_chromeos && use_x11) {
- if (cpu_arch == "arm") {
+ if (is_chromeos) {
+ sources += [
+ "gpu/media/accelerated_video_decoder.h",
+ "gpu/media/h264_decoder.cc",
+ "gpu/media/h264_decoder.h",
+ "gpu/media/h264_dpb.cc",
+ "gpu/media/h264_dpb.h",
+ "gpu/media/vp8_decoder.cc",
+ "gpu/media/vp8_decoder.h",
+ "gpu/media/vp8_picture.cc",
+ "gpu/media/vp8_picture.h",
+ ]
+ if (use_v4lplugin) {
+ defines += [ "USE_LIBV4L2" ]
+ sources += get_target_outputs(":libv4l2_generate_stubs")
+ deps += [ ":libv4l2_generate_stubs" ]
+ }
+ if (use_v4l2_codec) {
+ defines += [ "USE_V4L2_CODEC" ]
sources += [
- "gpu/media/exynos_v4l2_video_device.cc",
- "gpu/media/exynos_v4l2_video_device.h",
- "gpu/media/tegra_v4l2_video_device.cc",
- "gpu/media/tegra_v4l2_video_device.h",
+ "gpu/media/generic_v4l2_device.cc",
+ "gpu/media/generic_v4l2_device.h",
+ "gpu/media/v4l2_device.cc",
+ "gpu/media/v4l2_device.h",
"gpu/media/v4l2_image_processor.cc",
"gpu/media/v4l2_image_processor.h",
+ "gpu/media/v4l2_slice_video_decode_accelerator.cc",
+ "gpu/media/v4l2_slice_video_decode_accelerator.h",
"gpu/media/v4l2_video_decode_accelerator.cc",
"gpu/media/v4l2_video_decode_accelerator.h",
- "gpu/media/v4l2_video_device.cc",
- "gpu/media/v4l2_video_device.h",
"gpu/media/v4l2_video_encode_accelerator.cc",
"gpu/media/v4l2_video_encode_accelerator.h",
]
- libs = [ "EGL", "GLESv2" ]
- } else { # !arm
+ libs = [
+ "EGL",
+ "GLESv2",
+ ]
+ }
+ if (current_cpu == "arm") {
sources += [
- "gpu/media/h264_dpb.cc",
- "gpu/media/h264_dpb.h",
- "gpu/media/va_surface.h",
- "gpu/media/vaapi_h264_decoder.cc",
- "gpu/media/vaapi_h264_decoder.h",
- "gpu/media/vaapi_video_decode_accelerator.cc",
- "gpu/media/vaapi_video_decode_accelerator.h",
- "gpu/media/vaapi_video_encode_accelerator.cc",
- "gpu/media/vaapi_video_encode_accelerator.h",
- "gpu/media/vaapi_wrapper.cc",
- "gpu/media/vaapi_wrapper.h",
- ] + get_target_outputs(":libva_generate_stubs")
+ "gpu/media/tegra_v4l2_device.cc",
+ "gpu/media/tegra_v4l2_device.h",
+ ]
+ }
+ if (current_cpu != "arm") {
+ sources += [
+ "gpu/media/va_surface.h",
+ "gpu/media/vaapi_picture.cc",
+ "gpu/media/vaapi_picture.h",
+ "gpu/media/vaapi_video_decode_accelerator.cc",
+ "gpu/media/vaapi_video_decode_accelerator.h",
+ "gpu/media/vaapi_video_encode_accelerator.cc",
+ "gpu/media/vaapi_video_encode_accelerator.h",
+ "gpu/media/vaapi_wrapper.cc",
+ "gpu/media/vaapi_wrapper.h",
+ ] + get_target_outputs(":libva_generate_stubs")
configs += [
"//third_party/libva:libva_config",
"//third_party/libyuv:libyuv_config",
@@ -268,6 +400,18 @@ source_set("common") {
"//media",
"//third_party/libyuv",
]
+ if (use_x11) {
+ sources += [
+ "gpu/media/vaapi_tfp_picture.cc",
+ "gpu/media/vaapi_tfp_picture.h",
+ ]
+ }
+ if (use_ozone) {
+ sources += [
+ "gpu/media/vaapi_drm_picture.cc",
+ "gpu/media/vaapi_drm_picture.h",
+ ]
+ }
}
}
@@ -276,9 +420,23 @@ source_set("common") {
"gpu/media/dxva_video_decode_accelerator.cc",
"gpu/media/dxva_video_decode_accelerator.h",
]
- include_dirs += [ "//third_party/khronos" ]
- deps += [
- "//ui/gl",
+ configs += [ "//third_party/khronos:khronos_headers" ]
+ deps += [ "//ui/gl" ]
+ libs += [
+ "d3d9.lib",
+ "d3d11.lib",
+ "dxva2.lib",
+ "strmiids.lib",
+ "mf.lib",
+ "mfplat.lib",
+ "mfuuid.lib",
+ ]
+ ldflags += [
+ "/DELAYLOAD:d3d9.dll",
+ "/DELAYLOAD:d3d11.dll",
+ "/DELAYLOAD:dxva2.dll",
+ "/DELAYLOAD:mf.dll",
+ "/DELAYLOAD:mfplat.dll",
]
# TODO(GYP): extract_xinput action.
@@ -314,16 +472,25 @@ source_set("common") {
]
}
}
+
+ if (is_win && current_cpu == "x64") {
+ # TODO(jschuh): Remove this after crbug.com/173851 gets fixed.
+ cflags = [ "/bigobj" ]
+ }
}
mojom("mojo_bindings") {
sources = [
+ "application_setup.mojom",
+ "background_sync_service.mojom",
"geolocation_service.mojom",
+ "permission_service.mojom",
+ "presentation/presentation_service.mojom",
"render_frame_setup.mojom",
]
deps = [
"//content/public/common:mojo_bindings",
- "//mojo/public/interfaces/application:application",
+ "//mojo/application/public/interfaces",
]
}
diff --git a/chromium/content/common/DEPS b/chromium/content/common/DEPS
index 3a9551d0265..66eb41ff652 100644
--- a/chromium/content/common/DEPS
+++ b/chromium/content/common/DEPS
@@ -2,7 +2,6 @@ include_rules = [
"+media/audio",
"+media/base",
"-storage/browser",
- "-webkit/renderer",
# No inclusion of WebKit from the browser, other than strictly enum/POD,
# header-only types, and some selected common code.
@@ -10,44 +9,48 @@ include_rules = [
"+third_party/WebKit/public/platform/WebBatteryStatus.h",
"+third_party/WebKit/public/platform/WebCircularGeofencingRegion.h",
"+third_party/WebKit/public/platform/WebCString.h",
- "+third_party/WebKit/public/platform/WebDeviceMotionData.h",
- "+third_party/WebKit/public/platform/WebDeviceOrientationData.h",
+ "+third_party/WebKit/public/platform/modules/device_orientation/WebDeviceMotionData.h",
+ "+third_party/WebKit/public/platform/modules/device_orientation/WebDeviceOrientationData.h",
+ "+third_party/WebKit/public/platform/WebDisplayMode.h",
"+third_party/WebKit/public/platform/WebFloatPoint.h",
"+third_party/WebKit/public/platform/WebFloatRect.h",
+ "+third_party/WebKit/public/platform/WebFocusType.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/WebHistoryScrollRestorationType.h",
"+third_party/WebKit/public/platform/WebHTTPBody.h",
- "+third_party/WebKit/public/platform/WebIDBCursor.h",
- "+third_party/WebKit/public/platform/WebIDBDatabase.h",
- "+third_party/WebKit/public/platform/WebIDBTypes.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/WebPageVisibilityState.h",
"+third_party/WebKit/public/platform/WebReferrerPolicy.h",
+ "+third_party/WebKit/public/platform/WebScreenInfo.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/WebServiceWorkerClientType.h",
"+third_party/WebKit/public/platform/WebServiceWorkerError.h",
"+third_party/WebKit/public/platform/WebServiceWorkerEventResult.h",
- "+third_party/WebKit/public/platform/WebServiceWorkerCacheError.h",
"+third_party/WebKit/public/platform/WebServiceWorkerResponseType.h",
"+third_party/WebKit/public/platform/WebServiceWorkerState.h",
"+third_party/WebKit/public/platform/WebStorageArea.h",
"+third_party/WebKit/public/platform/WebString.h",
- "+third_party/WebKit/public/platform/linux/WebFontRenderStyle.h",
"+third_party/WebKit/public/platform/linux/WebFallbackFont.h",
+ "+third_party/WebKit/public/platform/linux/WebFontRenderStyle.h",
+ "+third_party/WebKit/public/platform/modules/indexeddb/WebIDBTypes.h",
+ "+third_party/WebKit/public/platform/modules/notifications/WebNotificationPermission.h",
+ "+third_party/WebKit/public/platform/modules/push_messaging/WebPushError.h",
+ "+third_party/WebKit/public/platform/modules/push_messaging/WebPushPermissionStatus.h",
"+third_party/WebKit/public/web/mac/WebScrollbarTheme.h",
"+third_party/WebKit/public/web/WebAXEnums.h",
"+third_party/WebKit/public/web/WebCompositionUnderline.h",
"+third_party/WebKit/public/web/WebContentSecurityPolicy.h",
+ "+third_party/WebKit/public/web/WebDeviceEmulationParams.h",
"+third_party/WebKit/public/web/WebDragOperation.h",
"+third_party/WebKit/public/web/WebDragStatus.h",
"+third_party/WebKit/public/web/WebFindOptions.h",
"+third_party/WebKit/public/web/WebInputEvent.h",
"+third_party/WebKit/public/web/WebMediaPlayerAction.h",
- "+third_party/WebKit/public/web/WebPageVisibilityState.h",
"+third_party/WebKit/public/web/WebPluginAction.h",
"+third_party/WebKit/public/web/WebPopupType.h",
"+third_party/WebKit/public/web/WebTextDirection.h",
diff --git a/chromium/content/common/OWNERS b/chromium/content/common/OWNERS
index 4bc5132b1a4..c035cf2c340 100644
--- a/chromium/content/common/OWNERS
+++ b/chromium/content/common/OWNERS
@@ -72,3 +72,7 @@ per-file websocket.*=yhirano@chromium.org
# Compositor
per-file cc_messages_unittest.cc=danakj@chromium.org
per-file cc_messages_perftest.cc=danakj@chromium.org
+
+# DirectWrite
+per-file dwrite_font_platform_win*=shrikant@chromium.org
+per-file dwrite_font_platform_win*=scottmg@chromium.org
diff --git a/chromium/content/common/accessibility_messages.h b/chromium/content/common/accessibility_messages.h
index 69dfb51d3ae..e7d0bcdff6c 100644
--- a/chromium/content/common/accessibility_messages.h
+++ b/chromium/content/common/accessibility_messages.h
@@ -178,6 +178,12 @@ IPC_MESSAGE_ROUTED1(AccessibilityMsg_Reset,
// and we've already reset too many times.
IPC_MESSAGE_ROUTED0(AccessibilityMsg_FatalError)
+// Request a one-time snapshot of the accessibility tree without
+// enabling accessibility if it wasn't already enabled. The passed id
+// will be returned in the AccessibilityHostMsg_SnapshotResponse message.
+IPC_MESSAGE_ROUTED1(AccessibilityMsg_SnapshotTree,
+ int /* callback id */)
+
// Messages sent from the renderer to the browser.
// Sent to notify the browser about renderer accessibility events.
@@ -200,3 +206,10 @@ IPC_MESSAGE_ROUTED1(
IPC_MESSAGE_ROUTED1(
AccessibilityHostMsg_FindInPageResult,
AccessibilityHostMsg_FindInPageResultParams)
+
+// Sent in response to AccessibilityMsg_SnapshotTree. The callback id that was
+// passed to the request will be returned in |callback_id|, along with
+// a standalone snapshot of the accessibility tree.
+IPC_MESSAGE_ROUTED2(AccessibilityHostMsg_SnapshotResponse,
+ int /* callback_id */,
+ ui::AXTreeUpdate)
diff --git a/chromium/content/common/android/address_parser.cc b/chromium/content/common/android/address_parser.cc
index 30fa304ba4c..41bdeb72ff1 100644
--- a/chromium/content/common/android/address_parser.cc
+++ b/chromium/content/common/android/address_parser.cc
@@ -182,8 +182,14 @@ bool FindAddress(const base::string16::const_iterator& begin,
size_t zip_word = state_last_word + 1;
if (zip_word == words.size()) {
do {
- if (!tokenizer.GetNext())
- return false;
+ if (!tokenizer.GetNext()) {
+ // The address ends with a state name without a zip code. This
+ // is legal according to WebView#findAddress public
+ // documentation.
+ *start_pos = words[0].begin - begin;
+ *end_pos = words[state_last_word].end - begin;
+ return true;
+ }
} while (tokenizer.token_is_delim());
words.push_back(Word(tokenizer.token_begin(),
tokenizer.token_end()));
diff --git a/chromium/content/common/android/address_parser.h b/chromium/content/common/android/address_parser.h
index 1a12a32c14d..036e27e745d 100644
--- a/chromium/content/common/android/address_parser.h
+++ b/chromium/content/common/android/address_parser.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_COMMON_ADDRESS_PARSER_H_
-#define CONTENT_COMMON_ADDRESS_PARSER_H_
+#ifndef CONTENT_COMMON_ANDROID_ADDRESS_PARSER_H_
+#define CONTENT_COMMON_ANDROID_ADDRESS_PARSER_H_
#include "base/strings/string16.h"
#include "content/common/content_export.h"
@@ -32,4 +32,4 @@ CONTENT_EXPORT bool FindAddress(const base::string16::const_iterator& begin,
} // namespace content
-#endif // CONTENT_COMMON_ADDRESS_PARSER_H_
+#endif // CONTENT_COMMON_ANDROID_ADDRESS_PARSER_H_
diff --git a/chromium/content/common/android/address_parser_internal.cc b/chromium/content/common/android/address_parser_internal.cc
index cc71b241ba4..127fb3c4cd6 100644
--- a/chromium/content/common/android/address_parser_internal.cc
+++ b/chromium/content/common/android/address_parser_internal.cc
@@ -66,6 +66,9 @@ namespace address_parser {
namespace internal {
+Word::Word() {
+}
+
Word::Word(const base::string16::const_iterator& begin,
const base::string16::const_iterator& end)
: begin(begin),
@@ -73,6 +76,9 @@ Word::Word(const base::string16::const_iterator& begin,
DCHECK(begin <= end);
}
+HouseNumberParser::HouseNumberParser() {
+}
+
bool HouseNumberParser::IsPreDelimiter(base::char16 character) {
return character == ':' || IsPostDelimiter(character);
}
diff --git a/chromium/content/common/android/address_parser_internal.h b/chromium/content/common/android/address_parser_internal.h
index 2c9d19cecfe..760dea60105 100644
--- a/chromium/content/common/android/address_parser_internal.h
+++ b/chromium/content/common/android/address_parser_internal.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_COMMON_ADDRESS_PARSER_INTERNAL_H_
-#define CONTENT_COMMON_ADDRESS_PARSER_INTERNAL_H_
+#ifndef CONTENT_COMMON_ANDROID_ADDRESS_PARSER_INTERNAL_H_
+#define CONTENT_COMMON_ANDROID_ADDRESS_PARSER_INTERNAL_H_
#include <vector>
@@ -22,7 +22,7 @@ struct CONTENT_EXPORT Word {
base::string16::const_iterator begin;
base::string16::const_iterator end;
- Word() {}
+ Word();
Word(const base::string16::const_iterator& begin,
const base::string16::const_iterator& end);
};
@@ -30,7 +30,7 @@ struct CONTENT_EXPORT Word {
// Exposed for tests.
class CONTENT_EXPORT HouseNumberParser {
public:
- HouseNumberParser() {}
+ HouseNumberParser();
bool Parse(const base::string16::const_iterator& begin,
const base::string16::const_iterator& end,
@@ -83,4 +83,4 @@ CONTENT_EXPORT bool IsZipValidForState(const Word& word, size_t state_index);
} // namespace content
-#endif // CONTENT_COMMON_ADDRESS_PARSER_INTERNAL_H_
+#endif // CONTENT_COMMON_ANDROID_ADDRESS_PARSER_INTERNAL_H_
diff --git a/chromium/content/common/android/address_parser_unittest.cc b/chromium/content/common/android/address_parser_unittest.cc
index cefc537b790..dd7148dbb49 100644
--- a/chromium/content/common/android/address_parser_unittest.cc
+++ b/chromium/content/common/android/address_parser_unittest.cc
@@ -592,3 +592,8 @@ TEST_F(AddressParserTest, FullAddress) {
"1 Supercalifragilisticexpialidocious is too long, CA 90000"));
EXPECT_FALSE(ContainsAddress(""));
}
+
+TEST_F(AddressParserTest, FullAddressWithoutZipCode) {
+ EXPECT_TRUE(IsAddress("1600 Amphitheatre Parkway Mountain View, CA"));
+ EXPECT_TRUE(IsAddress("201 S. Division St. Suite 500 Ann Arbor, MI"));
+}
diff --git a/chromium/content/common/android/gin_java_bridge_value_unittest.cc b/chromium/content/common/android/gin_java_bridge_value_unittest.cc
index 72a0ea87a0e..02768488d5c 100644
--- a/chromium/content/common/android/gin_java_bridge_value_unittest.cc
+++ b/chromium/content/common/android/gin_java_bridge_value_unittest.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 <cmath>
+
#include "base/basictypes.h"
-#include "base/float_util.h"
#include "base/memory/scoped_ptr.h"
#include "content/common/android/gin_java_bridge_value.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -40,8 +41,7 @@ TEST_F(GinJavaBridgeValueTest, BasicValues) {
ASSERT_TRUE(float_infinity_value.get());
EXPECT_TRUE(float_infinity_value->IsType(GinJavaBridgeValue::TYPE_NONFINITE));
EXPECT_TRUE(float_infinity_value->GetAsNonFinite(&native_float));
- EXPECT_FALSE(base::IsFinite(native_float));
- EXPECT_FALSE(base::IsNaN(native_float));
+ EXPECT_TRUE(std::isinf(native_float));
EXPECT_FALSE(undefined_value->GetAsObjectID(&native_object_id));
@@ -57,8 +57,7 @@ TEST_F(GinJavaBridgeValueTest, BasicValues) {
EXPECT_TRUE(
double_infinity_value->IsType(GinJavaBridgeValue::TYPE_NONFINITE));
EXPECT_TRUE(double_infinity_value->GetAsNonFinite(&native_float));
- EXPECT_FALSE(base::IsFinite(native_float));
- EXPECT_FALSE(base::IsNaN(native_float));
+ EXPECT_TRUE(std::isinf(native_float));
EXPECT_FALSE(undefined_value->GetAsObjectID(&native_object_id));
diff --git a/chromium/content/common/android/surface_texture_manager.h b/chromium/content/common/android/surface_texture_manager.h
index 3227f019599..cff81b98319 100644
--- a/chromium/content/common/android/surface_texture_manager.h
+++ b/chromium/content/common/android/surface_texture_manager.h
@@ -5,6 +5,7 @@
#ifndef CONTENT_COMMON_ANDROID_SURFACE_TEXTURE_MANAGER_H_
#define CONTENT_COMMON_ANDROID_SURFACE_TEXTURE_MANAGER_H_
+#include "content/common/content_export.h"
#include "ui/gfx/native_widget_types.h"
namespace gfx {
@@ -13,7 +14,7 @@ class SurfaceTexture;
namespace content {
-class SurfaceTextureManager {
+class CONTENT_EXPORT SurfaceTextureManager {
public:
static SurfaceTextureManager* GetInstance();
static void InitInstance(SurfaceTextureManager* instance);
diff --git a/chromium/content/common/appcache_interfaces.cc b/chromium/content/common/appcache_interfaces.cc
index f9f9a05b3a7..7f3f547139d 100644
--- a/chromium/content/common/appcache_interfaces.cc
+++ b/chromium/content/common/appcache_interfaces.cc
@@ -7,14 +7,13 @@
#include <set>
#include "base/strings/string_util.h"
+#include "content/public/common/url_constants.h"
#include "net/url_request/url_request.h"
#include "url/gurl.h"
+#include "url/url_constants.h"
namespace content {
-const char kHttpScheme[] = "http";
-const char kHttpsScheme[] = "https";
-const char kDevToolsScheme[] = "chrome-devtools";
const char kHttpGETMethod[] = "GET";
const char kHttpHEADMethod[] = "HEAD";
@@ -112,8 +111,9 @@ bool AppCacheNamespace::IsMatch(const GURL& url) const {
}
bool IsSchemeSupportedForAppCache(const GURL& url) {
- bool supported = url.SchemeIs(kHttpScheme) || url.SchemeIs(kHttpsScheme) ||
- url.SchemeIs(kDevToolsScheme);
+ bool supported = url.SchemeIs(url::kHttpScheme) ||
+ url.SchemeIs(url::kHttpsScheme) ||
+ url.SchemeIs(kChromeDevToolsScheme);
#ifndef NDEBUG
// TODO(michaeln): It would be really nice if this could optionally work for
diff --git a/chromium/content/common/appcache_interfaces.h b/chromium/content/common/appcache_interfaces.h
index 7199fbb1330..72afaa80bfe 100644
--- a/chromium/content/common/appcache_interfaces.h
+++ b/chromium/content/common/appcache_interfaces.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_COMMON_APPCACHE_APPCACHE_INTERFACES_H_
-#define CONTENT_COMMON_APPCACHE_APPCACHE_INTERFACES_H_
+#ifndef CONTENT_COMMON_APPCACHE_INTERFACES_H_
+#define CONTENT_COMMON_APPCACHE_INTERFACES_H_
#include <string>
@@ -163,15 +163,10 @@ class CONTENT_EXPORT AppCacheBackend {
};
// Useful string constants.
-// Note: These are also defined elsewhere in the chrome code base in
-// url_contants.h .cc, however the content library can not have
-// any dependencies on the chrome library, so we can't use them in here.
-CONTENT_EXPORT extern const char kHttpScheme[];
-CONTENT_EXPORT extern const char kHttpsScheme[];
CONTENT_EXPORT extern const char kHttpGETMethod[];
CONTENT_EXPORT extern const char kHttpHEADMethod[];
-// CommandLine flag to turn this experimental feature on.
+// base::CommandLine flag to turn this experimental feature on.
CONTENT_EXPORT extern const char kEnableExecutableHandlers[];
CONTENT_EXPORT bool IsSchemeSupportedForAppCache(const GURL& url);
@@ -185,4 +180,4 @@ CONTENT_EXPORT extern const base::FilePath::CharType
} // namespace
-#endif // CONTENT_COMMON_APPCACHE_APPCACHE_INTERFACES_H_
+#endif // CONTENT_COMMON_APPCACHE_INTERFACES_H_
diff --git a/chromium/content/common/application_setup.mojom b/chromium/content/common/application_setup.mojom
new file mode 100644
index 00000000000..1005663cd9a
--- /dev/null
+++ b/chromium/content/common/application_setup.mojom
@@ -0,0 +1,12 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module content;
+
+import "mojo/application/public/interfaces/service_provider.mojom";
+
+interface ApplicationSetup {
+ ExchangeServiceProviders(mojo.ServiceProvider& services,
+ mojo.ServiceProvider exposed_services);
+};
diff --git a/chromium/content/common/background_sync_service.mojom b/chromium/content/common/background_sync_service.mojom
new file mode 100644
index 00000000000..bbacc54c262
--- /dev/null
+++ b/chromium/content/common/background_sync_service.mojom
@@ -0,0 +1,33 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module content;
+
+import "content/public/common/background_sync.mojom";
+
+enum BackgroundSyncError {
+ NONE,
+ STORAGE,
+ NOT_FOUND,
+ NO_SERVICE_WORKER,
+ MAX=NO_SERVICE_WORKER
+};
+
+interface BackgroundSyncService {
+ Register(SyncRegistration options, int64 service_worker_registration_id)
+ => (BackgroundSyncError err, SyncRegistration options);
+ GetRegistration(BackgroundSyncPeriodicity periodicity, string tag,
+ int64 service_worker_registration_id)
+ => (BackgroundSyncError err, SyncRegistration? registration);
+ GetRegistrations(BackgroundSyncPeriodicity periodicity,
+ int64 service_worker_registration_id)
+ => (BackgroundSyncError err, array<SyncRegistration> registrations);
+ Unregister(BackgroundSyncPeriodicity periodicity, int64 id, string tag,
+ int64 service_worker_registration_id) => (BackgroundSyncError err);
+};
+
+interface BackgoundSyncServiceClient {
+ Sync(SyncRegistration event);
+};
+
diff --git a/chromium/content/common/bluetooth/DEPS b/chromium/content/common/bluetooth/DEPS
new file mode 100644
index 00000000000..2c5a329542a
--- /dev/null
+++ b/chromium/content/common/bluetooth/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+ "+device/bluetooth",
+]
+
diff --git a/chromium/content/common/bluetooth/OWNERS b/chromium/content/common/bluetooth/OWNERS
new file mode 100644
index 00000000000..aae325e5f14
--- /dev/null
+++ b/chromium/content/common/bluetooth/OWNERS
@@ -0,0 +1,14 @@
+scheib@chromium.org
+
+# For security review of IPC message files.
+per-file *_messages*.h=set noparent
+per-file *_messages*.h=dcheng@chromium.org
+per-file *_messages*.h=inferno@chromium.org
+per-file *_messages*.h=jln@chromium.org
+per-file *_messages*.h=jschuh@chromium.org
+per-file *_messages*.h=kenrb@chromium.org
+per-file *_messages*.h=mkwst@chromium.org
+per-file *_messages*.h=nasko@chromium.org
+per-file *_messages*.h=palmer@chromium.org
+per-file *_messages*.h=tsepez@chromium.org
+per-file *_messages*.h=wfh@chromium.org
diff --git a/chromium/content/common/bluetooth/PRESUBMIT.py b/chromium/content/common/bluetooth/PRESUBMIT.py
new file mode 100644
index 00000000000..3f9babedbd6
--- /dev/null
+++ b/chromium/content/common/bluetooth/PRESUBMIT.py
@@ -0,0 +1,14 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Presubmit script.
+
+See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
+for more details about the presubmit API built into depot_tools.
+"""
+
+def CheckChangeOnUpload(input_api, output_api):
+ results = []
+ results += input_api.canned_checks.CheckPatchFormatted(input_api, output_api)
+ return results
diff --git a/chromium/content/common/bluetooth/bluetooth_device.cc b/chromium/content/common/bluetooth/bluetooth_device.cc
new file mode 100644
index 00000000000..ee9a087291d
--- /dev/null
+++ b/chromium/content/common/bluetooth/bluetooth_device.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/common/bluetooth/bluetooth_device.h"
+
+#include "base/strings/string_util.h"
+
+namespace content {
+
+BluetoothDevice::BluetoothDevice()
+ : instance_id(""),
+ name(base::string16()),
+ device_class(0),
+ vendor_id_source(
+ device::BluetoothDevice::VendorIDSource::VENDOR_ID_UNKNOWN),
+ vendor_id(0),
+ product_id(0),
+ product_version(0),
+ paired(false),
+ uuids() {
+}
+
+BluetoothDevice::BluetoothDevice(
+ const std::string& instance_id,
+ const base::string16& name,
+ uint32 device_class,
+ device::BluetoothDevice::VendorIDSource vendor_id_source,
+ uint16 vendor_id,
+ uint16 product_id,
+ uint16 product_version,
+ bool paired,
+ const std::vector<std::string>& uuids)
+ : instance_id(instance_id),
+ name(name),
+ device_class(device_class),
+ vendor_id_source(vendor_id_source),
+ vendor_id(vendor_id),
+ product_id(product_id),
+ product_version(product_version),
+ paired(paired),
+ uuids(uuids) {
+}
+
+BluetoothDevice::~BluetoothDevice() {
+}
+
+// static
+std::vector<std::string> BluetoothDevice::UUIDsFromBluetoothUUIDs(
+ const device::BluetoothDevice::UUIDList& uuid_list) {
+ std::vector<std::string> uuids;
+ uuids.reserve(uuid_list.size());
+ for (const auto& it : uuid_list)
+ uuids.push_back(it.canonical_value());
+ return uuids;
+}
+
+} // namespace content
diff --git a/chromium/content/common/bluetooth/bluetooth_device.h b/chromium/content/common/bluetooth/bluetooth_device.h
new file mode 100644
index 00000000000..987477626e2
--- /dev/null
+++ b/chromium/content/common/bluetooth/bluetooth_device.h
@@ -0,0 +1,48 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_COMMON_BLUETOOTH_BLUETOOTH_DEVICE_H_
+#define CONTENT_COMMON_BLUETOOTH_BLUETOOTH_DEVICE_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+#include "content/common/content_export.h"
+#include "device/bluetooth/bluetooth_device.h"
+
+namespace content {
+
+// Data sent over IPC representing a Bluetooth device, corresponding to
+// blink::WebBluetoothDevice.
+struct CONTENT_EXPORT BluetoothDevice {
+ BluetoothDevice();
+ BluetoothDevice(const std::string& instance_id,
+ const base::string16& name,
+ uint32 device_class,
+ device::BluetoothDevice::VendorIDSource vendor_id_source,
+ uint16 vendor_id,
+ uint16 product_id,
+ uint16 product_version,
+ bool paired,
+ const std::vector<std::string>& uuids);
+ ~BluetoothDevice();
+
+ static std::vector<std::string> UUIDsFromBluetoothUUIDs(
+ const device::BluetoothDevice::UUIDList& uuid_list);
+
+ std::string instance_id;
+ base::string16 name;
+ uint32 device_class;
+ device::BluetoothDevice::VendorIDSource vendor_id_source;
+ uint16 vendor_id;
+ uint16 product_id;
+ uint16 product_version;
+ bool paired;
+ std::vector<std::string> uuids; // 128bit UUIDs with dashes. 36 chars.
+};
+
+} // namespace content
+
+#endif // CONTENT_COMMON_BLUETOOTH_BLUETOOTH_DEVICE_H_
diff --git a/chromium/content/common/bluetooth/bluetooth_error.h b/chromium/content/common/bluetooth/bluetooth_error.h
new file mode 100644
index 00000000000..7ebf7aef8c1
--- /dev/null
+++ b/chromium/content/common/bluetooth/bluetooth_error.h
@@ -0,0 +1,21 @@
+// Copyright 2014 The Chromium Authors. 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_COMMON_BLUETOOTH_BLUETOOTH_ERROR_H_
+#define CONTENT_COMMON_BLUETOOTH_BLUETOOTH_ERROR_H_
+
+namespace content {
+
+// Error enumerations corresponding to blink::WebBluetoothError::ErrorType
+// used to create DOMExceptions.
+enum class BluetoothError {
+ NOT_FOUND,
+ NETWORK_ERROR,
+ SECURITY,
+ ENUM_MAX_VALUE = SECURITY
+};
+
+} // namespace content
+
+#endif // CONTENT_COMMON_BLUETOOTH_BLUETOOTH_ERROR_H_
diff --git a/chromium/content/common/bluetooth/bluetooth_messages.h b/chromium/content/common/bluetooth/bluetooth_messages.h
new file mode 100644
index 00000000000..dda97d42eda
--- /dev/null
+++ b/chromium/content/common/bluetooth/bluetooth_messages.h
@@ -0,0 +1,148 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Messages for Web Bluetooth API.
+// Multiply-included message file, hence no include guard.
+
+// Web Bluetooth Security
+// The security mechanisms of Bluetooth are described in the specification:
+// https://webbluetoothcg.github.io/web-bluetooth
+//
+// Exerpts:
+//
+// From: Security and privacy considerations
+// http://webbluetoothcg.github.io/web-bluetooth/#security-and-privacy-considerations
+// """
+// When a website requests access to devices using requestDevice, it gets the
+// ability to access all GATT services mentioned in the call. The UA must inform
+// the user what capabilities these services give the website before asking
+// which devices to entrust to it. If any services in the list aren't known to
+// the UA, the UA must assume they give the site complete control over the
+// device and inform the user of this risk. The UA must also allow the user to
+// inspect what sites have access to what devices and revoke these pairings.
+//
+// The UA must not allow the user to pair entire classes of devices with a
+// website. It is possible to construct a class of devices for which each
+// individual device sends the same Bluetooth-level identifying information. UAs
+// are not required to attempt to detect this sort of forgery and may let a user
+// pair this pseudo-device with a website.
+//
+// To help ensure that only the entity the user approved for access actually has
+// access, this specification requires that only authenticated environments can
+// access Bluetooth devices (requestDevice).
+// """
+//
+// From: Per-origin Bluetooth device properties:
+// """
+// For each origin, the UA must maintain an allowed devices map, whose keys are
+// the Bluetooth devices the origin is allowed to access, and whose values are
+// pairs of a DOMString device id and an allowed services list consisting of
+// UUIDs for GATT Primary Services the origin is allowed to access on the
+// device.
+//
+// The UA may remove devices from the allowed devices map at any time based on
+// signals from the user. This needs a definition involving removing
+// BluetoothDevice instances from device instance maps and clearing out their
+// [[representedDevice]] fields. For example, if the user chooses not to
+// remember access, the UA might remove a device when the tab that was granted
+// access to it is closed. Or the UA might provide a revocation UI that allows
+// the user to explicitly remove a device even while a tab is actively using
+// that device. If a device is removed from this list while a Promise is pending
+// to do something with the device, it must be treated the same as if the device
+// moved out of Bluetooth range.
+// """
+//
+// From: Device Discovery: requestDevice
+// http://webbluetoothcg.github.io/web-bluetooth/#device-discovery
+// """
+// Even if scanResult is empty, display a prompt to the user requesting that the
+// user select a device from it. The UA should show the user the human-readable
+// name of each device. If this name is not available because the UA's Bluetooth
+// system doesn't support privacy-enabled scans, the UA should allow the user to
+// indicate interest and then perform a privacy-disabled scan to retrieve the
+// name.
+//
+// The UA may allow the user to select a nearby device that does not match
+// filters.
+//
+// Wait for the user to have selected a device or cancelled the prompt.
+//
+// If the user cancels the prompt, reject promise with a NotFoundError and abort
+// these steps.
+//
+// Add device to the origin's allowed devices map. with the union of the service
+// UUIDs from filters and options.optionalServices as allowed services.
+//
+// Get the BluetoothDevice representing device and resolve promise with the
+// result.
+// """
+
+#include "ipc/ipc_message_macros.h"
+#include "content/common/bluetooth/bluetooth_device.h"
+#include "content/common/bluetooth/bluetooth_error.h"
+
+#define IPC_MESSAGE_START BluetoothMsgStart
+
+IPC_ENUM_TRAITS_MAX_VALUE(
+ device::BluetoothDevice::VendorIDSource,
+ device::BluetoothDevice::VendorIDSource::VENDOR_ID_MAX_VALUE)
+
+IPC_STRUCT_TRAITS_BEGIN(content::BluetoothDevice)
+IPC_STRUCT_TRAITS_MEMBER(instance_id)
+IPC_STRUCT_TRAITS_MEMBER(name)
+IPC_STRUCT_TRAITS_MEMBER(device_class)
+IPC_STRUCT_TRAITS_MEMBER(vendor_id_source)
+IPC_STRUCT_TRAITS_MEMBER(vendor_id)
+IPC_STRUCT_TRAITS_MEMBER(product_id)
+IPC_STRUCT_TRAITS_MEMBER(product_version)
+IPC_STRUCT_TRAITS_MEMBER(paired)
+IPC_STRUCT_TRAITS_MEMBER(uuids)
+IPC_STRUCT_TRAITS_END()
+
+IPC_ENUM_TRAITS_MAX_VALUE(content::BluetoothError,
+ content::BluetoothError::ENUM_MAX_VALUE)
+
+// Messages sent from the browser to the renderer.
+
+// Informs the renderer that the device request |request_id| succeeded.
+IPC_MESSAGE_CONTROL3(BluetoothMsg_RequestDeviceSuccess,
+ int /* thread_id */,
+ int /* request_id */,
+ content::BluetoothDevice /* device */)
+
+// Informs the renderer that the device request |request_id| failed.
+IPC_MESSAGE_CONTROL3(BluetoothMsg_RequestDeviceError,
+ int /* thread_id */,
+ int /* request_id */,
+ content::BluetoothError /* result */)
+
+// Informs the renderer that the connection request |request_id| succeeded.
+IPC_MESSAGE_CONTROL3(BluetoothMsg_ConnectGATTSuccess,
+ int /* thread_id */,
+ int /* request_id */,
+ std::string /* device_instance_id */)
+
+// Messages sent from the renderer to the browser.
+
+// Requests a bluetooth device from the browser.
+// TODO(scheib): UI to select and permit access to a device crbug.com/436280.
+// This will include refactoring messages to be associated with an origin
+// and making this initial requestDevice call with an associated frame.
+// This work is deferred to simplify initial prototype patches.
+// The Bluetooth feature, and the BluetoothDispatcherHost are behind
+// the --enable-experimental-web-platform-features flag.
+IPC_MESSAGE_CONTROL2(BluetoothHostMsg_RequestDevice,
+ int /* thread_id */,
+ int /* request_id */)
+
+// Connects to a bluetooth device.
+IPC_MESSAGE_CONTROL3(BluetoothHostMsg_ConnectGATT,
+ int /* thread_id */,
+ int /* request_id */,
+ std::string /* device_instance_id */)
+
+// Configures the mock data set in the browser used while under test.
+// TODO(scheib): Disable testing in non-test executables. crbug.com/436284.
+IPC_MESSAGE_CONTROL1(BluetoothHostMsg_SetBluetoothMockDataSetForTesting,
+ std::string /* name */)
diff --git a/chromium/content/common/browser_plugin/browser_plugin_constants.h b/chromium/content/common/browser_plugin/browser_plugin_constants.h
index 812d07f8a4a..6741ee912f9 100644
--- a/chromium/content/common/browser_plugin/browser_plugin_constants.h
+++ b/chromium/content/common/browser_plugin/browser_plugin_constants.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_COMMON_BROWSER_PLUGIN_BROWSER_PLUGIN_CONSTANTS_H_
-#define CONTENT_COMMON_BROWSER_PLUGIN_BROWSER_PLUGIN_CONSTANTS_H_
+#ifndef CONTENT_COMMON_BROWSER_PLUGIN_BROWSER_PLUGIN_CONSTANTS_H_
+#define CONTENT_COMMON_BROWSER_PLUGIN_BROWSER_PLUGIN_CONSTANTS_H_
namespace content {
diff --git a/chromium/content/common/browser_plugin/browser_plugin_messages.h b/chromium/content/common/browser_plugin/browser_plugin_messages.h
index 61fbdefaf71..1a5a5f7be49 100644
--- a/chromium/content/common/browser_plugin/browser_plugin_messages.h
+++ b/chromium/content/common/browser_plugin/browser_plugin_messages.h
@@ -18,14 +18,15 @@
#include "ipc/ipc_channel_handle.h"
#include "ipc/ipc_message_macros.h"
#include "ipc/ipc_message_utils.h"
+#include "third_party/WebKit/public/platform/WebFocusType.h"
#include "third_party/WebKit/public/web/WebCompositionUnderline.h"
#include "third_party/WebKit/public/web/WebDragOperation.h"
#include "third_party/WebKit/public/web/WebDragStatus.h"
#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
#include "ui/gfx/ipc/gfx_param_traits.h"
-#include "ui/gfx/point.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/size.h"
#include "url/gurl.h"
#undef IPC_MESSAGE_EXPORT
@@ -35,24 +36,13 @@
IPC_ENUM_TRAITS_MAX_VALUE(blink::WebDragStatus, blink::WebDragStatusLast)
-
-IPC_STRUCT_BEGIN(BrowserPluginHostMsg_ResizeGuest_Params)
- // The new size of guest view.
- IPC_STRUCT_MEMBER(gfx::Size, view_size)
- // Indicates the scale factor of the embedder WebView.
- IPC_STRUCT_MEMBER(float, scale_factor)
- // Indicates a request for a full repaint of the page.
- // This is required for switching from compositing to the software
- // rendering path.
- IPC_STRUCT_MEMBER(bool, repaint)
-IPC_STRUCT_END()
+IPC_ENUM_TRAITS_MAX_VALUE(blink::WebFocusType, blink::WebFocusTypeLast)
IPC_STRUCT_BEGIN(BrowserPluginHostMsg_Attach_Params)
IPC_STRUCT_MEMBER(bool, focused)
IPC_STRUCT_MEMBER(bool, visible)
- IPC_STRUCT_MEMBER(BrowserPluginHostMsg_ResizeGuest_Params,
- resize_guest_params)
- IPC_STRUCT_MEMBER(gfx::Point, origin)
+ // The new size of the guest view.
+ IPC_STRUCT_MEMBER(gfx::Rect, view_rect)
// Whether the browser plugin is a full page plugin document.
IPC_STRUCT_MEMBER(bool, is_full_page_plugin)
IPC_STRUCT_END()
@@ -61,21 +51,24 @@ IPC_STRUCT_END()
// -----------------------------------------------------------------------------
// These messages are from the embedder to the browser process.
+// Most messages from the embedder to the browser process are CONTROL because
+// they are routed to the appropriate BrowserPluginGuest based on the
+// browser_plugin_instance_id which is unique per embedder process.
// This message is sent from BrowserPlugin to BrowserPluginGuest to issue an
// edit command.
-IPC_MESSAGE_ROUTED2(BrowserPluginHostMsg_ExecuteEditCommand,
- int /* browser_plugin_instance_id */,
- std::string /* command */)
+IPC_MESSAGE_CONTROL2(BrowserPluginHostMsg_ExecuteEditCommand,
+ int /* browser_plugin_instance_id */,
+ std::string /* command */)
// This message must be sent just before sending a key event.
-IPC_MESSAGE_ROUTED2(BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent,
- int /* browser_plugin_instance_id */,
- std::vector<content::EditCommand> /* edit_commands */)
+IPC_MESSAGE_CONTROL2(BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent,
+ int /* browser_plugin_instance_id */,
+ std::vector<content::EditCommand> /* edit_commands */)
// This message is sent from BrowserPlugin to BrowserPluginGuest whenever IME
// composition state is updated.
-IPC_MESSAGE_ROUTED5(
+IPC_MESSAGE_CONTROL5(
BrowserPluginHostMsg_ImeSetComposition,
int /* browser_plugin_instance_id */,
std::string /* text */,
@@ -85,88 +78,83 @@ IPC_MESSAGE_ROUTED5(
// This message is sent from BrowserPlugin to BrowserPluginGuest to notify that
// confirming the current composition is requested.
-IPC_MESSAGE_ROUTED3(BrowserPluginHostMsg_ImeConfirmComposition,
- int /* browser_plugin_instance_id */,
- std::string /* text */,
- bool /* keep selection */)
+IPC_MESSAGE_CONTROL3(BrowserPluginHostMsg_ImeConfirmComposition,
+ int /* browser_plugin_instance_id */,
+ std::string /* text */,
+ bool /* keep selection */)
// Deletes the current selection plus the specified number of characters before
// and after the selection or caret.
-IPC_MESSAGE_ROUTED3(BrowserPluginHostMsg_ExtendSelectionAndDelete,
- int /* browser_plugin_instance_id */,
- int /* before */,
- int /* after */)
-
-// This message is sent to the browser process to indicate that a BrowserPlugin
-// has taken ownership of the lifetime of the guest of the given
-// |browser_plugin_instance_id|. |params| is the state of the BrowserPlugin
-// taking ownership of the guest.
+IPC_MESSAGE_CONTROL3(BrowserPluginHostMsg_ExtendSelectionAndDelete,
+ int /* browser_plugin_instance_id */,
+ int /* before */,
+ int /* after */)
+
+// This message is sent to the browser process to indicate that the
+// BrowserPlugin identified by |browser_plugin_instance_id| is ready to serve
+// as container for a guest. |params| is the state of the BrowserPlugin.
+// This message is routed because we create a BrowserPluginEmbedder object
+// the first time we see this message arrive to a WebContents. We need a routing
+// ID to get this message to a particular WebContents.
IPC_MESSAGE_ROUTED2(BrowserPluginHostMsg_Attach,
int /* browser_plugin_instance_id */,
BrowserPluginHostMsg_Attach_Params /* params */)
+// This message is sent to the browser process to indicate that the
+// BrowserPlugin identified by |browser_plugin_instance_id| will no longer serve
+// as a container for a guest.
+IPC_MESSAGE_CONTROL1(BrowserPluginHostMsg_Detach,
+ int /* browser_plugin_instance_id */)
+
// Tells the guest to focus or defocus itself.
-IPC_MESSAGE_ROUTED2(BrowserPluginHostMsg_SetFocus,
- int /* browser_plugin_instance_id */,
- bool /* enable */)
+IPC_MESSAGE_CONTROL3(BrowserPluginHostMsg_SetFocus,
+ int /* browser_plugin_instance_id */,
+ bool /* enable */,
+ blink::WebFocusType /* focus_type */)
// Sends an input event to the guest.
-IPC_MESSAGE_ROUTED3(BrowserPluginHostMsg_HandleInputEvent,
- int /* browser_plugin_instance_id */,
- gfx::Rect /* guest_window_rect */,
- IPC::WebInputEventPointer /* event */)
+IPC_MESSAGE_CONTROL3(BrowserPluginHostMsg_HandleInputEvent,
+ int /* browser_plugin_instance_id */,
+ gfx::Rect /* guest_window_rect */,
+ IPC::WebInputEventPointer /* event */)
// Notify the guest renderer that some resources given to the embededer
// are not used any more.
-IPC_MESSAGE_ROUTED2(BrowserPluginHostMsg_ReclaimCompositorResources,
- int /* browser_plugin_instance_id */,
- FrameHostMsg_ReclaimCompositorResources_Params /* params */)
+IPC_MESSAGE_CONTROL2(
+ BrowserPluginHostMsg_ReclaimCompositorResources,
+ int /* browser_plugin_instance_id */,
+ FrameHostMsg_ReclaimCompositorResources_Params /* params */)
// Tells the guest it has been shown or hidden.
-IPC_MESSAGE_ROUTED2(BrowserPluginHostMsg_SetVisibility,
- int /* browser_plugin_instance_id */,
- bool /* visible */)
+IPC_MESSAGE_CONTROL2(BrowserPluginHostMsg_SetVisibility,
+ int /* browser_plugin_instance_id */,
+ bool /* visible */)
// Tells the guest that a drag event happened on the plugin.
-IPC_MESSAGE_ROUTED5(BrowserPluginHostMsg_DragStatusUpdate,
- int /* browser_plugin_instance_id */,
- blink::WebDragStatus /* drag_status */,
- content::DropData /* drop_data */,
- blink::WebDragOperationsMask /* operation_mask */,
- gfx::Point /* plugin_location */)
+IPC_MESSAGE_CONTROL5(BrowserPluginHostMsg_DragStatusUpdate,
+ int /* browser_plugin_instance_id */,
+ blink::WebDragStatus /* drag_status */,
+ content::DropData /* drop_data */,
+ blink::WebDragOperationsMask /* operation_mask */,
+ gfx::Point /* plugin_location */)
// Sends a PointerLock Lock ACK to the BrowserPluginGuest.
-IPC_MESSAGE_ROUTED2(BrowserPluginHostMsg_LockMouse_ACK,
- int /* browser_plugin_instance_id */,
- bool /* succeeded */)
+IPC_MESSAGE_CONTROL2(BrowserPluginHostMsg_LockMouse_ACK,
+ int /* browser_plugin_instance_id */,
+ bool /* succeeded */)
// Sends a PointerLock Unlock ACK to the BrowserPluginGuest.
-IPC_MESSAGE_ROUTED1(BrowserPluginHostMsg_UnlockMouse_ACK,
- int /* browser_plugin_instance_id */)
+IPC_MESSAGE_CONTROL1(BrowserPluginHostMsg_UnlockMouse_ACK,
+ int /* browser_plugin_instance_id */)
// Sent when plugin's position has changed.
-IPC_MESSAGE_ROUTED2(BrowserPluginHostMsg_UpdateGeometry,
- int /* browser_plugin_instance_id */,
- gfx::Rect /* view_rect */)
-
-// -----------------------------------------------------------------------------
-// These messages are from the guest renderer to the browser process
-
-// A embedder sends this message to the browser when it wants
-// to resize a guest plugin container so that the guest is relaid out
-// according to the new size.
-IPC_MESSAGE_ROUTED2(BrowserPluginHostMsg_ResizeGuest,
- int /* browser_plugin_instance_id*/,
- BrowserPluginHostMsg_ResizeGuest_Params)
+IPC_MESSAGE_CONTROL2(BrowserPluginHostMsg_UpdateGeometry,
+ int /* browser_plugin_instance_id */,
+ gfx::Rect /* view_rect */)
// -----------------------------------------------------------------------------
// These messages are from the browser process to the embedder.
-// This message is sent in response to a completed attachment of a guest
-// to a BrowserPlugin.
-IPC_MESSAGE_CONTROL1(BrowserPluginMsg_Attach_ACK,
- int /* browser_plugin_instance_id */)
-
// When the guest crashes, the browser process informs the embedder through this
// message.
IPC_MESSAGE_CONTROL1(BrowserPluginMsg_GuestGone,
@@ -209,6 +197,6 @@ IPC_MESSAGE_CONTROL2(BrowserPluginMsg_SetTooltipText,
base::string16 /* tooltip_text */)
// Acknowledge that we presented an ubercomp frame.
-IPC_MESSAGE_ROUTED2(BrowserPluginHostMsg_CompositorFrameSwappedACK,
- int /* browser_plugin_instance_id */,
- FrameHostMsg_CompositorFrameSwappedACK_Params /* params */)
+IPC_MESSAGE_CONTROL2(BrowserPluginHostMsg_CompositorFrameSwappedACK,
+ int /* browser_plugin_instance_id */,
+ FrameHostMsg_CompositorFrameSwappedACK_Params /* params */)
diff --git a/chromium/content/common/cache_storage/OWNERS b/chromium/content/common/cache_storage/OWNERS
new file mode 100644
index 00000000000..80517c24dba
--- /dev/null
+++ b/chromium/content/common/cache_storage/OWNERS
@@ -0,0 +1,18 @@
+michaeln@chromium.org
+nhiroki@chromium.org
+jkarlin@chromium.org
+jsbell@chromium.org
+
+# Changes to IPC messages require a security review to avoid introducing
+# new sandbox escapes.
+per-file *_messages*.h=set noparent
+per-file *_messages*.h=dcheng@chromium.org
+per-file *_messages*.h=inferno@chromium.org
+per-file *_messages*.h=jln@chromium.org
+per-file *_messages*.h=jschuh@chromium.org
+per-file *_messages*.h=kenrb@chromium.org
+per-file *_messages*.h=mkwst@chromium.org
+per-file *_messages*.h=nasko@chromium.org
+per-file *_messages*.h=palmer@chromium.org
+per-file *_messages*.h=tsepez@chromium.org
+per-file *_messages*.h=wfh@chromium.org
diff --git a/chromium/content/common/cache_storage/cache_storage_messages.h b/chromium/content/common/cache_storage/cache_storage_messages.h
new file mode 100644
index 00000000000..dc1de3c31ba
--- /dev/null
+++ b/chromium/content/common/cache_storage/cache_storage_messages.h
@@ -0,0 +1,197 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Message definition file, included multiple times, hence no include guard.
+
+#include <string>
+#include <vector>
+
+#include "base/strings/string16.h"
+#include "content/common/cache_storage/cache_storage_types.h"
+#include "content/common/service_worker/service_worker_types.h"
+#include "ipc/ipc_message_macros.h"
+#include "ipc/ipc_param_traits.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerCacheError.h"
+#include "url/gurl.h"
+
+#undef IPC_MESSAGE_EXPORT
+#define IPC_MESSAGE_EXPORT CONTENT_EXPORT
+
+#define IPC_MESSAGE_START CacheStorageMsgStart
+
+// TODO(jsbell): This depends on traits for content::ServiceWorkerResponse
+// which are defined in service_worker_messages.h - correct this implicit
+// cross-dependency.
+
+IPC_STRUCT_TRAITS_BEGIN(content::CacheStorageCacheQueryParams)
+ IPC_STRUCT_TRAITS_MEMBER(ignore_search)
+ IPC_STRUCT_TRAITS_MEMBER(ignore_method)
+ IPC_STRUCT_TRAITS_MEMBER(ignore_vary)
+ IPC_STRUCT_TRAITS_MEMBER(cache_name)
+IPC_STRUCT_TRAITS_END()
+
+IPC_ENUM_TRAITS_MAX_VALUE(content::CacheStorageCacheOperationType,
+ content::CACHE_STORAGE_CACHE_OPERATION_TYPE_LAST)
+
+IPC_STRUCT_TRAITS_BEGIN(content::CacheStorageBatchOperation)
+ IPC_STRUCT_TRAITS_MEMBER(operation_type)
+ IPC_STRUCT_TRAITS_MEMBER(request)
+ IPC_STRUCT_TRAITS_MEMBER(response)
+ IPC_STRUCT_TRAITS_MEMBER(match_params)
+IPC_STRUCT_TRAITS_END()
+
+IPC_ENUM_TRAITS_MAX_VALUE(blink::WebServiceWorkerCacheError,
+ blink::WebServiceWorkerCacheErrorLast)
+
+//---------------------------------------------------------------------------
+// Messages sent from the child process to the browser.
+
+// CacheStorage operations in the browser.
+IPC_MESSAGE_CONTROL4(CacheStorageHostMsg_CacheStorageHas,
+ int /* thread_id */,
+ int /* request_id */,
+ GURL /* origin */,
+ base::string16 /* fetch_store_name */)
+
+IPC_MESSAGE_CONTROL4(CacheStorageHostMsg_CacheStorageOpen,
+ int /* thread_id */,
+ int /* request_id */,
+ GURL /* origin */,
+ base::string16 /* fetch_store_name */)
+
+IPC_MESSAGE_CONTROL4(CacheStorageHostMsg_CacheStorageDelete,
+ int /* thread_id */,
+ int /* request_id */,
+ GURL /* origin */,
+ base::string16 /* fetch_store_name */)
+
+IPC_MESSAGE_CONTROL3(CacheStorageHostMsg_CacheStorageKeys,
+ int /* thread_id */,
+ int /* request_id */,
+ GURL /* origin */)
+
+IPC_MESSAGE_CONTROL5(CacheStorageHostMsg_CacheStorageMatch,
+ int /* thread_id */,
+ int /* request_id */,
+ GURL /* origin */,
+ content::ServiceWorkerFetchRequest,
+ content::CacheStorageCacheQueryParams)
+
+// Cache operations in the browser.
+IPC_MESSAGE_CONTROL5(CacheStorageHostMsg_CacheMatch,
+ int /* thread_id */,
+ int /* request_id */,
+ int /* cache_id */,
+ content::ServiceWorkerFetchRequest,
+ content::CacheStorageCacheQueryParams)
+
+IPC_MESSAGE_CONTROL5(CacheStorageHostMsg_CacheMatchAll,
+ int /* thread_id */,
+ int /* request_id */,
+ int /* cache_id */,
+ content::ServiceWorkerFetchRequest,
+ content::CacheStorageCacheQueryParams)
+
+IPC_MESSAGE_CONTROL5(CacheStorageHostMsg_CacheKeys,
+ int /* thread_id */,
+ int /* request_id */,
+ int /* cache_id */,
+ content::ServiceWorkerFetchRequest,
+ content::CacheStorageCacheQueryParams)
+
+IPC_MESSAGE_CONTROL4(CacheStorageHostMsg_CacheBatch,
+ int /* thread_id */,
+ int /* request_id */,
+ int /* cache_id */,
+ std::vector<content::CacheStorageBatchOperation>)
+
+IPC_MESSAGE_CONTROL1(CacheStorageHostMsg_CacheClosed,
+ int /* cache_id */)
+
+IPC_MESSAGE_CONTROL1(CacheStorageHostMsg_BlobDataHandled,
+ std::string /* uuid */)
+
+//---------------------------------------------------------------------------
+// Messages sent from the browser to the child process.
+//
+// All such messages must includes thread_id as the first int; it is read off
+// by CacheStorageMessageFilter::GetWorkerThreadIdForMessage to route delivery
+// to the appropriate thread.
+
+// Sent at successful completion of CacheStorage operations.
+IPC_MESSAGE_CONTROL2(CacheStorageMsg_CacheStorageHasSuccess,
+ int /* thread_id */,
+ int /* request_id */)
+IPC_MESSAGE_CONTROL3(CacheStorageMsg_CacheStorageOpenSuccess,
+ int /* thread_id */,
+ int /* request_id */,
+ int /* fetch_store_id */)
+IPC_MESSAGE_CONTROL2(CacheStorageMsg_CacheStorageDeleteSuccess,
+ int /* thread_id */,
+ int /* request_id */)
+IPC_MESSAGE_CONTROL3(CacheStorageMsg_CacheStorageKeysSuccess,
+ int /* thread_id */,
+ int /* request_id */,
+ std::vector<base::string16> /* keys */)
+IPC_MESSAGE_CONTROL3(CacheStorageMsg_CacheStorageMatchSuccess,
+ int /* thread_id */,
+ int /* request_id */,
+ content::ServiceWorkerResponse)
+
+// Sent at erroneous completion of CacheStorage operations.
+IPC_MESSAGE_CONTROL3(CacheStorageMsg_CacheStorageHasError,
+ int /* thread_id */,
+ int /* request_id */,
+ blink::WebServiceWorkerCacheError /* reason */)
+IPC_MESSAGE_CONTROL3(CacheStorageMsg_CacheStorageOpenError,
+ int /* thread_id */,
+ int /* request_id */,
+ blink::WebServiceWorkerCacheError /* reason */)
+IPC_MESSAGE_CONTROL3(CacheStorageMsg_CacheStorageDeleteError,
+ int /* thread_id */,
+ int /* request_id */,
+ blink::WebServiceWorkerCacheError /* reason */)
+IPC_MESSAGE_CONTROL3(CacheStorageMsg_CacheStorageKeysError,
+ int /* thread_id */,
+ int /* request_id */,
+ blink::WebServiceWorkerCacheError /* reason */)
+IPC_MESSAGE_CONTROL3(CacheStorageMsg_CacheStorageMatchError,
+ int /* thread_id */,
+ int /* request_id */,
+ blink::WebServiceWorkerCacheError)
+
+// Sent at successful completion of Cache operations.
+IPC_MESSAGE_CONTROL3(CacheStorageMsg_CacheMatchSuccess,
+ int /* thread_id */,
+ int /* request_id */,
+ content::ServiceWorkerResponse)
+IPC_MESSAGE_CONTROL3(CacheStorageMsg_CacheMatchAllSuccess,
+ int /* thread_id */,
+ int /* request_id */,
+ std::vector<content::ServiceWorkerResponse>)
+IPC_MESSAGE_CONTROL3(CacheStorageMsg_CacheKeysSuccess,
+ int /* thread_id */,
+ int /* request_id */,
+ std::vector<content::ServiceWorkerFetchRequest>)
+IPC_MESSAGE_CONTROL2(CacheStorageMsg_CacheBatchSuccess,
+ int /* thread_id */,
+ int /* request_id */)
+
+// Sent at erroneous completion of CacheStorage operations.
+IPC_MESSAGE_CONTROL3(CacheStorageMsg_CacheMatchError,
+ int /* thread_id */,
+ int /* request_id */,
+ blink::WebServiceWorkerCacheError)
+IPC_MESSAGE_CONTROL3(CacheStorageMsg_CacheMatchAllError,
+ int /* thread_id */,
+ int /* request_id */,
+ blink::WebServiceWorkerCacheError)
+IPC_MESSAGE_CONTROL3(CacheStorageMsg_CacheKeysError,
+ int /* thread_id */,
+ int /* request_id */,
+ blink::WebServiceWorkerCacheError)
+IPC_MESSAGE_CONTROL3(CacheStorageMsg_CacheBatchError,
+ int /* thread_id */,
+ int /* request_id */,
+ blink::WebServiceWorkerCacheError)
diff --git a/chromium/content/common/cache_storage/cache_storage_types.cc b/chromium/content/common/cache_storage/cache_storage_types.cc
new file mode 100644
index 00000000000..c2e5175d693
--- /dev/null
+++ b/chromium/content/common/cache_storage/cache_storage_types.cc
@@ -0,0 +1,16 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/common/cache_storage/cache_storage_types.h"
+
+namespace content {
+
+CacheStorageCacheQueryParams::CacheStorageCacheQueryParams()
+ : ignore_search(false), ignore_method(false), ignore_vary(false) {
+}
+
+CacheStorageBatchOperation::CacheStorageBatchOperation() {
+}
+
+} // namespace content
diff --git a/chromium/content/common/cache_storage/cache_storage_types.h b/chromium/content/common/cache_storage/cache_storage_types.h
new file mode 100644
index 00000000000..b52d5176df7
--- /dev/null
+++ b/chromium/content/common/cache_storage/cache_storage_types.h
@@ -0,0 +1,62 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_COMMON_CACHE_STORAGE_CACHE_STORAGE_TYPES_H_
+#define CONTENT_COMMON_CACHE_STORAGE_CACHE_STORAGE_TYPES_H_
+
+#include <map>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+#include "content/common/content_export.h"
+#include "content/common/service_worker/service_worker_types.h"
+
+// This file is to have common definitions that are to be shared by
+// browser and child process.
+
+namespace content {
+
+// Controls how requests are matched in the Cache API.
+struct CONTENT_EXPORT CacheStorageCacheQueryParams {
+ CacheStorageCacheQueryParams();
+
+ bool ignore_search;
+ bool ignore_method;
+ bool ignore_vary;
+ base::string16 cache_name;
+};
+
+// The type of a single batch operation in the Cache API.
+enum CacheStorageCacheOperationType {
+ CACHE_STORAGE_CACHE_OPERATION_TYPE_UNDEFINED,
+ CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT,
+ CACHE_STORAGE_CACHE_OPERATION_TYPE_DELETE,
+ CACHE_STORAGE_CACHE_OPERATION_TYPE_LAST =
+ CACHE_STORAGE_CACHE_OPERATION_TYPE_DELETE
+};
+
+// A single batch operation for the Cache API.
+struct CONTENT_EXPORT CacheStorageBatchOperation {
+ CacheStorageBatchOperation();
+
+ CacheStorageCacheOperationType operation_type;
+ ServiceWorkerFetchRequest request;
+ ServiceWorkerResponse response;
+ CacheStorageCacheQueryParams match_params;
+};
+
+// This enum is used in histograms, so do not change the ordering and always
+// append new types to the end.
+enum CacheStorageError {
+ CACHE_STORAGE_OK = 0,
+ CACHE_STORAGE_ERROR_EXISTS,
+ CACHE_STORAGE_ERROR_STORAGE,
+ CACHE_STORAGE_ERROR_NOT_FOUND,
+ CACHE_STORAGE_ERROR_LAST = CACHE_STORAGE_ERROR_NOT_FOUND
+};
+
+} // namespace content
+
+#endif // CONTENT_COMMON_CACHE_STORAGE_CACHE_STORAGE_TYPES_H_
diff --git a/chromium/content/common/cc_messages.cc b/chromium/content/common/cc_messages.cc
index 426cee21be4..e7c2ad21fde 100644
--- a/chromium/content/common/cc_messages.cc
+++ b/chromium/content/common/cc_messages.cc
@@ -7,6 +7,7 @@
#include "cc/output/compositor_frame.h"
#include "cc/output/filter_operations.h"
#include "cc/quads/largest_draw_quad.h"
+#include "cc/quads/render_pass_id.h"
#include "content/public/common/common_param_traits.h"
#include "third_party/skia/include/core/SkData.h"
#include "third_party/skia/include/core/SkFlattenableSerialization.h"
@@ -228,7 +229,7 @@ bool ParamTraits<skia::RefPtr<SkImageFilter> >::Read(
const Message* m, PickleIterator* iter, param_type* r) {
const char* data = 0;
int length = 0;
- if (!m->ReadData(iter, &data, &length))
+ if (!iter->ReadData(&data, &length))
return false;
if (length > 0) {
SkFlattenable* flattenable = SkValidatingDeserializeFlattenable(
@@ -262,7 +263,7 @@ void ParamTraits<gfx::Transform>::Write(
bool ParamTraits<gfx::Transform>::Read(
const Message* m, PickleIterator* iter, param_type* r) {
const char* column_major_data;
- if (!m->ReadBytes(iter, &column_major_data, sizeof(SkMScalar) * 16))
+ if (!iter->ReadBytes(&column_major_data, sizeof(SkMScalar) * 16))
return false;
r->matrix().setColMajor(
reinterpret_cast<const SkMScalar*>(column_major_data));
@@ -702,10 +703,10 @@ void ParamTraits<cc::DelegatedFrameData>::Write(Message* m,
WriteParam(m, p.device_scale_factor);
WriteParam(m, p.resource_list);
WriteParam(m, p.render_pass_list.size());
- for (size_t i = 0; i < p.render_pass_list.size(); ++i) {
- WriteParam(m, p.render_pass_list[i]->quad_list.size());
- WriteParam(m, p.render_pass_list[i]->shared_quad_state_list.size());
- WriteParam(m, *p.render_pass_list[i]);
+ for (const auto* pass : p.render_pass_list) {
+ WriteParam(m, pass->quad_list.size());
+ WriteParam(m, pass->shared_quad_state_list.size());
+ WriteParam(m, *pass);
}
}
@@ -719,6 +720,8 @@ bool ParamTraits<cc::DelegatedFrameData>::Read(const Message* m,
const static size_t kMaxSharedQuadStateListSize = 100000;
const static size_t kMaxQuadListSize = 1000000;
+ std::set<cc::RenderPassId> pass_set;
+
size_t num_render_passes;
if (!ReadParam(m, iter, &p->resource_list) ||
!ReadParam(m, iter, &num_render_passes) ||
@@ -736,6 +739,17 @@ bool ParamTraits<cc::DelegatedFrameData>::Read(const Message* m,
cc::RenderPass::Create(shared_quad_state_list_size, quad_list_size);
if (!ReadParam(m, iter, render_pass.get()))
return false;
+ // Validate that each RenderPassDrawQuad points at a valid RenderPass
+ // earlier in the frame.
+ for (const auto* quad : render_pass->quad_list) {
+ if (quad->material != cc::DrawQuad::RENDER_PASS)
+ continue;
+ const cc::RenderPassDrawQuad* rpdq =
+ cc::RenderPassDrawQuad::MaterialCast(quad);
+ if (!pass_set.count(rpdq->render_pass_id))
+ return false;
+ }
+ pass_set.insert(render_pass->id);
p->render_pass_list.push_back(render_pass.Pass());
}
return true;
diff --git a/chromium/content/common/cc_messages.h b/chromium/content/common/cc_messages.h
index 0c14ddf5ef5..f6e907da04f 100644
--- a/chromium/content/common/cc_messages.h
+++ b/chromium/content/common/cc_messages.h
@@ -158,6 +158,7 @@ IPC_STRUCT_TRAITS_END()
IPC_STRUCT_TRAITS_BEGIN(cc::CheckerboardDrawQuad)
IPC_STRUCT_TRAITS_PARENT(cc::DrawQuad)
IPC_STRUCT_TRAITS_MEMBER(color)
+ IPC_STRUCT_TRAITS_MEMBER(scale)
IPC_STRUCT_TRAITS_END()
IPC_STRUCT_TRAITS_BEGIN(cc::DebugBorderDrawQuad)
@@ -212,7 +213,8 @@ IPC_STRUCT_TRAITS_BEGIN(cc::TextureDrawQuad)
IPC_STRUCT_TRAITS_MEMBER(vertex_opacity[1])
IPC_STRUCT_TRAITS_MEMBER(vertex_opacity[2])
IPC_STRUCT_TRAITS_MEMBER(vertex_opacity[3])
- IPC_STRUCT_TRAITS_MEMBER(flipped)
+ IPC_STRUCT_TRAITS_MEMBER(y_flipped)
+ IPC_STRUCT_TRAITS_MEMBER(nearest_neighbor)
IPC_STRUCT_TRAITS_END()
IPC_STRUCT_TRAITS_BEGIN(cc::TileDrawQuad)
@@ -221,11 +223,15 @@ IPC_STRUCT_TRAITS_BEGIN(cc::TileDrawQuad)
IPC_STRUCT_TRAITS_MEMBER(tex_coord_rect)
IPC_STRUCT_TRAITS_MEMBER(texture_size)
IPC_STRUCT_TRAITS_MEMBER(swizzle_contents)
+ IPC_STRUCT_TRAITS_MEMBER(nearest_neighbor)
IPC_STRUCT_TRAITS_END()
IPC_STRUCT_TRAITS_BEGIN(cc::YUVVideoDrawQuad)
IPC_STRUCT_TRAITS_PARENT(cc::DrawQuad)
- IPC_STRUCT_TRAITS_MEMBER(tex_coord_rect)
+ IPC_STRUCT_TRAITS_MEMBER(ya_tex_coord_rect)
+ IPC_STRUCT_TRAITS_MEMBER(uv_tex_coord_rect)
+ IPC_STRUCT_TRAITS_MEMBER(ya_tex_size)
+ IPC_STRUCT_TRAITS_MEMBER(uv_tex_size)
IPC_STRUCT_TRAITS_MEMBER(y_plane_resource_id)
IPC_STRUCT_TRAITS_MEMBER(u_plane_resource_id)
IPC_STRUCT_TRAITS_MEMBER(v_plane_resource_id)
@@ -269,10 +275,22 @@ IPC_STRUCT_TRAITS_BEGIN(cc::ViewportSelectionBound)
IPC_STRUCT_TRAITS_MEMBER(visible)
IPC_STRUCT_TRAITS_END()
+IPC_STRUCT_TRAITS_BEGIN(cc::ViewportSelection)
+ IPC_STRUCT_TRAITS_MEMBER(start)
+ IPC_STRUCT_TRAITS_MEMBER(end)
+ IPC_STRUCT_TRAITS_MEMBER(is_editable)
+ IPC_STRUCT_TRAITS_MEMBER(is_empty_text_form_control)
+IPC_STRUCT_TRAITS_END()
+
+IPC_ENUM_TRAITS_MAX_VALUE( \
+ cc::BeginFrameArgs::BeginFrameArgsType, \
+ cc::BeginFrameArgs::BEGIN_FRAME_ARGS_TYPE_MAX - 1)
+
IPC_STRUCT_TRAITS_BEGIN(cc::BeginFrameArgs)
IPC_STRUCT_TRAITS_MEMBER(frame_time)
IPC_STRUCT_TRAITS_MEMBER(deadline)
IPC_STRUCT_TRAITS_MEMBER(interval)
+ IPC_STRUCT_TRAITS_MEMBER(type)
IPC_STRUCT_TRAITS_END()
IPC_STRUCT_TRAITS_BEGIN(cc::CompositorFrameMetadata)
@@ -283,10 +301,11 @@ IPC_STRUCT_TRAITS_BEGIN(cc::CompositorFrameMetadata)
IPC_STRUCT_TRAITS_MEMBER(root_layer_size)
IPC_STRUCT_TRAITS_MEMBER(min_page_scale_factor)
IPC_STRUCT_TRAITS_MEMBER(max_page_scale_factor)
+ IPC_STRUCT_TRAITS_MEMBER(root_overflow_x_hidden)
+ IPC_STRUCT_TRAITS_MEMBER(root_overflow_y_hidden)
IPC_STRUCT_TRAITS_MEMBER(location_bar_offset)
IPC_STRUCT_TRAITS_MEMBER(location_bar_content_translation)
- IPC_STRUCT_TRAITS_MEMBER(selection_start)
- IPC_STRUCT_TRAITS_MEMBER(selection_end)
+ IPC_STRUCT_TRAITS_MEMBER(selection)
IPC_STRUCT_TRAITS_MEMBER(latency_info)
IPC_STRUCT_TRAITS_MEMBER(satisfies_sequences)
IPC_STRUCT_TRAITS_END()
diff --git a/chromium/content/common/cc_messages_perftest.cc b/chromium/content/common/cc_messages_perftest.cc
index 1aa09e875d5..78085d21f56 100644
--- a/chromium/content/common/cc_messages_perftest.cc
+++ b/chromium/content/common/cc_messages_perftest.cc
@@ -33,7 +33,7 @@ class CCMessagesPerfTest : public testing::Test {
IPC::ParamTraits<CompositorFrame>::Write(&msg, frame);
}
- base::TimeTicks start = base::TimeTicks::HighResNow();
+ base::TimeTicks start = base::TimeTicks::Now();
base::TimeTicks end =
start + base::TimeDelta::FromMilliseconds(kTimeLimitMillis);
base::TimeDelta min_time;
@@ -45,10 +45,10 @@ class CCMessagesPerfTest : public testing::Test {
++count;
}
- base::TimeTicks now = base::TimeTicks::HighResNow();
+ base::TimeTicks now = base::TimeTicks::Now();
if (now - start < min_time || min_time == base::TimeDelta())
min_time = now - start;
- start = base::TimeTicks::HighResNow();
+ start = base::TimeTicks::Now();
}
perf_test::PrintResult(
diff --git a/chromium/content/common/cc_messages_unittest.cc b/chromium/content/common/cc_messages_unittest.cc
index cc1fdf0c84c..991371c97d0 100644
--- a/chromium/content/common/cc_messages_unittest.cc
+++ b/chromium/content/common/cc_messages_unittest.cc
@@ -39,7 +39,6 @@ using cc::TextureDrawQuad;
using cc::TileDrawQuad;
using cc::TransferableResource;
using cc::StreamVideoDrawQuad;
-using cc::VideoLayerImpl;
using cc::YUVVideoDrawQuad;
using gfx::Transform;
@@ -129,6 +128,7 @@ class CCMessagesTest : public testing::Test {
void Compare(const CheckerboardDrawQuad* a, const CheckerboardDrawQuad* b) {
EXPECT_EQ(a->color, b->color);
+ EXPECT_EQ(a->scale, b->scale);
}
void Compare(const DebugBorderDrawQuad* a, const DebugBorderDrawQuad* b) {
@@ -185,7 +185,8 @@ class CCMessagesTest : public testing::Test {
EXPECT_EQ(a->vertex_opacity[1], b->vertex_opacity[1]);
EXPECT_EQ(a->vertex_opacity[2], b->vertex_opacity[2]);
EXPECT_EQ(a->vertex_opacity[3], b->vertex_opacity[3]);
- EXPECT_EQ(a->flipped, b->flipped);
+ EXPECT_EQ(a->y_flipped, b->y_flipped);
+ EXPECT_EQ(a->nearest_neighbor, b->nearest_neighbor);
}
void Compare(const TileDrawQuad* a, const TileDrawQuad* b) {
@@ -193,10 +194,14 @@ class CCMessagesTest : public testing::Test {
EXPECT_EQ(a->tex_coord_rect, b->tex_coord_rect);
EXPECT_EQ(a->texture_size, b->texture_size);
EXPECT_EQ(a->swizzle_contents, b->swizzle_contents);
+ EXPECT_EQ(a->nearest_neighbor, b->nearest_neighbor);
}
void Compare(const YUVVideoDrawQuad* a, const YUVVideoDrawQuad* b) {
- EXPECT_EQ(a->tex_coord_rect, b->tex_coord_rect);
+ EXPECT_EQ(a->ya_tex_coord_rect, b->ya_tex_coord_rect);
+ EXPECT_EQ(a->uv_tex_coord_rect, b->uv_tex_coord_rect);
+ EXPECT_EQ(a->ya_tex_size, b->ya_tex_size);
+ EXPECT_EQ(a->uv_tex_size, b->uv_tex_size);
EXPECT_EQ(a->y_plane_resource_id, b->y_plane_resource_id);
EXPECT_EQ(a->u_plane_resource_id, b->u_plane_resource_id);
EXPECT_EQ(a->v_plane_resource_id, b->v_plane_resource_id);
@@ -222,10 +227,14 @@ class CCMessagesTest : public testing::Test {
TEST_F(CCMessagesTest, AllQuads) {
IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
- Transform arbitrary_matrix;
- arbitrary_matrix.Scale(3, 3);
- arbitrary_matrix.Translate(-5, 20);
- arbitrary_matrix.Rotate(15);
+ Transform arbitrary_matrix1;
+ arbitrary_matrix1.Scale(3, 3);
+ arbitrary_matrix1.Translate(-5, 20);
+ arbitrary_matrix1.Rotate(15);
+ Transform arbitrary_matrix2;
+ arbitrary_matrix2.Scale(10, -1);
+ arbitrary_matrix2.Translate(20, 3);
+ arbitrary_matrix2.Rotate(24);
gfx::Rect arbitrary_rect1(-5, 9, 3, 15);
gfx::Rect arbitrary_rect1_inside_rect1(-4, 12, 2, 8);
gfx::Rect arbitrary_rect2_inside_rect1(-5, 11, 1, 2);
@@ -239,6 +248,7 @@ TEST_F(CCMessagesTest, AllQuads) {
gfx::Size arbitrary_size2(3, 99);
gfx::Size arbitrary_size3(75, 1281);
gfx::RectF arbitrary_rectf1(4.2f, -922.1f, 15.6f, 29.5f);
+ gfx::RectF arbitrary_rectf2(2.1f, -411.05f, 7.8f, 14.75f);
gfx::SizeF arbitrary_sizef1(15.2f, 104.6f);
gfx::PointF arbitrary_pointf1(31.4f, 15.9f);
gfx::PointF arbitrary_pointf2(26.5f, -35.8f);
@@ -251,6 +261,7 @@ TEST_F(CCMessagesTest, AllQuads) {
bool arbitrary_bool1 = true;
bool arbitrary_bool2 = false;
bool arbitrary_bool3 = true;
+ bool arbitrary_bool4 = true;
int arbitrary_context_id1 = 12;
int arbitrary_context_id2 = 57;
int arbitrary_context_id3 = -503;
@@ -261,7 +272,6 @@ TEST_F(CCMessagesTest, AllQuads) {
SkXfermode::Mode arbitrary_blend_mode3 = SkXfermode::kOverlay_Mode;
IOSurfaceDrawQuad::Orientation arbitrary_orientation =
IOSurfaceDrawQuad::UNFLIPPED;
- RenderPassId arbitrary_id(10, 14);
ResourceProvider::ResourceId arbitrary_resourceid1 = 55;
ResourceProvider::ResourceId arbitrary_resourceid2 = 47;
ResourceProvider::ResourceId arbitrary_resourceid3 = 23;
@@ -270,6 +280,9 @@ TEST_F(CCMessagesTest, AllQuads) {
YUVVideoDrawQuad::ColorSpace arbitrary_color_space =
YUVVideoDrawQuad::REC_601;
+ RenderPassId child_id(30, 5);
+ RenderPassId root_id(10, 14);
+
FilterOperations arbitrary_filters1;
arbitrary_filters1.Append(FilterOperation::CreateGrayscaleFilter(
arbitrary_float1));
@@ -282,28 +295,25 @@ TEST_F(CCMessagesTest, AllQuads) {
arbitrary_filters2.Append(FilterOperation::CreateBrightnessFilter(
arbitrary_float2));
+ scoped_ptr<RenderPass> child_pass_in = RenderPass::Create();
+ child_pass_in->SetAll(child_id, arbitrary_rect2, arbitrary_rect3,
+ arbitrary_matrix2, arbitrary_bool2);
+
+ scoped_ptr<RenderPass> child_pass_cmp = RenderPass::Create();
+ child_pass_cmp->SetAll(child_id, arbitrary_rect2, arbitrary_rect3,
+ arbitrary_matrix2, arbitrary_bool2);
+
scoped_ptr<RenderPass> pass_in = RenderPass::Create();
- pass_in->SetAll(arbitrary_id,
- arbitrary_rect1,
- arbitrary_rect2,
- arbitrary_matrix,
+ pass_in->SetAll(root_id, arbitrary_rect1, arbitrary_rect2, arbitrary_matrix1,
arbitrary_bool1);
SharedQuadState* shared_state1_in = pass_in->CreateAndAppendSharedQuadState();
- shared_state1_in->SetAll(arbitrary_matrix,
- arbitrary_size1,
- arbitrary_rect1,
- arbitrary_rect2,
- arbitrary_bool1,
- arbitrary_float1,
- arbitrary_blend_mode1,
- arbitrary_context_id1);
+ shared_state1_in->SetAll(arbitrary_matrix1, arbitrary_size1, arbitrary_rect1,
+ arbitrary_rect2, arbitrary_bool1, arbitrary_float1,
+ arbitrary_blend_mode1, arbitrary_context_id1);
scoped_ptr<RenderPass> pass_cmp = RenderPass::Create();
- pass_cmp->SetAll(arbitrary_id,
- arbitrary_rect1,
- arbitrary_rect2,
- arbitrary_matrix,
+ pass_cmp->SetAll(root_id, arbitrary_rect1, arbitrary_rect2, arbitrary_matrix1,
arbitrary_bool1);
SharedQuadState* shared_state1_cmp =
@@ -312,12 +322,10 @@ TEST_F(CCMessagesTest, AllQuads) {
CheckerboardDrawQuad* checkerboard_in =
pass_in->CreateAndAppendDrawQuad<CheckerboardDrawQuad>();
- checkerboard_in->SetAll(shared_state1_in,
- arbitrary_rect1,
+ checkerboard_in->SetAll(shared_state1_in, arbitrary_rect1,
arbitrary_rect2_inside_rect1,
- arbitrary_rect1_inside_rect1,
- arbitrary_bool1,
- arbitrary_color);
+ arbitrary_rect1_inside_rect1, arbitrary_bool1,
+ arbitrary_color, arbitrary_float1);
pass_cmp->CopyFromAndAppendDrawQuad(checkerboard_in,
checkerboard_in->shared_quad_state);
@@ -347,46 +355,29 @@ TEST_F(CCMessagesTest, AllQuads) {
iosurface_in->shared_quad_state);
SharedQuadState* shared_state2_in = pass_in->CreateAndAppendSharedQuadState();
- shared_state2_in->SetAll(arbitrary_matrix,
- arbitrary_size2,
- arbitrary_rect2,
- arbitrary_rect3,
- arbitrary_bool1,
- arbitrary_float2,
- arbitrary_blend_mode2,
- arbitrary_context_id2);
+ shared_state2_in->SetAll(arbitrary_matrix2, arbitrary_size2, arbitrary_rect2,
+ arbitrary_rect3, arbitrary_bool1, arbitrary_float2,
+ arbitrary_blend_mode2, arbitrary_context_id2);
SharedQuadState* shared_state2_cmp =
pass_cmp->CreateAndAppendSharedQuadState();
shared_state2_cmp->CopyFrom(shared_state2_in);
RenderPassDrawQuad* renderpass_in =
pass_in->CreateAndAppendDrawQuad<RenderPassDrawQuad>();
- renderpass_in->SetAll(shared_state2_in,
- arbitrary_rect1,
- arbitrary_rect2_inside_rect1,
- arbitrary_rect1_inside_rect1,
- arbitrary_bool1,
- arbitrary_id,
- arbitrary_resourceid2,
- arbitrary_vector2df1,
- arbitrary_size1,
- arbitrary_filters1,
- arbitrary_vector2df2,
- arbitrary_filters2);
+ renderpass_in->SetAll(
+ shared_state2_in, arbitrary_rect1, arbitrary_rect2_inside_rect1,
+ arbitrary_rect1_inside_rect1, arbitrary_bool1, child_id,
+ arbitrary_resourceid2, arbitrary_vector2df1, arbitrary_size1,
+ arbitrary_filters1, arbitrary_vector2df2, arbitrary_filters2);
pass_cmp->CopyFromAndAppendRenderPassDrawQuad(
renderpass_in,
renderpass_in->shared_quad_state,
renderpass_in->render_pass_id);
SharedQuadState* shared_state3_in = pass_in->CreateAndAppendSharedQuadState();
- shared_state3_in->SetAll(arbitrary_matrix,
- arbitrary_size3,
- arbitrary_rect3,
- arbitrary_rect1,
- arbitrary_bool1,
- arbitrary_float3,
- arbitrary_blend_mode3,
- arbitrary_context_id3);
+ shared_state3_in->SetAll(arbitrary_matrix1, arbitrary_size3, arbitrary_rect3,
+ arbitrary_rect1, arbitrary_bool1, arbitrary_float3,
+ arbitrary_blend_mode3, arbitrary_context_id3);
SharedQuadState* shared_state3_cmp =
pass_cmp->CreateAndAppendSharedQuadState();
shared_state3_cmp->CopyFrom(shared_state3_in);
@@ -405,13 +396,10 @@ TEST_F(CCMessagesTest, AllQuads) {
StreamVideoDrawQuad* streamvideo_in =
pass_in->CreateAndAppendDrawQuad<StreamVideoDrawQuad>();
- streamvideo_in->SetAll(shared_state3_in,
- arbitrary_rect2,
+ streamvideo_in->SetAll(shared_state3_in, arbitrary_rect2,
arbitrary_rect2_inside_rect2,
- arbitrary_rect1_inside_rect2,
- arbitrary_bool1,
- arbitrary_resourceid2,
- arbitrary_matrix);
+ arbitrary_rect1_inside_rect2, arbitrary_bool1,
+ arbitrary_resourceid2, arbitrary_matrix1);
pass_cmp->CopyFromAndAppendDrawQuad(streamvideo_in,
streamvideo_in->shared_quad_state);
@@ -440,7 +428,8 @@ TEST_F(CCMessagesTest, AllQuads) {
arbitrary_pointf2,
arbitrary_color,
arbitrary_float_array,
- arbitrary_bool3);
+ arbitrary_bool3,
+ arbitrary_bool4);
pass_cmp->CopyFromAndAppendDrawQuad(texture_in,
texture_in->shared_quad_state);
@@ -453,26 +442,25 @@ TEST_F(CCMessagesTest, AllQuads) {
arbitrary_resourceid3,
arbitrary_rectf1,
arbitrary_size1,
- arbitrary_bool2);
+ arbitrary_bool2,
+ arbitrary_bool3);
pass_cmp->CopyFromAndAppendDrawQuad(tile_in, tile_in->shared_quad_state);
YUVVideoDrawQuad* yuvvideo_in =
pass_in->CreateAndAppendDrawQuad<YUVVideoDrawQuad>();
- yuvvideo_in->SetAll(shared_state3_in,
- arbitrary_rect1,
- arbitrary_rect2_inside_rect1,
- arbitrary_rect1_inside_rect1,
- arbitrary_bool1,
- arbitrary_rectf1,
- arbitrary_resourceid1,
- arbitrary_resourceid2,
- arbitrary_resourceid3,
- arbitrary_resourceid4,
- arbitrary_color_space);
+ yuvvideo_in->SetAll(
+ shared_state3_in, arbitrary_rect1, arbitrary_rect2_inside_rect1,
+ arbitrary_rect1_inside_rect1, arbitrary_bool1, arbitrary_rectf1,
+ arbitrary_rectf2, arbitrary_size1, arbitrary_size2, arbitrary_resourceid1,
+ arbitrary_resourceid2, arbitrary_resourceid3, arbitrary_resourceid4,
+ arbitrary_color_space);
pass_cmp->CopyFromAndAppendDrawQuad(yuvvideo_in,
yuvvideo_in->shared_quad_state);
// Make sure the in and cmp RenderPasses match.
+ Compare(child_pass_cmp.get(), child_pass_in.get());
+ ASSERT_EQ(0u, child_pass_in->shared_quad_state_list.size());
+ ASSERT_EQ(0u, child_pass_in->quad_list.size());
Compare(pass_cmp.get(), pass_in.get());
ASSERT_EQ(3u, pass_in->shared_quad_state_list.size());
ASSERT_EQ(10u, pass_in->quad_list.size());
@@ -500,6 +488,7 @@ TEST_F(CCMessagesTest, AllQuads) {
}
DelegatedFrameData frame_in;
+ frame_in.render_pass_list.push_back(child_pass_in.Pass());
frame_in.render_pass_list.push_back(pass_in.Pass());
IPC::ParamTraits<DelegatedFrameData>::Write(&msg, frame_in);
@@ -510,8 +499,13 @@ TEST_F(CCMessagesTest, AllQuads) {
&iter, &frame_out));
// Make sure the out and cmp RenderPasses match.
- scoped_ptr<RenderPass> pass_out = frame_out.render_pass_list.take(
- frame_out.render_pass_list.begin());
+ scoped_ptr<RenderPass> child_pass_out =
+ frame_out.render_pass_list.take(frame_out.render_pass_list.begin());
+ Compare(child_pass_cmp.get(), child_pass_out.get());
+ ASSERT_EQ(0u, child_pass_out->shared_quad_state_list.size());
+ ASSERT_EQ(0u, child_pass_out->quad_list.size());
+ scoped_ptr<RenderPass> pass_out =
+ frame_out.render_pass_list.take(frame_out.render_pass_list.begin() + 1);
Compare(pass_cmp.get(), pass_out.get());
ASSERT_EQ(3u, pass_out->shared_quad_state_list.size());
ASSERT_EQ(10u, pass_out->quad_list.size());
@@ -560,12 +554,8 @@ TEST_F(CCMessagesTest, UnusedSharedQuadStates) {
CheckerboardDrawQuad* quad1 =
pass_in->CreateAndAppendDrawQuad<CheckerboardDrawQuad>();
- quad1->SetAll(shared_state1_in,
- gfx::Rect(10, 10),
- gfx::Rect(10, 10),
- gfx::Rect(10, 10),
- false,
- SK_ColorRED);
+ quad1->SetAll(shared_state1_in, gfx::Rect(10, 10), gfx::Rect(10, 10),
+ gfx::Rect(10, 10), false, SK_ColorRED, 1.f);
// The second and third SharedQuadStates are not used.
SharedQuadState* shared_state2_in = pass_in->CreateAndAppendSharedQuadState();
@@ -601,12 +591,8 @@ TEST_F(CCMessagesTest, UnusedSharedQuadStates) {
CheckerboardDrawQuad* quad2 =
pass_in->CreateAndAppendDrawQuad<CheckerboardDrawQuad>();
- quad2->SetAll(shared_state4_in,
- gfx::Rect(10, 10),
- gfx::Rect(10, 10),
- gfx::Rect(10, 10),
- false,
- SK_ColorRED);
+ quad2->SetAll(shared_state4_in, gfx::Rect(10, 10), gfx::Rect(10, 10),
+ gfx::Rect(10, 10), false, SK_ColorRED, 1.f);
// The fifth is not used again.
SharedQuadState* shared_state5_in = pass_in->CreateAndAppendSharedQuadState();
diff --git a/chromium/content/common/child_process_host_impl.cc b/chromium/content/common/child_process_host_impl.cc
index 8e1f56f694f..69a63507f58 100644
--- a/chromium/content/common/child_process_host_impl.cc
+++ b/chromium/content/common/child_process_host_impl.cc
@@ -139,7 +139,6 @@ base::FilePath ChildProcessHost::GetChildPath(int flags) {
ChildProcessHostImpl::ChildProcessHostImpl(ChildProcessHostDelegate* delegate)
: delegate_(delegate),
- peer_handle_(base::kNullProcessHandle),
opening_channel_(false) {
#if defined(OS_WIN)
AddFilter(new FontCacheDispatcher());
@@ -151,8 +150,6 @@ ChildProcessHostImpl::~ChildProcessHostImpl() {
filters_[i]->OnChannelClosing();
filters_[i]->OnFilterRemoved();
}
-
- base::CloseProcessHandle(peer_handle_);
}
void ChildProcessHostImpl::AddFilter(IPC::MessageFilter* filter) {
@@ -257,9 +254,8 @@ bool ChildProcessHostImpl::OnMessageReceived(const IPC::Message& msg) {
OnShutdownRequest)
IPC_MESSAGE_HANDLER(ChildProcessHostMsg_SyncAllocateSharedMemory,
OnAllocateSharedMemory)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(
- ChildProcessHostMsg_SyncAllocateGpuMemoryBuffer,
- OnAllocateGpuMemoryBuffer)
+ IPC_MESSAGE_HANDLER(ChildProcessHostMsg_SyncAllocateGpuMemoryBuffer,
+ OnAllocateGpuMemoryBuffer)
IPC_MESSAGE_HANDLER(ChildProcessHostMsg_DeletedGpuMemoryBuffer,
OnDeletedGpuMemoryBuffer)
IPC_MESSAGE_UNHANDLED(handled = false)
@@ -277,10 +273,11 @@ bool ChildProcessHostImpl::OnMessageReceived(const IPC::Message& msg) {
}
void ChildProcessHostImpl::OnChannelConnected(int32 peer_pid) {
- if (!peer_handle_ &&
- !base::OpenPrivilegedProcessHandle(peer_pid, &peer_handle_)) {
- peer_handle_ = delegate_->GetHandle();
- DCHECK(peer_handle_);
+ if (!peer_process_.IsValid()) {
+ peer_process_ = base::Process::OpenWithExtraPrivileges(peer_pid);
+ if (!peer_process_.IsValid())
+ peer_process_ = delegate_->GetProcess().Duplicate();
+ DCHECK(peer_process_.IsValid());
}
opening_channel_ = false;
delegate_->OnChannelConnected(peer_pid);
@@ -306,7 +303,7 @@ void ChildProcessHostImpl::OnBadMessageReceived(const IPC::Message& message) {
void ChildProcessHostImpl::OnAllocateSharedMemory(
uint32 buffer_size,
base::SharedMemoryHandle* handle) {
- AllocateSharedMemory(buffer_size, peer_handle_, handle);
+ AllocateSharedMemory(buffer_size, peer_process_.Handle(), handle);
}
void ChildProcessHostImpl::OnShutdownRequest() {
@@ -319,31 +316,20 @@ void ChildProcessHostImpl::OnAllocateGpuMemoryBuffer(
uint32 height,
gfx::GpuMemoryBuffer::Format format,
gfx::GpuMemoryBuffer::Usage usage,
- IPC::Message* reply) {
- base::CheckedNumeric<int> size = width;
- size *= height;
- if (!size.IsValid()) {
- GpuMemoryBufferAllocated(reply, gfx::GpuMemoryBufferHandle());
- return;
- }
-
+ gfx::GpuMemoryBufferHandle* handle) {
// TODO(reveman): Add support for other types of GpuMemoryBuffers.
- if (!GpuMemoryBufferImplSharedMemory::IsConfigurationSupported(
- gfx::Size(width, height), format, usage)) {
- GpuMemoryBufferAllocated(reply, gfx::GpuMemoryBufferHandle());
- return;
- }
- // Note: It is safe to use base::Unretained here as the shared memory
- // implementation of AllocateForChildProcess() calls this synchronously.
- GpuMemoryBufferImplSharedMemory::AllocateForChildProcess(
- g_next_gpu_memory_buffer_id.GetNext(),
- gfx::Size(width, height),
- format,
- peer_handle_,
- base::Bind(&ChildProcessHostImpl::GpuMemoryBufferAllocated,
- base::Unretained(this),
- reply));
+ // AllocateForChildProcess() will check if |width| and |height| are valid
+ // and handle failure in a controlled way when not. We just need to make
+ // sure |format| and |usage| are supported here.
+ if (GpuMemoryBufferImplSharedMemory::IsFormatSupported(format) &&
+ usage == gfx::GpuMemoryBuffer::MAP) {
+ *handle = GpuMemoryBufferImplSharedMemory::AllocateForChildProcess(
+ g_next_gpu_memory_buffer_id.GetNext(),
+ gfx::Size(width, height),
+ format,
+ peer_process_.Handle());
+ }
}
void ChildProcessHostImpl::OnDeletedGpuMemoryBuffer(
@@ -353,12 +339,4 @@ void ChildProcessHostImpl::OnDeletedGpuMemoryBuffer(
// GpuMemoryBuffers is passed with IPC.
}
-void ChildProcessHostImpl::GpuMemoryBufferAllocated(
- IPC::Message* reply,
- const gfx::GpuMemoryBufferHandle& handle) {
- ChildProcessHostMsg_SyncAllocateGpuMemoryBuffer::WriteReplyParams(reply,
- handle);
- Send(reply);
-}
-
} // namespace content
diff --git a/chromium/content/common/child_process_host_impl.h b/chromium/content/common/child_process_host_impl.h
index 88c7cf25e83..93ff0ebe1d1 100644
--- a/chromium/content/common/child_process_host_impl.h
+++ b/chromium/content/common/child_process_host_impl.h
@@ -14,6 +14,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/shared_memory.h"
#include "base/memory/singleton.h"
+#include "base/process/process.h"
#include "base/strings/string16.h"
#include "content/public/common/child_process_host.h"
#include "ipc/ipc_listener.h"
@@ -83,15 +84,12 @@ class CONTENT_EXPORT ChildProcessHostImpl : public ChildProcessHost,
uint32 height,
gfx::GpuMemoryBuffer::Format format,
gfx::GpuMemoryBuffer::Usage usage,
- IPC::Message* reply);
+ gfx::GpuMemoryBufferHandle* handle);
void OnDeletedGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
uint32 sync_point);
- void GpuMemoryBufferAllocated(IPC::Message* reply,
- const gfx::GpuMemoryBufferHandle& handle);
-
ChildProcessHostDelegate* delegate_;
- base::ProcessHandle peer_handle_;
+ base::Process peer_process_;
bool opening_channel_; // True while we're waiting the channel to be opened.
scoped_ptr<IPC::Channel> channel_;
std::string channel_id_;
diff --git a/chromium/content/common/child_process_messages.h b/chromium/content/common/child_process_messages.h
index 948b60ed49a..3f37fbfd1e7 100644
--- a/chromium/content/common/child_process_messages.h
+++ b/chromium/content/common/child_process_messages.h
@@ -13,6 +13,7 @@
#include "base/values.h"
#include "cc/resources/shared_bitmap_manager.h"
#include "content/common/content_export.h"
+#include "content/common/host_discardable_shared_memory_manager.h"
#include "ipc/ipc_message_macros.h"
#include "ui/gfx/gpu_memory_buffer.h"
@@ -46,14 +47,12 @@ IPC_STRUCT_TRAITS_BEGIN(tracked_objects::TaskSnapshot)
IPC_STRUCT_TRAITS_MEMBER(death_thread_name)
IPC_STRUCT_TRAITS_END()
-IPC_STRUCT_TRAITS_BEGIN(tracked_objects::ParentChildPairSnapshot)
- IPC_STRUCT_TRAITS_MEMBER(parent)
- IPC_STRUCT_TRAITS_MEMBER(child)
+IPC_STRUCT_TRAITS_BEGIN(tracked_objects::ProcessDataPhaseSnapshot)
+ IPC_STRUCT_TRAITS_MEMBER(tasks)
IPC_STRUCT_TRAITS_END()
IPC_STRUCT_TRAITS_BEGIN(tracked_objects::ProcessDataSnapshot)
- IPC_STRUCT_TRAITS_MEMBER(tasks)
- IPC_STRUCT_TRAITS_MEMBER(descendants)
+ IPC_STRUCT_TRAITS_MEMBER(phased_snapshots)
IPC_STRUCT_TRAITS_MEMBER(process_id)
IPC_STRUCT_TRAITS_END()
@@ -98,16 +97,19 @@ IPC_MESSAGE_CONTROL1(ChildProcessMsg_SetProfilerStatus,
// Send to all the child processes to send back profiler data (ThreadData in
// tracked_objects).
-IPC_MESSAGE_CONTROL1(ChildProcessMsg_GetChildProfilerData,
- int /* sequence_number */)
+IPC_MESSAGE_CONTROL2(ChildProcessMsg_GetChildProfilerData,
+ int /* sequence_number */,
+ int /* current_profiling_phase */)
+
+// Send to all the child processes to mark the current profiling phase as
+// finished and start a new phase.
+IPC_MESSAGE_CONTROL1(ChildProcessMsg_ProfilingPhaseCompleted,
+ int /* profiling_phase */)
// Send to all the child processes to send back histogram data.
IPC_MESSAGE_CONTROL1(ChildProcessMsg_GetChildHistogramData,
int /* sequence_number */)
-// Sent to child processes to dump their handle table.
-IPC_MESSAGE_CONTROL0(ChildProcessMsg_DumpHandles)
-
// Sent to child processes to tell them to enter or leave background mode.
IPC_MESSAGE_CONTROL1(ChildProcessMsg_SetProcessBackgrounded,
bool /* background */)
@@ -123,9 +125,10 @@ IPC_MESSAGE_CONTROL0(ChildProcessMsg_GetTcmallocStats)
IPC_MESSAGE_CONTROL0(ChildProcessHostMsg_ShutdownRequest)
// Send back profiler data (ThreadData in tracked_objects).
-IPC_MESSAGE_CONTROL2(ChildProcessHostMsg_ChildProfilerData,
- int, /* sequence_number */
- tracked_objects::ProcessDataSnapshot /* profiler_data */)
+IPC_MESSAGE_CONTROL2(
+ ChildProcessHostMsg_ChildProfilerData,
+ int, /* sequence_number */
+ tracked_objects::ProcessDataSnapshot /* process_data_snapshot */)
// Send back histograms as vector of pickled-histogram strings.
IPC_MESSAGE_CONTROL2(ChildProcessHostMsg_ChildHistogramData,
@@ -139,9 +142,6 @@ IPC_SYNC_MESSAGE_CONTROL1_1(ChildProcessHostMsg_GetBrowserHistogram,
std::string, /* histogram_name */
std::string /* histogram_json */)
-// Reply to ChildProcessMsg_DumpHandles when handle table dump is complete.
-IPC_MESSAGE_CONTROL0(ChildProcessHostMsg_DumpHandlesDone)
-
#if defined(OS_WIN)
// Request that the given font be loaded by the host so it's cached by the
// OS. Please see ChildProcessHost::PreCacheFont for details.
@@ -196,7 +196,13 @@ IPC_MESSAGE_CONTROL2(ChildProcessHostMsg_DeletedGpuMemoryBuffer,
// Asks the browser to create a block of discardable shared memory for the
// child process.
-IPC_SYNC_MESSAGE_CONTROL1_1(
+IPC_SYNC_MESSAGE_CONTROL2_1(
ChildProcessHostMsg_SyncAllocateLockedDiscardableSharedMemory,
uint32 /* size */,
+ content::DiscardableSharedMemoryId,
base::SharedMemoryHandle)
+
+// Informs the browser that the child deleted a block of discardable shared
+// memory.
+IPC_MESSAGE_CONTROL1(ChildProcessHostMsg_DeletedDiscardableSharedMemory,
+ content::DiscardableSharedMemoryId)
diff --git a/chromium/content/common/child_process_sandbox_support_impl_linux.cc b/chromium/content/common/child_process_sandbox_support_impl_linux.cc
index 5cc8144e5ec..7c9ee4e5c53 100644
--- a/chromium/content/common/child_process_sandbox_support_impl_linux.cc
+++ b/chromium/content/common/child_process_sandbox_support_impl_linux.cc
@@ -9,15 +9,14 @@
#include <limits>
#include "base/basictypes.h"
-#include "base/debug/trace_event.h"
#include "base/memory/scoped_ptr.h"
#include "base/numerics/safe_conversions.h"
#include "base/pickle.h"
#include "base/posix/eintr_wrapper.h"
#include "base/posix/unix_domain_socket_linux.h"
#include "base/sys_byteorder.h"
+#include "base/trace_event/trace_event.h"
#include "content/common/sandbox_linux/sandbox_linux.h"
-#include "content/common/zygote_commands_linux.h"
#include "third_party/WebKit/public/platform/linux/WebFallbackFont.h"
#include "third_party/WebKit/public/platform/linux/WebFontRenderStyle.h"
@@ -46,12 +45,12 @@ void GetFallbackFontForCharacter(int32_t character,
if (n != -1) {
Pickle reply(reinterpret_cast<char*>(buf), n);
PickleIterator pickle_iter(reply);
- if (reply.ReadString(&pickle_iter, &family_name) &&
- reply.ReadString(&pickle_iter, &filename) &&
- reply.ReadInt(&pickle_iter, &fontconfigInterfaceId) &&
- reply.ReadInt(&pickle_iter, &ttcIndex) &&
- reply.ReadBool(&pickle_iter, &isBold) &&
- reply.ReadBool(&pickle_iter, &isItalic)) {
+ if (pickle_iter.ReadString(&family_name) &&
+ pickle_iter.ReadString(&filename) &&
+ pickle_iter.ReadInt(&fontconfigInterfaceId) &&
+ pickle_iter.ReadInt(&ttcIndex) &&
+ pickle_iter.ReadBool(&isBold) &&
+ pickle_iter.ReadBool(&isItalic)) {
fallbackFont->name = family_name;
fallbackFont->filename = filename;
fallbackFont->fontconfigInterfaceId = fontconfigInterfaceId;
@@ -95,13 +94,13 @@ void GetRenderStyleForStrike(const char* family,
PickleIterator pickle_iter(reply);
int use_bitmaps, use_autohint, use_hinting, hint_style, use_antialias;
int use_subpixel_rendering, use_subpixel_positioning;
- if (reply.ReadInt(&pickle_iter, &use_bitmaps) &&
- reply.ReadInt(&pickle_iter, &use_autohint) &&
- reply.ReadInt(&pickle_iter, &use_hinting) &&
- reply.ReadInt(&pickle_iter, &hint_style) &&
- reply.ReadInt(&pickle_iter, &use_antialias) &&
- reply.ReadInt(&pickle_iter, &use_subpixel_rendering) &&
- reply.ReadInt(&pickle_iter, &use_subpixel_positioning)) {
+ if (pickle_iter.ReadInt(&use_bitmaps) &&
+ pickle_iter.ReadInt(&use_autohint) &&
+ pickle_iter.ReadInt(&use_hinting) &&
+ pickle_iter.ReadInt(&hint_style) &&
+ pickle_iter.ReadInt(&use_antialias) &&
+ pickle_iter.ReadInt(&use_subpixel_rendering) &&
+ pickle_iter.ReadInt(&use_subpixel_positioning)) {
out->useBitmaps = use_bitmaps;
out->useAutoHint = use_autohint;
out->useHinting = use_hinting;
@@ -205,11 +204,4 @@ bool GetFontTable(int fd, uint32_t table_tag, off_t offset,
return true;
}
-bool SendZygoteChildPing(int fd) {
- return UnixDomainSocket::SendMsg(fd,
- kZygoteChildPingMessage,
- sizeof(kZygoteChildPingMessage),
- std::vector<int>());
-}
-
} // namespace content
diff --git a/chromium/content/common/clipboard_messages.h b/chromium/content/common/clipboard_messages.h
index add55e4d3b4..8e417c071f6 100644
--- a/chromium/content/common/clipboard_messages.h
+++ b/chromium/content/common/clipboard_messages.h
@@ -4,15 +4,28 @@
// Multiply-included message file, so no include guard.
+#include <map>
#include <string>
#include <vector>
#include "base/memory/shared_memory.h"
+#include "base/strings/string16.h"
#include "content/common/clipboard_format.h"
#include "content/public/common/common_param_traits.h"
#include "ipc/ipc_message_macros.h"
#include "ui/base/clipboard/clipboard.h"
+// Singly-included section for types and/or struct declarations.
+#ifndef CONTENT_COMMON_CLIPBOARD_MESSAGES_H_
+#define CONTENT_COMMON_CLIPBOARD_MESSAGES_H_
+
+// Custom data consists of arbitrary MIME types an untrusted sender wants to
+// write to the clipboard. Note that exposing a general interface to do this is
+// dangerous--an untrusted sender could cause a DoS or code execution.
+typedef std::map<base::string16, base::string16> CustomDataMap;
+
+#endif // CONTENT_COMMON_CLIPBOARD_MESSAGES_H_
+
#define IPC_MESSAGE_START ClipboardMsgStart
IPC_ENUM_TRAITS_MAX_VALUE(content::ClipboardFormat,
@@ -21,15 +34,6 @@ IPC_ENUM_TRAITS_MAX_VALUE(ui::ClipboardType, ui::CLIPBOARD_TYPE_LAST)
// Clipboard IPC messages sent from the renderer to the browser.
-// This message is used when the object list does not contain a bitmap.
-IPC_MESSAGE_CONTROL1(ClipboardHostMsg_WriteObjectsAsync,
- ui::Clipboard::ObjectMap /* objects */)
-// This message is used when the object list contains a bitmap.
-// It is synchronized so that the renderer knows when it is safe to
-// free the shared memory used to transfer the bitmap.
-IPC_SYNC_MESSAGE_CONTROL2_0(ClipboardHostMsg_WriteObjectsSync,
- ui::Clipboard::ObjectMap /* objects */,
- base::SharedMemoryHandle /* bitmap handle */)
IPC_SYNC_MESSAGE_CONTROL1_1(ClipboardHostMsg_GetSequenceNumber,
ui::ClipboardType /* type */,
uint64 /* result */)
@@ -64,6 +68,35 @@ IPC_SYNC_MESSAGE_CONTROL2_1(ClipboardHostMsg_ReadCustomData,
base::string16 /* type */,
base::string16 /* result */)
+// Writing to the clipboard via IPC is a two-phase operation. First, the sender
+// sends the different types of data it'd like to write to the receiver. Then,
+// it sends a commit message to commit the data to the system clipboard.
+IPC_MESSAGE_CONTROL2(ClipboardHostMsg_WriteText,
+ ui::ClipboardType /* type */,
+ base::string16 /* text */)
+IPC_MESSAGE_CONTROL3(ClipboardHostMsg_WriteHTML,
+ ui::ClipboardType /* type */,
+ base::string16 /* markup */,
+ GURL /* url */)
+IPC_MESSAGE_CONTROL1(ClipboardHostMsg_WriteSmartPasteMarker,
+ ui::ClipboardType /* type */)
+IPC_MESSAGE_CONTROL2(ClipboardHostMsg_WriteCustomData,
+ ui::ClipboardType /* type */,
+ CustomDataMap /* custom data */)
+// TODO(dcheng): The |url| parameter should really be a GURL, but <canvas>'s
+// copy as image tries to set very long data: URLs on the clipboard. Using
+// GURL causes the browser to kill the renderer for sending a bad IPC (GURLs
+// bigger than 2 megabytes are considered to be bad). https://crbug.com/459822
+IPC_MESSAGE_CONTROL3(ClipboardHostMsg_WriteBookmark,
+ ui::ClipboardType /* type */,
+ std::string /* url */,
+ base::string16 /* title */)
+IPC_SYNC_MESSAGE_CONTROL3_0(ClipboardHostMsg_WriteImage,
+ ui::ClipboardType /* type */,
+ gfx::Size /* size */,
+ base::SharedMemoryHandle /* bitmap handle */)
+IPC_MESSAGE_CONTROL1(ClipboardHostMsg_CommitWrite, ui::ClipboardType /* type */)
+
#if defined(OS_MACOSX)
IPC_MESSAGE_CONTROL1(ClipboardHostMsg_FindPboardWriteStringAsync,
base::string16 /* text */)
diff --git a/chromium/content/common/common.gni b/chromium/content/common/common.gni
index 36cb33960fa..597cd1b5e23 100644
--- a/chromium/content/common/common.gni
+++ b/chromium/content/common/common.gni
@@ -6,9 +6,17 @@
# cached, which is a performance optimization that allows us to share the
# results of parsing the .gypi file between the public and private BUILD.gn
# files. It also saves us from duplicating this exec_script call.
-content_common_gypi_values = exec_script(
- "//build/gypi_to_gn.py",
- [ rebase_path("../content_common.gypi") ],
- "scope",
- [ "../content_common.gypi" ])
+content_common_gypi_values =
+ exec_script("//build/gypi_to_gn.py",
+ [ rebase_path("../content_common.gypi") ],
+ "scope",
+ [ "../content_common.gypi" ])
+declare_args() {
+ # Indicates if V4L plugin is used.
+ use_v4lplugin = false
+
+ # Indicates if Video4Linux2 codec is used. This is used for all CrOS
+ # platforms which have v4l2 hardware encoder / decoder.
+ use_v4l2_codec = false
+}
diff --git a/chromium/content/common/common_param_traits_unittest.cc b/chromium/content/common/common_param_traits_unittest.cc
index c1f763af4e2..474df970192 100644
--- a/chromium/content/common/common_param_traits_unittest.cc
+++ b/chromium/content/common/common_param_traits_unittest.cc
@@ -15,8 +15,8 @@
#include "printing/page_range.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/ipc/gfx_param_traits.h"
-#include "ui/gfx/rect.h"
#include "url/gurl.h"
// Tests that serialize/deserialize correctly understand each other
@@ -109,7 +109,7 @@ TEST(IPCMessageTest, Bitmap) {
const char* fixed_data;
int fixed_data_size;
iter = PickleIterator(msg);
- EXPECT_TRUE(msg.ReadData(&iter, &fixed_data, &fixed_data_size));
+ EXPECT_TRUE(iter.ReadData(&fixed_data, &fixed_data_size));
bad_msg.WriteData(fixed_data, fixed_data_size);
// Add some bogus pixel data.
const size_t bogus_pixels_size = bitmap.getSize() * 2;
diff --git a/chromium/content/common/content_message_generator.h b/chromium/content/common/content_message_generator.h
index c8ec407e650..63d35847892 100644
--- a/chromium/content/common/content_message_generator.h
+++ b/chromium/content/common/content_message_generator.h
@@ -8,11 +8,12 @@
#include "content/common/accessibility_messages.h"
#include "content/common/appcache_messages.h"
+#include "content/common/bluetooth/bluetooth_messages.h"
#include "content/common/browser_plugin/browser_plugin_messages.h"
+#include "content/common/cache_storage/cache_storage_messages.h"
#include "content/common/cc_messages.h"
#include "content/common/clipboard_messages.h"
#include "content/common/database_messages.h"
-#include "content/common/desktop_notification_messages.h"
#include "content/common/device_sensors/device_light_messages.h"
#include "content/common/device_sensors/device_motion_messages.h"
#include "content/common/device_sensors/device_orientation_messages.h"
@@ -26,7 +27,6 @@
#include "content/common/frame_messages.h"
#include "content/common/gamepad_messages.h"
#include "content/common/geofencing_messages.h"
-#include "content/common/geolocation_messages.h"
#include "content/common/gpu/gpu_messages.h"
#include "content/common/image_messages.h"
#include "content/common/indexed_db/indexed_db_messages.h"
@@ -46,6 +46,7 @@
#include "content/common/message_port_messages.h"
#include "content/common/mime_registry_messages.h"
#include "content/common/mojo/mojo_messages.h"
+#include "content/common/navigator_connect_messages.h"
#include "content/common/pepper_messages.h"
#include "content/common/platform_notification_messages.h"
#include "content/common/plugin_process_messages.h"
diff --git a/chromium/content/common/content_param_traits.cc b/chromium/content/common/content_param_traits.cc
index 0f1ba055121..8faf97c1f00 100644
--- a/chromium/content/common/content_param_traits.cc
+++ b/chromium/content/common/content_param_traits.cc
@@ -7,30 +7,9 @@
#include "base/strings/string_number_conversions.h"
#include "content/common/input/web_input_event_traits.h"
#include "net/base/ip_endpoint.h"
-#include "ui/gfx/range/range.h"
namespace IPC {
-void ParamTraits<gfx::Range>::Write(Message* m, const gfx::Range& r) {
- m->WriteSizeT(r.start());
- m->WriteSizeT(r.end());
-}
-
-bool ParamTraits<gfx::Range>::Read(const Message* m,
- PickleIterator* iter,
- gfx::Range* r) {
- size_t start, end;
- if (!m->ReadSizeT(iter, &start) || !m->ReadSizeT(iter, &end))
- return false;
- r->set_start(start);
- r->set_end(end);
- return true;
-}
-
-void ParamTraits<gfx::Range>::Log(const gfx::Range& r, std::string* l) {
- l->append(base::StringPrintf("(%" PRIuS ", %" PRIuS ")", r.start(), r.end()));
-}
-
void ParamTraits<WebInputEventPointer>::Write(Message* m, const param_type& p) {
m->WriteData(reinterpret_cast<const char*>(p), p->size);
}
@@ -40,7 +19,7 @@ bool ParamTraits<WebInputEventPointer>::Read(const Message* m,
param_type* r) {
const char* data;
int data_length;
- if (!m->ReadData(iter, &data, &data_length)) {
+ if (!iter->ReadData(&data, &data_length)) {
NOTREACHED();
return false;
}
diff --git a/chromium/content/common/content_param_traits.h b/chromium/content/common/content_param_traits.h
index 323e76cabad..03040af7172 100644
--- a/chromium/content/common/content_param_traits.h
+++ b/chromium/content/common/content_param_traits.h
@@ -18,10 +18,6 @@
#include "content/common/cursors/webcursor.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
-namespace gfx {
-class Range;
-}
-
namespace net {
class IPEndPoint;
}
@@ -29,14 +25,6 @@ class IPEndPoint;
namespace IPC {
template <>
-struct ParamTraits<gfx::Range> {
- typedef gfx::Range param_type;
- static void Write(Message* m, const param_type& p);
- static bool Read(const Message* m, PickleIterator* iter, param_type* r);
- static void Log(const param_type& p, std::string* l);
-};
-
-template <>
struct ParamTraits<content::WebCursor> {
typedef content::WebCursor param_type;
static void Write(Message* m, const param_type& p) {
diff --git a/chromium/content/common/content_param_traits_macros.h b/chromium/content/common/content_param_traits_macros.h
index 1442a86dcf2..340dc7d2dd1 100644
--- a/chromium/content/common/content_param_traits_macros.h
+++ b/chromium/content/common/content_param_traits_macros.h
@@ -13,10 +13,10 @@
#include "content/public/common/request_context_type.h"
#include "content/public/common/resource_type.h"
#include "ipc/ipc_message_macros.h"
+#include "third_party/WebKit/public/platform/WebPageVisibilityState.h"
#include "third_party/WebKit/public/web/WebCompositionUnderline.h"
#include "third_party/WebKit/public/web/WebContentSecurityPolicy.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
-#include "third_party/WebKit/public/web/WebPageVisibilityState.h"
#undef IPC_MESSAGE_EXPORT
#define IPC_MESSAGE_EXPORT CONTENT_EXPORT
diff --git a/chromium/content/common/content_switches_internal.cc b/chromium/content/common/content_switches_internal.cc
index 76d877224a4..c13396ea3ca 100644
--- a/chromium/content/common/content_switches_internal.cc
+++ b/chromium/content/common/content_switches_internal.cc
@@ -4,15 +4,27 @@
#include "content/common/content_switches_internal.h"
+#include <string>
+
#include "base/command_line.h"
+#include "base/metrics/field_trial.h"
#include "content/public/common/content_switches.h"
#if defined(OS_WIN)
#include "base/win/windows_version.h"
+#include "ui/gfx/win/direct_write.h"
#endif
namespace content {
+namespace {
+
+#if defined(OS_WIN)
+static bool g_win32k_renderer_lockdown_disabled = false;
+#endif
+
+} // namespace
+
bool IsPinchToZoomEnabled() {
const base::CommandLine& command_line =
*base::CommandLine::ForCurrentProcess();
@@ -31,4 +43,58 @@ bool IsPinchToZoomEnabled() {
#endif
}
+#if defined(OS_WIN)
+
+void DisableWin32kRendererLockdown() {
+ g_win32k_renderer_lockdown_disabled = true;
+}
+
+bool IsWin32kRendererLockdownEnabled() {
+ if (g_win32k_renderer_lockdown_disabled)
+ return false;
+ if (base::win::GetVersion() < base::win::VERSION_WIN8)
+ return false;
+ if (!gfx::win::ShouldUseDirectWrite())
+ return false;
+ const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
+ if (cmd_line->HasSwitch(switches::kDisableWin32kRendererLockDown))
+ return false;
+ return true;
+}
+#endif
+
+V8CacheOptions GetV8CacheOptions() {
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
+ std::string v8_cache_options =
+ command_line.GetSwitchValueASCII(switches::kV8CacheOptions);
+ if (v8_cache_options.empty())
+ v8_cache_options = base::FieldTrialList::FindFullName("V8CacheOptions");
+ if (v8_cache_options == "parse") {
+ return V8_CACHE_OPTIONS_PARSE;
+ } else if (v8_cache_options == "code") {
+ return V8_CACHE_OPTIONS_CODE;
+ } else if (v8_cache_options == "code-compressed") {
+ return V8_CACHE_OPTIONS_CODE_COMPRESSED;
+ } else if (v8_cache_options == "none") {
+ return V8_CACHE_OPTIONS_NONE;
+ } else if (v8_cache_options == "parse-memory") {
+ return V8_CACHE_OPTIONS_PARSE_MEMORY;
+ } else if (v8_cache_options == "heuristics") {
+ return V8_CACHE_OPTIONS_HEURISTICS;
+ } else if (v8_cache_options == "heuristics-mobile") {
+ return V8_CACHE_OPTIONS_HEURISTICS_MOBILE;
+ } else if (v8_cache_options == "heuristics-default") {
+ return V8_CACHE_OPTIONS_HEURISTICS_DEFAULT;
+ } else if (v8_cache_options == "heuristics-default-mobile") {
+ return V8_CACHE_OPTIONS_HEURISTICS_DEFAULT_MOBILE;
+ } else if (v8_cache_options == "recent") {
+ return V8_CACHE_OPTIONS_RECENT;
+ } else if (v8_cache_options == "recent-small") {
+ return V8_CACHE_OPTIONS_RECENT_SMALL;
+ } else {
+ return V8_CACHE_OPTIONS_DEFAULT;
+ }
+}
+
} // namespace content
diff --git a/chromium/content/common/content_switches_internal.h b/chromium/content/common/content_switches_internal.h
index ac31c5f3312..aba55e54bf8 100644
--- a/chromium/content/common/content_switches_internal.h
+++ b/chromium/content/common/content_switches_internal.h
@@ -5,9 +5,19 @@
#ifndef CONTENT_COMMON_CONTENT_SWITCHES_INTERNAL_H_
#define CONTENT_COMMON_CONTENT_SWITCHES_INTERNAL_H_
+#include "content/public/common/web_preferences.h"
+
namespace content {
bool IsPinchToZoomEnabled();
+#if defined(OS_WIN)
+// Disables Win32k Renderer lockdown for any future renderer child processes.
+void DisableWin32kRendererLockdown();
+
+// Returns whether Win32k Renderer lockdown is enabled or not.
+bool IsWin32kRendererLockdownEnabled();
+#endif
+V8CacheOptions GetV8CacheOptions();
} // namespace content
diff --git a/chromium/content/common/cookie_data.cc b/chromium/content/common/cookie_data.cc
deleted file mode 100644
index 3a6980bbdea..00000000000
--- a/chromium/content/common/cookie_data.cc
+++ /dev/null
@@ -1,32 +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/common/cookie_data.h"
-
-#include "net/cookies/canonical_cookie.h"
-
-namespace content {
-
-CookieData::CookieData()
- : expires(0),
- http_only(false),
- secure(false),
- session(false) {
-}
-
-CookieData::CookieData(const net::CanonicalCookie& c)
- : name(c.Name()),
- value(c.Value()),
- domain(c.Domain()),
- path(c.Path()),
- expires(c.ExpiryDate().ToDoubleT() * 1000),
- http_only(c.IsHttpOnly()),
- secure(c.IsSecure()),
- session(!c.IsPersistent()) {
-}
-
-CookieData::~CookieData() {
-}
-
-} // namespace content
diff --git a/chromium/content/common/cookie_data.h b/chromium/content/common/cookie_data.h
deleted file mode 100644
index 21dd022778c..00000000000
--- a/chromium/content/common/cookie_data.h
+++ /dev/null
@@ -1,50 +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_COMMON_COOKIE_DATA_H_
-#define CONTENT_COMMON_COOKIE_DATA_H_
-
-#include <string>
-
-#include "content/common/content_export.h"
-
-namespace net {
-class CanonicalCookie;
-}
-
-namespace content {
-
-struct CONTENT_EXPORT CookieData {
- CookieData();
- explicit CookieData(const net::CanonicalCookie& c);
- ~CookieData();
-
- // Cookie name.
- std::string name;
-
- // Cookie value.
- std::string value;
-
- // Cookie domain.
- std::string domain;
-
- // Cookie path.
- std::string path;
-
- // Cookie expires param if any.
- double expires;
-
- // Cookie HTTPOnly param.
- bool http_only;
-
- // Cookie secure param.
- bool secure;
-
- // Session cookie flag.
- bool session;
-};
-
-} // namespace content
-
-#endif // CONTENT_COMMON_COOKIE_DATA_H_
diff --git a/chromium/content/common/cursors/webcursor.h b/chromium/content/common/cursors/webcursor.h
index d53fbd0514a..cd78c580004 100644
--- a/chromium/content/common/cursors/webcursor.h
+++ b/chromium/content/common/cursors/webcursor.h
@@ -11,9 +11,9 @@
#include "content/common/content_export.h"
#include "third_party/WebKit/public/platform/WebCursorInfo.h"
#include "ui/gfx/display.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/size.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/point.h"
-#include "ui/gfx/size.h"
#if defined(USE_AURA)
#include "ui/base/cursor/cursor.h"
diff --git a/chromium/content/common/cursors/webcursor_mac.mm b/chromium/content/common/cursors/webcursor_mac.mm
index 2c0c2aa87ef..3f406108ab3 100644
--- a/chromium/content/common/cursors/webcursor_mac.mm
+++ b/chromium/content/common/cursors/webcursor_mac.mm
@@ -15,9 +15,9 @@
#include "skia/ext/skia_utils_mac.h"
#include "third_party/WebKit/public/platform/WebCursorInfo.h"
#include "third_party/WebKit/public/platform/WebSize.h"
+#include "ui/gfx/geometry/point_conversions.h"
+#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/image/image.h"
-#include "ui/gfx/point_conversions.h"
-#include "ui/gfx/size_conversions.h"
using blink::WebCursorInfo;
using blink::WebSize;
diff --git a/chromium/content/common/cursors/webcursor_ozone.cc b/chromium/content/common/cursors/webcursor_ozone.cc
index 39a356d2834..d428aa37c67 100644
--- a/chromium/content/common/cursors/webcursor_ozone.cc
+++ b/chromium/content/common/cursors/webcursor_ozone.cc
@@ -9,6 +9,11 @@
#include "ui/base/cursor/cursor_util.h"
#include "ui/ozone/public/cursor_factory_ozone.h"
+namespace {
+const float kMaxCursorWidth = 64.f;
+const float kMaxCursorHeight = 64.f;
+}
+
namespace content {
ui::PlatformCursor WebCursor::GetPlatformCursor() {
@@ -18,11 +23,18 @@ ui::PlatformCursor WebCursor::GetPlatformCursor() {
SkBitmap bitmap;
ImageFromCustomData(&bitmap);
gfx::Point hotspot = hotspot_;
- ui::ScaleAndRotateCursorBitmapAndHotpoint(
- device_scale_factor_, rotation_, &bitmap, &hotspot);
- return ui::CursorFactoryOzone::GetInstance()->CreateImageCursor(bitmap,
- hotspot);
+ // TODO(spang): Consider allowing larger cursors if the hardware supports it.
+ float scale = device_scale_factor_ / custom_scale_;
+ scale = std::min(scale, kMaxCursorWidth / bitmap.width());
+ scale = std::min(scale, kMaxCursorHeight / bitmap.height());
+
+ ui::ScaleAndRotateCursorBitmapAndHotpoint(scale, rotation_, &bitmap,
+ &hotspot);
+
+ platform_cursor_ =
+ ui::CursorFactoryOzone::GetInstance()->CreateImageCursor(bitmap, hotspot);
+ return platform_cursor_;
}
void WebCursor::SetDisplayInfo(const gfx::Display& display) {
diff --git a/chromium/content/common/database_connections_unittest.cc b/chromium/content/common/database_connections_unittest.cc
index 7f9a9b27cb5..8992f0d74ce 100644
--- a/chromium/content/common/database_connections_unittest.cc
+++ b/chromium/content/common/database_connections_unittest.cc
@@ -5,6 +5,7 @@
#include "base/bind.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
#include "base/threading/thread.h"
#include "storage/common/database/database_connections.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -30,10 +31,9 @@ void ScheduleRemoveConnectionTask(
const base::string16& database_name,
scoped_refptr<DatabaseConnectionsWrapper> obj,
bool* did_task_execute) {
- thread->message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&RemoveConnectionTask, origin_id, database_name, obj,
- did_task_execute));
+ thread->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&RemoveConnectionTask, origin_id, database_name,
+ obj, did_task_execute));
}
} // anonymous namespace
@@ -121,10 +121,9 @@ TEST(DatabaseConnectionsTest, DatabaseConnectionsWrapperTest) {
// being removed on the current thread.
obj->AddOpenConnection(kOriginId, kName);
bool did_task_execute = false;
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&RemoveConnectionTask, kOriginId, kName, obj,
- &did_task_execute));
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&RemoveConnectionTask, kOriginId, kName, obj,
+ &did_task_execute));
obj->WaitForAllDatabasesToClose(); // should return after the task executes
EXPECT_TRUE(did_task_execute);
EXPECT_FALSE(obj->HasOpenConnections());
@@ -135,10 +134,9 @@ TEST(DatabaseConnectionsTest, DatabaseConnectionsWrapperTest) {
base::Thread thread("WrapperTestThread");
thread.Start();
did_task_execute = false;
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&ScheduleRemoveConnectionTask, &thread, kOriginId, kName, obj,
- &did_task_execute));
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&ScheduleRemoveConnectionTask, &thread, kOriginId,
+ kName, obj, &did_task_execute));
obj->WaitForAllDatabasesToClose(); // should return after the task executes
EXPECT_TRUE(did_task_execute);
EXPECT_FALSE(obj->HasOpenConnections());
diff --git a/chromium/content/common/database_messages.h b/chromium/content/common/database_messages.h
index 849b34794ec..713db98b2eb 100644
--- a/chromium/content/common/database_messages.h
+++ b/chromium/content/common/database_messages.h
@@ -61,6 +61,12 @@ IPC_SYNC_MESSAGE_CONTROL1_1(DatabaseHostMsg_GetSpaceAvailable,
std::string /* origin identifier */,
int64 /* remaining space available */)
+// Asks the browser set the size of a DB file
+IPC_SYNC_MESSAGE_CONTROL2_1(DatabaseHostMsg_SetFileSize,
+ base::string16 /* vfs file name */,
+ int64 /* expected size of the given DB file */,
+ bool /* indicates success */)
+
// Notifies the browser process that a new database has been opened
IPC_MESSAGE_CONTROL4(DatabaseHostMsg_Opened,
std::string /* origin identifier */,
diff --git a/chromium/content/common/desktop_notification_messages.h b/chromium/content/common/desktop_notification_messages.h
deleted file mode 100644
index 3b2215d0bda..00000000000
--- a/chromium/content/common/desktop_notification_messages.h
+++ /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.
-
-// IPC messages for desktop notification.
-// Multiply-included message file, hence no include guard.
-
-#include "content/public/common/show_desktop_notification_params.h"
-#include "ipc/ipc_message_macros.h"
-
-#define IPC_MESSAGE_START DesktopNotificationMsgStart
-
-IPC_STRUCT_TRAITS_BEGIN(content::ShowDesktopNotificationHostMsgParams)
- IPC_STRUCT_TRAITS_MEMBER(origin)
- IPC_STRUCT_TRAITS_MEMBER(icon)
- IPC_STRUCT_TRAITS_MEMBER(title)
- IPC_STRUCT_TRAITS_MEMBER(body)
- IPC_STRUCT_TRAITS_MEMBER(direction)
- IPC_STRUCT_TRAITS_MEMBER(replace_id)
-IPC_STRUCT_TRAITS_END()
-
-// Messages sent from the browser to the renderer.
-
-// Used to inform the renderer that the browser has displayed its
-// requested notification.
-IPC_MESSAGE_ROUTED1(DesktopNotificationMsg_PostDisplay,
- int /* notification_id */)
-
-// Informs the renderer that the one if its notifications has closed.
-IPC_MESSAGE_ROUTED2(DesktopNotificationMsg_PostClose,
- int /* notification_id */,
- bool /* by_user */)
-
-// Informs the renderer that one of its notifications was clicked on.
-IPC_MESSAGE_ROUTED1(DesktopNotificationMsg_PostClick,
- int /* notification_id */)
-
-// Messages sent from the renderer to the browser.
-
-IPC_MESSAGE_ROUTED2(DesktopNotificationHostMsg_Show,
- int /* notification_id */,
- content::ShowDesktopNotificationHostMsgParams /* params */)
-
-IPC_MESSAGE_ROUTED1(DesktopNotificationHostMsg_Cancel,
- int /* notification_id */)
-
-IPC_SYNC_MESSAGE_ROUTED1_1(DesktopNotificationHostMsg_CheckPermission,
- GURL /* origin */,
- int /* permission_result */)
diff --git a/chromium/content/common/device_sensors/device_motion_hardware_buffer.h b/chromium/content/common/device_sensors/device_motion_hardware_buffer.h
index b025972486a..d387cdac3d6 100644
--- a/chromium/content/common/device_sensors/device_motion_hardware_buffer.h
+++ b/chromium/content/common/device_sensors/device_motion_hardware_buffer.h
@@ -6,7 +6,7 @@
#define CONTENT_COMMON_DEVICE_SENSORS_DEVICE_MOTION_HARDWARE_BUFFER_H_
#include "content/common/shared_memory_seqlock_buffer.h"
-#include "third_party/WebKit/public/platform/WebDeviceMotionData.h"
+#include "third_party/WebKit/public/platform/modules/device_orientation/WebDeviceMotionData.h"
namespace content {
diff --git a/chromium/content/common/device_sensors/device_orientation_hardware_buffer.h b/chromium/content/common/device_sensors/device_orientation_hardware_buffer.h
index 92b705de2bd..c7a0ae87981 100644
--- a/chromium/content/common/device_sensors/device_orientation_hardware_buffer.h
+++ b/chromium/content/common/device_sensors/device_orientation_hardware_buffer.h
@@ -6,7 +6,7 @@
#define CONTENT_COMMON_DEVICE_SENSORS_DEVICE_ORIENTATION_HARDWARE_BUFFER_H_
#include "content/common/shared_memory_seqlock_buffer.h"
-#include "third_party/WebKit/public/platform/WebDeviceOrientationData.h"
+#include "third_party/WebKit/public/platform/modules/device_orientation/WebDeviceOrientationData.h"
namespace content {
diff --git a/chromium/content/common/devtools_messages.h b/chromium/content/common/devtools_messages.h
index 276a82f9678..d91498ed996 100644
--- a/chromium/content/common/devtools_messages.h
+++ b/chromium/content/common/devtools_messages.h
@@ -54,14 +54,24 @@
// These are messages sent from DevToolsAgent to DevToolsClient through the
// browser.
-// WebKit-level transport.
+
+// Agent -> Client message chunk.
+// |is_first| marks the first chunk, comes with the |message_size| for
+// total message size.
+// |is_last| marks the last chunk. |call_id| and |post_state| are optional
+// parameters passed with the last chunk of the protocol response.
+IPC_STRUCT_BEGIN(DevToolsMessageChunk)
+ IPC_STRUCT_MEMBER(bool, is_first)
+ IPC_STRUCT_MEMBER(bool, is_last)
+ IPC_STRUCT_MEMBER(int, message_size)
+ IPC_STRUCT_MEMBER(int, call_id)
+ IPC_STRUCT_MEMBER(std::string, data)
+ IPC_STRUCT_MEMBER(std::string, post_state)
+IPC_STRUCT_END()
// Sends response from the agent to the client. Supports chunked encoding.
-// First (the only) chunk arrives with the |total_size| != 0,
-// remaining chunks arrive with |total_size| == 0.
-IPC_MESSAGE_ROUTED2(DevToolsClientMsg_DispatchOnInspectorFrontend,
- std::string /* message */,
- uint32 /* total_size */)
+IPC_MESSAGE_ROUTED1(DevToolsClientMsg_DispatchOnInspectorFrontend,
+ DevToolsMessageChunk /* message */)
//-----------------------------------------------------------------------------
// These are messages sent from DevToolsClient to DevToolsAgent through the
@@ -110,27 +120,3 @@ IPC_MESSAGE_ROUTED0(DevToolsMsg_SetupDevToolsClient)
// Transport from Inspector frontend to frontend host.
IPC_MESSAGE_ROUTED1(DevToolsHostMsg_DispatchOnEmbedder,
std::string /* message */)
-
-// Updates agent runtime state stored in devtools manager in order to support
-// cross-navigation instrumentation.
-IPC_MESSAGE_ROUTED1(DevToolsHostMsg_SaveAgentRuntimeState,
- std::string /* state */)
-
-//-----------------------------------------------------------------------------
-// These are messages sent from the GPU process to the inspected renderer.
-
-IPC_STRUCT_BEGIN(GpuTaskInfo)
- IPC_STRUCT_MEMBER(double, timestamp)
- IPC_STRUCT_MEMBER(int, phase)
- IPC_STRUCT_MEMBER(bool, foreign)
- IPC_STRUCT_MEMBER(uint64, gpu_memory_used_bytes)
- IPC_STRUCT_MEMBER(uint64, gpu_memory_limit_bytes)
-IPC_STRUCT_END()
-
-// Recorded events are passed in chunks to the renderer process.
-IPC_MESSAGE_ROUTED1(DevToolsAgentMsg_GpuTasksChunk,
- std::vector<GpuTaskInfo> /* gpu_tasks */)
-
-//-----------------------------------------------------------------------------
-// These are messages sent from the inspected page renderer to the worker
-// renderer.
diff --git a/chromium/content/common/discardable_shared_memory_heap.cc b/chromium/content/common/discardable_shared_memory_heap.cc
new file mode 100644
index 00000000000..c784f134915
--- /dev/null
+++ b/chromium/content/common/discardable_shared_memory_heap.cc
@@ -0,0 +1,377 @@
+// Copyright 2014 The Chromium Authors. 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/common/discardable_shared_memory_heap.h"
+
+#include <algorithm>
+
+#include "base/memory/discardable_shared_memory.h"
+#include "base/strings/stringprintf.h"
+
+namespace content {
+namespace {
+
+const char kMemoryAllocatorHeapNamePrefix[] = "segment";
+const char kMemoryAllocatorName[] = "discardable";
+
+bool IsPowerOfTwo(size_t x) {
+ return (x & (x - 1)) == 0;
+}
+
+bool IsInFreeList(DiscardableSharedMemoryHeap::Span* span) {
+ return span->previous() || span->next();
+}
+
+} // namespace
+
+DiscardableSharedMemoryHeap::Span::Span(
+ base::DiscardableSharedMemory* shared_memory,
+ size_t start,
+ size_t length)
+ : shared_memory_(shared_memory), start_(start), length_(length) {
+}
+
+DiscardableSharedMemoryHeap::Span::~Span() {
+}
+
+DiscardableSharedMemoryHeap::ScopedMemorySegment::ScopedMemorySegment(
+ DiscardableSharedMemoryHeap* heap,
+ scoped_ptr<base::DiscardableSharedMemory> shared_memory,
+ size_t size,
+ int32_t id,
+ const base::Closure& deleted_callback)
+ : heap_(heap),
+ shared_memory_(shared_memory.Pass()),
+ size_(size),
+ id_(id),
+ deleted_callback_(deleted_callback) {
+}
+
+DiscardableSharedMemoryHeap::ScopedMemorySegment::~ScopedMemorySegment() {
+ heap_->ReleaseMemory(shared_memory_.get(), size_);
+ deleted_callback_.Run();
+}
+
+bool DiscardableSharedMemoryHeap::ScopedMemorySegment::IsUsed() const {
+ return heap_->IsMemoryUsed(shared_memory_.get(), size_);
+}
+
+bool DiscardableSharedMemoryHeap::ScopedMemorySegment::IsResident() const {
+ return heap_->IsMemoryResident(shared_memory_.get());
+}
+
+void DiscardableSharedMemoryHeap::ScopedMemorySegment::OnMemoryDump(
+ base::trace_event::ProcessMemoryDump* pmd) const {
+ heap_->OnMemoryDump(shared_memory_.get(), size_, id_, pmd);
+}
+
+DiscardableSharedMemoryHeap::DiscardableSharedMemoryHeap(size_t block_size)
+ : block_size_(block_size), num_blocks_(0), num_free_blocks_(0) {
+ DCHECK_NE(block_size_, 0u);
+ DCHECK(IsPowerOfTwo(block_size_));
+}
+
+DiscardableSharedMemoryHeap::~DiscardableSharedMemoryHeap() {
+ memory_segments_.clear();
+ DCHECK_EQ(num_blocks_, 0u);
+ DCHECK_EQ(num_free_blocks_, 0u);
+ DCHECK_EQ(std::count_if(free_spans_, free_spans_ + arraysize(free_spans_),
+ [](const base::LinkedList<Span>& free_spans) {
+ return !free_spans.empty();
+ }),
+ 0);
+}
+
+scoped_ptr<DiscardableSharedMemoryHeap::Span> DiscardableSharedMemoryHeap::Grow(
+ scoped_ptr<base::DiscardableSharedMemory> shared_memory,
+ size_t size,
+ int32_t id,
+ const base::Closure& deleted_callback) {
+ // Memory must be aligned to block size.
+ DCHECK_EQ(
+ reinterpret_cast<size_t>(shared_memory->memory()) & (block_size_ - 1),
+ 0u);
+ DCHECK_EQ(size & (block_size_ - 1), 0u);
+
+ scoped_ptr<Span> span(
+ new Span(shared_memory.get(),
+ reinterpret_cast<size_t>(shared_memory->memory()) / block_size_,
+ size / block_size_));
+ DCHECK(spans_.find(span->start_) == spans_.end());
+ DCHECK(spans_.find(span->start_ + span->length_ - 1) == spans_.end());
+ RegisterSpan(span.get());
+
+ num_blocks_ += span->length_;
+
+ // Start tracking if segment is resident by adding it to |memory_segments_|.
+ memory_segments_.push_back(new ScopedMemorySegment(
+ this, shared_memory.Pass(), size, id, deleted_callback));
+
+ return span.Pass();
+}
+
+void DiscardableSharedMemoryHeap::MergeIntoFreeLists(scoped_ptr<Span> span) {
+ DCHECK(span->shared_memory_);
+
+ // First add length of |span| to |num_free_blocks_|.
+ num_free_blocks_ += span->length_;
+
+ // Merge with previous span if possible.
+ SpanMap::iterator prev_it = spans_.find(span->start_ - 1);
+ if (prev_it != spans_.end() && IsInFreeList(prev_it->second)) {
+ scoped_ptr<Span> prev = RemoveFromFreeList(prev_it->second);
+ DCHECK_EQ(prev->start_ + prev->length_, span->start_);
+ UnregisterSpan(prev.get());
+ if (span->length_ > 1)
+ spans_.erase(span->start_);
+ span->start_ -= prev->length_;
+ span->length_ += prev->length_;
+ spans_[span->start_] = span.get();
+ }
+
+ // Merge with next span if possible.
+ SpanMap::iterator next_it = spans_.find(span->start_ + span->length_);
+ if (next_it != spans_.end() && IsInFreeList(next_it->second)) {
+ scoped_ptr<Span> next = RemoveFromFreeList(next_it->second);
+ DCHECK_EQ(next->start_, span->start_ + span->length_);
+ UnregisterSpan(next.get());
+ if (span->length_ > 1)
+ spans_.erase(span->start_ + span->length_ - 1);
+ span->length_ += next->length_;
+ spans_[span->start_ + span->length_ - 1] = span.get();
+ }
+
+ InsertIntoFreeList(span.Pass());
+}
+
+scoped_ptr<DiscardableSharedMemoryHeap::Span>
+DiscardableSharedMemoryHeap::Split(Span* span, size_t blocks) {
+ DCHECK(blocks);
+ DCHECK_LT(blocks, span->length_);
+
+ scoped_ptr<Span> leftover(new Span(
+ span->shared_memory_, span->start_ + blocks, span->length_ - blocks));
+ DCHECK_IMPLIES(leftover->length_ > 1,
+ spans_.find(leftover->start_) == spans_.end());
+ RegisterSpan(leftover.get());
+ spans_[span->start_ + blocks - 1] = span;
+ span->length_ = blocks;
+ return leftover.Pass();
+}
+
+scoped_ptr<DiscardableSharedMemoryHeap::Span>
+DiscardableSharedMemoryHeap::SearchFreeLists(size_t blocks, size_t slack) {
+ DCHECK(blocks);
+
+ size_t length = blocks;
+ size_t max_length = blocks + slack;
+
+ // Search array of free lists for a suitable span.
+ while (length - 1 < arraysize(free_spans_) - 1) {
+ const base::LinkedList<Span>& free_spans = free_spans_[length - 1];
+ if (!free_spans.empty()) {
+ // Return the most recently used span located in tail.
+ return Carve(free_spans.tail()->value(), blocks);
+ }
+
+ // Return early after surpassing |max_length|.
+ if (++length > max_length)
+ return nullptr;
+ }
+
+ const base::LinkedList<Span>& overflow_free_spans =
+ free_spans_[arraysize(free_spans_) - 1];
+
+ // Search overflow free list for a suitable span. Starting with the most
+ // recently used span located in tail and moving towards head.
+ for (base::LinkNode<Span>* node = overflow_free_spans.tail();
+ node != overflow_free_spans.end(); node = node->previous()) {
+ Span* span = node->value();
+ if (span->length_ >= blocks && span->length_ <= max_length)
+ return Carve(span, blocks);
+ }
+
+ return nullptr;
+}
+
+void DiscardableSharedMemoryHeap::ReleaseFreeMemory() {
+ // Erase all free segments after rearranging the segments in such a way
+ // that used segments precede all free segments.
+ memory_segments_.erase(
+ std::partition(
+ memory_segments_.begin(), memory_segments_.end(),
+ [](const ScopedMemorySegment* segment) { return segment->IsUsed(); }),
+ memory_segments_.end());
+}
+
+void DiscardableSharedMemoryHeap::ReleasePurgedMemory() {
+ // Erase all purged segments after rearranging the segments in such a way
+ // that resident segments precede all purged segments.
+ memory_segments_.erase(
+ std::partition(memory_segments_.begin(), memory_segments_.end(),
+ [](const ScopedMemorySegment* segment) {
+ return segment->IsResident();
+ }),
+ memory_segments_.end());
+}
+
+size_t DiscardableSharedMemoryHeap::GetSize() const {
+ return num_blocks_ * block_size_;
+}
+
+size_t DiscardableSharedMemoryHeap::GetSizeOfFreeLists() const {
+ return num_free_blocks_ * block_size_;
+}
+
+bool DiscardableSharedMemoryHeap::OnMemoryDump(
+ base::trace_event::ProcessMemoryDump* pmd) {
+ std::for_each(
+ memory_segments_.begin(), memory_segments_.end(),
+ [pmd](const ScopedMemorySegment* segment) {
+ segment->OnMemoryDump(pmd);
+ });
+ return true;
+}
+
+void DiscardableSharedMemoryHeap::InsertIntoFreeList(
+ scoped_ptr<DiscardableSharedMemoryHeap::Span> span) {
+ DCHECK(!IsInFreeList(span.get()));
+ size_t index = std::min(span->length_, arraysize(free_spans_)) - 1;
+ free_spans_[index].Append(span.release());
+}
+
+scoped_ptr<DiscardableSharedMemoryHeap::Span>
+DiscardableSharedMemoryHeap::RemoveFromFreeList(Span* span) {
+ DCHECK(IsInFreeList(span));
+ span->RemoveFromList();
+ return make_scoped_ptr(span);
+}
+
+scoped_ptr<DiscardableSharedMemoryHeap::Span>
+DiscardableSharedMemoryHeap::Carve(Span* span, size_t blocks) {
+ scoped_ptr<Span> serving = RemoveFromFreeList(span);
+
+ const int extra = serving->length_ - blocks;
+ if (extra) {
+ scoped_ptr<Span> leftover(
+ new Span(serving->shared_memory_, serving->start_ + blocks, extra));
+ DCHECK_IMPLIES(extra > 1, spans_.find(leftover->start_) == spans_.end());
+ RegisterSpan(leftover.get());
+
+ // No need to coalesce as the previous span of |leftover| was just split
+ // and the next span of |leftover| was not previously coalesced with
+ // |span|.
+ InsertIntoFreeList(leftover.Pass());
+
+ serving->length_ = blocks;
+ spans_[serving->start_ + blocks - 1] = serving.get();
+ }
+
+ // |serving| is no longer in the free list, remove its length from
+ // |num_free_blocks_|.
+ DCHECK_GE(num_free_blocks_, serving->length_);
+ num_free_blocks_ -= serving->length_;
+
+ return serving.Pass();
+}
+
+void DiscardableSharedMemoryHeap::RegisterSpan(Span* span) {
+ spans_[span->start_] = span;
+ if (span->length_ > 1)
+ spans_[span->start_ + span->length_ - 1] = span;
+}
+
+void DiscardableSharedMemoryHeap::UnregisterSpan(Span* span) {
+ DCHECK(spans_.find(span->start_) != spans_.end());
+ DCHECK_EQ(spans_[span->start_], span);
+ spans_.erase(span->start_);
+ if (span->length_ > 1) {
+ DCHECK(spans_.find(span->start_ + span->length_ - 1) != spans_.end());
+ DCHECK_EQ(spans_[span->start_ + span->length_ - 1], span);
+ spans_.erase(span->start_ + span->length_ - 1);
+ }
+}
+
+bool DiscardableSharedMemoryHeap::IsMemoryUsed(
+ const base::DiscardableSharedMemory* shared_memory,
+ size_t size) {
+ size_t offset =
+ reinterpret_cast<size_t>(shared_memory->memory()) / block_size_;
+ size_t length = size / block_size_;
+ DCHECK(spans_.find(offset) != spans_.end());
+ Span* span = spans_[offset];
+ DCHECK_LE(span->length_, length);
+ // Memory is used if first span is not in free list or shorter than segment.
+ return !IsInFreeList(span) || span->length_ != length;
+}
+
+bool DiscardableSharedMemoryHeap::IsMemoryResident(
+ const base::DiscardableSharedMemory* shared_memory) {
+ return shared_memory->IsMemoryResident();
+}
+
+void DiscardableSharedMemoryHeap::ReleaseMemory(
+ const base::DiscardableSharedMemory* shared_memory,
+ size_t size) {
+ size_t offset =
+ reinterpret_cast<size_t>(shared_memory->memory()) / block_size_;
+ size_t end = offset + size / block_size_;
+ while (offset < end) {
+ DCHECK(spans_.find(offset) != spans_.end());
+ Span* span = spans_[offset];
+ DCHECK_EQ(span->shared_memory_, shared_memory);
+ span->shared_memory_ = nullptr;
+ UnregisterSpan(span);
+
+ offset += span->length_;
+
+ DCHECK_GE(num_blocks_, span->length_);
+ num_blocks_ -= span->length_;
+
+ // If |span| is in the free list, remove it and update |num_free_blocks_|.
+ if (IsInFreeList(span)) {
+ DCHECK_GE(num_free_blocks_, span->length_);
+ num_free_blocks_ -= span->length_;
+ RemoveFromFreeList(span);
+ }
+ }
+}
+
+void DiscardableSharedMemoryHeap::OnMemoryDump(
+ const base::DiscardableSharedMemory* shared_memory,
+ size_t size,
+ int32_t id,
+ base::trace_event::ProcessMemoryDump* pmd) {
+ std::string heap_name = base::StringPrintf(
+ "%s/%s_%d", kMemoryAllocatorName, kMemoryAllocatorHeapNamePrefix, id);
+ base::trace_event::MemoryAllocatorDump* dump =
+ pmd->CreateAllocatorDump(heap_name);
+ DCHECK(dump);
+
+ size_t allocated_objects_count = 0;
+ size_t allocated_objects_size_in_bytes = 0;
+ size_t offset =
+ reinterpret_cast<size_t>(shared_memory->memory()) / block_size_;
+ size_t end = offset + size / block_size_;
+ while (offset < end) {
+ Span* span = spans_[offset];
+ if (!IsInFreeList(span)) {
+ allocated_objects_count++;
+ allocated_objects_size_in_bytes += span->length_;
+ }
+ offset += span->length_;
+ }
+
+ dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameOuterSize,
+ base::trace_event::MemoryAllocatorDump::kUnitsBytes,
+ static_cast<uint64_t>(size));
+ dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameObjectsCount,
+ base::trace_event::MemoryAllocatorDump::kUnitsObjects,
+ static_cast<uint64_t>(allocated_objects_count));
+ dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameInnerSize,
+ base::trace_event::MemoryAllocatorDump::kUnitsBytes,
+ static_cast<uint64_t>(allocated_objects_size_in_bytes));
+}
+
+} // namespace content
diff --git a/chromium/content/common/discardable_shared_memory_heap.h b/chromium/content/common/discardable_shared_memory_heap.h
new file mode 100644
index 00000000000..ba2b5911b9d
--- /dev/null
+++ b/chromium/content/common/discardable_shared_memory_heap.h
@@ -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.
+
+#ifndef CONTENT_COMMON_DISCARDABLE_SHARED_MEMORY_HEAP_H_
+#define CONTENT_COMMON_DISCARDABLE_SHARED_MEMORY_HEAP_H_
+
+#include "base/callback.h"
+#include "base/containers/hash_tables.h"
+#include "base/containers/linked_list.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "content/common/content_export.h"
+
+namespace base {
+class DiscardableSharedMemory;
+}
+
+namespace content {
+
+// Implements a heap of discardable shared memory. An array of free lists
+// is used to keep track of free blocks.
+class CONTENT_EXPORT DiscardableSharedMemoryHeap {
+ public:
+ class CONTENT_EXPORT Span : public base::LinkNode<Span> {
+ public:
+ ~Span();
+
+ base::DiscardableSharedMemory* shared_memory() { return shared_memory_; }
+ size_t start() const { return start_; }
+ size_t length() const { return length_; }
+
+ private:
+ friend class DiscardableSharedMemoryHeap;
+
+ Span(base::DiscardableSharedMemory* shared_memory,
+ size_t start,
+ size_t length);
+
+ base::DiscardableSharedMemory* shared_memory_;
+ size_t start_;
+ size_t length_;
+
+ DISALLOW_COPY_AND_ASSIGN(Span);
+ };
+
+ explicit DiscardableSharedMemoryHeap(size_t block_size);
+ ~DiscardableSharedMemoryHeap();
+
+ // Grow heap using |shared_memory| and return a span for this new memory.
+ // |shared_memory| must be aligned to the block size and |size| must be a
+ // multiple of the block size. |deleted_callback| is called when
+ // |shared_memory| has been deleted.
+ scoped_ptr<Span> Grow(scoped_ptr<base::DiscardableSharedMemory> shared_memory,
+ size_t size,
+ int32_t id,
+ const base::Closure& deleted_callback);
+
+ // Merge |span| into the free lists. This will coalesce |span| with
+ // neighboring free spans when possible.
+ void MergeIntoFreeLists(scoped_ptr<Span> span);
+
+ // Split an allocated span into two spans, one of length |blocks| followed
+ // by another span of length "span->length - blocks" blocks. Modifies |span|
+ // to point to the first span of length |blocks|. Return second span.
+ scoped_ptr<Span> Split(Span* span, size_t blocks);
+
+ // Search free lists for span that satisfies the request for |blocks| of
+ // memory. If found, the span is removed from the free list and returned.
+ // |slack| determines the fitness requirement. Only spans that are less
+ // or equal to |blocks| + |slack| are considered, worse fitting spans are
+ // ignored.
+ scoped_ptr<Span> SearchFreeLists(size_t blocks, size_t slack);
+
+ // Release free shared memory segments.
+ void ReleaseFreeMemory();
+
+ // Release shared memory segments that have been purged.
+ void ReleasePurgedMemory();
+
+ // Returns total bytes of memory in heap.
+ size_t GetSize() const;
+
+ // Returns bytes of memory currently in the free lists.
+ size_t GetSizeOfFreeLists() const;
+
+ // Dumps memory statistics for chrome://tracing.
+ bool OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd);
+
+ private:
+ class ScopedMemorySegment {
+ public:
+ ScopedMemorySegment(DiscardableSharedMemoryHeap* heap,
+ scoped_ptr<base::DiscardableSharedMemory> shared_memory,
+ size_t size,
+ int32_t id,
+ const base::Closure& deleted_callback);
+ ~ScopedMemorySegment();
+
+ bool IsUsed() const;
+ bool IsResident() const;
+
+ // Used for dumping memory statistics from the segment to chrome://tracing.
+ void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd) const;
+
+ private:
+ DiscardableSharedMemoryHeap* const heap_;
+ scoped_ptr<base::DiscardableSharedMemory> shared_memory_;
+ const size_t size_;
+ const int32_t id_;
+ const base::Closure deleted_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedMemorySegment);
+ };
+
+ void InsertIntoFreeList(scoped_ptr<Span> span);
+ scoped_ptr<Span> RemoveFromFreeList(Span* span);
+ scoped_ptr<Span> Carve(Span* span, size_t blocks);
+ void RegisterSpan(Span* span);
+ void UnregisterSpan(Span* span);
+ bool IsMemoryUsed(const base::DiscardableSharedMemory* shared_memory,
+ size_t size);
+ bool IsMemoryResident(const base::DiscardableSharedMemory* shared_memory);
+ void ReleaseMemory(const base::DiscardableSharedMemory* shared_memory,
+ size_t size);
+
+ // Dumps memory statistics about a memory segment for chrome://tracing.
+ void OnMemoryDump(const base::DiscardableSharedMemory* shared_memory,
+ size_t size,
+ int32_t id,
+ base::trace_event::ProcessMemoryDump* pmd);
+
+ size_t block_size_;
+ size_t num_blocks_;
+ size_t num_free_blocks_;
+
+ // Vector of memory segments.
+ ScopedVector<ScopedMemorySegment> memory_segments_;
+
+ // Mapping from first/last block of span to Span instance.
+ typedef base::hash_map<size_t, Span*> SpanMap;
+ SpanMap spans_;
+
+ // Array of linked-lists with free discardable memory regions. For i < 256,
+ // where the 1st entry is located at index 0 of the array, the kth entry
+ // is a free list of runs that consist of k blocks. The 256th entry is a
+ // free list of runs that have length >= 256 blocks.
+ base::LinkedList<Span> free_spans_[256];
+
+ DISALLOW_COPY_AND_ASSIGN(DiscardableSharedMemoryHeap);
+};
+
+} // namespace content
+
+#endif // CONTENT_COMMON_DISCARDABLE_SHARED_MEMORY_HEAP_H_
diff --git a/chromium/content/common/discardable_shared_memory_heap_perftest.cc b/chromium/content/common/discardable_shared_memory_heap_perftest.cc
new file mode 100644
index 00000000000..dda5c633466
--- /dev/null
+++ b/chromium/content/common/discardable_shared_memory_heap_perftest.cc
@@ -0,0 +1,99 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/common/discardable_shared_memory_heap.h"
+
+#include <algorithm>
+#include <cmath>
+#include <cstdlib>
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/memory/discardable_shared_memory.h"
+#include "base/memory/scoped_vector.h"
+#include "base/process/process_metrics.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/perf/perf_test.h"
+
+namespace content {
+namespace {
+
+const int kTimeLimitMs = 2000;
+const int kTimeCheckInterval = 8192;
+
+void NullTask() {
+}
+
+TEST(DiscardableSharedMemoryHeapTest, SearchFreeLists) {
+ size_t block_size = base::GetPageSize();
+ DiscardableSharedMemoryHeap heap(block_size);
+
+ const size_t kBlocks = 4096;
+ const size_t kSegments = 16;
+ size_t segment_size = block_size * kBlocks;
+ int next_discardable_shared_memory_id = 0;
+
+ for (size_t i = 0; i < kSegments; ++i) {
+ scoped_ptr<base::DiscardableSharedMemory> memory(
+ new base::DiscardableSharedMemory);
+ ASSERT_TRUE(memory->CreateAndMap(segment_size));
+ heap.MergeIntoFreeLists(heap.Grow(memory.Pass(), segment_size,
+ next_discardable_shared_memory_id++,
+ base::Bind(NullTask)).Pass());
+ }
+
+ unsigned kSeed = 1;
+ // Use kSeed as seed for random number generator.
+ srand(kSeed);
+
+ // Pre-compute random values.
+ int random_span[kTimeCheckInterval];
+ size_t random_blocks[kTimeCheckInterval];
+ for (int i = 0; i < kTimeCheckInterval; ++i) {
+ random_span[i] = std::rand();
+ // Exponentially distributed block size.
+ const double kLambda = 2.0;
+ double v = static_cast<double>(std::rand()) / RAND_MAX;
+ random_blocks[i] = 1 + log(1.0 - v) / -kLambda * kBlocks;
+ }
+
+ ScopedVector<base::ScopedClosureRunner> spans;
+
+ base::TimeTicks start = base::TimeTicks::Now();
+ base::TimeTicks end = start + base::TimeDelta::FromMilliseconds(kTimeLimitMs);
+ base::TimeDelta accumulator;
+ int count = 0;
+ while (start < end) {
+ for (int i = 0; i < kTimeCheckInterval; ++i) {
+ // Search for a perfect fit if greater than kBlocks.
+ size_t slack =
+ random_blocks[i] < kBlocks ? kBlocks - random_blocks[i] : 0;
+ scoped_ptr<DiscardableSharedMemoryHeap::Span> span =
+ heap.SearchFreeLists(random_blocks[i], slack);
+ if (span) {
+ spans.push_back(new base::ScopedClosureRunner(
+ base::Bind(&DiscardableSharedMemoryHeap::MergeIntoFreeLists,
+ base::Unretained(&heap), base::Passed(&span))));
+ } else if (!spans.empty()) {
+ // Merge a random span back into the free list.
+ std::swap(spans[random_span[i] % spans.size()], spans.back());
+ spans.pop_back();
+ }
+
+ ++count;
+ }
+
+ base::TimeTicks now = base::TimeTicks::Now();
+ accumulator += now - start;
+ start = now;
+ }
+
+ spans.clear();
+
+ perf_test::PrintResult("search_free_list", "", "",
+ count / accumulator.InSecondsF(), "runs/s", true);
+}
+
+} // namespace
+} // namespace content
diff --git a/chromium/content/common/discardable_shared_memory_heap_unittest.cc b/chromium/content/common/discardable_shared_memory_heap_unittest.cc
new file mode 100644
index 00000000000..c80d2c2e4bf
--- /dev/null
+++ b/chromium/content/common/discardable_shared_memory_heap_unittest.cc
@@ -0,0 +1,306 @@
+// Copyright 2014 The Chromium Authors. 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/common/discardable_shared_memory_heap.h"
+
+#include "base/bind.h"
+#include "base/memory/discardable_shared_memory.h"
+#include "base/process/process_metrics.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+namespace {
+
+void NullTask() {
+}
+
+TEST(DiscardableSharedMemoryHeapTest, Basic) {
+ size_t block_size = base::GetPageSize();
+ DiscardableSharedMemoryHeap heap(block_size);
+
+ // Initial size should be 0.
+ EXPECT_EQ(0u, heap.GetSize());
+
+ // Initial size of free lists should be 0.
+ EXPECT_EQ(0u, heap.GetSizeOfFreeLists());
+
+ // Free lists are initially empty.
+ EXPECT_FALSE(heap.SearchFreeLists(1, 0));
+
+ const size_t kBlocks = 10;
+ size_t memory_size = block_size * kBlocks;
+ int next_discardable_shared_memory_id = 0;
+
+ scoped_ptr<base::DiscardableSharedMemory> memory(
+ new base::DiscardableSharedMemory);
+ ASSERT_TRUE(memory->CreateAndMap(memory_size));
+
+ // Create new span for memory.
+ scoped_ptr<DiscardableSharedMemoryHeap::Span> new_span(
+ heap.Grow(memory.Pass(), memory_size, next_discardable_shared_memory_id++,
+ base::Bind(NullTask)));
+
+ // Size should match |memory_size|.
+ EXPECT_EQ(memory_size, heap.GetSize());
+
+ // Size of free lists should still be 0.
+ EXPECT_EQ(0u, heap.GetSizeOfFreeLists());
+
+ // Free list should still be empty as |new_span| is currently in use.
+ EXPECT_FALSE(heap.SearchFreeLists(1, 0));
+
+ // Done using |new_span|. Merge it into the free lists.
+ heap.MergeIntoFreeLists(new_span.Pass());
+
+ // Size of free lists should now match |memory_size|.
+ EXPECT_EQ(memory_size, heap.GetSizeOfFreeLists());
+
+ // Free lists should not contain a span that is larger than kBlocks.
+ EXPECT_FALSE(heap.SearchFreeLists(kBlocks + 1, 0));
+
+ // Free lists should contain a span that satisfies the request for kBlocks.
+ scoped_ptr<DiscardableSharedMemoryHeap::Span> span =
+ heap.SearchFreeLists(kBlocks, 0);
+ ASSERT_TRUE(span);
+
+ // Free lists should be empty again.
+ EXPECT_FALSE(heap.SearchFreeLists(1, 0));
+
+ // Merge it into the free lists again.
+ heap.MergeIntoFreeLists(span.Pass());
+}
+
+TEST(DiscardableSharedMemoryHeapTest, SplitAndMerge) {
+ size_t block_size = base::GetPageSize();
+ DiscardableSharedMemoryHeap heap(block_size);
+
+ const size_t kBlocks = 6;
+ size_t memory_size = block_size * kBlocks;
+ int next_discardable_shared_memory_id = 0;
+
+ scoped_ptr<base::DiscardableSharedMemory> memory(
+ new base::DiscardableSharedMemory);
+ ASSERT_TRUE(memory->CreateAndMap(memory_size));
+ scoped_ptr<DiscardableSharedMemoryHeap::Span> new_span(
+ heap.Grow(memory.Pass(), memory_size, next_discardable_shared_memory_id++,
+ base::Bind(NullTask)));
+
+ // Split span into two.
+ scoped_ptr<DiscardableSharedMemoryHeap::Span> leftover =
+ heap.Split(new_span.get(), 3);
+ ASSERT_TRUE(leftover);
+
+ // Merge |leftover| into free lists.
+ heap.MergeIntoFreeLists(leftover.Pass());
+
+ // Some of the memory is still in use.
+ EXPECT_FALSE(heap.SearchFreeLists(kBlocks, 0));
+
+ // Merge |span| into free lists.
+ heap.MergeIntoFreeLists(new_span.Pass());
+
+ // Remove a 2 page span from free lists.
+ scoped_ptr<DiscardableSharedMemoryHeap::Span> span1 =
+ heap.SearchFreeLists(2, kBlocks);
+ ASSERT_TRUE(span1);
+
+ // Remove another 2 page span from free lists.
+ scoped_ptr<DiscardableSharedMemoryHeap::Span> span2 =
+ heap.SearchFreeLists(2, kBlocks);
+ ASSERT_TRUE(span2);
+
+ // Merge |span1| back into free lists.
+ heap.MergeIntoFreeLists(span1.Pass());
+
+ // Some of the memory is still in use.
+ EXPECT_FALSE(heap.SearchFreeLists(kBlocks, 0));
+
+ // Merge |span2| back into free lists.
+ heap.MergeIntoFreeLists(span2.Pass());
+
+ // All memory has been returned to the free lists.
+ scoped_ptr<DiscardableSharedMemoryHeap::Span> large_span =
+ heap.SearchFreeLists(kBlocks, 0);
+ ASSERT_TRUE(large_span);
+
+ // Merge it into the free lists again.
+ heap.MergeIntoFreeLists(large_span.Pass());
+}
+
+TEST(DiscardableSharedMemoryHeapTest, MergeSingleBlockSpan) {
+ size_t block_size = base::GetPageSize();
+ DiscardableSharedMemoryHeap heap(block_size);
+
+ const size_t kBlocks = 6;
+ size_t memory_size = block_size * kBlocks;
+ int next_discardable_shared_memory_id = 0;
+
+ scoped_ptr<base::DiscardableSharedMemory> memory(
+ new base::DiscardableSharedMemory);
+ ASSERT_TRUE(memory->CreateAndMap(memory_size));
+ scoped_ptr<DiscardableSharedMemoryHeap::Span> new_span(
+ heap.Grow(memory.Pass(), memory_size, next_discardable_shared_memory_id++,
+ base::Bind(NullTask)));
+
+ // Split span into two.
+ scoped_ptr<DiscardableSharedMemoryHeap::Span> leftover =
+ heap.Split(new_span.get(), 5);
+ ASSERT_TRUE(leftover);
+
+ // Merge |new_span| into free lists.
+ heap.MergeIntoFreeLists(new_span.Pass());
+
+ // Merge |leftover| into free lists.
+ heap.MergeIntoFreeLists(leftover.Pass());
+}
+
+TEST(DiscardableSharedMemoryHeapTest, Grow) {
+ size_t block_size = base::GetPageSize();
+ DiscardableSharedMemoryHeap heap(block_size);
+ int next_discardable_shared_memory_id = 0;
+
+ scoped_ptr<base::DiscardableSharedMemory> memory1(
+ new base::DiscardableSharedMemory);
+ ASSERT_TRUE(memory1->CreateAndMap(block_size));
+ heap.MergeIntoFreeLists(heap.Grow(memory1.Pass(), block_size,
+ next_discardable_shared_memory_id++,
+ base::Bind(NullTask)).Pass());
+
+ // Remove a span from free lists.
+ scoped_ptr<DiscardableSharedMemoryHeap::Span> span1 =
+ heap.SearchFreeLists(1, 0);
+ EXPECT_TRUE(span1);
+
+ // No more memory available.
+ EXPECT_FALSE(heap.SearchFreeLists(1, 0));
+
+ // Grow free lists using new memory.
+ scoped_ptr<base::DiscardableSharedMemory> memory2(
+ new base::DiscardableSharedMemory);
+ ASSERT_TRUE(memory2->CreateAndMap(block_size));
+ heap.MergeIntoFreeLists(heap.Grow(memory2.Pass(), block_size,
+ next_discardable_shared_memory_id++,
+ base::Bind(NullTask)).Pass());
+
+ // Memory should now be available.
+ scoped_ptr<DiscardableSharedMemoryHeap::Span> span2 =
+ heap.SearchFreeLists(1, 0);
+ EXPECT_TRUE(span2);
+
+ // Merge spans into the free lists again.
+ heap.MergeIntoFreeLists(span1.Pass());
+ heap.MergeIntoFreeLists(span2.Pass());
+}
+
+TEST(DiscardableSharedMemoryHeapTest, ReleaseFreeMemory) {
+ size_t block_size = base::GetPageSize();
+ DiscardableSharedMemoryHeap heap(block_size);
+ int next_discardable_shared_memory_id = 0;
+
+ scoped_ptr<base::DiscardableSharedMemory> memory(
+ new base::DiscardableSharedMemory);
+ ASSERT_TRUE(memory->CreateAndMap(block_size));
+ scoped_ptr<DiscardableSharedMemoryHeap::Span> span =
+ heap.Grow(memory.Pass(), block_size, next_discardable_shared_memory_id++,
+ base::Bind(NullTask));
+
+ // Free lists should be empty.
+ EXPECT_EQ(0u, heap.GetSizeOfFreeLists());
+
+ heap.ReleaseFreeMemory();
+
+ // Size should still match |block_size|.
+ EXPECT_EQ(block_size, heap.GetSize());
+
+ heap.MergeIntoFreeLists(span.Pass());
+ heap.ReleaseFreeMemory();
+
+ // Memory should have been released.
+ EXPECT_EQ(0u, heap.GetSize());
+ EXPECT_EQ(0u, heap.GetSizeOfFreeLists());
+}
+
+TEST(DiscardableSharedMemoryHeapTest, ReleasePurgedMemory) {
+ size_t block_size = base::GetPageSize();
+ DiscardableSharedMemoryHeap heap(block_size);
+ int next_discardable_shared_memory_id = 0;
+
+ scoped_ptr<base::DiscardableSharedMemory> memory(
+ new base::DiscardableSharedMemory);
+ ASSERT_TRUE(memory->CreateAndMap(block_size));
+ scoped_ptr<DiscardableSharedMemoryHeap::Span> span =
+ heap.Grow(memory.Pass(), block_size, next_discardable_shared_memory_id++,
+ base::Bind(NullTask));
+
+ // Unlock memory so it can be purged.
+ span->shared_memory()->Unlock(0, 0);
+
+ // Purge and release shared memory.
+ bool rv = span->shared_memory()->Purge(base::Time::Now());
+ EXPECT_TRUE(rv);
+ heap.ReleasePurgedMemory();
+
+ // Shared memory backing for |span| should be gone.
+ EXPECT_FALSE(span->shared_memory());
+
+ // Size should be 0.
+ EXPECT_EQ(0u, heap.GetSize());
+}
+
+TEST(DiscardableSharedMemoryHeapTest, Slack) {
+ size_t block_size = base::GetPageSize();
+ DiscardableSharedMemoryHeap heap(block_size);
+
+ const size_t kBlocks = 6;
+ size_t memory_size = block_size * kBlocks;
+ int next_discardable_shared_memory_id = 0;
+
+ scoped_ptr<base::DiscardableSharedMemory> memory(
+ new base::DiscardableSharedMemory);
+ ASSERT_TRUE(memory->CreateAndMap(memory_size));
+ heap.MergeIntoFreeLists(heap.Grow(memory.Pass(), memory_size,
+ next_discardable_shared_memory_id++,
+ base::Bind(NullTask)).Pass());
+
+ // No free span that is less or equal to 3 + 1.
+ EXPECT_FALSE(heap.SearchFreeLists(3, 1));
+
+ // No free span that is less or equal to 3 + 2.
+ EXPECT_FALSE(heap.SearchFreeLists(3, 2));
+
+ // No free span that is less or equal to 1 + 4.
+ EXPECT_FALSE(heap.SearchFreeLists(1, 4));
+
+ scoped_ptr<DiscardableSharedMemoryHeap::Span> span =
+ heap.SearchFreeLists(1, 5);
+ EXPECT_TRUE(span);
+
+ heap.MergeIntoFreeLists(span.Pass());
+}
+
+void OnDeleted(bool* deleted) {
+ *deleted = true;
+}
+
+TEST(DiscardableSharedMemoryHeapTest, DeletedCallback) {
+ size_t block_size = base::GetPageSize();
+ DiscardableSharedMemoryHeap heap(block_size);
+ int next_discardable_shared_memory_id = 0;
+
+ scoped_ptr<base::DiscardableSharedMemory> memory(
+ new base::DiscardableSharedMemory);
+ ASSERT_TRUE(memory->CreateAndMap(block_size));
+ bool deleted = false;
+ scoped_ptr<DiscardableSharedMemoryHeap::Span> span =
+ heap.Grow(memory.Pass(), block_size, next_discardable_shared_memory_id++,
+ base::Bind(OnDeleted, base::Unretained(&deleted)));
+
+ heap.MergeIntoFreeLists(span.Pass());
+ heap.ReleaseFreeMemory();
+
+ EXPECT_TRUE(deleted);
+}
+
+} // namespace
+} // namespace content
diff --git a/chromium/content/common/dom_storage/dom_storage_map.cc b/chromium/content/common/dom_storage/dom_storage_map.cc
index de33a52e89a..71368bdd550 100644
--- a/chromium/content/common/dom_storage/dom_storage_map.cc
+++ b/chromium/content/common/dom_storage/dom_storage_map.cc
@@ -14,17 +14,6 @@ size_t size_of_item(const base::string16& key, const base::string16& value) {
return (key.length() + value.length()) * sizeof(base::char16);
}
-size_t CountBytes(const DOMStorageValuesMap& values) {
- if (values.size() == 0)
- return 0;
-
- size_t count = 0;
- DOMStorageValuesMap::const_iterator it = values.begin();
- for (; it != values.end(); ++it)
- count += size_of_item(it->first, it->second.string());
- return count;
-}
-
} // namespace
DOMStorageMap::DOMStorageMap(size_t quota)
@@ -119,4 +108,14 @@ void DOMStorageMap::ResetKeyIterator() {
last_key_index_ = 0;
}
+size_t DOMStorageMap::CountBytes(const DOMStorageValuesMap& values) {
+ if (values.empty())
+ return 0;
+
+ size_t count = 0;
+ for (const auto& pair : values)
+ count += size_of_item(pair.first, pair.second.string());
+ return count;
+}
+
} // namespace content
diff --git a/chromium/content/common/dom_storage/dom_storage_map.h b/chromium/content/common/dom_storage/dom_storage_map.h
index 140de07817a..7130d27a5c9 100644
--- a/chromium/content/common/dom_storage/dom_storage_map.h
+++ b/chromium/content/common/dom_storage/dom_storage_map.h
@@ -46,6 +46,8 @@ class CONTENT_EXPORT DOMStorageMap
size_t quota() const { return quota_; }
void set_quota(size_t quota) { quota_ = quota; }
+ static size_t CountBytes(const DOMStorageValuesMap& values);
+
private:
friend class base::RefCountedThreadSafe<DOMStorageMap>;
~DOMStorageMap();
diff --git a/chromium/content/common/dom_storage/dom_storage_messages.h b/chromium/content/common/dom_storage/dom_storage_messages.h
index 759dd20358d..95ccf229f7f 100644
--- a/chromium/content/common/dom_storage/dom_storage_messages.h
+++ b/chromium/content/common/dom_storage/dom_storage_messages.h
@@ -53,11 +53,6 @@ IPC_MESSAGE_CONTROL1(DOMStorageMsg_Event,
IPC_MESSAGE_CONTROL1(DOMStorageMsg_AsyncOperationComplete,
bool /* success */)
-// Notification instructing the renderer to refresh all cached values for
-// the given namespace.
-IPC_MESSAGE_CONTROL1(DOMStorageMsg_ResetCachedValues,
- int64 /* namespace_id */)
-
// DOM Storage messages sent from the renderer to the browser.
// Note: The 'connection_id' must be the first parameter in these message.
@@ -73,12 +68,9 @@ IPC_MESSAGE_CONTROL1(DOMStorageHostMsg_CloseStorageArea,
// Retrieves the set of key/value pairs for the area. Used to prime
// the renderer-side cache. A completion notification is sent in response.
-// The response will also indicate whether the renderer should send
-// messagse to the browser for get operations for logging purposes.
-IPC_SYNC_MESSAGE_CONTROL1_2(DOMStorageHostMsg_LoadStorageArea,
+IPC_SYNC_MESSAGE_CONTROL1_1(DOMStorageHostMsg_LoadStorageArea,
int /* connection_id */,
- content::DOMStorageValuesMap,
- bool /* send_log_get_messages */)
+ content::DOMStorageValuesMap)
// Set a value that's associated with a key in a storage area.
// A completion notification is sent in response.
@@ -88,12 +80,6 @@ IPC_MESSAGE_CONTROL4(DOMStorageHostMsg_SetItem,
base::string16 /* value */,
GURL /* page_url */)
-// Logs that a get operation was performed on a key/value pair.
-IPC_MESSAGE_CONTROL3(DOMStorageHostMsg_LogGetItem,
- int /* connection_id */,
- base::string16 /* key */,
- base::NullableString16 /* value */)
-
// Remove the value associated with a key in a storage area.
// A completion notification is sent in response.
IPC_MESSAGE_CONTROL3(DOMStorageHostMsg_RemoveItem,
diff --git a/chromium/content/common/drag_event_source_info.h b/chromium/content/common/drag_event_source_info.h
index 59a6f7c16df..b5177eed6a8 100644
--- a/chromium/content/common/drag_event_source_info.h
+++ b/chromium/content/common/drag_event_source_info.h
@@ -7,7 +7,7 @@
#include "content/common/content_export.h"
#include "ui/base/dragdrop/drag_drop_types.h"
-#include "ui/gfx/point.h"
+#include "ui/gfx/geometry/point.h"
namespace content {
diff --git a/chromium/content/common/drag_messages.h b/chromium/content/common/drag_messages.h
index 6f378a89e86..3db2428c6b5 100644
--- a/chromium/content/common/drag_messages.h
+++ b/chromium/content/common/drag_messages.h
@@ -9,10 +9,10 @@
#include "content/public/common/common_param_traits.h"
#include "content/public/common/drop_data.h"
#include "ipc/ipc_message_macros.h"
-#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/WebKit/public/web/WebDragOperation.h"
-#include "ui/gfx/point.h"
-#include "ui/gfx/vector2d.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/vector2d.h"
#define IPC_MESSAGE_START DragMsgStart
diff --git a/chromium/content/common/drag_traits.h b/chromium/content/common/drag_traits.h
index fa8d358f763..e07e5a052a3 100644
--- a/chromium/content/common/drag_traits.h
+++ b/chromium/content/common/drag_traits.h
@@ -7,7 +7,7 @@
#include "content/public/common/drop_data.h"
#include "ipc/ipc_message_macros.h"
#include "third_party/WebKit/public/web/WebDragOperation.h"
-#include "ui/gfx/point.h"
+#include "ui/gfx/geometry/point.h"
#define IPC_MESSAGE_START DragMsgStart
diff --git a/chromium/content/common/dwrite_font_platform_win.cc b/chromium/content/common/dwrite_font_platform_win.cc
new file mode 100644
index 00000000000..e312651ca71
--- /dev/null
+++ b/chromium/content/common/dwrite_font_platform_win.cc
@@ -0,0 +1,1229 @@
+// Copyright 2014 The Chromium Authors. 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/common/dwrite_font_platform_win.h"
+
+#include <dwrite.h>
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+#include <wrl/implements.h>
+#include <wrl/wrappers/corewrappers.h>
+
+#include "base/command_line.h"
+#include "base/debug/alias.h"
+#include "base/debug/crash_logging.h"
+#include "base/files/file_enumerator.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/memory_mapped_file.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/memory/shared_memory.h"
+#include "base/metrics/histogram.h"
+#include "base/path_service.h"
+#include "base/process/process_handle.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/synchronization/lock.h"
+#include "base/time/time.h"
+#include "base/win/registry.h"
+#include "base/win/scoped_comptr.h"
+#include "content/public/common/content_switches.h"
+
+namespace {
+
+// Font Cache implementation short story:
+// Due to our sandboxing restrictions, we cannot connect to Windows font cache
+// service from Renderer and need to use DirectWrite isolated font loading
+// mechanism.
+// DirectWrite needs to be initialized before any of the API could be used.
+// During initialization DirectWrite loads all font files and populates
+// internal cache, we refer this phase as enumeration and we are trying
+// to optimize this phase in our cache approach. Using cache during
+// initialization will help improve on startup latency in each renderer
+// instance.
+// During enumeration DirectWrite reads various fragments from .ttf/.ttc
+// font files. Our assumption is that these fragments are being read to
+// cache information such as font families, supported sizes etc.
+// For reading fragments DirectWrite calls ReadFragment of our FontFileStream
+// implementation with parameters start_offset and length. We cache these
+// parameters along with associated data chunk.
+// Here is small example of how segments are read
+// start_offset: 0, length: 16
+// start_offset: 0, length: 12
+// start_offset: 0, length: 117
+// For better cache management we collapse segments if they overlap or are
+// adjacent.
+
+namespace mswr = Microsoft::WRL;
+
+const char kFontKeyName[] = "font_key_name";
+
+// We use this value to determine whether to cache file fragments
+// or not. In our trials we observed that for some font files
+// direct write ends up reading almost entire file during enumeration
+// phase. If we don't use this percentile formula we will end up
+// increasing significant cache size by caching entire file contents
+// for some of the font files.
+const double kMaxPercentileOfFontFileSizeToCache = 0.6;
+
+// With current implementation we map entire shared section into memory during
+// renderer startup. This causes increase in working set of Chrome. As first
+// step we want to see if caching is really improving any performance for our
+// users, so we are putting arbitrary limit on cache file size. There are
+// multiple ways we can tune our working size, like mapping only required part
+// of section at any given time.
+const double kArbitraryCacheFileSizeLimit = (30 * 1024 * 1024);
+
+// We have chosen current font file length arbitrarily. In our logic
+// if we don't find file we are looking for in cache we end up loading
+// that file directly from system fonts folder.
+const unsigned int kMaxFontFileNameLength = 34;
+
+const DWORD kCacheFileVersion = 103;
+const DWORD kFileSignature = 0x4D4F5243; // CROM
+const DWORD kMagicCompletionSignature = 0x454E4F44; // DONE
+
+const DWORD kUndefinedDWORDS = 36;
+
+// Make sure that all structure sizes align with 8 byte boundary otherwise
+// dr. memory test may complain.
+#pragma pack(push, 8)
+// Cache file header, includes signature, completion bits and version.
+struct CacheFileHeader {
+ CacheFileHeader() {
+ file_signature = kFileSignature;
+ magic_completion_signature = 0;
+ version = kCacheFileVersion;
+ ::ZeroMemory(undefined, sizeof(undefined));
+ }
+
+ DWORD file_signature;
+ DWORD magic_completion_signature;
+ DWORD version;
+ BYTE undefined[kUndefinedDWORDS];
+};
+
+// Entry for a particular font file within this cache.
+struct CacheFileEntry {
+ CacheFileEntry() {
+ file_size = 0;
+ entry_count = 0;
+ ::ZeroMemory(file_name, sizeof(file_name));
+ }
+
+ UINT64 file_size;
+ DWORD entry_count;
+ wchar_t file_name[kMaxFontFileNameLength];
+};
+
+// Offsets or data chunks that are cached for particular font file.
+struct CacheFileOffsetEntry {
+ CacheFileOffsetEntry() {
+ start_offset = 0;
+ length = 0;
+ }
+
+ UINT64 start_offset;
+ UINT64 length;
+ /* BYTE blob_[]; // Place holder for the blob that follows. */
+};
+#pragma pack(pop)
+
+bool ValidateFontCacheHeader(CacheFileHeader* header) {
+ return (header->file_signature == kFileSignature &&
+ header->magic_completion_signature == kMagicCompletionSignature &&
+ header->version == kCacheFileVersion);
+}
+
+class FontCacheWriter;
+
+// This class implements main interface required for loading custom font
+// collection as specified by DirectWrite. We also use this class for storing
+// some state information as this is one of the centralized entity.
+class FontCollectionLoader
+ : public mswr::RuntimeClass<mswr::RuntimeClassFlags<mswr::ClassicCom>,
+ IDWriteFontCollectionLoader> {
+ public:
+ FontCollectionLoader()
+ : in_collection_building_mode_(false),
+ create_static_cache_(false) {}
+
+ ~FontCollectionLoader() override;
+
+ HRESULT RuntimeClassInitialize() {
+ return S_OK;
+ }
+
+ // IDWriteFontCollectionLoader methods.
+ HRESULT STDMETHODCALLTYPE
+ CreateEnumeratorFromKey(IDWriteFactory* factory,
+ void const* key,
+ UINT32 key_size,
+ IDWriteFontFileEnumerator** file_enumerator) override;
+
+ // Does all the initialization for required loading fonts from registry.
+ static HRESULT Initialize(IDWriteFactory* factory);
+
+ // Returns font cache map size.
+ UINT32 GetFontMapSize();
+
+ // Returns font name string when given font index.
+ base::string16 GetFontNameFromKey(UINT32 idx);
+
+ // Loads internal structure with fonts from registry.
+ bool LoadFontListFromRegistry();
+
+ // Loads restricted web safe fonts as fallback method to registry fonts.
+ bool LoadRestrictedFontList();
+
+ // Puts class in collection building mode. In collection building mode
+ // we use static cache if it is available as a look aside buffer.
+ void EnableCollectionBuildingMode(bool enable);
+
+ // Returns current state of collection building.
+ bool InCollectionBuildingMode();
+
+ // Loads static cache file.
+ bool LoadCacheFile();
+
+ // Puts class in static cache creating mode. In this mode we record all
+ // direct write requests and store chunks of font data.
+ void EnterStaticCacheMode(const WCHAR* file_name);
+
+ // Gets out of static cache building mode.
+ void LeaveStaticCacheMode();
+
+ // Returns if class is currently in static cache building mode.
+ bool IsBuildStaticCacheMode();
+
+ // Validates cache file for consistency.
+ bool ValidateCacheFile(base::File* file);
+
+ private:
+ // Structure to represent each chunk within font file that we load in memory.
+ struct CacheTableOffsetEntry {
+ UINT64 start_offset;
+ UINT64 length;
+ BYTE* inside_file_ptr;
+ };
+
+ typedef std::vector<CacheTableOffsetEntry> OffsetVector;
+
+ // Structure representing each font entry with cache.
+ struct CacheTableEntry {
+ UINT64 file_size;
+ OffsetVector offset_entries;
+ };
+
+ public:
+ // Returns whether file we have particular font entry within cache or not.
+ bool IsFileCached(UINT32 font_key);
+ // Returns cache fragment corresponding to specific font key.
+ void* GetCachedFragment(UINT32 font_key, UINT64 start_offset, UINT64 length);
+ // Returns actual font file size at the time of caching.
+ UINT64 GetCachedFileSize(UINT32 font_key);
+
+ // Returns instance of font cache writer. This class manages actual font
+ // file format.
+ FontCacheWriter* GetFontCacheWriter();
+
+ private:
+ // Functions validates and loads cache into internal map.
+ bool ValidateAndLoadCacheMap();
+
+ mswr::ComPtr<IDWriteFontFileLoader> file_loader_;
+
+ std::vector<base::string16> reg_fonts_;
+ bool in_collection_building_mode_;
+ bool create_static_cache_;
+ scoped_ptr<base::SharedMemory> cache_;
+ scoped_ptr<FontCacheWriter> cache_writer_;
+
+ typedef std::map<base::string16, CacheTableEntry*> CacheMap;
+ CacheMap cache_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(FontCollectionLoader);
+};
+
+mswr::ComPtr<FontCollectionLoader> g_font_loader;
+base::win::ScopedHandle g_shared_font_cache;
+
+// Class responsible for handling font cache file format details as well as
+// tracking various cache region requests by direct write.
+class FontCacheWriter {
+ public:
+ FontCacheWriter()
+ : cookie_counter_(0),
+ count_font_entries_ignored_(0) {
+ }
+
+ ~FontCacheWriter() {
+ if (static_cache_.get()) {
+ static_cache_->Close();
+ }
+ }
+
+ public:
+ // Holds data related to individual region as requested by direct write.
+ struct CacheRegion {
+ UINT64 start_offset;
+ UINT64 length;
+ const BYTE* ptr;
+ /* BYTE blob_[]; // Place holder for the blob that follows. */
+ };
+
+ // Function to create static font cache file.
+ bool Create(const wchar_t* file_name) {
+ static_cache_.reset(new base::File(base::FilePath(file_name),
+ base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_WRITE |
+ base::File::FLAG_EXCLUSIVE_WRITE));
+ if (!static_cache_->IsValid()) {
+ static_cache_.reset();
+ return false;
+ }
+ CacheFileHeader header;
+
+ // At offset 0 write cache version
+ static_cache_->Write(0,
+ reinterpret_cast<const char*>(&header),
+ sizeof(header));
+
+ static_cache_->Flush();
+ return true;
+ }
+
+ // Closes static font cache file. Also writes completion signature to mark
+ // it as completely written.
+ void Close() {
+ if (static_cache_.get()) {
+ CacheFileHeader header;
+ header.magic_completion_signature = kMagicCompletionSignature;
+ // At offset 0 write cache version
+ int bytes_written = static_cache_->Write(0,
+ reinterpret_cast<const char*>(&header),
+ sizeof(header));
+ DCHECK_NE(bytes_written, -1);
+
+ UMA_HISTOGRAM_MEMORY_KB("DirectWrite.Fonts.BuildCache.File.Size",
+ static_cache_->GetLength() / 1024);
+
+ UMA_HISTOGRAM_COUNTS("DirectWrite.Fonts.BuildCache.Ignored",
+ count_font_entries_ignored_);
+
+ static_cache_->Close();
+ static_cache_.reset(NULL);
+ }
+ }
+
+ private:
+ typedef std::vector<CacheRegion> RegionVector;
+
+ // Structure to track various regions requested by direct write for particular
+ // font file.
+ struct FontEntryInternal {
+ FontEntryInternal(const wchar_t* name, UINT64 size)
+ : file_name(name),
+ file_size(size) {
+ }
+
+ base::string16 file_name;
+ UINT64 file_size;
+ RegionVector regions;
+ };
+
+ public:
+ // Starts up new font entry to be tracked, returns cookie to identify this
+ // particular entry.
+ UINT NewFontEntry(const wchar_t* file_name, UINT64 file_size) {
+ base::AutoLock lock(lock_);
+ UINT old_counter = cookie_counter_;
+ FontEntryInternal* font_entry = new FontEntryInternal(file_name, file_size);
+ cookie_map_[cookie_counter_].reset(font_entry);
+ cookie_counter_++;
+ return old_counter;
+ }
+
+ // AddRegion function lets caller add various regions to be cached for
+ // particular font file. Once enumerating that particular font file is done
+ // (based on uniquely identifying cookie) changes could be committed using
+ // CommitFontEntry
+ bool AddRegion(UINT64 cookie, UINT64 start, UINT64 length, const BYTE* ptr) {
+ base::AutoLock lock(lock_);
+ if (cookie_map_.find(cookie) == cookie_map_.end())
+ return false;
+ RegionVector& regions = cookie_map_[cookie].get()->regions;
+ CacheRegion region;
+ region.start_offset = start;
+ region.length = length;
+ region.ptr = ptr;
+ regions.push_back(region);
+ return true;
+ }
+
+ // Function which commits after merging all collected regions into cache file.
+ bool CommitFontEntry(UINT cookie) {
+ base::AutoLock lock(lock_);
+ if (cookie_map_.find(cookie) == cookie_map_.end())
+ return false;
+
+ // We will skip writing entries beyond allowed limit. Following condition
+ // doesn't enforce hard file size. We need to write complete font entry.
+ int64 length = static_cache_->GetLength();
+ if (length == -1 || length >= kArbitraryCacheFileSizeLimit) {
+ count_font_entries_ignored_++;
+ return false;
+ }
+
+ FontEntryInternal* font_entry = cookie_map_[cookie].get();
+ RegionVector& regions = font_entry->regions;
+ std::sort(regions.begin(), regions.end(), SortCacheRegions);
+
+ // At this point, we have collected all regions to be cached. These regions
+ // are tuples of start, length, data for particular data segment.
+ // These tuples can overlap.
+ // e.g. (0, 12, data), (0, 117, data), (21, 314, data), (335, 15, data)
+ // In this case as you can see first three segments overlap and
+ // 4th is adjacent. If we cache them individually then we will end up
+ // caching duplicate data, so we merge these segments together to find
+ // superset for the cache. In above example our algorithm should
+ // produce (cache) single segment starting at offset 0 with length 350.
+ RegionVector merged_regions;
+ RegionVector::iterator iter;
+ int idx = 0;
+ for (iter = regions.begin(); iter != regions.end(); iter++) {
+ if (iter == regions.begin()) {
+ merged_regions.push_back(*iter);
+ continue;
+ }
+ CacheRegion& base_region = merged_regions[idx];
+ if (IsOverlap(&base_region, &(*iter))) {
+ UINT64 end1 = base_region.start_offset + base_region.length;
+ UINT64 end2 = iter->start_offset + iter->length;
+ if (base_region.start_offset > iter->start_offset) {
+ base_region.start_offset = iter->start_offset;
+ base_region.ptr = iter->ptr;
+ }
+ base_region.length = std::max(end1, end2) - base_region.start_offset;
+ } else {
+ merged_regions.push_back(*iter);
+ idx++;
+ }
+ }
+
+ UINT64 total_merged_cache_in_bytes = 0;
+ for (iter = merged_regions.begin(); iter != merged_regions.end(); iter++) {
+ total_merged_cache_in_bytes += iter->length;
+ }
+
+ // We want to adjust following parameter based on experiments. But general
+ // logic here is that if we are going to end up caching most of the contents
+ // for a file (e.g. simsunb.ttf > 90%) then we should avoid caching that
+ // file.
+ double percentile = static_cast<double>(total_merged_cache_in_bytes) /
+ font_entry->file_size;
+ if (percentile > kMaxPercentileOfFontFileSizeToCache) {
+ count_font_entries_ignored_++;
+ return false;
+ }
+
+ CacheFileEntry entry;
+ wcsncpy_s(entry.file_name, kMaxFontFileNameLength,
+ font_entry->file_name.c_str(), _TRUNCATE);
+ entry.file_size = font_entry->file_size;
+ entry.entry_count = merged_regions.size();
+ static_cache_->WriteAtCurrentPos(
+ reinterpret_cast<const char*>(&entry),
+ sizeof(entry));
+ for (iter = merged_regions.begin(); iter != merged_regions.end(); iter++) {
+ CacheFileOffsetEntry offset_entry;
+ offset_entry.start_offset = iter->start_offset;
+ offset_entry.length = iter->length;
+ static_cache_->WriteAtCurrentPos(
+ reinterpret_cast<const char*>(&offset_entry),
+ sizeof(offset_entry));
+ static_cache_->WriteAtCurrentPos(
+ reinterpret_cast<const char*>(iter->ptr),
+ iter->length);
+ }
+ return true;
+ }
+
+ private:
+ // This is the count of font entries that we reject based on size to be
+ // cached.
+ unsigned int count_font_entries_ignored_;
+ scoped_ptr<base::File> static_cache_;
+ std::map<UINT, scoped_ptr<FontEntryInternal>> cookie_map_;
+ UINT cookie_counter_;
+
+ // Lock is required to protect internal data structures and access to file,
+ // According to MSDN documentation on ReadFileFragment and based on our
+ // experiments so far, there is possibility of ReadFileFragment getting called
+ // from multiple threads.
+ base::Lock lock_;
+
+ // Function checks if two regions overlap or are adjacent.
+ bool IsOverlap(CacheRegion* region1, CacheRegion* region2) {
+ return
+ !((region1->start_offset + region1->length) < region2->start_offset ||
+ region1->start_offset > (region2->start_offset + region2->length));
+ }
+
+ // Function to sort cached regions.
+ static bool SortCacheRegions(const CacheRegion& region1,
+ const CacheRegion& region2) {
+ return
+ region1.start_offset == region2.start_offset ?
+ region1.length < region2.length :
+ region1.start_offset < region2.start_offset;
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(FontCacheWriter);
+};
+
+// Class implements IDWriteFontFileStream interface as required by direct write.
+class FontFileStream
+ : public mswr::RuntimeClass<mswr::RuntimeClassFlags<mswr::ClassicCom>,
+ IDWriteFontFileStream> {
+ public:
+ // IDWriteFontFileStream methods.
+ HRESULT STDMETHODCALLTYPE ReadFileFragment(
+ void const** fragment_start,
+ UINT64 file_offset,
+ UINT64 fragment_size,
+ void** context) override {
+ if (cached_data_) {
+ *fragment_start = g_font_loader->GetCachedFragment(font_key_,
+ file_offset,
+ fragment_size);
+ if (*fragment_start == NULL) {
+ DCHECK(false);
+ }
+ *context = NULL;
+ return *fragment_start != NULL ? S_OK : E_FAIL;
+ }
+ if (!memory_.get() || !memory_->IsValid() ||
+ file_offset >= memory_->length() ||
+ (file_offset + fragment_size) > memory_->length())
+ return E_FAIL;
+
+ *fragment_start = static_cast<BYTE const*>(memory_->data()) +
+ static_cast<size_t>(file_offset);
+ *context = NULL;
+ if (g_font_loader->IsBuildStaticCacheMode()) {
+ FontCacheWriter* cache_writer = g_font_loader->GetFontCacheWriter();
+ cache_writer->AddRegion(writer_cookie_,
+ file_offset,
+ fragment_size,
+ static_cast<const BYTE*>(*fragment_start));
+ }
+ return S_OK;
+ }
+
+ void STDMETHODCALLTYPE ReleaseFileFragment(void* context) override {}
+
+ HRESULT STDMETHODCALLTYPE GetFileSize(UINT64* file_size) override {
+ if (cached_data_) {
+ *file_size = g_font_loader->GetCachedFileSize(font_key_);
+ return S_OK;
+ }
+
+ if (!memory_.get() || !memory_->IsValid())
+ return E_FAIL;
+
+ *file_size = memory_->length();
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE GetLastWriteTime(UINT64* last_write_time) override {
+ if (cached_data_) {
+ *last_write_time = 0;
+ return S_OK;
+ }
+
+ if (!memory_.get() || !memory_->IsValid())
+ return E_FAIL;
+
+ // According to MSDN article http://goo.gl/rrSYzi the "last modified time"
+ // is used by DirectWrite font selection algorithms to determine whether
+ // one font resource is more up to date than another one.
+ // So by returning 0 we are assuming that it will treat all fonts to be
+ // equally up to date.
+ // TODO(shrikant): We should further investigate this.
+ *last_write_time = 0;
+ return S_OK;
+ }
+
+ FontFileStream::FontFileStream() : font_key_(0), cached_data_(false) {
+ }
+
+ HRESULT RuntimeClassInitialize(UINT32 font_key) {
+ if (g_font_loader->InCollectionBuildingMode() &&
+ g_font_loader->IsFileCached(font_key)) {
+ cached_data_ = true;
+ font_key_ = font_key;
+ return S_OK;
+ }
+
+ base::FilePath path;
+ PathService::Get(base::DIR_WINDOWS_FONTS, &path);
+ base::string16 font_key_name(g_font_loader->GetFontNameFromKey(font_key));
+ path = path.Append(font_key_name.c_str());
+ memory_.reset(new base::MemoryMappedFile());
+
+ // Put some debug information on stack.
+ WCHAR font_name[MAX_PATH];
+ path.value().copy(font_name, arraysize(font_name));
+ base::debug::Alias(font_name);
+
+ if (!memory_->Initialize(path)) {
+ memory_.reset();
+ return E_FAIL;
+ }
+
+ font_key_ = font_key;
+
+ base::debug::SetCrashKeyValue(kFontKeyName,
+ base::WideToUTF8(font_key_name));
+
+ if (g_font_loader->IsBuildStaticCacheMode()) {
+ FontCacheWriter* cache_writer = g_font_loader->GetFontCacheWriter();
+ writer_cookie_ = cache_writer->NewFontEntry(font_key_name.c_str(),
+ memory_->length());
+ }
+ return S_OK;
+ }
+
+ ~FontFileStream() override {
+ if (g_font_loader->IsBuildStaticCacheMode()) {
+ FontCacheWriter* cache_writer = g_font_loader->GetFontCacheWriter();
+ cache_writer->CommitFontEntry(writer_cookie_);
+ }
+ }
+
+ private:
+ UINT32 font_key_;
+ scoped_ptr<base::MemoryMappedFile> memory_;
+ bool cached_data_;
+ UINT writer_cookie_;
+
+ DISALLOW_COPY_AND_ASSIGN(FontFileStream);
+};
+
+// Implements IDWriteFontFileLoader as required by FontFileLoader.
+class FontFileLoader
+ : public mswr::RuntimeClass<mswr::RuntimeClassFlags<mswr::ClassicCom>,
+ IDWriteFontFileLoader> {
+ public:
+ // IDWriteFontFileLoader methods.
+ HRESULT STDMETHODCALLTYPE
+ CreateStreamFromKey(void const* ref_key,
+ UINT32 ref_key_size,
+ IDWriteFontFileStream** stream) override {
+ if (ref_key_size != sizeof(UINT32))
+ return E_FAIL;
+
+ UINT32 font_key = *static_cast<const UINT32*>(ref_key);
+ mswr::ComPtr<FontFileStream> font_stream;
+ HRESULT hr = mswr::MakeAndInitialize<FontFileStream>(&font_stream,
+ font_key);
+ if (SUCCEEDED(hr)) {
+ *stream = font_stream.Detach();
+ return S_OK;
+ }
+ return E_FAIL;
+ }
+
+ FontFileLoader() {}
+ ~FontFileLoader() override {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FontFileLoader);
+};
+
+// Implements IDWriteFontFileEnumerator as required by direct write.
+class FontFileEnumerator
+ : public mswr::RuntimeClass<mswr::RuntimeClassFlags<mswr::ClassicCom>,
+ IDWriteFontFileEnumerator> {
+ public:
+ // IDWriteFontFileEnumerator methods.
+ HRESULT STDMETHODCALLTYPE MoveNext(BOOL* has_current_file) override {
+ *has_current_file = FALSE;
+
+ if (current_file_)
+ current_file_.ReleaseAndGetAddressOf();
+
+ if (font_idx_ < g_font_loader->GetFontMapSize()) {
+ HRESULT hr =
+ factory_->CreateCustomFontFileReference(&font_idx_,
+ sizeof(UINT32),
+ file_loader_.Get(),
+ current_file_.GetAddressOf());
+ DCHECK(SUCCEEDED(hr));
+ *has_current_file = TRUE;
+ font_idx_++;
+ }
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE
+ GetCurrentFontFile(IDWriteFontFile** font_file) override {
+ if (!current_file_) {
+ *font_file = NULL;
+ return E_FAIL;
+ }
+
+ *font_file = current_file_.Detach();
+ return S_OK;
+ }
+
+ FontFileEnumerator(const void* keys,
+ UINT32 buffer_size,
+ IDWriteFactory* factory,
+ IDWriteFontFileLoader* file_loader)
+ : factory_(factory), file_loader_(file_loader), font_idx_(0) {}
+
+ ~FontFileEnumerator() override {}
+
+ mswr::ComPtr<IDWriteFactory> factory_;
+ mswr::ComPtr<IDWriteFontFile> current_file_;
+ mswr::ComPtr<IDWriteFontFileLoader> file_loader_;
+ UINT32 font_idx_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FontFileEnumerator);
+};
+
+// IDWriteFontCollectionLoader methods.
+HRESULT STDMETHODCALLTYPE FontCollectionLoader::CreateEnumeratorFromKey(
+ IDWriteFactory* factory,
+ void const* key,
+ UINT32 key_size,
+ IDWriteFontFileEnumerator** file_enumerator) {
+ *file_enumerator = mswr::Make<FontFileEnumerator>(
+ key, key_size, factory, file_loader_.Get()).Detach();
+ return S_OK;
+}
+
+// static
+HRESULT FontCollectionLoader::Initialize(IDWriteFactory* factory) {
+ DCHECK(g_font_loader == NULL);
+
+ HRESULT result;
+ result = mswr::MakeAndInitialize<FontCollectionLoader>(&g_font_loader);
+ if (FAILED(result) || !g_font_loader) {
+ DCHECK(false);
+ return E_FAIL;
+ }
+
+ CHECK(g_font_loader->LoadFontListFromRegistry());
+
+ g_font_loader->file_loader_ = mswr::Make<FontFileLoader>().Detach();
+
+ factory->RegisterFontFileLoader(g_font_loader->file_loader_.Get());
+ factory->RegisterFontCollectionLoader(g_font_loader.Get());
+
+ return S_OK;
+}
+
+FontCollectionLoader::~FontCollectionLoader() {
+ STLDeleteContainerPairSecondPointers(cache_map_.begin(), cache_map_.end());
+}
+
+UINT32 FontCollectionLoader::GetFontMapSize() {
+ return reg_fonts_.size();
+}
+
+base::string16 FontCollectionLoader::GetFontNameFromKey(UINT32 idx) {
+ DCHECK(idx < reg_fonts_.size());
+ return reg_fonts_[idx];
+}
+
+const base::FilePath::CharType* kFontExtensionsToIgnore[] {
+ FILE_PATH_LITERAL(".FON"), // Bitmap or vector
+ FILE_PATH_LITERAL(".PFM"), // Adobe Type 1
+ FILE_PATH_LITERAL(".PFB"), // Adobe Type 1
+};
+
+const wchar_t* kFontsToIgnore[] = {
+ // "Gill Sans Ultra Bold" turns into an Ultra Bold weight "Gill Sans" in
+ // DirectWrite, but most users don't have any other weights. The regular
+ // weight font is named "Gill Sans MT", but that ends up in a different
+ // family with that name. On Mac, there's a "Gill Sans" with various weights,
+ // so CSS authors use { 'font-family': 'Gill Sans', 'Gill Sans MT', ... } and
+ // because of the DirectWrite family futzing, they end up with an Ultra Bold
+ // font, when they just wanted "Gill Sans". Mozilla implemented a more
+ // complicated hack where they effectively rename the Ultra Bold font to
+ // "Gill Sans MT Ultra Bold", but because the Ultra Bold font is so ugly
+ // anyway, we simply ignore it. See
+ // http://www.microsoft.com/typography/fonts/font.aspx?FMID=978 for a picture
+ // of the font, and the file name. We also ignore "Gill Sans Ultra Bold
+ // Condensed".
+ L"gilsanub.ttf",
+ L"gillubcd.ttf",
+};
+
+bool FontCollectionLoader::LoadFontListFromRegistry() {
+ const wchar_t kFontsRegistry[] =
+ L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts";
+ CHECK(reg_fonts_.empty());
+ base::win::RegKey regkey;
+ if (regkey.Open(HKEY_LOCAL_MACHINE, kFontsRegistry, KEY_READ) !=
+ ERROR_SUCCESS) {
+ return false;
+ }
+
+ base::FilePath system_font_path;
+ PathService::Get(base::DIR_WINDOWS_FONTS, &system_font_path);
+
+ base::string16 name;
+ base::string16 value;
+ for (DWORD idx = 0; idx < regkey.GetValueCount(); idx++) {
+ if (regkey.GetValueNameAt(idx, &name) == ERROR_SUCCESS &&
+ regkey.ReadValue(name.c_str(), &value) == ERROR_SUCCESS) {
+ base::FilePath path(value.c_str());
+ // We need to check if file name is the only component that exists,
+ // we will ignore all other registry entries.
+ std::vector<base::FilePath::StringType> components;
+ path.GetComponents(&components);
+ if (components.size() == 1 ||
+ base::FilePath::CompareEqualIgnoreCase(system_font_path.value(),
+ path.DirName().value())) {
+ bool should_ignore = false;
+ for (const auto& ignore : kFontsToIgnore) {
+ if (base::FilePath::CompareEqualIgnoreCase(path.value(), ignore)) {
+ should_ignore = true;
+ break;
+ }
+ }
+ // DirectWrite doesn't support bitmap/vector fonts and Adobe type 1
+ // fonts, we will ignore those font extensions.
+ // MSDN article: http://goo.gl/TfCOA
+ if (!should_ignore) {
+ for (const auto& ignore : kFontExtensionsToIgnore) {
+ if (path.MatchesExtension(ignore)) {
+ should_ignore = true;
+ break;
+ }
+ }
+ }
+
+ if (!should_ignore)
+ reg_fonts_.push_back(value.c_str());
+ }
+ }
+ }
+ UMA_HISTOGRAM_COUNTS("DirectWrite.Fonts.Loaded", reg_fonts_.size());
+ UMA_HISTOGRAM_COUNTS("DirectWrite.Fonts.Ignored",
+ regkey.GetValueCount() - reg_fonts_.size());
+ return true;
+}
+
+// This list is mainly based on prefs/prefs_tab_helper.cc kFontDefaults.
+const wchar_t* kRestrictedFontSet[] = {
+ // These are the "Web Safe" fonts.
+ L"times.ttf", // IDS_STANDARD_FONT_FAMILY
+ L"timesbd.ttf", // IDS_STANDARD_FONT_FAMILY
+ L"timesbi.ttf", // IDS_STANDARD_FONT_FAMILY
+ L"timesi.ttf", // IDS_STANDARD_FONT_FAMILY
+ L"cour.ttf", // IDS_FIXED_FONT_FAMILY
+ L"courbd.ttf", // IDS_FIXED_FONT_FAMILY
+ L"courbi.ttf", // IDS_FIXED_FONT_FAMILY
+ L"couri.ttf", // IDS_FIXED_FONT_FAMILY
+ L"consola.ttf", // IDS_FIXED_FONT_FAMILY_ALT_WIN
+ L"consolab.ttf", // IDS_FIXED_FONT_FAMILY_ALT_WIN
+ L"consolai.ttf", // IDS_FIXED_FONT_FAMILY_ALT_WIN
+ L"consolaz.ttf", // IDS_FIXED_FONT_FAMILY_ALT_WIN
+ L"arial.ttf", // IDS_SANS_SERIF_FONT_FAMILY
+ L"arialbd.ttf", // IDS_SANS_SERIF_FONT_FAMILY
+ L"arialbi.ttf", // IDS_SANS_SERIF_FONT_FAMILY
+ L"ariali.ttf", // IDS_SANS_SERIF_FONT_FAMILY
+ L"comic.ttf", // IDS_CURSIVE_FONT_FAMILY
+ L"comicbd.ttf", // IDS_CURSIVE_FONT_FAMILY
+ L"comici.ttf", // IDS_CURSIVE_FONT_FAMILY
+ L"comicz.ttf", // IDS_CURSIVE_FONT_FAMILY
+ L"impact.ttf", // IDS_FANTASY_FONT_FAMILY
+ L"georgia.ttf",
+ L"georgiab.ttf",
+ L"georgiai.ttf",
+ L"georgiaz.ttf",
+ L"trebuc.ttf",
+ L"trebucbd.ttf",
+ L"trebucbi.ttf",
+ L"trebucit.ttf",
+ L"verdana.ttf",
+ L"verdanab.ttf",
+ L"verdanai.ttf",
+ L"verdanaz.ttf",
+ L"segoeui.ttf", // IDS_PICTOGRAPH_FONT_FAMILY
+ L"segoeuib.ttf", // IDS_PICTOGRAPH_FONT_FAMILY
+ L"segoeuii.ttf", // IDS_PICTOGRAPH_FONT_FAMILY
+ L"msgothic.ttc", // IDS_STANDARD_FONT_FAMILY_JAPANESE
+ L"msmincho.ttc", // IDS_SERIF_FONT_FAMILY_JAPANESE
+ L"gulim.ttc", // IDS_FIXED_FONT_FAMILY_KOREAN
+ L"batang.ttc", // IDS_SERIF_FONT_FAMILY_KOREAN
+ L"simsun.ttc", // IDS_STANDARD_FONT_FAMILY_SIMPLIFIED_HAN
+ L"mingliu.ttc", // IDS_SERIF_FONT_FAMILY_TRADITIONAL_HAN
+
+ // These are from the Blink fallback list.
+ L"david.ttf", // USCRIPT_HEBREW
+ L"davidbd.ttf", // USCRIPT_HEBREW
+ L"euphemia.ttf", // USCRIPT_CANADIAN_ABORIGINAL
+ L"gautami.ttf", // USCRIPT_TELUGU
+ L"gautamib.ttf", // USCRIPT_TELUGU
+ L"latha.ttf", // USCRIPT_TAMIL
+ L"lathab.ttf", // USCRIPT_TAMIL
+ L"mangal.ttf", // USCRIPT_DEVANAGARI
+ L"mangalb.ttf", // USCRIPT_DEVANAGARI
+ L"monbaiti.ttf", // USCRIPT_MONGOLIAN
+ L"mvboli.ttf", // USCRIPT_THAANA
+ L"plantc.ttf", // USCRIPT_CHEROKEE
+ L"raavi.ttf", // USCRIPT_GURMUKHI
+ L"raavib.ttf", // USCRIPT_GURMUKHI
+ L"shruti.ttf", // USCRIPT_GUJARATI
+ L"shrutib.ttf", // USCRIPT_GUJARATI
+ L"sylfaen.ttf", // USCRIPT_GEORGIAN and USCRIPT_ARMENIAN
+ L"tahoma.ttf", // USCRIPT_ARABIC,
+ L"tahomabd.ttf", // USCRIPT_ARABIC,
+ L"tunga.ttf", // USCRIPT_KANNADA
+ L"tungab.ttf", // USCRIPT_KANNADA
+ L"vrinda.ttf", // USCRIPT_BENGALI
+ L"vrindab.ttf", // USCRIPT_BENGALI
+};
+
+bool FontCollectionLoader::LoadRestrictedFontList() {
+ reg_fonts_.clear();
+ reg_fonts_.assign(kRestrictedFontSet,
+ kRestrictedFontSet + _countof(kRestrictedFontSet));
+ return true;
+}
+
+void FontCollectionLoader::EnableCollectionBuildingMode(bool enable) {
+ in_collection_building_mode_ = enable;
+}
+
+bool FontCollectionLoader::InCollectionBuildingMode() {
+ return in_collection_building_mode_;
+}
+
+bool FontCollectionLoader::IsFileCached(UINT32 font_key) {
+ if (!cache_.get() || cache_->memory() == NULL) {
+ return false;
+ }
+ CacheMap::iterator iter = cache_map_.find(
+ GetFontNameFromKey(font_key).c_str());
+ return iter != cache_map_.end();;
+}
+
+bool FontCollectionLoader::LoadCacheFile() {
+ std::string font_cache_handle_string =
+ base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kFontCacheSharedHandle);
+ if (font_cache_handle_string.empty())
+ return false;
+
+ base::SharedMemoryHandle font_cache_handle = NULL;
+ base::StringToUint(font_cache_handle_string,
+ reinterpret_cast<unsigned int*>(&font_cache_handle));
+ DCHECK(font_cache_handle);
+
+ base::SharedMemory* shared_mem = new base::SharedMemory(
+ font_cache_handle, true);
+ // Map while file
+ shared_mem->Map(0);
+
+ cache_.reset(shared_mem);
+
+ if (!ValidateAndLoadCacheMap()) {
+ cache_.reset();
+ return false;
+ }
+
+ return true;
+}
+
+void FontCollectionLoader::EnterStaticCacheMode(const WCHAR* file_name) {
+ cache_writer_.reset(new FontCacheWriter());
+ if (cache_writer_->Create(file_name))
+ create_static_cache_ = true;
+}
+
+void FontCollectionLoader::LeaveStaticCacheMode() {
+ cache_writer_->Close();
+ cache_writer_.reset(NULL);
+ create_static_cache_ = false;
+}
+
+bool FontCollectionLoader::IsBuildStaticCacheMode() {
+ return create_static_cache_;
+}
+
+bool FontCollectionLoader::ValidateAndLoadCacheMap() {
+ BYTE* mem_file_start = static_cast<BYTE*>(cache_->memory());
+ BYTE* mem_file_end = mem_file_start + cache_->mapped_size();
+
+ BYTE* current_ptr = mem_file_start;
+ CacheFileHeader* file_header =
+ reinterpret_cast<CacheFileHeader*>(current_ptr);
+ if (!ValidateFontCacheHeader(file_header))
+ return false;
+
+ current_ptr = current_ptr + sizeof(CacheFileHeader);
+ if (current_ptr >= mem_file_end)
+ return false;
+
+ while ((current_ptr + sizeof(CacheFileEntry)) < mem_file_end) {
+ CacheFileEntry* entry = reinterpret_cast<CacheFileEntry*>(current_ptr);
+ current_ptr += sizeof(CacheFileEntry);
+ WCHAR file_name[kMaxFontFileNameLength];
+ wcsncpy_s(file_name,
+ kMaxFontFileNameLength,
+ entry->file_name,
+ _TRUNCATE);
+ CacheTableEntry* table_entry = NULL;
+ CacheMap::iterator iter = cache_map_.find(file_name);
+ if (iter == cache_map_.end()) {
+ table_entry = new CacheTableEntry();
+ cache_map_[file_name] = table_entry;
+ } else {
+ table_entry = iter->second;
+ }
+ table_entry->file_size = entry->file_size;
+ for (DWORD idx = 0;
+ (current_ptr + sizeof(CacheFileOffsetEntry)) < mem_file_end &&
+ idx < entry->entry_count;
+ idx++) {
+ CacheFileOffsetEntry* offset_entry =
+ reinterpret_cast<CacheFileOffsetEntry*>(current_ptr);
+ CacheTableOffsetEntry table_offset_entry;
+ table_offset_entry.start_offset = offset_entry->start_offset;
+ table_offset_entry.length = offset_entry->length;
+ table_offset_entry.inside_file_ptr =
+ current_ptr + sizeof(CacheFileOffsetEntry);
+ table_entry->offset_entries.push_back(table_offset_entry);
+ current_ptr += sizeof(CacheFileOffsetEntry);
+ current_ptr += offset_entry->length;
+ }
+ }
+
+ return true;
+}
+
+void* FontCollectionLoader::GetCachedFragment(UINT32 font_key,
+ UINT64 start_offset,
+ UINT64 length) {
+ UINT64 just_past_end = start_offset + length;
+ CacheMap::iterator iter = cache_map_.find(
+ GetFontNameFromKey(font_key).c_str());
+ if (iter != cache_map_.end()) {
+ CacheTableEntry* entry = iter->second;
+ OffsetVector::iterator offset_iter = entry->offset_entries.begin();
+ while (offset_iter != entry->offset_entries.end()) {
+ UINT64 available_just_past_end =
+ offset_iter->start_offset + offset_iter->length;
+ if (offset_iter->start_offset <= start_offset &&
+ just_past_end <= available_just_past_end) {
+ return offset_iter->inside_file_ptr +
+ (start_offset - offset_iter->start_offset);
+ }
+ offset_iter++;
+ }
+ }
+ return NULL;
+}
+
+UINT64 FontCollectionLoader::GetCachedFileSize(UINT32 font_key) {
+ CacheMap::iterator iter = cache_map_.find(
+ GetFontNameFromKey(font_key).c_str());
+ if (iter != cache_map_.end()) {
+ return iter->second->file_size;
+ }
+ return 0;
+}
+
+FontCacheWriter* FontCollectionLoader::GetFontCacheWriter() {
+ return cache_writer_.get();
+}
+
+} // namespace
+
+namespace content {
+
+const char kFontCacheSharedSectionName[] = "ChromeDWriteFontCache";
+
+mswr::ComPtr<IDWriteFontCollection> g_font_collection;
+
+IDWriteFontCollection* GetCustomFontCollection(IDWriteFactory* factory) {
+ if (g_font_collection.Get() != NULL)
+ return g_font_collection.Get();
+
+ base::TimeTicks start_tick = base::TimeTicks::Now();
+
+ FontCollectionLoader::Initialize(factory);
+
+ bool cache_file_loaded = g_font_loader->LoadCacheFile();
+
+ // Arbitrary threshold to stop loading enormous number of fonts. Usual
+ // side effect of loading large number of fonts results in renderer getting
+ // killed as it appears to hang.
+ const UINT32 kMaxFontThreshold = 1750;
+ HRESULT hr = E_FAIL;
+ if (cache_file_loaded ||
+ g_font_loader->GetFontMapSize() < kMaxFontThreshold) {
+ g_font_loader->EnableCollectionBuildingMode(true);
+ hr = factory->CreateCustomFontCollection(
+ g_font_loader.Get(), NULL, 0, g_font_collection.GetAddressOf());
+ g_font_loader->EnableCollectionBuildingMode(false);
+ }
+ bool loading_restricted = false;
+ if (FAILED(hr) || !g_font_collection.Get()) {
+ loading_restricted = true;
+ // We will try here just one more time with restricted font set.
+ g_font_loader->LoadRestrictedFontList();
+ hr = factory->CreateCustomFontCollection(
+ g_font_loader.Get(), NULL, 0, g_font_collection.GetAddressOf());
+ }
+
+ base::TimeDelta time_delta = base::TimeTicks::Now() - start_tick;
+ int64 delta = time_delta.ToInternalValue();
+ base::debug::Alias(&delta);
+ UINT32 size = g_font_loader->GetFontMapSize();
+ base::debug::Alias(&size);
+ base::debug::Alias(&loading_restricted);
+
+ CHECK(SUCCEEDED(hr));
+ CHECK(g_font_collection.Get() != NULL);
+
+ if (cache_file_loaded)
+ UMA_HISTOGRAM_TIMES("DirectWrite.Fonts.LoadTime.Cached", time_delta);
+ else
+ UMA_HISTOGRAM_TIMES("DirectWrite.Fonts.LoadTime", time_delta);
+
+ base::debug::ClearCrashKey(kFontKeyName);
+
+ return g_font_collection.Get();
+}
+
+bool BuildFontCacheInternal(const WCHAR* file_name) {
+ typedef decltype(DWriteCreateFactory)* DWriteCreateFactoryProc;
+ HMODULE dwrite_dll = LoadLibraryW(L"dwrite.dll");
+ if (!dwrite_dll) {
+ DWORD load_library_get_last_error = GetLastError();
+ base::debug::Alias(&dwrite_dll);
+ base::debug::Alias(&load_library_get_last_error);
+ CHECK(false);
+ }
+
+ DWriteCreateFactoryProc dwrite_create_factory_proc =
+ reinterpret_cast<DWriteCreateFactoryProc>(
+ GetProcAddress(dwrite_dll, "DWriteCreateFactory"));
+
+ if (!dwrite_create_factory_proc) {
+ DWORD get_proc_address_get_last_error = GetLastError();
+ base::debug::Alias(&dwrite_create_factory_proc);
+ base::debug::Alias(&get_proc_address_get_last_error);
+ CHECK(false);
+ }
+
+ mswr::ComPtr<IDWriteFactory> factory;
+
+ CHECK(SUCCEEDED(
+ dwrite_create_factory_proc(
+ DWRITE_FACTORY_TYPE_ISOLATED,
+ __uuidof(IDWriteFactory),
+ reinterpret_cast<IUnknown**>(factory.GetAddressOf()))));
+
+ base::TimeTicks start_tick = base::TimeTicks::Now();
+
+ FontCollectionLoader::Initialize(factory.Get());
+
+ g_font_loader->EnterStaticCacheMode(file_name);
+
+ mswr::ComPtr<IDWriteFontCollection> font_collection;
+
+ HRESULT hr = E_FAIL;
+ g_font_loader->EnableCollectionBuildingMode(true);
+ hr = factory->CreateCustomFontCollection(
+ g_font_loader.Get(), NULL, 0, font_collection.GetAddressOf());
+ g_font_loader->EnableCollectionBuildingMode(false);
+
+ bool loading_restricted = false;
+ if (FAILED(hr) || !font_collection.Get()) {
+ loading_restricted = true;
+ // We will try here just one more time with restricted font set.
+ g_font_loader->LoadRestrictedFontList();
+ hr = factory->CreateCustomFontCollection(
+ g_font_loader.Get(), NULL, 0, font_collection.GetAddressOf());
+ }
+
+ g_font_loader->LeaveStaticCacheMode();
+
+ base::TimeDelta time_delta = base::TimeTicks::Now() - start_tick;
+ int64 delta = time_delta.ToInternalValue();
+ base::debug::Alias(&delta);
+ UINT32 size = g_font_loader->GetFontMapSize();
+ base::debug::Alias(&size);
+ base::debug::Alias(&loading_restricted);
+
+ CHECK(SUCCEEDED(hr));
+ CHECK(font_collection.Get() != NULL);
+
+ base::debug::ClearCrashKey(kFontKeyName);
+
+ return true;
+}
+
+bool ValidateFontCacheFile(base::File* file) {
+ DCHECK(file != NULL);
+ CacheFileHeader file_header;
+ if (file->Read(0, reinterpret_cast<char*>(&file_header), sizeof(file_header))
+ == -1) {
+ return false;
+ }
+ return ValidateFontCacheHeader(&file_header);
+}
+
+bool LoadFontCache(const base::FilePath& path) {
+ scoped_ptr<base::File> file(new base::File(path,
+ base::File::FLAG_OPEN | base::File::FLAG_READ));
+ if (!file->IsValid())
+ return false;
+
+ if (!ValidateFontCacheFile(file.get()))
+ return false;
+
+ base::string16 name(base::ASCIIToUTF16(content::kFontCacheSharedSectionName));
+ name.append(base::UintToString16(base::GetCurrentProcId()));
+ HANDLE mapping = ::CreateFileMapping(
+ file->GetPlatformFile(),
+ NULL,
+ PAGE_READONLY,
+ 0,
+ 0,
+ name.c_str());
+ if (mapping == INVALID_HANDLE_VALUE)
+ return false;
+
+ if (::GetLastError() == ERROR_ALREADY_EXISTS) {
+ CloseHandle(mapping);
+ // We crash here, as no one should have created this mapping except Chrome.
+ CHECK(false);
+ return false;
+ }
+
+ DCHECK(!g_shared_font_cache.IsValid());
+ g_shared_font_cache.Set(mapping);
+
+ return true;
+}
+
+bool BuildFontCache(const base::FilePath& file) {
+ return BuildFontCacheInternal(file.value().c_str());
+}
+
+} // namespace content
diff --git a/chromium/content/common/dwrite_font_platform_win_unittest.cc b/chromium/content/common/dwrite_font_platform_win_unittest.cc
new file mode 100644
index 00000000000..4e517feedf6
--- /dev/null
+++ b/chromium/content/common/dwrite_font_platform_win_unittest.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 "content/public/common/dwrite_font_platform_win.h"
+
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "content/public/common/content_paths.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/win/direct_write.h"
+
+namespace content {
+
+class DWriteFontCacheTest : public testing::Test {
+ public:
+ DWriteFontCacheTest() { }
+
+ void SetUp() override {
+ base::FilePath data_path;
+ ASSERT_TRUE(PathService::Get(content::DIR_TEST_DATA, &data_path));
+ arial_cache_path_ =
+ data_path.AppendASCII("font/dwrite_font_cache_arial.dat");
+
+ corrupt_cache_path_ =
+ data_path.AppendASCII("font/dwrite_font_cache_corrupt.dat");
+
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ cache_file_path_ = temp_dir_.path().AppendASCII("dwrite_font_cache.dat");
+ }
+
+ protected:
+ base::FilePath arial_cache_path_;
+ base::FilePath corrupt_cache_path_;
+ base::ScopedTempDir temp_dir_;
+ base::FilePath cache_file_path_;
+};
+
+TEST_F(DWriteFontCacheTest, BuildCacheTest) {
+ if (gfx::win::ShouldUseDirectWrite()) {
+ DLOG(INFO) << __FUNCTION__ << ": " << cache_file_path_.value().c_str();
+ EXPECT_TRUE(BuildFontCache(cache_file_path_));
+ ASSERT_TRUE(base::PathExists(cache_file_path_));
+ }
+}
+
+TEST_F(DWriteFontCacheTest, ValidCacheTest) {
+ if (gfx::win::ShouldUseDirectWrite()) {
+ DLOG(INFO) << __FUNCTION__ << ": " << arial_cache_path_.value().c_str();
+ scoped_ptr<base::File> file(new base::File(arial_cache_path_,
+ base::File::FLAG_OPEN | base::File::FLAG_READ));
+ ASSERT_TRUE(file->IsValid());
+
+ EXPECT_TRUE(ValidateFontCacheFile(file.get()));
+ }
+}
+
+TEST_F(DWriteFontCacheTest, CorruptCacheTest) {
+ if (gfx::win::ShouldUseDirectWrite()) {
+ DLOG(INFO) << __FUNCTION__ << ": " << corrupt_cache_path_.value().c_str();
+ scoped_ptr<base::File> file(new base::File(corrupt_cache_path_,
+ base::File::FLAG_OPEN | base::File::FLAG_READ));
+ ASSERT_TRUE(file->IsValid());
+
+ EXPECT_FALSE(ValidateFontCacheFile(file.get()));
+ }
+}
+
+} // content
diff --git a/chromium/content/common/fileapi/webblob_messages.h b/chromium/content/common/fileapi/webblob_messages.h
index f1dcea67a57..7527b18ef15 100644
--- a/chromium/content/common/fileapi/webblob_messages.h
+++ b/chromium/content/common/fileapi/webblob_messages.h
@@ -8,7 +8,7 @@
#include "content/common/content_export.h"
#include "content/public/common/common_param_traits.h"
#include "ipc/ipc_message_macros.h"
-#include "storage/common/blob/blob_data.h"
+#include "storage/common/data_element.h"
#undef IPC_MESSAGE_EXPORT
#define IPC_MESSAGE_EXPORT CONTENT_EXPORT
@@ -20,7 +20,7 @@ IPC_MESSAGE_CONTROL1(BlobHostMsg_StartBuilding,
std::string /*uuid */)
IPC_MESSAGE_CONTROL2(BlobHostMsg_AppendBlobDataItem,
std::string /* uuid */,
- storage::BlobData::Item)
+ storage::DataElement)
IPC_SYNC_MESSAGE_CONTROL3_0(BlobHostMsg_SyncAppendSharedMemory,
std::string /*uuid*/,
base::SharedMemoryHandle,
@@ -49,7 +49,7 @@ IPC_MESSAGE_CONTROL2(StreamHostMsg_StartBuilding,
// Appends data to a stream being built.
IPC_MESSAGE_CONTROL2(StreamHostMsg_AppendBlobDataItem,
GURL /* url */,
- storage::BlobData::Item)
+ storage::DataElement)
// Appends data to a stream being built.
IPC_SYNC_MESSAGE_CONTROL3_0(StreamHostMsg_SyncAppendSharedMemory,
@@ -57,6 +57,10 @@ IPC_SYNC_MESSAGE_CONTROL3_0(StreamHostMsg_SyncAppendSharedMemory,
base::SharedMemoryHandle,
size_t /* buffer size */)
+// Flushes contents buffered in the stream.
+IPC_MESSAGE_CONTROL1(StreamHostMsg_Flush,
+ GURL /* url */)
+
// Finishes building a stream.
IPC_MESSAGE_CONTROL1(StreamHostMsg_FinishBuilding,
GURL /* url */)
diff --git a/chromium/content/common/font_cache_dispatcher_win.cc b/chromium/content/common/font_cache_dispatcher_win.cc
index 2181a08f98d..880f0f47376 100644
--- a/chromium/content/common/font_cache_dispatcher_win.cc
+++ b/chromium/content/common/font_cache_dispatcher_win.cc
@@ -8,6 +8,7 @@
#include <vector>
#include "base/logging.h"
+#include "base/profiler/scoped_tracker.h"
#include "base/strings/string16.h"
#include "content/common/child_process_messages.h"
@@ -23,6 +24,10 @@ class FontCache {
}
void PreCacheFont(const LOGFONT& font, FontCacheDispatcher* dispatcher) {
+ // TODO(ananta): Remove ScopedTracker below once crbug.com/90127 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION("90127 FontCache::PreCacheFont"));
+
typedef std::map<base::string16, FontCache::CacheElement> FontNameToElement;
base::AutoLock lock(mutex_);
@@ -138,6 +143,14 @@ FontCacheDispatcher::FontCacheDispatcher()
: sender_(NULL) {
}
+bool FontCacheDispatcher::Send(IPC::Message* message) {
+ if (sender_)
+ return sender_->Send(message);
+
+ delete message;
+ return false;
+}
+
FontCacheDispatcher::~FontCacheDispatcher() {
}
@@ -160,14 +173,6 @@ void FontCacheDispatcher::OnChannelClosing() {
sender_ = NULL;
}
-bool FontCacheDispatcher::Send(IPC::Message* message) {
- if (sender_)
- return sender_->Send(message);
-
- delete message;
- return false;
-}
-
void FontCacheDispatcher::OnPreCacheFont(const LOGFONT& font) {
// If a child process is running in a sandbox, GetTextMetrics()
// can sometimes fail. If a font has not been loaded
diff --git a/chromium/content/common/font_cache_dispatcher_win.h b/chromium/content/common/font_cache_dispatcher_win.h
index 357aed6b491..3c0faf8ad36 100644
--- a/chromium/content/common/font_cache_dispatcher_win.h
+++ b/chromium/content/common/font_cache_dispatcher_win.h
@@ -20,16 +20,17 @@ namespace content {
class FontCacheDispatcher : public IPC::MessageFilter, public IPC::Sender {
public:
FontCacheDispatcher();
- virtual ~FontCacheDispatcher();
// IPC::Sender implementation:
- virtual bool Send(IPC::Message* message) override;
+ bool Send(IPC::Message* message) override;
private:
+ ~FontCacheDispatcher() override;
+
// IPC::MessageFilter implementation:
- virtual void OnFilterAdded(IPC::Sender* sender) override;
- virtual bool OnMessageReceived(const IPC::Message& message) override;
- virtual void OnChannelClosing() override;
+ void OnFilterAdded(IPC::Sender* sender) override;
+ bool OnMessageReceived(const IPC::Message& message) override;
+ void OnChannelClosing() override;
// Message handlers.
void OnPreCacheFont(const LOGFONT& font);
diff --git a/chromium/content/common/font_config_ipc_linux.cc b/chromium/content/common/font_config_ipc_linux.cc
index fcb06ebac0d..540d7d88825 100644
--- a/chromium/content/common/font_config_ipc_linux.cc
+++ b/chromium/content/common/font_config_ipc_linux.cc
@@ -12,25 +12,60 @@
#include <sys/uio.h>
#include <unistd.h>
-#include "base/debug/trace_event.h"
#include "base/files/file_util.h"
+#include "base/files/memory_mapped_file.h"
+#include "base/memory/ref_counted.h"
#include "base/pickle.h"
#include "base/posix/unix_domain_socket_linux.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/trace_event/trace_event.h"
#include "skia/ext/refptr.h"
#include "skia/ext/skia_utils_base.h"
#include "third_party/skia/include/core/SkData.h"
#include "third_party/skia/include/core/SkStream.h"
+#include "third_party/skia/include/core/SkTypeface.h"
namespace content {
-// Return a stream from the file descriptor, or NULL on failure.
-SkStream* StreamFromFD(int fd) {
- skia::RefPtr<SkData> data = skia::AdoptRef(SkData::NewFromFD(fd));
- if (!data) {
- return NULL;
+class FontConfigIPC::MappedFontFile
+ : public base::RefCountedThreadSafe<MappedFontFile> {
+ public:
+ explicit MappedFontFile(uint32_t font_id) : font_id_(font_id) {}
+
+ uint32_t font_id() const { return font_id_; }
+
+ bool Initialize(int fd) {
+ base::ThreadRestrictions::ScopedAllowIO allow_mmap;
+ return mapped_font_file_.Initialize(base::File(fd));
+ }
+
+ SkMemoryStream* CreateMemoryStream() {
+ DCHECK(mapped_font_file_.IsValid());
+ auto data = skia::AdoptRef(SkData::NewWithProc(
+ mapped_font_file_.data(), mapped_font_file_.length(),
+ &MappedFontFile::ReleaseProc, this));
+ if (!data)
+ return nullptr;
+ AddRef();
+ return new SkMemoryStream(data.get());
+ }
+
+ private:
+ friend class base::RefCountedThreadSafe<MappedFontFile>;
+
+ ~MappedFontFile() {
+ auto font_config = static_cast<FontConfigIPC*>(FontConfigIPC::RefGlobal());
+ font_config->RemoveMappedFontFile(this);
}
- return new SkMemoryStream(data.get());
-}
+
+ static void ReleaseProc(const void* ptr, size_t length, void* context) {
+ base::ThreadRestrictions::ScopedAllowIO allow_munmap;
+ static_cast<MappedFontFile*>(context)->Release();
+ }
+
+ uint32_t font_id_;
+ base::MemoryMappedFile mapped_font_file_;
+};
void CloseFD(int fd) {
int err = IGNORE_EINTR(close(fd));
@@ -70,7 +105,7 @@ bool FontConfigIPC::matchFamilyName(const char familyName[],
Pickle reply(reinterpret_cast<char*>(reply_buf), r);
PickleIterator iter(reply);
bool result;
- if (!reply.ReadBool(&iter, &result))
+ if (!iter.ReadBool(&result))
return false;
if (!result)
return false;
@@ -78,9 +113,9 @@ bool FontConfigIPC::matchFamilyName(const char familyName[],
SkString reply_family;
FontIdentity reply_identity;
uint32_t reply_style;
- if (!skia::ReadSkString(reply, &iter, &reply_family) ||
- !skia::ReadSkFontIdentity(reply, &iter, &reply_identity) ||
- !reply.ReadUInt32(&iter, &reply_style)) {
+ if (!skia::ReadSkString(&iter, &reply_family) ||
+ !skia::ReadSkFontIdentity(&iter, &reply_identity) ||
+ !iter.ReadUInt32(&reply_style)) {
return false;
}
@@ -94,8 +129,16 @@ bool FontConfigIPC::matchFamilyName(const char familyName[],
return true;
}
-SkStream* FontConfigIPC::openStream(const FontIdentity& identity) {
+SkStreamAsset* FontConfigIPC::openStream(const FontIdentity& identity) {
TRACE_EVENT0("sandbox_ipc", "FontConfigIPC::openStream");
+
+ {
+ base::AutoLock lock(lock_);
+ auto mapped_font_files_it = mapped_font_files_.find(identity.fID);
+ if (mapped_font_files_it != mapped_font_files_.end())
+ return mapped_font_files_it->second->CreateMemoryStream();
+ }
+
Pickle request;
request.WriteInt(METHOD_OPEN);
request.WriteUInt32(identity.fID);
@@ -112,16 +155,29 @@ SkStream* FontConfigIPC::openStream(const FontIdentity& identity) {
Pickle reply(reinterpret_cast<char*>(reply_buf), r);
bool result;
PickleIterator iter(reply);
- if (!reply.ReadBool(&iter, &result) ||
- !result) {
+ if (!iter.ReadBool(&result) || !result) {
if (result_fd)
CloseFD(result_fd);
return NULL;
}
- SkStream* stream = StreamFromFD(result_fd);
- CloseFD(result_fd);
- return stream;
+ scoped_refptr<MappedFontFile> mapped_font_file =
+ new MappedFontFile(identity.fID);
+ if (!mapped_font_file->Initialize(result_fd))
+ return nullptr;
+
+ {
+ base::AutoLock lock(lock_);
+ auto mapped_font_files_it =
+ mapped_font_files_.insert(std::make_pair(mapped_font_file->font_id(),
+ mapped_font_file.get())).first;
+ return mapped_font_files_it->second->CreateMemoryStream();
+ }
+}
+
+void FontConfigIPC::RemoveMappedFontFile(MappedFontFile* mapped_font_file) {
+ base::AutoLock lock(lock_);
+ mapped_font_files_.erase(mapped_font_file->font_id());
}
} // namespace content
diff --git a/chromium/content/common/font_config_ipc_linux.h b/chromium/content/common/font_config_ipc_linux.h
index c5cf80f7274..cbdabbeb1c9 100644
--- a/chromium/content/common/font_config_ipc_linux.h
+++ b/chromium/content/common/font_config_ipc_linux.h
@@ -6,10 +6,16 @@
#define CONTENT_COMMON_FONT_CONFIG_IPC_LINUX_H_
#include "base/compiler_specific.h"
+#include "base/containers/hash_tables.h"
+#include "base/synchronization/lock.h"
+#include "third_party/skia/include/core/SkStream.h"
+#include "third_party/skia/include/core/SkTypeface.h"
#include "third_party/skia/include/ports/SkFontConfigInterface.h"
#include <string>
+class SkString;
+
namespace content {
// FontConfig implementation for Skia that proxies out of process to get out
@@ -25,7 +31,7 @@ class FontConfigIPC : public SkFontConfigInterface {
SkString* outFamilyName,
SkTypeface::Style* outStyle) override;
- SkStream* openStream(const FontIdentity&) override;
+ SkStreamAsset* openStream(const FontIdentity&) override;
enum Method {
METHOD_MATCH = 0,
@@ -37,7 +43,18 @@ class FontConfigIPC : public SkFontConfigInterface {
};
private:
+ class MappedFontFile;
+
+ // Removes |mapped_font_file| from |mapped_font_files_|.
+ // Does not delete the passed-in object.
+ void RemoveMappedFontFile(MappedFontFile* mapped_font_file);
+
const int fd_;
+ // Lock preventing multiple threads from opening font file and accessing
+ // |mapped_font_files_| map at the same time.
+ base::Lock lock_;
+ // Maps font identity ID to the memory-mapped file with font data.
+ base::hash_map<uint32_t, MappedFontFile*> mapped_font_files_;
};
} // namespace content
diff --git a/chromium/content/common/frame_message_enums.h b/chromium/content/common/frame_message_enums.h
index c45989645f7..b93120607f5 100644
--- a/chromium/content/common/frame_message_enums.h
+++ b/chromium/content/common/frame_message_enums.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_COMMON_FRAME_MESSAGES_ENUMS_H_
-#define CONTENT_COMMON_FRAME_MESSAGES_ENUMS_H_
+#ifndef CONTENT_COMMON_FRAME_MESSAGE_ENUMS_H_
+#define CONTENT_COMMON_FRAME_MESSAGE_ENUMS_H_
#include "content/common/accessibility_mode_enums.h"
@@ -37,4 +37,20 @@ struct FrameMsg_Navigate_Type {
};
};
-#endif // CONTENT_COMMON_FRAME_MESSAGES_ENUMS_H_
+struct FrameMsg_UILoadMetricsReportType {
+ public:
+ enum Value {
+ // Do not report metrics for this load.
+ NO_REPORT,
+
+ // Report metrics for this load, that originated from clicking on a link.
+ REPORT_LINK,
+
+ // Report metrics for this load, that originated from an Android OS intent.
+ REPORT_INTENT,
+
+ REPORT_TYPE_LAST = REPORT_INTENT,
+ };
+};
+
+#endif // CONTENT_COMMON_FRAME_MESSAGE_ENUMS_H_
diff --git a/chromium/content/common/frame_messages.h b/chromium/content/common/frame_messages.h
index 7d03f8c508c..5271e4e191c 100644
--- a/chromium/content/common/frame_messages.h
+++ b/chromium/content/common/frame_messages.h
@@ -9,6 +9,7 @@
#include "content/common/content_param_traits.h"
#include "content/common/frame_message_enums.h"
#include "content/common/frame_param.h"
+#include "content/common/frame_replication_state.h"
#include "content/common/navigation_gesture.h"
#include "content/common/navigation_params.h"
#include "content/common/resource_request_body.h"
@@ -17,12 +18,14 @@
#include "content/public/common/context_menu_params.h"
#include "content/public/common/frame_navigate_params.h"
#include "content/public/common/javascript_message_type.h"
+#include "content/public/common/message_port_types.h"
#include "content/public/common/page_state.h"
#include "content/public/common/resource_response.h"
#include "content/public/common/transition_element.h"
#include "ipc/ipc_message_macros.h"
#include "ui/gfx/ipc/gfx_param_traits.h"
#include "url/gurl.h"
+#include "url/origin.h"
#undef IPC_MESSAGE_EXPORT
#define IPC_MESSAGE_EXPORT CONTENT_EXPORT
@@ -37,9 +40,12 @@ IPC_ENUM_TRAITS_MIN_MAX_VALUE(content::JavaScriptMessageType,
content::JAVASCRIPT_MESSAGE_TYPE_PROMPT)
IPC_ENUM_TRAITS_MAX_VALUE(FrameMsg_Navigate_Type::Value,
FrameMsg_Navigate_Type::NAVIGATE_TYPE_LAST)
+IPC_ENUM_TRAITS_MAX_VALUE(FrameMsg_UILoadMetricsReportType::Value,
+ FrameMsg_UILoadMetricsReportType::REPORT_TYPE_LAST)
IPC_ENUM_TRAITS_MAX_VALUE(blink::WebContextMenuData::MediaType,
blink::WebContextMenuData::MediaTypeLast)
IPC_ENUM_TRAITS_MAX_VALUE(ui::MenuSourceType, ui::MENU_SOURCE_TYPE_LAST)
+IPC_ENUM_TRAITS(content::SandboxFlags) // Bitmask.
IPC_STRUCT_TRAITS_BEGIN(content::ColorSuggestion)
IPC_STRUCT_TRAITS_MEMBER(color)
@@ -91,7 +97,7 @@ IPC_STRUCT_TRAITS_BEGIN(content::CustomContextMenuContext)
IPC_STRUCT_TRAITS_END()
IPC_STRUCT_TRAITS_BEGIN(content::TransitionElement)
- IPC_STRUCT_TRAITS_MEMBER(name)
+ IPC_STRUCT_TRAITS_MEMBER(id)
IPC_STRUCT_TRAITS_MEMBER(rect)
IPC_STRUCT_TRAITS_END()
@@ -118,6 +124,7 @@ IPC_STRUCT_END()
IPC_STRUCT_TRAITS_BEGIN(content::FrameNavigateParams)
IPC_STRUCT_TRAITS_MEMBER(page_id)
+ IPC_STRUCT_TRAITS_MEMBER(nav_entry_id)
IPC_STRUCT_TRAITS_MEMBER(url)
IPC_STRUCT_TRAITS_MEMBER(base_url)
IPC_STRUCT_TRAITS_MEMBER(referrer)
@@ -136,6 +143,15 @@ IPC_STRUCT_BEGIN_WITH_PARENT(FrameHostMsg_DidCommitProvisionalLoad_Params,
content::FrameNavigateParams)
IPC_STRUCT_TRAITS_PARENT(content::FrameNavigateParams)
+ // This is the value from the browser (copied from the navigation request)
+ // indicating whether it intended to make a new entry. TODO(avi): Remove this
+ // when the pending entry situation is made sane and the browser keeps them
+ // around long enough to match them via nav_entry_id.
+ IPC_STRUCT_MEMBER(bool, intended_as_new_entry)
+
+ // Whether this commit created a new entry.
+ IPC_STRUCT_MEMBER(bool, did_create_new_entry)
+
// Information regarding the security of the connection (empty if the
// connection was not secure).
IPC_STRUCT_MEMBER(std::string, security_info)
@@ -187,6 +203,48 @@ IPC_STRUCT_BEGIN_WITH_PARENT(FrameHostMsg_DidCommitProvisionalLoad_Params,
// are unwound or moved to RenderFrameHost (crbug.com/304341) we can move the
// client to be based on the routing_id of the RenderFrameHost.
IPC_STRUCT_MEMBER(int, render_view_routing_id)
+
+ // Origin of the frame. This will be replicated to any associated
+ // RenderFrameProxies.
+ IPC_STRUCT_MEMBER(url::Origin, origin)
+
+ // How navigation metrics starting on UI action for this load should be
+ // reported.
+ IPC_STRUCT_MEMBER(FrameMsg_UILoadMetricsReportType::Value, report_type)
+
+ // Timestamp at which the UI action that triggered the navigation originated.
+ IPC_STRUCT_MEMBER(base::TimeTicks, ui_timestamp)
+IPC_STRUCT_END()
+
+IPC_STRUCT_BEGIN(FrameMsg_PostMessage_Params)
+ // Whether the data format is supplied as serialized script value, or as
+ // a simple string. If it is a raw string, must be converted from string to a
+ // WebSerializedScriptValue in the renderer process.
+ IPC_STRUCT_MEMBER(bool, is_data_raw_string)
+
+ // The serialized script value.
+ IPC_STRUCT_MEMBER(base::string16, data)
+
+ // When sent to the browser, this is the routing ID of the source frame in
+ // the source process. The browser replaces it with the routing ID of the
+ // equivalent frame proxy in the destination process.
+ IPC_STRUCT_MEMBER(int, source_routing_id)
+
+ // When sent from the browser, this is the routing ID of the source view in
+ // the destination process. This currently exists only to support legacy
+ // postMessage to Android WebView and will be removed once crbug.com/473258
+ // is fixed.
+ IPC_STRUCT_MEMBER(int, source_view_routing_id)
+
+ // The origin of the source frame.
+ IPC_STRUCT_MEMBER(base::string16, source_origin)
+
+ // The origin for the message's target.
+ IPC_STRUCT_MEMBER(base::string16, target_origin)
+
+ // Information about the MessagePorts this message contains.
+ IPC_STRUCT_MEMBER(std::vector<content::TransferredMessagePort>, message_ports)
+ IPC_STRUCT_MEMBER(std::vector<int>, new_routing_ids)
IPC_STRUCT_END()
IPC_STRUCT_TRAITS_BEGIN(content::CommonNavigationParams)
@@ -195,85 +253,90 @@ IPC_STRUCT_TRAITS_BEGIN(content::CommonNavigationParams)
IPC_STRUCT_TRAITS_MEMBER(transition)
IPC_STRUCT_TRAITS_MEMBER(navigation_type)
IPC_STRUCT_TRAITS_MEMBER(allow_download)
+ IPC_STRUCT_TRAITS_MEMBER(ui_timestamp)
+ IPC_STRUCT_TRAITS_MEMBER(report_type)
+ IPC_STRUCT_TRAITS_MEMBER(base_url_for_data_url)
+ IPC_STRUCT_TRAITS_MEMBER(history_url_for_data_url)
IPC_STRUCT_TRAITS_END()
-IPC_STRUCT_TRAITS_BEGIN(content::RequestNavigationParams)
+IPC_STRUCT_TRAITS_BEGIN(content::BeginNavigationParams)
+ IPC_STRUCT_TRAITS_MEMBER(method)
+ IPC_STRUCT_TRAITS_MEMBER(headers)
+ IPC_STRUCT_TRAITS_MEMBER(load_flags)
+ IPC_STRUCT_TRAITS_MEMBER(has_user_gesture)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(content::StartNavigationParams)
IPC_STRUCT_TRAITS_MEMBER(is_post)
IPC_STRUCT_TRAITS_MEMBER(extra_headers)
IPC_STRUCT_TRAITS_MEMBER(browser_initiated_post_data)
+ IPC_STRUCT_TRAITS_MEMBER(should_replace_current_entry)
+ IPC_STRUCT_TRAITS_MEMBER(transferred_request_child_id)
+ IPC_STRUCT_TRAITS_MEMBER(transferred_request_request_id)
IPC_STRUCT_TRAITS_END()
-IPC_STRUCT_TRAITS_BEGIN(content::CommitNavigationParams)
- IPC_STRUCT_TRAITS_MEMBER(page_state)
+IPC_STRUCT_TRAITS_BEGIN(content::RequestNavigationParams)
IPC_STRUCT_TRAITS_MEMBER(is_overriding_user_agent)
IPC_STRUCT_TRAITS_MEMBER(browser_navigation_start)
+ IPC_STRUCT_TRAITS_MEMBER(redirects)
+ IPC_STRUCT_TRAITS_MEMBER(can_load_local_resources)
+ IPC_STRUCT_TRAITS_MEMBER(request_time)
+ IPC_STRUCT_TRAITS_MEMBER(page_state)
+ IPC_STRUCT_TRAITS_MEMBER(page_id)
+ IPC_STRUCT_TRAITS_MEMBER(nav_entry_id)
+ IPC_STRUCT_TRAITS_MEMBER(intended_as_new_entry)
+ IPC_STRUCT_TRAITS_MEMBER(pending_history_list_offset)
+ IPC_STRUCT_TRAITS_MEMBER(current_history_list_offset)
+ IPC_STRUCT_TRAITS_MEMBER(current_history_list_length)
+ IPC_STRUCT_TRAITS_MEMBER(should_clear_history_list)
IPC_STRUCT_TRAITS_END()
-IPC_STRUCT_BEGIN(FrameMsg_Navigate_Params)
- // TODO(clamy): investigate which parameters are also needed in PlzNavigate
- // and move them to the appropriate NavigationParams struct.
-
- // These structs contain parameters shared by other navigation IPCs.
- IPC_STRUCT_MEMBER(content::CommonNavigationParams, common_params)
- IPC_STRUCT_MEMBER(content::RequestNavigationParams, request_params)
- IPC_STRUCT_MEMBER(content::CommitNavigationParams, commit_params)
-
- // The page_id for this navigation, or -1 if it is a new navigation. Back,
- // Forward, and Reload navigations should have a valid page_id. If the load
- // succeeds, then this page_id will be reflected in the resultant
- // FrameHostMsg_DidCommitProvisionalLoad message.
- IPC_STRUCT_MEMBER(int32, page_id)
-
- // If page_id is -1, then pending_history_list_offset will also be -1.
- // Otherwise, it contains the offset into the history list corresponding to
- // the current navigation.
- IPC_STRUCT_MEMBER(int, pending_history_list_offset)
-
- // Informs the RenderView of where its current page contents reside in
- // session history and the total size of the session history list.
- IPC_STRUCT_MEMBER(int, current_history_list_offset)
- IPC_STRUCT_MEMBER(int, current_history_list_length)
-
- // Informs the RenderView the session history should be cleared. In that
- // case, the RenderView needs to notify the browser that the clearing was
- // succesful when the navigation commits.
- IPC_STRUCT_MEMBER(bool, should_clear_history_list)
-
- // Base URL for use in WebKit's SubstituteData.
- // Is only used with data: URLs.
- IPC_STRUCT_MEMBER(GURL, base_url_for_data_url)
-
- // History URL for use in WebKit's SubstituteData.
- // Is only used with data: URLs.
- IPC_STRUCT_MEMBER(GURL, history_url_for_data_url)
-
- // Any redirect URLs that occurred before |url|. Useful for cross-process
- // navigations; defaults to empty.
- IPC_STRUCT_MEMBER(std::vector<GURL>, redirects)
-
- // Informs the RenderView the pending navigation should replace the current
- // history entry when it commits. This is used for cross-process redirects so
- // the transferred navigation can recover the navigation state.
- IPC_STRUCT_MEMBER(bool, should_replace_current_entry)
+IPC_STRUCT_TRAITS_BEGIN(content::FrameReplicationState)
+ IPC_STRUCT_TRAITS_MEMBER(origin)
+ IPC_STRUCT_TRAITS_MEMBER(sandbox_flags)
+ IPC_STRUCT_TRAITS_MEMBER(name)
+IPC_STRUCT_TRAITS_END()
- // The time the request was created. This is used by the old performance
- // infrastructure to set up DocumentState associated with the RenderView.
- // TODO(ppi): make it go away.
- IPC_STRUCT_MEMBER(base::Time, request_time)
+IPC_STRUCT_BEGIN(FrameMsg_NewFrame_WidgetParams)
+ // Gives the routing ID for the RenderWidget that will be attached to the
+ // new RenderFrame. If the RenderFrame does not need a RenderWidget, this
+ // is MSG_ROUTING_NONE and the other parameters are not read.
+ IPC_STRUCT_MEMBER(int, routing_id)
- // The following two members identify a previous request that has been
- // created before this navigation is being transferred to a new render view.
- // This serves the purpose of recycling the old request.
- // Unless this refers to a transferred navigation, these values are -1 and -1.
- IPC_STRUCT_MEMBER(int, transferred_request_child_id)
- IPC_STRUCT_MEMBER(int, transferred_request_request_id)
+ // Identifier for the output surface for the new RenderWidget.
+ IPC_STRUCT_MEMBER(int, surface_id)
- // Whether or not this url should be allowed to access local file://
- // resources.
- IPC_STRUCT_MEMBER(bool, can_load_local_resources)
+ // Tells the new RenderWidget whether it is initially hidden.
+ IPC_STRUCT_MEMBER(bool, hidden)
+IPC_STRUCT_END()
- // If not empty, which frame to navigate.
- IPC_STRUCT_MEMBER(std::string, frame_to_navigate)
+IPC_STRUCT_BEGIN(FrameMsg_NewFrame_Params)
+ // Specifies the routing ID of the new RenderFrame object.
+ IPC_STRUCT_MEMBER(int, routing_id)
+
+ // The new frame should be created as a child of the object
+ // identified by |parent_routing_id| or as top level if that is
+ // MSG_ROUTING_NONE.
+ IPC_STRUCT_MEMBER(int, parent_routing_id)
+
+ // Identifies the previous sibling of the new frame, so that the new frame is
+ // inserted into the correct place in the frame tree. If this is
+ // MSG_ROUTING_NONE, the frame will be created as the leftmost child of its
+ // parent frame, in front of any other children.
+ IPC_STRUCT_MEMBER(int, previous_sibling_routing_id)
+
+ // If a valid |proxy_routing_id| is provided, the new frame will be
+ // configured to replace the proxy on commit.
+ IPC_STRUCT_MEMBER(int, proxy_routing_id)
+
+ // When the new frame has a parent, |replication_state| holds the new frame's
+ // properties replicated from the process rendering the parent frame, such as
+ // the new frame's sandbox flags.
+ IPC_STRUCT_MEMBER(content::FrameReplicationState, replication_state)
+
+ // Specifies properties for a new RenderWidget that will be attached to the
+ // new RenderFrame (if one is needed).
+ IPC_STRUCT_MEMBER(FrameMsg_NewFrame_WidgetParams, widget_params)
IPC_STRUCT_END()
IPC_STRUCT_BEGIN(FrameHostMsg_OpenURL_Params)
@@ -284,26 +347,27 @@ IPC_STRUCT_BEGIN(FrameHostMsg_OpenURL_Params)
IPC_STRUCT_MEMBER(bool, user_gesture)
IPC_STRUCT_END()
-// PlzNavigate
-IPC_STRUCT_BEGIN(FrameHostMsg_BeginNavigation_Params)
- // TODO(clamy): See if it is possible to define a common struct between this
- // IPC and ResourceMsg_Request_Params.
+IPC_STRUCT_BEGIN(FrameMsg_TextTrackSettings_Params)
+ // Background color of the text track.
+ IPC_STRUCT_MEMBER(std::string, text_track_background_color)
+
+ // Font family of the text track text.
+ IPC_STRUCT_MEMBER(std::string, text_track_font_family)
- // The request method: GET, POST, etc.
- IPC_STRUCT_MEMBER(std::string, method)
+ // Font style of the text track text.
+ IPC_STRUCT_MEMBER(std::string, text_track_font_style)
- // Additional HTTP request headers.
- IPC_STRUCT_MEMBER(std::string, headers)
+ // Font variant of the text track text.
+ IPC_STRUCT_MEMBER(std::string, text_track_font_variant)
- // net::URLRequest load flags (net::LOAD_NORMAL) by default).
- IPC_STRUCT_MEMBER(int, load_flags)
+ // Color of the text track text.
+ IPC_STRUCT_MEMBER(std::string, text_track_text_color)
- // Optional resource request body (may be null).
- IPC_STRUCT_MEMBER(scoped_refptr<content::ResourceRequestBody>,
- request_body)
+ // Text shadow (edge style) of the text track text.
+ IPC_STRUCT_MEMBER(std::string, text_track_text_shadow)
- // True if the request was user initiated.
- IPC_STRUCT_MEMBER(bool, has_user_gesture)
+ // Size of the text track text.
+ IPC_STRUCT_MEMBER(std::string, text_track_text_size)
IPC_STRUCT_END()
#if defined(OS_MACOSX) || defined(OS_ANDROID)
@@ -362,28 +426,29 @@ IPC_MESSAGE_ROUTED2(FrameMsg_CustomContextMenuAction,
// Requests that the RenderFrame or RenderFrameProxy sets its opener to null.
IPC_MESSAGE_ROUTED0(FrameMsg_DisownOpener)
-// Instructs the renderer to create a new RenderFrame object with |routing_id|.
-// The new frame should be created as a child of the object identified by
-// |parent_routing_id| or as top level if that is MSG_ROUTING_NONE.
-// If a valid |proxy_routing_id| is provided, the new frame will be configured
-// to replace the proxy on commit.
-IPC_MESSAGE_CONTROL3(FrameMsg_NewFrame,
- int /* routing_id */,
- int /* parent_routing_id */,
- int /* proxy_routing_id */)
+// Requests that the RenderFrame send back a response after waiting for the
+// commit, activation and frame swap of the current DOM tree in blink.
+IPC_MESSAGE_ROUTED1(FrameMsg_VisualStateRequest, uint64 /* id */)
+
+// Instructs the renderer to create a new RenderFrame object.
+IPC_MESSAGE_CONTROL1(FrameMsg_NewFrame, FrameMsg_NewFrame_Params /* params */)
// Instructs the renderer to create a new RenderFrameProxy object with
// |routing_id|. The new proxy should be created as a child of the object
// identified by |parent_routing_id| or as top level if that is
// MSG_ROUTING_NONE.
-IPC_MESSAGE_CONTROL3(FrameMsg_NewFrameProxy,
+IPC_MESSAGE_CONTROL4(FrameMsg_NewFrameProxy,
int /* routing_id */,
int /* parent_routing_id */,
- int /* render_view_routing_id */)
+ int /* render_view_routing_id */,
+ content::FrameReplicationState /* replication_state */)
// Tells the renderer to perform the specified navigation, interrupting any
// existing navigation.
-IPC_MESSAGE_ROUTED1(FrameMsg_Navigate, FrameMsg_Navigate_Params)
+IPC_MESSAGE_ROUTED3(FrameMsg_Navigate,
+ content::CommonNavigationParams, /* common_params */
+ content::StartNavigationParams, /* start_params */
+ content::RequestNavigationParams /* request_params */)
// Instructs the renderer to invoke the frame's beforeunload event handler.
// Expects the result to be returned via FrameHostMsg_BeforeUnload_ACK.
@@ -392,12 +457,22 @@ IPC_MESSAGE_ROUTED0(FrameMsg_BeforeUnload)
// Instructs the frame to swap out for a cross-site transition, including
// running the unload event handler and creating a RenderFrameProxy with the
// given |proxy_routing_id|. Expects a SwapOut_ACK message when finished.
-IPC_MESSAGE_ROUTED1(FrameMsg_SwapOut,
- int /* proxy_routing_id */)
+IPC_MESSAGE_ROUTED3(FrameMsg_SwapOut,
+ int /* proxy_routing_id */,
+ bool /* is_loading */,
+ content::FrameReplicationState /* replication_state */)
// Instructs the frame to stop the load in progress, if any.
IPC_MESSAGE_ROUTED0(FrameMsg_Stop)
+// A message sent to RenderFrameProxy to indicate that its corresponding
+// RenderFrame has started loading a document.
+IPC_MESSAGE_ROUTED0(FrameMsg_DidStartLoading)
+
+// A message sent to RenderFrameProxy to indicate that its corresponding
+// RenderFrame has completed loading.
+IPC_MESSAGE_ROUTED0(FrameMsg_DidStopLoading)
+
// Request for the renderer to insert CSS into the frame.
IPC_MESSAGE_ROUTED1(FrameMsg_CSSInsertRequest,
std::string /* css */)
@@ -418,10 +493,19 @@ IPC_MESSAGE_ROUTED3(FrameMsg_JavaScriptExecuteRequest,
// ONLY FOR TESTS: Same as above but adds a fake UserGestureindicator around
// execution. (crbug.com/408426)
-IPC_MESSAGE_ROUTED3(FrameMsg_JavaScriptExecuteRequestForTests,
+IPC_MESSAGE_ROUTED4(FrameMsg_JavaScriptExecuteRequestForTests,
base::string16, /* javascript */
int, /* ID */
- bool /* if true, a reply is requested */)
+ bool, /* if true, a reply is requested */
+ bool /* if true, a user gesture indicator is created */)
+
+// Same as FrameMsg_JavaScriptExecuteRequest above except the script is
+// run in the isolated world specified by the fourth parameter.
+IPC_MESSAGE_ROUTED4(FrameMsg_JavaScriptExecuteRequestInIsolatedWorld,
+ base::string16, /* javascript */
+ int, /* ID */
+ bool, /* if true, a reply is requested */
+ int /* world_id */)
// Selects between the given start and end offsets in the currently focused
// editable field.
@@ -436,7 +520,19 @@ IPC_MESSAGE_ROUTED1(FrameMsg_SetupTransitionView,
// Tells the renderer to hide the elements specified by the supplied CSS
// selector, and activates any exiting-transition stylesheets.
-IPC_MESSAGE_ROUTED1(FrameMsg_BeginExitTransition,
+IPC_MESSAGE_ROUTED2(FrameMsg_BeginExitTransition,
+ std::string /* css_selector */,
+ bool /* exit_to_native_app */)
+
+// Tell the renderer to revert the exit transition done before
+IPC_MESSAGE_ROUTED0(FrameMsg_RevertExitTransition)
+
+// Tell the renderer to hide transition elements.
+IPC_MESSAGE_ROUTED1(FrameMsg_HideTransitionElements,
+ std::string /* css_selector */)
+
+// Tell the renderer to hide transition elements.
+IPC_MESSAGE_ROUTED1(FrameMsg_ShowTransitionElements,
std::string /* css_selector */)
// Tells the renderer to reload the frame, optionally ignoring the cache while
@@ -467,6 +563,28 @@ IPC_MESSAGE_ROUTED1(FrameMsg_AddStyleSheetByURL, std::string)
IPC_MESSAGE_ROUTED1(FrameMsg_SetAccessibilityMode,
AccessibilityMode)
+// Dispatch a load event in the iframe element containing this frame.
+IPC_MESSAGE_ROUTED0(FrameMsg_DispatchLoad)
+
+// Notifies the frame that its parent has changed the frame's sandbox flags.
+IPC_MESSAGE_ROUTED1(FrameMsg_DidUpdateSandboxFlags, content::SandboxFlags)
+
+// Update a proxy's window.name property. Used when the frame's name is
+// changed in another process.
+IPC_MESSAGE_ROUTED1(FrameMsg_DidUpdateName, std::string /* name */)
+
+// Update a proxy's replicated origin. Used when the frame is navigated to a
+// new origin.
+IPC_MESSAGE_ROUTED1(FrameMsg_DidUpdateOrigin, url::Origin /* origin */)
+
+// Send to the RenderFrame to set text track style settings.
+// Sent for top-level frames.
+IPC_MESSAGE_ROUTED1(FrameMsg_SetTextTrackSettings,
+ FrameMsg_TextTrackSettings_Params /* params */)
+
+// Posts a message from a frame in another process to the current renderer.
+IPC_MESSAGE_ROUTED1(FrameMsg_PostMessageEvent, FrameMsg_PostMessage_Params)
+
#if defined(OS_ANDROID)
// External popup menus.
@@ -483,20 +601,23 @@ IPC_MESSAGE_ROUTED1(FrameMsg_SelectPopupMenuItem,
#endif
// PlzNavigate
-// Tells the renderer that a navigation has been requested.
-IPC_MESSAGE_ROUTED2(FrameMsg_RequestNavigation,
- content::CommonNavigationParams, /* common_params */
- content::RequestNavigationParams /* request_params */)
-
-// PlzNavigate
// Tells the renderer that a navigation is ready to commit. The renderer should
// request |stream_url| to get access to the stream containing the body of the
// response.
IPC_MESSAGE_ROUTED4(FrameMsg_CommitNavigation,
- content::ResourceResponseHead, /* response */
- GURL, /* stream_url */
+ content::ResourceResponseHead, /* response */
+ GURL, /* stream_url */
content::CommonNavigationParams, /* common_params */
- content::CommitNavigationParams /* commit_params */)
+ content::RequestNavigationParams /* request_params */)
+
+// PlzNavigate
+// Tells the renderer that a navigation failed with the error code |error_code|
+// and that the renderer should display an appropriate error page.
+IPC_MESSAGE_ROUTED4(FrameMsg_FailedNavigation,
+ content::CommonNavigationParams, /* common_params */
+ content::RequestNavigationParams, /* request_params */
+ bool, /* stale_copy_in_cache */
+ int /* error_code */)
#if defined(ENABLE_PLUGINS)
// Notifies the renderer of updates to the Plugin Power Saver origin whitelist.
@@ -519,15 +640,22 @@ IPC_MESSAGE_ROUTED4(FrameHostMsg_AddMessageToConsole,
//
// Each of these messages will have a corresponding FrameHostMsg_Detach message
// sent when the frame is detached from the DOM.
-IPC_SYNC_MESSAGE_CONTROL2_1(FrameHostMsg_CreateChildFrame,
+IPC_SYNC_MESSAGE_CONTROL3_1(FrameHostMsg_CreateChildFrame,
int32 /* parent_routing_id */,
std::string /* frame_name */,
+ content::SandboxFlags /* sandbox flags */,
int32 /* new_routing_id */)
// Sent by the renderer to the parent RenderFrameHost when a child frame is
// detached from the DOM.
IPC_MESSAGE_ROUTED0(FrameHostMsg_Detach)
+// Indicates the renderer process is gone. This actually is sent by the
+// browser process to itself, but keeps the interface cleaner.
+IPC_MESSAGE_ROUTED2(FrameHostMsg_RenderProcessGone,
+ int, /* this really is base::TerminationStatus */
+ int /* exit_code */)
+
// Sent by the renderer when the frame becomes focused.
IPC_MESSAGE_ROUTED0(FrameHostMsg_FrameFocused)
@@ -557,6 +685,9 @@ IPC_MESSAGE_ROUTED3(FrameHostMsg_DidFailLoadWithError,
int /* error_code */,
base::string16 /* error_description */)
+// Sent when the renderer decides to ignore a navigation.
+IPC_MESSAGE_ROUTED0(FrameHostMsg_DidDropNavigation)
+
// Sent when the renderer starts loading the page. |to_different_document| will
// be true unless the load is a fragment navigation, or triggered by
// history.pushState/replaceState.
@@ -566,6 +697,9 @@ IPC_MESSAGE_ROUTED1(FrameHostMsg_DidStartLoading,
// Sent when the renderer is done loading a page.
IPC_MESSAGE_ROUTED0(FrameHostMsg_DidStopLoading)
+// Sent when the frame changes its window.name.
+IPC_MESSAGE_ROUTED1(FrameHostMsg_DidChangeName, std::string /* name */)
+
// Sent when the renderer changed the progress of a load.
IPC_MESSAGE_ROUTED1(FrameHostMsg_DidChangeLoadProgress,
double /* load_progress */)
@@ -578,8 +712,12 @@ IPC_MESSAGE_ROUTED1(FrameHostMsg_DidFinishLoad,
GURL /* validated_url */)
// Sent when after the onload handler has been invoked for the document
-// in this frame. Sent for top-level frames.
-IPC_MESSAGE_ROUTED0(FrameHostMsg_DocumentOnLoadCompleted)
+// in this frame. Sent for top-level frames. |report_type| and |ui_timestamp|
+// are used to report navigation metrics starting on the ui input event that
+// triggered the navigation timestamp.
+IPC_MESSAGE_ROUTED2(FrameHostMsg_DocumentOnLoadCompleted,
+ FrameMsg_UILoadMetricsReportType::Value /* report_type */,
+ base::TimeTicks /* ui_timestamp */)
// Notifies that the initial empty document of a view has been accessed.
// After this, it is no longer safe to show a pending navigation's URL without
@@ -594,6 +732,12 @@ IPC_MESSAGE_ROUTED0(FrameHostMsg_DidDisownOpener)
IPC_MESSAGE_ROUTED1(FrameHostMsg_DidAssignPageId,
int32 /* page_id */)
+// Notifies the browser that sandbox flags have changed for a subframe of this
+// frame.
+IPC_MESSAGE_ROUTED2(FrameHostMsg_DidChangeSandboxFlags,
+ int32 /* subframe_routing_id */,
+ content::SandboxFlags /* updated_flags */)
+
// Changes the title for the page in the UI when the page is navigated or the
// title changes. Sent for top-level frames.
IPC_MESSAGE_ROUTED2(FrameHostMsg_UpdateTitle,
@@ -614,6 +758,30 @@ IPC_MESSAGE_ROUTED2(FrameHostMsg_DomOperationResponse,
std::string /* json_string */,
int /* automation_id */)
+// Used to set a cookie. The cookie is set asynchronously, but will be
+// available to a subsequent FrameHostMsg_GetCookies request.
+IPC_MESSAGE_CONTROL4(FrameHostMsg_SetCookie,
+ int /* render_frame_id */,
+ GURL /* url */,
+ GURL /* first_party_for_cookies */,
+ std::string /* cookie */)
+
+// Used to get cookies for the given URL. This may block waiting for a
+// previous SetCookie message to be processed.
+IPC_SYNC_MESSAGE_CONTROL3_1(FrameHostMsg_GetCookies,
+ int /* render_frame_id */,
+ GURL /* url */,
+ GURL /* first_party_for_cookies */,
+ std::string /* cookies */)
+
+// Used to check if cookies are enabled for the given URL. This may block
+// waiting for a previous SetCookie message to be processed.
+IPC_SYNC_MESSAGE_CONTROL3_1(FrameHostMsg_CookiesEnabled,
+ int /* render_frame_id */,
+ GURL /* url */,
+ GURL /* first_party_for_cookies */,
+ bool /* cookies_enabled */)
+
#if defined(ENABLE_PLUGINS)
// Sent to the browser when the renderer detects it is blocked on a pepper
// plugin message for too long. This is also sent when it becomes unhung
@@ -774,14 +942,32 @@ IPC_MESSAGE_CONTROL1(FrameHostMsg_AddNavigationTransitionData,
// PlzNavigate
// Tells the browser to perform a navigation.
-IPC_MESSAGE_ROUTED2(FrameHostMsg_BeginNavigation,
- FrameHostMsg_BeginNavigation_Params,
- content::CommonNavigationParams)
+IPC_MESSAGE_ROUTED3(FrameHostMsg_BeginNavigation,
+ content::CommonNavigationParams,
+ content::BeginNavigationParams,
+ scoped_refptr<content::ResourceRequestBody>)
// Sent once a paint happens after the first non empty layout. In other words
// after the frame has painted something.
IPC_MESSAGE_ROUTED0(FrameHostMsg_DidFirstVisuallyNonEmptyPaint)
+// Sent as a response to FrameMsg_VisualStateRequest.
+// The message is delivered using RenderWidget::QueueMessage.
+IPC_MESSAGE_ROUTED1(FrameHostMsg_VisualStateResponse, uint64 /* id */)
+
+// Puts the browser into "tab fullscreen" mode for the sending renderer.
+// See the comment in chrome/browser/ui/browser.h for more details.
+IPC_MESSAGE_ROUTED1(FrameHostMsg_ToggleFullscreen, bool /* enter_fullscreen */)
+
+// Dispatch a load event for this frame in the iframe element of an
+// out-of-process parent frame.
+IPC_MESSAGE_ROUTED0(FrameHostMsg_DispatchLoad)
+
+// Sent to the browser from a frame proxy to post a message to the frame's
+// active renderer.
+IPC_MESSAGE_ROUTED1(FrameHostMsg_RouteMessageEvent,
+ FrameMsg_PostMessage_Params)
+
#if defined(OS_MACOSX) || defined(OS_ANDROID)
// Message to show/hide a popup menu using native controls.
diff --git a/chromium/content/common/frame_replication_state.cc b/chromium/content/common/frame_replication_state.cc
new file mode 100644
index 00000000000..1c1530ca89d
--- /dev/null
+++ b/chromium/content/common/frame_replication_state.cc
@@ -0,0 +1,21 @@
+// Copyright 2014 The Chromium Authors. 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/common/frame_replication_state.h"
+
+namespace content {
+
+FrameReplicationState::FrameReplicationState()
+ : FrameReplicationState("", SandboxFlags::NONE) {
+}
+
+FrameReplicationState::FrameReplicationState(const std::string& name,
+ SandboxFlags sandbox_flags)
+ : origin(), sandbox_flags(sandbox_flags), name(name) {
+}
+
+FrameReplicationState::~FrameReplicationState() {
+}
+
+} // namespace content
diff --git a/chromium/content/common/frame_replication_state.h b/chromium/content/common/frame_replication_state.h
new file mode 100644
index 00000000000..86e53b9884b
--- /dev/null
+++ b/chromium/content/common/frame_replication_state.h
@@ -0,0 +1,95 @@
+// Copyright 2014 The Chromium Authors. 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_COMMON_FRAME_REPLICATION_STATE_H_
+#define CONTENT_COMMON_FRAME_REPLICATION_STATE_H_
+
+#include "content/common/content_export.h"
+#include "url/origin.h"
+
+namespace content {
+
+// Sandboxing flags for iframes. These flags are set via an iframe's "sandbox"
+// attribute in the renderer process and forwarded to the browser process,
+// which replicates them to other processes as needed. For a list of sandbox
+// flags, see
+// http://www.whatwg.org/specs/web-apps/current-work/#attr-iframe-sandbox
+// Must be kept in sync with blink::WebSandboxFlags. Enforced in
+// render_frame_impl.cc.
+enum class SandboxFlags : int {
+ NONE = 0,
+ NAVIGATION = 1,
+ PLUGINS = 1 << 1,
+ ORIGIN = 1 << 2,
+ FORMS = 1 << 3,
+ SCRIPTS = 1 << 4,
+ TOP_NAVIGATION = 1 << 5,
+ POPUPS = 1 << 6,
+ AUTOMATIC_FEATURES = 1 << 7,
+ POINTER_LOCK = 1 << 8,
+ DOCUMENT_DOMAIN = 1 << 9,
+ ORIENTATION_LOCK = 1 << 10,
+ ALL = -1
+};
+
+inline SandboxFlags operator&(SandboxFlags a, SandboxFlags b) {
+ return static_cast<SandboxFlags>(static_cast<int>(a) & static_cast<int>(b));
+}
+
+inline SandboxFlags operator~(SandboxFlags flags) {
+ return static_cast<SandboxFlags>(~static_cast<int>(flags));
+}
+
+// This structure holds information that needs to be replicated between a
+// RenderFrame and any of its associated RenderFrameProxies.
+struct CONTENT_EXPORT FrameReplicationState {
+ FrameReplicationState();
+ FrameReplicationState(const std::string& name, SandboxFlags sandbox_flags);
+ ~FrameReplicationState();
+
+ // Current serialized security origin of the frame. Unique origins are
+ // represented as the string "null" per RFC 6454. This field is updated
+ // whenever a frame navigation commits.
+ //
+ // TODO(alexmos): For now, |origin| updates are immediately sent to all frame
+ // proxies when in --site-per-process mode. This isn't ideal, since Blink
+ // typically needs a proxy's origin only when performing security checks on
+ // the ancestors of a local frame. So, as a future improvement, we could
+ // delay sending origin updates to proxies until they have a local descendant
+ // (if ever). This would reduce leaking a user's browsing history into a
+ // compromized renderer.
+ url::Origin origin;
+
+ // Current sandbox flags of the frame. |sandbox_flags| are initialized for
+ // new child frames using the value of the <iframe> element's "sandbox"
+ // attribute. They are updated dynamically whenever a parent frame updates an
+ // <iframe>'s sandbox attribute via JavaScript.
+ //
+ // Updates to |sandbox_flags| are sent to proxies, but only after a
+ // subsequent navigation of the (sandboxed) frame, since the flags only take
+ // effect on navigation (see also FrameTreeNode::effective_sandbox_flags_).
+ // The proxies need updated flags so that they can be inherited properly if a
+ // proxy ever becomes a parent of a local frame.
+ SandboxFlags sandbox_flags;
+
+ // The assigned name of the frame. This name can be empty, unlike the unique
+ // name generated internally in the DOM tree.
+ //
+ // |name| is set when a new child frame is created using the value of the
+ // <iframe> element's "name" attribute (see
+ // RenderFrameHostImpl::OnCreateChildFrame), and it is updated dynamically
+ // whenever a frame sets its window.name.
+ //
+ // |name| updates are immediately sent to all frame proxies (when in
+ // --site-per-process mode), so that other frames can look up or navigate a
+ // frame using its updated name (e.g., using window.open(url, frame_name)).
+ std::string name;
+
+ // TODO(alexmos): Eventually, this structure can also hold other state that
+ // needs to be replicated, such as frame sizing info.
+};
+
+} // namespace content
+
+#endif // CONTENT_COMMON_FRAME_REPLICATION_STATE_H_
diff --git a/chromium/content/common/gamepad_param_traits.cc b/chromium/content/common/gamepad_param_traits.cc
index 356d8753dfa..cc60d7c86cd 100644
--- a/chromium/content/common/gamepad_param_traits.cc
+++ b/chromium/content/common/gamepad_param_traits.cc
@@ -42,7 +42,7 @@ bool ParamTraits<WebGamepad>::Read(
WebGamepad* p) {
int length;
const char* data;
- if (!m->ReadData(iter, &data, &length) || length != sizeof(WebGamepad))
+ if (!iter->ReadData(&data, &length) || length != sizeof(WebGamepad))
return false;
memcpy(p, data, sizeof(WebGamepad));
diff --git a/chromium/content/common/gamepad_param_traits.h b/chromium/content/common/gamepad_param_traits.h
index aa9e4402413..7e694e09e09 100644
--- a/chromium/content/common/gamepad_param_traits.h
+++ b/chromium/content/common/gamepad_param_traits.h
@@ -29,4 +29,4 @@ struct ParamTraits<blink::WebGamepad> {
} // namespace IPC
-#endif
+#endif // CONTENT_COMMON_GAMEPAD_PARAM_TRAITS_H_
diff --git a/chromium/content/common/geofencing_messages.h b/chromium/content/common/geofencing_messages.h
index 152b108e0dc..e79b3aa0fc7 100644
--- a/chromium/content/common/geofencing_messages.h
+++ b/chromium/content/common/geofencing_messages.h
@@ -4,7 +4,7 @@
// IPC message for geofencing
-#include "content/common/geofencing_status.h"
+#include "content/common/geofencing_types.h"
#include "ipc/ipc_message_macros.h"
#include "third_party/WebKit/public/platform/WebCircularGeofencingRegion.h"
@@ -23,6 +23,9 @@ typedef std::map<std::string, blink::WebCircularGeofencingRegion>
IPC_ENUM_TRAITS_MAX_VALUE(content::GeofencingStatus,
content::GEOFENCING_STATUS_LAST)
+IPC_ENUM_TRAITS_MAX_VALUE(content::GeofencingMockState,
+ content::GeofencingMockState::LAST)
+
IPC_STRUCT_TRAITS_BEGIN(blink::WebCircularGeofencingRegion)
IPC_STRUCT_TRAITS_MEMBER(latitude)
IPC_STRUCT_TRAITS_MEMBER(longitude)
@@ -48,6 +51,13 @@ IPC_MESSAGE_CONTROL3(GeofencingHostMsg_GetRegisteredRegions,
int /* request_id */,
int64 /* serviceworker_registration_id */)
+IPC_MESSAGE_CONTROL1(GeofencingHostMsg_SetMockProvider,
+ content::GeofencingMockState /* mock_state */)
+
+IPC_MESSAGE_CONTROL2(GeofencingHostMsg_SetMockPosition,
+ double /* latitude */,
+ double /* longitude */)
+
// Messages sent from the browser to the child process.
// Reply in response to GeofencingHostMsg_RegisterRegion
diff --git a/chromium/content/common/geofencing_status.cc b/chromium/content/common/geofencing_status.cc
deleted file mode 100644
index ffca197bc85..00000000000
--- a/chromium/content/common/geofencing_status.cc
+++ /dev/null
@@ -1,32 +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/common/geofencing_status.h"
-
-#include "base/logging.h"
-
-namespace content {
-
-const char* GeofencingStatusToString(GeofencingStatus status) {
- switch (status) {
- case GEOFENCING_STATUS_OK:
- return "Operation has succeeded";
-
- case GEOFENCING_STATUS_OPERATION_FAILED_NO_SERVICE_WORKER:
- return "Operation failed - no Service Worker";
-
- case GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE:
- return "Operation failed - geofencing not available";
-
- case GEOFENCING_STATUS_UNREGISTRATION_FAILED_NOT_REGISTERED:
- return "Unregistration failed - no region registered with given ID";
-
- case GEOFENCING_STATUS_ERROR:
- return "Operation has failed (unspecified reason)";
- }
- NOTREACHED();
- return "";
-}
-
-} // namespace content
diff --git a/chromium/content/common/geofencing_status.h b/chromium/content/common/geofencing_status.h
deleted file mode 100644
index 13a1de8a2f4..00000000000
--- a/chromium/content/common/geofencing_status.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_COMMON_GEOFENCING_STATUS_H_
-#define CONTENT_COMMON_GEOFENCING_STATUS_H_
-
-namespace content {
-
-enum GeofencingStatus {
- // Everything is ok.
- GEOFENCING_STATUS_OK,
-
- // Operation failed because there is no Service Worker.
- GEOFENCING_STATUS_OPERATION_FAILED_NO_SERVICE_WORKER,
-
- // Operation failed because geofencing is not available.
- GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE,
-
- // Unregistering failed because region was not registered.
- GEOFENCING_STATUS_UNREGISTRATION_FAILED_NOT_REGISTERED,
-
- // Generic error.
- GEOFENCING_STATUS_ERROR,
-
- // Used for IPC message range checks.
- GEOFENCING_STATUS_LAST = GEOFENCING_STATUS_ERROR
-};
-
-const char* GeofencingStatusToString(GeofencingStatus status);
-
-} // namespace content
-
-#endif // CONTENT_COMMON_GEOFENCING_STATUS_H_
diff --git a/chromium/content/common/geofencing_types.cc b/chromium/content/common/geofencing_types.cc
new file mode 100644
index 00000000000..ab8babe6b80
--- /dev/null
+++ b/chromium/content/common/geofencing_types.cc
@@ -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.
+
+#include "content/common/geofencing_types.h"
+
+#include "base/logging.h"
+
+namespace content {
+
+const char* GeofencingStatusToString(GeofencingStatus status) {
+ switch (status) {
+ case GEOFENCING_STATUS_OK:
+ return "Operation has succeeded";
+
+ case GEOFENCING_STATUS_OPERATION_FAILED_NO_SERVICE_WORKER:
+ return "Operation failed - no Service Worker";
+
+ case GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE:
+ return "Operation failed - geofencing not available";
+
+ case GEOFENCING_STATUS_UNREGISTRATION_FAILED_NOT_REGISTERED:
+ return "Unregistration failed - no region registered with given ID";
+
+ case GEOFENCING_STATUS_ERROR:
+ return "Operation has failed (unspecified reason)";
+ }
+ NOTREACHED();
+ return "";
+}
+
+} // namespace content
diff --git a/chromium/content/common/geofencing_types.h b/chromium/content/common/geofencing_types.h
new file mode 100644
index 00000000000..12899898ee5
--- /dev/null
+++ b/chromium/content/common/geofencing_types.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_COMMON_GEOFENCING_TYPES_H_
+#define CONTENT_COMMON_GEOFENCING_TYPES_H_
+
+namespace content {
+
+enum GeofencingStatus {
+ // Everything is ok.
+ GEOFENCING_STATUS_OK,
+
+ // Operation failed because there is no Service Worker.
+ GEOFENCING_STATUS_OPERATION_FAILED_NO_SERVICE_WORKER,
+
+ // Operation failed because geofencing is not available.
+ GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE,
+
+ // Unregistering failed because region was not registered.
+ GEOFENCING_STATUS_UNREGISTRATION_FAILED_NOT_REGISTERED,
+
+ // Generic error.
+ GEOFENCING_STATUS_ERROR,
+
+ // Used for IPC message range checks.
+ GEOFENCING_STATUS_LAST = GEOFENCING_STATUS_ERROR
+};
+
+const char* GeofencingStatusToString(GeofencingStatus status);
+
+enum class GeofencingMockState {
+ // Not currently mocking, use real geofencing service.
+ NONE,
+
+ // Mock a geofencing service that isn't available.
+ SERVICE_UNAVAILABLE,
+
+ // Mock a geofencing service that is available.
+ SERVICE_AVAILABLE,
+
+ // Used for IPC message range checks.
+ LAST = SERVICE_AVAILABLE
+};
+
+} // namespace content
+
+#endif // CONTENT_COMMON_GEOFENCING_TYPES_H_
diff --git a/chromium/content/common/geolocation_messages.h b/chromium/content/common/geolocation_messages.h
deleted file mode 100644
index b66a1919b79..00000000000
--- a/chromium/content/common/geolocation_messages.h
+++ /dev/null
@@ -1,46 +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.
-
-// IPC messages for geolocation.
-// Multiply-included message file, hence no include guard.
-
-#include "content/public/common/geoposition.h"
-#include "ipc/ipc_message_macros.h"
-#include "url/gurl.h"
-
-#define IPC_MESSAGE_START GeolocationMsgStart
-
-IPC_ENUM_TRAITS_MAX_VALUE(content::Geoposition::ErrorCode,
- content::Geoposition::ERROR_CODE_LAST)
-
-IPC_STRUCT_TRAITS_BEGIN(content::Geoposition)
- IPC_STRUCT_TRAITS_MEMBER(latitude)
- IPC_STRUCT_TRAITS_MEMBER(longitude)
- IPC_STRUCT_TRAITS_MEMBER(altitude)
- IPC_STRUCT_TRAITS_MEMBER(accuracy)
- IPC_STRUCT_TRAITS_MEMBER(altitude_accuracy)
- IPC_STRUCT_TRAITS_MEMBER(heading)
- IPC_STRUCT_TRAITS_MEMBER(speed)
- IPC_STRUCT_TRAITS_MEMBER(timestamp)
- IPC_STRUCT_TRAITS_MEMBER(error_code)
- IPC_STRUCT_TRAITS_MEMBER(error_message)
-IPC_STRUCT_TRAITS_END()
-
-// Messages sent from the browser to the renderer.
-
-// Reply in response to GeolocationHostMsg_RequestPermission.
-IPC_MESSAGE_ROUTED2(GeolocationMsg_PermissionSet,
- int /* bridge_id */,
- bool /* is_allowed */)
-
-// Messages sent from the renderer to the browser.
-
-// The |bridge_id| representing |host| is requesting permission to access
-// geolocation position. This will be replied by GeolocationMsg_PermissionSet.
-// TODO(mlamouri): |origin| should be a security origin to guarantee that a
-// proper origin is passed.
-IPC_MESSAGE_ROUTED3(GeolocationHostMsg_RequestPermission,
- int /* bridge_id */,
- GURL /* origin in the frame requesting geolocation */,
- bool /* user_gesture */)
diff --git a/chromium/content/common/geolocation_service.mojom b/chromium/content/common/geolocation_service.mojom
index 00d56400ba4..a9c4e488646 100644
--- a/chromium/content/common/geolocation_service.mojom
+++ b/chromium/content/common/geolocation_service.mojom
@@ -6,14 +6,15 @@ module content;
import "content/public/common/mojo_geoposition.mojom";
-// The Geolocation service provides updates on the device's location to its
-// client. By default, it provides updates with low accuracy, but
-// |SetHighAccuracy()| can be called to change this.
-[Client=GeolocationServiceClient]
+// The Geolocation service provides updates on the device's location. By
+// default, it provides updates with low accuracy, but |SetHighAccuracy()| may
+// be called to change this.
interface GeolocationService {
SetHighAccuracy(bool high_accuracy);
-};
-interface GeolocationServiceClient {
- OnLocationUpdate(MojoGeoposition geoposition);
+ // Position is reported once it changes or immediately (to report the initial
+ // position) if this is the first call to QueryNextPosition on this instance.
+ // Position updates may be throttled by the service. Overlapping calls to
+ // this method are prohibited and will be treated as a connection error.
+ QueryNextPosition() => (MojoGeoposition geoposition);
};
diff --git a/chromium/content/common/gpu/client/DEPS b/chromium/content/common/gpu/client/DEPS
index 2e15de3446b..1aea6635f14 100644
--- a/chromium/content/common/gpu/client/DEPS
+++ b/chromium/content/common/gpu/client/DEPS
@@ -1,3 +1,7 @@
+include_rules = [
+ "+cc/blink",
+]
+
specific_include_rules = {
# Tests can make use of content/browser/ infrastructure.
".*browsertest\.cc": [
diff --git a/chromium/content/common/gpu/client/command_buffer_metrics.cc b/chromium/content/common/gpu/client/command_buffer_metrics.cc
new file mode 100644
index 00000000000..d16f2761905
--- /dev/null
+++ b/chromium/content/common/gpu/client/command_buffer_metrics.cc
@@ -0,0 +1,153 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/common/gpu/client/command_buffer_metrics.h"
+
+#include "base/metrics/histogram.h"
+
+namespace content {
+
+namespace {
+
+enum CommandBufferContextLostReason {
+ // Don't add new values here.
+ CONTEXT_INIT_FAILED,
+ CONTEXT_LOST_GPU_CHANNEL_ERROR,
+ CONTEXT_PARSE_ERROR_INVALID_SIZE,
+ CONTEXT_PARSE_ERROR_OUT_OF_BOUNDS,
+ CONTEXT_PARSE_ERROR_UNKNOWN_COMMAND,
+ CONTEXT_PARSE_ERROR_INVALID_ARGS,
+ CONTEXT_PARSE_ERROR_GENERIC_ERROR,
+ CONTEXT_LOST_GUILTY,
+ CONTEXT_LOST_INNOCENT,
+ CONTEXT_LOST_UNKNOWN,
+ CONTEXT_LOST_OUT_OF_MEMORY,
+ CONTEXT_LOST_MAKECURRENT_FAILED,
+ // Add new values here and update _MAX_ENUM.
+ CONTEXT_LOST_REASON_MAX_ENUM = CONTEXT_LOST_MAKECURRENT_FAILED
+};
+
+CommandBufferContextLostReason GetContextLostReason(
+ gpu::error::Error error,
+ gpu::error::ContextLostReason reason) {
+ if (error == gpu::error::kLostContext) {
+ switch (reason) {
+ case gpu::error::kGuilty:
+ return CONTEXT_LOST_GUILTY;
+ case gpu::error::kInnocent:
+ return CONTEXT_LOST_INNOCENT;
+ case gpu::error::kUnknown:
+ return CONTEXT_LOST_UNKNOWN;
+ case gpu::error::kOutOfMemory:
+ return CONTEXT_LOST_OUT_OF_MEMORY;
+ case gpu::error::kMakeCurrentFailed:
+ return CONTEXT_LOST_MAKECURRENT_FAILED;
+ case gpu::error::kGpuChannelLost:
+ return CONTEXT_LOST_GPU_CHANNEL_ERROR;
+ }
+ }
+ switch (error) {
+ case gpu::error::kInvalidSize:
+ return CONTEXT_PARSE_ERROR_INVALID_SIZE;
+ case gpu::error::kOutOfBounds:
+ return CONTEXT_PARSE_ERROR_OUT_OF_BOUNDS;
+ case gpu::error::kUnknownCommand:
+ return CONTEXT_PARSE_ERROR_UNKNOWN_COMMAND;
+ case gpu::error::kInvalidArguments:
+ return CONTEXT_PARSE_ERROR_INVALID_ARGS;
+ case gpu::error::kGenericError:
+ return CONTEXT_PARSE_ERROR_GENERIC_ERROR;
+ case gpu::error::kDeferCommandUntilLater:
+ case gpu::error::kNoError:
+ case gpu::error::kLostContext:
+ NOTREACHED();
+ return CONTEXT_LOST_UNKNOWN;
+ }
+ NOTREACHED();
+ return CONTEXT_LOST_UNKNOWN;
+}
+
+void RecordContextLost(CommandBufferContextType type,
+ CommandBufferContextLostReason reason) {
+ switch (type) {
+ case BROWSER_COMPOSITOR_ONSCREEN_CONTEXT:
+ UMA_HISTOGRAM_ENUMERATION("GPU.ContextLost.BrowserCompositor", reason,
+ CONTEXT_LOST_REASON_MAX_ENUM);
+ break;
+ case BROWSER_OFFSCREEN_MAINTHREAD_CONTEXT:
+ UMA_HISTOGRAM_ENUMERATION("GPU.ContextLost.BrowserMainThread", reason,
+ CONTEXT_LOST_REASON_MAX_ENUM);
+ break;
+ case RENDER_COMPOSITOR_CONTEXT:
+ UMA_HISTOGRAM_ENUMERATION("GPU.ContextLost.RenderCompositor", reason,
+ CONTEXT_LOST_REASON_MAX_ENUM);
+ break;
+ case RENDER_WORKER_CONTEXT:
+ UMA_HISTOGRAM_ENUMERATION("GPU.ContextLost.RenderWorker", reason,
+ CONTEXT_LOST_REASON_MAX_ENUM);
+ break;
+ case RENDERER_MAINTHREAD_CONTEXT:
+ UMA_HISTOGRAM_ENUMERATION("GPU.ContextLost.RenderMainThread", reason,
+ CONTEXT_LOST_REASON_MAX_ENUM);
+ break;
+ case GPU_VIDEO_ACCELERATOR_CONTEXT:
+ UMA_HISTOGRAM_ENUMERATION("GPU.ContextLost.VideoAccelerator", reason,
+ CONTEXT_LOST_REASON_MAX_ENUM);
+ break;
+ case OFFSCREEN_VIDEO_CAPTURE_CONTEXT:
+ UMA_HISTOGRAM_ENUMERATION("GPU.ContextLost.VideoCapture", reason,
+ CONTEXT_LOST_REASON_MAX_ENUM);
+ break;
+ case OFFSCREEN_CONTEXT_FOR_WEBGL:
+ UMA_HISTOGRAM_ENUMERATION("GPU.ContextLost.WebGL", reason,
+ CONTEXT_LOST_REASON_MAX_ENUM);
+ break;
+ case CONTEXT_TYPE_UNKNOWN:
+ UMA_HISTOGRAM_ENUMERATION("GPU.ContextLost.Unknown", reason,
+ CONTEXT_LOST_REASON_MAX_ENUM);
+ break;
+ }
+}
+
+} // anonymous namespace
+
+std::string CommandBufferContextTypeToString(CommandBufferContextType type) {
+ switch (type) {
+ case OFFSCREEN_CONTEXT_FOR_TESTING:
+ return "Context-For-Testing";
+ case BROWSER_COMPOSITOR_ONSCREEN_CONTEXT:
+ return "Compositor";
+ case BROWSER_OFFSCREEN_MAINTHREAD_CONTEXT:
+ return "Offscreen-MainThread";
+ case RENDER_COMPOSITOR_CONTEXT:
+ return "RenderCompositor";
+ case RENDER_WORKER_CONTEXT:
+ return "RenderWorker";
+ case RENDERER_MAINTHREAD_CONTEXT:
+ return "Offscreen-MainThread";
+ case GPU_VIDEO_ACCELERATOR_CONTEXT:
+ return "GPU-VideoAccelerator-Offscreen";
+ case OFFSCREEN_VIDEO_CAPTURE_CONTEXT:
+ return "Offscreen-CaptureThread";
+ case OFFSCREEN_CONTEXT_FOR_WEBGL:
+ return "Offscreen-For-WebGL";
+ default:
+ NOTREACHED();
+ return "unknown";
+ }
+}
+
+void UmaRecordContextInitFailed(CommandBufferContextType type) {
+ RecordContextLost(type, CONTEXT_INIT_FAILED);
+}
+
+void UmaRecordContextLost(CommandBufferContextType type,
+ gpu::error::Error error,
+ gpu::error::ContextLostReason reason) {
+ CommandBufferContextLostReason converted_reason =
+ GetContextLostReason(error, reason);
+ RecordContextLost(type, converted_reason);
+}
+
+} // namespace content
diff --git a/chromium/content/common/gpu/client/command_buffer_metrics.h b/chromium/content/common/gpu/client/command_buffer_metrics.h
new file mode 100644
index 00000000000..e198d8579d9
--- /dev/null
+++ b/chromium/content/common/gpu/client/command_buffer_metrics.h
@@ -0,0 +1,37 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_COMMON_GPU_CLIENT_COMMAND_BUFFER_METRICS_H_
+#define CONTENT_COMMON_GPU_CLIENT_COMMAND_BUFFER_METRICS_H_
+
+#include <string>
+
+#include "gpu/command_buffer/common/constants.h"
+
+namespace content {
+
+enum CommandBufferContextType {
+ BROWSER_COMPOSITOR_ONSCREEN_CONTEXT,
+ BROWSER_OFFSCREEN_MAINTHREAD_CONTEXT,
+ RENDER_COMPOSITOR_CONTEXT,
+ RENDER_WORKER_CONTEXT,
+ RENDERER_MAINTHREAD_CONTEXT,
+ GPU_VIDEO_ACCELERATOR_CONTEXT,
+ OFFSCREEN_VIDEO_CAPTURE_CONTEXT,
+ OFFSCREEN_CONTEXT_FOR_WEBGL,
+ CONTEXT_TYPE_UNKNOWN,
+ OFFSCREEN_CONTEXT_FOR_TESTING = CONTEXT_TYPE_UNKNOWN,
+};
+
+std::string CommandBufferContextTypeToString(CommandBufferContextType type);
+
+void UmaRecordContextInitFailed(CommandBufferContextType type);
+
+void UmaRecordContextLost(CommandBufferContextType type,
+ gpu::error::Error error,
+ gpu::error::ContextLostReason reason);
+
+} // namespace content
+
+#endif // CONTENT_COMMON_GPU_CLIENT_COMMAND_BUFFER_METRICS_H_
diff --git a/chromium/content/common/gpu/client/command_buffer_proxy_impl.cc b/chromium/content/common/gpu/client/command_buffer_proxy_impl.cc
index 33648837349..8ca94b32e45 100644
--- a/chromium/content/common/gpu/client/command_buffer_proxy_impl.cc
+++ b/chromium/content/common/gpu/client/command_buffer_proxy_impl.cc
@@ -4,11 +4,13 @@
#include "content/common/gpu/client/command_buffer_proxy_impl.h"
+#include <vector>
+
#include "base/callback.h"
-#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/memory/shared_memory.h"
#include "base/stl_util.h"
+#include "base/trace_event/trace_event.h"
#include "content/common/child_process_messages.h"
#include "content/common/gpu/client/gpu_channel_host.h"
#include "content/common/gpu/client/gpu_video_decode_accelerator_host.h"
@@ -20,18 +22,19 @@
#include "gpu/command_buffer/common/command_buffer_shared.h"
#include "gpu/command_buffer/common/gpu_memory_allocation.h"
#include "gpu/command_buffer/service/image_factory.h"
-#include "ui/gfx/size.h"
+#include "ui/gfx/geometry/size.h"
#include "ui/gl/gl_bindings.h"
namespace content {
-CommandBufferProxyImpl::CommandBufferProxyImpl(
- GpuChannelHost* channel,
- int route_id)
- : channel_(channel),
+CommandBufferProxyImpl::CommandBufferProxyImpl(GpuChannelHost* channel,
+ int route_id)
+ : lock_(nullptr),
+ channel_(channel),
route_id_(route_id),
flush_count_(0),
last_put_offset_(-1),
+ last_barrier_put_offset_(-1),
next_signal_id_(0) {
}
@@ -42,6 +45,9 @@ CommandBufferProxyImpl::~CommandBufferProxyImpl() {
}
bool CommandBufferProxyImpl::OnMessageReceived(const IPC::Message& message) {
+ scoped_ptr<base::AutoLock> lock;
+ if (lock_)
+ lock.reset(new base::AutoLock(*lock_));
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(CommandBufferProxyImpl, message)
IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_Destroyed, OnDestroyed);
@@ -52,6 +58,8 @@ bool CommandBufferProxyImpl::OnMessageReceived(const IPC::Message& message) {
OnSignalSyncPointAck);
IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_SwapBuffersCompleted,
OnSwapBuffersCompleted);
+ IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_UpdateVSyncParameters,
+ OnUpdateVSyncParameters);
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
@@ -60,22 +68,27 @@ bool CommandBufferProxyImpl::OnMessageReceived(const IPC::Message& message) {
}
void CommandBufferProxyImpl::OnChannelError() {
- OnDestroyed(gpu::error::kUnknown);
+ scoped_ptr<base::AutoLock> lock;
+ if (lock_)
+ lock.reset(new base::AutoLock(*lock_));
+ OnDestroyed(gpu::error::kGpuChannelLost, gpu::error::kLostContext);
}
-void CommandBufferProxyImpl::OnDestroyed(gpu::error::ContextLostReason reason) {
+void CommandBufferProxyImpl::OnDestroyed(gpu::error::ContextLostReason reason,
+ gpu::error::Error error) {
+ CheckLock();
// Prevent any further messages from being sent.
channel_ = NULL;
// When the client sees that the context is lost, they should delete this
// CommandBufferProxyImpl and create a new one.
- last_state_.error = gpu::error::kLostContext;
+ last_state_.error = error;
last_state_.context_lost_reason = reason;
- if (!channel_error_callback_.is_null()) {
- channel_error_callback_.Run();
+ if (!context_lost_callback_.is_null()) {
+ context_lost_callback_.Run();
// Avoid calling the error callback more than once.
- channel_error_callback_.Reset();
+ context_lost_callback_.Reset();
}
}
@@ -88,6 +101,7 @@ void CommandBufferProxyImpl::OnConsoleMessage(
void CommandBufferProxyImpl::SetMemoryAllocationChangedCallback(
const MemoryAllocationChangedCallback& callback) {
+ CheckLock();
if (last_state_.error != gpu::error::kNoError)
return;
@@ -97,11 +111,13 @@ void CommandBufferProxyImpl::SetMemoryAllocationChangedCallback(
}
void CommandBufferProxyImpl::AddDeletionObserver(DeletionObserver* observer) {
+ CheckLock();
deletion_observers_.AddObserver(observer);
}
void CommandBufferProxyImpl::RemoveDeletionObserver(
DeletionObserver* observer) {
+ CheckLock();
deletion_observers_.RemoveObserver(observer);
}
@@ -119,9 +135,10 @@ void CommandBufferProxyImpl::OnSignalSyncPointAck(uint32 id) {
callback.Run();
}
-void CommandBufferProxyImpl::SetChannelErrorCallback(
+void CommandBufferProxyImpl::SetContextLostCallback(
const base::Closure& callback) {
- channel_error_callback_ = callback;
+ CheckLock();
+ context_lost_callback_ = callback;
}
bool CommandBufferProxyImpl::Initialize() {
@@ -171,6 +188,7 @@ int32 CommandBufferProxyImpl::GetLastToken() {
}
void CommandBufferProxyImpl::Flush(int32 put_offset) {
+ CheckLock();
if (last_state_.error != gpu::error::kNoError)
return;
@@ -179,30 +197,59 @@ void CommandBufferProxyImpl::Flush(int32 put_offset) {
"put_offset",
put_offset);
- if (last_put_offset_ == put_offset)
+ bool put_offset_changed = last_put_offset_ != put_offset;
+ last_put_offset_ = put_offset;
+ last_barrier_put_offset_ = put_offset;
+
+ if (channel_) {
+ channel_->OrderingBarrier(route_id_, put_offset, ++flush_count_,
+ latency_info_, put_offset_changed, true);
+ }
+
+ if (put_offset_changed)
+ latency_info_.clear();
+}
+
+void CommandBufferProxyImpl::OrderingBarrier(int32 put_offset) {
+ if (last_state_.error != gpu::error::kNoError)
return;
- last_put_offset_ = put_offset;
+ TRACE_EVENT1("gpu", "CommandBufferProxyImpl::OrderingBarrier", "put_offset",
+ put_offset);
- Send(new GpuCommandBufferMsg_AsyncFlush(route_id_,
- put_offset,
- ++flush_count_,
- latency_info_));
- latency_info_.clear();
+ bool put_offset_changed = last_barrier_put_offset_ != put_offset;
+ last_barrier_put_offset_ = put_offset;
+
+ if (channel_) {
+ channel_->OrderingBarrier(route_id_, put_offset, ++flush_count_,
+ latency_info_, put_offset_changed, false);
+ }
+
+ if (put_offset_changed)
+ latency_info_.clear();
}
void CommandBufferProxyImpl::SetLatencyInfo(
const std::vector<ui::LatencyInfo>& latency_info) {
+ CheckLock();
for (size_t i = 0; i < latency_info.size(); i++)
latency_info_.push_back(latency_info[i]);
}
void CommandBufferProxyImpl::SetSwapBuffersCompletionCallback(
const SwapBuffersCompletionCallback& callback) {
+ CheckLock();
swap_buffers_completion_callback_ = callback;
}
+void CommandBufferProxyImpl::SetUpdateVSyncParametersCallback(
+ const UpdateVSyncParametersCallback& callback) {
+ CheckLock();
+ update_vsync_parameters_completion_callback_ = callback;
+}
+
void CommandBufferProxyImpl::WaitForTokenInRange(int32 start, int32 end) {
+ CheckLock();
TRACE_EVENT2("gpu",
"CommandBufferProxyImpl::WaitForToken",
"start",
@@ -222,6 +269,7 @@ void CommandBufferProxyImpl::WaitForTokenInRange(int32 start, int32 end) {
}
void CommandBufferProxyImpl::WaitForGetOffsetInRange(int32 start, int32 end) {
+ CheckLock();
TRACE_EVENT2("gpu",
"CommandBufferProxyImpl::WaitForGetOffset",
"start",
@@ -241,6 +289,7 @@ void CommandBufferProxyImpl::WaitForGetOffsetInRange(int32 start, int32 end) {
}
void CommandBufferProxyImpl::SetGetBuffer(int32 shm_id) {
+ CheckLock();
if (last_state_.error != gpu::error::kNoError)
return;
@@ -251,6 +300,7 @@ void CommandBufferProxyImpl::SetGetBuffer(int32 shm_id) {
scoped_refptr<gpu::Buffer> CommandBufferProxyImpl::CreateTransferBuffer(
size_t size,
int32* id) {
+ CheckLock();
*id = -1;
if (last_state_.error != gpu::error::kNoError)
@@ -289,6 +339,7 @@ scoped_refptr<gpu::Buffer> CommandBufferProxyImpl::CreateTransferBuffer(
}
void CommandBufferProxyImpl::DestroyTransferBuffer(int32 id) {
+ CheckLock();
if (last_state_.error != gpu::error::kNoError)
return;
@@ -303,6 +354,7 @@ int32_t CommandBufferProxyImpl::CreateImage(ClientBuffer buffer,
size_t width,
size_t height,
unsigned internalformat) {
+ CheckLock();
if (last_state_.error != gpu::error::kNoError)
return -1;
@@ -322,6 +374,10 @@ int32_t CommandBufferProxyImpl::CreateImage(ClientBuffer buffer,
channel_->ShareGpuMemoryBufferToGpuProcess(gpu_memory_buffer->GetHandle(),
&requires_sync_point);
+ DCHECK(gpu::ImageFactory::IsGpuMemoryBufferFormatSupported(
+ gpu_memory_buffer->GetFormat(), capabilities_));
+ DCHECK(gpu::ImageFactory::IsImageSizeValidForGpuMemoryBufferFormat(
+ gfx::Size(width, height), gpu_memory_buffer->GetFormat()));
DCHECK(gpu::ImageFactory::IsImageFormatCompatibleWithGpuMemoryBufferFormat(
internalformat, gpu_memory_buffer->GetFormat()));
if (!Send(new GpuCommandBufferMsg_CreateImage(route_id_,
@@ -342,6 +398,7 @@ int32_t CommandBufferProxyImpl::CreateImage(ClientBuffer buffer,
}
void CommandBufferProxyImpl::DestroyImage(int32 id) {
+ CheckLock();
if (last_state_.error != gpu::error::kNoError)
return;
@@ -353,6 +410,7 @@ int32_t CommandBufferProxyImpl::CreateGpuMemoryBufferImage(
size_t height,
unsigned internalformat,
unsigned usage) {
+ CheckLock();
scoped_ptr<gfx::GpuMemoryBuffer> buffer(
channel_->gpu_memory_buffer_manager()->AllocateGpuMemoryBuffer(
gfx::Size(width, height),
@@ -369,6 +427,7 @@ int CommandBufferProxyImpl::GetRouteID() const {
}
uint32 CommandBufferProxyImpl::CreateStreamTexture(uint32 texture_id) {
+ CheckLock();
if (last_state_.error != gpu::error::kNoError)
return 0;
@@ -383,7 +442,12 @@ uint32 CommandBufferProxyImpl::CreateStreamTexture(uint32 texture_id) {
return stream_id;
}
+void CommandBufferProxyImpl::SetLock(base::Lock* lock) {
+ lock_ = lock;
+}
+
uint32 CommandBufferProxyImpl::InsertSyncPoint() {
+ CheckLock();
if (last_state_.error != gpu::error::kNoError)
return 0;
@@ -393,6 +457,7 @@ uint32 CommandBufferProxyImpl::InsertSyncPoint() {
}
uint32_t CommandBufferProxyImpl::InsertFutureSyncPoint() {
+ CheckLock();
if (last_state_.error != gpu::error::kNoError)
return 0;
@@ -402,6 +467,7 @@ uint32_t CommandBufferProxyImpl::InsertFutureSyncPoint() {
}
void CommandBufferProxyImpl::RetireSyncPoint(uint32_t sync_point) {
+ CheckLock();
if (last_state_.error != gpu::error::kNoError)
return;
@@ -410,6 +476,7 @@ void CommandBufferProxyImpl::RetireSyncPoint(uint32_t sync_point) {
void CommandBufferProxyImpl::SignalSyncPoint(uint32 sync_point,
const base::Closure& callback) {
+ CheckLock();
if (last_state_.error != gpu::error::kNoError)
return;
@@ -425,6 +492,7 @@ void CommandBufferProxyImpl::SignalSyncPoint(uint32 sync_point,
void CommandBufferProxyImpl::SignalQuery(uint32 query,
const base::Closure& callback) {
+ CheckLock();
if (last_state_.error != gpu::error::kNoError)
return;
@@ -447,6 +515,7 @@ void CommandBufferProxyImpl::SignalQuery(uint32 query,
}
void CommandBufferProxyImpl::SetSurfaceVisible(bool visible) {
+ CheckLock();
if (last_state_.error != gpu::error::kNoError)
return;
@@ -454,6 +523,7 @@ void CommandBufferProxyImpl::SetSurfaceVisible(bool visible) {
}
bool CommandBufferProxyImpl::ProduceFrontBuffer(const gpu::Mailbox& mailbox) {
+ CheckLock();
if (last_state_.error != gpu::error::kNoError)
return false;
@@ -513,6 +583,7 @@ void CommandBufferProxyImpl::OnUpdateState(
void CommandBufferProxyImpl::SetOnConsoleMessageCallback(
const GpuConsoleMessageCallback& callback) {
+ CheckLock();
console_message_callback_ = callback;
}
@@ -538,4 +609,10 @@ void CommandBufferProxyImpl::OnSwapBuffersCompleted(
}
}
+void CommandBufferProxyImpl::OnUpdateVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval) {
+ if (!update_vsync_parameters_completion_callback_.is_null())
+ update_vsync_parameters_completion_callback_.Run(timebase, interval);
+}
+
} // namespace content
diff --git a/chromium/content/common/gpu/client/command_buffer_proxy_impl.h b/chromium/content/common/gpu/client/command_buffer_proxy_impl.h
index ea3974029cd..4bd2006bb5b 100644
--- a/chromium/content/common/gpu/client/command_buffer_proxy_impl.h
+++ b/chromium/content/common/gpu/client/command_buffer_proxy_impl.h
@@ -89,6 +89,7 @@ class CommandBufferProxyImpl
State GetLastState() override;
int32 GetLastToken() override;
void Flush(int32 put_offset) override;
+ void OrderingBarrier(int32 put_offset) override;
void WaitForTokenInRange(int32 start, int32 end) override;
void WaitForGetOffsetInRange(int32 start, int32 end) override;
void SetGetBuffer(int32 shm_id) override;
@@ -115,10 +116,11 @@ class CommandBufferProxyImpl
void SignalQuery(uint32 query, const base::Closure& callback) override;
void SetSurfaceVisible(bool visible) override;
uint32 CreateStreamTexture(uint32 texture_id) override;
+ void SetLock(base::Lock* lock) override;
int GetRouteID() const;
bool ProduceFrontBuffer(const gpu::Mailbox& mailbox);
- void SetChannelErrorCallback(const base::Closure& callback);
+ void SetContextLostCallback(const base::Closure& callback);
typedef base::Callback<void(const gpu::MemoryAllocation&)>
MemoryAllocationChangedCallback;
@@ -133,11 +135,16 @@ class CommandBufferProxyImpl
const GpuConsoleMessageCallback& callback);
void SetLatencyInfo(const std::vector<ui::LatencyInfo>& latency_info);
- typedef base::Callback<void(const std::vector<ui::LatencyInfo>& latency_info)>
- SwapBuffersCompletionCallback;
+ using SwapBuffersCompletionCallback =
+ base::Callback<void(const std::vector<ui::LatencyInfo>& latency_info)>;
void SetSwapBuffersCompletionCallback(
const SwapBuffersCompletionCallback& callback);
+ using UpdateVSyncParametersCallback =
+ base::Callback<void(base::TimeTicks timebase, base::TimeDelta interval)>;
+ void SetUpdateVSyncParametersCallback(
+ const UpdateVSyncParametersCallback& callback);
+
// TODO(apatrick): this is a temporary optimization while skia is calling
// ContentGLContext::MakeCurrent prior to every GL call. It saves returning 6
// ints redundantly when only the error is needed for the
@@ -153,9 +160,14 @@ class CommandBufferProxyImpl
private:
typedef std::map<int32, scoped_refptr<gpu::Buffer> > TransferBufferMap;
typedef base::hash_map<uint32, base::Closure> SignalTaskMap;
- typedef base::ScopedPtrHashMap<int32, gfx::GpuMemoryBuffer>
+ typedef base::ScopedPtrHashMap<int32, scoped_ptr<gfx::GpuMemoryBuffer>>
GpuMemoryBufferMap;
+ void CheckLock() {
+ if (lock_)
+ lock_->AssertAcquired();
+ }
+
// Send an IPC message over the GPU channel. This is private to fully
// encapsulate the channel; all callers of this function must explicitly
// verify that the context has not been lost.
@@ -163,11 +175,14 @@ class CommandBufferProxyImpl
// Message handlers:
void OnUpdateState(const gpu::CommandBuffer::State& state);
- void OnDestroyed(gpu::error::ContextLostReason reason);
+ void OnDestroyed(gpu::error::ContextLostReason reason,
+ gpu::error::Error error);
void OnConsoleMessage(const GPUCommandBufferConsoleMessage& message);
void OnSetMemoryAllocation(const gpu::MemoryAllocation& allocation);
void OnSignalSyncPointAck(uint32 id);
void OnSwapBuffersCompleted(const std::vector<ui::LatencyInfo>& latency_info);
+ void OnUpdateVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval);
// Try to read an updated copy of the state from shared memory.
void TryUpdateState();
@@ -175,6 +190,8 @@ class CommandBufferProxyImpl
// The shared memory area used to update state.
gpu::CommandBufferSharedState* shared_state() const;
+ base::Lock* lock_;
+
// Unowned list of DeletionObservers.
ObserverList<DeletionObserver> deletion_observers_;
@@ -190,8 +207,9 @@ class CommandBufferProxyImpl
int route_id_;
unsigned int flush_count_;
int32 last_put_offset_;
+ int32 last_barrier_put_offset_;
- base::Closure channel_error_callback_;
+ base::Closure context_lost_callback_;
MemoryAllocationChangedCallback memory_allocation_changed_callback_;
@@ -209,6 +227,7 @@ class CommandBufferProxyImpl
std::vector<ui::LatencyInfo> latency_info_;
SwapBuffersCompletionCallback swap_buffers_completion_callback_;
+ UpdateVSyncParametersCallback update_vsync_parameters_completion_callback_;
DISALLOW_COPY_AND_ASSIGN(CommandBufferProxyImpl);
};
diff --git a/chromium/content/common/gpu/client/context_provider_command_buffer.cc b/chromium/content/common/gpu/client/context_provider_command_buffer.cc
index a4c3111c0ce..58e34b64317 100644
--- a/chromium/content/common/gpu/client/context_provider_command_buffer.cc
+++ b/chromium/content/common/gpu/client/context_provider_command_buffer.cc
@@ -10,8 +10,9 @@
#include "base/callback_helpers.h"
#include "base/strings/stringprintf.h"
#include "cc/output/managed_memory_policy.h"
+#include "content/common/gpu/client/grcontext_for_webgraphicscontext3d.h"
#include "gpu/command_buffer/client/gles2_implementation.h"
-#include "webkit/common/gpu/grcontext_for_webgraphicscontext3d.h"
+#include "third_party/skia/include/gpu/GrContext.h"
namespace content {
@@ -38,18 +39,19 @@ class ContextProviderCommandBuffer::LostContextCallbackProxy
scoped_refptr<ContextProviderCommandBuffer>
ContextProviderCommandBuffer::Create(
scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context3d,
- const std::string& debug_name) {
+ CommandBufferContextType type) {
if (!context3d)
return NULL;
- return new ContextProviderCommandBuffer(context3d.Pass(), debug_name);
+ return new ContextProviderCommandBuffer(context3d.Pass(), type);
}
ContextProviderCommandBuffer::ContextProviderCommandBuffer(
scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context3d,
- const std::string& debug_name)
+ CommandBufferContextType type)
: context3d_(context3d.Pass()),
- debug_name_(debug_name),
+ context_type_(type),
+ debug_name_(CommandBufferContextTypeToString(type)),
destroyed_(false) {
DCHECK(main_thread_checker_.CalledOnValidThread());
DCHECK(context3d_);
@@ -64,6 +66,7 @@ ContextProviderCommandBuffer::~ContextProviderCommandBuffer() {
// Destroy references to the context3d_ before leaking it.
if (context3d_->GetCommandBufferProxy()) {
+ context3d_->GetCommandBufferProxy()->SetLock(nullptr);
context3d_->GetCommandBufferProxy()->SetMemoryAllocationChangedCallback(
CommandBufferProxyImpl::MemoryAllocationChangedCallback());
}
@@ -91,6 +94,7 @@ bool ContextProviderCommandBuffer::BindToCurrentThread() {
if (lost_context_callback_proxy_)
return true;
+ context3d_->SetContextType(context_type_);
if (!context3d_->InitializeOnCurrentThread())
return false;
@@ -98,7 +102,7 @@ bool ContextProviderCommandBuffer::BindToCurrentThread() {
std::string unique_context_name =
base::StringPrintf("%s-%p", debug_name_.c_str(), context3d_.get());
- context3d_->pushGroupMarkerEXT(unique_context_name.c_str());
+ context3d_->traceBeginCHROMIUM("gpu_toplevel", unique_context_name.c_str());
lost_context_callback_proxy_.reset(new LostContextCallbackProxy(this));
context3d_->GetCommandBufferProxy()->SetMemoryAllocationChangedCallback(
@@ -107,6 +111,10 @@ bool ContextProviderCommandBuffer::BindToCurrentThread() {
return true;
}
+void ContextProviderCommandBuffer::DetachFromThread() {
+ context_thread_checker_.DetachFromThread();
+}
+
gpu::gles2::GLES2Interface* ContextProviderCommandBuffer::ContextGL() {
DCHECK(context3d_);
DCHECK(lost_context_callback_proxy_); // Is bound to thread.
@@ -126,11 +134,32 @@ class GrContext* ContextProviderCommandBuffer::GrContext() {
if (gr_context_)
return gr_context_->get();
- gr_context_.reset(
- new webkit::gpu::GrContextForWebGraphicsContext3D(context3d_.get()));
+ gr_context_.reset(new GrContextForWebGraphicsContext3D(context3d_.get()));
+
+ // If GlContext is already lost, also abandon the new GrContext.
+ if (gr_context_->get() && IsContextLost())
+ gr_context_->get()->abandonContext();
+
return gr_context_->get();
}
+void ContextProviderCommandBuffer::InvalidateGrContext(uint32_t state) {
+ if (gr_context_) {
+ DCHECK(lost_context_callback_proxy_); // Is bound to thread.
+ DCHECK(context_thread_checker_.CalledOnValidThread());
+ gr_context_->get()->resetContext(state);
+ }
+}
+
+void ContextProviderCommandBuffer::SetupLock() {
+ DCHECK(context3d_);
+ context3d_->GetCommandBufferProxy()->SetLock(&context_lock_);
+}
+
+base::Lock* ContextProviderCommandBuffer::GetLock() {
+ return &context_lock_;
+}
+
cc::ContextProvider::Capabilities
ContextProviderCommandBuffer::ContextCapabilities() {
DCHECK(lost_context_callback_proxy_); // Is bound to thread.
diff --git a/chromium/content/common/gpu/client/context_provider_command_buffer.h b/chromium/content/common/gpu/client/context_provider_command_buffer.h
index 39c7fefc083..78c1b29b610 100644
--- a/chromium/content/common/gpu/client/context_provider_command_buffer.h
+++ b/chromium/content/common/gpu/client/context_provider_command_buffer.h
@@ -2,45 +2,46 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CONTENT_COMMON_GPU_CLIENT_CONTEXT_PROVIDER_COMMAND_BUFFER
-#define CONTENT_COMMON_GPU_CLIENT_CONTEXT_PROVIDER_COMMAND_BUFFER
+#ifndef CONTENT_COMMON_GPU_CLIENT_CONTEXT_PROVIDER_COMMAND_BUFFER_H_
+#define CONTENT_COMMON_GPU_CLIENT_CONTEXT_PROVIDER_COMMAND_BUFFER_H_
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "base/synchronization/lock.h"
#include "base/threading/thread_checker.h"
+#include "cc/blink/context_provider_web_context.h"
#include "cc/output/context_provider.h"
#include "content/common/content_export.h"
+#include "content/common/gpu/client/command_buffer_metrics.h"
#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
-#include "webkit/common/gpu/context_provider_web_context.h"
-
-namespace webkit {
-namespace gpu {
-class GrContextForWebGraphicsContext3D;
-}
-}
namespace content {
+class GrContextForWebGraphicsContext3D;
+
// Implementation of cc::ContextProvider that provides a
// WebGraphicsContext3DCommandBufferImpl context and a GrContext.
class CONTENT_EXPORT ContextProviderCommandBuffer
- : NON_EXPORTED_BASE(public webkit::gpu::ContextProviderWebContext) {
+ : NON_EXPORTED_BASE(public cc_blink::ContextProviderWebContext) {
public:
static scoped_refptr<ContextProviderCommandBuffer> Create(
scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context3d,
- const std::string& debug_name);
+ CommandBufferContextType type);
CommandBufferProxyImpl* GetCommandBufferProxy();
- // ContextProviderWebContext implementation.
+ // cc_blink::ContextProviderWebContext implementation.
WebGraphicsContext3DCommandBufferImpl* WebContext3D() override;
// cc::ContextProvider implementation.
bool BindToCurrentThread() override;
+ void DetachFromThread() override;
gpu::gles2::GLES2Interface* ContextGL() override;
gpu::ContextSupport* ContextSupport() override;
class GrContext* GrContext() override;
+ void InvalidateGrContext(uint32_t state) override;
+ void SetupLock() override;
+ base::Lock* GetLock() override;
Capabilities ContextCapabilities() override;
bool IsContextLost() override;
void VerifyContexts() override;
@@ -55,7 +56,7 @@ class CONTENT_EXPORT ContextProviderCommandBuffer
protected:
ContextProviderCommandBuffer(
scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context3d,
- const std::string& debug_name);
+ CommandBufferContextType type);
~ContextProviderCommandBuffer() override;
void OnLostContext();
@@ -68,9 +69,10 @@ class CONTENT_EXPORT ContextProviderCommandBuffer
base::ThreadChecker context_thread_checker_;
scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context3d_;
- scoped_ptr<webkit::gpu::GrContextForWebGraphicsContext3D> gr_context_;
+ scoped_ptr<GrContextForWebGraphicsContext3D> gr_context_;
cc::ContextProvider::Capabilities capabilities_;
+ CommandBufferContextType context_type_;
std::string debug_name_;
LostContextCallback lost_context_callback_;
@@ -79,10 +81,12 @@ class CONTENT_EXPORT ContextProviderCommandBuffer
base::Lock main_thread_lock_;
bool destroyed_;
+ base::Lock context_lock_;
+
class LostContextCallbackProxy;
scoped_ptr<LostContextCallbackProxy> lost_context_callback_proxy_;
};
} // namespace content
-#endif // CONTENT_COMMON_GPU_CLIENT_CONTEXT_PROVIDER_COMMAND_BUFFER
+#endif // CONTENT_COMMON_GPU_CLIENT_CONTEXT_PROVIDER_COMMAND_BUFFER_H_
diff --git a/chromium/content/common/gpu/client/gl_helper.cc b/chromium/content/common/gpu/client/gl_helper.cc
index 0ba9193c874..89dd8a9f8bb 100644
--- a/chromium/content/common/gpu/client/gl_helper.cc
+++ b/chromium/content/common/gpu/client/gl_helper.cc
@@ -8,13 +8,13 @@
#include <string>
#include "base/bind.h"
-#include "base/debug/trace_event.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/string_util.h"
#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
#include "content/common/gpu/client/gl_helper_readback_support.h"
#include "content/common/gpu/client/gl_helper_scaling.h"
#include "gpu/GLES2/gl2extchromium.h"
@@ -24,8 +24,9 @@
#include "media/base/video_frame.h"
#include "media/base/video_util.h"
#include "third_party/skia/include/core/SkRegion.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/size.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
using gpu::gles2::GLES2Interface;
@@ -172,7 +173,7 @@ class GLHelper::CopyTextureToImpl
const scoped_refptr<media::VideoFrame>& target,
int plane,
int size_shift,
- const gfx::Rect& dst_subrect,
+ const gfx::Rect& paste_rect,
ReadbackSwizzle swizzle,
const base::Callback<void(bool)>& callback);
@@ -187,7 +188,6 @@ class GLHelper::CopyTextureToImpl
const gfx::Size& src_size,
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
- const gfx::Rect& dst_subrect,
bool flip_vertically,
bool use_mrt);
@@ -225,6 +225,7 @@ class GLHelper::CopyTextureToImpl
query(0) {}
bool done;
+ bool result;
gfx::Size size;
int bytes_per_row;
int row_stride_bytes;
@@ -234,6 +235,29 @@ class GLHelper::CopyTextureToImpl
GLuint query;
};
+ // We must take care to call the callbacks last, as they may
+ // end up destroying the gl_helper and make *this invalid.
+ // We stick the finished requests in a stack object that calls
+ // the callbacks when it goes out of scope.
+ class FinishRequestHelper {
+ public:
+ FinishRequestHelper() {}
+ ~FinishRequestHelper() {
+ while (!requests_.empty()) {
+ Request* request = requests_.front();
+ requests_.pop();
+ request->callback.Run(request->result);
+ delete request;
+ }
+ }
+ void Add(Request* r) {
+ requests_.push(r);
+ }
+ private:
+ std::queue<Request*> requests_;
+ DISALLOW_COPY_AND_ASSIGN(FinishRequestHelper);
+ };
+
// A readback pipeline that also converts the data to YUV before
// reading it back.
class ReadbackYUVImpl : public ReadbackYUVInterface {
@@ -245,13 +269,13 @@ class GLHelper::CopyTextureToImpl
const gfx::Size& src_size,
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
- const gfx::Rect& dst_subrect,
bool flip_vertically,
ReadbackSwizzle swizzle);
void ReadbackYUV(const gpu::Mailbox& mailbox,
uint32 sync_point,
const scoped_refptr<media::VideoFrame>& target,
+ const gfx::Point& paste_location,
const base::Callback<void(bool)>& callback) override;
ScalerInterface* scaler() override { return scaler_.scaler(); }
@@ -260,7 +284,6 @@ class GLHelper::CopyTextureToImpl
GLES2Interface* gl_;
CopyTextureToImpl* copy_impl_;
gfx::Size dst_size_;
- gfx::Rect dst_subrect_;
ReadbackSwizzle swizzle_;
ScalerHolder scaler_;
ScalerHolder y_;
@@ -282,13 +305,13 @@ class GLHelper::CopyTextureToImpl
const gfx::Size& src_size,
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
- const gfx::Rect& dst_subrect,
bool flip_vertically,
ReadbackSwizzle swizzle);
void ReadbackYUV(const gpu::Mailbox& mailbox,
uint32 sync_point,
const scoped_refptr<media::VideoFrame>& target,
+ const gfx::Point& paste_location,
const base::Callback<void(bool)>& callback) override;
ScalerInterface* scaler() override { return scaler_.scaler(); }
@@ -297,7 +320,6 @@ class GLHelper::CopyTextureToImpl
GLES2Interface* gl_;
CopyTextureToImpl* copy_impl_;
gfx::Size dst_size_;
- gfx::Rect dst_subrect_;
GLHelper::ScalerQuality quality_;
ReadbackSwizzle swizzle_;
ScalerHolder scaler_;
@@ -344,7 +366,9 @@ class GLHelper::CopyTextureToImpl
static void nullcallback(bool success) {}
void ReadbackDone(Request *request, int bytes_per_pixel);
- void FinishRequest(Request* request, bool result);
+ void FinishRequest(Request* request,
+ bool result,
+ FinishRequestHelper* helper);
void CancelRequests();
static const float kRGBtoYColorWeights[];
@@ -468,7 +492,7 @@ void GLHelper::CopyTextureToImpl::ReadbackAsync(
GLenum type,
size_t bytes_per_pixel,
const base::Callback<void(bool)>& callback) {
- TRACE_EVENT0("mirror", "GLHelper::CopyTextureToImpl::ReadbackAsync");
+ TRACE_EVENT0("gpu.capture", "GLHelper::CopyTextureToImpl::ReadbackAsync");
Request* request =
new Request(dst_size, bytes_per_row, row_stride_bytes, out, callback);
request_queue_.push(request);
@@ -683,10 +707,12 @@ GLuint GLHelper::CopyTextureToImpl::CopyAndScaleTexture(
void GLHelper::CopyTextureToImpl::ReadbackDone(Request* finished_request,
int bytes_per_pixel) {
- TRACE_EVENT0("mirror",
+ TRACE_EVENT0("gpu.capture",
"GLHelper::CopyTextureToImpl::CheckReadbackFramebufferComplete");
finished_request->done = true;
+ FinishRequestHelper finish_request_helper;
+
// We process transfer requests in the order they were received, regardless
// of the order we get the callbacks in.
while (!request_queue_.empty()) {
@@ -718,15 +744,18 @@ void GLHelper::CopyTextureToImpl::ReadbackDone(Request* finished_request,
}
gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
}
- FinishRequest(request, result);
+ FinishRequest(request, result, &finish_request_helper);
}
}
-void GLHelper::CopyTextureToImpl::FinishRequest(Request* request, bool result) {
- TRACE_EVENT0("mirror", "GLHelper::CopyTextureToImpl::FinishRequest");
+void GLHelper::CopyTextureToImpl::FinishRequest(
+ Request* request,
+ bool result,
+ FinishRequestHelper* finish_request_helper) {
+ TRACE_EVENT0("gpu.capture", "GLHelper::CopyTextureToImpl::FinishRequest");
DCHECK(request_queue_.front() == request);
request_queue_.pop();
- request->callback.Run(result);
+ request->result = result;
ScopedFlush flush(gl_);
if (request->query != 0) {
gl_->DeleteQueriesEXT(1, &request->query);
@@ -736,13 +765,14 @@ void GLHelper::CopyTextureToImpl::FinishRequest(Request* request, bool result) {
gl_->DeleteBuffers(1, &request->buffer);
request->buffer = 0;
}
- delete request;
+ finish_request_helper->Add(request);
}
void GLHelper::CopyTextureToImpl::CancelRequests() {
+ FinishRequestHelper finish_request_helper;
while (!request_queue_.empty()) {
Request* request = request_queue_.front();
- FinishRequest(request, false);
+ FinishRequest(request, false, &finish_request_helper);
}
}
@@ -989,19 +1019,23 @@ void GLHelper::Flush() {
gl_->Flush();
}
+void GLHelper::InsertOrderingBarrier() {
+ gl_->OrderingBarrierCHROMIUM();
+}
+
void GLHelper::CopyTextureToImpl::ReadbackPlane(
TextureFrameBufferPair* source,
const scoped_refptr<media::VideoFrame>& target,
int plane,
int size_shift,
- const gfx::Rect& dst_subrect,
+ const gfx::Rect& paste_rect,
ReadbackSwizzle swizzle,
const base::Callback<void(bool)>& callback) {
gl_->BindFramebuffer(GL_FRAMEBUFFER, source->framebuffer());
- size_t offset = target->stride(plane) * (dst_subrect.y() >> size_shift) +
- (dst_subrect.x() >> size_shift);
+ const size_t offset = target->stride(plane) * (paste_rect.y() >> size_shift) +
+ (paste_rect.x() >> size_shift);
ReadbackAsync(source->size(),
- dst_subrect.width() >> size_shift,
+ paste_rect.width() >> size_shift,
target->stride(plane),
target->data(plane) + offset,
(swizzle == kSwizzleBGRA) ? GL_BGRA_EXT : GL_RGBA,
@@ -1029,62 +1063,56 @@ GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUVImpl(
const gfx::Size& src_size,
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
- const gfx::Rect& dst_subrect,
bool flip_vertically,
ReadbackSwizzle swizzle)
: gl_(gl),
copy_impl_(copy_impl),
dst_size_(dst_size),
- dst_subrect_(dst_subrect),
swizzle_(swizzle),
scaler_(gl,
scaler_impl->CreateScaler(quality,
src_size,
src_subrect,
- dst_subrect.size(),
+ dst_size,
flip_vertically,
false)),
y_(gl,
scaler_impl->CreatePlanarScaler(
- dst_subrect.size(),
+ dst_size,
gfx::Rect(0,
0,
- (dst_subrect.width() + 3) & ~3,
- dst_subrect.height()),
- gfx::Size((dst_subrect.width() + 3) / 4, dst_subrect.height()),
+ (dst_size.width() + 3) & ~3,
+ dst_size.height()),
+ gfx::Size((dst_size.width() + 3) / 4, dst_size.height()),
false,
(swizzle == kSwizzleBGRA),
kRGBtoYColorWeights)),
u_(gl,
scaler_impl->CreatePlanarScaler(
- dst_subrect.size(),
+ dst_size,
gfx::Rect(0,
0,
- (dst_subrect.width() + 7) & ~7,
- (dst_subrect.height() + 1) & ~1),
- gfx::Size((dst_subrect.width() + 7) / 8,
- (dst_subrect.height() + 1) / 2),
+ (dst_size.width() + 7) & ~7,
+ (dst_size.height() + 1) & ~1),
+ gfx::Size((dst_size.width() + 7) / 8,
+ (dst_size.height() + 1) / 2),
false,
(swizzle == kSwizzleBGRA),
kRGBtoUColorWeights)),
v_(gl,
scaler_impl->CreatePlanarScaler(
- dst_subrect.size(),
+ dst_size,
gfx::Rect(0,
0,
- (dst_subrect.width() + 7) & ~7,
- (dst_subrect.height() + 1) & ~1),
- gfx::Size((dst_subrect.width() + 7) / 8,
- (dst_subrect.height() + 1) / 2),
+ (dst_size.width() + 7) & ~7,
+ (dst_size.height() + 1) & ~1),
+ gfx::Size((dst_size.width() + 7) / 8,
+ (dst_size.height() + 1) / 2),
false,
(swizzle == kSwizzleBGRA),
kRGBtoVColorWeights)) {
DCHECK(!(dst_size.width() & 1));
DCHECK(!(dst_size.height() & 1));
- DCHECK(!(dst_subrect.width() & 1));
- DCHECK(!(dst_subrect.height() & 1));
- DCHECK(!(dst_subrect.x() & 1));
- DCHECK(!(dst_subrect.y() & 1));
}
static void CallbackKeepingVideoFrameAlive(
@@ -1098,7 +1126,11 @@ void GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUV(
const gpu::Mailbox& mailbox,
uint32 sync_point,
const scoped_refptr<media::VideoFrame>& target,
+ const gfx::Point& paste_location,
const base::Callback<void(bool)>& callback) {
+ DCHECK(!(paste_location.x() & 1));
+ DCHECK(!(paste_location.y() & 1));
+
GLuint mailbox_texture =
copy_impl_->ConsumeMailboxToTexture(mailbox, sync_point);
@@ -1111,9 +1143,9 @@ void GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUV(
u_.Scale(scaler_.texture());
v_.Scale(scaler_.texture());
- if (target->coded_size() != dst_size_) {
- DCHECK(target->coded_size() == dst_size_);
- LOG(ERROR) << "ReadbackYUV size error!";
+ const gfx::Rect paste_rect(paste_location, dst_size_);
+ if (!target->visible_rect().Contains(paste_rect)) {
+ LOG(DFATAL) << "Paste rect not inside VideoFrame's visible rect!";
callback.Run(false);
return;
}
@@ -1124,14 +1156,14 @@ void GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUV(
target,
media::VideoFrame::kYPlane,
0,
- dst_subrect_,
+ paste_rect,
swizzle_,
base::Bind(&nullcallback));
copy_impl_->ReadbackPlane(u_.texture_and_framebuffer(),
target,
media::VideoFrame::kUPlane,
1,
- dst_subrect_,
+ paste_rect,
swizzle_,
base::Bind(&nullcallback));
copy_impl_->ReadbackPlane(
@@ -1139,11 +1171,11 @@ void GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUV(
target,
media::VideoFrame::kVPlane,
1,
- dst_subrect_,
+ paste_rect,
swizzle_,
base::Bind(&CallbackKeepingVideoFrameAlive, target, callback));
gl_->BindFramebuffer(GL_FRAMEBUFFER, 0);
- media::LetterboxYUV(target.get(), dst_subrect_);
+ media::LetterboxYUV(target.get(), paste_rect);
}
// YUV readback constructors. Initiates the main scaler pipeline and
@@ -1156,73 +1188,70 @@ GLHelper::CopyTextureToImpl::ReadbackYUV_MRT::ReadbackYUV_MRT(
const gfx::Size& src_size,
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
- const gfx::Rect& dst_subrect,
bool flip_vertically,
ReadbackSwizzle swizzle)
: gl_(gl),
copy_impl_(copy_impl),
dst_size_(dst_size),
- dst_subrect_(dst_subrect),
quality_(quality),
swizzle_(swizzle),
scaler_(gl,
scaler_impl->CreateScaler(quality,
src_size,
src_subrect,
- dst_subrect.size(),
+ dst_size,
false,
false)),
pass1_shader_(scaler_impl->CreateYuvMrtShader(
- dst_subrect.size(),
- gfx::Rect(0, 0, (dst_subrect.width() + 3) & ~3, dst_subrect.height()),
- gfx::Size((dst_subrect.width() + 3) / 4, dst_subrect.height()),
+ dst_size,
+ gfx::Rect(0, 0, (dst_size.width() + 3) & ~3, dst_size.height()),
+ gfx::Size((dst_size.width() + 3) / 4, dst_size.height()),
flip_vertically,
(swizzle == kSwizzleBGRA),
GLHelperScaling::SHADER_YUV_MRT_PASS1)),
pass2_shader_(scaler_impl->CreateYuvMrtShader(
- gfx::Size((dst_subrect.width() + 3) / 4, dst_subrect.height()),
+ gfx::Size((dst_size.width() + 3) / 4, dst_size.height()),
gfx::Rect(0,
0,
- (dst_subrect.width() + 7) / 8 * 2,
- dst_subrect.height()),
- gfx::Size((dst_subrect.width() + 7) / 8,
- (dst_subrect.height() + 1) / 2),
+ (dst_size.width() + 7) / 8 * 2,
+ dst_size.height()),
+ gfx::Size((dst_size.width() + 7) / 8,
+ (dst_size.height() + 1) / 2),
false,
(swizzle == kSwizzleBGRA),
GLHelperScaling::SHADER_YUV_MRT_PASS2)),
- y_(gl, gfx::Size((dst_subrect.width() + 3) / 4, dst_subrect.height())),
+ y_(gl, gfx::Size((dst_size.width() + 3) / 4, dst_size.height())),
uv_(gl),
u_(gl,
- gfx::Size((dst_subrect.width() + 7) / 8,
- (dst_subrect.height() + 1) / 2)),
+ gfx::Size((dst_size.width() + 7) / 8,
+ (dst_size.height() + 1) / 2)),
v_(gl,
- gfx::Size((dst_subrect.width() + 7) / 8,
- (dst_subrect.height() + 1) / 2)) {
+ gfx::Size((dst_size.width() + 7) / 8,
+ (dst_size.height() + 1) / 2)) {
+ DCHECK(!(dst_size.width() & 1));
+ DCHECK(!(dst_size.height() & 1));
content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl, uv_);
gl->TexImage2D(GL_TEXTURE_2D,
0,
GL_RGBA,
- (dst_subrect.width() + 3) / 4,
- dst_subrect.height(),
+ (dst_size.width() + 3) / 4,
+ dst_size.height(),
0,
GL_RGBA,
GL_UNSIGNED_BYTE,
NULL);
-
- DCHECK(!(dst_size.width() & 1));
- DCHECK(!(dst_size.height() & 1));
- DCHECK(!(dst_subrect.width() & 1));
- DCHECK(!(dst_subrect.height() & 1));
- DCHECK(!(dst_subrect.x() & 1));
- DCHECK(!(dst_subrect.y() & 1));
}
void GLHelper::CopyTextureToImpl::ReadbackYUV_MRT::ReadbackYUV(
const gpu::Mailbox& mailbox,
uint32 sync_point,
const scoped_refptr<media::VideoFrame>& target,
+ const gfx::Point& paste_location,
const base::Callback<void(bool)>& callback) {
+ DCHECK(!(paste_location.x() & 1));
+ DCHECK(!(paste_location.y() & 1));
+
GLuint mailbox_texture =
copy_impl_->ConsumeMailboxToTexture(mailbox, sync_point);
@@ -1250,9 +1279,9 @@ void GLHelper::CopyTextureToImpl::ReadbackYUV_MRT::ReadbackYUV(
outputs[1] = v_.texture();
pass2_shader_->Execute(uv_, outputs);
- if (target->coded_size() != dst_size_) {
- DCHECK(target->coded_size() == dst_size_);
- LOG(ERROR) << "ReadbackYUV size error!";
+ const gfx::Rect paste_rect(paste_location, dst_size_);
+ if (!target->visible_rect().Contains(paste_rect)) {
+ LOG(DFATAL) << "Paste rect not inside VideoFrame's visible rect!";
callback.Run(false);
return;
}
@@ -1262,14 +1291,14 @@ void GLHelper::CopyTextureToImpl::ReadbackYUV_MRT::ReadbackYUV(
target,
media::VideoFrame::kYPlane,
0,
- dst_subrect_,
+ paste_rect,
swizzle_,
base::Bind(&nullcallback));
copy_impl_->ReadbackPlane(&u_,
target,
media::VideoFrame::kUPlane,
1,
- dst_subrect_,
+ paste_rect,
swizzle_,
base::Bind(&nullcallback));
copy_impl_->ReadbackPlane(
@@ -1277,11 +1306,11 @@ void GLHelper::CopyTextureToImpl::ReadbackYUV_MRT::ReadbackYUV(
target,
media::VideoFrame::kVPlane,
1,
- dst_subrect_,
+ paste_rect,
swizzle_,
base::Bind(&CallbackKeepingVideoFrameAlive, target, callback));
gl_->BindFramebuffer(GL_FRAMEBUFFER, 0);
- media::LetterboxYUV(target.get(), dst_subrect_);
+ media::LetterboxYUV(target.get(), paste_rect);
}
bool GLHelper::IsReadbackConfigSupported(SkColorType color_type) {
@@ -1299,7 +1328,6 @@ ReadbackYUVInterface* GLHelper::CopyTextureToImpl::CreateReadbackPipelineYUV(
const gfx::Size& src_size,
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
- const gfx::Rect& dst_subrect,
bool flip_vertically,
bool use_mrt) {
helper_->InitScalerImpl();
@@ -1324,7 +1352,6 @@ ReadbackYUVInterface* GLHelper::CopyTextureToImpl::CreateReadbackPipelineYUV(
src_size,
src_subrect,
dst_size,
- dst_subrect,
flip_vertically,
swizzle);
}
@@ -1335,7 +1362,6 @@ ReadbackYUVInterface* GLHelper::CopyTextureToImpl::CreateReadbackPipelineYUV(
src_size,
src_subrect,
dst_size,
- dst_subrect,
flip_vertically,
swizzle);
}
@@ -1345,7 +1371,6 @@ ReadbackYUVInterface* GLHelper::CreateReadbackPipelineYUV(
const gfx::Size& src_size,
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
- const gfx::Rect& dst_subrect,
bool flip_vertically,
bool use_mrt) {
InitCopyTextToImpl();
@@ -1353,7 +1378,6 @@ ReadbackYUVInterface* GLHelper::CreateReadbackPipelineYUV(
src_size,
src_subrect,
dst_size,
- dst_subrect,
flip_vertically,
use_mrt);
}
diff --git a/chromium/content/common/gpu/client/gl_helper.h b/chromium/content/common/gpu/client/gl_helper.h
index dc90ddeb1c4..72b39677d63 100644
--- a/chromium/content/common/gpu/client/gl_helper.h
+++ b/chromium/content/common/gpu/client/gl_helper.h
@@ -15,6 +15,7 @@
#include "third_party/skia/include/core/SkBitmap.h"
namespace gfx {
+class Point;
class Rect;
class Size;
}
@@ -271,6 +272,10 @@ class CONTENT_EXPORT GLHelper {
// Flushes GL commands.
void Flush();
+ // Force commands in the current command buffer to be executed before commands
+ // in other command buffers from the same process (ie channel to the GPU
+ // process).
+ void InsertOrderingBarrier();
// A scaler will cache all intermediate textures and programs
// needed to scale from a specified size to a destination size.
@@ -304,15 +309,14 @@ class CONTENT_EXPORT GLHelper {
// texture, then convert it to YUV422 planar form and then read back that.
// This reduces the amount of memory read from GPU to CPU memory by a factor
// 2.6, which can be quite handy since readbacks have very limited speed
- // on some platforms. All values in |dst_size| and |dst_subrect| must be
- // a multiple of two. If |use_mrt| is true, the pipeline will try to optimize
- // the YUV conversion using the multi-render-target extension. |use_mrt|
- // should only be set to false for testing.
+ // on some platforms. All values in |dst_size| must be a multiple of two. If
+ // |use_mrt| is true, the pipeline will try to optimize the YUV conversion
+ // using the multi-render-target extension. |use_mrt| should only be set to
+ // false for testing.
ReadbackYUVInterface* CreateReadbackPipelineYUV(ScalerQuality quality,
const gfx::Size& src_size,
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
- const gfx::Rect& dst_subrect,
bool flip_vertically,
bool use_mrt);
@@ -358,10 +362,15 @@ class CONTENT_EXPORT ReadbackYUVInterface {
ReadbackYUVInterface() {}
virtual ~ReadbackYUVInterface() {}
- // Note that |target| must use YV12 format.
+ // Note that |target| must use YV12 format. |paste_location| specifies where
+ // the captured pixels that are read back will be placed in the video frame.
+ // The region defined by the |paste_location| and the |dst_size| specified in
+ // the call to CreateReadbackPipelineYUV() must be fully contained within
+ // |target->visible_rect()|.
virtual void ReadbackYUV(const gpu::Mailbox& mailbox,
uint32 sync_point,
const scoped_refptr<media::VideoFrame>& target,
+ const gfx::Point& paste_location,
const base::Callback<void(bool)>& callback) = 0;
virtual GLHelper::ScalerInterface* scaler() = 0;
};
diff --git a/chromium/content/common/gpu/client/gl_helper_benchmark.cc b/chromium/content/common/gpu/client/gl_helper_benchmark.cc
index a394fcfa474..75a204d1272 100644
--- a/chromium/content/common/gpu/client/gl_helper_benchmark.cc
+++ b/chromium/content/common/gpu/client/gl_helper_benchmark.cc
@@ -26,12 +26,12 @@
#include "content/common/gpu/client/gl_helper_scaling.h"
#include "content/public/test/unittest_test_suite.h"
#include "content/test/content_test_suite.h"
+#include "gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkTypes.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gl/gl_surface.h"
-#include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"
#if defined(OS_MACOSX)
#include "base/mac/scoped_nsautorelease_pool.h"
@@ -59,7 +59,7 @@ class GLHelperTest : public testing::Test {
void SetUp() override {
WebGraphicsContext3D::Attributes attributes;
bool lose_context_when_out_of_memory = false;
- context_ = webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl::
+ context_ = gpu_blink::WebGraphicsContext3DInProcessCommandBufferImpl::
CreateOffscreenContext(attributes, lose_context_when_out_of_memory);
context_->InitializeOnCurrentThread();
@@ -107,7 +107,7 @@ class GLHelperTest : public testing::Test {
base::CloseFile(f);
}
- scoped_ptr<webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl>
+ scoped_ptr<gpu_blink::WebGraphicsContext3DInProcessCommandBufferImpl>
context_;
scoped_ptr<content::GLHelper> helper_;
scoped_ptr<content::GLHelperScaling> helper_scaling_;
diff --git a/chromium/content/common/gpu/client/gl_helper_scaling.cc b/chromium/content/common/gpu/client/gl_helper_scaling.cc
index be857b4b33f..ae7b0cf8b3d 100644
--- a/chromium/content/common/gpu/client/gl_helper_scaling.cc
+++ b/chromium/content/common/gpu/client/gl_helper_scaling.cc
@@ -9,16 +9,16 @@
#include <vector>
#include "base/bind.h"
-#include "base/debug/trace_event.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "third_party/skia/include/core/SkRegion.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/size.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
using gpu::gles2::GLES2Interface;
diff --git a/chromium/content/common/gpu/client/gl_helper_scaling.h b/chromium/content/common/gpu/client/gl_helper_scaling.h
index a8896c688be..af7b7fc4994 100644
--- a/chromium/content/common/gpu/client/gl_helper_scaling.h
+++ b/chromium/content/common/gpu/client/gl_helper_scaling.h
@@ -10,8 +10,8 @@
#include <vector>
#include "content/common/gpu/client/gl_helper.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/size.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
namespace content {
diff --git a/chromium/content/common/gpu/client/gl_helper_unittest.cc b/chromium/content/common/gpu/client/gl_helper_unittest.cc
index 47e2edf3956..606405432bb 100644
--- a/chromium/content/common/gpu/client/gl_helper_unittest.cc
+++ b/chromium/content/common/gpu/client/gl_helper_unittest.cc
@@ -14,25 +14,27 @@
#include "base/at_exit.h"
#include "base/bind.h"
#include "base/command_line.h"
-#include "base/debug/trace_event.h"
#include "base/files/file_util.h"
#include "base/json/json_reader.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/waitable_event.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_suite.h"
#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
#include "content/common/gpu/client/gl_helper.h"
#include "content/common/gpu/client/gl_helper_readback_support.h"
#include "content/common/gpu/client/gl_helper_scaling.h"
#include "content/public/test/unittest_test_suite.h"
#include "content/test/content_test_suite.h"
+#include "gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.h"
#include "media/base/video_frame.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkTypes.h"
#include "ui/gl/gl_implementation.h"
-#include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"
#if defined(OS_MACOSX)
#include "base/mac/scoped_nsautorelease_pool.h"
@@ -42,7 +44,7 @@ namespace content {
using blink::WebGLId;
using blink::WebGraphicsContext3D;
-using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;
+using gpu_blink::WebGraphicsContext3DInProcessCommandBufferImpl;
content::GLHelper::ScalerQuality kQualities[] = {
content::GLHelper::SCALER_QUALITY_BEST,
@@ -74,11 +76,11 @@ class GLHelperTest : public testing::Test {
}
void StartTracing(const std::string& filter) {
- base::debug::TraceLog::GetInstance()->SetEnabled(
- base::debug::CategoryFilter(filter),
- base::debug::TraceLog::RECORDING_MODE,
- base::debug::TraceOptions(
- base::debug::RECORD_UNTIL_FULL));
+ base::trace_event::TraceLog::GetInstance()->SetEnabled(
+ base::trace_event::CategoryFilter(filter),
+ base::trace_event::TraceLog::RECORDING_MODE,
+ base::trace_event::TraceOptions(
+ base::trace_event::RECORD_UNTIL_FULL));
}
static void TraceDataCB(
@@ -86,7 +88,7 @@ class GLHelperTest : public testing::Test {
std::string* output,
const scoped_refptr<base::RefCountedString>& json_events_str,
bool has_more_events) {
- if (output->size() > 1) {
+ if (output->size() > 1 && !json_events_str->data().empty()) {
output->append(",");
}
output->append(json_events_str->data());
@@ -99,16 +101,22 @@ class GLHelperTest : public testing::Test {
// of event name->counts.
void EndTracing(std::map<std::string, int>* event_counts) {
std::string json_data = "[";
- base::debug::TraceLog::GetInstance()->SetDisabled();
+ base::trace_event::TraceLog::GetInstance()->SetDisabled();
base::RunLoop run_loop;
- base::debug::TraceLog::GetInstance()->Flush(
+ base::trace_event::TraceLog::GetInstance()->Flush(
base::Bind(&GLHelperTest::TraceDataCB,
run_loop.QuitClosure(),
base::Unretained(&json_data)));
run_loop.Run();
json_data.append("]");
- scoped_ptr<base::Value> trace_data(base::JSONReader::Read(json_data));
+ std::string error_msg;
+ scoped_ptr<base::Value> trace_data(
+ base::JSONReader::ReadAndReturnError(json_data, 0, NULL, &error_msg));
+ CHECK(trace_data)
+ << "JSON parsing failed (" << error_msg << ") JSON data:" << std::endl
+ << json_data;
+
base::ListValue* list;
CHECK(trace_data->GetAsList(&list));
for (size_t i = 0; i < list->GetSize(); i++) {
@@ -1023,25 +1031,25 @@ class GLHelperTest : public testing::Test {
// Compare two planes make sure that each component of each pixel
// is no more than |maxdiff| apart.
void ComparePlane(unsigned char* truth,
+ int truth_stride,
unsigned char* other,
+ int other_stride,
int maxdiff,
int xsize,
- int stride,
int ysize,
SkBitmap* source,
std::string message) {
- int truth_stride = stride;
for (int x = 0; x < xsize; x++) {
for (int y = 0; y < ysize; y++) {
- int a = other[y * stride + x];
- int b = truth[y * stride + x];
+ int a = other[y * other_stride + x];
+ int b = truth[y * truth_stride + x];
EXPECT_NEAR(a, b, maxdiff) << " x=" << x << " y=" << y << " "
<< message;
if (std::abs(a - b) > maxdiff) {
LOG(ERROR) << "-------expected--------";
PrintPlane(truth, xsize, truth_stride, ysize);
LOG(ERROR) << "-------actual--------";
- PrintPlane(other, xsize, stride, ysize);
+ PrintPlane(other, xsize, other_stride, ysize);
if (source) {
LOG(ERROR) << "-------before yuv conversion: red--------";
PrintChannel(source, 0);
@@ -1377,15 +1385,18 @@ class GLHelperTest : public testing::Test {
quality,
gfx::Size(xsize, ysize),
gfx::Rect(0, 0, xsize, ysize),
- gfx::Size(output_xsize, output_ysize),
- gfx::Rect(xmargin, ymargin, xsize, ysize),
+ gfx::Size(xsize, ysize),
flip,
use_mrt));
scoped_refptr<media::VideoFrame> output_frame =
media::VideoFrame::CreateFrame(
media::VideoFrame::YV12,
- gfx::Size(output_xsize, output_ysize),
+ // The coded size of the output frame is rounded up to the next
+ // 16-byte boundary. This tests that the readback is being
+ // positioned inside the frame's visible region, and not dependent
+ // on its coded size.
+ gfx::Size((output_xsize + 15) & ~15, (output_ysize + 15) & ~15),
gfx::Rect(0, 0, output_xsize, output_ysize),
gfx::Size(output_xsize, output_ysize),
base::TimeDelta::FromSeconds(0));
@@ -1401,6 +1412,7 @@ class GLHelperTest : public testing::Test {
yuv_reader->ReadbackYUV(mailbox,
sync_point,
output_frame.get(),
+ gfx::Point(xmargin, ymargin),
base::Bind(&callcallback, run_loop.QuitClosure()));
run_loop.Run();
@@ -1408,9 +1420,9 @@ class GLHelperTest : public testing::Test {
FlipSKBitmap(&input_pixels);
}
- unsigned char* Y = truth_frame->data(media::VideoFrame::kYPlane);
- unsigned char* U = truth_frame->data(media::VideoFrame::kUPlane);
- unsigned char* V = truth_frame->data(media::VideoFrame::kVPlane);
+ unsigned char* Y = truth_frame->visible_data(media::VideoFrame::kYPlane);
+ unsigned char* U = truth_frame->visible_data(media::VideoFrame::kUPlane);
+ unsigned char* V = truth_frame->visible_data(media::VideoFrame::kVPlane);
int32 y_stride = truth_frame->stride(media::VideoFrame::kYPlane);
int32 u_stride = truth_frame->stride(media::VideoFrame::kUPlane);
int32 v_stride = truth_frame->stride(media::VideoFrame::kVPlane);
@@ -1454,26 +1466,29 @@ class GLHelperTest : public testing::Test {
}
ComparePlane(Y,
- output_frame->data(media::VideoFrame::kYPlane),
+ y_stride,
+ output_frame->visible_data(media::VideoFrame::kYPlane),
+ output_frame->stride(media::VideoFrame::kYPlane),
2,
output_xsize,
- y_stride,
output_ysize,
&input_pixels,
message + " Y plane");
ComparePlane(U,
- output_frame->data(media::VideoFrame::kUPlane),
+ u_stride,
+ output_frame->visible_data(media::VideoFrame::kUPlane),
+ output_frame->stride(media::VideoFrame::kUPlane),
2,
output_xsize / 2,
- u_stride,
output_ysize / 2,
&input_pixels,
message + " U plane");
ComparePlane(V,
- output_frame->data(media::VideoFrame::kVPlane),
+ v_stride,
+ output_frame->visible_data(media::VideoFrame::kVPlane),
+ output_frame->stride(media::VideoFrame::kVPlane),
2,
output_xsize / 2,
- v_stride,
output_ysize / 2,
&input_pixels,
message + " V plane");
@@ -1950,6 +1965,16 @@ TEST_F(GLHelperTest, CheckOptimizations) {
CheckOptimizationsTest();
}
+} // namespace content
+
+namespace {
+
+int RunHelper(base::TestSuite* test_suite) {
+ content::UnitTestTestSuite runner(test_suite);
+ base::MessageLoopForIO message_loop;
+ return runner.Run();
+}
+
} // namespace
// These tests needs to run against a proper GL environment, so we
@@ -1961,7 +1986,8 @@ int main(int argc, char** argv) {
base::mac::ScopedNSAutoreleasePool pool;
#endif
- content::UnitTestTestSuite runner(suite);
- base::MessageLoop message_loop;
- return runner.Run();
+ return base::LaunchUnitTestsSerially(
+ argc,
+ argv,
+ base::Bind(&RunHelper, base::Unretained(suite)));
}
diff --git a/chromium/content/common/gpu/client/gpu_channel_host.cc b/chromium/content/common/gpu/client/gpu_channel_host.cc
index 77ef8752afc..b4460bbb56e 100644
--- a/chromium/content/common/gpu/client/gpu_channel_host.cc
+++ b/chromium/content/common/gpu/client/gpu_channel_host.cc
@@ -7,11 +7,12 @@
#include <algorithm>
#include "base/bind.h"
-#include "base/debug/trace_event.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/location.h"
#include "base/posix/eintr_wrapper.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
#include "base/threading/thread_restrictions.h"
+#include "base/trace_event/trace_event.h"
#include "content/common/gpu/client/command_buffer_proxy_impl.h"
#include "content/common/gpu/gpu_messages.h"
#include "ipc/ipc_sync_message_filter.h"
@@ -22,7 +23,6 @@
#endif
using base::AutoLock;
-using base::MessageLoopProxy;
namespace content {
@@ -30,6 +30,16 @@ GpuListenerInfo::GpuListenerInfo() {}
GpuListenerInfo::~GpuListenerInfo() {}
+ProxyFlushInfo::ProxyFlushInfo()
+ : flush_pending(false),
+ route_id(MSG_ROUTING_NONE),
+ put_offset(0),
+ flush_count(0) {
+}
+
+ProxyFlushInfo::~ProxyFlushInfo() {
+}
+
// static
scoped_refptr<GpuChannelHost> GpuChannelHost::Create(
GpuChannelHostFactory* factory,
@@ -58,15 +68,14 @@ GpuChannelHost::GpuChannelHost(
void GpuChannelHost::Connect(const IPC::ChannelHandle& channel_handle,
base::WaitableEvent* shutdown_event) {
+ DCHECK(factory_->IsMainThread());
// Open a channel to the GPU process. We pass NULL as the main listener here
// since we need to filter everything to route it to the right thread.
- scoped_refptr<base::MessageLoopProxy> io_loop = factory_->GetIOLoopProxy();
- channel_ = IPC::SyncChannel::Create(channel_handle,
- IPC::Channel::MODE_CLIENT,
- NULL,
- io_loop.get(),
- true,
- shutdown_event);
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner =
+ factory_->GetIOThreadTaskRunner();
+ channel_ =
+ IPC::SyncChannel::Create(channel_handle, IPC::Channel::MODE_CLIENT, NULL,
+ io_task_runner.get(), true, shutdown_event);
sync_filter_ = new IPC::SyncMessageFilter(shutdown_event);
@@ -96,20 +105,55 @@ bool GpuChannelHost::Send(IPC::Message* msg) {
// TODO: Can we just always use sync_filter_ since we setup the channel
// without a main listener?
if (factory_->IsMainThread()) {
+ // channel_ is only modified on the main thread, so we don't need to take a
+ // lock here.
+ if (!channel_) {
+ DVLOG(1) << "GpuChannelHost::Send failed: Channel already destroyed";
+ return false;
+ }
// http://crbug.com/125264
base::ThreadRestrictions::ScopedAllowWait allow_wait;
bool result = channel_->Send(message.release());
if (!result)
DVLOG(1) << "GpuChannelHost::Send failed: Channel::Send failed";
return result;
- } else if (base::MessageLoop::current()) {
- bool result = sync_filter_->Send(message.release());
- if (!result)
- DVLOG(1) << "GpuChannelHost::Send failed: SyncMessageFilter::Send failed";
- return result;
}
- return false;
+ bool result = sync_filter_->Send(message.release());
+ return result;
+}
+
+void GpuChannelHost::OrderingBarrier(
+ int route_id,
+ int32 put_offset,
+ unsigned int flush_count,
+ const std::vector<ui::LatencyInfo>& latency_info,
+ bool put_offset_changed,
+ bool do_flush) {
+ AutoLock lock(context_lock_);
+ if (flush_info_.flush_pending && flush_info_.route_id != route_id)
+ InternalFlush();
+
+ if (put_offset_changed) {
+ flush_info_.flush_pending = true;
+ flush_info_.route_id = route_id;
+ flush_info_.put_offset = put_offset;
+ flush_info_.flush_count = flush_count;
+ flush_info_.latency_info.insert(flush_info_.latency_info.end(),
+ latency_info.begin(), latency_info.end());
+
+ if (do_flush)
+ InternalFlush();
+ }
+}
+
+void GpuChannelHost::InternalFlush() {
+ DCHECK(flush_info_.flush_pending);
+ Send(new GpuCommandBufferMsg_AsyncFlush(
+ flush_info_.route_id, flush_info_.put_offset, flush_info_.flush_count,
+ flush_info_.latency_info));
+ flush_info_.latency_info.clear();
+ flush_info_.flush_pending = false;
}
CommandBufferProxyImpl* GpuChannelHost::CreateViewCommandBuffer(
@@ -140,14 +184,11 @@ CommandBufferProxyImpl* GpuChannelHost::CreateViewCommandBuffer(
// then set up a new connection, and the GPU channel and any
// view command buffers will all be associated with the same GPU
// process.
- DCHECK(MessageLoopProxy::current().get());
-
- scoped_refptr<base::MessageLoopProxy> io_loop =
- factory_->GetIOLoopProxy();
- io_loop->PostTask(
- FROM_HERE,
- base::Bind(&GpuChannelHost::MessageFilter::OnChannelError,
- channel_filter_.get()));
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner =
+ factory_->GetIOThreadTaskRunner();
+ io_task_runner->PostTask(
+ FROM_HERE, base::Bind(&GpuChannelHost::MessageFilter::OnChannelError,
+ channel_filter_.get()));
}
return NULL;
@@ -178,10 +219,8 @@ CommandBufferProxyImpl* GpuChannelHost::CreateOffscreenCommandBuffer(
init_params.gpu_preference = gpu_preference;
int32 route_id = GenerateRouteID();
bool succeeded = false;
- if (!Send(new GpuChannelMsg_CreateOffscreenCommandBuffer(size,
- init_params,
- route_id,
- &succeeded))) {
+ if (!Send(new GpuChannelMsg_CreateOffscreenCommandBuffer(
+ size, init_params, route_id, &succeeded))) {
LOG(ERROR) << "Failed to send GpuChannelMsg_CreateOffscreenCommandBuffer.";
return NULL;
}
@@ -229,25 +268,34 @@ void GpuChannelHost::DestroyCommandBuffer(
AutoLock lock(context_lock_);
proxies_.erase(route_id);
+ if (flush_info_.flush_pending && flush_info_.route_id == route_id)
+ flush_info_.flush_pending = false;
+
delete command_buffer;
}
+void GpuChannelHost::DestroyChannel() {
+ DCHECK(factory_->IsMainThread());
+ AutoLock lock(context_lock_);
+ channel_.reset();
+}
+
void GpuChannelHost::AddRoute(
int route_id, base::WeakPtr<IPC::Listener> listener) {
- DCHECK(MessageLoopProxy::current().get());
-
- scoped_refptr<base::MessageLoopProxy> io_loop = factory_->GetIOLoopProxy();
- io_loop->PostTask(FROM_HERE,
- base::Bind(&GpuChannelHost::MessageFilter::AddRoute,
- channel_filter_.get(), route_id, listener,
- MessageLoopProxy::current()));
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner =
+ factory_->GetIOThreadTaskRunner();
+ io_task_runner->PostTask(FROM_HERE,
+ base::Bind(&GpuChannelHost::MessageFilter::AddRoute,
+ channel_filter_.get(), route_id, listener,
+ base::ThreadTaskRunnerHandle::Get()));
}
void GpuChannelHost::RemoveRoute(int route_id) {
- scoped_refptr<base::MessageLoopProxy> io_loop = factory_->GetIOLoopProxy();
- io_loop->PostTask(FROM_HERE,
- base::Bind(&GpuChannelHost::MessageFilter::RemoveRoute,
- channel_filter_.get(), route_id));
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner =
+ factory_->GetIOThreadTaskRunner();
+ io_task_runner->PostTask(
+ FROM_HERE, base::Bind(&GpuChannelHost::MessageFilter::RemoveRoute,
+ channel_filter_.get(), route_id));
}
base::SharedMemoryHandle GpuChannelHost::ShareToGpuProcess(
@@ -258,8 +306,15 @@ base::SharedMemoryHandle GpuChannelHost::ShareToGpuProcess(
#if defined(OS_WIN)
// Windows needs to explicitly duplicate the handle out to another process.
base::SharedMemoryHandle target_handle;
+ base::ProcessId peer_pid;
+ {
+ AutoLock lock(context_lock_);
+ if (!channel_)
+ return base::SharedMemory::NULLHandle();
+ peer_pid = channel_->GetPeerPID();
+ }
if (!BrokerDuplicateHandle(source_handle,
- channel_->GetPeerPID(),
+ peer_pid,
&target_handle,
FILE_GENERIC_READ | FILE_GENERIC_WRITE,
0)) {
@@ -311,12 +366,13 @@ int32 GpuChannelHost::GenerateRouteID() {
}
GpuChannelHost::~GpuChannelHost() {
- // channel_ must be destroyed on the main thread.
- if (!factory_->IsMainThread())
- factory_->GetMainLoop()->DeleteSoon(FROM_HERE, channel_.release());
+#if DCHECK_IS_ON()
+ AutoLock lock(context_lock_);
+ DCHECK(!channel_)
+ << "GpuChannelHost::DestroyChannel must be called before destruction.";
+#endif
}
-
GpuChannelHost::MessageFilter::MessageFilter()
: lost_(false) {
}
@@ -326,11 +382,12 @@ GpuChannelHost::MessageFilter::~MessageFilter() {}
void GpuChannelHost::MessageFilter::AddRoute(
int route_id,
base::WeakPtr<IPC::Listener> listener,
- scoped_refptr<MessageLoopProxy> loop) {
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
DCHECK(listeners_.find(route_id) == listeners_.end());
+ DCHECK(task_runner);
GpuListenerInfo info;
info.listener = listener;
- info.loop = loop;
+ info.task_runner = task_runner;
listeners_[route_id] = info;
}
@@ -351,12 +408,10 @@ bool GpuChannelHost::MessageFilter::OnMessageReceived(
return false;
const GpuListenerInfo& info = it->second;
- info.loop->PostTask(
+ info.task_runner->PostTask(
FROM_HERE,
- base::Bind(
- base::IgnoreResult(&IPC::Listener::OnMessageReceived),
- info.listener,
- message));
+ base::Bind(base::IgnoreResult(&IPC::Listener::OnMessageReceived),
+ info.listener, message));
return true;
}
@@ -375,9 +430,8 @@ void GpuChannelHost::MessageFilter::OnChannelError() {
it != listeners_.end();
it++) {
const GpuListenerInfo& info = it->second;
- info.loop->PostTask(
- FROM_HERE,
- base::Bind(&IPC::Listener::OnChannelError, info.listener));
+ info.task_runner->PostTask(
+ FROM_HERE, base::Bind(&IPC::Listener::OnChannelError, info.listener));
}
listeners_.clear();
diff --git a/chromium/content/common/gpu/client/gpu_channel_host.h b/chromium/content/common/gpu/client/gpu_channel_host.h
index ebbbdac3f66..4ec2e06d2bd 100644
--- a/chromium/content/common/gpu/client/gpu_channel_host.h
+++ b/chromium/content/common/gpu/client/gpu_channel_host.h
@@ -23,9 +23,10 @@
#include "ipc/ipc_channel_handle.h"
#include "ipc/ipc_sync_channel.h"
#include "ipc/message_filter.h"
+#include "ui/events/latency_info.h"
+#include "ui/gfx/geometry/size.h"
#include "ui/gfx/gpu_memory_buffer.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/size.h"
#include "ui/gl/gpu_preference.h"
class GURL;
@@ -34,7 +35,6 @@ struct GPUCreateCommandBufferConfig;
namespace base {
class MessageLoop;
-class MessageLoopProxy;
class WaitableEvent;
}
@@ -60,7 +60,18 @@ struct GpuListenerInfo {
~GpuListenerInfo();
base::WeakPtr<IPC::Listener> listener;
- scoped_refptr<base::MessageLoopProxy> loop;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner;
+};
+
+struct ProxyFlushInfo {
+ ProxyFlushInfo();
+ ~ProxyFlushInfo();
+
+ bool flush_pending;
+ int route_id;
+ int32 put_offset;
+ unsigned int flush_count;
+ std::vector<ui::LatencyInfo> latency_info;
};
class CONTENT_EXPORT GpuChannelHostFactory {
@@ -68,8 +79,8 @@ class CONTENT_EXPORT GpuChannelHostFactory {
virtual ~GpuChannelHostFactory() {}
virtual bool IsMainThread() = 0;
- virtual base::MessageLoop* GetMainLoop() = 0;
- virtual scoped_refptr<base::MessageLoopProxy> GetIOLoopProxy() = 0;
+ virtual scoped_refptr<base::SingleThreadTaskRunner>
+ GetIOThreadTaskRunner() = 0;
virtual scoped_ptr<base::SharedMemory> AllocateSharedMemory(size_t size) = 0;
virtual CreateCommandBufferResult CreateViewCommandBuffer(
int32 surface_id,
@@ -103,6 +114,15 @@ class GpuChannelHost : public IPC::Sender,
// IPC::Sender implementation:
bool Send(IPC::Message* msg) override;
+ // Set an ordering barrier. AsyncFlushes any pending barriers on other
+ // routes. Combines multiple OrderingBarriers into a single AsyncFlush.
+ void OrderingBarrier(int route_id,
+ int32 put_offset,
+ unsigned int flush_count,
+ const std::vector<ui::LatencyInfo>& latency_info,
+ bool put_offset_changed,
+ bool do_flush);
+
// Create and connect to a command buffer in the GPU process.
CommandBufferProxyImpl* CreateViewCommandBuffer(
int32 surface_id,
@@ -130,6 +150,10 @@ class GpuChannelHost : public IPC::Sender,
// Destroy a command buffer created by this channel.
void DestroyCommandBuffer(CommandBufferProxyImpl* command_buffer);
+ // Destroy this channel. Must be called on the main thread, before
+ // destruction.
+ void DestroyChannel();
+
// Add a route for the current message loop.
void AddRoute(int route_id, base::WeakPtr<IPC::Listener> listener);
void RemoveRoute(int route_id);
@@ -170,6 +194,8 @@ class GpuChannelHost : public IPC::Sender,
~GpuChannelHost() override;
void Connect(const IPC::ChannelHandle& channel_handle,
base::WaitableEvent* shutdown_event);
+ bool InternalSend(IPC::Message* msg);
+ void InternalFlush();
// A filter used internally to route incoming messages from the IO thread
// to the correct message loop. It also maintains some shared state between
@@ -181,7 +207,7 @@ class GpuChannelHost : public IPC::Sender,
// Called on the IO thread.
void AddRoute(int route_id,
base::WeakPtr<IPC::Listener> listener,
- scoped_refptr<base::MessageLoopProxy> loop);
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner);
// Called on the IO thread.
void RemoveRoute(int route_id);
@@ -220,7 +246,6 @@ class GpuChannelHost : public IPC::Sender,
const gpu::GPUInfo gpu_info_;
- scoped_ptr<IPC::SyncChannel> channel_;
scoped_refptr<MessageFilter> channel_filter_;
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager_;
@@ -237,11 +262,13 @@ class GpuChannelHost : public IPC::Sender,
// Route IDs are allocated in sequence.
base::AtomicSequenceNumber next_route_id_;
- // Protects proxies_.
+ // Protects channel_ and proxies_.
mutable base::Lock context_lock_;
+ scoped_ptr<IPC::SyncChannel> channel_;
// Used to look up a proxy from its routing id.
typedef base::hash_map<int, CommandBufferProxyImpl*> ProxyMap;
ProxyMap proxies_;
+ ProxyFlushInfo flush_info_;
DISALLOW_COPY_AND_ASSIGN(GpuChannelHost);
};
diff --git a/chromium/content/common/gpu/client/gpu_in_process_context_tests.cc b/chromium/content/common/gpu/client/gpu_in_process_context_tests.cc
index 3e134f5adf7..6e740572211 100644
--- a/chromium/content/common/gpu/client/gpu_in_process_context_tests.cc
+++ b/chromium/content/common/gpu/client/gpu_in_process_context_tests.cc
@@ -8,13 +8,13 @@
#include <vector>
#include "content/public/test/unittest_test_suite.h"
+#include "gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gl/gl_surface.h"
-#include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"
namespace {
-using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;
+using gpu_blink::WebGraphicsContext3DInProcessCommandBufferImpl;
class ContextTestBase : public testing::Test {
public:
diff --git a/chromium/content/common/gpu/client/gpu_memory_buffer_factory_host.cc b/chromium/content/common/gpu/client/gpu_memory_buffer_factory_host.cc
deleted file mode 100644
index ea7a321d1c5..00000000000
--- a/chromium/content/common/gpu/client/gpu_memory_buffer_factory_host.cc
+++ /dev/null
@@ -1,27 +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/common/gpu/client/gpu_memory_buffer_factory_host.h"
-
-#include "base/logging.h"
-
-namespace content {
-namespace {
-GpuMemoryBufferFactoryHost* instance = NULL;
-}
-
-// static
-GpuMemoryBufferFactoryHost* GpuMemoryBufferFactoryHost::GetInstance() {
- return instance;
-}
-
-GpuMemoryBufferFactoryHost::GpuMemoryBufferFactoryHost() {
- DCHECK(instance == NULL);
- instance = this;
-}
-
-GpuMemoryBufferFactoryHost::~GpuMemoryBufferFactoryHost() {
- instance = NULL;
-}
-}
diff --git a/chromium/content/common/gpu/client/gpu_memory_buffer_factory_host.h b/chromium/content/common/gpu/client/gpu_memory_buffer_factory_host.h
index 827308ed79e..fc42b1804b1 100644
--- a/chromium/content/common/gpu/client/gpu_memory_buffer_factory_host.h
+++ b/chromium/content/common/gpu/client/gpu_memory_buffer_factory_host.h
@@ -20,24 +20,23 @@ class CONTENT_EXPORT GpuMemoryBufferFactoryHost {
typedef base::Callback<void(const gfx::GpuMemoryBufferHandle& handle)>
CreateGpuMemoryBufferCallback;
- static GpuMemoryBufferFactoryHost* GetInstance();
-
+ virtual bool IsGpuMemoryBufferConfigurationSupported(
+ gfx::GpuMemoryBuffer::Format format,
+ gfx::GpuMemoryBuffer::Usage usage) = 0;
virtual void CreateGpuMemoryBuffer(
- gfx::GpuMemoryBufferType type,
gfx::GpuMemoryBufferId id,
const gfx::Size& size,
gfx::GpuMemoryBuffer::Format format,
gfx::GpuMemoryBuffer::Usage usage,
int client_id,
+ int32 surface_id,
const CreateGpuMemoryBufferCallback& callback) = 0;
- virtual void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferType type,
- gfx::GpuMemoryBufferId id,
+ virtual void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
int client_id,
int32 sync_point) = 0;
protected:
- GpuMemoryBufferFactoryHost();
- virtual ~GpuMemoryBufferFactoryHost();
+ virtual ~GpuMemoryBufferFactoryHost() {}
};
} // namespace content
diff --git a/chromium/content/common/gpu/client/gpu_memory_buffer_impl.cc b/chromium/content/common/gpu/client/gpu_memory_buffer_impl.cc
index 65edde33f12..0b2d249db42 100644
--- a/chromium/content/common/gpu/client/gpu_memory_buffer_impl.cc
+++ b/chromium/content/common/gpu/client/gpu_memory_buffer_impl.cc
@@ -4,8 +4,23 @@
#include "content/common/gpu/client/gpu_memory_buffer_impl.h"
+#include "base/logging.h"
+#include "base/numerics/safe_math.h"
+#include "content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h"
#include "ui/gl/gl_bindings.h"
+#if defined(OS_MACOSX)
+#include "content/common/gpu/client/gpu_memory_buffer_impl_io_surface.h"
+#endif
+
+#if defined(OS_ANDROID)
+#include "content/common/gpu/client/gpu_memory_buffer_impl_surface_texture.h"
+#endif
+
+#if defined(USE_OZONE)
+#include "content/common/gpu/client/gpu_memory_buffer_impl_ozone_native_buffer.h"
+#endif
+
namespace content {
GpuMemoryBufferImpl::GpuMemoryBufferImpl(gfx::GpuMemoryBufferId id,
@@ -25,24 +40,150 @@ GpuMemoryBufferImpl::~GpuMemoryBufferImpl() {
}
// static
+scoped_ptr<GpuMemoryBufferImpl> GpuMemoryBufferImpl::CreateFromHandle(
+ const gfx::GpuMemoryBufferHandle& handle,
+ const gfx::Size& size,
+ Format format,
+ const DestructionCallback& callback) {
+ switch (handle.type) {
+ case gfx::SHARED_MEMORY_BUFFER:
+ return GpuMemoryBufferImplSharedMemory::CreateFromHandle(
+ handle, size, format, callback);
+#if defined(OS_MACOSX)
+ case gfx::IO_SURFACE_BUFFER:
+ return GpuMemoryBufferImplIOSurface::CreateFromHandle(
+ handle, size, format, callback);
+#endif
+#if defined(OS_ANDROID)
+ case gfx::SURFACE_TEXTURE_BUFFER:
+ return GpuMemoryBufferImplSurfaceTexture::CreateFromHandle(
+ handle, size, format, callback);
+#endif
+#if defined(USE_OZONE)
+ case gfx::OZONE_NATIVE_BUFFER:
+ return GpuMemoryBufferImplOzoneNativeBuffer::CreateFromHandle(
+ handle, size, format, callback);
+#endif
+ default:
+ NOTREACHED();
+ return scoped_ptr<GpuMemoryBufferImpl>();
+ }
+}
+
+// static
GpuMemoryBufferImpl* GpuMemoryBufferImpl::FromClientBuffer(
ClientBuffer buffer) {
return reinterpret_cast<GpuMemoryBufferImpl*>(buffer);
}
// static
-size_t GpuMemoryBufferImpl::BytesPerPixel(Format format) {
+size_t GpuMemoryBufferImpl::NumberOfPlanesForGpuMemoryBufferFormat(
+ Format format) {
switch (format) {
+ case ATC:
+ case ATCIA:
+ case DXT1:
+ case DXT5:
+ case ETC1:
+ case R_8:
case RGBA_8888:
case RGBX_8888:
case BGRA_8888:
- return 4;
+ return 1;
+ case YUV_420:
+ return 3;
}
+ NOTREACHED();
+ return 0;
+}
+// static
+size_t GpuMemoryBufferImpl::SubsamplingFactor(Format format, int plane) {
+ switch (format) {
+ case ATC:
+ case ATCIA:
+ case DXT1:
+ case DXT5:
+ case ETC1:
+ case R_8:
+ case RGBA_8888:
+ case RGBX_8888:
+ case BGRA_8888:
+ return 1;
+ case YUV_420: {
+ static size_t factor[] = {1, 2, 2};
+ DCHECK_LT(static_cast<size_t>(plane), arraysize(factor));
+ return factor[plane];
+ }
+ }
NOTREACHED();
return 0;
}
+// static
+bool GpuMemoryBufferImpl::RowSizeInBytes(size_t width,
+ Format format,
+ int plane,
+ size_t* size_in_bytes) {
+ base::CheckedNumeric<size_t> checked_size = width;
+ switch (format) {
+ case ATCIA:
+ case DXT5:
+ DCHECK_EQ(plane, 0);
+ *size_in_bytes = width;
+ return true;
+ case ATC:
+ case DXT1:
+ case ETC1:
+ DCHECK_EQ(plane, 0);
+ DCHECK_EQ(width % 2, 0u);
+ *size_in_bytes = width / 2;
+ return true;
+ case R_8:
+ checked_size += 3;
+ if (!checked_size.IsValid())
+ return false;
+ *size_in_bytes = checked_size.ValueOrDie() & ~0x3;
+ return true;
+ case RGBX_8888:
+ case RGBA_8888:
+ case BGRA_8888:
+ checked_size *= 4;
+ if (!checked_size.IsValid())
+ return false;
+ *size_in_bytes = checked_size.ValueOrDie();
+ return true;
+ case YUV_420:
+ DCHECK_EQ(width % 2, 0u);
+ *size_in_bytes = width / SubsamplingFactor(format, plane);
+ return true;
+ }
+ NOTREACHED();
+ return false;
+}
+
+// static
+bool GpuMemoryBufferImpl::BufferSizeInBytes(const gfx::Size& size,
+ Format format,
+ size_t* size_in_bytes) {
+ base::CheckedNumeric<size_t> checked_size = 0;
+ size_t num_planes = NumberOfPlanesForGpuMemoryBufferFormat(format);
+ for (size_t i = 0; i < num_planes; ++i) {
+ size_t row_size_in_bytes = 0;
+ if (!RowSizeInBytes(size.width(), format, i, &row_size_in_bytes))
+ return false;
+ base::CheckedNumeric<size_t> checked_plane_size = row_size_in_bytes;
+ checked_plane_size *= size.height() / SubsamplingFactor(format, i);
+ if (!checked_plane_size.IsValid())
+ return false;
+ checked_size += checked_plane_size.ValueOrDie();
+ if (!checked_size.IsValid())
+ return false;
+ }
+ *size_in_bytes = checked_size.ValueOrDie();
+ return true;
+}
+
gfx::GpuMemoryBuffer::Format GpuMemoryBufferImpl::GetFormat() const {
return format_;
}
diff --git a/chromium/content/common/gpu/client/gpu_memory_buffer_impl.h b/chromium/content/common/gpu/client/gpu_memory_buffer_impl.h
index 52d5aef1095..1a7e043d606 100644
--- a/chromium/content/common/gpu/client/gpu_memory_buffer_impl.h
+++ b/chromium/content/common/gpu/client/gpu_memory_buffer_impl.h
@@ -7,49 +7,19 @@
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
+#include "content/common/content_export.h"
+#include "ui/gfx/geometry/size.h"
#include "ui/gfx/gpu_memory_buffer.h"
-#include "ui/gfx/size.h"
namespace content {
// Provides common implementation of a GPU memory buffer.
-class GpuMemoryBufferImpl : public gfx::GpuMemoryBuffer {
+class CONTENT_EXPORT GpuMemoryBufferImpl : public gfx::GpuMemoryBuffer {
public:
- typedef base::Callback<void(scoped_ptr<GpuMemoryBufferImpl> buffer)>
- CreationCallback;
- typedef base::Callback<void(const gfx::GpuMemoryBufferHandle& handle)>
- AllocationCallback;
typedef base::Callback<void(uint32 sync_point)> DestructionCallback;
~GpuMemoryBufferImpl() override;
- // Creates a GPU memory buffer instance with |size| and |format| for |usage|
- // by the current process and |client_id|.
- static void Create(gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- Format format,
- Usage usage,
- int client_id,
- const CreationCallback& callback);
-
- // Allocates a GPU memory buffer with |size| and |internalformat| for |usage|
- // by |child_process| and |child_client_id|. The |handle| returned can be
- // used by the |child_process| to create an instance of this class.
- static void AllocateForChildProcess(gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- Format format,
- Usage usage,
- base::ProcessHandle child_process,
- int child_client_id,
- const AllocationCallback& callback);
-
- // Notify that GPU memory buffer has been deleted by |child_process|.
- static void DeletedByChildProcess(gfx::GpuMemoryBufferType type,
- gfx::GpuMemoryBufferId id,
- base::ProcessHandle child_process,
- int child_client_id,
- uint32 sync_point);
-
// Creates an instance from the given |handle|. |size| and |internalformat|
// should match what was used to allocate the |handle|. |callback| is
// called when instance is deleted, which is not necessarily on the same
@@ -63,9 +33,29 @@ class GpuMemoryBufferImpl : public gfx::GpuMemoryBuffer {
// Type-checking upcast routine. Returns an NULL on failure.
static GpuMemoryBufferImpl* FromClientBuffer(ClientBuffer buffer);
- // Returns the number of bytes per pixel that must be used by an
- // implementation when using |format|.
- static size_t BytesPerPixel(Format format);
+ // Returns the number of planes based on the format of the buffer.
+ static size_t NumberOfPlanesForGpuMemoryBufferFormat(Format format);
+
+ // Returns the subsampling factor applied to the given zero-indexed |plane| of
+ // the |format| both horizontally and vertically.
+ static size_t SubsamplingFactor(Format format, int plane);
+
+ // Returns the number of bytes used to store a row of the given zero-indexed
+ // |plane| of |format|.
+ // Note: This is an approximation and the exact size used by an implementation
+ // might be different.
+ static bool RowSizeInBytes(size_t width,
+ Format format,
+ int plane,
+ size_t* size_in_bytes);
+
+ // Returns the number of bytes used to store all the planes of a given
+ // |format|.
+ // Note: This is an approximation and the exact size used by an implementation
+ // might be different.
+ static bool BufferSizeInBytes(const gfx::Size& size,
+ Format format,
+ size_t* size_in_bytes);
// Overridden from gfx::GpuMemoryBuffer:
bool IsMapped() const override;
@@ -89,6 +79,7 @@ class GpuMemoryBufferImpl : public gfx::GpuMemoryBuffer {
bool mapped_;
uint32 destruction_sync_point_;
+ private:
DISALLOW_COPY_AND_ASSIGN(GpuMemoryBufferImpl);
};
diff --git a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_android.cc b/chromium/content/common/gpu/client/gpu_memory_buffer_impl_android.cc
deleted file mode 100644
index 9c0fdb368c6..00000000000
--- a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_android.cc
+++ /dev/null
@@ -1,99 +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/common/gpu/client/gpu_memory_buffer_impl.h"
-
-#include "content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h"
-#include "content/common/gpu/client/gpu_memory_buffer_impl_surface_texture.h"
-
-namespace content {
-
-// static
-void GpuMemoryBufferImpl::Create(gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- Format format,
- Usage usage,
- int client_id,
- const CreationCallback& callback) {
- if (GpuMemoryBufferImplSurfaceTexture::IsConfigurationSupported(format,
- usage)) {
- GpuMemoryBufferImplSurfaceTexture::Create(
- id, size, format, client_id, callback);
- return;
- }
-
- if (GpuMemoryBufferImplSharedMemory::IsConfigurationSupported(
- size, format, usage)) {
- GpuMemoryBufferImplSharedMemory::Create(id, size, format, callback);
- return;
- }
-
- callback.Run(scoped_ptr<GpuMemoryBufferImpl>());
-}
-
-// static
-void GpuMemoryBufferImpl::AllocateForChildProcess(
- gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- Format format,
- Usage usage,
- base::ProcessHandle child_process,
- int child_client_id,
- const AllocationCallback& callback) {
- if (GpuMemoryBufferImplSurfaceTexture::IsConfigurationSupported(format,
- usage)) {
- GpuMemoryBufferImplSurfaceTexture::AllocateForChildProcess(
- id, size, format, child_client_id, callback);
- return;
- }
-
- if (GpuMemoryBufferImplSharedMemory::IsConfigurationSupported(
- size, format, usage)) {
- GpuMemoryBufferImplSharedMemory::AllocateForChildProcess(
- id, size, format, child_process, callback);
- return;
- }
-
- callback.Run(gfx::GpuMemoryBufferHandle());
-}
-
-// static
-void GpuMemoryBufferImpl::DeletedByChildProcess(
- gfx::GpuMemoryBufferType type,
- gfx::GpuMemoryBufferId id,
- base::ProcessHandle child_process,
- int child_client_id,
- uint32 sync_point) {
- switch (type) {
- case gfx::SHARED_MEMORY_BUFFER:
- break;
- case gfx::SURFACE_TEXTURE_BUFFER:
- GpuMemoryBufferImplSurfaceTexture::DeletedByChildProcess(
- id, child_client_id, sync_point);
- break;
- default:
- NOTREACHED();
- break;
- }
-}
-
-// static
-scoped_ptr<GpuMemoryBufferImpl> GpuMemoryBufferImpl::CreateFromHandle(
- const gfx::GpuMemoryBufferHandle& handle,
- const gfx::Size& size,
- Format format,
- const DestructionCallback& callback) {
- switch (handle.type) {
- case gfx::SHARED_MEMORY_BUFFER:
- return GpuMemoryBufferImplSharedMemory::CreateFromHandle(
- handle, size, format, callback);
- case gfx::SURFACE_TEXTURE_BUFFER:
- return GpuMemoryBufferImplSurfaceTexture::CreateFromHandle(
- handle, size, format, callback);
- default:
- return scoped_ptr<GpuMemoryBufferImpl>();
- }
-}
-
-} // namespace content
diff --git a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_io_surface.cc b/chromium/content/common/gpu/client/gpu_memory_buffer_impl_io_surface.cc
index 088795c974a..ed7836c197d 100644
--- a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_io_surface.cc
+++ b/chromium/content/common/gpu/client/gpu_memory_buffer_impl_io_surface.cc
@@ -4,49 +4,9 @@
#include "content/common/gpu/client/gpu_memory_buffer_impl_io_surface.h"
-#include "base/bind.h"
#include "base/logging.h"
-#include "content/common/gpu/client/gpu_memory_buffer_factory_host.h"
-#include "ui/gl/gl_bindings.h"
namespace content {
-namespace {
-
-void GpuMemoryBufferDeleted(gfx::GpuMemoryBufferId id,
- int client_id,
- uint32 sync_point) {
- GpuMemoryBufferFactoryHost::GetInstance()->DestroyGpuMemoryBuffer(
- gfx::IO_SURFACE_BUFFER, id, client_id, sync_point);
-}
-
-void GpuMemoryBufferCreated(
- const gfx::Size& size,
- gfx::GpuMemoryBuffer::Format format,
- int client_id,
- const GpuMemoryBufferImpl::CreationCallback& callback,
- const gfx::GpuMemoryBufferHandle& handle) {
- if (handle.is_null()) {
- callback.Run(scoped_ptr<GpuMemoryBufferImpl>());
- return;
- }
-
- DCHECK_EQ(gfx::IO_SURFACE_BUFFER, handle.type);
- callback.Run(GpuMemoryBufferImplIOSurface::CreateFromHandle(
- handle,
- size,
- format,
- base::Bind(&GpuMemoryBufferDeleted, handle.id, client_id)));
-}
-
-void GpuMemoryBufferCreatedForChildProcess(
- const GpuMemoryBufferImpl::AllocationCallback& callback,
- const gfx::GpuMemoryBufferHandle& handle) {
- DCHECK_IMPLIES(!handle.is_null(), gfx::IO_SURFACE_BUFFER == handle.type);
-
- callback.Run(handle);
-}
-
-} // namespace
GpuMemoryBufferImplIOSurface::GpuMemoryBufferImplIOSurface(
gfx::GpuMemoryBufferId id,
@@ -61,117 +21,26 @@ GpuMemoryBufferImplIOSurface::~GpuMemoryBufferImplIOSurface() {
}
// static
-void GpuMemoryBufferImplIOSurface::Create(gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- Format format,
- int client_id,
- const CreationCallback& callback) {
- GpuMemoryBufferFactoryHost::GetInstance()->CreateGpuMemoryBuffer(
- gfx::IO_SURFACE_BUFFER,
- id,
- size,
- format,
- MAP,
- client_id,
- base::Bind(&GpuMemoryBufferCreated, size, format, client_id, callback));
-}
-
-// static
-void GpuMemoryBufferImplIOSurface::AllocateForChildProcess(
- gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- Format format,
- int child_client_id,
- const AllocationCallback& callback) {
- GpuMemoryBufferFactoryHost::GetInstance()->CreateGpuMemoryBuffer(
- gfx::IO_SURFACE_BUFFER,
- id,
- size,
- format,
- MAP,
- child_client_id,
- base::Bind(&GpuMemoryBufferCreatedForChildProcess, callback));
-}
-
-// static
scoped_ptr<GpuMemoryBufferImpl> GpuMemoryBufferImplIOSurface::CreateFromHandle(
const gfx::GpuMemoryBufferHandle& handle,
const gfx::Size& size,
Format format,
const DestructionCallback& callback) {
- DCHECK(IsFormatSupported(format));
-
base::ScopedCFTypeRef<IOSurfaceRef> io_surface(
IOSurfaceLookup(handle.io_surface_id));
if (!io_surface)
return scoped_ptr<GpuMemoryBufferImpl>();
return make_scoped_ptr<GpuMemoryBufferImpl>(new GpuMemoryBufferImplIOSurface(
- handle.id, size, format, callback, io_surface.get()));
-}
-
-// static
-void GpuMemoryBufferImplIOSurface::DeletedByChildProcess(
- gfx::GpuMemoryBufferId id,
- int child_client_id,
- uint32_t sync_point) {
- GpuMemoryBufferFactoryHost::GetInstance()->DestroyGpuMemoryBuffer(
- gfx::IO_SURFACE_BUFFER, id, child_client_id, sync_point);
-}
-
-// static
-bool GpuMemoryBufferImplIOSurface::IsFormatSupported(Format format) {
- switch (format) {
- case BGRA_8888:
- return true;
- case RGBA_8888:
- case RGBX_8888:
- return false;
- }
-
- NOTREACHED();
- return false;
-}
-
-// static
-bool GpuMemoryBufferImplIOSurface::IsUsageSupported(Usage usage) {
- switch (usage) {
- case MAP:
- return true;
- case SCANOUT:
- return false;
- }
-
- NOTREACHED();
- return false;
-}
-
-// static
-bool GpuMemoryBufferImplIOSurface::IsConfigurationSupported(Format format,
- Usage usage) {
- return IsFormatSupported(format) && IsUsageSupported(usage);
-}
-
-// static
-uint32 GpuMemoryBufferImplIOSurface::PixelFormat(Format format) {
- switch (format) {
- case BGRA_8888:
- return 'BGRA';
- case RGBA_8888:
- case RGBX_8888:
- NOTREACHED();
- return 0;
- }
-
- NOTREACHED();
- return 0;
+ handle.id, size, format, callback, io_surface.release()));
}
-void* GpuMemoryBufferImplIOSurface::Map() {
+bool GpuMemoryBufferImplIOSurface::Map(void** data) {
DCHECK(!mapped_);
IOSurfaceLock(io_surface_, 0, NULL);
mapped_ = true;
- return IOSurfaceGetBaseAddress(io_surface_);
+ *data = IOSurfaceGetBaseAddress(io_surface_);
+ return true;
}
void GpuMemoryBufferImplIOSurface::Unmap() {
@@ -180,8 +49,8 @@ void GpuMemoryBufferImplIOSurface::Unmap() {
mapped_ = false;
}
-uint32 GpuMemoryBufferImplIOSurface::GetStride() const {
- return IOSurfaceGetBytesPerRow(io_surface_);
+void GpuMemoryBufferImplIOSurface::GetStride(int* stride) const {
+ *stride = IOSurfaceGetBytesPerRow(io_surface_);
}
gfx::GpuMemoryBufferHandle GpuMemoryBufferImplIOSurface::GetHandle() const {
diff --git a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_io_surface.h b/chromium/content/common/gpu/client/gpu_memory_buffer_impl_io_surface.h
index 4cd1903377a..89d4834bb54 100644
--- a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_io_surface.h
+++ b/chromium/content/common/gpu/client/gpu_memory_buffer_impl_io_surface.h
@@ -15,37 +15,16 @@ namespace content {
// Implementation of GPU memory buffer based on IO surfaces.
class GpuMemoryBufferImplIOSurface : public GpuMemoryBufferImpl {
public:
- static void Create(gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- Format format,
- int client_id,
- const CreationCallback& callback);
-
- static void AllocateForChildProcess(gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- Format format,
- int child_client_id,
- const AllocationCallback& callback);
-
static scoped_ptr<GpuMemoryBufferImpl> CreateFromHandle(
const gfx::GpuMemoryBufferHandle& handle,
const gfx::Size& size,
Format format,
const DestructionCallback& callback);
- static void DeletedByChildProcess(gfx::GpuMemoryBufferId id,
- int child_client_id,
- uint32_t sync_point);
-
- static bool IsFormatSupported(Format format);
- static bool IsUsageSupported(Usage usage);
- static bool IsConfigurationSupported(Format format, Usage usage);
- static uint32 PixelFormat(Format format);
-
// Overridden from gfx::GpuMemoryBuffer:
- void* Map() override;
+ bool Map(void** data) override;
void Unmap() override;
- uint32 GetStride() const override;
+ void GetStride(int* stride) const override;
gfx::GpuMemoryBufferHandle GetHandle() const override;
private:
diff --git a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_linux.cc b/chromium/content/common/gpu/client/gpu_memory_buffer_impl_linux.cc
deleted file mode 100644
index 3c144f37ccf..00000000000
--- a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_linux.cc
+++ /dev/null
@@ -1,70 +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/common/gpu/client/gpu_memory_buffer_impl.h"
-
-#include "content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h"
-
-namespace content {
-
-// static
-void GpuMemoryBufferImpl::Create(gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- Format format,
- Usage usage,
- int client_id,
- const CreationCallback& callback) {
- if (GpuMemoryBufferImplSharedMemory::IsConfigurationSupported(
- size, format, usage)) {
- GpuMemoryBufferImplSharedMemory::Create(id, size, format, callback);
- return;
- }
-
- callback.Run(scoped_ptr<GpuMemoryBufferImpl>());
-}
-
-// static
-void GpuMemoryBufferImpl::AllocateForChildProcess(
- gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- Format format,
- Usage usage,
- base::ProcessHandle child_process,
- int child_client_id,
- const AllocationCallback& callback) {
- if (GpuMemoryBufferImplSharedMemory::IsConfigurationSupported(
- size, format, usage)) {
- GpuMemoryBufferImplSharedMemory::AllocateForChildProcess(
- id, size, format, child_process, callback);
- return;
- }
-
- callback.Run(gfx::GpuMemoryBufferHandle());
-}
-
-// static
-void GpuMemoryBufferImpl::DeletedByChildProcess(
- gfx::GpuMemoryBufferType type,
- gfx::GpuMemoryBufferId id,
- base::ProcessHandle child_process,
- int child_client_id,
- uint32 sync_point) {
-}
-
-// static
-scoped_ptr<GpuMemoryBufferImpl> GpuMemoryBufferImpl::CreateFromHandle(
- const gfx::GpuMemoryBufferHandle& handle,
- const gfx::Size& size,
- Format format,
- const DestructionCallback& callback) {
- switch (handle.type) {
- case gfx::SHARED_MEMORY_BUFFER:
- return GpuMemoryBufferImplSharedMemory::CreateFromHandle(
- handle, size, format, callback);
- default:
- return scoped_ptr<GpuMemoryBufferImpl>();
- }
-}
-
-} // namespace content
diff --git a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_mac.cc b/chromium/content/common/gpu/client/gpu_memory_buffer_impl_mac.cc
deleted file mode 100644
index c4e9a03fe77..00000000000
--- a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_mac.cc
+++ /dev/null
@@ -1,96 +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/common/gpu/client/gpu_memory_buffer_impl.h"
-
-#include "content/common/gpu/client/gpu_memory_buffer_impl_io_surface.h"
-#include "content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h"
-
-namespace content {
-
-// static
-void GpuMemoryBufferImpl::Create(gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- Format format,
- Usage usage,
- int client_id,
- const CreationCallback& callback) {
- if (GpuMemoryBufferImplIOSurface::IsConfigurationSupported(format, usage)) {
- GpuMemoryBufferImplIOSurface::Create(id, size, format, client_id, callback);
- return;
- }
-
- if (GpuMemoryBufferImplSharedMemory::IsConfigurationSupported(
- size, format, usage)) {
- GpuMemoryBufferImplSharedMemory::Create(id, size, format, callback);
- return;
- }
-
- callback.Run(scoped_ptr<GpuMemoryBufferImpl>());
-}
-
-// static
-void GpuMemoryBufferImpl::AllocateForChildProcess(
- gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- Format format,
- Usage usage,
- base::ProcessHandle child_process,
- int child_client_id,
- const AllocationCallback& callback) {
- if (GpuMemoryBufferImplIOSurface::IsConfigurationSupported(format, usage)) {
- GpuMemoryBufferImplIOSurface::AllocateForChildProcess(
- id, size, format, child_client_id, callback);
- return;
- }
-
- if (GpuMemoryBufferImplSharedMemory::IsConfigurationSupported(
- size, format, usage)) {
- GpuMemoryBufferImplSharedMemory::AllocateForChildProcess(
- id, size, format, child_process, callback);
- return;
- }
-
- callback.Run(gfx::GpuMemoryBufferHandle());
-}
-
-// static
-void GpuMemoryBufferImpl::DeletedByChildProcess(
- gfx::GpuMemoryBufferType type,
- gfx::GpuMemoryBufferId id,
- base::ProcessHandle child_process,
- int child_client_id,
- uint32 sync_point) {
- switch (type) {
- case gfx::SHARED_MEMORY_BUFFER:
- break;
- case gfx::IO_SURFACE_BUFFER:
- GpuMemoryBufferImplIOSurface::DeletedByChildProcess(
- id, child_client_id, sync_point);
- break;
- default:
- NOTREACHED();
- break;
- }
-}
-
-// static
-scoped_ptr<GpuMemoryBufferImpl> GpuMemoryBufferImpl::CreateFromHandle(
- const gfx::GpuMemoryBufferHandle& handle,
- const gfx::Size& size,
- Format format,
- const DestructionCallback& callback) {
- switch (handle.type) {
- case gfx::SHARED_MEMORY_BUFFER:
- return GpuMemoryBufferImplSharedMemory::CreateFromHandle(
- handle, size, format, callback);
- case gfx::IO_SURFACE_BUFFER:
- return GpuMemoryBufferImplIOSurface::CreateFromHandle(
- handle, size, format, callback);
- default:
- return scoped_ptr<GpuMemoryBufferImpl>();
- }
-}
-
-} // namespace content
diff --git a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_ozone.cc b/chromium/content/common/gpu/client/gpu_memory_buffer_impl_ozone.cc
deleted file mode 100644
index 236d2bd5860..00000000000
--- a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_ozone.cc
+++ /dev/null
@@ -1,99 +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/common/gpu/client/gpu_memory_buffer_impl.h"
-
-#include "content/common/gpu/client/gpu_memory_buffer_impl_ozone_native_buffer.h"
-#include "content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h"
-
-namespace content {
-
-// static
-void GpuMemoryBufferImpl::Create(gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- Format format,
- Usage usage,
- int client_id,
- const CreationCallback& callback) {
- if (GpuMemoryBufferImplOzoneNativeBuffer::IsConfigurationSupported(format,
- usage)) {
- GpuMemoryBufferImplOzoneNativeBuffer::Create(
- id, size, format, client_id, callback);
- return;
- }
-
- if (GpuMemoryBufferImplSharedMemory::IsConfigurationSupported(
- size, format, usage)) {
- GpuMemoryBufferImplSharedMemory::Create(id, size, format, callback);
- return;
- }
-
- callback.Run(scoped_ptr<GpuMemoryBufferImpl>());
-}
-
-// static
-void GpuMemoryBufferImpl::AllocateForChildProcess(
- gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- Format format,
- Usage usage,
- base::ProcessHandle child_process,
- int child_client_id,
- const AllocationCallback& callback) {
- if (GpuMemoryBufferImplOzoneNativeBuffer::IsConfigurationSupported(format,
- usage)) {
- GpuMemoryBufferImplOzoneNativeBuffer::AllocateForChildProcess(
- id, size, format, child_client_id, callback);
- return;
- }
-
- if (GpuMemoryBufferImplSharedMemory::IsConfigurationSupported(
- size, format, usage)) {
- GpuMemoryBufferImplSharedMemory::AllocateForChildProcess(
- id, size, format, child_process, callback);
- return;
- }
-
- callback.Run(gfx::GpuMemoryBufferHandle());
-}
-
-// static
-void GpuMemoryBufferImpl::DeletedByChildProcess(
- gfx::GpuMemoryBufferType type,
- gfx::GpuMemoryBufferId id,
- base::ProcessHandle child_process,
- int child_client_id,
- uint32_t sync_point) {
- switch (type) {
- case gfx::SHARED_MEMORY_BUFFER:
- break;
- case gfx::OZONE_NATIVE_BUFFER:
- GpuMemoryBufferImplOzoneNativeBuffer::DeletedByChildProcess(
- id, child_client_id, sync_point);
- break;
- default:
- NOTREACHED();
- break;
- }
-}
-
-// static
-scoped_ptr<GpuMemoryBufferImpl> GpuMemoryBufferImpl::CreateFromHandle(
- const gfx::GpuMemoryBufferHandle& handle,
- const gfx::Size& size,
- Format format,
- const DestructionCallback& callback) {
- switch (handle.type) {
- case gfx::SHARED_MEMORY_BUFFER:
- return GpuMemoryBufferImplSharedMemory::CreateFromHandle(
- handle, size, format, callback);
- case gfx::OZONE_NATIVE_BUFFER:
- return GpuMemoryBufferImplOzoneNativeBuffer::CreateFromHandle(
- handle, size, format, callback);
- default:
- return scoped_ptr<GpuMemoryBufferImpl>();
- }
-}
-
-} // namespace content
diff --git a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_ozone_native_buffer.cc b/chromium/content/common/gpu/client/gpu_memory_buffer_impl_ozone_native_buffer.cc
index 2fd143894b2..8b3e34264bd 100644
--- a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_ozone_native_buffer.cc
+++ b/chromium/content/common/gpu/client/gpu_memory_buffer_impl_ozone_native_buffer.cc
@@ -4,48 +4,9 @@
#include "content/common/gpu/client/gpu_memory_buffer_impl_ozone_native_buffer.h"
-#include "base/bind.h"
-#include "content/common/gpu/client/gpu_memory_buffer_factory_host.h"
-#include "ui/gl/gl_bindings.h"
+#include "ui/ozone/public/surface_factory_ozone.h"
namespace content {
-namespace {
-
-void GpuMemoryBufferDeleted(gfx::GpuMemoryBufferId id,
- int client_id,
- uint32 sync_point) {
- GpuMemoryBufferFactoryHost::GetInstance()->DestroyGpuMemoryBuffer(
- gfx::OZONE_NATIVE_BUFFER, id, client_id, sync_point);
-}
-
-void GpuMemoryBufferCreated(
- const gfx::Size& size,
- gfx::GpuMemoryBuffer::Format format,
- int client_id,
- const GpuMemoryBufferImpl::CreationCallback& callback,
- const gfx::GpuMemoryBufferHandle& handle) {
- if (handle.is_null()) {
- callback.Run(scoped_ptr<GpuMemoryBufferImpl>());
- return;
- }
-
- DCHECK_EQ(gfx::OZONE_NATIVE_BUFFER, handle.type);
- callback.Run(GpuMemoryBufferImplOzoneNativeBuffer::CreateFromHandle(
- handle,
- size,
- format,
- base::Bind(&GpuMemoryBufferDeleted, handle.id, client_id)));
-}
-
-void GpuMemoryBufferCreatedForChildProcess(
- const GpuMemoryBufferImpl::AllocationCallback& callback,
- const gfx::GpuMemoryBufferHandle& handle) {
- DCHECK_IMPLIES(!handle.is_null(), gfx::OZONE_NATIVE_BUFFER == handle.type);
-
- callback.Run(handle);
-}
-
-} // namespace
GpuMemoryBufferImplOzoneNativeBuffer::GpuMemoryBufferImplOzoneNativeBuffer(
gfx::GpuMemoryBufferId id,
@@ -59,108 +20,28 @@ GpuMemoryBufferImplOzoneNativeBuffer::~GpuMemoryBufferImplOzoneNativeBuffer() {
}
// static
-void GpuMemoryBufferImplOzoneNativeBuffer::Create(
- gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- Format format,
- int client_id,
- const CreationCallback& callback) {
- GpuMemoryBufferFactoryHost::GetInstance()->CreateGpuMemoryBuffer(
- gfx::OZONE_NATIVE_BUFFER,
- id,
- size,
- format,
- SCANOUT,
- client_id,
- base::Bind(&GpuMemoryBufferCreated, size, format, client_id, callback));
-}
-
-// static
-void GpuMemoryBufferImplOzoneNativeBuffer::AllocateForChildProcess(
- gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- Format format,
- int child_client_id,
- const AllocationCallback& callback) {
- GpuMemoryBufferFactoryHost::GetInstance()->CreateGpuMemoryBuffer(
- gfx::OZONE_NATIVE_BUFFER,
- id,
- size,
- format,
- SCANOUT,
- child_client_id,
- base::Bind(&GpuMemoryBufferCreatedForChildProcess, callback));
-}
-
-// static
scoped_ptr<GpuMemoryBufferImpl>
GpuMemoryBufferImplOzoneNativeBuffer::CreateFromHandle(
const gfx::GpuMemoryBufferHandle& handle,
const gfx::Size& size,
Format format,
const DestructionCallback& callback) {
- DCHECK(IsFormatSupported(format));
-
return make_scoped_ptr<GpuMemoryBufferImpl>(
new GpuMemoryBufferImplOzoneNativeBuffer(
handle.id, size, format, callback));
}
-// static
-void GpuMemoryBufferImplOzoneNativeBuffer::DeletedByChildProcess(
- gfx::GpuMemoryBufferId id,
- int child_client_id,
- uint32_t sync_point) {
- GpuMemoryBufferFactoryHost::GetInstance()->DestroyGpuMemoryBuffer(
- gfx::OZONE_NATIVE_BUFFER, id, child_client_id, sync_point);
-}
-
-// static
-bool GpuMemoryBufferImplOzoneNativeBuffer::IsFormatSupported(Format format) {
- switch (format) {
- case RGBA_8888:
- case RGBX_8888:
- return true;
- case BGRA_8888:
- return false;
- }
-
+bool GpuMemoryBufferImplOzoneNativeBuffer::Map(void** data) {
NOTREACHED();
return false;
}
-// static
-bool GpuMemoryBufferImplOzoneNativeBuffer::IsUsageSupported(Usage usage) {
- switch (usage) {
- case MAP:
- return false;
- case SCANOUT:
- return true;
- }
-
- NOTREACHED();
- return false;
-}
-
-// static
-bool GpuMemoryBufferImplOzoneNativeBuffer::IsConfigurationSupported(
- Format format,
- Usage usage) {
- return IsFormatSupported(format) && IsUsageSupported(usage);
-}
-
-void* GpuMemoryBufferImplOzoneNativeBuffer::Map() {
- NOTREACHED();
- return NULL;
-}
-
void GpuMemoryBufferImplOzoneNativeBuffer::Unmap() {
NOTREACHED();
}
-uint32 GpuMemoryBufferImplOzoneNativeBuffer::GetStride() const {
+void GpuMemoryBufferImplOzoneNativeBuffer::GetStride(int* stride) const {
NOTREACHED();
- return 0;
}
gfx::GpuMemoryBufferHandle GpuMemoryBufferImplOzoneNativeBuffer::GetHandle()
diff --git a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_ozone_native_buffer.h b/chromium/content/common/gpu/client/gpu_memory_buffer_impl_ozone_native_buffer.h
index 2da30b4e3fc..040eab9738d 100644
--- a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_ozone_native_buffer.h
+++ b/chromium/content/common/gpu/client/gpu_memory_buffer_impl_ozone_native_buffer.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_COMMON_GPU_CLIENT_GPU_MEMORY_BUFFER_IMPL_OZONE_H_
-#define CONTENT_COMMON_GPU_CLIENT_GPU_MEMORY_BUFFER_IMPL_OZONE_H_
+#ifndef CONTENT_COMMON_GPU_CLIENT_GPU_MEMORY_BUFFER_IMPL_OZONE_NATIVE_BUFFER_H_
+#define CONTENT_COMMON_GPU_CLIENT_GPU_MEMORY_BUFFER_IMPL_OZONE_NATIVE_BUFFER_H_
#include "content/common/gpu/client/gpu_memory_buffer_impl.h"
@@ -12,36 +12,16 @@ namespace content {
// Implementation of GPU memory buffer based on Ozone native buffers.
class GpuMemoryBufferImplOzoneNativeBuffer : public GpuMemoryBufferImpl {
public:
- static void Create(gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- Format format,
- int client_id,
- const CreationCallback& callback);
-
- static void AllocateForChildProcess(gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- Format format,
- int child_client_id,
- const AllocationCallback& callback);
-
static scoped_ptr<GpuMemoryBufferImpl> CreateFromHandle(
const gfx::GpuMemoryBufferHandle& handle,
const gfx::Size& size,
Format format,
const DestructionCallback& callback);
- static void DeletedByChildProcess(gfx::GpuMemoryBufferId id,
- int child_client_id,
- uint32_t sync_point);
-
- static bool IsFormatSupported(Format format);
- static bool IsUsageSupported(Usage usage);
- static bool IsConfigurationSupported(Format format, Usage usage);
-
// Overridden from gfx::GpuMemoryBuffer:
- void* Map() override;
+ bool Map(void** data) override;
void Unmap() override;
- uint32 GetStride() const override;
+ void GetStride(int* stride) const override;
gfx::GpuMemoryBufferHandle GetHandle() const override;
private:
@@ -56,4 +36,4 @@ class GpuMemoryBufferImplOzoneNativeBuffer : public GpuMemoryBufferImpl {
} // namespace content
-#endif // CONTENT_COMMON_GPU_CLIENT_GPU_MEMORY_BUFFER_IMPL_OZONE_H_
+#endif // CONTENT_COMMON_GPU_CLIENT_GPU_MEMORY_BUFFER_IMPL_OZONE_NATIVE_BUFFER_H_
diff --git a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.cc b/chromium/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.cc
index 9a2ae220c3a..02a5048d27f 100644
--- a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.cc
+++ b/chromium/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.cc
@@ -24,48 +24,50 @@ GpuMemoryBufferImplSharedMemory::GpuMemoryBufferImplSharedMemory(
scoped_ptr<base::SharedMemory> shared_memory)
: GpuMemoryBufferImpl(id, size, format, callback),
shared_memory_(shared_memory.Pass()) {
+ DCHECK(IsFormatSupported(format));
+ DCHECK(IsSizeValidForFormat(size, format));
}
GpuMemoryBufferImplSharedMemory::~GpuMemoryBufferImplSharedMemory() {
}
// static
-void GpuMemoryBufferImplSharedMemory::Create(gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- Format format,
- const CreationCallback& callback) {
- DCHECK(IsLayoutSupported(size, format));
+scoped_ptr<GpuMemoryBufferImpl> GpuMemoryBufferImplSharedMemory::Create(
+ gfx::GpuMemoryBufferId id,
+ const gfx::Size& size,
+ Format format) {
+ size_t buffer_size = 0u;
+ if (!BufferSizeInBytes(size, format, &buffer_size))
+ return scoped_ptr<GpuMemoryBufferImpl>();
scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory());
- if (!shared_memory->CreateAnonymous(size.GetArea() * BytesPerPixel(format))) {
- callback.Run(scoped_ptr<GpuMemoryBufferImpl>());
- return;
- }
+ if (!shared_memory->CreateAndMapAnonymous(buffer_size))
+ return scoped_ptr<GpuMemoryBufferImpl>();
- callback.Run(
- make_scoped_ptr<GpuMemoryBufferImpl>(new GpuMemoryBufferImplSharedMemory(
- id, size, format, base::Bind(&Noop), shared_memory.Pass())));
+ return make_scoped_ptr(new GpuMemoryBufferImplSharedMemory(
+ id, size, format, base::Bind(&Noop), shared_memory.Pass()));
}
// static
-void GpuMemoryBufferImplSharedMemory::AllocateForChildProcess(
+gfx::GpuMemoryBufferHandle
+GpuMemoryBufferImplSharedMemory::AllocateForChildProcess(
gfx::GpuMemoryBufferId id,
const gfx::Size& size,
Format format,
- base::ProcessHandle child_process,
- const AllocationCallback& callback) {
- DCHECK(IsLayoutSupported(size, format));
+ base::ProcessHandle child_process) {
+ size_t buffer_size = 0u;
+ if (!BufferSizeInBytes(size, format, &buffer_size))
+ return gfx::GpuMemoryBufferHandle();
base::SharedMemory shared_memory;
- if (!shared_memory.CreateAnonymous(size.GetArea() * BytesPerPixel(format))) {
- callback.Run(gfx::GpuMemoryBufferHandle());
- return;
- }
+ if (!shared_memory.CreateAnonymous(buffer_size))
+ return gfx::GpuMemoryBufferHandle();
+
gfx::GpuMemoryBufferHandle handle;
handle.type = gfx::SHARED_MEMORY_BUFFER;
handle.id = id;
shared_memory.GiveToProcess(child_process, &handle.handle);
- callback.Run(handle);
+ return handle;
}
// static
@@ -75,25 +77,39 @@ GpuMemoryBufferImplSharedMemory::CreateFromHandle(
const gfx::Size& size,
Format format,
const DestructionCallback& callback) {
- DCHECK(IsLayoutSupported(size, format));
-
if (!base::SharedMemory::IsHandleValid(handle.handle))
return scoped_ptr<GpuMemoryBufferImpl>();
+ size_t buffer_size = 0u;
+ if (!BufferSizeInBytes(size, format, &buffer_size))
+ return scoped_ptr<GpuMemoryBufferImpl>();
+
+ scoped_ptr<base::SharedMemory> shared_memory(
+ new base::SharedMemory(handle.handle, false));
+ if (!shared_memory->Map(buffer_size))
+ return scoped_ptr<GpuMemoryBufferImpl>();
+
return make_scoped_ptr<GpuMemoryBufferImpl>(
new GpuMemoryBufferImplSharedMemory(
handle.id,
size,
format,
callback,
- make_scoped_ptr(new base::SharedMemory(handle.handle, false))));
+ shared_memory.Pass()));
}
// static
bool GpuMemoryBufferImplSharedMemory::IsFormatSupported(Format format) {
switch (format) {
+ case ATC:
+ case ATCIA:
+ case DXT1:
+ case DXT5:
+ case ETC1:
+ case R_8:
case RGBA_8888:
case BGRA_8888:
+ case YUV_420:
return true;
case RGBX_8888:
return false;
@@ -104,54 +120,69 @@ bool GpuMemoryBufferImplSharedMemory::IsFormatSupported(Format format) {
}
// static
-bool GpuMemoryBufferImplSharedMemory::IsUsageSupported(Usage usage) {
- switch (usage) {
- case MAP:
+bool GpuMemoryBufferImplSharedMemory::IsSizeValidForFormat(
+ const gfx::Size& size,
+ Format format) {
+ switch (format) {
+ case ATC:
+ case ATCIA:
+ case DXT1:
+ case DXT5:
+ case ETC1:
+ // Compressed images must have a width and height that's evenly divisible
+ // by the block size.
+ return size.width() % 4 == 0 && size.height() % 4 == 0;
+ case R_8:
+ case RGBA_8888:
+ case BGRA_8888:
+ case RGBX_8888:
return true;
- case SCANOUT:
- return false;
+ case YUV_420: {
+ size_t num_planes = NumberOfPlanesForGpuMemoryBufferFormat(format);
+ for (size_t i = 0; i < num_planes; ++i) {
+ size_t factor = SubsamplingFactor(format, i);
+ if (size.width() % factor || size.height() % factor)
+ return false;
+ }
+ return true;
+ }
}
NOTREACHED();
return false;
}
-// static
-bool GpuMemoryBufferImplSharedMemory::IsLayoutSupported(const gfx::Size& size,
- Format format) {
- if (!IsFormatSupported(format))
- return false;
-
- base::CheckedNumeric<int> buffer_size = size.width();
- buffer_size *= size.height();
- buffer_size *= BytesPerPixel(format);
- return buffer_size.IsValid();
-}
-
-// static
-bool GpuMemoryBufferImplSharedMemory::IsConfigurationSupported(
- const gfx::Size& size,
- Format format,
- Usage usage) {
- return IsLayoutSupported(size, format) && IsUsageSupported(usage);
-}
-
-void* GpuMemoryBufferImplSharedMemory::Map() {
+bool GpuMemoryBufferImplSharedMemory::Map(void** data) {
DCHECK(!mapped_);
- if (!shared_memory_->Map(size_.GetArea() * BytesPerPixel(format_)))
- return NULL;
+ size_t offset = 0;
+ size_t num_planes = NumberOfPlanesForGpuMemoryBufferFormat(format_);
+ for (size_t i = 0; i < num_planes; ++i) {
+ data[i] = reinterpret_cast<uint8*>(shared_memory_->memory()) + offset;
+ size_t row_size_in_bytes = 0;
+ bool valid_row_size =
+ RowSizeInBytes(size_.width(), format_, i, &row_size_in_bytes);
+ DCHECK(valid_row_size);
+ offset +=
+ row_size_in_bytes * (size_.height() / SubsamplingFactor(format_, i));
+ }
mapped_ = true;
- return shared_memory_->memory();
+ return true;
}
void GpuMemoryBufferImplSharedMemory::Unmap() {
DCHECK(mapped_);
- shared_memory_->Unmap();
mapped_ = false;
}
-uint32 GpuMemoryBufferImplSharedMemory::GetStride() const {
- return size_.width() * BytesPerPixel(format_);
+void GpuMemoryBufferImplSharedMemory::GetStride(int* stride) const {
+ size_t num_planes = NumberOfPlanesForGpuMemoryBufferFormat(format_);
+ for (size_t i = 0; i < num_planes; ++i) {
+ size_t row_size_in_bytes = 0;
+ bool valid_row_size =
+ RowSizeInBytes(size_.width(), format_, i, &row_size_in_bytes);
+ DCHECK(valid_row_size);
+ stride[i] = row_size_in_bytes;
+ }
}
gfx::GpuMemoryBufferHandle GpuMemoryBufferImplSharedMemory::GetHandle() const {
diff --git a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h b/chromium/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h
index d84d031b871..ce526a6be23 100644
--- a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h
+++ b/chromium/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h
@@ -12,16 +12,17 @@ namespace content {
// Implementation of GPU memory buffer based on shared memory.
class GpuMemoryBufferImplSharedMemory : public GpuMemoryBufferImpl {
public:
- static void Create(gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- Format format,
- const CreationCallback& callback);
+ ~GpuMemoryBufferImplSharedMemory() override;
- static void AllocateForChildProcess(gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- Format format,
- base::ProcessHandle child_process,
- const AllocationCallback& callback);
+ static scoped_ptr<GpuMemoryBufferImpl> Create(gfx::GpuMemoryBufferId id,
+ const gfx::Size& size,
+ Format format);
+
+ static gfx::GpuMemoryBufferHandle AllocateForChildProcess(
+ gfx::GpuMemoryBufferId id,
+ const gfx::Size& size,
+ Format format,
+ base::ProcessHandle child_process);
static scoped_ptr<GpuMemoryBufferImpl> CreateFromHandle(
const gfx::GpuMemoryBufferHandle& handle,
@@ -30,16 +31,12 @@ class GpuMemoryBufferImplSharedMemory : public GpuMemoryBufferImpl {
const DestructionCallback& callback);
static bool IsFormatSupported(Format format);
- static bool IsUsageSupported(Usage usage);
- static bool IsLayoutSupported(const gfx::Size& size, Format format);
- static bool IsConfigurationSupported(const gfx::Size& size,
- Format format,
- Usage usage);
+ static bool IsSizeValidForFormat(const gfx::Size& size, Format format);
// Overridden from gfx::GpuMemoryBuffer:
- void* Map() override;
+ bool Map(void** data) override;
void Unmap() override;
- uint32 GetStride() const override;
+ void GetStride(int* stride) const override;
gfx::GpuMemoryBufferHandle GetHandle() const override;
private:
@@ -48,7 +45,6 @@ class GpuMemoryBufferImplSharedMemory : public GpuMemoryBufferImpl {
Format format,
const DestructionCallback& callback,
scoped_ptr<base::SharedMemory> shared_memory);
- ~GpuMemoryBufferImplSharedMemory() override;
scoped_ptr<base::SharedMemory> shared_memory_;
diff --git a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_surface_texture.cc b/chromium/content/common/gpu/client/gpu_memory_buffer_impl_surface_texture.cc
index 28282729215..b1611b38e2a 100644
--- a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_surface_texture.cc
+++ b/chromium/content/common/gpu/client/gpu_memory_buffer_impl_surface_texture.cc
@@ -4,48 +4,33 @@
#include "content/common/gpu/client/gpu_memory_buffer_impl_surface_texture.h"
-#include "base/bind.h"
-#include "base/debug/trace_event.h"
#include "base/logging.h"
+#include "base/trace_event/trace_event.h"
#include "content/common/android/surface_texture_manager.h"
-#include "content/common/gpu/client/gpu_memory_buffer_factory_host.h"
#include "ui/gl/gl_bindings.h"
namespace content {
namespace {
-void GpuMemoryBufferDeleted(gfx::GpuMemoryBufferId id,
- int client_id,
- uint32 sync_point) {
- GpuMemoryBufferFactoryHost::GetInstance()->DestroyGpuMemoryBuffer(
- gfx::SURFACE_TEXTURE_BUFFER, id, client_id, sync_point);
-}
-
-void GpuMemoryBufferCreated(
- const gfx::Size& size,
- gfx::GpuMemoryBuffer::Format format,
- int client_id,
- const GpuMemoryBufferImpl::CreationCallback& callback,
- const gfx::GpuMemoryBufferHandle& handle) {
- if (handle.is_null()) {
- callback.Run(scoped_ptr<GpuMemoryBufferImpl>());
- return;
+int WindowFormat(gfx::GpuMemoryBuffer::Format format) {
+ switch (format) {
+ case gfx::GpuMemoryBuffer::RGBA_8888:
+ return WINDOW_FORMAT_RGBA_8888;
+ case gfx::GpuMemoryBuffer::ATC:
+ case gfx::GpuMemoryBuffer::ATCIA:
+ case gfx::GpuMemoryBuffer::DXT1:
+ case gfx::GpuMemoryBuffer::DXT5:
+ case gfx::GpuMemoryBuffer::ETC1:
+ case gfx::GpuMemoryBuffer::R_8:
+ case gfx::GpuMemoryBuffer::RGBX_8888:
+ case gfx::GpuMemoryBuffer::BGRA_8888:
+ case gfx::GpuMemoryBuffer::YUV_420:
+ NOTREACHED();
+ return 0;
}
- DCHECK_EQ(gfx::SURFACE_TEXTURE_BUFFER, handle.type);
- callback.Run(GpuMemoryBufferImplSurfaceTexture::CreateFromHandle(
- handle,
- size,
- format,
- base::Bind(&GpuMemoryBufferDeleted, handle.id, client_id)));
-}
-
-void GpuMemoryBufferCreatedForChildProcess(
- const GpuMemoryBufferImpl::AllocationCallback& callback,
- const gfx::GpuMemoryBufferHandle& handle) {
- DCHECK_IMPLIES(!handle.is_null(), gfx::SURFACE_TEXTURE_BUFFER == handle.type);
-
- callback.Run(handle);
+ NOTREACHED();
+ return 0;
}
} // namespace
@@ -66,48 +51,12 @@ GpuMemoryBufferImplSurfaceTexture::~GpuMemoryBufferImplSurfaceTexture() {
}
// static
-void GpuMemoryBufferImplSurfaceTexture::Create(
- gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- Format format,
- int client_id,
- const CreationCallback& callback) {
- GpuMemoryBufferFactoryHost::GetInstance()->CreateGpuMemoryBuffer(
- gfx::SURFACE_TEXTURE_BUFFER,
- id,
- size,
- format,
- MAP,
- client_id,
- base::Bind(&GpuMemoryBufferCreated, size, format, client_id, callback));
-}
-
-// static
-void GpuMemoryBufferImplSurfaceTexture::AllocateForChildProcess(
- gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- Format format,
- int child_client_id,
- const AllocationCallback& callback) {
- GpuMemoryBufferFactoryHost::GetInstance()->CreateGpuMemoryBuffer(
- gfx::SURFACE_TEXTURE_BUFFER,
- id,
- size,
- format,
- MAP,
- child_client_id,
- base::Bind(&GpuMemoryBufferCreatedForChildProcess, callback));
-}
-
-// static
scoped_ptr<GpuMemoryBufferImpl>
GpuMemoryBufferImplSurfaceTexture::CreateFromHandle(
const gfx::GpuMemoryBufferHandle& handle,
const gfx::Size& size,
Format format,
const DestructionCallback& callback) {
- DCHECK(IsFormatSupported(format));
-
ANativeWindow* native_window = SurfaceTextureManager::GetInstance()->
AcquireNativeWidgetForSurfaceTexture(handle.id);
if (!native_window)
@@ -121,64 +70,7 @@ GpuMemoryBufferImplSurfaceTexture::CreateFromHandle(
handle.id, size, format, callback, native_window));
}
-// static
-void GpuMemoryBufferImplSurfaceTexture::DeletedByChildProcess(
- gfx::GpuMemoryBufferId id,
- int child_client_id,
- uint32_t sync_point) {
- GpuMemoryBufferFactoryHost::GetInstance()->DestroyGpuMemoryBuffer(
- gfx::SURFACE_TEXTURE_BUFFER, id, child_client_id, sync_point);
-}
-
-// static
-bool GpuMemoryBufferImplSurfaceTexture::IsFormatSupported(Format format) {
- switch (format) {
- case RGBA_8888:
- return true;
- case RGBX_8888:
- case BGRA_8888:
- return false;
- }
-
- NOTREACHED();
- return false;
-}
-
-// static
-bool GpuMemoryBufferImplSurfaceTexture::IsUsageSupported(Usage usage) {
- switch (usage) {
- case MAP:
- return true;
- case SCANOUT:
- return false;
- }
-
- NOTREACHED();
- return false;
-}
-
-// static
-bool GpuMemoryBufferImplSurfaceTexture::IsConfigurationSupported(Format format,
- Usage usage) {
- return IsFormatSupported(format) && IsUsageSupported(usage);
-}
-
-// static
-int GpuMemoryBufferImplSurfaceTexture::WindowFormat(Format format) {
- switch (format) {
- case RGBA_8888:
- return WINDOW_FORMAT_RGBA_8888;
- case RGBX_8888:
- case BGRA_8888:
- NOTREACHED();
- return 0;
- }
-
- NOTREACHED();
- return 0;
-}
-
-void* GpuMemoryBufferImplSurfaceTexture::Map() {
+bool GpuMemoryBufferImplSurfaceTexture::Map(void** data) {
TRACE_EVENT0("gpu", "GpuMemoryBufferImplSurfaceTexture::Map");
DCHECK(!mapped_);
@@ -187,13 +79,19 @@ void* GpuMemoryBufferImplSurfaceTexture::Map() {
int status = ANativeWindow_lock(native_window_, &buffer, NULL);
if (status) {
VLOG(1) << "ANativeWindow_lock failed with error code: " << status;
- return NULL;
+ return false;
}
DCHECK_LE(size_.width(), buffer.stride);
- stride_ = buffer.stride * BytesPerPixel(format_);
+ size_t row_size_in_bytes = 0;
+ bool valid_row_size =
+ RowSizeInBytes(buffer.stride, format_, 0, &row_size_in_bytes);
+ DCHECK(valid_row_size);
+
+ stride_ = row_size_in_bytes;
mapped_ = true;
- return buffer.bits;
+ *data = buffer.bits;
+ return true;
}
void GpuMemoryBufferImplSurfaceTexture::Unmap() {
@@ -204,8 +102,8 @@ void GpuMemoryBufferImplSurfaceTexture::Unmap() {
mapped_ = false;
}
-uint32 GpuMemoryBufferImplSurfaceTexture::GetStride() const {
- return stride_;
+void GpuMemoryBufferImplSurfaceTexture::GetStride(int* stride) const {
+ *stride = stride_;
}
gfx::GpuMemoryBufferHandle GpuMemoryBufferImplSurfaceTexture::GetHandle()
diff --git a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_surface_texture.h b/chromium/content/common/gpu/client/gpu_memory_buffer_impl_surface_texture.h
index 57256347ca8..af96c33d24a 100644
--- a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_surface_texture.h
+++ b/chromium/content/common/gpu/client/gpu_memory_buffer_impl_surface_texture.h
@@ -14,38 +14,17 @@ namespace content {
// Implementation of GPU memory buffer based on SurfaceTextures.
class GpuMemoryBufferImplSurfaceTexture : public GpuMemoryBufferImpl {
public:
- static void Create(gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- Format format,
- int client_id,
- const CreationCallback& callback);
-
- static void AllocateForChildProcess(gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- Format format,
- int child_client_id,
- const AllocationCallback& callback);
-
static scoped_ptr<GpuMemoryBufferImpl> CreateFromHandle(
const gfx::GpuMemoryBufferHandle& handle,
const gfx::Size& size,
Format format,
const DestructionCallback& callback);
- static void DeletedByChildProcess(gfx::GpuMemoryBufferId id,
- int child_client_id,
- uint32_t sync_point);
-
- static bool IsFormatSupported(Format format);
- static bool IsUsageSupported(Usage usage);
- static bool IsConfigurationSupported(Format format, Usage usage);
- static int WindowFormat(Format format);
-
// Overridden from gfx::GpuMemoryBuffer:
- virtual void* Map() override;
- virtual void Unmap() override;
- virtual gfx::GpuMemoryBufferHandle GetHandle() const override;
- virtual uint32 GetStride() const override;
+ bool Map(void** data) override;
+ void Unmap() override;
+ gfx::GpuMemoryBufferHandle GetHandle() const override;
+ void GetStride(int* stride) const override;
private:
GpuMemoryBufferImplSurfaceTexture(gfx::GpuMemoryBufferId id,
@@ -53,7 +32,7 @@ class GpuMemoryBufferImplSurfaceTexture : public GpuMemoryBufferImpl {
Format format,
const DestructionCallback& callback,
ANativeWindow* native_window);
- virtual ~GpuMemoryBufferImplSurfaceTexture();
+ ~GpuMemoryBufferImplSurfaceTexture() override;
ANativeWindow* native_window_;
size_t stride_;
diff --git a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_unittest.cc b/chromium/content/common/gpu/client/gpu_memory_buffer_impl_unittest.cc
new file mode 100644
index 00000000000..94046f1cf15
--- /dev/null
+++ b/chromium/content/common/gpu/client/gpu_memory_buffer_impl_unittest.cc
@@ -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.
+
+#include "content/common/gpu/client/gpu_memory_buffer_impl.h"
+
+#include "base/bind.h"
+#include "content/common/gpu/gpu_memory_buffer_factory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+namespace {
+
+const int kClientId = 1;
+
+class GpuMemoryBufferImplTest
+ : public testing::TestWithParam<gfx::GpuMemoryBufferType> {
+ public:
+ GpuMemoryBufferImplTest() : buffer_count_(0), factory_(nullptr) {}
+
+ // Overridden from testing::Test:
+ void SetUp() override {
+ factory_ = GpuMemoryBufferFactory::Create(GetParam());
+ factory_->GetSupportedGpuMemoryBufferConfigurations(
+ &supported_configurations_);
+ }
+ void TearDown() override { factory_.reset(); }
+
+ gfx::GpuMemoryBufferHandle CreateGpuMemoryBuffer(
+ gfx::GpuMemoryBufferId id,
+ const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
+ gfx::GpuMemoryBuffer::Usage usage) {
+ ++buffer_count_;
+ return factory_->CreateGpuMemoryBuffer(id, size, format, usage, kClientId,
+ gfx::kNullPluginWindow);
+ }
+
+ void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id, uint32 sync_point) {
+ factory_->DestroyGpuMemoryBuffer(id, kClientId);
+ DCHECK_GT(buffer_count_, 0);
+ --buffer_count_;
+ }
+
+ std::vector<GpuMemoryBufferFactory::Configuration> supported_configurations_;
+ int buffer_count_;
+
+ private:
+ scoped_ptr<GpuMemoryBufferFactory> factory_;
+};
+
+TEST_P(GpuMemoryBufferImplTest, CreateFromHandle) {
+ const int kBufferId = 1;
+
+ gfx::Size buffer_size(8, 8);
+
+ for (auto configuration : supported_configurations_) {
+ scoped_ptr<GpuMemoryBufferImpl> buffer(
+ GpuMemoryBufferImpl::CreateFromHandle(
+ CreateGpuMemoryBuffer(kBufferId,
+ buffer_size,
+ configuration.format,
+ configuration.usage),
+ buffer_size,
+ configuration.format,
+ base::Bind(&GpuMemoryBufferImplTest::DestroyGpuMemoryBuffer,
+ base::Unretained(this),
+ kBufferId)));
+ EXPECT_EQ(1, buffer_count_);
+ ASSERT_TRUE(buffer);
+ EXPECT_EQ(buffer->GetFormat(), configuration.format);
+
+ // Check if destruction callback is executed when deleting the buffer.
+ buffer.reset();
+ EXPECT_EQ(0, buffer_count_);
+ }
+}
+
+TEST_P(GpuMemoryBufferImplTest, Map) {
+ const int kBufferId = 1;
+
+ gfx::Size buffer_size(2, 2);
+
+ for (auto configuration : supported_configurations_) {
+ if (configuration.usage != gfx::GpuMemoryBuffer::MAP)
+ continue;
+
+ scoped_ptr<GpuMemoryBufferImpl> buffer(
+ GpuMemoryBufferImpl::CreateFromHandle(
+ CreateGpuMemoryBuffer(kBufferId, buffer_size, configuration.format,
+ configuration.usage),
+ buffer_size, configuration.format,
+ base::Bind(&GpuMemoryBufferImplTest::DestroyGpuMemoryBuffer,
+ base::Unretained(this), kBufferId)));
+ ASSERT_TRUE(buffer);
+ EXPECT_FALSE(buffer->IsMapped());
+
+ size_t num_planes =
+ GpuMemoryBufferImpl::NumberOfPlanesForGpuMemoryBufferFormat(
+ configuration.format);
+
+ // Map buffer into user space.
+ scoped_ptr<void*[]> mapped_buffers(new void*[num_planes]);
+ bool rv = buffer->Map(mapped_buffers.get());
+ ASSERT_TRUE(rv);
+ EXPECT_TRUE(buffer->IsMapped());
+
+ // Get strides.
+ scoped_ptr<int[]> strides(new int[num_planes]);
+ buffer->GetStride(strides.get());
+
+ // Copy and compare mapped buffers.
+ for (size_t plane = 0; plane < num_planes; ++plane) {
+ size_t row_size_in_bytes = 0;
+ EXPECT_TRUE(GpuMemoryBufferImpl::RowSizeInBytes(
+ buffer_size.width(), configuration.format, plane,
+ &row_size_in_bytes));
+ EXPECT_GT(row_size_in_bytes, 0u);
+
+ scoped_ptr<char[]> data(new char[row_size_in_bytes]);
+ memset(data.get(), 0x2a + plane, row_size_in_bytes);
+
+ size_t height =
+ buffer_size.height() /
+ GpuMemoryBufferImpl::SubsamplingFactor(configuration.format, plane);
+ for (size_t y = 0; y < height; ++y) {
+ memcpy(static_cast<char*>(mapped_buffers[plane]) + y * strides[plane],
+ data.get(), row_size_in_bytes);
+ EXPECT_EQ(memcmp(static_cast<char*>(mapped_buffers[plane]) +
+ y * strides[plane],
+ data.get(), row_size_in_bytes),
+ 0);
+ }
+ }
+
+ buffer->Unmap();
+ EXPECT_FALSE(buffer->IsMapped());
+ }
+}
+
+std::vector<gfx::GpuMemoryBufferType> GetSupportedGpuMemoryBufferTypes() {
+ std::vector<gfx::GpuMemoryBufferType> supported_types;
+ GpuMemoryBufferFactory::GetSupportedTypes(&supported_types);
+ return supported_types;
+}
+
+INSTANTIATE_TEST_CASE_P(
+ GpuMemoryBufferImplTests,
+ GpuMemoryBufferImplTest,
+ ::testing::ValuesIn(GetSupportedGpuMemoryBufferTypes()));
+
+} // namespace
+} // namespace content
diff --git a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_win.cc b/chromium/content/common/gpu/client/gpu_memory_buffer_impl_win.cc
deleted file mode 100644
index 3c144f37ccf..00000000000
--- a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_win.cc
+++ /dev/null
@@ -1,70 +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/common/gpu/client/gpu_memory_buffer_impl.h"
-
-#include "content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h"
-
-namespace content {
-
-// static
-void GpuMemoryBufferImpl::Create(gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- Format format,
- Usage usage,
- int client_id,
- const CreationCallback& callback) {
- if (GpuMemoryBufferImplSharedMemory::IsConfigurationSupported(
- size, format, usage)) {
- GpuMemoryBufferImplSharedMemory::Create(id, size, format, callback);
- return;
- }
-
- callback.Run(scoped_ptr<GpuMemoryBufferImpl>());
-}
-
-// static
-void GpuMemoryBufferImpl::AllocateForChildProcess(
- gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- Format format,
- Usage usage,
- base::ProcessHandle child_process,
- int child_client_id,
- const AllocationCallback& callback) {
- if (GpuMemoryBufferImplSharedMemory::IsConfigurationSupported(
- size, format, usage)) {
- GpuMemoryBufferImplSharedMemory::AllocateForChildProcess(
- id, size, format, child_process, callback);
- return;
- }
-
- callback.Run(gfx::GpuMemoryBufferHandle());
-}
-
-// static
-void GpuMemoryBufferImpl::DeletedByChildProcess(
- gfx::GpuMemoryBufferType type,
- gfx::GpuMemoryBufferId id,
- base::ProcessHandle child_process,
- int child_client_id,
- uint32 sync_point) {
-}
-
-// static
-scoped_ptr<GpuMemoryBufferImpl> GpuMemoryBufferImpl::CreateFromHandle(
- const gfx::GpuMemoryBufferHandle& handle,
- const gfx::Size& size,
- Format format,
- const DestructionCallback& callback) {
- switch (handle.type) {
- case gfx::SHARED_MEMORY_BUFFER:
- return GpuMemoryBufferImplSharedMemory::CreateFromHandle(
- handle, size, format, callback);
- default:
- return scoped_ptr<GpuMemoryBufferImpl>();
- }
-}
-
-} // namespace content
diff --git a/chromium/content/common/gpu/client/gpu_video_decode_accelerator_host.cc b/chromium/content/common/gpu/client/gpu_video_decode_accelerator_host.cc
index a7844678001..86894bcde06 100644
--- a/chromium/content/common/gpu/client/gpu_video_decode_accelerator_host.cc
+++ b/chromium/content/common/gpu/client/gpu_video_decode_accelerator_host.cc
@@ -188,11 +188,9 @@ void GpuVideoDecodeAcceleratorHost::OnWillDeleteImpl() {
void GpuVideoDecodeAcceleratorHost::PostNotifyError(Error error) {
DCHECK(CalledOnValidThread());
DVLOG(2) << "PostNotifyError(): error=" << error;
- base::MessageLoopProxy::current()->PostTask(
- FROM_HERE,
- base::Bind(&GpuVideoDecodeAcceleratorHost::OnNotifyError,
- weak_this_factory_.GetWeakPtr(),
- error));
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&GpuVideoDecodeAcceleratorHost::OnNotifyError,
+ weak_this_factory_.GetWeakPtr(), error));
}
void GpuVideoDecodeAcceleratorHost::Send(IPC::Message* message) {
@@ -233,11 +231,13 @@ void GpuVideoDecodeAcceleratorHost::OnDismissPictureBuffer(
void GpuVideoDecodeAcceleratorHost::OnPictureReady(
int32 picture_buffer_id,
int32 bitstream_buffer_id,
- const gfx::Rect& visible_rect) {
+ const gfx::Rect& visible_rect,
+ bool allow_overlay) {
DCHECK(CalledOnValidThread());
if (!client_)
return;
- media::Picture picture(picture_buffer_id, bitstream_buffer_id, visible_rect);
+ media::Picture picture(picture_buffer_id, bitstream_buffer_id, visible_rect,
+ allow_overlay);
client_->PictureReady(picture);
}
diff --git a/chromium/content/common/gpu/client/gpu_video_decode_accelerator_host.h b/chromium/content/common/gpu/client/gpu_video_decode_accelerator_host.h
index 4cbeeb1272d..d82da0725e3 100644
--- a/chromium/content/common/gpu/client/gpu_video_decode_accelerator_host.h
+++ b/chromium/content/common/gpu/client/gpu_video_decode_accelerator_host.h
@@ -12,7 +12,7 @@
#include "content/common/gpu/client/command_buffer_proxy_impl.h"
#include "ipc/ipc_listener.h"
#include "media/video/video_decode_accelerator.h"
-#include "ui/gfx/size.h"
+#include "ui/gfx/geometry/size.h"
namespace content {
class GpuChannelHost;
@@ -65,7 +65,8 @@ class GpuVideoDecodeAcceleratorHost
void OnDismissPictureBuffer(int32 picture_buffer_id);
void OnPictureReady(int32 picture_buffer_id,
int32 bitstream_buffer_id,
- const gfx::Rect& visible_rect);
+ const gfx::Rect& visible_rect,
+ bool allow_overlay);
void OnFlushDone();
void OnResetDone();
void OnNotifyError(uint32 error);
diff --git a/chromium/content/common/gpu/client/gpu_video_encode_accelerator_host.cc b/chromium/content/common/gpu/client/gpu_video_encode_accelerator_host.cc
index 026040f455e..1cbfeaa025a 100644
--- a/chromium/content/common/gpu/client/gpu_video_encode_accelerator_host.cc
+++ b/chromium/content/common/gpu/client/gpu_video_encode_accelerator_host.cc
@@ -5,10 +5,9 @@
#include "content/common/gpu/client/gpu_video_encode_accelerator_host.h"
#include "base/logging.h"
-#include "base/message_loop/message_loop_proxy.h"
#include "content/common/gpu/client/gpu_channel_host.h"
#include "content/common/gpu/gpu_messages.h"
-#include "content/common/gpu/media/gpu_video_encode_accelerator.h"
+#include "content/common/gpu/media/gpu_video_accelerator_util.h"
#include "media/base/video_frame.h"
namespace content {
@@ -69,56 +68,15 @@ void GpuVideoEncodeAcceleratorHost::OnChannelError() {
NOTIFY_ERROR(kPlatformFailureError) << "OnChannelError()";
}
-std::vector<media::VideoEncodeAccelerator::SupportedProfile>
+media::VideoEncodeAccelerator::SupportedProfiles
GpuVideoEncodeAcceleratorHost::GetSupportedProfiles() {
DCHECK(CalledOnValidThread());
if (!channel_)
- return std::vector<media::VideoEncodeAccelerator::SupportedProfile>();
- return ConvertGpuToMediaProfiles(
+ return media::VideoEncodeAccelerator::SupportedProfiles();
+ return GpuVideoAcceleratorUtil::ConvertGpuToMediaEncodeProfiles(
channel_->gpu_info().video_encode_accelerator_supported_profiles);
}
-// Make sure the enum values of media::VideoCodecProfile and
-// gpu::VideoCodecProfile match.
-#define STATIC_ASSERT_ENUM_MATCH(name) \
- static_assert( \
- media::name == static_cast<media::VideoCodecProfile>(gpu::name), \
- #name " value must match in media and gpu.")
-
-STATIC_ASSERT_ENUM_MATCH(VIDEO_CODEC_PROFILE_UNKNOWN);
-STATIC_ASSERT_ENUM_MATCH(VIDEO_CODEC_PROFILE_MIN);
-STATIC_ASSERT_ENUM_MATCH(H264PROFILE_BASELINE);
-STATIC_ASSERT_ENUM_MATCH(H264PROFILE_MAIN);
-STATIC_ASSERT_ENUM_MATCH(H264PROFILE_EXTENDED);
-STATIC_ASSERT_ENUM_MATCH(H264PROFILE_HIGH);
-STATIC_ASSERT_ENUM_MATCH(H264PROFILE_HIGH10PROFILE);
-STATIC_ASSERT_ENUM_MATCH(H264PROFILE_HIGH422PROFILE);
-STATIC_ASSERT_ENUM_MATCH(H264PROFILE_HIGH444PREDICTIVEPROFILE);
-STATIC_ASSERT_ENUM_MATCH(H264PROFILE_SCALABLEBASELINE);
-STATIC_ASSERT_ENUM_MATCH(H264PROFILE_SCALABLEHIGH);
-STATIC_ASSERT_ENUM_MATCH(H264PROFILE_STEREOHIGH);
-STATIC_ASSERT_ENUM_MATCH(H264PROFILE_MULTIVIEWHIGH);
-STATIC_ASSERT_ENUM_MATCH(VP8PROFILE_ANY);
-STATIC_ASSERT_ENUM_MATCH(VP9PROFILE_ANY);
-STATIC_ASSERT_ENUM_MATCH(VIDEO_CODEC_PROFILE_MAX);
-
-std::vector<media::VideoEncodeAccelerator::SupportedProfile>
-GpuVideoEncodeAcceleratorHost::ConvertGpuToMediaProfiles(const std::vector<
- gpu::VideoEncodeAcceleratorSupportedProfile>& gpu_profiles) {
- std::vector<media::VideoEncodeAccelerator::SupportedProfile> profiles;
- for (size_t i = 0; i < gpu_profiles.size(); i++) {
- media::VideoEncodeAccelerator::SupportedProfile profile;
- profile.profile =
- static_cast<media::VideoCodecProfile>(gpu_profiles[i].profile);
- profile.max_resolution = gpu_profiles[i].max_resolution;
- profile.max_framerate_numerator = gpu_profiles[i].max_framerate_numerator;
- profile.max_framerate_denominator =
- gpu_profiles[i].max_framerate_denominator;
- profiles.push_back(profile);
- }
- return profiles;
-}
-
bool GpuVideoEncodeAcceleratorHost::Initialize(
media::VideoFrame::Format input_format,
const gfx::Size& input_visible_size,
@@ -184,7 +142,8 @@ void GpuVideoEncodeAcceleratorHost::Encode(
}
Send(new AcceleratedVideoEncoderMsg_Encode(
- encoder_route_id_, next_frame_id_, handle, frame_size, force_keyframe));
+ encoder_route_id_, next_frame_id_, handle, frame->shared_memory_offset(),
+ frame_size, force_keyframe));
frame_map_[next_frame_id_] = frame;
// Mask against 30 bits, to avoid (undefined) wraparound on signed integer.
@@ -240,11 +199,9 @@ void GpuVideoEncodeAcceleratorHost::PostNotifyError(Error error) {
DCHECK(CalledOnValidThread());
DVLOG(2) << "PostNotifyError(): error=" << error;
// Post the error notification back to this thread, to avoid re-entrancy.
- base::MessageLoopProxy::current()->PostTask(
- FROM_HERE,
- base::Bind(&GpuVideoEncodeAcceleratorHost::OnNotifyError,
- weak_this_factory_.GetWeakPtr(),
- error));
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&GpuVideoEncodeAcceleratorHost::OnNotifyError,
+ weak_this_factory_.GetWeakPtr(), error));
}
void GpuVideoEncodeAcceleratorHost::Send(IPC::Message* message) {
diff --git a/chromium/content/common/gpu/client/gpu_video_encode_accelerator_host.h b/chromium/content/common/gpu/client/gpu_video_encode_accelerator_host.h
index 021eff46ec1..4d1e79f1e44 100644
--- a/chromium/content/common/gpu/client/gpu_video_encode_accelerator_host.h
+++ b/chromium/content/common/gpu/client/gpu_video_encode_accelerator_host.h
@@ -45,16 +45,12 @@ class GpuVideoEncodeAcceleratorHost
GpuVideoEncodeAcceleratorHost(GpuChannelHost* channel,
CommandBufferProxyImpl* impl);
- static std::vector<media::VideoEncodeAccelerator::SupportedProfile>
- ConvertGpuToMediaProfiles(const std::vector<
- gpu::VideoEncodeAcceleratorSupportedProfile>& gpu_profiles);
-
// IPC::Listener implementation.
bool OnMessageReceived(const IPC::Message& message) override;
void OnChannelError() override;
// media::VideoEncodeAccelerator implementation.
- std::vector<SupportedProfile> GetSupportedProfiles() override;
+ SupportedProfiles GetSupportedProfiles() override;
bool Initialize(media::VideoFrame::Format input_format,
const gfx::Size& input_visible_size,
media::VideoCodecProfile output_profile,
diff --git a/chromium/content/common/gpu/client/grcontext_for_webgraphicscontext3d.cc b/chromium/content/common/gpu/client/grcontext_for_webgraphicscontext3d.cc
new file mode 100644
index 00000000000..970ec386067
--- /dev/null
+++ b/chromium/content/common/gpu/client/grcontext_for_webgraphicscontext3d.cc
@@ -0,0 +1,90 @@
+// 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/common/gpu/client/grcontext_for_webgraphicscontext3d.h"
+
+#include "base/lazy_instance.h"
+#include "base/trace_event/trace_event.h"
+#include "gpu/blink/webgraphicscontext3d_impl.h"
+#include "gpu/command_buffer/client/gles2_lib.h"
+#include "third_party/skia/include/gpu/GrContext.h"
+#include "third_party/skia/include/gpu/gl/GrGLInterface.h"
+
+using gpu_blink::WebGraphicsContext3DImpl;
+
+namespace content {
+
+namespace {
+
+// Singleton used to initialize and terminate the gles2 library.
+class GLES2Initializer {
+ public:
+ GLES2Initializer() { gles2::Initialize(); }
+
+ ~GLES2Initializer() { gles2::Terminate(); }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GLES2Initializer);
+};
+
+base::LazyInstance<GLES2Initializer> g_gles2_initializer =
+ LAZY_INSTANCE_INITIALIZER;
+
+void BindWebGraphicsContext3DGLContextCallback(const GrGLInterface* interface) {
+ gles2::SetGLContext(reinterpret_cast<WebGraphicsContext3DImpl*>(
+ interface->fCallbackData)->GetGLInterface());
+}
+
+} // namespace anonymous
+
+GrContextForWebGraphicsContext3D::GrContextForWebGraphicsContext3D(
+ WebGraphicsContext3DImpl* context3d) {
+ if (!context3d)
+ return;
+
+ // Ensure the gles2 library is initialized first in a thread safe way.
+ g_gles2_initializer.Get();
+ gles2::SetGLContext(context3d->GetGLInterface());
+ skia::RefPtr<GrGLInterface> interface = skia::AdoptRef(
+ context3d->createGrGLInterface());
+ if (!interface)
+ return;
+
+ interface->fCallback = BindWebGraphicsContext3DGLContextCallback;
+ interface->fCallbackData =
+ reinterpret_cast<GrGLInterfaceCallbackData>(context3d);
+
+ gr_context_ = skia::AdoptRef(GrContext::Create(
+ kOpenGL_GrBackend,
+ reinterpret_cast<GrBackendContext>(interface.get())));
+ if (gr_context_) {
+ // The limit of the number of GPU resources we hold in the GrContext's
+ // GPU cache.
+ static const int kMaxGaneshResourceCacheCount = 2048;
+ // The limit of the bytes allocated toward GPU resources in the GrContext's
+ // GPU cache.
+ static const size_t kMaxGaneshResourceCacheBytes = 96 * 1024 * 1024;
+
+ gr_context_->setResourceCacheLimits(kMaxGaneshResourceCacheCount,
+ kMaxGaneshResourceCacheBytes);
+ }
+}
+
+GrContextForWebGraphicsContext3D::~GrContextForWebGraphicsContext3D() {
+}
+
+void GrContextForWebGraphicsContext3D::OnLostContext() {
+ if (gr_context_)
+ gr_context_->abandonContext();
+}
+
+void GrContextForWebGraphicsContext3D::FreeGpuResources() {
+ if (gr_context_) {
+ TRACE_EVENT_INSTANT0("gpu", "GrContext::freeGpuResources", \
+ TRACE_EVENT_SCOPE_THREAD);
+ gr_context_->freeGpuResources();
+ }
+}
+
+} // namespace content
diff --git a/chromium/content/common/gpu/client/grcontext_for_webgraphicscontext3d.h b/chromium/content/common/gpu/client/grcontext_for_webgraphicscontext3d.h
new file mode 100644
index 00000000000..8d0a2ea2a70
--- /dev/null
+++ b/chromium/content/common/gpu/client/grcontext_for_webgraphicscontext3d.h
@@ -0,0 +1,41 @@
+// 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_COMMON_GPU_CLIENT_GRCONTEXT_FOR_WEBGRAPHICSCONTEXT3D_H_
+#define CONTENT_COMMON_GPU_CLIENT_GRCONTEXT_FOR_WEBGRAPHICSCONTEXT3D_H_
+
+#include "base/macros.h"
+#include "skia/ext/refptr.h"
+
+class GrContext;
+
+namespace gpu_blink {
+class WebGraphicsContext3DImpl;
+}
+
+namespace content {
+
+// This class binds an offscreen GrContext to an offscreen context3d. The
+// context3d is used by the GrContext so must be valid as long as this class
+// is alive.
+class GrContextForWebGraphicsContext3D {
+ public:
+ explicit GrContextForWebGraphicsContext3D(
+ gpu_blink::WebGraphicsContext3DImpl* context3d);
+ virtual ~GrContextForWebGraphicsContext3D();
+
+ GrContext* get() { return gr_context_.get(); }
+
+ void OnLostContext();
+ void FreeGpuResources();
+
+ private:
+ skia::RefPtr<class GrContext> gr_context_;
+
+ DISALLOW_COPY_AND_ASSIGN(GrContextForWebGraphicsContext3D);
+};
+
+} // namespace content
+
+#endif // CONTENT_COMMON_GPU_CLIENT_GRCONTEXT_FOR_WEBGRAPHICSCONTEXT3D_H_
diff --git a/chromium/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc b/chromium/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc
index a5ba1807fe9..b06b06ecab3 100644
--- a/chromium/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc
+++ b/chromium/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc
@@ -16,13 +16,13 @@
#include "base/atomicops.h"
#include "base/bind.h"
#include "base/command_line.h"
-#include "base/debug/trace_event.h"
#include "base/lazy_instance.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/tracked_objects.h"
+#include "base/profiler/scoped_tracker.h"
+#include "base/trace_event/trace_event.h"
#include "content/common/gpu/client/gpu_channel_host.h"
#include "content/public/common/content_constants.h"
#include "content/public/common/content_switches.h"
@@ -37,6 +37,8 @@
#include "gpu/skia_bindings/gl_bindings_skia_cmd_buffer.h"
#include "third_party/skia/include/core/SkTypes.h"
+using blink::WGC3Denum;
+
namespace content {
namespace {
@@ -95,10 +97,13 @@ WebGraphicsContext3DCommandBufferImpl::WebGraphicsContext3DCommandBufferImpl(
host_(host),
surface_id_(surface_id),
active_url_(active_url),
+ context_type_(CONTEXT_TYPE_UNKNOWN),
gpu_preference_(attributes.preferDiscreteGPU ? gfx::PreferDiscreteGpu
: gfx::PreferIntegratedGpu),
mem_limits_(limits),
weak_ptr_factory_(this) {
+ if (attributes_.webGL)
+ context_type_ = OFFSCREEN_CONTEXT_FOR_WEBGL;
if (share_context) {
DCHECK(!attributes_.shareResources);
share_group_ = share_context->share_group_;
@@ -128,18 +133,14 @@ bool WebGraphicsContext3DCommandBufferImpl::MaybeInitializeGL() {
TRACE_EVENT0("gpu", "WebGfxCtx3DCmdBfrImpl::MaybeInitializeGL");
- // Below, we perform an expensive one-time initialization that is required to
- // get first pixels to the screen. This can't be called "jank" since there is
- // nothing on the screen. Using TaskStopwatch to exclude the operation from
- // jank calculations.
- tracked_objects::TaskStopwatch stopwatch;
- stopwatch.Start();
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/125248 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "125248 WebGraphicsContext3DCommandBufferImpl::MaybeInitializeGL"));
if (!CreateContext(surface_id_ != 0)) {
Destroy();
- stopwatch.Stop();
-
initialize_failed_ = true;
return false;
}
@@ -147,8 +148,8 @@ bool WebGraphicsContext3DCommandBufferImpl::MaybeInitializeGL() {
if (gl_ && attributes_.webGL)
gl_->EnableFeatureCHROMIUM("webgl_enable_glsl_webgl_validation");
- command_buffer_->SetChannelErrorCallback(
- base::Bind(&WebGraphicsContext3DCommandBufferImpl::OnGpuChannelLost,
+ command_buffer_->SetContextLostCallback(
+ base::Bind(&WebGraphicsContext3DCommandBufferImpl::OnContextLost,
weak_ptr_factory_.GetWeakPtr()));
command_buffer_->SetOnConsoleMessageCallback(
@@ -157,8 +158,6 @@ bool WebGraphicsContext3DCommandBufferImpl::MaybeInitializeGL() {
real_gl_->SetErrorMessageCallback(getErrorMessageCallback());
- stopwatch.Stop();
-
visible_ = true;
initialized_ = true;
return true;
@@ -202,6 +201,7 @@ bool WebGraphicsContext3DCommandBufferImpl::InitializeCommandBuffer(
if (!command_buffer_) {
DLOG(ERROR) << "GpuChannelHost failed to create command buffer.";
+ UmaRecordContextInitFailed(context_type_);
return false;
}
@@ -211,6 +211,8 @@ bool WebGraphicsContext3DCommandBufferImpl::InitializeCommandBuffer(
// Initialize the command buffer.
bool result = command_buffer_->Initialize();
LOG_IF(ERROR, !result) << "CommandBufferProxy::Initialize failed.";
+ if (!result)
+ UmaRecordContextInitFailed(context_type_);
return result;
}
@@ -278,8 +280,8 @@ bool WebGraphicsContext3DCommandBufferImpl::CreateContext(bool onscreen) {
if (add_to_share_group)
share_group_->AddContextLocked(this);
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableGpuClientTracing)) {
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableGpuClientTracing)) {
trace_gl_.reset(new gpu::gles2::GLES2TraceImplementation(GetGLInterface()));
setGLInterface(trace_gl_.get());
}
@@ -355,7 +357,7 @@ bool WebGraphicsContext3DCommandBufferImpl::IsCommandBufferContextLost() {
if (host_.get() && host_->IsLost())
return true;
gpu::CommandBuffer::State state = command_buffer_->GetLastState();
- return state.error == gpu::error::kLostContext;
+ return gpu::error::IsError(state.error);
}
// static
@@ -391,7 +393,10 @@ WGC3Denum convertReason(gpu::error::ContextLostReason reason) {
return GL_GUILTY_CONTEXT_RESET_ARB;
case gpu::error::kInnocent:
return GL_INNOCENT_CONTEXT_RESET_ARB;
+ case gpu::error::kOutOfMemory:
+ case gpu::error::kMakeCurrentFailed:
case gpu::error::kUnknown:
+ case gpu::error::kGpuChannelLost:
return GL_UNKNOWN_CONTEXT_RESET_ARB;
}
@@ -401,9 +406,9 @@ WGC3Denum convertReason(gpu::error::ContextLostReason reason) {
} // anonymous namespace
-void WebGraphicsContext3DCommandBufferImpl::OnGpuChannelLost() {
- context_lost_reason_ = convertReason(
- command_buffer_->GetLastState().context_lost_reason);
+void WebGraphicsContext3DCommandBufferImpl::OnContextLost() {
+ context_lost_reason_ =
+ convertReason(command_buffer_->GetLastState().context_lost_reason);
if (context_lost_callback_) {
context_lost_callback_->onContextLost();
}
@@ -415,6 +420,9 @@ void WebGraphicsContext3DCommandBufferImpl::OnGpuChannelLost() {
base::AutoLock lock(g_default_share_groups_lock.Get());
g_default_share_groups.Get().erase(host_.get());
}
+
+ gpu::CommandBuffer::State state = command_buffer_->GetLastState();
+ UmaRecordContextLost(context_type_, state.error, state.context_lost_reason);
}
} // namespace content
diff --git a/chromium/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h b/chromium/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h
index 9b4c7b6157b..115e167dc56 100644
--- a/chromium/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h
+++ b/chromium/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h
@@ -13,13 +13,14 @@
#include "base/memory/weak_ptr.h"
#include "base/synchronization/lock.h"
#include "content/common/content_export.h"
+#include "content/common/gpu/client/command_buffer_metrics.h"
#include "content/common/gpu/client/command_buffer_proxy_impl.h"
+#include "gpu/blink/webgraphicscontext3d_impl.h"
#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gl/gpu_preference.h"
#include "url/gurl.h"
-#include "webkit/common/gpu/webgraphicscontext3d_impl.h"
namespace gpu {
@@ -42,7 +43,7 @@ const size_t kDefaultMinTransferBufferSize = 1 * 256 * 1024;
const size_t kDefaultMaxTransferBufferSize = 16 * 1024 * 1024;
class WebGraphicsContext3DCommandBufferImpl
- : public webkit::gpu::WebGraphicsContext3DImpl {
+ : public gpu_blink::WebGraphicsContext3DImpl {
public:
enum MappedMemoryReclaimLimit {
kNoLimit = 0,
@@ -148,8 +149,11 @@ class WebGraphicsContext3DCommandBufferImpl
// WebGraphicsContext3D methods
virtual bool isContextLost();
- virtual WGC3Denum getGraphicsResetStatusARB();
+ virtual blink::WGC3Denum getGraphicsResetStatusARB();
+ void SetContextType(CommandBufferContextType type) {
+ context_type_ = type;
+ }
private:
// These are the same error codes as used by EGL.
enum Error {
@@ -184,7 +188,7 @@ class WebGraphicsContext3DCommandBufferImpl
// unnecessary complexity at the moment.
bool CreateContext(bool onscreen);
- virtual void OnGpuChannelLost();
+ virtual void OnContextLost();
bool lose_context_when_out_of_memory_;
blink::WebGraphicsContext3D::Attributes attributes_;
@@ -195,6 +199,7 @@ class WebGraphicsContext3DCommandBufferImpl
scoped_refptr<GpuChannelHost> host_;
int32 surface_id_;
GURL active_url_;
+ CommandBufferContextType context_type_;
gfx::GpuPreference gpu_preference_;
diff --git a/chromium/content/common/gpu/devtools_gpu_agent.cc b/chromium/content/common/gpu/devtools_gpu_agent.cc
deleted file mode 100644
index e4f5595b37e..00000000000
--- a/chromium/content/common/gpu/devtools_gpu_agent.cc
+++ /dev/null
@@ -1,80 +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/common/gpu/devtools_gpu_agent.h"
-
-#include "base/logging.h"
-#include "content/common/devtools_messages.h"
-#include "content/common/gpu/gpu_channel.h"
-#include "content/common/gpu/gpu_channel_manager.h"
-
-namespace content {
-
-DevToolsGpuAgent::DevToolsGpuAgent(GpuChannel* gpu_channel) :
- gpu_channel_(gpu_channel),
- route_id_(MSG_ROUTING_NONE) {
-}
-
-DevToolsGpuAgent::~DevToolsGpuAgent() {
-}
-
-bool DevToolsGpuAgent::StartEventsRecording(int32 route_id) {
- DCHECK(CalledOnValidThread());
- if (route_id_ != MSG_ROUTING_NONE) {
- // Events recording is already in progress, so "fail" the call by
- // returning false.
- return false;
- }
- route_id_ = route_id;
- tasks_.reset(new GpuTaskInfoList());
- GpuEventsDispatcher* dispatcher =
- gpu_channel_->gpu_channel_manager()->gpu_devtools_events_dispatcher();
- dispatcher->AddProcessor(this);
- return true;
-}
-
-void DevToolsGpuAgent::StopEventsRecording() {
- DCHECK(CalledOnValidThread());
- if (route_id_ == MSG_ROUTING_NONE)
- return;
- GpuEventsDispatcher* dispatcher =
- gpu_channel_->gpu_channel_manager()->gpu_devtools_events_dispatcher();
- dispatcher->RemoveProcessor(this);
- route_id_ = MSG_ROUTING_NONE;
-}
-
-void DevToolsGpuAgent::ProcessEvent(
- TimeTicks timestamp,
- GpuEventsDispatcher::EventPhase phase,
- GpuChannel* channel) {
- DCHECK(CalledOnValidThread());
- if (route_id_ == MSG_ROUTING_NONE)
- return;
-
- GpuTaskInfo task;
- task.timestamp = (timestamp - TimeTicks()).InSecondsF();
- task.phase = phase;
- task.foreign = channel != gpu_channel_;
- task.gpu_memory_used_bytes = channel->GetMemoryUsage();
- task.gpu_memory_limit_bytes = gpu_channel_->gpu_channel_manager()->
- gpu_memory_manager()->GetMaximumClientAllocation();
-
- const int kFlushIntervalMs = 100;
- const unsigned kMaxPendingItems = 100;
- if (!tasks_->empty() &&
- ((timestamp - last_flush_time_).InMilliseconds() >= kFlushIntervalMs ||
- tasks_->size() >= kMaxPendingItems)) {
- Send(new DevToolsAgentMsg_GpuTasksChunk(route_id_, *tasks_));
- tasks_->clear();
- last_flush_time_ = timestamp;
- }
- tasks_->push_back(task);
-}
-
-bool DevToolsGpuAgent::Send(IPC::Message* msg) {
- scoped_ptr<IPC::Message> message(msg);
- return gpu_channel_ && gpu_channel_->Send(message.release());
-}
-
-} // namespace content
diff --git a/chromium/content/common/gpu/devtools_gpu_agent.h b/chromium/content/common/gpu/devtools_gpu_agent.h
deleted file mode 100644
index 3b7f4019a9f..00000000000
--- a/chromium/content/common/gpu/devtools_gpu_agent.h
+++ /dev/null
@@ -1,51 +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_COMMON_GPU_DEVTOOLS_GPU_AGENT_H_
-#define CONTENT_COMMON_GPU_DEVTOOLS_GPU_AGENT_H_
-
-#include "base/memory/scoped_ptr.h"
-#include "base/threading/non_thread_safe.h"
-#include "base/time/time.h"
-#include "content/common/gpu/devtools_gpu_instrumentation.h"
-
-using base::TimeTicks;
-struct GpuTaskInfo;
-
-namespace IPC {
-class Message;
-}
-
-namespace content {
-
-class GpuChannel;
-
-class DevToolsGpuAgent : public base::NonThreadSafe {
- public:
- explicit DevToolsGpuAgent(GpuChannel* gpu_channel);
- virtual ~DevToolsGpuAgent();
-
- void ProcessEvent(TimeTicks timestamp,
- GpuEventsDispatcher::EventPhase,
- GpuChannel* channel);
-
- bool StartEventsRecording(int32 route_id);
- void StopEventsRecording();
-
- private:
- typedef std::vector<GpuTaskInfo> GpuTaskInfoList;
-
- bool Send(IPC::Message* msg);
-
- GpuChannel* gpu_channel_;
- scoped_ptr<GpuTaskInfoList> tasks_;
- TimeTicks last_flush_time_;
- int32 route_id_;
-
- DISALLOW_COPY_AND_ASSIGN(DevToolsGpuAgent);
-};
-
-} // namespace content
-
-#endif // CONTENT_COMMON_GPU_DEVTOOLS_GPU_AGENT_H_
diff --git a/chromium/content/common/gpu/devtools_gpu_instrumentation.cc b/chromium/content/common/gpu/devtools_gpu_instrumentation.cc
deleted file mode 100644
index 0167cf8547a..00000000000
--- a/chromium/content/common/gpu/devtools_gpu_instrumentation.cc
+++ /dev/null
@@ -1,50 +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/common/gpu/devtools_gpu_instrumentation.h"
-
-#include "base/logging.h"
-#include "base/time/time.h"
-#include "content/common/gpu/devtools_gpu_agent.h"
-#include "content/common/gpu/gpu_channel.h"
-#include "content/common/gpu/gpu_channel_manager.h"
-
-namespace content {
-
-bool GpuEventsDispatcher::enabled_ = false;
-
-GpuEventsDispatcher::GpuEventsDispatcher() {
-}
-
-GpuEventsDispatcher::~GpuEventsDispatcher() {
-}
-
-void GpuEventsDispatcher::AddProcessor(DevToolsGpuAgent* processor) {
- DCHECK(CalledOnValidThread());
- processors_.push_back(processor);
- enabled_ = !processors_.empty();
-}
-
-void GpuEventsDispatcher::RemoveProcessor(DevToolsGpuAgent* processor) {
- DCHECK(CalledOnValidThread());
- processors_.erase(
- std::remove(processors_.begin(), processors_.end(), processor),
- processors_.end());
- enabled_ = !processors_.empty();
-}
-
-// static
-void GpuEventsDispatcher::DoFireEvent(EventPhase phase,
- GpuChannel* channel) {
- TimeTicks timestamp = base::TimeTicks::NowFromSystemTraceTime();
- GpuEventsDispatcher* self =
- channel->gpu_channel_manager()->gpu_devtools_events_dispatcher();
- DCHECK(self->CalledOnValidThread());
- std::vector<DevToolsGpuAgent*>::iterator it;
- for (it = self->processors_.begin(); it != self->processors_.end(); ++it) {
- (*it)->ProcessEvent(timestamp, phase, channel);
- }
-}
-
-} // namespace
diff --git a/chromium/content/common/gpu/devtools_gpu_instrumentation.h b/chromium/content/common/gpu/devtools_gpu_instrumentation.h
deleted file mode 100644
index 1296625860b..00000000000
--- a/chromium/content/common/gpu/devtools_gpu_instrumentation.h
+++ /dev/null
@@ -1,65 +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_COMMON_GPU_DEVTOOLS_GPU_INSTRUMENTATION_H_
-#define CONTENT_COMMON_GPU_DEVTOOLS_GPU_INSTRUMENTATION_H_
-
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/threading/non_thread_safe.h"
-
-namespace content {
-
-class DevToolsGpuAgent;
-class GpuChannel;
-
-class GpuEventsDispatcher : public base::NonThreadSafe {
- public:
- enum EventPhase {
- kEventStart,
- kEventFinish
- };
-
- GpuEventsDispatcher();
- ~GpuEventsDispatcher();
-
- void AddProcessor(DevToolsGpuAgent* processor);
- void RemoveProcessor(DevToolsGpuAgent* processor);
-
- static void FireEvent(EventPhase phase, GpuChannel* channel) {
- if (!IsEnabled())
- return;
- DoFireEvent(phase, channel);
- }
-
-private:
- static bool IsEnabled() { return enabled_; }
- static void DoFireEvent(EventPhase, GpuChannel* channel);
-
- static bool enabled_;
- std::vector<DevToolsGpuAgent*> processors_;
-};
-
-namespace devtools_gpu_instrumentation {
-
-class ScopedGpuTask {
- public:
- explicit ScopedGpuTask(GpuChannel* channel) :
- channel_(channel) {
- GpuEventsDispatcher::FireEvent(GpuEventsDispatcher::kEventStart, channel_);
- }
- ~ScopedGpuTask() {
- GpuEventsDispatcher::FireEvent(GpuEventsDispatcher::kEventFinish, channel_);
- }
- private:
- GpuChannel* channel_;
- DISALLOW_COPY_AND_ASSIGN(ScopedGpuTask);
-};
-
-} // namespace devtools_gpu_instrumentation
-
-} // namespace content
-
-#endif // CONTENT_COMMON_GPU_DEVTOOLS_GPU_INSTRUMENTATION_H_
diff --git a/chromium/content/common/gpu/gpu_channel.cc b/chromium/content/common/gpu/gpu_channel.cc
index 369d514d061..2768eea2f41 100644
--- a/chromium/content/common/gpu/gpu_channel.cc
+++ b/chromium/content/common/gpu/gpu_channel.cc
@@ -13,22 +13,28 @@
#include "base/bind.h"
#include "base/command_line.h"
-#include "base/debug/trace_event.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
#include "base/timer/timer.h"
-#include "content/common/gpu/devtools_gpu_agent.h"
+#include "base/trace_event/trace_event.h"
#include "content/common/gpu/gpu_channel_manager.h"
+#include "content/common/gpu/gpu_memory_buffer_factory.h"
#include "content/common/gpu/gpu_messages.h"
-#include "content/common/gpu/sync_point_manager.h"
#include "content/public/common/content_switches.h"
#include "gpu/command_buffer/common/mailbox.h"
+#include "gpu/command_buffer/common/value_state.h"
#include "gpu/command_buffer/service/gpu_scheduler.h"
+#include "gpu/command_buffer/service/image_factory.h"
#include "gpu/command_buffer/service/mailbox_manager_impl.h"
+#include "gpu/command_buffer/service/sync_point_manager.h"
+#include "gpu/command_buffer/service/valuebuffer_manager.h"
#include "ipc/ipc_channel.h"
#include "ipc/message_filter.h"
#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_image_shared_memory.h"
#include "ui/gl/gl_surface.h"
#if defined(OS_POSIX)
@@ -70,15 +76,16 @@ const int64 kStopPreemptThresholdMs = kVsyncIntervalMs;
// - it generates mailbox names for clients of the GPU process on the IO thread.
class GpuChannelMessageFilter : public IPC::MessageFilter {
public:
- GpuChannelMessageFilter(base::WeakPtr<GpuChannel> gpu_channel,
- scoped_refptr<SyncPointManager> sync_point_manager,
- scoped_refptr<base::MessageLoopProxy> message_loop,
- bool future_sync_points)
+ GpuChannelMessageFilter(
+ base::WeakPtr<GpuChannel> gpu_channel,
+ scoped_refptr<gpu::SyncPointManager> sync_point_manager,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ bool future_sync_points)
: preemption_state_(IDLE),
gpu_channel_(gpu_channel),
sender_(NULL),
sync_point_manager_(sync_point_manager),
- message_loop_(message_loop),
+ task_runner_(task_runner),
messages_forwarded_to_channel_(0),
a_stub_is_descheduled_(false),
future_sync_points_(future_sync_points) {}
@@ -105,7 +112,7 @@ class GpuChannelMessageFilter : public IPC::MessageFilter {
}
if (message.type() == GpuCommandBufferMsg_InsertSyncPoint::ID) {
- Tuple1<bool> retire;
+ Tuple<bool> retire;
IPC::Message* reply = IPC::SyncMessage::GenerateReply(&message);
if (!GpuCommandBufferMsg_InsertSyncPoint::ReadSendParam(&message,
&retire)) {
@@ -113,7 +120,7 @@ class GpuChannelMessageFilter : public IPC::MessageFilter {
Send(reply);
return true;
}
- if (!future_sync_points_ && !retire.a) {
+ if (!future_sync_points_ && !get<0>(retire)) {
LOG(ERROR) << "Untrusted contexts can't create future sync points";
reply->set_reply_error();
Send(reply);
@@ -122,14 +129,11 @@ class GpuChannelMessageFilter : public IPC::MessageFilter {
uint32 sync_point = sync_point_manager_->GenerateSyncPoint();
GpuCommandBufferMsg_InsertSyncPoint::WriteReplyParams(reply, sync_point);
Send(reply);
- message_loop_->PostTask(
+ task_runner_->PostTask(
FROM_HERE,
base::Bind(&GpuChannelMessageFilter::InsertSyncPointOnMainThread,
- gpu_channel_,
- sync_point_manager_,
- message.routing_id(),
- retire.a,
- sync_point));
+ gpu_channel_, sync_point_manager_, message.routing_id(),
+ get<0>(retire), sync_point));
handled = true;
}
@@ -348,7 +352,7 @@ class GpuChannelMessageFilter : public IPC::MessageFilter {
static void InsertSyncPointOnMainThread(
base::WeakPtr<GpuChannel> gpu_channel,
- scoped_refptr<SyncPointManager> manager,
+ scoped_refptr<gpu::SyncPointManager> manager,
int32 routing_id,
bool retire,
uint32 sync_point) {
@@ -377,8 +381,8 @@ class GpuChannelMessageFilter : public IPC::MessageFilter {
// passed through - therefore the WeakPtr assumptions are respected.
base::WeakPtr<GpuChannel> gpu_channel_;
IPC::Sender* sender_;
- scoped_refptr<SyncPointManager> sync_point_manager_;
- scoped_refptr<base::MessageLoopProxy> message_loop_;
+ scoped_refptr<gpu::SyncPointManager> sync_point_manager_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
scoped_refptr<gpu::PreemptionFlag> preempting_flag_;
std::queue<PendingMessage> pending_messages_;
@@ -420,35 +424,33 @@ GpuChannel::GpuChannel(GpuChannelManager* gpu_channel_manager,
const base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess();
log_messages_ = command_line->HasSwitch(switches::kLogPluginMessages);
+
+ subscription_ref_set_ = new gpu::gles2::SubscriptionRefSet();
+ subscription_ref_set_->AddObserver(this);
}
GpuChannel::~GpuChannel() {
STLDeleteElements(&deferred_messages_);
+ subscription_ref_set_->RemoveObserver(this);
if (preempting_flag_.get())
preempting_flag_->Reset();
}
-void GpuChannel::Init(base::MessageLoopProxy* io_message_loop,
+void GpuChannel::Init(base::SingleThreadTaskRunner* io_task_runner,
base::WaitableEvent* shutdown_event) {
DCHECK(!channel_.get());
// Map renderer ID to a (single) channel to that process.
- channel_ = IPC::SyncChannel::Create(channel_id_,
- IPC::Channel::MODE_SERVER,
- this,
- io_message_loop,
- false,
- shutdown_event);
-
- filter_ =
- new GpuChannelMessageFilter(weak_factory_.GetWeakPtr(),
- gpu_channel_manager_->sync_point_manager(),
- base::MessageLoopProxy::current(),
- allow_future_sync_points_);
- io_message_loop_ = io_message_loop;
+ channel_ =
+ IPC::SyncChannel::Create(channel_id_, IPC::Channel::MODE_SERVER, this,
+ io_task_runner, false, shutdown_event);
+
+ filter_ = new GpuChannelMessageFilter(
+ weak_factory_.GetWeakPtr(), gpu_channel_manager_->sync_point_manager(),
+ base::ThreadTaskRunnerHandle::Get(), allow_future_sync_points_);
+ io_task_runner_ = io_task_runner;
channel_->AddFilter(filter_.get());
-
- devtools_gpu_agent_.reset(new DevToolsGpuAgent(this));
+ pending_valuebuffer_state_ = new gpu::ValueStateMap();
}
std::string GpuChannel::GetChannelName() {
@@ -506,6 +508,16 @@ bool GpuChannel::Send(IPC::Message* message) {
return channel_->Send(message);
}
+void GpuChannel::OnAddSubscription(unsigned int target) {
+ gpu_channel_manager()->Send(
+ new GpuHostMsg_AddSubscription(client_id_, target));
+}
+
+void GpuChannel::OnRemoveSubscription(unsigned int target) {
+ gpu_channel_manager()->Send(
+ new GpuHostMsg_RemoveSubscription(client_id_, target));
+}
+
void GpuChannel::RequeueMessage() {
DCHECK(currently_processing_message_);
deferred_messages_.push_front(
@@ -522,7 +534,7 @@ void GpuChannel::OnScheduled() {
// defer newly received messages until the ones in the queue have all been
// handled by HandleMessage. HandleMessage is invoked as a
// task to prevent reentrancy.
- base::MessageLoop::current()->PostTask(
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(&GpuChannel::HandleMessage, weak_factory_.GetWeakPtr()));
handle_messages_scheduled_ = true;
@@ -541,11 +553,10 @@ void GpuChannel::StubSchedulingChanged(bool scheduled) {
if (a_stub_is_descheduled != a_stub_was_descheduled) {
if (preempting_flag_.get()) {
- io_message_loop_->PostTask(
+ io_task_runner_->PostTask(
FROM_HERE,
base::Bind(&GpuChannelMessageFilter::UpdateStubSchedulingState,
- filter_,
- a_stub_is_descheduled));
+ filter_, a_stub_is_descheduled));
}
}
}
@@ -575,6 +586,8 @@ CreateCommandBufferResult GpuChannel::CreateViewCommandBuffer(
share_group,
window,
mailbox_manager_.get(),
+ subscription_ref_set_.get(),
+ pending_valuebuffer_state_.get(),
gfx::Size(),
disallowed_features_,
init_params.attribs,
@@ -622,8 +635,9 @@ void GpuChannel::RemoveRoute(int32 route_id) {
gpu::PreemptionFlag* GpuChannel::GetPreemptionFlag() {
if (!preempting_flag_.get()) {
preempting_flag_ = new gpu::PreemptionFlag;
- io_message_loop_->PostTask(
- FROM_HERE, base::Bind(
+ io_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(
&GpuChannelMessageFilter::SetPreemptingFlagAndSchedulingState,
filter_, preempting_flag_, num_stubs_descheduled_ > 0));
}
@@ -652,10 +666,6 @@ bool GpuChannel::OnControlMessageReceived(const IPC::Message& msg) {
OnCreateOffscreenCommandBuffer)
IPC_MESSAGE_HANDLER(GpuChannelMsg_DestroyCommandBuffer,
OnDestroyCommandBuffer)
- IPC_MESSAGE_HANDLER(GpuChannelMsg_DevToolsStartEventsRecording,
- OnDevToolsStartEventsRecording)
- IPC_MESSAGE_HANDLER(GpuChannelMsg_DevToolsStopEventsRecording,
- OnDevToolsStopEventsRecording)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
DCHECK(handled) << msg.type();
@@ -733,6 +743,8 @@ void GpuChannel::OnCreateOffscreenCommandBuffer(
share_group,
gfx::GLSurfaceHandle(),
mailbox_manager_.get(),
+ subscription_ref_set_.get(),
+ pending_valuebuffer_state_.get(),
size,
disallowed_features_,
init_params.attribs,
@@ -775,23 +787,12 @@ void GpuChannel::OnDestroyCommandBuffer(int32 route_id) {
}
}
-void GpuChannel::OnDevToolsStartEventsRecording(int32 route_id,
- bool* succeeded) {
- *succeeded = devtools_gpu_agent_->StartEventsRecording(route_id);
-}
-
-void GpuChannel::OnDevToolsStopEventsRecording() {
- devtools_gpu_agent_->StopEventsRecording();
-}
-
void GpuChannel::MessageProcessed() {
messages_processed_++;
if (preempting_flag_.get()) {
- io_message_loop_->PostTask(
- FROM_HERE,
- base::Bind(&GpuChannelMessageFilter::MessageProcessed,
- filter_,
- messages_processed_));
+ io_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&GpuChannelMessageFilter::MessageProcessed,
+ filter_, messages_processed_));
}
}
@@ -818,4 +819,39 @@ uint64 GpuChannel::GetMemoryUsage() {
return size;
}
+scoped_refptr<gfx::GLImage> GpuChannel::CreateImageForGpuMemoryBuffer(
+ const gfx::GpuMemoryBufferHandle& handle,
+ const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
+ uint32 internalformat) {
+ switch (handle.type) {
+ case gfx::SHARED_MEMORY_BUFFER: {
+ scoped_refptr<gfx::GLImageSharedMemory> image(
+ new gfx::GLImageSharedMemory(size, internalformat));
+ if (!image->Initialize(handle, format))
+ return scoped_refptr<gfx::GLImage>();
+
+ return image;
+ }
+ default: {
+ GpuChannelManager* manager = gpu_channel_manager();
+ if (!manager->gpu_memory_buffer_factory())
+ return scoped_refptr<gfx::GLImage>();
+
+ return manager->gpu_memory_buffer_factory()
+ ->AsImageFactory()
+ ->CreateImageForGpuMemoryBuffer(handle,
+ size,
+ format,
+ internalformat,
+ client_id_);
+ }
+ }
+}
+
+void GpuChannel::HandleUpdateValueState(
+ unsigned int target, const gpu::ValueState& state) {
+ pending_valuebuffer_state_->UpdateState(target, state);
+}
+
} // namespace content
diff --git a/chromium/content/common/gpu/gpu_channel.h b/chromium/content/common/gpu/gpu_channel.h
index 0d8538f4889..710b31ab285 100644
--- a/chromium/content/common/gpu/gpu_channel.h
+++ b/chromium/content/common/gpu/gpu_channel.h
@@ -19,21 +19,26 @@
#include "content/common/gpu/gpu_memory_manager.h"
#include "content/common/gpu/gpu_result_codes.h"
#include "content/common/message_router.h"
+#include "gpu/command_buffer/service/valuebuffer_manager.h"
#include "ipc/ipc_sync_channel.h"
+#include "ui/gfx/geometry/size.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/size.h"
#include "ui/gl/gl_share_group.h"
#include "ui/gl/gpu_preference.h"
struct GPUCreateCommandBufferConfig;
namespace base {
-class MessageLoopProxy;
class WaitableEvent;
}
namespace gpu {
class PreemptionFlag;
+union ValueState;
+class ValueStateMap;
+namespace gles2 {
+class SubscriptionRefSet;
+}
}
namespace IPC {
@@ -41,14 +46,14 @@ class MessageFilter;
}
namespace content {
-class DevToolsGpuAgent;
class GpuChannelManager;
class GpuChannelMessageFilter;
class GpuWatchdog;
// Encapsulates an IPC channel between the GPU process and one renderer
// process. On the renderer side there's a corresponding GpuChannelHost.
-class GpuChannel : public IPC::Listener, public IPC::Sender {
+class GpuChannel : public IPC::Listener, public IPC::Sender,
+ public gpu::gles2::SubscriptionRefSet::Observer {
public:
// Takes ownership of the renderer process handle.
GpuChannel(GpuChannelManager* gpu_channel_manager,
@@ -60,7 +65,7 @@ class GpuChannel : public IPC::Listener, public IPC::Sender {
bool allow_future_sync_points);
~GpuChannel() override;
- void Init(base::MessageLoopProxy* io_message_loop,
+ void Init(base::SingleThreadTaskRunner* io_task_runner,
base::WaitableEvent* shutdown_event);
// Get the GpuChannelManager that owns this channel.
@@ -79,8 +84,8 @@ class GpuChannel : public IPC::Listener, public IPC::Sender {
int client_id() const { return client_id_; }
- scoped_refptr<base::MessageLoopProxy> io_message_loop() const {
- return io_message_loop_;
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner() const {
+ return io_task_runner_;
}
// IPC::Listener implementation:
@@ -95,6 +100,10 @@ class GpuChannel : public IPC::Listener, public IPC::Sender {
// unscheduling conditions.
void RequeueMessage();
+ // SubscriptionRefSet::Observer implementation
+ void OnAddSubscription(unsigned int target) override;
+ void OnRemoveSubscription(unsigned int target) override;
+
// This is called when a command buffer transitions from the unscheduled
// state to the scheduled state, which potentially means the channel
// transitions from the unscheduled to the scheduled state. When this occurs
@@ -143,8 +152,22 @@ class GpuChannel : public IPC::Listener, public IPC::Sender {
uint64 GetMemoryUsage();
+ scoped_refptr<gfx::GLImage> CreateImageForGpuMemoryBuffer(
+ const gfx::GpuMemoryBufferHandle& handle,
+ const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
+ uint32 internalformat);
+
bool allow_future_sync_points() const { return allow_future_sync_points_; }
+ void HandleUpdateValueState(unsigned int target,
+ const gpu::ValueState& state);
+
+ // Visible for testing.
+ const gpu::ValueStateMap* pending_valuebuffer_state() const {
+ return pending_valuebuffer_state_.get();
+ }
+
private:
friend class GpuChannelMessageFilter;
@@ -161,8 +184,6 @@ class GpuChannel : public IPC::Listener, public IPC::Sender {
int32 route_id,
bool* succeeded);
void OnDestroyCommandBuffer(int32 route_id);
- void OnDevToolsStartEventsRecording(int32 route_id, bool* succeeded);
- void OnDevToolsStopEventsRecording();
// Decrement the count of unhandled IPC messages and defer preemption.
void MessageProcessed();
@@ -201,6 +222,10 @@ class GpuChannel : public IPC::Listener, public IPC::Sender {
scoped_refptr<gpu::gles2::MailboxManager> mailbox_manager_;
+ scoped_refptr<gpu::gles2::SubscriptionRefSet> subscription_ref_set_;
+
+ scoped_refptr<gpu::ValueStateMap> pending_valuebuffer_state_;
+
typedef IDMap<GpuCommandBufferStub, IDMapOwnPointer> StubMap;
StubMap stubs_;
@@ -212,8 +237,7 @@ class GpuChannel : public IPC::Listener, public IPC::Sender {
IPC::Message* currently_processing_message_;
scoped_refptr<GpuChannelMessageFilter> filter_;
- scoped_refptr<base::MessageLoopProxy> io_message_loop_;
- scoped_ptr<DevToolsGpuAgent> devtools_gpu_agent_;
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
size_t num_stubs_descheduled_;
diff --git a/chromium/content/common/gpu/gpu_channel_manager.cc b/chromium/content/common/gpu/gpu_channel_manager.cc
index a073e20151e..4cec7cb3c81 100644
--- a/chromium/content/common/gpu/gpu_channel_manager.cc
+++ b/chromium/content/common/gpu/gpu_channel_manager.cc
@@ -6,20 +6,28 @@
#include "base/bind.h"
#include "base/command_line.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
#include "content/common/gpu/gpu_channel.h"
#include "content/common/gpu/gpu_memory_buffer_factory.h"
#include "content/common/gpu/gpu_memory_manager.h"
#include "content/common/gpu/gpu_messages.h"
-#include "content/common/gpu/sync_point_manager.h"
#include "content/common/message_router.h"
+#include "gpu/command_buffer/common/value_state.h"
#include "gpu/command_buffer/service/feature_info.h"
#include "gpu/command_buffer/service/gpu_switches.h"
#include "gpu/command_buffer/service/mailbox_manager_impl.h"
#include "gpu/command_buffer/service/memory_program_cache.h"
#include "gpu/command_buffer/service/shader_translator_cache.h"
+#include "gpu/command_buffer/service/sync_point_manager.h"
#include "ipc/message_filter.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_share_group.h"
+#if defined(USE_OZONE)
+#include "ui/ozone/public/gpu_platform_support.h"
+#include "ui/ozone/public/ozone_platform.h"
+#endif
namespace content {
@@ -54,49 +62,55 @@ class GpuChannelManagerMessageFilter : public IPC::MessageFilter {
protected:
~GpuChannelManagerMessageFilter() override {}
+ // GPU IO thread bounces off GpuMsg_CreateGpuMemoryBuffer message, because
+ // the UI thread in the browser process must remain fast at all times.
void OnCreateGpuMemoryBuffer(
const GpuMsg_CreateGpuMemoryBuffer_Params& params) {
TRACE_EVENT2("gpu",
"GpuChannelManagerMessageFilter::OnCreateGpuMemoryBuffer",
- "id",
- params.id,
- "client_id",
- params.client_id);
+ "id", params.id, "client_id", params.client_id);
sender_->Send(new GpuHostMsg_GpuMemoryBufferCreated(
- gpu_memory_buffer_factory_->CreateGpuMemoryBuffer(params.type,
- params.id,
- params.size,
- params.format,
- params.usage,
- params.client_id)));
+ gpu_memory_buffer_factory_->CreateGpuMemoryBuffer(
+ params.id, params.size, params.format, params.usage,
+ params.client_id, params.surface_handle)));
}
IPC::Sender* sender_;
GpuMemoryBufferFactory* gpu_memory_buffer_factory_;
};
+gfx::GpuMemoryBufferType GetGpuMemoryBufferFactoryType() {
+ std::vector<gfx::GpuMemoryBufferType> supported_types;
+ GpuMemoryBufferFactory::GetSupportedTypes(&supported_types);
+ DCHECK(!supported_types.empty());
+ return supported_types[0];
+}
+
} // namespace
-GpuChannelManager::GpuChannelManager(MessageRouter* router,
- GpuWatchdog* watchdog,
- base::MessageLoopProxy* io_message_loop,
- base::WaitableEvent* shutdown_event,
- IPC::SyncChannel* channel)
- : io_message_loop_(io_message_loop),
+GpuChannelManager::GpuChannelManager(
+ MessageRouter* router,
+ GpuWatchdog* watchdog,
+ base::SingleThreadTaskRunner* io_task_runner,
+ base::WaitableEvent* shutdown_event,
+ IPC::SyncChannel* channel)
+ : io_task_runner_(io_task_runner),
shutdown_event_(shutdown_event),
router_(router),
gpu_memory_manager_(
this,
GpuMemoryManager::kDefaultMaxSurfacesWithFrontbufferSoftLimit),
watchdog_(watchdog),
- sync_point_manager_(new SyncPointManager),
- gpu_memory_buffer_factory_(GpuMemoryBufferFactory::Create()),
+ sync_point_manager_(gpu::SyncPointManager::Create(false)),
+ gpu_memory_buffer_factory_(
+ GpuMemoryBufferFactory::Create(GetGpuMemoryBufferFactoryType())),
channel_(channel),
- filter_(new GpuChannelManagerMessageFilter(
- gpu_memory_buffer_factory_.get())),
+ filter_(
+ new GpuChannelManagerMessageFilter(gpu_memory_buffer_factory_.get())),
+ relinquish_resources_pending_(false),
weak_factory_(this) {
DCHECK(router_);
- DCHECK(io_message_loop);
+ DCHECK(io_task_runner);
DCHECK(shutdown_event);
channel_->AddFilter(filter_.get());
}
@@ -113,7 +127,7 @@ gpu::gles2::ProgramCache* GpuChannelManager::program_cache() {
if (!program_cache_.get() &&
(gfx::g_driver_gl.ext.b_GL_ARB_get_program_binary ||
gfx::g_driver_gl.ext.b_GL_OES_get_program_binary) &&
- !CommandLine::ForCurrentProcess()->HasSwitch(
+ !base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableGpuProgramCache)) {
program_cache_.reset(new gpu::gles2::MemoryProgramCache());
}
@@ -130,6 +144,7 @@ GpuChannelManager::shader_translator_cache() {
void GpuChannelManager::RemoveChannel(int client_id) {
Send(new GpuHostMsg_DestroyChannel(client_id));
gpu_channels_.erase(client_id);
+ CheckRelinquishGpuResources();
}
int GpuChannelManager::GenerateRouteID() {
@@ -162,6 +177,8 @@ bool GpuChannelManager::OnMessageReceived(const IPC::Message& msg) {
OnCreateViewCommandBuffer)
IPC_MESSAGE_HANDLER(GpuMsg_DestroyGpuMemoryBuffer, OnDestroyGpuMemoryBuffer)
IPC_MESSAGE_HANDLER(GpuMsg_LoadedShader, OnLoadedShader)
+ IPC_MESSAGE_HANDLER(GpuMsg_RelinquishResources, OnRelinquishResources)
+ IPC_MESSAGE_HANDLER(GpuMsg_UpdateValueState, OnUpdateValueState)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
@@ -193,7 +210,7 @@ void GpuChannelManager::OnEstablishChannel(int client_id,
client_id,
false,
allow_future_sync_points));
- channel->Init(io_message_loop_.get(), shutdown_event_);
+ channel->Init(io_task_runner_.get(), shutdown_event_);
channel_handle.name = channel->GetChannelName();
#if defined(OS_POSIX)
@@ -215,6 +232,7 @@ void GpuChannelManager::OnCloseChannel(
iter != gpu_channels_.end(); ++iter) {
if (iter->second->GetChannelName() == channel_handle.name) {
gpu_channels_.erase(iter);
+ CheckRelinquishGpuResources();
return;
}
}
@@ -239,43 +257,45 @@ void GpuChannelManager::OnCreateViewCommandBuffer(
}
void GpuChannelManager::DestroyGpuMemoryBuffer(
- gfx::GpuMemoryBufferType type,
gfx::GpuMemoryBufferId id,
int client_id) {
- io_message_loop_->PostTask(
- FROM_HERE,
- base::Bind(&GpuChannelManager::DestroyGpuMemoryBufferOnIO,
- base::Unretained(this),
- type,
- id,
- client_id));
+ io_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&GpuChannelManager::DestroyGpuMemoryBufferOnIO,
+ base::Unretained(this), id, client_id));
}
void GpuChannelManager::DestroyGpuMemoryBufferOnIO(
- gfx::GpuMemoryBufferType type,
gfx::GpuMemoryBufferId id,
int client_id) {
- gpu_memory_buffer_factory_->DestroyGpuMemoryBuffer(type, id, client_id);
+ gpu_memory_buffer_factory_->DestroyGpuMemoryBuffer(id, client_id);
}
void GpuChannelManager::OnDestroyGpuMemoryBuffer(
- gfx::GpuMemoryBufferType type,
gfx::GpuMemoryBufferId id,
int client_id,
int32 sync_point) {
if (!sync_point) {
- DestroyGpuMemoryBuffer(type, id, client_id);
+ DestroyGpuMemoryBuffer(id, client_id);
} else {
sync_point_manager()->AddSyncPointCallback(
sync_point,
base::Bind(&GpuChannelManager::DestroyGpuMemoryBuffer,
base::Unretained(this),
- type,
id,
client_id));
}
}
+void GpuChannelManager::OnUpdateValueState(
+ int client_id, unsigned int target, const gpu::ValueState& state) {
+ // Only pass updated state to the channel corresponding to the
+ // render_widget_host where the event originated.
+ GpuChannelMap::const_iterator iter = gpu_channels_.find(client_id);
+ if (iter != gpu_channels_.end()) {
+ iter->second->HandleUpdateValueState(target, state);
+ }
+}
+
void GpuChannelManager::OnLoadedShader(std::string program_proto) {
if (program_cache())
program_cache()->LoadProgram(program_proto);
@@ -305,14 +325,14 @@ void GpuChannelManager::LoseAllContexts() {
iter != gpu_channels_.end(); ++iter) {
iter->second->MarkAllContextsLost();
}
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&GpuChannelManager::OnLoseAllContexts,
- weak_factory_.GetWeakPtr()));
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&GpuChannelManager::OnLoseAllContexts,
+ weak_factory_.GetWeakPtr()));
}
void GpuChannelManager::OnLoseAllContexts() {
gpu_channels_.clear();
+ CheckRelinquishGpuResources();
}
gfx::GLSurface* GpuChannelManager::GetDefaultOffscreenSurface() {
@@ -323,4 +343,32 @@ gfx::GLSurface* GpuChannelManager::GetDefaultOffscreenSurface() {
return default_offscreen_surface_.get();
}
+void GpuChannelManager::OnRelinquishResources() {
+ relinquish_resources_pending_ = true;
+ CheckRelinquishGpuResources();
+}
+
+void GpuChannelManager::CheckRelinquishGpuResources() {
+ if (relinquish_resources_pending_ && gpu_channels_.size() <= 1) {
+ relinquish_resources_pending_ = false;
+ if (default_offscreen_surface_.get()) {
+ default_offscreen_surface_->DestroyAndTerminateDisplay();
+ default_offscreen_surface_ = NULL;
+ }
+#if defined(USE_OZONE)
+ ui::OzonePlatform::GetInstance()
+ ->GetGpuPlatformSupport()
+ ->RelinquishGpuResources(
+ base::Bind(&GpuChannelManager::OnResourcesRelinquished,
+ weak_factory_.GetWeakPtr()));
+#else
+ OnResourcesRelinquished();
+#endif
+ }
+}
+
+void GpuChannelManager::OnResourcesRelinquished() {
+ Send(new GpuHostMsg_ResourcesRelinquished());
+}
+
} // namespace content
diff --git a/chromium/content/common/gpu/gpu_channel_manager.h b/chromium/content/common/gpu/gpu_channel_manager.h
index fd9844f6420..a15a8adbb78 100644
--- a/chromium/content/common/gpu/gpu_channel_manager.h
+++ b/chromium/content/common/gpu/gpu_channel_manager.h
@@ -13,9 +13,9 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
#include "build/build_config.h"
-#include "content/common/gpu/devtools_gpu_instrumentation.h"
+#include "content/common/content_export.h"
+#include "content/common/content_param_traits.h"
#include "content/common/gpu/gpu_memory_manager.h"
#include "ipc/ipc_listener.h"
#include "ipc/ipc_sender.h"
@@ -33,6 +33,8 @@ struct GpuMemoryBufferHandle;
}
namespace gpu {
+class SyncPointManager;
+union ValueState;
namespace gles2 {
class MailboxManager;
class ProgramCache;
@@ -53,17 +55,16 @@ class GpuChannel;
class GpuMemoryBufferFactory;
class GpuWatchdog;
class MessageRouter;
-class SyncPointManager;
// A GpuChannelManager is a thread responsible for issuing rendering commands
// managing the lifetimes of GPU channels and forwarding IPC requests from the
// browser process to them based on the corresponding renderer ID.
-class GpuChannelManager : public IPC::Listener,
+class CONTENT_EXPORT GpuChannelManager : public IPC::Listener,
public IPC::Sender {
public:
GpuChannelManager(MessageRouter* router,
GpuWatchdog* watchdog,
- base::MessageLoopProxy* io_message_loop,
+ base::SingleThreadTaskRunner* io_task_runner,
base::WaitableEvent* shutdown_event,
IPC::SyncChannel* channel);
~GpuChannelManager() override;
@@ -91,13 +92,11 @@ class GpuChannelManager : public IPC::Listener,
GpuMemoryManager* gpu_memory_manager() { return &gpu_memory_manager_; }
- GpuEventsDispatcher* gpu_devtools_events_dispatcher() {
- return &gpu_devtools_events_dispatcher_;
- }
-
GpuChannel* LookupChannel(int32 client_id);
- SyncPointManager* sync_point_manager() { return sync_point_manager_.get(); }
+ gpu::SyncPointManager* sync_point_manager() {
+ return sync_point_manager_.get();
+ }
gfx::GLSurface* GetDefaultOffscreenSurface();
@@ -106,7 +105,7 @@ class GpuChannelManager : public IPC::Listener,
}
private:
- typedef base::ScopedPtrHashMap<int, GpuChannel> GpuChannelMap;
+ typedef base::ScopedPtrHashMap<int, scoped_ptr<GpuChannel>> GpuChannelMap;
// Message handlers.
void OnEstablishChannel(int client_id,
@@ -122,20 +121,23 @@ class GpuChannelManager : public IPC::Listener,
const GPUCreateCommandBufferConfig& init_params,
int32 route_id);
void OnLoadedShader(std::string shader);
- void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferType type,
- gfx::GpuMemoryBufferId id,
- int client_id);
- void DestroyGpuMemoryBufferOnIO(gfx::GpuMemoryBufferType type,
- gfx::GpuMemoryBufferId id,
- int client_id);
- void OnDestroyGpuMemoryBuffer(gfx::GpuMemoryBufferType type,
- gfx::GpuMemoryBufferId id,
+ void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id, int client_id);
+ void DestroyGpuMemoryBufferOnIO(gfx::GpuMemoryBufferId id, int client_id);
+ void OnDestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
int client_id,
int32 sync_point);
+ void OnRelinquishResources();
+ void OnResourcesRelinquished();
+
+ void OnUpdateValueState(int client_id,
+ unsigned int target,
+ const gpu::ValueState& state);
+
void OnLoseAllContexts();
+ void CheckRelinquishGpuResources();
- scoped_refptr<base::MessageLoopProxy> io_message_loop_;
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
base::WaitableEvent* shutdown_event_;
// Used to send and receive IPC messages from the browser process.
@@ -148,15 +150,15 @@ class GpuChannelManager : public IPC::Listener,
scoped_refptr<gfx::GLShareGroup> share_group_;
scoped_refptr<gpu::gles2::MailboxManager> mailbox_manager_;
GpuMemoryManager gpu_memory_manager_;
- GpuEventsDispatcher gpu_devtools_events_dispatcher_;
GpuWatchdog* watchdog_;
- scoped_refptr<SyncPointManager> sync_point_manager_;
+ scoped_refptr<gpu::SyncPointManager> sync_point_manager_;
scoped_ptr<gpu::gles2::ProgramCache> program_cache_;
scoped_refptr<gpu::gles2::ShaderTranslatorCache> shader_translator_cache_;
scoped_refptr<gfx::GLSurface> default_offscreen_surface_;
scoped_ptr<GpuMemoryBufferFactory> gpu_memory_buffer_factory_;
IPC::SyncChannel* channel_;
scoped_refptr<IPC::MessageFilter> filter_;
+ bool relinquish_resources_pending_;
// Member variables should appear before the WeakPtrFactory, to ensure
// that any WeakPtrs to Controller are invalidated before its members
diff --git a/chromium/content/common/gpu/gpu_channel_manager_unittest.cc b/chromium/content/common/gpu/gpu_channel_manager_unittest.cc
new file mode 100644
index 00000000000..2388a2e984b
--- /dev/null
+++ b/chromium/content/common/gpu/gpu_channel_manager_unittest.cc
@@ -0,0 +1,223 @@
+// 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/run_loop.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/test/test_simple_task_runner.h"
+#include "content/common/gpu/gpu_channel.h"
+#include "content/common/gpu/gpu_channel_manager.h"
+#include "content/common/gpu/gpu_messages.h"
+#include "content/common/message_router.h"
+#include "gpu/command_buffer/common/value_state.h"
+#include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/command_buffer/service/valuebuffer_manager.h"
+#include "ipc/ipc_sync_channel.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::WaitableEvent;
+using gpu::gles2::ValuebufferManager;
+using gpu::ValueState;
+
+namespace IPC {
+
+class SimpleWorker : public Listener, public Sender {
+ public:
+ SimpleWorker(Channel::Mode mode, const std::string& thread_name)
+ : mode_(mode),
+ ipc_thread_((thread_name + "_ipc").c_str()),
+ shutdown_event_(true, false) {
+ }
+
+ ~SimpleWorker() override {
+ }
+
+ void AddRef() { }
+ void Release() { }
+ bool Send(Message* msg) override { return channel_->Send(msg); }
+
+ virtual void Start() {
+ StartThread(&ipc_thread_, base::MessageLoop::TYPE_IO);
+ channel_.reset(CreateChannel());
+ }
+
+ virtual void Shutdown() {
+ WaitableEvent ipc_done(false, false);
+ ipc_thread_.task_runner()->PostTask(
+ FROM_HERE, base::Bind(&SimpleWorker::OnShutdown, this, &ipc_done));
+
+ channel_.reset();
+
+ ipc_done.Wait();
+ ipc_thread_.Stop();
+ }
+
+ protected:
+ SyncChannel* CreateChannel() {
+ scoped_ptr<SyncChannel> channel = SyncChannel::Create(
+ channel_name_, mode_, this, ipc_thread_.task_runner().get(), true,
+ &shutdown_event_);
+ return channel.release();
+ }
+
+ void OnShutdown(WaitableEvent* ipc_event) {
+ base::RunLoop().RunUntilIdle();
+ ipc_event->Signal();
+ }
+
+ const base::Thread& ipc_thread() const { return ipc_thread_; }
+
+ WaitableEvent* shutdown_event() { return &shutdown_event_; }
+
+ SyncChannel* channel() { return channel_.get(); }
+
+ private:
+ bool OnMessageReceived(const Message& message) override { return false; }
+
+ void StartThread(base::Thread* thread, base::MessageLoop::Type type) {
+ base::Thread::Options options;
+ options.message_loop_type = type;
+ thread->StartWithOptions(options);
+ }
+
+ std::string channel_name_;
+ Channel::Mode mode_;
+ scoped_ptr<SyncChannel> channel_;
+ base::Thread ipc_thread_;
+
+ base::WaitableEvent shutdown_event_;
+
+ DISALLOW_COPY_AND_ASSIGN(SimpleWorker);
+};
+
+class SimpleServer : public SimpleWorker {
+ public:
+ explicit SimpleServer()
+ : SimpleWorker(Channel::MODE_SERVER, "simpler_server") { }
+};
+
+} // namespace IPC
+
+namespace content {
+
+class SimpleGpuClient : public IPC::SimpleWorker {
+ public:
+ SimpleGpuClient()
+ : IPC::SimpleWorker(IPC::Channel::MODE_CLIENT, "simple_client"),
+ router_(this) {
+ }
+
+ void Start() override {
+ IPC::SimpleWorker::Start();
+ gpu_channel_manager_.reset(
+ new GpuChannelManager(&router_, NULL, ipc_thread().task_runner().get(),
+ shutdown_event(), channel()));
+ }
+
+ void Shutdown() override {
+ gpu_channel_manager_.reset();
+ IPC::SimpleWorker::Shutdown();
+ }
+
+ GpuChannelManager* gpu_channel_manager() {
+ return gpu_channel_manager_.get();
+ }
+
+ private:
+ class SimpleMessageRouter : public MessageRouter {
+ public:
+ explicit SimpleMessageRouter(IPC::Sender* sender)
+ : sender_(sender) {
+ }
+
+ bool Send(IPC::Message* msg) override { return sender_->Send(msg); }
+
+ private:
+ IPC::Sender* const sender_;
+ };
+
+ SimpleMessageRouter router_;
+
+ scoped_ptr<GpuChannelManager> gpu_channel_manager_;
+};
+
+class GpuChannelManagerTest : public testing::Test {
+ public:
+ GpuChannelManagerTest() {}
+
+ void SetUp() override {
+ simple_client_.reset(new SimpleGpuClient());
+ simple_server_.reset(new IPC::SimpleServer());
+ simple_server_->Start();
+ simple_client_->Start();
+ }
+
+ void TearDown() override {
+ simple_client_->Shutdown();
+ simple_server_->Shutdown();
+ }
+
+ protected:
+ scoped_ptr<SimpleGpuClient> simple_client_;
+ scoped_ptr<IPC::SimpleServer> simple_server_;
+
+ private:
+ base::MessageLoop message_loop_;
+};
+
+TEST_F(GpuChannelManagerTest, SecureValueStateForwarding) {
+ const int kClientId1 = 111;
+ const int kClientId2 = 222;
+ ValueState value_state1;
+ value_state1.int_value[0] = 1111;
+ value_state1.int_value[1] = 0;
+ value_state1.int_value[2] = 0;
+ value_state1.int_value[3] = 0;
+ ValueState value_state2;
+ value_state2.int_value[0] = 3333;
+ value_state2.int_value[1] = 0;
+ value_state2.int_value[2] = 0;
+ value_state2.int_value[3] = 0;
+
+ ASSERT_TRUE(simple_client_->gpu_channel_manager() != NULL);
+
+ // Initialize gpu channels
+ simple_client_->gpu_channel_manager()->OnMessageReceived(
+ GpuMsg_EstablishChannel(kClientId1, false, false));
+ GpuChannel *channel1 =
+ simple_client_->gpu_channel_manager()->LookupChannel(kClientId1);
+ simple_client_->gpu_channel_manager()->OnMessageReceived(
+ GpuMsg_EstablishChannel(kClientId2, false, false));
+ GpuChannel *channel2 =
+ simple_client_->gpu_channel_manager()->LookupChannel(kClientId2);
+ ASSERT_TRUE(channel1 != NULL);
+ ASSERT_TRUE(channel2 != NULL);
+ ASSERT_NE(channel1, channel2);
+
+ // Make sure value states are only accessible by proper channels
+ simple_client_->gpu_channel_manager()->OnMessageReceived(
+ GpuMsg_UpdateValueState(
+ kClientId1, GL_MOUSE_POSITION_CHROMIUM, value_state1));
+ simple_client_->gpu_channel_manager()->OnMessageReceived(
+ GpuMsg_UpdateValueState(
+ kClientId2, GL_MOUSE_POSITION_CHROMIUM, value_state2));
+
+ const gpu::ValueStateMap* pending_value_buffer_state1 =
+ channel1->pending_valuebuffer_state();
+ const gpu::ValueStateMap* pending_value_buffer_state2 =
+ channel2->pending_valuebuffer_state();
+ ASSERT_NE(pending_value_buffer_state1, pending_value_buffer_state2);
+
+ const ValueState* state1 =
+ pending_value_buffer_state1->GetState(GL_MOUSE_POSITION_CHROMIUM);
+ const ValueState* state2 =
+ pending_value_buffer_state2->GetState(GL_MOUSE_POSITION_CHROMIUM);
+ ASSERT_NE(state1, state2);
+
+ ASSERT_EQ(state1->int_value[0], value_state1.int_value[0]);
+ ASSERT_EQ(state2->int_value[0], value_state2.int_value[0]);
+ ASSERT_NE(state1->int_value[0], state2->int_value[0]);
+}
+
+} // namespace content
diff --git a/chromium/content/common/gpu/gpu_command_buffer_stub.cc b/chromium/content/common/gpu/gpu_command_buffer_stub.cc
index 18a666dcd9f..6e541ab4645 100644
--- a/chromium/content/common/gpu/gpu_command_buffer_stub.cc
+++ b/chromium/content/common/gpu/gpu_command_buffer_stub.cc
@@ -5,17 +5,15 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/command_line.h"
-#include "base/debug/trace_event.h"
#include "base/hash.h"
#include "base/json/json_writer.h"
#include "base/memory/shared_memory.h"
#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
-#include "content/common/gpu/devtools_gpu_instrumentation.h"
#include "content/common/gpu/gpu_channel.h"
#include "content/common/gpu/gpu_channel_manager.h"
#include "content/common/gpu/gpu_command_buffer_stub.h"
-#include "content/common/gpu/gpu_memory_buffer_factory.h"
#include "content/common/gpu/gpu_memory_manager.h"
#include "content/common/gpu/gpu_memory_tracking.h"
#include "content/common/gpu/gpu_messages.h"
@@ -23,8 +21,8 @@
#include "content/common/gpu/image_transport_surface.h"
#include "content/common/gpu/media/gpu_video_decode_accelerator.h"
#include "content/common/gpu/media/gpu_video_encode_accelerator.h"
-#include "content/common/gpu/sync_point_manager.h"
#include "content/public/common/content_client.h"
+#include "content/public/common/content_switches.h"
#include "gpu/command_buffer/common/constants.h"
#include "gpu/command_buffer/common/gles2_cmd_utils.h"
#include "gpu/command_buffer/common/mailbox.h"
@@ -36,6 +34,8 @@
#include "gpu/command_buffer/service/mailbox_manager.h"
#include "gpu/command_buffer/service/memory_tracking.h"
#include "gpu/command_buffer/service/query_manager.h"
+#include "gpu/command_buffer/service/sync_point_manager.h"
+#include "gpu/command_buffer/service/valuebuffer_manager.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_switches.h"
@@ -112,10 +112,10 @@ const int64 kHandleMoreWorkPeriodBusyMs = 1;
// Prevents idle work from being starved.
const int64 kMaxTimeSinceIdleMs = 10;
-class DevToolsChannelData : public base::debug::ConvertableToTraceFormat {
+class DevToolsChannelData : public base::trace_event::ConvertableToTraceFormat {
public:
- static scoped_refptr<base::debug::ConvertableToTraceFormat> CreateForChannel(
- GpuChannel* channel);
+ static scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+ CreateForChannel(GpuChannel* channel);
void AppendAsTraceFormat(std::string* out) const override {
std::string tmp;
@@ -130,7 +130,7 @@ class DevToolsChannelData : public base::debug::ConvertableToTraceFormat {
DISALLOW_COPY_AND_ASSIGN(DevToolsChannelData);
};
-scoped_refptr<base::debug::ConvertableToTraceFormat>
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
DevToolsChannelData::CreateForChannel(GpuChannel* channel) {
scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue);
res->SetInteger("renderer_pid", channel->renderer_pid());
@@ -149,6 +149,8 @@ GpuCommandBufferStub::GpuCommandBufferStub(
GpuCommandBufferStub* share_group,
const gfx::GLSurfaceHandle& handle,
gpu::gles2::MailboxManager* mailbox_manager,
+ gpu::gles2::SubscriptionRefSet* subscription_ref_set,
+ gpu::ValueStateMap* pending_valuebuffer_state,
const gfx::Size& size,
const gpu::gles2::DisallowedFeatures& disallowed_features,
const std::vector<int32>& attribs,
@@ -193,11 +195,21 @@ GpuCommandBufferStub::GpuCommandBufferStub(
new GpuCommandBufferMemoryTracker(channel),
channel_->gpu_channel_manager()->shader_translator_cache(),
NULL,
+ subscription_ref_set,
+ pending_valuebuffer_state,
attrib_parser.bind_generates_resource);
}
use_virtualized_gl_context_ |=
context_group_->feature_info()->workarounds().use_virtualized_gl_contexts;
+
+ bool is_offscreen = surface_id_ == 0;
+ if (is_offscreen && initial_size_.IsEmpty()) {
+ // If we're an offscreen surface with zero width and/or height, set to a
+ // non-zero size so that we have a complete framebuffer for operations like
+ // glClear.
+ initial_size_ = gfx::Size(1, 1);
+ }
}
GpuCommandBufferStub::~GpuCommandBufferStub() {
@@ -216,9 +228,6 @@ bool GpuCommandBufferStub::OnMessageReceived(const IPC::Message& message) {
"GPUTask",
"data",
DevToolsChannelData::CreateForChannel(channel()));
- // TODO(yurys): remove devtools_gpu_instrumentation call once DevTools
- // Timeline migrates to tracing crbug.com/361045.
- devtools_gpu_instrumentation::ScopedGpuTask task(channel());
FastSetActiveURL(active_url_, active_url_hash_);
bool have_context = false;
@@ -227,10 +236,15 @@ bool GpuCommandBufferStub::OnMessageReceived(const IPC::Message& message) {
// handler can assume that the context is current (not necessary for
// RetireSyncPoint or WaitSyncPoint).
if (decoder_.get() &&
+ message.type() != GpuCommandBufferMsg_SetGetBuffer::ID &&
message.type() != GpuCommandBufferMsg_WaitForTokenInRange::ID &&
message.type() != GpuCommandBufferMsg_WaitForGetOffsetInRange::ID &&
+ message.type() != GpuCommandBufferMsg_RegisterTransferBuffer::ID &&
+ message.type() != GpuCommandBufferMsg_DestroyTransferBuffer::ID &&
message.type() != GpuCommandBufferMsg_RetireSyncPoint::ID &&
- message.type() != GpuCommandBufferMsg_SignalSyncPoint::ID) {
+ message.type() != GpuCommandBufferMsg_SignalSyncPoint::ID &&
+ message.type() !=
+ GpuCommandBufferMsg_SetClientHasMemoryAllocationChangedCallback::ID) {
if (!MakeCurrent())
return false;
have_context = true;
@@ -309,30 +323,26 @@ void GpuCommandBufferStub::PollWork() {
return;
if (scheduler_) {
- bool fences_complete = scheduler_->PollUnscheduleFences();
- // Perform idle work if all fences are complete.
- if (fences_complete) {
- uint64 current_messages_processed =
- channel()->gpu_channel_manager()->MessagesProcessed();
- // We're idle when no messages were processed or scheduled.
- bool is_idle =
- (previous_messages_processed_ == current_messages_processed) &&
- !channel()->gpu_channel_manager()->HandleMessagesScheduled();
- if (!is_idle && !last_idle_time_.is_null()) {
- base::TimeDelta time_since_idle = base::TimeTicks::Now() -
- last_idle_time_;
- base::TimeDelta max_time_since_idle =
- base::TimeDelta::FromMilliseconds(kMaxTimeSinceIdleMs);
-
- // Force idle when it's been too long since last time we were idle.
- if (time_since_idle > max_time_since_idle)
- is_idle = true;
- }
+ uint64 current_messages_processed =
+ channel()->gpu_channel_manager()->MessagesProcessed();
+ // We're idle when no messages were processed or scheduled.
+ bool is_idle =
+ (previous_messages_processed_ == current_messages_processed) &&
+ !channel()->gpu_channel_manager()->HandleMessagesScheduled();
+ if (!is_idle && !last_idle_time_.is_null()) {
+ base::TimeDelta time_since_idle =
+ base::TimeTicks::Now() - last_idle_time_;
+ base::TimeDelta max_time_since_idle =
+ base::TimeDelta::FromMilliseconds(kMaxTimeSinceIdleMs);
+
+ // Force idle when it's been too long since last time we were idle.
+ if (time_since_idle > max_time_since_idle)
+ is_idle = true;
+ }
- if (is_idle) {
- last_idle_time_ = base::TimeTicks::Now();
- scheduler_->PerformIdleWork();
- }
+ if (is_idle) {
+ last_idle_time_ = base::TimeTicks::Now();
+ scheduler_->PerformIdleWork();
}
}
ScheduleDelayedWork(kHandleMoreWorkPeriodBusyMs);
@@ -376,9 +386,8 @@ void GpuCommandBufferStub::ScheduleDelayedWork(int64 delay) {
delay = 0;
}
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&GpuCommandBufferStub::PollWork, AsWeakPtr()),
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, base::Bind(&GpuCommandBufferStub::PollWork, AsWeakPtr()),
base::TimeDelta::FromMilliseconds(delay));
}
@@ -420,9 +429,11 @@ void GpuCommandBufferStub::Destroy() {
scheduler_.reset();
bool have_context = false;
- if (decoder_ && command_buffer_ &&
- command_buffer_->GetLastState().error != gpu::error::kLostContext)
- have_context = decoder_->MakeCurrent();
+ if (decoder_ && decoder_->GetGLContext()) {
+ // Try to make the context current regardless of whether it was lost, so we
+ // don't leak resources.
+ have_context = decoder_->GetGLContext()->MakeCurrent(surface_.get());
+ }
FOR_EACH_OBSERVER(DestructionObserver,
destruction_observers_,
OnWillDestroyStub());
@@ -462,6 +473,13 @@ void GpuCommandBufferStub::OnInitialize(
decoder_.reset(::gpu::gles2::GLES2Decoder::Create(context_group_.get()));
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSingleProcess) &&
+ !base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kInProcessGPU)) {
+ decoder_->SetAllowExit(true);
+ }
+
scheduler_.reset(new gpu::GpuScheduler(command_buffer_.get(),
decoder_.get(),
decoder_.get()));
@@ -566,8 +584,8 @@ void GpuCommandBufferStub::OnInitialize(
return;
}
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableGPUServiceLogging)) {
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableGPUServiceLogging)) {
decoder_->set_log_commands(true);
}
@@ -670,7 +688,7 @@ void GpuCommandBufferStub::OnParseError() {
DCHECK(command_buffer_.get());
gpu::CommandBuffer::State state = command_buffer_->GetLastState();
IPC::Message* msg = new GpuCommandBufferMsg_Destroyed(
- route_id_, state.context_lost_reason);
+ route_id_, state.context_lost_reason, state.error);
msg->set_unblock(true);
Send(msg);
@@ -820,7 +838,7 @@ void GpuCommandBufferStub::OnCreateVideoDecoder(
IPC::Message* reply_message) {
TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnCreateVideoDecoder");
GpuVideoDecodeAccelerator* decoder = new GpuVideoDecodeAccelerator(
- decoder_route_id, this, channel_->io_message_loop());
+ decoder_route_id, this, channel_->io_task_runner());
decoder->Initialize(profile, reply_message);
// decoder is registered as a DestructionObserver of this stub and will
// self-delete during destruction of this stub.
@@ -956,12 +974,26 @@ void GpuCommandBufferStub::OnCreateImage(int32 id,
return;
}
- GpuChannelManager* manager = channel_->gpu_channel_manager();
- scoped_refptr<gfx::GLImage> image =
- manager->gpu_memory_buffer_factory()
- ->AsImageFactory()
- ->CreateImageForGpuMemoryBuffer(
- handle, size, format, internalformat, channel()->client_id());
+ if (!gpu::ImageFactory::IsGpuMemoryBufferFormatSupported(
+ format, decoder_->GetCapabilities())) {
+ LOG(ERROR) << "Format is not supported.";
+ return;
+ }
+
+ if (!gpu::ImageFactory::IsImageSizeValidForGpuMemoryBufferFormat(size,
+ format)) {
+ LOG(ERROR) << "Invalid image size for format.";
+ return;
+ }
+
+ if (!gpu::ImageFactory::IsImageFormatCompatibleWithGpuMemoryBufferFormat(
+ internalformat, format)) {
+ LOG(ERROR) << "Incompatible image format.";
+ return;
+ }
+
+ scoped_refptr<gfx::GLImage> image = channel()->CreateImageForGpuMemoryBuffer(
+ handle, size, format, internalformat);
if (!image.get())
return;
@@ -1074,7 +1106,7 @@ void GpuCommandBufferStub::MarkContextLost() {
command_buffer_->SetContextLostReason(gpu::error::kUnknown);
if (decoder_)
- decoder_->LoseContext(GL_UNKNOWN_CONTEXT_RESET_ARB);
+ decoder_->MarkContextLost(gpu::error::kUnknown);
command_buffer_->SetParseError(gpu::error::kLostContext);
}
@@ -1082,9 +1114,15 @@ uint64 GpuCommandBufferStub::GetMemoryUsage() const {
return GetMemoryManager()->GetClientMemoryUsage(this);
}
-void GpuCommandBufferStub::SwapBuffersCompleted(
+void GpuCommandBufferStub::SendSwapBuffersCompleted(
const std::vector<ui::LatencyInfo>& latency_info) {
Send(new GpuCommandBufferMsg_SwapBuffersCompleted(route_id_, latency_info));
}
+void GpuCommandBufferStub::SendUpdateVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval) {
+ Send(new GpuCommandBufferMsg_UpdateVSyncParameters(route_id_, timebase,
+ interval));
+}
+
} // namespace content
diff --git a/chromium/content/common/gpu/gpu_command_buffer_stub.h b/chromium/content/common/gpu/gpu_command_buffer_stub.h
index 6f69a2a3d86..c9e215c7af0 100644
--- a/chromium/content/common/gpu/gpu_command_buffer_stub.h
+++ b/chromium/content/common/gpu/gpu_command_buffer_stub.h
@@ -24,17 +24,19 @@
#include "ipc/ipc_sender.h"
#include "media/base/video_decoder_config.h"
#include "ui/events/latency_info.h"
+#include "ui/gfx/geometry/size.h"
#include "ui/gfx/gpu_memory_buffer.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/size.h"
#include "ui/gl/gl_surface.h"
#include "ui/gl/gpu_preference.h"
#include "url/gurl.h"
namespace gpu {
struct Mailbox;
+class ValueStateMap;
namespace gles2 {
class MailboxManager;
+class SubscriptionRefSet;
}
}
@@ -69,6 +71,8 @@ class GpuCommandBufferStub
GpuCommandBufferStub* share_group,
const gfx::GLSurfaceHandle& handle,
gpu::gles2::MailboxManager* mailbox_manager,
+ gpu::gles2::SubscriptionRefSet* subscription_ref_set,
+ gpu::ValueStateMap* pending_valuebuffer_state,
const gfx::Size& size,
const gpu::gles2::DisallowedFeatures& disallowed_features,
const std::vector<int32>& attribs,
@@ -143,7 +147,10 @@ class GpuCommandBufferStub
uint64 GetMemoryUsage() const;
- void SwapBuffersCompleted(const std::vector<ui::LatencyInfo>& latency_info);
+ void SendSwapBuffersCompleted(
+ const std::vector<ui::LatencyInfo>& latency_info);
+ void SendUpdateVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval);
private:
GpuMemoryManager* GetMemoryManager() const;
diff --git a/chromium/content/common/gpu/gpu_memory_buffer_factory.cc b/chromium/content/common/gpu/gpu_memory_buffer_factory.cc
new file mode 100644
index 00000000000..019bdd8dbcc
--- /dev/null
+++ b/chromium/content/common/gpu/gpu_memory_buffer_factory.cc
@@ -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.
+
+#include "content/common/gpu/gpu_memory_buffer_factory.h"
+
+#include "base/logging.h"
+#include "content/common/gpu/gpu_memory_buffer_factory_shared_memory.h"
+
+#if defined(OS_MACOSX)
+#include "content/common/gpu/gpu_memory_buffer_factory_io_surface.h"
+#endif
+
+#if defined(OS_ANDROID)
+#include "content/common/gpu/gpu_memory_buffer_factory_surface_texture.h"
+#endif
+
+#if defined(USE_OZONE)
+#include "content/common/gpu/gpu_memory_buffer_factory_ozone_native_buffer.h"
+#endif
+
+namespace content {
+
+// static
+void GpuMemoryBufferFactory::GetSupportedTypes(
+ std::vector<gfx::GpuMemoryBufferType>* types) {
+ const gfx::GpuMemoryBufferType supported_types[] = {
+#if defined(OS_MACOSX)
+ gfx::IO_SURFACE_BUFFER,
+#endif
+#if defined(OS_ANDROID)
+ gfx::SURFACE_TEXTURE_BUFFER,
+#endif
+#if defined(USE_OZONE)
+ gfx::OZONE_NATIVE_BUFFER,
+#endif
+ gfx::SHARED_MEMORY_BUFFER
+ };
+ types->assign(supported_types, supported_types + arraysize(supported_types));
+}
+
+// static
+scoped_ptr<GpuMemoryBufferFactory> GpuMemoryBufferFactory::Create(
+ gfx::GpuMemoryBufferType type) {
+ switch (type) {
+ case gfx::SHARED_MEMORY_BUFFER:
+ return make_scoped_ptr(new GpuMemoryBufferFactorySharedMemory);
+#if defined(OS_MACOSX)
+ case gfx::IO_SURFACE_BUFFER:
+ return make_scoped_ptr(new GpuMemoryBufferFactoryIOSurface);
+#endif
+#if defined(OS_ANDROID)
+ case gfx::SURFACE_TEXTURE_BUFFER:
+ return make_scoped_ptr(new GpuMemoryBufferFactorySurfaceTexture);
+#endif
+#if defined(USE_OZONE)
+ case gfx::OZONE_NATIVE_BUFFER:
+ return make_scoped_ptr(new GpuMemoryBufferFactoryOzoneNativeBuffer);
+#endif
+ default:
+ NOTREACHED();
+ return scoped_ptr<GpuMemoryBufferFactory>();
+ }
+}
+
+} // namespace content
diff --git a/chromium/content/common/gpu/gpu_memory_buffer_factory.h b/chromium/content/common/gpu/gpu_memory_buffer_factory.h
index 5dd2203f268..5eb0dfce1a9 100644
--- a/chromium/content/common/gpu/gpu_memory_buffer_factory.h
+++ b/chromium/content/common/gpu/gpu_memory_buffer_factory.h
@@ -5,10 +5,14 @@
#ifndef CONTENT_COMMON_GPU_GPU_MEMORY_BUFFER_FACTORY_H_
#define CONTENT_COMMON_GPU_GPU_MEMORY_BUFFER_FACTORY_H_
+#include <vector>
+
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+#include "content/common/content_export.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/gpu_memory_buffer.h"
+#include "ui/gfx/native_widget_types.h"
namespace gfx {
class GLImage;
@@ -20,32 +24,48 @@ class ImageFactory;
namespace content {
-class GpuMemoryBufferFactory {
+class CONTENT_EXPORT GpuMemoryBufferFactory {
public:
- GpuMemoryBufferFactory() {}
+ struct Configuration {
+ gfx::GpuMemoryBuffer::Format format;
+ gfx::GpuMemoryBuffer::Usage usage;
+ };
+
virtual ~GpuMemoryBufferFactory() {}
- // Creates a new platform specific factory instance.
- static scoped_ptr<GpuMemoryBufferFactory> Create();
+ // Gets system supported GPU memory buffer factory types. Preferred type at
+ // the front of vector.
+ static void GetSupportedTypes(std::vector<gfx::GpuMemoryBufferType>* types);
+
+ // Creates a new factory instance for |type|.
+ static scoped_ptr<GpuMemoryBufferFactory> Create(
+ gfx::GpuMemoryBufferType type);
- // Creates a GPU memory buffer instance of |type|. A valid handle is
- // returned on success.
+ // Gets supported format/usage configurations.
+ virtual void GetSupportedGpuMemoryBufferConfigurations(
+ std::vector<Configuration>* configurations) = 0;
+
+ // Creates a new GPU memory buffer instance. A valid handle is returned on
+ // success. It can be called on any thread.
virtual gfx::GpuMemoryBufferHandle CreateGpuMemoryBuffer(
- gfx::GpuMemoryBufferType type,
gfx::GpuMemoryBufferId id,
const gfx::Size& size,
gfx::GpuMemoryBuffer::Format format,
gfx::GpuMemoryBuffer::Usage usage,
- int client_id) = 0;
+ int client_id,
+ gfx::PluginWindowHandle surface_handle) = 0;
// Destroys GPU memory buffer identified by |id|.
- virtual void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferType type,
- gfx::GpuMemoryBufferId id,
+ // It can be called on any thread.
+ virtual void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
int client_id) = 0;
// Type-checking downcast routine.
virtual gpu::ImageFactory* AsImageFactory() = 0;
+ protected:
+ GpuMemoryBufferFactory() {}
+
private:
DISALLOW_COPY_AND_ASSIGN(GpuMemoryBufferFactory);
};
diff --git a/chromium/content/common/gpu/gpu_memory_buffer_factory_android.cc b/chromium/content/common/gpu/gpu_memory_buffer_factory_android.cc
deleted file mode 100644
index 1fce6b67615..00000000000
--- a/chromium/content/common/gpu/gpu_memory_buffer_factory_android.cc
+++ /dev/null
@@ -1,88 +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/common/gpu/gpu_memory_buffer_factory.h"
-
-#include "base/logging.h"
-#include "content/common/gpu/gpu_memory_buffer_factory_surface_texture.h"
-#include "gpu/command_buffer/service/image_factory.h"
-#include "ui/gl/gl_image.h"
-#include "ui/gl/gl_image_shared_memory.h"
-
-namespace content {
-namespace {
-
-class GpuMemoryBufferFactoryImpl : public GpuMemoryBufferFactory,
- public gpu::ImageFactory {
- public:
- // Overridden from GpuMemoryBufferFactory:
- virtual gfx::GpuMemoryBufferHandle CreateGpuMemoryBuffer(
- gfx::GpuMemoryBufferType type,
- gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- gfx::GpuMemoryBuffer::Format format,
- gfx::GpuMemoryBuffer::Usage usage,
- int client_id) override {
- switch (type) {
- case gfx::SURFACE_TEXTURE_BUFFER:
- return surface_texture_factory_.CreateGpuMemoryBuffer(
- id, size, format, client_id);
- default:
- NOTREACHED();
- return gfx::GpuMemoryBufferHandle();
- }
- }
- virtual void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferType type,
- gfx::GpuMemoryBufferId id,
- int client_id) override {
- switch (type) {
- case gfx::SURFACE_TEXTURE_BUFFER:
- surface_texture_factory_.DestroyGpuMemoryBuffer(id, client_id);
- break;
- default:
- NOTREACHED();
- break;
- }
- }
- virtual gpu::ImageFactory* AsImageFactory() override { return this; }
-
- // Overridden from gpu::ImageFactory:
- virtual scoped_refptr<gfx::GLImage> CreateImageForGpuMemoryBuffer(
- const gfx::GpuMemoryBufferHandle& handle,
- const gfx::Size& size,
- gfx::GpuMemoryBuffer::Format format,
- unsigned internalformat,
- int client_id) override {
- switch (handle.type) {
- case gfx::SHARED_MEMORY_BUFFER: {
- scoped_refptr<gfx::GLImageSharedMemory> image(
- new gfx::GLImageSharedMemory(size, internalformat));
- if (!image->Initialize(handle, format))
- return NULL;
-
- return image;
- }
- case gfx::SURFACE_TEXTURE_BUFFER: {
- return surface_texture_factory_.CreateImageForGpuMemoryBuffer(
- handle.id, size, internalformat, client_id);
- }
- default:
- NOTREACHED();
- return scoped_refptr<gfx::GLImage>();
- }
- }
-
- private:
- GpuMemoryBufferFactorySurfaceTexture surface_texture_factory_;
-};
-
-} // namespace
-
-// static
-scoped_ptr<GpuMemoryBufferFactory> GpuMemoryBufferFactory::Create() {
- return make_scoped_ptr<GpuMemoryBufferFactory>(
- new GpuMemoryBufferFactoryImpl);
-}
-
-} // namespace content
diff --git a/chromium/content/common/gpu/gpu_memory_buffer_factory_io_surface.cc b/chromium/content/common/gpu/gpu_memory_buffer_factory_io_surface.cc
index 182f82655d9..1d4eeedcfbd 100644
--- a/chromium/content/common/gpu/gpu_memory_buffer_factory_io_surface.cc
+++ b/chromium/content/common/gpu/gpu_memory_buffer_factory_io_surface.cc
@@ -6,7 +6,7 @@
#include <CoreFoundation/CoreFoundation.h>
-#include "content/common/gpu/client/gpu_memory_buffer_impl_io_surface.h"
+#include "base/logging.h"
#include "ui/gl/gl_image_io_surface.h"
namespace content {
@@ -27,6 +27,54 @@ void AddIntegerValue(CFMutableDictionaryRef dictionary,
CFDictionaryAddValue(dictionary, key, number.get());
}
+int32 BytesPerPixel(gfx::GpuMemoryBuffer::Format format) {
+ switch (format) {
+ case gfx::GpuMemoryBuffer::R_8:
+ return 1;
+ case gfx::GpuMemoryBuffer::BGRA_8888:
+ return 4;
+ case gfx::GpuMemoryBuffer::ATC:
+ case gfx::GpuMemoryBuffer::ATCIA:
+ case gfx::GpuMemoryBuffer::DXT1:
+ case gfx::GpuMemoryBuffer::DXT5:
+ case gfx::GpuMemoryBuffer::ETC1:
+ case gfx::GpuMemoryBuffer::RGBA_8888:
+ case gfx::GpuMemoryBuffer::RGBX_8888:
+ case gfx::GpuMemoryBuffer::YUV_420:
+ NOTREACHED();
+ return 0;
+ }
+
+ NOTREACHED();
+ return 0;
+}
+
+int32 PixelFormat(gfx::GpuMemoryBuffer::Format format) {
+ switch (format) {
+ case gfx::GpuMemoryBuffer::R_8:
+ return 'L008';
+ case gfx::GpuMemoryBuffer::BGRA_8888:
+ return 'BGRA';
+ case gfx::GpuMemoryBuffer::ATC:
+ case gfx::GpuMemoryBuffer::ATCIA:
+ case gfx::GpuMemoryBuffer::DXT1:
+ case gfx::GpuMemoryBuffer::DXT5:
+ case gfx::GpuMemoryBuffer::ETC1:
+ case gfx::GpuMemoryBuffer::RGBA_8888:
+ case gfx::GpuMemoryBuffer::RGBX_8888:
+ case gfx::GpuMemoryBuffer::YUV_420:
+ NOTREACHED();
+ return 0;
+ }
+
+ NOTREACHED();
+ return 0;
+}
+
+const GpuMemoryBufferFactory::Configuration kSupportedConfigurations[] = {
+ {gfx::GpuMemoryBuffer::R_8, gfx::GpuMemoryBuffer::MAP},
+ {gfx::GpuMemoryBuffer::BGRA_8888, gfx::GpuMemoryBuffer::MAP}};
+
} // namespace
GpuMemoryBufferFactoryIOSurface::GpuMemoryBufferFactoryIOSurface() {
@@ -35,12 +83,33 @@ GpuMemoryBufferFactoryIOSurface::GpuMemoryBufferFactoryIOSurface() {
GpuMemoryBufferFactoryIOSurface::~GpuMemoryBufferFactoryIOSurface() {
}
+// static
+bool GpuMemoryBufferFactoryIOSurface::IsGpuMemoryBufferConfigurationSupported(
+ gfx::GpuMemoryBuffer::Format format,
+ gfx::GpuMemoryBuffer::Usage usage) {
+ for (auto& configuration : kSupportedConfigurations) {
+ if (configuration.format == format && configuration.usage == usage)
+ return true;
+ }
+
+ return false;
+}
+
+void GpuMemoryBufferFactoryIOSurface::GetSupportedGpuMemoryBufferConfigurations(
+ std::vector<Configuration>* configurations) {
+ configurations->assign(
+ kSupportedConfigurations,
+ kSupportedConfigurations + arraysize(kSupportedConfigurations));
+}
+
gfx::GpuMemoryBufferHandle
GpuMemoryBufferFactoryIOSurface::CreateGpuMemoryBuffer(
gfx::GpuMemoryBufferId id,
const gfx::Size& size,
gfx::GpuMemoryBuffer::Format format,
- int client_id) {
+ gfx::GpuMemoryBuffer::Usage usage,
+ int client_id,
+ gfx::PluginWindowHandle surface_handle) {
base::ScopedCFTypeRef<CFMutableDictionaryRef> properties;
properties.reset(CFDictionaryCreateMutable(kCFAllocatorDefault,
0,
@@ -48,12 +117,8 @@ GpuMemoryBufferFactoryIOSurface::CreateGpuMemoryBuffer(
&kCFTypeDictionaryValueCallBacks));
AddIntegerValue(properties, kIOSurfaceWidth, size.width());
AddIntegerValue(properties, kIOSurfaceHeight, size.height());
- AddIntegerValue(properties,
- kIOSurfaceBytesPerElement,
- GpuMemoryBufferImpl::BytesPerPixel(format));
- AddIntegerValue(properties,
- kIOSurfacePixelFormat,
- GpuMemoryBufferImplIOSurface::PixelFormat(format));
+ AddIntegerValue(properties, kIOSurfaceBytesPerElement, BytesPerPixel(format));
+ AddIntegerValue(properties, kIOSurfacePixelFormat, PixelFormat(format));
// TODO(reveman): Remove this when using a mach_port_t to transfer
// IOSurface to browser and renderer process. crbug.com/323304
AddBooleanValue(properties, kIOSurfaceIsGlobal, true);
@@ -62,9 +127,13 @@ GpuMemoryBufferFactoryIOSurface::CreateGpuMemoryBuffer(
if (!io_surface)
return gfx::GpuMemoryBufferHandle();
- IOSurfaceMapKey key(id, client_id);
- DCHECK(io_surfaces_.find(key) == io_surfaces_.end());
- io_surfaces_[key] = io_surface;
+ {
+ base::AutoLock lock(io_surfaces_lock_);
+
+ IOSurfaceMapKey key(id, client_id);
+ DCHECK(io_surfaces_.find(key) == io_surfaces_.end());
+ io_surfaces_[key] = io_surface;
+ }
gfx::GpuMemoryBufferHandle handle;
handle.type = gfx::IO_SURFACE_BUFFER;
@@ -76,25 +145,35 @@ GpuMemoryBufferFactoryIOSurface::CreateGpuMemoryBuffer(
void GpuMemoryBufferFactoryIOSurface::DestroyGpuMemoryBuffer(
gfx::GpuMemoryBufferId id,
int client_id) {
+ base::AutoLock lock(io_surfaces_lock_);
+
IOSurfaceMapKey key(id, client_id);
- IOSurfaceMap::iterator it = io_surfaces_.find(key);
- if (it != io_surfaces_.end())
- io_surfaces_.erase(it);
+ DCHECK(io_surfaces_.find(key) != io_surfaces_.end());
+ io_surfaces_.erase(key);
+}
+
+gpu::ImageFactory* GpuMemoryBufferFactoryIOSurface::AsImageFactory() {
+ return this;
}
scoped_refptr<gfx::GLImage>
GpuMemoryBufferFactoryIOSurface::CreateImageForGpuMemoryBuffer(
- gfx::GpuMemoryBufferId id,
+ const gfx::GpuMemoryBufferHandle& handle,
const gfx::Size& size,
gfx::GpuMemoryBuffer::Format format,
+ unsigned internalformat,
int client_id) {
- IOSurfaceMapKey key(id, client_id);
+ base::AutoLock lock(io_surfaces_lock_);
+
+ DCHECK_EQ(handle.type, gfx::IO_SURFACE_BUFFER);
+ IOSurfaceMapKey key(handle.id, client_id);
IOSurfaceMap::iterator it = io_surfaces_.find(key);
if (it == io_surfaces_.end())
return scoped_refptr<gfx::GLImage>();
- scoped_refptr<gfx::GLImageIOSurface> image(new gfx::GLImageIOSurface(size));
- if (!image->Initialize(it->second.get()))
+ scoped_refptr<gfx::GLImageIOSurface> image(
+ new gfx::GLImageIOSurface(size, internalformat));
+ if (!image->Initialize(it->second.get(), format))
return scoped_refptr<gfx::GLImage>();
return image;
diff --git a/chromium/content/common/gpu/gpu_memory_buffer_factory_io_surface.h b/chromium/content/common/gpu/gpu_memory_buffer_factory_io_surface.h
index 1ee16ef582f..eac05adb58a 100644
--- a/chromium/content/common/gpu/gpu_memory_buffer_factory_io_surface.h
+++ b/chromium/content/common/gpu/gpu_memory_buffer_factory_io_surface.h
@@ -10,6 +10,9 @@
#include "base/containers/hash_tables.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/memory/ref_counted.h"
+#include "base/synchronization/lock.h"
+#include "content/common/gpu/gpu_memory_buffer_factory.h"
+#include "gpu/command_buffer/service/image_factory.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/gpu_memory_buffer.h"
@@ -19,34 +22,46 @@ class GLImage;
namespace content {
-class GpuMemoryBufferFactoryIOSurface {
+class GpuMemoryBufferFactoryIOSurface : public GpuMemoryBufferFactory,
+ public gpu::ImageFactory {
public:
GpuMemoryBufferFactoryIOSurface();
- ~GpuMemoryBufferFactoryIOSurface();
+ ~GpuMemoryBufferFactoryIOSurface() override;
- // Creates a IOSurface backed GPU memory buffer with |size| and
- // |internalformat|. A valid handle is returned on success.
+ static bool IsGpuMemoryBufferConfigurationSupported(
+ gfx::GpuMemoryBuffer::Format format,
+ gfx::GpuMemoryBuffer::Usage usage);
+
+ // Overridden from GpuMemoryBufferFactory:
+ void GetSupportedGpuMemoryBufferConfigurations(
+ std::vector<Configuration>* configurations) override;
gfx::GpuMemoryBufferHandle CreateGpuMemoryBuffer(
gfx::GpuMemoryBufferId id,
const gfx::Size& size,
gfx::GpuMemoryBuffer::Format format,
- int client_id);
-
- // Destroy a previously created GPU memory buffer.
- void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id, int client_id);
+ gfx::GpuMemoryBuffer::Usage usage,
+ int client_id,
+ gfx::PluginWindowHandle surface_handle) override;
+ void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
+ int client_id) override;
+ gpu::ImageFactory* AsImageFactory() override;
- // Creates a GLImage instance for a GPU memory buffer.
+ // Overridden from gpu::ImageFactory:
scoped_refptr<gfx::GLImage> CreateImageForGpuMemoryBuffer(
- gfx::GpuMemoryBufferId id,
+ const gfx::GpuMemoryBufferHandle& handle,
const gfx::Size& size,
gfx::GpuMemoryBuffer::Format format,
- int client_id);
+ unsigned internalformat,
+ int client_id) override;
private:
typedef std::pair<int, int> IOSurfaceMapKey;
typedef base::hash_map<IOSurfaceMapKey, base::ScopedCFTypeRef<IOSurfaceRef>>
IOSurfaceMap;
IOSurfaceMap io_surfaces_;
+ base::Lock io_surfaces_lock_;
+
+ DISALLOW_COPY_AND_ASSIGN(GpuMemoryBufferFactoryIOSurface);
};
} // namespace content
diff --git a/chromium/content/common/gpu/gpu_memory_buffer_factory_linux.cc b/chromium/content/common/gpu/gpu_memory_buffer_factory_linux.cc
deleted file mode 100644
index 67465514533..00000000000
--- a/chromium/content/common/gpu/gpu_memory_buffer_factory_linux.cc
+++ /dev/null
@@ -1,67 +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/common/gpu/gpu_memory_buffer_factory.h"
-
-#include "base/logging.h"
-#include "gpu/command_buffer/service/image_factory.h"
-#include "ui/gl/gl_image.h"
-#include "ui/gl/gl_image_shared_memory.h"
-
-namespace content {
-namespace {
-
-class GpuMemoryBufferFactoryImpl : public GpuMemoryBufferFactory,
- public gpu::ImageFactory {
- public:
- // Overridden from GpuMemoryBufferFactory:
- gfx::GpuMemoryBufferHandle CreateGpuMemoryBuffer(
- gfx::GpuMemoryBufferType type,
- gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- gfx::GpuMemoryBuffer::Format format,
- gfx::GpuMemoryBuffer::Usage usage,
- int client_id) override {
- NOTREACHED();
- return gfx::GpuMemoryBufferHandle();
- }
- void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferType type,
- gfx::GpuMemoryBufferId id,
- int client_id) override {
- NOTREACHED();
- }
- gpu::ImageFactory* AsImageFactory() override { return this; }
-
- // Overridden from gpu::ImageFactory:
- scoped_refptr<gfx::GLImage> CreateImageForGpuMemoryBuffer(
- const gfx::GpuMemoryBufferHandle& handle,
- const gfx::Size& size,
- gfx::GpuMemoryBuffer::Format format,
- unsigned internalformat,
- int client_id) override {
- switch (handle.type) {
- case gfx::SHARED_MEMORY_BUFFER: {
- scoped_refptr<gfx::GLImageSharedMemory> image(
- new gfx::GLImageSharedMemory(size, internalformat));
- if (!image->Initialize(handle, format))
- return NULL;
-
- return image;
- }
- default:
- NOTREACHED();
- return scoped_refptr<gfx::GLImage>();
- }
- }
-};
-
-} // namespace
-
-// static
-scoped_ptr<GpuMemoryBufferFactory> GpuMemoryBufferFactory::Create() {
- return make_scoped_ptr<GpuMemoryBufferFactory>(
- new GpuMemoryBufferFactoryImpl);
-}
-
-} // namespace content
diff --git a/chromium/content/common/gpu/gpu_memory_buffer_factory_mac.cc b/chromium/content/common/gpu/gpu_memory_buffer_factory_mac.cc
deleted file mode 100644
index aa04b274b69..00000000000
--- a/chromium/content/common/gpu/gpu_memory_buffer_factory_mac.cc
+++ /dev/null
@@ -1,88 +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/common/gpu/gpu_memory_buffer_factory.h"
-
-#include "base/logging.h"
-#include "content/common/gpu/gpu_memory_buffer_factory_io_surface.h"
-#include "gpu/command_buffer/service/image_factory.h"
-#include "ui/gl/gl_image.h"
-#include "ui/gl/gl_image_shared_memory.h"
-
-namespace content {
-namespace {
-
-class GpuMemoryBufferFactoryImpl : public GpuMemoryBufferFactory,
- public gpu::ImageFactory {
- public:
- // Overridden from GpuMemoryBufferFactory:
- gfx::GpuMemoryBufferHandle CreateGpuMemoryBuffer(
- gfx::GpuMemoryBufferType type,
- gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- gfx::GpuMemoryBuffer::Format format,
- gfx::GpuMemoryBuffer::Usage usage,
- int client_id) override {
- switch (type) {
- case gfx::IO_SURFACE_BUFFER:
- return io_surface_factory_.CreateGpuMemoryBuffer(
- id, size, format, client_id);
- default:
- NOTREACHED();
- return gfx::GpuMemoryBufferHandle();
- }
- }
- void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferType type,
- gfx::GpuMemoryBufferId id,
- int client_id) override {
- switch (type) {
- case gfx::IO_SURFACE_BUFFER:
- io_surface_factory_.DestroyGpuMemoryBuffer(id, client_id);
- break;
- default:
- NOTREACHED();
- break;
- }
- }
- gpu::ImageFactory* AsImageFactory() override { return this; }
-
- // Overridden from gpu::ImageFactory:
- scoped_refptr<gfx::GLImage> CreateImageForGpuMemoryBuffer(
- const gfx::GpuMemoryBufferHandle& handle,
- const gfx::Size& size,
- gfx::GpuMemoryBuffer::Format format,
- unsigned internalformat,
- int client_id) override {
- switch (handle.type) {
- case gfx::SHARED_MEMORY_BUFFER: {
- scoped_refptr<gfx::GLImageSharedMemory> image(
- new gfx::GLImageSharedMemory(size, internalformat));
- if (!image->Initialize(handle, format))
- return NULL;
-
- return image;
- }
- case gfx::IO_SURFACE_BUFFER: {
- return io_surface_factory_.CreateImageForGpuMemoryBuffer(
- handle.id, size, format, client_id);
- }
- default:
- NOTREACHED();
- return scoped_refptr<gfx::GLImage>();
- }
- }
-
- private:
- GpuMemoryBufferFactoryIOSurface io_surface_factory_;
-};
-
-} // namespace
-
-// static
-scoped_ptr<GpuMemoryBufferFactory> GpuMemoryBufferFactory::Create() {
- return make_scoped_ptr<GpuMemoryBufferFactory>(
- new GpuMemoryBufferFactoryImpl);
-}
-
-} // namespace content
diff --git a/chromium/content/common/gpu/gpu_memory_buffer_factory_ozone.cc b/chromium/content/common/gpu/gpu_memory_buffer_factory_ozone.cc
deleted file mode 100644
index f2a296e72b6..00000000000
--- a/chromium/content/common/gpu/gpu_memory_buffer_factory_ozone.cc
+++ /dev/null
@@ -1,94 +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/common/gpu/gpu_memory_buffer_factory.h"
-
-#include "base/logging.h"
-#include "gpu/command_buffer/service/image_factory.h"
-#include "ui/gl/gl_image.h"
-#include "ui/gl/gl_image_shared_memory.h"
-#include "ui/ozone/gpu/gpu_memory_buffer_factory_ozone_native_buffer.h"
-
-namespace content {
-namespace {
-
-class GpuMemoryBufferFactoryImpl : public GpuMemoryBufferFactory,
- public gpu::ImageFactory {
- public:
- // Overridden from GpuMemoryBufferFactory:
- virtual gfx::GpuMemoryBufferHandle CreateGpuMemoryBuffer(
- gfx::GpuMemoryBufferType type,
- gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- gfx::GpuMemoryBuffer::Format format,
- gfx::GpuMemoryBuffer::Usage usage,
- int client_id) override {
- switch (type) {
- case gfx::OZONE_NATIVE_BUFFER: {
- if (!ozone_buffer_factory_.CreateGpuMemoryBuffer(
- id, size, format, usage, client_id)) {
- return gfx::GpuMemoryBufferHandle();
- }
- gfx::GpuMemoryBufferHandle handle;
- handle.type = gfx::OZONE_NATIVE_BUFFER;
- handle.id = id;
- return handle;
- }
- default:
- NOTREACHED();
- return gfx::GpuMemoryBufferHandle();
- }
- }
- virtual void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferType type,
- gfx::GpuMemoryBufferId id,
- int client_id) override {
- switch (type) {
- case gfx::OZONE_NATIVE_BUFFER:
- ozone_buffer_factory_.DestroyGpuMemoryBuffer(id, client_id);
- break;
- default:
- NOTREACHED();
- break;
- }
- }
- virtual gpu::ImageFactory* AsImageFactory() override { return this; }
-
- // Overridden from gpu::ImageFactory:
- virtual scoped_refptr<gfx::GLImage> CreateImageForGpuMemoryBuffer(
- const gfx::GpuMemoryBufferHandle& handle,
- const gfx::Size& size,
- gfx::GpuMemoryBuffer::Format format,
- unsigned internalformat,
- int client_id) override {
- switch (handle.type) {
- case gfx::SHARED_MEMORY_BUFFER: {
- scoped_refptr<gfx::GLImageSharedMemory> image(
- new gfx::GLImageSharedMemory(size, internalformat));
- if (!image->Initialize(handle, format))
- return NULL;
-
- return image;
- }
- case gfx::OZONE_NATIVE_BUFFER:
- return ozone_buffer_factory_.CreateImageForGpuMemoryBuffer(
- handle.id, size, format, internalformat, client_id);
- default:
- NOTREACHED();
- return scoped_refptr<gfx::GLImage>();
- }
- }
-
- private:
- ui::GpuMemoryBufferFactoryOzoneNativeBuffer ozone_buffer_factory_;
-};
-
-} // namespace
-
-// static
-scoped_ptr<GpuMemoryBufferFactory> GpuMemoryBufferFactory::Create() {
- return make_scoped_ptr<GpuMemoryBufferFactory>(
- new GpuMemoryBufferFactoryImpl);
-}
-
-} // namespace content
diff --git a/chromium/content/common/gpu/gpu_memory_buffer_factory_ozone_native_buffer.cc b/chromium/content/common/gpu/gpu_memory_buffer_factory_ozone_native_buffer.cc
new file mode 100644
index 00000000000..6185150e5cf
--- /dev/null
+++ b/chromium/content/common/gpu/gpu_memory_buffer_factory_ozone_native_buffer.cc
@@ -0,0 +1,93 @@
+// Copyright 2014 The Chromium Authors. 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/common/gpu/gpu_memory_buffer_factory_ozone_native_buffer.h"
+
+#include "base/logging.h"
+#include "ui/gl/gl_image.h"
+#include "ui/ozone/public/surface_factory_ozone.h"
+
+namespace content {
+namespace {
+
+const GpuMemoryBufferFactory::Configuration kSupportedConfigurations[] = {
+ { gfx::GpuMemoryBuffer::RGBA_8888, gfx::GpuMemoryBuffer::SCANOUT },
+ { gfx::GpuMemoryBuffer::RGBX_8888, gfx::GpuMemoryBuffer::SCANOUT }
+};
+
+} // namespace
+
+GpuMemoryBufferFactoryOzoneNativeBuffer::
+ GpuMemoryBufferFactoryOzoneNativeBuffer() {
+}
+
+GpuMemoryBufferFactoryOzoneNativeBuffer::
+ ~GpuMemoryBufferFactoryOzoneNativeBuffer() {
+}
+
+// static
+bool GpuMemoryBufferFactoryOzoneNativeBuffer::
+ IsGpuMemoryBufferConfigurationSupported(gfx::GpuMemoryBuffer::Format format,
+ gfx::GpuMemoryBuffer::Usage usage) {
+ for (auto& configuration : kSupportedConfigurations) {
+ if (configuration.format == format && configuration.usage == usage)
+ return true;
+ }
+
+ return false;
+}
+
+void GpuMemoryBufferFactoryOzoneNativeBuffer::
+ GetSupportedGpuMemoryBufferConfigurations(
+ std::vector<Configuration>* configurations) {
+ if (!ui::SurfaceFactoryOzone::GetInstance()->CanCreateNativePixmap(
+ ui::SurfaceFactoryOzone::SCANOUT))
+ return;
+
+ configurations->assign(
+ kSupportedConfigurations,
+ kSupportedConfigurations + arraysize(kSupportedConfigurations));
+}
+
+gfx::GpuMemoryBufferHandle
+GpuMemoryBufferFactoryOzoneNativeBuffer::CreateGpuMemoryBuffer(
+ gfx::GpuMemoryBufferId id,
+ const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
+ gfx::GpuMemoryBuffer::Usage usage,
+ int client_id,
+ gfx::PluginWindowHandle surface_handle) {
+ if (!ozone_native_buffer_factory_.CreateGpuMemoryBuffer(
+ id, size, format, usage, client_id, surface_handle)) {
+ return gfx::GpuMemoryBufferHandle();
+ }
+ gfx::GpuMemoryBufferHandle handle;
+ handle.type = gfx::OZONE_NATIVE_BUFFER;
+ handle.id = id;
+ return handle;
+}
+
+void GpuMemoryBufferFactoryOzoneNativeBuffer::DestroyGpuMemoryBuffer(
+ gfx::GpuMemoryBufferId id,
+ int client_id) {
+ ozone_native_buffer_factory_.DestroyGpuMemoryBuffer(id, client_id);
+}
+
+gpu::ImageFactory* GpuMemoryBufferFactoryOzoneNativeBuffer::AsImageFactory() {
+ return this;
+}
+
+scoped_refptr<gfx::GLImage>
+GpuMemoryBufferFactoryOzoneNativeBuffer::CreateImageForGpuMemoryBuffer(
+ const gfx::GpuMemoryBufferHandle& handle,
+ const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
+ unsigned internalformat,
+ int client_id) {
+ DCHECK_EQ(handle.type, gfx::OZONE_NATIVE_BUFFER);
+ return ozone_native_buffer_factory_.CreateImageForGpuMemoryBuffer(
+ handle.id, size, format, internalformat, client_id);
+}
+
+} // namespace content
diff --git a/chromium/content/common/gpu/gpu_memory_buffer_factory_ozone_native_buffer.h b/chromium/content/common/gpu/gpu_memory_buffer_factory_ozone_native_buffer.h
new file mode 100644
index 00000000000..5cdce582073
--- /dev/null
+++ b/chromium/content/common/gpu/gpu_memory_buffer_factory_ozone_native_buffer.h
@@ -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.
+
+#ifndef CONTENT_COMMON_GPU_GPU_MEMORY_BUFFER_FACTORY_OZONE_NATIVE_BUFFER_H_
+#define CONTENT_COMMON_GPU_GPU_MEMORY_BUFFER_FACTORY_OZONE_NATIVE_BUFFER_H_
+
+#include "base/memory/ref_counted.h"
+#include "content/common/gpu/gpu_memory_buffer_factory.h"
+#include "gpu/command_buffer/service/image_factory.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/gpu_memory_buffer.h"
+#include "ui/ozone/gpu/gpu_memory_buffer_factory_ozone_native_buffer.h"
+
+namespace gfx {
+class GLImage;
+}
+
+namespace content {
+
+class GpuMemoryBufferFactoryOzoneNativeBuffer : public GpuMemoryBufferFactory,
+ public gpu::ImageFactory {
+ public:
+ GpuMemoryBufferFactoryOzoneNativeBuffer();
+ ~GpuMemoryBufferFactoryOzoneNativeBuffer() override;
+
+ static bool IsGpuMemoryBufferConfigurationSupported(
+ gfx::GpuMemoryBuffer::Format format,
+ gfx::GpuMemoryBuffer::Usage usage);
+
+ // Overridden from GpuMemoryBufferFactory:
+ void GetSupportedGpuMemoryBufferConfigurations(
+ std::vector<Configuration>* configurations) override;
+ gfx::GpuMemoryBufferHandle CreateGpuMemoryBuffer(
+ gfx::GpuMemoryBufferId id,
+ const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
+ gfx::GpuMemoryBuffer::Usage usage,
+ int client_id,
+ gfx::PluginWindowHandle surface_handle) override;
+ void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
+ int client_id) override;
+ gpu::ImageFactory* AsImageFactory() override;
+
+ // Overridden from gpu::ImageFactory:
+ scoped_refptr<gfx::GLImage> CreateImageForGpuMemoryBuffer(
+ const gfx::GpuMemoryBufferHandle& handle,
+ const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
+ unsigned internalformat,
+ int client_id) override;
+
+ private:
+ ui::GpuMemoryBufferFactoryOzoneNativeBuffer ozone_native_buffer_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(GpuMemoryBufferFactoryOzoneNativeBuffer);
+};
+
+} // namespace content
+
+#endif // CONTENT_COMMON_GPU_GPU_MEMORY_BUFFER_FACTORY_OZONE_NATIVE_BUFFER_H_
diff --git a/chromium/content/common/gpu/gpu_memory_buffer_factory_shared_memory.cc b/chromium/content/common/gpu/gpu_memory_buffer_factory_shared_memory.cc
new file mode 100644
index 00000000000..4c8f0e9a4c3
--- /dev/null
+++ b/chromium/content/common/gpu/gpu_memory_buffer_factory_shared_memory.cc
@@ -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.
+
+#include "content/common/gpu/gpu_memory_buffer_factory_shared_memory.h"
+
+#include <vector>
+
+#include "base/logging.h"
+#include "content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h"
+#include "ui/gl/gl_image.h"
+#include "ui/gl/gl_image_shared_memory.h"
+
+namespace content {
+
+GpuMemoryBufferFactorySharedMemory::GpuMemoryBufferFactorySharedMemory() {
+}
+
+GpuMemoryBufferFactorySharedMemory::~GpuMemoryBufferFactorySharedMemory() {
+}
+
+void GpuMemoryBufferFactorySharedMemory::
+ GetSupportedGpuMemoryBufferConfigurations(
+ std::vector<Configuration>* configurations) {
+ const Configuration supported_configurations[] = {
+ {gfx::GpuMemoryBuffer::R_8, gfx::GpuMemoryBuffer::MAP},
+ {gfx::GpuMemoryBuffer::RGBA_8888, gfx::GpuMemoryBuffer::MAP},
+ {gfx::GpuMemoryBuffer::BGRA_8888, gfx::GpuMemoryBuffer::MAP},
+ {gfx::GpuMemoryBuffer::YUV_420, gfx::GpuMemoryBuffer::MAP}};
+ configurations->assign(
+ supported_configurations,
+ supported_configurations + arraysize(supported_configurations));
+}
+
+gfx::GpuMemoryBufferHandle
+GpuMemoryBufferFactorySharedMemory::CreateGpuMemoryBuffer(
+ gfx::GpuMemoryBufferId id,
+ const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
+ gfx::GpuMemoryBuffer::Usage usage,
+ int client_id,
+ gfx::PluginWindowHandle surface_handle) {
+ size_t buffer_size = 0u;
+ if (!GpuMemoryBufferImplSharedMemory::BufferSizeInBytes(size, format,
+ &buffer_size))
+ return gfx::GpuMemoryBufferHandle();
+
+ base::SharedMemory shared_memory;
+ if (!shared_memory.CreateAnonymous(buffer_size))
+ return gfx::GpuMemoryBufferHandle();
+
+ gfx::GpuMemoryBufferHandle handle;
+ handle.type = gfx::SHARED_MEMORY_BUFFER;
+ handle.id = id;
+ shared_memory.ShareToProcess(base::GetCurrentProcessHandle(), &handle.handle);
+ return handle;
+}
+
+void GpuMemoryBufferFactorySharedMemory::DestroyGpuMemoryBuffer(
+ gfx::GpuMemoryBufferId id,
+ int client_id) {
+}
+
+gpu::ImageFactory* GpuMemoryBufferFactorySharedMemory::AsImageFactory() {
+ return this;
+}
+
+scoped_refptr<gfx::GLImage>
+GpuMemoryBufferFactorySharedMemory::CreateImageForGpuMemoryBuffer(
+ const gfx::GpuMemoryBufferHandle& handle,
+ const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
+ unsigned internalformat,
+ int client_id) {
+ scoped_refptr<gfx::GLImageSharedMemory> image(
+ new gfx::GLImageSharedMemory(size, internalformat));
+ if (!image->Initialize(handle, format))
+ return scoped_refptr<gfx::GLImage>();
+
+ return image;
+}
+
+} // namespace content
diff --git a/chromium/content/common/gpu/gpu_memory_buffer_factory_shared_memory.h b/chromium/content/common/gpu/gpu_memory_buffer_factory_shared_memory.h
new file mode 100644
index 00000000000..b2a9c705f88
--- /dev/null
+++ b/chromium/content/common/gpu/gpu_memory_buffer_factory_shared_memory.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_COMMON_GPU_GPU_MEMORY_BUFFER_FACTORY_SHARED_MEMORY_H_
+#define CONTENT_COMMON_GPU_GPU_MEMORY_BUFFER_FACTORY_SHARED_MEMORY_H_
+
+#include "base/memory/ref_counted.h"
+#include "content/common/gpu/gpu_memory_buffer_factory.h"
+#include "gpu/command_buffer/service/image_factory.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/gpu_memory_buffer.h"
+
+namespace gfx {
+class GLImage;
+}
+
+namespace content {
+
+class GpuMemoryBufferFactorySharedMemory : public GpuMemoryBufferFactory,
+ public gpu::ImageFactory {
+ public:
+ GpuMemoryBufferFactorySharedMemory();
+ ~GpuMemoryBufferFactorySharedMemory() override;
+
+ // Overridden from GpuMemoryBufferFactory:
+ void GetSupportedGpuMemoryBufferConfigurations(
+ std::vector<Configuration>* configurations) override;
+ gfx::GpuMemoryBufferHandle CreateGpuMemoryBuffer(
+ gfx::GpuMemoryBufferId id,
+ const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
+ gfx::GpuMemoryBuffer::Usage usage,
+ int client_id,
+ gfx::PluginWindowHandle surface_handle) override;
+ void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
+ int client_id) override;
+ gpu::ImageFactory* AsImageFactory() override;
+
+ // Overridden from gpu::ImageFactory:
+ scoped_refptr<gfx::GLImage> CreateImageForGpuMemoryBuffer(
+ const gfx::GpuMemoryBufferHandle& handle,
+ const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
+ unsigned internalformat,
+ int client_id) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GpuMemoryBufferFactorySharedMemory);
+};
+
+} // namespace content
+
+#endif // CONTENT_COMMON_GPU_GPU_MEMORY_BUFFER_FACTORY_SHARED_MEMORY_H_
diff --git a/chromium/content/common/gpu/gpu_memory_buffer_factory_surface_texture.cc b/chromium/content/common/gpu/gpu_memory_buffer_factory_surface_texture.cc
index 91b81cbd651..002ad61b1c2 100644
--- a/chromium/content/common/gpu/gpu_memory_buffer_factory_surface_texture.cc
+++ b/chromium/content/common/gpu/gpu_memory_buffer_factory_surface_texture.cc
@@ -9,6 +9,13 @@
#include "ui/gl/gl_image_surface_texture.h"
namespace content {
+namespace {
+
+const GpuMemoryBufferFactory::Configuration kSupportedConfigurations[] = {
+ { gfx::GpuMemoryBuffer::RGBA_8888, gfx::GpuMemoryBuffer::MAP }
+};
+
+} // namespace
GpuMemoryBufferFactorySurfaceTexture::GpuMemoryBufferFactorySurfaceTexture() {
}
@@ -16,12 +23,34 @@ GpuMemoryBufferFactorySurfaceTexture::GpuMemoryBufferFactorySurfaceTexture() {
GpuMemoryBufferFactorySurfaceTexture::~GpuMemoryBufferFactorySurfaceTexture() {
}
+// static
+bool GpuMemoryBufferFactorySurfaceTexture::
+ IsGpuMemoryBufferConfigurationSupported(gfx::GpuMemoryBuffer::Format format,
+ gfx::GpuMemoryBuffer::Usage usage) {
+ for (auto& configuration : kSupportedConfigurations) {
+ if (configuration.format == format && configuration.usage == usage)
+ return true;
+ }
+
+ return false;
+}
+
+void GpuMemoryBufferFactorySurfaceTexture::
+ GetSupportedGpuMemoryBufferConfigurations(
+ std::vector<Configuration>* configurations) {
+ configurations->assign(
+ kSupportedConfigurations,
+ kSupportedConfigurations + arraysize(kSupportedConfigurations));
+}
+
gfx::GpuMemoryBufferHandle
GpuMemoryBufferFactorySurfaceTexture::CreateGpuMemoryBuffer(
gfx::GpuMemoryBufferId id,
const gfx::Size& size,
- unsigned internalformat,
- int client_id) {
+ gfx::GpuMemoryBuffer::Format format,
+ gfx::GpuMemoryBuffer::Usage usage,
+ int client_id,
+ gfx::PluginWindowHandle surface_handle) {
// 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
@@ -35,9 +64,13 @@ GpuMemoryBufferFactorySurfaceTexture::CreateGpuMemoryBuffer(
SurfaceTextureManager::GetInstance()->RegisterSurfaceTexture(
id, client_id, surface_texture.get());
- SurfaceTextureMapKey key(id, client_id);
- DCHECK(surface_textures_.find(key) == surface_textures_.end());
- surface_textures_[key] = surface_texture;
+ {
+ base::AutoLock lock(surface_textures_lock_);
+
+ SurfaceTextureMapKey key(id, client_id);
+ DCHECK(surface_textures_.find(key) == surface_textures_.end());
+ surface_textures_[key] = surface_texture;
+ }
gfx::GpuMemoryBufferHandle handle;
handle.type = gfx::SURFACE_TEXTURE_BUFFER;
@@ -48,21 +81,33 @@ GpuMemoryBufferFactorySurfaceTexture::CreateGpuMemoryBuffer(
void GpuMemoryBufferFactorySurfaceTexture::DestroyGpuMemoryBuffer(
gfx::GpuMemoryBufferId id,
int client_id) {
- SurfaceTextureMapKey key(id, client_id);
- SurfaceTextureMap::iterator it = surface_textures_.find(key);
- if (it != surface_textures_.end())
- surface_textures_.erase(it);
+ {
+ base::AutoLock lock(surface_textures_lock_);
+
+ SurfaceTextureMapKey key(id, client_id);
+ DCHECK(surface_textures_.find(key) != surface_textures_.end());
+ surface_textures_.erase(key);
+ }
SurfaceTextureManager::GetInstance()->UnregisterSurfaceTexture(id, client_id);
}
+gpu::ImageFactory* GpuMemoryBufferFactorySurfaceTexture::AsImageFactory() {
+ return this;
+}
+
scoped_refptr<gfx::GLImage>
GpuMemoryBufferFactorySurfaceTexture::CreateImageForGpuMemoryBuffer(
- gfx::GpuMemoryBufferId id,
+ const gfx::GpuMemoryBufferHandle& handle,
const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
unsigned internalformat,
int client_id) {
- SurfaceTextureMapKey key(id, client_id);
+ base::AutoLock lock(surface_textures_lock_);
+
+ DCHECK_EQ(handle.type, gfx::SURFACE_TEXTURE_BUFFER);
+
+ SurfaceTextureMapKey key(handle.id, client_id);
SurfaceTextureMap::iterator it = surface_textures_.find(key);
if (it == surface_textures_.end())
return scoped_refptr<gfx::GLImage>();
diff --git a/chromium/content/common/gpu/gpu_memory_buffer_factory_surface_texture.h b/chromium/content/common/gpu/gpu_memory_buffer_factory_surface_texture.h
index c9103eda4fd..24679b06c57 100644
--- a/chromium/content/common/gpu/gpu_memory_buffer_factory_surface_texture.h
+++ b/chromium/content/common/gpu/gpu_memory_buffer_factory_surface_texture.h
@@ -7,6 +7,9 @@
#include "base/containers/hash_tables.h"
#include "base/memory/ref_counted.h"
+#include "base/synchronization/lock.h"
+#include "content/common/gpu/gpu_memory_buffer_factory.h"
+#include "gpu/command_buffer/service/image_factory.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/gpu_memory_buffer.h"
@@ -17,33 +20,44 @@ class SurfaceTexture;
namespace content {
-class GpuMemoryBufferFactorySurfaceTexture {
+class GpuMemoryBufferFactorySurfaceTexture : public GpuMemoryBufferFactory,
+ public gpu::ImageFactory {
public:
GpuMemoryBufferFactorySurfaceTexture();
- ~GpuMemoryBufferFactorySurfaceTexture();
+ ~GpuMemoryBufferFactorySurfaceTexture() override;
- // Creates a SurfaceTexture backed GPU memory buffer with |size| and
- // |internalformat|. A valid handle is returned on success.
- gfx::GpuMemoryBufferHandle CreateGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- unsigned internalformat,
- int client_id);
+ static bool IsGpuMemoryBufferConfigurationSupported(
+ gfx::GpuMemoryBuffer::Format format,
+ gfx::GpuMemoryBuffer::Usage usage);
- // Destroy a previously created GPU memory buffer.
- void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id, int client_id);
+ // Overridden from GpuMemoryBufferFactory:
+ void GetSupportedGpuMemoryBufferConfigurations(
+ std::vector<Configuration>* configurations) override;
+ gfx::GpuMemoryBufferHandle CreateGpuMemoryBuffer(
+ gfx::GpuMemoryBufferId id,
+ const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
+ gfx::GpuMemoryBuffer::Usage usage,
+ int client_id,
+ gfx::PluginWindowHandle surface_handle) override;
+ void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
+ int client_id) override;
+ gpu::ImageFactory* AsImageFactory() override;
- // Creates a GLImage instance for a GPU memory buffer.
+ // Overridden from gpu::ImageFactory:
scoped_refptr<gfx::GLImage> CreateImageForGpuMemoryBuffer(
- gfx::GpuMemoryBufferId id,
+ const gfx::GpuMemoryBufferHandle& handle,
const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
unsigned internalformat,
- int client_id);
+ int client_id) override;
private:
typedef std::pair<int, int> SurfaceTextureMapKey;
typedef base::hash_map<SurfaceTextureMapKey,
scoped_refptr<gfx::SurfaceTexture>> SurfaceTextureMap;
SurfaceTextureMap surface_textures_;
+ base::Lock surface_textures_lock_;
};
} // namespace content
diff --git a/chromium/content/common/gpu/gpu_memory_buffer_factory_unittest.cc b/chromium/content/common/gpu/gpu_memory_buffer_factory_unittest.cc
new file mode 100644
index 00000000000..f9dc7e1a396
--- /dev/null
+++ b/chromium/content/common/gpu/gpu_memory_buffer_factory_unittest.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/common/gpu/gpu_memory_buffer_factory.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+namespace {
+
+class GpuMemoryBufferFactoryTest
+ : public testing::TestWithParam<gfx::GpuMemoryBufferType> {
+ public:
+ GpuMemoryBufferFactoryTest() : factory_(nullptr) {}
+
+ // Overridden from testing::Test:
+ void SetUp() override {
+ factory_ = GpuMemoryBufferFactory::Create(GetParam());
+ factory_->GetSupportedGpuMemoryBufferConfigurations(
+ &supported_configurations_);
+ }
+ void TearDown() override { factory_.reset(); }
+
+ protected:
+ scoped_ptr<GpuMemoryBufferFactory> factory_;
+ std::vector<GpuMemoryBufferFactory::Configuration> supported_configurations_;
+};
+
+TEST_P(GpuMemoryBufferFactoryTest, CreateAndDestroy) {
+ const int kBufferId = 1;
+ const int kClientId = 1;
+
+ gfx::Size buffer_size(2, 2);
+
+ for (auto configuration : supported_configurations_) {
+ gfx::GpuMemoryBufferHandle handle = factory_->CreateGpuMemoryBuffer(
+ kBufferId, buffer_size, configuration.format, configuration.usage,
+ kClientId, gfx::kNullPluginWindow);
+ EXPECT_EQ(handle.type, GetParam());
+ factory_->DestroyGpuMemoryBuffer(kBufferId, kClientId);
+ }
+}
+
+std::vector<gfx::GpuMemoryBufferType>
+GetSupportedGpuMemoryBufferFactoryTypes() {
+ std::vector<gfx::GpuMemoryBufferType> supported_types;
+ GpuMemoryBufferFactory::GetSupportedTypes(&supported_types);
+ return supported_types;
+}
+
+INSTANTIATE_TEST_CASE_P(
+ GpuMemoryBufferFactoryTests,
+ GpuMemoryBufferFactoryTest,
+ ::testing::ValuesIn(GetSupportedGpuMemoryBufferFactoryTypes()));
+
+} // namespace
+} // namespace content
diff --git a/chromium/content/common/gpu/gpu_memory_buffer_factory_win.cc b/chromium/content/common/gpu/gpu_memory_buffer_factory_win.cc
deleted file mode 100644
index 618ecc5ed24..00000000000
--- a/chromium/content/common/gpu/gpu_memory_buffer_factory_win.cc
+++ /dev/null
@@ -1,67 +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/common/gpu/gpu_memory_buffer_factory.h"
-
-#include "base/logging.h"
-#include "gpu/command_buffer/service/image_factory.h"
-#include "ui/gl/gl_image.h"
-#include "ui/gl/gl_image_shared_memory.h"
-
-namespace content {
-namespace {
-
-class GpuMemoryBufferFactoryImpl : public GpuMemoryBufferFactory,
- public gpu::ImageFactory {
- public:
- // Overridden from GpuMemoryBufferFactory:
- virtual gfx::GpuMemoryBufferHandle CreateGpuMemoryBuffer(
- gfx::GpuMemoryBufferType type,
- gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- gfx::GpuMemoryBuffer::Format format,
- gfx::GpuMemoryBuffer::Usage usage,
- int client_id) override {
- NOTREACHED();
- return gfx::GpuMemoryBufferHandle();
- }
- virtual void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferType type,
- gfx::GpuMemoryBufferId id,
- int client_id) override {
- NOTREACHED();
- }
- virtual gpu::ImageFactory* AsImageFactory() override { return this; }
-
- // Overridden from gpu::ImageFactory:
- virtual scoped_refptr<gfx::GLImage> CreateImageForGpuMemoryBuffer(
- const gfx::GpuMemoryBufferHandle& handle,
- const gfx::Size& size,
- gfx::GpuMemoryBuffer::Format format,
- unsigned internalformat,
- int client_id) override {
- switch (handle.type) {
- case gfx::SHARED_MEMORY_BUFFER: {
- scoped_refptr<gfx::GLImageSharedMemory> image(
- new gfx::GLImageSharedMemory(size, internalformat));
- if (!image->Initialize(handle, format))
- return NULL;
-
- return image;
- }
- default:
- NOTREACHED();
- return scoped_refptr<gfx::GLImage>();
- }
- }
-};
-
-} // namespace
-
-// static
-scoped_ptr<GpuMemoryBufferFactory> GpuMemoryBufferFactory::Create() {
- return make_scoped_ptr<GpuMemoryBufferFactory>(
- new GpuMemoryBufferFactoryImpl);
-}
-
-} // namespace content
diff --git a/chromium/content/common/gpu/gpu_memory_manager.cc b/chromium/content/common/gpu/gpu_memory_manager.cc
index b3c98c02168..ceedf098de5 100644
--- a/chromium/content/common/gpu/gpu_memory_manager.cc
+++ b/chromium/content/common/gpu/gpu_memory_manager.cc
@@ -8,10 +8,10 @@
#include "base/bind.h"
#include "base/command_line.h"
-#include "base/debug/trace_event.h"
#include "base/message_loop/message_loop.h"
#include "base/process/process_handle.h"
#include "base/strings/string_number_conversions.h"
+#include "base/trace_event/trace_event.h"
#include "content/common/gpu/gpu_channel_manager.h"
#include "content/common/gpu/gpu_memory_manager_client.h"
#include "content/common/gpu/gpu_memory_tracking.h"
@@ -100,7 +100,7 @@ void GpuMemoryManager::UpdateAvailableGpuMemory() {
client_hard_limit_bytes_ = bytes_min;
// Clamp the observed value to a specific range on Android.
client_hard_limit_bytes_ = std::max(client_hard_limit_bytes_,
- static_cast<uint64>(16 * 1024 * 1024));
+ static_cast<uint64>(8 * 1024 * 1024));
client_hard_limit_bytes_ = std::min(client_hard_limit_bytes_,
static_cast<uint64>(256 * 1024 * 1024));
#else
@@ -117,7 +117,7 @@ void GpuMemoryManager::ScheduleManage(
if (manage_immediate_scheduled_)
return;
if (schedule_manage_time == kScheduleManageNow) {
- base::MessageLoop::current()->PostTask(
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(&GpuMemoryManager::Manage, AsWeakPtr()));
manage_immediate_scheduled_ = true;
if (!delayed_manage_callback_.IsCancelled())
@@ -127,9 +127,8 @@ void GpuMemoryManager::ScheduleManage(
return;
delayed_manage_callback_.Reset(base::Bind(&GpuMemoryManager::Manage,
AsWeakPtr()));
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- delayed_manage_callback_.callback(),
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, delayed_manage_callback_.callback(),
base::TimeDelta::FromMilliseconds(kDelayedScheduleManageTimeoutMs));
}
}
diff --git a/chromium/content/common/gpu/gpu_memory_manager.h b/chromium/content/common/gpu/gpu_memory_manager.h
index 0c847e98bc4..5d259986317 100644
--- a/chromium/content/common/gpu/gpu_memory_manager.h
+++ b/chromium/content/common/gpu/gpu_memory_manager.h
@@ -183,4 +183,4 @@ class CONTENT_EXPORT GpuMemoryManager :
} // namespace content
-#endif // CONTENT_COMMON_GPU_GPU_MEMORY_MANAGER_H_
+#endif // CONTENT_COMMON_GPU_GPU_MEMORY_MANAGER_H_
diff --git a/chromium/content/common/gpu/gpu_memory_manager_client.h b/chromium/content/common/gpu/gpu_memory_manager_client.h
index 2058e461307..0c6c7d0920f 100644
--- a/chromium/content/common/gpu/gpu_memory_manager_client.h
+++ b/chromium/content/common/gpu/gpu_memory_manager_client.h
@@ -11,7 +11,7 @@
#include "content/common/content_export.h"
#include "gpu/command_buffer/common/gpu_memory_allocation.h"
#include "gpu/command_buffer/service/memory_tracking.h"
-#include "ui/gfx/size.h"
+#include "ui/gfx/geometry/size.h"
namespace content {
diff --git a/chromium/content/common/gpu/gpu_memory_manager_unittest.cc b/chromium/content/common/gpu/gpu_memory_manager_unittest.cc
index 18ebce20786..d0237fb5ec0 100644
--- a/chromium/content/common/gpu/gpu_memory_manager_unittest.cc
+++ b/chromium/content/common/gpu/gpu_memory_manager_unittest.cc
@@ -3,12 +3,12 @@
// found in the LICENSE file.
#include "content/common/gpu/gpu_memory_manager.h"
+
#include "content/common/gpu/gpu_memory_manager_client.h"
#include "content/common/gpu/gpu_memory_tracking.h"
#include "gpu/command_buffer/common/gpu_memory_allocation.h"
-#include "ui/gfx/size_conversions.h"
-
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/size_conversions.h"
using gpu::MemoryAllocation;
diff --git a/chromium/content/common/gpu/gpu_memory_tracking.h b/chromium/content/common/gpu/gpu_memory_tracking.h
index bd0b400a44c..97c0743fdff 100644
--- a/chromium/content/common/gpu/gpu_memory_tracking.h
+++ b/chromium/content/common/gpu/gpu_memory_tracking.h
@@ -54,4 +54,4 @@ class CONTENT_EXPORT GpuMemoryTrackingGroup {
} // namespace content
-#endif // CONTENT_COMMON_GPU_GPU_MEMORY_TRACKING_H_
+#endif // CONTENT_COMMON_GPU_GPU_MEMORY_TRACKING_H_
diff --git a/chromium/content/common/gpu/gpu_memory_uma_stats.h b/chromium/content/common/gpu/gpu_memory_uma_stats.h
index 8f67aeba76c..467619d35b8 100644
--- a/chromium/content/common/gpu/gpu_memory_uma_stats.h
+++ b/chromium/content/common/gpu/gpu_memory_uma_stats.h
@@ -41,4 +41,4 @@ struct GPUMemoryUmaStats {
} // namespace content
-#endif // CONTENT_COMMON_GPU_GPU_MEMORY_UMA_STATS_H_
+#endif // CONTENT_COMMON_GPU_GPU_MEMORY_UMA_STATS_H_
diff --git a/chromium/content/common/gpu/gpu_messages.h b/chromium/content/common/gpu/gpu_messages.h
index 839de2d55a9..6bdec50cb74 100644
--- a/chromium/content/common/gpu/gpu_messages.h
+++ b/chromium/content/common/gpu/gpu_messages.h
@@ -10,6 +10,7 @@
#include "base/memory/shared_memory.h"
#include "content/common/content_export.h"
+#include "content/common/content_param_traits.h"
#include "content/common/gpu/gpu_memory_uma_stats.h"
#include "content/common/gpu/gpu_process_launch_causes.h"
#include "content/common/gpu/gpu_result_codes.h"
@@ -20,6 +21,7 @@
#include "gpu/command_buffer/common/constants.h"
#include "gpu/command_buffer/common/gpu_memory_allocation.h"
#include "gpu/command_buffer/common/mailbox.h"
+#include "gpu/command_buffer/common/value_state.h"
#include "gpu/config/gpu_info.h"
#include "gpu/ipc/gpu_command_buffer_traits.h"
#include "ipc/ipc_channel_handle.h"
@@ -28,9 +30,9 @@
#include "media/video/video_decode_accelerator.h"
#include "media/video/video_encode_accelerator.h"
#include "ui/events/latency_info.h"
+#include "ui/gfx/geometry/size.h"
#include "ui/gfx/gpu_memory_buffer.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/size.h"
#include "ui/gl/gpu_preference.h"
#if defined(OS_ANDROID)
@@ -52,6 +54,7 @@ IPC_ENUM_TRAITS_MAX_VALUE(gfx::SurfaceType,
gfx::SURFACE_TYPE_LAST)
IPC_ENUM_TRAITS_MAX_VALUE(gpu::MemoryAllocation::PriorityCutoff,
gpu::MemoryAllocation::CUTOFF_LAST)
+IPC_ENUM_TRAITS_MAX_VALUE(gpu::error::Error, gpu::error::kErrorLast)
IPC_ENUM_TRAITS_MAX_VALUE(gpu::error::ContextLostReason,
gpu::error::kContextLostReasonLast)
IPC_ENUM_TRAITS_MAX_VALUE(media::VideoEncodeAccelerator::Error,
@@ -76,12 +79,12 @@ IPC_STRUCT_BEGIN(GPUCreateCommandBufferConfig)
IPC_STRUCT_END()
IPC_STRUCT_BEGIN(GpuMsg_CreateGpuMemoryBuffer_Params)
- IPC_STRUCT_MEMBER(gfx::GpuMemoryBufferType, type)
IPC_STRUCT_MEMBER(int32, id)
IPC_STRUCT_MEMBER(gfx::Size, size)
IPC_STRUCT_MEMBER(gfx::GpuMemoryBuffer::Format, format)
IPC_STRUCT_MEMBER(gfx::GpuMemoryBuffer::Usage, usage)
IPC_STRUCT_MEMBER(int32, client_id)
+ IPC_STRUCT_MEMBER(gfx::PluginWindowHandle, surface_handle)
IPC_STRUCT_END()
IPC_STRUCT_BEGIN(GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params)
@@ -136,12 +139,6 @@ IPC_STRUCT_END()
IPC_STRUCT_TRAITS_MEMBER(children)
IPC_STRUCT_TRAITS_END()
-IPC_STRUCT_TRAITS_BEGIN(gpu::GpuPerformanceStats)
- IPC_STRUCT_TRAITS_MEMBER(graphics)
- IPC_STRUCT_TRAITS_MEMBER(gaming)
- IPC_STRUCT_TRAITS_MEMBER(overall)
-IPC_STRUCT_TRAITS_END()
-
IPC_STRUCT_TRAITS_BEGIN(gpu::GPUInfo::GPUDevice)
IPC_STRUCT_TRAITS_MEMBER(vendor_id)
IPC_STRUCT_TRAITS_MEMBER(device_id)
@@ -150,6 +147,12 @@ IPC_STRUCT_TRAITS_BEGIN(gpu::GPUInfo::GPUDevice)
IPC_STRUCT_TRAITS_MEMBER(device_string)
IPC_STRUCT_TRAITS_END()
+IPC_STRUCT_TRAITS_BEGIN(gpu::VideoDecodeAcceleratorSupportedProfile)
+ IPC_STRUCT_TRAITS_MEMBER(profile)
+ IPC_STRUCT_TRAITS_MEMBER(max_resolution)
+ IPC_STRUCT_TRAITS_MEMBER(min_resolution)
+IPC_STRUCT_TRAITS_END()
+
IPC_STRUCT_TRAITS_BEGIN(gpu::VideoEncodeAcceleratorSupportedProfile)
IPC_STRUCT_TRAITS_MEMBER(profile)
IPC_STRUCT_TRAITS_MEMBER(max_resolution)
@@ -170,6 +173,7 @@ IPC_STRUCT_TRAITS_BEGIN(gpu::GPUInfo)
IPC_STRUCT_TRAITS_MEMBER(driver_date)
IPC_STRUCT_TRAITS_MEMBER(pixel_shader_version)
IPC_STRUCT_TRAITS_MEMBER(vertex_shader_version)
+ IPC_STRUCT_TRAITS_MEMBER(max_msaa_samples)
IPC_STRUCT_TRAITS_MEMBER(machine_model_name)
IPC_STRUCT_TRAITS_MEMBER(machine_model_version)
IPC_STRUCT_TRAITS_MEMBER(gl_version)
@@ -181,7 +185,6 @@ IPC_STRUCT_TRAITS_BEGIN(gpu::GPUInfo)
IPC_STRUCT_TRAITS_MEMBER(gl_ws_extensions)
IPC_STRUCT_TRAITS_MEMBER(gl_reset_notification_strategy)
IPC_STRUCT_TRAITS_MEMBER(can_lose_context)
- IPC_STRUCT_TRAITS_MEMBER(performance_stats)
IPC_STRUCT_TRAITS_MEMBER(software_rendering)
IPC_STRUCT_TRAITS_MEMBER(direct_rendering)
IPC_STRUCT_TRAITS_MEMBER(sandboxed)
@@ -192,6 +195,7 @@ IPC_STRUCT_TRAITS_BEGIN(gpu::GPUInfo)
IPC_STRUCT_TRAITS_MEMBER(dx_diagnostics_info_state)
IPC_STRUCT_TRAITS_MEMBER(dx_diagnostics)
#endif
+ IPC_STRUCT_TRAITS_MEMBER(video_decode_accelerator_supported_profiles)
IPC_STRUCT_TRAITS_MEMBER(video_encode_accelerator_supported_profiles)
IPC_STRUCT_TRAITS_END()
@@ -263,8 +267,7 @@ IPC_MESSAGE_CONTROL1(GpuMsg_CreateGpuMemoryBuffer,
GpuMsg_CreateGpuMemoryBuffer_Params)
// Tells the GPU process to destroy buffer.
-IPC_MESSAGE_CONTROL4(GpuMsg_DestroyGpuMemoryBuffer,
- gfx::GpuMemoryBufferType, /* type */
+IPC_MESSAGE_CONTROL3(GpuMsg_DestroyGpuMemoryBuffer,
gfx::GpuMemoryBufferId, /* id */
int32, /* client_id */
int32 /* sync_point */)
@@ -301,6 +304,17 @@ IPC_MESSAGE_CONTROL0(GpuMsg_DisableWatchdog)
// Tells the GPU process that the browser has seen a GPU switch.
IPC_MESSAGE_CONTROL0(GpuMsg_GpuSwitched)
+// Tells the GPU process to delete the default_offscreen surface. It will also
+// close the display and any other resources when the last GL surface is
+// deleted. GPU process will respond with GphHosMsg_ResourcesRelinquished.
+IPC_MESSAGE_CONTROL0(GpuMsg_RelinquishResources)
+
+// Sends an input event to the gpu service.
+IPC_MESSAGE_CONTROL3(GpuMsg_UpdateValueState,
+ int, /* client_id */
+ unsigned int, /* target */
+ gpu::ValueState /* valuestate */)
+
//------------------------------------------------------------------------------
// GPU Host Messages
// These are messages to the browser.
@@ -381,12 +395,6 @@ IPC_MESSAGE_CONTROL2(GpuHostMsg_AcceleratedSurfaceInitialized,
IPC_MESSAGE_CONTROL1(GpuHostMsg_AcceleratedSurfaceBuffersSwapped,
GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params)
-// Tells the browser about updated parameters for vsync alignment.
-IPC_MESSAGE_CONTROL3(GpuHostMsg_UpdateVSyncParameters,
- int32 /* surface_id */,
- base::TimeTicks /* timebase */,
- base::TimeDelta /* interval */)
-
IPC_MESSAGE_CONTROL1(GpuHostMsg_DidCreateOffscreenContext,
GURL /* url */)
@@ -402,6 +410,21 @@ IPC_MESSAGE_CONTROL1(GpuHostMsg_DidDestroyOffscreenContext,
IPC_MESSAGE_CONTROL1(GpuHostMsg_GpuMemoryUmaStats,
content::GPUMemoryUmaStats /* GPU memory UMA stats */)
+// Response to GpuMsg_RelinquishResources.
+IPC_MESSAGE_CONTROL0(GpuHostMsg_ResourcesRelinquished)
+
+// Tells the browser that a context has subscribed to a new target and
+// the browser should start sending the corresponding information
+IPC_MESSAGE_CONTROL2(GpuHostMsg_AddSubscription,
+ int32 /* client_id */,
+ unsigned int /* target */)
+
+// Tells the browser that no contexts are subscribed to the target anymore
+// so the browser should stop sending the corresponding information
+IPC_MESSAGE_CONTROL2(GpuHostMsg_RemoveSubscription,
+ int32 /* client_id */,
+ unsigned int /* target */)
+
//------------------------------------------------------------------------------
// GPU Channel Messages
// These are messages from a renderer process to the GPU process.
@@ -420,15 +443,6 @@ IPC_SYNC_MESSAGE_CONTROL3_1(GpuChannelMsg_CreateOffscreenCommandBuffer,
IPC_SYNC_MESSAGE_CONTROL1_0(GpuChannelMsg_DestroyCommandBuffer,
int32 /* instance_id */)
-// Sent by DevTools agent in the inspected renderer process to initiate GPU
-// instrumentation events recording.
-IPC_SYNC_MESSAGE_CONTROL1_1(GpuChannelMsg_DevToolsStartEventsRecording,
- int32, /* route_id */
- bool /* succeeded */)
-
-// The message is sent when DevTools want to stop events recording.
-IPC_MESSAGE_CONTROL0(GpuChannelMsg_DevToolsStopEventsRecording)
-
#if defined(OS_ANDROID)
//------------------------------------------------------------------------------
// Stream Texture Messages
@@ -539,13 +553,19 @@ IPC_SYNC_MESSAGE_ROUTED5_1(GpuCommandBufferMsg_CreateVideoEncoder,
// Tells the proxy that there was an error and the command buffer had to be
// destroyed for some reason.
-IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_Destroyed,
- gpu::error::ContextLostReason /* reason */)
+IPC_MESSAGE_ROUTED2(GpuCommandBufferMsg_Destroyed,
+ gpu::error::ContextLostReason, /* reason */
+ gpu::error::Error /* error */)
// Tells the browser that SwapBuffers returned and passes latency info
IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_SwapBuffersCompleted,
std::vector<ui::LatencyInfo> /* latency_info */)
+// Tells the browser about updated parameters for vsync alignment.
+IPC_MESSAGE_ROUTED2(GpuCommandBufferMsg_UpdateVSyncParameters,
+ base::TimeTicks /* timebase */,
+ base::TimeDelta /* interval */)
+
// Send to stub on surface visibility change.
IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_SetSurfaceVisible, bool /* visible */)
@@ -661,10 +681,11 @@ IPC_MESSAGE_ROUTED1(AcceleratedVideoDecoderHostMsg_DismissPictureBuffer,
int32) /* Picture buffer ID */
// Decoder reports that a picture is ready.
-IPC_MESSAGE_ROUTED3(AcceleratedVideoDecoderHostMsg_PictureReady,
+IPC_MESSAGE_ROUTED4(AcceleratedVideoDecoderHostMsg_PictureReady,
int32, /* Picture buffer ID */
int32, /* Bitstream buffer ID */
- gfx::Rect) /* Visible rectangle */
+ gfx::Rect, /* Visible rectangle */
+ bool) /* Buffer is HW overlay capable */
// Confirm decoder has been flushed.
IPC_MESSAGE_ROUTED0(AcceleratedVideoDecoderHostMsg_FlushDone)
@@ -681,10 +702,11 @@ IPC_MESSAGE_ROUTED1(AcceleratedVideoDecoderHostMsg_ErrorNotification,
// These messages are sent from the Renderer process to GPU process.
// Queue a input buffer to the encoder to encode. |frame_id| will be returned by
-// AcceleratedVideoEncoderHostMsg_NotifyEncodeDone.
-IPC_MESSAGE_ROUTED4(AcceleratedVideoEncoderMsg_Encode,
+// AcceleratedVideoEncoderHostMsg_NotifyInputDone.
+IPC_MESSAGE_ROUTED5(AcceleratedVideoEncoderMsg_Encode,
int32 /* frame_id */,
base::SharedMemoryHandle /* buffer_handle */,
+ uint32 /* buffer_offset */,
uint32 /* buffer_size */,
bool /* force_keyframe */)
diff --git a/chromium/content/common/gpu/gpu_process_launch_causes.h b/chromium/content/common/gpu/gpu_process_launch_causes.h
index c6416ae1881..b4dfc0a32f7 100644
--- a/chromium/content/common/gpu/gpu_process_launch_causes.h
+++ b/chromium/content/common/gpu/gpu_process_launch_causes.h
@@ -19,6 +19,7 @@ enum CauseForGpuLaunch {
CAUSE_FOR_GPU_LAUNCH_PEPPERPLATFORMCONTEXT3DIMPL_INITIALIZE,
CAUSE_FOR_GPU_LAUNCH_BROWSER_STARTUP,
CAUSE_FOR_GPU_LAUNCH_CANVAS_2D,
+ CAUSE_FOR_GPU_LAUNCH_PEPPERVIDEOENCODERACCELERATOR_INITIALIZE,
// All new values should be inserted above this point so that
// existing values continue to match up with those in histograms.xml.
diff --git a/chromium/content/common/gpu/image_transport_surface.cc b/chromium/content/common/gpu/image_transport_surface.cc
index c08477225d8..ac5eb2e7e2c 100644
--- a/chromium/content/common/gpu/image_transport_surface.cc
+++ b/chromium/content/common/gpu/image_transport_surface.cc
@@ -7,14 +7,13 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/command_line.h"
-#include "base/debug/trace_event.h"
+#include "base/trace_event/trace_event.h"
#include "content/common/gpu/gpu_channel.h"
#include "content/common/gpu/gpu_channel_manager.h"
#include "content/common/gpu/gpu_command_buffer_stub.h"
#include "content/common/gpu/gpu_messages.h"
#include "content/common/gpu/null_transport_surface.h"
-#include "content/common/gpu/sync_point_manager.h"
-#include "gpu/command_buffer/service/gpu_scheduler.h"
+#include "gpu/command_buffer/service/sync_point_manager.h"
#include "ui/gfx/vsync_provider.h"
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_switches.h"
@@ -109,33 +108,6 @@ void ImageTransportHelper::SendAcceleratedSurfaceBuffersSwapped(
manager_->Send(new GpuHostMsg_AcceleratedSurfaceBuffersSwapped(params));
}
-void ImageTransportHelper::SendUpdateVSyncParameters(
- base::TimeTicks timebase, base::TimeDelta interval) {
- manager_->Send(new GpuHostMsg_UpdateVSyncParameters(stub_->surface_id(),
- timebase,
- interval));
-}
-
-void ImageTransportHelper::SwapBuffersCompleted(
- const std::vector<ui::LatencyInfo>& latency_info) {
- stub_->SwapBuffersCompleted(latency_info);
-}
-
-void ImageTransportHelper::SetScheduled(bool is_scheduled) {
- gpu::GpuScheduler* scheduler = Scheduler();
- if (!scheduler)
- return;
-
- scheduler->SetScheduled(is_scheduled);
-}
-
-void ImageTransportHelper::DeferToFence(base::Closure task) {
- gpu::GpuScheduler* scheduler = Scheduler();
- DCHECK(scheduler);
-
- scheduler->DeferToFence(task);
-}
-
void ImageTransportHelper::SetPreemptByFlag(
scoped_refptr<gpu::PreemptionFlag> preemption_flag) {
stub_->channel()->SetPreemptByFlag(preemption_flag);
@@ -149,18 +121,13 @@ bool ImageTransportHelper::MakeCurrent() {
}
void ImageTransportHelper::SetSwapInterval(gfx::GLContext* context) {
- if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableGpuVsync))
- context->SetSwapInterval(0);
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableGpuVsync))
+ context->ForceSwapIntervalZero(true);
else
context->SetSwapInterval(1);
}
-gpu::GpuScheduler* ImageTransportHelper::Scheduler() {
- if (!stub_.get())
- return NULL;
- return stub_->scheduler();
-}
-
gpu::gles2::GLES2Decoder* ImageTransportHelper::Decoder() {
if (!stub_.get())
return NULL;
@@ -197,7 +164,8 @@ PassThroughImageTransportSurface::PassThroughImageTransportSurface(
GpuCommandBufferStub* stub,
gfx::GLSurface* surface)
: GLSurfaceAdapter(surface),
- did_set_swap_interval_(false) {
+ did_set_swap_interval_(false),
+ weak_ptr_factory_(this) {
helper_.reset(new ImageTransportHelper(this,
manager,
stub,
@@ -223,33 +191,59 @@ bool PassThroughImageTransportSurface::SwapBuffers() {
// GetVsyncValues before SwapBuffers to work around Mali driver bug:
// crbug.com/223558.
SendVSyncUpdateIfAvailable();
- for (size_t i = 0; i < latency_info_.size(); ++i) {
- latency_info_[i].AddLatencyNumber(
- ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, 0);
- }
- bool result = gfx::GLSurfaceAdapter::SwapBuffers();
- for (size_t i = 0; i < latency_info_.size(); i++) {
- latency_info_[i].AddLatencyNumber(
- ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0);
+
+ base::TimeTicks swap_time = base::TimeTicks::Now();
+ for (auto& latency : latency_info_) {
+ latency.AddLatencyNumberWithTimestamp(
+ ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, 0, swap_time, 1);
}
- helper_->SwapBuffersCompleted(latency_info_);
- latency_info_.clear();
- return result;
+ // We use WeakPtr here to avoid manual management of life time of an instance
+ // of this class. Callback will not be called once the instance of this class
+ // is destroyed. However, this also means that the callback can be run on
+ // the calling thread only.
+ std::vector<ui::LatencyInfo>* latency_info_ptr =
+ new std::vector<ui::LatencyInfo>();
+ latency_info_ptr->swap(latency_info_);
+ return gfx::GLSurfaceAdapter::SwapBuffersAsync(base::Bind(
+ &PassThroughImageTransportSurface::SwapBuffersCallBack,
+ weak_ptr_factory_.GetWeakPtr(), base::Owned(latency_info_ptr)));
}
bool PassThroughImageTransportSurface::PostSubBuffer(
int x, int y, int width, int height) {
SendVSyncUpdateIfAvailable();
- bool result = gfx::GLSurfaceAdapter::PostSubBuffer(x, y, width, height);
- for (size_t i = 0; i < latency_info_.size(); i++) {
- latency_info_[i].AddLatencyNumber(
- ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0);
+
+ base::TimeTicks swap_time = base::TimeTicks::Now();
+ for (auto& latency : latency_info_) {
+ latency.AddLatencyNumberWithTimestamp(
+ ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, 0, swap_time, 1);
+ }
+
+ // We use WeakPtr here to avoid manual management of life time of an instance
+ // of this class. Callback will not be called once the instance of this class
+ // is destroyed. However, this also means that the callback can be run on
+ // the calling thread only.
+ std::vector<ui::LatencyInfo>* latency_info_ptr =
+ new std::vector<ui::LatencyInfo>();
+ latency_info_ptr->swap(latency_info_);
+ return gfx::GLSurfaceAdapter::PostSubBufferAsync(
+ x, y, width, height,
+ base::Bind(&PassThroughImageTransportSurface::SwapBuffersCallBack,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::Owned(latency_info_ptr)));
+}
+
+void PassThroughImageTransportSurface::SwapBuffersCallBack(
+ std::vector<ui::LatencyInfo>* latency_info_ptr) {
+ base::TimeTicks swap_ack_time = base::TimeTicks::Now();
+ for (auto& latency : *latency_info_ptr) {
+ latency.AddLatencyNumberWithTimestamp(
+ ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0,
+ swap_ack_time, 1);
}
- helper_->SwapBuffersCompleted(latency_info_);
- latency_info_.clear();
- return result;
+ helper_->stub()->SendSwapBuffersCompleted(*latency_info_ptr);
}
bool PassThroughImageTransportSurface::OnMakeCurrent(gfx::GLContext* context) {
@@ -286,8 +280,8 @@ void PassThroughImageTransportSurface::SendVSyncUpdateIfAvailable() {
gfx::VSyncProvider* vsync_provider = GetVSyncProvider();
if (vsync_provider) {
vsync_provider->GetVSyncParameters(
- base::Bind(&ImageTransportHelper::SendUpdateVSyncParameters,
- helper_->AsWeakPtr()));
+ base::Bind(&GpuCommandBufferStub::SendUpdateVSyncParameters,
+ helper_->stub()->AsWeakPtr()));
}
}
diff --git a/chromium/content/common/gpu/image_transport_surface.h b/chromium/content/common/gpu/image_transport_surface.h
index fea2d4f0980..d3f2e85adb7 100644
--- a/chromium/content/common/gpu/image_transport_surface.h
+++ b/chromium/content/common/gpu/image_transport_surface.h
@@ -16,9 +16,9 @@
#include "ipc/ipc_listener.h"
#include "ipc/ipc_message.h"
#include "ui/events/latency_info.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/size.h"
#include "ui/gl/gl_surface.h"
struct AcceleratedSurfaceMsg_BufferPresented_Params;
@@ -29,7 +29,6 @@ class GLSurface;
}
namespace gpu {
-class GpuScheduler;
class PreemptionFlag;
namespace gles2 {
class GLES2Decoder;
@@ -124,15 +123,6 @@ class ImageTransportHelper
// like size and surface id. The helper fills in the rest.
void SendAcceleratedSurfaceBuffersSwapped(
GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params);
- void SendUpdateVSyncParameters(
- base::TimeTicks timebase, base::TimeDelta interval);
-
- void SwapBuffersCompleted(const std::vector<ui::LatencyInfo>& latency_info);
-
- // Whether or not we should execute more commands.
- void SetScheduled(bool is_scheduled);
-
- void DeferToFence(base::Closure task);
void SetPreemptByFlag(
scoped_refptr<gpu::PreemptionFlag> preemption_flag);
@@ -147,7 +137,6 @@ class ImageTransportHelper
GpuCommandBufferStub* stub() const { return stub_.get(); }
private:
- gpu::GpuScheduler* Scheduler();
gpu::gles2::GLES2Decoder* Decoder();
// IPC::Message handlers.
@@ -207,6 +196,7 @@ class PassThroughImageTransportSurface
// If updated vsync parameters can be determined, send this information to
// the browser.
virtual void SendVSyncUpdateIfAvailable();
+ void SwapBuffersCallBack(std::vector<ui::LatencyInfo>* latency_info_ptr);
ImageTransportHelper* GetHelper() { return helper_.get(); }
@@ -214,6 +204,7 @@ class PassThroughImageTransportSurface
scoped_ptr<ImageTransportHelper> helper_;
bool did_set_swap_interval_;
std::vector<ui::LatencyInfo> latency_info_;
+ base::WeakPtrFactory<PassThroughImageTransportSurface> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(PassThroughImageTransportSurface);
};
diff --git a/chromium/content/common/gpu/image_transport_surface_android.cc b/chromium/content/common/gpu/image_transport_surface_android.cc
index a2cadd065ac..6d67df285a7 100644
--- a/chromium/content/common/gpu/image_transport_surface_android.cc
+++ b/chromium/content/common/gpu/image_transport_surface_android.cc
@@ -39,11 +39,11 @@ class ImageTransportSurfaceAndroid
const gfx::GLSurfaceHandle& handle);
// gfx::GLSurface implementation.
- virtual bool OnMakeCurrent(gfx::GLContext* context) override;
- virtual void WakeUpGpu() override;
+ bool OnMakeCurrent(gfx::GLContext* context) override;
+ void WakeUpGpu() override;
protected:
- virtual ~ImageTransportSurfaceAndroid();
+ ~ImageTransportSurfaceAndroid() override;
private:
void ScheduleWakeUp();
@@ -59,10 +59,10 @@ class DirectSurfaceAndroid : public PassThroughImageTransportSurface {
gfx::GLSurface* surface);
// gfx::GLSurface implementation.
- virtual bool SwapBuffers() override;
+ bool SwapBuffers() override;
protected:
- virtual ~DirectSurfaceAndroid();
+ ~DirectSurfaceAndroid() override;
private:
DISALLOW_COPY_AND_ASSIGN(DirectSurfaceAndroid);
diff --git a/chromium/content/common/gpu/image_transport_surface_calayer_mac.h b/chromium/content/common/gpu/image_transport_surface_calayer_mac.h
index 1a7c3a211d6..43cd2afb4f1 100644
--- a/chromium/content/common/gpu/image_transport_surface_calayer_mac.h
+++ b/chromium/content/common/gpu/image_transport_surface_calayer_mac.h
@@ -8,7 +8,6 @@
#include "base/mac/scoped_nsobject.h"
#include "content/common/gpu/image_transport_surface_fbo_mac.h"
#include "ui/base/cocoa/remote_layer_api.h"
-#include "ui/gl/gl_bindings.h"
#include "ui/gl/gpu_switching_observer.h"
#include "ui/gl/scoped_cgl.h"
@@ -26,18 +25,20 @@ class CALayerStorageProvider
// ImageTransportSurfaceFBO::StorageProvider implementation:
gfx::Size GetRoundedSize(gfx::Size size) override;
- bool AllocateColorBufferStorage(CGLContextObj context,
- GLuint texture,
- gfx::Size pixel_size,
- float scale_factor) override;
+ bool AllocateColorBufferStorage(
+ CGLContextObj context, const base::Closure& context_dirtied_callback,
+ GLuint texture, gfx::Size pixel_size, float scale_factor) override;
void FreeColorBufferStorage() override;
- void SwapBuffers(const gfx::Size& size, float scale_factor) override;
+ void FrameSizeChanged(
+ const gfx::Size& pixel_size, float scale_factor) override;
+ void SwapBuffers() override;
void WillWriteToBackbuffer() override;
void DiscardBackbuffer() override;
void SwapBuffersAckedByBrowser(bool disable_throttling) override;
// Interface to ImageTransportLayer:
CGLContextObj LayerShareGroupContext();
+ base::Closure LayerShareGroupContextDirtiedCallback();
bool LayerCanDraw();
void LayerDoDraw();
void LayerResetStorageProvider();
@@ -55,7 +56,15 @@ class CALayerStorageProvider
ImageTransportSurfaceFBO* transport_surface_;
// Used to determine if we should use setNeedsDisplay or setAsynchronous to
- // animate.
+ // animate. If the last swap time happened very recently, then
+ // setAsynchronous is used (which allows smooth animation, but comes with the
+ // penalty of the canDrawInCGLContext function waking up the process every
+ // vsync).
+ base::TimeTicks last_synchronous_swap_time_;
+
+ // Used to determine if we should use setNeedsDisplay or setAsynchronous to
+ // animate. If vsync is disabled, an immediate setNeedsDisplay and
+ // displayIfNeeded are called.
const bool gpu_vsync_disabled_;
// Used also to determine if we should wait for CoreAnimation to call our
@@ -73,10 +82,20 @@ class CALayerStorageProvider
// The texture with the pixels to draw, and the share group it is allocated
// in.
base::ScopedTypeRef<CGLContextObj> share_group_context_;
+ base::Closure share_group_context_dirtied_callback_;
GLuint fbo_texture_;
gfx::Size fbo_pixel_size_;
float fbo_scale_factor_;
+ // State for the Core Profile code path.
+ GLuint program_;
+ GLuint vertex_shader_;
+ GLuint fragment_shader_;
+ GLuint position_location_;
+ GLuint tex_location_;
+ GLuint vertex_buffer_;
+ GLuint vertex_array_;
+
// The CALayer that the current frame is being drawn into.
base::scoped_nsobject<CAContext> context_;
base::scoped_nsobject<ImageTransportLayer> layer_;
@@ -99,4 +118,4 @@ class CALayerStorageProvider
} // namespace content
-#endif // CONTENT_COMMON_GPU_IMAGE_TRANSPORT_CALAYER_MAC_H_
+#endif // CONTENT_COMMON_GPU_IMAGE_TRANSPORT_SURFACE_CALAYER_MAC_H_
diff --git a/chromium/content/common/gpu/image_transport_surface_calayer_mac.mm b/chromium/content/common/gpu/image_transport_surface_calayer_mac.mm
index 0147b3c686a..1dddfbfbc0f 100644
--- a/chromium/content/common/gpu/image_transport_surface_calayer_mac.mm
+++ b/chromium/content/common/gpu/image_transport_surface_calayer_mac.mm
@@ -8,7 +8,8 @@
#include "base/command_line.h"
#include "base/mac/sdk_forward_declarations.h"
-#include "content/common/gpu/surface_handle_types_mac.h"
+#include "base/trace_event/trace_event.h"
+#include "ui/accelerated_widget_mac/surface_handle_types.h"
#include "ui/base/cocoa/animation_utils.h"
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gl/gl_gl_api_implementation.h"
@@ -17,10 +18,14 @@
namespace {
const size_t kFramesToKeepCAContextAfterDiscard = 2;
+const size_t kCanDrawFalsesBeforeSwitchFromAsync = 4;
+const base::TimeDelta kMinDeltaToSwitchToAsync =
+ base::TimeDelta::FromSecondsD(1. / 15.);
}
@interface ImageTransportLayer : CAOpenGLLayer {
content::CALayerStorageProvider* storageProvider_;
+ base::Closure didDrawCallback_;
}
- (id)initWithStorageProvider:(content::CALayerStorageProvider*)storageProvider;
- (void)resetStorageProvider;
@@ -51,12 +56,8 @@ const size_t kFramesToKeepCAContextAfterDiscard = 2;
- (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat {
if (!storageProvider_)
return NULL;
- CGLContextObj context = NULL;
- CGLError error = CGLCreateContext(
- pixelFormat, storageProvider_->LayerShareGroupContext(), &context);
- if (error != kCGLNoError)
- DLOG(ERROR) << "CGLCreateContext failed with CGL error: " << error;
- return context;
+ didDrawCallback_ = storageProvider_->LayerShareGroupContextDirtiedCallback();
+ return CGLRetainContext(storageProvider_->LayerShareGroupContext());
}
- (BOOL)canDrawInCGLContext:(CGLContextObj)glContext
@@ -86,6 +87,10 @@ const size_t kFramesToKeepCAContextAfterDiscard = 2;
pixelFormat:pixelFormat
forLayerTime:timeInterval
displayTime:timeStamp];
+
+
+ DCHECK(!didDrawCallback_.is_null());
+ didDrawCallback_.Run();
}
@end
@@ -94,16 +99,23 @@ namespace content {
CALayerStorageProvider::CALayerStorageProvider(
ImageTransportSurfaceFBO* transport_surface)
- : transport_surface_(transport_surface),
- gpu_vsync_disabled_(CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableGpuVsync)),
- throttling_disabled_(false),
- has_pending_draw_(false),
- can_draw_returned_false_count_(0),
- fbo_texture_(0),
- fbo_scale_factor_(1),
- recreate_layer_after_gpu_switch_(false),
- pending_draw_weak_factory_(this) {
+ : transport_surface_(transport_surface),
+ gpu_vsync_disabled_(base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableGpuVsync)),
+ throttling_disabled_(false),
+ has_pending_draw_(false),
+ can_draw_returned_false_count_(0),
+ fbo_texture_(0),
+ fbo_scale_factor_(1),
+ program_(0),
+ vertex_shader_(0),
+ fragment_shader_(0),
+ position_location_(0),
+ tex_location_(0),
+ vertex_buffer_(0),
+ vertex_array_(0),
+ recreate_layer_after_gpu_switch_(false),
+ pending_draw_weak_factory_(this) {
ui::GpuSwitchingManager::GetInstance()->AddObserver(this);
}
@@ -116,33 +128,131 @@ gfx::Size CALayerStorageProvider::GetRoundedSize(gfx::Size size) {
}
bool CALayerStorageProvider::AllocateColorBufferStorage(
- CGLContextObj context, GLuint texture,
- gfx::Size pixel_size, float scale_factor) {
+ CGLContextObj context, const base::Closure& context_dirtied_callback,
+ GLuint texture, gfx::Size pixel_size, float scale_factor) {
// Allocate an ordinary OpenGL texture to back the FBO.
GLenum error;
while ((error = glGetError()) != GL_NO_ERROR) {
- DLOG(ERROR) << "Error found (and ignored) before allocating buffer "
- << "storage: " << error;
+ LOG(ERROR) << "OpenGL error hit but ignored before allocating buffer "
+ << "storage: " << error;
}
- glTexImage2D(GL_TEXTURE_RECTANGLE_ARB,
- 0,
- GL_RGBA,
- pixel_size.width(),
- pixel_size.height(),
- 0,
- GL_RGBA,
- GL_UNSIGNED_BYTE,
- NULL);
- error = glGetError();
- if (error != GL_NO_ERROR) {
- DLOG(ERROR) << "glTexImage failed with GL error: " << error;
- return false;
+
+ if (gfx::GetGLImplementation() ==
+ gfx::kGLImplementationDesktopGLCoreProfile) {
+ glTexImage2D(GL_TEXTURE_2D,
+ 0,
+ GL_RGBA,
+ pixel_size.width(),
+ pixel_size.height(),
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ NULL);
+ glFlush();
+
+ if (!vertex_shader_) {
+ const char* source =
+ "#version 150\n"
+ "in vec4 position;\n"
+ "out vec2 texcoord;\n"
+ "void main() {\n"
+ " texcoord = vec2(position.x, position.y);\n"
+ " gl_Position = vec4(2*position.x-1, 2*position.y-1,\n"
+ " position.z, position.w);\n"
+ "}\n";
+ vertex_shader_ = glCreateShader(GL_VERTEX_SHADER);
+ glShaderSource(vertex_shader_, 1, &source, NULL);
+ glCompileShader(vertex_shader_);
+#if DCHECK_IS_ON()
+ GLint status = GL_FALSE;
+ glGetShaderiv(vertex_shader_, GL_COMPILE_STATUS, &status);
+ DCHECK(status == GL_TRUE);
+#endif
+ }
+ if (!fragment_shader_) {
+ const char* source =
+ "#version 150\n"
+ "uniform sampler2D tex;\n"
+ "in vec2 texcoord;\n"
+ "out vec4 frag_color;\n"
+ "void main() {\n"
+ " frag_color = texture(tex, texcoord);\n"
+ "}\n";
+ fragment_shader_ = glCreateShader(GL_FRAGMENT_SHADER);
+ glShaderSource(fragment_shader_, 1, &source, NULL);
+ glCompileShader(fragment_shader_);
+#if DCHECK_IS_ON()
+ GLint status = GL_FALSE;
+ glGetShaderiv(fragment_shader_, GL_COMPILE_STATUS, &status);
+ DCHECK(status == GL_TRUE);
+#endif
+ }
+ if (!program_) {
+ program_ = glCreateProgram();
+ glAttachShader(program_, vertex_shader_);
+ glAttachShader(program_, fragment_shader_);
+ glBindFragDataLocation(program_, 0, "frag_color");
+ glLinkProgram(program_);
+#if DCHECK_IS_ON()
+ GLint status = GL_FALSE;
+ glGetProgramiv(program_, GL_LINK_STATUS, &status);
+ DCHECK(status == GL_TRUE);
+#endif
+ position_location_ = glGetAttribLocation(program_, "position");
+ tex_location_ = glGetUniformLocation(program_, "tex");
+ }
+ if (!vertex_buffer_) {
+ GLfloat vertex_data[24] = {
+ 0, 0, 0, 1,
+ 1, 0, 0, 1,
+ 1, 1, 0, 1,
+ 1, 1, 0, 1,
+ 0, 1, 0, 1,
+ 0, 0, 0, 1,
+ };
+ glGenBuffersARB(1, &vertex_buffer_);
+ glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data),
+ vertex_data, GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ }
+ if (!vertex_array_) {
+ glGenVertexArraysOES(1, &vertex_array_);
+ glBindVertexArrayOES(vertex_array_);
+ {
+ glEnableVertexAttribArray(position_location_);
+ glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_);
+ glVertexAttribPointer(position_location_, 4, GL_FLOAT, GL_FALSE, 0, 0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ }
+ glBindVertexArrayOES(0);
+ }
+ } else {
+ glTexImage2D(GL_TEXTURE_RECTANGLE_ARB,
+ 0,
+ GL_RGBA,
+ pixel_size.width(),
+ pixel_size.height(),
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ NULL);
+ glFlush();
}
- glFlush();
+
+ bool hit_error = false;
+ while ((error = glGetError()) != GL_NO_ERROR) {
+ LOG(ERROR) << "OpenGL error hit while trying to allocate buffer storage: "
+ << error;
+ hit_error = true;
+ }
+ if (hit_error)
+ return false;
// Set the parameters that will be used to allocate the CALayer to draw the
// texture into.
share_group_context_.reset(CGLRetainContext(context));
+ share_group_context_dirtied_callback_ = context_dirtied_callback;
fbo_texture_ = texture;
fbo_pixel_size_ = pixel_size;
fbo_scale_factor_ = scale_factor;
@@ -150,21 +260,51 @@ bool CALayerStorageProvider::AllocateColorBufferStorage(
}
void CALayerStorageProvider::FreeColorBufferStorage() {
+ if (gfx::GetGLImplementation() ==
+ gfx::kGLImplementationDesktopGLCoreProfile) {
+ if (vertex_shader_)
+ glDeleteShader(vertex_shader_);
+ if (fragment_shader_)
+ glDeleteShader(fragment_shader_);
+ if (program_)
+ glDeleteProgram(program_);
+ if (vertex_buffer_)
+ glDeleteBuffersARB(1, &vertex_buffer_);
+ if (vertex_array_)
+ glDeleteVertexArraysOES(1, &vertex_array_);
+ vertex_shader_ = 0;
+ fragment_shader_ = 0;
+ program_ = 0;
+ vertex_buffer_ = 0;
+ vertex_array_ = 0;
+ }
+
// Note that |context_| still holds a reference to |layer_|, and will until
// a new frame is swapped in.
[layer_ resetStorageProvider];
layer_.reset();
share_group_context_.reset();
+ share_group_context_dirtied_callback_ = base::Closure();
fbo_texture_ = 0;
fbo_pixel_size_ = gfx::Size();
can_draw_returned_false_count_ = 0;
}
-void CALayerStorageProvider::SwapBuffers(
- const gfx::Size& size, float scale_factor) {
+void CALayerStorageProvider::FrameSizeChanged(const gfx::Size& pixel_size,
+ float scale_factor) {
+ DCHECK_EQ(fbo_pixel_size_.ToString(), pixel_size.ToString());
+ DCHECK_EQ(fbo_scale_factor_, scale_factor);
+}
+
+void CALayerStorageProvider::SwapBuffers() {
+ TRACE_EVENT0("gpu", "CALayerStorageProvider::SwapBuffers");
DCHECK(!has_pending_draw_);
+ // A trace value of 2 indicates that there is a pending swap ack. See
+ // LayerCanDraw for other value meanings.
+ TRACE_COUNTER_ID1("gpu", "CALayerPendingSwap", this, 2);
+
// Recreate the CALayer on the new GPU if a GPU switch has occurred. Note
// that the CAContext will retain a reference to the old CALayer until the
// call to -[CAContext setLayer:] replaces the old CALayer with the new one.
@@ -188,7 +328,8 @@ void CALayerStorageProvider::SwapBuffers(
[context_ retain];
}
- // Allocate a CALayer to use to draw the content, if needed.
+ // Allocate a CALayer to use to draw the content and make it current to the
+ // CAContext, if needed.
if (!layer_) {
layer_.reset([[ImageTransportLayer alloc] initWithStorageProvider:this]);
gfx::Size dip_size(gfx::ToFlooredSize(gfx::ScaleSize(
@@ -196,13 +337,11 @@ void CALayerStorageProvider::SwapBuffers(
[layer_ setContentsScale:fbo_scale_factor_];
[layer_ setFrame:CGRectMake(0, 0, dip_size.width(), dip_size.height())];
- // Make the CALayer current to the CAContext and display its contents
- // immediately.
[context_ setLayer:layer_];
}
// Replacing the CAContext's CALayer will sometimes results in an immediate
- // draw. If that happens, early-out.
+ // draw.
if (!has_pending_draw_)
return;
@@ -210,8 +349,19 @@ void CALayerStorageProvider::SwapBuffers(
if (gpu_vsync_disabled_ || throttling_disabled_) {
DrawImmediatelyAndUnblockBrowser();
} else {
- if (![layer_ isAsynchronous])
- [layer_ setAsynchronous:YES];
+ if (![layer_ isAsynchronous]) {
+ // Switch to asynchronous drawing only if we get two frames in rapid
+ // succession.
+ base::TimeTicks this_swap_time = base::TimeTicks::Now();
+ base::TimeDelta delta = this_swap_time - last_synchronous_swap_time_;
+ if (delta <= kMinDeltaToSwitchToAsync) {
+ last_synchronous_swap_time_ = base::TimeTicks();
+ [layer_ setAsynchronous:YES];
+ } else {
+ last_synchronous_swap_time_ = this_swap_time;
+ [layer_ setNeedsDisplay];
+ }
+ }
// If CoreAnimation doesn't end up drawing our frame, un-block the browser
// after a timeout of 1/6th of a second has passed.
@@ -272,6 +422,7 @@ void CALayerStorageProvider::DiscardBackbuffer() {
void CALayerStorageProvider::SwapBuffersAckedByBrowser(
bool disable_throttling) {
+ TRACE_EVENT0("gpu", "CALayerStorageProvider::SwapBuffersAckedByBrowser");
throttling_disabled_ = disable_throttling;
if (!previously_discarded_contexts_.empty())
previously_discarded_contexts_.pop_front();
@@ -281,7 +432,29 @@ CGLContextObj CALayerStorageProvider::LayerShareGroupContext() {
return share_group_context_;
}
+base::Closure CALayerStorageProvider::LayerShareGroupContextDirtiedCallback() {
+ return share_group_context_dirtied_callback_;
+}
+
bool CALayerStorageProvider::LayerCanDraw() {
+ TRACE_EVENT0("gpu", "CALayerStorageProvider::LayerCanDraw");
+
+ // This tracing would be more natural to do with a pseudo-thread for each
+ // layer, rather than a counter.
+ // http://crbug.com/366300
+ if (has_pending_draw_) {
+ // If there is a draw pending then increase the signal from 2 to 3, to
+ // indicate that there is a swap pending, and CoreAnimation has asked to
+ // draw it.
+ TRACE_COUNTER_ID1("gpu", "CALayerPendingSwap", this, 3);
+ } else {
+ // If there is not a draw pending, then give an instantaneous blip up from
+ // 0 to 1, indicating that CoreAnimation was ready to draw a frame but we
+ // were not (or didn't have new content to draw).
+ TRACE_COUNTER_ID1("gpu", "CALayerPendingSwap", this, 1);
+ TRACE_COUNTER_ID1("gpu", "CALayerPendingSwap", this, 0);
+ }
+
if (has_pending_draw_) {
can_draw_returned_false_count_ = 0;
return true;
@@ -289,10 +462,10 @@ bool CALayerStorageProvider::LayerCanDraw() {
if ([layer_ isAsynchronous]) {
DCHECK(!gpu_vsync_disabled_);
// If we are in asynchronous mode, we will be getting callbacks at every
- // vsync, asking us if we have anything to draw. If we get 30 of these in
- // a row, ask that we stop getting these callback for now, so that we
+ // vsync, asking us if we have anything to draw. If we get many of these
+ // in a row, ask that we stop getting these callback for now, so that we
// don't waste CPU cycles.
- if (can_draw_returned_false_count_ == 30)
+ if (can_draw_returned_false_count_ >= kCanDrawFalsesBeforeSwitchFromAsync)
[layer_ setAsynchronous:NO];
else
can_draw_returned_false_count_ += 1;
@@ -302,38 +475,70 @@ bool CALayerStorageProvider::LayerCanDraw() {
}
void CALayerStorageProvider::LayerDoDraw() {
- GLint viewport[4] = {0, 0, 0, 0};
- glGetIntegerv(GL_VIEWPORT, viewport);
- gfx::Size viewport_size(viewport[2], viewport[3]);
-
- // Set the coordinate system to be one-to-one with pixels.
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glOrtho(0, viewport_size.width(), 0, viewport_size.height(), -1, 1);
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
-
- // Draw a fullscreen quad.
- glColor4f(1, 1, 1, 1);
- glEnable(GL_TEXTURE_RECTANGLE_ARB);
- glBindTexture(GL_TEXTURE_RECTANGLE_ARB, fbo_texture_);
- glBegin(GL_QUADS);
- {
- glTexCoord2f(0, 0);
- glVertex2f(0, 0);
-
- glTexCoord2f(0, fbo_pixel_size_.height());
- glVertex2f(0, fbo_pixel_size_.height());
-
- glTexCoord2f(fbo_pixel_size_.width(), fbo_pixel_size_.height());
- glVertex2f(fbo_pixel_size_.width(), fbo_pixel_size_.height());
-
- glTexCoord2f(fbo_pixel_size_.width(), 0);
- glVertex2f(fbo_pixel_size_.width(), 0);
+ TRACE_EVENT0("gpu", "CALayerStorageProvider::LayerDoDraw");
+ if (gfx::GetGLImplementation() ==
+ gfx::kGLImplementationDesktopGLCoreProfile) {
+ glClearColor(1, 0, 1, 1);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glDisable(GL_BLEND);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_SCISSOR_TEST);
+
+ DCHECK(glIsProgram(program_));
+ glUseProgram(program_);
+ glBindVertexArrayOES(vertex_array_);
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, fbo_texture_);
+ glUniform1i(tex_location_, 0);
+
+ glDisable(GL_CULL_FACE);
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+ glBindVertexArrayOES(0);
+ glUseProgram(0);
+ } else {
+ GLint viewport[4] = {0, 0, 0, 0};
+ glGetIntegerv(GL_VIEWPORT, viewport);
+ gfx::Size viewport_size(viewport[2], viewport[3]);
+
+ // Set the coordinate system to be one-to-one with pixels.
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0, viewport_size.width(), 0, viewport_size.height(), -1, 1);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ // Reset drawing state and draw a fullscreen quad.
+ glUseProgram(0);
+ glDisable(GL_BLEND);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_SCISSOR_TEST);
+ glColor4f(1, 1, 1, 1);
+ glActiveTexture(GL_TEXTURE0);
+ glEnable(GL_TEXTURE_RECTANGLE_ARB);
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, fbo_texture_);
+ glBegin(GL_QUADS);
+ {
+ glTexCoord2f(0, 0);
+ glVertex2f(0, 0);
+
+ glTexCoord2f(0, fbo_pixel_size_.height());
+ glVertex2f(0, fbo_pixel_size_.height());
+
+ glTexCoord2f(fbo_pixel_size_.width(), fbo_pixel_size_.height());
+ glVertex2f(fbo_pixel_size_.width(), fbo_pixel_size_.height());
+
+ glTexCoord2f(fbo_pixel_size_.width(), 0);
+ glVertex2f(fbo_pixel_size_.width(), 0);
+ }
+ glEnd();
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
+ glDisable(GL_TEXTURE_RECTANGLE_ARB);
}
- glEnd();
- glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
- glDisable(GL_TEXTURE_RECTANGLE_ARB);
GLint current_renderer_id = 0;
if (CGLGetParameter(CGLGetCurrentContext(),
@@ -343,6 +548,11 @@ void CALayerStorageProvider::LayerDoDraw() {
transport_surface_->SetRendererID(current_renderer_id);
}
+ GLenum error;
+ while ((error = glGetError()) != GL_NO_ERROR) {
+ LOG(ERROR) << "OpenGL error hit while drawing frame: " << error;
+ }
+
// Allow forward progress in the context now that the swap is complete.
UnblockBrowserIfNeeded();
}
@@ -363,9 +573,12 @@ void CALayerStorageProvider::UnblockBrowserIfNeeded() {
pending_draw_weak_factory_.InvalidateWeakPtrs();
has_pending_draw_ = false;
transport_surface_->SendSwapBuffers(
- SurfaceHandleFromCAContextID([context_ contextId]),
+ ui::SurfaceHandleFromCAContextID([context_ contextId]),
fbo_pixel_size_,
fbo_scale_factor_);
+
+ // A trace value of 0 indicates that there is no longer a pending swap ack.
+ TRACE_COUNTER_ID1("gpu", "CALayerPendingSwap", this, 0);
}
} // namespace content
diff --git a/chromium/content/common/gpu/image_transport_surface_fbo_mac.h b/chromium/content/common/gpu/image_transport_surface_fbo_mac.h
index dbcdc83f7a3..d5a0c2011f8 100644
--- a/chromium/content/common/gpu/image_transport_surface_fbo_mac.h
+++ b/chromium/content/common/gpu/image_transport_surface_fbo_mac.h
@@ -34,16 +34,20 @@ class ImageTransportSurfaceFBO
// Allocate the storage for the color buffer. The specified context is
// current, and there is a texture bound to GL_TEXTURE_RECTANGLE_ARB.
virtual bool AllocateColorBufferStorage(
- CGLContextObj context, GLuint texture,
- gfx::Size size, float scale_factor) = 0;
+ CGLContextObj context, const base::Closure& context_dirtied_callback,
+ GLuint texture, gfx::Size size, float scale_factor) = 0;
// Free the storage allocated in the AllocateColorBufferStorage call. The
// GL texture that was bound has already been deleted by the caller.
virtual void FreeColorBufferStorage() = 0;
- // Swap buffers and return the handle for the surface to send to the browser
- // process to display.
- virtual void SwapBuffers(const gfx::Size& size, float scale_factor) = 0;
+ // Called when the frame size has changed (the buffer may not have been
+ // reallocated, since its size may be rounded).
+ virtual void FrameSizeChanged(
+ const gfx::Size& pixel_size, float scale_factor) = 0;
+
+ // Swap buffers, or post sub-buffer.
+ virtual void SwapBuffers() = 0;
// Indicate that the backbuffer will be written to.
virtual void WillWriteToBackbuffer() = 0;
@@ -74,6 +78,7 @@ class ImageTransportSurfaceFBO
void* GetHandle() override;
void* GetDisplay() override;
bool OnMakeCurrent(gfx::GLContext* context) override;
+ void NotifyWasBound() override;
unsigned int GetBackingFrameBufferObject() override;
bool SetBackbufferAllocation(bool allocated) override;
void SetFrontbufferAllocation(bool allocated) override;
@@ -102,6 +107,7 @@ class ImageTransportSurfaceFBO
void DestroyFramebuffer();
void AllocateOrResizeFramebuffer(
const gfx::Size& pixel_size, float scale_factor);
+ bool SwapBuffersInternal();
scoped_ptr<StorageProvider> storage_provider_;
@@ -135,4 +141,4 @@ class ImageTransportSurfaceFBO
} // namespace content
-#endif // CONTENT_COMMON_GPU_IMAGE_TRANSPORT_SURFACE_MAC_H_
+#endif // CONTENT_COMMON_GPU_IMAGE_TRANSPORT_SURFACE_FBO_MAC_H_
diff --git a/chromium/content/common/gpu/image_transport_surface_fbo_mac.mm b/chromium/content/common/gpu/image_transport_surface_fbo_mac.mm
index 6af794d552e..f1aa838a778 100644
--- a/chromium/content/common/gpu/image_transport_surface_fbo_mac.mm
+++ b/chromium/content/common/gpu/image_transport_surface_fbo_mac.mm
@@ -4,6 +4,7 @@
#include "content/common/gpu/image_transport_surface_fbo_mac.h"
+#include "base/trace_event/trace_event.h"
#include "content/common/gpu/gpu_messages.h"
#include "content/common/gpu/image_transport_surface_calayer_mac.h"
#include "content/common/gpu/image_transport_surface_iosurface_mac.h"
@@ -15,6 +16,13 @@
namespace content {
+scoped_refptr<gfx::GLSurface> ImageTransportSurfaceCreateNativeSurface(
+ GpuChannelManager* manager,
+ GpuCommandBufferStub* stub,
+ gfx::PluginWindowHandle handle) {
+ return new ImageTransportSurfaceFBO(manager, stub, handle);
+}
+
ImageTransportSurfaceFBO::ImageTransportSurfaceFBO(
GpuChannelManager* manager,
GpuCommandBufferStub* stub,
@@ -43,7 +51,9 @@ bool ImageTransportSurfaceFBO::Initialize() {
// Only support IOSurfaces if the GL implementation is the native desktop GL.
// IO surfaces will not work with, for example, OSMesa software renderer
// GL contexts.
- if (gfx::GetGLImplementation() != gfx::kGLImplementationDesktopGL &&
+ if (gfx::GetGLImplementation() !=
+ gfx::kGLImplementationDesktopGLCoreProfile &&
+ gfx::GetGLImplementation() != gfx::kGLImplementationDesktopGL &&
gfx::GetGLImplementation() != gfx::kGLImplementationAppleGL)
return false;
@@ -62,6 +72,10 @@ bool ImageTransportSurfaceFBO::DeferDraws() {
storage_provider_->WillWriteToBackbuffer();
// We should not have a pending send when we are drawing the next frame.
DCHECK(!is_swap_buffers_send_pending_);
+
+ // The call to WillWriteToBackbuffer could potentially force a draw. Ensure
+ // that any changes made to the context's state are restored.
+ context_->RestoreStateIfDirtiedExternally();
return false;
}
@@ -81,6 +95,47 @@ bool ImageTransportSurfaceFBO::OnMakeCurrent(gfx::GLContext* context) {
return true;
}
+void ImageTransportSurfaceFBO::NotifyWasBound() {
+ // Sometimes calling glBindFramebuffer doesn't seem to be enough to get
+ // rendered contents to show up in the color attachment. It appears that doing
+ // a glBegin/End pair with program 0 is enough to tickle the driver into
+ // actually effecting the binding.
+ // http://crbug.com/435786
+ DCHECK(has_complete_framebuffer_);
+
+ // We will restore the current program after the dummy glBegin/End pair.
+ // Ensure that we will be able to restore this state before attempting to
+ // change it.
+ GLint old_program_signed = 0;
+ glGetIntegerv(GL_CURRENT_PROGRAM, &old_program_signed);
+ GLuint old_program = static_cast<GLuint>(old_program_signed);
+ if (old_program && glIsProgram(old_program)) {
+ // A deleted program cannot be re-bound.
+ GLint delete_status = GL_FALSE;
+ glGetProgramiv(old_program, GL_DELETE_STATUS, &delete_status);
+ if (delete_status == GL_TRUE)
+ return;
+ // A program which has had the most recent link fail cannot be re-bound.
+ GLint link_status = GL_FALSE;
+ glGetProgramiv(old_program, GL_LINK_STATUS, &link_status);
+ if (link_status != GL_TRUE)
+ return;
+ }
+
+ // Issue the dummy call and then restore the state.
+ glUseProgram(0);
+ GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+ DCHECK(status == GL_FRAMEBUFFER_COMPLETE);
+ if (gfx::GetGLImplementation() == gfx::kGLImplementationDesktopGL) {
+ // These aren't present in the core profile.
+ // TODO(ccameron): verify this workaround isn't still needed with
+ // the core profile.
+ glBegin(GL_TRIANGLES);
+ glEnd();
+ }
+ glUseProgram(old_program);
+}
+
unsigned int ImageTransportSurfaceFBO::GetBackingFrameBufferObject() {
return fbo_id_;
}
@@ -115,6 +170,11 @@ void ImageTransportSurfaceFBO::AdjustBufferAllocation() {
}
bool ImageTransportSurfaceFBO::SwapBuffers() {
+ TRACE_EVENT0("gpu", "ImageTransportSurfaceFBO::SwapBuffers");
+ return SwapBuffersInternal();
+}
+
+bool ImageTransportSurfaceFBO::SwapBuffersInternal() {
DCHECK(backbuffer_suggested_allocation_);
if (!frontbuffer_suggested_allocation_)
return true;
@@ -122,13 +182,18 @@ bool ImageTransportSurfaceFBO::SwapBuffers() {
// It is the responsibility of the storage provider to send the swap IPC.
is_swap_buffers_send_pending_ = true;
- storage_provider_->SwapBuffers(pixel_size_, scale_factor_);
+ storage_provider_->SwapBuffers();
+
+ // The call to swapBuffers could potentially result in an immediate draw.
+ // Ensure that any changes made to the context's state are restored.
+ context_->RestoreStateIfDirtiedExternally();
return true;
}
void ImageTransportSurfaceFBO::SendSwapBuffers(uint64 surface_handle,
const gfx::Size pixel_size,
float scale_factor) {
+ TRACE_EVENT0("gpu", "ImageTransportSurfaceFBO::SendSwapBuffers");
GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params;
params.surface_handle = surface_handle;
params.size = pixel_size;
@@ -145,9 +210,8 @@ void ImageTransportSurfaceFBO::SetRendererID(int renderer_id) {
bool ImageTransportSurfaceFBO::PostSubBuffer(
int x, int y, int width, int height) {
- // Mac does not support sub-buffer swaps.
- NOTREACHED();
- return false;
+ TRACE_EVENT0("gpu", "ImageTransportSurfaceFBO::PostSubBuffer");
+ return SwapBuffersInternal();
}
bool ImageTransportSurfaceFBO::SupportsPostSubBuffer() {
@@ -168,6 +232,7 @@ void* ImageTransportSurfaceFBO::GetDisplay() {
void ImageTransportSurfaceFBO::OnBufferPresented(
const AcceleratedSurfaceMsg_BufferPresented_Params& params) {
+ TRACE_EVENT0("gpu", "ImageTransportSurfaceFBO::OnBufferPresented");
SetRendererID(params.renderer_id);
storage_provider_->SwapBuffersAckedByBrowser(params.disable_throttling);
}
@@ -244,8 +309,10 @@ void ImageTransportSurfaceFBO::AllocateOrResizeFramebuffer(
rounded_pixel_size_ = new_rounded_pixel_size;
scale_factor_ = new_scale_factor;
- if (!needs_new_storage)
+ if (!needs_new_storage) {
+ storage_provider_->FrameSizeChanged(pixel_size_, scale_factor_);
return;
+ }
TRACE_EVENT2("gpu", "ImageTransportSurfaceFBO::AllocateOrResizeFramebuffer",
"width", new_rounded_pixel_size.width(),
@@ -254,7 +321,19 @@ void ImageTransportSurfaceFBO::AllocateOrResizeFramebuffer(
// GL_TEXTURE_RECTANGLE_ARB is the best supported render target on
// Mac OS X and is required for IOSurface interoperability.
GLint previous_texture_id = 0;
- glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &previous_texture_id);
+
+ GLenum texture_target = GL_TEXTURE_RECTANGLE_ARB;
+ GLenum texture_binding_target = GL_TEXTURE_BINDING_RECTANGLE_ARB;
+ // However, the remote core animation path on the core profile will
+ // be the preferred combination going forward.
+ if (gfx::GetGLImplementation() ==
+ gfx::kGLImplementationDesktopGLCoreProfile &&
+ ui::RemoteLayerAPISupported()) {
+ texture_target = GL_TEXTURE_2D;
+ texture_binding_target = GL_TEXTURE_BINDING_2D;
+ }
+
+ glGetIntegerv(texture_binding_target, &previous_texture_id);
// Free the old IO Surface first to reduce memory fragmentation.
DestroyFramebuffer();
@@ -264,17 +343,17 @@ void ImageTransportSurfaceFBO::AllocateOrResizeFramebuffer(
glGenTextures(1, &texture_id_);
- glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture_id_);
- glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,
+ glBindTexture(texture_target, texture_id_);
+ glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(texture_target,
GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,
+ glTexParameteri(texture_target,
GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
GL_COLOR_ATTACHMENT0_EXT,
- GL_TEXTURE_RECTANGLE_ARB,
+ texture_target,
texture_id_,
0);
@@ -310,8 +389,10 @@ void ImageTransportSurfaceFBO::AllocateOrResizeFramebuffer(
}
bool allocated_color_buffer = storage_provider_->AllocateColorBufferStorage(
- static_cast<CGLContextObj>(context_->GetHandle()), texture_id_,
- rounded_pixel_size_, scale_factor_);
+ static_cast<CGLContextObj>(
+ context_->GetHandle()),
+ context_->GetStateWasDirtiedExternallyCallback(),
+ texture_id_, rounded_pixel_size_, scale_factor_);
if (!allocated_color_buffer) {
DLOG(ERROR) << "Failed to allocate color buffer storage.";
DestroyFramebuffer();
@@ -326,8 +407,9 @@ void ImageTransportSurfaceFBO::AllocateOrResizeFramebuffer(
}
has_complete_framebuffer_ = true;
+ storage_provider_->FrameSizeChanged(pixel_size_, scale_factor_);
- glBindTexture(GL_TEXTURE_RECTANGLE_ARB, previous_texture_id);
+ glBindTexture(texture_target, previous_texture_id);
// The FBO remains bound for this GL context.
}
diff --git a/chromium/content/common/gpu/image_transport_surface_iosurface_mac.cc b/chromium/content/common/gpu/image_transport_surface_iosurface_mac.cc
index 121a3a2f2ba..2b61810884f 100644
--- a/chromium/content/common/gpu/image_transport_surface_iosurface_mac.cc
+++ b/chromium/content/common/gpu/image_transport_surface_iosurface_mac.cc
@@ -5,7 +5,7 @@
#include "content/common/gpu/image_transport_surface_iosurface_mac.h"
#include "content/common/gpu/gpu_messages.h"
-#include "content/common/gpu/surface_handle_types_mac.h"
+#include "ui/accelerated_widget_mac/surface_handle_types.h"
namespace content {
namespace {
@@ -42,7 +42,8 @@ void AddIntegerValue(CFMutableDictionaryRef dictionary,
IOSurfaceStorageProvider::IOSurfaceStorageProvider(
ImageTransportSurfaceFBO* transport_surface)
- : transport_surface_(transport_surface) {}
+ : transport_surface_(transport_surface),
+ frame_scale_factor_(1) {}
IOSurfaceStorageProvider::~IOSurfaceStorageProvider() {
DCHECK(!io_surface_);
@@ -54,8 +55,8 @@ gfx::Size IOSurfaceStorageProvider::GetRoundedSize(gfx::Size size) {
}
bool IOSurfaceStorageProvider::AllocateColorBufferStorage(
- CGLContextObj context, GLuint texture,
- gfx::Size pixel_size, float scale_factor) {
+ CGLContextObj context, const base::Closure& context_dirtied_callback,
+ GLuint texture, gfx::Size pixel_size, float scale_factor) {
// Allocate a new IOSurface, which is the GPU resource that can be
// shared across processes.
base::ScopedCFTypeRef<CFMutableDictionaryRef> properties;
@@ -105,8 +106,13 @@ void IOSurfaceStorageProvider::FreeColorBufferStorage() {
io_surface_id_ = 0;
}
-void IOSurfaceStorageProvider::SwapBuffers(
- const gfx::Size& size, float scale_factor) {
+void IOSurfaceStorageProvider::FrameSizeChanged(const gfx::Size& pixel_size,
+ float scale_factor) {
+ frame_pixel_size_ = pixel_size;
+ frame_scale_factor_ = scale_factor;
+}
+
+void IOSurfaceStorageProvider::SwapBuffers() {
// The browser compositor will throttle itself, so we are free to unblock the
// context immediately. Make sure that the browser is doing its throttling
// appropriately by ensuring that the previous swap was acknowledged before
@@ -115,7 +121,9 @@ void IOSurfaceStorageProvider::SwapBuffers(
pending_swapped_surfaces_.push_back(io_surface_);
transport_surface_->SendSwapBuffers(
- SurfaceHandleFromIOSurfaceID(io_surface_id_), size, scale_factor);
+ ui::SurfaceHandleFromIOSurfaceID(io_surface_id_),
+ frame_pixel_size_,
+ frame_scale_factor_);
}
void IOSurfaceStorageProvider::WillWriteToBackbuffer() {
diff --git a/chromium/content/common/gpu/image_transport_surface_iosurface_mac.h b/chromium/content/common/gpu/image_transport_surface_iosurface_mac.h
index 4d49018e4f1..90625959b0a 100644
--- a/chromium/content/common/gpu/image_transport_surface_iosurface_mac.h
+++ b/chromium/content/common/gpu/image_transport_surface_iosurface_mac.h
@@ -8,7 +8,6 @@
#include <list>
#include "content/common/gpu/image_transport_surface_fbo_mac.h"
-#include "ui/gl/gl_bindings.h"
// Note that this must be included after gl_bindings.h to avoid conflicts.
#include <OpenGL/CGLIOSurface.h>
@@ -24,12 +23,13 @@ class IOSurfaceStorageProvider
// ImageTransportSurfaceFBO::StorageProvider implementation:
gfx::Size GetRoundedSize(gfx::Size size) override;
- bool AllocateColorBufferStorage(CGLContextObj context,
- GLuint texture,
- gfx::Size pixel_size,
- float scale_factor) override;
+ bool AllocateColorBufferStorage(
+ CGLContextObj context, const base::Closure& context_dirtied_callback,
+ GLuint texture, gfx::Size pixel_size, float scale_factor) override;
void FreeColorBufferStorage() override;
- void SwapBuffers(const gfx::Size& size, float scale_factor) override;
+ void FrameSizeChanged(
+ const gfx::Size& pixel_size, float scale_factor) override;
+ void SwapBuffers() override;
void WillWriteToBackbuffer() override;
void DiscardBackbuffer() override;
void SwapBuffersAckedByBrowser(bool disable_throttling) override;
@@ -38,6 +38,8 @@ class IOSurfaceStorageProvider
ImageTransportSurfaceFBO* transport_surface_;
base::ScopedCFTypeRef<IOSurfaceRef> io_surface_;
+ gfx::Size frame_pixel_size_;
+ float frame_scale_factor_;
// The list of IOSurfaces that have been sent to the browser process but have
// not been opened in the browser process yet. This list should never have
@@ -52,4 +54,4 @@ class IOSurfaceStorageProvider
} // namespace content
-#endif // CONTENT_COMMON_GPU_IMAGE_TRANSPORT_SURFACE_MAC_H_
+#endif // CONTENT_COMMON_GPU_IMAGE_TRANSPORT_SURFACE_IOSURFACE_MAC_H_
diff --git a/chromium/content/common/gpu/image_transport_surface_linux.cc b/chromium/content/common/gpu/image_transport_surface_linux.cc
index b648b197c5c..db36efea135 100644
--- a/chromium/content/common/gpu/image_transport_surface_linux.cc
+++ b/chromium/content/common/gpu/image_transport_surface_linux.cc
@@ -13,9 +13,13 @@ scoped_refptr<gfx::GLSurface> ImageTransportSurface::CreateNativeSurface(
const gfx::GLSurfaceHandle& handle) {
DCHECK(handle.handle);
DCHECK(handle.transport_type == gfx::NATIVE_DIRECT);
- scoped_refptr<gfx::GLSurface> surface =
- gfx::GLSurface::CreateViewGLSurface(handle.handle);
- if (!surface.get())
+ scoped_refptr<gfx::GLSurface> surface;
+#if defined(USE_OZONE)
+ surface = gfx::GLSurface::CreateSurfacelessViewGLSurface(handle.handle);
+#endif
+ if (!surface)
+ surface = gfx::GLSurface::CreateViewGLSurface(handle.handle);
+ if (!surface)
return surface;
return scoped_refptr<gfx::GLSurface>(new PassThroughImageTransportSurface(
manager, stub, surface.get()));
diff --git a/chromium/content/common/gpu/image_transport_surface_mac.mm b/chromium/content/common/gpu/image_transport_surface_mac.mm
index 0f40f23f1a3..7966d5ac712 100644
--- a/chromium/content/common/gpu/image_transport_surface_mac.mm
+++ b/chromium/content/common/gpu/image_transport_surface_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/common/gpu/image_transport_surface_fbo_mac.h"
+#include "content/common/gpu/image_transport_surface.h"
#include "content/common/gpu/gpu_messages.h"
#include "ui/gfx/native_widget_types.h"
@@ -11,6 +11,12 @@
#include "ui/gl/gl_surface_osmesa.h"
namespace content {
+
+scoped_refptr<gfx::GLSurface> ImageTransportSurfaceCreateNativeSurface(
+ GpuChannelManager* manager,
+ GpuCommandBufferStub* stub,
+ gfx::PluginWindowHandle handle);
+
namespace {
// A subclass of GLSurfaceOSMesa that doesn't print an error message when
@@ -47,9 +53,10 @@ scoped_refptr<gfx::GLSurface> ImageTransportSurface::CreateNativeSurface(
switch (gfx::GetGLImplementation()) {
case gfx::kGLImplementationDesktopGL:
+ case gfx::kGLImplementationDesktopGLCoreProfile:
case gfx::kGLImplementationAppleGL:
- return scoped_refptr<gfx::GLSurface>(new ImageTransportSurfaceFBO(
- manager, stub, surface_handle.handle));
+ return ImageTransportSurfaceCreateNativeSurface(manager, stub,
+ surface_handle.handle);
default:
// Content shell in DRT mode spins up a gpu process which needs an
// image transport surface, but that surface isn't used to read pixel
diff --git a/chromium/content/common/gpu/image_transport_surface_win.cc b/chromium/content/common/gpu/image_transport_surface_win.cc
index efa64dda4ae..597a4725f40 100644
--- a/chromium/content/common/gpu/image_transport_surface_win.cc
+++ b/chromium/content/common/gpu/image_transport_surface_win.cc
@@ -29,7 +29,7 @@ scoped_refptr<gfx::GLSurface> ImageTransportSurface::CreateNativeSurface(
DCHECK_EQ(handle.transport_type, gfx::NATIVE_DIRECT);
scoped_refptr<gfx::GLSurface> surface =
gfx::GLSurface::CreateViewGLSurface(handle.handle);
- if (!surface)
+ if (!surface.get())
return surface;
return scoped_refptr<gfx::GLSurface>(new PassThroughImageTransportSurface(
manager, stub, surface.get()));
diff --git a/chromium/content/common/gpu/media/DEPS b/chromium/content/common/gpu/media/DEPS
index 987a2b152a8..dac3d1ca5be 100644
--- a/chromium/content/common/gpu/media/DEPS
+++ b/chromium/content/common/gpu/media/DEPS
@@ -2,4 +2,8 @@ include_rules = [
"+media",
"+third_party/libva",
"+third_party/libyuv",
+ "+ui/display/chromeos",
+ "+ui/display/types",
+ "+ui/platform_window",
+ "+third_party/v4l-utils",
]
diff --git a/chromium/content/common/gpu/media/OWNERS b/chromium/content/common/gpu/media/OWNERS
index 7f528c0ab51..29eb0cd864a 100644
--- a/chromium/content/common/gpu/media/OWNERS
+++ b/chromium/content/common/gpu/media/OWNERS
@@ -1,6 +1,5 @@
dalecurtis@chromium.org
-ddorwin@chromium.org
posciak@chromium.org
+sandersd@chromium.org
scherkus@chromium.org
-vrk@chromium.org
-xhwang@chromium.org
+wuchengli@chromium.org
diff --git a/chromium/content/common/gpu/media/accelerated_video_decoder.h b/chromium/content/common/gpu/media/accelerated_video_decoder.h
new file mode 100644
index 00000000000..b0ba93506ff
--- /dev/null
+++ b/chromium/content/common/gpu/media/accelerated_video_decoder.h
@@ -0,0 +1,63 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_COMMON_GPU_MEDIA_ACCELERATED_VIDEO_DECODER_H_
+#define CONTENT_COMMON_GPU_MEDIA_ACCELERATED_VIDEO_DECODER_H_
+
+#include "base/macros.h"
+#include "content/common/content_export.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace content {
+
+// An AcceleratedVideoDecoder is a video decoder that requires support from an
+// external accelerator (typically a hardware accelerator) to partially offload
+// the decode process after parsing stream headers, and performing reference
+// frame and state management.
+class CONTENT_EXPORT AcceleratedVideoDecoder {
+ public:
+ AcceleratedVideoDecoder() {}
+ virtual ~AcceleratedVideoDecoder() {}
+
+ virtual void SetStream(const uint8_t* ptr, size_t size) = 0;
+
+ // Have the decoder flush its state and trigger output of all previously
+ // decoded surfaces. Return false on failure.
+ virtual bool Flush() WARN_UNUSED_RESULT = 0;
+
+ // Stop (pause) decoding, discarding all remaining inputs and outputs,
+ // but do not flush decoder state, so that playback can be resumed later,
+ // possibly from a different location.
+ // To be called during decoding.
+ virtual void Reset() = 0;
+
+ enum DecodeResult {
+ kDecodeError, // Error while decoding.
+ // TODO(posciak): unsupported streams are currently treated as error
+ // in decoding; in future it could perhaps be possible to fall back
+ // to software decoding instead.
+ // kStreamError, // Error in stream.
+ kAllocateNewSurfaces, // Need a new set of surfaces to be allocated.
+ kRanOutOfStreamData, // Need more stream data to proceed.
+ kRanOutOfSurfaces, // Waiting for the client to free up output surfaces.
+ };
+
+ // Try to decode more of the stream, returning decoded frames asynchronously.
+ // Return when more stream is needed, when we run out of free surfaces, when
+ // we need a new set of them, or when an error occurs.
+ virtual DecodeResult Decode() WARN_UNUSED_RESULT = 0;
+
+ // Return dimensions/required number of output surfaces that client should
+ // be ready to provide for the decoder to function properly.
+ // To be used after Decode() returns kNeedNewSurfaces.
+ virtual gfx::Size GetPicSize() const = 0;
+ virtual size_t GetRequiredNumOfPictures() const = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AcceleratedVideoDecoder);
+};
+
+} // namespace content
+
+#endif // CONTENT_COMMON_GPU_MEDIA_ACCELERATED_VIDEO_DECODER_H_
diff --git a/chromium/content/common/gpu/media/android_video_decode_accelerator.cc b/chromium/content/common/gpu/media/android_video_decode_accelerator.cc
index 0eee64152f5..06d59863d04 100644
--- a/chromium/content/common/gpu/media/android_video_decode_accelerator.cc
+++ b/chromium/content/common/gpu/media/android_video_decode_accelerator.cc
@@ -259,9 +259,6 @@ void AndroidVideoDecodeAccelerator::DequeueOutput() {
}
case media::MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED:
- RETURN_ON_FAILURE(media_codec_->GetOutputBuffers(),
- "Cannot get output buffer from MediaCodec.",
- PLATFORM_FAILURE);
break;
case media::MEDIA_CODEC_OK:
@@ -367,7 +364,6 @@ void AndroidVideoDecodeAccelerator::SendCurrentSurfaceToClient(
GL_TEXTURE_EXTERNAL_OES,
surface_texture_id_,
picture_buffer_texture_id,
- 0,
size_.width(),
size_.height(),
false,
@@ -376,11 +372,10 @@ void AndroidVideoDecodeAccelerator::SendCurrentSurfaceToClient(
default_matrix);
base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(
- &AndroidVideoDecodeAccelerator::NotifyPictureReady,
- weak_this_factory_.GetWeakPtr(),
- media::Picture(picture_buffer_id, bitstream_id, gfx::Rect(size_))));
+ FROM_HERE, base::Bind(&AndroidVideoDecodeAccelerator::NotifyPictureReady,
+ weak_this_factory_.GetWeakPtr(),
+ media::Picture(picture_buffer_id, bitstream_id,
+ gfx::Rect(size_), false)));
}
void AndroidVideoDecodeAccelerator::Decode(
@@ -559,4 +554,20 @@ void AndroidVideoDecodeAccelerator::NotifyError(
client_->NotifyError(error);
}
+// static
+media::VideoDecodeAccelerator::SupportedProfiles
+AndroidVideoDecodeAccelerator::GetSupportedProfiles() {
+ SupportedProfiles profiles;
+ if (media::VideoCodecBridge::IsKnownUnaccelerated(
+ media::kCodecVP8, media::MEDIA_CODEC_DECODER)) {
+ return profiles;
+ }
+ SupportedProfile profile;
+ profile.profile = media::VP8PROFILE_ANY;
+ profile.min_resolution.SetSize(16, 16);
+ profile.max_resolution.SetSize(1920, 1088);
+ profiles.push_back(profile);
+ return profiles;
+}
+
} // namespace content
diff --git a/chromium/content/common/gpu/media/android_video_decode_accelerator.h b/chromium/content/common/gpu/media/android_video_decode_accelerator.h
index 2b41925af47..d5bacfd9af1 100644
--- a/chromium/content/common/gpu/media/android_video_decode_accelerator.h
+++ b/chromium/content/common/gpu/media/android_video_decode_accelerator.h
@@ -37,16 +37,18 @@ class CONTENT_EXPORT AndroidVideoDecodeAccelerator
const base::Callback<bool(void)>& make_context_current);
// media::VideoDecodeAccelerator implementation.
- virtual bool Initialize(media::VideoCodecProfile profile,
- Client* client) override;
- virtual void Decode(const media::BitstreamBuffer& bitstream_buffer) override;
- virtual void AssignPictureBuffers(
+ bool Initialize(media::VideoCodecProfile profile, Client* client) override;
+ void Decode(const media::BitstreamBuffer& bitstream_buffer) override;
+ void AssignPictureBuffers(
const std::vector<media::PictureBuffer>& buffers) override;
- virtual void ReusePictureBuffer(int32 picture_buffer_id) override;
- virtual void Flush() override;
- virtual void Reset() override;
- virtual void Destroy() override;
- virtual bool CanDecodeOnIOThread() override;
+ void ReusePictureBuffer(int32 picture_buffer_id) override;
+ void Flush() override;
+ void Reset() override;
+ void Destroy() override;
+ bool CanDecodeOnIOThread() override;
+
+ static media::VideoDecodeAccelerator::SupportedProfiles
+ GetSupportedProfiles();
private:
enum State {
@@ -56,7 +58,7 @@ class CONTENT_EXPORT AndroidVideoDecodeAccelerator
static const base::TimeDelta kDecodePollDelay;
- virtual ~AndroidVideoDecodeAccelerator();
+ ~AndroidVideoDecodeAccelerator() override;
// Configures |media_codec_| with the given codec parameters from the client.
bool ConfigureMediaCodec();
diff --git a/chromium/content/common/gpu/media/android_video_decode_accelerator_unittest.cc b/chromium/content/common/gpu/media/android_video_decode_accelerator_unittest.cc
index e391d11ed4e..efd5b75a5ca 100644
--- a/chromium/content/common/gpu/media/android_video_decode_accelerator_unittest.cc
+++ b/chromium/content/common/gpu/media/android_video_decode_accelerator_unittest.cc
@@ -33,29 +33,27 @@ namespace content {
class MockVideoDecodeAcceleratorClient
: public media::VideoDecodeAccelerator::Client {
public:
- MockVideoDecodeAcceleratorClient() {};
- virtual ~MockVideoDecodeAcceleratorClient() {};
+ MockVideoDecodeAcceleratorClient() {}
+ ~MockVideoDecodeAcceleratorClient() override {}
// VideoDecodeAccelerator::Client implementation.
- virtual void ProvidePictureBuffers(uint32 requested_num_of_buffers,
- const gfx::Size& dimensions,
- uint32 texture_target) override {};
- virtual void DismissPictureBuffer(int32 picture_buffer_id) override {};
- virtual void PictureReady(const media::Picture& picture) override {};
- virtual void NotifyEndOfBitstreamBuffer(
- int32 bitstream_buffer_id) override {};
- virtual void NotifyFlushDone() override {};
- virtual void NotifyResetDone() override {};
- virtual void NotifyError(
- media::VideoDecodeAccelerator::Error error) override {};
+ void ProvidePictureBuffers(uint32 requested_num_of_buffers,
+ const gfx::Size& dimensions,
+ uint32 texture_target) override {}
+ void DismissPictureBuffer(int32 picture_buffer_id) override {}
+ void PictureReady(const media::Picture& picture) override {}
+ void NotifyEndOfBitstreamBuffer(int32 bitstream_buffer_id) override {}
+ void NotifyFlushDone() override {}
+ void NotifyResetDone() override {}
+ void NotifyError(media::VideoDecodeAccelerator::Error error) override {}
};
class AndroidVideoDecodeAcceleratorTest : public testing::Test {
public:
- virtual ~AndroidVideoDecodeAcceleratorTest() {}
+ ~AndroidVideoDecodeAcceleratorTest() override {}
protected:
- virtual void SetUp() override {
+ void SetUp() override {
JNIEnv* env = base::android::AttachCurrentThread();
media::RegisterJni(env);
// TODO(felipeg): fix GL bindings, so that the decoder can perform GL
diff --git a/chromium/content/common/gpu/media/android_video_encode_accelerator.cc b/chromium/content/common/gpu/media/android_video_encode_accelerator.cc
index 9b703d70f97..33a73e05a1f 100644
--- a/chromium/content/common/gpu/media/android_video_encode_accelerator.cc
+++ b/chromium/content/common/gpu/media/android_video_encode_accelerator.cc
@@ -28,6 +28,14 @@ using media::VideoFrame;
namespace content {
+// Limit default max video codec size for Android to avoid
+// HW codec initialization failure for resolution higher than 720p.
+// Default values are from Libjingle "jsepsessiondescription.cc".
+const int kMaxEncodeFrameWidth = 1280;
+const int kMaxEncodeFrameHeight = 720;
+const int kMaxFramerateNumerator = 30;
+const int kMaxFramerateDenominator = 1;
+
enum PixelFormat {
// Subset of MediaCodecInfo.CodecCapabilities.
COLOR_FORMAT_YUV420_PLANAR = 19,
@@ -72,6 +80,9 @@ static inline const base::TimeDelta NoWaitTimeOut() {
static bool GetSupportedColorFormatForMime(const std::string& mime,
PixelFormat* pixel_format) {
+ if (mime.empty())
+ return false;
+
std::set<int> formats = MediaCodecBridge::GetEncoderColorFormats(mime);
if (formats.count(COLOR_FORMAT_YUV420_SEMIPLANAR) > 0)
*pixel_format = COLOR_FORMAT_YUV420_SEMIPLANAR;
@@ -93,12 +104,9 @@ AndroidVideoEncodeAccelerator::~AndroidVideoEncodeAccelerator() {
DCHECK(thread_checker_.CalledOnValidThread());
}
-std::vector<media::VideoEncodeAccelerator::SupportedProfile>
+media::VideoEncodeAccelerator::SupportedProfiles
AndroidVideoEncodeAccelerator::GetSupportedProfiles() {
- std::vector<MediaCodecBridge::CodecsInfo> codecs_info =
- MediaCodecBridge::GetCodecsInfo();
-
- std::vector<SupportedProfile> profiles;
+ SupportedProfiles profiles;
#if defined(ENABLE_WEBRTC)
const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
@@ -106,22 +114,29 @@ AndroidVideoEncodeAccelerator::GetSupportedProfiles() {
return profiles;
#endif
- for (size_t i = 0; i < codecs_info.size(); ++i) {
- const MediaCodecBridge::CodecsInfo& info = codecs_info[i];
- if (info.direction != media::MEDIA_CODEC_ENCODER || info.codecs != "vp8" ||
- VideoCodecBridge::IsKnownUnaccelerated(media::kCodecVP8,
+ const struct {
+ const media::VideoCodec codec;
+ const media::VideoCodecProfile profile;
+ } kSupportedCodecs[] = {
+ { media::kCodecVP8, media::VP8PROFILE_ANY },
+ { media::kCodecH264, media::H264PROFILE_BASELINE },
+ { media::kCodecH264, media::H264PROFILE_MAIN }
+ };
+
+ for (const auto& supported_codec : kSupportedCodecs) {
+ if (VideoCodecBridge::IsKnownUnaccelerated(supported_codec.codec,
media::MEDIA_CODEC_ENCODER)) {
- // We're only looking for a HW VP8 encoder.
continue;
}
+
SupportedProfile profile;
- profile.profile = media::VP8PROFILE_ANY;
- // Wouldn't it be nice if MediaCodec exposed the maximum capabilities of the
- // encoder? Sure would be. Too bad it doesn't. So we hard-code some
- // reasonable defaults.
- profile.max_resolution.SetSize(1920, 1088);
- profile.max_framerate_numerator = 30;
- profile.max_framerate_denominator = 1;
+ profile.profile = supported_codec.profile;
+ // It would be nice if MediaCodec exposes the maximum capabilities of
+ // the encoder. Hard-code some reasonable defaults as workaround.
+ profile.max_resolution.SetSize(kMaxEncodeFrameWidth,
+ kMaxEncodeFrameHeight);
+ profile.max_framerate_numerator = kMaxFramerateNumerator;
+ profile.max_framerate_denominator = kMaxFramerateDenominator;
profiles.push_back(profile);
}
return profiles;
@@ -143,27 +158,39 @@ bool AndroidVideoEncodeAccelerator::Initialize(
client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client));
if (!(media::MediaCodecBridge::SupportsSetParameters() &&
- format == VideoFrame::I420 &&
- output_profile == media::VP8PROFILE_ANY)) {
+ format == VideoFrame::I420)) {
DLOG(ERROR) << "Unexpected combo: " << format << ", " << output_profile;
return false;
}
+ std::string mime_type;
+ media::VideoCodec codec;
+ if (output_profile == media::VP8PROFILE_ANY) {
+ codec = media::kCodecVP8;
+ mime_type = "video/x-vnd.on2.vp8";
+ } else if (output_profile == media::H264PROFILE_BASELINE ||
+ output_profile == media::H264PROFILE_MAIN) {
+ codec = media::kCodecH264;
+ mime_type = "video/avc";
+ } else {
+ return false;
+ }
+
last_set_bitrate_ = initial_bitrate;
// Only consider using MediaCodec if it's likely backed by hardware.
if (media::VideoCodecBridge::IsKnownUnaccelerated(
- media::kCodecVP8, media::MEDIA_CODEC_ENCODER)) {
+ codec, media::MEDIA_CODEC_ENCODER)) {
DLOG(ERROR) << "No HW support";
return false;
}
PixelFormat pixel_format = COLOR_FORMAT_YUV420_SEMIPLANAR;
- if (!GetSupportedColorFormatForMime("video/x-vnd.on2.vp8", &pixel_format)) {
+ if (!GetSupportedColorFormatForMime(mime_type, &pixel_format)) {
DLOG(ERROR) << "No color format support.";
return false;
}
- media_codec_.reset(media::VideoCodecBridge::CreateEncoder(media::kCodecVP8,
+ media_codec_.reset(media::VideoCodecBridge::CreateEncoder(codec,
input_visible_size,
initial_bitrate,
INITIAL_FRAMERATE,
@@ -293,7 +320,7 @@ void AndroidVideoEncodeAccelerator::QueueInput() {
}
const PendingFrames::value_type& input = pending_frames_.front();
- bool is_key_frame = input.b;
+ bool is_key_frame = get<1>(input);
if (is_key_frame) {
// Ideally MediaCodec would honor BUFFER_FLAG_SYNC_FRAME so we could
// indicate this in the QueueInputBuffer() call below and guarantee _this_
@@ -301,7 +328,7 @@ void AndroidVideoEncodeAccelerator::QueueInput() {
// Instead, we request a key frame "soon".
media_codec_->RequestKeyFrameSoon();
}
- scoped_refptr<VideoFrame> frame = input.a;
+ scoped_refptr<VideoFrame> frame = get<0>(input);
uint8* buffer = NULL;
size_t capacity = 0;
@@ -337,7 +364,8 @@ void AndroidVideoEncodeAccelerator::QueueInput() {
fake_input_timestamp_ += base::TimeDelta::FromMicroseconds(1);
status = media_codec_->QueueInputBuffer(
input_buf_index, NULL, queued_size, fake_input_timestamp_);
- UMA_HISTOGRAM_TIMES("Media.AVEA.InputQueueTime", base::Time::Now() - input.c);
+ UMA_HISTOGRAM_TIMES("Media.AVEA.InputQueueTime",
+ base::Time::Now() - get<2>(input));
RETURN_ON_FAILURE(status == media::MEDIA_CODEC_OK,
"Failed to QueueInputBuffer: " << status,
kPlatformFailureError);
@@ -351,8 +379,8 @@ bool AndroidVideoEncodeAccelerator::DoOutputBuffersSuffice() {
// prepared to field multiple requests to RequireBitstreamBuffers().
int count = media_codec_->GetOutputBuffersCount();
size_t capacity = media_codec_->GetOutputBuffersCapacity();
- bool ret = media_codec_->GetOutputBuffers() && count <= num_output_buffers_ &&
- capacity <= output_buffers_capacity_;
+ bool ret = count <= num_output_buffers_ &&
+ capacity <= output_buffers_capacity_;
LOG_IF(ERROR, !ret) << "Need more/bigger buffers; before: "
<< num_output_buffers_ << "x" << output_buffers_capacity_
<< ", now: " << count << "x" << capacity;
diff --git a/chromium/content/common/gpu/media/android_video_encode_accelerator.h b/chromium/content/common/gpu/media/android_video_encode_accelerator.h
index f7f6eab374b..c828de8493f 100644
--- a/chromium/content/common/gpu/media/android_video_encode_accelerator.h
+++ b/chromium/content/common/gpu/media/android_video_encode_accelerator.h
@@ -32,23 +32,22 @@ class CONTENT_EXPORT AndroidVideoEncodeAccelerator
: public media::VideoEncodeAccelerator {
public:
AndroidVideoEncodeAccelerator();
- virtual ~AndroidVideoEncodeAccelerator();
+ ~AndroidVideoEncodeAccelerator() override;
// media::VideoEncodeAccelerator implementation.
- virtual std::vector<media::VideoEncodeAccelerator::SupportedProfile>
- GetSupportedProfiles() override;
- virtual bool Initialize(media::VideoFrame::Format format,
- const gfx::Size& input_visible_size,
- media::VideoCodecProfile output_profile,
- uint32 initial_bitrate,
- Client* client) override;
- virtual void Encode(const scoped_refptr<media::VideoFrame>& frame,
- bool force_keyframe) override;
- virtual void UseOutputBitstreamBuffer(const media::BitstreamBuffer& buffer)
+ media::VideoEncodeAccelerator::SupportedProfiles GetSupportedProfiles()
override;
- virtual void RequestEncodingParametersChange(uint32 bitrate,
- uint32 framerate) override;
- virtual void Destroy() override;
+ bool Initialize(media::VideoFrame::Format format,
+ const gfx::Size& input_visible_size,
+ media::VideoCodecProfile output_profile,
+ uint32 initial_bitrate,
+ Client* client) override;
+ void Encode(const scoped_refptr<media::VideoFrame>& frame,
+ bool force_keyframe) override;
+ void UseOutputBitstreamBuffer(const media::BitstreamBuffer& buffer) override;
+ void RequestEncodingParametersChange(uint32 bitrate,
+ uint32 framerate) override;
+ void Destroy() override;
private:
enum {
@@ -86,7 +85,7 @@ class CONTENT_EXPORT AndroidVideoEncodeAccelerator
// Frames waiting to be passed to the codec, queued until an input buffer is
// available. Each element is a tuple of <Frame, key_frame, enqueue_time>.
typedef std::queue<
- Tuple3<scoped_refptr<media::VideoFrame>, bool, base::Time> >
+ Tuple<scoped_refptr<media::VideoFrame>, bool, base::Time>>
PendingFrames;
PendingFrames pending_frames_;
diff --git a/chromium/content/common/gpu/media/dxva_video_decode_accelerator.cc b/chromium/content/common/gpu/media/dxva_video_decode_accelerator.cc
index 530358e155f..628bccd0f45 100644
--- a/chromium/content/common/gpu/media/dxva_video_decode_accelerator.cc
+++ b/chromium/content/common/gpu/media/dxva_video_decode_accelerator.cc
@@ -10,31 +10,109 @@
#include <ks.h>
#include <codecapi.h>
+#include <dxgi1_2.h>
#include <mfapi.h>
#include <mferror.h>
#include <wmcodecdsp.h>
+#include "base/base_paths_win.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/command_line.h"
-#include "base/debug/trace_event.h"
+#include "base/debug/alias.h"
#include "base/file_version_info.h"
+#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/shared_memory.h"
#include "base/message_loop/message_loop.h"
+#include "base/path_service.h"
+#include "base/trace_event/trace_event.h"
#include "base/win/windows_version.h"
#include "media/video/video_decode_accelerator.h"
#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_context.h"
#include "ui/gl/gl_surface_egl.h"
#include "ui/gl/gl_switches.h"
+namespace {
+
+// Path is appended on to the PROGRAM_FILES base path.
+const wchar_t kVPXDecoderDLLPath[] = L"Intel\\Media SDK\\";
+
+const wchar_t kVP8DecoderDLLName[] =
+#if defined(ARCH_CPU_X86)
+ L"mfx_mft_vp8vd_32.dll";
+#elif defined(ARCH_CPU_X86_64)
+ L"mfx_mft_vp8vd_64.dll";
+#else
+#error Unsupported Windows CPU Architecture
+#endif
+
+const wchar_t kVP9DecoderDLLName[] =
+#if defined(ARCH_CPU_X86)
+ L"mfx_mft_vp9vd_32.dll";
+#elif defined(ARCH_CPU_X86_64)
+ L"mfx_mft_vp9vd_64.dll";
+#else
+#error Unsupported Windows CPU Architecture
+#endif
+
+const CLSID CLSID_WebmMfVp8Dec = {
+ 0x451e3cb7,
+ 0x2622,
+ 0x4ba5,
+ { 0x8e, 0x1d, 0x44, 0xb3, 0xc4, 0x1d, 0x09, 0x24 }
+};
+
+const CLSID CLSID_WebmMfVp9Dec = {
+ 0x07ab4bd2,
+ 0x1979,
+ 0x4fcd,
+ { 0xa6, 0x97, 0xdf, 0x9a, 0xd1, 0x5b, 0x34, 0xfe }
+};
+
+const CLSID MEDIASUBTYPE_VP80 = {
+ 0x30385056,
+ 0x0000,
+ 0x0010,
+ { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }
+};
+
+const CLSID MEDIASUBTYPE_VP90 = {
+ 0x30395056,
+ 0x0000,
+ 0x0010,
+ { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }
+};
+
+// The CLSID of the video processor media foundation transform which we use for
+// texture color conversion in DX11.
+DEFINE_GUID(CLSID_VideoProcessorMFT,
+ 0x88753b26, 0x5b24, 0x49bd, 0xb2, 0xe7, 0xc, 0x44, 0x5c, 0x78,
+ 0xc9, 0x82);
+
+// MF_XVP_PLAYBACK_MODE
+// Data type: UINT32 (treat as BOOL)
+// If this attribute is TRUE, the video processor will run in playback mode
+// where it allows callers to allocate output samples and allows last frame
+// regeneration (repaint).
+DEFINE_GUID(MF_XVP_PLAYBACK_MODE, 0x3c5d293f, 0xad67, 0x4e29, 0xaf, 0x12,
+ 0xcf, 0x3e, 0x23, 0x8a, 0xcc, 0xe9);
+}
+
namespace content {
-// We only request 5 picture buffers from the client which are used to hold the
-// decoded samples. These buffers are then reused when the client tells us that
-// it is done with the buffer.
-static const int kNumPictureBuffers = 5;
+static const media::VideoCodecProfile kSupportedProfiles[] = {
+ media::H264PROFILE_BASELINE,
+ media::H264PROFILE_MAIN,
+ media::H264PROFILE_HIGH,
+ media::VP8PROFILE_ANY,
+ media::VP9PROFILE_ANY
+};
+
+CreateDXGIDeviceManager DXVAVideoDecodeAccelerator::create_dxgi_device_manager_
+ = NULL;
#define RETURN_ON_FAILURE(result, log, ret) \
do { \
@@ -63,10 +141,18 @@ static const int kNumPictureBuffers = 5;
log << ", HRESULT: 0x" << std::hex << result, \
error_code, ret);
-// Maximum number of iterations we allow before aborting the attempt to flush
-// the batched queries to the driver and allow torn/corrupt frames to be
-// rendered.
-enum { kMaxIterationsForD3DFlush = 10 };
+enum {
+ // Maximum number of iterations we allow before aborting the attempt to flush
+ // the batched queries to the driver and allow torn/corrupt frames to be
+ // rendered.
+ kFlushDecoderSurfaceTimeoutMs = 1,
+ // Maximum iterations where we try to flush the d3d device.
+ kMaxIterationsForD3DFlush = 4,
+ // We only request 5 picture buffers from the client which are used to hold
+ // the decoded samples. These buffers are then reused when the client tells
+ // us that it is done with the buffer.
+ kNumPictureBuffers = 5,
+};
static IMFSample* CreateEmptySample() {
base::win::ScopedComPtr<IMFSample> sample;
@@ -96,9 +182,10 @@ static IMFSample* CreateEmptySampleWithBuffer(int buffer_length, int align) {
}
RETURN_ON_HR_FAILURE(hr, "Failed to create memory buffer for sample", NULL);
- hr = sample->AddBuffer(buffer);
+ hr = sample->AddBuffer(buffer.get());
RETURN_ON_HR_FAILURE(hr, "Failed to add buffer to sample", NULL);
+ buffer->SetCurrentLength(0);
return sample.Detach();
}
@@ -114,7 +201,7 @@ static IMFSample* CreateInputSample(const uint8* stream, int size,
base::win::ScopedComPtr<IMFSample> sample;
sample.Attach(CreateEmptySampleWithBuffer(std::max(min_size, size),
alignment));
- RETURN_ON_FAILURE(sample, "Failed to create empty sample", NULL);
+ RETURN_ON_FAILURE(sample.get(), "Failed to create empty sample", NULL);
base::win::ScopedComPtr<IMFMediaBuffer> buffer;
HRESULT hr = sample->GetBufferByIndex(0, buffer.Receive());
@@ -168,8 +255,10 @@ struct DXVAVideoDecodeAccelerator::DXVAPictureBuffer {
// client.
// The dest_surface parameter contains the decoded bits.
bool CopyOutputSampleDataToPictureBuffer(
- const DXVAVideoDecodeAccelerator& decoder,
- IDirect3DSurface9* dest_surface);
+ DXVAVideoDecodeAccelerator* decoder,
+ IDirect3DSurface9* dest_surface,
+ ID3D11Texture2D* dx11_texture,
+ int input_buffer_id);
bool available() const {
return available_;
@@ -187,6 +276,11 @@ struct DXVAVideoDecodeAccelerator::DXVAPictureBuffer {
return picture_buffer_.size();
}
+ // Called when the source surface |src_surface| is copied to the destination
+ // |dest_surface|
+ void CopySurfaceComplete(IDirect3DSurface9* src_surface,
+ IDirect3DSurface9* dest_surface);
+
private:
explicit DXVAPictureBuffer(const media::PictureBuffer& buffer);
@@ -194,6 +288,20 @@ struct DXVAVideoDecodeAccelerator::DXVAPictureBuffer {
media::PictureBuffer picture_buffer_;
EGLSurface decoding_surface_;
base::win::ScopedComPtr<IDirect3DTexture9> decoding_texture_;
+ base::win::ScopedComPtr<ID3D11Texture2D> dx11_decoding_texture_;
+
+ // The following |IDirect3DSurface9| interface pointers are used to hold
+ // references on the surfaces during the course of a StretchRect operation
+ // to copy the source surface to the target. The references are released
+ // when the StretchRect operation i.e. the copy completes.
+ base::win::ScopedComPtr<IDirect3DSurface9> decoder_surface_;
+ base::win::ScopedComPtr<IDirect3DSurface9> target_surface_;
+
+ // This ID3D11Texture2D interface pointer is used to hold a reference to the
+ // decoder texture during the course of a copy operation. This reference is
+ // released when the copy completes.
+ base::win::ScopedComPtr<ID3D11Texture2D> decoder_dx11_texture_;
+
// Set to true if RGB is supported by the texture.
// Defaults to true.
bool use_rgb_;
@@ -242,16 +350,27 @@ DXVAVideoDecodeAccelerator::DXVAPictureBuffer::Create(
"Failed to query ANGLE surface pointer",
linked_ptr<DXVAPictureBuffer>(NULL));
- HRESULT hr = decoder.device_->CreateTexture(
- buffer.size().width(),
- buffer.size().height(),
- 1,
- D3DUSAGE_RENDERTARGET,
- use_rgb ? D3DFMT_X8R8G8B8 : D3DFMT_A8R8G8B8,
- D3DPOOL_DEFAULT,
- picture_buffer->decoding_texture_.Receive(),
- &share_handle);
-
+ HRESULT hr = E_FAIL;
+ if (decoder.d3d11_device_) {
+ base::win::ScopedComPtr<ID3D11Resource> resource;
+ hr = decoder.d3d11_device_->OpenSharedResource(
+ share_handle,
+ __uuidof(ID3D11Resource),
+ reinterpret_cast<void**>(resource.Receive()));
+ RETURN_ON_HR_FAILURE(hr, "Failed to open shared resource",
+ linked_ptr<DXVAPictureBuffer>(NULL));
+ hr = picture_buffer->dx11_decoding_texture_.QueryFrom(resource.get());
+ } else {
+ hr = decoder.d3d9_device_ex_->CreateTexture(
+ buffer.size().width(),
+ buffer.size().height(),
+ 1,
+ D3DUSAGE_RENDERTARGET,
+ use_rgb ? D3DFMT_X8R8G8B8 : D3DFMT_A8R8G8B8,
+ D3DPOOL_DEFAULT,
+ picture_buffer->decoding_texture_.Receive(),
+ &share_handle);
+ }
RETURN_ON_HR_FAILURE(hr, "Failed to create texture",
linked_ptr<DXVAPictureBuffer>(NULL));
picture_buffer->use_rgb_ = !!use_rgb;
@@ -289,15 +408,28 @@ void DXVAVideoDecodeAccelerator::DXVAPictureBuffer::ReusePictureBuffer() {
egl_display,
decoding_surface_,
EGL_BACK_BUFFER);
+ decoder_surface_.Release();
+ target_surface_.Release();
+ decoder_dx11_texture_.Release();
set_available(true);
}
bool DXVAVideoDecodeAccelerator::DXVAPictureBuffer::
CopyOutputSampleDataToPictureBuffer(
- const DXVAVideoDecodeAccelerator& decoder,
- IDirect3DSurface9* dest_surface) {
- DCHECK(dest_surface);
-
+ DXVAVideoDecodeAccelerator* decoder,
+ IDirect3DSurface9* dest_surface,
+ ID3D11Texture2D* dx11_texture,
+ int input_buffer_id) {
+ DCHECK(dest_surface || dx11_texture);
+ if (dx11_texture) {
+ // Grab a reference on the decoder texture. This reference will be released
+ // when we receive a notification that the copy was completed or when the
+ // DXVAPictureBuffer instance is destroyed.
+ decoder_dx11_texture_ = dx11_texture;
+ decoder->CopyTexture(dx11_texture, dx11_decoding_texture_.get(), NULL,
+ id(), input_buffer_id);
+ return true;
+ }
D3DSURFACE_DESC surface_desc;
HRESULT hr = dest_surface->GetDesc(&surface_desc);
RETURN_ON_HR_FAILURE(hr, "Failed to get surface description", false);
@@ -311,13 +443,35 @@ bool DXVAVideoDecodeAccelerator::DXVAPictureBuffer::
return false;
}
- hr = decoder.d3d9_->CheckDeviceFormatConversion(
+ hr = decoder->d3d9_->CheckDeviceFormatConversion(
D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, surface_desc.Format,
use_rgb_ ? D3DFMT_X8R8G8B8 : D3DFMT_A8R8G8B8);
RETURN_ON_HR_FAILURE(hr, "Device does not support format converision", false);
- // This function currently executes in the context of IPC handlers in the
- // GPU process which ensures that there is always an OpenGL context.
+ // The same picture buffer can be reused for a different frame. Release the
+ // target surface and the decoder references here.
+ target_surface_.Release();
+ decoder_surface_.Release();
+
+ // Grab a reference on the decoder surface and the target surface. These
+ // references will be released when we receive a notification that the
+ // copy was completed or when the DXVAPictureBuffer instance is destroyed.
+ // We hold references here as it is easier to manage their lifetimes.
+ hr = decoding_texture_->GetSurfaceLevel(0, target_surface_.Receive());
+ RETURN_ON_HR_FAILURE(hr, "Failed to get surface from texture", false);
+
+ decoder_surface_ = dest_surface;
+
+ decoder->CopySurface(decoder_surface_.get(), target_surface_.get(), id(),
+ input_buffer_id);
+ return true;
+}
+
+void DXVAVideoDecodeAccelerator::DXVAPictureBuffer::CopySurfaceComplete(
+ IDirect3DSurface9* src_surface,
+ IDirect3DSurface9* dest_surface) {
+ DCHECK(!available());
+
GLint current_texture = 0;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &current_texture);
@@ -325,113 +479,55 @@ bool DXVAVideoDecodeAccelerator::DXVAPictureBuffer::
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- base::win::ScopedComPtr<IDirect3DSurface9> d3d_surface;
- hr = decoding_texture_->GetSurfaceLevel(0, d3d_surface.Receive());
- RETURN_ON_HR_FAILURE(hr, "Failed to get surface from texture", false);
-
- hr = decoder.device_->StretchRect(
- dest_surface, NULL, d3d_surface, NULL, D3DTEXF_NONE);
- RETURN_ON_HR_FAILURE(hr, "Colorspace conversion via StretchRect failed",
- false);
-
- // Ideally, this should be done immediately before the draw call that uses
- // the texture. Flush it once here though.
- hr = decoder.query_->Issue(D3DISSUE_END);
- RETURN_ON_HR_FAILURE(hr, "Failed to issue END", false);
-
- // The DXVA decoder has its own device which it uses for decoding. ANGLE
- // has its own device which we don't have access to.
- // The above code attempts to copy the decoded picture into a surface
- // which is owned by ANGLE. As there are multiple devices involved in
- // this, the StretchRect call above is not synchronous.
- // We attempt to flush the batched operations to ensure that the picture is
- // copied to the surface owned by ANGLE.
- // We need to do this in a loop and call flush multiple times.
- // We have seen the GetData call for flushing the command buffer fail to
- // return success occassionally on multi core machines, leading to an
- // infinite loop.
- // Workaround is to have an upper limit of 10 on the number of iterations to
- // wait for the Flush to finish.
- int iterations = 0;
- while ((decoder.query_->GetData(NULL, 0, D3DGETDATA_FLUSH) == S_FALSE) &&
- ++iterations < kMaxIterationsForD3DFlush) {
- Sleep(1); // Poor-man's Yield().
+ if (src_surface && dest_surface) {
+ DCHECK_EQ(src_surface, decoder_surface_.get());
+ DCHECK_EQ(dest_surface, target_surface_.get());
+ decoder_surface_.Release();
+ target_surface_.Release();
+ } else {
+ DCHECK(decoder_dx11_texture_.get());
+ decoder_dx11_texture_.Release();
}
+
EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay();
eglBindTexImage(
egl_display,
decoding_surface_,
EGL_BACK_BUFFER);
+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, current_texture);
- return true;
}
DXVAVideoDecodeAccelerator::PendingSampleInfo::PendingSampleInfo(
int32 buffer_id, IMFSample* sample)
- : input_buffer_id(buffer_id) {
+ : input_buffer_id(buffer_id),
+ picture_buffer_id(-1) {
output_sample.Attach(sample);
}
DXVAVideoDecodeAccelerator::PendingSampleInfo::~PendingSampleInfo() {}
-// static
-bool DXVAVideoDecodeAccelerator::CreateD3DDevManager() {
- TRACE_EVENT0("gpu", "DXVAVideoDecodeAccelerator_CreateD3DDevManager");
-
- HRESULT hr = Direct3DCreate9Ex(D3D_SDK_VERSION, d3d9_.Receive());
- RETURN_ON_HR_FAILURE(hr, "Direct3DCreate9Ex failed", false);
-
- D3DPRESENT_PARAMETERS present_params = {0};
- present_params.BackBufferWidth = 1;
- present_params.BackBufferHeight = 1;
- present_params.BackBufferFormat = D3DFMT_UNKNOWN;
- present_params.BackBufferCount = 1;
- present_params.SwapEffect = D3DSWAPEFFECT_DISCARD;
- present_params.hDeviceWindow = ::GetShellWindow();
- present_params.Windowed = TRUE;
- present_params.Flags = D3DPRESENTFLAG_VIDEO;
- present_params.FullScreen_RefreshRateInHz = 0;
- present_params.PresentationInterval = 0;
-
- hr = d3d9_->CreateDeviceEx(D3DADAPTER_DEFAULT,
- D3DDEVTYPE_HAL,
- ::GetShellWindow(),
- D3DCREATE_FPU_PRESERVE |
- D3DCREATE_SOFTWARE_VERTEXPROCESSING |
- D3DCREATE_DISABLE_PSGP_THREADING |
- D3DCREATE_MULTITHREADED,
- &present_params,
- NULL,
- device_.Receive());
- RETURN_ON_HR_FAILURE(hr, "Failed to create D3D device", false);
-
- hr = DXVA2CreateDirect3DDeviceManager9(&dev_manager_reset_token_,
- device_manager_.Receive());
- RETURN_ON_HR_FAILURE(hr, "DXVA2CreateDirect3DDeviceManager9 failed", false);
-
- hr = device_manager_->ResetDevice(device_, dev_manager_reset_token_);
- RETURN_ON_HR_FAILURE(hr, "Failed to reset device", false);
-
- hr = device_->CreateQuery(D3DQUERYTYPE_EVENT, query_.Receive());
- RETURN_ON_HR_FAILURE(hr, "Failed to create D3D device query", false);
- // Ensure query_ API works (to avoid an infinite loop later in
- // CopyOutputSampleDataToPictureBuffer).
- hr = query_->Issue(D3DISSUE_END);
- RETURN_ON_HR_FAILURE(hr, "Failed to issue END test query", false);
- return true;
-}
-
DXVAVideoDecodeAccelerator::DXVAVideoDecodeAccelerator(
- const base::Callback<bool(void)>& make_context_current)
+ const base::Callback<bool(void)>& make_context_current,
+ gfx::GLContext* gl_context)
: client_(NULL),
dev_manager_reset_token_(0),
+ dx11_dev_manager_reset_token_(0),
egl_config_(NULL),
state_(kUninitialized),
pictures_requested_(false),
inputs_before_decode_(0),
+ sent_drain_message_(false),
make_context_current_(make_context_current),
+ codec_(media::kUnknownVideoCodec),
+ decoder_thread_("DXVAVideoDecoderThread"),
+ pending_flush_(false),
+ use_dx11_(false),
+ dx11_video_format_converter_media_type_needs_init_(true),
+ gl_context_(gl_context),
weak_this_factory_(this) {
+ weak_ptr_ = weak_this_factory_.GetWeakPtr();
memset(&input_stream_info_, 0, sizeof(input_stream_info_));
memset(&output_stream_info_, 0, sizeof(output_stream_info_));
}
@@ -441,26 +537,55 @@ DXVAVideoDecodeAccelerator::~DXVAVideoDecodeAccelerator() {
}
bool DXVAVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile,
- Client* client) {
- DCHECK(CalledOnValidThread());
-
+ Client* client) {
client_ = client;
+ main_thread_task_runner_ = base::MessageLoop::current()->task_runner();
+
+ bool profile_supported = false;
+ for (const auto& supported_profile : kSupportedProfiles) {
+ if (profile == supported_profile) {
+ profile_supported = true;
+ break;
+ }
+ }
+ if (!profile_supported) {
+ RETURN_AND_NOTIFY_ON_FAILURE(false,
+ "Unsupported h.264, vp8, or vp9 profile", PLATFORM_FAILURE, false);
+ }
+
// Not all versions of Windows 7 and later include Media Foundation DLLs.
// Instead of crashing while delay loading the DLL when calling MFStartup()
// below, probe whether we can successfully load the DLL now.
- //
// See http://crbug.com/339678 for details.
- HMODULE mfplat_dll = ::LoadLibrary(L"MFPlat.dll");
- RETURN_ON_FAILURE(mfplat_dll, "MFPlat.dll is required for decoding", false);
+ HMODULE dxgi_manager_dll = NULL;
+ if ((dxgi_manager_dll = ::GetModuleHandle(L"MFPlat.dll")) == NULL) {
+ HMODULE mfplat_dll = ::LoadLibrary(L"MFPlat.dll");
+ RETURN_ON_FAILURE(mfplat_dll, "MFPlat.dll is required for decoding",
+ false);
+ // On Windows 8+ mfplat.dll provides the MFCreateDXGIDeviceManager API.
+ // On Windows 7 mshtmlmedia.dll provides it.
+ dxgi_manager_dll = mfplat_dll;
+ }
// TODO(ananta)
- // H264PROFILE_HIGH video decoding is janky at times. Needs more
- // investigation. http://crbug.com/426707
- if (profile != media::H264PROFILE_BASELINE &&
- profile != media::H264PROFILE_MAIN) {
- RETURN_AND_NOTIFY_ON_FAILURE(false,
- "Unsupported h264 profile", PLATFORM_FAILURE, false);
+ // The code below works, as in we can create the DX11 device manager for
+ // Windows 7. However the IMFTransform we use for texture conversion and
+ // copy does not exist on Windows 7. Look into an alternate approach
+ // and enable the code below.
+#if defined ENABLE_DX11_FOR_WIN7
+ if ((base::win::GetVersion() == base::win::VERSION_WIN7) &&
+ ((dxgi_manager_dll = ::GetModuleHandle(L"mshtmlmedia.dll")) == NULL)) {
+ HMODULE mshtml_media_dll = ::LoadLibrary(L"mshtmlmedia.dll");
+ if (mshtml_media_dll)
+ dxgi_manager_dll = mshtml_media_dll;
+ }
+#endif
+ // If we don't find the MFCreateDXGIDeviceManager API we fallback to D3D9
+ // decoding.
+ if (dxgi_manager_dll && !create_dxgi_device_manager_) {
+ create_dxgi_device_manager_ = reinterpret_cast<CreateDXGIDeviceManager>(
+ ::GetProcAddress(dxgi_manager_dll, "MFCreateDXGIDeviceManager"));
}
RETURN_AND_NOTIFY_ON_FAILURE(
@@ -469,18 +594,14 @@ bool DXVAVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile,
PLATFORM_FAILURE,
false);
- RETURN_AND_NOTIFY_ON_FAILURE((state_ == kUninitialized),
- "Initialize: invalid state: " << state_, ILLEGAL_STATE, false);
+ State state = GetState();
+ RETURN_AND_NOTIFY_ON_FAILURE((state == kUninitialized),
+ "Initialize: invalid state: " << state, ILLEGAL_STATE, false);
HRESULT hr = MFStartup(MF_VERSION, MFSTARTUP_FULL);
RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "MFStartup failed.", PLATFORM_FAILURE,
false);
- RETURN_AND_NOTIFY_ON_FAILURE(CreateD3DDevManager(),
- "Failed to initialize D3D device and manager",
- PLATFORM_FAILURE,
- false);
-
RETURN_AND_NOTIFY_ON_FAILURE(InitDecoder(profile),
"Failed to initialize decoder", PLATFORM_FAILURE, false);
@@ -497,37 +618,166 @@ bool DXVAVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile,
"Send MFT_MESSAGE_NOTIFY_START_OF_STREAM notification failed",
PLATFORM_FAILURE, false);
- state_ = kNormal;
+ SetState(kNormal);
+
+ StartDecoderThread();
+ return true;
+}
+
+bool DXVAVideoDecodeAccelerator::CreateD3DDevManager() {
+ TRACE_EVENT0("gpu", "DXVAVideoDecodeAccelerator_CreateD3DDevManager");
+
+ HRESULT hr = Direct3DCreate9Ex(D3D_SDK_VERSION, d3d9_.Receive());
+ RETURN_ON_HR_FAILURE(hr, "Direct3DCreate9Ex failed", false);
+
+ D3DPRESENT_PARAMETERS present_params = {0};
+ present_params.BackBufferWidth = 1;
+ present_params.BackBufferHeight = 1;
+ present_params.BackBufferFormat = D3DFMT_UNKNOWN;
+ present_params.BackBufferCount = 1;
+ present_params.SwapEffect = D3DSWAPEFFECT_DISCARD;
+ present_params.hDeviceWindow = ::GetShellWindow();
+ present_params.Windowed = TRUE;
+ present_params.Flags = D3DPRESENTFLAG_VIDEO;
+ present_params.FullScreen_RefreshRateInHz = 0;
+ present_params.PresentationInterval = 0;
+
+ hr = d3d9_->CreateDeviceEx(D3DADAPTER_DEFAULT,
+ D3DDEVTYPE_HAL,
+ ::GetShellWindow(),
+ D3DCREATE_FPU_PRESERVE |
+ D3DCREATE_SOFTWARE_VERTEXPROCESSING |
+ D3DCREATE_DISABLE_PSGP_THREADING |
+ D3DCREATE_MULTITHREADED,
+ &present_params,
+ NULL,
+ d3d9_device_ex_.Receive());
+ RETURN_ON_HR_FAILURE(hr, "Failed to create D3D device", false);
+
+ hr = DXVA2CreateDirect3DDeviceManager9(&dev_manager_reset_token_,
+ device_manager_.Receive());
+ RETURN_ON_HR_FAILURE(hr, "DXVA2CreateDirect3DDeviceManager9 failed", false);
+
+ hr = device_manager_->ResetDevice(d3d9_device_ex_.get(),
+ dev_manager_reset_token_);
+ RETURN_ON_HR_FAILURE(hr, "Failed to reset device", false);
+
+ hr = d3d9_device_ex_->CreateQuery(D3DQUERYTYPE_EVENT, query_.Receive());
+ RETURN_ON_HR_FAILURE(hr, "Failed to create D3D device query", false);
+ // Ensure query_ API works (to avoid an infinite loop later in
+ // CopyOutputSampleDataToPictureBuffer).
+ hr = query_->Issue(D3DISSUE_END);
+ RETURN_ON_HR_FAILURE(hr, "Failed to issue END test query", false);
+ return true;
+}
+
+bool DXVAVideoDecodeAccelerator::CreateDX11DevManager() {
+ HRESULT hr = create_dxgi_device_manager_(&dx11_dev_manager_reset_token_,
+ d3d11_device_manager_.Receive());
+ RETURN_ON_HR_FAILURE(hr, "MFCreateDXGIDeviceManager failed", false);
+
+ // This array defines the set of DirectX hardware feature levels we support.
+ // The ordering MUST be preserved. All applications are assumed to support
+ // 9.1 unless otherwise stated by the application, which is not our case.
+ D3D_FEATURE_LEVEL feature_levels[] = {
+ D3D_FEATURE_LEVEL_11_1,
+ D3D_FEATURE_LEVEL_11_0,
+ D3D_FEATURE_LEVEL_10_1,
+ D3D_FEATURE_LEVEL_10_0,
+ D3D_FEATURE_LEVEL_9_3,
+ D3D_FEATURE_LEVEL_9_2,
+ D3D_FEATURE_LEVEL_9_1 };
+
+ UINT flags = D3D11_CREATE_DEVICE_VIDEO_SUPPORT;
+
+#if defined _DEBUG
+ flags |= D3D11_CREATE_DEVICE_DEBUG;
+#endif
+
+ D3D_FEATURE_LEVEL feature_level_out = D3D_FEATURE_LEVEL_11_0;
+ hr = D3D11CreateDevice(NULL,
+ D3D_DRIVER_TYPE_HARDWARE,
+ NULL,
+ flags,
+ feature_levels,
+ arraysize(feature_levels),
+ D3D11_SDK_VERSION,
+ d3d11_device_.Receive(),
+ &feature_level_out,
+ d3d11_device_context_.Receive());
+ RETURN_ON_HR_FAILURE(hr, "Failed to create DX11 device", false);
+
+ // Enable multithreaded mode on the context. This ensures that accesses to
+ // context are synchronized across threads. We have multiple threads
+ // accessing the context, the media foundation decoder threads and the
+ // decoder thread via the video format conversion transform.
+ base::win::ScopedComPtr<ID3D10Multithread> multi_threaded;
+ hr = multi_threaded.QueryFrom(d3d11_device_context_.get());
+ RETURN_ON_HR_FAILURE(hr, "Failed to query ID3D10Multithread", false);
+ multi_threaded->SetMultithreadProtected(TRUE);
+
+ hr = d3d11_device_manager_->ResetDevice(d3d11_device_.get(),
+ dx11_dev_manager_reset_token_);
+ RETURN_ON_HR_FAILURE(hr, "Failed to reset device", false);
+
+ D3D11_QUERY_DESC query_desc;
+ query_desc.Query = D3D11_QUERY_EVENT;
+ query_desc.MiscFlags = 0;
+ hr = d3d11_device_->CreateQuery(
+ &query_desc,
+ d3d11_query_.Receive());
+ RETURN_ON_HR_FAILURE(hr, "Failed to create DX11 device query", false);
+
+ hr = ::CoCreateInstance(
+ CLSID_VideoProcessorMFT,
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ IID_IMFTransform,
+ reinterpret_cast<void**>(video_format_converter_mft_.Receive()));
+
+ if (FAILED(hr)) {
+ base::debug::Alias(&hr);
+ // TODO(ananta)
+ // Remove this CHECK when the change to use DX11 for H/W decoding
+ // stablizes.
+ CHECK(false);
+ }
+ RETURN_ON_HR_FAILURE(hr, "Failed to create video format converter", false);
return true;
}
void DXVAVideoDecodeAccelerator::Decode(
const media::BitstreamBuffer& bitstream_buffer) {
- DCHECK(CalledOnValidThread());
+ DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
- RETURN_AND_NOTIFY_ON_FAILURE((state_ == kNormal || state_ == kStopped ||
- state_ == kFlushing),
- "Invalid state: " << state_, ILLEGAL_STATE,);
+ State state = GetState();
+ RETURN_AND_NOTIFY_ON_FAILURE((state == kNormal || state == kStopped ||
+ state == kFlushing),
+ "Invalid state: " << state, ILLEGAL_STATE,);
base::win::ScopedComPtr<IMFSample> sample;
sample.Attach(CreateSampleFromInputBuffer(bitstream_buffer,
input_stream_info_.cbSize,
input_stream_info_.cbAlignment));
- RETURN_AND_NOTIFY_ON_FAILURE(sample, "Failed to create input sample",
- PLATFORM_FAILURE,);
+ RETURN_AND_NOTIFY_ON_FAILURE(sample.get(), "Failed to create input sample",
+ PLATFORM_FAILURE, );
RETURN_AND_NOTIFY_ON_HR_FAILURE(sample->SetSampleTime(bitstream_buffer.id()),
"Failed to associate input buffer id with sample", PLATFORM_FAILURE,);
- DecodeInternal(sample);
+ decoder_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&DXVAVideoDecodeAccelerator::DecodeInternal,
+ base::Unretained(this), sample));
}
void DXVAVideoDecodeAccelerator::AssignPictureBuffers(
const std::vector<media::PictureBuffer>& buffers) {
- DCHECK(CalledOnValidThread());
+ DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
- RETURN_AND_NOTIFY_ON_FAILURE((state_ != kUninitialized),
- "Invalid state: " << state_, ILLEGAL_STATE,);
+ State state = GetState();
+ RETURN_AND_NOTIFY_ON_FAILURE((state != kUninitialized),
+ "Invalid state: " << state, ILLEGAL_STATE,);
RETURN_AND_NOTIFY_ON_FAILURE((kNumPictureBuffers == buffers.size()),
"Failed to provide requested picture buffers. (Got " << buffers.size() <<
", requested " << kNumPictureBuffers << ")", INVALID_ARGUMENT,);
@@ -545,17 +795,23 @@ void DXVAVideoDecodeAccelerator::AssignPictureBuffers(
buffers[buffer_index].id(), picture_buffer)).second;
DCHECK(inserted);
}
+
ProcessPendingSamples();
- if (state_ == kFlushing && pending_output_samples_.empty())
- FlushInternal();
+ if (pending_flush_) {
+ decoder_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&DXVAVideoDecodeAccelerator::FlushInternal,
+ base::Unretained(this)));
+ }
}
void DXVAVideoDecodeAccelerator::ReusePictureBuffer(
int32 picture_buffer_id) {
- DCHECK(CalledOnValidThread());
+ DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
- RETURN_AND_NOTIFY_ON_FAILURE((state_ != kUninitialized),
- "Invalid state: " << state_, ILLEGAL_STATE,);
+ State state = GetState();
+ RETURN_AND_NOTIFY_ON_FAILURE((state != kUninitialized),
+ "Invalid state: " << state, ILLEGAL_STATE,);
if (output_picture_buffers_.empty() && stale_output_picture_buffers_.empty())
return;
@@ -571,47 +827,70 @@ void DXVAVideoDecodeAccelerator::ReusePictureBuffer(
it = stale_output_picture_buffers_.find(picture_buffer_id);
RETURN_AND_NOTIFY_ON_FAILURE(it != stale_output_picture_buffers_.end(),
"Invalid picture id: " << picture_buffer_id, INVALID_ARGUMENT,);
- base::MessageLoop::current()->PostTask(FROM_HERE,
+ main_thread_task_runner_->PostTask(
+ FROM_HERE,
base::Bind(&DXVAVideoDecodeAccelerator::DeferredDismissStaleBuffer,
- weak_this_factory_.GetWeakPtr(), picture_buffer_id));
+ weak_this_factory_.GetWeakPtr(), picture_buffer_id));
return;
}
it->second->ReusePictureBuffer();
ProcessPendingSamples();
-
- if (state_ == kFlushing && pending_output_samples_.empty())
- FlushInternal();
+ if (pending_flush_) {
+ decoder_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&DXVAVideoDecodeAccelerator::FlushInternal,
+ base::Unretained(this)));
+ }
}
void DXVAVideoDecodeAccelerator::Flush() {
- DCHECK(CalledOnValidThread());
+ DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
DVLOG(1) << "DXVAVideoDecodeAccelerator::Flush";
- RETURN_AND_NOTIFY_ON_FAILURE((state_ == kNormal || state_ == kStopped),
- "Unexpected decoder state: " << state_, ILLEGAL_STATE,);
+ State state = GetState();
+ RETURN_AND_NOTIFY_ON_FAILURE((state == kNormal || state == kStopped),
+ "Unexpected decoder state: " << state, ILLEGAL_STATE,);
- state_ = kFlushing;
+ SetState(kFlushing);
- RETURN_AND_NOTIFY_ON_FAILURE(SendMFTMessage(MFT_MESSAGE_COMMAND_DRAIN, 0),
- "Failed to send drain message", PLATFORM_FAILURE,);
+ pending_flush_ = true;
- if (!pending_output_samples_.empty())
- return;
-
- FlushInternal();
+ decoder_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&DXVAVideoDecodeAccelerator::FlushInternal,
+ base::Unretained(this)));
}
void DXVAVideoDecodeAccelerator::Reset() {
- DCHECK(CalledOnValidThread());
+ DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
DVLOG(1) << "DXVAVideoDecodeAccelerator::Reset";
- RETURN_AND_NOTIFY_ON_FAILURE((state_ == kNormal || state_ == kStopped),
- "Reset: invalid state: " << state_, ILLEGAL_STATE,);
+ State state = GetState();
+ RETURN_AND_NOTIFY_ON_FAILURE((state == kNormal || state == kStopped),
+ "Reset: invalid state: " << state, ILLEGAL_STATE,);
- state_ = kResetting;
+ decoder_thread_.Stop();
+
+ SetState(kResetting);
+
+ // If we have pending output frames waiting for display then we drop those
+ // frames and set the corresponding picture buffer as available.
+ PendingOutputSamples::iterator index;
+ for (index = pending_output_samples_.begin();
+ index != pending_output_samples_.end();
+ ++index) {
+ if (index->picture_buffer_id != -1) {
+ OutputBuffers::iterator it = output_picture_buffers_.find(
+ index->picture_buffer_id);
+ if (it != output_picture_buffers_.end()) {
+ DXVAPictureBuffer* picture_buffer = it->second.get();
+ picture_buffer->ReusePictureBuffer();
+ }
+ }
+ }
pending_output_samples_.clear();
@@ -620,16 +899,17 @@ void DXVAVideoDecodeAccelerator::Reset() {
RETURN_AND_NOTIFY_ON_FAILURE(SendMFTMessage(MFT_MESSAGE_COMMAND_FLUSH, 0),
"Reset: Failed to send message.", PLATFORM_FAILURE,);
- base::MessageLoop::current()->PostTask(
+ main_thread_task_runner_->PostTask(
FROM_HERE,
base::Bind(&DXVAVideoDecodeAccelerator::NotifyResetDone,
weak_this_factory_.GetWeakPtr()));
- state_ = DXVAVideoDecodeAccelerator::kNormal;
+ StartDecoderThread();
+ SetState(kNormal);
}
void DXVAVideoDecodeAccelerator::Destroy() {
- DCHECK(CalledOnValidThread());
+ DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
Invalidate();
delete this;
}
@@ -638,31 +918,82 @@ bool DXVAVideoDecodeAccelerator::CanDecodeOnIOThread() {
return false;
}
+GLenum DXVAVideoDecodeAccelerator::GetSurfaceInternalFormat() const {
+ return GL_BGRA_EXT;
+}
+
+// static
+media::VideoDecodeAccelerator::SupportedProfiles
+DXVAVideoDecodeAccelerator::GetSupportedProfiles() {
+ // TODO(henryhsu): Need to ensure the profiles are actually supported.
+ SupportedProfiles profiles;
+ for (const auto& supported_profile : kSupportedProfiles) {
+ SupportedProfile profile;
+ profile.profile = supported_profile;
+ // Windows Media Foundation H.264 decoding does not support decoding videos
+ // with any dimension smaller than 48 pixels:
+ // http://msdn.microsoft.com/en-us/library/windows/desktop/dd797815
+ profile.min_resolution.SetSize(48, 48);
+ // Use 1088 to account for 16x16 macroblocks.
+ profile.max_resolution.SetSize(1920, 1088);
+ profiles.push_back(profile);
+ }
+ return profiles;
+}
+
bool DXVAVideoDecodeAccelerator::InitDecoder(media::VideoCodecProfile profile) {
- if (profile < media::H264PROFILE_MIN || profile > media::H264PROFILE_MAX)
- return false;
+ HMODULE decoder_dll = NULL;
+
+ // Profile must fall within the valid range for one of the supported codecs.
+ if (profile >= media::H264PROFILE_MIN && profile <= media::H264PROFILE_MAX) {
+ // We mimic the steps CoCreateInstance uses to instantiate the object. This
+ // was previously done because it failed inside the sandbox, and now is done
+ // as a more minimal approach to avoid other side-effects CCI might have (as
+ // we are still in a reduced sandbox).
+ decoder_dll = ::LoadLibrary(L"msmpeg2vdec.dll");
+ RETURN_ON_FAILURE(decoder_dll,
+ "msmpeg2vdec.dll required for decoding is not loaded",
+ false);
+
+ // Check version of DLL, version 6.7.7140 is blacklisted due to high crash
+ // rates in browsers loading that DLL. If that is the version installed we
+ // fall back to software decoding. See crbug/403440.
+ FileVersionInfo* version_info =
+ FileVersionInfo::CreateFileVersionInfoForModule(decoder_dll);
+ RETURN_ON_FAILURE(version_info,
+ "unable to get version of msmpeg2vdec.dll",
+ false);
+ base::string16 file_version = version_info->file_version();
+ RETURN_ON_FAILURE(file_version.find(L"6.1.7140") == base::string16::npos,
+ "blacklisted version of msmpeg2vdec.dll 6.7.7140",
+ false);
+ codec_ = media::kCodecH264;
+ } else if (profile == media::VP8PROFILE_ANY ||
+ profile == media::VP9PROFILE_ANY) {
+ int program_files_key = base::DIR_PROGRAM_FILES;
+ if (base::win::OSInfo::GetInstance()->wow64_status() ==
+ base::win::OSInfo::WOW64_ENABLED) {
+ program_files_key = base::DIR_PROGRAM_FILES6432;
+ }
- // We mimic the steps CoCreateInstance uses to instantiate the object. This
- // was previously done because it failed inside the sandbox, and now is done
- // as a more minimal approach to avoid other side-effects CCI might have (as
- // we are still in a reduced sandbox).
- HMODULE decoder_dll = ::LoadLibrary(L"msmpeg2vdec.dll");
- RETURN_ON_FAILURE(decoder_dll,
- "msmpeg2vdec.dll required for decoding is not loaded",
- false);
-
- // Check version of DLL, version 6.7.7140 is blacklisted due to high crash
- // rates in browsers loading that DLL. If that is the version installed we
- // fall back to software decoding. See crbug/403440.
- FileVersionInfo* version_info =
- FileVersionInfo::CreateFileVersionInfoForModule(decoder_dll);
- RETURN_ON_FAILURE(version_info,
- "unable to get version of msmpeg2vdec.dll",
- false);
- base::string16 file_version = version_info->file_version();
- RETURN_ON_FAILURE(file_version.find(L"6.1.7140") == base::string16::npos,
- "blacklisted version of msmpeg2vdec.dll 6.7.7140",
- false);
+ base::FilePath dll_path;
+ RETURN_ON_FAILURE(PathService::Get(program_files_key, &dll_path),
+ "failed to get path for Program Files", false);
+
+ dll_path = dll_path.Append(kVPXDecoderDLLPath);
+ if (profile == media::VP8PROFILE_ANY) {
+ codec_ = media::kCodecVP8;
+ dll_path = dll_path.Append(kVP8DecoderDLLName);
+ } else {
+ codec_ = media::kCodecVP9;
+ dll_path = dll_path.Append(kVP9DecoderDLLName);
+ }
+ decoder_dll = ::LoadLibraryEx(dll_path.value().data(), NULL,
+ LOAD_WITH_ALTERED_SEARCH_PATH);
+ RETURN_ON_FAILURE(decoder_dll, "vpx decoder dll is not loaded", false);
+ } else {
+ RETURN_ON_FAILURE(false, "Unsupported codec.", false);
+ }
typedef HRESULT(WINAPI * GetClassObject)(
const CLSID & clsid, const IID & iid, void * *object);
@@ -673,9 +1004,22 @@ bool DXVAVideoDecodeAccelerator::InitDecoder(media::VideoCodecProfile profile) {
get_class_object, "Failed to get DllGetClassObject pointer", false);
base::win::ScopedComPtr<IClassFactory> factory;
- HRESULT hr = get_class_object(__uuidof(CMSH264DecoderMFT),
- __uuidof(IClassFactory),
- reinterpret_cast<void**>(factory.Receive()));
+ HRESULT hr;
+ if (codec_ == media::kCodecH264) {
+ hr = get_class_object(__uuidof(CMSH264DecoderMFT),
+ __uuidof(IClassFactory),
+ reinterpret_cast<void**>(factory.Receive()));
+ } else if (codec_ == media::kCodecVP8) {
+ hr = get_class_object(CLSID_WebmMfVp8Dec,
+ __uuidof(IClassFactory),
+ reinterpret_cast<void**>(factory.Receive()));
+ } else if (codec_ == media::kCodecVP9) {
+ hr = get_class_object(CLSID_WebmMfVp9Dec,
+ __uuidof(IClassFactory),
+ reinterpret_cast<void**>(factory.Receive()));
+ } else {
+ RETURN_ON_FAILURE(false, "Unsupported codec.", false);
+ }
RETURN_ON_HR_FAILURE(hr, "DllGetClassObject for decoder failed", false);
hr = factory->CreateInstance(NULL,
@@ -686,10 +1030,31 @@ bool DXVAVideoDecodeAccelerator::InitDecoder(media::VideoCodecProfile profile) {
RETURN_ON_FAILURE(CheckDecoderDxvaSupport(),
"Failed to check decoder DXVA support", false);
+ ULONG_PTR device_manager_to_use = NULL;
+ if (use_dx11_) {
+ CHECK(create_dxgi_device_manager_);
+ RETURN_AND_NOTIFY_ON_FAILURE(CreateDX11DevManager(),
+ "Failed to initialize DX11 device and manager",
+ PLATFORM_FAILURE,
+ false);
+ device_manager_to_use = reinterpret_cast<ULONG_PTR>(
+ d3d11_device_manager_.get());
+ } else {
+ RETURN_AND_NOTIFY_ON_FAILURE(CreateD3DDevManager(),
+ "Failed to initialize D3D device and manager",
+ PLATFORM_FAILURE,
+ false);
+ device_manager_to_use = reinterpret_cast<ULONG_PTR>(device_manager_.get());
+ }
+
hr = decoder_->ProcessMessage(
MFT_MESSAGE_SET_D3D_MANAGER,
- reinterpret_cast<ULONG_PTR>(device_manager_.get()));
- RETURN_ON_HR_FAILURE(hr, "Failed to pass D3D manager to decoder", false);
+ device_manager_to_use);
+ if (use_dx11_) {
+ RETURN_ON_HR_FAILURE(hr, "Failed to pass DX11 manager to decoder", false);
+ } else {
+ RETURN_ON_HR_FAILURE(hr, "Failed to pass D3D manager to decoder", false);
+ }
EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay();
@@ -725,8 +1090,31 @@ bool DXVAVideoDecodeAccelerator::CheckDecoderDxvaSupport() {
hr = attributes->GetUINT32(MF_SA_D3D_AWARE, &dxva);
RETURN_ON_HR_FAILURE(hr, "Failed to check if decoder supports DXVA", false);
- hr = attributes->SetUINT32(CODECAPI_AVDecVideoAcceleration_H264, TRUE);
- RETURN_ON_HR_FAILURE(hr, "Failed to enable DXVA H/W decoding", false);
+ if (codec_ == media::kCodecH264) {
+ hr = attributes->SetUINT32(CODECAPI_AVDecVideoAcceleration_H264, TRUE);
+ RETURN_ON_HR_FAILURE(hr, "Failed to enable DXVA H/W decoding", false);
+ }
+
+ hr = attributes->SetUINT32(CODECAPI_AVLowLatencyMode, TRUE);
+ if (SUCCEEDED(hr)) {
+ DVLOG(1) << "Successfully set Low latency mode on decoder.";
+ } else {
+ DVLOG(1) << "Failed to set Low latency mode on decoder. Error: " << hr;
+ }
+
+ // The decoder should use DX11 iff
+ // 1. The underlying H/W decoder supports it.
+ // 2. We have a pointer to the MFCreateDXGIDeviceManager function needed for
+ // this. This should always be true for Windows 8+.
+ // 3. ANGLE is using DX11.
+ DCHECK(gl_context_);
+ if (create_dxgi_device_manager_ &&
+ (gl_context_->GetGLRenderer().find("Direct3D11") !=
+ std::string::npos)) {
+ UINT32 dx11_aware = 0;
+ attributes->GetUINT32(MF_SA_D3D11_AWARE, &dx11_aware);
+ use_dx11_ = !!dx11_aware;
+ }
return true;
}
@@ -744,7 +1132,16 @@ bool DXVAVideoDecodeAccelerator::SetDecoderInputMediaType() {
hr = media_type->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
RETURN_ON_HR_FAILURE(hr, "Failed to set major input type", false);
- hr = media_type->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_H264);
+ if (codec_ == media::kCodecH264) {
+ hr = media_type->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_H264);
+ } else if (codec_ == media::kCodecVP8) {
+ hr = media_type->SetGUID(MF_MT_SUBTYPE, MEDIASUBTYPE_VP80);
+ } else if (codec_ == media::kCodecVP9) {
+ hr = media_type->SetGUID(MF_MT_SUBTYPE, MEDIASUBTYPE_VP90);
+ } else {
+ NOTREACHED();
+ RETURN_ON_FAILURE(false, "Unsupported codec on input media type.", false);
+ }
RETURN_ON_HR_FAILURE(hr, "Failed to set subtype", false);
// Not sure about this. msdn recommends setting this value on the input
@@ -753,7 +1150,7 @@ bool DXVAVideoDecodeAccelerator::SetDecoderInputMediaType() {
MFVideoInterlace_MixedInterlaceOrProgressive);
RETURN_ON_HR_FAILURE(hr, "Failed to set interlace mode", false);
- hr = decoder_->SetInputType(0, media_type, 0); // No flags
+ hr = decoder_->SetInputType(0, media_type.get(), 0); // No flags
RETURN_ON_HR_FAILURE(hr, "Failed to set decoder input type", false);
return true;
}
@@ -771,7 +1168,7 @@ bool DXVAVideoDecodeAccelerator::SetDecoderOutputMediaType(
RETURN_ON_HR_FAILURE(hr, "Failed to get output major type", false);
if (out_subtype == subtype) {
- hr = decoder_->SetOutputType(0, out_media_type, 0); // No flags
+ hr = decoder_->SetOutputType(0, out_media_type.get(), 0); // No flags
RETURN_ON_HR_FAILURE(hr, "Failed to set decoder output type", false);
return true;
}
@@ -798,10 +1195,12 @@ bool DXVAVideoDecodeAccelerator::GetStreamsInfoAndBufferReqs() {
DVLOG(1) << "Input stream info: ";
DVLOG(1) << "Max latency: " << input_stream_info_.hnsMaxLatency;
- // There should be three flags, one for requiring a whole frame be in a
- // single sample, one for requiring there be one buffer only in a single
- // sample, and one that specifies a fixed sample size. (as in cbSize)
- CHECK_EQ(input_stream_info_.dwFlags, 0x7u);
+ if (codec_ == media::kCodecH264) {
+ // There should be three flags, one for requiring a whole frame be in a
+ // single sample, one for requiring there be one buffer only in a single
+ // sample, and one that specifies a fixed sample size. (as in cbSize)
+ CHECK_EQ(input_stream_info_.dwFlags, 0x7u);
+ }
DVLOG(1) << "Min buffer size: " << input_stream_info_.cbSize;
DVLOG(1) << "Max lookahead: " << input_stream_info_.cbMaxLookahead;
@@ -813,18 +1212,22 @@ bool DXVAVideoDecodeAccelerator::GetStreamsInfoAndBufferReqs() {
// allocate its own sample.
DVLOG(1) << "Flags: "
<< std::hex << std::showbase << output_stream_info_.dwFlags;
- CHECK_EQ(output_stream_info_.dwFlags, 0x107u);
+ if (codec_ == media::kCodecH264) {
+ CHECK_EQ(output_stream_info_.dwFlags, 0x107u);
+ }
DVLOG(1) << "Min buffer size: " << output_stream_info_.cbSize;
DVLOG(1) << "Alignment: " << output_stream_info_.cbAlignment;
return true;
}
void DXVAVideoDecodeAccelerator::DoDecode() {
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
// This function is also called from FlushInternal in a loop which could
// result in the state transitioning to kStopped due to no decoded output.
- RETURN_AND_NOTIFY_ON_FAILURE((state_ == kNormal || state_ == kFlushing ||
- state_ == kStopped),
- "DoDecode: not in normal/flushing/stopped state", ILLEGAL_STATE,);
+ State state = GetState();
+ RETURN_AND_NOTIFY_ON_FAILURE(
+ (state == kNormal || state == kFlushing || state == kStopped),
+ "DoDecode: not in normal/flushing/stopped state", ILLEGAL_STATE,);
MFT_OUTPUT_DATA_BUFFER output_data_buffer = {0};
DWORD status = 0;
@@ -835,7 +1238,7 @@ void DXVAVideoDecodeAccelerator::DoDecode() {
&status);
IMFCollection* events = output_data_buffer.pEvents;
if (events != NULL) {
- VLOG(1) << "Got events from ProcessOuput, but discarding";
+ DVLOG(1) << "Got events from ProcessOuput, but discarding";
events->Release();
}
if (FAILED(hr)) {
@@ -846,7 +1249,7 @@ void DXVAVideoDecodeAccelerator::DoDecode() {
// Decoder didn't let us set NV12 output format. Not sure as to why
// this can happen. Give up in disgust.
NOTREACHED() << "Failed to set decoder output media type to NV12";
- state_ = kStopped;
+ SetState(kStopped);
} else {
DVLOG(1) << "Received output format change from the decoder."
" Recursively invoking DoDecode";
@@ -855,7 +1258,7 @@ void DXVAVideoDecodeAccelerator::DoDecode() {
return;
} else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
// No more output from the decoder. Stop playback.
- state_ = kStopped;
+ SetState(kStopped);
return;
} else {
NOTREACHED() << "Unhandled error in DoDecode()";
@@ -876,55 +1279,52 @@ void DXVAVideoDecodeAccelerator::DoDecode() {
bool DXVAVideoDecodeAccelerator::ProcessOutputSample(IMFSample* sample) {
RETURN_ON_FAILURE(sample, "Decode succeeded with NULL output sample", false);
- base::win::ScopedComPtr<IMFMediaBuffer> output_buffer;
- HRESULT hr = sample->GetBufferByIndex(0, output_buffer.Receive());
- RETURN_ON_HR_FAILURE(hr, "Failed to get buffer from output sample", false);
-
- base::win::ScopedComPtr<IDirect3DSurface9> surface;
- hr = MFGetService(output_buffer, MR_BUFFER_SERVICE,
- IID_PPV_ARGS(surface.Receive()));
- RETURN_ON_HR_FAILURE(hr, "Failed to get D3D surface from output sample",
- false);
-
LONGLONG input_buffer_id = 0;
RETURN_ON_HR_FAILURE(sample->GetSampleTime(&input_buffer_id),
"Failed to get input buffer id associated with sample",
false);
- pending_output_samples_.push_back(
- PendingSampleInfo(input_buffer_id, sample));
-
- // If we have available picture buffers to copy the output data then use the
- // first one and then flag it as not being available for use.
- if (output_picture_buffers_.size()) {
- ProcessPendingSamples();
- return true;
+ {
+ base::AutoLock lock(decoder_lock_);
+ DCHECK(pending_output_samples_.empty());
+ pending_output_samples_.push_back(
+ PendingSampleInfo(input_buffer_id, sample));
}
+
if (pictures_requested_) {
DVLOG(1) << "Waiting for picture slots from the client.";
+ main_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&DXVAVideoDecodeAccelerator::ProcessPendingSamples,
+ weak_this_factory_.GetWeakPtr()));
return true;
}
- // We only read the surface description, which contains its width/height when
- // we need the picture buffers from the client. Once we have those, then they
- // are reused.
- D3DSURFACE_DESC surface_desc;
- hr = surface->GetDesc(&surface_desc);
- RETURN_ON_HR_FAILURE(hr, "Failed to get surface description", false);
+ int width = 0;
+ int height = 0;
+ if (!GetVideoFrameDimensions(sample, &width, &height)) {
+ RETURN_ON_FAILURE(false, "Failed to get D3D surface from output sample",
+ false);
+ }
// Go ahead and request picture buffers.
- base::MessageLoop::current()->PostTask(
+ main_thread_task_runner_->PostTask(
FROM_HERE,
base::Bind(&DXVAVideoDecodeAccelerator::RequestPictureBuffers,
weak_this_factory_.GetWeakPtr(),
- surface_desc.Width,
- surface_desc.Height));
+ width,
+ height));
pictures_requested_ = true;
return true;
}
void DXVAVideoDecodeAccelerator::ProcessPendingSamples() {
+ DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
+
+ if (!output_picture_buffers_.size())
+ return;
+
RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_.Run(),
"Failed to make context current", PLATFORM_FAILURE,);
@@ -932,108 +1332,154 @@ void DXVAVideoDecodeAccelerator::ProcessPendingSamples() {
for (index = output_picture_buffers_.begin();
index != output_picture_buffers_.end() &&
- !pending_output_samples_.empty();
+ OutputSamplesPresent();
++index) {
if (index->second->available()) {
- PendingSampleInfo sample_info = pending_output_samples_.front();
+ PendingSampleInfo* pending_sample = NULL;
+ {
+ base::AutoLock lock(decoder_lock_);
+
+ PendingSampleInfo& sample_info = pending_output_samples_.front();
+ if (sample_info.picture_buffer_id != -1)
+ continue;
+ pending_sample = &sample_info;
+ }
+
+ int width = 0;
+ int height = 0;
+ if (!GetVideoFrameDimensions(pending_sample->output_sample.get(),
+ &width, &height)) {
+ RETURN_AND_NOTIFY_ON_FAILURE(false,
+ "Failed to get D3D surface from output sample", PLATFORM_FAILURE,);
+ }
+
+ if (width != index->second->size().width() ||
+ height != index->second->size().height()) {
+ HandleResolutionChanged(width, height);
+ return;
+ }
base::win::ScopedComPtr<IMFMediaBuffer> output_buffer;
- HRESULT hr = sample_info.output_sample->GetBufferByIndex(
+ HRESULT hr = pending_sample->output_sample->GetBufferByIndex(
0, output_buffer.Receive());
- RETURN_AND_NOTIFY_ON_HR_FAILURE(
- hr, "Failed to get buffer from output sample", PLATFORM_FAILURE,);
+ RETURN_AND_NOTIFY_ON_HR_FAILURE(hr,
+ "Failed to get buffer from output sample", PLATFORM_FAILURE,);
base::win::ScopedComPtr<IDirect3DSurface9> surface;
- hr = MFGetService(output_buffer, MR_BUFFER_SERVICE,
- IID_PPV_ARGS(surface.Receive()));
- RETURN_AND_NOTIFY_ON_HR_FAILURE(
- hr, "Failed to get D3D surface from output sample",
- PLATFORM_FAILURE,);
-
- D3DSURFACE_DESC surface_desc;
- hr = surface->GetDesc(&surface_desc);
- RETURN_AND_NOTIFY_ON_HR_FAILURE(
- hr, "Failed to get surface description", PLATFORM_FAILURE,);
-
- if (surface_desc.Width !=
- static_cast<uint32>(index->second->size().width()) ||
- surface_desc.Height !=
- static_cast<uint32>(index->second->size().height())) {
- HandleResolutionChanged(surface_desc.Width, surface_desc.Height);
- return;
+ base::win::ScopedComPtr<ID3D11Texture2D> d3d11_texture;
+
+ if (use_dx11_) {
+ base::win::ScopedComPtr<IMFDXGIBuffer> dxgi_buffer;
+ hr = dxgi_buffer.QueryFrom(output_buffer.get());
+ RETURN_AND_NOTIFY_ON_HR_FAILURE(hr,
+ "Failed to get DXGIBuffer from output sample", PLATFORM_FAILURE,);
+ hr = dxgi_buffer->GetResource(
+ __uuidof(ID3D11Texture2D),
+ reinterpret_cast<void**>(d3d11_texture.Receive()));
+ } else {
+ hr = MFGetService(output_buffer.get(), MR_BUFFER_SERVICE,
+ IID_PPV_ARGS(surface.Receive()));
}
+ RETURN_AND_NOTIFY_ON_HR_FAILURE(hr,
+ "Failed to get surface from output sample", PLATFORM_FAILURE,);
+
+ pending_sample->picture_buffer_id = index->second->id();
RETURN_AND_NOTIFY_ON_FAILURE(
- index->second->CopyOutputSampleDataToPictureBuffer(*this, surface),
- "Failed to copy output sample",
- PLATFORM_FAILURE, );
-
- media::Picture output_picture(index->second->id(),
- sample_info.input_buffer_id,
- gfx::Rect(index->second->size()));
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&DXVAVideoDecodeAccelerator::NotifyPictureReady,
- weak_this_factory_.GetWeakPtr(),
- output_picture));
+ index->second->CopyOutputSampleDataToPictureBuffer(
+ this,
+ surface.get(),
+ d3d11_texture.get(),
+ pending_sample->input_buffer_id),
+ "Failed to copy output sample", PLATFORM_FAILURE,);
index->second->set_available(false);
- pending_output_samples_.pop_front();
}
}
-
- if (!pending_input_buffers_.empty() && pending_output_samples_.empty()) {
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers,
- weak_this_factory_.GetWeakPtr()));
- }
}
void DXVAVideoDecodeAccelerator::StopOnError(
media::VideoDecodeAccelerator::Error error) {
- DCHECK(CalledOnValidThread());
+ if (!main_thread_task_runner_->BelongsToCurrentThread()) {
+ main_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&DXVAVideoDecodeAccelerator::StopOnError,
+ weak_this_factory_.GetWeakPtr(),
+ error));
+ return;
+ }
if (client_)
client_->NotifyError(error);
client_ = NULL;
- if (state_ != kUninitialized) {
+ if (GetState() != kUninitialized) {
Invalidate();
}
}
void DXVAVideoDecodeAccelerator::Invalidate() {
- if (state_ == kUninitialized)
+ if (GetState() == kUninitialized)
return;
+ decoder_thread_.Stop();
weak_this_factory_.InvalidateWeakPtrs();
output_picture_buffers_.clear();
stale_output_picture_buffers_.clear();
pending_output_samples_.clear();
pending_input_buffers_.clear();
decoder_.Release();
+
+ if (use_dx11_) {
+ if (video_format_converter_mft_.get()) {
+ video_format_converter_mft_->ProcessMessage(
+ MFT_MESSAGE_NOTIFY_END_STREAMING, 0);
+ video_format_converter_mft_.Release();
+ }
+ d3d11_device_context_.Release();
+ d3d11_device_.Release();
+ d3d11_device_manager_.Release();
+ d3d11_query_.Release();
+ dx11_video_format_converter_media_type_needs_init_ = true;
+ } else {
+ d3d9_.Release();
+ d3d9_device_ex_.Release();
+ device_manager_.Release();
+ query_.Release();
+ }
+
MFShutdown();
- state_ = kUninitialized;
+ SetState(kUninitialized);
}
void DXVAVideoDecodeAccelerator::NotifyInputBufferRead(int input_buffer_id) {
+ DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
if (client_)
client_->NotifyEndOfBitstreamBuffer(input_buffer_id);
}
void DXVAVideoDecodeAccelerator::NotifyFlushDone() {
- if (client_)
+ DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
+ if (client_ && pending_flush_) {
+ pending_flush_ = false;
+ {
+ base::AutoLock lock(decoder_lock_);
+ sent_drain_message_ = false;
+ }
+
client_->NotifyFlushDone();
+ }
}
void DXVAVideoDecodeAccelerator::NotifyResetDone() {
+ DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
if (client_)
client_->NotifyResetDone();
}
void DXVAVideoDecodeAccelerator::RequestPictureBuffers(int width, int height) {
+ DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
// This task could execute after the decoder has been torn down.
- if (state_ != kUninitialized && client_) {
+ if (GetState() != kUninitialized && client_) {
client_->ProvidePictureBuffers(
kNumPictureBuffers,
gfx::Size(width, height),
@@ -1042,14 +1488,21 @@ void DXVAVideoDecodeAccelerator::RequestPictureBuffers(int width, int height) {
}
void DXVAVideoDecodeAccelerator::NotifyPictureReady(
- const media::Picture& picture) {
+ int picture_buffer_id,
+ int input_buffer_id,
+ const gfx::Rect& picture_buffer_size) {
+ DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
// This task could execute after the decoder has been torn down.
- if (state_ != kUninitialized && client_)
+ if (GetState() != kUninitialized && client_) {
+ media::Picture picture(picture_buffer_id, input_buffer_id,
+ picture_buffer_size, false);
client_->PictureReady(picture);
+ }
}
void DXVAVideoDecodeAccelerator::NotifyInputBuffersDropped() {
- if (!client_ || !pending_output_samples_.empty())
+ DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
+ if (!client_)
return;
for (PendingInputs::iterator it = pending_input_buffers_.begin();
@@ -1063,10 +1516,12 @@ void DXVAVideoDecodeAccelerator::NotifyInputBuffersDropped() {
}
void DXVAVideoDecodeAccelerator::DecodePendingInputBuffers() {
- RETURN_AND_NOTIFY_ON_FAILURE((state_ != kUninitialized),
- "Invalid state: " << state_, ILLEGAL_STATE,);
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+ State state = GetState();
+ RETURN_AND_NOTIFY_ON_FAILURE((state != kUninitialized),
+ "Invalid state: " << state, ILLEGAL_STATE,);
- if (pending_input_buffers_.empty() || !pending_output_samples_.empty())
+ if (pending_input_buffers_.empty() || OutputSamplesPresent())
return;
PendingInputs pending_input_buffers_copy;
@@ -1079,33 +1534,62 @@ void DXVAVideoDecodeAccelerator::DecodePendingInputBuffers() {
}
void DXVAVideoDecodeAccelerator::FlushInternal() {
- // The DoDecode function sets the state to kStopped when the decoder returns
- // MF_E_TRANSFORM_NEED_MORE_INPUT.
- // The MFT decoder can buffer upto 30 frames worth of input before returning
- // an output frame. This loop here attempts to retrieve as many output frames
- // as possible from the buffered set.
- while (state_ != kStopped) {
- DoDecode();
- if (!pending_output_samples_.empty())
- return;
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+
+ // We allow only one output frame to be present at any given time. If we have
+ // an output frame, then we cannot complete the flush at this time.
+ if (OutputSamplesPresent())
+ return;
+
+ // First drain the pending input because once the drain message is sent below,
+ // the decoder will ignore further input until it's drained.
+ if (!pending_input_buffers_.empty()) {
+ decoder_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers,
+ base::Unretained(this)));
+ decoder_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&DXVAVideoDecodeAccelerator::FlushInternal,
+ base::Unretained(this)));
+ return;
}
- base::MessageLoop::current()->PostTask(
+ {
+ base::AutoLock lock(decoder_lock_);
+ if (!sent_drain_message_) {
+ RETURN_AND_NOTIFY_ON_FAILURE(SendMFTMessage(MFT_MESSAGE_COMMAND_DRAIN, 0),
+ "Failed to send drain message",
+ PLATFORM_FAILURE,);
+ sent_drain_message_ = true;
+ }
+ }
+
+ // Attempt to retrieve an output frame from the decoder. If we have one,
+ // return and proceed when the output frame is processed. If we don't have a
+ // frame then we are done.
+ DoDecode();
+ if (OutputSamplesPresent())
+ return;
+
+ SetState(kFlushing);
+
+ main_thread_task_runner_->PostTask(
FROM_HERE,
base::Bind(&DXVAVideoDecodeAccelerator::NotifyFlushDone,
weak_this_factory_.GetWeakPtr()));
- state_ = kNormal;
+ SetState(kNormal);
}
void DXVAVideoDecodeAccelerator::DecodeInternal(
const base::win::ScopedComPtr<IMFSample>& sample) {
- DCHECK(CalledOnValidThread());
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
- if (state_ == kUninitialized)
+ if (GetState() == kUninitialized)
return;
- if (!pending_output_samples_.empty() || !pending_input_buffers_.empty()) {
+ if (OutputSamplesPresent() || !pending_input_buffers_.empty()) {
pending_input_buffers_.push_back(sample);
return;
}
@@ -1115,7 +1599,7 @@ void DXVAVideoDecodeAccelerator::DecodeInternal(
}
inputs_before_decode_++;
- HRESULT hr = decoder_->ProcessInput(0, sample, 0);
+ HRESULT hr = decoder_->ProcessInput(0, sample.get(), 0);
// As per msdn if the decoder returns MF_E_NOTACCEPTING then it means that it
// has enough data to produce one or more output samples. In this case the
// recommended options are to
@@ -1127,10 +1611,16 @@ void DXVAVideoDecodeAccelerator::DecodeInternal(
// decoder failure.
if (hr == MF_E_NOTACCEPTING) {
DoDecode();
- RETURN_AND_NOTIFY_ON_FAILURE((state_ == kStopped || state_ == kNormal),
- "Failed to process output. Unexpected decoder state: " << state_,
- PLATFORM_FAILURE,);
- hr = decoder_->ProcessInput(0, sample, 0);
+ // If the DoDecode call resulted in an output frame then we should not
+ // process any more input until that frame is copied to the target surface.
+ if (!OutputSamplesPresent()) {
+ State state = GetState();
+ RETURN_AND_NOTIFY_ON_FAILURE((state == kStopped || state == kNormal ||
+ state == kFlushing),
+ "Failed to process output. Unexpected decoder state: " << state,
+ PLATFORM_FAILURE,);
+ hr = decoder_->ProcessInput(0, sample.get(), 0);
+ }
// If we continue to get the MF_E_NOTACCEPTING error we do the following:-
// 1. Add the input sample to the pending queue.
// 2. If we don't have any output samples we post the
@@ -1142,12 +1632,10 @@ void DXVAVideoDecodeAccelerator::DecodeInternal(
// decoder where it recycles the output Decoder surfaces.
if (hr == MF_E_NOTACCEPTING) {
pending_input_buffers_.push_back(sample);
- if (pending_output_samples_.empty()) {
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers,
- weak_this_factory_.GetWeakPtr()));
- }
+ decoder_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers,
+ base::Unretained(this)));
return;
}
}
@@ -1156,8 +1644,10 @@ void DXVAVideoDecodeAccelerator::DecodeInternal(
DoDecode();
- RETURN_AND_NOTIFY_ON_FAILURE((state_ == kStopped || state_ == kNormal),
- "Failed to process output. Unexpected decoder state: " << state_,
+ State state = GetState();
+ RETURN_AND_NOTIFY_ON_FAILURE((state == kStopped || state == kNormal ||
+ state == kFlushing),
+ "Failed to process output. Unexpected decoder state: " << state,
ILLEGAL_STATE,);
LONGLONG input_buffer_id = 0;
@@ -1173,7 +1663,7 @@ void DXVAVideoDecodeAccelerator::DecodeInternal(
// decoder to emit an output packet for every input packet.
// http://code.google.com/p/chromium/issues/detail?id=108121
// http://code.google.com/p/chromium/issues/detail?id=150925
- base::MessageLoop::current()->PostTask(
+ main_thread_task_runner_->PostTask(
FROM_HERE,
base::Bind(&DXVAVideoDecodeAccelerator::NotifyInputBufferRead,
weak_this_factory_.GetWeakPtr(),
@@ -1182,12 +1672,14 @@ void DXVAVideoDecodeAccelerator::DecodeInternal(
void DXVAVideoDecodeAccelerator::HandleResolutionChanged(int width,
int height) {
- base::MessageLoop::current()->PostTask(
+ dx11_video_format_converter_media_type_needs_init_ = true;
+
+ main_thread_task_runner_->PostTask(
FROM_HERE,
base::Bind(&DXVAVideoDecodeAccelerator::DismissStaleBuffers,
weak_this_factory_.GetWeakPtr()));
- base::MessageLoop::current()->PostTask(
+ main_thread_task_runner_->PostTask(
FROM_HERE,
base::Bind(&DXVAVideoDecodeAccelerator::RequestPictureBuffers,
weak_this_factory_.GetWeakPtr(),
@@ -1224,4 +1716,483 @@ void DXVAVideoDecodeAccelerator::DeferredDismissStaleBuffer(
stale_output_picture_buffers_.erase(it);
}
+DXVAVideoDecodeAccelerator::State
+DXVAVideoDecodeAccelerator::GetState() {
+ static_assert(sizeof(State) == sizeof(long), "mismatched type sizes");
+ State state = static_cast<State>(
+ InterlockedAdd(reinterpret_cast<volatile long*>(&state_), 0));
+ return state;
+}
+
+void DXVAVideoDecodeAccelerator::SetState(State new_state) {
+ if (!main_thread_task_runner_->BelongsToCurrentThread()) {
+ main_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&DXVAVideoDecodeAccelerator::SetState,
+ weak_this_factory_.GetWeakPtr(),
+ new_state));
+ return;
+ }
+
+ static_assert(sizeof(State) == sizeof(long), "mismatched type sizes");
+ ::InterlockedExchange(reinterpret_cast<volatile long*>(&state_),
+ new_state);
+ DCHECK_EQ(state_, new_state);
+}
+
+void DXVAVideoDecodeAccelerator::StartDecoderThread() {
+ decoder_thread_.init_com_with_mta(false);
+ decoder_thread_.Start();
+ decoder_thread_task_runner_ = decoder_thread_.task_runner();
+}
+
+bool DXVAVideoDecodeAccelerator::OutputSamplesPresent() {
+ base::AutoLock lock(decoder_lock_);
+ return !pending_output_samples_.empty();
+}
+
+void DXVAVideoDecodeAccelerator::CopySurface(IDirect3DSurface9* src_surface,
+ IDirect3DSurface9* dest_surface,
+ int picture_buffer_id,
+ int input_buffer_id) {
+ if (!decoder_thread_task_runner_->BelongsToCurrentThread()) {
+ decoder_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&DXVAVideoDecodeAccelerator::CopySurface,
+ base::Unretained(this),
+ src_surface,
+ dest_surface,
+ picture_buffer_id,
+ input_buffer_id));
+ return;
+ }
+
+ HRESULT hr = d3d9_device_ex_->StretchRect(src_surface, NULL, dest_surface,
+ NULL, D3DTEXF_NONE);
+ RETURN_ON_HR_FAILURE(hr, "Colorspace conversion via StretchRect failed",);
+
+ // Ideally, this should be done immediately before the draw call that uses
+ // the texture. Flush it once here though.
+ hr = query_->Issue(D3DISSUE_END);
+ RETURN_ON_HR_FAILURE(hr, "Failed to issue END",);
+
+ // Flush the decoder device to ensure that the decoded frame is copied to the
+ // target surface.
+ decoder_thread_task_runner_->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&DXVAVideoDecodeAccelerator::FlushDecoder,
+ base::Unretained(this), 0, src_surface, dest_surface,
+ picture_buffer_id, input_buffer_id),
+ base::TimeDelta::FromMilliseconds(kFlushDecoderSurfaceTimeoutMs));
+}
+
+void DXVAVideoDecodeAccelerator::CopySurfaceComplete(
+ IDirect3DSurface9* src_surface,
+ IDirect3DSurface9* dest_surface,
+ int picture_buffer_id,
+ int input_buffer_id) {
+ DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
+
+ // The output buffers may have changed in the following scenarios:-
+ // 1. A resolution change.
+ // 2. Decoder instance was destroyed.
+ // Ignore copy surface notifications for such buffers.
+ // copy surface notifications for such buffers.
+ OutputBuffers::iterator it = output_picture_buffers_.find(picture_buffer_id);
+ if (it == output_picture_buffers_.end())
+ return;
+
+ // If the picture buffer is marked as available it probably means that there
+ // was a Reset operation which dropped the output frame.
+ DXVAPictureBuffer* picture_buffer = it->second.get();
+ if (picture_buffer->available())
+ return;
+
+ RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_.Run(),
+ "Failed to make context current", PLATFORM_FAILURE,);
+
+ DCHECK(!output_picture_buffers_.empty());
+
+ picture_buffer->CopySurfaceComplete(src_surface,
+ dest_surface);
+
+ NotifyPictureReady(picture_buffer->id(),
+ input_buffer_id,
+ gfx::Rect(picture_buffer->size()));
+
+ {
+ base::AutoLock lock(decoder_lock_);
+ if (!pending_output_samples_.empty())
+ pending_output_samples_.pop_front();
+ }
+
+ if (pending_flush_) {
+ decoder_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&DXVAVideoDecodeAccelerator::FlushInternal,
+ base::Unretained(this)));
+ return;
+ }
+ decoder_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers,
+ base::Unretained(this)));
+}
+
+void DXVAVideoDecodeAccelerator::CopyTexture(ID3D11Texture2D* src_texture,
+ ID3D11Texture2D* dest_texture,
+ IMFSample* video_frame,
+ int picture_buffer_id,
+ int input_buffer_id) {
+ HRESULT hr = E_FAIL;
+
+ DCHECK(use_dx11_);
+
+ if (!decoder_thread_task_runner_->BelongsToCurrentThread()) {
+ // The media foundation H.264 decoder outputs YUV12 textures which we
+ // cannot copy into ANGLE as they expect ARGB textures. In D3D land
+ // the StretchRect API in the IDirect3DDevice9Ex interface did the color
+ // space conversion for us. Sadly in DX11 land the API does not provide
+ // a straightforward way to do this.
+ // We use the video processor MFT.
+ // https://msdn.microsoft.com/en-us/library/hh162913(v=vs.85).aspx
+ // This object implements a media foundation transform (IMFTransform)
+ // which follows the same contract as the decoder. The color space
+ // conversion as per msdn is done in the GPU.
+
+ D3D11_TEXTURE2D_DESC source_desc;
+ src_texture->GetDesc(&source_desc);
+
+ // Set up the input and output types for the video processor MFT.
+ if (!InitializeDX11VideoFormatConverterMediaType(source_desc.Width,
+ source_desc.Height)) {
+ RETURN_AND_NOTIFY_ON_FAILURE(
+ false, "Failed to initialize media types for convesion.",
+ PLATFORM_FAILURE,);
+ }
+
+ // The input to the video processor is the output sample.
+ base::win::ScopedComPtr<IMFSample> input_sample_for_conversion;
+ {
+ base::AutoLock lock(decoder_lock_);
+ PendingSampleInfo& sample_info = pending_output_samples_.front();
+ input_sample_for_conversion = sample_info.output_sample;
+ }
+
+ decoder_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&DXVAVideoDecodeAccelerator::CopyTexture,
+ base::Unretained(this),
+ src_texture,
+ dest_texture,
+ input_sample_for_conversion.Detach(),
+ picture_buffer_id,
+ input_buffer_id));
+ return;
+ }
+
+ DCHECK(video_frame);
+
+ base::win::ScopedComPtr<IMFSample> input_sample;
+ input_sample.Attach(video_frame);
+
+ DCHECK(video_format_converter_mft_.get());
+
+ // d3d11_device_context_->Begin(d3d11_query_.get());
+
+ hr = video_format_converter_mft_->ProcessInput(0, video_frame, 0);
+ if (FAILED(hr)) {
+ DCHECK(false);
+ RETURN_AND_NOTIFY_ON_HR_FAILURE(hr,
+ "Failed to convert output sample format.", PLATFORM_FAILURE,);
+ }
+
+ // The video processor MFT requires output samples to be allocated by the
+ // caller. We create a sample with a buffer backed with the ID3D11Texture2D
+ // interface exposed by ANGLE. This works nicely as this ensures that the
+ // video processor coverts the color space of the output frame and copies
+ // the result into the ANGLE texture.
+ base::win::ScopedComPtr<IMFSample> output_sample;
+ hr = MFCreateSample(output_sample.Receive());
+ if (FAILED(hr)) {
+ RETURN_AND_NOTIFY_ON_HR_FAILURE(hr,
+ "Failed to create output sample.", PLATFORM_FAILURE,);
+ }
+
+ base::win::ScopedComPtr<IMFMediaBuffer> output_buffer;
+ hr = MFCreateDXGISurfaceBuffer(
+ __uuidof(ID3D11Texture2D), dest_texture, 0, FALSE,
+ output_buffer.Receive());
+ if (FAILED(hr)) {
+ base::debug::Alias(&hr);
+ // TODO(ananta)
+ // Remove this CHECK when the change to use DX11 for H/W decoding
+ // stablizes.
+ CHECK(false);
+ RETURN_AND_NOTIFY_ON_HR_FAILURE(hr,
+ "Failed to create output sample.", PLATFORM_FAILURE,);
+ }
+
+ output_sample->AddBuffer(output_buffer.get());
+
+ DWORD status = 0;
+ MFT_OUTPUT_DATA_BUFFER format_converter_output = {};
+ format_converter_output.pSample = output_sample.get();
+ hr = video_format_converter_mft_->ProcessOutput(
+ 0, // No flags
+ 1, // # of out streams to pull from
+ &format_converter_output,
+ &status);
+
+ d3d11_device_context_->Flush();
+ d3d11_device_context_->End(d3d11_query_.get());
+
+ if (FAILED(hr)) {
+ base::debug::Alias(&hr);
+ // TODO(ananta)
+ // Remove this CHECK when the change to use DX11 for H/W decoding
+ // stablizes.
+ CHECK(false);
+ RETURN_AND_NOTIFY_ON_HR_FAILURE(hr,
+ "Failed to convert output sample format.", PLATFORM_FAILURE,);
+ }
+
+ decoder_thread_task_runner_->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&DXVAVideoDecodeAccelerator::FlushDecoder,
+ base::Unretained(this), 0,
+ reinterpret_cast<IDirect3DSurface9*>(NULL),
+ reinterpret_cast<IDirect3DSurface9*>(NULL),
+ picture_buffer_id, input_buffer_id),
+ base::TimeDelta::FromMilliseconds(
+ kFlushDecoderSurfaceTimeoutMs));
+}
+
+void DXVAVideoDecodeAccelerator::FlushDecoder(
+ int iterations,
+ IDirect3DSurface9* src_surface,
+ IDirect3DSurface9* dest_surface,
+ int picture_buffer_id,
+ int input_buffer_id) {
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+
+ // The DXVA decoder has its own device which it uses for decoding. ANGLE
+ // has its own device which we don't have access to.
+ // The above code attempts to copy the decoded picture into a surface
+ // which is owned by ANGLE. As there are multiple devices involved in
+ // this, the StretchRect call above is not synchronous.
+ // We attempt to flush the batched operations to ensure that the picture is
+ // copied to the surface owned by ANGLE.
+ // We need to do this in a loop and call flush multiple times.
+ // We have seen the GetData call for flushing the command buffer fail to
+ // return success occassionally on multi core machines, leading to an
+ // infinite loop.
+ // Workaround is to have an upper limit of 4 on the number of iterations to
+ // wait for the Flush to finish.
+ HRESULT hr = E_FAIL;
+
+ if (use_dx11_) {
+ BOOL query_data = 0;
+ hr = d3d11_device_context_->GetData(d3d11_query_.get(), &query_data,
+ sizeof(BOOL), 0);
+ if (FAILED(hr)) {
+ base::debug::Alias(&hr);
+ // TODO(ananta)
+ // Remove this CHECK when the change to use DX11 for H/W decoding
+ // stablizes.
+ CHECK(false);
+ }
+ } else {
+ hr = query_->GetData(NULL, 0, D3DGETDATA_FLUSH);
+ }
+ if ((hr == S_FALSE) && (++iterations < kMaxIterationsForD3DFlush)) {
+ decoder_thread_task_runner_->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&DXVAVideoDecodeAccelerator::FlushDecoder,
+ base::Unretained(this), iterations, src_surface,
+ dest_surface, picture_buffer_id, input_buffer_id),
+ base::TimeDelta::FromMilliseconds(kFlushDecoderSurfaceTimeoutMs));
+ return;
+ }
+
+ main_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&DXVAVideoDecodeAccelerator::CopySurfaceComplete,
+ weak_this_factory_.GetWeakPtr(),
+ src_surface,
+ dest_surface,
+ picture_buffer_id,
+ input_buffer_id));
+}
+
+bool DXVAVideoDecodeAccelerator::InitializeDX11VideoFormatConverterMediaType(
+ int width, int height) {
+ if (!dx11_video_format_converter_media_type_needs_init_)
+ return true;
+
+ CHECK(video_format_converter_mft_.get());
+
+ HRESULT hr = video_format_converter_mft_->ProcessMessage(
+ MFT_MESSAGE_SET_D3D_MANAGER,
+ reinterpret_cast<ULONG_PTR>(
+ d3d11_device_manager_.get()));
+
+ if (FAILED(hr)) {
+ base::debug::Alias(&hr);
+ // TODO(ananta)
+ // Remove this CHECK when the change to use DX11 for H/W decoding
+ // stablizes.
+ CHECK(false);
+ }
+ RETURN_AND_NOTIFY_ON_HR_FAILURE(hr,
+ "Failed to initialize video format converter", PLATFORM_FAILURE, false);
+
+ video_format_converter_mft_->ProcessMessage(
+ MFT_MESSAGE_NOTIFY_END_STREAMING, 0);
+
+ base::win::ScopedComPtr<IMFMediaType> media_type;
+ hr = MFCreateMediaType(media_type.Receive());
+ RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "MFCreateMediaType failed",
+ PLATFORM_FAILURE, false);
+
+ hr = media_type->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
+ RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to set major input type",
+ PLATFORM_FAILURE, false);
+
+ hr = media_type->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_NV12);
+ RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to set input sub type",
+ PLATFORM_FAILURE, false);
+
+ hr = media_type->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
+ RETURN_AND_NOTIFY_ON_HR_FAILURE(hr,
+ "Failed to set attributes on media type", PLATFORM_FAILURE, false);
+
+ hr = media_type->SetUINT32(MF_MT_INTERLACE_MODE,
+ MFVideoInterlace_Progressive);
+ RETURN_AND_NOTIFY_ON_HR_FAILURE(hr,
+ "Failed to set attributes on media type", PLATFORM_FAILURE, false);
+
+ base::win::ScopedComPtr<IMFAttributes> converter_attributes;
+ hr = video_format_converter_mft_->GetAttributes(
+ converter_attributes.Receive());
+ RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to get converter attributes",
+ PLATFORM_FAILURE, false);
+
+ hr = converter_attributes->SetUINT32(MF_XVP_PLAYBACK_MODE, TRUE);
+ RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to set converter attributes",
+ PLATFORM_FAILURE, false);
+
+ hr = converter_attributes->SetUINT32(MF_LOW_LATENCY, FALSE);
+ RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to set converter attributes",
+ PLATFORM_FAILURE, false);
+
+ hr = MFSetAttributeSize(media_type.get(), MF_MT_FRAME_SIZE, width, height);
+ RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to set media type attributes",
+ PLATFORM_FAILURE, false);
+
+ hr = video_format_converter_mft_->SetInputType(0, media_type.get(), 0);
+ if (FAILED(hr)) {
+ base::debug::Alias(&hr);
+ // TODO(ananta)
+ // Remove this CHECK when the change to use DX11 for H/W decoding
+ // stablizes.
+ CHECK(false);
+ }
+ RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to set converter input type",
+ PLATFORM_FAILURE, false);
+
+ base::win::ScopedComPtr<IMFMediaType> out_media_type;
+
+ for (uint32 i = 0;
+ SUCCEEDED(video_format_converter_mft_->GetOutputAvailableType(0, i,
+ out_media_type.Receive()));
+ ++i) {
+ GUID out_subtype = {0};
+ hr = out_media_type->GetGUID(MF_MT_SUBTYPE, &out_subtype);
+ RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to get output major type",
+ PLATFORM_FAILURE, false);
+
+ if (out_subtype == MFVideoFormat_ARGB32) {
+ hr = out_media_type->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
+ RETURN_AND_NOTIFY_ON_HR_FAILURE(hr,
+ "Failed to set attributes on media type", PLATFORM_FAILURE, false);
+
+ hr = out_media_type->SetUINT32(MF_MT_INTERLACE_MODE,
+ MFVideoInterlace_Progressive);
+ RETURN_AND_NOTIFY_ON_HR_FAILURE(hr,
+ "Failed to set attributes on media type", PLATFORM_FAILURE, false);
+
+ hr = MFSetAttributeSize(out_media_type.get(), MF_MT_FRAME_SIZE, width,
+ height);
+ RETURN_AND_NOTIFY_ON_HR_FAILURE(hr,
+ "Failed to set media type attributes", PLATFORM_FAILURE, false);
+
+ hr = video_format_converter_mft_->SetOutputType(
+ 0, out_media_type.get(), 0); // No flags
+ if (FAILED(hr)) {
+ base::debug::Alias(&hr);
+ // TODO(ananta)
+ // Remove this CHECK when the change to use DX11 for H/W decoding
+ // stablizes.
+ CHECK(false);
+ }
+ RETURN_AND_NOTIFY_ON_HR_FAILURE(hr,
+ "Failed to set converter output type", PLATFORM_FAILURE, false);
+
+ hr = video_format_converter_mft_->ProcessMessage(
+ MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0);
+ if (FAILED(hr)) {
+ // TODO(ananta)
+ // Remove this CHECK when the change to use DX11 for H/W decoding
+ // stablizes.
+ RETURN_AND_NOTIFY_ON_FAILURE(
+ false, "Failed to initialize video converter.", PLATFORM_FAILURE,
+ false);
+ }
+ dx11_video_format_converter_media_type_needs_init_ = false;
+ return true;
+ }
+ out_media_type.Release();
+ }
+ return false;
+}
+
+bool DXVAVideoDecodeAccelerator::GetVideoFrameDimensions(
+ IMFSample* sample,
+ int* width,
+ int* height) {
+ base::win::ScopedComPtr<IMFMediaBuffer> output_buffer;
+ HRESULT hr = sample->GetBufferByIndex(0, output_buffer.Receive());
+ RETURN_ON_HR_FAILURE(hr, "Failed to get buffer from output sample", false);
+
+ if (use_dx11_) {
+ base::win::ScopedComPtr<IMFDXGIBuffer> dxgi_buffer;
+ base::win::ScopedComPtr<ID3D11Texture2D> d3d11_texture;
+ hr = dxgi_buffer.QueryFrom(output_buffer.get());
+ RETURN_ON_HR_FAILURE(hr, "Failed to get DXGIBuffer from output sample",
+ false);
+ hr = dxgi_buffer->GetResource(
+ __uuidof(ID3D11Texture2D),
+ reinterpret_cast<void**>(d3d11_texture.Receive()));
+ RETURN_ON_HR_FAILURE(hr, "Failed to get D3D11Texture from output buffer",
+ false);
+ D3D11_TEXTURE2D_DESC d3d11_texture_desc;
+ d3d11_texture->GetDesc(&d3d11_texture_desc);
+ *width = d3d11_texture_desc.Width;
+ *height = d3d11_texture_desc.Height;
+ } else {
+ base::win::ScopedComPtr<IDirect3DSurface9> surface;
+ hr = MFGetService(output_buffer.get(), MR_BUFFER_SERVICE,
+ IID_PPV_ARGS(surface.Receive()));
+ RETURN_ON_HR_FAILURE(hr, "Failed to get D3D surface from output sample",
+ false);
+ D3DSURFACE_DESC surface_desc;
+ hr = surface->GetDesc(&surface_desc);
+ RETURN_ON_HR_FAILURE(hr, "Failed to get surface description", false);
+ *width = surface_desc.Width;
+ *height = surface_desc.Height;
+ }
+ return true;
+}
+
} // namespace content
diff --git a/chromium/content/common/gpu/media/dxva_video_decode_accelerator.h b/chromium/content/common/gpu/media/dxva_video_decode_accelerator.h
index f53f4a12bc1..918531dc988 100644
--- a/chromium/content/common/gpu/media/dxva_video_decode_accelerator.h
+++ b/chromium/content/common/gpu/media/dxva_video_decode_accelerator.h
@@ -5,6 +5,7 @@
#ifndef CONTENT_COMMON_GPU_MEDIA_DXVA_VIDEO_DECODE_ACCELERATOR_H_
#define CONTENT_COMMON_GPU_MEDIA_DXVA_VIDEO_DECODE_ACCELERATOR_H_
+#include <d3d11.h>
#include <d3d9.h>
// Work around bug in this header by disabling the relevant warning for it.
// https://connect.microsoft.com/VisualStudio/feedback/details/911260/dxva2api-h-in-win8-sdk-triggers-c4201-with-w4
@@ -20,7 +21,9 @@
#include "base/compiler_specific.h"
#include "base/memory/linked_ptr.h"
#include "base/memory/weak_ptr.h"
+#include "base/synchronization/lock.h"
#include "base/threading/non_thread_safe.h"
+#include "base/threading/thread.h"
#include "base/win/scoped_comptr.h"
#include "content/common/content_export.h"
#include "media/video/video_decode_accelerator.h"
@@ -28,6 +31,14 @@
interface IMFSample;
interface IDirect3DSurface9;
+namespace gfx {
+class GLContext;
+}
+
+typedef HRESULT (WINAPI* CreateDXGIDeviceManager)(
+ UINT* reset_token,
+ IMFDXGIDeviceManager** device_manager);
+
namespace content {
// Class to provide a DXVA 2.0 based accelerator using the Microsoft Media
@@ -35,60 +46,70 @@ namespace content {
// This class lives on a single thread and DCHECKs that it is never accessed
// from any other.
class CONTENT_EXPORT DXVAVideoDecodeAccelerator
- : public media::VideoDecodeAccelerator,
- NON_EXPORTED_BASE(public base::NonThreadSafe) {
+ : public media::VideoDecodeAccelerator {
public:
enum State {
- kUninitialized, // un-initialized.
- kNormal, // normal playing state.
- kResetting, // upon received Reset(), before ResetDone()
- kStopped, // upon output EOS received.
- kFlushing, // upon flush request received.
+ kUninitialized, // un-initialized.
+ kNormal, // normal playing state.
+ kResetting, // upon received Reset(), before ResetDone()
+ kStopped, // upon output EOS received.
+ kFlushing, // upon flush request received.
};
// Does not take ownership of |client| which must outlive |*this|.
explicit DXVAVideoDecodeAccelerator(
- const base::Callback<bool(void)>& make_context_current);
- virtual ~DXVAVideoDecodeAccelerator();
+ const base::Callback<bool(void)>& make_context_current,
+ gfx::GLContext* gl_context);
+ ~DXVAVideoDecodeAccelerator() override;
// media::VideoDecodeAccelerator implementation.
- virtual bool Initialize(media::VideoCodecProfile profile,
- Client* client) override;
- virtual void Decode(const media::BitstreamBuffer& bitstream_buffer) override;
- virtual void AssignPictureBuffers(
+ bool Initialize(media::VideoCodecProfile profile,
+ Client* client) override;
+ void Decode(const media::BitstreamBuffer& bitstream_buffer) override;
+ void AssignPictureBuffers(
const std::vector<media::PictureBuffer>& buffers) override;
- virtual void ReusePictureBuffer(int32 picture_buffer_id) override;
- virtual void Flush() override;
- virtual void Reset() override;
- virtual void Destroy() override;
- virtual bool CanDecodeOnIOThread() override;
+ void ReusePictureBuffer(int32 picture_buffer_id) override;
+ void Flush() override;
+ void Reset() override;
+ void Destroy() override;
+ bool CanDecodeOnIOThread() override;
+ GLenum GetSurfaceInternalFormat() const override;
+
+ static media::VideoDecodeAccelerator::SupportedProfiles
+ GetSupportedProfiles();
private:
typedef void* EGLConfig;
typedef void* EGLSurface;
+
// Creates and initializes an instance of the D3D device and the
// corresponding device manager. The device manager instance is eventually
- // passed to the IMFTransform interface implemented by the h.264 decoder.
+ // passed to the IMFTransform interface implemented by the decoder.
bool CreateD3DDevManager();
- // Creates, initializes and sets the media types for the h.264 decoder.
+ // Creates and initializes an instance of the DX11 device and the
+ // corresponding device manager. The device manager instance is eventually
+ // passed to the IMFTransform interface implemented by the decoder.
+ bool CreateDX11DevManager();
+
+ // Creates, initializes and sets the media codec types for the decoder.
bool InitDecoder(media::VideoCodecProfile profile);
- // Validates whether the h.264 decoder supports hardware video acceleration.
+ // Validates whether the decoder supports hardware video acceleration.
bool CheckDecoderDxvaSupport();
// Returns information about the input and output streams. This includes
// alignment information, decoder support flags, minimum sample size, etc.
bool GetStreamsInfoAndBufferReqs();
- // Registers the input and output media types on the h.264 decoder. This
- // includes the expected input and output formats.
+ // Registers the input and output media types on the decoder. This includes
+ // the expected input and output formats.
bool SetDecoderMediaTypes();
- // Registers the input media type for the h.264 decoder.
+ // Registers the input media type for the decoder.
bool SetDecoderInputMediaType();
- // Registers the output media type for the h.264 decoder.
+ // Registers the output media type for the decoder.
bool SetDecoderOutputMediaType(const GUID& subtype);
// Passes a command message to the decoder. This includes commands like
@@ -129,7 +150,9 @@ class CONTENT_EXPORT DXVAVideoDecodeAccelerator
void RequestPictureBuffers(int width, int height);
// Notifies the client about the availability of a picture.
- void NotifyPictureReady(const media::Picture& picture);
+ void NotifyPictureReady(int picture_buffer_id,
+ int input_buffer_id,
+ const gfx::Rect& picture_buffer_size);
// Sends pending input buffer processed acks to the client if we don't have
// output samples waiting to be processed.
@@ -156,15 +179,85 @@ class CONTENT_EXPORT DXVAVideoDecodeAccelerator
// Called after the client indicates we can recycle a stale picture buffer.
void DeferredDismissStaleBuffer(int32 picture_buffer_id);
+ // Sets the state of the decoder. Called from the main thread and the decoder
+ // thread. The state is changed on the main thread.
+ void SetState(State state);
+
+ // Gets the state of the decoder. Can be called from the main thread and
+ // the decoder thread. Thread safe.
+ State GetState();
+
+ // Worker function for the Decoder Reset functionality. Executes on the
+ // decoder thread and queues tasks on the main thread as needed.
+ void ResetHelper();
+
+ // Starts the thread used for decoding.
+ void StartDecoderThread();
+
+ // Returns if we have output samples waiting to be processed. We only
+ // allow one output sample to be present in the output queue at any given
+ // time.
+ bool OutputSamplesPresent();
+
+ // Copies the source surface |src_surface| to the destination |dest_surface|.
+ // The copying is done on the decoder thread.
+ void CopySurface(IDirect3DSurface9* src_surface,
+ IDirect3DSurface9* dest_surface,
+ int picture_buffer_id,
+ int input_buffer_id);
+
+ // This is a notification that the source surface |src_surface| was copied to
+ // the destination |dest_surface|. Received on the main thread.
+ void CopySurfaceComplete(IDirect3DSurface9* src_surface,
+ IDirect3DSurface9* dest_surface,
+ int picture_buffer_id,
+ int input_buffer_id);
+
+ // Copies the source texture |src_texture| to the destination |dest_texture|.
+ // The copying is done on the decoder thread. The |video_frame| parameter
+ // is the sample containing the frame to be copied.
+ void CopyTexture(ID3D11Texture2D* src_texture,
+ ID3D11Texture2D* dest_texture,
+ IMFSample* video_frame,
+ int picture_buffer_id,
+ int input_buffer_id);
+
+ // Flushes the decoder device to ensure that the decoded surface is copied
+ // to the target surface. |iterations| helps to maintain an upper limit on
+ // the number of times we try to complete the flush operation.
+ void FlushDecoder(int iterations,
+ IDirect3DSurface9* src_surface,
+ IDirect3DSurface9* dest_surface,
+ int picture_buffer_id,
+ int input_buffer_id);
+
+ // Initializes the DX11 Video format converter media types.
+ // Returns true on success.
+ bool InitializeDX11VideoFormatConverterMediaType(int width, int height);
+
+ // Returns the output video frame dimensions (width, height).
+ // |sample| :- This is the output sample containing the video frame.
+ // |width| :- The width is returned here.
+ // |height| :- The height is returned here.
+ // Returns true on success.
+ bool GetVideoFrameDimensions(IMFSample* sample, int* width, int* height);
+
// To expose client callbacks from VideoDecodeAccelerator.
media::VideoDecodeAccelerator::Client* client_;
base::win::ScopedComPtr<IMFTransform> decoder_;
+ base::win::ScopedComPtr<IMFTransform> video_format_converter_mft_;
base::win::ScopedComPtr<IDirect3D9Ex> d3d9_;
- base::win::ScopedComPtr<IDirect3DDevice9Ex> device_;
+ base::win::ScopedComPtr<IDirect3DDevice9Ex> d3d9_device_ex_;
base::win::ScopedComPtr<IDirect3DDeviceManager9> device_manager_;
base::win::ScopedComPtr<IDirect3DQuery9> query_;
+
+ base::win::ScopedComPtr<ID3D11DeviceContext> d3d11_device_context_;
+ base::win::ScopedComPtr<ID3D11Device > d3d11_device_;
+ base::win::ScopedComPtr<IMFDXGIDeviceManager> d3d11_device_manager_;
+ base::win::ScopedComPtr<ID3D11Query> d3d11_query_;
+
// Ideally the reset token would be a stack variable which is used while
// creating the device manager. However it seems that the device manager
// holds onto the token and attempts to access it if the underlying device
@@ -172,11 +265,16 @@ class CONTENT_EXPORT DXVAVideoDecodeAccelerator
// TODO(ananta): This needs to be verified.
uint32 dev_manager_reset_token_;
+ // Reset token for the DX11 device manager.
+ uint32 dx11_dev_manager_reset_token_;
+
+ uint32 dx11_dev_manager_reset_token_format_conversion_;
+
// The EGL config to use for decoded frames.
EGLConfig egl_config_;
// Current state of the decoder.
- State state_;
+ volatile State state_;
MFT_INPUT_STREAM_INFO input_stream_info_;
MFT_OUTPUT_STREAM_INFO output_stream_info_;
@@ -187,12 +285,17 @@ class CONTENT_EXPORT DXVAVideoDecodeAccelerator
~PendingSampleInfo();
int32 input_buffer_id;
+
+ // The target picture buffer id where the frame would be copied to.
+ // Defaults to -1.
+ int picture_buffer_id;
+
base::win::ScopedComPtr<IMFSample> output_sample;
};
typedef std::list<PendingSampleInfo> PendingOutputSamples;
- // List of decoded output samples.
+ // List of decoded output samples. Protected by |decoder_lock_|.
PendingOutputSamples pending_output_samples_;
// This map maintains the picture buffers passed the client for decoding.
@@ -212,6 +315,11 @@ class CONTENT_EXPORT DXVAVideoDecodeAccelerator
// decode.
int inputs_before_decode_;
+ // Set to true when the drain message is sent to the decoder during a flush
+ // operation. Used to ensure the message is only sent once after
+ // |pending_input_buffers_| is drained. Protected by |decoder_lock_|.
+ bool sent_drain_message_;
+
// List of input samples waiting to be processed.
typedef std::list<base::win::ScopedComPtr<IMFSample>> PendingInputs;
PendingInputs pending_input_buffers_;
@@ -219,8 +327,48 @@ class CONTENT_EXPORT DXVAVideoDecodeAccelerator
// Callback to set the correct gl context.
base::Callback<bool(void)> make_context_current_;
+ // Which codec we are decoding with hardware acceleration.
+ media::VideoCodec codec_;
+ // Thread on which the decoder operations like passing input frames,
+ // getting output frames are performed. One instance of this thread
+ // is created per decoder instance.
+ base::Thread decoder_thread_;
+
+ // Task runner to be used for posting tasks to the decoder thread.
+ scoped_refptr<base::SingleThreadTaskRunner> decoder_thread_task_runner_;
+
+ // Task runner to be used for posting tasks to the main thread.
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
+
+ // Used to synchronize access between the decoder thread and the main thread.
+ base::Lock decoder_lock_;
+
+ // Disallow rebinding WeakReference ownership to a different thread by
+ // keeping a persistent reference. This avoids problems with the
+ // thread safety of reaching into this class from multiple threads to
+ // attain a WeakPtr.
+ base::WeakPtr<DXVAVideoDecodeAccelerator> weak_ptr_;
+
+ // Set to true if we are in the context of a Flush operation. Used to prevent
+ // multiple flush done notifications being sent out.
+ bool pending_flush_;
+
+ // Defaults to false. Indicates if we should use D3D or DX11 interfaces for
+ // H/W decoding.
+ bool use_dx11_;
+
+ // Set to true if the DX11 video format converter input media types need to
+ // be initialized. Defaults to true.
+ bool dx11_video_format_converter_media_type_needs_init_;
+
+ // The GLContext to be used by the decoder.
+ scoped_refptr<gfx::GLContext> gl_context_;
+
// WeakPtrFactory for posting tasks back to |this|.
base::WeakPtrFactory<DXVAVideoDecodeAccelerator> weak_this_factory_;
+
+ // Function pointer for the MFCreateDXGIDeviceManager API.
+ static CreateDXGIDeviceManager create_dxgi_device_manager_;
};
} // namespace content
diff --git a/chromium/content/common/gpu/media/exynos_v4l2_video_device.cc b/chromium/content/common/gpu/media/exynos_v4l2_video_device.cc
deleted file mode 100644
index 214a4311ab3..00000000000
--- a/chromium/content/common/gpu/media/exynos_v4l2_video_device.cc
+++ /dev/null
@@ -1,211 +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 <fcntl.h>
-#include <libdrm/drm_fourcc.h>
-#include <linux/videodev2.h>
-#include <poll.h>
-#include <sys/eventfd.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-
-#include "base/debug/trace_event.h"
-#include "base/files/scoped_file.h"
-#include "base/posix/eintr_wrapper.h"
-#include "content/common/gpu/media/exynos_v4l2_video_device.h"
-#include "ui/gl/gl_bindings.h"
-
-namespace content {
-
-namespace {
-const char kDecoderDevice[] = "/dev/mfc-dec";
-const char kEncoderDevice[] = "/dev/mfc-enc";
-const char kImageProcessorDevice[] = "/dev/gsc1";
-}
-
-ExynosV4L2Device::ExynosV4L2Device(Type type)
- : type_(type),
- device_fd_(-1),
- device_poll_interrupt_fd_(-1) {}
-
-ExynosV4L2Device::~ExynosV4L2Device() {
- if (device_poll_interrupt_fd_ != -1) {
- close(device_poll_interrupt_fd_);
- device_poll_interrupt_fd_ = -1;
- }
- if (device_fd_ != -1) {
- close(device_fd_);
- device_fd_ = -1;
- }
-}
-
-int ExynosV4L2Device::Ioctl(int request, void* arg) {
- return HANDLE_EINTR(ioctl(device_fd_, request, arg));
-}
-
-bool ExynosV4L2Device::Poll(bool poll_device, bool* event_pending) {
- struct pollfd pollfds[2];
- nfds_t nfds;
- int pollfd = -1;
-
- pollfds[0].fd = device_poll_interrupt_fd_;
- pollfds[0].events = POLLIN | POLLERR;
- nfds = 1;
-
- if (poll_device) {
- DVLOG(3) << "Poll(): adding device fd to poll() set";
- pollfds[nfds].fd = device_fd_;
- pollfds[nfds].events = POLLIN | POLLOUT | POLLERR | POLLPRI;
- pollfd = nfds;
- nfds++;
- }
-
- if (HANDLE_EINTR(poll(pollfds, nfds, -1)) == -1) {
- DPLOG(ERROR) << "poll() failed";
- return false;
- }
- *event_pending = (pollfd != -1 && pollfds[pollfd].revents & POLLPRI);
- return true;
-}
-
-void* ExynosV4L2Device::Mmap(void* addr,
- unsigned int len,
- int prot,
- int flags,
- unsigned int offset) {
- return mmap(addr, len, prot, flags, device_fd_, offset);
-}
-
-void ExynosV4L2Device::Munmap(void* addr, unsigned int len) {
- munmap(addr, len);
-}
-
-bool ExynosV4L2Device::SetDevicePollInterrupt() {
- DVLOG(3) << "SetDevicePollInterrupt()";
-
- const uint64 buf = 1;
- if (HANDLE_EINTR(write(device_poll_interrupt_fd_, &buf, sizeof(buf))) == -1) {
- DPLOG(ERROR) << "SetDevicePollInterrupt(): write() failed";
- return false;
- }
- return true;
-}
-
-bool ExynosV4L2Device::ClearDevicePollInterrupt() {
- DVLOG(3) << "ClearDevicePollInterrupt()";
-
- uint64 buf;
- if (HANDLE_EINTR(read(device_poll_interrupt_fd_, &buf, sizeof(buf))) == -1) {
- if (errno == EAGAIN) {
- // No interrupt flag set, and we're reading nonblocking. Not an error.
- return true;
- } else {
- DPLOG(ERROR) << "ClearDevicePollInterrupt(): read() failed";
- return false;
- }
- }
- return true;
-}
-
-bool ExynosV4L2Device::Initialize() {
- const char* device_path = NULL;
- switch (type_) {
- case kDecoder:
- device_path = kDecoderDevice;
- break;
- case kEncoder:
- device_path = kEncoderDevice;
- break;
- case kImageProcessor:
- device_path = kImageProcessorDevice;
- break;
- }
-
- DVLOG(2) << "Initialize(): opening device: " << device_path;
- // Open the video device.
- device_fd_ = HANDLE_EINTR(open(device_path, O_RDWR | O_NONBLOCK | O_CLOEXEC));
- if (device_fd_ == -1) {
- return false;
- }
-
- device_poll_interrupt_fd_ = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
- if (device_poll_interrupt_fd_ == -1) {
- return false;
- }
- return true;
-}
-
-EGLImageKHR ExynosV4L2Device::CreateEGLImage(EGLDisplay egl_display,
- EGLContext /* egl_context */,
- GLuint texture_id,
- gfx::Size frame_buffer_size,
- unsigned int buffer_index,
- size_t planes_count) {
- DVLOG(3) << "CreateEGLImage()";
-
- scoped_ptr<base::ScopedFD[]> dmabuf_fds(new base::ScopedFD[planes_count]);
- for (size_t i = 0; i < planes_count; ++i) {
- // Export the DMABUF fd so we can export it as a texture.
- struct v4l2_exportbuffer expbuf;
- memset(&expbuf, 0, sizeof(expbuf));
- expbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- expbuf.index = buffer_index;
- expbuf.plane = i;
- expbuf.flags = O_CLOEXEC;
- if (Ioctl(VIDIOC_EXPBUF, &expbuf) != 0) {
- return EGL_NO_IMAGE_KHR;
- }
- dmabuf_fds[i].reset(expbuf.fd);
- }
- DCHECK_EQ(planes_count, 2u);
- EGLint attrs[] = {
- EGL_WIDTH, 0, EGL_HEIGHT, 0,
- EGL_LINUX_DRM_FOURCC_EXT, 0, EGL_DMA_BUF_PLANE0_FD_EXT, 0,
- EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0, EGL_DMA_BUF_PLANE0_PITCH_EXT, 0,
- EGL_DMA_BUF_PLANE1_FD_EXT, 0, EGL_DMA_BUF_PLANE1_OFFSET_EXT, 0,
- EGL_DMA_BUF_PLANE1_PITCH_EXT, 0, EGL_NONE, };
- attrs[1] = frame_buffer_size.width();
- attrs[3] = frame_buffer_size.height();
- attrs[5] = DRM_FORMAT_NV12;
- attrs[7] = dmabuf_fds[0].get();
- attrs[9] = 0;
- attrs[11] = frame_buffer_size.width();
- attrs[13] = dmabuf_fds[1].get();
- attrs[15] = 0;
- attrs[17] = frame_buffer_size.width();
-
- EGLImageKHR egl_image = eglCreateImageKHR(
- egl_display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attrs);
- if (egl_image == EGL_NO_IMAGE_KHR) {
- return egl_image;
- }
- glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_id);
- glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, egl_image);
-
- return egl_image;
-}
-
-EGLBoolean ExynosV4L2Device::DestroyEGLImage(EGLDisplay egl_display,
- EGLImageKHR egl_image) {
- return eglDestroyImageKHR(egl_display, egl_image);
-}
-
-GLenum ExynosV4L2Device::GetTextureTarget() { return GL_TEXTURE_EXTERNAL_OES; }
-
-uint32 ExynosV4L2Device::PreferredInputFormat() {
- // TODO(posciak): We should support "dontcare" returns here once we
- // implement proper handling (fallback, negotiation) for this in users.
- CHECK_EQ(type_, kEncoder);
- return V4L2_PIX_FMT_NV12M;
-}
-
-uint32 ExynosV4L2Device::PreferredOutputFormat() {
- // TODO(posciak): We should support "dontcare" returns here once we
- // implement proper handling (fallback, negotiation) for this in users.
- CHECK_EQ(type_, kDecoder);
- return V4L2_PIX_FMT_NV12M;
-}
-
-} // namespace content
diff --git a/chromium/content/common/gpu/media/exynos_v4l2_video_device.h b/chromium/content/common/gpu/media/exynos_v4l2_video_device.h
deleted file mode 100644
index d1498a66e18..00000000000
--- a/chromium/content/common/gpu/media/exynos_v4l2_video_device.h
+++ /dev/null
@@ -1,58 +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 contains the implementation of ExynosV4L2Device used on
-// Exynos platform.
-
-#ifndef CONTENT_COMMON_GPU_MEDIA_EXYNOS_V4L2_VIDEO_DEVICE_H_
-#define CONTENT_COMMON_GPU_MEDIA_EXYNOS_V4L2_VIDEO_DEVICE_H_
-
-#include "content/common/gpu/media/v4l2_video_device.h"
-
-namespace content {
-
-class ExynosV4L2Device : public V4L2Device {
- public:
- explicit ExynosV4L2Device(Type type);
- virtual ~ExynosV4L2Device();
-
- // V4L2Device implementation.
- virtual int Ioctl(int request, void* arg) override;
- virtual bool Poll(bool poll_device, bool* event_pending) override;
- virtual bool SetDevicePollInterrupt() override;
- virtual bool ClearDevicePollInterrupt() override;
- virtual void* Mmap(void* addr,
- unsigned int len,
- int prot,
- int flags,
- unsigned int offset) override;
- virtual void Munmap(void* addr, unsigned int len) override;
- virtual bool Initialize() override;
- virtual EGLImageKHR CreateEGLImage(EGLDisplay egl_display,
- EGLContext egl_context,
- GLuint texture_id,
- gfx::Size frame_buffer_size,
- unsigned int buffer_index,
- size_t planes_count) override;
- virtual EGLBoolean DestroyEGLImage(EGLDisplay egl_display,
- EGLImageKHR egl_image) override;
- virtual GLenum GetTextureTarget() override;
- virtual uint32 PreferredInputFormat() override;
- virtual uint32 PreferredOutputFormat() override;
-
- private:
- const Type type_;
-
- // The actual device fd.
- int device_fd_;
-
- // eventfd fd to signal device poll thread when its poll() should be
- // interrupted.
- int device_poll_interrupt_fd_;
-
- DISALLOW_COPY_AND_ASSIGN(ExynosV4L2Device);
-};
-} // namespace content
-
-#endif // CONTENT_COMMON_GPU_MEDIA_EXYNOS_V4L2_VIDEO_DEVICE_H_
diff --git a/chromium/content/common/gpu/media/fake_video_decode_accelerator.cc b/chromium/content/common/gpu/media/fake_video_decode_accelerator.cc
new file mode 100644
index 00000000000..eff497f48e7
--- /dev/null
+++ b/chromium/content/common/gpu/media/fake_video_decode_accelerator.cc
@@ -0,0 +1,175 @@
+// Copyright 2014 The Chromium Authors. 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/common/gpu/media/fake_video_decode_accelerator.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/thread_task_runner_handle.h"
+#include "media/base/bitstream_buffer.h"
+#include "media/base/limits.h"
+#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_surface.h"
+#include "ui/gl/gl_surface_egl.h"
+#include "ui/gl/gl_surface_glx.h"
+
+namespace content {
+
+static const uint32 kDefaultTextureTarget = GL_TEXTURE_2D;
+// Must be at least 2 since the rendering helper will switch between textures
+// and if there is only one, it will wait for the next one that will never come.
+// Must also be an even number as otherwise there won't be the same amount of
+// white and black frames.
+static const unsigned int kNumBuffers = media::limits::kMaxVideoFrames +
+ (media::limits::kMaxVideoFrames & 1u);
+
+FakeVideoDecodeAccelerator::FakeVideoDecodeAccelerator(
+ gfx::GLContext* gl,
+ gfx::Size size,
+ const base::Callback<bool(void)>& make_context_current)
+ : child_task_runner_(base::ThreadTaskRunnerHandle::Get()),
+ client_(NULL),
+ make_context_current_(make_context_current),
+ gl_(gl),
+ frame_buffer_size_(size),
+ flushing_(false),
+ weak_this_factory_(this) {
+}
+
+FakeVideoDecodeAccelerator::~FakeVideoDecodeAccelerator() {
+}
+
+bool FakeVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile,
+ Client* client) {
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
+ if (profile == media::VIDEO_CODEC_PROFILE_UNKNOWN) {
+ LOG(ERROR) << "unknown codec profile";
+ return false;
+ }
+ // V4L2VideoDecodeAccelerator waits until first decode call to ask for buffers
+ // This class asks for it on initialization instead.
+ client_ = client;
+ client_->ProvidePictureBuffers(kNumBuffers,
+ frame_buffer_size_,
+ kDefaultTextureTarget);
+ return true;
+}
+
+void FakeVideoDecodeAccelerator::Decode(
+ const media::BitstreamBuffer& bitstream_buffer) {
+ int bitstream_buffer_id = bitstream_buffer.id();
+ queued_bitstream_ids_.push(bitstream_buffer_id);
+ child_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&FakeVideoDecodeAccelerator::DoPictureReady,
+ weak_this_factory_.GetWeakPtr()));
+}
+
+// Similar to UseOutputBitstreamBuffer for the encode accelerator.
+void FakeVideoDecodeAccelerator::AssignPictureBuffers(
+ const std::vector<media::PictureBuffer>& buffers) {
+ DCHECK(buffers.size() == kNumBuffers);
+ DCHECK(!(buffers.size()%2));
+
+ // Save buffers and mark all buffers as ready for use.
+ scoped_ptr<uint8[]> white_data(
+ new uint8[frame_buffer_size_.width() * frame_buffer_size_.height() * 4]);
+ memset(white_data.get(),
+ UINT8_MAX,
+ frame_buffer_size_.width() * frame_buffer_size_.height() * 4);
+ scoped_ptr<uint8[]> black_data(
+ new uint8[frame_buffer_size_.width() * frame_buffer_size_.height() * 4]);
+ memset(black_data.get(),
+ 0,
+ frame_buffer_size_.width() * frame_buffer_size_.height() * 4);
+ if (!make_context_current_.Run()) {
+ LOG(ERROR) << "ReusePictureBuffer(): could not make context current";
+ return;
+ }
+ for (size_t index = 0; index < buffers.size(); ++index) {
+ glBindTexture(GL_TEXTURE_2D, buffers[index].texture_id());
+ // Every other frame white and the rest black.
+ uint8* data = index%2 ? white_data.get():black_data.get();
+ glTexImage2D(GL_TEXTURE_2D,
+ 0,
+ GL_RGBA,
+ frame_buffer_size_.width(),
+ frame_buffer_size_.height(),
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ data);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ free_output_buffers_.push(buffers[index].id());
+ }
+ child_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&FakeVideoDecodeAccelerator::DoPictureReady,
+ weak_this_factory_.GetWeakPtr()));
+}
+
+void FakeVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) {
+ free_output_buffers_.push(picture_buffer_id);
+ child_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&FakeVideoDecodeAccelerator::DoPictureReady,
+ weak_this_factory_.GetWeakPtr()));
+}
+
+void FakeVideoDecodeAccelerator::Flush() {
+ flushing_ = true;
+ child_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&FakeVideoDecodeAccelerator::DoPictureReady,
+ weak_this_factory_.GetWeakPtr()));
+}
+
+void FakeVideoDecodeAccelerator::Reset() {
+ while (!queued_bitstream_ids_.empty()) {
+ client_->NotifyEndOfBitstreamBuffer(queued_bitstream_ids_.front());
+ queued_bitstream_ids_.pop();
+ }
+ client_->NotifyResetDone();
+}
+
+void FakeVideoDecodeAccelerator::Destroy() {
+ while (!queued_bitstream_ids_.empty()) {
+ client_->NotifyEndOfBitstreamBuffer(queued_bitstream_ids_.front());
+ queued_bitstream_ids_.pop();
+ }
+ delete this;
+}
+
+bool FakeVideoDecodeAccelerator::CanDecodeOnIOThread() {
+ return true;
+}
+
+void FakeVideoDecodeAccelerator::DoPictureReady() {
+ if (flushing_ && queued_bitstream_ids_.empty()) {
+ flushing_ = false;
+ client_->NotifyFlushDone();
+ }
+ while (!free_output_buffers_.empty() && !queued_bitstream_ids_.empty()) {
+ int bitstream_id = queued_bitstream_ids_.front();
+ queued_bitstream_ids_.pop();
+ int buffer_id = free_output_buffers_.front();
+ free_output_buffers_.pop();
+
+ const media::Picture picture =
+ media::Picture(buffer_id,
+ bitstream_id,
+ gfx::Rect(frame_buffer_size_),
+ false);
+ client_->PictureReady(picture);
+ // Bitstream no longer needed.
+ client_->NotifyEndOfBitstreamBuffer(bitstream_id);
+ if (flushing_ && queued_bitstream_ids_.empty()) {
+ flushing_ = false;
+ client_->NotifyFlushDone();
+ }
+ }
+}
+
+} // namespace content
diff --git a/chromium/content/common/gpu/media/fake_video_decode_accelerator.h b/chromium/content/common/gpu/media/fake_video_decode_accelerator.h
new file mode 100644
index 00000000000..a669c82387d
--- /dev/null
+++ b/chromium/content/common/gpu/media/fake_video_decode_accelerator.h
@@ -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.
+
+#ifndef CONTENT_COMMON_GPU_MEDIA_FAKE_VIDEO_DECODE_ACCELERATOR_H_
+#define CONTENT_COMMON_GPU_MEDIA_FAKE_VIDEO_DECODE_ACCELERATOR_H_
+
+#include <queue>
+#include <vector>
+
+#include "base/memory/weak_ptr.h"
+#include "content/common/content_export.h"
+#include "media/video/video_decode_accelerator.h"
+#include "ui/gfx/geometry/size_f.h"
+#include "ui/gl/gl_context.h"
+
+namespace content {
+
+class CONTENT_EXPORT FakeVideoDecodeAccelerator
+ : public media::VideoDecodeAccelerator {
+ public:
+ FakeVideoDecodeAccelerator(
+ gfx::GLContext* gl,
+ gfx::Size size,
+ const base::Callback<bool(void)>& make_context_current);
+ ~FakeVideoDecodeAccelerator() override;
+
+ bool Initialize(media::VideoCodecProfile profile,
+ Client* client) override;
+ void Decode(const media::BitstreamBuffer& bitstream_buffer) override;
+ void AssignPictureBuffers(
+ const std::vector<media::PictureBuffer>& buffers) override;
+ void ReusePictureBuffer(int32 picture_buffer_id) override;
+ void Flush() override;
+ void Reset() override;
+ void Destroy() override;
+ bool CanDecodeOnIOThread() override;
+
+ private:
+ void DoPictureReady();
+
+ // The message loop that created the class. Used for all callbacks. This
+ // class expects all calls to this class to be on this message loop (not
+ // checked).
+ const scoped_refptr<base::SingleThreadTaskRunner> child_task_runner_;
+
+ Client* client_;
+
+ // Make our context current before running any GL entry points.
+ base::Callback<bool(void)> make_context_current_;
+ gfx::GLContext* gl_;
+
+ // Output picture size.
+ gfx::Size frame_buffer_size_;
+
+ // Picture buffer ids that are available for putting fake frames in.
+ std::queue<int> free_output_buffers_;
+ // BitstreamBuffer ids for buffers that contain new data to decode.
+ std::queue<int> queued_bitstream_ids_;
+
+ bool flushing_;
+
+ // The WeakPtrFactory for |weak_this_|.
+ base::WeakPtrFactory<FakeVideoDecodeAccelerator> weak_this_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeVideoDecodeAccelerator);
+};
+
+} // namespace content
+
+#endif // CONTENT_COMMON_GPU_MEDIA_FAKE_VIDEO_DECODE_ACCELERATOR_H_
diff --git a/chromium/content/common/gpu/media/generic_v4l2_device.cc b/chromium/content/common/gpu/media/generic_v4l2_device.cc
new file mode 100644
index 00000000000..2dde55d1fcc
--- /dev/null
+++ b/chromium/content/common/gpu/media/generic_v4l2_device.cc
@@ -0,0 +1,299 @@
+// Copyright 2014 The Chromium Authors. 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 <libdrm/drm_fourcc.h>
+#include <linux/videodev2.h>
+#include <poll.h>
+#include <sys/eventfd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+#include "base/files/scoped_file.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/trace_event/trace_event.h"
+#include "content/common/gpu/media/generic_v4l2_device.h"
+#include "ui/gl/egl_util.h"
+#include "ui/gl/gl_bindings.h"
+
+#if defined(USE_LIBV4L2)
+// Auto-generated for dlopen libv4l2 libraries
+#include "content/common/gpu/media/v4l2_stubs.h"
+#include "third_party/v4l-utils/lib/include/libv4l2.h"
+
+using content_common_gpu_media::kModuleV4l2;
+using content_common_gpu_media::InitializeStubs;
+using content_common_gpu_media::StubPathMap;
+
+static const base::FilePath::CharType kV4l2Lib[] =
+ FILE_PATH_LITERAL("/usr/lib/libv4l2.so");
+#endif
+
+namespace content {
+
+namespace {
+const char kDecoderDevice[] = "/dev/video-dec";
+const char kEncoderDevice[] = "/dev/video-enc";
+const char kImageProcessorDevice[] = "/dev/gsc0";
+}
+
+GenericV4L2Device::GenericV4L2Device(Type type)
+ : V4L2Device(type),
+ use_libv4l2_(false) {
+}
+
+GenericV4L2Device::~GenericV4L2Device() {
+#if defined(USE_LIBV4L2)
+ if (use_libv4l2_ && device_fd_.is_valid())
+ v4l2_close(device_fd_.release());
+#endif
+}
+
+int GenericV4L2Device::Ioctl(int request, void* arg) {
+#if defined(USE_LIBV4L2)
+ if (use_libv4l2_)
+ return HANDLE_EINTR(v4l2_ioctl(device_fd_.get(), request, arg));
+#endif
+ return HANDLE_EINTR(ioctl(device_fd_.get(), request, arg));
+}
+
+bool GenericV4L2Device::Poll(bool poll_device, bool* event_pending) {
+ struct pollfd pollfds[2];
+ nfds_t nfds;
+ int pollfd = -1;
+
+ pollfds[0].fd = device_poll_interrupt_fd_.get();
+ pollfds[0].events = POLLIN | POLLERR;
+ nfds = 1;
+
+ if (poll_device) {
+ DVLOG(3) << "Poll(): adding device fd to poll() set";
+ pollfds[nfds].fd = device_fd_.get();
+ pollfds[nfds].events = POLLIN | POLLOUT | POLLERR | POLLPRI;
+ pollfd = nfds;
+ nfds++;
+ }
+
+ if (HANDLE_EINTR(poll(pollfds, nfds, -1)) == -1) {
+ DPLOG(ERROR) << "poll() failed";
+ return false;
+ }
+ *event_pending = (pollfd != -1 && pollfds[pollfd].revents & POLLPRI);
+ return true;
+}
+
+void* GenericV4L2Device::Mmap(void* addr,
+ unsigned int len,
+ int prot,
+ int flags,
+ unsigned int offset) {
+ return mmap(addr, len, prot, flags, device_fd_.get(), offset);
+}
+
+void GenericV4L2Device::Munmap(void* addr, unsigned int len) {
+ munmap(addr, len);
+}
+
+bool GenericV4L2Device::SetDevicePollInterrupt() {
+ DVLOG(3) << "SetDevicePollInterrupt()";
+
+ const uint64 buf = 1;
+ if (HANDLE_EINTR(write(device_poll_interrupt_fd_.get(), &buf, sizeof(buf))) ==
+ -1) {
+ DPLOG(ERROR) << "SetDevicePollInterrupt(): write() failed";
+ return false;
+ }
+ return true;
+}
+
+bool GenericV4L2Device::ClearDevicePollInterrupt() {
+ DVLOG(3) << "ClearDevicePollInterrupt()";
+
+ uint64 buf;
+ if (HANDLE_EINTR(read(device_poll_interrupt_fd_.get(), &buf, sizeof(buf))) ==
+ -1) {
+ if (errno == EAGAIN) {
+ // No interrupt flag set, and we're reading nonblocking. Not an error.
+ return true;
+ } else {
+ DPLOG(ERROR) << "ClearDevicePollInterrupt(): read() failed";
+ return false;
+ }
+ }
+ return true;
+}
+
+bool GenericV4L2Device::Initialize() {
+ const char* device_path = NULL;
+ static bool v4l2_functions_initialized = PostSandboxInitialization();
+ if (!v4l2_functions_initialized) {
+ LOG(ERROR) << "Failed to initialize LIBV4L2 libs";
+ return false;
+ }
+
+ switch (type_) {
+ case kDecoder:
+ device_path = kDecoderDevice;
+ break;
+ case kEncoder:
+ device_path = kEncoderDevice;
+ break;
+ case kImageProcessor:
+ device_path = kImageProcessorDevice;
+ break;
+ }
+
+ DVLOG(2) << "Initialize(): opening device: " << device_path;
+ // Open the video device.
+ device_fd_.reset(
+ HANDLE_EINTR(open(device_path, O_RDWR | O_NONBLOCK | O_CLOEXEC)));
+ if (!device_fd_.is_valid()) {
+ return false;
+ }
+#if defined(USE_LIBV4L2)
+ if (HANDLE_EINTR(v4l2_fd_open(device_fd_.get(), V4L2_DISABLE_CONVERSION)) !=
+ -1) {
+ DVLOG(2) << "Using libv4l2 for " << device_path;
+ use_libv4l2_ = true;
+ }
+#endif
+
+ device_poll_interrupt_fd_.reset(eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC));
+ if (!device_poll_interrupt_fd_.is_valid()) {
+ return false;
+ }
+ return true;
+}
+
+bool GenericV4L2Device::CanCreateEGLImageFrom(uint32_t v4l2_pixfmt) {
+ static uint32_t kEGLImageDrmFmtsSupported[] = {
+ DRM_FORMAT_ARGB8888,
+#if defined(ARCH_CPU_ARMEL)
+ DRM_FORMAT_NV12,
+#endif
+ };
+
+ return std::find(
+ kEGLImageDrmFmtsSupported,
+ kEGLImageDrmFmtsSupported + arraysize(kEGLImageDrmFmtsSupported),
+ V4L2PixFmtToDrmFormat(v4l2_pixfmt)) !=
+ kEGLImageDrmFmtsSupported + arraysize(kEGLImageDrmFmtsSupported);
+}
+
+EGLImageKHR GenericV4L2Device::CreateEGLImage(EGLDisplay egl_display,
+ EGLContext /* egl_context */,
+ GLuint texture_id,
+ gfx::Size frame_buffer_size,
+ unsigned int buffer_index,
+ uint32_t v4l2_pixfmt,
+ size_t num_v4l2_planes) {
+ DVLOG(3) << "CreateEGLImage()";
+ if (!CanCreateEGLImageFrom(v4l2_pixfmt)) {
+ LOG(ERROR) << "Unsupported V4L2 pixel format";
+ return EGL_NO_IMAGE_KHR;
+ }
+
+ media::VideoFrame::Format vf_format =
+ V4L2PixFmtToVideoFrameFormat(v4l2_pixfmt);
+ // Number of components, as opposed to the number of V4L2 planes, which is
+ // just a buffer count.
+ size_t num_planes = media::VideoFrame::NumPlanes(vf_format);
+ DCHECK_LE(num_planes, 3u);
+ if (num_planes < num_v4l2_planes) {
+ // It's possible for more than one DRM plane to reside in one V4L2 plane,
+ // but not the other way around. We must use all V4L2 planes.
+ LOG(ERROR) << "Invalid plane count";
+ return EGL_NO_IMAGE_KHR;
+ }
+
+ scoped_ptr<base::ScopedFD[]> dmabuf_fds(new base::ScopedFD[num_v4l2_planes]);
+ // Export dmabuf fds so we can create an EGLImage from them.
+ for (size_t i = 0; i < num_v4l2_planes; ++i) {
+ struct v4l2_exportbuffer expbuf;
+ memset(&expbuf, 0, sizeof(expbuf));
+ expbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ expbuf.index = buffer_index;
+ expbuf.plane = i;
+ expbuf.flags = O_CLOEXEC;
+ if (Ioctl(VIDIOC_EXPBUF, &expbuf) != 0) {
+ return EGL_NO_IMAGE_KHR;
+ }
+ dmabuf_fds[i].reset(expbuf.fd);
+ }
+
+ std::vector<EGLint> attrs;
+ attrs.push_back(EGL_WIDTH);
+ attrs.push_back(frame_buffer_size.width());
+ attrs.push_back(EGL_HEIGHT);
+ attrs.push_back(frame_buffer_size.height());
+ attrs.push_back(EGL_LINUX_DRM_FOURCC_EXT);
+ attrs.push_back(V4L2PixFmtToDrmFormat(v4l2_pixfmt));
+
+ // For existing formats, if we have less buffers (V4L2 planes) than
+ // components (planes), the remaining planes are stored in the last
+ // V4L2 plane. Use one V4L2 plane per each component until we run out of V4L2
+ // planes, and use the last V4L2 plane for all remaining components, each
+ // with an offset equal to the size of the preceding planes in the same
+ // V4L2 plane.
+ size_t v4l2_plane = 0;
+ size_t plane_offset = 0;
+ for (size_t plane = 0; plane < num_planes; ++plane) {
+ attrs.push_back(EGL_DMA_BUF_PLANE0_FD_EXT + plane * 3);
+ attrs.push_back(dmabuf_fds[v4l2_plane].get());
+ attrs.push_back(EGL_DMA_BUF_PLANE0_OFFSET_EXT + plane * 3);
+ attrs.push_back(plane_offset);
+ attrs.push_back(EGL_DMA_BUF_PLANE0_PITCH_EXT + plane * 3);
+ attrs.push_back(media::VideoFrame::RowBytes(plane, vf_format,
+ frame_buffer_size.width()));
+
+ if (v4l2_plane + 1 < num_v4l2_planes) {
+ ++v4l2_plane;
+ } else {
+ plane_offset += media::VideoFrame::PlaneAllocationSize(
+ vf_format, plane, frame_buffer_size);
+ }
+ }
+
+ attrs.push_back(EGL_NONE);
+
+ EGLImageKHR egl_image = eglCreateImageKHR(
+ egl_display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, &attrs[0]);
+ if (egl_image == EGL_NO_IMAGE_KHR) {
+ LOG(ERROR) << "Failed creating EGL image: " << ui::GetLastEGLErrorString();
+ return egl_image;
+ }
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_id);
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, egl_image);
+
+ return egl_image;
+}
+
+EGLBoolean GenericV4L2Device::DestroyEGLImage(EGLDisplay egl_display,
+ EGLImageKHR egl_image) {
+ return eglDestroyImageKHR(egl_display, egl_image);
+}
+
+GLenum GenericV4L2Device::GetTextureTarget() { return GL_TEXTURE_EXTERNAL_OES; }
+
+uint32 GenericV4L2Device::PreferredInputFormat() {
+ // TODO(posciak): We should support "dontcare" returns here once we
+ // implement proper handling (fallback, negotiation) for this in users.
+ CHECK_EQ(type_, kEncoder);
+ return V4L2_PIX_FMT_NV12M;
+}
+
+// static
+bool GenericV4L2Device::PostSandboxInitialization() {
+#if defined(USE_LIBV4L2)
+ StubPathMap paths;
+ paths[kModuleV4l2].push_back(kV4l2Lib);
+
+ return InitializeStubs(paths);
+#else
+ return true;
+#endif
+}
+
+} // namespace content
diff --git a/chromium/content/common/gpu/media/generic_v4l2_device.h b/chromium/content/common/gpu/media/generic_v4l2_device.h
new file mode 100644
index 00000000000..df5381f604e
--- /dev/null
+++ b/chromium/content/common/gpu/media/generic_v4l2_device.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.
+//
+// This file contains the implementation of GenericV4L2Device used on
+// platforms, which provide generic V4L2 video codec devices.
+
+#ifndef CONTENT_COMMON_GPU_MEDIA_GENERIC_V4L2_DEVICE_H_
+#define CONTENT_COMMON_GPU_MEDIA_GENERIC_V4L2_DEVICE_H_
+
+#include "base/files/scoped_file.h"
+#include "content/common/gpu/media/v4l2_device.h"
+
+namespace content {
+
+class GenericV4L2Device : public V4L2Device {
+ public:
+ explicit GenericV4L2Device(Type type);
+
+ // V4L2Device implementation.
+ int Ioctl(int request, void* arg) override;
+ bool Poll(bool poll_device, bool* event_pending) override;
+ bool SetDevicePollInterrupt() override;
+ bool ClearDevicePollInterrupt() override;
+ void* Mmap(void* addr,
+ unsigned int len,
+ int prot,
+ int flags,
+ unsigned int offset) override;
+ void Munmap(void* addr, unsigned int len) override;
+ bool Initialize() override;
+ bool CanCreateEGLImageFrom(uint32_t v4l2_pixfmt) override;
+ EGLImageKHR CreateEGLImage(EGLDisplay egl_display,
+ EGLContext egl_context,
+ GLuint texture_id,
+ gfx::Size frame_buffer_size,
+ unsigned int buffer_index,
+ uint32_t v4l2_pixfmt,
+ size_t num_v4l2_planes) override;
+ EGLBoolean DestroyEGLImage(EGLDisplay egl_display,
+ EGLImageKHR egl_image) override;
+ GLenum GetTextureTarget() override;
+ uint32 PreferredInputFormat() override;
+
+ private:
+ ~GenericV4L2Device() override;
+
+ // The actual device fd.
+ base::ScopedFD device_fd_;
+
+ // eventfd fd to signal device poll thread when its poll() should be
+ // interrupted.
+ base::ScopedFD device_poll_interrupt_fd_;
+
+ // Use libv4l2 when operating |device_fd_|.
+ bool use_libv4l2_;
+
+ DISALLOW_COPY_AND_ASSIGN(GenericV4L2Device);
+
+ // Lazily initialize static data after sandbox is enabled. Return false on
+ // init failure.
+ static bool PostSandboxInitialization();
+};
+} // namespace content
+
+#endif // CONTENT_COMMON_GPU_MEDIA_GENERIC_V4L2_DEVICE_H_
diff --git a/chromium/content/common/gpu/media/gpu_video_accelerator_util.cc b/chromium/content/common/gpu/media/gpu_video_accelerator_util.cc
new file mode 100644
index 00000000000..d23c1920698
--- /dev/null
+++ b/chromium/content/common/gpu/media/gpu_video_accelerator_util.cc
@@ -0,0 +1,133 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/common/gpu/media/gpu_video_accelerator_util.h"
+
+namespace content {
+
+// Make sure the enum values of media::VideoCodecProfile and
+// gpu::VideoCodecProfile match.
+#define STATIC_ASSERT_ENUM_MATCH(name) \
+ static_assert( \
+ media::name == static_cast<media::VideoCodecProfile>(gpu::name), \
+ #name " value must match in media and gpu.")
+
+STATIC_ASSERT_ENUM_MATCH(VIDEO_CODEC_PROFILE_UNKNOWN);
+STATIC_ASSERT_ENUM_MATCH(VIDEO_CODEC_PROFILE_MIN);
+STATIC_ASSERT_ENUM_MATCH(H264PROFILE_BASELINE);
+STATIC_ASSERT_ENUM_MATCH(H264PROFILE_MAIN);
+STATIC_ASSERT_ENUM_MATCH(H264PROFILE_EXTENDED);
+STATIC_ASSERT_ENUM_MATCH(H264PROFILE_HIGH);
+STATIC_ASSERT_ENUM_MATCH(H264PROFILE_HIGH10PROFILE);
+STATIC_ASSERT_ENUM_MATCH(H264PROFILE_HIGH422PROFILE);
+STATIC_ASSERT_ENUM_MATCH(H264PROFILE_HIGH444PREDICTIVEPROFILE);
+STATIC_ASSERT_ENUM_MATCH(H264PROFILE_SCALABLEBASELINE);
+STATIC_ASSERT_ENUM_MATCH(H264PROFILE_SCALABLEHIGH);
+STATIC_ASSERT_ENUM_MATCH(H264PROFILE_STEREOHIGH);
+STATIC_ASSERT_ENUM_MATCH(H264PROFILE_MULTIVIEWHIGH);
+STATIC_ASSERT_ENUM_MATCH(VP8PROFILE_ANY);
+STATIC_ASSERT_ENUM_MATCH(VP9PROFILE_ANY);
+STATIC_ASSERT_ENUM_MATCH(VIDEO_CODEC_PROFILE_MAX);
+
+// static
+media::VideoDecodeAccelerator::SupportedProfiles
+GpuVideoAcceleratorUtil::ConvertGpuToMediaDecodeProfiles(const
+ gpu::VideoDecodeAcceleratorSupportedProfiles& gpu_profiles) {
+ media::VideoDecodeAccelerator::SupportedProfiles profiles;
+ for (const auto& gpu_profile : gpu_profiles) {
+ media::VideoDecodeAccelerator::SupportedProfile profile;
+ profile.profile =
+ static_cast<media::VideoCodecProfile>(gpu_profile.profile);
+ profile.max_resolution = gpu_profile.max_resolution;
+ profile.min_resolution = gpu_profile.min_resolution;
+ profiles.push_back(profile);
+ }
+ return profiles;
+}
+
+// static
+gpu::VideoDecodeAcceleratorSupportedProfiles
+GpuVideoAcceleratorUtil::ConvertMediaToGpuDecodeProfiles(const
+ media::VideoDecodeAccelerator::SupportedProfiles& media_profiles) {
+ gpu::VideoDecodeAcceleratorSupportedProfiles profiles;
+ for (const auto& media_profile : media_profiles) {
+ gpu::VideoDecodeAcceleratorSupportedProfile profile;
+ profile.profile =
+ static_cast<gpu::VideoCodecProfile>(media_profile.profile);
+ profile.max_resolution = media_profile.max_resolution;
+ profile.min_resolution = media_profile.min_resolution;
+ profiles.push_back(profile);
+ }
+ return profiles;
+}
+
+// static
+media::VideoEncodeAccelerator::SupportedProfiles
+GpuVideoAcceleratorUtil::ConvertGpuToMediaEncodeProfiles(const
+ gpu::VideoEncodeAcceleratorSupportedProfiles& gpu_profiles) {
+ media::VideoEncodeAccelerator::SupportedProfiles profiles;
+ for (const auto& gpu_profile : gpu_profiles) {
+ media::VideoEncodeAccelerator::SupportedProfile profile;
+ profile.profile =
+ static_cast<media::VideoCodecProfile>(gpu_profile.profile);
+ profile.max_resolution = gpu_profile.max_resolution;
+ profile.max_framerate_numerator = gpu_profile.max_framerate_numerator;
+ profile.max_framerate_denominator = gpu_profile.max_framerate_denominator;
+ profiles.push_back(profile);
+ }
+ return profiles;
+}
+
+// static
+gpu::VideoEncodeAcceleratorSupportedProfiles
+GpuVideoAcceleratorUtil::ConvertMediaToGpuEncodeProfiles(const
+ media::VideoEncodeAccelerator::SupportedProfiles& media_profiles) {
+ gpu::VideoEncodeAcceleratorSupportedProfiles profiles;
+ for (const auto& media_profile : media_profiles) {
+ gpu::VideoEncodeAcceleratorSupportedProfile profile;
+ profile.profile =
+ static_cast<gpu::VideoCodecProfile>(media_profile.profile);
+ profile.max_resolution = media_profile.max_resolution;
+ profile.max_framerate_numerator = media_profile.max_framerate_numerator;
+ profile.max_framerate_denominator = media_profile.max_framerate_denominator;
+ profiles.push_back(profile);
+ }
+ return profiles;
+}
+
+// static
+void GpuVideoAcceleratorUtil::InsertUniqueDecodeProfiles(
+ const media::VideoDecodeAccelerator::SupportedProfiles& new_profiles,
+ media::VideoDecodeAccelerator::SupportedProfiles* media_profiles) {
+ for (const auto& profile : new_profiles) {
+ bool duplicate = false;
+ for (const auto& media_profile : *media_profiles) {
+ if (media_profile.profile == profile.profile) {
+ duplicate = true;
+ break;
+ }
+ }
+ if (!duplicate)
+ media_profiles->push_back(profile);
+ }
+}
+
+// static
+void GpuVideoAcceleratorUtil::InsertUniqueEncodeProfiles(
+ const media::VideoEncodeAccelerator::SupportedProfiles& new_profiles,
+ media::VideoEncodeAccelerator::SupportedProfiles* media_profiles) {
+ for (const auto& profile : new_profiles) {
+ bool duplicate = false;
+ for (const auto& media_profile : *media_profiles) {
+ if (media_profile.profile == profile.profile) {
+ duplicate = true;
+ break;
+ }
+ }
+ if (!duplicate)
+ media_profiles->push_back(profile);
+ }
+}
+
+} // namespace content
diff --git a/chromium/content/common/gpu/media/gpu_video_accelerator_util.h b/chromium/content/common/gpu/media/gpu_video_accelerator_util.h
new file mode 100644
index 00000000000..28b11d13e6b
--- /dev/null
+++ b/chromium/content/common/gpu/media/gpu_video_accelerator_util.h
@@ -0,0 +1,53 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_COMMON_GPU_MEDIA_GPU_VIDEO_ACCELERATOR_UTIL_H_
+#define CONTENT_COMMON_GPU_MEDIA_GPU_VIDEO_ACCELERATOR_UTIL_H_
+
+#include <vector>
+
+#include "gpu/config/gpu_info.h"
+#include "media/video/video_decode_accelerator.h"
+#include "media/video/video_encode_accelerator.h"
+
+namespace content {
+
+class GpuVideoAcceleratorUtil {
+ public:
+ // Convert decoder gpu profiles to media profiles.
+ static media::VideoDecodeAccelerator::SupportedProfiles
+ ConvertGpuToMediaDecodeProfiles(const
+ gpu::VideoDecodeAcceleratorSupportedProfiles& gpu_profiles);
+
+ // Convert decoder media profiles to gpu profiles.
+ static gpu::VideoDecodeAcceleratorSupportedProfiles
+ ConvertMediaToGpuDecodeProfiles(const
+ media::VideoDecodeAccelerator::SupportedProfiles& media_profiles);
+
+ // Convert encoder gpu profiles to media profiles.
+ static media::VideoEncodeAccelerator::SupportedProfiles
+ ConvertGpuToMediaEncodeProfiles(const
+ gpu::VideoEncodeAcceleratorSupportedProfiles& gpu_profiles);
+
+ // Convert encoder media profiles to gpu profiles.
+ static gpu::VideoEncodeAcceleratorSupportedProfiles
+ ConvertMediaToGpuEncodeProfiles(const
+ media::VideoEncodeAccelerator::SupportedProfiles& media_profiles);
+
+ // Insert |new_profiles| into |media_profiles|, ensuring no duplicates are
+ // inserted.
+ static void InsertUniqueDecodeProfiles(
+ const media::VideoDecodeAccelerator::SupportedProfiles& new_profiles,
+ media::VideoDecodeAccelerator::SupportedProfiles* media_profiles);
+
+ // Insert |new_profiles| into |media_profiles|, ensuring no duplicates are
+ // inserted.
+ static void InsertUniqueEncodeProfiles(
+ const media::VideoEncodeAccelerator::SupportedProfiles& new_profiles,
+ media::VideoEncodeAccelerator::SupportedProfiles* media_profiles);
+};
+
+} // namespace content
+
+#endif // CONTENT_COMMON_GPU_MEDIA_GPU_VIDEO_ACCELERATOR_UTIL_H_
diff --git a/chromium/content/common/gpu/media/gpu_video_decode_accelerator.cc b/chromium/content/common/gpu/media/gpu_video_decode_accelerator.cc
index 2f71b827f66..c4d7eb9f886 100644
--- a/chromium/content/common/gpu/media/gpu_video_decode_accelerator.cc
+++ b/chromium/content/common/gpu/media/gpu_video_decode_accelerator.cc
@@ -8,12 +8,16 @@
#include "base/bind.h"
#include "base/command_line.h"
+#include "base/location.h"
#include "base/logging.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
+#include "base/thread_task_runner_handle.h"
#include "content/common/gpu/gpu_channel.h"
#include "content/common/gpu/gpu_messages.h"
+#include "content/common/gpu/media/gpu_video_accelerator_util.h"
#include "content/public/common/content_switches.h"
#include "gpu/command_buffer/common/command_buffer.h"
#include "ipc/ipc_message_macros.h"
@@ -21,6 +25,7 @@
#include "ipc/message_filter.h"
#include "media/base/limits.h"
#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_image.h"
#include "ui/gl/gl_surface_egl.h"
#if defined(OS_WIN)
@@ -28,20 +33,23 @@
#include "content/common/gpu/media/dxva_video_decode_accelerator.h"
#elif defined(OS_MACOSX)
#include "content/common/gpu/media/vt_video_decode_accelerator.h"
-#elif defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) && defined(USE_X11)
+#elif defined(OS_CHROMEOS)
+#if defined(USE_V4L2_CODEC)
+#include "content/common/gpu/media/v4l2_device.h"
+#include "content/common/gpu/media/v4l2_slice_video_decode_accelerator.h"
#include "content/common/gpu/media/v4l2_video_decode_accelerator.h"
-#include "content/common/gpu/media/v4l2_video_device.h"
-#elif defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) && defined(USE_X11)
+#endif
+#if defined(ARCH_CPU_X86_FAMILY)
#include "content/common/gpu/media/vaapi_video_decode_accelerator.h"
-#include "ui/gl/gl_context_glx.h"
#include "ui/gl/gl_implementation.h"
+#endif
#elif defined(USE_OZONE)
#include "media/ozone/media_ozone_platform.h"
#elif defined(OS_ANDROID)
#include "content/common/gpu/media/android_video_decode_accelerator.h"
#endif
-#include "ui/gfx/size.h"
+#include "ui/gfx/geometry/size.h"
namespace content {
@@ -62,7 +70,7 @@ static bool MakeDecoderContextCurrent(
// DebugAutoLock works like AutoLock but only acquires the lock when
// DCHECK is on.
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
typedef base::AutoLock DebugAutoLock;
#else
class DebugAutoLock {
@@ -112,8 +120,8 @@ class GpuVideoDecodeAccelerator::MessageFilter : public IPC::MessageFilter {
~MessageFilter() override {}
private:
- GpuVideoDecodeAccelerator* owner_;
- int32 host_route_id_;
+ GpuVideoDecodeAccelerator* const owner_;
+ const int32 host_route_id_;
// The sender to which this filter was added.
IPC::Sender* sender_;
};
@@ -121,16 +129,16 @@ class GpuVideoDecodeAccelerator::MessageFilter : public IPC::MessageFilter {
GpuVideoDecodeAccelerator::GpuVideoDecodeAccelerator(
int32 host_route_id,
GpuCommandBufferStub* stub,
- const scoped_refptr<base::MessageLoopProxy>& io_message_loop)
+ const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
: host_route_id_(host_route_id),
stub_(stub),
texture_target_(0),
filter_removed_(true, false),
- io_message_loop_(io_message_loop),
+ child_task_runner_(base::ThreadTaskRunnerHandle::Get()),
+ io_task_runner_(io_task_runner),
weak_factory_for_io_(this) {
DCHECK(stub_);
stub_->AddDestructionObserver(this);
- child_message_loop_ = base::MessageLoopProxy::current();
make_context_current_ =
base::Bind(&MakeDecoderContextCurrent, stub_->AsWeakPtr());
}
@@ -199,19 +207,18 @@ void GpuVideoDecodeAccelerator::PictureReady(
// VDA may call PictureReady on IO thread. SetTextureCleared should run on
// the child thread. VDA is responsible to call PictureReady on the child
// thread when a picture buffer is delivered the first time.
- if (child_message_loop_->BelongsToCurrentThread()) {
+ if (child_task_runner_->BelongsToCurrentThread()) {
SetTextureCleared(picture);
} else {
- DCHECK(io_message_loop_->BelongsToCurrentThread());
+ DCHECK(io_task_runner_->BelongsToCurrentThread());
DebugAutoLock auto_lock(debug_uncleared_textures_lock_);
DCHECK_EQ(0u, uncleared_textures_.count(picture.picture_buffer_id()));
}
if (!Send(new AcceleratedVideoDecoderHostMsg_PictureReady(
- host_route_id_,
- picture.picture_buffer_id(),
- picture.bitstream_buffer_id(),
- picture.visible_rect()))) {
+ host_route_id_, picture.picture_buffer_id(),
+ picture.bitstream_buffer_id(), picture.visible_rect(),
+ picture.allow_overlay()))) {
DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_PictureReady) failed";
}
}
@@ -231,8 +238,7 @@ void GpuVideoDecodeAccelerator::Initialize(
DCHECK(!video_decode_accelerator_.get());
if (!stub_->channel()->AddRoute(host_route_id_, this)) {
- DLOG(ERROR) << "GpuVideoDecodeAccelerator::Initialize(): "
- "failed to add route";
+ DLOG(ERROR) << "Initialize(): failed to add route";
SendCreateDecoderReply(init_done_msg, false);
}
@@ -245,74 +251,173 @@ void GpuVideoDecodeAccelerator::Initialize(
}
#endif
+ // Array of Create..VDA() function pointers, maybe applicable to the current
+ // platform. This list is ordered by priority of use and it should be the
+ // same as the order of querying supported profiles of VDAs.
+ const GpuVideoDecodeAccelerator::CreateVDAFp create_vda_fps[] = {
+ &GpuVideoDecodeAccelerator::CreateDXVAVDA,
+ &GpuVideoDecodeAccelerator::CreateV4L2VDA,
+ &GpuVideoDecodeAccelerator::CreateV4L2SliceVDA,
+ &GpuVideoDecodeAccelerator::CreateVaapiVDA,
+ &GpuVideoDecodeAccelerator::CreateVTVDA,
+ &GpuVideoDecodeAccelerator::CreateOzoneVDA,
+ &GpuVideoDecodeAccelerator::CreateAndroidVDA};
+
+ for (const auto& create_vda_function : create_vda_fps) {
+ video_decode_accelerator_ = (this->*create_vda_function)();
+ if (!video_decode_accelerator_ ||
+ !video_decode_accelerator_->Initialize(profile, this))
+ continue;
+
+ if (video_decode_accelerator_->CanDecodeOnIOThread()) {
+ filter_ = new MessageFilter(this, host_route_id_);
+ stub_->channel()->AddFilter(filter_.get());
+ }
+ SendCreateDecoderReply(init_done_msg, true);
+ return;
+ }
+ video_decode_accelerator_.reset();
+ LOG(ERROR) << "HW video decode not available for profile " << profile;
+ SendCreateDecoderReply(init_done_msg, false);
+}
+
+scoped_ptr<media::VideoDecodeAccelerator>
+GpuVideoDecodeAccelerator::CreateDXVAVDA() {
+ scoped_ptr<media::VideoDecodeAccelerator> decoder;
#if defined(OS_WIN)
- if (base::win::GetVersion() < base::win::VERSION_WIN7) {
+ if (base::win::GetVersion() >= base::win::VERSION_WIN7) {
+ DVLOG(0) << "Initializing DXVA HW decoder for windows.";
+ decoder.reset(new DXVAVideoDecodeAccelerator(make_context_current_,
+ stub_->decoder()->GetGLContext()));
+ } else {
NOTIMPLEMENTED() << "HW video decode acceleration not available.";
- SendCreateDecoderReply(init_done_msg, false);
- return;
}
- DVLOG(0) << "Initializing DXVA HW decoder for windows.";
- video_decode_accelerator_.reset(
- new DXVAVideoDecodeAccelerator(make_context_current_));
-#elif defined(OS_MACOSX)
- video_decode_accelerator_.reset(new VTVideoDecodeAccelerator(
- static_cast<CGLContextObj>(
- stub_->decoder()->GetGLContext()->GetHandle()),
- make_context_current_));
-#elif defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) && defined(USE_X11)
- scoped_ptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder);
- if (!device.get()) {
- SendCreateDecoderReply(init_done_msg, false);
- return;
+#endif
+ return decoder.Pass();
+}
+
+scoped_ptr<media::VideoDecodeAccelerator>
+GpuVideoDecodeAccelerator::CreateV4L2VDA() {
+ scoped_ptr<media::VideoDecodeAccelerator> decoder;
+#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC)
+ scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder);
+ if (device.get()) {
+ decoder.reset(new V4L2VideoDecodeAccelerator(
+ gfx::GLSurfaceEGL::GetHardwareDisplay(),
+ stub_->decoder()->GetGLContext()->GetHandle(),
+ weak_factory_for_io_.GetWeakPtr(),
+ make_context_current_,
+ device,
+ io_task_runner_));
}
- video_decode_accelerator_.reset(new V4L2VideoDecodeAccelerator(
- gfx::GLSurfaceEGL::GetHardwareDisplay(),
- stub_->decoder()->GetGLContext()->GetHandle(),
- weak_factory_for_io_.GetWeakPtr(),
- make_context_current_,
- device.Pass(),
- io_message_loop_));
-#elif defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) && defined(USE_X11)
- if (gfx::GetGLImplementation() != gfx::kGLImplementationDesktopGL) {
- VLOG(1) << "HW video decode acceleration not available without "
- "DesktopGL (GLX).";
- SendCreateDecoderReply(init_done_msg, false);
- return;
+#endif
+ return decoder.Pass();
+}
+
+scoped_ptr<media::VideoDecodeAccelerator>
+GpuVideoDecodeAccelerator::CreateV4L2SliceVDA() {
+ scoped_ptr<media::VideoDecodeAccelerator> decoder;
+#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC)
+ scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder);
+ if (device.get()) {
+ decoder.reset(new V4L2SliceVideoDecodeAccelerator(
+ device,
+ gfx::GLSurfaceEGL::GetHardwareDisplay(),
+ stub_->decoder()->GetGLContext()->GetHandle(),
+ weak_factory_for_io_.GetWeakPtr(),
+ make_context_current_,
+ io_task_runner_));
}
- gfx::GLContextGLX* glx_context =
- static_cast<gfx::GLContextGLX*>(stub_->decoder()->GetGLContext());
- video_decode_accelerator_.reset(new VaapiVideoDecodeAccelerator(
- glx_context->display(), make_context_current_));
-#elif defined(USE_OZONE)
+#endif
+ return decoder.Pass();
+}
+
+void GpuVideoDecodeAccelerator::BindImage(uint32 client_texture_id,
+ uint32 texture_target,
+ scoped_refptr<gfx::GLImage> image) {
+ gpu::gles2::GLES2Decoder* command_decoder = stub_->decoder();
+ gpu::gles2::TextureManager* texture_manager =
+ command_decoder->GetContextGroup()->texture_manager();
+ gpu::gles2::TextureRef* ref = texture_manager->GetTexture(client_texture_id);
+ if (ref)
+ texture_manager->SetLevelImage(ref, texture_target, 0, image.get());
+}
+
+scoped_ptr<media::VideoDecodeAccelerator>
+GpuVideoDecodeAccelerator::CreateVaapiVDA() {
+ scoped_ptr<media::VideoDecodeAccelerator> decoder;
+#if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)
+ decoder.reset(new VaapiVideoDecodeAccelerator(
+ make_context_current_, base::Bind(&GpuVideoDecodeAccelerator::BindImage,
+ base::Unretained(this))));
+#endif
+ return decoder.Pass();
+}
+
+scoped_ptr<media::VideoDecodeAccelerator>
+GpuVideoDecodeAccelerator::CreateVTVDA() {
+ scoped_ptr<media::VideoDecodeAccelerator> decoder;
+#if defined(OS_MACOSX)
+ decoder.reset(new VTVideoDecodeAccelerator(
+ static_cast<CGLContextObj>(stub_->decoder()->GetGLContext()->GetHandle()),
+ make_context_current_));
+#endif
+ return decoder.Pass();
+}
+
+scoped_ptr<media::VideoDecodeAccelerator>
+GpuVideoDecodeAccelerator::CreateOzoneVDA() {
+ scoped_ptr<media::VideoDecodeAccelerator> decoder;
+#if !defined(OS_CHROMEOS) && defined(USE_OZONE)
media::MediaOzonePlatform* platform =
media::MediaOzonePlatform::GetInstance();
- video_decode_accelerator_.reset(platform->CreateVideoDecodeAccelerator(
- make_context_current_));
- if (!video_decode_accelerator_) {
- SendCreateDecoderReply(init_done_msg, false);
- return;
- }
-#elif defined(OS_ANDROID)
- video_decode_accelerator_.reset(new AndroidVideoDecodeAccelerator(
+ decoder.reset(platform->CreateVideoDecodeAccelerator(make_context_current_));
+#endif
+ return decoder.Pass();
+}
+
+scoped_ptr<media::VideoDecodeAccelerator>
+GpuVideoDecodeAccelerator::CreateAndroidVDA() {
+ scoped_ptr<media::VideoDecodeAccelerator> decoder;
+#if defined(OS_ANDROID)
+ decoder.reset(new AndroidVideoDecodeAccelerator(
stub_->decoder()->AsWeakPtr(),
make_context_current_));
-#else
- NOTIMPLEMENTED() << "HW video decode acceleration not available.";
- SendCreateDecoderReply(init_done_msg, false);
- return;
#endif
+ return decoder.Pass();
+}
- if (video_decode_accelerator_->CanDecodeOnIOThread()) {
- filter_ = new MessageFilter(this, host_route_id_);
- stub_->channel()->AddFilter(filter_.get());
- }
-
- if (!video_decode_accelerator_->Initialize(profile, this)) {
- SendCreateDecoderReply(init_done_msg, false);
- return;
- }
-
- SendCreateDecoderReply(init_done_msg, true);
+// static
+gpu::VideoDecodeAcceleratorSupportedProfiles
+GpuVideoDecodeAccelerator::GetSupportedProfiles() {
+ media::VideoDecodeAccelerator::SupportedProfiles profiles;
+ const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
+ if (cmd_line->HasSwitch(switches::kDisableAcceleratedVideoDecode))
+ return gpu::VideoDecodeAcceleratorSupportedProfiles();
+
+ // Query supported profiles for each VDA. The order of querying VDAs should
+ // be the same as the order of initializing VDAs. Then the returned profile
+ // can be initialized by corresponding VDA successfully.
+#if defined(OS_WIN)
+ profiles = DXVAVideoDecodeAccelerator::GetSupportedProfiles();
+#elif defined(OS_CHROMEOS)
+ media::VideoDecodeAccelerator::SupportedProfiles vda_profiles;
+#if defined(USE_V4L2_CODEC)
+ vda_profiles = V4L2VideoDecodeAccelerator::GetSupportedProfiles();
+ GpuVideoAcceleratorUtil::InsertUniqueDecodeProfiles(vda_profiles, &profiles);
+ vda_profiles = V4L2SliceVideoDecodeAccelerator::GetSupportedProfiles();
+ GpuVideoAcceleratorUtil::InsertUniqueDecodeProfiles(vda_profiles, &profiles);
+#endif
+#if defined(ARCH_CPU_X86_FAMILY)
+ vda_profiles = VaapiVideoDecodeAccelerator::GetSupportedProfiles();
+ GpuVideoAcceleratorUtil::InsertUniqueDecodeProfiles(vda_profiles, &profiles);
+#endif
+#elif defined(OS_MACOSX)
+ profiles = VTVideoDecodeAccelerator::GetSupportedProfiles();
+#elif defined(OS_ANDROID)
+ profiles = AndroidVideoDecodeAccelerator::GetSupportedProfiles();
+#endif
+ return GpuVideoAcceleratorUtil::ConvertMediaToGpuDecodeProfiles(profiles);
}
// Runs on IO thread if video_decode_accelerator_->CanDecodeOnIOThread() is
@@ -322,10 +427,10 @@ void GpuVideoDecodeAccelerator::OnDecode(
DCHECK(video_decode_accelerator_.get());
if (id < 0) {
DLOG(ERROR) << "BitstreamBuffer id " << id << " out of range";
- if (child_message_loop_->BelongsToCurrentThread()) {
+ if (child_task_runner_->BelongsToCurrentThread()) {
NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT);
} else {
- child_message_loop_->PostTask(
+ child_task_runner_->PostTask(
FROM_HERE,
base::Bind(&GpuVideoDecodeAccelerator::NotifyError,
base::Unretained(this),
@@ -371,40 +476,42 @@ void GpuVideoDecodeAccelerator::OnAssignPictureBuffers(
return;
}
if (texture_target_ == GL_TEXTURE_EXTERNAL_OES ||
- texture_target_ == GL_TEXTURE_RECTANGLE) {
+ texture_target_ == GL_TEXTURE_RECTANGLE_ARB) {
// These textures have their dimensions defined by the underlying storage.
// Use |texture_dimensions_| for this size.
texture_manager->SetLevelInfo(texture_ref,
texture_target_,
0,
- 0,
+ GL_RGBA,
texture_dimensions_.width(),
texture_dimensions_.height(),
1,
0,
- 0,
+ GL_RGBA,
0,
false);
} else {
// For other targets, texture dimensions should already be defined.
GLsizei width = 0, height = 0;
- info->GetLevelSize(texture_target_, 0, &width, &height);
+ info->GetLevelSize(texture_target_, 0, &width, &height, nullptr);
if (width != texture_dimensions_.width() ||
height != texture_dimensions_.height()) {
DLOG(ERROR) << "Size mismatch for texture id " << texture_ids[i];
NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT);
return;
}
+
+ // TODO(dshwang): after moving to D3D11, remove this. crbug.com/438691
+ GLenum format =
+ video_decode_accelerator_.get()->GetSurfaceInternalFormat();
+ if (format != GL_RGBA) {
+ texture_manager->SetLevelInfo(texture_ref, texture_target_, 0, format,
+ width, height, 1, 0, format, 0, false);
+ }
}
- uint32 service_texture_id;
- if (!command_decoder->GetServiceTextureId(
- texture_ids[i], &service_texture_id)) {
- DLOG(ERROR) << "Failed to translate texture!";
- NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE);
- return;
- }
- buffers.push_back(media::PictureBuffer(
- buffer_ids[i], texture_dimensions_, service_texture_id));
+ buffers.push_back(media::PictureBuffer(buffer_ids[i], texture_dimensions_,
+ texture_ref->service_id(),
+ texture_ids[i]));
textures.push_back(texture_ref);
}
video_decode_accelerator_->AssignPictureBuffers(buffers);
@@ -483,7 +590,7 @@ void GpuVideoDecodeAccelerator::OnWillDestroyStub() {
void GpuVideoDecodeAccelerator::SetTextureCleared(
const media::Picture& picture) {
- DCHECK(child_message_loop_->BelongsToCurrentThread());
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
DebugAutoLock auto_lock(debug_uncleared_textures_lock_);
std::map<int32, scoped_refptr<gpu::gles2::TextureRef> >::iterator it;
it = uncleared_textures_.find(picture.picture_buffer_id());
@@ -500,9 +607,9 @@ void GpuVideoDecodeAccelerator::SetTextureCleared(
}
bool GpuVideoDecodeAccelerator::Send(IPC::Message* message) {
- if (filter_.get() && io_message_loop_->BelongsToCurrentThread())
+ if (filter_.get() && io_task_runner_->BelongsToCurrentThread())
return filter_->SendOnIOThread(message);
- DCHECK(child_message_loop_->BelongsToCurrentThread());
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
return stub_->channel()->Send(message);
}
diff --git a/chromium/content/common/gpu/media/gpu_video_decode_accelerator.h b/chromium/content/common/gpu/media/gpu_video_decode_accelerator.h
index e59a76fb5c3..cab2a2285cd 100644
--- a/chromium/content/common/gpu/media/gpu_video_decode_accelerator.h
+++ b/chromium/content/common/gpu/media/gpu_video_decode_accelerator.h
@@ -14,14 +14,11 @@
#include "base/synchronization/waitable_event.h"
#include "content/common/gpu/gpu_command_buffer_stub.h"
#include "gpu/command_buffer/service/texture_manager.h"
+#include "gpu/config/gpu_info.h"
#include "ipc/ipc_listener.h"
#include "ipc/ipc_sender.h"
#include "media/video/video_decode_accelerator.h"
-#include "ui/gfx/size.h"
-
-namespace base {
-class MessageLoopProxy;
-}
+#include "ui/gfx/geometry/size.h"
namespace content {
@@ -37,7 +34,7 @@ class GpuVideoDecodeAccelerator
GpuVideoDecodeAccelerator(
int32 host_route_id,
GpuCommandBufferStub* stub,
- const scoped_refptr<base::MessageLoopProxy>& io_message_loop);
+ const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner);
// IPC::Listener implementation.
bool OnMessageReceived(const IPC::Message& message) override;
@@ -59,14 +56,32 @@ class GpuVideoDecodeAccelerator
// Function to delegate sending to actual sender.
bool Send(IPC::Message* message) override;
- // Initialize the accelerator with the given profile and send the
- // |init_done_msg| when done.
+ // Initialize VDAs from the set of VDAs supported for current platform until
+ // one of them succeeds for given |profile|. Send the |init_done_msg| when
+ // done. filter_ is passed to GpuCommandBufferStub channel only if the chosen
+ // VDA can decode on IO thread.
void Initialize(const media::VideoCodecProfile profile,
IPC::Message* init_done_msg);
+ // Static query for supported profiles. This query calls the appropriate
+ // platform-specific version. The returned supported profiles vector will
+ // not contain duplicates.
+ static gpu::VideoDecodeAcceleratorSupportedProfiles GetSupportedProfiles();
+
private:
+ typedef scoped_ptr<media::VideoDecodeAccelerator>(
+ GpuVideoDecodeAccelerator::*CreateVDAFp)();
+
class MessageFilter;
+ scoped_ptr<media::VideoDecodeAccelerator> CreateDXVAVDA();
+ scoped_ptr<media::VideoDecodeAccelerator> CreateV4L2VDA();
+ scoped_ptr<media::VideoDecodeAccelerator> CreateV4L2SliceVDA();
+ scoped_ptr<media::VideoDecodeAccelerator> CreateVaapiVDA();
+ scoped_ptr<media::VideoDecodeAccelerator> CreateVTVDA();
+ scoped_ptr<media::VideoDecodeAccelerator> CreateOzoneVDA();
+ scoped_ptr<media::VideoDecodeAccelerator> CreateAndroidVDA();
+
// We only allow self-delete, from OnWillDestroyStub(), after cleanup there.
~GpuVideoDecodeAccelerator() override;
@@ -88,13 +103,18 @@ class GpuVideoDecodeAccelerator
// Helper for replying to the creation request.
void SendCreateDecoderReply(IPC::Message* message, bool succeeded);
+ // Helper to bind |image| to the texture specified by |client_texture_id|.
+ void BindImage(uint32 client_texture_id,
+ uint32 texture_target,
+ scoped_refptr<gfx::GLImage> image);
+
// Route ID to communicate with the host.
- int32 host_route_id_;
+ const int32 host_route_id_;
// Unowned pointer to the underlying GpuCommandBufferStub. |this| is
// registered as a DestuctionObserver of |stub_| and will self-delete when
// |stub_| is destroyed.
- GpuCommandBufferStub* stub_;
+ GpuCommandBufferStub* const stub_;
// The underlying VideoDecodeAccelerator.
scoped_ptr<media::VideoDecodeAccelerator> video_decode_accelerator_;
@@ -116,11 +136,11 @@ class GpuVideoDecodeAccelerator
// destroy the VDA.
base::WaitableEvent filter_removed_;
- // GPU child message loop.
- scoped_refptr<base::MessageLoopProxy> child_message_loop_;
+ // GPU child thread task runner.
+ const scoped_refptr<base::SingleThreadTaskRunner> child_task_runner_;
- // GPU IO message loop.
- scoped_refptr<base::MessageLoopProxy> io_message_loop_;
+ // GPU IO thread task runner.
+ const scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
// Weak pointers will be invalidated on IO thread.
base::WeakPtrFactory<Client> weak_factory_for_io_;
diff --git a/chromium/content/common/gpu/media/gpu_video_encode_accelerator.cc b/chromium/content/common/gpu/media/gpu_video_encode_accelerator.cc
index 12b473fcce2..4dd875b157c 100644
--- a/chromium/content/common/gpu/media/gpu_video_encode_accelerator.cc
+++ b/chromium/content/common/gpu/media/gpu_video_encode_accelerator.cc
@@ -8,24 +8,24 @@
#include "base/command_line.h"
#include "base/logging.h"
#include "base/memory/shared_memory.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/numerics/safe_math.h"
+#include "base/sys_info.h"
#include "build/build_config.h"
#include "content/common/gpu/gpu_channel.h"
#include "content/common/gpu/gpu_messages.h"
+#include "content/common/gpu/media/gpu_video_accelerator_util.h"
#include "content/public/common/content_switches.h"
#include "ipc/ipc_message_macros.h"
#include "media/base/limits.h"
#include "media/base/video_frame.h"
-#if defined(OS_CHROMEOS) && defined(USE_X11)
-
-#if defined(ARCH_CPU_ARMEL)
+#if defined(OS_CHROMEOS)
+#if defined(USE_V4L2_CODEC)
#include "content/common/gpu/media/v4l2_video_encode_accelerator.h"
-#elif defined(ARCH_CPU_X86_FAMILY)
+#endif
+#if defined(ARCH_CPU_X86_FAMILY)
#include "content/common/gpu/media/vaapi_video_encode_accelerator.h"
-#include "ui/gfx/x/x11_types.h"
#endif
-
#elif defined(OS_ANDROID) && defined(ENABLE_WEBRTC)
#include "content/common/gpu/media/android_video_encode_accelerator.h"
#endif
@@ -95,26 +95,26 @@ void GpuVideoEncodeAccelerator::Initialize(
return;
}
- encoder_ = CreateEncoder();
- if (!encoder_) {
- DLOG(ERROR)
- << "GpuVideoEncodeAccelerator::Initialize(): VEA creation failed";
- SendCreateEncoderReply(init_done_msg, false);
- return;
- }
- if (!encoder_->Initialize(input_format,
- input_visible_size,
- output_profile,
- initial_bitrate,
- this)) {
- DLOG(ERROR)
- << "GpuVideoEncodeAccelerator::Initialize(): VEA initialization failed";
- SendCreateEncoderReply(init_done_msg, false);
- return;
+ std::vector<GpuVideoEncodeAccelerator::CreateVEAFp>
+ create_vea_fps = CreateVEAFps();
+ // Try all possible encoders and use the first successful encoder.
+ for (size_t i = 0; i < create_vea_fps.size(); ++i) {
+ encoder_ = (*create_vea_fps[i])();
+ if (encoder_ && encoder_->Initialize(input_format,
+ input_visible_size,
+ output_profile,
+ initial_bitrate,
+ this)) {
+ input_format_ = input_format;
+ input_visible_size_ = input_visible_size;
+ SendCreateEncoderReply(init_done_msg, true);
+ return;
+ }
}
- input_format_ = input_format;
- input_visible_size_ = input_visible_size;
- SendCreateEncoderReply(init_done_msg, true);
+ encoder_.reset();
+ DLOG(ERROR)
+ << "GpuVideoEncodeAccelerator::Initialize(): VEA initialization failed";
+ SendCreateEncoderReply(init_done_msg, false);
}
bool GpuVideoEncodeAccelerator::OnMessageReceived(const IPC::Message& message) {
@@ -163,45 +163,64 @@ void GpuVideoEncodeAccelerator::OnWillDestroyStub() {
}
// static
-std::vector<gpu::VideoEncodeAcceleratorSupportedProfile>
+gpu::VideoEncodeAcceleratorSupportedProfiles
GpuVideoEncodeAccelerator::GetSupportedProfiles() {
- scoped_ptr<media::VideoEncodeAccelerator> encoder = CreateEncoder();
- if (!encoder)
- return std::vector<gpu::VideoEncodeAcceleratorSupportedProfile>();
- return ConvertMediaToGpuProfiles(encoder->GetSupportedProfiles());
+ media::VideoEncodeAccelerator::SupportedProfiles profiles;
+ std::vector<GpuVideoEncodeAccelerator::CreateVEAFp>
+ create_vea_fps = CreateVEAFps();
+
+ for (size_t i = 0; i < create_vea_fps.size(); ++i) {
+ scoped_ptr<media::VideoEncodeAccelerator>
+ encoder = (*create_vea_fps[i])();
+ if (!encoder)
+ continue;
+ media::VideoEncodeAccelerator::SupportedProfiles vea_profiles =
+ encoder->GetSupportedProfiles();
+ GpuVideoAcceleratorUtil::InsertUniqueEncodeProfiles(
+ vea_profiles, &profiles);
+ }
+ return GpuVideoAcceleratorUtil::ConvertMediaToGpuEncodeProfiles(profiles);
}
-std::vector<gpu::VideoEncodeAcceleratorSupportedProfile>
-GpuVideoEncodeAccelerator::ConvertMediaToGpuProfiles(const std::vector<
- media::VideoEncodeAccelerator::SupportedProfile>& media_profiles) {
- std::vector<gpu::VideoEncodeAcceleratorSupportedProfile> profiles;
- for (size_t i = 0; i < media_profiles.size(); i++) {
- gpu::VideoEncodeAcceleratorSupportedProfile profile;
- profile.profile =
- static_cast<gpu::VideoCodecProfile>(media_profiles[i].profile);
- profile.max_resolution = media_profiles[i].max_resolution;
- profile.max_framerate_numerator = media_profiles[i].max_framerate_numerator;
- profile.max_framerate_denominator =
- media_profiles[i].max_framerate_denominator;
- profiles.push_back(profile);
- }
- return profiles;
+// static
+std::vector<GpuVideoEncodeAccelerator::CreateVEAFp>
+GpuVideoEncodeAccelerator::CreateVEAFps() {
+ std::vector<GpuVideoEncodeAccelerator::CreateVEAFp> create_vea_fps;
+ create_vea_fps.push_back(&GpuVideoEncodeAccelerator::CreateV4L2VEA);
+ create_vea_fps.push_back(&GpuVideoEncodeAccelerator::CreateVaapiVEA);
+ create_vea_fps.push_back(&GpuVideoEncodeAccelerator::CreateAndroidVEA);
+ return create_vea_fps;
}
+// static
scoped_ptr<media::VideoEncodeAccelerator>
-GpuVideoEncodeAccelerator::CreateEncoder() {
+GpuVideoEncodeAccelerator::CreateV4L2VEA() {
scoped_ptr<media::VideoEncodeAccelerator> encoder;
-#if defined(OS_CHROMEOS) && defined(USE_X11)
-#if defined(ARCH_CPU_ARMEL)
- scoped_ptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kEncoder);
+#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC)
+ scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kEncoder);
if (device)
- encoder.reset(new V4L2VideoEncodeAccelerator(device.Pass()));
-#elif defined(ARCH_CPU_X86_FAMILY)
+ encoder.reset(new V4L2VideoEncodeAccelerator(device));
+#endif
+ return encoder.Pass();
+}
+
+// static
+scoped_ptr<media::VideoEncodeAccelerator>
+GpuVideoEncodeAccelerator::CreateVaapiVEA() {
+ scoped_ptr<media::VideoEncodeAccelerator> encoder;
+#if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)
const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
if (!cmd_line->HasSwitch(switches::kDisableVaapiAcceleratedVideoEncode))
- encoder.reset(new VaapiVideoEncodeAccelerator(gfx::GetXDisplay()));
+ encoder.reset(new VaapiVideoEncodeAccelerator());
#endif
-#elif defined(OS_ANDROID) && defined(ENABLE_WEBRTC)
+ return encoder.Pass();
+}
+
+// static
+scoped_ptr<media::VideoEncodeAccelerator>
+GpuVideoEncodeAccelerator::CreateAndroidVEA() {
+ scoped_ptr<media::VideoEncodeAccelerator> encoder;
+#if defined(OS_ANDROID) && defined(ENABLE_WEBRTC)
encoder.reset(new AndroidVideoEncodeAccelerator());
#endif
return encoder.Pass();
@@ -209,6 +228,7 @@ GpuVideoEncodeAccelerator::CreateEncoder() {
void GpuVideoEncodeAccelerator::OnEncode(int32 frame_id,
base::SharedMemoryHandle buffer_handle,
+ uint32 buffer_offset,
uint32 buffer_size,
bool force_keyframe) {
DVLOG(3) << "GpuVideoEncodeAccelerator::OnEncode(): frame_id=" << frame_id
@@ -223,16 +243,30 @@ void GpuVideoEncodeAccelerator::OnEncode(int32 frame_id,
return;
}
+ uint32 aligned_offset =
+ buffer_offset % base::SysInfo::VMAllocationGranularity();
+ base::CheckedNumeric<off_t> map_offset = buffer_offset;
+ map_offset -= aligned_offset;
+ base::CheckedNumeric<size_t> map_size = buffer_size;
+ map_size += aligned_offset;
+
+ if (!map_offset.IsValid() || !map_size.IsValid()) {
+ DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnEncode():"
+ << " invalid (buffer_offset,buffer_size)";
+ NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
+ return;
+ }
+
scoped_ptr<base::SharedMemory> shm(
new base::SharedMemory(buffer_handle, true));
- if (!shm->Map(buffer_size)) {
+ if (!shm->MapAt(map_offset.ValueOrDie(), map_size.ValueOrDie())) {
DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnEncode(): "
"could not map frame_id=" << frame_id;
NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
return;
}
- uint8* shm_memory = reinterpret_cast<uint8*>(shm->memory());
+ uint8* shm_memory = reinterpret_cast<uint8*>(shm->memory()) + aligned_offset;
scoped_refptr<media::VideoFrame> frame =
media::VideoFrame::WrapExternalPackedMemory(
input_format_,
@@ -242,10 +276,12 @@ void GpuVideoEncodeAccelerator::OnEncode(int32 frame_id,
shm_memory,
buffer_size,
buffer_handle,
+ buffer_offset,
base::TimeDelta(),
// It's turtles all the way down...
- base::Bind(base::IgnoreResult(&base::MessageLoopProxy::PostTask),
- base::MessageLoopProxy::current(),
+ base::Bind(base::IgnoreResult(
+ &base::SingleThreadTaskRunner::PostTask),
+ base::ThreadTaskRunnerHandle::Get(),
FROM_HERE,
base::Bind(&GpuVideoEncodeAccelerator::EncodeFrameFinished,
weak_this_factory_.GetWeakPtr(),
diff --git a/chromium/content/common/gpu/media/gpu_video_encode_accelerator.h b/chromium/content/common/gpu/media/gpu_video_encode_accelerator.h
index ca60f6f1c8d..f535f09339c 100644
--- a/chromium/content/common/gpu/media/gpu_video_encode_accelerator.h
+++ b/chromium/content/common/gpu/media/gpu_video_encode_accelerator.h
@@ -13,7 +13,7 @@
#include "gpu/config/gpu_info.h"
#include "ipc/ipc_listener.h"
#include "media/video/video_encode_accelerator.h"
-#include "ui/gfx/size.h"
+#include "ui/gfx/geometry/size.h"
namespace base {
@@ -58,21 +58,25 @@ class GpuVideoEncodeAccelerator
void OnWillDestroyStub() override;
// Static query for supported profiles. This query calls the appropriate
- // platform-specific version.
- static std::vector<gpu::VideoEncodeAcceleratorSupportedProfile>
- GetSupportedProfiles();
- static std::vector<gpu::VideoEncodeAcceleratorSupportedProfile>
- ConvertMediaToGpuProfiles(const std::vector<
- media::VideoEncodeAccelerator::SupportedProfile>& media_profiles);
+ // platform-specific version. The returned supported profiles vector will
+ // not contain duplicates.
+ static gpu::VideoEncodeAcceleratorSupportedProfiles GetSupportedProfiles();
private:
- // Create the appropriate platform-specific VEA.
- static scoped_ptr<media::VideoEncodeAccelerator> CreateEncoder();
+ typedef scoped_ptr<media::VideoEncodeAccelerator>(*CreateVEAFp)();
+
+ // Return a set of VEA Create function pointers applicable to the current
+ // platform.
+ static std::vector<CreateVEAFp> CreateVEAFps();
+ static scoped_ptr<media::VideoEncodeAccelerator> CreateV4L2VEA();
+ static scoped_ptr<media::VideoEncodeAccelerator> CreateVaapiVEA();
+ static scoped_ptr<media::VideoEncodeAccelerator> CreateAndroidVEA();
// IPC handlers, proxying media::VideoEncodeAccelerator for the renderer
// process.
void OnEncode(int32 frame_id,
base::SharedMemoryHandle buffer_handle,
+ uint32 buffer_offset,
uint32 buffer_size,
bool force_keyframe);
void OnUseOutputBitstreamBuffer(int32 buffer_id,
diff --git a/chromium/content/common/gpu/media/h264_decoder.cc b/chromium/content/common/gpu/media/h264_decoder.cc
new file mode 100644
index 00000000000..9953ff21a59
--- /dev/null
+++ b/chromium/content/common/gpu/media/h264_decoder.cc
@@ -0,0 +1,1292 @@
+// 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 <algorithm>
+#include <limits>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/stl_util.h"
+#include "content/common/gpu/media/h264_decoder.h"
+
+namespace content {
+
+H264Decoder::H264Accelerator::H264Accelerator() {
+}
+
+H264Decoder::H264Accelerator::~H264Accelerator() {
+}
+
+H264Decoder::H264Decoder(H264Accelerator* accelerator)
+ : max_pic_order_cnt_lsb_(0),
+ max_frame_num_(0),
+ max_pic_num_(0),
+ max_long_term_frame_idx_(0),
+ max_num_reorder_frames_(0),
+ curr_sps_id_(-1),
+ curr_pps_id_(-1),
+ accelerator_(accelerator) {
+ DCHECK(accelerator_);
+ Reset();
+ state_ = kNeedStreamMetadata;
+}
+
+H264Decoder::~H264Decoder() {
+}
+
+void H264Decoder::Reset() {
+ curr_pic_ = nullptr;
+ curr_nalu_ = nullptr;
+ curr_slice_hdr_ = nullptr;
+
+ frame_num_ = 0;
+ prev_frame_num_ = -1;
+ prev_frame_num_offset_ = -1;
+
+ prev_ref_has_memmgmnt5_ = false;
+ prev_ref_top_field_order_cnt_ = -1;
+ prev_ref_pic_order_cnt_msb_ = -1;
+ prev_ref_pic_order_cnt_lsb_ = -1;
+ prev_ref_field_ = H264Picture::FIELD_NONE;
+
+ ref_pic_list_p0_.clear();
+ ref_pic_list_b0_.clear();
+ ref_pic_list_b1_.clear();
+ dpb_.Clear();
+ parser_.Reset();
+ accelerator_->Reset();
+ last_output_poc_ = std::numeric_limits<int>::min();
+
+ // If we are in kDecoding, we can resume without processing an SPS.
+ if (state_ == kDecoding)
+ state_ = kAfterReset;
+}
+
+void H264Decoder::PrepareRefPicLists(media::H264SliceHeader* slice_hdr) {
+ ConstructReferencePicListsP(slice_hdr);
+ ConstructReferencePicListsB(slice_hdr);
+}
+
+bool H264Decoder::ModifyReferencePicLists(media::H264SliceHeader* slice_hdr,
+ H264Picture::Vector* ref_pic_list0,
+ H264Picture::Vector* ref_pic_list1) {
+ ref_pic_list0->clear();
+ ref_pic_list1->clear();
+
+ // Fill reference picture lists for B and S/SP slices.
+ if (slice_hdr->IsPSlice() || slice_hdr->IsSPSlice()) {
+ *ref_pic_list0 = ref_pic_list_p0_;
+ return ModifyReferencePicList(slice_hdr, 0, ref_pic_list0);
+ } else if (slice_hdr->IsBSlice()) {
+ *ref_pic_list0 = ref_pic_list_b0_;
+ *ref_pic_list1 = ref_pic_list_b1_;
+ return ModifyReferencePicList(slice_hdr, 0, ref_pic_list0) &&
+ ModifyReferencePicList(slice_hdr, 1, ref_pic_list1);
+ }
+
+ return true;
+}
+
+bool H264Decoder::DecodePicture() {
+ DCHECK(curr_pic_.get());
+
+ DVLOG(4) << "Decoding POC " << curr_pic_->pic_order_cnt;
+ return accelerator_->SubmitDecode(curr_pic_);
+}
+
+bool H264Decoder::InitCurrPicture(media::H264SliceHeader* slice_hdr) {
+ DCHECK(curr_pic_.get());
+
+ curr_pic_->idr = slice_hdr->idr_pic_flag;
+
+ if (slice_hdr->field_pic_flag) {
+ curr_pic_->field = slice_hdr->bottom_field_flag ? H264Picture::FIELD_BOTTOM
+ : H264Picture::FIELD_TOP;
+ } else {
+ curr_pic_->field = H264Picture::FIELD_NONE;
+ }
+
+ curr_pic_->ref = slice_hdr->nal_ref_idc != 0;
+ // This assumes non-interlaced stream.
+ curr_pic_->frame_num = curr_pic_->pic_num = slice_hdr->frame_num;
+
+ if (!CalculatePicOrderCounts(slice_hdr))
+ return false;
+
+ curr_pic_->long_term_reference_flag = slice_hdr->long_term_reference_flag;
+ curr_pic_->adaptive_ref_pic_marking_mode_flag =
+ slice_hdr->adaptive_ref_pic_marking_mode_flag;
+
+ // If the slice header indicates we will have to perform reference marking
+ // process after this picture is decoded, store required data for that
+ // purpose.
+ if (slice_hdr->adaptive_ref_pic_marking_mode_flag) {
+ static_assert(sizeof(curr_pic_->ref_pic_marking) ==
+ sizeof(slice_hdr->ref_pic_marking),
+ "Array sizes of ref pic marking do not match.");
+ memcpy(curr_pic_->ref_pic_marking, slice_hdr->ref_pic_marking,
+ sizeof(curr_pic_->ref_pic_marking));
+ }
+
+ return true;
+}
+
+bool H264Decoder::CalculatePicOrderCounts(media::H264SliceHeader* slice_hdr) {
+ DCHECK_NE(curr_sps_id_, -1);
+ const media::H264SPS* sps = parser_.GetSPS(curr_sps_id_);
+
+ int pic_order_cnt_lsb = slice_hdr->pic_order_cnt_lsb;
+ curr_pic_->pic_order_cnt_lsb = pic_order_cnt_lsb;
+
+ switch (sps->pic_order_cnt_type) {
+ case 0:
+ // See spec 8.2.1.1.
+ int prev_pic_order_cnt_msb, prev_pic_order_cnt_lsb;
+ if (slice_hdr->idr_pic_flag) {
+ prev_pic_order_cnt_msb = prev_pic_order_cnt_lsb = 0;
+ } else {
+ if (prev_ref_has_memmgmnt5_) {
+ if (prev_ref_field_ != H264Picture::FIELD_BOTTOM) {
+ prev_pic_order_cnt_msb = 0;
+ prev_pic_order_cnt_lsb = prev_ref_top_field_order_cnt_;
+ } else {
+ prev_pic_order_cnt_msb = 0;
+ prev_pic_order_cnt_lsb = 0;
+ }
+ } else {
+ prev_pic_order_cnt_msb = prev_ref_pic_order_cnt_msb_;
+ prev_pic_order_cnt_lsb = prev_ref_pic_order_cnt_lsb_;
+ }
+ }
+
+ DCHECK_NE(max_pic_order_cnt_lsb_, 0);
+ if ((pic_order_cnt_lsb < prev_pic_order_cnt_lsb) &&
+ (prev_pic_order_cnt_lsb - pic_order_cnt_lsb >=
+ max_pic_order_cnt_lsb_ / 2)) {
+ curr_pic_->pic_order_cnt_msb = prev_pic_order_cnt_msb +
+ max_pic_order_cnt_lsb_;
+ } else if ((pic_order_cnt_lsb > prev_pic_order_cnt_lsb) &&
+ (pic_order_cnt_lsb - prev_pic_order_cnt_lsb >
+ max_pic_order_cnt_lsb_ / 2)) {
+ curr_pic_->pic_order_cnt_msb = prev_pic_order_cnt_msb -
+ max_pic_order_cnt_lsb_;
+ } else {
+ curr_pic_->pic_order_cnt_msb = prev_pic_order_cnt_msb;
+ }
+
+ if (curr_pic_->field != H264Picture::FIELD_BOTTOM) {
+ curr_pic_->top_field_order_cnt = curr_pic_->pic_order_cnt_msb +
+ pic_order_cnt_lsb;
+ }
+
+ if (curr_pic_->field != H264Picture::FIELD_TOP) {
+ // TODO posciak: perhaps replace with pic->field?
+ if (!slice_hdr->field_pic_flag) {
+ curr_pic_->bottom_field_order_cnt = curr_pic_->top_field_order_cnt +
+ slice_hdr->delta_pic_order_cnt_bottom;
+ } else {
+ curr_pic_->bottom_field_order_cnt = curr_pic_->pic_order_cnt_msb +
+ pic_order_cnt_lsb;
+ }
+ }
+ break;
+
+ case 1: {
+ // See spec 8.2.1.2.
+ if (prev_has_memmgmnt5_)
+ prev_frame_num_offset_ = 0;
+
+ if (slice_hdr->idr_pic_flag)
+ curr_pic_->frame_num_offset = 0;
+ else if (prev_frame_num_ > slice_hdr->frame_num)
+ curr_pic_->frame_num_offset = prev_frame_num_offset_ + max_frame_num_;
+ else
+ curr_pic_->frame_num_offset = prev_frame_num_offset_;
+
+ int abs_frame_num = 0;
+ if (sps->num_ref_frames_in_pic_order_cnt_cycle != 0)
+ abs_frame_num = curr_pic_->frame_num_offset + slice_hdr->frame_num;
+ else
+ abs_frame_num = 0;
+
+ if (slice_hdr->nal_ref_idc == 0 && abs_frame_num > 0)
+ --abs_frame_num;
+
+ int expected_pic_order_cnt = 0;
+ if (abs_frame_num > 0) {
+ if (sps->num_ref_frames_in_pic_order_cnt_cycle == 0) {
+ DVLOG(1) << "Invalid num_ref_frames_in_pic_order_cnt_cycle "
+ << "in stream";
+ return false;
+ }
+
+ int pic_order_cnt_cycle_cnt = (abs_frame_num - 1) /
+ sps->num_ref_frames_in_pic_order_cnt_cycle;
+ int frame_num_in_pic_order_cnt_cycle = (abs_frame_num - 1) %
+ sps->num_ref_frames_in_pic_order_cnt_cycle;
+
+ expected_pic_order_cnt = pic_order_cnt_cycle_cnt *
+ sps->expected_delta_per_pic_order_cnt_cycle;
+ // frame_num_in_pic_order_cnt_cycle is verified < 255 in parser
+ for (int i = 0; i <= frame_num_in_pic_order_cnt_cycle; ++i)
+ expected_pic_order_cnt += sps->offset_for_ref_frame[i];
+ }
+
+ if (!slice_hdr->nal_ref_idc)
+ expected_pic_order_cnt += sps->offset_for_non_ref_pic;
+
+ if (!slice_hdr->field_pic_flag) {
+ curr_pic_->top_field_order_cnt = expected_pic_order_cnt +
+ slice_hdr->delta_pic_order_cnt0;
+ curr_pic_->bottom_field_order_cnt = curr_pic_->top_field_order_cnt +
+ sps->offset_for_top_to_bottom_field +
+ slice_hdr->delta_pic_order_cnt1;
+ } else if (!slice_hdr->bottom_field_flag) {
+ curr_pic_->top_field_order_cnt = expected_pic_order_cnt +
+ slice_hdr->delta_pic_order_cnt0;
+ } else {
+ curr_pic_->bottom_field_order_cnt = expected_pic_order_cnt +
+ sps->offset_for_top_to_bottom_field +
+ slice_hdr->delta_pic_order_cnt0;
+ }
+ break;
+ }
+
+ case 2:
+ // See spec 8.2.1.3.
+ if (prev_has_memmgmnt5_)
+ prev_frame_num_offset_ = 0;
+
+ if (slice_hdr->idr_pic_flag)
+ curr_pic_->frame_num_offset = 0;
+ else if (prev_frame_num_ > slice_hdr->frame_num)
+ curr_pic_->frame_num_offset = prev_frame_num_offset_ + max_frame_num_;
+ else
+ curr_pic_->frame_num_offset = prev_frame_num_offset_;
+
+ int temp_pic_order_cnt;
+ if (slice_hdr->idr_pic_flag) {
+ temp_pic_order_cnt = 0;
+ } else if (!slice_hdr->nal_ref_idc) {
+ temp_pic_order_cnt =
+ 2 * (curr_pic_->frame_num_offset + slice_hdr->frame_num) - 1;
+ } else {
+ temp_pic_order_cnt = 2 * (curr_pic_->frame_num_offset +
+ slice_hdr->frame_num);
+ }
+
+ if (!slice_hdr->field_pic_flag) {
+ curr_pic_->top_field_order_cnt = temp_pic_order_cnt;
+ curr_pic_->bottom_field_order_cnt = temp_pic_order_cnt;
+ } else if (slice_hdr->bottom_field_flag) {
+ curr_pic_->bottom_field_order_cnt = temp_pic_order_cnt;
+ } else {
+ curr_pic_->top_field_order_cnt = temp_pic_order_cnt;
+ }
+ break;
+
+ default:
+ DVLOG(1) << "Invalid pic_order_cnt_type: " << sps->pic_order_cnt_type;
+ return false;
+ }
+
+ switch (curr_pic_->field) {
+ case H264Picture::FIELD_NONE:
+ curr_pic_->pic_order_cnt = std::min(curr_pic_->top_field_order_cnt,
+ curr_pic_->bottom_field_order_cnt);
+ break;
+ case H264Picture::FIELD_TOP:
+ curr_pic_->pic_order_cnt = curr_pic_->top_field_order_cnt;
+ break;
+ case H264Picture::FIELD_BOTTOM:
+ curr_pic_->pic_order_cnt = curr_pic_->bottom_field_order_cnt;
+ break;
+ }
+
+ return true;
+}
+
+void H264Decoder::UpdatePicNums() {
+ for (auto& pic : dpb_) {
+ if (!pic->ref)
+ continue;
+
+ // Below assumes non-interlaced stream.
+ DCHECK_EQ(pic->field, H264Picture::FIELD_NONE);
+ if (pic->long_term) {
+ pic->long_term_pic_num = pic->long_term_frame_idx;
+ } else {
+ if (pic->frame_num > frame_num_)
+ pic->frame_num_wrap = pic->frame_num - max_frame_num_;
+ else
+ pic->frame_num_wrap = pic->frame_num;
+
+ pic->pic_num = pic->frame_num_wrap;
+ }
+ }
+}
+
+struct PicNumDescCompare {
+ bool operator()(const scoped_refptr<H264Picture>& a,
+ const scoped_refptr<H264Picture>& b) const {
+ return a->pic_num > b->pic_num;
+ }
+};
+
+struct LongTermPicNumAscCompare {
+ bool operator()(const scoped_refptr<H264Picture>& a,
+ const scoped_refptr<H264Picture>& b) const {
+ return a->long_term_pic_num < b->long_term_pic_num;
+ }
+};
+
+void H264Decoder::ConstructReferencePicListsP(
+ media::H264SliceHeader* slice_hdr) {
+ // RefPicList0 (8.2.4.2.1) [[1] [2]], where:
+ // [1] shortterm ref pics sorted by descending pic_num,
+ // [2] longterm ref pics by ascending long_term_pic_num.
+ ref_pic_list_p0_.clear();
+
+ // First get the short ref pics...
+ dpb_.GetShortTermRefPicsAppending(&ref_pic_list_p0_);
+ size_t num_short_refs = ref_pic_list_p0_.size();
+
+ // and sort them to get [1].
+ std::sort(ref_pic_list_p0_.begin(), ref_pic_list_p0_.end(),
+ PicNumDescCompare());
+
+ // Now get long term pics and sort them by long_term_pic_num to get [2].
+ dpb_.GetLongTermRefPicsAppending(&ref_pic_list_p0_);
+ std::sort(ref_pic_list_p0_.begin() + num_short_refs, ref_pic_list_p0_.end(),
+ LongTermPicNumAscCompare());
+
+ // Cut off if we have more than requested in slice header.
+ ref_pic_list_p0_.resize(slice_hdr->num_ref_idx_l0_active_minus1 + 1);
+}
+
+struct POCAscCompare {
+ bool operator()(const scoped_refptr<H264Picture>& a,
+ const scoped_refptr<H264Picture>& b) const {
+ return a->pic_order_cnt < b->pic_order_cnt;
+ }
+};
+
+struct POCDescCompare {
+ bool operator()(const scoped_refptr<H264Picture>& a,
+ const scoped_refptr<H264Picture>& b) const {
+ return a->pic_order_cnt > b->pic_order_cnt;
+ }
+};
+
+void H264Decoder::ConstructReferencePicListsB(
+ media::H264SliceHeader* slice_hdr) {
+ // RefPicList0 (8.2.4.2.3) [[1] [2] [3]], where:
+ // [1] shortterm ref pics with POC < curr_pic's POC sorted by descending POC,
+ // [2] shortterm ref pics with POC > curr_pic's POC by ascending POC,
+ // [3] longterm ref pics by ascending long_term_pic_num.
+ ref_pic_list_b0_.clear();
+ ref_pic_list_b1_.clear();
+ dpb_.GetShortTermRefPicsAppending(&ref_pic_list_b0_);
+ size_t num_short_refs = ref_pic_list_b0_.size();
+
+ // First sort ascending, this will put [1] in right place and finish [2].
+ std::sort(ref_pic_list_b0_.begin(), ref_pic_list_b0_.end(), POCAscCompare());
+
+ // Find first with POC > curr_pic's POC to get first element in [2]...
+ H264Picture::Vector::iterator iter;
+ iter = std::upper_bound(ref_pic_list_b0_.begin(), ref_pic_list_b0_.end(),
+ curr_pic_.get(), POCAscCompare());
+
+ // and sort [1] descending, thus finishing sequence [1] [2].
+ std::sort(ref_pic_list_b0_.begin(), iter, POCDescCompare());
+
+ // Now add [3] and sort by ascending long_term_pic_num.
+ dpb_.GetLongTermRefPicsAppending(&ref_pic_list_b0_);
+ std::sort(ref_pic_list_b0_.begin() + num_short_refs, ref_pic_list_b0_.end(),
+ LongTermPicNumAscCompare());
+
+ // RefPicList1 (8.2.4.2.4) [[1] [2] [3]], where:
+ // [1] shortterm ref pics with POC > curr_pic's POC sorted by ascending POC,
+ // [2] shortterm ref pics with POC < curr_pic's POC by descending POC,
+ // [3] longterm ref pics by ascending long_term_pic_num.
+
+ dpb_.GetShortTermRefPicsAppending(&ref_pic_list_b1_);
+ num_short_refs = ref_pic_list_b1_.size();
+
+ // First sort by descending POC.
+ std::sort(ref_pic_list_b1_.begin(), ref_pic_list_b1_.end(), POCDescCompare());
+
+ // Find first with POC < curr_pic's POC to get first element in [2]...
+ iter = std::upper_bound(ref_pic_list_b1_.begin(), ref_pic_list_b1_.end(),
+ curr_pic_.get(), POCDescCompare());
+
+ // and sort [1] ascending.
+ std::sort(ref_pic_list_b1_.begin(), iter, POCAscCompare());
+
+ // Now add [3] and sort by ascending long_term_pic_num
+ dpb_.GetShortTermRefPicsAppending(&ref_pic_list_b1_);
+ std::sort(ref_pic_list_b1_.begin() + num_short_refs, ref_pic_list_b1_.end(),
+ LongTermPicNumAscCompare());
+
+ // If lists identical, swap first two entries in RefPicList1 (spec 8.2.4.2.3)
+ if (ref_pic_list_b1_.size() > 1 &&
+ std::equal(ref_pic_list_b0_.begin(), ref_pic_list_b0_.end(),
+ ref_pic_list_b1_.begin()))
+ std::swap(ref_pic_list_b1_[0], ref_pic_list_b1_[1]);
+
+ // Per 8.2.4.2 it's possible for num_ref_idx_lX_active_minus1 to indicate
+ // there should be more ref pics on list than we constructed.
+ // Those superfluous ones should be treated as non-reference.
+ ref_pic_list_b0_.resize(slice_hdr->num_ref_idx_l0_active_minus1 + 1);
+ ref_pic_list_b1_.resize(slice_hdr->num_ref_idx_l1_active_minus1 + 1);
+}
+
+// See 8.2.4
+int H264Decoder::PicNumF(const scoped_refptr<H264Picture>& pic) {
+ if (!pic)
+ return -1;
+
+ if (!pic->long_term)
+ return pic->pic_num;
+ else
+ return max_pic_num_;
+}
+
+// See 8.2.4
+int H264Decoder::LongTermPicNumF(const scoped_refptr<H264Picture>& pic) {
+ if (pic->ref && pic->long_term)
+ return pic->long_term_pic_num;
+ else
+ return 2 * (max_long_term_frame_idx_ + 1);
+}
+
+// Shift elements on the |v| starting from |from| to |to|, inclusive,
+// one position to the right and insert pic at |from|.
+static void ShiftRightAndInsert(H264Picture::Vector* v,
+ int from,
+ int to,
+ const scoped_refptr<H264Picture>& pic) {
+ // Security checks, do not disable in Debug mode.
+ CHECK(from <= to);
+ CHECK(to <= std::numeric_limits<int>::max() - 2);
+ // Additional checks. Debug mode ok.
+ DCHECK(v);
+ DCHECK(pic);
+ DCHECK((to + 1 == static_cast<int>(v->size())) ||
+ (to + 2 == static_cast<int>(v->size())));
+
+ v->resize(to + 2);
+
+ for (int i = to + 1; i > from; --i)
+ (*v)[i] = (*v)[i - 1];
+
+ (*v)[from] = pic;
+}
+
+bool H264Decoder::ModifyReferencePicList(media::H264SliceHeader* slice_hdr,
+ int list,
+ H264Picture::Vector* ref_pic_listx) {
+ int num_ref_idx_lX_active_minus1;
+ media::H264ModificationOfPicNum* list_mod;
+
+ // This can process either ref_pic_list0 or ref_pic_list1, depending on
+ // the list argument. Set up pointers to proper list to be processed here.
+ if (list == 0) {
+ if (!slice_hdr->ref_pic_list_modification_flag_l0)
+ return true;
+
+ list_mod = slice_hdr->ref_list_l0_modifications;
+ } else {
+ if (!slice_hdr->ref_pic_list_modification_flag_l1)
+ return true;
+
+ list_mod = slice_hdr->ref_list_l1_modifications;
+ }
+
+ num_ref_idx_lX_active_minus1 = ref_pic_listx->size() - 1;
+ DCHECK_GE(num_ref_idx_lX_active_minus1, 0);
+
+ // Spec 8.2.4.3:
+ // Reorder pictures on the list in a way specified in the stream.
+ int pic_num_lx_pred = curr_pic_->pic_num;
+ int ref_idx_lx = 0;
+ int pic_num_lx_no_wrap;
+ int pic_num_lx;
+ bool done = false;
+ scoped_refptr<H264Picture> pic;
+ for (int i = 0; i < media::H264SliceHeader::kRefListModSize && !done; ++i) {
+ switch (list_mod->modification_of_pic_nums_idc) {
+ case 0:
+ case 1:
+ // Modify short reference picture position.
+ if (list_mod->modification_of_pic_nums_idc == 0) {
+ // Subtract given value from predicted PicNum.
+ pic_num_lx_no_wrap = pic_num_lx_pred -
+ (static_cast<int>(list_mod->abs_diff_pic_num_minus1) + 1);
+ // Wrap around max_pic_num_ if it becomes < 0 as result
+ // of subtraction.
+ if (pic_num_lx_no_wrap < 0)
+ pic_num_lx_no_wrap += max_pic_num_;
+ } else {
+ // Add given value to predicted PicNum.
+ pic_num_lx_no_wrap = pic_num_lx_pred +
+ (static_cast<int>(list_mod->abs_diff_pic_num_minus1) + 1);
+ // Wrap around max_pic_num_ if it becomes >= max_pic_num_ as result
+ // of the addition.
+ if (pic_num_lx_no_wrap >= max_pic_num_)
+ pic_num_lx_no_wrap -= max_pic_num_;
+ }
+
+ // For use in next iteration.
+ pic_num_lx_pred = pic_num_lx_no_wrap;
+
+ if (pic_num_lx_no_wrap > curr_pic_->pic_num)
+ pic_num_lx = pic_num_lx_no_wrap - max_pic_num_;
+ else
+ pic_num_lx = pic_num_lx_no_wrap;
+
+ DCHECK_LT(num_ref_idx_lX_active_minus1 + 1,
+ media::H264SliceHeader::kRefListModSize);
+ pic = dpb_.GetShortRefPicByPicNum(pic_num_lx);
+ if (!pic) {
+ DVLOG(1) << "Malformed stream, no pic num " << pic_num_lx;
+ return false;
+ }
+ ShiftRightAndInsert(ref_pic_listx, ref_idx_lx,
+ num_ref_idx_lX_active_minus1, pic);
+ ref_idx_lx++;
+
+ for (int src = ref_idx_lx, dst = ref_idx_lx;
+ src <= num_ref_idx_lX_active_minus1 + 1; ++src) {
+ if (PicNumF((*ref_pic_listx)[src]) != pic_num_lx)
+ (*ref_pic_listx)[dst++] = (*ref_pic_listx)[src];
+ }
+ break;
+
+ case 2:
+ // Modify long term reference picture position.
+ DCHECK_LT(num_ref_idx_lX_active_minus1 + 1,
+ media::H264SliceHeader::kRefListModSize);
+ pic = dpb_.GetLongRefPicByLongTermPicNum(list_mod->long_term_pic_num);
+ if (!pic) {
+ DVLOG(1) << "Malformed stream, no pic num "
+ << list_mod->long_term_pic_num;
+ return false;
+ }
+ ShiftRightAndInsert(ref_pic_listx, ref_idx_lx,
+ num_ref_idx_lX_active_minus1, pic);
+ ref_idx_lx++;
+
+ for (int src = ref_idx_lx, dst = ref_idx_lx;
+ src <= num_ref_idx_lX_active_minus1 + 1; ++src) {
+ if (LongTermPicNumF((*ref_pic_listx)[src]) !=
+ static_cast<int>(list_mod->long_term_pic_num))
+ (*ref_pic_listx)[dst++] = (*ref_pic_listx)[src];
+ }
+ break;
+
+ case 3:
+ // End of modification list.
+ done = true;
+ break;
+
+ default:
+ // May be recoverable.
+ DVLOG(1) << "Invalid modification_of_pic_nums_idc="
+ << list_mod->modification_of_pic_nums_idc
+ << " in position " << i;
+ break;
+ }
+
+ ++list_mod;
+ }
+
+ // Per NOTE 2 in 8.2.4.3.2, the ref_pic_listx size in the above loop is
+ // temporarily made one element longer than the required final list.
+ // Resize the list back to its required size.
+ ref_pic_listx->resize(num_ref_idx_lX_active_minus1 + 1);
+
+ return true;
+}
+
+void H264Decoder::OutputPic(scoped_refptr<H264Picture> pic) {
+ DCHECK(!pic->outputted);
+ pic->outputted = true;
+
+ DVLOG_IF(1, pic->pic_order_cnt < last_output_poc_)
+ << "Outputting out of order, likely a broken stream";
+ last_output_poc_ = pic->pic_order_cnt;
+
+ DVLOG(4) << "Posting output task for POC: " << pic->pic_order_cnt;
+ accelerator_->OutputPicture(pic);
+}
+
+void H264Decoder::ClearDPB() {
+ // Clear DPB contents, marking the pictures as unused first.
+ dpb_.Clear();
+ last_output_poc_ = std::numeric_limits<int>::min();
+}
+
+bool H264Decoder::OutputAllRemainingPics() {
+ // Output all pictures that are waiting to be outputted.
+ FinishPrevFrameIfPresent();
+ H264Picture::Vector to_output;
+ dpb_.GetNotOutputtedPicsAppending(&to_output);
+ // Sort them by ascending POC to output in order.
+ std::sort(to_output.begin(), to_output.end(), POCAscCompare());
+
+ for (auto& pic : to_output)
+ OutputPic(pic);
+
+ return true;
+}
+
+bool H264Decoder::Flush() {
+ DVLOG(2) << "Decoder flush";
+
+ if (!OutputAllRemainingPics())
+ return false;
+
+ ClearDPB();
+ DVLOG(2) << "Decoder flush finished";
+ return true;
+}
+
+bool H264Decoder::StartNewFrame(media::H264SliceHeader* slice_hdr) {
+ // TODO posciak: add handling of max_num_ref_frames per spec.
+ CHECK(curr_pic_.get());
+
+ if (!InitCurrPicture(slice_hdr))
+ return false;
+
+ DCHECK_GT(max_frame_num_, 0);
+
+ UpdatePicNums();
+ DCHECK(slice_hdr);
+ PrepareRefPicLists(slice_hdr);
+
+ const media::H264PPS* pps = parser_.GetPPS(curr_pps_id_);
+ DCHECK(pps);
+ const media::H264SPS* sps = parser_.GetSPS(pps->seq_parameter_set_id);
+ DCHECK(sps);
+
+ if (!accelerator_->SubmitFrameMetadata(sps, pps, dpb_, ref_pic_list_p0_,
+ ref_pic_list_b0_, ref_pic_list_b1_,
+ curr_pic_.get()))
+ return false;
+
+ return true;
+}
+
+bool H264Decoder::HandleMemoryManagementOps() {
+ // 8.2.5.4
+ for (unsigned int i = 0; i < arraysize(curr_pic_->ref_pic_marking); ++i) {
+ // Code below does not support interlaced stream (per-field pictures).
+ media::H264DecRefPicMarking* ref_pic_marking =
+ &curr_pic_->ref_pic_marking[i];
+ scoped_refptr<H264Picture> to_mark;
+ int pic_num_x;
+
+ switch (ref_pic_marking->memory_mgmnt_control_operation) {
+ case 0:
+ // Normal end of operations' specification.
+ return true;
+
+ case 1:
+ // Mark a short term reference picture as unused so it can be removed
+ // if outputted.
+ pic_num_x = curr_pic_->pic_num -
+ (ref_pic_marking->difference_of_pic_nums_minus1 + 1);
+ to_mark = dpb_.GetShortRefPicByPicNum(pic_num_x);
+ if (to_mark) {
+ to_mark->ref = false;
+ } else {
+ DVLOG(1) << "Invalid short ref pic num to unmark";
+ return false;
+ }
+ break;
+
+ case 2:
+ // Mark a long term reference picture as unused so it can be removed
+ // if outputted.
+ to_mark = dpb_.GetLongRefPicByLongTermPicNum(
+ ref_pic_marking->long_term_pic_num);
+ if (to_mark) {
+ to_mark->ref = false;
+ } else {
+ DVLOG(1) << "Invalid long term ref pic num to unmark";
+ return false;
+ }
+ break;
+
+ case 3:
+ // Mark a short term reference picture as long term reference.
+ pic_num_x = curr_pic_->pic_num -
+ (ref_pic_marking->difference_of_pic_nums_minus1 + 1);
+ to_mark = dpb_.GetShortRefPicByPicNum(pic_num_x);
+ if (to_mark) {
+ DCHECK(to_mark->ref && !to_mark->long_term);
+ to_mark->long_term = true;
+ to_mark->long_term_frame_idx = ref_pic_marking->long_term_frame_idx;
+ } else {
+ DVLOG(1) << "Invalid short term ref pic num to mark as long ref";
+ return false;
+ }
+ break;
+
+ case 4: {
+ // Unmark all reference pictures with long_term_frame_idx over new max.
+ max_long_term_frame_idx_ =
+ ref_pic_marking->max_long_term_frame_idx_plus1 - 1;
+ H264Picture::Vector long_terms;
+ dpb_.GetLongTermRefPicsAppending(&long_terms);
+ for (size_t i = 0; i < long_terms.size(); ++i) {
+ scoped_refptr<H264Picture>& pic = long_terms[i];
+ DCHECK(pic->ref && pic->long_term);
+ // Ok to cast, max_long_term_frame_idx is much smaller than 16bit.
+ if (pic->long_term_frame_idx >
+ static_cast<int>(max_long_term_frame_idx_))
+ pic->ref = false;
+ }
+ break;
+ }
+
+ case 5:
+ // Unmark all reference pictures.
+ dpb_.MarkAllUnusedForRef();
+ max_long_term_frame_idx_ = -1;
+ curr_pic_->mem_mgmt_5 = true;
+ break;
+
+ case 6: {
+ // Replace long term reference pictures with current picture.
+ // First unmark if any existing with this long_term_frame_idx...
+ H264Picture::Vector long_terms;
+ dpb_.GetLongTermRefPicsAppending(&long_terms);
+ for (size_t i = 0; i < long_terms.size(); ++i) {
+ scoped_refptr<H264Picture>& pic = long_terms[i];
+ DCHECK(pic->ref && pic->long_term);
+ // Ok to cast, long_term_frame_idx is much smaller than 16bit.
+ if (pic->long_term_frame_idx ==
+ static_cast<int>(ref_pic_marking->long_term_frame_idx))
+ pic->ref = false;
+ }
+
+ // and mark the current one instead.
+ curr_pic_->ref = true;
+ curr_pic_->long_term = true;
+ curr_pic_->long_term_frame_idx = ref_pic_marking->long_term_frame_idx;
+ break;
+ }
+
+ default:
+ // Would indicate a bug in parser.
+ NOTREACHED();
+ }
+ }
+
+ return true;
+}
+
+// This method ensures that DPB does not overflow, either by removing
+// reference pictures as specified in the stream, or using a sliding window
+// procedure to remove the oldest one.
+// It also performs marking and unmarking pictures as reference.
+// See spac 8.2.5.1.
+void H264Decoder::ReferencePictureMarking() {
+ if (curr_pic_->idr) {
+ // If current picture is an IDR, all reference pictures are unmarked.
+ dpb_.MarkAllUnusedForRef();
+
+ if (curr_pic_->long_term_reference_flag) {
+ curr_pic_->long_term = true;
+ curr_pic_->long_term_frame_idx = 0;
+ max_long_term_frame_idx_ = 0;
+ } else {
+ curr_pic_->long_term = false;
+ max_long_term_frame_idx_ = -1;
+ }
+ } else {
+ if (!curr_pic_->adaptive_ref_pic_marking_mode_flag) {
+ // If non-IDR, and the stream does not indicate what we should do to
+ // ensure DPB doesn't overflow, discard oldest picture.
+ // See spec 8.2.5.3.
+ if (curr_pic_->field == H264Picture::FIELD_NONE) {
+ DCHECK_LE(
+ dpb_.CountRefPics(),
+ std::max<int>(parser_.GetSPS(curr_sps_id_)->max_num_ref_frames, 1));
+ if (dpb_.CountRefPics() ==
+ std::max<int>(parser_.GetSPS(curr_sps_id_)->max_num_ref_frames,
+ 1)) {
+ // Max number of reference pics reached,
+ // need to remove one of the short term ones.
+ // Find smallest frame_num_wrap short reference picture and mark
+ // it as unused.
+ scoped_refptr<H264Picture> to_unmark =
+ dpb_.GetLowestFrameNumWrapShortRefPic();
+ if (to_unmark == NULL) {
+ DVLOG(1) << "Couldn't find a short ref picture to unmark";
+ return;
+ }
+ to_unmark->ref = false;
+ }
+ } else {
+ // Shouldn't get here.
+ DVLOG(1) << "Interlaced video not supported.";
+ }
+ } else {
+ // Stream has instructions how to discard pictures from DPB and how
+ // to mark/unmark existing reference pictures. Do it.
+ // Spec 8.2.5.4.
+ if (curr_pic_->field == H264Picture::FIELD_NONE) {
+ HandleMemoryManagementOps();
+ } else {
+ // Shouldn't get here.
+ DVLOG(1) << "Interlaced video not supported.";
+ }
+ }
+ }
+}
+
+bool H264Decoder::FinishPicture() {
+ DCHECK(curr_pic_.get());
+
+ // Finish processing previous picture.
+ // Start by storing previous reference picture data for later use,
+ // if picture being finished is a reference picture.
+ if (curr_pic_->ref) {
+ ReferencePictureMarking();
+ prev_ref_has_memmgmnt5_ = curr_pic_->mem_mgmt_5;
+ prev_ref_top_field_order_cnt_ = curr_pic_->top_field_order_cnt;
+ prev_ref_pic_order_cnt_msb_ = curr_pic_->pic_order_cnt_msb;
+ prev_ref_pic_order_cnt_lsb_ = curr_pic_->pic_order_cnt_lsb;
+ prev_ref_field_ = curr_pic_->field;
+ }
+ prev_has_memmgmnt5_ = curr_pic_->mem_mgmt_5;
+ prev_frame_num_offset_ = curr_pic_->frame_num_offset;
+
+ // Remove unused (for reference or later output) pictures from DPB, marking
+ // them as such.
+ dpb_.DeleteUnused();
+
+ DVLOG(4) << "Finishing picture, entries in DPB: " << dpb_.size();
+
+ // Whatever happens below, curr_pic_ will stop managing the pointer to the
+ // picture after this. The ownership will either be transferred to DPB, if
+ // the image is still needed (for output and/or reference), or the memory
+ // will be released if we manage to output it here without having to store
+ // it for future reference.
+ scoped_refptr<H264Picture> pic = curr_pic_;
+ curr_pic_ = nullptr;
+
+ // Get all pictures that haven't been outputted yet.
+ H264Picture::Vector not_outputted;
+ dpb_.GetNotOutputtedPicsAppending(&not_outputted);
+ // Include the one we've just decoded.
+ not_outputted.push_back(pic);
+
+ // Sort in output order.
+ std::sort(not_outputted.begin(), not_outputted.end(), POCAscCompare());
+
+ // Try to output as many pictures as we can. A picture can be output,
+ // if the number of decoded and not yet outputted pictures that would remain
+ // in DPB afterwards would at least be equal to max_num_reorder_frames.
+ // If the outputted picture is not a reference picture, it doesn't have
+ // to remain in the DPB and can be removed.
+ H264Picture::Vector::iterator output_candidate = not_outputted.begin();
+ size_t num_remaining = not_outputted.size();
+ while (num_remaining > max_num_reorder_frames_ ||
+ // If the condition below is used, this is an invalid stream. We should
+ // not be forced to output beyond max_num_reorder_frames in order to
+ // make room in DPB to store the current picture (if we need to do so).
+ // However, if this happens, ignore max_num_reorder_frames and try
+ // to output more. This may cause out-of-order output, but is not
+ // fatal, and better than failing instead.
+ ((dpb_.IsFull() && (!pic->outputted || pic->ref)) && num_remaining)) {
+ DVLOG_IF(1, num_remaining <= max_num_reorder_frames_)
+ << "Invalid stream: max_num_reorder_frames not preserved";
+
+ OutputPic(*output_candidate);
+
+ if (!(*output_candidate)->ref) {
+ // Current picture hasn't been inserted into DPB yet, so don't remove it
+ // if we managed to output it immediately.
+ int outputted_poc = (*output_candidate)->pic_order_cnt;
+ if (outputted_poc != pic->pic_order_cnt)
+ dpb_.DeleteByPOC(outputted_poc);
+ }
+
+ ++output_candidate;
+ --num_remaining;
+ }
+
+ // If we haven't managed to output the picture that we just decoded, or if
+ // it's a reference picture, we have to store it in DPB.
+ if (!pic->outputted || pic->ref) {
+ if (dpb_.IsFull()) {
+ // If we haven't managed to output anything to free up space in DPB
+ // to store this picture, it's an error in the stream.
+ DVLOG(1) << "Could not free up space in DPB!";
+ return false;
+ }
+
+ dpb_.StorePic(pic);
+ }
+
+ return true;
+}
+
+static int LevelToMaxDpbMbs(int level) {
+ // See table A-1 in spec.
+ switch (level) {
+ case 10: return 396;
+ case 11: return 900;
+ case 12: // fallthrough
+ case 13: // fallthrough
+ case 20: return 2376;
+ case 21: return 4752;
+ case 22: // fallthrough
+ case 30: return 8100;
+ case 31: return 18000;
+ case 32: return 20480;
+ case 40: // fallthrough
+ case 41: return 32768;
+ case 42: return 34816;
+ case 50: return 110400;
+ case 51: // fallthrough
+ case 52: return 184320;
+ default:
+ DVLOG(1) << "Invalid codec level (" << level << ")";
+ return 0;
+ }
+}
+
+bool H264Decoder::UpdateMaxNumReorderFrames(const media::H264SPS* sps) {
+ if (sps->vui_parameters_present_flag && sps->bitstream_restriction_flag) {
+ max_num_reorder_frames_ =
+ base::checked_cast<size_t>(sps->max_num_reorder_frames);
+ if (max_num_reorder_frames_ > dpb_.max_num_pics()) {
+ DVLOG(1)
+ << "max_num_reorder_frames present, but larger than MaxDpbFrames ("
+ << max_num_reorder_frames_ << " > " << dpb_.max_num_pics() << ")";
+ max_num_reorder_frames_ = 0;
+ return false;
+ }
+ return true;
+ }
+
+ // max_num_reorder_frames not present, infer from profile/constraints
+ // (see VUI semantics in spec).
+ if (sps->constraint_set3_flag) {
+ switch (sps->profile_idc) {
+ case 44:
+ case 86:
+ case 100:
+ case 110:
+ case 122:
+ case 244:
+ max_num_reorder_frames_ = 0;
+ break;
+ default:
+ max_num_reorder_frames_ = dpb_.max_num_pics();
+ break;
+ }
+ } else {
+ max_num_reorder_frames_ = dpb_.max_num_pics();
+ }
+
+ return true;
+}
+
+bool H264Decoder::ProcessSPS(int sps_id, bool* need_new_buffers) {
+ const media::H264SPS* sps = parser_.GetSPS(sps_id);
+ DCHECK(sps);
+ DVLOG(4) << "Processing SPS";
+
+ *need_new_buffers = false;
+
+ if (sps->frame_mbs_only_flag == 0) {
+ DVLOG(1) << "frame_mbs_only_flag != 1 not supported";
+ return false;
+ }
+
+ if (sps->gaps_in_frame_num_value_allowed_flag) {
+ DVLOG(1) << "Gaps in frame numbers not supported";
+ return false;
+ }
+
+ curr_sps_id_ = sps->seq_parameter_set_id;
+
+ // Calculate picture height/width in macroblocks and pixels
+ // (spec 7.4.2.1.1, 7.4.3).
+ int width_mb = sps->pic_width_in_mbs_minus1 + 1;
+ int height_mb = (2 - sps->frame_mbs_only_flag) *
+ (sps->pic_height_in_map_units_minus1 + 1);
+
+ gfx::Size new_pic_size(16 * width_mb, 16 * height_mb);
+ if (new_pic_size.IsEmpty()) {
+ DVLOG(1) << "Invalid picture size: " << new_pic_size.ToString();
+ return false;
+ }
+
+ if (!pic_size_.IsEmpty() && new_pic_size == pic_size_) {
+ // Already have surfaces and this SPS keeps the same resolution,
+ // no need to request a new set.
+ return true;
+ }
+
+ pic_size_ = new_pic_size;
+ DVLOG(1) << "New picture size: " << pic_size_.ToString();
+
+ max_pic_order_cnt_lsb_ = 1 << (sps->log2_max_pic_order_cnt_lsb_minus4 + 4);
+ max_frame_num_ = 1 << (sps->log2_max_frame_num_minus4 + 4);
+
+ int level = sps->level_idc;
+ int max_dpb_mbs = LevelToMaxDpbMbs(level);
+ if (max_dpb_mbs == 0)
+ return false;
+
+ size_t max_dpb_size = std::min(max_dpb_mbs / (width_mb * height_mb),
+ static_cast<int>(H264DPB::kDPBMaxSize));
+ DVLOG(1) << "Codec level: " << level << ", DPB size: " << max_dpb_size;
+ if (max_dpb_size == 0) {
+ DVLOG(1) << "Invalid DPB Size";
+ return false;
+ }
+
+ dpb_.set_max_num_pics(max_dpb_size);
+
+ if (!UpdateMaxNumReorderFrames(sps))
+ return false;
+ DVLOG(1) << "max_num_reorder_frames: " << max_num_reorder_frames_;
+
+ *need_new_buffers = true;
+ return true;
+}
+
+bool H264Decoder::ProcessPPS(int pps_id) {
+ const media::H264PPS* pps = parser_.GetPPS(pps_id);
+ DCHECK(pps);
+
+ curr_pps_id_ = pps->pic_parameter_set_id;
+
+ return true;
+}
+
+bool H264Decoder::FinishPrevFrameIfPresent() {
+ // If we already have a frame waiting to be decoded, decode it and finish.
+ if (curr_pic_ != NULL) {
+ if (!DecodePicture())
+ return false;
+ return FinishPicture();
+ }
+
+ return true;
+}
+
+bool H264Decoder::PreprocessSlice(media::H264SliceHeader* slice_hdr) {
+ prev_frame_num_ = frame_num_;
+ frame_num_ = slice_hdr->frame_num;
+
+ if (prev_frame_num_ > 0 && prev_frame_num_ < frame_num_ - 1) {
+ DVLOG(1) << "Gap in frame_num!";
+ return false;
+ }
+
+ if (slice_hdr->field_pic_flag == 0)
+ max_pic_num_ = max_frame_num_;
+ else
+ max_pic_num_ = 2 * max_frame_num_;
+
+ // TODO posciak: switch to new picture detection per 7.4.1.2.4.
+ if (curr_pic_ != NULL && slice_hdr->first_mb_in_slice != 0) {
+ // More slice data of the current picture.
+ return true;
+ } else {
+ // A new frame, so first finish the previous one before processing it...
+ if (!FinishPrevFrameIfPresent())
+ return false;
+ }
+
+ // If the new frame is an IDR, output what's left to output and clear DPB
+ if (slice_hdr->idr_pic_flag) {
+ // (unless we are explicitly instructed not to do so).
+ if (!slice_hdr->no_output_of_prior_pics_flag) {
+ // Output DPB contents.
+ if (!Flush())
+ return false;
+ }
+ dpb_.Clear();
+ last_output_poc_ = std::numeric_limits<int>::min();
+ }
+
+ return true;
+}
+
+bool H264Decoder::ProcessSlice(media::H264SliceHeader* slice_hdr) {
+ DCHECK(curr_pic_.get());
+ H264Picture::Vector ref_pic_list0, ref_pic_list1;
+
+ if (!ModifyReferencePicLists(slice_hdr, &ref_pic_list0, &ref_pic_list1))
+ return false;
+
+ const media::H264PPS* pps = parser_.GetPPS(slice_hdr->pic_parameter_set_id);
+ DCHECK(pps);
+
+ if (!accelerator_->SubmitSlice(pps, slice_hdr, ref_pic_list0, ref_pic_list1,
+ curr_pic_.get(), slice_hdr->nalu_data,
+ slice_hdr->nalu_size))
+ return false;
+
+ curr_slice_hdr_.reset();
+ return true;
+}
+
+#define SET_ERROR_AND_RETURN() \
+ do { \
+ DVLOG(1) << "Error during decode"; \
+ state_ = kError; \
+ return H264Decoder::kDecodeError; \
+ } while (0)
+
+void H264Decoder::SetStream(const uint8_t* ptr, size_t size) {
+ DCHECK(ptr);
+ DCHECK(size);
+
+ DVLOG(4) << "New input stream at: " << (void*)ptr << " size: " << size;
+ parser_.SetStream(ptr, size);
+}
+
+H264Decoder::DecodeResult H264Decoder::Decode() {
+ DCHECK_NE(state_, kError);
+
+ while (1) {
+ media::H264Parser::Result par_res;
+
+ if (!curr_nalu_) {
+ curr_nalu_.reset(new media::H264NALU());
+ par_res = parser_.AdvanceToNextNALU(curr_nalu_.get());
+ if (par_res == media::H264Parser::kEOStream)
+ return kRanOutOfStreamData;
+ else if (par_res != media::H264Parser::kOk)
+ SET_ERROR_AND_RETURN();
+ }
+
+ DVLOG(4) << "NALU found: " << static_cast<int>(curr_nalu_->nal_unit_type);
+
+ switch (curr_nalu_->nal_unit_type) {
+ case media::H264NALU::kNonIDRSlice:
+ // We can't resume from a non-IDR slice.
+ if (state_ != kDecoding)
+ break;
+ // else fallthrough
+ case media::H264NALU::kIDRSlice: {
+ // TODO(posciak): the IDR may require an SPS that we don't have
+ // available. For now we'd fail if that happens, but ideally we'd like
+ // to keep going until the next SPS in the stream.
+ if (state_ == kNeedStreamMetadata) {
+ // We need an SPS, skip this IDR and keep looking.
+ break;
+ }
+
+ // If after reset, we should be able to recover from an IDR.
+ if (!curr_slice_hdr_) {
+ curr_slice_hdr_.reset(new media::H264SliceHeader());
+ par_res =
+ parser_.ParseSliceHeader(*curr_nalu_, curr_slice_hdr_.get());
+ if (par_res != media::H264Parser::kOk)
+ SET_ERROR_AND_RETURN();
+
+ if (!PreprocessSlice(curr_slice_hdr_.get()))
+ SET_ERROR_AND_RETURN();
+ }
+
+ if (!curr_pic_) {
+ // New picture/finished previous one, try to start a new one
+ // or tell the client we need more surfaces.
+ curr_pic_ = accelerator_->CreateH264Picture();
+ if (!curr_pic_)
+ return kRanOutOfSurfaces;
+
+ if (!StartNewFrame(curr_slice_hdr_.get()))
+ SET_ERROR_AND_RETURN();
+ }
+
+ if (!ProcessSlice(curr_slice_hdr_.get()))
+ SET_ERROR_AND_RETURN();
+
+ state_ = kDecoding;
+ break;
+ }
+
+ case media::H264NALU::kSPS: {
+ int sps_id;
+
+ if (!FinishPrevFrameIfPresent())
+ SET_ERROR_AND_RETURN();
+
+ par_res = parser_.ParseSPS(&sps_id);
+ if (par_res != media::H264Parser::kOk)
+ SET_ERROR_AND_RETURN();
+
+ bool need_new_buffers = false;
+ if (!ProcessSPS(sps_id, &need_new_buffers))
+ SET_ERROR_AND_RETURN();
+
+ state_ = kDecoding;
+
+ if (need_new_buffers) {
+ if (!Flush())
+ return kDecodeError;
+
+ curr_pic_ = nullptr;
+ curr_nalu_ = nullptr;
+ ref_pic_list_p0_.clear();
+ ref_pic_list_b0_.clear();
+ ref_pic_list_b1_.clear();
+
+ return kAllocateNewSurfaces;
+ }
+ break;
+ }
+
+ case media::H264NALU::kPPS: {
+ if (state_ != kDecoding)
+ break;
+
+ int pps_id;
+
+ if (!FinishPrevFrameIfPresent())
+ SET_ERROR_AND_RETURN();
+
+ par_res = parser_.ParsePPS(&pps_id);
+ if (par_res != media::H264Parser::kOk)
+ SET_ERROR_AND_RETURN();
+
+ if (!ProcessPPS(pps_id))
+ SET_ERROR_AND_RETURN();
+ break;
+ }
+
+ default:
+ DVLOG(4) << "Skipping NALU type: " << curr_nalu_->nal_unit_type;
+ break;
+ }
+
+ DVLOG(4) << "Dropping nalu";
+ curr_nalu_.reset();
+ }
+}
+
+gfx::Size H264Decoder::GetPicSize() const {
+ return pic_size_;
+}
+
+size_t H264Decoder::GetRequiredNumOfPictures() const {
+ return dpb_.max_num_pics() + kPicsInPipeline;
+}
+
+} // namespace content
diff --git a/chromium/content/common/gpu/media/h264_decoder.h b/chromium/content/common/gpu/media/h264_decoder.h
new file mode 100644
index 00000000000..a82a6aa86a7
--- /dev/null
+++ b/chromium/content/common/gpu/media/h264_decoder.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_COMMON_GPU_MEDIA_H264_DECODER_H_
+#define CONTENT_COMMON_GPU_MEDIA_H264_DECODER_H_
+
+#include <vector>
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/common/content_export.h"
+#include "content/common/gpu/media/accelerated_video_decoder.h"
+#include "content/common/gpu/media/h264_dpb.h"
+#include "media/base/limits.h"
+#include "media/filters/h264_parser.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace content {
+
+// Clients of this class are expected to pass H264 Annex-B byte stream
+// and are expected to provide an implementation of H264Accelerator for
+// offloading final steps of the decoding process.
+//
+// This class must be created, called and destroyed on a single thread, and
+// does nothing internally on any other thread.
+class CONTENT_EXPORT H264Decoder : public AcceleratedVideoDecoder {
+ public:
+ class CONTENT_EXPORT H264Accelerator {
+ public:
+ H264Accelerator();
+ virtual ~H264Accelerator();
+
+ // Create a new H264Picture that the decoder client can use for decoding
+ // and pass back to this accelerator for decoding or reference.
+ // When the picture is no longer needed by decoder, it will just drop
+ // its reference to it, and it may do so at any time.
+ // Note that this may return nullptr if accelerator is not able to provide
+ // any new pictures at given time. The decoder is expected to handle
+ // this situation as normal and return from Decode() with kRanOutOfSurfaces.
+ virtual scoped_refptr<H264Picture> CreateH264Picture() = 0;
+
+ // Submit metadata for the current frame, providing the current |sps| and
+ // |pps| for it, |dpb| has to contain all the pictures in DPB for current
+ // frame, and |ref_pic_p0/b0/b1| as specified in the H264 spec. Note that
+ // depending on the frame type, either p0, or b0 and b1 are used. |pic|
+ // contains information about the picture for the current frame.
+ // Note that this does not run decode in the accelerator and the decoder
+ // is expected to follow this call with one or more SubmitSlice() calls
+ // before calling SubmitDecode().
+ // Return true if successful.
+ virtual bool SubmitFrameMetadata(const media::H264SPS* sps,
+ const media::H264PPS* pps,
+ const H264DPB& dpb,
+ const H264Picture::Vector& ref_pic_listp0,
+ const H264Picture::Vector& ref_pic_listb0,
+ const H264Picture::Vector& ref_pic_listb1,
+ const scoped_refptr<H264Picture>& pic) = 0;
+
+ // Submit one slice for the current frame, passing the current |pps| and
+ // |pic| (same as in SubmitFrameMetadata()), the parsed header for the
+ // current slice in |slice_hdr|, and the reordered |ref_pic_listX|,
+ // as per H264 spec.
+ // |data| pointing to the full slice (including the unparsed header| of
+ // |size| in bytes.
+ // This must be called one or more times per frame, before SubmitDecode().
+ // Note that |data| does not have to remain valid after this call returns.
+ // Return true if successful.
+ virtual bool SubmitSlice(const media::H264PPS* pps,
+ const media::H264SliceHeader* slice_hdr,
+ const H264Picture::Vector& ref_pic_list0,
+ const H264Picture::Vector& ref_pic_list1,
+ const scoped_refptr<H264Picture>& pic,
+ const uint8_t* data,
+ size_t size) = 0;
+
+ // Execute the decode in hardware for |pic|, using all the slices and
+ // metadata submitted via SubmitFrameMetadata() and SubmitSlice() since
+ // the previous call to SubmitDecode().
+ // Return true if successful.
+ virtual bool SubmitDecode(const scoped_refptr<H264Picture>& pic) = 0;
+
+ // Schedule output (display) of |pic|. Note that returning from this
+ // method does not mean that |pic| has already been outputted (displayed),
+ // but guarantees that all pictures will be outputted in the same order
+ // as this method was called for them. Decoder may drop its reference
+ // to |pic| after calling this method.
+ // Return true if successful.
+ virtual bool OutputPicture(const scoped_refptr<H264Picture>& pic) = 0;
+
+ // Reset any current state that may be cached in the accelerator, dropping
+ // any cached parameters/slices that have not been committed yet.
+ virtual void Reset() = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(H264Accelerator);
+ };
+
+ H264Decoder(H264Accelerator* accelerator);
+ ~H264Decoder() override;
+
+ // content::AcceleratedVideoDecoder implementation.
+ bool Flush() override WARN_UNUSED_RESULT;
+ void Reset() override;
+ void SetStream(const uint8_t* ptr, size_t size) override;
+ DecodeResult Decode() override WARN_UNUSED_RESULT;
+ gfx::Size GetPicSize() const override;
+ size_t GetRequiredNumOfPictures() const override;
+
+ private:
+ // We need to keep at most kDPBMaxSize pictures in DPB for
+ // reference/to display later and an additional one for the one currently
+ // being decoded. We also ask for some additional ones since VDA needs
+ // to accumulate a few ready-to-output pictures before it actually starts
+ // displaying and giving them back. +2 instead of +1 because of subjective
+ // smoothness improvement during testing.
+ enum {
+ kPicsInPipeline = media::limits::kMaxVideoFrames + 2,
+ kMaxNumReqPictures = H264DPB::kDPBMaxSize + kPicsInPipeline,
+ };
+
+ // Internal state of the decoder.
+ enum State {
+ kNeedStreamMetadata, // After initialization, need an SPS.
+ kDecoding, // Ready to decode from any point.
+ kAfterReset, // After Reset(), need a resume point.
+ kError, // Error in decode, can't continue.
+ };
+
+ // Process H264 stream structures.
+ bool ProcessSPS(int sps_id, bool* need_new_buffers);
+ bool ProcessPPS(int pps_id);
+ bool PreprocessSlice(media::H264SliceHeader* slice_hdr);
+ bool ProcessSlice(media::H264SliceHeader* slice_hdr);
+
+ // Initialize the current picture according to data in |slice_hdr|.
+ bool InitCurrPicture(media::H264SliceHeader* slice_hdr);
+
+ // Calculate picture order counts for the new picture
+ // on initialization of a new frame (see spec).
+ bool CalculatePicOrderCounts(media::H264SliceHeader* slice_hdr);
+
+ // Update PicNum values in pictures stored in DPB on creation of new
+ // frame (see spec).
+ void UpdatePicNums();
+
+ bool UpdateMaxNumReorderFrames(const media::H264SPS* sps);
+
+ // Prepare reference picture lists for the current frame.
+ void PrepareRefPicLists(media::H264SliceHeader* slice_hdr);
+ // Prepare reference picture lists for the given slice.
+ bool ModifyReferencePicLists(media::H264SliceHeader* slice_hdr,
+ H264Picture::Vector* ref_pic_list0,
+ H264Picture::Vector* ref_pic_list1);
+
+ // Construct initial reference picture lists for use in decoding of
+ // P and B pictures (see 8.2.4 in spec).
+ void ConstructReferencePicListsP(media::H264SliceHeader* slice_hdr);
+ void ConstructReferencePicListsB(media::H264SliceHeader* slice_hdr);
+
+ // Helper functions for reference list construction, per spec.
+ int PicNumF(const scoped_refptr<H264Picture>& pic);
+ int LongTermPicNumF(const scoped_refptr<H264Picture>& pic);
+
+ // Perform the reference picture lists' modification (reordering), as
+ // specified in spec (8.2.4).
+ //
+ // |list| indicates list number and should be either 0 or 1.
+ bool ModifyReferencePicList(media::H264SliceHeader* slice_hdr,
+ int list,
+ H264Picture::Vector* ref_pic_listx);
+
+ // Perform reference picture memory management operations (marking/unmarking
+ // of reference pictures, long term picture management, discarding, etc.).
+ // See 8.2.5 in spec.
+ bool HandleMemoryManagementOps();
+ void ReferencePictureMarking();
+
+ // Start processing a new frame.
+ bool StartNewFrame(media::H264SliceHeader* slice_hdr);
+
+ // All data for a frame received, process it and decode.
+ bool FinishPrevFrameIfPresent();
+
+ // Called after decoding, performs all operations to be done after decoding,
+ // including DPB management, reference picture marking and memory management
+ // operations.
+ // This will also output a picture if one is ready for output.
+ bool FinishPicture();
+
+ // Clear DPB contents and remove all surfaces in DPB from *in_use_ list.
+ // Cleared pictures will be made available for decode, unless they are
+ // at client waiting to be displayed.
+ void ClearDPB();
+
+ // Commits all pending data for HW decoder and starts HW decoder.
+ bool DecodePicture();
+
+ // Notifies client that a picture is ready for output.
+ void OutputPic(scoped_refptr<H264Picture> pic);
+
+ // Output all pictures in DPB that have not been outputted yet.
+ bool OutputAllRemainingPics();
+
+ // Decoder state.
+ State state_;
+
+ // Parser in use.
+ media::H264Parser parser_;
+
+ // DPB in use.
+ H264DPB dpb_;
+
+ // Picture currently being processed/decoded.
+ scoped_refptr<H264Picture> curr_pic_;
+
+ // Reference picture lists, constructed for each frame.
+ H264Picture::Vector ref_pic_list_p0_;
+ H264Picture::Vector ref_pic_list_b0_;
+ H264Picture::Vector ref_pic_list_b1_;
+
+ // Global state values, needed in decoding. See spec.
+ int max_pic_order_cnt_lsb_;
+ int max_frame_num_;
+ int max_pic_num_;
+ int max_long_term_frame_idx_;
+ size_t max_num_reorder_frames_;
+
+ int frame_num_;
+ int prev_frame_num_;
+ int prev_frame_num_offset_;
+ bool prev_has_memmgmnt5_;
+
+ // Values related to previously decoded reference picture.
+ bool prev_ref_has_memmgmnt5_;
+ int prev_ref_top_field_order_cnt_;
+ int prev_ref_pic_order_cnt_msb_;
+ int prev_ref_pic_order_cnt_lsb_;
+ H264Picture::Field prev_ref_field_;
+
+ // Currently active SPS and PPS.
+ int curr_sps_id_;
+ int curr_pps_id_;
+
+ // Current NALU and slice header being processed.
+ scoped_ptr<media::H264NALU> curr_nalu_;
+ scoped_ptr<media::H264SliceHeader> curr_slice_hdr_;
+
+ // Output picture size.
+ gfx::Size pic_size_;
+
+ // PicOrderCount of the previously outputted frame.
+ int last_output_poc_;
+
+ H264Accelerator* accelerator_;
+
+ DISALLOW_COPY_AND_ASSIGN(H264Decoder);
+};
+
+} // namespace content
+
+#endif // CONTENT_COMMON_GPU_MEDIA_H264_DECODER_H_
diff --git a/chromium/content/common/gpu/media/h264_dpb.cc b/chromium/content/common/gpu/media/h264_dpb.cc
index 371d6128313..1220d591fc5 100644
--- a/chromium/content/common/gpu/media/h264_dpb.cc
+++ b/chromium/content/common/gpu/media/h264_dpb.cc
@@ -10,6 +10,42 @@
namespace content {
+H264Picture::H264Picture()
+ : top_field_order_cnt(0),
+ bottom_field_order_cnt(0),
+ pic_order_cnt(0),
+ pic_order_cnt_msb(0),
+ pic_order_cnt_lsb(0),
+ pic_num(0),
+ long_term_pic_num(0),
+ frame_num(0),
+ frame_num_offset(0),
+ frame_num_wrap(0),
+ long_term_frame_idx(0),
+ type(media::H264SliceHeader::kPSlice),
+ idr(false),
+ ref(false),
+ long_term(false),
+ outputted(false),
+ mem_mgmt_5(false),
+ field(FIELD_NONE),
+ long_term_reference_flag(false),
+ adaptive_ref_pic_marking_mode_flag(false),
+ dpb_position(0) {
+ memset(&ref_pic_marking, 0, sizeof(ref_pic_marking));
+}
+
+H264Picture::~H264Picture() {
+}
+
+V4L2H264Picture* H264Picture::AsV4L2H264Picture() {
+ return nullptr;
+}
+
+VaapiH264Picture* H264Picture::AsVaapiH264Picture() {
+ return nullptr;
+}
+
H264DPB::H264DPB() : max_num_pics_(0) {}
H264DPB::~H264DPB() {}
@@ -24,10 +60,20 @@ void H264DPB::set_max_num_pics(size_t max_num_pics) {
pics_.resize(max_num_pics_);
}
+void H264DPB::UpdatePicPositions() {
+ size_t i = 0;
+ for (auto& pic : pics_) {
+ pic->dpb_position = i;
+ ++i;
+ }
+}
+
void H264DPB::DeleteByPOC(int poc) {
- for (Pictures::iterator it = pics_.begin(); it != pics_.end(); ++it) {
+ for (H264Picture::Vector::iterator it = pics_.begin();
+ it != pics_.end(); ++it) {
if ((*it)->pic_order_cnt == poc) {
pics_.erase(it);
+ UpdatePicPositions();
return;
}
}
@@ -35,18 +81,20 @@ void H264DPB::DeleteByPOC(int poc) {
}
void H264DPB::DeleteUnused() {
- for (Pictures::iterator it = pics_.begin(); it != pics_.end(); ) {
+ for (H264Picture::Vector::iterator it = pics_.begin(); it != pics_.end(); ) {
if ((*it)->outputted && !(*it)->ref)
it = pics_.erase(it);
else
++it;
}
+ UpdatePicPositions();
}
-void H264DPB::StorePic(H264Picture* pic) {
+void H264DPB::StorePic(const scoped_refptr<H264Picture>& pic) {
DCHECK_LT(pics_.size(), max_num_pics_);
DVLOG(3) << "Adding PicNum: " << pic->pic_num << " ref: " << (int)pic->ref
<< " longterm: " << (int)pic->long_term << " to DPB";
+ pic->dpb_position = pics_.size();
pics_.push_back(pic);
}
@@ -64,32 +112,29 @@ void H264DPB::MarkAllUnusedForRef() {
pics_[i]->ref = false;
}
-H264Picture* H264DPB::GetShortRefPicByPicNum(int pic_num) {
- for (size_t i = 0; i < pics_.size(); ++i) {
- H264Picture* pic = pics_[i];
+scoped_refptr<H264Picture> H264DPB::GetShortRefPicByPicNum(int pic_num) {
+ for (const auto& pic : pics_) {
if (pic->ref && !pic->long_term && pic->pic_num == pic_num)
return pic;
}
DVLOG(1) << "Missing short ref pic num: " << pic_num;
- return NULL;
+ return nullptr;
}
-H264Picture* H264DPB::GetLongRefPicByLongTermPicNum(int pic_num) {
- for (size_t i = 0; i < pics_.size(); ++i) {
- H264Picture* pic = pics_[i];
+scoped_refptr<H264Picture> H264DPB::GetLongRefPicByLongTermPicNum(int pic_num) {
+ for (const auto& pic : pics_) {
if (pic->ref && pic->long_term && pic->long_term_pic_num == pic_num)
return pic;
}
DVLOG(1) << "Missing long term pic num: " << pic_num;
- return NULL;
+ return nullptr;
}
-H264Picture* H264DPB::GetLowestFrameNumWrapShortRefPic() {
- H264Picture* ret = NULL;
- for (size_t i = 0; i < pics_.size(); ++i) {
- H264Picture* pic = pics_[i];
+scoped_refptr<H264Picture> H264DPB::GetLowestFrameNumWrapShortRefPic() {
+ scoped_refptr<H264Picture> ret;
+ for (const auto& pic : pics_) {
if (pic->ref && !pic->long_term &&
(!ret || pic->frame_num_wrap < ret->frame_num_wrap))
ret = pic;
@@ -97,27 +142,24 @@ H264Picture* H264DPB::GetLowestFrameNumWrapShortRefPic() {
return ret;
}
-void H264DPB::GetNotOutputtedPicsAppending(H264Picture::PtrVector& out) {
- for (size_t i = 0; i < pics_.size(); ++i) {
- H264Picture* pic = pics_[i];
+void H264DPB::GetNotOutputtedPicsAppending(H264Picture::Vector* out) {
+ for (const auto& pic : pics_) {
if (!pic->outputted)
- out.push_back(pic);
+ out->push_back(pic);
}
}
-void H264DPB::GetShortTermRefPicsAppending(H264Picture::PtrVector& out) {
- for (size_t i = 0; i < pics_.size(); ++i) {
- H264Picture* pic = pics_[i];
+void H264DPB::GetShortTermRefPicsAppending(H264Picture::Vector* out) {
+ for (const auto& pic : pics_) {
if (pic->ref && !pic->long_term)
- out.push_back(pic);
+ out->push_back(pic);
}
}
-void H264DPB::GetLongTermRefPicsAppending(H264Picture::PtrVector& out) {
- for (size_t i = 0; i < pics_.size(); ++i) {
- H264Picture* pic = pics_[i];
+void H264DPB::GetLongTermRefPicsAppending(H264Picture::Vector* out) {
+ for (const auto& pic : pics_) {
if (pic->ref && pic->long_term)
- out.push_back(pic);
+ out->push_back(pic);
}
}
diff --git a/chromium/content/common/gpu/media/h264_dpb.h b/chromium/content/common/gpu/media/h264_dpb.h
index 366c47a78cd..67330d944c7 100644
--- a/chromium/content/common/gpu/media/h264_dpb.h
+++ b/chromium/content/common/gpu/media/h264_dpb.h
@@ -11,20 +11,31 @@
#include <vector>
#include "base/basictypes.h"
-#include "base/memory/scoped_vector.h"
+#include "base/memory/ref_counted.h"
#include "media/filters/h264_parser.h"
namespace content {
+class V4L2H264Picture;
+class VaapiH264Picture;
+
// A picture (a frame or a field) in the H.264 spec sense.
// See spec at http://www.itu.int/rec/T-REC-H.264
-struct H264Picture {
+class H264Picture : public base::RefCounted<H264Picture> {
+ public:
+ using Vector = std::vector<scoped_refptr<H264Picture>>;
+
enum Field {
FIELD_NONE,
FIELD_TOP,
FIELD_BOTTOM,
};
+ H264Picture();
+
+ virtual V4L2H264Picture* AsV4L2H264Picture();
+ virtual VaapiH264Picture* AsVaapiH264Picture();
+
// Values calculated per H.264 specification or taken from slice header.
// See spec for more details on each (some names have been converted from
// CamelCase in spec to Chromium-style names).
@@ -59,7 +70,15 @@ struct H264Picture {
media::H264DecRefPicMarking
ref_pic_marking[media::H264SliceHeader::kRefListSize];
- typedef std::vector<H264Picture*> PtrVector;
+ // Position in DPB (i.e. index in DPB).
+ int dpb_position;
+
+ protected:
+ friend class base::RefCounted<H264Picture>;
+ virtual ~H264Picture();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(H264Picture);
};
// DPB - Decoded Picture Buffer.
@@ -71,7 +90,7 @@ class H264DPB {
~H264DPB();
void set_max_num_pics(size_t max_num_pics);
- size_t max_num_pics() { return max_num_pics_; }
+ size_t max_num_pics() const { return max_num_pics_; }
// Remove unused (not reference and already outputted) pictures from DPB
// and free it.
@@ -84,7 +103,7 @@ class H264DPB {
void Clear();
// Store picture in DPB. DPB takes ownership of its resources.
- void StorePic(H264Picture* pic);
+ void StorePic(const scoped_refptr<H264Picture>& pic);
// Return the number of reference pictures in DPB.
int CountRefPics();
@@ -93,32 +112,37 @@ class H264DPB {
void MarkAllUnusedForRef();
// Return a short-term reference picture by its pic_num.
- H264Picture* GetShortRefPicByPicNum(int pic_num);
+ scoped_refptr<H264Picture> GetShortRefPicByPicNum(int pic_num);
// Return a long-term reference picture by its long_term_pic_num.
- H264Picture* GetLongRefPicByLongTermPicNum(int pic_num);
+ scoped_refptr<H264Picture> GetLongRefPicByLongTermPicNum(int pic_num);
// Return the short reference picture with lowest frame_num. Used for sliding
// window memory management.
- H264Picture* GetLowestFrameNumWrapShortRefPic();
+ scoped_refptr<H264Picture> GetLowestFrameNumWrapShortRefPic();
// Append all pictures that have not been outputted yet to the passed |out|
// vector, sorted by lowest pic_order_cnt (in output order).
- void GetNotOutputtedPicsAppending(H264Picture::PtrVector& out);
+ void GetNotOutputtedPicsAppending(H264Picture::Vector* out);
// Append all short term reference pictures to the passed |out| vector.
- void GetShortTermRefPicsAppending(H264Picture::PtrVector& out);
+ void GetShortTermRefPicsAppending(H264Picture::Vector* out);
// Append all long term reference pictures to the passed |out| vector.
- void GetLongTermRefPicsAppending(H264Picture::PtrVector& out);
+ void GetLongTermRefPicsAppending(H264Picture::Vector* out);
// Iterators for direct access to DPB contents.
// Will be invalidated after any of Remove* calls.
- typedef ScopedVector<H264Picture> Pictures;
- Pictures::iterator begin() { return pics_.begin(); }
- Pictures::iterator end() { return pics_.end(); }
- Pictures::reverse_iterator rbegin() { return pics_.rbegin(); }
- Pictures::reverse_iterator rend() { return pics_.rend(); }
+ H264Picture::Vector::iterator begin() { return pics_.begin(); }
+ H264Picture::Vector::iterator end() { return pics_.end(); }
+ H264Picture::Vector::const_iterator begin() const { return pics_.begin(); }
+ H264Picture::Vector::const_iterator end() const { return pics_.end(); }
+ H264Picture::Vector::const_reverse_iterator rbegin() const {
+ return pics_.rbegin();
+ }
+ H264Picture::Vector::const_reverse_iterator rend() const {
+ return pics_.rend();
+ }
size_t size() const { return pics_.size(); }
bool IsFull() const { return pics_.size() == max_num_pics_; }
@@ -127,7 +151,9 @@ class H264DPB {
enum { kDPBMaxSize = 16, };
private:
- Pictures pics_;
+ void UpdatePicPositions();
+
+ H264Picture::Vector pics_;
size_t max_num_pics_;
DISALLOW_COPY_AND_ASSIGN(H264DPB);
diff --git a/chromium/content/common/gpu/media/rendering_helper.cc b/chromium/content/common/gpu/media/rendering_helper.cc
index 5870ceef564..f428ed66e7d 100644
--- a/chromium/content/common/gpu/media/rendering_helper.cc
+++ b/chromium/content/common/gpu/media/rendering_helper.cc
@@ -13,14 +13,13 @@
#include "base/command_line.h"
#include "base/mac/scoped_nsautorelease_pool.h"
#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
#include "base/strings/stringize_macros.h"
#include "base/synchronization/waitable_event.h"
#include "base/time/time.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_surface.h"
-#include "ui/gl/gl_surface_egl.h"
-#include "ui/gl/gl_surface_glx.h"
#if defined(OS_WIN)
#include <windows.h>
@@ -30,12 +29,24 @@
#include "ui/gfx/x/x11_types.h"
#endif
-#if !defined(OS_WIN) && defined(ARCH_CPU_X86_FAMILY)
+#if defined(ARCH_CPU_X86_FAMILY) && defined(USE_X11)
+#include "ui/gl/gl_surface_glx.h"
#define GL_VARIANT_GLX 1
#else
+#include "ui/gl/gl_surface_egl.h"
#define GL_VARIANT_EGL 1
#endif
+#if defined(USE_OZONE)
+#if defined(OS_CHROMEOS)
+#include "ui/display/chromeos/display_configurator.h"
+#include "ui/display/types/native_display_delegate.h"
+#endif // defined(OS_CHROMEOS)
+#include "ui/ozone/public/ozone_platform.h"
+#include "ui/platform_window/platform_window.h"
+#include "ui/platform_window/platform_window_delegate.h"
+#endif // defined(USE_OZONE)
+
// Helper for Shader creation.
static void CreateShader(GLuint program,
GLenum type,
@@ -58,6 +69,77 @@ static void CreateShader(GLuint program,
namespace content {
+#if defined(USE_OZONE)
+
+class DisplayConfiguratorObserver : public ui::DisplayConfigurator::Observer {
+ public:
+ DisplayConfiguratorObserver(base::RunLoop* loop) : loop_(loop) {}
+ ~DisplayConfiguratorObserver() override {}
+
+ private:
+ // ui::DisplayConfigurator::Observer overrides:
+ void OnDisplayModeChanged(
+ const ui::DisplayConfigurator::DisplayStateList& outputs) override {
+ if (!loop_)
+ return;
+ loop_->Quit();
+ loop_ = nullptr;
+ }
+ void OnDisplayModeChangeFailed(
+ const ui::DisplayConfigurator::DisplayStateList& outputs,
+ ui::MultipleDisplayState failed_new_state) override {
+ LOG(FATAL) << "Could not configure display";
+ }
+
+ base::RunLoop* loop_;
+
+ DISALLOW_COPY_AND_ASSIGN(DisplayConfiguratorObserver);
+};
+
+class RenderingHelper::StubOzoneDelegate : public ui::PlatformWindowDelegate {
+ public:
+ StubOzoneDelegate() : accelerated_widget_(gfx::kNullAcceleratedWidget) {
+ platform_window_ = ui::OzonePlatform::GetInstance()->CreatePlatformWindow(
+ this, gfx::Rect());
+ }
+ ~StubOzoneDelegate() override {}
+
+ void OnBoundsChanged(const gfx::Rect& new_bounds) override {}
+
+ void OnDamageRect(const gfx::Rect& damaged_region) override {}
+
+ void DispatchEvent(ui::Event* event) override {}
+
+ void OnCloseRequest() override {}
+ void OnClosed() override {}
+
+ void OnWindowStateChanged(ui::PlatformWindowState new_state) override {}
+
+ void OnLostCapture() override {};
+
+ void OnAcceleratedWidgetAvailable(gfx::AcceleratedWidget widget) override {
+ accelerated_widget_ = widget;
+ };
+
+ void OnActivationChanged(bool active) override {};
+
+ gfx::AcceleratedWidget accelerated_widget() const {
+ return accelerated_widget_;
+ }
+
+ gfx::Size GetSize() { return platform_window_->GetBounds().size(); }
+
+ ui::PlatformWindow* platform_window() const { return platform_window_.get(); }
+
+ private:
+ scoped_ptr<ui::PlatformWindow> platform_window_;
+ gfx::AcceleratedWidget accelerated_widget_;
+
+ DISALLOW_COPY_AND_ASSIGN(StubOzoneDelegate);
+};
+
+#endif // defined(USE_OZONE)
+
RenderingHelperParams::RenderingHelperParams()
: rendering_fps(0), warm_up_iterations(0), render_as_thumbnails(false) {
}
@@ -85,7 +167,7 @@ RenderingHelper::RenderedVideo::~RenderedVideo() {
}
// static
-bool RenderingHelper::InitializeOneOff() {
+void RenderingHelper::InitializeOneOff(base::WaitableEvent* done) {
base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
#if GL_VARIANT_GLX
cmd_line->AppendSwitchASCII(switches::kUseGL,
@@ -93,10 +175,13 @@ bool RenderingHelper::InitializeOneOff() {
#else
cmd_line->AppendSwitchASCII(switches::kUseGL, gfx::kGLImplementationEGLName);
#endif
- return gfx::GLSurface::InitializeOneOff();
+
+ if (!gfx::GLSurface::InitializeOneOff())
+ LOG(FATAL) << "Could not initialize GL";
+ done->Signal();
}
-RenderingHelper::RenderingHelper() {
+RenderingHelper::RenderingHelper() : ignore_vsync_(false) {
window_ = gfx::kNullAcceleratedWidget;
Clear();
}
@@ -106,37 +191,16 @@ RenderingHelper::~RenderingHelper() {
Clear();
}
-void RenderingHelper::Initialize(const RenderingHelperParams& params,
- base::WaitableEvent* done) {
- // Use videos_.size() != 0 as a proxy for the class having already been
- // Initialize()'d, and UnInitialize() before continuing.
- if (videos_.size()) {
- base::WaitableEvent done(false, false);
- UnInitialize(&done);
- done.Wait();
- }
-
- render_task_.Reset(
- base::Bind(&RenderingHelper::RenderContent, base::Unretained(this)));
-
- frame_duration_ = params.rendering_fps > 0
- ? base::TimeDelta::FromSeconds(1) / params.rendering_fps
- : base::TimeDelta();
-
- render_as_thumbnails_ = params.render_as_thumbnails;
- message_loop_ = base::MessageLoop::current();
-
+void RenderingHelper::Setup() {
#if defined(OS_WIN)
- screen_size_ =
- gfx::Size(GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
window_ = CreateWindowEx(0,
L"Static",
L"VideoDecodeAcceleratorTest",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
0,
0,
- screen_size_.width(),
- screen_size_.height(),
+ GetSystemMetrics(SM_CXSCREEN),
+ GetSystemMetrics(SM_CYSCREEN),
NULL,
NULL,
NULL,
@@ -144,7 +208,6 @@ void RenderingHelper::Initialize(const RenderingHelperParams& params,
#elif defined(USE_X11)
Display* display = gfx::GetXDisplay();
Screen* screen = DefaultScreenOfDisplay(display);
- screen_size_ = gfx::Size(XWidthOfScreen(screen), XHeightOfScreen(screen));
CHECK(display);
@@ -159,8 +222,8 @@ void RenderingHelper::Initialize(const RenderingHelperParams& params,
DefaultRootWindow(display),
0,
0,
- screen_size_.width(),
- screen_size_.height(),
+ XWidthOfScreen(screen),
+ XHeightOfScreen(screen),
0 /* border width */,
depth,
CopyFromParent /* class */,
@@ -170,15 +233,107 @@ void RenderingHelper::Initialize(const RenderingHelperParams& params,
XStoreName(display, window_, "VideoDecodeAcceleratorTest");
XSelectInput(display, window_, ExposureMask);
XMapWindow(display, window_);
+#elif defined(USE_OZONE)
+ base::MessageLoop::ScopedNestableTaskAllower nest_loop(
+ base::MessageLoop::current());
+ base::RunLoop wait_window_resize;
+
+ platform_window_delegate_.reset(new RenderingHelper::StubOzoneDelegate());
+ window_ = platform_window_delegate_->accelerated_widget();
+ gfx::Size window_size(800, 600);
+ // Ignore the vsync provider by default. On ChromeOS this will be set
+ // accordingly based on the display configuration.
+ ignore_vsync_ = true;
+#if defined(OS_CHROMEOS)
+ // We hold onto the main loop here to wait for the DisplayController
+ // to give us the size of the display so we can create a window of
+ // the same size.
+ base::RunLoop wait_display_setup;
+ DisplayConfiguratorObserver display_setup_observer(&wait_display_setup);
+ display_configurator_.reset(new ui::DisplayConfigurator());
+ display_configurator_->SetDelegateForTesting(0);
+ display_configurator_->AddObserver(&display_setup_observer);
+ display_configurator_->Init(true);
+ display_configurator_->ForceInitialConfigure(0);
+ // Make sure all the display configuration is applied.
+ wait_display_setup.Run();
+ display_configurator_->RemoveObserver(&display_setup_observer);
+
+ gfx::Size framebuffer_size = display_configurator_->framebuffer_size();
+ if (!framebuffer_size.IsEmpty()) {
+ window_size = framebuffer_size;
+ ignore_vsync_ = false;
+ }
+#endif
+ if (ignore_vsync_)
+ DVLOG(1) << "Ignoring vsync provider";
+
+ platform_window_delegate_->platform_window()->SetBounds(
+ gfx::Rect(window_size));
+
+ // On Ozone/DRI, platform windows are associated with the physical
+ // outputs. Association is achieved by matching the bounds of the
+ // window with the origin & modeset of the display output. Until a
+ // window is associated with a display output, we cannot get vsync
+ // events, because there is no hardware to get events from. Here we
+ // wait for the window to resized and therefore associated with
+ // display output to be sure that we will get such events.
+ wait_window_resize.RunUntilIdle();
#else
#error unknown platform
#endif
CHECK(window_ != gfx::kNullAcceleratedWidget);
+}
+
+void RenderingHelper::TearDown() {
+#if defined(OS_WIN)
+ if (window_)
+ DestroyWindow(window_);
+#elif defined(USE_X11)
+ // Destroy resources acquired in Initialize, in reverse-acquisition order.
+ if (window_) {
+ CHECK(XUnmapWindow(gfx::GetXDisplay(), window_));
+ CHECK(XDestroyWindow(gfx::GetXDisplay(), window_));
+ }
+#elif defined(USE_OZONE)
+ platform_window_delegate_.reset();
+#if defined(OS_CHROMEOS)
+ display_configurator_->PrepareForExit();
+ display_configurator_.reset();
+#endif
+#endif
+ window_ = gfx::kNullAcceleratedWidget;
+}
+
+void RenderingHelper::Initialize(const RenderingHelperParams& params,
+ base::WaitableEvent* done) {
+ // Use videos_.size() != 0 as a proxy for the class having already been
+ // Initialize()'d, and UnInitialize() before continuing.
+ if (videos_.size()) {
+ base::WaitableEvent done(false, false);
+ UnInitialize(&done);
+ done.Wait();
+ }
+
+ render_task_.Reset(
+ base::Bind(&RenderingHelper::RenderContent, base::Unretained(this)));
+
+ frame_duration_ = params.rendering_fps > 0
+ ? base::TimeDelta::FromSeconds(1) / params.rendering_fps
+ : base::TimeDelta();
+
+ render_as_thumbnails_ = params.render_as_thumbnails;
+ message_loop_ = base::MessageLoop::current();
gl_surface_ = gfx::GLSurface::CreateViewGLSurface(window_);
+#if defined(USE_OZONE)
+ gl_surface_->Resize(platform_window_delegate_->GetSize());
+#endif // defined(USE_OZONE)
+ screen_size_ = gl_surface_->GetSize();
+
gl_context_ = gfx::GLContext::CreateGLContext(
NULL, gl_surface_.get(), gfx::PreferIntegratedGpu);
- gl_context_->MakeCurrent(gl_surface_.get());
+ CHECK(gl_context_->MakeCurrent(gl_surface_.get()));
CHECK_GT(params.window_sizes.size(), 0U);
videos_.resize(params.window_sizes.size());
@@ -224,7 +379,8 @@ void RenderingHelper::Initialize(const RenderingHelperParams& params,
CHECK(fb_status == GL_FRAMEBUFFER_COMPLETE) << fb_status;
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
- glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
+ glBindFramebufferEXT(GL_FRAMEBUFFER,
+ gl_surface_->GetBackingFrameBufferObject());
}
// These vertices and texture coords. map (0,0) in the texture to the
@@ -304,14 +460,34 @@ void RenderingHelper::Initialize(const RenderingHelperParams& params,
glEnableVertexAttribArray(tc_location);
glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0, kTextureCoords);
- if (frame_duration_ != base::TimeDelta())
- WarmUpRendering(params.warm_up_iterations);
+ if (frame_duration_ != base::TimeDelta()) {
+ int warm_up_iterations = params.warm_up_iterations;
+#if defined(USE_OZONE)
+ // On Ozone the VSyncProvider can't provide a vsync interval until
+ // we render at least a frame, so we warm up with at least one
+ // frame.
+ // On top of this, we want to make sure all the buffers backing
+ // the GL surface are cleared, otherwise we can see the previous
+ // test's last frames, so we set warm up iterations to 2, to clear
+ // the front and back buffers.
+ warm_up_iterations = std::max(2, warm_up_iterations);
+#endif
+ WarmUpRendering(warm_up_iterations);
+ }
// It's safe to use Unretained here since |rendering_thread_| will be stopped
// in VideoDecodeAcceleratorTest.TearDown(), while the |rendering_helper_| is
// a member of that class. (See video_decode_accelerator_unittest.cc.)
- gl_surface_->GetVSyncProvider()->GetVSyncParameters(base::Bind(
- &RenderingHelper::UpdateVSyncParameters, base::Unretained(this), done));
+ gfx::VSyncProvider* vsync_provider = gl_surface_->GetVSyncProvider();
+
+ // VSync providers rely on the underlying CRTC to get the timing. In headless
+ // mode the surface isn't associated with a CRTC so the vsync provider can not
+ // get the timing, meaning it will not call UpdateVsyncParameters() ever.
+ if (!ignore_vsync_ && vsync_provider && frame_duration_ != base::TimeDelta())
+ vsync_provider->GetVSyncParameters(base::Bind(
+ &RenderingHelper::UpdateVSyncParameters, base::Unretained(this), done));
+ else
+ done->Signal();
}
// The rendering for the first few frames is slow (e.g., 100ms on Peach Pit).
@@ -319,7 +495,7 @@ void RenderingHelper::Initialize(const RenderingHelperParams& params,
// several frames here to warm up the rendering.
void RenderingHelper::WarmUpRendering(int warm_up_iterations) {
unsigned int texture_id;
- scoped_ptr<GLubyte[]> emptyData(new GLubyte[screen_size_.GetArea() * 2]);
+ scoped_ptr<GLubyte[]> emptyData(new GLubyte[screen_size_.GetArea() * 2]());
glGenTextures(1, &texture_id);
glBindTexture(GL_TEXTURE_2D, texture_id);
glTexImage2D(GL_TEXTURE_2D,
@@ -348,6 +524,7 @@ void RenderingHelper::UnInitialize(base::WaitableEvent* done) {
glDeleteFramebuffersEXT(1, &thumbnails_fbo_id_);
}
+ gl_surface_->Destroy();
gl_context_->ReleaseCurrent(gl_surface_.get());
gl_context_ = NULL;
gl_surface_ = NULL;
@@ -414,7 +591,8 @@ void RenderingHelper::RenderThumbnail(uint32 texture_target,
glBindFramebufferEXT(GL_FRAMEBUFFER, thumbnails_fbo_id_);
GLSetViewPort(area);
RenderTexture(texture_target, texture_id);
- glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
+ glBindFramebufferEXT(GL_FRAMEBUFFER,
+ gl_surface_->GetBackingFrameBufferObject());
// Need to flush the GL commands before we return the tnumbnail texture to
// the decoder.
@@ -463,7 +641,11 @@ void RenderingHelper::DeleteTexture(uint32 texture_id) {
CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR);
}
-void* RenderingHelper::GetGLContext() {
+scoped_refptr<gfx::GLContext> RenderingHelper::GetGLContext() {
+ return gl_context_;
+}
+
+void* RenderingHelper::GetGLContextHandle() {
return gl_context_->GetHandle();
}
@@ -481,18 +663,6 @@ void RenderingHelper::Clear() {
frame_count_ = 0;
thumbnails_fbo_id_ = 0;
thumbnails_texture_id_ = 0;
-
-#if defined(OS_WIN)
- if (window_)
- DestroyWindow(window_);
-#else
- // Destroy resources acquired in Initialize, in reverse-acquisition order.
- if (window_) {
- CHECK(XUnmapWindow(gfx::GetXDisplay(), window_));
- CHECK(XDestroyWindow(gfx::GetXDisplay(), window_));
- }
-#endif
- window_ = gfx::kNullAcceleratedWidget;
}
void RenderingHelper::GetThumbnailsAsRGB(std::vector<unsigned char>* rgb,
@@ -513,7 +683,8 @@ void RenderingHelper::GetThumbnailsAsRGB(std::vector<unsigned char>* rgb,
GL_RGBA,
GL_UNSIGNED_BYTE,
&rgba[0]);
- glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
+ glBindFramebufferEXT(GL_FRAMEBUFFER,
+ gl_surface_->GetBackingFrameBufferObject());
rgb->resize(num_pixels * 3);
// Drop the alpha channel, but check as we go that it is all 0xff.
bool solid = true;
@@ -543,12 +714,20 @@ void RenderingHelper::RenderContent() {
// It's safe to use Unretained here since |rendering_thread_| will be stopped
// in VideoDecodeAcceleratorTest.TearDown(), while the |rendering_helper_| is
// a member of that class. (See video_decode_accelerator_unittest.cc.)
- gl_surface_->GetVSyncProvider()->GetVSyncParameters(
- base::Bind(&RenderingHelper::UpdateVSyncParameters,
- base::Unretained(this),
- static_cast<base::WaitableEvent*>(NULL)));
+ gfx::VSyncProvider* vsync_provider = gl_surface_->GetVSyncProvider();
+ if (vsync_provider && !ignore_vsync_) {
+ vsync_provider->GetVSyncParameters(base::Bind(
+ &RenderingHelper::UpdateVSyncParameters, base::Unretained(this),
+ static_cast<base::WaitableEvent*>(NULL)));
+ }
- glUniform1i(glGetUniformLocation(program_, "tex_flip"), 1);
+ int tex_flip = 1;
+#if defined(USE_OZONE)
+ // Ozone surfaceless renders flipped from normal GL, so there's no need to
+ // do an extra flip.
+ tex_flip = 0;
+#endif // defined(USE_OZONE)
+ glUniform1i(glGetUniformLocation(program_, "tex_flip"), tex_flip);
// Frames that will be returned to the client (via the no_longer_needed_cb)
// after this vector falls out of scope at the end of this method. We need
@@ -664,15 +843,19 @@ void RenderingHelper::DropOneFrameForAllVideos() {
void RenderingHelper::ScheduleNextRenderContent() {
scheduled_render_time_ += frame_duration_;
-
- // Schedules the next RenderContent() at latest VSYNC before the
- // |scheduled_render_time_|.
base::TimeTicks now = base::TimeTicks::Now();
- base::TimeTicks target =
- std::max(now + vsync_interval_, scheduled_render_time_);
+ base::TimeTicks target;
- int64 intervals = (target - vsync_timebase_) / vsync_interval_;
- target = vsync_timebase_ + intervals * vsync_interval_;
+ if (vsync_interval_ != base::TimeDelta()) {
+ // Schedules the next RenderContent() at latest VSYNC before the
+ // |scheduled_render_time_|.
+ target = std::max(now + vsync_interval_, scheduled_render_time_);
+
+ int64 intervals = (target - vsync_timebase_) / vsync_interval_;
+ target = vsync_timebase_ + intervals * vsync_interval_;
+ } else {
+ target = std::max(now, scheduled_render_time_);
+ }
// When the rendering falls behind, drops frames.
while (scheduled_render_time_ < target) {
diff --git a/chromium/content/common/gpu/media/rendering_helper.h b/chromium/content/common/gpu/media/rendering_helper.h
index e66c8d5964f..31e5f7e69b5 100644
--- a/chromium/content/common/gpu/media/rendering_helper.h
+++ b/chromium/content/common/gpu/media/rendering_helper.h
@@ -23,6 +23,10 @@ class MessageLoop;
class WaitableEvent;
}
+namespace ui {
+class DisplayConfigurator;
+}
+
namespace content {
class VideoFrameTexture : public base::RefCounted<VideoFrameTexture> {
@@ -80,13 +84,25 @@ class RenderingHelper {
RenderingHelper();
~RenderingHelper();
- static bool InitializeOneOff();
+ // Initialize GL. This method must be called on the rendering
+ // thread.
+ static void InitializeOneOff(base::WaitableEvent* done);
+
+ // Setup the platform window to display test results. This method
+ // must be called on the main thread.
+ void Setup();
+
+ // Tear down the platform window. This method must be called on the
+ // main thread.
+ void TearDown();
- // Create the render context and windows by the specified dimensions.
+ // Create the render context and windows by the specified
+ // dimensions. This method must be called on the rendering thread.
void Initialize(const RenderingHelperParams& params,
base::WaitableEvent* done);
- // Undo the effects of Initialize() and signal |*done|.
+ // Undo the effects of Initialize() and signal |*done|. This method
+ // must be called on the rendering thread.
void UnInitialize(base::WaitableEvent* done);
// Return a newly-created GLES2 texture id of the specified size, and
@@ -114,8 +130,11 @@ class RenderingHelper {
// Get the platform specific handle to the OpenGL display.
void* GetGLDisplay();
+ // Get the GL context.
+ scoped_refptr<gfx::GLContext> GetGLContext();
+
// Get the platform specific handle to the OpenGL context.
- void* GetGLContext();
+ void* GetGLContextHandle();
// Get rendered thumbnails as RGB.
// Sets alpha_solid to true if the alpha channel is entirely 0xff.
@@ -169,6 +188,17 @@ class RenderingHelper {
scoped_refptr<gfx::GLContext> gl_context_;
scoped_refptr<gfx::GLSurface> gl_surface_;
+#if defined(USE_OZONE)
+ class StubOzoneDelegate;
+ scoped_ptr<StubOzoneDelegate> platform_window_delegate_;
+
+#if defined(OS_CHROMEOS)
+ scoped_ptr<ui::DisplayConfigurator> display_configurator_;
+#endif
+#endif
+
+ bool ignore_vsync_;
+
gfx::AcceleratedWidget window_;
gfx::Size screen_size_;
diff --git a/chromium/content/common/gpu/media/tegra_v4l2_device.cc b/chromium/content/common/gpu/media/tegra_v4l2_device.cc
new file mode 100644
index 00000000000..21cb57f5bb4
--- /dev/null
+++ b/chromium/content/common/gpu/media/tegra_v4l2_device.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 <dlfcn.h>
+#include <fcntl.h>
+#include <linux/videodev2.h>
+
+#include "base/lazy_instance.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/trace_event/trace_event.h"
+#include "content/common/gpu/media/tegra_v4l2_device.h"
+#include "ui/gl/gl_bindings.h"
+
+namespace content {
+
+namespace {
+const char kDecoderDevice[] = "/dev/tegra_avpchannel";
+const char kEncoderDevice[] = "/dev/nvhost-msenc";
+}
+
+typedef int32 (*TegraV4L2Open)(const char* name, int32 flags);
+typedef int32 (*TegraV4L2Close)(int32 fd);
+typedef int32 (*TegraV4L2Ioctl)(int32 fd, unsigned long cmd, ...);
+typedef int32 (*TegraV4L2Poll)(int32 fd, bool poll_device, bool* event_pending);
+typedef int32 (*TegraV4L2SetDevicePollInterrupt)(int32 fd);
+typedef int32 (*TegraV4L2ClearDevicePollInterrupt)(int32 fd);
+typedef void* (*TegraV4L2Mmap)(void* addr,
+ size_t length,
+ int prot,
+ int flags,
+ int fd,
+ unsigned int offset);
+typedef int32 (*TegraV4L2Munmap)(void* addr, size_t length);
+typedef int32 (*TegraV4L2UseEglImage)(int fd,
+ unsigned int buffer_index,
+ void* egl_image);
+
+#define TEGRAV4L2_SYM(name) TegraV4L2##name TegraV4L2_##name = NULL
+
+TEGRAV4L2_SYM(Open);
+TEGRAV4L2_SYM(Close);
+TEGRAV4L2_SYM(Ioctl);
+TEGRAV4L2_SYM(Poll);
+TEGRAV4L2_SYM(SetDevicePollInterrupt);
+TEGRAV4L2_SYM(ClearDevicePollInterrupt);
+TEGRAV4L2_SYM(Mmap);
+TEGRAV4L2_SYM(Munmap);
+TEGRAV4L2_SYM(UseEglImage);
+
+#undef TEGRAV4L2_SYM
+
+class TegraFunctionSymbolFinder {
+ public:
+ TegraFunctionSymbolFinder() : initialized_(false) {
+ if (!dlopen("/usr/lib/libtegrav4l2.so",
+ RTLD_NOW | RTLD_GLOBAL | RTLD_NODELETE)) {
+ DLOG(ERROR) << "Failed to load libtegrav4l2.so";
+ return;
+ }
+#define TEGRAV4L2_DLSYM_OR_RETURN_ON_ERROR(name) \
+ do { \
+ TegraV4L2_##name = reinterpret_cast<TegraV4L2##name>( \
+ dlsym(RTLD_DEFAULT, "TegraV4L2_" #name)); \
+ if (TegraV4L2_##name == NULL) { \
+ LOG(ERROR) << "Failed to dlsym TegraV4L2_" #name; \
+ return; \
+ } \
+ } while (0)
+
+ TEGRAV4L2_DLSYM_OR_RETURN_ON_ERROR(Open);
+ TEGRAV4L2_DLSYM_OR_RETURN_ON_ERROR(Close);
+ TEGRAV4L2_DLSYM_OR_RETURN_ON_ERROR(Ioctl);
+ TEGRAV4L2_DLSYM_OR_RETURN_ON_ERROR(Poll);
+ TEGRAV4L2_DLSYM_OR_RETURN_ON_ERROR(SetDevicePollInterrupt);
+ TEGRAV4L2_DLSYM_OR_RETURN_ON_ERROR(ClearDevicePollInterrupt);
+ TEGRAV4L2_DLSYM_OR_RETURN_ON_ERROR(Mmap);
+ TEGRAV4L2_DLSYM_OR_RETURN_ON_ERROR(Munmap);
+ TEGRAV4L2_DLSYM_OR_RETURN_ON_ERROR(UseEglImage);
+#undef TEGRAV4L2_DLSYM
+ initialized_ = true;
+ }
+
+ bool initialized() { return initialized_; }
+
+ private:
+ bool initialized_;
+};
+
+base::LazyInstance<TegraFunctionSymbolFinder> g_tegra_function_symbol_finder_ =
+ LAZY_INSTANCE_INITIALIZER;
+
+TegraV4L2Device::TegraV4L2Device(Type type)
+ : V4L2Device(type),
+ device_fd_(-1) {
+}
+
+TegraV4L2Device::~TegraV4L2Device() {
+ if (device_fd_ != -1) {
+ TegraV4L2_Close(device_fd_);
+ device_fd_ = -1;
+ }
+}
+
+int TegraV4L2Device::Ioctl(int flags, void* arg) {
+ return HANDLE_EINTR(TegraV4L2_Ioctl(device_fd_, flags, arg));
+}
+
+bool TegraV4L2Device::Poll(bool poll_device, bool* event_pending) {
+ if (HANDLE_EINTR(TegraV4L2_Poll(device_fd_, poll_device, event_pending)) ==
+ -1) {
+ LOG(ERROR) << "TegraV4L2Poll returned -1 ";
+ return false;
+ }
+ return true;
+}
+
+void* TegraV4L2Device::Mmap(void* addr,
+ unsigned int len,
+ int prot,
+ int flags,
+ unsigned int offset) {
+ return TegraV4L2_Mmap(addr, len, prot, flags, device_fd_, offset);
+}
+
+void TegraV4L2Device::Munmap(void* addr, unsigned int len) {
+ TegraV4L2_Munmap(addr, len);
+}
+
+bool TegraV4L2Device::SetDevicePollInterrupt() {
+ if (HANDLE_EINTR(TegraV4L2_SetDevicePollInterrupt(device_fd_)) == -1) {
+ LOG(ERROR) << "Error in calling TegraV4L2SetDevicePollInterrupt";
+ return false;
+ }
+ return true;
+}
+
+bool TegraV4L2Device::ClearDevicePollInterrupt() {
+ if (HANDLE_EINTR(TegraV4L2_ClearDevicePollInterrupt(device_fd_)) == -1) {
+ LOG(ERROR) << "Error in calling TegraV4L2ClearDevicePollInterrupt";
+ return false;
+ }
+ return true;
+}
+
+bool TegraV4L2Device::Initialize() {
+ const char* device_path = NULL;
+ switch (type_) {
+ case kDecoder:
+ device_path = kDecoderDevice;
+ break;
+ case kEncoder:
+ device_path = kEncoderDevice;
+ break;
+ case kImageProcessor:
+ DVLOG(1) << "Device type " << type_ << " not supported on this platform";
+ return false;
+ }
+
+ if (!g_tegra_function_symbol_finder_.Get().initialized()) {
+ DLOG(ERROR) << "Unable to initialize functions";
+ return false;
+ }
+ device_fd_ = HANDLE_EINTR(
+ TegraV4L2_Open(device_path, O_RDWR | O_NONBLOCK | O_CLOEXEC));
+ if (device_fd_ == -1) {
+ DLOG(ERROR) << "Unable to open device " << device_path;
+ return false;
+ }
+ return true;
+}
+
+bool TegraV4L2Device::CanCreateEGLImageFrom(uint32_t v4l2_pixfmt) {
+ return v4l2_pixfmt == V4L2_PIX_FMT_NV12M;
+}
+
+EGLImageKHR TegraV4L2Device::CreateEGLImage(EGLDisplay egl_display,
+ EGLContext egl_context,
+ GLuint texture_id,
+ gfx::Size /* frame_buffer_size */,
+ unsigned int buffer_index,
+ uint32_t v4l2_pixfmt,
+ size_t /* num_v4l2_planes */) {
+ DVLOG(3) << "CreateEGLImage()";
+ if (!CanCreateEGLImageFrom(v4l2_pixfmt)) {
+ LOG(ERROR) << "Unsupported V4L2 pixel format";
+ return EGL_NO_IMAGE_KHR;
+ }
+
+ EGLint attr = EGL_NONE;
+ EGLImageKHR egl_image =
+ eglCreateImageKHR(egl_display,
+ egl_context,
+ EGL_GL_TEXTURE_2D_KHR,
+ reinterpret_cast<EGLClientBuffer>(texture_id),
+ &attr);
+ if (egl_image == EGL_NO_IMAGE_KHR) {
+ LOG(ERROR) << "Unable to create EGL image";
+ return egl_image;
+ }
+ if (TegraV4L2_UseEglImage(device_fd_, buffer_index, egl_image) != 0) {
+ LOG(ERROR) << "Unable to use EGL image";
+ eglDestroyImageKHR(egl_display, egl_image);
+ egl_image = EGL_NO_IMAGE_KHR;
+ }
+ return egl_image;
+}
+
+EGLBoolean TegraV4L2Device::DestroyEGLImage(EGLDisplay egl_display,
+ EGLImageKHR egl_image) {
+ return eglDestroyImageKHR(egl_display, egl_image);
+}
+
+GLenum TegraV4L2Device::GetTextureTarget() { return GL_TEXTURE_2D; }
+
+uint32 TegraV4L2Device::PreferredInputFormat() {
+ // TODO(posciak): We should support "dontcare" returns here once we
+ // implement proper handling (fallback, negotiation) for this in users.
+ CHECK_EQ(type_, kEncoder);
+ return V4L2_PIX_FMT_YUV420M;
+}
+
+} // namespace content
diff --git a/chromium/content/common/gpu/media/tegra_v4l2_device.h b/chromium/content/common/gpu/media/tegra_v4l2_device.h
new file mode 100644
index 00000000000..4e05253f3d4
--- /dev/null
+++ b/chromium/content/common/gpu/media/tegra_v4l2_device.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.
+//
+// This file contains the implementation of TegraV4L2Device used on
+// Tegra platform.
+
+#ifndef CONTENT_COMMON_GPU_MEDIA_TEGRA_V4L2_DEVICE_H_
+#define CONTENT_COMMON_GPU_MEDIA_TEGRA_V4L2_DEVICE_H_
+
+#include "content/common/gpu/media/v4l2_device.h"
+#include "ui/gl/gl_bindings.h"
+
+namespace content {
+
+// This class implements the V4L2Device interface for Tegra platform.
+// It interfaces with libtegrav4l2 library which provides API that exhibit the
+// V4L2 specification via the library API instead of system calls.
+class TegraV4L2Device : public V4L2Device {
+ public:
+ explicit TegraV4L2Device(Type type);
+
+ int Ioctl(int flags, void* arg) override;
+ bool Poll(bool poll_device, bool* event_pending) override;
+ bool SetDevicePollInterrupt() override;
+ bool ClearDevicePollInterrupt() override;
+ void* Mmap(void* addr,
+ unsigned int len,
+ int prot,
+ int flags,
+ unsigned int offset) override;
+ void Munmap(void* addr, unsigned int len) override;
+ bool Initialize() override;
+ bool CanCreateEGLImageFrom(uint32_t v4l2_pixfmt) override;
+ EGLImageKHR CreateEGLImage(EGLDisplay egl_display,
+ EGLContext egl_context,
+ GLuint texture_id,
+ gfx::Size frame_buffer_size,
+ unsigned int buffer_index,
+ uint32_t v4l2_pixfmt,
+ size_t num_v4l2_planes);
+ EGLBoolean DestroyEGLImage(EGLDisplay egl_display,
+ EGLImageKHR egl_image) override;
+ GLenum GetTextureTarget() override;
+ uint32 PreferredInputFormat() override;
+
+ private:
+ ~TegraV4L2Device() override;
+
+ // The actual device fd.
+ int device_fd_;
+
+ DISALLOW_COPY_AND_ASSIGN(TegraV4L2Device);
+};
+
+} // namespace content
+
+#endif // CONTENT_COMMON_GPU_MEDIA_TEGRA_V4L2_DEVICE_H_
diff --git a/chromium/content/common/gpu/media/tegra_v4l2_video_device.cc b/chromium/content/common/gpu/media/tegra_v4l2_video_device.cc
deleted file mode 100644
index 991f54a76d3..00000000000
--- a/chromium/content/common/gpu/media/tegra_v4l2_video_device.cc
+++ /dev/null
@@ -1,220 +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 <dlfcn.h>
-#include <fcntl.h>
-#include <linux/videodev2.h>
-
-#include "base/debug/trace_event.h"
-#include "base/lazy_instance.h"
-#include "base/posix/eintr_wrapper.h"
-#include "content/common/gpu/media/tegra_v4l2_video_device.h"
-#include "ui/gl/gl_bindings.h"
-
-namespace content {
-
-namespace {
-const char kDecoderDevice[] = "/dev/tegra_avpchannel";
-const char kEncoderDevice[] = "/dev/nvhost-msenc";
-}
-
-typedef int32 (*TegraV4L2Open)(const char* name, int32 flags);
-typedef int32 (*TegraV4L2Close)(int32 fd);
-typedef int32 (*TegraV4L2Ioctl)(int32 fd, unsigned long cmd, ...);
-typedef int32 (*TegraV4L2Poll)(int32 fd, bool poll_device, bool* event_pending);
-typedef int32 (*TegraV4L2SetDevicePollInterrupt)(int32 fd);
-typedef int32 (*TegraV4L2ClearDevicePollInterrupt)(int32 fd);
-typedef void* (*TegraV4L2Mmap)(void* addr,
- size_t length,
- int prot,
- int flags,
- int fd,
- unsigned int offset);
-typedef int32 (*TegraV4L2Munmap)(void* addr, size_t length);
-typedef int32 (*TegraV4L2UseEglImage)(int fd,
- unsigned int buffer_index,
- void* egl_image);
-
-#define TEGRAV4L2_SYM(name) TegraV4L2##name TegraV4L2_##name = NULL
-
-TEGRAV4L2_SYM(Open);
-TEGRAV4L2_SYM(Close);
-TEGRAV4L2_SYM(Ioctl);
-TEGRAV4L2_SYM(Poll);
-TEGRAV4L2_SYM(SetDevicePollInterrupt);
-TEGRAV4L2_SYM(ClearDevicePollInterrupt);
-TEGRAV4L2_SYM(Mmap);
-TEGRAV4L2_SYM(Munmap);
-TEGRAV4L2_SYM(UseEglImage);
-
-#undef TEGRAV4L2_SYM
-
-class TegraFunctionSymbolFinder {
- public:
- TegraFunctionSymbolFinder() : initialized_(false) {
- if (!dlopen("/usr/lib/libtegrav4l2.so",
- RTLD_NOW | RTLD_GLOBAL | RTLD_NODELETE)) {
- DLOG(ERROR) << "Failed to load libtegrav4l2.so";
- return;
- }
-#define TEGRAV4L2_DLSYM_OR_RETURN_ON_ERROR(name) \
- do { \
- TegraV4L2_##name = reinterpret_cast<TegraV4L2##name>( \
- dlsym(RTLD_DEFAULT, "TegraV4L2_" #name)); \
- if (TegraV4L2_##name == NULL) { \
- LOG(ERROR) << "Failed to dlsym TegraV4L2_" #name; \
- return; \
- } \
- } while (0)
-
- TEGRAV4L2_DLSYM_OR_RETURN_ON_ERROR(Open);
- TEGRAV4L2_DLSYM_OR_RETURN_ON_ERROR(Close);
- TEGRAV4L2_DLSYM_OR_RETURN_ON_ERROR(Ioctl);
- TEGRAV4L2_DLSYM_OR_RETURN_ON_ERROR(Poll);
- TEGRAV4L2_DLSYM_OR_RETURN_ON_ERROR(SetDevicePollInterrupt);
- TEGRAV4L2_DLSYM_OR_RETURN_ON_ERROR(ClearDevicePollInterrupt);
- TEGRAV4L2_DLSYM_OR_RETURN_ON_ERROR(Mmap);
- TEGRAV4L2_DLSYM_OR_RETURN_ON_ERROR(Munmap);
- TEGRAV4L2_DLSYM_OR_RETURN_ON_ERROR(UseEglImage);
-#undef TEGRAV4L2_DLSYM
- initialized_ = true;
- }
-
- bool initialized() { return initialized_; }
-
- private:
- bool initialized_;
-};
-
-base::LazyInstance<TegraFunctionSymbolFinder> g_tegra_function_symbol_finder_ =
- LAZY_INSTANCE_INITIALIZER;
-
-TegraV4L2Device::TegraV4L2Device(Type type)
- : type_(type),
- device_fd_(-1) {
-}
-
-TegraV4L2Device::~TegraV4L2Device() {
- if (device_fd_ != -1) {
- TegraV4L2_Close(device_fd_);
- device_fd_ = -1;
- }
-}
-
-int TegraV4L2Device::Ioctl(int flags, void* arg) {
- return HANDLE_EINTR(TegraV4L2_Ioctl(device_fd_, flags, arg));
-}
-
-bool TegraV4L2Device::Poll(bool poll_device, bool* event_pending) {
- if (HANDLE_EINTR(TegraV4L2_Poll(device_fd_, poll_device, event_pending)) ==
- -1) {
- LOG(ERROR) << "TegraV4L2Poll returned -1 ";
- return false;
- }
- return true;
-}
-
-void* TegraV4L2Device::Mmap(void* addr,
- unsigned int len,
- int prot,
- int flags,
- unsigned int offset) {
- return TegraV4L2_Mmap(addr, len, prot, flags, device_fd_, offset);
-}
-
-void TegraV4L2Device::Munmap(void* addr, unsigned int len) {
- TegraV4L2_Munmap(addr, len);
-}
-
-bool TegraV4L2Device::SetDevicePollInterrupt() {
- if (HANDLE_EINTR(TegraV4L2_SetDevicePollInterrupt(device_fd_)) == -1) {
- LOG(ERROR) << "Error in calling TegraV4L2SetDevicePollInterrupt";
- return false;
- }
- return true;
-}
-
-bool TegraV4L2Device::ClearDevicePollInterrupt() {
- if (HANDLE_EINTR(TegraV4L2_ClearDevicePollInterrupt(device_fd_)) == -1) {
- LOG(ERROR) << "Error in calling TegraV4L2ClearDevicePollInterrupt";
- return false;
- }
- return true;
-}
-
-bool TegraV4L2Device::Initialize() {
- const char* device_path = NULL;
- switch (type_) {
- case kDecoder:
- device_path = kDecoderDevice;
- break;
- case kEncoder:
- device_path = kEncoderDevice;
- break;
- case kImageProcessor:
- DVLOG(1) << "Device type " << type_ << " not supported on this platform";
- return false;
- }
-
- if (!g_tegra_function_symbol_finder_.Get().initialized()) {
- DLOG(ERROR) << "Unable to initialize functions";
- return false;
- }
- device_fd_ = HANDLE_EINTR(
- TegraV4L2_Open(device_path, O_RDWR | O_NONBLOCK | O_CLOEXEC));
- if (device_fd_ == -1) {
- DLOG(ERROR) << "Unable to open device " << device_path;
- return false;
- }
- return true;
-}
-
-EGLImageKHR TegraV4L2Device::CreateEGLImage(EGLDisplay egl_display,
- EGLContext egl_context,
- GLuint texture_id,
- gfx::Size /* frame_buffer_size */,
- unsigned int buffer_index,
- size_t /* planes_count */) {
- DVLOG(3) << "CreateEGLImage()";
- EGLint attr = EGL_NONE;
- EGLImageKHR egl_image =
- eglCreateImageKHR(egl_display,
- egl_context,
- EGL_GL_TEXTURE_2D_KHR,
- reinterpret_cast<EGLClientBuffer>(texture_id),
- &attr);
- if (egl_image == EGL_NO_IMAGE_KHR) {
- LOG(ERROR) << "Unable to create EGL image";
- return egl_image;
- }
- if (TegraV4L2_UseEglImage(device_fd_, buffer_index, egl_image) != 0) {
- LOG(ERROR) << "Unable to use EGL image";
- eglDestroyImageKHR(egl_display, egl_image);
- egl_image = EGL_NO_IMAGE_KHR;
- }
- return egl_image;
-}
-
-EGLBoolean TegraV4L2Device::DestroyEGLImage(EGLDisplay egl_display,
- EGLImageKHR egl_image) {
- return eglDestroyImageKHR(egl_display, egl_image);
-}
-
-GLenum TegraV4L2Device::GetTextureTarget() { return GL_TEXTURE_2D; }
-
-uint32 TegraV4L2Device::PreferredInputFormat() {
- // TODO(posciak): We should support "dontcare" returns here once we
- // implement proper handling (fallback, negotiation) for this in users.
- CHECK_EQ(type_, kEncoder);
- return V4L2_PIX_FMT_YUV420M;
-}
-
-uint32 TegraV4L2Device::PreferredOutputFormat() {
- // TODO(posciak): We should support "dontcare" returns here once we
- // implement proper handling (fallback, negotiation) for this in users.
- CHECK_EQ(type_, kDecoder);
- return V4L2_PIX_FMT_NV12M;
-}
-
-} // namespace content
diff --git a/chromium/content/common/gpu/media/tegra_v4l2_video_device.h b/chromium/content/common/gpu/media/tegra_v4l2_video_device.h
deleted file mode 100644
index f9e38caa487..00000000000
--- a/chromium/content/common/gpu/media/tegra_v4l2_video_device.h
+++ /dev/null
@@ -1,58 +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 contains the implementation of TegraV4L2Device used on
-// Tegra platform.
-
-#ifndef CONTENT_COMMON_GPU_MEDIA_TEGRA_V4L2_VIDEO_DEVICE_H_
-#define CONTENT_COMMON_GPU_MEDIA_TEGRA_V4L2_VIDEO_DEVICE_H_
-
-#include "content/common/gpu/media/v4l2_video_device.h"
-#include "ui/gl/gl_bindings.h"
-
-namespace content {
-
-// This class implements the V4L2Device interface for Tegra platform.
-// It interfaces with libtegrav4l2 library which provides API that exhibit the
-// V4L2 specification via the library API instead of system calls.
-class TegraV4L2Device : public V4L2Device {
- public:
- explicit TegraV4L2Device(Type type);
- virtual ~TegraV4L2Device();
-
- virtual int Ioctl(int flags, void* arg) override;
- virtual bool Poll(bool poll_device, bool* event_pending) override;
- virtual bool SetDevicePollInterrupt() override;
- virtual bool ClearDevicePollInterrupt() override;
- virtual void* Mmap(void* addr,
- unsigned int len,
- int prot,
- int flags,
- unsigned int offset) override;
- virtual void Munmap(void* addr, unsigned int len) override;
- virtual bool Initialize() override;
- virtual EGLImageKHR CreateEGLImage(EGLDisplay egl_display,
- EGLContext egl_context,
- GLuint texture_id,
- gfx::Size frame_buffer_size,
- unsigned int buffer_index,
- size_t planes_count) override;
- virtual EGLBoolean DestroyEGLImage(EGLDisplay egl_display,
- EGLImageKHR egl_image) override;
- virtual GLenum GetTextureTarget() override;
- virtual uint32 PreferredInputFormat() override;
- virtual uint32 PreferredOutputFormat() override;
-
- private:
- const Type type_;
-
- // The actual device fd.
- int device_fd_;
-
- DISALLOW_COPY_AND_ASSIGN(TegraV4L2Device);
-};
-
-} // namespace content
-
-#endif // CONTENT_COMMON_GPU_MEDIA_TEGRA_V4L2_VIDEO_DEVICE_H_
diff --git a/chromium/content/common/gpu/media/v4l2.sig b/chromium/content/common/gpu/media/v4l2.sig
new file mode 100644
index 00000000000..4269fb48d59
--- /dev/null
+++ b/chromium/content/common/gpu/media/v4l2.sig
@@ -0,0 +1,10 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//------------------------------------------------
+// Functions from libv4l2 used in chromium code.
+//------------------------------------------------
+LIBV4L_PUBLIC int v4l2_close(int fd);
+LIBV4L_PUBLIC int v4l2_ioctl(int fd, unsigned long int request, ...);
+LIBV4L_PUBLIC int v4l2_fd_open(int fd, int v4l2_flags);
diff --git a/chromium/content/common/gpu/media/v4l2_device.cc b/chromium/content/common/gpu/media/v4l2_device.cc
new file mode 100644
index 00000000000..891da344d00
--- /dev/null
+++ b/chromium/content/common/gpu/media/v4l2_device.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 <libdrm/drm_fourcc.h>
+#include <linux/videodev2.h>
+
+#include "base/numerics/safe_conversions.h"
+#include "content/common/gpu/media/generic_v4l2_device.h"
+#if defined(ARCH_CPU_ARMEL)
+#include "content/common/gpu/media/tegra_v4l2_device.h"
+#endif
+
+namespace content {
+
+V4L2Device::V4L2Device(Type type) : type_(type) {
+}
+
+V4L2Device::~V4L2Device() {
+}
+
+// static
+scoped_refptr<V4L2Device> V4L2Device::Create(Type type) {
+ DVLOG(3) << __PRETTY_FUNCTION__;
+
+ scoped_refptr<GenericV4L2Device> generic_device(new GenericV4L2Device(type));
+ if (generic_device->Initialize())
+ return generic_device;
+
+#if defined(ARCH_CPU_ARMEL)
+ scoped_refptr<TegraV4L2Device> tegra_device(new TegraV4L2Device(type));
+ if (tegra_device->Initialize())
+ return tegra_device;
+#endif
+
+ DVLOG(1) << "Failed to create V4L2Device";
+ return scoped_refptr<V4L2Device>();
+}
+
+// static
+media::VideoFrame::Format V4L2Device::V4L2PixFmtToVideoFrameFormat(
+ uint32 pix_fmt) {
+ switch (pix_fmt) {
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV12M:
+ return media::VideoFrame::NV12;
+
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_YUV420M:
+ return media::VideoFrame::I420;
+
+ case V4L2_PIX_FMT_RGB32:
+ return media::VideoFrame::ARGB;
+
+ default:
+ LOG(FATAL) << "Add more cases as needed";
+ return media::VideoFrame::UNKNOWN;
+ }
+}
+
+// static
+uint32 V4L2Device::VideoFrameFormatToV4L2PixFmt(
+ media::VideoFrame::Format format) {
+ switch (format) {
+ case media::VideoFrame::NV12:
+ return V4L2_PIX_FMT_NV12M;
+
+ case media::VideoFrame::I420:
+ return V4L2_PIX_FMT_YUV420M;
+
+ default:
+ LOG(FATAL) << "Add more cases as needed";
+ return 0;
+ }
+}
+
+// static
+uint32 V4L2Device::VideoCodecProfileToV4L2PixFmt(
+ media::VideoCodecProfile profile,
+ bool slice_based) {
+ if (profile >= media::H264PROFILE_MIN &&
+ profile <= media::H264PROFILE_MAX) {
+ if (slice_based)
+ return V4L2_PIX_FMT_H264_SLICE;
+ else
+ return V4L2_PIX_FMT_H264;
+ } else if (profile >= media::VP8PROFILE_MIN &&
+ profile <= media::VP8PROFILE_MAX) {
+ if (slice_based)
+ return V4L2_PIX_FMT_VP8_FRAME;
+ else
+ return V4L2_PIX_FMT_VP8;
+ } else if (profile >= media::VP9PROFILE_MIN &&
+ profile <= media::VP9PROFILE_MAX) {
+ return V4L2_PIX_FMT_VP9;
+ } else {
+ LOG(FATAL) << "Add more cases as needed";
+ return 0;
+ }
+}
+
+// static
+uint32_t V4L2Device::V4L2PixFmtToDrmFormat(uint32_t format) {
+ switch (format) {
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV12M:
+ return DRM_FORMAT_NV12;
+
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_YUV420M:
+ return DRM_FORMAT_YUV420;
+
+ case V4L2_PIX_FMT_RGB32:
+ return DRM_FORMAT_ARGB8888;
+
+ default:
+ DVLOG(1) << "Add more cases as needed";
+ return 0;
+ }
+}
+
+// static
+gfx::Size V4L2Device::CodedSizeFromV4L2Format(struct v4l2_format format) {
+ gfx::Size coded_size;
+ gfx::Size visible_size;
+ media::VideoFrame::Format frame_format = media::VideoFrame::UNKNOWN;
+ size_t bytesperline = 0;
+ // Total bytes in the frame.
+ size_t sizeimage = 0;
+
+ if (V4L2_TYPE_IS_MULTIPLANAR(format.type)) {
+ DCHECK_GT(format.fmt.pix_mp.num_planes, 0);
+ bytesperline =
+ base::checked_cast<int>(format.fmt.pix_mp.plane_fmt[0].bytesperline);
+ for (size_t i = 0; i < format.fmt.pix_mp.num_planes; ++i) {
+ sizeimage +=
+ base::checked_cast<int>(format.fmt.pix_mp.plane_fmt[i].sizeimage);
+ }
+ visible_size.SetSize(base::checked_cast<int>(format.fmt.pix_mp.width),
+ base::checked_cast<int>(format.fmt.pix_mp.height));
+ frame_format =
+ V4L2Device::V4L2PixFmtToVideoFrameFormat(format.fmt.pix_mp.pixelformat);
+ } else {
+ bytesperline = base::checked_cast<int>(format.fmt.pix.bytesperline);
+ sizeimage = base::checked_cast<int>(format.fmt.pix.sizeimage);
+ visible_size.SetSize(base::checked_cast<int>(format.fmt.pix.width),
+ base::checked_cast<int>(format.fmt.pix.height));
+ frame_format =
+ V4L2Device::V4L2PixFmtToVideoFrameFormat(format.fmt.pix.pixelformat);
+ }
+
+ // V4L2 does not provide per-plane bytesperline (bpl) when different
+ // components are sharing one physical plane buffer. In this case, it only
+ // provides bpl for the first component in the plane. So we can't depend on it
+ // for calculating height, because bpl may vary within one physical plane
+ // buffer. For example, YUV420 contains 3 components in one physical plane,
+ // with Y at 8 bits per pixel, and Cb/Cr at 4 bits per pixel per component,
+ // but we only get 8 pits per pixel from bytesperline in physical plane 0.
+ // So we need to get total frame bpp from elsewhere to calculate coded height.
+
+ // We need bits per pixel for one component only to calculate
+ // coded_width from bytesperline.
+ int plane_horiz_bits_per_pixel =
+ media::VideoFrame::PlaneHorizontalBitsPerPixel(frame_format, 0);
+
+ // Adding up bpp for each component will give us total bpp for all components.
+ int total_bpp = 0;
+ for (size_t i = 0; i < media::VideoFrame::NumPlanes(frame_format); ++i)
+ total_bpp += media::VideoFrame::PlaneBitsPerPixel(frame_format, i);
+
+ if (sizeimage == 0 || bytesperline == 0 || plane_horiz_bits_per_pixel == 0 ||
+ total_bpp == 0 || (bytesperline * 8) % plane_horiz_bits_per_pixel != 0) {
+ LOG(ERROR) << "Invalid format provided";
+ return coded_size;
+ }
+
+ // Coded width can be calculated by taking the first component's bytesperline,
+ // which in V4L2 always applies to the first component in physical plane
+ // buffer.
+ int coded_width = bytesperline * 8 / plane_horiz_bits_per_pixel;
+ // Sizeimage is coded_width * coded_height * total_bpp.
+ int coded_height = sizeimage * 8 / coded_width / total_bpp;
+
+ coded_size.SetSize(coded_width, coded_height);
+ // It's possible the driver gave us a slightly larger sizeimage than what
+ // would be calculated from coded size. This is technically not allowed, but
+ // some drivers (Exynos) like to have some additional alignment that is not a
+ // multiple of bytesperline. The best thing we can do is to compensate by
+ // aligning to next full row.
+ if (sizeimage > media::VideoFrame::AllocationSize(frame_format, coded_size))
+ coded_size.SetSize(coded_width, coded_height + 1);
+ DVLOG(3) << "coded_size=" << coded_size.ToString();
+
+ // Sanity checks. Calculated coded size has to contain given visible size
+ // and fulfill buffer byte size requirements.
+ DCHECK(gfx::Rect(coded_size).Contains(gfx::Rect(visible_size)));
+ DCHECK_LE(sizeimage,
+ media::VideoFrame::AllocationSize(frame_format, coded_size));
+
+ return coded_size;
+}
+
+void V4L2Device::GetSupportedResolution(uint32_t pixelformat,
+ gfx::Size* min_resolution,
+ gfx::Size* max_resolution) {
+ max_resolution->SetSize(0, 0);
+ min_resolution->SetSize(0, 0);
+ v4l2_frmsizeenum frame_size;
+ memset(&frame_size, 0, sizeof(frame_size));
+ frame_size.pixel_format = pixelformat;
+ for (; Ioctl(VIDIOC_ENUM_FRAMESIZES, &frame_size) == 0; ++frame_size.index) {
+ if (frame_size.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
+ if (frame_size.discrete.width >=
+ base::checked_cast<uint32_t>(max_resolution->width()) &&
+ frame_size.discrete.height >=
+ base::checked_cast<uint32_t>(max_resolution->height())) {
+ max_resolution->SetSize(frame_size.discrete.width,
+ frame_size.discrete.height);
+ }
+ if (min_resolution->IsEmpty() ||
+ (frame_size.discrete.width <=
+ base::checked_cast<uint32_t>(min_resolution->width()) &&
+ frame_size.discrete.height <=
+ base::checked_cast<uint32_t>(min_resolution->height()))) {
+ min_resolution->SetSize(frame_size.discrete.width,
+ frame_size.discrete.height);
+ }
+ } else if (frame_size.type == V4L2_FRMSIZE_TYPE_STEPWISE ||
+ frame_size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) {
+ max_resolution->SetSize(frame_size.stepwise.max_width,
+ frame_size.stepwise.max_height);
+ min_resolution->SetSize(frame_size.stepwise.min_width,
+ frame_size.stepwise.min_height);
+ break;
+ }
+ }
+ if (max_resolution->IsEmpty()) {
+ max_resolution->SetSize(1920, 1088);
+ LOG(ERROR) << "GetSupportedResolution failed to get maximum resolution for "
+ << "fourcc " << std::hex << pixelformat
+ << ", fall back to " << max_resolution->ToString();
+ }
+ if (min_resolution->IsEmpty()) {
+ min_resolution->SetSize(16, 16);
+ LOG(ERROR) << "GetSupportedResolution failed to get minimum resolution for "
+ << "fourcc " << std::hex << pixelformat
+ << ", fall back to " << min_resolution->ToString();
+ }
+}
+
+media::VideoDecodeAccelerator::SupportedProfiles
+V4L2Device::GetSupportedDecodeProfiles(const size_t num_formats,
+ const uint32_t pixelformats[]) {
+ DCHECK_EQ(type_, kDecoder);
+ media::VideoDecodeAccelerator::SupportedProfiles profiles;
+ media::VideoDecodeAccelerator::SupportedProfile profile;
+ v4l2_fmtdesc fmtdesc;
+ memset(&fmtdesc, 0, sizeof(fmtdesc));
+ fmtdesc.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+
+ for (; Ioctl(VIDIOC_ENUM_FMT, &fmtdesc) == 0; ++fmtdesc.index) {
+ if (std::find(pixelformats, pixelformats + num_formats,
+ fmtdesc.pixelformat) == pixelformats + num_formats)
+ continue;
+ int min_profile, max_profile;
+ switch (fmtdesc.pixelformat) {
+ case V4L2_PIX_FMT_H264:
+ case V4L2_PIX_FMT_H264_SLICE:
+ min_profile = media::H264PROFILE_MIN;
+ max_profile = media::H264PROFILE_MAX;
+ break;
+ case V4L2_PIX_FMT_VP8:
+ case V4L2_PIX_FMT_VP8_FRAME:
+ min_profile = media::VP8PROFILE_MIN;
+ max_profile = media::VP8PROFILE_MAX;
+ break;
+ case V4L2_PIX_FMT_VP9:
+ min_profile = media::VP9PROFILE_MIN;
+ max_profile = media::VP9PROFILE_MAX;
+ break;
+ default:
+ NOTREACHED() << "Unhandled pixelformat " << std::hex
+ << fmtdesc.pixelformat;
+ return profiles;
+ }
+ GetSupportedResolution(fmtdesc.pixelformat, &profile.min_resolution,
+ &profile.max_resolution);
+ for (int media_profile = min_profile; media_profile <= max_profile;
+ ++media_profile) {
+ profile.profile = static_cast<media::VideoCodecProfile>(media_profile);
+ profiles.push_back(profile);
+ }
+ }
+ return profiles;
+}
+
+} // namespace content
diff --git a/chromium/content/common/gpu/media/v4l2_device.h b/chromium/content/common/gpu/media/v4l2_device.h
new file mode 100644
index 00000000000..8cc2f399589
--- /dev/null
+++ b/chromium/content/common/gpu/media/v4l2_device.h
@@ -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.
+//
+// This file defines the V4L2Device interface which is used by the
+// V4L2DecodeAccelerator class to delegate/pass the device specific
+// handling of any of the functionalities.
+
+#ifndef CONTENT_COMMON_GPU_MEDIA_V4L2_DEVICE_H_
+#define CONTENT_COMMON_GPU_MEDIA_V4L2_DEVICE_H_
+
+#include "base/memory/ref_counted.h"
+#include "content/common/content_export.h"
+#include "media/base/video_decoder_config.h"
+#include "media/base/video_frame.h"
+#include "media/video/video_decode_accelerator.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gl/gl_bindings.h"
+
+// TODO(posciak): remove this once V4L2 headers are updated.
+#define V4L2_PIX_FMT_VP9 v4l2_fourcc('V', 'P', '9', '0')
+#define V4L2_PIX_FMT_H264_SLICE v4l2_fourcc('S', '2', '6', '4')
+#define V4L2_PIX_FMT_VP8_FRAME v4l2_fourcc('V', 'P', '8', 'F')
+
+namespace content {
+
+class CONTENT_EXPORT V4L2Device
+ : public base::RefCountedThreadSafe<V4L2Device> {
+ public:
+ // Utility format conversion functions
+ static media::VideoFrame::Format V4L2PixFmtToVideoFrameFormat(uint32 format);
+ static uint32 VideoFrameFormatToV4L2PixFmt(media::VideoFrame::Format format);
+ static uint32 VideoCodecProfileToV4L2PixFmt(media::VideoCodecProfile profile,
+ bool slice_based);
+ static uint32_t V4L2PixFmtToDrmFormat(uint32_t format);
+ // Convert format requirements requested by a V4L2 device to gfx::Size.
+ static gfx::Size CodedSizeFromV4L2Format(struct v4l2_format format);
+
+ enum Type {
+ kDecoder,
+ kEncoder,
+ kImageProcessor,
+ };
+
+ // Creates and initializes an appropriate V4L2Device of |type| for the
+ // current platform and returns a scoped_ptr<V4L2Device> on success, or NULL.
+ static scoped_refptr<V4L2Device> Create(Type type);
+
+ // Parameters and return value are the same as for the standard ioctl() system
+ // call.
+ virtual int Ioctl(int request, void* arg) = 0;
+
+ // This method sleeps until either:
+ // - SetDevicePollInterrupt() is called (on another thread),
+ // - |poll_device| is true, and there is new data to be read from the device,
+ // or an event from the device has arrived; in the latter case
+ // |*event_pending| will be set to true.
+ // Returns false on error, true otherwise.
+ // This method should be called from a separate thread.
+ virtual bool Poll(bool poll_device, bool* event_pending) = 0;
+
+ // These methods are used to interrupt the thread sleeping on Poll() and force
+ // it to return regardless of device state, which is usually when the client
+ // is no longer interested in what happens with the device (on cleanup,
+ // client state change, etc.). When SetDevicePollInterrupt() is called, Poll()
+ // will return immediately, and any subsequent calls to it will also do so
+ // until ClearDevicePollInterrupt() is called.
+ virtual bool SetDevicePollInterrupt() = 0;
+ virtual bool ClearDevicePollInterrupt() = 0;
+
+ // Wrappers for standard mmap/munmap system calls.
+ virtual void* Mmap(void* addr,
+ unsigned int len,
+ int prot,
+ int flags,
+ unsigned int offset) = 0;
+ virtual void Munmap(void* addr, unsigned int len) = 0;
+
+ // Initializes the V4L2Device to operate as a device of |type|.
+ // Returns true on success.
+ virtual bool Initialize() = 0;
+
+ // Return true if the given V4L2 pixfmt can be used in CreateEGLImage()
+ // for the current platform.
+ virtual bool CanCreateEGLImageFrom(uint32_t v4l2_pixfmt) = 0;
+
+ // Creates an EGLImageKHR since each V4L2Device may use a different method of
+ // acquiring one and associating it to the given texture. The texture_id is
+ // used to bind the texture to the returned EGLImageKHR. buffer_index can be
+ // used to associate the returned EGLImageKHR by the underlying V4L2Device
+ // implementation.
+ virtual EGLImageKHR CreateEGLImage(EGLDisplay egl_display,
+ EGLContext egl_context,
+ GLuint texture_id,
+ gfx::Size frame_buffer_size,
+ unsigned int buffer_index,
+ uint32_t v4l2_pixfmt,
+ size_t num_v4l2_planes) = 0;
+
+ // Destroys the EGLImageKHR.
+ virtual EGLBoolean DestroyEGLImage(EGLDisplay egl_display,
+ EGLImageKHR egl_image) = 0;
+
+ // Returns the supported texture target for the V4L2Device.
+ virtual GLenum GetTextureTarget() = 0;
+
+ // Returns the preferred V4L2 input format or 0 if don't care.
+ virtual uint32 PreferredInputFormat() = 0;
+
+ // Get minimum and maximum resolution for fourcc |pixelformat| and store to
+ // |min_resolution| and |max_resolution|.
+ void GetSupportedResolution(uint32_t pixelformat, gfx::Size* min_resolution,
+ gfx::Size* max_resolution);
+
+ // Return supported profiles for decoder, including only profiles for given
+ // fourcc |pixelformats|.
+ media::VideoDecodeAccelerator::SupportedProfiles GetSupportedDecodeProfiles(
+ const size_t num_formats, const uint32_t pixelformats[]);
+
+ protected:
+ friend class base::RefCountedThreadSafe<V4L2Device>;
+ explicit V4L2Device(Type type);
+ virtual ~V4L2Device();
+
+ const Type type_;
+};
+
+} // namespace content
+
+#endif // CONTENT_COMMON_GPU_MEDIA_V4L2_DEVICE_H_
diff --git a/chromium/content/common/gpu/media/v4l2_image_processor.cc b/chromium/content/common/gpu/media/v4l2_image_processor.cc
index 20d91f02e15..4063e4c402a 100644
--- a/chromium/content/common/gpu/media/v4l2_image_processor.cc
+++ b/chromium/content/common/gpu/media/v4l2_image_processor.cc
@@ -12,7 +12,6 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
-#include "base/message_loop/message_loop_proxy.h"
#include "base/numerics/safe_conversions.h"
#include "content/common/gpu/media/v4l2_image_processor.h"
#include "media/base/bind_to_current_loop.h"
@@ -48,22 +47,31 @@ namespace content {
V4L2ImageProcessor::InputRecord::InputRecord() : at_device(false) {
}
+V4L2ImageProcessor::InputRecord::~InputRecord() {
+}
+
V4L2ImageProcessor::OutputRecord::OutputRecord()
: at_device(false), at_client(false) {
}
+V4L2ImageProcessor::OutputRecord::~OutputRecord() {
+}
+
V4L2ImageProcessor::JobRecord::JobRecord() {
}
-V4L2ImageProcessor::V4L2ImageProcessor(scoped_ptr<V4L2Device> device)
+V4L2ImageProcessor::JobRecord::~JobRecord() {
+}
+
+V4L2ImageProcessor::V4L2ImageProcessor(const scoped_refptr<V4L2Device>& device)
: input_format_(media::VideoFrame::UNKNOWN),
output_format_(media::VideoFrame::UNKNOWN),
input_format_fourcc_(0),
output_format_fourcc_(0),
input_planes_count_(0),
output_planes_count_(0),
- child_message_loop_proxy_(base::MessageLoopProxy::current()),
- device_(device.Pass()),
+ child_task_runner_(base::ThreadTaskRunnerHandle::Get()),
+ device_(device),
device_thread_("V4L2ImageProcessorThread"),
device_poll_thread_("V4L2ImageProcessorDevicePollThread"),
input_streamon_(false),
@@ -74,7 +82,7 @@ V4L2ImageProcessor::V4L2ImageProcessor(scoped_ptr<V4L2Device> device)
}
V4L2ImageProcessor::~V4L2ImageProcessor() {
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
DCHECK(!device_thread_.IsRunning());
DCHECK(!device_poll_thread_.IsRunning());
@@ -83,8 +91,8 @@ V4L2ImageProcessor::~V4L2ImageProcessor() {
}
void V4L2ImageProcessor::NotifyError() {
- if (!child_message_loop_proxy_->BelongsToCurrentThread())
- child_message_loop_proxy_->PostTask(FROM_HERE, error_cb_);
+ if (!child_task_runner_->BelongsToCurrentThread())
+ child_task_runner_->PostTask(FROM_HERE, error_cb_);
else
error_cb_.Run();
}
@@ -186,7 +194,7 @@ void V4L2ImageProcessor::ProcessTask(scoped_ptr<JobRecord> job_record) {
void V4L2ImageProcessor::Destroy() {
DVLOG(3) << __func__;
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
// If the device thread is running, destroy using posted task.
if (device_thread_.IsRunning()) {
@@ -215,7 +223,7 @@ void V4L2ImageProcessor::DestroyTask() {
bool V4L2ImageProcessor::CreateInputBuffers() {
DVLOG(3) << __func__;
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
DCHECK(!input_streamon_);
struct v4l2_control control;
@@ -286,7 +294,7 @@ bool V4L2ImageProcessor::CreateInputBuffers() {
bool V4L2ImageProcessor::CreateOutputBuffers() {
DVLOG(3) << __func__;
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
DCHECK(!output_streamon_);
struct v4l2_format format;
@@ -349,7 +357,7 @@ bool V4L2ImageProcessor::CreateOutputBuffers() {
}
void V4L2ImageProcessor::DestroyInputBuffers() {
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
DCHECK(!input_streamon_);
struct v4l2_requestbuffers reqbufs;
@@ -364,7 +372,7 @@ void V4L2ImageProcessor::DestroyInputBuffers() {
}
void V4L2ImageProcessor::DestroyOutputBuffers() {
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
DCHECK(!output_streamon_);
for (size_t buf = 0; buf < output_buffer_map_.size(); ++buf) {
@@ -522,7 +530,7 @@ void V4L2ImageProcessor::Dequeue() {
memset(&dqbuf, 0, sizeof(dqbuf));
memset(&planes, 0, sizeof(planes));
dqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- dqbuf.memory = V4L2_MEMORY_DMABUF;
+ dqbuf.memory = V4L2_MEMORY_MMAP;
dqbuf.m.planes = planes;
dqbuf.length = output_planes_count_;
if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) {
@@ -561,7 +569,7 @@ void V4L2ImageProcessor::Dequeue() {
DVLOG(3) << "Processing finished, returning frame, ts="
<< output_frame->timestamp().InMilliseconds();
- child_message_loop_proxy_->PostTask(
+ child_task_runner_->PostTask(
FROM_HERE, base::Bind(job_record->ready_cb, output_frame));
}
}
diff --git a/chromium/content/common/gpu/media/v4l2_image_processor.h b/chromium/content/common/gpu/media/v4l2_image_processor.h
index 24c52c451d1..5b8069d31a8 100644
--- a/chromium/content/common/gpu/media/v4l2_image_processor.h
+++ b/chromium/content/common/gpu/media/v4l2_image_processor.h
@@ -2,17 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CONTENT_COMMON_GPU_MEDIA_V4L2_VIDEO_PROCESSOR_H_
-#define CONTENT_COMMON_GPU_MEDIA_V4L2_VIDEO_PROCESSOR_H_
+#ifndef CONTENT_COMMON_GPU_MEDIA_V4L2_IMAGE_PROCESSOR_H_
+#define CONTENT_COMMON_GPU_MEDIA_V4L2_IMAGE_PROCESSOR_H_
#include <queue>
#include <vector>
#include "base/memory/linked_ptr.h"
+#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread.h"
#include "content/common/content_export.h"
-#include "content/common/gpu/media/v4l2_video_device.h"
+#include "content/common/gpu/media/v4l2_device.h"
#include "media/base/video_frame.h"
namespace content {
@@ -22,7 +23,7 @@ namespace content {
// hardware accelerators (see V4L2VideoDecodeAccelerator) for more details.
class CONTENT_EXPORT V4L2ImageProcessor {
public:
- explicit V4L2ImageProcessor(scoped_ptr<V4L2Device> device);
+ explicit V4L2ImageProcessor(const scoped_refptr<V4L2Device>& device);
virtual ~V4L2ImageProcessor();
// Initializes the processor to convert from |input_format| to |output_format|
@@ -58,6 +59,7 @@ class CONTENT_EXPORT V4L2ImageProcessor {
// Record for input buffers.
struct InputRecord {
InputRecord();
+ ~InputRecord();
scoped_refptr<media::VideoFrame> frame;
bool at_device;
};
@@ -65,6 +67,7 @@ class CONTENT_EXPORT V4L2ImageProcessor {
// Record for output buffers.
struct OutputRecord {
OutputRecord();
+ ~OutputRecord();
bool at_device;
bool at_client;
std::vector<int> fds;
@@ -78,6 +81,7 @@ class CONTENT_EXPORT V4L2ImageProcessor {
// device).
struct JobRecord {
JobRecord();
+ ~JobRecord();
scoped_refptr<media::VideoFrame> frame;
FrameReadyCB ready_cb;
};
@@ -129,11 +133,11 @@ class CONTENT_EXPORT V4L2ImageProcessor {
size_t input_planes_count_;
size_t output_planes_count_;
- // Our original calling message loop for the child thread.
- const scoped_refptr<base::MessageLoopProxy> child_message_loop_proxy_;
+ // Our original calling task runner for the child thread.
+ const scoped_refptr<base::SingleThreadTaskRunner> child_task_runner_;
// V4L2 device in use.
- scoped_ptr<V4L2Device> device_;
+ scoped_refptr<V4L2Device> device_;
// Thread to communicate with the device on.
base::Thread device_thread_;
@@ -174,4 +178,4 @@ class CONTENT_EXPORT V4L2ImageProcessor {
} // namespace content
-#endif // CONTENT_COMMON_GPU_MEDIA_V4L2_VIDEO_PROCESSOR_H_
+#endif // CONTENT_COMMON_GPU_MEDIA_V4L2_IMAGE_PROCESSOR_H_
diff --git a/chromium/content/common/gpu/media/v4l2_slice_video_decode_accelerator.cc b/chromium/content/common/gpu/media/v4l2_slice_video_decode_accelerator.cc
new file mode 100644
index 00000000000..c1853cb3ae3
--- /dev/null
+++ b/chromium/content/common/gpu/media/v4l2_slice_video_decode_accelerator.cc
@@ -0,0 +1,2515 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <fcntl.h>
+#include <linux/videodev2.h>
+#include <poll.h>
+#include <sys/eventfd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback.h"
+#include "base/callback_helpers.h"
+#include "base/command_line.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "content/common/gpu/media/v4l2_slice_video_decode_accelerator.h"
+#include "media/base/bind_to_current_loop.h"
+#include "media/base/media_switches.h"
+#include "ui/gl/scoped_binders.h"
+
+#define LOGF(level) LOG(level) << __FUNCTION__ << "(): "
+#define DVLOGF(level) DVLOG(level) << __FUNCTION__ << "(): "
+
+#define NOTIFY_ERROR(x) \
+ do { \
+ LOG(ERROR) << "Setting error state:" << x; \
+ SetErrorState(x); \
+ } while (0)
+
+#define IOCTL_OR_ERROR_RETURN_VALUE(type, arg, value) \
+ do { \
+ if (device_->Ioctl(type, arg) != 0) { \
+ PLOG(ERROR) << __FUNCTION__ << "(): ioctl() failed: " << #type; \
+ return value; \
+ } \
+ } while (0)
+
+#define IOCTL_OR_ERROR_RETURN(type, arg) \
+ IOCTL_OR_ERROR_RETURN_VALUE(type, arg, ((void)0))
+
+#define IOCTL_OR_ERROR_RETURN_FALSE(type, arg) \
+ IOCTL_OR_ERROR_RETURN_VALUE(type, arg, false)
+
+#define IOCTL_OR_LOG_ERROR(type, arg) \
+ do { \
+ if (device_->Ioctl(type, arg) != 0) \
+ PLOG(ERROR) << __FUNCTION__ << "(): ioctl() failed: " << #type; \
+ } while (0)
+
+namespace content {
+
+class V4L2SliceVideoDecodeAccelerator::V4L2DecodeSurface
+ : public base::RefCounted<V4L2DecodeSurface> {
+ public:
+ using ReleaseCB = base::Callback<void(int)>;
+
+ V4L2DecodeSurface(int32 bitstream_id,
+ int input_record,
+ int output_record,
+ const ReleaseCB& release_cb);
+
+ // Mark the surface as decoded. This will also release all references, as
+ // they are not needed anymore.
+ void SetDecoded();
+ bool decoded() const { return decoded_; }
+
+ int32 bitstream_id() const { return bitstream_id_; }
+ int input_record() const { return input_record_; }
+ int output_record() const { return output_record_; }
+ uint32_t config_store() const { return config_store_; }
+
+ // Take references to each reference surface and keep them until the
+ // target surface is decoded.
+ void SetReferenceSurfaces(
+ const std::vector<scoped_refptr<V4L2DecodeSurface>>& ref_surfaces);
+
+ std::string ToString() const;
+
+ private:
+ friend class base::RefCounted<V4L2DecodeSurface>;
+ ~V4L2DecodeSurface();
+
+ int32 bitstream_id_;
+ int input_record_;
+ int output_record_;
+ uint32_t config_store_;
+
+ bool decoded_;
+ ReleaseCB release_cb_;
+
+ std::vector<scoped_refptr<V4L2DecodeSurface>> reference_surfaces_;
+
+ DISALLOW_COPY_AND_ASSIGN(V4L2DecodeSurface);
+};
+
+V4L2SliceVideoDecodeAccelerator::V4L2DecodeSurface::V4L2DecodeSurface(
+ int32 bitstream_id,
+ int input_record,
+ int output_record,
+ const ReleaseCB& release_cb)
+ : bitstream_id_(bitstream_id),
+ input_record_(input_record),
+ output_record_(output_record),
+ config_store_(input_record + 1),
+ decoded_(false),
+ release_cb_(release_cb) {
+}
+
+V4L2SliceVideoDecodeAccelerator::V4L2DecodeSurface::~V4L2DecodeSurface() {
+ DVLOGF(5) << "Releasing output record id=" << output_record_;
+ release_cb_.Run(output_record_);
+}
+
+void V4L2SliceVideoDecodeAccelerator::V4L2DecodeSurface::SetReferenceSurfaces(
+ const std::vector<scoped_refptr<V4L2DecodeSurface>>& ref_surfaces) {
+ DCHECK(reference_surfaces_.empty());
+ reference_surfaces_ = ref_surfaces;
+}
+
+void V4L2SliceVideoDecodeAccelerator::V4L2DecodeSurface::SetDecoded() {
+ DCHECK(!decoded_);
+ decoded_ = true;
+
+ // We can now drop references to all reference surfaces for this surface
+ // as we are done with decoding.
+ reference_surfaces_.clear();
+}
+
+std::string V4L2SliceVideoDecodeAccelerator::V4L2DecodeSurface::ToString()
+ const {
+ std::string out;
+ base::StringAppendF(&out, "Buffer %d -> %d. ", input_record_, output_record_);
+ base::StringAppendF(&out, "Reference surfaces:");
+ for (const auto& ref : reference_surfaces_) {
+ DCHECK_NE(ref->output_record(), output_record_);
+ base::StringAppendF(&out, " %d", ref->output_record());
+ }
+ return out;
+}
+
+V4L2SliceVideoDecodeAccelerator::InputRecord::InputRecord()
+ : input_id(-1),
+ address(nullptr),
+ length(0),
+ bytes_used(0),
+ at_device(false) {
+}
+
+V4L2SliceVideoDecodeAccelerator::OutputRecord::OutputRecord()
+ : at_device(false),
+ at_client(false),
+ picture_id(-1),
+ egl_image(EGL_NO_IMAGE_KHR),
+ egl_sync(EGL_NO_SYNC_KHR),
+ cleared(false) {
+}
+
+struct V4L2SliceVideoDecodeAccelerator::BitstreamBufferRef {
+ BitstreamBufferRef(
+ base::WeakPtr<VideoDecodeAccelerator::Client>& client,
+ const scoped_refptr<base::SingleThreadTaskRunner>& client_task_runner,
+ base::SharedMemory* shm,
+ size_t size,
+ int32 input_id);
+ ~BitstreamBufferRef();
+ const base::WeakPtr<VideoDecodeAccelerator::Client> client;
+ const scoped_refptr<base::SingleThreadTaskRunner> client_task_runner;
+ const scoped_ptr<base::SharedMemory> shm;
+ const size_t size;
+ off_t bytes_used;
+ const int32 input_id;
+};
+
+V4L2SliceVideoDecodeAccelerator::BitstreamBufferRef::BitstreamBufferRef(
+ base::WeakPtr<VideoDecodeAccelerator::Client>& client,
+ const scoped_refptr<base::SingleThreadTaskRunner>& client_task_runner,
+ base::SharedMemory* shm,
+ size_t size,
+ int32 input_id)
+ : client(client),
+ client_task_runner(client_task_runner),
+ shm(shm),
+ size(size),
+ bytes_used(0),
+ input_id(input_id) {
+}
+
+V4L2SliceVideoDecodeAccelerator::BitstreamBufferRef::~BitstreamBufferRef() {
+ if (input_id >= 0) {
+ DVLOGF(5) << "returning input_id: " << input_id;
+ client_task_runner->PostTask(
+ FROM_HERE,
+ base::Bind(&VideoDecodeAccelerator::Client::NotifyEndOfBitstreamBuffer,
+ client, input_id));
+ }
+}
+
+struct V4L2SliceVideoDecodeAccelerator::EGLSyncKHRRef {
+ EGLSyncKHRRef(EGLDisplay egl_display, EGLSyncKHR egl_sync);
+ ~EGLSyncKHRRef();
+ EGLDisplay const egl_display;
+ EGLSyncKHR egl_sync;
+};
+
+V4L2SliceVideoDecodeAccelerator::EGLSyncKHRRef::EGLSyncKHRRef(
+ EGLDisplay egl_display,
+ EGLSyncKHR egl_sync)
+ : egl_display(egl_display), egl_sync(egl_sync) {
+}
+
+V4L2SliceVideoDecodeAccelerator::EGLSyncKHRRef::~EGLSyncKHRRef() {
+ // We don't check for eglDestroySyncKHR failures, because if we get here
+ // with a valid sync object, something went wrong and we are getting
+ // destroyed anyway.
+ if (egl_sync != EGL_NO_SYNC_KHR)
+ eglDestroySyncKHR(egl_display, egl_sync);
+}
+
+struct V4L2SliceVideoDecodeAccelerator::PictureRecord {
+ PictureRecord(bool cleared, const media::Picture& picture);
+ ~PictureRecord();
+ bool cleared; // Whether the texture is cleared and safe to render from.
+ media::Picture picture; // The decoded picture.
+};
+
+V4L2SliceVideoDecodeAccelerator::PictureRecord::PictureRecord(
+ bool cleared,
+ const media::Picture& picture)
+ : cleared(cleared), picture(picture) {
+}
+
+V4L2SliceVideoDecodeAccelerator::PictureRecord::~PictureRecord() {
+}
+
+class V4L2SliceVideoDecodeAccelerator::V4L2H264Accelerator
+ : public H264Decoder::H264Accelerator {
+ public:
+ V4L2H264Accelerator(V4L2SliceVideoDecodeAccelerator* v4l2_dec);
+ ~V4L2H264Accelerator() override;
+
+ // H264Decoder::H264Accelerator implementation.
+ scoped_refptr<H264Picture> CreateH264Picture() override;
+
+ bool SubmitFrameMetadata(const media::H264SPS* sps,
+ const media::H264PPS* pps,
+ const H264DPB& dpb,
+ const H264Picture::Vector& ref_pic_listp0,
+ const H264Picture::Vector& ref_pic_listb0,
+ const H264Picture::Vector& ref_pic_listb1,
+ const scoped_refptr<H264Picture>& pic) override;
+
+ bool SubmitSlice(const media::H264PPS* pps,
+ const media::H264SliceHeader* slice_hdr,
+ const H264Picture::Vector& ref_pic_list0,
+ const H264Picture::Vector& ref_pic_list1,
+ const scoped_refptr<H264Picture>& pic,
+ const uint8_t* data,
+ size_t size) override;
+
+ bool SubmitDecode(const scoped_refptr<H264Picture>& pic) override;
+ bool OutputPicture(const scoped_refptr<H264Picture>& pic) override;
+
+ void Reset() override;
+
+ private:
+ // Max size of reference list.
+ static const size_t kDPBIndicesListSize = 32;
+ void H264PictureListToDPBIndicesList(const H264Picture::Vector& src_pic_list,
+ uint8_t dst_list[kDPBIndicesListSize]);
+
+ void H264DPBToV4L2DPB(
+ const H264DPB& dpb,
+ std::vector<scoped_refptr<V4L2DecodeSurface>>* ref_surfaces);
+
+ scoped_refptr<V4L2DecodeSurface> H264PictureToV4L2DecodeSurface(
+ const scoped_refptr<H264Picture>& pic);
+
+ size_t num_slices_;
+ V4L2SliceVideoDecodeAccelerator* v4l2_dec_;
+
+ // TODO(posciak): This should be queried from hardware once supported.
+ static const size_t kMaxSlices = 16;
+ struct v4l2_ctrl_h264_slice_param v4l2_slice_params_[kMaxSlices];
+ struct v4l2_ctrl_h264_decode_param v4l2_decode_param_;
+
+ DISALLOW_COPY_AND_ASSIGN(V4L2H264Accelerator);
+};
+
+class V4L2SliceVideoDecodeAccelerator::V4L2VP8Accelerator
+ : public VP8Decoder::VP8Accelerator {
+ public:
+ V4L2VP8Accelerator(V4L2SliceVideoDecodeAccelerator* v4l2_dec);
+ ~V4L2VP8Accelerator() override;
+
+ // VP8Decoder::VP8Accelerator implementation.
+ scoped_refptr<VP8Picture> CreateVP8Picture() override;
+
+ bool SubmitDecode(const scoped_refptr<VP8Picture>& pic,
+ const media::Vp8FrameHeader* frame_hdr,
+ const scoped_refptr<VP8Picture>& last_frame,
+ const scoped_refptr<VP8Picture>& golden_frame,
+ const scoped_refptr<VP8Picture>& alt_frame) override;
+
+ bool OutputPicture(const scoped_refptr<VP8Picture>& pic) override;
+
+ private:
+ scoped_refptr<V4L2DecodeSurface> VP8PictureToV4L2DecodeSurface(
+ const scoped_refptr<VP8Picture>& pic);
+
+ V4L2SliceVideoDecodeAccelerator* v4l2_dec_;
+
+ DISALLOW_COPY_AND_ASSIGN(V4L2VP8Accelerator);
+};
+
+// Codec-specific subclasses of software decoder picture classes.
+// This allows us to keep decoders oblivious of our implementation details.
+class V4L2H264Picture : public H264Picture {
+ public:
+ V4L2H264Picture(const scoped_refptr<
+ V4L2SliceVideoDecodeAccelerator::V4L2DecodeSurface>& dec_surface);
+
+ V4L2H264Picture* AsV4L2H264Picture() override { return this; }
+ scoped_refptr<V4L2SliceVideoDecodeAccelerator::V4L2DecodeSurface>
+ dec_surface() {
+ return dec_surface_;
+ }
+
+ private:
+ ~V4L2H264Picture() override;
+
+ scoped_refptr<V4L2SliceVideoDecodeAccelerator::V4L2DecodeSurface>
+ dec_surface_;
+
+ DISALLOW_COPY_AND_ASSIGN(V4L2H264Picture);
+};
+
+V4L2H264Picture::V4L2H264Picture(const scoped_refptr<
+ V4L2SliceVideoDecodeAccelerator::V4L2DecodeSurface>& dec_surface)
+ : dec_surface_(dec_surface) {
+}
+
+V4L2H264Picture::~V4L2H264Picture() {
+}
+
+class V4L2VP8Picture : public VP8Picture {
+ public:
+ V4L2VP8Picture(const scoped_refptr<
+ V4L2SliceVideoDecodeAccelerator::V4L2DecodeSurface>& dec_surface);
+
+ V4L2VP8Picture* AsV4L2VP8Picture() override { return this; }
+ scoped_refptr<V4L2SliceVideoDecodeAccelerator::V4L2DecodeSurface>
+ dec_surface() {
+ return dec_surface_;
+ }
+
+ private:
+ ~V4L2VP8Picture() override;
+
+ scoped_refptr<V4L2SliceVideoDecodeAccelerator::V4L2DecodeSurface>
+ dec_surface_;
+
+ DISALLOW_COPY_AND_ASSIGN(V4L2VP8Picture);
+};
+
+V4L2VP8Picture::V4L2VP8Picture(const scoped_refptr<
+ V4L2SliceVideoDecodeAccelerator::V4L2DecodeSurface>& dec_surface)
+ : dec_surface_(dec_surface) {
+}
+
+V4L2VP8Picture::~V4L2VP8Picture() {
+}
+
+V4L2SliceVideoDecodeAccelerator::V4L2SliceVideoDecodeAccelerator(
+ const scoped_refptr<V4L2Device>& device,
+ EGLDisplay egl_display,
+ EGLContext egl_context,
+ const base::WeakPtr<Client>& io_client,
+ const base::Callback<bool(void)>& make_context_current,
+ const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
+ : input_planes_count_(0),
+ output_planes_count_(0),
+ child_task_runner_(base::ThreadTaskRunnerHandle::Get()),
+ io_task_runner_(io_task_runner),
+ io_client_(io_client),
+ device_(device),
+ decoder_thread_("V4L2SliceVideoDecodeAcceleratorThread"),
+ device_poll_thread_("V4L2SliceVideoDecodeAcceleratorDevicePollThread"),
+ input_streamon_(false),
+ input_buffer_queued_count_(0),
+ output_streamon_(false),
+ output_buffer_queued_count_(0),
+ video_profile_(media::VIDEO_CODEC_PROFILE_UNKNOWN),
+ output_format_fourcc_(0),
+ state_(kUninitialized),
+ decoder_flushing_(false),
+ decoder_resetting_(false),
+ surface_set_change_pending_(false),
+ picture_clearing_count_(0),
+ pictures_assigned_(false, false),
+ make_context_current_(make_context_current),
+ egl_display_(egl_display),
+ egl_context_(egl_context),
+ weak_this_factory_(this) {
+ weak_this_ = weak_this_factory_.GetWeakPtr();
+}
+
+V4L2SliceVideoDecodeAccelerator::~V4L2SliceVideoDecodeAccelerator() {
+ DVLOGF(2);
+
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
+ DCHECK(!decoder_thread_.IsRunning());
+ DCHECK(!device_poll_thread_.IsRunning());
+
+ DCHECK(input_buffer_map_.empty());
+ DCHECK(output_buffer_map_.empty());
+}
+
+void V4L2SliceVideoDecodeAccelerator::NotifyError(Error error) {
+ if (!child_task_runner_->BelongsToCurrentThread()) {
+ child_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::NotifyError,
+ weak_this_, error));
+ return;
+ }
+
+ if (client_) {
+ client_->NotifyError(error);
+ client_ptr_factory_.reset();
+ }
+}
+
+bool V4L2SliceVideoDecodeAccelerator::Initialize(
+ media::VideoCodecProfile profile,
+ VideoDecodeAccelerator::Client* client) {
+ DVLOGF(3) << "profile: " << profile;
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
+ DCHECK_EQ(state_, kUninitialized);
+
+ client_ptr_factory_.reset(
+ new base::WeakPtrFactory<VideoDecodeAccelerator::Client>(client));
+ client_ = client_ptr_factory_->GetWeakPtr();
+
+ video_profile_ = profile;
+
+ if (video_profile_ >= media::H264PROFILE_MIN &&
+ video_profile_ <= media::H264PROFILE_MAX) {
+ h264_accelerator_.reset(new V4L2H264Accelerator(this));
+ decoder_.reset(new H264Decoder(h264_accelerator_.get()));
+ } else if (video_profile_ >= media::VP8PROFILE_MIN &&
+ video_profile_ <= media::VP8PROFILE_MAX) {
+ vp8_accelerator_.reset(new V4L2VP8Accelerator(this));
+ decoder_.reset(new VP8Decoder(vp8_accelerator_.get()));
+ } else {
+ DLOG(ERROR) << "Unsupported profile " << video_profile_;
+ return false;
+ }
+
+ // TODO(posciak): This needs to be queried once supported.
+ input_planes_count_ = 1;
+ output_planes_count_ = 1;
+
+ if (egl_display_ == EGL_NO_DISPLAY) {
+ LOG(ERROR) << "Initialize(): could not get EGLDisplay";
+ return false;
+ }
+
+ // We need the context to be initialized to query extensions.
+ if (!make_context_current_.Run()) {
+ LOG(ERROR) << "Initialize(): could not make context current";
+ return false;
+ }
+
+ if (!gfx::g_driver_egl.ext.b_EGL_KHR_fence_sync) {
+ LOG(ERROR) << "Initialize(): context does not have EGL_KHR_fence_sync";
+ return false;
+ }
+
+ // Capabilities check.
+ struct v4l2_capability caps;
+ const __u32 kCapsRequired =
+ V4L2_CAP_VIDEO_CAPTURE_MPLANE |
+ V4L2_CAP_VIDEO_OUTPUT_MPLANE |
+ V4L2_CAP_STREAMING;
+ IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYCAP, &caps);
+ if ((caps.capabilities & kCapsRequired) != kCapsRequired) {
+ DLOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP"
+ ", caps check failed: 0x" << std::hex << caps.capabilities;
+ return false;
+ }
+
+ if (!SetupFormats())
+ return false;
+
+ if (!decoder_thread_.Start()) {
+ DLOG(ERROR) << "Initialize(): device thread failed to start";
+ return false;
+ }
+ decoder_thread_task_runner_ = decoder_thread_.task_runner();
+
+ state_ = kInitialized;
+
+ // InitializeTask will NOTIFY_ERROR on failure.
+ decoder_thread_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::InitializeTask,
+ base::Unretained(this)));
+
+ DVLOGF(1) << "V4L2SliceVideoDecodeAccelerator initialized";
+ return true;
+}
+
+void V4L2SliceVideoDecodeAccelerator::InitializeTask() {
+ DVLOGF(3);
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+ DCHECK_EQ(state_, kInitialized);
+
+ if (!CreateInputBuffers())
+ NOTIFY_ERROR(PLATFORM_FAILURE);
+
+ // Output buffers will be created once decoder gives us information
+ // about their size and required count.
+ state_ = kDecoding;
+}
+
+void V4L2SliceVideoDecodeAccelerator::Destroy() {
+ DVLOGF(3);
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
+
+ if (decoder_thread_.IsRunning()) {
+ decoder_thread_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::DestroyTask,
+ base::Unretained(this)));
+
+ // Wait for tasks to finish/early-exit.
+ decoder_thread_.Stop();
+ }
+
+ delete this;
+ DVLOGF(3) << "Destroyed";
+}
+
+void V4L2SliceVideoDecodeAccelerator::DestroyTask() {
+ DVLOGF(3);
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+
+ state_ = kError;
+
+ decoder_->Reset();
+
+ decoder_current_bitstream_buffer_.reset();
+ while (!decoder_input_queue_.empty())
+ decoder_input_queue_.pop();
+
+ // Stop streaming and the device_poll_thread_.
+ StopDevicePoll(false);
+
+ DestroyInputBuffers();
+ DestroyOutputs(false);
+
+ DCHECK(surfaces_at_device_.empty());
+ DCHECK(surfaces_at_display_.empty());
+ DCHECK(decoder_display_queue_.empty());
+}
+
+bool V4L2SliceVideoDecodeAccelerator::SetupFormats() {
+ DCHECK_EQ(state_, kUninitialized);
+
+ __u32 input_format_fourcc =
+ V4L2Device::VideoCodecProfileToV4L2PixFmt(video_profile_, true);
+ if (!input_format_fourcc) {
+ NOTREACHED();
+ return false;
+ }
+
+ size_t input_size;
+ gfx::Size max_resolution, min_resolution;
+ device_->GetSupportedResolution(input_format_fourcc, &min_resolution,
+ &max_resolution);
+ if (max_resolution.width() > 1920 && max_resolution.height() > 1088)
+ input_size = kInputBufferMaxSizeFor4k;
+ else
+ input_size = kInputBufferMaxSizeFor1080p;
+
+ struct v4l2_format format;
+ memset(&format, 0, sizeof(format));
+ format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ format.fmt.pix_mp.pixelformat = input_format_fourcc;
+ format.fmt.pix_mp.plane_fmt[0].sizeimage = input_size;
+ format.fmt.pix_mp.num_planes = input_planes_count_;
+ IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT, &format);
+
+ // We have to set up the format for output, because the driver may not allow
+ // changing it once we start streaming; whether it can support our chosen
+ // output format or not may depend on the input format.
+ struct v4l2_fmtdesc fmtdesc;
+ memset(&fmtdesc, 0, sizeof(fmtdesc));
+ fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ output_format_fourcc_ = 0;
+ while (device_->Ioctl(VIDIOC_ENUM_FMT, &fmtdesc) == 0) {
+ if (device_->CanCreateEGLImageFrom(fmtdesc.pixelformat)) {
+ output_format_fourcc_ = fmtdesc.pixelformat;
+ break;
+ }
+ ++fmtdesc.index;
+ }
+
+ if (output_format_fourcc_ == 0) {
+ LOG(ERROR) << "Could not find a usable output format";
+ return false;
+ }
+
+ // Only set fourcc for output; resolution, etc., will come from the
+ // driver once it extracts it from the stream.
+ memset(&format, 0, sizeof(format));
+ format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ format.fmt.pix_mp.pixelformat = output_format_fourcc_;
+ format.fmt.pix_mp.num_planes = output_planes_count_;
+ IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT, &format);
+
+ return true;
+}
+
+bool V4L2SliceVideoDecodeAccelerator::CreateInputBuffers() {
+ DVLOGF(3);
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+ DCHECK(!input_streamon_);
+ DCHECK(input_buffer_map_.empty());
+
+ struct v4l2_requestbuffers reqbufs;
+ memset(&reqbufs, 0, sizeof(reqbufs));
+ reqbufs.count = kNumInputBuffers;
+ reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ reqbufs.memory = V4L2_MEMORY_MMAP;
+ IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS, &reqbufs);
+ if (reqbufs.count < kNumInputBuffers) {
+ PLOG(ERROR) << "Could not allocate enough output buffers";
+ return false;
+ }
+ input_buffer_map_.resize(reqbufs.count);
+ for (size_t i = 0; i < input_buffer_map_.size(); ++i) {
+ free_input_buffers_.push_back(i);
+
+ // Query for the MEMORY_MMAP pointer.
+ struct v4l2_plane planes[VIDEO_MAX_PLANES];
+ struct v4l2_buffer buffer;
+ memset(&buffer, 0, sizeof(buffer));
+ memset(planes, 0, sizeof(planes));
+ buffer.index = i;
+ buffer.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ buffer.memory = V4L2_MEMORY_MMAP;
+ buffer.m.planes = planes;
+ buffer.length = input_planes_count_;
+ IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYBUF, &buffer);
+ void* address = device_->Mmap(nullptr,
+ buffer.m.planes[0].length,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED,
+ buffer.m.planes[0].m.mem_offset);
+ if (address == MAP_FAILED) {
+ PLOG(ERROR) << "CreateInputBuffers(): mmap() failed";
+ return false;
+ }
+ input_buffer_map_[i].address = address;
+ input_buffer_map_[i].length = buffer.m.planes[0].length;
+ }
+
+ return true;
+}
+
+bool V4L2SliceVideoDecodeAccelerator::CreateOutputBuffers() {
+ DVLOGF(3);
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+ DCHECK(!output_streamon_);
+ DCHECK(output_buffer_map_.empty());
+ DCHECK(surfaces_at_display_.empty());
+ DCHECK(surfaces_at_device_.empty());
+
+ visible_size_ = decoder_->GetPicSize();
+ size_t num_pictures = decoder_->GetRequiredNumOfPictures();
+
+ DCHECK_GT(num_pictures, 0u);
+ DCHECK(!visible_size_.IsEmpty());
+
+ struct v4l2_format format;
+ memset(&format, 0, sizeof(format));
+ format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ format.fmt.pix_mp.pixelformat = output_format_fourcc_;
+ format.fmt.pix_mp.width = visible_size_.width();
+ format.fmt.pix_mp.height = visible_size_.height();
+ format.fmt.pix_mp.num_planes = input_planes_count_;
+
+ if (device_->Ioctl(VIDIOC_S_FMT, &format) != 0) {
+ PLOG(ERROR) << "Failed setting format to: " << output_format_fourcc_;
+ NOTIFY_ERROR(PLATFORM_FAILURE);
+ return false;
+ }
+
+ coded_size_.SetSize(base::checked_cast<int>(format.fmt.pix_mp.width),
+ base::checked_cast<int>(format.fmt.pix_mp.height));
+ DCHECK_EQ(coded_size_.width() % 16, 0);
+ DCHECK_EQ(coded_size_.height() % 16, 0);
+
+ if (!gfx::Rect(coded_size_).Contains(gfx::Rect(visible_size_))) {
+ LOG(ERROR) << "Got invalid adjusted coded size: " << coded_size_.ToString();
+ return false;
+ }
+
+ struct v4l2_requestbuffers reqbufs;
+ memset(&reqbufs, 0, sizeof(reqbufs));
+ reqbufs.count = num_pictures;
+ reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ reqbufs.memory = V4L2_MEMORY_MMAP;
+ IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS, &reqbufs);
+
+ if (reqbufs.count < num_pictures) {
+ PLOG(ERROR) << "Could not allocate enough output buffers";
+ return false;
+ }
+
+ output_buffer_map_.resize(reqbufs.count);
+
+ DVLOGF(3) << "buffer_count=" << output_buffer_map_.size()
+ << ", visible size=" << visible_size_.ToString()
+ << ", coded size=" << coded_size_.ToString();
+
+ child_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&VideoDecodeAccelerator::Client::ProvidePictureBuffers,
+ client_, output_buffer_map_.size(), coded_size_,
+ device_->GetTextureTarget()));
+
+ // Wait for the client to call AssignPictureBuffers() on the Child thread.
+ // We do this, because if we continue decoding without finishing buffer
+ // allocation, we may end up Resetting before AssignPictureBuffers arrives,
+ // resulting in unnecessary complications and subtle bugs.
+ pictures_assigned_.Wait();
+
+ return true;
+}
+
+void V4L2SliceVideoDecodeAccelerator::DestroyInputBuffers() {
+ DVLOGF(3);
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread() ||
+ !decoder_thread_.IsRunning());
+ DCHECK(!input_streamon_);
+
+ for (auto& input_record : input_buffer_map_) {
+ if (input_record.address != nullptr)
+ device_->Munmap(input_record.address, input_record.length);
+ }
+
+ struct v4l2_requestbuffers reqbufs;
+ memset(&reqbufs, 0, sizeof(reqbufs));
+ reqbufs.count = 0;
+ reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ reqbufs.memory = V4L2_MEMORY_MMAP;
+ IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS, &reqbufs);
+
+ input_buffer_map_.clear();
+ free_input_buffers_.clear();
+}
+
+void V4L2SliceVideoDecodeAccelerator::DismissPictures(
+ std::vector<int32> picture_buffer_ids,
+ base::WaitableEvent* done) {
+ DVLOGF(3);
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
+
+ for (auto picture_buffer_id : picture_buffer_ids) {
+ DVLOGF(1) << "dismissing PictureBuffer id=" << picture_buffer_id;
+ client_->DismissPictureBuffer(picture_buffer_id);
+ }
+
+ done->Signal();
+}
+
+void V4L2SliceVideoDecodeAccelerator::DevicePollTask(bool poll_device) {
+ DVLOGF(4);
+ DCHECK_EQ(device_poll_thread_.message_loop(), base::MessageLoop::current());
+
+ bool event_pending;
+ if (!device_->Poll(poll_device, &event_pending)) {
+ NOTIFY_ERROR(PLATFORM_FAILURE);
+ return;
+ }
+
+ // All processing should happen on ServiceDeviceTask(), since we shouldn't
+ // touch encoder state from this thread.
+ decoder_thread_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::ServiceDeviceTask,
+ base::Unretained(this)));
+}
+
+void V4L2SliceVideoDecodeAccelerator::ServiceDeviceTask() {
+ DVLOGF(4);
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+
+ // ServiceDeviceTask() should only ever be scheduled from DevicePollTask().
+
+ Dequeue();
+ SchedulePollIfNeeded();
+}
+
+void V4L2SliceVideoDecodeAccelerator::SchedulePollIfNeeded() {
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+
+ if (!device_poll_thread_.IsRunning()) {
+ DVLOGF(2) << "Device poll thread stopped, will not schedule poll";
+ return;
+ }
+
+ DCHECK(input_streamon_ || output_streamon_);
+
+ if (input_buffer_queued_count_ + output_buffer_queued_count_ == 0) {
+ DVLOGF(4) << "No buffers queued, will not schedule poll";
+ return;
+ }
+
+ DVLOGF(4) << "Scheduling device poll task";
+
+ device_poll_thread_.message_loop()->PostTask(
+ FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::DevicePollTask,
+ base::Unretained(this), true));
+
+ DVLOGF(2) << "buffer counts: "
+ << "INPUT[" << decoder_input_queue_.size() << "]"
+ << " => DEVICE["
+ << free_input_buffers_.size() << "+"
+ << input_buffer_queued_count_ << "/"
+ << input_buffer_map_.size() << "]->["
+ << free_output_buffers_.size() << "+"
+ << output_buffer_queued_count_ << "/"
+ << output_buffer_map_.size() << "]"
+ << " => DISPLAYQ[" << decoder_display_queue_.size() << "]"
+ << " => CLIENT[" << surfaces_at_display_.size() << "]";
+}
+
+void V4L2SliceVideoDecodeAccelerator::Enqueue(
+ const scoped_refptr<V4L2DecodeSurface>& dec_surface) {
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+
+ const int old_inputs_queued = input_buffer_queued_count_;
+ const int old_outputs_queued = output_buffer_queued_count_;
+
+ if (!EnqueueInputRecord(dec_surface->input_record(),
+ dec_surface->config_store())) {
+ DVLOGF(1) << "Failed queueing an input buffer";
+ NOTIFY_ERROR(PLATFORM_FAILURE);
+ return;
+ }
+
+ if (!EnqueueOutputRecord(dec_surface->output_record())) {
+ DVLOGF(1) << "Failed queueing an output buffer";
+ NOTIFY_ERROR(PLATFORM_FAILURE);
+ return;
+ }
+
+ bool inserted =
+ surfaces_at_device_.insert(std::make_pair(dec_surface->output_record(),
+ dec_surface)).second;
+ DCHECK(inserted);
+
+ if (old_inputs_queued == 0 && old_outputs_queued == 0)
+ SchedulePollIfNeeded();
+}
+
+void V4L2SliceVideoDecodeAccelerator::Dequeue() {
+ DVLOGF(3);
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+
+ struct v4l2_buffer dqbuf;
+ struct v4l2_plane planes[VIDEO_MAX_PLANES];
+ while (input_buffer_queued_count_ > 0) {
+ DCHECK(input_streamon_);
+ memset(&dqbuf, 0, sizeof(dqbuf));
+ memset(&planes, 0, sizeof(planes));
+ dqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ dqbuf.memory = V4L2_MEMORY_USERPTR;
+ dqbuf.m.planes = planes;
+ dqbuf.length = input_planes_count_;
+ if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) {
+ if (errno == EAGAIN) {
+ // EAGAIN if we're just out of buffers to dequeue.
+ break;
+ }
+ PLOG(ERROR) << "ioctl() failed: VIDIOC_DQBUF";
+ NOTIFY_ERROR(PLATFORM_FAILURE);
+ return;
+ }
+ InputRecord& input_record = input_buffer_map_[dqbuf.index];
+ DCHECK(input_record.at_device);
+ input_record.at_device = false;
+ ReuseInputBuffer(dqbuf.index);
+ input_buffer_queued_count_--;
+ DVLOGF(4) << "Dequeued input=" << dqbuf.index
+ << " count: " << input_buffer_queued_count_;
+ }
+
+ while (output_buffer_queued_count_ > 0) {
+ DCHECK(output_streamon_);
+ memset(&dqbuf, 0, sizeof(dqbuf));
+ memset(&planes, 0, sizeof(planes));
+ dqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ dqbuf.memory = V4L2_MEMORY_MMAP;
+ dqbuf.m.planes = planes;
+ dqbuf.length = output_planes_count_;
+ if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) {
+ if (errno == EAGAIN) {
+ // EAGAIN if we're just out of buffers to dequeue.
+ break;
+ }
+ PLOG(ERROR) << "ioctl() failed: VIDIOC_DQBUF";
+ NOTIFY_ERROR(PLATFORM_FAILURE);
+ return;
+ }
+ OutputRecord& output_record = output_buffer_map_[dqbuf.index];
+ DCHECK(output_record.at_device);
+ output_record.at_device = false;
+ output_buffer_queued_count_--;
+ DVLOGF(3) << "Dequeued output=" << dqbuf.index
+ << " count " << output_buffer_queued_count_;
+
+ V4L2DecodeSurfaceByOutputId::iterator it =
+ surfaces_at_device_.find(dqbuf.index);
+ if (it == surfaces_at_device_.end()) {
+ DLOG(ERROR) << "Got invalid surface from device.";
+ NOTIFY_ERROR(PLATFORM_FAILURE);
+ }
+
+ it->second->SetDecoded();
+ surfaces_at_device_.erase(it);
+ }
+
+ // A frame was decoded, see if we can output it.
+ TryOutputSurfaces();
+
+ ProcessPendingEventsIfNeeded();
+}
+
+void V4L2SliceVideoDecodeAccelerator::ProcessPendingEventsIfNeeded() {
+ // Process pending events, if any, in the correct order.
+ // We always first process the surface set change, as it is an internal
+ // event from the decoder and interleaving it with external requests would
+ // put the decoder in an undefined state.
+ FinishSurfaceSetChangeIfNeeded();
+
+ // Process external (client) requests.
+ FinishFlushIfNeeded();
+ FinishResetIfNeeded();
+}
+
+void V4L2SliceVideoDecodeAccelerator::ReuseInputBuffer(int index) {
+ DVLOGF(4) << "Reusing input buffer, index=" << index;
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+
+ DCHECK_LT(index, static_cast<int>(input_buffer_map_.size()));
+ InputRecord& input_record = input_buffer_map_[index];
+
+ DCHECK(!input_record.at_device);
+ input_record.input_id = -1;
+ input_record.bytes_used = 0;
+
+ DCHECK_EQ(std::count(free_input_buffers_.begin(), free_input_buffers_.end(),
+ index), 0);
+ free_input_buffers_.push_back(index);
+}
+
+void V4L2SliceVideoDecodeAccelerator::ReuseOutputBuffer(int index) {
+ DVLOGF(4) << "Reusing output buffer, index=" << index;
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+
+ DCHECK_LT(index, static_cast<int>(output_buffer_map_.size()));
+ OutputRecord& output_record = output_buffer_map_[index];
+ DCHECK(!output_record.at_device);
+ DCHECK(!output_record.at_client);
+
+ DCHECK_EQ(std::count(free_output_buffers_.begin(), free_output_buffers_.end(),
+ index), 0);
+ free_output_buffers_.push_back(index);
+
+ ScheduleDecodeBufferTaskIfNeeded();
+}
+
+bool V4L2SliceVideoDecodeAccelerator::EnqueueInputRecord(
+ int index,
+ uint32_t config_store) {
+ DVLOGF(3);
+ DCHECK_LT(index, static_cast<int>(input_buffer_map_.size()));
+ DCHECK_GT(config_store, 0u);
+
+ // Enqueue an input (VIDEO_OUTPUT) buffer for an input video frame.
+ InputRecord& input_record = input_buffer_map_[index];
+ DCHECK(!input_record.at_device);
+ struct v4l2_buffer qbuf;
+ struct v4l2_plane qbuf_planes[VIDEO_MAX_PLANES];
+ memset(&qbuf, 0, sizeof(qbuf));
+ memset(qbuf_planes, 0, sizeof(qbuf_planes));
+ qbuf.index = index;
+ qbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ qbuf.memory = V4L2_MEMORY_MMAP;
+ qbuf.m.planes = qbuf_planes;
+ qbuf.m.planes[0].bytesused = input_record.bytes_used;
+ qbuf.length = input_planes_count_;
+ qbuf.config_store = config_store;
+ IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf);
+ input_record.at_device = true;
+ input_buffer_queued_count_++;
+ DVLOGF(4) << "Enqueued input=" << qbuf.index
+ << " count: " << input_buffer_queued_count_;
+
+ return true;
+}
+
+bool V4L2SliceVideoDecodeAccelerator::EnqueueOutputRecord(int index) {
+ DVLOGF(3);
+ DCHECK_LT(index, static_cast<int>(output_buffer_map_.size()));
+
+ // Enqueue an output (VIDEO_CAPTURE) buffer.
+ OutputRecord& output_record = output_buffer_map_[index];
+ DCHECK(!output_record.at_device);
+ DCHECK(!output_record.at_client);
+ DCHECK_NE(output_record.egl_image, EGL_NO_IMAGE_KHR);
+ DCHECK_NE(output_record.picture_id, -1);
+
+ if (output_record.egl_sync != EGL_NO_SYNC_KHR) {
+ // If we have to wait for completion, wait. Note that
+ // free_output_buffers_ is a FIFO queue, so we always wait on the
+ // buffer that has been in the queue the longest.
+ if (eglClientWaitSyncKHR(egl_display_, output_record.egl_sync, 0,
+ EGL_FOREVER_KHR) == EGL_FALSE) {
+ // This will cause tearing, but is safe otherwise.
+ DVLOGF(1) << "eglClientWaitSyncKHR failed!";
+ }
+ if (eglDestroySyncKHR(egl_display_, output_record.egl_sync) != EGL_TRUE) {
+ LOGF(ERROR) << "eglDestroySyncKHR failed!";
+ NOTIFY_ERROR(PLATFORM_FAILURE);
+ return false;
+ }
+ output_record.egl_sync = EGL_NO_SYNC_KHR;
+ }
+
+ struct v4l2_buffer qbuf;
+ struct v4l2_plane qbuf_planes[VIDEO_MAX_PLANES];
+ memset(&qbuf, 0, sizeof(qbuf));
+ memset(qbuf_planes, 0, sizeof(qbuf_planes));
+ qbuf.index = index;
+ qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ qbuf.memory = V4L2_MEMORY_MMAP;
+ qbuf.m.planes = qbuf_planes;
+ qbuf.length = output_planes_count_;
+ IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf);
+ output_record.at_device = true;
+ output_buffer_queued_count_++;
+ DVLOGF(4) << "Enqueued output=" << qbuf.index
+ << " count: " << output_buffer_queued_count_;
+
+ return true;
+}
+
+bool V4L2SliceVideoDecodeAccelerator::StartDevicePoll() {
+ DVLOGF(3) << "Starting device poll";
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+ DCHECK(!device_poll_thread_.IsRunning());
+
+ // Start up the device poll thread and schedule its first DevicePollTask().
+ if (!device_poll_thread_.Start()) {
+ DLOG(ERROR) << "StartDevicePoll(): Device thread failed to start";
+ NOTIFY_ERROR(PLATFORM_FAILURE);
+ return false;
+ }
+ if (!input_streamon_) {
+ __u32 type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_STREAMON, &type);
+ input_streamon_ = true;
+ }
+
+ if (!output_streamon_) {
+ __u32 type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_STREAMON, &type);
+ output_streamon_ = true;
+ }
+
+ device_poll_thread_.message_loop()->PostTask(
+ FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::DevicePollTask,
+ base::Unretained(this), true));
+
+ return true;
+}
+
+bool V4L2SliceVideoDecodeAccelerator::StopDevicePoll(bool keep_input_state) {
+ DVLOGF(3) << "Stopping device poll";
+ if (decoder_thread_.IsRunning())
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+
+ // Signal the DevicePollTask() to stop, and stop the device poll thread.
+ if (!device_->SetDevicePollInterrupt()) {
+ PLOG(ERROR) << "SetDevicePollInterrupt(): failed";
+ NOTIFY_ERROR(PLATFORM_FAILURE);
+ return false;
+ }
+ device_poll_thread_.Stop();
+ DVLOGF(3) << "Device poll thread stopped";
+
+ // Clear the interrupt now, to be sure.
+ if (!device_->ClearDevicePollInterrupt()) {
+ NOTIFY_ERROR(PLATFORM_FAILURE);
+ return false;
+ }
+
+ if (!keep_input_state) {
+ if (input_streamon_) {
+ __u32 type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_STREAMOFF, &type);
+ }
+ input_streamon_ = false;
+ }
+
+ if (output_streamon_) {
+ __u32 type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_STREAMOFF, &type);
+ }
+ output_streamon_ = false;
+
+ if (!keep_input_state) {
+ for (size_t i = 0; i < input_buffer_map_.size(); ++i) {
+ InputRecord& input_record = input_buffer_map_[i];
+ if (input_record.at_device) {
+ input_record.at_device = false;
+ ReuseInputBuffer(i);
+ input_buffer_queued_count_--;
+ }
+ }
+ DCHECK_EQ(input_buffer_queued_count_, 0);
+ }
+
+ // STREAMOFF makes the driver drop all buffers without decoding and DQBUFing,
+ // so we mark them all as at_device = false and clear surfaces_at_device_.
+ for (size_t i = 0; i < output_buffer_map_.size(); ++i) {
+ OutputRecord& output_record = output_buffer_map_[i];
+ if (output_record.at_device) {
+ output_record.at_device = false;
+ output_buffer_queued_count_--;
+ }
+ }
+ surfaces_at_device_.clear();
+ DCHECK_EQ(output_buffer_queued_count_, 0);
+
+ // Drop all surfaces that were awaiting decode before being displayed,
+ // since we've just cancelled all outstanding decodes.
+ while (!decoder_display_queue_.empty())
+ decoder_display_queue_.pop();
+
+ DVLOGF(3) << "Device poll stopped";
+ return true;
+}
+
+void V4L2SliceVideoDecodeAccelerator::Decode(
+ const media::BitstreamBuffer& bitstream_buffer) {
+ DVLOGF(3) << "input_id=" << bitstream_buffer.id()
+ << ", size=" << bitstream_buffer.size();
+ DCHECK(io_task_runner_->BelongsToCurrentThread());
+
+ decoder_thread_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::DecodeTask,
+ base::Unretained(this), bitstream_buffer));
+}
+
+void V4L2SliceVideoDecodeAccelerator::DecodeTask(
+ const media::BitstreamBuffer& bitstream_buffer) {
+ DVLOGF(3) << "input_id=" << bitstream_buffer.id()
+ << " size=" << bitstream_buffer.size();
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+
+ scoped_ptr<BitstreamBufferRef> bitstream_record(new BitstreamBufferRef(
+ io_client_, io_task_runner_,
+ new base::SharedMemory(bitstream_buffer.handle(), true),
+ bitstream_buffer.size(), bitstream_buffer.id()));
+ if (!bitstream_record->shm->Map(bitstream_buffer.size())) {
+ LOGF(ERROR) << "Could not map bitstream_buffer";
+ NOTIFY_ERROR(UNREADABLE_INPUT);
+ return;
+ }
+ DVLOGF(3) << "mapped at=" << bitstream_record->shm->memory();
+
+ decoder_input_queue_.push(
+ linked_ptr<BitstreamBufferRef>(bitstream_record.release()));
+
+ ScheduleDecodeBufferTaskIfNeeded();
+}
+
+bool V4L2SliceVideoDecodeAccelerator::TrySetNewBistreamBuffer() {
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+ DCHECK(!decoder_current_bitstream_buffer_);
+
+ if (decoder_input_queue_.empty())
+ return false;
+
+ decoder_current_bitstream_buffer_.reset(
+ decoder_input_queue_.front().release());
+ decoder_input_queue_.pop();
+
+ if (decoder_current_bitstream_buffer_->input_id == kFlushBufferId) {
+ // This is a buffer we queued for ourselves to trigger flush at this time.
+ InitiateFlush();
+ return false;
+ }
+
+ const uint8_t* const data = reinterpret_cast<const uint8_t*>(
+ decoder_current_bitstream_buffer_->shm->memory());
+ const size_t data_size = decoder_current_bitstream_buffer_->size;
+ decoder_->SetStream(data, data_size);
+
+ return true;
+}
+
+void V4L2SliceVideoDecodeAccelerator::ScheduleDecodeBufferTaskIfNeeded() {
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+ if (state_ == kDecoding) {
+ decoder_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&V4L2SliceVideoDecodeAccelerator::DecodeBufferTask,
+ base::Unretained(this)));
+ }
+}
+
+void V4L2SliceVideoDecodeAccelerator::DecodeBufferTask() {
+ DVLOGF(3);
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+
+ if (state_ != kDecoding) {
+ DVLOGF(3) << "Early exit, not in kDecoding";
+ return;
+ }
+
+ while (true) {
+ AcceleratedVideoDecoder::DecodeResult res;
+ res = decoder_->Decode();
+ switch (res) {
+ case AcceleratedVideoDecoder::kAllocateNewSurfaces:
+ DVLOGF(2) << "Decoder requesting a new set of surfaces";
+ InitiateSurfaceSetChange();
+ return;
+
+ case AcceleratedVideoDecoder::kRanOutOfStreamData:
+ decoder_current_bitstream_buffer_.reset();
+ if (!TrySetNewBistreamBuffer())
+ return;
+
+ break;
+
+ case AcceleratedVideoDecoder::kRanOutOfSurfaces:
+ // No more surfaces for the decoder, we'll come back once we have more.
+ DVLOGF(4) << "Ran out of surfaces";
+ return;
+
+ case AcceleratedVideoDecoder::kDecodeError:
+ DVLOGF(1) << "Error decoding stream";
+ NOTIFY_ERROR(PLATFORM_FAILURE);
+ return;
+ }
+ }
+}
+
+void V4L2SliceVideoDecodeAccelerator::InitiateSurfaceSetChange() {
+ DVLOGF(2);
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+
+ DCHECK_EQ(state_, kDecoding);
+ state_ = kIdle;
+
+ DCHECK(!surface_set_change_pending_);
+ surface_set_change_pending_ = true;
+
+ FinishSurfaceSetChangeIfNeeded();
+}
+
+void V4L2SliceVideoDecodeAccelerator::FinishSurfaceSetChangeIfNeeded() {
+ DVLOGF(2);
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+
+ if (!surface_set_change_pending_ || !surfaces_at_device_.empty())
+ return;
+
+ DCHECK_EQ(state_, kIdle);
+ DCHECK(decoder_display_queue_.empty());
+ // All output buffers should've been returned from decoder and device by now.
+ // The only remaining owner of surfaces may be display (client), and we will
+ // dismiss them when destroying output buffers below.
+ DCHECK_EQ(free_output_buffers_.size() + surfaces_at_display_.size(),
+ output_buffer_map_.size());
+
+ // Keep input queue running while we switch outputs.
+ if (!StopDevicePoll(true)) {
+ NOTIFY_ERROR(PLATFORM_FAILURE);
+ return;
+ }
+
+ // This will return only once all buffers are dismissed and destroyed.
+ // This does not wait until they are displayed however, as display retains
+ // references to the buffers bound to textures and will release them
+ // after displaying.
+ if (!DestroyOutputs(true)) {
+ NOTIFY_ERROR(PLATFORM_FAILURE);
+ return;
+ }
+
+ if (!CreateOutputBuffers()) {
+ NOTIFY_ERROR(PLATFORM_FAILURE);
+ return;
+ }
+
+ if (!StartDevicePoll()) {
+ NOTIFY_ERROR(PLATFORM_FAILURE);
+ return;
+ }
+
+ DVLOGF(3) << "Surface set change finished";
+
+ surface_set_change_pending_ = false;
+ state_ = kDecoding;
+ ScheduleDecodeBufferTaskIfNeeded();
+}
+
+bool V4L2SliceVideoDecodeAccelerator::DestroyOutputs(bool dismiss) {
+ DVLOGF(3);
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+ std::vector<EGLImageKHR> egl_images_to_destroy;
+ std::vector<int32> picture_buffers_to_dismiss;
+
+ if (output_buffer_map_.empty())
+ return true;
+
+ for (auto output_record : output_buffer_map_) {
+ DCHECK(!output_record.at_device);
+
+ if (output_record.egl_sync != EGL_NO_SYNC_KHR) {
+ if (eglDestroySyncKHR(egl_display_, output_record.egl_sync) != EGL_TRUE)
+ DVLOGF(1) << "eglDestroySyncKHR failed.";
+ }
+
+ if (output_record.egl_image != EGL_NO_IMAGE_KHR) {
+ child_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(base::IgnoreResult(&V4L2Device::DestroyEGLImage), device_,
+ egl_display_, output_record.egl_image));
+ }
+
+ picture_buffers_to_dismiss.push_back(output_record.picture_id);
+ }
+
+ if (dismiss) {
+ DVLOGF(2) << "Scheduling picture dismissal";
+ base::WaitableEvent done(false, false);
+ child_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::DismissPictures,
+ weak_this_, picture_buffers_to_dismiss, &done));
+ done.Wait();
+ }
+
+ // At this point client can't call ReusePictureBuffer on any of the pictures
+ // anymore, so it's safe to destroy.
+ return DestroyOutputBuffers();
+}
+
+bool V4L2SliceVideoDecodeAccelerator::DestroyOutputBuffers() {
+ DVLOGF(3);
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread() ||
+ !decoder_thread_.IsRunning());
+ DCHECK(!output_streamon_);
+ DCHECK(surfaces_at_device_.empty());
+ DCHECK(decoder_display_queue_.empty());
+ DCHECK_EQ(surfaces_at_display_.size() + free_output_buffers_.size(),
+ output_buffer_map_.size());
+
+ if (output_buffer_map_.empty())
+ return true;
+
+ // It's ok to do this, client will retain references to textures, but we are
+ // not interested in reusing the surfaces anymore.
+ // This will prevent us from reusing old surfaces in case we have some
+ // ReusePictureBuffer() pending on ChildThread already. It's ok to ignore
+ // them, because we have already dismissed them (in DestroyOutputs()).
+ for (const auto& surface_at_display : surfaces_at_display_) {
+ size_t index = surface_at_display.second->output_record();
+ DCHECK_LT(index, output_buffer_map_.size());
+ OutputRecord& output_record = output_buffer_map_[index];
+ DCHECK(output_record.at_client);
+ output_record.at_client = false;
+ }
+ surfaces_at_display_.clear();
+ DCHECK_EQ(free_output_buffers_.size(), output_buffer_map_.size());
+
+ free_output_buffers_.clear();
+ output_buffer_map_.clear();
+
+ struct v4l2_requestbuffers reqbufs;
+ memset(&reqbufs, 0, sizeof(reqbufs));
+ reqbufs.count = 0;
+ reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ reqbufs.memory = V4L2_MEMORY_MMAP;
+ IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS, &reqbufs);
+
+ return true;
+}
+
+void V4L2SliceVideoDecodeAccelerator::AssignPictureBuffers(
+ const std::vector<media::PictureBuffer>& buffers) {
+ DVLOGF(3);
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
+
+ if (buffers.size() != output_buffer_map_.size()) {
+ DLOG(ERROR) << "Failed to provide requested picture buffers. "
+ << "(Got " << buffers.size()
+ << ", requested " << output_buffer_map_.size() << ")";
+ NOTIFY_ERROR(INVALID_ARGUMENT);
+ return;
+ }
+
+ if (!make_context_current_.Run()) {
+ DLOG(ERROR) << "could not make context current";
+ NOTIFY_ERROR(PLATFORM_FAILURE);
+ return;
+ }
+
+ gfx::ScopedTextureBinder bind_restore(GL_TEXTURE_EXTERNAL_OES, 0);
+
+ // It's safe to manipulate all the buffer state here, because the decoder
+ // thread is waiting on pictures_assigned_.
+ DCHECK(free_output_buffers_.empty());
+ for (size_t i = 0; i < output_buffer_map_.size(); ++i) {
+ DCHECK(buffers[i].size() == coded_size_);
+
+ OutputRecord& output_record = output_buffer_map_[i];
+ DCHECK(!output_record.at_device);
+ DCHECK(!output_record.at_client);
+ DCHECK_EQ(output_record.egl_image, EGL_NO_IMAGE_KHR);
+ DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR);
+ DCHECK_EQ(output_record.picture_id, -1);
+ DCHECK_EQ(output_record.cleared, false);
+
+ EGLImageKHR egl_image = device_->CreateEGLImage(egl_display_,
+ egl_context_,
+ buffers[i].texture_id(),
+ coded_size_,
+ i,
+ output_format_fourcc_,
+ output_planes_count_);
+ if (egl_image == EGL_NO_IMAGE_KHR) {
+ LOGF(ERROR) << "Could not create EGLImageKHR";
+ // Ownership of EGLImages allocated in previous iterations of this loop
+ // has been transferred to output_buffer_map_. After we error-out here
+ // the destructor will handle their cleanup.
+ NOTIFY_ERROR(PLATFORM_FAILURE);
+ return;
+ }
+
+ output_record.egl_image = egl_image;
+ output_record.picture_id = buffers[i].id();
+ free_output_buffers_.push_back(i);
+ DVLOGF(3) << "buffer[" << i << "]: picture_id=" << output_record.picture_id;
+ }
+
+ pictures_assigned_.Signal();
+}
+
+void V4L2SliceVideoDecodeAccelerator::ReusePictureBuffer(
+ int32 picture_buffer_id) {
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
+ DVLOGF(4) << "picture_buffer_id=" << picture_buffer_id;
+
+ if (!make_context_current_.Run()) {
+ LOGF(ERROR) << "could not make context current";
+ NOTIFY_ERROR(PLATFORM_FAILURE);
+ return;
+ }
+
+ EGLSyncKHR egl_sync =
+ eglCreateSyncKHR(egl_display_, EGL_SYNC_FENCE_KHR, NULL);
+ if (egl_sync == EGL_NO_SYNC_KHR) {
+ LOGF(ERROR) << "eglCreateSyncKHR() failed";
+ NOTIFY_ERROR(PLATFORM_FAILURE);
+ return;
+ }
+
+ scoped_ptr<EGLSyncKHRRef> egl_sync_ref(
+ new EGLSyncKHRRef(egl_display_, egl_sync));
+ decoder_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&V4L2SliceVideoDecodeAccelerator::ReusePictureBufferTask,
+ base::Unretained(this), picture_buffer_id,
+ base::Passed(&egl_sync_ref)));
+}
+
+void V4L2SliceVideoDecodeAccelerator::ReusePictureBufferTask(
+ int32 picture_buffer_id,
+ scoped_ptr<EGLSyncKHRRef> egl_sync_ref) {
+ DVLOGF(3) << "picture_buffer_id=" << picture_buffer_id;
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+
+ V4L2DecodeSurfaceByPictureBufferId::iterator it =
+ surfaces_at_display_.find(picture_buffer_id);
+ if (it == surfaces_at_display_.end()) {
+ // It's possible that we've already posted a DismissPictureBuffer for this
+ // picture, but it has not yet executed when this ReusePictureBuffer was
+ // posted to us by the client. In that case just ignore this (we've already
+ // dismissed it and accounted for that) and let the sync object get
+ // destroyed.
+ DVLOGF(3) << "got picture id=" << picture_buffer_id
+ << " not in use (anymore?).";
+ return;
+ }
+
+ OutputRecord& output_record = output_buffer_map_[it->second->output_record()];
+ if (output_record.at_device || !output_record.at_client) {
+ DVLOGF(1) << "picture_buffer_id not reusable";
+ NOTIFY_ERROR(INVALID_ARGUMENT);
+ return;
+ }
+
+ DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR);
+ DCHECK(!output_record.at_device);
+ output_record.at_client = false;
+ output_record.egl_sync = egl_sync_ref->egl_sync;
+ // Take ownership of the EGLSync.
+ egl_sync_ref->egl_sync = EGL_NO_SYNC_KHR;
+ surfaces_at_display_.erase(it);
+}
+
+void V4L2SliceVideoDecodeAccelerator::Flush() {
+ DVLOGF(3);
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
+
+ decoder_thread_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::FlushTask,
+ base::Unretained(this)));
+}
+
+void V4L2SliceVideoDecodeAccelerator::FlushTask() {
+ DVLOGF(3);
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+
+ if (!decoder_input_queue_.empty()) {
+ // We are not done with pending inputs, so queue an empty buffer,
+ // which - when reached - will trigger flush sequence.
+ decoder_input_queue_.push(
+ linked_ptr<BitstreamBufferRef>(new BitstreamBufferRef(
+ io_client_, io_task_runner_, nullptr, 0, kFlushBufferId)));
+ return;
+ }
+
+ // No more inputs pending, so just finish flushing here.
+ InitiateFlush();
+}
+
+void V4L2SliceVideoDecodeAccelerator::InitiateFlush() {
+ DVLOGF(3);
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+
+ DCHECK(!decoder_flushing_);
+ DCHECK_EQ(state_, kDecoding);
+ state_ = kIdle;
+
+ // This will trigger output for all remaining surfaces in the decoder.
+ // However, not all of them may be decoded yet (they would be queued
+ // in hardware then).
+ if (!decoder_->Flush()) {
+ DVLOGF(1) << "Failed flushing the decoder.";
+ NOTIFY_ERROR(PLATFORM_FAILURE);
+ return;
+ }
+
+ // Put the decoder in an idle state, ready to resume.
+ decoder_->Reset();
+
+ decoder_flushing_ = true;
+
+ decoder_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&V4L2SliceVideoDecodeAccelerator::FinishFlushIfNeeded,
+ base::Unretained(this)));
+}
+
+void V4L2SliceVideoDecodeAccelerator::FinishFlushIfNeeded() {
+ DVLOGF(3);
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+
+ if (!decoder_flushing_ || !surfaces_at_device_.empty())
+ return;
+
+ DCHECK_EQ(state_, kIdle);
+
+ // At this point, all remaining surfaces are decoded and dequeued, and since
+ // we have already scheduled output for them in InitiateFlush(), their
+ // respective PictureReady calls have been posted (or they have been queued on
+ // pending_picture_ready_). So at this time, once we SendPictureReady(),
+ // we will have all remaining PictureReady() posted to the client and we
+ // can post NotifyFlushDone().
+ DCHECK(decoder_display_queue_.empty());
+
+ // Decoder should have already returned all surfaces and all surfaces are
+ // out of hardware. There can be no other owners of input buffers.
+ DCHECK_EQ(free_input_buffers_.size(), input_buffer_map_.size());
+
+ SendPictureReady();
+
+ child_task_runner_->PostTask(FROM_HERE,
+ base::Bind(&Client::NotifyFlushDone, client_));
+
+ decoder_flushing_ = false;
+
+ DVLOGF(3) << "Flush finished";
+ state_ = kDecoding;
+ ScheduleDecodeBufferTaskIfNeeded();
+}
+
+void V4L2SliceVideoDecodeAccelerator::Reset() {
+ DVLOGF(3);
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
+
+ decoder_thread_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::ResetTask,
+ base::Unretained(this)));
+}
+
+void V4L2SliceVideoDecodeAccelerator::ResetTask() {
+ DVLOGF(3);
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+
+ if (decoder_resetting_) {
+ // This is a bug in the client, multiple Reset()s before NotifyResetDone()
+ // are not allowed.
+ NOTREACHED() << "Client should not be requesting multiple Reset()s";
+ return;
+ }
+
+ DCHECK_EQ(state_, kDecoding);
+ state_ = kIdle;
+
+ // Put the decoder in an idle state, ready to resume.
+ decoder_->Reset();
+
+ decoder_resetting_ = true;
+
+ // Drop all remaining inputs.
+ decoder_current_bitstream_buffer_.reset();
+ while (!decoder_input_queue_.empty())
+ decoder_input_queue_.pop();
+
+ FinishResetIfNeeded();
+}
+
+void V4L2SliceVideoDecodeAccelerator::FinishResetIfNeeded() {
+ DVLOGF(3);
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+
+ if (!decoder_resetting_ || !surfaces_at_device_.empty())
+ return;
+
+ DCHECK_EQ(state_, kIdle);
+ DCHECK(!decoder_flushing_);
+ SendPictureReady();
+
+ // Drop any pending outputs.
+ while (!decoder_display_queue_.empty())
+ decoder_display_queue_.pop();
+
+ // At this point we can have no input buffers in the decoder, because we
+ // Reset()ed it in ResetTask(), and have not scheduled any new Decode()s
+ // having been in kIdle since. We don't have any surfaces in the HW either -
+ // we just checked that surfaces_at_device_.empty(), and inputs are tied
+ // to surfaces. Since there can be no other owners of input buffers, we can
+ // simply mark them all as available.
+ DCHECK_EQ(input_buffer_queued_count_, 0);
+ free_input_buffers_.clear();
+ for (size_t i = 0; i < input_buffer_map_.size(); ++i) {
+ DCHECK(!input_buffer_map_[i].at_device);
+ ReuseInputBuffer(i);
+ }
+
+ decoder_resetting_ = false;
+
+ child_task_runner_->PostTask(FROM_HERE,
+ base::Bind(&Client::NotifyResetDone, client_));
+
+ DVLOGF(3) << "Reset finished";
+
+ state_ = kDecoding;
+ ScheduleDecodeBufferTaskIfNeeded();
+}
+
+void V4L2SliceVideoDecodeAccelerator::SetErrorState(Error error) {
+ // We can touch decoder_state_ only if this is the decoder thread or the
+ // decoder thread isn't running.
+ if (decoder_thread_.IsRunning() &&
+ !decoder_thread_task_runner_->BelongsToCurrentThread()) {
+ decoder_thread_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::SetErrorState,
+ base::Unretained(this), error));
+ return;
+ }
+
+ // Post NotifyError only if we are already initialized, as the API does
+ // not allow doing so before that.
+ if (state_ != kError && state_ != kUninitialized)
+ NotifyError(error);
+
+ state_ = kError;
+}
+
+V4L2SliceVideoDecodeAccelerator::V4L2H264Accelerator::V4L2H264Accelerator(
+ V4L2SliceVideoDecodeAccelerator* v4l2_dec)
+ : num_slices_(0), v4l2_dec_(v4l2_dec) {
+ DCHECK(v4l2_dec_);
+}
+
+V4L2SliceVideoDecodeAccelerator::V4L2H264Accelerator::~V4L2H264Accelerator() {
+}
+
+scoped_refptr<H264Picture>
+V4L2SliceVideoDecodeAccelerator::V4L2H264Accelerator::CreateH264Picture() {
+ scoped_refptr<V4L2DecodeSurface> dec_surface = v4l2_dec_->CreateSurface();
+ if (!dec_surface)
+ return nullptr;
+
+ return new V4L2H264Picture(dec_surface);
+}
+
+void V4L2SliceVideoDecodeAccelerator::V4L2H264Accelerator::
+ H264PictureListToDPBIndicesList(const H264Picture::Vector& src_pic_list,
+ uint8_t dst_list[kDPBIndicesListSize]) {
+ size_t i;
+ for (i = 0; i < src_pic_list.size() && i < kDPBIndicesListSize; ++i) {
+ const scoped_refptr<H264Picture>& pic = src_pic_list[i];
+ dst_list[i] = pic ? pic->dpb_position : VIDEO_MAX_FRAME;
+ }
+
+ while (i < kDPBIndicesListSize)
+ dst_list[i++] = VIDEO_MAX_FRAME;
+}
+
+void V4L2SliceVideoDecodeAccelerator::V4L2H264Accelerator::H264DPBToV4L2DPB(
+ const H264DPB& dpb,
+ std::vector<scoped_refptr<V4L2DecodeSurface>>* ref_surfaces) {
+ memset(v4l2_decode_param_.dpb, 0, sizeof(v4l2_decode_param_.dpb));
+ size_t i = 0;
+ for (const auto& pic : dpb) {
+ if (i >= arraysize(v4l2_decode_param_.dpb)) {
+ DVLOG(1) << "Invalid DPB size";
+ break;
+ }
+ struct v4l2_h264_dpb_entry& entry = v4l2_decode_param_.dpb[i++];
+ scoped_refptr<V4L2DecodeSurface> dec_surface =
+ H264PictureToV4L2DecodeSurface(pic);
+ entry.buf_index = dec_surface->output_record();
+ entry.frame_num = pic->frame_num;
+ entry.pic_num = pic->pic_num;
+ entry.top_field_order_cnt = pic->top_field_order_cnt;
+ entry.bottom_field_order_cnt = pic->bottom_field_order_cnt;
+ entry.flags = (pic->ref ? V4L2_H264_DPB_ENTRY_FLAG_ACTIVE : 0) |
+ (pic->long_term ? V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM : 0);
+
+ ref_surfaces->push_back(dec_surface);
+ }
+}
+
+bool V4L2SliceVideoDecodeAccelerator::V4L2H264Accelerator::SubmitFrameMetadata(
+ const media::H264SPS* sps,
+ const media::H264PPS* pps,
+ const H264DPB& dpb,
+ const H264Picture::Vector& ref_pic_listp0,
+ const H264Picture::Vector& ref_pic_listb0,
+ const H264Picture::Vector& ref_pic_listb1,
+ const scoped_refptr<H264Picture>& pic) {
+ struct v4l2_ext_control ctrl;
+ std::vector<struct v4l2_ext_control> ctrls;
+
+ struct v4l2_ctrl_h264_sps v4l2_sps;
+ memset(&v4l2_sps, 0, sizeof(v4l2_sps));
+ v4l2_sps.constraint_set_flags =
+ sps->constraint_set0_flag ? V4L2_H264_SPS_CONSTRAINT_SET0_FLAG : 0 |
+ sps->constraint_set1_flag ? V4L2_H264_SPS_CONSTRAINT_SET1_FLAG : 0 |
+ sps->constraint_set2_flag ? V4L2_H264_SPS_CONSTRAINT_SET2_FLAG : 0 |
+ sps->constraint_set3_flag ? V4L2_H264_SPS_CONSTRAINT_SET3_FLAG : 0 |
+ sps->constraint_set4_flag ? V4L2_H264_SPS_CONSTRAINT_SET4_FLAG : 0 |
+ sps->constraint_set5_flag ? V4L2_H264_SPS_CONSTRAINT_SET5_FLAG : 0;
+#define SPS_TO_V4L2SPS(a) v4l2_sps.a = sps->a
+ SPS_TO_V4L2SPS(profile_idc);
+ SPS_TO_V4L2SPS(level_idc);
+ SPS_TO_V4L2SPS(seq_parameter_set_id);
+ SPS_TO_V4L2SPS(chroma_format_idc);
+ SPS_TO_V4L2SPS(bit_depth_luma_minus8);
+ SPS_TO_V4L2SPS(bit_depth_chroma_minus8);
+ SPS_TO_V4L2SPS(log2_max_frame_num_minus4);
+ SPS_TO_V4L2SPS(pic_order_cnt_type);
+ SPS_TO_V4L2SPS(log2_max_pic_order_cnt_lsb_minus4);
+ SPS_TO_V4L2SPS(offset_for_non_ref_pic);
+ SPS_TO_V4L2SPS(offset_for_top_to_bottom_field);
+ SPS_TO_V4L2SPS(num_ref_frames_in_pic_order_cnt_cycle);
+
+ static_assert(arraysize(v4l2_sps.offset_for_ref_frame) ==
+ arraysize(sps->offset_for_ref_frame),
+ "offset_for_ref_frame arrays must be same size");
+ for (size_t i = 0; i < arraysize(v4l2_sps.offset_for_ref_frame); ++i)
+ v4l2_sps.offset_for_ref_frame[i] = sps->offset_for_ref_frame[i];
+ SPS_TO_V4L2SPS(max_num_ref_frames);
+ SPS_TO_V4L2SPS(pic_width_in_mbs_minus1);
+ SPS_TO_V4L2SPS(pic_height_in_map_units_minus1);
+#undef SPS_TO_V4L2SPS
+
+#define SET_V4L2_SPS_FLAG_IF(cond, flag) \
+ v4l2_sps.flags |= ((sps->cond) ? (flag) : 0)
+ SET_V4L2_SPS_FLAG_IF(separate_colour_plane_flag,
+ V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE);
+ SET_V4L2_SPS_FLAG_IF(qpprime_y_zero_transform_bypass_flag,
+ V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS);
+ SET_V4L2_SPS_FLAG_IF(delta_pic_order_always_zero_flag,
+ V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO);
+ SET_V4L2_SPS_FLAG_IF(gaps_in_frame_num_value_allowed_flag,
+ V4L2_H264_SPS_FLAG_GAPS_IN_FRAME_NUM_VALUE_ALLOWED);
+ SET_V4L2_SPS_FLAG_IF(frame_mbs_only_flag, V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY);
+ SET_V4L2_SPS_FLAG_IF(mb_adaptive_frame_field_flag,
+ V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD);
+ SET_V4L2_SPS_FLAG_IF(direct_8x8_inference_flag,
+ V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE);
+#undef SET_FLAG
+ memset(&ctrl, 0, sizeof(ctrl));
+ ctrl.id = V4L2_CID_MPEG_VIDEO_H264_SPS;
+ ctrl.size = sizeof(v4l2_sps);
+ ctrl.p_h264_sps = &v4l2_sps;
+ ctrls.push_back(ctrl);
+
+ struct v4l2_ctrl_h264_pps v4l2_pps;
+ memset(&v4l2_pps, 0, sizeof(v4l2_pps));
+#define PPS_TO_V4L2PPS(a) v4l2_pps.a = pps->a
+ PPS_TO_V4L2PPS(pic_parameter_set_id);
+ PPS_TO_V4L2PPS(seq_parameter_set_id);
+ PPS_TO_V4L2PPS(num_slice_groups_minus1);
+ PPS_TO_V4L2PPS(num_ref_idx_l0_default_active_minus1);
+ PPS_TO_V4L2PPS(num_ref_idx_l1_default_active_minus1);
+ PPS_TO_V4L2PPS(weighted_bipred_idc);
+ PPS_TO_V4L2PPS(pic_init_qp_minus26);
+ PPS_TO_V4L2PPS(pic_init_qs_minus26);
+ PPS_TO_V4L2PPS(chroma_qp_index_offset);
+ PPS_TO_V4L2PPS(second_chroma_qp_index_offset);
+#undef PPS_TO_V4L2PPS
+
+#define SET_V4L2_PPS_FLAG_IF(cond, flag) \
+ v4l2_pps.flags |= ((pps->cond) ? (flag) : 0)
+ SET_V4L2_PPS_FLAG_IF(entropy_coding_mode_flag,
+ V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE);
+ SET_V4L2_PPS_FLAG_IF(
+ bottom_field_pic_order_in_frame_present_flag,
+ V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT);
+ SET_V4L2_PPS_FLAG_IF(weighted_pred_flag, V4L2_H264_PPS_FLAG_WEIGHTED_PRED);
+ SET_V4L2_PPS_FLAG_IF(deblocking_filter_control_present_flag,
+ V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT);
+ SET_V4L2_PPS_FLAG_IF(constrained_intra_pred_flag,
+ V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED);
+ SET_V4L2_PPS_FLAG_IF(redundant_pic_cnt_present_flag,
+ V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT);
+ SET_V4L2_PPS_FLAG_IF(transform_8x8_mode_flag,
+ V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE);
+ SET_V4L2_PPS_FLAG_IF(pic_scaling_matrix_present_flag,
+ V4L2_H264_PPS_FLAG_PIC_SCALING_MATRIX_PRESENT);
+#undef SET_V4L2_PPS_FLAG_IF
+ memset(&ctrl, 0, sizeof(ctrl));
+ ctrl.id = V4L2_CID_MPEG_VIDEO_H264_PPS;
+ ctrl.size = sizeof(v4l2_pps);
+ ctrl.p_h264_pps = &v4l2_pps;
+ ctrls.push_back(ctrl);
+
+ struct v4l2_ctrl_h264_scaling_matrix v4l2_scaling_matrix;
+ memset(&v4l2_scaling_matrix, 0, sizeof(v4l2_scaling_matrix));
+ static_assert(arraysize(v4l2_scaling_matrix.scaling_list_4x4) <=
+ arraysize(pps->scaling_list4x4) &&
+ arraysize(v4l2_scaling_matrix.scaling_list_4x4[0]) <=
+ arraysize(pps->scaling_list4x4[0]) &&
+ arraysize(v4l2_scaling_matrix.scaling_list_8x8) <=
+ arraysize(pps->scaling_list8x8) &&
+ arraysize(v4l2_scaling_matrix.scaling_list_8x8[0]) <=
+ arraysize(pps->scaling_list8x8[0]),
+ "scaling_lists must be of correct size");
+ for (size_t i = 0; i < arraysize(v4l2_scaling_matrix.scaling_list_4x4); ++i) {
+ for (size_t j = 0; j < arraysize(v4l2_scaling_matrix.scaling_list_4x4[i]);
+ ++j) {
+ v4l2_scaling_matrix.scaling_list_4x4[i][j] = pps->scaling_list4x4[i][j];
+ }
+ }
+ for (size_t i = 0; i < arraysize(v4l2_scaling_matrix.scaling_list_8x8); ++i) {
+ for (size_t j = 0; j < arraysize(v4l2_scaling_matrix.scaling_list_8x8[i]);
+ ++j) {
+ v4l2_scaling_matrix.scaling_list_8x8[i][j] = pps->scaling_list8x8[i][j];
+ }
+ }
+ memset(&ctrl, 0, sizeof(ctrl));
+ ctrl.id = V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX;
+ ctrl.size = sizeof(v4l2_scaling_matrix);
+ ctrl.p_h264_scal_mtrx = &v4l2_scaling_matrix;
+ ctrls.push_back(ctrl);
+
+ scoped_refptr<V4L2DecodeSurface> dec_surface =
+ H264PictureToV4L2DecodeSurface(pic);
+
+ struct v4l2_ext_controls ext_ctrls;
+ memset(&ext_ctrls, 0, sizeof(ext_ctrls));
+ ext_ctrls.count = ctrls.size();
+ ext_ctrls.controls = &ctrls[0];
+ ext_ctrls.config_store = dec_surface->config_store();
+ v4l2_dec_->SubmitExtControls(&ext_ctrls);
+
+ H264PictureListToDPBIndicesList(ref_pic_listp0,
+ v4l2_decode_param_.ref_pic_list_p0);
+ H264PictureListToDPBIndicesList(ref_pic_listb0,
+ v4l2_decode_param_.ref_pic_list_b0);
+ H264PictureListToDPBIndicesList(ref_pic_listb1,
+ v4l2_decode_param_.ref_pic_list_b1);
+
+ std::vector<scoped_refptr<V4L2DecodeSurface>> ref_surfaces;
+ H264DPBToV4L2DPB(dpb, &ref_surfaces);
+ dec_surface->SetReferenceSurfaces(ref_surfaces);
+
+ return true;
+}
+
+bool V4L2SliceVideoDecodeAccelerator::V4L2H264Accelerator::SubmitSlice(
+ const media::H264PPS* pps,
+ const media::H264SliceHeader* slice_hdr,
+ const H264Picture::Vector& ref_pic_list0,
+ const H264Picture::Vector& ref_pic_list1,
+ const scoped_refptr<H264Picture>& pic,
+ const uint8_t* data,
+ size_t size) {
+ if (num_slices_ == kMaxSlices) {
+ LOGF(ERROR) << "Over limit of supported slices per frame";
+ return false;
+ }
+
+ struct v4l2_ctrl_h264_slice_param& v4l2_slice_param =
+ v4l2_slice_params_[num_slices_++];
+ memset(&v4l2_slice_param, 0, sizeof(v4l2_slice_param));
+
+ v4l2_slice_param.size = size;
+#define SHDR_TO_V4L2SPARM(a) v4l2_slice_param.a = slice_hdr->a
+ SHDR_TO_V4L2SPARM(header_bit_size);
+ SHDR_TO_V4L2SPARM(first_mb_in_slice);
+ SHDR_TO_V4L2SPARM(slice_type);
+ SHDR_TO_V4L2SPARM(pic_parameter_set_id);
+ SHDR_TO_V4L2SPARM(colour_plane_id);
+ SHDR_TO_V4L2SPARM(frame_num);
+ SHDR_TO_V4L2SPARM(idr_pic_id);
+ SHDR_TO_V4L2SPARM(pic_order_cnt_lsb);
+ SHDR_TO_V4L2SPARM(delta_pic_order_cnt_bottom);
+ SHDR_TO_V4L2SPARM(delta_pic_order_cnt0);
+ SHDR_TO_V4L2SPARM(delta_pic_order_cnt1);
+ SHDR_TO_V4L2SPARM(redundant_pic_cnt);
+ SHDR_TO_V4L2SPARM(dec_ref_pic_marking_bit_size);
+ SHDR_TO_V4L2SPARM(cabac_init_idc);
+ SHDR_TO_V4L2SPARM(slice_qp_delta);
+ SHDR_TO_V4L2SPARM(slice_qs_delta);
+ SHDR_TO_V4L2SPARM(disable_deblocking_filter_idc);
+ SHDR_TO_V4L2SPARM(slice_alpha_c0_offset_div2);
+ SHDR_TO_V4L2SPARM(slice_beta_offset_div2);
+ SHDR_TO_V4L2SPARM(num_ref_idx_l0_active_minus1);
+ SHDR_TO_V4L2SPARM(num_ref_idx_l1_active_minus1);
+ SHDR_TO_V4L2SPARM(pic_order_cnt_bit_size);
+#undef SHDR_TO_V4L2SPARM
+
+#define SET_V4L2_SPARM_FLAG_IF(cond, flag) \
+ v4l2_slice_param.flags |= ((slice_hdr->cond) ? (flag) : 0)
+ SET_V4L2_SPARM_FLAG_IF(field_pic_flag, V4L2_SLICE_FLAG_FIELD_PIC);
+ SET_V4L2_SPARM_FLAG_IF(bottom_field_flag, V4L2_SLICE_FLAG_BOTTOM_FIELD);
+ SET_V4L2_SPARM_FLAG_IF(direct_spatial_mv_pred_flag,
+ V4L2_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED);
+ SET_V4L2_SPARM_FLAG_IF(sp_for_switch_flag, V4L2_SLICE_FLAG_SP_FOR_SWITCH);
+#undef SET_V4L2_SPARM_FLAG_IF
+
+ struct v4l2_h264_pred_weight_table* pred_weight_table =
+ &v4l2_slice_param.pred_weight_table;
+
+ if (((slice_hdr->IsPSlice() || slice_hdr->IsSPSlice()) &&
+ pps->weighted_pred_flag) ||
+ (slice_hdr->IsBSlice() && pps->weighted_bipred_idc == 1)) {
+ pred_weight_table->luma_log2_weight_denom =
+ slice_hdr->luma_log2_weight_denom;
+ pred_weight_table->chroma_log2_weight_denom =
+ slice_hdr->chroma_log2_weight_denom;
+
+ struct v4l2_h264_weight_factors* factorsl0 =
+ &pred_weight_table->weight_factors[0];
+
+ for (int i = 0; i < 32; ++i) {
+ factorsl0->luma_weight[i] =
+ slice_hdr->pred_weight_table_l0.luma_weight[i];
+ factorsl0->luma_offset[i] =
+ slice_hdr->pred_weight_table_l0.luma_offset[i];
+
+ for (int j = 0; j < 2; ++j) {
+ factorsl0->chroma_weight[i][j] =
+ slice_hdr->pred_weight_table_l0.chroma_weight[i][j];
+ factorsl0->chroma_offset[i][j] =
+ slice_hdr->pred_weight_table_l0.chroma_offset[i][j];
+ }
+ }
+
+ if (slice_hdr->IsBSlice()) {
+ struct v4l2_h264_weight_factors* factorsl1 =
+ &pred_weight_table->weight_factors[1];
+
+ for (int i = 0; i < 32; ++i) {
+ factorsl1->luma_weight[i] =
+ slice_hdr->pred_weight_table_l1.luma_weight[i];
+ factorsl1->luma_offset[i] =
+ slice_hdr->pred_weight_table_l1.luma_offset[i];
+
+ for (int j = 0; j < 2; ++j) {
+ factorsl1->chroma_weight[i][j] =
+ slice_hdr->pred_weight_table_l1.chroma_weight[i][j];
+ factorsl1->chroma_offset[i][j] =
+ slice_hdr->pred_weight_table_l1.chroma_offset[i][j];
+ }
+ }
+ }
+ }
+
+ H264PictureListToDPBIndicesList(ref_pic_list0,
+ v4l2_slice_param.ref_pic_list0);
+ H264PictureListToDPBIndicesList(ref_pic_list1,
+ v4l2_slice_param.ref_pic_list1);
+
+ scoped_refptr<V4L2DecodeSurface> dec_surface =
+ H264PictureToV4L2DecodeSurface(pic);
+
+ v4l2_decode_param_.nal_ref_idc = slice_hdr->nal_ref_idc;
+
+ // TODO(posciak): Don't add start code back here, but have it passed from
+ // the parser.
+ size_t data_copy_size = size + 3;
+ scoped_ptr<uint8_t[]> data_copy(new uint8_t[data_copy_size]);
+ memset(data_copy.get(), 0, data_copy_size);
+ data_copy[2] = 0x01;
+ memcpy(data_copy.get() + 3, data, size);
+ return v4l2_dec_->SubmitSlice(dec_surface->input_record(), data_copy.get(),
+ data_copy_size);
+}
+
+bool V4L2SliceVideoDecodeAccelerator::SubmitSlice(int index,
+ const uint8_t* data,
+ size_t size) {
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+
+ InputRecord& input_record = input_buffer_map_[index];
+
+ if (input_record.bytes_used + size > input_record.length) {
+ DVLOGF(1) << "Input buffer too small";
+ return false;
+ }
+
+ memcpy(static_cast<uint8_t*>(input_record.address) + input_record.bytes_used,
+ data, size);
+ input_record.bytes_used += size;
+
+ return true;
+}
+
+bool V4L2SliceVideoDecodeAccelerator::SubmitExtControls(
+ struct v4l2_ext_controls* ext_ctrls) {
+ DCHECK_GT(ext_ctrls->config_store, 0u);
+ IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_EXT_CTRLS, ext_ctrls);
+ return true;
+}
+
+bool V4L2SliceVideoDecodeAccelerator::V4L2H264Accelerator::SubmitDecode(
+ const scoped_refptr<H264Picture>& pic) {
+ scoped_refptr<V4L2DecodeSurface> dec_surface =
+ H264PictureToV4L2DecodeSurface(pic);
+
+ v4l2_decode_param_.num_slices = num_slices_;
+ v4l2_decode_param_.idr_pic_flag = pic->idr;
+ v4l2_decode_param_.top_field_order_cnt = pic->top_field_order_cnt;
+ v4l2_decode_param_.bottom_field_order_cnt = pic->bottom_field_order_cnt;
+
+ struct v4l2_ext_control ctrl;
+ std::vector<struct v4l2_ext_control> ctrls;
+
+ memset(&ctrl, 0, sizeof(ctrl));
+ ctrl.id = V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAM;
+ ctrl.size = sizeof(v4l2_slice_params_);
+ ctrl.p_h264_slice_param = v4l2_slice_params_;
+ ctrls.push_back(ctrl);
+
+ memset(&ctrl, 0, sizeof(ctrl));
+ ctrl.id = V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAM;
+ ctrl.size = sizeof(v4l2_decode_param_);
+ ctrl.p_h264_decode_param = &v4l2_decode_param_;
+ ctrls.push_back(ctrl);
+
+ struct v4l2_ext_controls ext_ctrls;
+ memset(&ext_ctrls, 0, sizeof(ext_ctrls));
+ ext_ctrls.count = ctrls.size();
+ ext_ctrls.controls = &ctrls[0];
+ ext_ctrls.config_store = dec_surface->config_store();
+ v4l2_dec_->SubmitExtControls(&ext_ctrls);
+
+ Reset();
+
+ v4l2_dec_->DecodeSurface(dec_surface);
+ return true;
+}
+
+bool V4L2SliceVideoDecodeAccelerator::V4L2H264Accelerator::OutputPicture(
+ const scoped_refptr<H264Picture>& pic) {
+ scoped_refptr<V4L2DecodeSurface> dec_surface =
+ H264PictureToV4L2DecodeSurface(pic);
+ v4l2_dec_->SurfaceReady(dec_surface);
+ return true;
+}
+
+void V4L2SliceVideoDecodeAccelerator::V4L2H264Accelerator::Reset() {
+ num_slices_ = 0;
+ memset(&v4l2_decode_param_, 0, sizeof(v4l2_decode_param_));
+ memset(&v4l2_slice_params_, 0, sizeof(v4l2_slice_params_));
+}
+
+scoped_refptr<V4L2SliceVideoDecodeAccelerator::V4L2DecodeSurface>
+V4L2SliceVideoDecodeAccelerator::V4L2H264Accelerator::
+ H264PictureToV4L2DecodeSurface(const scoped_refptr<H264Picture>& pic) {
+ V4L2H264Picture* v4l2_pic = pic->AsV4L2H264Picture();
+ CHECK(v4l2_pic);
+ return v4l2_pic->dec_surface();
+}
+
+V4L2SliceVideoDecodeAccelerator::V4L2VP8Accelerator::V4L2VP8Accelerator(
+ V4L2SliceVideoDecodeAccelerator* v4l2_dec)
+ : v4l2_dec_(v4l2_dec) {
+ DCHECK(v4l2_dec_);
+}
+
+V4L2SliceVideoDecodeAccelerator::V4L2VP8Accelerator::~V4L2VP8Accelerator() {
+}
+
+scoped_refptr<VP8Picture>
+V4L2SliceVideoDecodeAccelerator::V4L2VP8Accelerator::CreateVP8Picture() {
+ scoped_refptr<V4L2DecodeSurface> dec_surface = v4l2_dec_->CreateSurface();
+ if (!dec_surface)
+ return nullptr;
+
+ return new V4L2VP8Picture(dec_surface);
+}
+
+#define ARRAY_MEMCPY_CHECKED(to, from) \
+ do { \
+ static_assert(sizeof(to) == sizeof(from), \
+ #from " and " #to " arrays must be of same size"); \
+ memcpy(to, from, sizeof(to)); \
+ } while (0)
+
+static void FillV4L2SegmentationHeader(
+ const media::Vp8SegmentationHeader& vp8_sgmnt_hdr,
+ struct v4l2_vp8_sgmnt_hdr* v4l2_sgmnt_hdr) {
+#define SET_V4L2_SGMNT_HDR_FLAG_IF(cond, flag) \
+ v4l2_sgmnt_hdr->flags |= ((vp8_sgmnt_hdr.cond) ? (flag) : 0)
+ SET_V4L2_SGMNT_HDR_FLAG_IF(segmentation_enabled,
+ V4L2_VP8_SEGMNT_HDR_FLAG_ENABLED);
+ SET_V4L2_SGMNT_HDR_FLAG_IF(update_mb_segmentation_map,
+ V4L2_VP8_SEGMNT_HDR_FLAG_UPDATE_MAP);
+ SET_V4L2_SGMNT_HDR_FLAG_IF(update_segment_feature_data,
+ V4L2_VP8_SEGMNT_HDR_FLAG_UPDATE_FEATURE_DATA);
+#undef SET_V4L2_SPARM_FLAG_IF
+ v4l2_sgmnt_hdr->segment_feature_mode = vp8_sgmnt_hdr.segment_feature_mode;
+
+ ARRAY_MEMCPY_CHECKED(v4l2_sgmnt_hdr->quant_update,
+ vp8_sgmnt_hdr.quantizer_update_value);
+ ARRAY_MEMCPY_CHECKED(v4l2_sgmnt_hdr->lf_update,
+ vp8_sgmnt_hdr.lf_update_value);
+ ARRAY_MEMCPY_CHECKED(v4l2_sgmnt_hdr->segment_probs,
+ vp8_sgmnt_hdr.segment_prob);
+}
+
+static void FillV4L2LoopfilterHeader(
+ const media::Vp8LoopFilterHeader& vp8_loopfilter_hdr,
+ struct v4l2_vp8_loopfilter_hdr* v4l2_lf_hdr) {
+#define SET_V4L2_LF_HDR_FLAG_IF(cond, flag) \
+ v4l2_lf_hdr->flags |= ((vp8_loopfilter_hdr.cond) ? (flag) : 0)
+ SET_V4L2_LF_HDR_FLAG_IF(loop_filter_adj_enable, V4L2_VP8_LF_HDR_ADJ_ENABLE);
+ SET_V4L2_LF_HDR_FLAG_IF(mode_ref_lf_delta_update,
+ V4L2_VP8_LF_HDR_DELTA_UPDATE);
+#undef SET_V4L2_SGMNT_HDR_FLAG_IF
+
+#define LF_HDR_TO_V4L2_LF_HDR(a) v4l2_lf_hdr->a = vp8_loopfilter_hdr.a;
+ LF_HDR_TO_V4L2_LF_HDR(type);
+ LF_HDR_TO_V4L2_LF_HDR(level);
+ LF_HDR_TO_V4L2_LF_HDR(sharpness_level);
+#undef LF_HDR_TO_V4L2_LF_HDR
+
+ ARRAY_MEMCPY_CHECKED(v4l2_lf_hdr->ref_frm_delta_magnitude,
+ vp8_loopfilter_hdr.ref_frame_delta);
+ ARRAY_MEMCPY_CHECKED(v4l2_lf_hdr->mb_mode_delta_magnitude,
+ vp8_loopfilter_hdr.mb_mode_delta);
+}
+
+static void FillV4L2QuantizationHeader(
+ const media::Vp8QuantizationHeader& vp8_quant_hdr,
+ struct v4l2_vp8_quantization_hdr* v4l2_quant_hdr) {
+ v4l2_quant_hdr->y_ac_qi = vp8_quant_hdr.y_ac_qi;
+ v4l2_quant_hdr->y_dc_delta = vp8_quant_hdr.y_dc_delta;
+ v4l2_quant_hdr->y2_dc_delta = vp8_quant_hdr.y2_dc_delta;
+ v4l2_quant_hdr->y2_ac_delta = vp8_quant_hdr.y2_ac_delta;
+ v4l2_quant_hdr->uv_dc_delta = vp8_quant_hdr.uv_dc_delta;
+ v4l2_quant_hdr->uv_ac_delta = vp8_quant_hdr.uv_ac_delta;
+}
+
+static void FillV4L2EntropyHeader(
+ const media::Vp8EntropyHeader& vp8_entropy_hdr,
+ struct v4l2_vp8_entropy_hdr* v4l2_entropy_hdr) {
+ ARRAY_MEMCPY_CHECKED(v4l2_entropy_hdr->coeff_probs,
+ vp8_entropy_hdr.coeff_probs);
+ ARRAY_MEMCPY_CHECKED(v4l2_entropy_hdr->y_mode_probs,
+ vp8_entropy_hdr.y_mode_probs);
+ ARRAY_MEMCPY_CHECKED(v4l2_entropy_hdr->uv_mode_probs,
+ vp8_entropy_hdr.uv_mode_probs);
+ ARRAY_MEMCPY_CHECKED(v4l2_entropy_hdr->mv_probs,
+ vp8_entropy_hdr.mv_probs);
+}
+
+bool V4L2SliceVideoDecodeAccelerator::V4L2VP8Accelerator::SubmitDecode(
+ const scoped_refptr<VP8Picture>& pic,
+ const media::Vp8FrameHeader* frame_hdr,
+ const scoped_refptr<VP8Picture>& last_frame,
+ const scoped_refptr<VP8Picture>& golden_frame,
+ const scoped_refptr<VP8Picture>& alt_frame) {
+ struct v4l2_ctrl_vp8_frame_hdr v4l2_frame_hdr;
+ memset(&v4l2_frame_hdr, 0, sizeof(v4l2_frame_hdr));
+
+#define FHDR_TO_V4L2_FHDR(a) v4l2_frame_hdr.a = frame_hdr->a
+ FHDR_TO_V4L2_FHDR(key_frame);
+ FHDR_TO_V4L2_FHDR(version);
+ FHDR_TO_V4L2_FHDR(width);
+ FHDR_TO_V4L2_FHDR(horizontal_scale);
+ FHDR_TO_V4L2_FHDR(height);
+ FHDR_TO_V4L2_FHDR(vertical_scale);
+ FHDR_TO_V4L2_FHDR(sign_bias_golden);
+ FHDR_TO_V4L2_FHDR(sign_bias_alternate);
+ FHDR_TO_V4L2_FHDR(prob_skip_false);
+ FHDR_TO_V4L2_FHDR(prob_intra);
+ FHDR_TO_V4L2_FHDR(prob_last);
+ FHDR_TO_V4L2_FHDR(prob_gf);
+ FHDR_TO_V4L2_FHDR(bool_dec_range);
+ FHDR_TO_V4L2_FHDR(bool_dec_value);
+ FHDR_TO_V4L2_FHDR(bool_dec_count);
+#undef FHDR_TO_V4L2_FHDR
+
+#define SET_V4L2_FRM_HDR_FLAG_IF(cond, flag) \
+ v4l2_frame_hdr.flags |= ((frame_hdr->cond) ? (flag) : 0)
+ SET_V4L2_FRM_HDR_FLAG_IF(is_experimental,
+ V4L2_VP8_FRAME_HDR_FLAG_EXPERIMENTAL);
+ SET_V4L2_FRM_HDR_FLAG_IF(show_frame, V4L2_VP8_FRAME_HDR_FLAG_SHOW_FRAME);
+ SET_V4L2_FRM_HDR_FLAG_IF(mb_no_skip_coeff,
+ V4L2_VP8_FRAME_HDR_FLAG_MB_NO_SKIP_COEFF);
+#undef SET_V4L2_FRM_HDR_FLAG_IF
+
+ FillV4L2SegmentationHeader(frame_hdr->segmentation_hdr,
+ &v4l2_frame_hdr.sgmnt_hdr);
+
+ FillV4L2LoopfilterHeader(frame_hdr->loopfilter_hdr, &v4l2_frame_hdr.lf_hdr);
+
+ FillV4L2QuantizationHeader(frame_hdr->quantization_hdr,
+ &v4l2_frame_hdr.quant_hdr);
+
+ FillV4L2EntropyHeader(frame_hdr->entropy_hdr, &v4l2_frame_hdr.entropy_hdr);
+
+ v4l2_frame_hdr.first_part_size =
+ base::checked_cast<__u32>(frame_hdr->first_part_size);
+ v4l2_frame_hdr.first_part_offset =
+ base::checked_cast<__u32>(frame_hdr->first_part_offset);
+ v4l2_frame_hdr.macroblock_bit_offset =
+ base::checked_cast<__u32>(frame_hdr->macroblock_bit_offset);
+ v4l2_frame_hdr.num_dct_parts = frame_hdr->num_of_dct_partitions;
+
+ static_assert(arraysize(v4l2_frame_hdr.dct_part_sizes) ==
+ arraysize(frame_hdr->dct_partition_sizes),
+ "DCT partition size arrays must have equal number of elements");
+ for (size_t i = 0; i < frame_hdr->num_of_dct_partitions &&
+ i < arraysize(v4l2_frame_hdr.dct_part_sizes); ++i)
+ v4l2_frame_hdr.dct_part_sizes[i] = frame_hdr->dct_partition_sizes[i];
+
+ scoped_refptr<V4L2DecodeSurface> dec_surface =
+ VP8PictureToV4L2DecodeSurface(pic);
+ std::vector<scoped_refptr<V4L2DecodeSurface>> ref_surfaces;
+
+ if (last_frame) {
+ scoped_refptr<V4L2DecodeSurface> last_frame_surface =
+ VP8PictureToV4L2DecodeSurface(last_frame);
+ v4l2_frame_hdr.last_frame = last_frame_surface->output_record();
+ ref_surfaces.push_back(last_frame_surface);
+ } else {
+ v4l2_frame_hdr.last_frame = VIDEO_MAX_FRAME;
+ }
+
+ if (golden_frame) {
+ scoped_refptr<V4L2DecodeSurface> golden_frame_surface =
+ VP8PictureToV4L2DecodeSurface(golden_frame);
+ v4l2_frame_hdr.golden_frame = golden_frame_surface->output_record();
+ ref_surfaces.push_back(golden_frame_surface);
+ } else {
+ v4l2_frame_hdr.golden_frame = VIDEO_MAX_FRAME;
+ }
+
+ if (alt_frame) {
+ scoped_refptr<V4L2DecodeSurface> alt_frame_surface =
+ VP8PictureToV4L2DecodeSurface(alt_frame);
+ v4l2_frame_hdr.alt_frame = alt_frame_surface->output_record();
+ ref_surfaces.push_back(alt_frame_surface);
+ } else {
+ v4l2_frame_hdr.alt_frame = VIDEO_MAX_FRAME;
+ }
+
+ struct v4l2_ext_control ctrl;
+ memset(&ctrl, 0, sizeof(ctrl));
+ ctrl.id = V4L2_CID_MPEG_VIDEO_VP8_FRAME_HDR;
+ ctrl.size = sizeof(v4l2_frame_hdr);
+ ctrl.p_vp8_frame_hdr = &v4l2_frame_hdr;
+
+ struct v4l2_ext_controls ext_ctrls;
+ memset(&ext_ctrls, 0, sizeof(ext_ctrls));
+ ext_ctrls.count = 1;
+ ext_ctrls.controls = &ctrl;
+ ext_ctrls.config_store = dec_surface->config_store();
+
+ if (!v4l2_dec_->SubmitExtControls(&ext_ctrls))
+ return false;
+
+ dec_surface->SetReferenceSurfaces(ref_surfaces);
+
+ if (!v4l2_dec_->SubmitSlice(dec_surface->input_record(), frame_hdr->data,
+ frame_hdr->frame_size))
+ return false;
+
+ v4l2_dec_->DecodeSurface(dec_surface);
+ return true;
+}
+
+bool V4L2SliceVideoDecodeAccelerator::V4L2VP8Accelerator::OutputPicture(
+ const scoped_refptr<VP8Picture>& pic) {
+ scoped_refptr<V4L2DecodeSurface> dec_surface =
+ VP8PictureToV4L2DecodeSurface(pic);
+
+ v4l2_dec_->SurfaceReady(dec_surface);
+ return true;
+}
+
+scoped_refptr<V4L2SliceVideoDecodeAccelerator::V4L2DecodeSurface>
+V4L2SliceVideoDecodeAccelerator::V4L2VP8Accelerator::
+ VP8PictureToV4L2DecodeSurface(const scoped_refptr<VP8Picture>& pic) {
+ V4L2VP8Picture* v4l2_pic = pic->AsV4L2VP8Picture();
+ CHECK(v4l2_pic);
+ return v4l2_pic->dec_surface();
+}
+
+void V4L2SliceVideoDecodeAccelerator::DecodeSurface(
+ const scoped_refptr<V4L2DecodeSurface>& dec_surface) {
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+
+ DVLOGF(3) << "Submitting decode for surface: " << dec_surface->ToString();
+ Enqueue(dec_surface);
+}
+
+void V4L2SliceVideoDecodeAccelerator::SurfaceReady(
+ const scoped_refptr<V4L2DecodeSurface>& dec_surface) {
+ DVLOGF(3);
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+
+ decoder_display_queue_.push(dec_surface);
+ TryOutputSurfaces();
+}
+
+void V4L2SliceVideoDecodeAccelerator::TryOutputSurfaces() {
+ while (!decoder_display_queue_.empty()) {
+ scoped_refptr<V4L2DecodeSurface> dec_surface =
+ decoder_display_queue_.front();
+
+ if (!dec_surface->decoded())
+ break;
+
+ decoder_display_queue_.pop();
+ OutputSurface(dec_surface);
+ }
+}
+
+void V4L2SliceVideoDecodeAccelerator::OutputSurface(
+ const scoped_refptr<V4L2DecodeSurface>& dec_surface) {
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+
+ OutputRecord& output_record =
+ output_buffer_map_[dec_surface->output_record()];
+
+ bool inserted =
+ surfaces_at_display_.insert(std::make_pair(output_record.picture_id,
+ dec_surface)).second;
+ DCHECK(inserted);
+
+ DCHECK(!output_record.at_client);
+ DCHECK(!output_record.at_device);
+ DCHECK_NE(output_record.egl_image, EGL_NO_IMAGE_KHR);
+ DCHECK_NE(output_record.picture_id, -1);
+ output_record.at_client = true;
+
+ media::Picture picture(output_record.picture_id, dec_surface->bitstream_id(),
+ gfx::Rect(visible_size_), false);
+ DVLOGF(3) << dec_surface->ToString()
+ << ", bitstream_id: " << picture.bitstream_buffer_id()
+ << ", picture_id: " << picture.picture_buffer_id();
+ pending_picture_ready_.push(PictureRecord(output_record.cleared, picture));
+ SendPictureReady();
+ output_record.cleared = true;
+}
+
+scoped_refptr<V4L2SliceVideoDecodeAccelerator::V4L2DecodeSurface>
+V4L2SliceVideoDecodeAccelerator::CreateSurface() {
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+ DCHECK_EQ(state_, kDecoding);
+
+ if (free_input_buffers_.empty() || free_output_buffers_.empty())
+ return nullptr;
+
+ int input = free_input_buffers_.front();
+ free_input_buffers_.pop_front();
+ int output = free_output_buffers_.front();
+ free_output_buffers_.pop_front();
+
+ InputRecord& input_record = input_buffer_map_[input];
+ DCHECK_EQ(input_record.bytes_used, 0u);
+ DCHECK_EQ(input_record.input_id, -1);
+ DCHECK(decoder_current_bitstream_buffer_ != nullptr);
+ input_record.input_id = decoder_current_bitstream_buffer_->input_id;
+
+ scoped_refptr<V4L2DecodeSurface> dec_surface = new V4L2DecodeSurface(
+ decoder_current_bitstream_buffer_->input_id, input, output,
+ base::Bind(&V4L2SliceVideoDecodeAccelerator::ReuseOutputBuffer,
+ base::Unretained(this)));
+
+ DVLOGF(4) << "Created surface " << input << " -> " << output;
+ return dec_surface;
+}
+
+void V4L2SliceVideoDecodeAccelerator::SendPictureReady() {
+ DVLOGF(3);
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+ bool resetting_or_flushing = (decoder_resetting_ || decoder_flushing_);
+ while (!pending_picture_ready_.empty()) {
+ bool cleared = pending_picture_ready_.front().cleared;
+ const media::Picture& picture = pending_picture_ready_.front().picture;
+ if (cleared && picture_clearing_count_ == 0) {
+ DVLOGF(4) << "Posting picture ready to IO for: "
+ << picture.picture_buffer_id();
+ // This picture is cleared. Post it to IO thread to reduce latency. This
+ // should be the case after all pictures are cleared at the beginning.
+ io_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&Client::PictureReady, io_client_, picture));
+ pending_picture_ready_.pop();
+ } else if (!cleared || resetting_or_flushing) {
+ DVLOGF(3) << "cleared=" << pending_picture_ready_.front().cleared
+ << ", decoder_resetting_=" << decoder_resetting_
+ << ", decoder_flushing_=" << decoder_flushing_
+ << ", picture_clearing_count_=" << picture_clearing_count_;
+ DVLOGF(4) << "Posting picture ready to GPU for: "
+ << picture.picture_buffer_id();
+ // If the picture is not cleared, post it to the child thread because it
+ // has to be cleared in the child thread. A picture only needs to be
+ // cleared once. If the decoder is resetting or flushing, send all
+ // pictures to ensure PictureReady arrive before reset or flush done.
+ child_task_runner_->PostTaskAndReply(
+ FROM_HERE, base::Bind(&Client::PictureReady, client_, picture),
+ // Unretained is safe. If Client::PictureReady gets to run, |this| is
+ // alive. Destroy() will wait the decode thread to finish.
+ base::Bind(&V4L2SliceVideoDecodeAccelerator::PictureCleared,
+ base::Unretained(this)));
+ picture_clearing_count_++;
+ pending_picture_ready_.pop();
+ } else {
+ // This picture is cleared. But some pictures are about to be cleared on
+ // the child thread. To preserve the order, do not send this until those
+ // pictures are cleared.
+ break;
+ }
+ }
+}
+
+void V4L2SliceVideoDecodeAccelerator::PictureCleared() {
+ DVLOGF(3) << "clearing count=" << picture_clearing_count_;
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+ DCHECK_GT(picture_clearing_count_, 0);
+ picture_clearing_count_--;
+ SendPictureReady();
+}
+
+bool V4L2SliceVideoDecodeAccelerator::CanDecodeOnIOThread() {
+ return true;
+}
+
+// static
+media::VideoDecodeAccelerator::SupportedProfiles
+V4L2SliceVideoDecodeAccelerator::GetSupportedProfiles() {
+ scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder);
+ if (!device)
+ return SupportedProfiles();
+
+ const uint32_t supported_formats[] = {
+ V4L2_PIX_FMT_H264_SLICE, V4L2_PIX_FMT_VP8_FRAME};
+ return device->GetSupportedDecodeProfiles(arraysize(supported_formats),
+ supported_formats);
+}
+
+} // namespace content
diff --git a/chromium/content/common/gpu/media/v4l2_slice_video_decode_accelerator.h b/chromium/content/common/gpu/media/v4l2_slice_video_decode_accelerator.h
new file mode 100644
index 00000000000..dd12487bb2c
--- /dev/null
+++ b/chromium/content/common/gpu/media/v4l2_slice_video_decode_accelerator.h
@@ -0,0 +1,397 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_COMMON_GPU_MEDIA_V4L2_SLICE_VIDEO_DECODE_ACCELERATOR_H_
+#define CONTENT_COMMON_GPU_MEDIA_V4L2_SLICE_VIDEO_DECODE_ACCELERATOR_H_
+
+#include <linux/videodev2.h>
+#include <queue>
+#include <vector>
+
+#include "base/memory/linked_ptr.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "content/common/content_export.h"
+#include "content/common/gpu/media/h264_decoder.h"
+#include "content/common/gpu/media/v4l2_device.h"
+#include "content/common/gpu/media/vp8_decoder.h"
+#include "media/video/video_decode_accelerator.h"
+
+namespace content {
+
+// An implementation of VideoDecodeAccelerator that utilizes the V4L2 slice
+// level codec API for decoding. The slice level API provides only a low-level
+// decoding functionality and requires userspace to provide support for parsing
+// the input stream and managing decoder state across frames.
+class CONTENT_EXPORT V4L2SliceVideoDecodeAccelerator
+ : public media::VideoDecodeAccelerator {
+ public:
+ class V4L2DecodeSurface;
+
+ V4L2SliceVideoDecodeAccelerator(
+ const scoped_refptr<V4L2Device>& device,
+ EGLDisplay egl_display,
+ EGLContext egl_context,
+ const base::WeakPtr<Client>& io_client_,
+ const base::Callback<bool(void)>& make_context_current,
+ const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner);
+ ~V4L2SliceVideoDecodeAccelerator() override;
+
+ // media::VideoDecodeAccelerator implementation.
+ bool Initialize(media::VideoCodecProfile profile,
+ VideoDecodeAccelerator::Client* client) override;
+ void Decode(const media::BitstreamBuffer& bitstream_buffer) override;
+ void AssignPictureBuffers(
+ const std::vector<media::PictureBuffer>& buffers) override;
+ void ReusePictureBuffer(int32 picture_buffer_id) override;
+ void Flush() override;
+ void Reset() override;
+ void Destroy() override;
+ bool CanDecodeOnIOThread() override;
+
+ static media::VideoDecodeAccelerator::SupportedProfiles
+ GetSupportedProfiles();
+
+ private:
+ class V4L2H264Accelerator;
+ class V4L2VP8Accelerator;
+
+ // Record for input buffers.
+ struct InputRecord {
+ InputRecord();
+ int32 input_id;
+ void* address;
+ size_t length;
+ size_t bytes_used;
+ bool at_device;
+ };
+
+ // Record for output buffers.
+ struct OutputRecord {
+ OutputRecord();
+ bool at_device;
+ bool at_client;
+ int32 picture_id;
+ EGLImageKHR egl_image;
+ EGLSyncKHR egl_sync;
+ bool cleared;
+ };
+
+ // See http://crbug.com/255116.
+ // Input bitstream buffer size for up to 1080p streams.
+ const size_t kInputBufferMaxSizeFor1080p = 1024 * 1024;
+ // Input bitstream buffer size for up to 4k streams.
+ const size_t kInputBufferMaxSizeFor4k = 4 * kInputBufferMaxSizeFor1080p;
+ const size_t kNumInputBuffers = 16;
+
+ //
+ // Below methods are used by accelerator implementations.
+ //
+ // Append slice data in |data| of size |size| to pending hardware
+ // input buffer with |index|. This buffer will be submitted for decode
+ // on the next DecodeSurface(). Return true on success.
+ bool SubmitSlice(int index, const uint8_t* data, size_t size);
+
+ // Submit controls in |ext_ctrls| to hardware. Return true on success.
+ bool SubmitExtControls(struct v4l2_ext_controls* ext_ctrls);
+
+ // Decode of |dec_surface| is ready to be submitted and all codec-specific
+ // settings are set in hardware.
+ void DecodeSurface(const scoped_refptr<V4L2DecodeSurface>& dec_surface);
+
+ // |dec_surface| is ready to be outputted once decode is finished.
+ // This can be called before decode is actually done in hardware, and this
+ // method is responsible for maintaining the ordering, i.e. the surfaces will
+ // be outputted in the same order as SurfaceReady calls. To do so, the
+ // surfaces are put on decoder_display_queue_ and sent to output in that
+ // order once all preceding surfaces are sent.
+ void SurfaceReady(const scoped_refptr<V4L2DecodeSurface>& dec_surface);
+
+ //
+ // Internal methods of this class.
+ //
+ // Recycle a V4L2 input buffer with |index| after dequeuing from device.
+ void ReuseInputBuffer(int index);
+
+ // Recycle V4L2 output buffer with |index|. Used as surface release callback.
+ void ReuseOutputBuffer(int index);
+
+ // Queue a |dec_surface| to device for decoding.
+ void Enqueue(const scoped_refptr<V4L2DecodeSurface>& dec_surface);
+
+ // Dequeue any V4L2 buffers available and process.
+ void Dequeue();
+
+ // V4L2 QBUF helpers.
+ bool EnqueueInputRecord(int index, uint32_t config_store);
+ bool EnqueueOutputRecord(int index);
+
+ // Set input and output formats in hardware.
+ bool SetupFormats();
+
+ // Create input and output buffers.
+ bool CreateInputBuffers();
+ bool CreateOutputBuffers();
+
+ // Destroy input buffers.
+ void DestroyInputBuffers();
+
+ // Destroy output buffers and release associated resources (textures,
+ // EGLImages). If |dismiss| is true, also dismissing the associated
+ // PictureBuffers.
+ bool DestroyOutputs(bool dismiss);
+
+ // Used by DestroyOutputs.
+ bool DestroyOutputBuffers();
+
+ // Dismiss all |picture_buffer_ids| via Client::DismissPictureBuffer()
+ // and signal |done| after finishing.
+ void DismissPictures(std::vector<int32> picture_buffer_ids,
+ base::WaitableEvent* done);
+
+ // Task to finish initialization on decoder_thread_.
+ void InitializeTask();
+
+ // Surface set change (resolution change) flow.
+ // If we have no surfaces allocated, just allocate them and return.
+ // Otherwise mark us as pending for surface set change.
+ void InitiateSurfaceSetChange();
+ // If a surface set change is pending and we are ready, stop the device,
+ // destroy outputs, releasing resources and dismissing pictures as required,
+ // followed by allocating a new set for the new resolution/DPB size
+ // as provided by decoder. Finally, try to resume decoding.
+ void FinishSurfaceSetChangeIfNeeded();
+
+ void NotifyError(Error error);
+ void DestroyTask();
+
+ // Sets the state to kError and notifies client if needed.
+ void SetErrorState(Error error);
+
+ // Flush flow when requested by client.
+ // When Flush() is called, it posts a FlushTask, which checks the input queue.
+ // If nothing is pending for decode on decoder_input_queue_, we call
+ // InitiateFlush() directly. Otherwise, we push a dummy BitstreamBufferRef
+ // onto the decoder_input_queue_ to schedule a flush. When we reach it later
+ // on, we call InitiateFlush() to perform it at the correct time.
+ void FlushTask();
+ // Tell the decoder to flush all frames, reset it and mark us as scheduled
+ // for flush, so that we can finish it once all pending decodes are finished.
+ void InitiateFlush();
+ // If all pending frames are decoded and we are waiting to flush, perform it.
+ // This will send all pending pictures to client and notify the client that
+ // flush is complete and puts us in a state ready to resume.
+ void FinishFlushIfNeeded();
+
+ // Reset flow when requested by client.
+ // Drop all inputs and reset the decoder and mark us as pending for reset.
+ void ResetTask();
+ // If all pending frames are decoded and we are waiting to reset, perform it.
+ // This drops all pending outputs (client is not interested anymore),
+ // notifies the client we are done and puts us in a state ready to resume.
+ void FinishResetIfNeeded();
+
+ // Process pending events if any.
+ void ProcessPendingEventsIfNeeded();
+
+ // Performed on decoder_thread_ as a consequence of poll() on decoder_thread_
+ // returning an event.
+ void ServiceDeviceTask();
+
+ // Schedule poll if we have any buffers queued and the poll thread
+ // is not stopped (on surface set change).
+ void SchedulePollIfNeeded();
+
+ // Attempt to start/stop device_poll_thread_.
+ bool StartDevicePoll();
+ bool StopDevicePoll(bool keep_input_state);
+
+ // Ran on device_poll_thread_ to wait for device events.
+ void DevicePollTask(bool poll_device);
+
+ enum State {
+ // We are in this state until Initialize() returns successfully.
+ // We can't post errors to the client in this state yet.
+ kUninitialized,
+ // Initialize() returned successfully.
+ kInitialized,
+ // This state allows making progress decoding more input stream.
+ kDecoding,
+ // Transitional state when we are not decoding any more stream, but are
+ // performing flush, reset, resolution change or are destroying ourselves.
+ kIdle,
+ // Error state, set when sending NotifyError to client.
+ kError,
+ };
+
+ // Buffer id for flush buffer, queued by FlushTask().
+ const int kFlushBufferId = -2;
+
+ // Handler for Decode() on decoder_thread_.
+ void DecodeTask(const media::BitstreamBuffer& bitstream_buffer);
+
+ // Schedule a new DecodeBufferTask if we are decoding.
+ void ScheduleDecodeBufferTaskIfNeeded();
+
+ // Main decoder loop. Keep decoding the current buffer in decoder_, asking
+ // for more stream via TrySetNewBistreamBuffer() if decoder_ requests so,
+ // and handle other returns from it appropriately.
+ void DecodeBufferTask();
+
+ // Check decoder_input_queue_ for any available buffers to decode and
+ // set the decoder_current_bitstream_buffer_ to the next buffer if one is
+ // available, taking it off the queue. Also set the current stream pointer
+ // in decoder_, and return true.
+ // Return false if no buffers are pending on decoder_input_queue_.
+ bool TrySetNewBistreamBuffer();
+
+ // Auto-destruction reference for EGLSync (for message-passing).
+ struct EGLSyncKHRRef;
+ void ReusePictureBufferTask(int32 picture_buffer_id,
+ scoped_ptr<EGLSyncKHRRef> egl_sync_ref);
+
+ // Called to actually send |dec_surface| to the client, after it is decoded
+ // preserving the order in which it was scheduled via SurfaceReady().
+ void OutputSurface(const scoped_refptr<V4L2DecodeSurface>& dec_surface);
+
+ // Goes over the |decoder_display_queue_| and sends all buffers from the
+ // front of the queue that are already decoded to the client, in order.
+ void TryOutputSurfaces();
+
+ // Creates a new decode surface or returns nullptr if one is not available.
+ scoped_refptr<V4L2DecodeSurface> CreateSurface();
+
+ // Send decoded pictures to PictureReady.
+ void SendPictureReady();
+
+ // Callback that indicates a picture has been cleared.
+ void PictureCleared();
+
+ size_t input_planes_count_;
+ size_t output_planes_count_;
+
+ // GPU Child thread task runner.
+ const scoped_refptr<base::SingleThreadTaskRunner> child_task_runner_;
+
+ // IO thread task runner.
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
+
+ // WeakPtr<> pointing to |this| for use in posting tasks from the decoder or
+ // device worker threads back to the child thread.
+ base::WeakPtr<V4L2SliceVideoDecodeAccelerator> weak_this_;
+
+ // To expose client callbacks from VideoDecodeAccelerator.
+ // NOTE: all calls to these objects *MUST* be executed on
+ // child_task_runner_.
+ scoped_ptr<base::WeakPtrFactory<VideoDecodeAccelerator::Client>>
+ client_ptr_factory_;
+ base::WeakPtr<VideoDecodeAccelerator::Client> client_;
+ // Callbacks to |io_client_| must be executed on |io_task_runner_|.
+ base::WeakPtr<Client> io_client_;
+
+ // V4L2 device in use.
+ scoped_refptr<V4L2Device> device_;
+
+ // Thread to communicate with the device on.
+ base::Thread decoder_thread_;
+ scoped_refptr<base::SingleThreadTaskRunner> decoder_thread_task_runner_;
+
+ // Thread used to poll the device for events.
+ base::Thread device_poll_thread_;
+
+ // Input queue state.
+ bool input_streamon_;
+ // Number of input buffers enqueued to the device.
+ int input_buffer_queued_count_;
+ // Input buffers ready to use; LIFO since we don't care about ordering.
+ std::list<int> free_input_buffers_;
+ // Mapping of int index to an input buffer record.
+ std::vector<InputRecord> input_buffer_map_;
+
+ // Output queue state.
+ bool output_streamon_;
+ // Number of output buffers enqueued to the device.
+ int output_buffer_queued_count_;
+ // Output buffers ready to use.
+ std::list<int> free_output_buffers_;
+ // Mapping of int index to an output buffer record.
+ std::vector<OutputRecord> output_buffer_map_;
+
+ media::VideoCodecProfile video_profile_;
+ uint32_t output_format_fourcc_;
+ gfx::Size visible_size_;
+ gfx::Size coded_size_;
+
+ struct BitstreamBufferRef;
+ // Input queue of stream buffers coming from the client.
+ std::queue<linked_ptr<BitstreamBufferRef>> decoder_input_queue_;
+ // BitstreamBuffer currently being processed.
+ scoped_ptr<BitstreamBufferRef> decoder_current_bitstream_buffer_;
+
+ // Queue storing decode surfaces ready to be output as soon as they are
+ // decoded. The surfaces must be output in order they are queued.
+ std::queue<scoped_refptr<V4L2DecodeSurface>> decoder_display_queue_;
+
+ // Decoder state.
+ State state_;
+
+ // If any of these are true, we are waiting for the device to finish decoding
+ // all previously-queued frames, so we can finish the flush/reset/surface
+ // change flows. These can stack.
+ bool decoder_flushing_;
+ bool decoder_resetting_;
+ bool surface_set_change_pending_;
+
+ // Hardware accelerators.
+ // TODO(posciak): Try to have a superclass here if possible.
+ scoped_ptr<V4L2H264Accelerator> h264_accelerator_;
+ scoped_ptr<V4L2VP8Accelerator> vp8_accelerator_;
+
+ // Codec-specific software decoder in use.
+ scoped_ptr<AcceleratedVideoDecoder> decoder_;
+
+ // Surfaces queued to device to keep references to them while decoded.
+ using V4L2DecodeSurfaceByOutputId =
+ std::map<int, scoped_refptr<V4L2DecodeSurface>>;
+ V4L2DecodeSurfaceByOutputId surfaces_at_device_;
+
+ // Surfaces sent to client to keep references to them while displayed.
+ using V4L2DecodeSurfaceByPictureBufferId =
+ std::map<int32, scoped_refptr<V4L2DecodeSurface>>;
+ V4L2DecodeSurfaceByPictureBufferId surfaces_at_display_;
+
+ // Record for decoded pictures that can be sent to PictureReady.
+ struct PictureRecord;
+ // Pictures that are ready but not sent to PictureReady yet.
+ std::queue<PictureRecord> pending_picture_ready_;
+
+ // The number of pictures that are sent to PictureReady and will be cleared.
+ int picture_clearing_count_;
+
+ // Used by the decoder thread to wait for AssignPictureBuffers to arrive
+ // to avoid races with potential Reset requests.
+ base::WaitableEvent pictures_assigned_;
+
+ // Make the GL context current callback.
+ base::Callback<bool(void)> make_context_current_;
+
+ // EGL state
+ EGLDisplay egl_display_;
+ EGLContext egl_context_;
+
+ // The WeakPtrFactory for |weak_this_|.
+ base::WeakPtrFactory<V4L2SliceVideoDecodeAccelerator> weak_this_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(V4L2SliceVideoDecodeAccelerator);
+};
+
+class V4L2H264Picture;
+class V4L2VP8Picture;
+
+} // namespace content
+
+#endif // CONTENT_COMMON_GPU_MEDIA_V4L2_SLICE_VIDEO_DECODE_ACCELERATOR_H_
diff --git a/chromium/content/common/gpu/media/v4l2_stub_header.fragment b/chromium/content/common/gpu/media/v4l2_stub_header.fragment
new file mode 100644
index 00000000000..9f8b2071d7b
--- /dev/null
+++ b/chromium/content/common/gpu/media/v4l2_stub_header.fragment
@@ -0,0 +1,8 @@
+// The extra include header needed in the generated stub file for defining
+// various Pulse types.
+
+extern "C" {
+
+#include "third_party/v4l-utils/lib/include/libv4l2.h"
+
+}
diff --git a/chromium/content/common/gpu/media/v4l2_video_decode_accelerator.cc b/chromium/content/common/gpu/media/v4l2_video_decode_accelerator.cc
index 243fee58d2e..dfd0866e47d 100644
--- a/chromium/content/common/gpu/media/v4l2_video_decode_accelerator.cc
+++ b/chromium/content/common/gpu/media/v4l2_video_decode_accelerator.cc
@@ -13,21 +13,21 @@
#include "base/bind.h"
#include "base/command_line.h"
-#include "base/debug/trace_event.h"
#include "base/memory/shared_memory.h"
#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
#include "base/numerics/safe_conversions.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/trace_event/trace_event.h"
#include "content/common/gpu/media/v4l2_video_decode_accelerator.h"
#include "media/base/media_switches.h"
#include "media/filters/h264_parser.h"
+#include "ui/gfx/geometry/rect.h"
#include "ui/gl/scoped_binders.h"
-#define NOTIFY_ERROR(x) \
- do { \
- SetDecoderState(kError); \
- LOG(ERROR) << "calling NotifyError(): " << x; \
- NotifyError(x); \
+#define NOTIFY_ERROR(x) \
+ do { \
+ LOG(ERROR) << "Setting error state:" << x; \
+ SetErrorState(x); \
} while (0)
#define IOCTL_OR_ERROR_RETURN_VALUE(type, arg, value) \
@@ -65,16 +65,16 @@ namespace {
struct V4L2VideoDecodeAccelerator::BitstreamBufferRef {
BitstreamBufferRef(
base::WeakPtr<Client>& client,
- scoped_refptr<base::MessageLoopProxy>& client_message_loop_proxy,
+ scoped_refptr<base::SingleThreadTaskRunner>& client_task_runner,
base::SharedMemory* shm,
size_t size,
int32 input_id);
~BitstreamBufferRef();
const base::WeakPtr<Client> client;
- const scoped_refptr<base::MessageLoopProxy> client_message_loop_proxy;
+ const scoped_refptr<base::SingleThreadTaskRunner> client_task_runner;
const scoped_ptr<base::SharedMemory> shm;
const size_t size;
- off_t bytes_used;
+ size_t bytes_used;
const int32 input_id;
};
@@ -94,10 +94,12 @@ struct V4L2VideoDecodeAccelerator::PictureRecord {
V4L2VideoDecodeAccelerator::BitstreamBufferRef::BitstreamBufferRef(
base::WeakPtr<Client>& client,
- scoped_refptr<base::MessageLoopProxy>& client_message_loop_proxy,
- base::SharedMemory* shm, size_t size, int32 input_id)
+ scoped_refptr<base::SingleThreadTaskRunner>& client_task_runner,
+ base::SharedMemory* shm,
+ size_t size,
+ int32 input_id)
: client(client),
- client_message_loop_proxy(client_message_loop_proxy),
+ client_task_runner(client_task_runner),
shm(shm),
size(size),
bytes_used(0),
@@ -106,8 +108,9 @@ V4L2VideoDecodeAccelerator::BitstreamBufferRef::BitstreamBufferRef(
V4L2VideoDecodeAccelerator::BitstreamBufferRef::~BitstreamBufferRef() {
if (input_id >= 0) {
- client_message_loop_proxy->PostTask(FROM_HERE, base::Bind(
- &Client::NotifyEndOfBitstreamBuffer, client, input_id));
+ client_task_runner->PostTask(
+ FROM_HERE,
+ base::Bind(&Client::NotifyEndOfBitstreamBuffer, client, input_id));
}
}
@@ -159,14 +162,14 @@ V4L2VideoDecodeAccelerator::V4L2VideoDecodeAccelerator(
EGLContext egl_context,
const base::WeakPtr<Client>& io_client,
const base::Callback<bool(void)>& make_context_current,
- scoped_ptr<V4L2Device> device,
- const scoped_refptr<base::MessageLoopProxy>& io_message_loop_proxy)
- : child_message_loop_proxy_(base::MessageLoopProxy::current()),
- io_message_loop_proxy_(io_message_loop_proxy),
+ const scoped_refptr<V4L2Device>& device,
+ const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
+ : child_task_runner_(base::ThreadTaskRunnerHandle::Get()),
+ io_task_runner_(io_task_runner),
io_client_(io_client),
decoder_thread_("V4L2DecoderThread"),
decoder_state_(kUninitialized),
- device_(device.Pass()),
+ device_(device),
decoder_delay_bitstream_buffer_id_(-1),
decoder_current_input_buffer_(-1),
decoder_decode_buffer_tasks_scheduled_(0),
@@ -188,6 +191,7 @@ V4L2VideoDecodeAccelerator::V4L2VideoDecodeAccelerator(
egl_display_(egl_display),
egl_context_(egl_context),
video_profile_(media::VIDEO_CODEC_PROFILE_UNKNOWN),
+ output_format_fourcc_(0),
weak_this_factory_(this) {
weak_this_ = weak_this_factory_.GetWeakPtr();
}
@@ -208,7 +212,7 @@ V4L2VideoDecodeAccelerator::~V4L2VideoDecodeAccelerator() {
bool V4L2VideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile,
Client* client) {
DVLOG(3) << "Initialize()";
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
DCHECK_EQ(decoder_state_, kUninitialized);
client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client));
@@ -227,6 +231,9 @@ bool V4L2VideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile,
case media::VP8PROFILE_ANY:
DVLOG(2) << "Initialize(): profile VP8PROFILE_ANY";
break;
+ case media::VP9PROFILE_ANY:
+ DVLOG(2) << "Initialize(): profile VP9PROFILE_ANY";
+ break;
default:
DLOG(ERROR) << "Initialize(): unsupported profile=" << profile;
return false;
@@ -235,22 +242,22 @@ bool V4L2VideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile,
if (egl_display_ == EGL_NO_DISPLAY) {
LOG(ERROR) << "Initialize(): could not get EGLDisplay";
- NOTIFY_ERROR(PLATFORM_FAILURE);
return false;
}
// We need the context to be initialized to query extensions.
if (!make_context_current_.Run()) {
LOG(ERROR) << "Initialize(): could not make context current";
- NOTIFY_ERROR(PLATFORM_FAILURE);
return false;
}
+// TODO(posciak): crbug.com/450898.
+#if defined(ARCH_CPU_ARMEL)
if (!gfx::g_driver_egl.ext.b_EGL_KHR_fence_sync) {
LOG(ERROR) << "Initialize(): context does not have EGL_KHR_fence_sync";
- NOTIFY_ERROR(PLATFORM_FAILURE);
return false;
}
+#endif
// Capabilities check.
struct v4l2_capability caps;
@@ -262,25 +269,11 @@ bool V4L2VideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile,
if ((caps.capabilities & kCapsRequired) != kCapsRequired) {
LOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP"
", caps check failed: 0x" << std::hex << caps.capabilities;
- NOTIFY_ERROR(PLATFORM_FAILURE);
return false;
}
- if (!CreateInputBuffers())
- return false;
-
- // Output format has to be setup before streaming starts.
- struct v4l2_format format;
- memset(&format, 0, sizeof(format));
- format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- uint32 output_format_fourcc = device_->PreferredOutputFormat();
- if (output_format_fourcc == 0) {
- // TODO(posciak): We should enumerate available output formats, as well as
- // take into account formats that the client is ready to accept.
+ if (!SetupFormats())
return false;
- }
- format.fmt.pix_mp.pixelformat = output_format_fourcc;
- IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT, &format);
// Subscribe to the resolution change event.
struct v4l2_event_subscription sub;
@@ -288,18 +281,21 @@ bool V4L2VideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile,
sub.type = V4L2_EVENT_RESOLUTION_CHANGE;
IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_SUBSCRIBE_EVENT, &sub);
- // Initialize format-specific bits.
if (video_profile_ >= media::H264PROFILE_MIN &&
video_profile_ <= media::H264PROFILE_MAX) {
decoder_h264_parser_.reset(new media::H264Parser());
}
+ if (!CreateInputBuffers())
+ return false;
+
if (!decoder_thread_.Start()) {
LOG(ERROR) << "Initialize(): decoder thread failed to start";
- NOTIFY_ERROR(PLATFORM_FAILURE);
return false;
}
+ decoder_state_ = kInitialized;
+
// StartDevicePoll will NOTIFY_ERROR on failure, so IgnoreResult is fine here.
decoder_thread_.message_loop()->PostTask(
FROM_HERE,
@@ -307,7 +303,6 @@ bool V4L2VideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile,
base::IgnoreResult(&V4L2VideoDecodeAccelerator::StartDevicePoll),
base::Unretained(this)));
- SetDecoderState(kInitialized);
return true;
}
@@ -315,7 +310,7 @@ void V4L2VideoDecodeAccelerator::Decode(
const media::BitstreamBuffer& bitstream_buffer) {
DVLOG(1) << "Decode(): input_id=" << bitstream_buffer.id()
<< ", size=" << bitstream_buffer.size();
- DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK(io_task_runner_->BelongsToCurrentThread());
// DecodeTask() will take care of running a DecodeBufferTask().
decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
@@ -326,7 +321,7 @@ void V4L2VideoDecodeAccelerator::Decode(
void V4L2VideoDecodeAccelerator::AssignPictureBuffers(
const std::vector<media::PictureBuffer>& buffers) {
DVLOG(3) << "AssignPictureBuffers(): buffer_count=" << buffers.size();
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
if (buffers.size() != output_buffer_map_.size()) {
LOG(ERROR) << "AssignPictureBuffers(): Failed to provide requested picture"
@@ -348,7 +343,7 @@ void V4L2VideoDecodeAccelerator::AssignPictureBuffers(
// thread is waiting on pictures_assigned_.
DCHECK(free_output_buffers_.empty());
for (size_t i = 0; i < output_buffer_map_.size(); ++i) {
- DCHECK(buffers[i].size() == frame_buffer_size_);
+ DCHECK(buffers[i].size() == coded_size_);
OutputRecord& output_record = output_buffer_map_[i];
DCHECK(!output_record.at_device);
@@ -361,8 +356,9 @@ void V4L2VideoDecodeAccelerator::AssignPictureBuffers(
EGLImageKHR egl_image = device_->CreateEGLImage(egl_display_,
egl_context_,
buffers[i].texture_id(),
- frame_buffer_size_,
+ coded_size_,
i,
+ output_format_fourcc_,
output_planes_count_);
if (egl_image == EGL_NO_IMAGE_KHR) {
LOG(ERROR) << "AssignPictureBuffers(): could not create EGLImageKHR";
@@ -386,7 +382,7 @@ void V4L2VideoDecodeAccelerator::AssignPictureBuffers(
void V4L2VideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) {
DVLOG(3) << "ReusePictureBuffer(): picture_buffer_id=" << picture_buffer_id;
// Must be run on child thread, as we'll insert a sync in the EGL context.
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
if (!make_context_current_.Run()) {
LOG(ERROR) << "ReusePictureBuffer(): could not make context current";
@@ -394,13 +390,16 @@ void V4L2VideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) {
return;
}
- EGLSyncKHR egl_sync =
- eglCreateSyncKHR(egl_display_, EGL_SYNC_FENCE_KHR, NULL);
+ EGLSyncKHR egl_sync = EGL_NO_SYNC_KHR;
+// TODO(posciak): crbug.com/450898.
+#if defined(ARCH_CPU_ARMEL)
+ egl_sync = eglCreateSyncKHR(egl_display_, EGL_SYNC_FENCE_KHR, NULL);
if (egl_sync == EGL_NO_SYNC_KHR) {
LOG(ERROR) << "ReusePictureBuffer(): eglCreateSyncKHR() failed";
NOTIFY_ERROR(PLATFORM_FAILURE);
return;
}
+#endif
scoped_ptr<EGLSyncKHRRef> egl_sync_ref(new EGLSyncKHRRef(
egl_display_, egl_sync));
@@ -411,21 +410,21 @@ void V4L2VideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) {
void V4L2VideoDecodeAccelerator::Flush() {
DVLOG(3) << "Flush()";
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
&V4L2VideoDecodeAccelerator::FlushTask, base::Unretained(this)));
}
void V4L2VideoDecodeAccelerator::Reset() {
DVLOG(3) << "Reset()";
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
&V4L2VideoDecodeAccelerator::ResetTask, base::Unretained(this)));
}
void V4L2VideoDecodeAccelerator::Destroy() {
DVLOG(3) << "Destroy()";
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
// We're destroying; cancel all callbacks.
client_ptr_factory_.reset();
@@ -443,14 +442,24 @@ void V4L2VideoDecodeAccelerator::Destroy() {
DestroyTask();
}
- // Set to kError state just in case.
- SetDecoderState(kError);
-
delete this;
}
bool V4L2VideoDecodeAccelerator::CanDecodeOnIOThread() { return true; }
+// static
+media::VideoDecodeAccelerator::SupportedProfiles
+V4L2VideoDecodeAccelerator::GetSupportedProfiles() {
+ scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder);
+ if (!device)
+ return SupportedProfiles();
+
+ const uint32_t supported_formats[] = {
+ V4L2_PIX_FMT_H264, V4L2_PIX_FMT_VP8, V4L2_PIX_FMT_VP9};
+ return device->GetSupportedDecodeProfiles(arraysize(supported_formats),
+ supported_formats);
+}
+
void V4L2VideoDecodeAccelerator::DecodeTask(
const media::BitstreamBuffer& bitstream_buffer) {
DVLOG(3) << "DecodeTask(): input_id=" << bitstream_buffer.id();
@@ -460,7 +469,7 @@ void V4L2VideoDecodeAccelerator::DecodeTask(
bitstream_buffer.id());
scoped_ptr<BitstreamBufferRef> bitstream_record(new BitstreamBufferRef(
- io_client_, io_message_loop_proxy_,
+ io_client_, io_task_runner_,
new base::SharedMemory(bitstream_buffer.handle(), true),
bitstream_buffer.size(), bitstream_buffer.id()));
if (!bitstream_record->shm->Map(bitstream_buffer.size())) {
@@ -688,8 +697,8 @@ bool V4L2VideoDecodeAccelerator::AdvanceFrameFragment(
return false;
} else {
DCHECK_GE(video_profile_, media::VP8PROFILE_MIN);
- DCHECK_LE(video_profile_, media::VP8PROFILE_MAX);
- // For VP8, we can just dump the entire buffer. No fragmentation needed,
+ DCHECK_LE(video_profile_, media::VP9PROFILE_MAX);
+ // For VP8/9, we can just dump the entire buffer. No fragmentation needed,
// and we never return a partial frame.
*endpos = size;
decoder_partial_frame_pending_ = false;
@@ -737,13 +746,15 @@ bool V4L2VideoDecodeAccelerator::DecodeBufferInitial(
// Check and see if we have format info yet.
struct v4l2_format format;
+ gfx::Size visible_size;
bool again = false;
- if (!GetFormatInfo(&format, &again))
+ if (!GetFormatInfo(&format, &visible_size, &again))
return false;
+ *endpos = size;
+
if (again) {
// Need more stream to decode format, return true and schedule next buffer.
- *endpos = size;
return true;
}
@@ -751,16 +762,8 @@ bool V4L2VideoDecodeAccelerator::DecodeBufferInitial(
if (decoder_state_ == kInitialized) {
DVLOG(3) << "DecodeBufferInitial(): running initialization";
// Success! Setup our parameters.
- if (!CreateBuffersForFormat(format))
+ if (!CreateBuffersForFormat(format, visible_size))
return false;
-
- // We expect to process the initial buffer once during stream init to
- // configure stream parameters, but will not consume the steam data on that
- // iteration. Subsequent iterations (including after reset) do not require
- // the stream init step.
- *endpos = 0;
- } else {
- *endpos = size;
}
decoder_state_ = kDecoding;
@@ -1083,7 +1086,7 @@ void V4L2VideoDecodeAccelerator::Dequeue() {
DCHECK_NE(output_record.egl_image, EGL_NO_IMAGE_KHR);
DCHECK_NE(output_record.picture_id, -1);
output_record.at_device = false;
- if (dqbuf.m.planes[0].bytesused + dqbuf.m.planes[1].bytesused == 0) {
+ if (dqbuf.m.planes[0].bytesused == 0) {
// This is an empty output buffer returned as part of a flush.
free_output_buffers_.push(dqbuf.index);
} else {
@@ -1092,9 +1095,8 @@ void V4L2VideoDecodeAccelerator::Dequeue() {
DVLOG(3) << "Dequeue(): returning input_id=" << dqbuf.timestamp.tv_sec
<< " as picture_id=" << output_record.picture_id;
const media::Picture& picture =
- media::Picture(output_record.picture_id,
- dqbuf.timestamp.tv_sec,
- gfx::Rect(frame_buffer_size_));
+ media::Picture(output_record.picture_id, dqbuf.timestamp.tv_sec,
+ gfx::Rect(visible_size_), false);
pending_picture_ready_.push(
PictureRecord(output_record.cleared, picture));
SendPictureReady();
@@ -1244,8 +1246,8 @@ void V4L2VideoDecodeAccelerator::FlushTask() {
if (decoder_state_ == kInitialized || decoder_state_ == kAfterReset) {
// There's nothing in the pipe, so return done immediately.
DVLOG(3) << "FlushTask(): returning flush";
- child_message_loop_proxy_->PostTask(
- FROM_HERE, base::Bind(&Client::NotifyFlushDone, client_));
+ child_task_runner_->PostTask(FROM_HERE,
+ base::Bind(&Client::NotifyFlushDone, client_));
return;
} else if (decoder_state_ == kError) {
DVLOG(2) << "FlushTask(): early out: kError state";
@@ -1258,7 +1260,7 @@ void V4L2VideoDecodeAccelerator::FlushTask() {
// Queue up an empty buffer -- this triggers the flush.
decoder_input_queue_.push(
linked_ptr<BitstreamBufferRef>(new BitstreamBufferRef(
- io_client_, io_message_loop_proxy_, NULL, 0, kFlushBufferId)));
+ io_client_, io_task_runner_, NULL, 0, kFlushBufferId)));
decoder_flushing_ = true;
SendPictureReady(); // Send all pending PictureReady.
@@ -1302,8 +1304,8 @@ void V4L2VideoDecodeAccelerator::NotifyFlushDoneIfNeeded() {
decoder_delay_bitstream_buffer_id_ = -1;
decoder_flushing_ = false;
DVLOG(3) << "NotifyFlushDoneIfNeeded(): returning flush";
- child_message_loop_proxy_->PostTask(
- FROM_HERE, base::Bind(&Client::NotifyFlushDone, client_));
+ child_task_runner_->PostTask(FROM_HERE,
+ base::Bind(&Client::NotifyFlushDone, client_));
// While we were flushing, we early-outed DecodeBufferTask()s.
ScheduleDecodeBufferTaskIfNeeded();
@@ -1389,8 +1391,8 @@ void V4L2VideoDecodeAccelerator::ResetDoneTask() {
decoder_partial_frame_pending_ = false;
decoder_delay_bitstream_buffer_id_ = -1;
- child_message_loop_proxy_->PostTask(FROM_HERE, base::Bind(
- &Client::NotifyResetDone, client_));
+ child_task_runner_->PostTask(FROM_HERE,
+ base::Bind(&Client::NotifyResetDone, client_));
// While we were resetting, we early-outed DecodeBufferTask()s.
ScheduleDecodeBufferTaskIfNeeded();
@@ -1525,9 +1527,10 @@ void V4L2VideoDecodeAccelerator::StartResolutionChangeIfNeeded() {
// Post a task to clean up buffers on child thread. This will also ensure
// that we won't accept ReusePictureBuffer() anymore after that.
- child_message_loop_proxy_->PostTask(FROM_HERE, base::Bind(
- &V4L2VideoDecodeAccelerator::ResolutionChangeDestroyBuffers,
- weak_this_));
+ child_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&V4L2VideoDecodeAccelerator::ResolutionChangeDestroyBuffers,
+ weak_this_));
}
void V4L2VideoDecodeAccelerator::FinishResolutionChange() {
@@ -1542,14 +1545,15 @@ void V4L2VideoDecodeAccelerator::FinishResolutionChange() {
struct v4l2_format format;
bool again;
- bool ret = GetFormatInfo(&format, &again);
+ gfx::Size visible_size;
+ bool ret = GetFormatInfo(&format, &visible_size, &again);
if (!ret || again) {
LOG(ERROR) << "Couldn't get format information after resolution change";
NOTIFY_ERROR(PLATFORM_FAILURE);
return;
}
- if (!CreateBuffersForFormat(format)) {
+ if (!CreateBuffersForFormat(format, visible_size)) {
LOG(ERROR) << "Couldn't reallocate buffers after resolution change";
NOTIFY_ERROR(PLATFORM_FAILURE);
return;
@@ -1592,9 +1596,10 @@ void V4L2VideoDecodeAccelerator::DevicePollTask(bool poll_device) {
void V4L2VideoDecodeAccelerator::NotifyError(Error error) {
DVLOG(2) << "NotifyError()";
- if (!child_message_loop_proxy_->BelongsToCurrentThread()) {
- child_message_loop_proxy_->PostTask(FROM_HERE, base::Bind(
- &V4L2VideoDecodeAccelerator::NotifyError, weak_this_, error));
+ if (!child_task_runner_->BelongsToCurrentThread()) {
+ child_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&V4L2VideoDecodeAccelerator::NotifyError,
+ weak_this_, error));
return;
}
@@ -1604,23 +1609,28 @@ void V4L2VideoDecodeAccelerator::NotifyError(Error error) {
}
}
-void V4L2VideoDecodeAccelerator::SetDecoderState(State state) {
- DVLOG(3) << "SetDecoderState(): state=" << state;
-
+void V4L2VideoDecodeAccelerator::SetErrorState(Error error) {
// We can touch decoder_state_ only if this is the decoder thread or the
// decoder thread isn't running.
if (decoder_thread_.message_loop() != NULL &&
decoder_thread_.message_loop() != base::MessageLoop::current()) {
decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
- &V4L2VideoDecodeAccelerator::SetDecoderState,
- base::Unretained(this), state));
- } else {
- decoder_state_ = state;
+ &V4L2VideoDecodeAccelerator::SetErrorState,
+ base::Unretained(this), error));
+ return;
}
+
+ // Post NotifyError only if we are already initialized, as the API does
+ // not allow doing so before that.
+ if (decoder_state_ != kError && decoder_state_ != kUninitialized)
+ NotifyError(error);
+
+ decoder_state_ = kError;
}
bool V4L2VideoDecodeAccelerator::GetFormatInfo(struct v4l2_format* format,
- bool* again) {
+ gfx::Size* visible_size,
+ bool* again) {
DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current());
*again = false;
@@ -1638,17 +1648,29 @@ bool V4L2VideoDecodeAccelerator::GetFormatInfo(struct v4l2_format* format,
}
}
+ // Make sure we are still getting the format we set on initialization.
+ if (format->fmt.pix_mp.pixelformat != output_format_fourcc_) {
+ LOG(ERROR) << "Unexpected format from G_FMT on output";
+ return false;
+ }
+
+ gfx::Size coded_size(format->fmt.pix_mp.width, format->fmt.pix_mp.height);
+ if (visible_size != nullptr)
+ *visible_size = GetVisibleSize(coded_size);
+
return true;
}
bool V4L2VideoDecodeAccelerator::CreateBuffersForFormat(
- const struct v4l2_format& format) {
+ const struct v4l2_format& format,
+ const gfx::Size& visible_size) {
DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current());
output_planes_count_ = format.fmt.pix_mp.num_planes;
- frame_buffer_size_.SetSize(
- format.fmt.pix_mp.width, format.fmt.pix_mp.height);
+ coded_size_.SetSize(format.fmt.pix_mp.width, format.fmt.pix_mp.height);
+ visible_size_ = visible_size;
DVLOG(3) << "CreateBuffersForFormat(): new resolution: "
- << frame_buffer_size_.ToString();
+ << coded_size_.ToString() << ", visible size: "
+ << visible_size_.ToString();
if (!CreateOutputBuffers())
return false;
@@ -1656,6 +1678,42 @@ bool V4L2VideoDecodeAccelerator::CreateBuffersForFormat(
return true;
}
+gfx::Size V4L2VideoDecodeAccelerator::GetVisibleSize(
+ const gfx::Size& coded_size) {
+ DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current());
+
+ struct v4l2_crop crop_arg;
+ memset(&crop_arg, 0, sizeof(crop_arg));
+ crop_arg.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+
+ if (device_->Ioctl(VIDIOC_G_CROP, &crop_arg) != 0) {
+ PLOG(ERROR) << "GetVisibleSize(): ioctl() VIDIOC_G_CROP failed";
+ return coded_size;
+ }
+
+ gfx::Rect rect(crop_arg.c.left, crop_arg.c.top, crop_arg.c.width,
+ crop_arg.c.height);
+ DVLOG(3) << "visible rectangle is " << rect.ToString();
+ if (!gfx::Rect(coded_size).Contains(rect)) {
+ DLOG(ERROR) << "visible rectangle " << rect.ToString()
+ << " is not inside coded size " << coded_size.ToString();
+ return coded_size;
+ }
+ if (rect.IsEmpty()) {
+ DLOG(ERROR) << "visible size is empty";
+ return coded_size;
+ }
+
+ // Chrome assume picture frame is coded at (0, 0).
+ if (!rect.origin().IsOrigin()) {
+ DLOG(ERROR) << "Unexpected visible rectangle " << rect.ToString()
+ << ", top-left is not origin";
+ return coded_size;
+ }
+
+ return rect.size();
+}
+
bool V4L2VideoDecodeAccelerator::CreateInputBuffers() {
DVLOG(3) << "CreateInputBuffers()";
// We always run this as we prepare to initialize.
@@ -1663,24 +1721,6 @@ bool V4L2VideoDecodeAccelerator::CreateInputBuffers() {
DCHECK(!input_streamon_);
DCHECK(input_buffer_map_.empty());
- __u32 pixelformat = V4L2Device::VideoCodecProfileToV4L2PixFmt(video_profile_);
- if (!pixelformat) {
- NOTREACHED();
- return false;
- }
-
- struct v4l2_format format;
- memset(&format, 0, sizeof(format));
- format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
- format.fmt.pix_mp.pixelformat = pixelformat;
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kIgnoreResolutionLimitsForAcceleratedVideoDecode))
- format.fmt.pix_mp.plane_fmt[0].sizeimage = kInputBufferMaxSizeFor4k;
- else
- format.fmt.pix_mp.plane_fmt[0].sizeimage = kInputBufferMaxSizeFor1080p;
- format.fmt.pix_mp.num_planes = 1;
- IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT, &format);
-
struct v4l2_requestbuffers reqbufs;
memset(&reqbufs, 0, sizeof(reqbufs));
reqbufs.count = kInputBufferCount;
@@ -1718,6 +1758,65 @@ bool V4L2VideoDecodeAccelerator::CreateInputBuffers() {
return true;
}
+bool V4L2VideoDecodeAccelerator::SetupFormats() {
+ // We always run this as we prepare to initialize.
+ DCHECK_EQ(decoder_state_, kUninitialized);
+ DCHECK(!input_streamon_);
+ DCHECK(!output_streamon_);
+
+ __u32 input_format_fourcc =
+ V4L2Device::VideoCodecProfileToV4L2PixFmt(video_profile_, false);
+ if (!input_format_fourcc) {
+ NOTREACHED();
+ return false;
+ }
+
+ size_t input_size;
+ gfx::Size max_resolution, min_resolution;
+ device_->GetSupportedResolution(input_format_fourcc, &min_resolution,
+ &max_resolution);
+ if (max_resolution.width() > 1920 && max_resolution.height() > 1088)
+ input_size = kInputBufferMaxSizeFor4k;
+ else
+ input_size = kInputBufferMaxSizeFor1080p;
+
+ struct v4l2_format format;
+ memset(&format, 0, sizeof(format));
+ format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ format.fmt.pix_mp.pixelformat = input_format_fourcc;
+ format.fmt.pix_mp.plane_fmt[0].sizeimage = input_size;
+ format.fmt.pix_mp.num_planes = 1;
+ IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT, &format);
+
+ // We have to set up the format for output, because the driver may not allow
+ // changing it once we start streaming; whether it can support our chosen
+ // output format or not may depend on the input format.
+ struct v4l2_fmtdesc fmtdesc;
+ memset(&fmtdesc, 0, sizeof(fmtdesc));
+ fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ while (device_->Ioctl(VIDIOC_ENUM_FMT, &fmtdesc) == 0) {
+ if (device_->CanCreateEGLImageFrom(fmtdesc.pixelformat)) {
+ output_format_fourcc_ = fmtdesc.pixelformat;
+ break;
+ }
+ ++fmtdesc.index;
+ }
+
+ if (output_format_fourcc_ == 0) {
+ LOG(ERROR) << "Could not find a usable output format";
+ return false;
+ }
+
+ // Just set the fourcc for output; resolution, etc., will come from the
+ // driver once it extracts it from the stream.
+ memset(&format, 0, sizeof(format));
+ format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ format.fmt.pix_mp.pixelformat = output_format_fourcc_;
+ IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT, &format);
+
+ return true;
+}
+
bool V4L2VideoDecodeAccelerator::CreateOutputBuffers() {
DVLOG(3) << "CreateOutputBuffers()";
DCHECK(decoder_state_ == kInitialized ||
@@ -1746,14 +1845,11 @@ bool V4L2VideoDecodeAccelerator::CreateOutputBuffers() {
DVLOG(3) << "CreateOutputBuffers(): ProvidePictureBuffers(): "
<< "buffer_count=" << output_buffer_map_.size()
- << ", width=" << frame_buffer_size_.width()
- << ", height=" << frame_buffer_size_.height();
- child_message_loop_proxy_->PostTask(FROM_HERE,
- base::Bind(&Client::ProvidePictureBuffers,
- client_,
- output_buffer_map_.size(),
- frame_buffer_size_,
- device_->GetTextureTarget()));
+ << ", coded_size=" << coded_size_.ToString();
+ child_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&Client::ProvidePictureBuffers, client_,
+ output_buffer_map_.size(), coded_size_,
+ device_->GetTextureTarget()));
// Wait for the client to call AssignPictureBuffers() on the Child thread.
// We do this, because if we continue decoding without finishing buffer
@@ -1776,7 +1872,7 @@ bool V4L2VideoDecodeAccelerator::CreateOutputBuffers() {
void V4L2VideoDecodeAccelerator::DestroyInputBuffers() {
DVLOG(3) << "DestroyInputBuffers()";
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
DCHECK(!input_streamon_);
for (size_t i = 0; i < input_buffer_map_.size(); ++i) {
@@ -1799,7 +1895,7 @@ void V4L2VideoDecodeAccelerator::DestroyInputBuffers() {
bool V4L2VideoDecodeAccelerator::DestroyOutputBuffers() {
DVLOG(3) << "DestroyOutputBuffers()";
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
DCHECK(!output_streamon_);
bool success = true;
@@ -1823,10 +1919,9 @@ bool V4L2VideoDecodeAccelerator::DestroyOutputBuffers() {
DVLOG(1) << "DestroyOutputBuffers(): dismissing PictureBuffer id="
<< output_record.picture_id;
- child_message_loop_proxy_->PostTask(
- FROM_HERE,
- base::Bind(
- &Client::DismissPictureBuffer, client_, output_record.picture_id));
+ child_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&Client::DismissPictureBuffer, client_,
+ output_record.picture_id));
}
struct v4l2_requestbuffers reqbufs;
@@ -1847,7 +1942,7 @@ bool V4L2VideoDecodeAccelerator::DestroyOutputBuffers() {
}
void V4L2VideoDecodeAccelerator::ResolutionChangeDestroyBuffers() {
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
DVLOG(3) << "ResolutionChangeDestroyBuffers()";
if (!DestroyOutputBuffers()) {
@@ -1873,7 +1968,7 @@ void V4L2VideoDecodeAccelerator::SendPictureReady() {
if (cleared && picture_clearing_count_ == 0) {
// This picture is cleared. Post it to IO thread to reduce latency. This
// should be the case after all pictures are cleared at the beginning.
- io_message_loop_proxy_->PostTask(
+ io_task_runner_->PostTask(
FROM_HERE, base::Bind(&Client::PictureReady, io_client_, picture));
pending_picture_ready_.pop();
} else if (!cleared || resetting_or_flushing) {
@@ -1886,9 +1981,8 @@ void V4L2VideoDecodeAccelerator::SendPictureReady() {
// has to be cleared in the child thread. A picture only needs to be
// cleared once. If the decoder is resetting or flushing, send all
// pictures to ensure PictureReady arrive before reset or flush done.
- child_message_loop_proxy_->PostTaskAndReply(
- FROM_HERE,
- base::Bind(&Client::PictureReady, client_, picture),
+ child_task_runner_->PostTaskAndReply(
+ FROM_HERE, base::Bind(&Client::PictureReady, client_, picture),
// Unretained is safe. If Client::PictureReady gets to run, |this| is
// alive. Destroy() will wait the decode thread to finish.
base::Bind(&V4L2VideoDecodeAccelerator::PictureCleared,
@@ -1926,14 +2020,14 @@ bool V4L2VideoDecodeAccelerator::IsResolutionChangeNecessary() {
}
struct v4l2_format format;
bool again = false;
- bool ret = GetFormatInfo(&format, &again);
+ bool ret = GetFormatInfo(&format, nullptr, &again);
if (!ret || again) {
DVLOG(3) << "IsResolutionChangeNecessary(): GetFormatInfo() failed";
return false;
}
- gfx::Size new_size(base::checked_cast<int>(format.fmt.pix_mp.width),
- base::checked_cast<int>(format.fmt.pix_mp.height));
- if (frame_buffer_size_ != new_size) {
+ gfx::Size new_coded_size(base::checked_cast<int>(format.fmt.pix_mp.width),
+ base::checked_cast<int>(format.fmt.pix_mp.height));
+ if (coded_size_ != new_coded_size) {
DVLOG(3) << "IsResolutionChangeNecessary(): Resolution change detected";
return true;
}
diff --git a/chromium/content/common/gpu/media/v4l2_video_decode_accelerator.h b/chromium/content/common/gpu/media/v4l2_video_decode_accelerator.h
index 9b973105f3b..3dfd8606b82 100644
--- a/chromium/content/common/gpu/media/v4l2_video_decode_accelerator.h
+++ b/chromium/content/common/gpu/media/v4l2_video_decode_accelerator.h
@@ -14,22 +14,19 @@
#include "base/callback_forward.h"
#include "base/memory/linked_ptr.h"
+#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
#include "content/common/content_export.h"
-#include "content/common/gpu/media/v4l2_video_device.h"
+#include "content/common/gpu/media/v4l2_device.h"
#include "media/base/limits.h"
#include "media/base/video_decoder_config.h"
#include "media/video/picture.h"
#include "media/video/video_decode_accelerator.h"
-#include "ui/gfx/size.h"
+#include "ui/gfx/geometry/size.h"
#include "ui/gl/gl_bindings.h"
-namespace base {
-class MessageLoopProxy;
-} // namespace base
-
namespace media {
class H264Parser;
} // namespace media
@@ -80,22 +77,25 @@ class CONTENT_EXPORT V4L2VideoDecodeAccelerator
EGLContext egl_context,
const base::WeakPtr<Client>& io_client_,
const base::Callback<bool(void)>& make_context_current,
- scoped_ptr<V4L2Device> device,
- const scoped_refptr<base::MessageLoopProxy>& io_message_loop_proxy);
- virtual ~V4L2VideoDecodeAccelerator();
+ const scoped_refptr<V4L2Device>& device,
+ const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner);
+ ~V4L2VideoDecodeAccelerator() override;
// media::VideoDecodeAccelerator implementation.
// Note: Initialize() and Destroy() are synchronous.
- virtual bool Initialize(media::VideoCodecProfile profile,
- Client* client) override;
- virtual void Decode(const media::BitstreamBuffer& bitstream_buffer) override;
- virtual void AssignPictureBuffers(
+ bool Initialize(media::VideoCodecProfile profile,
+ Client* client) override;
+ void Decode(const media::BitstreamBuffer& bitstream_buffer) override;
+ void AssignPictureBuffers(
const std::vector<media::PictureBuffer>& buffers) override;
- virtual void ReusePictureBuffer(int32 picture_buffer_id) override;
- virtual void Flush() override;
- virtual void Reset() override;
- virtual void Destroy() override;
- virtual bool CanDecodeOnIOThread() override;
+ void ReusePictureBuffer(int32 picture_buffer_id) override;
+ void Flush() override;
+ void Reset() override;
+ void Destroy() override;
+ bool CanDecodeOnIOThread() override;
+
+ static media::VideoDecodeAccelerator::SupportedProfiles
+ GetSupportedProfiles();
private:
// These are rather subjectively tuned.
@@ -241,11 +241,19 @@ class CONTENT_EXPORT V4L2VideoDecodeAccelerator
void StartResolutionChangeIfNeeded();
void FinishResolutionChange();
- // Try to get output format, detected after parsing the beginning
- // of the stream. Sets |again| to true if more parsing is needed.
- bool GetFormatInfo(struct v4l2_format* format, bool* again);
- // Create output buffers for the given |format|.
- bool CreateBuffersForFormat(const struct v4l2_format& format);
+ // Try to get output format and visible size, detected after parsing the
+ // beginning of the stream. Sets |again| to true if more parsing is needed.
+ // |visible_size| could be nullptr and ignored.
+ bool GetFormatInfo(struct v4l2_format* format,
+ gfx::Size* visible_size,
+ bool* again);
+ // Create output buffers for the given |format| and |visible_size|.
+ bool CreateBuffersForFormat(const struct v4l2_format& format,
+ const gfx::Size& visible_size);
+
+ // Try to get |visible_size|. Return visible size, or, if querying it is not
+ // supported or produces invalid size, return |coded_size| instead.
+ gfx::Size GetVisibleSize(const gfx::Size& coded_size);
//
// Device tasks, to be run on device_poll_thread_.
@@ -261,9 +269,8 @@ class CONTENT_EXPORT V4L2VideoDecodeAccelerator
// Error notification (using PostTask() to child thread, if necessary).
void NotifyError(Error error);
- // Set the decoder_thread_ state (using PostTask to decoder thread, if
- // necessary).
- void SetDecoderState(State state);
+ // Set the decoder_state_ to kError and notify the client (if necessary).
+ void SetErrorState(Error error);
//
// Other utility functions. Called on decoder_thread_, unless
@@ -275,6 +282,9 @@ class CONTENT_EXPORT V4L2VideoDecodeAccelerator
bool CreateInputBuffers();
bool CreateOutputBuffers();
+ // Set input and output formats before starting decode.
+ bool SetupFormats();
+
//
// Methods run on child thread.
//
@@ -301,11 +311,11 @@ class CONTENT_EXPORT V4L2VideoDecodeAccelerator
// - V4L2_CID_MIN_BUFFERS_FOR_CAPTURE has changed.
bool IsResolutionChangeNecessary();
- // Our original calling message loop for the child thread.
- scoped_refptr<base::MessageLoopProxy> child_message_loop_proxy_;
+ // Our original calling task runner for the child thread.
+ scoped_refptr<base::SingleThreadTaskRunner> child_task_runner_;
- // Message loop of the IO thread.
- scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_;
+ // Task runner of the IO thread.
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
// WeakPtr<> pointing to |this| for use in posting tasks from the decoder or
// device worker threads back to the child thread. Because the worker threads
@@ -317,10 +327,10 @@ class CONTENT_EXPORT V4L2VideoDecodeAccelerator
// To expose client callbacks from VideoDecodeAccelerator.
// NOTE: all calls to these objects *MUST* be executed on
- // child_message_loop_proxy_.
+ // child_task_runner_.
scoped_ptr<base::WeakPtrFactory<Client> > client_ptr_factory_;
base::WeakPtr<Client> client_;
- // Callbacks to |io_client_| must be executed on |io_message_loop_proxy_|.
+ // Callbacks to |io_client_| must be executed on |io_task_runner_|.
base::WeakPtr<Client> io_client_;
//
@@ -338,7 +348,7 @@ class CONTENT_EXPORT V4L2VideoDecodeAccelerator
// BitstreamBuffer we're presently reading.
scoped_ptr<BitstreamBufferRef> decoder_current_bitstream_buffer_;
// The V4L2Device this class is operating upon.
- scoped_ptr<V4L2Device> device_;
+ scoped_refptr<V4L2Device> device_;
// FlushTask() and ResetTask() should not affect buffers that have been
// queued afterwards. For flushing or resetting the pipeline then, we will
// delay these buffers until after the flush or reset completes.
@@ -398,7 +408,8 @@ class CONTENT_EXPORT V4L2VideoDecodeAccelerator
std::vector<OutputRecord> output_buffer_map_;
// Required size of DPB for decoding.
int output_dpb_size_;
- // Stores the number of planes (i.e. separate memory buffers) for output.
+
+ // Number of planes (i.e. separate memory buffers) for output.
size_t output_planes_count_;
// Pictures that are ready but not sent to PictureReady yet.
@@ -411,8 +422,11 @@ class CONTENT_EXPORT V4L2VideoDecodeAccelerator
// to avoid races with potential Reset requests.
base::WaitableEvent pictures_assigned_;
- // Output picture size.
- gfx::Size frame_buffer_size_;
+ // Output picture coded size.
+ gfx::Size coded_size_;
+
+ // Output picture visible size.
+ gfx::Size visible_size_;
//
// The device polling thread handles notifications of V4L2 device changes.
@@ -434,6 +448,8 @@ class CONTENT_EXPORT V4L2VideoDecodeAccelerator
// The codec we'll be decoding for.
media::VideoCodecProfile video_profile_;
+ // Chosen output format.
+ uint32_t output_format_fourcc_;
// The WeakPtrFactory for |weak_this_|.
base::WeakPtrFactory<V4L2VideoDecodeAccelerator> weak_this_factory_;
diff --git a/chromium/content/common/gpu/media/v4l2_video_device.cc b/chromium/content/common/gpu/media/v4l2_video_device.cc
deleted file mode 100644
index 58b935a4008..00000000000
--- a/chromium/content/common/gpu/media/v4l2_video_device.cc
+++ /dev/null
@@ -1,143 +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 <linux/videodev2.h>
-
-#include "base/numerics/safe_conversions.h"
-#include "content/common/gpu/media/exynos_v4l2_video_device.h"
-#include "content/common/gpu/media/tegra_v4l2_video_device.h"
-
-namespace content {
-
-V4L2Device::~V4L2Device() {}
-
-// static
-scoped_ptr<V4L2Device> V4L2Device::Create(Type type) {
- DVLOG(3) << __PRETTY_FUNCTION__;
-
- scoped_ptr<ExynosV4L2Device> exynos_device(new ExynosV4L2Device(type));
- if (exynos_device->Initialize())
- return exynos_device.Pass();
-
- scoped_ptr<TegraV4L2Device> tegra_device(new TegraV4L2Device(type));
- if (tegra_device->Initialize())
- return tegra_device.Pass();
-
- LOG(ERROR) << "Failed to create V4L2Device";
- return scoped_ptr<V4L2Device>();
-}
-
-// static
-media::VideoFrame::Format V4L2Device::V4L2PixFmtToVideoFrameFormat(
- uint32 pix_fmt) {
- switch (pix_fmt) {
- case V4L2_PIX_FMT_NV12:
- case V4L2_PIX_FMT_NV12M:
- return media::VideoFrame::NV12;
-
- case V4L2_PIX_FMT_YUV420:
- case V4L2_PIX_FMT_YUV420M:
- return media::VideoFrame::I420;
-
- default:
- LOG(FATAL) << "Add more cases as needed";
- return media::VideoFrame::UNKNOWN;
- }
-}
-
-// static
-uint32 V4L2Device::VideoFrameFormatToV4L2PixFmt(
- media::VideoFrame::Format format) {
- switch (format) {
- case media::VideoFrame::NV12:
- return V4L2_PIX_FMT_NV12M;
-
- case media::VideoFrame::I420:
- return V4L2_PIX_FMT_YUV420M;
-
- default:
- LOG(FATAL) << "Add more cases as needed";
- return 0;
- }
-}
-
-// static
-uint32 V4L2Device::VideoCodecProfileToV4L2PixFmt(
- media::VideoCodecProfile profile) {
- if (profile >= media::H264PROFILE_MIN &&
- profile <= media::H264PROFILE_MAX) {
- return V4L2_PIX_FMT_H264;
- } else if (profile >= media::VP8PROFILE_MIN &&
- profile <= media::VP8PROFILE_MAX) {
- return V4L2_PIX_FMT_VP8;
- } else {
- LOG(FATAL) << "Add more cases as needed";
- return 0;
- }
-}
-
-// static
-gfx::Size V4L2Device::CodedSizeFromV4L2Format(struct v4l2_format format) {
- gfx::Size coded_size;
- gfx::Size visible_size;
- media::VideoFrame::Format frame_format = media::VideoFrame::UNKNOWN;
- int bytesperline = 0;
- int sizeimage = 0;
-
- if (V4L2_TYPE_IS_MULTIPLANAR(format.type) &&
- format.fmt.pix_mp.num_planes > 0) {
- bytesperline =
- base::checked_cast<int>(format.fmt.pix_mp.plane_fmt[0].bytesperline);
- sizeimage =
- base::checked_cast<int>(format.fmt.pix_mp.plane_fmt[0].sizeimage);
- visible_size.SetSize(base::checked_cast<int>(format.fmt.pix_mp.width),
- base::checked_cast<int>(format.fmt.pix_mp.height));
- frame_format =
- V4L2Device::V4L2PixFmtToVideoFrameFormat(format.fmt.pix_mp.pixelformat);
- } else {
- bytesperline = base::checked_cast<int>(format.fmt.pix.bytesperline);
- sizeimage = base::checked_cast<int>(format.fmt.pix.sizeimage);
- visible_size.SetSize(base::checked_cast<int>(format.fmt.pix.width),
- base::checked_cast<int>(format.fmt.pix.height));
- frame_format =
- V4L2Device::V4L2PixFmtToVideoFrameFormat(format.fmt.pix.pixelformat);
- }
-
- int horiz_bpp =
- media::VideoFrame::PlaneHorizontalBitsPerPixel(frame_format, 0);
- DVLOG(3) << __func__ << ": bytesperline=" << bytesperline
- << ", sizeimage=" << sizeimage
- << ", visible_size=" << visible_size.ToString() << ", frame_format="
- << media::VideoFrame::FormatToString(frame_format)
- << ", horiz_bpp=" << horiz_bpp;
- if (sizeimage == 0 || bytesperline == 0 || horiz_bpp == 0 ||
- (bytesperline * 8) % horiz_bpp != 0) {
- LOG(ERROR) << "Invalid format provided";
- return coded_size;
- }
-
- // Round up sizeimage to full bytesperlines. sizeimage does not have to be
- // a multiple of bytesperline, as in V4L2 terms it's just a byte size of
- // the buffer, unrelated to its payload.
- sizeimage = ((sizeimage + bytesperline - 1) / bytesperline) * bytesperline;
-
- coded_size.SetSize(bytesperline * 8 / horiz_bpp, sizeimage / bytesperline);
- DVLOG(3) << "coded_size=" << coded_size.ToString();
-
- // Sanity checks. Calculated coded size has to contain given visible size
- // and fulfill buffer byte size requirements for each plane.
- DCHECK(gfx::Rect(coded_size).Contains(gfx::Rect(visible_size)));
-
- if (V4L2_TYPE_IS_MULTIPLANAR(format.type)) {
- for (size_t i = 0; i < format.fmt.pix_mp.num_planes; ++i) {
- DCHECK_EQ(format.fmt.pix_mp.plane_fmt[i].bytesperline,
- base::checked_cast<__u32>(media::VideoFrame::RowBytes(
- i, frame_format, coded_size.width())));
- }
- }
-
- return coded_size;
-}
-
-} // namespace content
diff --git a/chromium/content/common/gpu/media/v4l2_video_device.h b/chromium/content/common/gpu/media/v4l2_video_device.h
deleted file mode 100644
index f4b368f017e..00000000000
--- a/chromium/content/common/gpu/media/v4l2_video_device.h
+++ /dev/null
@@ -1,102 +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 defines the V4L2Device interface which is used by the
-// V4L2DecodeAccelerator class to delegate/pass the device specific
-// handling of any of the functionalities.
-
-#ifndef CONTENT_COMMON_GPU_MEDIA_V4L2_VIDEO_DEVICE_H_
-#define CONTENT_COMMON_GPU_MEDIA_V4L2_VIDEO_DEVICE_H_
-
-#include "media/base/video_decoder_config.h"
-#include "media/base/video_frame.h"
-#include "ui/gfx/size.h"
-#include "ui/gl/gl_bindings.h"
-
-namespace content {
-
-class V4L2Device {
- public:
- // Utility format conversion functions
- static media::VideoFrame::Format V4L2PixFmtToVideoFrameFormat(uint32 format);
- static uint32 VideoFrameFormatToV4L2PixFmt(media::VideoFrame::Format format);
- static uint32 VideoCodecProfileToV4L2PixFmt(media::VideoCodecProfile profile);
- // Convert format requirements requested by a V4L2 device to gfx::Size.
- static gfx::Size CodedSizeFromV4L2Format(struct v4l2_format format);
-
- virtual ~V4L2Device();
-
- enum Type {
- kDecoder,
- kEncoder,
- kImageProcessor,
- };
-
- // Creates and initializes an appropriate V4L2Device of |type| for the
- // current platform and returns a scoped_ptr<V4L2Device> on success, or NULL.
- static scoped_ptr<V4L2Device> Create(Type type);
-
- // Parameters and return value are the same as for the standard ioctl() system
- // call.
- virtual int Ioctl(int request, void* arg) = 0;
-
- // This method sleeps until either:
- // - SetDevicePollInterrupt() is called (on another thread),
- // - |poll_device| is true, and there is new data to be read from the device,
- // or an event from the device has arrived; in the latter case
- // |*event_pending| will be set to true.
- // Returns false on error, true otherwise.
- // This method should be called from a separate thread.
- virtual bool Poll(bool poll_device, bool* event_pending) = 0;
-
- // These methods are used to interrupt the thread sleeping on Poll() and force
- // it to return regardless of device state, which is usually when the client
- // is no longer interested in what happens with the device (on cleanup,
- // client state change, etc.). When SetDevicePollInterrupt() is called, Poll()
- // will return immediately, and any subsequent calls to it will also do so
- // until ClearDevicePollInterrupt() is called.
- virtual bool SetDevicePollInterrupt() = 0;
- virtual bool ClearDevicePollInterrupt() = 0;
-
- // Wrappers for standard mmap/munmap system calls.
- virtual void* Mmap(void* addr,
- unsigned int len,
- int prot,
- int flags,
- unsigned int offset) = 0;
- virtual void Munmap(void* addr, unsigned int len) = 0;
-
- // Initializes the V4L2Device to operate as a device of |type|.
- // Returns true on success.
- virtual bool Initialize() = 0;
-
- // Creates an EGLImageKHR since each V4L2Device may use a different method of
- // acquiring one and associating it to the given texture. The texture_id is
- // used to bind the texture to the returned EGLImageKHR. buffer_index can be
- // used to associate the returned EGLImageKHR by the underlying V4L2Device
- // implementation.
- virtual EGLImageKHR CreateEGLImage(EGLDisplay egl_display,
- EGLContext egl_context,
- GLuint texture_id,
- gfx::Size frame_buffer_size,
- unsigned int buffer_index,
- size_t planes_count) = 0;
-
- // Destroys the EGLImageKHR.
- virtual EGLBoolean DestroyEGLImage(EGLDisplay egl_display,
- EGLImageKHR egl_image) = 0;
-
- // Returns the supported texture target for the V4L2Device.
- virtual GLenum GetTextureTarget() = 0;
-
- // Returns the preferred V4L2 input format or 0 if don't care.
- virtual uint32 PreferredInputFormat() = 0;
-
- // Returns the preferred V4L2 output format or 0 if don't care.
- virtual uint32 PreferredOutputFormat() = 0;
-};
-
-} // namespace content
-
-#endif // CONTENT_COMMON_GPU_MEDIA_V4L2_VIDEO_DEVICE_H_
diff --git a/chromium/content/common/gpu/media/v4l2_video_encode_accelerator.cc b/chromium/content/common/gpu/media/v4l2_video_encode_accelerator.cc
index d69c97da551..8ee6ec96ca1 100644
--- a/chromium/content/common/gpu/media/v4l2_video_encode_accelerator.cc
+++ b/chromium/content/common/gpu/media/v4l2_video_encode_accelerator.cc
@@ -11,18 +11,17 @@
#include "base/callback.h"
#include "base/command_line.h"
-#include "base/debug/trace_event.h"
-#include "base/message_loop/message_loop_proxy.h"
#include "base/numerics/safe_conversions.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/trace_event/trace_event.h"
#include "content/common/gpu/media/v4l2_video_encode_accelerator.h"
#include "content/public/common/content_switches.h"
#include "media/base/bitstream_buffer.h"
-#define NOTIFY_ERROR(x) \
- do { \
- SetEncoderState(kError); \
- LOG(ERROR) << "calling NotifyError(): " << x; \
- NotifyError(x); \
+#define NOTIFY_ERROR(x) \
+ do { \
+ LOG(ERROR) << "Setting error state:" << x; \
+ SetErrorState(x); \
} while (0)
#define IOCTL_OR_ERROR_RETURN_VALUE(type, arg, value) \
@@ -59,20 +58,26 @@ struct V4L2VideoEncodeAccelerator::BitstreamBufferRef {
V4L2VideoEncodeAccelerator::InputRecord::InputRecord() : at_device(false) {
}
+V4L2VideoEncodeAccelerator::InputRecord::~InputRecord() {
+}
+
V4L2VideoEncodeAccelerator::OutputRecord::OutputRecord()
: at_device(false), address(NULL), length(0) {
}
+V4L2VideoEncodeAccelerator::OutputRecord::~OutputRecord() {
+}
+
V4L2VideoEncodeAccelerator::V4L2VideoEncodeAccelerator(
- scoped_ptr<V4L2Device> device)
- : child_message_loop_proxy_(base::MessageLoopProxy::current()),
+ const scoped_refptr<V4L2Device>& device)
+ : child_task_runner_(base::ThreadTaskRunnerHandle::Get()),
output_buffer_byte_size_(0),
device_input_format_(media::VideoFrame::UNKNOWN),
input_planes_count_(0),
output_format_fourcc_(0),
encoder_state_(kUninitialized),
stream_header_size_(0),
- device_(device.Pass()),
+ device_(device),
input_streamon_(false),
input_buffer_queued_count_(0),
input_memory_type_(V4L2_MEMORY_USERPTR),
@@ -110,7 +115,7 @@ bool V4L2VideoEncodeAccelerator::Initialize(
client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client));
client_ = client_ptr_factory_->GetWeakPtr();
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
DCHECK_EQ(encoder_state_, kUninitialized);
struct v4l2_capability caps;
@@ -133,9 +138,9 @@ bool V4L2VideoEncodeAccelerator::Initialize(
DVLOG(1) << "Input format not supported by the HW, will convert to "
<< media::VideoFrame::FormatToString(device_input_format_);
- scoped_ptr<V4L2Device> device =
+ scoped_refptr<V4L2Device> device =
V4L2Device::Create(V4L2Device::kImageProcessor);
- image_processor_.reset(new V4L2ImageProcessor(device.Pass()));
+ image_processor_.reset(new V4L2ImageProcessor(device));
// Convert from input_format to device_input_format_, keeping the size
// at visible_size_ and requiring the output buffers to be of at least
@@ -166,16 +171,14 @@ bool V4L2VideoEncodeAccelerator::Initialize(
RequestEncodingParametersChange(initial_bitrate, kInitialFramerate);
- SetEncoderState(kInitialized);
+ encoder_state_ = kInitialized;
- child_message_loop_proxy_->PostTask(
+ child_task_runner_->PostTask(
FROM_HERE,
- base::Bind(&Client::RequireBitstreamBuffers,
- client_,
- kInputBufferCount,
- image_processor_.get() ?
- image_processor_->input_allocated_size() :
- input_allocated_size_,
+ base::Bind(&Client::RequireBitstreamBuffers, client_, kInputBufferCount,
+ image_processor_.get()
+ ? image_processor_->input_allocated_size()
+ : input_allocated_size_,
output_buffer_byte_size_));
return true;
}
@@ -189,7 +192,7 @@ void V4L2VideoEncodeAccelerator::Encode(
const scoped_refptr<media::VideoFrame>& frame,
bool force_keyframe) {
DVLOG(3) << "Encode(): force_keyframe=" << force_keyframe;
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
if (image_processor_) {
image_processor_->Process(
@@ -210,7 +213,7 @@ void V4L2VideoEncodeAccelerator::Encode(
void V4L2VideoEncodeAccelerator::UseOutputBitstreamBuffer(
const media::BitstreamBuffer& buffer) {
DVLOG(3) << "UseOutputBitstreamBuffer(): id=" << buffer.id();
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
if (buffer.size() < output_buffer_byte_size_) {
NOTIFY_ERROR(kInvalidArgumentError);
@@ -238,7 +241,7 @@ void V4L2VideoEncodeAccelerator::RequestEncodingParametersChange(
uint32 framerate) {
DVLOG(3) << "RequestEncodingParametersChange(): bitrate=" << bitrate
<< ", framerate=" << framerate;
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
encoder_thread_.message_loop()->PostTask(
FROM_HERE,
@@ -251,7 +254,7 @@ void V4L2VideoEncodeAccelerator::RequestEncodingParametersChange(
void V4L2VideoEncodeAccelerator::Destroy() {
DVLOG(3) << "Destroy()";
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
// We're destroying; cancel all callbacks.
client_ptr_factory_.reset();
@@ -275,30 +278,40 @@ void V4L2VideoEncodeAccelerator::Destroy() {
}
// Set to kError state just in case.
- SetEncoderState(kError);
+ encoder_state_ = kError;
delete this;
}
-std::vector<media::VideoEncodeAccelerator::SupportedProfile>
+media::VideoEncodeAccelerator::SupportedProfiles
V4L2VideoEncodeAccelerator::GetSupportedProfiles() {
- std::vector<SupportedProfile> profiles;
+ SupportedProfiles profiles;
SupportedProfile profile;
-
- const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
- if (cmd_line->HasSwitch(switches::kEnableWebRtcHWVp8Encoding)) {
- profile.profile = media::VP8PROFILE_ANY;
- profile.max_resolution.SetSize(1920, 1088);
- profile.max_framerate_numerator = 30;
- profile.max_framerate_denominator = 1;
- profiles.push_back(profile);
- }
-
- profile.profile = media::H264PROFILE_MAIN;
- profile.max_resolution.SetSize(1920, 1088);
profile.max_framerate_numerator = 30;
profile.max_framerate_denominator = 1;
- profiles.push_back(profile);
+
+ gfx::Size min_resolution;
+ v4l2_fmtdesc fmtdesc;
+ memset(&fmtdesc, 0, sizeof(fmtdesc));
+ fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ for (; device_->Ioctl(VIDIOC_ENUM_FMT, &fmtdesc) == 0; ++fmtdesc.index) {
+ device_->GetSupportedResolution(fmtdesc.pixelformat,
+ &min_resolution, &profile.max_resolution);
+ switch (fmtdesc.pixelformat) {
+ case V4L2_PIX_FMT_H264:
+ profile.profile = media::H264PROFILE_MAIN;
+ profiles.push_back(profile);
+ break;
+ case V4L2_PIX_FMT_VP8:
+ profile.profile = media::VP8PROFILE_ANY;
+ profiles.push_back(profile);
+ break;
+ case V4L2_PIX_FMT_VP9:
+ profile.profile = media::VP9PROFILE_ANY;
+ profiles.push_back(profile);
+ break;
+ }
+ }
return profiles;
}
@@ -306,7 +319,7 @@ V4L2VideoEncodeAccelerator::GetSupportedProfiles() {
void V4L2VideoEncodeAccelerator::FrameProcessed(
bool force_keyframe,
const scoped_refptr<media::VideoFrame>& frame) {
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
DVLOG(3) << "FrameProcessed(): force_keyframe=" << force_keyframe;
encoder_thread_.message_loop()->PostTask(
@@ -338,16 +351,17 @@ void V4L2VideoEncodeAccelerator::EncodeTask(
// incoming input frame, we should queue the parameters together with the
// frame onto encoder_input_queue_ and apply them when the input is about
// to be queued to the codec.
- struct v4l2_ext_control ctrls[1];
- struct v4l2_ext_controls control;
- memset(&ctrls, 0, sizeof(ctrls));
- memset(&control, 0, sizeof(control));
- ctrls[0].id = V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE;
- ctrls[0].value = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_I_FRAME;
- control.ctrl_class = V4L2_CTRL_CLASS_MPEG;
- control.count = 1;
- control.controls = ctrls;
- IOCTL_OR_ERROR_RETURN(VIDIOC_S_EXT_CTRLS, &control);
+ std::vector<struct v4l2_ext_control> ctrls;
+ struct v4l2_ext_control ctrl;
+ memset(&ctrl, 0, sizeof(ctrl));
+ ctrl.id = V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE;
+ ctrl.value = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_I_FRAME;
+ ctrls.push_back(ctrl);
+ if (!SetExtCtrls(ctrls)) {
+ LOG(ERROR) << "Failed requesting keyframe";
+ NOTIFY_ERROR(kPlatformFailureError);
+ return;
+ }
}
}
@@ -491,7 +505,7 @@ void V4L2VideoEncodeAccelerator::Dequeue() {
memset(&dqbuf, 0, sizeof(dqbuf));
memset(&planes, 0, sizeof(planes));
dqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
- dqbuf.memory = V4L2_MEMORY_MMAP;
+ dqbuf.memory = input_memory_type_;
dqbuf.m.planes = planes;
dqbuf.length = input_planes_count_;
if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) {
@@ -568,13 +582,10 @@ void V4L2VideoEncodeAccelerator::Dequeue() {
DVLOG(3) << "Dequeue(): returning "
"bitstream_buffer_id=" << output_record.buffer_ref->id
<< ", size=" << output_size << ", key_frame=" << key_frame;
- child_message_loop_proxy_->PostTask(
+ child_task_runner_->PostTask(
FROM_HERE,
- base::Bind(&Client::BitstreamBufferReady,
- client_,
- output_record.buffer_ref->id,
- output_size,
- key_frame));
+ base::Bind(&Client::BitstreamBufferReady, client_,
+ output_record.buffer_ref->id, output_size, key_frame));
output_record.at_device = false;
output_record.buffer_ref.reset();
free_output_buffers_.push_back(dqbuf.index);
@@ -758,11 +769,10 @@ void V4L2VideoEncodeAccelerator::DevicePollTask(bool poll_device) {
void V4L2VideoEncodeAccelerator::NotifyError(Error error) {
DVLOG(1) << "NotifyError(): error=" << error;
- if (!child_message_loop_proxy_->BelongsToCurrentThread()) {
- child_message_loop_proxy_->PostTask(
- FROM_HERE,
- base::Bind(
- &V4L2VideoEncodeAccelerator::NotifyError, weak_this_, error));
+ if (!child_task_runner_->BelongsToCurrentThread()) {
+ child_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&V4L2VideoEncodeAccelerator::NotifyError,
+ weak_this_, error));
return;
}
@@ -772,21 +782,23 @@ void V4L2VideoEncodeAccelerator::NotifyError(Error error) {
}
}
-void V4L2VideoEncodeAccelerator::SetEncoderState(State state) {
- DVLOG(3) << "SetEncoderState(): state=" << state;
-
+void V4L2VideoEncodeAccelerator::SetErrorState(Error error) {
// We can touch encoder_state_ only if this is the encoder thread or the
// encoder thread isn't running.
if (encoder_thread_.message_loop() != NULL &&
encoder_thread_.message_loop() != base::MessageLoop::current()) {
encoder_thread_.message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&V4L2VideoEncodeAccelerator::SetEncoderState,
- base::Unretained(this),
- state));
- } else {
- encoder_state_ = state;
+ FROM_HERE, base::Bind(&V4L2VideoEncodeAccelerator::SetErrorState,
+ base::Unretained(this), error));
+ return;
}
+
+ // Post NotifyError only if we are already initialized, as the API does
+ // not allow doing so before that.
+ if (encoder_state_ != kError && encoder_state_ != kUninitialized)
+ NotifyError(error);
+
+ encoder_state_ = kError;
}
void V4L2VideoEncodeAccelerator::RequestEncodingParametersChangeTask(
@@ -801,16 +813,17 @@ void V4L2VideoEncodeAccelerator::RequestEncodingParametersChangeTask(
if (framerate < 1)
framerate = 1;
- struct v4l2_ext_control ctrls[1];
- struct v4l2_ext_controls control;
- memset(&ctrls, 0, sizeof(ctrls));
- memset(&control, 0, sizeof(control));
- ctrls[0].id = V4L2_CID_MPEG_VIDEO_BITRATE;
- ctrls[0].value = bitrate;
- control.ctrl_class = V4L2_CTRL_CLASS_MPEG;
- control.count = arraysize(ctrls);
- control.controls = ctrls;
- IOCTL_OR_ERROR_RETURN(VIDIOC_S_EXT_CTRLS, &control);
+ std::vector<struct v4l2_ext_control> ctrls;
+ struct v4l2_ext_control ctrl;
+ memset(&ctrl, 0, sizeof(ctrl));
+ ctrl.id = V4L2_CID_MPEG_VIDEO_BITRATE;
+ ctrl.value = bitrate;
+ ctrls.push_back(ctrl);
+ if (!SetExtCtrls(ctrls)) {
+ LOG(ERROR) << "Failed changing bitrate";
+ NOTIFY_ERROR(kPlatformFailureError);
+ return;
+ }
struct v4l2_streamparm parms;
memset(&parms, 0, sizeof(parms));
@@ -824,12 +837,12 @@ void V4L2VideoEncodeAccelerator::RequestEncodingParametersChangeTask(
bool V4L2VideoEncodeAccelerator::SetOutputFormat(
media::VideoCodecProfile output_profile) {
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
DCHECK(!input_streamon_);
DCHECK(!output_streamon_);
output_format_fourcc_ =
- V4L2Device::VideoCodecProfileToV4L2PixFmt(output_profile);
+ V4L2Device::VideoCodecProfileToV4L2PixFmt(output_profile, false);
if (!output_format_fourcc_) {
LOG(ERROR) << "Initialize(): invalid output_profile=" << output_profile;
return false;
@@ -851,7 +864,6 @@ bool V4L2VideoEncodeAccelerator::SetOutputFormat(
// Device might have adjusted the required output size.
size_t adjusted_output_buffer_size =
base::checked_cast<size_t>(format.fmt.pix_mp.plane_fmt[0].sizeimage);
- DCHECK_GE(adjusted_output_buffer_size, output_buffer_byte_size_);
output_buffer_byte_size_ = adjusted_output_buffer_size;
return true;
@@ -860,7 +872,7 @@ bool V4L2VideoEncodeAccelerator::SetOutputFormat(
bool V4L2VideoEncodeAccelerator::NegotiateInputFormat(
media::VideoFrame::Format input_format) {
DVLOG(3) << "NegotiateInputFormat()";
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
DCHECK(!input_streamon_);
DCHECK(!output_streamon_);
@@ -920,7 +932,7 @@ bool V4L2VideoEncodeAccelerator::SetFormats(
media::VideoFrame::Format input_format,
media::VideoCodecProfile output_profile) {
DVLOG(3) << "SetFormats()";
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
DCHECK(!input_streamon_);
DCHECK(!output_streamon_);
@@ -932,7 +944,7 @@ bool V4L2VideoEncodeAccelerator::SetFormats(
struct v4l2_crop crop;
memset(&crop, 0, sizeof(crop));
- crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
crop.c.left = 0;
crop.c.top = 0;
crop.c.width = visible_size_.width();
@@ -942,44 +954,87 @@ bool V4L2VideoEncodeAccelerator::SetFormats(
return true;
}
+bool V4L2VideoEncodeAccelerator::SetExtCtrls(
+ std::vector<struct v4l2_ext_control> ctrls) {
+ struct v4l2_ext_controls ext_ctrls;
+ memset(&ext_ctrls, 0, sizeof(ext_ctrls));
+ ext_ctrls.ctrl_class = V4L2_CTRL_CLASS_MPEG;
+ ext_ctrls.count = ctrls.size();
+ ext_ctrls.controls = &ctrls[0];
+ return device_->Ioctl(VIDIOC_S_EXT_CTRLS, &ext_ctrls) == 0;
+}
+
bool V4L2VideoEncodeAccelerator::InitControls() {
- struct v4l2_ext_control ctrls[9];
- struct v4l2_ext_controls control;
- memset(&ctrls, 0, sizeof(ctrls));
- memset(&control, 0, sizeof(control));
- // No B-frames, for lowest decoding latency.
- ctrls[0].id = V4L2_CID_MPEG_VIDEO_B_FRAMES;
- ctrls[0].value = 0;
- // Enable frame-level bitrate control.
- ctrls[1].id = V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE;
- ctrls[1].value = 1;
+ std::vector<struct v4l2_ext_control> ctrls;
+ struct v4l2_ext_control ctrl;
+
+ // Enable frame-level bitrate control. This is the only mandatory control.
+ memset(&ctrl, 0, sizeof(ctrl));
+ ctrl.id = V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE;
+ ctrl.value = 1;
+ ctrls.push_back(ctrl);
+ if (!SetExtCtrls(ctrls)) {
+ LOG(ERROR) << "Failed enabling bitrate control";
+ NOTIFY_ERROR(kPlatformFailureError);
+ return false;
+ }
+
+ // Optional controls.
+ ctrls.clear();
+ if (output_format_fourcc_ == V4L2_PIX_FMT_H264) {
+ // No B-frames, for lowest decoding latency.
+ memset(&ctrl, 0, sizeof(ctrl));
+ ctrl.id = V4L2_CID_MPEG_VIDEO_B_FRAMES;
+ ctrl.value = 0;
+ ctrls.push_back(ctrl);
+
+ // Quantization parameter maximum value (for variable bitrate control).
+ memset(&ctrl, 0, sizeof(ctrl));
+ ctrl.id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP;
+ ctrl.value = 51;
+ ctrls.push_back(ctrl);
+
+ // Use H.264 level 4.0 to match the supported max resolution.
+ memset(&ctrl, 0, sizeof(ctrl));
+ ctrl.id = V4L2_CID_MPEG_VIDEO_H264_LEVEL;
+ ctrl.value = V4L2_MPEG_VIDEO_H264_LEVEL_4_0;
+ ctrls.push_back(ctrl);
+
+ // Separate stream header so we can cache it and insert into the stream.
+ memset(&ctrl, 0, sizeof(ctrl));
+ ctrl.id = V4L2_CID_MPEG_VIDEO_HEADER_MODE;
+ ctrl.value = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE;
+ ctrls.push_back(ctrl);
+ }
+
// Enable "tight" bitrate mode. For this to work properly, frame- and mb-level
// bitrate controls have to be enabled as well.
- ctrls[2].id = V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF;
- ctrls[2].value = 1;
+ memset(&ctrl, 0, sizeof(ctrl));
+ ctrl.id = V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF;
+ ctrl.value = 1;
+ ctrls.push_back(ctrl);
+
// Force bitrate control to average over a GOP (for tight bitrate
// tolerance).
- ctrls[3].id = V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT;
- ctrls[3].value = 1;
- // Quantization parameter maximum value (for variable bitrate control).
- ctrls[4].id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP;
- ctrls[4].value = 51;
- // Separate stream header so we can cache it and insert into the stream.
- ctrls[5].id = V4L2_CID_MPEG_VIDEO_HEADER_MODE;
- ctrls[5].value = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE;
+ memset(&ctrl, 0, sizeof(ctrl));
+ ctrl.id = V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT;
+ ctrl.value = 1;
+ ctrls.push_back(ctrl);
+
// Enable macroblock-level bitrate control.
- ctrls[6].id = V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE;
- ctrls[6].value = 1;
- // Use H.264 level 4.0 to match the supported max resolution.
- ctrls[7].id = V4L2_CID_MPEG_VIDEO_H264_LEVEL;
- ctrls[7].value = V4L2_MPEG_VIDEO_H264_LEVEL_4_0;
+ memset(&ctrl, 0, sizeof(ctrl));
+ ctrl.id = V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE;
+ ctrl.value = 1;
+ ctrls.push_back(ctrl);
+
// Disable periodic key frames.
- ctrls[8].id = V4L2_CID_MPEG_VIDEO_GOP_SIZE;
- ctrls[8].value = 0;
- control.ctrl_class = V4L2_CTRL_CLASS_MPEG;
- control.count = arraysize(ctrls);
- control.controls = ctrls;
- IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_EXT_CTRLS, &control);
+ memset(&ctrl, 0, sizeof(ctrl));
+ ctrl.id = V4L2_CID_MPEG_VIDEO_GOP_SIZE;
+ ctrl.value = 0;
+ ctrls.push_back(ctrl);
+
+ // Ignore return value as these controls are optional.
+ SetExtCtrls(ctrls);
return true;
}
@@ -1017,7 +1072,7 @@ bool V4L2VideoEncodeAccelerator::CreateInputBuffers() {
bool V4L2VideoEncodeAccelerator::CreateOutputBuffers() {
DVLOG(3) << "CreateOutputBuffers()";
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
DCHECK(!output_streamon_);
struct v4l2_requestbuffers reqbufs;
@@ -1059,7 +1114,7 @@ bool V4L2VideoEncodeAccelerator::CreateOutputBuffers() {
void V4L2VideoEncodeAccelerator::DestroyInputBuffers() {
DVLOG(3) << "DestroyInputBuffers()";
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
DCHECK(!input_streamon_);
struct v4l2_requestbuffers reqbufs;
@@ -1075,7 +1130,7 @@ void V4L2VideoEncodeAccelerator::DestroyInputBuffers() {
void V4L2VideoEncodeAccelerator::DestroyOutputBuffers() {
DVLOG(3) << "DestroyOutputBuffers()";
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
DCHECK(!output_streamon_);
for (size_t i = 0; i < output_buffer_map_.size(); ++i) {
diff --git a/chromium/content/common/gpu/media/v4l2_video_encode_accelerator.h b/chromium/content/common/gpu/media/v4l2_video_encode_accelerator.h
index 267d0d010a6..d292f22f1c9 100644
--- a/chromium/content/common/gpu/media/v4l2_video_encode_accelerator.h
+++ b/chromium/content/common/gpu/media/v4l2_video_encode_accelerator.h
@@ -5,24 +5,18 @@
#ifndef CONTENT_COMMON_GPU_MEDIA_V4L2_VIDEO_ENCODE_ACCELERATOR_H_
#define CONTENT_COMMON_GPU_MEDIA_V4L2_VIDEO_ENCODE_ACCELERATOR_H_
-#include <list>
#include <linux/videodev2.h>
+#include <list>
#include <vector>
#include "base/memory/linked_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread.h"
#include "content/common/content_export.h"
+#include "content/common/gpu/media/v4l2_device.h"
#include "content/common/gpu/media/v4l2_image_processor.h"
-#include "content/common/gpu/media/v4l2_video_device.h"
#include "media/video/video_encode_accelerator.h"
-#include "ui/gfx/size.h"
-
-namespace base {
-
-class MessageLoopProxy;
-
-} // namespace base
+#include "ui/gfx/geometry/size.h"
namespace media {
@@ -42,24 +36,24 @@ namespace content {
class CONTENT_EXPORT V4L2VideoEncodeAccelerator
: public media::VideoEncodeAccelerator {
public:
- explicit V4L2VideoEncodeAccelerator(scoped_ptr<V4L2Device> device);
- virtual ~V4L2VideoEncodeAccelerator();
+ explicit V4L2VideoEncodeAccelerator(const scoped_refptr<V4L2Device>& device);
+ ~V4L2VideoEncodeAccelerator() override;
// media::VideoEncodeAccelerator implementation.
- virtual std::vector<media::VideoEncodeAccelerator::SupportedProfile>
- GetSupportedProfiles() override;
- virtual bool Initialize(media::VideoFrame::Format format,
- const gfx::Size& input_visible_size,
- media::VideoCodecProfile output_profile,
- uint32 initial_bitrate,
- Client* client) override;
- virtual void Encode(const scoped_refptr<media::VideoFrame>& frame,
- bool force_keyframe) override;
- virtual void UseOutputBitstreamBuffer(const media::BitstreamBuffer& buffer)
+ media::VideoEncodeAccelerator::SupportedProfiles GetSupportedProfiles()
+ override;
+ bool Initialize(media::VideoFrame::Format format,
+ const gfx::Size& input_visible_size,
+ media::VideoCodecProfile output_profile,
+ uint32 initial_bitrate,
+ Client* client) override;
+ void Encode(const scoped_refptr<media::VideoFrame>& frame,
+ bool force_keyframe) override;
+ void UseOutputBitstreamBuffer(const media::BitstreamBuffer& buffer)
override;
- virtual void RequestEncodingParametersChange(uint32 bitrate,
- uint32 framerate) override;
- virtual void Destroy() override;
+ void RequestEncodingParametersChange(uint32 bitrate,
+ uint32 framerate) override;
+ void Destroy() override;
private:
// Auto-destroy reference for BitstreamBuffer, for tracking buffers passed to
@@ -69,6 +63,7 @@ class CONTENT_EXPORT V4L2VideoEncodeAccelerator
// Record for codec input buffers.
struct InputRecord {
InputRecord();
+ ~InputRecord();
bool at_device;
scoped_refptr<media::VideoFrame> frame;
};
@@ -76,6 +71,7 @@ class CONTENT_EXPORT V4L2VideoEncodeAccelerator
// Record for output buffers.
struct OutputRecord {
OutputRecord();
+ ~OutputRecord();
bool at_device;
linked_ptr<BitstreamBufferRef> buffer_ref;
void* address;
@@ -152,9 +148,8 @@ class CONTENT_EXPORT V4L2VideoEncodeAccelerator
// Error notification (using PostTask() to child thread, if necessary).
void NotifyError(Error error);
- // Set the encoder_thread_ state (using PostTask to encoder thread, if
- // necessary).
- void SetEncoderState(State state);
+ // Set the encoder_state_ to kError and notify the client (if necessary).
+ void SetErrorState(Error error);
//
// Other utility functions. Called on encoder_thread_, unless
@@ -188,8 +183,11 @@ class CONTENT_EXPORT V4L2VideoEncodeAccelerator
void DestroyInputBuffers();
void DestroyOutputBuffers();
- // Our original calling message loop for the child thread.
- const scoped_refptr<base::MessageLoopProxy> child_message_loop_proxy_;
+ // Set controls in |ctrls| and return true if successful.
+ bool SetExtCtrls(std::vector<struct v4l2_ext_control> ctrls);
+
+ // Our original calling task runner for the child thread.
+ const scoped_refptr<base::SingleThreadTaskRunner> child_task_runner_;
gfx::Size visible_size_;
// Input allocated size required by the device.
@@ -220,7 +218,7 @@ class CONTENT_EXPORT V4L2VideoEncodeAccelerator
std::list<scoped_refptr<media::VideoFrame> > encoder_input_queue_;
// Encoder device.
- scoped_ptr<V4L2Device> device_;
+ scoped_refptr<V4L2Device> device_;
// Input queue state.
bool input_streamon_;
@@ -258,7 +256,7 @@ class CONTENT_EXPORT V4L2VideoEncodeAccelerator
// To expose client callbacks from VideoEncodeAccelerator.
// NOTE: all calls to these objects *MUST* be executed on
- // child_message_loop_proxy_.
+ // child_task_runner_.
base::WeakPtr<Client> client_;
scoped_ptr<base::WeakPtrFactory<Client> > client_ptr_factory_;
diff --git a/chromium/content/common/gpu/media/va.sigs b/chromium/content/common/gpu/media/va.sigs
index 9906f9f8cbb..ac28f963a41 100644
--- a/chromium/content/common/gpu/media/va.sigs
+++ b/chromium/content/common/gpu/media/va.sigs
@@ -9,6 +9,7 @@ VAStatus vaBeginPicture(VADisplay dpy, VAContextID context, VASurfaceID render_t
VAStatus vaCreateBuffer(VADisplay dpy, VAContextID context, VABufferType type, unsigned int size, unsigned int num_elements, void *data, VABufferID *buf_id);
VAStatus vaCreateConfig(VADisplay dpy, VAProfile profile, VAEntrypoint entrypoint, VAConfigAttrib *attrib_list, int num_attribs, VAConfigID *config_id);
VAStatus vaCreateContext(VADisplay dpy, VAConfigID config_id, int picture_width, int picture_height, int flag, VASurfaceID *render_targets, int num_render_targets, VAContextID *context);
+VAStatus vaCreateImage(VADisplay dpy, VAImageFormat *format, int width, int height, VAImage *image);
VAStatus vaCreateSurfaces(VADisplay dpy, unsigned int format, unsigned int width, unsigned int height, VASurfaceID *surfaces, unsigned int num_surfaces, VASurfaceAttrib *attrib_list, unsigned int num_attribs);
VAStatus vaDeriveImage(VADisplay dpy, VASurfaceID surface, VAImage *image);
VAStatus vaDestroyBuffer(VADisplay dpy, VABufferID buffer_id);
@@ -20,21 +21,16 @@ int vaDisplayIsValid(VADisplay dpy);
VAStatus vaEndPicture(VADisplay dpy, VAContextID context);
const char *vaErrorStr(VAStatus error_status);
VAStatus vaGetConfigAttributes(VADisplay dpy, VAProfile profile, VAEntrypoint entrypoint, VAConfigAttrib *attrib_list, int num_attribs);
+VAStatus vaGetImage(VADisplay dpy, VASurfaceID surface, int x, int y, unsigned int width, unsigned int height, VAImageID image);
VAStatus vaInitialize(VADisplay dpy, int *major_version, int *minor_version);
VAStatus vaMapBuffer(VADisplay dpy, VABufferID buf_id, void **pbuf);
int vaMaxNumEntrypoints (VADisplay dpy);
int vaMaxNumProfiles(VADisplay dpy);
VAStatus vaQueryConfigEntrypoints (VADisplay dpy, VAProfile profile, VAEntrypoint *entrypoint_list, int *num_entrypoints);
VAStatus vaQueryConfigProfiles(VADisplay dpy, VAProfile *profile_list, int *num_profiles);
+VAStatus vaQuerySurfaceAttributes(VADisplay dpy, VAConfigID config, VASurfaceAttrib *attrib_list, unsigned int *num_attribs);
VAStatus vaRenderPicture(VADisplay dpy, VAContextID context, VABufferID *buffers, int num_buffers);
VAStatus vaSetDisplayAttributes(VADisplay dpy, VADisplayAttribute *attr_list, int num_attributes);
VAStatus vaSyncSurface(VADisplay dpy, VASurfaceID render_target);
VAStatus vaTerminate(VADisplay dpy);
VAStatus vaUnmapBuffer(VADisplay dpy, VABufferID buf_id);
-
-
-//------------------------------------------------
-// Functions from libva-x11 used in chromium code.
-//------------------------------------------------
-VADisplay vaGetDisplay(Display *dpy);
-VAStatus vaPutSurface(VADisplay dpy, VASurfaceID surface, Drawable draw, short srcx, short srcy, unsigned short srcw, unsigned short srch, short destx, short desty, unsigned short destw, unsigned short desth, VARectangle *cliprects, unsigned int number_cliprects, unsigned int flags);
diff --git a/chromium/content/common/gpu/media/va_drm.sigs b/chromium/content/common/gpu/media/va_drm.sigs
new file mode 100644
index 00000000000..093e36c8851
--- /dev/null
+++ b/chromium/content/common/gpu/media/va_drm.sigs
@@ -0,0 +1,8 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//------------------------------------------------
+// Functions from libva-drm used in chromium code.
+//------------------------------------------------
+VADisplay vaGetDisplayDRM(int fd);
diff --git a/chromium/content/common/gpu/media/va_stub_header.fragment b/chromium/content/common/gpu/media/va_stub_header.fragment
index 8d89c16adbd..91ba89274bd 100644
--- a/chromium/content/common/gpu/media/va_stub_header.fragment
+++ b/chromium/content/common/gpu/media/va_stub_header.fragment
@@ -3,7 +3,10 @@
extern "C" {
+#include "third_party/libva/va/drm/va_drm.h"
#include "third_party/libva/va/va.h"
+#if defined(USE_X11)
#include "third_party/libva/va/va_x11.h"
+#endif
}
diff --git a/chromium/content/common/gpu/media/va_surface.h b/chromium/content/common/gpu/media/va_surface.h
index 88dfc2a9041..c76c11fea28 100644
--- a/chromium/content/common/gpu/media/va_surface.h
+++ b/chromium/content/common/gpu/media/va_surface.h
@@ -8,7 +8,11 @@
#ifndef CONTENT_COMMON_GPU_MEDIA_VA_SURFACE_H_
#define CONTENT_COMMON_GPU_MEDIA_VA_SURFACE_H_
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "content/common/content_export.h"
#include "third_party/libva/va/va.h"
+#include "ui/gfx/geometry/size.h"
namespace content {
@@ -16,7 +20,7 @@ namespace content {
// and use as reference for decoding other surfaces. It is also handed by the
// decoder to VaapiVideoDecodeAccelerator when the contents of the surface are
// ready and should be displayed. VAVDA converts the surface contents into an
-// X Pixmap bound to a texture for display and releases its reference to it.
+// X/Drm Pixmap bound to a texture for display and releases its reference to it.
// Decoder releases its references to the surface when it's done decoding and
// using it as reference. Note that a surface may still be used for reference
// after it's been sent to output and also after it is no longer used by VAVDA.
@@ -56,11 +60,11 @@ namespace content {
// | VASurface to VaapiVideoDecodeAccelerator, VASurface as reference for
// | which stores it (taking a ref) on decoding more frames.
// | pending_output_cbs_ queue until an output |
-// | TFPPicture becomes available. v
+// | VaapiPicture becomes available. v
// | | Once the DecodeSurface is not
// | | needed as reference anymore,
// | v it is released, releasing the
-// | A TFPPicture becomes available after associated VASurface reference.
+// | A VaapiPicture becomes available after associated VASurface reference.
// | the client of VVDA returns |
// | a PictureBuffer associated with it. VVDA |
// | puts the contents of the VASurface into |
@@ -84,17 +88,22 @@ class CONTENT_EXPORT VASurface : public base::RefCountedThreadSafe<VASurface> {
// are released.
typedef base::Callback<void(VASurfaceID)> ReleaseCB;
- VASurface(VASurfaceID va_surface_id, const ReleaseCB& release_cb);
+ VASurface(VASurfaceID va_surface_id,
+ const gfx::Size& size,
+ const ReleaseCB& release_cb);
VASurfaceID id() {
return va_surface_id_;
}
+ const gfx::Size& size() const { return size_; }
+
private:
friend class base::RefCountedThreadSafe<VASurface>;
~VASurface();
const VASurfaceID va_surface_id_;
+ gfx::Size size_;
ReleaseCB release_cb_;
DISALLOW_COPY_AND_ASSIGN(VASurface);
diff --git a/chromium/content/common/gpu/media/va_x11.sigs b/chromium/content/common/gpu/media/va_x11.sigs
new file mode 100644
index 00000000000..d87356b5c20
--- /dev/null
+++ b/chromium/content/common/gpu/media/va_x11.sigs
@@ -0,0 +1,9 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//------------------------------------------------
+// Functions from libva-x11 used in chromium code.
+//------------------------------------------------
+VADisplay vaGetDisplay(Display *dpy);
+VAStatus vaPutSurface(VADisplay dpy, VASurfaceID surface, Drawable draw, short srcx, short srcy, unsigned short srcw, unsigned short srch, short destx, short desty, unsigned short destw, unsigned short desth, VARectangle *cliprects, unsigned int number_cliprects, unsigned int flags);
diff --git a/chromium/content/common/gpu/media/vaapi_drm_picture.cc b/chromium/content/common/gpu/media/vaapi_drm_picture.cc
new file mode 100644
index 00000000000..bf694d216a3
--- /dev/null
+++ b/chromium/content/common/gpu/media/vaapi_drm_picture.cc
@@ -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.
+
+#include "base/file_descriptor_posix.h"
+#include "content/common/gpu/media/va_surface.h"
+#include "content/common/gpu/media/vaapi_drm_picture.h"
+#include "content/common/gpu/media/vaapi_wrapper.h"
+#include "third_party/libva/va/drm/va_drm.h"
+#include "third_party/libva/va/va.h"
+#include "third_party/libva/va/va_drmcommon.h"
+#include "ui/gfx/gpu_memory_buffer.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_image_linux_dma_buffer.h"
+#include "ui/gl/scoped_binders.h"
+#include "ui/ozone/gpu/gpu_memory_buffer_factory_ozone_native_buffer.h"
+#include "ui/ozone/public/native_pixmap.h"
+#include "ui/ozone/public/ozone_platform.h"
+#include "ui/ozone/public/surface_factory_ozone.h"
+
+namespace content {
+
+VaapiDrmPicture::VaapiDrmPicture(
+ VaapiWrapper* vaapi_wrapper,
+ const base::Callback<bool(void)>& make_context_current,
+ int32 picture_buffer_id,
+ uint32 texture_id,
+ const gfx::Size& size)
+ : VaapiPicture(picture_buffer_id, texture_id, size),
+ vaapi_wrapper_(vaapi_wrapper),
+ make_context_current_(make_context_current) {
+}
+
+VaapiDrmPicture::~VaapiDrmPicture() {
+ if (gl_image_ && make_context_current_.Run()) {
+ gl_image_->ReleaseTexImage(GL_TEXTURE_EXTERNAL_OES);
+ gl_image_->Destroy(true);
+
+ DCHECK_EQ(glGetError(), static_cast<GLenum>(GL_NO_ERROR));
+ }
+}
+
+bool VaapiDrmPicture::Initialize() {
+ // We want to create a VASurface and an EGLImage out of the same
+ // memory buffer, so we can output decoded pictures to it using
+ // VAAPI and also use it to paint with GL.
+ ui::OzonePlatform* platform = ui::OzonePlatform::GetInstance();
+ ui::SurfaceFactoryOzone* factory = platform->GetSurfaceFactoryOzone();
+
+ // Create a buffer from Ozone.
+ pixmap_ = factory->CreateNativePixmap(gfx::kNullAcceleratedWidget, size(),
+ ui::SurfaceFactoryOzone::BGRA_8888,
+ ui::SurfaceFactoryOzone::SCANOUT);
+ if (!pixmap_) {
+ LOG(ERROR) << "Failed creating an Ozone NativePixmap";
+ return false;
+ }
+
+ // Get the dmabuf of the created buffer.
+ int dmabuf_fd = pixmap_->GetDmaBufFd();
+ if (dmabuf_fd < 0) {
+ LOG(ERROR) << "Failed to get dmabuf from an Ozone NativePixmap";
+ return false;
+ }
+ int dmabuf_pitch = pixmap_->GetDmaBufPitch();
+
+ // Create a VASurface out of the created buffer using the dmabuf.
+ VASurfaceAttribExternalBuffers va_attrib_extbuf;
+ memset(&va_attrib_extbuf, 0, sizeof(va_attrib_extbuf));
+ va_attrib_extbuf.pixel_format = VA_FOURCC_BGRX;
+ va_attrib_extbuf.width = size().width();
+ va_attrib_extbuf.height = size().height();
+ va_attrib_extbuf.data_size = size().height() * dmabuf_pitch;
+ va_attrib_extbuf.num_planes = 1;
+ va_attrib_extbuf.pitches[0] = dmabuf_pitch;
+ va_attrib_extbuf.offsets[0] = 0;
+ va_attrib_extbuf.buffers = reinterpret_cast<unsigned long*>(&dmabuf_fd);
+ va_attrib_extbuf.num_buffers = 1;
+ va_attrib_extbuf.flags = 0;
+ va_attrib_extbuf.private_data = NULL;
+
+ std::vector<VASurfaceAttrib> va_attribs;
+ va_attribs.resize(2);
+
+ va_attribs[0].type = VASurfaceAttribMemoryType;
+ va_attribs[0].flags = VA_SURFACE_ATTRIB_SETTABLE;
+ va_attribs[0].value.type = VAGenericValueTypeInteger;
+ va_attribs[0].value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
+
+ va_attribs[1].type = VASurfaceAttribExternalBufferDescriptor;
+ va_attribs[1].flags = VA_SURFACE_ATTRIB_SETTABLE;
+ va_attribs[1].value.type = VAGenericValueTypePointer;
+ va_attribs[1].value.value.p = &va_attrib_extbuf;
+
+ va_surface_ = vaapi_wrapper_->CreateUnownedSurface(VA_RT_FORMAT_RGB32, size(),
+ va_attribs);
+ if (!va_surface_) {
+ LOG(ERROR) << "Failed to create VASurface for an Ozone NativePixmap";
+ return false;
+ }
+
+ if (!make_context_current_.Run())
+ return false;
+
+ gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_EXTERNAL_OES,
+ texture_id());
+ gl_image_ = ui::GpuMemoryBufferFactoryOzoneNativeBuffer::CreateImageForPixmap(
+ pixmap_, size(), gfx::GpuMemoryBuffer::BGRA_8888, GL_BGRA_EXT);
+ if (!gl_image_) {
+ LOG(ERROR) << "Failed to create GLImage";
+ return false;
+ }
+ if (!gl_image_->BindTexImage(GL_TEXTURE_EXTERNAL_OES)) {
+ LOG(ERROR) << "Failed to bind texture to GLImage";
+ return false;
+ }
+
+ return true;
+}
+
+bool VaapiDrmPicture::DownloadFromSurface(
+ const scoped_refptr<VASurface>& va_surface) {
+ return vaapi_wrapper_->BlitSurface(va_surface->id(), va_surface->size(),
+ va_surface_->id(), va_surface_->size());
+}
+
+scoped_refptr<gfx::GLImage> VaapiDrmPicture::GetImageToBind() {
+ return gl_image_;
+}
+
+bool VaapiDrmPicture::AllowOverlay() const {
+ return true;
+}
+
+} // namespace
diff --git a/chromium/content/common/gpu/media/vaapi_drm_picture.h b/chromium/content/common/gpu/media/vaapi_drm_picture.h
new file mode 100644
index 00000000000..e982b595e8c
--- /dev/null
+++ b/chromium/content/common/gpu/media/vaapi_drm_picture.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.
+//
+// This file contains an implementation of picture allocation for the
+// Ozone window system used by VaapiVideoDecodeAccelerator to produce
+// output pictures.
+
+#ifndef CONTENT_COMMON_GPU_MEDIA_VAAPI_DRM_PICTURE_H_
+#define CONTENT_COMMON_GPU_MEDIA_VAAPI_DRM_PICTURE_H_
+
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "content/common/gpu/media/vaapi_picture.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace gfx {
+class GLImage;
+}
+
+namespace ui {
+class NativePixmap;
+}
+
+namespace content {
+
+class VaapiWrapper;
+
+// Implementation of VaapiPicture for the ozone/drm backed chromium.
+class VaapiDrmPicture : public VaapiPicture {
+ public:
+ VaapiDrmPicture(VaapiWrapper* vaapi_wrapper,
+ const base::Callback<bool(void)>& make_context_current,
+ int32 picture_buffer_id,
+ uint32 texture_id,
+ const gfx::Size& size);
+
+ ~VaapiDrmPicture() override;
+
+ bool Initialize() override;
+
+ bool DownloadFromSurface(const scoped_refptr<VASurface>& va_surface) override;
+
+ scoped_refptr<gfx::GLImage> GetImageToBind() override;
+
+ bool AllowOverlay() const override;
+
+ private:
+ VaapiWrapper* vaapi_wrapper_; // Not owned.
+ base::Callback<bool(void)> make_context_current_;
+
+ // Ozone buffer, the storage of the EGLImage and the VASurface.
+ scoped_refptr<ui::NativePixmap> pixmap_;
+
+ // EGLImage bound to the GL textures used by the VDA client.
+ scoped_refptr<gfx::GLImage> gl_image_;
+
+ // VASurface used to transfer from the decoder's pixel format.
+ scoped_refptr<VASurface> va_surface_;
+
+ DISALLOW_COPY_AND_ASSIGN(VaapiDrmPicture);
+};
+
+} // namespace content
+
+#endif // CONTENT_COMMON_GPU_MEDIA_VAAPI_DRM_PICTURE_H_
diff --git a/chromium/content/common/gpu/media/vaapi_h264_decoder.cc b/chromium/content/common/gpu/media/vaapi_h264_decoder.cc
deleted file mode 100644
index 56918caf5d7..00000000000
--- a/chromium/content/common/gpu/media/vaapi_h264_decoder.cc
+++ /dev/null
@@ -1,1700 +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 <algorithm>
-#include <limits>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/numerics/safe_conversions.h"
-#include "base/stl_util.h"
-#include "content/common/gpu/media/vaapi_h264_decoder.h"
-
-namespace content {
-
-// Decode surface, used for decoding and reference. input_id comes from client
-// and is associated with the surface that was produced as the result
-// of decoding a bitstream buffer with that id.
-class VaapiH264Decoder::DecodeSurface {
- public:
- DecodeSurface(int poc,
- int32 input_id,
- const scoped_refptr<VASurface>& va_surface);
- DecodeSurface(int poc, const scoped_refptr<DecodeSurface>& dec_surface);
- ~DecodeSurface();
-
- int poc() {
- return poc_;
- }
-
- scoped_refptr<VASurface> va_surface() {
- return va_surface_;
- }
-
- int32 input_id() {
- return input_id_;
- }
-
- private:
- int poc_;
- int32 input_id_;
- scoped_refptr<VASurface> va_surface_;
-};
-
-VaapiH264Decoder::DecodeSurface::DecodeSurface(
- int poc,
- int32 input_id,
- const scoped_refptr<VASurface>& va_surface)
- : poc_(poc),
- input_id_(input_id),
- va_surface_(va_surface) {
- DCHECK(va_surface_.get());
-}
-
-VaapiH264Decoder::DecodeSurface::~DecodeSurface() {
-}
-
-VaapiH264Decoder::VaapiH264Decoder(
- VaapiWrapper* vaapi_wrapper,
- const OutputPicCB& output_pic_cb,
- const ReportErrorToUmaCB& report_error_to_uma_cb)
- : max_pic_order_cnt_lsb_(0),
- max_frame_num_(0),
- max_pic_num_(0),
- max_long_term_frame_idx_(0),
- max_num_reorder_frames_(0),
- curr_sps_id_(-1),
- curr_pps_id_(-1),
- vaapi_wrapper_(vaapi_wrapper),
- output_pic_cb_(output_pic_cb),
- report_error_to_uma_cb_(report_error_to_uma_cb) {
- Reset();
- state_ = kNeedStreamMetadata;
-}
-
-VaapiH264Decoder::~VaapiH264Decoder() {
-}
-
-void VaapiH264Decoder::Reset() {
- curr_pic_.reset();
-
- curr_input_id_ = -1;
- frame_num_ = 0;
- prev_frame_num_ = -1;
- prev_frame_num_offset_ = -1;
-
- prev_ref_has_memmgmnt5_ = false;
- prev_ref_top_field_order_cnt_ = -1;
- prev_ref_pic_order_cnt_msb_ = -1;
- prev_ref_pic_order_cnt_lsb_ = -1;
- prev_ref_field_ = H264Picture::FIELD_NONE;
-
- vaapi_wrapper_->DestroyPendingBuffers();
-
- ref_pic_list0_.clear();
- ref_pic_list1_.clear();
-
- for (DecSurfacesInUse::iterator it = decode_surfaces_in_use_.begin();
- it != decode_surfaces_in_use_.end(); ) {
- int poc = it->second->poc();
- // Must be incremented before UnassignSurfaceFromPoC as this call
- // invalidates |it|.
- ++it;
- UnassignSurfaceFromPoC(poc);
- }
- DCHECK(decode_surfaces_in_use_.empty());
-
- dpb_.Clear();
- parser_.Reset();
- last_output_poc_ = std::numeric_limits<int>::min();
-
- // If we are in kDecoding, we can resume without processing an SPS.
- if (state_ == kDecoding)
- state_ = kAfterReset;
-}
-
-void VaapiH264Decoder::ReuseSurface(
- const scoped_refptr<VASurface>& va_surface) {
- available_va_surfaces_.push_back(va_surface);
-}
-
-// Fill |va_pic| with default/neutral values.
-static void InitVAPicture(VAPictureH264* va_pic) {
- memset(va_pic, 0, sizeof(*va_pic));
- va_pic->picture_id = VA_INVALID_ID;
- va_pic->flags = VA_PICTURE_H264_INVALID;
-}
-
-void VaapiH264Decoder::FillVAPicture(VAPictureH264 *va_pic, H264Picture* pic) {
- DCHECK(pic);
-
- DecodeSurface* dec_surface = DecodeSurfaceByPoC(pic->pic_order_cnt);
- if (!dec_surface) {
- // Cannot provide a ref picture, will corrupt output, but may be able
- // to recover.
- InitVAPicture(va_pic);
- return;
- }
-
- va_pic->picture_id = dec_surface->va_surface()->id();
- va_pic->frame_idx = pic->frame_num;
- va_pic->flags = 0;
-
- switch (pic->field) {
- case H264Picture::FIELD_NONE:
- break;
- case H264Picture::FIELD_TOP:
- va_pic->flags |= VA_PICTURE_H264_TOP_FIELD;
- break;
- case H264Picture::FIELD_BOTTOM:
- va_pic->flags |= VA_PICTURE_H264_BOTTOM_FIELD;
- break;
- }
-
- if (pic->ref) {
- va_pic->flags |= pic->long_term ? VA_PICTURE_H264_LONG_TERM_REFERENCE
- : VA_PICTURE_H264_SHORT_TERM_REFERENCE;
- }
-
- va_pic->TopFieldOrderCnt = pic->top_field_order_cnt;
- va_pic->BottomFieldOrderCnt = pic->bottom_field_order_cnt;
-}
-
-int VaapiH264Decoder::FillVARefFramesFromDPB(VAPictureH264 *va_pics,
- int num_pics) {
- H264DPB::Pictures::reverse_iterator rit;
- int i;
-
- // Return reference frames in reverse order of insertion.
- // Libva does not document this, but other implementations (e.g. mplayer)
- // do it this way as well.
- for (rit = dpb_.rbegin(), i = 0; rit != dpb_.rend() && i < num_pics; ++rit) {
- if ((*rit)->ref)
- FillVAPicture(&va_pics[i++], *rit);
- }
-
- return i;
-}
-
-VaapiH264Decoder::DecodeSurface* VaapiH264Decoder::DecodeSurfaceByPoC(int poc) {
- DecSurfacesInUse::iterator iter = decode_surfaces_in_use_.find(poc);
- if (iter == decode_surfaces_in_use_.end()) {
- DVLOG(1) << "Could not find surface assigned to POC: " << poc;
- return NULL;
- }
-
- return iter->second.get();
-}
-
-bool VaapiH264Decoder::AssignSurfaceToPoC(int32 input_id, int poc) {
- if (available_va_surfaces_.empty()) {
- DVLOG(1) << "No VA Surfaces available";
- return false;
- }
-
- linked_ptr<DecodeSurface> dec_surface(new DecodeSurface(
- poc, input_id, available_va_surfaces_.back()));
- available_va_surfaces_.pop_back();
-
- DVLOG(4) << "POC " << poc
- << " will use surface " << dec_surface->va_surface()->id();
-
- bool inserted = decode_surfaces_in_use_.insert(
- std::make_pair(poc, dec_surface)).second;
- DCHECK(inserted);
-
- return true;
-}
-
-void VaapiH264Decoder::UnassignSurfaceFromPoC(int poc) {
- DecSurfacesInUse::iterator it = decode_surfaces_in_use_.find(poc);
- if (it == decode_surfaces_in_use_.end()) {
- DVLOG(1) << "Asked to unassign an unassigned POC " << poc;
- return;
- }
-
- DVLOG(4) << "POC " << poc << " no longer using VA surface "
- << it->second->va_surface()->id();
-
- decode_surfaces_in_use_.erase(it);
-}
-
-bool VaapiH264Decoder::SendPPS() {
- const media::H264PPS* pps = parser_.GetPPS(curr_pps_id_);
- DCHECK(pps);
-
- const media::H264SPS* sps = parser_.GetSPS(pps->seq_parameter_set_id);
- DCHECK(sps);
-
- DCHECK(curr_pic_.get());
-
- VAPictureParameterBufferH264 pic_param;
- memset(&pic_param, 0, sizeof(VAPictureParameterBufferH264));
-
-#define FROM_SPS_TO_PP(a) pic_param.a = sps->a;
-#define FROM_SPS_TO_PP2(a, b) pic_param.b = sps->a;
- FROM_SPS_TO_PP2(pic_width_in_mbs_minus1, picture_width_in_mbs_minus1);
- // This assumes non-interlaced video
- FROM_SPS_TO_PP2(pic_height_in_map_units_minus1,
- picture_height_in_mbs_minus1);
- FROM_SPS_TO_PP(bit_depth_luma_minus8);
- FROM_SPS_TO_PP(bit_depth_chroma_minus8);
-#undef FROM_SPS_TO_PP
-#undef FROM_SPS_TO_PP2
-
-#define FROM_SPS_TO_PP_SF(a) pic_param.seq_fields.bits.a = sps->a;
-#define FROM_SPS_TO_PP_SF2(a, b) pic_param.seq_fields.bits.b = sps->a;
- FROM_SPS_TO_PP_SF(chroma_format_idc);
- FROM_SPS_TO_PP_SF2(separate_colour_plane_flag,
- residual_colour_transform_flag);
- FROM_SPS_TO_PP_SF(gaps_in_frame_num_value_allowed_flag);
- FROM_SPS_TO_PP_SF(frame_mbs_only_flag);
- FROM_SPS_TO_PP_SF(mb_adaptive_frame_field_flag);
- FROM_SPS_TO_PP_SF(direct_8x8_inference_flag);
- pic_param.seq_fields.bits.MinLumaBiPredSize8x8 = (sps->level_idc >= 31);
- FROM_SPS_TO_PP_SF(log2_max_frame_num_minus4);
- FROM_SPS_TO_PP_SF(pic_order_cnt_type);
- FROM_SPS_TO_PP_SF(log2_max_pic_order_cnt_lsb_minus4);
- FROM_SPS_TO_PP_SF(delta_pic_order_always_zero_flag);
-#undef FROM_SPS_TO_PP_SF
-#undef FROM_SPS_TO_PP_SF2
-
-#define FROM_PPS_TO_PP(a) pic_param.a = pps->a;
- FROM_PPS_TO_PP(num_slice_groups_minus1);
- pic_param.slice_group_map_type = 0;
- pic_param.slice_group_change_rate_minus1 = 0;
- FROM_PPS_TO_PP(pic_init_qp_minus26);
- FROM_PPS_TO_PP(pic_init_qs_minus26);
- FROM_PPS_TO_PP(chroma_qp_index_offset);
- FROM_PPS_TO_PP(second_chroma_qp_index_offset);
-#undef FROM_PPS_TO_PP
-
-#define FROM_PPS_TO_PP_PF(a) pic_param.pic_fields.bits.a = pps->a;
-#define FROM_PPS_TO_PP_PF2(a, b) pic_param.pic_fields.bits.b = pps->a;
- FROM_PPS_TO_PP_PF(entropy_coding_mode_flag);
- FROM_PPS_TO_PP_PF(weighted_pred_flag);
- FROM_PPS_TO_PP_PF(weighted_bipred_idc);
- FROM_PPS_TO_PP_PF(transform_8x8_mode_flag);
-
- pic_param.pic_fields.bits.field_pic_flag = 0;
- FROM_PPS_TO_PP_PF(constrained_intra_pred_flag);
- FROM_PPS_TO_PP_PF2(bottom_field_pic_order_in_frame_present_flag,
- pic_order_present_flag);
- FROM_PPS_TO_PP_PF(deblocking_filter_control_present_flag);
- FROM_PPS_TO_PP_PF(redundant_pic_cnt_present_flag);
- pic_param.pic_fields.bits.reference_pic_flag = curr_pic_->ref;
-#undef FROM_PPS_TO_PP_PF
-#undef FROM_PPS_TO_PP_PF2
-
- pic_param.frame_num = curr_pic_->frame_num;
-
- InitVAPicture(&pic_param.CurrPic);
- FillVAPicture(&pic_param.CurrPic, curr_pic_.get());
-
- // Init reference pictures' array.
- for (int i = 0; i < 16; ++i)
- InitVAPicture(&pic_param.ReferenceFrames[i]);
-
- // And fill it with picture info from DPB.
- FillVARefFramesFromDPB(pic_param.ReferenceFrames,
- arraysize(pic_param.ReferenceFrames));
-
- pic_param.num_ref_frames = sps->max_num_ref_frames;
-
- return vaapi_wrapper_->SubmitBuffer(VAPictureParameterBufferType,
- sizeof(VAPictureParameterBufferH264),
- &pic_param);
-}
-
-bool VaapiH264Decoder::SendIQMatrix() {
- const media::H264PPS* pps = parser_.GetPPS(curr_pps_id_);
- DCHECK(pps);
-
- VAIQMatrixBufferH264 iq_matrix_buf;
- memset(&iq_matrix_buf, 0, sizeof(VAIQMatrixBufferH264));
-
- if (pps->pic_scaling_matrix_present_flag) {
- for (int i = 0; i < 6; ++i) {
- for (int j = 0; j < 16; ++j)
- iq_matrix_buf.ScalingList4x4[i][j] = pps->scaling_list4x4[i][j];
- }
-
- for (int i = 0; i < 2; ++i) {
- for (int j = 0; j < 64; ++j)
- iq_matrix_buf.ScalingList8x8[i][j] = pps->scaling_list8x8[i][j];
- }
- } else {
- const media::H264SPS* sps = parser_.GetSPS(pps->seq_parameter_set_id);
- DCHECK(sps);
- for (int i = 0; i < 6; ++i) {
- for (int j = 0; j < 16; ++j)
- iq_matrix_buf.ScalingList4x4[i][j] = sps->scaling_list4x4[i][j];
- }
-
- for (int i = 0; i < 2; ++i) {
- for (int j = 0; j < 64; ++j)
- iq_matrix_buf.ScalingList8x8[i][j] = sps->scaling_list8x8[i][j];
- }
- }
-
- return vaapi_wrapper_->SubmitBuffer(VAIQMatrixBufferType,
- sizeof(VAIQMatrixBufferH264),
- &iq_matrix_buf);
-}
-
-bool VaapiH264Decoder::SendVASliceParam(media::H264SliceHeader* slice_hdr) {
- const media::H264PPS* pps = parser_.GetPPS(slice_hdr->pic_parameter_set_id);
- DCHECK(pps);
-
- const media::H264SPS* sps = parser_.GetSPS(pps->seq_parameter_set_id);
- DCHECK(sps);
-
- VASliceParameterBufferH264 slice_param;
- memset(&slice_param, 0, sizeof(VASliceParameterBufferH264));
-
- slice_param.slice_data_size = slice_hdr->nalu_size;
- slice_param.slice_data_offset = 0;
- slice_param.slice_data_flag = VA_SLICE_DATA_FLAG_ALL;
- slice_param.slice_data_bit_offset = slice_hdr->header_bit_size;
-
-#define SHDRToSP(a) slice_param.a = slice_hdr->a;
- SHDRToSP(first_mb_in_slice);
- slice_param.slice_type = slice_hdr->slice_type % 5;
- SHDRToSP(direct_spatial_mv_pred_flag);
-
- // TODO posciak: make sure parser sets those even when override flags
- // in slice header is off.
- SHDRToSP(num_ref_idx_l0_active_minus1);
- SHDRToSP(num_ref_idx_l1_active_minus1);
- SHDRToSP(cabac_init_idc);
- SHDRToSP(slice_qp_delta);
- SHDRToSP(disable_deblocking_filter_idc);
- SHDRToSP(slice_alpha_c0_offset_div2);
- SHDRToSP(slice_beta_offset_div2);
-
- if (((slice_hdr->IsPSlice() || slice_hdr->IsSPSlice()) &&
- pps->weighted_pred_flag) ||
- (slice_hdr->IsBSlice() && pps->weighted_bipred_idc == 1)) {
- SHDRToSP(luma_log2_weight_denom);
- SHDRToSP(chroma_log2_weight_denom);
-
- SHDRToSP(luma_weight_l0_flag);
- SHDRToSP(luma_weight_l1_flag);
-
- SHDRToSP(chroma_weight_l0_flag);
- SHDRToSP(chroma_weight_l1_flag);
-
- for (int i = 0; i <= slice_param.num_ref_idx_l0_active_minus1; ++i) {
- slice_param.luma_weight_l0[i] =
- slice_hdr->pred_weight_table_l0.luma_weight[i];
- slice_param.luma_offset_l0[i] =
- slice_hdr->pred_weight_table_l0.luma_offset[i];
-
- for (int j = 0; j < 2; ++j) {
- slice_param.chroma_weight_l0[i][j] =
- slice_hdr->pred_weight_table_l0.chroma_weight[i][j];
- slice_param.chroma_offset_l0[i][j] =
- slice_hdr->pred_weight_table_l0.chroma_offset[i][j];
- }
- }
-
- if (slice_hdr->IsBSlice()) {
- for (int i = 0; i <= slice_param.num_ref_idx_l1_active_minus1; ++i) {
- slice_param.luma_weight_l1[i] =
- slice_hdr->pred_weight_table_l1.luma_weight[i];
- slice_param.luma_offset_l1[i] =
- slice_hdr->pred_weight_table_l1.luma_offset[i];
-
- for (int j = 0; j < 2; ++j) {
- slice_param.chroma_weight_l1[i][j] =
- slice_hdr->pred_weight_table_l1.chroma_weight[i][j];
- slice_param.chroma_offset_l1[i][j] =
- slice_hdr->pred_weight_table_l1.chroma_offset[i][j];
- }
- }
- }
- }
-
- for (int i = 0; i < 32; ++i) {
- InitVAPicture(&slice_param.RefPicList0[i]);
- InitVAPicture(&slice_param.RefPicList1[i]);
- }
-
- int i;
- H264Picture::PtrVector::iterator it;
- for (it = ref_pic_list0_.begin(), i = 0; it != ref_pic_list0_.end() && *it;
- ++it, ++i)
- FillVAPicture(&slice_param.RefPicList0[i], *it);
- for (it = ref_pic_list1_.begin(), i = 0; it != ref_pic_list1_.end() && *it;
- ++it, ++i)
- FillVAPicture(&slice_param.RefPicList1[i], *it);
-
- return vaapi_wrapper_->SubmitBuffer(VASliceParameterBufferType,
- sizeof(VASliceParameterBufferH264),
- &slice_param);
-}
-
-bool VaapiH264Decoder::SendSliceData(const uint8* ptr, size_t size) {
- // Can't help it, blame libva...
- void* non_const_ptr = const_cast<uint8*>(ptr);
- return vaapi_wrapper_->SubmitBuffer(VASliceDataBufferType, size,
- non_const_ptr);
-}
-
-bool VaapiH264Decoder::PrepareRefPicLists(media::H264SliceHeader* slice_hdr) {
- ref_pic_list0_.clear();
- ref_pic_list1_.clear();
-
- // Fill reference picture lists for B and S/SP slices.
- if (slice_hdr->IsPSlice() || slice_hdr->IsSPSlice()) {
- ConstructReferencePicListsP(slice_hdr);
- return ModifyReferencePicList(slice_hdr, 0);
- }
-
- if (slice_hdr->IsBSlice()) {
- ConstructReferencePicListsB(slice_hdr);
- return ModifyReferencePicList(slice_hdr, 0) &&
- ModifyReferencePicList(slice_hdr, 1);
- }
-
- return true;
-}
-
-bool VaapiH264Decoder::QueueSlice(media::H264SliceHeader* slice_hdr) {
- DCHECK(curr_pic_.get());
-
- if (!PrepareRefPicLists(slice_hdr))
- return false;
-
- if (!SendVASliceParam(slice_hdr))
- return false;
-
- if (!SendSliceData(slice_hdr->nalu_data, slice_hdr->nalu_size))
- return false;
-
- return true;
-}
-
-// TODO(posciak) start using vaMapBuffer instead of vaCreateBuffer wherever
-// possible.
-bool VaapiH264Decoder::DecodePicture() {
- DCHECK(curr_pic_.get());
-
- DVLOG(4) << "Decoding POC " << curr_pic_->pic_order_cnt;
- DecodeSurface* dec_surface = DecodeSurfaceByPoC(curr_pic_->pic_order_cnt);
- if (!dec_surface) {
- DVLOG(1) << "Asked to decode an invalid POC " << curr_pic_->pic_order_cnt;
- return false;
- }
-
- if (!vaapi_wrapper_->ExecuteAndDestroyPendingBuffers(
- dec_surface->va_surface()->id())) {
- DVLOG(1) << "Failed decoding picture";
- return false;
- }
-
- return true;
-}
-
-bool VaapiH264Decoder::InitCurrPicture(media::H264SliceHeader* slice_hdr) {
- DCHECK(curr_pic_.get());
-
- memset(curr_pic_.get(), 0, sizeof(H264Picture));
-
- curr_pic_->idr = slice_hdr->idr_pic_flag;
-
- if (slice_hdr->field_pic_flag) {
- curr_pic_->field = slice_hdr->bottom_field_flag ? H264Picture::FIELD_BOTTOM
- : H264Picture::FIELD_TOP;
- } else {
- curr_pic_->field = H264Picture::FIELD_NONE;
- }
-
- curr_pic_->ref = slice_hdr->nal_ref_idc != 0;
- // This assumes non-interlaced stream.
- curr_pic_->frame_num = curr_pic_->pic_num = slice_hdr->frame_num;
-
- if (!CalculatePicOrderCounts(slice_hdr))
- return false;
-
- // Try to get an empty surface to decode this picture to.
- if (!AssignSurfaceToPoC(curr_input_id_, curr_pic_->pic_order_cnt)) {
- DVLOG(1) << "Failed getting a free surface for a picture";
- return false;
- }
-
- curr_pic_->long_term_reference_flag = slice_hdr->long_term_reference_flag;
- curr_pic_->adaptive_ref_pic_marking_mode_flag =
- slice_hdr->adaptive_ref_pic_marking_mode_flag;
-
- // If the slice header indicates we will have to perform reference marking
- // process after this picture is decoded, store required data for that
- // purpose.
- if (slice_hdr->adaptive_ref_pic_marking_mode_flag) {
- COMPILE_ASSERT(sizeof(curr_pic_->ref_pic_marking) ==
- sizeof(slice_hdr->ref_pic_marking),
- ref_pic_marking_array_sizes_do_not_match);
- memcpy(curr_pic_->ref_pic_marking, slice_hdr->ref_pic_marking,
- sizeof(curr_pic_->ref_pic_marking));
- }
-
- return true;
-}
-
-bool VaapiH264Decoder::CalculatePicOrderCounts(
- media::H264SliceHeader* slice_hdr) {
- DCHECK_NE(curr_sps_id_, -1);
- const media::H264SPS* sps = parser_.GetSPS(curr_sps_id_);
-
- int pic_order_cnt_lsb = slice_hdr->pic_order_cnt_lsb;
- curr_pic_->pic_order_cnt_lsb = pic_order_cnt_lsb;
-
- switch (sps->pic_order_cnt_type) {
- case 0:
- // See spec 8.2.1.1.
- int prev_pic_order_cnt_msb, prev_pic_order_cnt_lsb;
- if (slice_hdr->idr_pic_flag) {
- prev_pic_order_cnt_msb = prev_pic_order_cnt_lsb = 0;
- } else {
- if (prev_ref_has_memmgmnt5_) {
- if (prev_ref_field_ != H264Picture::FIELD_BOTTOM) {
- prev_pic_order_cnt_msb = 0;
- prev_pic_order_cnt_lsb = prev_ref_top_field_order_cnt_;
- } else {
- prev_pic_order_cnt_msb = 0;
- prev_pic_order_cnt_lsb = 0;
- }
- } else {
- prev_pic_order_cnt_msb = prev_ref_pic_order_cnt_msb_;
- prev_pic_order_cnt_lsb = prev_ref_pic_order_cnt_lsb_;
- }
- }
-
- DCHECK_NE(max_pic_order_cnt_lsb_, 0);
- if ((pic_order_cnt_lsb < prev_pic_order_cnt_lsb) &&
- (prev_pic_order_cnt_lsb - pic_order_cnt_lsb >=
- max_pic_order_cnt_lsb_ / 2)) {
- curr_pic_->pic_order_cnt_msb = prev_pic_order_cnt_msb +
- max_pic_order_cnt_lsb_;
- } else if ((pic_order_cnt_lsb > prev_pic_order_cnt_lsb) &&
- (pic_order_cnt_lsb - prev_pic_order_cnt_lsb >
- max_pic_order_cnt_lsb_ / 2)) {
- curr_pic_->pic_order_cnt_msb = prev_pic_order_cnt_msb -
- max_pic_order_cnt_lsb_;
- } else {
- curr_pic_->pic_order_cnt_msb = prev_pic_order_cnt_msb;
- }
-
- if (curr_pic_->field != H264Picture::FIELD_BOTTOM) {
- curr_pic_->top_field_order_cnt = curr_pic_->pic_order_cnt_msb +
- pic_order_cnt_lsb;
- }
-
- if (curr_pic_->field != H264Picture::FIELD_TOP) {
- // TODO posciak: perhaps replace with pic->field?
- if (!slice_hdr->field_pic_flag) {
- curr_pic_->bottom_field_order_cnt = curr_pic_->top_field_order_cnt +
- slice_hdr->delta_pic_order_cnt_bottom;
- } else {
- curr_pic_->bottom_field_order_cnt = curr_pic_->pic_order_cnt_msb +
- pic_order_cnt_lsb;
- }
- }
- break;
-
- case 1: {
- // See spec 8.2.1.2.
- if (prev_has_memmgmnt5_)
- prev_frame_num_offset_ = 0;
-
- if (slice_hdr->idr_pic_flag)
- curr_pic_->frame_num_offset = 0;
- else if (prev_frame_num_ > slice_hdr->frame_num)
- curr_pic_->frame_num_offset = prev_frame_num_offset_ + max_frame_num_;
- else
- curr_pic_->frame_num_offset = prev_frame_num_offset_;
-
- int abs_frame_num = 0;
- if (sps->num_ref_frames_in_pic_order_cnt_cycle != 0)
- abs_frame_num = curr_pic_->frame_num_offset + slice_hdr->frame_num;
- else
- abs_frame_num = 0;
-
- if (slice_hdr->nal_ref_idc == 0 && abs_frame_num > 0)
- --abs_frame_num;
-
- int expected_pic_order_cnt = 0;
- if (abs_frame_num > 0) {
- if (sps->num_ref_frames_in_pic_order_cnt_cycle == 0) {
- DVLOG(1) << "Invalid num_ref_frames_in_pic_order_cnt_cycle "
- << "in stream";
- return false;
- }
-
- int pic_order_cnt_cycle_cnt = (abs_frame_num - 1) /
- sps->num_ref_frames_in_pic_order_cnt_cycle;
- int frame_num_in_pic_order_cnt_cycle = (abs_frame_num - 1) %
- sps->num_ref_frames_in_pic_order_cnt_cycle;
-
- expected_pic_order_cnt = pic_order_cnt_cycle_cnt *
- sps->expected_delta_per_pic_order_cnt_cycle;
- // frame_num_in_pic_order_cnt_cycle is verified < 255 in parser
- for (int i = 0; i <= frame_num_in_pic_order_cnt_cycle; ++i)
- expected_pic_order_cnt += sps->offset_for_ref_frame[i];
- }
-
- if (!slice_hdr->nal_ref_idc)
- expected_pic_order_cnt += sps->offset_for_non_ref_pic;
-
- if (!slice_hdr->field_pic_flag) {
- curr_pic_->top_field_order_cnt = expected_pic_order_cnt +
- slice_hdr->delta_pic_order_cnt[0];
- curr_pic_->bottom_field_order_cnt = curr_pic_->top_field_order_cnt +
- sps->offset_for_top_to_bottom_field +
- slice_hdr->delta_pic_order_cnt[1];
- } else if (!slice_hdr->bottom_field_flag) {
- curr_pic_->top_field_order_cnt = expected_pic_order_cnt +
- slice_hdr->delta_pic_order_cnt[0];
- } else {
- curr_pic_->bottom_field_order_cnt = expected_pic_order_cnt +
- sps->offset_for_top_to_bottom_field +
- slice_hdr->delta_pic_order_cnt[0];
- }
- break;
- }
-
- case 2:
- // See spec 8.2.1.3.
- if (prev_has_memmgmnt5_)
- prev_frame_num_offset_ = 0;
-
- if (slice_hdr->idr_pic_flag)
- curr_pic_->frame_num_offset = 0;
- else if (prev_frame_num_ > slice_hdr->frame_num)
- curr_pic_->frame_num_offset = prev_frame_num_offset_ + max_frame_num_;
- else
- curr_pic_->frame_num_offset = prev_frame_num_offset_;
-
- int temp_pic_order_cnt;
- if (slice_hdr->idr_pic_flag) {
- temp_pic_order_cnt = 0;
- } else if (!slice_hdr->nal_ref_idc) {
- temp_pic_order_cnt =
- 2 * (curr_pic_->frame_num_offset + slice_hdr->frame_num) - 1;
- } else {
- temp_pic_order_cnt = 2 * (curr_pic_->frame_num_offset +
- slice_hdr->frame_num);
- }
-
- if (!slice_hdr->field_pic_flag) {
- curr_pic_->top_field_order_cnt = temp_pic_order_cnt;
- curr_pic_->bottom_field_order_cnt = temp_pic_order_cnt;
- } else if (slice_hdr->bottom_field_flag) {
- curr_pic_->bottom_field_order_cnt = temp_pic_order_cnt;
- } else {
- curr_pic_->top_field_order_cnt = temp_pic_order_cnt;
- }
- break;
-
- default:
- DVLOG(1) << "Invalid pic_order_cnt_type: " << sps->pic_order_cnt_type;
- return false;
- }
-
- switch (curr_pic_->field) {
- case H264Picture::FIELD_NONE:
- curr_pic_->pic_order_cnt = std::min(curr_pic_->top_field_order_cnt,
- curr_pic_->bottom_field_order_cnt);
- break;
- case H264Picture::FIELD_TOP:
- curr_pic_->pic_order_cnt = curr_pic_->top_field_order_cnt;
- break;
- case H264Picture::FIELD_BOTTOM:
- curr_pic_->pic_order_cnt = curr_pic_->bottom_field_order_cnt;
- break;
- }
-
- return true;
-}
-
-void VaapiH264Decoder::UpdatePicNums() {
- for (H264DPB::Pictures::iterator it = dpb_.begin(); it != dpb_.end(); ++it) {
- H264Picture* pic = *it;
- DCHECK(pic);
- if (!pic->ref)
- continue;
-
- // Below assumes non-interlaced stream.
- DCHECK_EQ(pic->field, H264Picture::FIELD_NONE);
- if (pic->long_term) {
- pic->long_term_pic_num = pic->long_term_frame_idx;
- } else {
- if (pic->frame_num > frame_num_)
- pic->frame_num_wrap = pic->frame_num - max_frame_num_;
- else
- pic->frame_num_wrap = pic->frame_num;
-
- pic->pic_num = pic->frame_num_wrap;
- }
- }
-}
-
-struct PicNumDescCompare {
- bool operator()(const H264Picture* a, const H264Picture* b) const {
- return a->pic_num > b->pic_num;
- }
-};
-
-struct LongTermPicNumAscCompare {
- bool operator()(const H264Picture* a, const H264Picture* b) const {
- return a->long_term_pic_num < b->long_term_pic_num;
- }
-};
-
-void VaapiH264Decoder::ConstructReferencePicListsP(
- media::H264SliceHeader* slice_hdr) {
- // RefPicList0 (8.2.4.2.1) [[1] [2]], where:
- // [1] shortterm ref pics sorted by descending pic_num,
- // [2] longterm ref pics by ascending long_term_pic_num.
- DCHECK(ref_pic_list0_.empty() && ref_pic_list1_.empty());
- // First get the short ref pics...
- dpb_.GetShortTermRefPicsAppending(ref_pic_list0_);
- size_t num_short_refs = ref_pic_list0_.size();
-
- // and sort them to get [1].
- std::sort(ref_pic_list0_.begin(), ref_pic_list0_.end(), PicNumDescCompare());
-
- // Now get long term pics and sort them by long_term_pic_num to get [2].
- dpb_.GetLongTermRefPicsAppending(ref_pic_list0_);
- std::sort(ref_pic_list0_.begin() + num_short_refs, ref_pic_list0_.end(),
- LongTermPicNumAscCompare());
-
- // Cut off if we have more than requested in slice header.
- ref_pic_list0_.resize(slice_hdr->num_ref_idx_l0_active_minus1 + 1);
-}
-
-struct POCAscCompare {
- bool operator()(const H264Picture* a, const H264Picture* b) const {
- return a->pic_order_cnt < b->pic_order_cnt;
- }
-};
-
-struct POCDescCompare {
- bool operator()(const H264Picture* a, const H264Picture* b) const {
- return a->pic_order_cnt > b->pic_order_cnt;
- }
-};
-
-void VaapiH264Decoder::ConstructReferencePicListsB(
- media::H264SliceHeader* slice_hdr) {
- // RefPicList0 (8.2.4.2.3) [[1] [2] [3]], where:
- // [1] shortterm ref pics with POC < curr_pic's POC sorted by descending POC,
- // [2] shortterm ref pics with POC > curr_pic's POC by ascending POC,
- // [3] longterm ref pics by ascending long_term_pic_num.
- DCHECK(ref_pic_list0_.empty() && ref_pic_list1_.empty());
- dpb_.GetShortTermRefPicsAppending(ref_pic_list0_);
- size_t num_short_refs = ref_pic_list0_.size();
-
- // First sort ascending, this will put [1] in right place and finish [2].
- std::sort(ref_pic_list0_.begin(), ref_pic_list0_.end(), POCAscCompare());
-
- // Find first with POC > curr_pic's POC to get first element in [2]...
- H264Picture::PtrVector::iterator iter;
- iter = std::upper_bound(ref_pic_list0_.begin(), ref_pic_list0_.end(),
- curr_pic_.get(), POCAscCompare());
-
- // and sort [1] descending, thus finishing sequence [1] [2].
- std::sort(ref_pic_list0_.begin(), iter, POCDescCompare());
-
- // Now add [3] and sort by ascending long_term_pic_num.
- dpb_.GetLongTermRefPicsAppending(ref_pic_list0_);
- std::sort(ref_pic_list0_.begin() + num_short_refs, ref_pic_list0_.end(),
- LongTermPicNumAscCompare());
-
- // RefPicList1 (8.2.4.2.4) [[1] [2] [3]], where:
- // [1] shortterm ref pics with POC > curr_pic's POC sorted by ascending POC,
- // [2] shortterm ref pics with POC < curr_pic's POC by descending POC,
- // [3] longterm ref pics by ascending long_term_pic_num.
-
- dpb_.GetShortTermRefPicsAppending(ref_pic_list1_);
- num_short_refs = ref_pic_list1_.size();
-
- // First sort by descending POC.
- std::sort(ref_pic_list1_.begin(), ref_pic_list1_.end(), POCDescCompare());
-
- // Find first with POC < curr_pic's POC to get first element in [2]...
- iter = std::upper_bound(ref_pic_list1_.begin(), ref_pic_list1_.end(),
- curr_pic_.get(), POCDescCompare());
-
- // and sort [1] ascending.
- std::sort(ref_pic_list1_.begin(), iter, POCAscCompare());
-
- // Now add [3] and sort by ascending long_term_pic_num
- dpb_.GetShortTermRefPicsAppending(ref_pic_list1_);
- std::sort(ref_pic_list1_.begin() + num_short_refs, ref_pic_list1_.end(),
- LongTermPicNumAscCompare());
-
- // If lists identical, swap first two entries in RefPicList1 (spec 8.2.4.2.3)
- if (ref_pic_list1_.size() > 1 &&
- std::equal(ref_pic_list0_.begin(), ref_pic_list0_.end(),
- ref_pic_list1_.begin()))
- std::swap(ref_pic_list1_[0], ref_pic_list1_[1]);
-
- // Per 8.2.4.2 it's possible for num_ref_idx_lX_active_minus1 to indicate
- // there should be more ref pics on list than we constructed.
- // Those superfluous ones should be treated as non-reference.
- ref_pic_list0_.resize(slice_hdr->num_ref_idx_l0_active_minus1 + 1);
- ref_pic_list1_.resize(slice_hdr->num_ref_idx_l1_active_minus1 + 1);
-}
-
-// See 8.2.4
-int VaapiH264Decoder::PicNumF(H264Picture *pic) {
- if (!pic)
- return -1;
-
- if (!pic->long_term)
- return pic->pic_num;
- else
- return max_pic_num_;
-}
-
-// See 8.2.4
-int VaapiH264Decoder::LongTermPicNumF(H264Picture *pic) {
- if (pic->ref && pic->long_term)
- return pic->long_term_pic_num;
- else
- return 2 * (max_long_term_frame_idx_ + 1);
-}
-
-// Shift elements on the |v| starting from |from| to |to|, inclusive,
-// one position to the right and insert pic at |from|.
-static void ShiftRightAndInsert(H264Picture::PtrVector *v,
- int from,
- int to,
- H264Picture* pic) {
- // Security checks, do not disable in Debug mode.
- CHECK(from <= to);
- CHECK(to <= std::numeric_limits<int>::max() - 2);
- // Additional checks. Debug mode ok.
- DCHECK(v);
- DCHECK(pic);
- DCHECK((to + 1 == static_cast<int>(v->size())) ||
- (to + 2 == static_cast<int>(v->size())));
-
- v->resize(to + 2);
-
- for (int i = to + 1; i > from; --i)
- (*v)[i] = (*v)[i - 1];
-
- (*v)[from] = pic;
-}
-
-bool VaapiH264Decoder::ModifyReferencePicList(media::H264SliceHeader* slice_hdr,
- int list) {
- int num_ref_idx_lX_active_minus1;
- H264Picture::PtrVector* ref_pic_listx;
- media::H264ModificationOfPicNum* list_mod;
-
- // This can process either ref_pic_list0 or ref_pic_list1, depending on
- // the list argument. Set up pointers to proper list to be processed here.
- if (list == 0) {
- if (!slice_hdr->ref_pic_list_modification_flag_l0)
- return true;
-
- list_mod = slice_hdr->ref_list_l0_modifications;
- num_ref_idx_lX_active_minus1 = ref_pic_list0_.size() - 1;
-
- ref_pic_listx = &ref_pic_list0_;
- } else {
- if (!slice_hdr->ref_pic_list_modification_flag_l1)
- return true;
-
- list_mod = slice_hdr->ref_list_l1_modifications;
- num_ref_idx_lX_active_minus1 = ref_pic_list1_.size() - 1;
-
- ref_pic_listx = &ref_pic_list1_;
- }
-
- DCHECK_GE(num_ref_idx_lX_active_minus1, 0);
-
- // Spec 8.2.4.3:
- // Reorder pictures on the list in a way specified in the stream.
- int pic_num_lx_pred = curr_pic_->pic_num;
- int ref_idx_lx = 0;
- int pic_num_lx_no_wrap;
- int pic_num_lx;
- bool done = false;
- H264Picture* pic;
- for (int i = 0; i < media::H264SliceHeader::kRefListModSize && !done; ++i) {
- switch (list_mod->modification_of_pic_nums_idc) {
- case 0:
- case 1:
- // Modify short reference picture position.
- if (list_mod->modification_of_pic_nums_idc == 0) {
- // Subtract given value from predicted PicNum.
- pic_num_lx_no_wrap = pic_num_lx_pred -
- (static_cast<int>(list_mod->abs_diff_pic_num_minus1) + 1);
- // Wrap around max_pic_num_ if it becomes < 0 as result
- // of subtraction.
- if (pic_num_lx_no_wrap < 0)
- pic_num_lx_no_wrap += max_pic_num_;
- } else {
- // Add given value to predicted PicNum.
- pic_num_lx_no_wrap = pic_num_lx_pred +
- (static_cast<int>(list_mod->abs_diff_pic_num_minus1) + 1);
- // Wrap around max_pic_num_ if it becomes >= max_pic_num_ as result
- // of the addition.
- if (pic_num_lx_no_wrap >= max_pic_num_)
- pic_num_lx_no_wrap -= max_pic_num_;
- }
-
- // For use in next iteration.
- pic_num_lx_pred = pic_num_lx_no_wrap;
-
- if (pic_num_lx_no_wrap > curr_pic_->pic_num)
- pic_num_lx = pic_num_lx_no_wrap - max_pic_num_;
- else
- pic_num_lx = pic_num_lx_no_wrap;
-
- DCHECK_LT(num_ref_idx_lX_active_minus1 + 1,
- media::H264SliceHeader::kRefListModSize);
- pic = dpb_.GetShortRefPicByPicNum(pic_num_lx);
- if (!pic) {
- DVLOG(1) << "Malformed stream, no pic num " << pic_num_lx;
- return false;
- }
- ShiftRightAndInsert(ref_pic_listx, ref_idx_lx,
- num_ref_idx_lX_active_minus1, pic);
- ref_idx_lx++;
-
- for (int src = ref_idx_lx, dst = ref_idx_lx;
- src <= num_ref_idx_lX_active_minus1 + 1; ++src) {
- if (PicNumF((*ref_pic_listx)[src]) != pic_num_lx)
- (*ref_pic_listx)[dst++] = (*ref_pic_listx)[src];
- }
- break;
-
- case 2:
- // Modify long term reference picture position.
- DCHECK_LT(num_ref_idx_lX_active_minus1 + 1,
- media::H264SliceHeader::kRefListModSize);
- pic = dpb_.GetLongRefPicByLongTermPicNum(list_mod->long_term_pic_num);
- if (!pic) {
- DVLOG(1) << "Malformed stream, no pic num "
- << list_mod->long_term_pic_num;
- return false;
- }
- ShiftRightAndInsert(ref_pic_listx, ref_idx_lx,
- num_ref_idx_lX_active_minus1, pic);
- ref_idx_lx++;
-
- for (int src = ref_idx_lx, dst = ref_idx_lx;
- src <= num_ref_idx_lX_active_minus1 + 1; ++src) {
- if (LongTermPicNumF((*ref_pic_listx)[src])
- != static_cast<int>(list_mod->long_term_pic_num))
- (*ref_pic_listx)[dst++] = (*ref_pic_listx)[src];
- }
- break;
-
- case 3:
- // End of modification list.
- done = true;
- break;
-
- default:
- // May be recoverable.
- DVLOG(1) << "Invalid modification_of_pic_nums_idc="
- << list_mod->modification_of_pic_nums_idc
- << " in position " << i;
- break;
- }
-
- ++list_mod;
- }
-
- // Per NOTE 2 in 8.2.4.3.2, the ref_pic_listx size in the above loop is
- // temporarily made one element longer than the required final list.
- // Resize the list back to its required size.
- ref_pic_listx->resize(num_ref_idx_lX_active_minus1 + 1);
-
- return true;
-}
-
-bool VaapiH264Decoder::OutputPic(H264Picture* pic) {
- DCHECK(!pic->outputted);
- pic->outputted = true;
- last_output_poc_ = pic->pic_order_cnt;
-
- DecodeSurface* dec_surface = DecodeSurfaceByPoC(pic->pic_order_cnt);
- if (!dec_surface)
- return false;
-
- DCHECK_GE(dec_surface->input_id(), 0);
- DVLOG(4) << "Posting output task for POC: " << pic->pic_order_cnt
- << " input_id: " << dec_surface->input_id();
- output_pic_cb_.Run(dec_surface->input_id(), dec_surface->va_surface());
-
- return true;
-}
-
-void VaapiH264Decoder::ClearDPB() {
- // Clear DPB contents, marking the pictures as unused first.
- for (H264DPB::Pictures::iterator it = dpb_.begin(); it != dpb_.end(); ++it)
- UnassignSurfaceFromPoC((*it)->pic_order_cnt);
-
- dpb_.Clear();
- last_output_poc_ = std::numeric_limits<int>::min();
-}
-
-bool VaapiH264Decoder::OutputAllRemainingPics() {
- // Output all pictures that are waiting to be outputted.
- FinishPrevFrameIfPresent();
- H264Picture::PtrVector to_output;
- dpb_.GetNotOutputtedPicsAppending(to_output);
- // Sort them by ascending POC to output in order.
- std::sort(to_output.begin(), to_output.end(), POCAscCompare());
-
- H264Picture::PtrVector::iterator it;
- for (it = to_output.begin(); it != to_output.end(); ++it) {
- if (!OutputPic(*it)) {
- DVLOG(1) << "Failed to output pic POC: " << (*it)->pic_order_cnt;
- return false;
- }
- }
-
- return true;
-}
-
-bool VaapiH264Decoder::Flush() {
- DVLOG(2) << "Decoder flush";
-
- if (!OutputAllRemainingPics())
- return false;
-
- ClearDPB();
-
- DCHECK(decode_surfaces_in_use_.empty());
- return true;
-}
-
-bool VaapiH264Decoder::StartNewFrame(media::H264SliceHeader* slice_hdr) {
- // TODO posciak: add handling of max_num_ref_frames per spec.
-
- // If the new frame is an IDR, output what's left to output and clear DPB
- if (slice_hdr->idr_pic_flag) {
- // (unless we are explicitly instructed not to do so).
- if (!slice_hdr->no_output_of_prior_pics_flag) {
- // Output DPB contents.
- if (!Flush())
- return false;
- }
- dpb_.Clear();
- last_output_poc_ = std::numeric_limits<int>::min();
- }
-
- // curr_pic_ should have either been added to DPB or discarded when finishing
- // the last frame. DPB is responsible for releasing that memory once it's
- // not needed anymore.
- DCHECK(!curr_pic_.get());
- curr_pic_.reset(new H264Picture);
- CHECK(curr_pic_.get());
-
- if (!InitCurrPicture(slice_hdr))
- return false;
-
- DCHECK_GT(max_frame_num_, 0);
-
- UpdatePicNums();
-
- // Send parameter buffers before each new picture, before the first slice.
- if (!SendPPS())
- return false;
-
- if (!SendIQMatrix())
- return false;
-
- if (!QueueSlice(slice_hdr))
- return false;
-
- return true;
-}
-
-bool VaapiH264Decoder::HandleMemoryManagementOps() {
- // 8.2.5.4
- for (unsigned int i = 0; i < arraysize(curr_pic_->ref_pic_marking); ++i) {
- // Code below does not support interlaced stream (per-field pictures).
- media::H264DecRefPicMarking* ref_pic_marking =
- &curr_pic_->ref_pic_marking[i];
- H264Picture* to_mark;
- int pic_num_x;
-
- switch (ref_pic_marking->memory_mgmnt_control_operation) {
- case 0:
- // Normal end of operations' specification.
- return true;
-
- case 1:
- // Mark a short term reference picture as unused so it can be removed
- // if outputted.
- pic_num_x = curr_pic_->pic_num -
- (ref_pic_marking->difference_of_pic_nums_minus1 + 1);
- to_mark = dpb_.GetShortRefPicByPicNum(pic_num_x);
- if (to_mark) {
- to_mark->ref = false;
- } else {
- DVLOG(1) << "Invalid short ref pic num to unmark";
- return false;
- }
- break;
-
- case 2:
- // Mark a long term reference picture as unused so it can be removed
- // if outputted.
- to_mark = dpb_.GetLongRefPicByLongTermPicNum(
- ref_pic_marking->long_term_pic_num);
- if (to_mark) {
- to_mark->ref = false;
- } else {
- DVLOG(1) << "Invalid long term ref pic num to unmark";
- return false;
- }
- break;
-
- case 3:
- // Mark a short term reference picture as long term reference.
- pic_num_x = curr_pic_->pic_num -
- (ref_pic_marking->difference_of_pic_nums_minus1 + 1);
- to_mark = dpb_.GetShortRefPicByPicNum(pic_num_x);
- if (to_mark) {
- DCHECK(to_mark->ref && !to_mark->long_term);
- to_mark->long_term = true;
- to_mark->long_term_frame_idx = ref_pic_marking->long_term_frame_idx;
- } else {
- DVLOG(1) << "Invalid short term ref pic num to mark as long ref";
- return false;
- }
- break;
-
- case 4: {
- // Unmark all reference pictures with long_term_frame_idx over new max.
- max_long_term_frame_idx_
- = ref_pic_marking->max_long_term_frame_idx_plus1 - 1;
- H264Picture::PtrVector long_terms;
- dpb_.GetLongTermRefPicsAppending(long_terms);
- for (size_t i = 0; i < long_terms.size(); ++i) {
- H264Picture* pic = long_terms[i];
- DCHECK(pic->ref && pic->long_term);
- // Ok to cast, max_long_term_frame_idx is much smaller than 16bit.
- if (pic->long_term_frame_idx >
- static_cast<int>(max_long_term_frame_idx_))
- pic->ref = false;
- }
- break;
- }
-
- case 5:
- // Unmark all reference pictures.
- dpb_.MarkAllUnusedForRef();
- max_long_term_frame_idx_ = -1;
- curr_pic_->mem_mgmt_5 = true;
- break;
-
- case 6: {
- // Replace long term reference pictures with current picture.
- // First unmark if any existing with this long_term_frame_idx...
- H264Picture::PtrVector long_terms;
- dpb_.GetLongTermRefPicsAppending(long_terms);
- for (size_t i = 0; i < long_terms.size(); ++i) {
- H264Picture* pic = long_terms[i];
- DCHECK(pic->ref && pic->long_term);
- // Ok to cast, long_term_frame_idx is much smaller than 16bit.
- if (pic->long_term_frame_idx ==
- static_cast<int>(ref_pic_marking->long_term_frame_idx))
- pic->ref = false;
- }
-
- // and mark the current one instead.
- curr_pic_->ref = true;
- curr_pic_->long_term = true;
- curr_pic_->long_term_frame_idx = ref_pic_marking->long_term_frame_idx;
- break;
- }
-
- default:
- // Would indicate a bug in parser.
- NOTREACHED();
- }
- }
-
- return true;
-}
-
-// This method ensures that DPB does not overflow, either by removing
-// reference pictures as specified in the stream, or using a sliding window
-// procedure to remove the oldest one.
-// It also performs marking and unmarking pictures as reference.
-// See spac 8.2.5.1.
-void VaapiH264Decoder::ReferencePictureMarking() {
- if (curr_pic_->idr) {
- // If current picture is an IDR, all reference pictures are unmarked.
- dpb_.MarkAllUnusedForRef();
-
- if (curr_pic_->long_term_reference_flag) {
- curr_pic_->long_term = true;
- curr_pic_->long_term_frame_idx = 0;
- max_long_term_frame_idx_ = 0;
- } else {
- curr_pic_->long_term = false;
- max_long_term_frame_idx_ = -1;
- }
- } else {
- if (!curr_pic_->adaptive_ref_pic_marking_mode_flag) {
- // If non-IDR, and the stream does not indicate what we should do to
- // ensure DPB doesn't overflow, discard oldest picture.
- // See spec 8.2.5.3.
- if (curr_pic_->field == H264Picture::FIELD_NONE) {
- DCHECK_LE(dpb_.CountRefPics(),
- std::max<int>(parser_.GetSPS(curr_sps_id_)->max_num_ref_frames,
- 1));
- if (dpb_.CountRefPics() ==
- std::max<int>(parser_.GetSPS(curr_sps_id_)->max_num_ref_frames,
- 1)) {
- // Max number of reference pics reached,
- // need to remove one of the short term ones.
- // Find smallest frame_num_wrap short reference picture and mark
- // it as unused.
- H264Picture* to_unmark = dpb_.GetLowestFrameNumWrapShortRefPic();
- if (to_unmark == NULL) {
- DVLOG(1) << "Couldn't find a short ref picture to unmark";
- return;
- }
- to_unmark->ref = false;
- }
- } else {
- // Shouldn't get here.
- DVLOG(1) << "Interlaced video not supported.";
- report_error_to_uma_cb_.Run(INTERLACED_STREAM);
- }
- } else {
- // Stream has instructions how to discard pictures from DPB and how
- // to mark/unmark existing reference pictures. Do it.
- // Spec 8.2.5.4.
- if (curr_pic_->field == H264Picture::FIELD_NONE) {
- HandleMemoryManagementOps();
- } else {
- // Shouldn't get here.
- DVLOG(1) << "Interlaced video not supported.";
- report_error_to_uma_cb_.Run(INTERLACED_STREAM);
- }
- }
- }
-}
-
-bool VaapiH264Decoder::FinishPicture() {
- DCHECK(curr_pic_.get());
-
- // Finish processing previous picture.
- // Start by storing previous reference picture data for later use,
- // if picture being finished is a reference picture.
- if (curr_pic_->ref) {
- ReferencePictureMarking();
- prev_ref_has_memmgmnt5_ = curr_pic_->mem_mgmt_5;
- prev_ref_top_field_order_cnt_ = curr_pic_->top_field_order_cnt;
- prev_ref_pic_order_cnt_msb_ = curr_pic_->pic_order_cnt_msb;
- prev_ref_pic_order_cnt_lsb_ = curr_pic_->pic_order_cnt_lsb;
- prev_ref_field_ = curr_pic_->field;
- }
- prev_has_memmgmnt5_ = curr_pic_->mem_mgmt_5;
- prev_frame_num_offset_ = curr_pic_->frame_num_offset;
-
- // Remove unused (for reference or later output) pictures from DPB, marking
- // them as such.
- for (H264DPB::Pictures::iterator it = dpb_.begin(); it != dpb_.end(); ++it) {
- if ((*it)->outputted && !(*it)->ref)
- UnassignSurfaceFromPoC((*it)->pic_order_cnt);
- }
- dpb_.DeleteUnused();
-
- DVLOG(4) << "Finishing picture, entries in DPB: " << dpb_.size();
-
- // Whatever happens below, curr_pic_ will stop managing the pointer to the
- // picture after this function returns. The ownership will either be
- // transferred to DPB, if the image is still needed (for output and/or
- // reference), or the memory will be released if we manage to output it here
- // without having to store it for future reference.
- scoped_ptr<H264Picture> pic(curr_pic_.release());
-
- // Get all pictures that haven't been outputted yet.
- H264Picture::PtrVector not_outputted;
- // TODO(posciak): pass as pointer, not reference (violates coding style).
- dpb_.GetNotOutputtedPicsAppending(not_outputted);
- // Include the one we've just decoded.
- not_outputted.push_back(pic.get());
-
- // Sort in output order.
- std::sort(not_outputted.begin(), not_outputted.end(), POCAscCompare());
-
- // Try to output as many pictures as we can. A picture can be output,
- // if the number of decoded and not yet outputted pictures that would remain
- // in DPB afterwards would at least be equal to max_num_reorder_frames.
- // If the outputted picture is not a reference picture, it doesn't have
- // to remain in the DPB and can be removed.
- H264Picture::PtrVector::iterator output_candidate = not_outputted.begin();
- size_t num_remaining = not_outputted.size();
- while (num_remaining > max_num_reorder_frames_) {
- int poc = (*output_candidate)->pic_order_cnt;
- DCHECK_GE(poc, last_output_poc_);
- if (!OutputPic(*output_candidate))
- return false;
-
- if (!(*output_candidate)->ref) {
- // Current picture hasn't been inserted into DPB yet, so don't remove it
- // if we managed to output it immediately.
- if (*output_candidate != pic)
- dpb_.DeleteByPOC(poc);
- // Mark as unused.
- UnassignSurfaceFromPoC(poc);
- }
-
- ++output_candidate;
- --num_remaining;
- }
-
- // If we haven't managed to output the picture that we just decoded, or if
- // it's a reference picture, we have to store it in DPB.
- if (!pic->outputted || pic->ref) {
- if (dpb_.IsFull()) {
- // If we haven't managed to output anything to free up space in DPB
- // to store this picture, it's an error in the stream.
- DVLOG(1) << "Could not free up space in DPB!";
- return false;
- }
-
- dpb_.StorePic(pic.release());
- }
-
- return true;
-}
-
-static int LevelToMaxDpbMbs(int level) {
- // See table A-1 in spec.
- switch (level) {
- case 10: return 396;
- case 11: return 900;
- case 12: // fallthrough
- case 13: // fallthrough
- case 20: return 2376;
- case 21: return 4752;
- case 22: // fallthrough
- case 30: return 8100;
- case 31: return 18000;
- case 32: return 20480;
- case 40: // fallthrough
- case 41: return 32768;
- case 42: return 34816;
- case 50: return 110400;
- case 51: // fallthrough
- case 52: return 184320;
- default:
- DVLOG(1) << "Invalid codec level (" << level << ")";
- return 0;
- }
-}
-
-bool VaapiH264Decoder::UpdateMaxNumReorderFrames(const media::H264SPS* sps) {
- if (sps->vui_parameters_present_flag && sps->bitstream_restriction_flag) {
- max_num_reorder_frames_ =
- base::checked_cast<size_t>(sps->max_num_reorder_frames);
- if (max_num_reorder_frames_ > dpb_.max_num_pics()) {
- DVLOG(1)
- << "max_num_reorder_frames present, but larger than MaxDpbFrames ("
- << max_num_reorder_frames_ << " > " << dpb_.max_num_pics() << ")";
- max_num_reorder_frames_ = 0;
- return false;
- }
- return true;
- }
-
- // max_num_reorder_frames not present, infer from profile/constraints
- // (see VUI semantics in spec).
- if (sps->constraint_set3_flag) {
- switch (sps->profile_idc) {
- case 44:
- case 86:
- case 100:
- case 110:
- case 122:
- case 244:
- max_num_reorder_frames_ = 0;
- break;
- default:
- max_num_reorder_frames_ = dpb_.max_num_pics();
- break;
- }
- } else {
- max_num_reorder_frames_ = dpb_.max_num_pics();
- }
-
- return true;
-}
-
-bool VaapiH264Decoder::ProcessSPS(int sps_id, bool* need_new_buffers) {
- const media::H264SPS* sps = parser_.GetSPS(sps_id);
- DCHECK(sps);
- DVLOG(4) << "Processing SPS";
-
- *need_new_buffers = false;
-
- if (sps->frame_mbs_only_flag == 0) {
- DVLOG(1) << "frame_mbs_only_flag != 1 not supported";
- report_error_to_uma_cb_.Run(FRAME_MBS_ONLY_FLAG_NOT_ONE);
- return false;
- }
-
- if (sps->gaps_in_frame_num_value_allowed_flag) {
- DVLOG(1) << "Gaps in frame numbers not supported";
- report_error_to_uma_cb_.Run(GAPS_IN_FRAME_NUM);
- return false;
- }
-
- curr_sps_id_ = sps->seq_parameter_set_id;
-
- // Calculate picture height/width in macroblocks and pixels
- // (spec 7.4.2.1.1, 7.4.3).
- int width_mb = sps->pic_width_in_mbs_minus1 + 1;
- int height_mb = (2 - sps->frame_mbs_only_flag) *
- (sps->pic_height_in_map_units_minus1 + 1);
-
- gfx::Size new_pic_size(16 * width_mb, 16 * height_mb);
- if (new_pic_size.IsEmpty()) {
- DVLOG(1) << "Invalid picture size: " << new_pic_size.ToString();
- return false;
- }
-
- if (!pic_size_.IsEmpty() && new_pic_size == pic_size_) {
- // Already have surfaces and this SPS keeps the same resolution,
- // no need to request a new set.
- return true;
- }
-
- pic_size_ = new_pic_size;
- DVLOG(1) << "New picture size: " << pic_size_.ToString();
-
- max_pic_order_cnt_lsb_ = 1 << (sps->log2_max_pic_order_cnt_lsb_minus4 + 4);
- max_frame_num_ = 1 << (sps->log2_max_frame_num_minus4 + 4);
-
- int level = sps->level_idc;
- int max_dpb_mbs = LevelToMaxDpbMbs(level);
- if (max_dpb_mbs == 0)
- return false;
-
- size_t max_dpb_size = std::min(max_dpb_mbs / (width_mb * height_mb),
- static_cast<int>(H264DPB::kDPBMaxSize));
- DVLOG(1) << "Codec level: " << level << ", DPB size: " << max_dpb_size;
- if (max_dpb_size == 0) {
- DVLOG(1) << "Invalid DPB Size";
- return false;
- }
-
- dpb_.set_max_num_pics(max_dpb_size);
-
- if (!UpdateMaxNumReorderFrames(sps))
- return false;
- DVLOG(1) << "max_num_reorder_frames: " << max_num_reorder_frames_;
-
- *need_new_buffers = true;
- return true;
-}
-
-bool VaapiH264Decoder::ProcessPPS(int pps_id) {
- const media::H264PPS* pps = parser_.GetPPS(pps_id);
- DCHECK(pps);
-
- curr_pps_id_ = pps->pic_parameter_set_id;
-
- return true;
-}
-
-bool VaapiH264Decoder::FinishPrevFrameIfPresent() {
- // If we already have a frame waiting to be decoded, decode it and finish.
- if (curr_pic_ != NULL) {
- if (!DecodePicture())
- return false;
- return FinishPicture();
- }
-
- return true;
-}
-
-bool VaapiH264Decoder::ProcessSlice(media::H264SliceHeader* slice_hdr) {
- prev_frame_num_ = frame_num_;
- frame_num_ = slice_hdr->frame_num;
-
- if (prev_frame_num_ > 0 && prev_frame_num_ < frame_num_ - 1) {
- DVLOG(1) << "Gap in frame_num!";
- report_error_to_uma_cb_.Run(GAPS_IN_FRAME_NUM);
- return false;
- }
-
- if (slice_hdr->field_pic_flag == 0)
- max_pic_num_ = max_frame_num_;
- else
- max_pic_num_ = 2 * max_frame_num_;
-
- // TODO posciak: switch to new picture detection per 7.4.1.2.4.
- if (curr_pic_ != NULL && slice_hdr->first_mb_in_slice != 0) {
- // This is just some more slice data of the current picture, so
- // just queue it and return.
- QueueSlice(slice_hdr);
- return true;
- } else {
- // A new frame, so first finish the previous one before processing it...
- if (!FinishPrevFrameIfPresent())
- return false;
-
- // and then start a new one.
- return StartNewFrame(slice_hdr);
- }
-}
-
-#define SET_ERROR_AND_RETURN() \
- do { \
- DVLOG(1) << "Error during decode"; \
- state_ = kError; \
- return VaapiH264Decoder::kDecodeError; \
- } while (0)
-
-void VaapiH264Decoder::SetStream(const uint8* ptr,
- size_t size,
- int32 input_id) {
- DCHECK(ptr);
- DCHECK(size);
-
- // Got new input stream data from the client.
- DVLOG(4) << "New input stream id: " << input_id << " at: " << (void*) ptr
- << " size: " << size;
- parser_.SetStream(ptr, size);
- curr_input_id_ = input_id;
-}
-
-VaapiH264Decoder::DecResult VaapiH264Decoder::Decode() {
- media::H264Parser::Result par_res;
- media::H264NALU nalu;
- DCHECK_NE(state_, kError);
-
- while (1) {
- // If we've already decoded some of the stream (after reset, i.e. we are
- // not in kNeedStreamMetadata state), we may be able to go back into
- // decoding state not only starting at/resuming from an SPS, but also from
- // other resume points, such as IDRs. In the latter case we need an output
- // surface, because we will end up decoding that IDR in the process.
- // Otherwise we just look for an SPS and don't produce any output frames.
- if (state_ != kNeedStreamMetadata && available_va_surfaces_.empty()) {
- DVLOG(4) << "No output surfaces available";
- return kRanOutOfSurfaces;
- }
-
- par_res = parser_.AdvanceToNextNALU(&nalu);
- if (par_res == media::H264Parser::kEOStream)
- return kRanOutOfStreamData;
- else if (par_res != media::H264Parser::kOk)
- SET_ERROR_AND_RETURN();
-
- DVLOG(4) << "NALU found: " << static_cast<int>(nalu.nal_unit_type);
-
- switch (nalu.nal_unit_type) {
- case media::H264NALU::kNonIDRSlice:
- // We can't resume from a non-IDR slice.
- if (state_ != kDecoding)
- break;
- // else fallthrough
- case media::H264NALU::kIDRSlice: {
- // TODO(posciak): the IDR may require an SPS that we don't have
- // available. For now we'd fail if that happens, but ideally we'd like
- // to keep going until the next SPS in the stream.
- if (state_ == kNeedStreamMetadata) {
- // We need an SPS, skip this IDR and keep looking.
- break;
- }
-
- // If after reset, we should be able to recover from an IDR.
- media::H264SliceHeader slice_hdr;
-
- par_res = parser_.ParseSliceHeader(nalu, &slice_hdr);
- if (par_res != media::H264Parser::kOk)
- SET_ERROR_AND_RETURN();
-
- if (!ProcessSlice(&slice_hdr))
- SET_ERROR_AND_RETURN();
-
- state_ = kDecoding;
- break;
- }
-
- case media::H264NALU::kSPS: {
- int sps_id;
-
- if (!FinishPrevFrameIfPresent())
- SET_ERROR_AND_RETURN();
-
- par_res = parser_.ParseSPS(&sps_id);
- if (par_res != media::H264Parser::kOk)
- SET_ERROR_AND_RETURN();
-
- bool need_new_buffers = false;
- if (!ProcessSPS(sps_id, &need_new_buffers))
- SET_ERROR_AND_RETURN();
-
- state_ = kDecoding;
-
- if (need_new_buffers) {
- if (!Flush())
- return kDecodeError;
-
- available_va_surfaces_.clear();
- return kAllocateNewSurfaces;
- }
- break;
- }
-
- case media::H264NALU::kPPS: {
- if (state_ != kDecoding)
- break;
-
- int pps_id;
-
- if (!FinishPrevFrameIfPresent())
- SET_ERROR_AND_RETURN();
-
- par_res = parser_.ParsePPS(&pps_id);
- if (par_res != media::H264Parser::kOk)
- SET_ERROR_AND_RETURN();
-
- if (!ProcessPPS(pps_id))
- SET_ERROR_AND_RETURN();
- break;
- }
-
- case media::H264NALU::kAUD:
- case media::H264NALU::kEOSeq:
- case media::H264NALU::kEOStream:
- if (state_ != kDecoding)
- break;
- if (!FinishPrevFrameIfPresent())
- SET_ERROR_AND_RETURN();
-
- break;
-
- default:
- DVLOG(4) << "Skipping NALU type: " << nalu.nal_unit_type;
- break;
- }
- }
-}
-
-size_t VaapiH264Decoder::GetRequiredNumOfPictures() {
- return dpb_.max_num_pics() + kPicsInPipeline;
-}
-
-} // namespace content
diff --git a/chromium/content/common/gpu/media/vaapi_h264_decoder.h b/chromium/content/common/gpu/media/vaapi_h264_decoder.h
deleted file mode 100644
index 914e37a1863..00000000000
--- a/chromium/content/common/gpu/media/vaapi_h264_decoder.h
+++ /dev/null
@@ -1,295 +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.
-//
-// This file contains an implementation of a class that provides H264 decode
-// support for use with VAAPI hardware video decode acceleration on Intel
-// systems.
-
-#ifndef CONTENT_COMMON_GPU_MEDIA_VAAPI_H264_DECODER_H_
-#define CONTENT_COMMON_GPU_MEDIA_VAAPI_H264_DECODER_H_
-
-#include <vector>
-
-#include "base/callback_forward.h"
-#include "base/memory/linked_ptr.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "content/common/gpu/media/h264_dpb.h"
-#include "content/common/gpu/media/vaapi_wrapper.h"
-#include "media/base/limits.h"
-#include "media/filters/h264_parser.h"
-
-namespace content {
-
-// An H264 decoder that utilizes VA-API. Provides features not supported by
-// the VA-API userspace library (libva), including stream parsing, reference
-// picture management and other operations not supported by the HW codec.
-//
-// Provides functionality to allow plugging VAAPI HW acceleration into the
-// VDA framework.
-//
-// Clients of this class are expected to pass H264 Annex-B byte stream and
-// will receive decoded surfaces via client-provided |OutputPicCB|.
-//
-// This class must be created, called and destroyed on a single thread, and
-// does nothing internally on any other thread.
-class CONTENT_EXPORT VaapiH264Decoder {
- public:
- // Callback invoked on the client when a surface is to be displayed.
- // Arguments: input buffer id provided at the time of Decode()
- // and VASurface to output.
- typedef base::Callback<
- void(int32, const scoped_refptr<VASurface>&)> OutputPicCB;
-
- enum VAVDAH264DecoderFailure {
- FRAME_MBS_ONLY_FLAG_NOT_ONE = 0,
- GAPS_IN_FRAME_NUM = 1,
- MID_STREAM_RESOLUTION_CHANGE = 2,
- INTERLACED_STREAM = 3,
- VAAPI_ERROR = 4,
- VAVDA_H264_DECODER_FAILURES_MAX,
- };
-
- // Callback to report errors for UMA purposes, not used to return errors
- // to clients.
- typedef base::Callback<void(VAVDAH264DecoderFailure error)>
- ReportErrorToUmaCB;
-
- // Decode result codes.
- enum DecResult {
- kDecodeError, // Error while decoding.
- // TODO posciak: unsupported streams are currently treated as error
- // in decoding; in future it could perhaps be possible to fall back
- // to software decoding instead.
- // kStreamError, // Error in stream.
- kAllocateNewSurfaces, // Need a new set of surfaces to be allocated.
- kRanOutOfStreamData, // Need more stream data to proceed.
- kRanOutOfSurfaces, // Waiting for the client to free up output surfaces.
- };
-
- // |vaapi_wrapper| should be initialized.
- // |output_pic_cb| notifies the client a surface is to be displayed.
- // |report_error_to_uma_cb| called on errors for UMA purposes, not used
- // to report errors to clients.
- VaapiH264Decoder(VaapiWrapper* vaapi_wrapper,
- const OutputPicCB& output_pic_cb,
- const ReportErrorToUmaCB& report_error_to_uma_cb);
-
- ~VaapiH264Decoder();
-
- // Have the decoder flush its state and trigger output of all previously
- // decoded surfaces via OutputPicCB. Return false on failure.
- bool Flush() WARN_UNUSED_RESULT;
-
- // To be called during decoding.
- // Stop (pause) decoding, discarding all remaining inputs and outputs,
- // but do not flush decoder state, so that the playback can be resumed later,
- // possibly from a different location.
- void Reset();
-
- // Set current stream data pointer to |ptr| and |size|. Output surfaces
- // that are decoded from data in this stream chunk are to be returned along
- // with the given |input_id|.
- void SetStream(const uint8* ptr, size_t size, int32 input_id);
-
- // Try to decode more of the stream, returning decoded frames asynchronously
- // via output_pic_cb_. Return when more stream is needed, when we run out
- // of free surfaces, when we need a new set of them, or when an error occurs.
- DecResult Decode() WARN_UNUSED_RESULT;
-
- // Return dimensions/required number of output surfaces that client should
- // be ready to provide for the decoder to function properly.
- // To be used after Decode() returns kNeedNewSurfaces.
- gfx::Size GetPicSize() { return pic_size_; }
- size_t GetRequiredNumOfPictures();
-
- // To be used by the client to feed decoder with output surfaces.
- void ReuseSurface(const scoped_refptr<VASurface>& va_surface);
-
- private:
- // We need to keep at most kDPBMaxSize pictures in DPB for
- // reference/to display later and an additional one for the one currently
- // being decoded. We also ask for some additional ones since VDA needs
- // to accumulate a few ready-to-output pictures before it actually starts
- // displaying and giving them back. +2 instead of +1 because of subjective
- // smoothness improvement during testing.
- enum {
- kPicsInPipeline = media::limits::kMaxVideoFrames + 2,
- kMaxNumReqPictures = H264DPB::kDPBMaxSize + kPicsInPipeline,
- };
-
- // Internal state of the decoder.
- enum State {
- kNeedStreamMetadata, // After initialization, need an SPS.
- kDecoding, // Ready to decode from any point.
- kAfterReset, // After Reset(), need a resume point.
- kError, // Error in decode, can't continue.
- };
-
- // Process H264 stream structures.
- bool ProcessSPS(int sps_id, bool* need_new_buffers);
- bool ProcessPPS(int pps_id);
- bool ProcessSlice(media::H264SliceHeader* slice_hdr);
-
- // Initialize the current picture according to data in |slice_hdr|.
- bool InitCurrPicture(media::H264SliceHeader* slice_hdr);
-
- // Calculate picture order counts for the new picture
- // on initialization of a new frame (see spec).
- bool CalculatePicOrderCounts(media::H264SliceHeader* slice_hdr);
-
- // Update PicNum values in pictures stored in DPB on creation of new
- // frame (see spec).
- void UpdatePicNums();
-
- bool UpdateMaxNumReorderFrames(const media::H264SPS* sps);
-
- // Prepare reference picture lists (ref_pic_list[01]_).
- bool PrepareRefPicLists(media::H264SliceHeader* slice_hdr);
-
- // Construct initial reference picture lists for use in decoding of
- // P and B pictures (see 8.2.4 in spec).
- void ConstructReferencePicListsP(media::H264SliceHeader* slice_hdr);
- void ConstructReferencePicListsB(media::H264SliceHeader* slice_hdr);
-
- // Helper functions for reference list construction, per spec.
- int PicNumF(H264Picture *pic);
- int LongTermPicNumF(H264Picture *pic);
-
- // Perform the reference picture lists' modification (reordering), as
- // specified in spec (8.2.4).
- //
- // |list| indicates list number and should be either 0 or 1.
- bool ModifyReferencePicList(media::H264SliceHeader* slice_hdr, int list);
-
- // Perform reference picture memory management operations (marking/unmarking
- // of reference pictures, long term picture management, discarding, etc.).
- // See 8.2.5 in spec.
- bool HandleMemoryManagementOps();
- void ReferencePictureMarking();
-
- // Start processing a new frame.
- bool StartNewFrame(media::H264SliceHeader* slice_hdr);
-
- // All data for a frame received, process it and decode.
- bool FinishPrevFrameIfPresent();
-
- // Called after decoding, performs all operations to be done after decoding,
- // including DPB management, reference picture marking and memory management
- // operations.
- // This will also output a picture if one is ready for output.
- bool FinishPicture();
-
- // Clear DPB contents and remove all surfaces in DPB from *in_use_ list.
- // Cleared pictures will be made available for decode, unless they are
- // at client waiting to be displayed.
- void ClearDPB();
-
- // These queue up data for HW decoder to be committed on running HW decode.
- bool SendPPS();
- bool SendIQMatrix();
- bool SendVASliceParam(media::H264SliceHeader* slice_hdr);
- bool SendSliceData(const uint8* ptr, size_t size);
- bool QueueSlice(media::H264SliceHeader* slice_hdr);
-
- // Helper methods for filling HW structures.
- void FillVAPicture(VAPictureH264 *va_pic, H264Picture* pic);
- int FillVARefFramesFromDPB(VAPictureH264 *va_pics, int num_pics);
-
- // Commits all pending data for HW decoder and starts HW decoder.
- bool DecodePicture();
-
- // Notifies client that a picture is ready for output.
- bool OutputPic(H264Picture* pic);
-
- // Output all pictures in DPB that have not been outputted yet.
- bool OutputAllRemainingPics();
-
- // Represents a frame being decoded. Will always have a VASurface
- // assigned to it, which will eventually contain decoded picture data.
- class DecodeSurface;
-
- // Assign an available surface to the given PicOrderCnt |poc|,
- // removing it from the available surfaces pool. Return true if a surface
- // has been found, false otherwise.
- bool AssignSurfaceToPoC(int32 input_id, int poc);
-
- // Indicate that a surface is no longer needed by decoder.
- void UnassignSurfaceFromPoC(int poc);
-
- // Return DecodeSurface assigned to |poc|.
- DecodeSurface* DecodeSurfaceByPoC(int poc);
-
- // Decoder state.
- State state_;
-
- // Parser in use.
- media::H264Parser parser_;
-
- // DPB in use.
- H264DPB dpb_;
-
- // Picture currently being processed/decoded.
- scoped_ptr<H264Picture> curr_pic_;
-
- // Reference picture lists, constructed for each picture before decoding.
- // Those lists are not owners of the pointers (DPB is).
- H264Picture::PtrVector ref_pic_list0_;
- H264Picture::PtrVector ref_pic_list1_;
-
- // Global state values, needed in decoding. See spec.
- int max_pic_order_cnt_lsb_;
- int max_frame_num_;
- int max_pic_num_;
- int max_long_term_frame_idx_;
- size_t max_num_reorder_frames_;
-
- int frame_num_;
- int prev_frame_num_;
- int prev_frame_num_offset_;
- bool prev_has_memmgmnt5_;
-
- // Values related to previously decoded reference picture.
- bool prev_ref_has_memmgmnt5_;
- int prev_ref_top_field_order_cnt_;
- int prev_ref_pic_order_cnt_msb_;
- int prev_ref_pic_order_cnt_lsb_;
- H264Picture::Field prev_ref_field_;
-
- // Currently active SPS and PPS.
- int curr_sps_id_;
- int curr_pps_id_;
-
- // Output picture size.
- gfx::Size pic_size_;
-
- // Maps H.264 PicOrderCount to currently used DecodeSurfaces;
- typedef std::map<int, linked_ptr<DecodeSurface> > DecSurfacesInUse;
- DecSurfacesInUse decode_surfaces_in_use_;
-
- // Unused VA surfaces returned by client, ready to be reused.
- std::vector<scoped_refptr<VASurface> > available_va_surfaces_;
-
- // The id of current input buffer, which will be associated with an
- // output surface when a frame is successfully decoded.
- int32 curr_input_id_;
-
- VaapiWrapper* vaapi_wrapper_;
-
- // Called by decoder when a surface should be outputted.
- OutputPicCB output_pic_cb_;
-
- // Called to report decoding error to UMA, not used to indicate errors
- // to clients.
- ReportErrorToUmaCB report_error_to_uma_cb_;
-
- // PicOrderCount of the previously outputted frame.
- int last_output_poc_;
-
- DISALLOW_COPY_AND_ASSIGN(VaapiH264Decoder);
-};
-
-} // namespace content
-
-#endif // CONTENT_COMMON_GPU_MEDIA_VAAPI_H264_DECODER_H_
diff --git a/chromium/content/common/gpu/media/vaapi_h264_decoder_unittest.cc b/chromium/content/common/gpu/media/vaapi_h264_decoder_unittest.cc
deleted file mode 100644
index 70d8220ddbe..00000000000
--- a/chromium/content/common/gpu/media/vaapi_h264_decoder_unittest.cc
+++ /dev/null
@@ -1,385 +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 <string>
-
-// This has to be included first.
-// See http://code.google.com/p/googletest/issues/detail?id=371
-#include "testing/gtest/include/gtest/gtest.h"
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/files/file_util.h"
-#include "base/logging.h"
-#include "content/common/gpu/media/vaapi_h264_decoder.h"
-#include "media/base/video_decoder_config.h"
-#include "third_party/libyuv/include/libyuv.h"
-
-// This program is run like this:
-// DISPLAY=:0 ./vaapi_h264_decoder_unittest --input_file input.h264
-// [--output_file output.i420] [--md5sum expected_md5_hex]
-//
-// The input is read from input.h264. The output is written to output.i420 if it
-// is given. It also verifies the MD5 sum of the decoded I420 data if the
-// expected MD5 sum is given.
-
-namespace content {
-namespace {
-
-// These are the command line parameters
-base::FilePath g_input_file;
-base::FilePath g_output_file;
-std::string g_md5sum;
-
-// These default values are used if nothing is specified in the command line.
-const base::FilePath::CharType* kDefaultInputFile =
- FILE_PATH_LITERAL("test-25fps.h264");
-const char* kDefaultMD5Sum = "3af866863225b956001252ebeccdb71d";
-
-// This class encapsulates the use of VaapiH264Decoder to a simpler interface.
-// It reads an H.264 Annex B bytestream from a file and outputs the decoded
-// frames (in I420 format) to another file. The output file can be played by
-// $ mplayer test_dec.yuv -demuxer rawvideo -rawvideo w=1920:h=1080
-//
-// To use the class, construct an instance, call Initialize() to specify the
-// input and output file paths, then call Run() to decode the whole stream and
-// output the frames.
-//
-// This class must be created, called and destroyed on a single thread, and
-// does nothing internally on any other thread.
-class VaapiH264DecoderLoop {
- public:
- VaapiH264DecoderLoop();
- ~VaapiH264DecoderLoop();
-
- // Initialize the decoder. Return true if successful.
- bool Initialize(base::FilePath input_file, base::FilePath output_file);
-
- // Run the decode loop. The decoded data is written to the file specified by
- // output_file in Initialize(). Return true if all decoding is successful.
- bool Run();
-
- // Get the MD5 sum of the decoded data.
- std::string GetMD5Sum();
-
- private:
- // Callback from the decoder when a picture is decoded.
- void OutputPicture(int32 input_id,
- const scoped_refptr<VASurface>& va_surface);
-
- // Recycle one surface and put it on available_surfaces_ list.
- void RecycleSurface(VASurfaceID va_surface_id);
-
- // Give all surfaces in available_surfaces_ to the decoder.
- void RefillSurfaces();
-
- // Free the current set of surfaces and allocate a new set of
- // surfaces. Returns true when successful.
- bool AllocateNewSurfaces();
-
- // Use the data in the frame: write to file and update MD5 sum.
- bool ProcessVideoFrame(const scoped_refptr<media::VideoFrame>& frame);
-
- scoped_ptr<VaapiWrapper> wrapper_;
- scoped_ptr<VaapiH264Decoder> decoder_;
- std::string data_; // data read from input_file
- base::FilePath output_file_; // output data is written to this file
- std::vector<VASurfaceID> available_surfaces_;
-
- // These members (x_display_, num_outputted_pictures_, num_surfaces_)
- // need to be initialized and possibly freed manually.
- Display* x_display_;
- int num_outputted_pictures_; // number of pictures already outputted
- size_t num_surfaces_; // number of surfaces in the current set of surfaces
- base::MD5Context md5_context_;
-};
-
-VaapiH264DecoderLoop::VaapiH264DecoderLoop()
- : x_display_(NULL), num_outputted_pictures_(0), num_surfaces_(0) {
- base::MD5Init(&md5_context_);
-}
-
-VaapiH264DecoderLoop::~VaapiH264DecoderLoop() {
- // We need to destruct decoder and wrapper first because:
- // (1) The decoder has a reference to the wrapper.
- // (2) The wrapper has a reference to x_display_.
- decoder_.reset();
- wrapper_.reset();
-
- if (x_display_) {
- XCloseDisplay(x_display_);
- }
-}
-
-void LogOnError(VaapiH264Decoder::VAVDAH264DecoderFailure error) {
- LOG(FATAL) << "Oh noes! Decoder failed: " << error;
-}
-
-bool VaapiH264DecoderLoop::Initialize(base::FilePath input_file,
- base::FilePath output_file) {
- x_display_ = XOpenDisplay(NULL);
- if (!x_display_) {
- LOG(ERROR) << "Can't open X display";
- return false;
- }
-
- media::VideoCodecProfile profile = media::H264PROFILE_BASELINE;
- base::Closure report_error_cb =
- base::Bind(&LogOnError, VaapiH264Decoder::VAAPI_ERROR);
- wrapper_ = VaapiWrapper::Create(
- VaapiWrapper::kDecode, profile, x_display_, report_error_cb);
- if (!wrapper_.get()) {
- LOG(ERROR) << "Can't create vaapi wrapper";
- return false;
- }
-
- decoder_.reset(new VaapiH264Decoder(
- wrapper_.get(),
- base::Bind(&VaapiH264DecoderLoop::OutputPicture, base::Unretained(this)),
- base::Bind(&LogOnError)));
-
- if (!base::ReadFileToString(input_file, &data_)) {
- LOG(ERROR) << "failed to read input data from " << input_file.value();
- return false;
- }
-
- const int input_id = 0; // We don't use input_id in this class.
- decoder_->SetStream(
- reinterpret_cast<const uint8*>(data_.c_str()), data_.size(), input_id);
-
- // This creates or truncates output_file.
- // Without it, AppendToFile() will not work.
- if (!output_file.empty()) {
- if (base::WriteFile(output_file, NULL, 0) != 0) {
- return false;
- }
- output_file_ = output_file;
- }
-
- return true;
-}
-
-bool VaapiH264DecoderLoop::Run() {
- while (1) {
- switch (decoder_->Decode()) {
- case VaapiH264Decoder::kDecodeError:
- LOG(ERROR) << "Decode Error";
- return false;
- case VaapiH264Decoder::kAllocateNewSurfaces:
- VLOG(1) << "Allocate new surfaces";
- if (!AllocateNewSurfaces()) {
- LOG(ERROR) << "Failed to allocate new surfaces";
- return false;
- }
- break;
- case VaapiH264Decoder::kRanOutOfStreamData: {
- bool rc = decoder_->Flush();
- VLOG(1) << "Flush returns " << rc;
- return rc;
- }
- case VaapiH264Decoder::kRanOutOfSurfaces:
- VLOG(1) << "Ran out of surfaces";
- RefillSurfaces();
- break;
- }
- }
-}
-
-std::string VaapiH264DecoderLoop::GetMD5Sum() {
- base::MD5Digest digest;
- base::MD5Final(&digest, &md5_context_);
- return MD5DigestToBase16(digest);
-}
-
-scoped_refptr<media::VideoFrame> CopyNV12ToI420(VAImage* image, void* mem) {
- int width = image->width;
- int height = image->height;
-
- DVLOG(1) << "CopyNV12ToI420 width=" << width << ", height=" << height;
-
- const gfx::Size coded_size(width, height);
- const gfx::Rect visible_rect(width, height);
- const gfx::Size natural_size(width, height);
-
- scoped_refptr<media::VideoFrame> frame =
- media::VideoFrame::CreateFrame(media::VideoFrame::I420,
- coded_size,
- visible_rect,
- natural_size,
- base::TimeDelta());
-
- uint8_t* mem_byte_ptr = static_cast<uint8_t*>(mem);
- uint8_t* src_y = mem_byte_ptr + image->offsets[0];
- uint8_t* src_uv = mem_byte_ptr + image->offsets[1];
- int src_stride_y = image->pitches[0];
- int src_stride_uv = image->pitches[1];
-
- uint8_t* dst_y = frame->data(media::VideoFrame::kYPlane);
- uint8_t* dst_u = frame->data(media::VideoFrame::kUPlane);
- uint8_t* dst_v = frame->data(media::VideoFrame::kVPlane);
- int dst_stride_y = frame->stride(media::VideoFrame::kYPlane);
- int dst_stride_u = frame->stride(media::VideoFrame::kUPlane);
- int dst_stride_v = frame->stride(media::VideoFrame::kVPlane);
-
- int rc = libyuv::NV12ToI420(src_y,
- src_stride_y,
- src_uv,
- src_stride_uv,
- dst_y,
- dst_stride_y,
- dst_u,
- dst_stride_u,
- dst_v,
- dst_stride_v,
- width,
- height);
- CHECK_EQ(0, rc);
- return frame;
-}
-
-bool VaapiH264DecoderLoop::ProcessVideoFrame(
- const scoped_refptr<media::VideoFrame>& frame) {
- frame->HashFrameForTesting(&md5_context_);
-
- if (output_file_.empty())
- return true;
-
- for (size_t i = 0; i < media::VideoFrame::NumPlanes(frame->format()); i++) {
- int to_write = media::VideoFrame::PlaneAllocationSize(
- frame->format(), i, frame->coded_size());
- const char* buf = reinterpret_cast<const char*>(frame->data(i));
- if (!base::AppendToFile(output_file_, buf, to_write))
- return false;
- }
- return true;
-}
-
-void VaapiH264DecoderLoop::OutputPicture(
- int32 input_id,
- const scoped_refptr<VASurface>& va_surface) {
- VLOG(1) << "OutputPicture: picture " << num_outputted_pictures_++;
-
- VAImage image;
- void* mem;
-
- if (!wrapper_->GetVaImageForTesting(va_surface->id(), &image, &mem)) {
- LOG(ERROR) << "Cannot get VAImage.";
- return;
- }
-
- if (image.format.fourcc != VA_FOURCC_NV12) {
- LOG(ERROR) << "Unexpected image format: " << image.format.fourcc;
- wrapper_->ReturnVaImageForTesting(&image);
- return;
- }
-
- // Convert NV12 to I420 format.
- scoped_refptr<media::VideoFrame> frame = CopyNV12ToI420(&image, mem);
-
- if (frame.get()) {
- if (!ProcessVideoFrame(frame)) {
- LOG(ERROR) << "Write to file failed";
- }
- } else {
- LOG(ERROR) << "Cannot convert image to I420.";
- }
-
- wrapper_->ReturnVaImageForTesting(&image);
-}
-
-void VaapiH264DecoderLoop::RecycleSurface(VASurfaceID va_surface_id) {
- available_surfaces_.push_back(va_surface_id);
-}
-
-void VaapiH264DecoderLoop::RefillSurfaces() {
- for (size_t i = 0; i < available_surfaces_.size(); i++) {
- VASurface::ReleaseCB release_cb = base::Bind(
- &VaapiH264DecoderLoop::RecycleSurface, base::Unretained(this));
- scoped_refptr<VASurface> surface(
- new VASurface(available_surfaces_[i], release_cb));
- decoder_->ReuseSurface(surface);
- }
- available_surfaces_.clear();
-}
-
-bool VaapiH264DecoderLoop::AllocateNewSurfaces() {
- CHECK_EQ(num_surfaces_, available_surfaces_.size())
- << "not all surfaces are returned";
-
- available_surfaces_.clear();
- wrapper_->DestroySurfaces();
-
- gfx::Size size = decoder_->GetPicSize();
- num_surfaces_ = decoder_->GetRequiredNumOfPictures();
- return wrapper_->CreateSurfaces(size, num_surfaces_, &available_surfaces_);
-}
-
-TEST(VaapiH264DecoderTest, TestDecode) {
- base::FilePath input_file = g_input_file;
- base::FilePath output_file = g_output_file;
- std::string md5sum = g_md5sum;
-
- // If nothing specified, use the default file in the source tree.
- if (input_file.empty() && output_file.empty() && md5sum.empty()) {
- input_file = base::FilePath(kDefaultInputFile);
- md5sum = kDefaultMD5Sum;
- } else {
- ASSERT_FALSE(input_file.empty()) << "Need to specify --input_file";
- }
-
- VLOG(1) << "Input File: " << input_file.value();
- VLOG(1) << "Output File: " << output_file.value();
- VLOG(1) << "Expected MD5 sum: " << md5sum;
-
- content::VaapiH264DecoderLoop loop;
- ASSERT_TRUE(loop.Initialize(input_file, output_file))
- << "initialize decoder loop failed";
- ASSERT_TRUE(loop.Run()) << "run decoder loop failed";
-
- if (!md5sum.empty()) {
- std::string actual = loop.GetMD5Sum();
- VLOG(1) << "Actual MD5 sum: " << actual;
- EXPECT_EQ(md5sum, actual);
- }
-}
-
-} // namespace
-} // namespace content
-
-int main(int argc, char** argv) {
- testing::InitGoogleTest(&argc, argv); // Removes gtest-specific args.
- base::CommandLine::Init(argc, argv);
-
- // Needed to enable DVLOG through --vmodule.
- logging::LoggingSettings settings;
- settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
- CHECK(logging::InitLogging(settings));
-
- // Process command line.
- base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
- CHECK(cmd_line);
-
- base::CommandLine::SwitchMap switches = cmd_line->GetSwitches();
- for (base::CommandLine::SwitchMap::const_iterator it = switches.begin();
- it != switches.end();
- ++it) {
- if (it->first == "input_file") {
- content::g_input_file = base::FilePath(it->second);
- continue;
- }
- if (it->first == "output_file") {
- content::g_output_file = base::FilePath(it->second);
- continue;
- }
- if (it->first == "md5sum") {
- content::g_md5sum = it->second;
- continue;
- }
- if (it->first == "v" || it->first == "vmodule")
- continue;
- LOG(FATAL) << "Unexpected switch: " << it->first << ":" << it->second;
- }
-
- return RUN_ALL_TESTS();
-}
diff --git a/chromium/content/common/gpu/media/vaapi_jpeg_decoder.cc b/chromium/content/common/gpu/media/vaapi_jpeg_decoder.cc
new file mode 100644
index 00000000000..416bb093e91
--- /dev/null
+++ b/chromium/content/common/gpu/media/vaapi_jpeg_decoder.cc
@@ -0,0 +1,303 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/common/gpu/media/vaapi_jpeg_decoder.h"
+
+#include "base/logging.h"
+#include "media/filters/jpeg_parser.h"
+
+namespace {
+
+// K.3.3.1 "Specification of typical tables for DC difference coding"
+media::JpegHuffmanTable
+ kDefaultDcTable[media::kJpegMaxHuffmanTableNumBaseline] = {
+ // luminance DC coefficients
+ {
+ true,
+ {0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0},
+ {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b},
+ },
+ // chrominance DC coefficients
+ {
+ true,
+ {0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb},
+ },
+};
+
+// K.3.3.2 "Specification of typical tables for AC coefficient coding"
+media::JpegHuffmanTable
+ kDefaultAcTable[media::kJpegMaxHuffmanTableNumBaseline] = {
+ // luminance AC coefficients
+ {
+ true,
+ {0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d},
+ {0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
+ 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
+ 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
+ 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+ 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
+ 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+ 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+ 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+ 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+ 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+ 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+ 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+ 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
+ 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+ 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
+ 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa},
+ },
+ // chrominance AC coefficients
+ {
+ true,
+ {0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77},
+ {0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
+ 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
+ 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+ 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
+ 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
+ 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
+ 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
+ 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+ 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
+ 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+ 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
+ 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
+ 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
+ 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
+ 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+ 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa},
+ },
+};
+
+} // namespace
+
+namespace content {
+
+// VAAPI only support subset of JPEG profiles. This function determines a given
+// parsed JPEG result is supported or not.
+static bool IsVaapiSupportedJpeg(const media::JpegParseResult& jpeg) {
+ if (jpeg.frame_header.visible_width < 1 ||
+ jpeg.frame_header.visible_height < 1) {
+ DLOG(ERROR) << "width(" << jpeg.frame_header.visible_width
+ << ") and height(" << jpeg.frame_header.visible_height
+ << ") should be at least 1";
+ return false;
+ }
+
+ // Size 64k*64k is the maximum in the JPEG standard. VAAPI doesn't support
+ // resolutions larger than 16k*16k.
+ const int kMaxDimension = 16384;
+ if (jpeg.frame_header.coded_width > kMaxDimension ||
+ jpeg.frame_header.coded_height > kMaxDimension) {
+ DLOG(ERROR) << "VAAPI doesn't support size("
+ << jpeg.frame_header.coded_width << "*"
+ << jpeg.frame_header.coded_height << ") larger than "
+ << kMaxDimension << "*" << kMaxDimension;
+ return false;
+ }
+
+ if (jpeg.frame_header.num_components != 3) {
+ DLOG(ERROR) << "VAAPI doesn't support num_components("
+ << static_cast<int>(jpeg.frame_header.num_components)
+ << ") != 3";
+ return false;
+ }
+
+ if (jpeg.frame_header.components[0].horizontal_sampling_factor <
+ jpeg.frame_header.components[1].horizontal_sampling_factor ||
+ jpeg.frame_header.components[0].horizontal_sampling_factor <
+ jpeg.frame_header.components[2].horizontal_sampling_factor) {
+ DLOG(ERROR) << "VAAPI doesn't supports horizontal sampling factor of Y"
+ << " smaller than Cb and Cr";
+ return false;
+ }
+
+ if (jpeg.frame_header.components[0].vertical_sampling_factor <
+ jpeg.frame_header.components[1].vertical_sampling_factor ||
+ jpeg.frame_header.components[0].vertical_sampling_factor <
+ jpeg.frame_header.components[2].vertical_sampling_factor) {
+ DLOG(ERROR) << "VAAPI doesn't supports vertical sampling factor of Y"
+ << " smaller than Cb and Cr";
+ return false;
+ }
+
+ return true;
+}
+
+static void FillPictureParameters(
+ const media::JpegFrameHeader& frame_header,
+ VAPictureParameterBufferJPEGBaseline* pic_param) {
+ memset(pic_param, 0, sizeof(*pic_param));
+ pic_param->picture_width = frame_header.coded_width;
+ pic_param->picture_height = frame_header.coded_height;
+ pic_param->num_components = frame_header.num_components;
+
+ for (int i = 0; i < pic_param->num_components; i++) {
+ pic_param->components[i].component_id = frame_header.components[i].id;
+ pic_param->components[i].h_sampling_factor =
+ frame_header.components[i].horizontal_sampling_factor;
+ pic_param->components[i].v_sampling_factor =
+ frame_header.components[i].vertical_sampling_factor;
+ pic_param->components[i].quantiser_table_selector =
+ frame_header.components[i].quantization_table_selector;
+ }
+}
+
+static void FillIQMatrix(const media::JpegQuantizationTable* q_table,
+ VAIQMatrixBufferJPEGBaseline* iq_matrix) {
+ memset(iq_matrix, 0, sizeof(*iq_matrix));
+ static_assert(media::kJpegMaxQuantizationTableNum ==
+ arraysize(iq_matrix->load_quantiser_table),
+ "max number of quantization table mismatched");
+ for (size_t i = 0; i < media::kJpegMaxQuantizationTableNum; i++) {
+ if (!q_table[i].valid)
+ continue;
+ iq_matrix->load_quantiser_table[i] = 1;
+ static_assert(
+ arraysize(iq_matrix->quantiser_table[i]) == arraysize(q_table[i].value),
+ "number of quantization entries mismatched");
+ for (size_t j = 0; j < arraysize(q_table[i].value); j++)
+ iq_matrix->quantiser_table[i][j] = q_table[i].value[j];
+ }
+}
+
+static void FillHuffmanTable(const media::JpegHuffmanTable* dc_table,
+ const media::JpegHuffmanTable* ac_table,
+ VAHuffmanTableBufferJPEGBaseline* huffman_table) {
+ memset(huffman_table, 0, sizeof(*huffman_table));
+ // Use default huffman tables if not specified in header.
+ bool has_huffman_table = false;
+ for (size_t i = 0; i < media::kJpegMaxHuffmanTableNumBaseline; i++) {
+ if (dc_table[i].valid || ac_table[i].valid) {
+ has_huffman_table = true;
+ break;
+ }
+ }
+ if (!has_huffman_table) {
+ dc_table = kDefaultDcTable;
+ ac_table = kDefaultAcTable;
+ }
+
+ static_assert(media::kJpegMaxHuffmanTableNumBaseline ==
+ arraysize(huffman_table->load_huffman_table),
+ "max number of huffman table mismatched");
+ static_assert(sizeof(huffman_table->huffman_table[0].num_dc_codes) ==
+ sizeof(dc_table[0].code_length),
+ "size of huffman table code length mismatch");
+ static_assert(sizeof(huffman_table->huffman_table[0].dc_values[0]) ==
+ sizeof(dc_table[0].code_value[0]),
+ "size of huffman table code value mismatch");
+ for (size_t i = 0; i < media::kJpegMaxHuffmanTableNumBaseline; i++) {
+ if (!dc_table[i].valid || !ac_table[i].valid)
+ continue;
+ huffman_table->load_huffman_table[i] = 1;
+
+ memcpy(huffman_table->huffman_table[i].num_dc_codes,
+ dc_table[i].code_length,
+ sizeof(huffman_table->huffman_table[i].num_dc_codes));
+ memcpy(huffman_table->huffman_table[i].dc_values, dc_table[i].code_value,
+ sizeof(huffman_table->huffman_table[i].dc_values));
+ memcpy(huffman_table->huffman_table[i].num_ac_codes,
+ ac_table[i].code_length,
+ sizeof(huffman_table->huffman_table[i].num_ac_codes));
+ memcpy(huffman_table->huffman_table[i].ac_values, ac_table[i].code_value,
+ sizeof(huffman_table->huffman_table[i].ac_values));
+ }
+}
+
+static void FillSliceParameters(
+ const media::JpegParseResult& parse_result,
+ VASliceParameterBufferJPEGBaseline* slice_param) {
+ memset(slice_param, 0, sizeof(*slice_param));
+ slice_param->slice_data_size = parse_result.data_size;
+ slice_param->slice_data_offset = 0;
+ slice_param->slice_data_flag = VA_SLICE_DATA_FLAG_ALL;
+ slice_param->slice_horizontal_position = 0;
+ slice_param->slice_vertical_position = 0;
+ slice_param->num_components = parse_result.scan.num_components;
+ for (int i = 0; i < slice_param->num_components; i++) {
+ slice_param->components[i].component_selector =
+ parse_result.scan.components[i].component_selector;
+ slice_param->components[i].dc_table_selector =
+ parse_result.scan.components[i].dc_selector;
+ slice_param->components[i].ac_table_selector =
+ parse_result.scan.components[i].ac_selector;
+ }
+ slice_param->restart_interval = parse_result.restart_interval;
+
+ // Cast to int to prevent overflow.
+ int max_h_factor =
+ parse_result.frame_header.components[0].horizontal_sampling_factor;
+ int max_v_factor =
+ parse_result.frame_header.components[0].vertical_sampling_factor;
+ int mcu_cols = parse_result.frame_header.coded_width / (max_h_factor * 8);
+ DCHECK_GT(mcu_cols, 0);
+ int mcu_rows = parse_result.frame_header.coded_height / (max_v_factor * 8);
+ DCHECK_GT(mcu_rows, 0);
+ slice_param->num_mcus = mcu_rows * mcu_cols;
+}
+
+// static
+bool VaapiJpegDecoder::Decode(VaapiWrapper* vaapi_wrapper,
+ const media::JpegParseResult& parse_result,
+ VASurfaceID va_surface) {
+ DCHECK_NE(va_surface, VA_INVALID_SURFACE);
+ if (!IsVaapiSupportedJpeg(parse_result))
+ return false;
+
+ // Set picture parameters.
+ VAPictureParameterBufferJPEGBaseline pic_param;
+ FillPictureParameters(parse_result.frame_header, &pic_param);
+ if (!vaapi_wrapper->SubmitBuffer(VAPictureParameterBufferType,
+ sizeof(pic_param), &pic_param))
+ return false;
+
+ // Set quantization table.
+ VAIQMatrixBufferJPEGBaseline iq_matrix;
+ FillIQMatrix(parse_result.q_table, &iq_matrix);
+ if (!vaapi_wrapper->SubmitBuffer(VAIQMatrixBufferType, sizeof(iq_matrix),
+ &iq_matrix))
+ return false;
+
+ // Set huffman table.
+ VAHuffmanTableBufferJPEGBaseline huffman_table;
+ FillHuffmanTable(parse_result.dc_table, parse_result.ac_table,
+ &huffman_table);
+ if (!vaapi_wrapper->SubmitBuffer(VAHuffmanTableBufferType,
+ sizeof(huffman_table), &huffman_table))
+ return false;
+
+ // Set slice parameters.
+ VASliceParameterBufferJPEGBaseline slice_param;
+ FillSliceParameters(parse_result, &slice_param);
+ if (!vaapi_wrapper->SubmitBuffer(VASliceParameterBufferType,
+ sizeof(slice_param), &slice_param))
+ return false;
+
+ // Set scan data.
+ if (!vaapi_wrapper->SubmitBuffer(VASliceDataBufferType,
+ parse_result.data_size,
+ const_cast<char*>(parse_result.data)))
+ return false;
+
+ if (!vaapi_wrapper->ExecuteAndDestroyPendingBuffers(va_surface))
+ return false;
+
+ return true;
+}
+
+} // namespace content
diff --git a/chromium/content/common/gpu/media/vaapi_jpeg_decoder.h b/chromium/content/common/gpu/media/vaapi_jpeg_decoder.h
new file mode 100644
index 00000000000..30400164e7e
--- /dev/null
+++ b/chromium/content/common/gpu/media/vaapi_jpeg_decoder.h
@@ -0,0 +1,45 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_COMMON_GPU_MEDIA_VAAPI_JPEG_DECODER_H_
+#define CONTENT_COMMON_GPU_MEDIA_VAAPI_JPEG_DECODER_H_
+
+#include "base/macros.h"
+#include "content/common/content_export.h"
+#include "content/common/gpu/media/vaapi_wrapper.h"
+
+namespace media {
+struct JpegParseResult;
+} // namespace media
+
+namespace content {
+
+// A JPEG decoder that utilizes VA-API hardware video decode acceleration on
+// Intel systems. Provides functionality to allow plugging VAAPI HW
+// acceleration into the JpegDecodeAccelerator framework.
+//
+// Clients of this class are expected to manage VA surfaces created via
+// VaapiWrapper, parse JPEG picture via media::ParseJpegPicture, and then pass
+// them to this class.
+class CONTENT_EXPORT VaapiJpegDecoder {
+ public:
+ // Decode a JPEG picture. It will fill VA-API parameters and call
+ // corresponding VA-API methods according to parsed JPEG result
+ // |parse_result|. Decoded data will be outputted to the given |va_surface|.
+ // Return false on failure.
+ // |vaapi_wrapper| should be initialized in kDecode mode with
+ // VAProfileJPEGBaseline profile.
+ // |va_surface| should be created with size at least as large as the picture
+ // size.
+ static bool Decode(VaapiWrapper* vaapi_wrapper,
+ const media::JpegParseResult& parse_result,
+ VASurfaceID va_surface);
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(VaapiJpegDecoder);
+};
+
+} // namespace content
+
+#endif // CONTENT_COMMON_GPU_MEDIA_VAAPI_JPEG_DECODER_H_
diff --git a/chromium/content/common/gpu/media/vaapi_jpeg_decoder_unittest.cc b/chromium/content/common/gpu/media/vaapi_jpeg_decoder_unittest.cc
new file mode 100644
index 00000000000..70f4edff53f
--- /dev/null
+++ b/chromium/content/common/gpu/media/vaapi_jpeg_decoder_unittest.cc
@@ -0,0 +1,136 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+// This has to be included first.
+// See http://code.google.com/p/googletest/issues/detail?id=371
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include "base/at_exit.h"
+#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/md5.h"
+#include "base/path_service.h"
+#include "base/strings/string_piece.h"
+#include "content/common/gpu/media/vaapi_jpeg_decoder.h"
+#include "media/base/test_data_util.h"
+#include "media/base/video_frame.h"
+#include "media/filters/jpeg_parser.h"
+
+namespace content {
+namespace {
+
+const char* kTestFilename = "pixel-1280x720.jpg";
+const char* kExpectedMd5Sum = "6e9e1716073c9a9a1282e3f0e0dab743";
+
+void LogOnError() {
+ LOG(FATAL) << "Oh noes! Decoder failed";
+}
+
+class VaapiJpegDecoderTest : public ::testing::Test {
+ protected:
+ VaapiJpegDecoderTest() {}
+
+ void SetUp() override {
+ base::Closure report_error_cb = base::Bind(&LogOnError);
+ wrapper_ = VaapiWrapper::Create(VaapiWrapper::kDecode,
+ VAProfileJPEGBaseline, report_error_cb);
+ ASSERT_TRUE(wrapper_);
+
+ base::FilePath input_file = media::GetTestDataFilePath(kTestFilename);
+
+ ASSERT_TRUE(base::ReadFileToString(input_file, &jpeg_data_))
+ << "failed to read input data from " << input_file.value();
+ }
+
+ void TearDown() override { wrapper_.reset(); }
+
+ bool VerifyDecode(const media::JpegParseResult& parse_result,
+ const std::string& md5sum);
+
+ protected:
+ scoped_ptr<VaapiWrapper> wrapper_;
+ std::string jpeg_data_;
+};
+
+bool VaapiJpegDecoderTest::VerifyDecode(
+ const media::JpegParseResult& parse_result,
+ const std::string& expected_md5sum) {
+ gfx::Size size(parse_result.frame_header.coded_width,
+ parse_result.frame_header.coded_height);
+
+ std::vector<VASurfaceID> va_surfaces;
+ if (!wrapper_->CreateSurfaces(size, 1, &va_surfaces))
+ return false;
+
+ if (!VaapiJpegDecoder::Decode(wrapper_.get(), parse_result, va_surfaces[0])) {
+ LOG(ERROR) << "Decode failed";
+ return false;
+ }
+
+ VAImage image;
+ VAImageFormat format;
+ const uint32_t kI420Fourcc = VA_FOURCC('I', '4', '2', '0');
+ memset(&image, 0, sizeof(image));
+ memset(&format, 0, sizeof(format));
+ format.fourcc = kI420Fourcc;
+ format.byte_order = VA_LSB_FIRST;
+ format.bits_per_pixel = 12; // 12 for I420
+
+ void* mem;
+ if (!wrapper_->GetVaImage(va_surfaces[0], &format, size, &image, &mem)) {
+ LOG(ERROR) << "Cannot get VAImage";
+ return false;
+ }
+ EXPECT_EQ(kI420Fourcc, image.format.fourcc);
+
+ base::StringPiece result(
+ reinterpret_cast<const char*>(mem),
+ media::VideoFrame::AllocationSize(media::VideoFrame::I420, size));
+ EXPECT_EQ(expected_md5sum, base::MD5String(result));
+
+ wrapper_->ReturnVaImage(&image);
+
+ return true;
+}
+
+TEST_F(VaapiJpegDecoderTest, DecodeSuccess) {
+ media::JpegParseResult parse_result;
+ ASSERT_TRUE(media::ParseJpegPicture(
+ reinterpret_cast<const uint8_t*>(jpeg_data_.data()), jpeg_data_.size(),
+ &parse_result));
+
+ EXPECT_TRUE(VerifyDecode(parse_result, kExpectedMd5Sum));
+}
+
+TEST_F(VaapiJpegDecoderTest, DecodeFail) {
+ media::JpegParseResult parse_result;
+ ASSERT_TRUE(media::ParseJpegPicture(
+ reinterpret_cast<const uint8_t*>(jpeg_data_.data()), jpeg_data_.size(),
+ &parse_result));
+
+ // Not supported by VAAPI.
+ parse_result.frame_header.num_components = 1;
+ parse_result.scan.num_components = 1;
+
+ gfx::Size size(parse_result.frame_header.coded_width,
+ parse_result.frame_header.coded_height);
+
+ std::vector<VASurfaceID> va_surfaces;
+ ASSERT_TRUE(wrapper_->CreateSurfaces(size, 1, &va_surfaces));
+
+ EXPECT_FALSE(
+ VaapiJpegDecoder::Decode(wrapper_.get(), parse_result, va_surfaces[0]));
+}
+
+} // namespace
+} // namespace content
+
+int main(int argc, char** argv) {
+ testing::InitGoogleTest(&argc, argv);
+ base::AtExitManager exit_manager;
+ return RUN_ALL_TESTS();
+}
diff --git a/chromium/content/common/gpu/media/vaapi_picture.cc b/chromium/content/common/gpu/media/vaapi_picture.cc
new file mode 100644
index 00000000000..cd886c06ebf
--- /dev/null
+++ b/chromium/content/common/gpu/media/vaapi_picture.cc
@@ -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.
+
+#include "content/common/gpu/media/vaapi_picture.h"
+#include "content/common/gpu/media/vaapi_wrapper.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_implementation.h"
+
+#if defined(USE_X11)
+#include "content/common/gpu/media/vaapi_tfp_picture.h"
+#elif defined(USE_OZONE)
+#include "content/common/gpu/media/vaapi_drm_picture.h"
+#endif
+
+namespace content {
+
+// static
+linked_ptr<VaapiPicture> VaapiPicture::CreatePicture(
+ VaapiWrapper* vaapi_wrapper,
+ const base::Callback<bool(void)> make_context_current,
+ int32 picture_buffer_id,
+ uint32 texture_id,
+ const gfx::Size& size) {
+ linked_ptr<VaapiPicture> picture;
+#if defined(USE_X11)
+ picture.reset(new VaapiTFPPicture(vaapi_wrapper, make_context_current,
+ picture_buffer_id, texture_id, size));
+#elif defined(USE_OZONE)
+ picture.reset(new VaapiDrmPicture(vaapi_wrapper, make_context_current,
+ picture_buffer_id, texture_id, size));
+#endif // USE_X11
+
+ if (picture.get() && !picture->Initialize())
+ picture.reset();
+
+ return picture;
+}
+
+bool VaapiPicture::AllowOverlay() const {
+ return false;
+}
+
+// static
+uint32 VaapiPicture::GetGLTextureTarget() {
+#if defined(USE_OZONE)
+ return GL_TEXTURE_EXTERNAL_OES;
+#else
+ return GL_TEXTURE_2D;
+#endif
+}
+
+} // namespace content
diff --git a/chromium/content/common/gpu/media/vaapi_picture.h b/chromium/content/common/gpu/media/vaapi_picture.h
new file mode 100644
index 00000000000..ad43dfa3af3
--- /dev/null
+++ b/chromium/content/common/gpu/media/vaapi_picture.h
@@ -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.
+//
+// This file contains an interface of output pictures for the Vaapi
+// video decoder. This is implemented by different window system
+// (X11/Ozone) and used by VaapiVideoDecodeAccelerator to produce
+// output pictures.
+
+#ifndef CONTENT_COMMON_GPU_MEDIA_VAAPI_PICTURE_H_
+#define CONTENT_COMMON_GPU_MEDIA_VAAPI_PICTURE_H_
+
+#include "base/callback.h"
+#include "base/memory/linked_ptr.h"
+#include "base/memory/ref_counted.h"
+#include "base/threading/non_thread_safe.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace gfx {
+class GLImage;
+}
+
+namespace content {
+
+class VASurface;
+class VaapiWrapper;
+
+// Picture is native pixmap abstraction (X11/Ozone).
+class VaapiPicture : public base::NonThreadSafe {
+ public:
+ virtual ~VaapiPicture() {}
+
+ // Try to allocate the underlying resources for the picture.
+ virtual bool Initialize() = 0;
+
+ int32 picture_buffer_id() const { return picture_buffer_id_; }
+ uint32 texture_id() const { return texture_id_; }
+ const gfx::Size& size() const { return size_; }
+
+ virtual bool AllowOverlay() const;
+
+ // Returns the |GLImage|, if any, to bind to the texture.
+ virtual scoped_refptr<gfx::GLImage> GetImageToBind() = 0;
+
+ // Downloads the |va_surface| into the picture, potentially scaling
+ // it if needed.
+ virtual bool DownloadFromSurface(
+ const scoped_refptr<VASurface>& va_surface) = 0;
+
+ // Create a VaapiPicture of |size| to be associated with
+ // |picture_buffer_id| and bound to |texture_id|.
+ // |make_context_current| is provided for the GL operations.
+ static linked_ptr<VaapiPicture> CreatePicture(
+ VaapiWrapper* vaapi_wrapper,
+ const base::Callback<bool(void)> make_context_current,
+ int32 picture_buffer_id,
+ uint32 texture_id,
+ const gfx::Size& size);
+
+ // Get the texture target used to bind EGLImages (either
+ // GL_TEXTURE_2D on X11 or GL_TEXTURE_EXTERNAL_OES on DRM).
+ static uint32 GetGLTextureTarget();
+
+ protected:
+ VaapiPicture(int32 picture_buffer_id,
+ uint32 texture_id,
+ const gfx::Size& size)
+ : picture_buffer_id_(picture_buffer_id),
+ texture_id_(texture_id),
+ size_(size) {}
+
+ private:
+ int32 picture_buffer_id_;
+ uint32 texture_id_;
+ gfx::Size size_;
+
+ DISALLOW_COPY_AND_ASSIGN(VaapiPicture);
+};
+
+} // namespace content
+
+#endif // CONTENT_COMMON_GPU_MEDIA_VAAPI_PICTURE_H_
diff --git a/chromium/content/common/gpu/media/vaapi_tfp_picture.cc b/chromium/content/common/gpu/media/vaapi_tfp_picture.cc
new file mode 100644
index 00000000000..ee037421edf
--- /dev/null
+++ b/chromium/content/common/gpu/media/vaapi_tfp_picture.cc
@@ -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.
+
+#include "content/common/gpu/media/va_surface.h"
+#include "content/common/gpu/media/vaapi_tfp_picture.h"
+#include "content/common/gpu/media/vaapi_wrapper.h"
+#include "ui/gfx/x/x11_types.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_image_glx.h"
+#include "ui/gl/scoped_binders.h"
+
+namespace content {
+
+VaapiTFPPicture::VaapiTFPPicture(
+ VaapiWrapper* vaapi_wrapper,
+ const base::Callback<bool(void)> make_context_current,
+ int32 picture_buffer_id,
+ uint32 texture_id,
+ const gfx::Size& size)
+ : VaapiPicture(picture_buffer_id, texture_id, size),
+ vaapi_wrapper_(vaapi_wrapper),
+ make_context_current_(make_context_current),
+ x_display_(gfx::GetXDisplay()),
+ x_pixmap_(0) {
+}
+
+VaapiTFPPicture::~VaapiTFPPicture() {
+ if (glx_image_.get() && make_context_current_.Run()) {
+ glx_image_->ReleaseTexImage(GL_TEXTURE_2D);
+ glx_image_->Destroy(true);
+ DCHECK_EQ(glGetError(), static_cast<GLenum>(GL_NO_ERROR));
+ }
+
+ if (x_pixmap_)
+ XFreePixmap(x_display_, x_pixmap_);
+}
+
+bool VaapiTFPPicture::Initialize() {
+ if (!make_context_current_.Run())
+ return false;
+
+ XWindowAttributes win_attr;
+ int screen = DefaultScreen(x_display_);
+ XGetWindowAttributes(x_display_, RootWindow(x_display_, screen), &win_attr);
+ // TODO(posciak): pass the depth required by libva, not the RootWindow's
+ // depth
+ x_pixmap_ = XCreatePixmap(x_display_, RootWindow(x_display_, screen),
+ size().width(), size().height(), win_attr.depth);
+ if (!x_pixmap_) {
+ LOG(ERROR) << "Failed creating an X Pixmap for TFP";
+ return false;
+ }
+
+ glx_image_ = new gfx::GLImageGLX(size(), GL_RGB);
+ if (!glx_image_->Initialize(x_pixmap_)) {
+ // x_pixmap_ will be freed in the destructor.
+ LOG(ERROR) << "Failed creating a GLX Pixmap for TFP";
+ return false;
+ }
+
+ gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_2D, texture_id());
+ if (!glx_image_->BindTexImage(GL_TEXTURE_2D)) {
+ LOG(ERROR) << "Failed to bind texture to glx image";
+ return false;
+ }
+
+ return true;
+}
+
+bool VaapiTFPPicture::DownloadFromSurface(
+ const scoped_refptr<VASurface>& va_surface) {
+ return vaapi_wrapper_->PutSurfaceIntoPixmap(va_surface->id(), x_pixmap_,
+ va_surface->size());
+}
+
+scoped_refptr<gfx::GLImage> VaapiTFPPicture::GetImageToBind() {
+ return nullptr;
+}
+
+} // namespace content
diff --git a/chromium/content/common/gpu/media/vaapi_tfp_picture.h b/chromium/content/common/gpu/media/vaapi_tfp_picture.h
new file mode 100644
index 00000000000..3261791fbf0
--- /dev/null
+++ b/chromium/content/common/gpu/media/vaapi_tfp_picture.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.
+//
+// This file contains an implementation of picture allocation for the
+// X11 window system used by VaapiVideoDecodeAccelerator to produce
+// output pictures.
+
+#ifndef CONTENT_COMMON_GPU_MEDIA_VAAPI_TFP_PICTURE_H_
+#define CONTENT_COMMON_GPU_MEDIA_VAAPI_TFP_PICTURE_H_
+
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "content/common/gpu/media/vaapi_picture.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gl/gl_bindings.h"
+
+namespace gfx {
+class GLImageGLX;
+class GLContextGLX;
+}
+
+namespace content {
+
+class VaapiWrapper;
+
+// Implementation of VaapiPicture for the X11 backed chromium.
+class VaapiTFPPicture : public VaapiPicture {
+ public:
+ VaapiTFPPicture(VaapiWrapper* vaapi_wrapper,
+ const base::Callback<bool(void)> make_context_current,
+ int32 picture_buffer_id,
+ uint32 texture_id,
+ const gfx::Size& size);
+
+ ~VaapiTFPPicture() override;
+
+ bool Initialize() override;
+
+ bool DownloadFromSurface(const scoped_refptr<VASurface>& va_surface) override;
+
+ scoped_refptr<gfx::GLImage> GetImageToBind() override;
+
+ private:
+ VaapiWrapper* vaapi_wrapper_; // Not owned.
+
+ base::Callback<bool(void)> make_context_current_;
+ Display* x_display_;
+
+ Pixmap x_pixmap_;
+ scoped_refptr<gfx::GLImageGLX> glx_image_;
+
+ DISALLOW_COPY_AND_ASSIGN(VaapiTFPPicture);
+};
+
+} // namespace content
+
+#endif // CONTENT_COMMON_GPU_MEDIA_VAAPI_TFP_PICTURE_H_
diff --git a/chromium/content/common/gpu/media/vaapi_video_decode_accelerator.cc b/chromium/content/common/gpu/media/vaapi_video_decode_accelerator.cc
index df1f6443421..2773a408dca 100644
--- a/chromium/content/common/gpu/media/vaapi_video_decode_accelerator.cc
+++ b/chromium/content/common/gpu/media/vaapi_video_decode_accelerator.cc
@@ -2,30 +2,40 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "content/common/gpu/media/vaapi_video_decode_accelerator.h"
+
#include "base/bind.h"
-#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/synchronization/waitable_event.h"
-#include "base/threading/non_thread_safe.h"
+#include "base/trace_event/trace_event.h"
#include "content/common/gpu/gpu_channel.h"
-#include "content/common/gpu/media/vaapi_video_decode_accelerator.h"
+#include "content/common/gpu/media/accelerated_video_decoder.h"
+#include "content/common/gpu/media/h264_decoder.h"
+#include "content/common/gpu/media/vaapi_picture.h"
+#include "content/common/gpu/media/vp8_decoder.h"
#include "media/base/bind_to_current_loop.h"
#include "media/video/picture.h"
+#include "third_party/libva/va/va_dec_vp8.h"
#include "ui/gl/gl_bindings.h"
-#include "ui/gl/scoped_binders.h"
+#include "ui/gl/gl_image.h"
+
+namespace content {
-static void ReportToUMA(
- content::VaapiH264Decoder::VAVDAH264DecoderFailure failure) {
- UMA_HISTOGRAM_ENUMERATION(
- "Media.VAVDAH264.DecoderFailure",
- failure,
- content::VaapiH264Decoder::VAVDA_H264_DECODER_FAILURES_MAX);
+namespace {
+// UMA errors that the VaapiVideoDecodeAccelerator class reports.
+enum VAVDADecoderFailure {
+ VAAPI_ERROR = 0,
+ VAVDA_DECODER_FAILURES_MAX,
+};
}
-namespace content {
+static void ReportToUMA(VAVDADecoderFailure failure) {
+ UMA_HISTOGRAM_ENUMERATION("Media.VAVDA.DecoderFailure", failure,
+ VAVDA_DECODER_FAILURES_MAX);
+}
#define RETURN_AND_NOTIFY_ON_FAILURE(result, log, error_code, ret) \
do { \
@@ -36,189 +46,187 @@ namespace content {
} \
} while (0)
-VaapiVideoDecodeAccelerator::InputBuffer::InputBuffer() : id(0), size(0) {
-}
+class VaapiVideoDecodeAccelerator::VaapiDecodeSurface
+ : public base::RefCountedThreadSafe<VaapiDecodeSurface> {
+ public:
+ VaapiDecodeSurface(int32 bitstream_id,
+ const scoped_refptr<VASurface>& va_surface);
-VaapiVideoDecodeAccelerator::InputBuffer::~InputBuffer() {
-}
+ int32 bitstream_id() const { return bitstream_id_; }
+ scoped_refptr<VASurface> va_surface() { return va_surface_; }
-void VaapiVideoDecodeAccelerator::NotifyError(Error error) {
- if (message_loop_ != base::MessageLoop::current()) {
- DCHECK(decoder_thread_proxy_->BelongsToCurrentThread());
- message_loop_->PostTask(FROM_HERE, base::Bind(
- &VaapiVideoDecodeAccelerator::NotifyError, weak_this_, error));
- return;
- }
+ private:
+ friend class base::RefCountedThreadSafe<VaapiDecodeSurface>;
+ ~VaapiDecodeSurface();
- // Post Cleanup() as a task so we don't recursively acquire lock_.
- message_loop_->PostTask(FROM_HERE, base::Bind(
- &VaapiVideoDecodeAccelerator::Cleanup, weak_this_));
+ int32 bitstream_id_;
+ scoped_refptr<VASurface> va_surface_;
+};
- LOG(ERROR) << "Notifying of error " << error;
- if (client_) {
- client_->NotifyError(error);
- client_ptr_factory_.reset();
- }
+VaapiVideoDecodeAccelerator::VaapiDecodeSurface::VaapiDecodeSurface(
+ int32 bitstream_id,
+ const scoped_refptr<VASurface>& va_surface)
+ : bitstream_id_(bitstream_id), va_surface_(va_surface) {
}
-// TFPPicture allocates X Pixmaps and binds them to textures passed
-// in PictureBuffers from clients to them. TFPPictures are created as
-// a consequence of receiving a set of PictureBuffers from clients and released
-// at the end of decode (or when a new set of PictureBuffers is required).
-//
-// TFPPictures are used for output, contents of VASurfaces passed from decoder
-// are put into the associated pixmap memory and sent to client.
-class VaapiVideoDecodeAccelerator::TFPPicture : public base::NonThreadSafe {
- public:
- ~TFPPicture();
+VaapiVideoDecodeAccelerator::VaapiDecodeSurface::~VaapiDecodeSurface() {
+}
- static linked_ptr<TFPPicture> Create(
- const base::Callback<bool(void)>& make_context_current,
- const GLXFBConfig& fb_config,
- Display* x_display,
- int32 picture_buffer_id,
- uint32 texture_id,
- gfx::Size size);
+class VaapiH264Picture : public H264Picture {
+ public:
+ VaapiH264Picture(const scoped_refptr<
+ VaapiVideoDecodeAccelerator::VaapiDecodeSurface>& dec_surface);
- int32 picture_buffer_id() {
- return picture_buffer_id_;
+ VaapiH264Picture* AsVaapiH264Picture() override { return this; }
+ scoped_refptr<VaapiVideoDecodeAccelerator::VaapiDecodeSurface> dec_surface() {
+ return dec_surface_;
}
- gfx::Size size() {
- return size_;
- }
+ private:
+ ~VaapiH264Picture() override;
- int x_pixmap() {
- return x_pixmap_;
- }
+ scoped_refptr<VaapiVideoDecodeAccelerator::VaapiDecodeSurface> dec_surface_;
- // Bind texture to pixmap. Needs to be called every frame.
- bool Bind();
+ DISALLOW_COPY_AND_ASSIGN(VaapiH264Picture);
+};
+
+VaapiH264Picture::VaapiH264Picture(const scoped_refptr<
+ VaapiVideoDecodeAccelerator::VaapiDecodeSurface>& dec_surface)
+ : dec_surface_(dec_surface) {
+}
+
+VaapiH264Picture::~VaapiH264Picture() {
+}
+
+class VaapiVideoDecodeAccelerator::VaapiH264Accelerator
+ : public H264Decoder::H264Accelerator {
+ public:
+ VaapiH264Accelerator(VaapiVideoDecodeAccelerator* vaapi_dec,
+ VaapiWrapper* vaapi_wrapper);
+ ~VaapiH264Accelerator() override;
+
+ // H264Decoder::H264Accelerator implementation.
+ scoped_refptr<H264Picture> CreateH264Picture() override;
+
+ bool SubmitFrameMetadata(const media::H264SPS* sps,
+ const media::H264PPS* pps,
+ const H264DPB& dpb,
+ const H264Picture::Vector& ref_pic_listp0,
+ const H264Picture::Vector& ref_pic_listb0,
+ const H264Picture::Vector& ref_pic_listb1,
+ const scoped_refptr<H264Picture>& pic) override;
+
+ bool SubmitSlice(const media::H264PPS* pps,
+ const media::H264SliceHeader* slice_hdr,
+ const H264Picture::Vector& ref_pic_list0,
+ const H264Picture::Vector& ref_pic_list1,
+ const scoped_refptr<H264Picture>& pic,
+ const uint8_t* data,
+ size_t size) override;
+
+ bool SubmitDecode(const scoped_refptr<H264Picture>& pic) override;
+ bool OutputPicture(const scoped_refptr<H264Picture>& pic) override;
+
+ void Reset() override;
private:
- TFPPicture(const base::Callback<bool(void)>& make_context_current,
- Display* x_display,
- int32 picture_buffer_id,
- uint32 texture_id,
- gfx::Size size);
+ scoped_refptr<VaapiDecodeSurface> H264PictureToVaapiDecodeSurface(
+ const scoped_refptr<H264Picture>& pic);
- bool Initialize(const GLXFBConfig& fb_config);
+ void FillVAPicture(VAPictureH264* va_pic, scoped_refptr<H264Picture> pic);
+ int FillVARefFramesFromDPB(const H264DPB& dpb,
+ VAPictureH264* va_pics,
+ int num_pics);
- base::Callback<bool(void)> make_context_current_;
+ VaapiWrapper* vaapi_wrapper_;
+ VaapiVideoDecodeAccelerator* vaapi_dec_;
- Display* x_display_;
+ DISALLOW_COPY_AND_ASSIGN(VaapiH264Accelerator);
+};
- // Output id for the client.
- int32 picture_buffer_id_;
- uint32 texture_id_;
+class VaapiVP8Picture : public VP8Picture {
+ public:
+ VaapiVP8Picture(const scoped_refptr<
+ VaapiVideoDecodeAccelerator::VaapiDecodeSurface>& dec_surface);
- gfx::Size size_;
+ VaapiVP8Picture* AsVaapiVP8Picture() override { return this; }
+ scoped_refptr<VaapiVideoDecodeAccelerator::VaapiDecodeSurface> dec_surface() {
+ return dec_surface_;
+ }
- // Pixmaps bound to this texture.
- Pixmap x_pixmap_;
- GLXPixmap glx_pixmap_;
+ private:
+ ~VaapiVP8Picture() override;
- DISALLOW_COPY_AND_ASSIGN(TFPPicture);
-};
+ scoped_refptr<VaapiVideoDecodeAccelerator::VaapiDecodeSurface> dec_surface_;
-VaapiVideoDecodeAccelerator::TFPPicture::TFPPicture(
- const base::Callback<bool(void)>& make_context_current,
- Display* x_display,
- int32 picture_buffer_id,
- uint32 texture_id,
- gfx::Size size)
- : make_context_current_(make_context_current),
- x_display_(x_display),
- picture_buffer_id_(picture_buffer_id),
- texture_id_(texture_id),
- size_(size),
- x_pixmap_(0),
- glx_pixmap_(0) {
- DCHECK(!make_context_current_.is_null());
+ DISALLOW_COPY_AND_ASSIGN(VaapiVP8Picture);
};
-linked_ptr<VaapiVideoDecodeAccelerator::TFPPicture>
-VaapiVideoDecodeAccelerator::TFPPicture::Create(
- const base::Callback<bool(void)>& make_context_current,
- const GLXFBConfig& fb_config,
- Display* x_display,
- int32 picture_buffer_id,
- uint32 texture_id,
- gfx::Size size) {
+VaapiVP8Picture::VaapiVP8Picture(const scoped_refptr<
+ VaapiVideoDecodeAccelerator::VaapiDecodeSurface>& dec_surface)
+ : dec_surface_(dec_surface) {
+}
- linked_ptr<TFPPicture> tfp_picture(
- new TFPPicture(make_context_current, x_display, picture_buffer_id,
- texture_id, size));
+VaapiVP8Picture::~VaapiVP8Picture() {
+}
- if (!tfp_picture->Initialize(fb_config))
- tfp_picture.reset();
+class VaapiVideoDecodeAccelerator::VaapiVP8Accelerator
+ : public VP8Decoder::VP8Accelerator {
+ public:
+ VaapiVP8Accelerator(VaapiVideoDecodeAccelerator* vaapi_dec,
+ VaapiWrapper* vaapi_wrapper);
+ ~VaapiVP8Accelerator() override;
- return tfp_picture;
-}
+ // VP8Decoder::VP8Accelerator implementation.
+ scoped_refptr<VP8Picture> CreateVP8Picture() override;
-bool VaapiVideoDecodeAccelerator::TFPPicture::Initialize(
- const GLXFBConfig& fb_config) {
- DCHECK(CalledOnValidThread());
- if (!make_context_current_.Run())
- return false;
+ bool SubmitDecode(const scoped_refptr<VP8Picture>& pic,
+ const media::Vp8FrameHeader* frame_hdr,
+ const scoped_refptr<VP8Picture>& last_frame,
+ const scoped_refptr<VP8Picture>& golden_frame,
+ const scoped_refptr<VP8Picture>& alt_frame) override;
- XWindowAttributes win_attr;
- int screen = DefaultScreen(x_display_);
- XGetWindowAttributes(x_display_, RootWindow(x_display_, screen), &win_attr);
- //TODO(posciak): pass the depth required by libva, not the RootWindow's depth
- x_pixmap_ = XCreatePixmap(x_display_, RootWindow(x_display_, screen),
- size_.width(), size_.height(), win_attr.depth);
- if (!x_pixmap_) {
- LOG(ERROR) << "Failed creating an X Pixmap for TFP";
- return false;
- }
+ bool OutputPicture(const scoped_refptr<VP8Picture>& pic) override;
+
+ private:
+ scoped_refptr<VaapiDecodeSurface> VP8PictureToVaapiDecodeSurface(
+ const scoped_refptr<VP8Picture>& pic);
- static const int pixmap_attr[] = {
- GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
- GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGB_EXT,
- GL_NONE,
- };
+ VaapiWrapper* vaapi_wrapper_;
+ VaapiVideoDecodeAccelerator* vaapi_dec_;
- glx_pixmap_ = glXCreatePixmap(x_display_, fb_config, x_pixmap_, pixmap_attr);
- if (!glx_pixmap_) {
- // x_pixmap_ will be freed in the destructor.
- LOG(ERROR) << "Failed creating a GLX Pixmap for TFP";
- return false;
- }
+ DISALLOW_COPY_AND_ASSIGN(VaapiVP8Accelerator);
+};
- return true;
+VaapiVideoDecodeAccelerator::InputBuffer::InputBuffer() : id(0), size(0) {
}
-VaapiVideoDecodeAccelerator::TFPPicture::~TFPPicture() {
- DCHECK(CalledOnValidThread());
- // Unbind surface from texture and deallocate resources.
- if (glx_pixmap_ && make_context_current_.Run()) {
- glXReleaseTexImageEXT(x_display_, glx_pixmap_, GLX_FRONT_LEFT_EXT);
- glXDestroyPixmap(x_display_, glx_pixmap_);
- }
-
- if (x_pixmap_)
- XFreePixmap(x_display_, x_pixmap_);
- XSync(x_display_, False); // Needed to work around buggy vdpau-driver.
+VaapiVideoDecodeAccelerator::InputBuffer::~InputBuffer() {
}
-bool VaapiVideoDecodeAccelerator::TFPPicture::Bind() {
- DCHECK(CalledOnValidThread());
- DCHECK(x_pixmap_);
- DCHECK(glx_pixmap_);
- if (!make_context_current_.Run())
- return false;
+void VaapiVideoDecodeAccelerator::NotifyError(Error error) {
+ if (message_loop_ != base::MessageLoop::current()) {
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+ message_loop_->PostTask(FROM_HERE, base::Bind(
+ &VaapiVideoDecodeAccelerator::NotifyError, weak_this_, error));
+ return;
+ }
- gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_2D, texture_id_);
- glXBindTexImageEXT(x_display_, glx_pixmap_, GLX_FRONT_LEFT_EXT, NULL);
+ // Post Cleanup() as a task so we don't recursively acquire lock_.
+ message_loop_->PostTask(FROM_HERE, base::Bind(
+ &VaapiVideoDecodeAccelerator::Cleanup, weak_this_));
- return true;
+ LOG(ERROR) << "Notifying of error " << error;
+ if (client_) {
+ client_->NotifyError(error);
+ client_ptr_factory_.reset();
+ }
}
-VaapiVideoDecodeAccelerator::TFPPicture*
- VaapiVideoDecodeAccelerator::TFPPictureById(int32 picture_buffer_id) {
- TFPPictures::iterator it = tfp_pictures_.find(picture_buffer_id);
- if (it == tfp_pictures_.end()) {
+VaapiPicture* VaapiVideoDecodeAccelerator::PictureById(
+ int32 picture_buffer_id) {
+ Pictures::iterator it = pictures_.find(picture_buffer_id);
+ if (it == pictures_.end()) {
LOG(ERROR) << "Picture id " << picture_buffer_id << " does not exist";
return NULL;
}
@@ -227,10 +235,10 @@ VaapiVideoDecodeAccelerator::TFPPicture*
}
VaapiVideoDecodeAccelerator::VaapiVideoDecodeAccelerator(
- Display* x_display,
- const base::Callback<bool(void)>& make_context_current)
- : x_display_(x_display),
- make_context_current_(make_context_current),
+ const base::Callback<bool(void)>& make_context_current,
+ const base::Callback<void(uint32, uint32, scoped_refptr<gfx::GLImage>)>&
+ bind_image)
+ : make_context_current_(make_context_current),
state_(kUninitialized),
input_ready_(&lock_),
surfaces_available_(&lock_),
@@ -241,6 +249,7 @@ VaapiVideoDecodeAccelerator::VaapiVideoDecodeAccelerator(
finish_flush_pending_(false),
awaiting_va_surfaces_recycle_(false),
requested_num_pics_(0),
+ bind_image_(bind_image),
weak_this_factory_(this) {
weak_this_ = weak_this_factory_.GetWeakPtr();
va_surface_release_cb_ = media::BindToCurrentLoop(
@@ -251,35 +260,6 @@ VaapiVideoDecodeAccelerator::~VaapiVideoDecodeAccelerator() {
DCHECK_EQ(message_loop_, base::MessageLoop::current());
}
-class XFreeDeleter {
- public:
- void operator()(void* x) const {
- ::XFree(x);
- }
-};
-
-bool VaapiVideoDecodeAccelerator::InitializeFBConfig() {
- const int fbconfig_attr[] = {
- GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
- GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT,
- GLX_BIND_TO_TEXTURE_RGB_EXT, GL_TRUE,
- GLX_Y_INVERTED_EXT, GL_TRUE,
- GL_NONE,
- };
-
- int num_fbconfigs;
- scoped_ptr<GLXFBConfig, XFreeDeleter> glx_fb_configs(
- glXChooseFBConfig(x_display_, DefaultScreen(x_display_), fbconfig_attr,
- &num_fbconfigs));
- if (!glx_fb_configs)
- return false;
- if (!num_fbconfigs)
- return false;
-
- fb_config_ = glx_fb_configs.get()[0];
- return true;
-}
-
bool VaapiVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile,
Client* client) {
DCHECK_EQ(message_loop_, base::MessageLoop::current());
@@ -291,63 +271,52 @@ bool VaapiVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile,
DCHECK_EQ(state_, kUninitialized);
DVLOG(2) << "Initializing VAVDA, profile: " << profile;
- if (!make_context_current_.Run())
+#if defined(USE_X11)
+ if (gfx::GetGLImplementation() != gfx::kGLImplementationDesktopGL) {
+ DVLOG(1) << "HW video decode acceleration not available without "
+ "DesktopGL (GLX).";
return false;
-
- if (!InitializeFBConfig()) {
- LOG(ERROR) << "Could not get a usable FBConfig";
+ }
+#elif defined(USE_OZONE)
+ if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2) {
+ DVLOG(1) << "HW video decode acceleration not available without "
+ << "EGLGLES2.";
return false;
}
+#endif // USE_X11
- vaapi_wrapper_ = VaapiWrapper::Create(
- VaapiWrapper::kDecode,
- profile,
- x_display_,
- base::Bind(&ReportToUMA, content::VaapiH264Decoder::VAAPI_ERROR));
+ vaapi_wrapper_ = VaapiWrapper::CreateForVideoCodec(
+ VaapiWrapper::kDecode, profile, base::Bind(&ReportToUMA, VAAPI_ERROR));
if (!vaapi_wrapper_.get()) {
- LOG(ERROR) << "Failed initializing VAAPI";
+ DVLOG(1) << "Failed initializing VAAPI for profile " << profile;
return false;
}
- decoder_.reset(
- new VaapiH264Decoder(
- vaapi_wrapper_.get(),
- media::BindToCurrentLoop(base::Bind(
- &VaapiVideoDecodeAccelerator::SurfaceReady, weak_this_)),
- base::Bind(&ReportToUMA)));
+ // TODO(posciak): add back VP8 (crbug.com/490233)
+ if (profile >= media::H264PROFILE_MIN && profile <= media::H264PROFILE_MAX) {
+ h264_accelerator_.reset(
+ new VaapiH264Accelerator(this, vaapi_wrapper_.get()));
+ decoder_.reset(new H264Decoder(h264_accelerator_.get()));
+ } else {
+ DLOG(ERROR) << "Unsupported profile " << profile;
+ return false;
+ }
CHECK(decoder_thread_.Start());
- decoder_thread_proxy_ = decoder_thread_.message_loop_proxy();
+ decoder_thread_task_runner_ = decoder_thread_.task_runner();
state_ = kIdle;
return true;
}
-void VaapiVideoDecodeAccelerator::SurfaceReady(
- int32 input_id,
- const scoped_refptr<VASurface>& va_surface) {
- DCHECK_EQ(message_loop_, base::MessageLoop::current());
- DCHECK(!awaiting_va_surfaces_recycle_);
-
- // Drop any requests to output if we are resetting or being destroyed.
- if (state_ == kResetting || state_ == kDestroying)
- return;
-
- pending_output_cbs_.push(
- base::Bind(&VaapiVideoDecodeAccelerator::OutputPicture,
- weak_this_, va_surface, input_id));
-
- TryOutputSurface();
-}
-
void VaapiVideoDecodeAccelerator::OutputPicture(
const scoped_refptr<VASurface>& va_surface,
int32 input_id,
- TFPPicture* tfp_picture) {
+ VaapiPicture* picture) {
DCHECK_EQ(message_loop_, base::MessageLoop::current());
- int32 output_id = tfp_picture->picture_buffer_id();
+ int32 output_id = picture->picture_buffer_id();
TRACE_EVENT2("Video Decoder", "VAVDA::OutputSurface",
"input_id", input_id,
@@ -356,16 +325,10 @@ void VaapiVideoDecodeAccelerator::OutputPicture(
DVLOG(3) << "Outputting VASurface " << va_surface->id()
<< " into pixmap bound to picture buffer id " << output_id;
- RETURN_AND_NOTIFY_ON_FAILURE(tfp_picture->Bind(),
- "Failed binding texture to pixmap",
+ RETURN_AND_NOTIFY_ON_FAILURE(picture->DownloadFromSurface(va_surface),
+ "Failed putting surface into pixmap",
PLATFORM_FAILURE, );
- RETURN_AND_NOTIFY_ON_FAILURE(
- vaapi_wrapper_->PutSurfaceIntoPixmap(va_surface->id(),
- tfp_picture->x_pixmap(),
- tfp_picture->size()),
- "Failed putting surface into pixmap", PLATFORM_FAILURE, );
-
// Notify the client a picture is ready to be displayed.
++num_frames_at_client_;
TRACE_COUNTER1("Video Decoder", "Textures at client", num_frames_at_client_);
@@ -374,8 +337,9 @@ void VaapiVideoDecodeAccelerator::OutputPicture(
// TODO(posciak): Use visible size from decoder here instead
// (crbug.com/402760).
if (client_)
- client_->PictureReady(
- media::Picture(output_id, input_id, gfx::Rect(tfp_picture->size())));
+ client_->PictureReady(media::Picture(output_id, input_id,
+ gfx::Rect(picture->size()),
+ picture->AllowOverlay()));
}
void VaapiVideoDecodeAccelerator::TryOutputSurface() {
@@ -391,11 +355,11 @@ void VaapiVideoDecodeAccelerator::TryOutputSurface() {
OutputCB output_cb = pending_output_cbs_.front();
pending_output_cbs_.pop();
- TFPPicture* tfp_picture = TFPPictureById(output_buffers_.front());
- DCHECK(tfp_picture);
+ VaapiPicture* picture = PictureById(output_buffers_.front());
+ DCHECK(picture);
output_buffers_.pop();
- output_cb.Run(tfp_picture);
+ output_cb.Run(picture);
if (finish_flush_pending_ && pending_output_cbs_.empty())
FinishFlush();
@@ -432,7 +396,7 @@ void VaapiVideoDecodeAccelerator::MapAndQueueNewInputBuffer(
}
bool VaapiVideoDecodeAccelerator::GetInputBuffer_Locked() {
- DCHECK(decoder_thread_proxy_->BelongsToCurrentThread());
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
lock_.AssertAcquired();
if (curr_input_buffer_.get())
@@ -466,7 +430,7 @@ bool VaapiVideoDecodeAccelerator::GetInputBuffer_Locked() {
decoder_->SetStream(
static_cast<uint8*>(curr_input_buffer_->shm->memory()),
- curr_input_buffer_->size, curr_input_buffer_->id);
+ curr_input_buffer_->size);
return true;
default:
@@ -478,7 +442,7 @@ bool VaapiVideoDecodeAccelerator::GetInputBuffer_Locked() {
void VaapiVideoDecodeAccelerator::ReturnCurrInputBuffer_Locked() {
lock_.AssertAcquired();
- DCHECK(decoder_thread_proxy_->BelongsToCurrentThread());
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
DCHECK(curr_input_buffer_.get());
int32 id = curr_input_buffer_->id;
@@ -492,9 +456,11 @@ void VaapiVideoDecodeAccelerator::ReturnCurrInputBuffer_Locked() {
num_stream_bufs_at_decoder_);
}
-bool VaapiVideoDecodeAccelerator::FeedDecoderWithOutputSurfaces_Locked() {
+// TODO(posciak): refactor the whole class to remove sleeping in wait for
+// surfaces, and reschedule DecodeTask instead.
+bool VaapiVideoDecodeAccelerator::WaitForSurfaces_Locked() {
lock_.AssertAcquired();
- DCHECK(decoder_thread_proxy_->BelongsToCurrentThread());
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
while (available_va_surfaces_.empty() &&
(state_ == kDecoding || state_ == kFlushing || state_ == kIdle)) {
@@ -504,18 +470,11 @@ bool VaapiVideoDecodeAccelerator::FeedDecoderWithOutputSurfaces_Locked() {
if (state_ != kDecoding && state_ != kFlushing && state_ != kIdle)
return false;
- while (!available_va_surfaces_.empty()) {
- scoped_refptr<VASurface> va_surface(
- new VASurface(available_va_surfaces_.front(), va_surface_release_cb_));
- available_va_surfaces_.pop_front();
- decoder_->ReuseSurface(va_surface);
- }
-
return true;
}
void VaapiVideoDecodeAccelerator::DecodeTask() {
- DCHECK(decoder_thread_proxy_->BelongsToCurrentThread());
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
TRACE_EVENT0("Video Decoder", "VAVDA::DecodeTask");
base::AutoLock auto_lock(lock_);
@@ -530,7 +489,7 @@ void VaapiVideoDecodeAccelerator::DecodeTask() {
while (GetInputBuffer_Locked()) {
DCHECK(curr_input_buffer_.get());
- VaapiH264Decoder::DecResult res;
+ AcceleratedVideoDecoder::DecodeResult res;
{
// We are OK releasing the lock here, as decoder never calls our methods
// directly and we will reacquire the lock before looking at state again.
@@ -542,7 +501,7 @@ void VaapiVideoDecodeAccelerator::DecodeTask() {
}
switch (res) {
- case VaapiH264Decoder::kAllocateNewSurfaces:
+ case AcceleratedVideoDecoder::kAllocateNewSurfaces:
DVLOG(1) << "Decoder requesting a new set of surfaces";
message_loop_->PostTask(FROM_HERE, base::Bind(
&VaapiVideoDecodeAccelerator::InitiateSurfaceSetChange, weak_this_,
@@ -551,19 +510,19 @@ void VaapiVideoDecodeAccelerator::DecodeTask() {
// We'll get rescheduled once ProvidePictureBuffers() finishes.
return;
- case VaapiH264Decoder::kRanOutOfStreamData:
+ case AcceleratedVideoDecoder::kRanOutOfStreamData:
ReturnCurrInputBuffer_Locked();
break;
- case VaapiH264Decoder::kRanOutOfSurfaces:
+ case AcceleratedVideoDecoder::kRanOutOfSurfaces:
// No more output buffers in the decoder, try getting more or go to
// sleep waiting for them.
- if (!FeedDecoderWithOutputSurfaces_Locked())
+ if (!WaitForSurfaces_Locked())
return;
break;
- case VaapiH264Decoder::kDecodeError:
+ case AcceleratedVideoDecoder::kDecodeError:
RETURN_AND_NOTIFY_ON_FAILURE(false, "Error decoding stream",
PLATFORM_FAILURE, );
return;
@@ -598,7 +557,7 @@ void VaapiVideoDecodeAccelerator::TryFinishSurfaceSetChange() {
return;
if (!pending_output_cbs_.empty() ||
- tfp_pictures_.size() != available_va_surfaces_.size()) {
+ pictures_.size() != available_va_surfaces_.size()) {
// Either:
// 1. Not all pending pending output callbacks have been executed yet.
// Wait for the client to return enough pictures and retry later.
@@ -616,21 +575,22 @@ void VaapiVideoDecodeAccelerator::TryFinishSurfaceSetChange() {
available_va_surfaces_.clear();
vaapi_wrapper_->DestroySurfaces();
- for (TFPPictures::iterator iter = tfp_pictures_.begin();
- iter != tfp_pictures_.end(); ++iter) {
+ for (Pictures::iterator iter = pictures_.begin(); iter != pictures_.end();
+ ++iter) {
DVLOG(2) << "Dismissing picture id: " << iter->first;
if (client_)
client_->DismissPictureBuffer(iter->first);
}
- tfp_pictures_.clear();
+ pictures_.clear();
// And ask for a new set as requested.
DVLOG(1) << "Requesting " << requested_num_pics_ << " pictures of size: "
<< requested_pic_size_.ToString();
- message_loop_->PostTask(FROM_HERE, base::Bind(
- &Client::ProvidePictureBuffers, client_,
- requested_num_pics_, requested_pic_size_, GL_TEXTURE_2D));
+ message_loop_->PostTask(
+ FROM_HERE,
+ base::Bind(&Client::ProvidePictureBuffers, client_, requested_num_pics_,
+ requested_pic_size_, VaapiPicture::GetGLTextureTarget()));
}
void VaapiVideoDecodeAccelerator::Decode(
@@ -647,9 +607,9 @@ void VaapiVideoDecodeAccelerator::Decode(
switch (state_) {
case kIdle:
state_ = kDecoding;
- decoder_thread_proxy_->PostTask(FROM_HERE, base::Bind(
- &VaapiVideoDecodeAccelerator::DecodeTask,
- base::Unretained(this)));
+ decoder_thread_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&VaapiVideoDecodeAccelerator::DecodeTask,
+ base::Unretained(this)));
break;
case kDecoding:
@@ -682,7 +642,7 @@ void VaapiVideoDecodeAccelerator::AssignPictureBuffers(
DCHECK_EQ(message_loop_, base::MessageLoop::current());
base::AutoLock auto_lock(lock_);
- DCHECK(tfp_pictures_.empty());
+ DCHECK(pictures_.empty());
while (!output_buffers_.empty())
output_buffers_.pop();
@@ -706,17 +666,22 @@ void VaapiVideoDecodeAccelerator::AssignPictureBuffers(
<< " to texture id: " << buffers[i].texture_id()
<< " VASurfaceID: " << va_surface_ids[i];
- linked_ptr<TFPPicture> tfp_picture(
- TFPPicture::Create(make_context_current_, fb_config_, x_display_,
- buffers[i].id(), buffers[i].texture_id(),
- requested_pic_size_));
+ linked_ptr<VaapiPicture> picture(VaapiPicture::CreatePicture(
+ vaapi_wrapper_.get(), make_context_current_, buffers[i].id(),
+ buffers[i].texture_id(), requested_pic_size_));
+
+ scoped_refptr<gfx::GLImage> image = picture->GetImageToBind();
+ if (image) {
+ bind_image_.Run(buffers[i].internal_texture_id(),
+ VaapiPicture::GetGLTextureTarget(), image);
+ }
RETURN_AND_NOTIFY_ON_FAILURE(
- tfp_picture.get(), "Failed assigning picture buffer to a texture.",
+ picture.get(), "Failed assigning picture buffer to a texture.",
PLATFORM_FAILURE, );
- bool inserted = tfp_pictures_.insert(std::make_pair(
- buffers[i].id(), tfp_picture)).second;
+ bool inserted =
+ pictures_.insert(std::make_pair(buffers[i].id(), picture)).second;
DCHECK(inserted);
output_buffers_.push(buffers[i].id());
@@ -725,8 +690,9 @@ void VaapiVideoDecodeAccelerator::AssignPictureBuffers(
}
state_ = kDecoding;
- decoder_thread_proxy_->PostTask(FROM_HERE, base::Bind(
- &VaapiVideoDecodeAccelerator::DecodeTask, base::Unretained(this)));
+ decoder_thread_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&VaapiVideoDecodeAccelerator::DecodeTask,
+ base::Unretained(this)));
}
void VaapiVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) {
@@ -742,7 +708,7 @@ void VaapiVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) {
}
void VaapiVideoDecodeAccelerator::FlushTask() {
- DCHECK(decoder_thread_proxy_->BelongsToCurrentThread());
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
DVLOG(1) << "Flush task";
// First flush all the pictures that haven't been outputted, notifying the
@@ -765,8 +731,9 @@ void VaapiVideoDecodeAccelerator::Flush() {
base::AutoLock auto_lock(lock_);
state_ = kFlushing;
// Queue a flush task after all existing decoding tasks to clean up.
- decoder_thread_proxy_->PostTask(FROM_HERE, base::Bind(
- &VaapiVideoDecodeAccelerator::FlushTask, base::Unretained(this)));
+ decoder_thread_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&VaapiVideoDecodeAccelerator::FlushTask,
+ base::Unretained(this)));
input_ready_.Signal();
surfaces_available_.Signal();
@@ -799,7 +766,7 @@ void VaapiVideoDecodeAccelerator::FinishFlush() {
}
void VaapiVideoDecodeAccelerator::ResetTask() {
- DCHECK(decoder_thread_proxy_->BelongsToCurrentThread());
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
DVLOG(1) << "ResetTask";
// All the decoding tasks from before the reset request from client are done
@@ -835,8 +802,9 @@ void VaapiVideoDecodeAccelerator::Reset() {
input_buffers_.pop();
}
- decoder_thread_proxy_->PostTask(FROM_HERE, base::Bind(
- &VaapiVideoDecodeAccelerator::ResetTask, base::Unretained(this)));
+ decoder_thread_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&VaapiVideoDecodeAccelerator::ResetTask,
+ base::Unretained(this)));
input_ready_.Signal();
surfaces_available_.Signal();
@@ -879,9 +847,9 @@ void VaapiVideoDecodeAccelerator::FinishReset() {
// that we are back in kDecoding state.
if (!input_buffers_.empty()) {
state_ = kDecoding;
- decoder_thread_proxy_->PostTask(FROM_HERE, base::Bind(
- &VaapiVideoDecodeAccelerator::DecodeTask,
- base::Unretained(this)));
+ decoder_thread_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&VaapiVideoDecodeAccelerator::DecodeTask,
+ base::Unretained(this)));
}
DVLOG(1) << "Reset finished";
@@ -890,11 +858,11 @@ void VaapiVideoDecodeAccelerator::FinishReset() {
void VaapiVideoDecodeAccelerator::Cleanup() {
DCHECK_EQ(message_loop_, base::MessageLoop::current());
+ base::AutoLock auto_lock(lock_);
if (state_ == kUninitialized || state_ == kDestroying)
return;
DVLOG(1) << "Destroying VAVDA";
- base::AutoLock auto_lock(lock_);
state_ = kDestroying;
client_ptr_factory_.reset();
@@ -923,4 +891,628 @@ bool VaapiVideoDecodeAccelerator::CanDecodeOnIOThread() {
return false;
}
+bool VaapiVideoDecodeAccelerator::DecodeSurface(
+ const scoped_refptr<VaapiDecodeSurface>& dec_surface) {
+ if (!vaapi_wrapper_->ExecuteAndDestroyPendingBuffers(
+ dec_surface->va_surface()->id())) {
+ DVLOG(1) << "Failed decoding picture";
+ return false;
+ }
+
+ return true;
+}
+
+void VaapiVideoDecodeAccelerator::SurfaceReady(
+ const scoped_refptr<VaapiDecodeSurface>& dec_surface) {
+ if (message_loop_ != base::MessageLoop::current()) {
+ message_loop_->PostTask(
+ FROM_HERE, base::Bind(&VaapiVideoDecodeAccelerator::SurfaceReady,
+ weak_this_, dec_surface));
+ return;
+ }
+
+ DCHECK(!awaiting_va_surfaces_recycle_);
+
+ {
+ base::AutoLock auto_lock(lock_);
+ // Drop any requests to output if we are resetting or being destroyed.
+ if (state_ == kResetting || state_ == kDestroying)
+ return;
+ }
+
+ pending_output_cbs_.push(
+ base::Bind(&VaapiVideoDecodeAccelerator::OutputPicture, weak_this_,
+ dec_surface->va_surface(), dec_surface->bitstream_id()));
+
+ TryOutputSurface();
+}
+
+scoped_refptr<VaapiVideoDecodeAccelerator::VaapiDecodeSurface>
+VaapiVideoDecodeAccelerator::CreateSurface() {
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+ base::AutoLock auto_lock(lock_);
+
+ if (available_va_surfaces_.empty())
+ return nullptr;
+
+ DCHECK(!awaiting_va_surfaces_recycle_);
+ scoped_refptr<VASurface> va_surface(
+ new VASurface(available_va_surfaces_.front(), requested_pic_size_,
+ va_surface_release_cb_));
+ available_va_surfaces_.pop_front();
+
+ scoped_refptr<VaapiDecodeSurface> dec_surface =
+ new VaapiDecodeSurface(curr_input_buffer_->id, va_surface);
+
+ return dec_surface;
+}
+
+VaapiVideoDecodeAccelerator::VaapiH264Accelerator::VaapiH264Accelerator(
+ VaapiVideoDecodeAccelerator* vaapi_dec,
+ VaapiWrapper* vaapi_wrapper)
+ : vaapi_wrapper_(vaapi_wrapper), vaapi_dec_(vaapi_dec) {
+ DCHECK(vaapi_wrapper_);
+ DCHECK(vaapi_dec_);
+}
+
+VaapiVideoDecodeAccelerator::VaapiH264Accelerator::~VaapiH264Accelerator() {
+}
+
+scoped_refptr<H264Picture>
+VaapiVideoDecodeAccelerator::VaapiH264Accelerator::CreateH264Picture() {
+ scoped_refptr<VaapiDecodeSurface> va_surface = vaapi_dec_->CreateSurface();
+ if (!va_surface)
+ return nullptr;
+
+ return new VaapiH264Picture(va_surface);
+}
+
+// Fill |va_pic| with default/neutral values.
+static void InitVAPicture(VAPictureH264* va_pic) {
+ memset(va_pic, 0, sizeof(*va_pic));
+ va_pic->picture_id = VA_INVALID_ID;
+ va_pic->flags = VA_PICTURE_H264_INVALID;
+}
+
+bool VaapiVideoDecodeAccelerator::VaapiH264Accelerator::SubmitFrameMetadata(
+ const media::H264SPS* sps,
+ const media::H264PPS* pps,
+ const H264DPB& dpb,
+ const H264Picture::Vector& ref_pic_listp0,
+ const H264Picture::Vector& ref_pic_listb0,
+ const H264Picture::Vector& ref_pic_listb1,
+ const scoped_refptr<H264Picture>& pic) {
+ VAPictureParameterBufferH264 pic_param;
+ memset(&pic_param, 0, sizeof(pic_param));
+
+#define FROM_SPS_TO_PP(a) pic_param.a = sps->a;
+#define FROM_SPS_TO_PP2(a, b) pic_param.b = sps->a;
+ FROM_SPS_TO_PP2(pic_width_in_mbs_minus1, picture_width_in_mbs_minus1);
+ // This assumes non-interlaced video
+ FROM_SPS_TO_PP2(pic_height_in_map_units_minus1, picture_height_in_mbs_minus1);
+ FROM_SPS_TO_PP(bit_depth_luma_minus8);
+ FROM_SPS_TO_PP(bit_depth_chroma_minus8);
+#undef FROM_SPS_TO_PP
+#undef FROM_SPS_TO_PP2
+
+#define FROM_SPS_TO_PP_SF(a) pic_param.seq_fields.bits.a = sps->a;
+#define FROM_SPS_TO_PP_SF2(a, b) pic_param.seq_fields.bits.b = sps->a;
+ FROM_SPS_TO_PP_SF(chroma_format_idc);
+ FROM_SPS_TO_PP_SF2(separate_colour_plane_flag,
+ residual_colour_transform_flag);
+ FROM_SPS_TO_PP_SF(gaps_in_frame_num_value_allowed_flag);
+ FROM_SPS_TO_PP_SF(frame_mbs_only_flag);
+ FROM_SPS_TO_PP_SF(mb_adaptive_frame_field_flag);
+ FROM_SPS_TO_PP_SF(direct_8x8_inference_flag);
+ pic_param.seq_fields.bits.MinLumaBiPredSize8x8 = (sps->level_idc >= 31);
+ FROM_SPS_TO_PP_SF(log2_max_frame_num_minus4);
+ FROM_SPS_TO_PP_SF(pic_order_cnt_type);
+ FROM_SPS_TO_PP_SF(log2_max_pic_order_cnt_lsb_minus4);
+ FROM_SPS_TO_PP_SF(delta_pic_order_always_zero_flag);
+#undef FROM_SPS_TO_PP_SF
+#undef FROM_SPS_TO_PP_SF2
+
+#define FROM_PPS_TO_PP(a) pic_param.a = pps->a;
+ FROM_PPS_TO_PP(num_slice_groups_minus1);
+ pic_param.slice_group_map_type = 0;
+ pic_param.slice_group_change_rate_minus1 = 0;
+ FROM_PPS_TO_PP(pic_init_qp_minus26);
+ FROM_PPS_TO_PP(pic_init_qs_minus26);
+ FROM_PPS_TO_PP(chroma_qp_index_offset);
+ FROM_PPS_TO_PP(second_chroma_qp_index_offset);
+#undef FROM_PPS_TO_PP
+
+#define FROM_PPS_TO_PP_PF(a) pic_param.pic_fields.bits.a = pps->a;
+#define FROM_PPS_TO_PP_PF2(a, b) pic_param.pic_fields.bits.b = pps->a;
+ FROM_PPS_TO_PP_PF(entropy_coding_mode_flag);
+ FROM_PPS_TO_PP_PF(weighted_pred_flag);
+ FROM_PPS_TO_PP_PF(weighted_bipred_idc);
+ FROM_PPS_TO_PP_PF(transform_8x8_mode_flag);
+
+ pic_param.pic_fields.bits.field_pic_flag = 0;
+ FROM_PPS_TO_PP_PF(constrained_intra_pred_flag);
+ FROM_PPS_TO_PP_PF2(bottom_field_pic_order_in_frame_present_flag,
+ pic_order_present_flag);
+ FROM_PPS_TO_PP_PF(deblocking_filter_control_present_flag);
+ FROM_PPS_TO_PP_PF(redundant_pic_cnt_present_flag);
+ pic_param.pic_fields.bits.reference_pic_flag = pic->ref;
+#undef FROM_PPS_TO_PP_PF
+#undef FROM_PPS_TO_PP_PF2
+
+ pic_param.frame_num = pic->frame_num;
+
+ InitVAPicture(&pic_param.CurrPic);
+ FillVAPicture(&pic_param.CurrPic, pic);
+
+ // Init reference pictures' array.
+ for (int i = 0; i < 16; ++i)
+ InitVAPicture(&pic_param.ReferenceFrames[i]);
+
+ // And fill it with picture info from DPB.
+ FillVARefFramesFromDPB(dpb, pic_param.ReferenceFrames,
+ arraysize(pic_param.ReferenceFrames));
+
+ pic_param.num_ref_frames = sps->max_num_ref_frames;
+
+ if (!vaapi_wrapper_->SubmitBuffer(VAPictureParameterBufferType,
+ sizeof(pic_param),
+ &pic_param))
+ return false;
+
+ VAIQMatrixBufferH264 iq_matrix_buf;
+ memset(&iq_matrix_buf, 0, sizeof(iq_matrix_buf));
+
+ if (pps->pic_scaling_matrix_present_flag) {
+ for (int i = 0; i < 6; ++i) {
+ for (int j = 0; j < 16; ++j)
+ iq_matrix_buf.ScalingList4x4[i][j] = pps->scaling_list4x4[i][j];
+ }
+
+ for (int i = 0; i < 2; ++i) {
+ for (int j = 0; j < 64; ++j)
+ iq_matrix_buf.ScalingList8x8[i][j] = pps->scaling_list8x8[i][j];
+ }
+ } else {
+ for (int i = 0; i < 6; ++i) {
+ for (int j = 0; j < 16; ++j)
+ iq_matrix_buf.ScalingList4x4[i][j] = sps->scaling_list4x4[i][j];
+ }
+
+ for (int i = 0; i < 2; ++i) {
+ for (int j = 0; j < 64; ++j)
+ iq_matrix_buf.ScalingList8x8[i][j] = sps->scaling_list8x8[i][j];
+ }
+ }
+
+ return vaapi_wrapper_->SubmitBuffer(VAIQMatrixBufferType,
+ sizeof(iq_matrix_buf),
+ &iq_matrix_buf);
+}
+
+bool VaapiVideoDecodeAccelerator::VaapiH264Accelerator::SubmitSlice(
+ const media::H264PPS* pps,
+ const media::H264SliceHeader* slice_hdr,
+ const H264Picture::Vector& ref_pic_list0,
+ const H264Picture::Vector& ref_pic_list1,
+ const scoped_refptr<H264Picture>& pic,
+ const uint8_t* data,
+ size_t size) {
+ VASliceParameterBufferH264 slice_param;
+ memset(&slice_param, 0, sizeof(slice_param));
+
+ slice_param.slice_data_size = slice_hdr->nalu_size;
+ slice_param.slice_data_offset = 0;
+ slice_param.slice_data_flag = VA_SLICE_DATA_FLAG_ALL;
+ slice_param.slice_data_bit_offset = slice_hdr->header_bit_size;
+
+#define SHDRToSP(a) slice_param.a = slice_hdr->a;
+ SHDRToSP(first_mb_in_slice);
+ slice_param.slice_type = slice_hdr->slice_type % 5;
+ SHDRToSP(direct_spatial_mv_pred_flag);
+
+ // TODO posciak: make sure parser sets those even when override flags
+ // in slice header is off.
+ SHDRToSP(num_ref_idx_l0_active_minus1);
+ SHDRToSP(num_ref_idx_l1_active_minus1);
+ SHDRToSP(cabac_init_idc);
+ SHDRToSP(slice_qp_delta);
+ SHDRToSP(disable_deblocking_filter_idc);
+ SHDRToSP(slice_alpha_c0_offset_div2);
+ SHDRToSP(slice_beta_offset_div2);
+
+ if (((slice_hdr->IsPSlice() || slice_hdr->IsSPSlice()) &&
+ pps->weighted_pred_flag) ||
+ (slice_hdr->IsBSlice() && pps->weighted_bipred_idc == 1)) {
+ SHDRToSP(luma_log2_weight_denom);
+ SHDRToSP(chroma_log2_weight_denom);
+
+ SHDRToSP(luma_weight_l0_flag);
+ SHDRToSP(luma_weight_l1_flag);
+
+ SHDRToSP(chroma_weight_l0_flag);
+ SHDRToSP(chroma_weight_l1_flag);
+
+ for (int i = 0; i <= slice_param.num_ref_idx_l0_active_minus1; ++i) {
+ slice_param.luma_weight_l0[i] =
+ slice_hdr->pred_weight_table_l0.luma_weight[i];
+ slice_param.luma_offset_l0[i] =
+ slice_hdr->pred_weight_table_l0.luma_offset[i];
+
+ for (int j = 0; j < 2; ++j) {
+ slice_param.chroma_weight_l0[i][j] =
+ slice_hdr->pred_weight_table_l0.chroma_weight[i][j];
+ slice_param.chroma_offset_l0[i][j] =
+ slice_hdr->pred_weight_table_l0.chroma_offset[i][j];
+ }
+ }
+
+ if (slice_hdr->IsBSlice()) {
+ for (int i = 0; i <= slice_param.num_ref_idx_l1_active_minus1; ++i) {
+ slice_param.luma_weight_l1[i] =
+ slice_hdr->pred_weight_table_l1.luma_weight[i];
+ slice_param.luma_offset_l1[i] =
+ slice_hdr->pred_weight_table_l1.luma_offset[i];
+
+ for (int j = 0; j < 2; ++j) {
+ slice_param.chroma_weight_l1[i][j] =
+ slice_hdr->pred_weight_table_l1.chroma_weight[i][j];
+ slice_param.chroma_offset_l1[i][j] =
+ slice_hdr->pred_weight_table_l1.chroma_offset[i][j];
+ }
+ }
+ }
+ }
+
+ static_assert(
+ arraysize(slice_param.RefPicList0) == arraysize(slice_param.RefPicList1),
+ "Invalid RefPicList sizes");
+
+ for (size_t i = 0; i < arraysize(slice_param.RefPicList0); ++i) {
+ InitVAPicture(&slice_param.RefPicList0[i]);
+ InitVAPicture(&slice_param.RefPicList1[i]);
+ }
+
+ for (size_t i = 0;
+ i < ref_pic_list0.size() && i < arraysize(slice_param.RefPicList0);
+ ++i) {
+ if (ref_pic_list0[i])
+ FillVAPicture(&slice_param.RefPicList0[i], ref_pic_list0[i]);
+ }
+ for (size_t i = 0;
+ i < ref_pic_list1.size() && i < arraysize(slice_param.RefPicList1);
+ ++i) {
+ if (ref_pic_list1[i])
+ FillVAPicture(&slice_param.RefPicList1[i], ref_pic_list1[i]);
+ }
+
+ if (!vaapi_wrapper_->SubmitBuffer(VASliceParameterBufferType,
+ sizeof(slice_param),
+ &slice_param))
+ return false;
+
+ // Can't help it, blame libva...
+ void* non_const_ptr = const_cast<uint8*>(data);
+ return vaapi_wrapper_->SubmitBuffer(VASliceDataBufferType, size,
+ non_const_ptr);
+}
+
+bool VaapiVideoDecodeAccelerator::VaapiH264Accelerator::SubmitDecode(
+ const scoped_refptr<H264Picture>& pic) {
+ DVLOG(4) << "Decoding POC " << pic->pic_order_cnt;
+ scoped_refptr<VaapiDecodeSurface> dec_surface =
+ H264PictureToVaapiDecodeSurface(pic);
+
+ return vaapi_dec_->DecodeSurface(dec_surface);
+}
+
+bool VaapiVideoDecodeAccelerator::VaapiH264Accelerator::OutputPicture(
+ const scoped_refptr<H264Picture>& pic) {
+ scoped_refptr<VaapiDecodeSurface> dec_surface =
+ H264PictureToVaapiDecodeSurface(pic);
+
+ vaapi_dec_->SurfaceReady(dec_surface);
+
+ return true;
+}
+
+void VaapiVideoDecodeAccelerator::VaapiH264Accelerator::Reset() {
+ vaapi_wrapper_->DestroyPendingBuffers();
+}
+
+scoped_refptr<VaapiVideoDecodeAccelerator::VaapiDecodeSurface>
+VaapiVideoDecodeAccelerator::VaapiH264Accelerator::
+ H264PictureToVaapiDecodeSurface(const scoped_refptr<H264Picture>& pic) {
+ VaapiH264Picture* vaapi_pic = pic->AsVaapiH264Picture();
+ CHECK(vaapi_pic);
+ return vaapi_pic->dec_surface();
+}
+
+void VaapiVideoDecodeAccelerator::VaapiH264Accelerator::FillVAPicture(
+ VAPictureH264* va_pic,
+ scoped_refptr<H264Picture> pic) {
+ scoped_refptr<VaapiDecodeSurface> dec_surface =
+ H264PictureToVaapiDecodeSurface(pic);
+
+ va_pic->picture_id = dec_surface->va_surface()->id();
+ va_pic->frame_idx = pic->frame_num;
+ va_pic->flags = 0;
+
+ switch (pic->field) {
+ case H264Picture::FIELD_NONE:
+ break;
+ case H264Picture::FIELD_TOP:
+ va_pic->flags |= VA_PICTURE_H264_TOP_FIELD;
+ break;
+ case H264Picture::FIELD_BOTTOM:
+ va_pic->flags |= VA_PICTURE_H264_BOTTOM_FIELD;
+ break;
+ }
+
+ if (pic->ref) {
+ va_pic->flags |= pic->long_term ? VA_PICTURE_H264_LONG_TERM_REFERENCE
+ : VA_PICTURE_H264_SHORT_TERM_REFERENCE;
+ }
+
+ va_pic->TopFieldOrderCnt = pic->top_field_order_cnt;
+ va_pic->BottomFieldOrderCnt = pic->bottom_field_order_cnt;
+}
+
+int VaapiVideoDecodeAccelerator::VaapiH264Accelerator::FillVARefFramesFromDPB(
+ const H264DPB& dpb,
+ VAPictureH264* va_pics,
+ int num_pics) {
+ H264Picture::Vector::const_reverse_iterator rit;
+ int i;
+
+ // Return reference frames in reverse order of insertion.
+ // Libva does not document this, but other implementations (e.g. mplayer)
+ // do it this way as well.
+ for (rit = dpb.rbegin(), i = 0; rit != dpb.rend() && i < num_pics; ++rit) {
+ if ((*rit)->ref)
+ FillVAPicture(&va_pics[i++], *rit);
+ }
+
+ return i;
+}
+
+VaapiVideoDecodeAccelerator::VaapiVP8Accelerator::VaapiVP8Accelerator(
+ VaapiVideoDecodeAccelerator* vaapi_dec,
+ VaapiWrapper* vaapi_wrapper)
+ : vaapi_wrapper_(vaapi_wrapper), vaapi_dec_(vaapi_dec) {
+ DCHECK(vaapi_wrapper_);
+ DCHECK(vaapi_dec_);
+}
+
+VaapiVideoDecodeAccelerator::VaapiVP8Accelerator::~VaapiVP8Accelerator() {
+}
+
+scoped_refptr<VP8Picture>
+VaapiVideoDecodeAccelerator::VaapiVP8Accelerator::CreateVP8Picture() {
+ scoped_refptr<VaapiDecodeSurface> va_surface = vaapi_dec_->CreateSurface();
+ if (!va_surface)
+ return nullptr;
+
+ return new VaapiVP8Picture(va_surface);
+}
+
+#define ARRAY_MEMCPY_CHECKED(to, from) \
+ do { \
+ static_assert(sizeof(to) == sizeof(from), \
+ #from " and " #to " arrays must be of same size"); \
+ memcpy(to, from, sizeof(to)); \
+ } while (0)
+
+bool VaapiVideoDecodeAccelerator::VaapiVP8Accelerator::SubmitDecode(
+ const scoped_refptr<VP8Picture>& pic,
+ const media::Vp8FrameHeader* frame_hdr,
+ const scoped_refptr<VP8Picture>& last_frame,
+ const scoped_refptr<VP8Picture>& golden_frame,
+ const scoped_refptr<VP8Picture>& alt_frame) {
+ VAIQMatrixBufferVP8 iq_matrix_buf;
+ memset(&iq_matrix_buf, 0, sizeof(VAIQMatrixBufferVP8));
+
+ const media::Vp8SegmentationHeader& sgmnt_hdr = frame_hdr->segmentation_hdr;
+ const media::Vp8QuantizationHeader& quant_hdr = frame_hdr->quantization_hdr;
+ static_assert(
+ arraysize(iq_matrix_buf.quantization_index) == media::kMaxMBSegments,
+ "incorrect quantization matrix size");
+ for (size_t i = 0; i < media::kMaxMBSegments; ++i) {
+ int q = quant_hdr.y_ac_qi;
+
+ if (sgmnt_hdr.segmentation_enabled) {
+ if (sgmnt_hdr.segment_feature_mode ==
+ media::Vp8SegmentationHeader::FEATURE_MODE_ABSOLUTE)
+ q = sgmnt_hdr.quantizer_update_value[i];
+ else
+ q += sgmnt_hdr.quantizer_update_value[i];
+ }
+
+#define CLAMP_Q(q) std::min(std::max(q, 0), 127)
+ static_assert(arraysize(iq_matrix_buf.quantization_index[i]) == 6,
+ "incorrect quantization matrix size");
+ iq_matrix_buf.quantization_index[i][0] = CLAMP_Q(q);
+ iq_matrix_buf.quantization_index[i][1] = CLAMP_Q(q + quant_hdr.y_dc_delta);
+ iq_matrix_buf.quantization_index[i][2] = CLAMP_Q(q + quant_hdr.y2_dc_delta);
+ iq_matrix_buf.quantization_index[i][3] = CLAMP_Q(q + quant_hdr.y2_ac_delta);
+ iq_matrix_buf.quantization_index[i][4] = CLAMP_Q(q + quant_hdr.uv_dc_delta);
+ iq_matrix_buf.quantization_index[i][5] = CLAMP_Q(q + quant_hdr.uv_ac_delta);
+#undef CLAMP_Q
+ }
+
+ if (!vaapi_wrapper_->SubmitBuffer(VAIQMatrixBufferType,
+ sizeof(VAIQMatrixBufferVP8),
+ &iq_matrix_buf))
+ return false;
+
+ VAProbabilityDataBufferVP8 prob_buf;
+ memset(&prob_buf, 0, sizeof(VAProbabilityDataBufferVP8));
+
+ const media::Vp8EntropyHeader& entr_hdr = frame_hdr->entropy_hdr;
+ ARRAY_MEMCPY_CHECKED(prob_buf.dct_coeff_probs, entr_hdr.coeff_probs);
+
+ if (!vaapi_wrapper_->SubmitBuffer(VAProbabilityBufferType,
+ sizeof(VAProbabilityDataBufferVP8),
+ &prob_buf))
+ return false;
+
+ VAPictureParameterBufferVP8 pic_param;
+ memset(&pic_param, 0, sizeof(VAPictureParameterBufferVP8));
+ pic_param.frame_width = frame_hdr->width;
+ pic_param.frame_height = frame_hdr->height;
+
+ if (last_frame) {
+ scoped_refptr<VaapiDecodeSurface> last_frame_surface =
+ VP8PictureToVaapiDecodeSurface(last_frame);
+ pic_param.last_ref_frame = last_frame_surface->va_surface()->id();
+ } else {
+ pic_param.last_ref_frame = VA_INVALID_SURFACE;
+ }
+
+ if (golden_frame) {
+ scoped_refptr<VaapiDecodeSurface> golden_frame_surface =
+ VP8PictureToVaapiDecodeSurface(golden_frame);
+ pic_param.golden_ref_frame = golden_frame_surface->va_surface()->id();
+ } else {
+ pic_param.golden_ref_frame = VA_INVALID_SURFACE;
+ }
+
+ if (alt_frame) {
+ scoped_refptr<VaapiDecodeSurface> alt_frame_surface =
+ VP8PictureToVaapiDecodeSurface(alt_frame);
+ pic_param.alt_ref_frame = alt_frame_surface->va_surface()->id();
+ } else {
+ pic_param.alt_ref_frame = VA_INVALID_SURFACE;
+ }
+
+ pic_param.out_of_loop_frame = VA_INVALID_SURFACE;
+
+ const media::Vp8LoopFilterHeader& lf_hdr = frame_hdr->loopfilter_hdr;
+
+#define FHDR_TO_PP_PF(a, b) pic_param.pic_fields.bits.a = (b);
+ FHDR_TO_PP_PF(key_frame, frame_hdr->IsKeyframe() ? 0 : 1);
+ FHDR_TO_PP_PF(version, frame_hdr->version);
+ FHDR_TO_PP_PF(segmentation_enabled, sgmnt_hdr.segmentation_enabled);
+ FHDR_TO_PP_PF(update_mb_segmentation_map,
+ sgmnt_hdr.update_mb_segmentation_map);
+ FHDR_TO_PP_PF(update_segment_feature_data,
+ sgmnt_hdr.update_segment_feature_data);
+ FHDR_TO_PP_PF(filter_type, lf_hdr.type);
+ FHDR_TO_PP_PF(sharpness_level, lf_hdr.sharpness_level);
+ FHDR_TO_PP_PF(loop_filter_adj_enable, lf_hdr.loop_filter_adj_enable);
+ FHDR_TO_PP_PF(mode_ref_lf_delta_update, lf_hdr.mode_ref_lf_delta_update);
+ FHDR_TO_PP_PF(sign_bias_golden, frame_hdr->sign_bias_golden);
+ FHDR_TO_PP_PF(sign_bias_alternate, frame_hdr->sign_bias_alternate);
+ FHDR_TO_PP_PF(mb_no_coeff_skip, frame_hdr->mb_no_skip_coeff);
+ FHDR_TO_PP_PF(loop_filter_disable, lf_hdr.level == 0);
+#undef FHDR_TO_PP_PF
+
+ ARRAY_MEMCPY_CHECKED(pic_param.mb_segment_tree_probs, sgmnt_hdr.segment_prob);
+
+ static_assert(arraysize(sgmnt_hdr.lf_update_value) ==
+ arraysize(pic_param.loop_filter_level),
+ "loop filter level arrays mismatch");
+ for (size_t i = 0; i < arraysize(sgmnt_hdr.lf_update_value); ++i) {
+ int lf_level = lf_hdr.level;
+ if (sgmnt_hdr.segmentation_enabled) {
+ if (sgmnt_hdr.segment_feature_mode ==
+ media::Vp8SegmentationHeader::FEATURE_MODE_ABSOLUTE)
+ lf_level = sgmnt_hdr.lf_update_value[i];
+ else
+ lf_level += sgmnt_hdr.lf_update_value[i];
+ }
+
+ // Clamp to [0..63] range.
+ lf_level = std::min(std::max(lf_level, 0), 63);
+ pic_param.loop_filter_level[i] = lf_level;
+ }
+
+ static_assert(arraysize(lf_hdr.ref_frame_delta) ==
+ arraysize(pic_param.loop_filter_deltas_ref_frame) &&
+ arraysize(lf_hdr.mb_mode_delta) ==
+ arraysize(pic_param.loop_filter_deltas_mode) &&
+ arraysize(lf_hdr.ref_frame_delta) ==
+ arraysize(lf_hdr.mb_mode_delta),
+ "loop filter deltas arrays size mismatch");
+ for (size_t i = 0; i < arraysize(lf_hdr.ref_frame_delta); ++i) {
+ pic_param.loop_filter_deltas_ref_frame[i] = lf_hdr.ref_frame_delta[i];
+ pic_param.loop_filter_deltas_mode[i] = lf_hdr.mb_mode_delta[i];
+ }
+
+#define FHDR_TO_PP(a) pic_param.a = frame_hdr->a;
+ FHDR_TO_PP(prob_skip_false);
+ FHDR_TO_PP(prob_intra);
+ FHDR_TO_PP(prob_last);
+ FHDR_TO_PP(prob_gf);
+#undef FHDR_TO_PP
+
+ ARRAY_MEMCPY_CHECKED(pic_param.y_mode_probs, entr_hdr.y_mode_probs);
+ ARRAY_MEMCPY_CHECKED(pic_param.uv_mode_probs, entr_hdr.uv_mode_probs);
+ ARRAY_MEMCPY_CHECKED(pic_param.mv_probs, entr_hdr.mv_probs);
+
+ pic_param.bool_coder_ctx.range = frame_hdr->bool_dec_range;
+ pic_param.bool_coder_ctx.value = frame_hdr->bool_dec_value;
+ pic_param.bool_coder_ctx.count = frame_hdr->bool_dec_count;
+
+ if (!vaapi_wrapper_->SubmitBuffer(VAPictureParameterBufferType,
+ sizeof(VAPictureParameterBufferVP8),
+ &pic_param))
+ return false;
+
+ VASliceParameterBufferVP8 slice_param;
+ memset(&slice_param, 0, sizeof(VASliceParameterBufferVP8));
+ slice_param.slice_data_size = frame_hdr->frame_size;
+ slice_param.slice_data_offset = frame_hdr->first_part_offset;
+ slice_param.slice_data_flag = VA_SLICE_DATA_FLAG_ALL;
+ slice_param.macroblock_offset = frame_hdr->macroblock_bit_offset;
+ // Number of DCT partitions plus control partition.
+ slice_param.num_of_partitions = frame_hdr->num_of_dct_partitions + 1;
+
+ // Per VAAPI, this size only includes the size of the macroblock data in
+ // the first partition (in bytes), so we have to subtract the header size.
+ slice_param.partition_size[0] =
+ frame_hdr->first_part_size - ((frame_hdr->macroblock_bit_offset + 7) / 8);
+
+ for (size_t i = 0; i < frame_hdr->num_of_dct_partitions; ++i)
+ slice_param.partition_size[i + 1] = frame_hdr->dct_partition_sizes[i];
+
+ if (!vaapi_wrapper_->SubmitBuffer(VASliceParameterBufferType,
+ sizeof(VASliceParameterBufferVP8),
+ &slice_param))
+ return false;
+
+ void* non_const_ptr = const_cast<uint8*>(frame_hdr->data);
+ if (!vaapi_wrapper_->SubmitBuffer(VASliceDataBufferType,
+ frame_hdr->frame_size,
+ non_const_ptr))
+ return false;
+
+ scoped_refptr<VaapiDecodeSurface> dec_surface =
+ VP8PictureToVaapiDecodeSurface(pic);
+
+ return vaapi_dec_->DecodeSurface(dec_surface);
+}
+
+bool VaapiVideoDecodeAccelerator::VaapiVP8Accelerator::OutputPicture(
+ const scoped_refptr<VP8Picture>& pic) {
+ scoped_refptr<VaapiDecodeSurface> dec_surface =
+ VP8PictureToVaapiDecodeSurface(pic);
+
+ vaapi_dec_->SurfaceReady(dec_surface);
+ return true;
+}
+
+scoped_refptr<VaapiVideoDecodeAccelerator::VaapiDecodeSurface>
+VaapiVideoDecodeAccelerator::VaapiVP8Accelerator::
+ VP8PictureToVaapiDecodeSurface(const scoped_refptr<VP8Picture>& pic) {
+ VaapiVP8Picture* vaapi_pic = pic->AsVaapiVP8Picture();
+ CHECK(vaapi_pic);
+ return vaapi_pic->dec_surface();
+}
+
+// static
+media::VideoDecodeAccelerator::SupportedProfiles
+VaapiVideoDecodeAccelerator::GetSupportedProfiles() {
+ return VaapiWrapper::GetSupportedDecodeProfiles();
+}
+
} // namespace content
diff --git a/chromium/content/common/gpu/media/vaapi_video_decode_accelerator.h b/chromium/content/common/gpu/media/vaapi_video_decode_accelerator.h
index 5d65da7a4ae..268439b96bc 100644
--- a/chromium/content/common/gpu/media/vaapi_video_decode_accelerator.h
+++ b/chromium/content/common/gpu/media/vaapi_video_decode_accelerator.h
@@ -8,6 +8,7 @@
#ifndef CONTENT_COMMON_GPU_MEDIA_VAAPI_VIDEO_DECODE_ACCELERATOR_H_
#define CONTENT_COMMON_GPU_MEDIA_VAAPI_VIDEO_DECODE_ACCELERATOR_H_
+#include <list>
#include <map>
#include <queue>
#include <utility>
@@ -20,18 +21,22 @@
#include "base/message_loop/message_loop.h"
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
-#include "base/threading/non_thread_safe.h"
#include "base/threading/thread.h"
#include "content/common/content_export.h"
-#include "content/common/gpu/media/vaapi_h264_decoder.h"
#include "content/common/gpu/media/vaapi_wrapper.h"
#include "media/base/bitstream_buffer.h"
#include "media/video/picture.h"
#include "media/video/video_decode_accelerator.h"
-#include "ui/gl/gl_bindings.h"
+
+namespace gfx {
+class GLImage;
+}
namespace content {
+class AcceleratedVideoDecoder;
+class VaapiPicture;
+
// Class to provide video decode acceleration for Intel systems with hardware
// support for it, and on which libva is available.
// Decoding tasks are performed in a separate decoding thread.
@@ -43,24 +48,32 @@ namespace content {
class CONTENT_EXPORT VaapiVideoDecodeAccelerator
: public media::VideoDecodeAccelerator {
public:
+ class VaapiDecodeSurface;
+
VaapiVideoDecodeAccelerator(
- Display* x_display,
- const base::Callback<bool(void)>& make_context_current);
- virtual ~VaapiVideoDecodeAccelerator();
+ const base::Callback<bool(void)>& make_context_current,
+ const base::Callback<void(uint32, uint32, scoped_refptr<gfx::GLImage>)>&
+ bind_image);
+ ~VaapiVideoDecodeAccelerator() override;
// media::VideoDecodeAccelerator implementation.
- virtual bool Initialize(media::VideoCodecProfile profile,
- Client* client) override;
- virtual void Decode(const media::BitstreamBuffer& bitstream_buffer) override;
- virtual void AssignPictureBuffers(
+ bool Initialize(media::VideoCodecProfile profile, Client* client) override;
+ void Decode(const media::BitstreamBuffer& bitstream_buffer) override;
+ void AssignPictureBuffers(
const std::vector<media::PictureBuffer>& buffers) override;
- virtual void ReusePictureBuffer(int32 picture_buffer_id) override;
- virtual void Flush() override;
- virtual void Reset() override;
- virtual void Destroy() override;
- virtual bool CanDecodeOnIOThread() override;
+ void ReusePictureBuffer(int32 picture_buffer_id) override;
+ void Flush() override;
+ void Reset() override;
+ void Destroy() override;
+ bool CanDecodeOnIOThread() override;
+
+ static media::VideoDecodeAccelerator::SupportedProfiles
+ GetSupportedProfiles();
+
+ private:
+ class VaapiH264Accelerator;
+ class VaapiVP8Accelerator;
-private:
// Notify the client that an error has occurred and decoding cannot continue.
void NotifyError(Error error);
@@ -79,11 +92,10 @@ private:
// returned. Will also release the mapping.
void ReturnCurrInputBuffer_Locked();
- // Pass one or more output buffers to the decoder. This will sleep
- // if no buffers are available. Return true if buffers have been set up or
- // false if an early exit has been requested (due to initiated
+ // Wait for more surfaces to become available. Return true once they do or
+ // false if an early exit has been requested (due to an initiated
// reset/flush/destroy).
- bool FeedDecoderWithOutputSurfaces_Locked();
+ bool WaitForSurfaces_Locked();
// Continue decoding given input buffers and sleep waiting for input/output
// as needed. Will exit if a new set of surfaces or reset/flush/destroy
@@ -119,20 +131,13 @@ private:
// or return false on failure.
bool InitializeFBConfig();
- // Callback for the decoder to execute when it wants us to output given
- // |va_surface|.
- void SurfaceReady(int32 input_id, const scoped_refptr<VASurface>& va_surface);
-
- // Represents a texture bound to an X Pixmap for output purposes.
- class TFPPicture;
-
// Callback to be executed once we have a |va_surface| to be output and
- // an available |tfp_picture| to use for output.
- // Puts contents of |va_surface| into given |tfp_picture|, releases the
+ // an available |picture| to use for output.
+ // Puts contents of |va_surface| into given |picture|, releases the
// surface and passes the resulting picture to client for output.
void OutputPicture(const scoped_refptr<VASurface>& va_surface,
int32 input_id,
- TFPPicture* tfp_picture);
+ VaapiPicture* picture);
// Try to OutputPicture() if we have both a ready surface and picture.
void TryOutputSurface();
@@ -145,13 +150,34 @@ private:
// Initiate wait cycle for surfaces to be released before we release them
// and allocate new ones, as requested by the decoder.
void InitiateSurfaceSetChange(size_t num_pics, gfx::Size size);
+
// Check if the surfaces have been released or post ourselves for later.
void TryFinishSurfaceSetChange();
- // Client-provided X/GLX state.
- Display* x_display_;
+ //
+ // Below methods are used by accelerator implementations.
+ //
+ // Decode of |dec_surface| is ready to be submitted and all codec-specific
+ // settings are set in hardware.
+ bool DecodeSurface(const scoped_refptr<VaapiDecodeSurface>& dec_surface);
+
+ // |dec_surface| is ready to be outputted once decode is finished.
+ // This can be called before decode is actually done in hardware, and this
+ // method is responsible for maintaining the ordering, i.e. the surfaces have
+ // to be outputted in the same order as SurfaceReady is called.
+ // On Intel, we don't have to explicitly maintain the ordering however, as the
+ // driver will maintain ordering, as well as dependencies, and will process
+ // each submitted command in order, and run each command only if its
+ // dependencies are ready.
+ void SurfaceReady(const scoped_refptr<VaapiDecodeSurface>& dec_surface);
+
+ // Return a new VaapiDecodeSurface for decoding into, or nullptr if not
+ // available.
+ scoped_refptr<VaapiDecodeSurface> CreateSurface();
+
+
+ // Client-provided GL state.
base::Callback<bool(void)> make_context_current_;
- GLXFBConfig fb_config_;
// VAVDA state.
enum State {
@@ -196,13 +222,17 @@ private:
typedef std::queue<int32> OutputBuffers;
OutputBuffers output_buffers_;
- typedef std::map<int32, linked_ptr<TFPPicture> > TFPPictures;
- // All allocated TFPPictures, regardless of their current state. TFPPictures
- // are allocated once and destroyed at the end of decode.
- TFPPictures tfp_pictures_;
+ scoped_ptr<VaapiWrapper> vaapi_wrapper_;
+
+ typedef std::map<int32, linked_ptr<VaapiPicture>> Pictures;
+ // All allocated Pictures, regardless of their current state.
+ // Pictures are allocated once and destroyed at the end of decode.
+ // Comes after vaapi_wrapper_ to ensure all pictures are destroyed
+ // before vaapi_wrapper_ is destroyed.
+ Pictures pictures_;
- // Return a TFPPicture associated with given client-provided id.
- TFPPicture* TFPPictureById(int32 picture_buffer_id);
+ // Return a VaapiPicture associated with given client-provided id.
+ VaapiPicture* PictureById(int32 picture_buffer_id);
// VA Surfaces no longer in use that can be passed back to the decoder for
// reuse, once it requests them.
@@ -212,15 +242,15 @@ private:
base::ConditionVariable surfaces_available_;
// Pending output requests from the decoder. When it indicates that we should
- // output a surface and we have an available TFPPicture (i.e. texture) ready
- // to use, we'll execute the callback passing the TFPPicture. The callback
+ // output a surface and we have an available Picture (i.e. texture) ready
+ // to use, we'll execute the callback passing the Picture. The callback
// will put the contents of the surface into the picture and return it to
// the client, releasing the surface as well.
- // If we don't have any available TFPPictures at the time when the decoder
+ // If we don't have any available Pictures at the time when the decoder
// requests output, we'll store the request on pending_output_cbs_ queue for
// later and run it once the client gives us more textures
// via ReusePictureBuffer().
- typedef base::Callback<void(TFPPicture*)> OutputCB;
+ typedef base::Callback<void(VaapiPicture*)> OutputCB;
std::queue<OutputCB> pending_output_cbs_;
// ChildThread's message loop
@@ -242,16 +272,17 @@ private:
scoped_ptr<base::WeakPtrFactory<Client> > client_ptr_factory_;
base::WeakPtr<Client> client_;
- scoped_ptr<VaapiWrapper> vaapi_wrapper_;
+ // Accelerators come after vaapi_wrapper_ to ensure they are destroyed first.
+ scoped_ptr<VaapiH264Accelerator> h264_accelerator_;
+ scoped_ptr<VaapiVP8Accelerator> vp8_accelerator_;
+ // After *_accelerator_ to ensure correct destruction order.
+ scoped_ptr<AcceleratedVideoDecoder> decoder_;
- // Comes after vaapi_wrapper_ to ensure its destructor is executed before
- // vaapi_wrapper_ is destroyed.
- scoped_ptr<VaapiH264Decoder> decoder_;
base::Thread decoder_thread_;
// Use this to post tasks to |decoder_thread_| instead of
// |decoder_thread_.message_loop()| because the latter will be NULL once
// |decoder_thread_.Stop()| returns.
- scoped_refptr<base::MessageLoopProxy> decoder_thread_proxy_;
+ scoped_refptr<base::SingleThreadTaskRunner> decoder_thread_task_runner_;
int num_frames_at_client_;
int num_stream_bufs_at_decoder_;
@@ -268,6 +299,10 @@ private:
size_t requested_num_pics_;
gfx::Size requested_pic_size_;
+ // Binds the provided GLImage to a givenr client texture ID & texture target
+ // combination in GLES.
+ base::Callback<void(uint32, uint32, scoped_refptr<gfx::GLImage>)> bind_image_;
+
// The WeakPtrFactory for |weak_this_|.
base::WeakPtrFactory<VaapiVideoDecodeAccelerator> weak_this_factory_;
diff --git a/chromium/content/common/gpu/media/vaapi_video_encode_accelerator.cc b/chromium/content/common/gpu/media/vaapi_video_encode_accelerator.cc
index 19e1c0820dd..cdd03a156fb 100644
--- a/chromium/content/common/gpu/media/vaapi_video_encode_accelerator.cc
+++ b/chromium/content/common/gpu/media/vaapi_video_encode_accelerator.cc
@@ -6,12 +6,9 @@
#include "base/bind.h"
#include "base/callback.h"
-#include "base/command_line.h"
-#include "base/message_loop/message_loop_proxy.h"
#include "base/metrics/histogram.h"
#include "base/numerics/safe_conversions.h"
#include "content/common/gpu/media/h264_dpb.h"
-#include "content/public/common/content_switches.h"
#include "media/base/bind_to_current_loop.h"
#include "third_party/libva/va/va_enc_h264.h"
@@ -47,9 +44,10 @@ const size_t kMaxNumReferenceFrames = 4;
const size_t kNumSurfaces = kMaxNumReferenceFrames + kMinSurfacesToEncode +
kMinSurfacesToEncode * (kNumInputBuffers - 1);
-// An IDR every 128 frames, an I frame every 30 and no B frames.
-const int kIDRPeriod = 128;
-const int kIPeriod = 30;
+// An IDR every 2048 frames, an I frame every 256 and no B frames.
+// We choose IDR period to equal MaxFrameNum so it must be a power of 2.
+const int kIDRPeriod = 2048;
+const int kIPeriod = 256;
const int kIPPeriod = 1;
const int kDefaultFramerate = 30;
@@ -104,27 +102,9 @@ struct VaapiVideoEncodeAccelerator::BitstreamBufferRef {
const size_t size;
};
-std::vector<media::VideoEncodeAccelerator::SupportedProfile>
+media::VideoEncodeAccelerator::SupportedProfiles
VaapiVideoEncodeAccelerator::GetSupportedProfiles() {
- std::vector<SupportedProfile> profiles;
-
- const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
- if (cmd_line->HasSwitch(switches::kDisableVaapiAcceleratedVideoEncode))
- return profiles;
-
- std::vector<media::VideoCodecProfile> hw_profiles =
- VaapiWrapper::GetSupportedEncodeProfiles(
- x_display_, base::Bind(&base::DoNothing));
-
- media::VideoEncodeAccelerator::SupportedProfile profile;
- profile.max_resolution.SetSize(1920, 1088);
- profile.max_framerate_numerator = kDefaultFramerate;
- profile.max_framerate_denominator = 1;
- for (size_t i = 0; i < hw_profiles.size(); i++) {
- profile.profile = hw_profiles[i];
- profiles.push_back(profile);
- }
- return profiles;
+ return VaapiWrapper::GetSupportedEncodeProfiles();
}
static unsigned int Log2OfPowerOf2(unsigned int x) {
@@ -132,28 +112,27 @@ static unsigned int Log2OfPowerOf2(unsigned int x) {
DCHECK_EQ(x & (x - 1), 0u);
int log = 0;
- while (x) {
+ while (x > 1) {
x >>= 1;
++log;
}
return log;
}
-VaapiVideoEncodeAccelerator::VaapiVideoEncodeAccelerator(Display* x_display)
+VaapiVideoEncodeAccelerator::VaapiVideoEncodeAccelerator()
: profile_(media::VIDEO_CODEC_PROFILE_UNKNOWN),
mb_width_(0),
mb_height_(0),
output_buffer_byte_size_(0),
- x_display_(x_display),
state_(kUninitialized),
frame_num_(0),
- last_idr_frame_num_(0),
+ idr_pic_id_(0),
bitrate_(0),
framerate_(0),
cpb_size_(0),
encoding_parameters_changed_(false),
encoder_thread_("VAVEAEncoderThread"),
- child_message_loop_proxy_(base::MessageLoopProxy::current()),
+ child_task_runner_(base::ThreadTaskRunnerHandle::Get()),
weak_this_ptr_factory_(this) {
DVLOGF(4);
weak_this_ = weak_this_ptr_factory_.GetWeakPtr();
@@ -167,7 +146,7 @@ VaapiVideoEncodeAccelerator::VaapiVideoEncodeAccelerator(Display* x_display)
VaapiVideoEncodeAccelerator::~VaapiVideoEncodeAccelerator() {
DVLOGF(4);
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
DCHECK(!encoder_thread_.IsRunning());
}
@@ -177,7 +156,7 @@ bool VaapiVideoEncodeAccelerator::Initialize(
media::VideoCodecProfile output_profile,
uint32 initial_bitrate,
Client* client) {
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
DCHECK(!encoder_thread_.IsRunning());
DCHECK_EQ(state_, kUninitialized);
@@ -215,12 +194,11 @@ bool VaapiVideoEncodeAccelerator::Initialize(
UpdateRates(initial_bitrate, kDefaultFramerate);
- vaapi_wrapper_ = VaapiWrapper::Create(VaapiWrapper::kEncode,
- output_profile,
- x_display_,
+ vaapi_wrapper_ =
+ VaapiWrapper::CreateForVideoCodec(VaapiWrapper::kEncode, output_profile,
base::Bind(&ReportToUMA, VAAPI_ERROR));
- if (!vaapi_wrapper_) {
- LOG(ERROR) << "Failed initializing VAAPI";
+ if (!vaapi_wrapper_.get()) {
+ DVLOGF(1) << "Failed initializing VAAPI for profile " << output_profile;
return false;
}
@@ -228,19 +206,18 @@ bool VaapiVideoEncodeAccelerator::Initialize(
LOG(ERROR) << "Failed to start encoder thread";
return false;
}
- encoder_thread_proxy_ = encoder_thread_.message_loop_proxy();
+ encoder_thread_task_runner_ = encoder_thread_.task_runner();
// Finish the remaining initialization on the encoder thread.
- encoder_thread_proxy_->PostTask(
- FROM_HERE,
- base::Bind(&VaapiVideoEncodeAccelerator::InitializeTask,
- base::Unretained(this)));
+ encoder_thread_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&VaapiVideoEncodeAccelerator::InitializeTask,
+ base::Unretained(this)));
return true;
}
void VaapiVideoEncodeAccelerator::InitializeTask() {
- DCHECK(encoder_thread_proxy_->BelongsToCurrentThread());
+ DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread());
DCHECK_EQ(state_, kUninitialized);
DVLOGF(4);
@@ -260,13 +237,10 @@ void VaapiVideoEncodeAccelerator::InitializeTask() {
UpdatePPS();
GeneratePackedPPS();
- child_message_loop_proxy_->PostTask(
+ child_task_runner_->PostTask(
FROM_HERE,
- base::Bind(&Client::RequireBitstreamBuffers,
- client_,
- kNumInputBuffers,
- coded_size_,
- output_buffer_byte_size_));
+ base::Bind(&Client::RequireBitstreamBuffers, client_, kNumInputBuffers,
+ coded_size_, output_buffer_byte_size_));
SetState(kEncoding);
}
@@ -274,48 +248,54 @@ void VaapiVideoEncodeAccelerator::InitializeTask() {
void VaapiVideoEncodeAccelerator::RecycleVASurfaceID(
VASurfaceID va_surface_id) {
DVLOGF(4) << "va_surface_id: " << va_surface_id;
- DCHECK(encoder_thread_proxy_->BelongsToCurrentThread());
+ DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread());
available_va_surface_ids_.push_back(va_surface_id);
EncodeFrameTask();
}
void VaapiVideoEncodeAccelerator::BeginFrame(bool force_keyframe) {
- memset(&current_pic_, 0, sizeof(current_pic_));
+ current_pic_ = new H264Picture();
- current_pic_.frame_num = frame_num_++;
- frame_num_ %= idr_period_;
+ // If the current picture is an IDR picture, frame_num shall be equal to 0.
+ if (force_keyframe)
+ frame_num_ = 0;
- if (current_pic_.frame_num % i_period_ == 0 || force_keyframe)
- current_pic_.type = media::H264SliceHeader::kISlice;
- else
- current_pic_.type = media::H264SliceHeader::kPSlice;
+ current_pic_->frame_num = frame_num_++;
+ frame_num_ %= idr_period_;
- if (current_pic_.frame_num % idr_period_ == 0 || force_keyframe) {
- current_pic_.idr = true;
- last_idr_frame_num_ = current_pic_.frame_num;
+ if (current_pic_->frame_num == 0) {
+ current_pic_->idr = true;
+ // H264 spec mandates idr_pic_id to differ between two consecutive IDRs.
+ idr_pic_id_ ^= 1;
ref_pic_list0_.clear();
}
- if (current_pic_.type != media::H264SliceHeader::kBSlice)
- current_pic_.ref = true;
+ if (current_pic_->frame_num % i_period_ == 0)
+ current_pic_->type = media::H264SliceHeader::kISlice;
+ else
+ current_pic_->type = media::H264SliceHeader::kPSlice;
- current_pic_.pic_order_cnt = current_pic_.frame_num * 2;
- current_pic_.top_field_order_cnt = current_pic_.pic_order_cnt;
- current_pic_.pic_order_cnt_lsb = current_pic_.pic_order_cnt;
+ if (current_pic_->type != media::H264SliceHeader::kBSlice)
+ current_pic_->ref = true;
- current_encode_job_->keyframe = current_pic_.idr;
+ current_pic_->pic_order_cnt = current_pic_->frame_num * 2;
+ current_pic_->top_field_order_cnt = current_pic_->pic_order_cnt;
+ current_pic_->pic_order_cnt_lsb = current_pic_->pic_order_cnt;
- DVLOGF(4) << "Starting a new frame, type: " << current_pic_.type
+ current_encode_job_->keyframe = current_pic_->idr;
+
+ DVLOGF(4) << "Starting a new frame, type: " << current_pic_->type
<< (force_keyframe ? " (forced keyframe)" : "")
- << " frame_num: " << current_pic_.frame_num
- << " POC: " << current_pic_.pic_order_cnt;
+ << " frame_num: " << current_pic_->frame_num
+ << " POC: " << current_pic_->pic_order_cnt;
}
void VaapiVideoEncodeAccelerator::EndFrame() {
+ DCHECK(current_pic_);
// Store the picture on the list of reference pictures and keep the list
// below maximum size, dropping oldest references.
- if (current_pic_.ref)
+ if (current_pic_->ref)
ref_pic_list0_.push_front(current_encode_job_->recon_surface);
size_t max_num_ref_frames =
base::checked_cast<size_t>(current_sps_.max_num_ref_frames);
@@ -332,6 +312,7 @@ static void InitVAPicture(VAPictureH264* va_pic) {
}
bool VaapiVideoEncodeAccelerator::SubmitFrameParameters() {
+ DCHECK(current_pic_);
VAEncSequenceParameterBufferH264 seq_param;
memset(&seq_param, 0, sizeof(seq_param));
@@ -384,8 +365,8 @@ bool VaapiVideoEncodeAccelerator::SubmitFrameParameters() {
memset(&pic_param, 0, sizeof(pic_param));
pic_param.CurrPic.picture_id = current_encode_job_->recon_surface->id();
- pic_param.CurrPic.TopFieldOrderCnt = current_pic_.top_field_order_cnt;
- pic_param.CurrPic.BottomFieldOrderCnt = current_pic_.bottom_field_order_cnt;
+ pic_param.CurrPic.TopFieldOrderCnt = current_pic_->top_field_order_cnt;
+ pic_param.CurrPic.BottomFieldOrderCnt = current_pic_->bottom_field_order_cnt;
pic_param.CurrPic.flags = 0;
for (size_t i = 0; i < arraysize(pic_param.ReferenceFrames); ++i)
@@ -403,11 +384,11 @@ bool VaapiVideoEncodeAccelerator::SubmitFrameParameters() {
pic_param.coded_buf = current_encode_job_->coded_buffer;
pic_param.pic_parameter_set_id = current_pps_.pic_parameter_set_id;
pic_param.seq_parameter_set_id = current_pps_.seq_parameter_set_id;
- pic_param.frame_num = current_pic_.frame_num;
+ pic_param.frame_num = current_pic_->frame_num;
pic_param.pic_init_qp = qp_;
pic_param.num_ref_idx_l0_active_minus1 = max_ref_idx_l0_size_ - 1;
- pic_param.pic_fields.bits.idr_pic_flag = current_pic_.idr;
- pic_param.pic_fields.bits.reference_pic_flag = current_pic_.ref;
+ pic_param.pic_fields.bits.idr_pic_flag = current_pic_->idr;
+ pic_param.pic_fields.bits.reference_pic_flag = current_pic_->ref;
#define PPS_TO_PP_PF(a) pic_param.pic_fields.bits.a = current_pps_.a;
PPS_TO_PP_PF(entropy_coding_mode_flag);
PPS_TO_PP_PF(transform_8x8_mode_flag);
@@ -424,10 +405,10 @@ bool VaapiVideoEncodeAccelerator::SubmitFrameParameters() {
slice_param.num_macroblocks = mb_width_ * mb_height_;
slice_param.macroblock_info = VA_INVALID_ID;
- slice_param.slice_type = current_pic_.type;
+ slice_param.slice_type = current_pic_->type;
slice_param.pic_parameter_set_id = current_pps_.pic_parameter_set_id;
- slice_param.idr_pic_id = last_idr_frame_num_;
- slice_param.pic_order_cnt_lsb = current_pic_.pic_order_cnt_lsb;
+ slice_param.idr_pic_id = idr_pic_id_;
+ slice_param.pic_order_cnt_lsb = current_pic_->pic_order_cnt_lsb;
slice_param.num_ref_idx_active_override_flag = true;
for (size_t i = 0; i < arraysize(slice_param.RefPicList0); ++i)
@@ -487,7 +468,8 @@ bool VaapiVideoEncodeAccelerator::SubmitFrameParameters() {
}
bool VaapiVideoEncodeAccelerator::SubmitHeadersIfNeeded() {
- if (current_pic_.type != media::H264SliceHeader::kISlice)
+ DCHECK(current_pic_);
+ if (current_pic_->type != media::H264SliceHeader::kISlice)
return true;
// Submit PPS.
@@ -525,7 +507,8 @@ bool VaapiVideoEncodeAccelerator::SubmitHeadersIfNeeded() {
}
bool VaapiVideoEncodeAccelerator::ExecuteEncode() {
- DVLOGF(3) << "Encoding frame_num: " << current_pic_.frame_num;
+ DCHECK(current_pic_);
+ DVLOGF(3) << "Encoding frame_num: " << current_pic_->frame_num;
return vaapi_wrapper_->ExecuteAndDestroyPendingBuffers(
current_encode_job_->input_surface->id());
}
@@ -537,7 +520,7 @@ bool VaapiVideoEncodeAccelerator::UploadFrame(
}
void VaapiVideoEncodeAccelerator::TryToReturnBitstreamBuffer() {
- DCHECK(encoder_thread_proxy_->BelongsToCurrentThread());
+ DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread());
if (state_ != kEncoding)
return;
@@ -568,12 +551,9 @@ void VaapiVideoEncodeAccelerator::TryToReturnBitstreamBuffer() {
<< (encode_job->keyframe ? "(keyframe)" : "")
<< " id: " << buffer->id << " size: " << data_size;
- child_message_loop_proxy_->PostTask(FROM_HERE,
- base::Bind(&Client::BitstreamBufferReady,
- client_,
- buffer->id,
- data_size,
- encode_job->keyframe));
+ child_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&Client::BitstreamBufferReady, client_, buffer->id,
+ data_size, encode_job->keyframe));
}
void VaapiVideoEncodeAccelerator::Encode(
@@ -581,14 +561,11 @@ void VaapiVideoEncodeAccelerator::Encode(
bool force_keyframe) {
DVLOGF(3) << "Frame timestamp: " << frame->timestamp().InMilliseconds()
<< " force_keyframe: " << force_keyframe;
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
- encoder_thread_proxy_->PostTask(
- FROM_HERE,
- base::Bind(&VaapiVideoEncodeAccelerator::EncodeTask,
- base::Unretained(this),
- frame,
- force_keyframe));
+ encoder_thread_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&VaapiVideoEncodeAccelerator::EncodeTask,
+ base::Unretained(this), frame, force_keyframe));
}
bool VaapiVideoEncodeAccelerator::PrepareNextJob() {
@@ -604,12 +581,12 @@ bool VaapiVideoEncodeAccelerator::PrepareNextJob() {
return false;
}
- current_encode_job_->input_surface =
- new VASurface(available_va_surface_ids_.back(), va_surface_release_cb_);
+ current_encode_job_->input_surface = new VASurface(
+ available_va_surface_ids_.back(), coded_size_, va_surface_release_cb_);
available_va_surface_ids_.pop_back();
- current_encode_job_->recon_surface =
- new VASurface(available_va_surface_ids_.back(), va_surface_release_cb_);
+ current_encode_job_->recon_surface = new VASurface(
+ available_va_surface_ids_.back(), coded_size_, va_surface_release_cb_);
available_va_surface_ids_.pop_back();
// Reference surfaces are needed until the job is done, but they get
@@ -623,7 +600,7 @@ bool VaapiVideoEncodeAccelerator::PrepareNextJob() {
void VaapiVideoEncodeAccelerator::EncodeTask(
const scoped_refptr<media::VideoFrame>& frame,
bool force_keyframe) {
- DCHECK(encoder_thread_proxy_->BelongsToCurrentThread());
+ DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread());
DCHECK_NE(state_, kUninitialized);
encoder_input_queue_.push(
@@ -632,7 +609,7 @@ void VaapiVideoEncodeAccelerator::EncodeTask(
}
void VaapiVideoEncodeAccelerator::EncodeFrameTask() {
- DCHECK(encoder_thread_proxy_->BelongsToCurrentThread());
+ DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread());
if (state_ != kEncoding || encoder_input_queue_.empty())
return;
@@ -675,7 +652,7 @@ void VaapiVideoEncodeAccelerator::EncodeFrameTask() {
void VaapiVideoEncodeAccelerator::UseOutputBitstreamBuffer(
const media::BitstreamBuffer& buffer) {
DVLOGF(4) << "id: " << buffer.id();
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
if (buffer.size() < output_buffer_byte_size_) {
NOTIFY_ERROR(kInvalidArgumentError, "Provided bitstream buffer too small");
@@ -692,16 +669,15 @@ void VaapiVideoEncodeAccelerator::UseOutputBitstreamBuffer(
scoped_ptr<BitstreamBufferRef> buffer_ref(
new BitstreamBufferRef(buffer.id(), shm.Pass(), buffer.size()));
- encoder_thread_proxy_->PostTask(
+ encoder_thread_task_runner_->PostTask(
FROM_HERE,
base::Bind(&VaapiVideoEncodeAccelerator::UseOutputBitstreamBufferTask,
- base::Unretained(this),
- base::Passed(&buffer_ref)));
+ base::Unretained(this), base::Passed(&buffer_ref)));
}
void VaapiVideoEncodeAccelerator::UseOutputBitstreamBufferTask(
scoped_ptr<BitstreamBufferRef> buffer_ref) {
- DCHECK(encoder_thread_proxy_->BelongsToCurrentThread());
+ DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread());
DCHECK_NE(state_, kUninitialized);
available_bitstream_buffers_.push(make_linked_ptr(buffer_ref.release()));
@@ -712,21 +688,19 @@ void VaapiVideoEncodeAccelerator::RequestEncodingParametersChange(
uint32 bitrate,
uint32 framerate) {
DVLOGF(2) << "bitrate: " << bitrate << " framerate: " << framerate;
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
- encoder_thread_proxy_->PostTask(
+ encoder_thread_task_runner_->PostTask(
FROM_HERE,
base::Bind(
&VaapiVideoEncodeAccelerator::RequestEncodingParametersChangeTask,
- base::Unretained(this),
- bitrate,
- framerate));
+ base::Unretained(this), bitrate, framerate));
}
void VaapiVideoEncodeAccelerator::UpdateRates(uint32 bitrate,
uint32 framerate) {
if (encoder_thread_.IsRunning())
- DCHECK(encoder_thread_proxy_->BelongsToCurrentThread());
+ DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread());
DCHECK_NE(bitrate, 0u);
DCHECK_NE(framerate, 0u);
bitrate_ = bitrate;
@@ -738,7 +712,7 @@ void VaapiVideoEncodeAccelerator::RequestEncodingParametersChangeTask(
uint32 bitrate,
uint32 framerate) {
DVLOGF(2) << "bitrate: " << bitrate << " framerate: " << framerate;
- DCHECK(encoder_thread_proxy_->BelongsToCurrentThread());
+ DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread());
DCHECK_NE(state_, kUninitialized);
// This is a workaround to zero being temporarily, as part of the initial
@@ -751,6 +725,9 @@ void VaapiVideoEncodeAccelerator::RequestEncodingParametersChangeTask(
if (framerate < 1)
framerate = 1;
+ if (bitrate_ == bitrate && framerate_ == framerate)
+ return;
+
UpdateRates(bitrate, framerate);
UpdateSPS();
@@ -761,7 +738,7 @@ void VaapiVideoEncodeAccelerator::RequestEncodingParametersChangeTask(
}
void VaapiVideoEncodeAccelerator::Destroy() {
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK(child_task_runner_->BelongsToCurrentThread());
// Can't call client anymore after Destroy() returns.
client_ptr_factory_.reset();
@@ -781,7 +758,7 @@ void VaapiVideoEncodeAccelerator::Destroy() {
void VaapiVideoEncodeAccelerator::DestroyTask() {
DVLOGF(2);
- DCHECK(encoder_thread_proxy_->BelongsToCurrentThread());
+ DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread());
SetState(kError);
}
@@ -966,7 +943,23 @@ void VaapiVideoEncodeAccelerator::GeneratePackedSPS() {
packed_sps_.AppendBool(current_sps_.low_delay_hrd_flag);
packed_sps_.AppendBool(false); // pic_struct_present_flag
- packed_sps_.AppendBool(false); // bitstream_restriction_flag
+ packed_sps_.AppendBool(true); // bitstream_restriction_flag
+
+ packed_sps_.AppendBool(false); // motion_vectors_over_pic_boundaries_flag
+ packed_sps_.AppendUE(2); // max_bytes_per_pic_denom
+ packed_sps_.AppendUE(1); // max_bits_per_mb_denom
+ packed_sps_.AppendUE(16); // log2_max_mv_length_horizontal
+ packed_sps_.AppendUE(16); // log2_max_mv_length_vertical
+
+ // Explicitly set max_num_reorder_frames to 0 to allow the decoder to
+ // output pictures early.
+ packed_sps_.AppendUE(0); // max_num_reorder_frames
+
+ // The value of max_dec_frame_buffering shall be greater than or equal to
+ // max_num_ref_frames.
+ const unsigned int max_dec_frame_buffering =
+ current_sps_.max_num_ref_frames;
+ packed_sps_.AppendUE(max_dec_frame_buffering);
}
packed_sps_.FinishNALU();
@@ -1029,12 +1022,10 @@ void VaapiVideoEncodeAccelerator::GeneratePackedPPS() {
void VaapiVideoEncodeAccelerator::SetState(State state) {
// Only touch state on encoder thread, unless it's not running.
if (encoder_thread_.IsRunning() &&
- !encoder_thread_proxy_->BelongsToCurrentThread()) {
- encoder_thread_proxy_->PostTask(
- FROM_HERE,
- base::Bind(&VaapiVideoEncodeAccelerator::SetState,
- base::Unretained(this),
- state));
+ !encoder_thread_task_runner_->BelongsToCurrentThread()) {
+ encoder_thread_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&VaapiVideoEncodeAccelerator::SetState,
+ base::Unretained(this), state));
return;
}
@@ -1043,11 +1034,10 @@ void VaapiVideoEncodeAccelerator::SetState(State state) {
}
void VaapiVideoEncodeAccelerator::NotifyError(Error error) {
- if (!child_message_loop_proxy_->BelongsToCurrentThread()) {
- child_message_loop_proxy_->PostTask(
- FROM_HERE,
- base::Bind(
- &VaapiVideoEncodeAccelerator::NotifyError, weak_this_, error));
+ if (!child_task_runner_->BelongsToCurrentThread()) {
+ child_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&VaapiVideoEncodeAccelerator::NotifyError,
+ weak_this_, error));
return;
}
diff --git a/chromium/content/common/gpu/media/vaapi_video_encode_accelerator.h b/chromium/content/common/gpu/media/vaapi_video_encode_accelerator.h
index 520228cbc1e..8a5cf7f5aa1 100644
--- a/chromium/content/common/gpu/media/vaapi_video_encode_accelerator.h
+++ b/chromium/content/common/gpu/media/vaapi_video_encode_accelerator.h
@@ -25,24 +25,23 @@ namespace content {
class CONTENT_EXPORT VaapiVideoEncodeAccelerator
: public media::VideoEncodeAccelerator {
public:
- explicit VaapiVideoEncodeAccelerator(Display* x_display);
- virtual ~VaapiVideoEncodeAccelerator();
+ VaapiVideoEncodeAccelerator();
+ ~VaapiVideoEncodeAccelerator() override;
// media::VideoEncodeAccelerator implementation.
- virtual std::vector<media::VideoEncodeAccelerator::SupportedProfile>
- GetSupportedProfiles() override;
- virtual bool Initialize(media::VideoFrame::Format format,
- const gfx::Size& input_visible_size,
- media::VideoCodecProfile output_profile,
- uint32 initial_bitrate,
- Client* client) override;
- virtual void Encode(const scoped_refptr<media::VideoFrame>& frame,
- bool force_keyframe) override;
- virtual void UseOutputBitstreamBuffer(
- const media::BitstreamBuffer& buffer) override;
- virtual void RequestEncodingParametersChange(uint32 bitrate,
- uint32 framerate) override;
- virtual void Destroy() override;
+ media::VideoEncodeAccelerator::SupportedProfiles GetSupportedProfiles()
+ override;
+ bool Initialize(media::VideoFrame::Format format,
+ const gfx::Size& input_visible_size,
+ media::VideoCodecProfile output_profile,
+ uint32 initial_bitrate,
+ Client* client) override;
+ void Encode(const scoped_refptr<media::VideoFrame>& frame,
+ bool force_keyframe) override;
+ void UseOutputBitstreamBuffer(const media::BitstreamBuffer& buffer) override;
+ void RequestEncodingParametersChange(uint32 bitrate,
+ uint32 framerate) override;
+ void Destroy() override;
private:
// Reference picture list.
@@ -178,8 +177,6 @@ class CONTENT_EXPORT VaapiVideoEncodeAccelerator
// Size in bytes required for input bitstream buffers.
size_t output_buffer_byte_size_;
- Display* x_display_;
-
// All of the members below must be accessed on the encoder_thread_,
// while it is running.
@@ -188,8 +185,8 @@ class CONTENT_EXPORT VaapiVideoEncodeAccelerator
// frame_num to be used for the next frame.
unsigned int frame_num_;
- // frame_num of the previous IDR.
- unsigned int last_idr_frame_num_;
+ // idr_pic_id to be used for the next frame.
+ unsigned int idr_pic_id_;
// Current bitrate in bps.
unsigned int bitrate_;
@@ -213,7 +210,7 @@ class CONTENT_EXPORT VaapiVideoEncodeAccelerator
media::H264BitstreamBuffer packed_pps_;
// Picture currently being prepared for encode.
- H264Picture current_pic_;
+ scoped_refptr<H264Picture> current_pic_;
// VA surfaces available for reuse.
std::vector<VASurfaceID> available_va_surface_ids_;
@@ -238,13 +235,13 @@ class CONTENT_EXPORT VaapiVideoEncodeAccelerator
// Encoder thread. All tasks are executed on it.
base::Thread encoder_thread_;
- scoped_refptr<base::MessageLoopProxy> encoder_thread_proxy_;
+ scoped_refptr<base::SingleThreadTaskRunner> encoder_thread_task_runner_;
- const scoped_refptr<base::MessageLoopProxy> child_message_loop_proxy_;
+ const scoped_refptr<base::SingleThreadTaskRunner> child_task_runner_;
// To expose client callbacks from VideoEncodeAccelerator.
// NOTE: all calls to these objects *MUST* be executed on
- // child_message_loop_proxy_.
+ // child_task_runner_.
scoped_ptr<base::WeakPtrFactory<Client> > client_ptr_factory_;
base::WeakPtr<Client> client_;
diff --git a/chromium/content/common/gpu/media/vaapi_wrapper.cc b/chromium/content/common/gpu/media/vaapi_wrapper.cc
index 2b4b33349aa..f2d21e5fa32 100644
--- a/chromium/content/common/gpu/media/vaapi_wrapper.cc
+++ b/chromium/content/common/gpu/media/vaapi_wrapper.cc
@@ -8,20 +8,33 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
+#include "base/command_line.h"
#include "base/logging.h"
#include "base/numerics/safe_conversions.h"
+#include "base/sys_info.h"
// Auto-generated for dlopen libva libraries
#include "content/common/gpu/media/va_stubs.h"
+#include "content/common/gpu/media/vaapi_picture.h"
+#include "content/public/common/content_switches.h"
#include "third_party/libyuv/include/libyuv.h"
+#include "ui/gl/gl_bindings.h"
+#if defined(USE_X11)
+#include "ui/gfx/x/x11_types.h"
+#elif defined(USE_OZONE)
+#include "third_party/libva/va/drm/va_drm.h"
+#include "ui/ozone/public/ozone_platform.h"
+#include "ui/ozone/public/surface_factory_ozone.h"
+#endif // USE_X11
using content_common_gpu_media::kModuleVa;
+#if defined(USE_X11)
+using content_common_gpu_media::kModuleVa_x11;
+#elif defined(USE_OZONE)
+using content_common_gpu_media::kModuleVa_drm;
+#endif // USE_X11
using content_common_gpu_media::InitializeStubs;
using content_common_gpu_media::StubPathMap;
-// libva-x11 depends on libva, so dlopen libva-x11 is enough
-static const base::FilePath::CharType kVaLib[] =
- FILE_PATH_LITERAL("libva-x11.so.1");
-
#define LOG_VA_ERROR_AND_REPORT(va_error, err_msg) \
do { \
LOG(ERROR) << err_msg \
@@ -45,6 +58,16 @@ static const base::FilePath::CharType kVaLib[] =
namespace content {
+// Maximum framerate of encoded profile. This value is an arbitary limit
+// and not taken from HW documentation.
+const int kMaxEncoderFramerate = 30;
+
+base::LazyInstance<VaapiWrapper::VADisplayState>
+ VaapiWrapper::va_display_state_ = LAZY_INSTANCE_INITIALIZER;
+
+base::LazyInstance<VaapiWrapper::LazyProfileInfos>
+ VaapiWrapper::profile_infos_ = LAZY_INSTANCE_INITIALIZER;
+
// Config attributes common for both encode and decode.
static const VAConfigAttrib kCommonVAConfigAttribs[] = {
{VAConfigAttribRTFormat, VA_RT_FORMAT_YUV420},
@@ -69,6 +92,7 @@ static const ProfileMap kProfileMap[] = {
// TODO(posciak): See if we can/want support other variants of
// media::H264PROFILE_HIGH*.
{media::H264PROFILE_HIGH, VAProfileH264High},
+ {media::VP8PROFILE_ANY, VAProfileVP8Version0_3},
};
static std::vector<VAConfigAttrib> GetRequiredAttribs(
@@ -87,44 +111,10 @@ static std::vector<VAConfigAttrib> GetRequiredAttribs(
return required_attribs;
}
-// Maps Profile enum values to VaProfile values.
-static VAProfile ProfileToVAProfile(
- media::VideoCodecProfile profile,
- const std::vector<VAProfile>& supported_profiles) {
-
- VAProfile va_profile = VAProfileNone;
- for (size_t i = 0; i < arraysize(kProfileMap); i++) {
- if (kProfileMap[i].profile == profile) {
- va_profile = kProfileMap[i].va_profile;
- break;
- }
- }
-
- bool supported = std::find(supported_profiles.begin(),
- supported_profiles.end(),
- va_profile) != supported_profiles.end();
-
- if (!supported && va_profile == VAProfileH264Baseline) {
- // crbug.com/345569: media::ProfileIDToVideoCodecProfile() currently strips
- // the information whether the profile is constrained or not, so we have no
- // way to know here. Try for baseline first, but if it is not supported,
- // try constrained baseline and hope this is what it actually is
- // (which in practice is true for a great majority of cases).
- if (std::find(supported_profiles.begin(),
- supported_profiles.end(),
- VAProfileH264ConstrainedBaseline) !=
- supported_profiles.end()) {
- va_profile = VAProfileH264ConstrainedBaseline;
- DVLOG(1) << "Falling back to constrained baseline profile.";
- }
- }
-
- return va_profile;
-}
-
-VASurface::VASurface(VASurfaceID va_surface_id, const ReleaseCB& release_cb)
- : va_surface_id_(va_surface_id),
- release_cb_(release_cb) {
+VASurface::VASurface(VASurfaceID va_surface_id,
+ const gfx::Size& size,
+ const ReleaseCB& release_cb)
+ : va_surface_id_(va_surface_id), size_(size), release_cb_(release_cb) {
DCHECK(!release_cb_.is_null());
}
@@ -135,60 +125,108 @@ VASurface::~VASurface() {
VaapiWrapper::VaapiWrapper()
: va_display_(NULL),
va_config_id_(VA_INVALID_ID),
- va_context_id_(VA_INVALID_ID) {
+ va_context_id_(VA_INVALID_ID),
+ va_vpp_config_id_(VA_INVALID_ID),
+ va_vpp_context_id_(VA_INVALID_ID),
+ va_vpp_buffer_id_(VA_INVALID_ID) {
+ va_lock_ = va_display_state_.Get().va_lock();
}
VaapiWrapper::~VaapiWrapper() {
DestroyPendingBuffers();
DestroyCodedBuffers();
DestroySurfaces();
+ DeinitializeVpp();
Deinitialize();
}
+// static
scoped_ptr<VaapiWrapper> VaapiWrapper::Create(
CodecMode mode,
- media::VideoCodecProfile profile,
- Display* x_display,
+ VAProfile va_profile,
const base::Closure& report_error_to_uma_cb) {
- scoped_ptr<VaapiWrapper> vaapi_wrapper(new VaapiWrapper());
-
- if (!vaapi_wrapper->Initialize(
- mode, profile, x_display, report_error_to_uma_cb))
- vaapi_wrapper.reset();
+ if (!profile_infos_.Get().IsProfileSupported(mode, va_profile)) {
+ DVLOG(1) << "Unsupported va_profile: " << va_profile;
+ return nullptr;
+ }
- return vaapi_wrapper.Pass();
+ scoped_ptr<VaapiWrapper> vaapi_wrapper(new VaapiWrapper());
+ if (vaapi_wrapper->VaInitialize(report_error_to_uma_cb)) {
+ if (vaapi_wrapper->Initialize(mode, va_profile))
+ return vaapi_wrapper.Pass();
+ }
+ LOG(ERROR) << "Failed to create VaapiWrapper for va_profile: " << va_profile;
+ return nullptr;
}
-std::vector<media::VideoCodecProfile> VaapiWrapper::GetSupportedEncodeProfiles(
- Display* x_display,
+// static
+scoped_ptr<VaapiWrapper> VaapiWrapper::CreateForVideoCodec(
+ CodecMode mode,
+ media::VideoCodecProfile profile,
const base::Closure& report_error_to_uma_cb) {
- std::vector<media::VideoCodecProfile> supported_profiles;
+ VAProfile va_profile = ProfileToVAProfile(profile, mode);
+ scoped_ptr<VaapiWrapper> vaapi_wrapper =
+ Create(mode, va_profile, report_error_to_uma_cb);
+ return vaapi_wrapper.Pass();
+}
- scoped_ptr<VaapiWrapper> wrapper(new VaapiWrapper());
- if (!wrapper->VaInitialize(x_display, report_error_to_uma_cb)) {
- return supported_profiles;
+// static
+media::VideoEncodeAccelerator::SupportedProfiles
+VaapiWrapper::GetSupportedEncodeProfiles() {
+ media::VideoEncodeAccelerator::SupportedProfiles profiles;
+ const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
+ if (cmd_line->HasSwitch(switches::kDisableVaapiAcceleratedVideoEncode))
+ return profiles;
+
+ std::vector<ProfileInfo> encode_profile_infos =
+ profile_infos_.Get().GetSupportedProfileInfosForCodecMode(kEncode);
+
+ for (size_t i = 0; i < arraysize(kProfileMap); ++i) {
+ VAProfile va_profile = ProfileToVAProfile(kProfileMap[i].profile, kEncode);
+ if (va_profile == VAProfileNone)
+ continue;
+ for (const auto& profile_info : encode_profile_infos) {
+ if (profile_info.va_profile == va_profile) {
+ media::VideoEncodeAccelerator::SupportedProfile profile;
+ profile.profile = kProfileMap[i].profile;
+ profile.max_resolution = profile_info.max_resolution;
+ profile.max_framerate_numerator = kMaxEncoderFramerate;
+ profile.max_framerate_denominator = 1;
+ profiles.push_back(profile);
+ break;
+ }
+ }
}
+ return profiles;
+}
- std::vector<VAProfile> va_profiles;
- if (!wrapper->GetSupportedVaProfiles(&va_profiles))
- return supported_profiles;
-
- std::vector<VAConfigAttrib> required_attribs = GetRequiredAttribs(kEncode);
- for (size_t i = 0; i < arraysize(kProfileMap); i++) {
- VAProfile va_profile =
- ProfileToVAProfile(kProfileMap[i].profile, va_profiles);
- if (va_profile != VAProfileNone &&
- wrapper->IsEntrypointSupported(va_profile, VAEntrypointEncSlice) &&
- wrapper->AreAttribsSupported(
- va_profile, VAEntrypointEncSlice, required_attribs)) {
- supported_profiles.push_back(kProfileMap[i].profile);
+// static
+media::VideoDecodeAccelerator::SupportedProfiles
+VaapiWrapper::GetSupportedDecodeProfiles() {
+ media::VideoDecodeAccelerator::SupportedProfiles profiles;
+ std::vector<ProfileInfo> decode_profile_infos =
+ profile_infos_.Get().GetSupportedProfileInfosForCodecMode(kDecode);
+
+ for (size_t i = 0; i < arraysize(kProfileMap); ++i) {
+ VAProfile va_profile = ProfileToVAProfile(kProfileMap[i].profile, kDecode);
+ if (va_profile == VAProfileNone)
+ continue;
+ for (const auto& profile_info : decode_profile_infos) {
+ if (profile_info.va_profile == va_profile) {
+ media::VideoDecodeAccelerator::SupportedProfile profile;
+ profile.profile = kProfileMap[i].profile;
+ profile.max_resolution = profile_info.max_resolution;
+ profile.min_resolution.SetSize(16, 16);
+ profiles.push_back(profile);
+ break;
+ }
}
}
- return supported_profiles;
+ return profiles;
}
void VaapiWrapper::TryToSetVADisplayAttributeToLocalGPU() {
- base::AutoLock auto_lock(va_lock_);
+ base::AutoLock auto_lock(*va_lock_);
VADisplayAttribute item = {VADisplayAttribRenderMode,
1, // At least support '_LOCAL_OVERLAY'.
-1, // The maximum possible support 'ALL'.
@@ -200,37 +238,103 @@ void VaapiWrapper::TryToSetVADisplayAttributeToLocalGPU() {
DVLOG(2) << "vaSetDisplayAttributes unsupported, ignoring by default.";
}
-bool VaapiWrapper::VaInitialize(Display* x_display,
- const base::Closure& report_error_to_uma_cb) {
+// static
+VAProfile VaapiWrapper::ProfileToVAProfile(
+ media::VideoCodecProfile profile, CodecMode mode) {
+ VAProfile va_profile = VAProfileNone;
+ for (size_t i = 0; i < arraysize(kProfileMap); ++i) {
+ if (kProfileMap[i].profile == profile) {
+ va_profile = kProfileMap[i].va_profile;
+ break;
+ }
+ }
+ if (!profile_infos_.Get().IsProfileSupported(mode, va_profile) &&
+ va_profile == VAProfileH264Baseline) {
+ // crbug.com/345569: media::ProfileIDToVideoCodecProfile() currently strips
+ // the information whether the profile is constrained or not, so we have no
+ // way to know here. Try for baseline first, but if it is not supported,
+ // try constrained baseline and hope this is what it actually is
+ // (which in practice is true for a great majority of cases).
+ if (profile_infos_.Get().IsProfileSupported(
+ mode, VAProfileH264ConstrainedBaseline)) {
+ va_profile = VAProfileH264ConstrainedBaseline;
+ DVLOG(1) << "Fall back to constrained baseline profile.";
+ }
+ }
+ return va_profile;
+}
+
+std::vector<VaapiWrapper::ProfileInfo>
+VaapiWrapper::GetSupportedProfileInfosForCodecModeInternal(CodecMode mode) {
+ std::vector<ProfileInfo> supported_profile_infos;
+ std::vector<VAProfile> va_profiles;
+ if (!GetSupportedVaProfiles(&va_profiles))
+ return supported_profile_infos;
+
+ std::vector<VAConfigAttrib> required_attribs = GetRequiredAttribs(mode);
+ VAEntrypoint entrypoint =
+ (mode == kEncode ? VAEntrypointEncSlice: VAEntrypointVLD);
+
+ base::AutoLock auto_lock(*va_lock_);
+ for (const auto& va_profile : va_profiles) {
+ if (!IsEntrypointSupported_Locked(va_profile, entrypoint))
+ continue;
+ if (!AreAttribsSupported_Locked(va_profile, entrypoint, required_attribs))
+ continue;
+ ProfileInfo profile_info;
+ if (!GetMaxResolution_Locked(va_profile,
+ entrypoint,
+ required_attribs,
+ &profile_info.max_resolution)) {
+ LOG(ERROR) << "GetMaxResolution failed for va_profile " << va_profile
+ << " and entrypoint " << entrypoint;
+ continue;
+ }
+ profile_info.va_profile = va_profile;
+ supported_profile_infos.push_back(profile_info);
+ }
+ return supported_profile_infos;
+}
+
+bool VaapiWrapper::VaInitialize(const base::Closure& report_error_to_uma_cb) {
static bool vaapi_functions_initialized = PostSandboxInitialization();
if (!vaapi_functions_initialized) {
- LOG(ERROR) << "Failed to initialize VAAPI libs";
+ bool running_on_chromeos = false;
+#if defined(OS_CHROMEOS)
+ // When chrome runs on linux with chromeos=1, do not log error message
+ // without VAAPI libraries.
+ running_on_chromeos = base::SysInfo::IsRunningOnChromeOS();
+#endif
+ static const char kErrorMsg[] = "Failed to initialize VAAPI libs";
+ if (running_on_chromeos)
+ LOG(ERROR) << kErrorMsg;
+ else
+ DVLOG(1) << kErrorMsg;
return false;
}
report_error_to_uma_cb_ = report_error_to_uma_cb;
- base::AutoLock auto_lock(va_lock_);
+ base::AutoLock auto_lock(*va_lock_);
- va_display_ = vaGetDisplay(x_display);
- if (!vaDisplayIsValid(va_display_)) {
- LOG(ERROR) << "Could not get a valid VA display";
+ VADisplayState* va_display_state = &va_display_state_.Get();
+ if (!va_display_state) {
+ LOG(ERROR) << "Failed to allocate VA display state";
return false;
}
- VAStatus va_res = vaInitialize(va_display_, &major_version_, &minor_version_);
- VA_SUCCESS_OR_RETURN(va_res, "vaInitialize failed", false);
- DVLOG(1) << "VAAPI version: " << major_version_ << "." << minor_version_;
-
- if (VAAPIVersionLessThan(0, 34)) {
- LOG(ERROR) << "VAAPI version < 0.34 is not supported.";
+ VAStatus va_res = VA_STATUS_SUCCESS;
+ if (!va_display_state->Initialize(&va_res)) {
+ VA_LOG_ON_ERROR(va_res, "vaInitialize failed");
return false;
}
+
+ va_display_ = va_display_state->va_display();
return true;
}
bool VaapiWrapper::GetSupportedVaProfiles(std::vector<VAProfile>* profiles) {
- base::AutoLock auto_lock(va_lock_);
+ base::AutoLock auto_lock(*va_lock_);
// Query the driver for supported profiles.
int max_profiles = vaMaxNumProfiles(va_display_);
std::vector<VAProfile> supported_profiles(
@@ -250,9 +354,9 @@ bool VaapiWrapper::GetSupportedVaProfiles(std::vector<VAProfile>* profiles) {
return true;
}
-bool VaapiWrapper::IsEntrypointSupported(VAProfile va_profile,
- VAEntrypoint entrypoint) {
- base::AutoLock auto_lock(va_lock_);
+bool VaapiWrapper::IsEntrypointSupported_Locked(VAProfile va_profile,
+ VAEntrypoint entrypoint) {
+ va_lock_->AssertAcquired();
// Query the driver for supported entrypoints.
int max_entrypoints = vaMaxNumEntrypoints(va_display_);
std::vector<VAEntrypoint> supported_entrypoints(
@@ -280,11 +384,11 @@ bool VaapiWrapper::IsEntrypointSupported(VAProfile va_profile,
return true;
}
-bool VaapiWrapper::AreAttribsSupported(
+bool VaapiWrapper::AreAttribsSupported_Locked(
VAProfile va_profile,
VAEntrypoint entrypoint,
const std::vector<VAConfigAttrib>& required_attribs) {
- base::AutoLock auto_lock(va_lock_);
+ va_lock_->AssertAcquired();
// Query the driver for required attributes.
std::vector<VAConfigAttrib> attribs = required_attribs;
for (size_t i = 0; i < required_attribs.size(); ++i)
@@ -306,31 +410,61 @@ bool VaapiWrapper::AreAttribsSupported(
return true;
}
-bool VaapiWrapper::Initialize(CodecMode mode,
- media::VideoCodecProfile profile,
- Display* x_display,
- const base::Closure& report_error_to_uma_cb) {
- if (!VaInitialize(x_display, report_error_to_uma_cb))
- return false;
- std::vector<VAProfile> supported_va_profiles;
- if (!GetSupportedVaProfiles(&supported_va_profiles))
- return false;
- VAProfile va_profile = ProfileToVAProfile(profile, supported_va_profiles);
- if (va_profile == VAProfileNone) {
- DVLOG(1) << "Unsupported profile";
+bool VaapiWrapper::GetMaxResolution_Locked(
+ VAProfile va_profile,
+ VAEntrypoint entrypoint,
+ std::vector<VAConfigAttrib>& required_attribs,
+ gfx::Size* resolution) {
+ va_lock_->AssertAcquired();
+ VAConfigID va_config_id;
+ VAStatus va_res = vaCreateConfig(
+ va_display_,
+ va_profile,
+ entrypoint,
+ &required_attribs[0],
+ required_attribs.size(),
+ &va_config_id);
+ VA_SUCCESS_OR_RETURN(va_res, "vaCreateConfig failed", false);
+
+ // Calls vaQuerySurfaceAttributes twice. The first time is to get the number
+ // of attributes to prepare the space and the second time is to get all
+ // attributes.
+ unsigned int num_attribs;
+ va_res = vaQuerySurfaceAttributes(
+ va_display_, va_config_id, nullptr, &num_attribs);
+ VA_SUCCESS_OR_RETURN(va_res, "vaQuerySurfaceAttributes failed", false);
+ if (!num_attribs)
return false;
+
+ std::vector<VASurfaceAttrib> attrib_list(
+ base::checked_cast<size_t>(num_attribs));
+
+ va_res = vaQuerySurfaceAttributes(
+ va_display_, va_config_id, &attrib_list[0], &num_attribs);
+ VA_SUCCESS_OR_RETURN(va_res, "vaQuerySurfaceAttributes failed", false);
+
+ resolution->SetSize(0, 0);
+ for (const auto& attrib : attrib_list) {
+ if (attrib.type == VASurfaceAttribMaxWidth)
+ resolution->set_width(attrib.value.value.i);
+ else if (attrib.type == VASurfaceAttribMaxHeight)
+ resolution->set_height(attrib.value.value.i);
}
- VAEntrypoint entrypoint =
- (mode == kEncode ? VAEntrypointEncSlice : VAEntrypointVLD);
- if (!IsEntrypointSupported(va_profile, entrypoint))
- return false;
- std::vector<VAConfigAttrib> required_attribs = GetRequiredAttribs(mode);
- if (!AreAttribsSupported(va_profile, entrypoint, required_attribs))
+ if (resolution->IsEmpty()) {
+ LOG(ERROR) << "Codec resolution " << resolution->ToString()
+ << " cannot be zero.";
return false;
+ }
+ return true;
+}
+bool VaapiWrapper::Initialize(CodecMode mode, VAProfile va_profile) {
TryToSetVADisplayAttributeToLocalGPU();
- base::AutoLock auto_lock(va_lock_);
+ VAEntrypoint entrypoint =
+ (mode == kEncode ? VAEntrypointEncSlice : VAEntrypointVLD);
+ std::vector<VAConfigAttrib> required_attribs = GetRequiredAttribs(mode);
+ base::AutoLock auto_lock(*va_lock_);
VAStatus va_res = vaCreateConfig(va_display_,
va_profile,
entrypoint,
@@ -343,15 +477,17 @@ bool VaapiWrapper::Initialize(CodecMode mode,
}
void VaapiWrapper::Deinitialize() {
- base::AutoLock auto_lock(va_lock_);
+ base::AutoLock auto_lock(*va_lock_);
if (va_config_id_ != VA_INVALID_ID) {
VAStatus va_res = vaDestroyConfig(va_display_, va_config_id_);
VA_LOG_ON_ERROR(va_res, "vaDestroyConfig failed");
}
- if (va_display_) {
- VAStatus va_res = vaTerminate(va_display_);
+ VADisplayState* va_display_state = &va_display_state_.Get();
+ if (va_display_state) {
+ VAStatus va_res = VA_STATUS_SUCCESS;
+ va_display_state->Deinitialize(&va_res);
VA_LOG_ON_ERROR(va_res, "vaTerminate failed");
}
@@ -359,15 +495,10 @@ void VaapiWrapper::Deinitialize() {
va_display_ = NULL;
}
-bool VaapiWrapper::VAAPIVersionLessThan(int major, int minor) {
- return (major_version_ < major) ||
- (major_version_ == major && minor_version_ < minor);
-}
-
-bool VaapiWrapper::CreateSurfaces(gfx::Size size,
+bool VaapiWrapper::CreateSurfaces(const gfx::Size& size,
size_t num_surfaces,
std::vector<VASurfaceID>* va_surfaces) {
- base::AutoLock auto_lock(va_lock_);
+ base::AutoLock auto_lock(*va_lock_);
DVLOG(2) << "Creating " << num_surfaces << " surfaces";
DCHECK(va_surfaces->empty());
@@ -405,7 +536,7 @@ bool VaapiWrapper::CreateSurfaces(gfx::Size size,
}
void VaapiWrapper::DestroySurfaces() {
- base::AutoLock auto_lock(va_lock_);
+ base::AutoLock auto_lock(*va_lock_);
DVLOG(2) << "Destroying " << va_surface_ids_.size() << " surfaces";
if (va_context_id_ != VA_INVALID_ID) {
@@ -423,10 +554,43 @@ void VaapiWrapper::DestroySurfaces() {
va_context_id_ = VA_INVALID_ID;
}
+scoped_refptr<VASurface> VaapiWrapper::CreateUnownedSurface(
+ unsigned int va_format,
+ const gfx::Size& size,
+ const std::vector<VASurfaceAttrib>& va_attribs) {
+ base::AutoLock auto_lock(*va_lock_);
+
+ std::vector<VASurfaceAttrib> attribs(va_attribs);
+ VASurfaceID va_surface_id;
+ VAStatus va_res =
+ vaCreateSurfaces(va_display_, va_format, size.width(), size.height(),
+ &va_surface_id, 1, &attribs[0], attribs.size());
+
+ scoped_refptr<VASurface> va_surface;
+ VA_SUCCESS_OR_RETURN(va_res, "Failed to create unowned VASurface",
+ va_surface);
+
+ // This is safe to use Unretained() here, because the VDA takes care
+ // of the destruction order. All the surfaces will be destroyed
+ // before VaapiWrapper.
+ va_surface = new VASurface(
+ va_surface_id, size,
+ base::Bind(&VaapiWrapper::DestroyUnownedSurface, base::Unretained(this)));
+
+ return va_surface;
+}
+
+void VaapiWrapper::DestroyUnownedSurface(VASurfaceID va_surface_id) {
+ base::AutoLock auto_lock(*va_lock_);
+
+ VAStatus va_res = vaDestroySurfaces(va_display_, &va_surface_id, 1);
+ VA_LOG_ON_ERROR(va_res, "vaDestroySurfaces on surface failed");
+}
+
bool VaapiWrapper::SubmitBuffer(VABufferType va_buffer_type,
size_t size,
void* buffer) {
- base::AutoLock auto_lock(va_lock_);
+ base::AutoLock auto_lock(*va_lock_);
VABufferID buffer_id;
VAStatus va_res = vaCreateBuffer(va_display_, va_context_id_,
@@ -453,7 +617,7 @@ bool VaapiWrapper::SubmitVAEncMiscParamBuffer(
VAEncMiscParameterType misc_param_type,
size_t size,
void* buffer) {
- base::AutoLock auto_lock(va_lock_);
+ base::AutoLock auto_lock(*va_lock_);
VABufferID buffer_id;
VAStatus va_res = vaCreateBuffer(va_display_,
@@ -487,15 +651,15 @@ bool VaapiWrapper::SubmitVAEncMiscParamBuffer(
}
void VaapiWrapper::DestroyPendingBuffers() {
- base::AutoLock auto_lock(va_lock_);
+ base::AutoLock auto_lock(*va_lock_);
- for (size_t i = 0; i < pending_va_bufs_.size(); ++i) {
- VAStatus va_res = vaDestroyBuffer(va_display_, pending_va_bufs_[i]);
+ for (const auto& pending_va_buf : pending_va_bufs_) {
+ VAStatus va_res = vaDestroyBuffer(va_display_, pending_va_buf);
VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed");
}
- for (size_t i = 0; i < pending_slice_bufs_.size(); ++i) {
- VAStatus va_res = vaDestroyBuffer(va_display_, pending_slice_bufs_[i]);
+ for (const auto& pending_slice_buf : pending_slice_bufs_) {
+ VAStatus va_res = vaDestroyBuffer(va_display_, pending_slice_buf);
VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed");
}
@@ -504,7 +668,7 @@ void VaapiWrapper::DestroyPendingBuffers() {
}
bool VaapiWrapper::CreateCodedBuffer(size_t size, VABufferID* buffer_id) {
- base::AutoLock auto_lock(va_lock_);
+ base::AutoLock auto_lock(*va_lock_);
VAStatus va_res = vaCreateBuffer(va_display_,
va_context_id_,
VAEncCodedBufferType,
@@ -519,7 +683,7 @@ bool VaapiWrapper::CreateCodedBuffer(size_t size, VABufferID* buffer_id) {
}
void VaapiWrapper::DestroyCodedBuffers() {
- base::AutoLock auto_lock(va_lock_);
+ base::AutoLock auto_lock(*va_lock_);
for (std::set<VABufferID>::const_iterator iter = coded_buffers_.begin();
iter != coded_buffers_.end();
@@ -532,7 +696,7 @@ void VaapiWrapper::DestroyCodedBuffers() {
}
bool VaapiWrapper::Execute(VASurfaceID va_surface_id) {
- base::AutoLock auto_lock(va_lock_);
+ base::AutoLock auto_lock(*va_lock_);
DVLOG(4) << "Pending VA bufs to commit: " << pending_va_bufs_.size();
DVLOG(4) << "Pending slice bufs to commit: " << pending_slice_bufs_.size();
@@ -574,10 +738,11 @@ bool VaapiWrapper::ExecuteAndDestroyPendingBuffers(VASurfaceID va_surface_id) {
return result;
}
+#if defined(USE_X11)
bool VaapiWrapper::PutSurfaceIntoPixmap(VASurfaceID va_surface_id,
Pixmap x_pixmap,
gfx::Size dest_size) {
- base::AutoLock auto_lock(va_lock_);
+ base::AutoLock auto_lock(*va_lock_);
VAStatus va_res = vaSyncSurface(va_display_, va_surface_id);
VA_SUCCESS_OR_RETURN(va_res, "Failed syncing surface", false);
@@ -592,11 +757,12 @@ bool VaapiWrapper::PutSurfaceIntoPixmap(VASurfaceID va_surface_id,
VA_SUCCESS_OR_RETURN(va_res, "Failed putting surface to pixmap", false);
return true;
}
+#endif // USE_X11
-bool VaapiWrapper::GetVaImageForTesting(VASurfaceID va_surface_id,
- VAImage* image,
- void** mem) {
- base::AutoLock auto_lock(va_lock_);
+bool VaapiWrapper::GetDerivedVaImage(VASurfaceID va_surface_id,
+ VAImage* image,
+ void** mem) {
+ base::AutoLock auto_lock(*va_lock_);
VAStatus va_res = vaSyncSurface(va_display_, va_surface_id);
VA_SUCCESS_OR_RETURN(va_res, "Failed syncing surface", false);
@@ -619,8 +785,41 @@ bool VaapiWrapper::GetVaImageForTesting(VASurfaceID va_surface_id,
return false;
}
-void VaapiWrapper::ReturnVaImageForTesting(VAImage* image) {
- base::AutoLock auto_lock(va_lock_);
+bool VaapiWrapper::GetVaImage(VASurfaceID va_surface_id,
+ VAImageFormat* format,
+ const gfx::Size& size,
+ VAImage* image,
+ void** mem) {
+ base::AutoLock auto_lock(*va_lock_);
+
+ VAStatus va_res = vaSyncSurface(va_display_, va_surface_id);
+ VA_SUCCESS_OR_RETURN(va_res, "Failed syncing surface", false);
+
+ va_res =
+ vaCreateImage(va_display_, format, size.width(), size.height(), image);
+ VA_SUCCESS_OR_RETURN(va_res, "vaCreateImage failed", false);
+
+ va_res = vaGetImage(va_display_, va_surface_id, 0, 0, size.width(),
+ size.height(), image->image_id);
+ VA_LOG_ON_ERROR(va_res, "vaGetImage failed");
+
+ if (va_res == VA_STATUS_SUCCESS) {
+ // Map the VAImage into memory
+ va_res = vaMapBuffer(va_display_, image->buf, mem);
+ VA_LOG_ON_ERROR(va_res, "vaMapBuffer failed");
+ }
+
+ if (va_res != VA_STATUS_SUCCESS) {
+ va_res = vaDestroyImage(va_display_, image->image_id);
+ VA_LOG_ON_ERROR(va_res, "vaDestroyImage failed");
+ return false;
+ }
+
+ return true;
+}
+
+void VaapiWrapper::ReturnVaImage(VAImage* image) {
+ base::AutoLock auto_lock(*va_lock_);
VAStatus va_res = vaUnmapBuffer(va_display_, image->buf);
VA_LOG_ON_ERROR(va_res, "vaUnmapBuffer failed");
@@ -637,7 +836,7 @@ static void DestroyVAImage(VADisplay va_display, VAImage image) {
bool VaapiWrapper::UploadVideoFrameToSurface(
const scoped_refptr<media::VideoFrame>& frame,
VASurfaceID va_surface_id) {
- base::AutoLock auto_lock(va_lock_);
+ base::AutoLock auto_lock(*va_lock_);
VAImage image;
VAStatus va_res = vaDeriveImage(va_display_, va_surface_id, &image);
@@ -662,7 +861,7 @@ bool VaapiWrapper::UploadVideoFrameToSurface(
int ret = 0;
{
- base::AutoUnlock auto_unlock(va_lock_);
+ base::AutoUnlock auto_unlock(*va_lock_);
ret = libyuv::I420ToNV12(frame->data(media::VideoFrame::kYPlane),
frame->stride(media::VideoFrame::kYPlane),
frame->data(media::VideoFrame::kUPlane),
@@ -688,7 +887,7 @@ bool VaapiWrapper::DownloadAndDestroyCodedBuffer(VABufferID buffer_id,
uint8* target_ptr,
size_t target_size,
size_t* coded_data_size) {
- base::AutoLock auto_lock(va_lock_);
+ base::AutoLock auto_lock(*va_lock_);
VAStatus va_res = vaSyncSurface(va_display_, sync_surface_id);
VA_SUCCESS_OR_RETURN(va_res, "Failed syncing surface", false);
@@ -700,7 +899,7 @@ bool VaapiWrapper::DownloadAndDestroyCodedBuffer(VABufferID buffer_id,
DCHECK(target_ptr);
{
- base::AutoUnlock auto_unlock(va_lock_);
+ base::AutoUnlock auto_unlock(*va_lock_);
*coded_data_size = 0;
while (buffer_segment) {
@@ -733,12 +932,220 @@ bool VaapiWrapper::DownloadAndDestroyCodedBuffer(VABufferID buffer_id,
return buffer_segment == NULL;
}
+bool VaapiWrapper::BlitSurface(VASurfaceID va_surface_id_src,
+ const gfx::Size& src_size,
+ VASurfaceID va_surface_id_dest,
+ const gfx::Size& dest_size) {
+ base::AutoLock auto_lock(*va_lock_);
+
+ // Initialize the post processing engine if not already done.
+ if (va_vpp_buffer_id_ == VA_INVALID_ID) {
+ if (!InitializeVpp_Locked())
+ return false;
+ }
+
+ VAProcPipelineParameterBuffer* pipeline_param;
+ VA_SUCCESS_OR_RETURN(vaMapBuffer(va_display_, va_vpp_buffer_id_,
+ reinterpret_cast<void**>(&pipeline_param)),
+ "Couldn't map vpp buffer", false);
+
+ memset(pipeline_param, 0, sizeof *pipeline_param);
+
+ VARectangle input_region;
+ input_region.x = input_region.y = 0;
+ input_region.width = src_size.width();
+ input_region.height = src_size.height();
+ pipeline_param->surface_region = &input_region;
+ pipeline_param->surface = va_surface_id_src;
+ pipeline_param->surface_color_standard = VAProcColorStandardNone;
+
+ VARectangle output_region;
+ output_region.x = output_region.y = 0;
+ output_region.width = dest_size.width();
+ output_region.height = dest_size.height();
+ pipeline_param->output_region = &output_region;
+ pipeline_param->output_background_color = 0xff000000;
+ pipeline_param->output_color_standard = VAProcColorStandardNone;
+
+ VA_SUCCESS_OR_RETURN(vaUnmapBuffer(va_display_, va_vpp_buffer_id_),
+ "Couldn't unmap vpp buffer", false);
+
+ VA_SUCCESS_OR_RETURN(
+ vaBeginPicture(va_display_, va_vpp_context_id_, va_surface_id_dest),
+ "Couldn't begin picture", false);
+
+ VA_SUCCESS_OR_RETURN(
+ vaRenderPicture(va_display_, va_vpp_context_id_, &va_vpp_buffer_id_, 1),
+ "Couldn't render picture", false);
+
+ VA_SUCCESS_OR_RETURN(vaEndPicture(va_display_, va_vpp_context_id_),
+ "Couldn't end picture", false);
+
+ return true;
+}
+
+bool VaapiWrapper::InitializeVpp_Locked() {
+ va_lock_->AssertAcquired();
+
+ VA_SUCCESS_OR_RETURN(
+ vaCreateConfig(va_display_, VAProfileNone, VAEntrypointVideoProc, NULL, 0,
+ &va_vpp_config_id_),
+ "Couldn't create config", false);
+
+ // The size of the picture for the context is irrelevant in the case
+ // of the VPP, just passing 1x1.
+ VA_SUCCESS_OR_RETURN(vaCreateContext(va_display_, va_vpp_config_id_, 1, 1, 0,
+ NULL, 0, &va_vpp_context_id_),
+ "Couldn't create context", false);
+
+ VA_SUCCESS_OR_RETURN(vaCreateBuffer(va_display_, va_vpp_context_id_,
+ VAProcPipelineParameterBufferType,
+ sizeof(VAProcPipelineParameterBuffer), 1,
+ NULL, &va_vpp_buffer_id_),
+ "Couldn't create buffer", false);
+
+ return true;
+}
+
+void VaapiWrapper::DeinitializeVpp() {
+ base::AutoLock auto_lock(*va_lock_);
+
+ if (va_vpp_buffer_id_ != VA_INVALID_ID) {
+ vaDestroyBuffer(va_display_, va_vpp_buffer_id_);
+ va_vpp_buffer_id_ = VA_INVALID_ID;
+ }
+ if (va_vpp_context_id_ != VA_INVALID_ID) {
+ vaDestroyContext(va_display_, va_vpp_context_id_);
+ va_vpp_context_id_ = VA_INVALID_ID;
+ }
+ if (va_vpp_config_id_ != VA_INVALID_ID) {
+ vaDestroyConfig(va_display_, va_vpp_config_id_);
+ va_vpp_config_id_ = VA_INVALID_ID;
+ }
+}
+
+// static
+void VaapiWrapper::PreSandboxInitialization() {
+#if defined(USE_OZONE)
+ const char* kDriRenderNode0Path = "/dev/dri/renderD128";
+ base::File drm_file = base::File(
+ base::FilePath::FromUTF8Unsafe(kDriRenderNode0Path),
+ base::File::FLAG_OPEN | base::File::FLAG_READ | base::File::FLAG_WRITE);
+ if (drm_file.IsValid())
+ va_display_state_.Get().SetDrmFd(drm_file.GetPlatformFile());
+#endif
+}
+
// static
bool VaapiWrapper::PostSandboxInitialization() {
StubPathMap paths;
- paths[kModuleVa].push_back(kVaLib);
+
+ paths[kModuleVa].push_back("libva.so.1");
+
+#if defined(USE_X11)
+ paths[kModuleVa_x11].push_back("libva-x11.so.1");
+#elif defined(USE_OZONE)
+ paths[kModuleVa_drm].push_back("libva-drm.so.1");
+#endif
return InitializeStubs(paths);
}
+VaapiWrapper::LazyProfileInfos::LazyProfileInfos() {
+ static_assert(arraysize(supported_profiles_) == kCodecModeMax,
+ "The array size of supported profile is incorrect.");
+ scoped_ptr<VaapiWrapper> vaapi_wrapper(new VaapiWrapper());
+ if (!vaapi_wrapper->VaInitialize(base::Bind(&base::DoNothing)))
+ return;
+ for (size_t i = 0; i < kCodecModeMax; ++i) {
+ supported_profiles_[i] =
+ vaapi_wrapper->GetSupportedProfileInfosForCodecModeInternal(
+ static_cast<CodecMode>(i));
+ }
+}
+
+VaapiWrapper::LazyProfileInfos::~LazyProfileInfos() {
+}
+
+std::vector<VaapiWrapper::ProfileInfo>
+VaapiWrapper::LazyProfileInfos::GetSupportedProfileInfosForCodecMode(
+ CodecMode mode) {
+ return supported_profiles_[mode];
+}
+
+bool VaapiWrapper::LazyProfileInfos::IsProfileSupported(
+ CodecMode mode, VAProfile va_profile) {
+ for (const auto& profile : supported_profiles_[mode]) {
+ if (profile.va_profile == va_profile)
+ return true;
+ }
+ return false;
+}
+
+VaapiWrapper::VADisplayState::VADisplayState()
+ : refcount_(0),
+ va_display_(nullptr),
+ major_version_(-1),
+ minor_version_(-1),
+ va_initialized_(false) {}
+
+VaapiWrapper::VADisplayState::~VADisplayState() {}
+
+bool VaapiWrapper::VADisplayState::Initialize(VAStatus* status) {
+ va_lock_.AssertAcquired();
+ if (refcount_++ == 0) {
+#if defined(USE_X11)
+ va_display_ = vaGetDisplay(gfx::GetXDisplay());
+#elif defined(USE_OZONE)
+ va_display_ = vaGetDisplayDRM(drm_fd_.get());
+#endif // USE_X11
+
+ if (!vaDisplayIsValid(va_display_)) {
+ LOG(ERROR) << "Could not get a valid VA display";
+ return false;
+ }
+
+ *status = vaInitialize(va_display_, &major_version_, &minor_version_);
+ if (*status != VA_STATUS_SUCCESS)
+ return false;
+
+ va_initialized_ = true;
+ DVLOG(1) << "VAAPI version: " << major_version_ << "." << minor_version_;
+ }
+
+ if (VAAPIVersionLessThan(0, 34)) {
+ LOG(ERROR) << "VAAPI version < 0.34 is not supported.";
+ return false;
+ }
+ return true;
+}
+
+void VaapiWrapper::VADisplayState::Deinitialize(VAStatus* status) {
+ va_lock_.AssertAcquired();
+ if (--refcount_ > 0)
+ return;
+
+ // Must check if vaInitialize completed successfully, to work around a bug in
+ // libva. The bug was fixed upstream:
+ // http://lists.freedesktop.org/archives/libva/2013-July/001807.html
+ // TODO(mgiuca): Remove this check, and the |va_initialized_| variable, once
+ // the fix has rolled out sufficiently.
+ if (va_initialized_ && va_display_) {
+ *status = vaTerminate(va_display_);
+ }
+ va_initialized_ = false;
+ va_display_ = nullptr;
+}
+
+#if defined(USE_OZONE)
+void VaapiWrapper::VADisplayState::SetDrmFd(base::PlatformFile fd) {
+ drm_fd_.reset(HANDLE_EINTR(dup(fd)));
+}
+#endif // USE_OZONE
+
+bool VaapiWrapper::VADisplayState::VAAPIVersionLessThan(int major, int minor) {
+ return (major_version_ < major) ||
+ (major_version_ == major && minor_version_ < minor);
+}
+
} // namespace content
diff --git a/chromium/content/common/gpu/media/vaapi_wrapper.h b/chromium/content/common/gpu/media/vaapi_wrapper.h
index 39906a0f405..8951702c1eb 100644
--- a/chromium/content/common/gpu/media/vaapi_wrapper.h
+++ b/chromium/content/common/gpu/media/vaapi_wrapper.h
@@ -13,15 +13,22 @@
#include <set>
#include <vector>
-#include "base/callback.h"
+#include "base/files/file.h"
+#include "base/lazy_instance.h"
#include "base/memory/ref_counted.h"
#include "base/synchronization/lock.h"
#include "content/common/content_export.h"
#include "content/common/gpu/media/va_surface.h"
#include "media/base/video_decoder_config.h"
#include "media/base/video_frame.h"
+#include "media/video/video_decode_accelerator.h"
+#include "media/video/video_encode_accelerator.h"
+#include "third_party/libva/va/va.h"
+#include "third_party/libva/va/va_vpp.h"
+#include "ui/gfx/geometry/size.h"
+#if defined(USE_X11)
#include "third_party/libva/va/va_x11.h"
-#include "ui/gfx/size.h"
+#endif // USE_X11
namespace content {
@@ -40,20 +47,33 @@ class CONTENT_EXPORT VaapiWrapper {
enum CodecMode {
kDecode,
kEncode,
+ kCodecModeMax,
};
+ // Return an instance of VaapiWrapper initialized for |va_profile| and
+ // |mode|. |report_error_to_uma_cb| will be called independently from
+ // reporting errors to clients via method return values.
+ static scoped_ptr<VaapiWrapper> Create(
+ CodecMode mode,
+ VAProfile va_profile,
+ const base::Closure& report_error_to_uma_cb);
+
+ // Create VaapiWrapper for VideoCodecProfile. It maps VideoCodecProfile
+ // |profile| to VAProfile.
// |report_error_to_uma_cb| will be called independently from reporting
// errors to clients via method return values.
- static scoped_ptr<VaapiWrapper> Create(
+ static scoped_ptr<VaapiWrapper> CreateForVideoCodec(
CodecMode mode,
media::VideoCodecProfile profile,
- Display* x_display,
const base::Closure& report_error_to_uma_cb);
// Return the supported encode profiles.
- static std::vector<media::VideoCodecProfile> GetSupportedEncodeProfiles(
- Display* x_display,
- const base::Closure& report_error_to_uma_cb);
+ static media::VideoEncodeAccelerator::SupportedProfiles
+ GetSupportedEncodeProfiles();
+
+ // Return the supported decode profiles.
+ static media::VideoDecodeAccelerator::SupportedProfiles
+ GetSupportedDecodeProfiles();
~VaapiWrapper();
@@ -64,13 +84,22 @@ class CONTENT_EXPORT VaapiWrapper {
// again to free the allocated surfaces first, but is not required to do so
// at destruction time, as this will be done automatically from
// the destructor.
- bool CreateSurfaces(gfx::Size size,
+ bool CreateSurfaces(const gfx::Size& size,
size_t num_surfaces,
std::vector<VASurfaceID>* va_surfaces);
// Free all memory allocated in CreateSurfaces.
void DestroySurfaces();
+ // Create a VASurface of |va_format|, |size| and using |va_attribs|
+ // attributes. The ownership of the surface is transferred to the
+ // caller. It differs from surfaces created using CreateSurfaces(),
+ // where VaapiWrapper is the owner of the surfaces.
+ scoped_refptr<VASurface> CreateUnownedSurface(
+ unsigned int va_format,
+ const gfx::Size& size,
+ const std::vector<VASurfaceAttrib>& va_attribs);
+
// Submit parameters or slice data of |va_buffer_type|, copying them from
// |buffer| of size |size|, into HW codec. The data in |buffer| is no
// longer needed and can be freed after this method returns.
@@ -97,25 +126,37 @@ class CONTENT_EXPORT VaapiWrapper {
// buffers. Return false if Execute() fails.
bool ExecuteAndDestroyPendingBuffers(VASurfaceID va_surface_id);
- // Put data from |va_surface_id| into |x_pixmap| of size |size|,
- // converting/scaling to it.
+#if defined(USE_X11)
+ // Put data from |va_surface_id| into |x_pixmap| of size
+ // |dest_size|, converting/scaling to it.
bool PutSurfaceIntoPixmap(VASurfaceID va_surface_id,
Pixmap x_pixmap,
gfx::Size dest_size);
-
- // Returns true if the VAAPI version is less than the specified version.
- bool VAAPIVersionLessThan(int major, int minor);
-
- // Get a VAImage from a VASurface and map it into memory. The VAImage should
- // be released using the ReturnVaImage function. Returns true when successful.
- // This is intended for testing only.
- bool GetVaImageForTesting(VASurfaceID va_surface_id,
- VAImage* image,
- void** mem);
+#endif // USE_X11
+
+ // Get a VAImage from a VASurface and map it into memory. The size and format
+ // are derived from the surface. Use GetVaImage() instead if |format| or
+ // |size| are different from surface internal representation. The VAImage
+ // should be released using the ReturnVaImage function. Returns true when
+ // successful.
+ bool GetDerivedVaImage(VASurfaceID va_surface_id, VAImage* image, void** mem);
+
+ // Get a VAImage from a VASurface |va_surface_id| and map it into memory with
+ // given |format| and |size|. The output is |image| and the mapped memory is
+ // |mem|. If |format| doesn't equal to the internal format, the underlying
+ // implementation will do format conversion if supported. |size| should be
+ // smaller than or equal to the surface. If |size| is smaller, the image will
+ // be cropped. The VAImage should be released using the ReturnVaImage
+ // function. Returns true when successful.
+ bool GetVaImage(VASurfaceID va_surface_id,
+ VAImageFormat* format,
+ const gfx::Size& size,
+ VAImage* image,
+ void** mem);
// Release the VAImage (and the associated memory mapping) obtained from
- // GetVaImage(). This is intended for testing only.
- void ReturnVaImageForTesting(VAImage* image);
+ // GetVaImage() or GetDerivedVaImage().
+ void ReturnVaImage(VAImage* image);
// Upload contents of |frame| into |va_surface_id| for encode.
bool UploadVideoFrameToSurface(const scoped_refptr<media::VideoFrame>& frame,
@@ -139,21 +180,117 @@ class CONTENT_EXPORT VaapiWrapper {
// Destroy all previously-allocated (and not yet destroyed) coded buffers.
void DestroyCodedBuffers();
+ // Blits a VASurface |va_surface_id_src| into another VASurface
+ // |va_surface_id_dest| applying pixel format conversion and scaling
+ // if needed.
+ bool BlitSurface(VASurfaceID va_surface_id_src,
+ const gfx::Size& src_size,
+ VASurfaceID va_surface_id_dest,
+ const gfx::Size& dest_size);
+
+ // Initialize static data before sandbox is enabled.
+ static void PreSandboxInitialization();
+
private:
+ struct ProfileInfo {
+ VAProfile va_profile;
+ gfx::Size max_resolution;
+ };
+
+ class LazyProfileInfos {
+ public:
+ LazyProfileInfos();
+ ~LazyProfileInfos();
+ std::vector<ProfileInfo> GetSupportedProfileInfosForCodecMode(
+ CodecMode mode);
+ bool IsProfileSupported(CodecMode mode, VAProfile va_profile);
+
+ private:
+ std::vector<ProfileInfo> supported_profiles_[kCodecModeMax];
+ };
+
+ class VADisplayState {
+ public:
+ VADisplayState();
+ ~VADisplayState();
+
+ // |va_lock_| must be held on entry.
+ bool Initialize(VAStatus* status);
+ void Deinitialize(VAStatus* status);
+
+ base::Lock* va_lock() { return &va_lock_; }
+ VADisplay va_display() const { return va_display_; }
+
+#if defined(USE_OZONE)
+ void SetDrmFd(base::PlatformFile fd);
+#endif // USE_OZONE
+
+ private:
+ friend class base::LazyInstance<VADisplayState>;
+
+ // Returns true if the VAAPI version is less than the specified version.
+ bool VAAPIVersionLessThan(int major, int minor);
+
+ // Protected by |va_lock_|.
+ int refcount_;
+
+ // Libva is not thread safe, so we have to do locking for it ourselves.
+ // This lock is to be taken for the duration of all VA-API calls and for
+ // the entire job submission sequence in ExecuteAndDestroyPendingBuffers().
+ base::Lock va_lock_;
+
+#if defined(USE_OZONE)
+ // Drm fd used to obtain access to the driver interface by VA.
+ base::ScopedFD drm_fd_;
+#endif // USE_OZONE
+
+ // The VADisplay handle.
+ VADisplay va_display_;
+
+ // The VAAPI version.
+ int major_version_, minor_version_;
+
+ // True if vaInitialize has been called successfully.
+ bool va_initialized_;
+ };
+
VaapiWrapper();
- bool Initialize(CodecMode mode,
- media::VideoCodecProfile profile,
- Display* x_display,
- const base::Closure& report_error_to_uma_cb);
+ bool Initialize(CodecMode mode, VAProfile va_profile);
void Deinitialize();
- bool VaInitialize(Display* x_display,
- const base::Closure& report_error_to_uma_cb);
+ bool VaInitialize(const base::Closure& report_error_to_uma_cb);
bool GetSupportedVaProfiles(std::vector<VAProfile>* profiles);
- bool IsEntrypointSupported(VAProfile va_profile, VAEntrypoint entrypoint);
- bool AreAttribsSupported(VAProfile va_profile,
- VAEntrypoint entrypoint,
- const std::vector<VAConfigAttrib>& required_attribs);
+
+ // Check if |va_profile| supports |entrypoint| or not. |va_lock_| must be
+ // held on entry.
+ bool IsEntrypointSupported_Locked(VAProfile va_profile,
+ VAEntrypoint entrypoint);
+
+ // Return true if |va_profile| for |entrypoint| with |required_attribs| is
+ // supported. |va_lock_| must be held on entry.
+ bool AreAttribsSupported_Locked(
+ VAProfile va_profile,
+ VAEntrypoint entrypoint,
+ const std::vector<VAConfigAttrib>& required_attribs);
+
+ // Get maximum resolution for |va_profile| and |entrypoint| with
+ // |required_attribs|. If return value is true, |resolution| is the maximum
+ // resolution. |va_lock_| must be held on entry.
+ bool GetMaxResolution_Locked(
+ VAProfile va_profile,
+ VAEntrypoint entrypoint,
+ std::vector<VAConfigAttrib>& required_attribs,
+ gfx::Size* resolution);
+
+ // Destroys a |va_surface| created using CreateUnownedSurface.
+ void DestroyUnownedSurface(VASurfaceID va_surface_id);
+
+ // Initialize the video post processing context with the |size| of
+ // the input pictures to be processed.
+ bool InitializeVpp_Locked();
+
+ // Deinitialize the video post processing context.
+ void DeinitializeVpp();
// Execute pending job in hardware and destroy pending buffers. Return false
// if vaapi driver refuses to accept parameter or slice buffers submitted
@@ -163,23 +300,32 @@ class CONTENT_EXPORT VaapiWrapper {
// Attempt to set render mode to "render to texture.". Failure is non-fatal.
void TryToSetVADisplayAttributeToLocalGPU();
+ // Get supported profile infos for |mode|.
+ std::vector<ProfileInfo> GetSupportedProfileInfosForCodecModeInternal(
+ CodecMode mode);
+
// Lazily initialize static data after sandbox is enabled. Return false on
// init failure.
static bool PostSandboxInitialization();
- // Libva is not thread safe, so we have to do locking for it ourselves.
- // This lock is to be taken for the duration of all VA-API calls and for
- // the entire job submission sequence in ExecuteAndDestroyPendingBuffers().
- base::Lock va_lock_;
+ // Map VideoCodecProfile enum values to VaProfile values. This function
+ // includes a workaround for crbug.com/345569. If va_profile is h264 baseline
+ // and it is not supported, we try constrained baseline.
+ static VAProfile ProfileToVAProfile(media::VideoCodecProfile profile,
+ CodecMode mode);
+
+ // Pointer to VADisplayState's member |va_lock_|. Guaranteed to be valid for
+ // the lifetime of VaapiWrapper.
+ base::Lock* va_lock_;
// Allocated ids for VASurfaces.
std::vector<VASurfaceID> va_surface_ids_;
- // The VAAPI version.
- int major_version_, minor_version_;
+ // Singleton instance of VADisplayState.
+ static base::LazyInstance<VADisplayState> va_display_state_;
// VA handles.
- // Both valid after successful Initialize() and until Deinitialize().
+ // All valid after successful Initialize() and until Deinitialize().
VADisplay va_display_;
VAConfigID va_config_id_;
// Created for the current set of va_surface_ids_ in CreateSurfaces() and
@@ -197,6 +343,17 @@ class CONTENT_EXPORT VaapiWrapper {
// return values from public methods.
base::Closure report_error_to_uma_cb_;
+ // VPP (Video Post Processing) context, this is used to convert
+ // pictures used by the decoder to RGBA pictures usable by GL or the
+ // display hardware.
+ VAConfigID va_vpp_config_id_;
+ VAContextID va_vpp_context_id_;
+ VABufferID va_vpp_buffer_id_;
+
+ // Singleton variable to store supported profile information for encode and
+ // decode.
+ static base::LazyInstance<LazyProfileInfos> profile_infos_;
+
DISALLOW_COPY_AND_ASSIGN(VaapiWrapper);
};
diff --git a/chromium/content/common/gpu/media/video_decode_accelerator_unittest.cc b/chromium/content/common/gpu/media/video_decode_accelerator_unittest.cc
index 8b89d049b93..fb0a2173e9b 100644
--- a/chromium/content/common/gpu/media/video_decode_accelerator_unittest.cc
+++ b/chromium/content/common/gpu/media/video_decode_accelerator_unittest.cc
@@ -29,12 +29,12 @@
#include "base/at_exit.h"
#include "base/bind.h"
+#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/files/file.h"
#include "base/files/file_util.h"
#include "base/format_macros.h"
#include "base/md5.h"
-#include "base/message_loop/message_loop_proxy.h"
#include "base/process/process_handle.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
@@ -45,28 +45,38 @@
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
+#include "base/thread_task_runner_handle.h"
#include "base/threading/thread.h"
+#include "content/common/gpu/media/fake_video_decode_accelerator.h"
#include "content/common/gpu/media/rendering_helper.h"
#include "content/common/gpu/media/video_accelerator_unittest_helpers.h"
#include "content/public/common/content_switches.h"
#include "media/filters/h264_parser.h"
#include "ui/gfx/codec/png_codec.h"
+#include "ui/gl/gl_image.h"
#if defined(OS_WIN)
+#include "base/win/windows_version.h"
#include "content/common/gpu/media/dxva_video_decode_accelerator.h"
-#elif defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL)
+#elif defined(OS_CHROMEOS)
+#if defined(USE_V4L2_CODEC)
+#include "content/common/gpu/media/v4l2_device.h"
+#include "content/common/gpu/media/v4l2_slice_video_decode_accelerator.h"
#include "content/common/gpu/media/v4l2_video_decode_accelerator.h"
-#include "content/common/gpu/media/v4l2_video_device.h"
-#elif defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)
+#endif
+#if defined(ARCH_CPU_X86_FAMILY)
#include "content/common/gpu/media/vaapi_video_decode_accelerator.h"
#include "content/common/gpu/media/vaapi_wrapper.h"
-#if defined(USE_X11)
-#include "ui/gl/gl_implementation.h"
-#endif // USE_X11
+#endif // defined(ARCH_CPU_X86_FAMILY)
#else
#error The VideoAccelerator tests are not supported on this platform.
#endif // OS_WIN
+#if defined(USE_OZONE)
+#include "ui/ozone/public/ozone_gpu_test_helper.h"
+#include "ui/ozone/public/ozone_platform.h"
+#endif // defined(USE_OZONE)
+
using media::VideoDecodeAccelerator;
namespace content {
@@ -80,10 +90,10 @@ namespace {
// The syntax of each test-video is:
// filename:width:height:numframes:numfragments:minFPSwithRender:minFPSnoRender
// where only the first field is required. Value details:
-// - |filename| must be an h264 Annex B (NAL) stream or an IVF VP8 stream.
+// - |filename| must be an h264 Annex B (NAL) stream or an IVF VP8/9 stream.
// - |width| and |height| are in pixels.
// - |numframes| is the number of picture frames in the file.
-// - |numfragments| NALU (h264) or frame (VP8) count in the stream.
+// - |numfragments| NALU (h264) or frame (VP8/9) count in the stream.
// - |minFPSwithRender| and |minFPSnoRender| are minimum frames/second speeds
// expected to be achieved with and without rendering to the screen, resp.
// (the latter tests just decode speed).
@@ -104,6 +114,18 @@ double g_rendering_fps = 60;
// The value is set by the switch "--rendering_warm_up".
int g_rendering_warm_up = 0;
+// The value is set by the switch "--num_play_throughs". The video will play
+// the specified number of times. In different test cases, we have different
+// values for |num_play_throughs|. This setting will override the value. A
+// special value "0" means no override.
+int g_num_play_throughs = 0;
+// Fake decode
+int g_fake_decoder = 0;
+
+// Environment to store rendering thread.
+class VideoDecodeAcceleratorTestEnvironment;
+VideoDecodeAcceleratorTestEnvironment* g_env;
+
// Magic constants for differentiating the reasons for NotifyResetDone being
// called.
enum ResetPoint {
@@ -174,7 +196,9 @@ void ReadGoldenThumbnailMD5s(const TestVideoFile* video_file,
kMD5StringLength;
CHECK(hex_only) << *md5_string;
}
- CHECK_GE(md5_strings->size(), 1U) << all_md5s;
+ CHECK_GE(md5_strings->size(), 1U) << " MD5 checksum file ("
+ << filepath.MaybeAsASCII()
+ << ") missing or empty.";
}
// State of the GLRenderingVDAClient below. Order matters here as the test
@@ -192,6 +216,73 @@ enum ClientState {
CS_MAX, // Must be last entry.
};
+// Initialize the GPU thread for rendering. We only need to setup once
+// for all test cases.
+class VideoDecodeAcceleratorTestEnvironment : public ::testing::Environment {
+ public:
+ VideoDecodeAcceleratorTestEnvironment()
+ : rendering_thread_("GLRenderingVDAClientThread") {}
+
+ void SetUp() override {
+ rendering_thread_.Start();
+
+ base::WaitableEvent done(false, false);
+ rendering_thread_.task_runner()->PostTask(
+ FROM_HERE, base::Bind(&RenderingHelper::InitializeOneOff, &done));
+ done.Wait();
+
+#if defined(USE_OZONE)
+ gpu_helper_.reset(new ui::OzoneGpuTestHelper());
+ // Need to initialize after the rendering side since the rendering side
+ // initializes the "GPU" parts of Ozone.
+ //
+ // This also needs to be done in the test environment since this shouldn't
+ // be initialized multiple times for the same Ozone platform.
+ gpu_helper_->Initialize(base::ThreadTaskRunnerHandle::Get(),
+ GetRenderingTaskRunner());
+#endif
+ }
+
+ void TearDown() override {
+#if defined(USE_OZONE)
+ gpu_helper_.reset();
+#endif
+ rendering_thread_.Stop();
+ }
+
+ scoped_refptr<base::SingleThreadTaskRunner> GetRenderingTaskRunner() const {
+ return rendering_thread_.task_runner();
+ }
+
+ private:
+ base::Thread rendering_thread_;
+#if defined(USE_OZONE)
+ scoped_ptr<ui::OzoneGpuTestHelper> gpu_helper_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(VideoDecodeAcceleratorTestEnvironment);
+};
+
+// A helper class used to manage the lifetime of a Texture.
+class TextureRef : public base::RefCounted<TextureRef> {
+ public:
+ TextureRef(uint32 texture_id, const base::Closure& no_longer_needed_cb)
+ : texture_id_(texture_id), no_longer_needed_cb_(no_longer_needed_cb) {}
+
+ int32 texture_id() const { return texture_id_; }
+
+ private:
+ friend class base::RefCounted<TextureRef>;
+ ~TextureRef();
+
+ uint32 texture_id_;
+ base::Closure no_longer_needed_cb_;
+};
+
+TextureRef::~TextureRef() {
+ base::ResetAndReturn(&no_longer_needed_cb_).Run();
+}
+
// Client that can accept callbacks from a VideoDecodeAccelerator and is used by
// the TESTs below.
class GLRenderingVDAClient
@@ -227,25 +318,26 @@ class GLRenderingVDAClient
int frame_width,
int frame_height,
media::VideoCodecProfile profile,
+ int fake_decoder,
bool suppress_rendering,
int delay_reuse_after_frame_num,
int decode_calls_per_second,
bool render_as_thumbnails);
- virtual ~GLRenderingVDAClient();
+ ~GLRenderingVDAClient() override;
void CreateAndStartDecoder();
// VideoDecodeAccelerator::Client implementation.
// The heart of the Client.
- virtual void ProvidePictureBuffers(uint32 requested_num_of_buffers,
- const gfx::Size& dimensions,
- uint32 texture_target) override;
- virtual void DismissPictureBuffer(int32 picture_buffer_id) override;
- virtual void PictureReady(const media::Picture& picture) override;
+ void ProvidePictureBuffers(uint32 requested_num_of_buffers,
+ const gfx::Size& dimensions,
+ uint32 texture_target) override;
+ void DismissPictureBuffer(int32 picture_buffer_id) override;
+ void PictureReady(const media::Picture& picture) override;
// Simple state changes.
- virtual void NotifyEndOfBitstreamBuffer(int32 bitstream_buffer_id) override;
- virtual void NotifyFlushDone() override;
- virtual void NotifyResetDone() override;
- virtual void NotifyError(VideoDecodeAccelerator::Error error) override;
+ void NotifyEndOfBitstreamBuffer(int32 bitstream_buffer_id) override;
+ void NotifyFlushDone() override;
+ void NotifyResetDone() override;
+ void NotifyError(VideoDecodeAccelerator::Error error) override;
void OutputFrameDeliveryTimes(base::File* output);
@@ -260,7 +352,17 @@ class GLRenderingVDAClient
bool decoder_deleted() { return !decoder_.get(); }
private:
- typedef std::map<int, media::PictureBuffer*> PictureBufferById;
+ typedef std::map<int32, scoped_refptr<TextureRef>> TextureRefMap;
+
+ scoped_ptr<media::VideoDecodeAccelerator> CreateFakeVDA();
+ scoped_ptr<media::VideoDecodeAccelerator> CreateDXVAVDA();
+ scoped_ptr<media::VideoDecodeAccelerator> CreateV4L2VDA();
+ scoped_ptr<media::VideoDecodeAccelerator> CreateV4L2SliceVDA();
+ scoped_ptr<media::VideoDecodeAccelerator> CreateVaapiVDA();
+
+ void BindImage(uint32 client_texture_id,
+ uint32 texture_target,
+ scoped_refptr<gfx::GLImage> image);
void SetState(ClientState new_state);
void FinishInitialization();
@@ -279,7 +381,7 @@ class GLRenderingVDAClient
// Helpers for GetBytesForNextFragment above.
void GetBytesForNextNALU(size_t start_pos, size_t* end_pos); // For h.264.
std::string GetBytesForNextFrame(
- size_t start_pos, size_t* end_pos); // For VP8.
+ size_t start_pos, size_t* end_pos); // For VP8/9.
// Request decode of the next fragment in the encoded data.
void DecodeNextFragment();
@@ -296,7 +398,6 @@ class GLRenderingVDAClient
scoped_ptr<VideoDecodeAccelerator> decoder_;
scoped_ptr<base::WeakPtrFactory<VideoDecodeAccelerator> >
weak_decoder_factory_;
- std::set<int> outstanding_texture_ids_;
int remaining_play_throughs_;
int reset_after_frame_num_;
int delete_decoder_state_;
@@ -305,9 +406,9 @@ class GLRenderingVDAClient
int num_queued_fragments_;
int num_decoded_frames_;
int num_done_bitstream_buffers_;
- PictureBufferById picture_buffers_by_id_;
base::TimeTicks initialize_done_ticks_;
media::VideoCodecProfile profile_;
+ int fake_decoder_;
GLenum texture_target_;
bool suppress_rendering_;
std::vector<base::TimeTicks> frame_delivery_times_;
@@ -319,10 +420,20 @@ class GLRenderingVDAClient
// The number of VDA::Decode calls per second. This is to simulate webrtc.
int decode_calls_per_second_;
bool render_as_thumbnails_;
- // The number of frames that are not returned from rendering_helper_. We
- // checks this count to ensure all frames are rendered before entering the
- // CS_RESET state.
- int frames_at_render_;
+
+ // A map of the textures that are currently active for the decoder, i.e.,
+ // have been created via AssignPictureBuffers() and not dismissed via
+ // DismissPictureBuffer(). The keys in the map are the IDs of the
+ // corresponding picture buffers, and the values are TextureRefs to the
+ // textures.
+ TextureRefMap active_textures_;
+
+ // A map of the textures that are still pending in the renderer.
+ // We check this to ensure all frames are rendered before entering the
+ // CS_RESET_State.
+ TextureRefMap pending_textures_;
+
+ int32 next_picture_buffer_id_;
DISALLOW_IMPLICIT_CONSTRUCTORS(GLRenderingVDAClient);
};
@@ -339,6 +450,7 @@ GLRenderingVDAClient::GLRenderingVDAClient(
int frame_width,
int frame_height,
media::VideoCodecProfile profile,
+ int fake_decoder,
bool suppress_rendering,
int delay_reuse_after_frame_num,
int decode_calls_per_second,
@@ -360,12 +472,13 @@ GLRenderingVDAClient::GLRenderingVDAClient(
num_queued_fragments_(0),
num_decoded_frames_(0),
num_done_bitstream_buffers_(0),
+ fake_decoder_(fake_decoder),
texture_target_(0),
suppress_rendering_(suppress_rendering),
delay_reuse_after_frame_num_(delay_reuse_after_frame_num),
decode_calls_per_second_(decode_calls_per_second),
render_as_thumbnails_(render_as_thumbnails),
- frames_at_render_(0) {
+ next_picture_buffer_id_(1) {
CHECK_GT(num_in_flight_decodes, 0);
CHECK_GT(num_play_throughs, 0);
// |num_in_flight_decodes_| is unsupported if |decode_calls_per_second_| > 0.
@@ -381,51 +494,115 @@ GLRenderingVDAClient::GLRenderingVDAClient(
GLRenderingVDAClient::~GLRenderingVDAClient() {
DeleteDecoder(); // Clean up in case of expected error.
CHECK(decoder_deleted());
- STLDeleteValues(&picture_buffers_by_id_);
SetState(CS_DESTROYED);
}
static bool DoNothingReturnTrue() { return true; }
+scoped_ptr<media::VideoDecodeAccelerator>
+GLRenderingVDAClient::CreateFakeVDA() {
+ scoped_ptr<media::VideoDecodeAccelerator> decoder;
+ if (fake_decoder_) {
+ decoder.reset(new FakeVideoDecodeAccelerator(
+ static_cast<gfx::GLContext*> (rendering_helper_->GetGLContextHandle()),
+ frame_size_,
+ base::Bind(&DoNothingReturnTrue)));
+ }
+ return decoder.Pass();
+}
+
+scoped_ptr<media::VideoDecodeAccelerator>
+GLRenderingVDAClient::CreateDXVAVDA() {
+ scoped_ptr<media::VideoDecodeAccelerator> decoder;
+#if defined(OS_WIN)
+ if (base::win::GetVersion() >= base::win::VERSION_WIN7)
+ decoder.reset(
+ new DXVAVideoDecodeAccelerator(
+ base::Bind(&DoNothingReturnTrue),
+ rendering_helper_->GetGLContext().get()));
+#endif
+ return decoder.Pass();
+}
+
+scoped_ptr<media::VideoDecodeAccelerator>
+GLRenderingVDAClient::CreateV4L2VDA() {
+ scoped_ptr<media::VideoDecodeAccelerator> decoder;
+#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC)
+ scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder);
+ if (device.get()) {
+ base::WeakPtr<VideoDecodeAccelerator::Client> weak_client = AsWeakPtr();
+ decoder.reset(new V4L2VideoDecodeAccelerator(
+ static_cast<EGLDisplay>(rendering_helper_->GetGLDisplay()),
+ static_cast<EGLContext>(rendering_helper_->GetGLContextHandle()),
+ weak_client, base::Bind(&DoNothingReturnTrue), device,
+ base::ThreadTaskRunnerHandle::Get()));
+ }
+#endif
+ return decoder.Pass();
+}
+
+scoped_ptr<media::VideoDecodeAccelerator>
+GLRenderingVDAClient::CreateV4L2SliceVDA() {
+ scoped_ptr<media::VideoDecodeAccelerator> decoder;
+#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC)
+ scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder);
+ if (device.get()) {
+ base::WeakPtr<VideoDecodeAccelerator::Client> weak_client = AsWeakPtr();
+ decoder.reset(new V4L2SliceVideoDecodeAccelerator(
+ device, static_cast<EGLDisplay>(rendering_helper_->GetGLDisplay()),
+ static_cast<EGLContext>(rendering_helper_->GetGLContextHandle()),
+ weak_client, base::Bind(&DoNothingReturnTrue),
+ base::ThreadTaskRunnerHandle::Get()));
+ }
+#endif
+ return decoder.Pass();
+}
+
+scoped_ptr<media::VideoDecodeAccelerator>
+GLRenderingVDAClient::CreateVaapiVDA() {
+ scoped_ptr<media::VideoDecodeAccelerator> decoder;
+#if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)
+ decoder.reset(new VaapiVideoDecodeAccelerator(
+ base::Bind(&DoNothingReturnTrue),
+ base::Bind(&GLRenderingVDAClient::BindImage, base::Unretained(this))));
+#endif
+ return decoder.Pass();
+}
+
+void GLRenderingVDAClient::BindImage(uint32 client_texture_id,
+ uint32 texture_target,
+ scoped_refptr<gfx::GLImage> image) {
+}
+
void GLRenderingVDAClient::CreateAndStartDecoder() {
CHECK(decoder_deleted());
CHECK(!decoder_.get());
VideoDecodeAccelerator::Client* client = this;
- base::WeakPtr<VideoDecodeAccelerator::Client> weak_client = AsWeakPtr();
-#if defined(OS_WIN)
- decoder_.reset(
- new DXVAVideoDecodeAccelerator(base::Bind(&DoNothingReturnTrue)));
-#elif defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL)
- scoped_ptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder);
- if (!device.get()) {
- NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE);
- return;
- }
- decoder_.reset(new V4L2VideoDecodeAccelerator(
- static_cast<EGLDisplay>(rendering_helper_->GetGLDisplay()),
- static_cast<EGLContext>(rendering_helper_->GetGLContext()),
- weak_client,
- base::Bind(&DoNothingReturnTrue),
- device.Pass(),
- base::MessageLoopProxy::current()));
-#elif defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)
- CHECK_EQ(gfx::kGLImplementationDesktopGL, gfx::GetGLImplementation())
- << "Hardware video decode does not work with OSMesa";
- decoder_.reset(new VaapiVideoDecodeAccelerator(
- static_cast<Display*>(rendering_helper_->GetGLDisplay()),
- base::Bind(&DoNothingReturnTrue)));
-#endif // OS_WIN
- CHECK(decoder_.get());
- weak_decoder_factory_.reset(
- new base::WeakPtrFactory<VideoDecodeAccelerator>(decoder_.get()));
- SetState(CS_DECODER_SET);
- if (decoder_deleted())
- return;
+ scoped_ptr<media::VideoDecodeAccelerator> decoders[] = {
+ CreateFakeVDA(),
+ CreateDXVAVDA(),
+ CreateV4L2VDA(),
+ CreateV4L2SliceVDA(),
+ CreateVaapiVDA(),
+ };
- CHECK(decoder_->Initialize(profile_, client));
- FinishInitialization();
+ for (size_t i = 0; i < arraysize(decoders); ++i) {
+ if (!decoders[i])
+ continue;
+ decoder_ = decoders[i].Pass();
+ weak_decoder_factory_.reset(
+ new base::WeakPtrFactory<VideoDecodeAccelerator>(decoder_.get()));
+ if (decoder_->Initialize(profile_, client)) {
+ SetState(CS_DECODER_SET);
+ FinishInitialization();
+ return;
+ }
+ }
+ // Decoders are all initialize failed.
+ LOG(ERROR) << "VideoDecodeAccelerator::Initialize() failed";
+ CHECK(false);
}
void GLRenderingVDAClient::ProvidePictureBuffers(
@@ -438,29 +615,30 @@ void GLRenderingVDAClient::ProvidePictureBuffers(
texture_target_ = texture_target;
for (uint32 i = 0; i < requested_num_of_buffers; ++i) {
- uint32 id = picture_buffers_by_id_.size();
uint32 texture_id;
base::WaitableEvent done(false, false);
rendering_helper_->CreateTexture(
texture_target_, &texture_id, dimensions, &done);
done.Wait();
- CHECK(outstanding_texture_ids_.insert(texture_id).second);
- media::PictureBuffer* buffer =
- new media::PictureBuffer(id, dimensions, texture_id);
- CHECK(picture_buffers_by_id_.insert(std::make_pair(id, buffer)).second);
- buffers.push_back(*buffer);
+
+ int32 picture_buffer_id = next_picture_buffer_id_++;
+ CHECK(active_textures_
+ .insert(std::make_pair(
+ picture_buffer_id,
+ new TextureRef(texture_id,
+ base::Bind(&RenderingHelper::DeleteTexture,
+ base::Unretained(rendering_helper_),
+ texture_id))))
+ .second);
+
+ buffers.push_back(
+ media::PictureBuffer(picture_buffer_id, dimensions, texture_id));
}
decoder_->AssignPictureBuffers(buffers);
}
void GLRenderingVDAClient::DismissPictureBuffer(int32 picture_buffer_id) {
- PictureBufferById::iterator it =
- picture_buffers_by_id_.find(picture_buffer_id);
- CHECK(it != picture_buffers_by_id_.end());
- CHECK_EQ(outstanding_texture_ids_.erase(it->second->texture_id()), 1U);
- rendering_helper_->DeleteTexture(it->second->texture_id());
- delete it->second;
- picture_buffers_by_id_.erase(it);
+ CHECK_EQ(1U, active_textures_.erase(picture_buffer_id));
}
void GLRenderingVDAClient::PictureReady(const media::Picture& picture) {
@@ -495,17 +673,15 @@ void GLRenderingVDAClient::PictureReady(const media::Picture& picture) {
encoded_data_next_pos_to_decode_ = 0;
}
- media::PictureBuffer* picture_buffer =
- picture_buffers_by_id_[picture.picture_buffer_id()];
- CHECK(picture_buffer);
+ TextureRefMap::iterator texture_it =
+ active_textures_.find(picture.picture_buffer_id());
+ ASSERT_NE(active_textures_.end(), texture_it);
- scoped_refptr<VideoFrameTexture> video_frame =
- new VideoFrameTexture(texture_target_,
- picture_buffer->texture_id(),
- base::Bind(&GLRenderingVDAClient::ReturnPicture,
- AsWeakPtr(),
- picture.picture_buffer_id()));
- ++frames_at_render_;
+ scoped_refptr<VideoFrameTexture> video_frame = new VideoFrameTexture(
+ texture_target_, texture_it->second->texture_id(),
+ base::Bind(&GLRenderingVDAClient::ReturnPicture, AsWeakPtr(),
+ picture.picture_buffer_id()));
+ ASSERT_TRUE(pending_textures_.insert(*texture_it).second);
if (render_as_thumbnails_) {
rendering_helper_->RenderThumbnail(video_frame->texture_target(),
@@ -518,9 +694,9 @@ void GLRenderingVDAClient::PictureReady(const media::Picture& picture) {
void GLRenderingVDAClient::ReturnPicture(int32 picture_buffer_id) {
if (decoder_deleted())
return;
+ CHECK_EQ(1U, pending_textures_.erase(picture_buffer_id));
- --frames_at_render_;
- if (frames_at_render_ == 0 && state_ == CS_RESETTING) {
+ if (pending_textures_.empty() && state_ == CS_RESETTING) {
SetState(CS_RESET);
DeleteDecoder();
return;
@@ -586,7 +762,7 @@ void GLRenderingVDAClient::NotifyResetDone() {
rendering_helper_->Flush(window_id_);
- if (frames_at_render_ == 0) {
+ if (pending_textures_.empty()) {
SetState(CS_RESET);
DeleteDecoder();
}
@@ -645,11 +821,8 @@ void GLRenderingVDAClient::DeleteDecoder() {
weak_decoder_factory_.reset();
decoder_.reset();
STLClearObject(&encoded_data_);
- for (std::set<int>::iterator it = outstanding_texture_ids_.begin();
- it != outstanding_texture_ids_.end(); ++it) {
- rendering_helper_->DeleteTexture(*it);
- }
- outstanding_texture_ids_.clear();
+ active_textures_.clear();
+
// Cascade through the rest of the states to simplify test code below.
for (int i = state_ + 1; i < CS_MAX; ++i)
SetState(static_cast<ClientState>(i));
@@ -668,7 +841,7 @@ std::string GLRenderingVDAClient::GetBytesForFirstFragment(
*end_pos = start_pos;
return std::string();
}
- DCHECK_LE(profile_, media::VP8PROFILE_MAX);
+ DCHECK_LE(profile_, media::VP9PROFILE_MAX);
return GetBytesForNextFragment(start_pos, end_pos);
}
@@ -682,7 +855,7 @@ std::string GLRenderingVDAClient::GetBytesForNextFragment(
}
return encoded_data_.substr(start_pos, *end_pos - start_pos);
}
- DCHECK_LE(profile_, media::VP8PROFILE_MAX);
+ DCHECK_LE(profile_, media::VP9PROFILE_MAX);
return GetBytesForNextFrame(start_pos, end_pos);
}
@@ -731,7 +904,7 @@ static bool FragmentHasConfigInfo(const uint8* data, size_t size,
return nalu.nal_unit_type == media::H264NALU::kSPS;
} else if (profile >= media::VP8PROFILE_MIN &&
- profile <= media::VP8PROFILE_MAX) {
+ profile <= media::VP9PROFILE_MAX) {
return (size > 0 && !(data[0] & 0x01));
}
// Shouldn't happen at this point.
@@ -827,8 +1000,8 @@ base::TimeDelta GLRenderingVDAClient::decode_time_median() {
class VideoDecodeAcceleratorTest : public ::testing::Test {
protected:
VideoDecodeAcceleratorTest();
- virtual void SetUp();
- virtual void TearDown();
+ void SetUp() override;
+ void TearDown() override;
// Parse |data| into its constituent parts, set the various output fields
// accordingly, and read in video stream. CHECK-fails on unexpected or
@@ -854,50 +1027,33 @@ class VideoDecodeAcceleratorTest : public ::testing::Test {
std::vector<TestVideoFile*> test_video_files_;
RenderingHelper rendering_helper_;
- scoped_refptr<base::MessageLoopProxy> rendering_loop_proxy_;
private:
- base::Thread rendering_thread_;
// Required for Thread to work. Not used otherwise.
base::ShadowingAtExitManager at_exit_manager_;
DISALLOW_COPY_AND_ASSIGN(VideoDecodeAcceleratorTest);
};
-VideoDecodeAcceleratorTest::VideoDecodeAcceleratorTest()
- : rendering_thread_("GLRenderingVDAClientThread") {}
+VideoDecodeAcceleratorTest::VideoDecodeAcceleratorTest() {
+}
void VideoDecodeAcceleratorTest::SetUp() {
ParseAndReadTestVideoData(g_test_video_data, &test_video_files_);
-
- // Initialize the rendering thread.
- base::Thread::Options options;
- options.message_loop_type = base::MessageLoop::TYPE_DEFAULT;
-#if defined(OS_WIN)
- // For windows the decoding thread initializes the media foundation decoder
- // which uses COM. We need the thread to be a UI thread.
- options.message_loop_type = base::MessageLoop::TYPE_UI;
-#endif // OS_WIN
-
- rendering_thread_.StartWithOptions(options);
- rendering_loop_proxy_ = rendering_thread_.message_loop_proxy();
}
void VideoDecodeAcceleratorTest::TearDown() {
- rendering_loop_proxy_->PostTask(
- FROM_HERE,
- base::Bind(&STLDeleteElements<std::vector<TestVideoFile*> >,
- &test_video_files_));
+ g_env->GetRenderingTaskRunner()->PostTask(
+ FROM_HERE, base::Bind(&STLDeleteElements<std::vector<TestVideoFile*>>,
+ &test_video_files_));
base::WaitableEvent done(false, false);
- rendering_loop_proxy_->PostTask(
- FROM_HERE,
- base::Bind(&RenderingHelper::UnInitialize,
- base::Unretained(&rendering_helper_),
- &done));
+ g_env->GetRenderingTaskRunner()->PostTask(
+ FROM_HERE, base::Bind(&RenderingHelper::UnInitialize,
+ base::Unretained(&rendering_helper_), &done));
done.Wait();
- rendering_thread_.Stop();
+ rendering_helper_.TearDown();
}
void VideoDecodeAcceleratorTest::ParseAndReadTestVideoData(
@@ -965,23 +1121,22 @@ void VideoDecodeAcceleratorTest::UpdateTestVideoFileParams(
void VideoDecodeAcceleratorTest::InitializeRenderingHelper(
const RenderingHelperParams& helper_params) {
+ rendering_helper_.Setup();
+
base::WaitableEvent done(false, false);
- rendering_loop_proxy_->PostTask(
+ g_env->GetRenderingTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&RenderingHelper::Initialize,
- base::Unretained(&rendering_helper_),
- helper_params,
- &done));
+ base::Unretained(&rendering_helper_), helper_params, &done));
done.Wait();
}
void VideoDecodeAcceleratorTest::CreateAndStartDecoder(
GLRenderingVDAClient* client,
ClientStateNotification<ClientState>* note) {
- rendering_loop_proxy_->PostTask(
- FROM_HERE,
- base::Bind(&GLRenderingVDAClient::CreateAndStartDecoder,
- base::Unretained(client)));
+ g_env->GetRenderingTaskRunner()->PostTask(
+ FROM_HERE, base::Bind(&GLRenderingVDAClient::CreateAndStartDecoder,
+ base::Unretained(client)));
ASSERT_EQ(note->Wait(), CS_DECODER_SET);
}
@@ -995,7 +1150,7 @@ void VideoDecodeAcceleratorTest::WaitUntilDecodeFinish(
void VideoDecodeAcceleratorTest::WaitUntilIdle() {
base::WaitableEvent done(false, false);
- rendering_loop_proxy_->PostTask(
+ g_env->GetRenderingTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&base::WaitableEvent::Signal, base::Unretained(&done)));
done.Wait();
@@ -1010,7 +1165,9 @@ void VideoDecodeAcceleratorTest::OutputLogFile(
}
// Test parameters:
-// - Number of concurrent decoders.
+// - Number of concurrent decoders. The value takes effect when there is only
+// one input stream; otherwise, one decoder per input stream will be
+// instantiated.
// - Number of concurrent in-flight Decode() calls per decoder.
// - Number of play-throughs.
// - reset_after_frame_num: see GLRenderingVDAClient ctor.
@@ -1020,16 +1177,17 @@ void VideoDecodeAcceleratorTest::OutputLogFile(
class VideoDecodeAcceleratorParamTest
: public VideoDecodeAcceleratorTest,
public ::testing::WithParamInterface<
- Tuple7<int, int, int, ResetPoint, ClientState, bool, bool> > {
+ Tuple<int, int, int, ResetPoint, ClientState, bool, bool> > {
};
// Helper so that gtest failures emit a more readable version of the tuple than
// its byte representation.
::std::ostream& operator<<(
::std::ostream& os,
- const Tuple7<int, int, int, ResetPoint, ClientState, bool, bool>& t) {
- return os << t.a << ", " << t.b << ", " << t.c << ", " << t.d << ", " << t.e
- << ", " << t.f << ", " << t.g;
+ const Tuple<int, int, int, ResetPoint, ClientState, bool, bool>& t) {
+ return os << get<0>(t) << ", " << get<1>(t) << ", " << get<2>(t) << ", "
+ << get<3>(t) << ", " << get<4>(t) << ", " << get<5>(t) << ", "
+ << get<6>(t);
}
// Wait for |note| to report a state and if it's not |expected_state| then
@@ -1053,13 +1211,19 @@ enum { kMinSupportedNumConcurrentDecoders = 3 };
// Test the most straightforward case possible: data is decoded from a single
// chunk and rendered to the screen.
TEST_P(VideoDecodeAcceleratorParamTest, TestSimpleDecode) {
- const size_t num_concurrent_decoders = GetParam().a;
- const size_t num_in_flight_decodes = GetParam().b;
- const int num_play_throughs = GetParam().c;
- const int reset_point = GetParam().d;
- const int delete_decoder_state = GetParam().e;
- bool test_reuse_delay = GetParam().f;
- const bool render_as_thumbnails = GetParam().g;
+ size_t num_concurrent_decoders = get<0>(GetParam());
+ const size_t num_in_flight_decodes = get<1>(GetParam());
+ int num_play_throughs = get<2>(GetParam());
+ const int reset_point = get<3>(GetParam());
+ const int delete_decoder_state = get<4>(GetParam());
+ bool test_reuse_delay = get<5>(GetParam());
+ const bool render_as_thumbnails = get<6>(GetParam());
+
+ if (test_video_files_.size() > 1)
+ num_concurrent_decoders = test_video_files_.size();
+
+ if (g_num_play_throughs > 0)
+ num_play_throughs = g_num_play_throughs;
UpdateTestVideoFileParams(
num_concurrent_decoders, reset_point, &test_video_files_);
@@ -1108,6 +1272,7 @@ TEST_P(VideoDecodeAcceleratorParamTest, TestSimpleDecode) {
video_file->width,
video_file->height,
video_file->profile,
+ g_fake_decoder,
suppress_rendering,
delay_after_frame_num,
0,
@@ -1201,11 +1366,10 @@ TEST_P(VideoDecodeAcceleratorParamTest, TestSimpleDecode) {
std::vector<unsigned char> rgb;
bool alpha_solid;
base::WaitableEvent done(false, false);
- rendering_loop_proxy_->PostTask(
- FROM_HERE,
- base::Bind(&RenderingHelper::GetThumbnailsAsRGB,
- base::Unretained(&rendering_helper_),
- &rgb, &alpha_solid, &done));
+ g_env->GetRenderingTaskRunner()->PostTask(
+ FROM_HERE, base::Bind(&RenderingHelper::GetThumbnailsAsRGB,
+ base::Unretained(&rendering_helper_), &rgb,
+ &alpha_solid, &done));
done.Wait();
std::vector<std::string> golden_md5s;
@@ -1251,14 +1415,14 @@ TEST_P(VideoDecodeAcceleratorParamTest, TestSimpleDecode) {
}
}
- rendering_loop_proxy_->PostTask(
+ g_env->GetRenderingTaskRunner()->PostTask(
FROM_HERE,
- base::Bind(&STLDeleteElements<std::vector<GLRenderingVDAClient*> >,
+ base::Bind(&STLDeleteElements<std::vector<GLRenderingVDAClient*>>,
&clients));
- rendering_loop_proxy_->PostTask(
+ g_env->GetRenderingTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&STLDeleteElements<
- std::vector<ClientStateNotification<ClientState>*> >,
+ std::vector<ClientStateNotification<ClientState>*>>,
&notes));
WaitUntilIdle();
};
@@ -1362,6 +1526,7 @@ TEST_F(VideoDecodeAcceleratorTest, TestDecodeTimeMedian) {
test_video_files_[0]->width,
test_video_files_[0]->height,
test_video_files_[0]->profile,
+ g_fake_decoder,
true,
std::numeric_limits<int>::max(),
kWebRtcDecodeCallsPerSecond,
@@ -1381,8 +1546,8 @@ TEST_F(VideoDecodeAcceleratorTest, TestDecodeTimeMedian) {
if (g_output_log != NULL)
OutputLogFile(g_output_log, output_string);
- rendering_loop_proxy_->DeleteSoon(FROM_HERE, client);
- rendering_loop_proxy_->DeleteSoon(FROM_HERE, note);
+ g_env->GetRenderingTaskRunner()->DeleteSoon(FROM_HERE, client);
+ g_env->GetRenderingTaskRunner()->DeleteSoon(FROM_HERE, note);
WaitUntilIdle();
};
@@ -1408,7 +1573,7 @@ int main(int argc, char **argv) {
DCHECK(cmd_line);
base::CommandLine::SwitchMap switches = cmd_line->GetSwitches();
- for (CommandLine::SwitchMap::const_iterator it = switches.begin();
+ for (base::CommandLine::SwitchMap::const_iterator it = switches.begin();
it != switches.end(); ++it) {
if (it->first == "test_video_data") {
content::g_test_video_data = it->second.c_str();
@@ -1436,13 +1601,46 @@ int main(int argc, char **argv) {
content::g_rendering_fps = 0;
continue;
}
+
+ if (it->first == "num_play_throughs") {
+ std::string input(it->second.begin(), it->second.end());
+ CHECK(base::StringToInt(input, &content::g_num_play_throughs));
+ continue;
+ }
+ if (it->first == "fake_decoder") {
+ content::g_fake_decoder = 1;
+ continue;
+ }
if (it->first == "v" || it->first == "vmodule")
continue;
+ if (it->first == "ozone-platform" || it->first == "ozone-use-surfaceless")
+ continue;
LOG(FATAL) << "Unexpected switch: " << it->first << ":" << it->second;
}
base::ShadowingAtExitManager at_exit_manager;
- content::RenderingHelper::InitializeOneOff();
+#if defined(OS_WIN) || defined(USE_OZONE)
+ // For windows the decoding thread initializes the media foundation decoder
+ // which uses COM. We need the thread to be a UI thread.
+ // On Ozone, the backend initializes the event system using a UI
+ // thread.
+ base::MessageLoopForUI main_loop;
+#else
+ base::MessageLoop main_loop;
+#endif // OS_WIN || USE_OZONE
+
+#if defined(USE_OZONE)
+ ui::OzonePlatform::InitializeForUI();
+#endif
+
+#if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)
+ content::VaapiWrapper::PreSandboxInitialization();
+#endif
+
+ content::g_env =
+ reinterpret_cast<content::VideoDecodeAcceleratorTestEnvironment*>(
+ testing::AddGlobalTestEnvironment(
+ new content::VideoDecodeAcceleratorTestEnvironment()));
return RUN_ALL_TESTS();
}
diff --git a/chromium/content/common/gpu/media/video_encode_accelerator_unittest.cc b/chromium/content/common/gpu/media/video_encode_accelerator_unittest.cc
index b1fb5922666..8405ac34a7b 100644
--- a/chromium/content/common/gpu/media/video_encode_accelerator_unittest.cc
+++ b/chromium/content/common/gpu/media/video_encode_accelerator_unittest.cc
@@ -2,6 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <inttypes.h>
+
+#include <algorithm>
+
#include "base/at_exit.h"
#include "base/bind.h"
#include "base/command_line.h"
@@ -12,23 +16,27 @@
#include "base/process/process_handle.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
+#include "base/strings/stringprintf.h"
+#include "base/sys_byteorder.h"
#include "base/time/time.h"
+#include "base/timer/timer.h"
#include "content/common/gpu/media/video_accelerator_unittest_helpers.h"
#include "media/base/bind_to_current_loop.h"
#include "media/base/bitstream_buffer.h"
#include "media/base/test_data_util.h"
#include "media/filters/h264_parser.h"
+#include "media/video/fake_video_encode_accelerator.h"
#include "media/video/video_encode_accelerator.h"
#include "testing/gtest/include/gtest/gtest.h"
-#if defined(USE_X11)
-#include "ui/gfx/x/x11_types.h"
-#endif
-
-#if defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL)
+#if defined(OS_CHROMEOS)
+#if defined(ARCH_CPU_ARMEL) || (defined(USE_OZONE) && defined(USE_V4L2_CODEC))
#include "content/common/gpu/media/v4l2_video_encode_accelerator.h"
-#elif defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) && defined(USE_X11)
+#endif
+#if defined(ARCH_CPU_X86_FAMILY)
#include "content/common/gpu/media/vaapi_video_encode_accelerator.h"
+#include "content/common/gpu/media/vaapi_wrapper.h"
+#endif // defined(ARCH_CPU_X86_FAMILY)
#else
#error The VideoEncodeAcceleratorUnittest is not supported on this platform.
#endif
@@ -46,9 +54,6 @@ const unsigned int kNumExtraInputFrames = 4;
// Maximum delay between requesting a keyframe and receiving one, in frames.
// Arbitrarily chosen as a reasonable requirement.
const unsigned int kMaxKeyframeDelay = 4;
-// Value to use as max frame number for keyframe detection.
-const unsigned int kMaxFrameNum =
- std::numeric_limits<unsigned int>::max() - kMaxKeyframeDelay;
// Default initial bitrate.
const uint32 kDefaultBitrate = 2000000;
// Default ratio of requested_subsequent_bitrate to initial_bitrate
@@ -69,6 +74,8 @@ const uint32 kMinPerfFPS = 30;
// The input stream will be looped as many times as needed in bitrate tests
// to reach at least this number of frames before calculating final bitrate.
const unsigned int kMinFramesForBitrateTests = 300;
+// The percentiles to measure for encode latency.
+const unsigned int kLoggedLatencyPercentiles[] = {50, 75, 95};
// The syntax of multiple test streams is:
// test-stream1;test-stream2;test-stream3
@@ -79,8 +86,12 @@ const unsigned int kMinFramesForBitrateTests = 300;
// (see http://www.fourcc.org/yuv.php#IYUV).
// - |width| and |height| are in pixels.
// - |profile| to encode into (values of media::VideoCodecProfile).
-// - |out_filename| filename to save the encoded stream to (optional).
-// Output stream is saved for the simple encode test only.
+// - |out_filename| filename to save the encoded stream to (optional). The
+// format for H264 is Annex-B byte stream. The format for VP8 is IVF. Output
+// stream is saved for the simple encode test only. H264 raw stream and IVF
+// can be used as input of VDA unittest. H264 raw stream can be played by
+// "mplayer -fps 25 out.h264" and IVF can be played by mplayer directly.
+// Helpful description: http://wiki.multimedia.cx/index.php?title=IVF
// Further parameters are optional (need to provide preceding positional
// parameters if a specific subsequent parameter is required):
// - |requested_bitrate| requested bitrate in bits per second.
@@ -92,10 +103,39 @@ const unsigned int kMinFramesForBitrateTests = 300;
// Bitrate is only forced for tests that test bitrate.
const char* g_default_in_filename = "bear_320x192_40frames.yuv";
const char* g_default_in_parameters = ":320:192:1:out.h264:200000";
+
+// Enabled by including a --fake_encoder flag to the command line invoking the
+// test.
+bool g_fake_encoder = false;
+
// Environment to store test stream data for all test cases.
class VideoEncodeAcceleratorTestEnvironment;
VideoEncodeAcceleratorTestEnvironment* g_env;
+struct IvfFileHeader {
+ char signature[4]; // signature: 'DKIF'
+ uint16_t version; // version (should be 0)
+ uint16_t header_size; // size of header in bytes
+ uint32_t fourcc; // codec FourCC (e.g., 'VP80')
+ uint16_t width; // width in pixels
+ uint16_t height; // height in pixels
+ uint32_t framerate; // frame rate per seconds
+ uint32_t timescale; // time scale. For example, if framerate is 30 and
+ // timescale is 2, the unit of IvfFrameHeader.timestamp
+ // is 2/30 seconds.
+ uint32_t num_frames; // number of frames in file
+ uint32_t unused; // unused
+} __attribute__((packed));
+
+struct IvfFrameHeader {
+ uint32_t frame_size; // Size of frame in bytes (not including the header)
+ uint64_t timestamp; // 64-bit presentation timestamp
+} __attribute__((packed));
+
+// The number of frames to be encoded. This variable is set by the switch
+// "--num_frames_to_encode". Ignored if 0.
+int g_num_frames_to_encode = 0;
+
struct TestStream {
TestStream()
: num_frames(0),
@@ -156,6 +196,27 @@ static bool WriteFile(base::File* file,
return true;
}
+// Return the |percentile| from a sorted vector.
+static base::TimeDelta Percentile(
+ const std::vector<base::TimeDelta>& sorted_values,
+ unsigned int percentile) {
+ size_t size = sorted_values.size();
+ CHECK_GT(size, 0UL);
+ CHECK_LE(percentile, 100UL);
+ // Use Nearest Rank method in http://en.wikipedia.org/wiki/Percentile.
+ int index =
+ std::max(static_cast<int>(ceil(0.01f * percentile * size)) - 1, 0);
+ return sorted_values[index];
+}
+
+static bool IsH264(media::VideoCodecProfile profile) {
+ return profile >= media::H264PROFILE_MIN && profile <= media::H264PROFILE_MAX;
+}
+
+static bool IsVP8(media::VideoCodecProfile profile) {
+ return profile >= media::VP8PROFILE_MIN && profile <= media::VP8PROFILE_MAX;
+}
+
// ARM performs CPU cache management with CPU cache line granularity. We thus
// need to ensure our buffers are CPU cache line-aligned (64 byte-aligned).
// Otherwise newer kernels will refuse to accept them, and on older kernels
@@ -254,7 +315,6 @@ static void CreateAlignedInputStreamFile(const gfx::Size& coded_size,
0U)
<< "Stream byte size is not a product of calculated frame byte size";
CHECK_GT(test_stream->num_frames, 0UL);
- CHECK_LE(test_stream->num_frames, kMaxFrameNum);
}
// Parse |data| into its constituent parts, set the various output fields
@@ -309,6 +369,71 @@ static void ParseAndReadTestStreamData(const base::FilePath::StringType& data,
}
}
+// Basic test environment shared across multiple test cases. We only need to
+// setup it once for all test cases.
+// It helps
+// - maintain test stream data and other test settings.
+// - clean up temporary aligned files.
+// - output log to file.
+class VideoEncodeAcceleratorTestEnvironment : public ::testing::Environment {
+ public:
+ VideoEncodeAcceleratorTestEnvironment(
+ scoped_ptr<base::FilePath::StringType> data,
+ const base::FilePath& log_path,
+ bool run_at_fps,
+ bool needs_encode_latency)
+ : test_stream_data_(data.Pass()),
+ log_path_(log_path),
+ run_at_fps_(run_at_fps),
+ needs_encode_latency_(needs_encode_latency) {}
+
+ virtual void SetUp() {
+ if (!log_path_.empty()) {
+ log_file_.reset(new base::File(
+ log_path_, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE));
+ CHECK(log_file_->IsValid());
+ }
+ ParseAndReadTestStreamData(*test_stream_data_, &test_streams_);
+ }
+
+ virtual void TearDown() {
+ for (size_t i = 0; i < test_streams_.size(); i++) {
+ base::DeleteFile(test_streams_[i]->aligned_in_file, false);
+ }
+ log_file_.reset();
+ }
+
+ // Log one entry of machine-readable data to file and LOG(INFO).
+ // The log has one data entry per line in the format of "<key>: <value>".
+ // Note that Chrome OS video_VEAPerf autotest parses the output key and value
+ // pairs. Be sure to keep the autotest in sync.
+ void LogToFile(const std::string& key, const std::string& value) {
+ std::string s = base::StringPrintf("%s: %s\n", key.c_str(), value.c_str());
+ LOG(INFO) << s;
+ if (log_file_) {
+ log_file_->WriteAtCurrentPos(s.data(), s.length());
+ }
+ }
+
+ // Feed the encoder with the input buffers at the requested framerate. If
+ // false, feed as fast as possible. This is set by the command line switch
+ // "--run_at_fps".
+ bool run_at_fps() const { return run_at_fps_; }
+
+ // Whether to measure encode latency. This is set by the command line switch
+ // "--measure_latency".
+ bool needs_encode_latency() const { return needs_encode_latency_; }
+
+ ScopedVector<TestStream> test_streams_;
+
+ private:
+ scoped_ptr<base::FilePath::StringType> test_stream_data_;
+ base::FilePath log_path_;
+ scoped_ptr<base::File> log_file_;
+ bool run_at_fps_;
+ bool needs_encode_latency_;
+};
+
enum ClientState {
CS_CREATED,
CS_ENCODER_SET,
@@ -354,7 +479,7 @@ class H264Validator : public StreamValidator {
seen_pps_(false),
seen_idr_(false) {}
- virtual void ProcessStreamBuffer(const uint8* stream, size_t size) override;
+ void ProcessStreamBuffer(const uint8* stream, size_t size) override;
private:
// Set to true when encoder provides us with the corresponding NALU type.
@@ -421,7 +546,7 @@ class VP8Validator : public StreamValidator {
: StreamValidator(frame_cb),
seen_keyframe_(false) {}
- virtual void ProcessStreamBuffer(const uint8* stream, size_t size) override;
+ void ProcessStreamBuffer(const uint8* stream, size_t size) override;
private:
// Have we already got a keyframe in the stream?
@@ -447,11 +572,9 @@ scoped_ptr<StreamValidator> StreamValidator::Create(
const FrameFoundCallback& frame_cb) {
scoped_ptr<StreamValidator> validator;
- if (profile >= media::H264PROFILE_MIN &&
- profile <= media::H264PROFILE_MAX) {
+ if (IsH264(profile)) {
validator.reset(new H264Validator(frame_cb));
- } else if (profile >= media::VP8PROFILE_MIN &&
- profile <= media::VP8PROFILE_MAX) {
+ } else if (IsVP8(profile)) {
validator.reset(new VP8Validator(frame_cb));
} else {
LOG(FATAL) << "Unsupported profile: " << profile;
@@ -470,25 +593,29 @@ class VEAClient : public VideoEncodeAccelerator::Client {
bool test_perf,
bool mid_stream_bitrate_switch,
bool mid_stream_framerate_switch);
- virtual ~VEAClient();
+ ~VEAClient() override;
void CreateEncoder();
void DestroyEncoder();
- // Return the number of encoded frames per second.
- double frames_per_second();
-
// VideoDecodeAccelerator::Client implementation.
- virtual void RequireBitstreamBuffers(unsigned int input_count,
- const gfx::Size& input_coded_size,
- size_t output_buffer_size) override;
- virtual void BitstreamBufferReady(int32 bitstream_buffer_id,
- size_t payload_size,
- bool key_frame) override;
- virtual void NotifyError(VideoEncodeAccelerator::Error error) override;
+ void RequireBitstreamBuffers(unsigned int input_count,
+ const gfx::Size& input_coded_size,
+ size_t output_buffer_size) override;
+ void BitstreamBufferReady(int32 bitstream_buffer_id,
+ size_t payload_size,
+ bool key_frame) override;
+ void NotifyError(VideoEncodeAccelerator::Error error) override;
private:
bool has_encoder() { return encoder_.get(); }
+ // Return the number of encoded frames per second.
+ double frames_per_second();
+
+ scoped_ptr<media::VideoEncodeAccelerator> CreateFakeVEA();
+ scoped_ptr<media::VideoEncodeAccelerator> CreateV4L2VEA();
+ scoped_ptr<media::VideoEncodeAccelerator> CreateVaapiVEA();
+
void SetState(ClientState new_state);
// Set current stream parameters to given |bitrate| at |framerate|.
@@ -497,9 +624,8 @@ class VEAClient : public VideoEncodeAccelerator::Client {
// Called when encoder is done with a VideoFrame.
void InputNoLongerNeededCallback(int32 input_id);
- // Ensure encoder has at least as many inputs as it asked for
- // via RequireBitstreamBuffers().
- void FeedEncoderWithInputs();
+ // Feed the encoder with one input frame.
+ void FeedEncoderWithOneInput();
// Provide the encoder with a new output buffer.
void FeedEncoderWithOutput(base::SharedMemory* shm);
@@ -509,37 +635,58 @@ class VEAClient : public VideoEncodeAccelerator::Client {
// and accounting. Returns false once we have collected all frames we needed.
bool HandleEncodedFrame(bool keyframe);
+ // Verify the minimum FPS requirement.
+ void VerifyMinFPS();
+
// Verify that stream bitrate has been close to current_requested_bitrate_,
// assuming current_framerate_ since the last time VerifyStreamProperties()
// was called. Fail the test if |force_bitrate_| is true and the bitrate
// is not within kBitrateTolerance.
void VerifyStreamProperties();
- // Test codec performance, failing the test if we are currently running
- // the performance test.
- void VerifyPerf();
+ // Log the performance data.
+ void LogPerf();
+
+ // Write IVF file header to test_stream_->out_filename.
+ void WriteIvfFileHeader();
+
+ // Write an IVF frame header to test_stream_->out_filename.
+ void WriteIvfFrameHeader(int frame_index, size_t frame_size);
- // Prepare and return a frame wrapping the data at |position| bytes in
- // the input stream, ready to be sent to encoder.
- scoped_refptr<media::VideoFrame> PrepareInputFrame(off_t position);
+ // Prepare and return a frame wrapping the data at |position| bytes in the
+ // input stream, ready to be sent to encoder.
+ // The input frame id is returned in |input_id|.
+ scoped_refptr<media::VideoFrame> PrepareInputFrame(off_t position,
+ int32* input_id);
// Update the parameters according to |mid_stream_bitrate_switch| and
// |mid_stream_framerate_switch|.
void UpdateTestStreamData(bool mid_stream_bitrate_switch,
bool mid_stream_framerate_switch);
+ // Callback function of the |input_timer_|.
+ void OnInputTimer();
+
ClientState state_;
scoped_ptr<VideoEncodeAccelerator> encoder_;
TestStream* test_stream_;
+
// Used to notify another thread about the state. VEAClient does not own this.
ClientStateNotification<ClientState>* note_;
- // Ids assigned to VideoFrames (start at 1 for easy comparison with
- // num_encoded_frames_).
+ // Ids assigned to VideoFrames.
std::set<int32> inputs_at_client_;
int32 next_input_id_;
+ // Encode start time of all encoded frames. The position in the vector is the
+ // frame input id.
+ std::vector<base::TimeTicks> encode_start_time_;
+ // The encode latencies of all encoded frames. We define encode latency as the
+ // time delay from input of each VideoFrame (VEA::Encode()) to output of the
+ // corresponding BitstreamBuffer (VEA::Client::BitstreamBufferReady()).
+ std::vector<base::TimeDelta> encode_latencies_;
+
// Ids for output BitstreamBuffers.
typedef std::map<int32, base::SharedMemory*> IdToSHM;
ScopedVector<base::SharedMemory> output_shms_;
@@ -572,8 +719,11 @@ class VEAClient : public VideoEncodeAccelerator::Client {
// Request a keyframe every keyframe_period_ frames.
const unsigned int keyframe_period_;
- // Frame number for which we requested a keyframe.
- unsigned int keyframe_requested_at_;
+ // Number of keyframes requested by now.
+ unsigned int num_keyframes_requested_;
+
+ // Next keyframe expected before next_keyframe_at_ + kMaxKeyframeDelay.
+ unsigned int next_keyframe_at_;
// True if we are asking encoder for a particular bitrate.
bool force_bitrate_;
@@ -593,9 +743,6 @@ class VEAClient : public VideoEncodeAccelerator::Client {
scoped_ptr<StreamValidator> validator_;
- // The time when the encoding started.
- base::TimeTicks encode_start_time_;
-
// The time when the last encoded frame is ready.
base::TimeTicks last_frame_ready_time_;
@@ -613,6 +760,9 @@ class VEAClient : public VideoEncodeAccelerator::Client {
// Framerate to switch to in the middle of the stream.
unsigned int requested_subsequent_framerate_;
+
+ // The timer used to feed the encoder with the input frames.
+ scoped_ptr<base::RepeatingTimer<VEAClient>> input_timer_;
};
VEAClient::VEAClient(TestStream* test_stream,
@@ -626,7 +776,7 @@ VEAClient::VEAClient(TestStream* test_stream,
: state_(CS_CREATED),
test_stream_(test_stream),
note_(note),
- next_input_id_(1),
+ next_input_id_(0),
next_output_buffer_id_(0),
pos_in_input_stream_(0),
num_required_input_buffers_(0),
@@ -637,7 +787,8 @@ VEAClient::VEAClient(TestStream* test_stream,
seen_keyframe_in_this_buffer_(false),
save_to_file_(save_to_file),
keyframe_period_(keyframe_period),
- keyframe_requested_at_(kMaxFrameNum),
+ num_keyframes_requested_(0),
+ next_keyframe_at_(0),
force_bitrate_(force_bitrate),
current_requested_bitrate_(0),
current_framerate_(0),
@@ -650,11 +801,13 @@ VEAClient::VEAClient(TestStream* test_stream,
if (keyframe_period_)
CHECK_LT(kMaxKeyframeDelay, keyframe_period_);
- validator_ = StreamValidator::Create(
- test_stream_->requested_profile,
- base::Bind(&VEAClient::HandleEncodedFrame, base::Unretained(this)));
-
- CHECK(validator_.get());
+ // Fake encoder produces an invalid stream, so skip validating it.
+ if (!g_fake_encoder) {
+ validator_ = StreamValidator::Create(
+ test_stream_->requested_profile,
+ base::Bind(&VEAClient::HandleEncodedFrame, base::Unretained(this)));
+ CHECK(validator_);
+ }
if (save_to_file_) {
CHECK(!test_stream_->out_filename.empty());
@@ -672,33 +825,66 @@ VEAClient::VEAClient(TestStream* test_stream,
VEAClient::~VEAClient() { CHECK(!has_encoder()); }
+scoped_ptr<media::VideoEncodeAccelerator> VEAClient::CreateFakeVEA() {
+ scoped_ptr<media::VideoEncodeAccelerator> encoder;
+ if (g_fake_encoder) {
+ encoder.reset(new media::FakeVideoEncodeAccelerator(
+ scoped_refptr<base::SingleThreadTaskRunner>(
+ base::ThreadTaskRunnerHandle::Get())));
+ }
+ return encoder.Pass();
+}
+
+scoped_ptr<media::VideoEncodeAccelerator> VEAClient::CreateV4L2VEA() {
+ scoped_ptr<media::VideoEncodeAccelerator> encoder;
+#if defined(OS_CHROMEOS) && (defined(ARCH_CPU_ARMEL) || \
+ (defined(USE_OZONE) && defined(USE_V4L2_CODEC)))
+ scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kEncoder);
+ if (device)
+ encoder.reset(new V4L2VideoEncodeAccelerator(device));
+#endif
+ return encoder.Pass();
+}
+
+scoped_ptr<media::VideoEncodeAccelerator> VEAClient::CreateVaapiVEA() {
+ scoped_ptr<media::VideoEncodeAccelerator> encoder;
+#if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)
+ encoder.reset(new VaapiVideoEncodeAccelerator());
+#endif
+ return encoder.Pass();
+}
+
void VEAClient::CreateEncoder() {
DCHECK(thread_checker_.CalledOnValidThread());
CHECK(!has_encoder());
-#if defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL)
- scoped_ptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kEncoder);
- encoder_.reset(new V4L2VideoEncodeAccelerator(device.Pass()));
-#elif defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) && defined(USE_X11)
- encoder_.reset(new VaapiVideoEncodeAccelerator(gfx::GetXDisplay()));
-#endif
-
- SetState(CS_ENCODER_SET);
+ scoped_ptr<media::VideoEncodeAccelerator> encoders[] = {
+ CreateFakeVEA(),
+ CreateV4L2VEA(),
+ CreateVaapiVEA()
+ };
DVLOG(1) << "Profile: " << test_stream_->requested_profile
<< ", initial bitrate: " << requested_bitrate_;
- if (!encoder_->Initialize(kInputFormat,
- test_stream_->visible_size,
- test_stream_->requested_profile,
- requested_bitrate_,
- this)) {
- LOG(ERROR) << "VideoEncodeAccelerator::Initialize() failed";
- SetState(CS_ERROR);
- return;
- }
- SetStreamParameters(requested_bitrate_, requested_framerate_);
- SetState(CS_INITIALIZED);
+ for (size_t i = 0; i < arraysize(encoders); ++i) {
+ if (!encoders[i])
+ continue;
+ encoder_ = encoders[i].Pass();
+ SetState(CS_ENCODER_SET);
+ if (encoder_->Initialize(kInputFormat,
+ test_stream_->visible_size,
+ test_stream_->requested_profile,
+ requested_bitrate_,
+ this)) {
+ SetStreamParameters(requested_bitrate_, requested_framerate_);
+ SetState(CS_INITIALIZED);
+ return;
+ }
+ }
+ encoder_.reset();
+ LOG(ERROR) << "VideoEncodeAccelerator::Initialize() failed";
+ SetState(CS_ERROR);
}
void VEAClient::DestroyEncoder() {
@@ -706,6 +892,7 @@ void VEAClient::DestroyEncoder() {
if (!has_encoder())
return;
encoder_.reset();
+ input_timer_.reset();
}
void VEAClient::UpdateTestStreamData(bool mid_stream_bitrate_switch,
@@ -753,7 +940,8 @@ void VEAClient::UpdateTestStreamData(bool mid_stream_bitrate_switch,
}
double VEAClient::frames_per_second() {
- base::TimeDelta duration = last_frame_ready_time_ - encode_start_time_;
+ CHECK(!encode_start_time_.empty());
+ base::TimeDelta duration = last_frame_ready_time_ - encode_start_time_[0];
return num_encoded_frames_ / duration.InSecondsF();
}
@@ -766,16 +954,25 @@ void VEAClient::RequireBitstreamBuffers(unsigned int input_count,
CreateAlignedInputStreamFile(input_coded_size, test_stream_);
+ num_frames_to_encode_ = test_stream_->num_frames;
+ if (g_num_frames_to_encode > 0)
+ num_frames_to_encode_ = g_num_frames_to_encode;
+
+ // Speed up vector insertion.
+ encode_start_time_.reserve(num_frames_to_encode_);
+ if (g_env->needs_encode_latency())
+ encode_latencies_.reserve(num_frames_to_encode_);
+
// We may need to loop over the stream more than once if more frames than
// provided is required for bitrate tests.
- if (force_bitrate_ && test_stream_->num_frames < kMinFramesForBitrateTests) {
+ if (force_bitrate_ && num_frames_to_encode_ < kMinFramesForBitrateTests) {
DVLOG(1) << "Stream too short for bitrate test ("
<< test_stream_->num_frames << " frames), will loop it to reach "
<< kMinFramesForBitrateTests << " frames";
num_frames_to_encode_ = kMinFramesForBitrateTests;
- } else {
- num_frames_to_encode_ = test_stream_->num_frames;
}
+ if (save_to_file_ && IsVP8(test_stream_->requested_profile))
+ WriteIvfFileHeader();
input_coded_size_ = input_coded_size;
num_required_input_buffers_ = input_count;
@@ -791,8 +988,16 @@ void VEAClient::RequireBitstreamBuffers(unsigned int input_count,
FeedEncoderWithOutput(shm);
}
- encode_start_time_ = base::TimeTicks::Now();
- FeedEncoderWithInputs();
+ if (g_env->run_at_fps()) {
+ input_timer_.reset(new base::RepeatingTimer<VEAClient>());
+ input_timer_->Start(
+ FROM_HERE, base::TimeDelta::FromSeconds(1) / current_framerate_,
+ base::Bind(&VEAClient::OnInputTimer, base::Unretained(this)));
+ } else {
+ while (inputs_at_client_.size() <
+ num_required_input_buffers_ + kNumExtraInputFrames)
+ FeedEncoderWithOneInput();
+ }
}
void VEAClient::BitstreamBufferReady(int32 bitstream_buffer_id,
@@ -812,20 +1017,27 @@ void VEAClient::BitstreamBufferReady(int32 bitstream_buffer_id,
encoded_stream_size_since_last_check_ += payload_size;
const uint8* stream_ptr = static_cast<const uint8*>(shm->memory());
- if (payload_size > 0)
- validator_->ProcessStreamBuffer(stream_ptr, payload_size);
+ if (payload_size > 0) {
+ if (validator_) {
+ validator_->ProcessStreamBuffer(stream_ptr, payload_size);
+ } else {
+ HandleEncodedFrame(key_frame);
+ }
- EXPECT_EQ(key_frame, seen_keyframe_in_this_buffer_);
- seen_keyframe_in_this_buffer_ = false;
+ if (save_to_file_) {
+ if (IsVP8(test_stream_->requested_profile))
+ WriteIvfFrameHeader(num_encoded_frames_ - 1, payload_size);
- if (save_to_file_) {
- int size = base::checked_cast<int>(payload_size);
- EXPECT_TRUE(base::AppendToFile(
- base::FilePath::FromUTF8Unsafe(test_stream_->out_filename),
- static_cast<char*>(shm->memory()),
- size));
+ EXPECT_TRUE(base::AppendToFile(
+ base::FilePath::FromUTF8Unsafe(test_stream_->out_filename),
+ static_cast<char*>(shm->memory()),
+ base::checked_cast<int>(payload_size)));
+ }
}
+ EXPECT_EQ(key_frame, seen_keyframe_in_this_buffer_);
+ seen_keyframe_in_this_buffer_ = false;
+
FeedEncoderWithOutput(shm);
}
@@ -856,10 +1068,12 @@ void VEAClient::InputNoLongerNeededCallback(int32 input_id) {
std::set<int32>::iterator it = inputs_at_client_.find(input_id);
ASSERT_NE(it, inputs_at_client_.end());
inputs_at_client_.erase(it);
- FeedEncoderWithInputs();
+ if (!g_env->run_at_fps())
+ FeedEncoderWithOneInput();
}
-scoped_refptr<media::VideoFrame> VEAClient::PrepareInputFrame(off_t position) {
+scoped_refptr<media::VideoFrame> VEAClient::PrepareInputFrame(off_t position,
+ int32* input_id) {
CHECK_LE(position + test_stream_->aligned_buffer_size,
test_stream_->mapped_aligned_in_file.length());
@@ -890,44 +1104,50 @@ scoped_refptr<media::VideoFrame> VEAClient::PrepareInputFrame(off_t position) {
next_input_id_)));
CHECK(inputs_at_client_.insert(next_input_id_).second);
- ++next_input_id_;
+ *input_id = next_input_id_++;
return frame;
}
-void VEAClient::FeedEncoderWithInputs() {
- if (!has_encoder())
- return;
+void VEAClient::OnInputTimer() {
+ if (!has_encoder() || state_ != CS_ENCODING)
+ input_timer_.reset();
+ else if (inputs_at_client_.size() <
+ num_required_input_buffers_ + kNumExtraInputFrames)
+ FeedEncoderWithOneInput();
+ else
+ DVLOG(1) << "Dropping input frame";
+}
- if (state_ != CS_ENCODING)
+void VEAClient::FeedEncoderWithOneInput() {
+ if (!has_encoder() || state_ != CS_ENCODING)
return;
- while (inputs_at_client_.size() <
- num_required_input_buffers_ + kNumExtraInputFrames) {
- size_t bytes_left =
- test_stream_->mapped_aligned_in_file.length() - pos_in_input_stream_;
- if (bytes_left < test_stream_->aligned_buffer_size) {
- DCHECK_EQ(bytes_left, 0UL);
- // Rewind if at the end of stream and we are still encoding.
- // This is to flush the encoder with additional frames from the beginning
- // of the stream, or if the stream is shorter that the number of frames
- // we require for bitrate tests.
- pos_in_input_stream_ = 0;
- continue;
- }
-
- bool force_keyframe = false;
- if (keyframe_period_ && next_input_id_ % keyframe_period_ == 0) {
- keyframe_requested_at_ = next_input_id_;
- force_keyframe = true;
- }
+ size_t bytes_left =
+ test_stream_->mapped_aligned_in_file.length() - pos_in_input_stream_;
+ if (bytes_left < test_stream_->aligned_buffer_size) {
+ DCHECK_EQ(bytes_left, 0UL);
+ // Rewind if at the end of stream and we are still encoding.
+ // This is to flush the encoder with additional frames from the beginning
+ // of the stream, or if the stream is shorter that the number of frames
+ // we require for bitrate tests.
+ pos_in_input_stream_ = 0;
+ }
- scoped_refptr<media::VideoFrame> video_frame =
- PrepareInputFrame(pos_in_input_stream_);
- pos_in_input_stream_ += test_stream_->aligned_buffer_size;
+ int32 input_id;
+ scoped_refptr<media::VideoFrame> video_frame =
+ PrepareInputFrame(pos_in_input_stream_, &input_id);
+ pos_in_input_stream_ += test_stream_->aligned_buffer_size;
- encoder_->Encode(video_frame, force_keyframe);
+ bool force_keyframe = false;
+ if (keyframe_period_ && input_id % keyframe_period_ == 0) {
+ force_keyframe = true;
+ ++num_keyframes_requested_;
}
+
+ CHECK_EQ(input_id, static_cast<int32>(encode_start_time_.size()));
+ encode_start_time_.push_back(base::TimeTicks::Now());
+ encoder_->Encode(video_frame, force_keyframe);
}
void VEAClient::FeedEncoderWithOutput(base::SharedMemory* shm) {
@@ -952,17 +1172,18 @@ bool VEAClient::HandleEncodedFrame(bool keyframe) {
// return value from this method.
CHECK_LE(num_encoded_frames_, num_frames_to_encode_);
- ++num_encoded_frames_;
- ++num_frames_since_last_check_;
-
last_frame_ready_time_ = base::TimeTicks::Now();
- if (keyframe) {
- // Got keyframe, reset keyframe detection regardless of whether we
- // got a frame in time or not.
- keyframe_requested_at_ = kMaxFrameNum;
- seen_keyframe_in_this_buffer_ = true;
+
+ if (g_env->needs_encode_latency()) {
+ CHECK_LT(num_encoded_frames_, encode_start_time_.size());
+ base::TimeTicks start_time = encode_start_time_[num_encoded_frames_];
+ CHECK(!start_time.is_null());
+ encode_latencies_.push_back(last_frame_ready_time_ - start_time);
}
+ ++num_encoded_frames_;
+ ++num_frames_since_last_check_;
+
// Because the keyframe behavior requirements are loose, we give
// the encoder more freedom here. It could either deliver a keyframe
// immediately after we requested it, which could be for a frame number
@@ -973,7 +1194,17 @@ bool VEAClient::HandleEncodedFrame(bool keyframe) {
// earlier than we requested one (in time), and not later than
// kMaxKeyframeDelay frames after the frame, for which we requested
// it, comes back encoded.
- EXPECT_LE(num_encoded_frames_, keyframe_requested_at_ + kMaxKeyframeDelay);
+ if (keyframe) {
+ if (num_keyframes_requested_ > 0 &&
+ num_encoded_frames_ > next_keyframe_at_) {
+ --num_keyframes_requested_;
+ next_keyframe_at_ += keyframe_period_;
+ }
+ seen_keyframe_in_this_buffer_ = true;
+ }
+
+ if (num_keyframes_requested_ > 0)
+ EXPECT_LE(num_encoded_frames_, next_keyframe_at_ + kMaxKeyframeDelay);
if (num_encoded_frames_ == num_frames_to_encode_ / 2) {
VerifyStreamProperties();
@@ -981,9 +1212,14 @@ bool VEAClient::HandleEncodedFrame(bool keyframe) {
requested_subsequent_framerate_ != current_framerate_) {
SetStreamParameters(requested_subsequent_bitrate_,
requested_subsequent_framerate_);
+ if (g_env->run_at_fps() && input_timer_)
+ input_timer_->Start(
+ FROM_HERE, base::TimeDelta::FromSeconds(1) / current_framerate_,
+ base::Bind(&VEAClient::OnInputTimer, base::Unretained(this)));
}
} else if (num_encoded_frames_ == num_frames_to_encode_) {
- VerifyPerf();
+ LogPerf();
+ VerifyMinFPS();
VerifyStreamProperties();
SetState(CS_FINISHED);
return false;
@@ -992,11 +1228,26 @@ bool VEAClient::HandleEncodedFrame(bool keyframe) {
return true;
}
-void VEAClient::VerifyPerf() {
- double measured_fps = frames_per_second();
- LOG(INFO) << "Measured encoder FPS: " << measured_fps;
+void VEAClient::LogPerf() {
+ g_env->LogToFile("Measured encoder FPS",
+ base::StringPrintf("%.3f", frames_per_second()));
+
+ // Log encode latencies.
+ if (g_env->needs_encode_latency()) {
+ std::sort(encode_latencies_.begin(), encode_latencies_.end());
+ for (const auto& percentile : kLoggedLatencyPercentiles) {
+ base::TimeDelta latency = Percentile(encode_latencies_, percentile);
+ g_env->LogToFile(
+ base::StringPrintf("Encode latency for the %dth percentile",
+ percentile),
+ base::StringPrintf("%" PRId64 " us", latency.InMicroseconds()));
+ }
+ }
+}
+
+void VEAClient::VerifyMinFPS() {
if (test_perf_)
- EXPECT_GE(measured_fps, kMinPerfFPS);
+ EXPECT_GE(frames_per_second(), kMinPerfFPS);
}
void VEAClient::VerifyStreamProperties() {
@@ -1017,35 +1268,55 @@ void VEAClient::VerifyStreamProperties() {
current_requested_bitrate_,
kBitrateTolerance * current_requested_bitrate_);
}
-}
-// Setup test stream data and delete temporary aligned files at the beginning
-// and end of unittest. We only need to setup once for all test cases.
-class VideoEncodeAcceleratorTestEnvironment : public ::testing::Environment {
- public:
- VideoEncodeAcceleratorTestEnvironment(
- scoped_ptr<base::FilePath::StringType> data) {
- test_stream_data_ = data.Pass();
- }
-
- virtual void SetUp() {
- ParseAndReadTestStreamData(*test_stream_data_, &test_streams_);
- }
+ // All requested keyframes should've been provided. Allow the last requested
+ // frame to remain undelivered if we haven't reached the maximum frame number
+ // by which it should have arrived.
+ if (num_encoded_frames_ < next_keyframe_at_ + kMaxKeyframeDelay)
+ EXPECT_LE(num_keyframes_requested_, 1UL);
+ else
+ EXPECT_EQ(num_keyframes_requested_, 0UL);
+}
- virtual void TearDown() {
- for (size_t i = 0; i < test_streams_.size(); i++) {
- base::DeleteFile(test_streams_[i]->aligned_in_file, false);
- }
- }
+void VEAClient::WriteIvfFileHeader() {
+ IvfFileHeader header;
+
+ memset(&header, 0, sizeof(header));
+ header.signature[0] = 'D';
+ header.signature[1] = 'K';
+ header.signature[2] = 'I';
+ header.signature[3] = 'F';
+ header.version = 0;
+ header.header_size = base::ByteSwapToLE16(sizeof(header));
+ header.fourcc = base::ByteSwapToLE32(0x30385056); // VP80
+ header.width = base::ByteSwapToLE16(
+ base::checked_cast<uint16_t>(test_stream_->visible_size.width()));
+ header.height = base::ByteSwapToLE16(
+ base::checked_cast<uint16_t>(test_stream_->visible_size.height()));
+ header.framerate = base::ByteSwapToLE32(requested_framerate_);
+ header.timescale = base::ByteSwapToLE32(1);
+ header.num_frames = base::ByteSwapToLE32(num_frames_to_encode_);
+
+ EXPECT_TRUE(base::AppendToFile(
+ base::FilePath::FromUTF8Unsafe(test_stream_->out_filename),
+ reinterpret_cast<char*>(&header), sizeof(header)));
+}
- ScopedVector<TestStream> test_streams_;
+void VEAClient::WriteIvfFrameHeader(int frame_index, size_t frame_size) {
+ IvfFrameHeader header;
- private:
- scoped_ptr<base::FilePath::StringType> test_stream_data_;
-};
+ memset(&header, 0, sizeof(header));
+ header.frame_size = base::ByteSwapToLE32(frame_size);
+ header.timestamp = base::ByteSwapToLE64(frame_index);
+ EXPECT_TRUE(base::AppendToFile(
+ base::FilePath::FromUTF8Unsafe(test_stream_->out_filename),
+ reinterpret_cast<char*>(&header), sizeof(header)));
+}
// Test parameters:
-// - Number of concurrent encoders.
+// - Number of concurrent encoders. The value takes effect when there is only
+// one input stream; otherwise, one encoder per input stream will be
+// instantiated.
// - If true, save output to file (provided an output filename was supplied).
// - Force a keyframe every n frames.
// - Force bitrate; the actual required value is provided as a property
@@ -1055,22 +1326,25 @@ class VideoEncodeAcceleratorTestEnvironment : public ::testing::Environment {
// - If true, switch framerate mid-stream.
class VideoEncodeAcceleratorTest
: public ::testing::TestWithParam<
- Tuple7<int, bool, int, bool, bool, bool, bool> > {};
+ Tuple<int, bool, int, bool, bool, bool, bool>> {};
TEST_P(VideoEncodeAcceleratorTest, TestSimpleEncode) {
- const size_t num_concurrent_encoders = GetParam().a;
- const bool save_to_file = GetParam().b;
- const unsigned int keyframe_period = GetParam().c;
- const bool force_bitrate = GetParam().d;
- const bool test_perf = GetParam().e;
- const bool mid_stream_bitrate_switch = GetParam().f;
- const bool mid_stream_framerate_switch = GetParam().g;
+ size_t num_concurrent_encoders = get<0>(GetParam());
+ const bool save_to_file = get<1>(GetParam());
+ const unsigned int keyframe_period = get<2>(GetParam());
+ const bool force_bitrate = get<3>(GetParam());
+ const bool test_perf = get<4>(GetParam());
+ const bool mid_stream_bitrate_switch = get<5>(GetParam());
+ const bool mid_stream_framerate_switch = get<6>(GetParam());
ScopedVector<ClientStateNotification<ClientState> > notes;
ScopedVector<VEAClient> clients;
base::Thread encoder_thread("EncoderThread");
ASSERT_TRUE(encoder_thread.Start());
+ if (g_env->test_streams_.size() > 1)
+ num_concurrent_encoders = g_env->test_streams_.size();
+
// Create all encoders.
for (size_t i = 0; i < num_concurrent_encoders; i++) {
size_t test_stream_index = i % g_env->test_streams_.size();
@@ -1080,14 +1354,10 @@ TEST_P(VideoEncodeAcceleratorTest, TestSimpleEncode) {
!g_env->test_streams_[test_stream_index]->out_filename.empty());
notes.push_back(new ClientStateNotification<ClientState>());
- clients.push_back(new VEAClient(g_env->test_streams_[test_stream_index],
- notes.back(),
- encoder_save_to_file,
- keyframe_period,
- force_bitrate,
- test_perf,
- mid_stream_bitrate_switch,
- mid_stream_framerate_switch));
+ clients.push_back(new VEAClient(
+ g_env->test_streams_[test_stream_index], notes.back(),
+ encoder_save_to_file, keyframe_period, force_bitrate, test_perf,
+ mid_stream_bitrate_switch, mid_stream_framerate_switch));
encoder_thread.message_loop()->PostTask(
FROM_HERE,
@@ -1171,6 +1441,8 @@ int main(int argc, char** argv) {
base::CommandLine::Init(argc, argv);
base::ShadowingAtExitManager at_exit_manager;
+ base::MessageLoop main_loop;
+
scoped_ptr<base::FilePath::StringType> test_stream_data(
new base::FilePath::StringType(
media::GetTestDataFilePath(content::g_default_in_filename).value() +
@@ -1184,6 +1456,10 @@ int main(int argc, char** argv) {
const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
DCHECK(cmd_line);
+ bool run_at_fps = false;
+ bool needs_encode_latency = false;
+ base::FilePath log_path;
+
base::CommandLine::SwitchMap switches = cmd_line->GetSwitches();
for (base::CommandLine::SwitchMap::const_iterator it = switches.begin();
it != switches.end();
@@ -1192,16 +1468,53 @@ int main(int argc, char** argv) {
test_stream_data->assign(it->second.c_str());
continue;
}
+ // Output machine-readable logs with fixed formats to a file.
+ if (it->first == "output_log") {
+ log_path = base::FilePath(
+ base::FilePath::StringType(it->second.begin(), it->second.end()));
+ continue;
+ }
+ if (it->first == "num_frames_to_encode") {
+ std::string input(it->second.begin(), it->second.end());
+ CHECK(base::StringToInt(input, &content::g_num_frames_to_encode));
+ continue;
+ }
+ if (it->first == "measure_latency") {
+ needs_encode_latency = true;
+ continue;
+ }
+ if (it->first == "fake_encoder") {
+ content::g_fake_encoder = true;
+ continue;
+ }
+ if (it->first == "run_at_fps") {
+ run_at_fps = true;
+ continue;
+ }
if (it->first == "v" || it->first == "vmodule")
continue;
+ if (it->first == "ozone-platform" || it->first == "ozone-use-surfaceless")
+ continue;
LOG(FATAL) << "Unexpected switch: " << it->first << ":" << it->second;
}
+ if (needs_encode_latency && !run_at_fps) {
+ // Encode latency can only be measured with --run_at_fps. Otherwise, we get
+ // skewed results since it may queue too many frames at once with the same
+ // encode start time.
+ LOG(FATAL) << "--measure_latency requires --run_at_fps enabled to work.";
+ }
+
+#if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)
+ content::VaapiWrapper::PreSandboxInitialization();
+#endif
+
content::g_env =
reinterpret_cast<content::VideoEncodeAcceleratorTestEnvironment*>(
testing::AddGlobalTestEnvironment(
new content::VideoEncodeAcceleratorTestEnvironment(
- test_stream_data.Pass())));
+ test_stream_data.Pass(), log_path, run_at_fps,
+ needs_encode_latency)));
return RUN_ALL_TESTS();
}
diff --git a/chromium/content/common/gpu/media/vp8_decoder.cc b/chromium/content/common/gpu/media/vp8_decoder.cc
new file mode 100644
index 00000000000..eed6b59a143
--- /dev/null
+++ b/chromium/content/common/gpu/media/vp8_decoder.cc
@@ -0,0 +1,197 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/common/gpu/media/vp8_decoder.h"
+#include "media/base/limits.h"
+
+namespace content {
+
+VP8Decoder::VP8Accelerator::VP8Accelerator() {
+}
+
+VP8Decoder::VP8Accelerator::~VP8Accelerator() {
+}
+
+VP8Decoder::VP8Decoder(VP8Accelerator* accelerator)
+ : state_(kNeedStreamMetadata),
+ curr_frame_start_(nullptr),
+ frame_size_(0),
+ accelerator_(accelerator) {
+ DCHECK(accelerator_);
+}
+
+VP8Decoder::~VP8Decoder() {
+}
+
+bool VP8Decoder::Flush() {
+ DVLOG(2) << "Decoder flush";
+ Reset();
+ return true;
+}
+
+void VP8Decoder::SetStream(const uint8_t* ptr, size_t size) {
+ DCHECK(ptr);
+ DCHECK(size);
+
+ curr_frame_start_ = ptr;
+ frame_size_ = size;
+ DVLOG(4) << "New input stream at: " << (void*)ptr << " size: " << size;
+}
+
+void VP8Decoder::Reset() {
+ curr_pic_ = nullptr;
+ curr_frame_hdr_ = nullptr;
+ curr_frame_start_ = nullptr;
+ frame_size_ = 0;
+
+ last_frame_ = nullptr;
+ golden_frame_ = nullptr;
+ alt_frame_ = nullptr;
+
+ if (state_ == kDecoding)
+ state_ = kAfterReset;
+}
+
+VP8Decoder::DecodeResult VP8Decoder::Decode() {
+ if (!curr_frame_start_ || frame_size_ == 0)
+ return kRanOutOfStreamData;
+
+ if (!curr_frame_hdr_) {
+ curr_frame_hdr_.reset(new media::Vp8FrameHeader());
+ if (!parser_.ParseFrame(curr_frame_start_, frame_size_,
+ curr_frame_hdr_.get())) {
+ DVLOG(1) << "Error during decode";
+ state_ = kError;
+ return kDecodeError;
+ }
+ }
+
+ if (curr_frame_hdr_->IsKeyframe()) {
+ gfx::Size new_pic_size(curr_frame_hdr_->width, curr_frame_hdr_->height);
+ if (new_pic_size.IsEmpty())
+ return kDecodeError;
+
+ if (new_pic_size != pic_size_) {
+ DVLOG(2) << "New resolution: " << new_pic_size.ToString();
+ pic_size_ = new_pic_size;
+
+ DCHECK(!curr_pic_);
+ last_frame_ = nullptr;
+ golden_frame_ = nullptr;
+ alt_frame_ = nullptr;
+
+ return kAllocateNewSurfaces;
+ }
+
+ state_ = kDecoding;
+ } else {
+ if (state_ != kDecoding) {
+ // Need a resume point.
+ curr_frame_hdr_.reset();
+ return kRanOutOfStreamData;
+ }
+ }
+
+ curr_pic_ = accelerator_->CreateVP8Picture();
+ if (!curr_pic_)
+ return kRanOutOfSurfaces;
+
+ if (!DecodeAndOutputCurrentFrame())
+ return kDecodeError;
+
+ return kRanOutOfStreamData;
+}
+
+void VP8Decoder::RefreshReferenceFrames() {
+ if (curr_frame_hdr_->IsKeyframe()) {
+ last_frame_ = curr_pic_;
+ golden_frame_ = curr_pic_;
+ alt_frame_ = curr_pic_;
+ return;
+ }
+
+ // Save current golden since we overwrite it here,
+ // but may have to use it to update alt below.
+ scoped_refptr<VP8Picture> curr_golden = golden_frame_;
+
+ if (curr_frame_hdr_->refresh_golden_frame) {
+ golden_frame_ = curr_pic_;
+ } else {
+ switch (curr_frame_hdr_->copy_buffer_to_golden) {
+ case media::Vp8FrameHeader::COPY_LAST_TO_GOLDEN:
+ DCHECK(last_frame_);
+ golden_frame_ = last_frame_;
+ break;
+
+ case media::Vp8FrameHeader::COPY_ALT_TO_GOLDEN:
+ DCHECK(alt_frame_);
+ golden_frame_ = alt_frame_;
+ break;
+ }
+ }
+
+ if (curr_frame_hdr_->refresh_alternate_frame) {
+ alt_frame_ = curr_pic_;
+ } else {
+ switch (curr_frame_hdr_->copy_buffer_to_alternate) {
+ case media::Vp8FrameHeader::COPY_LAST_TO_ALT:
+ DCHECK(last_frame_);
+ alt_frame_ = last_frame_;
+ break;
+
+ case media::Vp8FrameHeader::COPY_GOLDEN_TO_ALT:
+ DCHECK(curr_golden);
+ alt_frame_ = curr_golden;
+ break;
+ }
+ }
+
+ if (curr_frame_hdr_->refresh_last)
+ last_frame_ = curr_pic_;
+}
+
+bool VP8Decoder::DecodeAndOutputCurrentFrame() {
+ DCHECK(!pic_size_.IsEmpty());
+ DCHECK(curr_pic_);
+ DCHECK(curr_frame_hdr_);
+
+ if (curr_frame_hdr_->IsKeyframe()) {
+ horizontal_scale_ = curr_frame_hdr_->horizontal_scale;
+ vertical_scale_ = curr_frame_hdr_->vertical_scale;
+ } else {
+ // Populate fields from decoder state instead.
+ curr_frame_hdr_->width = pic_size_.width();
+ curr_frame_hdr_->height = pic_size_.height();
+ curr_frame_hdr_->horizontal_scale = horizontal_scale_;
+ curr_frame_hdr_->vertical_scale = vertical_scale_;
+ }
+
+ if (!accelerator_->SubmitDecode(curr_pic_, curr_frame_hdr_.get(), last_frame_,
+ golden_frame_, alt_frame_))
+ return false;
+
+ if (curr_frame_hdr_->show_frame)
+ if (!accelerator_->OutputPicture(curr_pic_))
+ return false;
+
+ RefreshReferenceFrames();
+
+ curr_pic_ = nullptr;
+ curr_frame_hdr_ = nullptr;
+ curr_frame_start_ = nullptr;
+ frame_size_ = 0;
+ return true;
+}
+
+gfx::Size VP8Decoder::GetPicSize() const {
+ return pic_size_;
+}
+
+size_t VP8Decoder::GetRequiredNumOfPictures() const {
+ const size_t kVP8NumFramesActive = 4;
+ const size_t kPicsInPipeline = media::limits::kMaxVideoFrames + 2;
+ return kVP8NumFramesActive + kPicsInPipeline;
+}
+
+} // namespace content
diff --git a/chromium/content/common/gpu/media/vp8_decoder.h b/chromium/content/common/gpu/media/vp8_decoder.h
new file mode 100644
index 00000000000..e05ab51345c
--- /dev/null
+++ b/chromium/content/common/gpu/media/vp8_decoder.h
@@ -0,0 +1,107 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_COMMON_GPU_MEDIA_VP8_DECODER_H_
+#define CONTENT_COMMON_GPU_MEDIA_VP8_DECODER_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/common/gpu/media/accelerated_video_decoder.h"
+#include "content/common/gpu/media/vp8_picture.h"
+#include "media/filters/vp8_parser.h"
+
+namespace content {
+
+// Clients of this class are expected to pass raw VP8 stream and are expected
+// to provide an implementation of VP8Accelerator for offloading final steps
+// of the decoding process.
+//
+// This class must be created, called and destroyed on a single thread, and
+// does nothing internally on any other thread.
+class CONTENT_EXPORT VP8Decoder : public AcceleratedVideoDecoder {
+ public:
+ class CONTENT_EXPORT VP8Accelerator {
+ public:
+ VP8Accelerator();
+ virtual ~VP8Accelerator();
+
+ // Create a new VP8Picture that the decoder client can use for decoding
+ // and pass back to this accelerator for decoding or reference.
+ // When the picture is no longer needed by decoder, it will just drop
+ // its reference to it, and it may do so at any time.
+ // Note that this may return nullptr if accelerator is not able to provide
+ // any new pictures at given time. The decoder is expected to handle
+ // this situation as normal and return from Decode() with kRanOutOfSurfaces.
+ virtual scoped_refptr<VP8Picture> CreateVP8Picture() = 0;
+
+ // Submit decode for |pic|, taking as arguments |frame_hdr| with parsed
+ // VP8 frame header information for current frame, and using |last_frame|,
+ // |golden_frame| and |alt_frame| as references, as per VP8 specification.
+ // Note that this runs the decode in hardware.
+ // Return true if successful.
+ virtual bool SubmitDecode(const scoped_refptr<VP8Picture>& pic,
+ const media::Vp8FrameHeader* frame_hdr,
+ const scoped_refptr<VP8Picture>& last_frame,
+ const scoped_refptr<VP8Picture>& golden_frame,
+ const scoped_refptr<VP8Picture>& alt_frame) = 0;
+
+ // Schedule output (display) of |pic|. Note that returning from this
+ // method does not mean that |pic| has already been outputted (displayed),
+ // but guarantees that all pictures will be outputted in the same order
+ // as this method was called for them. Decoder may drop its reference
+ // to |pic| after calling this method.
+ // Return true if successful.
+ virtual bool OutputPicture(const scoped_refptr<VP8Picture>& pic) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(VP8Accelerator);
+ };
+
+ VP8Decoder(VP8Accelerator* accelerator);
+ ~VP8Decoder() override;
+
+ // content::AcceleratedVideoDecoder implementation.
+ bool Flush() override WARN_UNUSED_RESULT;
+ void Reset() override;
+ void SetStream(const uint8_t* ptr, size_t size) override;
+ DecodeResult Decode() override WARN_UNUSED_RESULT;
+ gfx::Size GetPicSize() const override;
+ size_t GetRequiredNumOfPictures() const override;
+
+ private:
+ bool DecodeAndOutputCurrentFrame();
+ void RefreshReferenceFrames();
+
+ enum State {
+ kNeedStreamMetadata, // After initialization, need a keyframe.
+ kDecoding, // Ready to decode from any point.
+ kAfterReset, // After Reset(), need a resume point.
+ kError, // Error in decode, can't continue.
+ };
+
+ State state_;
+
+ media::Vp8Parser parser_;
+
+ scoped_ptr<media::Vp8FrameHeader> curr_frame_hdr_;
+ scoped_refptr<VP8Picture> curr_pic_;
+ scoped_refptr<VP8Picture> last_frame_;
+ scoped_refptr<VP8Picture> golden_frame_;
+ scoped_refptr<VP8Picture> alt_frame_;
+
+ const uint8_t* curr_frame_start_;
+ size_t frame_size_;
+
+ gfx::Size pic_size_;
+ int horizontal_scale_;
+ int vertical_scale_;
+
+ VP8Accelerator* accelerator_;
+
+ DISALLOW_COPY_AND_ASSIGN(VP8Decoder);
+};
+
+} // namespace content
+
+#endif // CONTENT_COMMON_GPU_MEDIA_VP8_DECODER_H_
diff --git a/chromium/content/common/gpu/media/vp8_picture.cc b/chromium/content/common/gpu/media/vp8_picture.cc
new file mode 100644
index 00000000000..63ec8e93eaa
--- /dev/null
+++ b/chromium/content/common/gpu/media/vp8_picture.cc
@@ -0,0 +1,23 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/common/gpu/media/vp8_picture.h"
+
+namespace content {
+
+VP8Picture::VP8Picture() {
+}
+
+VP8Picture::~VP8Picture() {
+}
+
+V4L2VP8Picture* VP8Picture::AsV4L2VP8Picture() {
+ return nullptr;
+}
+
+VaapiVP8Picture* VP8Picture::AsVaapiVP8Picture() {
+ return nullptr;
+}
+
+} // namespace content
diff --git a/chromium/content/common/gpu/media/vp8_picture.h b/chromium/content/common/gpu/media/vp8_picture.h
new file mode 100644
index 00000000000..eb8307f62ff
--- /dev/null
+++ b/chromium/content/common/gpu/media/vp8_picture.h
@@ -0,0 +1,31 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_COMMON_GPU_MEDIA_VP8_PICTURE_H_
+#define CONTENT_COMMON_GPU_MEDIA_VP8_PICTURE_H_
+
+#include "base/memory/ref_counted.h"
+
+namespace content {
+
+class V4L2VP8Picture;
+class VaapiVP8Picture;
+
+class VP8Picture : public base::RefCounted<VP8Picture> {
+ public:
+ VP8Picture();
+
+ virtual V4L2VP8Picture* AsV4L2VP8Picture();
+ virtual VaapiVP8Picture* AsVaapiVP8Picture();
+
+ protected:
+ friend class base::RefCounted<VP8Picture>;
+ virtual ~VP8Picture();
+
+ DISALLOW_COPY_AND_ASSIGN(VP8Picture);
+};
+
+} // namespace content
+
+#endif // CONTENT_COMMON_GPU_MEDIA_VP8_PICTURE_H_
diff --git a/chromium/content/common/gpu/media/vt.sig b/chromium/content/common/gpu/media/vt.sig
index 236a52a4801..39c408e32c9 100644
--- a/chromium/content/common/gpu/media/vt.sig
+++ b/chromium/content/common/gpu/media/vt.sig
@@ -13,4 +13,5 @@ CMVideoDimensions CMVideoFormatDescriptionGetDimensions(CMVideoFormatDescription
Boolean VTDecompressionSessionCanAcceptFormatDescription(VTDecompressionSessionRef session, CMFormatDescriptionRef newFormatDesc);
OSStatus VTDecompressionSessionCreate(CFAllocatorRef allocator, CMVideoFormatDescriptionRef videoFormatDescription, CFDictionaryRef videoDecoderSpecification, CFDictionaryRef destinationImageBufferAttributes, const VTDecompressionOutputCallbackRecord *outputCallback, VTDecompressionSessionRef *decompressionSessionOut);
OSStatus VTDecompressionSessionDecodeFrame(VTDecompressionSessionRef session, CMSampleBufferRef sampleBuffer, VTDecodeFrameFlags decodeFlags, void *sourceFrameRefCon, VTDecodeInfoFlags *infoFlagsOut);
-OSStatus VTDecompressionSessionFinishDelayedFrames(VTDecompressionSessionRef session);
+OSStatus VTDecompressionSessionWaitForAsynchronousFrames(VTDecompressionSessionRef session);
+OSStatus VTSessionCopyProperty(VTSessionRef session, CFStringRef propertyKey, CFAllocatorRef allocator, void *propertyValueOut);
diff --git a/chromium/content/common/gpu/media/vt_stubs_header.fragment b/chromium/content/common/gpu/media/vt_stubs_header.fragment
index f8f7ded55a6..eabcd26b580 100644
--- a/chromium/content/common/gpu/media/vt_stubs_header.fragment
+++ b/chromium/content/common/gpu/media/vt_stubs_header.fragment
@@ -66,6 +66,7 @@ enum {
};
typedef UInt32 VTDecodeInfoFlags;
typedef struct OpaqueVTDecompressionSession* VTDecompressionSessionRef;
+typedef CFTypeRef VTSessionRef;
typedef void (*VTDecompressionOutputCallback)(
void *decompressionOutputRefCon,
diff --git a/chromium/content/common/gpu/media/vt_video_decode_accelerator.cc b/chromium/content/common/gpu/media/vt_video_decode_accelerator.cc
index b09a5e3e0c3..4435cd70280 100644
--- a/chromium/content/common/gpu/media/vt_video_decode_accelerator.cc
+++ b/chromium/content/common/gpu/media/vt_video_decode_accelerator.cc
@@ -2,18 +2,22 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <algorithm>
+
#include <CoreVideo/CoreVideo.h>
#include <OpenGL/CGLIOSurface.h>
#include <OpenGL/gl.h>
#include "base/bind.h"
-#include "base/callback_helpers.h"
#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/mac/mac_logging.h"
+#include "base/metrics/histogram_macros.h"
#include "base/sys_byteorder.h"
#include "base/thread_task_runner_handle.h"
#include "content/common/gpu/media/vt_video_decode_accelerator.h"
#include "content/public/common/content_switches.h"
-#include "media/filters/h264_parser.h"
+#include "media/base/limits.h"
#include "ui/gl/scoped_binders.h"
using content_common_gpu_media::kModuleVt;
@@ -21,21 +25,211 @@ using content_common_gpu_media::InitializeStubs;
using content_common_gpu_media::IsVtInitialized;
using content_common_gpu_media::StubPathMap;
-#define NOTIFY_STATUS(name, status) \
- do { \
- LOG(ERROR) << name << " failed with status " << status; \
- NotifyError(PLATFORM_FAILURE); \
+#define NOTIFY_STATUS(name, status, session_failure) \
+ do { \
+ OSSTATUS_DLOG(ERROR, status) << name; \
+ NotifyError(PLATFORM_FAILURE, session_failure); \
} while (0)
namespace content {
-// Size of NALU length headers in AVCC/MPEG-4 format (can be 1, 2, or 4).
+// Only H.264 with 4:2:0 chroma sampling is supported.
+static const media::VideoCodecProfile kSupportedProfiles[] = {
+ media::H264PROFILE_BASELINE,
+ media::H264PROFILE_MAIN,
+ media::H264PROFILE_EXTENDED,
+ media::H264PROFILE_HIGH,
+ media::H264PROFILE_HIGH10PROFILE,
+ media::H264PROFILE_SCALABLEBASELINE,
+ media::H264PROFILE_SCALABLEHIGH,
+ media::H264PROFILE_STEREOHIGH,
+ media::H264PROFILE_MULTIVIEWHIGH,
+};
+
+// Size to use for NALU length headers in AVC format (can be 1, 2, or 4).
static const int kNALUHeaderLength = 4;
-// We only request 5 picture buffers from the client which are used to hold the
-// decoded samples. These buffers are then reused when the client tells us that
-// it is done with the buffer.
-static const int kNumPictureBuffers = 5;
+// We request 5 picture buffers from the client, each of which has a texture ID
+// that we can bind decoded frames to. We need enough to satisfy preroll, and
+// enough to avoid unnecessary stalling, but no more than that. The resource
+// requirements are low, as we don't need the textures to be backed by storage.
+static const int kNumPictureBuffers = media::limits::kMaxVideoFrames + 1;
+
+// Maximum number of frames to queue for reordering before we stop asking for
+// more. (NotifyEndOfBitstreamBuffer() is called when frames are moved into the
+// reorder queue.)
+static const int kMaxReorderQueueSize = 16;
+
+// Build an |image_config| dictionary for VideoToolbox initialization.
+static base::ScopedCFTypeRef<CFMutableDictionaryRef>
+BuildImageConfig(CMVideoDimensions coded_dimensions) {
+ base::ScopedCFTypeRef<CFMutableDictionaryRef> image_config;
+
+ // TODO(sandersd): Does it save some work or memory to use 4:2:0?
+ int32_t pixel_format = kCVPixelFormatType_422YpCbCr8;
+#define CFINT(i) CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i)
+ base::ScopedCFTypeRef<CFNumberRef> cf_pixel_format(CFINT(pixel_format));
+ base::ScopedCFTypeRef<CFNumberRef> cf_width(CFINT(coded_dimensions.width));
+ base::ScopedCFTypeRef<CFNumberRef> cf_height(CFINT(coded_dimensions.height));
+#undef CFINT
+ if (!cf_pixel_format.get() || !cf_width.get() || !cf_height.get())
+ return image_config;
+
+ image_config.reset(
+ CFDictionaryCreateMutable(
+ kCFAllocatorDefault,
+ 4, // capacity
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks));
+ if (!image_config.get())
+ return image_config;
+
+ CFDictionarySetValue(image_config, kCVPixelBufferPixelFormatTypeKey,
+ cf_pixel_format);
+ CFDictionarySetValue(image_config, kCVPixelBufferWidthKey, cf_width);
+ CFDictionarySetValue(image_config, kCVPixelBufferHeightKey, cf_height);
+ CFDictionarySetValue(image_config, kCVPixelBufferOpenGLCompatibilityKey,
+ kCFBooleanTrue);
+
+ return image_config;
+}
+
+// Create a VTDecompressionSession using the provided |pps| and |sps|. If
+// |require_hardware| is true, the session must uses real hardware decoding
+// (as opposed to software decoding inside of VideoToolbox) to be considered
+// successful.
+//
+// TODO(sandersd): Merge with ConfigureDecoder(), as the code is very similar.
+static bool CreateVideoToolboxSession(const uint8_t* sps, size_t sps_size,
+ const uint8_t* pps, size_t pps_size,
+ bool require_hardware) {
+ const uint8_t* data_ptrs[] = {sps, pps};
+ const size_t data_sizes[] = {sps_size, pps_size};
+
+ base::ScopedCFTypeRef<CMFormatDescriptionRef> format;
+ OSStatus status = CMVideoFormatDescriptionCreateFromH264ParameterSets(
+ kCFAllocatorDefault,
+ 2, // parameter_set_count
+ data_ptrs, // &parameter_set_pointers
+ data_sizes, // &parameter_set_sizes
+ kNALUHeaderLength, // nal_unit_header_length
+ format.InitializeInto());
+ if (status) {
+ OSSTATUS_DLOG(WARNING, status)
+ << "Failed to create CMVideoFormatDescription.";
+ return false;
+ }
+
+ base::ScopedCFTypeRef<CFMutableDictionaryRef> decoder_config(
+ CFDictionaryCreateMutable(
+ kCFAllocatorDefault,
+ 1, // capacity
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks));
+ if (!decoder_config.get())
+ return false;
+
+ if (require_hardware) {
+ CFDictionarySetValue(
+ decoder_config,
+ // kVTVideoDecoderSpecification_RequireHardwareAcceleratedVideoDecoder
+ CFSTR("RequireHardwareAcceleratedVideoDecoder"),
+ kCFBooleanTrue);
+ }
+
+ base::ScopedCFTypeRef<CFMutableDictionaryRef> image_config(
+ BuildImageConfig(CMVideoFormatDescriptionGetDimensions(format)));
+ if (!image_config.get())
+ return false;
+
+ VTDecompressionOutputCallbackRecord callback = {0};
+
+ base::ScopedCFTypeRef<VTDecompressionSessionRef> session;
+ status = VTDecompressionSessionCreate(
+ kCFAllocatorDefault,
+ format, // video_format_description
+ decoder_config, // video_decoder_specification
+ image_config, // destination_image_buffer_attributes
+ &callback, // output_callback
+ session.InitializeInto());
+ if (status) {
+ OSSTATUS_DLOG(WARNING, status) << "Failed to create VTDecompressionSession";
+ return false;
+ }
+
+ return true;
+}
+
+// The purpose of this function is to preload the generic and hardware-specific
+// libraries required by VideoToolbox before the GPU sandbox is enabled.
+// VideoToolbox normally loads the hardware-specific libraries lazily, so we
+// must actually create a decompression session. If creating a decompression
+// session fails, hardware decoding will be disabled (Initialize() will always
+// return false).
+static bool InitializeVideoToolboxInternal() {
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableAcceleratedVideoDecode)) {
+ return false;
+ }
+
+ if (!IsVtInitialized()) {
+ // CoreVideo is also required, but the loader stops after the first path is
+ // loaded. Instead we rely on the transitive dependency from VideoToolbox to
+ // CoreVideo.
+ // TODO(sandersd): Fallback to PrivateFrameworks to support OS X < 10.8.
+ StubPathMap paths;
+ paths[kModuleVt].push_back(FILE_PATH_LITERAL(
+ "/System/Library/Frameworks/VideoToolbox.framework/VideoToolbox"));
+ if (!InitializeStubs(paths)) {
+ LOG(WARNING) << "Failed to initialize VideoToolbox framework. "
+ << "Hardware accelerated video decoding will be disabled.";
+ return false;
+ }
+ }
+
+ // Create a hardware decoding session.
+ // SPS and PPS data are taken from a 480p sample (buck2.mp4).
+ const uint8_t sps_normal[] = {0x67, 0x64, 0x00, 0x1e, 0xac, 0xd9, 0x80, 0xd4,
+ 0x3d, 0xa1, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00,
+ 0x00, 0x03, 0x00, 0x30, 0x8f, 0x16, 0x2d, 0x9a};
+ const uint8_t pps_normal[] = {0x68, 0xe9, 0x7b, 0xcb};
+ if (!CreateVideoToolboxSession(sps_normal, arraysize(sps_normal), pps_normal,
+ arraysize(pps_normal), true)) {
+ LOG(WARNING) << "Failed to create hardware VideoToolbox session. "
+ << "Hardware accelerated video decoding will be disabled.";
+ return false;
+ }
+
+ // Create a software decoding session.
+ // SPS and PPS data are taken from a 18p sample (small2.mp4).
+ const uint8_t sps_small[] = {0x67, 0x64, 0x00, 0x0a, 0xac, 0xd9, 0x89, 0x7e,
+ 0x22, 0x10, 0x00, 0x00, 0x3e, 0x90, 0x00, 0x0e,
+ 0xa6, 0x08, 0xf1, 0x22, 0x59, 0xa0};
+ const uint8_t pps_small[] = {0x68, 0xe9, 0x79, 0x72, 0xc0};
+ if (!CreateVideoToolboxSession(sps_small, arraysize(sps_small), pps_small,
+ arraysize(pps_small), false)) {
+ LOG(WARNING) << "Failed to create software VideoToolbox session. "
+ << "Hardware accelerated video decoding will be disabled.";
+ return false;
+ }
+
+ return true;
+}
+
+bool InitializeVideoToolbox() {
+ // InitializeVideoToolbox() is called only from the GPU process main thread;
+ // once for sandbox warmup, and then once each time a VTVideoDecodeAccelerator
+ // is initialized.
+ static bool attempted = false;
+ static bool succeeded = false;
+
+ if (!attempted) {
+ attempted = true;
+ succeeded = InitializeVideoToolboxInternal();
+ }
+
+ return succeeded;
+}
// Route decoded frame callbacks back into the VTVideoDecodeAccelerator.
static void OutputThunk(
@@ -48,28 +242,32 @@ static void OutputThunk(
CMTime presentation_duration) {
VTVideoDecodeAccelerator* vda =
reinterpret_cast<VTVideoDecodeAccelerator*>(decompression_output_refcon);
- int32_t bitstream_id = reinterpret_cast<intptr_t>(source_frame_refcon);
- vda->Output(bitstream_id, status, image_buffer);
+ vda->Output(source_frame_refcon, status, image_buffer);
+}
+
+VTVideoDecodeAccelerator::Task::Task(TaskType type) : type(type) {
}
-VTVideoDecodeAccelerator::DecodedFrame::DecodedFrame(
- int32_t bitstream_id,
- CVImageBufferRef image_buffer)
- : bitstream_id(bitstream_id),
- image_buffer(image_buffer) {
+VTVideoDecodeAccelerator::Task::~Task() {
}
-VTVideoDecodeAccelerator::DecodedFrame::~DecodedFrame() {
+VTVideoDecodeAccelerator::Frame::Frame(int32_t bitstream_id)
+ : bitstream_id(bitstream_id), pic_order_cnt(0), reorder_window(0) {
}
-VTVideoDecodeAccelerator::PendingAction::PendingAction(
- Action action,
- int32_t bitstream_id)
- : action(action),
- bitstream_id(bitstream_id) {
+VTVideoDecodeAccelerator::Frame::~Frame() {
}
-VTVideoDecodeAccelerator::PendingAction::~PendingAction() {
+bool VTVideoDecodeAccelerator::FrameOrder::operator()(
+ const linked_ptr<Frame>& lhs,
+ const linked_ptr<Frame>& rhs) const {
+ if (lhs->pic_order_cnt != rhs->pic_order_cnt)
+ return lhs->pic_order_cnt > rhs->pic_order_cnt;
+ // If |pic_order_cnt| is the same, fall back on using the bitstream order.
+ // TODO(sandersd): Assign a sequence number in Decode() and use that instead.
+ // TODO(sandersd): Using the sequence number, ensure that frames older than
+ // |kMaxReorderQueueSize| are ordered first, regardless of |pic_order_cnt|.
+ return lhs->bitstream_id > rhs->bitstream_id;
}
VTVideoDecodeAccelerator::VTVideoDecodeAccelerator(
@@ -77,16 +275,19 @@ VTVideoDecodeAccelerator::VTVideoDecodeAccelerator(
const base::Callback<bool(void)>& make_context_current)
: cgl_context_(cgl_context),
make_context_current_(make_context_current),
- client_(NULL),
- has_error_(false),
- format_(NULL),
- session_(NULL),
+ client_(nullptr),
+ state_(STATE_DECODING),
+ format_(nullptr),
+ session_(nullptr),
+ last_sps_id_(-1),
+ last_pps_id_(-1),
gpu_task_runner_(base::ThreadTaskRunnerHandle::Get()),
- weak_this_factory_(this),
- decoder_thread_("VTDecoderThread") {
+ decoder_thread_("VTDecoderThread"),
+ weak_this_factory_(this) {
DCHECK(!make_context_current_.is_null());
callback_.decompressionOutputCallback = OutputThunk;
callback_.decompressionOutputRefCon = this;
+ weak_this_ = weak_this_factory_.GetWeakPtr();
}
VTVideoDecodeAccelerator::~VTVideoDecodeAccelerator() {
@@ -95,41 +296,64 @@ VTVideoDecodeAccelerator::~VTVideoDecodeAccelerator() {
bool VTVideoDecodeAccelerator::Initialize(
media::VideoCodecProfile profile,
Client* client) {
- DCHECK(CalledOnValidThread());
+ DCHECK(gpu_thread_checker_.CalledOnValidThread());
client_ = client;
- // Only H.264 is supported.
- if (profile < media::H264PROFILE_MIN || profile > media::H264PROFILE_MAX)
+ if (!InitializeVideoToolbox())
return false;
- // Require --no-sandbox until VideoToolbox library loading is part of sandbox
- // startup (and this VDA is ready for regular users).
- if (!base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoSandbox))
- return false;
-
- if (!IsVtInitialized()) {
- // CoreVideo is also required, but the loader stops after the first
- // path is loaded. Instead we rely on the transitive dependency from
- // VideoToolbox to CoreVideo.
- // TODO(sandersd): Fallback to PrivateFrameworks for VideoToolbox.
- StubPathMap paths;
- paths[kModuleVt].push_back(FILE_PATH_LITERAL(
- "/System/Library/Frameworks/VideoToolbox.framework/VideoToolbox"));
- if (!InitializeStubs(paths))
- return false;
+ bool profile_supported = false;
+ for (const auto& supported_profile : kSupportedProfiles) {
+ if (profile == supported_profile) {
+ profile_supported = true;
+ break;
+ }
}
+ if (!profile_supported)
+ return false;
// Spawn a thread to handle parsing and calling VideoToolbox.
if (!decoder_thread_.Start())
return false;
+ // Count the session as successfully initialized.
+ UMA_HISTOGRAM_ENUMERATION("Media.VTVDA.SessionFailureReason",
+ SFT_SUCCESSFULLY_INITIALIZED,
+ SFT_MAX + 1);
+ return true;
+}
+
+bool VTVideoDecodeAccelerator::FinishDelayedFrames() {
+ DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
+ if (session_) {
+ OSStatus status = VTDecompressionSessionWaitForAsynchronousFrames(session_);
+ if (status) {
+ NOTIFY_STATUS("VTDecompressionSessionWaitForAsynchronousFrames()",
+ status, SFT_PLATFORM_ERROR);
+ return false;
+ }
+ }
return true;
}
-bool VTVideoDecodeAccelerator::ConfigureDecoder(
- const std::vector<const uint8_t*>& nalu_data_ptrs,
- const std::vector<size_t>& nalu_data_sizes) {
- DCHECK(decoder_thread_.message_loop_proxy()->BelongsToCurrentThread());
+bool VTVideoDecodeAccelerator::ConfigureDecoder() {
+ DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
+ DCHECK(!last_sps_.empty());
+ DCHECK(!last_pps_.empty());
+
+ // Build the configuration records.
+ std::vector<const uint8_t*> nalu_data_ptrs;
+ std::vector<size_t> nalu_data_sizes;
+ nalu_data_ptrs.reserve(3);
+ nalu_data_sizes.reserve(3);
+ nalu_data_ptrs.push_back(&last_sps_.front());
+ nalu_data_sizes.push_back(last_sps_.size());
+ if (!last_spsext_.empty()) {
+ nalu_data_ptrs.push_back(&last_spsext_.front());
+ nalu_data_sizes.push_back(last_spsext_.size());
+ }
+ nalu_data_ptrs.push_back(&last_pps_.front());
+ nalu_data_sizes.push_back(last_pps_.size());
// Construct a new format description from the parameter sets.
// TODO(sandersd): Replace this with custom code to support OS X < 10.9.
@@ -143,14 +367,19 @@ bool VTVideoDecodeAccelerator::ConfigureDecoder(
format_.InitializeInto());
if (status) {
NOTIFY_STATUS("CMVideoFormatDescriptionCreateFromH264ParameterSets()",
- status);
+ status, SFT_PLATFORM_ERROR);
return false;
}
- // If the session is compatible, there's nothing to do.
+ // Store the new configuration data.
+ CMVideoDimensions coded_dimensions =
+ CMVideoFormatDescriptionGetDimensions(format_);
+ coded_size_.SetSize(coded_dimensions.width, coded_dimensions.height);
+
+ // If the session is compatible, there's nothing else to do.
if (session_ &&
VTDecompressionSessionCanAcceptFormatDescription(session_, format_)) {
- return true;
+ return true;
}
// Prepare VideoToolbox configuration dictionaries.
@@ -160,6 +389,11 @@ bool VTVideoDecodeAccelerator::ConfigureDecoder(
1, // capacity
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks));
+ if (!decoder_config.get()) {
+ DLOG(ERROR) << "Failed to create CFMutableDictionary.";
+ NotifyError(PLATFORM_FAILURE, SFT_PLATFORM_ERROR);
+ return false;
+ }
CFDictionarySetValue(
decoder_config,
@@ -168,29 +402,18 @@ bool VTVideoDecodeAccelerator::ConfigureDecoder(
kCFBooleanTrue);
base::ScopedCFTypeRef<CFMutableDictionaryRef> image_config(
- CFDictionaryCreateMutable(
- kCFAllocatorDefault,
- 4, // capacity
- &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks));
+ BuildImageConfig(coded_dimensions));
+ if (!image_config.get()) {
+ DLOG(ERROR) << "Failed to create decoder image configuration.";
+ NotifyError(PLATFORM_FAILURE, SFT_PLATFORM_ERROR);
+ return false;
+ }
- CMVideoDimensions coded_dimensions =
- CMVideoFormatDescriptionGetDimensions(format_);
-#define CFINT(i) CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i)
- // TODO(sandersd): RGBA option for 4:4:4 video.
- int32_t pixel_format = kCVPixelFormatType_422YpCbCr8;
- base::ScopedCFTypeRef<CFNumberRef> cf_pixel_format(CFINT(pixel_format));
- base::ScopedCFTypeRef<CFNumberRef> cf_width(CFINT(coded_dimensions.width));
- base::ScopedCFTypeRef<CFNumberRef> cf_height(CFINT(coded_dimensions.height));
-#undef CFINT
- CFDictionarySetValue(
- image_config, kCVPixelBufferPixelFormatTypeKey, cf_pixel_format);
- CFDictionarySetValue(image_config, kCVPixelBufferWidthKey, cf_width);
- CFDictionarySetValue(image_config, kCVPixelBufferHeightKey, cf_height);
- CFDictionarySetValue(
- image_config, kCVPixelBufferOpenGLCompatibilityKey, kCFBooleanTrue);
+ // Ensure that the old decoder emits all frames before the new decoder can
+ // emit any.
+ if (!FinishDelayedFrames())
+ return false;
- // TODO(sandersd): Does the old session need to be flushed first?
session_.reset();
status = VTDecompressionSessionCreate(
kCFAllocatorDefault,
@@ -200,57 +423,50 @@ bool VTVideoDecodeAccelerator::ConfigureDecoder(
&callback_, // output_callback
session_.InitializeInto());
if (status) {
- NOTIFY_STATUS("VTDecompressionSessionCreate()", status);
+ NOTIFY_STATUS("VTDecompressionSessionCreate()", status,
+ SFT_UNSUPPORTED_STREAM_PARAMETERS);
return false;
}
- return true;
-}
-
-void VTVideoDecodeAccelerator::Decode(const media::BitstreamBuffer& bitstream) {
- DCHECK(CalledOnValidThread());
- // Not actually a requirement of the VDA API, but we're lazy and use negative
- // values as flags internally. Revisit that if this actually happens.
- if (bitstream.id() < 0) {
- LOG(ERROR) << "Negative bitstream ID";
- NotifyError(INVALID_ARGUMENT);
- client_->NotifyEndOfBitstreamBuffer(bitstream.id());
- return;
+ // Report whether hardware decode is being used.
+ bool using_hardware = false;
+ base::ScopedCFTypeRef<CFBooleanRef> cf_using_hardware;
+ if (VTSessionCopyProperty(
+ session_,
+ // kVTDecompressionPropertyKey_UsingHardwareAcceleratedVideoDecoder
+ CFSTR("UsingHardwareAcceleratedVideoDecoder"),
+ kCFAllocatorDefault,
+ cf_using_hardware.InitializeInto()) == 0) {
+ using_hardware = CFBooleanGetValue(cf_using_hardware);
}
- pending_bitstream_ids_.push(bitstream.id());
- decoder_thread_.message_loop_proxy()->PostTask(FROM_HERE, base::Bind(
- &VTVideoDecodeAccelerator::DecodeTask, base::Unretained(this),
- bitstream));
+ UMA_HISTOGRAM_BOOLEAN("Media.VTVDA.HardwareAccelerated", using_hardware);
+
+ return true;
}
void VTVideoDecodeAccelerator::DecodeTask(
- const media::BitstreamBuffer& bitstream) {
- DCHECK(decoder_thread_.message_loop_proxy()->BelongsToCurrentThread());
-
- // Once we have a bitstream buffer, we must either decode it or drop it.
- // This construct ensures that the buffer is always dropped unless we call
- // drop_bitstream.Release().
- base::ScopedClosureRunner drop_bitstream(base::Bind(
- &VTVideoDecodeAccelerator::DropBitstream, base::Unretained(this),
- bitstream.id()));
+ const media::BitstreamBuffer& bitstream,
+ Frame* frame) {
+ DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
// Map the bitstream buffer.
base::SharedMemory memory(bitstream.handle(), true);
size_t size = bitstream.size();
if (!memory.Map(size)) {
- LOG(ERROR) << "Failed to map bitstream buffer";
- NotifyError(PLATFORM_FAILURE);
+ DLOG(ERROR) << "Failed to map bitstream buffer";
+ NotifyError(PLATFORM_FAILURE, SFT_PLATFORM_ERROR);
return;
}
const uint8_t* buf = static_cast<uint8_t*>(memory.memory());
// NALUs are stored with Annex B format in the bitstream buffer (start codes),
- // but VideoToolbox expects AVCC/MPEG-4 format (length headers), so we must
- // rewrite the data.
+ // but VideoToolbox expects AVC format (length headers), so we must rewrite
+ // the data.
//
- // 1. Locate relevant NALUs and compute the size of the translated data.
- // Also record any parameter sets for VideoToolbox initialization.
+ // Locate relevant NALUs and compute the size of the rewritten data. Also
+ // record any parameter sets for VideoToolbox initialization.
bool config_changed = false;
+ bool has_slice = false;
size_t data_size = 0;
std::vector<media::H264NALU> nalus;
parser_.SetStream(buf, size);
@@ -259,27 +475,112 @@ void VTVideoDecodeAccelerator::DecodeTask(
media::H264Parser::Result result = parser_.AdvanceToNextNALU(&nalu);
if (result == media::H264Parser::kEOStream)
break;
+ if (result == media::H264Parser::kUnsupportedStream) {
+ DLOG(ERROR) << "Unsupported H.264 stream";
+ NotifyError(PLATFORM_FAILURE, SFT_UNSUPPORTED_STREAM);
+ return;
+ }
if (result != media::H264Parser::kOk) {
- LOG(ERROR) << "Failed to find H.264 NALU";
- NotifyError(PLATFORM_FAILURE);
+ DLOG(ERROR) << "Failed to parse H.264 stream";
+ NotifyError(UNREADABLE_INPUT, SFT_INVALID_STREAM);
return;
}
- // TODO(sandersd): Strict ordering rules.
switch (nalu.nal_unit_type) {
case media::H264NALU::kSPS:
last_sps_.assign(nalu.data, nalu.data + nalu.size);
last_spsext_.clear();
config_changed = true;
+ result = parser_.ParseSPS(&last_sps_id_);
+ if (result == media::H264Parser::kUnsupportedStream) {
+ DLOG(ERROR) << "Unsupported SPS";
+ NotifyError(PLATFORM_FAILURE, SFT_UNSUPPORTED_STREAM);
+ return;
+ }
+ if (result != media::H264Parser::kOk) {
+ DLOG(ERROR) << "Could not parse SPS";
+ NotifyError(UNREADABLE_INPUT, SFT_INVALID_STREAM);
+ return;
+ }
break;
+
case media::H264NALU::kSPSExt:
// TODO(sandersd): Check that the previous NALU was an SPS.
last_spsext_.assign(nalu.data, nalu.data + nalu.size);
config_changed = true;
break;
+
case media::H264NALU::kPPS:
last_pps_.assign(nalu.data, nalu.data + nalu.size);
config_changed = true;
+ result = parser_.ParsePPS(&last_pps_id_);
+ if (result == media::H264Parser::kUnsupportedStream) {
+ DLOG(ERROR) << "Unsupported PPS";
+ NotifyError(PLATFORM_FAILURE, SFT_UNSUPPORTED_STREAM);
+ return;
+ }
+ if (result != media::H264Parser::kOk) {
+ DLOG(ERROR) << "Could not parse PPS";
+ NotifyError(UNREADABLE_INPUT, SFT_INVALID_STREAM);
+ return;
+ }
break;
+
+ case media::H264NALU::kSliceDataA:
+ case media::H264NALU::kSliceDataB:
+ case media::H264NALU::kSliceDataC:
+ case media::H264NALU::kNonIDRSlice:
+ // TODO(sandersd): Check that there has been an IDR slice since the
+ // last reset.
+ case media::H264NALU::kIDRSlice:
+ // Compute the |pic_order_cnt| for the picture from the first slice.
+ // TODO(sandersd): Make sure that any further slices are part of the
+ // same picture or a redundant coded picture.
+ if (!has_slice) {
+ media::H264SliceHeader slice_hdr;
+ result = parser_.ParseSliceHeader(nalu, &slice_hdr);
+ if (result == media::H264Parser::kUnsupportedStream) {
+ DLOG(ERROR) << "Unsupported slice header";
+ NotifyError(PLATFORM_FAILURE, SFT_UNSUPPORTED_STREAM);
+ return;
+ }
+ if (result != media::H264Parser::kOk) {
+ DLOG(ERROR) << "Could not parse slice header";
+ NotifyError(UNREADABLE_INPUT, SFT_INVALID_STREAM);
+ return;
+ }
+
+ // TODO(sandersd): Maintain a cache of configurations and reconfigure
+ // only when a slice references a new config.
+ DCHECK_EQ(slice_hdr.pic_parameter_set_id, last_pps_id_);
+ const media::H264PPS* pps =
+ parser_.GetPPS(slice_hdr.pic_parameter_set_id);
+ if (!pps) {
+ DLOG(ERROR) << "Mising PPS referenced by slice";
+ NotifyError(UNREADABLE_INPUT, SFT_INVALID_STREAM);
+ return;
+ }
+
+ DCHECK_EQ(pps->seq_parameter_set_id, last_sps_id_);
+ const media::H264SPS* sps = parser_.GetSPS(pps->seq_parameter_set_id);
+ if (!sps) {
+ DLOG(ERROR) << "Mising SPS referenced by PPS";
+ NotifyError(UNREADABLE_INPUT, SFT_INVALID_STREAM);
+ return;
+ }
+
+ if (!poc_.ComputePicOrderCnt(sps, slice_hdr, &frame->pic_order_cnt)) {
+ DLOG(ERROR) << "Unable to compute POC";
+ NotifyError(UNREADABLE_INPUT, SFT_INVALID_STREAM);
+ return;
+ }
+
+ if (sps->vui_parameters_present_flag &&
+ sps->bitstream_restriction_flag) {
+ frame->reorder_window = std::min(sps->max_num_reorder_frames,
+ kMaxReorderQueueSize - 1);
+ }
+ }
+ has_slice = true;
default:
nalus.push_back(nalu);
data_size += kNALUHeaderLength + nalu.size;
@@ -287,64 +588,60 @@ void VTVideoDecodeAccelerator::DecodeTask(
}
}
- // 2. Initialize VideoToolbox.
- // TODO(sandersd): Check if the new configuration is identical before
- // reconfiguring.
+ // Initialize VideoToolbox.
+ // TODO(sandersd): Instead of assuming that the last SPS and PPS units are
+ // always the correct ones, maintain a cache of recent SPS and PPS units and
+ // select from them using the slice header.
if (config_changed) {
if (last_sps_.size() == 0 || last_pps_.size() == 0) {
- LOG(ERROR) << "Invalid configuration data";
- NotifyError(INVALID_ARGUMENT);
+ DLOG(ERROR) << "Invalid configuration data";
+ NotifyError(INVALID_ARGUMENT, SFT_INVALID_STREAM);
return;
}
- // TODO(sandersd): Check that the SPS and PPS IDs match.
- std::vector<const uint8_t*> nalu_data_ptrs;
- std::vector<size_t> nalu_data_sizes;
- nalu_data_ptrs.push_back(&last_sps_.front());
- nalu_data_sizes.push_back(last_sps_.size());
- if (last_spsext_.size() != 0) {
- nalu_data_ptrs.push_back(&last_spsext_.front());
- nalu_data_sizes.push_back(last_spsext_.size());
- }
- nalu_data_ptrs.push_back(&last_pps_.front());
- nalu_data_sizes.push_back(last_pps_.size());
-
- // If ConfigureDecoder() fails, it already called NotifyError().
- if (!ConfigureDecoder(nalu_data_ptrs, nalu_data_sizes))
+ if (!ConfigureDecoder())
return;
}
- // If there are no non-configuration units, immediately return an empty
- // (ie. dropped) frame. It is an error to create a MemoryBlock with zero
- // size.
- if (!data_size)
+ // If there are no image slices, drop the bitstream buffer by returning an
+ // empty frame.
+ if (!has_slice) {
+ if (!FinishDelayedFrames())
+ return;
+ gpu_task_runner_->PostTask(FROM_HERE, base::Bind(
+ &VTVideoDecodeAccelerator::DecodeDone, weak_this_, frame));
return;
+ }
- // If the session is not configured, fail.
+ // If the session is not configured by this point, fail.
if (!session_) {
- LOG(ERROR) << "Image slice without configuration data";
- NotifyError(INVALID_ARGUMENT);
+ DLOG(ERROR) << "Configuration data missing";
+ NotifyError(INVALID_ARGUMENT, SFT_INVALID_STREAM);
return;
}
- // 3. Allocate a memory-backed CMBlockBuffer for the translated data.
- // TODO(sandersd): Check that the slice's PPS matches the current PPS.
+ // Update the frame metadata with configuration data.
+ frame->coded_size = coded_size_;
+
+ // Create a memory-backed CMBlockBuffer for the translated data.
+ // TODO(sandersd): Pool of memory blocks.
base::ScopedCFTypeRef<CMBlockBufferRef> data;
OSStatus status = CMBlockBufferCreateWithMemoryBlock(
kCFAllocatorDefault,
- NULL, // &memory_block
+ nullptr, // &memory_block
data_size, // block_length
kCFAllocatorDefault, // block_allocator
- NULL, // &custom_block_source
+ nullptr, // &custom_block_source
0, // offset_to_data
data_size, // data_length
0, // flags
data.InitializeInto());
if (status) {
- NOTIFY_STATUS("CMBlockBufferCreateWithMemoryBlock()", status);
+ NOTIFY_STATUS("CMBlockBufferCreateWithMemoryBlock()", status,
+ SFT_PLATFORM_ERROR);
return;
}
- // 4. Copy NALU data, inserting length headers.
+ // Copy NALU data into the CMBlockBuffer, inserting length headers.
size_t offset = 0;
for (size_t i = 0; i < nalus.size(); i++) {
media::H264NALU& nalu = nalus[i];
@@ -352,399 +649,416 @@ void VTVideoDecodeAccelerator::DecodeTask(
status = CMBlockBufferReplaceDataBytes(
&header, data, offset, kNALUHeaderLength);
if (status) {
- NOTIFY_STATUS("CMBlockBufferReplaceDataBytes()", status);
+ NOTIFY_STATUS("CMBlockBufferReplaceDataBytes()", status,
+ SFT_PLATFORM_ERROR);
return;
}
offset += kNALUHeaderLength;
status = CMBlockBufferReplaceDataBytes(nalu.data, data, offset, nalu.size);
if (status) {
- NOTIFY_STATUS("CMBlockBufferReplaceDataBytes()", status);
+ NOTIFY_STATUS("CMBlockBufferReplaceDataBytes()", status,
+ SFT_PLATFORM_ERROR);
return;
}
offset += nalu.size;
}
- // 5. Package the data for VideoToolbox and request decoding.
- base::ScopedCFTypeRef<CMSampleBufferRef> frame;
+ // Package the data in a CMSampleBuffer.
+ base::ScopedCFTypeRef<CMSampleBufferRef> sample;
status = CMSampleBufferCreate(
kCFAllocatorDefault,
data, // data_buffer
true, // data_ready
- NULL, // make_data_ready_callback
- NULL, // make_data_ready_refcon
+ nullptr, // make_data_ready_callback
+ nullptr, // make_data_ready_refcon
format_, // format_description
1, // num_samples
0, // num_sample_timing_entries
- NULL, // &sample_timing_array
+ nullptr, // &sample_timing_array
0, // num_sample_size_entries
- NULL, // &sample_size_array
- frame.InitializeInto());
+ nullptr, // &sample_size_array
+ sample.InitializeInto());
if (status) {
- NOTIFY_STATUS("CMSampleBufferCreate()", status);
+ NOTIFY_STATUS("CMSampleBufferCreate()", status, SFT_PLATFORM_ERROR);
return;
}
+ // Send the frame for decoding.
// Asynchronous Decompression allows for parallel submission of frames
// (without it, DecodeFrame() does not return until the frame has been
// decoded). We don't enable Temporal Processing so that frames are always
// returned in decode order; this makes it easier to avoid deadlock.
VTDecodeFrameFlags decode_flags =
kVTDecodeFrame_EnableAsynchronousDecompression;
-
- intptr_t bitstream_id = bitstream.id();
status = VTDecompressionSessionDecodeFrame(
session_,
- frame, // sample_buffer
+ sample, // sample_buffer
decode_flags, // decode_flags
- reinterpret_cast<void*>(bitstream_id), // source_frame_refcon
- NULL); // &info_flags_out
+ reinterpret_cast<void*>(frame), // source_frame_refcon
+ nullptr); // &info_flags_out
if (status) {
- NOTIFY_STATUS("VTDecompressionSessionDecodeFrame()", status);
+ NOTIFY_STATUS("VTDecompressionSessionDecodeFrame()", status,
+ SFT_DECODE_ERROR);
return;
}
-
- // Now that the bitstream is decoding, don't drop it.
- (void)drop_bitstream.Release();
}
// This method may be called on any VideoToolbox thread.
void VTVideoDecodeAccelerator::Output(
- int32_t bitstream_id,
+ void* source_frame_refcon,
OSStatus status,
CVImageBufferRef image_buffer) {
if (status) {
- // TODO(sandersd): Handle dropped frames.
- NOTIFY_STATUS("Decoding", status);
- image_buffer = NULL;
- } else if (CFGetTypeID(image_buffer) != CVPixelBufferGetTypeID()) {
- LOG(ERROR) << "Decoded frame is not a CVPixelBuffer";
- NotifyError(PLATFORM_FAILURE);
- image_buffer = NULL;
- } else {
- CFRetain(image_buffer);
+ NOTIFY_STATUS("Decoding", status, SFT_DECODE_ERROR);
+ return;
}
+
+ // The type of |image_buffer| is CVImageBuffer, but we only handle
+ // CVPixelBuffers. This should be guaranteed as we set
+ // kCVPixelBufferOpenGLCompatibilityKey in |image_config|.
+ //
+ // Sometimes, for unknown reasons (http://crbug.com/453050), |image_buffer| is
+ // NULL, which causes CFGetTypeID() to crash. While the rest of the code would
+ // smoothly handle NULL as a dropped frame, we choose to fail permanantly here
+ // until the issue is better understood.
+ if (!image_buffer || CFGetTypeID(image_buffer) != CVPixelBufferGetTypeID()) {
+ DLOG(ERROR) << "Decoded frame is not a CVPixelBuffer";
+ NotifyError(PLATFORM_FAILURE, SFT_DECODE_ERROR);
+ return;
+ }
+
+ Frame* frame = reinterpret_cast<Frame*>(source_frame_refcon);
+ frame->image.reset(image_buffer, base::scoped_policy::RETAIN);
+ gpu_task_runner_->PostTask(FROM_HERE, base::Bind(
+ &VTVideoDecodeAccelerator::DecodeDone, weak_this_, frame));
+}
+
+void VTVideoDecodeAccelerator::DecodeDone(Frame* frame) {
+ DCHECK(gpu_thread_checker_.CalledOnValidThread());
+ DCHECK_EQ(1u, pending_frames_.count(frame->bitstream_id));
+ Task task(TASK_FRAME);
+ task.frame = pending_frames_[frame->bitstream_id];
+ pending_frames_.erase(frame->bitstream_id);
+ task_queue_.push(task);
+ ProcessWorkQueues();
+}
+
+void VTVideoDecodeAccelerator::FlushTask(TaskType type) {
+ DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
+ FinishDelayedFrames();
+
+ // Always queue a task, even if FinishDelayedFrames() fails, so that
+ // destruction always completes.
gpu_task_runner_->PostTask(FROM_HERE, base::Bind(
- &VTVideoDecodeAccelerator::OutputTask,
- weak_this_factory_.GetWeakPtr(),
- DecodedFrame(bitstream_id, image_buffer)));
+ &VTVideoDecodeAccelerator::FlushDone, weak_this_, type));
+}
+
+void VTVideoDecodeAccelerator::FlushDone(TaskType type) {
+ DCHECK(gpu_thread_checker_.CalledOnValidThread());
+ task_queue_.push(Task(type));
+ ProcessWorkQueues();
}
-void VTVideoDecodeAccelerator::OutputTask(DecodedFrame frame) {
- DCHECK(CalledOnValidThread());
- decoded_frames_.push(frame);
- ProcessDecodedFrames();
+void VTVideoDecodeAccelerator::Decode(const media::BitstreamBuffer& bitstream) {
+ DCHECK(gpu_thread_checker_.CalledOnValidThread());
+ DCHECK_EQ(0u, assigned_bitstream_ids_.count(bitstream.id()));
+ assigned_bitstream_ids_.insert(bitstream.id());
+ Frame* frame = new Frame(bitstream.id());
+ pending_frames_[frame->bitstream_id] = make_linked_ptr(frame);
+ decoder_thread_.task_runner()->PostTask(
+ FROM_HERE, base::Bind(&VTVideoDecodeAccelerator::DecodeTask,
+ base::Unretained(this), bitstream, frame));
}
void VTVideoDecodeAccelerator::AssignPictureBuffers(
const std::vector<media::PictureBuffer>& pictures) {
- DCHECK(CalledOnValidThread());
+ DCHECK(gpu_thread_checker_.CalledOnValidThread());
- for (size_t i = 0; i < pictures.size(); i++) {
- DCHECK(!texture_ids_.count(pictures[i].id()));
- assigned_picture_ids_.insert(pictures[i].id());
- available_picture_ids_.push_back(pictures[i].id());
- texture_ids_[pictures[i].id()] = pictures[i].texture_id();
+ for (const media::PictureBuffer& picture : pictures) {
+ DCHECK(!texture_ids_.count(picture.id()));
+ assigned_picture_ids_.insert(picture.id());
+ available_picture_ids_.push_back(picture.id());
+ texture_ids_[picture.id()] = picture.texture_id();
}
// Pictures are not marked as uncleared until after this method returns, and
// they will be broken if they are used before that happens. So, schedule
// future work after that happens.
gpu_task_runner_->PostTask(FROM_HERE, base::Bind(
- &VTVideoDecodeAccelerator::ProcessDecodedFrames,
- weak_this_factory_.GetWeakPtr()));
+ &VTVideoDecodeAccelerator::ProcessWorkQueues, weak_this_));
}
void VTVideoDecodeAccelerator::ReusePictureBuffer(int32_t picture_id) {
- DCHECK(CalledOnValidThread());
+ DCHECK(gpu_thread_checker_.CalledOnValidThread());
DCHECK_EQ(CFGetRetainCount(picture_bindings_[picture_id]), 1);
picture_bindings_.erase(picture_id);
- // Don't put the picture back in the available list if has been dismissed.
if (assigned_picture_ids_.count(picture_id) != 0) {
available_picture_ids_.push_back(picture_id);
- ProcessDecodedFrames();
- }
-}
-
-void VTVideoDecodeAccelerator::CompleteAction(Action action) {
- DCHECK(CalledOnValidThread());
-
- switch (action) {
- case ACTION_FLUSH:
- client_->NotifyFlushDone();
- break;
- case ACTION_RESET:
- client_->NotifyResetDone();
- break;
- case ACTION_DESTROY:
- delete this;
- break;
- }
-}
-
-void VTVideoDecodeAccelerator::CompleteActions(int32_t bitstream_id) {
- DCHECK(CalledOnValidThread());
- while (!pending_actions_.empty() &&
- pending_actions_.front().bitstream_id == bitstream_id) {
- CompleteAction(pending_actions_.front().action);
- pending_actions_.pop();
+ ProcessWorkQueues();
+ } else {
+ client_->DismissPictureBuffer(picture_id);
}
}
-void VTVideoDecodeAccelerator::ProcessDecodedFrames() {
- DCHECK(CalledOnValidThread());
-
- while (!decoded_frames_.empty()) {
- if (pending_actions_.empty()) {
- // No pending actions; send frames normally.
- if (!has_error_)
- SendPictures(pending_bitstream_ids_.back());
+void VTVideoDecodeAccelerator::ProcessWorkQueues() {
+ DCHECK(gpu_thread_checker_.CalledOnValidThread());
+ switch (state_) {
+ case STATE_DECODING:
+ // TODO(sandersd): Batch where possible.
+ while (state_ == STATE_DECODING) {
+ if (!ProcessReorderQueue() && !ProcessTaskQueue())
+ break;
+ }
return;
- }
- int32_t next_action_bitstream_id = pending_actions_.front().bitstream_id;
- int32_t last_sent_bitstream_id = -1;
- switch (pending_actions_.front().action) {
- case ACTION_FLUSH:
- // Send frames normally.
- if (has_error_)
- return;
- last_sent_bitstream_id = SendPictures(next_action_bitstream_id);
- break;
+ case STATE_ERROR:
+ // Do nothing until Destroy() is called.
+ return;
- case ACTION_RESET:
- // Drop decoded frames.
- if (has_error_)
+ case STATE_DESTROYING:
+ // Drop tasks until we are ready to destruct.
+ while (!task_queue_.empty()) {
+ if (task_queue_.front().type == TASK_DESTROY) {
+ delete this;
return;
- while (!decoded_frames_.empty() &&
- last_sent_bitstream_id != next_action_bitstream_id) {
- last_sent_bitstream_id = decoded_frames_.front().bitstream_id;
- decoded_frames_.pop();
- DCHECK_EQ(pending_bitstream_ids_.front(), last_sent_bitstream_id);
- pending_bitstream_ids_.pop();
- client_->NotifyEndOfBitstreamBuffer(last_sent_bitstream_id);
}
- break;
+ task_queue_.pop();
+ }
+ return;
+ }
+}
- case ACTION_DESTROY:
- // Drop decoded frames, without bookkeeping.
- while (!decoded_frames_.empty()) {
- last_sent_bitstream_id = decoded_frames_.front().bitstream_id;
- decoded_frames_.pop();
- }
+bool VTVideoDecodeAccelerator::ProcessTaskQueue() {
+ DCHECK(gpu_thread_checker_.CalledOnValidThread());
+ DCHECK_EQ(state_, STATE_DECODING);
- // Handle completing the action specially, as it is important not to
- // access |this| after calling CompleteAction().
- if (last_sent_bitstream_id == next_action_bitstream_id)
- CompleteAction(ACTION_DESTROY);
+ if (task_queue_.empty())
+ return false;
- // Either |this| was deleted or no more progress can be made.
- return;
- }
+ const Task& task = task_queue_.front();
+ switch (task.type) {
+ case TASK_FRAME:
+ // TODO(sandersd): Signal IDR explicitly (not using pic_order_cnt == 0).
+ if (reorder_queue_.size() < kMaxReorderQueueSize &&
+ (task.frame->pic_order_cnt != 0 || reorder_queue_.empty())) {
+ assigned_bitstream_ids_.erase(task.frame->bitstream_id);
+ client_->NotifyEndOfBitstreamBuffer(task.frame->bitstream_id);
+ reorder_queue_.push(task.frame);
+ task_queue_.pop();
+ return true;
+ }
+ return false;
- // If we ran out of buffers (or pictures), no more progress can be made
- // until more frames are decoded.
- if (last_sent_bitstream_id != next_action_bitstream_id)
- return;
+ case TASK_FLUSH:
+ DCHECK_EQ(task.type, pending_flush_tasks_.front());
+ if (reorder_queue_.size() == 0) {
+ pending_flush_tasks_.pop();
+ client_->NotifyFlushDone();
+ task_queue_.pop();
+ return true;
+ }
+ return false;
- // Complete all actions pending for this |bitstream_id|, then loop to see
- // if progress can be made on the next action.
- CompleteActions(next_action_bitstream_id);
- }
-}
-
-int32_t VTVideoDecodeAccelerator::ProcessDroppedFrames(
- int32_t last_sent_bitstream_id,
- int32_t up_to_bitstream_id) {
- DCHECK(CalledOnValidThread());
- // Drop frames as long as there is a frame, we have not reached the next
- // action, and the next frame has no image.
- while (!decoded_frames_.empty() &&
- last_sent_bitstream_id != up_to_bitstream_id &&
- decoded_frames_.front().image_buffer.get() == NULL) {
- const DecodedFrame& frame = decoded_frames_.front();
- DCHECK_EQ(pending_bitstream_ids_.front(), frame.bitstream_id);
- client_->NotifyEndOfBitstreamBuffer(frame.bitstream_id);
- last_sent_bitstream_id = frame.bitstream_id;
- decoded_frames_.pop();
- pending_bitstream_ids_.pop();
- }
- return last_sent_bitstream_id;
-}
-
-// TODO(sandersd): If GpuVideoDecoder didn't specifically check the size of
-// textures, this would be unnecessary, as the size is actually a property of
-// the texture binding, not the texture. We rebind every frame, so the size
-// passed to ProvidePictureBuffers() is meaningless.
-void VTVideoDecodeAccelerator::ProcessSizeChangeIfNeeded() {
- DCHECK(CalledOnValidThread());
- DCHECK(!decoded_frames_.empty());
-
- // Find the size of the next image.
- const DecodedFrame& frame = decoded_frames_.front();
- CVImageBufferRef image_buffer = frame.image_buffer.get();
- size_t width = CVPixelBufferGetWidth(image_buffer);
- size_t height = CVPixelBufferGetHeight(image_buffer);
- gfx::Size image_size(width, height);
-
- if (picture_size_ != image_size) {
- // Dismiss all assigned picture buffers.
- for (int32_t picture_id : assigned_picture_ids_)
- client_->DismissPictureBuffer(picture_id);
- assigned_picture_ids_.clear();
- available_picture_ids_.clear();
-
- // Request new pictures.
- client_->ProvidePictureBuffers(
- kNumPictureBuffers, image_size, GL_TEXTURE_RECTANGLE_ARB);
- picture_size_ = image_size;
- }
-}
-
-int32_t VTVideoDecodeAccelerator::SendPictures(int32_t up_to_bitstream_id) {
- DCHECK(CalledOnValidThread());
- DCHECK(!decoded_frames_.empty());
-
- // TODO(sandersd): Store the actual last sent bitstream ID?
- int32_t last_sent_bitstream_id = -1;
-
- last_sent_bitstream_id =
- ProcessDroppedFrames(last_sent_bitstream_id, up_to_bitstream_id);
- if (last_sent_bitstream_id == up_to_bitstream_id || decoded_frames_.empty())
- return last_sent_bitstream_id;
-
- ProcessSizeChangeIfNeeded();
- if (available_picture_ids_.empty())
- return last_sent_bitstream_id;
+ case TASK_RESET:
+ DCHECK_EQ(task.type, pending_flush_tasks_.front());
+ if (reorder_queue_.size() == 0) {
+ last_sps_id_ = -1;
+ last_pps_id_ = -1;
+ last_sps_.clear();
+ last_spsext_.clear();
+ last_pps_.clear();
+ poc_.Reset();
+ pending_flush_tasks_.pop();
+ client_->NotifyResetDone();
+ task_queue_.pop();
+ return true;
+ }
+ return false;
- if (!make_context_current_.Run()) {
- LOG(ERROR) << "Failed to make GL context current";
- NotifyError(PLATFORM_FAILURE);
- return last_sent_bitstream_id;
+ case TASK_DESTROY:
+ NOTREACHED() << "Can't destroy while in STATE_DECODING.";
+ NotifyError(ILLEGAL_STATE, SFT_PLATFORM_ERROR);
+ return false;
}
+}
- glEnable(GL_TEXTURE_RECTANGLE_ARB);
- while (!available_picture_ids_.empty() && !has_error_) {
- DCHECK_NE(last_sent_bitstream_id, up_to_bitstream_id);
- DCHECK(!decoded_frames_.empty());
-
- // We don't pop |frame| or |picture_id| until they are consumed, which may
- // not happen if an error occurs. Conveniently, this also removes some
- // refcounting.
- const DecodedFrame& frame = decoded_frames_.front();
- DCHECK_EQ(pending_bitstream_ids_.front(), frame.bitstream_id);
- int32_t picture_id = available_picture_ids_.back();
-
- CVImageBufferRef image_buffer = frame.image_buffer.get();
- IOSurfaceRef surface = CVPixelBufferGetIOSurface(image_buffer);
-
- gfx::ScopedTextureBinder
- texture_binder(GL_TEXTURE_RECTANGLE_ARB, texture_ids_[picture_id]);
- CGLError status = CGLTexImageIOSurface2D(
- cgl_context_, // ctx
- GL_TEXTURE_RECTANGLE_ARB, // target
- GL_RGB, // internal_format
- picture_size_.width(), // width
- picture_size_.height(), // height
- GL_YCBCR_422_APPLE, // format
- GL_UNSIGNED_SHORT_8_8_APPLE, // type
- surface, // io_surface
- 0); // plane
- if (status != kCGLNoError) {
- NOTIFY_STATUS("CGLTexImageIOSurface2D()", status);
- break;
- }
+bool VTVideoDecodeAccelerator::ProcessReorderQueue() {
+ DCHECK(gpu_thread_checker_.CalledOnValidThread());
+ DCHECK_EQ(state_, STATE_DECODING);
- picture_bindings_[picture_id] = frame.image_buffer;
- client_->PictureReady(media::Picture(
- picture_id, frame.bitstream_id, gfx::Rect(picture_size_)));
- available_picture_ids_.pop_back();
- client_->NotifyEndOfBitstreamBuffer(frame.bitstream_id);
- last_sent_bitstream_id = frame.bitstream_id;
- decoded_frames_.pop();
- pending_bitstream_ids_.pop();
-
- last_sent_bitstream_id =
- ProcessDroppedFrames(last_sent_bitstream_id, up_to_bitstream_id);
- if (last_sent_bitstream_id == up_to_bitstream_id || decoded_frames_.empty())
- break;
+ if (reorder_queue_.empty())
+ return false;
- ProcessSizeChangeIfNeeded();
+ // If the next task is a flush (because there is a pending flush or becuase
+ // the next frame is an IDR), then we don't need a full reorder buffer to send
+ // the next frame.
+ bool flushing = !task_queue_.empty() &&
+ (task_queue_.front().type != TASK_FRAME ||
+ task_queue_.front().frame->pic_order_cnt == 0);
+
+ size_t reorder_window = std::max(0, reorder_queue_.top()->reorder_window);
+ if (flushing || reorder_queue_.size() > reorder_window) {
+ if (ProcessFrame(*reorder_queue_.top())) {
+ reorder_queue_.pop();
+ return true;
+ }
}
- glDisable(GL_TEXTURE_RECTANGLE_ARB);
- return last_sent_bitstream_id;
+ return false;
}
-void VTVideoDecodeAccelerator::FlushTask() {
- DCHECK(decoder_thread_.message_loop_proxy()->BelongsToCurrentThread());
- OSStatus status = VTDecompressionSessionFinishDelayedFrames(session_);
- if (status)
- NOTIFY_STATUS("VTDecompressionSessionFinishDelayedFrames()", status);
+bool VTVideoDecodeAccelerator::ProcessFrame(const Frame& frame) {
+ DCHECK(gpu_thread_checker_.CalledOnValidThread());
+ DCHECK_EQ(state_, STATE_DECODING);
+
+ // If the next pending flush is for a reset, then the frame will be dropped.
+ bool resetting = !pending_flush_tasks_.empty() &&
+ pending_flush_tasks_.front() == TASK_RESET;
+
+ if (!resetting && frame.image.get()) {
+ // If the |coded_size| has changed, request new picture buffers and then
+ // wait for them.
+ // TODO(sandersd): If GpuVideoDecoder didn't specifically check the size of
+ // textures, this would be unnecessary, as the size is actually a property
+ // of the texture binding, not the texture. We rebind every frame, so the
+ // size passed to ProvidePictureBuffers() is meaningless.
+ if (picture_size_ != frame.coded_size) {
+ // Dismiss current pictures.
+ for (int32_t picture_id : assigned_picture_ids_)
+ client_->DismissPictureBuffer(picture_id);
+ assigned_picture_ids_.clear();
+ available_picture_ids_.clear();
+
+ // Request new pictures.
+ picture_size_ = frame.coded_size;
+ client_->ProvidePictureBuffers(
+ kNumPictureBuffers, coded_size_, GL_TEXTURE_RECTANGLE_ARB);
+ return false;
+ }
+ if (!SendFrame(frame))
+ return false;
+ }
+
+ return true;
}
-void VTVideoDecodeAccelerator::QueueAction(Action action) {
- DCHECK(CalledOnValidThread());
- if (pending_bitstream_ids_.empty()) {
- // If there are no pending frames, all actions complete immediately.
- CompleteAction(action);
- } else {
- // Otherwise, queue the action.
- pending_actions_.push(PendingAction(action, pending_bitstream_ids_.back()));
+bool VTVideoDecodeAccelerator::SendFrame(const Frame& frame) {
+ DCHECK(gpu_thread_checker_.CalledOnValidThread());
+ DCHECK_EQ(state_, STATE_DECODING);
+
+ if (available_picture_ids_.empty())
+ return false;
- // Request a flush to make sure the action will eventually complete.
- decoder_thread_.message_loop_proxy()->PostTask(FROM_HERE, base::Bind(
- &VTVideoDecodeAccelerator::FlushTask, base::Unretained(this)));
+ int32_t picture_id = available_picture_ids_.back();
+ IOSurfaceRef surface = CVPixelBufferGetIOSurface(frame.image.get());
+
+ if (!make_context_current_.Run()) {
+ DLOG(ERROR) << "Failed to make GL context current";
+ NotifyError(PLATFORM_FAILURE, SFT_PLATFORM_ERROR);
+ return false;
+ }
- // See if we can make progress now that there is a new pending action.
- ProcessDecodedFrames();
+ glEnable(GL_TEXTURE_RECTANGLE_ARB);
+ gfx::ScopedTextureBinder
+ texture_binder(GL_TEXTURE_RECTANGLE_ARB, texture_ids_[picture_id]);
+ CGLError status = CGLTexImageIOSurface2D(
+ cgl_context_, // ctx
+ GL_TEXTURE_RECTANGLE_ARB, // target
+ GL_RGB, // internal_format
+ frame.coded_size.width(), // width
+ frame.coded_size.height(), // height
+ GL_YCBCR_422_APPLE, // format
+ GL_UNSIGNED_SHORT_8_8_APPLE, // type
+ surface, // io_surface
+ 0); // plane
+ if (status != kCGLNoError) {
+ NOTIFY_STATUS("CGLTexImageIOSurface2D()", status, SFT_PLATFORM_ERROR);
+ return false;
}
+ glDisable(GL_TEXTURE_RECTANGLE_ARB);
+
+ available_picture_ids_.pop_back();
+ picture_bindings_[picture_id] = frame.image;
+ client_->PictureReady(media::Picture(picture_id, frame.bitstream_id,
+ gfx::Rect(frame.coded_size), false));
+ return true;
}
-void VTVideoDecodeAccelerator::NotifyError(Error error) {
- if (!CalledOnValidThread()) {
+void VTVideoDecodeAccelerator::NotifyError(
+ Error vda_error_type,
+ VTVDASessionFailureType session_failure_type) {
+ DCHECK_LT(session_failure_type, SFT_MAX + 1);
+ if (!gpu_thread_checker_.CalledOnValidThread()) {
gpu_task_runner_->PostTask(FROM_HERE, base::Bind(
- &VTVideoDecodeAccelerator::NotifyError,
- weak_this_factory_.GetWeakPtr(),
- error));
- return;
+ &VTVideoDecodeAccelerator::NotifyError, weak_this_, vda_error_type,
+ session_failure_type));
+ } else if (state_ == STATE_DECODING) {
+ state_ = STATE_ERROR;
+ UMA_HISTOGRAM_ENUMERATION("Media.VTVDA.SessionFailureReason",
+ session_failure_type,
+ SFT_MAX + 1);
+ client_->NotifyError(vda_error_type);
}
- has_error_ = true;
- client_->NotifyError(error);
}
-void VTVideoDecodeAccelerator::DropBitstream(int32_t bitstream_id) {
- DCHECK(decoder_thread_.message_loop_proxy()->BelongsToCurrentThread());
- gpu_task_runner_->PostTask(FROM_HERE, base::Bind(
- &VTVideoDecodeAccelerator::OutputTask,
- weak_this_factory_.GetWeakPtr(),
- DecodedFrame(bitstream_id, NULL)));
+void VTVideoDecodeAccelerator::QueueFlush(TaskType type) {
+ DCHECK(gpu_thread_checker_.CalledOnValidThread());
+ pending_flush_tasks_.push(type);
+ decoder_thread_.task_runner()->PostTask(
+ FROM_HERE, base::Bind(&VTVideoDecodeAccelerator::FlushTask,
+ base::Unretained(this), type));
+
+ // If this is a new flush request, see if we can make progress.
+ if (pending_flush_tasks_.size() == 1)
+ ProcessWorkQueues();
}
void VTVideoDecodeAccelerator::Flush() {
- DCHECK(CalledOnValidThread());
- QueueAction(ACTION_FLUSH);
+ DCHECK(gpu_thread_checker_.CalledOnValidThread());
+ QueueFlush(TASK_FLUSH);
}
void VTVideoDecodeAccelerator::Reset() {
- DCHECK(CalledOnValidThread());
- QueueAction(ACTION_RESET);
+ DCHECK(gpu_thread_checker_.CalledOnValidThread());
+ QueueFlush(TASK_RESET);
}
void VTVideoDecodeAccelerator::Destroy() {
- DCHECK(CalledOnValidThread());
- // Drop any other pending actions.
- while (!pending_actions_.empty())
- pending_actions_.pop();
- // Return all bitstream buffers.
- while (!pending_bitstream_ids_.empty()) {
- client_->NotifyEndOfBitstreamBuffer(pending_bitstream_ids_.front());
- pending_bitstream_ids_.pop();
+ DCHECK(gpu_thread_checker_.CalledOnValidThread());
+
+ // In a forceful shutdown, the decoder thread may be dead already.
+ if (!decoder_thread_.IsRunning()) {
+ delete this;
+ return;
}
- QueueAction(ACTION_DESTROY);
+
+ // For a graceful shutdown, return assigned buffers and flush before
+ // destructing |this|.
+ // TODO(sandersd): Make sure the decoder won't try to read the buffers again
+ // before discarding them.
+ for (int32_t bitstream_id : assigned_bitstream_ids_)
+ client_->NotifyEndOfBitstreamBuffer(bitstream_id);
+ assigned_bitstream_ids_.clear();
+ state_ = STATE_DESTROYING;
+ QueueFlush(TASK_DESTROY);
}
bool VTVideoDecodeAccelerator::CanDecodeOnIOThread() {
return false;
}
+// static
+media::VideoDecodeAccelerator::SupportedProfiles
+VTVideoDecodeAccelerator::GetSupportedProfiles() {
+ SupportedProfiles profiles;
+ for (const auto& supported_profile : kSupportedProfiles) {
+ SupportedProfile profile;
+ profile.profile = supported_profile;
+ profile.min_resolution.SetSize(16, 16);
+ profile.max_resolution.SetSize(4096, 2160);
+ profiles.push_back(profile);
+ }
+ return profiles;
+}
+
} // namespace content
diff --git a/chromium/content/common/gpu/media/vt_video_decode_accelerator.h b/chromium/content/common/gpu/media/vt_video_decode_accelerator.h
index 5aa4f7051c7..7fbc88837bc 100644
--- a/chromium/content/common/gpu/media/vt_video_decode_accelerator.h
+++ b/chromium/content/common/gpu/media/vt_video_decode_accelerator.h
@@ -11,27 +11,26 @@
#include <queue>
#include "base/mac/scoped_cftyperef.h"
-#include "base/memory/ref_counted.h"
+#include "base/memory/linked_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/threading/thread.h"
+#include "base/threading/thread_checker.h"
#include "content/common/gpu/media/vt.h"
#include "media/filters/h264_parser.h"
+#include "media/video/h264_poc.h"
#include "media/video/video_decode_accelerator.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gl/gl_context_cgl.h"
-namespace base {
-class SingleThreadTaskRunner;
-} // namespace base
-
namespace content {
+// Preload VideoToolbox libraries, needed for sandbox warmup.
+bool InitializeVideoToolbox();
+
// VideoToolbox.framework implementation of the VideoDecodeAccelerator
// interface for Mac OS X (currently limited to 10.9+).
-class VTVideoDecodeAccelerator
- : public media::VideoDecodeAccelerator,
- public base::NonThreadSafe {
+class VTVideoDecodeAccelerator : public media::VideoDecodeAccelerator {
public:
explicit VTVideoDecodeAccelerator(
CGLContextObj cgl_context,
@@ -51,85 +50,115 @@ class VTVideoDecodeAccelerator
// Called by OutputThunk() when VideoToolbox finishes decoding a frame.
void Output(
- int32_t bitstream_id,
+ void* source_frame_refcon,
OSStatus status,
CVImageBufferRef image_buffer);
+ static media::VideoDecodeAccelerator::SupportedProfiles
+ GetSupportedProfiles();
+
private:
- struct DecodedFrame {
- DecodedFrame(int32_t bitstream_id, CVImageBufferRef image_buffer);
- ~DecodedFrame();
+ // Logged to UMA, so never reuse values. Make sure to update
+ // VTVDASessionFailureType in histograms.xml to match.
+ enum VTVDASessionFailureType {
+ SFT_SUCCESSFULLY_INITIALIZED = 0,
+ SFT_PLATFORM_ERROR = 1,
+ SFT_INVALID_STREAM = 2,
+ SFT_UNSUPPORTED_STREAM_PARAMETERS = 3,
+ SFT_DECODE_ERROR = 4,
+ SFT_UNSUPPORTED_STREAM = 5,
+ // Must always be equal to largest entry logged.
+ SFT_MAX = SFT_UNSUPPORTED_STREAM
+ };
- int32_t bitstream_id;
- base::ScopedCFTypeRef<CVImageBufferRef> image_buffer;
+ enum State {
+ STATE_DECODING,
+ STATE_ERROR,
+ STATE_DESTROYING,
};
- // Actions are the possible types of pending operations, which are queued
- // by Flush(), Reset(), and Destroy().
- enum Action {
- ACTION_FLUSH,
- ACTION_RESET,
- ACTION_DESTROY
+ enum TaskType {
+ TASK_FRAME,
+ TASK_FLUSH,
+ TASK_RESET,
+ TASK_DESTROY,
};
- // PendingActions contain the |bitstream_id| of a frame that, once decoded and
- // sent, a particular |action| should be completed at.
- struct PendingAction {
- PendingAction(Action action, int32_t bitstream_id);
- ~PendingAction();
+ struct Frame {
+ Frame(int32_t bitstream_id);
+ ~Frame();
- Action action;
+ // ID of the bitstream buffer this Frame will be decoded from.
int32_t bitstream_id;
+
+ // Relative presentation order of this frame (see AVC spec).
+ int32_t pic_order_cnt;
+
+ // Nnumber of frames after this one in decode order that can appear before
+ // before it in presentation order.
+ int32_t reorder_window;
+
+ // Size of the decoded frame.
+ // TODO(sandersd): visible_rect.
+ gfx::Size coded_size;
+
+ // VideoToolbox decoded image, if decoding was successful.
+ base::ScopedCFTypeRef<CVImageBufferRef> image;
};
+ struct Task {
+ Task(TaskType type);
+ ~Task();
+
+ TaskType type;
+ linked_ptr<Frame> frame;
+ };
+
+ //
// Methods for interacting with VideoToolbox. Run on |decoder_thread_|.
- bool ConfigureDecoder(
- const std::vector<const uint8_t*>& nalu_data_ptrs,
- const std::vector<size_t>& nalu_data_sizes);
- void DecodeTask(const media::BitstreamBuffer&);
- void FlushTask();
- void DropBitstream(int32_t bitstream_id);
+ //
+ // Compute the |pic_order_cnt| for a frame. Returns true or calls
+ // NotifyError() before returning false.
+ bool ComputePicOrderCnt(
+ const media::H264SPS* sps,
+ const media::H264SliceHeader& slice_hdr,
+ Frame* frame);
+
+ // Set up VideoToolbox using the current SPS and PPS. Returns true or calls
+ // NotifyError() before returning false.
+ bool ConfigureDecoder();
+
+ // Wait for VideoToolbox to output all pending frames. Returns true or calls
+ // NotifyError() before returning false.
+ bool FinishDelayedFrames();
+
+ // |frame| is owned by |pending_frames_|.
+ void DecodeTask(const media::BitstreamBuffer&, Frame* frame);
+ void DecodeDone(Frame* frame);
+
+ //
// Methods for interacting with |client_|. Run on |gpu_task_runner_|.
- void OutputTask(DecodedFrame frame);
- void NotifyError(Error error);
-
- // Send decoded frames up to and including |up_to_bitstream_id|, and return
- // the last sent |bitstream_id|.
- int32_t SendPictures(int32_t up_to_bitstream_id);
-
- // Internal helper for SendPictures(): Drop frames with no image data up to
- // a particular bitstream ID, so that if there is still a frame in the queue
- // when this function returns, it is guaranteed to have image data, and thus
- // it is time to set up the GPU context. Returns the last bitstream ID that
- // was dropped, or |last_sent_bitstream_id| if no frames were dropped.
- int32_t ProcessDroppedFrames(
- int32_t last_sent_bitstream_id,
- int32_t up_to_bitstream_id);
-
- // Internal helper for SendPictures(): Check if the next frame has a size
- // different from the current picture buffers, and request new ones if so.
- void ProcessSizeChangeIfNeeded();
-
- // Since VideoToolbox has no reset feature (only flush), and the VDA API
- // allows Decode() and Flush() calls during a reset operation, it's possible
- // to have multiple pending actions at once. We handle the fully general case
- // of an arbitrary sequence of pending actions (in reality, there should
- // probably be at most one reset and one flush at a time).
- void QueueAction(Action action);
-
- // Process queued decoded frames, usually by sending them (unless there
- // is a pending ACTION_RESET or ACTION_DESTROY, in which case they are
- // dropped), completing queued actions along the way.
- void ProcessDecodedFrames();
-
- // Complete a particular action, by eg. calling NotifyFlushDone().
- // Warning: Deletes |this| if |action| is ACTION_DESTROY.
- void CompleteAction(Action action);
-
- // Complete all actions pending for a particular |bitstream_id|.
- // Warning: Do not call if there is a pending ACTION_DESTROY.
- void CompleteActions(int32_t bitstream_id);
+ //
+ void NotifyError(
+ Error vda_error_type,
+ VTVDASessionFailureType session_failure_type);
+
+ // |type| is the type of task that the flush will complete, one of TASK_FLUSH,
+ // TASK_RESET, or TASK_DESTROY.
+ void QueueFlush(TaskType type);
+ void FlushTask(TaskType type);
+ void FlushDone(TaskType type);
+
+ // Try to make progress on tasks in the |task_queue_| or sending frames in the
+ // |reorder_queue_|.
+ void ProcessWorkQueues();
+
+ // These methods returns true if a task was completed, false otherwise.
+ bool ProcessTaskQueue();
+ bool ProcessReorderQueue();
+ bool ProcessFrame(const Frame& frame);
+ bool SendFrame(const Frame& frame);
//
// GPU thread state.
@@ -137,21 +166,36 @@ class VTVideoDecodeAccelerator
CGLContextObj cgl_context_;
base::Callback<bool(void)> make_context_current_;
media::VideoDecodeAccelerator::Client* client_;
+ State state_;
+
+ // Queue of pending flush tasks. This is used to drop frames when a reset
+ // is pending.
+ std::queue<TaskType> pending_flush_tasks_;
- // client_->NotifyError() called.
- bool has_error_;
+ // Queue of tasks to complete in the GPU thread.
+ std::queue<Task> task_queue_;
+
+ // Utility class to define the order of frames in the reorder queue.
+ struct FrameOrder {
+ bool operator()(
+ const linked_ptr<Frame>& lhs,
+ const linked_ptr<Frame>& rhs) const;
+ };
+
+ // Queue of decoded frames in presentation order.
+ std::priority_queue<linked_ptr<Frame>,
+ std::vector<linked_ptr<Frame>>,
+ FrameOrder> reorder_queue_;
// Size of assigned picture buffers.
gfx::Size picture_size_;
- // Queue of actions so that we can quickly discover what the next action will
- // be; this is useful because we are dropping all frames when the next action
- // is ACTION_RESET or ACTION_DESTROY.
- std::queue<PendingAction> pending_actions_;
+ // Frames that have not yet been decoded, keyed by bitstream ID; maintains
+ // ownership of Frame objects while they flow through VideoToolbox.
+ std::map<int32_t, linked_ptr<Frame>> pending_frames_;
- // Queue of bitstreams that have not yet been decoded. This is mostly needed
- // to be sure we free them all in Destroy().
- std::queue<int32_t> pending_bitstream_ids_;
+ // Set of assigned bitstream IDs, so that Destroy() can release them all.
+ std::set<int32_t> assigned_bitstream_ids_;
// All picture buffers assigned to us. Used to check if reused picture buffers
// should be added back to the available list or released. (They are not
@@ -164,9 +208,6 @@ class VTVideoDecodeAccelerator
// Pictures ready to be rendered to.
std::vector<int32_t> available_picture_ids_;
- // Decoded frames ready to render.
- std::queue<DecodedFrame> decoded_frames_;
-
// Image buffers kept alive while they are bound to pictures.
std::map<int32_t, base::ScopedCFTypeRef<CVImageBufferRef>> picture_bindings_;
@@ -177,24 +218,27 @@ class VTVideoDecodeAccelerator
base::ScopedCFTypeRef<CMFormatDescriptionRef> format_;
base::ScopedCFTypeRef<VTDecompressionSessionRef> session_;
media::H264Parser parser_;
+ gfx::Size coded_size_;
+ int last_sps_id_;
std::vector<uint8_t> last_sps_;
std::vector<uint8_t> last_spsext_;
+ int last_pps_id_;
std::vector<uint8_t> last_pps_;
+ media::H264POC poc_;
//
// Shared state (set up and torn down on GPU thread).
//
scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner_;
+ base::ThreadChecker gpu_thread_checker_;
+ base::WeakPtr<VTVideoDecodeAccelerator> weak_this_;
+ base::Thread decoder_thread_;
- // This WeakPtrFactory does not need to be last as its pointers are bound to
- // the same thread it is destructed on (the GPU thread).
+ // Declared last to ensure that all weak pointers are invalidated before
+ // other destructors run.
base::WeakPtrFactory<VTVideoDecodeAccelerator> weak_this_factory_;
- // Declared last to ensure that all decoder thread tasks complete before any
- // state is destructed.
- base::Thread decoder_thread_;
-
DISALLOW_COPY_AND_ASSIGN(VTVideoDecodeAccelerator);
};
diff --git a/chromium/content/common/gpu/stream_texture_android.cc b/chromium/content/common/gpu/stream_texture_android.cc
index eb7f3bbe32b..5985821862f 100644
--- a/chromium/content/common/gpu/stream_texture_android.cc
+++ b/chromium/content/common/gpu/stream_texture_android.cc
@@ -12,7 +12,7 @@
#include "gpu/command_buffer/service/context_state.h"
#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
#include "gpu/command_buffer/service/texture_manager.h"
-#include "ui/gfx/size.h"
+#include "ui/gfx/geometry/size.h"
#include "ui/gl/scoped_make_current.h"
namespace content {
diff --git a/chromium/content/common/gpu/stream_texture_android.h b/chromium/content/common/gpu/stream_texture_android.h
index 066d4faa727..72e4ed4dee0 100644
--- a/chromium/content/common/gpu/stream_texture_android.h
+++ b/chromium/content/common/gpu/stream_texture_android.h
@@ -30,32 +30,32 @@ class StreamTexture : public gfx::GLImage,
StreamTexture(GpuCommandBufferStub* owner_stub,
int32 route_id,
uint32 texture_id);
- virtual ~StreamTexture();
+ ~StreamTexture() override;
// gfx::GLImage implementation:
- virtual void Destroy(bool have_context) override;
- virtual gfx::Size GetSize() override;
- virtual bool BindTexImage(unsigned target) override;
- virtual void ReleaseTexImage(unsigned target) override;
- virtual bool CopyTexImage(unsigned target) override;
- virtual void WillUseTexImage() override;
- virtual void DidUseTexImage() override {}
- virtual void WillModifyTexImage() override {}
- virtual void DidModifyTexImage() override {}
- virtual bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
- int z_order,
- gfx::OverlayTransform transform,
- const gfx::Rect& bounds_rect,
- const gfx::RectF& crop_rect) override;
+ void Destroy(bool have_context) override;
+ gfx::Size GetSize() override;
+ bool BindTexImage(unsigned target) override;
+ void ReleaseTexImage(unsigned target) override;
+ bool CopyTexImage(unsigned target) override;
+ void WillUseTexImage() override;
+ void DidUseTexImage() override {}
+ void WillModifyTexImage() override {}
+ void DidModifyTexImage() override {}
+ bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
+ int z_order,
+ gfx::OverlayTransform transform,
+ const gfx::Rect& bounds_rect,
+ const gfx::RectF& crop_rect) override;
// GpuCommandBufferStub::DestructionObserver implementation.
- virtual void OnWillDestroyStub() override;
+ void OnWillDestroyStub() override;
// Called when a new frame is available for the SurfaceTexture.
void OnFrameAvailable();
// IPC::Listener implementation:
- virtual bool OnMessageReceived(const IPC::Message& message) override;
+ bool OnMessageReceived(const IPC::Message& message) override;
// IPC message handlers:
void OnStartListening();
diff --git a/chromium/content/common/gpu/surface_handle_types_mac.cc b/chromium/content/common/gpu/surface_handle_types_mac.cc
deleted file mode 100644
index ef7254241da..00000000000
--- a/chromium/content/common/gpu/surface_handle_types_mac.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/common/gpu/surface_handle_types_mac.h"
-
-#include "base/logging.h"
-
-namespace content {
-namespace {
-
-// The type of the handle is stored in the upper 64 bits.
-const uint64 kTypeMask = 0xFFFFFFFFull << 32;
-
-const uint64 kTypeIOSurface = 0x01010101ull << 32;
-const uint64 kTypeCAContext = 0x02020202ull << 32;
-
-// To make it a bit less likely that we'll just cast off the top bits of the
-// handle to get the ID, XOR lower bits with a type-specific mask.
-const uint32 kXORMaskIOSurface = 0x01010101;
-const uint32 kXORMaskCAContext = 0x02020202;
-
-} // namespace
-
-SurfaceHandleType GetSurfaceHandleType(uint64 surface_handle) {
- switch(surface_handle & kTypeMask) {
- case kTypeIOSurface:
- return kSurfaceHandleTypeIOSurface;
- case kTypeCAContext:
- return kSurfaceHandleTypeCAContext;
- }
- return kSurfaceHandleTypeInvalid;
-}
-
-IOSurfaceID IOSurfaceIDFromSurfaceHandle(uint64 surface_handle) {
- DCHECK_EQ(kSurfaceHandleTypeIOSurface, GetSurfaceHandleType(surface_handle));
- return static_cast<uint32>(surface_handle) ^ kXORMaskIOSurface;
-}
-
-CAContextID CAContextIDFromSurfaceHandle(uint64 surface_handle) {
- DCHECK_EQ(kSurfaceHandleTypeCAContext, GetSurfaceHandleType(surface_handle));
- return static_cast<uint32>(surface_handle) ^ kXORMaskCAContext;
-}
-
-uint64 SurfaceHandleFromIOSurfaceID(IOSurfaceID io_surface_id) {
- return kTypeIOSurface | (io_surface_id ^ kXORMaskIOSurface);
-}
-
-uint64 SurfaceHandleFromCAContextID(CAContextID ca_context_id) {
- return kTypeCAContext | (ca_context_id ^ kXORMaskCAContext);
-}
-
-} // namespace content
diff --git a/chromium/content/common/gpu/surface_handle_types_mac.h b/chromium/content/common/gpu/surface_handle_types_mac.h
deleted file mode 100644
index 8432017377a..00000000000
--- a/chromium/content/common/gpu/surface_handle_types_mac.h
+++ /dev/null
@@ -1,35 +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_COMMON_GPU_SURFACE_HANDLE_TYPES_MAC_H_
-#define CONTENT_COMMON_GPU_SURFACE_HANDLE_TYPES_MAC_H_
-
-#include <IOSurface/IOSurface.h>
-#include <OpenGL/CGLIOSurface.h>
-
-#include "base/basictypes.h"
-#include "ui/base/cocoa/remote_layer_api.h"
-
-namespace content {
-
-// The surface handle passed between the GPU and browser process may refer to
-// an IOSurface or a CAContext. These helper functions must be used to identify
-// and translate between the types.
-enum SurfaceHandleType {
- kSurfaceHandleTypeInvalid,
- kSurfaceHandleTypeIOSurface,
- kSurfaceHandleTypeCAContext,
-};
-
-SurfaceHandleType GetSurfaceHandleType(uint64 surface_handle);
-
-CAContextID CAContextIDFromSurfaceHandle(uint64 surface_handle);
-IOSurfaceID IOSurfaceIDFromSurfaceHandle(uint64 surface_handle);
-
-uint64 SurfaceHandleFromIOSurfaceID(IOSurfaceID io_surface_id);
-uint64 SurfaceHandleFromCAContextID(CAContextID ca_context_id);
-
-} // namespace content
-
-#endif // CONTENT_COMMON_GPU_HANDLE_TYPES_MAC_H_
diff --git a/chromium/content/common/gpu/sync_point_manager.cc b/chromium/content/common/gpu/sync_point_manager.cc
deleted file mode 100644
index fd5fa6a02f0..00000000000
--- a/chromium/content/common/gpu/sync_point_manager.cc
+++ /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.
-
-#include "content/common/gpu/sync_point_manager.h"
-
-#include <climits>
-
-#include "base/logging.h"
-#include "base/rand_util.h"
-
-namespace content {
-
-static const int kMaxSyncBase = INT_MAX;
-
-SyncPointManager::SyncPointManager()
- : next_sync_point_(base::RandInt(1, kMaxSyncBase)) {
- // To reduce the risk that a sync point created in a previous GPU process
- // will be in flight in the next GPU process, randomize the starting sync
- // point number. http://crbug.com/373452
-}
-
-SyncPointManager::~SyncPointManager() {
-}
-
-uint32 SyncPointManager::GenerateSyncPoint() {
- base::AutoLock lock(lock_);
- uint32 sync_point = next_sync_point_++;
- // When an integer overflow occurs, don't return 0.
- if (!sync_point)
- sync_point = next_sync_point_++;
-
- // Note: wrapping would take days for a buggy/compromized renderer that would
- // insert sync points in a loop, but if that were to happen, better explicitly
- // crash the GPU process than risk worse.
- // For normal operation (at most a few per frame), it would take ~a year to
- // wrap.
- CHECK(sync_point_map_.find(sync_point) == sync_point_map_.end());
- sync_point_map_.insert(std::make_pair(sync_point, ClosureList()));
- return sync_point;
-}
-
-void SyncPointManager::RetireSyncPoint(uint32 sync_point) {
- DCHECK(thread_checker_.CalledOnValidThread());
- ClosureList list;
- {
- base::AutoLock lock(lock_);
- SyncPointMap::iterator it = sync_point_map_.find(sync_point);
- if (it == sync_point_map_.end()) {
- LOG(ERROR) << "Attempted to retire sync point that"
- " didn't exist or was already retired.";
- return;
- }
- list.swap(it->second);
- sync_point_map_.erase(it);
- }
- for (ClosureList::iterator i = list.begin(); i != list.end(); ++i)
- i->Run();
-}
-
-void SyncPointManager::AddSyncPointCallback(uint32 sync_point,
- const base::Closure& callback) {
- DCHECK(thread_checker_.CalledOnValidThread());
- {
- base::AutoLock lock(lock_);
- SyncPointMap::iterator it = sync_point_map_.find(sync_point);
- if (it != sync_point_map_.end()) {
- it->second.push_back(callback);
- return;
- }
- }
- callback.Run();
-}
-
-bool SyncPointManager::IsSyncPointRetired(uint32 sync_point) {
- DCHECK(thread_checker_.CalledOnValidThread());
- {
- base::AutoLock lock(lock_);
- SyncPointMap::iterator it = sync_point_map_.find(sync_point);
- return it == sync_point_map_.end();
- }
-}
-
-} // namespace content
diff --git a/chromium/content/common/gpu/sync_point_manager.h b/chromium/content/common/gpu/sync_point_manager.h
deleted file mode 100644
index 77a4e6d0b75..00000000000
--- a/chromium/content/common/gpu/sync_point_manager.h
+++ /dev/null
@@ -1,60 +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_COMMON_GPU_SYNC_POINT_MANAGER_H_
-#define CONTENT_COMMON_GPU_SYNC_POINT_MANAGER_H_
-
-#include <vector>
-
-#include "base/callback.h"
-#include "base/containers/hash_tables.h"
-#include "base/memory/ref_counted.h"
-#include "base/synchronization/lock.h"
-#include "base/threading/thread_checker.h"
-
-namespace content {
-
-// This class manages the sync points, which allow cross-channel
-// synchronization.
-class SyncPointManager : public base::RefCountedThreadSafe<SyncPointManager> {
- public:
- SyncPointManager();
-
- // Generates a sync point, returning its ID. This can me called on any thread.
- // IDs start at a random number. Never return 0.
- uint32 GenerateSyncPoint();
-
- // Retires a sync point. This will call all the registered callbacks for this
- // sync point. This can only be called on the main thread.
- void RetireSyncPoint(uint32 sync_point);
-
- // Adds a callback to the sync point. The callback will be called when the
- // sync point is retired, or immediately (from within that function) if the
- // sync point was already retired (or not created yet). This can only be
- // called on the main thread.
- void AddSyncPointCallback(uint32 sync_point, const base::Closure& callback);
-
- bool IsSyncPointRetired(uint32 sync_point);
-
- private:
- friend class base::RefCountedThreadSafe<SyncPointManager>;
- typedef std::vector<base::Closure> ClosureList;
- typedef base::hash_map<uint32, ClosureList > SyncPointMap;
-
- ~SyncPointManager();
-
- base::ThreadChecker thread_checker_;
-
- // Protects the 2 fields below. Note: callbacks shouldn't be called with this
- // held.
- base::Lock lock_;
- SyncPointMap sync_point_map_;
- uint32 next_sync_point_;
-
- DISALLOW_COPY_AND_ASSIGN(SyncPointManager);
-};
-
-} // namespace content
-
-#endif // CONTENT_COMMON_GPU_SYNC_POINT_MANAGER_H_
diff --git a/chromium/content/common/gpu/x_util.cc b/chromium/content/common/gpu/x_util.cc
deleted file mode 100644
index df14ceed246..00000000000
--- a/chromium/content/common/gpu/x_util.cc
+++ /dev/null
@@ -1,15 +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/common/gpu/x_util.h"
-
-#include <X11/Xutil.h>
-
-namespace content {
-
-void ScopedPtrXFree::operator()(void* x) const {
- ::XFree(x);
-}
-
-} // namespace content
diff --git a/chromium/content/common/gpu/x_util.h b/chromium/content/common/gpu/x_util.h
index c7591e26c61..99687566356 100644
--- a/chromium/content/common/gpu/x_util.h
+++ b/chromium/content/common/gpu/x_util.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 CHROME_GPU_X_UTIL_H_
-#define CHROME_GPU_X_UTIL_H_
+#ifndef CONTENT_COMMON_GPU_X_UTIL_H_
+#define CONTENT_COMMON_GPU_X_UTIL_H_
// Some X-Windows specific stuff. This can be included on any platform, and will
// be a NOP on non-Linux ones.
@@ -33,18 +33,8 @@ typedef struct __GLXcontextRec *GLXContext;
} // extern "C"
-// Utils -----------------------------------------------------------------------
-
-// scoped_ptr functor for XFree(). Use as follows:
-// scoped_ptr_mallox<XVisualInfo, ScopedPtrXFree> foo(...);
-// where "XVisualInfo" is any X type that is freed with XFree.
-class ScopedPtrXFree {
- public:
- void operator()(void* x) const;
-};
-
} // namespace content
#endif // USE_X11
-#endif // CHROME_GPU_X_UTIL_H_
+#endif // CONTENT_COMMON_GPU_X_UTIL_H_
diff --git a/chromium/content/common/handle_enumerator_win.cc b/chromium/content/common/handle_enumerator_win.cc
deleted file mode 100644
index 981655065d9..00000000000
--- a/chromium/content/common/handle_enumerator_win.cc
+++ /dev/null
@@ -1,322 +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/common/handle_enumerator_win.h"
-
-#include <windows.h>
-#include <map>
-
-#include "base/command_line.h"
-#include "base/logging.h"
-#include "base/process/process.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/win/windows_version.h"
-#include "content/public/common/content_switches.h"
-#include "content/public/common/result_codes.h"
-#include "sandbox/win/src/handle_table.h"
-
-using base::ASCIIToUTF16;
-
-namespace content {
-namespace {
-
-typedef std::map<const base::string16, HandleType> HandleTypeMap;
-
-HandleTypeMap& MakeHandleTypeMap() {
- HandleTypeMap& handle_types = *(new HandleTypeMap());
- handle_types[sandbox::HandleTable::kTypeProcess] = ProcessHandle;
- handle_types[sandbox::HandleTable::kTypeThread] = ThreadHandle;
- handle_types[sandbox::HandleTable::kTypeFile] = FileHandle;
- handle_types[sandbox::HandleTable::kTypeDirectory] = DirectoryHandle;
- handle_types[sandbox::HandleTable::kTypeKey] = KeyHandle;
- handle_types[sandbox::HandleTable::kTypeWindowStation] = WindowStationHandle;
- handle_types[sandbox::HandleTable::kTypeDesktop] = DesktopHandle;
- handle_types[sandbox::HandleTable::kTypeService] = ServiceHandle;
- handle_types[sandbox::HandleTable::kTypeMutex] = MutexHandle;
- handle_types[sandbox::HandleTable::kTypeSemaphore] = SemaphoreHandle;
- handle_types[sandbox::HandleTable::kTypeEvent] = EventHandle;
- handle_types[sandbox::HandleTable::kTypeTimer] = TimerHandle;
- handle_types[sandbox::HandleTable::kTypeNamedPipe] = NamedPipeHandle;
- handle_types[sandbox::HandleTable::kTypeJobObject] = JobHandle;
- handle_types[sandbox::HandleTable::kTypeFileMap] = FileMapHandle;
- handle_types[sandbox::HandleTable::kTypeAlpcPort] = AlpcPortHandle;
-
- return handle_types;
-}
-
-} // namespace
-
-const size_t kMaxHandleNameLength = 1024;
-
-void HandleEnumerator::EnumerateHandles() {
- sandbox::HandleTable handles;
- std::string process_type =
- base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kProcessType);
- base::string16 output = ASCIIToUTF16(process_type);
- output.append(ASCIIToUTF16(" process - Handles at shutdown:\n"));
- for (sandbox::HandleTable::Iterator sys_handle
- = handles.HandlesForProcess(::GetCurrentProcessId());
- sys_handle != handles.end(); ++sys_handle) {
- HandleType current_type = StringToHandleType(sys_handle->Type());
- if (!all_handles_ && (current_type != ProcessHandle &&
- current_type != FileHandle &&
- current_type != DirectoryHandle &&
- current_type != KeyHandle &&
- current_type != WindowStationHandle &&
- current_type != DesktopHandle &&
- current_type != ServiceHandle))
- continue;
-
- output += ASCIIToUTF16("[");
- output += sys_handle->Type();
- output += ASCIIToUTF16("] (");
- output += sys_handle->Name();
- output += ASCIIToUTF16(")\n");
- output += GetAccessString(current_type,
- sys_handle->handle_entry()->GrantedAccess);
- }
- DVLOG(0) << output;
-}
-
-HandleType StringToHandleType(const base::string16& type) {
- static HandleTypeMap handle_types = MakeHandleTypeMap();
- HandleTypeMap::iterator result = handle_types.find(type);
- return result != handle_types.end() ? result->second : OtherHandle;
-}
-
-base::string16 GetAccessString(HandleType handle_type,
- ACCESS_MASK access) {
- base::string16 output;
- if (access & GENERIC_READ)
- output.append(ASCIIToUTF16("\tGENERIC_READ\n"));
- if (access & GENERIC_WRITE)
- output.append(ASCIIToUTF16("\tGENERIC_WRITE\n"));
- if (access & GENERIC_EXECUTE)
- output.append(ASCIIToUTF16("\tGENERIC_EXECUTE\n"));
- if (access & GENERIC_ALL)
- output.append(ASCIIToUTF16("\tGENERIC_ALL\n"));
- if (access & DELETE)
- output.append(ASCIIToUTF16("\tDELETE\n"));
- if (access & READ_CONTROL)
- output.append(ASCIIToUTF16("\tREAD_CONTROL\n"));
- if (access & WRITE_DAC)
- output.append(ASCIIToUTF16("\tWRITE_DAC\n"));
- if (access & WRITE_OWNER)
- output.append(ASCIIToUTF16("\tWRITE_OWNER\n"));
- if (access & SYNCHRONIZE)
- output.append(ASCIIToUTF16("\tSYNCHRONIZE\n"));
-
- switch (handle_type) {
- case ProcessHandle:
- if (access & PROCESS_CREATE_PROCESS)
- output.append(ASCIIToUTF16("\tPROCESS_CREATE_PROCESS\n"));
- if (access & PROCESS_CREATE_THREAD)
- output.append(ASCIIToUTF16("\tPROCESS_CREATE_THREAD\n"));
- if (access & PROCESS_DUP_HANDLE)
- output.append(ASCIIToUTF16("\tPROCESS_DUP_HANDLE\n"));
- if (access & PROCESS_QUERY_INFORMATION)
- output.append(ASCIIToUTF16("\tPROCESS_QUERY_INFORMATION\n"));
- if (access & PROCESS_QUERY_LIMITED_INFORMATION)
- output.append(ASCIIToUTF16("\tPROCESS_QUERY_LIMITED_INFORMATION\n"));
- if (access & PROCESS_SET_INFORMATION)
- output.append(ASCIIToUTF16("\tPROCESS_SET_INFORMATION\n"));
- if (access & PROCESS_SET_QUOTA)
- output.append(ASCIIToUTF16("\tPROCESS_SET_QUOTA\n"));
- if (access & PROCESS_SUSPEND_RESUME)
- output.append(ASCIIToUTF16("\tPROCESS_SUSPEND_RESUME\n"));
- if (access & PROCESS_TERMINATE)
- output.append(ASCIIToUTF16("\tPROCESS_TERMINATE\n"));
- if (access & PROCESS_VM_OPERATION)
- output.append(ASCIIToUTF16("\tPROCESS_VM_OPERATION\n"));
- if (access & PROCESS_VM_READ)
- output.append(ASCIIToUTF16("\tPROCESS_VM_READ\n"));
- if (access & PROCESS_VM_WRITE)
- output.append(ASCIIToUTF16("\tPROCESS_VM_WRITE\n"));
- break;
- case ThreadHandle:
- if (access & THREAD_DIRECT_IMPERSONATION)
- output.append(ASCIIToUTF16("\tTHREAD_DIRECT_IMPERSONATION\n"));
- if (access & THREAD_GET_CONTEXT)
- output.append(ASCIIToUTF16("\tTHREAD_GET_CONTEXT\n"));
- if (access & THREAD_IMPERSONATE)
- output.append(ASCIIToUTF16("\tTHREAD_IMPERSONATE\n"));
- if (access & THREAD_QUERY_INFORMATION )
- output.append(ASCIIToUTF16("\tTHREAD_QUERY_INFORMATION\n"));
- if (access & THREAD_QUERY_LIMITED_INFORMATION)
- output.append(ASCIIToUTF16("\tTHREAD_QUERY_LIMITED_INFORMATION\n"));
- if (access & THREAD_SET_CONTEXT)
- output.append(ASCIIToUTF16("\tTHREAD_SET_CONTEXT\n"));
- if (access & THREAD_SET_INFORMATION)
- output.append(ASCIIToUTF16("\tTHREAD_SET_INFORMATION\n"));
- if (access & THREAD_SET_LIMITED_INFORMATION)
- output.append(ASCIIToUTF16("\tTHREAD_SET_LIMITED_INFORMATION\n"));
- if (access & THREAD_SET_THREAD_TOKEN)
- output.append(ASCIIToUTF16("\tTHREAD_SET_THREAD_TOKEN\n"));
- if (access & THREAD_SUSPEND_RESUME)
- output.append(ASCIIToUTF16("\tTHREAD_SUSPEND_RESUME\n"));
- if (access & THREAD_TERMINATE)
- output.append(ASCIIToUTF16("\tTHREAD_TERMINATE\n"));
- break;
- case FileHandle:
- if (access & FILE_APPEND_DATA)
- output.append(ASCIIToUTF16("\tFILE_APPEND_DATA\n"));
- if (access & FILE_EXECUTE)
- output.append(ASCIIToUTF16("\tFILE_EXECUTE\n"));
- if (access & FILE_READ_ATTRIBUTES)
- output.append(ASCIIToUTF16("\tFILE_READ_ATTRIBUTES\n"));
- if (access & FILE_READ_DATA)
- output.append(ASCIIToUTF16("\tFILE_READ_DATA\n"));
- if (access & FILE_READ_EA)
- output.append(ASCIIToUTF16("\tFILE_READ_EA\n"));
- if (access & FILE_WRITE_ATTRIBUTES)
- output.append(ASCIIToUTF16("\tFILE_WRITE_ATTRIBUTES\n"));
- if (access & FILE_WRITE_DATA)
- output.append(ASCIIToUTF16("\tFILE_WRITE_DATA\n"));
- if (access & FILE_WRITE_EA)
- output.append(ASCIIToUTF16("\tFILE_WRITE_EA\n"));
- break;
- case DirectoryHandle:
- if (access & FILE_ADD_FILE)
- output.append(ASCIIToUTF16("\tFILE_ADD_FILE\n"));
- if (access & FILE_ADD_SUBDIRECTORY)
- output.append(ASCIIToUTF16("\tFILE_ADD_SUBDIRECTORY\n"));
- if (access & FILE_APPEND_DATA)
- output.append(ASCIIToUTF16("\tFILE_APPEND_DATA\n"));
- if (access & FILE_DELETE_CHILD)
- output.append(ASCIIToUTF16("\tFILE_DELETE_CHILD\n"));
- if (access & FILE_LIST_DIRECTORY)
- output.append(ASCIIToUTF16("\tFILE_LIST_DIRECTORY\n"));
- if (access & FILE_READ_DATA)
- output.append(ASCIIToUTF16("\tFILE_READ_DATA\n"));
- if (access & FILE_TRAVERSE)
- output.append(ASCIIToUTF16("\tFILE_TRAVERSE\n"));
- if (access & FILE_WRITE_DATA)
- output.append(ASCIIToUTF16("\tFILE_WRITE_DATA\n"));
- break;
- case KeyHandle:
- if (access & KEY_CREATE_LINK)
- output.append(ASCIIToUTF16("\tKEY_CREATE_LINK\n"));
- if (access & KEY_CREATE_SUB_KEY)
- output.append(ASCIIToUTF16("\tKEY_CREATE_SUB_KEY\n"));
- if (access & KEY_ENUMERATE_SUB_KEYS)
- output.append(ASCIIToUTF16("\tKEY_ENUMERATE_SUB_KEYS\n"));
- if (access & KEY_EXECUTE)
- output.append(ASCIIToUTF16("\tKEY_EXECUTE\n"));
- if (access & KEY_NOTIFY)
- output.append(ASCIIToUTF16("\tKEY_NOTIFY\n"));
- if (access & KEY_QUERY_VALUE)
- output.append(ASCIIToUTF16("\tKEY_QUERY_VALUE\n"));
- if (access & KEY_READ)
- output.append(ASCIIToUTF16("\tKEY_READ\n"));
- if (access & KEY_SET_VALUE)
- output.append(ASCIIToUTF16("\tKEY_SET_VALUE\n"));
- if (access & KEY_WOW64_32KEY)
- output.append(ASCIIToUTF16("\tKEY_WOW64_32KEY\n"));
- if (access & KEY_WOW64_64KEY)
- output.append(ASCIIToUTF16("\tKEY_WOW64_64KEY\n"));
- break;
- case WindowStationHandle:
- if (access & WINSTA_ACCESSCLIPBOARD)
- output.append(ASCIIToUTF16("\tWINSTA_ACCESSCLIPBOARD\n"));
- if (access & WINSTA_ACCESSGLOBALATOMS)
- output.append(ASCIIToUTF16("\tWINSTA_ACCESSGLOBALATOMS\n"));
- if (access & WINSTA_CREATEDESKTOP)
- output.append(ASCIIToUTF16("\tWINSTA_CREATEDESKTOP\n"));
- if (access & WINSTA_ENUMDESKTOPS)
- output.append(ASCIIToUTF16("\tWINSTA_ENUMDESKTOPS\n"));
- if (access & WINSTA_ENUMERATE)
- output.append(ASCIIToUTF16("\tWINSTA_ENUMERATE\n"));
- if (access & WINSTA_EXITWINDOWS)
- output.append(ASCIIToUTF16("\tWINSTA_EXITWINDOWS\n"));
- if (access & WINSTA_READATTRIBUTES)
- output.append(ASCIIToUTF16("\tWINSTA_READATTRIBUTES\n"));
- if (access & WINSTA_READSCREEN)
- output.append(ASCIIToUTF16("\tWINSTA_READSCREEN\n"));
- if (access & WINSTA_WRITEATTRIBUTES)
- output.append(ASCIIToUTF16("\tWINSTA_WRITEATTRIBUTES\n"));
- break;
- case DesktopHandle:
- if (access & DESKTOP_CREATEMENU)
- output.append(ASCIIToUTF16("\tDESKTOP_CREATEMENU\n"));
- if (access & DESKTOP_CREATEWINDOW)
- output.append(ASCIIToUTF16("\tDESKTOP_CREATEWINDOW\n"));
- if (access & DESKTOP_ENUMERATE)
- output.append(ASCIIToUTF16("\tDESKTOP_ENUMERATE\n"));
- if (access & DESKTOP_HOOKCONTROL)
- output.append(ASCIIToUTF16("\tDESKTOP_HOOKCONTROL\n"));
- if (access & DESKTOP_JOURNALPLAYBACK)
- output.append(ASCIIToUTF16("\tDESKTOP_JOURNALPLAYBACK\n"));
- if (access & DESKTOP_JOURNALRECORD)
- output.append(ASCIIToUTF16("\tDESKTOP_JOURNALRECORD\n"));
- if (access & DESKTOP_READOBJECTS)
- output.append(ASCIIToUTF16("\tDESKTOP_READOBJECTS\n"));
- if (access & DESKTOP_SWITCHDESKTOP)
- output.append(ASCIIToUTF16("\tDESKTOP_SWITCHDESKTOP\n"));
- if (access & DESKTOP_WRITEOBJECTS)
- output.append(ASCIIToUTF16("\tDESKTOP_WRITEOBJECTS\n"));
- break;
- case ServiceHandle:
- if (access & SC_MANAGER_CREATE_SERVICE)
- output.append(ASCIIToUTF16("\tSC_MANAGER_CREATE_SERVICE\n"));
- if (access & SC_MANAGER_CONNECT)
- output.append(ASCIIToUTF16("\tSC_MANAGER_CONNECT\n"));
- if (access & SC_MANAGER_ENUMERATE_SERVICE )
- output.append(ASCIIToUTF16("\tSC_MANAGER_ENUMERATE_SERVICE\n"));
- if (access & SC_MANAGER_LOCK)
- output.append(ASCIIToUTF16("\tSC_MANAGER_LOCK\n"));
- if (access & SC_MANAGER_MODIFY_BOOT_CONFIG )
- output.append(ASCIIToUTF16("\tSC_MANAGER_MODIFY_BOOT_CONFIG\n"));
- if (access & SC_MANAGER_QUERY_LOCK_STATUS )
- output.append(ASCIIToUTF16("\tSC_MANAGER_QUERY_LOCK_STATUS\n"));
- break;
- case EventHandle:
- if (access & EVENT_MODIFY_STATE)
- output.append(ASCIIToUTF16("\tEVENT_MODIFY_STATE\n"));
- break;
- case MutexHandle:
- if (access & MUTEX_MODIFY_STATE)
- output.append(ASCIIToUTF16("\tMUTEX_MODIFY_STATE\n"));
- break;
- case SemaphoreHandle:
- if (access & SEMAPHORE_MODIFY_STATE)
- output.append(ASCIIToUTF16("\tSEMAPHORE_MODIFY_STATE\n"));
- break;
- case TimerHandle:
- if (access & TIMER_MODIFY_STATE)
- output.append(ASCIIToUTF16("\tTIMER_MODIFY_STATE\n"));
- if (access & TIMER_QUERY_STATE)
- output.append(ASCIIToUTF16("\tTIMER_QUERY_STATE\n"));
- break;
- case NamedPipeHandle:
- if (access & PIPE_ACCESS_INBOUND)
- output.append(ASCIIToUTF16("\tPIPE_ACCESS_INBOUND\n"));
- if (access & PIPE_ACCESS_OUTBOUND)
- output.append(ASCIIToUTF16("\tPIPE_ACCESS_OUTBOUND\n"));
- break;
- case JobHandle:
- if (access & JOB_OBJECT_ASSIGN_PROCESS)
- output.append(ASCIIToUTF16("\tJOB_OBJECT_ASSIGN_PROCESS\n"));
- if (access & JOB_OBJECT_QUERY)
- output.append(ASCIIToUTF16("\tJOB_OBJECT_QUERY\n"));
- if (access & JOB_OBJECT_SET_ATTRIBUTES)
- output.append(ASCIIToUTF16("\tJOB_OBJECT_SET_ATTRIBUTES\n"));
- if (access & JOB_OBJECT_SET_SECURITY_ATTRIBUTES)
- output.append(ASCIIToUTF16("\tJOB_OBJECT_SET_SECURITY_ATTRIBUTES\n"));
- if (access & JOB_OBJECT_TERMINATE)
- output.append(ASCIIToUTF16("\tJOB_OBJECT_TERMINATE\n"));
- break;
- case FileMapHandle:
- if (access & FILE_MAP_EXECUTE)
- output.append(ASCIIToUTF16("\tFILE_MAP_EXECUTE\n"));
- if (access & FILE_MAP_READ)
- output.append(ASCIIToUTF16("\tFILE_MAP_READ\n"));
- if (access & FILE_MAP_WRITE)
- output.append(ASCIIToUTF16("\tFILE_MAP_WRITE\n"));
- break;
- }
- return output;
-}
-
-} // namespace content
diff --git a/chromium/content/common/handle_enumerator_win.h b/chromium/content/common/handle_enumerator_win.h
deleted file mode 100644
index 3caba84971e..00000000000
--- a/chromium/content/common/handle_enumerator_win.h
+++ /dev/null
@@ -1,55 +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_COMMON_HANDLE_ENUMERATOR_WIN_H_
-#define CONTENT_COMMON_HANDLE_ENUMERATOR_WIN_H_
-
-#include "base/memory/ref_counted.h"
-#include "base/process/process.h"
-#include "base/strings/string16.h"
-
-namespace content {
-
-enum HandleType {
- ProcessHandle,
- ThreadHandle,
- FileHandle,
- DirectoryHandle,
- KeyHandle,
- WindowStationHandle,
- DesktopHandle,
- ServiceHandle,
- EventHandle,
- MutexHandle,
- SemaphoreHandle,
- TimerHandle,
- NamedPipeHandle,
- JobHandle,
- FileMapHandle,
- AlpcPortHandle,
- OtherHandle
-};
-
-static HandleType StringToHandleType(const base::string16& type);
-
-static base::string16 GetAccessString(HandleType handle_type,
- ACCESS_MASK access);
-
-class HandleEnumerator : public base::RefCountedThreadSafe<HandleEnumerator> {
- public:
- explicit HandleEnumerator(bool all_handles):
- all_handles_(all_handles) { }
-
- void EnumerateHandles();
-
- private:
- bool all_handles_;
-
- DISALLOW_COPY_AND_ASSIGN(HandleEnumerator);
-};
-
-} // namespace content
-
-#endif // CONTENT_COMMON_HANDLE_ENUMERATOR_WIN_H_
-
diff --git a/chromium/content/common/host_discardable_shared_memory_manager.cc b/chromium/content/common/host_discardable_shared_memory_manager.cc
index c56fd113f59..a209cc0cc56 100644
--- a/chromium/content/common/host_discardable_shared_memory_manager.cc
+++ b/chromium/content/common/host_discardable_shared_memory_manager.cc
@@ -6,42 +6,106 @@
#include <algorithm>
+#include "base/atomic_sequence_num.h"
+#include "base/bind.h"
#include "base/callback.h"
#include "base/debug/crash_logging.h"
-#include "base/debug/trace_event.h"
#include "base/lazy_instance.h"
+#include "base/memory/discardable_memory.h"
#include "base/numerics/safe_math.h"
#include "base/strings/string_number_conversions.h"
+#include "base/sys_info.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/trace_event/trace_event.h"
namespace content {
namespace {
+class DiscardableMemoryImpl : public base::DiscardableMemory {
+ public:
+ DiscardableMemoryImpl(scoped_ptr<base::DiscardableSharedMemory> shared_memory,
+ const base::Closure& deleted_callback)
+ : shared_memory_(shared_memory.Pass()),
+ deleted_callback_(deleted_callback),
+ is_locked_(true) {}
+
+ ~DiscardableMemoryImpl() override {
+ if (is_locked_)
+ shared_memory_->Unlock(0, 0);
+
+ deleted_callback_.Run();
+ }
+
+ // Overridden from base::DiscardableMemory:
+ bool Lock() override {
+ DCHECK(!is_locked_);
+
+ if (shared_memory_->Lock(0, 0) != base::DiscardableSharedMemory::SUCCESS)
+ return false;
+
+ is_locked_ = true;
+ return true;
+ }
+ void Unlock() override {
+ DCHECK(is_locked_);
+
+ shared_memory_->Unlock(0, 0);
+ is_locked_ = false;
+ }
+ void* data() const override {
+ DCHECK(is_locked_);
+ return shared_memory_->memory();
+ }
+
+ private:
+ scoped_ptr<base::DiscardableSharedMemory> shared_memory_;
+ const base::Closure deleted_callback_;
+ bool is_locked_;
+
+ DISALLOW_COPY_AND_ASSIGN(DiscardableMemoryImpl);
+};
+
base::LazyInstance<HostDiscardableSharedMemoryManager>
g_discardable_shared_memory_manager = LAZY_INSTANCE_INITIALIZER;
-const size_t kDefaultMemoryLimit = 512 * 1024 * 1024;
+#if defined(OS_ANDROID)
+// Limits the number of FDs used to 32, assuming a 4MB allocation size.
+const int64_t kMaxDefaultMemoryLimit = 128 * 1024 * 1024;
+#else
+const int64_t kMaxDefaultMemoryLimit = 512 * 1024 * 1024;
+#endif
const int kEnforceMemoryPolicyDelayMs = 1000;
+// Global atomic to generate unique discardable shared memory IDs.
+base::StaticAtomicSequenceNumber g_next_discardable_shared_memory_id;
+
} // namespace
HostDiscardableSharedMemoryManager::MemorySegment::MemorySegment(
- linked_ptr<base::DiscardableSharedMemory> memory,
- base::ProcessHandle process_handle)
- : memory(memory), process_handle(process_handle) {
+ scoped_ptr<base::DiscardableSharedMemory> memory)
+ : memory_(memory.Pass()) {
}
HostDiscardableSharedMemoryManager::MemorySegment::~MemorySegment() {
}
HostDiscardableSharedMemoryManager::HostDiscardableSharedMemoryManager()
- : memory_limit_(kDefaultMemoryLimit),
+ : memory_limit_(
+ // Allow 25% of physical memory to be used for discardable memory.
+ std::min(base::SysInfo::AmountOfPhysicalMemory() / 4,
+ base::SysInfo::IsLowEndDevice()
+ ?
+ // Use 1/8th of discardable memory on low-end devices.
+ kMaxDefaultMemoryLimit / 8
+ : kMaxDefaultMemoryLimit)),
bytes_allocated_(0),
memory_pressure_listener_(new base::MemoryPressureListener(
base::Bind(&HostDiscardableSharedMemoryManager::OnMemoryPressure,
base::Unretained(this)))),
enforce_memory_policy_pending_(false),
weak_ptr_factory_(this) {
+ DCHECK_NE(memory_limit_, 0u);
}
HostDiscardableSharedMemoryManager::~HostDiscardableSharedMemoryManager() {
@@ -52,22 +116,101 @@ HostDiscardableSharedMemoryManager::current() {
return g_discardable_shared_memory_manager.Pointer();
}
-scoped_ptr<base::DiscardableSharedMemory>
-HostDiscardableSharedMemoryManager::AllocateLockedDiscardableSharedMemory(
+scoped_ptr<base::DiscardableMemory>
+HostDiscardableSharedMemoryManager::AllocateLockedDiscardableMemory(
size_t size) {
- // TODO(reveman): Need to implement this for discardable memory support in
- // the browser process.
- NOTIMPLEMENTED();
- return scoped_ptr<base::DiscardableSharedMemory>();
+ DiscardableSharedMemoryId new_id =
+ g_next_discardable_shared_memory_id.GetNext();
+ base::ProcessHandle current_process_handle = base::GetCurrentProcessHandle();
+
+ // Note: Use DiscardableSharedMemoryHeap for in-process allocation
+ // of discardable memory if the cost of each allocation is too high.
+ base::SharedMemoryHandle handle;
+ AllocateLockedDiscardableSharedMemory(current_process_handle, size, new_id,
+ &handle);
+ CHECK(base::SharedMemory::IsHandleValid(handle));
+ scoped_ptr<base::DiscardableSharedMemory> memory(
+ new base::DiscardableSharedMemory(handle));
+ CHECK(memory->Map(size));
+ // Close file descriptor to avoid running out.
+ memory->Close();
+ return make_scoped_ptr(new DiscardableMemoryImpl(
+ memory.Pass(),
+ base::Bind(
+ &HostDiscardableSharedMemoryManager::DeletedDiscardableSharedMemory,
+ base::Unretained(this), new_id, current_process_handle)));
}
void HostDiscardableSharedMemoryManager::
AllocateLockedDiscardableSharedMemoryForChild(
base::ProcessHandle process_handle,
size_t size,
+ DiscardableSharedMemoryId id,
base::SharedMemoryHandle* shared_memory_handle) {
+ AllocateLockedDiscardableSharedMemory(process_handle, size, id,
+ shared_memory_handle);
+}
+
+void HostDiscardableSharedMemoryManager::ChildDeletedDiscardableSharedMemory(
+ DiscardableSharedMemoryId id,
+ base::ProcessHandle process_handle) {
+ DeletedDiscardableSharedMemory(id, process_handle);
+}
+
+void HostDiscardableSharedMemoryManager::ProcessRemoved(
+ base::ProcessHandle process_handle) {
base::AutoLock lock(lock_);
+ ProcessMap::iterator process_it = processes_.find(process_handle);
+ if (process_it == processes_.end())
+ return;
+
+ size_t bytes_allocated_before_releasing_memory = bytes_allocated_;
+
+ for (auto& segment_it : process_it->second)
+ ReleaseMemory(segment_it.second->memory());
+
+ processes_.erase(process_it);
+
+ if (bytes_allocated_ != bytes_allocated_before_releasing_memory)
+ BytesAllocatedChanged(bytes_allocated_);
+}
+
+void HostDiscardableSharedMemoryManager::SetMemoryLimit(size_t limit) {
+ base::AutoLock lock(lock_);
+
+ memory_limit_ = limit;
+ ReduceMemoryUsageUntilWithinMemoryLimit();
+}
+
+void HostDiscardableSharedMemoryManager::EnforceMemoryPolicy() {
+ base::AutoLock lock(lock_);
+
+ enforce_memory_policy_pending_ = false;
+ ReduceMemoryUsageUntilWithinMemoryLimit();
+}
+
+size_t HostDiscardableSharedMemoryManager::GetBytesAllocated() {
+ base::AutoLock lock(lock_);
+
+ return bytes_allocated_;
+}
+
+void HostDiscardableSharedMemoryManager::AllocateLockedDiscardableSharedMemory(
+ base::ProcessHandle process_handle,
+ size_t size,
+ DiscardableSharedMemoryId id,
+ base::SharedMemoryHandle* shared_memory_handle) {
+ base::AutoLock lock(lock_);
+
+ // Make sure |id| is not already in use.
+ MemorySegmentMap& process_segments = processes_[process_handle];
+ if (process_segments.find(id) != process_segments.end()) {
+ LOG(ERROR) << "Invalid discardable shared memory ID";
+ *shared_memory_handle = base::SharedMemory::NULLHandle();
+ return;
+ }
+
// Memory usage must be reduced to prevent the addition of |size| from
// taking usage above the limit. Usage should be reduced to 0 in cases
// where |size| is greater than the limit.
@@ -82,7 +225,7 @@ void HostDiscardableSharedMemoryManager::
if (bytes_allocated_ > limit)
ReduceMemoryUsageUntilWithinLimit(limit);
- linked_ptr<base::DiscardableSharedMemory> memory(
+ scoped_ptr<base::DiscardableSharedMemory> memory(
new base::DiscardableSharedMemory);
if (!memory->CreateAndMap(size)) {
*shared_memory_handle = base::SharedMemory::NULLHandle();
@@ -105,52 +248,41 @@ void HostDiscardableSharedMemoryManager::
bytes_allocated_ = checked_bytes_allocated.ValueOrDie();
BytesAllocatedChanged(bytes_allocated_);
- segments_.push_back(MemorySegment(memory, process_handle));
+#if !defined(DISCARDABLE_SHARED_MEMORY_SHRINKING)
+ // Close file descriptor to avoid running out.
+ memory->Close();
+#endif
+
+ scoped_refptr<MemorySegment> segment(new MemorySegment(memory.Pass()));
+ process_segments[id] = segment.get();
+ segments_.push_back(segment.get());
std::push_heap(segments_.begin(), segments_.end(), CompareMemoryUsageTime);
if (bytes_allocated_ > memory_limit_)
ScheduleEnforceMemoryPolicy();
}
-void HostDiscardableSharedMemoryManager::ProcessRemoved(
+void HostDiscardableSharedMemoryManager::DeletedDiscardableSharedMemory(
+ DiscardableSharedMemoryId id,
base::ProcessHandle process_handle) {
base::AutoLock lock(lock_);
- size_t bytes_allocated_before_purging = bytes_allocated_;
- for (auto& segment : segments_) {
- // Skip segments that belong to a different process.
- if (segment.process_handle != process_handle)
- continue;
+ MemorySegmentMap& process_segments = processes_[process_handle];
- size_t size = segment.memory->mapped_size();
- DCHECK_GE(bytes_allocated_, size);
-
- // This will unmap the memory segment and drop our reference. The result
- // is that the memory will be released to the OS if the child process is
- // no longer referencing it.
- // Note: We intentionally leave the segment in the vector to avoid
- // reconstructing the heap. The element will be removed from the heap
- // when its last usage time is older than all other segments.
- segment.memory->Close();
- bytes_allocated_ -= size;
+ MemorySegmentMap::iterator segment_it = process_segments.find(id);
+ if (segment_it == process_segments.end()) {
+ LOG(ERROR) << "Invalid discardable shared memory ID";
+ return;
}
- if (bytes_allocated_ != bytes_allocated_before_purging)
- BytesAllocatedChanged(bytes_allocated_);
-}
-
-void HostDiscardableSharedMemoryManager::SetMemoryLimit(size_t limit) {
- base::AutoLock lock(lock_);
+ size_t bytes_allocated_before_releasing_memory = bytes_allocated_;
- memory_limit_ = limit;
- ReduceMemoryUsageUntilWithinMemoryLimit();
-}
+ ReleaseMemory(segment_it->second->memory());
-void HostDiscardableSharedMemoryManager::EnforceMemoryPolicy() {
- base::AutoLock lock(lock_);
+ process_segments.erase(segment_it);
- enforce_memory_policy_pending_ = false;
- ReduceMemoryUsageUntilWithinMemoryLimit();
+ if (bytes_allocated_ != bytes_allocated_before_releasing_memory)
+ BytesAllocatedChanged(bytes_allocated_);
}
void HostDiscardableSharedMemoryManager::OnMemoryPressure(
@@ -158,7 +290,11 @@ void HostDiscardableSharedMemoryManager::OnMemoryPressure(
base::AutoLock lock(lock_);
switch (memory_pressure_level) {
+ case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
+ break;
case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
+ // Purge memory until usage is within half of |memory_limit_|.
+ ReduceMemoryUsageUntilWithinLimit(memory_limit_ / 2);
break;
case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
// Purge everything possible when pressure is critical.
@@ -169,6 +305,8 @@ void HostDiscardableSharedMemoryManager::OnMemoryPressure(
void
HostDiscardableSharedMemoryManager::ReduceMemoryUsageUntilWithinMemoryLimit() {
+ lock_.AssertAcquired();
+
if (bytes_allocated_ <= memory_limit_)
return;
@@ -197,28 +335,31 @@ void HostDiscardableSharedMemoryManager::ReduceMemoryUsageUntilWithinLimit(
break;
// Stop eviction attempts when the LRU segment is currently in use.
- if (segments_.front().memory->last_known_usage() >= current_time)
+ if (segments_.front()->memory()->last_known_usage() >= current_time)
break;
std::pop_heap(segments_.begin(), segments_.end(), CompareMemoryUsageTime);
- MemorySegment segment = segments_.back();
+ scoped_refptr<MemorySegment> segment = segments_.back();
segments_.pop_back();
- // Attempt to purge and truncate LRU segment. When successful, as much
- // memory as possible will be released to the OS. How much memory is
- // released depends on the platform. The child process should perform
- // periodic cleanup to ensure that all memory is release within a
- // reasonable amount of time.
- if (segment.memory->PurgeAndTruncate(current_time)) {
- size_t size = segment.memory->mapped_size();
+ // Attempt to purge LRU segment. When successful, released the memory.
+ if (segment->memory()->Purge(current_time)) {
+#if defined(DISCARDABLE_SHARED_MEMORY_SHRINKING)
+ size_t size = segment->memory()->mapped_size();
DCHECK_GE(bytes_allocated_, size);
bytes_allocated_ -= size;
+ // Shrink memory segment. This will immediately release the memory to
+ // the OS.
+ segment->memory()->Shrink();
+ DCHECK_EQ(segment->memory()->mapped_size(), 0u);
+#endif
+ ReleaseMemory(segment->memory());
continue;
}
// Add memory segment (with updated usage timestamp) back on heap after
// failed attempt to purge it.
- segments_.push_back(segment);
+ segments_.push_back(segment.get());
std::push_heap(segments_.begin(), segments_.end(), CompareMemoryUsageTime);
}
@@ -226,13 +367,32 @@ void HostDiscardableSharedMemoryManager::ReduceMemoryUsageUntilWithinLimit(
BytesAllocatedChanged(bytes_allocated_);
}
+void HostDiscardableSharedMemoryManager::ReleaseMemory(
+ base::DiscardableSharedMemory* memory) {
+ lock_.AssertAcquired();
+
+ size_t size = memory->mapped_size();
+ DCHECK_GE(bytes_allocated_, size);
+ bytes_allocated_ -= size;
+
+ // This will unmap the memory segment and drop our reference. The result
+ // is that the memory will be released to the OS if the child process is
+ // no longer referencing it.
+ // Note: We intentionally leave the segment in the |segments| vector to
+ // avoid reconstructing the heap. The element will be removed from the heap
+ // when its last usage time is older than all other segments.
+ memory->Unmap();
+ memory->Close();
+}
+
void HostDiscardableSharedMemoryManager::BytesAllocatedChanged(
size_t new_bytes_allocated) const {
- TRACE_COUNTER_ID1(
- "base", "TotalDiscardableMemoryUsage", this, new_bytes_allocated);
+ TRACE_COUNTER1("renderer_host", "TotalDiscardableMemoryUsage",
+ new_bytes_allocated);
- static const char kTotalDiscardableMemoryUsageKey[] = "total-dm-usage";
- base::debug::SetCrashKeyValue(kTotalDiscardableMemoryUsageKey,
+ static const char kTotalDiscardableMemoryAllocatedKey[] =
+ "total-discardable-memory-allocated";
+ base::debug::SetCrashKeyValue(kTotalDiscardableMemoryAllocatedKey,
base::Uint64ToString(new_bytes_allocated));
}
@@ -241,11 +401,13 @@ base::Time HostDiscardableSharedMemoryManager::Now() const {
}
void HostDiscardableSharedMemoryManager::ScheduleEnforceMemoryPolicy() {
+ lock_.AssertAcquired();
+
if (enforce_memory_policy_pending_)
return;
enforce_memory_policy_pending_ = true;
- base::MessageLoop::current()->PostDelayedTask(
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::Bind(&HostDiscardableSharedMemoryManager::EnforceMemoryPolicy,
weak_ptr_factory_.GetWeakPtr()),
diff --git a/chromium/content/common/host_discardable_shared_memory_manager.h b/chromium/content/common/host_discardable_shared_memory_manager.h
index 148c4fc3f80..f68ed937cb5 100644
--- a/chromium/content/common/host_discardable_shared_memory_manager.h
+++ b/chromium/content/common/host_discardable_shared_memory_manager.h
@@ -7,10 +7,11 @@
#include <vector>
-#include "base/memory/discardable_memory_shmem_allocator.h"
+#include "base/containers/hash_tables.h"
+#include "base/memory/discardable_memory_allocator.h"
#include "base/memory/discardable_shared_memory.h"
-#include "base/memory/linked_ptr.h"
#include "base/memory/memory_pressure_listener.h"
+#include "base/memory/ref_counted.h"
#include "base/memory/shared_memory.h"
#include "base/memory/weak_ptr.h"
#include "base/process/process_handle.h"
@@ -18,13 +19,13 @@
#include "content/common/content_export.h"
namespace content {
+typedef int32_t DiscardableSharedMemoryId;
-// Implementation of DiscardableMemoryShmemAllocator that allocates and
-// manages discardable memory segments for the browser process and child
-// processes. This class is thread-safe and instances can safely be used
-// on any thread.
+// Implementation of DiscardableMemoryAllocator that allocates and manages
+// discardable memory segments for the browser process and child processes.
+// This class is thread-safe and instances can safely be used on any thread.
class CONTENT_EXPORT HostDiscardableSharedMemoryManager
- : public base::DiscardableMemoryShmemAllocator {
+ : public base::DiscardableMemoryAllocator {
public:
HostDiscardableSharedMemoryManager();
~HostDiscardableSharedMemoryManager() override;
@@ -32,18 +33,24 @@ class CONTENT_EXPORT HostDiscardableSharedMemoryManager
// Returns a singleton instance.
static HostDiscardableSharedMemoryManager* current();
- // Overridden from base::DiscardableMemoryShmemAllocator:
- scoped_ptr<base::DiscardableSharedMemory>
- AllocateLockedDiscardableSharedMemory(size_t size) override;
+ // Overridden from base::DiscardableMemoryAllocator:
+ scoped_ptr<base::DiscardableMemory> AllocateLockedDiscardableMemory(
+ size_t size) override;
// This allocates a discardable memory segment for |process_handle|.
// A valid shared memory handle is returned on success.
void AllocateLockedDiscardableSharedMemoryForChild(
base::ProcessHandle process_handle,
size_t size,
+ DiscardableSharedMemoryId id,
base::SharedMemoryHandle* shared_memory_handle);
// Call this to notify the manager that child process associated with
+ // |process_handle| has deleted discardable memory segment with |id|.
+ void ChildDeletedDiscardableSharedMemory(DiscardableSharedMemoryId id,
+ base::ProcessHandle process_handle);
+
+ // Call this to notify the manager that child process associated with
// |process_handle| has been removed. The manager will use this to release
// memory segments allocated for child process to the OS.
void ProcessRemoved(base::ProcessHandle process_handle);
@@ -55,26 +62,44 @@ class CONTENT_EXPORT HostDiscardableSharedMemoryManager
// Reduce memory usage if above current memory limit.
void EnforceMemoryPolicy();
+ // Returns bytes of allocated discardable memory.
+ size_t GetBytesAllocated();
+
private:
- struct MemorySegment {
- MemorySegment(linked_ptr<base::DiscardableSharedMemory> memory,
- base::ProcessHandle process_handle);
+ class MemorySegment : public base::RefCountedThreadSafe<MemorySegment> {
+ public:
+ MemorySegment(scoped_ptr<base::DiscardableSharedMemory> memory);
+
+ base::DiscardableSharedMemory* memory() const { return memory_.get(); }
+
+ private:
+ friend class base::RefCountedThreadSafe<MemorySegment>;
+
~MemorySegment();
- linked_ptr<base::DiscardableSharedMemory> memory;
- base::ProcessHandle process_handle;
+ scoped_ptr<base::DiscardableSharedMemory> memory_;
+
+ DISALLOW_COPY_AND_ASSIGN(MemorySegment);
};
- static bool CompareMemoryUsageTime(const MemorySegment& a,
- const MemorySegment& b) {
+ static bool CompareMemoryUsageTime(const scoped_refptr<MemorySegment>& a,
+ const scoped_refptr<MemorySegment>& b) {
// In this system, LRU memory segment is evicted first.
- return a.memory->last_known_usage() > b.memory->last_known_usage();
+ return a->memory()->last_known_usage() > b->memory()->last_known_usage();
}
+ void AllocateLockedDiscardableSharedMemory(
+ base::ProcessHandle process_handle,
+ size_t size,
+ DiscardableSharedMemoryId id,
+ base::SharedMemoryHandle* shared_memory_handle);
+ void DeletedDiscardableSharedMemory(DiscardableSharedMemoryId id,
+ base::ProcessHandle process_handle);
void OnMemoryPressure(
base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level);
void ReduceMemoryUsageUntilWithinMemoryLimit();
void ReduceMemoryUsageUntilWithinLimit(size_t limit);
+ void ReleaseMemory(base::DiscardableSharedMemory* memory);
void BytesAllocatedChanged(size_t new_bytes_allocated) const;
// Virtual for tests.
@@ -82,9 +107,13 @@ class CONTENT_EXPORT HostDiscardableSharedMemoryManager
virtual void ScheduleEnforceMemoryPolicy();
base::Lock lock_;
+ typedef base::hash_map<DiscardableSharedMemoryId,
+ scoped_refptr<MemorySegment>> MemorySegmentMap;
+ typedef base::hash_map<base::ProcessHandle, MemorySegmentMap> ProcessMap;
+ ProcessMap processes_;
// Note: The elements in |segments_| are arranged in such a way that they form
// a heap. The LRU memory segment always first.
- typedef std::vector<MemorySegment> MemorySegmentVector;
+ typedef std::vector<scoped_refptr<MemorySegment>> MemorySegmentVector;
MemorySegmentVector segments_;
size_t memory_limit_;
size_t bytes_allocated_;
diff --git a/chromium/content/common/host_discardable_shared_memory_manager_unittest.cc b/chromium/content/common/host_discardable_shared_memory_manager_unittest.cc
index d4c5e0054d6..4855a2a6b00 100644
--- a/chromium/content/common/host_discardable_shared_memory_manager_unittest.cc
+++ b/chromium/content/common/host_discardable_shared_memory_manager_unittest.cc
@@ -67,7 +67,7 @@ TEST_F(HostDiscardableSharedMemoryManagerTest, AllocateForChild) {
base::SharedMemoryHandle shared_handle;
manager_->AllocateLockedDiscardableSharedMemoryForChild(
- base::GetCurrentProcessHandle(), kDataSize, &shared_handle);
+ base::GetCurrentProcessHandle(), kDataSize, 0, &shared_handle);
ASSERT_TRUE(base::SharedMemory::IsHandleValid(shared_handle));
TestDiscardableSharedMemory memory(shared_handle);
@@ -76,11 +76,11 @@ TEST_F(HostDiscardableSharedMemoryManagerTest, AllocateForChild) {
memcpy(memory.memory(), data, kDataSize);
memory.SetNow(base::Time::FromDoubleT(1));
- memory.Unlock();
+ memory.Unlock(0, 0);
- ASSERT_TRUE(memory.Lock());
+ ASSERT_EQ(base::DiscardableSharedMemory::SUCCESS, memory.Lock(0, 0));
EXPECT_EQ(memcmp(data, memory.memory(), kDataSize), 0);
- memory.Unlock();
+ memory.Unlock(0, 0);
}
TEST_F(HostDiscardableSharedMemoryManagerTest, Purge) {
@@ -88,7 +88,7 @@ TEST_F(HostDiscardableSharedMemoryManagerTest, Purge) {
base::SharedMemoryHandle shared_handle1;
manager_->AllocateLockedDiscardableSharedMemoryForChild(
- base::GetCurrentProcessHandle(), kDataSize, &shared_handle1);
+ base::GetCurrentProcessHandle(), kDataSize, 1, &shared_handle1);
ASSERT_TRUE(base::SharedMemory::IsHandleValid(shared_handle1));
TestDiscardableSharedMemory memory1(shared_handle1);
@@ -97,7 +97,7 @@ TEST_F(HostDiscardableSharedMemoryManagerTest, Purge) {
base::SharedMemoryHandle shared_handle2;
manager_->AllocateLockedDiscardableSharedMemoryForChild(
- base::GetCurrentProcessHandle(), kDataSize, &shared_handle2);
+ base::GetCurrentProcessHandle(), kDataSize, 2, &shared_handle2);
ASSERT_TRUE(base::SharedMemory::IsHandleValid(shared_handle2));
TestDiscardableSharedMemory memory2(shared_handle2);
@@ -109,9 +109,9 @@ TEST_F(HostDiscardableSharedMemoryManagerTest, Purge) {
manager_->SetMemoryLimit(memory1.mapped_size() + memory2.mapped_size());
memory1.SetNow(base::Time::FromDoubleT(2));
- memory1.Unlock();
+ memory1.Unlock(0, 0);
memory2.SetNow(base::Time::FromDoubleT(2));
- memory2.Unlock();
+ memory2.Unlock(0, 0);
// Manager should not have to schedule another call to EnforceMemoryPolicy().
manager_->SetNow(base::Time::FromDoubleT(3));
@@ -122,15 +122,15 @@ TEST_F(HostDiscardableSharedMemoryManagerTest, Purge) {
EXPECT_TRUE(memory1.IsMemoryResident());
EXPECT_TRUE(memory2.IsMemoryResident());
- rv = memory1.Lock();
- EXPECT_TRUE(rv);
- rv = memory2.Lock();
- EXPECT_TRUE(rv);
+ auto lock_rv = memory1.Lock(0, 0);
+ EXPECT_EQ(base::DiscardableSharedMemory::SUCCESS, lock_rv);
+ lock_rv = memory2.Lock(0, 0);
+ EXPECT_EQ(base::DiscardableSharedMemory::SUCCESS, lock_rv);
memory1.SetNow(base::Time::FromDoubleT(4));
- memory1.Unlock();
+ memory1.Unlock(0, 0);
memory2.SetNow(base::Time::FromDoubleT(5));
- memory2.Unlock();
+ memory2.Unlock(0, 0);
// Just enough memory for one allocation.
manager_->SetNow(base::Time::FromDoubleT(6));
@@ -141,10 +141,10 @@ TEST_F(HostDiscardableSharedMemoryManagerTest, Purge) {
EXPECT_FALSE(memory1.IsMemoryResident());
EXPECT_TRUE(memory2.IsMemoryResident());
- rv = memory1.Lock();
- EXPECT_FALSE(rv);
- rv = memory2.Lock();
- EXPECT_TRUE(rv);
+ lock_rv = memory1.Lock(0, 0);
+ EXPECT_EQ(base::DiscardableSharedMemory::FAILED, lock_rv);
+ lock_rv = memory2.Lock(0, 0);
+ EXPECT_EQ(base::DiscardableSharedMemory::SUCCESS, lock_rv);
}
TEST_F(HostDiscardableSharedMemoryManagerTest, EnforceMemoryPolicy) {
@@ -152,7 +152,7 @@ TEST_F(HostDiscardableSharedMemoryManagerTest, EnforceMemoryPolicy) {
base::SharedMemoryHandle shared_handle;
manager_->AllocateLockedDiscardableSharedMemoryForChild(
- base::GetCurrentProcessHandle(), kDataSize, &shared_handle);
+ base::GetCurrentProcessHandle(), kDataSize, 0, &shared_handle);
ASSERT_TRUE(base::SharedMemory::IsHandleValid(shared_handle));
TestDiscardableSharedMemory memory(shared_handle);
@@ -173,7 +173,7 @@ TEST_F(HostDiscardableSharedMemoryManagerTest, EnforceMemoryPolicy) {
EXPECT_TRUE(manager_->enforce_memory_policy_pending());
memory.SetNow(base::Time::FromDoubleT(3));
- memory.Unlock();
+ memory.Unlock(0, 0);
manager_->set_enforce_memory_policy_pending(false);
manager_->SetNow(base::Time::FromDoubleT(4));
@@ -181,7 +181,7 @@ TEST_F(HostDiscardableSharedMemoryManagerTest, EnforceMemoryPolicy) {
// Memory policy should have successfully been enforced.
EXPECT_FALSE(manager_->enforce_memory_policy_pending());
- EXPECT_FALSE(memory.Lock());
+ EXPECT_EQ(base::DiscardableSharedMemory::FAILED, memory.Lock(0, 0));
}
} // namespace
diff --git a/chromium/content/common/host_shared_bitmap_manager.cc b/chromium/content/common/host_shared_bitmap_manager.cc
index 66f721552f9..3237a992fdb 100644
--- a/chromium/content/common/host_shared_bitmap_manager.cc
+++ b/chromium/content/common/host_shared_bitmap_manager.cc
@@ -6,21 +6,20 @@
#include "base/lazy_instance.h"
#include "base/memory/ref_counted.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/trace_event/process_memory_dump.h"
#include "content/common/view_messages.h"
-#include "ui/gfx/size.h"
+#include "ui/gfx/geometry/size.h"
namespace content {
class BitmapData : public base::RefCountedThreadSafe<BitmapData> {
public:
BitmapData(base::ProcessHandle process_handle,
- base::SharedMemoryHandle memory_handle,
size_t buffer_size)
: process_handle(process_handle),
- memory_handle(memory_handle),
buffer_size(buffer_size) {}
base::ProcessHandle process_handle;
- base::SharedMemoryHandle memory_handle;
scoped_ptr<base::SharedMemory> memory;
scoped_ptr<uint8[]> pixels;
size_t buffer_size;
@@ -31,15 +30,74 @@ class BitmapData : public base::RefCountedThreadSafe<BitmapData> {
DISALLOW_COPY_AND_ASSIGN(BitmapData);
};
-// Holds a reference on the memory to keep it alive.
-void FreeSharedMemory(scoped_refptr<BitmapData> data,
- cc::SharedBitmap* bitmap) {}
+namespace {
+
+class HostSharedBitmap : public cc::SharedBitmap {
+ public:
+ HostSharedBitmap(uint8* pixels,
+ scoped_refptr<BitmapData> bitmap_data,
+ const cc::SharedBitmapId& id,
+ HostSharedBitmapManager* manager)
+ : SharedBitmap(pixels, id),
+ bitmap_data_(bitmap_data),
+ manager_(manager) {}
+
+ ~HostSharedBitmap() override {
+ if (manager_)
+ manager_->FreeSharedMemoryFromMap(id());
+ }
+
+ private:
+ scoped_refptr<BitmapData> bitmap_data_;
+ HostSharedBitmapManager* manager_;
+};
+
+const char kMemoryAllocatorName[] = "sharedbitmap";
+
+} // namespace
base::LazyInstance<HostSharedBitmapManager> g_shared_memory_manager =
LAZY_INSTANCE_INITIALIZER;
+HostSharedBitmapManagerClient::HostSharedBitmapManagerClient(
+ HostSharedBitmapManager* manager)
+ : manager_(manager) {
+}
+
+HostSharedBitmapManagerClient::~HostSharedBitmapManagerClient() {
+ for (const auto& id : owned_bitmaps_)
+ manager_->ChildDeletedSharedBitmap(id);
+}
+
+void HostSharedBitmapManagerClient::AllocateSharedBitmapForChild(
+ base::ProcessHandle process_handle,
+ size_t buffer_size,
+ const cc::SharedBitmapId& id,
+ base::SharedMemoryHandle* shared_memory_handle) {
+ manager_->AllocateSharedBitmapForChild(process_handle, buffer_size, id,
+ shared_memory_handle);
+ owned_bitmaps_.insert(id);
+}
+
+void HostSharedBitmapManagerClient::ChildAllocatedSharedBitmap(
+ size_t buffer_size,
+ const base::SharedMemoryHandle& handle,
+ base::ProcessHandle process_handle,
+ const cc::SharedBitmapId& id) {
+ manager_->ChildAllocatedSharedBitmap(buffer_size, handle, process_handle, id);
+ owned_bitmaps_.insert(id);
+}
+
+void HostSharedBitmapManagerClient::ChildDeletedSharedBitmap(
+ const cc::SharedBitmapId& id) {
+ manager_->ChildDeletedSharedBitmap(id);
+ owned_bitmaps_.erase(id);
+}
+
HostSharedBitmapManager::HostSharedBitmapManager() {}
-HostSharedBitmapManager::~HostSharedBitmapManager() {}
+HostSharedBitmapManager::~HostSharedBitmapManager() {
+ DCHECK(handle_map_.empty());
+}
HostSharedBitmapManager* HostSharedBitmapManager::current() {
return g_shared_memory_manager.Pointer();
@@ -54,7 +112,6 @@ scoped_ptr<cc::SharedBitmap> HostSharedBitmapManager::AllocateSharedBitmap(
scoped_refptr<BitmapData> data(
new BitmapData(base::GetCurrentProcessHandle(),
- base::SharedMemory::NULLHandle(),
bitmap_size));
// Bitmaps allocated in host don't need to be shared to other processes, so
// allocate them with new instead.
@@ -62,11 +119,8 @@ scoped_ptr<cc::SharedBitmap> HostSharedBitmapManager::AllocateSharedBitmap(
cc::SharedBitmapId id = cc::SharedBitmap::GenerateId();
handle_map_[id] = data;
- return make_scoped_ptr(new cc::SharedBitmap(
- data->pixels.get(),
- id,
- base::Bind(&HostSharedBitmapManager::FreeSharedMemoryFromMap,
- base::Unretained(this))));
+ return make_scoped_ptr(
+ new HostSharedBitmap(data->pixels.get(), data, id, this));
}
scoped_ptr<cc::SharedBitmap> HostSharedBitmapManager::GetSharedBitmapFromId(
@@ -85,26 +139,35 @@ scoped_ptr<cc::SharedBitmap> HostSharedBitmapManager::GetSharedBitmapFromId(
return scoped_ptr<cc::SharedBitmap>();
if (data->pixels) {
- return make_scoped_ptr(new cc::SharedBitmap(
- data->pixels.get(), id, base::Bind(&FreeSharedMemory, it->second)));
+ return make_scoped_ptr(
+ new HostSharedBitmap(data->pixels.get(), data, id, nullptr));
}
if (!data->memory->memory()) {
- TRACE_EVENT0("renderer_host",
- "HostSharedBitmapManager::GetSharedBitmapFromId");
- if (!data->memory->Map(data->buffer_size)) {
- return scoped_ptr<cc::SharedBitmap>();
- }
+ return scoped_ptr<cc::SharedBitmap>();
}
- scoped_ptr<cc::SharedBitmap> bitmap(new cc::SharedBitmap(
- data->memory.get(), id, base::Bind(&FreeSharedMemory, it->second)));
-
- return bitmap.Pass();
+ return make_scoped_ptr(new HostSharedBitmap(
+ static_cast<uint8*>(data->memory->memory()), data, id, nullptr));
}
-scoped_ptr<cc::SharedBitmap> HostSharedBitmapManager::GetBitmapForSharedMemory(
- base::SharedMemory*) {
- return scoped_ptr<cc::SharedBitmap>();
+bool HostSharedBitmapManager::OnMemoryDump(
+ base::trace_event::ProcessMemoryDump* pmd) {
+ base::AutoLock lock(lock_);
+
+ for (const auto& bitmap : handle_map_) {
+ base::trace_event::MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(
+ base::StringPrintf("%s/%s", kMemoryAllocatorName,
+ base::HexEncode(bitmap.first.name,
+ sizeof(bitmap.first.name)).c_str()));
+ if (!dump)
+ return false;
+
+ dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameOuterSize,
+ base::trace_event::MemoryAllocatorDump::kUnitsBytes,
+ bitmap.second->buffer_size);
+ }
+
+ return true;
}
void HostSharedBitmapManager::ChildAllocatedSharedBitmap(
@@ -116,17 +179,18 @@ void HostSharedBitmapManager::ChildAllocatedSharedBitmap(
if (handle_map_.find(id) != handle_map_.end())
return;
scoped_refptr<BitmapData> data(
- new BitmapData(process_handle, handle, buffer_size));
+ new BitmapData(process_handle, buffer_size));
handle_map_[id] = data;
- process_map_[process_handle].insert(id);
#if defined(OS_WIN)
data->memory = make_scoped_ptr(
- new base::SharedMemory(data->memory_handle, false, data->process_handle));
+ new base::SharedMemory(handle, false, data->process_handle));
#else
data->memory =
- make_scoped_ptr(new base::SharedMemory(data->memory_handle, false));
+ make_scoped_ptr(new base::SharedMemory(handle, false));
#endif
+ data->memory->Map(data->buffer_size);
+ data->memory->Close();
}
void HostSharedBitmapManager::AllocateSharedBitmapForChild(
@@ -147,44 +211,22 @@ void HostSharedBitmapManager::AllocateSharedBitmapForChild(
}
scoped_refptr<BitmapData> data(
- new BitmapData(process_handle, shared_memory->handle(), buffer_size));
+ new BitmapData(process_handle, buffer_size));
data->memory = shared_memory.Pass();
handle_map_[id] = data;
- process_map_[process_handle].insert(id);
if (!data->memory->ShareToProcess(process_handle, shared_memory_handle)) {
LOG(ERROR) << "Cannot share shared memory buffer";
*shared_memory_handle = base::SharedMemory::NULLHandle();
return;
}
+ data->memory->Close();
}
void HostSharedBitmapManager::ChildDeletedSharedBitmap(
const cc::SharedBitmapId& id) {
base::AutoLock lock(lock_);
- BitmapMap::iterator it = handle_map_.find(id);
- if (it == handle_map_.end())
- return;
- base::hash_set<cc::SharedBitmapId>& res =
- process_map_[it->second->process_handle];
- res.erase(id);
- handle_map_.erase(it);
-}
-
-void HostSharedBitmapManager::ProcessRemoved(
- base::ProcessHandle process_handle) {
- base::AutoLock lock(lock_);
- ProcessMap::iterator proc_it = process_map_.find(process_handle);
- if (proc_it == process_map_.end())
- return;
- base::hash_set<cc::SharedBitmapId>& res = proc_it->second;
-
- for (base::hash_set<cc::SharedBitmapId>::iterator it = res.begin();
- it != res.end();
- ++it) {
- handle_map_.erase(*it);
- }
- process_map_.erase(proc_it);
+ handle_map_.erase(id);
}
size_t HostSharedBitmapManager::AllocatedBitmapCount() const {
@@ -193,9 +235,9 @@ size_t HostSharedBitmapManager::AllocatedBitmapCount() const {
}
void HostSharedBitmapManager::FreeSharedMemoryFromMap(
- cc::SharedBitmap* bitmap) {
+ const cc::SharedBitmapId& id) {
base::AutoLock lock(lock_);
- handle_map_.erase(bitmap->id());
+ handle_map_.erase(id);
}
} // namespace content
diff --git a/chromium/content/common/host_shared_bitmap_manager.h b/chromium/content/common/host_shared_bitmap_manager.h
index 71af0e36ec6..ab846fb668f 100644
--- a/chromium/content/common/host_shared_bitmap_manager.h
+++ b/chromium/content/common/host_shared_bitmap_manager.h
@@ -15,6 +15,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/shared_memory.h"
#include "base/synchronization/lock.h"
+#include "base/trace_event/memory_dump_provider.h"
#include "cc/resources/shared_bitmap_manager.h"
#include "content/common/content_export.h"
@@ -29,8 +30,35 @@ struct hash<cc::SharedBitmapId> {
namespace content {
class BitmapData;
+class HostSharedBitmapManager;
-class CONTENT_EXPORT HostSharedBitmapManager : public cc::SharedBitmapManager {
+class CONTENT_EXPORT HostSharedBitmapManagerClient {
+ public:
+ explicit HostSharedBitmapManagerClient(HostSharedBitmapManager* manager);
+
+ ~HostSharedBitmapManagerClient();
+
+ void AllocateSharedBitmapForChild(
+ base::ProcessHandle process_handle,
+ size_t buffer_size,
+ const cc::SharedBitmapId& id,
+ base::SharedMemoryHandle* shared_memory_handle);
+ void ChildAllocatedSharedBitmap(size_t buffer_size,
+ const base::SharedMemoryHandle& handle,
+ base::ProcessHandle process_handle,
+ const cc::SharedBitmapId& id);
+ void ChildDeletedSharedBitmap(const cc::SharedBitmapId& id);
+
+ private:
+ HostSharedBitmapManager* manager_;
+ base::hash_set<cc::SharedBitmapId> owned_bitmaps_;
+
+ DISALLOW_COPY_AND_ASSIGN(HostSharedBitmapManagerClient);
+};
+
+class CONTENT_EXPORT HostSharedBitmapManager
+ : public cc::SharedBitmapManager,
+ public base::trace_event::MemoryDumpProvider {
public:
HostSharedBitmapManager();
~HostSharedBitmapManager() override;
@@ -43,8 +71,16 @@ class CONTENT_EXPORT HostSharedBitmapManager : public cc::SharedBitmapManager {
scoped_ptr<cc::SharedBitmap> GetSharedBitmapFromId(
const gfx::Size& size,
const cc::SharedBitmapId&) override;
- scoped_ptr<cc::SharedBitmap> GetBitmapForSharedMemory(
- base::SharedMemory*) override;
+
+ // base::trace_event::MemoryDumpProvider implementation.
+ bool OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd) override;
+
+ size_t AllocatedBitmapCount() const;
+
+ void FreeSharedMemoryFromMap(const cc::SharedBitmapId& id);
+
+ private:
+ friend class HostSharedBitmapManagerClient;
void AllocateSharedBitmapForChild(
base::ProcessHandle process_handle,
@@ -56,12 +92,6 @@ class CONTENT_EXPORT HostSharedBitmapManager : public cc::SharedBitmapManager {
base::ProcessHandle process_handle,
const cc::SharedBitmapId& id);
void ChildDeletedSharedBitmap(const cc::SharedBitmapId& id);
- void ProcessRemoved(base::ProcessHandle process_handle);
-
- size_t AllocatedBitmapCount() const;
-
- private:
- void FreeSharedMemoryFromMap(cc::SharedBitmap* bitmap);
mutable base::Lock lock_;
@@ -69,9 +99,7 @@ class CONTENT_EXPORT HostSharedBitmapManager : public cc::SharedBitmapManager {
BitmapMap;
BitmapMap handle_map_;
- typedef base::hash_map<base::ProcessHandle,
- base::hash_set<cc::SharedBitmapId> > ProcessMap;
- ProcessMap process_map_;
+ DISALLOW_COPY_AND_ASSIGN(HostSharedBitmapManager);
};
} // namespace content
diff --git a/chromium/content/common/host_shared_bitmap_manager_unittest.cc b/chromium/content/common/host_shared_bitmap_manager_unittest.cc
index 68456a8f7ba..308402e36a5 100644
--- a/chromium/content/common/host_shared_bitmap_manager_unittest.cc
+++ b/chromium/content/common/host_shared_bitmap_manager_unittest.cc
@@ -23,10 +23,11 @@ TEST_F(HostSharedBitmapManagerTest, TestCreate) {
memset(bitmap->memory(), 0xff, size_in_bytes);
cc::SharedBitmapId id = cc::SharedBitmap::GenerateId();
+ HostSharedBitmapManagerClient client(manager_.get());
base::SharedMemoryHandle handle;
bitmap->ShareToProcess(base::GetCurrentProcessHandle(), &handle);
- manager_->ChildAllocatedSharedBitmap(
- size_in_bytes, handle, base::GetCurrentProcessHandle(), id);
+ client.ChildAllocatedSharedBitmap(size_in_bytes, handle,
+ base::GetCurrentProcessHandle(), id);
scoped_ptr<cc::SharedBitmap> large_bitmap;
large_bitmap = manager_->GetSharedBitmapFromId(gfx::Size(1024, 1024), id);
@@ -63,7 +64,7 @@ TEST_F(HostSharedBitmapManagerTest, TestCreate) {
EXPECT_EQ(memcmp(shared_bitmap->pixels(), bitmap->memory(), size_in_bytes),
0);
- manager_->ChildDeletedSharedBitmap(id);
+ client.ChildDeletedSharedBitmap(id);
memset(bitmap->memory(), 0, size_in_bytes);
@@ -78,9 +79,10 @@ TEST_F(HostSharedBitmapManagerTest, TestCreateForChild) {
size_t size_in_bytes;
EXPECT_TRUE(cc::SharedBitmap::SizeInBytes(bitmap_size, &size_in_bytes));
cc::SharedBitmapId id = cc::SharedBitmap::GenerateId();
+ HostSharedBitmapManagerClient client(manager_.get());
base::SharedMemoryHandle handle;
- manager_->AllocateSharedBitmapForChild(
- base::GetCurrentProcessHandle(), size_in_bytes, id, &handle);
+ client.AllocateSharedBitmapForChild(base::GetCurrentProcessHandle(),
+ size_in_bytes, id, &handle);
EXPECT_TRUE(base::SharedMemory::IsHandleValid(handle));
scoped_ptr<base::SharedMemory> bitmap(new base::SharedMemory(handle, false));
@@ -92,6 +94,8 @@ TEST_F(HostSharedBitmapManagerTest, TestCreateForChild) {
EXPECT_TRUE(shared_bitmap);
EXPECT_TRUE(
memcmp(bitmap->memory(), shared_bitmap->pixels(), size_in_bytes) == 0);
+
+ client.ChildDeletedSharedBitmap(id);
}
TEST_F(HostSharedBitmapManagerTest, RemoveProcess) {
@@ -104,17 +108,19 @@ TEST_F(HostSharedBitmapManagerTest, RemoveProcess) {
cc::SharedBitmapId id = cc::SharedBitmap::GenerateId();
base::SharedMemoryHandle handle;
+ scoped_ptr<HostSharedBitmapManagerClient> client(
+ new HostSharedBitmapManagerClient(manager_.get()));
bitmap->ShareToProcess(base::GetCurrentProcessHandle(), &handle);
- manager_->ChildAllocatedSharedBitmap(
- size_in_bytes, handle, base::GetCurrentProcessHandle(), id);
-
- manager_->ProcessRemoved(base::kNullProcessHandle);
+ client->ChildAllocatedSharedBitmap(size_in_bytes, handle,
+ base::GetCurrentProcessHandle(), id);
scoped_ptr<cc::SharedBitmap> shared_bitmap;
shared_bitmap = manager_->GetSharedBitmapFromId(bitmap_size, id);
ASSERT_TRUE(shared_bitmap.get() != NULL);
- manager_->ProcessRemoved(base::GetCurrentProcessHandle());
+ EXPECT_EQ(1u, manager_->AllocatedBitmapCount());
+ client.reset();
+ EXPECT_EQ(0u, manager_->AllocatedBitmapCount());
scoped_ptr<cc::SharedBitmap> shared_bitmap2;
shared_bitmap2 = manager_->GetSharedBitmapFromId(bitmap_size, id);
@@ -123,9 +129,6 @@ TEST_F(HostSharedBitmapManagerTest, RemoveProcess) {
0);
shared_bitmap.reset();
-
- // Should no-op.
- manager_->ChildDeletedSharedBitmap(id);
}
TEST_F(HostSharedBitmapManagerTest, AddDuplicate) {
@@ -136,24 +139,26 @@ TEST_F(HostSharedBitmapManagerTest, AddDuplicate) {
bitmap->CreateAndMapAnonymous(size_in_bytes);
memset(bitmap->memory(), 0xff, size_in_bytes);
cc::SharedBitmapId id = cc::SharedBitmap::GenerateId();
+ HostSharedBitmapManagerClient client(manager_.get());
base::SharedMemoryHandle handle;
bitmap->ShareToProcess(base::GetCurrentProcessHandle(), &handle);
- manager_->ChildAllocatedSharedBitmap(
- size_in_bytes, handle, base::GetCurrentProcessHandle(), id);
+ client.ChildAllocatedSharedBitmap(size_in_bytes, handle,
+ base::GetCurrentProcessHandle(), id);
scoped_ptr<base::SharedMemory> bitmap2(new base::SharedMemory());
bitmap2->CreateAndMapAnonymous(size_in_bytes);
memset(bitmap2->memory(), 0x00, size_in_bytes);
- manager_->ChildAllocatedSharedBitmap(
- size_in_bytes, bitmap2->handle(), base::GetCurrentProcessHandle(), id);
+ client.ChildAllocatedSharedBitmap(size_in_bytes, bitmap2->handle(),
+ base::GetCurrentProcessHandle(), id);
scoped_ptr<cc::SharedBitmap> shared_bitmap;
shared_bitmap = manager_->GetSharedBitmapFromId(bitmap_size, id);
ASSERT_TRUE(shared_bitmap.get() != NULL);
EXPECT_EQ(memcmp(shared_bitmap->pixels(), bitmap->memory(), size_in_bytes),
0);
+ client.ChildDeletedSharedBitmap(id);
}
} // namespace
diff --git a/chromium/content/common/image_messages.h b/chromium/content/common/image_messages.h
index f2f734dd39c..8e8279f9207 100644
--- a/chromium/content/common/image_messages.h
+++ b/chromium/content/common/image_messages.h
@@ -9,7 +9,7 @@
#include "ipc/ipc_message_macros.h"
#include "ipc/ipc_param_traits.h"
#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/gfx/size.h"
+#include "ui/gfx/geometry/size.h"
#define IPC_MESSAGE_START ImageMsgStart
@@ -17,7 +17,7 @@
// Requests the renderer to download the specified image, decode it,
// and send the image data back via ImageHostMsg_DidDownloadImage.
-IPC_MESSAGE_ROUTED4(ImageMsg_DownloadImage,
+IPC_MESSAGE_ROUTED5(ImageMsg_DownloadImage,
int /* Identifier for the request */,
GURL /* URL of the image */,
bool /* is favicon (turn off cookies) */,
@@ -26,7 +26,8 @@ IPC_MESSAGE_ROUTED4(ImageMsg_DownloadImage,
bitmaps at the passed in GURL <= max size, the
smallest bitmap is resized to the max size and
is the only result. A max size of zero means
- that the max size is unlimited. */)
+ that the max size is unlimited. */,
+ bool /* bypass cache */)
// Messages sent from the renderer to the browser.
diff --git a/chromium/content/common/in_process_child_thread_params.cc b/chromium/content/common/in_process_child_thread_params.cc
new file mode 100644
index 00000000000..13e93902da6
--- /dev/null
+++ b/chromium/content/common/in_process_child_thread_params.cc
@@ -0,0 +1,18 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/common/in_process_child_thread_params.h"
+
+namespace content {
+
+InProcessChildThreadParams::InProcessChildThreadParams(
+ const std::string& channel_name,
+ scoped_refptr<base::SequencedTaskRunner> io_runner)
+ : channel_name_(channel_name), io_runner_(io_runner) {
+}
+
+InProcessChildThreadParams::~InProcessChildThreadParams() {
+}
+
+} // namespace content
diff --git a/chromium/content/common/in_process_child_thread_params.h b/chromium/content/common/in_process_child_thread_params.h
new file mode 100644
index 00000000000..938a6ef0806
--- /dev/null
+++ b/chromium/content/common/in_process_child_thread_params.h
@@ -0,0 +1,38 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_COMMON_IN_PROCESS_CHILD_THREAD_PARAMS_H_
+#define CONTENT_COMMON_IN_PROCESS_CHILD_THREAD_PARAMS_H_
+
+#include <string>
+
+#include "base/memory/ref_counted.h"
+#include "base/sequenced_task_runner.h"
+#include "content/common/content_export.h"
+
+namespace content {
+
+// Tells ChildThreadImpl to run in in-process mode. There are a couple of
+// parameters to run in the mode: An emulated io task runner used by
+// ChnanelMojo, an IPC channel name to open.
+class CONTENT_EXPORT InProcessChildThreadParams {
+ public:
+ InProcessChildThreadParams(
+ const std::string& channel_name,
+ scoped_refptr<base::SequencedTaskRunner> io_runner);
+ ~InProcessChildThreadParams();
+
+ const std::string& channel_name() const { return channel_name_; }
+ scoped_refptr<base::SequencedTaskRunner> io_runner() const {
+ return io_runner_;
+ }
+
+ private:
+ std::string channel_name_;
+ scoped_refptr<base::SequencedTaskRunner> io_runner_;
+};
+
+} // namespace content
+
+#endif // CONTENT_COMMON_IN_PROCESS_CHILD_THREAD_PARAMS_H_
diff --git a/chromium/content/common/indexed_db/indexed_db_constants.h b/chromium/content/common/indexed_db/indexed_db_constants.h
index 5c7377ba13f..b6c6363cdc3 100644
--- a/chromium/content/common/indexed_db/indexed_db_constants.h
+++ b/chromium/content/common/indexed_db/indexed_db_constants.h
@@ -9,6 +9,8 @@ namespace content {
const int32 kNoDatabase = -1;
+const size_t kMaxIDBMessageOverhead = 1024 * 1024; // 1MB; arbitrarily chosen.
+
} // namespace content
#endif // CONTENT_COMMON_INDEXED_DB_INDEXED_DB_CONSTANTS_H_
diff --git a/chromium/content/common/indexed_db/indexed_db_key.cc b/chromium/content/common/indexed_db/indexed_db_key.cc
index 4c553ca4bdf..c23d3e44e2f 100644
--- a/chromium/content/common/indexed_db/indexed_db_key.cc
+++ b/chromium/content/common/indexed_db/indexed_db_key.cc
@@ -5,7 +5,6 @@
#include "content/common/indexed_db/indexed_db_key.h"
#include <string>
-#include "base/logging.h"
namespace content {
@@ -56,18 +55,15 @@ static IndexedDBKey::KeyArray CopyKeyArray(const T& array) {
IndexedDBKey::IndexedDBKey()
: type_(WebIDBKeyTypeNull),
- date_(0),
- number_(0),
size_estimate_(kOverheadSize) {}
IndexedDBKey::IndexedDBKey(WebIDBKeyType type)
- : type_(type), date_(0), number_(0), size_estimate_(kOverheadSize) {
+ : type_(type), size_estimate_(kOverheadSize) {
DCHECK(type == WebIDBKeyTypeNull || type == WebIDBKeyTypeInvalid);
}
IndexedDBKey::IndexedDBKey(double number, WebIDBKeyType type)
: type_(type),
- date_(number),
number_(number),
size_estimate_(kOverheadSize + sizeof(number)) {
DCHECK(type == WebIDBKeyTypeNumber || type == WebIDBKeyTypeDate);
@@ -76,8 +72,6 @@ IndexedDBKey::IndexedDBKey(double number, WebIDBKeyType type)
IndexedDBKey::IndexedDBKey(const KeyArray& array)
: type_(WebIDBKeyTypeArray),
array_(CopyKeyArray(array)),
- date_(0),
- number_(0),
size_estimate_(kOverheadSize + CalculateArraySize(array)) {}
IndexedDBKey::IndexedDBKey(const std::string& binary)
@@ -92,7 +86,9 @@ IndexedDBKey::IndexedDBKey(const base::string16& string)
size_estimate_(kOverheadSize +
(string.length() * sizeof(base::string16::value_type))) {}
-IndexedDBKey::~IndexedDBKey() {}
+IndexedDBKey::IndexedDBKey(const IndexedDBKey& other) = default;
+IndexedDBKey::~IndexedDBKey() = default;
+IndexedDBKey& IndexedDBKey::operator=(const IndexedDBKey& other) = default;
bool IndexedDBKey::IsValid() const {
if (type_ == WebIDBKeyTypeInvalid || type_ == WebIDBKeyTypeNull)
@@ -135,7 +131,6 @@ int IndexedDBKey::CompareTo(const IndexedDBKey& other) const {
case WebIDBKeyTypeString:
return string_.compare(other.string_);
case WebIDBKeyTypeDate:
- return Compare(date_, other.date_);
case WebIDBKeyTypeNumber:
return Compare(number_, other.number_);
case WebIDBKeyTypeInvalid:
diff --git a/chromium/content/common/indexed_db/indexed_db_key.h b/chromium/content/common/indexed_db/indexed_db_key.h
index bb027700e89..47fc947a943 100644
--- a/chromium/content/common/indexed_db/indexed_db_key.h
+++ b/chromium/content/common/indexed_db/indexed_db_key.h
@@ -9,10 +9,11 @@
#include <vector>
#include "base/basictypes.h"
+#include "base/logging.h"
#include "base/memory/scoped_vector.h"
#include "base/strings/string16.h"
#include "content/common/content_export.h"
-#include "third_party/WebKit/public/platform/WebIDBTypes.h"
+#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBTypes.h"
namespace blink {
class WebIDBKey;
@@ -31,7 +32,9 @@ class CONTENT_EXPORT IndexedDBKey {
explicit IndexedDBKey(const base::string16& string);
IndexedDBKey(double number,
blink::WebIDBKeyType type); // must be date or number
+ IndexedDBKey(const IndexedDBKey& other);
~IndexedDBKey();
+ IndexedDBKey& operator=(const IndexedDBKey& other);
bool IsValid() const;
@@ -39,11 +42,26 @@ class CONTENT_EXPORT IndexedDBKey {
bool Equals(const IndexedDBKey& other) const;
blink::WebIDBKeyType type() const { return type_; }
- const std::vector<IndexedDBKey>& array() const { return array_; }
- const std::string& binary() const { return binary_; }
- const base::string16& string() const { return string_; }
- double date() const { return date_; }
- double number() const { return number_; }
+ const std::vector<IndexedDBKey>& array() const {
+ DCHECK_EQ(type_, blink::WebIDBKeyTypeArray);
+ return array_;
+ }
+ const std::string& binary() const {
+ DCHECK_EQ(type_, blink::WebIDBKeyTypeBinary);
+ return binary_;
+ }
+ const base::string16& string() const {
+ DCHECK_EQ(type_, blink::WebIDBKeyTypeString);
+ return string_;
+ }
+ double date() const {
+ DCHECK_EQ(type_, blink::WebIDBKeyTypeDate);
+ return number_;
+ }
+ double number() const {
+ DCHECK_EQ(type_, blink::WebIDBKeyTypeNumber);
+ return number_;
+ }
size_t size_estimate() const { return size_estimate_; }
@@ -54,8 +72,7 @@ class CONTENT_EXPORT IndexedDBKey {
std::vector<IndexedDBKey> array_;
std::string binary_;
base::string16 string_;
- double date_;
- double number_;
+ double number_ = 0;
size_t size_estimate_;
};
diff --git a/chromium/content/common/indexed_db/indexed_db_key_path.cc b/chromium/content/common/indexed_db/indexed_db_key_path.cc
index 3783d4281a8..a5756b51418 100644
--- a/chromium/content/common/indexed_db/indexed_db_key_path.cc
+++ b/chromium/content/common/indexed_db/indexed_db_key_path.cc
@@ -20,7 +20,10 @@ IndexedDBKeyPath::IndexedDBKeyPath(const base::string16& string)
IndexedDBKeyPath::IndexedDBKeyPath(const std::vector<base::string16>& array)
: type_(WebIDBKeyPathTypeArray), array_(array) {}
-IndexedDBKeyPath::~IndexedDBKeyPath() {}
+IndexedDBKeyPath::IndexedDBKeyPath(const IndexedDBKeyPath& other) = default;
+IndexedDBKeyPath::~IndexedDBKeyPath() = default;
+IndexedDBKeyPath& IndexedDBKeyPath::operator=(const IndexedDBKeyPath& other) =
+ default;
const std::vector<base::string16>& IndexedDBKeyPath::array() const {
DCHECK(type_ == blink::WebIDBKeyPathTypeArray);
diff --git a/chromium/content/common/indexed_db/indexed_db_key_path.h b/chromium/content/common/indexed_db/indexed_db_key_path.h
index b9387a4c8ac..c4ae73ec3f3 100644
--- a/chromium/content/common/indexed_db/indexed_db_key_path.h
+++ b/chromium/content/common/indexed_db/indexed_db_key_path.h
@@ -11,7 +11,7 @@
#include "base/logging.h"
#include "base/strings/string16.h"
#include "content/common/content_export.h"
-#include "third_party/WebKit/public/platform/WebIDBTypes.h"
+#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBTypes.h"
namespace content {
@@ -20,7 +20,9 @@ class CONTENT_EXPORT IndexedDBKeyPath {
IndexedDBKeyPath(); // Defaults to blink::WebIDBKeyPathTypeNull.
explicit IndexedDBKeyPath(const base::string16&);
explicit IndexedDBKeyPath(const std::vector<base::string16>&);
+ IndexedDBKeyPath(const IndexedDBKeyPath& other);
~IndexedDBKeyPath();
+ IndexedDBKeyPath& operator=(const IndexedDBKeyPath& other);
bool IsNull() const { return type_ == blink::WebIDBKeyPathTypeNull; }
bool operator==(const IndexedDBKeyPath& other) const;
diff --git a/chromium/content/common/indexed_db/indexed_db_key_range.cc b/chromium/content/common/indexed_db/indexed_db_key_range.cc
index 47e0cf1a9ac..f1938bfb2cd 100644
--- a/chromium/content/common/indexed_db/indexed_db_key_range.cc
+++ b/chromium/content/common/indexed_db/indexed_db_key_range.cc
@@ -5,15 +5,11 @@
#include "content/common/indexed_db/indexed_db_key_range.h"
#include "base/logging.h"
-#include "third_party/WebKit/public/platform/WebIDBTypes.h"
+#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBTypes.h"
namespace content {
-IndexedDBKeyRange::IndexedDBKeyRange()
- : lower_(blink::WebIDBKeyTypeNull),
- upper_(blink::WebIDBKeyTypeNull),
- lower_open_(false),
- upper_open_(false) {}
+IndexedDBKeyRange::IndexedDBKeyRange() = default;
IndexedDBKeyRange::IndexedDBKeyRange(const IndexedDBKey& lower,
const IndexedDBKey& upper,
@@ -25,15 +21,25 @@ IndexedDBKeyRange::IndexedDBKeyRange(const IndexedDBKey& lower,
upper_open_(upper_open) {}
IndexedDBKeyRange::IndexedDBKeyRange(const IndexedDBKey& key)
- : lower_(key), upper_(key), lower_open_(false), upper_open_(false) {}
+ : lower_(key), upper_(key) {
+}
-IndexedDBKeyRange::~IndexedDBKeyRange() {}
+IndexedDBKeyRange::IndexedDBKeyRange(const IndexedDBKeyRange& other) = default;
+IndexedDBKeyRange::~IndexedDBKeyRange() = default;
+IndexedDBKeyRange& IndexedDBKeyRange::operator=(
+ const IndexedDBKeyRange& other) = default;
bool IndexedDBKeyRange::IsOnlyKey() const {
if (lower_open_ || upper_open_)
return false;
+ if (IsEmpty())
+ return false;
return lower_.Equals(upper_);
}
+bool IndexedDBKeyRange::IsEmpty() const {
+ return !lower_.IsValid() && !upper_.IsValid();
+}
+
} // namespace content
diff --git a/chromium/content/common/indexed_db/indexed_db_key_range.h b/chromium/content/common/indexed_db/indexed_db_key_range.h
index 67248b6ba2b..8bf6fb33d9b 100644
--- a/chromium/content/common/indexed_db/indexed_db_key_range.h
+++ b/chromium/content/common/indexed_db/indexed_db_key_range.h
@@ -14,25 +14,28 @@ namespace content {
class CONTENT_EXPORT IndexedDBKeyRange {
public:
IndexedDBKeyRange();
- explicit IndexedDBKeyRange(const IndexedDBKey& onlyKey);
+ explicit IndexedDBKeyRange(const IndexedDBKey& key);
IndexedDBKeyRange(const IndexedDBKey& lower,
const IndexedDBKey& upper,
bool lower_open,
bool upper_open);
+ IndexedDBKeyRange(const IndexedDBKeyRange& other);
~IndexedDBKeyRange();
+ IndexedDBKeyRange& operator=(const IndexedDBKeyRange& other);
const IndexedDBKey& lower() const { return lower_; }
const IndexedDBKey& upper() const { return upper_; }
- bool lowerOpen() const { return lower_open_; }
- bool upperOpen() const { return upper_open_; }
+ bool lower_open() const { return lower_open_; }
+ bool upper_open() const { return upper_open_; }
bool IsOnlyKey() const;
+ bool IsEmpty() const;
private:
- IndexedDBKey lower_;
- IndexedDBKey upper_;
- bool lower_open_;
- bool upper_open_;
+ IndexedDBKey lower_ = IndexedDBKey(blink::WebIDBKeyTypeNull);
+ IndexedDBKey upper_ = IndexedDBKey(blink::WebIDBKeyTypeNull);
+ bool lower_open_ = false;
+ bool upper_open_ = false;
};
} // namespace content
diff --git a/chromium/content/common/indexed_db/indexed_db_messages.h b/chromium/content/common/indexed_db/indexed_db_messages.h
index 85c354c1264..9e92e98ba26 100644
--- a/chromium/content/common/indexed_db/indexed_db_messages.h
+++ b/chromium/content/common/indexed_db/indexed_db_messages.h
@@ -14,7 +14,7 @@
#include "content/common/indexed_db/indexed_db_param_traits.h"
#include "ipc/ipc_message_macros.h"
#include "ipc/ipc_param_traits.h"
-#include "third_party/WebKit/public/platform/WebIDBTypes.h"
+#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBTypes.h"
// Singly-included section for typedefs in multiply-included file.
#ifndef CONTENT_COMMON_INDEXED_DB_INDEXED_DB_MESSAGES_H_
@@ -126,6 +126,22 @@ IPC_STRUCT_BEGIN(IndexedDBHostMsg_DatabaseGet_Params)
IPC_STRUCT_MEMBER(bool, key_only)
IPC_STRUCT_END()
+IPC_STRUCT_BEGIN(IndexedDBHostMsg_DatabaseGetAll_Params)
+ IPC_STRUCT_MEMBER(int32, ipc_thread_id)
+ // The id any response should contain.
+ IPC_STRUCT_MEMBER(int32, ipc_callbacks_id)
+ // The database the object store belongs to.
+ IPC_STRUCT_MEMBER(int32, ipc_database_id)
+ // The transaction its associated with.
+ IPC_STRUCT_MEMBER(int64, transaction_id)
+ // The object store's id.
+ IPC_STRUCT_MEMBER(int64, object_store_id)
+ // The serialized key range.
+ IPC_STRUCT_MEMBER(content::IndexedDBKeyRange, key_range)
+ // The max number of values to retrieve.
+ IPC_STRUCT_MEMBER(int64, max_count)
+IPC_STRUCT_END()
+
IPC_STRUCT_BEGIN(IndexedDBMsg_BlobOrFileInfo)
IPC_STRUCT_MEMBER(bool, is_file)
IPC_STRUCT_MEMBER(std::string, uuid)
@@ -136,6 +152,20 @@ IPC_STRUCT_MEMBER(base::string16, file_name)
IPC_STRUCT_MEMBER(double, last_modified)
IPC_STRUCT_END()
+IPC_STRUCT_BEGIN(IndexedDBMsg_Value)
+ // The serialized value being transferred.
+ IPC_STRUCT_MEMBER(std::string, bits)
+ // Sideband data for any blob or file encoded in value.
+ IPC_STRUCT_MEMBER(std::vector<IndexedDBMsg_BlobOrFileInfo>, blob_or_file_info)
+IPC_STRUCT_END()
+
+IPC_STRUCT_BEGIN_WITH_PARENT(IndexedDBMsg_ReturnValue, IndexedDBMsg_Value)
+ IPC_STRUCT_TRAITS_PARENT(IndexedDBMsg_Value)
+ // Optional primary key & path used only when key generator specified.
+ IPC_STRUCT_MEMBER(content::IndexedDBKey, primary_key)
+ IPC_STRUCT_MEMBER(content::IndexedDBKeyPath, key_path)
+IPC_STRUCT_END()
+
// Used to set a value in an object store.
IPC_STRUCT_BEGIN(IndexedDBHostMsg_DatabasePut_Params)
// The id any response should contain.
@@ -150,15 +180,13 @@ IPC_STRUCT_BEGIN(IndexedDBHostMsg_DatabasePut_Params)
// The index's id.
IPC_STRUCT_MEMBER(int64, index_id)
// The value to set.
- IPC_STRUCT_MEMBER(std::string, value)
+ IPC_STRUCT_MEMBER(IndexedDBMsg_Value, value)
// The key to set it on (may not be "valid"/set in some cases).
IPC_STRUCT_MEMBER(content::IndexedDBKey, key)
// Whether this is an add or a put.
IPC_STRUCT_MEMBER(blink::WebIDBPutMode, put_mode)
// The index ids and the list of keys for each index.
IPC_STRUCT_MEMBER(std::vector<IndexKeys>, index_keys)
- // Sideband data for any blob or file encoded in value.
- IPC_STRUCT_MEMBER(std::vector<IndexedDBMsg_BlobOrFileInfo>, blob_or_file_info)
IPC_STRUCT_END()
// Used to open both cursors and object cursors in IndexedDB.
@@ -254,9 +282,7 @@ IPC_STRUCT_BEGIN(IndexedDBMsg_CallbacksSuccessIDBCursor_Params)
IPC_STRUCT_MEMBER(int32, ipc_cursor_id)
IPC_STRUCT_MEMBER(content::IndexedDBKey, key)
IPC_STRUCT_MEMBER(content::IndexedDBKey, primary_key)
- IPC_STRUCT_MEMBER(std::string, value)
- // Sideband data for any blob or file encoded in value.
- IPC_STRUCT_MEMBER(std::vector<IndexedDBMsg_BlobOrFileInfo>, blob_or_file_info)
+ IPC_STRUCT_MEMBER(IndexedDBMsg_Value, value)
IPC_STRUCT_END()
IPC_STRUCT_BEGIN(IndexedDBMsg_CallbacksSuccessCursorContinue_Params)
@@ -265,9 +291,7 @@ IPC_STRUCT_BEGIN(IndexedDBMsg_CallbacksSuccessCursorContinue_Params)
IPC_STRUCT_MEMBER(int32, ipc_cursor_id)
IPC_STRUCT_MEMBER(content::IndexedDBKey, key)
IPC_STRUCT_MEMBER(content::IndexedDBKey, primary_key)
- IPC_STRUCT_MEMBER(std::string, value)
- // Sideband data for any blob or file encoded in value.
- IPC_STRUCT_MEMBER(std::vector<IndexedDBMsg_BlobOrFileInfo>, blob_or_file_info)
+ IPC_STRUCT_MEMBER(IndexedDBMsg_Value, value)
IPC_STRUCT_END()
IPC_STRUCT_BEGIN(IndexedDBMsg_CallbacksSuccessCursorPrefetch_Params)
@@ -276,43 +300,34 @@ IPC_STRUCT_BEGIN(IndexedDBMsg_CallbacksSuccessCursorPrefetch_Params)
IPC_STRUCT_MEMBER(int32, ipc_cursor_id)
IPC_STRUCT_MEMBER(std::vector<content::IndexedDBKey>, keys)
IPC_STRUCT_MEMBER(std::vector<content::IndexedDBKey>, primary_keys)
- IPC_STRUCT_MEMBER(std::vector<std::string>, values)
- // Sideband data for any blob or file encoded in value.
- IPC_STRUCT_MEMBER(std::vector<std::vector<IndexedDBMsg_BlobOrFileInfo> >,
- blob_or_file_infos)
+ IPC_STRUCT_MEMBER(std::vector<IndexedDBMsg_Value>, values)
IPC_STRUCT_END()
-IPC_STRUCT_BEGIN(IndexedDBMsg_CallbacksSuccessValue_Params)
+IPC_STRUCT_BEGIN(IndexedDBMsg_CallbacksSuccessArray_Params)
IPC_STRUCT_MEMBER(int32, ipc_thread_id)
IPC_STRUCT_MEMBER(int32, ipc_callbacks_id)
- IPC_STRUCT_MEMBER(std::string, value)
- // Sideband data for any blob or file encoded in value.
- IPC_STRUCT_MEMBER(std::vector<IndexedDBMsg_BlobOrFileInfo>, blob_or_file_info)
+ IPC_STRUCT_MEMBER(std::vector<IndexedDBMsg_ReturnValue>, values)
IPC_STRUCT_END()
-IPC_STRUCT_BEGIN(IndexedDBMsg_CallbacksSuccessValueWithKey_Params)
+IPC_STRUCT_BEGIN(IndexedDBMsg_CallbacksSuccessValue_Params)
IPC_STRUCT_MEMBER(int32, ipc_thread_id)
IPC_STRUCT_MEMBER(int32, ipc_callbacks_id)
- IPC_STRUCT_MEMBER(std::string, value)
- IPC_STRUCT_MEMBER(content::IndexedDBKey, primary_key)
- IPC_STRUCT_MEMBER(content::IndexedDBKeyPath, key_path)
- // Sideband data for any blob or file encoded in value.
- IPC_STRUCT_MEMBER(std::vector<IndexedDBMsg_BlobOrFileInfo>, blob_or_file_info)
+ IPC_STRUCT_MEMBER(IndexedDBMsg_ReturnValue, value)
IPC_STRUCT_END()
IPC_STRUCT_BEGIN(IndexedDBIndexMetadata)
IPC_STRUCT_MEMBER(int64, id)
IPC_STRUCT_MEMBER(base::string16, name)
- IPC_STRUCT_MEMBER(content::IndexedDBKeyPath, keyPath)
+ IPC_STRUCT_MEMBER(content::IndexedDBKeyPath, key_path)
IPC_STRUCT_MEMBER(bool, unique)
- IPC_STRUCT_MEMBER(bool, multiEntry)
+ IPC_STRUCT_MEMBER(bool, multi_entry)
IPC_STRUCT_END()
IPC_STRUCT_BEGIN(IndexedDBObjectStoreMetadata)
IPC_STRUCT_MEMBER(int64, id)
IPC_STRUCT_MEMBER(base::string16, name)
- IPC_STRUCT_MEMBER(content::IndexedDBKeyPath, keyPath)
- IPC_STRUCT_MEMBER(bool, autoIncrement)
+ IPC_STRUCT_MEMBER(content::IndexedDBKeyPath, key_path)
+ IPC_STRUCT_MEMBER(bool, auto_increment)
IPC_STRUCT_MEMBER(int64, max_index_id)
IPC_STRUCT_MEMBER(std::vector<IndexedDBIndexMetadata>, indexes)
IPC_STRUCT_END()
@@ -356,6 +371,9 @@ IPC_MESSAGE_CONTROL1(IndexedDBMsg_CallbacksSuccessCursorAdvance,
IPC_MESSAGE_CONTROL1(IndexedDBMsg_CallbacksSuccessCursorPrefetch,
IndexedDBMsg_CallbacksSuccessCursorPrefetch_Params)
+IPC_MESSAGE_CONTROL1(IndexedDBMsg_CallbacksSuccessArray,
+ IndexedDBMsg_CallbacksSuccessArray_Params)
+
IPC_MESSAGE_CONTROL5(IndexedDBMsg_CallbacksSuccessIDBDatabase,
int32 /* ipc_thread_id */,
int32 /* ipc_callbacks_id */,
@@ -370,9 +388,6 @@ IPC_MESSAGE_CONTROL3(IndexedDBMsg_CallbacksSuccessIndexedDBKey,
IPC_MESSAGE_CONTROL1(IndexedDBMsg_CallbacksSuccessValue,
IndexedDBMsg_CallbacksSuccessValue_Params)
-IPC_MESSAGE_CONTROL1(IndexedDBMsg_CallbacksSuccessValueWithKey,
- IndexedDBMsg_CallbacksSuccessValueWithKey_Params)
-
IPC_MESSAGE_CONTROL3(IndexedDBMsg_CallbacksSuccessInteger,
int32 /* ipc_thread_id */,
int32 /* ipc_callbacks_id */,
@@ -494,6 +509,10 @@ IPC_MESSAGE_CONTROL1(IndexedDBHostMsg_DatabaseDestroyed,
IPC_MESSAGE_CONTROL1(IndexedDBHostMsg_DatabaseGet,
IndexedDBHostMsg_DatabaseGet_Params)
+// WebIDBDatabase::getAll() message.
+IPC_MESSAGE_CONTROL1(IndexedDBHostMsg_DatabaseGetAll,
+ IndexedDBHostMsg_DatabaseGetAll_Params)
+
// WebIDBDatabase::put() message.
IPC_MESSAGE_CONTROL1(IndexedDBHostMsg_DatabasePut,
IndexedDBHostMsg_DatabasePut_Params)
diff --git a/chromium/content/common/indexed_db/indexed_db_param_traits.cc b/chromium/content/common/indexed_db/indexed_db_param_traits.cc
index 916503c3504..8e714087a8d 100644
--- a/chromium/content/common/indexed_db/indexed_db_param_traits.cc
+++ b/chromium/content/common/indexed_db/indexed_db_param_traits.cc
@@ -198,8 +198,8 @@ void ParamTraits<IndexedDBKeyPath>::Log(const param_type& p, std::string* l) {
void ParamTraits<IndexedDBKeyRange>::Write(Message* m, const param_type& p) {
WriteParam(m, p.lower());
WriteParam(m, p.upper());
- WriteParam(m, p.lowerOpen());
- WriteParam(m, p.upperOpen());
+ WriteParam(m, p.lower_open());
+ WriteParam(m, p.upper_open());
}
bool ParamTraits<IndexedDBKeyRange>::Read(const Message* m,
@@ -231,9 +231,9 @@ void ParamTraits<IndexedDBKeyRange>::Log(const param_type& p, std::string* l) {
l->append(", upper=");
LogParam(p.upper(), l);
l->append(", lower_open=");
- LogParam(p.lowerOpen(), l);
+ LogParam(p.lower_open(), l);
l->append(", upper_open=");
- LogParam(p.upperOpen(), l);
+ LogParam(p.upper_open(), l);
l->append(")");
}
diff --git a/chromium/content/common/input/gesture_event_stream_validator.cc b/chromium/content/common/input/gesture_event_stream_validator.cc
index eccdbe0079f..6ea29de25ac 100644
--- a/chromium/content/common/input/gesture_event_stream_validator.cc
+++ b/chromium/content/common/input/gesture_event_stream_validator.cc
@@ -5,6 +5,8 @@
#include "content/common/input/gesture_event_stream_validator.h"
#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "content/common/input/web_input_event_traits.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
using blink::WebInputEvent;
@@ -22,6 +24,10 @@ bool GestureEventStreamValidator::Validate(const blink::WebGestureEvent& event,
std::string* error_msg) {
DCHECK(error_msg);
error_msg->clear();
+ if (!WebInputEvent::isGestureEventType(event.type)) {
+ error_msg->append(base::StringPrintf(
+ "Invalid gesture type: %s", WebInputEventTraits::GetName(event.type)));
+ }
switch (event.type) {
case WebInputEvent::GestureScrollBegin:
if (scrolling_)
@@ -31,12 +37,22 @@ bool GestureEventStreamValidator::Validate(const blink::WebGestureEvent& event,
scrolling_ = true;
break;
case WebInputEvent::GestureScrollUpdate:
- case WebInputEvent::GestureScrollUpdateWithoutPropagation:
if (!scrolling_)
error_msg->append("Scroll update outside of scroll\n");
break;
- case WebInputEvent::GestureScrollEnd:
case WebInputEvent::GestureFlingStart:
+ if (event.sourceDevice == blink::WebGestureDeviceTouchscreen &&
+ !event.data.flingStart.velocityX &&
+ !event.data.flingStart.velocityY) {
+ error_msg->append("Zero velocity touchscreen fling\n");
+ }
+ if (!scrolling_)
+ error_msg->append("Fling start outside of scroll\n");
+ if (pinching_)
+ error_msg->append("Flinging while pinching\n");
+ scrolling_ = false;
+ break;
+ case WebInputEvent::GestureScrollEnd:
if (!scrolling_)
error_msg->append("Scroll end outside of scroll\n");
if (pinching_)
@@ -59,7 +75,7 @@ bool GestureEventStreamValidator::Validate(const blink::WebGestureEvent& event,
break;
case WebInputEvent::GestureTapDown:
if (waiting_for_tap_end_)
- error_msg->append("Missing tap end event\n");
+ error_msg->append("Missing tap ending event before TapDown\n");
waiting_for_tap_end_ = true;
break;
case WebInputEvent::GestureTapUnconfirmed:
@@ -72,9 +88,13 @@ bool GestureEventStreamValidator::Validate(const blink::WebGestureEvent& event,
waiting_for_tap_end_ = false;
break;
case WebInputEvent::GestureTap:
+ if (!waiting_for_tap_end_)
+ error_msg->append("Missing TapDown event before Tap\n");
+ waiting_for_tap_end_ = false;
+ break;
case WebInputEvent::GestureDoubleTap:
- // Both Tap and DoubleTap gestures may be synthetically inserted, and do
- // not require a preceding TapDown.
+ // DoubleTap gestures may be synthetically inserted, and do not require a
+ // preceding TapDown.
waiting_for_tap_end_ = false;
break;
default:
diff --git a/chromium/content/common/input/gesture_event_stream_validator.h b/chromium/content/common/input/gesture_event_stream_validator.h
index 8a2bf86a000..f5d536fd2fa 100644
--- a/chromium/content/common/input/gesture_event_stream_validator.h
+++ b/chromium/content/common/input/gesture_event_stream_validator.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_COMMON_INPUT_GESTURE_EVENT_STREAM_VALIDATOR
-#define CONTENT_COMMON_INPUT_GESTURE_EVENT_STREAM_VALIDATOR
+#ifndef CONTENT_COMMON_INPUT_GESTURE_EVENT_STREAM_VALIDATOR_H_
+#define CONTENT_COMMON_INPUT_GESTURE_EVENT_STREAM_VALIDATOR_H_
#include <string>
@@ -36,4 +36,4 @@ class CONTENT_EXPORT GestureEventStreamValidator {
} // namespace content
-#endif // CONTENT_COMMON_INPUT_GESTURE_EVENT_STREAM_VALIDATOR
+#endif // CONTENT_COMMON_INPUT_GESTURE_EVENT_STREAM_VALIDATOR_H_
diff --git a/chromium/content/common/input/gesture_event_stream_validator_unittest.cc b/chromium/content/common/input/gesture_event_stream_validator_unittest.cc
index 857dcfe9375..88484ef372f 100644
--- a/chromium/content/common/input/gesture_event_stream_validator_unittest.cc
+++ b/chromium/content/common/input/gesture_event_stream_validator_unittest.cc
@@ -17,7 +17,12 @@ const blink::WebGestureDevice kDefaultGestureDevice =
blink::WebGestureDeviceTouchscreen;
blink::WebGestureEvent Build(WebInputEvent::Type type) {
- return SyntheticWebGestureEventBuilder::Build(type, kDefaultGestureDevice);
+ blink::WebGestureEvent event =
+ SyntheticWebGestureEventBuilder::Build(type, kDefaultGestureDevice);
+ // Default to providing a (valid) non-zero fling velocity.
+ if (type == WebInputEvent::GestureFlingStart)
+ event.data.flingStart.velocityX = 5;
+ return event;
}
} // namespace
@@ -97,6 +102,17 @@ TEST(GestureEventStreamValidator, InvalidFling) {
event = Build(WebInputEvent::GestureFlingStart);
EXPECT_FALSE(validator.Validate(event, &error_msg));
EXPECT_FALSE(error_msg.empty());
+
+ // Zero velocity.
+ event = Build(WebInputEvent::GestureScrollBegin);
+ EXPECT_TRUE(validator.Validate(event, &error_msg));
+ EXPECT_TRUE(error_msg.empty());
+
+ event = Build(WebInputEvent::GestureFlingStart);
+ event.data.flingStart.velocityX = 0;
+ event.data.flingStart.velocityY = 0;
+ EXPECT_FALSE(validator.Validate(event, &error_msg));
+ EXPECT_FALSE(error_msg.empty());
}
TEST(GestureEventStreamValidator, ValidPinch) {
@@ -181,12 +197,16 @@ TEST(GestureEventStreamValidator, ValidTap) {
EXPECT_TRUE(validator.Validate(event, &error_msg));
EXPECT_TRUE(error_msg.empty());
- // Tap and DoubleTap do not require a TapDown (unlike TapUnconfirmed and
- // TapCancel).
+ event = Build(WebInputEvent::GestureTapDown);
+ EXPECT_TRUE(validator.Validate(event, &error_msg));
+ EXPECT_TRUE(error_msg.empty());
+
event = Build(WebInputEvent::GestureTap);
EXPECT_TRUE(validator.Validate(event, &error_msg));
EXPECT_TRUE(error_msg.empty());
+ // DoubleTap does not require a TapDown (unlike Tap, TapUnconfirmed and
+ // TapCancel).
event = Build(WebInputEvent::GestureDoubleTap);
EXPECT_TRUE(validator.Validate(event, &error_msg));
EXPECT_TRUE(error_msg.empty());
@@ -206,6 +226,10 @@ TEST(GestureEventStreamValidator, InvalidTap) {
EXPECT_FALSE(validator.Validate(event, &error_msg));
EXPECT_FALSE(error_msg.empty());
+ event = Build(WebInputEvent::GestureTap);
+ EXPECT_FALSE(validator.Validate(event, &error_msg));
+ EXPECT_FALSE(error_msg.empty());
+
// TapDown already terminated.
event = Build(WebInputEvent::GestureTapDown);
EXPECT_TRUE(validator.Validate(event, &error_msg));
diff --git a/chromium/content/common/input/input_event_stream_validator.cc b/chromium/content/common/input/input_event_stream_validator.cc
index 85ac42cb5cf..f8a39994b45 100644
--- a/chromium/content/common/input/input_event_stream_validator.cc
+++ b/chromium/content/common/input/input_event_stream_validator.cc
@@ -6,6 +6,7 @@
#include "base/command_line.h"
#include "base/logging.h"
+#include "content/common/input/web_input_event_traits.h"
#include "content/public/common/content_switches.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
@@ -16,7 +17,7 @@ using blink::WebTouchEvent;
namespace content {
InputEventStreamValidator::InputEventStreamValidator()
- : enabled_(CommandLine::ForCurrentProcess()->HasSwitch(
+ : enabled_(base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kValidateInputEventStream)) {
}
@@ -27,7 +28,9 @@ void InputEventStreamValidator::Validate(const WebInputEvent& event) {
if (!enabled_)
return;
- DCHECK(ValidateImpl(event, &error_msg_)) << error_msg_;
+ DCHECK(ValidateImpl(event, &error_msg_))
+ << error_msg_
+ << "\nInvalid Event: " << WebInputEventTraits::ToString(event);
}
bool InputEventStreamValidator::ValidateImpl(const blink::WebInputEvent& event,
diff --git a/chromium/content/common/input/input_event_stream_validator.h b/chromium/content/common/input/input_event_stream_validator.h
index 1ae4c3ac19c..60435b78059 100644
--- a/chromium/content/common/input/input_event_stream_validator.h
+++ b/chromium/content/common/input/input_event_stream_validator.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_COMMON_INPUT_EVENT_STREAM_VALIDATOR
-#define CONTENT_COMMON_INPUT_EVENT_STREAM_VALIDATOR
+#ifndef CONTENT_COMMON_INPUT_INPUT_EVENT_STREAM_VALIDATOR_H_
+#define CONTENT_COMMON_INPUT_INPUT_EVENT_STREAM_VALIDATOR_H_
#include <string>
@@ -38,4 +38,4 @@ class InputEventStreamValidator {
} // namespace content
-#endif // CONTENT_COMMON_INPUT_EVENT_STREAM_VALIDATOR
+#endif // CONTENT_COMMON_INPUT_INPUT_EVENT_STREAM_VALIDATOR_H_
diff --git a/chromium/content/common/input/input_param_traits.cc b/chromium/content/common/input/input_param_traits.cc
index e9aba992a82..1f4b7e4b163 100644
--- a/chromium/content/common/input/input_param_traits.cc
+++ b/chromium/content/common/input/input_param_traits.cc
@@ -6,6 +6,7 @@
#include "content/common/content_param_traits.h"
#include "content/common/input/synthetic_pinch_gesture_params.h"
+#include "content/common/input/synthetic_smooth_drag_gesture_params.h"
#include "content/common/input/synthetic_smooth_scroll_gesture_params.h"
#include "content/common/input/web_input_event_traits.h"
#include "content/common/input_messages.h"
@@ -62,6 +63,10 @@ void ParamTraits<content::SyntheticGesturePacket>::Write(Message* m,
WriteParam(m, *content::SyntheticSmoothScrollGestureParams::Cast(
p.gesture_params()));
break;
+ case content::SyntheticGestureParams::SMOOTH_DRAG_GESTURE:
+ WriteParam(m, *content::SyntheticSmoothDragGestureParams::Cast(
+ p.gesture_params()));
+ break;
case content::SyntheticGestureParams::PINCH_GESTURE:
WriteParam(m, *content::SyntheticPinchGestureParams::Cast(
p.gesture_params()));
@@ -86,6 +91,10 @@ bool ParamTraits<content::SyntheticGesturePacket>::Read(const Message* m,
ReadGestureParams<content::SyntheticSmoothScrollGestureParams>(m,
iter);
break;
+ case content::SyntheticGestureParams::SMOOTH_DRAG_GESTURE:
+ gesture_params =
+ ReadGestureParams<content::SyntheticSmoothDragGestureParams>(m, iter);
+ break;
case content::SyntheticGestureParams::PINCH_GESTURE:
gesture_params =
ReadGestureParams<content::SyntheticPinchGestureParams>(m, iter);
@@ -112,6 +121,11 @@ void ParamTraits<content::SyntheticGesturePacket>::Log(const param_type& p,
p.gesture_params()),
l);
break;
+ case content::SyntheticGestureParams::SMOOTH_DRAG_GESTURE:
+ LogParam(
+ *content::SyntheticSmoothDragGestureParams::Cast(p.gesture_params()),
+ l);
+ break;
case content::SyntheticGestureParams::PINCH_GESTURE:
LogParam(
*content::SyntheticPinchGestureParams::Cast(p.gesture_params()),
diff --git a/chromium/content/common/input/input_param_traits_unittest.cc b/chromium/content/common/input/input_param_traits_unittest.cc
index cbfd9aa2bcc..b70b19c966c 100644
--- a/chromium/content/common/input/input_param_traits_unittest.cc
+++ b/chromium/content/common/input/input_param_traits_unittest.cc
@@ -7,6 +7,7 @@
#include "content/common/input/input_event.h"
#include "content/common/input/synthetic_gesture_params.h"
#include "content/common/input/synthetic_pinch_gesture_params.h"
+#include "content/common/input/synthetic_smooth_drag_gesture_params.h"
#include "content/common/input/synthetic_smooth_scroll_gesture_params.h"
#include "content/common/input_messages.h"
#include "ipc/ipc_message.h"
@@ -43,11 +44,21 @@ class InputParamTraitsTest : public testing::Test {
EXPECT_EQ(a->anchor, b->anchor);
EXPECT_EQ(a->distances.size(), b->distances.size());
for (size_t i = 0; i < a->distances.size(); i++)
- EXPECT_EQ(a->distances[i], b->distances[i]);
+ EXPECT_EQ(a->distances[i], b->distances[i]);
EXPECT_EQ(a->prevent_fling, b->prevent_fling);
EXPECT_EQ(a->speed_in_pixels_s, b->speed_in_pixels_s);
}
+ static void Compare(const SyntheticSmoothDragGestureParams* a,
+ const SyntheticSmoothDragGestureParams* b) {
+ EXPECT_EQ(a->gesture_source_type, b->gesture_source_type);
+ EXPECT_EQ(a->start_point, b->start_point);
+ EXPECT_EQ(a->distances.size(), b->distances.size());
+ for (size_t i = 0; i < a->distances.size(); i++)
+ EXPECT_EQ(a->distances[i], b->distances[i]);
+ EXPECT_EQ(a->speed_in_pixels_s, b->speed_in_pixels_s);
+ }
+
static void Compare(const SyntheticPinchGestureParams* a,
const SyntheticPinchGestureParams* b) {
EXPECT_EQ(a->gesture_source_type, b->gesture_source_type);
@@ -77,6 +88,10 @@ class InputParamTraitsTest : public testing::Test {
Compare(SyntheticSmoothScrollGestureParams::Cast(a->gesture_params()),
SyntheticSmoothScrollGestureParams::Cast(b->gesture_params()));
break;
+ case SyntheticGestureParams::SMOOTH_DRAG_GESTURE:
+ Compare(SyntheticSmoothDragGestureParams::Cast(a->gesture_params()),
+ SyntheticSmoothDragGestureParams::Cast(b->gesture_params()));
+ break;
case SyntheticGestureParams::PINCH_GESTURE:
Compare(SyntheticPinchGestureParams::Cast(a->gesture_params()),
SyntheticPinchGestureParams::Cast(b->gesture_params()));
diff --git a/chromium/content/common/input/synthetic_gesture_params.h b/chromium/content/common/input/synthetic_gesture_params.h
index 3607bcdfdae..1c40ca98fd2 100644
--- a/chromium/content/common/input/synthetic_gesture_params.h
+++ b/chromium/content/common/input/synthetic_gesture_params.h
@@ -45,6 +45,7 @@ struct CONTENT_EXPORT SyntheticGestureParams {
enum GestureType {
SMOOTH_SCROLL_GESTURE,
+ SMOOTH_DRAG_GESTURE,
PINCH_GESTURE,
TAP_GESTURE,
SYNTHETIC_GESTURE_TYPE_MAX = TAP_GESTURE
diff --git a/chromium/content/common/input/synthetic_pinch_gesture_params.h b/chromium/content/common/input/synthetic_pinch_gesture_params.h
index ba15cafbf98..12942497372 100644
--- a/chromium/content/common/input/synthetic_pinch_gesture_params.h
+++ b/chromium/content/common/input/synthetic_pinch_gesture_params.h
@@ -7,7 +7,7 @@
#include "content/common/content_export.h"
#include "content/common/input/synthetic_gesture_params.h"
-#include "ui/gfx/point.h"
+#include "ui/gfx/geometry/point.h"
namespace content {
@@ -22,8 +22,8 @@ struct CONTENT_EXPORT SyntheticPinchGestureParams
GestureType GetGestureType() const override;
float scale_factor;
- gfx::Point anchor;
- int relative_pointer_speed_in_pixels_s;
+ gfx::PointF anchor;
+ float relative_pointer_speed_in_pixels_s;
static const SyntheticPinchGestureParams* Cast(
const SyntheticGestureParams* gesture_params);
diff --git a/chromium/content/common/input/synthetic_smooth_drag_gesture_params.cc b/chromium/content/common/input/synthetic_smooth_drag_gesture_params.cc
new file mode 100644
index 00000000000..f5adc46a5a8
--- /dev/null
+++ b/chromium/content/common/input/synthetic_smooth_drag_gesture_params.cc
@@ -0,0 +1,43 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/common/input/synthetic_smooth_drag_gesture_params.h"
+
+#include "base/logging.h"
+
+namespace content {
+namespace {
+
+const float kDefaultSpeedInPixelsPerSec = 800;
+
+} // namespace
+
+SyntheticSmoothDragGestureParams::SyntheticSmoothDragGestureParams()
+ : speed_in_pixels_s(kDefaultSpeedInPixelsPerSec) {
+}
+
+SyntheticSmoothDragGestureParams::SyntheticSmoothDragGestureParams(
+ const SyntheticSmoothDragGestureParams& other)
+ : SyntheticGestureParams(other),
+ start_point(other.start_point),
+ distances(other.distances),
+ speed_in_pixels_s(other.speed_in_pixels_s) {
+}
+
+SyntheticSmoothDragGestureParams::~SyntheticSmoothDragGestureParams() {
+}
+
+SyntheticGestureParams::GestureType
+SyntheticSmoothDragGestureParams::GetGestureType() const {
+ return SMOOTH_DRAG_GESTURE;
+}
+
+const SyntheticSmoothDragGestureParams* SyntheticSmoothDragGestureParams::Cast(
+ const SyntheticGestureParams* gesture_params) {
+ DCHECK(gesture_params);
+ DCHECK_EQ(SMOOTH_DRAG_GESTURE, gesture_params->GetGestureType());
+ return static_cast<const SyntheticSmoothDragGestureParams*>(gesture_params);
+}
+
+} // namespace content
diff --git a/chromium/content/common/input/synthetic_smooth_drag_gesture_params.h b/chromium/content/common/input/synthetic_smooth_drag_gesture_params.h
new file mode 100644
index 00000000000..11387d8d6cd
--- /dev/null
+++ b/chromium/content/common/input/synthetic_smooth_drag_gesture_params.h
@@ -0,0 +1,37 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_COMMON_INPUT_SYNTHETIC_SMOOTH_DRAG_GESTURE_PARAMS_H_
+#define CONTENT_COMMON_INPUT_SYNTHETIC_SMOOTH_DRAG_GESTURE_PARAMS_H_
+
+#include <vector>
+
+#include "content/common/content_export.h"
+#include "content/common/input/synthetic_gesture_params.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/vector2d.h"
+
+namespace content {
+
+struct CONTENT_EXPORT SyntheticSmoothDragGestureParams
+ : public SyntheticGestureParams {
+ public:
+ SyntheticSmoothDragGestureParams();
+ SyntheticSmoothDragGestureParams(
+ const SyntheticSmoothDragGestureParams& other);
+ ~SyntheticSmoothDragGestureParams() override;
+
+ GestureType GetGestureType() const override;
+
+ gfx::PointF start_point;
+ std::vector<gfx::Vector2dF> distances;
+ float speed_in_pixels_s;
+
+ static const SyntheticSmoothDragGestureParams* Cast(
+ const SyntheticGestureParams* gesture_params);
+};
+
+} // namespace content
+
+#endif // CONTENT_COMMON_INPUT_SYNTHETIC_SMOOTH_DRAG_GESTURE_PARAMS_H_
diff --git a/chromium/content/common/input/synthetic_smooth_scroll_gesture_params.cc b/chromium/content/common/input/synthetic_smooth_scroll_gesture_params.cc
index 35c78c16294..8e1c9748270 100644
--- a/chromium/content/common/input/synthetic_smooth_scroll_gesture_params.cc
+++ b/chromium/content/common/input/synthetic_smooth_scroll_gesture_params.cc
@@ -9,7 +9,7 @@
namespace content {
namespace {
-const int kDefaultSpeedInPixelsS = 800;
+const float kDefaultSpeedInPixelsS = 800;
} // namespace
diff --git a/chromium/content/common/input/synthetic_smooth_scroll_gesture_params.h b/chromium/content/common/input/synthetic_smooth_scroll_gesture_params.h
index 05f7357c6e5..34d0f613e1f 100644
--- a/chromium/content/common/input/synthetic_smooth_scroll_gesture_params.h
+++ b/chromium/content/common/input/synthetic_smooth_scroll_gesture_params.h
@@ -9,8 +9,8 @@
#include "content/common/content_export.h"
#include "content/common/input/synthetic_gesture_params.h"
-#include "ui/gfx/point.h"
-#include "ui/gfx/vector2d.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/vector2d.h"
namespace content {
@@ -24,10 +24,10 @@ struct CONTENT_EXPORT SyntheticSmoothScrollGestureParams
GestureType GetGestureType() const override;
- gfx::Point anchor;
- std::vector<gfx::Vector2d> distances; // Positive X/Y to scroll left/up.
+ gfx::PointF anchor;
+ std::vector<gfx::Vector2dF> distances; // Positive X/Y to scroll left/up.
bool prevent_fling; // Defaults to true.
- int speed_in_pixels_s;
+ float speed_in_pixels_s;
static const SyntheticSmoothScrollGestureParams* Cast(
const SyntheticGestureParams* gesture_params);
diff --git a/chromium/content/common/input/synthetic_tap_gesture_params.h b/chromium/content/common/input/synthetic_tap_gesture_params.h
index c4ca5766ed4..6011094230b 100644
--- a/chromium/content/common/input/synthetic_tap_gesture_params.h
+++ b/chromium/content/common/input/synthetic_tap_gesture_params.h
@@ -7,7 +7,7 @@
#include "content/common/content_export.h"
#include "content/common/input/synthetic_gesture_params.h"
-#include "ui/gfx/point.h"
+#include "ui/gfx/geometry/point.h"
namespace content {
@@ -20,8 +20,8 @@ struct CONTENT_EXPORT SyntheticTapGestureParams
GestureType GetGestureType() const override;
- gfx::Point position;
- int duration_ms;
+ gfx::PointF position;
+ float duration_ms;
static const SyntheticTapGestureParams* Cast(
const SyntheticGestureParams* gesture_params);
@@ -29,4 +29,4 @@ struct CONTENT_EXPORT SyntheticTapGestureParams
} // namespace content
-#endif // CONTENT_COMMON_INPUT_SYNTHETIC_PINCH_GESTURE_PARAMS_H_
+#endif // CONTENT_COMMON_INPUT_SYNTHETIC_TAP_GESTURE_PARAMS_H_
diff --git a/chromium/content/common/input/synthetic_web_input_event_builders.cc b/chromium/content/common/input/synthetic_web_input_event_builders.cc
index d3addb67918..ba6cda093d0 100644
--- a/chromium/content/common/input/synthetic_web_input_event_builders.cc
+++ b/chromium/content/common/input/synthetic_web_input_event_builders.cc
@@ -6,6 +6,7 @@
#include "base/logging.h"
#include "content/common/input/web_touch_event_traits.h"
+#include "ui/events/base_event_utils.h"
#include "ui/events/keycodes/keyboard_codes.h"
namespace content {
@@ -68,6 +69,7 @@ WebMouseWheelEvent SyntheticWebMouseWheelEventBuilder::Build(float dx,
result.wheelTicksY = dy > 0.0f ? 1.0f : -1.0f;
result.modifiers = modifiers;
result.hasPreciseScrollingDeltas = precise;
+ result.canScroll = true;
return result;
}
@@ -110,9 +112,10 @@ WebGestureEvent SyntheticWebGestureEventBuilder::BuildScrollBegin(
WebGestureEvent SyntheticWebGestureEventBuilder::BuildScrollUpdate(
float dx,
float dy,
- int modifiers) {
- WebGestureEvent result = Build(WebInputEvent::GestureScrollUpdate,
- blink::WebGestureDeviceTouchscreen);
+ int modifiers,
+ blink::WebGestureDevice source_device) {
+ WebGestureEvent result =
+ Build(WebInputEvent::GestureScrollUpdate, source_device);
result.data.scrollUpdate.deltaX = dx;
result.data.scrollUpdate.deltaY = dy;
result.modifiers = modifiers;
@@ -148,6 +151,7 @@ WebGestureEvent SyntheticWebGestureEventBuilder::BuildFling(
}
SyntheticWebTouchEvent::SyntheticWebTouchEvent() : WebTouchEvent() {
+ uniqueTouchEventId = ui::GetNextTouchEventId();
SetTimestamp(base::TimeTicks::Now() - base::TimeTicks());
}
@@ -163,6 +167,7 @@ void SyntheticWebTouchEvent::ResetPoints() {
}
touchesLength = point;
type = WebInputEvent::Undefined;
+ causesScrollingIfUncanceled = false;
}
int SyntheticWebTouchEvent::PressPoint(float x, float y) {
@@ -174,6 +179,8 @@ int SyntheticWebTouchEvent::PressPoint(float x, float y) {
point.position.y = point.screenPosition.y = y;
point.state = WebTouchPoint::StatePressed;
point.radiusX = point.radiusY = 1.f;
+ point.rotationAngle = 1.f;
+ point.force = 1.f;
++touchesLength;
WebTouchEventTraits::ResetType(
WebInputEvent::TouchStart, timeStampSeconds, this);
@@ -181,7 +188,11 @@ int SyntheticWebTouchEvent::PressPoint(float x, float y) {
}
void SyntheticWebTouchEvent::MovePoint(int index, float x, float y) {
- CHECK(index >= 0 && index < touchesLengthCap);
+ CHECK_GE(index, 0);
+ CHECK_LT(index, touchesLengthCap);
+ // Always set this bit to avoid otherwise unexpected touchmove suppression.
+ // The caller can opt-out explicitly, if necessary.
+ causesScrollingIfUncanceled = true;
WebTouchPoint& point = touches[index];
point.position.x = point.screenPosition.x = x;
point.position.y = point.screenPosition.y = y;
@@ -191,14 +202,16 @@ void SyntheticWebTouchEvent::MovePoint(int index, float x, float y) {
}
void SyntheticWebTouchEvent::ReleasePoint(int index) {
- CHECK(index >= 0 && index < touchesLengthCap);
+ CHECK_GE(index, 0);
+ CHECK_LT(index, touchesLengthCap);
touches[index].state = WebTouchPoint::StateReleased;
WebTouchEventTraits::ResetType(
WebInputEvent::TouchEnd, timeStampSeconds, this);
}
void SyntheticWebTouchEvent::CancelPoint(int index) {
- CHECK(index >= 0 && index < touchesLengthCap);
+ CHECK_GE(index, 0);
+ CHECK_LT(index, touchesLengthCap);
touches[index].state = WebTouchPoint::StateCancelled;
WebTouchEventTraits::ResetType(
WebInputEvent::TouchCancel, timeStampSeconds, this);
diff --git a/chromium/content/common/input/synthetic_web_input_event_builders.h b/chromium/content/common/input/synthetic_web_input_event_builders.h
index f16830d2cba..ff8d1934e8d 100644
--- a/chromium/content/common/input/synthetic_web_input_event_builders.h
+++ b/chromium/content/common/input/synthetic_web_input_event_builders.h
@@ -43,9 +43,11 @@ class CONTENT_EXPORT SyntheticWebGestureEventBuilder {
blink::WebGestureDevice source_device);
static blink::WebGestureEvent BuildScrollBegin(float dx_hint,
float dy_hint);
- static blink::WebGestureEvent BuildScrollUpdate(float dx,
- float dy,
- int modifiers);
+ static blink::WebGestureEvent BuildScrollUpdate(
+ float dx,
+ float dy,
+ int modifiers,
+ blink::WebGestureDevice source_device);
static blink::WebGestureEvent BuildPinchUpdate(
float scale,
float anchor_x,
diff --git a/chromium/content/common/input/touch_action.h b/chromium/content/common/input/touch_action.h
index 5eb09f9ada2..89f000df7bd 100644
--- a/chromium/content/common/input/touch_action.h
+++ b/chromium/content/common/input/touch_action.h
@@ -17,17 +17,25 @@ enum TouchAction {
// No scrolling or zooming allowed.
TOUCH_ACTION_NONE = 1 << 0,
- TOUCH_ACTION_PAN_X = 1 << 1,
+ TOUCH_ACTION_PAN_LEFT = 1 << 1,
- TOUCH_ACTION_PAN_Y = 1 << 2,
+ TOUCH_ACTION_PAN_RIGHT = 1 << 2,
+
+ TOUCH_ACTION_PAN_X = TOUCH_ACTION_PAN_LEFT | TOUCH_ACTION_PAN_RIGHT,
+
+ TOUCH_ACTION_PAN_UP = 1 << 3,
+
+ TOUCH_ACTION_PAN_DOWN = 1 << 4,
+
+ TOUCH_ACTION_PAN_Y = TOUCH_ACTION_PAN_UP | TOUCH_ACTION_PAN_DOWN,
TOUCH_ACTION_PAN_X_Y = TOUCH_ACTION_PAN_X | TOUCH_ACTION_PAN_Y,
- TOUCH_ACTION_PINCH_ZOOM = 1 << 3,
+ TOUCH_ACTION_PINCH_ZOOM = 1 << 5,
TOUCH_ACTION_MANIPULATION = TOUCH_ACTION_PAN_X_Y | TOUCH_ACTION_PINCH_ZOOM,
- TOUCH_ACTION_MAX = (1 << 4) - 1
+ TOUCH_ACTION_MAX = (1 << 6) - 1
};
} // namespace content
diff --git a/chromium/content/common/input/touch_event_stream_validator.cc b/chromium/content/common/input/touch_event_stream_validator.cc
index 3310036c5b4..4c7598901dd 100644
--- a/chromium/content/common/input/touch_event_stream_validator.cc
+++ b/chromium/content/common/input/touch_event_stream_validator.cc
@@ -5,8 +5,11 @@
#include "content/common/input/touch_event_stream_validator.h"
#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "content/common/input/web_input_event_traits.h"
#include "content/common/input/web_touch_event_traits.h"
+using base::StringPrintf;
using blink::WebInputEvent;
using blink::WebTouchEvent;
using blink::WebTouchPoint;
@@ -22,6 +25,16 @@ const WebTouchPoint* FindTouchPoint(const WebTouchEvent& event, int id) {
return NULL;
}
+std::string TouchPointIdsToString(const WebTouchEvent& event) {
+ std::stringstream ss;
+ for (unsigned i = 0; i < event.touchesLength; ++i) {
+ if (i)
+ ss << ",";
+ ss << event.touches[i].id;
+ }
+ return ss.str();
+}
+
} // namespace
TouchEventStreamValidator::TouchEventStreamValidator() {
@@ -43,8 +56,10 @@ bool TouchEventStreamValidator::Validate(const WebTouchEvent& event,
return false;
}
- if (!WebInputEvent::isTouchEventType(event.type))
- error_msg->append("Touch event has invalid type.\n");
+ if (!WebInputEvent::isTouchEventType(event.type)) {
+ error_msg->append(StringPrintf("Touch event has invalid type: %s\n",
+ WebInputEventTraits::GetName(event.type)));
+ }
// Allow "hard" restarting of touch stream validation. This is necessary
// in cases where touch event forwarding ceases in response to the event ack
@@ -60,8 +75,11 @@ bool TouchEventStreamValidator::Validate(const WebTouchEvent& event,
continue;
const WebTouchPoint* point = FindTouchPoint(event, previous_point.id);
- if (!point)
- error_msg->append("Previously active touch point not in new event.\n");
+ if (!point) {
+ error_msg->append(StringPrintf(
+ "Previously active touch point (id=%d) not in new event (ids=%s).\n",
+ previous_point.id, TouchPointIdsToString(event).c_str()));
+ }
}
bool found_valid_state_for_type = false;
@@ -73,55 +91,73 @@ bool TouchEventStreamValidator::Validate(const WebTouchEvent& event,
// The point should exist in the previous event if it is not a new point.
if (!previous_point) {
if (point.state != WebTouchPoint::StatePressed)
- error_msg->append("Active touch point not found in previous event.\n");
+ error_msg->append(StringPrintf(
+ "Active touch point (id=%d) not in previous event (ids=%s).\n",
+ point.id, TouchPointIdsToString(previous_event).c_str()));
} else {
if (point.state == WebTouchPoint::StatePressed &&
previous_point->state != WebTouchPoint::StateCancelled &&
previous_point->state != WebTouchPoint::StateReleased) {
- error_msg->append("Pressed touch point id already exists.\n");
+ error_msg->append(StringPrintf(
+ "Pressed touch point (id=%d) already exists in previous event "
+ "(ids=%s).\n",
+ point.id, TouchPointIdsToString(previous_event).c_str()));
}
}
switch (point.state) {
case WebTouchPoint::StateUndefined:
- error_msg->append("Undefined WebTouchPoint state.\n");
+ error_msg->append(
+ StringPrintf("Undefined touch point state (id=%d).\n", point.id));
break;
case WebTouchPoint::StateReleased:
- if (event.type != WebInputEvent::TouchEnd)
- error_msg->append("Released touch point outside touchend.\n");
- else
+ if (event.type != WebInputEvent::TouchEnd) {
+ error_msg->append(StringPrintf(
+ "Released touch point (id=%d) outside touchend.\n", point.id));
+ } else {
found_valid_state_for_type = true;
+ }
break;
case WebTouchPoint::StatePressed:
- if (event.type != WebInputEvent::TouchStart)
- error_msg->append("Pressed touch point outside touchstart.\n");
- else
+ if (event.type != WebInputEvent::TouchStart) {
+ error_msg->append(StringPrintf(
+ "Pressed touch point (id=%d) outside touchstart.\n", point.id));
+ } else {
found_valid_state_for_type = true;
+ }
break;
case WebTouchPoint::StateMoved:
- if (event.type != WebInputEvent::TouchMove)
- error_msg->append("Moved touch point outside touchmove.\n");
- else
+ if (event.type != WebInputEvent::TouchMove) {
+ error_msg->append(StringPrintf(
+ "Moved touch point (id=%d) outside touchmove.\n", point.id));
+ } else {
found_valid_state_for_type = true;
+ }
break;
case WebTouchPoint::StateStationary:
break;
case WebTouchPoint::StateCancelled:
- if (event.type != WebInputEvent::TouchCancel)
- error_msg->append("Cancelled touch point outside touchcancel.\n");
- else
+ if (event.type != WebInputEvent::TouchCancel) {
+ error_msg->append(StringPrintf(
+ "Cancelled touch point (id=%d) outside touchcancel.\n",
+ point.id));
+ } else {
found_valid_state_for_type = true;
+ }
break;
}
}
- if (!found_valid_state_for_type)
- error_msg->append("No valid touch point corresponding to event type.");
+ if (!found_valid_state_for_type) {
+ error_msg->append(
+ StringPrintf("No valid touch point corresponding to event type: %s\n",
+ WebInputEventTraits::GetName(event.type)));
+ }
return error_msg->empty();
}
diff --git a/chromium/content/common/input/touch_event_stream_validator.h b/chromium/content/common/input/touch_event_stream_validator.h
index ec112fd8e97..95bc10626df 100644
--- a/chromium/content/common/input/touch_event_stream_validator.h
+++ b/chromium/content/common/input/touch_event_stream_validator.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_COMMON_INPUT_TOUCH_EVENT_STREAM_VALIDATOR
-#define CONTENT_COMMON_INPUT_TOUCH_EVENT_STREAM_VALIDATOR
+#ifndef CONTENT_COMMON_INPUT_TOUCH_EVENT_STREAM_VALIDATOR_H_
+#define CONTENT_COMMON_INPUT_TOUCH_EVENT_STREAM_VALIDATOR_H_
#include <string>
@@ -31,4 +31,4 @@ class CONTENT_EXPORT TouchEventStreamValidator {
} // namespace content
-#endif // CONTENT_COMMON_INPUT_TOUCH_EVENT_STREAM_VALIDATOR
+#endif // CONTENT_COMMON_INPUT_TOUCH_EVENT_STREAM_VALIDATOR_H_
diff --git a/chromium/content/common/input/web_input_event_traits.cc b/chromium/content/common/input/web_input_event_traits.cc
index 4de53c70ebc..b2346401ad4 100644
--- a/chromium/content/common/input/web_input_event_traits.cc
+++ b/chromium/content/common/input/web_input_event_traits.cc
@@ -58,7 +58,7 @@ void ApppendEventDetails(const WebMouseWheelEvent& event, std::string* result) {
StringAppendF(result,
"{\n Delta: (%f, %f)\n WheelTicks: (%f, %f)\n Accel: (%f, %f)\n"
" ScrollByPage: %d\n HasPreciseScrollingDeltas: %d\n"
- " Phase: (%d, %d)\n CanRubberband: (%d, %d)\n}",
+ " Phase: (%d, %d)\n CanRubberband: (%d, %d)\n CanScroll: %d\n}",
event.deltaX,
event.deltaY,
event.wheelTicksX,
@@ -70,13 +70,14 @@ void ApppendEventDetails(const WebMouseWheelEvent& event, std::string* result) {
event.phase,
event.momentumPhase,
event.canRubberbandLeft,
- event.canRubberbandRight);
+ event.canRubberbandRight,
+ event.canScroll);
}
void ApppendEventDetails(const WebGestureEvent& event, std::string* result) {
StringAppendF(result,
"{\n Pos: (%d, %d)\n GlobalPos: (%d, %d)\n SourceDevice: %d\n"
- " RawData: (%f, %f, %f, %f)\n}",
+ " RawData: (%f, %f, %f, %f, %d)\n}",
event.x,
event.y,
event.globalX,
@@ -85,7 +86,8 @@ void ApppendEventDetails(const WebGestureEvent& event, std::string* result) {
event.data.scrollUpdate.deltaX,
event.data.scrollUpdate.deltaY,
event.data.scrollUpdate.velocityX,
- event.data.scrollUpdate.velocityY);
+ event.data.scrollUpdate.velocityY,
+ event.data.scrollUpdate.previousUpdateInSequencePrevented);
}
void ApppendTouchPointDetails(const WebTouchPoint& point, std::string* result) {
@@ -106,9 +108,12 @@ void ApppendTouchPointDetails(const WebTouchPoint& point, std::string* result) {
void ApppendEventDetails(const WebTouchEvent& event, std::string* result) {
StringAppendF(result,
- "{\n Touches: %u, Cancelable: %d,\n[\n",
+ "{\n Touches: %u, Cancelable: %d, CausesScrolling: %d,"
+ " uniqueTouchEventId: %u\n[\n",
event.touchesLength,
- event.cancelable);
+ event.cancelable,
+ event.causesScrollingIfUncanceled,
+ static_cast<uint32>(event.uniqueTouchEventId));
for (unsigned i = 0; i < event.touchesLength; ++i)
ApppendTouchPointDetails(event.touches[i], result);
result->append(" ]\n}");
@@ -147,7 +152,8 @@ bool CanCoalesce(const WebMouseWheelEvent& event_to_coalesce,
event.phase == event_to_coalesce.phase &&
event.momentumPhase == event_to_coalesce.momentumPhase &&
event.hasPreciseScrollingDeltas ==
- event_to_coalesce.hasPreciseScrollingDeltas;
+ event_to_coalesce.hasPreciseScrollingDeltas &&
+ event.canScroll == event_to_coalesce.canScroll;
}
float GetUnacceleratedDelta(float accelerated_delta, float acceleration_ratio) {
@@ -203,8 +209,8 @@ bool CanCoalesce(const WebTouchEvent& event_to_coalesce,
event.touchesLength > WebTouchEvent::touchesLengthCap)
return false;
- COMPILE_ASSERT(WebTouchEvent::touchesLengthCap <= sizeof(int32_t) * 8U,
- suboptimal_touches_length_cap_size);
+ static_assert(WebTouchEvent::touchesLengthCap <= sizeof(int32_t) * 8U,
+ "suboptimal touchesLengthCap size");
// Ensure that we have a 1-to-1 mapping of pointer ids between touches.
std::bitset<WebTouchEvent::touchesLengthCap> unmatched_event_touches(
(1 << event.touchesLength) - 1);
@@ -235,6 +241,7 @@ void Coalesce(const WebTouchEvent& event_to_coalesce, WebTouchEvent* event) {
if (old_event.touches[i_old].state == blink::WebTouchPoint::StateMoved)
event->touches[i].state = blink::WebTouchPoint::StateMoved;
}
+ event->causesScrollingIfUncanceled |= old_event.causesScrollingIfUncanceled;
}
bool CanCoalesce(const WebGestureEvent& event_to_coalesce,
@@ -265,6 +272,9 @@ void Coalesce(const WebGestureEvent& event_to_coalesce,
event_to_coalesce.data.scrollUpdate.deltaX;
event->data.scrollUpdate.deltaY +=
event_to_coalesce.data.scrollUpdate.deltaY;
+ DCHECK_EQ(
+ event->data.scrollUpdate.previousUpdateInSequencePrevented,
+ event_to_coalesce.data.scrollUpdate.previousUpdateInSequencePrevented);
} else if (event->type == WebInputEvent::GesturePinchUpdate) {
event->data.pinchUpdate.scale *= event_to_coalesce.data.pinchUpdate.scale;
// Ensure the scale remains bounded above 0 and below Infinity so that
diff --git a/chromium/content/common/input/web_input_event_traits_unittest.cc b/chromium/content/common/input/web_input_event_traits_unittest.cc
index 7a7cb7ff8b3..62417dba063 100644
--- a/chromium/content/common/input/web_input_event_traits_unittest.cc
+++ b/chromium/content/common/input/web_input_event_traits_unittest.cc
@@ -51,6 +51,17 @@ class WebInputEventTraitsTest : public testing::Test {
event.y = y;
return event;
}
+
+ static WebMouseWheelEvent CreateMouseWheel(float deltaX,
+ float deltaY,
+ bool canScroll) {
+ WebMouseWheelEvent event;
+ event.type = WebInputEvent::MouseWheel;
+ event.deltaX = deltaX;
+ event.deltaY = deltaY;
+ event.canScroll = canScroll;
+ return event;
+ }
};
TEST_F(WebInputEventTraitsTest, TouchEventCoalescing) {
@@ -162,6 +173,31 @@ TEST_F(WebInputEventTraitsTest, PinchEventCoalescing) {
EXPECT_EQ(numeric_limits<float>::max(), pinch1.data.pinchUpdate.scale);
}
+TEST_F(WebInputEventTraitsTest, WebMouseWheelEventCoalescing) {
+ WebMouseWheelEvent mouse_wheel_0 =
+ CreateMouseWheel(1, 1, true);
+ WebMouseWheelEvent mouse_wheel_1 =
+ CreateMouseWheel(2, 2, true);
+
+ // WebMouseWheelEvent objects with same values except different deltaX and
+ // deltaY should coalesce.
+ EXPECT_TRUE(WebInputEventTraits::CanCoalesce(mouse_wheel_0, mouse_wheel_1));
+
+ mouse_wheel_0 = CreateMouseWheel(1, 1, true);
+ mouse_wheel_1 = CreateMouseWheel(1, 1, false);
+
+ // WebMouseWheelEvent objects with different canScroll values should not
+ // coalesce.
+ EXPECT_FALSE(WebInputEventTraits::CanCoalesce(mouse_wheel_0, mouse_wheel_1));
+
+ // WebMouseWheelEvent objects with different modifiers should not coalesce.
+ mouse_wheel_0 = CreateMouseWheel(1, 1, true);
+ mouse_wheel_1 = CreateMouseWheel(1, 1, true);
+ mouse_wheel_0.modifiers = blink::WebInputEvent::ControlKey;
+ mouse_wheel_1.modifiers = blink::WebInputEvent::ShiftKey;
+ EXPECT_FALSE(WebInputEventTraits::CanCoalesce(mouse_wheel_0, mouse_wheel_1));
+}
+
// Very basic smoke test to ensure stringification doesn't explode.
TEST_F(WebInputEventTraitsTest, ToString) {
WebKeyboardEvent key;
diff --git a/chromium/content/common/input_messages.h b/chromium/content/common/input_messages.h
index 95663f75a34..80d30430ded 100644
--- a/chromium/content/common/input_messages.h
+++ b/chromium/content/common/input_messages.h
@@ -17,6 +17,7 @@
#include "content/common/input/synthetic_gesture_packet.h"
#include "content/common/input/synthetic_gesture_params.h"
#include "content/common/input/synthetic_pinch_gesture_params.h"
+#include "content/common/input/synthetic_smooth_drag_gesture_params.h"
#include "content/common/input/synthetic_smooth_scroll_gesture_params.h"
#include "content/common/input/synthetic_tap_gesture_params.h"
#include "content/common/input/touch_action.h"
@@ -24,11 +25,11 @@
#include "ipc/ipc_message_macros.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
#include "ui/events/ipc/latency_info_param_traits.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/vector2d_f.h"
#include "ui/gfx/ipc/gfx_param_traits.h"
-#include "ui/gfx/point.h"
#include "ui/gfx/range/range.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/vector2d_f.h"
#undef IPC_MESSAGE_EXPORT
#define IPC_MESSAGE_EXPORT CONTENT_EXPORT
@@ -77,6 +78,13 @@ IPC_STRUCT_TRAITS_BEGIN(content::SyntheticGestureParams)
IPC_STRUCT_TRAITS_MEMBER(gesture_source_type)
IPC_STRUCT_TRAITS_END()
+IPC_STRUCT_TRAITS_BEGIN(content::SyntheticSmoothDragGestureParams)
+ IPC_STRUCT_TRAITS_PARENT(content::SyntheticGestureParams)
+ IPC_STRUCT_TRAITS_MEMBER(start_point)
+ IPC_STRUCT_TRAITS_MEMBER(distances)
+ IPC_STRUCT_TRAITS_MEMBER(speed_in_pixels_s)
+IPC_STRUCT_TRAITS_END()
+
IPC_STRUCT_TRAITS_BEGIN(content::SyntheticSmoothScrollGestureParams)
IPC_STRUCT_TRAITS_PARENT(content::SyntheticGestureParams)
IPC_STRUCT_TRAITS_MEMBER(anchor)
@@ -162,6 +170,9 @@ IPC_MESSAGE_ROUTED2(InputMsg_ExecuteEditCommand,
std::string, /* name */
std::string /* value */)
+// Message payload is the name of a WebCore edit command to execute.
+IPC_MESSAGE_ROUTED1(InputMsg_ExecuteNoValueEditCommand, std::string /* name */)
+
IPC_MESSAGE_ROUTED0(InputMsg_MouseCaptureLost)
// TODO(darin): figure out how this meshes with RestoreFocus
@@ -242,6 +253,9 @@ IPC_MESSAGE_ROUTED1(InputHostMsg_SetTouchAction,
IPC_MESSAGE_ROUTED1(InputHostMsg_DidOverscroll,
content::DidOverscrollParams /* params */)
+// Sent by the compositor when a fling animation is stopped.
+IPC_MESSAGE_ROUTED0(InputHostMsg_DidStopFlinging)
+
// Acknowledges receipt of a InputMsg_MoveCaret message.
IPC_MESSAGE_ROUTED0(InputHostMsg_MoveCaret_ACK)
@@ -254,15 +268,11 @@ IPC_MESSAGE_ROUTED0(InputHostMsg_SelectRange_ACK)
// Required for cancelling an ongoing input method composition.
IPC_MESSAGE_ROUTED0(InputHostMsg_ImeCancelComposition)
-#if defined(OS_MACOSX) || defined(USE_AURA) || defined(OS_ANDROID)
-// On Mac and Aura IME can request composition character bounds
-// synchronously (see crbug.com/120597). This IPC message sends the character
-// bounds after every composition change to always have correct bound info.
-// This IPC message is also used on Android 5.0 and above.
+// This IPC message sends the character bounds after every composition change
+// to always have correct bound info.
IPC_MESSAGE_ROUTED2(InputHostMsg_ImeCompositionRangeChanged,
gfx::Range /* composition range */,
std::vector<gfx::Rect> /* character bounds */)
-#endif
// Adding a new message? Stick to the sort order above: first platform
// independent InputMsg, then ifdefs for platform specific InputMsg, then
diff --git a/chromium/content/common/mac/attributed_string_coder.mm b/chromium/content/common/mac/attributed_string_coder.mm
index bcd8b118c55..ed377bb91d1 100644
--- a/chromium/content/common/mac/attributed_string_coder.mm
+++ b/chromium/content/common/mac/attributed_string_coder.mm
@@ -100,10 +100,12 @@ AttributedStringCoder::FontAttribute::FontAttribute()
AttributedStringCoder::FontAttribute::~FontAttribute() {
}
-NSDictionary* AttributedStringCoder::FontAttribute::ToAttributesDictionary(
- void) const {
+NSDictionary*
+AttributedStringCoder::FontAttribute::ToAttributesDictionary() const {
DCHECK(ShouldEncode());
NSFont* font = font_descriptor_.ToNSFont();
+ if (!font)
+ return [NSDictionary dictionary];
return [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName];
}
diff --git a/chromium/content/common/mac/font_descriptor.h b/chromium/content/common/mac/font_descriptor.h
index 219f1fb2ca8..71d555dbaa8 100644
--- a/chromium/content/common/mac/font_descriptor.h
+++ b/chromium/content/common/mac/font_descriptor.h
@@ -21,7 +21,9 @@ struct CONTENT_EXPORT FontDescriptor {
FontDescriptor() : font_point_size(0) {}
- // Return an autoreleased NSFont corresponding to the font description.
+ // Return an autoreleased NSFont corresponding to the font description. Note
+ // that this will return nil if the font specified isn't available in this
+ // process.
NSFont* ToNSFont() const;
// Name of the font.
diff --git a/chromium/content/common/mac/font_loader.h b/chromium/content/common/mac/font_loader.h
index 934e26c6f2b..2f9f8982a5b 100644
--- a/chromium/content/common/mac/font_loader.h
+++ b/chromium/content/common/mac/font_loader.h
@@ -65,4 +65,4 @@ class FontLoader {
CGFontRef* out);
};
-#endif // CONTENT_COMMON_MAC_FONT_LOADER_H_
+#endif // CONTENT_COMMON_MAC_FONT_LOADER_H_
diff --git a/chromium/content/common/mac/font_loader.mm b/chromium/content/common/mac/font_loader.mm
index 37dedf4dbe6..d829175b8a8 100644
--- a/chromium/content/common/mac/font_loader.mm
+++ b/chromium/content/common/mac/font_loader.mm
@@ -11,7 +11,6 @@
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/mac/foundation_util.h"
-#include "base/mac/mac_util.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/mac/scoped_nsobject.h"
#include "base/strings/sys_string_conversions.h"
@@ -94,12 +93,10 @@ void FontLoader::LoadFont(const FontDescriptor& font,
result->font_id = 0;
NSFont* font_to_encode = font.ToNSFont();
- // Used only for logging.
- std::string font_name([[font_to_encode fontName] UTF8String]);
// Load appropriate NSFont.
if (!font_to_encode) {
- DLOG(ERROR) << "Failed to load font " << font_name;
+ DLOG(ERROR) << "Failed to load font " << font.font_name;
return;
}
@@ -116,7 +113,7 @@ void FontLoader::LoadFont(const FontDescriptor& font,
base::mac::CFToNSCast(base::mac::CFCastStrict<CFURLRef>(
CTFontCopyAttribute(ct_font_to_encode, kCTFontURLAttribute))));
if (![font_url isFileURL]) {
- DLOG(ERROR) << "Failed to find font file for " << font_name;
+ DLOG(ERROR) << "Failed to find font file for " << font.font_name;
return;
}
@@ -136,7 +133,7 @@ void FontLoader::LoadFont(const FontDescriptor& font,
int32 font_file_size_32 = static_cast<int32>(font_file_size_64);
if (!result->font_data.CreateAndMapAnonymous(font_file_size_32)) {
- DLOG(ERROR) << "Failed to create shmem area for " << font_name;
+ DLOG(ERROR) << "Failed to create shmem area for " << font.font_name;
return;
}
diff --git a/chromium/content/common/manifest_manager_messages.h b/chromium/content/common/manifest_manager_messages.h
index 881ff6b6435..157e5d17d55 100644
--- a/chromium/content/common/manifest_manager_messages.h
+++ b/chromium/content/common/manifest_manager_messages.h
@@ -24,6 +24,12 @@ IPC_STRUCT_TRAITS_BEGIN(content::Manifest::Icon)
IPC_STRUCT_TRAITS_MEMBER(sizes)
IPC_STRUCT_TRAITS_END()
+IPC_STRUCT_TRAITS_BEGIN(content::Manifest::RelatedApplication)
+ IPC_STRUCT_TRAITS_MEMBER(platform)
+ IPC_STRUCT_TRAITS_MEMBER(url)
+ IPC_STRUCT_TRAITS_MEMBER(id)
+IPC_STRUCT_TRAITS_END()
+
IPC_STRUCT_TRAITS_BEGIN(content::Manifest)
IPC_STRUCT_TRAITS_MEMBER(name)
IPC_STRUCT_TRAITS_MEMBER(short_name)
@@ -31,6 +37,8 @@ IPC_STRUCT_TRAITS_BEGIN(content::Manifest)
IPC_STRUCT_TRAITS_MEMBER(display)
IPC_STRUCT_TRAITS_MEMBER(orientation)
IPC_STRUCT_TRAITS_MEMBER(icons)
+ IPC_STRUCT_TRAITS_MEMBER(related_applications)
+ IPC_STRUCT_TRAITS_MEMBER(prefer_related_applications)
IPC_STRUCT_TRAITS_MEMBER(gcm_sender_id)
IPC_STRUCT_TRAITS_END()
diff --git a/chromium/content/common/media/OWNERS b/chromium/content/common/media/OWNERS
index 594b5ee5dd5..2ba40a0bffb 100644
--- a/chromium/content/common/media/OWNERS
+++ b/chromium/content/common/media/OWNERS
@@ -1,9 +1,9 @@
dalecurtis@chromium.org
ddorwin@chromium.org
+jrummell@chromium.org
+sandersd@chromium.org
scherkus@chromium.org
tommi@chromium.org
-vrk@chromium.org
-wjia@chromium.org
xhwang@chromium.org
# For security review of IPC message files.
diff --git a/chromium/content/common/media/audio_messages.h b/chromium/content/common/media/audio_messages.h
index cdc35211288..57dd4a66b67 100644
--- a/chromium/content/common/media/audio_messages.h
+++ b/chromium/content/common/media/audio_messages.h
@@ -56,13 +56,6 @@ IPC_MESSAGE_CONTROL5(
uint32 /* length */,
uint32 /* segment count */)
-// Notification message sent from AudioRendererHost to renderer after an output
-// device change has occurred.
-IPC_MESSAGE_CONTROL3(AudioMsg_NotifyDeviceChanged,
- int /* stream_id */,
- int /* new_buffer_size */,
- int /* new_sample_rate */)
-
// Notification message sent from AudioRendererHost to renderer for state
// update after the renderer has requested a Create/Start/Close.
IPC_MESSAGE_CONTROL2(AudioMsg_NotifyStreamStateChanged,
@@ -81,21 +74,20 @@ IPC_MESSAGE_CONTROL2(AudioInputMsg_NotifyStreamVolume,
// Messages sent from the renderer to the browser.
// Request that is sent to the browser for creating an audio output stream.
-// |render_view_id| is the routing ID for the render view producing the audio
+// |render_frame_id| is the routing ID for the RenderFrame producing the audio
// data.
-IPC_MESSAGE_CONTROL5(AudioHostMsg_CreateStream,
+IPC_MESSAGE_CONTROL4(AudioHostMsg_CreateStream,
int /* stream_id */,
- int /* render_view_id */,
int /* render_frame_id */,
int /* session_id */,
media::AudioParameters /* params */)
// Request that is sent to the browser for creating an audio input stream.
-// |render_view_id| is the routing ID for the render view consuming the audio
+// |render_frame_id| is the routing ID for the RenderFrame consuming the audio
// data.
IPC_MESSAGE_CONTROL4(AudioInputHostMsg_CreateStream,
int /* stream_id */,
- int /* render_view_id */,
+ int /* render_frame_id */,
int /* session_id */,
AudioInputHostMsg_CreateStream_Config)
diff --git a/chromium/content/common/media/cdm_messages.h b/chromium/content/common/media/cdm_messages.h
index 68c7bd184df..1efe0aec040 100644
--- a/chromium/content/common/media/cdm_messages.h
+++ b/chromium/content/common/media/cdm_messages.h
@@ -12,6 +12,7 @@
#include "content/common/content_export.h"
#include "content/common/media/cdm_messages_enums.h"
#include "ipc/ipc_message_macros.h"
+#include "media/base/cdm_key_information.h"
#include "media/base/media_keys.h"
#include "url/gurl.h"
@@ -19,35 +20,60 @@
#define IPC_MESSAGE_EXPORT CONTENT_EXPORT
#define IPC_MESSAGE_START CdmMsgStart
-IPC_ENUM_TRAITS(media::MediaKeys::KeyError)
-IPC_ENUM_TRAITS_MAX_VALUE(CdmHostMsg_CreateSession_ContentType,
- CREATE_SESSION_TYPE_LAST)
+IPC_ENUM_TRAITS_MAX_VALUE(media::CdmKeyInformation::KeyStatus,
+ media::CdmKeyInformation::KEY_STATUS_MAX)
+IPC_ENUM_TRAITS_MAX_VALUE(media::MediaKeys::Exception,
+ media::MediaKeys::EXCEPTION_MAX)
+IPC_ENUM_TRAITS_MAX_VALUE(media::MediaKeys::MessageType,
+ media::MediaKeys::MESSAGE_TYPE_MAX)
+IPC_ENUM_TRAITS_MAX_VALUE(CdmHostMsg_CreateSession_InitDataType,
+ INIT_DATA_TYPE_MAX)
+
+IPC_STRUCT_BEGIN(CdmHostMsg_InitializeCdm_Params)
+ IPC_STRUCT_MEMBER(std::string, key_system)
+ IPC_STRUCT_MEMBER(GURL, security_origin)
+ IPC_STRUCT_MEMBER(bool, use_hw_secure_codecs)
+IPC_STRUCT_END()
+
+IPC_STRUCT_TRAITS_BEGIN(media::CdmKeyInformation)
+ IPC_STRUCT_TRAITS_MEMBER(key_id)
+ IPC_STRUCT_TRAITS_MEMBER(status)
+ IPC_STRUCT_TRAITS_MEMBER(system_code)
+IPC_STRUCT_TRAITS_END()
// Messages from render to browser.
IPC_MESSAGE_CONTROL4(CdmHostMsg_InitializeCdm,
int /* render_frame_id */,
int /* cdm_id */,
- std::string /* key_system */,
- GURL /* security_origin */)
+ uint32_t /* promise_id */,
+ CdmHostMsg_InitializeCdm_Params /* params */)
-IPC_MESSAGE_CONTROL5(CdmHostMsg_CreateSession,
+IPC_MESSAGE_CONTROL4(CdmHostMsg_SetServerCertificate,
int /* render_frame_id */,
int /* cdm_id */,
- uint32_t /* session_id */,
- CdmHostMsg_CreateSession_ContentType /* content_type */,
- std::vector<uint8> /* init_data */)
+ uint32_t /* promise_id */,
+ std::vector<uint8_t> /* certificate */)
-IPC_MESSAGE_CONTROL4(CdmHostMsg_UpdateSession,
+IPC_MESSAGE_CONTROL5(CdmHostMsg_CreateSessionAndGenerateRequest,
int /* render_frame_id */,
int /* cdm_id */,
- uint32_t /* session_id */,
- std::vector<uint8> /* response */)
+ uint32_t /* promise_id */,
+ CdmHostMsg_CreateSession_InitDataType /* init_data_type */,
+ std::vector<uint8_t> /* init_data */)
-IPC_MESSAGE_CONTROL3(CdmHostMsg_ReleaseSession,
+IPC_MESSAGE_CONTROL5(CdmHostMsg_UpdateSession,
int /* render_frame_id */,
int /* cdm_id */,
- uint32_t /* session_id */)
+ uint32_t /* promise_id */,
+ std::string /* session_id */,
+ std::vector<uint8_t> /* response */)
+
+IPC_MESSAGE_CONTROL4(CdmHostMsg_CloseSession,
+ int /* render_frame_id */,
+ int /* cdm_id */,
+ uint32_t /* promise_id */,
+ std::string /* session_id */)
IPC_MESSAGE_CONTROL2(CdmHostMsg_DestroyCdm,
int /* render_frame_id */,
@@ -55,27 +81,47 @@ IPC_MESSAGE_CONTROL2(CdmHostMsg_DestroyCdm,
// Messages from browser to render.
-IPC_MESSAGE_ROUTED3(CdmMsg_SessionCreated,
+IPC_MESSAGE_ROUTED5(CdmMsg_SessionMessage,
int /* cdm_id */,
- uint32_t /* session_id */,
- std::string /* web_session_id */)
+ std::string /* session_id */,
+ media::MediaKeys::MessageType /* message_type */,
+ std::vector<uint8_t> /* message */,
+ GURL /* legacy_destination_url */)
-IPC_MESSAGE_ROUTED4(CdmMsg_SessionMessage,
+IPC_MESSAGE_ROUTED2(CdmMsg_SessionClosed,
int /* cdm_id */,
- uint32_t /* session_id */,
- std::vector<uint8> /* message */,
- GURL /* destination_url */)
+ std::string /* session_id */)
-IPC_MESSAGE_ROUTED2(CdmMsg_SessionReady,
+IPC_MESSAGE_ROUTED5(CdmMsg_LegacySessionError,
int /* cdm_id */,
- uint32_t /* session_id */)
+ std::string /* session_id */,
+ media::MediaKeys::Exception /* exception_code */,
+ uint32_t /* system_code */,
+ std::string /* error_message */)
-IPC_MESSAGE_ROUTED2(CdmMsg_SessionClosed,
+IPC_MESSAGE_ROUTED4(CdmMsg_SessionKeysChange,
+ int /* cdm_id */,
+ std::string /* session_id */,
+ bool /* has_additional_usable_key */,
+ std::vector<media::CdmKeyInformation> /* keys_info */)
+
+IPC_MESSAGE_ROUTED3(CdmMsg_SessionExpirationUpdate,
+ int /* cdm_id */,
+ std::string /* session_id */,
+ base::Time /* new_expiry_time */)
+
+IPC_MESSAGE_ROUTED2(CdmMsg_ResolvePromise,
+ int /* cdm_id */,
+ uint32_t /* promise_id */)
+
+IPC_MESSAGE_ROUTED3(CdmMsg_ResolvePromiseWithSession,
int /* cdm_id */,
- uint32_t /* session_id */)
+ uint32_t /* promise_id */,
+ std::string /* session_id */)
-IPC_MESSAGE_ROUTED4(CdmMsg_SessionError,
+IPC_MESSAGE_ROUTED5(CdmMsg_RejectPromise,
int /* cdm_id */,
- uint32_t /* session_id */,
- media::MediaKeys::KeyError /* error_code */,
- uint32_t /* system_code */)
+ uint32_t /* promise_id */,
+ media::MediaKeys::Exception /* exception */,
+ uint32_t /* system_code */,
+ std::string /* error_message */)
diff --git a/chromium/content/common/media/cdm_messages_enums.h b/chromium/content/common/media/cdm_messages_enums.h
index 5357b512570..c87eb137c7b 100644
--- a/chromium/content/common/media/cdm_messages_enums.h
+++ b/chromium/content/common/media/cdm_messages_enums.h
@@ -5,11 +5,12 @@
#ifndef CONTENT_COMMON_MEDIA_CDM_MESSAGES_ENUMS_H_
#define CONTENT_COMMON_MEDIA_CDM_MESSAGES_ENUMS_H_
-// Dictates the session type when an EME session is created.
-enum CdmHostMsg_CreateSession_ContentType {
- CREATE_SESSION_TYPE_WEBM,
- CREATE_SESSION_TYPE_MP4,
- CREATE_SESSION_TYPE_LAST = CREATE_SESSION_TYPE_MP4
+// The Initialization Data Type when a request is generated.
+// TODO(ddorwin): Replace this with a generic constant. See crbug.com/417440#c9.
+enum CdmHostMsg_CreateSession_InitDataType {
+ INIT_DATA_TYPE_WEBM,
+ INIT_DATA_TYPE_CENC,
+ INIT_DATA_TYPE_MAX = INIT_DATA_TYPE_CENC
};
#endif // CONTENT_COMMON_MEDIA_CDM_MESSAGES_ENUMS_H_
diff --git a/chromium/content/common/media/media_param_traits.cc b/chromium/content/common/media/media_param_traits.cc
index 405e89de17e..a9606ceaff6 100644
--- a/chromium/content/common/media/media_param_traits.cc
+++ b/chromium/content/common/media/media_param_traits.cc
@@ -7,7 +7,7 @@
#include "base/strings/stringprintf.h"
#include "media/audio/audio_parameters.h"
#include "media/base/limits.h"
-#include "media/video/capture/video_capture_types.h"
+#include "media/base/video_capture_types.h"
using media::AudioParameters;
using media::ChannelLayout;
@@ -33,13 +33,13 @@ bool ParamTraits<AudioParameters>::Read(const Message* m,
int format, channel_layout, sample_rate, bits_per_sample,
frames_per_buffer, channels, effects;
- if (!m->ReadInt(iter, &format) ||
- !m->ReadInt(iter, &channel_layout) ||
- !m->ReadInt(iter, &sample_rate) ||
- !m->ReadInt(iter, &bits_per_sample) ||
- !m->ReadInt(iter, &frames_per_buffer) ||
- !m->ReadInt(iter, &channels) ||
- !m->ReadInt(iter, &effects))
+ if (!iter->ReadInt(&format) ||
+ !iter->ReadInt(&channel_layout) ||
+ !iter->ReadInt(&sample_rate) ||
+ !iter->ReadInt(&bits_per_sample) ||
+ !iter->ReadInt(&frames_per_buffer) ||
+ !iter->ReadInt(&channels) ||
+ !iter->ReadInt(&effects))
return false;
AudioParameters params(static_cast<AudioParameters::Format>(format),
@@ -69,10 +69,10 @@ bool ParamTraits<VideoCaptureFormat>::Read(const Message* m,
PickleIterator* iter,
VideoCaptureFormat* r) {
int frame_size_width, frame_size_height, pixel_format;
- if (!m->ReadInt(iter, &frame_size_width) ||
- !m->ReadInt(iter, &frame_size_height) ||
- !m->ReadFloat(iter, &r->frame_rate) ||
- !m->ReadInt(iter, &pixel_format))
+ if (!iter->ReadInt(&frame_size_width) ||
+ !iter->ReadInt(&frame_size_height) ||
+ !iter->ReadFloat(&r->frame_rate) ||
+ !iter->ReadInt(&pixel_format))
return false;
r->frame_size.SetSize(frame_size_width, frame_size_height);
diff --git a/chromium/content/common/media/media_player_messages_android.h b/chromium/content/common/media/media_player_messages_android.h
index 999ab0f95a6..8cdf7030532 100644
--- a/chromium/content/common/media/media_player_messages_android.h
+++ b/chromium/content/common/media/media_player_messages_android.h
@@ -10,9 +10,9 @@
#include "content/common/content_export.h"
#include "content/common/media/media_player_messages_enums_android.h"
#include "ipc/ipc_message_macros.h"
-#include "media/base/android/media_player_android.h"
#include "media/base/android/demuxer_stream_player_params.h"
-#include "ui/gfx/rect_f.h"
+#include "media/base/android/media_player_android.h"
+#include "ui/gfx/geometry/rect_f.h"
#include "url/gurl.h"
#undef IPC_MESSAGE_EXPORT
@@ -30,6 +30,8 @@ IPC_STRUCT_TRAITS_BEGIN(media::DemuxerConfigs)
IPC_STRUCT_TRAITS_MEMBER(audio_sampling_rate)
IPC_STRUCT_TRAITS_MEMBER(is_audio_encrypted)
IPC_STRUCT_TRAITS_MEMBER(audio_extra_data)
+ IPC_STRUCT_TRAITS_MEMBER(audio_codec_delay_ns)
+ IPC_STRUCT_TRAITS_MEMBER(audio_seek_preroll_ns)
IPC_STRUCT_TRAITS_MEMBER(video_codec)
IPC_STRUCT_TRAITS_MEMBER(video_size)
@@ -47,12 +49,13 @@ IPC_STRUCT_TRAITS_END()
IPC_STRUCT_TRAITS_BEGIN(media::AccessUnit)
IPC_STRUCT_TRAITS_MEMBER(status)
- IPC_STRUCT_TRAITS_MEMBER(end_of_stream)
+ IPC_STRUCT_TRAITS_MEMBER(is_end_of_stream)
IPC_STRUCT_TRAITS_MEMBER(data)
IPC_STRUCT_TRAITS_MEMBER(timestamp)
IPC_STRUCT_TRAITS_MEMBER(key_id)
IPC_STRUCT_TRAITS_MEMBER(iv)
IPC_STRUCT_TRAITS_MEMBER(subsamples)
+ IPC_STRUCT_TRAITS_MEMBER(is_key_frame)
IPC_STRUCT_TRAITS_END()
IPC_STRUCT_TRAITS_BEGIN(media::SubsampleEntry)
@@ -159,14 +162,13 @@ IPC_MESSAGE_ROUTED3(MediaPlayerMsg_MediaTimeUpdate,
base::TimeDelta /* current_timestamp */,
base::TimeTicks /* current_time_ticks */)
+// A new key is required in order to continue decrypting encrypted content.
+IPC_MESSAGE_ROUTED1(MediaPlayerMsg_WaitingForDecryptionKey, int /* player_id */)
+
// The player has been released.
IPC_MESSAGE_ROUTED1(MediaPlayerMsg_MediaPlayerReleased,
int /* player_id */)
-// The player has entered fullscreen mode.
-IPC_MESSAGE_ROUTED1(MediaPlayerMsg_DidEnterFullscreen,
- int /* player_id */)
-
// The player exited fullscreen.
IPC_MESSAGE_ROUTED1(MediaPlayerMsg_DidExitFullscreen,
int /* player_id */)
diff --git a/chromium/content/common/media/media_stream_options.cc b/chromium/content/common/media/media_stream_options.cc
index 83add2a42de..dfba2e821e5 100644
--- a/chromium/content/common/media/media_stream_options.cc
+++ b/chromium/content/common/media/media_stream_options.cc
@@ -20,6 +20,7 @@ const char kMediaStreamRenderToAssociatedSink[] =
// The prefix of this constant is 'goog' to match with other getUserMedia
// constraints for audio.
const char kMediaStreamAudioDucking[] = "googDucking";
+const char kMediaStreamAudioHotword[] = "googHotword";
namespace {
diff --git a/chromium/content/common/media/media_stream_options.h b/chromium/content/common/media/media_stream_options.h
index e58f1370003..9f208da80e3 100644
--- a/chromium/content/common/media/media_stream_options.h
+++ b/chromium/content/common/media/media_stream_options.h
@@ -31,6 +31,10 @@ CONTENT_EXPORT extern const char kMediaStreamRenderToAssociatedSink[];
// Controls whether ducking of audio is enabled on platforms that support it.
CONTENT_EXPORT extern const char kMediaStreamAudioDucking[];
+// Controls whether the hotword audio stream is used on platforms that support
+// it.
+CONTENT_EXPORT extern const char kMediaStreamAudioHotword[];
+
// StreamOptions is a Chromium representation of constraints
// used in WebUserMediaRequest.
// It describes properties requested by JS in a request for a new
diff --git a/chromium/content/common/media/midi_messages.h b/chromium/content/common/media/midi_messages.h
index 388d518e5c8..67500f60b68 100644
--- a/chromium/content/common/media/midi_messages.h
+++ b/chromium/content/common/media/midi_messages.h
@@ -17,28 +17,19 @@
#define IPC_MESSAGE_EXPORT CONTENT_EXPORT
#define IPC_MESSAGE_START MidiMsgStart
-IPC_STRUCT_TRAITS_BEGIN(media::MidiPortInfo)
+IPC_ENUM_TRAITS_MAX_VALUE(media::midi::MidiPortState,
+ media::midi::MIDI_PORT_STATE_LAST)
+
+IPC_STRUCT_TRAITS_BEGIN(media::midi::MidiPortInfo)
IPC_STRUCT_TRAITS_MEMBER(id)
IPC_STRUCT_TRAITS_MEMBER(manufacturer)
IPC_STRUCT_TRAITS_MEMBER(name)
IPC_STRUCT_TRAITS_MEMBER(version)
+ IPC_STRUCT_TRAITS_MEMBER(state)
IPC_STRUCT_TRAITS_END()
-IPC_ENUM_TRAITS_MAX_VALUE(media::MidiResult, media::MIDI_RESULT_LAST)
-
-// Messages for IPC between MidiDispatcher and MidiDispatcherHost.
-
-// Renderer request to browser for using system exclusive messages.
-IPC_MESSAGE_ROUTED3(MidiHostMsg_RequestSysExPermission,
- int /* client id */,
- GURL /* origin */,
- bool /* user_gesture */)
-
-// Messages sent from the browser to the renderer.
-
-IPC_MESSAGE_ROUTED2(MidiMsg_SysExPermissionApproved,
- int /* client id */,
- bool /* is_allowed */)
+IPC_ENUM_TRAITS_MAX_VALUE(media::midi::MidiResult,
+ media::midi::MIDI_RESULT_LAST)
// Messages for IPC between MidiMessageFilter and MidiHost.
@@ -55,13 +46,21 @@ IPC_MESSAGE_CONTROL0(MidiHostMsg_EndSession)
// Messages sent from the browser to the renderer.
IPC_MESSAGE_CONTROL1(MidiMsg_AddInputPort,
- media::MidiPortInfo /* input port */)
+ media::midi::MidiPortInfo /* input port */)
IPC_MESSAGE_CONTROL1(MidiMsg_AddOutputPort,
- media::MidiPortInfo /* output port */)
+ media::midi::MidiPortInfo /* output port */)
+
+IPC_MESSAGE_CONTROL2(MidiMsg_SetInputPortState,
+ uint32 /* port */,
+ media::midi::MidiPortState /* state */)
+
+IPC_MESSAGE_CONTROL2(MidiMsg_SetOutputPortState,
+ uint32 /* port */,
+ media::midi::MidiPortState /* state */)
IPC_MESSAGE_CONTROL1(MidiMsg_SessionStarted,
- media::MidiResult /* result */)
+ media::midi::MidiResult /* result */)
IPC_MESSAGE_CONTROL3(MidiMsg_DataReceived,
uint32 /* port */,
diff --git a/chromium/content/common/media/video_capture.h b/chromium/content/common/media/video_capture.h
index 80dca93ad82..7a5115dd6a5 100644
--- a/chromium/content/common/media/video_capture.h
+++ b/chromium/content/common/media/video_capture.h
@@ -8,8 +8,8 @@
#define CONTENT_COMMON_MEDIA_VIDEO_CAPTURE_H_
#include "base/time/time.h"
+#include "media/base/video_capture_types.h"
#include "media/base/video_frame.h"
-#include "media/video/capture/video_capture_types.h"
namespace content {
diff --git a/chromium/content/common/media/video_capture_messages.h b/chromium/content/common/media/video_capture_messages.h
index b7a2ee17ff3..77f95bfd517 100644
--- a/chromium/content/common/media/video_capture_messages.h
+++ b/chromium/content/common/media/video_capture_messages.h
@@ -8,7 +8,7 @@
#include "content/public/common/common_param_traits.h"
#include "gpu/command_buffer/common/mailbox_holder.h"
#include "ipc/ipc_message_macros.h"
-#include "media/video/capture/video_capture_types.h"
+#include "media/base/video_capture_types.h"
#undef IPC_MESSAGE_EXPORT
#define IPC_MESSAGE_EXPORT CONTENT_EXPORT
@@ -25,6 +25,24 @@ IPC_STRUCT_TRAITS_BEGIN(media::VideoCaptureParams)
IPC_STRUCT_TRAITS_MEMBER(resolution_change_policy)
IPC_STRUCT_TRAITS_END()
+IPC_STRUCT_BEGIN(VideoCaptureMsg_BufferReady_Params)
+ IPC_STRUCT_MEMBER(int, device_id)
+ IPC_STRUCT_MEMBER(int, buffer_id)
+ IPC_STRUCT_MEMBER(gfx::Size, coded_size)
+ IPC_STRUCT_MEMBER(gfx::Rect, visible_rect)
+ IPC_STRUCT_MEMBER(base::TimeTicks, timestamp)
+ IPC_STRUCT_MEMBER(base::DictionaryValue, metadata)
+IPC_STRUCT_END()
+
+IPC_STRUCT_BEGIN(VideoCaptureMsg_MailboxBufferReady_Params)
+ IPC_STRUCT_MEMBER(int, device_id)
+ IPC_STRUCT_MEMBER(int, buffer_id)
+ IPC_STRUCT_MEMBER(gpu::MailboxHolder, mailbox_holder)
+ IPC_STRUCT_MEMBER(gfx::Size, packed_frame_size)
+ IPC_STRUCT_MEMBER(base::TimeTicks, timestamp)
+ IPC_STRUCT_MEMBER(base::DictionaryValue, metadata)
+IPC_STRUCT_END()
+
// TODO(nick): device_id in these messages is basically just a route_id. We
// should shift to IPC_MESSAGE_ROUTED and use MessageRouter in the filter impls.
@@ -48,21 +66,13 @@ IPC_MESSAGE_CONTROL2(VideoCaptureMsg_FreeBuffer,
int /* buffer_id */)
// Tell the renderer process that a buffer is available from video capture.
-IPC_MESSAGE_CONTROL5(VideoCaptureMsg_BufferReady,
- int /* device id */,
- int /* buffer_id */,
- media::VideoCaptureFormat /* format */,
- gfx::Rect /* visible_rect */,
- base::TimeTicks /* timestamp */)
+IPC_MESSAGE_CONTROL1(VideoCaptureMsg_BufferReady,
+ VideoCaptureMsg_BufferReady_Params)
// Tell the renderer process that a texture mailbox buffer is available from
// video capture.
-IPC_MESSAGE_CONTROL5(VideoCaptureMsg_MailboxBufferReady,
- int /* device_id */,
- int /* buffer_id */,
- gpu::MailboxHolder /* mailbox_holder */,
- media::VideoCaptureFormat /* format */,
- base::TimeTicks /* timestamp */)
+IPC_MESSAGE_CONTROL1(VideoCaptureMsg_MailboxBufferReady,
+ VideoCaptureMsg_MailboxBufferReady_Params)
// Notify the renderer about a device's supported formats; this is a response
// to a VideoCaptureHostMsg_GetDeviceSupportedFormats request.
diff --git a/chromium/content/common/message_port_messages.h b/chromium/content/common/message_port_messages.h
index 4269ade839e..d2c6fb8e8a6 100644
--- a/chromium/content/common/message_port_messages.h
+++ b/chromium/content/common/message_port_messages.h
@@ -14,6 +14,7 @@
#include "base/basictypes.h"
#include "base/strings/string16.h"
#include "content/common/content_export.h"
+#include "content/public/common/message_port_types.h"
#include "ipc/ipc_message_macros.h"
#include "ipc/ipc_message_utils.h"
@@ -21,23 +22,35 @@
#define IPC_MESSAGE_EXPORT CONTENT_EXPORT
#define IPC_MESSAGE_START MessagePortMsgStart
-// Singly-included section, not converted.
+// Singly-included section for typedefs.
#ifndef CONTENT_COMMON_MESSAGE_PORT_MESSAGES_H_
#define CONTENT_COMMON_MESSAGE_PORT_MESSAGES_H_
-typedef std::pair<base::string16, std::vector<int> > QueuedMessage;
+typedef std::pair<content::MessagePortMessage,
+ std::vector<content::TransferredMessagePort>> QueuedMessage;
#endif // CONTENT_COMMON_MESSAGE_PORT_MESSAGES_H_
+IPC_STRUCT_TRAITS_BEGIN(content::MessagePortMessage)
+ IPC_STRUCT_TRAITS_MEMBER(message_as_string)
+ IPC_STRUCT_TRAITS_MEMBER(message_as_value)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(content::TransferredMessagePort)
+ IPC_STRUCT_TRAITS_MEMBER(id)
+ IPC_STRUCT_TRAITS_MEMBER(send_messages_as_values)
+IPC_STRUCT_TRAITS_END()
+
//-----------------------------------------------------------------------------
// MessagePort messages
// These are messages sent from the browser to child processes.
// Sends a message to a message port.
-IPC_MESSAGE_ROUTED3(MessagePortMsg_Message,
- base::string16 /* message */,
- std::vector<int> /* sent_message_port_ids */,
- std::vector<int> /* new_routing_ids */)
+IPC_MESSAGE_ROUTED3(
+ MessagePortMsg_Message,
+ content::MessagePortMessage /* message */,
+ std::vector<content::TransferredMessagePort> /* sent_message_ports */,
+ std::vector<int> /* new_routing_ids */)
// Tells the Message Port Channel object that there are no more in-flight
// messages arriving.
@@ -60,10 +73,11 @@ IPC_MESSAGE_CONTROL1(MessagePortHostMsg_DestroyMessagePort,
// Sends a message to a message port. Optionally sends a message port as
// as well if sent_message_port_id != MSG_ROUTING_NONE.
-IPC_MESSAGE_CONTROL3(MessagePortHostMsg_PostMessage,
- int /* sender_message_port_id */,
- base::string16 /* message */,
- std::vector<int> /* sent_message_port_ids */)
+IPC_MESSAGE_CONTROL3(
+ MessagePortHostMsg_PostMessage,
+ int /* sender_message_port_id */,
+ content::MessagePortMessage /* message */,
+ std::vector<content::TransferredMessagePort> /* sent_message_ports */)
// Causes messages sent to the remote port to be delivered to this local port.
IPC_MESSAGE_CONTROL2(MessagePortHostMsg_Entangle,
@@ -83,3 +97,9 @@ IPC_MESSAGE_CONTROL1(MessagePortHostMsg_QueueMessages,
IPC_MESSAGE_CONTROL2(MessagePortHostMsg_SendQueuedMessages,
int /* message_port_id */,
std::vector<QueuedMessage> /* queued_messages */)
+
+// Tells the browser this message port is ready to receive messages. If the
+// browser was holding messages to this port because no destination for the
+// port was available yet this will cause the browser to release those messages.
+IPC_MESSAGE_CONTROL1(MessagePortHostMsg_ReleaseMessages,
+ int /* message_port_id */)
diff --git a/chromium/content/common/message_router.h b/chromium/content/common/message_router.h
index a842f8eb899..3df9bd59748 100644
--- a/chromium/content/common/message_router.h
+++ b/chromium/content/common/message_router.h
@@ -6,6 +6,7 @@
#define CONTENT_COMMON_MESSAGE_ROUTER_H_
#include "base/id_map.h"
+#include "content/common/content_export.h"
#include "ipc/ipc_listener.h"
#include "ipc/ipc_sender.h"
@@ -29,7 +30,7 @@
namespace content {
-class MessageRouter : public IPC::Listener, public IPC::Sender {
+class CONTENT_EXPORT MessageRouter : public IPC::Listener, public IPC::Sender {
public:
MessageRouter();
~MessageRouter() override;
diff --git a/chromium/content/common/mojo/DEPS b/chromium/content/common/mojo/DEPS
new file mode 100644
index 00000000000..c6b01113ba2
--- /dev/null
+++ b/chromium/content/common/mojo/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+mojo/application/public/interfaces",
+]
diff --git a/chromium/content/common/mojo/channel_init.cc b/chromium/content/common/mojo/channel_init.cc
new file mode 100644
index 00000000000..c2d4bf25cb9
--- /dev/null
+++ b/chromium/content/common/mojo/channel_init.cc
@@ -0,0 +1,69 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/common/mojo/channel_init.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/lazy_instance.h"
+#include "base/message_loop/message_loop.h"
+#include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
+
+namespace content {
+
+ChannelInit::ChannelInit() : channel_info_(nullptr), weak_factory_(this) {}
+
+ChannelInit::~ChannelInit() {
+ if (channel_info_)
+ mojo::embedder::DestroyChannel(channel_info_,
+ base::Bind(&base::DoNothing), nullptr);
+}
+
+mojo::ScopedMessagePipeHandle ChannelInit::Init(
+ base::PlatformFile file,
+ scoped_refptr<base::TaskRunner> io_thread_task_runner) {
+ scoped_ptr<IPC::ScopedIPCSupport> ipc_support(
+ new IPC::ScopedIPCSupport(io_thread_task_runner));
+ mojo::ScopedMessagePipeHandle message_pipe =
+ mojo::embedder::CreateChannel(
+ mojo::embedder::ScopedPlatformHandle(
+ mojo::embedder::PlatformHandle(file)),
+ io_thread_task_runner,
+ base::Bind(&ChannelInit::OnCreatedChannel,
+ weak_factory_.GetWeakPtr(),
+ base::Passed(&ipc_support)),
+ base::MessageLoop::current()->task_runner()).Pass();
+ return message_pipe.Pass();
+}
+
+void ChannelInit::WillDestroySoon() {
+ if (channel_info_)
+ mojo::embedder::WillDestroyChannelSoon(channel_info_);
+}
+
+void ChannelInit::ShutdownOnIOThread() {
+ if (channel_info_)
+ mojo::embedder::DestroyChannelOnIOThread(channel_info_);
+ channel_info_ = nullptr;
+ ipc_support_.reset();
+}
+
+// static
+void ChannelInit::OnCreatedChannel(
+ base::WeakPtr<ChannelInit> self,
+ scoped_ptr<IPC::ScopedIPCSupport> ipc_support,
+ mojo::embedder::ChannelInfo* channel) {
+ // If |self| was already destroyed, shut the channel down.
+ if (!self) {
+ mojo::embedder::DestroyChannel(channel,
+ base::Bind(&base::DoNothing), nullptr);
+ return;
+ }
+
+ DCHECK(!self->channel_info_);
+ self->channel_info_ = channel;
+ self->ipc_support_ = ipc_support.Pass();
+}
+
+} // namespace content
diff --git a/chromium/content/common/mojo/channel_init.h b/chromium/content/common/mojo/channel_init.h
new file mode 100644
index 00000000000..2660a7bcbf2
--- /dev/null
+++ b/chromium/content/common/mojo/channel_init.h
@@ -0,0 +1,61 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_COMMON_MOJO_CHANNEL_INIT_H_
+#define CONTENT_COMMON_MOJO_CHANNEL_INIT_H_
+
+#include "base/files/file.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "content/common/content_export.h"
+#include "ipc/mojo/scoped_ipc_support.h"
+#include "third_party/mojo/src/mojo/edk/embedder/channel_info_forward.h"
+#include "third_party/mojo/src/mojo/public/cpp/system/message_pipe.h"
+
+namespace base {
+class TaskRunner;
+}
+
+namespace content {
+
+// ChannelInit handles creation and destruction of the Mojo channel. It is not
+// thread-safe, but may be used on any single thread with a MessageLoop.
+class CONTENT_EXPORT ChannelInit {
+ public:
+ ChannelInit();
+ ~ChannelInit();
+
+ // Initializes the channel. This takes ownership of |file|. Returns the
+ // primordial MessagePipe for the channel.
+ mojo::ScopedMessagePipeHandle Init(
+ base::PlatformFile file,
+ scoped_refptr<base::TaskRunner> io_thread_task_runner);
+
+ // Notifies the channel that we (hence it) will soon be destroyed.
+ void WillDestroySoon();
+
+ // Shuts down the channel. Must be called from the IO thread.
+ void ShutdownOnIOThread();
+
+ private:
+ // Invoked on the thread on which this object lives once the channel has been
+ // established. This is a static method that takes a weak pointer to self,
+ // since we want to destroy the channel if we were destroyed first.
+ static void OnCreatedChannel(
+ base::WeakPtr<ChannelInit> self,
+ scoped_ptr<IPC::ScopedIPCSupport> ipc_support,
+ mojo::embedder::ChannelInfo* channel);
+
+ // If non-null the channel has been established.
+ mojo::embedder::ChannelInfo* channel_info_;
+
+ scoped_ptr<IPC::ScopedIPCSupport> ipc_support_;
+ base::WeakPtrFactory<ChannelInit> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ChannelInit);
+};
+
+} // namespace content
+
+#endif // CONTENT_COMMON_MOJO_CHANNEL_INIT_H_
diff --git a/chromium/content/common/mojo/service_registry_impl.cc b/chromium/content/common/mojo/service_registry_impl.cc
index 348d1d45c81..eec7640bc30 100644
--- a/chromium/content/common/mojo/service_registry_impl.cc
+++ b/chromium/content/common/mojo/service_registry_impl.cc
@@ -9,12 +9,7 @@
namespace content {
ServiceRegistryImpl::ServiceRegistryImpl()
- : bound_(false), weak_factory_(this) {
-}
-
-ServiceRegistryImpl::ServiceRegistryImpl(mojo::ScopedMessagePipeHandle handle)
- : bound_(false), weak_factory_(this) {
- BindRemoteServiceProvider(handle.Pass());
+ : binding_(this), weak_factory_(this) {
}
ServiceRegistryImpl::~ServiceRegistryImpl() {
@@ -24,23 +19,23 @@ ServiceRegistryImpl::~ServiceRegistryImpl() {
}
}
+void ServiceRegistryImpl::Bind(
+ mojo::InterfaceRequest<mojo::ServiceProvider> request) {
+ binding_.Bind(request.Pass());
+}
+
void ServiceRegistryImpl::BindRemoteServiceProvider(
- mojo::ScopedMessagePipeHandle handle) {
- CHECK(!bound_);
- bound_ = true;
- mojo::WeakBindToPipe(this, handle.Pass());
+ mojo::ServiceProviderPtr service_provider) {
+ CHECK(!remote_provider_);
+ remote_provider_ = service_provider.Pass();
while (!pending_connects_.empty()) {
- client()->ConnectToService(
+ remote_provider_->ConnectToService(
mojo::String::From(pending_connects_.front().first),
mojo::ScopedMessagePipeHandle(pending_connects_.front().second));
pending_connects_.pop();
}
}
-void ServiceRegistryImpl::OnConnectionError() {
- // TODO(sammc): Support reporting this to our owner.
-}
-
void ServiceRegistryImpl::AddService(
const std::string& service_name,
const base::Callback<void(mojo::ScopedMessagePipeHandle)> service_factory) {
@@ -54,12 +49,13 @@ void ServiceRegistryImpl::RemoveService(const std::string& service_name) {
void ServiceRegistryImpl::ConnectToRemoteService(
const base::StringPiece& service_name,
mojo::ScopedMessagePipeHandle handle) {
- if (!bound_) {
+ if (!remote_provider_) {
pending_connects_.push(
std::make_pair(service_name.as_string(), handle.release()));
return;
}
- client()->ConnectToService(mojo::String::From(service_name), handle.Pass());
+ remote_provider_->ConnectToService(mojo::String::From(service_name),
+ handle.Pass());
}
base::WeakPtr<ServiceRegistry> ServiceRegistryImpl::GetWeakPtr() {
diff --git a/chromium/content/common/mojo/service_registry_impl.h b/chromium/content/common/mojo/service_registry_impl.h
index b3a6576b27a..5cdd3226063 100644
--- a/chromium/content/common/mojo/service_registry_impl.h
+++ b/chromium/content/common/mojo/service_registry_impl.h
@@ -14,25 +14,27 @@
#include "base/compiler_specific.h"
#include "base/memory/weak_ptr.h"
#include "content/public/common/service_registry.h"
-#include "mojo/public/cpp/bindings/interface_impl.h"
-#include "mojo/public/cpp/system/core.h"
-#include "mojo/public/interfaces/application/service_provider.mojom.h"
+#include "mojo/application/public/interfaces/service_provider.mojom.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h"
+#include "third_party/mojo/src/mojo/public/cpp/system/core.h"
namespace content {
class CONTENT_EXPORT ServiceRegistryImpl
: public ServiceRegistry,
- public NON_EXPORTED_BASE(mojo::InterfaceImpl<mojo::ServiceProvider>) {
+ public NON_EXPORTED_BASE(mojo::ServiceProvider) {
public:
ServiceRegistryImpl();
- explicit ServiceRegistryImpl(mojo::ScopedMessagePipeHandle handle);
~ServiceRegistryImpl() override;
+ // Binds this ServiceProvider implementation to a message pipe endpoint.
+ void Bind(mojo::InterfaceRequest<mojo::ServiceProvider> request);
+
// Binds to a remote ServiceProvider. This will expose added services to the
// remote ServiceProvider with the corresponding handle and enable
// ConnectToRemoteService to provide access to services exposed by the remote
// ServiceProvider.
- void BindRemoteServiceProvider(mojo::ScopedMessagePipeHandle handle);
+ void BindRemoteServiceProvider(mojo::ServiceProviderPtr service_provider);
// ServiceRegistry overrides.
void AddService(const std::string& service_name,
@@ -45,16 +47,17 @@ class CONTENT_EXPORT ServiceRegistryImpl
base::WeakPtr<ServiceRegistry> GetWeakPtr();
private:
- // mojo::InterfaceImpl<mojo::ServiceProvider> overrides.
+ // mojo::ServiceProvider overrides.
void ConnectToService(const mojo::String& name,
mojo::ScopedMessagePipeHandle client_handle) override;
- void OnConnectionError() override;
+
+ mojo::Binding<mojo::ServiceProvider> binding_;
+ mojo::ServiceProviderPtr remote_provider_;
std::map<std::string, base::Callback<void(mojo::ScopedMessagePipeHandle)> >
service_factories_;
std::queue<std::pair<std::string, mojo::MessagePipeHandle> >
pending_connects_;
- bool bound_;
base::WeakPtrFactory<ServiceRegistry> weak_factory_;
};
diff --git a/chromium/content/common/navigation_params.cc b/chromium/content/common/navigation_params.cc
index 31787acb975..57149de1edc 100644
--- a/chromium/content/common/navigation_params.cc
+++ b/chromium/content/common/navigation_params.cc
@@ -7,55 +7,133 @@
#include "base/memory/ref_counted_memory.h"
namespace content {
+
CommonNavigationParams::CommonNavigationParams()
: transition(ui::PAGE_TRANSITION_LINK),
navigation_type(FrameMsg_Navigate_Type::NORMAL),
- allow_download(true) {
+ allow_download(true),
+ report_type(FrameMsg_UILoadMetricsReportType::NO_REPORT) {
}
-CommonNavigationParams::~CommonNavigationParams() {}
-
CommonNavigationParams::CommonNavigationParams(
const GURL& url,
const Referrer& referrer,
ui::PageTransition transition,
FrameMsg_Navigate_Type::Value navigation_type,
- bool allow_download)
+ bool allow_download,
+ base::TimeTicks ui_timestamp,
+ FrameMsg_UILoadMetricsReportType::Value report_type,
+ const GURL& base_url_for_data_url,
+ const GURL& history_url_for_data_url)
: url(url),
referrer(referrer),
transition(transition),
navigation_type(navigation_type),
- allow_download(allow_download) {
+ allow_download(allow_download),
+ ui_timestamp(ui_timestamp),
+ report_type(report_type),
+ base_url_for_data_url(base_url_for_data_url),
+ history_url_for_data_url(history_url_for_data_url) {
}
-RequestNavigationParams::RequestNavigationParams() : is_post(false) {}
+CommonNavigationParams::~CommonNavigationParams() {
+}
-RequestNavigationParams::RequestNavigationParams(
+BeginNavigationParams::BeginNavigationParams()
+ : load_flags(0), has_user_gesture(false) {
+}
+
+BeginNavigationParams::BeginNavigationParams(std::string method,
+ std::string headers,
+ int load_flags,
+ bool has_user_gesture)
+ : method(method),
+ headers(headers),
+ load_flags(load_flags),
+ has_user_gesture(has_user_gesture) {
+}
+
+StartNavigationParams::StartNavigationParams()
+ : is_post(false),
+ should_replace_current_entry(false),
+ transferred_request_child_id(-1),
+ transferred_request_request_id(-1) {
+}
+
+StartNavigationParams::StartNavigationParams(
bool is_post,
const std::string& extra_headers,
- const base::RefCountedMemory* post_data)
+ const std::vector<unsigned char>& browser_initiated_post_data,
+ bool should_replace_current_entry,
+ int transferred_request_child_id,
+ int transferred_request_request_id)
: is_post(is_post),
- extra_headers(extra_headers) {
- if (post_data) {
- browser_initiated_post_data.assign(
- post_data->front(), post_data->front() + post_data->size());
- }
+ extra_headers(extra_headers),
+ browser_initiated_post_data(browser_initiated_post_data),
+ should_replace_current_entry(should_replace_current_entry),
+ transferred_request_child_id(transferred_request_child_id),
+ transferred_request_request_id(transferred_request_request_id) {
+}
+
+StartNavigationParams::~StartNavigationParams() {
+}
+
+RequestNavigationParams::RequestNavigationParams()
+ : is_overriding_user_agent(false),
+ browser_navigation_start(base::TimeTicks::Now()),
+ can_load_local_resources(false),
+ request_time(base::Time::Now()),
+ page_id(-1),
+ nav_entry_id(0),
+ intended_as_new_entry(false),
+ pending_history_list_offset(-1),
+ current_history_list_offset(-1),
+ current_history_list_length(0),
+ should_clear_history_list(false) {
}
-RequestNavigationParams::~RequestNavigationParams() {}
+RequestNavigationParams::RequestNavigationParams(
+ bool is_overriding_user_agent,
+ base::TimeTicks navigation_start,
+ const std::vector<GURL>& redirects,
+ bool can_load_local_resources,
+ base::Time request_time,
+ const PageState& page_state,
+ int32 page_id,
+ int nav_entry_id,
+ bool intended_as_new_entry,
+ int pending_history_list_offset,
+ int current_history_list_offset,
+ int current_history_list_length,
+ bool should_clear_history_list)
+ : is_overriding_user_agent(is_overriding_user_agent),
+ browser_navigation_start(navigation_start),
+ redirects(redirects),
+ can_load_local_resources(can_load_local_resources),
+ request_time(request_time),
+ page_state(page_state),
+ page_id(page_id),
+ nav_entry_id(nav_entry_id),
+ intended_as_new_entry(intended_as_new_entry),
+ pending_history_list_offset(pending_history_list_offset),
+ current_history_list_offset(current_history_list_offset),
+ current_history_list_length(current_history_list_length),
+ should_clear_history_list(should_clear_history_list) {
+}
-CommitNavigationParams::CommitNavigationParams()
- : is_overriding_user_agent(false) {
+RequestNavigationParams::~RequestNavigationParams() {
}
-CommitNavigationParams::CommitNavigationParams(const PageState& page_state,
- bool is_overriding_user_agent,
- base::TimeTicks navigation_start)
- : page_state(page_state),
- is_overriding_user_agent(is_overriding_user_agent),
- browser_navigation_start(navigation_start) {
+NavigationParams::NavigationParams(
+ const CommonNavigationParams& common_params,
+ const StartNavigationParams& start_params,
+ const RequestNavigationParams& request_params)
+ : common_params(common_params),
+ start_params(start_params),
+ request_params(request_params) {
}
-CommitNavigationParams::~CommitNavigationParams() {}
+NavigationParams::~NavigationParams() {
+}
} // namespace content
diff --git a/chromium/content/common/navigation_params.h b/chromium/content/common/navigation_params.h
index d30d382322d..90eb70eea51 100644
--- a/chromium/content/common/navigation_params.h
+++ b/chromium/content/common/navigation_params.h
@@ -21,13 +21,12 @@ class RefCountedMemory;
}
namespace content {
-class NavigationEntry;
// The following structures hold parameters used during a navigation. In
// particular they are used by FrameMsg_Navigate, FrameMsg_CommitNavigation and
// FrameHostMsg_BeginNavigation.
-// TODO(clamy): Depending on the avancement of the history refactoring move the
-// history parameters from FrameMsg_Navigate into one of the structs.
+
+// Provided by the browser or the renderer -------------------------------------
// Used by all navigation IPCs.
struct CONTENT_EXPORT CommonNavigationParams {
@@ -36,7 +35,11 @@ struct CONTENT_EXPORT CommonNavigationParams {
const Referrer& referrer,
ui::PageTransition transition,
FrameMsg_Navigate_Type::Value navigation_type,
- bool allow_download);
+ bool allow_download,
+ base::TimeTicks ui_timestamp,
+ FrameMsg_UILoadMetricsReportType::Value report_type,
+ const GURL& base_url_for_data_url,
+ const GURL& history_url_for_data_url);
~CommonNavigationParams();
// The URL to navigate to.
@@ -56,16 +59,79 @@ struct CONTENT_EXPORT CommonNavigationParams {
// Allows the URL to be downloaded (true by default).
// Avoid downloading when in view-source mode.
bool allow_download;
+
+ // Timestamp of the user input event that triggered this navigation. Empty if
+ // the navigation was not triggered by clicking on a link or by receiving an
+ // intent on Android.
+ base::TimeTicks ui_timestamp;
+
+ // The report type to be used when recording the metric using |ui_timestamp|.
+ FrameMsg_UILoadMetricsReportType::Value report_type;
+
+ // Base URL for use in Blink's SubstituteData.
+ // Is only used with data: URLs.
+ GURL base_url_for_data_url;
+
+ // History URL for use in Blink's SubstituteData.
+ // Is only used with data: URLs.
+ GURL history_url_for_data_url;
};
-// Used by FrameMsg_Navigate.
-// PlzNavigate: sent to the renderer when requesting a navigation.
-struct CONTENT_EXPORT RequestNavigationParams {
- RequestNavigationParams();
- RequestNavigationParams(bool is_post,
- const std::string& extra_headers,
- const base::RefCountedMemory* post_data);
- ~RequestNavigationParams();
+// Provided by the renderer ----------------------------------------------------
+//
+// This struct holds parameters sent by the renderer to the browser. It is only
+// used in PlzNavigate (since in the current architecture, the renderer does not
+// inform the browser of navigations until they commit).
+
+// This struct is not used outside of the PlzNavigate project.
+// PlzNavigate: parameters needed to start a navigation on the IO thread,
+// following a renderer-initiated navigation request.
+struct CONTENT_EXPORT BeginNavigationParams {
+ // TODO(clamy): See if it is possible to reuse this in
+ // ResourceMsg_Request_Params.
+ BeginNavigationParams();
+ BeginNavigationParams(std::string method,
+ std::string headers,
+ int load_flags,
+ bool has_user_gesture);
+
+ // The request method: GET, POST, etc.
+ std::string method;
+
+ // Additional HTTP request headers.
+ std::string headers;
+
+ // net::URLRequest load flags (net::LOAD_NORMAL) by default).
+ int load_flags;
+
+ // True if the request was user initiated.
+ bool has_user_gesture;
+};
+
+// Provided by the browser -----------------------------------------------------
+//
+// These structs are sent by the browser to the renderer to start/commit a
+// navigation depending on whether browser-side navigation is enabled.
+// Parameters used both in the current architecture and PlzNavigate should be
+// put in RequestNavigationParams. Parameters only used by the current
+// architecture should go in StartNavigationParams.
+
+// Used by FrameMsg_Navigate. Holds the parameters needed by the renderer to
+// start a browser-initiated navigation besides those in CommonNavigationParams.
+// The difference with the RequestNavigationParams below is that they are only
+// used in the current architecture of navigation, and will not be used by
+// PlzNavigate.
+// PlzNavigate: These are not used.
+struct CONTENT_EXPORT StartNavigationParams {
+ StartNavigationParams();
+ StartNavigationParams(
+ bool is_post,
+ const std::string& extra_headers,
+ const std::vector<unsigned char>& browser_initiated_post_data,
+ bool should_replace_current_entry,
+ int transferred_request_child_id,
+ int transferred_request_request_id);
+ ~StartNavigationParams();
// Whether the navigation is a POST request (as opposed to a GET).
bool is_post;
@@ -76,19 +142,40 @@ struct CONTENT_EXPORT RequestNavigationParams {
// If is_post is true, holds the post_data information from browser. Empty
// otherwise.
std::vector<unsigned char> browser_initiated_post_data;
-};
-// Used by FrameMsg_Navigate.
-// PlzNavigate: sent to the renderer when the navigation is ready to commit.
-struct CONTENT_EXPORT CommitNavigationParams {
- CommitNavigationParams();
- CommitNavigationParams(const PageState& page_state,
- bool is_overriding_user_agent,
- base::TimeTicks navigation_start);
- ~CommitNavigationParams();
+ // Informs the RenderView the pending navigation should replace the current
+ // history entry when it commits. This is used for cross-process redirects so
+ // the transferred navigation can recover the navigation state.
+ bool should_replace_current_entry;
+
+ // The following two members identify a previous request that has been
+ // created before this navigation is being transferred to a new render view.
+ // This serves the purpose of recycling the old request.
+ // Unless this refers to a transferred navigation, these values are -1 and -1.
+ int transferred_request_child_id;
+ int transferred_request_request_id;
+};
- // Opaque history state (received by ViewHostMsg_UpdateState).
- PageState page_state;
+// Used by FrameMsg_Navigate. Holds the parameters needed by the renderer to
+// start a browser-initiated navigation besides those in CommonNavigationParams.
+// PlzNavigate: sent to the renderer to make it issue a stream request for a
+// navigation that is ready to commit.
+struct CONTENT_EXPORT RequestNavigationParams {
+ RequestNavigationParams();
+ RequestNavigationParams(bool is_overriding_user_agent,
+ base::TimeTicks navigation_start,
+ const std::vector<GURL>& redirects,
+ bool can_load_local_resources,
+ base::Time request_time,
+ const PageState& page_state,
+ int32 page_id,
+ int nav_entry_id,
+ bool intended_as_new_entry,
+ int pending_history_list_offset,
+ int current_history_list_offset,
+ int current_history_list_length,
+ bool should_clear_history_list);
+ ~RequestNavigationParams();
// Whether or not the user agent override string should be used.
bool is_overriding_user_agent;
@@ -96,7 +183,66 @@ struct CONTENT_EXPORT CommitNavigationParams {
// The navigationStart time to expose through the Navigation Timing API to JS.
base::TimeTicks browser_navigation_start;
- // TODO(clamy): Move the redirect chain here.
+ // Any redirect URLs that occurred before |url|. Useful for cross-process
+ // navigations; defaults to empty.
+ std::vector<GURL> redirects;
+
+ // Whether or not this url should be allowed to access local file://
+ // resources.
+ bool can_load_local_resources;
+
+ // The time the request was created. This is used by the old performance
+ // infrastructure to set up DocumentState associated with the RenderView.
+ // TODO(ppi): make it go away.
+ base::Time request_time;
+
+ // Opaque history state (received by ViewHostMsg_UpdateState).
+ PageState page_state;
+
+ // The page_id for this navigation, or -1 if it is a new navigation. Back,
+ // Forward, and Reload navigations should have a valid page_id. If the load
+ // succeeds, then this page_id will be reflected in the resultant
+ // FrameHostMsg_DidCommitProvisionalLoad message.
+ int32 page_id;
+
+ // For browser-initiated navigations, this is the unique id of the
+ // NavigationEntry being navigated to. (For renderer-initiated navigations it
+ // is 0.) If the load succeeds, then this nav_entry_id will be reflected in
+ // the resulting FrameHostMsg_DidCommitProvisionalLoad message.
+ int nav_entry_id;
+
+ // For browser-initiated navigations, this is true if this is a new entry
+ // being navigated to. This is false otherwise. TODO(avi): Remove this when
+ // the pending entry situation is made sane and the browser keeps them around
+ // long enough to match them via nav_entry_id, above.
+ bool intended_as_new_entry;
+
+ // For history navigations, this is the offset in the history list of the
+ // pending load. For non-history navigations, this will be ignored.
+ int pending_history_list_offset;
+
+ // Where its current page contents reside in session history and the total
+ // size of the session history list.
+ int current_history_list_offset;
+ int current_history_list_length;
+
+ // Whether session history should be cleared. In that case, the RenderView
+ // needs to notify the browser that the clearing was succesful when the
+ // navigation commits.
+ bool should_clear_history_list;
+};
+
+// Helper struct keeping track in one place of all the parameters the browser
+// needs to provide to the renderer.
+struct NavigationParams {
+ NavigationParams(const CommonNavigationParams& common_params,
+ const StartNavigationParams& start_params,
+ const RequestNavigationParams& request_params);
+ ~NavigationParams();
+
+ CommonNavigationParams common_params;
+ StartNavigationParams start_params;
+ RequestNavigationParams request_params;
};
} // namespace content
diff --git a/chromium/content/common/navigator_connect_messages.h b/chromium/content/common/navigator_connect_messages.h
new file mode 100644
index 00000000000..760a69a2e75
--- /dev/null
+++ b/chromium/content/common/navigator_connect_messages.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.
+
+// IPC messages for navigator.connect
+
+#include "content/public/common/message_port_types.h"
+#include "content/public/common/navigator_connect_client.h"
+#include "ipc/ipc_message_macros.h"
+#include "url/gurl.h"
+
+#define IPC_MESSAGE_START NavigatorConnectMsgStart
+
+IPC_STRUCT_TRAITS_BEGIN(content::NavigatorConnectClient)
+ IPC_STRUCT_TRAITS_MEMBER(target_url)
+ IPC_STRUCT_TRAITS_MEMBER(origin)
+ IPC_STRUCT_TRAITS_MEMBER(message_port_id)
+IPC_STRUCT_TRAITS_END()
+
+// Messages sent from the child process to the browser.
+IPC_MESSAGE_CONTROL3(NavigatorConnectHostMsg_Connect,
+ int /* thread_id */,
+ int /* request_id */,
+ content::NavigatorConnectClient /* client */)
+
+// Messages sent from the browser to the child process.
+IPC_MESSAGE_CONTROL5(NavigatorConnectMsg_ConnectResult,
+ int /* thread_id */,
+ int /* request_id */,
+ content::TransferredMessagePort /* message_port */,
+ int /* message_port_route_id */,
+ bool /* allow_connect */)
diff --git a/chromium/content/common/origin_util.cc b/chromium/content/common/origin_util.cc
new file mode 100644
index 00000000000..1b16422ed11
--- /dev/null
+++ b/chromium/content/common/origin_util.cc
@@ -0,0 +1,66 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/public/common/origin_util.h"
+
+#include "base/lazy_instance.h"
+#include "base/stl_util.h"
+#include "content/public/common/content_client.h"
+#include "net/base/net_util.h"
+#include "url/gurl.h"
+
+namespace content {
+
+namespace {
+
+class SecureSchemeAndOriginSet {
+ public:
+ SecureSchemeAndOriginSet() { Reset(); }
+ ~SecureSchemeAndOriginSet() {}
+
+ void Reset() {
+ GetContentClient()->AddSecureSchemesAndOrigins(&schemes_, &origins_);
+ }
+
+ const std::set<std::string>& schemes() const { return schemes_; }
+ const std::set<GURL>& origins() const { return origins_; }
+
+ private:
+ std::set<std::string> schemes_;
+ std::set<GURL> origins_;
+ DISALLOW_COPY_AND_ASSIGN(SecureSchemeAndOriginSet);
+};
+
+base::LazyInstance<SecureSchemeAndOriginSet>::Leaky g_trustworthy_whitelist =
+ LAZY_INSTANCE_INITIALIZER;
+
+} // namespace
+
+bool IsOriginSecure(const GURL& url) {
+ if (url.SchemeIsCryptographic() || url.SchemeIsFile())
+ return true;
+
+ if (url.SchemeIsFileSystem() && url.inner_url() &&
+ IsOriginSecure(*url.inner_url())) {
+ return true;
+ }
+
+ std::string hostname = url.HostNoBrackets();
+ if (net::IsLocalhost(hostname))
+ return true;
+
+ if (ContainsKey(g_trustworthy_whitelist.Get().schemes(), url.scheme()))
+ return true;
+
+ if (ContainsKey(g_trustworthy_whitelist.Get().origins(), url.GetOrigin()))
+ return true;
+
+ return false;
+}
+
+void ResetSecureSchemesAndOriginsForTesting() {
+ g_trustworthy_whitelist.Get().Reset();
+}
+
+} // namespace content
diff --git a/chromium/content/common/origin_util_unittest.cc b/chromium/content/common/origin_util_unittest.cc
new file mode 100644
index 00000000000..49598f659b8
--- /dev/null
+++ b/chromium/content/common/origin_util_unittest.cc
@@ -0,0 +1,51 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "content/public/common/origin_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace content {
+
+TEST(URLSchemesTest, IsOriginSecure) {
+ EXPECT_TRUE(IsOriginSecure(GURL("file:///test/fun.html")));
+ EXPECT_TRUE(IsOriginSecure(GURL("file:///test/")));
+
+ EXPECT_TRUE(IsOriginSecure(GURL("https://example.com/fun.html")));
+ EXPECT_FALSE(IsOriginSecure(GURL("http://example.com/fun.html")));
+
+ EXPECT_TRUE(IsOriginSecure(GURL("wss://example.com/fun.html")));
+ EXPECT_FALSE(IsOriginSecure(GURL("ws://example.com/fun.html")));
+
+ EXPECT_TRUE(IsOriginSecure(GURL("http://localhost/fun.html")));
+ EXPECT_TRUE(IsOriginSecure(GURL("http://pumpkin.localhost/fun.html")));
+ EXPECT_TRUE(
+ IsOriginSecure(GURL("http://crumpet.pumpkin.localhost/fun.html")));
+ EXPECT_TRUE(IsOriginSecure(GURL("http://pumpkin.localhost:8080/fun.html")));
+ EXPECT_TRUE(
+ IsOriginSecure(GURL("http://crumpet.pumpkin.localhost:3000/fun.html")));
+ EXPECT_FALSE(IsOriginSecure(GURL("http://localhost.com/fun.html")));
+ EXPECT_TRUE(IsOriginSecure(GURL("https://localhost.com/fun.html")));
+
+ EXPECT_TRUE(IsOriginSecure(GURL("http://127.0.0.1/fun.html")));
+ EXPECT_TRUE(IsOriginSecure(GURL("ftp://127.0.0.1/fun.html")));
+ EXPECT_TRUE(IsOriginSecure(GURL("http://127.3.0.1/fun.html")));
+ EXPECT_FALSE(IsOriginSecure(GURL("http://127.example.com/fun.html")));
+ EXPECT_TRUE(IsOriginSecure(GURL("https://127.example.com/fun.html")));
+
+ EXPECT_TRUE(IsOriginSecure(GURL("http://[::1]/fun.html")));
+ EXPECT_FALSE(IsOriginSecure(GURL("http://[::2]/fun.html")));
+ EXPECT_FALSE(IsOriginSecure(GURL("http://[::1].example.com/fun.html")));
+
+ EXPECT_FALSE(
+ IsOriginSecure(GURL("filesystem:http://www.example.com/temporary/")));
+ EXPECT_FALSE(
+ IsOriginSecure(GURL("filesystem:ftp://www.example.com/temporary/")));
+ EXPECT_TRUE(IsOriginSecure(GURL("filesystem:ftp://127.0.0.1/temporary/")));
+ EXPECT_TRUE(
+ IsOriginSecure(GURL("filesystem:https://www.example.com/temporary/")));
+}
+
+} // namespace content
diff --git a/chromium/content/common/p2p_messages.h b/chromium/content/common/p2p_messages.h
index e1237947743..b72d8325480 100644
--- a/chromium/content/common/p2p_messages.h
+++ b/chromium/content/common/p2p_messages.h
@@ -28,7 +28,7 @@ IPC_STRUCT_TRAITS_BEGIN(net::NetworkInterface)
IPC_STRUCT_TRAITS_MEMBER(name)
IPC_STRUCT_TRAITS_MEMBER(type)
IPC_STRUCT_TRAITS_MEMBER(address)
- IPC_STRUCT_TRAITS_MEMBER(network_prefix)
+ IPC_STRUCT_TRAITS_MEMBER(prefix_length)
IPC_STRUCT_TRAITS_MEMBER(ip_address_attributes)
IPC_STRUCT_TRAITS_END()
@@ -49,6 +49,10 @@ IPC_STRUCT_TRAITS_BEGIN(content::P2PHostAndIPEndPoint)
IPC_STRUCT_TRAITS_MEMBER(ip_address)
IPC_STRUCT_TRAITS_END()
+IPC_STRUCT_TRAITS_BEGIN(content::P2PSendPacketMetrics)
+ IPC_STRUCT_TRAITS_MEMBER(packet_id)
+IPC_STRUCT_TRAITS_END()
+
// P2P Socket messages sent from the browser to the renderer.
IPC_MESSAGE_CONTROL1(P2PMsg_NetworkListChanged,
@@ -63,8 +67,10 @@ IPC_MESSAGE_CONTROL3(P2PMsg_OnSocketCreated,
net::IPEndPoint /* local_address */,
net::IPEndPoint /* remote_address */)
-IPC_MESSAGE_CONTROL1(P2PMsg_OnSendComplete,
- int /* socket_id */)
+// |send_metrics| carries packet_id for this packet.
+IPC_MESSAGE_CONTROL2(P2PMsg_OnSendComplete,
+ int /* socket_id */,
+ content::P2PSendPacketMetrics /* send_metrics */)
IPC_MESSAGE_CONTROL1(P2PMsg_OnError,
int /* socket_id */)
diff --git a/chromium/content/common/p2p_socket_type.h b/chromium/content/common/p2p_socket_type.h
index b47ae933134..ed77296b28d 100644
--- a/chromium/content/common/p2p_socket_type.h
+++ b/chromium/content/common/p2p_socket_type.h
@@ -48,6 +48,16 @@ struct P2PHostAndIPEndPoint {
net::IPEndPoint ip_address;
};
+// Stuct which keeps track of metrics during a send operation on P2P sockets.
+// Currently, it only carries packet_id but could be expanded to include
+// timestamps when packet arrives at various points.
+struct P2PSendPacketMetrics {
+ P2PSendPacketMetrics() : packet_id(0) {}
+ explicit P2PSendPacketMetrics(uint64_t packet_id) : packet_id(packet_id) {}
+
+ uint64_t packet_id;
+};
+
} // namespace content
#endif // CONTENT_COMMON_P2P_SOCKET_TYPE_H_
diff --git a/chromium/content/common/page_state_serialization.cc b/chromium/content/common/page_state_serialization.cc
index d99830a2ce2..cff62c36ce3 100644
--- a/chromium/content/common/page_state_serialization.cc
+++ b/chromium/content/common/page_state_serialization.cc
@@ -193,13 +193,14 @@ struct SerializeObject {
// which is no longer used.
// 20: Add pinch viewport scroll offset, the offset of the pinched zoomed
// viewport within the unzoomed main frame.
-// 21: Add frame sequence number
+// 21: Add frame sequence number.
+// 22: Add scroll restoration type.
//
// NOTE: If the version is -1, then the pickle contains only a URL string.
// See ReadPageState.
//
const int kMinVersion = 11;
-const int kCurrentVersion = 21;
+const int kCurrentVersion = 22;
// A bunch of convenience functions to read/write to SerializeObjects. The
// de-serializers assume the input data will be in the correct format and fall
@@ -211,7 +212,7 @@ void WriteData(const void* data, int length, SerializeObject* obj) {
void ReadData(SerializeObject* obj, const void** data, int* length) {
const char* tmp;
- if (obj->pickle.ReadData(&obj->iter, &tmp, length)) {
+ if (obj->iter.ReadData(&tmp, length)) {
*data = tmp;
} else {
obj->parse_error = true;
@@ -226,7 +227,7 @@ void WriteInteger(int data, SerializeObject* obj) {
int ReadInteger(SerializeObject* obj) {
int tmp;
- if (obj->pickle.ReadInt(&obj->iter, &tmp))
+ if (obj->iter.ReadInt(&tmp))
return tmp;
obj->parse_error = true;
return 0;
@@ -238,7 +239,7 @@ void WriteInteger64(int64 data, SerializeObject* obj) {
int64 ReadInteger64(SerializeObject* obj) {
int64 tmp = 0;
- if (obj->pickle.ReadInt64(&obj->iter, &tmp))
+ if (obj->iter.ReadInt64(&tmp))
return tmp;
obj->parse_error = true;
return 0;
@@ -268,7 +269,7 @@ void WriteBoolean(bool data, SerializeObject* obj) {
bool ReadBoolean(SerializeObject* obj) {
bool tmp;
- if (obj->pickle.ReadBool(&obj->iter, &tmp))
+ if (obj->iter.ReadBool(&tmp))
return tmp;
obj->parse_error = true;
return false;
@@ -280,7 +281,7 @@ void WriteGURL(const GURL& url, SerializeObject* obj) {
GURL ReadGURL(SerializeObject* obj) {
std::string spec;
- if (obj->pickle.ReadString(&obj->iter, &spec))
+ if (obj->iter.ReadString(&spec))
return GURL(spec);
obj->parse_error = true;
return GURL();
@@ -292,7 +293,7 @@ void WriteStdString(const std::string& s, SerializeObject* obj) {
std::string ReadStdString(SerializeObject* obj) {
std::string s;
- if (obj->pickle.ReadString(&obj->iter, &s))
+ if (obj->iter.ReadString(&s))
return s;
obj->parse_error = true;
return std::string();
@@ -319,7 +320,7 @@ void WriteString(const base::NullableString16& str, SerializeObject* obj) {
// read, NULL is returned.
const base::char16* ReadStringNoCopy(SerializeObject* obj, int* num_chars) {
int length_in_bytes;
- if (!obj->pickle.ReadInt(&obj->iter, &length_in_bytes)) {
+ if (!obj->iter.ReadInt(&length_in_bytes)) {
obj->parse_error = true;
return NULL;
}
@@ -328,7 +329,7 @@ const base::char16* ReadStringNoCopy(SerializeObject* obj, int* num_chars) {
return NULL;
const char* data;
- if (!obj->pickle.ReadBytes(&obj->iter, &data, length_in_bytes)) {
+ if (!obj->iter.ReadBytes(&data, length_in_bytes)) {
obj->parse_error = true;
return NULL;
}
@@ -497,6 +498,8 @@ void WriteFrameState(
WriteReal(state.pinch_viewport_scroll_offset.x(), obj);
WriteReal(state.pinch_viewport_scroll_offset.y(), obj);
+ WriteInteger(state.scroll_restoration_type, obj);
+
bool has_state_object = !state.state_object.is_null();
WriteBoolean(has_state_object, obj);
if (has_state_object)
@@ -568,6 +571,11 @@ void ReadFrameState(SerializeObject* obj, bool is_top,
state->pinch_viewport_scroll_offset = gfx::PointF(-1, -1);
}
+ if (obj->version >= 22) {
+ state->scroll_restoration_type =
+ static_cast<blink::WebHistoryScrollRestorationType>(ReadInteger(obj));
+ }
+
bool has_state_object = ReadBoolean(obj);
if (has_state_object)
state->state_object = ReadString(obj);
@@ -674,7 +682,8 @@ ExplodedHttpBody::~ExplodedHttpBody() {
}
ExplodedFrameState::ExplodedFrameState()
- : item_sequence_number(0),
+ : scroll_restoration_type(blink::WebHistoryScrollRestorationAuto),
+ item_sequence_number(0),
document_sequence_number(0),
frame_sequence_number(0),
page_scale_factor(0.0),
@@ -699,6 +708,7 @@ void ExplodedFrameState::assign(const ExplodedFrameState& other) {
target = other.target;
state_object = other.state_object;
document_state = other.document_state;
+ scroll_restoration_type = other.scroll_restoration_type;
pinch_viewport_scroll_offset = other.pinch_viewport_scroll_offset;
scroll_offset = other.scroll_offset;
item_sequence_number = other.item_sequence_number;
diff --git a/chromium/content/common/page_state_serialization.h b/chromium/content/common/page_state_serialization.h
index e31780fd3c3..9613a2ee0da 100644
--- a/chromium/content/common/page_state_serialization.h
+++ b/chromium/content/common/page_state_serialization.h
@@ -10,9 +10,10 @@
#include "base/strings/nullable_string16.h"
#include "content/common/content_export.h"
#include "third_party/WebKit/public/platform/WebHTTPBody.h"
+#include "third_party/WebKit/public/platform/WebHistoryScrollRestorationType.h"
#include "third_party/WebKit/public/platform/WebReferrerPolicy.h"
-#include "ui/gfx/point.h"
-#include "ui/gfx/point_f.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/point_f.h"
#include "url/gurl.h"
namespace content {
@@ -48,6 +49,7 @@ struct CONTENT_EXPORT ExplodedFrameState {
base::NullableString16 target;
base::NullableString16 state_object;
std::vector<base::NullableString16> document_state;
+ blink::WebHistoryScrollRestorationType scroll_restoration_type;
gfx::PointF pinch_viewport_scroll_offset;
gfx::Point scroll_offset;
int64 item_sequence_number;
@@ -68,6 +70,9 @@ private:
};
struct CONTENT_EXPORT ExplodedPageState {
+ // TODO(creis): Move referenced_files to ExplodedFrameState.
+ // It currently contains a list from all frames, but cannot be deserialized
+ // into the files referenced by each frame. See http://crbug.com/441966.
std::vector<base::NullableString16> referenced_files;
ExplodedFrameState top;
diff --git a/chromium/content/common/page_state_serialization_unittest.cc b/chromium/content/common/page_state_serialization_unittest.cc
index 3c25bccd565..f860b215747 100644
--- a/chromium/content/common/page_state_serialization_unittest.cc
+++ b/chromium/content/common/page_state_serialization_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 <math.h>
+#include <cmath>
#include "base/base64.h"
#include "base/files/file_util.h"
@@ -18,10 +18,6 @@
namespace content {
namespace {
-#if defined(OS_WIN)
-inline bool isnan(double num) { return !!_isnan(num); }
-#endif
-
base::NullableString16 NS16(const char* s) {
return s ? base::NullableString16(base::ASCIIToUTF16(s), false) :
base::NullableString16();
@@ -50,8 +46,10 @@ void ExpectEquality(const ExplodedHttpBodyElement& a,
EXPECT_EQ(a.filesystem_url, b.filesystem_url);
EXPECT_EQ(a.file_start, b.file_start);
EXPECT_EQ(a.file_length, b.file_length);
- if (!(isnan(a.file_modification_time) && isnan(b.file_modification_time)))
+ if (!(std::isnan(a.file_modification_time) &&
+ std::isnan(b.file_modification_time))) {
EXPECT_DOUBLE_EQ(a.file_modification_time, b.file_modification_time);
+ }
EXPECT_EQ(a.blob_uuid, b.blob_uuid);
}
@@ -72,6 +70,7 @@ void ExpectEquality(const ExplodedFrameState& a, const ExplodedFrameState& b) {
EXPECT_EQ(a.target, b.target);
EXPECT_EQ(a.state_object, b.state_object);
ExpectEquality(a.document_state, b.document_state);
+ EXPECT_EQ(a.scroll_restoration_type, b.scroll_restoration_type);
EXPECT_EQ(a.pinch_viewport_scroll_offset, b.pinch_viewport_scroll_offset);
EXPECT_EQ(a.scroll_offset, b.scroll_offset);
EXPECT_EQ(a.item_sequence_number, b.item_sequence_number);
@@ -101,6 +100,8 @@ class PageStateSerializationTest : public testing::Test {
frame_state->document_state.push_back(NS16("q"));
frame_state->document_state.push_back(NS16("text"));
frame_state->document_state.push_back(NS16("dev.chromium.org"));
+ frame_state->scroll_restoration_type =
+ blink::WebHistoryScrollRestorationManual;
frame_state->pinch_viewport_scroll_offset = gfx::PointF(10, 15);
frame_state->scroll_offset = gfx::Point(0, 100);
frame_state->item_sequence_number = 1;
@@ -140,6 +141,8 @@ class PageStateSerializationTest : public testing::Test {
frame_state->referrer_policy = blink::WebReferrerPolicyDefault;
if (!is_child)
frame_state->target = NS16("target");
+ frame_state->scroll_restoration_type =
+ blink::WebHistoryScrollRestorationAuto;
frame_state->pinch_viewport_scroll_offset = gfx::PointF(-1, -1);
frame_state->scroll_offset = gfx::Point(42, -42);
frame_state->item_sequence_number = 123;
@@ -430,5 +433,9 @@ TEST_F(PageStateSerializationTest, BackwardsCompat_v20) {
TestBackwardsCompat(20);
}
+TEST_F(PageStateSerializationTest, BackwardsCompat_v21) {
+ TestBackwardsCompat(21);
+}
+
} // namespace
} // namespace content
diff --git a/chromium/content/common/pepper_file_util.cc b/chromium/content/common/pepper_file_util.cc
index fea5ef24cf3..be253c150c9 100644
--- a/chromium/content/common/pepper_file_util.cc
+++ b/chromium/content/common/pepper_file_util.cc
@@ -20,4 +20,26 @@ storage::FileSystemType PepperFileSystemTypeToFileSystemType(
}
}
+base::PlatformFile PlatformFileFromSharedMemoryHandle(
+ const base::SharedMemoryHandle& shm_handle) {
+#if defined(OS_WIN)
+ return shm_handle;
+#elif defined(OS_POSIX)
+ return shm_handle.fd;
+#else
+#error Platform not supported.
+#endif
+}
+
+int IntegerFromSyncSocketHandle(
+ const base::SyncSocket::Handle& socket_handle) {
+#if defined(OS_WIN)
+ return reinterpret_cast<int>(socket_handle);
+#elif defined(OS_POSIX)
+ return socket_handle;
+#else
+#error Platform not supported.
+#endif
+}
+
} // namespace content
diff --git a/chromium/content/common/pepper_file_util.h b/chromium/content/common/pepper_file_util.h
index aab9c1d63fc..b276cfa88a4 100644
--- a/chromium/content/common/pepper_file_util.h
+++ b/chromium/content/common/pepper_file_util.h
@@ -5,6 +5,9 @@
#ifndef CONTENT_COMMON_PEPPER_FILE_UTIL_H_
#define CONTENT_COMMON_PEPPER_FILE_UTIL_H_
+#include "base/files/file.h"
+#include "base/memory/shared_memory.h"
+#include "base/sync_socket.h"
#include "ppapi/c/pp_file_info.h"
#include "storage/common/fileapi/file_system_types.h"
@@ -17,6 +20,12 @@ namespace content {
storage::FileSystemType PepperFileSystemTypeToFileSystemType(
PP_FileSystemType type);
+base::PlatformFile PlatformFileFromSharedMemoryHandle(
+ const base::SharedMemoryHandle& shm_handle);
+
+int IntegerFromSyncSocketHandle(
+ const base::SyncSocket::Handle& socket_handle);
+
} // namespace content
#endif // CONTENT_COMMON_PEPPER_FILE_UTIL_H_
diff --git a/chromium/content/common/pepper_plugin_list.cc b/chromium/content/common/pepper_plugin_list.cc
index 81eda1aeac5..704c81996f8 100644
--- a/chromium/content/common/pepper_plugin_list.cc
+++ b/chromium/content/common/pepper_plugin_list.cc
@@ -31,9 +31,9 @@ void ComputePluginsFromCommandLine(std::vector<PepperPluginInfo>* plugins) {
// NOTE: In theory we could have unlimited number of plugins registered in
// command line. But in practice, 64 plugins should be more than enough.
static uint64 skip_file_check_flags = 0;
- COMPILE_ASSERT(
+ static_assert(
kMaxPluginsToRegisterFromCommandLine <= sizeof(skip_file_check_flags) * 8,
- max_plugins_to_register_from_command_line_exceeds_limit);
+ "max plugins to register from command line exceeds limit");
bool out_of_process = true;
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
@@ -57,9 +57,9 @@ void ComputePluginsFromCommandLine(std::vector<PepperPluginInfo>* plugins) {
size_t plugins_to_register = modules.size();
if (plugins_to_register > kMaxPluginsToRegisterFromCommandLine) {
- VLOG(1) << plugins_to_register << " pepper plugins registered from"
- << " command line which exceeds the limit (maximum "
- << kMaxPluginsToRegisterFromCommandLine << " plugins allowed)";
+ DVLOG(1) << plugins_to_register << " pepper plugins registered from"
+ << " command line which exceeds the limit (maximum "
+ << kMaxPluginsToRegisterFromCommandLine << " plugins allowed)";
plugins_to_register = kMaxPluginsToRegisterFromCommandLine;
}
@@ -67,7 +67,7 @@ void ComputePluginsFromCommandLine(std::vector<PepperPluginInfo>* plugins) {
std::vector<std::string> parts;
base::SplitString(modules[i], ';', &parts);
if (parts.size() < 2) {
- VLOG(1) << "Required mime-type not found";
+ DVLOG(1) << "Required mime-type not found";
continue;
}
@@ -90,7 +90,7 @@ void ComputePluginsFromCommandLine(std::vector<PepperPluginInfo>* plugins) {
if (base::PathExists(plugin.path)) {
skip_file_check_flags |= index_mask;
} else {
- VLOG(1) << "Plugin doesn't exist: " << plugin.path.MaybeAsASCII();
+ DVLOG(1) << "Plugin doesn't exist: " << plugin.path.MaybeAsASCII();
continue;
}
}
@@ -129,10 +129,7 @@ bool MakePepperPluginInfo(const WebPluginInfo& webplugin_info,
return false;
pepper_info->is_out_of_process =
- webplugin_info.type == WebPluginInfo::PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS ||
- webplugin_info.type == WebPluginInfo::PLUGIN_TYPE_PEPPER_UNSANDBOXED;
- pepper_info->is_sandboxed = webplugin_info.type !=
- WebPluginInfo::PLUGIN_TYPE_PEPPER_UNSANDBOXED;
+ webplugin_info.type == WebPluginInfo::PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS;
pepper_info->path = base::FilePath(webplugin_info.path);
pepper_info->name = base::UTF16ToASCII(webplugin_info.name);
diff --git a/chromium/content/common/pepper_renderer_instance_data.cc b/chromium/content/common/pepper_renderer_instance_data.cc
index 6fda4bfd69f..8ec9320e891 100644
--- a/chromium/content/common/pepper_renderer_instance_data.cc
+++ b/chromium/content/common/pepper_renderer_instance_data.cc
@@ -8,18 +8,20 @@ namespace content {
PepperRendererInstanceData::PepperRendererInstanceData()
: render_process_id(0),
- render_frame_id(0) {
+ render_frame_id(0),
+ is_potentially_secure_plugin_context(false) {
}
-PepperRendererInstanceData::PepperRendererInstanceData(
- int render_process,
- int render_frame,
- const GURL& document,
- const GURL& plugin)
+PepperRendererInstanceData::PepperRendererInstanceData(int render_process,
+ int render_frame,
+ const GURL& document,
+ const GURL& plugin,
+ bool secure)
: render_process_id(render_process),
render_frame_id(render_frame),
document_url(document),
- plugin_url(plugin) {
+ plugin_url(plugin),
+ is_potentially_secure_plugin_context(secure) {
}
PepperRendererInstanceData::~PepperRendererInstanceData() {
diff --git a/chromium/content/common/pepper_renderer_instance_data.h b/chromium/content/common/pepper_renderer_instance_data.h
index 6b3baa40059..84e9f97519e 100644
--- a/chromium/content/common/pepper_renderer_instance_data.h
+++ b/chromium/content/common/pepper_renderer_instance_data.h
@@ -22,12 +22,17 @@ struct PepperRendererInstanceData {
PepperRendererInstanceData(int render_process,
int render_frame_id,
const GURL& document,
- const GURL& plugin);
+ const GURL& plugin,
+ bool secure);
~PepperRendererInstanceData();
int render_process_id;
int render_frame_id;
GURL document_url;
GURL plugin_url;
+ // Whether the plugin context is secure. That is, it is served from a secure
+ // origin and it is embedded within a hierarchy of secure frames. This value
+ // comes from the renderer so should not be trusted. It is used for metrics.
+ bool is_potentially_secure_plugin_context;
};
} // namespace content
diff --git a/chromium/content/common/permission_service.mojom b/chromium/content/common/permission_service.mojom
new file mode 100644
index 00000000000..16d4866355c
--- /dev/null
+++ b/chromium/content/common/permission_service.mojom
@@ -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.
+
+module content;
+
+import "content/public/common/permission_status.mojom";
+
+enum PermissionName {
+ GEOLOCATION,
+ NOTIFICATIONS,
+ PUSH_NOTIFICATIONS,
+ MIDI_SYSEX,
+ PROTECTED_MEDIA_IDENTIFIER,
+};
+
+// The Permission service provides permission handling capabilities by exposing
+// methods to check, request, and revoke permissions. It also allows a client to
+// start listening to permission changes.
+interface PermissionService {
+ HasPermission(PermissionName permission, string origin)
+ => (PermissionStatus status);
+ RequestPermission(PermissionName permission, string origin, bool user_gesture)
+ => (PermissionStatus status);
+ RevokePermission(PermissionName permission, string origin)
+ => (PermissionStatus status);
+
+ // Runs the callback next time there is a permission status change for the
+ // given { permission, origin }. Callers of this method will have to call it
+ // again if they want to keep listening to the changes. To prevent race
+ // conditions, the caller must pass the last known value.
+ GetNextPermissionChange(PermissionName permission,
+ string origin,
+ PermissionStatus last_known_status)
+ => (PermissionStatus status);
+};
diff --git a/chromium/content/common/platform_notification_messages.h b/chromium/content/common/platform_notification_messages.h
index 1585165af7f..009ff619e5c 100644
--- a/chromium/content/common/platform_notification_messages.h
+++ b/chromium/content/common/platform_notification_messages.h
@@ -5,23 +5,49 @@
// Messages for platform-native notifications using the Web Notification API.
// Multiply-included message file, hence no include guard.
-#include "content/public/common/show_desktop_notification_params.h"
+#include <stdint.h>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "content/public/common/platform_notification_data.h"
#include "ipc/ipc_message_macros.h"
-#include "third_party/WebKit/public/platform/WebNotificationPermission.h"
-#include "url/gurl.h"
+#include "third_party/WebKit/public/platform/modules/notifications/WebNotificationPermission.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+// Singly-included section for type definitions.
+#ifndef CONTENT_COMMON_PLATFORM_NOTIFICATION_MESSAGES_H_
+#define CONTENT_COMMON_PLATFORM_NOTIFICATION_MESSAGES_H_
+
+// Defines the pair of [persistent notification id] => [notification data] used
+// when getting the notifications for a given Service Worker registration.
+using PersistentNotificationInfo =
+ std::pair<int64_t, content::PlatformNotificationData>;
+
+#endif // CONTENT_COMMON_PLATFORM_NOTIFICATION_MESSAGES_H_
#define IPC_MESSAGE_START PlatformNotificationMsgStart
IPC_ENUM_TRAITS_MAX_VALUE(blink::WebNotificationPermission,
blink::WebNotificationPermissionLast)
-// Messages sent from the browser to the renderer.
+IPC_ENUM_TRAITS_MAX_VALUE(
+ content::PlatformNotificationData::NotificationDirection,
+ content::PlatformNotificationData::NotificationDirectionLast)
+
+IPC_STRUCT_TRAITS_BEGIN(content::PlatformNotificationData)
+ IPC_STRUCT_TRAITS_MEMBER(title)
+ IPC_STRUCT_TRAITS_MEMBER(direction)
+ IPC_STRUCT_TRAITS_MEMBER(lang)
+ IPC_STRUCT_TRAITS_MEMBER(body)
+ IPC_STRUCT_TRAITS_MEMBER(tag)
+ IPC_STRUCT_TRAITS_MEMBER(icon)
+ IPC_STRUCT_TRAITS_MEMBER(vibration_pattern)
+ IPC_STRUCT_TRAITS_MEMBER(silent)
+ IPC_STRUCT_TRAITS_MEMBER(data)
+IPC_STRUCT_TRAITS_END()
-// Informs the renderer that the permission request for |request_id| is done,
-// and has been settled with |result|.
-IPC_MESSAGE_ROUTED2(PlatformNotificationMsg_PermissionRequestComplete,
- int /* request_id */,
- blink::WebNotificationPermission /* result */)
+// Messages sent from the browser to the renderer.
// Informs the renderer that the browser has displayed the notification.
IPC_MESSAGE_CONTROL1(PlatformNotificationMsg_DidShow,
@@ -35,20 +61,48 @@ IPC_MESSAGE_CONTROL1(PlatformNotificationMsg_DidClose,
IPC_MESSAGE_CONTROL1(PlatformNotificationMsg_DidClick,
int /* notification_id */)
-// Messages sent from the renderer to the browser.
+// Reply to PlatformNotificationHostMsg_ShowPersistent indicating that a
+// persistent notification has been shown on the platform (if |success| is
+// true), or that an unspecified error occurred.
+IPC_MESSAGE_CONTROL2(PlatformNotificationMsg_DidShowPersistent,
+ int /* request_id */,
+ bool /* success */)
+
+// Reply to PlatformNotificationHostMsg_GetNotifications sharing a vector of
+// available notifications per the request's constraints.
+IPC_MESSAGE_CONTROL2(PlatformNotificationMsg_DidGetNotifications,
+ int /* request_id */,
+ std::vector<PersistentNotificationInfo>
+ /* notifications */)
-// Requests permission to display platform notifications for |origin|.
-IPC_MESSAGE_ROUTED2(PlatformNotificationHostMsg_RequestPermission,
- GURL /* origin */,
- int /* request_id */)
+// Messages sent from the renderer to the browser.
-IPC_MESSAGE_CONTROL2(PlatformNotificationHostMsg_Show,
+IPC_MESSAGE_CONTROL4(PlatformNotificationHostMsg_Show,
int /* notification_id */,
- content::ShowDesktopNotificationHostMsgParams /* params */)
+ GURL /* origin */,
+ SkBitmap /* icon */,
+ content::PlatformNotificationData /* notification_data */)
+
+IPC_MESSAGE_CONTROL5(PlatformNotificationHostMsg_ShowPersistent,
+ int /* request_id */,
+ int64_t /* service_worker_registration_id */,
+ GURL /* origin */,
+ SkBitmap /* icon */,
+ content::PlatformNotificationData /* notification_data */)
+
+IPC_MESSAGE_CONTROL4(PlatformNotificationHostMsg_GetNotifications,
+ int /* request_id */,
+ int64_t /* service_worker_registration_id */,
+ GURL /* origin */,
+ std::string /* filter_tag */)
IPC_MESSAGE_CONTROL1(PlatformNotificationHostMsg_Close,
int /* notification_id */)
+IPC_MESSAGE_CONTROL2(PlatformNotificationHostMsg_ClosePersistent,
+ GURL /* origin */,
+ int64_t /* persistent_notification_id */)
+
IPC_SYNC_MESSAGE_CONTROL1_1(PlatformNotificationHostMsg_CheckPermission,
GURL /* origin */,
blink::WebNotificationPermission /* result */)
diff --git a/chromium/content/common/plugin_list.cc b/chromium/content/common/plugin_list.cc
index a0f9507ea9d..7e8d1c2e355 100644
--- a/chromium/content/common/plugin_list.cc
+++ b/chromium/content/common/plugin_list.cc
@@ -278,7 +278,7 @@ void PluginList::GetPluginPathsToLoad(std::vector<base::FilePath>* plugin_paths,
void PluginList::SetPlugins(const std::vector<WebPluginInfo>& plugins) {
base::AutoLock lock(lock_);
- // If we haven't been invalidated in the mean time, mark the plug-in list as
+ // If we haven't been invalidated in the mean time, mark the plugin list as
// up-to-date.
if (loading_state_ != LOADING_STATE_NEEDS_REFRESH)
loading_state_ = LOADING_STATE_UP_TO_DATE;
@@ -340,11 +340,11 @@ void PluginList::GetPluginInfoArray(
}
// Add in plugins by url.
- // We do not permit URL-sniff based plug-in MIME type overrides aside from
+ // We do not permit URL-sniff based plugin MIME type overrides aside from
// the case where the "type" was initially missing.
// We collected stats to determine this approach isn't a major compat issue,
// and we defend against content confusion attacks in various cases, such
- // as when the user doesn't have the Flash plug-in enabled.
+ // as when the user doesn't have the Flash plugin enabled.
std::string path = url.path();
std::string::size_type last_dot = path.rfind('.');
if (last_dot != std::string::npos && mime_type.empty()) {
diff --git a/chromium/content/common/plugin_list.h b/chromium/content/common/plugin_list.h
index 9ad67fc8634..26a2aa64953 100644
--- a/chromium/content/common/plugin_list.h
+++ b/chromium/content/common/plugin_list.h
@@ -103,7 +103,7 @@ class CONTENT_EXPORT PluginList {
void GetPlugins(std::vector<WebPluginInfo>* plugins,
bool include_npapi);
- // Copies the list of plug-ins into |plugins| without loading them.
+ // Copies the list of plugins into |plugins| without loading them.
// Returns true if the list of plugins is up-to-date.
bool GetPluginsNoRefresh(std::vector<WebPluginInfo>* plugins);
@@ -116,9 +116,9 @@ class CONTENT_EXPORT PluginList {
// returns plugins which support wildcard mime types (* as the mime
// type). The |info| parameter is required to be non-NULL. The
// list is in order of "most desirable" to "least desirable".
- // If |use_stale| is NULL, this will load the plug-in list if necessary.
- // If it is not NULL, the plug-in list will not be loaded, and |*use_stale|
- // will be true iff the plug-in list was stale.
+ // If |use_stale| is NULL, this will load the plugin list if necessary.
+ // If it is not NULL, the plugin list will not be loaded, and |*use_stale|
+ // will be true iff the plugin list was stale.
void GetPluginInfoArray(const GURL& url,
const std::string& mime_type,
bool allow_wildcard,
@@ -127,7 +127,7 @@ class CONTENT_EXPORT PluginList {
std::vector<WebPluginInfo>* info,
std::vector<std::string>* actual_mime_types);
- // Load a specific plugin with full path. Return true iff loading the plug-in
+ // Load a specific plugin with full path. Return true iff loading the plugin
// was successful.
bool LoadPluginIntoPluginList(const base::FilePath& filename,
std::vector<WebPluginInfo>* plugins,
@@ -212,7 +212,7 @@ class CONTENT_EXPORT PluginList {
// Internals
//
- // States whether we will load the plug-in list the next time we try to access
+ // States whether we will load the plugin list the next time we try to access
// it, whether we are currently in the process of loading it, or whether we
// consider it up-to-date.
LoadingState loading_state_;
@@ -226,7 +226,7 @@ class CONTENT_EXPORT PluginList {
// Holds information about internal plugins.
std::vector<WebPluginInfo> internal_plugins_;
- // A list holding all plug-ins.
+ // A list holding all plugins.
std::vector<WebPluginInfo> plugins_list_;
// Callback that is invoked whenever the PluginList will reload the plugins.
diff --git a/chromium/content/common/plugin_list_unittest.cc b/chromium/content/common/plugin_list_unittest.cc
index 859ac136e24..4b8150b499b 100644
--- a/chromium/content/common/plugin_list_unittest.cc
+++ b/chromium/content/common/plugin_list_unittest.cc
@@ -51,7 +51,7 @@ class PluginListTest : public testing::Test {
base::ASCIIToUTF16("bar")) {
}
- virtual void SetUp() {
+ void SetUp() override {
plugin_list_.DisablePluginsDiscovery();
plugin_list_.RegisterInternalPlugin(bar_plugin_, false);
foo_plugin_.mime_types.push_back(
diff --git a/chromium/content/common/plugin_process_messages.h b/chromium/content/common/plugin_process_messages.h
index c520dcc025e..c21186b252e 100644
--- a/chromium/content/common/plugin_process_messages.h
+++ b/chromium/content/common/plugin_process_messages.h
@@ -10,9 +10,9 @@
#include "content/public/common/common_param_traits.h"
#include "ipc/ipc_channel_handle.h"
#include "ipc/ipc_message_macros.h"
+#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/ipc/gfx_param_traits.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/rect.h"
#undef IPC_MESSAGE_EXPORT
#define IPC_MESSAGE_EXPORT CONTENT_EXPORT
diff --git a/chromium/content/common/presentation/OWNERS b/chromium/content/common/presentation/OWNERS
new file mode 100644
index 00000000000..44b349ce215
--- /dev/null
+++ b/chromium/content/common/presentation/OWNERS
@@ -0,0 +1,3 @@
+avayvod@chromium.org
+imcheng@chromium.org
+mfoltz@chromium.org \ No newline at end of file
diff --git a/chromium/content/common/presentation/presentation_service.mojom b/chromium/content/common/presentation/presentation_service.mojom
new file mode 100644
index 00000000000..bc06725ceca
--- /dev/null
+++ b/chromium/content/common/presentation/presentation_service.mojom
@@ -0,0 +1,115 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module presentation;
+
+struct PresentationSessionInfo {
+ string url;
+ string id;
+};
+
+enum PresentationSessionState {
+ CONNECTED,
+ DISCONNECTED
+};
+
+enum PresentationErrorType {
+ NO_AVAILABLE_SCREENS,
+ SESSION_REQUEST_CANCELLED,
+ NO_PRESENTATION_FOUND,
+ UNKNOWN,
+};
+
+struct PresentationError {
+ PresentationErrorType error_type;
+ string message;
+};
+
+enum PresentationMessageType {
+ TEXT,
+ ARRAY_BUFFER,
+};
+
+struct SessionMessage {
+ string presentation_url;
+ string presentation_id;
+ PresentationMessageType type;
+ string? message;
+ array<uint8>? data;
+};
+
+interface PresentationService {
+ // Called when the frame sets or changes the default presentation URL or
+ // presentation ID.
+ SetDefaultPresentationURL(
+ string default_presentation_url,
+ string? default_presentation_id);
+
+ // Sets the PresentationServiceClient.
+ SetClient(PresentationServiceClient client);
+
+ // Starts listening for screen availability for the current default
+ // presentation URL. Availability results will be returned to the client
+ // via PresentationServiceClient::OnScreenAvailabilityUpdated.
+ ListenForScreenAvailability();
+
+ // Stops listening for screen availability for the current default
+ // default presentation URL. The client will stop receiving availability
+ // updates.
+ StopListeningForScreenAvailability();
+
+ // Called when the renderer is ready to receive the browser initiated
+ // session. If the default session is started by the embedder before this
+ // call, the embedder may queue it and run the callback when the call is
+ // performed.
+ ListenForDefaultSessionStart()
+ => (PresentationSessionInfo? defaultSessionInfo);
+
+ // Called when startSession() is called by the frame. The result callback
+ // will return a non-null and valid PresentationSessionInfo if starting the
+ // session succeeded, or null with a PresentationError if starting the
+ // session failed.
+ // The presentation id is always returned along with the initialized
+ // session on success.
+ // If the UA identifies a matching session (same presentation url and id),
+ // the user may choose this existing session and the page will join it
+ // rather than get a new one. An empty presentation id means that the
+ // UA will generate the presentation id.
+ StartSession(string presentation_url, string? presentation_id)
+ => (PresentationSessionInfo? sessionInfo, PresentationError? error);
+
+ // Called when joinSession() is called by the frame. The result callback
+ // works the same as for the method above. JoinSession will join a known
+ // session (i.e. when the page navigates or the user opens another tab)
+ // silently and without user action.
+ JoinSession(string presentation_url, string? presentation_id)
+ => (PresentationSessionInfo? sessionInfo, PresentationError? error);
+
+ // Called when send() is called by the frame. The true in the
+ // result callback notifies that the service is ready for next message.
+ // The false in the result callback notifies the renderer to stop sending
+ // the send requests and invalidate all pending requests. This occurs
+ // for eg., when frame is deleted or navigated away.
+ SendSessionMessage(SessionMessage message_request) => (bool success);
+
+ // Called when closeSession() is called by the frame.
+ CloseSession(string presentation_url, string presentation_id);
+
+ // Called when the frame is ready to process the next state change. Returns
+ // the last session state if it’s changed since the last time the callback
+ // was called. Might cause the event fired with the initial state change.
+ ListenForSessionStateChange()
+ => (PresentationSessionInfo sessionInfo,
+ PresentationSessionState newState);
+
+ // Called when the frame is ready to process the next batch of messages.
+ // When the callback carries null messages, there is an error
+ // at the presentation service side.
+ ListenForSessionMessages()
+ => (array<SessionMessage>? messages);
+};
+
+interface PresentationServiceClient {
+ OnScreenAvailabilityUpdated(bool available);
+};
diff --git a/chromium/content/common/process_type.cc b/chromium/content/common/process_type.cc
index d3c6894242f..34019d453a6 100644
--- a/chromium/content/common/process_type.cc
+++ b/chromium/content/common/process_type.cc
@@ -16,7 +16,7 @@ std::string GetProcessTypeNameInEnglish(int type) {
case PROCESS_TYPE_RENDERER:
return "Tab";
case PROCESS_TYPE_PLUGIN:
- return "Plug-in";
+ return "Plugin";
case PROCESS_TYPE_UTILITY:
return "Utility";
case PROCESS_TYPE_ZYGOTE:
diff --git a/chromium/content/common/push_messaging_messages.h b/chromium/content/common/push_messaging_messages.h
index 40a1a4b0400..dcf48b1b0d3 100644
--- a/chromium/content/common/push_messaging_messages.h
+++ b/chromium/content/common/push_messaging_messages.h
@@ -5,9 +5,12 @@
// IPC messages for push messaging.
// Multiply-included message file, hence no include guard.
+#include <stdint.h>
+
#include "content/public/common/push_messaging_status.h"
#include "ipc/ipc_message_macros.h"
-#include "third_party/WebKit/public/platform/WebPushPermissionStatus.h"
+#include "third_party/WebKit/public/platform/modules/push_messaging/WebPushError.h"
+#include "third_party/WebKit/public/platform/modules/push_messaging/WebPushPermissionStatus.h"
#include "url/gurl.h"
#define IPC_MESSAGE_START PushMessagingMsgStart
@@ -15,44 +18,86 @@
IPC_ENUM_TRAITS_MAX_VALUE(content::PushRegistrationStatus,
content::PUSH_REGISTRATION_STATUS_LAST)
+IPC_ENUM_TRAITS_MAX_VALUE(content::PushGetRegistrationStatus,
+ content::PUSH_GETREGISTRATION_STATUS_LAST)
+
IPC_ENUM_TRAITS_MAX_VALUE(
blink::WebPushPermissionStatus,
blink::WebPushPermissionStatus::WebPushPermissionStatusLast)
-// Messages sent from the browser to the renderer.
-IPC_MESSAGE_ROUTED3(PushMessagingMsg_RegisterSuccess,
- int32 /* callbacks_id */,
+IPC_ENUM_TRAITS_MAX_VALUE(
+ blink::WebPushError::ErrorType,
+ blink::WebPushError::ErrorType::ErrorTypeLast)
+
+// Messages sent from the browser to the child process.
+
+IPC_MESSAGE_ROUTED3(PushMessagingMsg_RegisterFromDocumentSuccess,
+ int32_t /* request_id */,
GURL /* push_endpoint */,
std::string /* push_registration_id */)
-IPC_MESSAGE_ROUTED2(PushMessagingMsg_RegisterError,
- int32 /* callbacks_id */,
+IPC_MESSAGE_CONTROL3(PushMessagingMsg_RegisterFromWorkerSuccess,
+ int32_t /* request_id */,
+ GURL /* push_endpoint */,
+ std::string /* push_registration_id */)
+
+IPC_MESSAGE_ROUTED2(PushMessagingMsg_RegisterFromDocumentError,
+ int32_t /* request_id */,
content::PushRegistrationStatus /* status */)
-IPC_MESSAGE_ROUTED2(PushMessagingMsg_PermissionStatusResult,
- int32 /* callback_id */,
- blink::WebPushPermissionStatus /* status */)
+IPC_MESSAGE_CONTROL2(PushMessagingMsg_RegisterFromWorkerError,
+ int32_t /* request_id */,
+ content::PushRegistrationStatus /* status */)
-IPC_MESSAGE_ROUTED1(PushMessagingMsg_PermissionStatusFailure,
- int32 /* callback_id */)
+IPC_MESSAGE_CONTROL2(PushMessagingMsg_UnregisterSuccess,
+ int32_t /* request_id */,
+ bool /* did_unregister */)
-IPC_MESSAGE_ROUTED1(PushMessagingMsg_RequestPermissionResponse,
- int32 /* request_id */)
+IPC_MESSAGE_CONTROL3(PushMessagingMsg_UnregisterError,
+ int32_t /* request_id */,
+ blink::WebPushError::ErrorType /* error_type */,
+ std::string /* error_message */)
-// Messages sent from the renderer to the browser.
+IPC_MESSAGE_CONTROL3(PushMessagingMsg_GetRegistrationSuccess,
+ int32_t /* request_id */,
+ GURL /* push_endpoint */,
+ std::string /* push_registration_id */)
-IPC_MESSAGE_CONTROL5(PushMessagingHostMsg_Register,
- int32 /* render_frame_id */,
- int32 /* callbacks_id */,
+IPC_MESSAGE_CONTROL2(PushMessagingMsg_GetRegistrationError,
+ int32_t /* request_id */,
+ content::PushGetRegistrationStatus /* status */)
+
+IPC_MESSAGE_CONTROL2(PushMessagingMsg_GetPermissionStatusSuccess,
+ int32_t /* request_id */,
+ blink::WebPushPermissionStatus /* status */)
+
+IPC_MESSAGE_CONTROL2(PushMessagingMsg_GetPermissionStatusError,
+ int32_t /* request_id */,
+ blink::WebPushError::ErrorType /* error_type */)
+
+// Messages sent from the child process to the browser.
+
+IPC_MESSAGE_CONTROL5(PushMessagingHostMsg_RegisterFromDocument,
+ int32_t /* render_frame_id */,
+ int32_t /* request_id */,
std::string /* sender_id */,
- bool /* user_gesture */,
- int32 /* service_worker_provider_id */)
+ bool /* user_visible */,
+ int64_t /* service_worker_registration_id */)
+
+IPC_MESSAGE_CONTROL3(PushMessagingHostMsg_RegisterFromWorker,
+ int32_t /* request_id */,
+ int64_t /* service_worker_registration_id */,
+ bool /* user_visible */)
+
+IPC_MESSAGE_CONTROL2(PushMessagingHostMsg_Unregister,
+ int32_t /* request_id */,
+ int64_t /* service_worker_registration_id */)
-IPC_MESSAGE_CONTROL3(PushMessagingHostMsg_PermissionStatus,
- int32 /* render_frame_id */,
- int32 /* service_worker_provider_id */,
- int32 /* permission_callback_id */)
+IPC_MESSAGE_CONTROL2(PushMessagingHostMsg_GetRegistration,
+ int32_t /* request_id */,
+ int64_t /* service_worker_registration_id */)
-IPC_MESSAGE_ROUTED2(PushMessagingHostMsg_RequestPermission,
- int32 /* request_id */,
- bool /* user_gesture */)
+IPC_MESSAGE_CONTROL3(PushMessagingHostMsg_GetPermissionStatus,
+ int32_t /* request_id */,
+ int64_t /* service_worker_registration_id */,
+ bool /* user_visible */)
diff --git a/chromium/content/common/quota_messages.h b/chromium/content/common/quota_messages.h
index 5551210f4ee..06ec3d3686d 100644
--- a/chromium/content/common/quota_messages.h
+++ b/chromium/content/common/quota_messages.h
@@ -13,7 +13,7 @@
#define IPC_MESSAGE_START QuotaMsgStart
IPC_ENUM_TRAITS_MAX_VALUE(storage::StorageType, storage::kStorageTypeLast)
-IPC_ENUM_TRAITS(storage::QuotaStatusCode)
+IPC_ENUM_TRAITS_MAX_VALUE(storage::QuotaStatusCode, storage::kQuotaStatusLast)
IPC_STRUCT_TRAITS_BEGIN(content::StorageQuotaParams)
IPC_STRUCT_TRAITS_MEMBER(render_view_id)
diff --git a/chromium/content/common/render_frame_setup.mojom b/chromium/content/common/render_frame_setup.mojom
index 0a1d433447d..b32f9532703 100644
--- a/chromium/content/common/render_frame_setup.mojom
+++ b/chromium/content/common/render_frame_setup.mojom
@@ -4,9 +4,10 @@
module content;
-import "mojo/public/interfaces/application/service_provider.mojom";
+import "mojo/application/public/interfaces/service_provider.mojom";
interface RenderFrameSetup {
- GetServiceProviderForFrame(int32 frame_routing_id,
- mojo.ServiceProvider& service_provider);
+ ExchangeServiceProviders(int32 frame_routing_id,
+ mojo.ServiceProvider& services,
+ mojo.ServiceProvider exposed_services);
};
diff --git a/chromium/content/common/resource_messages.cc b/chromium/content/common/resource_messages.cc
index 1e7632db9ea..6fcda2ab021 100644
--- a/chromium/content/common/resource_messages.cc
+++ b/chromium/content/common/resource_messages.cc
@@ -24,7 +24,7 @@ bool ParamTraits<scoped_refptr<net::HttpResponseHeaders> >::Read(
if (!ReadParam(m, iter, &has_object))
return false;
if (has_object)
- *r = new net::HttpResponseHeaders(*m, iter);
+ *r = new net::HttpResponseHeaders(iter);
return true;
}
@@ -74,7 +74,7 @@ bool ParamTraits<storage::DataElement>::Read(const Message* m,
case storage::DataElement::TYPE_BYTES: {
const char* data;
int len;
- if (!m->ReadData(iter, &data, &len))
+ if (!iter->ReadData(&data, &len))
return false;
r->SetToBytes(data, len);
break;
diff --git a/chromium/content/common/resource_messages.h b/chromium/content/common/resource_messages.h
index e35a88e06ca..a57ef1770b8 100644
--- a/chromium/content/common/resource_messages.h
+++ b/chromium/content/common/resource_messages.h
@@ -194,6 +194,9 @@ IPC_STRUCT_BEGIN(ResourceHostMsg_Request)
// or kAppCacheNoHostId.
IPC_STRUCT_MEMBER(int, appcache_host_id)
+ // True if corresponding AppCache group should be resetted.
+ IPC_STRUCT_MEMBER(bool, should_reset_appcache)
+
// Indicates which frame (or worker context) the request is being loaded into,
// or kInvalidServiceWorkerProviderId.
IPC_STRUCT_MEMBER(int, service_worker_provider_id)
@@ -228,6 +231,9 @@ IPC_STRUCT_BEGIN(ResourceHostMsg_Request)
// True if upload progress should be available for request.
IPC_STRUCT_MEMBER(bool, enable_upload_progress)
+ // True if login prompts for this request should be supressed.
+ IPC_STRUCT_MEMBER(bool, do_not_prompt_for_login)
+
// The routing id of the RenderFrame.
IPC_STRUCT_MEMBER(int, render_frame_id)
diff --git a/chromium/content/common/sandbox_init_mac.h b/chromium/content/common/sandbox_init_mac.h
index 54070814144..4bbabb397b6 100644
--- a/chromium/content/common/sandbox_init_mac.h
+++ b/chromium/content/common/sandbox_init_mac.h
@@ -7,7 +7,7 @@
namespace content {
-// Initialize the sandbox for renderer, gpu, utility, worker, and plug-in
+// Initialize the sandbox for renderer, gpu, utility, worker, and plugin
// processes, depending on the command line flags. For the browser process which
// is not sandboxed, this call is a no-op.
// Returns true if the sandbox was initialized succesfully, false if an error
diff --git a/chromium/content/common/sandbox_init_win.cc b/chromium/content/common/sandbox_init_win.cc
index fe67bda7e31..16e3e4afbd4 100644
--- a/chromium/content/common/sandbox_init_win.cc
+++ b/chromium/content/common/sandbox_init_win.cc
@@ -26,11 +26,6 @@ bool InitializeSandbox(sandbox::SandboxInterfaceInfo* sandbox_info) {
// process to swap its window station. During this time all the UI will be
// broken. This has to run before threads and windows are created.
if (!command_line.HasSwitch(switches::kNoSandbox)) {
-#if defined(ADDRESS_SANITIZER) && defined(OS_WIN)
- LOG(FATAL) << "AddressSanitizer for Windows doesn't support sandboxing "
- "yet (http://crbug.com/382867). "
- "Please rerun with sandbox disabled.";
-#endif
// Precreate the desktop and window station used by the renderers.
sandbox::TargetPolicy* policy = broker_services->CreatePolicy();
sandbox::ResultCode result = policy->CreateAlternateDesktop(true);
diff --git a/chromium/content/common/sandbox_linux/android/sandbox_bpf_base_policy_android.cc b/chromium/content/common/sandbox_linux/android/sandbox_bpf_base_policy_android.cc
index 8ce5f868da4..c831390cb96 100644
--- a/chromium/content/common/sandbox_linux/android/sandbox_bpf_base_policy_android.cc
+++ b/chromium/content/common/sandbox_linux/android/sandbox_bpf_base_policy_android.cc
@@ -27,6 +27,11 @@ ResultExpr SandboxBPFBasePolicyAndroid::EvaluateSyscall(int sysno) const {
case __NR_clone:
case __NR_epoll_pwait:
case __NR_flock:
+#if defined(__x86_64__) || defined(__aarch64__)
+ case __NR_newfstatat:
+#elif defined(__i386__) || defined(__arm__) || defined(__mips__)
+ case __NR_fstatat64:
+#endif
case __NR_getpriority:
case __NR_ioctl:
case __NR_mremap:
@@ -35,13 +40,14 @@ ResultExpr SandboxBPFBasePolicyAndroid::EvaluateSyscall(int sysno) const {
// access. It may be possible to restrict the filesystem with SELinux.
// Currently we rely on the app/service UID isolation to create a
// filesystem "sandbox".
-#if !ARCH_CPU_ARM64
+#if !defined(ARCH_CPU_ARM64)
case __NR_open:
#endif
case __NR_openat:
case __NR_pread64:
case __NR_rt_sigtimedwait:
case __NR_setpriority:
+ case __NR_set_tid_address:
case __NR_sigaltstack:
#if defined(__i386__) || defined(__arm__)
case __NR_ugetrlimit:
diff --git a/chromium/content/common/sandbox_linux/android/sandbox_bpf_base_policy_android.h b/chromium/content/common/sandbox_linux/android/sandbox_bpf_base_policy_android.h
index 4a0e6c5e953..f8693d9feb8 100644
--- a/chromium/content/common/sandbox_linux/android/sandbox_bpf_base_policy_android.h
+++ b/chromium/content/common/sandbox_linux/android/sandbox_bpf_base_policy_android.h
@@ -15,10 +15,10 @@ namespace content {
class SandboxBPFBasePolicyAndroid : public SandboxBPFBasePolicy {
public:
SandboxBPFBasePolicyAndroid();
- virtual ~SandboxBPFBasePolicyAndroid();
+ ~SandboxBPFBasePolicyAndroid() override;
// sandbox::SandboxBPFPolicy:
- virtual sandbox::bpf_dsl::ResultExpr EvaluateSyscall(
+ sandbox::bpf_dsl::ResultExpr EvaluateSyscall(
int system_call_number) const override;
private:
diff --git a/chromium/content/common/sandbox_linux/bpf_cros_arm_gpu_policy_linux.cc b/chromium/content/common/sandbox_linux/bpf_cros_arm_gpu_policy_linux.cc
index 20b8f94ea54..338acf9add8 100644
--- a/chromium/content/common/sandbox_linux/bpf_cros_arm_gpu_policy_linux.cc
+++ b/chromium/content/common/sandbox_linux/bpf_cros_arm_gpu_policy_linux.cc
@@ -24,14 +24,16 @@
#include "content/common/sandbox_linux/sandbox_seccomp_bpf_linux.h"
#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
#include "sandbox/linux/seccomp-bpf-helpers/syscall_sets.h"
-#include "sandbox/linux/services/linux_syscalls.h"
+#include "sandbox/linux/syscall_broker/broker_file_permission.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
-using sandbox::SyscallSets;
using sandbox::bpf_dsl::Allow;
using sandbox::bpf_dsl::Arg;
using sandbox::bpf_dsl::Error;
using sandbox::bpf_dsl::If;
using sandbox::bpf_dsl::ResultExpr;
+using sandbox::syscall_broker::BrokerFilePermission;
+using sandbox::SyscallSets;
namespace content {
@@ -46,38 +48,25 @@ inline bool IsChromeOS() {
}
inline bool IsArchitectureArm() {
-#if defined(__arm__)
+#if defined(__arm__) || defined(__aarch64__)
return true;
#else
return false;
#endif
}
-void AddArmMaliGpuWhitelist(std::vector<std::string>* read_whitelist,
- std::vector<std::string>* write_whitelist) {
+void AddArmMaliGpuWhitelist(std::vector<BrokerFilePermission>* permissions) {
// Device file needed by the ARM GPU userspace.
static const char kMali0Path[] = "/dev/mali0";
- // Devices needed for video decode acceleration on ARM.
- static const char kDevMfcDecPath[] = "/dev/mfc-dec";
- static const char kDevGsc1Path[] = "/dev/gsc1";
-
- // Devices needed for video encode acceleration on ARM.
- static const char kDevMfcEncPath[] = "/dev/mfc-enc";
-
- read_whitelist->push_back(kMali0Path);
- read_whitelist->push_back(kDevMfcDecPath);
- read_whitelist->push_back(kDevGsc1Path);
- read_whitelist->push_back(kDevMfcEncPath);
+ // Video processor used on ARM Exynos platforms.
+ static const char kDevGsc0Path[] = "/dev/gsc0";
- write_whitelist->push_back(kMali0Path);
- write_whitelist->push_back(kDevMfcDecPath);
- write_whitelist->push_back(kDevGsc1Path);
- write_whitelist->push_back(kDevMfcEncPath);
+ permissions->push_back(BrokerFilePermission::ReadWrite(kMali0Path));
+ permissions->push_back(BrokerFilePermission::ReadWrite(kDevGsc0Path));
}
-void AddArmGpuWhitelist(std::vector<std::string>* read_whitelist,
- std::vector<std::string>* write_whitelist) {
+void AddArmGpuWhitelist(std::vector<BrokerFilePermission>* permissions) {
// On ARM we're enabling the sandbox before the X connection is made,
// so we need to allow access to |.Xauthority|.
static const char kXAuthorityPath[] = "/home/chronos/.Xauthority";
@@ -87,12 +76,12 @@ void AddArmGpuWhitelist(std::vector<std::string>* read_whitelist,
static const char kLibGlesPath[] = "/usr/lib/libGLESv2.so.2";
static const char kLibEglPath[] = "/usr/lib/libEGL.so.1";
- read_whitelist->push_back(kXAuthorityPath);
- read_whitelist->push_back(kLdSoCache);
- read_whitelist->push_back(kLibGlesPath);
- read_whitelist->push_back(kLibEglPath);
+ permissions->push_back(BrokerFilePermission::ReadOnly(kXAuthorityPath));
+ permissions->push_back(BrokerFilePermission::ReadOnly(kLdSoCache));
+ permissions->push_back(BrokerFilePermission::ReadOnly(kLibGlesPath));
+ permissions->push_back(BrokerFilePermission::ReadOnly(kLibEglPath));
- AddArmMaliGpuWhitelist(read_whitelist, write_whitelist);
+ AddArmMaliGpuWhitelist(permissions);
}
class CrosArmGpuBrokerProcessPolicy : public CrosArmGpuProcessPolicy {
@@ -113,8 +102,11 @@ class CrosArmGpuBrokerProcessPolicy : public CrosArmGpuProcessPolicy {
// openat allowed.
ResultExpr CrosArmGpuBrokerProcessPolicy::EvaluateSyscall(int sysno) const {
switch (sysno) {
+#if !defined(__aarch64__)
case __NR_access:
case __NR_open:
+#endif // !defined(__aarch64__)
+ case __NR_faccessat:
case __NR_openat:
return Allow();
default:
@@ -130,13 +122,13 @@ CrosArmGpuProcessPolicy::CrosArmGpuProcessPolicy(bool allow_shmat)
CrosArmGpuProcessPolicy::~CrosArmGpuProcessPolicy() {}
ResultExpr CrosArmGpuProcessPolicy::EvaluateSyscall(int sysno) const {
-#if defined(__arm__)
+#if defined(__arm__) || defined(__aarch64__)
if (allow_shmat_ && sysno == __NR_shmat)
return Allow();
-#endif // defined(__arm__)
+#endif // defined(__arm__) || defined(__aarch64__)
switch (sysno) {
-#if defined(__arm__)
+#if defined(__arm__) || defined(__aarch64__)
// ARM GPU sandbox is started earlier so we need to allow networking
// in the sandbox.
case __NR_connect:
@@ -151,7 +143,7 @@ ResultExpr CrosArmGpuProcessPolicy::EvaluateSyscall(int sysno) const {
const Arg<int> domain(0);
return If(domain == AF_UNIX, Allow()).Else(Error(EPERM));
}
-#endif // defined(__arm__)
+#endif // defined(__arm__) || defined(__aarch64__)
default:
// Default to the generic GPU policy.
return GpuProcessPolicy::EvaluateSyscall(sysno);
@@ -163,14 +155,11 @@ bool CrosArmGpuProcessPolicy::PreSandboxHook() {
// Create a new broker process.
DCHECK(!broker_process());
- std::vector<std::string> read_whitelist_extra;
- std::vector<std::string> write_whitelist_extra;
// Add ARM-specific files to whitelist in the broker.
+ std::vector<BrokerFilePermission> permissions;
- AddArmGpuWhitelist(&read_whitelist_extra, &write_whitelist_extra);
- InitGpuBrokerProcess(CrosArmGpuBrokerProcessPolicy::Create,
- read_whitelist_extra,
- write_whitelist_extra);
+ AddArmGpuWhitelist(&permissions);
+ InitGpuBrokerProcess(CrosArmGpuBrokerProcessPolicy::Create, permissions);
const int dlopen_flag = RTLD_NOW | RTLD_GLOBAL | RTLD_NODELETE;
diff --git a/chromium/content/common/sandbox_linux/bpf_cros_arm_gpu_policy_linux.h b/chromium/content/common/sandbox_linux/bpf_cros_arm_gpu_policy_linux.h
index 179ac81f127..ed5c2055a58 100644
--- a/chromium/content/common/sandbox_linux/bpf_cros_arm_gpu_policy_linux.h
+++ b/chromium/content/common/sandbox_linux/bpf_cros_arm_gpu_policy_linux.h
@@ -26,4 +26,4 @@ class CrosArmGpuProcessPolicy : public GpuProcessPolicy {
} // namespace content
-#endif // CONTENT_COMMON_SANDBOX_LINUX_BPF_CROS_ARM_GPU_POLICY_LINUX_H_
+#endif // CONTENT_COMMON_SANDBOX_LINUX_BPF_CROS_ARM_GPU_POLICY_LINUX_H_
diff --git a/chromium/content/common/sandbox_linux/bpf_gpu_policy_linux.cc b/chromium/content/common/sandbox_linux/bpf_gpu_policy_linux.cc
index e1a33d02a9b..f47e703dd40 100644
--- a/chromium/content/common/sandbox_linux/bpf_gpu_policy_linux.cc
+++ b/chromium/content/common/sandbox_linux/bpf_gpu_policy_linux.cc
@@ -28,15 +28,17 @@
#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
#include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h"
#include "sandbox/linux/seccomp-bpf-helpers/syscall_sets.h"
-#include "sandbox/linux/services/linux_syscalls.h"
+#include "sandbox/linux/syscall_broker/broker_file_permission.h"
#include "sandbox/linux/syscall_broker/broker_process.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
-using sandbox::BrokerProcess;
-using sandbox::SyscallSets;
using sandbox::arch_seccomp_data;
using sandbox::bpf_dsl::Allow;
using sandbox::bpf_dsl::ResultExpr;
using sandbox::bpf_dsl::Trap;
+using sandbox::syscall_broker::BrokerFilePermission;
+using sandbox::syscall_broker::BrokerProcess;
+using sandbox::SyscallSets;
namespace content {
@@ -67,23 +69,44 @@ inline bool IsArchitectureI386() {
}
inline bool IsArchitectureArm() {
-#if defined(__arm__)
+#if defined(__arm__) || defined(__aarch64__)
return true;
#else
return false;
#endif
}
-bool IsAcceleratedVideoEnabled() {
- const base::CommandLine& command_line =
- *base::CommandLine::ForCurrentProcess();
+inline bool IsOzone() {
+#if defined(USE_OZONE)
+ return true;
+#else
+ return false;
+#endif
+}
+
+inline bool UseLibV4L2() {
+#if defined(USE_LIBV4L2)
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool IsAcceleratedVaapiVideoEncodeEnabled() {
bool accelerated_encode_enabled = false;
#if defined(OS_CHROMEOS)
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
accelerated_encode_enabled =
!command_line.HasSwitch(switches::kDisableVaapiAcceleratedVideoEncode);
#endif
- return !command_line.HasSwitch(switches::kDisableAcceleratedVideoDecode) ||
- accelerated_encode_enabled;
+ return accelerated_encode_enabled;
+}
+
+bool IsAcceleratedVideoDecodeEnabled() {
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
+ return !command_line.HasSwitch(switches::kDisableAcceleratedVideoDecode);
}
intptr_t GpuSIGSYS_Handler(const struct arch_seccomp_data& args,
@@ -92,6 +115,7 @@ intptr_t GpuSIGSYS_Handler(const struct arch_seccomp_data& args,
BrokerProcess* broker_process =
static_cast<BrokerProcess*>(aux_broker_process);
switch (args.nr) {
+#if !defined(__aarch64__)
case __NR_access:
return broker_process->Access(reinterpret_cast<const char*>(args.args[0]),
static_cast<int>(args.args[1]));
@@ -102,6 +126,15 @@ intptr_t GpuSIGSYS_Handler(const struct arch_seccomp_data& args,
#endif
return broker_process->Open(reinterpret_cast<const char*>(args.args[0]),
static_cast<int>(args.args[1]));
+#endif // !defined(__aarch64__)
+ case __NR_faccessat:
+ if (static_cast<int>(args.args[0]) == AT_FDCWD) {
+ return
+ broker_process->Access(reinterpret_cast<const char*>(args.args[1]),
+ static_cast<int>(args.args[2]));
+ } else {
+ return -EPERM;
+ }
case __NR_openat:
// Allow using openat() as open().
if (static_cast<int>(args.args[0]) == AT_FDCWD) {
@@ -117,6 +150,18 @@ intptr_t GpuSIGSYS_Handler(const struct arch_seccomp_data& args,
}
}
+void AddV4L2GpuWhitelist(std::vector<BrokerFilePermission>* permissions) {
+ if (IsAcceleratedVideoDecodeEnabled()) {
+ // Device node for V4L2 video decode accelerator drivers.
+ static const char kDevVideoDecPath[] = "/dev/video-dec";
+ permissions->push_back(BrokerFilePermission::ReadWrite(kDevVideoDecPath));
+ }
+
+ // Device node for V4L2 video encode accelerator drivers.
+ static const char kDevVideoEncPath[] = "/dev/video-enc";
+ permissions->push_back(BrokerFilePermission::ReadWrite(kDevVideoEncPath));
+}
+
class GpuBrokerProcessPolicy : public GpuProcessPolicy {
public:
static sandbox::bpf_dsl::Policy* Create() {
@@ -132,13 +177,21 @@ class GpuBrokerProcessPolicy : public GpuProcessPolicy {
};
// x86_64/i386 or desktop ARM.
-// A GPU broker policy is the same as a GPU policy with open and
-// openat allowed.
+// A GPU broker policy is the same as a GPU policy with access, open,
+// openat and in the non-Chrome OS case unlink allowed.
ResultExpr GpuBrokerProcessPolicy::EvaluateSyscall(int sysno) const {
switch (sysno) {
+#if !defined(__aarch64__)
case __NR_access:
case __NR_open:
+#endif // !defined(__aarch64__)
+ case __NR_faccessat:
case __NR_openat:
+#if !defined(OS_CHROMEOS)
+ // The broker process needs to able to unlink the temporary
+ // files that it may create. This is used by DRI3.
+ case __NR_unlink:
+#endif
return Allow();
default:
return GpuProcessPolicy::EvaluateSyscall(sysno);
@@ -165,7 +218,7 @@ bool UpdateProcessTypeAndEnableSandbox(
DCHECK(broker_sandboxer_allocator);
UpdateProcessTypeToGpuBroker();
return SandboxSeccompBPF::StartSandboxWithExternalPolicy(
- make_scoped_ptr(broker_sandboxer_allocator()));
+ make_scoped_ptr(broker_sandboxer_allocator()), base::ScopedFD());
}
} // namespace
@@ -182,6 +235,9 @@ GpuProcessPolicy::~GpuProcessPolicy() {}
// Main policy for x86_64/i386. Extended by CrosArmGpuProcessPolicy.
ResultExpr GpuProcessPolicy::EvaluateSyscall(int sysno) const {
switch (sysno) {
+#if !defined(OS_CHROMEOS)
+ case __NR_ftruncate:
+#endif
case __NR_ioctl:
return Allow();
case __NR_mincore:
@@ -201,13 +257,14 @@ ResultExpr GpuProcessPolicy::EvaluateSyscall(int sysno) const {
// TODO(jln): restrict prctl.
case __NR_prctl:
return Allow();
+#if !defined(__aarch64__)
case __NR_access:
case __NR_open:
+#endif // !defined(__aarch64__)
+ case __NR_faccessat:
case __NR_openat:
DCHECK(broker_process_);
return Trap(GpuSIGSYS_Handler, broker_process_);
- case __NR_setpriority:
- return sandbox::RestrictGetSetpriority(GetPolicyPid());
case __NR_sched_getaffinity:
case __NR_sched_setaffinity:
return sandbox::RestrictSchedTarget(GetPolicyPid(), sysno);
@@ -231,13 +288,13 @@ bool GpuProcessPolicy::PreSandboxHook() {
// Create a new broker process.
InitGpuBrokerProcess(
GpuBrokerProcessPolicy::Create,
- std::vector<std::string>(), // No extra files in whitelist.
- std::vector<std::string>());
+ std::vector<BrokerFilePermission>()); // No extra files in whitelist.
if (IsArchitectureX86_64() || IsArchitectureI386()) {
// Accelerated video dlopen()'s some shared objects
// inside the sandbox, so preload them now.
- if (IsAcceleratedVideoEnabled()) {
+ if (IsAcceleratedVaapiVideoEncodeEnabled() ||
+ IsAcceleratedVideoDecodeEnabled()) {
const char* I965DrvVideoPath = NULL;
if (IsArchitectureX86_64()) {
@@ -248,7 +305,11 @@ bool GpuProcessPolicy::PreSandboxHook() {
dlopen(I965DrvVideoPath, RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE);
dlopen("libva.so.1", RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE);
+#if defined(USE_OZONE)
+ dlopen("libva-drm.so.1", RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE);
+#elif defined(USE_X11)
dlopen("libva-x11.so.1", RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE);
+#endif
}
}
@@ -257,32 +318,36 @@ bool GpuProcessPolicy::PreSandboxHook() {
void GpuProcessPolicy::InitGpuBrokerProcess(
sandbox::bpf_dsl::Policy* (*broker_sandboxer_allocator)(void),
- const std::vector<std::string>& read_whitelist_extra,
- const std::vector<std::string>& write_whitelist_extra) {
+ const std::vector<BrokerFilePermission>& permissions_extra) {
static const char kDriRcPath[] = "/etc/drirc";
static const char kDriCard0Path[] = "/dev/dri/card0";
+ static const char kDevShm[] = "/dev/shm/";
CHECK(broker_process_ == NULL);
// All GPU process policies need these files brokered out.
- std::vector<std::string> read_whitelist;
- read_whitelist.push_back(kDriCard0Path);
- read_whitelist.push_back(kDriRcPath);
- // Add eventual extra files from read_whitelist_extra.
- read_whitelist.insert(read_whitelist.end(),
- read_whitelist_extra.begin(),
- read_whitelist_extra.end());
-
- std::vector<std::string> write_whitelist;
- write_whitelist.push_back(kDriCard0Path);
- // Add eventual extra files from write_whitelist_extra.
- write_whitelist.insert(write_whitelist.end(),
- write_whitelist_extra.begin(),
- write_whitelist_extra.end());
-
- broker_process_ = new BrokerProcess(GetFSDeniedErrno(),
- read_whitelist,
- write_whitelist);
+ std::vector<BrokerFilePermission> permissions;
+ permissions.push_back(BrokerFilePermission::ReadWrite(kDriCard0Path));
+ permissions.push_back(BrokerFilePermission::ReadOnly(kDriRcPath));
+ if (!IsChromeOS()) {
+ permissions.push_back(
+ BrokerFilePermission::ReadWriteCreateUnlinkRecursive(kDevShm));
+ } else if (IsArchitectureArm() || IsOzone()){
+ AddV4L2GpuWhitelist(&permissions);
+ if (UseLibV4L2()) {
+ dlopen("/usr/lib/libv4l2.so", RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE);
+ // This is a device-specific encoder plugin.
+ dlopen("/usr/lib/libv4l/plugins/libv4l-encplugin.so",
+ RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE);
+ }
+ }
+
+ // Add eventual extra files from permissions_extra.
+ for (const auto& perm : permissions_extra) {
+ permissions.push_back(perm);
+ }
+
+ broker_process_ = new BrokerProcess(GetFSDeniedErrno(), permissions);
// The initialization callback will perform generic initialization and then
// call broker_sandboxer_callback.
CHECK(broker_process_->Init(base::Bind(&UpdateProcessTypeAndEnableSandbox,
diff --git a/chromium/content/common/sandbox_linux/bpf_gpu_policy_linux.h b/chromium/content/common/sandbox_linux/bpf_gpu_policy_linux.h
index aae79c1381e..cc66c5bc96f 100644
--- a/chromium/content/common/sandbox_linux/bpf_gpu_policy_linux.h
+++ b/chromium/content/common/sandbox_linux/bpf_gpu_policy_linux.h
@@ -12,8 +12,11 @@
#include "content/common/sandbox_linux/sandbox_bpf_base_policy_linux.h"
namespace sandbox {
+namespace syscall_broker {
+class BrokerFilePermission;
class BrokerProcess;
}
+}
namespace content {
@@ -32,15 +35,17 @@ class GpuProcessPolicy : public SandboxBPFBasePolicy {
// Start a broker process to handle open() inside the sandbox.
// |broker_sandboxer_allocator| is a function pointer which can allocate a
// suitable sandbox policy for the broker process itself.
- // |read_whitelist_extra| and |write_whitelist_extra| are lists of file
- // names that should be whitelisted by the broker process, in addition to
+ // |permissions_extra| is a list of file permissions
+ // that should be whitelisted by the broker process, in addition to
// the basic ones.
void InitGpuBrokerProcess(
sandbox::bpf_dsl::Policy* (*broker_sandboxer_allocator)(void),
- const std::vector<std::string>& read_whitelist_extra,
- const std::vector<std::string>& write_whitelist_extra);
+ const std::vector<sandbox::syscall_broker::BrokerFilePermission>&
+ permissions_extra);
- sandbox::BrokerProcess* broker_process() { return broker_process_; }
+ sandbox::syscall_broker::BrokerProcess* broker_process() {
+ return broker_process_;
+ }
private:
// A BrokerProcess is a helper that is started before the sandbox is engaged
@@ -50,7 +55,7 @@ class GpuProcessPolicy : public SandboxBPFBasePolicy {
// vital to the process.
// This is allocated by InitGpuBrokerProcess, called from PreSandboxHook(),
// which executes iff the sandbox is going to be enabled afterwards.
- sandbox::BrokerProcess* broker_process_;
+ sandbox::syscall_broker::BrokerProcess* broker_process_;
// eglCreateWindowSurface() needs mincore().
bool allow_mincore_;
diff --git a/chromium/content/common/sandbox_linux/bpf_ppapi_policy_linux.cc b/chromium/content/common/sandbox_linux/bpf_ppapi_policy_linux.cc
index c8fcb45de0c..8a7cee54d69 100644
--- a/chromium/content/common/sandbox_linux/bpf_ppapi_policy_linux.cc
+++ b/chromium/content/common/sandbox_linux/bpf_ppapi_policy_linux.cc
@@ -12,7 +12,7 @@
#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
#include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h"
#include "sandbox/linux/seccomp-bpf-helpers/syscall_sets.h"
-#include "sandbox/linux/services/linux_syscalls.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
using sandbox::SyscallSets;
using sandbox::bpf_dsl::Allow;
diff --git a/chromium/content/common/sandbox_linux/bpf_renderer_policy_linux.cc b/chromium/content/common/sandbox_linux/bpf_renderer_policy_linux.cc
index 408a3801bed..bd252ff7557 100644
--- a/chromium/content/common/sandbox_linux/bpf_renderer_policy_linux.cc
+++ b/chromium/content/common/sandbox_linux/bpf_renderer_policy_linux.cc
@@ -12,7 +12,7 @@
#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
#include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h"
#include "sandbox/linux/seccomp-bpf-helpers/syscall_sets.h"
-#include "sandbox/linux/services/linux_syscalls.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
using sandbox::SyscallSets;
using sandbox::bpf_dsl::Allow;
diff --git a/chromium/content/common/sandbox_linux/bpf_utility_policy_linux.cc b/chromium/content/common/sandbox_linux/bpf_utility_policy_linux.cc
index 401a5f718cd..56b3813fe16 100644
--- a/chromium/content/common/sandbox_linux/bpf_utility_policy_linux.cc
+++ b/chromium/content/common/sandbox_linux/bpf_utility_policy_linux.cc
@@ -12,7 +12,7 @@
#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
#include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h"
#include "sandbox/linux/seccomp-bpf-helpers/syscall_sets.h"
-#include "sandbox/linux/services/linux_syscalls.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
using sandbox::SyscallSets;
using sandbox::bpf_dsl::Allow;
diff --git a/chromium/content/common/sandbox_linux/sandbox_debug_handling_linux.cc b/chromium/content/common/sandbox_linux/sandbox_debug_handling_linux.cc
new file mode 100644
index 00000000000..0bf8799f048
--- /dev/null
+++ b/chromium/content/common/sandbox_linux/sandbox_debug_handling_linux.cc
@@ -0,0 +1,79 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/common/sandbox_linux/sandbox_debug_handling_linux.h"
+
+#include <errno.h>
+#include <signal.h>
+#include <sys/prctl.h>
+#include <unistd.h>
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/strings/safe_sprintf.h"
+#include "content/public/common/content_switches.h"
+
+namespace content {
+
+namespace {
+
+void DoChrootSignalHandler(int) {
+ const int old_errno = errno;
+ const char kFirstMessage[] = "Chroot signal handler called.\n";
+ ignore_result(write(STDERR_FILENO, kFirstMessage, sizeof(kFirstMessage) - 1));
+
+ const int chroot_ret = chroot("/");
+
+ char kSecondMessage[100];
+ const ssize_t printed = base::strings::SafeSPrintf(
+ kSecondMessage, "chroot() returned %d. Errno is %d.\n", chroot_ret,
+ errno);
+ if (printed > 0 && printed < static_cast<ssize_t>(sizeof(kSecondMessage))) {
+ ignore_result(write(STDERR_FILENO, kSecondMessage, printed));
+ }
+ errno = old_errno;
+}
+
+// This is a quick hack to allow testing sandbox crash reports in production
+// binaries.
+// This installs a signal handler for SIGUSR2 that performs a chroot().
+// In most of our BPF policies, it is a "watched" system call which will
+// trigger a SIGSYS signal whose handler will crash.
+// This has been added during the investigation of https://crbug.com/415842.
+void InstallCrashTestHandler() {
+ struct sigaction act = {};
+ act.sa_handler = DoChrootSignalHandler;
+ CHECK_EQ(0, sigemptyset(&act.sa_mask));
+ act.sa_flags = 0;
+
+ PCHECK(0 == sigaction(SIGUSR2, &act, NULL));
+}
+
+bool IsSandboxDebuggingEnabled() {
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
+ return command_line.HasSwitch(switches::kAllowSandboxDebugging);
+}
+
+} // namespace
+
+// static
+bool SandboxDebugHandling::SetDumpableStatusAndHandlers() {
+ if (IsSandboxDebuggingEnabled()) {
+ // If sandbox debugging is allowed, install a handler for sandbox-related
+ // crash testing.
+ InstallCrashTestHandler();
+ return true;
+ }
+
+ if (prctl(PR_SET_DUMPABLE, 0) != 0) {
+ PLOG(ERROR) << "Failed to set non-dumpable flag";
+ return false;
+ }
+
+ return prctl(PR_GET_DUMPABLE) == 0;
+}
+
+} // namespace content
diff --git a/chromium/content/common/sandbox_linux/sandbox_debug_handling_linux.h b/chromium/content/common/sandbox_linux/sandbox_debug_handling_linux.h
new file mode 100644
index 00000000000..248b54b43e7
--- /dev/null
+++ b/chromium/content/common/sandbox_linux/sandbox_debug_handling_linux.h
@@ -0,0 +1,25 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_COMMON_SANDBOX_LINUX_SANDBOX_DEBUG_HANDLING_LINUX_H_
+#define CONTENT_COMMON_SANDBOX_LINUX_SANDBOX_DEBUG_HANDLING_LINUX_H_
+
+#include "base/macros.h"
+
+namespace content {
+
+class SandboxDebugHandling {
+ public:
+ // Depending on the command line, set the current process as
+ // non dumpable. Also set any signal handlers for sandbox
+ // debugging.
+ static bool SetDumpableStatusAndHandlers();
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(SandboxDebugHandling);
+};
+
+} // namespace content
+
+#endif // CONTENT_COMMON_SANDBOX_LINUX_SANDBOX_DEBUG_HANDLING_LINUX_H_
diff --git a/chromium/content/common/sandbox_linux/sandbox_init_linux.cc b/chromium/content/common/sandbox_linux/sandbox_init_linux.cc
index 0585d5421dd..146b3528b69 100644
--- a/chromium/content/common/sandbox_linux/sandbox_init_linux.cc
+++ b/chromium/content/common/sandbox_linux/sandbox_init_linux.cc
@@ -4,18 +4,23 @@
#include "content/public/common/sandbox_init.h"
+#include "base/files/scoped_file.h"
#include "base/memory/scoped_ptr.h"
#include "content/common/sandbox_linux/sandbox_seccomp_bpf_linux.h"
#include "sandbox/linux/bpf_dsl/policy.h"
namespace content {
-bool InitializeSandbox(scoped_ptr<sandbox::bpf_dsl::Policy> policy) {
- return SandboxSeccompBPF::StartSandboxWithExternalPolicy(policy.Pass());
+bool InitializeSandbox(scoped_ptr<sandbox::bpf_dsl::Policy> policy,
+ base::ScopedFD proc_fd) {
+ return SandboxSeccompBPF::StartSandboxWithExternalPolicy(policy.Pass(),
+ proc_fd.Pass());
}
+#if !defined(OS_NACL_NONSFI)
scoped_ptr<sandbox::bpf_dsl::Policy> GetBPFSandboxBaselinePolicy() {
return SandboxSeccompBPF::GetBaselinePolicy().Pass();
}
+#endif // !defined(OS_NACL_NONSFI)
} // namespace content
diff --git a/chromium/content/common/sandbox_linux/sandbox_linux.cc b/chromium/content/common/sandbox_linux/sandbox_linux.cc
index 12e11d8e131..b2a7b3e6e96 100644
--- a/chromium/content/common/sandbox_linux/sandbox_linux.cc
+++ b/chromium/content/common/sandbox_linux/sandbox_linux.cc
@@ -11,6 +11,8 @@
#include <unistd.h>
#include <limits>
+#include <string>
+#include <vector>
#include "base/bind.h"
#include "base/callback_helpers.h"
@@ -26,11 +28,15 @@
#include "base/sys_info.h"
#include "base/time/time.h"
#include "build/build_config.h"
+#include "content/common/sandbox_linux/sandbox_debug_handling_linux.h"
#include "content/common/sandbox_linux/sandbox_linux.h"
#include "content/common/sandbox_linux/sandbox_seccomp_bpf_linux.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/sandbox_linux.h"
#include "sandbox/linux/services/credentials.h"
+#include "sandbox/linux/services/namespace_sandbox.h"
+#include "sandbox/linux/services/proc_util.h"
+#include "sandbox/linux/services/resource_limits.h"
#include "sandbox/linux/services/thread_helpers.h"
#include "sandbox/linux/services/yama.h"
#include "sandbox/linux/suid/client/setuid_sandbox_client.h"
@@ -62,19 +68,6 @@ void LogSandboxStarted(const std::string& sandbox_name) {
VLOG(1) << activated_sandbox;
}
-bool AddResourceLimit(int resource, rlim_t limit) {
- struct rlimit old_rlimit;
- if (getrlimit(resource, &old_rlimit))
- return false;
- // Make sure we don't raise the existing limit.
- const struct rlimit new_rlimit = {
- std::min(old_rlimit.rlim_cur, limit),
- std::min(old_rlimit.rlim_max, limit)
- };
- int rc = setrlimit(resource, &new_rlimit);
- return rc == 0;
-}
-
bool IsRunningTSAN() {
#if defined(THREAD_SANITIZER)
return true;
@@ -83,19 +76,23 @@ bool IsRunningTSAN() {
#endif
}
-// Try to open /proc/self/task/ with the help of |proc_fd|. |proc_fd| can be
-// -1. Will return -1 on error and set errno like open(2).
-int OpenProcTaskFd(int proc_fd) {
- int proc_self_task = -1;
+// Get a file descriptor to /proc. Either duplicate |proc_fd| or try to open
+// it by using the filesystem directly.
+// TODO(jln): get rid of this ugly interface.
+base::ScopedFD OpenProc(int proc_fd) {
+ int ret_proc_fd = -1;
if (proc_fd >= 0) {
// If a handle to /proc is available, use it. This allows to bypass file
// system restrictions.
- proc_self_task = openat(proc_fd, "self/task/", O_RDONLY | O_DIRECTORY);
+ ret_proc_fd =
+ HANDLE_EINTR(openat(proc_fd, ".", O_RDONLY | O_DIRECTORY | O_CLOEXEC));
} else {
// Otherwise, make an attempt to access the file system directly.
- proc_self_task = open("/proc/self/task/", O_RDONLY | O_DIRECTORY);
+ ret_proc_fd = HANDLE_EINTR(
+ openat(AT_FDCWD, "/proc/", O_RDONLY | O_DIRECTORY | O_CLOEXEC));
}
- return proc_self_task;
+ DCHECK_LE(0, ret_proc_fd);
+ return base::ScopedFD(ret_proc_fd);
}
} // namespace
@@ -108,9 +105,10 @@ LinuxSandbox::LinuxSandbox()
sandbox_status_flags_(kSandboxLinuxInvalid),
pre_initialized_(false),
seccomp_bpf_supported_(false),
+ seccomp_bpf_with_tsync_supported_(false),
yama_is_enforcing_(false),
- setuid_sandbox_client_(sandbox::SetuidSandboxClient::Create())
-{
+ initialize_sandbox_ran_(false),
+ setuid_sandbox_client_(sandbox::SetuidSandboxClient::Create()) {
if (setuid_sandbox_client_ == NULL) {
LOG(FATAL) << "Failed to instantiate the setuid sandbox client.";
}
@@ -121,6 +119,9 @@ LinuxSandbox::LinuxSandbox()
}
LinuxSandbox::~LinuxSandbox() {
+ if (pre_initialized_) {
+ CHECK(initialize_sandbox_ran_);
+ }
}
LinuxSandbox* LinuxSandbox::GetInstance() {
@@ -144,12 +145,14 @@ void LinuxSandbox::PreinitializeSandbox() {
// its contents before the sandbox is enabled. It also pre-opens the
// object files that are already loaded in the process address space.
base::debug::EnableInProcessStackDumpingForSandbox();
+#endif // !defined(NDEBUG)
- // Open proc_fd_ only in Debug mode so that forgetting to close it doesn't
- // produce a sandbox escape in Release mode.
- proc_fd_ = open("/proc", O_DIRECTORY | O_RDONLY | O_CLOEXEC);
+ // Open proc_fd_. It would break the security of the setuid sandbox if it was
+ // not closed.
+ // If LinuxSandbox::PreinitializeSandbox() runs, InitializeSandbox() must run
+ // as well.
+ proc_fd_ = HANDLE_EINTR(open("/proc", O_DIRECTORY | O_RDONLY | O_CLOEXEC));
CHECK_GE(proc_fd_, 0);
-#endif // !defined(NDEBUG)
// We "pre-warm" the code that detects supports for seccomp BPF.
if (SandboxSeccompBPF::IsSeccompBPFDesired()) {
if (!SandboxSeccompBPF::SupportsSandbox()) {
@@ -157,6 +160,10 @@ void LinuxSandbox::PreinitializeSandbox() {
} else {
seccomp_bpf_supported_ = true;
}
+
+ if (SandboxSeccompBPF::SupportsSandboxWithTsync()) {
+ seccomp_bpf_with_tsync_supported_ = true;
+ }
}
// Yama is a "global", system-level status. We assume it will not regress
@@ -167,6 +174,38 @@ void LinuxSandbox::PreinitializeSandbox() {
pre_initialized_ = true;
}
+void LinuxSandbox::EngageNamespaceSandbox() {
+ CHECK(pre_initialized_);
+ // Check being in a new PID namespace created by the namespace sandbox and
+ // being the init process.
+ CHECK(sandbox::NamespaceSandbox::InNewPidNamespace());
+ const pid_t pid = getpid();
+ CHECK_EQ(1, pid);
+
+ CHECK(sandbox::Credentials::MoveToNewUserNS());
+ // Note: this requires SealSandbox() to be called later in this process to be
+ // safe, as this class is keeping a file descriptor to /proc/.
+ CHECK(sandbox::Credentials::DropFileSystemAccess(proc_fd_));
+
+ // We do not drop CAP_SYS_ADMIN because we need it to place each child process
+ // in its own PID namespace later on.
+ std::vector<sandbox::Credentials::Capability> caps;
+ caps.push_back(sandbox::Credentials::Capability::SYS_ADMIN);
+ CHECK(sandbox::Credentials::SetCapabilities(proc_fd_, caps));
+
+ // This needs to happen after moving to a new user NS, since doing so involves
+ // writing the UID/GID map.
+ CHECK(SandboxDebugHandling::SetDumpableStatusAndHandlers());
+}
+
+std::vector<int> LinuxSandbox::GetFileDescriptorsToClose() {
+ std::vector<int> fds;
+ if (proc_fd_ >= 0) {
+ fds.push_back(proc_fd_);
+ }
+ return fds;
+}
+
bool LinuxSandbox::InitializeSandbox() {
LinuxSandbox* linux_sandbox = LinuxSandbox::GetInstance();
return linux_sandbox->InitializeSandboxImpl();
@@ -178,7 +217,9 @@ void LinuxSandbox::StopThread(base::Thread* thread) {
}
int LinuxSandbox::GetStatus() {
- CHECK(pre_initialized_);
+ if (!pre_initialized_) {
+ return 0;
+ }
if (kSandboxLinuxInvalid == sandbox_status_flags_) {
// Initialize sandbox_status_flags_.
sandbox_status_flags_ = 0;
@@ -188,6 +229,12 @@ int LinuxSandbox::GetStatus() {
sandbox_status_flags_ |= kSandboxLinuxPIDNS;
if (setuid_sandbox_client_->IsInNewNETNamespace())
sandbox_status_flags_ |= kSandboxLinuxNetNS;
+ } else if (sandbox::NamespaceSandbox::InNewUserNamespace()) {
+ sandbox_status_flags_ |= kSandboxLinuxUserNS;
+ if (sandbox::NamespaceSandbox::InNewPidNamespace())
+ sandbox_status_flags_ |= kSandboxLinuxPIDNS;
+ if (sandbox::NamespaceSandbox::InNewNetNamespace())
+ sandbox_status_flags_ |= kSandboxLinuxNetNS;
}
// We report whether the sandbox will be activated when renderers, workers
@@ -197,6 +244,11 @@ int LinuxSandbox::GetStatus() {
sandbox_status_flags_ |= kSandboxLinuxSeccompBPF;
}
+ if (seccomp_bpf_with_tsync_supported() &&
+ SandboxSeccompBPF::ShouldEnableSeccompBPF(switches::kRendererProcess)) {
+ sandbox_status_flags_ |= kSandboxLinuxSeccompTSYNC;
+ }
+
if (yama_is_enforcing_) {
sandbox_status_flags_ |= kSandboxLinuxYama;
}
@@ -209,27 +261,13 @@ int LinuxSandbox::GetStatus() {
// PID namespaces and existing sandboxes, so "self" must really be used instead
// of using the pid.
bool LinuxSandbox::IsSingleThreaded() const {
- bool is_single_threaded = false;
- base::ScopedFD proc_self_task(OpenProcTaskFd(proc_fd_));
+ base::ScopedFD proc_fd(OpenProc(proc_fd_));
-// In Debug mode, it's mandatory to be able to count threads to catch bugs.
-#if !defined(NDEBUG)
- // Using CHECK here since we want to check all the cases where
- // !defined(NDEBUG)
- // gets built.
- CHECK(proc_self_task.is_valid())
- << "Could not count threads, the sandbox was not "
- << "pre-initialized properly.";
-#endif // !defined(NDEBUG)
+ CHECK(proc_fd.is_valid()) << "Could not count threads, the sandbox was not "
+ << "pre-initialized properly.";
- if (!proc_self_task.is_valid()) {
- // Pretend to be monothreaded if it can't be determined (for instance the
- // setuid sandbox is already engaged but no proc_fd_ is available).
- is_single_threaded = true;
- } else {
- is_single_threaded =
- sandbox::ThreadHelpers::IsSingleThreaded(proc_self_task.get());
- }
+ const bool is_single_threaded =
+ sandbox::ThreadHelpers::IsSingleThreaded(proc_fd.get());
return is_single_threaded;
}
@@ -247,16 +285,22 @@ sandbox::SetuidSandboxClient*
bool LinuxSandbox::StartSeccompBPF(const std::string& process_type) {
CHECK(!seccomp_bpf_started_);
CHECK(pre_initialized_);
- if (seccomp_bpf_supported())
- seccomp_bpf_started_ = SandboxSeccompBPF::StartSandbox(process_type);
+ if (seccomp_bpf_supported()) {
+ seccomp_bpf_started_ =
+ SandboxSeccompBPF::StartSandbox(process_type, OpenProc(proc_fd_));
+ }
- if (seccomp_bpf_started_)
+ if (seccomp_bpf_started_) {
LogSandboxStarted("seccomp-bpf");
+ }
return seccomp_bpf_started_;
}
bool LinuxSandbox::InitializeSandboxImpl() {
+ DCHECK(!initialize_sandbox_ran_);
+ initialize_sandbox_ran_ = true;
+
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
const std::string process_type =
command_line->GetSwitchValueASCII(switches::kProcessType);
@@ -329,6 +373,11 @@ bool LinuxSandbox::seccomp_bpf_supported() const {
return seccomp_bpf_supported_;
}
+bool LinuxSandbox::seccomp_bpf_with_tsync_supported() const {
+ CHECK(pre_initialized_);
+ return seccomp_bpf_with_tsync_supported_;
+}
+
bool LinuxSandbox::LimitAddressSpace(const std::string& process_type) {
(void) process_type;
#if !defined(ADDRESS_SANITIZER) && !defined(MEMORY_SANITIZER) && \
@@ -361,17 +410,16 @@ bool LinuxSandbox::LimitAddressSpace(const std::string& process_type) {
// allocations that can't be index by an int.
const rlim_t kNewDataSegmentMaxSize = std::numeric_limits<int>::max();
- bool limited_as = AddResourceLimit(RLIMIT_AS, address_space_limit);
- bool limited_data = AddResourceLimit(RLIMIT_DATA, kNewDataSegmentMaxSize);
+ bool limited_as =
+ sandbox::ResourceLimits::Lower(RLIMIT_AS, address_space_limit);
+ bool limited_data =
+ sandbox::ResourceLimits::Lower(RLIMIT_DATA, kNewDataSegmentMaxSize);
// Cache the resource limit before turning on the sandbox.
base::SysInfo::AmountOfVirtualMemory();
return limited_as && limited_data;
#else
- // Silence the compiler warning about unused function. This doesn't actually
- // call AddResourceLimit().
- ignore_result(AddResourceLimit);
base::SysInfo::AmountOfVirtualMemory();
return false;
#endif // !defined(ADDRESS_SANITIZER) && !defined(MEMORY_SANITIZER) &&
@@ -379,7 +427,7 @@ bool LinuxSandbox::LimitAddressSpace(const std::string& process_type) {
}
bool LinuxSandbox::HasOpenDirectories() const {
- return sandbox::Credentials().HasOpenDirectory(proc_fd_);
+ return sandbox::ProcUtil::HasOpenDirectory(proc_fd_);
}
void LinuxSandbox::SealSandbox() {
@@ -406,10 +454,10 @@ void LinuxSandbox::CheckForBrokenPromises(const std::string& process_type) {
void LinuxSandbox::StopThreadAndEnsureNotCounted(base::Thread* thread) const {
DCHECK(thread);
- base::ScopedFD proc_self_task(OpenProcTaskFd(proc_fd_));
- PCHECK(proc_self_task.is_valid());
- CHECK(sandbox::ThreadHelpers::StopThreadAndWatchProcFS(proc_self_task.get(),
- thread));
+ base::ScopedFD proc_fd(OpenProc(proc_fd_));
+ PCHECK(proc_fd.is_valid());
+ CHECK(
+ sandbox::ThreadHelpers::StopThreadAndWatchProcFS(proc_fd.get(), thread));
}
} // namespace content
diff --git a/chromium/content/common/sandbox_linux/sandbox_linux.h b/chromium/content/common/sandbox_linux/sandbox_linux.h
index a5a232277e9..01a0bd9a354 100644
--- a/chromium/content/common/sandbox_linux/sandbox_linux.h
+++ b/chromium/content/common/sandbox_linux/sandbox_linux.h
@@ -6,14 +6,16 @@
#define CONTENT_COMMON_SANDBOX_LINUX_SANDBOX_LINUX_H_
#include <string>
+#include <vector>
#include "base/basictypes.h"
+#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "content/public/common/sandbox_linux.h"
#if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \
defined(THREAD_SANITIZER) || defined(LEAK_SANITIZER) || \
- defined(UNDEFINED_SANITIZER)
+ defined(UNDEFINED_SANITIZER) || defined(SANITIZER_COVERAGE)
#include <sanitizer/common_interface_defs.h>
#define ANY_OF_AMTLU_SANITIZER 1
#endif
@@ -28,6 +30,14 @@ namespace content {
// A singleton class to represent and change our sandboxing state for the
// three main Linux sandboxes.
+// The sandboxing model allows using two layers of sandboxing. The first layer
+// can be implemented either with unprivileged namespaces or with the setuid
+// sandbox. This class provides a way to engage the namespace sandbox, but does
+// not deal with the legacy setuid sandbox directly.
+// The second layer is mainly based on seccomp-bpf and is engaged with
+// InitializeSandbox(). InitializeSandbox() is also responsible for "sealing"
+// the first layer of sandboxing. That is, InitializeSandbox must always be
+// called to have any meaningful sandboxing at all.
class LinuxSandbox {
public:
// This is a list of sandbox IPC methods which the renderer may send to the
@@ -49,12 +59,32 @@ class LinuxSandbox {
// Do some initialization that can only be done before any of the sandboxes
// are enabled. If using the setuid sandbox, this should be called manually
// before the setuid sandbox is engaged.
+ // Security: When this runs, it is imperative that either InitializeSandbox()
+ // runs as well or that all file descriptors returned in
+ // GetFileDescriptorsToClose() get closed.
+ // Otherwise file descriptors that bypass the security of the setuid sandbox
+ // would be kept open. One must be particularly careful if a process performs
+ // a fork().
void PreinitializeSandbox();
- // Initialize the sandbox with the given pre-built configuration. Currently
- // seccomp-bpf and address space limitations (the setuid sandbox works
- // differently and is set-up in the Zygote). This will instantiate the
- // LinuxSandbox singleton if it doesn't already exist.
+ // Check that the current process is the init process of a new PID
+ // namespace and then proceed to drop access to the file system by using
+ // a new unprivileged namespace. This is a layer-1 sandbox.
+ // In order for this sandbox to be effective, it must be "sealed" by calling
+ // InitializeSandbox().
+ void EngageNamespaceSandbox();
+
+ // Return a list of file descriptors to close if PreinitializeSandbox() ran
+ // but InitializeSandbox() won't. Avoid using.
+ // TODO(jln): get rid of this hack.
+ std::vector<int> GetFileDescriptorsToClose();
+
+ // Seal an eventual layer-1 sandbox and initialize the layer-2 sandbox with
+ // an adequate policy depending on the process type and command line
+ // arguments.
+ // Currently the layer-2 sandbox is composed of seccomp-bpf and address space
+ // limitations. This will instantiate the LinuxSandbox singleton if it
+ // doesn't already exist.
// This function should only be called without any thread running.
static bool InitializeSandbox();
@@ -89,6 +119,13 @@ class LinuxSandbox {
// to make some vulnerabilities harder to exploit.
bool LimitAddressSpace(const std::string& process_type);
+ // Returns a file descriptor to proc. The file descriptor is no longer valid
+ // after the sandbox has been sealed.
+ int proc_fd() const {
+ DCHECK_NE(-1, proc_fd_);
+ return proc_fd_;
+ }
+
#if defined(ANY_OF_AMTLU_SANITIZER)
__sanitizer_sandbox_arguments* sanitizer_args() const {
return sanitizer_args_.get();
@@ -105,8 +142,9 @@ class LinuxSandbox {
// are the non-static implementations.
bool InitializeSandboxImpl();
void StopThreadImpl(base::Thread* thread);
- // We must have been pre_initialized_ before using this.
+ // We must have been pre_initialized_ before using these.
bool seccomp_bpf_supported() const;
+ bool seccomp_bpf_with_tsync_supported() const;
// Returns true if it can be determined that the current process has open
// directories that are not managed by the LinuxSandbox class. This would
// be a vulnerability as it would allow to bypass the setuid sandbox.
@@ -131,7 +169,9 @@ class LinuxSandbox {
// Did PreinitializeSandbox() run?
bool pre_initialized_;
bool seccomp_bpf_supported_; // Accurate if pre_initialized_.
+ bool seccomp_bpf_with_tsync_supported_; // Accurate if pre_initialized_.
bool yama_is_enforcing_; // Accurate if pre_initialized_.
+ bool initialize_sandbox_ran_; // InitializeSandbox() was called.
scoped_ptr<sandbox::SetuidSandboxClient> setuid_sandbox_client_;
#if defined(ANY_OF_AMTLU_SANITIZER)
scoped_ptr<__sanitizer_sandbox_arguments> sanitizer_args_;
diff --git a/chromium/content/common/sandbox_linux/sandbox_seccomp_bpf_linux.cc b/chromium/content/common/sandbox_linux/sandbox_seccomp_bpf_linux.cc
index 54daf90eb98..79adbee4bba 100644
--- a/chromium/content/common/sandbox_linux/sandbox_seccomp_bpf_linux.cc
+++ b/chromium/content/common/sandbox_linux/sandbox_seccomp_bpf_linux.cc
@@ -19,6 +19,8 @@
#if defined(USE_SECCOMP_BPF)
+#include "base/files/scoped_file.h"
+#include "base/memory/scoped_ptr.h"
#include "base/posix/eintr_wrapper.h"
#include "content/common/sandbox_linux/bpf_cros_arm_gpu_policy_linux.h"
#include "content/common/sandbox_linux/bpf_gpu_policy_linux.h"
@@ -26,17 +28,16 @@
#include "content/common/sandbox_linux/bpf_renderer_policy_linux.h"
#include "content/common/sandbox_linux/bpf_utility_policy_linux.h"
#include "content/common/sandbox_linux/sandbox_bpf_base_policy_linux.h"
-#include "content/common/sandbox_linux/sandbox_linux.h"
#include "sandbox/linux/seccomp-bpf-helpers/baseline_policy.h"
#include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
#include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h"
#include "sandbox/linux/seccomp-bpf-helpers/syscall_sets.h"
#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
-#include "sandbox/linux/services/linux_syscalls.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
#if !defined(IN_NACL_HELPER)
#include "ui/gl/gl_switches.h"
-#endif
+#endif // !defined(IN_NACL_HELPER)
using sandbox::BaselinePolicy;
using sandbox::SandboxBPF;
@@ -59,7 +60,21 @@ namespace content {
#if defined(USE_SECCOMP_BPF)
namespace {
-void StartSandboxWithPolicy(sandbox::bpf_dsl::Policy* policy);
+// This function takes ownership of |policy|.
+void StartSandboxWithPolicy(sandbox::bpf_dsl::Policy* policy,
+ base::ScopedFD proc_fd) {
+ // Starting the sandbox is a one-way operation. The kernel doesn't allow
+ // us to unload a sandbox policy after it has been started. Nonetheless,
+ // in order to make the use of the "Sandbox" object easier, we allow for
+ // the object to be destroyed after the sandbox has been started. Note that
+ // doing so does not stop the sandbox.
+ SandboxBPF sandbox(policy);
+
+ sandbox.SetProcFd(proc_fd.Pass());
+ CHECK(sandbox.StartSandbox(SandboxBPF::SeccompLevel::SINGLE_THREADED));
+}
+
+#if !defined(OS_NACL_NONSFI)
inline bool IsChromeOS() {
#if defined(OS_CHROMEOS)
@@ -142,19 +157,6 @@ void RunSandboxSanityChecks(const std::string& process_type) {
}
}
-
-// This function takes ownership of |policy|.
-void StartSandboxWithPolicy(sandbox::bpf_dsl::Policy* policy) {
- // Starting the sandbox is a one-way operation. The kernel doesn't allow
- // us to unload a sandbox policy after it has been started. Nonetheless,
- // in order to make the use of the "Sandbox" object easier, we allow for
- // the object to be destroyed after the sandbox has been started. Note that
- // doing so does not stop the sandbox.
- SandboxBPF sandbox;
- sandbox.SetSandboxPolicy(policy);
- CHECK(sandbox.StartSandbox(SandboxBPF::PROCESS_SINGLE_THREADED));
-}
-
// nacl_helper needs to be tiny and includes only part of content/
// in its dependencies. Make sure to not link things that are not needed.
#if !defined(IN_NACL_HELPER)
@@ -181,7 +183,8 @@ scoped_ptr<SandboxBPFBasePolicy> GetGpuProcessSandbox() {
// Initialize the seccomp-bpf sandbox.
bool StartBPFSandbox(const base::CommandLine& command_line,
- const std::string& process_type) {
+ const std::string& process_type,
+ base::ScopedFD proc_fd) {
scoped_ptr<SandboxBPFBasePolicy> policy;
if (process_type == switches::kGpuProcess) {
@@ -198,7 +201,7 @@ bool StartBPFSandbox(const base::CommandLine& command_line,
}
CHECK(policy->PreSandboxHook());
- StartSandboxWithPolicy(policy.release());
+ StartSandboxWithPolicy(policy.release(), proc_fd.Pass());
RunSandboxSanityChecks(process_type);
return true;
@@ -214,6 +217,7 @@ bool StartBPFSandbox(const base::CommandLine& command_line,
return false;
}
#endif // !defined(IN_NACL_HELPER)
+#endif // !defined(OS_NACL_NONSFI)
} // namespace
@@ -231,6 +235,7 @@ bool SandboxSeccompBPF::IsSeccompBPFDesired() {
}
}
+#if !defined(OS_NACL_NONSFI)
bool SandboxSeccompBPF::ShouldEnableSeccompBPF(
const std::string& process_type) {
#if defined(USE_SECCOMP_BPF)
@@ -243,25 +248,27 @@ bool SandboxSeccompBPF::ShouldEnableSeccompBPF(
#endif // USE_SECCOMP_BPF
return false;
}
+#endif // !defined(OS_NACL_NONSFI)
bool SandboxSeccompBPF::SupportsSandbox() {
#if defined(USE_SECCOMP_BPF)
- // TODO(jln): pass the saved proc_fd_ from the LinuxSandbox singleton
- // here.
- SandboxBPF::SandboxStatus bpf_sandbox_status =
- SandboxBPF::SupportsSeccompSandbox(-1);
- // Kernel support is what we are interested in here. Other status
- // such as STATUS_UNAVAILABLE (has threads) still indicate kernel support.
- // We make this a negative check, since if there is a bug, we would rather
- // "fail closed" (expect a sandbox to be available and try to start it).
- if (bpf_sandbox_status != SandboxBPF::STATUS_UNSUPPORTED) {
- return true;
- }
+ return SandboxBPF::SupportsSeccompSandbox(
+ SandboxBPF::SeccompLevel::SINGLE_THREADED);
+#endif
+ return false;
+}
+
+#if !defined(OS_NACL_NONSFI)
+bool SandboxSeccompBPF::SupportsSandboxWithTsync() {
+#if defined(USE_SECCOMP_BPF)
+ return SandboxBPF::SupportsSeccompSandbox(
+ SandboxBPF::SeccompLevel::MULTI_THREADED);
#endif
return false;
}
-bool SandboxSeccompBPF::StartSandbox(const std::string& process_type) {
+bool SandboxSeccompBPF::StartSandbox(const std::string& process_type,
+ base::ScopedFD proc_fd) {
#if defined(USE_SECCOMP_BPF)
const base::CommandLine& command_line =
*base::CommandLine::ForCurrentProcess();
@@ -271,26 +278,30 @@ bool SandboxSeccompBPF::StartSandbox(const std::string& process_type) {
SupportsSandbox()) {
// If the kernel supports the sandbox, and if the command line says we
// should enable it, enable it or die.
- bool started_sandbox = StartBPFSandbox(command_line, process_type);
+ bool started_sandbox =
+ StartBPFSandbox(command_line, process_type, proc_fd.Pass());
CHECK(started_sandbox);
return true;
}
#endif
return false;
}
+#endif // !defined(OS_NACL_NONSFI)
bool SandboxSeccompBPF::StartSandboxWithExternalPolicy(
- scoped_ptr<sandbox::bpf_dsl::Policy> policy) {
+ scoped_ptr<sandbox::bpf_dsl::Policy> policy,
+ base::ScopedFD proc_fd) {
#if defined(USE_SECCOMP_BPF)
if (IsSeccompBPFDesired() && SupportsSandbox()) {
CHECK(policy);
- StartSandboxWithPolicy(policy.release());
+ StartSandboxWithPolicy(policy.release(), proc_fd.Pass());
return true;
}
#endif // defined(USE_SECCOMP_BPF)
return false;
}
+#if !defined(OS_NACL_NONSFI)
scoped_ptr<sandbox::bpf_dsl::Policy> SandboxSeccompBPF::GetBaselinePolicy() {
#if defined(USE_SECCOMP_BPF)
return scoped_ptr<sandbox::bpf_dsl::Policy>(new BaselinePolicy);
@@ -298,5 +309,6 @@ scoped_ptr<sandbox::bpf_dsl::Policy> SandboxSeccompBPF::GetBaselinePolicy() {
return scoped_ptr<sandbox::bpf_dsl::Policy>();
#endif // defined(USE_SECCOMP_BPF)
}
+#endif // !defined(OS_NACL_NONSFI)
} // namespace content
diff --git a/chromium/content/common/sandbox_linux/sandbox_seccomp_bpf_linux.h b/chromium/content/common/sandbox_linux/sandbox_seccomp_bpf_linux.h
index 91702fc443d..6761a1a1668 100644
--- a/chromium/content/common/sandbox_linux/sandbox_seccomp_bpf_linux.h
+++ b/chromium/content/common/sandbox_linux/sandbox_seccomp_bpf_linux.h
@@ -8,13 +8,9 @@
#include <string>
#include "base/basictypes.h"
+#include "base/files/scoped_file.h"
#include "base/memory/scoped_ptr.h"
-
-namespace sandbox {
-namespace bpf_dsl {
-class Policy;
-}
-}
+#include "sandbox/linux/bpf_dsl/policy.h"
namespace content {
@@ -31,17 +27,20 @@ class SandboxSeccompBPF {
static bool IsSeccompBPFDesired();
// Should the sandbox be enabled for process_type ?
static bool ShouldEnableSeccompBPF(const std::string& process_type);
- // Check if the kernel supports this sandbox. It's useful to "prewarm"
- // this, part of the result will be cached.
+ // Check if the kernel supports seccomp-bpf.
static bool SupportsSandbox();
+ // Check if the kernel supports TSYNC (thread synchronization) with seccomp.
+ static bool SupportsSandboxWithTsync();
// Start the sandbox and apply the policy for process_type, depending on
// command line switches.
- static bool StartSandbox(const std::string& process_type);
+ static bool StartSandbox(const std::string& process_type,
+ base::ScopedFD proc_fd);
// This is the API to enable a seccomp-bpf sandbox by using an
// external policy.
static bool StartSandboxWithExternalPolicy(
- scoped_ptr<sandbox::bpf_dsl::Policy> policy);
+ scoped_ptr<sandbox::bpf_dsl::Policy> policy,
+ base::ScopedFD proc_fd);
// The "baseline" policy can be a useful base to build a sandbox policy.
static scoped_ptr<sandbox::bpf_dsl::Policy> GetBaselinePolicy();
diff --git a/chromium/content/common/sandbox_mac.mm b/chromium/content/common/sandbox_mac.mm
index 118919f20a3..a13aaf77372 100644
--- a/chromium/content/common/sandbox_mac.mm
+++ b/chromium/content/common/sandbox_mac.mm
@@ -19,6 +19,7 @@ extern "C" {
#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
#include "base/mac/bundle_locations.h"
+#include "base/mac/foundation_util.h"
#include "base/mac/mac_util.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/mac/scoped_nsautorelease_pool.h"
@@ -31,6 +32,7 @@ extern "C" {
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/sys_info.h"
+#include "content/common/gpu/media/vt_video_decode_accelerator.h"
#include "content/grit/content_resources.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_switches.h"
@@ -63,9 +65,9 @@ SandboxTypeToResourceIDMapping kDefaultSandboxTypeToResourceIDMapping[] = {
{ SANDBOX_TYPE_PPAPI, IDR_PPAPI_SANDBOX_PROFILE },
};
-COMPILE_ASSERT(arraysize(kDefaultSandboxTypeToResourceIDMapping) == \
- size_t(SANDBOX_TYPE_AFTER_LAST_TYPE), \
- sandbox_type_to_resource_id_mapping_incorrect);
+static_assert(arraysize(kDefaultSandboxTypeToResourceIDMapping) == \
+ size_t(SANDBOX_TYPE_AFTER_LAST_TYPE), \
+ "sandbox type to resource id mapping incorrect");
// Try to escape |c| as a "SingleEscapeCharacter" (\n, etc). If successful,
// returns true and appends the escape sequence to |dst|.
@@ -323,6 +325,9 @@ void Sandbox::SandboxWarmup(int sandbox_type) {
// Preload either the desktop GL or the osmesa so, depending on the
// --use-gl flag.
gfx::GLSurface::InitializeOneOff();
+
+ // Preload VideoToolbox.
+ InitializeVideoToolbox();
}
if (sandbox_type == SANDBOX_TYPE_PPAPI) {
diff --git a/chromium/content/common/sandbox_mac_diraccess_unittest.mm b/chromium/content/common/sandbox_mac_diraccess_unittest.mm
index 7a3fed8dfbc..a403ecd2563 100644
--- a/chromium/content/common/sandbox_mac_diraccess_unittest.mm
+++ b/chromium/content/common/sandbox_mac_diraccess_unittest.mm
@@ -34,14 +34,14 @@ class MacDirAccessSandboxTest : public base::MultiProcessTest {
public:
bool CheckSandbox(const std::string& directory_to_try) {
setenv(kSandboxAccessPathKey, directory_to_try.c_str(), 1);
- base::ProcessHandle child_process = SpawnChild("mac_sandbox_path_access");
- if (child_process == base::kNullProcessHandle) {
+ base::Process child_process = SpawnChild("mac_sandbox_path_access");
+ if (!child_process.IsValid()) {
LOG(WARNING) << "SpawnChild failed";
return false;
}
int code = -1;
- if (!base::WaitForExitCode(child_process, &code)) {
- LOG(WARNING) << "base::WaitForExitCode failed";
+ if (!child_process.WaitForExit(&code)) {
+ LOG(WARNING) << "Process::WaitForExit failed";
return false;
}
return code == 0;
diff --git a/chromium/content/common/sandbox_mac_system_access_unittest.mm b/chromium/content/common/sandbox_mac_system_access_unittest.mm
index 1d5f1d48d53..8a6c1d3a114 100644
--- a/chromium/content/common/sandbox_mac_system_access_unittest.mm
+++ b/chromium/content/common/sandbox_mac_system_access_unittest.mm
@@ -156,7 +156,7 @@ TEST_F(MacSandboxTest, OpenSSLAccess) {
// Test case for checking sandboxing of NSS initialization.
class MacSandboxedNSSTestCase : public MacSandboxTestCase {
public:
- virtual bool SandboxedTest() override;
+ bool SandboxedTest() override;
};
REGISTER_SANDBOX_TEST_CASE(MacSandboxedNSSTestCase);
diff --git a/chromium/content/common/sandbox_mac_unittest_helper.mm b/chromium/content/common/sandbox_mac_unittest_helper.mm
index faac7ae21d1..cb029d146e1 100644
--- a/chromium/content/common/sandbox_mac_unittest_helper.mm
+++ b/chromium/content/common/sandbox_mac_unittest_helper.mm
@@ -77,14 +77,14 @@ bool MacSandboxTest::RunTestInSandbox(SandboxType sandbox_type,
if (test_data)
setenv(kTestDataKey, test_data, 1);
- base::ProcessHandle child_process = SpawnChild("mac_sandbox_test_runner");
- if (child_process == base::kNullProcessHandle) {
+ base::Process child_process = SpawnChild("mac_sandbox_test_runner");
+ if (!child_process.IsValid()) {
LOG(WARNING) << "SpawnChild failed";
return false;
}
int code = -1;
- if (!base::WaitForExitCode(child_process, &code)) {
- LOG(WARNING) << "base::WaitForExitCode failed";
+ if (!child_process.WaitForExit(&code)) {
+ LOG(WARNING) << "Process::WaitForExit failed";
return false;
}
return code == 0;
diff --git a/chromium/content/common/sandbox_win.cc b/chromium/content/common/sandbox_win.cc
index 1a5a66c0831..8f76710bc8d 100644
--- a/chromium/content/common/sandbox_win.cc
+++ b/chromium/content/common/sandbox_win.cc
@@ -9,24 +9,30 @@
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/debug/profiler.h"
-#include "base/debug/trace_event.h"
#include "base/files/file_util.h"
#include "base/hash.h"
+#include "base/memory/shared_memory.h"
+#include "base/metrics/sparse_histogram.h"
#include "base/path_service.h"
#include "base/process/launch.h"
+#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event.h"
#include "base/win/iat_patch_function.h"
#include "base/win/scoped_handle.h"
#include "base/win/scoped_process_information.h"
#include "base/win/windows_version.h"
+#include "content/common/content_switches_internal.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_switches.h"
+#include "content/public/common/dwrite_font_platform_win.h"
#include "content/public/common/sandbox_init.h"
#include "content/public/common/sandboxed_process_launcher_delegate.h"
#include "sandbox/win/src/process_mitigations.h"
#include "sandbox/win/src/sandbox.h"
#include "sandbox/win/src/sandbox_nt_util.h"
+#include "sandbox/win/src/sandbox_policy_base.h"
#include "sandbox/win/src/win_utils.h"
#include "ui/gfx/win/direct_write.h"
@@ -55,14 +61,18 @@ const wchar_t* const kTroublesomeDlls[] = {
L"cmcsyshk.dll", // CMC Internet Security.
L"cmsetac.dll", // Unknown (suspected malware).
L"cooliris.dll", // CoolIris.
+ L"cplushook.dll", // Unknown (suspected malware).
L"dockshellhook.dll", // Stardock Objectdock.
L"easyhook32.dll", // GDIPP and others.
+ L"esspd.dll", // Samsung Smart Security ESCORT.
L"googledesktopnetwork3.dll", // Google Desktop Search v5.
L"fwhook.dll", // PC Tools Firewall Plus.
L"hookprocesscreation.dll", // Blumentals Program protector.
L"hookterminateapis.dll", // Blumentals and Cyberprinter.
L"hookprintapis.dll", // Cyberprinter.
L"imon.dll", // NOD32 Antivirus.
+ L"icatcdll.dll", // Samsung Smart Security ESCORT.
+ L"icdcnl.dll", // Samsung Smart Security ESCORT.
L"ioloHL.dll", // Iolo (System Mechanic).
L"kloehk.dll", // Kaspersky Internet Security.
L"lawenforcer.dll", // Spyware-Browser AntiSpyware (Spybro).
@@ -76,6 +86,7 @@ const wchar_t* const kTroublesomeDlls[] = {
L"npggNT.des", // GameGuard 2008.
L"npggNT.dll", // GameGuard (older).
L"oawatch.dll", // Online Armor.
+ L"pastali32.dll", // PastaLeads.
L"pavhook.dll", // Panda Internet Security.
L"pavlsphook.dll", // Panda Antivirus.
L"pavshook.dll", // Panda Antivirus.
@@ -335,6 +346,40 @@ bool AddGenericPolicy(sandbox::TargetPolicy* policy) {
return false;
#endif // NDEBUG
+ // Add the policy for read-only PDB file access for AddressSanitizer.
+#if defined(ADDRESS_SANITIZER)
+ base::FilePath exe;
+ if (!PathService::Get(base::FILE_EXE, &exe))
+ return false;
+ base::FilePath pdb_path = exe.DirName().Append(L"*.pdb");
+ result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
+ sandbox::TargetPolicy::FILES_ALLOW_READONLY,
+ pdb_path.value().c_str());
+ if (result != sandbox::SBOX_ALL_OK)
+ return false;
+#endif
+
+#if defined(SANITIZER_COVERAGE)
+ DWORD coverage_dir_size =
+ ::GetEnvironmentVariable(L"SANITIZER_COVERAGE_DIR", NULL, 0);
+ if (coverage_dir_size == 0) {
+ LOG(WARNING) << "SANITIZER_COVERAGE_DIR was not set, coverage won't work.";
+ } else {
+ std::wstring coverage_dir;
+ wchar_t* coverage_dir_str = WriteInto(&coverage_dir, coverage_dir_size);
+ coverage_dir_size = ::GetEnvironmentVariable(
+ L"SANITIZER_COVERAGE_DIR", coverage_dir_str, coverage_dir_size);
+ CHECK(coverage_dir.size() == coverage_dir_size);
+ base::FilePath sancov_path =
+ base::FilePath(coverage_dir).Append(L"*.sancov");
+ result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
+ sandbox::TargetPolicy::FILES_ALLOW_ANY,
+ sancov_path.value().c_str());
+ if (result != sandbox::SBOX_ALL_OK)
+ return false;
+ }
+#endif
+
AddGenericDllEvictionPolicy(policy);
return true;
}
@@ -577,7 +622,7 @@ bool InitTargetServices(sandbox::TargetServices* target_services) {
return sandbox::SBOX_ALL_OK == result;
}
-base::ProcessHandle StartSandboxedProcess(
+base::Process StartSandboxedProcess(
SandboxedProcessLauncherDelegate* delegate,
base::CommandLine* cmd_line) {
const base::CommandLine& browser_command_line =
@@ -602,10 +647,11 @@ base::ProcessHandle StartSandboxedProcess(
if ((delegate && !delegate->ShouldSandbox()) ||
browser_command_line.HasSwitch(switches::kNoSandbox) ||
cmd_line->HasSwitch(switches::kNoSandbox)) {
- base::ProcessHandle process = 0;
- base::LaunchProcess(*cmd_line, base::LaunchOptions(), &process);
- g_broker_services->AddTargetPeer(process);
- return process;
+ base::Process process =
+ base::LaunchProcess(*cmd_line, base::LaunchOptions());
+ // TODO(rvargas) crbug.com/417532: Don't share a raw handle.
+ g_broker_services->AddTargetPeer(process.Handle());
+ return process.Pass();
}
sandbox::TargetPolicy* policy = g_broker_services->CreatePolicy();
@@ -616,26 +662,26 @@ base::ProcessHandle StartSandboxedProcess(
sandbox::MITIGATION_DEP_NO_ATL_THUNK |
sandbox::MITIGATION_SEHOP;
- if (base::win::GetVersion() >= base::win::VERSION_WIN8 &&
- type_str == switches::kRendererProcess &&
- browser_command_line.HasSwitch(
- switches::kEnableWin32kRendererLockDown)) {
+#if !defined(NACL_WIN64)
+ if (type_str == switches::kRendererProcess &&
+ IsWin32kRendererLockdownEnabled()) {
if (policy->AddRule(sandbox::TargetPolicy::SUBSYS_WIN32K_LOCKDOWN,
sandbox::TargetPolicy::FAKE_USER_GDI_INIT,
NULL) != sandbox::SBOX_ALL_OK) {
- return 0;
+ return base::Process();
}
mitigations |= sandbox::MITIGATION_WIN32K_DISABLE;
}
+#endif
if (policy->SetProcessMitigations(mitigations) != sandbox::SBOX_ALL_OK)
- return 0;
+ return base::Process();
mitigations = sandbox::MITIGATION_STRICT_HANDLE_CHECKS |
sandbox::MITIGATION_DLL_SEARCH_ORDER;
if (policy->SetDelayedProcessMitigations(mitigations) != sandbox::SBOX_ALL_OK)
- return 0;
+ return base::Process();
SetJobLevel(*cmd_line, sandbox::JOB_LOCKDOWN, 0, policy);
@@ -645,7 +691,7 @@ base::ProcessHandle StartSandboxedProcess(
delegate->PreSandbox(&disable_default_policy, &exposed_dir);
if (!disable_default_policy && !AddPolicyForSandboxedProcess(policy))
- return 0;
+ return base::Process();
if (type_str == switches::kRendererProcess) {
#if !defined(NACL_WIN64)
@@ -655,6 +701,22 @@ base::ProcessHandle StartSandboxedProcess(
true,
sandbox::TargetPolicy::FILES_ALLOW_READONLY,
policy);
+
+ // If DirectWrite is enabled for font rendering then open the font cache
+ // section which is created by the browser and pass the handle to the
+ // renderer process. This is needed because renderer processes on
+ // Windows 8+ may be running in an AppContainer sandbox and hence their
+ // kernel object namespace may be partitioned.
+ std::string name(content::kFontCacheSharedSectionName);
+ name.append(base::UintToString(base::GetCurrentProcId()));
+
+ base::SharedMemory direct_write_font_cache_section;
+ if (direct_write_font_cache_section.Open(name, true)) {
+ void* shared_handle =
+ policy->AddHandleToShare(direct_write_font_cache_section.handle());
+ cmd_line->AppendSwitchASCII(switches::kFontCacheSharedHandle,
+ base::UintToString(reinterpret_cast<unsigned int>(shared_handle)));
+ }
}
#endif
} else {
@@ -670,19 +732,19 @@ base::ProcessHandle StartSandboxedProcess(
sandbox::TargetPolicy::FILES_ALLOW_ANY,
exposed_dir.value().c_str());
if (result != sandbox::SBOX_ALL_OK)
- return 0;
+ return base::Process();
base::FilePath exposed_files = exposed_dir.AppendASCII("*");
result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
sandbox::TargetPolicy::FILES_ALLOW_ANY,
exposed_files.value().c_str());
if (result != sandbox::SBOX_ALL_OK)
- return 0;
+ return base::Process();
}
if (!AddGenericPolicy(policy)) {
NOTREACHED();
- return 0;
+ return base::Process();
}
if (browser_command_line.HasSwitch(switches::kEnableLogging)) {
@@ -696,7 +758,7 @@ base::ProcessHandle StartSandboxedProcess(
bool success = true;
delegate->PreSpawnTarget(policy, &success);
if (!success)
- return 0;
+ return base::Process();
}
TRACE_EVENT_BEGIN_ETW("StartProcessWithAccess::LAUNCHPROCESS", 0, 0);
@@ -706,7 +768,7 @@ base::ProcessHandle StartSandboxedProcess(
cmd_line->GetProgram().value().c_str(),
cmd_line->GetCommandLineString().c_str(),
policy, &temp_process_info);
- policy->Release();
+ DWORD last_error = ::GetLastError();
base::win::ScopedProcessInformation target(temp_process_info);
TRACE_EVENT_END_ETW("StartProcessWithAccess::LAUNCHPROCESS", 0, 0);
@@ -714,17 +776,29 @@ base::ProcessHandle StartSandboxedProcess(
if (sandbox::SBOX_ALL_OK != result) {
if (result == sandbox::SBOX_ERROR_GENERIC)
DPLOG(ERROR) << "Failed to launch process";
- else
+ else if (result == sandbox::SBOX_ERROR_CREATE_PROCESS) {
+ // TODO(shrikant): Remove this special case handling after determining
+ // cause for lowbox/createprocess errors.
+ sandbox::PolicyBase* policy_base =
+ static_cast<sandbox::PolicyBase*>(policy);
+ UMA_HISTOGRAM_SPARSE_SLOWLY(policy_base->GetLowBoxSid() ?
+ "Process.Sandbox.Lowbox.Launch.Error" :
+ "Process.Sandbox.Launch.Error",
+ last_error);
+ } else
DLOG(ERROR) << "Failed to launch process. Error: " << result;
- return 0;
+
+ policy->Release();
+ return base::Process();
}
+ policy->Release();
if (delegate)
delegate->PostSpawnTarget(target.process_handle());
CHECK(ResumeThread(target.thread_handle()) != -1);
TRACE_EVENT_END_ETW("StartProcessWithAccess", 0, type_str);
- return target.TakeProcessHandle();
+ return base::Process(target.TakeProcessHandle());
}
bool BrokerDuplicateHandle(HANDLE source_handle,
diff --git a/chromium/content/common/screen_orientation_messages.h b/chromium/content/common/screen_orientation_messages.h
index 2defcc71fa5..d5c3a601add 100644
--- a/chromium/content/common/screen_orientation_messages.h
+++ b/chromium/content/common/screen_orientation_messages.h
@@ -9,16 +9,12 @@
#include "ipc/ipc_message_macros.h"
#include "third_party/WebKit/public/platform/WebLockOrientationError.h"
#include "third_party/WebKit/public/platform/WebScreenOrientationLockType.h"
-#include "third_party/WebKit/public/platform/WebScreenOrientationType.h"
#undef IPC_MESSAGE_EXPORT
#define IPC_MESSAGE_EXPORT CONTENT_EXPORT
#define IPC_MESSAGE_START ScreenOrientationMsgStart
-IPC_ENUM_TRAITS_MIN_MAX_VALUE(blink::WebScreenOrientationType,
- blink::WebScreenOrientationUndefined,
- blink::WebScreenOrientationLandscapeSecondary)
IPC_ENUM_TRAITS_MIN_MAX_VALUE(blink::WebScreenOrientationLockType,
blink::WebScreenOrientationLockDefault,
blink::WebScreenOrientationLockNatural)
@@ -27,12 +23,6 @@ IPC_ENUM_TRAITS_MIN_MAX_VALUE(
blink::WebLockOrientationErrorNotAvailable,
blink::WebLockOrientationErrorCanceled)
-// The browser process informs the renderer process that the screen orientation
-// has changed. |orientation| contains the new screen orientation in degrees.
-// TODO(mlamouri): we could probably get rid of it.
-IPC_MESSAGE_CONTROL1(ScreenOrientationMsg_OrientationChange,
- blink::WebScreenOrientationType /* orientation */ )
-
// The browser process' response to a ScreenOrientationHostMsg_LockRequest when
// the lock actually succeeded. The |request_id| passed when receiving the
// request is passed back so the renderer process can associate the response to
diff --git a/chromium/content/common/send_zygote_child_ping_linux.cc b/chromium/content/common/send_zygote_child_ping_linux.cc
new file mode 100644
index 00000000000..1a4f49f8ae0
--- /dev/null
+++ b/chromium/content/common/send_zygote_child_ping_linux.cc
@@ -0,0 +1,21 @@
+// Copyright 2014 The Chromium Authors. 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/common/send_zygote_child_ping_linux.h"
+
+#include <vector>
+
+#include "base/posix/unix_domain_socket_linux.h"
+#include "content/common/zygote_commands_linux.h"
+
+namespace content {
+
+bool SendZygoteChildPing(int fd) {
+ return UnixDomainSocket::SendMsg(fd,
+ kZygoteChildPingMessage,
+ sizeof(kZygoteChildPingMessage),
+ std::vector<int>());
+}
+
+} // namespace content
diff --git a/chromium/content/common/service_worker/embedded_worker_messages.h b/chromium/content/common/service_worker/embedded_worker_messages.h
index 438cf6cc19d..557b8a48012 100644
--- a/chromium/content/common/service_worker/embedded_worker_messages.h
+++ b/chromium/content/common/service_worker/embedded_worker_messages.h
@@ -6,6 +6,7 @@
#include <string>
+#include "content/public/common/web_preferences.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_message_macros.h"
#include "ipc/ipc_param_traits.h"
@@ -25,6 +26,7 @@ IPC_STRUCT_BEGIN(EmbeddedWorkerMsg_StartWorker_Params)
IPC_STRUCT_MEMBER(int, worker_devtools_agent_route_id)
IPC_STRUCT_MEMBER(bool, pause_after_download)
IPC_STRUCT_MEMBER(bool, wait_for_debugger)
+ IPC_STRUCT_MEMBER(content::V8CacheOptions, v8_cache_options)
IPC_STRUCT_END()
// Parameters structure for EmbeddedWorkerHostMsg_ReportConsoleMessage.
@@ -63,9 +65,10 @@ IPC_MESSAGE_CONTROL1(EmbeddedWorkerHostMsg_WorkerReadyForInspection,
// Renderer -> Browser message to indicate that the worker has loadedd the
// script.
-IPC_MESSAGE_CONTROL2(EmbeddedWorkerHostMsg_WorkerScriptLoaded,
+IPC_MESSAGE_CONTROL3(EmbeddedWorkerHostMsg_WorkerScriptLoaded,
int /* embedded_worker_id */,
- int /* thread_id */)
+ int /* thread_id */,
+ int /* provider_id */)
// Renderer -> Browser message to indicate that the worker has failed to load
// the script.
diff --git a/chromium/content/common/service_worker/service_worker_client_info.cc b/chromium/content/common/service_worker/service_worker_client_info.cc
new file mode 100644
index 00000000000..3d9d554af4f
--- /dev/null
+++ b/chromium/content/common/service_worker/service_worker_client_info.cc
@@ -0,0 +1,44 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/common/service_worker/service_worker_client_info.h"
+
+#include "base/logging.h"
+#include "content/common/service_worker/service_worker_types.h"
+
+namespace content {
+
+ServiceWorkerClientInfo::ServiceWorkerClientInfo()
+ : page_visibility_state(blink::WebPageVisibilityStateLast),
+ is_focused(false),
+ frame_type(REQUEST_CONTEXT_FRAME_TYPE_LAST),
+ client_type(blink::WebServiceWorkerClientTypeLast) {
+}
+
+ServiceWorkerClientInfo::ServiceWorkerClientInfo(
+ blink::WebPageVisibilityState page_visibility_state,
+ bool is_focused,
+ const GURL& url,
+ RequestContextFrameType frame_type,
+ blink::WebServiceWorkerClientType client_type)
+ : page_visibility_state(page_visibility_state),
+ is_focused(is_focused),
+ url(url),
+ frame_type(frame_type),
+ client_type(client_type) {
+}
+
+bool ServiceWorkerClientInfo::IsEmpty() const {
+ return page_visibility_state == blink::WebPageVisibilityStateLast &&
+ is_focused == false &&
+ url.is_empty() &&
+ frame_type == REQUEST_CONTEXT_FRAME_TYPE_LAST &&
+ client_type == blink::WebServiceWorkerClientTypeLast;
+}
+
+bool ServiceWorkerClientInfo::IsValid() const {
+ return !IsEmpty() && !client_uuid.empty();
+}
+
+} // namespace content
diff --git a/chromium/content/common/service_worker/service_worker_client_info.h b/chromium/content/common/service_worker/service_worker_client_info.h
new file mode 100644
index 00000000000..e21aa1552f9
--- /dev/null
+++ b/chromium/content/common/service_worker/service_worker_client_info.h
@@ -0,0 +1,45 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_COMMON_SERVICE_WORKER_SERVICE_WORKER_CLIENT_INFO_H_
+#define CONTENT_COMMON_SERVICE_WORKER_SERVICE_WORKER_CLIENT_INFO_H_
+
+#include "content/public/common/request_context_frame_type.h"
+#include "third_party/WebKit/public/platform/WebPageVisibilityState.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerClientType.h"
+#include "url/gurl.h"
+
+namespace content {
+
+// This class holds the information related to a service worker window client.
+// It is the content/ equivalent of Blink's WebServiceWorkerClientInfo.
+// An instance can be created empty or can be filed with the expected
+// properties. Except for the client_uuid, it is preferred to use the
+// constructor to fill the properties.
+struct ServiceWorkerClientInfo {
+ ServiceWorkerClientInfo();
+ ServiceWorkerClientInfo(blink::WebPageVisibilityState page_visibility_state,
+ bool is_focused,
+ const GURL& url,
+ RequestContextFrameType frame_type,
+ blink::WebServiceWorkerClientType client_type);
+
+ // Returns whether the instance is empty.
+ bool IsEmpty() const;
+
+ // Returns whether the instance is valid. A valid instance is not empty and
+ // has a valid client_uuid.
+ bool IsValid() const;
+
+ std::string client_uuid;
+ blink::WebPageVisibilityState page_visibility_state;
+ bool is_focused;
+ GURL url;
+ RequestContextFrameType frame_type;
+ blink::WebServiceWorkerClientType client_type;
+};
+
+} // namespace content
+
+#endif // CONTENT_COMMON_SERVICE_WORKER_SERVICE_WORKER_CLIENT_INFO_H_
diff --git a/chromium/content/common/service_worker/service_worker_messages.h b/chromium/content/common/service_worker/service_worker_messages.h
index f645c5699fb..2c40c232758 100644
--- a/chromium/content/common/service_worker/service_worker_messages.h
+++ b/chromium/content/common/service_worker/service_worker_messages.h
@@ -8,13 +8,16 @@
#include <vector>
#include "base/strings/string16.h"
+#include "content/common/service_worker/service_worker_client_info.h"
#include "content/common/service_worker/service_worker_status_code.h"
#include "content/common/service_worker/service_worker_types.h"
+#include "content/public/common/message_port_types.h"
+#include "content/public/common/navigator_connect_client.h"
+#include "content/public/common/platform_notification_data.h"
#include "ipc/ipc_message_macros.h"
#include "ipc/ipc_param_traits.h"
#include "third_party/WebKit/public/platform/WebCircularGeofencingRegion.h"
#include "third_party/WebKit/public/platform/WebGeofencingEventType.h"
-#include "third_party/WebKit/public/platform/WebServiceWorkerCacheError.h"
#include "third_party/WebKit/public/platform/WebServiceWorkerError.h"
#include "third_party/WebKit/public/platform/WebServiceWorkerEventResult.h"
#include "url/gurl.h"
@@ -36,6 +39,12 @@ IPC_ENUM_TRAITS_MAX_VALUE(blink::WebServiceWorkerState,
IPC_ENUM_TRAITS_MAX_VALUE(blink::WebServiceWorkerResponseType,
blink::WebServiceWorkerResponseTypeLast)
+IPC_ENUM_TRAITS_MAX_VALUE(blink::WebServiceWorkerClientType,
+ blink::WebServiceWorkerClientTypeLast)
+
+IPC_ENUM_TRAITS_MAX_VALUE(content::ServiceWorkerProviderType,
+ content::SERVICE_WORKER_PROVIDER_TYPE_LAST)
+
IPC_STRUCT_TRAITS_BEGIN(content::ServiceWorkerFetchRequest)
IPC_STRUCT_TRAITS_MEMBER(mode)
IPC_STRUCT_TRAITS_MEMBER(request_context_type)
@@ -61,28 +70,11 @@ IPC_STRUCT_TRAITS_BEGIN(content::ServiceWorkerResponse)
IPC_STRUCT_TRAITS_MEMBER(headers)
IPC_STRUCT_TRAITS_MEMBER(blob_uuid)
IPC_STRUCT_TRAITS_MEMBER(blob_size)
-IPC_STRUCT_TRAITS_END()
-
-IPC_STRUCT_TRAITS_BEGIN(content::ServiceWorkerCacheQueryParams)
- IPC_STRUCT_TRAITS_MEMBER(ignore_search)
- IPC_STRUCT_TRAITS_MEMBER(ignore_method)
- IPC_STRUCT_TRAITS_MEMBER(ignore_vary)
- IPC_STRUCT_TRAITS_MEMBER(prefix_match)
-IPC_STRUCT_TRAITS_END()
-
-IPC_ENUM_TRAITS_MAX_VALUE(content::ServiceWorkerCacheOperationType,
- content::SERVICE_WORKER_CACHE_OPERATION_TYPE_LAST)
-
-IPC_STRUCT_TRAITS_BEGIN(content::ServiceWorkerBatchOperation)
- IPC_STRUCT_TRAITS_MEMBER(operation_type)
- IPC_STRUCT_TRAITS_MEMBER(request)
- IPC_STRUCT_TRAITS_MEMBER(response)
- IPC_STRUCT_TRAITS_MEMBER(match_params)
+ IPC_STRUCT_TRAITS_MEMBER(stream_url)
IPC_STRUCT_TRAITS_END()
IPC_STRUCT_TRAITS_BEGIN(content::ServiceWorkerObjectInfo)
IPC_STRUCT_TRAITS_MEMBER(handle_id)
- IPC_STRUCT_TRAITS_MEMBER(scope)
IPC_STRUCT_TRAITS_MEMBER(url)
IPC_STRUCT_TRAITS_MEMBER(state)
IPC_STRUCT_TRAITS_MEMBER(version_id)
@@ -100,9 +92,19 @@ IPC_STRUCT_TRAITS_BEGIN(content::ServiceWorkerVersionAttributes)
IPC_STRUCT_TRAITS_MEMBER(active)
IPC_STRUCT_TRAITS_END()
-IPC_ENUM_TRAITS_MAX_VALUE(
- blink::WebServiceWorkerCacheError,
- blink::WebServiceWorkerCacheErrorLast)
+IPC_STRUCT_TRAITS_BEGIN(content::ServiceWorkerClientInfo)
+ IPC_STRUCT_TRAITS_MEMBER(client_uuid)
+ IPC_STRUCT_TRAITS_MEMBER(page_visibility_state)
+ IPC_STRUCT_TRAITS_MEMBER(is_focused)
+ IPC_STRUCT_TRAITS_MEMBER(url)
+ IPC_STRUCT_TRAITS_MEMBER(frame_type)
+ IPC_STRUCT_TRAITS_MEMBER(client_type)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(content::ServiceWorkerClientQueryOptions)
+ IPC_STRUCT_TRAITS_MEMBER(client_type)
+ IPC_STRUCT_TRAITS_MEMBER(include_uncontrolled)
+IPC_STRUCT_TRAITS_END()
IPC_ENUM_TRAITS_MAX_VALUE(blink::WebGeofencingEventType,
blink::WebGeofencingEventTypeLast)
@@ -129,16 +131,29 @@ IPC_MESSAGE_CONTROL4(ServiceWorkerHostMsg_GetRegistration,
int /* provider_id */,
GURL /* document_url */)
+IPC_MESSAGE_CONTROL3(ServiceWorkerHostMsg_GetRegistrationForReady,
+ int /* thread_id */,
+ int /* request_id */,
+ int /* provider_id */)
+
// Sends a 'message' event to a service worker (renderer->browser).
-IPC_MESSAGE_CONTROL3(ServiceWorkerHostMsg_PostMessageToWorker,
- int /* handle_id */,
- base::string16 /* message */,
- std::vector<int> /* sent_message_port_ids */)
+IPC_MESSAGE_CONTROL3(
+ ServiceWorkerHostMsg_PostMessageToWorker,
+ int /* handle_id */,
+ base::string16 /* message */,
+ std::vector<content::TransferredMessagePort> /* sent_message_ports */)
// Informs the browser of a new ServiceWorkerProvider in the child process,
// |provider_id| is unique within its child process.
-IPC_MESSAGE_CONTROL1(ServiceWorkerHostMsg_ProviderCreated,
- int /* provider_id */)
+// |render_frame_id| identifies the frame associated with the provider, it will
+// it will be MSG_ROUTING_NONE if the context is a worker instead of a document.
+// |provider_type| identifies whether this provider is for ServiceWorker
+// controllees (documents and SharedWorkers) or for controllers
+// (ServiceWorkers).
+IPC_MESSAGE_CONTROL3(ServiceWorkerHostMsg_ProviderCreated,
+ int /* provider_id */,
+ int /* render_frame_id */,
+ content::ServiceWorkerProviderType /* provider_type */)
// Informs the browser of a ServiceWorkerProvider being destroyed.
IPC_MESSAGE_CONTROL1(ServiceWorkerHostMsg_ProviderDestroyed,
@@ -160,6 +175,11 @@ IPC_MESSAGE_CONTROL1(ServiceWorkerHostMsg_IncrementRegistrationRefCount,
IPC_MESSAGE_CONTROL1(ServiceWorkerHostMsg_DecrementRegistrationRefCount,
int /* registration_handle_id */)
+// Tells the browser to terminate a service worker. Used in layout tests to
+// verify behavior when a service worker isn't running.
+IPC_MESSAGE_CONTROL1(ServiceWorkerHostMsg_TerminateWorker,
+ int /* handle_id */)
+
// Informs the browser that |provider_id| is associated
// with a service worker script running context and
// |version_id| identifies which ServiceWorkerVersion.
@@ -181,67 +201,61 @@ IPC_MESSAGE_ROUTED3(ServiceWorkerHostMsg_FetchEventFinished,
content::ServiceWorkerResponse)
IPC_MESSAGE_ROUTED1(ServiceWorkerHostMsg_SyncEventFinished,
int /* request_id */)
-IPC_MESSAGE_ROUTED1(ServiceWorkerHostMsg_PushEventFinished,
+IPC_MESSAGE_ROUTED1(ServiceWorkerHostMsg_NotificationClickEventFinished,
int /* request_id */)
+IPC_MESSAGE_ROUTED2(ServiceWorkerHostMsg_PushEventFinished,
+ int /* request_id */,
+ blink::WebServiceWorkerEventResult)
IPC_MESSAGE_ROUTED1(ServiceWorkerHostMsg_GeofencingEventFinished,
int /* request_id */)
-
-// Asks the browser to retrieve documents controlled by the sender
-// ServiceWorker.
-IPC_MESSAGE_ROUTED1(ServiceWorkerHostMsg_GetClientDocuments,
- int /* request_id */)
-
-// Sends a 'message' event to a client document (renderer->browser).
-IPC_MESSAGE_ROUTED3(ServiceWorkerHostMsg_PostMessageToDocument,
- int /* client_id */,
- base::string16 /* message */,
- std::vector<int> /* sent_message_port_ids */)
-
-// CacheStorage operations in the browser.
-IPC_MESSAGE_ROUTED2(ServiceWorkerHostMsg_CacheStorageHas,
- int /* request_id */,
- base::string16 /* fetch_store_name */)
-
-IPC_MESSAGE_ROUTED2(ServiceWorkerHostMsg_CacheStorageOpen,
- int /* request_id */,
- base::string16 /* fetch_store_name */)
-
-IPC_MESSAGE_ROUTED2(ServiceWorkerHostMsg_CacheStorageDelete,
+IPC_MESSAGE_ROUTED2(ServiceWorkerHostMsg_CrossOriginConnectEventFinished,
int /* request_id */,
- base::string16 /* fetch_store_name */)
+ bool /* accept_connection */)
-IPC_MESSAGE_ROUTED1(ServiceWorkerHostMsg_CacheStorageKeys,
- int /* request_id */)
+// Responds to a Ping from the browser.
+// Routed to the target ServiceWorkerVersion.
+IPC_MESSAGE_ROUTED0(ServiceWorkerHostMsg_Pong)
-// Cache operations in the browser.
-IPC_MESSAGE_ROUTED4(ServiceWorkerHostMsg_CacheMatch,
+// Asks the browser to retrieve clients of the sender ServiceWorker.
+IPC_MESSAGE_ROUTED2(ServiceWorkerHostMsg_GetClients,
int /* request_id */,
- int /* cache_id */,
- content::ServiceWorkerFetchRequest,
- content::ServiceWorkerCacheQueryParams)
-
-IPC_MESSAGE_ROUTED4(ServiceWorkerHostMsg_CacheMatchAll,
+ content::ServiceWorkerClientQueryOptions)
+
+// Sends a 'message' event to a client (renderer->browser).
+IPC_MESSAGE_ROUTED3(
+ ServiceWorkerHostMsg_PostMessageToClient,
+ std::string /* uuid */,
+ base::string16 /* message */,
+ std::vector<content::TransferredMessagePort> /* sent_message_ports */)
+
+// ServiceWorker -> Browser message to request that the ServiceWorkerStorage
+// cache |data| associated with |url|.
+IPC_MESSAGE_ROUTED2(ServiceWorkerHostMsg_SetCachedMetadata,
+ GURL /* url */,
+ std::vector<char> /* data */)
+
+// ServiceWorker -> Browser message to request that the ServiceWorkerStorage
+// clear the cache associated with |url|.
+IPC_MESSAGE_ROUTED1(ServiceWorkerHostMsg_ClearCachedMetadata, GURL /* url */)
+
+// Ask the browser to open a tab/window (renderer->browser).
+IPC_MESSAGE_ROUTED2(ServiceWorkerHostMsg_OpenWindow,
int /* request_id */,
- int /* cache_id */,
- content::ServiceWorkerFetchRequest,
- content::ServiceWorkerCacheQueryParams)
+ GURL /* url */)
-IPC_MESSAGE_ROUTED4(ServiceWorkerHostMsg_CacheKeys,
+// Ask the browser to focus a client (renderer->browser).
+IPC_MESSAGE_ROUTED2(ServiceWorkerHostMsg_FocusClient,
int /* request_id */,
- int /* cache_id */,
- content::ServiceWorkerFetchRequest,
- content::ServiceWorkerCacheQueryParams)
-
-IPC_MESSAGE_ROUTED3(ServiceWorkerHostMsg_CacheBatch,
- int /* request_id */,
- int /* cache_id */,
- std::vector<content::ServiceWorkerBatchOperation>)
+ std::string /* uuid */)
-IPC_MESSAGE_ROUTED1(ServiceWorkerHostMsg_CacheClosed,
- int /* cache_id */)
+// Asks the browser to force this worker to become activated.
+IPC_MESSAGE_ROUTED1(ServiceWorkerHostMsg_SkipWaiting,
+ int /* request_id */)
-IPC_MESSAGE_ROUTED1(ServiceWorkerHostMsg_BlobDataHandled,
- std::string /* uuid */)
+// Asks the browser to have this worker take control of pages that match
+// its scope.
+IPC_MESSAGE_ROUTED1(ServiceWorkerHostMsg_ClaimClients,
+ int /* request_id */)
//---------------------------------------------------------------------------
// Messages sent from the browser to the child process.
@@ -251,6 +265,14 @@ IPC_MESSAGE_ROUTED1(ServiceWorkerHostMsg_BlobDataHandled,
// extract it and dispatch the message to the correct ServiceWorkerDispatcher
// on the correct thread.
+// Informs the child process of the registration associated with the service
+// worker.
+IPC_MESSAGE_CONTROL4(ServiceWorkerMsg_AssociateRegistrationWithServiceWorker,
+ int /* thread_id*/,
+ int /* provider_id */,
+ content::ServiceWorkerRegistrationObjectInfo,
+ content::ServiceWorkerVersionAttributes)
+
// Informs the child process that the given provider gets associated or
// disassociated with the registration.
IPC_MESSAGE_CONTROL4(ServiceWorkerMsg_AssociateRegistration,
@@ -282,6 +304,13 @@ IPC_MESSAGE_CONTROL4(ServiceWorkerMsg_DidGetRegistration,
content::ServiceWorkerRegistrationObjectInfo,
content::ServiceWorkerVersionAttributes)
+// Response to ServiceWorkerHostMsg_GetRegistrationForReady.
+IPC_MESSAGE_CONTROL4(ServiceWorkerMsg_DidGetRegistrationForReady,
+ int /* thread_id */,
+ int /* request_id */,
+ content::ServiceWorkerRegistrationObjectInfo,
+ content::ServiceWorkerVersionAttributes)
+
// Sent when any kind of registration error occurs during a
// RegisterServiceWorker handler above.
IPC_MESSAGE_CONTROL4(ServiceWorkerMsg_ServiceWorkerRegistrationError,
@@ -324,27 +353,28 @@ IPC_MESSAGE_CONTROL5(ServiceWorkerMsg_SetVersionAttributes,
// phase.
IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_UpdateFound,
int /* thread_id */,
- content::ServiceWorkerRegistrationObjectInfo)
+ int /* registration_handle_id */)
// Tells the child process to set the controller ServiceWorker for the given
// provider.
-IPC_MESSAGE_CONTROL3(ServiceWorkerMsg_SetControllerServiceWorker,
+IPC_MESSAGE_CONTROL4(ServiceWorkerMsg_SetControllerServiceWorker,
int /* thread_id */,
int /* provider_id */,
- content::ServiceWorkerObjectInfo)
+ content::ServiceWorkerObjectInfo,
+ bool /* should_notify_controllerchange */)
// Sends a 'message' event to a client document (browser->renderer).
-IPC_MESSAGE_CONTROL5(ServiceWorkerMsg_MessageToDocument,
- int /* thread_id */,
- int /* provider_id */,
- base::string16 /* message */,
- std::vector<int> /* sent_message_port_ids */,
- std::vector<int> /* new_routing_ids */)
+IPC_MESSAGE_CONTROL5(
+ ServiceWorkerMsg_MessageToDocument,
+ int /* thread_id */,
+ int /* provider_id */,
+ base::string16 /* message */,
+ std::vector<content::TransferredMessagePort> /* sent_message_ports */,
+ std::vector<int> /* new_routing_ids */)
// Sent via EmbeddedWorker to dispatch events.
-IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_InstallEvent,
- int /* request_id */,
- int /* active_version_id */)
+IPC_MESSAGE_CONTROL1(ServiceWorkerMsg_InstallEvent,
+ int /* request_id */)
IPC_MESSAGE_CONTROL1(ServiceWorkerMsg_ActivateEvent,
int /* request_id */)
IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_FetchEvent,
@@ -352,6 +382,10 @@ IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_FetchEvent,
content::ServiceWorkerFetchRequest)
IPC_MESSAGE_CONTROL1(ServiceWorkerMsg_SyncEvent,
int /* request_id */)
+IPC_MESSAGE_CONTROL3(ServiceWorkerMsg_NotificationClickEvent,
+ int /* request_id */,
+ int64_t /* persistent_notification_id */,
+ content::PlatformNotificationData /* notification_data */)
IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_PushEvent,
int /* request_id */,
std::string /* data */)
@@ -360,66 +394,48 @@ IPC_MESSAGE_CONTROL4(ServiceWorkerMsg_GeofencingEvent,
blink::WebGeofencingEventType /* event_type */,
std::string /* region_id */,
blink::WebCircularGeofencingRegion /* region */)
-IPC_MESSAGE_CONTROL3(ServiceWorkerMsg_MessageToWorker,
- base::string16 /* message */,
- std::vector<int> /* sent_message_port_ids */,
- std::vector<int> /* new_routing_ids */)
-
-// Sent via EmbeddedWorker as a response of GetClientDocuments.
-IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_DidGetClientDocuments,
+IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_CrossOriginConnectEvent,
int /* request_id */,
- std::vector<int> /* client_ids */)
-
-// Sent via EmbeddedWorker at successful completion of CacheStorage operations.
-IPC_MESSAGE_CONTROL1(ServiceWorkerMsg_CacheStorageHasSuccess,
+ content::NavigatorConnectClient /* client */)
+IPC_MESSAGE_CONTROL3(
+ ServiceWorkerMsg_MessageToWorker,
+ base::string16 /* message */,
+ std::vector<content::TransferredMessagePort> /* sent_message_ports */,
+ std::vector<int> /* new_routing_ids */)
+IPC_MESSAGE_CONTROL4(
+ ServiceWorkerMsg_CrossOriginMessageToWorker,
+ content::NavigatorConnectClient /* client */,
+ base::string16 /* message */,
+ std::vector<content::TransferredMessagePort> /* sent_message_ports */,
+ std::vector<int> /* new_routing_ids */)
+IPC_MESSAGE_CONTROL1(ServiceWorkerMsg_DidSkipWaiting,
int /* request_id */)
-IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_CacheStorageOpenSuccess,
- int /* request_id */,
- int /* fetch_store_id */)
-IPC_MESSAGE_CONTROL1(ServiceWorkerMsg_CacheStorageDeleteSuccess,
+IPC_MESSAGE_CONTROL1(ServiceWorkerMsg_DidClaimClients,
int /* request_id */)
-IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_CacheStorageKeysSuccess,
+IPC_MESSAGE_CONTROL3(ServiceWorkerMsg_ClaimClientsError,
int /* request_id */,
- std::vector<base::string16> /* keys */)
+ blink::WebServiceWorkerError::ErrorType /* code */,
+ base::string16 /* message */)
-// Sent via EmbeddedWorker at erroneous completion of CacheStorage operations.
-IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_CacheStorageHasError,
- int /* request_id */,
- blink::WebServiceWorkerCacheError /* reason */)
-IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_CacheStorageOpenError,
- int /* request_id */,
- blink::WebServiceWorkerCacheError /* reason */)
-IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_CacheStorageDeleteError,
- int /* request_id */,
- blink::WebServiceWorkerCacheError /* reason */)
-IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_CacheStorageKeysError,
- int /* request_id */,
- blink::WebServiceWorkerCacheError /* reason */)
+// Sent via EmbeddedWorker to Ping the worker, expecting a Pong in response.
+IPC_MESSAGE_CONTROL0(ServiceWorkerMsg_Ping)
-// Sent via EmbeddedWorker at successful completion of Cache operations.
-IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_CacheMatchSuccess,
- int /* request_id */,
- content::ServiceWorkerResponse)
-IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_CacheMatchAllSuccess,
- int /* request_id */,
- std::vector<content::ServiceWorkerResponse>)
-IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_CacheKeysSuccess,
+// Sent via EmbeddedWorker as a response of GetClients.
+IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_DidGetClients,
int /* request_id */,
- std::vector<content::ServiceWorkerFetchRequest>)
-IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_CacheBatchSuccess,
- int /* request_id */,
- std::vector<content::ServiceWorkerResponse>)
+ std::vector<content::ServiceWorkerClientInfo>)
-// Sent via EmbeddedWorker at erroneous completion of CacheStorage operations.
-IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_CacheMatchError,
- int /* request_id */,
- blink::WebServiceWorkerCacheError)
-IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_CacheMatchAllError,
+// Sent via EmbeddedWorker as a response of OpenWindow.
+IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_OpenWindowResponse,
int /* request_id */,
- blink::WebServiceWorkerCacheError)
-IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_CacheKeysError,
+ content::ServiceWorkerClientInfo /* client */)
+
+// Sent via EmbeddedWorker as an error response of OpenWindow.
+IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_OpenWindowError,
int /* request_id */,
- blink::WebServiceWorkerCacheError)
-IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_CacheBatchError,
+ std::string /* message */ )
+
+// Sent via EmbeddedWorker as a response of FocusClient.
+IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_FocusClientResponse,
int /* request_id */,
- blink::WebServiceWorkerCacheError)
+ content::ServiceWorkerClientInfo /* client */)
diff --git a/chromium/content/common/service_worker/service_worker_status_code.cc b/chromium/content/common/service_worker/service_worker_status_code.cc
index a402a8a73ef..51a58b0213b 100644
--- a/chromium/content/common/service_worker/service_worker_status_code.cc
+++ b/chromium/content/common/service_worker/service_worker_status_code.cc
@@ -34,6 +34,19 @@ const char* ServiceWorkerStatusToString(ServiceWorkerStatusCode status) {
return "Operation failed by network issue";
case SERVICE_WORKER_ERROR_SECURITY:
return "Operation failed by security issue";
+ case SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED:
+ return "ServiceWorker failed to handle event (event.waitUntil "
+ "Promise rejected)";
+ case SERVICE_WORKER_ERROR_STATE:
+ return "The ServiceWorker state was not valid";
+ case SERVICE_WORKER_ERROR_TIMEOUT:
+ return "The ServiceWorker timed out";
+ case SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED:
+ return "ServiceWorker script evaluation failed";
+ case SERVICE_WORKER_ERROR_DISK_CACHE:
+ return "Disk cache error";
+ case SERVICE_WORKER_ERROR_MAX_VALUE:
+ NOTREACHED();
}
NOTREACHED();
return "";
diff --git a/chromium/content/common/service_worker/service_worker_status_code.h b/chromium/content/common/service_worker/service_worker_status_code.h
index 953d533fc3c..88c06098871 100644
--- a/chromium/content/common/service_worker/service_worker_status_code.h
+++ b/chromium/content/common/service_worker/service_worker_status_code.h
@@ -10,6 +10,8 @@
namespace content {
// Generic service worker operation statuses.
+// This enum is used in UMA histograms, so don't change the order or remove
+// entries.
enum ServiceWorkerStatusCode {
// Operation succeeded.
SERVICE_WORKER_OK,
@@ -48,6 +50,23 @@ enum ServiceWorkerStatusCode {
// Operation is failed by security issue.
SERVICE_WORKER_ERROR_SECURITY,
+
+ // Event handling failed (event.waitUntil Promise rejected).
+ SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED,
+
+ // An error triggered by invalid worker state.
+ SERVICE_WORKER_ERROR_STATE,
+
+ // The Service Worker took too long to finish a task.
+ SERVICE_WORKER_ERROR_TIMEOUT,
+
+ // An error occurred during initial script evaluation.
+ SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED,
+
+ // Generic error to indicate failure to read/write the disk cache.
+ SERVICE_WORKER_ERROR_DISK_CACHE,
+
+ SERVICE_WORKER_ERROR_MAX_VALUE
};
CONTENT_EXPORT const char* ServiceWorkerStatusToString(
diff --git a/chromium/content/common/service_worker/service_worker_types.cc b/chromium/content/common/service_worker/service_worker_types.cc
index dec264e6414..c6be99d9c7c 100644
--- a/chromium/content/common/service_worker/service_worker_types.cc
+++ b/chromium/content/common/service_worker/service_worker_types.cc
@@ -6,6 +6,15 @@
namespace content {
+const char kServiceWorkerRegisterErrorPrefix[] =
+ "Failed to register a ServiceWorker: ";
+const char kServiceWorkerUnregisterErrorPrefix[] =
+ "Failed to unregister a ServiceWorkerRegistration: ";
+const char kServiceWorkerGetRegistrationErrorPrefix[] =
+ "Failed to get a ServiceWorkerRegistration: ";
+const char kFetchScriptError[] =
+ "An unknown error occurred when fetching the script.";
+
ServiceWorkerFetchRequest::ServiceWorkerFetchRequest()
: mode(FETCH_REQUEST_MODE_NO_CORS),
request_context_type(REQUEST_CONTEXT_TYPE_UNSPECIFIED),
@@ -19,7 +28,7 @@ ServiceWorkerFetchRequest::ServiceWorkerFetchRequest(
const GURL& url,
const std::string& method,
const ServiceWorkerHeaderMap& headers,
- const GURL& referrer,
+ const Referrer& referrer,
bool is_reload)
: mode(FETCH_REQUEST_MODE_NO_CORS),
request_context_type(REQUEST_CONTEXT_TYPE_UNSPECIFIED),
@@ -48,26 +57,20 @@ ServiceWorkerResponse::ServiceWorkerResponse(
blink::WebServiceWorkerResponseType response_type,
const ServiceWorkerHeaderMap& headers,
const std::string& blob_uuid,
- uint64 blob_size)
+ uint64 blob_size,
+ const GURL& stream_url)
: url(url),
status_code(status_code),
status_text(status_text),
response_type(response_type),
headers(headers),
blob_uuid(blob_uuid),
- blob_size(blob_size) {
+ blob_size(blob_size),
+ stream_url(stream_url) {
}
ServiceWorkerResponse::~ServiceWorkerResponse() {}
-ServiceWorkerCacheQueryParams::ServiceWorkerCacheQueryParams()
- : ignore_search(false),
- ignore_method(false),
- ignore_vary(false),
- prefix_match(false) {}
-
-ServiceWorkerBatchOperation::ServiceWorkerBatchOperation() {}
-
ServiceWorkerObjectInfo::ServiceWorkerObjectInfo()
: handle_id(kInvalidServiceWorkerHandleId),
state(blink::WebServiceWorkerStateUnknown),
@@ -78,4 +81,9 @@ ServiceWorkerRegistrationObjectInfo::ServiceWorkerRegistrationObjectInfo()
registration_id(kInvalidServiceWorkerRegistrationId) {
}
+ServiceWorkerClientQueryOptions::ServiceWorkerClientQueryOptions()
+ : client_type(blink::WebServiceWorkerClientTypeWindow),
+ include_uncontrolled(false) {
+}
+
} // namespace content
diff --git a/chromium/content/common/service_worker/service_worker_types.h b/chromium/content/common/service_worker/service_worker_types.h
index d0ef45cbc0c..6e235a77a4b 100644
--- a/chromium/content/common/service_worker/service_worker_types.h
+++ b/chromium/content/common/service_worker/service_worker_types.h
@@ -11,8 +11,11 @@
#include "base/basictypes.h"
#include "base/strings/string_util.h"
#include "content/common/content_export.h"
+#include "content/public/common/referrer.h"
#include "content/public/common/request_context_frame_type.h"
#include "content/public/common/request_context_type.h"
+#include "third_party/WebKit/public/platform/WebPageVisibilityState.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerClientType.h"
#include "third_party/WebKit/public/platform/WebServiceWorkerResponseType.h"
#include "third_party/WebKit/public/platform/WebServiceWorkerState.h"
#include "url/gurl.h"
@@ -22,11 +25,21 @@
namespace content {
+// Indicates the document main thread ID in the child process. This is used for
+// messaging between the browser process and the child process.
+static const int kDocumentMainThreadId = 0;
+
// Indicates invalid request ID (i.e. the sender does not expect it gets
// response for the message) for messaging between browser process
// and embedded worker.
static const int kInvalidServiceWorkerRequestId = -1;
+// Constants for error messages.
+extern const char kServiceWorkerRegisterErrorPrefix[];
+extern const char kServiceWorkerUnregisterErrorPrefix[];
+extern const char kServiceWorkerGetRegistrationErrorPrefix[];
+extern const char kFetchScriptError[];
+
// Constants for invalid identifiers.
static const int kInvalidServiceWorkerHandleId = -1;
static const int kInvalidServiceWorkerRegistrationHandleId = -1;
@@ -36,6 +49,22 @@ static const int64 kInvalidServiceWorkerVersionId = -1;
static const int64 kInvalidServiceWorkerResourceId = -1;
static const int64 kInvalidServiceWorkerResponseId = -1;
static const int kInvalidEmbeddedWorkerThreadId = -1;
+static const int kInvalidServiceWorkerClientId = 0;
+
+// ServiceWorker provider type.
+enum ServiceWorkerProviderType {
+ SERVICE_WORKER_PROVIDER_UNKNOWN,
+
+ // For ServiceWorker clients.
+ SERVICE_WORKER_PROVIDER_FOR_WINDOW,
+ SERVICE_WORKER_PROVIDER_FOR_WORKER,
+ SERVICE_WORKER_PROVIDER_FOR_SHARED_WORKER,
+
+ // For ServiceWorkers.
+ SERVICE_WORKER_PROVIDER_FOR_CONTROLLER,
+
+ SERVICE_WORKER_PROVIDER_TYPE_LAST = SERVICE_WORKER_PROVIDER_FOR_CONTROLLER
+};
enum FetchRequestMode {
FETCH_REQUEST_MODE_SAME_ORIGIN,
@@ -76,7 +105,7 @@ struct CONTENT_EXPORT ServiceWorkerFetchRequest {
ServiceWorkerFetchRequest(const GURL& url,
const std::string& method,
const ServiceWorkerHeaderMap& headers,
- const GURL& referrer,
+ const Referrer& referrer,
bool is_reload);
~ServiceWorkerFetchRequest();
@@ -88,7 +117,7 @@ struct CONTENT_EXPORT ServiceWorkerFetchRequest {
ServiceWorkerHeaderMap headers;
std::string blob_uuid;
uint64 blob_size;
- GURL referrer;
+ Referrer referrer;
FetchCredentialsMode credentials_mode;
bool is_reload;
};
@@ -102,7 +131,8 @@ struct CONTENT_EXPORT ServiceWorkerResponse {
blink::WebServiceWorkerResponseType response_type,
const ServiceWorkerHeaderMap& headers,
const std::string& blob_uuid,
- uint64 blob_size);
+ uint64 blob_size,
+ const GURL& stream_url);
~ServiceWorkerResponse();
GURL url;
@@ -112,48 +142,19 @@ struct CONTENT_EXPORT ServiceWorkerResponse {
ServiceWorkerHeaderMap headers;
std::string blob_uuid;
uint64 blob_size;
-};
-
-// Controls how requests are matched in the Cache API.
-struct CONTENT_EXPORT ServiceWorkerCacheQueryParams {
- ServiceWorkerCacheQueryParams();
-
- bool ignore_search;
- bool ignore_method;
- bool ignore_vary;
- bool prefix_match;
-};
-
-// The type of a single batch operation in the Cache API.
-enum ServiceWorkerCacheOperationType {
- SERVICE_WORKER_CACHE_OPERATION_TYPE_UNDEFINED,
- SERVICE_WORKER_CACHE_OPERATION_TYPE_PUT,
- SERVICE_WORKER_CACHE_OPERATION_TYPE_DELETE,
- SERVICE_WORKER_CACHE_OPERATION_TYPE_LAST =
- SERVICE_WORKER_CACHE_OPERATION_TYPE_DELETE
-};
-
-// A single batch operation for the Cache API.
-struct CONTENT_EXPORT ServiceWorkerBatchOperation {
- ServiceWorkerBatchOperation();
-
- ServiceWorkerCacheOperationType operation_type;
- ServiceWorkerFetchRequest request;
- ServiceWorkerResponse response;
- ServiceWorkerCacheQueryParams match_params;
+ GURL stream_url;
};
// Represents initialization info for a WebServiceWorker object.
struct CONTENT_EXPORT ServiceWorkerObjectInfo {
ServiceWorkerObjectInfo();
int handle_id;
- GURL scope;
GURL url;
blink::WebServiceWorkerState state;
int64 version_id;
};
-struct ServiceWorkerRegistrationObjectInfo {
+struct CONTENT_EXPORT ServiceWorkerRegistrationObjectInfo {
ServiceWorkerRegistrationObjectInfo();
int handle_id;
GURL scope;
@@ -190,6 +191,12 @@ class ChangedVersionAttributesMask {
int changed_;
};
+struct ServiceWorkerClientQueryOptions {
+ ServiceWorkerClientQueryOptions();
+ blink::WebServiceWorkerClientType client_type;
+ bool include_uncontrolled;
+};
+
} // namespace content
#endif // CONTENT_COMMON_SERVICE_WORKER_SERVICE_WORKER_TYPES_H_
diff --git a/chromium/content/common/set_process_title.cc b/chromium/content/common/set_process_title.cc
index fdbf06cd0d8..74651ca6c3e 100644
--- a/chromium/content/common/set_process_title.cc
+++ b/chromium/content/common/set_process_title.cc
@@ -70,7 +70,8 @@ void SetProcessTitleFromCommandLine(const char** main_argv) {
}
#endif // defined(OS_LINUX)
- const CommandLine* command_line = CommandLine::ForCurrentProcess();
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
for (size_t i = 1; i < command_line->argv().size(); ++i) {
if (!title.empty())
title += " ";
diff --git a/chromium/content/common/shareable_file_reference_unittest.cc b/chromium/content/common/shareable_file_reference_unittest.cc
deleted file mode 100644
index 5e697b9eb24..00000000000
--- a/chromium/content/common/shareable_file_reference_unittest.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "storage/common/blob/shareable_file_reference.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 "testing/gtest/include/gtest/gtest.h"
-
-using storage::ShareableFileReference;
-
-namespace content {
-
-TEST(ShareableFileReferenceTest, TestReferences) {
- base::MessageLoop message_loop;
- scoped_refptr<base::MessageLoopProxy> loop_proxy =
- base::MessageLoopProxy::current();
- base::ScopedTempDir temp_dir;
- ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
-
- // Create a file.
- base::FilePath file;
- base::CreateTemporaryFileInDir(temp_dir.path(), &file);
- EXPECT_TRUE(base::PathExists(file));
-
- // Create a first reference to that file.
- scoped_refptr<ShareableFileReference> reference1;
- reference1 = ShareableFileReference::Get(file);
- EXPECT_FALSE(reference1.get());
- reference1 = ShareableFileReference::GetOrCreate(
- file, ShareableFileReference::DELETE_ON_FINAL_RELEASE, loop_proxy.get());
- EXPECT_TRUE(reference1.get());
- EXPECT_TRUE(file == reference1->path());
-
- // Get a second reference to that file.
- scoped_refptr<ShareableFileReference> reference2;
- reference2 = ShareableFileReference::Get(file);
- EXPECT_EQ(reference1.get(), reference2.get());
- reference2 = ShareableFileReference::GetOrCreate(
- file, ShareableFileReference::DELETE_ON_FINAL_RELEASE, loop_proxy.get());
- EXPECT_EQ(reference1.get(), reference2.get());
-
- // Drop the first reference, the file and reference should still be there.
- reference1 = NULL;
- EXPECT_TRUE(ShareableFileReference::Get(file).get());
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(base::PathExists(file));
-
- // Drop the second reference, the file and reference should get deleted.
- reference2 = NULL;
- EXPECT_FALSE(ShareableFileReference::Get(file).get());
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(base::PathExists(file));
-
- // TODO(michaeln): add a test for files that aren't deletable behavior.
-}
-
-} // namespace content
diff --git a/chromium/content/common/speech_recognition_messages.h b/chromium/content/common/speech_recognition_messages.h
index 80eb7f74d2d..7ad6aee1363 100644
--- a/chromium/content/common/speech_recognition_messages.h
+++ b/chromium/content/common/speech_recognition_messages.h
@@ -14,7 +14,7 @@
#include "ipc/ipc_message_macros.h"
#include "ipc/ipc_param_traits.h"
#include "media/audio/audio_parameters.h"
-#include "ui/gfx/rect.h"
+#include "ui/gfx/geometry/rect.h"
#define IPC_MESSAGE_START SpeechRecognitionMsgStart
diff --git a/chromium/content/common/ssl_status_serialization.cc b/chromium/content/common/ssl_status_serialization.cc
index d10b1b8a7e4..0e2e4d2d353 100644
--- a/chromium/content/common/ssl_status_serialization.cc
+++ b/chromium/content/common/ssl_status_serialization.cc
@@ -54,18 +54,17 @@ bool DeserializeSecurityInfo(
Pickle pickle(state.data(), static_cast<int>(state.size()));
PickleIterator iter(pickle);
int num_scts_to_read;
- if (!pickle.ReadInt(&iter, cert_id) ||
- !pickle.ReadUInt32(&iter, cert_status) ||
- !pickle.ReadInt(&iter, security_bits) ||
- !pickle.ReadInt(&iter, ssl_connection_status) ||
- !pickle.ReadInt(&iter, &num_scts_to_read))
+ if (!iter.ReadInt(cert_id) ||
+ !iter.ReadUInt32(cert_status) ||
+ !iter.ReadInt(security_bits) ||
+ !iter.ReadInt(ssl_connection_status) ||
+ !iter.ReadInt(&num_scts_to_read))
return false;
for (; num_scts_to_read > 0; --num_scts_to_read) {
int id;
uint16 status;
- if (!pickle.ReadInt(&iter, &id) ||
- !pickle.ReadUInt16(&iter, &status))
+ if (!iter.ReadInt(&id) || !iter.ReadUInt16(&status))
return false;
signed_certificate_timestamp_ids->push_back(
SignedCertificateTimestampIDAndStatus(
diff --git a/chromium/content/common/swapped_out_messages.cc b/chromium/content/common/swapped_out_messages.cc
index 6c872d43f1a..de5da6490ea 100644
--- a/chromium/content/common/swapped_out_messages.cc
+++ b/chromium/content/common/swapped_out_messages.cc
@@ -9,6 +9,7 @@
#include "content/common/input_messages.h"
#include "content/common/view_messages.h"
#include "content/public/common/content_client.h"
+#include "content/shell/common/shell_messages.h"
namespace content {
@@ -24,7 +25,6 @@ bool SwappedOutMessages::CanSendWhileSwappedOut(const IPC::Message* msg) {
case FrameHostMsg_OpenURL::ID:
case ViewHostMsg_Focus::ID:
// Handled by RenderViewHost.
- case ViewHostMsg_RenderProcessGone::ID:
case ViewHostMsg_ClosePage_ACK::ID:
case ViewHostMsg_SwapCompositorFrame::ID:
// Handled by WorkerMessageFilter (or by SharedWorkerMessageFilter when
@@ -32,10 +32,10 @@ bool SwappedOutMessages::CanSendWhileSwappedOut(const IPC::Message* msg) {
case ViewHostMsg_DocumentDetached::ID:
// Allow cross-process JavaScript calls.
case ViewHostMsg_RouteCloseEvent::ID:
- case ViewHostMsg_RouteMessageEvent::ID:
// Handled by RenderFrameHost.
case FrameHostMsg_BeforeUnload_ACK::ID:
case FrameHostMsg_SwapOut_ACK::ID:
+ case FrameHostMsg_RenderProcessGone::ID:
// Frame detach must occur after the RenderView has swapped out.
case FrameHostMsg_Detach::ID:
case FrameHostMsg_DomOperationResponse::ID:
@@ -47,6 +47,8 @@ bool SwappedOutMessages::CanSendWhileSwappedOut(const IPC::Message* msg) {
// The browser should always have an accurate mirror of the renderer's
// notion of the current page id.
case FrameHostMsg_DidAssignPageId::ID:
+ // Used in layout tests; handled in BlinkTestController.
+ case ShellViewHostMsg_PrintMessage::ID:
return true;
default:
break;
diff --git a/chromium/content/common/text_input_client_messages.h b/chromium/content/common/text_input_client_messages.h
index 4c8fb49384e..860bf10911b 100644
--- a/chromium/content/common/text_input_client_messages.h
+++ b/chromium/content/common/text_input_client_messages.h
@@ -5,8 +5,8 @@
// Multiply-included message file, hence no include guard
#include "ipc/ipc_message_macros.h"
+#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/range/range.h"
-#include "ui/gfx/rect.h"
#if defined(OS_MACOSX)
#include "content/common/mac/attributed_string_coder.h"
diff --git a/chromium/content/common/user_agent.cc b/chromium/content/common/user_agent.cc
index 1176c488d3d..f3e113da7c1 100644
--- a/chromium/content/common/user_agent.cc
+++ b/chromium/content/common/user_agent.cc
@@ -156,8 +156,8 @@ std::string BuildOSCpuInfo() {
return os_cpu;
}
-std::string BuildUserAgentFromProduct(const std::string& product) {
- const char kUserAgentPlatform[] =
+std::string getUserAgentPlatform() {
+ return
#if defined(OS_WIN)
"";
#elif defined(OS_MACOSX)
@@ -169,10 +169,28 @@ std::string BuildUserAgentFromProduct(const std::string& product) {
#else
"Unknown; ";
#endif
+}
+
+std::string BuildUserAgentFromProduct(const std::string& product) {
+ std::string os_info;
+ base::StringAppendF(
+ &os_info,
+ "%s%s",
+ getUserAgentPlatform().c_str(),
+ BuildOSCpuInfo().c_str());
+ return BuildUserAgentFromOSAndProduct(os_info, product);
+}
+std::string BuildUserAgentFromProductAndExtraOSInfo(
+ const std::string& product,
+ const std::string& extra_os_info) {
std::string os_info;
base::StringAppendF(
- &os_info, "%s%s", kUserAgentPlatform, BuildOSCpuInfo().c_str());
+ &os_info,
+ "%s%s%s",
+ getUserAgentPlatform().c_str(),
+ BuildOSCpuInfo().c_str(),
+ extra_os_info.c_str());
return BuildUserAgentFromOSAndProduct(os_info, product);
}
diff --git a/chromium/content/common/view_message_enums.h b/chromium/content/common/view_message_enums.h
index 4d3d193ebcf..ddff44a710e 100644
--- a/chromium/content/common/view_message_enums.h
+++ b/chromium/content/common/view_message_enums.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_COMMON_VIEW_MESSAGES_ENUMS_H_
-#define CONTENT_COMMON_VIEW_MESSAGES_ENUMS_H_
+#ifndef CONTENT_COMMON_VIEW_MESSAGE_ENUMS_H_
+#define CONTENT_COMMON_VIEW_MESSAGE_ENUMS_H_
#include "ipc/ipc_message_macros.h"
@@ -22,4 +22,4 @@ struct ViewHostMsg_UpdateRect_Flags {
}
};
-#endif // CONTENT_COMMON_VIEW_MESSAGES_ENUMS_H_
+#endif // CONTENT_COMMON_VIEW_MESSAGE_ENUMS_H_
diff --git a/chromium/content/common/view_messages.h b/chromium/content/common/view_messages.h
index 426ac1faa12..448a65fd0bc 100644
--- a/chromium/content/common/view_messages.h
+++ b/chromium/content/common/view_messages.h
@@ -13,8 +13,8 @@
#include "cc/output/compositor_frame_ack.h"
#include "content/common/content_export.h"
#include "content/common/content_param_traits.h"
-#include "content/common/cookie_data.h"
#include "content/common/date_time_suggestion.h"
+#include "content/common/frame_replication_state.h"
#include "content/common/navigation_gesture.h"
#include "content/common/view_message_enums.h"
#include "content/common/webplugin_geometry.h"
@@ -23,6 +23,7 @@
#include "content/public/common/file_chooser_file_info.h"
#include "content/public/common/file_chooser_params.h"
#include "content/public/common/menu_item.h"
+#include "content/public/common/message_port_types.h"
#include "content/public/common/page_state.h"
#include "content/public/common/page_zoom.h"
#include "content/public/common/referrer.h"
@@ -37,9 +38,12 @@
#include "media/base/channel_layout.h"
#include "media/base/media_log_event.h"
#include "net/base/network_change_notifier.h"
+#include "third_party/WebKit/public/platform/WebDisplayMode.h"
#include "third_party/WebKit/public/platform/WebFloatPoint.h"
#include "third_party/WebKit/public/platform/WebFloatRect.h"
#include "third_party/WebKit/public/platform/WebScreenInfo.h"
+#include "third_party/WebKit/public/platform/WebScreenOrientationType.h"
+#include "third_party/WebKit/public/web/WebDeviceEmulationParams.h"
#include "third_party/WebKit/public/web/WebFindOptions.h"
#include "third_party/WebKit/public/web/WebMediaPlayerAction.h"
#include "third_party/WebKit/public/web/WebPluginAction.h"
@@ -49,13 +53,13 @@
#include "ui/base/ime/text_input_mode.h"
#include "ui/base/ime/text_input_type.h"
#include "ui/base/ui_base_types.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/geometry/vector2d.h"
+#include "ui/gfx/geometry/vector2d_f.h"
#include "ui/gfx/ipc/gfx_param_traits.h"
-#include "ui/gfx/point.h"
#include "ui/gfx/range/range.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/rect_f.h"
-#include "ui/gfx/vector2d.h"
-#include "ui/gfx/vector2d_f.h"
#if defined(OS_MACOSX)
#include "content/common/mac/font_descriptor.h"
@@ -71,15 +75,23 @@
#define IPC_MESSAGE_START ViewMsgStart
+IPC_ENUM_TRAITS_MAX_VALUE(blink::WebDeviceEmulationParams::ScreenPosition,
+ blink::WebDeviceEmulationParams::ScreenPositionLast)
IPC_ENUM_TRAITS_MAX_VALUE(blink::WebMediaPlayerAction::Type,
blink::WebMediaPlayerAction::Type::TypeLast)
IPC_ENUM_TRAITS_MAX_VALUE(blink::WebPluginAction::Type,
blink::WebPluginAction::Type::TypeLast)
IPC_ENUM_TRAITS_MAX_VALUE(blink::WebPopupType,
blink::WebPopupType::WebPopupTypeLast)
+// TODO(dcheng): Update WebScreenOrientationType to have a "Last" enum member.
+IPC_ENUM_TRAITS_MIN_MAX_VALUE(blink::WebScreenOrientationType,
+ blink::WebScreenOrientationUndefined,
+ blink::WebScreenOrientationLandscapeSecondary)
IPC_ENUM_TRAITS_MAX_VALUE(blink::WebTextDirection,
blink::WebTextDirection::WebTextDirectionLast)
-IPC_ENUM_TRAITS(WindowContainerType)
+IPC_ENUM_TRAITS_MAX_VALUE(blink::WebDisplayMode,
+ blink::WebDisplayMode::WebDisplayModeLast)
+IPC_ENUM_TRAITS_MAX_VALUE(WindowContainerType, WINDOW_CONTAINER_TYPE_MAX_VALUE)
IPC_ENUM_TRAITS(content::FaviconURL::IconType)
IPC_ENUM_TRAITS(content::FileChooserParams::Mode)
IPC_ENUM_TRAITS(content::MenuItem::Type)
@@ -88,8 +100,10 @@ IPC_ENUM_TRAITS_MAX_VALUE(content::NavigationGesture,
IPC_ENUM_TRAITS_MIN_MAX_VALUE(content::PageZoom,
content::PageZoom::PAGE_ZOOM_OUT,
content::PageZoom::PAGE_ZOOM_IN)
-IPC_ENUM_TRAITS(gfx::FontRenderParams::Hinting)
-IPC_ENUM_TRAITS(gfx::FontRenderParams::SubpixelRendering)
+IPC_ENUM_TRAITS_MAX_VALUE(gfx::FontRenderParams::Hinting,
+ gfx::FontRenderParams::HINTING_MAX)
+IPC_ENUM_TRAITS_MAX_VALUE(gfx::FontRenderParams::SubpixelRendering,
+ gfx::FontRenderParams::SUBPIXEL_RENDERING_MAX)
IPC_ENUM_TRAITS_MAX_VALUE(content::TapMultipleTargetsStrategy,
content::TAP_MULTIPLE_TARGETS_STRATEGY_MAX)
IPC_ENUM_TRAITS_MAX_VALUE(content::StopFindAction,
@@ -100,7 +114,7 @@ IPC_ENUM_TRAITS_MAX_VALUE(media::ChannelLayout, media::CHANNEL_LAYOUT_MAX - 1)
IPC_ENUM_TRAITS_MAX_VALUE(media::MediaLogEvent::Type,
media::MediaLogEvent::TYPE_LAST)
IPC_ENUM_TRAITS_MAX_VALUE(ui::TextInputMode, ui::TEXT_INPUT_MODE_MAX)
-IPC_ENUM_TRAITS(ui::TextInputType)
+IPC_ENUM_TRAITS_MAX_VALUE(ui::TextInputType, ui::TEXT_INPUT_TYPE_MAX)
#if defined(OS_MACOSX)
IPC_STRUCT_TRAITS_BEGIN(FontDescriptor)
@@ -137,6 +151,20 @@ IPC_STRUCT_TRAITS_BEGIN(blink::WebFloatRect)
IPC_STRUCT_TRAITS_MEMBER(height)
IPC_STRUCT_TRAITS_END()
+IPC_STRUCT_TRAITS_BEGIN(blink::WebSize)
+ IPC_STRUCT_TRAITS_MEMBER(width)
+ IPC_STRUCT_TRAITS_MEMBER(height)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(blink::WebDeviceEmulationParams)
+ IPC_STRUCT_TRAITS_MEMBER(screenPosition)
+ IPC_STRUCT_TRAITS_MEMBER(deviceScaleFactor)
+ IPC_STRUCT_TRAITS_MEMBER(viewSize)
+ IPC_STRUCT_TRAITS_MEMBER(fitToView)
+ IPC_STRUCT_TRAITS_MEMBER(offset)
+ IPC_STRUCT_TRAITS_MEMBER(scale)
+IPC_STRUCT_TRAITS_END()
+
IPC_STRUCT_TRAITS_BEGIN(blink::WebScreenInfo)
IPC_STRUCT_TRAITS_MEMBER(deviceScaleFactor)
IPC_STRUCT_TRAITS_MEMBER(depth)
@@ -198,6 +226,7 @@ IPC_STRUCT_TRAITS_BEGIN(content::PepperRendererInstanceData)
IPC_STRUCT_TRAITS_MEMBER(render_frame_id)
IPC_STRUCT_TRAITS_MEMBER(document_url)
IPC_STRUCT_TRAITS_MEMBER(plugin_url)
+ IPC_STRUCT_TRAITS_MEMBER(is_potentially_secure_plugin_context)
IPC_STRUCT_TRAITS_END()
#endif
@@ -223,6 +252,7 @@ IPC_STRUCT_TRAITS_BEGIN(content::RendererPreferences)
IPC_STRUCT_TRAITS_MEMBER(use_custom_colors)
IPC_STRUCT_TRAITS_MEMBER(enable_referrers)
IPC_STRUCT_TRAITS_MEMBER(enable_do_not_track)
+ IPC_STRUCT_TRAITS_MEMBER(enable_webrtc_multiple_routes)
IPC_STRUCT_TRAITS_MEMBER(default_zoom_level)
IPC_STRUCT_TRAITS_MEMBER(user_agent_override)
IPC_STRUCT_TRAITS_MEMBER(accept_languages)
@@ -231,17 +261,24 @@ IPC_STRUCT_TRAITS_BEGIN(content::RendererPreferences)
IPC_STRUCT_TRAITS_MEMBER(disable_client_blocked_error_page)
IPC_STRUCT_TRAITS_MEMBER(plugin_fullscreen_allowed)
IPC_STRUCT_TRAITS_MEMBER(use_video_overlay_for_embedded_encrypted_video)
-IPC_STRUCT_TRAITS_END()
-
-IPC_STRUCT_TRAITS_BEGIN(content::CookieData)
- IPC_STRUCT_TRAITS_MEMBER(name)
- IPC_STRUCT_TRAITS_MEMBER(value)
- IPC_STRUCT_TRAITS_MEMBER(domain)
- IPC_STRUCT_TRAITS_MEMBER(path)
- IPC_STRUCT_TRAITS_MEMBER(expires)
- IPC_STRUCT_TRAITS_MEMBER(http_only)
- IPC_STRUCT_TRAITS_MEMBER(secure)
- IPC_STRUCT_TRAITS_MEMBER(session)
+ IPC_STRUCT_TRAITS_MEMBER(use_view_overlay_for_all_video)
+ IPC_STRUCT_TRAITS_MEMBER(network_contry_iso)
+#if defined(OS_WIN)
+ IPC_STRUCT_TRAITS_MEMBER(caption_font_family_name)
+ IPC_STRUCT_TRAITS_MEMBER(caption_font_height)
+ IPC_STRUCT_TRAITS_MEMBER(small_caption_font_family_name)
+ IPC_STRUCT_TRAITS_MEMBER(small_caption_font_height)
+ IPC_STRUCT_TRAITS_MEMBER(menu_font_family_name)
+ IPC_STRUCT_TRAITS_MEMBER(menu_font_height)
+ IPC_STRUCT_TRAITS_MEMBER(status_font_family_name)
+ IPC_STRUCT_TRAITS_MEMBER(status_font_height)
+ IPC_STRUCT_TRAITS_MEMBER(message_font_family_name)
+ IPC_STRUCT_TRAITS_MEMBER(message_font_height)
+ IPC_STRUCT_TRAITS_MEMBER(vertical_scroll_bar_width_in_dips)
+ IPC_STRUCT_TRAITS_MEMBER(horizontal_scroll_bar_height_in_dips)
+ IPC_STRUCT_TRAITS_MEMBER(arrow_bitmap_height_vertical_scroll_bar_in_dips)
+ IPC_STRUCT_TRAITS_MEMBER(arrow_bitmap_width_horizontal_scroll_bar_in_dips)
+#endif
IPC_STRUCT_TRAITS_END()
IPC_STRUCT_TRAITS_BEGIN(content::WebPluginGeometry)
@@ -413,6 +450,34 @@ IPC_STRUCT_BEGIN(ViewHostMsg_UpdateRect_Params)
IPC_STRUCT_MEMBER(int, flags)
IPC_STRUCT_END()
+IPC_STRUCT_BEGIN(ViewMsg_Resize_Params)
+ // Information about the screen (dpi, depth, etc..).
+ IPC_STRUCT_MEMBER(blink::WebScreenInfo, screen_info)
+ // The size of the renderer.
+ IPC_STRUCT_MEMBER(gfx::Size, new_size)
+ // The size of the view's backing surface in non-DPI-adjusted pixels.
+ IPC_STRUCT_MEMBER(gfx::Size, physical_backing_size)
+ // Whether or not Blink's viewport size should be shrunk by the height of the
+ // URL-bar (always false on platforms where URL-bar hiding isn't supported).
+ IPC_STRUCT_MEMBER(bool, top_controls_shrink_blink_size)
+ // The height of the top controls (always 0 on platforms where URL-bar hiding
+ // isn't supported).
+ IPC_STRUCT_MEMBER(float, top_controls_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
+ // DPI-adjusted pixels.
+ IPC_STRUCT_MEMBER(gfx::Size, visible_viewport_size)
+ // The resizer rect.
+ IPC_STRUCT_MEMBER(gfx::Rect, resizer_rect)
+ // Indicates whether tab-initiated fullscreen was granted.
+ IPC_STRUCT_MEMBER(bool, is_fullscreen_granted)
+ // The display mode.
+ IPC_STRUCT_MEMBER(blink::WebDisplayMode, display_mode)
+ // If set, requests the renderer to reply with a ViewHostMsg_UpdateRect
+ // with the ViewHostMsg_UpdateRect_Flags::IS_RESIZE_ACK bit set in flags.
+ IPC_STRUCT_MEMBER(bool, needs_resize_ack)
+IPC_STRUCT_END()
+
IPC_STRUCT_BEGIN(ViewMsg_New_Params)
// Renderer-wide preferences.
IPC_STRUCT_MEMBER(content::RendererPreferences, renderer_preferences)
@@ -442,6 +507,11 @@ IPC_STRUCT_BEGIN(ViewMsg_New_Params)
// Whether the RenderView should initially be swapped out.
IPC_STRUCT_MEMBER(bool, swapped_out)
+ // In --site-per-process mode, if this view is |swapped_out|, its main frame
+ // will become a RenderFrameProxy. |replicated_frame_state| is used to
+ // replicate information such as security origin to that RenderFrameProxy.
+ IPC_STRUCT_MEMBER(content::FrameReplicationState, replicated_frame_state)
+
// The ID of the proxy object for the main frame in this view. It is only
// used if |swapped_out| is true.
IPC_STRUCT_MEMBER(int32, proxy_routing_id)
@@ -460,31 +530,17 @@ IPC_STRUCT_BEGIN(ViewMsg_New_Params)
// to a view and are only updated by the renderer after this initial value.
IPC_STRUCT_MEMBER(int32, next_page_id)
- // The properties of the screen associated with the view.
- IPC_STRUCT_MEMBER(blink::WebScreenInfo, screen_info)
-IPC_STRUCT_END()
+ // The initial renderer size.
+ IPC_STRUCT_MEMBER(ViewMsg_Resize_Params, initial_size)
+
+ // Whether to enable auto-resize.
+ IPC_STRUCT_MEMBER(bool, enable_auto_resize)
-IPC_STRUCT_BEGIN(ViewMsg_PostMessage_Params)
- // Whether the data format is supplied as serialized script value, or as
- // a simple string. If it is a raw string, must be converted from string to a
- // WebSerializedScriptValue in renderer.
- IPC_STRUCT_MEMBER(bool, is_data_raw_string)
- // The serialized script value.
- IPC_STRUCT_MEMBER(base::string16, data)
- // When sent to the browser, this is the routing ID of the source frame in
- // the source process. The browser replaces it with the routing ID of the
- // equivalent (swapped out) frame in the destination process.
- IPC_STRUCT_MEMBER(int, source_routing_id)
-
- // The origin of the source frame.
- IPC_STRUCT_MEMBER(base::string16, source_origin)
-
- // The origin for the message's target.
- IPC_STRUCT_MEMBER(base::string16, target_origin)
-
- // Information about the MessagePorts this message contains.
- IPC_STRUCT_MEMBER(std::vector<int>, message_port_ids)
- IPC_STRUCT_MEMBER(std::vector<int>, new_routing_ids)
+ // The minimum size to layout the page if auto-resize is enabled.
+ IPC_STRUCT_MEMBER(gfx::Size, min_size)
+
+ // The maximum size to layout the page if auto-resize is enabled.
+ IPC_STRUCT_MEMBER(gfx::Size, max_size)
IPC_STRUCT_END()
// Messages sent from the browser to the renderer.
@@ -524,18 +580,12 @@ IPC_MESSAGE_ROUTED2(ViewMsg_UpdateVSyncParameters,
base::TimeTicks /* timebase */,
base::TimeDelta /* interval */)
-// Sent to the RenderView when a new tab is swapped into an existing
-// tab and the histories need to be merged. The existing tab has a history of
-// |merged_history_length| which precedes the history of the new tab. All
-// page_ids >= |minimum_page_id| in the new tab are appended to the history.
-//
-// For example, suppose the history of page_ids in the new tab's RenderView
-// is [4 7 8]. This is merged into an existing tab with 3 history items, and
-// all pages in the new tab with page_id >= 7 are to be preserved.
-// The resulting page history is [-1 -1 -1 7 8].
-IPC_MESSAGE_ROUTED2(ViewMsg_SetHistoryLengthAndPrune,
- int, /* merge_history_length */
- int32 /* minimum_page_id */)
+// Sent when the history is altered outside of navigation. The history list was
+// reset to |history_length| length, and the offset was reset to be
+// |history_offset|.
+IPC_MESSAGE_ROUTED2(ViewMsg_SetHistoryOffsetAndLength,
+ int /* history_offset */,
+ int /* history_length */)
// Tells the renderer to create a new view.
// This message is slightly different, the view it takes (via
@@ -557,23 +607,14 @@ IPC_MESSAGE_ROUTED1(ViewMsg_SetRendererPrefs,
IPC_MESSAGE_ROUTED1(ViewMsg_UpdateWebPreferences,
content::WebPreferences)
-// Informs the renderer that the timezone has changed.
-IPC_MESSAGE_CONTROL0(ViewMsg_TimezoneChange)
+// Informs the renderer that the timezone has changed along with a new
+// timezone ID.
+IPC_MESSAGE_CONTROL1(ViewMsg_TimezoneChange, std::string)
// Tells the render view to close.
// Expects a Close_ACK message when finished.
IPC_MESSAGE_ROUTED0(ViewMsg_Close)
-IPC_STRUCT_BEGIN(ViewMsg_Resize_Params)
- IPC_STRUCT_MEMBER(blink::WebScreenInfo, screen_info)
- IPC_STRUCT_MEMBER(gfx::Size, new_size)
- IPC_STRUCT_MEMBER(gfx::Size, physical_backing_size)
- IPC_STRUCT_MEMBER(float, top_controls_layout_height)
- IPC_STRUCT_MEMBER(gfx::Size, visible_viewport_size)
- IPC_STRUCT_MEMBER(gfx::Rect, resizer_rect)
- IPC_STRUCT_MEMBER(bool, is_fullscreen)
-IPC_STRUCT_END()
-
// Tells the render view to change its size. A ViewHostMsg_UpdateRect message
// is generated in response provided new_size is not empty and not equal to
// the view's current size. The generated ViewHostMsg_UpdateRect message will
@@ -582,6 +623,13 @@ IPC_STRUCT_END()
IPC_MESSAGE_ROUTED1(ViewMsg_Resize,
ViewMsg_Resize_Params /* params */)
+// Enables device emulation. See WebDeviceEmulationParams for description.
+IPC_MESSAGE_ROUTED1(ViewMsg_EnableDeviceEmulation,
+ blink::WebDeviceEmulationParams /* params */)
+
+// Disables device emulation, enabled previously by EnableDeviceEmulation.
+IPC_MESSAGE_ROUTED0(ViewMsg_DisableDeviceEmulation)
+
// Sent to inform the renderer of its screen device color profile. An empty
// profile tells the renderer use the default sRGB color profile.
IPC_MESSAGE_ROUTED1(ViewMsg_ColorProfile,
@@ -649,9 +697,8 @@ IPC_MESSAGE_ROUTED2(ViewMsg_PluginActionAt,
gfx::Point, /* location */
blink::WebPluginAction)
-// Posts a message from a frame in another process to the current renderer.
-IPC_MESSAGE_ROUTED1(ViewMsg_PostMessageEvent,
- ViewMsg_PostMessage_Params)
+// Resets the page scale for the current main frame to the default page scale.
+IPC_MESSAGE_ROUTED0(ViewMsg_ResetPageScale)
// Change the zoom level for the current main frame. If the level actually
// changes, a ViewHostMsg_DidZoomURL message will be sent back to the browser
@@ -857,12 +904,6 @@ IPC_MESSAGE_CONTROL1(ViewMsg_TempCrashWithData,
IPC_MESSAGE_ROUTED1(ViewMsg_ReleaseDisambiguationPopupBitmap,
cc::SharedBitmapId /* id */)
-// Notifies the renderer that a snapshot has been retrieved.
-IPC_MESSAGE_ROUTED3(ViewMsg_WindowSnapshotCompleted,
- int /* snapshot_id */,
- gfx::Size /* size */,
- std::vector<unsigned char> /* png */)
-
// Fetches complete rendered content of a web page as plain text.
IPC_MESSAGE_ROUTED0(ViewMsg_GetRenderedText)
@@ -905,10 +946,6 @@ IPC_MESSAGE_ROUTED3(ViewMsg_UpdateTopControlsState,
IPC_MESSAGE_ROUTED0(ViewMsg_ShowImeIfNeeded)
-// Sent by the browser when the renderer should generate a new frame.
-IPC_MESSAGE_ROUTED1(ViewMsg_BeginFrame,
- cc::BeginFrameArgs /* args */)
-
// Sent by the browser when an IME update that requires acknowledgement has been
// processed on the browser side.
IPC_MESSAGE_ROUTED0(ViewMsg_ImeEventAck)
@@ -950,6 +987,11 @@ IPC_MESSAGE_ROUTED2(ViewMsg_ReclaimCompositorResources,
uint32 /* output_surface_id */,
cc::CompositorFrameAck /* ack */)
+// Sent by browser to give renderer compositor a new namespace ID for any
+// SurfaceSequences it has to create.
+IPC_MESSAGE_ROUTED1(ViewMsg_SetSurfaceIdNamespace,
+ uint32_t /* surface_id_namespace */)
+
IPC_MESSAGE_ROUTED0(ViewMsg_SelectWordAroundCaret)
// Sent by the browser to ask the renderer to redraw.
@@ -958,9 +1000,19 @@ IPC_MESSAGE_ROUTED0(ViewMsg_SelectWordAroundCaret)
IPC_MESSAGE_ROUTED1(ViewMsg_ForceRedraw,
int /* request_id */)
+// Sent by the browser when the renderer should generate a new frame.
+IPC_MESSAGE_ROUTED1(ViewMsg_BeginFrame,
+ cc::BeginFrameArgs /* args */)
+
// -----------------------------------------------------------------------------
// Messages sent from the renderer to the browser.
+// Sent by renderer to request a ViewMsg_BeginFrame message for upcoming
+// display events. If |enabled| is true, the BeginFrame message will continue
+// to be be delivered until the notification is disabled.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_SetNeedsBeginFrames,
+ bool /* enabled */)
+
// Sent by the renderer when it is creating a new window. The browser creates
// a tab for it and responds with a ViewMsg_CreatingNew_ACK. If route_id is
// MSG_ROUTING_NONE, the view couldn't be created.
@@ -1005,39 +1057,28 @@ IPC_SYNC_MESSAGE_CONTROL0_2(ViewHostMsg_GetProcessMemorySizes,
// page/widget that was created by
// CreateWindow/CreateWidget/CreateFullscreenWidget. routing_id
// refers to the id that was returned from the Create message above.
-// The initial_position parameter is a rectangle in screen coordinates.
+// The initial_rect parameter is in screen coordinates.
//
// FUTURE: there will probably be flags here to control if the result is
// in a new window.
IPC_MESSAGE_ROUTED4(ViewHostMsg_ShowView,
int /* route_id */,
WindowOpenDisposition /* disposition */,
- gfx::Rect /* initial_pos */,
+ gfx::Rect /* initial_rect */,
bool /* opened_by_user_gesture */)
IPC_MESSAGE_ROUTED2(ViewHostMsg_ShowWidget,
int /* route_id */,
- gfx::Rect /* initial_pos */)
+ gfx::Rect /* initial_rect */)
// Message to show a full screen widget.
IPC_MESSAGE_ROUTED1(ViewHostMsg_ShowFullscreenWidget,
int /* route_id */)
-// This message is sent after ViewHostMsg_ShowView to cause the RenderView
-// to run in a modal fashion until it is closed.
-IPC_SYNC_MESSAGE_ROUTED1_0(ViewHostMsg_RunModal,
- int /* opener_id */)
-
// Indicates the renderer is ready in response to a ViewMsg_New or
// a ViewMsg_CreatingNew_ACK.
IPC_MESSAGE_ROUTED0(ViewHostMsg_RenderViewReady)
-// Indicates the renderer process is gone. This actually is sent by the
-// browser process to itself, but keeps the interface cleaner.
-IPC_MESSAGE_ROUTED2(ViewHostMsg_RenderProcessGone,
- int, /* this really is base::TerminationStatus */
- int /* exit_code */)
-
// Sent by the renderer process to request that the browser close the view.
// This corresponds to the window.close() API, and the browser may ignore
// this message. Otherwise, the browser will generates a ViewMsg_Close
@@ -1121,50 +1162,15 @@ IPC_MESSAGE_ROUTED0(ViewHostMsg_Focus)
IPC_MESSAGE_ROUTED0(ViewHostMsg_Blur)
// Message sent from renderer to the browser when focus changes inside the
-// webpage. The parameter says whether the newly focused element needs
+// webpage. The first parameter says whether the newly focused element needs
// keyboard input (true for textfields, text areas and content editable divs).
-IPC_MESSAGE_ROUTED1(ViewHostMsg_FocusedNodeChanged,
- bool /* is_editable_node */)
+// The second parameter is the node bounds relative to RenderWidgetHostView.
+IPC_MESSAGE_ROUTED2(ViewHostMsg_FocusedNodeChanged,
+ bool /* is_editable_node */,
+ gfx::Rect /* node_bounds */)
IPC_MESSAGE_ROUTED1(ViewHostMsg_SetCursor, content::WebCursor)
-// Used to set a cookie. The cookie is set asynchronously, but will be
-// available to a subsequent ViewHostMsg_GetCookies request.
-IPC_MESSAGE_CONTROL4(ViewHostMsg_SetCookie,
- int /* render_frame_id */,
- GURL /* url */,
- GURL /* first_party_for_cookies */,
- std::string /* cookie */)
-
-// Used to get cookies for the given URL. This may block waiting for a
-// previous SetCookie message to be processed.
-IPC_SYNC_MESSAGE_CONTROL3_1(ViewHostMsg_GetCookies,
- int /* render_frame_id */,
- GURL /* url */,
- GURL /* first_party_for_cookies */,
- std::string /* cookies */)
-
-// Used to get raw cookie information for the given URL. This may block
-// waiting for a previous SetCookie message to be processed.
-IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_GetRawCookies,
- GURL /* url */,
- GURL /* first_party_for_cookies */,
- std::vector<content::CookieData>
- /* raw_cookies */)
-
-// Used to delete cookie for the given URL and name
-IPC_SYNC_MESSAGE_CONTROL2_0(ViewHostMsg_DeleteCookie,
- GURL /* url */,
- std::string /* cookie_name */)
-
-// Used to check if cookies are enabled for the given URL. This may block
-// waiting for a previous SetCookie message to be processed.
-IPC_SYNC_MESSAGE_CONTROL3_1(ViewHostMsg_CookiesEnabled,
- int /* render_frame_id */,
- GURL /* url */,
- GURL /* first_party_for_cookies */,
- bool /* cookies_enabled */)
-
// Used to get the list of plugins
IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_GetPlugins,
bool /* refresh*/,
@@ -1230,11 +1236,6 @@ IPC_MESSAGE_ROUTED1(ViewHostMsg_GoToEntryAtOffset,
// renderer, instructing it to close.
IPC_MESSAGE_ROUTED0(ViewHostMsg_RouteCloseEvent)
-// Sent to the browser from an inactive renderer to post a message to the
-// active renderer.
-IPC_MESSAGE_ROUTED1(ViewHostMsg_RouteMessageEvent,
- ViewMsg_PostMessage_Params)
-
// Notifies that the preferred size of the content changed.
IPC_MESSAGE_ROUTED1(ViewHostMsg_DidContentsPreferredSizeChange,
gfx::Size /* pref_size */)
@@ -1323,6 +1324,13 @@ IPC_MESSAGE_ROUTED3(ViewHostMsg_RequestPpapiBrokerPermission,
int /* routing_id */,
GURL /* document_url */,
base::FilePath /* plugin_path */)
+
+// A renderer sends this to the browser process when it throttles or unthrottles
+// a plugin instance for the Plugin Power Saver feature.
+IPC_MESSAGE_CONTROL3(ViewHostMsg_PluginInstanceThrottleStateChange,
+ int /* plugin_child_id */,
+ int32 /* pp_instance */,
+ bool /* is_throttled */)
#endif // defined(ENABLE_PLUGINS)
// Send the tooltip text for the current mouse position to the browser.
@@ -1390,6 +1398,10 @@ IPC_MESSAGE_ROUTED2(ViewHostMsg_DidZoomURL,
double /* zoom_level */,
GURL /* url */)
+// Sent when the renderer changes its page scale factor and whether or not the
+// page scale factor is one changes.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_PageScaleFactorIsOneChanged, bool /* is_one */)
+
// Updates the minimum/maximum allowed zoom percent for this tab from the
// default values. If |remember| is true, then the zoom setting is applied to
// other pages in the site and is saved, otherwise it only applies to this
@@ -1409,9 +1421,6 @@ IPC_MESSAGE_ROUTED3(
cc::CompositorFrame /* frame */,
std::vector<IPC::Message> /* messages_to_deliver_with_frame */)
-// Sent by the compositor when a flinging animation is stopped.
-IPC_MESSAGE_ROUTED0(ViewHostMsg_DidStopFlinging)
-
//---------------------------------------------------------------------------
// Request for cryptographic operation messages:
// These are messages from the renderer to the browser to perform a
@@ -1427,10 +1436,10 @@ IPC_SYNC_MESSAGE_CONTROL3_1(ViewHostMsg_Keygen,
std::string /* signed public key and challenge */)
// Message sent from the renderer to the browser to request that the browser
-// cache |data| associated with |url|.
+// cache |data| associated with |url| and |expected_response_time|.
IPC_MESSAGE_CONTROL3(ViewHostMsg_DidGenerateCacheableMetadata,
GURL /* url */,
- double /* expected_response_time */,
+ base::Time /* expected_response_time */,
std::vector<char> /* data */)
// Register a new handler for URL requests with the given scheme.
@@ -1446,11 +1455,6 @@ IPC_MESSAGE_ROUTED3(ViewHostMsg_UnregisterProtocolHandler,
GURL /* url */,
bool /* user_gesture */)
-// Puts the browser into "tab fullscreen" mode for the sending renderer.
-// See the comment in chrome/browser/ui/browser.h for more details.
-IPC_MESSAGE_ROUTED1(ViewHostMsg_ToggleFullscreen,
- bool /* enter_fullscreen */)
-
// Send back a string to be recorded by UserMetrics.
IPC_MESSAGE_CONTROL1(ViewHostMsg_UserMetricsRecordAction,
std::string /* action */)
@@ -1521,15 +1525,6 @@ IPC_MESSAGE_ROUTED0(ViewHostMsg_WillInsertBody)
IPC_MESSAGE_ROUTED1(ViewHostMsg_UpdateFaviconURL,
std::vector<content::FaviconURL> /* candidates */)
-// Sent by the renderer to the browser to start a vibration with the given
-// duration.
-IPC_MESSAGE_CONTROL1(ViewHostMsg_Vibrate,
- int64 /* milliseconds */)
-
-// Sent by the renderer to the browser to cancel the currently running
-// vibration, if there is one.
-IPC_MESSAGE_CONTROL0(ViewHostMsg_CancelVibration)
-
// Message sent from renderer to the browser when the element that is focused
// has been touched. A bool is passed in this message which indicates if the
// node is editable.
@@ -1587,18 +1582,18 @@ IPC_MESSAGE_CONTROL3(ViewHostMsg_RunWebAudioMediaCodec,
base::FileDescriptor /* pcm_output */,
uint32_t /* data_size*/)
-// Sent by renderer to request a ViewMsg_BeginFrame message for upcoming
-// display events. If |enabled| is true, the BeginFrame message will continue
-// to be be delivered until the notification is disabled.
-IPC_MESSAGE_ROUTED1(ViewHostMsg_SetNeedsBeginFrame,
- bool /* enabled */)
-
// Reply to the ViewMsg_ExtractSmartClipData message.
IPC_MESSAGE_ROUTED3(ViewHostMsg_SmartClipDataExtracted,
base::string16 /* text */,
base::string16 /* html */,
gfx::Rect /* rect */)
+// Notifies that an unhandled tap has occurred at the specified x,y position
+// and that the UI may need to be triggered.
+IPC_MESSAGE_ROUTED2(ViewHostMsg_ShowUnhandledTapUIIfNeeded,
+ int /* x */,
+ int /* y */)
+
#elif defined(OS_MACOSX)
// Request that the browser load a font into shared memory for us.
IPC_SYNC_MESSAGE_CONTROL1_3(ViewHostMsg_LoadFont,
@@ -1627,27 +1622,6 @@ IPC_SYNC_MESSAGE_CONTROL2_0(ViewHostMsg_PreCacheFontCharacters,
base::string16 /* characters */)
#endif
-#if defined(OS_POSIX)
-// On POSIX, we cannot allocated shared memory from within the sandbox, so
-// this call exists for the renderer to ask the browser to allocate memory
-// on its behalf. We return a file descriptor to the POSIX shared memory.
-// If the |cache_in_browser| flag is |true|, then a copy of the shmem is kept
-// by the browser, and it is the caller's repsonsibility to send a
-// ViewHostMsg_FreeTransportDIB message in order to release the cached shmem.
-// In all cases, the caller is responsible for deleting the resulting
-// TransportDIB.
-IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_AllocTransportDIB,
- uint32_t, /* bytes requested */
- bool, /* cache in the browser */
- TransportDIB::Handle /* DIB */)
-
-// Since the browser keeps handles to the allocated transport DIBs, this
-// message is sent to tell the browser that it may release them when the
-// renderer is finished with them.
-IPC_MESSAGE_CONTROL1(ViewHostMsg_FreeTransportDIB,
- TransportDIB::Id /* DIB id */)
-#endif
-
// Adding a new message? Stick to the sort order above: first platform
// independent ViewMsg, then ifdefs for platform specific ViewMsg, then platform
// independent ViewHostMsg, then ifdefs for platform specific ViewHostMsg.
diff --git a/chromium/content/common/webplugin_geometry.h b/chromium/content/common/webplugin_geometry.h
index 7f0a21b4b31..f6cf700334f 100644
--- a/chromium/content/common/webplugin_geometry.h
+++ b/chromium/content/common/webplugin_geometry.h
@@ -8,8 +8,8 @@
#include <vector>
#include "base/basictypes.h"
+#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/rect.h"
namespace content {
diff --git a/chromium/content/common/websocket.h b/chromium/content/common/websocket.h
index e79fc988c05..324e9a100d4 100644
--- a/chromium/content/common/websocket.h
+++ b/chromium/content/common/websocket.h
@@ -52,7 +52,7 @@ struct WebSocketHandshakeResponse {
// HTTP status text
std::string status_text;
// Additional HTTP response headers
- std::vector<std::pair<std::string, std::string> > headers;
+ base::StringPairs headers;
// HTTP response headers raw string
std::string headers_text;
// The time that this response arrives
diff --git a/chromium/content/common/websocket_messages.h b/chromium/content/common/websocket_messages.h
index 394c9698c6c..657b44eb2a1 100644
--- a/chromium/content/common/websocket_messages.h
+++ b/chromium/content/common/websocket_messages.h
@@ -7,8 +7,26 @@
// This file defines the IPCs for the browser-side implementation of
// WebSockets.
//
-// This IPC interface is based on the WebSocket multiplexing draft spec,
-// http://tools.ietf.org/html/draft-ietf-hybi-websocket-multiplexing-09
+// This IPC interface was originally desined based on the WebSocket
+// multiplexing draft spec,
+// http://tools.ietf.org/html/draft-ietf-hybi-websocket-multiplexing-09. So,
+// some of them are given names correspond to the concepts defined in the spec.
+//
+// A WebSocketBridge object in the renderer and the corresponding WebSocketHost
+// object in the browser are associated using an identifier named channel ID.
+// The channel id is chosen by the renderer for a new channel. While the
+// channel id is unique per-renderer, the browser may have multiple renderers
+// using the same channel id.
+//
+// There're WebSocketDispatcherHost objects for each renderer. Each of
+// WebSocketDispatcherHost holds a channel id to WebSocketHost map.
+//
+// Received messages are routed to the corresponding object by
+// WebSocketDispatcher in the renderer and WebSocketDispatcherHost in the
+// browser using the channel ID.
+//
+// The channel ID value is stored in the routing ID member which is available
+// when we use the IPC_MESSAGE_ROUTED macro though it's unintended use.
#include <string>
#include <vector>
@@ -45,16 +63,9 @@ IPC_STRUCT_TRAITS_END()
// WebSocket messages sent from the renderer to the browser.
-// Open new virtual WebSocket connection to |socket_url|. |channel_id| is an
-// identifier chosen by the renderer for the new channel. It cannot correspond
-// to an existing open channel, and must be between 1 and
-// 0x7FFFFFFF. |requested_protocols| is a list of tokens identifying
-// sub-protocols the renderer would like to use, as described in RFC6455
-// "Subprotocols Using the WebSocket Protocol".
-//
-// The browser process will not send |channel_id| as-is to the remote server; it
-// will try to use a short id on the wire. This saves the renderer from
-// having to try to choose the ids cleverly.
+// Open new WebSocket connection to |socket_url|. |requested_protocols| is a
+// list of tokens identifying sub-protocols the renderer would like to use, as
+// described in RFC6455 "Subprotocols Using the WebSocket Protocol".
IPC_MESSAGE_ROUTED4(WebSocketHostMsg_AddChannelRequest,
GURL /* socket_url */,
std::vector<std::string> /* requested_protocols */,
@@ -63,17 +74,10 @@ IPC_MESSAGE_ROUTED4(WebSocketHostMsg_AddChannelRequest,
// WebSocket messages sent from the browser to the renderer.
-// Respond to an AddChannelRequest for channel |channel_id|. |channel_id| is
-// scoped to the renderer process; while it is unique per-renderer, the browser
-// may have multiple renderers using the same id. If |fail| is true, the channel
-// could not be established (the cause of the failure is not provided to the
-// renderer in order to limit its ability to abuse WebSockets to perform network
-// probing, etc.). If |fail| is set then the |channel_id| is available for
-// re-use. |selected_protocol| is the sub-protocol the server selected,
-// or empty if no sub-protocol was selected. |extensions| is the list of
-// extensions negotiated for the connection.
-IPC_MESSAGE_ROUTED3(WebSocketMsg_AddChannelResponse,
- bool /* fail */,
+// Respond to an AddChannelRequest. |selected_protocol| is the sub-protocol the
+// server selected, or empty if no sub-protocol was selected. |extensions| is
+// the list of extensions negotiated for the connection.
+IPC_MESSAGE_ROUTED2(WebSocketMsg_AddChannelResponse,
std::string /* selected_protocol */,
std::string /* extensions */)
@@ -90,8 +94,11 @@ IPC_MESSAGE_ROUTED1(WebSocketMsg_NotifyStartOpeningHandshake,
IPC_MESSAGE_ROUTED1(WebSocketMsg_NotifyFinishOpeningHandshake,
content::WebSocketHandshakeResponse /* response */)
-// Notify the renderer that the browser is required to fail the connection
-// (see RFC6455 7.1.7 for details).
+// Notify the renderer that either:
+// - the connection open request (WebSocketHostMsg_AddChannelRequest) failed.
+// - the browser is required to fail the connection
+// (see RFC6455 7.1.7 for details).
+//
// When the renderer process receives this messages it does the following:
// 1. Fire an error event.
// 2. Show |message| to the inspector.
@@ -105,48 +112,49 @@ IPC_MESSAGE_ROUTED1(WebSocketMsg_NotifyFailure,
// WebSocket messages that can be sent in either direction.
-// Send a non-control frame on |channel_id|. If the sender is the renderer, it
-// will be sent to the remote server. If the sender is the browser, it comes
-// from the remote server. |fin| indicates that this frame is the last in the
-// current message. |type| is the type of the message. On the first frame of a
-// message, it must be set to either WEB_SOCKET_MESSAGE_TYPE_TEXT or
-// WEB_SOCKET_MESSAGE_TYPE_BINARY. On subsequent frames, it must be set to
-// WEB_SOCKET_MESSAGE_TYPE_CONTINUATION, and the type is the same as that of the
-// first message. If |type| is WEB_SOCKET_MESSAGE_TYPE_TEXT, then the
-// concatenation of the |data| from every frame in the message must be valid
-// UTF-8. If |fin| is not set, |data| must be non-empty.
+// Send a non-control frame to the channel.
+// - If the sender is the renderer, it will be sent to the remote server.
+// - If the sender is the browser, it comes from the remote server.
+//
+// - |fin| indicates that this frame is the last in the current message.
+// - |type| is the type of the message. On the first frame of a message, it
+// must be set to either WEB_SOCKET_MESSAGE_TYPE_TEXT or
+// WEB_SOCKET_MESSAGE_TYPE_BINARY. On subsequent frames, it must be set to
+// WEB_SOCKET_MESSAGE_TYPE_CONTINUATION, and the type is the same as that of
+// the first message. If |type| is WEB_SOCKET_MESSAGE_TYPE_TEXT, then the
+// concatenation of the |data| from every frame in the message must be valid
+// UTF-8. If |fin| is not set, |data| must be non-empty.
IPC_MESSAGE_ROUTED3(WebSocketMsg_SendFrame,
bool /* fin */,
content::WebSocketMessageType /* type */,
std::vector<char> /* data */)
-// Add |quota| tokens of send quota for channel |channel_id|. |quota| must be a
-// positive integer. Both the browser and the renderer set send quota for the
-// other side, and check that quota has not been exceeded when receiving
-// messages. Both sides start a new channel with a quota of 0, and must wait for
-// a FlowControl message before calling SendFrame. The total available quota on
+// Add |quota| tokens of send quota for the channel. |quota| must be a positive
+// integer. Both the browser and the renderer set send quota for the other
+// side, and check that quota has not been exceeded when receiving messages.
+// Both sides start a new channel with a quota of 0, and must wait for a
+// FlowControl message before calling SendFrame. The total available quota on
// one side must never exceed 0x7FFFFFFFFFFFFFFF tokens.
IPC_MESSAGE_ROUTED1(WebSocketMsg_FlowControl,
int64 /* quota */)
// Drop the channel.
-// When sent by the renderer, this will cause a DropChannel message to be sent
-// if the multiplex extension is in use, otherwise a Close message will be sent
-// and the TCP/IP connection will be closed.
-// When sent by the browser, this indicates that a Close or DropChannel has been
-// received, the connection was closed, or a network or protocol error
-// occurred. On receiving DropChannel, the renderer process may consider the
-// |channel_id| available for reuse by a new AddChannelRequest.
-// |code| is one of the reason codes specified in RFC6455 or
-// draft-ietf-hybi-websocket-multiplexing-09. |reason|, if non-empty, is a
-// UTF-8 encoded string which may be useful for debugging but is not necessarily
-// human-readable, as supplied by the server in the Close or DropChannel
-// message.
-// If |was_clean| is false on a message from the browser, then the WebSocket
-// connection was not closed cleanly. If |was_clean| is false on a message from
-// the renderer, then the connection should be closed immediately without a
-// closing handshake and the renderer cannot accept any new messages on this
-// connection.
+//
+// When sent by the renderer, this will cause a Close message will be sent and
+// the TCP/IP connection will be closed.
+//
+// When sent by the browser, this indicates that a Close has been received, the
+// connection was closed, or a network or protocol error occurred.
+//
+// - |code| is one of the reason codes specified in RFC6455.
+// - |reason|, if non-empty, is a UTF-8 encoded string which may be useful for
+// debugging but is not necessarily human-readable, as supplied by the server
+// in the Close message.
+// - If |was_clean| is false on a message from the browser, then the WebSocket
+// connection was not closed cleanly. If |was_clean| is false on a message
+// from the renderer, then the connection should be closed immediately without
+// a closing handshake and the renderer cannot accept any new messages on this
+// connection.
IPC_MESSAGE_ROUTED3(WebSocketMsg_DropChannel,
bool /* was_clean */,
unsigned short /* code */,
diff --git a/chromium/content/content.gni b/chromium/content/content.gni
index cd1b86e7f63..e0834a3c56e 100644
--- a/chromium/content/content.gni
+++ b/chromium/content/content.gni
@@ -4,9 +4,9 @@
if (is_win) {
directxsdk_exists =
- (exec_script("//build/dir_exists.py",
- [ rebase_path("//third_party/directxsdk", root_build_dir) ],
- "trim string") == "True")
+ exec_script("//build/dir_exists.py",
+ [ rebase_path("//third_party/directxsdk", root_build_dir) ],
+ "trim string") == "True"
} else {
directxsdk_exists = false
}
diff --git a/chromium/content/content.gyp b/chromium/content/content.gyp
index 5a7355f7ff3..0125b2c8c7f 100644
--- a/chromium/content/content.gyp
+++ b/chromium/content/content.gyp
@@ -24,14 +24,14 @@
'conditions': [
['OS != "ios"', {
'includes': [
- 'content_common_mojo_bindings.gypi',
- 'content_resources.gypi',
'../build/win_precompile.gypi',
+ 'content_resources.gypi',
],
}],
['OS == "win"', {
'targets': [
{
+ # GN: //content:content_startup_helper_win
'target_name': 'content_startup_helper_win',
'type': 'static_library',
'include_dirs': [
@@ -265,6 +265,9 @@
'content_common',
'content_resources',
],
+ 'export_dependent_settings': [
+ 'content_common',
+ ],
'conditions': [
['chromium_enable_vtune_jit_for_v8==1', {
'dependencies': [
@@ -394,6 +397,7 @@
'target_name': 'content_renderer',
'type': 'none',
'dependencies': ['content'],
+ 'export_dependent_settings': ['content'],
},
{
# GN version: //content/utility
@@ -425,19 +429,28 @@
'dependencies': [
'../base/base.gyp:base',
'../device/battery/battery.gyp:device_battery_java',
+ '../device/bluetooth/bluetooth.gyp:device_bluetooth_java',
+ '../device/vibration/vibration.gyp:device_vibration_java',
'../media/media.gyp:media_java',
+ '../mojo/mojo_base.gyp:mojo_application_bindings',
'../mojo/mojo_base.gyp:mojo_system_java',
- '../mojo/public/mojo_public.gyp:mojo_bindings_java',
'../net/net.gyp:net',
+ '../third_party/mojo/mojo_public.gyp:mojo_bindings_java',
'../ui/android/ui_android.gyp:ui_java',
+ '../ui/touch_selection/ui_touch_selection.gyp:selection_event_type_java',
+ '../ui/touch_selection/ui_touch_selection.gyp:touch_handle_orientation_java',
+ '../third_party/WebKit/public/blink_headers.gyp:blink_headers_java',
'common_aidl',
+ 'console_message_level_java',
'content_common',
'content_strings_grd',
'content_gamepad_mapping',
'gesture_event_type_java',
+ 'invalidate_types_java',
+ 'navigation_controller_java',
'popup_item_type_java',
'result_codes_java',
- 'selection_event_type_java',
+ 'readback_response_java',
'speech_recognition_error_java',
'top_controls_state_java',
'screen_orientation_values_java',
@@ -448,16 +461,17 @@
'R_package': 'org.chromium.content',
'R_package_relpath': 'org/chromium/content',
},
- 'conditions': [
- ['android_webview_build == 0', {
- 'dependencies': [
- '../third_party/eyesfree/eyesfree.gyp:eyesfree_java',
- ],
- }],
- ],
'includes': [ '../build/java.gypi' ],
},
{
+ 'target_name': 'console_message_level_java',
+ 'type': 'none',
+ 'variables': {
+ 'source_file': 'public/common/console_message_level.h',
+ },
+ 'includes': [ '../build/android/java_cpp_enum.gypi' ],
+ },
+ {
'target_name': 'content_strings_grd',
# The android_webview/Android.mk file depends on this target directly.
'android_unmangled_name': 1,
@@ -486,6 +500,22 @@
'includes': [ '../build/android/java_cpp_enum.gypi' ],
},
{
+ 'target_name': 'invalidate_types_java',
+ 'type': 'none',
+ 'variables': {
+ 'source_file': 'public/browser/invalidate_type.h',
+ },
+ 'includes': [ '../build/android/java_cpp_enum.gypi' ],
+ },
+ {
+ 'target_name': 'navigation_controller_java',
+ 'type': 'none',
+ 'variables': {
+ 'source_file': 'public/browser/navigation_controller.h',
+ },
+ 'includes': [ '../build/android/java_cpp_enum.gypi' ],
+ },
+ {
'target_name': 'popup_item_type_java',
'type': 'none',
'variables': {
@@ -494,18 +524,18 @@
'includes': [ '../build/android/java_cpp_enum.gypi' ],
},
{
- 'target_name': 'result_codes_java',
+ 'target_name': 'readback_response_java',
'type': 'none',
'variables': {
- 'source_file': 'public/common/result_codes.h',
+ 'source_file': 'public/browser/readback_types.h',
},
'includes': [ '../build/android/java_cpp_enum.gypi' ],
},
{
- 'target_name': 'selection_event_type_java',
+ 'target_name': 'result_codes_java',
'type': 'none',
'variables': {
- 'source_file': 'browser/renderer_host/input/selection_event_type.h',
+ 'source_file': 'public/common/result_codes.h',
},
'includes': [ '../build/android/java_cpp_enum.gypi' ],
},
diff --git a/chromium/content/content_app.gypi b/chromium/content/content_app.gypi
index 12c217798b3..d7b2b447119 100644
--- a/chromium/content/content_app.gypi
+++ b/chromium/content/content_app.gypi
@@ -10,23 +10,30 @@
'../base/base.gyp:base',
'../base/base.gyp:base_i18n',
'../crypto/crypto.gyp:crypto',
+ '../mojo/mojo_base.gyp:mojo_environment_chromium',
+ '../third_party/mojo/mojo_edk.gyp:mojo_system_impl',
'../ui/base/ui_base.gyp:ui_base',
'../ui/gfx/gfx.gyp:gfx',
'../ui/gfx/gfx.gyp:gfx_geometry',
+ 'content_common_mojo_bindings.gyp:content_common_mojo_bindings',
],
'sources': [
'app/android/app_jni_registrar.cc',
'app/android/app_jni_registrar.h',
'app/android/child_process_service.cc',
'app/android/child_process_service.h',
+ 'app/android/content_jni_onload.cc',
'app/android/content_main.cc',
'app/android/content_main.h',
'app/android/library_loader_hooks.cc',
+ 'app/android/library_loader_hooks.h',
'app/content_main.cc',
'app/content_main_runner.cc',
+ 'app/mac/mac_init.mm',
+ 'app/mac/mac_init.h',
'app/mojo/mojo_init.cc',
'app/mojo/mojo_init.h',
- 'public/app/android_library_loader_hooks.h',
+ 'public/app/content_jni_onload.h',
'public/app/content_main.h',
'public/app/content_main_delegate.cc',
'public/app/content_main_delegate.h',
@@ -45,10 +52,9 @@
],
'dependencies': [
'content.gyp:content_jni_headers',
+ '../build/android/ndk.gyp:cpu_features',
'../skia/skia.gyp:skia',
- ],
- 'includes': [
- '../build/android/cpufeatures.gypi',
+ '../ui/android/ui_android.gyp:ui_android',
],
}],
['OS=="win"', {
@@ -62,12 +68,6 @@
'app/mojo/mojo_init.cc',
'app/mojo/mojo_init.h',
],
- }, { # OS!="ios"
- 'dependencies': [
- '../mojo/edk/mojo_edk.gyp:mojo_system_impl',
- '../mojo/mojo_base.gyp:mojo_environment_chromium',
- '../mojo/public/mojo_public.gyp:mojo_application_bindings',
- ],
}],
],
}
diff --git a/chromium/content/content_browser.gypi b/chromium/content/content_browser.gypi
index 2cf449d3fe8..9ae48ee8dac 100644
--- a/chromium/content/content_browser.gypi
+++ b/chromium/content/content_browser.gypi
@@ -8,6 +8,8 @@
'../crypto/crypto.gyp:crypto',
'../device/battery/battery.gyp:device_battery',
'../device/battery/battery.gyp:device_battery_mojo_bindings',
+ '../device/vibration/vibration.gyp:device_vibration',
+ '../device/vibration/vibration.gyp:device_vibration_mojo_bindings',
'../google_apis/google_apis.gyp:google_apis',
'../net/net.gyp:net',
'../skia/skia.gyp:skia',
@@ -19,14 +21,21 @@
'../ui/accessibility/accessibility.gyp:accessibility',
'../ui/accessibility/accessibility.gyp:ax_gen',
'../ui/base/ui_base.gyp:ui_base',
+ '../ui/base/ime/ui_base_ime.gyp:ui_base_ime',
+ '../ui/events/events.gyp:blink',
+ '../ui/events/events.gyp:events',
'../ui/events/events.gyp:events_base',
'../ui/events/events.gyp:gesture_detection',
'../ui/gfx/gfx.gyp:gfx',
'../ui/gfx/gfx.gyp:gfx_geometry',
'../ui/resources/ui_resources.gyp:ui_resources',
'../ui/snapshot/snapshot.gyp:snapshot',
- 'browser/service_worker/service_worker_proto.gyp:proto',
+ 'browser/background_sync/background_sync_proto.gyp:background_sync_proto',
+ 'browser/cache_storage/cache_storage_proto.gyp:cache_storage_proto',
+ 'browser/notifications/notification_proto.gyp:notification_proto',
+ 'browser/service_worker/service_worker_proto.gyp:service_worker_proto',
'browser/speech/proto/speech_proto.gyp:speech_proto',
+ 'content_common_mojo_bindings.gyp:content_common_mojo_bindings',
],
'export_dependent_settings': [
'../ui/accessibility/accessibility.gyp:ax_gen',
@@ -36,6 +45,7 @@
'../third_party/WebKit/public/blink_headers.gyp:blink_headers',
# The public render_widget_host.h needs to re-export skia defines.
'../skia/skia.gyp:skia',
+ 'content_common_mojo_bindings.gyp:content_common_mojo_bindings',
],
'include_dirs': [
'..',
@@ -44,18 +54,18 @@
'variables': {
'public_browser_sources': [
'public/browser/access_token_store.h',
+ 'public/browser/android/browser_media_player_manager.cc',
+ 'public/browser/android/browser_media_player_manager.h',
'public/browser/android/compositor.h',
'public/browser/android/compositor_client.h',
+ 'public/browser/android/content_protocol_handler.h',
'public/browser/android/content_view_core.h',
'public/browser/android/content_view_layer_renderer.h',
'public/browser/android/devtools_auth.h',
'public/browser/android/download_controller_android.h',
'public/browser/android/external_video_surface_container.h',
- 'public/browser/android/layer_tree_build_helper.h',
- 'public/browser/android/synchronous_compositor_client.h',
'public/browser/android/synchronous_compositor.h',
- 'public/browser/android/ui_resource_client_android.h',
- 'public/browser/android/ui_resource_provider.h',
+ 'public/browser/android/synchronous_compositor_client.h',
'public/browser/appcache_service.h',
'public/browser/ax_event_notification_details.cc',
'public/browser/ax_event_notification_details.h',
@@ -81,14 +91,15 @@
'public/browser/browser_plugin_guest_manager.h',
'public/browser/browser_ppapi_host.h',
'public/browser/browser_shutdown.h',
- 'public/browser/browser_url_handler.h',
'public/browser/browser_thread.h',
'public/browser/browser_thread_delegate.h',
+ 'public/browser/browser_url_handler.h',
'public/browser/cert_store.h',
+ 'public/browser/certificate_request_result_type.h',
'public/browser/child_process_data.h',
'public/browser/child_process_security_policy.h',
+ 'public/browser/client_certificate_delegate.h',
'public/browser/color_chooser.h',
- 'public/browser/certificate_request_result_type.h',
'public/browser/content_browser_client.cc',
'public/browser/content_browser_client.h',
'public/browser/context_factory.h',
@@ -100,14 +111,11 @@
'public/browser/devtools_agent_host_client.h',
'public/browser/devtools_external_agent_proxy.h',
'public/browser/devtools_external_agent_proxy_delegate.h',
- 'public/browser/download_danger_type.h',
'public/browser/devtools_frontend_host.h',
- 'public/browser/devtools_http_handler.h',
- 'public/browser/devtools_http_handler_delegate.h',
'public/browser/devtools_manager_delegate.h',
- 'public/browser/devtools_target.h',
'public/browser/dom_operation_notification_details.h',
'public/browser/dom_storage_context.h',
+ 'public/browser/download_danger_type.h',
'public/browser/download_destination_observer.h',
'public/browser/download_interrupt_reason_values.h',
'public/browser/download_interrupt_reasons.h',
@@ -122,6 +130,7 @@
'public/browser/favicon_status.cc',
'public/browser/favicon_status.h',
'public/browser/file_descriptor_info.h',
+ 'public/browser/focused_node_details.h',
'public/browser/font_list_async.h',
'public/browser/geolocation_provider.h',
'public/browser/global_request_id.h',
@@ -133,6 +142,8 @@
'public/browser/indexed_db_info.cc',
'public/browser/indexed_db_info.h',
'public/browser/interstitial_page.h',
+ 'public/browser/interstitial_page_delegate.cc',
+ 'public/browser/interstitial_page_delegate.h',
'public/browser/invalidate_type.h',
'public/browser/javascript_dialog_manager.cc',
'public/browser/javascript_dialog_manager.h',
@@ -145,6 +156,8 @@
'public/browser/media_capture_devices.h',
'public/browser/media_device_id.cc',
'public/browser/media_device_id.h',
+ 'public/browser/message_port_delegate.h',
+ 'public/browser/message_port_provider.h',
'public/browser/native_web_keyboard_event.h',
'public/browser/navigation_controller.cc',
'public/browser/navigation_controller.h',
@@ -152,7 +165,11 @@
'public/browser/navigation_details.h',
'public/browser/navigation_entry.h',
'public/browser/navigation_type.h',
+ 'public/browser/navigator_connect_context.h',
+ 'public/browser/navigator_connect_service_factory.h',
+ 'public/browser/notification_database_data.h',
'public/browser/notification_details.h',
+ 'public/browser/notification_event_dispatcher.h',
'public/browser/notification_observer.h',
'public/browser/notification_registrar.cc',
'public/browser/notification_registrar.h',
@@ -164,14 +181,24 @@
'public/browser/page_navigator.h',
'public/browser/pepper_flash_settings_helper.h',
'public/browser/permission_type.h',
+ 'public/browser/platform_notification_context.h',
+ 'public/browser/platform_notification_service.h',
'public/browser/plugin_data_remover.h',
'public/browser/plugin_service.h',
'public/browser/plugin_service_filter.h',
'public/browser/power_save_blocker.h',
+ 'public/browser/presentation_screen_availability_listener.h',
+ 'public/browser/presentation_service_delegate.h',
+ 'public/browser/presentation_session.cc',
+ 'public/browser/presentation_session.h',
+ 'public/browser/presentation_session_message.cc',
+ 'public/browser/presentation_session_message.h',
'public/browser/profiler_controller.h',
'public/browser/profiler_subscriber.h',
+ 'public/browser/push_messaging_service.cc',
'public/browser/push_messaging_service.h',
'public/browser/quota_permission_context.h',
+ 'public/browser/readback_types.h',
'public/browser/render_frame_host.h',
'public/browser/render_process_host.h',
'public/browser/render_process_host_factory.h',
@@ -192,8 +219,8 @@
'public/browser/resource_request_info.h',
'public/browser/resource_throttle.h',
'public/browser/save_page_type.h',
- 'public/browser/screen_orientation_dispatcher_host.h',
'public/browser/screen_orientation_delegate.h',
+ 'public/browser/screen_orientation_dispatcher_host.h',
'public/browser/screen_orientation_provider.cc',
'public/browser/screen_orientation_provider.h',
'public/browser/service_worker_context.h',
@@ -210,15 +237,20 @@
'public/browser/speech_recognition_session_config.h',
'public/browser/speech_recognition_session_context.cc',
'public/browser/speech_recognition_session_context.h',
+ 'public/browser/speech_recognition_session_preamble.cc',
+ 'public/browser/speech_recognition_session_preamble.h',
'public/browser/ssl_host_state_delegate.h',
'public/browser/storage_partition.h',
'public/browser/stream_handle.h',
'public/browser/stream_info.cc',
'public/browser/stream_info.h',
+ 'public/browser/trace_uploader.h',
'public/browser/tracing_controller.h',
+ 'public/browser/tracing_delegate.h',
+ 'public/browser/url_data_source.cc',
+ 'public/browser/url_data_source.h',
'public/browser/user_metrics.h',
'public/browser/utility_process_host.h',
- 'public/browser/vibration_provider.h',
'public/browser/web_contents.cc',
'public/browser/web_contents.h',
'public/browser/web_contents_delegate.cc',
@@ -234,14 +266,22 @@
'public/browser/web_ui_controller.h',
'public/browser/web_ui_controller_factory.h',
'public/browser/web_ui_data_source.h',
- 'public/browser/url_data_source.cc',
- 'public/browser/url_data_source.h',
'public/browser/web_ui_message_handler.h',
'public/browser/worker_service.h',
'public/browser/worker_service_observer.h',
+ 'public/browser/zoom_level_delegate.h',
'public/browser/zygote_host_linux.h',
],
'private_browser_sources': [
+ # These files are generated by GRIT.
+ '<(SHARED_INTERMEDIATE_DIR)/blink/grit/devtools_resources.h',
+ '<(SHARED_INTERMEDIATE_DIR)/blink/grit/devtools_resources_map.cc',
+ '<(SHARED_INTERMEDIATE_DIR)/blink/grit/devtools_resources_map.h',
+ # These files are generated by devtools_protocol_handler_generator.py.
+ '<(SHARED_INTERMEDIATE_DIR)/content/browser/devtools/protocol/devtools_protocol_dispatcher.cc',
+ '<(SHARED_INTERMEDIATE_DIR)/content/browser/devtools/protocol/devtools_protocol_dispatcher.h',
+ '<(SHARED_INTERMEDIATE_DIR)/content/browser/tracing/grit/tracing_resources.h',
+ '<(SHARED_INTERMEDIATE_DIR)/ui/resources/grit/webui_resources_map.cc',
'browser/accessibility/accessibility_mode_helper.cc',
'browser/accessibility/accessibility_mode_helper.h',
'browser/accessibility/accessibility_tree_formatter.cc',
@@ -270,10 +310,13 @@
'browser/accessibility/browser_accessibility_manager_win.cc',
'browser/accessibility/browser_accessibility_manager_win.h',
'browser/accessibility/browser_accessibility_state_impl.cc',
- 'browser/accessibility/browser_accessibility_state_impl_win.cc',
'browser/accessibility/browser_accessibility_state_impl.h',
+ 'browser/accessibility/browser_accessibility_state_impl_win.cc',
'browser/accessibility/browser_accessibility_win.cc',
'browser/accessibility/browser_accessibility_win.h',
+ 'browser/accessibility/one_shot_accessibility_tree_search.cc',
+ 'browser/accessibility/one_shot_accessibility_tree_search.h',
+ 'browser/android/animation_utils.h',
'browser/android/browser_jni_registrar.cc',
'browser/android/browser_jni_registrar.h',
'browser/android/browser_startup_controller.cc',
@@ -284,10 +327,10 @@
'browser/android/child_process_launcher_android.h',
'browser/android/composited_touch_handle_drawable.cc',
'browser/android/composited_touch_handle_drawable.h',
+ 'browser/android/content_protocol_handler_impl.cc',
+ 'browser/android/content_protocol_handler_impl.h',
'browser/android/content_readback_handler.cc',
'browser/android/content_readback_handler.h',
- 'browser/android/content_settings.cc',
- 'browser/android/content_settings.h',
'browser/android/content_startup_flags.cc',
'browser/android/content_startup_flags.h',
'browser/android/content_video_view.cc',
@@ -300,39 +343,49 @@
'browser/android/content_view_statics.h',
'browser/android/date_time_chooser_android.cc',
'browser/android/date_time_chooser_android.h',
+ 'browser/android/deferred_download_observer.cc',
+ 'browser/android/deferred_download_observer.h',
+ 'browser/android/devtools_auth.cc',
'browser/android/download_controller_android_impl.cc',
'browser/android/download_controller_android_impl.h',
- 'browser/android/devtools_auth.cc',
'browser/android/edge_effect.cc',
'browser/android/edge_effect.h',
'browser/android/edge_effect_l.cc',
'browser/android/edge_effect_l.h',
- 'browser/android/gesture_event_type_list.h',
+ 'browser/android/in_process/context_provider_in_process.cc',
+ 'browser/android/in_process/context_provider_in_process.h',
+ 'browser/android/in_process/synchronous_compositor_external_begin_frame_source.cc',
+ 'browser/android/in_process/synchronous_compositor_external_begin_frame_source.h',
'browser/android/in_process/synchronous_compositor_factory_impl.cc',
'browser/android/in_process/synchronous_compositor_factory_impl.h',
'browser/android/in_process/synchronous_compositor_impl.cc',
'browser/android/in_process/synchronous_compositor_impl.h',
'browser/android/in_process/synchronous_compositor_output_surface.cc',
'browser/android/in_process/synchronous_compositor_output_surface.h',
+ 'browser/android/in_process/synchronous_compositor_registry.cc',
+ 'browser/android/in_process/synchronous_compositor_registry.h',
'browser/android/in_process/synchronous_input_event_filter.cc',
'browser/android/in_process/synchronous_input_event_filter.h',
'browser/android/interstitial_page_delegate_android.cc',
'browser/android/interstitial_page_delegate_android.h',
'browser/android/load_url_params.cc',
'browser/android/load_url_params.h',
+ 'browser/android/media_players_observer.cc',
+ 'browser/android/media_players_observer.h',
+ 'browser/android/overscroll_controller_android.cc',
+ 'browser/android/overscroll_controller_android.h',
'browser/android/overscroll_glow.cc',
'browser/android/overscroll_glow.h',
- 'browser/android/popup_item_type_list.h',
+ 'browser/android/overscroll_refresh.cc',
+ 'browser/android/overscroll_refresh.h',
'browser/android/popup_touch_handle_drawable.cc',
'browser/android/popup_touch_handle_drawable.h',
- 'browser/android/system_ui_resource_manager_impl.cc',
- 'browser/android/system_ui_resource_manager_impl.h',
'browser/android/tracing_controller_android.cc',
'browser/android/tracing_controller_android.h',
- 'browser/android/web_contents_observer_android.cc',
- 'browser/android/web_contents_observer_android.h',
- 'browser/android/ui_resource_provider_impl.cc',
- 'browser/android/ui_resource_provider_impl.h',
+ 'browser/android/url_request_content_job.cc',
+ 'browser/android/url_request_content_job.h',
+ 'browser/android/web_contents_observer_proxy.cc',
+ 'browser/android/web_contents_observer_proxy.h',
'browser/appcache/appcache.cc',
'browser/appcache/appcache.h',
'browser/appcache/appcache_backend_impl.cc',
@@ -355,6 +408,8 @@
'browser/appcache/appcache_host.h',
'browser/appcache/appcache_interceptor.cc',
'browser/appcache/appcache_interceptor.h',
+ 'browser/appcache/appcache_manifest_parser.cc',
+ 'browser/appcache/appcache_manifest_parser.h',
'browser/appcache/appcache_policy.h',
'browser/appcache/appcache_quota_client.cc',
'browser/appcache/appcache_quota_client.h',
@@ -376,10 +431,18 @@
'browser/appcache/appcache_working_set.h',
'browser/appcache/chrome_appcache_service.cc',
'browser/appcache/chrome_appcache_service.h',
- 'browser/appcache/appcache_manifest_parser.cc',
- 'browser/appcache/appcache_manifest_parser.h',
'browser/appcache/view_appcache_internals_job.cc',
'browser/appcache/view_appcache_internals_job.h',
+ 'browser/background_sync/background_sync_context_impl.cc',
+ 'browser/background_sync/background_sync_context_impl.h',
+ 'browser/background_sync/background_sync_manager.cc',
+ 'browser/background_sync/background_sync_manager.h',
+ 'browser/background_sync/background_sync_network_observer.cc',
+ 'browser/background_sync/background_sync_network_observer.h',
+ 'browser/bad_message.cc',
+ 'browser/bad_message.h',
+ 'browser/bluetooth/bluetooth_dispatcher_host.cc',
+ 'browser/bluetooth/bluetooth_dispatcher_host.h',
'browser/bootstrap_sandbox_mac.cc',
'browser/bootstrap_sandbox_mac.h',
'browser/browser_child_process_host_impl.cc',
@@ -411,6 +474,20 @@
'browser/browsing_instance.h',
'browser/byte_stream.cc',
'browser/byte_stream.h',
+ 'browser/cache_storage/cache_storage.cc',
+ 'browser/cache_storage/cache_storage.h',
+ 'browser/cache_storage/cache_storage_cache.cc',
+ 'browser/cache_storage/cache_storage_cache.h',
+ 'browser/cache_storage/cache_storage_context_impl.cc',
+ 'browser/cache_storage/cache_storage_context_impl.h',
+ 'browser/cache_storage/cache_storage_dispatcher_host.cc',
+ 'browser/cache_storage/cache_storage_dispatcher_host.h',
+ 'browser/cache_storage/cache_storage_manager.cc',
+ 'browser/cache_storage/cache_storage_manager.h',
+ 'browser/cache_storage/cache_storage_quota_client.cc',
+ 'browser/cache_storage/cache_storage_quota_client.h',
+ 'browser/cache_storage/cache_storage_scheduler.cc',
+ 'browser/cache_storage/cache_storage_scheduler.h',
'browser/cert_store_impl.cc',
'browser/cert_store_impl.h',
'browser/child_process_launcher.cc',
@@ -421,34 +498,59 @@
'browser/cocoa/system_hotkey_helper_mac.mm',
'browser/cocoa/system_hotkey_map.h',
'browser/cocoa/system_hotkey_map.mm',
+ 'browser/device_monitor_mac.h',
+ 'browser/device_monitor_mac.mm',
+ 'browser/device_monitor_udev.cc',
+ 'browser/device_monitor_udev.h',
+ 'browser/device_sensors/ambient_light_mac.cc',
+ 'browser/device_sensors/ambient_light_mac.h',
+ 'browser/device_sensors/data_fetcher_shared_memory.h',
+ 'browser/device_sensors/data_fetcher_shared_memory_android.cc',
+ 'browser/device_sensors/data_fetcher_shared_memory_base.cc',
+ 'browser/device_sensors/data_fetcher_shared_memory_base.h',
+ 'browser/device_sensors/data_fetcher_shared_memory_chromeos.cc',
+ 'browser/device_sensors/data_fetcher_shared_memory_default.cc',
+ 'browser/device_sensors/data_fetcher_shared_memory_mac.cc',
+ 'browser/device_sensors/data_fetcher_shared_memory_win.cc',
+ 'browser/device_sensors/device_inertial_sensor_service.cc',
+ 'browser/device_sensors/device_inertial_sensor_service.h',
+ 'browser/device_sensors/device_light_message_filter.cc',
+ 'browser/device_sensors/device_light_message_filter.h',
+ 'browser/device_sensors/device_motion_message_filter.cc',
+ 'browser/device_sensors/device_motion_message_filter.h',
+ 'browser/device_sensors/device_orientation_message_filter.cc',
+ 'browser/device_sensors/device_orientation_message_filter.h',
+ 'browser/device_sensors/inertial_sensor_consts.h',
+ 'browser/device_sensors/sensor_manager_android.cc',
+ 'browser/device_sensors/sensor_manager_android.h',
+ 'browser/device_sensors/sensor_manager_chromeos.cc',
+ 'browser/device_sensors/sensor_manager_chromeos.h',
+ 'browser/devtools/browser_devtools_agent_host.cc',
+ 'browser/devtools/browser_devtools_agent_host.h',
'browser/devtools/devtools_agent_host_impl.cc',
'browser/devtools/devtools_agent_host_impl.h',
+ 'browser/devtools/devtools_frame_trace_recorder.cc',
+ 'browser/devtools/devtools_frame_trace_recorder.h',
'browser/devtools/devtools_frontend_host_impl.cc',
'browser/devtools/devtools_frontend_host_impl.h',
- 'browser/devtools/devtools_http_handler_impl.cc',
- 'browser/devtools/devtools_http_handler_impl.h',
'browser/devtools/devtools_manager.cc',
'browser/devtools/devtools_manager.h',
'browser/devtools/devtools_netlog_observer.cc',
'browser/devtools/devtools_netlog_observer.h',
- 'browser/devtools/devtools_protocol.cc',
- 'browser/devtools/devtools_protocol.h',
- 'browser/devtools/devtools_system_info_handler.cc',
- 'browser/devtools/devtools_system_info_handler.h',
'browser/devtools/forwarding_agent_host.cc',
'browser/devtools/forwarding_agent_host.h',
'browser/devtools/ipc_devtools_agent_host.cc',
'browser/devtools/ipc_devtools_agent_host.h',
- 'browser/devtools/embedded_worker_devtools_agent_host.cc',
- 'browser/devtools/embedded_worker_devtools_agent_host.h',
- 'browser/devtools/embedded_worker_devtools_manager.cc',
- 'browser/devtools/embedded_worker_devtools_manager.h',
'browser/devtools/protocol/color_picker.cc',
'browser/devtools/protocol/color_picker.h',
'browser/devtools/protocol/devtools_protocol_client.cc',
'browser/devtools/protocol/devtools_protocol_client.h',
+ 'browser/devtools/protocol/devtools_protocol_handler.cc',
+ 'browser/devtools/protocol/devtools_protocol_handler.h',
'browser/devtools/protocol/dom_handler.cc',
'browser/devtools/protocol/dom_handler.h',
+ 'browser/devtools/protocol/emulation_handler.cc',
+ 'browser/devtools/protocol/emulation_handler.h',
'browser/devtools/protocol/input_handler.cc',
'browser/devtools/protocol/input_handler.h',
'browser/devtools/protocol/inspector_handler.cc',
@@ -459,38 +561,26 @@
'browser/devtools/protocol/page_handler.h',
'browser/devtools/protocol/power_handler.cc',
'browser/devtools/protocol/power_handler.h',
+ 'browser/devtools/protocol/service_worker_handler.cc',
+ 'browser/devtools/protocol/service_worker_handler.h',
+ 'browser/devtools/protocol/system_info_handler.cc',
+ 'browser/devtools/protocol/system_info_handler.h',
+ 'browser/devtools/protocol/tethering_handler.cc',
+ 'browser/devtools/protocol/tethering_handler.h',
'browser/devtools/protocol/tracing_handler.cc',
'browser/devtools/protocol/tracing_handler.h',
- 'browser/devtools/protocol/usage_and_quota_query.cc',
- 'browser/devtools/protocol/usage_and_quota_query.h',
- 'browser/devtools/protocol/worker_handler.cc',
- 'browser/devtools/protocol/worker_handler.h',
- 'browser/devtools/render_view_devtools_agent_host.cc',
- 'browser/devtools/render_view_devtools_agent_host.h',
- 'browser/devtools/tethering_handler.h',
- 'browser/devtools/tethering_handler.cc',
- 'browser/device_monitor_mac.h',
- 'browser/device_monitor_mac.mm',
- 'browser/device_monitor_udev.cc',
- 'browser/device_monitor_udev.h',
- 'browser/device_sensors/data_fetcher_shared_memory.h',
- 'browser/device_sensors/data_fetcher_shared_memory_android.cc',
- 'browser/device_sensors/data_fetcher_shared_memory_base.cc',
- 'browser/device_sensors/data_fetcher_shared_memory_base.h',
- 'browser/device_sensors/data_fetcher_shared_memory_default.cc',
- 'browser/device_sensors/data_fetcher_shared_memory_mac.cc',
- 'browser/device_sensors/data_fetcher_shared_memory_win.cc',
- 'browser/device_sensors/device_inertial_sensor_service.cc',
- 'browser/device_sensors/device_inertial_sensor_service.h',
- 'browser/device_sensors/device_light_message_filter.cc',
- 'browser/device_sensors/device_light_message_filter.h',
- 'browser/device_sensors/device_motion_message_filter.cc',
- 'browser/device_sensors/device_motion_message_filter.h',
- 'browser/device_sensors/device_orientation_message_filter.cc',
- 'browser/device_sensors/device_orientation_message_filter.h',
- 'browser/device_sensors/inertial_sensor_consts.h',
- 'browser/device_sensors/sensor_manager_android.cc',
- 'browser/device_sensors/sensor_manager_android.h',
+ 'browser/devtools/render_frame_devtools_agent_host.cc',
+ 'browser/devtools/render_frame_devtools_agent_host.h',
+ 'browser/devtools/service_worker_devtools_agent_host.cc',
+ 'browser/devtools/service_worker_devtools_agent_host.h',
+ 'browser/devtools/service_worker_devtools_manager.cc',
+ 'browser/devtools/service_worker_devtools_manager.h',
+ 'browser/devtools/shared_worker_devtools_agent_host.cc',
+ 'browser/devtools/shared_worker_devtools_agent_host.h',
+ 'browser/devtools/shared_worker_devtools_manager.cc',
+ 'browser/devtools/shared_worker_devtools_manager.h',
+ 'browser/devtools/worker_devtools_agent_host.cc',
+ 'browser/devtools/worker_devtools_agent_host.h',
'browser/dom_storage/dom_storage_area.cc',
'browser/dom_storage/dom_storage_area.h',
'browser/dom_storage/dom_storage_context_impl.cc',
@@ -591,6 +681,8 @@
'browser/frame_host/debug_urls.h',
'browser/frame_host/frame_accessibility.cc',
'browser/frame_host/frame_accessibility.h',
+ 'browser/frame_host/frame_navigation_entry.cc',
+ 'browser/frame_host/frame_navigation_entry.h',
'browser/frame_host/frame_tree.cc',
'browser/frame_host/frame_tree.h',
'browser/frame_host/frame_tree_node.cc',
@@ -614,10 +706,10 @@
'browser/frame_host/navigation_request_info.h',
'browser/frame_host/navigator.cc',
'browser/frame_host/navigator.h',
- 'browser/frame_host/navigator_impl.cc',
- 'browser/frame_host/navigator_impl.h',
'browser/frame_host/navigator_delegate.cc',
'browser/frame_host/navigator_delegate.h',
+ 'browser/frame_host/navigator_impl.cc',
+ 'browser/frame_host/navigator_impl.h',
'browser/frame_host/popup_menu_helper_mac.h',
'browser/frame_host/popup_menu_helper_mac.mm',
'browser/frame_host/render_frame_host_delegate.cc',
@@ -668,10 +760,10 @@
'browser/geofencing/geofencing_registration_delegate.h',
'browser/geofencing/geofencing_service.cc',
'browser/geofencing/geofencing_service.h',
+ 'browser/geofencing/mock_geofencing_service.cc',
+ 'browser/geofencing/mock_geofencing_service.h',
'browser/geolocation/empty_wifi_data_provider.cc',
'browser/geolocation/empty_wifi_data_provider.h',
- 'browser/geolocation/geolocation_dispatcher_host.cc',
- 'browser/geolocation/geolocation_dispatcher_host.h',
'browser/geolocation/geolocation_provider_impl.cc',
'browser/geolocation/geolocation_provider_impl.h',
'browser/geolocation/geolocation_service_context.cc',
@@ -724,8 +816,6 @@
'browser/gpu/gpu_data_manager_impl_private.h',
'browser/gpu/gpu_internals_ui.cc',
'browser/gpu/gpu_internals_ui.h',
- 'browser/gpu/gpu_memory_buffer_factory_host_impl.cc',
- 'browser/gpu/gpu_memory_buffer_factory_host_impl.h',
'browser/gpu/gpu_process_host.cc',
'browser/gpu/gpu_process_host.h',
'browser/gpu/gpu_process_host_ui_shim.cc',
@@ -743,6 +833,8 @@
'browser/histogram_subscriber.h',
'browser/histogram_synchronizer.cc',
'browser/histogram_synchronizer.h',
+ 'browser/host_zoom_level_context.cc',
+ 'browser/host_zoom_level_context.h',
'browser/host_zoom_map_impl.cc',
'browser/host_zoom_map_impl.h',
'browser/indexed_db/indexed_db.h',
@@ -766,6 +858,7 @@
'browser/indexed_db/indexed_db_database.h',
'browser/indexed_db/indexed_db_database_callbacks.cc',
'browser/indexed_db/indexed_db_database_callbacks.h',
+ 'browser/indexed_db/indexed_db_database_error.cc',
'browser/indexed_db/indexed_db_database_error.h',
'browser/indexed_db/indexed_db_dispatcher_host.cc',
'browser/indexed_db/indexed_db_dispatcher_host.h',
@@ -784,12 +877,13 @@
'browser/indexed_db/indexed_db_pending_connection.h',
'browser/indexed_db/indexed_db_quota_client.cc',
'browser/indexed_db/indexed_db_quota_client.h',
+ 'browser/indexed_db/indexed_db_response_value.h',
'browser/indexed_db/indexed_db_transaction.cc',
'browser/indexed_db/indexed_db_transaction.h',
'browser/indexed_db/indexed_db_transaction_coordinator.cc',
'browser/indexed_db/indexed_db_transaction_coordinator.h',
- 'browser/indexed_db/indexed_db_value.h',
'browser/indexed_db/indexed_db_value.cc',
+ 'browser/indexed_db/indexed_db_value.h',
'browser/indexed_db/leveldb/leveldb_comparator.h',
'browser/indexed_db/leveldb/leveldb_database.cc',
'browser/indexed_db/leveldb/leveldb_database.h',
@@ -861,6 +955,8 @@
'browser/loader/upload_data_stream_builder.h',
'browser/mach_broker_mac.h',
'browser/mach_broker_mac.mm',
+ 'browser/manifest/manifest_manager_host.cc',
+ 'browser/manifest/manifest_manager_host.h',
'browser/media/android/browser_demuxer_android.cc',
'browser/media/android/browser_demuxer_android.h',
'browser/media/android/browser_media_player_manager.cc',
@@ -869,12 +965,22 @@
'browser/media/android/media_drm_credential_manager.h',
'browser/media/android/media_resource_getter_impl.cc',
'browser/media/android/media_resource_getter_impl.h',
+ 'browser/media/audio_state_provider.cc',
+ 'browser/media/audio_state_provider.h',
'browser/media/audio_stream_monitor.cc',
'browser/media/audio_stream_monitor.h',
+ 'browser/media/capture/animated_content_sampler.cc',
+ 'browser/media/capture/animated_content_sampler.h',
'browser/media/capture/audio_mirroring_manager.cc',
'browser/media/capture/audio_mirroring_manager.h',
+ 'browser/media/capture/capture_resolution_chooser.cc',
+ 'browser/media/capture/capture_resolution_chooser.h',
'browser/media/capture/content_video_capture_device_core.cc',
'browser/media/capture/content_video_capture_device_core.h',
+ 'browser/media/capture/feedback_signal_accumulator.cc',
+ 'browser/media/capture/feedback_signal_accumulator.h',
+ 'browser/media/capture/smooth_event_sampler.cc',
+ 'browser/media/capture/smooth_event_sampler.h',
'browser/media/capture/video_capture_oracle.cc',
'browser/media/capture/video_capture_oracle.h',
'browser/media/capture/web_contents_audio_input_stream.cc',
@@ -895,26 +1001,31 @@
'browser/media/media_internals_proxy.h',
'browser/media/media_internals_ui.cc',
'browser/media/media_internals_ui.h',
- 'browser/media/midi_dispatcher_host.cc',
- 'browser/media/midi_dispatcher_host.h',
'browser/media/midi_host.cc',
'browser/media/midi_host.h',
'browser/media/webrtc_identity_store.cc',
'browser/media/webrtc_identity_store.h',
'browser/media/webrtc_identity_store_backend.cc',
'browser/media/webrtc_identity_store_backend.h',
- 'browser/manifest/manifest_manager_host.cc',
- 'browser/manifest/manifest_manager_host.h',
'browser/message_port_message_filter.cc',
'browser/message_port_message_filter.h',
+ 'browser/message_port_provider.cc',
'browser/message_port_service.cc',
'browser/message_port_service.h',
'browser/mime_registry_message_filter.cc',
'browser/mime_registry_message_filter.h',
'browser/mojo/mojo_application_host.cc',
'browser/mojo/mojo_application_host.h',
+ 'browser/mojo/service_registrar_android.cc',
+ 'browser/mojo/service_registrar_android.h',
'browser/mojo/service_registry_android.cc',
'browser/mojo/service_registry_android.h',
+ 'browser/navigator_connect/navigator_connect_context_impl.cc',
+ 'browser/navigator_connect/navigator_connect_context_impl.h',
+ 'browser/navigator_connect/navigator_connect_dispatcher_host.cc',
+ 'browser/navigator_connect/navigator_connect_dispatcher_host.h',
+ 'browser/navigator_connect/navigator_connect_service_worker_service_factory.cc',
+ 'browser/navigator_connect/navigator_connect_service_worker_service_factory.h',
'browser/net/browser_online_state_observer.cc',
'browser/net/browser_online_state_observer.h',
'browser/net/sqlite_persistent_cookie_store.cc',
@@ -923,12 +1034,24 @@
'browser/net/view_blob_internals_job_factory.h',
'browser/net/view_http_cache_job_factory.cc',
'browser/net/view_http_cache_job_factory.h',
+ 'browser/notification_service_impl.cc',
+ 'browser/notification_service_impl.h',
+ 'browser/notifications/notification_database.cc',
+ 'browser/notifications/notification_database.h',
+ 'browser/notifications/notification_database_data_conversions.cc',
+ 'browser/notifications/notification_database_data_conversions.h',
+ 'browser/notifications/notification_event_dispatcher_impl.cc',
+ 'browser/notifications/notification_event_dispatcher_impl.h',
'browser/notifications/notification_message_filter.cc',
'browser/notifications/notification_message_filter.h',
'browser/notifications/page_notification_delegate.cc',
'browser/notifications/page_notification_delegate.h',
- 'browser/notification_service_impl.cc',
- 'browser/notification_service_impl.h',
+ 'browser/notifications/platform_notification_context_impl.cc',
+ 'browser/notifications/platform_notification_context_impl.h',
+ 'browser/permissions/permission_service_context.cc',
+ 'browser/permissions/permission_service_context.h',
+ 'browser/permissions/permission_service_impl.cc',
+ 'browser/permissions/permission_service_impl.h',
'browser/power_monitor_message_broadcaster.cc',
'browser/power_monitor_message_broadcaster.h',
'browser/power_profiler/power_data_provider.h',
@@ -946,6 +1069,12 @@
'browser/power_save_blocker_ozone.cc',
'browser/power_save_blocker_win.cc',
'browser/power_save_blocker_x11.cc',
+ 'browser/power_usage_monitor_impl.cc',
+ 'browser/power_usage_monitor_impl.h',
+ 'browser/presentation/presentation_service_impl.cc',
+ 'browser/presentation/presentation_service_impl.h',
+ 'browser/presentation/presentation_type_converters.cc',
+ 'browser/presentation/presentation_type_converters.h',
'browser/profiler_controller_impl.cc',
'browser/profiler_controller_impl.h',
'browser/profiler_message_filter.cc',
@@ -957,6 +1086,8 @@
'browser/quota_dispatcher_host.cc',
'browser/quota_dispatcher_host.h',
'browser/renderer_data_memoizing_store.h',
+ 'browser/renderer_host/begin_frame_observer_proxy.cc',
+ 'browser/renderer_host/begin_frame_observer_proxy.h',
'browser/renderer_host/clipboard_message_filter.cc',
'browser/renderer_host/clipboard_message_filter.h',
'browser/renderer_host/clipboard_message_filter_mac.mm',
@@ -970,38 +1101,40 @@
'browser/renderer_host/delegated_frame_evictor.h',
'browser/renderer_host/dip_util.cc',
'browser/renderer_host/dip_util.h',
- 'browser/renderer_host/display_link_mac.h',
'browser/renderer_host/display_link_mac.cc',
+ 'browser/renderer_host/display_link_mac.h',
'browser/renderer_host/event_with_latency_info.h',
'browser/renderer_host/file_utilities_message_filter.cc',
'browser/renderer_host/file_utilities_message_filter.h',
'browser/renderer_host/font_utils_linux.cc',
'browser/renderer_host/font_utils_linux.h',
+ 'browser/renderer_host/frame_metadata_util.cc',
+ 'browser/renderer_host/frame_metadata_util.h',
'browser/renderer_host/gamepad_browser_message_filter.cc',
'browser/renderer_host/gamepad_browser_message_filter.h',
'browser/renderer_host/gpu_message_filter.cc',
'browser/renderer_host/gpu_message_filter.h',
- 'browser/renderer_host/image_transport_factory_android.cc',
- 'browser/renderer_host/image_transport_factory_android.h',
'browser/renderer_host/ime_adapter_android.cc',
'browser/renderer_host/ime_adapter_android.h',
'browser/renderer_host/input/gesture_event_queue.cc',
'browser/renderer_host/input/gesture_event_queue.h',
- 'browser/renderer_host/input/gesture_text_selector.cc',
- 'browser/renderer_host/input/gesture_text_selector.h',
'browser/renderer_host/input/input_ack_handler.h',
'browser/renderer_host/input/input_router.h',
'browser/renderer_host/input/input_router_client.h',
- 'browser/renderer_host/input/input_router_impl.cc',
- 'browser/renderer_host/input/input_router_impl.h',
'browser/renderer_host/input/input_router_config_helper.cc',
'browser/renderer_host/input/input_router_config_helper.h',
+ 'browser/renderer_host/input/input_router_impl.cc',
+ 'browser/renderer_host/input/input_router_impl.h',
'browser/renderer_host/input/motion_event_android.cc',
'browser/renderer_host/input/motion_event_android.h',
'browser/renderer_host/input/motion_event_web.cc',
'browser/renderer_host/input/motion_event_web.h',
- 'browser/renderer_host/input/selection_event_type.h',
- 'browser/renderer_host/input/selection_event_type_list.h',
+ 'browser/renderer_host/input/mouse_wheel_rails_filter_mac.cc',
+ 'browser/renderer_host/input/mouse_wheel_rails_filter_mac.h',
+ 'browser/renderer_host/input/render_widget_host_latency_tracker.cc',
+ 'browser/renderer_host/input/render_widget_host_latency_tracker.h',
+ 'browser/renderer_host/input/stylus_text_selector.cc',
+ 'browser/renderer_host/input/stylus_text_selector.h',
'browser/renderer_host/input/synthetic_gesture.cc',
'browser/renderer_host/input/synthetic_gesture.h',
'browser/renderer_host/input/synthetic_gesture_controller.cc',
@@ -1015,6 +1148,10 @@
'browser/renderer_host/input/synthetic_gesture_target_base.h',
'browser/renderer_host/input/synthetic_pinch_gesture.cc',
'browser/renderer_host/input/synthetic_pinch_gesture.h',
+ 'browser/renderer_host/input/synthetic_smooth_drag_gesture.cc',
+ 'browser/renderer_host/input/synthetic_smooth_drag_gesture.h',
+ 'browser/renderer_host/input/synthetic_smooth_move_gesture.cc',
+ 'browser/renderer_host/input/synthetic_smooth_move_gesture.h',
'browser/renderer_host/input/synthetic_smooth_scroll_gesture.cc',
'browser/renderer_host/input/synthetic_smooth_scroll_gesture.h',
'browser/renderer_host/input/synthetic_tap_gesture.cc',
@@ -1024,17 +1161,13 @@
'browser/renderer_host/input/tap_suppression_controller_client.h',
'browser/renderer_host/input/timeout_monitor.cc',
'browser/renderer_host/input/timeout_monitor.h',
+ 'browser/renderer_host/input/touch_action_filter.cc',
+ 'browser/renderer_host/input/touch_action_filter.h',
'browser/renderer_host/input/touch_emulator.cc',
'browser/renderer_host/input/touch_emulator.h',
'browser/renderer_host/input/touch_emulator_client.h',
'browser/renderer_host/input/touch_event_queue.cc',
'browser/renderer_host/input/touch_event_queue.h',
- 'browser/renderer_host/input/touch_action_filter.cc',
- 'browser/renderer_host/input/touch_action_filter.h',
- 'browser/renderer_host/input/touch_handle.cc',
- 'browser/renderer_host/input/touch_handle.h',
- 'browser/renderer_host/input/touch_selection_controller.cc',
- 'browser/renderer_host/input/touch_selection_controller.h',
'browser/renderer_host/input/touchpad_tap_suppression_controller.cc',
'browser/renderer_host/input/touchpad_tap_suppression_controller.h',
'browser/renderer_host/input/touchscreen_tap_suppression_controller.cc',
@@ -1075,15 +1208,15 @@
'browser/renderer_host/media/video_capture_buffer_pool.h',
'browser/renderer_host/media/video_capture_controller.cc',
'browser/renderer_host/media/video_capture_controller.h',
- 'browser/renderer_host/media/video_capture_controller_event_handler.cc',
'browser/renderer_host/media/video_capture_controller_event_handler.h',
+ 'browser/renderer_host/media/video_capture_device_client.cc',
+ 'browser/renderer_host/media/video_capture_device_client.h',
'browser/renderer_host/media/video_capture_host.cc',
'browser/renderer_host/media/video_capture_host.h',
'browser/renderer_host/media/video_capture_manager.cc',
'browser/renderer_host/media/video_capture_manager.h',
'browser/renderer_host/memory_benchmark_message_filter.cc',
'browser/renderer_host/memory_benchmark_message_filter.h',
- 'browser/renderer_host/native_web_keyboard_event.cc',
'browser/renderer_host/native_web_keyboard_event_android.cc',
'browser/renderer_host/native_web_keyboard_event_aura.cc',
'browser/renderer_host/native_web_keyboard_event_mac.mm',
@@ -1116,20 +1249,18 @@
'browser/renderer_host/render_widget_host_view_aura.h',
'browser/renderer_host/render_widget_host_view_base.cc',
'browser/renderer_host/render_widget_host_view_base.h',
+ 'browser/renderer_host/render_widget_host_view_mac.h',
+ 'browser/renderer_host/render_widget_host_view_mac.mm',
'browser/renderer_host/render_widget_host_view_mac_dictionary_helper.h',
'browser/renderer_host/render_widget_host_view_mac_dictionary_helper.mm',
'browser/renderer_host/render_widget_host_view_mac_editcommand_helper.h',
'browser/renderer_host/render_widget_host_view_mac_editcommand_helper.mm',
- 'browser/renderer_host/render_widget_host_view_mac.h',
- 'browser/renderer_host/render_widget_host_view_mac.mm',
'browser/renderer_host/render_widget_resize_helper.cc',
'browser/renderer_host/render_widget_resize_helper.h',
'browser/renderer_host/renderer_frame_manager.cc',
'browser/renderer_host/renderer_frame_manager.h',
'browser/renderer_host/sandbox_ipc_linux.cc',
'browser/renderer_host/sandbox_ipc_linux.h',
- 'browser/renderer_host/software_frame_manager.cc',
- 'browser/renderer_host/software_frame_manager.h',
'browser/renderer_host/text_input_client_mac.h',
'browser/renderer_host/text_input_client_mac.mm',
'browser/renderer_host/text_input_client_message_filter.h',
@@ -1155,27 +1286,19 @@
'browser/screen_orientation/screen_orientation_delegate_android.h',
'browser/screen_orientation/screen_orientation_dispatcher_host_impl.cc',
'browser/screen_orientation/screen_orientation_dispatcher_host_impl.h',
- 'browser/screen_orientation/screen_orientation_message_filter_android.h',
'browser/screen_orientation/screen_orientation_message_filter_android.cc',
+ 'browser/screen_orientation/screen_orientation_message_filter_android.h',
'browser/service_worker/embedded_worker_instance.cc',
'browser/service_worker/embedded_worker_instance.h',
'browser/service_worker/embedded_worker_registry.cc',
'browser/service_worker/embedded_worker_registry.h',
- 'browser/service_worker/service_worker_cache.cc',
- 'browser/service_worker/service_worker_cache.h',
- 'browser/service_worker/service_worker_cache_listener.cc',
- 'browser/service_worker/service_worker_cache_listener.h',
- 'browser/service_worker/service_worker_cache_quota_client.cc',
- 'browser/service_worker/service_worker_cache_quota_client.h',
- 'browser/service_worker/service_worker_cache_storage.cc',
- 'browser/service_worker/service_worker_cache_storage.h',
- 'browser/service_worker/service_worker_cache_storage_manager.cc',
- 'browser/service_worker/service_worker_cache_storage_manager.h',
'browser/service_worker/service_worker_context_core.cc',
'browser/service_worker/service_worker_context_core.h',
'browser/service_worker/service_worker_context_observer.h',
'browser/service_worker/service_worker_context_request_handler.cc',
'browser/service_worker/service_worker_context_request_handler.h',
+ 'browser/service_worker/service_worker_context_watcher.cc',
+ 'browser/service_worker/service_worker_context_watcher.h',
'browser/service_worker/service_worker_context_wrapper.cc',
'browser/service_worker/service_worker_context_wrapper.h',
'browser/service_worker/service_worker_controllee_request_handler.cc',
@@ -1208,9 +1331,9 @@
'browser/service_worker/service_worker_quota_client.h',
'browser/service_worker/service_worker_read_from_cache_job.cc',
'browser/service_worker/service_worker_read_from_cache_job.h',
- 'browser/service_worker/service_worker_register_job_base.h',
'browser/service_worker/service_worker_register_job.cc',
'browser/service_worker/service_worker_register_job.h',
+ 'browser/service_worker/service_worker_register_job_base.h',
'browser/service_worker/service_worker_registration.cc',
'browser/service_worker/service_worker_registration.h',
'browser/service_worker/service_worker_registration_handle.cc',
@@ -1284,34 +1407,37 @@
'browser/ssl/ssl_error_handler.h',
'browser/ssl/ssl_manager.cc',
'browser/ssl/ssl_manager.h',
- 'browser/ssl/ssl_policy_backend.cc',
- 'browser/ssl/ssl_policy_backend.h',
'browser/ssl/ssl_policy.cc',
'browser/ssl/ssl_policy.h',
+ 'browser/ssl/ssl_policy_backend.cc',
+ 'browser/ssl/ssl_policy_backend.h',
'browser/ssl/ssl_request_info.cc',
'browser/ssl/ssl_request_info.h',
'browser/startup_task_runner.cc',
'browser/startup_task_runner.h',
+ 'browser/storage_partition_impl.cc',
+ 'browser/storage_partition_impl.h',
+ 'browser/storage_partition_impl_map.cc',
+ 'browser/storage_partition_impl_map.h',
'browser/streams/stream.cc',
'browser/streams/stream.h',
'browser/streams/stream_context.cc',
+ 'browser/streams/stream_context.h',
'browser/streams/stream_handle_impl.cc',
'browser/streams/stream_handle_impl.h',
- 'browser/streams/stream_context.h',
'browser/streams/stream_read_observer.h',
+ 'browser/streams/stream_register_observer.h',
'browser/streams/stream_registry.cc',
'browser/streams/stream_registry.h',
'browser/streams/stream_url_request_job.cc',
'browser/streams/stream_url_request_job.h',
'browser/streams/stream_write_observer.h',
- 'browser/storage_partition_impl.cc',
- 'browser/storage_partition_impl.h',
- 'browser/storage_partition_impl_map.cc',
- 'browser/storage_partition_impl_map.h',
'browser/system_message_window_win.cc',
'browser/system_message_window_win.h',
'browser/tcmalloc_internals_request_job.cc',
'browser/tcmalloc_internals_request_job.h',
+ 'browser/theme_helper_mac.h',
+ 'browser/theme_helper_mac.mm',
'browser/time_zone_monitor.cc',
'browser/time_zone_monitor.h',
'browser/time_zone_monitor_android.cc',
@@ -1320,16 +1446,16 @@
'browser/time_zone_monitor_linux.cc',
'browser/time_zone_monitor_mac.mm',
'browser/time_zone_monitor_win.cc',
- 'browser/theme_helper_mac.mm',
- 'browser/theme_helper_mac.h',
- 'browser/tracing/trace_message_filter.cc',
- 'browser/tracing/trace_message_filter.h',
'browser/tracing/etw_system_event_consumer_win.cc',
'browser/tracing/etw_system_event_consumer_win.h',
- 'browser/tracing/trace_uploader.cc',
- 'browser/tracing/trace_uploader.h',
+ 'browser/tracing/file_tracing_provider_impl.cc',
+ 'browser/tracing/file_tracing_provider_impl.h',
+ 'browser/tracing/trace_message_filter.cc',
+ 'browser/tracing/trace_message_filter.h',
'browser/tracing/tracing_controller_impl.cc',
'browser/tracing/tracing_controller_impl.h',
+ 'browser/tracing/tracing_controller_impl_data_sinks.cc',
+ 'browser/tracing/tracing_controller_impl_data_sinks.h',
'browser/tracing/tracing_ui.cc',
'browser/tracing/tracing_ui.h',
'browser/transition_request_manager.cc',
@@ -1339,20 +1465,16 @@
'browser/user_metrics.cc',
'browser/utility_process_host_impl.cc',
'browser/utility_process_host_impl.h',
- 'browser/vibration/vibration_message_filter.cc',
- 'browser/vibration/vibration_message_filter.h',
- 'browser/vibration/vibration_provider_android.cc',
- 'browser/vibration/vibration_provider_android.h',
'browser/web_contents/aura/gesture_nav_simple.cc',
'browser/web_contents/aura/gesture_nav_simple.h',
- 'browser/web_contents/aura/image_window_delegate.cc',
- 'browser/web_contents/aura/image_window_delegate.h',
'browser/web_contents/aura/overscroll_navigation_overlay.cc',
'browser/web_contents/aura/overscroll_navigation_overlay.h',
+ 'browser/web_contents/aura/overscroll_window_animation.cc',
+ 'browser/web_contents/aura/overscroll_window_animation.h',
+ 'browser/web_contents/aura/overscroll_window_delegate.cc',
+ 'browser/web_contents/aura/overscroll_window_delegate.h',
'browser/web_contents/aura/shadow_layer_delegate.cc',
'browser/web_contents/aura/shadow_layer_delegate.h',
- 'browser/web_contents/aura/window_slider.cc',
- 'browser/web_contents/aura/window_slider.h',
'browser/web_contents/touch_editable_impl_aura.cc',
'browser/web_contents/touch_editable_impl_aura.h',
'browser/web_contents/web_contents_android.cc',
@@ -1386,10 +1508,10 @@
'browser/webui/url_data_manager_backend.h',
'browser/webui/url_data_source_impl.cc',
'browser/webui/url_data_source_impl.h',
- 'browser/webui/web_ui_data_source_impl.cc',
- 'browser/webui/web_ui_data_source_impl.h',
'browser/webui/web_ui_controller_factory_registry.cc',
'browser/webui/web_ui_controller_factory_registry.h',
+ 'browser/webui/web_ui_data_source_impl.cc',
+ 'browser/webui/web_ui_data_source_impl.h',
'browser/webui/web_ui_impl.cc',
'browser/webui/web_ui_impl.h',
'browser/webui/web_ui_message_handler.cc',
@@ -1398,18 +1520,6 @@
'zygote/zygote_linux.cc',
'zygote/zygote_linux.h',
'zygote/zygote_main_linux.cc',
- # These files are generated by GRIT.
- '<(SHARED_INTERMEDIATE_DIR)/webkit/grit/devtools_resources.h',
- '<(SHARED_INTERMEDIATE_DIR)/webkit/grit/devtools_resources_map.cc',
- '<(SHARED_INTERMEDIATE_DIR)/webkit/grit/devtools_resources_map.h',
- '<(SHARED_INTERMEDIATE_DIR)/content/browser/tracing/grit/tracing_resources.h',
- '<(SHARED_INTERMEDIATE_DIR)/ui/resources/grit/webui_resources_map.cc',
- # These files are generated by devtools_protocol_constants_generator.py.
- '<(SHARED_INTERMEDIATE_DIR)/content/browser/devtools/devtools_protocol_constants.cc',
- '<(SHARED_INTERMEDIATE_DIR)/content/browser/devtools/devtools_protocol_constants.h',
- # These files are generated by devtools_protocol_handler_generator.py.
- '<(SHARED_INTERMEDIATE_DIR)/content/browser/devtools/protocol/devtools_protocol_handler_impl.cc',
- '<(SHARED_INTERMEDIATE_DIR)/content/browser/devtools/protocol/devtools_protocol_handler_impl.h',
],
'android_browser_sources': [
'browser/android/java/gin_java_bound_object.cc',
@@ -1441,6 +1551,8 @@
'browser/renderer_host/media/peer_connection_tracker_host.h',
'browser/renderer_host/media/webrtc_identity_service_host.cc',
'browser/renderer_host/media/webrtc_identity_service_host.h',
+ 'browser/renderer_host/p2p/socket_dispatcher_host.cc',
+ 'browser/renderer_host/p2p/socket_dispatcher_host.h',
'browser/renderer_host/p2p/socket_host.cc',
'browser/renderer_host/p2p/socket_host.h',
'browser/renderer_host/p2p/socket_host_tcp.cc',
@@ -1451,60 +1563,47 @@
'browser/renderer_host/p2p/socket_host_throttler.h',
'browser/renderer_host/p2p/socket_host_udp.cc',
'browser/renderer_host/p2p/socket_host_udp.h',
- 'browser/renderer_host/p2p/socket_dispatcher_host.cc',
- 'browser/renderer_host/p2p/socket_dispatcher_host.h',
],
'compositor_browser_sources': [
- 'browser/compositor/browser_compositor_ca_layer_tree_mac.mm',
- 'browser/compositor/browser_compositor_ca_layer_tree_mac.h',
'browser/compositor/browser_compositor_output_surface.cc',
'browser/compositor/browser_compositor_output_surface.h',
- 'browser/compositor/browser_compositor_output_surface_proxy.cc',
- 'browser/compositor/browser_compositor_output_surface_proxy.h',
- 'browser/compositor/browser_compositor_view_mac.mm',
+ 'browser/compositor/browser_compositor_overlay_candidate_validator.h',
+ 'browser/compositor/browser_compositor_overlay_candidate_validator_ozone.cc',
+ 'browser/compositor/browser_compositor_overlay_candidate_validator_ozone.h',
'browser/compositor/browser_compositor_view_mac.h',
+ 'browser/compositor/browser_compositor_view_mac.mm',
'browser/compositor/buffer_queue.cc',
'browser/compositor/buffer_queue.h',
'browser/compositor/delegated_frame_host.cc',
'browser/compositor/delegated_frame_host.h',
+ 'browser/compositor/gpu_browser_compositor_output_surface.cc',
+ 'browser/compositor/gpu_browser_compositor_output_surface.h',
'browser/compositor/gpu_process_transport_factory.cc',
'browser/compositor/gpu_process_transport_factory.h',
+ 'browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc',
+ 'browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h',
'browser/compositor/image_transport_factory.cc',
'browser/compositor/image_transport_factory.h',
- 'browser/compositor/io_surface_context_mac.h',
- 'browser/compositor/io_surface_context_mac.mm',
- 'browser/compositor/io_surface_layer_mac.h',
- 'browser/compositor/io_surface_layer_mac.mm',
- 'browser/compositor/io_surface_texture_mac.h',
- 'browser/compositor/io_surface_texture_mac.mm',
- 'browser/compositor/onscreen_display_client.cc',
- 'browser/compositor/onscreen_display_client.h',
- 'browser/compositor/overlay_candidate_validator_ozone.cc',
- 'browser/compositor/overlay_candidate_validator_ozone.h',
- 'browser/compositor/owned_mailbox.h',
+ 'browser/compositor/offscreen_browser_compositor_output_surface.cc',
+ 'browser/compositor/offscreen_browser_compositor_output_surface.h',
'browser/compositor/owned_mailbox.cc',
+ 'browser/compositor/owned_mailbox.h',
'browser/compositor/reflector_impl.cc',
'browser/compositor/reflector_impl.h',
+ 'browser/compositor/reflector_texture.cc',
+ 'browser/compositor/reflector_texture.h',
'browser/compositor/resize_lock.cc',
'browser/compositor/resize_lock.h',
- 'browser/compositor/software_layer_mac.mm',
- 'browser/compositor/software_layer_mac.h',
- 'browser/compositor/gpu_browser_compositor_output_surface.cc',
- 'browser/compositor/gpu_browser_compositor_output_surface.h',
- 'browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc',
- 'browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h',
'browser/compositor/software_browser_compositor_output_surface.cc',
'browser/compositor/software_browser_compositor_output_surface.h',
- 'browser/compositor/software_output_device_mac.mm',
'browser/compositor/software_output_device_mac.h',
+ 'browser/compositor/software_output_device_mac.mm',
'browser/compositor/software_output_device_ozone.cc',
'browser/compositor/software_output_device_ozone.h',
'browser/compositor/software_output_device_win.cc',
'browser/compositor/software_output_device_win.h',
'browser/compositor/software_output_device_x11.cc',
'browser/compositor/software_output_device_x11.h',
- 'browser/compositor/surface_display_output_surface.cc',
- 'browser/compositor/surface_display_output_surface.h',
'browser/context_factory.cc',
],
'plugin_browser_sources': [
@@ -1552,10 +1651,10 @@
'browser/renderer_host/pepper/pepper_network_monitor_host.h',
'browser/renderer_host/pepper/pepper_network_proxy_host.cc',
'browser/renderer_host/pepper/pepper_network_proxy_host.h',
- 'browser/renderer_host/pepper/pepper_printing_host.cc',
- 'browser/renderer_host/pepper/pepper_printing_host.h',
'browser/renderer_host/pepper/pepper_print_settings_manager.cc',
'browser/renderer_host/pepper/pepper_print_settings_manager.h',
+ 'browser/renderer_host/pepper/pepper_printing_host.cc',
+ 'browser/renderer_host/pepper/pepper_printing_host.h',
'browser/renderer_host/pepper/pepper_renderer_connection.cc',
'browser/renderer_host/pepper/pepper_renderer_connection.h',
'browser/renderer_host/pepper/pepper_security_helper.cc',
@@ -1571,8 +1670,8 @@
'browser/renderer_host/pepper/pepper_truetype_font_host.cc',
'browser/renderer_host/pepper/pepper_truetype_font_host.h',
'browser/renderer_host/pepper/pepper_truetype_font_linux.cc',
- 'browser/renderer_host/pepper/pepper_truetype_font_list_android.cc',
'browser/renderer_host/pepper/pepper_truetype_font_list.h',
+ 'browser/renderer_host/pepper/pepper_truetype_font_list_android.cc',
'browser/renderer_host/pepper/pepper_truetype_font_list_host.cc',
'browser/renderer_host/pepper/pepper_truetype_font_list_host.h',
'browser/renderer_host/pepper/pepper_truetype_font_list_mac.mm',
@@ -1595,11 +1694,6 @@
'<@(private_browser_sources)',
],
'conditions': [
- ['toolkit_views==1', {
- 'dependencies': [
- '../ui/events/events.gyp:events',
- ],
- }],
['OS == "win"', {
'dependencies': [
'../third_party/power_gadget/power_gadget.gyp:power_gadget',
@@ -1610,9 +1704,9 @@
]
}, { # os != "win"
'sources': [
- 'browser/power_profiler/power_data_provider_dummy.cc',
- 'browser/file_descriptor_info_impl.h',
'browser/file_descriptor_info_impl.cc',
+ 'browser/file_descriptor_info_impl.h',
+ 'browser/power_profiler/power_data_provider_dummy.cc',
]
}],
['OS!="win" and OS!="mac" and OS!="android" and (OS!="linux" or use_udev==0)', {
@@ -1652,18 +1746,28 @@
'app/strings/content_strings.gyp:content_strings',
'browser/devtools/devtools_resources.gyp:devtools_resources',
'browser/devtools/devtools.gyp:devtools_protocol_handler',
- 'content_common_mojo_bindings',
'../cc/cc.gyp:cc',
'../cc/cc.gyp:cc_surfaces',
- '../mojo/public/mojo_public.gyp:mojo_application_bindings',
- '../mojo/public/mojo_public.gyp:mojo_cpp_bindings',
- '../mojo/public/mojo_public.gyp:mojo_js_bindings',
+ '../components/mime_util/mime_util.gyp:mime_util',
+ '../components/scheduler/scheduler.gyp:scheduler_common',
+ '../device/bluetooth/bluetooth.gyp:device_bluetooth',
'../net/net.gyp:http_server',
'../storage/storage_browser.gyp:storage',
'../storage/storage_common.gyp:storage_common',
'../third_party/angle/src/angle.gyp:commit_id',
'../third_party/leveldatabase/leveldatabase.gyp:leveldatabase',
+ '../third_party/mojo/mojo_public.gyp:mojo_cpp_bindings',
+ '../third_party/mojo/mojo_public.gyp:mojo_js_bindings',
'../ui/surface/surface.gyp:surface',
+ '../ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection',
+ ],
+ 'export_dependent_settings': [
+ '../third_party/mojo/mojo_public.gyp:mojo_cpp_bindings',
+ ],
+ }],
+ ['debug_devtools==1', {
+ 'defines': [
+ 'DEBUG_DEVTOOLS=1',
],
}],
['enable_basic_printing==1 or enable_print_preview==1', {
@@ -1714,8 +1818,6 @@
'sources': [
'browser/media/capture/desktop_capture_device.cc',
'browser/media/capture/desktop_capture_device.h',
- 'browser/media/capture/desktop_capture_device_aura.cc',
- 'browser/media/capture/desktop_capture_device_aura.h',
'browser/media/capture/desktop_capture_device_uma_types.cc',
'browser/media/capture/desktop_capture_device_uma_types.h',
],
@@ -1726,6 +1828,14 @@
'ENABLE_SCREEN_CAPTURE=1',
],
}],
+ ['enable_webrtc==1 and use_aura==1', {
+ 'sources': [
+ "browser/media/capture/aura_window_capture_machine.cc",
+ "browser/media/capture/aura_window_capture_machine.h",
+ 'browser/media/capture/desktop_capture_device_aura.cc',
+ 'browser/media/capture/desktop_capture_device_aura.h',
+ ],
+ }],
['OS=="win"', {
'dependencies': [
# For accessibility
@@ -1767,7 +1877,7 @@
}],
['use_udev == 1', {
'dependencies': [
- '../build/linux/system.gyp:udev',
+ '../device/udev_linux/udev.gyp:udev_linux',
],
}, {
'sources!': [
@@ -1786,6 +1896,8 @@
['use_x11==1', {
'dependencies': [
'../build/linux/system.gyp:x11',
+ '../ui/events/platform/x11/x11_events_platform.gyp:x11_events_platform',
+ '../ui/gfx/x/gfx_x11.gyp:gfx_x11',
],
}],
['use_pango==1', {
@@ -1800,6 +1912,7 @@
'dependencies': [
'../media/media.gyp:media',
'../mojo/mojo_base.gyp:libmojo_system_java',
+ '../ui/android/ui_android.gyp:ui_android',
'content.gyp:content_jni_headers',
],
'defines': ['APPCACHE_USE_SIMPLE_CACHE'],
@@ -1823,10 +1936,10 @@
],
'sources!': [
'browser/browser_ipc_logging.cc',
- 'browser/font_list_async.cc',
'browser/geolocation/device_data_provider.cc',
'browser/geolocation/empty_device_data_provider.cc',
'browser/geolocation/wifi_data_provider_common.cc',
+ 'browser/renderer_host/begin_frame_observer_proxy.cc',
'browser/renderer_host/native_web_keyboard_event.cc',
]
}],
@@ -1840,6 +1953,7 @@
'dependencies': [
'../third_party/mozilla/mozilla.gyp:mozilla',
'../third_party/sudden_motion_sensor/sudden_motion_sensor.gyp:sudden_motion_sensor',
+ '../ui/accelerated_widget_mac/accelerated_widget_mac.gyp:accelerated_widget_mac',
],
'link_settings': {
'libraries': [
@@ -1850,9 +1964,11 @@
['chromeos==1', {
'dependencies': [
'../build/linux/system.gyp:dbus',
+ '../chromeos/chromeos.gyp:chromeos',
'../chromeos/chromeos.gyp:power_manager_proto',
],
'sources!': [
+ 'browser/device_sensors/data_fetcher_shared_memory_default.cc',
'browser/geolocation/wifi_data_provider_linux.cc',
'browser/power_save_blocker_ozone.cc',
'browser/power_save_blocker_x11.cc',
@@ -1866,6 +1982,7 @@
['use_aura==1', {
'dependencies': [
'../ui/aura/aura.gyp:aura',
+ '../ui/aura_extra/aura_extra.gyp:aura_extra',
'../ui/strings/ui_strings.gyp:ui_strings',
],
}, {
@@ -1929,5 +2046,10 @@
'browser/media/media_web_contents_observer.h',
],
}],
+ ['OS == "linux" and use_openssl==1', {
+ 'dependencies': [
+ '../third_party/boringssl/boringssl.gyp:boringssl',
+ ],
+ }],
],
}
diff --git a/chromium/content/content_browsertests.isolate b/chromium/content/content_browsertests.isolate
index 53a53fc317a..2fcab670f2a 100644
--- a/chromium/content/content_browsertests.isolate
+++ b/chromium/content/content_browsertests.isolate
@@ -3,6 +3,35 @@
# found in the LICENSE file.
{
'conditions': [
+ ['use_x11==0', {
+ 'variables': {
+ 'command': [
+ '../testing/test_env.py',
+ '<(PRODUCT_DIR)/content_browsertests<(EXECUTABLE_SUFFIX)',
+ '--test-launcher-bot-mode',
+ '--asan=<(asan)',
+ '--msan=<(msan)',
+ '--tsan=<(tsan)',
+ ],
+ },
+ }],
+ ['use_x11==1', {
+ 'variables': {
+ 'command': [
+ '../testing/xvfb.py',
+ '<(PRODUCT_DIR)',
+ '<(PRODUCT_DIR)/content_browsertests<(EXECUTABLE_SUFFIX)',
+ '--test-launcher-bot-mode',
+ '--asan=<(asan)',
+ '--msan=<(msan)',
+ '--tsan=<(tsan)',
+ ],
+ 'files': [
+ '../testing/xvfb.py',
+ '<(PRODUCT_DIR)/xdisplaycheck<(EXECUTABLE_SUFFIX)',
+ ],
+ },
+ }],
['OS=="android"', {
'variables': {
'files': [
@@ -35,27 +64,17 @@
}],
['OS=="linux"', {
'variables': {
- 'command': [
- '../testing/xvfb.py',
- '<(PRODUCT_DIR)',
- '<(PRODUCT_DIR)/content_browsertests<(EXECUTABLE_SUFFIX)',
- '--test-launcher-bot-mode',
- '--asan=<(asan)',
- '--lsan=<(lsan)',
- ],
'files': [
- '../testing/xvfb.py',
'<(PRODUCT_DIR)/content_shell.pak',
'<(PRODUCT_DIR)/libffmpegsumo.so',
'<(PRODUCT_DIR)/libosmesa.so',
- '<(PRODUCT_DIR)/libppapi_tests.so',
],
},
}],
- ['OS=="linux" and use_ozone==0', {
+ ['OS=="linux" and enable_plugins==1', {
'variables': {
'files': [
- '<(PRODUCT_DIR)/xdisplaycheck<(EXECUTABLE_SUFFIX)',
+ '<(PRODUCT_DIR)/libppapi_tests.so',
],
},
}],
@@ -84,14 +103,17 @@
],
},
}],
- ['OS=="mac" or OS=="win"', {
+ ['OS=="mac" and asan==1 and fastbuild==0', {
'variables': {
- 'command': [
- '../testing/test_env.py',
- '<(PRODUCT_DIR)/content_browsertests<(EXECUTABLE_SUFFIX)',
- '--test-launcher-bot-mode',
- '--asan=<(asan)',
- '--lsan=<(lsan)',
+ 'files': [
+ '<(PRODUCT_DIR)/Content Shell Framework.framework.dSYM/',
+ '<(PRODUCT_DIR)/Content Shell Helper.app.dSYM/',
+ '<(PRODUCT_DIR)/Content Shell.app.dSYM/',
+ '<(PRODUCT_DIR)/content_browsertests.dSYM/',
+ '<(PRODUCT_DIR)/ffmpegsumo.so.dSYM/',
+ '<(PRODUCT_DIR)/npapi_test_plugin.plugin.dSYM/',
+ '<(PRODUCT_DIR)/ppapi_tests.plugin.dSYM/',
+ '<(PRODUCT_DIR)/test_netscape_plugin.plugin.dSYM/',
],
},
}],
@@ -125,5 +147,6 @@
'includes': [
'../base/base.isolate',
'../gin/v8.isolate',
+ '../third_party/angle/angle.isolate',
],
}
diff --git a/chromium/content/content_child.gypi b/chromium/content/content_child.gypi
index c51317f3c76..e32039d896c 100644
--- a/chromium/content/content_child.gypi
+++ b/chromium/content/content_child.gypi
@@ -5,15 +5,18 @@
{
'dependencies': [
'../base/base.gyp:base',
+ '../components/mime_util/mime_util.gyp:mime_util',
'../components/tracing.gyp:tracing',
+ '../components/webcrypto/webcrypto.gyp:webcrypto',
'../mojo/mojo_base.gyp:mojo_environment_chromium',
'../mojo/mojo_base.gyp:mojo_common_lib',
- '../mojo/public/mojo_public.gyp:mojo_application_bindings',
'../skia/skia.gyp:skia',
'../ui/base/ui_base.gyp:ui_base',
+ '../ui/events/events.gyp:gestures_blink',
'../ui/gfx/gfx.gyp:gfx',
'../ui/gfx/gfx.gyp:gfx_geometry',
'../url/url.gyp:url_lib',
+ 'content_common_mojo_bindings.gyp:content_common_mojo_bindings',
],
'include_dirs': [
'..',
@@ -23,9 +26,11 @@
],
'variables': {
'public_child_sources': [
+ 'public/child/child_thread.h',
'public/child/image_decoder_utils.h',
'public/child/request_peer.h',
'public/child/resource_dispatcher_delegate.h',
+ 'public/child/v8_value_converter.h',
],
'private_child_sources': [
'child/appcache/appcache_backend_proxy.cc',
@@ -37,8 +42,18 @@
'child/appcache/web_application_cache_host_impl.cc',
'child/appcache/web_application_cache_host_impl.h',
'child/assert_matching_enums.cc',
+ 'child/background_sync/background_sync_provider_thread_proxy.cc',
+ 'child/background_sync/background_sync_provider_thread_proxy.h',
+ 'child/background_sync/background_sync_provider.cc',
+ 'child/background_sync/background_sync_provider.h',
+ 'child/background_sync/background_sync_type_converters.cc',
+ 'child/background_sync/background_sync_type_converters.h',
'child/blink_platform_impl.cc',
'child/blink_platform_impl.h',
+ 'child/bluetooth/bluetooth_dispatcher.cc',
+ 'child/bluetooth/bluetooth_dispatcher.h',
+ 'child/bluetooth/bluetooth_message_filter.cc',
+ 'child/bluetooth/bluetooth_message_filter.h',
'child/bluetooth/web_bluetooth_impl.cc',
'child/bluetooth/web_bluetooth_impl.h',
'child/browser_font_resource_trusted.cc',
@@ -57,8 +72,8 @@
'child/child_resource_message_filter.h',
'child/child_shared_bitmap_manager.cc',
'child/child_shared_bitmap_manager.h',
- 'child/child_thread.cc',
- 'child/child_thread.h',
+ 'child/child_thread_impl.cc',
+ 'child/child_thread_impl.h',
'child/content_child_helpers.cc',
'child/content_child_helpers.h',
'child/database_util.cc',
@@ -101,10 +116,20 @@
'child/mojo/mojo_application.h',
'child/multipart_response_delegate.cc',
'child/multipart_response_delegate.h',
+ 'child/navigator_connect/navigator_connect_dispatcher.cc',
+ 'child/navigator_connect/navigator_connect_dispatcher.h',
+ 'child/navigator_connect/navigator_connect_provider.cc',
+ 'child/navigator_connect/navigator_connect_provider.h',
+ 'child/notifications/notification_data_conversions.cc',
+ 'child/notifications/notification_data_conversions.h',
'child/notifications/notification_dispatcher.cc',
'child/notifications/notification_dispatcher.h',
+ 'child/notifications/notification_image_loader.cc',
+ 'child/notifications/notification_image_loader.h',
'child/notifications/notification_manager.cc',
'child/notifications/notification_manager.h',
+ 'child/notifications/pending_notifications_tracker.cc',
+ 'child/notifications/pending_notifications_tracker.h',
'child/npapi/np_channel_base.cc',
'child/npapi/np_channel_base.h',
'child/npapi/npobject_base.h',
@@ -147,6 +172,12 @@
'child/npapi/webplugin_ime_win.cc',
'child/npapi/webplugin_ime_win.h',
'child/npapi/webplugin_resource_client.h',
+ 'child/permissions/permission_dispatcher.cc',
+ 'child/permissions/permission_dispatcher.h',
+ 'child/permissions/permission_dispatcher_thread_proxy.cc',
+ 'child/permissions/permission_dispatcher_thread_proxy.h',
+ 'child/permissions/permission_observers_registry.cc',
+ 'child/permissions/permission_observers_registry.h',
'child/plugin_message_generator.cc',
'child/plugin_message_generator.h',
'child/plugin_messages.h',
@@ -154,6 +185,10 @@
'child/plugin_param_traits.h',
'child/power_monitor_broadcast_source.cc',
'child/power_monitor_broadcast_source.h',
+ 'child/push_messaging/push_dispatcher.cc',
+ 'child/push_messaging/push_dispatcher.h',
+ 'child/push_messaging/push_provider.cc',
+ 'child/push_messaging/push_provider.h',
'child/quota_dispatcher.cc',
'child/quota_dispatcher.h',
'child/quota_message_filter.cc',
@@ -164,8 +199,8 @@
'child/request_info.h',
'child/resource_dispatcher.cc',
'child/resource_dispatcher.h',
- 'child/resource_loader_bridge.cc',
- 'child/resource_loader_bridge.h',
+ 'child/resource_scheduling_filter.cc',
+ 'child/resource_scheduling_filter.h',
'child/runtime_features.cc',
'child/runtime_features.h',
'child/scoped_child_process_reference.cc',
@@ -200,41 +235,26 @@
'child/thread_safe_sender.h',
'child/threaded_data_provider.cc',
'child/threaded_data_provider.h',
+ 'child/v8_value_converter_impl.cc',
+ 'child/v8_value_converter_impl.h',
'child/web_data_consumer_handle_impl.cc',
'child/web_data_consumer_handle_impl.h',
'child/web_database_observer_impl.cc',
'child/web_database_observer_impl.h',
'child/web_discardable_memory_impl.cc',
'child/web_discardable_memory_impl.h',
- 'child/web_gesture_curve_impl.cc',
- 'child/web_gesture_curve_impl.h',
+ 'child/web_memory_allocator_dump_impl.cc',
+ 'child/web_memory_allocator_dump_impl.h',
+ 'child/web_memory_dump_provider_adapter.cc',
+ 'child/web_memory_dump_provider_adapter.h',
+ 'child/web_process_memory_dump_impl.cc',
+ 'child/web_process_memory_dump_impl.h',
'child/web_url_loader_impl.cc',
'child/web_url_loader_impl.h',
'child/web_url_request_util.cc',
'child/web_url_request_util.h',
'child/webblobregistry_impl.cc',
'child/webblobregistry_impl.h',
- 'child/webcrypto/algorithm_dispatch.cc',
- 'child/webcrypto/algorithm_dispatch.h',
- 'child/webcrypto/algorithm_implementation.cc',
- 'child/webcrypto/algorithm_implementation.h',
- 'child/webcrypto/algorithm_registry.cc',
- 'child/webcrypto/algorithm_registry.h',
- 'child/webcrypto/crypto_data.cc',
- 'child/webcrypto/crypto_data.h',
- 'child/webcrypto/generate_key_result.cc',
- 'child/webcrypto/generate_key_result.h',
- 'child/webcrypto/jwk.cc',
- 'child/webcrypto/jwk.h',
- 'child/webcrypto/platform_crypto.h',
- 'child/webcrypto/status.cc',
- 'child/webcrypto/status.h',
- 'child/webcrypto/structured_clone.cc',
- 'child/webcrypto/structured_clone.h',
- 'child/webcrypto/webcrypto_impl.cc',
- 'child/webcrypto/webcrypto_impl.h',
- 'child/webcrypto/webcrypto_util.cc',
- 'child/webcrypto/webcrypto_util.h',
'child/webfallbackthemeengine_impl.cc',
'child/webfallbackthemeengine_impl.h',
'child/webfileutilities_impl.cc',
@@ -250,56 +270,12 @@
'child/webthemeengine_impl_default.cc',
'child/webthemeengine_impl_default.h',
'child/webthemeengine_impl_mac.h',
- 'child/webthread_impl.cc',
- 'child/webthread_impl.h',
'child/weburlresponse_extradata_impl.cc',
'child/weburlresponse_extradata_impl.h',
'child/worker_task_runner.cc',
'child/worker_task_runner.h',
- 'child/worker_thread_task_runner.cc',
- 'child/worker_thread_task_runner.h',
- ],
- 'webcrypto_nss_sources': [
- 'child/webcrypto/nss/aes_cbc_nss.cc',
- 'child/webcrypto/nss/aes_gcm_nss.cc',
- 'child/webcrypto/nss/aes_key_nss.cc',
- 'child/webcrypto/nss/aes_key_nss.h',
- 'child/webcrypto/nss/aes_kw_nss.cc',
- 'child/webcrypto/nss/hmac_nss.cc',
- 'child/webcrypto/nss/key_nss.cc',
- 'child/webcrypto/nss/key_nss.h',
- 'child/webcrypto/nss/rsa_key_nss.cc',
- 'child/webcrypto/nss/rsa_key_nss.h',
- 'child/webcrypto/nss/rsa_oaep_nss.cc',
- 'child/webcrypto/nss/rsa_ssa_nss.cc',
- 'child/webcrypto/nss/sha_nss.cc',
- 'child/webcrypto/nss/sym_key_nss.cc',
- 'child/webcrypto/nss/sym_key_nss.h',
- 'child/webcrypto/nss/util_nss.cc',
- 'child/webcrypto/nss/util_nss.h',
- ],
- 'webcrypto_openssl_sources': [
- 'child/webcrypto/openssl/aes_cbc_openssl.cc',
- 'child/webcrypto/openssl/aes_ctr_openssl.cc',
- 'child/webcrypto/openssl/aes_gcm_openssl.cc',
- 'child/webcrypto/openssl/aes_key_openssl.cc',
- 'child/webcrypto/openssl/aes_key_openssl.h',
- 'child/webcrypto/openssl/aes_kw_openssl.cc',
- 'child/webcrypto/openssl/hmac_openssl.cc',
- 'child/webcrypto/openssl/key_openssl.cc',
- 'child/webcrypto/openssl/key_openssl.h',
- 'child/webcrypto/openssl/rsa_key_openssl.cc',
- 'child/webcrypto/openssl/rsa_key_openssl.h',
- 'child/webcrypto/openssl/rsa_oaep_openssl.cc',
- 'child/webcrypto/openssl/rsa_pss_openssl.cc',
- 'child/webcrypto/openssl/rsa_sign_openssl.cc',
- 'child/webcrypto/openssl/rsa_sign_openssl.h',
- 'child/webcrypto/openssl/rsa_ssa_openssl.cc',
- 'child/webcrypto/openssl/sha_openssl.cc',
- 'child/webcrypto/openssl/sym_key_openssl.cc',
- 'child/webcrypto/openssl/sym_key_openssl.h',
- 'child/webcrypto/openssl/util_openssl.cc',
- 'child/webcrypto/openssl/util_openssl.h',
+ 'child/worker_thread_message_filter.cc',
+ 'child/worker_thread_message_filter.h',
],
},
'sources': [
@@ -316,8 +292,8 @@
}
],
['OS=="android"', {
- 'includes': [
- '../build/android/cpufeatures.gypi',
+ 'dependencies': [
+ '../build/android/ndk.gyp:cpu_features',
],
}],
['enable_plugins==0', {
@@ -339,8 +315,10 @@
'dependencies': [
'app/resources/content_resources.gyp:content_resources',
'app/strings/content_strings.gyp:content_strings',
+ '../components/scheduler/scheduler.gyp:scheduler',
'../storage/storage_common.gyp:storage_common',
'../third_party/WebKit/public/blink.gyp:blink',
+ '../third_party/WebKit/public/blink_resources.gyp:blink_image_resources',
'../third_party/WebKit/public/blink_resources.gyp:blink_resources',
'../third_party/npapi/npapi.gyp:npapi',
],
@@ -355,29 +333,5 @@
'child/npapi/webplugin_delegate_impl_aura.cc',
],
}],
- ['use_openssl==1', {
- 'sources': [
- '<@(webcrypto_openssl_sources)',
- ],
- 'dependencies': [
- '../third_party/boringssl/boringssl.gyp:boringssl',
- ],
- }, {
- 'sources': [
- '<@(webcrypto_nss_sources)',
- ],
- 'conditions': [
- ['os_posix == 1 and OS != "mac" and OS != "ios" and OS != "android"', {
- 'dependencies': [
- '../build/linux/system.gyp:ssl',
- ],
- }, {
- 'dependencies': [
- '../third_party/nss/nss.gyp:nspr',
- '../third_party/nss/nss.gyp:nss',
- ],
- }],
- ],
- }],
],
}
diff --git a/chromium/content/content_common.gypi b/chromium/content/content_common.gypi
index 6d9a28d1493..c19df690c50 100644
--- a/chromium/content/content_common.gypi
+++ b/chromium/content/content_common.gypi
@@ -12,6 +12,7 @@
'../third_party/WebKit/public/blink_headers.gyp:blink_headers',
'../third_party/icu/icu.gyp:icuuc',
'../ui/accessibility/accessibility.gyp:accessibility',
+ '../ui/base/ime/ui_base_ime.gyp:ui_base_ime',
'../ui/base/ui_base.gyp:ui_base',
'../ui/events/ipc/events_ipc.gyp:events_ipc',
'../ui/gfx/gfx.gyp:gfx',
@@ -31,6 +32,8 @@
'../third_party/WebKit/public/blink_headers.gyp:blink_headers',
],
'variables': {
+ 'use_v4lplugin%': 0,
+ 'use_v4l2_codec%': 0,
'public_common_sources': [
'public/common/appcache_info.h',
'public/common/bindings_policy.h',
@@ -57,6 +60,7 @@
'public/common/context_menu_params.h',
'public/common/drop_data.cc',
'public/common/drop_data.h',
+ 'public/common/dwrite_font_platform_win.h',
'public/common/favicon_url.cc',
'public/common/favicon_url.h',
'public/common/file_chooser_file_info.cc',
@@ -72,22 +76,35 @@
'public/common/injection_test_mac.h',
'public/common/injection_test_win.h',
'public/common/javascript_message_type.h',
+ 'public/common/main_function_params.h',
'public/common/manifest.cc',
'public/common/manifest.h',
- 'public/common/main_function_params.h',
'public/common/media_stream_request.cc',
'public/common/media_stream_request.h',
'public/common/menu_item.cc',
'public/common/menu_item.h',
+ 'public/common/message_port_types.cc',
+ 'public/common/message_port_types.h',
+ 'public/common/mojo_channel_switches.cc',
+ 'public/common/mojo_channel_switches.h',
+ 'public/common/navigator_connect_client.cc',
+ 'public/common/navigator_connect_client.h',
+ 'public/common/origin_util.h',
'public/common/page_state.cc',
'public/common/page_state.h',
'public/common/page_type.h',
'public/common/page_zoom.h',
'public/common/pepper_plugin_info.cc',
'public/common/pepper_plugin_info.h',
+ 'public/common/persistent_notification_status.h',
+ 'public/common/platform_notification_data.cc',
+ 'public/common/platform_notification_data.h',
+ 'public/common/presentation_constants.cc',
+ 'public/common/presentation_constants.h',
'public/common/process_type.h',
'public/common/push_messaging_status.cc',
'public/common/push_messaging_status.h',
+ 'public/common/referrer.cc',
'public/common/referrer.h',
'public/common/renderer_preferences.cc',
'public/common/renderer_preferences.h',
@@ -102,16 +119,14 @@
'public/common/resource_type.cc',
'public/common/resource_type.h',
'public/common/result_codes.h',
- 'public/common/result_codes_list.h',
'public/common/sandbox_init.h',
'public/common/sandbox_linux.h',
'public/common/sandbox_type_mac.h',
'public/common/sandboxed_process_launcher_delegate.cc',
'public/common/sandboxed_process_launcher_delegate.h',
'public/common/security_style.h',
+ 'public/common/send_zygote_child_ping_linux.h',
'public/common/service_registry.h',
- 'public/common/show_desktop_notification_params.cc',
- 'public/common/show_desktop_notification_params.h',
'public/common/signed_certificate_timestamp_id_and_status.cc',
'public/common/signed_certificate_timestamp_id_and_status.h',
'public/common/speech_recognition_error.h',
@@ -124,7 +139,6 @@
'public/common/storage_quota_params.h',
'public/common/three_d_api_types.h',
'public/common/top_controls_state.h',
- 'public/common/top_controls_state_list.h',
'public/common/transition_element.h',
'public/common/url_constants.cc',
'public/common/url_constants.h',
@@ -162,9 +176,16 @@
'common/appcache_interfaces.cc',
'common/appcache_interfaces.h',
'common/appcache_messages.h',
+ 'common/bluetooth/bluetooth_device.cc',
+ 'common/bluetooth/bluetooth_device.h',
+ 'common/bluetooth/bluetooth_error.h',
+ 'common/bluetooth/bluetooth_messages.h',
'common/browser_plugin/browser_plugin_constants.cc',
'common/browser_plugin/browser_plugin_constants.h',
'common/browser_plugin/browser_plugin_messages.h',
+ 'common/cache_storage/cache_storage_messages.h',
+ 'common/cache_storage/cache_storage_types.cc',
+ 'common/cache_storage/cache_storage_types.h',
'common/cc_messages.cc',
'common/cc_messages.h',
'common/child_process_host_impl.cc',
@@ -187,8 +208,6 @@
'common/content_paths.cc',
'common/content_switches_internal.cc',
'common/content_switches_internal.h',
- 'common/cookie_data.cc',
- 'common/cookie_data.h',
'common/cursors/webcursor.cc',
'common/cursors/webcursor.h',
'common/cursors/webcursor_android.cc',
@@ -199,7 +218,6 @@
'common/cursors/webcursor_ozone.cc',
'common/database_messages.h',
'common/date_time_suggestion.h',
- 'common/desktop_notification_messages.h',
'common/device_sensors/device_light_data.h',
'common/device_sensors/device_light_hardware_buffer.h',
'common/device_sensors/device_light_messages.h',
@@ -208,12 +226,15 @@
'common/device_sensors/device_orientation_hardware_buffer.h',
'common/device_sensors/device_orientation_messages.h',
'common/devtools_messages.h',
+ 'common/discardable_shared_memory_heap.cc',
+ 'common/discardable_shared_memory_heap.h',
'common/dom_storage/dom_storage_map.cc',
'common/dom_storage/dom_storage_map.h',
'common/dom_storage/dom_storage_messages.h',
'common/drag_event_source_info.h',
'common/drag_messages.h',
'common/drag_traits.h',
+ 'common/dwrite_font_platform_win.cc',
'common/edit_command.h',
'common/file_utilities_messages.h',
'common/fileapi/file_system_messages.h',
@@ -234,6 +255,8 @@
'common/frame_param.cc',
'common/frame_param.h',
'common/frame_param_macros.h',
+ 'common/frame_replication_state.cc',
+ 'common/frame_replication_state.h',
'common/gamepad_hardware_buffer.h',
'common/gamepad_messages.h',
'common/gamepad_param_traits.cc',
@@ -241,12 +264,13 @@
'common/gamepad_user_gesture.cc',
'common/gamepad_user_gesture.h',
'common/geofencing_messages.h',
- 'common/geofencing_status.cc',
- 'common/geofencing_status.h',
- 'common/geolocation_messages.h',
+ 'common/geofencing_types.cc',
+ 'common/geofencing_types.h',
'common/gin_java_bridge_messages.h',
'common/gpu/client/command_buffer_proxy_impl.cc',
'common/gpu/client/command_buffer_proxy_impl.h',
+ 'common/gpu/client/command_buffer_metrics.cc',
+ 'common/gpu/client/command_buffer_metrics.h',
'common/gpu/client/context_provider_command_buffer.cc',
'common/gpu/client/context_provider_command_buffer.h',
'common/gpu/client/gl_helper.cc',
@@ -257,28 +281,21 @@
'common/gpu/client/gl_helper_scaling.h',
'common/gpu/client/gpu_channel_host.cc',
'common/gpu/client/gpu_channel_host.h',
- 'common/gpu/client/gpu_memory_buffer_factory_host.cc',
'common/gpu/client/gpu_memory_buffer_factory_host.h',
'common/gpu/client/gpu_memory_buffer_impl.cc',
'common/gpu/client/gpu_memory_buffer_impl.h',
- 'common/gpu/client/gpu_memory_buffer_impl_android.cc',
- 'common/gpu/client/gpu_memory_buffer_impl_linux.cc',
- 'common/gpu/client/gpu_memory_buffer_impl_mac.cc',
'common/gpu/client/gpu_memory_buffer_impl_ozone_native_buffer.cc',
'common/gpu/client/gpu_memory_buffer_impl_ozone_native_buffer.h',
'common/gpu/client/gpu_memory_buffer_impl_shared_memory.cc',
'common/gpu/client/gpu_memory_buffer_impl_shared_memory.h',
- 'common/gpu/client/gpu_memory_buffer_impl_win.cc',
'common/gpu/client/gpu_video_decode_accelerator_host.cc',
'common/gpu/client/gpu_video_decode_accelerator_host.h',
'common/gpu/client/gpu_video_encode_accelerator_host.cc',
'common/gpu/client/gpu_video_encode_accelerator_host.h',
+ 'common/gpu/client/grcontext_for_webgraphicscontext3d.cc',
+ 'common/gpu/client/grcontext_for_webgraphicscontext3d.h',
'common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc',
'common/gpu/client/webgraphicscontext3d_command_buffer_impl.h',
- 'common/gpu/devtools_gpu_agent.cc',
- 'common/gpu/devtools_gpu_agent.h',
- 'common/gpu/devtools_gpu_instrumentation.cc',
- 'common/gpu/devtools_gpu_instrumentation.h',
'common/gpu/gpu_channel.cc',
'common/gpu/gpu_channel.h',
'common/gpu/gpu_channel_manager.cc',
@@ -286,12 +303,12 @@
'common/gpu/gpu_command_buffer_stub.cc',
'common/gpu/gpu_command_buffer_stub.h',
'common/gpu/gpu_config.h',
+ 'common/gpu/gpu_memory_buffer_factory.cc',
'common/gpu/gpu_memory_buffer_factory.h',
- 'common/gpu/gpu_memory_buffer_factory_android.cc',
- 'common/gpu/gpu_memory_buffer_factory_linux.cc',
- 'common/gpu/gpu_memory_buffer_factory_mac.cc',
- 'common/gpu/gpu_memory_buffer_factory_ozone.cc',
- 'common/gpu/gpu_memory_buffer_factory_win.cc',
+ 'common/gpu/gpu_memory_buffer_factory_ozone_native_buffer.cc',
+ 'common/gpu/gpu_memory_buffer_factory_ozone_native_buffer.h',
+ 'common/gpu/gpu_memory_buffer_factory_shared_memory.cc',
+ 'common/gpu/gpu_memory_buffer_factory_shared_memory.h',
'common/gpu/gpu_memory_manager.cc',
'common/gpu/gpu_memory_manager.h',
'common/gpu/gpu_memory_manager_client.cc',
@@ -308,15 +325,19 @@
'common/gpu/image_transport_surface.cc',
'common/gpu/image_transport_surface.h',
'common/gpu/image_transport_surface_android.cc',
- 'common/gpu/image_transport_surface_calayer_mac.mm',
'common/gpu/image_transport_surface_calayer_mac.h',
- 'common/gpu/image_transport_surface_fbo_mac.mm',
+ 'common/gpu/image_transport_surface_calayer_mac.mm',
'common/gpu/image_transport_surface_fbo_mac.h',
- 'common/gpu/image_transport_surface_linux.cc',
- 'common/gpu/image_transport_surface_mac.mm',
+ 'common/gpu/image_transport_surface_fbo_mac.mm',
'common/gpu/image_transport_surface_iosurface_mac.cc',
'common/gpu/image_transport_surface_iosurface_mac.h',
+ 'common/gpu/image_transport_surface_linux.cc',
+ 'common/gpu/image_transport_surface_mac.mm',
'common/gpu/image_transport_surface_win.cc',
+ 'common/gpu/media/fake_video_decode_accelerator.cc',
+ 'common/gpu/media/fake_video_decode_accelerator.h',
+ 'common/gpu/media/gpu_video_accelerator_util.cc',
+ 'common/gpu/media/gpu_video_accelerator_util.h',
'common/gpu/media/gpu_video_decode_accelerator.cc',
'common/gpu/media/gpu_video_decode_accelerator.h',
'common/gpu/media/gpu_video_encode_accelerator.cc',
@@ -325,12 +346,6 @@
'common/gpu/null_transport_surface.h',
'common/gpu/stream_texture_android.cc',
'common/gpu/stream_texture_android.h',
- 'common/gpu/surface_handle_types_mac.cc',
- 'common/gpu/surface_handle_types_mac.h',
- 'common/gpu/sync_point_manager.cc',
- 'common/gpu/sync_point_manager.h',
- 'common/handle_enumerator_win.cc',
- 'common/handle_enumerator_win.h',
'common/host_discardable_shared_memory_manager.cc',
'common/host_discardable_shared_memory_manager.h',
'common/host_shared_bitmap_manager.cc',
@@ -364,6 +379,8 @@
'common/input/synthetic_gesture_params.h',
'common/input/synthetic_pinch_gesture_params.cc',
'common/input/synthetic_pinch_gesture_params.h',
+ 'common/input/synthetic_smooth_drag_gesture_params.cc',
+ 'common/input/synthetic_smooth_drag_gesture_params.h',
'common/input/synthetic_smooth_scroll_gesture_params.cc',
'common/input/synthetic_smooth_scroll_gesture_params.h',
'common/input/synthetic_tap_gesture_params.cc',
@@ -379,6 +396,8 @@
'common/input_messages.h',
'common/inter_process_time_ticks_converter.cc',
'common/inter_process_time_ticks_converter.h',
+ 'common/in_process_child_thread_params.cc',
+ 'common/in_process_child_thread_params.h',
'common/mac/attributed_string_coder.h',
'common/mac/attributed_string_coder.mm',
'common/mac/font_descriptor.h',
@@ -407,18 +426,22 @@
'common/message_router.cc',
'common/message_router.h',
'common/mime_registry_messages.h',
+ 'common/mojo/channel_init.cc',
+ 'common/mojo/channel_init.h',
'common/mojo/mojo_messages.h',
'common/mojo/service_registry_impl.cc',
'common/mojo/service_registry_impl.h',
'common/navigation_gesture.h',
'common/navigation_params.cc',
'common/navigation_params.h',
+ 'common/navigator_connect_messages.h',
'common/net/url_fetcher.cc',
'common/net/url_request_user_data.cc',
'common/net/url_request_user_data.h',
'common/one_writer_seqlock.cc',
'common/one_writer_seqlock.h',
'common/p2p_messages.h',
+ 'common/origin_util.cc',
'common/page_state_serialization.cc',
'common/page_state_serialization.h',
'common/page_zoom.cc',
@@ -463,6 +486,8 @@
'common/sandbox_linux/bpf_utility_policy_linux.h',
'common/sandbox_linux/sandbox_bpf_base_policy_linux.cc',
'common/sandbox_linux/sandbox_bpf_base_policy_linux.h',
+ 'common/sandbox_linux/sandbox_debug_handling_linux.cc',
+ 'common/sandbox_linux/sandbox_debug_handling_linux.h',
'common/sandbox_linux/sandbox_init_linux.cc',
'common/sandbox_linux/sandbox_linux.cc',
'common/sandbox_linux/sandbox_linux.h',
@@ -477,7 +502,10 @@
'common/savable_url_schemes.cc',
'common/savable_url_schemes.h',
'common/screen_orientation_messages.h',
+ 'common/send_zygote_child_ping_linux.cc',
'common/service_worker/embedded_worker_messages.h',
+ 'common/service_worker/service_worker_client_info.cc',
+ 'common/service_worker/service_worker_client_info.h',
'common/service_worker/service_worker_messages.h',
'common/service_worker/service_worker_status_code.cc',
'common/service_worker/service_worker_status_code.h',
@@ -555,6 +583,7 @@
}, { # OS!="ios"
'dependencies': [
'../cc/cc.gyp:cc',
+ '../gpu/blink/gpu_blink.gyp:gpu_blink',
'../gpu/gpu.gyp:command_buffer_service',
'../gpu/gpu.gyp:gles2_c_lib',
'../gpu/gpu.gyp:gles2_implementation',
@@ -567,15 +596,18 @@
'../ipc/mojo/ipc_mojo.gyp:ipc_mojo',
'../media/media.gyp:media',
'../media/media.gyp:shared_memory_support',
- '../mojo/edk/mojo_edk.gyp:mojo_system_impl',
+ '../media/midi/midi.gyp:midi',
+ '../mojo/mojo_base.gyp:mojo_application_bindings',
'../mojo/mojo_base.gyp:mojo_environment_chromium',
- '../mojo/public/mojo_public.gyp:mojo_application_bindings',
- '../mojo/public/mojo_public.gyp:mojo_cpp_bindings',
- '../storage/storage_browser.gyp:storage',
'../storage/storage_common.gyp:storage_common',
'../third_party/WebKit/public/blink.gyp:blink',
+ '../third_party/mojo/mojo_edk.gyp:mojo_system_impl',
+ '../third_party/mojo/mojo_public.gyp:mojo_cpp_bindings',
'../ui/gl/gl.gyp:gl',
- '../webkit/common/gpu/webkit_gpu.gyp:webkit_gpu',
+ ],
+ 'export_dependent_settings' : [
+ '../mojo/mojo_base.gyp:mojo_application_bindings',
+ '../third_party/mojo/mojo_public.gyp:mojo_cpp_bindings',
],
'actions': [
{
@@ -604,7 +636,9 @@
}],
['OS=="mac"', {
'dependencies': [
+ '../media/media.gyp:media',
'app/resources/content_resources.gyp:content_resources',
+ '../ui/accelerated_widget_mac/accelerated_widget_mac.gyp:accelerated_widget_mac'
],
'sources': [
'common/gpu/client/gpu_memory_buffer_impl_io_surface.cc',
@@ -699,7 +733,6 @@
}],
['use_x11 == 1 and (target_arch != "arm" or chromeos == 0)', {
'sources': [
- 'common/gpu/x_util.cc',
'common/gpu/x_util.h',
],
}],
@@ -747,21 +780,86 @@
'../third_party/libjingle/libjingle.gyp:libjingle',
],
}],
- ['target_arch=="arm" and chromeos == 1 and use_x11 == 1', {
+ ['use_v4lplugin==1 and chromeos==1', {
+ 'defines': [
+ 'USE_LIBV4L2'
+ ],
+ 'variables': {
+ 'generate_stubs_script': '../tools/generate_stubs/generate_stubs.py',
+ 'extra_header': 'common/gpu/media/v4l2_stub_header.fragment',
+ 'sig_files': ['common/gpu/media/v4l2.sig'],
+ 'outfile_type': 'posix_stubs',
+ 'stubs_filename_root': 'v4l2_stubs',
+ 'project_path': 'content/common/gpu/media',
+ 'intermediate_dir': '<(INTERMEDIATE_DIR)',
+ 'output_root': '<(SHARED_INTERMEDIATE_DIR)/v4l2',
+ },
+ 'include_dirs': [
+ '<(output_root)',
+ ],
+ 'actions': [
+ {
+ 'action_name': 'generate_stubs',
+ 'inputs': [
+ '<(generate_stubs_script)',
+ '<(extra_header)',
+ '<@(sig_files)',
+ ],
+ 'outputs': [
+ '<(intermediate_dir)/<(stubs_filename_root).cc',
+ '<(output_root)/<(project_path)/<(stubs_filename_root).h',
+ ],
+ 'action': ['python',
+ '<(generate_stubs_script)',
+ '-i', '<(intermediate_dir)',
+ '-o', '<(output_root)/<(project_path)',
+ '-t', '<(outfile_type)',
+ '-e', '<(extra_header)',
+ '-s', '<(stubs_filename_root)',
+ '-p', '<(project_path)',
+ '<@(_inputs)',
+ ],
+ 'process_outputs_as_sources': 1,
+ 'message': 'Generating libv4l2 stubs for dynamic loading',
+ },
+ ],
+ }],
+ ['chromeos==1', {
+ 'sources': [
+ 'common/gpu/media/accelerated_video_decoder.h',
+ 'common/gpu/media/h264_decoder.cc',
+ 'common/gpu/media/h264_decoder.h',
+ 'common/gpu/media/h264_dpb.cc',
+ 'common/gpu/media/h264_dpb.h',
+ 'common/gpu/media/vp8_decoder.cc',
+ 'common/gpu/media/vp8_decoder.h',
+ 'common/gpu/media/vp8_picture.cc',
+ 'common/gpu/media/vp8_picture.h',
+ ],
+ }],
+ ['chromeos==1 and use_v4l2_codec==1', {
+ 'direct_dependent_settings': {
+ 'defines': [
+ 'USE_V4L2_CODEC'
+ ],
+ },
+ 'defines': [
+ 'USE_V4L2_CODEC'
+ ],
'dependencies': [
'../media/media.gyp:media',
],
'sources': [
- 'common/gpu/media/exynos_v4l2_video_device.cc',
- 'common/gpu/media/exynos_v4l2_video_device.h',
- 'common/gpu/media/tegra_v4l2_video_device.cc',
- 'common/gpu/media/tegra_v4l2_video_device.h',
+ 'common/gpu/media/generic_v4l2_device.cc',
+ 'common/gpu/media/generic_v4l2_device.h',
+ 'common/gpu/media/v4l2_device.cc',
+ 'common/gpu/media/v4l2_device.h',
'common/gpu/media/v4l2_image_processor.cc',
'common/gpu/media/v4l2_image_processor.h',
+ 'common/gpu/media/v4l2_slice_video_decode_accelerator.cc',
+ 'common/gpu/media/v4l2_slice_video_decode_accelerator.h',
'common/gpu/media/v4l2_video_decode_accelerator.cc',
'common/gpu/media/v4l2_video_decode_accelerator.h',
- 'common/gpu/media/v4l2_video_device.cc',
- 'common/gpu/media/v4l2_video_device.h',
'common/gpu/media/v4l2_video_encode_accelerator.cc',
'common/gpu/media/v4l2_video_encode_accelerator.h',
],
@@ -769,17 +867,23 @@
'<(DEPTH)/third_party/khronos',
],
}],
- ['target_arch != "arm" and chromeos == 1 and use_x11 == 1', {
+ ['target_arch == "arm" and chromeos == 1', {
+ 'sources': [
+ 'common/gpu/media/tegra_v4l2_device.cc',
+ 'common/gpu/media/tegra_v4l2_device.h',
+ ],
+ }],
+ ['target_arch != "arm" and chromeos == 1', {
'dependencies': [
'../media/media.gyp:media',
'../third_party/libyuv/libyuv.gyp:libyuv',
],
'sources': [
- 'common/gpu/media/h264_dpb.cc',
- 'common/gpu/media/h264_dpb.h',
'common/gpu/media/va_surface.h',
- 'common/gpu/media/vaapi_h264_decoder.cc',
- 'common/gpu/media/vaapi_h264_decoder.h',
+ 'common/gpu/media/vaapi_jpeg_decoder.cc',
+ 'common/gpu/media/vaapi_jpeg_decoder.h',
+ 'common/gpu/media/vaapi_picture.cc',
+ 'common/gpu/media/vaapi_picture.h',
'common/gpu/media/vaapi_video_decode_accelerator.cc',
'common/gpu/media/vaapi_video_decode_accelerator.h',
'common/gpu/media/vaapi_video_encode_accelerator.cc',
@@ -787,10 +891,34 @@
'common/gpu/media/vaapi_wrapper.cc',
'common/gpu/media/vaapi_wrapper.h',
],
+ 'conditions': [
+ ['use_x11 == 1', {
+ 'variables': {
+ 'sig_files': [
+ 'common/gpu/media/va.sigs',
+ 'common/gpu/media/va_x11.sigs',
+ ],
+ },
+ 'sources': [
+ 'common/gpu/media/vaapi_tfp_picture.cc',
+ 'common/gpu/media/vaapi_tfp_picture.h',
+ ],
+ }, {
+ 'variables': {
+ 'sig_files': [
+ 'common/gpu/media/va.sigs',
+ 'common/gpu/media/va_drm.sigs',
+ ],
+ },
+ 'sources': [
+ 'common/gpu/media/vaapi_drm_picture.cc',
+ 'common/gpu/media/vaapi_drm_picture.h',
+ ],
+ }],
+ ],
'variables': {
'generate_stubs_script': '../tools/generate_stubs/generate_stubs.py',
'extra_header': 'common/gpu/media/va_stub_header.fragment',
- 'sig_files': ['common/gpu/media/va.sigs'],
'outfile_type': 'posix_stubs',
'stubs_filename_root': 'va_stubs',
'project_path': 'content/common/gpu/media',
@@ -837,6 +965,7 @@
'link_settings': {
'libraries': [
'-ld3d9.lib',
+ '-ld3d11.lib',
'-ldxva2.lib',
'-lstrmiids.lib',
'-lmf.lib',
@@ -847,6 +976,7 @@
'VCLinkerTool': {
'DelayLoadDLLs': [
'd3d9.dll',
+ 'd3d11.dll',
'dxva2.dll',
'mf.dll',
'mfplat.dll',
@@ -909,15 +1039,24 @@
['use_ozone==1', {
'dependencies': [
'../ui/ozone/ozone.gyp:ozone',
+ '../ui/ozone/ozone.gyp:ozone_base',
'../ui/ozone/gpu/ozone_gpu.gyp:ozone_gpu',
],
- 'sources': [
- 'common/gpu/client/gpu_memory_buffer_impl_ozone.cc',
- ],
'sources!': [
'common/gpu/client/gpu_memory_buffer_impl_linux.cc',
'common/gpu/gpu_memory_buffer_factory_linux.cc',
],
+ }, { # use_ozone!=1
+ 'sources!': [
+ 'common/cursors/webcursor_ozone.cc',
+ 'common/font_list_ozone.cc',
+ 'common/gpu/client/gpu_memory_buffer_impl_ozone.cc',
+ 'common/gpu/client/gpu_memory_buffer_impl_ozone_native_buffer.cc',
+ 'common/gpu/client/gpu_memory_buffer_impl_ozone_native_buffer.h',
+ 'common/gpu/gpu_memory_buffer_factory_ozone.cc',
+ 'common/gpu/gpu_memory_buffer_factory_ozone_native_buffer.cc',
+ 'common/gpu/gpu_memory_buffer_factory_ozone_native_buffer.h',
+ ],
}],
],
}
diff --git a/chromium/content/content_common_mojo_bindings.gyp b/chromium/content/content_common_mojo_bindings.gyp
new file mode 100644
index 00000000000..dc2df70ef9e
--- /dev/null
+++ b/chromium/content/content_common_mojo_bindings.gyp
@@ -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.
+
+{
+ 'targets': [
+ {
+ # GN version: //content/common:mojo_bindings
+ 'target_name': 'content_common_mojo_bindings_mojom',
+ 'type': 'none',
+ 'variables': {
+ 'mojom_files': [
+ # NOTE: Sources duplicated in //content/common/BUILD.gn:mojo_bindings.
+ 'common/application_setup.mojom',
+ 'common/background_sync_service.mojom',
+ 'common/geolocation_service.mojom',
+ 'common/permission_service.mojom',
+ 'common/presentation/presentation_service.mojom',
+ 'common/render_frame_setup.mojom',
+
+ # NOTE: Sources duplicated in
+ # //content/public/common/BUILD.gn:mojo_bindings.
+ 'public/common/background_sync.mojom',
+ 'public/common/mojo_geoposition.mojom',
+ 'public/common/permission_status.mojom',
+ ],
+ },
+ 'includes': [ '../third_party/mojo/mojom_bindings_generator_explicit.gypi' ],
+ },
+ {
+ 'target_name': 'content_common_mojo_bindings',
+ 'type': 'static_library',
+ 'variables': { 'enable_wexit_time_destructors': 1, },
+ 'dependencies': [
+ 'content_common_mojo_bindings_mojom',
+ '../mojo/mojo_base.gyp:mojo_application_bindings',
+ '../mojo/mojo_base.gyp:mojo_environment_chromium',
+ '../third_party/mojo/mojo_public.gyp:mojo_cpp_bindings',
+ ]
+ },
+ ]
+}
diff --git a/chromium/content/content_common_mojo_bindings.gypi b/chromium/content/content_common_mojo_bindings.gypi
deleted file mode 100644
index da5c00a4d3d..00000000000
--- a/chromium/content/content_common_mojo_bindings.gypi
+++ /dev/null
@@ -1,32 +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.
-
-{
- 'targets': [
- {
- 'target_name': 'content_common_mojo_bindings',
- 'type': 'static_library',
- 'dependencies': [
- '../mojo/mojo_base.gyp:mojo_environment_chromium',
- '../mojo/public/mojo_public.gyp:mojo_application_bindings',
- '../mojo/public/mojo_public.gyp:mojo_cpp_bindings',
- ],
- 'sources': [
- # NOTE: Sources duplicated in //content/common/BUILD.gn:mojo_bindings.
- 'common/geolocation_service.mojom',
- 'common/render_frame_setup.mojom',
-
- # NOTE: Sources duplicated in
- # //content/public/common/BUILD.gn:mojo_bindings.
- 'public/common/mojo_geoposition.mojom',
- ],
- 'includes': [ '../mojo/public/tools/bindings/mojom_bindings_generator.gypi' ],
- 'export_dependent_settings': [
- '../mojo/mojo_base.gyp:mojo_environment_chromium',
- '../mojo/public/mojo_public.gyp:mojo_application_bindings',
- '../mojo/public/mojo_public.gyp:mojo_cpp_bindings',
- ],
- },
- ],
-}
diff --git a/chromium/content/content_gl_tests.isolate b/chromium/content/content_gl_tests.isolate
index a9ca4e3deae..ea9938d8a3b 100644
--- a/chromium/content/content_gl_tests.isolate
+++ b/chromium/content/content_gl_tests.isolate
@@ -41,7 +41,7 @@
['OS=="win"', {
'variables': {
'files': [
- '<(PRODUCT_DIR)/d3dcompiler_46.dll',
+ '<(PRODUCT_DIR)/d3dcompiler_47.dll',
'<(PRODUCT_DIR)/libEGL.dll',
'<(PRODUCT_DIR)/libGLESv2.dll',
'<(PRODUCT_DIR)/ffmpegsumo.dll',
diff --git a/chromium/content/content_gpu.gypi b/chromium/content/content_gpu.gypi
index 396106ce1a4..1c2121d59bc 100644
--- a/chromium/content/content_gpu.gypi
+++ b/chromium/content/content_gpu.gypi
@@ -5,16 +5,15 @@
{
'dependencies': [
'../base/base.gyp:base',
- '../mojo/public/mojo_public.gyp:mojo_application_bindings',
'../skia/skia.gyp:skia',
'../ui/gl/gl.gyp:gl',
],
'sources': [
+ 'gpu/gpu_child_thread.cc',
+ 'gpu/gpu_child_thread.h',
'gpu/gpu_main.cc',
'gpu/gpu_process.cc',
'gpu/gpu_process.h',
- 'gpu/gpu_child_thread.cc',
- 'gpu/gpu_child_thread.h',
'gpu/gpu_watchdog_thread.cc',
'gpu/gpu_watchdog_thread.h',
'gpu/in_process_gpu_thread.cc',
@@ -27,13 +26,10 @@
['OS=="win"', {
'include_dirs': [
'<(DEPTH)/third_party/khronos',
+ # ANGLE libs picked up from ui/gl
'<(angle_path)/src',
'<(DEPTH)/third_party/wtl/include',
],
- 'dependencies': [
- '<(angle_path)/src/angle.gyp:libEGL',
- '<(angle_path)/src/angle.gyp:libGLESv2',
- ],
'link_settings': {
'libraries': [
'-lsetupapi.lib',
diff --git a/chromium/content/content_jni.gypi b/chromium/content/content_jni.gypi
index 202f5580fa3..744e9e1884f 100644
--- a/chromium/content/content_jni.gypi
+++ b/chromium/content/content_jni.gypi
@@ -13,7 +13,6 @@
'public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java',
'public/android/java/src/org/chromium/content/browser/BrowserStartupController.java',
'public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java',
- 'public/android/java/src/org/chromium/content/browser/ContentSettings.java',
'public/android/java/src/org/chromium/content/browser/ContentReadbackHandler.java',
'public/android/java/src/org/chromium/content/browser/ContentVideoView.java',
'public/android/java/src/org/chromium/content/browser/ContentViewCore.java',
@@ -31,16 +30,16 @@
'public/android/java/src/org/chromium/content/browser/MediaDrmCredentialManager.java',
'public/android/java/src/org/chromium/content/browser/MediaResourceGetter.java',
'public/android/java/src/org/chromium/content/browser/PowerSaveBlocker.java',
+ 'public/android/java/src/org/chromium/content/browser/ServiceRegistrar.java',
'public/android/java/src/org/chromium/content/browser/ServiceRegistry.java',
'public/android/java/src/org/chromium/content/browser/ScreenOrientationProvider.java',
'public/android/java/src/org/chromium/content/browser/SpeechRecognition.java',
'public/android/java/src/org/chromium/content/browser/TimeZoneMonitor.java',
'public/android/java/src/org/chromium/content/browser/TouchEventSynthesizer.java',
'public/android/java/src/org/chromium/content/browser/TracingControllerAndroid.java',
- 'public/android/java/src/org/chromium/content/browser/VibrationProvider.java',
- 'public/android/java/src/org/chromium/content/browser/WebContentsObserver.java',
'public/android/java/src/org/chromium/content/browser/framehost/NavigationControllerImpl.java',
'public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java',
+ 'public/android/java/src/org/chromium/content/browser/webcontents/WebContentsObserverProxy.java',
'public/android/java/src/org/chromium/content_public/browser/LoadUrlParams.java',
],
'variables': {
diff --git a/chromium/content/content_nacl_nonsfi.gyp b/chromium/content/content_nacl_nonsfi.gyp
new file mode 100644
index 00000000000..cfff0a54589
--- /dev/null
+++ b/chromium/content/content_nacl_nonsfi.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.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ },
+ 'includes': [
+ '../build/common_untrusted.gypi',
+ ],
+ 'conditions': [
+ ['disable_nacl==0 and disable_nacl_untrusted==0', {
+ 'targets': [
+ {
+ 'target_name': 'content_common_nacl_nonsfi',
+ 'type': 'none',
+ 'variables': {
+ 'nacl_untrusted_build': 1,
+ 'nlib_target': 'libcontent_common_nacl_nonsfi.a',
+ 'build_glibc': 0,
+ 'build_newlib': 0,
+ 'build_irt': 0,
+ 'build_pnacl_newlib': 0,
+ 'build_nonsfi_helper': 1,
+
+ 'sources': [
+ 'common/sandbox_linux/sandbox_init_linux.cc',
+ 'common/sandbox_linux/sandbox_seccomp_bpf_linux.cc',
+ 'common/send_zygote_child_ping_linux.cc',
+ 'public/common/content_switches.cc',
+ ],
+ },
+ 'defines': [
+ 'USE_SECCOMP_BPF=1',
+ ],
+ 'dependencies': [
+ '../base/base_nacl.gyp:base_nacl_nonsfi',
+ ],
+ },
+ ],
+ }],
+ ],
+}
diff --git a/chromium/content/content_plugin.gypi b/chromium/content/content_plugin.gypi
index 30336a0ed12..5d3ca951d20 100644
--- a/chromium/content/content_plugin.gypi
+++ b/chromium/content/content_plugin.gypi
@@ -6,7 +6,6 @@
'conditions': [
['enable_plugins==1 and OS!="linux"', {
'dependencies': [
- '../mojo/public/mojo_public.gyp:mojo_application_bindings',
'../skia/skia.gyp:skia',
'../third_party/WebKit/public/blink.gyp:blink',
'../third_party/npapi/npapi.gyp:npapi',
@@ -19,8 +18,8 @@
# mocks.
'plugin/plugin_channel.cc',
'plugin/plugin_channel.h',
- 'plugin/plugin_interpose_util_mac.mm',
'plugin/plugin_interpose_util_mac.h',
+ 'plugin/plugin_interpose_util_mac.mm',
'plugin/plugin_main.cc',
'plugin/plugin_main_mac.mm',
'plugin/plugin_thread.cc',
diff --git a/chromium/content/content_ppapi_plugin.gypi b/chromium/content/content_ppapi_plugin.gypi
index c02e053d3f1..89c200f0d3b 100644
--- a/chromium/content/content_ppapi_plugin.gypi
+++ b/chromium/content/content_ppapi_plugin.gypi
@@ -7,12 +7,12 @@
['enable_plugins==1', {
'dependencies': [
'../base/base.gyp:base',
- '../mojo/public/mojo_public.gyp:mojo_application_bindings',
'../ppapi/ppapi_internal.gyp:ppapi_ipc',
'../ui/base/ui_base.gyp:ui_base',
'../ui/gfx/gfx.gyp:gfx',
'../ui/gfx/gfx.gyp:gfx_geometry',
'../third_party/WebKit/public/blink.gyp:blink',
+ 'content_common_mojo_bindings.gyp:content_common_mojo_bindings',
],
'sources': [
'ppapi_plugin/broker_process_dispatcher.cc',
diff --git a/chromium/content/content_renderer.gypi b/chromium/content/content_renderer.gypi
index 144f8de37ef..52ce045a761 100644
--- a/chromium/content/content_renderer.gypi
+++ b/chromium/content/content_renderer.gypi
@@ -4,21 +4,21 @@
{
'dependencies': [
- 'content_common_mojo_bindings',
'../base/base.gyp:base',
'../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
'../cc/cc.gyp:cc',
'../cc/blink/cc_blink.gyp:cc_blink',
+ '../components/scheduler/scheduler.gyp:scheduler',
'../device/battery/battery.gyp:device_battery',
'../device/battery/battery.gyp:device_battery_mojo_bindings',
+ '../device/vibration/vibration.gyp:device_vibration',
+ '../device/vibration/vibration.gyp:device_vibration_mojo_bindings',
'../gin/gin.gyp:gin',
'../gpu/gpu.gyp:gpu',
'../jingle/jingle.gyp:jingle_glue',
'../media/blink/media_blink.gyp:media_blink',
'../media/media.gyp:media',
- '../mojo/edk/mojo_edk.gyp:mojo_js_lib',
'../mojo/mojo_base.gyp:mojo_environment_chromium',
- '../mojo/public/mojo_public.gyp:mojo_application_bindings',
'../net/net.gyp:net',
'../skia/skia.gyp:skia',
'../storage/storage_common.gyp:storage_common',
@@ -26,16 +26,17 @@
'../third_party/icu/icu.gyp:icui18n',
'../third_party/icu/icu.gyp:icuuc',
'../third_party/libjingle/libjingle.gyp:libjingle',
+ '../third_party/mojo/mojo_edk.gyp:mojo_js_lib',
'../third_party/npapi/npapi.gyp:npapi',
'../third_party/widevine/cdm/widevine_cdm.gyp:widevine_cdm_version_h',
'../ui/accessibility/accessibility.gyp:accessibility',
- '../ui/events/events.gyp:dom4_keycode_converter',
+ '../ui/events/events.gyp:dom_keycode_converter',
'../ui/gfx/gfx.gyp:gfx',
'../ui/gfx/gfx.gyp:gfx_geometry',
'../ui/native_theme/native_theme.gyp:native_theme',
'../ui/surface/surface.gyp:surface',
'../v8/tools/gyp/v8.gyp:v8',
- '../webkit/common/gpu/webkit_gpu.gyp:webkit_gpu',
+ 'content_common_mojo_bindings.gyp:content_common_mojo_bindings',
],
'include_dirs': [
'..',
@@ -45,6 +46,7 @@
'public_renderer_sources': [
'public/renderer/android_content_detection_prefixes.cc',
'public/renderer/android_content_detection_prefixes.h',
+ 'public/renderer/browser_plugin_delegate.cc',
'public/renderer/browser_plugin_delegate.h',
'public/renderer/content_renderer_client.cc',
'public/renderer/content_renderer_client.h',
@@ -55,12 +57,11 @@
'public/renderer/navigation_state.h',
'public/renderer/pepper_plugin_instance.h',
'public/renderer/platform_event_observer.h',
- 'public/renderer/renderer_ppapi_host.h',
+ 'public/renderer/render_font_warmup_win.h',
'public/renderer/render_frame.h',
'public/renderer/render_frame_observer.cc',
'public/renderer/render_frame_observer.h',
'public/renderer/render_frame_observer_tracker.h',
- 'public/renderer/render_font_warmup_win.h',
'public/renderer/render_process_observer.cc',
'public/renderer/render_process_observer.h',
'public/renderer/render_thread.cc',
@@ -70,11 +71,14 @@
'public/renderer/render_view_observer.h',
'public/renderer/render_view_observer_tracker.h',
'public/renderer/render_view_visitor.h',
+ 'public/renderer/renderer_ppapi_host.h',
'public/renderer/resource_fetcher.h',
- 'public/renderer/v8_value_converter.h',
'public/renderer/video_encode_accelerator.cc',
'public/renderer/video_encode_accelerator.h',
],
+ 'public_renderer_plugin_sources': [
+ 'public/renderer/plugin_instance_throttler.h',
+ ],
'private_renderer_sources': [
'renderer/accessibility/blink_ax_enum_conversion.cc',
'renderer/accessibility/blink_ax_enum_conversion.h',
@@ -82,8 +86,6 @@
'renderer/accessibility/blink_ax_tree_source.h',
'renderer/accessibility/renderer_accessibility.cc',
'renderer/accessibility/renderer_accessibility.h',
- 'renderer/active_notification_tracker.cc',
- 'renderer/active_notification_tracker.h',
'renderer/android/address_detector.cc',
'renderer/android/address_detector.h',
'renderer/android/content_detector.cc',
@@ -102,12 +104,18 @@
'renderer/browser_plugin/browser_plugin.h',
'renderer/browser_plugin/browser_plugin_manager.cc',
'renderer/browser_plugin/browser_plugin_manager.h',
- 'renderer/clipboard_utils.cc',
- 'renderer/clipboard_utils.h',
+ 'renderer/cache_storage/cache_storage_dispatcher.cc',
+ 'renderer/cache_storage/cache_storage_dispatcher.h',
+ 'renderer/cache_storage/cache_storage_message_filter.cc',
+ 'renderer/cache_storage/cache_storage_message_filter.h',
+ 'renderer/cache_storage/webserviceworkercachestorage_impl.cc',
+ 'renderer/cache_storage/webserviceworkercachestorage_impl.h',
'renderer/child_frame_compositing_helper.cc',
'renderer/child_frame_compositing_helper.h',
'renderer/chrome_object_extensions_utils.cc',
'renderer/chrome_object_extensions_utils.h',
+ 'renderer/clipboard_utils.cc',
+ 'renderer/clipboard_utils.h',
'renderer/context_menu_params_builder.cc',
'renderer/context_menu_params_builder.h',
'renderer/cursor_utils.cc',
@@ -127,6 +135,9 @@
'renderer/devtools/devtools_agent_filter.h',
'renderer/devtools/devtools_client.cc',
'renderer/devtools/devtools_client.h',
+ 'renderer/devtools/lock_free_circular_queue.h',
+ 'renderer/devtools/v8_sampling_profiler.cc',
+ 'renderer/devtools/v8_sampling_profiler.h',
'renderer/disambiguation_popup_helper.cc',
'renderer/disambiguation_popup_helper.h',
'renderer/dom_automation_controller.cc',
@@ -144,8 +155,6 @@
'renderer/dom_utils.h',
'renderer/drop_data_builder.cc',
'renderer/drop_data_builder.h',
- 'renderer/fetchers/image_resource_fetcher.cc',
- 'renderer/fetchers/image_resource_fetcher.h',
'renderer/fetchers/manifest_fetcher.cc',
'renderer/fetchers/manifest_fetcher.h',
'renderer/fetchers/multi_resolution_image_resource_fetcher.cc',
@@ -158,10 +167,13 @@
'renderer/gamepad_shared_memory_reader.h',
'renderer/geolocation_dispatcher.cc',
'renderer/geolocation_dispatcher.h',
+ 'renderer/gpu/compositor_dependencies.h',
+ 'renderer/gpu/compositor_external_begin_frame_source.cc',
+ 'renderer/gpu/compositor_external_begin_frame_source.h',
+ 'renderer/gpu/compositor_forwarding_message_filter.cc',
+ 'renderer/gpu/compositor_forwarding_message_filter.h',
'renderer/gpu/compositor_output_surface.cc',
'renderer/gpu/compositor_output_surface.h',
- 'renderer/gpu/compositor_software_output_device.cc',
- 'renderer/gpu/compositor_software_output_device.h',
'renderer/gpu/delegated_compositor_output_surface.cc',
'renderer/gpu/delegated_compositor_output_surface.h',
'renderer/gpu/frame_swap_message_queue.cc',
@@ -201,6 +213,8 @@
'renderer/input/input_handler_wrapper.h',
'renderer/input/input_scroll_elasticity_controller.cc',
'renderer/input/input_scroll_elasticity_controller.h',
+ 'renderer/input/main_thread_input_event_filter.cc',
+ 'renderer/input/main_thread_input_event_filter.h',
'renderer/internal_document_state_data.cc',
'renderer/internal_document_state_data.h',
'renderer/java/gin_java_bridge_dispatcher.cc',
@@ -209,6 +223,8 @@
'renderer/java/gin_java_bridge_object.h',
'renderer/java/gin_java_bridge_value_converter.cc',
'renderer/java/gin_java_bridge_value_converter.h',
+ 'renderer/java/gin_java_function_invocation_helper.cc',
+ 'renderer/java/gin_java_function_invocation_helper.h',
'renderer/manifest/manifest_manager.cc',
'renderer/manifest/manifest_manager.h',
'renderer/manifest/manifest_parser.cc',
@@ -244,23 +260,17 @@
'renderer/media/audio_message_filter.h',
'renderer/media/audio_renderer_mixer_manager.cc',
'renderer/media/audio_renderer_mixer_manager.h',
- 'renderer/media/cdm_session_adapter.cc',
- 'renderer/media/cdm_session_adapter.h',
- 'renderer/media/crypto/encrypted_media_player_support_impl.cc',
- 'renderer/media/crypto/encrypted_media_player_support_impl.h',
- 'renderer/media/crypto/key_systems.cc',
- 'renderer/media/crypto/key_systems.h',
- 'renderer/media/crypto/key_systems_support_uma.cc',
- 'renderer/media/crypto/key_systems_support_uma.h',
+ 'renderer/media/crypto/cdm_initialized_promise.cc',
+ 'renderer/media/crypto/cdm_initialized_promise.h',
'renderer/media/crypto/pepper_cdm_wrapper.h',
'renderer/media/crypto/pepper_cdm_wrapper_impl.cc',
'renderer/media/crypto/pepper_cdm_wrapper_impl.h',
'renderer/media/crypto/ppapi_decryptor.cc',
'renderer/media/crypto/ppapi_decryptor.h',
- 'renderer/media/crypto/proxy_decryptor.cc',
- 'renderer/media/crypto/proxy_decryptor.h',
'renderer/media/crypto/render_cdm_factory.cc',
'renderer/media/crypto/render_cdm_factory.h',
+ 'renderer/media/media_permission_dispatcher.cc',
+ 'renderer/media/media_permission_dispatcher.h',
'renderer/media/media_stream_audio_level_calculator.cc',
'renderer/media/media_stream_audio_level_calculator.h',
'renderer/media/media_stream_audio_renderer.cc',
@@ -276,6 +286,8 @@
'renderer/media/midi_dispatcher.h',
'renderer/media/midi_message_filter.cc',
'renderer/media/midi_message_filter.h',
+ 'renderer/media/render_media_client.cc',
+ 'renderer/media/render_media_client.h',
'renderer/media/render_media_log.cc',
'renderer/media/render_media_log.h',
'renderer/media/renderer_gpu_video_accelerator_factories.cc',
@@ -292,10 +304,6 @@
'renderer/media/video_capture_message_filter.h',
'renderer/media/video_frame_provider.cc',
'renderer/media/video_frame_provider.h',
- 'renderer/media/webcontentdecryptionmodule_impl.cc',
- 'renderer/media/webcontentdecryptionmodule_impl.h',
- 'renderer/media/webcontentdecryptionmodulesession_impl.cc',
- 'renderer/media/webcontentdecryptionmodulesession_impl.h',
'renderer/media/webmediaplayer_ms.cc',
'renderer/media/webmediaplayer_ms.h',
'renderer/memory_benchmarking_extension.cc',
@@ -308,18 +316,18 @@
'renderer/mojo/service_registry_js_wrapper.h',
'renderer/mouse_lock_dispatcher.cc',
'renderer/mouse_lock_dispatcher.h',
+ 'renderer/navigation_state_impl.cc',
+ 'renderer/navigation_state_impl.h',
'renderer/net_info_helper.cc',
'renderer/net_info_helper.h',
- 'renderer/notification_icon_loader.cc',
- 'renderer/notification_icon_loader.h',
'renderer/notification_permission_dispatcher.cc',
'renderer/notification_permission_dispatcher.h',
- 'renderer/notification_provider.cc',
- 'renderer/notification_provider.h',
- 'renderer/push_messaging_dispatcher.cc',
- 'renderer/push_messaging_dispatcher.h',
- 'renderer/push_permission_dispatcher.cc',
- 'renderer/push_permission_dispatcher.h',
+ 'renderer/presentation/presentation_dispatcher.cc',
+ 'renderer/presentation/presentation_dispatcher.h',
+ 'renderer/presentation/presentation_session_client.cc',
+ 'renderer/presentation/presentation_session_client.h',
+ 'renderer/push_messaging/push_messaging_dispatcher.cc',
+ 'renderer/push_messaging/push_messaging_dispatcher.h',
'renderer/render_font_warmup_win.cc',
'renderer/render_frame_impl.cc',
'renderer/render_frame_impl.h',
@@ -333,21 +341,18 @@
'renderer/render_view_impl.cc',
'renderer/render_view_impl.h',
'renderer/render_view_impl_android.cc',
- 'renderer/render_view_impl_params.cc',
- 'renderer/render_view_impl_params.h',
'renderer/render_view_linux.cc',
'renderer/render_view_mouse_lock_dispatcher.cc',
'renderer/render_view_mouse_lock_dispatcher.h',
+ 'renderer/render_view_win.cc',
'renderer/render_widget.cc',
'renderer/render_widget.h',
'renderer/render_widget_fullscreen.cc',
'renderer/render_widget_fullscreen.h',
'renderer/renderer_blink_platform_impl.cc',
'renderer/renderer_blink_platform_impl.h',
- 'renderer/renderer_clipboard_client.cc',
- 'renderer/renderer_clipboard_client.h',
- 'renderer/renderer_font_platform_win.cc',
- 'renderer/renderer_font_platform_win.h',
+ 'renderer/renderer_clipboard_delegate.cc',
+ 'renderer/renderer_clipboard_delegate.h',
'renderer/renderer_main.cc',
'renderer/renderer_main_platform_delegate.h',
'renderer/renderer_main_platform_delegate_android.cc',
@@ -366,27 +371,12 @@
'renderer/sad_plugin.h',
'renderer/savable_resources.cc',
'renderer/savable_resources.h',
- 'renderer/scheduler/null_renderer_scheduler.cc',
- 'renderer/scheduler/null_renderer_scheduler.h',
- 'renderer/scheduler/renderer_scheduler.cc',
- 'renderer/scheduler/renderer_scheduler.h',
- 'renderer/scheduler/renderer_scheduler_impl.cc',
- 'renderer/scheduler/renderer_scheduler_impl.h',
- 'renderer/scheduler/renderer_task_queue_selector.cc',
- 'renderer/scheduler/renderer_task_queue_selector.h',
- 'renderer/scheduler/single_thread_idle_task_runner.cc',
- 'renderer/scheduler/single_thread_idle_task_runner.h',
- 'renderer/scheduler/task_queue_manager.cc',
- 'renderer/scheduler/task_queue_manager.h',
- 'renderer/scheduler/task_queue_selector.h',
- 'renderer/scheduler/web_scheduler_impl.cc',
- 'renderer/scheduler/web_scheduler_impl.h',
+ 'renderer/scheduler/resource_dispatch_throttler.cc',
+ 'renderer/scheduler/resource_dispatch_throttler.h',
'renderer/screen_orientation/screen_orientation_dispatcher.cc',
'renderer/screen_orientation/screen_orientation_dispatcher.h',
'renderer/screen_orientation/screen_orientation_observer.cc',
'renderer/screen_orientation/screen_orientation_observer.h',
- 'renderer/scoped_clipboard_writer_glue.cc',
- 'renderer/scoped_clipboard_writer_glue.h',
'renderer/service_worker/embedded_worker_context_client.cc',
'renderer/service_worker/embedded_worker_context_client.h',
'renderer/service_worker/embedded_worker_context_message_filter.cc',
@@ -395,18 +385,18 @@
'renderer/service_worker/embedded_worker_devtools_agent.h',
'renderer/service_worker/embedded_worker_dispatcher.cc',
'renderer/service_worker/embedded_worker_dispatcher.h',
- 'renderer/service_worker/service_worker_cache_storage_dispatcher.cc',
- 'renderer/service_worker/service_worker_cache_storage_dispatcher.h',
'renderer/service_worker/service_worker_script_context.cc',
'renderer/service_worker/service_worker_script_context.h',
+ 'renderer/service_worker/service_worker_type_util.cc',
+ 'renderer/service_worker/service_worker_type_util.h',
'renderer/shared_memory_seqlock_reader.cc',
'renderer/shared_memory_seqlock_reader.h',
- 'renderer/shared_worker_repository.cc',
- 'renderer/shared_worker_repository.h',
- 'renderer/shared_worker/embedded_shared_worker_permission_client_proxy.cc',
- 'renderer/shared_worker/embedded_shared_worker_permission_client_proxy.h',
+ 'renderer/shared_worker/embedded_shared_worker_content_settings_client_proxy.cc',
+ 'renderer/shared_worker/embedded_shared_worker_content_settings_client_proxy.h',
'renderer/shared_worker/embedded_shared_worker_stub.cc',
'renderer/shared_worker/embedded_shared_worker_stub.h',
+ 'renderer/shared_worker_repository.cc',
+ 'renderer/shared_worker_repository.h',
'renderer/skia_benchmarking_extension.cc',
'renderer/skia_benchmarking_extension.h',
'renderer/speech_recognition_dispatcher.cc',
@@ -417,8 +407,6 @@
'renderer/stats_collection_observer.h',
'renderer/text_input_client_observer.cc',
'renderer/text_input_client_observer.h',
- 'renderer/v8_value_converter_impl.cc',
- 'renderer/v8_value_converter_impl.h',
'renderer/web_ui_extension.cc',
'renderer/web_ui_extension.h',
'renderer/web_ui_extension_data.cc',
@@ -437,8 +425,8 @@
'renderer/webpublicsuffixlist_impl.h',
'renderer/webscrollbarbehavior_impl_gtkoraura.cc',
'renderer/webscrollbarbehavior_impl_gtkoraura.h',
- 'renderer/webscrollbarbehavior_impl_mac.mm',
'renderer/webscrollbarbehavior_impl_mac.h',
+ 'renderer/webscrollbarbehavior_impl_mac.mm',
'renderer/websharedworker_proxy.cc',
'renderer/websharedworker_proxy.h',
],
@@ -478,6 +466,8 @@
'renderer/pepper/pepper_broker.h',
'renderer/pepper/pepper_browser_connection.cc',
'renderer/pepper/pepper_browser_connection.h',
+ 'renderer/pepper/pepper_camera_device_host.cc',
+ 'renderer/pepper/pepper_camera_device_host.h',
'renderer/pepper/pepper_compositor_host.cc',
'renderer/pepper/pepper_compositor_host.h',
'renderer/pepper/pepper_device_enumeration_host_helper.cc',
@@ -502,12 +492,14 @@
'renderer/pepper/pepper_platform_audio_input.h',
'renderer/pepper/pepper_platform_audio_output.cc',
'renderer/pepper/pepper_platform_audio_output.h',
+ 'renderer/pepper/pepper_platform_camera_device.cc',
+ 'renderer/pepper/pepper_platform_camera_device.h',
'renderer/pepper/pepper_platform_video_capture.cc',
'renderer/pepper/pepper_platform_video_capture.h',
'renderer/pepper/pepper_plugin_instance_impl.cc',
'renderer/pepper/pepper_plugin_instance_impl.h',
- 'renderer/pepper/pepper_plugin_instance_throttler.cc',
- 'renderer/pepper/pepper_plugin_instance_throttler.h',
+ 'renderer/pepper/pepper_plugin_instance_metrics.cc',
+ 'renderer/pepper/pepper_plugin_instance_metrics.h',
'renderer/pepper/pepper_plugin_registry.cc',
'renderer/pepper/pepper_plugin_registry.h',
'renderer/pepper/pepper_proxy_channel_delegate_impl.cc',
@@ -520,10 +512,14 @@
'renderer/pepper/pepper_video_capture_host.h',
'renderer/pepper/pepper_video_decoder_host.cc',
'renderer/pepper/pepper_video_decoder_host.h',
+ 'renderer/pepper/pepper_video_encoder_host.cc',
+ 'renderer/pepper/pepper_video_encoder_host.h',
'renderer/pepper/pepper_webplugin_impl.cc',
'renderer/pepper/pepper_webplugin_impl.h',
'renderer/pepper/pepper_websocket_host.cc',
'renderer/pepper/pepper_websocket_host.h',
+ 'renderer/pepper/plugin_instance_throttler_impl.cc',
+ 'renderer/pepper/plugin_instance_throttler_impl.h',
'renderer/pepper/plugin_module.cc',
'renderer/pepper/plugin_module.h',
'renderer/pepper/plugin_object.cc',
@@ -565,23 +561,22 @@
'renderer/pepper/url_request_info_util.h',
'renderer/pepper/url_response_info_util.cc',
'renderer/pepper/url_response_info_util.h',
- 'renderer/pepper/usb_key_code_conversion.cc',
- 'renderer/pepper/usb_key_code_conversion.h',
- 'renderer/pepper/usb_key_code_conversion_linux.cc',
- 'renderer/pepper/usb_key_code_conversion_mac.cc',
- 'renderer/pepper/usb_key_code_conversion_win.cc',
- 'renderer/pepper/v8object_var.cc',
- 'renderer/pepper/v8object_var.h',
'renderer/pepper/v8_var_converter.cc',
'renderer/pepper/v8_var_converter.h',
+ 'renderer/pepper/v8object_var.cc',
+ 'renderer/pepper/v8object_var.h',
'renderer/pepper/video_decoder_shim.cc',
'renderer/pepper/video_decoder_shim.h',
+ 'renderer/pepper/video_encoder_shim.cc',
+ 'renderer/pepper/video_encoder_shim.h',
'renderer/render_widget_fullscreen_pepper.cc',
'renderer/render_widget_fullscreen_pepper.h',
],
'public_renderer_webrtc_sources': [
- 'public/renderer/media_stream_audio_sink.h',
+ 'public/renderer/media_stream_api.cc',
+ 'public/renderer/media_stream_api.h',
'public/renderer/media_stream_audio_sink.cc',
+ 'public/renderer/media_stream_audio_sink.h',
'public/renderer/media_stream_sink.h',
'public/renderer/media_stream_video_sink.cc',
'public/renderer/media_stream_video_sink.h',
@@ -590,20 +585,20 @@
# WebRTC-specific sources. Put WebRTC plugin-related stuff in the
# Plugin+WebRTC section below.
'private_renderer_webrtc_sources': [
- 'renderer/media/media_stream.h',
'renderer/media/media_stream.cc',
+ 'renderer/media/media_stream.h',
'renderer/media/media_stream_audio_processor.cc',
'renderer/media/media_stream_audio_processor.h',
'renderer/media/media_stream_audio_processor_options.cc',
'renderer/media/media_stream_audio_processor_options.h',
'renderer/media/media_stream_audio_sink_owner.cc',
'renderer/media/media_stream_audio_sink_owner.h',
+ 'renderer/media/media_stream_audio_source.cc',
+ 'renderer/media/media_stream_audio_source.h',
'renderer/media/media_stream_audio_track_sink.h',
'renderer/media/media_stream_center.cc',
'renderer/media/media_stream_dispatcher.cc',
'renderer/media/media_stream_registry_interface.h',
- 'renderer/media/media_stream_audio_source.cc',
- 'renderer/media/media_stream_audio_source.h',
'renderer/media/media_stream_renderer_factory.cc',
'renderer/media/media_stream_renderer_factory.h',
'renderer/media/media_stream_source.cc',
@@ -614,10 +609,6 @@
'renderer/media/media_stream_video_source.h',
'renderer/media/media_stream_video_track.cc',
'renderer/media/media_stream_video_track.h',
- 'renderer/media/native_handle_impl.cc',
- 'renderer/media/native_handle_impl.h',
- 'renderer/media/peer_connection_audio_sink_owner.cc',
- 'renderer/media/peer_connection_audio_sink_owner.h',
'renderer/media/peer_connection_identity_service.cc',
'renderer/media/peer_connection_identity_service.h',
'renderer/media/peer_connection_tracker.cc',
@@ -651,14 +642,14 @@
'renderer/media/video_track_adapter.h',
'renderer/media/webaudio_capturer_source.cc',
'renderer/media/webaudio_capturer_source.h',
- 'renderer/media/webrtc/webrtc_video_track_adapter.cc',
- 'renderer/media/webrtc/webrtc_video_track_adapter.h',
'renderer/media/webrtc/media_stream_remote_video_source.cc',
'renderer/media/webrtc/media_stream_remote_video_source.h',
'renderer/media/webrtc/media_stream_track_metrics.cc',
'renderer/media/webrtc/media_stream_track_metrics.h',
'renderer/media/webrtc/peer_connection_dependency_factory.cc',
'renderer/media/webrtc/peer_connection_dependency_factory.h',
+ 'renderer/media/webrtc/track_observer.cc',
+ 'renderer/media/webrtc/track_observer.h',
'renderer/media/webrtc/video_destination_handler.cc',
'renderer/media/webrtc/video_destination_handler.h',
'renderer/media/webrtc/webrtc_audio_sink_adapter.cc',
@@ -669,6 +660,8 @@
'renderer/media/webrtc/webrtc_media_stream_adapter.h',
'renderer/media/webrtc/webrtc_video_capturer_adapter.cc',
'renderer/media/webrtc/webrtc_video_capturer_adapter.h',
+ 'renderer/media/webrtc/webrtc_video_track_adapter.cc',
+ 'renderer/media/webrtc/webrtc_video_track_adapter.h',
'renderer/media/webrtc_audio_capturer.cc',
'renderer/media/webrtc_audio_capturer.h',
'renderer/media/webrtc_audio_device_impl.cc',
@@ -722,12 +715,6 @@
'<@(private_renderer_sources)',
],
'conditions': [
- ['notifications==0', {
- 'sources!': [
- 'renderer/notification_provider.cc',
- 'renderer/active_notification_tracker.cc',
- ],
- }],
['OS=="mac"', {
'sources!': [
'common/process_watcher_posix.cc',
@@ -740,8 +727,8 @@
],
}, {
'sources!': [
- 'renderer/webscrollbarbehavior_impl_mac.mm',
'renderer/webscrollbarbehavior_impl_mac.h',
+ 'renderer/webscrollbarbehavior_impl_mac.mm',
],
}],
['OS=="win" and win_use_allocator_shim==1', {
@@ -752,18 +739,15 @@
['OS=="android"', {
'sources!': [
'renderer/media/audio_decoder.cc',
- 'renderer/media/crypto/encrypted_media_player_support_impl.cc',
],
'sources': [
'renderer/external_popup_menu.cc',
'renderer/external_popup_menu.h',
],
'dependencies': [
+ '../build/android/ndk.gyp:cpu_features',
'../third_party/libphonenumber/libphonenumber.gyp:libphonenumber',
],
- 'includes': [
- '../build/android/cpufeatures.gypi',
- ],
}, {
'sources!': [
'renderer/java/gin_java_bridge_dispatcher.cc',
@@ -772,11 +756,12 @@
'renderer/java/gin_java_bridge_object.h',
'renderer/java/gin_java_bridge_value_converter.cc',
'renderer/java/gin_java_bridge_value_converter.h',
- 'renderer/java/java_bridge_channel.cc',
- 'renderer/java/java_bridge_channel.h',
- 'renderer/java/java_bridge_dispatcher.cc',
- 'renderer/java/java_bridge_dispatcher.h',
+ 'renderer/java/gin_java_function_invocation_helper.cc',
+ 'renderer/java/gin_java_function_invocation_helper.h',
],
+ 'dependencies': [
+ '../media/cast/cast.gyp:cast_sender',
+ ]
}],
# TODO(jrg): remove the OS=="android" section?
# http://crbug.com/113172
@@ -801,12 +786,13 @@
],
},{ # enable_webrtc==0
'sources': [
- 'renderer/media/webrtc_logging_noop.cc',
'renderer/media/webrtc_logging.h',
+ 'renderer/media/webrtc_logging_noop.cc',
],
}],
['enable_plugins==1', {
'sources': [
+ '<@(public_renderer_plugin_sources)',
'<@(private_renderer_plugin_sources)',
],
'conditions': [
@@ -815,6 +801,8 @@
# Android does not build FFmpeg, which these depend on.
'renderer/pepper/video_decoder_shim.cc',
'renderer/pepper/video_decoder_shim.h',
+ 'renderer/pepper/video_encoder_shim.cc',
+ 'renderer/pepper/video_encoder_shim.h',
],
}],
],
@@ -853,6 +841,9 @@
'renderer/media/crypto/renderer_cdm_manager.h',
],
}],
+ ['use_seccomp_bpf==1', {
+ 'defines': ['USE_SECCOMP_BPF'],
+ }],
],
'target_conditions': [
['OS=="android"', {
diff --git a/chromium/content/content_resources.grd b/chromium/content/content_resources.grd
index 445cc8d98d8..5a531299d88 100644
--- a/chromium/content/content_resources.grd
+++ b/chromium/content/content_resources.grd
@@ -38,13 +38,14 @@
<include name="IDR_UTILITY_SANDBOX_PROFILE" file="utility/utility.sb" type="BINDATA" />
</if>
<if expr="not is_ios">
- <include name="IDR_MOJO_BUFFER_JS" file="../mojo/public/js/buffer.js" flattenhtml="true" type="BINDATA" />
- <include name="IDR_MOJO_CODEC_JS" file="../mojo/public/js/codec.js" flattenhtml="true" type="BINDATA" />
- <include name="IDR_MOJO_CONNECTION_JS" file="../mojo/public/js/connection.js" flattenhtml="true" type="BINDATA" />
- <include name="IDR_MOJO_CONNECTOR_JS" file="../mojo/public/js/connector.js" flattenhtml="true" type="BINDATA" />
- <include name="IDR_MOJO_ROUTER_JS" file="../mojo/public/js/router.js" flattenhtml="true" type="BINDATA" />
- <include name="IDR_MOJO_UNICODE_JS" file="../mojo/public/js/unicode.js" flattenhtml="true" type="BINDATA" />
- <include name="IDR_MOJO_VALIDATOR_JS" file="../mojo/public/js/validator.js" flattenhtml="true" type="BINDATA" />
+ <include name="IDR_MOJO_BINDINGS_JS" file="../third_party/mojo/src/mojo/public/js/bindings.js" flattenhtml="true" type="BINDATA" />
+ <include name="IDR_MOJO_BUFFER_JS" file="../third_party/mojo/src/mojo/public/js/buffer.js" flattenhtml="true" type="BINDATA" />
+ <include name="IDR_MOJO_CODEC_JS" file="../third_party/mojo/src/mojo/public/js/codec.js" flattenhtml="true" type="BINDATA" />
+ <include name="IDR_MOJO_CONNECTION_JS" file="../third_party/mojo/src/mojo/public/js/connection.js" flattenhtml="true" type="BINDATA" />
+ <include name="IDR_MOJO_CONNECTOR_JS" file="../third_party/mojo/src/mojo/public/js/connector.js" flattenhtml="true" type="BINDATA" />
+ <include name="IDR_MOJO_ROUTER_JS" file="../third_party/mojo/src/mojo/public/js/router.js" flattenhtml="true" type="BINDATA" />
+ <include name="IDR_MOJO_UNICODE_JS" file="../third_party/mojo/src/mojo/public/js/unicode.js" flattenhtml="true" type="BINDATA" />
+ <include name="IDR_MOJO_VALIDATOR_JS" file="../third_party/mojo/src/mojo/public/js/validator.js" flattenhtml="true" type="BINDATA" />
</if>
</includes>
</release>
diff --git a/chromium/content/content_shell.gypi b/chromium/content/content_shell.gypi
index 0ba38e16ba8..08e1ca0ba34 100644
--- a/chromium/content/content_shell.gypi
+++ b/chromium/content/content_shell.gypi
@@ -46,8 +46,11 @@
'../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
'../cc/blink/cc_blink.gyp:cc_blink',
'../cc/cc.gyp:cc',
- '../components/components.gyp:crash_component',
+ '../components/components.gyp:crash_component_breakpad_mac_to_be_deleted',
+ '../components/components.gyp:devtools_discovery',
+ '../components/components.gyp:devtools_http_handler',
'../components/components.gyp:web_cache_renderer',
+ '../device/bluetooth/bluetooth.gyp:device_bluetooth',
'../gin/gin.gyp:gin',
'../gpu/gpu.gyp:gpu',
'../ipc/ipc.gyp:ipc',
@@ -59,6 +62,7 @@
'../storage/storage_browser.gyp:storage',
'../third_party/WebKit/public/blink.gyp:blink',
'../third_party/WebKit/public/blink.gyp:blink_test_support',
+ '../ui/base/ime/ui_base_ime.gyp:ui_base_ime',
'../ui/base/ui_base.gyp:ui_base',
'../ui/events/events.gyp:events_base',
'../ui/gfx/gfx.gyp:gfx',
@@ -90,6 +94,8 @@
'shell/app/shell_main_delegate.h',
'shell/app/shell_main_delegate_mac.h',
'shell/app/shell_main_delegate_mac.mm',
+ 'shell/browser/blink_test_controller.cc',
+ 'shell/browser/blink_test_controller.h',
'shell/browser/ipc_echo_message_filter.cc',
'shell/browser/ipc_echo_message_filter.h',
'shell/browser/layout_test/layout_test_android.cc',
@@ -102,16 +108,22 @@
'shell/browser/layout_test/layout_test_browser_main_parts.h',
'shell/browser/layout_test/layout_test_content_browser_client.cc',
'shell/browser/layout_test/layout_test_content_browser_client.h',
- 'shell/browser/layout_test/layout_test_download_manager_delegate.cc',
- 'shell/browser/layout_test/layout_test_download_manager_delegate.h',
'shell/browser/layout_test/layout_test_devtools_frontend.cc',
'shell/browser/layout_test/layout_test_devtools_frontend.h',
+ 'shell/browser/layout_test/layout_test_download_manager_delegate.cc',
+ 'shell/browser/layout_test/layout_test_download_manager_delegate.h',
'shell/browser/layout_test/layout_test_javascript_dialog_manager.cc',
'shell/browser/layout_test/layout_test_javascript_dialog_manager.h',
'shell/browser/layout_test/layout_test_message_filter.cc',
'shell/browser/layout_test/layout_test_message_filter.h',
+ 'shell/browser/layout_test/layout_test_navigator_connect_service_factory.cc',
+ 'shell/browser/layout_test/layout_test_navigator_connect_service_factory.h',
'shell/browser/layout_test/layout_test_notification_manager.cc',
'shell/browser/layout_test/layout_test_notification_manager.h',
+ 'shell/browser/layout_test/layout_test_permission_manager.cc',
+ 'shell/browser/layout_test/layout_test_permission_manager.h',
+ 'shell/browser/layout_test/layout_test_push_messaging_service.cc',
+ 'shell/browser/layout_test/layout_test_push_messaging_service.h',
'shell/browser/layout_test/layout_test_resource_dispatcher_host_delegate.cc',
'shell/browser/layout_test/layout_test_resource_dispatcher_host_delegate.h',
'shell/browser/layout_test/layout_test_url_request_context_getter.cc',
@@ -135,10 +147,10 @@
'shell/browser/shell_browser_main_parts_mac.mm',
'shell/browser/shell_content_browser_client.cc',
'shell/browser/shell_content_browser_client.h',
- 'shell/browser/shell_devtools_manager_delegate.cc',
- 'shell/browser/shell_devtools_manager_delegate.h',
'shell/browser/shell_devtools_frontend.cc',
'shell/browser/shell_devtools_frontend.h',
+ 'shell/browser/shell_devtools_manager_delegate.cc',
+ 'shell/browser/shell_devtools_manager_delegate.h',
'shell/browser/shell_download_manager_delegate.cc',
'shell/browser/shell_download_manager_delegate.h',
'shell/browser/shell_javascript_dialog.h',
@@ -146,16 +158,18 @@
'shell/browser/shell_javascript_dialog_manager.cc',
'shell/browser/shell_javascript_dialog_manager.h',
'shell/browser/shell_javascript_dialog_win.cc',
- 'shell/browser/shell_mojo_test_utils_android.cc',
- 'shell/browser/shell_mojo_test_utils_android.h',
'shell/browser/shell_login_dialog.cc',
'shell/browser/shell_login_dialog.h',
'shell/browser/shell_login_dialog_mac.mm',
'shell/browser/shell_mac.mm',
+ 'shell/browser/shell_mojo_test_utils_android.cc',
+ 'shell/browser/shell_mojo_test_utils_android.h',
'shell/browser/shell_net_log.cc',
'shell/browser/shell_net_log.h',
'shell/browser/shell_network_delegate.cc',
'shell/browser/shell_network_delegate.h',
+ 'shell/browser/shell_permission_manager.cc',
+ 'shell/browser/shell_permission_manager.h',
'shell/browser/shell_platform_data_aura.cc',
'shell/browser/shell_platform_data_aura.h',
'shell/browser/shell_plugin_service_filter.cc',
@@ -169,13 +183,11 @@
'shell/browser/shell_url_request_context_getter.cc',
'shell/browser/shell_url_request_context_getter.h',
'shell/browser/shell_views.cc',
+ 'shell/browser/shell_web_contents_view_delegate.h',
'shell/browser/shell_web_contents_view_delegate_android.cc',
'shell/browser/shell_web_contents_view_delegate_creator.h',
- 'shell/browser/shell_web_contents_view_delegate.h',
'shell/browser/shell_web_contents_view_delegate_mac.mm',
'shell/browser/shell_web_contents_view_delegate_win.cc',
- 'shell/browser/webkit_test_controller.cc',
- 'shell/browser/webkit_test_controller.h',
'shell/common/layout_test/layout_test_messages.cc',
'shell/common/layout_test/layout_test_messages.h',
'shell/common/leak_detection_result.h',
@@ -191,10 +203,12 @@
'shell/common/test_runner/test_preferences.h',
'shell/common/v8_breakpad_support_win.cc',
'shell/common/v8_breakpad_support_win.h',
- 'shell/common/webkit_test_helpers.cc',
- 'shell/common/webkit_test_helpers.h',
'shell/renderer/ipc_echo.cc',
'shell/renderer/ipc_echo.h',
+ 'shell/renderer/layout_test/blink_test_helpers.cc',
+ 'shell/renderer/layout_test/blink_test_helpers.h',
+ 'shell/renderer/layout_test/blink_test_runner.cc',
+ 'shell/renderer/layout_test/blink_test_runner.h',
'shell/renderer/layout_test/gc_controller.cc',
'shell/renderer/layout_test/gc_controller.h',
'shell/renderer/layout_test/layout_test_content_renderer_client.cc',
@@ -205,8 +219,6 @@
'shell/renderer/layout_test/layout_test_render_process_observer.h',
'shell/renderer/layout_test/leak_detector.cc',
'shell/renderer/layout_test/leak_detector.h',
- 'shell/renderer/layout_test/webkit_test_runner.cc',
- 'shell/renderer/layout_test/webkit_test_runner.h',
'shell/renderer/shell_content_renderer_client.cc',
'shell/renderer/shell_content_renderer_client.h',
'shell/renderer/shell_render_view_observer.cc',
@@ -235,8 +247,6 @@
'shell/renderer/test_runner/mock_web_media_stream_center.h',
'shell/renderer/test_runner/mock_web_midi_accessor.cc',
'shell/renderer/test_runner/mock_web_midi_accessor.h',
- 'shell/renderer/test_runner/mock_web_push_client.cc',
- 'shell/renderer/test_runner/mock_web_push_client.h',
'shell/renderer/test_runner/mock_web_speech_recognizer.cc',
'shell/renderer/test_runner/mock_web_speech_recognizer.h',
'shell/renderer/test_runner/mock_web_theme_engine.cc',
@@ -249,8 +259,6 @@
'shell/renderer/test_runner/mock_webrtc_dtmf_sender_handler.h',
'shell/renderer/test_runner/mock_webrtc_peer_connection_handler.cc',
'shell/renderer/test_runner/mock_webrtc_peer_connection_handler.h',
- 'shell/renderer/test_runner/notification_presenter.cc',
- 'shell/renderer/test_runner/notification_presenter.h',
'shell/renderer/test_runner/spell_check_client.cc',
'shell/renderer/test_runner/spell_check_client.h',
'shell/renderer/test_runner/test_common.cc',
@@ -265,9 +273,9 @@
'shell/renderer/test_runner/text_input_controller.h',
'shell/renderer/test_runner/web_ax_object_proxy.cc',
'shell/renderer/test_runner/web_ax_object_proxy.h',
+ 'shell/renderer/test_runner/web_content_settings.cc',
+ 'shell/renderer/test_runner/web_content_settings.h',
'shell/renderer/test_runner/web_frame_test_proxy.h',
- 'shell/renderer/test_runner/web_permissions.cc',
- 'shell/renderer/test_runner/web_permissions.h',
'shell/renderer/test_runner/web_task.cc',
'shell/renderer/test_runner/web_task.h',
'shell/renderer/test_runner/web_test_delegate.h',
@@ -327,7 +335,7 @@
'copy_test_netscape_plugin',
],
}], # OS=="android"
- ['os_posix == 1 and OS != "mac" and android_webview_build != 1', {
+ ['os_posix == 1 and OS != "mac"', {
'dependencies': [
'../components/components.gyp:breakpad_host',
],
@@ -499,6 +507,7 @@
'variables': {
'pak_inputs': [
'<(SHARED_INTERMEDIATE_DIR)/blink/public/resources/blink_resources.pak',
+ '<(SHARED_INTERMEDIATE_DIR)/blink/public/resources/blink_image_resources_100_percent.pak',
'<(SHARED_INTERMEDIATE_DIR)/content/app/resources/content_resources_100_percent.pak',
'<(SHARED_INTERMEDIATE_DIR)/content/app/strings/content_strings_en-US.pak',
'<(SHARED_INTERMEDIATE_DIR)/content/browser/tracing/tracing_resources.pak',
@@ -512,7 +521,7 @@
],
'conditions': [
['OS!="android"', {
- 'pak_inputs': ['<(SHARED_INTERMEDIATE_DIR)/webkit/devtools_resources.pak',],
+ 'pak_inputs': ['<(SHARED_INTERMEDIATE_DIR)/blink/devtools_resources.pak',],
'pak_output': '<(PRODUCT_DIR)/content_shell.pak',
}, {
'pak_output': '<(PRODUCT_DIR)/content_shell/assets/content_shell.pak',
@@ -655,15 +664,13 @@
],
}], # OS=="mac"
['OS=="android"', {
+ 'dependencies': [
+ '../tools/imagediff/image_diff.gyp:image_diff#host',
+ ],
'dependencies!': [
'../tools/imagediff/image_diff.gyp:image_diff',
],
}], # OS=="android"
- ['OS=="android" and android_webview_build==0', {
- 'dependencies': [
- '../tools/imagediff/image_diff.gyp:image_diff#host',
- ],
- }], # OS=="android" and android_webview_build==0
],
},
{
@@ -734,10 +741,18 @@
'-fvisibility=default',
],
}],
+ ['use_x11 == 1', {
+ 'dependencies': [ '../build/linux/system.gyp:x11' ],
+ }],
['OS=="win"', {
- 'defines': [
- # This seems like a hack, but this is what Safari Win does.
- 'snprintf=_snprintf',
+ 'conditions': [
+ ['MSVS_VERSION < "2015"', {
+ 'defines': [
+ # This seems like a hack, but this is what Safari Win does.
+ # Luckily it is no longer needed/allowed with VS 2015.
+ 'snprintf=_snprintf',
+ ],
+ }],
],
'sources': [
'shell/tools/plugin/win/TestNetscapePlugin.def',
@@ -782,6 +797,7 @@
['OS=="mac" or OS=="win"', {
'targets': [
{
+ # GN version: //content/shell:layout_test_helper
'target_name': 'layout_test_helper',
'type': 'executable',
'sources': [
@@ -894,6 +910,12 @@
'<(PRODUCT_DIR)/icudtl.dat',
],
}],
+ ['v8_use_external_startup_data==1', {
+ 'mac_bundle_resources': [
+ '<(PRODUCT_DIR)/natives_blob.bin',
+ '<(PRODUCT_DIR)/snapshot_blob.bin',
+ ],
+ }],
],
}, # target content_shell_framework
{
@@ -1008,14 +1030,6 @@
],
'sources': [
'shell/android/shell_library_loader.cc',
- 'shell/android/shell_library_loader.h',
- ],
- 'conditions': [
- ['android_webview_build==1', {
- 'ldflags': [
- '-lgabi++', # For rtti
- ],
- }],
],
},
{
@@ -1046,6 +1060,17 @@
'includes': [ '../build/apk_fake_jar.gypi' ],
},
{
+ # GN version: //content/shell/android:content_shell_manifest
+ 'target_name': 'content_shell_manifest',
+ 'type': 'none',
+ 'variables': {
+ 'jinja_inputs': ['shell/android/shell_apk/AndroidManifest.xml.jinja2'],
+ 'jinja_output': '<(SHARED_INTERMEDIATE_DIR)/content_shell_manifest/AndroidManifest.xml',
+ },
+ 'includes': [ '../build/android/jinja_template.gypi' ],
+ },
+ {
+ # GN version: //content/shell/android:content_shell_apk
'target_name': 'content_shell_apk',
'type': 'none',
'dependencies': [
@@ -1060,11 +1085,13 @@
'../net/net.gyp:net_java',
'../third_party/mesa/mesa.gyp:osmesa_in_lib_dir',
'../tools/android/forwarder/forwarder.gyp:forwarder',
+ '../tools/imagediff/image_diff.gyp:image_diff#host',
'../ui/android/ui_android.gyp:ui_java',
],
'variables': {
'apk_name': 'ContentShell',
'manifest_package_name': 'org.chromium.content_shell_apk',
+ 'android_manifest_path': '<(SHARED_INTERMEDIATE_DIR)/content_shell_manifest/AndroidManifest.xml',
'java_in_dir': 'shell/android/shell_apk',
'resource_dir': 'shell/android/shell_apk/res',
'native_lib_target': 'libcontent_shell_content_view',
@@ -1085,13 +1112,6 @@
}],
],
},
- 'conditions': [
- ['android_webview_build==0', {
- 'dependencies': [
- '../tools/imagediff/image_diff.gyp:image_diff#host',
- ],
- }],
- ],
'includes': [ '../build/java_apk.gypi' ],
},
],
@@ -1099,6 +1119,7 @@
['OS=="win"', {
'targets': [
{
+ # GN version: //content/shell:crash_service
'target_name': 'content_shell_crash_service',
'type': 'executable',
'dependencies': [
@@ -1141,7 +1162,7 @@
],
'action': [
'python',
- '<(DEPTH)/chrome/tools/build/win/syzygy_instrument.py',
+ '<(DEPTH)/chrome/tools/build/win/syzygy/instrument.py',
'--mode', 'asan',
'--input_executable', '<(PRODUCT_DIR)/content_shell.exe',
'--input_symbol', '<(PRODUCT_DIR)/content_shell.exe.pdb',
diff --git a/chromium/content/content_shell_test_apk.isolate b/chromium/content/content_shell_test_apk.isolate
new file mode 100644
index 00000000000..46c76580a34
--- /dev/null
+++ b/chromium/content/content_shell_test_apk.isolate
@@ -0,0 +1,20 @@
+# 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.
+{
+ 'conditions': [
+ ['OS=="android"', {
+ 'variables': {
+ 'files': [
+ '<(DEPTH)/content/test/data/android/',
+ '<(DEPTH)/net/data/ssl/certificates/crit-codeSigning-chain.pem',
+ '<(DEPTH)/net/data/ssl/certificates/eku-test-root.pem',
+ '<(DEPTH)/net/data/ssl/certificates/invalid_key_usage_cert.der',
+ '<(DEPTH)/net/data/ssl/certificates/non-crit-codeSigning-chain.pem',
+ '<(DEPTH)/net/data/ssl/certificates/ok_cert.pem',
+ '<(DEPTH)/net/data/ssl/certificates/root_ca_cert.pem',
+ ],
+ },
+ }],
+ ],
+}
diff --git a/chromium/content/content_tests.gypi b/chromium/content/content_tests.gypi
index ceb8a35b7c2..fa04ec89612 100644
--- a/chromium/content/content_tests.gypi
+++ b/chromium/content/content_tests.gypi
@@ -15,11 +15,22 @@
'test/test_video_frame_provider.h',
],
'test_support_content_sources': [
+ # TODO(phajdan.jr): All of those files should live in content/test (if
+ # they're only used by content) or content/public/test (if they're used
+ # by other embedders).
+ 'browser/download/mock_download_file.cc',
+ 'browser/download/mock_download_file.h',
+ 'browser/geolocation/fake_access_token_store.cc',
+ 'browser/geolocation/fake_access_token_store.h',
+ 'browser/geolocation/mock_location_arbitrator.cc',
+ 'browser/geolocation/mock_location_arbitrator.h',
+ 'browser/geolocation/mock_location_provider.cc',
+ 'browser/geolocation/mock_location_provider.h',
'public/test/async_file_test_helper.cc',
'public/test/async_file_test_helper.h',
+ 'public/test/browser_test.h',
'public/test/browser_test_base.cc',
'public/test/browser_test_base.h',
- 'public/test/browser_test.h',
'public/test/browser_test_utils.cc',
'public/test/browser_test_utils.h',
'public/test/content_test_suite_base.cc',
@@ -50,6 +61,8 @@
'public/test/mock_special_storage_policy.h',
'public/test/mock_storage_client.cc',
'public/test/mock_storage_client.h',
+ 'public/test/ppapi_test_utils.cc',
+ 'public/test/ppapi_test_utils.h',
'public/test/render_view_test.cc',
'public/test/render_view_test.h',
'public/test/render_widget_test.cc',
@@ -80,35 +93,33 @@
'public/test/test_notification_tracker.h',
'public/test/test_renderer_host.cc',
'public/test/test_renderer_host.h',
+ 'public/test/test_synchronous_compositor_android.cc',
+ 'public/test/test_synchronous_compositor_android.h',
'public/test/test_utils.cc',
'public/test/test_utils.h',
+ 'public/test/test_web_contents_factory.h',
'public/test/unittest_test_suite.cc',
'public/test/unittest_test_suite.h',
'public/test/web_contents_tester.cc',
'public/test/web_contents_tester.h',
- # TODO(phajdan.jr): All of those files should live in content/test (if
- # they're only used by content) or content/public/test (if they're used
- # by other embedders).
- 'browser/download/mock_download_file.cc',
- 'browser/download/mock_download_file.h',
- 'browser/geolocation/fake_access_token_store.cc',
- 'browser/geolocation/fake_access_token_store.h',
- 'browser/geolocation/mock_location_arbitrator.cc',
- 'browser/geolocation/mock_location_arbitrator.h',
- 'browser/geolocation/mock_location_provider.cc',
- 'browser/geolocation/mock_location_provider.h',
- 'browser/renderer_host/media/mock_media_observer.cc',
- 'browser/renderer_host/media/mock_media_observer.h',
- 'browser/renderer_host/test/no_transport_image_transport_factory_android.cc',
- 'browser/renderer_host/test/no_transport_image_transport_factory_android.h',
'test/appcache_test_helper.cc',
'test/appcache_test_helper.h',
'test/blink_test_environment.cc',
'test/blink_test_environment.h',
+ 'test/browser_side_navigation_test_utils.cc',
+ 'test/browser_side_navigation_test_utils.h',
+ 'test/content_browser_sanity_checker.cc',
+ 'test/content_browser_sanity_checker.h',
'test/content_browser_test_utils_internal.cc',
'test/content_browser_test_utils_internal.h',
'test/content_test_suite.cc',
'test/content_test_suite.h',
+ 'test/fake_compositor_dependencies.cc',
+ 'test/fake_compositor_dependencies.h',
+ 'test/fake_plugin_service.cc',
+ 'test/fake_plugin_service.h',
+ 'test/fake_renderer_scheduler.cc',
+ 'test/fake_renderer_scheduler.h',
'test/mock_google_streaming_server.cc',
'test/mock_google_streaming_server.h',
'test/mock_keyboard.cc',
@@ -126,10 +137,10 @@
'test/mock_weburlloader.h',
'test/net/url_request_abort_on_end_job.cc',
'test/net/url_request_abort_on_end_job.h',
- 'test/net/url_request_slow_download_job.cc',
- 'test/net/url_request_slow_download_job.h',
'test/ppapi_unittest.cc',
'test/ppapi_unittest.h',
+ 'test/render_thread_impl_browser_test_ipc_helper.cc',
+ 'test/render_thread_impl_browser_test_ipc_helper.h',
'test/test_blink_web_unit_test_support.cc',
'test/test_blink_web_unit_test_support.h',
'test/test_content_browser_client.cc',
@@ -138,6 +149,10 @@
'test/test_content_client.h',
'test/test_frame_navigation_observer.cc',
'test/test_frame_navigation_observer.h',
+ 'test/test_navigation_url_loader.cc',
+ 'test/test_navigation_url_loader.h',
+ 'test/test_navigation_url_loader_factory.cc',
+ 'test/test_navigation_url_loader_factory.h',
'test/test_render_frame_host.cc',
'test/test_render_frame_host.h',
'test/test_render_frame_host_factory.cc',
@@ -148,6 +163,9 @@
'test/test_render_view_host_factory.h',
'test/test_web_contents.cc',
'test/test_web_contents.h',
+ 'test/test_web_contents_factory.cc',
+ 'test/web_contents_observer_sanity_checker.cc',
+ 'test/web_contents_observer_sanity_checker.h',
'test/web_gesture_curve_mock.cc',
'test/web_gesture_curve_mock.h',
'test/web_layer_tree_view_impl_for_testing.cc',
@@ -156,7 +174,581 @@
'test/weburl_loader_mock.h',
'test/weburl_loader_mock_factory.cc',
'test/weburl_loader_mock_factory.h',
- ]
+ ],
+ 'content_browsertests_sources': [
+ 'app/mojo/mojo_browsertest.cc',
+ 'browser/accessibility/accessibility_event_recorder.cc',
+ 'browser/accessibility/accessibility_event_recorder.h',
+ 'browser/accessibility/accessibility_event_recorder_mac.mm',
+ 'browser/accessibility/accessibility_event_recorder_win.cc',
+ 'browser/accessibility/accessibility_ipc_error_browsertest.cc',
+ 'browser/accessibility/accessibility_mode_browsertest.cc',
+ 'browser/accessibility/cross_platform_accessibility_browsertest.cc',
+ 'browser/accessibility/dump_accessibility_browsertest_base.cc',
+ 'browser/accessibility/dump_accessibility_browsertest_base.h',
+ 'browser/accessibility/dump_accessibility_events_browsertest.cc',
+ 'browser/accessibility/dump_accessibility_tree_browsertest.cc',
+ 'browser/accessibility/site_per_process_accessibility_browsertest.cc',
+ 'browser/accessibility/snapshot_ax_tree_browsertest.cc',
+ 'browser/battery_status/battery_monitor_impl_browsertest.cc',
+ 'browser/battery_status/battery_monitor_integration_browsertest.cc',
+ 'browser/bookmarklet_browsertest.cc',
+ 'browser/browser_side_navigation_browsertest.cc',
+ 'browser/child_process_launcher_browsertest.cc',
+ 'browser/child_process_security_policy_browsertest.cc',
+ 'browser/compositor/image_transport_factory_browsertest.cc',
+ 'browser/cross_site_transfer_browsertest.cc',
+ 'browser/database_browsertest.cc',
+ 'browser/device_sensors/device_inertial_sensor_browsertest.cc',
+ 'browser/devtools/protocol/devtools_protocol_browsertest.cc',
+ 'browser/devtools/site_per_process_devtools_browsertest.cc',
+ 'browser/dom_storage/dom_storage_browsertest.cc',
+ 'browser/download/download_browsertest.cc',
+ 'browser/download/drag_download_file_browsertest.cc',
+ 'browser/download/mhtml_generation_browsertest.cc',
+ 'browser/download/save_package_browsertest.cc',
+ 'browser/fileapi/file_system_browsertest.cc',
+ 'browser/frame_host/frame_tree_browsertest.cc',
+ 'browser/frame_host/navigation_controller_impl_browsertest.cc',
+ 'browser/frame_host/render_frame_host_impl_browsertest.cc',
+ 'browser/frame_host/render_frame_host_manager_browsertest.cc',
+ 'browser/gpu/gpu_ipc_browsertests.cc',
+ 'browser/host_zoom_map_impl_browsertest.cc',
+ 'browser/indexed_db/indexed_db_browsertest.cc',
+ 'browser/indexed_db/mock_browsertest_indexed_db_class_factory.cc',
+ 'browser/indexed_db/mock_browsertest_indexed_db_class_factory.h',
+ 'browser/loader/resource_dispatcher_host_browsertest.cc',
+ 'browser/manifest/manifest_browsertest.cc',
+ 'browser/media/encrypted_media_browsertest.cc',
+ 'browser/media/media_browsertest.cc',
+ 'browser/media/media_browsertest.h',
+ 'browser/media/media_canplaytype_browsertest.cc',
+ 'browser/media/media_source_browsertest.cc',
+ 'browser/message_port_provider_browsertest.cc',
+ 'browser/net_info_browsertest.cc',
+ 'browser/plugin_browsertest.cc',
+ 'browser/renderer_host/input/touch_action_browsertest.cc',
+ 'browser/renderer_host/input/touch_input_browsertest.cc',
+ 'browser/renderer_host/render_process_host_browsertest.cc',
+ 'browser/renderer_host/render_view_host_browsertest.cc',
+ 'browser/renderer_host/render_widget_host_view_browsertest.cc',
+ 'browser/screen_orientation/screen_orientation_browsertest.cc',
+ 'browser/security_exploit_browsertest.cc',
+ 'browser/service_worker/service_worker_browsertest.cc',
+ 'browser/session_history_browsertest.cc',
+ 'browser/shared_worker/worker_browsertest.cc',
+ 'browser/site_per_process_browsertest.cc',
+ 'browser/site_per_process_browsertest.h',
+ 'browser/tracing/tracing_controller_browsertest.cc',
+ 'browser/transition_browsertest.cc',
+ 'browser/web_contents/opened_by_dom_browsertest.cc',
+ 'browser/web_contents/touch_editable_impl_aura_browsertest.cc',
+ 'browser/web_contents/web_contents_impl_browsertest.cc',
+ 'browser/web_contents/web_contents_view_aura_browsertest.cc',
+ 'browser/webkit_browsertest.cc',
+ 'browser/webui/web_ui_mojo_browsertest.cc',
+ 'child/child_thread_impl_browsertest.cc',
+ 'child/site_isolation_policy_browsertest.cc',
+ 'renderer/accessibility/renderer_accessibility_browsertest.cc',
+ 'renderer/devtools/v8_sampling_profiler_browsertest.cc',
+ 'renderer/gin_browsertest.cc',
+ 'renderer/mouse_lock_dispatcher_browsertest.cc',
+ 'renderer/render_frame_impl_browsertest.cc',
+ 'renderer/render_thread_impl_browsertest.cc',
+ 'renderer/render_view_browsertest.cc',
+ 'renderer/render_view_browsertest_mac.mm',
+ 'renderer/render_widget_browsertest.cc',
+ 'renderer/visual_state_browsertest.cc',
+ 'test/accessibility_browser_test_utils.cc',
+ 'test/accessibility_browser_test_utils.h',
+ 'test/browser_test_utils_browsertest.cc',
+ 'test/content_browser_test_test.cc',
+ 'test/webui_resource_browsertest.cc',
+
+ ],
+ 'content_browsertests_android_sources': [
+ 'browser/accessibility/android_granularity_movement_browsertest.cc',
+ 'browser/accessibility/android_hit_testing_browsertest.cc',
+ 'shell/android/browsertests_apk/content_browser_tests_android.cc',
+ 'shell/android/browsertests_apk/content_browser_tests_android.h',
+ 'shell/android/browsertests_apk/content_browser_tests_jni_onload.cc',
+ ],
+ 'content_browsertests_webrtc_sources': [
+ 'browser/media/webrtc_aecdump_browsertest.cc',
+ 'browser/media/webrtc_browsertest.cc',
+ 'browser/media/webrtc_getusermedia_browsertest.cc',
+ 'browser/media/webrtc_internals_browsertest.cc',
+ 'browser/media/webrtc_webcam_browsertest.cc',
+ 'test/webrtc_content_browsertest_base.cc',
+ 'test/webrtc_content_browsertest_base.h',
+ ],
+ 'content_browsertests_plugins_sources': [
+ 'browser/plugin_data_remover_impl_browsertest.cc',
+ 'browser/plugin_service_impl_browsertest.cc',
+ 'renderer/pepper/fake_pepper_plugin_instance.cc',
+ 'renderer/pepper/mock_renderer_ppapi_host.cc',
+ 'renderer/pepper/pepper_device_enumeration_host_helper_unittest.cc',
+ 'renderer/pepper/pepper_file_chooser_host_unittest.cc',
+ 'renderer/pepper/pepper_graphics_2d_host_unittest.cc',
+ 'renderer/pepper/pepper_url_request_unittest.cc',
+ 'renderer/pepper/pepper_webplugin_impl_browsertest.cc',
+ 'renderer/pepper/plugin_power_saver_helper_browsertest.cc',
+ 'test/ppapi/ppapi_browsertest.cc',
+ 'test/ppapi/ppapi_test.cc',
+ 'test/ppapi/ppapi_test.h',
+ ],
+ 'content_browsertests_speech_sources': [
+ 'browser/speech/speech_recognition_browsertest.cc',
+ ],
+ 'content_browsertests_unofficial_build_sources': [
+ # These tests depend on single process mode, which is disabled
+ # in official builds.
+ 'renderer/browser_render_view_browsertest.cc',
+ 'renderer/dom_serializer_browsertest.cc',
+ 'renderer/resource_fetcher_browsertest.cc',
+ 'renderer/savable_resources_browsertest.cc',
+ ],
+ 'content_browsertests_win_sources': [
+ 'browser/accessibility/accessibility_win_browsertest.cc',
+ ],
+ 'content_unittests_sources': [
+ 'browser/accessibility/accessibility_mode_helper_unittest.cc',
+ 'browser/accessibility/browser_accessibility_mac_unittest.mm',
+ 'browser/accessibility/browser_accessibility_manager_unittest.cc',
+ 'browser/accessibility/browser_accessibility_win_unittest.cc',
+ 'browser/accessibility/one_shot_accessibility_tree_search_unittest.cc',
+ 'browser/appcache/appcache_database_unittest.cc',
+ 'browser/appcache/appcache_disk_cache_unittest.cc',
+ 'browser/appcache/appcache_group_unittest.cc',
+ 'browser/appcache/appcache_host_unittest.cc',
+ 'browser/appcache/appcache_manifest_parser_unittest.cc',
+ 'browser/appcache/appcache_quota_client_unittest.cc',
+ 'browser/appcache/appcache_request_handler_unittest.cc',
+ 'browser/appcache/appcache_response_unittest.cc',
+ 'browser/appcache/appcache_service_unittest.cc',
+ 'browser/appcache/appcache_storage_impl_unittest.cc',
+ 'browser/appcache/appcache_storage_unittest.cc',
+ 'browser/appcache/appcache_unittest.cc',
+ 'browser/appcache/appcache_update_job_unittest.cc',
+ 'browser/appcache/appcache_url_request_job_unittest.cc',
+ 'browser/appcache/chrome_appcache_service_unittest.cc',
+ 'browser/appcache/mock_appcache_policy.cc',
+ 'browser/appcache/mock_appcache_policy.h',
+ 'browser/appcache/mock_appcache_service.cc',
+ 'browser/appcache/mock_appcache_service.h',
+ 'browser/appcache/mock_appcache_storage.cc',
+ 'browser/appcache/mock_appcache_storage.h',
+ 'browser/appcache/mock_appcache_storage_unittest.cc',
+ 'browser/background_sync/background_sync_manager_unittest.cc',
+ 'browser/background_sync/background_sync_network_observer_unittest.cc',
+ 'browser/browser_thread_unittest.cc',
+ 'browser/browser_url_handler_impl_unittest.cc',
+ 'browser/byte_stream_unittest.cc',
+ 'browser/cache_storage/cache_storage_cache_unittest.cc',
+ 'browser/cache_storage/cache_storage_manager_unittest.cc',
+ 'browser/cache_storage/cache_storage_scheduler_unittest.cc',
+ 'browser/child_process_security_policy_unittest.cc',
+ 'browser/cocoa/system_hotkey_map_unittest.mm',
+ 'browser/compositor/buffer_queue_unittest.cc',
+ 'browser/compositor/reflector_impl_unittest.cc',
+ 'browser/compositor/software_browser_compositor_output_surface_unittest.cc',
+ 'browser/compositor/software_output_device_ozone_unittest.cc',
+ 'browser/database_quota_client_unittest.cc',
+ 'browser/database_tracker_unittest.cc',
+ 'browser/database_util_unittest.cc',
+ 'browser/databases_table_unittest.cc',
+ 'browser/device_sensors/data_fetcher_shared_memory_base_unittest.cc',
+ 'browser/device_sensors/sensor_manager_android_unittest.cc',
+ 'browser/device_sensors/sensor_manager_chromeos_unittest.cc',
+ 'browser/devtools/devtools_manager_unittest.cc',
+ 'browser/devtools/shared_worker_devtools_manager_unittest.cc',
+ 'browser/dom_storage/dom_storage_area_unittest.cc',
+ 'browser/dom_storage/dom_storage_context_impl_unittest.cc',
+ 'browser/dom_storage/dom_storage_database_unittest.cc',
+ 'browser/dom_storage/session_storage_database_unittest.cc',
+ 'browser/download/base_file_unittest.cc',
+ 'browser/download/download_file_unittest.cc',
+ 'browser/download/download_item_impl_unittest.cc',
+ 'browser/download/download_manager_impl_unittest.cc',
+ 'browser/download/file_metadata_unittest_linux.cc',
+ 'browser/download/rate_estimator_unittest.cc',
+ 'browser/download/save_package_unittest.cc',
+ 'browser/fileapi/blob_storage_context_unittest.cc',
+ 'browser/fileapi/blob_url_request_job_unittest.cc',
+ 'browser/fileapi/copy_or_move_file_validator_unittest.cc',
+ 'browser/fileapi/copy_or_move_operation_delegate_unittest.cc',
+ 'browser/fileapi/dragged_file_util_unittest.cc',
+ 'browser/fileapi/external_mount_points_unittest.cc',
+ 'browser/fileapi/file_system_context_unittest.cc',
+ 'browser/fileapi/file_system_dir_url_request_job_unittest.cc',
+ 'browser/fileapi/file_system_file_stream_reader_unittest.cc',
+ 'browser/fileapi/file_system_operation_impl_unittest.cc',
+ 'browser/fileapi/file_system_operation_impl_write_unittest.cc',
+ 'browser/fileapi/file_system_operation_runner_unittest.cc',
+ 'browser/fileapi/file_system_quota_client_unittest.cc',
+ 'browser/fileapi/file_system_url_request_job_unittest.cc',
+ 'browser/fileapi/file_system_url_unittest.cc',
+ 'browser/fileapi/file_system_usage_cache_unittest.cc',
+ 'browser/fileapi/file_writer_delegate_unittest.cc',
+ 'browser/fileapi/fileapi_message_filter_unittest.cc',
+ 'browser/fileapi/isolated_context_unittest.cc',
+ 'browser/fileapi/local_file_stream_reader_unittest.cc',
+ 'browser/fileapi/local_file_stream_writer_unittest.cc',
+ 'browser/fileapi/local_file_util_unittest.cc',
+ 'browser/fileapi/mock_file_change_observer.cc',
+ 'browser/fileapi/mock_file_change_observer.h',
+ 'browser/fileapi/mock_file_update_observer.cc',
+ 'browser/fileapi/mock_file_update_observer.h',
+ 'browser/fileapi/mock_url_request_delegate.cc',
+ 'browser/fileapi/mock_url_request_delegate.h',
+ 'browser/fileapi/native_file_util_unittest.cc',
+ 'browser/fileapi/obfuscated_file_util_unittest.cc',
+ 'browser/fileapi/plugin_private_file_system_backend_unittest.cc',
+ 'browser/fileapi/recursive_operation_delegate_unittest.cc',
+ 'browser/fileapi/sandbox_database_test_helper.cc',
+ 'browser/fileapi/sandbox_database_test_helper.h',
+ 'browser/fileapi/sandbox_directory_database_unittest.cc',
+ 'browser/fileapi/sandbox_file_system_backend_delegate_unittest.cc',
+ 'browser/fileapi/sandbox_file_system_backend_unittest.cc',
+ 'browser/fileapi/sandbox_isolated_origin_database_unittest.cc',
+ 'browser/fileapi/sandbox_origin_database_unittest.cc',
+ 'browser/fileapi/sandbox_prioritized_origin_database_unittest.cc',
+ 'browser/fileapi/timed_task_helper_unittest.cc',
+ 'browser/fileapi/transient_file_util_unittest.cc',
+ 'browser/fileapi/upload_file_system_file_element_reader_unittest.cc',
+ 'browser/frame_host/frame_tree_unittest.cc',
+ 'browser/frame_host/navigation_controller_impl_unittest.cc',
+ 'browser/frame_host/navigation_entry_impl_unittest.cc',
+ 'browser/frame_host/navigator_impl_unittest.cc',
+ 'browser/frame_host/render_frame_host_manager_unittest.cc',
+ 'browser/frame_host/render_widget_host_view_child_frame_unittest.cc',
+ 'browser/frame_host/render_widget_host_view_guest_unittest.cc',
+ 'browser/gamepad/gamepad_provider_unittest.cc',
+ 'browser/gamepad/gamepad_service_unittest.cc',
+ 'browser/gamepad/gamepad_test_helpers.cc',
+ 'browser/gamepad/gamepad_test_helpers.h',
+ 'browser/geofencing/geofencing_manager_unittest.cc',
+ 'browser/geofencing/geofencing_service_unittest.cc',
+ 'browser/geolocation/geolocation_provider_impl_unittest.cc',
+ 'browser/geolocation/location_arbitrator_impl_unittest.cc',
+ 'browser/geolocation/network_location_provider_unittest.cc',
+ 'browser/geolocation/wifi_data_provider_chromeos_unittest.cc',
+ 'browser/geolocation/wifi_data_provider_common_unittest.cc',
+ 'browser/geolocation/wifi_data_provider_linux_unittest.cc',
+ 'browser/geolocation/wifi_data_provider_win_unittest.cc',
+ 'browser/gpu/gpu_data_manager_impl_private_unittest.cc',
+ 'browser/gpu/shader_disk_cache_unittest.cc',
+ 'browser/host_zoom_map_impl_unittest.cc',
+ 'browser/indexed_db/indexed_db_active_blob_registry_unittest.cc',
+ 'browser/indexed_db/indexed_db_backing_store_unittest.cc',
+ 'browser/indexed_db/indexed_db_cleanup_on_io_error_unittest.cc',
+ 'browser/indexed_db/indexed_db_database_unittest.cc',
+ 'browser/indexed_db/indexed_db_factory_unittest.cc',
+ 'browser/indexed_db/indexed_db_fake_backing_store.cc',
+ 'browser/indexed_db/indexed_db_fake_backing_store.h',
+ 'browser/indexed_db/indexed_db_leveldb_coding_unittest.cc',
+ 'browser/indexed_db/indexed_db_quota_client_unittest.cc',
+ 'browser/indexed_db/indexed_db_transaction_unittest.cc',
+ 'browser/indexed_db/indexed_db_unittest.cc',
+ 'browser/indexed_db/leveldb/leveldb_unittest.cc',
+ 'browser/indexed_db/leveldb/mock_leveldb_factory.cc',
+ 'browser/indexed_db/leveldb/mock_leveldb_factory.h',
+ 'browser/indexed_db/list_set_unittest.cc',
+ 'browser/indexed_db/mock_indexed_db_callbacks.cc',
+ 'browser/indexed_db/mock_indexed_db_callbacks.h',
+ 'browser/indexed_db/mock_indexed_db_database_callbacks.cc',
+ 'browser/indexed_db/mock_indexed_db_database_callbacks.h',
+ 'browser/indexed_db/mock_indexed_db_factory.cc',
+ 'browser/indexed_db/mock_indexed_db_factory.h',
+ 'browser/loader/buffered_resource_handler_unittest.cc',
+ 'browser/loader/navigation_url_loader_unittest.cc',
+ 'browser/loader/resource_buffer_unittest.cc',
+ 'browser/loader/resource_dispatcher_host_unittest.cc',
+ 'browser/loader/resource_loader_unittest.cc',
+ 'browser/loader/resource_scheduler_unittest.cc',
+ 'browser/loader/temporary_file_stream_unittest.cc',
+ 'browser/loader/upload_data_stream_builder_unittest.cc',
+ 'browser/mach_broker_mac_unittest.cc',
+ 'browser/media/audio_stream_monitor_unittest.cc',
+ 'browser/media/capture/animated_content_sampler_unittest.cc',
+ 'browser/media/capture/audio_mirroring_manager_unittest.cc',
+ 'browser/media/capture/capture_resolution_chooser_unittest.cc',
+ 'browser/media/capture/feedback_signal_accumulator_unittest.cc',
+ 'browser/media/capture/smooth_event_sampler_unittest.cc',
+ 'browser/media/capture/video_capture_oracle_unittest.cc',
+ 'browser/media/capture/web_contents_audio_input_stream_unittest.cc',
+ 'browser/media/capture/web_contents_video_capture_device_unittest.cc',
+ 'browser/media/media_internals_unittest.cc',
+ 'browser/media/midi_host_unittest.cc',
+ 'browser/media/webrtc_identity_store_unittest.cc',
+ 'browser/net/sqlite_persistent_cookie_store_unittest.cc',
+ 'browser/notification_service_impl_unittest.cc',
+ 'browser/notifications/notification_database_data_unittest.cc',
+ 'browser/notifications/notification_database_unittest.cc',
+ 'browser/notifications/platform_notification_context_unittest.cc',
+ 'browser/power_monitor_message_broadcaster_unittest.cc',
+ 'browser/power_profiler/power_profiler_service_unittest.cc',
+ 'browser/power_usage_monitor_impl_unittest.cc',
+ 'browser/presentation/presentation_service_impl_unittest.cc',
+ 'browser/presentation/presentation_type_converters_unittest.cc',
+ 'browser/quota/mock_quota_manager.cc',
+ 'browser/quota/mock_quota_manager.h',
+ 'browser/quota/mock_quota_manager_proxy.cc',
+ 'browser/quota/mock_quota_manager_proxy.h',
+ 'browser/quota/mock_quota_manager_unittest.cc',
+ 'browser/quota/quota_backend_impl_unittest.cc',
+ 'browser/quota/quota_database_unittest.cc',
+ 'browser/quota/quota_manager_unittest.cc',
+ 'browser/quota/quota_reservation_manager_unittest.cc',
+ 'browser/quota/quota_temporary_storage_evictor_unittest.cc',
+ 'browser/quota/storage_monitor_unittest.cc',
+ 'browser/quota/usage_tracker_unittest.cc',
+ 'browser/renderer_host/begin_frame_observer_proxy_unittest.cc',
+ 'browser/renderer_host/clipboard_message_filter_unittest.cc',
+ 'browser/renderer_host/input/gesture_event_queue_unittest.cc',
+ 'browser/renderer_host/input/input_router_impl_unittest.cc',
+ 'browser/renderer_host/input/mock_input_ack_handler.cc',
+ 'browser/renderer_host/input/mock_input_ack_handler.h',
+ 'browser/renderer_host/input/mock_input_router_client.cc',
+ 'browser/renderer_host/input/mock_input_router_client.h',
+ 'browser/renderer_host/input/mouse_wheel_rails_filter_unittest_mac.cc',
+ 'browser/renderer_host/input/render_widget_host_latency_tracker_unittest.cc',
+ 'browser/renderer_host/input/stylus_text_selector_unittest.cc',
+ 'browser/renderer_host/input/synthetic_gesture_controller_unittest.cc',
+ 'browser/renderer_host/input/tap_suppression_controller_unittest.cc',
+ 'browser/renderer_host/input/touch_action_filter_unittest.cc',
+ 'browser/renderer_host/input/touch_emulator_unittest.cc',
+ 'browser/renderer_host/input/touch_event_queue_unittest.cc',
+ 'browser/renderer_host/input/web_input_event_unittest.cc',
+ 'browser/renderer_host/input/web_input_event_util_unittest.cc',
+ 'browser/renderer_host/media/audio_input_device_manager_unittest.cc',
+ 'browser/renderer_host/media/audio_renderer_host_unittest.cc',
+ 'browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc',
+ 'browser/renderer_host/media/media_stream_manager_unittest.cc',
+ 'browser/renderer_host/media/media_stream_ui_proxy_unittest.cc',
+ 'browser/renderer_host/media/video_capture_buffer_pool_unittest.cc',
+ 'browser/renderer_host/media/video_capture_controller_unittest.cc',
+ 'browser/renderer_host/media/video_capture_host_unittest.cc',
+ 'browser/renderer_host/media/video_capture_manager_unittest.cc',
+ 'browser/renderer_host/render_process_host_unittest.cc',
+ 'browser/renderer_host/render_view_host_unittest.cc',
+ 'browser/renderer_host/render_widget_host_unittest.cc',
+ 'browser/renderer_host/render_widget_host_view_aura_unittest.cc',
+ 'browser/renderer_host/render_widget_host_view_base_unittest.cc',
+ 'browser/renderer_host/render_widget_host_view_mac_editcommand_helper_unittest.mm',
+ 'browser/renderer_host/render_widget_host_view_mac_unittest.mm',
+ 'browser/renderer_host/text_input_client_mac_unittest.mm',
+ 'browser/renderer_host/web_input_event_aura_unittest.cc',
+ 'browser/renderer_host/websocket_dispatcher_host_unittest.cc',
+ 'browser/resolve_proxy_msg_helper_unittest.cc',
+ 'browser/service_worker/embedded_worker_instance_unittest.cc',
+ 'browser/service_worker/embedded_worker_test_helper.cc',
+ 'browser/service_worker/embedded_worker_test_helper.h',
+ 'browser/service_worker/service_worker_context_request_handler_unittest.cc',
+ 'browser/service_worker/service_worker_context_unittest.cc',
+ 'browser/service_worker/service_worker_controllee_request_handler_unittest.cc',
+ 'browser/service_worker/service_worker_database_unittest.cc',
+ 'browser/service_worker/service_worker_dispatcher_host_unittest.cc',
+ 'browser/service_worker/service_worker_handle_unittest.cc',
+ 'browser/service_worker/service_worker_job_unittest.cc',
+ 'browser/service_worker/service_worker_process_manager_unittest.cc',
+ 'browser/service_worker/service_worker_provider_host_unittest.cc',
+ 'browser/service_worker/service_worker_registration_unittest.cc',
+ 'browser/service_worker/service_worker_request_handler_unittest.cc',
+ 'browser/service_worker/service_worker_storage_unittest.cc',
+ 'browser/service_worker/service_worker_url_request_job_unittest.cc',
+ 'browser/service_worker/service_worker_utils_unittest.cc',
+ 'browser/service_worker/service_worker_version_unittest.cc',
+ 'browser/service_worker/service_worker_write_to_cache_job_unittest.cc',
+ 'browser/shareable_file_reference_unittest.cc',
+ 'browser/shared_worker/shared_worker_instance_unittest.cc',
+ 'browser/shared_worker/shared_worker_service_impl_unittest.cc',
+ 'browser/site_instance_impl_unittest.cc',
+ 'browser/startup_task_runner_unittest.cc',
+ 'browser/storage_partition_impl_map_unittest.cc',
+ 'browser/storage_partition_impl_unittest.cc',
+ 'browser/streams/stream_unittest.cc',
+ 'browser/streams/stream_url_request_job_unittest.cc',
+ 'browser/system_message_window_win_unittest.cc',
+ 'browser/transition_request_manager_unittest.cc',
+ 'browser/web_contents/aura/overscroll_navigation_overlay_unittest.cc',
+ 'browser/web_contents/aura/overscroll_window_animation_unittest.cc',
+ 'browser/web_contents/aura/overscroll_window_delegate_unittest.cc',
+ 'browser/web_contents/web_contents_delegate_unittest.cc',
+ 'browser/web_contents/web_contents_impl_unittest.cc',
+ 'browser/web_contents/web_contents_user_data_unittest.cc',
+ 'browser/web_contents/web_contents_view_mac_unittest.mm',
+ 'browser/web_contents/web_drag_dest_mac_unittest.mm',
+ 'browser/web_contents/web_drag_source_mac_unittest.mm',
+ 'browser/webui/url_data_manager_backend_unittest.cc',
+ 'browser/webui/web_ui_data_source_unittest.cc',
+ 'browser/webui/web_ui_message_handler_unittest.cc',
+ 'child/background_sync/background_sync_type_converters_unittest.cc',
+ 'child/blink_platform_impl_unittest.cc',
+ 'child/fileapi/webfilewriter_base_unittest.cc',
+ 'child/indexed_db/indexed_db_dispatcher_unittest.cc',
+ 'child/indexed_db/webidbcursor_impl_unittest.cc',
+ 'child/multipart_response_delegate_unittest.cc',
+ 'child/notifications/notification_data_conversions_unittest.cc',
+ 'child/power_monitor_broadcast_source_unittest.cc',
+ 'child/resource_dispatcher_unittest.cc',
+ 'child/service_worker/service_worker_dispatcher_unittest.cc',
+ 'child/simple_webmimeregistry_impl_unittest.cc',
+ 'child/site_isolation_policy_unittest.cc',
+ 'child/v8_value_converter_impl_unittest.cc',
+ 'child/web_data_consumer_handle_impl_unittest.cc',
+ 'child/web_url_loader_impl_unittest.cc',
+ 'child/worker_task_runner_unittest.cc',
+ 'common/android/address_parser_unittest.cc',
+ 'common/android/gin_java_bridge_value_unittest.cc',
+ 'common/cc_messages_unittest.cc',
+ 'common/common_param_traits_unittest.cc',
+ 'common/cursors/webcursor_unittest.cc',
+ 'common/database_connections_unittest.cc',
+ 'common/database_identifier_unittest.cc',
+ 'common/discardable_shared_memory_heap_unittest.cc',
+ 'common/dom_storage/dom_storage_map_unittest.cc',
+ 'common/dwrite_font_platform_win_unittest.cc',
+ 'common/fileapi/file_system_util_unittest.cc',
+ 'common/gpu/client/gpu_memory_buffer_impl_unittest.cc',
+ 'common/gpu/gpu_channel_manager_unittest.cc',
+ 'common/gpu/gpu_memory_buffer_factory_unittest.cc',
+ 'common/gpu/gpu_memory_manager_unittest.cc',
+ 'common/host_discardable_shared_memory_manager_unittest.cc',
+ 'common/host_shared_bitmap_manager_unittest.cc',
+ 'common/indexed_db/indexed_db_key_unittest.cc',
+ 'common/input/gesture_event_stream_validator_unittest.cc',
+ 'common/input/input_param_traits_unittest.cc',
+ 'common/input/touch_event_stream_validator_unittest.cc',
+ 'common/input/web_input_event_traits_unittest.cc',
+ 'common/inter_process_time_ticks_converter_unittest.cc',
+ 'common/mac/attributed_string_coder_unittest.mm',
+ 'common/mac/font_descriptor_unittest.mm',
+ 'common/origin_util_unittest.cc',
+ 'common/one_writer_seqlock_unittest.cc',
+ 'common/page_state_serialization_unittest.cc',
+ 'common/page_zoom_unittest.cc',
+ 'common/plugin_list_unittest.cc',
+ 'common/sandbox_mac_diraccess_unittest.mm',
+ 'common/sandbox_mac_fontloading_unittest.mm',
+ 'common/sandbox_mac_system_access_unittest.mm',
+ 'common/sandbox_mac_unittest_helper.h',
+ 'common/sandbox_mac_unittest_helper.mm',
+ 'common/webplugininfo_unittest.cc',
+ 'renderer/android/email_detector_unittest.cc',
+ 'renderer/android/phone_number_detector_unittest.cc',
+ 'renderer/battery_status/battery_status_dispatcher_unittest.cc',
+ 'renderer/bmp_image_decoder_unittest.cc',
+ 'renderer/device_sensors/device_light_event_pump_unittest.cc',
+ 'renderer/device_sensors/device_motion_event_pump_unittest.cc',
+ 'renderer/device_sensors/device_orientation_event_pump_unittest.cc',
+ 'renderer/disambiguation_popup_helper_unittest.cc',
+ 'renderer/dom_storage/dom_storage_cached_area_unittest.cc',
+ 'renderer/gpu/compositor_forwarding_message_filter_unittest.cc',
+ 'renderer/gpu/frame_swap_message_queue_unittest.cc',
+ 'renderer/gpu/queue_message_swap_promise_unittest.cc',
+ 'renderer/gpu/render_widget_compositor_unittest.cc',
+ 'renderer/ico_image_decoder_unittest.cc',
+ 'renderer/input/input_event_filter_unittest.cc',
+ 'renderer/input/input_handler_proxy_unittest.cc',
+ 'renderer/input/input_scroll_elasticity_controller_unittest.cc',
+ 'renderer/manifest/manifest_parser_unittest.cc',
+ 'renderer/media/android/media_info_loader_unittest.cc',
+ 'renderer/media/audio_message_filter_unittest.cc',
+ 'renderer/media/audio_renderer_mixer_manager_unittest.cc',
+ 'renderer/media/midi_message_filter_unittest.cc',
+ 'renderer/media/render_media_client_unittest.cc',
+ 'renderer/media/render_media_log_unittest.cc',
+ 'renderer/media/video_capture_impl_manager_unittest.cc',
+ 'renderer/media/video_capture_impl_unittest.cc',
+ 'renderer/media/video_capture_message_filter_unittest.cc',
+ 'renderer/render_thread_impl_unittest.cc',
+ 'renderer/render_widget_unittest.cc',
+ 'renderer/scheduler/resource_dispatch_throttler_unittest.cc',
+ 'renderer/screen_orientation/screen_orientation_dispatcher_unittest.cc',
+ 'renderer/skia_benchmarking_extension_unittest.cc',
+ 'test/fileapi_test_file_set.cc',
+ 'test/fileapi_test_file_set.h',
+ 'test/image_decoder_test.cc',
+ 'test/image_decoder_test.h',
+ 'test/run_all_unittests.cc',
+ ],
+ 'content_unittests_speech_sources': [
+ 'browser/speech/chunked_byte_buffer_unittest.cc',
+ 'browser/speech/endpointer/endpointer_unittest.cc',
+ 'browser/speech/google_one_shot_remote_engine_unittest.cc',
+ 'browser/speech/google_streaming_remote_engine_unittest.cc',
+ 'browser/speech/speech_recognizer_impl_unittest.cc',
+ ],
+ 'content_unittests_plugins_sources': [
+ 'browser/plugin_loader_posix_unittest.cc',
+ 'browser/renderer_host/pepper/browser_ppapi_host_test.cc',
+ 'browser/renderer_host/pepper/browser_ppapi_host_test.h',
+ 'browser/renderer_host/pepper/pepper_file_system_browser_host_unittest.cc',
+ 'browser/renderer_host/pepper/pepper_gamepad_host_unittest.cc',
+ 'browser/renderer_host/pepper/pepper_printing_host_unittest.cc',
+ 'browser/renderer_host/pepper/quota_reservation_unittest.cc',
+ 'child/npapi/plugin_lib_unittest.cc',
+ 'renderer/media/webrtc/video_destination_handler_unittest.cc',
+ 'renderer/npapi/webplugin_impl_unittest.cc',
+ 'renderer/pepper/event_conversion_unittest.cc',
+ 'renderer/pepper/host_var_tracker_unittest.cc',
+ 'renderer/pepper/mock_resource.h',
+ 'renderer/pepper/pepper_broker_unittest.cc',
+ 'renderer/pepper/plugin_instance_throttler_impl_unittest.cc',
+ 'renderer/pepper/v8_var_converter_unittest.cc',
+ ],
+ 'content_unittests_webrtc_sources': [
+ 'browser/media/webrtc_internals_unittest.cc',
+ 'browser/renderer_host/media/webrtc_identity_service_host_unittest.cc',
+ 'browser/renderer_host/p2p/socket_host_tcp_server_unittest.cc',
+ 'browser/renderer_host/p2p/socket_host_tcp_unittest.cc',
+ 'browser/renderer_host/p2p/socket_host_test_utils.cc',
+ 'browser/renderer_host/p2p/socket_host_test_utils.h',
+ 'browser/renderer_host/p2p/socket_host_udp_unittest.cc',
+ 'browser/renderer_host/p2p/socket_host_unittest.cc',
+ 'renderer/media/media_stream_audio_processor_unittest.cc',
+ 'renderer/media/media_stream_constraints_util_unittest.cc',
+ 'renderer/media/media_stream_dispatcher_unittest.cc',
+ 'renderer/media/media_stream_video_capture_source_unittest.cc',
+ 'renderer/media/media_stream_video_source_unittest.cc',
+ 'renderer/media/media_stream_video_track_unittest.cc',
+ 'renderer/media/mock_media_constraint_factory.cc',
+ 'renderer/media/mock_media_stream_registry.cc',
+ 'renderer/media/mock_media_stream_registry.h',
+ 'renderer/media/mock_media_stream_video_sink.cc',
+ 'renderer/media/mock_media_stream_video_sink.h',
+ 'renderer/media/mock_media_stream_video_source.cc',
+ 'renderer/media/mock_media_stream_video_source.h',
+ 'renderer/media/rtc_data_channel_handler_unittest.cc',
+ 'renderer/media/rtc_peer_connection_handler_unittest.cc',
+ 'renderer/media/rtc_video_decoder_unittest.cc',
+ 'renderer/media/speech_recognition_audio_sink_unittest.cc',
+ 'renderer/media/user_media_client_impl_unittest.cc',
+ 'renderer/media/video_source_handler_unittest.cc',
+ 'renderer/media/webrtc/media_stream_remote_video_source_unittest.cc',
+ 'renderer/media/webrtc/media_stream_track_metrics_unittest.cc',
+ 'renderer/media/webrtc/peer_connection_dependency_factory_unittest.cc',
+ 'renderer/media/webrtc/webrtc_local_audio_track_adapter_unittest.cc',
+ 'renderer/media/webrtc/webrtc_media_stream_adapter_unittest.cc',
+ 'renderer/media/webrtc/webrtc_video_capturer_adapter_unittest.cc',
+ 'renderer/media/webrtc_audio_capturer_unittest.cc',
+ 'renderer/media/webrtc_audio_renderer_unittest.cc',
+ 'renderer/media/webrtc_identity_service_unittest.cc',
+ 'renderer/media/webrtc_local_audio_source_provider_unittest.cc',
+ 'renderer/media/webrtc_local_audio_track_unittest.cc',
+ 'renderer/media/webrtc_uma_histograms_unittest.cc',
+ 'renderer/p2p/ipc_network_manager_unittest.cc',
+ ],
+ 'content_unittests_android_sources': [
+ 'browser/android/java/gin_java_method_invocation_helper_unittest.cc',
+ 'browser/android/java/java_type_unittest.cc',
+ 'browser/android/java/jni_helper_unittest.cc',
+ 'browser/android/overscroll_refresh_unittest.cc',
+ 'browser/android/url_request_content_job_unittest.cc',
+ 'browser/renderer_host/input/motion_event_android_unittest.cc',
+ 'renderer/java/gin_java_bridge_value_converter_unittest.cc',
+ ],
},
'targets': [
{
@@ -172,9 +764,11 @@
['OS!="ios"', {
# layouttest_support_content is not supported nor required on iOS.
'dependencies': [
+ 'content.gyp:content_renderer',
'test_support_content',
'../skia/skia.gyp:skia',
'../ui/accessibility/accessibility.gyp:ax_gen',
+ '../ui/base/ime/ui_base_ime.gyp:ui_base_ime',
'../v8/tools/gyp/v8.gyp:v8',
],
'include_dirs': [
@@ -190,15 +784,18 @@
'target_name': 'test_support_content',
'type': 'static_library',
'dependencies': [
+ '../mojo/mojo_base.gyp:mojo_environment_chromium',
'../net/net.gyp:net_test_support',
'../skia/skia.gyp:skia',
'../storage/storage_common.gyp:storage_common',
'../testing/gmock.gyp:gmock',
'../testing/gtest.gyp:gtest',
+ '../third_party/mojo/mojo_edk.gyp:mojo_system_impl',
'../ui/accessibility/accessibility.gyp:ax_gen',
+ '../ui/base/ime/ui_base_ime.gyp:ui_base_ime',
'../ui/base/ui_base.gyp:ui_base',
'../ui/base/ui_base.gyp:ui_base_test_support',
- '../ui/events/events.gyp:dom4_keycode_converter',
+ '../ui/events/events.gyp:dom_keycode_converter',
'../ui/events/events.gyp:events_base',
'../ui/events/events.gyp:events_test_support',
'../ui/events/events.gyp:gesture_detection',
@@ -210,6 +807,9 @@
'content.gyp:content_browser',
'content.gyp:content_common',
],
+ 'export_dependent_settings': [
+ 'content.gyp:content_browser',
+ ],
'include_dirs': [
'..',
],
@@ -217,6 +817,7 @@
'conditions': [
['enable_plugins==0', {
'sources!': [
+ 'public/test/ppapi_test_utils.cc',
'test/ppapi_unittest.cc',
],
}],
@@ -235,6 +836,7 @@
['include', '^public/test/mock_notification_observer\\.cc$'],
['include', '^public/test/mock_resource_context\\.cc$'],
['include', '^public/test/test_browser_thread\\.cc$'],
+ ['include', '^public/test/test_browser_thread_bundle\\.cc$'],
['include', '^public/test/test_content_client_initializer\\.cc$'],
['include', '^public/test/test_notification_tracker\\.cc$'],
['include', '^public/test/test_utils\\.cc$'],
@@ -267,8 +869,12 @@
'../cc/blink/cc_blink.gyp:cc_blink',
'../cc/cc.gyp:cc',
'../cc/cc_tests.gyp:cc_test_support',
+ '../components/scheduler/scheduler.gyp:scheduler',
+ '../gpu/blink/gpu_blink.gyp:gpu_blink',
+ '../ipc/mojo/ipc_mojo.gyp:*',
'../media/blink/media_blink.gyp:media_blink',
'../media/media.gyp:media',
+ '../media/midi/midi.gyp:midi',
'../ppapi/ppapi_internal.gyp:ppapi_host',
'../ppapi/ppapi_internal.gyp:ppapi_proxy',
'../ppapi/ppapi_internal.gyp:ppapi_shared',
@@ -279,7 +885,6 @@
'../ui/compositor/compositor.gyp:compositor_test_support',
'../ui/surface/surface.gyp:surface',
'../v8/tools/gyp/v8.gyp:v8',
- '../webkit/common/gpu/webkit_gpu.gyp:webkit_gpu',
],
'export_dependent_settings': [
'../third_party/WebKit/public/blink.gyp:blink',
@@ -293,6 +898,8 @@
}],
['enable_webrtc==1', {
'sources': [
+ 'renderer/media/mock_data_channel_impl.cc',
+ 'renderer/media/mock_data_channel_impl.h',
'renderer/media/mock_media_stream_dispatcher.cc',
'renderer/media/mock_media_stream_dispatcher.h',
'renderer/media/mock_peer_connection_impl.cc',
@@ -320,6 +927,12 @@
'../ui/wm/wm.gyp:wm',
],
}],
+ ['use_ozone==1', {
+ 'dependencies': [
+ '../ui/ozone/ozone.gyp:ozone',
+ '../ui/platform_window/platform_window.gyp:platform_window',
+ ],
+ }],
['OS=="win"', {
'dependencies': [
'../third_party/iaccessible2/iaccessible2.gyp:iaccessible2',
@@ -337,407 +950,57 @@
}],
['OS=="android"', {
'dependencies': [
- '../gin/gin.gyp:gin',
+ '../ui/android/ui_android.gyp:ui_android',
'../ui/shell_dialogs/shell_dialogs.gyp:shell_dialogs',
'content.gyp:content_v8_external_data',
],
}],
+ ['v8_use_external_startup_data==1 and OS!="ios"', {
+ 'dependencies': [
+ '../gin/gin.gyp:gin',
+ ],
+ }],
],
},
{
+ # GN version: //content/test:content_unittests
'target_name': 'content_unittests',
'type': '<(gtest_target_type)',
'dependencies': [
- 'browser/service_worker/service_worker_proto.gyp:proto',
+ 'browser/background_sync/background_sync_proto.gyp:background_sync_proto',
+ 'browser/notifications/notification_proto.gyp:notification_proto',
+ 'browser/service_worker/service_worker_proto.gyp:service_worker_proto',
'browser/speech/proto/speech_proto.gyp:speech_proto',
'content.gyp:content_browser',
'content.gyp:content_common',
+ 'content_common_mojo_bindings.gyp:content_common_mojo_bindings',
'test_support_content',
'../base/base.gyp:test_support_base',
'../crypto/crypto.gyp:crypto',
- '../mojo/edk/mojo_edk.gyp:mojo_common_test_support',
+ '../device/battery/battery.gyp:device_battery',
+ '../device/battery/battery.gyp:device_battery_mojo_bindings',
+ '../mojo/mojo_base.gyp:mojo_environment_chromium',
'../net/net.gyp:net_test_support',
'../skia/skia.gyp:skia',
'../sql/sql.gyp:sql',
'../sql/sql.gyp:test_support_sql',
'../testing/gmock.gyp:gmock',
'../testing/gtest.gyp:gtest',
+ '../third_party/mojo/mojo_edk.gyp:mojo_common_test_support',
+ '../third_party/mojo/mojo_public.gyp:mojo_cpp_bindings',
'../third_party/re2/re2.gyp:re2',
'../ui/accessibility/accessibility.gyp:accessibility',
'../ui/base/ui_base.gyp:ui_base',
+ '../ui/events/events.gyp:blink',
'../ui/gfx/gfx.gyp:gfx',
'../ui/gfx/gfx.gyp:gfx_geometry',
'../ui/gfx/ipc/gfx_ipc.gyp:gfx_ipc',
],
'include_dirs': [
'..',
- '<(SHARED_INTERMEDIATE_DIR)', # Needed by key_systems_unittest.cc.
- ],
- 'sources': [
- 'browser/accessibility/accessibility_mode_helper_unittest.cc',
- 'browser/accessibility/browser_accessibility_mac_unittest.mm',
- 'browser/accessibility/browser_accessibility_manager_unittest.cc',
- 'browser/accessibility/browser_accessibility_win_unittest.cc',
- 'browser/appcache/appcache_database_unittest.cc',
- 'browser/appcache/appcache_disk_cache_unittest.cc',
- 'browser/appcache/appcache_group_unittest.cc',
- 'browser/appcache/appcache_host_unittest.cc',
- 'browser/appcache/appcache_manifest_parser_unittest.cc',
- 'browser/appcache/appcache_quota_client_unittest.cc',
- 'browser/appcache/appcache_request_handler_unittest.cc',
- 'browser/appcache/appcache_response_unittest.cc',
- 'browser/appcache/appcache_service_unittest.cc',
- 'browser/appcache/appcache_storage_unittest.cc',
- 'browser/appcache/appcache_storage_impl_unittest.cc',
- 'browser/appcache/appcache_unittest.cc',
- 'browser/appcache/appcache_update_job_unittest.cc',
- 'browser/appcache/appcache_url_request_job_unittest.cc',
- 'browser/appcache/chrome_appcache_service_unittest.cc',
- 'browser/appcache/mock_appcache_policy.cc',
- 'browser/appcache/mock_appcache_policy.h',
- 'browser/appcache/mock_appcache_service.cc',
- 'browser/appcache/mock_appcache_service.h',
- 'browser/appcache/mock_appcache_storage.cc',
- 'browser/appcache/mock_appcache_storage.h',
- 'browser/appcache/mock_appcache_storage_unittest.cc',
- 'browser/browser_thread_unittest.cc',
- 'browser/browser_url_handler_impl_unittest.cc',
- 'browser/byte_stream_unittest.cc',
- 'browser/child_process_security_policy_unittest.cc',
- 'browser/cocoa/system_hotkey_map_unittest.mm',
- 'browser/compositor/buffer_queue_unittest.cc',
- 'browser/compositor/software_browser_compositor_output_surface_unittest.cc',
- 'browser/compositor/software_output_device_ozone_unittest.cc',
- 'browser/databases_table_unittest.cc',
- 'browser/database_quota_client_unittest.cc',
- 'browser/database_tracker_unittest.cc',
- 'browser/database_util_unittest.cc',
- 'browser/device_sensors/data_fetcher_shared_memory_base_unittest.cc',
- 'browser/device_sensors/sensor_manager_android_unittest.cc',
- 'browser/devtools/embedded_worker_devtools_manager_unittest.cc',
- 'browser/devtools/devtools_http_handler_unittest.cc',
- 'browser/devtools/devtools_manager_unittest.cc',
- 'browser/dom_storage/dom_storage_area_unittest.cc',
- 'browser/dom_storage/dom_storage_context_impl_unittest.cc',
- 'browser/dom_storage/dom_storage_database_unittest.cc',
- 'browser/dom_storage/session_storage_database_unittest.cc',
- 'browser/download/base_file_unittest.cc',
- 'browser/download/download_file_unittest.cc',
- 'browser/download/download_item_impl_unittest.cc',
- 'browser/download/download_manager_impl_unittest.cc',
- 'browser/download/file_metadata_unittest_linux.cc',
- 'browser/download/rate_estimator_unittest.cc',
- 'browser/download/save_package_unittest.cc',
- 'browser/fileapi/blob_storage_context_unittest.cc',
- 'browser/fileapi/blob_url_request_job_unittest.cc',
- 'browser/fileapi/copy_or_move_file_validator_unittest.cc',
- 'browser/fileapi/copy_or_move_operation_delegate_unittest.cc',
- 'browser/fileapi/dragged_file_util_unittest.cc',
- 'browser/fileapi/external_mount_points_unittest.cc',
- 'browser/fileapi/file_system_context_unittest.cc',
- 'browser/fileapi/file_system_dir_url_request_job_unittest.cc',
- 'browser/fileapi/file_system_file_stream_reader_unittest.cc',
- 'browser/fileapi/file_system_operation_impl_unittest.cc',
- 'browser/fileapi/file_system_operation_impl_write_unittest.cc',
- 'browser/fileapi/file_system_operation_runner_unittest.cc',
- 'browser/fileapi/file_system_quota_client_unittest.cc',
- 'browser/fileapi/file_system_url_request_job_unittest.cc',
- 'browser/fileapi/file_system_url_unittest.cc',
- 'browser/fileapi/file_system_usage_cache_unittest.cc',
- 'browser/fileapi/file_writer_delegate_unittest.cc',
- 'browser/fileapi/fileapi_message_filter_unittest.cc',
- 'browser/fileapi/isolated_context_unittest.cc',
- 'browser/fileapi/local_file_stream_reader_unittest.cc',
- 'browser/fileapi/local_file_stream_writer_unittest.cc',
- 'browser/fileapi/local_file_util_unittest.cc',
- 'browser/fileapi/mock_file_change_observer.cc',
- 'browser/fileapi/mock_file_change_observer.h',
- 'browser/fileapi/mock_file_update_observer.cc',
- 'browser/fileapi/mock_file_update_observer.h',
- 'browser/fileapi/mock_url_request_delegate.cc',
- 'browser/fileapi/mock_url_request_delegate.h',
- 'browser/fileapi/native_file_util_unittest.cc',
- 'browser/fileapi/obfuscated_file_util_unittest.cc',
- 'browser/fileapi/plugin_private_file_system_backend_unittest.cc',
- 'browser/fileapi/recursive_operation_delegate_unittest.cc',
- 'browser/fileapi/sandbox_database_test_helper.cc',
- 'browser/fileapi/sandbox_database_test_helper.h',
- 'browser/fileapi/sandbox_directory_database_unittest.cc',
- 'browser/fileapi/sandbox_file_system_backend_delegate_unittest.cc',
- 'browser/fileapi/sandbox_file_system_backend_unittest.cc',
- 'browser/fileapi/sandbox_isolated_origin_database_unittest.cc',
- 'browser/fileapi/sandbox_origin_database_unittest.cc',
- 'browser/fileapi/sandbox_prioritized_origin_database_unittest.cc',
- 'browser/fileapi/timed_task_helper_unittest.cc',
- 'browser/fileapi/transient_file_util_unittest.cc',
- 'browser/fileapi/upload_file_system_file_element_reader_unittest.cc',
- 'browser/frame_host/frame_tree_unittest.cc',
- 'browser/frame_host/navigation_controller_impl_unittest.cc',
- 'browser/frame_host/navigation_entry_impl_unittest.cc',
- 'browser/frame_host/navigator_impl_unittest.cc',
- 'browser/frame_host/render_frame_host_manager_unittest.cc',
- 'browser/frame_host/render_widget_host_view_child_frame_unittest.cc',
- 'browser/frame_host/render_widget_host_view_guest_unittest.cc',
- 'browser/gamepad/gamepad_provider_unittest.cc',
- 'browser/gamepad/gamepad_service_unittest.cc',
- 'browser/gamepad/gamepad_test_helpers.cc',
- 'browser/gamepad/gamepad_test_helpers.h',
- 'browser/geofencing/geofencing_manager_unittest.cc',
- 'browser/geofencing/geofencing_service_unittest.cc',
- 'browser/geolocation/geolocation_provider_impl_unittest.cc',
- 'browser/geolocation/location_arbitrator_impl_unittest.cc',
- 'browser/geolocation/network_location_provider_unittest.cc',
- 'browser/geolocation/wifi_data_provider_chromeos_unittest.cc',
- 'browser/geolocation/wifi_data_provider_common_unittest.cc',
- 'browser/geolocation/wifi_data_provider_linux_unittest.cc',
- 'browser/geolocation/wifi_data_provider_win_unittest.cc',
- 'browser/gpu/gpu_data_manager_impl_private_unittest.cc',
- 'browser/gpu/shader_disk_cache_unittest.cc',
- 'browser/host_zoom_map_impl_unittest.cc',
- 'browser/indexed_db/indexed_db_active_blob_registry_unittest.cc',
- 'browser/indexed_db/indexed_db_backing_store_unittest.cc',
- 'browser/indexed_db/indexed_db_cleanup_on_io_error_unittest.cc',
- 'browser/indexed_db/indexed_db_database_unittest.cc',
- 'browser/indexed_db/indexed_db_factory_unittest.cc',
- 'browser/indexed_db/indexed_db_fake_backing_store.cc',
- 'browser/indexed_db/indexed_db_fake_backing_store.h',
- 'browser/indexed_db/indexed_db_leveldb_coding_unittest.cc',
- 'browser/indexed_db/indexed_db_quota_client_unittest.cc',
- 'browser/indexed_db/indexed_db_transaction_unittest.cc',
- 'browser/indexed_db/indexed_db_unittest.cc',
- 'browser/indexed_db/leveldb/mock_leveldb_factory.cc',
- 'browser/indexed_db/leveldb/mock_leveldb_factory.h',
- 'browser/indexed_db/mock_indexed_db_callbacks.cc',
- 'browser/indexed_db/mock_indexed_db_callbacks.h',
- 'browser/indexed_db/mock_indexed_db_database_callbacks.cc',
- 'browser/indexed_db/mock_indexed_db_database_callbacks.h',
- 'browser/indexed_db/mock_indexed_db_factory.cc',
- 'browser/indexed_db/mock_indexed_db_factory.h',
- 'browser/indexed_db/leveldb/leveldb_unittest.cc',
- 'browser/indexed_db/list_set_unittest.cc',
- 'browser/loader/navigation_url_loader_unittest.cc',
- 'browser/loader/resource_buffer_unittest.cc',
- 'browser/loader/resource_dispatcher_host_unittest.cc',
- 'browser/loader/resource_loader_unittest.cc',
- 'browser/loader/resource_scheduler_unittest.cc',
- 'browser/loader/temporary_file_stream_unittest.cc',
- 'browser/loader/upload_data_stream_builder_unittest.cc',
- 'browser/mach_broker_mac_unittest.cc',
- 'browser/media/audio_stream_monitor_unittest.cc',
- 'browser/media/capture/audio_mirroring_manager_unittest.cc',
- 'browser/media/capture/video_capture_oracle_unittest.cc',
- 'browser/media/capture/web_contents_audio_input_stream_unittest.cc',
- 'browser/media/capture/web_contents_video_capture_device_unittest.cc',
- 'browser/media/media_internals_unittest.cc',
- 'browser/media/midi_host_unittest.cc',
- 'browser/media/webrtc_identity_store_unittest.cc',
- 'browser/net/sqlite_persistent_cookie_store_unittest.cc',
- 'browser/notification_service_impl_unittest.cc',
- 'browser/plugin_loader_posix_unittest.cc',
- 'browser/power_monitor_message_broadcaster_unittest.cc',
- 'browser/power_profiler/power_profiler_service_unittest.cc',
- 'browser/quota/mock_quota_manager.cc',
- 'browser/quota/mock_quota_manager.h',
- 'browser/quota/mock_quota_manager_proxy.cc',
- 'browser/quota/mock_quota_manager_proxy.h',
- 'browser/quota/mock_quota_manager_unittest.cc',
- 'browser/quota/quota_database_unittest.cc',
- 'browser/quota/quota_backend_impl_unittest.cc',
- 'browser/quota/quota_manager_unittest.cc',
- 'browser/quota/quota_reservation_manager_unittest.cc',
- 'browser/quota/quota_temporary_storage_evictor_unittest.cc',
- 'browser/quota/storage_monitor_unittest.cc',
- 'browser/quota/usage_tracker_unittest.cc',
- 'browser/renderer_host/input/gesture_event_queue_unittest.cc',
- 'browser/renderer_host/input/gesture_text_selector_unittest.cc',
- 'browser/renderer_host/input/input_router_impl_unittest.cc',
- 'browser/renderer_host/input/mock_input_ack_handler.cc',
- 'browser/renderer_host/input/mock_input_ack_handler.h',
- 'browser/renderer_host/input/mock_input_router_client.cc',
- 'browser/renderer_host/input/mock_input_router_client.h',
- 'browser/renderer_host/input/synthetic_gesture_controller_unittest.cc',
- 'browser/renderer_host/input/tap_suppression_controller_unittest.cc',
- 'browser/renderer_host/input/touch_action_filter_unittest.cc',
- 'browser/renderer_host/input/touch_emulator_unittest.cc',
- 'browser/renderer_host/input/touch_event_queue_unittest.cc',
- 'browser/renderer_host/input/touch_handle_unittest.cc',
- 'browser/renderer_host/input/touch_selection_controller_unittest.cc',
- 'browser/renderer_host/input/web_input_event_util_unittest.cc',
- 'browser/renderer_host/media/audio_input_device_manager_unittest.cc',
- 'browser/renderer_host/media/audio_renderer_host_unittest.cc',
- 'browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc',
- 'browser/renderer_host/media/media_stream_manager_unittest.cc',
- 'browser/renderer_host/media/media_stream_ui_proxy_unittest.cc',
- 'browser/renderer_host/media/video_capture_buffer_pool_unittest.cc',
- 'browser/renderer_host/media/video_capture_controller_unittest.cc',
- 'browser/renderer_host/media/video_capture_host_unittest.cc',
- 'browser/renderer_host/media/video_capture_manager_unittest.cc',
- 'browser/renderer_host/pepper/browser_ppapi_host_test.cc',
- 'browser/renderer_host/pepper/browser_ppapi_host_test.h',
- 'browser/renderer_host/pepper/pepper_file_system_browser_host_unittest.cc',
- 'browser/renderer_host/pepper/pepper_gamepad_host_unittest.cc',
- 'browser/renderer_host/pepper/pepper_printing_host_unittest.cc',
- 'browser/renderer_host/pepper/quota_reservation_unittest.cc',
- 'browser/renderer_host/render_process_host_unittest.cc',
- 'browser/renderer_host/render_view_host_unittest.cc',
- 'browser/renderer_host/render_widget_host_unittest.cc',
- 'browser/renderer_host/render_widget_host_view_aura_unittest.cc',
- 'browser/renderer_host/render_widget_host_view_base_unittest.cc',
- 'browser/renderer_host/render_widget_host_view_mac_editcommand_helper_unittest.mm',
- 'browser/renderer_host/render_widget_host_view_mac_unittest.mm',
- 'browser/renderer_host/software_frame_manager_unittest.cc',
- 'browser/renderer_host/text_input_client_mac_unittest.mm',
- 'browser/renderer_host/web_input_event_aura_unittest.cc',
- 'browser/renderer_host/websocket_dispatcher_host_unittest.cc',
- 'browser/resolve_proxy_msg_helper_unittest.cc',
- 'browser/service_worker/embedded_worker_instance_unittest.cc',
- 'browser/service_worker/embedded_worker_test_helper.cc',
- 'browser/service_worker/embedded_worker_test_helper.h',
- 'browser/service_worker/service_worker_cache_unittest.cc',
- 'browser/service_worker/service_worker_cache_storage_manager_unittest.cc',
- 'browser/service_worker/service_worker_context_unittest.cc',
- 'browser/service_worker/service_worker_controllee_request_handler_unittest.cc',
- 'browser/service_worker/service_worker_context_request_handler_unittest.cc',
- 'browser/service_worker/service_worker_database_unittest.cc',
- 'browser/service_worker/service_worker_dispatcher_host_unittest.cc',
- 'browser/service_worker/service_worker_handle_unittest.cc',
- 'browser/service_worker/service_worker_job_unittest.cc',
- 'browser/service_worker/service_worker_process_manager_unittest.cc',
- 'browser/service_worker/service_worker_provider_host_unittest.cc',
- 'browser/service_worker/service_worker_registration_unittest.cc',
- 'browser/service_worker/service_worker_request_handler_unittest.cc',
- 'browser/service_worker/service_worker_storage_unittest.cc',
- 'browser/service_worker/service_worker_url_request_job_unittest.cc',
- 'browser/service_worker/service_worker_utils_unittest.cc',
- 'browser/service_worker/service_worker_version_unittest.cc',
- 'browser/service_worker/service_worker_write_to_cache_job_unittest.cc',
- 'browser/shared_worker/shared_worker_instance_unittest.cc',
- 'browser/shared_worker/shared_worker_service_impl_unittest.cc',
- 'browser/site_instance_impl_unittest.cc',
- 'browser/speech/chunked_byte_buffer_unittest.cc',
- 'browser/speech/endpointer/endpointer_unittest.cc',
- 'browser/speech/google_one_shot_remote_engine_unittest.cc',
- 'browser/speech/google_streaming_remote_engine_unittest.cc',
- 'browser/speech/speech_recognizer_impl_unittest.cc',
- 'browser/startup_task_runner_unittest.cc',
- 'browser/storage_partition_impl_map_unittest.cc',
- 'browser/storage_partition_impl_unittest.cc',
- 'browser/streams/stream_unittest.cc',
- 'browser/streams/stream_url_request_job_unittest.cc',
- 'browser/system_message_window_win_unittest.cc',
- 'browser/transition_request_manager_unittest.cc',
- 'browser/web_contents/aura/overscroll_navigation_overlay_unittest.cc',
- 'browser/web_contents/aura/window_slider_unittest.cc',
- 'browser/web_contents/web_contents_delegate_unittest.cc',
- 'browser/web_contents/web_contents_impl_unittest.cc',
- 'browser/web_contents/web_contents_user_data_unittest.cc',
- 'browser/web_contents/web_contents_view_mac_unittest.mm',
- 'browser/web_contents/web_drag_dest_mac_unittest.mm',
- 'browser/web_contents/web_drag_source_mac_unittest.mm',
- 'browser/webui/web_ui_data_source_unittest.cc',
- 'browser/webui/web_ui_message_handler_unittest.cc',
- 'child/blink_platform_impl_unittest.cc',
- 'child/fileapi/webfilewriter_base_unittest.cc',
- 'child/indexed_db/indexed_db_dispatcher_unittest.cc',
- 'child/indexed_db/webidbcursor_impl_unittest.cc',
- 'child/multipart_response_delegate_unittest.cc',
- 'child/npapi/plugin_lib_unittest.cc',
- 'child/power_monitor_broadcast_source_unittest.cc',
- 'child/resource_dispatcher_unittest.cc',
- 'child/simple_webmimeregistry_impl_unittest.cc',
- 'child/site_isolation_policy_unittest.cc',
- 'child/web_data_consumer_handle_impl_unittest.cc',
- 'child/web_gesture_curve_impl_unittest.cc',
- 'child/web_url_loader_impl_unittest.cc',
- 'child/webcrypto/test/aes_cbc_unittest.cc',
- 'child/webcrypto/test/aes_ctr_unittest.cc',
- 'child/webcrypto/test/aes_gcm_unittest.cc',
- 'child/webcrypto/test/aes_kw_unittest.cc',
- 'child/webcrypto/test/hmac_unittest.cc',
- 'child/webcrypto/test/rsa_oaep_unittest.cc',
- 'child/webcrypto/test/rsa_pss_unittest.cc',
- 'child/webcrypto/test/rsa_ssa_unittest.cc',
- 'child/webcrypto/test/sha_unittest.cc',
- 'child/webcrypto/test/status_unittest.cc',
- 'child/webcrypto/test/test_helpers.cc',
- 'child/webcrypto/test/test_helpers.h',
- 'child/worker_task_runner_unittest.cc',
- 'common/android/address_parser_unittest.cc',
- 'common/android/gin_java_bridge_value_unittest.cc',
- 'common/cc_messages_unittest.cc',
- 'common/common_param_traits_unittest.cc',
- 'common/cursors/webcursor_unittest.cc',
- 'common/database_connections_unittest.cc',
- 'common/database_identifier_unittest.cc',
- 'common/dom_storage/dom_storage_map_unittest.cc',
- 'common/fileapi/file_system_util_unittest.cc',
- 'common/gpu/gpu_memory_manager_unittest.cc',
- 'common/host_discardable_shared_memory_manager_unittest.cc',
- 'common/host_shared_bitmap_manager_unittest.cc',
- 'common/indexed_db/indexed_db_key_unittest.cc',
- 'common/input/gesture_event_stream_validator_unittest.cc',
- 'common/input/input_param_traits_unittest.cc',
- 'common/input/touch_event_stream_validator_unittest.cc',
- 'common/input/web_input_event_traits_unittest.cc',
- 'common/inter_process_time_ticks_converter_unittest.cc',
- 'common/mac/attributed_string_coder_unittest.mm',
- 'common/mac/font_descriptor_unittest.mm',
- 'common/one_writer_seqlock_unittest.cc',
- 'common/page_state_serialization_unittest.cc',
- 'common/page_zoom_unittest.cc',
- 'common/plugin_list_unittest.cc',
- 'common/sandbox_mac_diraccess_unittest.mm',
- 'common/sandbox_mac_fontloading_unittest.mm',
- 'common/sandbox_mac_system_access_unittest.mm',
- 'common/sandbox_mac_unittest_helper.h',
- 'common/sandbox_mac_unittest_helper.mm',
- 'common/shareable_file_reference_unittest.cc',
- 'common/webplugininfo_unittest.cc',
- 'renderer/active_notification_tracker_unittest.cc',
- 'renderer/android/email_detector_unittest.cc',
- 'renderer/android/phone_number_detector_unittest.cc',
- 'renderer/bmp_image_decoder_unittest.cc',
- 'renderer/device_sensors/device_light_event_pump_unittest.cc',
- 'renderer/device_sensors/device_motion_event_pump_unittest.cc',
- 'renderer/device_sensors/device_orientation_event_pump_unittest.cc',
- 'renderer/disambiguation_popup_helper_unittest.cc',
- 'renderer/dom_storage/dom_storage_cached_area_unittest.cc',
- 'renderer/gpu/frame_swap_message_queue_unittest.cc',
- 'renderer/gpu/queue_message_swap_promise_unittest.cc',
- 'renderer/gpu/render_widget_compositor_unittest.cc',
- 'renderer/ico_image_decoder_unittest.cc',
- 'renderer/input/input_event_filter_unittest.cc',
- 'renderer/input/input_handler_proxy_unittest.cc',
- 'renderer/manifest/manifest_parser_unittest.cc',
- 'renderer/media/android/media_info_loader_unittest.cc',
- 'renderer/media/audio_message_filter_unittest.cc',
- 'renderer/media/audio_renderer_mixer_manager_unittest.cc',
- 'renderer/media/crypto/key_systems_unittest.cc',
- 'renderer/media/render_media_log_unittest.cc',
- 'renderer/media/video_capture_impl_manager_unittest.cc',
- 'renderer/media/video_capture_impl_unittest.cc',
- 'renderer/media/video_capture_message_filter_unittest.cc',
- 'renderer/media/webrtc/video_destination_handler_unittest.cc',
- 'renderer/npapi/webplugin_impl_unittest.cc',
- 'renderer/pepper/event_conversion_unittest.cc',
- 'renderer/pepper/host_var_tracker_unittest.cc',
- 'renderer/pepper/mock_resource.h',
- 'renderer/pepper/pepper_broker_unittest.cc',
- 'renderer/pepper/v8_var_converter_unittest.cc',
- 'renderer/render_thread_impl_unittest.cc',
- 'renderer/render_widget_unittest.cc',
- 'renderer/scheduler/renderer_scheduler_impl_unittest.cc',
- 'renderer/scheduler/renderer_task_queue_selector_unittest.cc',
- 'renderer/scheduler/task_queue_manager_unittest.cc',
- 'renderer/screen_orientation/screen_orientation_dispatcher_unittest.cc',
- 'renderer/skia_benchmarking_extension_unittest.cc',
- 'renderer/v8_value_converter_impl_unittest.cc',
- 'test/fileapi_test_file_set.cc',
- 'test/fileapi_test_file_set.h',
- 'test/image_decoder_test.cc',
- 'test/image_decoder_test.h',
- 'test/run_all_unittests.cc',
+ '<(SHARED_INTERMEDIATE_DIR)', # Needed by render_media_client_unittest.cc.
],
+ 'sources': [ '<@(content_unittests_sources)' ],
'conditions': [
['OS == "ios"', {
'sources/': [
@@ -782,60 +1045,16 @@
'browser/file_descriptor_info_impl_unittest.cc',
],
}],
- ['enable_plugins==0', {
- 'sources/': [
- ['exclude', '^browser/renderer_host/pepper/'],
- ['exclude', '^child/npapi/'],
- ['exclude', '^renderer/npapi/'],
- ['exclude', '^renderer/pepper/'],
- ],
- 'sources!': [
- 'browser/plugin_loader_posix_unittest.cc',
- 'renderer/media/webrtc/video_destination_handler_unittest.cc',
+ ['OS == "mac"', {
+ 'dependencies': [
+ '../third_party/ocmock/ocmock.gyp:ocmock',
],
}],
+ ['enable_plugins==1', {
+ 'sources': [ '<@(content_unittests_plugins_sources)' ],
+ }],
['enable_webrtc==1', {
- 'sources': [
- 'browser/media/webrtc_internals_unittest.cc',
- 'browser/renderer_host/media/webrtc_identity_service_host_unittest.cc',
- 'browser/renderer_host/p2p/socket_host_test_utils.cc',
- 'browser/renderer_host/p2p/socket_host_test_utils.h',
- 'browser/renderer_host/p2p/socket_host_tcp_unittest.cc',
- 'browser/renderer_host/p2p/socket_host_tcp_server_unittest.cc',
- 'browser/renderer_host/p2p/socket_host_udp_unittest.cc',
- 'browser/renderer_host/p2p/socket_host_unittest.cc',
- 'renderer/media/media_stream_audio_processor_unittest.cc',
- 'renderer/media/media_stream_constraints_util_unittest.cc',
- 'renderer/media/media_stream_dispatcher_unittest.cc',
- 'renderer/media/media_stream_video_capture_source_unittest.cc',
- 'renderer/media/media_stream_video_source_unittest.cc',
- 'renderer/media/media_stream_video_track_unittest.cc',
- 'renderer/media/mock_media_stream_registry.cc',
- 'renderer/media/mock_media_stream_registry.h',
- 'renderer/media/mock_media_stream_video_sink.cc',
- 'renderer/media/mock_media_stream_video_sink.h',
- 'renderer/media/mock_media_stream_video_source.cc',
- 'renderer/media/mock_media_stream_video_source.h',
- 'renderer/media/mock_media_constraint_factory.cc',
- 'renderer/media/rtc_peer_connection_handler_unittest.cc',
- 'renderer/media/rtc_video_decoder_unittest.cc',
- 'renderer/media/speech_recognition_audio_sink_unittest.cc',
- 'renderer/media/user_media_client_impl_unittest.cc',
- 'renderer/media/video_source_handler_unittest.cc',
- 'renderer/media/webrtc/media_stream_remote_video_source_unittest.cc',
- 'renderer/media/webrtc/media_stream_track_metrics_unittest.cc',
- 'renderer/media/webrtc/peer_connection_dependency_factory_unittest.cc',
- 'renderer/media/webrtc/webrtc_local_audio_track_adapter_unittest.cc',
- 'renderer/media/webrtc/webrtc_media_stream_adapter_unittest.cc',
- 'renderer/media/webrtc/webrtc_video_capturer_adapter_unittest.cc',
- 'renderer/media/webrtc_audio_capturer_unittest.cc',
- 'renderer/media/webrtc_audio_renderer_unittest.cc',
- 'renderer/media/webrtc_identity_service_unittest.cc',
- 'renderer/media/webrtc_local_audio_source_provider_unittest.cc',
- 'renderer/media/webrtc_local_audio_track_unittest.cc',
- 'renderer/media/webrtc_uma_histograms_unittest.cc',
- 'renderer/p2p/ipc_network_manager_unittest.cc',
- ],
+ 'sources': [ '<@(content_unittests_webrtc_sources)' ],
'dependencies': [
'../third_party/libjingle/libjingle.gyp:libjingle_webrtc',
'../third_party/libjingle/libjingle.gyp:libpeerconnection',
@@ -859,25 +1078,10 @@
'browser/media/capture/desktop_capture_device_aura_unittest.cc',
],
}],
- # TODO(jrg): remove the OS=="android" section?
- # http://crbug.com/113172
- # Understand better how media_stream_ is tied into Chromium.
- ['enable_webrtc==0 and OS=="android"', {
- 'sources/': [
- ['exclude', '^renderer/media/media_stream_'],
- ],
- }],
- ['enable_web_speech==0', {
- 'sources/': [
- ['exclude', '^browser/speech/'],
- ]
+ ['enable_web_speech==1', {
+ 'sources': [ '<@(content_unittests_speech_sources)' ],
}],
- ['notifications==0', {
- 'sources!': [
- 'renderer/active_notification_tracker_unittest.cc',
- ],
- }],
- ['OS=="linux"', {
+ ['OS=="linux" and use_dbus==1', {
'dependencies': [
'../build/linux/system.gyp:dbus',
'../dbus/dbus.gyp:dbus_test_support',
@@ -902,13 +1106,14 @@
'dependencies': [
'../chromeos/chromeos.gyp:chromeos',
],
- 'sources/': [
- ['exclude', '^browser/geolocation/wifi_data_provider_linux_unittest.cc'],
+ 'sources!': [
+ 'browser/geolocation/wifi_data_provider_linux_unittest.cc',
],
}],
['use_aura==1', {
'dependencies': [
'../ui/aura/aura.gyp:aura',
+ '../ui/aura_extra/aura_extra.gyp:aura_extra',
'../ui/wm/wm.gyp:wm',
]
}],
@@ -923,29 +1128,21 @@
],
}],
['OS == "android"', {
- 'sources': [
- 'browser/android/java/gin_java_method_invocation_helper_unittest.cc',
- 'browser/android/java/java_type_unittest.cc',
- 'browser/android/java/jni_helper_unittest.cc',
- 'browser/android/system_ui_resource_manager_impl_unittest.cc',
- 'browser/renderer_host/input/motion_event_android_unittest.cc',
- 'renderer/java/gin_java_bridge_value_converter_unittest.cc',
- ],
+ 'sources': [ '<@(content_unittests_android_sources)' ],
'sources!': [
'browser/geolocation/network_location_provider_unittest.cc',
- 'browser/geolocation/wifi_data_provider_chromeos_unittest.cc',
'browser/geolocation/wifi_data_provider_common_unittest.cc',
- 'browser/geolocation/wifi_data_provider_linux_unittest.cc',
+ 'browser/media/audio_stream_monitor_unittest.cc',
+ 'browser/renderer_host/begin_frame_observer_proxy_unittest.cc',
+ 'browser/webui/url_data_manager_backend_unittest.cc',
],
- }],
- ['OS != "android" and OS != "ios"', {
'dependencies': [
- '../third_party/libvpx/libvpx.gyp:libvpx',
+ '../testing/android/native_test.gyp:native_test_native_code',
],
}],
- ['OS == "android"', {
+ ['OS != "android" and OS != "ios"', {
'dependencies': [
- '../testing/android/native_test.gyp:native_test_native_code',
+ '../third_party/libvpx/libvpx.gyp:libvpx',
],
}],
['use_aura!=1 and OS!="android"', {
@@ -965,9 +1162,15 @@
}],
['use_ozone==1', {
'dependencies': [
+ '../ui/ozone/ozone.gyp:ozone',
'../ui/ozone/ozone.gyp:ozone_base',
],
}],
+ ['OS == "mac" and use_openssl==1', {
+ 'dependencies': [
+ '../third_party/boringssl/boringssl.gyp:boringssl',
+ ],
+ }],
],
},
],
@@ -1031,6 +1234,7 @@
['OS!="ios"', {
'targets': [
{
+ # GN version: //content/test:content_perftests
'target_name': 'content_perftests',
'type': '<(gtest_target_type)',
'defines!': ['CONTENT_IMPLEMENTATION'],
@@ -1050,8 +1254,10 @@
'..',
],
'sources': [
+ 'browser/net/sqlite_persistent_cookie_store_perftest.cc',
'browser/renderer_host/input/input_router_impl_perftest.cc',
'common/cc_messages_perftest.cc',
+ 'common/discardable_shared_memory_heap_perftest.cc',
'test/run_all_perftests.cc',
],
'conditions': [
@@ -1068,6 +1274,7 @@
],
},
{
+ # GN version: //content/tests:browsertest_support
'target_name': 'content_browser_test_support',
'type': 'static_library',
'dependencies': [
@@ -1075,14 +1282,16 @@
'../skia/skia.gyp:skia',
'../testing/gtest.gyp:gtest',
'../ui/accessibility/accessibility.gyp:ax_gen',
+ '../ui/base/ime/ui_base_ime.gyp:ui_base_ime',
],
'sources': [
- 'test/content_test_launcher.cc',
+ # Source list duplicated in GN build.
'public/test/content_browser_test.cc',
'public/test/content_browser_test.h',
'public/test/content_browser_test_utils.cc',
'public/test/content_browser_test_utils.h',
'public/test/content_browser_test_utils_mac.mm',
+ 'test/content_test_launcher.cc',
],
'include_dirs': [
'<(SHARED_INTERMEDIATE_DIR)',
@@ -1100,20 +1309,22 @@
],
},
{
+ # GN version: //content/test:web_ui_test_mojo_bindings
'target_name': 'web_ui_test_mojo_bindings',
'type': 'static_library',
'dependencies': [
- '../mojo/public/mojo_public.gyp:mojo_cpp_bindings',
+ '../third_party/mojo/mojo_public.gyp:mojo_cpp_bindings',
],
'sources': [
'test/data/web_ui_test_mojo_bindings.mojom',
],
- 'includes': [ '../mojo/public/tools/bindings/mojom_bindings_generator.gypi' ],
+ 'includes': [ '../third_party/mojo/mojom_bindings_generator.gypi' ],
'export_dependent_settings': [
- '../mojo/public/mojo_public.gyp:mojo_cpp_bindings',
+ '../third_party/mojo/mojo_public.gyp:mojo_cpp_bindings',
],
},
{
+ # GN version: //content/tests:content_browsertests
'target_name': 'content_browsertests',
'type': '<(gtest_target_type)',
'dependencies': [
@@ -1123,6 +1334,7 @@
'content.gyp:content_renderer',
'content.gyp:content_resources',
'content_browser_test_support',
+ 'content_common_mojo_bindings.gyp:content_common_mojo_bindings',
'content_shell_lib',
'content_shell_pak',
'test_support_content',
@@ -1135,23 +1347,22 @@
'../ipc/ipc.gyp:test_support_ipc',
'../media/media.gyp:media_test_support',
'../media/media.gyp:shared_memory_support',
- '../mojo/edk/mojo_edk.gyp:mojo_common_test_support',
- '../mojo/edk/mojo_edk.gyp:mojo_system_impl',
'../mojo/mojo_base.gyp:mojo_environment_chromium',
- '../mojo/public/mojo_public.gyp:mojo_cpp_bindings',
- '../mojo/public/mojo_public.gyp:mojo_js_bindings',
'../net/net.gyp:net_test_support',
'../ppapi/ppapi_internal.gyp:ppapi_host',
'../ppapi/ppapi_internal.gyp:ppapi_ipc',
'../ppapi/ppapi_internal.gyp:ppapi_proxy',
'../ppapi/ppapi_internal.gyp:ppapi_shared',
- '../ppapi/ppapi_internal.gyp:ppapi_tests',
'../ppapi/ppapi_internal.gyp:ppapi_unittest_shared',
'../testing/gmock.gyp:gmock',
'../testing/gtest.gyp:gtest',
'../third_party/WebKit/public/blink.gyp:blink',
'../third_party/leveldatabase/leveldatabase.gyp:leveldatabase',
'../third_party/mesa/mesa.gyp:osmesa',
+ '../third_party/mojo/mojo_edk.gyp:mojo_common_test_support',
+ '../third_party/mojo/mojo_edk.gyp:mojo_system_impl',
+ '../third_party/mojo/mojo_public.gyp:mojo_cpp_bindings',
+ '../third_party/mojo/mojo_public.gyp:mojo_js_bindings',
'../ui/accessibility/accessibility.gyp:accessibility',
'../ui/base/ui_base.gyp:ui_base',
'../ui/gfx/gfx.gyp:gfx',
@@ -1172,100 +1383,7 @@
'defines': [
'HAS_OUT_OF_PROC_TEST_RUNNER',
],
- 'sources': [
- 'app/mojo/mojo_browsertest.cc',
- 'browser/accessibility/accessibility_ipc_error_browsertest.cc',
- 'browser/accessibility/accessibility_mode_browsertest.cc',
- 'browser/accessibility/accessibility_win_browsertest.cc',
- 'browser/accessibility/android_granularity_movement_browsertest.cc',
- 'browser/accessibility/android_hit_testing_browsertest.cc',
- 'browser/accessibility/cross_platform_accessibility_browsertest.cc',
- 'browser/accessibility/dump_accessibility_tree_browsertest.cc',
- 'browser/accessibility/site_per_process_accessibility_browsertest.cc',
- 'browser/battery_status/battery_status_browsertest.cc',
- 'browser/compositor/image_transport_factory_browsertest.cc',
- 'browser/bookmarklet_browsertest.cc',
- 'browser/child_process_launcher_browsertest.cc',
- 'browser/child_process_security_policy_browsertest.cc',
- 'browser/cross_site_transfer_browsertest.cc',
- 'browser/database_browsertest.cc',
- 'browser/device_sensors/device_inertial_sensor_browsertest.cc',
- 'browser/devtools/renderer_overrides_handler_browsertest.cc',
- 'browser/dom_storage/dom_storage_browsertest.cc',
- 'browser/download/download_browsertest.cc',
- 'browser/download/drag_download_file_browsertest.cc',
- 'browser/download/mhtml_generation_browsertest.cc',
- 'browser/download/save_package_browsertest.cc',
- 'browser/fileapi/file_system_browsertest.cc',
- 'browser/frame_host/frame_tree_browsertest.cc',
- 'browser/frame_host/render_frame_host_manager_browsertest.cc',
- 'browser/frame_host/navigation_controller_impl_browsertest.cc',
- 'browser/gpu/compositor_util_browsertest.cc',
- 'browser/gpu/gpu_ipc_browsertests.cc',
- 'browser/indexed_db/indexed_db_browsertest.cc',
- 'browser/indexed_db/mock_browsertest_indexed_db_class_factory.cc',
- 'browser/indexed_db/mock_browsertest_indexed_db_class_factory.h',
- 'browser/loader/resource_dispatcher_host_browsertest.cc',
- 'browser/manifest/manifest_browsertest.cc',
- 'browser/media/encrypted_media_browsertest.cc',
- 'browser/media/media_browsertest.cc',
- 'browser/media/media_browsertest.h',
- 'browser/media/media_canplaytype_browsertest.cc',
- 'browser/media/media_source_browsertest.cc',
- 'browser/net_info_browsertest.cc',
- 'browser/plugin_data_remover_impl_browsertest.cc',
- 'browser/plugin_browsertest.cc',
- 'browser/plugin_service_impl_browsertest.cc',
- 'browser/renderer_host/input/touch_action_browsertest.cc',
- 'browser/renderer_host/input/touch_input_browsertest.cc',
- 'browser/renderer_host/render_process_host_browsertest.cc',
- 'browser/renderer_host/render_view_host_browsertest.cc',
- 'browser/renderer_host/render_widget_host_browsertest.cc',
- 'browser/renderer_host/render_widget_host_view_browsertest.cc',
- 'browser/screen_orientation/screen_orientation_browsertest.cc',
- 'browser/security_exploit_browsertest.cc',
- 'browser/service_worker/service_worker_browsertest.cc',
- 'browser/session_history_browsertest.cc',
- 'browser/shared_worker/worker_browsertest.cc',
- 'browser/site_per_process_browsertest.h',
- 'browser/site_per_process_browsertest.cc',
- 'browser/speech/speech_recognition_browsertest.cc',
- 'browser/tracing/tracing_controller_browsertest.cc',
- 'browser/transition_browsertest.cc',
- 'browser/web_contents/opened_by_dom_browsertest.cc',
- 'browser/web_contents/touch_editable_impl_aura_browsertest.cc',
- 'browser/web_contents/web_contents_impl_browsertest.cc',
- 'browser/web_contents/web_contents_view_aura_browsertest.cc',
- 'browser/webkit_browsertest.cc',
- 'browser/webui/web_ui_mojo_browsertest.cc',
- 'child/site_isolation_policy_browsertest.cc',
- 'renderer/accessibility/renderer_accessibility_browsertest.cc',
- 'renderer/browser_render_view_browsertest.cc',
- 'renderer/dom_serializer_browsertest.cc',
- 'renderer/gin_browsertest.cc',
- 'renderer/mouse_lock_dispatcher_browsertest.cc',
- 'renderer/pepper/fake_pepper_plugin_instance.cc',
- 'renderer/pepper/mock_renderer_ppapi_host.cc',
- 'renderer/pepper/pepper_device_enumeration_host_helper_unittest.cc',
- 'renderer/pepper/pepper_file_chooser_host_unittest.cc',
- 'renderer/pepper/pepper_graphics_2d_host_unittest.cc',
- 'renderer/pepper/pepper_url_request_unittest.cc',
- 'renderer/pepper/plugin_power_saver_helper_browsertest.cc',
- 'renderer/render_thread_impl_browsertest.cc',
- 'renderer/render_view_browsertest.cc',
- 'renderer/render_view_browsertest_mac.mm',
- 'renderer/render_widget_browsertest.cc',
- 'renderer/resource_fetcher_browsertest.cc',
- 'renderer/savable_resources_browsertest.cc',
- 'test/accessibility_browser_test_utils.cc',
- 'test/accessibility_browser_test_utils.h',
- 'test/browser_test_utils_browsertest.cc',
- 'test/content_browser_test_test.cc',
- 'test/ppapi/ppapi_browsertest.cc',
- 'test/ppapi/ppapi_test.cc',
- 'test/ppapi/ppapi_test.h',
- 'test/webui_resource_browsertest.cc',
- ],
+ 'sources': [ '<@(content_browsertests_sources)' ],
'conditions': [
['chromeos==0', {
'sources!': [
@@ -1277,8 +1395,7 @@
'<(SHARED_INTERMEDIATE_DIR)/webkit',
],
'sources': [
- 'shell/app/resource.h',
- 'shell/app/shell.rc',
+ '<@(content_browsertests_win_sources)',
# TODO: It would be nice to have these pulled in
# automatically from direct_dependent_settings in
# their various targets (net.gyp:net_resources, etc.),
@@ -1287,6 +1404,8 @@
'<(SHARED_INTERMEDIATE_DIR)/blink/public/resources/blink_resources.rc',
'<(SHARED_INTERMEDIATE_DIR)/content/app/strings/content_strings_en-US.rc',
'<(SHARED_INTERMEDIATE_DIR)/net/net_resources.rc',
+ 'shell/app/resource.h',
+ 'shell/app/shell.rc',
],
'dependencies': [
'<(DEPTH)/content/app/strings/content_strings.gyp:content_strings',
@@ -1317,15 +1436,10 @@
'browser/accessibility/dump_accessibility_tree_browsertest.cc',
],
}],
- ['OS!="android"', {
- 'sources!': [
- 'browser/accessibility/android_granularity_movement_browsertest.cc',
- 'browser/accessibility/android_hit_testing_browsertest.cc',
- ]
- }],
['OS=="android"', {
- 'sources': [
- 'shell/android/browsertests_apk/content_browser_tests_android.cc',
+ 'sources': [ '<@(content_browsertests_android_sources)' ],
+ 'sources!': [
+ 'browser/battery_status/battery_monitor_impl_browsertest.cc',
],
'dependencies': [
'content_shell_jni_headers',
@@ -1352,8 +1466,8 @@
],
}],
['use_aura!=1 and OS!="mac"', {
- 'sources/': [
- ['exclude', '^browser/compositor/'],
+ 'sources!' :[
+ 'browser/compositor/image_transport_factory_browsertest.cc',
],
}],
['OS!="android" and OS!="ios" and OS!="linux"', {
@@ -1364,52 +1478,27 @@
],
}],
['enable_webrtc==1', {
- 'sources': [
- 'browser/media/webrtc_aecdump_browsertest.cc',
- 'browser/media/webrtc_browsertest.cc',
- 'browser/media/webrtc_getusermedia_browsertest.cc',
- 'browser/media/webrtc_internals_browsertest.cc',
- 'browser/media/webrtc_webcam_browsertest.cc',
- 'test/webrtc_content_browsertest_base.cc',
- 'test/webrtc_content_browsertest_base.h',
- ],
+ 'sources': [ '<@(content_browsertests_webrtc_sources)' ],
'dependencies': [
'../testing/perf/perf_test.gyp:perf_test',
],
}],
- ['enable_plugins==0', {
- 'sources/': [
- ['exclude', '^renderer/pepper/'],
- ],
- 'sources!': [
- 'browser/plugin_service_impl_browsertest.cc',
- 'browser/plugin_data_remover_impl_browsertest.cc',
- 'test/ppapi/ppapi_browsertest.cc',
- 'test/ppapi/ppapi_test.cc',
- 'test/ppapi/ppapi_test.h',
- ],
- 'dependencies!': [
+ ['enable_plugins==1', {
+ 'sources': [ '<@(content_browsertests_plugins_sources)' ],
+ 'dependencies': [
'../ppapi/ppapi_internal.gyp:ppapi_tests',
]
}],
- ['enable_web_speech==0', {
- 'sources/': [
- ['exclude', '^browser/speech/'],
- ]
+ ['enable_web_speech == 1', {
+ 'sources': [ '<@(content_browsertests_speech_sources)' ],
}],
- ['branding=="Chrome"', {
- 'sources!': [
- # These tests depend on single process mode, which is disabled
- # in official builds.
- 'renderer/browser_render_view_browsertest.cc',
- 'renderer/dom_serializer_browsertest.cc',
- 'renderer/resource_fetcher_browsertest.cc',
- 'renderer/savable_resources_browsertest.cc',
- ],
+ ['branding != "Chrome"', {
+ 'sources': [ '<@(content_browsertests_unofficial_build_sources)' ],
}],
],
},
{
+ # GN version: //content/test:content_gl_tests
'target_name': 'content_gl_tests',
'type': '<(gtest_target_type)',
'dependencies': [
@@ -1453,6 +1542,7 @@
],
},
{
+ # GN version: //content/test:content_gl_benchmark
'target_name': 'content_gl_benchmark',
'type': '<(gtest_target_type)',
'dependencies': [
@@ -1482,7 +1572,7 @@
},
],
}],
- ['(chromeos==1 or OS=="win" or OS=="android") and use_ozone==0', {
+ ['chromeos==1 or OS=="win" or OS=="android"', {
'targets': [
{
'target_name': 'video_decode_accelerator_unittest',
@@ -1503,8 +1593,8 @@
],
'sources': [
'common/gpu/media/android_video_decode_accelerator_unittest.cc',
- 'common/gpu/media/rendering_helper.h',
'common/gpu/media/rendering_helper.cc',
+ 'common/gpu/media/rendering_helper.h',
'common/gpu/media/video_accelerator_unittest_helpers.h',
'common/gpu/media/video_decode_accelerator_unittest.cc',
],
@@ -1521,7 +1611,7 @@
'../testing/android/native_test.gyp:native_test_native_code',
'../gpu/gpu.gyp:gpu_unittest_utils',
],
- }, { # OS!="android"
+ }, { # OS!="android"
'sources/': [
['exclude', '^common/gpu/media/android_video_decode_accelerator_unittest.cc'],
],
@@ -1550,36 +1640,51 @@
'../ui/gfx/x/gfx_x11.gyp:gfx_x11',
],
}],
+ ['use_ozone==1 and chromeos==1', {
+ 'dependencies': [
+ '../ui/display/display.gyp:display', # Used by rendering_helper.cc
+ '../ui/ozone/ozone.gyp:ozone', # Used by rendering_helper.cc
+ ],
+ }],
],
# TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
'msvs_disabled_warnings': [ 4267, ],
},
]
}],
- ['chromeos==1 and use_x11 == 1 and target_arch != "arm"', {
+ ['chromeos==1 and target_arch != "arm"', {
'targets': [
{
- 'target_name': 'vaapi_h264_decoder_unittest',
+ 'target_name': 'vaapi_jpeg_decoder_unittest',
'type': '<(gtest_target_type)',
'dependencies': [
'content.gyp:content_common',
'../base/base.gyp:base',
- '../build/linux/system.gyp:x11',
'../media/media.gyp:media',
+ '../media/media.gyp:media_test_support',
'../testing/gtest.gyp:gtest',
- '../third_party/libyuv/libyuv.gyp:libyuv',
- '../ui/gfx/gfx.gyp:gfx_geometry',
],
'sources': [
- 'common/gpu/media/vaapi_h264_decoder_unittest.cc',
+ 'common/gpu/media/vaapi_jpeg_decoder_unittest.cc',
],
'include_dirs': [
'<(DEPTH)/third_party/libva',
],
- },
+ 'conditions': [
+ ['use_x11==1', {
+ 'dependencies': [
+ '../build/linux/system.gyp:x11',
+ ]
+ }, {
+ 'dependencies': [
+ '../build/linux/system.gyp:libdrm',
+ ]
+ }],
+ ],
+ }
]
}],
- ['chromeos==1 and (target_arch == "arm" or use_x11 == 1)', {
+ ['chromeos==1', {
'targets': [
{
'target_name': 'video_encode_accelerator_unittest',
@@ -1610,6 +1715,11 @@
'../ui/gfx/x/gfx_x11.gyp:gfx_x11',
],
}],
+ ['use_ozone==1', {
+ 'dependencies': [
+ '../ui/ozone/ozone.gyp:ozone',
+ ],
+ }],
],
},
]
@@ -1639,23 +1749,35 @@
'content.gyp:content_java',
'content_unittests',
],
+ 'conditions': [
+ ['v8_use_external_startup_data==1', {
+ 'dependencies': [
+ '../v8/tools/gyp/v8.gyp:v8_external_snapshot',
+ ],
+ 'copies': [
+ {
+ 'destination': '<(asset_location)',
+ 'files': [
+ '<(PRODUCT_DIR)/natives_blob.bin',
+ '<(PRODUCT_DIR)/snapshot_blob.bin',
+ ],
+ },
+ ],
+ }],
+ ],
'variables': {
'test_suite_name': 'content_unittests',
'conditions': [
['v8_use_external_startup_data==1', {
+ 'asset_location': '<(PRODUCT_DIR)/content_unittests_apk/assets',
'additional_input_paths': [
+ '<(PRODUCT_DIR)/content_unittests_apk/assets/natives_blob.bin',
+ '<(PRODUCT_DIR)/content_unittests_apk/assets/snapshot_blob.bin',
+ ],
+ 'inputs': [
'<(PRODUCT_DIR)/natives_blob.bin',
'<(PRODUCT_DIR)/snapshot_blob.bin',
],
- 'copies': [
- {
- 'destination': '<(PRODUCT_DIR)/content_unittests_apk/assets',
- 'files': [
- '<(PRODUCT_DIR)/natives_blob.bin',
- '<(PRODUCT_DIR)/snapshot_blob.bin',
- ],
- },
- ],
}],
],
},
@@ -1663,6 +1785,16 @@
},
{
# TODO(GN)
+ 'target_name': 'content_browsertests_manifest',
+ 'type': 'none',
+ 'variables': {
+ 'jinja_inputs': ['shell/android/browsertests_apk/AndroidManifest.xml.jinja2'],
+ 'jinja_output': '<(SHARED_INTERMEDIATE_DIR)/content_browsertests_manifest/AndroidManifest.xml',
+ },
+ 'includes': [ '../build/android/jinja_template.gypi' ],
+ },
+ {
+ # TODO(GN)
'target_name': 'content_browsertests_apk',
'type': 'none',
'dependencies': [
@@ -1676,6 +1808,7 @@
'variables': {
'apk_name': 'content_browsertests',
'java_in_dir': 'shell/android/browsertests_apk',
+ 'android_manifest_path': '<(SHARED_INTERMEDIATE_DIR)/content_browsertests_manifest/AndroidManifest.xml',
'resource_dir': 'shell/android/browsertests_apk/res',
'native_lib_target': 'libcontent_browsertests',
'additional_input_paths': ['<(PRODUCT_DIR)/content_shell/assets/content_shell.pak'],
@@ -1710,6 +1843,16 @@
'includes': [ '../build/apk_test.gypi' ],
},
{
+ # GN: //content/shell/android:chromium_linker_test_manifest
+ 'target_name': 'chromium_linker_test_manifest',
+ 'type': 'none',
+ 'variables': {
+ 'jinja_inputs': ['shell/android/linker_test_apk/AndroidManifest.xml.jinja2'],
+ 'jinja_output': '<(SHARED_INTERMEDIATE_DIR)/chromium_linker_test_manifest/AndroidManifest.xml',
+ },
+ 'includes': [ '../build/android/jinja_template.gypi' ],
+ },
+ {
# GN: //content/shell/android:chromium_linker_test_apk
'target_name': 'chromium_linker_test_apk',
'type': 'none',
@@ -1724,6 +1867,7 @@
],
'variables': {
'apk_name': 'ChromiumLinkerTest',
+ 'android_manifest_path': '<(SHARED_INTERMEDIATE_DIR)/chromium_linker_test_manifest/AndroidManifest.xml',
'java_in_dir': 'shell/android/linker_test_apk',
'resource_dir': 'shell/android/linker_test_apk/res',
'native_lib_target': 'libchromium_android_linker_test',
@@ -1810,7 +1954,6 @@
'dependencies': [
'../base/base.gyp:base',
'../base/base.gyp:base_java_test_support',
- 'content.gyp:content_common',
'content.gyp:content_java',
],
'variables': {
@@ -1833,20 +1976,42 @@
'../device/battery/battery.gyp:device_battery_javatests',
'../media/media.gyp:media_java',
'../media/media.gyp:media_test_support',
- '../mojo/public/mojo_public.gyp:mojo_public_test_interfaces',
'../net/net.gyp:net_java',
'../net/net.gyp:net_javatests',
'../net/net.gyp:net_java_test_support',
+ '../testing/android/on_device_instrumentation.gyp:broker_java',
+ '../testing/android/on_device_instrumentation.gyp:require_driver_apk',
+ '../third_party/mojo/mojo_public.gyp:mojo_public_test_interfaces',
],
'variables': {
'apk_name': 'ContentShellTest',
'java_in_dir': 'shell/android/javatests',
'resource_dir': 'shell/android/shell_apk/res',
- 'additional_src_dirs': ['public/android/javatests/',],
+ 'additional_src_dirs': ['public/android/javatests/', ],
'is_test_apk': 1,
},
'includes': [ '../build/java_apk.gypi' ],
},
+ {
+ # GN: //content/public/android:content_junit_tests
+ 'target_name': 'content_junit_tests',
+ 'type': 'none',
+ 'dependencies': [
+ 'content.gyp:content_java',
+ '../base/base.gyp:base_java',
+ '../base/base.gyp:base_java_test_support',
+ '../testing/android/junit/junit_test.gyp:junit_test_support',
+ ],
+ 'variables': {
+ 'main_class': 'org.chromium.testing.local.JunitTestMain',
+ 'src_paths': [
+ 'public/android/junit/',
+ ],
+ },
+ 'includes': [
+ '../build/host_jar.gypi',
+ ],
+ },
],
}],
['OS!="android" and OS!="ios" and OS!="linux"', {
@@ -1882,10 +2047,10 @@
'test/plugin/plugin_delete_plugin_in_stream_test.h',
'test/plugin/plugin_execute_stream_javascript.cc',
'test/plugin/plugin_execute_stream_javascript.h',
- 'test/plugin/plugin_get_javascript_url_test.cc',
- 'test/plugin/plugin_get_javascript_url_test.h',
'test/plugin/plugin_get_javascript_url2_test.cc',
'test/plugin/plugin_get_javascript_url2_test.h',
+ 'test/plugin/plugin_get_javascript_url_test.cc',
+ 'test/plugin/plugin_get_javascript_url_test.h',
'test/plugin/plugin_geturl_test.cc',
'test/plugin/plugin_geturl_test.h',
'test/plugin/plugin_javascript_open_popup.cc',
@@ -1898,24 +2063,24 @@
'test/plugin/plugin_npobject_lifetime_test.h',
'test/plugin/plugin_npobject_proxy_test.cc',
'test/plugin/plugin_npobject_proxy_test.h',
- 'test/plugin/plugin_request_read_test.h',
+ 'test/plugin/plugin_private_test.cc',
+ 'test/plugin/plugin_private_test.h',
'test/plugin/plugin_request_read_test.cc',
+ 'test/plugin/plugin_request_read_test.h',
'test/plugin/plugin_schedule_timer_test.cc',
'test/plugin/plugin_schedule_timer_test.h',
'test/plugin/plugin_setup_test.cc',
'test/plugin/plugin_setup_test.h',
'test/plugin/plugin_test.cc',
'test/plugin/plugin_test.h',
+ 'test/plugin/plugin_test_factory.cc',
'test/plugin/plugin_test_factory.h',
'test/plugin/plugin_thread_async_call_test.cc',
'test/plugin/plugin_thread_async_call_test.h',
- 'test/plugin/plugin_windowed_test.cc',
- 'test/plugin/plugin_windowed_test.h',
- 'test/plugin/plugin_private_test.cc',
- 'test/plugin/plugin_private_test.h',
- 'test/plugin/plugin_test_factory.cc',
'test/plugin/plugin_window_size_test.cc',
'test/plugin/plugin_window_size_test.h',
+ 'test/plugin/plugin_windowed_test.cc',
+ 'test/plugin/plugin_windowed_test.h',
'test/plugin/plugin_windowless_test.cc',
'test/plugin/plugin_windowless_test.h',
'test/plugin/resource.h',
@@ -1929,6 +2094,12 @@
'conditions': [
['OS!="win"', {
'sources!': [
+ # windows-specific resources
+ 'test/plugin/npapi_test.def',
+ 'test/plugin/npapi_test.rc',
+ # Seems windows specific.
+ 'test/plugin/plugin_create_instance_in_paint.cc',
+ 'test/plugin/plugin_create_instance_in_paint.h',
# TODO(port): Port these.
# plugin_npobject_lifetime_test.cc has win32-isms
# (HWND, CALLBACK).
@@ -1936,12 +2107,6 @@
# The window APIs are necessarily platform-specific.
'test/plugin/plugin_window_size_test.cc',
'test/plugin/plugin_windowed_test.cc',
- # Seems windows specific.
- 'test/plugin/plugin_create_instance_in_paint.cc',
- 'test/plugin/plugin_create_instance_in_paint.h',
- # windows-specific resources
- 'test/plugin/npapi_test.def',
- 'test/plugin/npapi_test.rc',
],
}],
['OS=="mac"', {
diff --git a/chromium/content/content_unittests.isolate b/chromium/content/content_unittests.isolate
index bc982e2c3dd..07ac6e751c8 100644
--- a/chromium/content/content_unittests.isolate
+++ b/chromium/content/content_unittests.isolate
@@ -3,9 +3,41 @@
# found in the LICENSE file.
{
'conditions': [
+ ['use_x11==0', {
+ 'variables': {
+ 'command': [
+ '../testing/test_env.py',
+ '<(PRODUCT_DIR)/content_unittests<(EXECUTABLE_SUFFIX)',
+ '--brave-new-test-launcher',
+ '--test-launcher-bot-mode',
+ '--asan=<(asan)',
+ '--msan=<(msan)',
+ '--tsan=<(tsan)',
+ ],
+ },
+ }],
+ ['use_x11==1', {
+ 'variables': {
+ 'command': [
+ '../testing/xvfb.py',
+ '<(PRODUCT_DIR)',
+ '<(PRODUCT_DIR)/content_unittests<(EXECUTABLE_SUFFIX)',
+ '--brave-new-test-launcher',
+ '--test-launcher-bot-mode',
+ '--asan=<(asan)',
+ '--msan=<(msan)',
+ '--tsan=<(tsan)',
+ ],
+ 'files': [
+ '../testing/xvfb.py',
+ '<(PRODUCT_DIR)/xdisplaycheck<(EXECUTABLE_SUFFIX)',
+ ],
+ },
+ }],
['OS=="android" or OS=="linux" or OS=="mac" or OS=="win"', {
'variables': {
'files': [
+ '../net/data/ssl/certificates/',
'../media/test/data/',
'test/data/',
],
@@ -35,39 +67,14 @@
}],
['OS=="linux"', {
'variables': {
- 'command': [
- '../testing/xvfb.py',
- '<(PRODUCT_DIR)',
- '<(PRODUCT_DIR)/content_unittests<(EXECUTABLE_SUFFIX)',
- '--brave-new-test-launcher',
- '--test-launcher-bot-mode',
- '--asan=<(asan)',
- '--lsan=<(lsan)',
- ],
'files': [
- '../testing/xvfb.py',
'<(PRODUCT_DIR)/libffmpegsumo.so',
'<(PRODUCT_DIR)/libosmesa.so',
],
},
}],
- ['OS=="linux" and use_ozone==0', {
- 'variables': {
- 'files': [
- '<(PRODUCT_DIR)/xdisplaycheck<(EXECUTABLE_SUFFIX)',
- ],
- },
- }],
['OS=="mac"', {
'variables': {
- 'command': [
- '../testing/test_env.py',
- '<(PRODUCT_DIR)/content_unittests<(EXECUTABLE_SUFFIX)',
- '--brave-new-test-launcher',
- '--test-launcher-bot-mode',
- '--asan=<(asan)',
- '--lsan=<(lsan)',
- ],
'files': [
'<(PRODUCT_DIR)/ffmpegsumo.so',
'<(PRODUCT_DIR)/osmesa.so',
@@ -76,20 +83,21 @@
}],
['OS=="win"', {
'variables': {
- 'command': [
- '../testing/test_env.py',
- '<(PRODUCT_DIR)/content_unittests<(EXECUTABLE_SUFFIX)',
- '--brave-new-test-launcher',
- '--test-launcher-bot-mode',
- '--asan=<(asan)',
- '--lsan=<(lsan)',
- ],
'files': [
'<(PRODUCT_DIR)/ffmpegsumo.dll',
'<(PRODUCT_DIR)/osmesa.dll',
],
},
}],
+ ['OS=="mac" and asan==1 and fastbuild==0', {
+ 'variables': {
+ 'files': [
+ '<(PRODUCT_DIR)/content_unittests.dSYM/',
+ '<(PRODUCT_DIR)/ffmpegsumo.so.dSYM/',
+ '<(PRODUCT_DIR)/osmesa.so.dSYM/',
+ ],
+ },
+ }],
['OS=="win" and (fastbuild==0 or fastbuild==1)', {
'variables': {
'files': [
@@ -101,5 +109,6 @@
'includes': [
'../base/base.isolate',
'../gin/v8.isolate',
+ '../third_party/angle/angle.isolate',
],
}
diff --git a/chromium/content/content_utility.gypi b/chromium/content/content_utility.gypi
index dee05e44676..b202787c8f8 100644
--- a/chromium/content/content_utility.gypi
+++ b/chromium/content/content_utility.gypi
@@ -6,7 +6,6 @@
'dependencies': [
'../base/base.gyp:base',
'../courgette/courgette.gyp:courgette_lib',
- '../mojo/public/mojo_public.gyp:mojo_application_bindings',
],
'sources': [
'public/utility/content_utility_client.cc',
@@ -15,9 +14,13 @@
'public/utility/utility_thread.h',
'utility/in_process_utility_thread.cc',
'utility/in_process_utility_thread.h',
+ 'utility/utility_blink_platform_impl.cc',
+ 'utility/utility_blink_platform_impl.h',
'utility/utility_main.cc',
'utility/utility_thread_impl.cc',
'utility/utility_thread_impl.h',
+ 'utility/webthread_impl_for_utility_thread.cc',
+ 'utility/webthread_impl_for_utility_thread.h',
],
'include_dirs': [
'..',
diff --git a/chromium/content/gpu/BUILD.gn b/chromium/content/gpu/BUILD.gn
index d1f844897d8..2f5d1133244 100644
--- a/chromium/content/gpu/BUILD.gn
+++ b/chromium/content/gpu/BUILD.gn
@@ -5,15 +5,30 @@
import("//build/config/ui.gni")
import("//content/content.gni")
-source_set("gpu") {
+# See //content/BUILD.gn for how this works.
+group("gpu") {
+ visibility = [ "//content/*" ]
+
+ if (is_component_build) {
+ public_deps = [
+ "//content",
+ ]
+ } else {
+ public_deps = [
+ ":gpu_sources",
+ ]
+ }
+}
+
+source_set("gpu_sources") {
visibility = [ "//content/*" ]
sources = [
+ "gpu_child_thread.cc",
+ "gpu_child_thread.h",
"gpu_main.cc",
"gpu_process.cc",
"gpu_process.h",
- "gpu_child_thread.cc",
- "gpu_child_thread.h",
"gpu_watchdog_thread.cc",
"gpu_watchdog_thread.h",
"in_process_gpu_thread.cc",
@@ -25,7 +40,8 @@ source_set("gpu") {
deps = [
"//base",
"//content:export",
- "//mojo/public/interfaces/application",
+ "//content/public/child:child_sources",
+ "//mojo/application/public/interfaces",
"//skia",
"//ui/gl",
]
@@ -42,7 +58,7 @@ source_set("gpu") {
]
}
- if (is_chromeos && cpu_arch != "arm") {
+ if (is_chromeos && current_cpu != "arm") {
configs += [ "//third_party/libva:libva_config" ]
}
diff --git a/chromium/content/gpu/gpu_child_thread.cc b/chromium/content/gpu/gpu_child_thread.cc
index f47294b9d66..3d26c84e876 100644
--- a/chromium/content/gpu/gpu_child_thread.cc
+++ b/chromium/content/gpu/gpu_child_thread.cc
@@ -44,13 +44,28 @@ bool GpuProcessLogMessageHandler(int severity,
return false;
}
+ChildThreadImpl::Options GetOptions() {
+ ChildThreadImpl::Options::Builder builder;
+
+#if defined(USE_OZONE)
+ IPC::MessageFilter* message_filter = ui::OzonePlatform::GetInstance()
+ ->GetGpuPlatformSupport()
+ ->GetMessageFilter();
+ if (message_filter)
+ builder.AddStartupFilter(message_filter);
+#endif
+
+ return builder.Build();
+}
+
} // namespace
GpuChildThread::GpuChildThread(GpuWatchdogThread* watchdog_thread,
bool dead_on_arrival,
const gpu::GPUInfo& gpu_info,
const DeferredMessages& deferred_messages)
- : dead_on_arrival_(dead_on_arrival),
+ : ChildThreadImpl(GetOptions()),
+ dead_on_arrival_(dead_on_arrival),
gpu_info_(gpu_info),
deferred_messages_(deferred_messages),
in_browser_process_(false) {
@@ -61,16 +76,19 @@ GpuChildThread::GpuChildThread(GpuWatchdogThread* watchdog_thread,
g_thread_safe_sender.Get() = thread_safe_sender();
}
-GpuChildThread::GpuChildThread(const std::string& channel_id)
- : ChildThread(Options(channel_id, false)),
+GpuChildThread::GpuChildThread(const InProcessChildThreadParams& params)
+ : ChildThreadImpl(ChildThreadImpl::Options::Builder()
+ .InBrowserProcess(params)
+ .Build()),
dead_on_arrival_(false),
in_browser_process_(true) {
#if defined(OS_WIN)
target_services_ = NULL;
#endif
- DCHECK(
- CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess) ||
- CommandLine::ForCurrentProcess()->HasSwitch(switches::kInProcessGPU));
+ DCHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSingleProcess) ||
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kInProcessGPU));
#if !defined(OS_ANDROID)
// For single process and in-process GPU mode, we need to load and
// initialize the GL implementation and locate the GL entry points here.
@@ -86,7 +104,7 @@ GpuChildThread::~GpuChildThread() {
}
void GpuChildThread::Shutdown() {
- ChildThread::Shutdown();
+ ChildThreadImpl::Shutdown();
logging::SetLogMessageHandler(NULL);
}
@@ -99,7 +117,7 @@ bool GpuChildThread::Send(IPC::Message* msg) {
// process. This could result in deadlock.
DCHECK(!msg->is_sync());
- return ChildThread::Send(msg);
+ return ChildThreadImpl::Send(msg);
}
bool GpuChildThread::OnControlMessageReceived(const IPC::Message& msg) {
@@ -148,9 +166,8 @@ void GpuChildThread::OnInitialize() {
}
#if defined(OS_ANDROID)
- base::PlatformThread::SetThreadPriority(
- base::PlatformThread::CurrentHandle(),
- base::kThreadPriority_Display);
+ base::PlatformThread::SetThreadPriority(base::PlatformThread::CurrentHandle(),
+ base::ThreadPriority::DISPLAY);
#endif
// We don't need to pipe log messages if we are running the GPU thread in
@@ -185,7 +202,7 @@ void GpuChildThread::OnCollectGraphicsInfo() {
#if defined(OS_WIN)
// GPU full info collection should only happen on un-sandboxed GPU process
// or single process/in-process gpu mode on Windows.
- CommandLine* command_line = CommandLine::ForCurrentProcess();
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
DCHECK(command_line->HasSwitch(switches::kDisableGpuSandbox) ||
in_browser_process_);
#endif // OS_WIN
@@ -198,7 +215,7 @@ void GpuChildThread::OnCollectGraphicsInfo() {
// TODO(piman): can we signal overall failure?
break;
case gpu::kCollectInfoNonFatalFailure:
- VLOG(1) << "gpu::CollectGraphicsInfo failed (non-fatal).";
+ DVLOG(1) << "gpu::CollectGraphicsInfo failed (non-fatal).";
break;
case gpu::kCollectInfoNone:
NOTREACHED();
@@ -235,20 +252,20 @@ void GpuChildThread::OnGetVideoMemoryUsageStats() {
}
void GpuChildThread::OnClean() {
- VLOG(1) << "GPU: Removing all contexts";
+ DVLOG(1) << "GPU: Removing all contexts";
if (gpu_channel_manager_)
gpu_channel_manager_->LoseAllContexts();
}
void GpuChildThread::OnCrash() {
- VLOG(1) << "GPU: Simulating GPU crash";
+ DVLOG(1) << "GPU: Simulating GPU crash";
// Good bye, cruel world.
volatile int* it_s_the_end_of_the_world_as_we_know_it = NULL;
*it_s_the_end_of_the_world_as_we_know_it = 0xdead;
}
void GpuChildThread::OnHang() {
- VLOG(1) << "GPU: Simulating GPU hang";
+ DVLOG(1) << "GPU: Simulating GPU hang";
for (;;) {
// Do not sleep here. The GPU watchdog timer tracks the amount of user
// time this thread is using and it doesn't use much while calling Sleep.
@@ -256,7 +273,7 @@ void GpuChildThread::OnHang() {
}
void GpuChildThread::OnDisableWatchdog() {
- VLOG(1) << "GPU: Disabling watchdog thread";
+ DVLOG(1) << "GPU: Disabling watchdog thread";
if (watchdog_thread_.get()) {
// Disarm the watchdog before shutting down the message loop. This prevents
// the future posting of tasks to the message loop.
@@ -268,7 +285,7 @@ void GpuChildThread::OnDisableWatchdog() {
}
void GpuChildThread::OnGpuSwitched() {
- VLOG(1) << "GPU: GPU has switched";
+ DVLOG(1) << "GPU: GPU has switched";
// Notify observers in the GPU process.
ui::GpuSwitchingManager::GetInstance()->NotifyGpuSwitched();
}
diff --git a/chromium/content/gpu/gpu_child_thread.h b/chromium/content/gpu/gpu_child_thread.h
index b5c312db935..70a6bb8c13a 100644
--- a/chromium/content/gpu/gpu_child_thread.h
+++ b/chromium/content/gpu/gpu_child_thread.h
@@ -14,7 +14,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/time/time.h"
#include "build/build_config.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
#include "content/common/gpu/gpu_channel.h"
#include "content/common/gpu/gpu_channel_manager.h"
#include "content/common/gpu/gpu_config.h"
@@ -33,7 +33,7 @@ class GpuWatchdogThread;
// these per process. It does process initialization and shutdown. It forwards
// IPC messages to GpuChannelManager, which is responsible for issuing rendering
// commands to the GPU.
-class GpuChildThread : public ChildThread {
+class GpuChildThread : public ChildThreadImpl {
public:
typedef std::queue<IPC::Message*> DeferredMessages;
@@ -42,8 +42,7 @@ class GpuChildThread : public ChildThread {
const gpu::GPUInfo& gpu_info,
const DeferredMessages& deferred_messages);
- // For single-process mode.
- explicit GpuChildThread(const std::string& channel_id);
+ explicit GpuChildThread(const InProcessChildThreadParams& params);
~GpuChildThread() override;
diff --git a/chromium/content/gpu/gpu_main.cc b/chromium/content/gpu/gpu_main.cc
index 37606e2b3d8..c6a59fc9c19 100644
--- a/chromium/content/gpu/gpu_main.cc
+++ b/chromium/content/gpu/gpu_main.cc
@@ -9,20 +9,22 @@
#include <windows.h>
#endif
-#include "base/debug/trace_event.h"
-#include "base/environment.h"
#include "base/lazy_instance.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram.h"
+#include "base/metrics/statistics_recorder.h"
#include "base/rand_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
#include "base/threading/platform_thread.h"
+#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "content/child/child_process.h"
#include "content/common/content_constants_internal.h"
#include "content/common/gpu/gpu_config.h"
#include "content/common/gpu/gpu_messages.h"
+#include "content/common/gpu/media/gpu_video_decode_accelerator.h"
#include "content/common/gpu/media/gpu_video_encode_accelerator.h"
#include "content/common/sandbox_linux/sandbox_linux.h"
#include "content/gpu/gpu_child_thread.h"
@@ -33,6 +35,7 @@
#include "content/public/common/main_function_params.h"
#include "gpu/command_buffer/service/gpu_switches.h"
#include "gpu/config/gpu_info_collector.h"
+#include "gpu/config/gpu_switches.h"
#include "gpu/config/gpu_util.h"
#include "ui/events/platform/platform_event_source.h"
#include "ui/gl/gl_implementation.h"
@@ -59,8 +62,13 @@
#include "content/common/sandbox_mac.h"
#endif
-#if defined(ADDRESS_SANITIZER)
-#include <sanitizer/asan_interface.h>
+#if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)
+#include "content/common/gpu/media/vaapi_wrapper.h"
+#endif
+
+#if defined(SANITIZER_COVERAGE)
+#include <sanitizer/common_interface_defs.h>
+#include <sanitizer/coverage_interface.h>
#endif
const int kGpuTimeout = 10000;
@@ -70,8 +78,8 @@ namespace content {
namespace {
void GetGpuInfoFromCommandLine(gpu::GPUInfo& gpu_info,
- const CommandLine& command_line);
-bool WarmUpSandbox(const CommandLine& command_line);
+ const base::CommandLine& command_line);
+bool WarmUpSandbox(const base::CommandLine& command_line);
#if !defined(OS_MACOSX)
bool CollectGraphicsInfo(gpu::GPUInfo& gpu_info);
@@ -105,11 +113,11 @@ bool GpuProcessLogMessageHandler(int severity,
// Main function for starting the Gpu process.
int GpuMain(const MainFunctionParams& parameters) {
TRACE_EVENT0("gpu", "GpuMain");
- base::debug::TraceLog::GetInstance()->SetProcessName("GPU Process");
- base::debug::TraceLog::GetInstance()->SetProcessSortIndex(
+ base::trace_event::TraceLog::GetInstance()->SetProcessName("GPU Process");
+ base::trace_event::TraceLog::GetInstance()->SetProcessSortIndex(
kTraceEventGpuProcessSortIndex);
- const CommandLine& command_line = parameters.command_line;
+ const base::CommandLine& command_line = parameters.command_line;
if (command_line.HasSwitch(switches::kGpuStartupDialog)) {
ChildProcess::WaitForDebugger("Gpu");
}
@@ -152,16 +160,9 @@ int GpuMain(const MainFunctionParams& parameters) {
bool dead_on_arrival = false;
#if defined(OS_WIN)
- base::MessageLoop::Type message_loop_type = base::MessageLoop::TYPE_IO;
- // Unless we're running on desktop GL, we don't need a UI message
- // loop, so avoid its use to work around apparent problems with some
- // third-party software.
- if (command_line.HasSwitch(switches::kUseGL) &&
- command_line.GetSwitchValueASCII(switches::kUseGL) ==
- gfx::kGLImplementationDesktopName) {
- message_loop_type = base::MessageLoop::TYPE_UI;
- }
- base::MessageLoop main_message_loop(message_loop_type);
+ // Use a UI message loop because ANGLE and the desktop GL platform can
+ // create child windows to render to.
+ base::MessageLoop main_message_loop(base::MessageLoop::TYPE_UI);
#elif defined(OS_LINUX) && defined(USE_X11)
// We need a UI loop so that we can grab the Expose events. See GLSurfaceGLX
// and https://crbug.com/326995.
@@ -213,23 +214,17 @@ int GpuMain(const MainFunctionParams& parameters) {
watchdog_thread->StartWithOptions(options);
}
- // Temporarily disable DRI3 on desktop Linux.
- // The GPU process is crashing on DRI3-enabled desktop Linux systems.
- // TODO(jorgelo): remove this when crbug.com/415681 is fixed.
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
- {
- scoped_ptr<base::Environment> env(base::Environment::Create());
- env->SetVar("LIBGL_DRI3_DISABLE", "1");
- }
-#endif
+ // Initializes StatisticsRecorder which tracks UMA histograms.
+ base::StatisticsRecorder::Initialize();
gpu::GPUInfo gpu_info;
// Get vendor_id, device_id, driver_version from browser process through
// commandline switches.
GetGpuInfoFromCommandLine(gpu_info, command_line);
- base::TimeDelta collect_context_time;
- base::TimeDelta initialize_one_off_time;
+#if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)
+ VaapiWrapper::PreSandboxInitialization();
+#endif
// Warm up resources that don't need access to GPUInfo.
if (WarmUpSandbox(command_line)) {
@@ -288,7 +283,7 @@ int GpuMain(const MainFunctionParams& parameters) {
// on systems where vendor_id/device_id aren't available.
if (!command_line.HasSwitch(switches::kDisableGpuDriverBugWorkarounds)) {
gpu::ApplyGpuDriverBugWorkarounds(
- gpu_info, const_cast<CommandLine*>(&command_line));
+ gpu_info, const_cast<base::CommandLine*>(&command_line));
}
#endif
@@ -302,15 +297,19 @@ int GpuMain(const MainFunctionParams& parameters) {
#endif // !defined(OS_CHROMEOS)
#endif // defined(OS_LINUX)
#endif // !defined(OS_MACOSX)
- collect_context_time =
+ base::TimeDelta collect_context_time =
base::TimeTicks::Now() - before_collect_context_graphics_info;
+ UMA_HISTOGRAM_TIMES("GPU.CollectContextGraphicsInfo",
+ collect_context_time);
} else { // gl_initialized
VLOG(1) << "gfx::GLSurface::InitializeOneOff failed";
dead_on_arrival = true;
}
- initialize_one_off_time =
+ base::TimeDelta initialize_one_off_time =
base::TimeTicks::Now() - before_initialize_one_off;
+ UMA_HISTOGRAM_MEDIUM_TIMES("GPU.InitializeOneOffMediumTime",
+ initialize_one_off_time);
if (enable_watchdog && delayed_watchdog_enable) {
watchdog_thread = new GpuWatchdogThread(kGpuTimeout);
@@ -341,6 +340,8 @@ int GpuMain(const MainFunctionParams& parameters) {
gpu_info.sandboxed = Sandbox::SandboxIsCurrentlyActive();
#endif
+ gpu_info.video_decode_accelerator_supported_profiles =
+ content::GpuVideoDecodeAccelerator::GetSupportedProfiles();
gpu_info.video_encode_accelerator_supported_profiles =
content::GpuVideoEncodeAccelerator::GetSupportedProfiles();
} else {
@@ -351,11 +352,6 @@ int GpuMain(const MainFunctionParams& parameters) {
GpuProcess gpu_process;
- // These UMA must be stored after GpuProcess is constructed as it
- // initializes StatisticsRecorder which tracks the histograms.
- UMA_HISTOGRAM_TIMES("GPU.CollectContextGraphicsInfo", collect_context_time);
- UMA_HISTOGRAM_TIMES("GPU.InitializeOneOffTime", initialize_one_off_time);
-
GpuChildThread* child_thread = new GpuChildThread(watchdog_thread.get(),
dead_on_arrival,
gpu_info,
@@ -383,7 +379,7 @@ int GpuMain(const MainFunctionParams& parameters) {
namespace {
void GetGpuInfoFromCommandLine(gpu::GPUInfo& gpu_info,
- const CommandLine& command_line) {
+ const base::CommandLine& command_line) {
DCHECK(command_line.HasSwitch(switches::kGpuVendorID) &&
command_line.HasSwitch(switches::kGpuDeviceID) &&
command_line.HasSwitch(switches::kGpuDriverVersion));
@@ -402,7 +398,7 @@ void GetGpuInfoFromCommandLine(gpu::GPUInfo& gpu_info,
GetContentClient()->SetGpuInfo(gpu_info);
}
-bool WarmUpSandbox(const CommandLine& command_line) {
+bool WarmUpSandbox(const base::CommandLine& command_line) {
{
TRACE_EVENT0("gpu", "Warm up rand");
// Warm up the random subsystem, which needs to be done pre-sandbox on all
@@ -422,7 +418,7 @@ bool CollectGraphicsInfo(gpu::GPUInfo& gpu_info) {
res = false;
break;
case gpu::kCollectInfoNonFatalFailure:
- VLOG(1) << "gpu::CollectGraphicsInfo failed (non-fatal).";
+ DVLOG(1) << "gpu::CollectGraphicsInfo failed (non-fatal).";
break;
case gpu::kCollectInfoNone:
NOTREACHED();
@@ -441,7 +437,7 @@ bool CanAccessNvidiaDeviceFile() {
bool res = true;
base::ThreadRestrictions::AssertIOAllowed();
if (access("/dev/nvidiactl", R_OK) != 0) {
- VLOG(1) << "NVIDIA device file /dev/nvidiactl access denied";
+ DVLOG(1) << "NVIDIA device file /dev/nvidiactl access denied";
res = false;
}
return res;
@@ -452,7 +448,7 @@ void CreateDummyGlContext() {
scoped_refptr<gfx::GLSurface> surface(
gfx::GLSurface::CreateOffscreenGLSurface(gfx::Size()));
if (!surface.get()) {
- VLOG(1) << "gfx::GLSurface::CreateOffscreenGLSurface failed";
+ DVLOG(1) << "gfx::GLSurface::CreateOffscreenGLSurface failed";
return;
}
@@ -461,7 +457,7 @@ void CreateDummyGlContext() {
scoped_refptr<gfx::GLContext> context(gfx::GLContext::CreateGLContext(
NULL, surface.get(), gfx::PreferDiscreteGpu));
if (!context.get()) {
- VLOG(1) << "gfx::GLContext::CreateGLContext failed";
+ DVLOG(1) << "gfx::GLContext::CreateGLContext failed";
return;
}
@@ -469,7 +465,7 @@ void CreateDummyGlContext() {
if (context->MakeCurrent(surface.get())) {
context->ReleaseCurrent(surface.get());
} else {
- VLOG(1) << "gfx::GLContext::MakeCurrent failed";
+ DVLOG(1) << "gfx::GLContext::MakeCurrent failed";
}
}
@@ -500,7 +496,7 @@ bool StartSandboxLinux(const gpu::GPUInfo& gpu_info,
LinuxSandbox::StopThread(watchdog_thread);
}
-#if defined(ADDRESS_SANITIZER)
+#if defined(SANITIZER_COVERAGE)
const std::string sancov_file_name =
"gpu." + base::Uint64ToString(base::RandUint64());
LinuxSandbox* linux_sandbox = LinuxSandbox::GetInstance();
@@ -532,6 +528,13 @@ bool StartSandboxWindows(const sandbox::SandboxInterfaceInfo* sandbox_info) {
// content.
sandbox::TargetServices* target_services = sandbox_info->target_services;
if (target_services) {
+#if defined(ADDRESS_SANITIZER)
+ // Bind and leak dbghelp.dll before the token is lowered, otherwise
+ // AddressSanitizer will crash when trying to symbolize a report.
+ if (!LoadLibraryA("dbghelp.dll"))
+ return false;
+#endif
+
target_services->LowerToken();
return true;
}
diff --git a/chromium/content/gpu/gpu_watchdog_thread.cc b/chromium/content/gpu/gpu_watchdog_thread.cc
index 02b6bff8040..6052d41647d 100644
--- a/chromium/content/gpu/gpu_watchdog_thread.cc
+++ b/chromium/content/gpu/gpu_watchdog_thread.cc
@@ -21,11 +21,13 @@
namespace content {
namespace {
-const int64 kCheckPeriodMs = 2000;
#if defined(OS_CHROMEOS)
const base::FilePath::CharType
kTtyFilePath[] = FILE_PATH_LITERAL("/sys/class/tty/tty0/active");
#endif
+#if defined(USE_X11)
+const unsigned char text[20] = "check";
+#endif
} // namespace
GpuWatchdogThread::GpuWatchdogThread(int timeout)
@@ -39,6 +41,11 @@ GpuWatchdogThread::GpuWatchdogThread(int timeout)
#endif
task_observer_(this),
suspended_(false),
+#if defined(USE_X11)
+ display_(NULL),
+ window_(0),
+ atom_(None),
+#endif
weak_factory_(this) {
DCHECK(timeout >= 0);
@@ -59,6 +66,9 @@ GpuWatchdogThread::GpuWatchdogThread(int timeout)
#if defined(OS_CHROMEOS)
tty_file_ = base::OpenFile(base::FilePath(kTtyFilePath), "r");
#endif
+#if defined(USE_X11)
+ SetupXServer();
+#endif
watched_message_loop_->AddTaskObserver(&task_observer_);
}
@@ -102,7 +112,6 @@ void GpuWatchdogThread::GpuWatchdogTaskObserver::WillProcessTask(
void GpuWatchdogThread::GpuWatchdogTaskObserver::DidProcessTask(
const base::PendingTask& pending_task) {
- watchdog_->CheckArmed();
}
GpuWatchdogThread::~GpuWatchdogThread() {
@@ -123,6 +132,11 @@ GpuWatchdogThread::~GpuWatchdogThread() {
fclose(tty_file_);
#endif
+#if defined(USE_X11)
+ XDestroyWindow(display_, window_);
+ XCloseDisplay(display_);
+#endif
+
watched_message_loop_->RemoveTaskObserver(&task_observer_);
}
@@ -152,7 +166,7 @@ void GpuWatchdogThread::OnAcknowledge() {
FROM_HERE,
base::Bind(&GpuWatchdogThread::OnCheck, weak_factory_.GetWeakPtr(),
was_suspended),
- base::TimeDelta::FromMilliseconds(kCheckPeriodMs));
+ 0.5 * timeout_);
}
void GpuWatchdogThread::OnCheck(bool after_suspend) {
@@ -188,9 +202,8 @@ void GpuWatchdogThread::OnCheck(bool after_suspend) {
// not respond in time.
message_loop()->PostDelayedTask(
FROM_HERE,
- base::Bind(
- &GpuWatchdogThread::DeliberatelyTerminateToRecoverFromHang,
- weak_factory_.GetWeakPtr()),
+ base::Bind(&GpuWatchdogThread::DeliberatelyTerminateToRecoverFromHang,
+ weak_factory_.GetWeakPtr()),
timeout);
}
@@ -224,6 +237,52 @@ void GpuWatchdogThread::DeliberatelyTerminateToRecoverFromHang() {
return;
}
+#if defined(USE_X11)
+ XWindowAttributes attributes;
+ XGetWindowAttributes(display_, window_, &attributes);
+
+ XSelectInput(display_, window_, PropertyChangeMask);
+ SetupXChangeProp();
+
+ XFlush(display_);
+
+ // We wait for the property change event with a timeout. If it arrives we know
+ // that X is responsive and is not the cause of the watchdog trigger, so we
+ // should
+ // terminate. If it times out, it may be due to X taking a long time, but
+ // terminating won't help, so ignore the watchdog trigger.
+ XEvent event_return;
+ base::TimeTicks deadline = base::TimeTicks::Now() + timeout_;
+ while (true) {
+ base::TimeDelta delta = deadline - base::TimeTicks::Now();
+ if (delta < base::TimeDelta()) {
+ return;
+ } else {
+ while (XCheckWindowEvent(display_, window_, PropertyChangeMask,
+ &event_return)) {
+ if (MatchXEventAtom(&event_return))
+ break;
+ }
+ struct pollfd fds[1];
+ fds[0].fd = XConnectionNumber(display_);
+ fds[0].events = POLLIN;
+ int status = poll(fds, 1, delta.InMilliseconds());
+ if (status == -1) {
+ if (errno == EINTR) {
+ continue;
+ } else {
+ LOG(FATAL) << "Lost X connection, aborting.";
+ break;
+ }
+ } else if (status == 0) {
+ return;
+ } else {
+ continue;
+ }
+ }
+ }
+#endif
+
// For minimal developer annoyance, don't keep terminating. You need to skip
// the call to base::Process::Terminate below in a debugger for this to be
// useful.
@@ -259,6 +318,28 @@ void GpuWatchdogThread::DeliberatelyTerminateToRecoverFromHang() {
terminated = true;
}
+#if defined(USE_X11)
+void GpuWatchdogThread::SetupXServer() {
+ display_ = XOpenDisplay(NULL);
+ window_ = XCreateWindow(display_, DefaultRootWindow(display_), 0, 0, 1, 1, 0,
+ CopyFromParent, InputOutput, CopyFromParent, 0, NULL);
+ atom_ = XInternAtom(display_, "CHECK", False);
+}
+
+void GpuWatchdogThread::SetupXChangeProp() {
+ XChangeProperty(display_, window_, atom_, XA_STRING, 8, PropModeReplace, text,
+ (arraysize(text) - 1));
+}
+
+bool GpuWatchdogThread::MatchXEventAtom(XEvent* event) {
+ if (event->xproperty.window == window_ && event->type == PropertyNotify &&
+ event->xproperty.atom == atom_)
+ return true;
+
+ return false;
+}
+
+#endif
void GpuWatchdogThread::AddPowerObserver() {
message_loop()->PostTask(
FROM_HERE,
diff --git a/chromium/content/gpu/gpu_watchdog_thread.h b/chromium/content/gpu/gpu_watchdog_thread.h
index c766ca34937..9dd184ab326 100644
--- a/chromium/content/gpu/gpu_watchdog_thread.h
+++ b/chromium/content/gpu/gpu_watchdog_thread.h
@@ -12,6 +12,18 @@
#include "base/threading/thread.h"
#include "base/time/time.h"
#include "content/common/gpu/gpu_watchdog.h"
+#include "ui/gfx/native_widget_types.h"
+
+#if defined(USE_X11)
+extern "C" {
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+}
+#include <sys/poll.h>
+#include "ui/base/x/x11_util.h"
+#include "ui/gfx/x/x11_types.h"
+
+#endif
namespace content {
@@ -62,6 +74,11 @@ class GpuWatchdogThread : public base::Thread,
void OnAcknowledge();
void OnCheck(bool after_suspend);
void DeliberatelyTerminateToRecoverFromHang();
+#if defined(USE_X11)
+ void SetupXServer();
+ void SetupXChangeProp();
+ bool MatchXEventAtom(XEvent* event);
+#endif
void OnAddPowerObserver();
@@ -93,6 +110,12 @@ class GpuWatchdogThread : public base::Thread,
FILE* tty_file_;
#endif
+#if defined(USE_X11)
+ XDisplay* display_;
+ gfx::AcceleratedWidget window_;
+ XAtom atom_;
+#endif
+
base::WeakPtrFactory<GpuWatchdogThread> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(GpuWatchdogThread);
diff --git a/chromium/content/gpu/in_process_gpu_thread.cc b/chromium/content/gpu/in_process_gpu_thread.cc
index 8a7818d6e19..dfd9d358e5f 100644
--- a/chromium/content/gpu/in_process_gpu_thread.cc
+++ b/chromium/content/gpu/in_process_gpu_thread.cc
@@ -9,9 +9,9 @@
namespace content {
-InProcessGpuThread::InProcessGpuThread(const std::string& channel_id)
+InProcessGpuThread::InProcessGpuThread(const InProcessChildThreadParams& params)
: base::Thread("Chrome_InProcGpuThread"),
- channel_id_(channel_id),
+ params_(params),
gpu_process_(NULL) {
}
@@ -23,7 +23,7 @@ void InProcessGpuThread::Init() {
gpu_process_ = new GpuProcess();
// The process object takes ownership of the thread object, so do not
// save and delete the pointer.
- gpu_process_->set_main_thread(new GpuChildThread(channel_id_));
+ gpu_process_->set_main_thread(new GpuChildThread(params_));
}
void InProcessGpuThread::CleanUp() {
@@ -31,8 +31,9 @@ void InProcessGpuThread::CleanUp() {
delete gpu_process_;
}
-base::Thread* CreateInProcessGpuThread(const std::string& channel_id) {
- return new InProcessGpuThread(channel_id);
+base::Thread* CreateInProcessGpuThread(
+ const InProcessChildThreadParams& params) {
+ return new InProcessGpuThread(params);
}
} // namespace content
diff --git a/chromium/content/gpu/in_process_gpu_thread.h b/chromium/content/gpu/in_process_gpu_thread.h
index e8e0140dc28..67ba017c54d 100644
--- a/chromium/content/gpu/in_process_gpu_thread.h
+++ b/chromium/content/gpu/in_process_gpu_thread.h
@@ -7,6 +7,8 @@
#include "base/threading/thread.h"
#include "content/common/content_export.h"
+#include "content/common/content_export.h"
+#include "content/common/in_process_child_thread_params.h"
namespace content {
@@ -16,7 +18,7 @@ class GpuProcess;
// with --in-process-gpu or --single-process.
class InProcessGpuThread : public base::Thread {
public:
- explicit InProcessGpuThread(const std::string& channel_id);
+ InProcessGpuThread(const InProcessChildThreadParams& params);
~InProcessGpuThread() override;
protected:
@@ -24,7 +26,8 @@ class InProcessGpuThread : public base::Thread {
void CleanUp() override;
private:
- std::string channel_id_;
+ InProcessChildThreadParams params_;
+
// Deleted in CleanUp() on the gpu thread, so don't use smart pointers.
GpuProcess* gpu_process_;
@@ -32,7 +35,7 @@ class InProcessGpuThread : public base::Thread {
};
CONTENT_EXPORT base::Thread* CreateInProcessGpuThread(
- const std::string& channel_id);
+ const InProcessChildThreadParams& params);
} // namespace content
diff --git a/chromium/content/plugin/BUILD.gn b/chromium/content/plugin/BUILD.gn
index 03171deaa90..884a8649668 100644
--- a/chromium/content/plugin/BUILD.gn
+++ b/chromium/content/plugin/BUILD.gn
@@ -14,8 +14,8 @@ if (enable_plugins && !is_linux) {
sources = [
"plugin_channel.cc",
"plugin_channel.h",
- "plugin_interpose_util_mac.mm",
"plugin_interpose_util_mac.h",
+ "plugin_interpose_util_mac.mm",
"plugin_main.cc",
"plugin_main_mac.mm",
"plugin_thread.cc",
@@ -32,7 +32,7 @@ if (enable_plugins && !is_linux) {
deps = [
"//content:export",
- "//mojo/public/interfaces/application",
+ "//mojo/application/public/interfaces",
"//skia",
"//third_party/npapi",
"//third_party/WebKit/public:blink",
diff --git a/chromium/content/plugin/plugin_channel.cc b/chromium/content/plugin/plugin_channel.cc
index 0b7ed4f40bf..d94863aeb47 100644
--- a/chromium/content/plugin/plugin_channel.cc
+++ b/chromium/content/plugin/plugin_channel.cc
@@ -243,7 +243,8 @@ PluginChannel::PluginChannel()
filter_(new MessageFilter()),
npp_(new struct _NPP) {
set_send_unblocking_only_during_unblock_dispatch();
- const CommandLine* command_line = CommandLine::ForCurrentProcess();
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
log_messages_ = command_line->HasSwitch(switches::kLogPluginMessages);
// Register |npp_| as the default owner for any object we receive via IPC,
@@ -315,7 +316,7 @@ void PluginChannel::OnClearSiteData(const std::string& site,
uint64 flags,
uint64 max_age) {
bool success = false;
- CommandLine* command_line = CommandLine::ForCurrentProcess();
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
base::FilePath path = command_line->GetSwitchValuePath(switches::kPluginPath);
scoped_refptr<PluginLib> plugin_lib(PluginLib::CreatePluginLib(path));
if (plugin_lib.get()) {
diff --git a/chromium/content/plugin/plugin_main.cc b/chromium/content/plugin/plugin_main.cc
index a793831a4fa..2cef8973c86 100644
--- a/chromium/content/plugin/plugin_main.cc
+++ b/chromium/content/plugin/plugin_main.cc
@@ -44,11 +44,11 @@ int PluginMain(const MainFunctionParams& parameters) {
#endif
base::MessageLoopForUI main_message_loop;
base::PlatformThread::SetName("CrPluginMain");
- base::debug::TraceLog::GetInstance()->SetProcessName("Plugin Process");
- base::debug::TraceLog::GetInstance()->SetProcessSortIndex(
+ base::trace_event::TraceLog::GetInstance()->SetProcessName("Plugin Process");
+ base::trace_event::TraceLog::GetInstance()->SetProcessSortIndex(
kTraceEventPluginProcessSortIndex);
- const CommandLine& parsed_command_line = parameters.command_line;
+ const base::CommandLine& parsed_command_line = parameters.command_line;
#if defined(OS_WIN)
base::win::ScopedCOMInitializer com_initializer;
diff --git a/chromium/content/plugin/plugin_thread.cc b/chromium/content/plugin/plugin_thread.cc
index e51e39b9a63..7fd9bddeba4 100644
--- a/chromium/content/plugin/plugin_thread.cc
+++ b/chromium/content/plugin/plugin_thread.cc
@@ -16,8 +16,7 @@
#include "base/bind.h"
#include "base/command_line.h"
#include "base/lazy_instance.h"
-#include "base/process/kill.h"
-#include "base/process/process_handle.h"
+#include "base/process/process.h"
#include "base/threading/thread_local.h"
#include "content/child/blink_platform_impl.h"
#include "content/child/child_process.h"
@@ -57,7 +56,7 @@ class EnsureTerminateMessageFilter : public IPC::MessageFilter {
private:
void Terminate() {
- base::KillProcess(base::GetCurrentProcessHandle(), 0, false);
+ base::Process::Current().Terminate(0, false);
}
};
@@ -70,7 +69,7 @@ PluginThread::PluginThread()
: preloaded_plugin_module_(NULL),
forcefully_terminate_plugin_process_(false) {
base::FilePath plugin_path =
- CommandLine::ForCurrentProcess()->GetSwitchValuePath(
+ base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
switches::kPluginPath);
lazy_tls.Pointer()->Set(this);
@@ -106,7 +105,7 @@ void PluginThread::SetForcefullyTerminatePluginProcess() {
}
void PluginThread::Shutdown() {
- ChildThread::Shutdown();
+ ChildThreadImpl::Shutdown();
if (preloaded_plugin_module_) {
base::UnloadNativeLibrary(preloaded_plugin_module_);
@@ -116,7 +115,7 @@ void PluginThread::Shutdown() {
PluginLib::UnloadAllPlugins();
if (forcefully_terminate_plugin_process_)
- base::KillProcess(base::GetCurrentProcessHandle(), 0, /* wait= */ false);
+ base::Process::Current().Terminate(0, /* wait= */ false);
lazy_tls.Pointer()->Set(NULL);
}
diff --git a/chromium/content/plugin/plugin_thread.h b/chromium/content/plugin/plugin_thread.h
index 11acafc79c1..8ad115e21c9 100644
--- a/chromium/content/plugin/plugin_thread.h
+++ b/chromium/content/plugin/plugin_thread.h
@@ -8,7 +8,7 @@
#include "base/files/file_path.h"
#include "base/native_library.h"
#include "build/build_config.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
#include "content/child/npapi/plugin_lib.h"
#include "content/plugin/plugin_channel.h"
@@ -22,7 +22,7 @@ class BlinkPlatformImpl;
// The PluginThread class represents a background thread where plugin instances
// live. Communication occurs between WebPluginDelegateProxy in the renderer
// process and WebPluginDelegateStub in this thread through IPC messages.
-class PluginThread : public ChildThread {
+class PluginThread : public ChildThreadImpl {
public:
PluginThread();
~PluginThread() override;
diff --git a/chromium/content/plugin/webplugin_accelerated_surface_proxy_mac.cc b/chromium/content/plugin/webplugin_accelerated_surface_proxy_mac.cc
index f01131302cd..e5f643ba54a 100644
--- a/chromium/content/plugin/webplugin_accelerated_surface_proxy_mac.cc
+++ b/chromium/content/plugin/webplugin_accelerated_surface_proxy_mac.cc
@@ -20,7 +20,7 @@ WebPluginAcceleratedSurfaceProxy* WebPluginAcceleratedSurfaceProxy::Create(
gfx::GpuPreference gpu_preference) {
// This code path shouldn't be taken if CA plugins are disabled
// because the CA drawing model shouldn't be advertised.
- DCHECK(!CommandLine::ForCurrentProcess()->HasSwitch(
+ DCHECK(!base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableCoreAnimationPlugins));
AcceleratedSurface* surface = new AcceleratedSurface;
diff --git a/chromium/content/plugin/webplugin_accelerated_surface_proxy_mac.h b/chromium/content/plugin/webplugin_accelerated_surface_proxy_mac.h
index 2374ba3ef18..09b1b6469fe 100644
--- a/chromium/content/plugin/webplugin_accelerated_surface_proxy_mac.h
+++ b/chromium/content/plugin/webplugin_accelerated_surface_proxy_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_PLUGIN_WEBPLUGIN_ACCELERATED_SURFACE_PROXY_H_
-#define CONTENT_PLUGIN_WEBPLUGIN_ACCELERATED_SURFACE_PROXY_H_
+#ifndef CONTENT_PLUGIN_WEBPLUGIN_ACCELERATED_SURFACE_PROXY_MAC_H_
+#define CONTENT_PLUGIN_WEBPLUGIN_ACCELERATED_SURFACE_PROXY_MAC_H_
#include "base/compiler_specific.h"
#include "content/child/npapi/webplugin_accelerated_surface_mac.h"
@@ -45,4 +45,4 @@ class WebPluginAcceleratedSurfaceProxy : public WebPluginAcceleratedSurface {
} // namespace content
-#endif // CONTENT_PLUGIN_WEBPLUGIN_ACCELERATED_SURFACE_PROXY_H_
+#endif // CONTENT_PLUGIN_WEBPLUGIN_ACCELERATED_SURFACE_PROXY_MAC_H_
diff --git a/chromium/content/plugin/webplugin_delegate_stub.cc b/chromium/content/plugin/webplugin_delegate_stub.cc
index 81267b5f64f..ae4ebee43f0 100644
--- a/chromium/content/plugin/webplugin_delegate_stub.cc
+++ b/chromium/content/plugin/webplugin_delegate_stub.cc
@@ -175,7 +175,8 @@ void WebPluginDelegateStub::OnInit(const PluginMsg_Init_Params& params,
return;
}
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
base::FilePath path =
command_line.GetSwitchValuePath(switches::kPluginPath);
@@ -438,7 +439,7 @@ void WebPluginDelegateStub::OnFetchURL(
params.method,
data,
static_cast<unsigned int>(params.post_data.size()),
- params.referrer,
+ Referrer(params.referrer, params.referrer_policy),
params.notify_redirect,
params.is_plugin_src_load,
channel_->renderer_id(),
diff --git a/chromium/content/plugin/webplugin_delegate_stub.h b/chromium/content/plugin/webplugin_delegate_stub.h
index d6f6323db1e..63964e11555 100644
--- a/chromium/content/plugin/webplugin_delegate_stub.h
+++ b/chromium/content/plugin/webplugin_delegate_stub.h
@@ -13,8 +13,8 @@
#include "ipc/ipc_listener.h"
#include "ipc/ipc_sender.h"
#include "third_party/npapi/bindings/npapi.h"
+#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/rect.h"
#include "url/gurl.h"
struct PluginMsg_Init_Params;
diff --git a/chromium/content/plugin/webplugin_proxy.cc b/chromium/content/plugin/webplugin_proxy.cc
index 81003fccb04..21f76ea9be6 100644
--- a/chromium/content/plugin/webplugin_proxy.cc
+++ b/chromium/content/plugin/webplugin_proxy.cc
@@ -605,8 +605,8 @@ bool WebPluginProxy::CheckIfRunInsecureContent(const GURL& url) {
#if defined(OS_WIN) && !defined(USE_AURA)
void WebPluginProxy::UpdateIMEStatus() {
- // Retrieve the IME status from a plug-in and send it to a renderer process
- // when the plug-in has updated it.
+ // Retrieve the IME status from a plugin and send it to a renderer process
+ // when the plugin has updated it.
int input_type;
gfx::Rect caret_rect;
if (!delegate_->GetIMEStatus(&input_type, &caret_rect))
diff --git a/chromium/content/plugin/webplugin_proxy.h b/chromium/content/plugin/webplugin_proxy.h
index e1fb45dc8e8..2a561edb427 100644
--- a/chromium/content/plugin/webplugin_proxy.h
+++ b/chromium/content/plugin/webplugin_proxy.h
@@ -9,9 +9,6 @@
#include "base/containers/hash_tables.h"
#include "base/memory/ref_counted.h"
-#if defined(OS_MACOSX)
-#include "base/mac/scoped_cftyperef.h"
-#endif
#include "base/memory/scoped_ptr.h"
#include "base/memory/shared_memory.h"
#include "base/memory/weak_ptr.h"
@@ -24,6 +21,12 @@
#include "ui/gl/gpu_preference.h"
#include "ui/surface/transport_dib.h"
+#if defined(OS_MACOSX)
+#include <ApplicationServices/ApplicationServices.h>
+
+#include "base/mac/scoped_cftyperef.h"
+#endif
+
struct PluginMsg_FetchURL_Params;
namespace content {
@@ -90,7 +93,7 @@ class WebPluginProxy : public WebPlugin,
bool CheckIfRunInsecureContent(const GURL& url) override;
#if defined(OS_WIN)
void SetWindowlessData(HANDLE pump_messages_event,
- gfx::NativeViewId dummy_activation_window);
+ gfx::NativeViewId dummy_activation_window) override;
#endif
#if defined(OS_MACOSX)
void FocusChanged(bool focused) override;
@@ -131,7 +134,7 @@ class WebPluginProxy : public WebPlugin,
void OnResourceCreated(int resource_id, WebPluginResourceClient* client);
#if defined(OS_WIN) && !defined(USE_AURA)
- // Retrieves the IME status from a windowless plug-in and sends it to a
+ // Retrieves the IME status from a windowless plugin and sends it to a
// renderer process. A renderer process will convert the coordinates from
// local to the window coordinates and send the converted coordinates to a
// browser process.
diff --git a/chromium/content/ppapi_plugin/BUILD.gn b/chromium/content/ppapi_plugin/BUILD.gn
index eff00a52cba..ef4dcdf5976 100644
--- a/chromium/content/ppapi_plugin/BUILD.gn
+++ b/chromium/content/ppapi_plugin/BUILD.gn
@@ -2,7 +2,21 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("ppapi_plugin") {
+group("ppapi_plugin") {
+ visibility = [ "//content/*" ]
+
+ if (is_component_build) {
+ public_deps = [
+ "//content",
+ ]
+ } else {
+ public_deps = [
+ ":ppapi_plugin_sources",
+ ]
+ }
+}
+
+source_set("ppapi_plugin_sources") {
visibility = [ "//content/*" ]
sources = [
@@ -25,8 +39,8 @@ source_set("ppapi_plugin") {
"//content:export",
"//content/public/child:child_sources",
"//content/public/common:common_sources",
- "//mojo/public/interfaces/application",
- "//ppapi:ppapi_ipc",
+ "//mojo/application/public/interfaces",
+ "//ppapi/proxy:ipc",
"//skia",
"//third_party/icu",
"//third_party/WebKit/public:blink",
diff --git a/chromium/content/ppapi_plugin/broker_process_dispatcher.cc b/chromium/content/ppapi_plugin/broker_process_dispatcher.cc
index 35d5b9d48e6..97d425043c8 100644
--- a/chromium/content/ppapi_plugin/broker_process_dispatcher.cc
+++ b/chromium/content/ppapi_plugin/broker_process_dispatcher.cc
@@ -309,14 +309,16 @@ bool BrokerProcessDispatcher::SetSitePermission(
if (flash_browser_operations_1_3_) {
PP_Bool result = flash_browser_operations_1_3_->SetSitePermission(
- data_str.c_str(), setting_type, sites.size(), site_array.get());
+ data_str.c_str(), setting_type,
+ static_cast<uint32_t>(sites.size()), site_array.get());
return PP_ToBool(result);
}
if (flash_browser_operations_1_2_) {
PP_Bool result = flash_browser_operations_1_2_->SetSitePermission(
- data_str.c_str(), setting_type, sites.size(), site_array.get());
+ data_str.c_str(), setting_type,
+ static_cast<uint32_t>(sites.size()), site_array.get());
return PP_ToBool(result);
}
diff --git a/chromium/content/ppapi_plugin/ppapi_blink_platform_impl.cc b/chromium/content/ppapi_plugin/ppapi_blink_platform_impl.cc
index ad84196ac3f..5c9de83d08b 100644
--- a/chromium/content/ppapi_plugin/ppapi_blink_platform_impl.cc
+++ b/chromium/content/ppapi_plugin/ppapi_blink_platform_impl.cc
@@ -10,19 +10,15 @@
#include "base/strings/string16.h"
#include "base/threading/platform_thread.h"
#include "build/build_config.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
#include "content/common/child_process_messages.h"
#include "ppapi/proxy/plugin_globals.h"
#include "ppapi/shared_impl/proxy_lock.h"
#include "third_party/WebKit/public/platform/WebString.h"
-#if defined(OS_WIN)
-#include "third_party/WebKit/public/platform/win/WebSandboxSupport.h"
-#elif defined(OS_MACOSX)
+#if defined(OS_MACOSX)
#include "third_party/WebKit/public/platform/mac/WebSandboxSupport.h"
-#elif defined(OS_ANDROID)
-#include "third_party/WebKit/public/platform/android/WebSandboxSupport.h"
-#elif defined(OS_POSIX)
+#elif defined(OS_POSIX) && !defined(OS_ANDROID)
#include "content/common/child_process_sandbox_support_impl_linux.h"
#include "third_party/WebKit/public/platform/linux/WebFallbackFont.h"
#include "third_party/WebKit/public/platform/linux/WebSandboxSupport.h"
@@ -38,16 +34,14 @@ typedef struct CGFont* CGFontRef;
namespace content {
+#if !defined(OS_ANDROID) && !defined(OS_WIN)
+
class PpapiBlinkPlatformImpl::SandboxSupport : public WebSandboxSupport {
public:
virtual ~SandboxSupport() {}
-#if defined(OS_WIN)
- virtual bool ensureFontLoaded(HFONT);
-#elif defined(OS_MACOSX)
+#if defined(OS_MACOSX)
virtual bool loadFont(NSFont* srcFont, CGFontRef* out, uint32_t* fontID);
-#elif defined(OS_ANDROID)
- // Empty class.
#elif defined(OS_POSIX)
SandboxSupport();
virtual void getFallbackFontForCharacter(
@@ -68,19 +62,7 @@ class PpapiBlinkPlatformImpl::SandboxSupport : public WebSandboxSupport {
#endif
};
-#if defined(OS_WIN)
-
-bool PpapiBlinkPlatformImpl::SandboxSupport::ensureFontLoaded(HFONT font) {
- LOGFONT logfont;
- GetObject(font, sizeof(LOGFONT), &logfont);
-
- // Use the proxy sender rather than going directly to the ChildThread since
- // the proxy browser sender will properly unlock during sync messages.
- return ppapi::proxy::PluginGlobals::Get()->GetBrowserSender()->Send(
- new ChildProcessHostMsg_PreCacheFont(logfont));
-}
-
-#elif defined(OS_MACOSX)
+#if defined(OS_MACOSX)
bool PpapiBlinkPlatformImpl::SandboxSupport::loadFont(NSFont* src_font,
CGFontRef* out,
@@ -92,10 +74,6 @@ bool PpapiBlinkPlatformImpl::SandboxSupport::loadFont(NSFont* src_font,
return false;
}
-#elif defined(OS_ANDROID)
-
-// Empty class.
-
#elif defined(OS_POSIX)
PpapiBlinkPlatformImpl::SandboxSupport::SandboxSupport()
@@ -134,18 +112,24 @@ void PpapiBlinkPlatformImpl::SandboxSupport::getRenderStyleForStrike(
#endif
-PpapiBlinkPlatformImpl::PpapiBlinkPlatformImpl()
- : sandbox_support_(new PpapiBlinkPlatformImpl::SandboxSupport()) {
+#endif // !defined(OS_ANDROID) && !defined(OS_WIN)
+
+PpapiBlinkPlatformImpl::PpapiBlinkPlatformImpl() {
+#if !defined(OS_ANDROID) && !defined(OS_WIN)
+ sandbox_support_.reset(new PpapiBlinkPlatformImpl::SandboxSupport);
+#endif
}
PpapiBlinkPlatformImpl::~PpapiBlinkPlatformImpl() {
}
void PpapiBlinkPlatformImpl::Shutdown() {
+#if !defined(OS_ANDROID) && !defined(OS_WIN)
// SandboxSupport contains a map of WebFontFamily objects, which hold
// WebCStrings, which become invalidated when blink is shut down. Hence, we
// need to clear that map now, just before blink::shutdown() is called.
sandbox_support_.reset();
+#endif
}
blink::WebClipboard* PpapiBlinkPlatformImpl::clipboard() {
@@ -164,7 +148,11 @@ blink::WebFileUtilities* PpapiBlinkPlatformImpl::fileUtilities() {
}
blink::WebSandboxSupport* PpapiBlinkPlatformImpl::sandboxSupport() {
+#if !defined(OS_ANDROID) && !defined(OS_WIN)
return sandbox_support_.get();
+#else
+ return nullptr;
+#endif
}
bool PpapiBlinkPlatformImpl::sandboxEnabled() {
diff --git a/chromium/content/ppapi_plugin/ppapi_blink_platform_impl.h b/chromium/content/ppapi_plugin/ppapi_blink_platform_impl.h
index 25076d8fd30..3358436b602 100644
--- a/chromium/content/ppapi_plugin/ppapi_blink_platform_impl.h
+++ b/chromium/content/ppapi_plugin/ppapi_blink_platform_impl.h
@@ -50,8 +50,10 @@ class PpapiBlinkPlatformImpl : public BlinkPlatformImpl {
bool sync_dir);
private:
+#if !defined(OS_ANDROID) && !defined(OS_WIN)
class SandboxSupport;
scoped_ptr<SandboxSupport> sandbox_support_;
+#endif
DISALLOW_COPY_AND_ASSIGN(PpapiBlinkPlatformImpl);
};
diff --git a/chromium/content/ppapi_plugin/ppapi_broker_main.cc b/chromium/content/ppapi_plugin/ppapi_broker_main.cc
index 78d0f1d698e..b441d7a6b9f 100644
--- a/chromium/content/ppapi_plugin/ppapi_broker_main.cc
+++ b/chromium/content/ppapi_plugin/ppapi_broker_main.cc
@@ -15,15 +15,16 @@ namespace content {
// Main function for starting the PPAPI broker process.
int PpapiBrokerMain(const MainFunctionParams& parameters) {
- const CommandLine& command_line = parameters.command_line;
+ const base::CommandLine& command_line = parameters.command_line;
if (command_line.HasSwitch(switches::kPpapiStartupDialog)) {
ChildProcess::WaitForDebugger("PpapiBroker");
}
base::MessageLoop main_message_loop;
base::PlatformThread::SetName("CrPPAPIBrokerMain");
- base::debug::TraceLog::GetInstance()->SetProcessName("PPAPI Broker Process");
- base::debug::TraceLog::GetInstance()->SetProcessSortIndex(
+ base::trace_event::TraceLog::GetInstance()->SetProcessName(
+ "PPAPI Broker Process");
+ base::trace_event::TraceLog::GetInstance()->SetProcessSortIndex(
kTraceEventPpapiBrokerProcessSortIndex);
ChildProcess ppapi_broker_process;
diff --git a/chromium/content/ppapi_plugin/ppapi_plugin_main.cc b/chromium/content/ppapi_plugin/ppapi_plugin_main.cc
index fb0beda4ab3..742a49bdc37 100644
--- a/chromium/content/ppapi_plugin/ppapi_plugin_main.cc
+++ b/chromium/content/ppapi_plugin/ppapi_plugin_main.cc
@@ -63,7 +63,7 @@ void SkiaPreCacheFont(const LOGFONT& logfont) {
// Main function for starting the PPAPI plugin process.
int PpapiPluginMain(const MainFunctionParams& parameters) {
- const CommandLine& command_line = parameters.command_line;
+ const base::CommandLine& command_line = parameters.command_line;
#if defined(OS_WIN)
g_target_services = parameters.sandbox_info->target_services;
@@ -111,11 +111,11 @@ int PpapiPluginMain(const MainFunctionParams& parameters) {
base::MessageLoop main_message_loop;
base::PlatformThread::SetName("CrPPAPIMain");
- base::debug::TraceLog::GetInstance()->SetProcessName("PPAPI Process");
- base::debug::TraceLog::GetInstance()->SetProcessSortIndex(
+ base::trace_event::TraceLog::GetInstance()->SetProcessName("PPAPI Process");
+ base::trace_event::TraceLog::GetInstance()->SetProcessSortIndex(
kTraceEventPpapiProcessSortIndex);
-#if defined(OS_LINUX) && defined(USE_NSS)
+#if defined(OS_LINUX) && defined(USE_NSS_CERTS)
// Some out-of-process PPAPI plugins use NSS.
// NSS must be initialized before enabling the sandbox below.
crypto::InitNSSSafely();
diff --git a/chromium/content/ppapi_plugin/ppapi_thread.cc b/chromium/content/ppapi_plugin/ppapi_thread.cc
index 45d8951fe67..13babb43fcb 100644
--- a/chromium/content/ppapi_plugin/ppapi_thread.cc
+++ b/chromium/content/ppapi_plugin/ppapi_thread.cc
@@ -11,6 +11,7 @@
#include "base/debug/crash_logging.h"
#include "base/files/file_util.h"
#include "base/logging.h"
+#include "base/memory/discardable_memory_allocator.h"
#include "base/metrics/histogram.h"
#include "base/metrics/sparse_histogram.h"
#include "base/rand_util.h"
@@ -19,6 +20,7 @@
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
#include "content/child/browser_font_resource_trusted.h"
+#include "content/child/child_discardable_shared_memory_manager.h"
#include "content/child/child_process.h"
#include "content/common/child_process_messages.h"
#include "content/common/sandbox_util.h"
@@ -91,8 +93,7 @@ static void WarmupWindowsLocales(const ppapi::PpapiPermissions& permissions) {
}
}
}
-#else
-extern void* g_target_services;
+
#endif
namespace content {
@@ -100,24 +101,32 @@ namespace content {
typedef int32_t (*InitializeBrokerFunc)
(PP_ConnectInstance_Func* connect_instance_func);
-PpapiThread::PpapiThread(const CommandLine& command_line, bool is_broker)
+PpapiThread::PpapiThread(const base::CommandLine& command_line, bool is_broker)
: is_broker_(is_broker),
+ plugin_globals_(GetIOTaskRunner()),
connect_instance_func_(NULL),
- local_pp_module_(
- base::RandInt(0, std::numeric_limits<PP_Module>::max())),
+ local_pp_module_(base::RandInt(0, std::numeric_limits<PP_Module>::max())),
next_plugin_dispatcher_id_(1) {
- ppapi::proxy::PluginGlobals* globals = ppapi::proxy::PluginGlobals::Get();
- globals->SetPluginProxyDelegate(this);
- globals->set_command_line(
+ plugin_globals_.SetPluginProxyDelegate(this);
+ plugin_globals_.set_command_line(
command_line.GetSwitchValueASCII(switches::kPpapiFlashArgs));
blink_platform_impl_.reset(new PpapiBlinkPlatformImpl);
blink::initialize(blink_platform_impl_.get());
if (!is_broker_) {
- channel()->AddFilter(
+ scoped_refptr<ppapi::proxy::PluginMessageFilter> plugin_filter(
new ppapi::proxy::PluginMessageFilter(
- NULL, globals->resource_reply_thread_registrar()));
+ NULL, plugin_globals_.resource_reply_thread_registrar()));
+ channel()->AddFilter(plugin_filter.get());
+ plugin_globals_.RegisterResourceMessageFilters(plugin_filter.get());
+ }
+
+ // In single process, browser main loop set up the discardable memory
+ // allocator.
+ if (!command_line.HasSwitch(switches::kSingleProcess)) {
+ base::DiscardableMemoryAllocator::SetInstance(
+ ChildThreadImpl::discardable_shared_memory_manager());
}
}
@@ -125,7 +134,7 @@ PpapiThread::~PpapiThread() {
}
void PpapiThread::Shutdown() {
- ChildThread::Shutdown();
+ ChildThreadImpl::Shutdown();
ppapi::proxy::PluginGlobals::Get()->ResetPluginProxyDelegate();
if (plugin_entry_points_.shutdown_module)
@@ -137,7 +146,7 @@ void PpapiThread::Shutdown() {
bool PpapiThread::Send(IPC::Message* msg) {
// Allow access from multiple threads.
if (base::MessageLoop::current() == message_loop())
- return ChildThread::Send(msg);
+ return ChildThreadImpl::Send(msg);
return sync_message_filter()->Send(msg);
}
@@ -159,7 +168,7 @@ bool PpapiThread::OnControlMessageReceived(const IPC::Message& msg) {
}
void PpapiThread::OnChannelConnected(int32 peer_pid) {
- ChildThread::OnChannelConnected(peer_pid);
+ ChildThreadImpl::OnChannelConnected(peer_pid);
#if defined(OS_WIN)
if (is_broker_)
peer_handle_.Set(::OpenProcess(PROCESS_DUP_HANDLE, FALSE, peer_pid));
@@ -199,14 +208,13 @@ IPC::Sender* PpapiThread::GetBrowserSender() {
}
std::string PpapiThread::GetUILanguage() {
- CommandLine* command_line = CommandLine::ForCurrentProcess();
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
return command_line->GetSwitchValueASCII(switches::kLang);
}
void PpapiThread::PreCacheFont(const void* logfontw) {
#if defined(OS_WIN)
- Send(new ChildProcessHostMsg_PreCacheFont(
- *static_cast<const LOGFONTW*>(logfontw)));
+ ChildThreadImpl::PreCacheFont(*static_cast<const LOGFONTW*>(logfontw));
#endif
}
@@ -360,6 +368,12 @@ void PpapiThread::OnLoadPlugin(const base::FilePath& path,
WarmupWindowsLocales(permissions);
+#if defined(ADDRESS_SANITIZER)
+ // Bind and leak dbghelp.dll before the token is lowered, otherwise
+ // AddressSanitizer will crash when trying to symbolize a report.
+ LoadLibraryA("dbghelp.dll");
+#endif
+
g_target_services->LowerToken();
}
#endif
diff --git a/chromium/content/ppapi_plugin/ppapi_thread.h b/chromium/content/ppapi_plugin/ppapi_thread.h
index 3d80e490c9f..8b4f522d7c4 100644
--- a/chromium/content/ppapi_plugin/ppapi_thread.h
+++ b/chromium/content/ppapi_plugin/ppapi_thread.h
@@ -14,7 +14,7 @@
#include "base/process/process.h"
#include "base/scoped_native_library.h"
#include "build/build_config.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
#include "content/public/common/pepper_plugin_info.h"
#include "ppapi/c/pp_module.h"
#include "ppapi/c/trusted/ppp_broker.h"
@@ -40,7 +40,13 @@ namespace content {
class PpapiBlinkPlatformImpl;
-class PpapiThread : public ChildThread,
+#if defined(COMPILER_MSVC)
+// See explanation for other RenderViewHostImpl which is the same issue.
+#pragma warning(push)
+#pragma warning(disable: 4250)
+#endif
+
+class PpapiThread : public ChildThreadImpl,
public ppapi::proxy::PluginDispatcher::PluginDelegate,
public ppapi::proxy::PluginProxyDelegate {
public:
@@ -158,6 +164,10 @@ class PpapiThread : public ChildThread,
DISALLOW_IMPLICIT_CONSTRUCTORS(PpapiThread);
};
+#if defined(COMPILER_MSVC)
+#pragma warning(pop)
+#endif
+
} // namespace content
#endif // CONTENT_PPAPI_PLUGIN_PPAPI_THREAD_H_
diff --git a/chromium/content/public/android/BUILD.gn b/chromium/content/public/android/BUILD.gn
index 94bb8780b17..cd62d1f3238 100644
--- a/chromium/content/public/android/BUILD.gn
+++ b/chromium/content/public/android/BUILD.gn
@@ -6,9 +6,9 @@ import("//build/config/android/config.gni")
import("//build/config/android/rules.gni")
content_jni_gypi_values = exec_script("//build/gypi_to_gn.py",
- [ rebase_path("../../content_jni.gypi") ],
- "scope",
- [ "../../content_jni.gypi" ])
+ [ rebase_path("../../content_jni.gypi") ],
+ "scope",
+ [ "../../content_jni.gypi" ])
android_aidl("common_aidl") {
interface_file = "java/src/org/chromium/content/common/common.aidl"
@@ -32,28 +32,30 @@ android_library("content_java") {
deps = [
":content_java_resources",
"//base:base_java",
+ "//device/battery/android:battery_monitor_android",
+ "//device/battery:mojo_bindings_java",
"//media/base/android:media_java",
+ "//media/midi:midi_java",
"//mojo/android:system_java",
- "//mojo/public/java:bindings",
- "//mojo/public/java:system",
"//net/android:net_java",
+ "//third_party/mojo/src/mojo/public/java:bindings",
+ "//third_party/mojo/src/mojo/public/java:system",
+ "//ui/accessibility:ui_accessibility_java",
"//ui/android:ui_java",
"//third_party/jsr-305:jsr_305_javalib",
+ "//third_party/WebKit/public:blink_headers_java",
-#"//content:content_common",
+ #"//content:content_common",
]
srcjar_deps = [
":common_aidl",
":content_public_android_java_enums_srcjar",
+ "//ui/touch_selection:ui_touch_selection_enums_srcjar",
+ "//ui/touch_selection:ui_touch_handle_orientation_srcjar",
]
DEPRECATED_java_in_dir = "java/src"
- if (!is_android_webview_build) {
- deps += [
- "//third_party/eyesfree:eyesfree_java",
- ]
- }
}
java_strings_grd("content_strings_grd") {
@@ -110,8 +112,11 @@ java_cpp_enum("content_public_android_java_enums_srcjar") {
sources = [
"//content/browser/android/content_view_core_impl.cc",
"//content/browser/android/gesture_event_type.h",
- "//content/browser/renderer_host/input/selection_event_type.h",
"//content/browser/gamepad/gamepad_standard_mappings.h",
+ "//content/public/browser/invalidate_type.h",
+ "//content/public/browser/navigation_controller.h",
+ "//content/public/browser/readback_types.h",
+ "//content/public/common/console_message_level.h",
"//content/public/common/result_codes.h",
"//content/public/common/screen_orientation_values.h",
"//content/public/common/speech_recognition_error.h",
@@ -122,7 +127,11 @@ java_cpp_enum("content_public_android_java_enums_srcjar") {
"org/chromium/content/browser/input/CanonicalAxisIndex.java",
"org/chromium/content/browser/input/CanonicalButtonIndex.java",
"org/chromium/content/browser/input/PopupItemType.java",
- "org/chromium/content/browser/input/SelectionEventType.java",
+ "org/chromium/content_public/browser/InvalidateTypes.java",
+ "org/chromium/content_public/browser/navigation_controller/LoadURLType.java",
+ "org/chromium/content_public/browser/navigation_controller/UserAgentOverrideOption.java",
+ "org/chromium/content_public/browser/readback_types/ReadbackResponse.java",
+ "org/chromium/content_public/common/ConsoleMessageLevel.java",
"org/chromium/content_public/common/ResultCode.java",
"org/chromium/content_public/common/ScreenOrientationValues.java",
"org/chromium/content_public/common/SpeechRecognitionErrorCode.java",
@@ -162,11 +171,11 @@ android_library("content_javatests") {
"//content/shell/android:content_shell_test_java",
"//media/base/android:media_java",
"//mojo/android:system_java",
- "//mojo/public/interfaces/bindings/tests:test_interfaces_java",
- "//mojo/public/java:bindings",
- "//mojo/public/java:system",
"//net/android:net_java",
"//net/android:net_java_test_support",
+ "//third_party/mojo/src/mojo/public/interfaces/bindings/tests:test_interfaces_java",
+ "//third_party/mojo/src/mojo/public/java:bindings",
+ "//third_party/mojo/src/mojo/public/java:system",
"//ui/android:ui_java",
":content_java",
]
@@ -174,5 +183,13 @@ android_library("content_javatests") {
DEPRECATED_java_in_dir = "javatests/src"
}
-
+# GYP: //content/content_tests.gypi:content_junit_tests
+junit_binary("content_junit_tests") {
+ java_files = [ "junit/src/org/chromium/content/browser/input/GamepadMappingsTest.java" ]
+ deps = [
+ ":content_java",
+ "//base:base_java",
+ "//base:base_java_test_support",
+ ]
+}
# TODO(GYP): content_icudata
diff --git a/chromium/content/public/android/DEPS b/chromium/content/public/android/DEPS
index 01d0156151a..edd6d0de7db 100644
--- a/chromium/content/public/android/DEPS
+++ b/chromium/content/public/android/DEPS
@@ -5,6 +5,8 @@ include_rules = [
"+content/public/test/android",
# ContentShellActivity is needed for running ContentView.
"+content/shell/android",
+ # Needed for device APIs implemented as Mojo services in Java.
+ "+device",
# Mojo is needed for Mojo service registry kept in the browser.
"+mojo/android",
]
diff --git a/chromium/content/public/android/OWNERS b/chromium/content/public/android/OWNERS
index 1f0649b1740..7702ef7a713 100644
--- a/chromium/content/public/android/OWNERS
+++ b/chromium/content/public/android/OWNERS
@@ -1,4 +1,5 @@
benm@chromium.org
+dtrainor@chromium.org
tedchoc@chromium.org
yfriedman@chromium.org
diff --git a/chromium/content/public/app/BUILD.gn b/chromium/content/public/app/BUILD.gn
index ccb31698574..d75b59e3a55 100644
--- a/chromium/content/public/app/BUILD.gn
+++ b/chromium/content/public/app/BUILD.gn
@@ -20,8 +20,10 @@
# //content (shared library) ->
# //content/public/app:both_sources (source set)
+import("//build/config/chrome_build.gni")
+
public_app_shared_sources = [
- "android_library_loader_hooks.h",
+ "content_jni_onload.h",
"content_main.h",
"content_main_delegate.cc",
"content_main_delegate.h",
@@ -37,7 +39,6 @@ public_app_shared_deps = [
]
if (is_component_build) {
-
source_set("both_sources") {
# Only the main content shared library can pull this in.
visibility = [ "//content:content" ]
@@ -47,24 +48,28 @@ if (is_component_build) {
configs += [ "//content:content_implementation" ]
deps = public_app_shared_deps + [
- "//content/app:both",
- "//content/public/browser:browser_sources",
- ]
+ "//content/app:both",
+ "//content/public/browser:browser_sources",
+ ]
}
# These all just forward to content, which in turn depends on "both_sources".
group("browser") {
- deps = [ "//content" ]
+ deps = [
+ "//content",
+ ]
}
group("child") {
- deps = [ "//content" ]
+ deps = [
+ "//content",
+ ]
}
group("both") {
- deps = [ "//content" ]
+ deps = [
+ "//content",
+ ]
}
-
} else {
-
# content_main_delegate.cc conditionally includes content_browser_client.h
# from //content/public/browser when it's not the child build. However,
# the header checker doesn't know this doesn't apply and throws an error.
@@ -82,16 +87,13 @@ if (is_component_build) {
sources = public_app_shared_sources
configs += [ "//content:content_implementation" ]
deps = public_app_shared_deps + [
- "//content/app:both",
- "//content/public/browser",
- "//content/public/common",
- ]
+ "//content/app:both",
+ "//content/public/browser",
+ "//content/public/common",
+ ]
}
- # TODO(GYP) enable chrome_multiple_dll support
- is_chrome_multiple_dll = false
-
- if (is_chrome_multiple_dll) {
+ if (is_multi_dll_chrome) {
source_set("browser") {
check_includes = false # See comment above.
@@ -101,10 +103,10 @@ if (is_component_build) {
configs += [ "//content:content_implementation" ]
deps = public_app_shared_deps + [
- "//content/app:browser",
- "//content/public/browser",
- "//content/public/common",
- ]
+ "//content/app:browser",
+ "//content/public/browser",
+ "//content/public/common",
+ ]
}
source_set("child") {
@@ -116,19 +118,22 @@ if (is_component_build) {
configs += [ "//content:content_implementation" ]
deps = public_app_shared_deps + [
- "//content/app:child",
- "//content/public/common",
- ]
+ "//content/app:child",
+ "//content/public/common",
+ ]
}
} else {
# When the multi-DLL build is disabled, there is only one type of the
# "app" target, and "browser" and "child" are the same as "both".
group("browser") {
- deps = [ ":both" ]
+ deps = [
+ ":both",
+ ]
}
group("child") {
- deps = [ ":both" ]
+ deps = [
+ ":both",
+ ]
}
}
-
}
diff --git a/chromium/content/public/app/android_library_loader_hooks.h b/chromium/content/public/app/android_library_loader_hooks.h
deleted file mode 100644
index f6779c6a149..00000000000
--- a/chromium/content/public/app/android_library_loader_hooks.h
+++ /dev/null
@@ -1,28 +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_PUBLIC_APP_ANDROID_LIBRARY_LOADER_HOOKS_H_
-#define CONTENT_PUBLIC_APP_ANDROID_LIBRARY_LOADER_HOOKS_H_
-
-#include <jni.h>
-
-#include "base/basictypes.h"
-#include "content/common/content_export.h"
-
-namespace content {
-
-// Register all content JNI functions now, rather than waiting for the process
-// of fully loading the native library to complete.
-CONTENT_EXPORT bool EnsureJniRegistered(JNIEnv* env);
-
-// Do the intialization of content needed immediately after the native library
-// has loaded.
-// This is designed to be used as a hook function to be passed to
-// base::android::SetLibraryLoadedHook
-CONTENT_EXPORT bool LibraryLoaded(JNIEnv* env,
- jclass clazz);
-
-} // namespace content
-
-#endif // CONTENT_PUBLIC_APP_ANDROID_LIBRARY_LOADER_HOOKS_H_
diff --git a/chromium/content/public/app/content_main_delegate.cc b/chromium/content/public/app/content_main_delegate.cc
index e86f6c8c3e1..a7dfe022ac1 100644
--- a/chromium/content/public/app/content_main_delegate.cc
+++ b/chromium/content/public/app/content_main_delegate.cc
@@ -50,8 +50,8 @@ void ContentMainDelegate::ZygoteStarting(
#endif
-bool ContentMainDelegate::ShouldEnableTerminationOnHeapCorruption() {
- return true;
+bool ContentMainDelegate::ShouldEnableProfilerRecording() {
+ return false;
}
ContentBrowserClient* ContentMainDelegate::CreateContentBrowserClient() {
diff --git a/chromium/content/public/app/content_main_delegate.h b/chromium/content/public/app/content_main_delegate.h
index 6273950f2ab..6bd725d0f5c 100644
--- a/chromium/content/public/app/content_main_delegate.h
+++ b/chromium/content/public/app/content_main_delegate.h
@@ -76,12 +76,10 @@ class CONTENT_EXPORT ContentMainDelegate {
virtual void ZygoteForked() {}
#endif // OS_MACOSX
- // Allows the embedder to disable termination on heap corruption.
- // This is being used to measure the impact of this feature on crash reports.
- // Termination on heap corruption is enabled by default.
- // TODO(erikwright): Remove this by September 2014 when experimentation is
- // complete.
- virtual bool ShouldEnableTerminationOnHeapCorruption();
+ // TODO(vadimt, yiyaoliu): Remove this function once crbug.com/453640 is
+ // fixed.
+ // Returns whether or not profiler recording should be enabled.
+ virtual bool ShouldEnableProfilerRecording();
protected:
friend class ContentClientInitializer;
diff --git a/chromium/content/public/browser/BUILD.gn b/chromium/content/public/browser/BUILD.gn
index 39bddc485ca..a0c7f91d6f8 100644
--- a/chromium/content/public/browser/BUILD.gn
+++ b/chromium/content/public/browser/BUILD.gn
@@ -8,9 +8,13 @@ import("//build/config/ui.gni")
# See //content/BUILD.gn for how this works.
group("browser") {
if (is_component_build) {
- public_deps = [ "//content" ]
+ public_deps = [
+ "//content",
+ ]
} else {
- public_deps = [ ":browser_sources" ]
+ public_deps = [
+ ":browser_sources",
+ ]
}
}
@@ -31,7 +35,8 @@ source_set("browser_sources") {
]
} else {
sources = rebase_path(content_browser_gypi_values.public_browser_sources,
- ".", "//content")
+ ".",
+ "//content")
}
if (use_aura) {
@@ -41,8 +46,11 @@ source_set("browser_sources") {
configs += [ "//content:content_implementation" ]
public_deps = [
+ "//content/public/common:mojo_bindings",
+
# We expose skia headers in the public API.
"//skia",
+ "//third_party/mojo/src/mojo/public/cpp/system",
]
deps = [
"//content/browser",
diff --git a/chromium/content/public/browser/android/OWNERS b/chromium/content/public/browser/android/OWNERS
index ade1eb825b7..e98349fb373 100644
--- a/chromium/content/public/browser/android/OWNERS
+++ b/chromium/content/public/browser/android/OWNERS
@@ -1,3 +1,3 @@
-mkosiba@chromium.org
+torne@chromium.org
tedchoc@chromium.org
yfriedman@chromium.org
diff --git a/chromium/content/public/browser/android/browser_media_player_manager.cc b/chromium/content/public/browser/android/browser_media_player_manager.cc
new file mode 100644
index 00000000000..64ad578a02e
--- /dev/null
+++ b/chromium/content/public/browser/android/browser_media_player_manager.cc
@@ -0,0 +1,17 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/public/browser/android/browser_media_player_manager.h"
+
+#include "content/browser/media/android/browser_media_player_manager.h"
+
+namespace content {
+
+void RegisterMediaUrlInterceptor(
+ media::MediaUrlInterceptor* media_url_interceptor) {
+ content::BrowserMediaPlayerManager::RegisterMediaUrlInterceptor(
+ media_url_interceptor);
+}
+
+} // namespace content
diff --git a/chromium/content/public/browser/android/browser_media_player_manager.h b/chromium/content/public/browser/android/browser_media_player_manager.h
new file mode 100644
index 00000000000..172cd8d5342
--- /dev/null
+++ b/chromium/content/public/browser/android/browser_media_player_manager.h
@@ -0,0 +1,22 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_PUBLIC_BROWSER_ANDROID_BROWSER_MEDIA_PLAYER_MANAGER_H_
+#define CONTENT_PUBLIC_BROWSER_ANDROID_BROWSER_MEDIA_PLAYER_MANAGER_H_
+
+#include "content/common/content_export.h"
+
+namespace media {
+class MediaUrlInterceptor;
+}
+
+namespace content {
+
+// Permits embedders to handle custom urls.
+CONTENT_EXPORT void RegisterMediaUrlInterceptor(
+ media::MediaUrlInterceptor* media_url_interceptor);
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_BROWSER_ANDROID_BROWSER_MEDIA_PLAYER_MANAGER_H_
diff --git a/chromium/content/public/browser/android/compositor.h b/chromium/content/public/browser/android/compositor.h
index 25a61c88aec..1a96ee6ee90 100644
--- a/chromium/content/public/browser/android/compositor.h
+++ b/chromium/content/public/browser/android/compositor.h
@@ -8,10 +8,10 @@
#include "base/callback.h"
#include "cc/resources/ui_resource_bitmap.h"
#include "content/common/content_export.h"
-#include "content/public/browser/android/ui_resource_provider.h"
+#include "ui/android/resources/ui_resource_provider.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/size.h"
class SkBitmap;
@@ -23,9 +23,13 @@ namespace gfx {
class JavaBitmap;
}
+namespace ui {
+class ResourceManager;
+class UIResourceProvider;
+}
+
namespace content {
class CompositorClient;
-class UIResourceProvider;
// An interface to the browser-side compositor.
class CONTENT_EXPORT Compositor {
@@ -50,11 +54,6 @@ class CONTENT_EXPORT Compositor {
// Set the output surface bounds.
virtual void SetWindowBounds(const gfx::Size& size) = 0;
- // Sets the window visibility. When becoming invisible, resources will get
- // freed and other calls into the compositor are not allowed until after
- // having been made visible again.
- virtual void SetVisible(bool visible) = 0;
-
// Set the output surface which the compositor renders into.
virtual void SetSurface(jobject surface) = 0;
@@ -66,7 +65,10 @@ class CONTENT_EXPORT Compositor {
virtual void SetNeedsComposite() = 0;
// Returns the UI resource provider associated with the compositor.
- virtual UIResourceProvider& GetUIResourceProvider() = 0;
+ virtual ui::UIResourceProvider& GetUIResourceProvider() = 0;
+
+ // Returns the resource manager associated with the compositor.
+ virtual ui::ResourceManager& GetResourceManager() = 0;
protected:
Compositor() {}
diff --git a/chromium/content/public/browser/android/compositor_client.h b/chromium/content/public/browser/android/compositor_client.h
index 84a263e0ed6..29c4a289eda 100644
--- a/chromium/content/public/browser/android/compositor_client.h
+++ b/chromium/content/public/browser/android/compositor_client.h
@@ -17,9 +17,6 @@ class CONTENT_EXPORT CompositorClient {
// The compositor has completed swapping a frame.
virtual void OnSwapBuffersCompleted(int pending_swap_buffers) {}
- // Tells the client that GL resources were lost and need to be reinitialized.
- virtual void DidLoseResources() {}
-
protected:
CompositorClient() {}
virtual ~CompositorClient() {}
diff --git a/chromium/content/public/browser/android/content_protocol_handler.h b/chromium/content/public/browser/android/content_protocol_handler.h
new file mode 100644
index 00000000000..be9473e1bb3
--- /dev/null
+++ b/chromium/content/public/browser/android/content_protocol_handler.h
@@ -0,0 +1,32 @@
+// 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_PUBLIC_BROWSER_ANDROID_CONTENT_PROTOCOL_HANDLER_H_
+#define CONTENT_PUBLIC_BROWSER_ANDROID_CONTENT_PROTOCOL_HANDLER_H_
+
+#include "base/memory/ref_counted.h"
+#include "content/common/content_export.h"
+#include "net/url_request/url_request_job_factory.h"
+
+namespace base {
+class TaskRunner;
+}
+
+namespace content {
+
+// ProtocolHandler for content scheme jobs.
+class CONTENT_EXPORT ContentProtocolHandler :
+ public net::URLRequestJobFactory::ProtocolHandler {
+ public:
+ // Creates and returns a ContentProtocolHandler instance.
+ static ContentProtocolHandler* Create(
+ const scoped_refptr<base::TaskRunner>& content_task_runner);
+
+ protected:
+ ~ContentProtocolHandler() override {}
+};
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_BROWSER_ANDROID_CONTENT_PROTOCOL_HANDLER_H_
diff --git a/chromium/content/public/browser/android/content_view_core.h b/chromium/content/public/browser/android/content_view_core.h
index 2afd50efe8b..e528090c6d2 100644
--- a/chromium/content/public/browser/android/content_view_core.h
+++ b/chromium/content/public/browser/android/content_view_core.h
@@ -11,8 +11,9 @@
#include "base/callback.h"
#include "content/common/content_export.h"
#include "content/public/browser/navigation_controller.h"
+#include "content/public/browser/readback_types.h"
#include "third_party/skia/include/core/SkImageInfo.h"
-#include "ui/gfx/rect.h"
+#include "ui/gfx/geometry/rect.h"
class SkBitmap;
@@ -39,15 +40,17 @@ class WebContents;
// public interface used by native code outside of the content module.
class CONTENT_EXPORT ContentViewCore {
public:
- // Returns the existing ContentViewCore for |web_contents|, or NULL.
+ // Returns the existing ContentViewCore for |web_contents|, or nullptr.
static ContentViewCore* FromWebContents(WebContents* web_contents);
static ContentViewCore* GetNativeContentViewCore(JNIEnv* env, jobject obj);
virtual WebContents* GetWebContents() const = 0;
+
+ // May return null reference.
virtual base::android::ScopedJavaLocalRef<jobject> GetJavaObject() = 0;
virtual ui::ViewAndroid* GetViewAndroid() const = 0;
virtual ui::WindowAndroid* GetWindowAndroid() const = 0;
- virtual scoped_refptr<cc::Layer> GetLayer() const = 0;
+ virtual const scoped_refptr<cc::Layer>& GetLayer() const = 0;
virtual void ShowPastePopup(int x, int y) = 0;
// Request a scaled content readback. The result is passed through the
@@ -57,7 +60,7 @@ class CONTENT_EXPORT ContentViewCore {
float scale,
SkColorType color_type,
gfx::Rect src_rect,
- const base::Callback<void(bool, const SkBitmap&)>& result_callback) = 0;
+ ReadbackRequestCallback& result_callback) = 0;
virtual float GetDpiScale() const = 0;
virtual void PauseOrResumeGeolocation(bool should_pause) = 0;
diff --git a/chromium/content/public/browser/android/content_view_layer_renderer.h b/chromium/content/public/browser/android/content_view_layer_renderer.h
index a7d563ab104..2911bb4f948 100644
--- a/chromium/content/public/browser/android/content_view_layer_renderer.h
+++ b/chromium/content/public/browser/android/content_view_layer_renderer.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_PUBLIC_BROWSER_ANDROID_CONTENT_VIEW_LAYER_RENDERER_H
-#define CONTENT_PUBLIC_BROWSER_ANDROID_CONTENT_VIEW_LAYER_RENDERER_H
+#ifndef CONTENT_PUBLIC_BROWSER_ANDROID_CONTENT_VIEW_LAYER_RENDERER_H_
+#define CONTENT_PUBLIC_BROWSER_ANDROID_CONTENT_VIEW_LAYER_RENDERER_H_
// This interface is used by consumers of the ContentViewRenderView to
// attach/detach layers.
@@ -25,4 +25,4 @@ class ContentViewLayerRenderer {
} // namespace content
-#endif // CONTENT_PUBLIC_BROWSER_ANDROID_CONTENT_VIEW_LAYER_RENDERER_H
+#endif // CONTENT_PUBLIC_BROWSER_ANDROID_CONTENT_VIEW_LAYER_RENDERER_H_
diff --git a/chromium/content/public/browser/android/devtools_auth.h b/chromium/content/public/browser/android/devtools_auth.h
index 857a1a14137..00ae9d96d85 100644
--- a/chromium/content/public/browser/android/devtools_auth.h
+++ b/chromium/content/public/browser/android/devtools_auth.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_PUBLIC_BROWSER_DEVTOOLS_AUTH_ANDROID_H_
-#define CONTENT_PUBLIC_BROWSER_DEVTOOLS_AUTH_ANDROID_H_
+#ifndef CONTENT_PUBLIC_BROWSER_ANDROID_DEVTOOLS_AUTH_H_
+#define CONTENT_PUBLIC_BROWSER_ANDROID_DEVTOOLS_AUTH_H_
#include "content/common/content_export.h"
#include "net/socket/unix_domain_server_socket_posix.h"
@@ -17,4 +17,4 @@ CONTENT_EXPORT bool CanUserConnectToDevTools(
} // namespace content
-#endif // CONTENT_PUBLIC_BROWSER_DEVTOOLS_AUTH_ANDROID_H_
+#endif // CONTENT_PUBLIC_BROWSER_ANDROID_DEVTOOLS_AUTH_H_
diff --git a/chromium/content/public/browser/android/external_video_surface_container.h b/chromium/content/public/browser/android/external_video_surface_container.h
index 38cbe5987ba..52aec1aed62 100644
--- a/chromium/content/public/browser/android/external_video_surface_container.h
+++ b/chromium/content/public/browser/android/external_video_surface_container.h
@@ -22,6 +22,7 @@ class CONTENT_EXPORT ExternalVideoSurfaceContainer {
public:
typedef base::Callback<void(int, jobject)> SurfaceCreatedCB;
typedef base::Callback<void(int)> SurfaceDestroyedCB;
+ static const int kInvalidPlayerId = -1;
// Called when a media player wants to request an external video surface.
// Whenever the surface is created and visible, |surface_created_cb| will be
@@ -32,7 +33,12 @@ class CONTENT_EXPORT ExternalVideoSurfaceContainer {
const SurfaceCreatedCB& surface_created_cb,
const SurfaceDestroyedCB& surface_destroyed_cb) = 0;
- // Called when a media player wants to release an external video surface.
+ // Returns id of player currently using the external video surface.
+ // Returns kInvalidPlayerId if no player uses the surface.
+ virtual int GetCurrentPlayerId() = 0;
+
+ // Called when a media player wants to release a certain player's external
+ // video surface.
virtual void ReleaseExternalVideoSurface(int player_id) = 0;
// Called when the position and size of the video element which uses
diff --git a/chromium/content/public/browser/android/layer_tree_build_helper.h b/chromium/content/public/browser/android/layer_tree_build_helper.h
deleted file mode 100644
index 4f23a4bed12..00000000000
--- a/chromium/content/public/browser/android/layer_tree_build_helper.h
+++ /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.
-
-#ifndef CONTENT_PUBLIC_BROWSER_ANDROID_LAYER_TREE_BUILD_HELPER_H_
-#define CONTENT_PUBLIC_BROWSER_ANDROID_LAYER_TREE_BUILD_HELPER_H_
-
-#include "base/memory/ref_counted.h"
-
-namespace cc {
-class Layer;
-}
-
-namespace content {
-
-// A Helper class to build a layer tree to be composited
-// given a content root layer.
-class LayerTreeBuildHelper {
- public:
- LayerTreeBuildHelper() {};
- virtual scoped_refptr<cc::Layer> GetLayerTree(
- scoped_refptr<cc::Layer> content_root_layer) = 0;
- virtual ~LayerTreeBuildHelper() {};
-
- private:
- DISALLOW_COPY_AND_ASSIGN(LayerTreeBuildHelper);
-};
-
-}
-
-#endif // CONTENT_PUBLIC_BROWSER_ANDROID_LAYER_TREE_BUILD_HELPER_H_
diff --git a/chromium/content/public/browser/android/synchronous_compositor.h b/chromium/content/public/browser/android/synchronous_compositor.h
index 69000e56639..afe49cdd5cd 100644
--- a/chromium/content/public/browser/android/synchronous_compositor.h
+++ b/chromium/content/public/browser/android/synchronous_compositor.h
@@ -8,8 +8,8 @@
#include "base/memory/ref_counted.h"
#include "content/common/content_export.h"
#include "gpu/command_buffer/service/in_process_command_buffer.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/size.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
class SkCanvas;
@@ -37,16 +37,10 @@ class WebContents;
class CONTENT_EXPORT SynchronousCompositor {
public:
// Must be called once per WebContents instance. Will create the compositor
- // instance as needed, but only if |client| is non-NULL.
+ // instance as needed, but only if |client| is non-nullptr.
static void SetClientForWebContents(WebContents* contents,
SynchronousCompositorClient* client);
- // Allows changing or resetting the client to NULL (this must be used if
- // the client is being deleted prior to the DidDestroyCompositor() call
- // being received by the client). Ownership of |client| remains with
- // the caller.
- virtual void SetClient(SynchronousCompositorClient* client) = 0;
-
static void SetGpuService(
scoped_refptr<gpu::InProcessCommandBuffer::Service> service);
@@ -56,17 +50,6 @@ class CONTENT_EXPORT SynchronousCompositor {
// behavior.
static void SetRecordFullDocument(bool record_full_document);
- // Synchronously initialize compositor for hardware draw. Can only be called
- // while compositor is in software only mode, either after compositor is
- // first created or after ReleaseHwDraw is called. It is invalid to
- // DemandDrawHw before this returns true.
- virtual bool InitializeHwDraw() = 0;
-
- // Reverse of InitializeHwDraw above. Can only be called while hardware draw
- // is already initialized. Brings compositor back to software only mode and
- // releases all hardware resources.
- virtual void ReleaseHwDraw() = 0;
-
// "On demand" hardware draw. The content is first clipped to |damage_area|,
// then transformed through |transform|, and finally clipped to |view_size|.
virtual scoped_ptr<cc::CompositorFrame> DemandDrawHw(
@@ -93,6 +76,11 @@ class CONTENT_EXPORT SynchronousCompositor {
// SynchronousCompositorClient::GetTotalRootLayerScrollOffset).
virtual void DidChangeRootLayerScrollOffset() = 0;
+ // Called by the embedder to notify that the compositor is active. The
+ // compositor won't ask for vsyncs when it's inactive. NOTE: The compositor
+ // starts off as inactive and needs a SetActive(true) call to begin.
+ virtual void SetIsActive(bool is_active) = 0;
+
protected:
virtual ~SynchronousCompositor() {}
};
diff --git a/chromium/content/public/browser/android/synchronous_compositor_client.h b/chromium/content/public/browser/android/synchronous_compositor_client.h
index 2247f3d9b98..e42e09aadca 100644
--- a/chromium/content/public/browser/android/synchronous_compositor_client.h
+++ b/chromium/content/public/browser/android/synchronous_compositor_client.h
@@ -7,7 +7,7 @@
#include "base/basictypes.h"
#include "ui/gfx/geometry/size_f.h"
-#include "ui/gfx/vector2d_f.h"
+#include "ui/gfx/geometry/vector2d_f.h"
namespace content {
@@ -22,7 +22,7 @@ class SynchronousCompositorClient {
// Indication to the client that |compositor| is going out of scope, and
// must not be accessed within or after this call.
// NOTE if the client goes away before the compositor it must call
- // SynchronousCompositor::SetClient(NULL) to release the back pointer.
+ // SynchronousCompositor::SetClient(nullptr) to release the back pointer.
virtual void DidDestroyCompositor(SynchronousCompositor* compositor) = 0;
// See LayerScrollOffsetDelegate for details.
@@ -39,10 +39,7 @@ class SynchronousCompositorClient {
gfx::Vector2dF latest_overscroll_delta,
gfx::Vector2dF current_fling_velocity) = 0;
- // When true, should periodically call
- // SynchronousCompositorOutputSurface::DemandDrawHw. Note that this value
- // can change inside DemandDrawHw call.
- virtual void SetContinuousInvalidate(bool invalidate) = 0;
+ virtual void PostInvalidate() = 0;
virtual void DidUpdateContent() = 0;
diff --git a/chromium/content/public/browser/android/ui_resource_client_android.h b/chromium/content/public/browser/android/ui_resource_client_android.h
deleted file mode 100644
index 83228bd0f56..00000000000
--- a/chromium/content/public/browser/android/ui_resource_client_android.h
+++ /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.
-
-#ifndef CONTENT_PUBLIC_BROWSER_ANDROID_UI_RESOURCE_CLIENT_ANDROID_H_
-#define CONTENT_PUBLIC_BROWSER_ANDROID_UI_RESOURCE_CLIENT_ANDROID_H_
-
-#include "cc/resources/ui_resource_client.h"
-#include "content/common/content_export.h"
-
-namespace content {
-
-class UIResourceProvider;
-
-// Android's UIResourceClient has one extra callback (UIResourceIsInvalid).
-// This signal is intended for the case when the LayerTreeHost is cleared and
-// the user needs to recreate their resources.
-// TODO(powei): This interface can be removed once crbug.com/374906 has been
-// addressed.
-class CONTENT_EXPORT UIResourceClientAndroid : public cc::UIResourceClient {
- public:
- // This method indicates that the UI resource the user holds is no longer
- // valid. The user should not call DeleteUIResource on any resource generated
- // before this signal.
- virtual void UIResourceIsInvalid() = 0;
-};
-
-} // namespace content
-
-#endif // CONTENT_PUBLIC_BROWSER_ANDROID_UI_RESOURCE_CLIENT_ANDROID_H_
diff --git a/chromium/content/public/browser/android/ui_resource_provider.h b/chromium/content/public/browser/android/ui_resource_provider.h
deleted file mode 100644
index c764d1e6360..00000000000
--- a/chromium/content/public/browser/android/ui_resource_provider.h
+++ /dev/null
@@ -1,29 +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_PUBLIC_BROWSER_ANDROID_UI_RESOURCE_PROVIDER_H_
-#define CONTENT_PUBLIC_BROWSER_ANDROID_UI_RESOURCE_PROVIDER_H_
-
-#include "cc/resources/ui_resource_client.h"
-#include "content/common/content_export.h"
-
-namespace content {
-
-class UIResourceClientAndroid;
-
-class CONTENT_EXPORT UIResourceProvider {
- public:
- virtual ~UIResourceProvider() {}
-
- virtual cc::UIResourceId CreateUIResource(
- UIResourceClientAndroid* client) = 0;
-
- virtual void DeleteUIResource(cc::UIResourceId resource_id) = 0;
-
- virtual bool SupportsETC1NonPowerOfTwo() const = 0;
-};
-
-} // namespace content
-
-#endif // CONTENT_PUBLIC_BROWSER_ANDROID_UI_RESOURCE_PROVIDER_H_
diff --git a/chromium/content/public/browser/browser_child_process_host.h b/chromium/content/public/browser/browser_child_process_host.h
index b243678ce54..d1369a455b0 100644
--- a/chromium/content/public/browser/browser_child_process_host.h
+++ b/chromium/content/public/browser/browser_child_process_host.h
@@ -35,7 +35,7 @@ class CONTENT_EXPORT BrowserChildProcessHost : public IPC::Sender {
// |process_type| needs to be either an enum value from ProcessType or an
// embedder-defined value.
static BrowserChildProcessHost* Create(
- int process_type,
+ content::ProcessType process_type,
BrowserChildProcessHostDelegate* delegate);
~BrowserChildProcessHost() override {}
@@ -44,7 +44,8 @@ class CONTENT_EXPORT BrowserChildProcessHost : public IPC::Sender {
// Takes ownership of |cmd_line| and |delegate|.
virtual void Launch(
SandboxedProcessLauncherDelegate* delegate,
- base::CommandLine* cmd_line) = 0;
+ base::CommandLine* cmd_line,
+ bool terminate_on_shutdown) = 0;
virtual const ChildProcessData& GetData() const = 0;
@@ -54,7 +55,7 @@ class CONTENT_EXPORT BrowserChildProcessHost : public IPC::Sender {
// Returns the termination status of a child. |exit_code| is the
// status returned when the process exited (for posix, as returned
// from waitpid(), for Windows, as returned from
- // GetExitCodeProcess()). |exit_code| may be NULL.
+ // GetExitCodeProcess()). |exit_code| may be nullptr.
// |known_dead| indicates that the child is already dead. On Linux, this
// information is necessary to retrieve accurate information. See
// ChildProcessLauncher::GetChildTerminationStatus() for more details.
diff --git a/chromium/content/public/browser/browser_child_process_observer.h b/chromium/content/public/browser/browser_child_process_observer.h
index 41c9c9d5b08..002ec8556bb 100644
--- a/chromium/content/public/browser/browser_child_process_observer.h
+++ b/chromium/content/public/browser/browser_child_process_observer.h
@@ -24,7 +24,9 @@ class CONTENT_EXPORT BrowserChildProcessObserver {
const ChildProcessData& data) {}
// Called when a child process disappears unexpectedly as a result of a crash.
- virtual void BrowserChildProcessCrashed(const ChildProcessData& data) {}
+ // |exit_code| contains the exit code from the process.
+ virtual void BrowserChildProcessCrashed(const ChildProcessData& data,
+ int exit_code) {}
// Called when an instance of a particular child is created in a page. If one
// page contains several regions rendered by the same child, this will be
diff --git a/chromium/content/public/browser/browser_context.h b/chromium/content/public/browser/browser_context.h
index fec68dc320f..c15afefc81a 100644
--- a/chromium/content/public/browser/browser_context.h
+++ b/chromium/content/public/browser/browser_context.h
@@ -10,12 +10,14 @@
#include "base/memory/scoped_ptr.h"
#include "base/supports_user_data.h"
#include "content/common/content_export.h"
+#include "content/public/browser/zoom_level_delegate.h"
#include "content/public/common/push_messaging_status.h"
class GURL;
namespace base {
class FilePath;
+class Time;
}
namespace storage {
@@ -37,6 +39,7 @@ class BrowserPluginGuestManager;
class DownloadManager;
class DownloadManagerDelegate;
class IndexedDBContext;
+class PermissionManager;
class PushMessagingService;
class ResourceContext;
class SiteInstance;
@@ -50,9 +53,9 @@ class CONTENT_EXPORT BrowserContext : public base::SupportsUserData {
public:
static DownloadManager* GetDownloadManager(BrowserContext* browser_context);
- // Returns BrowserContext specific external mount points. It may return NULL
- // if the context doesn't have any BrowserContext specific external mount
- // points. Currenty, non-NULL value is returned only on ChromeOS.
+ // Returns BrowserContext specific external mount points. It may return
+ // nullptr if the context doesn't have any BrowserContext specific external
+ // mount points. Currenty, non-nullptr value is returned only on ChromeOS.
static storage::ExternalMountPoints* GetMountPoints(BrowserContext* context);
static content::StoragePartition* GetStoragePartition(
@@ -82,11 +85,19 @@ class CONTENT_EXPORT BrowserContext : public base::SupportsUserData {
typedef base::Callback<void(scoped_ptr<BlobHandle>)> BlobCallback;
- // |callback| returns a NULL scoped_ptr on failure.
+ // |callback| returns a nullptr scoped_ptr on failure.
static void CreateMemoryBackedBlob(BrowserContext* browser_context,
const char* data, size_t length,
const BlobCallback& callback);
+ // |callback| returns a nullptr scoped_ptr on failure.
+ static void CreateFileBackedBlob(BrowserContext* browser_context,
+ const base::FilePath& path,
+ int64_t offset,
+ int64_t size,
+ const base::Time& expected_modification_time,
+ const BlobCallback& callback);
+
// Delivers a push message with |data| to the Service Worker identified by
// |origin| and |service_worker_registration_id|.
static void DeliverPushMessage(
@@ -111,6 +122,11 @@ class CONTENT_EXPORT BrowserContext : public base::SupportsUserData {
~BrowserContext() override;
+ // Creates a delegate to initialize a HostZoomMap and persist its information.
+ // This is called during creation of each StoragePartition.
+ virtual scoped_ptr<ZoomLevelDelegate> CreateZoomLevelDelegate(
+ const base::FilePath& partition_path) = 0;
+
// Returns the path of the directory where this context's data is stored.
virtual base::FilePath GetPath() const = 0;
@@ -149,23 +165,27 @@ class CONTENT_EXPORT BrowserContext : public base::SupportsUserData {
// Returns the DownloadManagerDelegate for this context. This will be called
// once per context. The embedder owns the delegate and is responsible for
- // ensuring that it outlives DownloadManager. It's valid to return NULL.
+ // ensuring that it outlives DownloadManager. It's valid to return nullptr.
virtual DownloadManagerDelegate* GetDownloadManagerDelegate() = 0;
// Returns the guest manager for this context.
virtual BrowserPluginGuestManager* GetGuestManager() = 0;
- // Returns a special storage policy implementation, or NULL.
+ // Returns a special storage policy implementation, or nullptr.
virtual storage::SpecialStoragePolicy* GetSpecialStoragePolicy() = 0;
// Returns a push messaging service. The embedder owns the service, and is
// responsible for ensuring that it outlives RenderProcessHost. It's valid to
- // return NULL.
+ // return nullptr.
virtual PushMessagingService* GetPushMessagingService() = 0;
// Returns the SSL host state decisions for this context. The context may
- // return NULL, implementing the default exception storage strategy.
+ // return nullptr, implementing the default exception storage strategy.
virtual SSLHostStateDelegate* GetSSLHostStateDelegate() = 0;
+
+ // Returns the PermissionManager associated with that context if any, nullptr
+ // otherwise.
+ virtual PermissionManager* GetPermissionManager() = 0;
};
} // namespace content
diff --git a/chromium/content/public/browser/browser_message_filter.cc b/chromium/content/public/browser/browser_message_filter.cc
index e4cf09407c7..cb75ff1b86a 100644
--- a/chromium/content/public/browser/browser_message_filter.cc
+++ b/chromium/content/public/browser/browser_message_filter.cc
@@ -8,7 +8,6 @@
#include "base/bind_helpers.h"
#include "base/command_line.h"
#include "base/logging.h"
-#include "base/process/kill.h"
#include "base/process/process_handle.h"
#include "base/task_runner.h"
#include "content/browser/browser_child_process_host_impl.h"
@@ -38,12 +37,12 @@ class BrowserMessageFilter::Internal : public IPC::MessageFilter {
void OnFilterRemoved() override { filter_->OnFilterRemoved(); }
void OnChannelClosing() override {
- filter_->sender_ = NULL;
+ filter_->sender_ = nullptr;
filter_->OnChannelClosing();
}
void OnChannelConnected(int32 peer_pid) override {
- filter_->peer_pid_ = peer_pid;
+ filter_->peer_process_ = base::Process::OpenWithExtraPrivileges(peer_pid);
filter_->OnChannelConnected(peer_pid);
}
@@ -98,23 +97,15 @@ class BrowserMessageFilter::Internal : public IPC::MessageFilter {
};
BrowserMessageFilter::BrowserMessageFilter(uint32 message_class_to_filter)
- : internal_(NULL),
- sender_(NULL),
-#if defined(OS_WIN)
- peer_handle_(base::kNullProcessHandle),
-#endif
- peer_pid_(base::kNullProcessId),
+ : internal_(nullptr),
+ sender_(nullptr),
message_classes_to_filter_(1, message_class_to_filter) {}
BrowserMessageFilter::BrowserMessageFilter(
const uint32* message_classes_to_filter,
size_t num_message_classes_to_filter)
- : internal_(NULL),
- sender_(NULL),
-#if defined(OS_WIN)
- peer_handle_(base::kNullProcessHandle),
-#endif
- peer_pid_(base::kNullProcessId),
+ : internal_(nullptr),
+ sender_(nullptr),
message_classes_to_filter_(
message_classes_to_filter,
message_classes_to_filter + num_message_classes_to_filter) {
@@ -122,20 +113,9 @@ BrowserMessageFilter::BrowserMessageFilter(
}
base::ProcessHandle BrowserMessageFilter::PeerHandle() {
-#if defined(OS_WIN)
- base::AutoLock lock(peer_handle_lock_);
- if (peer_handle_ == base::kNullProcessHandle)
- base::OpenPrivilegedProcessHandle(peer_pid_, &peer_handle_);
-
- return peer_handle_;
-#else
- base::ProcessHandle result = base::kNullProcessHandle;
- base::OpenPrivilegedProcessHandle(peer_pid_, &result);
- return result;
-#endif
+ return peer_process_.Handle();
}
-
void BrowserMessageFilter::OnDestruct() const {
delete this;
}
@@ -168,7 +148,7 @@ bool BrowserMessageFilter::Send(IPC::Message* message) {
base::TaskRunner* BrowserMessageFilter::OverrideTaskRunnerForMessage(
const IPC::Message& message) {
- return NULL;
+ return nullptr;
}
bool BrowserMessageFilter::CheckCanDispatchOnUI(const IPC::Message& message,
@@ -197,21 +177,16 @@ bool BrowserMessageFilter::CheckCanDispatchOnUI(const IPC::Message& message,
}
void BrowserMessageFilter::BadMessageReceived() {
- CommandLine* command_line = CommandLine::ForCurrentProcess();
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kDisableKillAfterBadIPC))
return;
BrowserChildProcessHostImpl::HistogramBadMessageTerminated(
PROCESS_TYPE_RENDERER);
- base::KillProcess(PeerHandle(), content::RESULT_CODE_KILLED_BAD_MESSAGE,
- false);
+ peer_process_.Terminate(content::RESULT_CODE_KILLED_BAD_MESSAGE, false);
}
BrowserMessageFilter::~BrowserMessageFilter() {
-#if defined(OS_WIN)
- if (peer_handle_ != base::kNullProcessHandle)
- base::CloseProcessHandle(peer_handle_);
-#endif
}
IPC::MessageFilter* BrowserMessageFilter::GetFilter() {
diff --git a/chromium/content/public/browser/browser_message_filter.h b/chromium/content/public/browser/browser_message_filter.h
index 5ff787de788..1966e5846e7 100644
--- a/chromium/content/public/browser/browser_message_filter.h
+++ b/chromium/content/public/browser/browser_message_filter.h
@@ -81,10 +81,10 @@ class CONTENT_EXPORT BrowserMessageFilter
base::ProcessHandle PeerHandle();
// Can be called on any thread, after OnChannelConnected is called.
- base::ProcessId peer_pid() const { return peer_pid_; }
+ base::ProcessId peer_pid() const { return peer_process_.Pid(); }
- void set_peer_pid_for_testing(base::ProcessId peer_pid) {
- peer_pid_ = peer_pid;
+ void set_peer_process_for_testing(base::Process peer_process) {
+ peer_process_ = peer_process.Pass();
}
// Checks that the given message can be dispatched on the UI thread, depending
@@ -124,14 +124,9 @@ class CONTENT_EXPORT BrowserMessageFilter
Internal* internal_;
IPC::Sender* sender_;
- base::ProcessId peer_pid_;
+ base::Process peer_process_;
std::vector<uint32> message_classes_to_filter_;
-
-#if defined(OS_WIN)
- base::Lock peer_handle_lock_;
- base::ProcessHandle peer_handle_;
-#endif
};
struct BrowserMessageFilterTraits {
diff --git a/chromium/content/public/browser/browser_plugin_guest_delegate.cc b/chromium/content/public/browser/browser_plugin_guest_delegate.cc
index d9a61ea24a3..fd7dec4ccf8 100644
--- a/chromium/content/public/browser/browser_plugin_guest_delegate.cc
+++ b/chromium/content/public/browser/browser_plugin_guest_delegate.cc
@@ -6,15 +6,27 @@
namespace content {
+bool BrowserPluginGuestDelegate::CanRunInDetachedState() const {
+ return false;
+}
+
WebContents* BrowserPluginGuestDelegate::CreateNewGuestWindow(
const WebContents::CreateParams& create_params) {
- return NULL;
+ NOTREACHED();
+ return nullptr;
+}
+
+WebContents* BrowserPluginGuestDelegate::GetOwnerWebContents() const {
+ return nullptr;
}
bool BrowserPluginGuestDelegate::Find(int request_id,
const base::string16& search_text,
- const blink::WebFindOptions& options,
- bool is_full_page_plugin) {
+ const blink::WebFindOptions& options) {
+ return false;
+}
+
+bool BrowserPluginGuestDelegate::StopFinding(StopFindAction action) {
return false;
}
diff --git a/chromium/content/public/browser/browser_plugin_guest_delegate.h b/chromium/content/public/browser/browser_plugin_guest_delegate.h
index 90abc5ddfda..000e3b627da 100644
--- a/chromium/content/public/browser/browser_plugin_guest_delegate.h
+++ b/chromium/content/public/browser/browser_plugin_guest_delegate.h
@@ -20,6 +20,8 @@ class Size;
namespace content {
+class GuestHost;
+
// Objects implement this interface to get notified about changes in the guest
// WebContents and to provide necessary functionality.
class CONTENT_EXPORT BrowserPluginGuestDelegate {
@@ -29,26 +31,43 @@ class CONTENT_EXPORT BrowserPluginGuestDelegate {
// Notification that the embedder will begin attachment. This is called
// prior to resuming resource loads. |element_instance_id| uniquely identifies
// the element that will serve as a container for the guest.
+ // Once the content embedder has completed setting up state for attachment, it
+ // must call the |completion_callback| to complete attachment.
virtual void WillAttach(content::WebContents* embedder_web_contents,
- int element_instance_id) {}
+ int element_instance_id,
+ bool is_full_page_plugin,
+ const base::Closure& completion_callback) {}
virtual WebContents* CreateNewGuestWindow(
const WebContents::CreateParams& create_params);
+ // Asks the delegate whether this guest can run while detached from a
+ // container. A detached guest is a WebContents that has no visual surface
+ // into which it can composite its content. Detached guests can be thought
+ // of as workers with a DOM.
+ virtual bool CanRunInDetachedState() const;
+
// Notification that the embedder has completed attachment. The
// |guest_proxy_routing_id| is the routing ID for the RenderView in the
// embedder that will serve as a contentWindow proxy for the guest.
virtual void DidAttach(int guest_proxy_routing_id) {}
+ // Notification that the guest has detached from its container.
+ virtual void DidDetach() {}
+
+ // Notification that a valid |url| was dropped over the guest.
+ virtual void DidDropLink(const GURL& url) {}
+
// Notification that the BrowserPlugin has resized.
- virtual void ElementSizeChanged(const gfx::Size& old_size,
- const gfx::Size& new_size) {}
+ virtual void ElementSizeChanged(const gfx::Size& size) {}
+
+ // Returns the WebContents that currently owns this guest.
+ virtual WebContents* GetOwnerWebContents() const;
// Notifies that the content size of the guest has changed.
- // Note: In autosize mode, it si possible that the guest size may not match
+ // Note: In autosize mode, it is possible that the guest size may not match
// the element size.
- virtual void GuestSizeChanged(const gfx::Size& old_size,
- const gfx::Size& new_size) {}
+ virtual void GuestSizeChanged(const gfx::Size& new_size) {}
// Asks the delegate if the given guest can lock the pointer.
// Invoking the |callback| synchronously is OK.
@@ -57,18 +76,16 @@ class CONTENT_EXPORT BrowserPluginGuestDelegate {
bool last_unlocked_by_target,
const base::Callback<void(bool)>& callback) {}
- // Registers a |callback| with the delegate that the delegate would call when
- // it is about to be destroyed.
- typedef base::Callback<void()> DestructionCallback;
- virtual void RegisterDestructionCallback(
- const DestructionCallback& callback) {}
-
// Find the given |search_text| in the page. Returns true if the find request
// is handled by this browser plugin guest delegate.
virtual bool Find(int request_id,
const base::string16& search_text,
- const blink::WebFindOptions& options,
- bool is_full_page_plugin);
+ const blink::WebFindOptions& options);
+ virtual bool StopFinding(StopFindAction action);
+
+ // Provides the delegate with an interface with which to communicate with the
+ // content module.
+ virtual void SetGuestHost(GuestHost* guest_host) {}
};
} // namespace content
diff --git a/chromium/content/public/browser/browser_plugin_guest_manager.cc b/chromium/content/public/browser/browser_plugin_guest_manager.cc
index 4ea181739c9..6db83291ad9 100644
--- a/chromium/content/public/browser/browser_plugin_guest_manager.cc
+++ b/chromium/content/public/browser/browser_plugin_guest_manager.cc
@@ -7,9 +7,9 @@
namespace content {
WebContents* BrowserPluginGuestManager::GetGuestByInstanceID(
- WebContents* embedder_web_contents,
+ int owner_process_id,
int browser_plugin_instance_id) {
- return NULL;
+ return nullptr;
}
bool BrowserPluginGuestManager::ForEachGuest(
@@ -18,5 +18,10 @@ bool BrowserPluginGuestManager::ForEachGuest(
return false;
}
+WebContents* BrowserPluginGuestManager::GetFullPageGuest(
+ WebContents* embedder_web_contents) {
+ return nullptr;
+}
+
} // content
diff --git a/chromium/content/public/browser/browser_plugin_guest_manager.h b/chromium/content/public/browser/browser_plugin_guest_manager.h
index 481a8ab6517..c809c0ff7e5 100644
--- a/chromium/content/public/browser/browser_plugin_guest_manager.h
+++ b/chromium/content/public/browser/browser_plugin_guest_manager.h
@@ -19,9 +19,8 @@ class CONTENT_EXPORT BrowserPluginGuestManager {
virtual ~BrowserPluginGuestManager() {}
// Requests a guest WebContents associated with the provided
- // |browser_plugin_instance_id|.
- // Returns the guest associated with the provided ID if one exists.
- virtual WebContents* GetGuestByInstanceID(WebContents* embedder_web_contents,
+ // <owner_process_id, browser_plugin_instance_id> tuple.
+ virtual WebContents* GetGuestByInstanceID(int owner_process_id,
int browser_plugin_instance_id);
// Iterates over all WebContents belonging to a given |embedder_web_contents|,
@@ -30,6 +29,11 @@ class CONTENT_EXPORT BrowserPluginGuestManager {
typedef base::Callback<bool(WebContents*)> GuestCallback;
virtual bool ForEachGuest(WebContents* embedder_web_contents,
const GuestCallback& callback);
+
+ // Returns the "full page" guest if there is one. That is, if there is a
+ // single BrowserPlugin in the given embedder which takes up the full page,
+ // then it is returned.
+ virtual WebContents* GetFullPageGuest(WebContents* embedder_web_contents);
};
} // namespace content
diff --git a/chromium/content/public/browser/browser_ppapi_host.h b/chromium/content/public/browser/browser_ppapi_host.h
index 81b78b69141..777b7b07ae5 100644
--- a/chromium/content/public/browser/browser_ppapi_host.h
+++ b/chromium/content/public/browser/browser_ppapi_host.h
@@ -61,8 +61,8 @@ class CONTENT_EXPORT BrowserPpapiHost {
// Returns the PpapiHost object.
virtual ppapi::host::PpapiHost* GetPpapiHost() = 0;
- // Returns the handle to the plugin process.
- virtual base::ProcessHandle GetPluginProcessHandle() const = 0;
+ // Returns a reference to the plugin process.
+ virtual const base::Process& GetPluginProcess() const = 0;
// Returns true if the given PP_Instance is valid.
virtual bool IsValidInstance(PP_Instance instance) const = 0;
diff --git a/chromium/content/public/browser/browser_thread.h b/chromium/content/public/browser/browser_thread.h
index a9591e9516a..9473c2cd386 100644
--- a/chromium/content/public/browser/browser_thread.h
+++ b/chromium/content/public/browser/browser_thread.h
@@ -81,7 +81,9 @@ class CONTENT_EXPORT BrowserThread {
// This is the thread to handle slow HTTP cache operations.
CACHE,
- // This is the thread that processes IPC and network messages.
+ // This is the thread that processes non-blocking IO, i.e. IPC and network.
+ // Blocking IO should happen on other threads like DB, FILE,
+ // FILE_USER_BLOCKING and CACHE depending on the usage.
IO,
// NOTE: do not add new threads here that are only used by a small number of
@@ -182,6 +184,16 @@ class CONTENT_EXPORT BrowserThread {
const tracked_objects::Location& from_here,
const base::Closure& task);
+ // For use with scheduling non-critical tasks for execution after startup.
+ // The order or execution of tasks posted here is unspecified even when
+ // posting to a SequencedTaskRunner and tasks are not guaranteed to be run
+ // prior to browser shutdown.
+ // Note: see related ContentBrowserClient::PostAfterStartupTask.
+ static void PostAfterStartupTask(
+ const tracked_objects::Location& from_here,
+ const scoped_refptr<base::TaskRunner>& task_runner,
+ const base::Closure& task);
+
// Returns the thread pool used for blocking file I/O. Use this object to
// perform random blocking operations such as file writes or querying the
// Windows registry.
@@ -222,7 +234,7 @@ class CONTENT_EXPORT BrowserThread {
// Sets the delegate for the specified BrowserThread.
//
// Only one delegate may be registered at a time. Delegates may be
- // unregistered by providing a NULL pointer.
+ // unregistered by providing a nullptr pointer.
//
// If the caller unregisters a delegate before CleanUp has been
// called, it must perform its own locking to ensure the delegate is
diff --git a/chromium/content/public/browser/browser_url_handler.h b/chromium/content/public/browser/browser_url_handler.h
index 4fabec3c925..964741f6861 100644
--- a/chromium/content/public/browser/browser_url_handler.h
+++ b/chromium/content/public/browser/browser_url_handler.h
@@ -43,6 +43,11 @@ class CONTENT_EXPORT BrowserURLHandler {
BrowserContext* browser_context,
bool* reverse_on_redirect) = 0;
+ // Set the specified handler as a preliminary fixup phase to be done before
+ // rewriting. This allows minor cleanup for the URL without having it affect
+ // the virtual URL.
+ virtual void SetFixupHandler(URLHandler handler) = 0;
+
// Add the specified handler pair to the list of URL handlers.
//
// Note that normally, the reverse handler is only used if the modified URL is
diff --git a/chromium/content/public/browser/cert_store.h b/chromium/content/public/browser/cert_store.h
index 11d843019fe..73c35a24e8e 100644
--- a/chromium/content/public/browser/cert_store.h
+++ b/chromium/content/public/browser/cert_store.h
@@ -38,7 +38,7 @@ class CertStore {
// Tries to retrieve the previously stored cert associated with the specified
// |cert_id|. Returns whether the cert could be found, and, if |cert| is
- // non-NULL, copies it in.
+ // non-nullptr, copies it in.
virtual bool RetrieveCert(int cert_id,
scoped_refptr<net::X509Certificate>* cert) = 0;
diff --git a/chromium/content/public/browser/child_process_data.h b/chromium/content/public/browser/child_process_data.h
index 395c4876b8d..14e0a84c239 100644
--- a/chromium/content/public/browser/child_process_data.h
+++ b/chromium/content/public/browser/child_process_data.h
@@ -30,9 +30,15 @@ struct ChildProcessData {
// current process.
base::ProcessHandle handle;
+ // The exit code for the process. This is only valid for processes that have
+ // already exited e.g. when receiving a BrowserChildProcessCrashed callback.
+ int exit_code;
+
explicit ChildProcessData(int process_type)
- : process_type(process_type), id(0), handle(base::kNullProcessHandle) {
- }
+ : process_type(process_type),
+ id(0),
+ handle(base::kNullProcessHandle),
+ exit_code(0) {}
};
} // namespace content
diff --git a/chromium/content/public/browser/child_process_security_policy.h b/chromium/content/public/browser/child_process_security_policy.h
index 7048d91cf52..b2a343f05b1 100644
--- a/chromium/content/public/browser/child_process_security_policy.h
+++ b/chromium/content/public/browser/child_process_security_policy.h
@@ -150,6 +150,9 @@ class ChildProcessSecurityPolicy {
// The browser should check this property before assuming the child process
// is allowed to use WebUI bindings.
virtual bool HasWebUIBindings(int child_id) = 0;
+
+ // Grants permission to send system exclusive message to any MIDI devices.
+ virtual void GrantSendMidiSysExMessage(int child_id) = 0;
};
} // namespace content
diff --git a/chromium/content/public/browser/client_certificate_delegate.h b/chromium/content/public/browser/client_certificate_delegate.h
new file mode 100644
index 00000000000..d957fd995b3
--- /dev/null
+++ b/chromium/content/public/browser/client_certificate_delegate.h
@@ -0,0 +1,35 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_PUBLIC_BROWSER_CLIENT_CERTIFICATE_DELEGATE_H_
+#define CONTENT_PUBLIC_BROWSER_CLIENT_CERTIFICATE_DELEGATE_H_
+
+#include "base/macros.h"
+
+namespace net {
+class X509Certificate;
+}
+
+namespace content {
+
+// A delegate interface for selecting a client certificate for use with a
+// network request. If the delegate is destroyed without calling
+// ContinueWithCertificate, the certificate request will be aborted.
+class ClientCertificateDelegate {
+ public:
+ ClientCertificateDelegate() {}
+ virtual ~ClientCertificateDelegate() {}
+
+ // Continue the request with |cert|. |cert| may be nullptr to continue without
+ // supplying a certificate. This decision will be remembered for future
+ // requests to the domain.
+ virtual void ContinueWithCertificate(net::X509Certificate* cert) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ClientCertificateDelegate);
+};
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_BROWSER_CLIENT_CERTIFICATE_DELEGATE_H_
diff --git a/chromium/content/public/browser/content_browser_client.cc b/chromium/content/public/browser/content_browser_client.cc
index 728d8226fa5..486272f317f 100644
--- a/chromium/content/public/browser/content_browser_client.cc
+++ b/chromium/content/public/browser/content_browser_client.cc
@@ -5,6 +5,7 @@
#include "content/public/browser/content_browser_client.h"
#include "base/files/file_path.h"
+#include "content/public/browser/client_certificate_delegate.h"
#include "ui/gfx/image/image_skia.h"
#include "url/gurl.h"
@@ -12,12 +13,19 @@ namespace content {
BrowserMainParts* ContentBrowserClient::CreateBrowserMainParts(
const MainFunctionParams& parameters) {
- return NULL;
+ return nullptr;
+}
+
+void ContentBrowserClient::PostAfterStartupTask(
+ const tracked_objects::Location& from_here,
+ const scoped_refptr<base::TaskRunner>& task_runner,
+ const base::Closure& task) {
+ task_runner->PostTask(from_here, task);
}
WebContentsViewDelegate* ContentBrowserClient::GetWebContentsViewDelegate(
WebContents* web_contents) {
- return NULL;
+ return nullptr;
}
GURL ContentBrowserClient::GetEffectiveURL(BrowserContext* browser_context,
@@ -34,7 +42,7 @@ net::URLRequestContextGetter* ContentBrowserClient::CreateRequestContext(
BrowserContext* browser_context,
ProtocolHandlerMap* protocol_handlers,
URLRequestInterceptorScopedVector request_interceptors) {
- return NULL;
+ return nullptr;
}
net::URLRequestContextGetter*
@@ -44,7 +52,7 @@ ContentBrowserClient::CreateRequestContextForStoragePartition(
bool in_memory,
ProtocolHandlerMap* protocol_handlers,
URLRequestInterceptorScopedVector request_interceptors) {
- return NULL;
+ return nullptr;
}
bool ContentBrowserClient::IsHandledURL(const GURL& url) {
@@ -116,10 +124,11 @@ bool ContentBrowserClient::AllowAppCache(const GURL& manifest_url,
return true;
}
-bool ContentBrowserClient::AllowServiceWorker(
- const GURL& scope,
- const GURL& document_url,
- content::ResourceContext* context) {
+bool ContentBrowserClient::AllowServiceWorker(const GURL& scope,
+ const GURL& document_url,
+ content::ResourceContext* context,
+ int render_process_id,
+ int render_frame_id) {
return true;
}
@@ -173,20 +182,18 @@ bool ContentBrowserClient::AllowWorkerIndexedDB(
}
QuotaPermissionContext* ContentBrowserClient::CreateQuotaPermissionContext() {
- return NULL;
+ return nullptr;
}
void ContentBrowserClient::SelectClientCertificate(
- int render_process_id,
- int render_frame_id,
+ WebContents* web_contents,
net::SSLCertRequestInfo* cert_request_info,
- const base::Callback<void(net::X509Certificate*)>& callback) {
- callback.Run(NULL);
+ scoped_ptr<ClientCertificateDelegate> delegate) {
}
net::URLRequestContext* ContentBrowserClient::OverrideRequestContextForURL(
const GURL& url, ResourceContext* context) {
- return NULL;
+ return nullptr;
}
std::string ContentBrowserClient::GetStoragePartitionIdForSite(
@@ -216,25 +223,12 @@ void ContentBrowserClient::GetStoragePartitionConfigForSite(
}
MediaObserver* ContentBrowserClient::GetMediaObserver() {
- return NULL;
-}
-
-blink::WebNotificationPermission
-ContentBrowserClient::CheckDesktopNotificationPermission(
- const GURL& source_origin,
- ResourceContext* context,
- int render_process_id) {
- return blink::WebNotificationPermissionAllowed;
+ return nullptr;
}
-void ContentBrowserClient::RequestPermission(
- PermissionType permission,
- WebContents* web_contents,
- int bridge_id,
- const GURL& requesting_frame,
- bool user_gesture,
- const base::Callback<void(bool)>& result_callback) {
- result_callback.Run(true);
+PlatformNotificationService*
+ContentBrowserClient::GetPlatformNotificationService() {
+ return nullptr;
}
bool ContentBrowserClient::CanCreateWindow(
@@ -257,16 +251,16 @@ bool ContentBrowserClient::CanCreateWindow(
}
SpeechRecognitionManagerDelegate*
- ContentBrowserClient::GetSpeechRecognitionManagerDelegate() {
- return NULL;
+ ContentBrowserClient::CreateSpeechRecognitionManagerDelegate() {
+ return nullptr;
}
net::NetLog* ContentBrowserClient::GetNetLog() {
- return NULL;
+ return nullptr;
}
AccessTokenStore* ContentBrowserClient::CreateAccessTokenStore() {
- return NULL;
+ return nullptr;
}
bool ContentBrowserClient::IsFastShutdownPossible() {
@@ -283,7 +277,7 @@ std::string ContentBrowserClient::GetDefaultDownloadName() {
BrowserPpapiHost*
ContentBrowserClient::GetExternalBrowserPpapiHost(int plugin_process_id) {
- return NULL;
+ return nullptr;
}
bool ContentBrowserClient::AllowPepperSocketAPI(
@@ -296,19 +290,19 @@ bool ContentBrowserClient::AllowPepperSocketAPI(
ui::SelectFilePolicy* ContentBrowserClient::CreateSelectFilePolicy(
WebContents* web_contents) {
- return NULL;
+ return nullptr;
}
LocationProvider* ContentBrowserClient::OverrideSystemLocationProvider() {
- return NULL;
+ return nullptr;
}
-VibrationProvider* ContentBrowserClient::OverrideVibrationProvider() {
- return NULL;
+DevToolsManagerDelegate* ContentBrowserClient::GetDevToolsManagerDelegate() {
+ return nullptr;
}
-DevToolsManagerDelegate* ContentBrowserClient::GetDevToolsManagerDelegate() {
- return NULL;
+TracingDelegate* ContentBrowserClient::GetTracingDelegate() {
+ return nullptr;
}
bool ContentBrowserClient::IsPluginAllowedToCallRequestOSFileHandle(
@@ -323,14 +317,22 @@ bool ContentBrowserClient::IsPluginAllowedToUseDevChannelAPIs(
return false;
}
-net::CookieStore* ContentBrowserClient::OverrideCookieStoreForRenderProcess(
- int render_process_id) {
- return NULL;
+PresentationServiceDelegate*
+ContentBrowserClient::GetPresentationServiceDelegate(
+ WebContents* web_contents) {
+ return nullptr;
+}
+
+void ContentBrowserClient::OpenURL(
+ content::BrowserContext* browser_context,
+ const content::OpenURLParams& params,
+ const base::Callback<void(content::WebContents*)>& callback) {
+ callback.Run(nullptr);
}
#if defined(OS_WIN)
const wchar_t* ContentBrowserClient::GetResourceDllName() {
- return NULL;
+ return nullptr;
}
#endif
@@ -338,15 +340,8 @@ const wchar_t* ContentBrowserClient::GetResourceDllName() {
ExternalVideoSurfaceContainer*
ContentBrowserClient::OverrideCreateExternalVideoSurfaceContainer(
WebContents* web_contents) {
- return NULL;
+ return nullptr;
}
#endif
-bool ContentBrowserClient::CheckMediaAccessPermission(
- BrowserContext* browser_context,
- const GURL& security_origin,
- MediaStreamType type) {
- return false;
-}
-
} // namespace content
diff --git a/chromium/content/public/browser/content_browser_client.h b/chromium/content/public/browser/content_browser_client.h
index 5a27d9822c5..eff374d1c72 100644
--- a/chromium/content/public/browser/content_browser_client.h
+++ b/chromium/content/public/browser/content_browser_client.h
@@ -16,8 +16,6 @@
#include "base/memory/scoped_vector.h"
#include "base/values.h"
#include "content/public/browser/certificate_request_result_type.h"
-#include "content/public/browser/desktop_notification_delegate.h"
-#include "content/public/browser/permission_type.h"
#include "content/public/common/content_client.h"
#include "content/public/common/media_stream_request.h"
#include "content/public/common/resource_type.h"
@@ -28,7 +26,7 @@
#include "net/url_request/url_request_interceptor.h"
#include "net/url_request/url_request_job_factory.h"
#include "storage/browser/fileapi/file_system_context.h"
-#include "third_party/WebKit/public/platform/WebNotificationPermission.h"
+#include "third_party/WebKit/public/platform/WebPageVisibilityState.h"
#include "ui/base/window_open_disposition.h"
#if defined(OS_POSIX) && !defined(OS_MACOSX)
@@ -57,7 +55,6 @@ class ImageSkia;
namespace net {
class CookieOptions;
-class CookieStore;
class NetLog;
class SSLCertRequestInfo;
class SSLInfo;
@@ -82,6 +79,7 @@ class FileSystemBackend;
namespace content {
+enum class PermissionType;
class AccessTokenStore;
class BrowserChildProcessHost;
class BrowserContext;
@@ -89,24 +87,29 @@ class BrowserMainParts;
class BrowserPluginGuestDelegate;
class BrowserPpapiHost;
class BrowserURLHandler;
-class DesktopNotificationDelegate;
+class ClientCertificateDelegate;
class DevToolsManagerDelegate;
class ExternalVideoSurfaceContainer;
class LocationProvider;
class MediaObserver;
+class NavigatorConnectContext;
+class NavigatorConnectServiceFactory;
+class PlatformNotificationService;
+class PresentationServiceDelegate;
class QuotaPermissionContext;
class RenderFrameHost;
class RenderProcessHost;
class RenderViewHost;
class ResourceContext;
+class ServiceRegistry;
class SiteInstance;
class SpeechRecognitionManagerDelegate;
-class VibrationProvider;
+class TracingDelegate;
class WebContents;
class WebContentsViewDelegate;
struct MainFunctionParams;
+struct OpenURLParams;
struct Referrer;
-struct ShowDesktopNotificationHostMsgParams;
struct WebPreferences;
// A mapping from the scheme name to the protocol handler that services its
@@ -137,6 +140,16 @@ class CONTENT_EXPORT ContentBrowserClient {
virtual BrowserMainParts* CreateBrowserMainParts(
const MainFunctionParams& parameters);
+ // Allows the embedder to change the default behavior of
+ // BrowserThread::PostAfterStartupTask to better match whatever
+ // definition of "startup" the embedder has in mind. This may be
+ // called on any thread.
+ // Note: see related BrowserThread::PostAfterStartupTask.
+ virtual void PostAfterStartupTask(
+ const tracked_objects::Location& from_here,
+ const scoped_refptr<base::TaskRunner>& task_runner,
+ const base::Closure& task);
+
// If content creates the WebContentsView implementation, it will ask the
// embedder to return an (optional) delegate to customize it. The view will
// own the delegate.
@@ -279,7 +292,9 @@ class CONTENT_EXPORT ContentBrowserClient {
// This is called on the IO thread.
virtual bool AllowServiceWorker(const GURL& scope,
const GURL& first_party,
- content::ResourceContext* context);
+ content::ResourceContext* context,
+ int render_process_id,
+ int render_frame_id);
// Allow the embedder to control if the given cookie can be read.
// This is called on the IO thread.
@@ -334,7 +349,7 @@ class CONTENT_EXPORT ContentBrowserClient {
const std::vector<std::pair<int, int> >& render_frames);
// Allow the embedder to override the request context based on the URL for
- // certain operations, like cookie access. Returns NULL to indicate the
+ // certain operations, like cookie access. Returns nullptr to indicate the
// regular request context should be used.
// This is called on the IO thread.
virtual net::URLRequestContext* OverrideRequestContextForURL(
@@ -396,18 +411,19 @@ class CONTENT_EXPORT ContentBrowserClient {
const base::Callback<void(bool)>& callback,
CertificateRequestResultType* result) {}
- // Selects a SSL client certificate and returns it to the |callback|. If no
- // certificate was selected NULL is returned to the |callback|.
+ // Selects a SSL client certificate and returns it to the |delegate|. Note:
+ // |delegate| may be called synchronously or asynchronously.
+ //
+ // TODO(davidben): Move this hook to WebContentsDelegate.
virtual void SelectClientCertificate(
- int render_process_id,
- int render_frame_id,
+ WebContents* web_contents,
net::SSLCertRequestInfo* cert_request_info,
- const base::Callback<void(net::X509Certificate*)>& callback);
+ scoped_ptr<ClientCertificateDelegate> delegate);
// Adds a new installable certificate or private key.
// Typically used to install an X.509 user certificate.
// Note that it's up to the embedder to verify that the data is
- // well-formed. |cert_data| will be NULL if |cert_size| is 0.
+ // well-formed. |cert_data| will be nullptr if |cert_size| is 0.
virtual void AddCertificate(net::CertificateMimeType cert_type,
const void* cert_data,
size_t cert_size,
@@ -415,43 +431,13 @@ class CONTENT_EXPORT ContentBrowserClient {
int render_frame_id) {}
// Returns a class to get notifications about media event. The embedder can
- // return NULL if they're not interested.
+ // return nullptr if they're not interested.
virtual MediaObserver* GetMediaObserver();
- // Checks if the given page has permission to show desktop notifications.
- // This is called on the IO thread.
- virtual blink::WebNotificationPermission
- CheckDesktopNotificationPermission(
- const GURL& source_url,
- ResourceContext* context,
- int render_process_id);
-
- // Show a desktop notification. If |cancel_callback| is non-null, it's set to
- // a callback which can be used to cancel the notification.
- virtual void ShowDesktopNotification(
- const ShowDesktopNotificationHostMsgParams& params,
- BrowserContext* browser_context,
- int render_process_id,
- scoped_ptr<DesktopNotificationDelegate> delegate,
- base::Closure* cancel_callback) {}
-
- virtual void RequestPermission(
- PermissionType permission,
- WebContents* web_contents,
- int bridge_id,
- const GURL& requesting_frame,
- bool user_gesture,
- const base::Callback<void(bool)>& result_callback);
-
- virtual void CancelPermissionRequest(PermissionType permission,
- WebContents* web_contents,
- int bridge_id,
- const GURL& requesting_frame) {}
-
- virtual void RegisterPermissionUsage(PermissionType permission,
- WebContents* web_contents,
- const GURL& frame_url,
- const GURL& main_frame_url) {}
+ // Returns the platform notification service, capable of displaying Web
+ // Notifications to the user. The embedder can return a nullptr if they don't
+ // support this functionality. May be called from any thread.
+ virtual PlatformNotificationService* GetPlatformNotificationService();
// Returns true if the given page is allowed to open a window of the given
// type. If true is returned, |no_javascript_access| will indicate whether
@@ -477,9 +463,9 @@ class CONTENT_EXPORT ContentBrowserClient {
virtual void ResourceDispatcherHostCreated() {}
// Allows the embedder to return a delegate for the SpeechRecognitionManager.
- // The delegate will be owned by the manager. It's valid to return NULL.
+ // The delegate will be owned by the manager. It's valid to return nullptr.
virtual SpeechRecognitionManagerDelegate*
- GetSpeechRecognitionManagerDelegate();
+ CreateSpeechRecognitionManagerDelegate();
// Getters for common objects.
virtual net::NetLog* GetNetLog();
@@ -494,7 +480,6 @@ class CONTENT_EXPORT ContentBrowserClient {
// the renderer. The content layer will add its own settings, and then it's up
// to the embedder to update it if it wants.
virtual void OverrideWebkitPrefs(RenderViewHost* render_view_host,
- const GURL& url,
WebPreferences* prefs) {}
// Notifies that BrowserURLHandler has been created, so that the embedder can
@@ -502,10 +487,10 @@ class CONTENT_EXPORT ContentBrowserClient {
virtual void BrowserURLHandlerCreated(BrowserURLHandler* handler) {}
// Clears browser cache.
- virtual void ClearCache(RenderViewHost* rvh) {}
+ virtual void ClearCache(RenderFrameHost* rfh) {}
// Clears browser cookies.
- virtual void ClearCookies(RenderViewHost* rvh) {}
+ virtual void ClearCookies(RenderFrameHost* rfh) {}
// Returns the default download directory.
// This can be called on any thread.
@@ -525,7 +510,7 @@ class CONTENT_EXPORT ContentBrowserClient {
int plugin_child_id);
// Returns true if the socket operation specified by |params| is allowed from
- // the given |browser_context| and |url|. If |params| is NULL, this method
+ // the given |browser_context| and |url|. If |params| is nullptr, this method
// checks the basic "socket" permission, which is for those operations that
// don't require a specific socket permission rule.
// |private_api| indicates whether this permission check is for the private
@@ -535,7 +520,7 @@ class CONTENT_EXPORT ContentBrowserClient {
bool private_api,
const SocketPermissionRequest* params);
- // Returns an implementation of a file selecition policy. Can return NULL.
+ // Returns an implementation of a file selecition policy. Can return nullptr.
virtual ui::SelectFilePolicy* CreateSelectFilePolicy(
WebContents* web_contents);
@@ -558,23 +543,20 @@ class CONTENT_EXPORT ContentBrowserClient {
ScopedVector<storage::FileSystemBackend>* additional_backends) {}
// Allows an embedder to return its own LocationProvider implementation.
- // Return NULL to use the default one for the platform to be created.
+ // Return nullptr to use the default one for the platform to be created.
// FYI: Used by an external project; please don't remove.
// Contact Viatcheslav Ostapenko at sl.ostapenko@samsung.com for more
// information.
virtual LocationProvider* OverrideSystemLocationProvider();
- // Allows an embedder to return its own VibrationProvider implementation.
- // Return NULL to use the default one for the platform to be created.
- // FYI: Used by an external project; please don't remove.
- // Contact Viatcheslav Ostapenko at sl.ostapenko@samsung.com for more
- // information.
- virtual VibrationProvider* OverrideVibrationProvider();
-
// Creates a new DevToolsManagerDelegate. The caller owns the returned value.
- // It's valid to return NULL.
+ // It's valid to return nullptr.
virtual DevToolsManagerDelegate* GetDevToolsManagerDelegate();
+ // Creates a new TracingDelegate. The caller owns the returned value.
+ // It's valid to return nullptr.
+ virtual TracingDelegate* GetTracingDelegate();
+
// Returns true if plugin referred to by the url can use
// pp::FileIO::RequestOSFileHandle.
virtual bool IsPluginAllowedToCallRequestOSFileHandle(
@@ -586,11 +568,41 @@ class CONTENT_EXPORT ContentBrowserClient {
BrowserContext* browser_context,
const GURL& url);
- // Returns a special cookie store to use for a given render process, or NULL
- // if the default cookie store should be used
- // This is called on the IO thread.
- virtual net::CookieStore* OverrideCookieStoreForRenderProcess(
- int render_process_id);
+ // Allows to override browser Mojo services exposed through the
+ // RenderProcessHost.
+ virtual void OverrideRenderProcessMojoServices(ServiceRegistry* registry) {}
+
+ // Allows to override browser Mojo services exposed through the
+ // RenderFrameHost.
+ virtual void OverrideRenderFrameMojoServices(
+ ServiceRegistry* registry,
+ RenderFrameHost* render_frame_host) {}
+
+ // Registers additional navigator.connect service factories available in a
+ // particular NavigatorConnectContext.
+ virtual void GetAdditionalNavigatorConnectServices(
+ const scoped_refptr<NavigatorConnectContext>& context) {}
+
+ // Allows to override the visibility state of a RenderFrameHost.
+ // |visibility_state| should not be null. It will only be set if needed.
+ virtual void OverridePageVisibilityState(
+ RenderFrameHost* render_frame_host,
+ blink::WebPageVisibilityState* visibility_state) {}
+
+ // Allows an embedder to provide its own PresentationServiceDelegate
+ // implementation. Returns nullptr if unavailable.
+ virtual PresentationServiceDelegate* GetPresentationServiceDelegate(
+ WebContents* web_contents);
+
+ // Allows programmatic opening of a new tab/window without going through
+ // another WebContents. For example, from a Worker. |callback| will be
+ // invoked with the appropriate WebContents* when available.
+ virtual void OpenURL(BrowserContext* browser_context,
+ const OpenURLParams& params,
+ const base::Callback<void(WebContents*)>& callback);
+
+ // Allows the embedder to record |metric| for a specific |url|.
+ virtual void RecordURLMetric(const std::string& metric, const GURL& url) {}
#if defined(OS_POSIX) && !defined(OS_MACOSX)
// Populates |mappings| with all files that need to be mapped before launching
@@ -614,17 +626,10 @@ class CONTENT_EXPORT ContentBrowserClient {
#if defined(VIDEO_HOLE)
// Allows an embedder to provide its own ExternalVideoSurfaceContainer
- // implementation. Return NULL to disable external surface video.
+ // implementation. Return nullptr to disable external surface video.
virtual ExternalVideoSurfaceContainer*
OverrideCreateExternalVideoSurfaceContainer(WebContents* web_contents);
#endif
-
-// Checks if |security_origin| has 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(BrowserContext* browser_context,
- const GURL& security_origin,
- MediaStreamType type);
};
} // namespace content
diff --git a/chromium/content/public/browser/cookie_crypto_delegate.h b/chromium/content/public/browser/cookie_crypto_delegate.h
deleted file mode 100644
index 92a9a6a35cf..00000000000
--- a/chromium/content/public/browser/cookie_crypto_delegate.h
+++ /dev/null
@@ -1,22 +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_PUBLIC_BROWSER_COOKIE_CRYPTO_DELEGATE_H_
-#define CONTENT_PUBLIC_BROWSER_COOKIE_CRYPTO_DELEGATE_H_
-
-namespace content {
-
-// Implements encryption and decryption for the persistent cookie store.
-class CookieCryptoDelegate {
- public:
- virtual ~CookieCryptoDelegate() {}
- virtual bool EncryptString(const std::string& plaintext,
- std::string* ciphertext) = 0;
- virtual bool DecryptString(const std::string& ciphertext,
- std::string* plaintext) = 0;
-};
-
-} // namespace content
-
-#endif // CONTENT_PUBLIC_BROWSER_COOKIE_CRYPTO_DELEGATE_H_
diff --git a/chromium/content/public/browser/cookie_store_factory.h b/chromium/content/public/browser/cookie_store_factory.h
index 03834bfb420..5b2bb7ac789 100644
--- a/chromium/content/public/browser/cookie_store_factory.h
+++ b/chromium/content/public/browser/cookie_store_factory.h
@@ -14,6 +14,7 @@ class SequencedTaskRunner;
}
namespace net {
+class CookieCryptoDelegate;
class CookieMonsterDelegate;
class CookieStore;
}
@@ -23,7 +24,6 @@ class SpecialStoragePolicy;
}
namespace content {
-class CookieCryptoDelegate;
struct CONTENT_EXPORT CookieStoreConfig {
// Specifies how session cookies are persisted in the backing data store.
@@ -52,7 +52,7 @@ struct CONTENT_EXPORT CookieStoreConfig {
// With in-memory cookie stores, |session_cookie_mode| must be
// EPHEMERAL_SESSION_COOKIES.
//
- // Note: If |crypto_delegate| is non-NULL, it must outlive any CookieStores
+ // Note: If |crypto_delegate| is non-nullptr, it must outlive any CookieStores
// created using this config.
CookieStoreConfig(const base::FilePath& path,
SessionCookieMode session_cookie_mode,
@@ -73,16 +73,16 @@ struct CONTENT_EXPORT CookieStoreConfig {
// Used to provide encryption hooks for the cookie store. The
// CookieCryptoDelegate must outlive any cookie store created with this
// config.
- content::CookieCryptoDelegate* crypto_delegate;
+ net::CookieCryptoDelegate* crypto_delegate;
// Callbacks for data load events will be performed on |client_task_runner|.
- // If NULL, uses the task runner for BrowserThread::IO.
+ // If nullptr, uses the task runner for BrowserThread::IO.
//
// Only used for persistent cookie stores.
scoped_refptr<base::SequencedTaskRunner> client_task_runner;
// All blocking database accesses will be performed on
- // |background_task_runner|. If NULL, uses a SequencedTaskRunner from the
+ // |background_task_runner|. If nullptr, uses a SequencedTaskRunner from the
// BrowserThread blocking pool.
//
// Only used for persistent cookie stores.
diff --git a/chromium/content/public/browser/desktop_media_id.cc b/chromium/content/public/browser/desktop_media_id.cc
index 9f5d4bb1e9e..7817766e4d3 100644
--- a/chromium/content/public/browser/desktop_media_id.cc
+++ b/chromium/content/public/browser/desktop_media_id.cc
@@ -46,7 +46,7 @@ class AuraWindowRegistry : public aura::WindowObserver {
aura::Window* GetWindowById(int id) {
std::map<int, aura::Window*>::iterator it = id_to_window_map_.find(id);
- return (it != id_to_window_map_.end()) ? it->second : NULL;
+ return (it != id_to_window_map_.end()) ? it->second : nullptr;
}
private:
diff --git a/chromium/content/public/browser/desktop_notification_delegate.h b/chromium/content/public/browser/desktop_notification_delegate.h
index aaf2c9d98d7..4803070985b 100644
--- a/chromium/content/public/browser/desktop_notification_delegate.h
+++ b/chromium/content/public/browser/desktop_notification_delegate.h
@@ -17,7 +17,7 @@ class DesktopNotificationDelegate {
virtual void NotificationDisplayed() = 0;
// The notification was closed.
- virtual void NotificationClosed(bool by_user) = 0;
+ virtual void NotificationClosed() = 0;
// The user clicked on the notification.
virtual void NotificationClick() = 0;
diff --git a/chromium/content/public/browser/devtools_agent_host.h b/chromium/content/public/browser/devtools_agent_host.h
index cc5d69caa57..12616c1a549 100644
--- a/chromium/content/public/browser/devtools_agent_host.h
+++ b/chromium/content/public/browser/devtools_agent_host.h
@@ -11,12 +11,19 @@
#include "base/basictypes.h"
#include "base/callback.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop_proxy.h"
#include "content/common/content_export.h"
#include "content/public/browser/devtools_agent_host_client.h"
#include "url/gurl.h"
+namespace net {
+class ServerSocket;
+}
+
namespace content {
+class BrowserContext;
class DevToolsExternalAgentProxyDelegate;
class WebContents;
@@ -28,6 +35,9 @@ class CONTENT_EXPORT DevToolsAgentHost
// Agent host associated with WebContents.
TYPE_WEB_CONTENTS,
+ // Agent host associated with RenderFrameHost.
+ TYPE_FRAME,
+
// Agent host associated with shared worker.
TYPE_SHARED_WORKER,
@@ -36,9 +46,18 @@ class CONTENT_EXPORT DevToolsAgentHost
// Agent host associated with DevToolsExternalAgentProxyDelegate.
TYPE_EXTERNAL,
+
+ // Agent host associated with browser.
+ TYPE_BROWSER,
};
- // Returns DevToolsAgentHost with a given |id| or NULL of it does not exist.
+ // Latest DevTools protocol version supported.
+ static std::string GetProtocolVersion();
+
+ // Returns whether particular version of DevTools protocol is supported.
+ static bool IsSupportedProtocolVersion(const std::string& version);
+
+ // Returns DevToolsAgentHost with a given |id| or nullptr of it doesn't exist.
static scoped_refptr<DevToolsAgentHost> GetForId(const std::string& id);
// Returns DevToolsAgentHost that can be used for inspecting |web_contents|.
@@ -61,6 +80,15 @@ class CONTENT_EXPORT DevToolsAgentHost
static scoped_refptr<DevToolsAgentHost> Create(
DevToolsExternalAgentProxyDelegate* delegate);
+ using CreateServerSocketCallback =
+ base::Callback<scoped_ptr<net::ServerSocket>(std::string*)>;
+
+ // Creates DevToolsAgentHost for the browser, which works with browser-wide
+ // debugging protocol.
+ static scoped_refptr<DevToolsAgentHost> CreateForBrowser(
+ scoped_refptr<base::MessageLoopProxy> tethering_message_loop,
+ const CreateServerSocketCallback& socket_callback);
+
static bool IsDebuggerAttached(WebContents* web_contents);
typedef std::vector<scoped_refptr<DevToolsAgentHost> > List;
@@ -77,8 +105,8 @@ class CONTENT_EXPORT DevToolsAgentHost
// Returns true if there is a client attached.
virtual bool IsAttached() = 0;
- // Sends a message to the agent.
- virtual void DispatchProtocolMessage(const std::string& message) = 0;
+ // Sends a message to the agent. Returns true if the message is handled.
+ virtual bool DispatchProtocolMessage(const std::string& message) = 0;
// Starts inspecting element at position (|x|, |y|) in the specified page.
virtual void InspectElement(int x, int y) = 0;
@@ -89,6 +117,9 @@ class CONTENT_EXPORT DevToolsAgentHost
// Returns web contents instance for this host if any.
virtual WebContents* GetWebContents() = 0;
+ // Returns related browser context instance if available.
+ virtual BrowserContext* GetBrowserContext() = 0;
+
// Temporarily detaches render view host from this host. Must be followed by
// a call to ConnectWebContents (may leak the host instance otherwise).
virtual void DisconnectWebContents() = 0;
@@ -96,9 +127,6 @@ class CONTENT_EXPORT DevToolsAgentHost
// Attaches render view host to this host.
virtual void ConnectWebContents(WebContents* web_contents) = 0;
- // Returns true if DevToolsAgentHost is for worker.
- virtual bool IsWorker() const = 0;
-
// Returns agent host type.
virtual Type GetType() = 0;
diff --git a/chromium/content/public/browser/devtools_frontend_host.h b/chromium/content/public/browser/devtools_frontend_host.h
index 24c50f51e07..05d6ab1836a 100644
--- a/chromium/content/public/browser/devtools_frontend_host.h
+++ b/chromium/content/public/browser/devtools_frontend_host.h
@@ -7,11 +7,12 @@
#include <string>
+#include "base/strings/string_piece.h"
#include "content/common/content_export.h"
namespace content {
-class RenderViewHost;
+class RenderFrameHost;
// This class dispatches messages between DevTools frontend and Delegate
// which is implemented by the embedder.
@@ -35,12 +36,20 @@ class DevToolsFrontendHost {
const std::string& message) = 0;
};
- // Creates a new DevToolsFrontendHost for RenderViewHost where DevTools
+ // Creates a new DevToolsFrontendHost for RenderFrameHost where DevTools
// frontend is loaded.
CONTENT_EXPORT static DevToolsFrontendHost* Create(
- RenderViewHost* frontend_rvh, Delegate* delegate);
+ RenderFrameHost* frontend_main_frame,
+ Delegate* delegate);
CONTENT_EXPORT virtual ~DevToolsFrontendHost() {}
+
+ CONTENT_EXPORT virtual void BadMessageRecieved() {}
+
+ // Returns bundled DevTools frontend resource by |path|. Returns empty string
+ // if |path| does not correspond to any frontend resource.
+ CONTENT_EXPORT static base::StringPiece GetFrontendResource(
+ const std::string& path);
};
} // namespace content
diff --git a/chromium/content/public/browser/devtools_http_handler.h b/chromium/content/public/browser/devtools_http_handler.h
deleted file mode 100644
index 2b656b64958..00000000000
--- a/chromium/content/public/browser/devtools_http_handler.h
+++ /dev/null
@@ -1,88 +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_PUBLIC_BROWSER_DEVTOOLS_HTTP_HANDLER_H_
-#define CONTENT_PUBLIC_BROWSER_DEVTOOLS_HTTP_HANDLER_H_
-
-#include <string>
-
-#include "base/files/file_path.h"
-#include "base/memory/scoped_ptr.h"
-#include "content/common/content_export.h"
-
-class GURL;
-
-namespace net {
-class ServerSocket;
-class URLRequestContextGetter;
-}
-
-namespace content {
-
-class DevToolsHttpHandlerDelegate;
-
-// This class is used for managing DevTools remote debugging server.
-// Clients can connect to the specified ip:port and start debugging
-// this browser.
-class DevToolsHttpHandler {
- public:
-
- // Factory of net::ServerSocket. This is to separate instantiating dev tools
- // and instantiating server socket.
- class CONTENT_EXPORT ServerSocketFactory {
- public:
- ServerSocketFactory(const std::string& address, int port, int backlog);
- virtual ~ServerSocketFactory();
-
- // Returns a new instance of ServerSocket or NULL if an error occurred.
- // It calls ServerSocket::ListenWithAddressAndPort() with address, port and
- // backlog passed to constructor.
- virtual scoped_ptr<net::ServerSocket> CreateAndListen() const;
-
- protected:
- // Creates a server socket. ServerSocket::Listen() will be called soon
- // unless it returns NULL.
- virtual scoped_ptr<net::ServerSocket> Create() const = 0;
-
- const std::string address_;
- const int port_;
- const int backlog_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ServerSocketFactory);
- };
-
- // Returns true if the given protocol version is supported.
- CONTENT_EXPORT static bool IsSupportedProtocolVersion(
- const std::string& version);
-
- // Returns frontend resource id for the given resource |name|.
- CONTENT_EXPORT static int GetFrontendResourceId(
- const std::string& name);
-
- // Takes ownership over |socket_factory| and |delegate|.
- // If |active_port_output_directory| is non-empty, it is assumed the
- // socket_factory was initialized with an ephemeral port (0). The
- // port selected by the OS will be written to a well-known file in
- // the output directory.
- CONTENT_EXPORT static DevToolsHttpHandler* Start(
- scoped_ptr<ServerSocketFactory> server_socket_factory,
- const std::string& frontend_url,
- DevToolsHttpHandlerDelegate* delegate,
- const base::FilePath& active_port_output_directory);
-
- // Called from the main thread in order to stop protocol handler.
- // Automatically destroys the handler instance.
- virtual void Stop() = 0;
-
- // Returns the URL for the address to debug |agent_host|.
- virtual GURL GetFrontendURL() = 0;
-
- protected:
- virtual ~DevToolsHttpHandler() {}
-};
-
-} // namespace content
-
-#endif // CONTENT_PUBLIC_BROWSER_DEVTOOLS_HTTP_HANDLER_H_
diff --git a/chromium/content/public/browser/devtools_http_handler_delegate.h b/chromium/content/public/browser/devtools_http_handler_delegate.h
deleted file mode 100644
index 514b273f5ae..00000000000
--- a/chromium/content/public/browser/devtools_http_handler_delegate.h
+++ /dev/null
@@ -1,42 +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_PUBLIC_BROWSER_DEVTOOLS_HTTP_HANDLER_DELEGATE_H_
-#define CONTENT_PUBLIC_BROWSER_DEVTOOLS_HTTP_HANDLER_DELEGATE_H_
-
-#include <string>
-#include <vector>
-
-#include "base/files/file_path.h"
-#include "base/memory/scoped_ptr.h"
-#include "net/socket/stream_listen_socket.h"
-
-namespace content {
-
-class DevToolsTarget;
-
-class DevToolsHttpHandlerDelegate {
- public:
- virtual ~DevToolsHttpHandlerDelegate() {}
-
- // Should return discovery page HTML that should list available tabs
- // and provide attach links.
- virtual std::string GetDiscoveryPageHTML() = 0;
-
- // Returns true if and only if frontend resources are bundled.
- virtual bool BundlesFrontendResources() = 0;
-
- // Returns path to the front-end files on the local filesystem for debugging.
- virtual base::FilePath GetDebugFrontendDir() = 0;
-
- // Creates named socket for reversed tethering implementation (used with
- // remote debugging, primarily for mobile).
- virtual scoped_ptr<net::StreamListenSocket> CreateSocketForTethering(
- net::StreamListenSocket::Delegate* delegate,
- std::string* name) = 0;
-};
-
-} // namespace content
-
-#endif // CONTENT_PUBLIC_BROWSER_DEVTOOLS_HTTP_HANDLER_DELEGATE_H_
diff --git a/chromium/content/public/browser/devtools_manager_delegate.h b/chromium/content/public/browser/devtools_manager_delegate.h
index 5ebd854b108..d34e7af3957 100644
--- a/chromium/content/public/browser/devtools_manager_delegate.h
+++ b/chromium/content/public/browser/devtools_manager_delegate.h
@@ -5,22 +5,14 @@
#ifndef CONTENT_PUBLIC_BROWSER_DEVTOOLS_MANAGER_DELEGATE_H_
#define CONTENT_PUBLIC_BROWSER_DEVTOOLS_MANAGER_DELEGATE_H_
-#include <string>
-#include <vector>
-
-#include "base/callback.h"
-
namespace base {
class DictionaryValue;
}
-class GURL;
-
namespace content {
class BrowserContext;
class DevToolsAgentHost;
-class DevToolsTarget;
class DevToolsManagerDelegate {
public:
@@ -37,20 +29,6 @@ class DevToolsManagerDelegate {
virtual base::DictionaryValue* HandleCommand(
DevToolsAgentHost* agent_host,
base::DictionaryValue* command) = 0;
-
- // Creates new inspectable target.
- virtual scoped_ptr<DevToolsTarget> CreateNewTarget(const GURL& url) = 0;
-
- typedef std::vector<DevToolsTarget*> TargetList;
- typedef base::Callback<void(const TargetList&)> TargetCallback;
-
- // Requests the list of all inspectable targets.
- // The caller gets the ownership of the returned targets.
- virtual void EnumerateTargets(TargetCallback callback) = 0;
-
- // Get a thumbnail for a given page. Returns non-empty string iff we have the
- // thumbnail.
- virtual std::string GetPageThumbnailData(const GURL& url) = 0;
};
} // namespace content
diff --git a/chromium/content/public/browser/devtools_protocol_constants_generator.py b/chromium/content/public/browser/devtools_protocol_constants_generator.py
deleted file mode 100755
index 3447fb1dfbf..00000000000
--- a/chromium/content/public/browser/devtools_protocol_constants_generator.py
+++ /dev/null
@@ -1,211 +0,0 @@
-#!/usr/bin/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
-
-package = sys.argv[1]
-output_cc_path = sys.argv[2]
-output_h_path = sys.argv[3]
-blink_protocol_path = sys.argv[4]
-browser_protocol_path = sys.argv[5] if len(sys.argv) > 5 else None
-
-template_h = string.Template("""\
-// 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 ${PACKAGE}_BROWSER_DEVTOOLS_DEVTOOLS_PROTOCOL_CONSTANTS_H_
-#define ${PACKAGE}_BROWSER_DEVTOOLS_DEVTOOLS_PROTOCOL_CONSTANTS_H_
-
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// Generated by
-// content/public/browser/devtools_protocol_constants_generator.py from
-// third_party/WebKit/Source/devtools/protocol.json and
-// content/browser/devtools/browser_protocol.json
-
-#include <string>
-
-namespace $package {
-namespace devtools {
-
-extern const char kProtocolVersion[];
-
-bool IsSupportedProtocolVersion(const std::string& version);
-
-extern const char kResult[];
-$contents
-
-} // devtools
-} // $package
-
-#endif // ${PACKAGE}_BROWSER_DEVTOOLS_DEVTOOLS_PROTOCOL_CONSTANTS_H_
-""")
-
-template_cc = string.Template("""\
-// 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 IS AUTOGENERATED. DO NOT EDIT.
-// Generated by
-// content/public/browser/devtools_protocol_constants_generator.py from
-// third_party/WebKit/Source/devtools/protocol.json and
-// content/browser/devtools/browser_protocol.json
-
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "$package/browser/devtools/devtools_protocol_constants.h"
-
-namespace $package {
-namespace devtools {
-
-const char kProtocolVersion[] = "$major.$minor";
-
-bool IsSupportedProtocolVersion(const std::string& version) {
- std::vector<std::string> tokens;
- Tokenize(version, ".", &tokens);
- int major, minor;
- return tokens.size() == 2 &&
- base::StringToInt(tokens[0], &major) && major == $major &&
- base::StringToInt(tokens[1], &minor) && minor <= $minor;
-}
-
-const char kResult[] = "result";
-$contents
-
-} // devtools
-} // $package
-""")
-
-def Capitalize(s):
- return s[:1].capitalize() + s[1:]
-
-references = []
-
-def CreateNamespace(domain_name, data, keys, prefixes, name = None):
- result = {}
- if name:
- result["kName"] = name
- for i, key in enumerate(keys):
- if key in data:
- for parameter in data[key]:
- parameter_name = parameter["name"];
- result[prefixes[i] + Capitalize(parameter_name)] = parameter_name
- if "enum" in parameter:
- enum_name = Capitalize(parameter_name)
- result[enum_name] = {}
- for enum in parameter["enum"]:
- result[enum_name]["kEnum" + Capitalize(enum)] = enum
- reference = ""
- if "$ref" in parameter:
- reference = parameter["$ref"]
- if "items" in parameter and "$ref" in parameter["items"]:
- reference = parameter["items"]["$ref"]
- if reference:
- if not "." in reference:
- reference = domain_name + "." + reference
- references.append(reference)
- return result
-
-def IsHandledInBrowser(item):
- return "handlers" in item and "browser" in item["handlers"]
-
-def FormatContents(tree, indent, format_string):
- outer = dict((key, value) for key, value in tree.iteritems()
- if not isinstance(value, dict))
- inner = dict((key, value) for key, value in tree.iteritems()
- if isinstance(value, dict))
- body = ""
- body += "".join(indent + format_string.format(key, value)
- for (key, value) in sorted(outer.items()))
- body += "".join(FormatNamespace(key, value, indent, format_string)
- for (key, value) in sorted(inner.items()))
- return body
-
-def FormatNamespace(title, tree, indent, format_string):
- if (not tree):
- return ""
- body = '\n' + indent + "namespace " + title + " {\n"
- body += FormatContents(tree, indent + " ", format_string)
- body += indent + "} // " + title + "\n"
- return body
-
-def CreateHeader(tree, output_file):
- contents = FormatContents(tree, "", "extern const char {0}[];\n")
- output_file.write(template_h.substitute({
- "contents": contents,
- "package": package,
- "PACKAGE": package.upper()
- }))
-
-def CreateBody(tree, version, output_file):
- contents = FormatContents(tree, "", "const char {0}[] = \"{1}\";\n")
- output_file.write(template_cc.substitute({
- "major": version["major"],
- "minor": version["minor"],
- "contents": contents,
- "package": package
- }))
-
-blink_protocol_data = open(blink_protocol_path).read()
-blink_protocol = json.loads(blink_protocol_data)
-blink_version = blink_protocol["version"]
-
-domains = blink_protocol["domains"]
-
-if browser_protocol_path:
- browser_protocol_data = open(browser_protocol_path).read()
- browser_protocol = json.loads(browser_protocol_data)
- domains = domains + browser_protocol["domains"]
-
-namespace_tree = {}
-
-for domain in domains:
- domain_value = {}
- domain_namespace_name = Capitalize(domain["domain"])
- if "commands" in domain:
- for command in domain["commands"]:
- if (IsHandledInBrowser(command)):
- domain_value[command["name"]] = CreateNamespace(domain["domain"],
- command, ["parameters", "returns"], ["kParam", "kResponse"],
- domain_namespace_name + "." + command["name"])
-
- if "events" in domain:
- for event in domain["events"]:
- if IsHandledInBrowser(event):
- domain_value[event["name"]] = CreateNamespace(domain["domain"],
- event, ["parameters"], ["kParam"],
- domain_namespace_name + "." + event["name"])
- if domain_value:
- namespace_tree[domain_namespace_name] = domain_value
-
-while (references):
- reference = references.pop();
- path = reference.split(".");
- parent_namespace = namespace_tree;
- for path_segment in path[0:-1]:
- if path_segment not in parent_namespace:
- parent_namespace[path_segment] = {}
- parent_namespace = parent_namespace[path_segment]
- if (path[-1] not in parent_namespace):
- try:
- domain = [d for d in domains if d["domain"] == path[0]][0]
- ref_type = [t for t in domain["types"] if t["id"] == path[1]][0]
- parent_namespace[ref_type["id"]] = CreateNamespace(path[0],
- ref_type, ["properties"], ["kParam"])
- except IndexError:
- sys.stderr.write("Failed to resolve type [{0}].\n".format(reference))
- sys.exit(1)
-
-for (namespace_name, namespace) in namespace_tree.items():
- namespace["kName"] = namespace_name
-
-with open(output_cc_path, "w") as f:
- CreateBody(namespace_tree, blink_version, f)
-
-with open(output_h_path, "w") as f:
- CreateHeader(namespace_tree, f)
diff --git a/chromium/content/public/browser/devtools_target.h b/chromium/content/public/browser/devtools_target.h
deleted file mode 100644
index 80085350ae1..00000000000
--- a/chromium/content/public/browser/devtools_target.h
+++ /dev/null
@@ -1,67 +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_PUBLIC_BROWSER_DEVTOOLS_TARGET_H_
-#define CONTENT_PUBLIC_BROWSER_DEVTOOLS_TARGET_H_
-
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/memory/ref_counted.h"
-#include "base/time/time.h"
-#include "content/common/content_export.h"
-#include "url/gurl.h"
-
-namespace content {
-
-class DevToolsAgentHost;
-
-// DevToolsTarget represents an inspectable target and can be used to
-// manipulate the target and query its details.
-// Instantiation and discovery of DevToolsTarget instances is the responsibility
-// of DevToolsHttpHandlerDelegate.
-class DevToolsTarget {
- public:
- virtual ~DevToolsTarget() {}
-
- // Returns the unique target id.
- virtual std::string GetId() const = 0;
-
- // Returns the id of the parent target, or empty string if no parent.
- virtual std::string GetParentId() const = 0;
-
- // Returns the target type.
- virtual std::string GetType() const = 0;
-
- // Returns the target title.
- virtual std::string GetTitle() const = 0;
-
- // Returns the target description.
- virtual std::string GetDescription() const = 0;
-
- // Returns the url associated with this target.
- virtual GURL GetURL() const = 0;
-
- // Returns the favicon url for this target.
- virtual GURL GetFaviconURL() const = 0;
-
- // Returns the time when the target was last active.
- virtual base::TimeTicks GetLastActivityTime() const = 0;
-
- // Returns true if the debugger is attached to the target.
- virtual bool IsAttached() const = 0;
-
- // Returns the agent host for this target.
- virtual scoped_refptr<DevToolsAgentHost> GetAgentHost() const = 0;
-
- // Activates the target. Returns false if the operation failed.
- virtual bool Activate() const = 0;
-
- // Closes the target. Returns false if the operation failed.
- virtual bool Close() const = 0;
-};
-
-} // namespace content
-
-#endif // CONTENT_PUBLIC_BROWSER_DEVTOOLS_TARGET_H_
diff --git a/chromium/content/public/browser/download_manager.h b/chromium/content/public/browser/download_manager.h
index d51ebe9b294..74cb77d6d4d 100644
--- a/chromium/content/public/browser/download_manager.h
+++ b/chromium/content/public/browser/download_manager.h
@@ -40,7 +40,7 @@
#include "content/public/browser/download_item.h"
#include "content/public/browser/download_url_parameters.h"
#include "net/base/net_errors.h"
-#include "net/base/net_log.h"
+#include "net/log/net_log.h"
class GURL;
diff --git a/chromium/content/public/browser/download_url_parameters.cc b/chromium/content/public/browser/download_url_parameters.cc
index d604a4dae82..e7c632885af 100644
--- a/chromium/content/public/browser/download_url_parameters.cc
+++ b/chromium/content/public/browser/download_url_parameters.cc
@@ -20,14 +20,14 @@ DownloadUrlParameters::DownloadUrlParameters(
int render_view_host_routing_id,
ResourceContext* resource_context)
: content_initiated_(false),
- load_flags_(0),
method_("GET"),
post_id_(-1),
prefer_cache_(false),
render_process_host_id_(render_process_host_id),
render_view_host_routing_id_(render_view_host_routing_id),
resource_context_(resource_context),
- url_(url) {
+ url_(url),
+ do_not_prompt_for_login_(false) {
}
DownloadUrlParameters::~DownloadUrlParameters() {
diff --git a/chromium/content/public/browser/download_url_parameters.h b/chromium/content/public/browser/download_url_parameters.h
index fbf298410e1..bc5dfd356fd 100644
--- a/chromium/content/public/browser/download_url_parameters.h
+++ b/chromium/content/public/browser/download_url_parameters.h
@@ -38,7 +38,7 @@ class WebContents;
class CONTENT_EXPORT DownloadUrlParameters {
public:
- // If there is an error, then |item| will be NULL.
+ // If there is an error, then |item| will be nullptr.
typedef base::Callback<void(DownloadItem*, DownloadInterruptReason)>
OnStartedCallback;
@@ -67,7 +67,6 @@ class CONTENT_EXPORT DownloadUrlParameters {
void set_referrer_encoding(const std::string& referrer_encoding) {
referrer_encoding_ = referrer_encoding;
}
- void set_load_flags(int load_flags) { load_flags_ |= load_flags; }
void set_last_modified(const std::string& last_modified) {
last_modified_ = last_modified;
}
@@ -101,10 +100,12 @@ class CONTENT_EXPORT DownloadUrlParameters {
void set_file(base::File file) {
save_info_.file = file.Pass();
}
+ void set_do_not_prompt_for_login(bool do_not_prompt) {
+ do_not_prompt_for_login_ = do_not_prompt;
+ }
const OnStartedCallback& callback() const { return callback_; }
bool content_initiated() const { return content_initiated_; }
- int load_flags() const { return load_flags_; }
const std::string& last_modified() const { return last_modified_; }
const std::string& etag() const { return etag_; }
const std::string& method() const { return method_; }
@@ -134,6 +135,7 @@ class CONTENT_EXPORT DownloadUrlParameters {
const std::string& hash_state() const { return save_info_.hash_state; }
bool prompt() const { return save_info_.prompt_for_save_location; }
const GURL& url() const { return url_; }
+ bool do_not_prompt_for_login() const { return do_not_prompt_for_login_; }
// Note that this is state changing--the DownloadUrlParameters object
// will not have a file attached to it after this call.
@@ -143,7 +145,6 @@ class CONTENT_EXPORT DownloadUrlParameters {
OnStartedCallback callback_;
bool content_initiated_;
RequestHeadersType request_headers_;
- int load_flags_;
std::string last_modified_;
std::string etag_;
std::string method_;
@@ -157,6 +158,7 @@ class CONTENT_EXPORT DownloadUrlParameters {
ResourceContext* resource_context_;
DownloadSaveInfo save_info_;
GURL url_;
+ bool do_not_prompt_for_login_;
DISALLOW_COPY_AND_ASSIGN(DownloadUrlParameters);
};
diff --git a/chromium/content/public/browser/file_descriptor_info.h b/chromium/content/public/browser/file_descriptor_info.h
index b0b2bdad7dc..76c546e40b2 100644
--- a/chromium/content/public/browser/file_descriptor_info.h
+++ b/chromium/content/public/browser/file_descriptor_info.h
@@ -41,6 +41,11 @@ class FileDescriptorInfo {
virtual base::PlatformFile GetFDAt(size_t i) const = 0;
virtual int GetIDAt(size_t i) const = 0;
virtual size_t GetMappingSize() const = 0;
+
+ // True if |this| has an ownership of |file|.
+ virtual bool OwnsFD(base::PlatformFile file) const = 0;
+ // Assuming |OwnsFD(file)|, release the ownership.
+ virtual base::ScopedFD ReleaseFD(base::PlatformFile file) = 0;
};
}
diff --git a/chromium/content/public/browser/focused_node_details.h b/chromium/content/public/browser/focused_node_details.h
new file mode 100644
index 00000000000..6870bc4943b
--- /dev/null
+++ b/chromium/content/public/browser/focused_node_details.h
@@ -0,0 +1,19 @@
+// Copyright 2014 The Chromium Authors. 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_FOCUSED_NODE_DETAILS_H_
+#define CONTENT_PUBLIC_BROWSER_FOCUSED_NODE_DETAILS_H_
+
+#include "ui/gfx/geometry/rect.h"
+
+namespace content {
+
+struct FocusedNodeDetails {
+ bool is_editable_node;
+ gfx::Rect node_bounds_in_screen;
+};
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_BROWSER_FOCUSED_NODE_DETAILS_H_
diff --git a/chromium/content/public/browser/gpu_data_manager.h b/chromium/content/public/browser/gpu_data_manager.h
index a29575f762c..4991a4e6fdf 100644
--- a/chromium/content/public/browser/gpu_data_manager.h
+++ b/chromium/content/public/browser/gpu_data_manager.h
@@ -53,7 +53,7 @@ class GpuDataManager {
// process, establish GPU channel, and GPU info collection, should be
// blocked.
// Can be called on any thread.
- // If |reason| is not NULL and GPU access is blocked, upon return, |reason|
+ // If |reason| is not nullptr and GPU access is blocked, upon return, |reason|
// contains a description of the reason why GPU access is blocked.
virtual bool GpuAccessAllowed(std::string* reason) const = 0;
@@ -110,6 +110,10 @@ class GpuDataManager {
// Whether the browser compositor can be used.
virtual bool CanUseGpuBrowserCompositor() const = 0;
+ // Extensions that are currently disabled.
+ virtual void GetDisabledExtensions(
+ std::string* disabled_extensions) const = 0;
+
protected:
virtual ~GpuDataManager() {}
};
diff --git a/chromium/content/public/browser/guest_host.h b/chromium/content/public/browser/guest_host.h
new file mode 100644
index 00000000000..c955e4616c9
--- /dev/null
+++ b/chromium/content/public/browser/guest_host.h
@@ -0,0 +1,37 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_PUBLIC_BROWSER_GUEST_HOST_H_
+#define CONTENT_PUBLIC_BROWSER_GUEST_HOST_H_
+
+#include "ui/gfx/geometry/size.h"
+
+namespace content {
+
+// A GuestHost is the content API for a guest WebContents.
+// Guests are top-level frames that can be embedded within other pages.
+// The content module manages routing of input events and compositing, but all
+// other operations are managed outside of content. To limit exposure of
+// implementation details within content, content embedders must use this
+// interface for loading, sizing, and cleanup of guests.
+//
+// This class currently only serves as a base class for BrowserPluginGuest, and
+// its API can only be accessed by a BrowserPluginGuestDelegate.
+class GuestHost {
+ public:
+ // Loads a URL using the specified |load_params| and returns a routing ID for
+ // a proxy for the guest.
+ virtual int LoadURLWithParams(
+ const NavigationController::LoadURLParams& load_params) = 0;
+
+ // Sets the size of the guest WebContents.
+ virtual void SizeContents(const gfx::Size& new_size) = 0;
+
+ // Called when the GuestHost is about to be destroyed.
+ virtual void WillDestroy() = 0;
+};
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_BROWSER_GUEST_HOST_H_
diff --git a/chromium/content/public/browser/host_zoom_map.h b/chromium/content/public/browser/host_zoom_map.h
index e9e523e29f4..a4aca1d232f 100644
--- a/chromium/content/public/browser/host_zoom_map.h
+++ b/chromium/content/public/browser/host_zoom_map.h
@@ -20,6 +20,7 @@ namespace content {
class NavigationEntry;
class BrowserContext;
class ResourceContext;
+class SiteInstance;
class WebContents;
// Maps hostnames to custom zoom levels. Written on the UI thread and read on
@@ -36,11 +37,13 @@ class HostZoomMap {
public:
// Enum that indicates what was the scope of zoom level change.
enum ZoomLevelChangeMode {
- ZOOM_CHANGED_FOR_HOST, // Zoom level changed for host.
- ZOOM_CHANGED_FOR_SCHEME_AND_HOST, // Zoom level changed for scheme/host
- // pair.
- ZOOM_CHANGED_TEMPORARY_ZOOM, // Temporary zoom change for specific
- // renderer, no scheme/host is specified.
+ ZOOM_CHANGED_FOR_HOST, // Zoom level changed for host.
+ ZOOM_CHANGED_FOR_SCHEME_AND_HOST, // Zoom level changed for scheme/host
+ // pair.
+ ZOOM_CHANGED_TEMPORARY_ZOOM, // Temporary zoom change for specific
+ // renderer, no scheme/host is specified.
+ PAGE_SCALE_IS_ONE_CHANGED, // Page scale factor equal to one changed
+ // for a host.
};
// Structure used to notify about zoom changes. Host and/or scheme are empty
@@ -61,10 +64,25 @@ class HostZoomMap {
CONTENT_EXPORT static HostZoomMap* GetDefaultForBrowserContext(
BrowserContext* browser_context);
+ // Returns the HostZoomMap associated with this SiteInstance. The SiteInstance
+ // may serve multiple WebContents, and the HostZoomMap is the same for all of
+ // these WebContents.
+ CONTENT_EXPORT static HostZoomMap* Get(SiteInstance* instance);
+
+ // Returns the HostZoomMap associated with this WebContent's main frame. If
+ // multiple WebContents share the same SiteInstance, then they share a single
+ // HostZoomMap.
+ CONTENT_EXPORT static HostZoomMap* GetForWebContents(
+ const WebContents* contents);
+
// Returns the current zoom level for the specified WebContents. May be
// temporary or host-specific.
CONTENT_EXPORT static double GetZoomLevel(const WebContents* web_contents);
+ // Returns true if the page scale factor for the WebContents is one.
+ CONTENT_EXPORT static bool PageScaleFactorIsOne(
+ const WebContents* web_contents);
+
// Sets the current zoom level for the specified WebContents. The level may
// be temporary or host-specific depending on the particular WebContents.
CONTENT_EXPORT static void SetZoomLevel(const WebContents* web_contents,
@@ -75,6 +93,12 @@ class HostZoomMap {
CONTENT_EXPORT static void SendErrorPageZoomLevelRefresh(
const WebContents* web_contents);
+ // Set or clear whether or not the page scale factor for a view is one.
+ virtual void SetPageScaleFactorIsOneForView(
+ int render_process_id, int render_view_id, bool is_one) = 0;
+ virtual void ClearPageScaleFactorIsOneForView(
+ int render_process_id, int render_view_id) = 0;
+
// Copy the zoom levels from the given map. Can only be called on the UI
// thread.
virtual void CopyFrom(HostZoomMap* copy) = 0;
diff --git a/chromium/content/public/browser/indexed_db_context.h b/chromium/content/public/browser/indexed_db_context.h
index af469e33027..136c30c3a25 100644
--- a/chromium/content/public/browser/indexed_db_context.h
+++ b/chromium/content/public/browser/indexed_db_context.h
@@ -34,6 +34,11 @@ class IndexedDBContext : public base::RefCountedThreadSafe<IndexedDBContext> {
// Deletes all indexed db files for the given origin.
virtual void DeleteForOrigin(const GURL& origin_url) = 0;
+ // Copies the indexed db files from this context to another. The
+ // indexed db directory in the destination context needs to be empty.
+ virtual void CopyOriginData(const GURL& origin_url,
+ IndexedDBContext* dest_context) = 0;
+
// Get the file name of the local storage file for the given origin.
virtual base::FilePath GetFilePathForTesting(
const std::string& origin_id) const = 0;
diff --git a/chromium/content/public/browser/indexed_db_info.cc b/chromium/content/public/browser/indexed_db_info.cc
index ae7446c5cf6..01e26a2c770 100644
--- a/chromium/content/public/browser/indexed_db_info.cc
+++ b/chromium/content/public/browser/indexed_db_info.cc
@@ -9,12 +9,14 @@ namespace content {
IndexedDBInfo::IndexedDBInfo(const GURL& origin,
int64 size,
const base::Time& last_modified,
- const base::FilePath& path,
size_t connection_count)
: origin_(origin),
size_(size),
last_modified_(last_modified),
- path_(path),
connection_count_(connection_count) {}
+IndexedDBInfo::IndexedDBInfo(const IndexedDBInfo& other) = default;
+IndexedDBInfo::~IndexedDBInfo() = default;
+IndexedDBInfo& IndexedDBInfo::operator=(const IndexedDBInfo& other) = default;
+
} // namespace content
diff --git a/chromium/content/public/browser/indexed_db_info.h b/chromium/content/public/browser/indexed_db_info.h
index fcf6c0417e5..8a2ee7c8815 100644
--- a/chromium/content/public/browser/indexed_db_info.h
+++ b/chromium/content/public/browser/indexed_db_info.h
@@ -17,13 +17,14 @@ class CONTENT_EXPORT IndexedDBInfo {
IndexedDBInfo(const GURL& origin,
int64 size,
const base::Time& last_modified,
- const base::FilePath& path,
- size_t connection_count_);
+ size_t connection_count);
+ IndexedDBInfo(const IndexedDBInfo& other);
+ ~IndexedDBInfo();
+ IndexedDBInfo& operator=(const IndexedDBInfo& other);
GURL origin_;
int64 size_;
base::Time last_modified_;
- base::FilePath path_;
size_t connection_count_;
};
diff --git a/chromium/content/public/browser/interstitial_page.h b/chromium/content/public/browser/interstitial_page.h
index 368458a13e5..71b8707e54d 100644
--- a/chromium/content/public/browser/interstitial_page.h
+++ b/chromium/content/public/browser/interstitial_page.h
@@ -16,7 +16,7 @@ class Size;
namespace content {
class InterstitialPageDelegate;
-class RenderViewHost;
+class RenderFrameHost;
class WebContents;
// This class is used for showing interstitial pages, pages that show some
@@ -79,7 +79,10 @@ class InterstitialPage {
// Sets the focus to the interstitial.
virtual void Focus() = 0;
- virtual RenderViewHost* GetRenderViewHostForTesting() const = 0;
+ // Gets the RenderFrameHost associated with
+ // the interstitial page's main frame.
+ virtual RenderFrameHost* GetMainFrame() const = 0;
+
virtual InterstitialPageDelegate* GetDelegateForTesting() = 0;
virtual void DontCreateViewForTesting() = 0;
};
diff --git a/chromium/content/public/browser/interstitial_page_delegate.cc b/chromium/content/public/browser/interstitial_page_delegate.cc
new file mode 100644
index 00000000000..60a441842b4
--- /dev/null
+++ b/chromium/content/public/browser/interstitial_page_delegate.cc
@@ -0,0 +1,13 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/public/browser/interstitial_page_delegate.h"
+
+namespace content {
+InterstitialPageDelegate::TypeID InterstitialPageDelegate::GetTypeForTesting()
+ const {
+ return nullptr;
+}
+
+} // namespace content
diff --git a/chromium/content/public/browser/interstitial_page_delegate.h b/chromium/content/public/browser/interstitial_page_delegate.h
index 74e4c4ccaad..d64879c2549 100644
--- a/chromium/content/public/browser/interstitial_page_delegate.h
+++ b/chromium/content/public/browser/interstitial_page_delegate.h
@@ -16,8 +16,11 @@ struct RendererPreferences;
// Controls and provides the html for an interstitial page. The delegate is
// owned by the InterstitialPage.
-class InterstitialPageDelegate {
+class CONTENT_EXPORT InterstitialPageDelegate {
public:
+ // An identifier used to identify an InterstitialPage.
+ typedef const void* TypeID;
+
virtual ~InterstitialPageDelegate() {}
// Return the HTML that should be displayed in the page.
@@ -42,6 +45,9 @@ class InterstitialPageDelegate {
// Allows the delegate to override the renderer preferences structure that's
// sent to the new RenderViewHost.
virtual void OverrideRendererPrefs(content::RendererPreferences* prefs) {}
+
+ // Return the interstitial type for testing.
+ virtual TypeID GetTypeForTesting() const;
};
} // namespace content
diff --git a/chromium/content/public/browser/invalidate_type.h b/chromium/content/public/browser/invalidate_type.h
index 975bb304cf1..f85ec3da0af 100644
--- a/chromium/content/public/browser/invalidate_type.h
+++ b/chromium/content/public/browser/invalidate_type.h
@@ -9,6 +9,11 @@ namespace content {
// Flags passed to the WebContentsDelegate.NavigationStateChanged to tell it
// what has changed. Combine them to update more than one thing.
+//
+// A Java counterpart will be generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: (
+// org.chromium.content_public.browser)
+// GENERATED_JAVA_PREFIX_TO_STRIP: INVALIDATE_TYPE_
enum InvalidateTypes {
INVALIDATE_TYPE_URL = 1 << 0, // The URL has changed.
INVALIDATE_TYPE_TAB = 1 << 1, // The favicon, app icon, or crashed
diff --git a/chromium/content/public/browser/javascript_dialog_manager.h b/chromium/content/public/browser/javascript_dialog_manager.h
index cdc628b5bc5..114418cf51a 100644
--- a/chromium/content/public/browser/javascript_dialog_manager.h
+++ b/chromium/content/public/browser/javascript_dialog_manager.h
@@ -55,9 +55,8 @@ class CONTENT_EXPORT JavaScriptDialogManager {
// Cancels all active and pending dialogs for the given WebContents.
virtual void CancelActiveAndPendingDialogs(WebContents* web_contents) = 0;
- // The given WebContents is being destroyed; discards any saved state tied
- // to it.
- virtual void WebContentsDestroyed(WebContents* web_contents) = 0;
+ // Reset any saved state tied to the given WebContents.
+ virtual void ResetDialogState(WebContents* web_contents) = 0;
virtual ~JavaScriptDialogManager() {}
};
diff --git a/chromium/content/public/browser/message_port_delegate.h b/chromium/content/public/browser/message_port_delegate.h
new file mode 100644
index 00000000000..7c2de5bbde6
--- /dev/null
+++ b/chromium/content/public/browser/message_port_delegate.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_PUBLIC_BROWSER_MESSAGE_PORT_DELEGATE_H_
+#define CONTENT_PUBLIC_BROWSER_MESSAGE_PORT_DELEGATE_H_
+
+#include <vector>
+
+#include "base/strings/string16.h"
+#include "content/common/content_export.h"
+
+// Windows headers will redefine SendMessage.
+#ifdef SendMessage
+#undef SendMessage
+#endif
+
+namespace content {
+struct MessagePortMessage;
+struct TransferredMessagePort;
+
+// Delegate used by MessagePortService to send messages to message ports to the
+// correct renderer. Delegates are responsible for managing their own lifetime,
+// and should call MessagePortService::OnMessagePortDelegateClosing if they are
+// destroyed while there are still message ports associated with them.
+class CONTENT_EXPORT MessagePortDelegate {
+ public:
+ // Sends a message to the given route. Implementations are responsible for
+ // updating MessagePortService with new routes for the sent message ports.
+ virtual void SendMessage(
+ int route_id,
+ const MessagePortMessage& message,
+ const std::vector<TransferredMessagePort>& sent_message_ports) = 0;
+
+ // Requests messages to the given route to be queued.
+ virtual void SendMessagesAreQueued(int route_id) = 0;
+
+ protected:
+ virtual ~MessagePortDelegate() {}
+};
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_BROWSER_MESSAGE_PORT_DELEGATE_H_
diff --git a/chromium/content/public/browser/message_port_provider.h b/chromium/content/public/browser/message_port_provider.h
new file mode 100644
index 00000000000..cf82ec74673
--- /dev/null
+++ b/chromium/content/public/browser/message_port_provider.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_PUBLIC_BROWSER_MESSAGE_PORT_PROVIDER_H_
+#define CONTENT_PUBLIC_BROWSER_MESSAGE_PORT_PROVIDER_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "content/common/content_export.h"
+
+namespace content {
+
+class MessagePortDelegate;
+class WebContents;
+struct MessagePortMessage;
+struct TransferredMessagePort;
+
+// An interface consisting of methods that can be called to use Message ports.
+class CONTENT_EXPORT MessagePortProvider {
+ public:
+ // Posts a MessageEvent to the main frame using the given source and target
+ // origins and data. The caller may also provide any message port ids as
+ // part of the message.
+ // See https://html.spec.whatwg.org/multipage/comms.html#messageevent for
+ // further information on message events.
+ // Should be called on UI thread.
+ static void PostMessageToFrame(
+ WebContents* web_contents,
+ const base::string16& source_origin,
+ const base::string16& target_origin,
+ const base::string16& data,
+ const std::vector<TransferredMessagePort>& ports);
+
+ // Creates a message channel and provide the ids of the message ports that are
+ // associated with this message channel.
+ // See https://html.spec.whatwg.org/multipage/comms.html#messagechannel
+ // Should be called on IO thread.
+ // The message ports that are created will have their routing id numbers equal
+ // to the message port numbers.
+ static void CreateMessageChannel(MessagePortDelegate* delegate,
+ int* port1,
+ int* port2);
+
+ // Posts a MessageEvent to a message port associated with a message channel.
+ // Should be called on IO thread.
+ static void PostMessageToPort(
+ int sender_port_id,
+ const MessagePortMessage& message,
+ const std::vector<TransferredMessagePort>& sent_ports);
+
+ // Close the message port. Should be called on IO thread.
+ static void ClosePort(int message_port_id);
+
+ // Queue up all the messages for this message port until ReleaseMessages
+ // is called. Should be called on IO thread.
+ static void HoldMessages(int message_port_id);
+
+ // Release any queued messages as a result of HoldMessages. Should be
+ // called on IO thread.
+ static void ReleaseMessages(int message_port_id);
+
+ // Cleanup the message ports that belong to the closing delegate.
+ // Should be called on IO thread.
+ static void OnMessagePortDelegateClosing(MessagePortDelegate * delegate);
+
+ // Update message port information when the message port is transferred
+ // from a different process. The updated message ports will have their
+ // routing numbers equal to the message port numbers.
+ // Should be called on IO thread.
+ static void UpdateMessagePort(int message_port_id,
+ MessagePortDelegate* delegate);
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(MessagePortProvider);
+};
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_BROWSER_MESSAGE_PORT_PROVIDER_H_
diff --git a/chromium/content/public/browser/native_web_keyboard_event.h b/chromium/content/public/browser/native_web_keyboard_event.h
index 3e4db80d49d..fc7c7325c96 100644
--- a/chromium/content/public/browser/native_web_keyboard_event.h
+++ b/chromium/content/public/browser/native_web_keyboard_event.h
@@ -13,6 +13,10 @@
#include "ui/events/event_constants.h"
#include "ui/gfx/native_widget_types.h"
+namespace ui {
+class KeyEvent;
+}
+
namespace content {
// Owns a platform specific event; used to pass own and pass event through
@@ -22,21 +26,7 @@ struct CONTENT_EXPORT NativeWebKeyboardEvent :
NativeWebKeyboardEvent();
explicit NativeWebKeyboardEvent(gfx::NativeEvent native_event);
-#if defined(USE_AURA)
- NativeWebKeyboardEvent(ui::EventType type,
- bool is_char,
- wchar_t character,
- int state,
- double time_stamp_seconds);
-#elif defined(OS_MACOSX)
- // TODO(suzhe): Limit these constructors to Linux native Gtk port.
- // For Linux Views port, after using RenderWidgetHostViewViews to replace
- // RenderWidgetHostViewGtk, we can use constructors for TOOLKIT_VIEWS defined
- // below.
- NativeWebKeyboardEvent(wchar_t character,
- int state,
- double time_stamp_seconds);
-#elif defined(OS_ANDROID)
+#if defined(OS_ANDROID)
NativeWebKeyboardEvent(blink::WebInputEvent::Type type,
int modifiers,
double time_secs,
@@ -51,6 +41,15 @@ struct CONTENT_EXPORT NativeWebKeyboardEvent :
int keycode,
int unicode_character,
bool is_system_key);
+#else
+ explicit NativeWebKeyboardEvent(const ui::KeyEvent& key_event);
+#if defined(USE_AURA)
+ NativeWebKeyboardEvent(ui::EventType type,
+ bool is_char,
+ wchar_t character,
+ int state,
+ double time_stamp_seconds);
+#endif
#endif
NativeWebKeyboardEvent(const NativeWebKeyboardEvent& event);
@@ -75,10 +74,6 @@ struct CONTENT_EXPORT NativeWebKeyboardEvent :
#endif
};
-// Returns a bitmak of values from ui/events/event_constants.h.
-CONTENT_EXPORT int GetModifiersFromNativeWebKeyboardEvent(
- const NativeWebKeyboardEvent& event);
-
} // namespace content
#endif // CONTENT_PUBLIC_BROWSER_NATIVE_WEB_KEYBOARD_EVENT_H_
diff --git a/chromium/content/public/browser/navigation_controller.cc b/chromium/content/public/browser/navigation_controller.cc
index 6a1e87f602a..23b32d991fb 100644
--- a/chromium/content/public/browser/navigation_controller.cc
+++ b/chromium/content/public/browser/navigation_controller.cc
@@ -15,10 +15,13 @@ NavigationController::LoadURLParams::LoadURLParams(const GURL& url)
frame_tree_node_id(-1),
is_renderer_initiated(false),
override_user_agent(UA_OVERRIDE_INHERIT),
- browser_initiated_post_data(NULL),
+ browser_initiated_post_data(nullptr),
can_load_local_resources(false),
should_replace_current_entry(false),
- should_clear_history_list(false) {
+ should_clear_history_list(false) {
+#if defined(OS_ANDROID)
+ intent_received_timestamp = 0;
+#endif
}
NavigationController::LoadURLParams::~LoadURLParams() {
@@ -40,6 +43,9 @@ NavigationController::LoadURLParams::LoadURLParams(
browser_initiated_post_data(other.browser_initiated_post_data),
should_replace_current_entry(false),
should_clear_history_list(false) {
+#if defined(OS_ANDROID)
+ intent_received_timestamp = other.intent_received_timestamp;
+#endif
}
NavigationController::LoadURLParams&
@@ -60,6 +66,9 @@ NavigationController::LoadURLParams::operator=(
browser_initiated_post_data = other.browser_initiated_post_data;
should_replace_current_entry = other.should_replace_current_entry;
should_clear_history_list = other.should_clear_history_list;
+#if defined(OS_ANDROID)
+ intent_received_timestamp = other.intent_received_timestamp;
+#endif
return *this;
}
diff --git a/chromium/content/public/browser/navigation_controller.h b/chromium/content/public/browser/navigation_controller.h
index abc6c7e6988..358e850aadc 100644
--- a/chromium/content/public/browser/navigation_controller.h
+++ b/chromium/content/public/browser/navigation_controller.h
@@ -14,6 +14,7 @@
#include "content/common/content_export.h"
#include "content/public/browser/global_request_id.h"
#include "content/public/browser/session_storage_namespace.h"
+#include "content/public/browser/site_instance.h"
#include "content/public/common/referrer.h"
#include "ui/base/page_transition_types.h"
#include "url/gurl.h"
@@ -45,6 +46,11 @@ class NavigationController {
};
// Load type used in LoadURLParams.
+ //
+ // A Java counterpart will be generated for this enum.
+ // GENERATED_JAVA_ENUM_PACKAGE: (
+ // org.chromium.content_public.browser.navigation_controller)
+ // GENERATED_JAVA_PREFIX_TO_STRIP: LOAD_TYPE_
enum LoadURLType {
// For loads that do not fall into any types below.
LOAD_TYPE_DEFAULT,
@@ -63,6 +69,11 @@ class NavigationController {
};
// User agent override type used in LoadURLParams.
+ //
+ // A Java counterpart will be generated for this enum.
+ // GENERATED_JAVA_ENUM_PACKAGE: (
+ // org.chromium.content_public.browser.navigation_controller)
+ // GENERATED_JAVA_PREFIX_TO_STRIP: UA_OVERRIDE_
enum UserAgentOverrideOption {
// Use the override value from the previous NavigationEntry in the
// NavigationController.
@@ -104,6 +115,10 @@ class NavigationController {
// The url to load. This field is required.
GURL url;
+ // SiteInstance of the frame that initiated the navigation or null if we
+ // don't know it.
+ scoped_refptr<SiteInstance> source_site_instance;
+
// See LoadURLType comments above.
LoadURLType load_type;
@@ -112,7 +127,7 @@ class NavigationController {
ui::PageTransition transition_type;
// The FrameTreeNode ID for the frame to navigate, or -1 for the main frame.
- int64 frame_tree_node_id;
+ int frame_tree_node_id;
// Referrer for this load. Empty if none.
Referrer referrer;
@@ -169,6 +184,13 @@ class NavigationController {
// commits.
bool should_clear_history_list;
+#if defined(OS_ANDROID)
+ // On Android, for a load triggered by an intent, the time Chrome received
+ // the original intent that prompted the load (in milliseconds active time
+ // since boot).
+ int64 intent_received_timestamp;
+#endif
+
explicit LoadURLParams(const GURL& url);
~LoadURLParams();
@@ -184,10 +206,10 @@ class NavigationController {
virtual ~NavigationController() {}
// Returns the web contents associated with this controller. It can never be
- // NULL.
+ // nullptr.
virtual WebContents* GetWebContents() const = 0;
- // Get/set the browser context for this controller. It can never be NULL.
+ // Get/set the browser context for this controller. It can never be nullptr.
virtual BrowserContext* GetBrowserContext() const = 0;
virtual void SetBrowserContext(BrowserContext* browser_context) = 0;
@@ -219,14 +241,14 @@ class NavigationController {
//
// Returns the active entry, which is the transient entry if any, the pending
// entry if a navigation is in progress or the last committed entry otherwise.
- // NOTE: This can be NULL!!
+ // NOTE: This can be nullptr!!
virtual NavigationEntry* GetActiveEntry() const = 0;
// Returns the entry that should be displayed to the user in the address bar.
// This is the transient entry if any, the pending entry if a navigation is
// in progress *and* is safe to display to the user (see below), or the last
// committed entry otherwise.
- // NOTE: This can be NULL if no entry has committed!
+ // NOTE: This can be nullptr if no entry has committed!
//
// A pending entry is safe to display if it started in the browser process or
// if it's a renderer-initiated navigation in a new tab which hasn't been
@@ -257,7 +279,7 @@ class NavigationController {
virtual NavigationEntry* GetEntryAtIndex(int index) const = 0;
- // Returns the entry at the specified offset from current. Returns NULL
+ // Returns the entry at the specified offset from current. Returns nullptr
// if out of bounds.
virtual NavigationEntry* GetEntryAtOffset(int offset) const = 0;
diff --git a/chromium/content/public/browser/navigation_details.cc b/chromium/content/public/browser/navigation_details.cc
index 2eb2ba1ca87..19d62998b44 100644
--- a/chromium/content/public/browser/navigation_details.cc
+++ b/chromium/content/public/browser/navigation_details.cc
@@ -7,7 +7,7 @@
namespace content {
LoadCommittedDetails::LoadCommittedDetails()
- : entry(NULL),
+ : entry(nullptr),
type(content::NAVIGATION_TYPE_UNKNOWN),
previous_entry_index(-1),
did_replace_entry(false),
diff --git a/chromium/content/public/browser/navigation_entry.h b/chromium/content/public/browser/navigation_entry.h
index de8ee49b7ad..9345f0f8cac 100644
--- a/chromium/content/public/browser/navigation_entry.h
+++ b/chromium/content/public/browser/navigation_entry.h
@@ -32,7 +32,6 @@ class NavigationEntry {
virtual ~NavigationEntry() {}
CONTENT_EXPORT static NavigationEntry* Create();
- CONTENT_EXPORT static NavigationEntry* Create(const NavigationEntry& copy);
// Page-related stuff --------------------------------------------------------
@@ -97,7 +96,7 @@ class NavigationEntry {
// Returns the title to be displayed on the tab. This could be the title of
// the page if it is available or the URL. |languages| is the list of
- // accpeted languages (e.g., prefs::kAcceptLanguages) or empty if proper
+ // accepted languages (e.g., prefs::kAcceptLanguages) or empty if proper
// URL formatting isn't needed (e.g., unit tests).
virtual const base::string16& GetTitleForDisplay(
const std::string& languages) const = 0;
@@ -145,7 +144,7 @@ class NavigationEntry {
// Note, this field:
// 1) is not persisted in session restore.
// 2) is shallow copied with the static copy Create method above.
- // 3) may be NULL so check before use.
+ // 3) may be nullptr so check before use.
virtual void SetBrowserInitiatedPostData(
const base::RefCountedMemory* data) = 0;
virtual const base::RefCountedMemory* GetBrowserInitiatedPostData() const = 0;
@@ -184,12 +183,6 @@ class NavigationEntry {
virtual void SetCanLoadLocalResources(bool allow) = 0;
virtual bool GetCanLoadLocalResources() const = 0;
- // Used to specify which frame to navigate. If empty, the main frame is
- // navigated. This is currently not persisted in session restore, because it
- // is currently only used in tests.
- virtual void SetFrameToNavigate(const std::string& frame_name) = 0;
- virtual const std::string& GetFrameToNavigate() const = 0;
-
// Set extra data on this NavigationEntry according to the specified |key|.
// This data is not persisted by default.
virtual void SetExtraData(const std::string& key,
diff --git a/chromium/content/public/browser/navigation_type.h b/chromium/content/public/browser/navigation_type.h
index 01431cd0244..b63190b183e 100644
--- a/chromium/content/public/browser/navigation_type.h
+++ b/chromium/content/public/browser/navigation_type.h
@@ -13,11 +13,15 @@ enum NavigationType {
// Unknown type.
NAVIGATION_TYPE_UNKNOWN,
- // A new page was navigated in the main frame.
+ // A new page was navigated to in the main frame. This covers all cases where
+ // the main frame navigated and a new navigation entry was created. This means
+ // cases like navigations to a hash on the same page are NEW_PAGE, not
+ // IN_PAGE. (Navigation entries created by subframe navigations are
+ // NEW_SUBFRAME.)
NAVIGATION_TYPE_NEW_PAGE,
- // Renavigating to an existing navigation entry. The entry is guaranteed to
- // exist in the list, or else it would be a new page or IGNORE navigation.
+ // Renavigating to an existing navigation entry. This is the case for history
+ // navigation, reloads, and location.replace().
NAVIGATION_TYPE_EXISTING_PAGE,
// The same page has been reloaded as a result of the user requesting
@@ -26,10 +30,10 @@ enum NavigationType {
// pending entry for the load, which is then meaningless.
NAVIGATION_TYPE_SAME_PAGE,
- // In page navigations are when the reference fragment changes. This will
- // be in the main frame only (we won't even get notified of in-page
- // subframe navigations). It may be for any page, not necessarily the last
- // committed one (for example, whey going back to a page with a ref).
+ // The navigation was in the main frame, to a different navigation entry, but
+ // appearing to the user to be a navigation within the same page. This is the
+ // case for history.replaceState(), as well as back and forward across
+ // fragment entries and history.pushState() entries.
NAVIGATION_TYPE_IN_PAGE,
// A new subframe was manually navigated by the user. We will create a new
diff --git a/chromium/content/public/browser/navigator_connect_context.h b/chromium/content/public/browser/navigator_connect_context.h
new file mode 100644
index 00000000000..1c6dc7efa87
--- /dev/null
+++ b/chromium/content/public/browser/navigator_connect_context.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_PUBLIC_BROWSER_NAVIGATOR_CONNECT_CONTEXT_H_
+#define CONTENT_PUBLIC_BROWSER_NAVIGATOR_CONNECT_CONTEXT_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+
+namespace content {
+
+class NavigatorConnectServiceFactory;
+
+// Use this class to register additional navigator.connect service factories.
+// One instance of this class exists per StoragePartition.
+// TODO(mek): Add API so services can close a connection.
+class NavigatorConnectContext
+ : public base::RefCountedThreadSafe<NavigatorConnectContext> {
+ public:
+ // Register a service factory. The most recently added factory that claims to
+ // handle a URL will be used to handle a connection request for that URL.
+ // This method must always be called on the UI thread. No guarantees are
+ // given as to on what thread the passed in factory will get destroyed.
+ virtual void AddFactory(
+ scoped_ptr<NavigatorConnectServiceFactory> factory) = 0;
+
+ protected:
+ friend class base::RefCountedThreadSafe<NavigatorConnectContext>;
+ NavigatorConnectContext() {}
+ virtual ~NavigatorConnectContext() {}
+};
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_BROWSER_NAVIGATOR_CONNECT_CONTEXT_H_
diff --git a/chromium/content/public/browser/navigator_connect_service_factory.h b/chromium/content/public/browser/navigator_connect_service_factory.h
new file mode 100644
index 00000000000..4a71f27b801
--- /dev/null
+++ b/chromium/content/public/browser/navigator_connect_service_factory.h
@@ -0,0 +1,49 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_PUBLIC_BROWSER_NAVIGATOR_CONNECT_SERVICE_FACTORY_H_
+#define CONTENT_PUBLIC_BROWSER_NAVIGATOR_CONNECT_SERVICE_FACTORY_H_
+
+#include "base/callback.h"
+
+class GURL;
+
+namespace content {
+
+struct NavigatorConnectClient;
+class MessagePortDelegate;
+
+// Implement this interface to provide a new kind of navigator.connect
+// accessible service.
+// Instances of this class are owned by NavigatorConnectContext. Register new
+// factories by calling NavigatorConnectContext::AddFactory.
+class NavigatorConnectServiceFactory {
+ public:
+ // Call with nullptr to indicate connection failure. Ownership of the delegate
+ // remains with the factory. It is assumed that for the passed
+ // MessagePortDelegate implementation the route_id and message_port_id of a
+ // connection are the same.
+ // Pass true to |data_as_values| if the delegate expects to receive messages
+ // from the client encoded as base::Value instead of the normal serialization
+ // format.
+ using ConnectCallback =
+ base::Callback<void(MessagePortDelegate*, bool data_as_values)>;
+
+ virtual ~NavigatorConnectServiceFactory() {}
+
+ // Return true if this factory is responsible for handling connections to the
+ // |target_url|. The most recently added factory that returns true for a
+ // particular url is picked to handle the connection attempt.
+ virtual bool HandlesUrl(const GURL& target_url) = 0;
+
+ // Called to try to establish a connection. Only called if this factory was
+ // the most recently added factory that returned true from |HandlesUrl| for
+ // the url being connected to.
+ virtual void Connect(const NavigatorConnectClient& client,
+ const ConnectCallback& callback) = 0;
+};
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_BROWSER_NAVIGATOR_CONNECT_SERVICE_FACTORY_H_
diff --git a/chromium/content/public/browser/notification_database_data.h b/chromium/content/public/browser/notification_database_data.h
new file mode 100644
index 00000000000..e10f3146925
--- /dev/null
+++ b/chromium/content/public/browser/notification_database_data.h
@@ -0,0 +1,34 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_PUBLIC_BROWSER_NOTIFICATION_DATABASE_DATA_H_
+#define CONTENT_PUBLIC_BROWSER_NOTIFICATION_DATABASE_DATA_H_
+
+#include <stdint.h>
+
+#include "content/public/common/platform_notification_data.h"
+#include "url/gurl.h"
+
+namespace content {
+
+// Stores information about a Web Notification as available in the notification
+// database. Beyond the notification's own data, its id and attribution need
+// to be available for users of the database as well.
+struct NotificationDatabaseData {
+ // Id of the notification as allocated by the NotificationDatabase.
+ int64_t notification_id = 0;
+
+ // Origin of the website this notification is associated with.
+ GURL origin;
+
+ // Id of the Service Worker registration this notification is associated with.
+ int64_t service_worker_registration_id = 0;
+
+ // Platform data of the notification that's being stored.
+ PlatformNotificationData notification_data;
+};
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_BROWSER_NOTIFICATION_DATABASE_DATA_H_
diff --git a/chromium/content/public/browser/notification_details.h b/chromium/content/public/browser/notification_details.h
index 815d74804c0..235586abdf3 100644
--- a/chromium/content/public/browser/notification_details.h
+++ b/chromium/content/public/browser/notification_details.h
@@ -18,7 +18,7 @@ namespace content {
// NotificationService::NoDetails().
class CONTENT_EXPORT NotificationDetails {
public:
- NotificationDetails() : ptr_(NULL) {}
+ NotificationDetails() : ptr_(nullptr) {}
NotificationDetails(const NotificationDetails& other) : ptr_(other.ptr_) {}
~NotificationDetails() {}
diff --git a/chromium/content/public/browser/notification_event_dispatcher.h b/chromium/content/public/browser/notification_event_dispatcher.h
new file mode 100644
index 00000000000..4509bacf246
--- /dev/null
+++ b/chromium/content/public/browser/notification_event_dispatcher.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_PUBLIC_BROWSER_NOTIFICATION_EVENT_DISPATCHER_H_
+#define CONTENT_PUBLIC_BROWSER_NOTIFICATION_EVENT_DISPATCHER_H_
+
+#include <stdint.h>
+#include <string>
+
+#include "base/callback_forward.h"
+#include "content/common/content_export.h"
+#include "content/public/common/persistent_notification_status.h"
+
+class GURL;
+
+namespace content {
+
+class BrowserContext;
+struct PlatformNotificationData;
+
+// This is the dispatcher to be used for firing events related to persistent
+// notifications on a Service Worker. This class is a singleton, the instance of
+// which can be retrieved using the static GetInstance() method. All methods
+// must be called on the UI thread.
+class CONTENT_EXPORT NotificationEventDispatcher {
+ public:
+ static NotificationEventDispatcher* GetInstance();
+
+ using NotificationClickDispatchCompleteCallback =
+ base::Callback<void(PersistentNotificationStatus)>;
+
+ // Dispatches the "notificationclick" event on the Service Worker associated
+ // with |persistent_notification_id| belonging to |origin|. The |callback|
+ // will be invoked when it's known whether the event successfully executed.
+ virtual void DispatchNotificationClickEvent(
+ BrowserContext* browser_context,
+ int64_t persistent_notification_id,
+ const GURL& origin,
+ const NotificationClickDispatchCompleteCallback&
+ dispatch_complete_callback) = 0;
+
+ protected:
+ virtual ~NotificationEventDispatcher() {}
+};
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_BROWSER_NOTIFICATION_EVENT_DISPATCHER_H_
diff --git a/chromium/content/public/browser/notification_registrar.cc b/chromium/content/public/browser/notification_registrar.cc
index 1d6985a0636..af82710b81e 100644
--- a/chromium/content/public/browser/notification_registrar.cc
+++ b/chromium/content/public/browser/notification_registrar.cc
@@ -65,8 +65,8 @@ void NotificationRegistrar::Remove(NotificationObserver* observer,
registered_.erase(found);
- // This can be NULL if our owner outlives the NotificationService, e.g. if our
- // owner is a Singleton.
+ // This can be nullptr if our owner outlives the NotificationService, e.g. if
+ // our owner is a Singleton.
NotificationServiceImpl* service = NotificationServiceImpl::current();
if (service)
service->RemoveObserver(observer, type, source);
@@ -83,8 +83,8 @@ void NotificationRegistrar::RemoveAll() {
if (registered_.empty())
return;
- // This can be NULL if our owner outlives the NotificationService, e.g. if our
- // owner is a Singleton.
+ // This can be nullptr if our owner outlives the NotificationService, e.g. if
+ // our owner is a Singleton.
NotificationServiceImpl* service = NotificationServiceImpl::current();
if (service) {
for (size_t i = 0; i < registered_.size(); i++) {
diff --git a/chromium/content/public/browser/notification_service.h b/chromium/content/public/browser/notification_service.h
index ff3217cd6a5..c657d2b10de 100644
--- a/chromium/content/public/browser/notification_service.h
+++ b/chromium/content/public/browser/notification_service.h
@@ -17,8 +17,8 @@ namespace content {
class CONTENT_EXPORT NotificationService {
public:
- // Returns the NotificationService object for the current thread, or NULL if
- // none.
+ // Returns the NotificationService object for the current thread, or nullptr
+ // if none.
static NotificationService* current();
static NotificationService* Create();
@@ -39,7 +39,7 @@ class CONTENT_EXPORT NotificationService {
// Returns a NotificationSource that represents all notification sources
// (for the purpose of registering an observer for events from all sources).
- static Source<void> AllSources() { return Source<void>(NULL); }
+ static Source<void> AllSources() { return Source<void>(nullptr); }
// Returns the same value as AllSources(). This function has semantic
// differences to the programmer: We have checked that this AllSources()
@@ -52,12 +52,12 @@ class CONTENT_EXPORT NotificationService {
// drop to almost nothing, because most usages are not multiprofile safe and
// were done because it was easier to listen to everything.
static Source<void> AllBrowserContextsAndSources() {
- return Source<void>(NULL);
+ return Source<void>(nullptr);
}
// Returns a NotificationDetails object that represents a lack of details
// associated with a notification. (This is effectively a null pointer.)
- static Details<void> NoDetails() { return Details<void>(NULL); }
+ static Details<void> NoDetails() { return Details<void>(nullptr); }
};
} // namespace content
diff --git a/chromium/content/public/browser/notification_types.h b/chromium/content/public/browser/notification_types.h
index 08ffd3306de..a704315387c 100644
--- a/chromium/content/public/browser/notification_types.h
+++ b/chromium/content/public/browser/notification_types.h
@@ -112,13 +112,6 @@ enum NotificationType {
// DEPRECATED: Use WebContentsObserver::RenderViewReady()
NOTIFICATION_WEB_CONTENTS_CONNECTED,
- // This notification is sent when a WebContents swaps its render view host
- // with another one, possibly changing processes. The source is a
- // Source<WebContents> with a pointer to the WebContents, details is a
- // std::pair::<old RenderViewHost, new RenderViewHost>.
- // DEPRECATED: Use WebContentsObserver::RenderViewHostChanged()
- NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
-
// This message is sent after a WebContents is disconnected from the
// renderer process. The source is a Source<WebContents> with a pointer to
// the WebContents (the pointer is usable). No details are expected.
diff --git a/chromium/content/public/browser/page_navigator.cc b/chromium/content/public/browser/page_navigator.cc
index f585501e9e4..c919ee2d8ca 100644
--- a/chromium/content/public/browser/page_navigator.cc
+++ b/chromium/content/public/browser/page_navigator.cc
@@ -26,7 +26,7 @@ OpenURLParams::OpenURLParams(
OpenURLParams::OpenURLParams(
const GURL& url,
const Referrer& referrer,
- int64 frame_tree_node_id,
+ int frame_tree_node_id,
WindowOpenDisposition disposition,
ui::PageTransition transition,
bool is_renderer_initiated)
diff --git a/chromium/content/public/browser/page_navigator.h b/chromium/content/public/browser/page_navigator.h
index 0cdba29607c..912cab83ea6 100644
--- a/chromium/content/public/browser/page_navigator.h
+++ b/chromium/content/public/browser/page_navigator.h
@@ -15,6 +15,7 @@
#include "base/memory/ref_counted_memory.h"
#include "content/common/content_export.h"
#include "content/public/browser/global_request_id.h"
+#include "content/public/browser/site_instance.h"
#include "content/public/common/referrer.h"
#include "ui/base/page_transition_types.h"
#include "ui/base/window_open_disposition.h"
@@ -32,7 +33,7 @@ struct CONTENT_EXPORT OpenURLParams {
bool is_renderer_initiated);
OpenURLParams(const GURL& url,
const Referrer& referrer,
- int64 frame_tree_node_id,
+ int frame_tree_node_id,
WindowOpenDisposition disposition,
ui::PageTransition transition,
bool is_renderer_initiated);
@@ -42,6 +43,10 @@ struct CONTENT_EXPORT OpenURLParams {
GURL url;
Referrer referrer;
+ // SiteInstance of the frame that initiated the navigation or null if we
+ // don't know it.
+ scoped_refptr<content::SiteInstance> source_site_instance;
+
// Any redirect URLs that occurred for this navigation before |url|.
std::vector<GURL> redirect_chain;
@@ -60,7 +65,7 @@ struct CONTENT_EXPORT OpenURLParams {
std::string extra_headers;
// The browser-global FrameTreeNode ID or -1 to indicate the main frame.
- int64 frame_tree_node_id;
+ int frame_tree_node_id;
// The disposition requested by the navigation source.
WindowOpenDisposition disposition;
@@ -93,7 +98,7 @@ class PageNavigator {
// Opens a URL with the given disposition. The transition specifies how this
// navigation should be recorded in the history system (for example, typed).
- // Returns the WebContents the URL is opened in, or NULL if the URL wasn't
+ // Returns the WebContents the URL is opened in, or nullptr if the URL wasn't
// opened immediately.
virtual WebContents* OpenURL(const OpenURLParams& params) = 0;
};
diff --git a/chromium/content/public/browser/permission_manager.h b/chromium/content/public/browser/permission_manager.h
new file mode 100644
index 00000000000..6a56e0b6a58
--- /dev/null
+++ b/chromium/content/public/browser/permission_manager.h
@@ -0,0 +1,61 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_PUBLIC_BROWSER_PERMISSION_MANAGER_H_
+#define CONTENT_PUBLIC_BROWSER_PERMISSION_MANAGER_H_
+
+#include "content/common/content_export.h"
+#include "content/public/common/permission_status.mojom.h"
+
+class GURL;
+
+namespace content {
+enum class PermissionType;
+class WebContents;
+
+class CONTENT_EXPORT PermissionManager {
+ public:
+ virtual ~PermissionManager() = default;
+
+ virtual void RequestPermission(
+ PermissionType permission,
+ WebContents* web_contents,
+ int request_id,
+ const GURL& requesting_origin,
+ bool user_gesture,
+ const base::Callback<void(PermissionStatus)>& callback) = 0;
+
+ virtual void CancelPermissionRequest(PermissionType permission,
+ WebContents* web_contents,
+ int request_id,
+ const GURL& requesting_origin) = 0;
+
+ virtual PermissionStatus GetPermissionStatus(
+ PermissionType permission,
+ const GURL& requesting_origin,
+ const GURL& embedding_origin) = 0;
+
+ virtual void ResetPermission(PermissionType permission,
+ const GURL& requesting_origin,
+ const GURL& embedding_origin) = 0;
+
+ virtual void RegisterPermissionUsage(PermissionType permission,
+ const GURL& requesting_origin,
+ const GURL& embedding_origin) = 0;
+
+ // Runs the given |callback| whenever the |permission| associated with the
+ // pair { requesting_origin, embedding_origin } changes.
+ // Returns the subscription_id to be used to unsubscribe.
+ virtual int SubscribePermissionStatusChange(
+ PermissionType permission,
+ const GURL& requesting_origin,
+ const GURL& embedding_origin,
+ const base::Callback<void(PermissionStatus)>& callback) = 0;
+
+ virtual void UnsubscribePermissionStatusChange(int subscription_id) = 0;
+};
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_BROWSER_PERMISSION_MANAGER_H_
diff --git a/chromium/content/public/browser/permission_type.h b/chromium/content/public/browser/permission_type.h
index 1a3b2617232..4fb062c44e7 100644
--- a/chromium/content/public/browser/permission_type.h
+++ b/chromium/content/public/browser/permission_type.h
@@ -11,16 +11,16 @@ namespace content {
// the UMA guidelines.
// Make sure you update histograms.xml if you add new permission types.
// Never delete or reorder an entry; only add new entries
-// immediately before PERMISSION_NUM
-enum PermissionType {
- PERMISSION_MIDI_SYSEX = 1,
- PERMISSION_PUSH_MESSAGING = 2,
- PERMISSION_NOTIFICATIONS = 3,
- PERMISSION_GEOLOCATION = 4,
- PERMISSION_PROTECTED_MEDIA = 5,
+// immediately before PermissionType::NUM
+enum class PermissionType {
+ MIDI_SYSEX = 1,
+ PUSH_MESSAGING = 2,
+ NOTIFICATIONS = 3,
+ GEOLOCATION = 4,
+ PROTECTED_MEDIA_IDENTIFIER = 5,
// Always keep this at the end.
- PERMISSION_NUM,
+ NUM,
};
} // namespace content
diff --git a/chromium/content/public/browser/platform_notification_context.h b/chromium/content/public/browser/platform_notification_context.h
new file mode 100644
index 00000000000..47d6b755a50
--- /dev/null
+++ b/chromium/content/public/browser/platform_notification_context.h
@@ -0,0 +1,80 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_PUBLIC_BROWSER_PLATFORM_NOTIFICATION_CONTEXT_H_
+#define CONTENT_PUBLIC_BROWSER_PLATFORM_NOTIFICATION_CONTEXT_H_
+
+#include <stdint.h>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/notification_database_data.h"
+
+class GURL;
+
+namespace content {
+
+// Represents the storage context for persistent Web Notifications, specific to
+// the storage partition owning the instance. All methods defined in this
+// interface may only be used on the IO thread.
+class PlatformNotificationContext
+ : public base::RefCountedThreadSafe<PlatformNotificationContext,
+ BrowserThread::DeleteOnUIThread> {
+ public:
+ using ReadResultCallback =
+ base::Callback<void(bool /* success */,
+ const NotificationDatabaseData&)>;
+
+ using ReadAllResultCallback =
+ base::Callback<void(bool /* success */,
+ const std::vector<NotificationDatabaseData>&)>;
+
+ using WriteResultCallback =
+ base::Callback<void(bool /* success */,
+ int64_t /* notification_id */)>;
+
+ using DeleteResultCallback = base::Callback<void(bool /* success */)>;
+
+ // Reads the data associated with |notification_id| belonging to |origin|
+ // from the database. |callback| will be invoked with the success status
+ // and a reference to the notification database data when completed.
+ virtual void ReadNotificationData(int64_t notification_id,
+ const GURL& origin,
+ const ReadResultCallback& callback) = 0;
+
+ // Reads all data associated with |service_worker_registration_id| belonging
+ // to |origin| from the database. |callback| will be invoked with the success
+ // status and a vector with all read notification data when completed.
+ virtual void ReadAllNotificationDataForServiceWorkerRegistration(
+ const GURL& origin,
+ int64_t service_worker_registration_id,
+ const ReadAllResultCallback& callback) = 0;
+
+ // Writes the data associated with a notification to a database. When this
+ // action completed, |callback| will be invoked with the success status and
+ // the persistent notification id when written successfully.
+ virtual void WriteNotificationData(
+ const GURL& origin,
+ const NotificationDatabaseData& database_data,
+ const WriteResultCallback& callback) = 0;
+
+ // Deletes all data associated with |notification_id| belonging to |origin|
+ // from the database. |callback| will be invoked with the success status
+ // when the operation has completed.
+ virtual void DeleteNotificationData(int64_t notification_id,
+ const GURL& origin,
+ const DeleteResultCallback& callback) = 0;
+
+ protected:
+ friend class base::DeleteHelper<PlatformNotificationContext>;
+ friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>;
+
+ virtual ~PlatformNotificationContext() {}
+};
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_BROWSER_PLATFORM_NOTIFICATION_CONTEXT_H_
diff --git a/chromium/content/public/browser/platform_notification_service.h b/chromium/content/public/browser/platform_notification_service.h
new file mode 100644
index 00000000000..6c9e50904cf
--- /dev/null
+++ b/chromium/content/public/browser/platform_notification_service.h
@@ -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.
+
+#ifndef CONTENT_PUBLIC_BROWSER_PLATFORM_NOTIFICATION_SERVICE_H_
+#define CONTENT_PUBLIC_BROWSER_PLATFORM_NOTIFICATION_SERVICE_H_
+
+#include <stdint.h>
+#include <set>
+#include <string>
+
+#include "base/callback_forward.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/common/content_export.h"
+#include "third_party/WebKit/public/platform/modules/notifications/WebNotificationPermission.h"
+
+class GURL;
+class SkBitmap;
+
+namespace content {
+
+class BrowserContext;
+class DesktopNotificationDelegate;
+struct PlatformNotificationData;
+class ResourceContext;
+
+// The service using which notifications can be presented to the user. There
+// should be a unique instance of the PlatformNotificationService depending
+// on the browsing context being used.
+class CONTENT_EXPORT PlatformNotificationService {
+ public:
+ virtual ~PlatformNotificationService() {}
+
+ // Checks if |origin| has permission to display Web Notifications.
+ // This method must only be called on the UI thread.
+ virtual blink::WebNotificationPermission CheckPermissionOnUIThread(
+ BrowserContext* browser_context,
+ const GURL& origin,
+ int render_process_id) = 0;
+
+ // Checks if |origin| has permission to display Web Notifications. This method
+ // exists to serve the synchronous IPC required by the Notification.permission
+ // JavaScript getter, and should not be used for other purposes. See
+ // https://crbug.com/446497 for the plan to deprecate this method.
+ // This method must only be called on the IO thread.
+ virtual blink::WebNotificationPermission CheckPermissionOnIOThread(
+ ResourceContext* resource_context,
+ const GURL& origin,
+ int render_process_id) = 0;
+
+ // Displays the notification described in |params| to the user. A closure
+ // through which the notification can be closed will be stored in the
+ // |cancel_callback| argument. This method must be called on the UI thread.
+ virtual void DisplayNotification(
+ BrowserContext* browser_context,
+ const GURL& origin,
+ const SkBitmap& icon,
+ const PlatformNotificationData& notification_data,
+ scoped_ptr<DesktopNotificationDelegate> delegate,
+ base::Closure* cancel_callback) = 0;
+
+ // Displays the persistent notification described in |notification_data| to
+ // the user. This method must be called on the UI thread.
+ virtual void DisplayPersistentNotification(
+ BrowserContext* browser_context,
+ int64_t persistent_notification_id,
+ const GURL& origin,
+ const SkBitmap& icon,
+ const PlatformNotificationData& notification_data) = 0;
+
+ // Closes the persistent notification identified by
+ // |persistent_notification_id|. This method must be called on the UI thread.
+ virtual void ClosePersistentNotification(
+ BrowserContext* browser_context,
+ int64_t persistent_notification_id) = 0;
+
+ // Writes the ids of all currently displaying persistent notifications for the
+ // given |browser_context| to |displayed_notifications|. Returns whether the
+ // platform is able to provide such a set.
+ virtual bool GetDisplayedPersistentNotifications(
+ BrowserContext* browser_context,
+ std::set<std::string>* displayed_notifications) = 0;
+};
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_BROWSER_PLATFORM_NOTIFICATION_SERVICE_H_
diff --git a/chromium/content/public/browser/plugin_data_remover.h b/chromium/content/public/browser/plugin_data_remover.h
index 02d3acd53ca..e242cf2a4ff 100644
--- a/chromium/content/public/browser/plugin_data_remover.h
+++ b/chromium/content/public/browser/plugin_data_remover.h
@@ -24,10 +24,10 @@ class CONTENT_EXPORT PluginDataRemover {
static PluginDataRemover* Create(content::BrowserContext* browser_context);
virtual ~PluginDataRemover() {}
- // Starts removing plug-in data stored since |begin_time|.
+ // Starts removing plugin data stored since |begin_time|.
virtual base::WaitableEvent* StartRemoving(base::Time begin_time) = 0;
- // Returns a list of all plug-ins that support removing LSO data. This method
+ // Returns a list of all plugins that support removing LSO data. This method
// will use cached plugin data. Call PluginService::GetPlugins() if the latest
// data is needed.
static void GetSupportedPlugins(std::vector<WebPluginInfo>* plugins);
diff --git a/chromium/content/public/browser/plugin_service.h b/chromium/content/public/browser/plugin_service.h
index 696800f3f28..c09331eed3c 100644
--- a/chromium/content/public/browser/plugin_service.h
+++ b/chromium/content/public/browser/plugin_service.h
@@ -41,8 +41,8 @@ class PluginService {
// Tells all the renderer processes associated with the given browser context
// to throw away their cache of the plugin list, and optionally also reload
- // all the pages with plugins. If |browser_context| is NULL, purges the cache
- // in all renderers.
+ // all the pages with plugins. If |browser_context| is nullptr, purges the
+ // cache in all renderers.
// NOTE: can only be called on the UI thread.
CONTENT_EXPORT static void PurgePluginListCache(
BrowserContext* browser_context,
@@ -53,7 +53,7 @@ class PluginService {
// Must be called on the instance to finish initialization.
virtual void Init() = 0;
- // Starts watching for changes in the list of installed plug-ins.
+ // Starts watching for changes in the list of installed plugins.
virtual void StartWatchingPlugins() = 0;
// Gets the plugin in the list of plugins that matches the given url and mime
@@ -96,7 +96,7 @@ class PluginService {
// provided function on the calling MessageLoop on completion.
virtual void GetPlugins(const GetPluginsCallback& callback) = 0;
- // Returns information about a pepper plugin if it exists, otherwise NULL.
+ // Returns information about a pepper plugin if it exists, otherwise nullptr.
// The caller does not own the pointer, and it's not guaranteed to live past
// the call stack.
virtual PepperPluginInfo* GetRegisteredPpapiPluginInfo(
@@ -108,7 +108,7 @@ class PluginService {
// If the plugin with the given path is running, cleanly shuts it down.
virtual void ForcePluginShutdown(const base::FilePath& plugin_path) = 0;
- // Used to monitor plug-in stability. An unstable plug-in is one that has
+ // Used to monitor plugin stability. An unstable plugin is one that has
// crashed more than a set number of times in a set time period.
virtual bool IsPluginUnstable(const base::FilePath& plugin_path) = 0;
@@ -143,6 +143,9 @@ class PluginService {
// This can be called from any thread.
virtual bool NPAPIPluginsSupported() = 0;
+ // This is equivalent to specifying kEnableNpapi.
+ virtual void EnableNpapiPlugins() = 0;
+
// This is equivalent to specifying kDisablePluginsDiscovery, but is useful
// for unittests.
virtual void DisablePluginsDiscoveryForTesting() = 0;
diff --git a/chromium/content/public/browser/plugin_service_filter.h b/chromium/content/public/browser/plugin_service_filter.h
index fda9d33c1ec..5b9d216e88c 100644
--- a/chromium/content/public/browser/plugin_service_filter.h
+++ b/chromium/content/public/browser/plugin_service_filter.h
@@ -5,6 +5,8 @@
#ifndef CONTENT_PUBLIC_BROWSER_PLUGIN_SERVICE_FILTER_H_
#define CONTENT_PUBLIC_BROWSER_PLUGIN_SERVICE_FILTER_H_
+#include <string>
+
class GURL;
namespace base {
@@ -14,7 +16,7 @@ class FilePath;
namespace content {
struct WebPluginInfo;
-// Callback class to let the client filter the list of all installed plug-ins
+// Callback class to let the client filter the list of all installed plugins
// and block them from being loaded.
// This class is called on the FILE thread.
class PluginServiceFilter {
@@ -33,6 +35,13 @@ class PluginServiceFilter {
// Whether the renderer has permission to load available |plugin|.
virtual bool CanLoadPlugin(int render_process_id,
const base::FilePath& path) = 0;
+
+ // Called when a renderer loads an NPAPI |plugin| that matched |mime_type|.
+ // TODO(wfh): Remove when NPAPI is gone.
+ virtual void NPAPIPluginLoaded(int render_process_id,
+ int render_frame_id,
+ const std::string& mime_type,
+ const WebPluginInfo& plugin) {}
};
} // namespace content
diff --git a/chromium/content/public/browser/power_save_blocker.h b/chromium/content/public/browser/power_save_blocker.h
index fe9f9661e4a..813c8783068 100644
--- a/chromium/content/public/browser/power_save_blocker.h
+++ b/chromium/content/public/browser/power_save_blocker.h
@@ -32,13 +32,26 @@ class CONTENT_EXPORT PowerSaveBlocker {
kPowerSaveBlockPreventDisplaySleep,
};
+ // Reasons why power-saving features may be blocked.
+ enum Reason {
+ // Audio is being played.
+ kReasonAudioPlayback,
+ // Video is being played.
+ kReasonVideoPlayback,
+ // Power-saving is blocked for some other reason.
+ kReasonOther,
+ };
+
virtual ~PowerSaveBlocker() = 0;
// Pass in the type of power save blocking desired. If multiple types of
// blocking are desired, instantiate one PowerSaveBlocker for each type.
- // |reason| may be provided to the underlying system APIs on some platforms.
+ // |reason| and |description| (a more-verbose, human-readable justification of
+ // the blocking) may be provided to the underlying system APIs on some
+ // platforms.
static scoped_ptr<PowerSaveBlocker> Create(PowerSaveBlockerType type,
- const std::string& reason);
+ Reason reason,
+ const std::string& description);
};
} // namespace content
diff --git a/chromium/content/public/browser/power_usage_monitor.h b/chromium/content/public/browser/power_usage_monitor.h
new file mode 100644
index 00000000000..f28b98c3166
--- /dev/null
+++ b/chromium/content/public/browser/power_usage_monitor.h
@@ -0,0 +1,17 @@
+// Copyright 2014 The Chromium Authors. 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_POWER_USAGE_MONITOR_H_
+#define CONTENT_PUBLIC_BROWSER_POWER_USAGE_MONITOR_H_
+
+#include "content/common/content_export.h"
+
+namespace content {
+
+// Start the PowerUsageMonitor.
+CONTENT_EXPORT void StartPowerUsageMonitor();
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_BROWSER_POWER_USAGE_MONITOR_H_
diff --git a/chromium/content/public/browser/presentation_screen_availability_listener.h b/chromium/content/public/browser/presentation_screen_availability_listener.h
new file mode 100644
index 00000000000..a30c24810d1
--- /dev/null
+++ b/chromium/content/public/browser/presentation_screen_availability_listener.h
@@ -0,0 +1,34 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_PUBLIC_BROWSER_PRESENTATION_SCREEN_AVAILABILITY_LISTENER_H_
+#define CONTENT_PUBLIC_BROWSER_PRESENTATION_SCREEN_AVAILABILITY_LISTENER_H_
+
+#include <string>
+
+#include "content/common/content_export.h"
+
+namespace content {
+
+// A listener interface used for receiving updates on screen availability
+// associated with a presentation URL from an embedder.
+// See also PresentationServiceDelegate.
+class CONTENT_EXPORT PresentationScreenAvailabilityListener {
+ public:
+ virtual ~PresentationScreenAvailabilityListener() {}
+
+ // Returns the Presentation URL associated with this listener.
+ // Empty string means this object is listening for screen availability
+ // for "1-UA" mode, i.e. offscreen tab rendering.
+ virtual std::string GetPresentationUrl() const = 0;
+
+ // Called when screen availability for the associated Presentation URL has
+ // changed to |available|.
+ virtual void OnScreenAvailabilityChanged(bool available) = 0;
+};
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_BROWSER_PRESENTATION_SCREEN_AVAILABILITY_LISTENER_H_
+
diff --git a/chromium/content/public/browser/presentation_service_delegate.h b/chromium/content/public/browser/presentation_service_delegate.h
new file mode 100644
index 00000000000..9b3ca39ddd4
--- /dev/null
+++ b/chromium/content/public/browser/presentation_service_delegate.h
@@ -0,0 +1,163 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_PUBLIC_BROWSER_PRESENTATION_SERVICE_DELEGATE_H_
+#define CONTENT_PUBLIC_BROWSER_PRESENTATION_SERVICE_DELEGATE_H_
+
+#include <vector>
+
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "content/common/content_export.h"
+#include "content/public/browser/presentation_session.h"
+#include "content/public/browser/presentation_session_message.h"
+
+namespace content {
+
+class PresentationScreenAvailabilityListener;
+
+// An interface implemented by embedders to handle presentation API calls
+// forwarded from PresentationServiceImpl.
+class CONTENT_EXPORT PresentationServiceDelegate {
+ public:
+ // Observer interface to listen for changes to PresentationServiceDelegate.
+ class CONTENT_EXPORT Observer {
+ public:
+ // Called when the PresentationServiceDelegate is being destroyed.
+ virtual void OnDelegateDestroyed() = 0;
+
+ // Called when the default presentation has been started outside of a
+ // Presentation API context (e.g., browser action). This will not be called
+ // if the session was created as a result of Presentation API's
+ // StartSession()/JoinSession().
+ virtual void OnDefaultPresentationStarted(
+ const PresentationSessionInfo& session) = 0;
+
+ protected:
+ virtual ~Observer() {}
+ };
+
+ using PresentationSessionSuccessCallback =
+ base::Callback<void(const PresentationSessionInfo&)>;
+ using PresentationSessionErrorCallback =
+ base::Callback<void(const PresentationError&)>;
+ using PresentationSessionMessageCallback = base::Callback<void(
+ scoped_ptr<ScopedVector<PresentationSessionMessage>>)>;
+ using SendMessageCallback = base::Closure;
+
+ virtual ~PresentationServiceDelegate() {}
+
+ // Registers an observer associated with frame with |render_process_id|
+ // and |render_frame_id| with this class to listen for updates.
+ // This class does not own the observer.
+ // It is an error to add an observer if there is already an observer for that
+ // frame.
+ virtual void AddObserver(int render_process_id,
+ int render_frame_id,
+ Observer* observer) = 0;
+
+ // Unregisters the observer associated with the frame with |render_process_id|
+ // and |render_frame_id|.
+ // The observer will no longer receive updates.
+ virtual void RemoveObserver(int render_process_id, int render_frame_id) = 0;
+
+ // Registers |listener| to continuously listen for
+ // availability updates for a presentation URL, originated from the frame
+ // given by |render_process_id| and |render_frame_id|.
+ // This class does not own |listener|.
+ // Returns true on success.
+ // This call will return false if a listener with the same presentation URL
+ // from the same frame is already registered.
+ virtual bool AddScreenAvailabilityListener(
+ int render_process_id,
+ int render_frame_id,
+ PresentationScreenAvailabilityListener* listener) = 0;
+
+ // Unregisters |listener| originated from the frame given by
+ // |render_process_id| and |render_frame_id| from this class. The listener
+ // will no longer receive availability updates.
+ virtual void RemoveScreenAvailabilityListener(
+ int render_process_id,
+ int render_frame_id,
+ PresentationScreenAvailabilityListener* listener) = 0;
+
+ // Resets the presentation state for the frame given by |render_process_id|
+ // and |render_frame_id|.
+ // This unregisters all listeners associated with the given frame, and clears
+ // the default presentation URL and ID set for the frame.
+ virtual void Reset(
+ int render_process_id,
+ int render_frame_id) = 0;
+
+ // Sets the default presentation URL and ID for frame given by
+ // |render_process_id| and |render_frame_id|.
+ // If |default_presentation_url| is empty, the default presentation URL will
+ // be cleared.
+ virtual void SetDefaultPresentationUrl(
+ int render_process_id,
+ int render_frame_id,
+ const std::string& default_presentation_url,
+ const std::string& default_presentation_id) = 0;
+
+ // Starts a new presentation session.
+ // Typically, the embedder will allow the user to select a screen to show
+ // |presentation_url|.
+ // |render_process_id|, |render_frame_id|: ID of originating frame.
+ // |presentation_url|: URL of the presentation.
+ // |presentation_id|: The caller may provide an non-empty string to be used
+ // as the ID of the presentation. If empty, the default presentation ID
+ // will be used. If both are empty, the embedder will automatically generate
+ // one.
+ // |success_cb|: Invoked with session info, if presentation session started
+ // successfully.
+ // |error_cb|: Invoked with error reason, if presentation session did not
+ // start.
+ virtual void StartSession(
+ int render_process_id,
+ int render_frame_id,
+ const std::string& presentation_url,
+ const std::string& presentation_id,
+ const PresentationSessionSuccessCallback& success_cb,
+ const PresentationSessionErrorCallback& error_cb) = 0;
+
+ // Joins an existing presentation session. Unlike StartSession(), this
+ // does not bring a screen list UI.
+ // |render_process_id|, |render_frame_id|: ID for originating frame.
+ // |presentation_url|: URL of the presentation.
+ // |presentation_id|: The ID of the presentation to join.
+ // |success_cb|: Invoked with session info, if presentation session joined
+ // successfully.
+ // |error_cb|: Invoked with error reason, if joining failed.
+ virtual void JoinSession(
+ int render_process_id,
+ int render_frame_id,
+ const std::string& presentation_url,
+ const std::string& presentation_id,
+ const PresentationSessionSuccessCallback& success_cb,
+ const PresentationSessionErrorCallback& error_cb) = 0;
+
+ // Gets the next batch of messages from all presentation sessions in the frame
+ // |render_process_id|, |render_frame_id|: ID for originating frame.
+ // |message_cb|: Invoked with a non-empty list of messages.
+ virtual void ListenForSessionMessages(
+ int render_process_id,
+ int render_frame_id,
+ const PresentationSessionMessageCallback& message_cb) = 0;
+
+ // Sends a message (string or binary data) to a presentation session.
+ // |render_process_id|, |render_frame_id|: ID of originating frame.
+ // |message_request|: Contains Presentation URL, ID and message to be sent
+ // and delegate is responsible for deallocating the message_request.
+ // |send_message_cb|: Invoked after handling the send message request.
+ virtual void SendMessage(
+ int render_process_id,
+ int render_frame_id,
+ scoped_ptr<PresentationSessionMessage> message_request,
+ const SendMessageCallback& send_message_cb) = 0;
+};
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_BROWSER_PRESENTATION_SERVICE_DELEGATE_H_
diff --git a/chromium/content/public/browser/presentation_session.cc b/chromium/content/public/browser/presentation_session.cc
new file mode 100644
index 00000000000..cf6111da59e
--- /dev/null
+++ b/chromium/content/public/browser/presentation_session.cc
@@ -0,0 +1,30 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/public/browser/presentation_session.h"
+
+namespace content {
+
+PresentationSessionInfo::PresentationSessionInfo(
+ const std::string& presentation_url,
+ const std::string& presentation_id)
+ : presentation_url(presentation_url),
+ presentation_id(presentation_id) {
+}
+
+PresentationSessionInfo::~PresentationSessionInfo() {
+}
+
+PresentationError::PresentationError(
+ PresentationErrorType error_type,
+ const std::string& message)
+ : error_type(error_type),
+ message(message) {
+}
+
+PresentationError::~PresentationError() {
+}
+
+} // namespace content
+
diff --git a/chromium/content/public/browser/presentation_session.h b/chromium/content/public/browser/presentation_session.h
new file mode 100644
index 00000000000..028d49ac8f4
--- /dev/null
+++ b/chromium/content/public/browser/presentation_session.h
@@ -0,0 +1,45 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_PUBLIC_BROWSER_PRESENTATION_SESSION_H_
+#define CONTENT_PUBLIC_BROWSER_PRESENTATION_SESSION_H_
+
+#include <string>
+
+#include "content/common/content_export.h"
+
+namespace content {
+
+// Represents a presentation session that has been established via either
+// browser actions or Presentation API.
+struct CONTENT_EXPORT PresentationSessionInfo {
+ PresentationSessionInfo(const std::string& presentation_url,
+ const std::string& presentation_id);
+ ~PresentationSessionInfo();
+
+ const std::string presentation_url;
+ const std::string presentation_id;
+};
+
+// Possible reasons why an attempt to create a presentation session failed.
+enum CONTENT_EXPORT PresentationErrorType {
+ PRESENTATION_ERROR_NO_AVAILABLE_SCREENS,
+ PRESENTATION_ERROR_SESSION_REQUEST_CANCELLED,
+ PRESENTATION_ERROR_NO_PRESENTATION_FOUND,
+ PRESENTATION_ERROR_UNKNOWN,
+};
+
+// Struct returned when an attempt to create a presentation session failed.
+struct CONTENT_EXPORT PresentationError {
+ PresentationError(PresentationErrorType error_type,
+ const std::string& message);
+ ~PresentationError();
+
+ const PresentationErrorType error_type;
+ const std::string message;
+};
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_BROWSER_PRESENTATION_SESSION_H_
diff --git a/chromium/content/public/browser/presentation_session_message.cc b/chromium/content/public/browser/presentation_session_message.cc
new file mode 100644
index 00000000000..a03a055b004
--- /dev/null
+++ b/chromium/content/public/browser/presentation_session_message.cc
@@ -0,0 +1,56 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/public/browser/presentation_session_message.h"
+
+namespace content {
+
+PresentationSessionMessage::PresentationSessionMessage(
+ const std::string& presentation_url,
+ const std::string& presentation_id,
+ scoped_ptr<std::string> message)
+ : presentation_url(presentation_url),
+ presentation_id(presentation_id),
+ message(message.Pass()),
+ data(nullptr) {
+}
+
+PresentationSessionMessage::PresentationSessionMessage(
+ const std::string& presentation_url,
+ const std::string& presentation_id,
+ scoped_ptr<std::vector<uint8_t>> data)
+ : presentation_url(presentation_url),
+ presentation_id(presentation_id),
+ message(nullptr),
+ data(data.Pass()) {
+}
+
+// static
+scoped_ptr<PresentationSessionMessage>
+PresentationSessionMessage::CreateStringMessage(
+ const std::string& presentation_url,
+ const std::string& presentation_id,
+ scoped_ptr<std::string> message) {
+ return scoped_ptr<PresentationSessionMessage>(new PresentationSessionMessage(
+ presentation_url, presentation_id, message.Pass()));
+}
+
+// static
+scoped_ptr<PresentationSessionMessage>
+PresentationSessionMessage::CreateBinaryMessage(
+ const std::string& presentation_url,
+ const std::string& presentation_id,
+ scoped_ptr<std::vector<uint8_t>> data) {
+ return scoped_ptr<PresentationSessionMessage>(new PresentationSessionMessage(
+ presentation_url, presentation_id, data.Pass()));
+}
+
+bool PresentationSessionMessage::is_binary() const {
+ return data != nullptr;
+}
+
+PresentationSessionMessage::~PresentationSessionMessage() {
+}
+
+} // namespace content
diff --git a/chromium/content/public/browser/presentation_session_message.h b/chromium/content/public/browser/presentation_session_message.h
new file mode 100644
index 00000000000..54f65fcc84e
--- /dev/null
+++ b/chromium/content/public/browser/presentation_session_message.h
@@ -0,0 +1,52 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_PUBLIC_BROWSER_PRESENTATION_SESSION_MESSAGE_H_
+#define CONTENT_PUBLIC_BROWSER_PRESENTATION_SESSION_MESSAGE_H_
+
+#include <string>
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "content/common/content_export.h"
+
+namespace content {
+
+// Represents a presentation session message.
+// If this is a text message, |data| is null; otherwise, |message| is null.
+// Empty messages are allowed.
+struct CONTENT_EXPORT PresentationSessionMessage {
+ public:
+ ~PresentationSessionMessage();
+
+ // Creates string message, which takes the ownership of |message|.
+ static scoped_ptr<PresentationSessionMessage> CreateStringMessage(
+ const std::string& presentation_url,
+ const std::string& presentation_id,
+ scoped_ptr<std::string> message);
+
+ // Creates binary message, which takes the ownership of |data|.
+ static scoped_ptr<PresentationSessionMessage> CreateBinaryMessage(
+ const std::string& presentation_url,
+ const std::string& presentation_id,
+ scoped_ptr<std::vector<uint8_t>> data);
+
+ bool is_binary() const;
+ std::string presentation_url;
+ std::string presentation_id;
+ scoped_ptr<std::string> message;
+ scoped_ptr<std::vector<uint8_t>> data;
+
+ private:
+ PresentationSessionMessage(const std::string& presentation_url,
+ const std::string& presentation_id,
+ scoped_ptr<std::string> message);
+ PresentationSessionMessage(const std::string& presentation_url,
+ const std::string& presentation_id,
+ scoped_ptr<std::vector<uint8_t>> data);
+};
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_BROWSER_PRESENTATION_SESSION_H_
diff --git a/chromium/content/public/browser/profiler_controller.h b/chromium/content/public/browser/profiler_controller.h
index e9fbe6a149a..34ac03f231b 100644
--- a/chromium/content/public/browser/profiler_controller.h
+++ b/chromium/content/public/browser/profiler_controller.h
@@ -25,8 +25,8 @@ class ProfilerSubscriber;
// object.
class CONTENT_EXPORT ProfilerController {
public:
- // Returns the ProfilerController object for the current process, or NULL if
- // none.
+ // Returns the ProfilerController object for the current process, or nullptr
+ // if none.
static ProfilerController* GetInstance();
virtual ~ProfilerController() {}
@@ -42,7 +42,14 @@ class CONTENT_EXPORT ProfilerController {
virtual void Unregister(const ProfilerSubscriber* subscriber) = 0;
// Contact all processes and get their profiler data.
- virtual void GetProfilerData(int sequence_number) = 0;
+ // |current_profiling_phase| is the 0-indexed identifier of the current
+ // profiling phase.
+ virtual void GetProfilerData(int sequence_number,
+ int current_profiling_phase) = 0;
+
+ // Contact child processes and notify them that the |profiling_phase| has
+ // completed.
+ virtual void OnProfilingPhaseCompleted(int profiling_phase) = 0;
};
} // namespace content
diff --git a/chromium/content/public/browser/profiler_subscriber.h b/chromium/content/public/browser/profiler_subscriber.h
index 102de1ae422..a70918d9fcb 100644
--- a/chromium/content/public/browser/profiler_subscriber.h
+++ b/chromium/content/public/browser/profiler_subscriber.h
@@ -6,6 +6,7 @@
#define CONTENT_PUBLIC_BROWSER_PROFILER_SUBSCRIBER_H_
#include "content/common/content_export.h"
+#include "content/public/common/process_type.h"
namespace tracked_objects {
struct ProcessDataSnapshot;
@@ -27,7 +28,7 @@ class CONTENT_EXPORT ProfilerSubscriber {
virtual void OnProfilerDataCollected(
int sequence_number,
const tracked_objects::ProcessDataSnapshot& profiler_data,
- int process_type) = 0;
+ content::ProcessType process_type) = 0;
protected:
virtual ~ProfilerSubscriber() {}
diff --git a/chromium/content/public/browser/push_messaging_service.cc b/chromium/content/public/browser/push_messaging_service.cc
new file mode 100644
index 00000000000..27335eb9adf
--- /dev/null
+++ b/chromium/content/public/browser/push_messaging_service.cc
@@ -0,0 +1,160 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/public/browser/push_messaging_service.h"
+
+#include "base/callback.h"
+#include "content/browser/push_messaging/push_messaging_message_filter.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"
+
+namespace content {
+
+namespace {
+
+const char kNotificationsShownServiceWorkerKey[] =
+ "notifications_shown_by_last_few_pushes";
+
+void CallStringCallbackFromIO(
+ const PushMessagingService::StringCallback& callback,
+ const std::string& data,
+ ServiceWorkerStatusCode service_worker_status) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ bool success = service_worker_status == SERVICE_WORKER_OK;
+ bool not_found = service_worker_status == SERVICE_WORKER_ERROR_NOT_FOUND;
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(callback, data, success, not_found));
+}
+
+void CallResultCallbackFromIO(
+ const ServiceWorkerContext::ResultCallback& callback,
+ ServiceWorkerStatusCode service_worker_status) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ bool success = service_worker_status == SERVICE_WORKER_OK;
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(callback, success));
+}
+
+void CallClosureFromIO(const base::Closure& callback,
+ ServiceWorkerStatusCode status) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
+}
+
+void GetUserDataOnIO(
+ scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_wrapper,
+ int64 service_worker_registration_id,
+ const std::string& key,
+ const PushMessagingService::StringCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ service_worker_context_wrapper->GetRegistrationUserData(
+ service_worker_registration_id, key,
+ base::Bind(&CallStringCallbackFromIO, callback));
+}
+
+void SetNotificationsShownOnIO(
+ scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_wrapper,
+ int64 service_worker_registration_id, const GURL& origin,
+ const std::string& data,
+ const PushMessagingService::ResultCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ service_worker_context_wrapper->StoreRegistrationUserData(
+ service_worker_registration_id, origin,
+ kNotificationsShownServiceWorkerKey, data,
+ base::Bind(&CallResultCallbackFromIO, callback));
+}
+
+void ClearPushRegistrationIDOnIO(
+ scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
+ int64 service_worker_registration_id,
+ const base::Closure& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ service_worker_context->ClearRegistrationUserData(
+ service_worker_registration_id,
+ kPushRegistrationIdServiceWorkerKey,
+ base::Bind(&CallClosureFromIO, callback));
+}
+
+scoped_refptr<ServiceWorkerContextWrapper> GetServiceWorkerContext(
+ BrowserContext* browser_context, const GURL& origin) {
+ StoragePartition* partition =
+ BrowserContext::GetStoragePartitionForSite(browser_context, origin);
+ return make_scoped_refptr(
+ static_cast<ServiceWorkerContextWrapper*>(
+ partition->GetServiceWorkerContext()));
+}
+
+} // anonymous namespace
+
+// static
+void PushMessagingService::GetNotificationsShownByLastFewPushes(
+ ServiceWorkerContext* service_worker_context,
+ int64 service_worker_registration_id,
+ const StringCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ scoped_refptr<ServiceWorkerContextWrapper> wrapper =
+ static_cast<ServiceWorkerContextWrapper*>(service_worker_context);
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(&GetUserDataOnIO,
+ wrapper,
+ service_worker_registration_id,
+ kNotificationsShownServiceWorkerKey,
+ callback));
+}
+
+// static
+void PushMessagingService::SetNotificationsShownByLastFewPushes(
+ ServiceWorkerContext* service_worker_context,
+ int64 service_worker_registration_id,
+ const GURL& origin,
+ const std::string& notifications_shown,
+ const ResultCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ scoped_refptr<ServiceWorkerContextWrapper> wrapper =
+ static_cast<ServiceWorkerContextWrapper*>(service_worker_context);
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(&SetNotificationsShownOnIO,
+ wrapper,
+ service_worker_registration_id,
+ origin,
+ notifications_shown,
+ callback));
+}
+
+// static
+void PushMessagingService::GetSenderId(BrowserContext* browser_context,
+ const GURL& origin,
+ int64 service_worker_registration_id,
+ const StringCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&GetUserDataOnIO,
+ GetServiceWorkerContext(browser_context, origin),
+ service_worker_registration_id,
+ kPushSenderIdServiceWorkerKey,
+ callback));
+}
+
+// static
+void PushMessagingService::ClearPushRegistrationID(
+ BrowserContext* browser_context,
+ const GURL& origin,
+ int64 service_worker_registration_id,
+ const base::Closure& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&ClearPushRegistrationIDOnIO,
+ GetServiceWorkerContext(browser_context, origin),
+ service_worker_registration_id,
+ callback));
+}
+
+} // namespace content
diff --git a/chromium/content/public/browser/push_messaging_service.h b/chromium/content/public/browser/push_messaging_service.h
index d0cd124a823..d772f45091a 100644
--- a/chromium/content/public/browser/push_messaging_service.h
+++ b/chromium/content/public/browser/push_messaging_service.h
@@ -7,40 +7,108 @@
#include <string>
-#include "base/callback.h"
+#include "base/callback_forward.h"
#include "content/common/content_export.h"
#include "content/public/common/push_messaging_status.h"
-#include "third_party/WebKit/public/platform/WebPushPermissionStatus.h"
+#include "third_party/WebKit/public/platform/modules/push_messaging/WebPushPermissionStatus.h"
#include "url/gurl.h"
namespace content {
+class BrowserContext;
+class ServiceWorkerContext;
+
// A push service-agnostic interface that the Push API uses for talking to
-// push messaging services like GCM.
+// push messaging services like GCM. Must only be used on the UI thread.
class CONTENT_EXPORT PushMessagingService {
public:
- typedef base::Callback<void(const GURL& /* endpoint */,
- const std::string& /* registration_id */,
- PushRegistrationStatus /* status */)>
- RegisterCallback;
+ using RegisterCallback =
+ base::Callback<void(const std::string& /* registration_id */,
+ PushRegistrationStatus /* status */)>;
+ using UnregisterCallback = base::Callback<void(PushUnregistrationStatus)>;
+
+ using StringCallback = base::Callback<void(const std::string& data,
+ bool success,
+ bool not_found)>;
+
+ using ResultCallback = base::Callback<void(bool success)>;
virtual ~PushMessagingService() {}
- // Register the given |sender_id| with GCM.
- virtual void Register(const GURL& origin,
- int64 service_worker_registration_id,
- const std::string& sender_id,
- int renderer_id,
- int render_frame_id,
- bool user_gesture,
- const RegisterCallback& callback) = 0;
-
- // Check whether the requester has permission to register for Push
- // Messages
+ // Returns the absolute URL exposed by the push server where the webapp server
+ // can send push messages. This is currently assumed to be the same for all
+ // origins and push registrations.
+ virtual GURL GetPushEndpoint() = 0;
+
+ // Register the given |sender_id| with the push messaging service in a
+ // document context. The frame is known and a permission UI may be displayed
+ // to the user.
+ virtual void RegisterFromDocument(const GURL& requesting_origin,
+ int64 service_worker_registration_id,
+ const std::string& sender_id,
+ int renderer_id,
+ int render_frame_id,
+ bool user_visible,
+ const RegisterCallback& callback) = 0;
+
+ // Register the given |sender_id| with the push messaging service. The frame
+ // is not known so if permission was not previously granted by the user this
+ // request should fail.
+ virtual void RegisterFromWorker(const GURL& requesting_origin,
+ int64 service_worker_registration_id,
+ const std::string& sender_id,
+ bool user_visible,
+ const RegisterCallback& callback) = 0;
+
+ // Unregister the given |sender_id| from the push messaging service. The
+ // registration will be synchronously deactivated locally, and asynchronously
+ // sent to the push service, with automatic retry.
+ virtual void Unregister(const GURL& requesting_origin,
+ int64 service_worker_registration_id,
+ const std::string& sender_id,
+ const UnregisterCallback& callback) = 0;
+
+ // Checks the permission status for the requesting origin. Permission is only
+ // ever granted when the requesting origin matches the top level embedding
+ // origin. The |user_visible| boolean indicates whether the permission status
+ // only has to cover push messages resulting in visible effects to the user.
virtual blink::WebPushPermissionStatus GetPermissionStatus(
const GURL& requesting_origin,
- int renderer_id,
- int render_frame_id) = 0;
+ const GURL& embedding_origin,
+ bool user_visible) = 0;
+
+ // Returns whether subscriptions that do not mandate user visible UI upon
+ // receiving a push message are supported. Influences permission request and
+ // permission check behaviour.
+ virtual bool SupportNonVisibleMessages() = 0;
+
+ // Provide a storage mechanism to read/write an opaque
+ // "notifications_shown_by_last_few_pushes" string associated with a Service
+ // Worker registration. Stored data is deleted when the associated
+ // registration is deleted.
+ static void GetNotificationsShownByLastFewPushes(
+ ServiceWorkerContext* service_worker_context,
+ int64 service_worker_registration_id,
+ const StringCallback& callback);
+ static void SetNotificationsShownByLastFewPushes(
+ ServiceWorkerContext* service_worker_context,
+ int64 service_worker_registration_id,
+ const GURL& origin,
+ const std::string& notifications_shown,
+ const ResultCallback& callback);
+
+ protected:
+ static void GetSenderId(BrowserContext* browser_context,
+ const GURL& origin,
+ int64 service_worker_registration_id,
+ const StringCallback& callback);
+
+ // Clear the push registration id stored in the service worker with the given
+ // |service_worker_registration_id| for the given |origin|.
+ static void ClearPushRegistrationID(BrowserContext* browser_context,
+ const GURL& origin,
+ int64 service_worker_registration_id,
+ const base::Closure& callback);
};
} // namespace content
diff --git a/chromium/content/public/browser/readback_types.h b/chromium/content/public/browser/readback_types.h
new file mode 100644
index 00000000000..4929ab9de9c
--- /dev/null
+++ b/chromium/content/public/browser/readback_types.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_PUBLIC_BROWSER_READBACK_TYPES_H_
+#define CONTENT_PUBLIC_BROWSER_READBACK_TYPES_H_
+
+#include "base/callback.h"
+
+class SkBitmap;
+
+namespace content {
+
+// ReadbackResponse type used in ContentReadbackHandler.
+//
+// A Java counterpart will be generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: (
+// org.chromium.content_public.browser.readback_types)
+// GENERATED_JAVA_PREFIX_TO_STRIP: READBACK_
+enum ReadbackResponse {
+ READBACK_SUCCESS,
+ READBACK_FAILED,
+ READBACK_SURFACE_UNAVAILABLE,
+ READBACK_BITMAP_ALLOCATION_FAILURE,
+};
+
+typedef const base::Callback<void(const SkBitmap&, ReadbackResponse)>
+ ReadbackRequestCallback;
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_BROWSER_READBACK_TYPES_H_
diff --git a/chromium/content/public/browser/render_frame_host.h b/chromium/content/public/browser/render_frame_host.h
index 53032b4ccf6..2b0c5dddeac 100644
--- a/chromium/content/public/browser/render_frame_host.h
+++ b/chromium/content/public/browser/render_frame_host.h
@@ -11,8 +11,9 @@
#include "content/common/content_export.h"
#include "ipc/ipc_listener.h"
#include "ipc/ipc_sender.h"
+#include "third_party/WebKit/public/platform/WebPageVisibilityState.h"
+#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/rect.h"
#include "url/gurl.h"
namespace base {
@@ -30,7 +31,7 @@ class CONTENT_EXPORT RenderFrameHost : public IPC::Listener,
public IPC::Sender {
public:
// Returns the RenderFrameHost given its ID and the ID of its render process.
- // Returns NULL if the IDs do not correspond to a live RenderFrameHost.
+ // Returns nullptr if the IDs do not correspond to a live RenderFrameHost.
static RenderFrameHost* FromID(int render_process_id, int render_frame_id);
~RenderFrameHost() override {}
@@ -46,9 +47,9 @@ class CONTENT_EXPORT RenderFrameHost : public IPC::Listener,
// Returns the process for this frame.
virtual RenderProcessHost* GetProcess() = 0;
- // Returns the current RenderFrameHost of the parent frame, or NULL if there
- // is no parent. The result may be in a different process than the current
- // RenderFrameHost.
+ // Returns the current RenderFrameHost of the parent frame, or nullptr if
+ // there is no parent. The result may be in a different process than the
+ // current RenderFrameHost.
virtual RenderFrameHost* GetParent() = 0;
// Returns the assigned name of the frame, the name of the iframe tag
@@ -72,10 +73,15 @@ class CONTENT_EXPORT RenderFrameHost : public IPC::Listener,
virtual void ExecuteJavaScript(const base::string16& javascript) = 0;
virtual void ExecuteJavaScript(const base::string16& javascript,
const JavaScriptResultCallback& callback) = 0;
+ virtual void ExecuteJavaScriptInIsolatedWorld(
+ const base::string16& javascript,
+ const JavaScriptResultCallback& callback,
+ int world_id) = 0;
// ONLY FOR TESTS: Same as above but adds a fake UserGestureIndicator around
// execution. (crbug.com/408426)
- virtual void ExecuteJavaScriptForTests(const base::string16& javascript) = 0;
+ virtual void ExecuteJavaScriptWithUserGestureForTests(
+ const base::string16& javascript) = 0;
// Accessibility actions - these send a message to the RenderFrame
// to trigger an action on an accessibility object.
@@ -93,12 +99,25 @@ class CONTENT_EXPORT RenderFrameHost : public IPC::Listener,
// result.
virtual void ActivateFindInPageResultForAccessibility(int request_id) = 0;
+ // Roundtrips through the renderer and compositor pipeline to ensure that any
+ // changes to the contents resulting from operations executed prior to this
+ // call are visible on screen. The call completes asynchronously by running
+ // the supplied |callback| with a value of true upon successful completion and
+ // false otherwise (when the frame is destroyed, detached, etc..).
+ typedef base::Callback<void(bool)> VisualStateCallback;
+ virtual void InsertVisualStateCallback(
+ const VisualStateCallback& callback) = 0;
+
// Temporary until we get rid of RenderViewHost.
virtual RenderViewHost* GetRenderViewHost() = 0;
// Returns the ServiceRegistry for this frame.
virtual ServiceRegistry* GetServiceRegistry() = 0;
+ // Returns the visibility state of the frame. The different visibility states
+ // of a frame are defined in Blink.
+ virtual blink::WebPageVisibilityState GetVisibilityState() = 0;
+
private:
// This interface should only be implemented inside content.
friend class RenderFrameHostImpl;
diff --git a/chromium/content/public/browser/render_process_host.h b/chromium/content/public/browser/render_process_host.h
index 4ae7f3a282a..ca5cdf8b98b 100644
--- a/chromium/content/public/browser/render_process_host.h
+++ b/chromium/content/public/browser/render_process_host.h
@@ -5,6 +5,8 @@
#ifndef CONTENT_PUBLIC_BROWSER_RENDER_PROCESS_HOST_H_
#define CONTENT_PUBLIC_BROWSER_RENDER_PROCESS_HOST_H_
+#include <list>
+
#include "base/basictypes.h"
#include "base/id_map.h"
#include "base/process/kill.h"
@@ -22,6 +24,15 @@ namespace base {
class TimeDelta;
}
+namespace gpu {
+union ValueState;
+}
+
+namespace media {
+class AudioOutputController;
+class BrowserCdm;
+}
+
namespace content {
class BrowserContext;
class BrowserMessageFilter;
@@ -42,14 +53,11 @@ class CONTENT_EXPORT RenderProcessHost : public IPC::Sender,
// Details for RENDERER_PROCESS_CLOSED notifications.
struct RendererClosedDetails {
- RendererClosedDetails(base::ProcessHandle handle,
- base::TerminationStatus status,
+ RendererClosedDetails(base::TerminationStatus status,
int exit_code) {
- this->handle = handle;
this->status = status;
this->exit_code = exit_code;
}
- base::ProcessHandle handle;
base::TerminationStatus status;
int exit_code;
};
@@ -80,8 +88,11 @@ class CONTENT_EXPORT RenderProcessHost : public IPC::Sender,
virtual void AddObserver(RenderProcessHostObserver* observer) = 0;
virtual void RemoveObserver(RenderProcessHostObserver* observer) = 0;
- // Called when a received message cannot be decoded.
- virtual void ReceivedBadMessage() = 0;
+ // Called when a received message cannot be decoded. Terminates the renderer.
+ // Most callers should not call this directly, but instead should call
+ // bad_message::BadMessageReceived() or an equivalent method outside of the
+ // content module.
+ virtual void ShutdownForBadMessage() = 0;
// Track the count of visible widgets. Called by listeners to register and
// unregister visibility.
@@ -102,18 +113,21 @@ class CONTENT_EXPORT RenderProcessHost : public IPC::Sender,
// http://crbug.com/158595
virtual StoragePartition* GetStoragePartition() const = 0;
- // Try to shutdown the associated renderer process as fast as possible.
+ // Try to shut down the associated renderer process without running unload
+ // handlers, etc, giving it the specified exit code. If |wait| is true, wait
+ // for the process to be actually terminated before returning.
+ // Returns true if it was able to shut down.
+ virtual bool Shutdown(int exit_code, bool wait) = 0;
+
+ // Try to shut down the associated renderer process as fast as possible.
// If this renderer has any RenderViews with unload handlers, then this
- // function does nothing. The current implementation uses TerminateProcess.
- // Returns True if it was able to do fast shutdown.
+ // function does nothing.
+ // Returns true if it was able to do fast shutdown.
virtual bool FastShutdownIfPossible() = 0;
// Returns true if fast shutdown was started for the renderer.
virtual bool FastShutdownStarted() const = 0;
- // Dump the child process' handle table before shutting down.
- virtual void DumpHandles() = 0;
-
// Returns the process object associated with the child process. In certain
// tests or single-process mode, this will actually represent the current
// process.
@@ -140,8 +154,8 @@ class CONTENT_EXPORT RenderProcessHost : public IPC::Sender,
// This will never return ChildProcessHost::kInvalidUniqueID.
virtual int GetID() const = 0;
- // Returns true iff channel_ has been set to non-NULL. Use this for checking
- // if there is connection or not. Virtual for mocking out for tests.
+ // Returns true iff channel_ has been set to non-nullptr. Use this for
+ // checking if there is connection or not. Virtual for mocking out for tests.
virtual bool HasConnection() const = 0;
// Call this to allow queueing of IPC messages that are sent before the
@@ -224,7 +238,7 @@ class CONTENT_EXPORT RenderProcessHost : public IPC::Sender,
// Notifies the renderer that the timezone configuration of the system might
// have changed.
- virtual void NotifyTimezoneChange() = 0;
+ virtual void NotifyTimezoneChange(const std::string& zone_id) = 0;
// Returns the ServiceRegistry for this process.
virtual ServiceRegistry* GetServiceRegistry() = 0;
@@ -236,6 +250,39 @@ class CONTENT_EXPORT RenderProcessHost : public IPC::Sender,
// Note: Do not use! Will disappear after PlzNavitate is completed.
virtual const base::TimeTicks& GetInitTimeForNavigationMetrics() const = 0;
+ // Returns whether or not the CHROMIUM_subscribe_uniform WebGL extension
+ // is currently enabled
+ virtual bool SubscribeUniformEnabled() const = 0;
+
+ // Handlers for subscription target changes to update subscription_set_
+ virtual void OnAddSubscription(unsigned int target) = 0;
+ virtual void OnRemoveSubscription(unsigned int target) = 0;
+
+ // Send a new ValueState to the Gpu Service to update a subscription target
+ virtual void SendUpdateValueState(
+ unsigned int target, const gpu::ValueState& state) = 0;
+
+ // Retrieves the list of AudioOutputController objects associated
+ // with this object and passes it to the callback you specify, on
+ // the same thread on which you called the method.
+ typedef std::list<scoped_refptr<media::AudioOutputController>>
+ AudioOutputControllerList;
+ typedef base::Callback<void(const AudioOutputControllerList&)>
+ GetAudioOutputControllersCallback;
+ virtual void GetAudioOutputControllers(
+ const GetAudioOutputControllersCallback& callback) const = 0;
+
+#if defined(ENABLE_BROWSER_CDMS)
+ // Returns the ::media::BrowserCdm instance associated with |render_frame_id|
+ // and |cdm_id|, or nullptr if not found.
+ virtual media::BrowserCdm* GetBrowserCdm(int render_frame_id,
+ int cdm_id) const = 0;
+#endif
+
+ // Returns the current number of active views in this process. Excludes
+ // any RenderViewHosts that are swapped out.
+ int GetActiveViewCount();
+
// Static management functions -----------------------------------------------
// Flag to run the renderer in process. This is primarily
@@ -252,10 +299,10 @@ class CONTENT_EXPORT RenderProcessHost : public IPC::Sender,
static void SetRunRendererInProcess(bool value);
// Allows iteration over all the RenderProcessHosts in the browser. Note
- // that each host may not be active, and therefore may have NULL channels.
+ // that each host may not be active, and therefore may have nullptr channels.
static iterator AllHostsIterator();
- // Returns the RenderProcessHost given its ID. Returns NULL if the ID does
+ // Returns the RenderProcessHost given its ID. Returns nullptr if the ID does
// not correspond to a live RenderProcessHost.
static RenderProcessHost* FromID(int render_process_id);
@@ -274,7 +321,7 @@ class CONTENT_EXPORT RenderProcessHost : public IPC::Sender,
// context, if possible. The renderer process is chosen randomly from
// suitable renderers that share the same context and type (determined by the
// site url).
- // Returns NULL if no suitable renderer process is available, in which case
+ // Returns nullptr if no suitable renderer process is available, in which case
// the caller is free to create a new renderer.
static RenderProcessHost* GetExistingProcessHost(
content::BrowserContext* browser_context, const GURL& site_url);
diff --git a/chromium/content/public/browser/render_view_host.h b/chromium/content/public/browser/render_view_host.h
index b3308d18aae..5909d286f41 100644
--- a/chromium/content/public/browser/render_view_host.h
+++ b/chromium/content/public/browser/render_view_host.h
@@ -5,15 +5,13 @@
#ifndef CONTENT_PUBLIC_BROWSER_RENDER_VIEW_HOST_H_
#define CONTENT_PUBLIC_BROWSER_RENDER_VIEW_HOST_H_
-#include <list>
-
#include "base/callback_forward.h"
#include "content/common/content_export.h"
#include "content/public/browser/render_widget_host.h"
#include "content/public/common/file_chooser_params.h"
#include "content/public/common/page_zoom.h"
-#include "mojo/public/cpp/system/core.h"
#include "third_party/WebKit/public/web/WebDragOperation.h"
+#include "third_party/mojo/src/mojo/public/cpp/system/core.h"
class GURL;
@@ -31,10 +29,6 @@ namespace gfx {
class Point;
}
-namespace media {
-class AudioOutputController;
-}
-
namespace content {
class ChildProcessSecurityPolicy;
@@ -57,10 +51,17 @@ struct WebPreferences;
// The intent of this interface is to provide a view-agnostic communication
// conduit with a renderer. This is so we can build HTML views not only as
// WebContents (see WebContents for an example) but also as views, etc.
+//
+// DEPRECATED: RenderViewHost is being removed as part of the SiteIsolation
+// project. New code should not be added here, but to either RenderFrameHost
+// (if frame specific) or WebContents (if page specific).
+//
+// For context, please see https://crbug.com/467770 and
+// http://www.chromium.org/developers/design-documents/site-isolation.
class CONTENT_EXPORT RenderViewHost : virtual public RenderWidgetHost {
public:
// Returns the RenderViewHost given its ID and the ID of its render process.
- // Returns NULL if the IDs do not correspond to a live RenderViewHost.
+ // Returns nullptr if the IDs do not correspond to a live RenderViewHost.
static RenderViewHost* FromID(int render_process_id, int render_view_id);
// Downcasts from a RenderWidgetHost to a RenderViewHost. Required
@@ -82,11 +83,6 @@ class CONTENT_EXPORT RenderViewHost : virtual public RenderWidgetHost {
// Returns true if the current focused element is editable.
virtual bool IsFocusedElementEditable() = 0;
- // Causes the renderer to close the current page, including running its
- // onunload event handler. A ClosePage_ACK message will be sent to the
- // ResourceDispatcherHost when it is finished.
- virtual void ClosePage() = 0;
-
// Copies the image at location x, y to the clipboard (if there indeed is an
// image at that location).
virtual void CopyImageAt(int x, int y) = 0;
@@ -153,9 +149,6 @@ class CONTENT_EXPORT RenderViewHost : virtual public RenderWidgetHost {
virtual void ExecutePluginActionAtLocation(
const gfx::Point& location, const blink::WebPluginAction& action) = 0;
- // Asks the renderer to exit fullscreen
- virtual void ExitFullscreen() = 0;
-
// Notifies the Listener that one or more files have been chosen by the user
// from a file chooser dialog for the form. |permissions| is the file
// selection mode in which the chooser dialog was created.
@@ -171,8 +164,7 @@ class CONTENT_EXPORT RenderViewHost : virtual public RenderWidgetHost {
virtual SiteInstance* GetSiteInstance() const = 0;
- // Returns true if the RenderView is active and has not crashed. Virtual
- // because it is overridden by TestRenderViewHost.
+ // Returns true if the RenderView is active and has not crashed.
virtual bool IsRenderViewLive() const = 0;
// Notification that a move or resize renderer's containing window has
@@ -202,16 +194,6 @@ class CONTENT_EXPORT RenderViewHost : virtual public RenderWidgetHost {
// Passes a list of Webkit preferences to the renderer.
virtual void UpdateWebkitPreferences(const WebPreferences& prefs) = 0;
- // Retrieves the list of AudioOutputController objects associated
- // with this object and passes it to the callback you specify, on
- // the same thread on which you called the method.
- typedef std::list<scoped_refptr<media::AudioOutputController> >
- AudioOutputControllerList;
- typedef base::Callback<void(const AudioOutputControllerList&)>
- GetAudioOutputControllersCallback;
- virtual void GetAudioOutputControllers(
- const GetAudioOutputControllersCallback& callback) const = 0;
-
// Notify the render view host to select the word around the caret.
virtual void SelectWordAroundCaret() = 0;
diff --git a/chromium/content/public/browser/render_widget_host.h b/chromium/content/public/browser/render_widget_host.h
index e37c3cdce5e..d770c4ce864 100644
--- a/chromium/content/public/browser/render_widget_host.h
+++ b/chromium/content/public/browser/render_widget_host.h
@@ -8,12 +8,13 @@
#include "base/callback.h"
#include "content/common/content_export.h"
#include "content/public/browser/native_web_keyboard_event.h"
+#include "content/public/browser/readback_types.h"
#include "ipc/ipc_channel.h"
#include "ipc/ipc_sender.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
#include "third_party/WebKit/public/web/WebTextDirection.h"
#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/gfx/size.h"
+#include "ui/gfx/geometry/size.h"
#include "ui/surface/transport_dib.h"
#if defined(OS_MACOSX)
@@ -70,7 +71,7 @@ class RenderWidgetHostView;
//
// The lifetime of the RenderWidgetHostView is tied to the render process. If
// the render process dies, the RenderWidgetHostView goes away and all
-// references to it must become NULL.
+// references to it must become nullptr.
//
// RenderViewHost (a RenderWidgetHost subclass) is the conduit used to
// communicate with the RenderView and is owned by the WebContents. If the
@@ -107,7 +108,7 @@ class RenderWidgetHostView;
class CONTENT_EXPORT RenderWidgetHost : public IPC::Sender {
public:
// Returns the RenderWidgetHost given its ID and the ID of its render process.
- // Returns NULL if the IDs do not correspond to a live RenderWidgetHost.
+ // Returns nullptr if the IDs do not correspond to a live RenderWidgetHost.
static RenderWidgetHost* FromID(int32 process_id, int32 routing_id);
// Returns an iterator to iterate over the global list of active render widget
@@ -177,11 +178,10 @@ class CONTENT_EXPORT RenderWidgetHost : public IPC::Sender {
// NOTE: |callback| is called synchronously if the backing store is available.
// When accelerated compositing is active, |callback| may be called
// asynchronously.
- virtual void CopyFromBackingStore(
- const gfx::Rect& src_rect,
- const gfx::Size& accelerated_dst_size,
- const base::Callback<void(bool, const SkBitmap&)>& callback,
- const SkColorType color_type) = 0;
+ virtual void CopyFromBackingStore(const gfx::Rect& src_rect,
+ const gfx::Size& accelerated_dst_size,
+ ReadbackRequestCallback& callback,
+ const SkColorType color_type) = 0;
// Ensures that the view does not drop the backing store even when hidden.
virtual bool CanCopyFromBackingStore() = 0;
#if defined(OS_ANDROID)
@@ -202,10 +202,10 @@ class CONTENT_EXPORT RenderWidgetHost : public IPC::Sender {
virtual int GetRoutingID() const = 0;
- // Gets the View of this RenderWidgetHost. Can be NULL, e.g. if the
+ // Gets the View of this RenderWidgetHost. Can be nullptr, e.g. if the
// RenderWidget is being destroyed or the render process crashed. You should
- // never cache this pointer since it can become NULL if the renderer crashes,
- // instead you should always ask for it using the accessor.
+ // never cache this pointer since it can become nullptr if the renderer
+ // crashes, instead you should always ask for it using the accessor.
virtual RenderWidgetHostView* GetView() const = 0;
// Returns true if the renderer is loading, false if not.
@@ -249,8 +249,6 @@ class CONTENT_EXPORT RenderWidgetHost : public IPC::Sender {
// Get the screen info corresponding to this render widget.
virtual void GetWebScreenInfo(blink::WebScreenInfo* result) = 0;
- virtual SkColorType PreferredReadbackFormat() = 0;
-
protected:
friend class RenderWidgetHostImpl;
diff --git a/chromium/content/public/browser/render_widget_host_iterator.h b/chromium/content/public/browser/render_widget_host_iterator.h
index 508fddbf3a9..c18be800d97 100644
--- a/chromium/content/public/browser/render_widget_host_iterator.h
+++ b/chromium/content/public/browser/render_widget_host_iterator.h
@@ -15,7 +15,7 @@ class RenderWidgetHostIterator {
public:
virtual ~RenderWidgetHostIterator() {}
- // Returns the next RenderWidgetHost in the list. Returns NULL if none is
+ // Returns the next RenderWidgetHost in the list. Returns nullptr if none is
// available.
virtual RenderWidgetHost* GetNextHost() = 0;
};
diff --git a/chromium/content/public/browser/render_widget_host_view.h b/chromium/content/public/browser/render_widget_host_view.h
index 6d97fd898ef..d503fa9db67 100644
--- a/chromium/content/public/browser/render_widget_host_view.h
+++ b/chromium/content/public/browser/render_widget_host_view.h
@@ -48,8 +48,8 @@ class CONTENT_EXPORT RenderWidgetHostView {
virtual ~RenderWidgetHostView() {}
// Initialize this object for use as a drawing area. |parent_view| may be
- // left as NULL on platforms where a parent view is not required to initialize
- // a child window.
+ // left as nullptr on platforms where a parent view is not required to
+ // initialize a child window.
virtual void InitAsChild(gfx::NativeView parent_view) = 0;
// Returns the associated RenderWidgetHost.
@@ -71,7 +71,7 @@ class CONTENT_EXPORT RenderWidgetHostView {
virtual gfx::NativeViewId GetNativeViewId() const = 0;
virtual gfx::NativeViewAccessible GetNativeViewAccessible() = 0;
- // Returns a ui::TextInputClient to support text input or NULL if this RWHV
+ // Returns a ui::TextInputClient to support text input or nullptr if this RWHV
// doesn't support text input.
// Note: Not all the platforms use ui::InputMethod and ui::TextInputClient for
// text input. Some platforms (Mac and Android for example) use their own
@@ -93,6 +93,14 @@ class CONTENT_EXPORT RenderWidgetHostView {
// Whether the view is showing.
virtual bool IsShowing() = 0;
+ // Indicates if the view is currently occluded (e.g, not visible because it's
+ // covered up by other windows), and as a result the view's renderer may be
+ // suspended. If Show() is called on a view then its state should be re-set to
+ // being un-occluded (an explicit WasUnOccluded call will not be made for
+ // that). These calls are not necessarily made in pairs.
+ virtual void WasUnOccluded() = 0;
+ virtual void WasOccluded() = 0;
+
// Retrieve the bounds of the View, in screen coordinates.
virtual gfx::Rect GetViewBounds() const = 0;
diff --git a/chromium/content/public/browser/render_widget_host_view_frame_subscriber.h b/chromium/content/public/browser/render_widget_host_view_frame_subscriber.h
index 0b24ea1a9be..e29bf15c104 100644
--- a/chromium/content/public/browser/render_widget_host_view_frame_subscriber.h
+++ b/chromium/content/public/browser/render_widget_host_view_frame_subscriber.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_PORT_BROWSER_RENDER_WIDGET_HOST_VIEW_FRAME_SUBSCRIBER_H_
-#define CONTENT_PORT_BROWSER_RENDER_WIDGET_HOST_VIEW_FRAME_SUBSCRIBER_H_
+#ifndef CONTENT_PUBLIC_BROWSER_RENDER_WIDGET_HOST_VIEW_FRAME_SUBSCRIBER_H_
+#define CONTENT_PUBLIC_BROWSER_RENDER_WIDGET_HOST_VIEW_FRAME_SUBSCRIBER_H_
#include "base/callback.h"
#include "base/time/time.h"
@@ -69,4 +69,4 @@ class RenderWidgetHostViewFrameSubscriber {
} // namespace content
-#endif // CONTENT_PORT_BROWSER_RENDER_WIDGET_HOST_VIEW_FRAME_SUBSCRIBER_H_
+#endif // CONTENT_PUBLIC_BROWSER_RENDER_WIDGET_HOST_VIEW_FRAME_SUBSCRIBER_H_
diff --git a/chromium/content/public/browser/resource_context.h b/chromium/content/public/browser/resource_context.h
index 27183f8ae68..3a3fafe0d1a 100644
--- a/chromium/content/public/browser/resource_context.h
+++ b/chromium/content/public/browser/resource_context.h
@@ -32,12 +32,10 @@ class AppCacheService;
// the UI thread. It must be destructed on the IO thread.
class CONTENT_EXPORT ResourceContext : public base::SupportsUserData {
public:
-#if defined(OS_IOS)
- virtual ~ResourceContext() {}
-#else
+#if !defined(OS_IOS)
ResourceContext();
- ~ResourceContext() override;
#endif
+ ~ResourceContext() override;
virtual net::HostResolver* GetHostResolver() = 0;
// DEPRECATED: This is no longer a valid given isolated apps/sites and
@@ -45,7 +43,7 @@ class CONTENT_EXPORT ResourceContext : public base::SupportsUserData {
// with a BrowsingContext.
virtual net::URLRequestContext* GetRequestContext() = 0;
- // Get platform ClientCertStore. May return NULL.
+ // Get platform ClientCertStore. May return nullptr.
virtual scoped_ptr<net::ClientCertStore> CreateClientCertStore();
// Create a platform KeygenHandler and pass it to |callback|. The |callback|
diff --git a/chromium/content/public/browser/resource_dispatcher_host.h b/chromium/content/public/browser/resource_dispatcher_host.h
index 7db278c8aac..3625abbc598 100644
--- a/chromium/content/public/browser/resource_dispatcher_host.h
+++ b/chromium/content/public/browser/resource_dispatcher_host.h
@@ -55,6 +55,7 @@ class CONTENT_EXPORT ResourceDispatcherHost {
int child_id,
int route_id,
bool prefer_cache,
+ bool do_not_prompt_for_login,
scoped_ptr<DownloadSaveInfo> save_info,
uint32 download_id,
const DownloadStartedCallback& started_callback) = 0;
diff --git a/chromium/content/public/browser/resource_dispatcher_host_delegate.cc b/chromium/content/public/browser/resource_dispatcher_host_delegate.cc
index 49eece0e0e9..c67ab55dff2 100644
--- a/chromium/content/public/browser/resource_dispatcher_host_delegate.cc
+++ b/chromium/content/public/browser/resource_dispatcher_host_delegate.cc
@@ -39,12 +39,16 @@ ResourceDispatcherHostLoginDelegate*
ResourceDispatcherHostDelegate::CreateLoginDelegate(
net::AuthChallengeInfo* auth_info,
net::URLRequest* request) {
- return NULL;
+ return nullptr;
}
-bool ResourceDispatcherHostDelegate::HandleExternalProtocol(const GURL& url,
- int child_id,
- int route_id) {
+bool ResourceDispatcherHostDelegate::HandleExternalProtocol(
+ const GURL& url,
+ int child_id,
+ int route_id,
+ bool is_main_frame,
+ ui::PageTransition page_transition,
+ bool has_user_gesture) {
return true;
}
diff --git a/chromium/content/public/browser/resource_dispatcher_host_delegate.h b/chromium/content/public/browser/resource_dispatcher_host_delegate.h
index 7942df56898..9a08117d2fb 100644
--- a/chromium/content/public/browser/resource_dispatcher_host_delegate.h
+++ b/chromium/content/public/browser/resource_dispatcher_host_delegate.h
@@ -11,6 +11,7 @@
#include "base/memory/scoped_ptr.h"
#include "content/common/content_export.h"
#include "content/public/common/resource_type.h"
+#include "ui/base/page_transition_types.h"
class GURL;
template <class T> class ScopedVector;
@@ -74,7 +75,10 @@ class CONTENT_EXPORT ResourceDispatcherHostDelegate {
// guarantee that the app successfully handled it.
virtual bool HandleExternalProtocol(const GURL& url,
int child_id,
- int route_id);
+ int route_id,
+ bool is_main_frame,
+ ui::PageTransition page_transition,
+ bool has_user_gesture);
// Returns true if we should force the given resource to be downloaded.
// Otherwise, the content layer decides.
diff --git a/chromium/content/public/browser/resource_request_info.h b/chromium/content/public/browser/resource_request_info.h
index 00be9c7ceb9..e9ba86ebcc0 100644
--- a/chromium/content/public/browser/resource_request_info.h
+++ b/chromium/content/public/browser/resource_request_info.h
@@ -8,8 +8,8 @@
#include "base/basictypes.h"
#include "content/common/content_export.h"
#include "content/public/common/resource_type.h"
+#include "third_party/WebKit/public/platform/WebPageVisibilityState.h"
#include "third_party/WebKit/public/platform/WebReferrerPolicy.h"
-#include "third_party/WebKit/public/web/WebPageVisibilityState.h"
#include "ui/base/page_transition_types.h"
namespace net {
@@ -36,6 +36,9 @@ class ResourceRequestInfo {
int render_process_id,
int render_view_id,
int render_frame_id,
+ bool is_main_frame,
+ bool parent_is_main_frame,
+ bool allow_download,
bool is_async);
// Returns the associated RenderFrame for a given process. Returns false, if
diff --git a/chromium/content/public/browser/resource_throttle.h b/chromium/content/public/browser/resource_throttle.h
index ec176bc907b..240d95e1967 100644
--- a/chromium/content/public/browser/resource_throttle.h
+++ b/chromium/content/public/browser/resource_throttle.h
@@ -9,6 +9,10 @@
class GURL;
+namespace net {
+struct RedirectInfo;
+}
+
namespace content {
class ResourceController;
@@ -22,13 +26,24 @@ class ResourceThrottle {
public:
virtual ~ResourceThrottle() {}
+ // Called before the resource request is started.
virtual void WillStartRequest(bool* defer) {}
+
+ // Called before the resource request uses the network for the first time.
virtual void WillStartUsingNetwork(bool* defer) {}
- virtual void WillRedirectRequest(const GURL& new_url, bool* defer) {}
+
+ // Called when the request was redirected. |redirect_info| contains the
+ // redirect responses's HTTP status code and some information about the new
+ // request that will be sent if the redirect is followed, including the new
+ // URL and new method.
+ virtual void WillRedirectRequest(const net::RedirectInfo& redirect_info,
+ bool* defer) {}
+
+ // Called when the response headers and meta data are available.
virtual void WillProcessResponse(bool* defer) {}
// Returns the name of the throttle, as a UTF-8 C-string, for logging
- // purposes. NULL is not allowed. Caller does *not* take ownership of the
+ // purposes. nullptr is not allowed. Caller does *not* take ownership of the
// returned string.
virtual const char* GetNameForLogging() const = 0;
@@ -37,7 +52,7 @@ class ResourceThrottle {
}
protected:
- ResourceThrottle() : controller_(NULL) {}
+ ResourceThrottle() : controller_(nullptr) {}
ResourceController* controller() { return controller_; }
private:
diff --git a/chromium/content/public/browser/screen_orientation_delegate.h b/chromium/content/public/browser/screen_orientation_delegate.h
index 243d2c3659b..8dd16db826e 100644
--- a/chromium/content/public/browser/screen_orientation_delegate.h
+++ b/chromium/content/public/browser/screen_orientation_delegate.h
@@ -25,13 +25,14 @@ class CONTENT_EXPORT ScreenOrientationDelegate {
virtual bool FullScreenRequired(WebContents* web_contents) = 0;
// Lock display to the given orientation.
- virtual void Lock(blink::WebScreenOrientationLockType lock_orientation) = 0;
+ virtual void Lock(WebContents* web_contents,
+ blink::WebScreenOrientationLockType lock_orientation) = 0;
// Are ScreenOrientationProvider requests currently supported by the platform.
virtual bool ScreenOrientationProviderSupported() = 0;
// Unlocks the display, allowing hardware rotation to resume.
- virtual void Unlock() = 0;
+ virtual void Unlock(WebContents* web_contents) = 0;
private:
DISALLOW_COPY_AND_ASSIGN(ScreenOrientationDelegate);
@@ -39,5 +40,5 @@ class CONTENT_EXPORT ScreenOrientationDelegate {
} // namespace content
-#endif // CONTENT_PUBLIC_BROWSER_SCREEN_ORIENTATION_DELEGATE_H_
+#endif // CONTENT_PUBLIC_BROWSER_SCREEN_ORIENTATION_DELEGATE_H_
diff --git a/chromium/content/public/browser/screen_orientation_dispatcher_host.h b/chromium/content/public/browser/screen_orientation_dispatcher_host.h
index c0f8bc0268f..0c49b0db4d2 100644
--- a/chromium/content/public/browser/screen_orientation_dispatcher_host.h
+++ b/chromium/content/public/browser/screen_orientation_dispatcher_host.h
@@ -33,4 +33,4 @@ class CONTENT_EXPORT ScreenOrientationDispatcherHost {
} // namespace content
-#endif // CONTENT_PUBLIC_BROWSER_SCREEN_ORIENTATION_DISPATCHER_HOST_H_
+#endif // CONTENT_PUBLIC_BROWSER_SCREEN_ORIENTATION_DISPATCHER_HOST_H_
diff --git a/chromium/content/public/browser/screen_orientation_provider.cc b/chromium/content/public/browser/screen_orientation_provider.cc
index 35a07eeffde..849b946570b 100644
--- a/chromium/content/public/browser/screen_orientation_provider.cc
+++ b/chromium/content/public/browser/screen_orientation_provider.cc
@@ -14,7 +14,7 @@
namespace content {
-ScreenOrientationDelegate* ScreenOrientationProvider::delegate_ = NULL;
+ScreenOrientationDelegate* ScreenOrientationProvider::delegate_ = nullptr;
ScreenOrientationProvider::LockInformation::LockInformation(int request_id,
blink::WebScreenOrientationLockType lock)
@@ -73,7 +73,7 @@ void ScreenOrientationProvider::LockOrientation(int request_id,
}
lock_applied_ = true;
- delegate_->Lock(lock_orientation);
+ delegate_->Lock(web_contents(), lock_orientation);
// If two calls happen close to each other some platforms will ignore the
// first. A successful lock will be once orientation matches the latest
@@ -94,7 +94,7 @@ void ScreenOrientationProvider::UnlockOrientation() {
if (!lock_applied_ || !delegate_)
return;
- delegate_->Unlock();
+ delegate_->Unlock(web_contents());
lock_applied_ = false;
pending_lock_.reset();
diff --git a/chromium/content/public/browser/screen_orientation_provider.h b/chromium/content/public/browser/screen_orientation_provider.h
index 7879d3455d7..30fd89c2851 100644
--- a/chromium/content/public/browser/screen_orientation_provider.h
+++ b/chromium/content/public/browser/screen_orientation_provider.h
@@ -77,4 +77,4 @@ class CONTENT_EXPORT ScreenOrientationProvider : public WebContentsObserver {
} // namespace content
-#endif // CONTENT_PUBLIC_BROWSER_SCREEN_ORIENTATION_PROVIDER_H_
+#endif // CONTENT_PUBLIC_BROWSER_SCREEN_ORIENTATION_PROVIDER_H_
diff --git a/chromium/content/public/browser/service_worker_context.h b/chromium/content/public/browser/service_worker_context.h
index 94ab73f67e2..a28662bb171 100644
--- a/chromium/content/public/browser/service_worker_context.h
+++ b/chromium/content/public/browser/service_worker_context.h
@@ -11,8 +11,13 @@
#include "base/basictypes.h"
#include "base/callback_forward.h"
#include "content/public/browser/service_worker_usage_info.h"
+#include "net/base/completion_callback.h"
#include "url/gurl.h"
+namespace net {
+class URLRequest;
+}
+
namespace content {
// Represents the per-StoragePartition ServiceWorker data.
@@ -27,6 +32,9 @@ class ServiceWorkerContext {
typedef base::Callback<void(const std::vector<ServiceWorkerUsageInfo>&
usage_info)> GetUsageInfoCallback;
+ typedef base::Callback<void(bool has_service_worker)>
+ CheckHasServiceWorkerCallback;
+
// Registers the header name which should not be passed to the ServiceWorker.
// Must be called from the IO thread.
CONTENT_EXPORT static void AddExcludedHeadersForFetchEvent(
@@ -36,6 +44,10 @@ class ServiceWorkerContext {
// Must be called from the IO thread.
static bool IsExcludedHeaderNameForFetchEvent(const std::string& header_name);
+ // Retrieves the ServiceWorkerContext, if any, associated with |request|.
+ CONTENT_EXPORT static ServiceWorkerContext* GetServiceWorkerContext(
+ net::URLRequest* request);
+
// Equivalent to calling navigator.serviceWorker.register(script_url, {scope:
// pattern}) from a renderer, except that |pattern| is an absolute URL instead
// of relative to some current origin. |callback| is passed true when the JS
@@ -64,10 +76,28 @@ class ServiceWorkerContext {
// TODO(jyasskin): Provide a way to SendMessage to a Scope.
+ // Determines if a request for |url| can be satisfied while offline.
+ // This method always completes asynchronously.
+ virtual void CanHandleMainResourceOffline(const GURL& url,
+ const GURL& first_party,
+ const net::CompletionCallback&
+ callback) = 0;
+
// Methods used in response to browsing data and quota manager requests.
virtual void GetAllOriginsInfo(const GetUsageInfoCallback& callback) = 0;
virtual void DeleteForOrigin(const GURL& origin_url) = 0;
+ // Returns true if an active Service Worker registration exists that matches
+ // |url|, and if |other_url| falls inside the scope of the same registration.
+ // Note this still returns true even if there is a Service Worker registration
+ // which has a longer match for |other_url|.
+ // This function can be called from any thread, but the callback will always
+ // be called on the UI thread.
+ virtual void CheckHasServiceWorker(
+ const GURL& url,
+ const GURL& other_url,
+ const CheckHasServiceWorkerCallback& callback) = 0;
+
protected:
ServiceWorkerContext() {}
virtual ~ServiceWorkerContext() {}
diff --git a/chromium/content/public/browser/session_storage_namespace.h b/chromium/content/public/browser/session_storage_namespace.h
index 374b7b050fb..78110af9caf 100644
--- a/chromium/content/public/browser/session_storage_namespace.h
+++ b/chromium/content/public/browser/session_storage_namespace.h
@@ -9,7 +9,6 @@
#include <string>
#include "base/basictypes.h"
-#include "base/callback.h"
#include "base/memory/ref_counted.h"
namespace content {
@@ -33,48 +32,6 @@ class SessionStorageNamespace
virtual bool should_persist() const = 0;
- // SessionStorageNamespaces can be merged. These merges happen based on
- // a transaction log of operations on the session storage namespace since
- // this function has been called. Transaction logging will be restricted
- // to the processes indicated.
- virtual void AddTransactionLogProcessId(int process_id) = 0;
-
- // When transaction logging for a process is no longer required, the log
- // can be removed to save space.
- virtual void RemoveTransactionLogProcessId(int process_id) = 0;
-
- // Creates a new session storage namespace which is an alias of the current
- // instance.
- virtual SessionStorageNamespace* CreateAlias() = 0;
-
- enum MergeResult {
- MERGE_RESULT_NAMESPACE_NOT_FOUND,
- MERGE_RESULT_NAMESPACE_NOT_ALIAS,
- MERGE_RESULT_NOT_LOGGING,
- MERGE_RESULT_NO_TRANSACTIONS,
- MERGE_RESULT_TOO_MANY_TRANSACTIONS,
- MERGE_RESULT_NOT_MERGEABLE,
- MERGE_RESULT_MERGEABLE,
- MERGE_RESULT_MAX_VALUE
- };
-
- typedef base::Callback<void(MergeResult)> MergeResultCallback;
-
- // Determines whether the transaction log for the process specified can
- // be merged into the other session storage namespace supplied.
- // If actually_merge is set to true, the merge will actually be performed,
- // if possible, and the result of the merge will be returned.
- // If actually_merge is set to false, the result of whether a merge would be
- // possible is returned.
- virtual void Merge(bool actually_merge,
- int process_id,
- SessionStorageNamespace* other,
- const MergeResultCallback& callback) = 0;
-
- // Indicates whether this SessionStorageNamespace is an alias of |other|,
- // i.e. whether they point to the same underlying data.
- virtual bool IsAliasOf(SessionStorageNamespace* other) = 0;
-
protected:
friend class base::RefCountedThreadSafe<SessionStorageNamespace>;
virtual ~SessionStorageNamespace() {}
diff --git a/chromium/content/public/browser/signed_certificate_timestamp_store.h b/chromium/content/public/browser/signed_certificate_timestamp_store.h
index 753c1ada81d..a12250a40c8 100644
--- a/chromium/content/public/browser/signed_certificate_timestamp_store.h
+++ b/chromium/content/public/browser/signed_certificate_timestamp_store.h
@@ -40,7 +40,7 @@ class SignedCertificateTimestampStore {
// Tries to retrieve the previously stored SCT associated with the specified
// |sct_id|. Returns whether the SCT could be found, and, if |sct| is
- // non-NULL, copies it in.
+ // non-nullptr, copies it in.
virtual bool Retrieve(
int sct_id, scoped_refptr<net::ct::SignedCertificateTimestamp>* sct) = 0;
diff --git a/chromium/content/public/browser/site_instance.h b/chromium/content/public/browser/site_instance.h
index 61d593da3e0..a828d29f297 100644
--- a/chromium/content/public/browser/site_instance.h
+++ b/chromium/content/public/browser/site_instance.h
@@ -115,7 +115,8 @@ class CONTENT_EXPORT SiteInstance : public base::RefCounted<SiteInstance> {
// from scratch (or similar circumstances). Callers should ensure that
// this SiteInstance becomes ref counted, by storing it in a scoped_refptr.
//
- // The render process host factory may be NULL. See SiteInstance constructor.
+ // The render process host factory may be nullptr. See SiteInstance
+ // constructor.
//
// TODO(creis): This may be an argument to build a pass_refptr<T> class, as
// Darin suggests.
diff --git a/chromium/content/public/browser/speech_recognition_manager_delegate.h b/chromium/content/public/browser/speech_recognition_manager_delegate.h
index bbfeaed7762..f29931827cd 100644
--- a/chromium/content/public/browser/speech_recognition_manager_delegate.h
+++ b/chromium/content/public/browser/speech_recognition_manager_delegate.h
@@ -32,8 +32,8 @@ class SpeechRecognitionManagerDelegate {
int session_id,
base::Callback<void(bool ask_user, bool is_allowed)> callback) = 0;
- // Checks whether the delegate is interested (returning a non NULL ptr) or not
- // (returning NULL) in receiving a copy of all sessions events.
+ // Checks whether the delegate is interested (returning a non nullptr ptr) or
+ // not (returning nullptr) in receiving a copy of all sessions events.
// This is called on the IO thread.
virtual SpeechRecognitionEventListener* GetEventListener() = 0;
diff --git a/chromium/content/public/browser/speech_recognition_session_config.h b/chromium/content/public/browser/speech_recognition_session_config.h
index 1cde6430b0d..e5343e27503 100644
--- a/chromium/content/public/browser/speech_recognition_session_config.h
+++ b/chromium/content/public/browser/speech_recognition_session_config.h
@@ -5,11 +5,14 @@
#ifndef CONTENT_PUBLIC_BROWSER_SPEECH_RECOGNITION_SESSION_CONFIG_H_
#define CONTENT_PUBLIC_BROWSER_SPEECH_RECOGNITION_SESSION_CONFIG_H_
+#include <string>
+
#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "content/common/content_export.h"
#include "content/public/browser/speech_recognition_session_context.h"
+#include "content/public/browser/speech_recognition_session_preamble.h"
#include "content/public/common/speech_recognition_grammar.h"
#include "net/url_request/url_request_context_getter.h"
@@ -32,6 +35,9 @@ struct CONTENT_EXPORT SpeechRecognitionSessionConfig {
bool continuous;
bool interim_results;
uint32 max_hypotheses;
+ std::string auth_token;
+ std::string auth_scope;
+ scoped_refptr<SpeechRecognitionSessionPreamble> preamble;
SpeechRecognitionSessionContext initial_context;
scoped_refptr<net::URLRequestContextGetter> url_request_context_getter;
base::WeakPtr<SpeechRecognitionEventListener> event_listener;
diff --git a/chromium/content/public/browser/speech_recognition_session_context.h b/chromium/content/public/browser/speech_recognition_session_context.h
index 532a4e47e65..94931894e68 100644
--- a/chromium/content/public/browser/speech_recognition_session_context.h
+++ b/chromium/content/public/browser/speech_recognition_session_context.h
@@ -9,7 +9,7 @@
#include "content/common/content_export.h"
#include "content/public/common/media_stream_request.h"
-#include "ui/gfx/rect.h"
+#include "ui/gfx/geometry/rect.h"
namespace content {
diff --git a/chromium/content/public/browser/speech_recognition_session_preamble.cc b/chromium/content/public/browser/speech_recognition_session_preamble.cc
new file mode 100644
index 00000000000..00b65ff3b5d
--- /dev/null
+++ b/chromium/content/public/browser/speech_recognition_session_preamble.cc
@@ -0,0 +1,17 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/public/browser/speech_recognition_session_preamble.h"
+
+namespace content {
+
+SpeechRecognitionSessionPreamble::SpeechRecognitionSessionPreamble()
+ : sample_rate(8000),
+ sample_depth(2) {
+}
+
+SpeechRecognitionSessionPreamble::~SpeechRecognitionSessionPreamble() {
+}
+
+} // namespace content
diff --git a/chromium/content/public/browser/speech_recognition_session_preamble.h b/chromium/content/public/browser/speech_recognition_session_preamble.h
new file mode 100644
index 00000000000..589953184d5
--- /dev/null
+++ b/chromium/content/public/browser/speech_recognition_session_preamble.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_PUBLIC_BROWSER_SPEECH_RECOGNITION_SESSION_PREAMBLE_H_
+#define CONTENT_PUBLIC_BROWSER_SPEECH_RECOGNITION_SESSION_PREAMBLE_H_
+
+#include <vector>
+
+#include "base/memory/ref_counted.h"
+#include "content/common/content_export.h"
+
+namespace content {
+
+// The preamble is the few seconds of audio before the speech recognition
+// starts. This is used to contain trigger audio used to start a voice
+// query, such as the 'Ok Google' hotword.
+struct CONTENT_EXPORT SpeechRecognitionSessionPreamble
+ : public base::RefCounted<SpeechRecognitionSessionPreamble> {
+ SpeechRecognitionSessionPreamble();
+
+ // Sampling rate (hz) for the preamble data. i.e. 44100, 32000, etc
+ int sample_rate;
+
+ // Bytes per sample.
+ int sample_depth;
+
+ // Audio data, in little-endian samples.
+ std::vector<char> sample_data;
+
+ private:
+ friend class base::RefCounted<SpeechRecognitionSessionPreamble>;
+ ~SpeechRecognitionSessionPreamble();
+};
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_BROWSER_SPEECH_RECOGNITION_SESSION_PREAMBLE_H_
diff --git a/chromium/content/public/browser/ssl_host_state_delegate.h b/chromium/content/public/browser/ssl_host_state_delegate.h
index 4666471a148..39589a5b73d 100644
--- a/chromium/content/public/browser/ssl_host_state_delegate.h
+++ b/chromium/content/public/browser/ssl_host_state_delegate.h
@@ -54,6 +54,16 @@ class SSLHostStateDelegate {
virtual bool DidHostRunInsecureContent(const std::string& host,
int pid) const = 0;
+ // Revokes all SSL certificate error allow exceptions made by the user for
+ // |host|.
+ virtual void RevokeUserAllowExceptions(const std::string& host) = 0;
+
+ // Returns whether the user has allowed a certificate error exception for
+ // |host|. This does not mean that *all* certificate errors are allowed, just
+ // that there exists an exception. To see if a particular certificate and
+ // error combination exception is allowed, use QueryPolicy().
+ virtual bool HasAllowException(const std::string& host) const = 0;
+
protected:
virtual ~SSLHostStateDelegate() {}
};
diff --git a/chromium/content/public/browser/storage_partition.h b/chromium/content/public/browser/storage_partition.h
index c16e5e6a0e6..3426a4892f3 100644
--- a/chromium/content/public/browser/storage_partition.h
+++ b/chromium/content/public/browser/storage_partition.h
@@ -40,10 +40,15 @@ namespace content {
class AppCacheService;
class BrowserContext;
+class HostZoomLevelContext;
+class HostZoomMap;
class DOMStorageContext;
class GeofencingManager;
class IndexedDBContext;
+class NavigatorConnectContext;
+class PlatformNotificationContext;
class ServiceWorkerContext;
+class ZoomLevelDelegate;
// Defines what persistent state a child process can access.
//
@@ -64,6 +69,11 @@ class CONTENT_EXPORT StoragePartition {
virtual IndexedDBContext* GetIndexedDBContext() = 0;
virtual ServiceWorkerContext* GetServiceWorkerContext() = 0;
virtual GeofencingManager* GetGeofencingManager() = 0;
+ virtual HostZoomMap* GetHostZoomMap() = 0;
+ virtual HostZoomLevelContext* GetHostZoomLevelContext() = 0;
+ virtual ZoomLevelDelegate* GetZoomLevelDelegate() = 0;
+ virtual NavigatorConnectContext* GetNavigatorConnectContext() = 0;
+ virtual PlatformNotificationContext* GetPlatformNotificationContext() = 0;
static const uint32 REMOVE_DATA_MASK_APPCACHE = 1 << 0;
static const uint32 REMOVE_DATA_MASK_COOKIES = 1 << 1;
@@ -110,7 +120,8 @@ class CONTENT_EXPORT StoragePartition {
OriginMatcherFunction;
// Similar to ClearDataForOrigin().
- // Deletes all data out fo the StoragePartition if |storage_origin| is NULL.
+ // Deletes all data out fo the StoragePartition if |storage_origin| is
+ // nullptr.
// |origin_matcher| is present if special storage policy is to be handled,
// otherwise the callback can be null (base::Callback::is_null() == true).
// |callback| is called when data deletion is done or at least the deletion is
@@ -123,6 +134,11 @@ class CONTENT_EXPORT StoragePartition {
const base::Time end,
const base::Closure& callback) = 0;
+ // Write any unwritten data to disk.
+ // Note: this method does not sync the data - it only ensures that any
+ // unwritten data has been written out to the filesystem.
+ virtual void Flush() = 0;
+
protected:
virtual ~StoragePartition() {}
};
diff --git a/chromium/content/public/browser/trace_uploader.h b/chromium/content/public/browser/trace_uploader.h
new file mode 100644
index 00000000000..dbf245853b7
--- /dev/null
+++ b/chromium/content/public/browser/trace_uploader.h
@@ -0,0 +1,34 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_PUBLIC_BROWSER_TRACE_UPLOADER_H_
+#define CONTENT_PUBLIC_BROWSER_TRACE_UPLOADER_H_
+
+#include "base/callback.h"
+
+namespace content {
+
+// Used to implement a trace upload service for use in about://tracing,
+// which gets requested through the TracingDelegate.
+class TraceUploader {
+ public:
+ // This should be called when the tracing is complete.
+ // The bool denotes success or failure, the string is feedback
+ // to show in the Tracing UI.
+ typedef base::Callback<void(bool, const std::string&)> UploadDoneCallback;
+ // Call this to update the progress UI with the current bytes uploaded,
+ // as well as the total.
+ typedef base::Callback<void(int64, int64)> UploadProgressCallback;
+
+ virtual ~TraceUploader() {}
+
+ // Compresses and uploads the given file contents.
+ virtual void DoUpload(const std::string& file_contents,
+ const UploadProgressCallback& progress_callback,
+ const UploadDoneCallback& done_callback) = 0;
+};
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_BROWSER_TRACE_UPLOADER_H_
diff --git a/chromium/content/public/browser/tracing_controller.h b/chromium/content/public/browser/tracing_controller.h
index 5b3eb4e4873..70d608ce9b8 100644
--- a/chromium/content/public/browser/tracing_controller.h
+++ b/chromium/content/public/browser/tracing_controller.h
@@ -9,8 +9,8 @@
#include <string>
#include "base/callback.h"
-#include "base/debug/trace_event.h"
#include "base/memory/ref_counted.h"
+#include "base/trace_event/trace_event.h"
#include "content/common/content_export.h"
namespace content {
@@ -45,17 +45,41 @@ class TracingController {
virtual ~TraceDataSink() {}
};
+ // An implementation of this interface is passed when constructing a
+ // TraceDataSink, and receives chunks of the final trace data as it's being
+ // constructed.
+ // Methods may be called from any thread.
+ class CONTENT_EXPORT TraceDataEndpoint
+ : public base::RefCountedThreadSafe<TraceDataEndpoint> {
+ public:
+ virtual void ReceiveTraceChunk(const std::string& chunk) {}
+ virtual void ReceiveTraceFinalContents(const std::string& contents) {}
+
+ protected:
+ friend class base::RefCountedThreadSafe<TraceDataEndpoint>;
+ virtual ~TraceDataEndpoint() {}
+ };
+
// Create a trace sink that may be supplied to DisableRecording or
// CaptureMonitoringSnapshot to capture the trace data as a string.
CONTENT_EXPORT static scoped_refptr<TraceDataSink> CreateStringSink(
const base::Callback<void(base::RefCountedString*)>& callback);
+ CONTENT_EXPORT static scoped_refptr<TraceDataSink> CreateCompressedStringSink(
+ scoped_refptr<TraceDataEndpoint> endpoint);
+
// Create a trace sink that may be supplied to DisableRecording or
// CaptureMonitoringSnapshot to dump the trace data to a file.
CONTENT_EXPORT static scoped_refptr<TraceDataSink> CreateFileSink(
const base::FilePath& file_path,
const base::Closure& callback);
+ // Create an endpoint that may be supplied to any TraceDataSink to
+ // dump the trace data to a file.
+ CONTENT_EXPORT static scoped_refptr<TraceDataEndpoint> CreateFileEndpoint(
+ const base::FilePath& file_path,
+ const base::Closure& callback);
+
// Get a set of category groups. The category groups can change as
// new code paths are reached.
//
@@ -87,8 +111,8 @@ class TracingController {
// |options| controls what kind of tracing is enabled.
typedef base::Callback<void()> EnableRecordingDoneCallback;
virtual bool EnableRecording(
- const base::debug::CategoryFilter& category_filter,
- const base::debug::TraceOptions& trace_options,
+ const base::trace_event::CategoryFilter& category_filter,
+ const base::trace_event::TraceOptions& trace_options,
const EnableRecordingDoneCallback& callback) = 0;
// Stop recording on all processes.
@@ -124,8 +148,8 @@ class TracingController {
// |options| controls what kind of tracing is enabled.
typedef base::Callback<void()> EnableMonitoringDoneCallback;
virtual bool EnableMonitoring(
- const base::debug::CategoryFilter& category_filter,
- const base::debug::TraceOptions& trace_options,
+ const base::trace_event::CategoryFilter& category_filter,
+ const base::trace_event::TraceOptions& trace_options,
const EnableMonitoringDoneCallback& callback) = 0;
// Stop monitoring on all processes.
@@ -139,8 +163,8 @@ class TracingController {
// Get the current monitoring configuration.
virtual void GetMonitoringStatus(
bool* out_enabled,
- base::debug::CategoryFilter* out_category_filter,
- base::debug::TraceOptions* out_trace_options) = 0;
+ base::trace_event::CategoryFilter* out_category_filter,
+ base::trace_event::TraceOptions* out_trace_options) = 0;
// Get the current monitoring traced data.
//
@@ -161,11 +185,11 @@ class TracingController {
const scoped_refptr<TraceDataSink>& trace_data_sink) = 0;
// Get the maximum across processes of trace buffer percent full state.
- // When the TraceBufferPercentFull value is determined, the callback is
+ // When the TraceBufferUsage value is determined, the callback is
// called.
- typedef base::Callback<void(float)> GetTraceBufferPercentFullCallback;
- virtual bool GetTraceBufferPercentFull(
- const GetTraceBufferPercentFullCallback& callback) = 0;
+ typedef base::Callback<void(float, size_t)> GetTraceBufferUsageCallback;
+ virtual bool GetTraceBufferUsage(
+ const GetTraceBufferUsageCallback& callback) = 0;
// |callback| will will be called every time the given event occurs on any
// process.
diff --git a/chromium/content/public/browser/tracing_delegate.h b/chromium/content/public/browser/tracing_delegate.h
new file mode 100644
index 00000000000..5fab907c102
--- /dev/null
+++ b/chromium/content/public/browser/tracing_delegate.h
@@ -0,0 +1,30 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_PUBLIC_BROWSER_TRACING_DELEGATE_H_
+#define CONTENT_PUBLIC_BROWSER_TRACING_DELEGATE_H_
+
+#include "base/memory/scoped_ptr.h"
+
+namespace net {
+class URLRequestContextGetter;
+}
+
+namespace content {
+class TraceUploader;
+
+// This can be implemented by the embedder to provide functionality for the
+// about://tracing WebUI.
+class TracingDelegate {
+ public:
+ virtual ~TracingDelegate() {}
+
+ // Provide trace uploading functionality; see trace_uploader.h.
+ virtual scoped_ptr<TraceUploader> GetTraceUploader(
+ net::URLRequestContextGetter* request_context) = 0;
+};
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_BROWSER_TRACING_DELEGATE_H_
diff --git a/chromium/content/public/browser/url_data_source.h b/chromium/content/public/browser/url_data_source.h
index 9230360721f..c9e5f1c5a04 100644
--- a/chromium/content/public/browser/url_data_source.h
+++ b/chromium/content/public/browser/url_data_source.h
@@ -65,11 +65,11 @@ class CONTENT_EXPORT URLDataSource {
// Returns the MessageLoop on which the delegate wishes to have
// StartDataRequest called to handle the request for |path|. The default
// implementation returns BrowserThread::UI. If the delegate does not care
- // which thread StartDataRequest is called on, this should return NULL. It may
- // be beneficial to return NULL for requests that are safe to handle directly
- // on the IO thread. This can improve performance by satisfying such requests
- // more rapidly when there is a large amount of UI thread contention. Or the
- // delegate can return a specific thread's Messageloop if they wish.
+ // which thread StartDataRequest is called on, this should return nullptr.
+ // It may be beneficial to return nullptr for requests that are safe to handle
+ // directly on the IO thread. This can improve performance by satisfying such
+ // requests more rapidly when there is a large amount of UI thread contention.
+ // Or the delegate can return a specific thread's Messageloop if they wish.
virtual base::MessageLoop* MessageLoopForRequestPath(
const std::string& path) const;
diff --git a/chromium/content/public/browser/utility_process_host.h b/chromium/content/public/browser/utility_process_host.h
index 07f46ee0c74..36b28509dc9 100644
--- a/chromium/content/public/browser/utility_process_host.h
+++ b/chromium/content/public/browser/utility_process_host.h
@@ -17,6 +17,7 @@ class SequencedTaskRunner;
}
namespace content {
+class ServiceRegistry;
class UtilityProcessHostClient;
struct ChildProcessData;
@@ -27,6 +28,9 @@ struct ChildProcessData;
// If you need multiple batches of work to be done in the process, use
// StartBatchMode(), then multiple calls to StartFooBar(p), then finish with
// EndBatchMode().
+// If you need to call Mojo services, use StartMojoMode() to start the child
+// process and GetServiceRegistry() to get the service registry to connect to
+// the child's Mojo services.
//
// Note: If your class keeps a ptr to an object of this type, grab a weak ptr to
// avoid a use after free since this object is deleted synchronously but the
@@ -72,6 +76,16 @@ class UtilityProcessHost : public IPC::Sender,
#if defined(OS_POSIX)
virtual void SetEnv(const base::EnvironmentMap& env) = 0;
#endif
+
+ // Starts the utility process in Mojo mode.
+ virtual bool StartMojoMode() = 0;
+
+ // Returns the ServiceRegistry for this process. Only valid to call this if
+ // the process was started with StartMojoMode().
+ virtual ServiceRegistry* GetServiceRegistry() = 0;
+
+ // Set the name of the process to appear in the task manager.
+ virtual void SetName(const base::string16& name) = 0;
};
}; // namespace content
diff --git a/chromium/content/public/browser/vibration_provider.h b/chromium/content/public/browser/vibration_provider.h
deleted file mode 100644
index 71eba76a2da..00000000000
--- a/chromium/content/public/browser/vibration_provider.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.
-
-#ifndef CONTENT_PUBLIC_BROWSER_VIBRATION_PROVIDER_H_
-#define CONTENT_PUBLIC_BROWSER_VIBRATION_PROVIDER_H_
-
-namespace content {
-
-class VibrationProvider {
- public:
- // Device should start vibrating for N milliseconds.
- virtual void Vibrate(int64 milliseconds) = 0;
-
- // Cancels vibration of the device.
- virtual void CancelVibration() = 0;
-
- virtual ~VibrationProvider() {}
-};
-
-} // namespace content
-
-#endif // CONTENT_PUBLIC_BROWSER_VIBRATION_PROVIDER_H_
diff --git a/chromium/content/public/browser/web_contents.cc b/chromium/content/public/browser/web_contents.cc
index 7afc3385c98..aece7c630ad 100644
--- a/chromium/content/public/browser/web_contents.cc
+++ b/chromium/content/public/browser/web_contents.cc
@@ -10,26 +10,28 @@ namespace content {
WebContents::CreateParams::CreateParams(BrowserContext* context)
: browser_context(context),
- site_instance(NULL),
- opener(NULL),
+ site_instance(nullptr),
+ opener(nullptr),
opener_suppressed(false),
routing_id(MSG_ROUTING_NONE),
main_frame_routing_id(MSG_ROUTING_NONE),
initially_hidden(false),
- guest_delegate(NULL),
- context(NULL) {}
+ guest_delegate(nullptr),
+ context(nullptr),
+ renderer_initiated_creation(false) {}
WebContents::CreateParams::CreateParams(
BrowserContext* context, SiteInstance* site)
: browser_context(context),
site_instance(site),
- opener(NULL),
+ opener(nullptr),
opener_suppressed(false),
routing_id(MSG_ROUTING_NONE),
main_frame_routing_id(MSG_ROUTING_NONE),
initially_hidden(false),
- guest_delegate(NULL),
- context(NULL) {}
+ guest_delegate(nullptr),
+ context(nullptr),
+ renderer_initiated_creation(false) {}
WebContents::CreateParams::~CreateParams() {
}
diff --git a/chromium/content/public/browser/web_contents.h b/chromium/content/public/browser/web_contents.h
index 5478a378158..86ac67516f2 100644
--- a/chromium/content/public/browser/web_contents.h
+++ b/chromium/content/public/browser/web_contents.h
@@ -23,8 +23,8 @@
#include "ipc/ipc_sender.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/window_open_disposition.h"
+#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/rect.h"
#if defined(OS_ANDROID)
#include "base/android/scoped_java_ref.h"
@@ -103,9 +103,18 @@ class WebContents : public PageNavigator,
// If the opener is suppressed, then the new WebContents doesn't hold a
// reference to its opener.
bool opener_suppressed;
+
+ // The routing ids of the RenderView and of the main RenderFrame. Either
+ // both must be provided, or both must be MSG_ROUTING_NONE to have the
+ // WebContents make the assignment.
int routing_id;
int main_frame_routing_id;
+ // The name of the top-level frame of the new window. It is non-empty
+ // when creating a named window (e.g. <a target="foo"> or
+ // window.open('', 'bar')).
+ std::string main_frame_name;
+
// Initial size of the new WebContent's view. Can be (0, 0) if not needed.
gfx::Size initial_size;
@@ -116,8 +125,14 @@ class WebContents : public PageNavigator,
BrowserPluginGuestDelegate* guest_delegate;
// Used to specify the location context which display the new view should
- // belong. This can be NULL if not needed.
+ // belong. This can be nullptr if not needed.
gfx::NativeView context;
+
+ // Used to specify that the new WebContents creation is driven by the
+ // renderer process. In this case, the renderer-side objects, such as
+ // RenderFrame, have already been created on the renderer side, and
+ // WebContents construction should take this into account.
+ bool renderer_initiated_creation;
};
// Creates a new WebContents.
@@ -137,7 +152,7 @@ class WebContents : public PageNavigator,
const CreateParams& params,
const SessionStorageNamespaceMap& session_storage_namespace_map);
- // Returns a WebContents that wraps the RenderViewHost, or NULL if the
+ // Returns a WebContents that wraps the RenderViewHost, or nullptr if the
// render view host's delegate isn't a WebContents.
CONTENT_EXPORT static WebContents* FromRenderViewHost(
const RenderViewHost* rvh);
@@ -188,6 +203,10 @@ class WebContents : public PageNavigator,
virtual RenderFrameHost* GetFocusedFrame() = 0;
// Calls |on_frame| for each frame in the currently active view.
+ // Note: The RenderFrameHost parameter is not guaranteed to have a live
+ // RenderFrame counterpart in the renderer process. Callbacks should check
+ // IsRenderFrameLive, as sending IPC messages to it in this case will fail
+ // silently.
virtual void ForEachFrame(
const base::Callback<void(RenderFrameHost*)>& on_frame) = 0;
@@ -203,13 +222,21 @@ class WebContents : public PageNavigator,
virtual int GetRoutingID() const = 0;
// Returns the currently active RenderWidgetHostView. This may change over
- // time and can be NULL (during setup and teardown).
+ // time and can be nullptr (during setup and teardown).
virtual RenderWidgetHostView* GetRenderWidgetHostView() const = 0;
+ // Causes the current page to be closed, including running its onunload event
+ // handler.
+ virtual void ClosePage() = 0;
+
// Returns the currently active fullscreen widget. If there is none, returns
- // NULL.
+ // nullptr.
virtual RenderWidgetHostView* GetFullscreenRenderWidgetHostView() const = 0;
+ // Returns the theme color for the underlying content as set by the
+ // theme-color meta tag.
+ virtual SkColor GetThemeColor() const = 0;
+
// Create a WebUI page for the given url. In most cases, this doesn't need to
// be called by embedders since content will create its own WebUI objects as
// necessary. However if the embedder wants to create its own WebUI object and
@@ -324,9 +351,10 @@ class WebContents : public PageNavigator,
// change.
virtual void NotifyNavigationStateChanged(InvalidateTypes changed_flags) = 0;
- // Get the last time that the WebContents was made active (either when it was
- // created or shown with WasShown()).
+ // Get/Set the last time that the WebContents was made active (either when it
+ // was created or shown with WasShown()).
virtual base::TimeTicks GetLastActiveTime() const = 0;
+ virtual void SetLastActiveTime(base::TimeTicks last_active_time) = 0;
// Invoked when the WebContents becomes shown/hidden.
virtual void WasShown() = 0;
@@ -436,7 +464,7 @@ class WebContents : public PageNavigator,
// Various other systems need to know about our interstitials.
virtual bool ShowingInterstitialPage() const = 0;
- // Returns the currently showing interstitial, NULL if no interstitial is
+ // Returns the currently showing interstitial, nullptr if no interstitial is
// showing.
virtual InterstitialPage* GetInterstitialPage() const = 0;
@@ -456,10 +484,18 @@ class WebContents : public PageNavigator,
const base::FilePath& dir_path,
SavePageType save_type) = 0;
- // Saves the given frame's URL to the local filesystem..
+ // Saves the given frame's URL to the local filesystem.
virtual void SaveFrame(const GURL& url,
const Referrer& referrer) = 0;
+ // Saves the given frame's URL to the local filesystem. The headers, if
+ // provided, is used to make a request to the URL rather than using cache.
+ // Format of |headers| is a new line separated list of key value pairs:
+ // "<key1>: <value1>\n<key2>: <value2>".
+ virtual void SaveFrameWithHeaders(const GURL& url,
+ const Referrer& referrer,
+ const std::string& headers) = 0;
+
// Generate an MHTML representation of the current page in the given file.
virtual void GenerateMHTML(
const base::FilePath& file,
@@ -516,6 +552,9 @@ class WebContents : public PageNavigator,
virtual int GetMinimumZoomPercent() const = 0;
virtual int GetMaximumZoomPercent() const = 0;
+ // Set the renderer's page scale back to one.
+ virtual void ResetPageScale() = 0;
+
// Gets the preferred size of the contents.
virtual gfx::Size GetPreferredSize() const = 0;
@@ -538,6 +577,9 @@ class WebContents : public PageNavigator,
// Does this have an opener associated with it?
virtual bool HasOpener() const = 0;
+ // Returns the opener if HasOpener() is true, or nullptr otherwise.
+ virtual WebContents* GetOpener() const = 0;
+
typedef base::Callback<void(
int, /* id */
int, /* HTTP status code */
@@ -552,15 +594,19 @@ class WebContents : public PageNavigator,
// Sends a request to download the given image |url| and returns the unique
// id of the download request. When the download is finished, |callback| will
- // be called with the bitmaps received from the renderer. If |is_favicon| is
- // true, the cookies are not sent and not accepted during download.
+ // be called with the bitmaps received from the renderer.
+ // If |is_favicon| is true, the cookies are not sent and not accepted during
+ // download.
// Bitmaps with pixel sizes larger than |max_bitmap_size| are filtered out
// from the bitmap results. If there are no bitmap results <=
// |max_bitmap_size|, the smallest bitmap is resized to |max_bitmap_size| and
// is the only result. A |max_bitmap_size| of 0 means unlimited.
+ // If |bypass_cache| is true, |url| is requested from the server even if it
+ // is present in the browser cache.
virtual int DownloadImage(const GURL& url,
bool is_favicon,
uint32_t max_bitmap_size,
+ bool bypass_cache,
const ImageDownloadCallback& callback) = 0;
// Returns true if the WebContents is responsible for displaying a subframe
@@ -589,6 +635,16 @@ class WebContents : public PageNavigator,
// Requests the Manifest of the main frame's document.
virtual void GetManifest(const GetManifestCallback&) = 0;
+ // Requests the renderer to exit fullscreen.
+ virtual void ExitFullscreen() = 0;
+
+ // Unblocks requests from renderer for a newly created window. This is
+ // used in showCreatedWindow() or sometimes later in cases where
+ // delegate->ShouldResumeRequestsForCreatedWindow() indicated the requests
+ // should not yet be resumed. Then the client is responsible for calling this
+ // as soon as they are ready.
+ virtual void ResumeLoadingCreatedWebContents() = 0;
+
#if defined(OS_ANDROID)
CONTENT_EXPORT static WebContents* FromJavaWebContents(
jobject jweb_contents_android);
diff --git a/chromium/content/public/browser/web_contents_delegate.cc b/chromium/content/public/browser/web_contents_delegate.cc
index f264df7f4a0..808ab9fede0 100644
--- a/chromium/content/public/browser/web_contents_delegate.cc
+++ b/chromium/content/public/browser/web_contents_delegate.cc
@@ -9,9 +9,9 @@
#include "base/memory/singleton.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
-#include "content/public/common/url_constants.h"
#include "content/public/common/bindings_policy.h"
-#include "ui/gfx/rect.h"
+#include "content/public/common/url_constants.h"
+#include "ui/gfx/geometry/rect.h"
namespace content {
@@ -20,7 +20,7 @@ WebContentsDelegate::WebContentsDelegate() {
WebContents* WebContentsDelegate::OpenURLFromTab(WebContents* source,
const OpenURLParams& params) {
- return NULL;
+ return nullptr;
}
bool WebContentsDelegate::IsPopupOrPanel(const WebContents* source) const {
@@ -33,7 +33,7 @@ gfx::Rect WebContentsDelegate::GetRootWindowResizerRect() const {
return gfx::Rect();
}
-bool WebContentsDelegate::ShouldSuppressDialogs() {
+bool WebContentsDelegate::ShouldSuppressDialogs(WebContents* source) {
return false;
}
@@ -63,12 +63,12 @@ bool WebContentsDelegate::ShouldFocusPageAfterCrash() {
return true;
}
-bool WebContentsDelegate::TakeFocus(WebContents* source, bool reverse) {
- return false;
+bool WebContentsDelegate::ShouldResumeRequestsForCreatedWindow() {
+ return true;
}
-int WebContentsDelegate::GetExtraRenderViewHeight() const {
- return 0;
+bool WebContentsDelegate::TakeFocus(WebContents* source, bool reverse) {
+ return false;
}
void WebContentsDelegate::CanDownload(
@@ -132,6 +132,7 @@ bool WebContentsDelegate::OnGoToEntryOffset(int offset) {
bool WebContentsDelegate::ShouldCreateWebContents(
WebContents* web_contents,
int route_id,
+ int main_frame_route_id,
WindowContainerType window_container_type,
const base::string16& frame_name,
const GURL& target_url,
@@ -140,8 +141,9 @@ bool WebContentsDelegate::ShouldCreateWebContents(
return true;
}
-JavaScriptDialogManager* WebContentsDelegate::GetJavaScriptDialogManager() {
- return NULL;
+JavaScriptDialogManager* WebContentsDelegate::GetJavaScriptDialogManager(
+ WebContents* source) {
+ return nullptr;
}
bool WebContentsDelegate::EmbedsFullscreenWidget() const {
@@ -153,11 +155,16 @@ bool WebContentsDelegate::IsFullscreenForTabOrPending(
return false;
}
+blink::WebDisplayMode WebContentsDelegate::GetDisplayMode(
+ const WebContents* web_contents) const {
+ return blink::WebDisplayModeBrowser;
+}
+
content::ColorChooser* WebContentsDelegate::OpenColorChooser(
WebContents* web_contents,
SkColor color,
const std::vector<ColorSuggestion>& suggestions) {
- return NULL;
+ return nullptr;
}
void WebContentsDelegate::RequestMediaAccessPermission(
@@ -191,7 +198,7 @@ bool WebContentsDelegate::RequestPpapiBrokerPermission(
WebContentsDelegate::~WebContentsDelegate() {
while (!attached_contents_.empty()) {
WebContents* web_contents = *attached_contents_.begin();
- web_contents->SetDelegate(NULL);
+ web_contents->SetDelegate(nullptr);
}
DCHECK(attached_contents_.empty());
}
@@ -215,4 +222,8 @@ bool WebContentsDelegate::IsNeverVisible(WebContents* web_contents) {
return false;
}
+bool WebContentsDelegate::SaveFrame(const GURL& url, const Referrer& referrer) {
+ return false;
+}
+
} // namespace content
diff --git a/chromium/content/public/browser/web_contents_delegate.h b/chromium/content/public/browser/web_contents_delegate.h
index bcd5caf609b..05e3a1d8d23 100644
--- a/chromium/content/public/browser/web_contents_delegate.h
+++ b/chromium/content/public/browser/web_contents_delegate.h
@@ -16,11 +16,12 @@
#include "content/public/browser/navigation_type.h"
#include "content/public/common/media_stream_request.h"
#include "content/public/common/window_container_type.h"
+#include "third_party/WebKit/public/platform/WebDisplayMode.h"
#include "third_party/WebKit/public/web/WebDragOperation.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/window_open_disposition.h"
+#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/rect_f.h"
class GURL;
@@ -56,8 +57,6 @@ class Size;
namespace blink {
class WebGestureEvent;
-class WebLayer;
-struct WebWindowFeatures;
}
namespace content {
@@ -74,10 +73,10 @@ class CONTENT_EXPORT WebContentsDelegate {
// in the current front-most tab), unless |disposition| indicates the url
// should be opened in a new tab or window.
//
- // A NULL source indicates the current tab (callers should probably use
+ // A nullptr source indicates the current tab (callers should probably use
// OpenURL() for these cases which does it for you).
- // Returns the WebContents the URL is opened in, or NULL if the URL wasn't
+ // Returns the WebContents the URL is opened in, or nullptr if the URL wasn't
// opened immediately.
virtual WebContents* OpenURLFromTab(WebContents* source,
const OpenURLParams& params);
@@ -85,7 +84,7 @@ class CONTENT_EXPORT WebContentsDelegate {
// Called to inform the delegate that the WebContents's navigation state
// changed. The |changed_flags| indicates the parts of the navigation state
// that have been updated.
- virtual void NavigationStateChanged(const WebContents* source,
+ virtual void NavigationStateChanged(WebContents* source,
InvalidateTypes changed_flags) {}
// Called to inform the delegate that the WebContent's visible SSL state (as
@@ -94,14 +93,14 @@ class CONTENT_EXPORT WebContentsDelegate {
// Creates a new tab with the already-created WebContents 'new_contents'.
// The window for the added contents should be reparented correctly when this
- // method returns. If |disposition| is NEW_POPUP, |initial_pos| should hold
- // the initial position. If |was_blocked| is non-NULL, then |*was_blocked|
- // will be set to true if the popup gets blocked, and left unchanged
- // otherwise.
+ // method returns. If |disposition| is NEW_POPUP, |initial_rect| should hold
+ // the initial position and size. If |was_blocked| is non-nullptr, then
+ // |*was_blocked| will be set to true if the popup gets blocked, and left
+ // unchanged otherwise.
virtual void AddNewContents(WebContents* source,
WebContents* new_contents,
WindowOpenDisposition disposition,
- const gfx::Rect& initial_pos,
+ const gfx::Rect& initial_rect,
bool user_gesture,
bool* was_blocked) {}
@@ -176,7 +175,7 @@ class CONTENT_EXPORT WebContentsDelegate {
// Returns true if javascript dialogs and unload alerts are suppressed.
// Default is false.
- virtual bool ShouldSuppressDialogs();
+ virtual bool ShouldSuppressDialogs(WebContents* source);
// Returns whether pending NavigationEntries for aborted browser-initiated
// navigations should be preserved (and thus returned from GetVisibleURL).
@@ -216,6 +215,11 @@ class CONTENT_EXPORT WebContentsDelegate {
// to live. Default is true.
virtual bool ShouldFocusPageAfterCrash();
+ // Returns whether the page should resume accepting requests for the new
+ // window. This is used when window creation is asynchronous
+ // and the navigations need to be delayed. Default is true.
+ virtual bool ShouldResumeRequestsForCreatedWindow();
+
// This is called when WebKit tells us that it is done tabbing through
// controls on the page. Provides a way for WebContentsDelegates to handle
// this. Returns true if the delegate successfully handled it.
@@ -225,9 +229,6 @@ class CONTENT_EXPORT WebContentsDelegate {
// Invoked when the page loses mouse capture.
virtual void LostCapture() {}
- // Notification that |contents| has gained focus.
- virtual void WebContentsFocused(WebContents* contents) {}
-
// Asks the delegate if the given tab can download.
// Invoking the |callback| synchronously is OK.
virtual void CanDownload(RenderViewHost* render_view_host,
@@ -235,11 +236,6 @@ class CONTENT_EXPORT WebContentsDelegate {
const std::string& request_method,
const base::Callback<void(bool)>& callback);
- // Return much extra vertical space should be allotted to the
- // render view widget during various animations (e.g. infobar closing).
- // This is used to make painting look smoother.
- virtual int GetExtraRenderViewHeight() const;
-
// Returns true if the context menu operation was handled by the delegate.
virtual bool HandleContextMenu(const content::ContextMenuParams& params);
@@ -265,13 +261,6 @@ class CONTENT_EXPORT WebContentsDelegate {
virtual void HandleKeyboardEvent(WebContents* source,
const NativeWebKeyboardEvent& event) {}
- virtual void HandleMouseDown() {}
- virtual void HandleMouseUp() {}
-
- // Handles activation resulting from a pointer event (e.g. when mouse is
- // pressed, or a touch-gesture begins).
- virtual void HandlePointerActivate() {}
-
// Allows delegates to handle gesture events before sending to the renderer.
// Returns true if the |event| was handled and thus shouldn't be processed
// by the renderer's event handler. Note that the touch events that create
@@ -281,9 +270,6 @@ class CONTENT_EXPORT WebContentsDelegate {
WebContents* source,
const blink::WebGestureEvent& event);
- virtual void HandleGestureBegin() {}
- virtual void HandleGestureEnd() {}
-
// Called when an external drag event enters the web contents window. Return
// true to allow dragging and dropping on the web contents window or false to
// cancel the operation. This method is used by Chromium Embedded Framework.
@@ -291,9 +277,6 @@ class CONTENT_EXPORT WebContentsDelegate {
const DropData& data,
blink::WebDragOperationsMask operations_allowed);
- // Render view drag n drop ended.
- virtual void DragEnded() {}
-
// Shows the repost form confirmation dialog box.
virtual void ShowRepostFormWarningDialog(WebContents* source) {}
@@ -309,6 +292,7 @@ class CONTENT_EXPORT WebContentsDelegate {
virtual bool ShouldCreateWebContents(
WebContents* web_contents,
int route_id,
+ int main_frame_route_id,
WindowContainerType window_container_type,
const base::string16& frame_name,
const GURL& target_url,
@@ -335,18 +319,14 @@ class CONTENT_EXPORT WebContentsDelegate {
// Invoked when a main fram navigation occurs.
virtual void DidNavigateMainFramePostCommit(WebContents* source) {}
- // Invoked when navigating to a pending entry. When invoked the
- // NavigationController has configured its pending entry, but it has not yet
- // been committed.
- virtual void DidNavigateToPendingEntry(WebContents* source) {}
-
// Returns a pointer to a service to manage JavaScript dialogs. May return
- // NULL in which case dialogs aren't shown.
- virtual JavaScriptDialogManager* GetJavaScriptDialogManager();
+ // nullptr in which case dialogs aren't shown.
+ virtual JavaScriptDialogManager* GetJavaScriptDialogManager(
+ WebContents* source);
// Called when color chooser should open. Returns the opened color chooser.
- // Returns NULL if we failed to open the color chooser (e.g. when there is a
- // ColorChooserDialog already open on Windows). Ownership of the returned
+ // Returns nullptr if we failed to open the color chooser (e.g. when there is
+ // a ColorChooserDialog already open on Windows). Ownership of the returned
// pointer is transferred to the caller.
virtual ColorChooser* OpenColorChooser(
WebContents* web_contents,
@@ -370,12 +350,27 @@ class CONTENT_EXPORT WebContentsDelegate {
// WebContents will be responsible for showing the fullscreen widget.
virtual bool EmbedsFullscreenWidget() const;
- // Called when the renderer puts a tab into or out of fullscreen mode.
- virtual void ToggleFullscreenModeForTab(WebContents* web_contents,
- bool enter_fullscreen) {}
+ // Called when the renderer puts a tab into fullscreen mode.
+ // |origin| is the origin of the initiating frame inside the |web_contents|.
+ // |origin| can be empty in which case the |web_contents| last committed
+ // URL's origin should be used.
+ virtual void EnterFullscreenModeForTab(WebContents* web_contents,
+ const GURL& origin) {}
+
+ // Called when the renderer puts a tab out of fullscreen mode.
+ virtual void ExitFullscreenModeForTab(WebContents*) {}
+
virtual bool IsFullscreenForTabOrPending(
const WebContents* web_contents) const;
+ // Returns the actual display mode of the top-level browsing context.
+ // For example, it should return 'blink::WebDisplayModeFullscreen' whenever
+ // the browser window is put to fullscreen mode (either by the end user,
+ // or HTML API or from a web manifest setting).
+ // See http://w3c.github.io/manifest/#dfn-display-mode
+ virtual blink::WebDisplayMode GetDisplayMode(
+ const WebContents* web_contents) const;
+
// Register a new handler for URL requests with the given scheme.
// |user_gesture| is true if the registration is made in the context of a user
// gesture.
@@ -487,6 +482,10 @@ class CONTENT_EXPORT WebContentsDelegate {
// Returns true if the WebContents is never visible.
virtual bool IsNeverVisible(WebContents* web_contents);
+ // Called in response to a request to save a frame. If this returns true, the
+ // default behavior is suppressed.
+ virtual bool SaveFrame(const GURL& url, const Referrer& referrer);
+
protected:
virtual ~WebContentsDelegate();
diff --git a/chromium/content/public/browser/web_contents_observer.cc b/chromium/content/public/browser/web_contents_observer.cc
index 3178b188bd5..1e705f86527 100644
--- a/chromium/content/public/browser/web_contents_observer.cc
+++ b/chromium/content/public/browser/web_contents_observer.cc
@@ -11,12 +11,12 @@
namespace content {
WebContentsObserver::WebContentsObserver(WebContents* web_contents)
- : web_contents_(NULL) {
+ : web_contents_(nullptr) {
Observe(web_contents);
}
WebContentsObserver::WebContentsObserver()
- : web_contents_(NULL) {
+ : web_contents_(nullptr) {
}
WebContentsObserver::~WebContentsObserver() {
@@ -69,7 +69,7 @@ int WebContentsObserver::routing_id() const {
void WebContentsObserver::ResetWebContents() {
web_contents_->RemoveObserver(this);
- web_contents_ = NULL;
+ web_contents_ = nullptr;
}
} // namespace content
diff --git a/chromium/content/public/browser/web_contents_observer.h b/chromium/content/public/browser/web_contents_observer.h
index d792ad22e03..b040d64223f 100644
--- a/chromium/content/public/browser/web_contents_observer.h
+++ b/chromium/content/public/browser/web_contents_observer.h
@@ -48,13 +48,35 @@ struct ResourceRequestDetails;
class CONTENT_EXPORT WebContentsObserver : public IPC::Listener,
public IPC::Sender {
public:
- // Called when a RenderFrameHost associated with this WebContents is created.
+ // Called when a RenderFrame for |render_frame_host| is created in the
+ // renderer process. Use |RenderFrameDeleted| to listen for when this
+ // RenderFrame goes away.
virtual void RenderFrameCreated(RenderFrameHost* render_frame_host) {}
- // Called whenever a RenderFrameHost associated with this WebContents is
- // deleted.
+ // Called when a RenderFrame for |render_frame_host| is deleted or the
+ // renderer process in which it runs it has died. Use |RenderFrameCreated| to
+ // listen for when RenderFrame objects are created.
virtual void RenderFrameDeleted(RenderFrameHost* render_frame_host) {}
+ // This method is invoked whenever one of the current frames of a WebContents
+ // swaps its RenderFrameHost with another one; for example because that frame
+ // navigated and the new content is in a different process. The
+ // RenderFrameHost that has been replaced is in |old_host|, which can be
+ // nullptr if the old RenderFrameHost was shut down or a new frame has been
+ // created and no old RenderFrameHost exists.
+ //
+ // This method, in combination with |FrameDeleted|, is appropriate for
+ // observers wishing to track the set of current RenderFrameHosts -- i.e.,
+ // those hosts that would be visited by calling WebContents::ForEachFrame.
+ virtual void RenderFrameHostChanged(RenderFrameHost* old_host,
+ RenderFrameHost* new_host) {}
+
+ // This method is invoked when a subframe associated with a WebContents is
+ // deleted or the WebContents is destroyed and the top-level frame is deleted.
+ // Use |RenderFrameHostChanged| to listen for when a RenderFrameHost object is
+ // made the current host for a frame.
+ virtual void FrameDeleted(RenderFrameHost* render_frame_host) {}
+
// This is called when a RVH is created for a WebContents, but not if it's an
// interstitial.
virtual void RenderViewCreated(RenderViewHost* render_view_host) {}
@@ -84,26 +106,20 @@ class CONTENT_EXPORT WebContentsObserver : public IPC::Listener,
// This method is invoked when a WebContents swaps its visible RenderViewHost
// with another one, possibly changing processes. The RenderViewHost that has
- // been replaced is in |old_host|, which is NULL if the old RVH was shut down.
+ // been replaced is in |old_host|, which is nullptr if the old RVH was shut
+ // down.
virtual void RenderViewHostChanged(RenderViewHost* old_host,
RenderViewHost* new_host) {}
- // This method is invoked whenever one of the current frames of a WebContents
- // swaps its RenderFrameHost with another one; for example because that frame
- // navigated and the new content is in a different process. The
- // RenderFrameHost that has been replaced is in |old_host|, which can be NULL
- // if the old RFH was shut down.
+ // This method is invoked after the WebContents decides which RenderFrameHost
+ // to use for the next browser-initiated navigation, but before the navigation
+ // starts. It is not called for most renderer-initiated navigations, and it
+ // does not guarantee that the navigation will commit (e.g., 204s, downloads).
//
- // This method, in combination with RenderFrameDeleted, is appropriate for
- // observers wishing to track the set of active RenderFrameHosts -- i.e.,
- // those hosts that would be visited by calling WebContents::ForEachFrame.
- virtual void RenderFrameHostChanged(RenderFrameHost* old_host,
- RenderFrameHost* new_host) {}
-
- // This method is invoked after the WebContents decided which RenderViewHost
- // to use for the next navigation, but before the navigation starts.
- virtual void AboutToNavigateRenderView(
- RenderViewHost* render_view_host) {}
+ // DEPRECATED. This method is difficult to use correctly and should be
+ // removed. TODO(creis): Remove in http://crbug.com/424641.
+ virtual void AboutToNavigateRenderFrame(RenderFrameHost* old_host,
+ RenderFrameHost* new_host) {}
// This method is invoked after the browser process starts a navigation to a
// pending NavigationEntry. It is not called for renderer-initiated
@@ -201,7 +217,7 @@ class CONTENT_EXPORT WebContentsObserver : public IPC::Listener,
// This method is invoked when a redirect was received while requesting a
// resource.
virtual void DidGetRedirectForResourceRequest(
- RenderViewHost* render_view_host,
+ RenderFrameHost* render_frame_host,
const ResourceRedirectDetails& details) {}
// This method is invoked when a new non-pending navigation entry is created.
@@ -213,25 +229,23 @@ class CONTENT_EXPORT WebContentsObserver : public IPC::Listener,
// This method is invoked when a new WebContents was created in response to
// an action in the observed WebContents, e.g. a link with target=_blank was
- // clicked. The |source_frame_id| indicates in which frame the action took
- // place.
+ // clicked. The |source_render_frame_host| is the frame in which the action
+ // took place.
virtual void DidOpenRequestedURL(WebContents* new_contents,
+ RenderFrameHost* source_render_frame_host,
const GURL& url,
const Referrer& referrer,
WindowOpenDisposition disposition,
- ui::PageTransition transition,
- int64 source_frame_id) {}
-
- virtual void FrameDetached(RenderFrameHost* render_frame_host) {}
+ ui::PageTransition transition) {}
- // This method is invoked when the renderer has completed its first paint
- // after a non-empty layout.
+ // This method is invoked when the renderer process has completed its first
+ // paint after a non-empty layout.
virtual void DidFirstVisuallyNonEmptyPaint() {}
// These two methods correspond to the points in time when the spinner of the
// tab starts and stops spinning.
- virtual void DidStartLoading(RenderViewHost* render_view_host) {}
- virtual void DidStopLoading(RenderViewHost* render_view_host) {}
+ virtual void DidStartLoading() {}
+ virtual void DidStopLoading() {}
// When WebContents::Stop() is called, the WebContents stops loading and then
// invokes this method. If there are ongoing navigations, their respective
@@ -249,6 +263,13 @@ class CONTENT_EXPORT WebContentsObserver : public IPC::Listener,
virtual void WasShown() {}
virtual void WasHidden() {}
+ // Invoked when the main frame changes size.
+ virtual void MainFrameWasResized(bool width_changed) {}
+
+ // Invoked when the given frame changes its window.name property.
+ virtual void FrameNameChanged(RenderFrameHost* render_frame_host,
+ const std::string& name) {}
+
// This methods is invoked when the title of the WebContents is set. If the
// title was explicitly set, |explicit_set| is true, otherwise the title was
// synthesized and |explicit_set| is false.
@@ -259,9 +280,9 @@ class CONTENT_EXPORT WebContentsObserver : public IPC::Listener,
// Notification that a plugin has crashed.
// |plugin_pid| is the process ID identifying the plugin process. Note that
- // this ID is supplied by the renderer, so should not be trusted. Besides, the
- // corresponding process has probably died at this point. The ID may even have
- // been reused by a new process.
+ // this ID is supplied by the renderer process, so should not be trusted.
+ // Besides, the corresponding process has probably died at this point. The ID
+ // may even have been reused by a new process.
virtual void PluginCrashed(const base::FilePath& plugin_path,
base::ProcessId plugin_pid) {}
@@ -269,8 +290,9 @@ class CONTENT_EXPORT WebContentsObserver : public IPC::Listener,
// notification is only for Pepper plugins.
//
// The plugin_child_id is the unique child process ID from the plugin. Note
- // that this ID is supplied by the renderer, so should be validated before
- // it's used for anything in case there's an exploited renderer.
+ // that this ID is supplied by the renderer process, so should be validated
+ // before it's used for anything in case there's an exploited renderer
+ // process.
virtual void PluginHungStatusChanged(int plugin_child_id,
const base::FilePath& plugin_path,
bool is_hung) {}
@@ -281,21 +303,23 @@ class CONTENT_EXPORT WebContentsObserver : public IPC::Listener,
// Invoked when the WebContents is being destroyed. Gives subclasses a chance
// to cleanup. After the whole loop over all WebContentsObservers has been
- // finished, web_contents() returns NULL.
+ // finished, web_contents() returns nullptr.
virtual void WebContentsDestroyed() {}
// Called when the user agent override for a WebContents has been changed.
virtual void UserAgentOverrideSet(const std::string& user_agent) {}
- // Invoked when new FaviconURL candidates are received from the renderer.
+ // Invoked when new FaviconURL candidates are received from the renderer
+ // process.
virtual void DidUpdateFaviconURL(const std::vector<FaviconURL>& candidates) {}
// Invoked when a pepper plugin creates and shows or destroys a fullscreen
- // render widget.
+ // RenderWidget.
virtual void DidShowFullscreenWidget(int routing_id) {}
virtual void DidDestroyFullscreenWidget(int routing_id) {}
- // Invoked when the renderer has toggled the tab into/out of fullscreen mode.
+ // Invoked when the renderer process has toggled the tab into/out of
+ // fullscreen mode.
virtual void DidToggleFullscreenModeForTab(bool entered_fullscreen) {}
// Invoked when an interstitial page is attached or detached.
@@ -305,23 +329,33 @@ class CONTENT_EXPORT WebContentsObserver : public IPC::Listener,
// Invoked before a form repost warning is shown.
virtual void BeforeFormRepostWarningShow() {}
- // Invoked when the beforeunload handler fires. The time is from the renderer.
+ // Invoked when the beforeunload handler fires. The time is from the renderer
+ // process.
virtual void BeforeUnloadFired(const base::TimeTicks& proceed_time) {}
// Invoked when a user cancels a before unload dialog.
virtual void BeforeUnloadDialogCancelled() {}
- // Invoked when an accessibility event is received from the renderer.
+ // Invoked when an accessibility event is received from the renderer process.
virtual void AccessibilityEventReceived(
const std::vector<AXEventNotificationDetails>& details) {}
// Invoked when theme color is changed to |theme_color|.
virtual void DidChangeThemeColor(SkColor theme_color) {}
+ // Invoked when media is playing.
+ virtual void MediaStartedPlaying() {}
+
+ // Invoked when media is paused.
+ virtual void MediaPaused() {}
+
// Invoked if an IPC message is coming from a specific RenderFrameHost.
virtual bool OnMessageReceived(const IPC::Message& message,
RenderFrameHost* render_frame_host);
+ // Notification that |contents| has gained focus.
+ virtual void OnWebContentsFocused() {}
+
// IPC::Listener implementation.
bool OnMessageReceived(const IPC::Message& message) override;
diff --git a/chromium/content/public/browser/web_contents_user_data.h b/chromium/content/public/browser/web_contents_user_data.h
index e737ff30edb..5ee0fb9f633 100644
--- a/chromium/content/public/browser/web_contents_user_data.h
+++ b/chromium/content/public/browser/web_contents_user_data.h
@@ -40,7 +40,7 @@ class WebContentsUserData : public base::SupportsUserData::Data {
// Retrieves the instance of type T that was attached to the specified
// WebContents (via CreateForWebContents above) and returns it. If no instance
- // of the type was attached, returns NULL.
+ // of the type was attached, returns nullptr.
static T* FromWebContents(WebContents* contents) {
DCHECK(contents);
return static_cast<T*>(contents->GetUserData(UserDataKey()));
diff --git a/chromium/content/public/browser/web_contents_view_delegate.cc b/chromium/content/public/browser/web_contents_view_delegate.cc
index e582621be3f..5a2020433dd 100644
--- a/chromium/content/public/browser/web_contents_view_delegate.cc
+++ b/chromium/content/public/browser/web_contents_view_delegate.cc
@@ -11,8 +11,12 @@ namespace content {
WebContentsViewDelegate::~WebContentsViewDelegate() {
}
+gfx::NativeWindow WebContentsViewDelegate::GetNativeWindow() {
+ return nullptr;
+}
+
WebDragDestDelegate* WebContentsViewDelegate::GetDragDestDelegate() {
- return NULL;
+ return nullptr;
}
void WebContentsViewDelegate::ShowContextMenu(
@@ -49,7 +53,7 @@ void WebContentsViewDelegate::SizeChanged(const gfx::Size& size) {
void* WebContentsViewDelegate::CreateRenderWidgetHostViewDelegate(
RenderWidgetHost* render_widget_host) {
- return NULL;
+ return nullptr;
}
} // namespace content
diff --git a/chromium/content/public/browser/web_contents_view_delegate.h b/chromium/content/public/browser/web_contents_view_delegate.h
index ecbd0ff968a..75ded748ba3 100644
--- a/chromium/content/public/browser/web_contents_view_delegate.h
+++ b/chromium/content/public/browser/web_contents_view_delegate.h
@@ -39,6 +39,10 @@ class CONTENT_EXPORT WebContentsViewDelegate {
public:
virtual ~WebContentsViewDelegate();
+ // Returns the native window containing the WebContents, or nullptr if the
+ // WebContents is not in any window.
+ virtual gfx::NativeWindow GetNativeWindow();
+
// Returns a delegate to process drags not handled by content.
virtual WebDragDestDelegate* GetDragDestDelegate();
diff --git a/chromium/content/public/browser/web_ui_controller_factory.h b/chromium/content/public/browser/web_ui_controller_factory.h
index 74ae62a1f0f..80e88c700b3 100644
--- a/chromium/content/public/browser/web_ui_controller_factory.h
+++ b/chromium/content/public/browser/web_ui_controller_factory.h
@@ -27,14 +27,14 @@ class CONTENT_EXPORT WebUIControllerFactory {
static void UnregisterFactoryForTesting(WebUIControllerFactory* factory);
- // Returns a WebUIController instance for the given URL, or NULL if the URL
+ // Returns a WebUIController instance for the given URL, or nullptr if the URL
// doesn't correspond to a WebUI.
virtual WebUIController* CreateWebUIControllerForURL(
WebUI* web_ui, const GURL& url) const = 0;
// Gets the WebUI type for the given URL. This will return kNoWebUI if the
- // corresponding call to CreateWebUIForURL would fail, or something non-NULL
- // if CreateWebUIForURL would succeed.
+ // corresponding call to CreateWebUIForURL would fail, or something
+ // non-nullptr if CreateWebUIForURL would succeed.
virtual WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
const GURL& url) const = 0;
diff --git a/chromium/content/public/browser/web_ui_message_handler.h b/chromium/content/public/browser/web_ui_message_handler.h
index 20a60726033..b6908769a00 100644
--- a/chromium/content/public/browser/web_ui_message_handler.h
+++ b/chromium/content/public/browser/web_ui_message_handler.h
@@ -28,7 +28,7 @@ class WebUIImpl;
// host is destroyed.
class CONTENT_EXPORT WebUIMessageHandler {
public:
- WebUIMessageHandler() : web_ui_(NULL) {}
+ WebUIMessageHandler() : web_ui_(nullptr) {}
virtual ~WebUIMessageHandler() {}
protected:
diff --git a/chromium/content/public/browser/worker_service.h b/chromium/content/public/browser/worker_service.h
index 7ce2bf4ec1f..782b1fc0fd1 100644
--- a/chromium/content/public/browser/worker_service.h
+++ b/chromium/content/public/browser/worker_service.h
@@ -46,4 +46,4 @@ class WorkerService {
} // namespace content
-#endif // CONTENT_PUBLIC_BROWSER_PLUGIN_SERVICE_H_
+#endif // CONTENT_PUBLIC_BROWSER_WORKER_SERVICE_H_
diff --git a/chromium/content/public/browser/zoom_level_delegate.h b/chromium/content/public/browser/zoom_level_delegate.h
new file mode 100644
index 00000000000..e6a93bde06e
--- /dev/null
+++ b/chromium/content/public/browser/zoom_level_delegate.h
@@ -0,0 +1,21 @@
+// Copyright 2014 The Chromium Authors. 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_ZOOM_LEVEL_DELEGATE_H_
+#define CONTENT_PUBLIC_BROWSER_ZOOM_LEVEL_DELEGATE_H_
+
+namespace content {
+
+class HostZoomMap;
+
+// An interface to allow the client to initialize the HostZoomMap.
+class ZoomLevelDelegate {
+ public:
+ virtual void InitHostZoomMap(HostZoomMap* host_zoom_map) = 0;
+ virtual ~ZoomLevelDelegate() {}
+};
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_BROWSER_ZOOM_LEVEL_DELEGATE_H_
diff --git a/chromium/content/public/child/BUILD.gn b/chromium/content/public/child/BUILD.gn
index fff416aff02..fb5c5bf4334 100644
--- a/chromium/content/public/child/BUILD.gn
+++ b/chromium/content/public/child/BUILD.gn
@@ -7,9 +7,19 @@ import("//content/child/child.gni")
# See //content/BUILD.gn for how this works.
group("child") {
if (is_component_build) {
- public_deps = [ "//content" ]
+ public_deps = [
+ "//content",
+ ]
} else {
- public_deps = [ ":child_sources" ]
+ public_deps = [
+ ":child_sources",
+ ]
+ if (!is_android) {
+ public_deps += [
+ "//content/gpu",
+ "//content/ppapi_plugin",
+ ]
+ }
}
}
@@ -17,14 +27,16 @@ source_set("child_sources") {
visibility = [ "//content/*" ]
sources = rebase_path(content_child_gypi_values.public_child_sources,
- ".", "//content")
+ ".",
+ "//content")
- configs += [
- "//content:content_implementation",
+ configs += [ "//content:content_implementation" ]
+
+ public_deps = [
+ "//content/child",
]
deps = [
- "//content/child",
"//content/public/common:common_sources",
]
}
diff --git a/chromium/content/public/child/DEPS b/chromium/content/public/child/DEPS
new file mode 100644
index 00000000000..fdd9052e81a
--- /dev/null
+++ b/chromium/content/public/child/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+v8/include/v8.h",
+]
diff --git a/chromium/content/public/child/child_thread.h b/chromium/content/public/child/child_thread.h
new file mode 100644
index 00000000000..6293ed164d8
--- /dev/null
+++ b/chromium/content/public/child/child_thread.h
@@ -0,0 +1,37 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_PUBLIC_CHILD_CHILD_THREAD_H_
+#define CONTENT_PUBLIC_CHILD_CHILD_THREAD_H_
+
+#include "content/common/content_export.h"
+#include "ipc/ipc_sender.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+namespace content {
+
+class CONTENT_EXPORT ChildThread : public IPC::Sender {
+ public:
+ // Returns the one child thread for this process. Note that this can only be
+ // accessed when running on the child thread itself.
+ static ChildThread* Get();
+
+ ~ChildThread() override {}
+
+#if defined(OS_WIN)
+ // Request that the given font be loaded by the browser so it's cached by the
+ // OS. Please see ChildProcessHost::PreCacheFont for details.
+ virtual void PreCacheFont(const LOGFONT& log_font) = 0;
+
+ // Release cached font.
+ virtual void ReleaseCachedFonts() = 0;
+#endif
+};
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_CHILD_CHILD_THREAD_H_
diff --git a/chromium/content/public/child/image_decoder_utils.h b/chromium/content/public/child/image_decoder_utils.h
index e7565157615..c85893d7a51 100644
--- a/chromium/content/public/child/image_decoder_utils.h
+++ b/chromium/content/public/child/image_decoder_utils.h
@@ -2,15 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CONTENT_PUBLIC_UTILITY_IMAGE_DECODER_UTILS_H_
-#define CONTENT_PUBLIC_UTILITY_IMAGE_DECODER_UTILS_H_
+#ifndef CONTENT_PUBLIC_CHILD_IMAGE_DECODER_UTILS_H_
+#define CONTENT_PUBLIC_CHILD_IMAGE_DECODER_UTILS_H_
#include "base/basictypes.h"
#include "content/common/content_export.h"
-#include "ui/gfx/size.h"
class SkBitmap;
+namespace gfx {
+class Size;
+}
+
namespace content {
// Helper function to decode the image using the data passed in.
@@ -21,4 +24,4 @@ CONTENT_EXPORT SkBitmap DecodeImage(const unsigned char* data,
size_t size);
} // namespace content
-#endif // CONTENT_PUBLIC_UTILITY_IMAGE_DECODER_UTILS_H_
+#endif // CONTENT_PUBLIC_CHILD_IMAGE_DECODER_UTILS_H_
diff --git a/chromium/content/public/child/v8_value_converter.h b/chromium/content/public/child/v8_value_converter.h
new file mode 100644
index 00000000000..a7a0e8946f0
--- /dev/null
+++ b/chromium/content/public/child/v8_value_converter.h
@@ -0,0 +1,127 @@
+// 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_CHILD_V8_VALUE_CONVERTER_H_
+#define CONTENT_PUBLIC_CHILD_V8_VALUE_CONVERTER_H_
+
+#include "base/callback.h"
+#include "content/common/content_export.h"
+#include "v8/include/v8.h"
+
+namespace base {
+class Value;
+}
+
+namespace content {
+
+// Converts between v8::Value (JavaScript values in the v8 heap) and Chrome's
+// values (from base/values.h). Lists and dictionaries are converted
+// recursively.
+//
+// The JSON types (null, boolean, string, number, array, and object) as well as
+// binary values are supported. For binary values, we convert to WebKit
+// ArrayBuffers, and support converting from an ArrayBuffer or any of the
+// ArrayBufferView subclasses (Uint8Array, etc.).
+class CONTENT_EXPORT V8ValueConverter {
+ public:
+ // Extends the default behaviour of V8ValueConverter.
+ class CONTENT_EXPORT Strategy {
+ public:
+ typedef base::Callback<base::Value*(
+ v8::Local<v8::Value>, v8::Isolate* isolate)> FromV8ValueCallback;
+
+ virtual ~Strategy() {}
+
+ // If false is returned, V8ValueConverter proceeds with the default
+ // behavior.
+ // Use |callback| to convert any child values, as this will retain
+ // the ValueConverter's internal checks for depth and cycles.
+ virtual bool FromV8Object(v8::Local<v8::Object> value,
+ base::Value** out,
+ v8::Isolate* isolate,
+ const FromV8ValueCallback& callback) const;
+
+ // If false is returned, V8ValueConverter proceeds with the default
+ // behavior.
+ // Use |callback| to convert any child values, as this will retain
+ // the ValueConverter's internal checks for depth and cycles.
+ virtual bool FromV8Array(v8::Local<v8::Array> value,
+ base::Value** out,
+ v8::Isolate* isolate,
+ const FromV8ValueCallback& callback) const;
+
+ // If false is returned, V8ValueConverter proceeds with the default
+ // behavior. v8::Object is passed as ArrayBuffer and ArrayBufferView
+ // classes are siblings.
+ virtual bool FromV8ArrayBuffer(v8::Local<v8::Object> value,
+ base::Value** out,
+ v8::Isolate* isolate) const;
+
+ // If false is returned, V8ValueConverter proceeds with the default
+ // behavior. This allows to intercept "non-finite" values and do something
+ // with them.
+ virtual bool FromV8Number(v8::Local<v8::Number> value,
+ base::Value** out) const;
+
+ // If false is returned, V8ValueConverter proceeds with the default
+ // behavior.
+ virtual bool FromV8Undefined(base::Value** out) const;
+ };
+
+ static V8ValueConverter* create();
+
+ virtual ~V8ValueConverter() {}
+
+ // If true, Date objects are converted into DoubleValues with the number of
+ // seconds since Unix epoch.
+ //
+ // Otherwise they are converted into DictionaryValues with whatever additional
+ // properties has been set on them.
+ virtual void SetDateAllowed(bool val) = 0;
+
+ // If true, RegExp objects are converted into StringValues with the regular
+ // expression between / and /, for example "/ab?c/".
+ //
+ // Otherwise they are converted into DictionaryValues with whatever additional
+ // properties has been set on them.
+ virtual void SetRegExpAllowed(bool val) = 0;
+
+ // If true, Function objects are converted into DictionaryValues with whatever
+ // additional properties has been set on them.
+ //
+ // Otherwise they are treated as unsupported, see FromV8Value.
+ virtual void SetFunctionAllowed(bool val) = 0;
+
+ // If true, null values are stripped from objects. This is often useful when
+ // converting arguments to extension APIs.
+ virtual void SetStripNullFromObjects(bool val) = 0;
+
+ // Extend default behavior of V8ValueConverter.
+ virtual void SetStrategy(Strategy* strategy) = 0;
+
+ // Converts a base::Value to a v8::Value.
+ //
+ // Unsupported types are replaced with null. If an array or object throws
+ // while setting a value, that property or item is skipped, leaving a hole in
+ // the case of arrays.
+ virtual v8::Local<v8::Value> ToV8Value(
+ const base::Value* value,
+ v8::Local<v8::Context> context) const = 0;
+
+ // Converts a v8::Value to base::Value.
+ //
+ // Unsupported types (unless explicitly configured) are not converted, so
+ // this method may return NULL -- the exception is when converting arrays,
+ // where unsupported types are converted to Value(TYPE_NULL).
+ //
+ // Likewise, if an object throws while converting a property it will not be
+ // converted, whereas if an array throws while converting an item it will be
+ // converted to Value(TYPE_NULL).
+ virtual base::Value* FromV8Value(v8::Local<v8::Value> value,
+ v8::Local<v8::Context> context) const = 0;
+};
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_CHILD_V8_VALUE_CONVERTER_H_
diff --git a/chromium/content/public/common/BUILD.gn b/chromium/content/public/common/BUILD.gn
index c4d003669dc..51772e35912 100644
--- a/chromium/content/public/common/BUILD.gn
+++ b/chromium/content/public/common/BUILD.gn
@@ -4,14 +4,18 @@
import("//build/config/features.gni")
import("//content/common/common.gni")
-import("//mojo/public/tools/bindings/mojom.gni")
+import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni")
# See //content/BUILD.gn for how this works.
group("common") {
if (is_component_build) {
- public_deps = [ "//content" ]
+ public_deps = [
+ "//content",
+ ]
} else {
- public_deps = [ ":common_sources" ]
+ public_deps = [
+ ":common_sources",
+ ]
}
}
@@ -19,14 +23,14 @@ source_set("common_sources") {
visibility = [ "//content/*" ]
sources = rebase_path(content_common_gypi_values.public_common_sources,
- ".", "//content")
+ ".",
+ "//content")
- configs += [
- "//content:content_implementation",
- ]
+ configs += [ "//content:content_implementation" ]
public_deps = [
"//content/common",
+ "//third_party/mojo/src/mojo/public/cpp/bindings",
]
deps = [
"//net",
@@ -47,6 +51,8 @@ source_set("common_sources") {
mojom("mojo_bindings") {
sources = [
+ "background_sync.mojom",
"mojo_geoposition.mojom",
+ "permission_status.mojom",
]
}
diff --git a/chromium/content/public/common/OWNERS b/chromium/content/public/common/OWNERS
index 86e41044421..95aabc67f23 100644
--- a/chromium/content/public/common/OWNERS
+++ b/chromium/content/public/common/OWNERS
@@ -13,6 +13,10 @@ per-file *param_traits*.h=palmer@chromium.org
per-file *param_traits*.h=tsepez@chromium.org
per-file *param_traits*.h=wfh@chromium.org
+# DirectWrite
+per-file dwrite_font_platform_win.h=shrikant@chromium.org
+per-file dwrite_font_platform_win.h=scottmg@chromium.org
+
# Changes to Mojo interfaces require a security review to avoid
# introducing new sandbox escapes.
per-file *.mojom=set noparent
diff --git a/chromium/content/public/common/background_sync.mojom b/chromium/content/public/common/background_sync.mojom
new file mode 100644
index 00000000000..8d3bdd22ef7
--- /dev/null
+++ b/chromium/content/public/common/background_sync.mojom
@@ -0,0 +1,33 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module content;
+
+enum BackgroundSyncNetworkState {
+ ANY,
+ AVOID_CELLULAR,
+ ONLINE,
+ MAX=ONLINE
+};
+
+enum BackgroundSyncPowerState {
+ AUTO,
+ AVOID_DRAINING,
+ MAX=AVOID_DRAINING
+};
+
+enum BackgroundSyncPeriodicity {
+ PERIODIC,
+ ONE_SHOT,
+ MAX=ONE_SHOT
+};
+
+struct SyncRegistration {
+ int64 id = -1;
+ BackgroundSyncPeriodicity periodicity = ONE_SHOT;
+ string tag = "";
+ uint64 min_period_ms = 0;
+ BackgroundSyncNetworkState network_state = ONLINE;
+ BackgroundSyncPowerState power_state = AUTO;
+};
diff --git a/chromium/content/public/common/child_process_host.h b/chromium/content/public/common/child_process_host.h
index cd9ed56ab58..c79938b405f 100644
--- a/chromium/content/public/common/child_process_host.h
+++ b/chromium/content/public/common/child_process_host.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_PULIC_COMMON_CHILD_PROCESS_HOST_H_
-#define CONTENT_PULIC_COMMON_CHILD_PROCESS_HOST_H_
+#ifndef CONTENT_PUBLIC_COMMON_CHILD_PROCESS_HOST_H_
+#define CONTENT_PUBLIC_COMMON_CHILD_PROCESS_HOST_H_
#include "base/files/scoped_file.h"
#include "build/build_config.h"
@@ -64,7 +64,7 @@ class CONTENT_EXPORT ChildProcessHost : public IPC::Sender {
// Requests that the child run in a process that does not protect the
// heap against execution. Normally, heap pages may be made executable
// with mprotect, so this mode should be used sparingly. It is intended
- // for processes that may host plug-ins that expect an executable heap
+ // for processes that may host plugins that expect an executable heap
// without having to call mprotect. This option is currently incompatible
// with CHILD_NO_PIE.
CHILD_ALLOW_HEAP_EXECUTION = 1 << 2,
@@ -105,4 +105,4 @@ class CONTENT_EXPORT ChildProcessHost : public IPC::Sender {
}; // namespace content
-#endif // CONTENT_PULIC_COMMON_CHILD_PROCESS_HOST_H_
+#endif // CONTENT_PUBLIC_COMMON_CHILD_PROCESS_HOST_H_
diff --git a/chromium/content/public/common/child_process_host_delegate.h b/chromium/content/public/common/child_process_host_delegate.h
index 9aa23ae8823..95942763c15 100644
--- a/chromium/content/public/common/child_process_host_delegate.h
+++ b/chromium/content/public/common/child_process_host_delegate.h
@@ -28,9 +28,9 @@ class ChildProcessHostDelegate : public IPC::Listener {
// would normally delete the object in this case.
virtual void OnChildDisconnected() {}
- // Returns the handle of the child process. This can be called only after
+ // Returns a reference to the child process. This can be called only after
// OnProcessLaunched is called or it will be invalid and may crash.
- virtual base::ProcessHandle GetHandle() const = 0;
+ virtual const base::Process& GetProcess() const = 0;
};
}; // namespace content
diff --git a/chromium/content/public/common/child_process_sandbox_support_linux.h b/chromium/content/public/common/child_process_sandbox_support_linux.h
index 58dc3ea8bf5..9e1cde273ad 100644
--- a/chromium/content/public/common/child_process_sandbox_support_linux.h
+++ b/chromium/content/public/common/child_process_sandbox_support_linux.h
@@ -50,10 +50,6 @@ CONTENT_EXPORT int MatchFontWithFallback(
CONTENT_EXPORT bool GetFontTable(int fd, uint32_t table_tag, off_t offset,
uint8_t* output, size_t* output_length);
-// Sends a zygote child "ping" message to browser process via socket |fd|.
-// Returns true on success.
-CONTENT_EXPORT bool SendZygoteChildPing(int fd);
-
}; // namespace content
#endif // CONTENT_PUBLIC_COMMON_CHILD_PROCESS_SANDBOX_SUPPORT_LINUX_H_
diff --git a/chromium/content/public/common/common_param_traits.cc b/chromium/content/public/common/common_param_traits.cc
index f4f9a0874b5..a0b5bd3d498 100644
--- a/chromium/content/public/common/common_param_traits.cc
+++ b/chromium/content/public/common/common_param_traits.cc
@@ -35,7 +35,7 @@ void ParamTraits<GURL>::Write(Message* m, const GURL& p) {
bool ParamTraits<GURL>::Read(const Message* m, PickleIterator* iter, GURL* p) {
std::string s;
- if (!m->ReadString(iter, &s) || s.length() > content::GetMaxURLChars()) {
+ if (!iter->ReadString(&s) || s.length() > content::GetMaxURLChars()) {
*p = GURL();
return false;
}
@@ -60,7 +60,7 @@ bool ParamTraits<url::Origin>::Read(const Message* m,
PickleIterator* iter,
url::Origin* p) {
std::string s;
- if (!m->ReadString(iter, &s)) {
+ if (!iter->ReadString(&s)) {
*p = url::Origin();
return false;
}
@@ -102,7 +102,7 @@ void ParamTraits<net::IPEndPoint>::Write(Message* m, const param_type& p) {
bool ParamTraits<net::IPEndPoint>::Read(const Message* m, PickleIterator* iter,
param_type* p) {
net::IPAddressNumber address;
- int port;
+ uint16 port;
if (!ReadParam(m, iter, &address) || !ReadParam(m, iter, &port))
return false;
if (address.size() &&
diff --git a/chromium/content/public/common/common_param_traits.h b/chromium/content/public/common/common_param_traits.h
index 657ef646c71..52d7a2f8c9b 100644
--- a/chromium/content/public/common/common_param_traits.h
+++ b/chromium/content/public/common/common_param_traits.h
@@ -89,11 +89,11 @@ struct ParamTraits<gfx::NativeWindow> {
}
static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
#if defined(OS_WIN)
- return m->ReadUInt32(iter, reinterpret_cast<uint32*>(r));
+ return iter->ReadUInt32(reinterpret_cast<uint32*>(r));
#else
const char *data;
int data_size = 0;
- bool result = m->ReadData(iter, &data, &data_size);
+ bool result = iter->ReadData(&data, &data_size);
if (result && data_size == sizeof(gfx::NativeWindow)) {
memcpy(r, data, sizeof(gfx::NativeWindow));
} else {
diff --git a/chromium/content/public/common/common_param_traits_macros.h b/chromium/content/public/common/common_param_traits_macros.h
index cb17472ea91..53f112826e2 100644
--- a/chromium/content/public/common/common_param_traits_macros.h
+++ b/chromium/content/public/common/common_param_traits_macros.h
@@ -28,7 +28,10 @@
#undef IPC_MESSAGE_EXPORT
#define IPC_MESSAGE_EXPORT CONTENT_EXPORT
-IPC_ENUM_TRAITS(ui::PageTransition) // Bitmask.
+IPC_ENUM_TRAITS_VALIDATE(ui::PageTransition,
+ ((value &
+ ui::PageTransition::PAGE_TRANSITION_CORE_MASK) <=
+ ui::PageTransition::PAGE_TRANSITION_LAST_CORE))
IPC_ENUM_TRAITS_MAX_VALUE(net::NetworkChangeNotifier::ConnectionType,
net::NetworkChangeNotifier::CONNECTION_LAST)
IPC_ENUM_TRAITS_MAX_VALUE(content::ConsoleMessageLevel,
@@ -44,8 +47,15 @@ IPC_ENUM_TRAITS_MAX_VALUE(WindowOpenDisposition,
IPC_ENUM_TRAITS_MAX_VALUE(net::RequestPriority, net::MAXIMUM_PRIORITY)
IPC_ENUM_TRAITS_MAX_VALUE(content::V8CacheOptions,
content::V8_CACHE_OPTIONS_LAST)
-IPC_ENUM_TRAITS_MAX_VALUE(content::V8ScriptStreamingMode,
- content::V8_SCRIPT_STREAMING_MODE_LAST)
+IPC_ENUM_TRAITS_MIN_MAX_VALUE(ui::PointerType,
+ ui::POINTER_TYPE_FIRST,
+ ui::POINTER_TYPE_LAST)
+IPC_ENUM_TRAITS_MIN_MAX_VALUE(ui::HoverType,
+ ui::HOVER_TYPE_FIRST,
+ ui::HOVER_TYPE_LAST)
+IPC_ENUM_TRAITS_MIN_MAX_VALUE(content::ImageAnimationPolicy,
+ content::IMAGE_ANIMATION_POLICY_ALLOWED,
+ content::IMAGE_ANIMATION_POLICY_NO_ANIMATION)
IPC_STRUCT_TRAITS_BEGIN(blink::WebPoint)
IPC_STRUCT_TRAITS_MEMBER(x)
@@ -103,6 +113,7 @@ IPC_STRUCT_TRAITS_BEGIN(content::WebPreferences)
IPC_STRUCT_TRAITS_MEMBER(minimum_font_size)
IPC_STRUCT_TRAITS_MEMBER(minimum_logical_font_size)
IPC_STRUCT_TRAITS_MEMBER(default_encoding)
+ IPC_STRUCT_TRAITS_MEMBER(context_menu_on_mouse_up)
IPC_STRUCT_TRAITS_MEMBER(javascript_enabled)
IPC_STRUCT_TRAITS_MEMBER(web_security_enabled)
IPC_STRUCT_TRAITS_MEMBER(javascript_can_open_windows_automatically)
@@ -142,7 +153,6 @@ IPC_STRUCT_TRAITS_BEGIN(content::WebPreferences)
IPC_STRUCT_TRAITS_MEMBER(privileged_webgl_extensions_enabled)
IPC_STRUCT_TRAITS_MEMBER(webgl_errors_to_console_enabled)
IPC_STRUCT_TRAITS_MEMBER(mock_scrollbars_enabled)
- IPC_STRUCT_TRAITS_MEMBER(layer_squashing_enabled)
IPC_STRUCT_TRAITS_MEMBER(asynchronous_spell_checking_enabled)
IPC_STRUCT_TRAITS_MEMBER(unified_textchecker_enabled)
IPC_STRUCT_TRAITS_MEMBER(accelerated_2d_canvas_enabled)
@@ -156,6 +166,9 @@ IPC_STRUCT_TRAITS_BEGIN(content::WebPreferences)
IPC_STRUCT_TRAITS_MEMBER(text_blobs_enabled)
IPC_STRUCT_TRAITS_MEMBER(allow_displaying_insecure_content)
IPC_STRUCT_TRAITS_MEMBER(allow_running_insecure_content)
+ IPC_STRUCT_TRAITS_MEMBER(disable_reading_from_canvas)
+ IPC_STRUCT_TRAITS_MEMBER(strict_mixed_content_checking)
+ IPC_STRUCT_TRAITS_MEMBER(strict_powerful_feature_restrictions)
IPC_STRUCT_TRAITS_MEMBER(enable_scroll_animator)
IPC_STRUCT_TRAITS_MEMBER(password_echo_enabled)
IPC_STRUCT_TRAITS_MEMBER(should_clear_document_background)
@@ -165,6 +178,10 @@ IPC_STRUCT_TRAITS_BEGIN(content::WebPreferences)
IPC_STRUCT_TRAITS_MEMBER(device_supports_mouse)
IPC_STRUCT_TRAITS_MEMBER(touch_adjustment_enabled)
IPC_STRUCT_TRAITS_MEMBER(pointer_events_max_touch_points)
+ IPC_STRUCT_TRAITS_MEMBER(available_pointer_types)
+ IPC_STRUCT_TRAITS_MEMBER(primary_pointer_type)
+ IPC_STRUCT_TRAITS_MEMBER(available_hover_types)
+ IPC_STRUCT_TRAITS_MEMBER(primary_hover_type)
IPC_STRUCT_TRAITS_MEMBER(sync_xhr_in_documents_enabled)
IPC_STRUCT_TRAITS_MEMBER(deferred_image_decoding_enabled)
IPC_STRUCT_TRAITS_MEMBER(image_color_profiles_enabled)
@@ -181,10 +198,9 @@ IPC_STRUCT_TRAITS_BEGIN(content::WebPreferences)
IPC_STRUCT_TRAITS_MEMBER(navigate_on_drag_drop)
IPC_STRUCT_TRAITS_MEMBER(spatial_navigation_enabled)
IPC_STRUCT_TRAITS_MEMBER(v8_cache_options)
- IPC_STRUCT_TRAITS_MEMBER(v8_script_streaming_enabled)
- IPC_STRUCT_TRAITS_MEMBER(v8_script_streaming_mode)
IPC_STRUCT_TRAITS_MEMBER(slimming_paint_enabled)
IPC_STRUCT_TRAITS_MEMBER(pepper_accelerated_video_decode_enabled)
+ IPC_STRUCT_TRAITS_MEMBER(animation_policy)
#if defined(OS_ANDROID)
IPC_STRUCT_TRAITS_MEMBER(text_autosizing_enabled)
IPC_STRUCT_TRAITS_MEMBER(font_scale_factor)
@@ -207,6 +223,8 @@ IPC_STRUCT_TRAITS_BEGIN(content::WebPreferences)
IPC_STRUCT_TRAITS_MEMBER(ignore_main_frame_overflow_hidden_quirk)
IPC_STRUCT_TRAITS_MEMBER(report_screen_size_in_physical_pixels_quirk)
#endif
+ IPC_STRUCT_TRAITS_MEMBER(default_minimum_page_scale_factor)
+ IPC_STRUCT_TRAITS_MEMBER(default_maximum_page_scale_factor)
IPC_STRUCT_TRAITS_END()
IPC_STRUCT_TRAITS_BEGIN(blink::WebWindowFeatures)
diff --git a/chromium/content/public/common/console_message_level.h b/chromium/content/public/common/console_message_level.h
index af51c32c04a..b7c89177d7b 100644
--- a/chromium/content/public/common/console_message_level.h
+++ b/chromium/content/public/common/console_message_level.h
@@ -7,6 +7,8 @@
namespace content {
+// A Java counterpart will be generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.content_public.common
enum ConsoleMessageLevel {
CONSOLE_MESSAGE_LEVEL_DEBUG,
CONSOLE_MESSAGE_LEVEL_LOG,
diff --git a/chromium/content/public/common/content_client.cc b/chromium/content/public/common/content_client.cc
index 425c40ff29d..421a0a33540 100644
--- a/chromium/content/public/common/content_client.cc
+++ b/chromium/content/public/common/content_client.cc
@@ -6,6 +6,7 @@
#include "base/logging.h"
#include "base/strings/string_piece.h"
+#include "content/public/common/origin_util.h"
#include "content/public/common/user_agent.h"
#include "ui/gfx/image/image.h"
diff --git a/chromium/content/public/common/content_client.h b/chromium/content/public/common/content_client.h
index 13f0d5c57dc..9b9cebac720 100644
--- a/chromium/content/public/common/content_client.h
+++ b/chromium/content/public/common/content_client.h
@@ -5,6 +5,7 @@
#ifndef CONTENT_PUBLIC_COMMON_CONTENT_CLIENT_H_
#define CONTENT_PUBLIC_COMMON_CONTENT_CLIENT_H_
+#include <set>
#include <string>
#include <vector>
@@ -134,6 +135,12 @@ class CONTENT_EXPORT ContentClient {
int* sandbox_profile_resource_id) const;
#endif
+ // Gives the embedder a chance to register additional schemes and origins
+ // that need to be considered trustworthy.
+ // See https://www.w3.org/TR/powerful-features/#is-origin-trustworthy.
+ virtual void AddSecureSchemesAndOrigins(std::set<std::string>* schemes,
+ std::set<GURL>* origins) {}
+
private:
friend class ContentClientInitializer; // To set these pointers.
friend class InternalTestInitializer;
diff --git a/chromium/content/public/common/content_descriptors.h b/chromium/content/public/common/content_descriptors.h
index db972015048..9b1ecc0759e 100644
--- a/chromium/content/public/common/content_descriptors.h
+++ b/chromium/content/public/common/content_descriptors.h
@@ -13,15 +13,14 @@ enum {
kCrashDumpSignal = kIPCDescriptorMax,
kSandboxIPCChannel, // http://code.google.com/p/chromium/LinuxSandboxIPC
-#if defined(OS_ANDROID)
- kAndroidPropertyDescriptor,
- kAndroidICUDataDescriptor,
-
-#ifdef V8_USE_EXTERNAL_STARTUP_DATA
+#if defined(V8_USE_EXTERNAL_STARTUP_DATA)
kV8NativesDataDescriptor,
kV8SnapshotDataDescriptor,
#endif
+#if defined(OS_ANDROID)
+ kAndroidPropertyDescriptor,
+ kAndroidICUDataDescriptor,
#endif
// The first key that embedders can use to register descriptors (see
diff --git a/chromium/content/public/common/content_switches.cc b/chromium/content/public/common/content_switches.cc
index 03c757801f1..bc896daf491 100644
--- a/chromium/content/public/common/content_switches.cc
+++ b/chromium/content/public/common/content_switches.cc
@@ -4,8 +4,6 @@
#include "content/public/common/content_switches.h"
-#include "base/command_line.h"
-
namespace switches {
// The number of MSAA samples for canvas2D. Requires MSAA support by GPU to
@@ -16,11 +14,6 @@ const char kAcceleratedCanvas2dMSAASampleCount[] = "canvas-msaa-sample-count";
// override for developers who need the old behavior for testing.
const char kAllowFileAccessFromFiles[] = "allow-file-access-from-files";
-// Allows frames with an https origin to use WebSockets with an insecure URL
-// (ws://).
-const char kAllowInsecureWebSocketFromHttpsOrigin[] =
- "allow-insecure-websocket-from-https-origin";
-
// Allows loopback interface to be added in network list for peer connection.
const char kAllowLoopbackInPeerConnection[] =
"allow-loopback-in-peer-connection";
@@ -36,26 +29,22 @@ const char kAllowNoSandboxJob[] = "allow-no-sandbox-job";
// Allows debugging of sandboxed processes (see zygote_main_linux.cc).
const char kAllowSandboxDebugging[] = "allow-sandbox-debugging";
-// The same as kAuditHandles except all handles are enumerated.
-const char kAuditAllHandles[] = "enable-handle-auditing-all";
-
-// Enumerates and prints a child process' most dangerous handles when it
-// is terminated.
-const char kAuditHandles[] = "enable-handle-auditing";
-
// Choose which logging channels in blink platform to activate. See
// Logging.cpp in blink's Source/platform for a list of available channels.
const char kBlinkPlatformLogChannels[] = "blink-platform-log-channels";
+// Set blink settings. Format is <name>[=<value],<name>[=<value>],...
+// The names are declared in Settings.in. For boolean type, use "true", "false",
+// or omit '=<value>' part to set to true. For enum type, use the int value of
+// the enum value. Applied after other command line flags and prefs.
+const char kBlinkSettings[] = "blink-settings";
+
// Block cross-site documents (i.e., HTML/XML/JSON) from being loaded in
// subresources when a document is not supposed to read them. This will later
// allow us to block them from the entire renderer process when site isolation
// is enabled.
const char kBlockCrossSiteDocuments[] = "block-cross-site-documents";
-// Causes the browser process to throw an assertion on startup.
-const char kBrowserAssertTest[] = "assert-test";
-
// Causes the browser process to crash on startup.
const char kBrowserCrashTest[] = "crash-test";
@@ -81,36 +70,30 @@ const char kDisable3DAPIs[] = "disable-3d-apis";
// Disable gpu-accelerated 2d canvas.
const char kDisableAccelerated2dCanvas[] = "disable-accelerated-2d-canvas";
-// Disables layer squashing.
-const char kDisableLayerSquashing[] =
- "disable-layer-squashing";
-
// Disables hardware acceleration of video decode, where available.
const char kDisableAcceleratedVideoDecode[] =
"disable-accelerated-video-decode";
-// Disable the ApplicationCache.
-const char kDisableApplicationCache[] = "disable-application-cache";
-
// Disable limits on the number of backing stores. Can prevent blinking for
// users with many windows/tabs and lots of memory.
const char kDisableBackingStoreLimit[] = "disable-backing-store-limit";
-// Disable the Blink Scheduler. Ensures there's no reordering of blink tasks.
-// This switch is intended only for performance tests.
-const char kDisableBlinkScheduler[] = "disable-blink-scheduler";
+// Disable one or more Blink runtime-enabled features.
+// Use names from RuntimeEnabledFeatures.in, separated by commas.
+// Applied after kEnableBlinkFeatures, and after other flags that change these
+// features.
+const char kDisableBlinkFeatures[] = "disable-blink-features";
// Disable the creation of compositing layers when it would prevent LCD text.
const char kDisablePreferCompositingToLCDText[] =
"disable-prefer-compositing-to-lcd-text";
-// See comment for kEnableCompositingForTransition.
-const char kDisableCompositingForTransition[] =
- "disable-transition-compositing";
-
// Disables HTML5 DB support.
const char kDisableDatabases[] = "disable-databases";
+// Disables Delay Agnostic AEC in WebRTC.
+const char kDisableDelayAgnosticAec[] = "disable-delay-agnostic-aec";
+
// Disables delegated renderer.
const char kDisableDelegatedRenderer[] = "disable-delegated-renderer";
@@ -141,6 +124,9 @@ const char kDisableGpu[] = "disable-gpu";
// Prevent the compositor from using its GPU implementation.
const char kDisableGpuCompositing[] = "disable-gpu-compositing";
+// Disable proactive early init of GPU process.
+const char kDisableGpuEarlyInit[] = "disable-gpu-early-init";
+
// Disable the limit on the number of times the GPU process may be restarted
// This switch is intended only for tests.
extern const char kDisableGpuProcessCrashLimit[] =
@@ -167,19 +153,20 @@ const char kDisableGpuWatchdog[] = "disable-gpu-watchdog";
// Manager can be used to terminate the offending process in this case.
const char kDisableHangMonitor[] = "disable-hang-monitor";
+// Disable hiding the close buttons of inactive tabs when the tabstrip is in
+// stacked mode.
+const char kDisableHideInactiveStackedTabCloseButtons[] =
+ "disable-hide-inactive-stacked-tab-close-buttons";
+
// Disable the RenderThread's HistogramCustomizer.
const char kDisableHistogramCustomizer[] = "disable-histogram-customizer";
// Paint content on the main thread instead of the compositor thread.
-// Overrides the kEnableImplSidePainting flag.
const char kDisableImplSidePainting[] = "disable-impl-side-painting";
// Prevent Java from running.
const char kDisableJava[] = "disable-java";
-// Don't execute JavaScript (browser JS like the new tab page still runs).
-const char kDisableJavaScript[] = "disable-javascript";
-
// Don't kill a child process when it sends a bad IPC message. Apart
// from testing, it is a bad idea from a security perspective to enable
// this switch.
@@ -205,6 +192,12 @@ const char kDisableLogging[] = "disable-logging";
// Disables Media Source API (i.e., the MediaSource object).
const char kDisableMediaSource[] = "disable-media-source";
+// Disables usage of the namespace sandbox.
+const char kDisableNamespaceSandbox[] = "disable-namespace-sandbox";
+
+// Disables the Web Notification and the Push APIs.
+const char kDisableNotifications[] = "disable-notifications";
+
// Disable rasterizer that writes directly to GPU memory.
// Overrides the kEnableOneCopy flag.
const char kDisableOneCopy[] = "disable-one-copy";
@@ -212,17 +205,20 @@ const char kDisableOneCopy[] = "disable-one-copy";
// Disable Pepper3D.
const char kDisablePepper3d[] = "disable-pepper-3d";
+// Disables the Permissions API.
+const char kDisablePermissionsAPI[] = "disable-permissions-api";
+
// Disables compositor-accelerated touch-screen pinch gestures.
const char kDisablePinch[] = "disable-pinch";
-// Prevent plugins from running.
-const char kDisablePlugins[] = "disable-plugins";
-
-// Disable discovering third-party plug-ins. Effectively loading only
+// Disable discovering third-party plugins. Effectively loading only
// ones shipped with the browser plus third-party ones as specified by
// --extra-plugin-dir and --load-plugin switches.
const char kDisablePluginsDiscovery[] = "disable-plugins-discovery";
+// Taints all <canvas> elements, regardless of origin.
+const char kDisableReadingFromCanvas[] = "disable-reading-from-canvas";
+
// Disables remote web font support. SVG font should always work whether this
// option is specified or not.
const char kDisableRemoteFonts[] = "disable-remote-fonts";
@@ -230,48 +226,45 @@ const char kDisableRemoteFonts[] = "disable-remote-fonts";
// Turns off the accessibility in the renderer.
const char kDisableRendererAccessibility[] = "disable-renderer-accessibility";
+// Prevent renderer process backgrounding when set.
+const char kDisableRendererBackgrounding[] = "disable-renderer-backgrounding";
+
// Disable the seccomp filter sandbox (seccomp-bpf) (Linux only).
const char kDisableSeccompFilterSandbox[] = "disable-seccomp-filter-sandbox";
-// Disable session storage.
-const char kDisableSessionStorage[] = "disable-session-storage";
-
// Disable the setuid sandbox (Linux only).
const char kDisableSetuidSandbox[] = "disable-setuid-sandbox";
// Disable shared workers.
const char kDisableSharedWorkers[] = "disable-shared-workers";
-// For tests, disable single thread scheduler and only manually composite.
-const char kDisableSingleThreadProxyScheduler[] =
- "disable-single-thread-proxy-scheduler";
-
// Disable smooth scrolling for testing.
const char kDisableSmoothScrolling[] = "disable-smooth-scrolling";
// Disables the use of a 3D software rasterizer.
const char kDisableSoftwareRasterizer[] = "disable-software-rasterizer";
+// Disables the Web Speech API.
+const char kDisableSpeechAPI[] = "disable-speech-api";
+
// Disables SVG 1.1 DOM.
const char kDisableSVG1DOM[] = "disable-svg1dom";
+// Disable text blob rendering.
+const char kDisableTextBlobs[] = "disable-text-blobs";
+
// Disable multithreaded GPU compositing of web content.
const char kDisableThreadedCompositing[] = "disable-threaded-compositing";
// Disable multithreaded, compositor scrolling of web content.
const char kDisableThreadedScrolling[] = "disable-threaded-scrolling";
-// Disable V8 idle notification after commit.
-// Overrides kEnableV8IdleNotificationAfterCommit.
-const char kDisableV8IdleNotificationAfterCommit[] =
- "disable-v8-idle-notification-after-commit";
+// Disable V8 idle tasks.
+const char kDisableV8IdleTasks[] = "disable-v8-idle-tasks";
// Don't enforce the same-origin policy. (Used by people testing their sites.)
const char kDisableWebSecurity[] = "disable-web-security";
-// Disables support for XSLT.
-const char kDisableXSLT[] = "disable-xslt";
-
// Disables Blink's XSSAuditor. The XSSAuditor mitigates reflective XSS.
const char kDisableXSSAuditor[] = "disable-xss-auditor";
@@ -284,11 +277,11 @@ const char kDomAutomationController[] = "dom-automation";
// Enable antialiasing on 2d canvas clips (as opposed to draw operations)
const char kEnable2dCanvasClipAntialiasing[] = "enable-2d-canvas-clip-aa";
-// Enable partially decoding jpeg images using the GPU.
-// At least YUV decoding will be accelerated when using this flag.
+// Disable partially decoding jpeg images using the GPU.
+// At least YUV decoding will be accelerated when not using this flag.
// Has no effect unless GPU rasterization is enabled.
-const char kEnableAcceleratedJpegDecoding[] =
- "enable-accelerated-jpeg-decoding";
+const char kDisableAcceleratedJpegDecoding[] =
+ "disable-accelerated-jpeg-decoding";
// Enable bleeding-edge code to make Chrome draw content faster. The changes
// behind this path are very likely to break lots of content.
@@ -296,6 +289,10 @@ const char kEnableAcceleratedJpegDecoding[] =
const char kEnableBleedingEdgeRenderingFastPaths[] =
"enable-bleeding-edge-rendering-fast-paths";
+// Enables new cc/animation system (Project Heaviside). crbug.com/394772
+const char kEnableCompositorAnimationTimelines[] =
+ "enable-compositor-animation-timelines";
+
// Enables LCD text.
const char kEnableLCDText[] = "enable-lcd-text";
@@ -303,14 +300,6 @@ const char kEnableLCDText[] = "enable-lcd-text";
// Only valid if GPU rasterization is enabled as well.
const char kEnableDistanceFieldText[] = "enable-distance-field-text";
-// Enables experimental feature that maps multiple RenderLayers to
-// one composited layer to avoid pathological layer counts.
-const char kEnableLayerSquashing[] =
- "enable-layer-squashing";
-
-// Enable experimental container node culling.
-const char kEnableContainerCulling[] = "enable-container-culling";
-
// Enable the experimental Credential Manager JavaScript API.
const char kEnableCredentialManagerAPI[] = "enable-credential-manager-api";
@@ -321,34 +310,37 @@ const char kEnableBeginFrameScheduling[] = "enable-begin-frame-scheduling";
const char kEnablePreferCompositingToLCDText[] =
"enable-prefer-compositing-to-lcd-text";
+// Disable one or more Blink runtime-enabled features.
+// Use names from RuntimeEnabledFeatures.in, separated by commas.
+// Applied before kDisableBlinkFeatures, and after other flags that change these
+// features.
+const char kEnableBlinkFeatures[] = "enable-blink-features";
+
// PlzNavigate: Use the experimental browser-side navigation path.
const char kEnableBrowserSideNavigation[] = "enable-browser-side-navigation";
-// Enable/Disable the creation of compositing layers for RenderLayers with a
-// transition on a property that supports accelerated animation (that is,
-// opacity, -webkit-transform, and -webkit-filter), even when no animation is
-// running. These options allow for three possible scenarios:
-// 1. Default (enabled only if we dectect a highDPI display)
-// 2. Enabled always.
-// 3. Disabled always.
-const char kEnableCompositingForTransition[] =
- "enable-transition-compositing";
-
// Defer image decoding in WebKit until painting.
const char kEnableDeferredImageDecoding[] = "enable-deferred-image-decoding";
+// Enables Delay Agnostic AEC in WebRTC.
+const char kEnableDelayAgnosticAec[] = "enable-delay-agnostic-aec";
+
// Enables delegated renderer.
const char kEnableDelegatedRenderer[] = "enable-delegated-renderer";
-// Enables display list based 2d canvas implementation.
+// Enables display list based 2d canvas implementation. Options:
+// 1. Enable: allow browser to use display list for 2d canvas (browser makes
+// decision).
+// 2. Force: browser always uses display list for 2d canvas.
const char kEnableDisplayList2dCanvas[] = "enable-display-list-2d-canvas";
-const char kDisableDisplayList2dCanvas[] = "disable-display-list-2d-canvas";
+const char kForceDisplayList2dCanvas[] = "force-display-list-2d-canvas";
+const char kDisableDisplayList2dCanvas[] = "disable-display-list-2d-canvas";
// Enables restarting interrupted downloads.
const char kEnableDownloadResumption[] = "enable-download-resumption";
-// Enables support for Encrypted Media Extensions (e.g. MediaKeys).
-const char kEnableEncryptedMedia[] = "enable-encrypted-media";
+// Disables (unprefixed) Encrypted Media Extensions.
+const char kDisableEncryptedMedia[] = "disable-encrypted-media";
// Enable experimental canvas features, e.g. canvas 2D context attributes
const char kEnableExperimentalCanvasFeatures[] =
@@ -358,10 +350,6 @@ const char kEnableExperimentalCanvasFeatures[] =
const char kEnableExperimentalWebPlatformFeatures[] =
"enable-experimental-web-platform-features";
-// By default, cookies are not allowed on file://. They are needed for testing,
-// for example page cycler and layout tests. See bug 1157243.
-const char kEnableFileCookies[] = "enable-file-cookies";
-
// Enables TRACE for GL calls in the renderer.
const char kEnableGpuClientTracing[] = "enable-gpu-client-tracing";
@@ -377,9 +365,6 @@ const char kEnableLowResTiling[] = "enable-low-res-tiling";
// Dynamically apply color profiles to web content images.
const char kEnableImageColorProfiles[] = "enable-image-color-profiles";
-// Paint content on the compositor thread instead of the main thread.
-const char kEnableImplSidePainting[] = "enable-impl-side-painting";
-
// Force logging to be enabled. Logging is disabled by default in release
// builds.
const char kEnableLogging[] = "enable-logging";
@@ -396,29 +381,37 @@ const char kEnableOneCopy[] = "enable-one-copy";
// Enables use of hardware overlay for fullscreen video playback. Android only.
const char kEnableOverlayFullscreenVideo[] = "enable-overlay-fullscreen-video";
-// Forward overscroll event data from the renderer to the browser.
-const char kEnableOverscrollNotifications[] = "enable-overscroll-notifications";
-
// Enables compositor-accelerated touch-screen pinch gestures.
const char kEnablePinch[] = "enable-pinch";
+// Enables testing features of the Plugin Placeholder. For internal use only.
+const char kEnablePluginPlaceholderTesting[] =
+ "enable-plugin-placeholder-testing";
+
// Make the values returned to window.performance.memory more granular and more
// up to date in shared worker. Without this flag, the memory information is
// still available, but it is bucketized and updated less frequently. This flag
// also applys to workers.
const char kEnablePreciseMemoryInfo[] = "enable-precise-memory-info";
+// Enables payloads for received push messages when using the W3C Push API.
+const char kEnablePushMessagePayload[] = "enable-push-message-payload";
+
// Set options to cache V8 data. (off, preparse data, or code)
const char kV8CacheOptions[] = "v8-cache-options";
+// Signals that the V8 natives file has been transfered to the child process
+// by a file descriptor.
+const char kV8NativesPassedByFD[] = "v8-natives-passed-by-fd";
+
+// Signals that the V8 startup snapshot file has been transfered to the child
+// process by a file descriptor.
+const char kV8SnapshotPassedByFD[] = "v8-snapshot-passed-by-fd";
+
// Enables the CSS multicol implementation that uses the regions implementation.
const char kEnableRegionBasedColumns[] =
"enable-region-based-columns";
-// Replaces renderer-browser IPC channel with ChnanelMojo.
-const char kEnableRendererMojoChannel[] =
- "enable-renderer-mojo-channel";
-
// Cause the OS X sandbox write to syslog every time an access to a resource
// is denied by the sandbox.
const char kEnableSandboxLogging[] = "enable-sandbox-logging";
@@ -440,6 +433,11 @@ const char kEnableSmoothScrolling[] = "enable-smooth-scrolling";
// Enable spatial navigation
const char kEnableSpatialNavigation[] = "enable-spatial-navigation";
+// Enables implementation of the Cache-Control: stale-while-revalidate directive
+// which permits servers to allow the use of stale resources while revalidation
+// proceeds in the background.
+const char kEnableStaleWhileRevalidate[] = "enable-stale-while-revalidate";
+
// Enables StatsTable, logging statistics to a global named shared memory table.
const char kEnableStatsTable[] = "enable-stats-table";
@@ -455,6 +453,16 @@ const char kEnableStatsTable[] = "enable-stats-table";
// cookies on cross-site requests.
const char kEnableStrictSiteIsolation[] = "enable-strict-site-isolation";
+// Blocks all insecure requests from secure contexts, and prevents the user
+// from overriding that decision.
+const char kEnableStrictMixedContentChecking[] =
+ "enable-strict-mixed-content-checking";
+
+// Blocks insecure usage of number of powerful features (geolocation, for
+// example) that we haven't yet deprecated for the web at large.
+const char kEnableStrictPowerfulFeatureRestrictions[] =
+ "enable-strict-powerful-feature-restrictions";
+
// Enable support for sync events in ServiceWorkers.
const char kEnableServiceWorkerSync[] = "enable-service-worker-sync";
@@ -462,9 +470,6 @@ const char kEnableServiceWorkerSync[] = "enable-service-worker-sync";
// SYN packet.
const char kEnableTcpFastOpen[] = "enable-tcp-fastopen";
-// Enable experimental text blob rendering.
-const char kEnableTextBlobs[] = "enable-text-blobs";
-
// Enabled threaded compositing for layout tests.
const char kEnableThreadedCompositing[] = "enable-threaded-compositing";
@@ -478,24 +483,13 @@ const char kEnableTracingOutput[] = "enable-tracing-output";
const char kEnableUserMediaScreenCapturing[] =
"enable-usermedia-screen-capturing";
-// Enables streaming scripts to V8 while loading.
-const char kEnableV8ScriptStreaming[] = "enable-v8-script-streaming";
-
-// Send a notification from RenderWidgetCompositor to V8 to do idle work
-// (e.g. garbage collection) after the commit until the beginning of the next
-// frame. This moves the work off the critical path where compositor is waiting
-// for the main thread. The flag is experimental until the implementation of the
-// V8 idle handler is completed.
-const char kEnableV8IdleNotificationAfterCommit[] =
- "enable-v8-idle-notification-after-commit";
-
// Enables the use of the @viewport CSS rule, which allows
// pages to control aspects of their own layout. This also turns on touch-screen
// pinch gestures.
const char kEnableViewport[] = "enable-viewport";
-// Enables the use of the legacy viewport meta tag. Turning this on also
-// turns on the @viewport CSS rule
+// Enables the viewport meta tag, the de facto way to control layout which works
+// only on mobile browsers.
const char kEnableViewportMeta[] = "enable-viewport-meta";
// Resizes of the main frame are the caused by changing between landscape
@@ -512,12 +506,13 @@ const char kEnableWebGLDraftExtensions[] = "enable-webgl-draft-extensions";
// Enables WebGL rendering into a scanout buffer for overlay support.
const char kEnableWebGLImageChromium[] = "enable-webgl-image-chromium";
-// Enables Web MIDI API.
-const char kEnableWebMIDI[] = "enable-web-midi";
-
// Enable rasterizer that writes directly to GPU memory associated with tiles.
const char kEnableZeroCopy[] = "enable-zero-copy";
+// Explicitly allows additional ports using a comma-separated list of port
+// numbers.
+const char kExplicitlyAllowedPorts[] = "explicitly-allowed-ports";
+
// Load NPAPI plugins from the specified directory.
const char kExtraPluginDir[] = "extra-plugin-dir";
@@ -536,11 +531,21 @@ const char kForceFieldTrials[] = "force-fieldtrials";
// kEnableGpuRasterization flag.
const char kForceGpuRasterization[] = "force-gpu-rasterization";
+// The number of multisample antialiasing samples for GPU rasterization.
+// Requires MSAA support on GPU to have an effect. 0 disables MSAA.
+const char kGpuRasterizationMSAASampleCount[] =
+ "gpu-rasterization-msaa-sample-count";
+
// Force renderer accessibility to be on instead of enabling it on demand when
// a screen reader is detected. The disable-renderer-accessibility switch
// overrides this if present.
const char kForceRendererAccessibility[] = "force-renderer-accessibility";
+// Always use text blob rendering, overriding kDisableTextBlobs and any
+// heuristics that may otherwise disable it.
+// TODO(fmalita): remove after --disable-impl-side-painting is phased out.
+const char kForceTextBlobs[] = "force-text-blobs";
+
// Passes gpu device_id from browser process to GPU process.
const char kGpuDeviceID[] = "gpu-device-id";
@@ -625,9 +630,20 @@ const char kNoReferrers[] = "no-referrers";
// Disables the sandbox for all process types that are normally sandboxed.
const char kNoSandbox[] = "no-sandbox";
+// Disables appcontainer/lowbox for renderer on Win8+ platforms.
+const char kDisableAppContainer[] = "disable-appcontainer";
+
// Number of worker threads used to rasterize content.
const char kNumRasterThreads[] = "num-raster-threads";
+// Override the behavior of plugin throttling for testing.
+// By default the throttler is only enabled for a hard-coded list of plugins.
+// Set the value to 'never' to disable throttling.
+// Set the value to 'ignore-list' to ignore the hard-coded list.
+// Set the value to 'always' to always throttle every plugin instance.
+const char kOverridePluginPowerSaverForTesting[] =
+ "override-plugin-power-saver-for-testing";
+
// Controls the behavior of history navigation in response to horizontal
// overscroll.
// Set the value to '0' to disable.
@@ -700,11 +716,8 @@ const char kRegisterPepperPlugins[] = "register-pepper-plugins";
// Enables remote debug over HTTP on the specified port.
const char kRemoteDebuggingPort[] = "remote-debugging-port";
-// Causes the renderer process to throw an assertion on launch.
-const char kRendererAssertTest[] = "renderer-assert-test";
-
-// On POSIX only: the contents of this flag are prepended to the renderer
-// command line. Useful values might be "valgrind" or "xterm -e gdb --args".
+// The contents of this flag are prepended to the renderer command line.
+// Useful values might be "valgrind" or "xterm -e gdb --args".
const char kRendererCmdPrefix[] = "renderer-cmd-prefix";
// Causes the process to run as renderer instead of as browser.
@@ -718,6 +731,10 @@ const char kRendererProcessLimit[] = "renderer-process-limit";
// Causes the renderer process to display a dialog on launch.
const char kRendererStartupDialog[] = "renderer-startup-dialog";
+// Reduce the default `referer` header's granularity.
+const char kReducedReferrerGranularity[] =
+ "reduced-referrer-granularity";
+
// Handles frame scrolls via the root RenderLayer instead of the FrameView.
const char kRootLayerScrolls[] = "root-layer-scrolls";
@@ -780,10 +797,10 @@ const char kTestingFixedHttpsPort[] = "testing-fixed-https-port";
// Type of the current test harness ("browser" or "ui").
const char kTestType[] = "test-type";
-const char kTouchScrollingMode[] = "touch-scrolling-mode";
-const char kTouchScrollingModeAsyncTouchmove[] = "async-touchmove";
-const char kTouchScrollingModeSyncTouchmove[] = "sync-touchmove";
-const char kTouchScrollingModeTouchcancel[] = "touchcancel";
+// Controls how text selection granularity changes when touch text selection
+// handles are dragged. Should be "character" or "direction". If not specified,
+// the platform default is used.
+const char kTouchTextSelectionStrategy[] = "touch-selection-strategy";
// Causes TRACE_EVENT flags to be recorded beginning with shutdown. Optionally,
// can specify the specific trace categories to include (e.g.
@@ -829,22 +846,32 @@ const char kTraceUploadURL[] = "trace-upload-url";
extern const char kUIPrioritizeInGpuProcess[] =
"ui-prioritize-in-gpu-process";
-// Overrides the preferred discardable memory implementation.
-const char kUseDiscardableMemory[] = "use-discardable-memory";
-
// Bypass the media stream infobar by selecting the default device for media
// streams (e.g. WebRTC). Works with --use-fake-device-for-media-stream.
const char kUseFakeUIForMediaStream[] = "use-fake-ui-for-media-stream";
+// Enable native GPU memory buffer support when available.
+const char kEnableNativeGpuMemoryBuffers[] = "enable-native-gpu-memory-buffers";
+
+// Overrides the default texture target used with CHROMIUM_image extension.
+const char kUseImageTextureTarget[] = "use-image-texture-target";
+
// Set when Chromium should use a mobile user agent.
const char kUseMobileUserAgent[] = "use-mobile-user-agent";
+// Use normal priority for tile task worker threads. Otherwise they may
+// be run at background priority on some platforms.
+const char kUseNormalPriorityForTileTaskWorkerThreads[] =
+ "use-normal-priority-for-tile-task-worker-threads";
+
// Use the new surfaces system to handle compositor delegation.
const char kUseSurfaces[] = "use-surfaces";
-// On POSIX only: the contents of this flag are prepended to the utility
-// process command line. Useful values might be "valgrind" or "xterm -e gdb
-// --args".
+// Disable the use of the new surfaces system to handle compositor delegation.
+const char kDisableSurfaces[] = "disable-surfaces";
+
+// The contents of this flag are prepended to the utility process command line.
+// Useful values might be "valgrind" or "xterm -e gdb --args".
const char kUtilityCmdPrefix[] = "utility-cmd-prefix";
// Causes the process to run as a utility subprocess.
@@ -874,10 +901,6 @@ const char kZygoteCmdPrefix[] = "zygote-cmd-prefix";
const char kZygoteProcess[] = "zygote";
#if defined(ENABLE_WEBRTC)
-// Disables audio processing in a MediaStreamTrack. When this flag is on, AEC,
-// NS and AGC will be done in PeerConnection instead of MediaStreamTrack.
-const char kDisableAudioTrackProcessing[] = "disable-audio-track-processing";
-
// Disables HW decode acceleration for WebRTC.
const char kDisableWebRtcHWDecoding[] = "disable-webrtc-hw-decoding";
@@ -888,11 +911,15 @@ const char kDisableWebRtcEncryption[] = "disable-webrtc-encryption";
// Disables HW encode acceleration for WebRTC.
const char kDisableWebRtcHWEncoding[] = "disable-webrtc-hw-encoding";
-// Enables VP8 HW encode acceleration for WebRTC.
-const char kEnableWebRtcHWVp8Encoding[] = "enable-webrtc-hw-vp8-encoding";
-
// Enables H264 HW encode acceleration for WebRTC.
const char kEnableWebRtcHWH264Encoding[] = "enable-webrtc-hw-h264-encoding";
+
+// Enables Origin header in Stun messages for WebRTC.
+const char kEnableWebRtcStunOrigin[] = "enable-webrtc-stun-origin";
+
+// Override the maximum framerate as can be specified in calls to getUserMedia.
+// This flag expects a value. Example: --max-gum-fps=17.5
+const char kWebRtcMaxCaptureFramerate[] = "max-gum-fps";
#endif
#if defined(OS_ANDROID)
@@ -906,15 +933,14 @@ const char kDisableClickDelay[] = "disable-click-delay";
// Disable overscroll edge effects like those found in Android views.
const char kDisableOverscrollEdgeEffect[] = "disable-overscroll-edge-effect";
-// WebRTC is enabled by default on Android.
-const char kDisableWebRTC[] = "disable-webrtc";
+// Disable the pull-to-refresh effect when vertically overscrolling content.
+const char kDisablePullToRefreshEffect[] = "disable-pull-to-refresh-effect";
-// Enable the recognition part of the Web Speech API.
-const char kEnableSpeechRecognition[] = "enable-speech-recognition";
+// Disable the locking feature of the screen orientation API.
+const char kDisableScreenOrientationLock[] = "disable-screen-orientation-lock";
-// Always use the video overlay for the embedded video.
-// This switch is intended only for tests.
-const char kForceUseOverlayEmbeddedVideo[] = "force-use-overlay-embedded-video";
+// WebRTC is enabled by default on Android.
+const char kDisableWebRTC[] = "disable-webrtc";
// The telephony region (ISO country code) to use in phone number detection.
const char kNetworkCountryIso[] = "network-country-iso";
@@ -927,6 +953,10 @@ const char kRemoteDebuggingSocketName[] = "remote-debugging-socket-name";
const char kRendererWaitForJavaDebugger[] = "renderer-wait-for-java-debugger";
#endif
+// Enable the aggressive flushing of DOM Storage to minimize data loss.
+const char kEnableAggressiveDOMStorageFlushing[] =
+ "enable-aggressive-domstorage-flushing";
+
// Disable web audio API.
const char kDisableWebAudio[] = "disable-webaudio";
@@ -934,7 +964,7 @@ const char kDisableWebAudio[] = "disable-webaudio";
// Disables panel fitting (used for mirror mode).
const char kDisablePanelFitting[] = "disable-panel-fitting";
-// Enables VA-API accelerated video encode.
+// Disables VA-API accelerated video encode.
const char kDisableVaapiAcceleratedVideoEncode[] =
"disable-vaapi-accelerated-video-encode";
#endif
@@ -951,11 +981,6 @@ const char kEnableSpeechDispatcher[] = "enable-speech-dispatcher";
// accelerated compositing is disabled. See http://crbug.com/122430.
const char kDisableCoreAnimationPlugins[] =
"disable-core-animation-plugins";
-
-// Allows input events to be handed on the compositor thread.
-// This feature is under development, see http://crbug.com/138003.
-extern const char kEnableThreadedEventHandlingMac[] =
- "enable-threaded-event-handling-mac";
#endif
#if defined(OS_WIN)
@@ -965,18 +990,28 @@ const char kDeviceScaleFactor[] = "device-scale-factor";
// Disable the Legacy Window which corresponds to the size of the WebContents.
const char kDisableLegacyIntermediateWindow[] = "disable-legacy-window";
-// Enable the Win32K process mitigation policy for renderer processes which
-// prevents them from invoking user32 and gdi32 system calls which enter
-// the kernel. This is only supported on Windows 8 and beyond.
-const char kEnableWin32kRendererLockDown[]
- = "enable_win32k_renderer_lockdown";
-#endif
+// Disables the Win32K process mitigation policy for renderer processes.
+const char kDisableWin32kRendererLockDown[] =
+ "disable-win32k-renderer-lockdown";
+
+// DirectWrite FontCache is shared by browser to renderers using shared memory.
+// This switch allows us to pass the shared memory handle to the renderer.
+const char kFontCacheSharedHandle[] = "font-cache-shared-handle";
-#if defined(ENABLE_PLUGINS)
-// Enables the plugin power saver feature.
-const char kEnablePluginPowerSaver[] = "enable-plugin-power-saver";
+// Sets the free memory thresholds below which the system is considered to be
+// under moderate and critical memory pressure. Used in the browser process,
+// and ignored if invalid. Specified as a pair of comma separated integers.
+// See base/win/memory_pressure_monitor.cc for defaults.
+const char kMemoryPressureThresholdsMb[] = "memory-pressure-thresholds-mb";
+
+// Enables the exporting of the tracing events to ETW. This is only supported on
+// Windows Vista and later.
+const char kTraceExportEventsToETW[] = "trace-export-events-to-etw";
#endif
+// Enables the use of NPAPI plugins.
+const char kEnableNpapi[] = "enable-npapi";
+
// Don't dump stuff here, follow the same order as the header.
} // namespace switches
diff --git a/chromium/content/public/common/content_switches.h b/chromium/content/public/common/content_switches.h
index 360aded3172..c27bee842a0 100644
--- a/chromium/content/public/common/content_switches.h
+++ b/chromium/content/public/common/content_switches.h
@@ -16,15 +16,12 @@ namespace switches {
// alongside the definition of their values in the .cc file.
CONTENT_EXPORT extern const char kAcceleratedCanvas2dMSAASampleCount[];
CONTENT_EXPORT extern const char kAllowFileAccessFromFiles[];
-CONTENT_EXPORT extern const char kAllowInsecureWebSocketFromHttpsOrigin[];
CONTENT_EXPORT extern const char kAllowLoopbackInPeerConnection[];
CONTENT_EXPORT extern const char kAllowNoSandboxJob[];
-extern const char kAllowSandboxDebugging[];
-extern const char kAuditAllHandles[];
-extern const char kAuditHandles[];
+CONTENT_EXPORT extern const char kAllowSandboxDebugging[];
+CONTENT_EXPORT extern const char kBlinkSettings[];
CONTENT_EXPORT extern const char kBlinkPlatformLogChannels[];
CONTENT_EXPORT extern const char kBlockCrossSiteDocuments[];
-CONTENT_EXPORT extern const char kBrowserAssertTest[];
CONTENT_EXPORT extern const char kBrowserCrashTest[];
CONTENT_EXPORT extern const char kBrowserSubprocessPath[];
extern const char kDebugPluginLoading[];
@@ -32,128 +29,132 @@ CONTENT_EXPORT extern const char kDefaultTileWidth[];
CONTENT_EXPORT extern const char kDefaultTileHeight[];
CONTENT_EXPORT extern const char kDisable2dCanvasAntialiasing[];
CONTENT_EXPORT extern const char kDisable3DAPIs[];
+CONTENT_EXPORT extern const char kDisableBlinkFeatures[];
CONTENT_EXPORT extern const char kDisableAccelerated2dCanvas[];
-CONTENT_EXPORT extern const char kDisableLayerSquashing[];
+CONTENT_EXPORT extern const char kDisableAcceleratedJpegDecoding[];
CONTENT_EXPORT extern const char kDisableAcceleratedVideoDecode[];
-CONTENT_EXPORT extern const char kDisableApplicationCache[];
extern const char kDisableBackingStoreLimit[];
-CONTENT_EXPORT extern const char kDisableBlinkScheduler[];
CONTENT_EXPORT extern const char kDisablePreferCompositingToLCDText[];
-CONTENT_EXPORT extern const char kDisableCompositingForTransition[];
CONTENT_EXPORT extern const char kDisableDatabases[];
+CONTENT_EXPORT extern const char kDisableDelayAgnosticAec[];
CONTENT_EXPORT extern const char kDisableDelegatedRenderer[];
extern const char kDisableDirectNPAPIRequests[];
CONTENT_EXPORT extern const char kDisableDistanceFieldText[];
CONTENT_EXPORT extern const char kDisableDisplayList2dCanvas[];
extern const char kDisableDomainBlockingFor3DAPIs[];
+CONTENT_EXPORT extern const char kDisableEncryptedMedia[];
CONTENT_EXPORT extern const char kDisableExperimentalWebGL[];
CONTENT_EXPORT extern const char kDisableFileSystem[];
CONTENT_EXPORT extern const char kDisableFlash3d[];
CONTENT_EXPORT extern const char kDisableFlashStage3d[];
CONTENT_EXPORT extern const char kDisableGpu[];
CONTENT_EXPORT extern const char kDisableGpuCompositing[];
+CONTENT_EXPORT extern const char kDisableGpuEarlyInit[];
extern const char kDisableGpuProcessCrashLimit[];
CONTENT_EXPORT extern const char kDisableGpuRasterization[];
CONTENT_EXPORT extern const char kDisableGpuSandbox[];
CONTENT_EXPORT extern const char kDisableGpuWatchdog[];
CONTENT_EXPORT extern const char kDisableLowResTiling[];
CONTENT_EXPORT extern const char kDisableHangMonitor[];
+CONTENT_EXPORT extern const char kDisableHideInactiveStackedTabCloseButtons[];
extern const char kDisableHistogramCustomizer[];
CONTENT_EXPORT extern const char kDisableImplSidePainting[];
CONTENT_EXPORT extern const char kDisableJava[];
-CONTENT_EXPORT extern const char kDisableJavaScript[];
CONTENT_EXPORT extern const char kDisableLCDText[];
CONTENT_EXPORT extern const char kDisablePrefixedEncryptedMedia[];
extern const char kDisableKillAfterBadIPC[];
CONTENT_EXPORT extern const char kDisableLocalStorage[];
CONTENT_EXPORT extern const char kDisableLogging[];
CONTENT_EXPORT extern const char kDisableMediaSource[];
+CONTENT_EXPORT extern const char kDisableNamespaceSandbox[];
+CONTENT_EXPORT extern const char kDisableNotifications[];
CONTENT_EXPORT extern const char kDisableOneCopy[];
extern const char kDisablePepper3d[];
CONTENT_EXPORT extern const char kDisablePinch[];
-CONTENT_EXPORT extern const char kDisablePlugins[];
+CONTENT_EXPORT extern const char kDisablePermissionsAPI[];
CONTENT_EXPORT extern const char kDisablePluginsDiscovery[];
+CONTENT_EXPORT extern const char kDisableReadingFromCanvas[];
extern const char kDisableRemoteFonts[];
extern const char kDisableRendererAccessibility[];
+CONTENT_EXPORT extern const char kDisableRendererBackgrounding[];
CONTENT_EXPORT extern const char kDisableSeccompFilterSandbox[];
-extern const char kDisableSessionStorage[];
CONTENT_EXPORT extern const char kDisableSetuidSandbox[];
CONTENT_EXPORT extern const char kDisableSharedWorkers[];
-CONTENT_EXPORT extern const char kDisableSingleThreadProxyScheduler[];
CONTENT_EXPORT extern const char kDisableSmoothScrolling[];
CONTENT_EXPORT extern const char kDisableSoftwareRasterizer[];
+CONTENT_EXPORT extern const char kDisableSpeechAPI[];
CONTENT_EXPORT extern const char kDisableSVG1DOM[];
+CONTENT_EXPORT extern const char kDisableTextBlobs[];
CONTENT_EXPORT extern const char kDisableThreadedCompositing[];
CONTENT_EXPORT extern const char kDisableThreadedScrolling[];
-extern const char kDisableV8IdleNotificationAfterCommit[];
+extern const char kDisableV8IdleTasks[];
CONTENT_EXPORT extern const char kDisableWebSecurity[];
-extern const char kDisableXSLT[];
extern const char kDisableXSSAuditor[];
CONTENT_EXPORT extern const char kDomAutomationController[];
extern const char kEnable2dCanvasClipAntialiasing[];
-CONTENT_EXPORT extern const char kEnableAcceleratedJpegDecoding[];
+CONTENT_EXPORT extern const char kEnableAggressiveDOMStorageFlushing[];
CONTENT_EXPORT extern const char kEnableBleedingEdgeRenderingFastPaths[];
-CONTENT_EXPORT extern const char kEnableLayerSquashing[];
-CONTENT_EXPORT extern const char kEnableContainerCulling[];
+CONTENT_EXPORT extern const char kEnableCompositorAnimationTimelines[];
CONTENT_EXPORT extern const char kEnableCredentialManagerAPI[];
CONTENT_EXPORT extern const char kEnableBeginFrameScheduling[];
CONTENT_EXPORT extern const char kEnablePreferCompositingToLCDText[];
+CONTENT_EXPORT extern const char kEnableBlinkFeatures[];
CONTENT_EXPORT extern const char kEnableBrowserSideNavigation[];
-CONTENT_EXPORT extern const char kEnableCompositingForTransition[];
CONTENT_EXPORT extern const char kEnableDeferredImageDecoding[];
+CONTENT_EXPORT extern const char kEnableDelayAgnosticAec[];
CONTENT_EXPORT extern const char kEnableDelegatedRenderer[];
CONTENT_EXPORT extern const char kEnableDisplayList2dCanvas[];
CONTENT_EXPORT extern const char kEnableDistanceFieldText[];
CONTENT_EXPORT extern const char kEnableDownloadResumption[];
-CONTENT_EXPORT extern const char kEnableEncryptedMedia[];
CONTENT_EXPORT extern const char kEnableExperimentalCanvasFeatures[];
CONTENT_EXPORT extern const char kEnableExperimentalWebPlatformFeatures[];
-CONTENT_EXPORT extern const char kEnableFileCookies[];
extern const char kEnableGpuClientTracing[];
CONTENT_EXPORT extern const char kEnableGpuRasterization[];
+CONTENT_EXPORT extern const char kGpuRasterizationMSAASampleCount[];
CONTENT_EXPORT extern const char kEnableLowResTiling[];
CONTENT_EXPORT extern const char kEnableImageColorProfiles[];
-CONTENT_EXPORT extern const char kEnableImplSidePainting[];
CONTENT_EXPORT extern const char kEnableLCDText[];
CONTENT_EXPORT extern const char kEnableLogging[];
extern const char kEnableMemoryBenchmarking[];
CONTENT_EXPORT extern const char kEnableNetworkInformation[];
CONTENT_EXPORT extern const char kEnableOneCopy[];
CONTENT_EXPORT extern const char kEnableOverlayFullscreenVideo[];
-CONTENT_EXPORT extern const char kEnableOverscrollNotifications[];
CONTENT_EXPORT extern const char kEnablePinch[];
+CONTENT_EXPORT extern const char kEnablePluginPlaceholderTesting[];
CONTENT_EXPORT extern const char kEnablePreciseMemoryInfo[];
+CONTENT_EXPORT extern const char kEnablePushMessagePayload[];
CONTENT_EXPORT extern const char kEnableRegionBasedColumns[];
-CONTENT_EXPORT extern const char kEnableRendererMojoChannel[];
CONTENT_EXPORT extern const char kEnableSandboxLogging[];
-extern const char kEnableSeccompFilterSandbox[];
+CONTENT_EXPORT extern const char kEnableSeccompFilterSandbox[];
extern const char kEnableSkiaBenchmarking[];
-extern const char kEnableSlimmingPaint[];
+CONTENT_EXPORT extern const char kEnableSlimmingPaint[];
CONTENT_EXPORT extern const char kEnableSmoothScrolling[];
CONTENT_EXPORT extern const char kEnableSpatialNavigation[];
+CONTENT_EXPORT extern const char kEnableStaleWhileRevalidate[];
CONTENT_EXPORT extern const char kEnableStatsTable[];
+CONTENT_EXPORT extern const char kEnableStrictMixedContentChecking[];
+CONTENT_EXPORT extern const char kEnableStrictPowerfulFeatureRestrictions[];
CONTENT_EXPORT extern const char kEnableStrictSiteIsolation[];
CONTENT_EXPORT extern const char kEnableServiceWorkerSync[];
CONTENT_EXPORT extern const char kEnableTcpFastOpen[];
-CONTENT_EXPORT extern const char kEnableTextBlobs[];
CONTENT_EXPORT extern const char kEnableThreadedCompositing[];
CONTENT_EXPORT extern const char kEnableTracing[];
CONTENT_EXPORT extern const char kEnableTracingOutput[];
CONTENT_EXPORT extern const char kEnableUserMediaScreenCapturing[];
-extern const char kEnableV8ScriptStreaming[];
-extern const char kEnableV8IdleNotificationAfterCommit[];
CONTENT_EXPORT extern const char kEnableViewport[];
CONTENT_EXPORT extern const char kEnableViewportMeta[];
CONTENT_EXPORT extern const char kMainFrameResizesAreOrientationChanges[];
CONTENT_EXPORT extern const char kEnableVtune[];
CONTENT_EXPORT extern const char kEnableWebGLDraftExtensions[];
CONTENT_EXPORT extern const char kEnableWebGLImageChromium[];
-CONTENT_EXPORT extern const char kEnableWebMIDI[];
CONTENT_EXPORT extern const char kEnableZeroCopy[];
+CONTENT_EXPORT extern const char kExplicitlyAllowedPorts[];
CONTENT_EXPORT extern const char kExtraPluginDir[];
+CONTENT_EXPORT extern const char kForceDisplayList2dCanvas[];
CONTENT_EXPORT extern const char kForceFieldTrials[];
CONTENT_EXPORT extern const char kForceGpuRasterization[];
CONTENT_EXPORT extern const char kForceRendererAccessibility[];
+CONTENT_EXPORT extern const char kForceTextBlobs[];
extern const char kGpuDeviceID[];
extern const char kGpuDriverVendor[];
extern const char kGpuDriverVersion[];
@@ -181,7 +182,9 @@ extern const char kMemoryMetrics[];
CONTENT_EXPORT extern const char kMuteAudio[];
CONTENT_EXPORT extern const char kNoReferrers[];
CONTENT_EXPORT extern const char kNoSandbox[];
+CONTENT_EXPORT extern const char kDisableAppContainer[];
CONTENT_EXPORT extern const char kNumRasterThreads[];
+CONTENT_EXPORT extern const char kOverridePluginPowerSaverForTesting[];
CONTENT_EXPORT extern const char kOverscrollHistoryNavigation[];
extern const char kPluginLauncher[];
CONTENT_EXPORT extern const char kPluginPath[];
@@ -197,9 +200,9 @@ CONTENT_EXPORT extern const char kProcessPerSite[];
CONTENT_EXPORT extern const char kProcessPerTab[];
CONTENT_EXPORT extern const char kProcessType[];
CONTENT_EXPORT extern const char kReduceSecurityForTesting[];
+CONTENT_EXPORT extern const char kReducedReferrerGranularity[];
CONTENT_EXPORT extern const char kRegisterPepperPlugins[];
CONTENT_EXPORT extern const char kRemoteDebuggingPort[];
-CONTENT_EXPORT extern const char kRendererAssertTest[];
extern const char kRendererCmdPrefix[];
CONTENT_EXPORT extern const char kRendererProcess[];
CONTENT_EXPORT extern const char kRendererProcessLimit[];
@@ -218,48 +221,50 @@ CONTENT_EXPORT extern const char kTabCaptureUpscaleQuality[];
CONTENT_EXPORT extern const char kTestingFixedHttpPort[];
CONTENT_EXPORT extern const char kTestingFixedHttpsPort[];
CONTENT_EXPORT extern const char kTestType[];
-CONTENT_EXPORT extern const char kTouchScrollingMode[];
-CONTENT_EXPORT extern const char kTouchScrollingModeAsyncTouchmove[];
-CONTENT_EXPORT extern const char kTouchScrollingModeSyncTouchmove[];
-CONTENT_EXPORT extern const char kTouchScrollingModeTouchcancel[];
+CONTENT_EXPORT extern const char kTouchTextSelectionStrategy[];
CONTENT_EXPORT extern const char kTraceShutdown[];
extern const char kTraceShutdownFile[];
extern const char kTraceStartup[];
extern const char kTraceStartupDuration[];
extern const char kTraceStartupFile[];
-extern const char kTraceUploadURL[];
+CONTENT_EXPORT extern const char kTraceUploadURL[];
CONTENT_EXPORT extern const char kUIPrioritizeInGpuProcess[];
-CONTENT_EXPORT extern const char kUseDiscardableMemory[];
CONTENT_EXPORT extern const char kUseFakeUIForMediaStream[];
+CONTENT_EXPORT extern const char kEnableNativeGpuMemoryBuffers[];
+CONTENT_EXPORT extern const char kUseImageTextureTarget[];
CONTENT_EXPORT extern const char kUseMobileUserAgent[];
+CONTENT_EXPORT extern const char kUseNormalPriorityForTileTaskWorkerThreads[];
extern const char kUseSurfaces[];
+CONTENT_EXPORT extern const char kDisableSurfaces[];
extern const char kUtilityCmdPrefix[];
CONTENT_EXPORT extern const char kUtilityProcess[];
extern const char kUtilityProcessAllowedDir[];
CONTENT_EXPORT extern const char kUtilityProcessEnableMDns[];
CONTENT_EXPORT extern const char kUtilityProcessRunningElevated[];
-extern const char kV8CacheOptions[];
+CONTENT_EXPORT extern const char kV8CacheOptions[];
+CONTENT_EXPORT extern const char kV8NativesPassedByFD[];
+CONTENT_EXPORT extern const char kV8SnapshotPassedByFD[];
CONTENT_EXPORT extern const char kValidateInputEventStream[];
CONTENT_EXPORT extern const char kWaitForDebuggerChildren[];
CONTENT_EXPORT extern const char kZygoteCmdPrefix[];
CONTENT_EXPORT extern const char kZygoteProcess[];
#if defined(ENABLE_WEBRTC)
-CONTENT_EXPORT extern const char kDisableAudioTrackProcessing[];
CONTENT_EXPORT extern const char kDisableWebRtcHWDecoding[];
CONTENT_EXPORT extern const char kDisableWebRtcEncryption[];
CONTENT_EXPORT extern const char kDisableWebRtcHWEncoding[];
-CONTENT_EXPORT extern const char kEnableWebRtcHWVp8Encoding[];
CONTENT_EXPORT extern const char kEnableWebRtcHWH264Encoding[];
+CONTENT_EXPORT extern const char kEnableWebRtcStunOrigin[];
+extern const char kWebRtcMaxCaptureFramerate[];
#endif
#if defined(OS_ANDROID)
CONTENT_EXPORT extern const char kDisableGestureRequirementForMediaPlayback[];
CONTENT_EXPORT extern const char kDisableClickDelay[];
CONTENT_EXPORT extern const char kDisableOverscrollEdgeEffect[];
+CONTENT_EXPORT extern const char kDisablePullToRefreshEffect[];
+CONTENT_EXPORT extern const char kDisableScreenOrientationLock[];
CONTENT_EXPORT extern const char kDisableWebRTC[];
-CONTENT_EXPORT extern const char kEnableSpeechRecognition[];
-CONTENT_EXPORT extern const char kForceUseOverlayEmbeddedVideo[];
CONTENT_EXPORT extern const char kHideScrollbars[];
extern const char kNetworkCountryIso[];
CONTENT_EXPORT extern const char kRemoteDebuggingSocketName[];
@@ -279,7 +284,7 @@ CONTENT_EXPORT extern const char kEnableSpeechDispatcher[];
#if defined(OS_MACOSX) && !defined(OS_IOS)
extern const char kDisableCoreAnimationPlugins[];
-extern const char kEnableThreadedEventHandlingMac[];
+extern const char kDisableThreadedEventHandlingMac[];
#endif
#if defined(OS_WIN)
@@ -287,14 +292,14 @@ extern const char kEnableThreadedEventHandlingMac[];
// like renderers, etc.
CONTENT_EXPORT extern const char kDeviceScaleFactor[];
CONTENT_EXPORT extern const char kDisableLegacyIntermediateWindow[];
-// This switch will be removed when we enable the win32K lockdown process
-// mitigation.
-CONTENT_EXPORT extern const char kEnableWin32kRendererLockDown[];
+CONTENT_EXPORT extern const char kDisableWin32kRendererLockDown[];
+CONTENT_EXPORT extern const char kMemoryPressureThresholdsMb[];
+// Switch to pass the font cache shared memory handle to the renderer.
+CONTENT_EXPORT extern const char kFontCacheSharedHandle[];
+CONTENT_EXPORT extern const char kTraceExportEventsToETW[];
#endif
-#if defined(ENABLE_PLUGINS)
-CONTENT_EXPORT extern const char kEnablePluginPowerSaver[];
-#endif
+CONTENT_EXPORT extern const char kEnableNpapi[];
// DON'T ADD RANDOM STUFF HERE. Put it in the main section above in
// alphabetical order, or in one of the ifdefs (also in order in each section).
diff --git a/chromium/content/public/common/context_menu_params.h b/chromium/content/public/common/context_menu_params.h
index 8849dae303d..9fe170a0184 100644
--- a/chromium/content/public/common/context_menu_params.h
+++ b/chromium/content/public/common/context_menu_params.h
@@ -20,7 +20,7 @@
#include "url/gurl.h"
#if defined(OS_ANDROID)
-#include "ui/gfx/point.h"
+#include "ui/gfx/geometry/point.h"
#endif
namespace content {
diff --git a/chromium/content/public/common/dwrite_font_platform_win.h b/chromium/content/public/common/dwrite_font_platform_win.h
new file mode 100644
index 00000000000..4c988bc82eb
--- /dev/null
+++ b/chromium/content/public/common/dwrite_font_platform_win.h
@@ -0,0 +1,41 @@
+// Copyright 2014 The Chromium Authors. 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_COMMON_DWRITE_FONT_PLATFORM_WIN_H_
+#define CONTENT_PUBLIC_COMMON_DWRITE_FONT_PLATFORM_WIN_H_
+
+#include "base/files/file.h"
+#include "content/common/content_export.h"
+
+struct IDWriteFactory;
+struct IDWriteFontCollection;
+
+namespace content {
+
+// This is the shared section that is used between browser and renderer for
+// loading font cache. Section name is suffixed with browser process id so that
+// multiple instance chrome scenario works fine.
+CONTENT_EXPORT extern const char kFontCacheSharedSectionName[];
+
+// Function returns custom font collection in terms of IDWriteFontCollection.
+// This function maintains singleton instance of font collection and returns
+// it on repeated calls.
+CONTENT_EXPORT IDWriteFontCollection* GetCustomFontCollection(
+ IDWriteFactory* factory);
+
+// Builds static font cache. As this function need to iterate through all
+// available fonts in the system, it may take a while.
+CONTENT_EXPORT bool BuildFontCache(const base::FilePath& file);
+
+// Loads font cache from file. This is supposed to be used from browser
+// side where loading means creating readonly shared memory file mapping so that
+// renderers can read from it.
+CONTENT_EXPORT bool LoadFontCache(const base::FilePath& path);
+
+// Added in header mainly for unittest
+CONTENT_EXPORT bool ValidateFontCacheFile(base::File* file);
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_COMMON_DWRITE_FONT_PLATFORM_WIN_H_
diff --git a/chromium/content/public/common/favicon_url.h b/chromium/content/public/common/favicon_url.h
index 141925b099b..43770c2b86b 100644
--- a/chromium/content/public/common/favicon_url.h
+++ b/chromium/content/public/common/favicon_url.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_PUBLIC_COMMON_FAVICON_URL_
-#define CONTENT_PUBLIC_COMMON_FAVICON_URL_
+#ifndef CONTENT_PUBLIC_COMMON_FAVICON_URL_H_
+#define CONTENT_PUBLIC_COMMON_FAVICON_URL_H_
#include <vector>
@@ -42,4 +42,4 @@ struct CONTENT_EXPORT FaviconURL {
} // namespace content
-#endif // CONTENT_PUBLIC_COMMON_FAVICON_URL_
+#endif // CONTENT_PUBLIC_COMMON_FAVICON_URL_H_
diff --git a/chromium/content/public/common/frame_navigate_params.cc b/chromium/content/public/common/frame_navigate_params.cc
index 637cec53e8e..1aef9e51e51 100644
--- a/chromium/content/public/common/frame_navigate_params.cc
+++ b/chromium/content/public/common/frame_navigate_params.cc
@@ -8,6 +8,7 @@ namespace content {
FrameNavigateParams::FrameNavigateParams()
: page_id(0),
+ nav_entry_id(0),
transition(ui::PAGE_TRANSITION_LINK),
should_update_history(false) {
}
diff --git a/chromium/content/public/common/frame_navigate_params.h b/chromium/content/public/common/frame_navigate_params.h
index b704b8e9306..884a1d1b6d2 100644
--- a/chromium/content/public/common/frame_navigate_params.h
+++ b/chromium/content/public/common/frame_navigate_params.h
@@ -27,6 +27,12 @@ struct CONTENT_EXPORT FrameNavigateParams {
// iframes are loaded automatically.
int32 page_id;
+ // The unique ID of the NavigationEntry for browser-initiated navigations.
+ // This value was given to the render process in the HistoryNavigationParams
+ // and is being returned by the renderer without it having any idea what it
+ // means. If the navigation was renderer-initiated, this value is 0.
+ int nav_entry_id;
+
// URL of the page being loaded.
GURL url;
diff --git a/chromium/content/public/common/geoposition.h b/chromium/content/public/common/geoposition.h
index 04946963972..0bcb839e6b9 100644
--- a/chromium/content/public/common/geoposition.h
+++ b/chromium/content/public/common/geoposition.h
@@ -64,4 +64,4 @@ struct CONTENT_EXPORT Geoposition {
} // namespace content
-#endif // CONTENT_COMMON_GEOPOSITION_H_
+#endif // CONTENT_PUBLIC_COMMON_GEOPOSITION_H_
diff --git a/chromium/content/public/common/injection_test_win.h b/chromium/content/public/common/injection_test_win.h
index cc1e684e13f..67e8428d851 100644
--- a/chromium/content/public/common/injection_test_win.h
+++ b/chromium/content/public/common/injection_test_win.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_COMMON_INJECTION_TEST_WIN_H_
-#define CONTENT_COMMON_INJECTION_TEST_WIN_H_
+#ifndef CONTENT_PUBLIC_COMMON_INJECTION_TEST_WIN_H_
+#define CONTENT_PUBLIC_COMMON_INJECTION_TEST_WIN_H_
// This file defines the entry points for any DLL that can be loaded into the
// renderer or plugin process for the purposes of testing. The DLL code must
@@ -23,4 +23,4 @@ typedef BOOL (__cdecl *RunPluginTests)(int* test_count);
#endif
}
-#endif // CONTENT_COMMON_INJECTION_TEST_WIN_H_
+#endif // CONTENT_PUBLIC_COMMON_INJECTION_TEST_WIN_H_
diff --git a/chromium/content/public/common/manifest.cc b/chromium/content/public/common/manifest.cc
index 292b85b44db..5ee29630588 100644
--- a/chromium/content/public/common/manifest.cc
+++ b/chromium/content/public/common/manifest.cc
@@ -16,9 +16,17 @@ Manifest::Icon::Icon()
Manifest::Icon::~Icon() {
}
+Manifest::RelatedApplication::RelatedApplication() {
+}
+
+Manifest::RelatedApplication::~RelatedApplication() {
+}
+
Manifest::Manifest()
: display(DISPLAY_MODE_UNSPECIFIED),
- orientation(blink::WebScreenOrientationLockDefault) {
+ orientation(blink::WebScreenOrientationLockDefault),
+ prefer_related_applications(false),
+ gcm_user_visible_only(false) {
}
Manifest::~Manifest() {
@@ -31,7 +39,10 @@ bool Manifest::IsEmpty() const {
display == DISPLAY_MODE_UNSPECIFIED &&
orientation == blink::WebScreenOrientationLockDefault &&
icons.empty() &&
- gcm_sender_id.is_null();
+ related_applications.empty() &&
+ !prefer_related_applications &&
+ gcm_sender_id.is_null() &&
+ !gcm_user_visible_only;
}
} // namespace content
diff --git a/chromium/content/public/common/manifest.h b/chromium/content/public/common/manifest.h
index 038bd0d9f7c..59948c0b8ef 100644
--- a/chromium/content/public/common/manifest.h
+++ b/chromium/content/public/common/manifest.h
@@ -54,6 +54,26 @@ struct CONTENT_EXPORT Manifest {
static const double kDefaultDensity;
};
+ // Structure representing a related application.
+ struct CONTENT_EXPORT RelatedApplication {
+ RelatedApplication();
+ ~RelatedApplication();
+
+ // The platform on which the application can be found. This can be any
+ // string, and is interpreted by the consumer of the object. Empty if the
+ // parsing failed.
+ base::NullableString16 platform;
+
+ // URL at which the application can be found. One of |url| and |id| must be
+ // present. Empty if the parsing failed or the field was not present.
+ GURL url;
+
+ // An id which is used to represent the application on the platform. One of
+ // |url| and |id| must be present. Empty if the parsing failed or the field
+ // was not present.
+ base::NullableString16 id;
+ };
+
Manifest();
~Manifest();
@@ -82,11 +102,26 @@ struct CONTENT_EXPORT Manifest {
// icons inside the JSON array were invalid.
std::vector<Icon> icons;
+ // Empty if the parsing failed, the field was not present, empty or all the
+ // applications inside the array were invalid. The order of the array
+ // indicates the priority of the application to use.
+ std::vector<RelatedApplication> related_applications;
+
+ // A boolean that is used as a hint for the user agent to say that related
+ // applications should be preferred over the web application. False if missing
+ // or there is a parsing failure.
+ bool prefer_related_applications;
+
// This is a proprietary extension of the web Manifest, double-check that it
// is okay to use this entry.
// Null if parsing failed or the field was not present.
base::NullableString16 gcm_sender_id;
+ // This is a proprietary extension of the web Manifest, double-check that it
+ // is okay to use this entry.
+ // False if parsing failed or the field was not present.
+ bool gcm_user_visible_only;
+
// Maximum length for all the strings inside the Manifest when it is sent over
// IPC. The renderer process should truncate the strings before sending the
// Manifest and the browser process must do the same when receiving it.
diff --git a/chromium/content/public/common/media_stream_request.cc b/chromium/content/public/common/media_stream_request.cc
index dc5e1569cc8..0a35bd783bf 100644
--- a/chromium/content/public/common/media_stream_request.cc
+++ b/chromium/content/public/common/media_stream_request.cc
@@ -11,7 +11,7 @@ namespace content {
bool IsAudioInputMediaType(MediaStreamType type) {
return (type == MEDIA_DEVICE_AUDIO_CAPTURE ||
type == content::MEDIA_TAB_AUDIO_CAPTURE ||
- type == content::MEDIA_LOOPBACK_AUDIO_CAPTURE);
+ type == content::MEDIA_DESKTOP_AUDIO_CAPTURE);
}
bool IsVideoMediaType(MediaStreamType type) {
@@ -103,7 +103,8 @@ MediaStreamRequest::MediaStreamRequest(
requested_audio_device_id(requested_audio_device_id),
requested_video_device_id(requested_video_device_id),
audio_type(audio_type),
- video_type(video_type) {
+ video_type(video_type),
+ all_ancestors_have_same_origin(false) {
}
MediaStreamRequest::~MediaStreamRequest() {}
diff --git a/chromium/content/public/common/media_stream_request.h b/chromium/content/public/common/media_stream_request.h
index 31ebbead2a9..b60835ee04b 100644
--- a/chromium/content/public/common/media_stream_request.h
+++ b/chromium/content/public/common/media_stream_request.h
@@ -34,9 +34,7 @@ enum MediaStreamType {
MEDIA_DESKTOP_VIDEO_CAPTURE,
// Capture system audio (post-mix loopback stream).
- //
- // TODO(sergeyu): Replace with MEDIA_DESKTOP_AUDIO_CAPTURE.
- MEDIA_LOOPBACK_AUDIO_CAPTURE,
+ MEDIA_DESKTOP_AUDIO_CAPTURE,
// This is used for enumerating audio output devices.
// TODO(grunell): Output isn't really a part of media streams. Device
@@ -220,9 +218,6 @@ struct CONTENT_EXPORT MediaStreamRequest {
// identifying this request. This is used for cancelling request.
int page_request_id;
- // Used by tab capture.
- std::string tab_capture_device_id;
-
// The WebKit security origin for the current request (e.g. "html5rocks.com").
GURL security_origin;
@@ -244,6 +239,9 @@ struct CONTENT_EXPORT MediaStreamRequest {
// Flag to indicate if the request contains video.
MediaStreamType video_type;
+
+ // True if all ancestors of the requesting frame have the same origin.
+ bool all_ancestors_have_same_origin;
};
// Interface used by the content layer to notify chrome about changes in the
diff --git a/chromium/content/public/common/menu_item.cc b/chromium/content/public/common/menu_item.cc
index 4ea06cfb243..a379774d727 100644
--- a/chromium/content/public/common/menu_item.cc
+++ b/chromium/content/public/common/menu_item.cc
@@ -17,6 +17,7 @@ MenuItem::MenuItem()
MenuItem::MenuItem(const MenuItem& item)
: label(item.label),
+ icon(item.icon),
tool_tip(item.tool_tip),
type(item.type),
action(item.action),
diff --git a/chromium/content/public/common/menu_item.h b/chromium/content/public/common/menu_item.h
index 982832c7334..26255bd9821 100644
--- a/chromium/content/public/common/menu_item.h
+++ b/chromium/content/public/common/menu_item.h
@@ -29,6 +29,7 @@ struct CONTENT_EXPORT MenuItem {
~MenuItem();
base::string16 label;
+ base::string16 icon;
base::string16 tool_tip;
Type type;
unsigned action;
diff --git a/chromium/content/public/common/message_port_types.cc b/chromium/content/public/common/message_port_types.cc
new file mode 100644
index 00000000000..bc69ff0eb77
--- /dev/null
+++ b/chromium/content/public/common/message_port_types.cc
@@ -0,0 +1,46 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/public/common/message_port_types.h"
+
+#include "base/logging.h"
+
+namespace content {
+
+MessagePortMessage::MessagePortMessage() {
+}
+
+MessagePortMessage::MessagePortMessage(const base::string16& message)
+ : message_as_string(message) {
+}
+
+MessagePortMessage::MessagePortMessage(scoped_ptr<base::Value> message) {
+ message_as_value.Append(message.release());
+}
+
+MessagePortMessage::MessagePortMessage(const MessagePortMessage& other) {
+ *this = other;
+}
+
+MessagePortMessage& MessagePortMessage::operator=(
+ const MessagePortMessage& other) {
+ message_as_string = other.message_as_string;
+ message_as_value.Clear();
+ const base::Value* value;
+ if (other.message_as_value.Get(0, &value))
+ message_as_value.Append(value->DeepCopy());
+ return *this;
+}
+
+MessagePortMessage::~MessagePortMessage() {
+}
+
+const base::Value* MessagePortMessage::as_value() const {
+ const base::Value* value = nullptr;
+ bool result = message_as_value.Get(0, &value);
+ DCHECK(result);
+ return value;
+}
+
+} // namespace content
diff --git a/chromium/content/public/common/message_port_types.h b/chromium/content/public/common/message_port_types.h
new file mode 100644
index 00000000000..cf53d088dc4
--- /dev/null
+++ b/chromium/content/public/common/message_port_types.h
@@ -0,0 +1,48 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_PUBLIC_COMMON_MESSAGE_PORT_TYPES_H_
+#define CONTENT_PUBLIC_COMMON_MESSAGE_PORT_TYPES_H_
+
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string16.h"
+#include "base/values.h"
+#include "content/common/content_export.h"
+#include "ipc/ipc_message.h"
+
+namespace content {
+
+// Struct representing a message sent across a message port. This struct hides
+// the fact that messages can be serialized/encoded in multiple ways from code
+// that doesn't care about the message contents.
+struct CONTENT_EXPORT MessagePortMessage {
+ MessagePortMessage();
+ explicit MessagePortMessage(const base::string16& message);
+ explicit MessagePortMessage(scoped_ptr<base::Value> message);
+ MessagePortMessage(const MessagePortMessage& other);
+ MessagePortMessage& operator=(const MessagePortMessage& other);
+ ~MessagePortMessage();
+
+ bool is_string() const { return !message_as_string.empty(); }
+ bool is_value() const { return !message_as_value.empty(); }
+ const base::Value* as_value() const;
+
+ // Message serialized using blink::WebSerializedScriptValue. Only one of
+ // |message_as_string| and |message_as_value| should be non-empty.
+ base::string16 message_as_string;
+ // Message as a base::Value. This is either an empty list or a list
+ // containing exactly one item.
+ base::ListValue message_as_value;
+};
+
+struct TransferredMessagePort {
+ int id = MSG_ROUTING_NONE;
+ bool send_messages_as_values = false;
+};
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_COMMON_MESSAGE_PORT_TYPES_H_
diff --git a/chromium/content/public/common/mojo_channel_switches.cc b/chromium/content/public/common/mojo_channel_switches.cc
new file mode 100644
index 00000000000..8f70ce287d0
--- /dev/null
+++ b/chromium/content/public/common/mojo_channel_switches.cc
@@ -0,0 +1,37 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/public/common/mojo_channel_switches.h"
+
+#include "base/command_line.h"
+#include "ipc/mojo/ipc_channel_mojo.h"
+#include "mojo/common/common_type_converters.h"
+
+namespace switches {
+
+// Replaces renderer-browser IPC channel with ChnanelMojo.
+// TODO(morrita): Now ChannelMojo for the renderer is on by default.
+// Remove this once the change sticks.
+const char kEnableRendererMojoChannel[] =
+ "enable-renderer-mojo-channel";
+
+// Disale ChannelMojo usage regardless of the platform or the process type.
+const char kDisableMojoChannel[] = "disable-mojo-channel";
+
+} // namespace switches
+
+namespace content {
+
+bool ShouldUseMojoChannel() {
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
+
+ if (command_line.HasSwitch(switches::kDisableMojoChannel))
+ return false;
+ if (command_line.HasSwitch(switches::kEnableRendererMojoChannel))
+ return true;
+ return IPC::ChannelMojo::ShouldBeUsed();
+}
+
+} // namespace content
diff --git a/chromium/content/public/common/mojo_channel_switches.h b/chromium/content/public/common/mojo_channel_switches.h
new file mode 100644
index 00000000000..5e2af68f8d6
--- /dev/null
+++ b/chromium/content/public/common/mojo_channel_switches.h
@@ -0,0 +1,23 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_PUBLIC_COMMON_MOJO_CHANNEL_SWITCHES_H_
+#define CONTENT_PUBLIC_COMMON_MOJO_CHANNEL_SWITCHES_H_
+
+#include "content/common/content_export.h"
+
+namespace switches {
+
+extern const char kEnableRendererMojoChannel[];
+extern const char kDisableMojoChannel[];
+
+} // namespace switches
+
+namespace content {
+
+bool CONTENT_EXPORT ShouldUseMojoChannel();
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_COMMON_MOJO_CHANNEL_SWITCHES_H_
diff --git a/chromium/content/public/common/navigator_connect_client.cc b/chromium/content/public/common/navigator_connect_client.cc
new file mode 100644
index 00000000000..bf21bc96cdd
--- /dev/null
+++ b/chromium/content/public/common/navigator_connect_client.cc
@@ -0,0 +1,21 @@
+// Copyright 2014 The Chromium Authors. 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/common/navigator_connect_client.h"
+
+namespace content {
+
+NavigatorConnectClient::NavigatorConnectClient() : message_port_id(-1) {
+}
+
+NavigatorConnectClient::NavigatorConnectClient(const GURL& target_url,
+ const GURL& origin,
+ int message_port_id)
+ : target_url(target_url), origin(origin), message_port_id(message_port_id) {
+}
+
+NavigatorConnectClient::~NavigatorConnectClient() {
+}
+
+} // namespace content
diff --git a/chromium/content/public/common/navigator_connect_client.h b/chromium/content/public/common/navigator_connect_client.h
new file mode 100644
index 00000000000..9cc66ec7163
--- /dev/null
+++ b/chromium/content/public/common/navigator_connect_client.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_PUBLIC_COMMON_NAVIGATOR_CONNECT_CLIENT_H_
+#define CONTENT_PUBLIC_COMMON_NAVIGATOR_CONNECT_CLIENT_H_
+
+#include "url/gurl.h"
+
+namespace content {
+
+// This struct represents a connection to a navigator.connect exposed service.
+struct NavigatorConnectClient {
+ NavigatorConnectClient();
+ NavigatorConnectClient(const GURL& target_url,
+ const GURL& origin,
+ int message_port_id);
+ ~NavigatorConnectClient();
+
+ // The URL this client is connected to (or trying to connect to).
+ GURL target_url;
+
+ // The origin of the client.
+ GURL origin;
+
+ // Message port ID for the service side message port associated with this
+ // client.
+ int message_port_id;
+};
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_COMMON_NAVIGATOR_CONNECT_CLIENT_H_
diff --git a/chromium/content/public/common/origin_util.h b/chromium/content/public/common/origin_util.h
new file mode 100644
index 00000000000..e3efd6b5213
--- /dev/null
+++ b/chromium/content/public/common/origin_util.h
@@ -0,0 +1,26 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_PUBLIC_COMMON_ORIGIN_UTIL_H_
+#define CONTENT_PUBLIC_COMMON_ORIGIN_UTIL_H_
+
+#include "content/common/content_export.h"
+
+class GURL;
+
+namespace content {
+
+// Returns true if the origin is trustworthy: that is, if its contents can be
+// said to have been transferred to the browser in a way that a network attacker
+// cannot tamper with or observe.
+//
+// See https://www.w3.org/TR/powerful-features/#is-origin-trustworthy.
+bool CONTENT_EXPORT IsOriginSecure(const GURL& url);
+
+// Resets the internal schemes/origins whitelist. Used only for testing.
+void CONTENT_EXPORT ResetSecureSchemesAndOriginsForTesting();
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_COMMON_ORIGIN_UTIL_H_
diff --git a/chromium/content/public/common/pepper_plugin_info.cc b/chromium/content/public/common/pepper_plugin_info.cc
index d627a4becb0..018bf183103 100644
--- a/chromium/content/public/common/pepper_plugin_info.cc
+++ b/chromium/content/public/common/pepper_plugin_info.cc
@@ -17,7 +17,6 @@ PepperPluginInfo::EntryPoints::EntryPoints()
PepperPluginInfo::PepperPluginInfo()
: is_internal(false),
is_out_of_process(false),
- is_sandboxed(true),
permissions(0) {
}
@@ -28,9 +27,7 @@ WebPluginInfo PepperPluginInfo::ToWebPluginInfo() const {
WebPluginInfo info;
info.type = is_out_of_process ?
- (is_sandboxed ?
- WebPluginInfo::PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS :
- WebPluginInfo::PLUGIN_TYPE_PEPPER_UNSANDBOXED) :
+ WebPluginInfo::PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS :
WebPluginInfo::PLUGIN_TYPE_PEPPER_IN_PROCESS;
info.name = name.empty() ?
diff --git a/chromium/content/public/common/pepper_plugin_info.h b/chromium/content/public/common/pepper_plugin_info.h
index bb1d9de6127..0c202f94fcb 100644
--- a/chromium/content/public/common/pepper_plugin_info.h
+++ b/chromium/content/public/common/pepper_plugin_info.h
@@ -48,10 +48,6 @@ struct CONTENT_EXPORT PepperPluginInfo {
// True when this plugin should be run out of process. Defaults to false.
bool is_out_of_process;
- // True when an out-of-process plugin should also be run within sandbox.
- // Defaults to true.
- bool is_sandboxed;
-
base::FilePath path; // Internal plugins have "internal-[name]" as path.
std::string name;
std::string description;
diff --git a/chromium/content/public/common/permission_status.mojom b/chromium/content/public/common/permission_status.mojom
new file mode 100644
index 00000000000..f7e56bfab19
--- /dev/null
+++ b/chromium/content/public/common/permission_status.mojom
@@ -0,0 +1,11 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module content;
+
+enum PermissionStatus {
+ GRANTED,
+ DENIED,
+ ASK
+};
diff --git a/chromium/content/public/common/persistent_notification_status.h b/chromium/content/public/common/persistent_notification_status.h
new file mode 100644
index 00000000000..b8f14094b3a
--- /dev/null
+++ b/chromium/content/public/common/persistent_notification_status.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_PUBLIC_COMMON_PERSISTENT_NOTIFICATION_STATUS_H_
+#define CONTENT_PUBLIC_COMMON_PERSISTENT_NOTIFICATION_STATUS_H_
+
+namespace content {
+
+// Delivery status for persistent notification clicks to a Service Worker.
+enum PersistentNotificationStatus {
+ // The notificationclick event has been delivered successfully.
+ PERSISTENT_NOTIFICATION_STATUS_SUCCESS = 0,
+
+ // The event could not be delivered because the Service Worker is unavailable.
+ PERSISTENT_NOTIFICATION_STATUS_NO_SERVICE_WORKER,
+
+ // The event could not be delivered because of a Service Worker error.
+ PERSISTENT_NOTIFICATION_STATUS_SERVICE_WORKER_ERROR,
+
+ // The event has been delivered, but the developer extended the event with a
+ // promise that has been rejected.
+ PERSISTENT_NOTIFICATION_STATUS_EVENT_WAITUNTIL_REJECTED,
+
+ // The event could not be delivered because the data associated with the
+ // notification could not be read from the database.
+ PERSISTENT_NOTIFICATION_STATUS_DATABASE_ERROR,
+};
+
+} // content
+
+#endif // CONTENT_PUBLIC_COMMON_PERSISTENT_NOTIFICATION_STATUS_H_
diff --git a/chromium/content/public/common/platform_notification_data.cc b/chromium/content/public/common/platform_notification_data.cc
new file mode 100644
index 00000000000..387dee678ce
--- /dev/null
+++ b/chromium/content/public/common/platform_notification_data.cc
@@ -0,0 +1,13 @@
+// Copyright 2014 The Chromium Authors. 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/common/platform_notification_data.h"
+
+namespace content {
+
+PlatformNotificationData::PlatformNotificationData() {}
+
+PlatformNotificationData::~PlatformNotificationData() {}
+
+} // namespace content
diff --git a/chromium/content/public/common/platform_notification_data.h b/chromium/content/public/common/platform_notification_data.h
new file mode 100644
index 00000000000..40bd98d0873
--- /dev/null
+++ b/chromium/content/public/common/platform_notification_data.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_PUBLIC_COMMON_PLATFORM_NOTIFICATION_DATA_H_
+#define CONTENT_PUBLIC_COMMON_PLATFORM_NOTIFICATION_DATA_H_
+
+#include <string>
+#include <vector>
+
+#include "base/strings/string16.h"
+#include "content/common/content_export.h"
+#include "url/gurl.h"
+
+namespace content {
+
+// Structure representing the information associated with a Web Notification.
+// This struct should include the developer-visible information, kept
+// synchronized with the WebNotificationData structure defined in the Blink API.
+struct CONTENT_EXPORT PlatformNotificationData {
+ PlatformNotificationData();
+ ~PlatformNotificationData();
+
+ // The maximum size of developer-provided data to be stored in the |data|
+ // property of this structure.
+ static const size_t kMaximumDeveloperDataSize = 1024 * 1024;
+
+ enum NotificationDirection {
+ NotificationDirectionLeftToRight,
+ NotificationDirectionRightToLeft,
+
+ NotificationDirectionLast = NotificationDirectionRightToLeft
+ };
+
+ // Title to be displayed with the Web Notification.
+ base::string16 title;
+
+ // Hint to determine the directionality of the displayed notification.
+ NotificationDirection direction = NotificationDirectionLeftToRight;
+
+ // BCP 47 language tag describing the notification's contents. Optional.
+ std::string lang;
+
+ // Contents of the notification.
+ base::string16 body;
+
+ // Tag of the notification. Notifications sharing both their origin and their
+ // tag will replace the first displayed notification.
+ std::string tag;
+
+ // URL of the icon which is to be displayed with the notification.
+ GURL icon;
+
+ // Vibration pattern for the notification, following the syntax of the
+ // Vibration API. https://www.w3.org/TR/vibration/
+ std::vector<int> vibration_pattern;
+
+ // Whether default notification indicators (sound, vibration, light) should
+ // be suppressed.
+ bool silent = false;
+
+ // Developer-provided data associated with the notification, in the form of
+ // a serialized string. Must not exceed |kMaximumDeveloperDataSize| bytes.
+ std::vector<char> data;
+};
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_COMMON_PLATFORM_NOTIFICATION_DATA_H_
diff --git a/chromium/content/public/common/presentation_constants.cc b/chromium/content/public/common/presentation_constants.cc
new file mode 100644
index 00000000000..da7e6acd376
--- /dev/null
+++ b/chromium/content/public/common/presentation_constants.cc
@@ -0,0 +1,11 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/public/common/presentation_constants.h"
+
+namespace content {
+
+const size_t kMaxPresentationSessionMessageSize = 64 * 1024; // 64 KB.
+
+} // namespace content
diff --git a/chromium/content/public/common/presentation_constants.h b/chromium/content/public/common/presentation_constants.h
new file mode 100644
index 00000000000..e162d400f0f
--- /dev/null
+++ b/chromium/content/public/common/presentation_constants.h
@@ -0,0 +1,19 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_PUBLIC_COMMON_PRESENTATION_CONSTANTS_H_
+#define CONTENT_PUBLIC_COMMON_PRESENTATION_CONSTANTS_H_
+
+#include <stddef.h> // For size_t
+
+#include "content/common/content_export.h"
+
+namespace content {
+
+// The maximum number of bytes allowed in a presentation session message.
+CONTENT_EXPORT extern const size_t kMaxPresentationSessionMessageSize;
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_COMMON_PRESENTATION_CONSTANTS_H_
diff --git a/chromium/content/public/common/push_messaging_status.cc b/chromium/content/public/common/push_messaging_status.cc
index d3b3d1b9dc5..9b4a42138e6 100644
--- a/chromium/content/public/common/push_messaging_status.cc
+++ b/chromium/content/public/common/push_messaging_status.cc
@@ -10,8 +10,8 @@ namespace content {
const char* PushRegistrationStatusToString(PushRegistrationStatus status) {
switch (status) {
- case PUSH_REGISTRATION_STATUS_SUCCESS:
- return "Registration successful";
+ case PUSH_REGISTRATION_STATUS_SUCCESS_FROM_PUSH_SERVICE:
+ return "Registration successful - from push service";
case PUSH_REGISTRATION_STATUS_NO_SERVICE_WORKER:
return "Registration failed - no Service Worker";
@@ -30,6 +30,52 @@ const char* PushRegistrationStatusToString(PushRegistrationStatus status) {
case PUSH_REGISTRATION_STATUS_NO_SENDER_ID:
return "Registration failed - no sender id provided";
+
+ case PUSH_REGISTRATION_STATUS_STORAGE_ERROR:
+ return "Registration failed - storage error";
+
+ case PUSH_REGISTRATION_STATUS_SUCCESS_FROM_CACHE:
+ return "Registration successful - from cache";
+
+ case PUSH_REGISTRATION_STATUS_NETWORK_ERROR:
+ return "Registration failed - could not connect to push server";
+
+ case PUSH_REGISTRATION_STATUS_INCOGNITO_PERMISSION_DENIED:
+ // We split this out for UMA, but it must be indistinguishable to JS.
+ return PushRegistrationStatusToString(
+ PUSH_REGISTRATION_STATUS_PERMISSION_DENIED);
+ }
+ NOTREACHED();
+ return "";
+}
+
+const char* PushUnregistrationStatusToString(PushUnregistrationStatus status) {
+ switch (status) {
+ case PUSH_UNREGISTRATION_STATUS_SUCCESS_UNREGISTERED:
+ return "Unregistration successful - from push service";
+
+ case PUSH_UNREGISTRATION_STATUS_SUCCESS_WAS_NOT_REGISTERED:
+ return "Unregistration successful - was not registered";
+
+ case PUSH_UNREGISTRATION_STATUS_PENDING_NETWORK_ERROR:
+ return "Unregistration pending - a network error occurred, but it will "
+ "be retried until it succeeds";
+
+ case PUSH_UNREGISTRATION_STATUS_NO_SERVICE_WORKER:
+ return "Unregistration failed - no Service Worker";
+
+ case PUSH_UNREGISTRATION_STATUS_SERVICE_NOT_AVAILABLE:
+ return "Unregistration failed - push service not available";
+
+ case PUSH_UNREGISTRATION_STATUS_PENDING_SERVICE_ERROR:
+ return "Unregistration pending - a push service error occurred, but it "
+ "will be retried until it succeeds";
+
+ case PUSH_UNREGISTRATION_STATUS_STORAGE_ERROR:
+ return "Unregistration failed - storage error";
+
+ case PUSH_UNREGISTRATION_STATUS_NETWORK_ERROR:
+ return "Unregistration failed - could not connect to push server";
}
NOTREACHED();
return "";
diff --git a/chromium/content/public/common/push_messaging_status.h b/chromium/content/public/common/push_messaging_status.h
index 22351ca18bf..9d9fc8f9105 100644
--- a/chromium/content/public/common/push_messaging_status.h
+++ b/chromium/content/public/common/push_messaging_status.h
@@ -7,10 +7,15 @@
namespace content {
-// Push registration success / error codes for internal use & reporting in UMA.
+// Push registration success/error codes for internal use & reporting in UMA.
enum PushRegistrationStatus {
- // Registration was successful.
- PUSH_REGISTRATION_STATUS_SUCCESS = 0,
+ // New successful registration (there was not yet a registration cached in
+ // Service Worker storage, so the browser successfully registered with the
+ // push service. This is likely to be a new push registration, though it's
+ // possible that the push service had its own cache (for example if Chrome's
+ // app data was cleared, we might have forgotten about a registration that the
+ // push service still stores).
+ PUSH_REGISTRATION_STATUS_SUCCESS_FROM_PUSH_SERVICE = 0,
// Registration failed because there is no Service Worker.
PUSH_REGISTRATION_STATUS_NO_SERVICE_WORKER = 1,
@@ -31,34 +36,155 @@ enum PushRegistrationStatus {
// Registration failed because no sender id was provided by the page.
PUSH_REGISTRATION_STATUS_NO_SENDER_ID = 6,
+ // Registration succeeded, but we failed to persist it.
+ PUSH_REGISTRATION_STATUS_STORAGE_ERROR = 7,
+
+ // A successful registration was already cached in Service Worker storage.
+ PUSH_REGISTRATION_STATUS_SUCCESS_FROM_CACHE = 8,
+
+ // Registration failed due to a network error.
+ PUSH_REGISTRATION_STATUS_NETWORK_ERROR = 9,
+
+ // Registration failed because the push service is not available in incognito,
+ // but we tell JS that permission was denied to not reveal incognito.
+ PUSH_REGISTRATION_STATUS_INCOGNITO_PERMISSION_DENIED = 10,
+
// 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, and
// update PUSH_REGISTRATION_STATUS_LAST below.
- // Used for IPC message range checks.
- PUSH_REGISTRATION_STATUS_LAST = PUSH_REGISTRATION_STATUS_NO_SENDER_ID
+ PUSH_REGISTRATION_STATUS_LAST =
+ PUSH_REGISTRATION_STATUS_INCOGNITO_PERMISSION_DENIED
+};
+
+// Push unregistration success/error codes for internal use & reporting in UMA.
+enum PushUnregistrationStatus {
+ // The unregistration was successful.
+ PUSH_UNREGISTRATION_STATUS_SUCCESS_UNREGISTERED = 0,
+
+ // Unregistration was unnecessary, as the registration was not found.
+ PUSH_UNREGISTRATION_STATUS_SUCCESS_WAS_NOT_REGISTERED = 1,
+
+ // The unregistration did not happen because of a network error, but will be
+ // retried until it succeeds.
+ PUSH_UNREGISTRATION_STATUS_PENDING_NETWORK_ERROR = 2,
+
+ // Unregistration failed because there is no Service Worker.
+ PUSH_UNREGISTRATION_STATUS_NO_SERVICE_WORKER = 3,
+
+ // Unregistration failed because the push service is not available.
+ PUSH_UNREGISTRATION_STATUS_SERVICE_NOT_AVAILABLE = 4,
+
+ // Unregistration failed in the push service implemented by the embedder, but
+ // will be retried until it succeeds.
+ PUSH_UNREGISTRATION_STATUS_PENDING_SERVICE_ERROR = 5,
+
+ // Unregistration succeeded, but we failed to clear Service Worker storage.
+ PUSH_UNREGISTRATION_STATUS_STORAGE_ERROR = 6,
+
+ // Unregistration failed due to a network error.
+ PUSH_UNREGISTRATION_STATUS_NETWORK_ERROR = 7,
+
+ // 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, and
+ // update PUSH_UNREGISTRATION_STATUS_LAST below.
+
+ PUSH_UNREGISTRATION_STATUS_LAST = PUSH_UNREGISTRATION_STATUS_NETWORK_ERROR
+};
+
+// Push getregistration success/error codes for internal use & reporting in UMA.
+enum PushGetRegistrationStatus {
+ // Getting the registration was successful.
+ PUSH_GETREGISTRATION_STATUS_SUCCESS = 0,
+
+ // Getting the registration failed because the push service is not available.
+ PUSH_GETREGISTRATION_STATUS_SERVICE_NOT_AVAILABLE = 1,
+
+ // Getting the registration failed because we failed to read from storage.
+ PUSH_GETREGISTRATION_STATUS_STORAGE_ERROR = 2,
+
+ // Getting the registration failed because there is no push registration.
+ PUSH_GETREGISTRATION_STATUS_REGISTRATION_NOT_FOUND = 3,
+
+ // Getting the registration failed because the push service isn't available in
+ // incognito, but we tell JS registration not found to not reveal incognito.
+ PUSH_GETREGISTRATION_STATUS_INCOGNITO_REGISTRATION_NOT_FOUND = 4,
+
+ // 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, and
+ // update PUSH_GETREGISTRATION_STATUS_LAST below.
+
+ PUSH_GETREGISTRATION_STATUS_LAST =
+ PUSH_GETREGISTRATION_STATUS_INCOGNITO_REGISTRATION_NOT_FOUND
};
-// Push message delivery success / error codes for internal use.
+// Push message event success/error codes for internal use & reporting in UMA.
enum PushDeliveryStatus {
// The message was successfully delivered.
- PUSH_DELIVERY_STATUS_SUCCESS,
+ PUSH_DELIVERY_STATUS_SUCCESS = 0,
+
+ // The message could not be delivered because it was invalid.
+ PUSH_DELIVERY_STATUS_INVALID_MESSAGE = 1,
+
+ // The message could not be delivered because the app id was unknown.
+ PUSH_DELIVERY_STATUS_UNKNOWN_APP_ID = 2,
+
+ // The message could not be delivered because origin no longer has permission.
+ PUSH_DELIVERY_STATUS_PERMISSION_DENIED = 3,
// The message could not be delivered because no service worker was found.
- PUSH_DELIVERY_STATUS_NO_SERVICE_WORKER,
+ PUSH_DELIVERY_STATUS_NO_SERVICE_WORKER = 4,
// The message could not be delivered because of a service worker error.
- PUSH_DELIVERY_STATUS_SERVICE_WORKER_ERROR,
+ PUSH_DELIVERY_STATUS_SERVICE_WORKER_ERROR = 5,
+
+ // The message was delivered, but the Service Worker passed a Promise to
+ // event.waitUntil that got rejected.
+ PUSH_DELIVERY_STATUS_EVENT_WAITUNTIL_REJECTED = 6,
+
+ // 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, and
+ // update PUSH_DELIVERY_STATUS_LAST below.
+
+ PUSH_DELIVERY_STATUS_LAST = PUSH_DELIVERY_STATUS_EVENT_WAITUNTIL_REJECTED
+};
+
+// Push message user visible tracking for reporting in UMA.
+enum PushUserVisibleStatus {
+ // A notification was required and one (or more) were shown.
+ PUSH_USER_VISIBLE_STATUS_REQUIRED_AND_SHOWN = 0,
+
+ // A notification was not required, but one (or more) were shown anyway.
+ PUSH_USER_VISIBLE_STATUS_NOT_REQUIRED_BUT_SHOWN = 1,
+
+ // A notification was not required and none were shown.
+ PUSH_USER_VISIBLE_STATUS_NOT_REQUIRED_AND_NOT_SHOWN = 2,
- // When making changes, update PUSH_DELIVERY_STATUS_LAST below.
+ // A notification was required, but none were shown. Fortunately, the site has
+ // been well behaved recently so it was glossed over.
+ PUSH_USER_VISIBLE_STATUS_REQUIRED_BUT_NOT_SHOWN_USED_GRACE = 3,
- // Used for IPC message range checks.
- PUSH_DELIVERY_STATUS_LAST = PUSH_DELIVERY_STATUS_SERVICE_WORKER_ERROR
+ // A notification was required, but none were shown. Unfortunately, the site
+ // has run out of grace, so we had to show the user a generic notification.
+ PUSH_USER_VISIBLE_STATUS_REQUIRED_BUT_NOT_SHOWN_GRACE_EXCEEDED = 4,
+
+ // 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, and
+ // update PUSH_USER_VISIBLE_STATUS_LAST below.
+
+ PUSH_USER_VISIBLE_STATUS_LAST =
+ PUSH_USER_VISIBLE_STATUS_REQUIRED_BUT_NOT_SHOWN_GRACE_EXCEEDED
};
const char* PushRegistrationStatusToString(PushRegistrationStatus status);
+const char* PushUnregistrationStatusToString(PushUnregistrationStatus status);
+
} // namespace content
#endif // CONTENT_PUBLIC_COMMON_PUSH_MESSAGING_STATUS_H_
diff --git a/chromium/content/public/common/referrer.cc b/chromium/content/public/common/referrer.cc
new file mode 100644
index 00000000000..183c950673f
--- /dev/null
+++ b/chromium/content/public/common/referrer.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 "base/command_line.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/common/referrer.h"
+
+namespace content {
+
+// static.
+Referrer Referrer::SanitizeForRequest(const GURL& request,
+ const Referrer& referrer) {
+ Referrer sanitized_referrer(referrer.url.GetAsReferrer(), referrer.policy);
+
+ if (!request.SchemeIsHTTPOrHTTPS() ||
+ !sanitized_referrer.url.SchemeIsHTTPOrHTTPS()) {
+ sanitized_referrer.url = GURL();
+ return sanitized_referrer;
+ }
+
+ bool is_downgrade = sanitized_referrer.url.SchemeIsCryptographic() &&
+ !request.SchemeIsCryptographic();
+
+ if (sanitized_referrer.policy < 0 ||
+ sanitized_referrer.policy > blink::WebReferrerPolicyLast) {
+ NOTREACHED();
+ sanitized_referrer.policy = blink::WebReferrerPolicyNever;
+ }
+
+ switch (sanitized_referrer.policy) {
+ case blink::WebReferrerPolicyDefault:
+ if (is_downgrade) {
+ sanitized_referrer.url = GURL();
+ } else if (request.GetOrigin() != sanitized_referrer.url.GetOrigin() &&
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kReducedReferrerGranularity)) {
+ sanitized_referrer.url = sanitized_referrer.url.GetOrigin();
+ }
+ break;
+ case blink::WebReferrerPolicyNoReferrerWhenDowngrade:
+ if (is_downgrade)
+ sanitized_referrer.url = GURL();
+ break;
+ case blink::WebReferrerPolicyAlways:
+ break;
+ case blink::WebReferrerPolicyNever:
+ sanitized_referrer.url = GURL();
+ break;
+ case blink::WebReferrerPolicyOrigin:
+ sanitized_referrer.url = sanitized_referrer.url.GetOrigin();
+ break;
+ case blink::WebReferrerPolicyOriginWhenCrossOrigin:
+ if (request.GetOrigin() != sanitized_referrer.url.GetOrigin())
+ sanitized_referrer.url = sanitized_referrer.url.GetOrigin();
+ break;
+ }
+ return sanitized_referrer;
+}
+
+} // namespace content
diff --git a/chromium/content/public/common/referrer.h b/chromium/content/public/common/referrer.h
index 122c5ead790..b45cd07150a 100644
--- a/chromium/content/public/common/referrer.h
+++ b/chromium/content/public/common/referrer.h
@@ -16,46 +16,15 @@ namespace content {
// applied to this URL. When passing around referrers that will eventually end
// up being used for URL requests, always use this struct.
struct CONTENT_EXPORT Referrer {
- Referrer(const GURL& url, blink::WebReferrerPolicy policy) : url(url),
- policy(policy) {
- }
- Referrer() : policy(blink::WebReferrerPolicyDefault) {
- }
+ Referrer(const GURL& url, blink::WebReferrerPolicy policy)
+ : url(url), policy(policy) {}
+ Referrer() : policy(blink::WebReferrerPolicyDefault) {}
GURL url;
blink::WebReferrerPolicy policy;
static Referrer SanitizeForRequest(const GURL& request,
- const Referrer& referrer) {
- Referrer sanitized_referrer(referrer.url.GetAsReferrer(), referrer.policy);
-
- if (!request.SchemeIsHTTPOrHTTPS() ||
- !sanitized_referrer.url.SchemeIsHTTPOrHTTPS()) {
- sanitized_referrer.url = GURL();
- return sanitized_referrer;
- }
-
- switch (sanitized_referrer.policy) {
- case blink::WebReferrerPolicyDefault:
- if (sanitized_referrer.url.SchemeIsSecure() &&
- !request.SchemeIsSecure()) {
- sanitized_referrer.url = GURL();
- }
- break;
- case blink::WebReferrerPolicyAlways:
- break;
- case blink::WebReferrerPolicyNever:
- sanitized_referrer.url = GURL();
- break;
- case blink::WebReferrerPolicyOrigin:
- sanitized_referrer.url = sanitized_referrer.url.GetOrigin();
- break;
- default:
- NOTREACHED();
- break;
- }
- return sanitized_referrer;
- }
+ const Referrer& referrer);
};
} // namespace content
diff --git a/chromium/content/public/common/renderer_preferences.cc b/chromium/content/public/common/renderer_preferences.cc
index a43b94398bb..e8af8b5dd11 100644
--- a/chromium/content/public/common/renderer_preferences.cc
+++ b/chromium/content/public/common/renderer_preferences.cc
@@ -31,13 +31,26 @@ RendererPreferences::RendererPreferences()
use_custom_colors(true),
enable_referrers(true),
enable_do_not_track(false),
+ enable_webrtc_multiple_routes(true),
default_zoom_level(0),
report_frame_name_changes(false),
tap_multiple_targets_strategy(TAP_MULTIPLE_TARGETS_STRATEGY_POPUP),
disable_client_blocked_error_page(false),
plugin_fullscreen_allowed(true),
- use_video_overlay_for_embedded_encrypted_video(false) {
-}
+ use_video_overlay_for_embedded_encrypted_video(false),
+ use_view_overlay_for_all_video(false)
+#if defined(OS_WIN)
+ , caption_font_height(0),
+ small_caption_font_height(0),
+ menu_font_height(0),
+ status_font_height(0),
+ message_font_height(0),
+ vertical_scroll_bar_width_in_dips(0),
+ horizontal_scroll_bar_height_in_dips(0),
+ arrow_bitmap_height_vertical_scroll_bar_in_dips(0),
+ arrow_bitmap_width_horizontal_scroll_bar_in_dips(0)
+#endif
+{}
RendererPreferences::~RendererPreferences() { }
diff --git a/chromium/content/public/common/renderer_preferences.h b/chromium/content/public/common/renderer_preferences.h
index cb13db7908b..13dd30fb3b9 100644
--- a/chromium/content/public/common/renderer_preferences.h
+++ b/chromium/content/public/common/renderer_preferences.h
@@ -15,6 +15,7 @@
#include <string>
#include <vector>
+#include "base/strings/string16.h"
#include "content/common/content_export.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/font_render_params.h"
@@ -53,7 +54,7 @@ struct CONTENT_EXPORT RendererPreferences {
bool use_bitmaps;
// The type of subpixel rendering to use for text.
- // Currently only used by Linux.
+ // Currently only used by Linux and Windows.
gfx::FontRenderParams::SubpixelRendering subpixel_rendering;
// Whether subpixel positioning should be used, permitting fractional X
@@ -95,6 +96,9 @@ struct CONTENT_EXPORT RendererPreferences {
// Set to true to indicate that the preference to set DNT to 1 is enabled.
bool enable_do_not_track;
+ // Set to false to indicate that WebRTC should use the OS default routing.
+ bool enable_webrtc_multiple_routes;
+
// Default page zoom level.
double default_zoom_level;
@@ -126,6 +130,45 @@ struct CONTENT_EXPORT RendererPreferences {
// Whether video-overlay (hole-punching) should be used for the embedded
// encrypted video. Currently only used by Android.
bool use_video_overlay_for_embedded_encrypted_video;
+
+ // Use video-overlay (hole-punching) should be used for all video, not just
+ // encrypted video. Currently only used by Android.
+ bool use_view_overlay_for_all_video;
+
+ // Country iso of the mobile network for content detection purpose.
+ std::string network_contry_iso;
+
+#if defined(OS_WIN)
+ // The default system font settings for caption, small caption, menu and
+ // status messages. Used only by Windows.
+ base::string16 caption_font_family_name;
+ int32 caption_font_height;
+
+ base::string16 small_caption_font_family_name;
+ int32 small_caption_font_height;
+
+ base::string16 menu_font_family_name;
+ int32 menu_font_height;
+
+ base::string16 status_font_family_name;
+ int32 status_font_height;
+
+ base::string16 message_font_family_name;
+ int32 message_font_height;
+
+ // The width of a vertical scroll bar in dips.
+ int32 vertical_scroll_bar_width_in_dips;
+
+ // The height of a horizontal scroll bar in dips.
+ int32 horizontal_scroll_bar_height_in_dips;
+
+ // The height of the arrow bitmap on a vertical scroll bar in dips.
+ int32 arrow_bitmap_height_vertical_scroll_bar_in_dips;
+
+ // The width of the arrow bitmap on a horizontal scroll bar in dips.
+ int32 arrow_bitmap_width_horizontal_scroll_bar_in_dips;
+#endif
+
};
} // namespace content
diff --git a/chromium/content/public/common/resource_devtools_info.h b/chromium/content/public/common/resource_devtools_info.h
index 8c1e8e3433e..bf17b1b6a82 100644
--- a/chromium/content/public/common/resource_devtools_info.h
+++ b/chromium/content/public/common/resource_devtools_info.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_COMMON_RESOURCE_DEVTOOLS_INFO_H_
-#define CONTENT_COMMON_RESOURCE_DEVTOOLS_INFO_H_
+#ifndef CONTENT_PUBLIC_COMMON_RESOURCE_DEVTOOLS_INFO_H_
+#define CONTENT_PUBLIC_COMMON_RESOURCE_DEVTOOLS_INFO_H_
#include <string>
#include <vector>
@@ -38,4 +38,4 @@ struct ResourceDevToolsInfo : base::RefCounted<ResourceDevToolsInfo> {
} // namespace content
-#endif // CONTENT_COMMON_RESOURCE_DEVTOOLS_INFO_H_
+#endif // CONTENT_PUBLIC_COMMON_RESOURCE_DEVTOOLS_INFO_H_
diff --git a/chromium/content/public/common/resource_response.cc b/chromium/content/public/common/resource_response.cc
index 92abfba8e3c..e362f329a50 100644
--- a/chromium/content/public/common/resource_response.cc
+++ b/chromium/content/public/common/resource_response.cc
@@ -31,7 +31,7 @@ scoped_refptr<ResourceResponse> ResourceResponse::DeepCopy() const {
new_response->head.was_fetched_via_spdy = head.was_fetched_via_spdy;
new_response->head.was_npn_negotiated = head.was_npn_negotiated;
new_response->head.was_alternate_protocol_available =
- new_response->head.was_alternate_protocol_available;
+ head.was_alternate_protocol_available;
new_response->head.connection_info = head.connection_info;
new_response->head.was_fetched_via_proxy = head.was_fetched_via_proxy;
new_response->head.proxy_server = head.proxy_server;
diff --git a/chromium/content/public/common/resource_type.h b/chromium/content/public/common/resource_type.h
index f71d953df4e..a77787ccd3f 100644
--- a/chromium/content/public/common/resource_type.h
+++ b/chromium/content/public/common/resource_type.h
@@ -9,26 +9,26 @@
namespace content {
-// Used in histograms, so please add new types at the end, and rename unused
-// entries to RESOURCETYPE_UNUSED_0, etc...
+// Used in histograms; explicitly assign each type and do not re-use old values.
enum ResourceType {
- RESOURCE_TYPE_MAIN_FRAME = 0, // top level page
- RESOURCE_TYPE_SUB_FRAME, // frame or iframe
- RESOURCE_TYPE_STYLESHEET, // a CSS stylesheet
- RESOURCE_TYPE_SCRIPT, // an external script
- RESOURCE_TYPE_IMAGE, // an image (jpg/gif/png/etc)
- RESOURCE_TYPE_FONT_RESOURCE, // a font
- RESOURCE_TYPE_SUB_RESOURCE, // an "other" subresource.
- RESOURCE_TYPE_OBJECT, // an object (or embed) tag for a plugin,
- // or a resource that a plugin requested.
- RESOURCE_TYPE_MEDIA, // a media resource.
- RESOURCE_TYPE_WORKER, // the main resource of a dedicated worker.
- RESOURCE_TYPE_SHARED_WORKER, // the main resource of a shared worker.
- RESOURCE_TYPE_PREFETCH, // an explicitly requested prefetch
- RESOURCE_TYPE_FAVICON, // a favicon
- RESOURCE_TYPE_XHR, // a XMLHttpRequest
- RESOURCE_TYPE_PING, // a ping request for <a ping>
- RESOURCE_TYPE_SERVICE_WORKER, // the main resource of a service worker.
+ RESOURCE_TYPE_MAIN_FRAME = 0, // top level page
+ RESOURCE_TYPE_SUB_FRAME = 1, // frame or iframe
+ RESOURCE_TYPE_STYLESHEET = 2, // a CSS stylesheet
+ RESOURCE_TYPE_SCRIPT = 3, // an external script
+ RESOURCE_TYPE_IMAGE = 4, // an image (jpg/gif/png/etc)
+ RESOURCE_TYPE_FONT_RESOURCE = 5, // a font
+ RESOURCE_TYPE_SUB_RESOURCE = 6, // an "other" subresource.
+ RESOURCE_TYPE_OBJECT = 7, // an object (or embed) tag for a plugin,
+ // or a resource that a plugin requested.
+ RESOURCE_TYPE_MEDIA = 8, // a media resource.
+ RESOURCE_TYPE_WORKER = 9, // the main resource of a dedicated
+ // worker.
+ RESOURCE_TYPE_SHARED_WORKER = 10, // the main resource of a shared worker.
+ RESOURCE_TYPE_PREFETCH = 11, // an explicitly requested prefetch
+ RESOURCE_TYPE_FAVICON = 12, // a favicon
+ RESOURCE_TYPE_XHR = 13, // a XMLHttpRequest
+ RESOURCE_TYPE_PING = 14, // a ping request for <a ping>
+ RESOURCE_TYPE_SERVICE_WORKER = 15, // the main resource of a service worker.
RESOURCE_TYPE_LAST_TYPE
};
diff --git a/chromium/content/public/common/sandbox_init.h b/chromium/content/public/common/sandbox_init.h
index 4173d9afe4d..6f4b19c9ea4 100644
--- a/chromium/content/public/common/sandbox_init.h
+++ b/chromium/content/public/common/sandbox_init.h
@@ -5,6 +5,7 @@
#ifndef CONTENT_PUBLIC_COMMON_SANDBOX_INIT_H_
#define CONTENT_PUBLIC_COMMON_SANDBOX_INIT_H_
+#include "base/files/scoped_file.h"
#include "base/memory/scoped_ptr.h"
#include "base/process/process.h"
#include "build/build_config.h"
@@ -27,7 +28,7 @@ class SandboxedProcessLauncherDelegate;
#if defined(OS_WIN)
-// Initialize the sandbox for renderer, gpu, utility, worker, nacl, and plug-in
+// Initialize the sandbox for renderer, gpu, utility, worker, nacl, and plugin
// processes, depending on the command line flags. Although The browser process
// is not sandboxed, this also needs to be called because it will initialize
// the broker code.
@@ -58,7 +59,7 @@ CONTENT_EXPORT bool BrokerAddTargetPeer(HANDLE peer_process);
// Launch a sandboxed process. |delegate| may be NULL. If |delegate| is non-NULL
// then it just has to outlive this method call.
-CONTENT_EXPORT base::ProcessHandle StartSandboxedProcess(
+CONTENT_EXPORT base::Process StartSandboxedProcess(
SandboxedProcessLauncherDelegate* delegate,
base::CommandLine* cmd_line);
@@ -81,20 +82,23 @@ CONTENT_EXPORT base::ProcessHandle StartSandboxedProcess(
CONTENT_EXPORT bool InitializeSandbox(int sandbox_type,
const base::FilePath& allowed_path);
-#elif defined(OS_LINUX)
+#elif defined(OS_LINUX) || defined(OS_NACL_NONSFI)
class SandboxInitializerDelegate;
// Initialize a seccomp-bpf sandbox. |policy| may not be NULL.
+// If an existing layer of sandboxing is present that would prevent access to
+// /proc, |proc_fd| must be a valid file descriptor to /proc/.
// Returns true if the sandbox has been properly engaged.
CONTENT_EXPORT bool InitializeSandbox(
- scoped_ptr<sandbox::bpf_dsl::Policy> policy);
+ scoped_ptr<sandbox::bpf_dsl::Policy> policy,
+ base::ScopedFD proc_fd);
// Return a "baseline" policy. This is used by a SandboxInitializerDelegate to
// implement a policy that is derived from the baseline.
CONTENT_EXPORT scoped_ptr<sandbox::bpf_dsl::Policy>
GetBPFSandboxBaselinePolicy();
-#endif // defined(OS_LINUX)
+#endif // defined(OS_LINUX) || defined(OS_NACL_NONSFI)
} // namespace content
diff --git a/chromium/content/public/common/sandbox_linux.h b/chromium/content/public/common/sandbox_linux.h
index a9be3b5470e..acee4037e74 100644
--- a/chromium/content/public/common/sandbox_linux.h
+++ b/chromium/content/public/common/sandbox_linux.h
@@ -14,10 +14,10 @@ enum LinuxSandboxStatus {
// SUID sandbox active.
kSandboxLinuxSUID = 1 << 0,
- // SUID sandbox is using the PID namespace.
+ // Sandbox is using a new PID namespace.
kSandboxLinuxPIDNS = 1 << 1,
- // SUID sandbox is using the network namespace.
+ // Sandbox is using a new network namespace.
kSandboxLinuxNetNS = 1 << 2,
// seccomp-bpf sandbox active.
@@ -26,6 +26,12 @@ enum LinuxSandboxStatus {
// The Yama LSM module is present and enforcing.
kSandboxLinuxYama = 1 << 4,
+ // seccomp-bpf sandbox is active and the kernel supports TSYNC.
+ kSandboxLinuxSeccompTSYNC = 1 << 5,
+
+ // User namespace sandbox active.
+ kSandboxLinuxUserNS = 1 << 6,
+
// A flag that denotes an invalid sandbox status.
kSandboxLinuxInvalid = 1 << 31,
};
diff --git a/chromium/content/public/common/send_zygote_child_ping_linux.h b/chromium/content/public/common/send_zygote_child_ping_linux.h
new file mode 100644
index 00000000000..ae971a1b290
--- /dev/null
+++ b/chromium/content/public/common/send_zygote_child_ping_linux.h
@@ -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.
+
+#ifndef CONTENT_PUBLIC_COMMON_SEND_ZYGOTE_CHILD_PING_LINUX_H_
+#define CONTENT_PUBLIC_COMMON_SEND_ZYGOTE_CHILD_PING_LINUX_H_
+
+#include "content/common/content_export.h"
+
+namespace content {
+
+// Sends a zygote child "ping" message to browser process via socket |fd|.
+// Returns true on success.
+CONTENT_EXPORT bool SendZygoteChildPing(int fd);
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_COMMON_SEND_ZYGOTE_CHILD_PING_LINUX_H_
diff --git a/chromium/content/public/common/service_registry.h b/chromium/content/public/common/service_registry.h
index be2294ee53e..2d65cf9ee93 100644
--- a/chromium/content/public/common/service_registry.h
+++ b/chromium/content/public/common/service_registry.h
@@ -11,9 +11,9 @@
#include "base/callback.h"
#include "base/strings/string_piece.h"
#include "content/common/content_export.h"
-#include "mojo/public/cpp/bindings/interface_ptr.h"
-#include "mojo/public/cpp/bindings/interface_request.h"
-#include "mojo/public/cpp/system/core.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/interface_ptr.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h"
+#include "third_party/mojo/src/mojo/public/cpp/system/core.h"
namespace content {
@@ -54,9 +54,8 @@ class CONTENT_EXPORT ServiceRegistry {
// Connect to an interface provided by the remote service provider.
template <typename Interface>
void ConnectToRemoteService(mojo::InterfacePtr<Interface>* ptr) {
- mojo::MessagePipe pipe;
- ptr->Bind(pipe.handle0.Pass());
- ConnectToRemoteService(Interface::Name_, pipe.handle1.Pass());
+ ConnectToRemoteService(Interface::Name_,
+ mojo::GetProxy(ptr).PassMessagePipe());
}
virtual void ConnectToRemoteService(const base::StringPiece& name,
mojo::ScopedMessagePipeHandle handle) = 0;
diff --git a/chromium/content/public/common/show_desktop_notification_params.cc b/chromium/content/public/common/show_desktop_notification_params.cc
deleted file mode 100644
index f001f79eeab..00000000000
--- a/chromium/content/public/common/show_desktop_notification_params.cc
+++ /dev/null
@@ -1,16 +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/public/common/show_desktop_notification_params.h"
-
-namespace content {
-
-ShowDesktopNotificationHostMsgParams::ShowDesktopNotificationHostMsgParams()
- : direction(blink::WebTextDirectionDefault) {
-}
-
-ShowDesktopNotificationHostMsgParams::~ShowDesktopNotificationHostMsgParams() {
-}
-
-} // namespace content
diff --git a/chromium/content/public/common/show_desktop_notification_params.h b/chromium/content/public/common/show_desktop_notification_params.h
deleted file mode 100644
index c601654409a..00000000000
--- a/chromium/content/public/common/show_desktop_notification_params.h
+++ /dev/null
@@ -1,39 +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_PUBLIC_COMMON_SHOW_DESKTOP_NOTIFICATION_PARAMS_H_
-#define CONTENT_PUBLIC_COMMON_SHOW_DESKTOP_NOTIFICATION_PARAMS_H_
-
-#include "content/common/content_export.h"
-#include "third_party/WebKit/public/web/WebTextDirection.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "url/gurl.h"
-
-namespace content {
-
-// Parameters used when showing an HTML5 notification.
-struct CONTENT_EXPORT ShowDesktopNotificationHostMsgParams {
- ShowDesktopNotificationHostMsgParams();
- ~ShowDesktopNotificationHostMsgParams();
-
- // URL which is the origin that created this notification.
- GURL origin;
-
- // Image to be displayed as part of the notification.
- SkBitmap icon;
-
- base::string16 title;
- base::string16 body;
-
- // Directionality of the notification.
- blink::WebTextDirection direction;
-
- // ReplaceID if this notification should replace an existing one; may be
- // empty if no replacement is called for.
- base::string16 replace_id;
-};
-
-} // namespace content
-
-#endif // CONTENT_PUBLIC_COMMON_SHOW_DESKTOP_NOTIFICATION_PARAMS_H_
diff --git a/chromium/content/public/common/socket_permission_request.h b/chromium/content/public/common/socket_permission_request.h
index b7b4389b9b4..3db53b3699a 100644
--- a/chromium/content/public/common/socket_permission_request.h
+++ b/chromium/content/public/common/socket_permission_request.h
@@ -7,6 +7,8 @@
#include <string>
+#include "base/basictypes.h"
+
namespace content {
// This module provides helper types for checking socket permission.
@@ -27,7 +29,7 @@ struct SocketPermissionRequest {
SocketPermissionRequest(OperationType type,
const std::string& host,
- int port)
+ uint16 port)
: type(type),
host(host),
port(port) {
@@ -35,7 +37,7 @@ struct SocketPermissionRequest {
OperationType type;
std::string host;
- int port;
+ uint16 port;
};
} // namespace content
diff --git a/chromium/content/public/common/speech_recognition_error.h b/chromium/content/public/common/speech_recognition_error.h
index bbd73c7494c..7456a43f204 100644
--- a/chromium/content/public/common/speech_recognition_error.h
+++ b/chromium/content/public/common/speech_recognition_error.h
@@ -14,11 +14,14 @@ enum SpeechRecognitionErrorCode {
// There was no error.
SPEECH_RECOGNITION_ERROR_NONE,
+ // No speech heard before timeout.
+ SPEECH_RECOGNITION_ERROR_NO_SPEECH,
+
// The user or a script aborted speech input.
SPEECH_RECOGNITION_ERROR_ABORTED,
// There was an error with recording audio.
- SPEECH_RECOGNITION_ERROR_AUDIO,
+ SPEECH_RECOGNITION_ERROR_AUDIO_CAPTURE,
// There was a network error.
SPEECH_RECOGNITION_ERROR_NETWORK,
@@ -26,15 +29,19 @@ enum SpeechRecognitionErrorCode {
// Not allowed for privacy or security reasons.
SPEECH_RECOGNITION_ERROR_NOT_ALLOWED,
- // No speech heard before timeout.
- SPEECH_RECOGNITION_ERROR_NO_SPEECH,
+ // Speech service is not allowed for privacy or security reasons.
+ SPEECH_RECOGNITION_ERROR_SERVICE_NOT_ALLOWED,
+
+ // There was an error in the speech recognition grammar.
+ SPEECH_RECOGNITION_ERROR_BAD_GRAMMAR,
+
+ // The language was not supported.
+ SPEECH_RECOGNITION_ERROR_LANGUAGE_NOT_SUPPORTED,
// Speech was heard, but could not be interpreted.
SPEECH_RECOGNITION_ERROR_NO_MATCH,
- // There was an error in the speech recognition grammar.
- SPEECH_RECOGNITION_ERROR_BAD_GRAMMAR,
- SPEECH_RECOGNITION_ERROR_LAST = SPEECH_RECOGNITION_ERROR_BAD_GRAMMAR,
+ SPEECH_RECOGNITION_ERROR_LAST = SPEECH_RECOGNITION_ERROR_NO_MATCH,
};
// Error details for the SPEECH_RECOGNITION_ERROR_AUDIO error.
diff --git a/chromium/content/public/common/top_controls_state.h b/chromium/content/public/common/top_controls_state.h
index 7f71e6e451a..4223b63641a 100644
--- a/chromium/content/public/common/top_controls_state.h
+++ b/chromium/content/public/common/top_controls_state.h
@@ -13,6 +13,8 @@ enum TopControlsState {
TOP_CONTROLS_STATE_SHOWN = 1,
TOP_CONTROLS_STATE_HIDDEN = 2,
TOP_CONTROLS_STATE_BOTH = 3,
+
+ TOP_CONTROLS_STATE_LAST = TOP_CONTROLS_STATE_BOTH,
};
} // namespace content
diff --git a/chromium/content/public/common/transition_element.h b/chromium/content/public/common/transition_element.h
index d8168b8ccf5..a21fdc094eb 100644
--- a/chromium/content/public/common/transition_element.h
+++ b/chromium/content/public/common/transition_element.h
@@ -14,7 +14,7 @@ namespace content {
// This struct stores the information of one transition element.
struct CONTENT_EXPORT TransitionElement {
- std::string name;
+ std::string id;
gfx::Rect rect;
};
diff --git a/chromium/content/public/common/url_constants.cc b/chromium/content/public/common/url_constants.cc
index fb7d9d64299..6ecc6f3e889 100644
--- a/chromium/content/public/common/url_constants.cc
+++ b/chromium/content/public/common/url_constants.cc
@@ -36,6 +36,7 @@ const char kChromeUITracingHost[] = "tracing";
const char kChromeUIWebRTCInternalsHost[] = "webrtc-internals";
const char kChromeUIBrowserCrashURL[] = "chrome://inducebrowsercrashforrealz";
+const char kChromeUIBrowserUIHang[] = "chrome://uithreadhang";
const char kChromeUICrashURL[] = "chrome://crash";
const char kChromeUIDumpURL[] = "chrome://crashdump";
const char kChromeUIGpuCleanURL[] = "chrome://gpuclean";
diff --git a/chromium/content/public/common/url_constants.h b/chromium/content/public/common/url_constants.h
index d04328d8c49..3143cf85630 100644
--- a/chromium/content/public/common/url_constants.h
+++ b/chromium/content/public/common/url_constants.h
@@ -45,6 +45,7 @@ CONTENT_EXPORT extern const char kChromeUIWebRTCInternalsHost[];
// Full about URLs (including schemes).
CONTENT_EXPORT extern const char kChromeUIBrowserCrashURL[];
+CONTENT_EXPORT extern const char kChromeUIBrowserUIHang[];
CONTENT_EXPORT extern const char kChromeUICrashURL[];
CONTENT_EXPORT extern const char kChromeUIDumpURL[];
CONTENT_EXPORT extern const char kChromeUIGpuCleanURL[];
diff --git a/chromium/content/public/common/url_utils.cc b/chromium/content/public/common/url_utils.cc
index d2fb13bd0f7..f977df0e0f0 100644
--- a/chromium/content/public/common/url_utils.cc
+++ b/chromium/content/public/common/url_utils.cc
@@ -40,7 +40,7 @@ bool IsSavableURL(const GURL& url) {
#if defined(OS_ANDROID)
void SetMaxURLChars(size_t max_chars) {
// Check that it is not used by a multiprocesses embedder
- CommandLine* cmd = CommandLine::ForCurrentProcess();
+ base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
CHECK(cmd->HasSwitch(switches::kSingleProcess));
g_max_url_size = max_chars;
}
diff --git a/chromium/content/public/common/user_agent.h b/chromium/content/public/common/user_agent.h
index 0613678a3ba..107440e91de 100644
--- a/chromium/content/public/common/user_agent.h
+++ b/chromium/content/public/common/user_agent.h
@@ -28,6 +28,12 @@ CONTENT_EXPORT std::string BuildOSCpuInfo();
CONTENT_EXPORT std::string BuildUserAgentFromProduct(
const std::string& product);
+// Helper function to generate a full user agent string given a short
+// product name and some extra text to be added to the OS info.
+CONTENT_EXPORT std::string BuildUserAgentFromProductAndExtraOSInfo(
+ const std::string& product,
+ const std::string& extra_os_info);
+
// Builds a full user agent string given a string describing the OS and a
// product name.
CONTENT_EXPORT std::string BuildUserAgentFromOSAndProduct(
diff --git a/chromium/content/public/common/web_preferences.cc b/chromium/content/public/common/web_preferences.cc
index dbe16297f90..039a5ff0e4f 100644
--- a/chromium/content/public/common/web_preferences.cc
+++ b/chromium/content/public/common/web_preferences.cc
@@ -17,40 +17,68 @@ namespace content {
// "Zyyy" is the ISO 15924 script code for undetermined script aka Common.
const char kCommonScript[] = "Zyyy";
-#define COMPILE_ASSERT_MATCHING_ENUMS(content_name, blink_name) \
- COMPILE_ASSERT( \
+#define STATIC_ASSERT_MATCHING_ENUMS(content_name, blink_name) \
+ static_assert( \
static_cast<int>(content_name) == static_cast<int>(blink_name), \
- mismatching_enums)
+ "mismatching enums: " #content_name)
-COMPILE_ASSERT_MATCHING_ENUMS(EDITING_BEHAVIOR_MAC,
- WebSettings::EditingBehaviorMac);
-COMPILE_ASSERT_MATCHING_ENUMS(EDITING_BEHAVIOR_WIN,
- WebSettings::EditingBehaviorWin);
-COMPILE_ASSERT_MATCHING_ENUMS(EDITING_BEHAVIOR_UNIX,
- WebSettings::EditingBehaviorUnix);
-COMPILE_ASSERT_MATCHING_ENUMS(EDITING_BEHAVIOR_ANDROID,
- WebSettings::EditingBehaviorAndroid);
+STATIC_ASSERT_MATCHING_ENUMS(EDITING_BEHAVIOR_MAC,
+ WebSettings::EditingBehaviorMac);
+STATIC_ASSERT_MATCHING_ENUMS(EDITING_BEHAVIOR_WIN,
+ WebSettings::EditingBehaviorWin);
+STATIC_ASSERT_MATCHING_ENUMS(EDITING_BEHAVIOR_UNIX,
+ WebSettings::EditingBehaviorUnix);
+STATIC_ASSERT_MATCHING_ENUMS(EDITING_BEHAVIOR_ANDROID,
+ WebSettings::EditingBehaviorAndroid);
-COMPILE_ASSERT_MATCHING_ENUMS(V8_CACHE_OPTIONS_OFF,
- WebSettings::V8CacheOptionsOff);
-COMPILE_ASSERT_MATCHING_ENUMS(V8_CACHE_OPTIONS_PARSE,
- WebSettings::V8CacheOptionsParse);
-COMPILE_ASSERT_MATCHING_ENUMS(V8_CACHE_OPTIONS_CODE,
- WebSettings::V8CacheOptionsCode);
-COMPILE_ASSERT_MATCHING_ENUMS(V8_CACHE_OPTIONS_LAST,
- WebSettings::V8CacheOptionsCode);
+STATIC_ASSERT_MATCHING_ENUMS(V8_CACHE_OPTIONS_DEFAULT,
+ WebSettings::V8CacheOptionsDefault);
+STATIC_ASSERT_MATCHING_ENUMS(V8_CACHE_OPTIONS_PARSE,
+ WebSettings::V8CacheOptionsParse);
+STATIC_ASSERT_MATCHING_ENUMS(V8_CACHE_OPTIONS_CODE,
+ WebSettings::V8CacheOptionsCode);
+STATIC_ASSERT_MATCHING_ENUMS(V8_CACHE_OPTIONS_CODE_COMPRESSED,
+ WebSettings::V8CacheOptionsCodeCompressed);
+STATIC_ASSERT_MATCHING_ENUMS(V8_CACHE_OPTIONS_NONE,
+ WebSettings::V8CacheOptionsNone);
+STATIC_ASSERT_MATCHING_ENUMS(V8_CACHE_OPTIONS_PARSE_MEMORY,
+ WebSettings::V8CacheOptionsParseMemory);
+STATIC_ASSERT_MATCHING_ENUMS(V8_CACHE_OPTIONS_HEURISTICS,
+ WebSettings::V8CacheOptionsHeuristics);
+STATIC_ASSERT_MATCHING_ENUMS(V8_CACHE_OPTIONS_HEURISTICS_MOBILE,
+ WebSettings::V8CacheOptionsHeuristicsMobile);
+STATIC_ASSERT_MATCHING_ENUMS(V8_CACHE_OPTIONS_HEURISTICS_DEFAULT,
+ WebSettings::V8CacheOptionsHeuristicsDefault);
+STATIC_ASSERT_MATCHING_ENUMS(
+ V8_CACHE_OPTIONS_HEURISTICS_DEFAULT_MOBILE,
+ WebSettings::V8CacheOptionsHeuristicsDefaultMobile);
+STATIC_ASSERT_MATCHING_ENUMS(V8_CACHE_OPTIONS_RECENT,
+ WebSettings::V8CacheOptionsRecent);
+STATIC_ASSERT_MATCHING_ENUMS(V8_CACHE_OPTIONS_RECENT_SMALL,
+ WebSettings::V8CacheOptionsRecentSmall);
+STATIC_ASSERT_MATCHING_ENUMS(V8_CACHE_OPTIONS_LAST,
+ WebSettings::V8CacheOptionsRecentSmall);
-COMPILE_ASSERT_MATCHING_ENUMS(V8_SCRIPT_STREAMING_MODE_ALL,
- WebSettings::V8ScriptStreamingModeAll);
-COMPILE_ASSERT_MATCHING_ENUMS(
- V8_SCRIPT_STREAMING_MODE_ONLY_ASYNC_AND_DEFER,
- WebSettings::V8ScriptStreamingModeOnlyAsyncAndDefer);
-COMPILE_ASSERT_MATCHING_ENUMS(
- V8_SCRIPT_STREAMING_MODE_ALL_PLUS_BLOCK_PARSER_BLOCKING,
- WebSettings::V8ScriptStreamingModeAllPlusBlockParsingBlocking);
-COMPILE_ASSERT_MATCHING_ENUMS(
- V8_SCRIPT_STREAMING_MODE_LAST,
- WebSettings::V8ScriptStreamingModeAllPlusBlockParsingBlocking);
+STATIC_ASSERT_MATCHING_ENUMS(IMAGE_ANIMATION_POLICY_ALLOWED,
+ WebSettings::ImageAnimationPolicyAllowed);
+STATIC_ASSERT_MATCHING_ENUMS(IMAGE_ANIMATION_POLICY_ANIMATION_ONCE,
+ WebSettings::ImageAnimationPolicyAnimateOnce);
+STATIC_ASSERT_MATCHING_ENUMS(IMAGE_ANIMATION_POLICY_NO_ANIMATION,
+ WebSettings::ImageAnimationPolicyNoAnimation);
+
+STATIC_ASSERT_MATCHING_ENUMS(ui::POINTER_TYPE_NONE,
+ WebSettings::PointerTypeNone);
+STATIC_ASSERT_MATCHING_ENUMS(ui::POINTER_TYPE_COARSE,
+ WebSettings::PointerTypeCoarse);
+STATIC_ASSERT_MATCHING_ENUMS(ui::POINTER_TYPE_FINE,
+ WebSettings::PointerTypeFine);
+
+STATIC_ASSERT_MATCHING_ENUMS(ui::HOVER_TYPE_NONE,
+ WebSettings::HoverTypeNone);
+STATIC_ASSERT_MATCHING_ENUMS(ui::HOVER_TYPE_ON_DEMAND,
+ WebSettings::HoverTypeOnDemand);
+STATIC_ASSERT_MATCHING_ENUMS(ui::HOVER_TYPE_HOVER,
+ WebSettings::HoverTypeHover);
WebPreferences::WebPreferences()
: default_font_size(16),
@@ -58,6 +86,11 @@ WebPreferences::WebPreferences()
minimum_font_size(0),
minimum_logical_font_size(6),
default_encoding("ISO-8859-1"),
+#if defined(OS_WIN)
+ context_menu_on_mouse_up(true),
+#else
+ context_menu_on_mouse_up(false),
+#endif
javascript_enabled(true),
web_security_enabled(true),
javascript_can_open_windows_automatically(true),
@@ -95,7 +128,6 @@ WebPreferences::WebPreferences()
privileged_webgl_extensions_enabled(false),
webgl_errors_to_console_enabled(true),
mock_scrollbars_enabled(false),
- layer_squashing_enabled(true),
asynchronous_spell_checking_enabled(true),
unified_textchecker_enabled(false),
accelerated_2d_canvas_enabled(false),
@@ -109,6 +141,9 @@ WebPreferences::WebPreferences()
text_blobs_enabled(false),
allow_displaying_insecure_content(true),
allow_running_insecure_content(false),
+ disable_reading_from_canvas(false),
+ strict_mixed_content_checking(false),
+ strict_powerful_feature_restrictions(false),
password_echo_enabled(false),
should_print_backgrounds(false),
should_clear_document_background(true),
@@ -119,6 +154,10 @@ WebPreferences::WebPreferences()
device_supports_mouse(true),
touch_adjustment_enabled(true),
pointer_events_max_touch_points(0),
+ available_pointer_types(0),
+ primary_pointer_type(ui::POINTER_TYPE_NONE),
+ available_hover_types(0),
+ primary_hover_type(ui::HOVER_TYPE_NONE),
sync_xhr_in_documents_enabled(true),
deferred_image_decoding_enabled(false),
image_color_profiles_enabled(false),
@@ -150,14 +189,12 @@ WebPreferences::WebPreferences()
pinch_overlay_scrollbar_thickness(0),
use_solid_color_scrollbars(false),
navigate_on_drag_drop(true),
- v8_cache_options(V8_CACHE_OPTIONS_OFF),
- v8_script_streaming_enabled(false),
- v8_script_streaming_mode(V8_SCRIPT_STREAMING_MODE_ALL),
+ v8_cache_options(V8_CACHE_OPTIONS_DEFAULT),
slimming_paint_enabled(false),
cookie_enabled(true),
- pepper_accelerated_video_decode_enabled(false)
+ pepper_accelerated_video_decode_enabled(false),
+ animation_policy(IMAGE_ANIMATION_POLICY_ALLOWED),
#if defined(OS_ANDROID)
- ,
text_autosizing_enabled(true),
font_scale_factor(1.0f),
device_scale_adjustment(1.0f),
@@ -176,7 +213,17 @@ WebPreferences::WebPreferences()
viewport_meta_zero_values_quirk(false),
clobber_user_agent_initial_scale_quirk(false),
ignore_main_frame_overflow_hidden_quirk(false),
- report_screen_size_in_physical_pixels_quirk(false)
+ report_screen_size_in_physical_pixels_quirk(false),
+#endif
+#if defined(OS_ANDROID)
+ default_minimum_page_scale_factor(0.25f),
+ default_maximum_page_scale_factor(5.f)
+#elif defined(OS_MACOSX)
+ default_minimum_page_scale_factor(1.f),
+ default_maximum_page_scale_factor(3.f)
+#else
+ default_minimum_page_scale_factor(1.f),
+ default_maximum_page_scale_factor(4.f)
#endif
{
standard_font_family_map[kCommonScript] =
diff --git a/chromium/content/public/common/web_preferences.h b/chromium/content/public/common/web_preferences.h
index 057174fef62..8d25487b9a2 100644
--- a/chromium/content/public/common/web_preferences.h
+++ b/chromium/content/public/common/web_preferences.h
@@ -12,6 +12,7 @@
#include "base/strings/string16.h"
#include "content/common/content_export.h"
#include "net/base/network_change_notifier.h"
+#include "ui/base/touch/touch_device.h"
#include "url/gurl.h"
namespace blink {
@@ -32,19 +33,31 @@ enum EditingBehavior {
EDITING_BEHAVIOR_LAST = EDITING_BEHAVIOR_ANDROID
};
+// Cache options for V8. See V8CacheOptions.h for information on the options.
enum V8CacheOptions {
- V8_CACHE_OPTIONS_OFF,
+ V8_CACHE_OPTIONS_DEFAULT,
V8_CACHE_OPTIONS_PARSE,
V8_CACHE_OPTIONS_CODE,
- V8_CACHE_OPTIONS_LAST = V8_CACHE_OPTIONS_CODE
+ V8_CACHE_OPTIONS_CODE_COMPRESSED,
+ V8_CACHE_OPTIONS_NONE,
+ V8_CACHE_OPTIONS_PARSE_MEMORY,
+ V8_CACHE_OPTIONS_HEURISTICS,
+ V8_CACHE_OPTIONS_HEURISTICS_MOBILE,
+ V8_CACHE_OPTIONS_HEURISTICS_DEFAULT,
+ V8_CACHE_OPTIONS_HEURISTICS_DEFAULT_MOBILE,
+ V8_CACHE_OPTIONS_RECENT,
+ V8_CACHE_OPTIONS_RECENT_SMALL,
+ V8_CACHE_OPTIONS_LAST = V8_CACHE_OPTIONS_RECENT_SMALL
};
-enum V8ScriptStreamingMode {
- V8_SCRIPT_STREAMING_MODE_ALL,
- V8_SCRIPT_STREAMING_MODE_ONLY_ASYNC_AND_DEFER,
- V8_SCRIPT_STREAMING_MODE_ALL_PLUS_BLOCK_PARSER_BLOCKING,
- V8_SCRIPT_STREAMING_MODE_LAST =
- V8_SCRIPT_STREAMING_MODE_ALL_PLUS_BLOCK_PARSER_BLOCKING
+// ImageAnimationPolicy is used for controlling image animation
+// when image frame is rendered for animation.
+// See third_party/WebKit/Source/platform/graphics/ImageAnimationPolicy.h
+// for information on the options.
+enum ImageAnimationPolicy {
+ IMAGE_ANIMATION_POLICY_ALLOWED,
+ IMAGE_ANIMATION_POLICY_ANIMATION_ONCE,
+ IMAGE_ANIMATION_POLICY_NO_ANIMATION
};
// The ISO 15924 script code for undetermined script aka Common. It's the
@@ -70,6 +83,7 @@ struct CONTENT_EXPORT WebPreferences {
int minimum_font_size;
int minimum_logical_font_size;
std::string default_encoding;
+ bool context_menu_on_mouse_up;
bool javascript_enabled;
bool web_security_enabled;
bool javascript_can_open_windows_automatically;
@@ -110,7 +124,6 @@ struct CONTENT_EXPORT WebPreferences {
bool privileged_webgl_extensions_enabled;
bool webgl_errors_to_console_enabled;
bool mock_scrollbars_enabled;
- bool layer_squashing_enabled;
bool asynchronous_spell_checking_enabled;
bool unified_textchecker_enabled;
bool accelerated_2d_canvas_enabled;
@@ -124,6 +137,16 @@ struct CONTENT_EXPORT WebPreferences {
bool text_blobs_enabled;
bool allow_displaying_insecure_content;
bool allow_running_insecure_content;
+ // If true, taints all <canvas> elements, regardless of origin.
+ bool disable_reading_from_canvas;
+ // Strict mixed content checking disables both displaying and running insecure
+ // mixed content, and disables embedder notifications that such content was
+ // requested (thereby preventing user override).
+ bool strict_mixed_content_checking;
+ // Strict powerful feature restrictions block insecure usage of powerful
+ // features (like geolocation) that we haven't yet disabled for the web at
+ // large.
+ bool strict_powerful_feature_restrictions;
bool password_echo_enabled;
bool should_print_backgrounds;
bool should_clear_document_background;
@@ -131,10 +154,16 @@ struct CONTENT_EXPORT WebPreferences {
bool css_variables_enabled;
bool region_based_columns_enabled;
bool touch_enabled;
+ // TODO(mustaq): Nuke when the new API is ready
bool device_supports_touch;
+ // TODO(mustaq): Nuke when the new API is ready
bool device_supports_mouse;
bool touch_adjustment_enabled;
int pointer_events_max_touch_points;
+ int available_pointer_types;
+ ui::PointerType primary_pointer_type;
+ int available_hover_types;
+ ui::HoverType primary_hover_type;
bool sync_xhr_in_documents_enabled;
bool deferred_image_decoding_enabled;
bool image_color_profiles_enabled;
@@ -153,8 +182,6 @@ struct CONTENT_EXPORT WebPreferences {
bool use_solid_color_scrollbars;
bool navigate_on_drag_drop;
V8CacheOptions v8_cache_options;
- bool v8_script_streaming_enabled;
- V8ScriptStreamingMode v8_script_streaming_mode;
bool slimming_paint_enabled;
// This flags corresponds to a Page's Settings' setCookieEnabled state. It
@@ -168,6 +195,8 @@ struct CONTENT_EXPORT WebPreferences {
// pepper plugins. Defaults to false.
bool pepper_accelerated_video_decode_enabled;
+ ImageAnimationPolicy animation_policy;
+
#if defined(OS_ANDROID)
bool text_autosizing_enabled;
float font_scale_factor;
@@ -191,6 +220,12 @@ struct CONTENT_EXPORT WebPreferences {
bool report_screen_size_in_physical_pixels_quirk;
#endif
+ // Default (used if the page or UA doesn't override these) values for page
+ // scale limits. These are set directly on the WebView so there's no analogue
+ // in WebSettings.
+ float default_minimum_page_scale_factor;
+ float default_maximum_page_scale_factor;
+
// We try to keep the default values the same as the default values in
// chrome, except for the cases where it would require lots of extra work for
// the embedder to use the same default value.
diff --git a/chromium/content/public/common/webplugininfo.h b/chromium/content/public/common/webplugininfo.h
index 2912cefb331..b21b9ea99f9 100644
--- a/chromium/content/public/common/webplugininfo.h
+++ b/chromium/content/public/common/webplugininfo.h
@@ -47,7 +47,6 @@ struct CONTENT_EXPORT WebPluginInfo {
PLUGIN_TYPE_NPAPI,
PLUGIN_TYPE_PEPPER_IN_PROCESS,
PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS,
- PLUGIN_TYPE_PEPPER_UNSANDBOXED,
PLUGIN_TYPE_BROWSER_PLUGIN
};
@@ -64,11 +63,10 @@ struct CONTENT_EXPORT WebPluginInfo {
bool is_pepper_plugin() const {
return ((type == PLUGIN_TYPE_PEPPER_IN_PROCESS ) ||
- (type == PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS) ||
- (type == PLUGIN_TYPE_PEPPER_UNSANDBOXED));
+ (type == PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS));
}
- // Parse a version string as used by a plug-in. This method is more lenient
+ // Parse a version string as used by a plugin. This method is more lenient
// in accepting weird version strings than base::Version::GetFromString()
static void CreateVersionFromString(const base::string16& version_string,
base::Version* parsed_version);
diff --git a/chromium/content/public/common/window_container_type.h b/chromium/content/public/common/window_container_type.h
index 1d3b46fe6b1..3c9e728f959 100644
--- a/chromium/content/public/common/window_container_type.h
+++ b/chromium/content/public/common/window_container_type.h
@@ -25,7 +25,7 @@ enum WindowContainerType {
// reference it.
WINDOW_CONTAINER_TYPE_PERSISTENT,
- WINDOW_CONTAINER_TYPE_MAX_VALUE
+ WINDOW_CONTAINER_TYPE_MAX_VALUE = WINDOW_CONTAINER_TYPE_PERSISTENT,
};
// Conversion function:
diff --git a/chromium/content/public/plugin/BUILD.gn b/chromium/content/public/plugin/BUILD.gn
index c43de9bd3e8..e4c4d368193 100644
--- a/chromium/content/public/plugin/BUILD.gn
+++ b/chromium/content/public/plugin/BUILD.gn
@@ -5,9 +5,13 @@
# See //content/BUILD.gn for how this works.
group("plugin") {
if (is_component_build) {
- public_deps = [ "//content" ]
+ public_deps = [
+ "//content",
+ ]
} else {
- public_deps = [ ":plugin_sources" ]
+ public_deps = [
+ ":plugin_sources",
+ ]
}
}
diff --git a/chromium/content/public/renderer/BUILD.gn b/chromium/content/public/renderer/BUILD.gn
index 3a5070b65b9..0ab2d33a7ff 100644
--- a/chromium/content/public/renderer/BUILD.gn
+++ b/chromium/content/public/renderer/BUILD.gn
@@ -8,9 +8,13 @@ import("//content/renderer/renderer.gni")
# See //content/BUILD.gn for how this works.
group("renderer") {
if (is_component_build) {
- public_deps = [ "//content" ]
+ public_deps = [
+ "//content",
+ ]
} else {
- public_deps = [ ":renderer_sources" ]
+ public_deps = [
+ ":renderer_sources",
+ ]
}
}
@@ -18,11 +22,10 @@ source_set("renderer_sources") {
visibility = [ "//content/*" ]
sources = rebase_path(content_renderer_gypi_values.public_renderer_sources,
- ".", "//content")
+ ".",
+ "//content")
- configs += [
- "//content:content_implementation",
- ]
+ configs += [ "//content:content_implementation" ]
deps = [
"//content/public/common:common_sources",
@@ -42,8 +45,17 @@ source_set("renderer_sources") {
]
if (enable_webrtc) {
- sources += rebase_path(
- content_renderer_gypi_values.public_renderer_webrtc_sources,
- ".", "//content")
+ sources +=
+ rebase_path(content_renderer_gypi_values.public_renderer_webrtc_sources,
+ ".",
+ "//content")
+ deps += [ "//third_party/webrtc" ]
+ }
+
+ if (enable_plugins) {
+ sources +=
+ rebase_path(content_renderer_gypi_values.public_renderer_plugin_sources,
+ ".",
+ "//content")
}
}
diff --git a/chromium/content/public/renderer/DEPS b/chromium/content/public/renderer/DEPS
index 11f2420efb5..b80961c0192 100644
--- a/chromium/content/public/renderer/DEPS
+++ b/chromium/content/public/renderer/DEPS
@@ -1,5 +1,7 @@
include_rules = [
- "+media/filters",
+ "+content/public/child",
+ "+media/base",
+ "+media/renderers",
"+media/video",
"+v8/include/v8.h",
]
diff --git a/chromium/content/public/renderer/browser_plugin_delegate.cc b/chromium/content/public/renderer/browser_plugin_delegate.cc
new file mode 100644
index 00000000000..dd0eafcc421
--- /dev/null
+++ b/chromium/content/public/renderer/browser_plugin_delegate.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/public/renderer/browser_plugin_delegate.h"
+
+#include "v8/include/v8.h"
+
+namespace content {
+
+bool BrowserPluginDelegate::OnMessageReceived(const IPC::Message& message) {
+ return false;
+}
+
+v8::Local<v8::Object> BrowserPluginDelegate::V8ScriptableObject(
+ v8::Isolate* isolate) {
+ return v8::Local<v8::Object>();
+}
+
+} // namespace content
diff --git a/chromium/content/public/renderer/browser_plugin_delegate.h b/chromium/content/public/renderer/browser_plugin_delegate.h
index 282adda24a4..de6e46d670b 100644
--- a/chromium/content/public/renderer/browser_plugin_delegate.h
+++ b/chromium/content/public/renderer/browser_plugin_delegate.h
@@ -8,6 +8,17 @@
#include <string>
#include "content/common/content_export.h"
+#include "ipc/ipc_message.h"
+
+namespace gfx {
+class Size;
+}
+
+namespace v8 {
+class Isolate;
+class Object;
+template<typename T> class Local;
+} // namespace v8
namespace content {
@@ -33,6 +44,16 @@ class CONTENT_EXPORT BrowserPluginDelegate {
// Sets the instance ID that idenfies the plugin within current render
// process.
virtual void SetElementInstanceID(int element_instance_id) {}
+
+ // Called when the plugin resizes.
+ virtual void DidResizeElement(const gfx::Size& new_size) {}
+
+ // Called when a message is received. Returns true iff the message was
+ // handled.
+ virtual bool OnMessageReceived(const IPC::Message& message);
+
+ // Return a scriptable object for the plugin.
+ virtual v8::Local<v8::Object> V8ScriptableObject(v8::Isolate* isolate);
};
} // namespace content
diff --git a/chromium/content/public/renderer/content_renderer_client.cc b/chromium/content/public/renderer/content_renderer_client.cc
index ca1b9fe536f..df391b644c1 100644
--- a/chromium/content/public/renderer/content_renderer_client.cc
+++ b/chromium/content/public/renderer/content_renderer_client.cc
@@ -4,6 +4,8 @@
#include "content/public/renderer/content_renderer_client.h"
+#include "media/base/renderer_factory.h"
+#include "third_party/WebKit/public/platform/modules/app_banner/WebAppBannerClient.h"
#include "third_party/WebKit/public/web/WebPluginPlaceholder.h"
namespace content {
@@ -121,6 +123,11 @@ bool ContentRendererClient::ShouldFork(blink::WebFrame* frame,
return false;
}
+bool ContentRendererClient::ShouldForwardToGuestContainer(
+ const IPC::Message& msg) {
+ return false;
+}
+
bool ContentRendererClient::WillSendRequest(
blink::WebFrame* frame,
ui::PageTransition transition_type,
@@ -168,6 +175,13 @@ void ContentRendererClient::AddKeySystems(
std::vector<media::KeySystemInfo>* key_systems) {
}
+scoped_ptr<media::RendererFactory>
+ContentRendererClient::CreateMediaRendererFactory(
+ RenderFrame* render_frame,
+ const scoped_refptr<media::MediaLog>& media_log) {
+ return nullptr;
+}
+
bool ContentRendererClient::ShouldReportDetailedMessageForSource(
const base::string16& source) const {
return false;
@@ -177,18 +191,18 @@ bool ContentRendererClient::ShouldEnableSiteIsolationPolicy() const {
return true;
}
-blink::WebWorkerPermissionClientProxy*
-ContentRendererClient::CreateWorkerPermissionClientProxy(
+blink::WebWorkerContentSettingsClientProxy*
+ContentRendererClient::CreateWorkerContentSettingsClientProxy(
RenderFrame* render_frame, blink::WebFrame* frame) {
return nullptr;
}
-bool ContentRendererClient::IsPluginAllowedToUseCompositorAPI(const GURL& url) {
+bool ContentRendererClient::IsPluginAllowedToUseCameraDeviceAPI(
+ const GURL& url) {
return false;
}
-bool ContentRendererClient::IsPluginAllowedToUseVideoDecodeAPI(
- const GURL& url) {
+bool ContentRendererClient::IsPluginAllowedToUseCompositorAPI(const GURL& url) {
return false;
}
@@ -207,4 +221,9 @@ std::string ContentRendererClient::GetUserAgentOverrideForURL(const GURL& url) {
return std::string();
}
+scoped_ptr<blink::WebAppBannerClient>
+ContentRendererClient::CreateAppBannerClient(RenderFrame* render_frame) {
+ return nullptr;
+}
+
} // namespace content
diff --git a/chromium/content/public/renderer/content_renderer_client.h b/chromium/content/public/renderer/content_renderer_client.h
index 7b79a5cb177..9e1e7d73e61 100644
--- a/chromium/content/public/renderer/content_renderer_client.h
+++ b/chromium/content/public/renderer/content_renderer_client.h
@@ -8,14 +8,15 @@
#include <string>
#include <vector>
+#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/string16.h"
#include "content/public/common/content_client.h"
#include "ipc/ipc_message.h"
+#include "third_party/WebKit/public/platform/WebPageVisibilityState.h"
#include "third_party/WebKit/public/web/WebNavigationPolicy.h"
#include "third_party/WebKit/public/web/WebNavigationType.h"
-#include "third_party/WebKit/public/web/WebPageVisibilityState.h"
#include "ui/base/page_transition_types.h"
#include "v8/include/v8.h"
@@ -24,10 +25,11 @@ class SkBitmap;
namespace base {
class FilePath;
-class MessageLoop;
+class SingleThreadTaskRunner;
}
namespace blink {
+class WebAppBannerClient;
class WebAudioDevice;
class WebClipboard;
class WebFrame;
@@ -46,12 +48,14 @@ class WebSpeechSynthesizer;
class WebSpeechSynthesizerClient;
class WebThemeEngine;
class WebURLRequest;
-class WebWorkerPermissionClientProxy;
+class WebWorkerContentSettingsClientProxy;
struct WebPluginParams;
struct WebURLError;
}
namespace media {
+class MediaLog;
+class RendererFactory;
struct KeySystemInfo;
}
@@ -79,9 +83,6 @@ class CONTENT_EXPORT ContentRendererClient {
// Notifies that a new RenderView has been created.
virtual void RenderViewCreated(RenderView* render_view) {}
- // Sets a number of views/tabs opened in this process.
- virtual void SetNumberOfViews(int number_of_views) {}
-
// Returns the bitmap to show when a plugin crashed, or NULL for none.
virtual SkBitmap* GetSadPluginBitmap();
@@ -106,7 +107,7 @@ class CONTENT_EXPORT ContentRendererClient {
const blink::WebPluginParams& params,
blink::WebPlugin** plugin);
- // Creates a replacement plug-in that is shown when the plug-in at |file_path|
+ // Creates a replacement plugin that is shown when the plugin at |file_path|
// couldn't be loaded. This allows the embedder to show a custom placeholder.
virtual blink::WebPlugin* CreatePluginReplacement(
RenderFrame* render_frame,
@@ -221,6 +222,10 @@ class CONTENT_EXPORT ContentRendererClient {
bool is_server_redirect,
bool* send_referrer);
+ // Returns true if this IPC message belongs to a guest container. Currently,
+ // BrowserPlugin is a guest container.
+ virtual bool ShouldForwardToGuestContainer(const IPC::Message& msg);
+
// Notifies the embedder that the given frame is requesting the resource at
// |url|. If the function returns true, the url is changed to |new_url|.
virtual bool WillSendRequest(blink::WebFrame* frame,
@@ -229,12 +234,6 @@ class CONTENT_EXPORT ContentRendererClient {
const GURL& first_party_for_cookies,
GURL* new_url);
- // See the corresponding functions in blink::WebFrameClient.
- virtual void DidCreateScriptContext(blink::WebFrame* frame,
- v8::Handle<v8::Context> context,
- int extension_group,
- int world_id) {}
-
// See blink::Platform.
virtual unsigned long long VisitedLinkHash(const char* canonical_url,
size_t length);
@@ -255,6 +254,11 @@ class CONTENT_EXPORT ContentRendererClient {
// Returns true if the page at |url| can use Pepper MediaStream APIs.
virtual bool AllowPepperMediaStreamAPI(const GURL& url);
+ // Allows an embedder to provide a media::RendererFactory.
+ virtual scoped_ptr<media::RendererFactory> CreateMediaRendererFactory(
+ RenderFrame* render_frame,
+ const scoped_refptr<media::MediaLog>& media_log);
+
// Gives the embedder a chance to register the key system(s) it supports by
// populating |key_systems|.
virtual void AddKeySystems(std::vector<media::KeySystemInfo>* key_systems);
@@ -272,22 +276,35 @@ class CONTENT_EXPORT ContentRendererClient {
virtual bool ShouldEnableSiteIsolationPolicy() const;
// Creates a permission client proxy for in-renderer worker.
- virtual blink::WebWorkerPermissionClientProxy*
- CreateWorkerPermissionClientProxy(RenderFrame* render_frame,
- blink::WebFrame* frame);
+ virtual blink::WebWorkerContentSettingsClientProxy*
+ CreateWorkerContentSettingsClientProxy(RenderFrame* render_frame,
+ blink::WebFrame* frame);
+
+ // Returns true if the page at |url| can use Pepper CameraDevice APIs.
+ virtual bool IsPluginAllowedToUseCameraDeviceAPI(const GURL& url);
// Returns true if the page at |url| can use Pepper Compositor APIs.
virtual bool IsPluginAllowedToUseCompositorAPI(const GURL& url);
- // Returns true if the page at |url| can use Pepper VideoDecoder APIs.
- virtual bool IsPluginAllowedToUseVideoDecodeAPI(const GURL& url);
-
// Returns true if dev channel APIs are available for plugins.
virtual bool IsPluginAllowedToUseDevChannelAPIs();
// Returns a user agent override specific for |url|, or empty string if
// default user agent should be used.
virtual std::string GetUserAgentOverrideForURL(const GURL& url);
+
+ // Records a sample string to a Rappor privacy-preserving metric.
+ // See: https://www.chromium.org/developers/design-documents/rappor
+ virtual void RecordRappor(const std::string& metric,
+ const std::string& sample) {}
+
+ // Records a domain and registry of a url to a Rappor privacy-preserving
+ // metric. See: https://www.chromium.org/developers/design-documents/rappor
+ virtual void RecordRapporURL(const std::string& metric, const GURL& url) {}
+
+ // Allows an embedder to provide a blink::WebAppBannerClient.
+ virtual scoped_ptr<blink::WebAppBannerClient> CreateAppBannerClient(
+ RenderFrame* render_frame);
};
} // namespace content
diff --git a/chromium/content/public/renderer/document_state.h b/chromium/content/public/renderer/document_state.h
index d388a8a979e..d3d8c54064a 100644
--- a/chromium/content/public/renderer/document_state.h
+++ b/chromium/content/public/renderer/document_state.h
@@ -161,8 +161,8 @@ class CONTENT_EXPORT DocumentState
was_fetched_via_proxy_ = value;
}
- net::HostPortPair proxy_server() const { return proxy_server_; }
- void set_proxy_server(net::HostPortPair proxy_server) {
+ const net::HostPortPair& proxy_server() const { return proxy_server_; }
+ void set_proxy_server(const net::HostPortPair& proxy_server) {
proxy_server_ = proxy_server;
}
diff --git a/chromium/content/public/renderer/isolated_world_ids.h b/chromium/content/public/renderer/isolated_world_ids.h
new file mode 100644
index 00000000000..597211ab6fb
--- /dev/null
+++ b/chromium/content/public/renderer/isolated_world_ids.h
@@ -0,0 +1,23 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_PUBLIC_RENDERER_ISOLATED_WORLD_IDS_H_
+#define CONTENT_PUBLIC_RENDERER_ISOLATED_WORLD_IDS_H_
+
+namespace content {
+
+enum IsolatedWorldIDs {
+ // Chrome cannot use ID 0 for an isolated world because 0 represents the main
+ // world.
+ ISOLATED_WORLD_ID_GLOBAL = 0,
+ // Custom isolated world ids used by other embedders should start from here.
+ ISOLATED_WORLD_ID_CONTENT_END,
+ // If any embedder has more than 10 custom isolated worlds that will be run
+ // via RenderFrameImpl::OnJavaScriptExecuteRequestInIsolatedWorld update this.
+ ISOLATED_WORLD_ID_MAX = ISOLATED_WORLD_ID_CONTENT_END + 10,
+};
+
+} // namespace content
+
+#endif // COTENT_PUBLIC_RENDERER_ISOLATED_WORLD_IDS_H_
diff --git a/chromium/content/public/renderer/media_stream_api.cc b/chromium/content/public/renderer/media_stream_api.cc
new file mode 100644
index 00000000000..da39c4be45d
--- /dev/null
+++ b/chromium/content/public/renderer/media_stream_api.cc
@@ -0,0 +1,121 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/public/renderer/media_stream_api.h"
+
+#include "base/base64.h"
+#include "base/callback.h"
+#include "base/rand_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/renderer/media/media_stream_audio_source.h"
+#include "content/renderer/media/media_stream_video_capturer_source.h"
+#include "content/renderer/media/media_stream_video_track.h"
+#include "media/base/audio_capturer_source.h"
+#include "media/base/video_capturer_source.h"
+#include "third_party/WebKit/public/platform/WebMediaDeviceInfo.h"
+#include "third_party/WebKit/public/platform/WebMediaStream.h"
+#include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
+#include "third_party/WebKit/public/platform/WebURL.h"
+#include "third_party/WebKit/public/web/WebMediaStreamRegistry.h"
+#include "url/gurl.h"
+
+namespace content {
+
+namespace {
+
+blink::WebString MakeTrackId() {
+ std::string track_id;
+ base::Base64Encode(base::RandBytesAsString(64), &track_id);
+ return base::UTF8ToUTF16(track_id);
+}
+
+} // namespace
+
+bool AddVideoTrackToMediaStream(
+ scoped_ptr<media::VideoCapturerSource> source,
+ bool is_remote,
+ bool is_readonly,
+ const std::string& media_stream_url) {
+ blink::WebMediaStream stream =
+ blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(
+ GURL(media_stream_url));
+
+ if (stream.isNull()) {
+ LOG(ERROR) << "Stream not found";
+ return false;
+ }
+ blink::WebString track_id = MakeTrackId();
+ blink::WebMediaStreamSource webkit_source;
+ scoped_ptr<MediaStreamVideoSource> media_stream_source(
+ new MediaStreamVideoCapturerSource(
+ MediaStreamSource::SourceStoppedCallback(),
+ source.Pass()));
+ webkit_source.initialize(
+ track_id,
+ blink::WebMediaStreamSource::TypeVideo,
+ track_id,
+ is_remote,
+ is_readonly);
+ webkit_source.setExtraData(media_stream_source.get());
+
+ blink::WebMediaConstraints constraints;
+ constraints.initialize();
+ stream.addTrack(MediaStreamVideoTrack::CreateVideoTrack(
+ media_stream_source.release(),
+ constraints,
+ MediaStreamVideoSource::ConstraintsCallback(),
+ true));
+ return true;
+}
+
+bool AddAudioTrackToMediaStream(
+ scoped_refptr<media::AudioCapturerSource> source,
+ const media::AudioParameters& params,
+ bool is_remote,
+ bool is_readonly,
+ const std::string& media_stream_url) {
+ DCHECK(params.IsValid()) << params.AsHumanReadableString();
+ blink::WebMediaStream stream =
+ blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(
+ GURL(media_stream_url));
+
+ if (stream.isNull()) {
+ LOG(ERROR) << "Stream not found";
+ return false;
+ }
+ blink::WebMediaStreamSource webkit_source;
+ blink::WebString track_id = MakeTrackId();
+ webkit_source.initialize(
+ track_id,
+ blink::WebMediaStreamSource::TypeAudio,
+ track_id,
+ is_remote,
+ is_readonly);
+
+ MediaStreamAudioSource* audio_source(
+ new MediaStreamAudioSource(
+ -1,
+ StreamDeviceInfo(),
+ MediaStreamSource::SourceStoppedCallback(),
+ RenderThreadImpl::current()->GetPeerConnectionDependencyFactory()));
+
+ blink::WebMediaConstraints constraints;
+ constraints.initialize();
+ scoped_refptr<WebRtcAudioCapturer> capturer(
+ WebRtcAudioCapturer::CreateCapturer(-1, StreamDeviceInfo(), constraints,
+ nullptr, audio_source));
+ capturer->SetCapturerSource(source, params);
+ audio_source->SetAudioCapturer(capturer);
+ webkit_source.setExtraData(audio_source);
+
+ blink::WebMediaStreamTrack web_media_audio_track;
+ web_media_audio_track.initialize(webkit_source);
+ RenderThreadImpl::current()->GetPeerConnectionDependencyFactory()->
+ CreateLocalAudioTrack(web_media_audio_track);
+
+ stream.addTrack(web_media_audio_track);
+ return true;
+}
+
+} // namespace content
diff --git a/chromium/content/public/renderer/media_stream_api.h b/chromium/content/public/renderer/media_stream_api.h
new file mode 100644
index 00000000000..71ce675309b
--- /dev/null
+++ b/chromium/content/public/renderer/media_stream_api.h
@@ -0,0 +1,41 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_PUBLIC_RENDERER_MEDIA_STREAM_API_H_
+#define CONTENT_PUBLIC_RENDERER_MEDIA_STREAM_API_H_
+
+#include "content/common/content_export.h"
+#include "media/base/audio_capturer_source.h"
+#include "media/base/video_capturer_source.h"
+
+namespace blink {
+class WebMediaStreamSource;
+}
+
+namespace Media {
+class AudioParameters;
+}
+
+namespace content {
+
+// These two methods will initialize a WebMediaStreamSource object to take
+// data from the provided audio or video capturer source.
+// |is_remote| should be true if the source of the data is not a local device.
+// |is_readonly| should be true if the format of the data cannot be changed by
+// MediaTrackConstraints.
+CONTENT_EXPORT bool AddVideoTrackToMediaStream(
+ scoped_ptr<media::VideoCapturerSource> source,
+ bool is_remote,
+ bool is_readonly,
+ const std::string& media_stream_url);
+CONTENT_EXPORT bool AddAudioTrackToMediaStream(
+ scoped_refptr<media::AudioCapturerSource> source,
+ const media::AudioParameters& params,
+ bool is_remote,
+ bool is_readonly,
+ const std::string& media_stream_url);
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_RENDERER_MEDIA_STREAM_API_H_
diff --git a/chromium/content/public/renderer/media_stream_audio_sink.cc b/chromium/content/public/renderer/media_stream_audio_sink.cc
index 5b14f95b4f2..507bef0fa29 100644
--- a/chromium/content/public/renderer/media_stream_audio_sink.cc
+++ b/chromium/content/public/renderer/media_stream_audio_sink.cc
@@ -43,4 +43,17 @@ void MediaStreamAudioSink::RemoveFromAudioTrack(
audio_track->RemoveSink(sink);
}
+media::AudioParameters MediaStreamAudioSink::GetFormatFromAudioTrack(
+ const blink::WebMediaStreamTrack& track) {
+ MediaStreamTrack* native_track = MediaStreamTrack::GetTrack(track);
+ if (!native_track->is_local_track()) {
+ LOG(ERROR) << "Can't get format from a remote audio track";
+ return media::AudioParameters();
+ }
+
+ WebRtcLocalAudioTrack* audio_track =
+ static_cast<WebRtcLocalAudioTrack*>(native_track);
+ return audio_track->GetOutputFormat();
+}
+
} // namespace content
diff --git a/chromium/content/public/renderer/media_stream_audio_sink.h b/chromium/content/public/renderer/media_stream_audio_sink.h
index 3bd0ff9cf2e..862c32baa68 100644
--- a/chromium/content/public/renderer/media_stream_audio_sink.h
+++ b/chromium/content/public/renderer/media_stream_audio_sink.h
@@ -8,6 +8,7 @@
#include <vector>
#include "base/basictypes.h"
+#include "base/time/time.h"
#include "content/common/content_export.h"
#include "content/public/renderer/media_stream_sink.h"
@@ -16,6 +17,7 @@ class WebMediaStreamTrack;
}
namespace media {
+class AudioBus;
class AudioParameters;
}
@@ -35,19 +37,27 @@ class CONTENT_EXPORT MediaStreamAudioSink : public MediaStreamSink {
static void RemoveFromAudioTrack(MediaStreamAudioSink* sink,
const blink::WebMediaStreamTrack& track);
- // Callback on delivering the interleaved audio data.
- // |audio_data| is the pointer to the audio data.
- // |sample_rate| is the sample frequency of |audio_data|.
- // |number_of_channels| is the number of audio channels of |audio_data|.
- // |number_of_frames| is the number of audio frames in the |audio_data|.
- // Called on real-time audio thread.
- virtual void OnData(const int16* audio_data,
- int sample_rate,
- int number_of_channels,
- int number_of_frames) = 0;
-
- // Callback called when the format of the audio stream has changed.
- // This is called on the same thread as OnData().
+ // Returns the format of the audio track.
+ // Called on the main render thread.
+ static media::AudioParameters GetFormatFromAudioTrack(
+ const blink::WebMediaStreamTrack& track);
+
+ // Callback called to deliver audio data. The data in |audio_bus| respects the
+ // AudioParameters passed in the last call to OnSetFormat(). Called on
+ // real-time audio thread.
+ //
+ // |estimated_capture_time| is the local time at which the first sample frame
+ // in |audio_bus| either: 1) was generated, if it was done so locally; or 2)
+ // should be targeted for play-out, if it was generated from a remote
+ // source. Either way, an implementation should not play-out the audio before
+ // this point-in-time. This value is NOT a high-resolution timestamp, and so
+ // it should not be used as a presentation time; but, instead, it should be
+ // used for buffering playback and for A/V synchronization purposes.
+ virtual void OnData(const media::AudioBus& audio_bus,
+ base::TimeTicks estimated_capture_time) = 0;
+
+ // Callback called when the format of the audio stream has changed. This is
+ // always called at least once before OnData(), and on the same thread.
virtual void OnSetFormat(const media::AudioParameters& params) = 0;
protected:
diff --git a/chromium/content/public/renderer/media_stream_video_sink.h b/chromium/content/public/renderer/media_stream_video_sink.h
index 37f84d1de8e..04fba9298e3 100644
--- a/chromium/content/public/renderer/media_stream_video_sink.h
+++ b/chromium/content/public/renderer/media_stream_video_sink.h
@@ -11,11 +11,7 @@
#include "base/time/time.h"
#include "content/common/content_export.h"
#include "content/public/renderer/media_stream_sink.h"
-
-namespace media {
-class VideoCaptureFormat;
-class VideoFrame;
-}
+#include "media/base/video_capturer_source.h"
namespace blink {
class WebMediaStreamTrack;
@@ -23,21 +19,7 @@ class WebMediaStreamTrack;
namespace content {
-// This callback is used to deliver video frames.
-// |estimated_capture_time| - An optional field to provide the capture time of
-// the delivered video frame. This field usually means the local time when the
-// video frame was generated. It is possible for this value to be null if this
-// timing information cannot be determined. There is no gurantee that this
-// value is accurate. For example video frames from a remote source can only
-// provide this timing information as an estimate.
-// |video_frame->timestamp()| gives the presentation timestamp of the video
-// frame relative to the first frame generated by the corresponding source.
-// Because a source can start generating frames before a subscriber is added,
-// the first video frame delivered may not have timestamp equal to 0.
-typedef base::Callback<
- void(const scoped_refptr<media::VideoFrame>& video_frame,
- const media::VideoCaptureFormat& format,
- const base::TimeTicks& estimated_capture_time)>
+typedef media::VideoCapturerSource::VideoCaptureDeliverFrameCB
VideoCaptureDeliverFrameCB;
// MediaStreamVideoSink is an interface used for receiving video frames from a
diff --git a/chromium/content/public/renderer/navigation_state.cc b/chromium/content/public/renderer/navigation_state.cc
index e5f91fa8186..1543da32dc3 100644
--- a/chromium/content/public/renderer/navigation_state.cc
+++ b/chromium/content/public/renderer/navigation_state.cc
@@ -6,24 +6,6 @@
namespace content {
-NavigationState::NavigationState(ui::PageTransition transition_type,
- bool is_content_initiated,
- int32 pending_page_id,
- int pending_history_list_offset,
- bool history_list_was_cleared)
- : transition_type_(transition_type),
- request_committed_(false),
- is_content_initiated_(is_content_initiated),
- pending_page_id_(pending_page_id),
- pending_history_list_offset_(pending_history_list_offset),
- history_list_was_cleared_(history_list_was_cleared),
- should_replace_current_entry_(false),
- was_within_same_page_(false),
- transferred_request_child_id_(-1),
- transferred_request_request_id_(-1),
- allow_download_(true) {
-}
-
NavigationState::~NavigationState() {}
} // namespace content
diff --git a/chromium/content/public/renderer/navigation_state.h b/chromium/content/public/renderer/navigation_state.h
index 15eac2663e6..1c1ed64d849 100644
--- a/chromium/content/public/renderer/navigation_state.h
+++ b/chromium/content/public/renderer/navigation_state.h
@@ -19,126 +19,17 @@ class CONTENT_EXPORT NavigationState {
public:
virtual ~NavigationState();
- static NavigationState* CreateBrowserInitiated(
- int32 pending_page_id,
- int pending_history_list_offset,
- bool history_list_was_cleared,
- ui::PageTransition transition_type) {
- return new NavigationState(transition_type,
- false,
- pending_page_id,
- pending_history_list_offset,
- history_list_was_cleared);
- }
-
- static NavigationState* CreateContentInitiated() {
- return new NavigationState(
- ui::PAGE_TRANSITION_LINK, true, -1, -1, false);
- }
-
- // Contains the page_id for this navigation or -1 if there is none yet.
- int32 pending_page_id() const { return pending_page_id_; }
-
- // If pending_page_id() is not -1, then this contains the corresponding
- // offset of the page in the back/forward history list.
- int pending_history_list_offset() const {
- return pending_history_list_offset_;
- }
-
- // If pending_page_id() is not -1, then this returns true if the session
- // history was cleared during this navigation.
- bool history_list_was_cleared() const {
- return history_list_was_cleared_;
- }
-
- // If is_content_initiated() is false, whether this navigation should replace
- // the current entry in the back/forward history list. Otherwise, use
- // replacesCurrentHistoryItem() on the WebDataSource.
- //
- // TODO(davidben): It would be good to unify these and have only one source
- // for the two cases. We can plumb this through WebFrame::loadRequest to set
- // lockBackForwardList on the FrameLoadRequest. However, this breaks process
- // swaps because FrameLoader::loadWithNavigationAction treats loads before a
- // FrameLoader has committedFirstRealDocumentLoad as a replacement. (Added for
- // http://crbug.com/178380).
- bool should_replace_current_entry() const {
- return should_replace_current_entry_;
- }
- void set_should_replace_current_entry(bool value) {
- should_replace_current_entry_ = value;
- }
-
// Contains the transition type that the browser specified when it
// initiated the load.
- ui::PageTransition transition_type() const { return transition_type_; }
- void set_transition_type(ui::PageTransition type) {
- transition_type_ = type;
- }
-
- // True if we have already processed the "DidCommitLoad" event for this
- // request. Used by session history.
- bool request_committed() const { return request_committed_; }
- void set_request_committed(bool value) { request_committed_ = value; }
-
- // True if this navigation was not initiated via WebFrame::LoadRequest.
- bool is_content_initiated() const { return is_content_initiated_; }
+ virtual ui::PageTransition GetTransitionType() = 0;
// True iff the frame's navigation was within the same page.
- void set_was_within_same_page(bool value) { was_within_same_page_ = value; }
- bool was_within_same_page() const { return was_within_same_page_; }
-
- // transferred_request_child_id and transferred_request_request_id identify
- // a request that has been created before the navigation is being transferred
- // to a new renderer. This is used to recycle the old request once the new
- // renderer tries to pick up the navigation of the old one.
- void set_transferred_request_child_id(int value) {
- transferred_request_child_id_ = value;
- }
- int transferred_request_child_id() const {
- return transferred_request_child_id_;
- }
- void set_transferred_request_request_id(int value) {
- transferred_request_request_id_ = value;
- }
- int transferred_request_request_id() const {
- return transferred_request_request_id_;
- }
- void set_allow_download(bool value) {
- allow_download_ = value;
- }
- bool allow_download() const {
- return allow_download_;
- }
-
- void set_extra_headers(const std::string& extra_headers) {
- extra_headers_ = extra_headers;
- }
- const std::string& extra_headers() { return extra_headers_; }
-
- private:
- NavigationState(ui::PageTransition transition_type,
- bool is_content_initiated,
- int32 pending_page_id,
- int pending_history_list_offset,
- bool history_list_was_cleared);
+ virtual bool WasWithinSamePage() = 0;
- ui::PageTransition transition_type_;
- bool request_committed_;
- bool is_content_initiated_;
- int32 pending_page_id_;
- int pending_history_list_offset_;
- bool history_list_was_cleared_;
- bool should_replace_current_entry_;
-
- bool was_within_same_page_;
- int transferred_request_child_id_;
- int transferred_request_request_id_;
- bool allow_download_;
- std::string extra_headers_;
-
- DISALLOW_COPY_AND_ASSIGN(NavigationState);
+ // True if this navigation was not initiated via WebFrame::LoadRequest.
+ virtual bool IsContentInitiated() = 0;
};
} // namespace content
-#endif // CONTENT_PUBLIC_RENDERER_NAVIGATION_STATE_H_
+#endif // CONTENT_PUBLIC_RENDERER_NAVIGATION_STATE_H
diff --git a/chromium/content/public/renderer/platform_event_observer.h b/chromium/content/public/renderer/platform_event_observer.h
index 6d569227af6..083007cfc99 100644
--- a/chromium/content/public/renderer/platform_event_observer.h
+++ b/chromium/content/public/renderer/platform_event_observer.h
@@ -63,7 +63,7 @@ class PlatformEventObserver : public PlatformEventObserverBase,
// The observer must automatically stop observing when destroyed in case it
// did not stop before. Implementations of PlatformEventObserver must do
// so by calling StopIfObserving() from their destructors.
- virtual ~PlatformEventObserver() {
+ ~PlatformEventObserver() override {
// If this assert fails, the derived destructor failed to invoke
// StopIfObserving().
DCHECK(!is_observing());
@@ -71,14 +71,14 @@ class PlatformEventObserver : public PlatformEventObserverBase,
// Called when a new IPC message is received. Must be used to listen to the
// responses from the browser process if any expected.
- virtual bool OnControlMessageReceived(const IPC::Message& msg) override {
+ bool OnControlMessageReceived(const IPC::Message& msg) override {
return false;
}
// Start observing. Will request the browser process to start listening to the
// events. |listener| will receive any response from the browser process.
// Note: should not be called if already observing.
- virtual void Start(blink::WebPlatformEventListener* listener) {
+ void Start(blink::WebPlatformEventListener* listener) override {
DCHECK(!is_observing());
listener_ = static_cast<ListenerType*>(listener);
is_observing_ = true;
@@ -88,7 +88,7 @@ class PlatformEventObserver : public PlatformEventObserverBase,
// Stop observing. Will let the browser know that it doesn't need to observe
// anymore.
- virtual void Stop() {
+ void Stop() override {
DCHECK(is_observing());
listener_ = 0;
is_observing_ = false;
@@ -133,4 +133,4 @@ class PlatformEventObserver : public PlatformEventObserverBase,
} // namespace content
-#endif // CONTENT_PUBLIC_RENDERER_PLATFORM_EVENT_OBSERVER_H_
+#endif // CONTENT_PUBLIC_RENDERER_PLATFORM_EVENT_OBSERVER_H_
diff --git a/chromium/content/public/renderer/plugin_instance_throttler.h b/chromium/content/public/renderer/plugin_instance_throttler.h
new file mode 100644
index 00000000000..025ccbd8a8a
--- /dev/null
+++ b/chromium/content/public/renderer/plugin_instance_throttler.h
@@ -0,0 +1,108 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_PUBLIC_RENDERER_PLUGIN_INSTANCE_THROTTLER_H_
+#define CONTENT_PUBLIC_RENDERER_PLUGIN_INSTANCE_THROTTLER_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/common/content_export.h"
+
+namespace blink {
+class WebPlugin;
+struct WebPluginParams;
+}
+
+namespace gfx {
+class Size;
+}
+
+class GURL;
+class SkBitmap;
+
+namespace content {
+
+// This class manages the metric collection, throttling, and unthrottling of a
+// single peripheral plugin instance. If the Power Saver feature is disabled,
+// the plugin instance will never actually be throttled, but still collects
+// user interaction metrics.
+//
+// The process for throttling a plugin is as follows:
+// 1) Attempt to find a representative keyframe to display as a placeholder for
+// the plugin.
+// 2) a) If a representative keyframe is found, throttle the plugin at that
+// keyframe.
+// b) If a representative keyframe is not found, throttle the plugin after a
+// certain period of time.
+//
+// The plugin will then be unthrottled by receiving a mouse click from the user.
+//
+// To choose a representative keyframe, we first wait for a certain number of
+// "interesting" frames to be displayed by the plugin. A frame is called
+// interesting if it meets some heuristic. After we have seen a certain number
+// of interesting frames, we throttle the plugin and use that frame as the
+// representative keyframe.
+class CONTENT_EXPORT PluginInstanceThrottler {
+ public:
+ // How the throttled power saver is unthrottled, if ever.
+ // These numeric values are used in UMA logs; do not change them.
+ enum PowerSaverUnthrottleMethod {
+ UNTHROTTLE_METHOD_NEVER = 0,
+ UNTHROTTLE_METHOD_BY_CLICK = 1,
+ UNTHROTTLE_METHOD_BY_WHITELIST = 2,
+ UNTHROTTLE_METHOD_BY_AUDIO = 3,
+ UNTHROTTLE_METHOD_NUM_ITEMS
+ };
+
+ class Observer {
+ public:
+ // Guaranteed to be called before the throttle is engaged.
+ virtual void OnKeyframeExtracted(const SkBitmap* bitmap) {}
+
+ virtual void OnThrottleStateChange() {}
+
+ virtual void OnPeripheralStateChange() {}
+
+ // Called when the plugin should be hidden due to a placeholder.
+ virtual void OnHiddenForPlaceholder(bool hidden) {}
+
+ virtual void OnThrottlerDestroyed() {}
+ };
+
+ static scoped_ptr<PluginInstanceThrottler> Create();
+
+ static void RecordUnthrottleMethodMetric(PowerSaverUnthrottleMethod method);
+
+ virtual ~PluginInstanceThrottler() {}
+
+ virtual void AddObserver(Observer* observer) = 0;
+ virtual void RemoveObserver(Observer* observer) = 0;
+
+ virtual bool IsThrottled() const = 0;
+ virtual bool IsHiddenForPlaceholder() const = 0;
+
+ // Marks the plugin as essential. Unthrottles the plugin if already throttled.
+ virtual void MarkPluginEssential(PowerSaverUnthrottleMethod method) = 0;
+
+ // Called by the placeholder when the plugin should temporarily be hidden.
+ virtual void SetHiddenForPlaceholder(bool hidden) = 0;
+
+ virtual blink::WebPlugin* GetWebPlugin() const = 0;
+
+ // Gets the throttler's best estimate of the plugin's visible dimensions.
+ virtual const gfx::Size& GetSize() const = 0;
+
+ // Throttler needs to know when the plugin audio is throttled, as this may
+ // prevent the plugin from generating new frames.
+ virtual void NotifyAudioThrottled() = 0;
+
+ protected:
+ PluginInstanceThrottler() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PluginInstanceThrottler);
+};
+}
+
+#endif // CONTENT_PUBLIC_RENDERER_PLUGIN_INSTANCE_THROTTLER_H_
diff --git a/chromium/content/public/renderer/render_frame.h b/chromium/content/public/renderer/render_frame.h
index 223825daeaf..e8f11ed02bb 100644
--- a/chromium/content/public/renderer/render_frame.h
+++ b/chromium/content/public/renderer/render_frame.h
@@ -5,13 +5,18 @@
#ifndef CONTENT_PUBLIC_RENDERER_RENDER_FRAME_H_
#define CONTENT_PUBLIC_RENDERER_RENDER_FRAME_H_
+#include "base/callback_forward.h"
+#include "base/memory/scoped_ptr.h"
#include "base/strings/string16.h"
#include "content/common/content_export.h"
#include "ipc/ipc_listener.h"
#include "ipc/ipc_sender.h"
#include "third_party/WebKit/public/web/WebNavigationPolicy.h"
+class GURL;
+
namespace blink {
+class WebElement;
class WebFrame;
class WebLocalFrame;
class WebNode;
@@ -26,13 +31,14 @@ class Range;
}
namespace v8 {
-template <typename T> class Handle;
+template <typename T> class Local;
class Context;
class Isolate;
}
namespace content {
class ContextMenuClient;
+class PluginInstanceThrottler;
class RenderView;
class ServiceRegistry;
struct ContextMenuParams;
@@ -57,6 +63,10 @@ class CONTENT_EXPORT RenderFrame : public IPC::Listener,
// Returns the associated WebFrame.
virtual blink::WebLocalFrame* GetWebFrame() = 0;
+ // Gets the focused element. If no such element exists then
+ // the element will be Null.
+ virtual blink::WebElement GetFocusedElement() const = 0;
+
// Gets WebKit related preferences associated with this frame.
virtual WebPreferences& GetWebkitPreferences() = 0;
@@ -82,11 +92,12 @@ class CONTENT_EXPORT RenderFrame : public IPC::Listener,
virtual blink::WebNode GetContextMenuNode() const = 0;
// Create a new NPAPI/Pepper plugin depending on |info|. Returns NULL if no
- // plugin was found.
+ // plugin was found. |throttler| may be empty.
virtual blink::WebPlugin* CreatePlugin(
blink::WebFrame* frame,
const WebPluginInfo& info,
- const blink::WebPluginParams& params) = 0;
+ const blink::WebPluginParams& params,
+ scoped_ptr<PluginInstanceThrottler> throttler) = 0;
// The client should handle the navigation externally.
virtual void LoadURLExternally(blink::WebLocalFrame* frame,
@@ -102,6 +113,15 @@ class CONTENT_EXPORT RenderFrame : public IPC::Listener,
// Returns the ServiceRegistry for this frame.
virtual ServiceRegistry* GetServiceRegistry() = 0;
+#if defined(ENABLE_PLUGINS)
+ // Registers a plugin that has been marked peripheral. If the origin
+ // whitelist is later updated and includes |content_origin|, then
+ // |unthrottle_callback| will be called.
+ virtual void RegisterPeripheralPlugin(
+ const GURL& content_origin,
+ const base::Closure& unthrottle_callback) = 0;
+#endif
+
// Returns true if this frame is a FTP directory listing.
virtual bool IsFTPDirectoryListing() = 0;
@@ -109,6 +129,10 @@ class CONTENT_EXPORT RenderFrame : public IPC::Listener,
// content created by the embedder.
virtual void AttachGuest(int element_instance_id) = 0;
+ // Detaches the browser plugin identified by |element_instance_id| from guest
+ // content created by the embedder.
+ virtual void DetachGuest(int element_instance_id) = 0;
+
// Notifies the browser of text selection changes made.
virtual void SetSelectedText(const base::string16& selection_text,
size_t offset,
@@ -117,7 +141,7 @@ class CONTENT_EXPORT RenderFrame : public IPC::Listener,
// Ensures that builtin mojo bindings modules are available in |context|.
virtual void EnsureMojoBuiltinsAreAvailable(
v8::Isolate* isolate,
- v8::Handle<v8::Context> context) = 0;
+ v8::Local<v8::Context> context) = 0;
protected:
~RenderFrame() override {}
diff --git a/chromium/content/public/renderer/render_frame_observer.h b/chromium/content/public/renderer/render_frame_observer.h
index 7ad46d7d52c..0c787b6382d 100644
--- a/chromium/content/public/renderer/render_frame_observer.h
+++ b/chromium/content/public/renderer/render_frame_observer.h
@@ -14,7 +14,9 @@
#include "v8/include/v8.h"
namespace blink {
+class WebFormElement;
class WebFrame;
+class WebNode;
struct WebURLError;
}
@@ -43,20 +45,37 @@ class CONTENT_EXPORT RenderFrameObserver : public IPC::Listener,
virtual void WasHidden() {}
virtual void WasShown() {}
+ // Called when associated widget is about to close.
+ virtual void WidgetWillClose() {}
+
// These match the Blink API notifications
- virtual void DidCommitProvisionalLoad(bool is_new_navigation) {}
+ virtual void DidCommitProvisionalLoad(bool is_new_navigation,
+ bool is_same_page_navigation) {}
virtual void DidStartProvisionalLoad() {}
virtual void DidFailProvisionalLoad(const blink::WebURLError& error) {}
virtual void DidFinishLoad() {}
virtual void DidFinishDocumentLoad() {}
- virtual void WillReleaseScriptContext(v8::Handle<v8::Context> context,
+ virtual void DidCreateScriptContext(v8::Local<v8::Context> context,
+ int extension_group,
+ int world_id) {}
+ virtual void WillReleaseScriptContext(v8::Local<v8::Context> context,
int world_id) {}
virtual void DidClearWindowObject() {}
- virtual void DidChangeName(const base::string16& name) {}
virtual void DidChangeManifest() {}
+ virtual void DidChangeDefaultPresentation() {}
+ virtual void DidChangeScrollOffset() {}
+ virtual void WillSendSubmitEvent(const blink::WebFormElement& form) {}
+ virtual void WillSubmitForm(const blink::WebFormElement& form) {}
+
+ // Called before FrameWillClose, when this frame has been detached from the
+ // view, but has not been closed yet. This *will* be called when parent frames
+ // are closing. Since the frame is already detached from the DOM at this time
+ // it should not be inspected.
+ virtual void FrameDetached() {}
// Called when the frame will soon be closed. This is the last opportunity to
- // send messages to the host (e.g., for clean-up, shutdown, etc.).
+ // send messages to the host (e.g., for clean-up, shutdown, etc.). This is
+ // *not* called on child frames when parent frames are being closed.
virtual void FrameWillClose() {}
// Called when we receive a console message from Blink for which we requested
@@ -74,6 +93,9 @@ class CONTENT_EXPORT RenderFrameObserver : public IPC::Listener,
// Called when a compositor frame has committed.
virtual void DidCommitCompositorFrame() {}
+ // Called when the focused node has changed to |node|.
+ virtual void FocusedNodeChanged(const blink::WebNode& node) {}
+
// IPC::Listener implementation.
bool OnMessageReceived(const IPC::Message& message) override;
diff --git a/chromium/content/public/renderer/render_frame_observer_tracker.h b/chromium/content/public/renderer/render_frame_observer_tracker.h
index 7c5b332ef32..70b296ffd65 100644
--- a/chromium/content/public/renderer/render_frame_observer_tracker.h
+++ b/chromium/content/public/renderer/render_frame_observer_tracker.h
@@ -38,12 +38,12 @@ template <class T>
class RenderFrameObserverTracker {
public:
static T* Get(const RenderFrame* render_frame) {
- return render_frame_map_.Get()[render_frame];
+ return static_cast<T*>(render_frame_map_.Get()[render_frame]);
}
explicit RenderFrameObserverTracker(const RenderFrame* render_frame)
: render_frame_(render_frame) {
- render_frame_map_.Get()[render_frame] = static_cast<T*>(this);
+ render_frame_map_.Get()[render_frame] = this;
}
~RenderFrameObserverTracker() {
render_frame_map_.Get().erase(render_frame_);
@@ -52,14 +52,16 @@ class RenderFrameObserverTracker {
private:
const RenderFrame* render_frame_;
- static base::LazyInstance<std::map<const RenderFrame*, T*> >
- render_frame_map_;
+ static base::LazyInstance<
+ std::map<const RenderFrame*, RenderFrameObserverTracker<T>*>>
+ render_frame_map_;
DISALLOW_COPY_AND_ASSIGN(RenderFrameObserverTracker<T>);
};
template <class T>
-base::LazyInstance<std::map<const RenderFrame*, T*> >
+base::LazyInstance<std::map<const RenderFrame*,
+ RenderFrameObserverTracker<T>*>>
RenderFrameObserverTracker<T>::render_frame_map_ =
LAZY_INSTANCE_INITIALIZER;
diff --git a/chromium/content/public/renderer/render_process_observer.h b/chromium/content/public/renderer/render_process_observer.h
index de23dae1468..582a60fb5e4 100644
--- a/chromium/content/public/renderer/render_process_observer.h
+++ b/chromium/content/public/renderer/render_process_observer.h
@@ -30,7 +30,7 @@ class CONTENT_EXPORT RenderProcessObserver {
// Called right after the WebKit API is initialized.
virtual void WebKitInitialized() {}
- // Called when the renderer cache of the plug-in list has changed.
+ // Called when the renderer cache of the plugin list has changed.
virtual void PluginListChanged() {}
virtual void IdleNotification() {}
diff --git a/chromium/content/public/renderer/render_thread.h b/chromium/content/public/renderer/render_thread.h
index 38006d81d43..407128b3331 100644
--- a/chromium/content/public/renderer/render_thread.h
+++ b/chromium/content/public/renderer/render_thread.h
@@ -10,12 +10,8 @@
#include "base/memory/shared_memory.h"
#include "base/metrics/user_metrics_action.h"
#include "content/common/content_export.h"
+#include "content/public/child/child_thread.h"
#include "ipc/ipc_channel_proxy.h"
-#include "ipc/ipc_sender.h"
-
-#if defined(OS_WIN)
-#include <windows.h>
-#endif
class GURL;
@@ -25,6 +21,10 @@ class MessageLoopProxy;
class WaitableEvent;
}
+namespace cc {
+class SharedBitmapManager;
+}
+
namespace IPC {
class MessageFilter;
class SyncChannel;
@@ -41,7 +41,7 @@ class RenderProcessObserver;
class ResourceDispatcherDelegate;
class ServiceRegistry;
-class CONTENT_EXPORT RenderThread : public IPC::Sender {
+class CONTENT_EXPORT RenderThread : virtual public ChildThread {
public:
// Returns the one render thread for this process. Note that this can only
// be accessed when running on the render thread itself.
@@ -50,7 +50,7 @@ class CONTENT_EXPORT RenderThread : public IPC::Sender {
RenderThread();
~RenderThread() override;
- virtual base::MessageLoop* GetMessageLoop() = 0;
+ virtual scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner() = 0;
virtual IPC::SyncChannel* GetChannel() = 0;
virtual std::string GetLocale() = 0;
virtual IPC::SyncMessageFilter* GetSyncMessageFilter() = 0;
@@ -102,6 +102,8 @@ class CONTENT_EXPORT RenderThread : public IPC::Sender {
virtual scoped_ptr<base::SharedMemory> HostAllocateSharedMemoryBuffer(
size_t buffer_size) = 0;
+ virtual cc::SharedBitmapManager* GetSharedBitmapManager() = 0;
+
// Registers the given V8 extension with WebKit.
virtual void RegisterExtension(v8::Extension* extension) = 0;
@@ -129,15 +131,6 @@ class CONTENT_EXPORT RenderThread : public IPC::Sender {
// Gets the shutdown event for the process.
virtual base::WaitableEvent* GetShutdownEvent() = 0;
-#if defined(OS_WIN)
- // Request that the given font be loaded by the browser so it's cached by the
- // OS. Please see ChildProcessHost::PreCacheFont for details.
- virtual void PreCacheFont(const LOGFONT& log_font) = 0;
-
- // Release cached font.
- virtual void ReleaseCachedFonts() = 0;
-#endif
-
// Returns the ServiceRegistry for this thread.
virtual ServiceRegistry* GetServiceRegistry() = 0;
};
diff --git a/chromium/content/public/renderer/render_view.h b/chromium/content/public/renderer/render_view.h
index 6040a6b4ee2..34782e3399f 100644
--- a/chromium/content/public/renderer/render_view.h
+++ b/chromium/content/public/renderer/render_view.h
@@ -12,7 +12,7 @@
#include "content/common/content_export.h"
#include "content/public/common/top_controls_state.h"
#include "ipc/ipc_sender.h"
-#include "third_party/WebKit/public/web/WebPageVisibilityState.h"
+#include "third_party/WebKit/public/platform/WebPageVisibilityState.h"
#include "ui/gfx/native_widget_types.h"
namespace blink {
@@ -38,6 +38,11 @@ class RenderViewVisitor;
struct SSLStatus;
struct WebPreferences;
+// DEPRECATED: RenderView is being removed as part of the SiteIsolation project.
+// New code should be added to RenderFrame instead.
+//
+// For context, please see https://crbug.com/467770 and
+// http://www.chromium.org/developers/design-documents/site-isolation.
class CONTENT_EXPORT RenderView : public IPC::Sender {
public:
// Returns the RenderView containing the given WebView.
@@ -73,18 +78,10 @@ class CONTENT_EXPORT RenderView : public IPC::Sender {
// Returns the associated WebView. May return NULL when the view is closing.
virtual blink::WebView* GetWebView() = 0;
- // Gets the focused element. If no such element exists then
- // the element will be Null.
- virtual blink::WebElement GetFocusedElement() const = 0;
-
// Returns true if the parameter node is a textfield, text area, a content
// editable div, or has an ARIA role of textbox.
virtual bool IsEditableNode(const blink::WebNode& node) const = 0;
- // Returns true if a hit test for |point| returns a descendant of |node|.
- virtual bool NodeContainsPoint(const blink::WebNode& node,
- const gfx::Point& point) const = 0;
-
// Returns true if we should display scrollbars for the given view size and
// false if the scrollbars should be hidden.
virtual bool ShouldDisplayScrollbars(int width, int height) const = 0;
diff --git a/chromium/content/public/renderer/render_view_observer.h b/chromium/content/public/renderer/render_view_observer.h
index 4c7aba0529f..6345aea5312 100644
--- a/chromium/content/public/renderer/render_view_observer.h
+++ b/chromium/content/public/renderer/render_view_observer.h
@@ -11,6 +11,7 @@
#include "ipc/ipc_listener.h"
#include "ipc/ipc_sender.h"
#include "third_party/WebKit/public/platform/WebVector.h"
+#include "v8/include/v8.h"
class GURL;
@@ -61,6 +62,7 @@ class CONTENT_EXPORT RenderViewObserver : public IPC::Listener,
const blink::WebURLError& error) {}
virtual void DidCommitProvisionalLoad(blink::WebLocalFrame* frame,
bool is_new_navigation) {}
+ virtual void DidCreateNewDocument(blink::WebLocalFrame* frame) {}
virtual void DidClearWindowObject(blink::WebLocalFrame* frame) {}
virtual void DidCreateDocumentElement(blink::WebLocalFrame* frame) {}
virtual void FrameCreated(blink::WebLocalFrame* parent,
@@ -71,29 +73,24 @@ class CONTENT_EXPORT RenderViewObserver : public IPC::Listener,
blink::WebLocalFrame* frame,
const blink::WebVector<blink::WebString>& newly_matching_selectors,
const blink::WebVector<blink::WebString>& stopped_matching_selectors) {}
- virtual void WillSendSubmitEvent(blink::WebLocalFrame* frame,
- const blink::WebFormElement& form) {}
- virtual void WillSubmitForm(blink::WebLocalFrame* frame,
- const blink::WebFormElement& form) {}
- virtual void DidCreateDataSource(blink::WebLocalFrame* frame,
- blink::WebDataSource* ds) {}
virtual void PrintPage(blink::WebLocalFrame* frame, bool user_initiated) {}
virtual void FocusedNodeChanged(const blink::WebNode& node) {}
- virtual void DidChangeScrollOffset(blink::WebLocalFrame* frame) {}
virtual void DraggableRegionsChanged(blink::WebFrame* frame) {}
virtual void DidCommitCompositorFrame() {}
virtual void DidUpdateLayout() {}
// These match the RenderView methods.
virtual void DidHandleMouseEvent(const blink::WebMouseEvent& event) {}
- virtual void DidHandleTouchEvent(const blink::WebTouchEvent& event) {}
virtual void DidHandleGestureEvent(const blink::WebGestureEvent& event) {}
// These match incoming IPCs.
virtual void Navigate(const GURL& url) {}
virtual void ClosePage() {}
- virtual void OrientationChangeEvent() {}
- virtual void Resized() {}
+
+ // This indicates that animations to scroll the focused element into view (if
+ // any) have completed. May be called more than once for a single focus. Can
+ // be called from browser, renderer, or compositor.
+ virtual void FocusChangeComplete() {}
virtual void OnStop() {}
diff --git a/chromium/content/public/renderer/render_view_observer_tracker.h b/chromium/content/public/renderer/render_view_observer_tracker.h
index 54de713ef90..0ef3016403e 100644
--- a/chromium/content/public/renderer/render_view_observer_tracker.h
+++ b/chromium/content/public/renderer/render_view_observer_tracker.h
@@ -38,12 +38,12 @@ template <class T>
class RenderViewObserverTracker {
public:
static T* Get(const RenderView* render_view) {
- return render_view_map_.Get()[render_view];
+ return static_cast<T*>(render_view_map_.Get()[render_view]);
}
explicit RenderViewObserverTracker(const RenderView* render_view)
: render_view_(render_view) {
- render_view_map_.Get()[render_view] = static_cast<T*>(this);
+ render_view_map_.Get()[render_view] = this;
}
~RenderViewObserverTracker() {
render_view_map_.Get().erase(render_view_);
@@ -52,14 +52,15 @@ class RenderViewObserverTracker {
private:
const RenderView* render_view_;
- static base::LazyInstance<std::map<const RenderView*, T*> >
- render_view_map_;
+ static base::LazyInstance<
+ std::map<const RenderView*, RenderViewObserverTracker<T>*>>
+ render_view_map_;
DISALLOW_COPY_AND_ASSIGN(RenderViewObserverTracker<T>);
};
template <class T>
-base::LazyInstance<std::map<const RenderView*, T*> >
+base::LazyInstance<std::map<const RenderView*, RenderViewObserverTracker<T>*>>
RenderViewObserverTracker<T>::render_view_map_ = LAZY_INSTANCE_INITIALIZER;
} // namespace content
diff --git a/chromium/content/public/renderer/renderer_gamepad_provider.h b/chromium/content/public/renderer/renderer_gamepad_provider.h
index 6899948bb2c..f51586d5ab8 100644
--- a/chromium/content/public/renderer/renderer_gamepad_provider.h
+++ b/chromium/content/public/renderer/renderer_gamepad_provider.h
@@ -32,4 +32,4 @@ class RendererGamepadProvider
} // namespace content
-#endif
+#endif // CONTENT_PUBLIC_RENDERER_RENDERER_GAMEPAD_PROVIDER_H_
diff --git a/chromium/content/public/renderer/resource_fetcher.h b/chromium/content/public/renderer/resource_fetcher.h
index 5c010f99965..2c402aab395 100644
--- a/chromium/content/public/renderer/resource_fetcher.h
+++ b/chromium/content/public/renderer/resource_fetcher.h
@@ -20,6 +20,7 @@ class TimeDelta;
namespace blink {
class WebFrame;
class WebURLResponse;
+struct WebURLLoaderOptions;
}
namespace content {
@@ -47,11 +48,18 @@ class CONTENT_EXPORT ResourceFetcher {
static ResourceFetcher* Create(const GURL& url);
// Set the corresponding parameters of the request. Must be called before
- // Start. By default, requests are GETs with no body.
+ // Start. By default, requests are GETs with no body and respect the default
+ // cache policy.
virtual void SetMethod(const std::string& method) = 0;
virtual void SetBody(const std::string& body) = 0;
virtual void SetHeader(const std::string& header,
const std::string& value) = 0;
+ virtual void SetSkipServiceWorker(bool skip_service_worker) = 0;
+ virtual void SetCachePolicy(blink::WebURLRequest::CachePolicy policy) = 0;
+
+ // Associate the corresponding WebURLLoaderOptions to the loader. Must be
+ // called before Start. Used if the LoaderType is FRAME_ASSOCIATED_LOADER.
+ virtual void SetLoaderOptions(const blink::WebURLLoaderOptions& options) = 0;
// Starts the request using the specified frame. Calls |callback| when
// done.
diff --git a/chromium/content/public/renderer/v8_value_converter.h b/chromium/content/public/renderer/v8_value_converter.h
deleted file mode 100644
index f3fd126931a..00000000000
--- a/chromium/content/public/renderer/v8_value_converter.h
+++ /dev/null
@@ -1,127 +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_PUBLIC_RENDERER_V8_VALUE_CONVERTER_H_
-#define CONTENT_PUBLIC_RENDERER_V8_VALUE_CONVERTER_H_
-
-#include "base/callback.h"
-#include "content/common/content_export.h"
-#include "v8/include/v8.h"
-
-namespace base {
-class Value;
-}
-
-namespace content {
-
-// Converts between v8::Value (JavaScript values in the v8 heap) and Chrome's
-// values (from base/values.h). Lists and dictionaries are converted
-// recursively.
-//
-// The JSON types (null, boolean, string, number, array, and object) as well as
-// binary values are supported. For binary values, we convert to WebKit
-// ArrayBuffers, and support converting from an ArrayBuffer or any of the
-// ArrayBufferView subclasses (Uint8Array, etc.).
-class CONTENT_EXPORT V8ValueConverter {
- public:
- // Extends the default behaviour of V8ValueConverter.
- class CONTENT_EXPORT Strategy {
- public:
- typedef base::Callback<base::Value*(
- v8::Handle<v8::Value>, v8::Isolate* isolate)> FromV8ValueCallback;
-
- virtual ~Strategy() {}
-
- // If false is returned, V8ValueConverter proceeds with the default
- // behavior.
- // Use |callback| to convert any child values, as this will retain
- // the ValueConverter's internal checks for depth and cycles.
- virtual bool FromV8Object(v8::Handle<v8::Object> value,
- base::Value** out,
- v8::Isolate* isolate,
- const FromV8ValueCallback& callback) const;
-
- // If false is returned, V8ValueConverter proceeds with the default
- // behavior.
- // Use |callback| to convert any child values, as this will retain
- // the ValueConverter's internal checks for depth and cycles.
- virtual bool FromV8Array(v8::Handle<v8::Array> value,
- base::Value** out,
- v8::Isolate* isolate,
- const FromV8ValueCallback& callback) const;
-
- // If false is returned, V8ValueConverter proceeds with the default
- // behavior. v8::Object is passed as ArrayBuffer and ArrayBufferView
- // classes are siblings.
- virtual bool FromV8ArrayBuffer(v8::Handle<v8::Object> value,
- base::Value** out,
- v8::Isolate* isolate) const;
-
- // If false is returned, V8ValueConverter proceeds with the default
- // behavior. This allows to intercept "non-finite" values and do something
- // with them.
- virtual bool FromV8Number(v8::Handle<v8::Number> value,
- base::Value** out) const;
-
- // If false is returned, V8ValueConverter proceeds with the default
- // behavior.
- virtual bool FromV8Undefined(base::Value** out) const;
- };
-
- static V8ValueConverter* create();
-
- virtual ~V8ValueConverter() {}
-
- // If true, Date objects are converted into DoubleValues with the number of
- // seconds since Unix epoch.
- //
- // Otherwise they are converted into DictionaryValues with whatever additional
- // properties has been set on them.
- virtual void SetDateAllowed(bool val) = 0;
-
- // If true, RegExp objects are converted into StringValues with the regular
- // expression between / and /, for example "/ab?c/".
- //
- // Otherwise they are converted into DictionaryValues with whatever additional
- // properties has been set on them.
- virtual void SetRegExpAllowed(bool val) = 0;
-
- // If true, Function objects are converted into DictionaryValues with whatever
- // additional properties has been set on them.
- //
- // Otherwise they are treated as unsupported, see FromV8Value.
- virtual void SetFunctionAllowed(bool val) = 0;
-
- // If true, null values are stripped from objects. This is often useful when
- // converting arguments to extension APIs.
- virtual void SetStripNullFromObjects(bool val) = 0;
-
- // Extend default behavior of V8ValueConverter.
- virtual void SetStrategy(Strategy* strategy) = 0;
-
- // Converts a base::Value to a v8::Value.
- //
- // Unsupported types are replaced with null. If an array or object throws
- // while setting a value, that property or item is skipped, leaving a hole in
- // the case of arrays.
- virtual v8::Handle<v8::Value> ToV8Value(
- const base::Value* value,
- v8::Handle<v8::Context> context) const = 0;
-
- // Converts a v8::Value to base::Value.
- //
- // Unsupported types (unless explicitly configured) are not converted, so
- // this method may return NULL -- the exception is when converting arrays,
- // where unsupported types are converted to Value(TYPE_NULL).
- //
- // Likewise, if an object throws while converting a property it will not be
- // converted, whereas if an array throws while converting an item it will be
- // converted to Value(TYPE_NULL).
- virtual base::Value* FromV8Value(v8::Handle<v8::Value> value,
- v8::Handle<v8::Context> context) const = 0;
-};
-
-} // namespace content
-
-#endif // CONTENT_PUBLIC_RENDERER_V8_VALUE_CONVERTER_H_
diff --git a/chromium/content/public/renderer/video_encode_accelerator.cc b/chromium/content/public/renderer/video_encode_accelerator.cc
index a8ad12bc847..32c6772aae5 100644
--- a/chromium/content/public/renderer/video_encode_accelerator.cc
+++ b/chromium/content/public/renderer/video_encode_accelerator.cc
@@ -7,7 +7,7 @@
#include "base/task_runner_util.h"
#include "content/common/gpu/client/gpu_video_encode_accelerator_host.h"
#include "content/renderer/render_thread_impl.h"
-#include "media/filters/gpu_video_accelerator_factories.h"
+#include "media/renderers/gpu_video_accelerator_factories.h"
namespace content {
@@ -33,12 +33,12 @@ void CreateVideoEncodeAccelerator(
base::Bind(callback, encode_task_runner));
}
-std::vector<media::VideoEncodeAccelerator::SupportedProfile>
+media::VideoEncodeAccelerator::SupportedProfiles
GetSupportedVideoEncodeAcceleratorProfiles() {
scoped_refptr<media::GpuVideoAcceleratorFactories> gpu_factories =
RenderThreadImpl::current()->GetGpuFactories();
if (!gpu_factories.get())
- return std::vector<media::VideoEncodeAccelerator::SupportedProfile>();
+ return media::VideoEncodeAccelerator::SupportedProfiles();
return gpu_factories->GetVideoEncodeAcceleratorSupportedProfiles();
}
diff --git a/chromium/content/public/renderer/video_encode_accelerator.h b/chromium/content/public/renderer/video_encode_accelerator.h
index 426b05279d0..e98e443d0d7 100644
--- a/chromium/content/public/renderer/video_encode_accelerator.h
+++ b/chromium/content/public/renderer/video_encode_accelerator.h
@@ -27,8 +27,8 @@ CreateVideoEncodeAccelerator(
const OnCreateVideoEncodeAcceleratorCallback& callback);
// Returns list of encoding profiles supported by VideoEncodeAccelerator.
-CONTENT_EXPORT std::vector<media::VideoEncodeAccelerator::SupportedProfile>
-GetSupportedVideoEncodeAcceleratorProfiles();
+CONTENT_EXPORT media::VideoEncodeAccelerator::SupportedProfiles
+ GetSupportedVideoEncodeAcceleratorProfiles();
} // namespace content
diff --git a/chromium/content/public/renderer/webrtc_log_message_delegate.h b/chromium/content/public/renderer/webrtc_log_message_delegate.h
index cb324df8cb2..351cf9efd50 100644
--- a/chromium/content/public/renderer/webrtc_log_message_delegate.h
+++ b/chromium/content/public/renderer/webrtc_log_message_delegate.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_PUBLIC_RENDERER_MEDIA_WEBRTC_LOG_MESSAGE_DELEGATE_H_
-#define CONTENT_PUBLIC_RENDERER_MEDIA_WEBRTC_LOG_MESSAGE_DELEGATE_H_
+#ifndef CONTENT_PUBLIC_RENDERER_WEBRTC_LOG_MESSAGE_DELEGATE_H_
+#define CONTENT_PUBLIC_RENDERER_WEBRTC_LOG_MESSAGE_DELEGATE_H_
#include <string>
@@ -33,4 +33,4 @@ CONTENT_EXPORT void InitWebRtcLogging();
} // namespace content
-#endif // CONTENT_PUBLIC_RENDERER_MEDIA_WEBRTC_LOG_MESSAGE_DELEGATE_H_
+#endif // CONTENT_PUBLIC_RENDERER_WEBRTC_LOG_MESSAGE_DELEGATE_H_
diff --git a/chromium/content/public/utility/BUILD.gn b/chromium/content/public/utility/BUILD.gn
index 7d40a50f230..999549ac452 100644
--- a/chromium/content/public/utility/BUILD.gn
+++ b/chromium/content/public/utility/BUILD.gn
@@ -5,9 +5,13 @@
# See //content/BUILD.gn for how this works.
group("utility") {
if (is_component_build) {
- public_deps = [ "//content" ]
+ public_deps = [
+ "//content",
+ ]
} else {
- public_deps = [ ":utility_sources" ]
+ public_deps = [
+ ":utility_sources",
+ ]
}
}
@@ -37,4 +41,3 @@ source_set("utility_sources") {
"//content/utility",
]
}
-
diff --git a/chromium/content/public/utility/DEPS b/chromium/content/public/utility/DEPS
new file mode 100644
index 00000000000..ad94e88de19
--- /dev/null
+++ b/chromium/content/public/utility/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+content/public/child",
+]
diff --git a/chromium/content/public/utility/content_utility_client.h b/chromium/content/public/utility/content_utility_client.h
index 5a5d0e54e78..8a333e7ed7d 100644
--- a/chromium/content/public/utility/content_utility_client.h
+++ b/chromium/content/public/utility/content_utility_client.h
@@ -9,6 +9,8 @@
namespace content {
+class ServiceRegistry;
+
// Embedder API for participating in renderer logic.
class CONTENT_EXPORT ContentUtilityClient {
public:
@@ -19,6 +21,9 @@ class CONTENT_EXPORT ContentUtilityClient {
// Allows the embedder to filter messages.
virtual bool OnMessageReceived(const IPC::Message& message);
+
+ // Registers Mojo services.
+ virtual void RegisterMojoServices(ServiceRegistry* registry) {}
};
} // namespace content
diff --git a/chromium/content/public/utility/utility_thread.h b/chromium/content/public/utility/utility_thread.h
index 6e7cbd108d8..42bf10cf5ea 100644
--- a/chromium/content/public/utility/utility_thread.h
+++ b/chromium/content/public/utility/utility_thread.h
@@ -6,16 +6,11 @@
#define CONTENT_PUBLIC_UTILITY_UTILITY_THREAD_H_
#include "base/basictypes.h"
-#include "content/common/content_export.h"
-#include "ipc/ipc_sender.h"
-
-#if defined(OS_WIN)
-#include <windows.h>
-#endif
+#include "content/public/child/child_thread.h"
namespace content {
-class CONTENT_EXPORT UtilityThread : public IPC::Sender {
+class CONTENT_EXPORT UtilityThread : virtual public ChildThread {
public:
// Returns the one utility thread for this process. Note that this can only
// be accessed when running on the utility thread itself.
@@ -26,15 +21,6 @@ class CONTENT_EXPORT UtilityThread : public IPC::Sender {
// Releases the process if we are not (or no longer) in batch mode.
virtual void ReleaseProcessIfNeeded() = 0;
-
-#if defined(OS_WIN)
- // Request that the given font be loaded by the browser so it's cached by the
- // OS. Please see ChildProcessHost::PreCacheFont for details.
- virtual void PreCacheFont(const LOGFONT& log_font) = 0;
-
- // Release cached font.
- virtual void ReleaseCachedFonts() = 0;
-#endif
};
} // namespace content
diff --git a/chromium/content/renderer/BUILD.gn b/chromium/content/renderer/BUILD.gn
index 22acf49b724..bba336d7eb7 100644
--- a/chromium/content/renderer/BUILD.gn
+++ b/chromium/content/renderer/BUILD.gn
@@ -13,62 +13,57 @@ source_set("renderer") {
visibility = [ "//content/public/renderer:renderer_sources" ]
sources = rebase_path(content_renderer_gypi_values.private_renderer_sources,
- ".", "//content")
+ ".",
+ "//content")
configs += [
"//content:content_implementation",
+ "//build/config/compiler:no_size_t_to_int_warning",
]
deps = [
# TODO(GYP) bug 376846 remove this. This should be inherited from //net but
# those don't cross component boundaries.
"//crypto:platform",
-
"//base/allocator",
"//cc",
"//cc/blink",
+ "//components/scheduler:scheduler",
"//content:resources",
"//content/common:mojo_bindings",
"//content/public/child:child_sources",
"//content/public/common:common_sources",
"//content/public/common:mojo_bindings",
"//device/battery:mojo_bindings",
+ "//device/vibration:mojo_bindings",
"//gin",
"//gpu",
"//gpu/command_buffer/client:gles2_interface",
"//jingle:jingle_glue",
"//media",
"//media/blink",
- "//mojo/edk/js",
+ "//mojo/application/public/interfaces",
"//mojo/environment:chromium",
- "//mojo/public/js",
- "//mojo/public/interfaces/application",
"//net",
"//skia",
"//storage/common",
"//third_party/icu",
"//third_party/libjingle",
+ "//third_party/mojo/src/mojo/edk/js",
+ "//third_party/mojo/src/mojo/public/js",
"//third_party/npapi",
"//third_party/WebKit/public:blink",
"//third_party/widevine/cdm:version_h",
"//ui/accessibility",
"//ui/base",
"//ui/events:events_base",
- "//ui/events:dom4_keycode_converter",
+ "//ui/events:dom_keycode_converter",
"//ui/gl",
"//ui/native_theme",
"//ui/surface",
"//v8",
- "//webkit/common/gpu",
]
- if (!enable_notifications) {
- sources -= [
- "notification_provider.cc",
- "active_notification_tracker.cc",
- ]
- }
-
if (is_mac) {
sources -= [
"webscrollbarbehavior_impl_gtkoraura.cc",
@@ -81,10 +76,7 @@ source_set("renderer") {
}
if (is_android) {
- sources -= [
- "media/audio_decoder.cc",
- "media/crypto/encrypted_media_player_support_impl.cc",
- ]
+ sources -= [ "media/audio_decoder.cc" ]
sources += [
"external_popup_menu.cc",
"external_popup_menu.h",
@@ -92,9 +84,7 @@ source_set("renderer") {
# Add back the Linux file which Android shares.
set_sources_assignment_filter([])
- sources += [
- "render_view_linux.cc",
- ]
+ sources += [ "render_view_linux.cc" ]
deps += [
"//third_party/android_tools:cpu_features",
@@ -108,6 +98,8 @@ source_set("renderer") {
"java/gin_java_bridge_object.h",
"java/gin_java_bridge_value_converter.cc",
"java/gin_java_bridge_value_converter.h",
+ "java/gin_java_function_invocation_helper.cc",
+ "java/gin_java_function_invocation_helper.h",
]
}
@@ -132,8 +124,9 @@ source_set("renderer") {
if (enable_webrtc) {
sources += rebase_path(
- content_renderer_gypi_values.private_renderer_webrtc_sources,
- ".", "//content")
+ content_renderer_gypi_values.private_renderer_webrtc_sources,
+ ".",
+ "//content")
deps += [
"//crypto",
"//third_party/libyuv",
@@ -144,19 +137,21 @@ source_set("renderer") {
]
} else {
sources += [
- "media/webrtc_logging_noop.cc",
"media/webrtc_logging.h",
+ "media/webrtc_logging_noop.cc",
]
}
if (enable_plugins) {
sources += rebase_path(
- content_renderer_gypi_values.private_renderer_plugin_sources,
- ".", "//content")
+ content_renderer_gypi_values.private_renderer_plugin_sources,
+ ".",
+ "//content")
deps += [
- "//ppapi:ppapi_host",
- "//ppapi:ppapi_proxy",
- "//ppapi:ppapi_shared",
+ "//ppapi/host",
+ "//ppapi/proxy",
+ "//ppapi/shared_impl",
+ "//third_party/libvpx",
"//third_party/libyuv",
]
} else {
@@ -171,8 +166,9 @@ source_set("renderer") {
if (enable_plugins && enable_webrtc) {
sources += rebase_path(
- content_renderer_gypi_values.private_renderer_plugin_webrtc_sources,
- ".", "//content")
+ content_renderer_gypi_values.private_renderer_plugin_webrtc_sources,
+ ".",
+ "//content")
}
if (!enable_pepper_cdms) {
@@ -197,4 +193,12 @@ source_set("renderer") {
"media/crypto/renderer_cdm_manager.h",
]
}
+
+ if (enable_media_mojo_renderer) {
+ sources += [
+ "media/media_renderer_service_provider.cc",
+ "media/media_renderer_service_provider.h",
+ ]
+ deps += [ "//media/mojo/services:renderer_proxy" ]
+ }
}
diff --git a/chromium/content/renderer/DEPS b/chromium/content/renderer/DEPS
index 3ddb64470fc..1f43f93727d 100644
--- a/chromium/content/renderer/DEPS
+++ b/chromium/content/renderer/DEPS
@@ -1,8 +1,14 @@
include_rules = [
+ # Allow inclusion of specific components that we depend on. We may only
+ # depend on components which we share with the mojo html_viewer.
+ "+components/scheduler",
+
"+cc/blink",
+ "+content/public/child",
"+content/public/renderer",
"+content/child",
"+device/battery", # For battery status service.
+ "+device/vibration",
"+gin",
"+jingle/glue",
"+media", # For audio input/output and audio/video decoding.
diff --git a/chromium/content/renderer/OWNERS b/chromium/content/renderer/OWNERS
index b9a7ad47651..097b4915e23 100644
--- a/chromium/content/renderer/OWNERS
+++ b/chromium/content/renderer/OWNERS
@@ -1,5 +1,3 @@
-jamesr@chromium.org
-
# Mac Sandbox profiles.
per-file *.sb=set noparent
per-file *.sb=jeremy@chromium.org
diff --git a/chromium/content/renderer/accessibility/blink_ax_enum_conversion.cc b/chromium/content/renderer/accessibility/blink_ax_enum_conversion.cc
index 02d73fd5319..fcc55a94f24 100644
--- a/chromium/content/renderer/accessibility/blink_ax_enum_conversion.cc
+++ b/chromium/content/renderer/accessibility/blink_ax_enum_conversion.cc
@@ -43,6 +43,9 @@ uint32 AXStateFromBlink(const blink::WebAXObject& o) {
if (o.isLinked())
state |= (1 << ui::AX_STATE_LINKED);
+ if (o.isMultiline())
+ state |= (1 << ui::AX_STATE_MULTILINE);
+
if (o.isMultiSelectable())
state |= (1 << ui::AX_STATE_MULTISELECTABLE);
@@ -73,8 +76,10 @@ uint32 AXStateFromBlink(const blink::WebAXObject& o) {
if (o.isEnabled())
state |= (1 << ui::AX_STATE_ENABLED);
- if (o.isVertical())
+ if (o.orientation() == blink::WebAXOrientationVertical)
state |= (1 << ui::AX_STATE_VERTICAL);
+ else if (o.orientation() == blink::WebAXOrientationHorizontal)
+ state |= (1 << ui::AX_STATE_HORIZONTAL);
if (o.isVisited())
state |= (1 << ui::AX_STATE_VISITED);
@@ -98,14 +103,14 @@ ui::AXRole AXRoleFromBlink(blink::WebAXRole role) {
return ui::AX_ROLE_BANNER;
case blink::WebAXRoleBlockquote:
return ui::AX_ROLE_BLOCKQUOTE;
- case blink::WebAXRoleBrowser:
- return ui::AX_ROLE_BROWSER;
case blink::WebAXRoleBusyIndicator:
return ui::AX_ROLE_BUSY_INDICATOR;
case blink::WebAXRoleButton:
return ui::AX_ROLE_BUTTON;
case blink::WebAXRoleCanvas:
return ui::AX_ROLE_CANVAS;
+ case blink::WebAXRoleCaption:
+ return ui::AX_ROLE_CAPTION;
case blink::WebAXRoleCell:
return ui::AX_ROLE_CELL;
case blink::WebAXRoleCheckBox:
@@ -146,10 +151,6 @@ ui::AXRole AXRoleFromBlink(blink::WebAXRole role) {
return ui::AX_ROLE_DIV;
case blink::WebAXRoleDocument:
return ui::AX_ROLE_DOCUMENT;
- case blink::WebAXRoleDrawer:
- return ui::AX_ROLE_DRAWER;
- case blink::WebAXRoleEditableText:
- return ui::AX_ROLE_EDITABLE_TEXT;
case blink::WebAXRoleEmbeddedObject:
return ui::AX_ROLE_EMBEDDED_OBJECT;
case blink::WebAXRoleFigcaption:
@@ -164,16 +165,12 @@ ui::AXRole AXRoleFromBlink(blink::WebAXRole role) {
return ui::AX_ROLE_GRID;
case blink::WebAXRoleGroup:
return ui::AX_ROLE_GROUP;
- case blink::WebAXRoleGrowArea:
- return ui::AX_ROLE_GROW_AREA;
case blink::WebAXRoleHeading:
return ui::AX_ROLE_HEADING;
- case blink::WebAXRoleHelpTag:
- return ui::AX_ROLE_HELP_TAG;
- case blink::WebAXRoleHorizontalRule:
- return ui::AX_ROLE_HORIZONTAL_RULE;
case blink::WebAXRoleIframe:
return ui::AX_ROLE_IFRAME;
+ case blink::WebAXRoleIframePresentational:
+ return ui::AX_ROLE_IFRAME_PRESENTATIONAL;
case blink::WebAXRoleIgnored:
return ui::AX_ROLE_IGNORED;
case blink::WebAXRoleImage:
@@ -182,8 +179,6 @@ ui::AXRole AXRoleFromBlink(blink::WebAXRole role) {
return ui::AX_ROLE_IMAGE_MAP;
case blink::WebAXRoleImageMapLink:
return ui::AX_ROLE_IMAGE_MAP_LINK;
- case blink::WebAXRoleIncrementor:
- return ui::AX_ROLE_INCREMENTOR;
case blink::WebAXRoleInlineTextBox:
return ui::AX_ROLE_INLINE_TEXT_BOX;
case blink::WebAXRoleLabel:
@@ -210,8 +205,6 @@ ui::AXRole AXRoleFromBlink(blink::WebAXRole role) {
return ui::AX_ROLE_MARQUEE;
case blink::WebAXRoleMath:
return ui::AX_ROLE_MATH;
- case blink::WebAXRoleMatte:
- return ui::AX_ROLE_MATTE;
case blink::WebAXRoleMenu:
return ui::AX_ROLE_MENU;
case blink::WebAXRoleMenuBar:
@@ -258,12 +251,12 @@ ui::AXRole AXRoleFromBlink(blink::WebAXRole role) {
return ui::AX_ROLE_ROOT_WEB_AREA;
case blink::WebAXRoleRow:
return ui::AX_ROLE_ROW;
+ case blink::WebAXRoleRuby:
+ return ui::AX_ROLE_RUBY;
case blink::WebAXRoleRowHeader:
return ui::AX_ROLE_ROW_HEADER;
case blink::WebAXRoleRuler:
return ui::AX_ROLE_RULER;
- case blink::WebAXRoleRulerMarker:
- return ui::AX_ROLE_RULER_MARKER;
case blink::WebAXRoleSVGRoot:
return ui::AX_ROLE_SVG_ROOT;
case blink::WebAXRoleScrollArea:
@@ -274,8 +267,8 @@ ui::AXRole AXRoleFromBlink(blink::WebAXRole role) {
return ui::AX_ROLE_SEAMLESS_WEB_AREA;
case blink::WebAXRoleSearch:
return ui::AX_ROLE_SEARCH;
- case blink::WebAXRoleSheet:
- return ui::AX_ROLE_SHEET;
+ case blink::WebAXRoleSearchBox:
+ return ui::AX_ROLE_SEARCH_BOX;
case blink::WebAXRoleSlider:
return ui::AX_ROLE_SLIDER;
case blink::WebAXRoleSliderThumb:
@@ -284,16 +277,14 @@ ui::AXRole AXRoleFromBlink(blink::WebAXRole role) {
return ui::AX_ROLE_SPIN_BUTTON;
case blink::WebAXRoleSpinButtonPart:
return ui::AX_ROLE_SPIN_BUTTON_PART;
- case blink::WebAXRoleSplitGroup:
- return ui::AX_ROLE_SPLIT_GROUP;
case blink::WebAXRoleSplitter:
return ui::AX_ROLE_SPLITTER;
case blink::WebAXRoleStaticText:
return ui::AX_ROLE_STATIC_TEXT;
case blink::WebAXRoleStatus:
return ui::AX_ROLE_STATUS;
- case blink::WebAXRoleSystemWide:
- return ui::AX_ROLE_SYSTEM_WIDE;
+ case blink::WebAXRoleSwitch:
+ return ui::AX_ROLE_SWITCH;
case blink::WebAXRoleTab:
return ui::AX_ROLE_TAB;
case blink::WebAXRoleTabGroup:
@@ -306,8 +297,6 @@ ui::AXRole AXRoleFromBlink(blink::WebAXRole role) {
return ui::AX_ROLE_TABLE;
case blink::WebAXRoleTableHeaderContainer:
return ui::AX_ROLE_TABLE_HEADER_CONTAINER;
- case blink::WebAXRoleTextArea:
- return ui::AX_ROLE_TEXT_AREA;
case blink::WebAXRoleTextField:
return ui::AX_ROLE_TEXT_FIELD;
case blink::WebAXRoleTime:
@@ -328,10 +317,10 @@ ui::AXRole AXRoleFromBlink(blink::WebAXRole role) {
return ui::AX_ROLE_UNKNOWN;
case blink::WebAXRoleUserInterfaceTooltip:
return ui::AX_ROLE_TOOLTIP;
- case blink::WebAXRoleValueIndicator:
- return ui::AX_ROLE_VALUE_INDICATOR;
case blink::WebAXRoleWebArea:
return ui::AX_ROLE_WEB_AREA;
+ case blink::WebAXRoleLineBreak:
+ return ui::AX_ROLE_LINE_BREAK;
case blink::WebAXRoleWindow:
return ui::AX_ROLE_WINDOW;
default:
@@ -371,8 +360,10 @@ ui::AXEvent AXEventFromBlink(blink::WebAXEvent event) {
return ui::AX_EVENT_LOCATION_CHANGED;
case blink::WebAXEventMenuListItemSelected:
return ui::AX_EVENT_MENU_LIST_ITEM_SELECTED;
+ case blink::WebAXEventMenuListItemUnselected:
+ return ui::AX_EVENT_MENU_LIST_ITEM_SELECTED;
case blink::WebAXEventMenuListValueChanged:
- return ui::AX_EVENT_MENU_LIST_VALUE_CHANGED;
+ return ui::AX_EVENT_MENU_LIST_VALUE_CHANGED;
case blink::WebAXEventRowCollapsed:
return ui::AX_EVENT_ROW_COLLAPSED;
case blink::WebAXEventRowCountChanged:
@@ -402,13 +393,13 @@ ui::AXTextDirection AXTextDirectionFromBlink(
blink::WebAXTextDirection text_direction) {
switch (text_direction) {
case blink::WebAXTextDirectionLR:
- return ui::AX_TEXT_DIRECTION_LR;
+ return ui::AX_TEXT_DIRECTION_LTR;
case blink::WebAXTextDirectionRL:
- return ui::AX_TEXT_DIRECTION_RL;
+ return ui::AX_TEXT_DIRECTION_RTL;
case blink::WebAXTextDirectionTB:
- return ui::AX_TEXT_DIRECTION_TB;
+ return ui::AX_TEXT_DIRECTION_TTB;
case blink::WebAXTextDirectionBT:
- return ui::AX_TEXT_DIRECTION_BT;
+ return ui::AX_TEXT_DIRECTION_BTT;
default:
NOTREACHED();
}
@@ -416,4 +407,59 @@ ui::AXTextDirection AXTextDirectionFromBlink(
return ui::AX_TEXT_DIRECTION_NONE;
}
-} // namespace content
+ui::AXTextStyle AXTextStyleFromBlink(blink::WebAXTextStyle text_style) {
+ unsigned int browser_text_style = ui::AX_TEXT_STYLE_NONE;
+ if (text_style & blink::WebAXTextStyleBold)
+ browser_text_style |= ui::AX_TEXT_STYLE_BOLD;
+ if (text_style & blink::WebAXTextStyleItalic)
+ browser_text_style |= ui::AX_TEXT_STYLE_ITALIC;
+ if (text_style & blink::WebAXTextStyleUnderline)
+ browser_text_style |= ui::AX_TEXT_STYLE_UNDERLINE;
+ if (text_style & blink::WebAXTextStyleLineThrough)
+ browser_text_style |= ui::AX_TEXT_STYLE_LINE_THROUGH;
+ return static_cast<ui::AXTextStyle>(browser_text_style);
+}
+
+ui::AXInvalidState AXInvalidStateFromBlink(
+ blink::WebAXInvalidState invalid_state) {
+ switch (invalid_state) {
+ case blink::WebAXInvalidStateUndefined:
+ return ui::AX_INVALID_STATE_NONE;
+ case blink::WebAXInvalidStateFalse:
+ return ui::AX_INVALID_STATE_FALSE;
+ case blink::WebAXInvalidStateTrue:
+ return ui::AX_INVALID_STATE_TRUE;
+ case blink::WebAXInvalidStateSpelling:
+ return ui::AX_INVALID_STATE_SPELLING;
+ case blink::WebAXInvalidStateGrammar:
+ return ui::AX_INVALID_STATE_GRAMMAR;
+ case blink::WebAXInvalidStateOther:
+ return ui::AX_INVALID_STATE_OTHER;
+ default:
+ NOTREACHED();
+ }
+
+ return ui::AX_INVALID_STATE_NONE;
+}
+
+ui::AXSortDirection AXSortDirectionFromBlink(
+ blink::WebAXSortDirection sort_direction) {
+ switch (sort_direction) {
+ case blink::WebAXSortDirectionUndefined:
+ return ui::AX_SORT_DIRECTION_NONE;
+ case blink::WebAXSortDirectionNone:
+ return ui::AX_SORT_DIRECTION_UNSORTED;
+ case blink::WebAXSortDirectionAscending:
+ return ui::AX_SORT_DIRECTION_ASCENDING;
+ case blink::WebAXSortDirectionDescending:
+ return ui::AX_SORT_DIRECTION_DESCENDING;
+ case blink::WebAXSortDirectionOther:
+ return ui::AX_SORT_DIRECTION_OTHER;
+ default:
+ NOTREACHED();
+ }
+
+ return ui::AX_SORT_DIRECTION_NONE;
+}
+
+} // Namespace content.
diff --git a/chromium/content/renderer/accessibility/blink_ax_enum_conversion.h b/chromium/content/renderer/accessibility/blink_ax_enum_conversion.h
index b7c41a10e90..4c27400fa19 100644
--- a/chromium/content/renderer/accessibility/blink_ax_enum_conversion.h
+++ b/chromium/content/renderer/accessibility/blink_ax_enum_conversion.h
@@ -27,6 +27,18 @@ uint32 AXStateFromBlink(const blink::WebAXObject& o);
ui::AXTextDirection AXTextDirectionFromBlink(
blink::WebAXTextDirection text_direction);
+ui::AXTextStyle AXTextStyleFromBlink(blink::WebAXTextStyle text_style);
+
+// Convert a Blink WebAXInvalidState to an AXInvalidState defined in
+// ui/accessibility.
+ui::AXInvalidState AXInvalidStateFromBlink(
+ blink::WebAXInvalidState invalid_state);
+
+// Convert a Blink WebAXSortDirection to an AXSortDirection defined in
+// ui/accessibility.
+ui::AXSortDirection AXSortDirectionFromBlink(
+ blink::WebAXSortDirection sort_direction);
+
} // namespace content
#endif // CONTENT_RENDERER_ACCESSIBILITY_BLINK_AX_ENUM_CONVERSION_H_
diff --git a/chromium/content/renderer/accessibility/blink_ax_tree_source.cc b/chromium/content/renderer/accessibility/blink_ax_tree_source.cc
index 22c66acbdaa..8ae828e97ed 100644
--- a/chromium/content/renderer/accessibility/blink_ax_tree_source.cc
+++ b/chromium/content/renderer/accessibility/blink_ax_tree_source.cc
@@ -70,10 +70,12 @@ std::string GetEquivalentAriaRoleString(const ui::AXRole role) {
return "button";
case ui::AX_ROLE_COMPLEMENTARY:
return "complementary";
+ case ui::AX_ROLE_FIGURE:
+ return "figure";
case ui::AX_ROLE_FOOTER:
return "contentinfo";
- case ui::AX_ROLE_HORIZONTAL_RULE:
- return "separator";
+ case ui::AX_ROLE_HEADING:
+ return "heading";
case ui::AX_ROLE_IMAGE:
return "img";
case ui::AX_ROLE_MAIN:
@@ -115,6 +117,10 @@ BlinkAXTreeSource::BlinkAXTreeSource(RenderFrameImpl* render_frame)
BlinkAXTreeSource::~BlinkAXTreeSource() {
}
+void BlinkAXTreeSource::SetRoot(blink::WebAXObject root) {
+ root_ = root;
+}
+
bool BlinkAXTreeSource::IsInTree(blink::WebAXObject node) const {
const blink::WebAXObject& root = GetRoot();
while (IsValid(node)) {
@@ -134,6 +140,8 @@ void BlinkAXTreeSource::CollectChildFrameIdMapping(
}
blink::WebAXObject BlinkAXTreeSource::GetRoot() const {
+ if (!root_.isNull())
+ return root_;
return GetMainDocument().accessibilityObject();
}
@@ -216,7 +224,7 @@ void BlinkAXTreeSource::SerializeNode(blink::WebAXObject src,
dst->state = AXStateFromBlink(src);
dst->location = src.boundingBoxRect();
dst->id = src.axID();
- std::string name = UTF16ToUTF8(src.title());
+ std::string name = UTF16ToUTF8(src.deprecatedTitle());
std::string value;
if (src.valueDescription().length()) {
@@ -226,18 +234,42 @@ void BlinkAXTreeSource::SerializeNode(blink::WebAXObject src,
dst->AddStringAttribute(ui::AX_ATTR_VALUE, UTF16ToUTF8(src.stringValue()));
}
- if (dst->role == ui::AX_ROLE_COLOR_WELL) {
- int r, g, b;
- src.colorValue(r, g, b);
- dst->AddIntAttribute(ui::AX_ATTR_COLOR_VALUE_RED, r);
- dst->AddIntAttribute(ui::AX_ATTR_COLOR_VALUE_GREEN, g);
- dst->AddIntAttribute(ui::AX_ATTR_COLOR_VALUE_BLUE, b);
+ if (dst->role == ui::AX_ROLE_COLOR_WELL)
+ dst->AddIntAttribute(ui::AX_ATTR_COLOR_VALUE, src.colorValue());
+
+
+ // Text attributes.
+ if (src.backgroundColor())
+ dst->AddIntAttribute(ui::AX_ATTR_BACKGROUND_COLOR, src.backgroundColor());
+
+ if (src.color())
+ dst->AddIntAttribute(ui::AX_ATTR_COLOR, src.color());
+
+ // Font size is in pixels.
+ if (src.fontSize())
+ dst->AddFloatAttribute(ui::AX_ATTR_FONT_SIZE, src.fontSize());
+
+ if (src.invalidState()) {
+ dst->AddIntAttribute(ui::AX_ATTR_INVALID_STATE,
+ AXInvalidStateFromBlink(src.invalidState()));
+ }
+ if (src.invalidState() == blink::WebAXInvalidStateOther) {
+ dst->AddStringAttribute(ui::AX_ATTR_ARIA_INVALID_VALUE,
+ UTF16ToUTF8(src.ariaInvalidValue()));
}
- if (dst->role == ui::AX_ROLE_INLINE_TEXT_BOX) {
+ if (src.textDirection()) {
dst->AddIntAttribute(ui::AX_ATTR_TEXT_DIRECTION,
AXTextDirectionFromBlink(src.textDirection()));
+ }
+
+ if (src.textStyle()) {
+ dst->AddIntAttribute(ui::AX_ATTR_TEXT_STYLE,
+ AXTextStyleFromBlink(src.textStyle()));
+ }
+
+ if (dst->role == ui::AX_ROLE_INLINE_TEXT_BOX) {
WebVector<int> src_character_offsets;
src.characterOffsets(src_character_offsets);
std::vector<int32> character_offsets;
@@ -265,31 +297,41 @@ void BlinkAXTreeSource::SerializeNode(blink::WebAXObject src,
dst->AddStringAttribute(ui::AX_ATTR_ACCESS_KEY,
UTF16ToUTF8(src.accessKey()));
}
+
if (src.actionVerb().length())
dst->AddStringAttribute(ui::AX_ATTR_ACTION, UTF16ToUTF8(src.actionVerb()));
+ if (src.ariaAutoComplete().length())
+ dst->AddStringAttribute(ui::AX_ATTR_AUTO_COMPLETE,
+ UTF16ToUTF8(src.ariaAutoComplete()));
if (src.isAriaReadOnly())
dst->AddBoolAttribute(ui::AX_ATTR_ARIA_READONLY, true);
if (src.isButtonStateMixed())
dst->AddBoolAttribute(ui::AX_ATTR_BUTTON_MIXED, true);
if (src.canSetValueAttribute())
dst->AddBoolAttribute(ui::AX_ATTR_CAN_SET_VALUE, true);
- if (src.accessibilityDescription().length()) {
- dst->AddStringAttribute(ui::AX_ATTR_DESCRIPTION,
- UTF16ToUTF8(src.accessibilityDescription()));
+ if (src.deprecatedAccessibilityDescription().length()) {
+ dst->AddStringAttribute(
+ ui::AX_ATTR_DESCRIPTION,
+ UTF16ToUTF8(src.deprecatedAccessibilityDescription()));
}
if (src.hasComputedStyle()) {
dst->AddStringAttribute(ui::AX_ATTR_DISPLAY,
UTF16ToUTF8(src.computedStyleDisplay()));
}
- if (src.helpText().length())
- dst->AddStringAttribute(ui::AX_ATTR_HELP, UTF16ToUTF8(src.helpText()));
+ if (src.deprecatedHelpText().length())
+ dst->AddStringAttribute(ui::AX_ATTR_HELP,
+ UTF16ToUTF8(src.deprecatedHelpText()));
+ if (src.deprecatedPlaceholder().length()) {
+ dst->AddStringAttribute(ui::AX_ATTR_PLACEHOLDER,
+ UTF16ToUTF8(src.deprecatedPlaceholder()));
+ }
if (src.keyboardShortcut().length()) {
dst->AddStringAttribute(ui::AX_ATTR_SHORTCUT,
UTF16ToUTF8(src.keyboardShortcut()));
}
- if (!src.titleUIElement().isDetached()) {
+ if (!src.deprecatedTitleUIElement().isDetached()) {
dst->AddIntAttribute(ui::AX_ATTR_TITLE_UI_ELEMENT,
- src.titleUIElement().axID());
+ src.deprecatedTitleUIElement().axID());
}
if (!src.ariaActiveDescendant().isDetached()) {
dst->AddIntAttribute(ui::AX_ATTR_ACTIVEDESCENDANT_ID,
@@ -308,6 +350,12 @@ void BlinkAXTreeSource::SerializeNode(blink::WebAXObject src,
src.hierarchicalLevel());
}
+ if (src.setSize())
+ dst->AddIntAttribute(ui::AX_ATTR_SET_SIZE, src.setSize());
+
+ if (src.posInSet())
+ dst->AddIntAttribute(ui::AX_ATTR_POS_IN_SET, src.posInSet());
+
// Treat the active list box item as focused.
if (dst->role == ui::AX_ROLE_LIST_BOX_OPTION &&
src.isSelectedOptionActive()) {
@@ -337,9 +385,7 @@ void BlinkAXTreeSource::SerializeNode(blink::WebAXObject src,
dst->html_attributes.push_back(std::make_pair(name, value));
}
- if (dst->role == ui::AX_ROLE_EDITABLE_TEXT ||
- dst->role == ui::AX_ROLE_TEXT_AREA ||
- dst->role == ui::AX_ROLE_TEXT_FIELD) {
+ if (!src.isReadOnly() || dst->role == ui::AX_ROLE_TEXT_FIELD) {
dst->AddIntAttribute(ui::AX_ATTR_TEXT_SEL_START, src.selectionStart());
dst->AddIntAttribute(ui::AX_ATTR_TEXT_SEL_END, src.selectionEnd());
@@ -360,6 +406,12 @@ void BlinkAXTreeSource::SerializeNode(blink::WebAXObject src,
}
}
+ blink::WebAXOptionalBool optionalBool = src.isAriaGrabbed();
+ if (optionalBool == blink::WebAXOptionalBoolFalse)
+ dst->AddBoolAttribute(ui::AX_ATTR_GRABBED, false);
+ else if (optionalBool == blink::WebAXOptionalBoolTrue)
+ dst->AddBoolAttribute(ui::AX_ATTR_GRABBED, true);
+
// ARIA role.
if (element.hasAttribute("role")) {
dst->AddStringAttribute(ui::AX_ATTR_ROLE,
@@ -384,8 +436,12 @@ void BlinkAXTreeSource::SerializeNode(blink::WebAXObject src,
if (src.isInLiveRegion()) {
dst->AddBoolAttribute(ui::AX_ATTR_LIVE_ATOMIC, src.liveRegionAtomic());
dst->AddBoolAttribute(ui::AX_ATTR_LIVE_BUSY, src.liveRegionBusy());
- dst->AddStringAttribute(ui::AX_ATTR_LIVE_STATUS,
- UTF16ToUTF8(src.liveRegionStatus()));
+ if (src.liveRegionBusy())
+ dst->state |= (1 << ui::AX_STATE_BUSY);
+ if (!src.liveRegionStatus().isEmpty()) {
+ dst->AddStringAttribute(ui::AX_ATTR_LIVE_STATUS,
+ UTF16ToUTF8(src.liveRegionStatus()));
+ }
dst->AddStringAttribute(ui::AX_ATTR_LIVE_RELEVANT,
UTF16ToUTF8(src.liveRegionRelevant()));
dst->AddBoolAttribute(ui::AX_ATTR_CONTAINER_LIVE_ATOMIC,
@@ -399,6 +455,7 @@ void BlinkAXTreeSource::SerializeNode(blink::WebAXObject src,
}
if (dst->role == ui::AX_ROLE_PROGRESS_INDICATOR ||
+ dst->role == ui::AX_ROLE_METER ||
dst->role == ui::AX_ROLE_SCROLL_BAR ||
dst->role == ui::AX_ROLE_SLIDER ||
dst->role == ui::AX_ROLE_SPIN_BUTTON) {
@@ -409,8 +466,7 @@ void BlinkAXTreeSource::SerializeNode(blink::WebAXObject src,
src.minValueForRange());
}
- if (dst->role == ui::AX_ROLE_DOCUMENT ||
- dst->role == ui::AX_ROLE_WEB_AREA) {
+ if (dst->role == ui::AX_ROLE_WEB_AREA) {
dst->AddStringAttribute(ui::AX_ATTR_HTML_TAG, "#document");
const WebDocument& document = src.document();
if (name.empty())
@@ -517,6 +573,12 @@ void BlinkAXTreeSource::SerializeNode(blink::WebAXObject src,
dst->AddIntAttribute(ui::AX_ATTR_TABLE_CELL_ROW_SPAN, src.cellRowSpan());
}
+ if ((dst->role == ui::AX_ROLE_ROW_HEADER ||
+ dst->role == ui::AX_ROLE_COLUMN_HEADER) && src.sortDirection()) {
+ dst->AddIntAttribute(ui::AX_ATTR_SORT_DIRECTION,
+ AXSortDirectionFromBlink(src.sortDirection()));
+ }
+
dst->AddStringAttribute(ui::AX_ATTR_NAME, name);
// Add the ids of *indirect* children - those who are children of this node,
@@ -541,17 +603,22 @@ void BlinkAXTreeSource::SerializeNode(blink::WebAXObject src,
AddIntListAttributeFromWebObjects(ui::AX_ATTR_CONTROLS_IDS, controls, dst);
WebVector<WebAXObject> describedby;
- if (src.ariaDescribedby(describedby)) {
+ if (src.deprecatedAriaDescribedby(describedby)) {
AddIntListAttributeFromWebObjects(
ui::AX_ATTR_DESCRIBEDBY_IDS, describedby, dst);
}
+ if (src.ariaDropEffect().length()) {
+ dst->AddStringAttribute(ui::AX_ATTR_DROPEFFECT,
+ UTF16ToUTF8(src.ariaDropEffect()));
+ }
+
WebVector<WebAXObject> flowTo;
if (src.ariaFlowTo(flowTo))
AddIntListAttributeFromWebObjects(ui::AX_ATTR_FLOWTO_IDS, flowTo, dst);
WebVector<WebAXObject> labelledby;
- if (src.ariaLabelledby(labelledby)) {
+ if (src.deprecatedAriaLabelledby(labelledby)) {
AddIntListAttributeFromWebObjects(
ui::AX_ATTR_LABELLEDBY_IDS, labelledby, dst);
}
diff --git a/chromium/content/renderer/accessibility/blink_ax_tree_source.h b/chromium/content/renderer/accessibility/blink_ax_tree_source.h
index b08108b12e5..ae93ff4b115 100644
--- a/chromium/content/renderer/accessibility/blink_ax_tree_source.h
+++ b/chromium/content/renderer/accessibility/blink_ax_tree_source.h
@@ -19,6 +19,11 @@ class BlinkAXTreeSource
BlinkAXTreeSource(RenderFrameImpl* render_frame);
~BlinkAXTreeSource() override;
+ // It may be necessary to call SetRoot if you're using a WebScopedAXContext,
+ // because BlinkAXTreeSource can't get the root of the tree from the
+ // WebDocument if accessibility isn't enabled globally.
+ void SetRoot(blink::WebAXObject root);
+
// Call this to have BlinkAXTreeSource collect a mapping from
// node ids to the frame routing id for an out-of-process iframe during
// calls to SerializeNode.
@@ -54,6 +59,7 @@ class BlinkAXTreeSource
private:
RenderFrameImpl* render_frame_;
+ blink::WebAXObject root_;
std::map<int32, int>* node_to_frame_routing_id_map_;
std::map<int32, int>* node_to_browser_plugin_instance_id_map_;
int accessibility_focus_id_;
diff --git a/chromium/content/renderer/accessibility/renderer_accessibility.cc b/chromium/content/renderer/accessibility/renderer_accessibility.cc
index ac83a767997..8e3b41c4713 100644
--- a/chromium/content/renderer/accessibility/renderer_accessibility.cc
+++ b/chromium/content/renderer/accessibility/renderer_accessibility.cc
@@ -25,11 +25,29 @@ using blink::WebLocalFrame;
using blink::WebNode;
using blink::WebPoint;
using blink::WebRect;
+using blink::WebScopedAXContext;
using blink::WebSettings;
using blink::WebView;
namespace content {
+// static
+void RendererAccessibility::SnapshotAccessibilityTree(
+ RenderFrameImpl* render_frame,
+ ui::AXTreeUpdate* response) {
+ DCHECK(render_frame);
+ DCHECK(response);
+ if (!render_frame->GetWebFrame())
+ return;
+
+ WebDocument document = render_frame->GetWebFrame()->document();
+ WebScopedAXContext context(document);
+ BlinkAXTreeSource tree_source(render_frame);
+ tree_source.SetRoot(context.root());
+ ui::AXTreeSerializer<blink::WebAXObject> serializer(&tree_source);
+ serializer.SerializeChanges(context.root(), response);
+}
+
RendererAccessibility::RendererAccessibility(RenderFrameImpl* render_frame)
: RenderFrameObserver(render_frame),
render_frame_(render_frame),
@@ -108,7 +126,8 @@ void RendererAccessibility::HandleAccessibilityFindInPageResult(
Send(new AccessibilityHostMsg_FindInPageResult(routing_id(), params));
}
-void RendererAccessibility::FocusedNodeChanged(const WebNode& node) {
+void RendererAccessibility::AccessibilityFocusedNodeChanged(
+ const WebNode& node) {
const WebDocument& document = GetMainDocument();
if (document.isNull())
return;
@@ -234,13 +253,6 @@ void RendererAccessibility::SendPendingAccessibilityEvents() {
if (!tree_source_.IsInTree(obj))
continue;
- // When we get a "selected children changed" event, Blink
- // doesn't also send us events for each child that changed
- // selection state, so make sure we re-send that whole subtree.
- if (event.event_type == ui::AX_EVENT_SELECTED_CHILDREN_CHANGED) {
- serializer_.DeleteClientSubtree(obj);
- }
-
AccessibilityHostMsg_EventParams event_msg;
tree_source_.CollectChildFrameIdMapping(
&event_msg.node_to_frame_routing_id_map,
@@ -257,9 +269,9 @@ void RendererAccessibility::SendPendingAccessibilityEvents() {
event_msg.update.nodes[i].location;
}
- VLOG(0) << "Accessibility event: " << ui::ToString(event.event_type)
- << " on node id " << event_msg.id
- << "\n" << event_msg.update.ToString();
+ DVLOG(0) << "Accessibility event: " << ui::ToString(event.event_type)
+ << " on node id " << event_msg.id
+ << "\n" << event_msg.update.ToString();
}
Send(new AccessibilityHostMsg_Events(routing_id(), event_msgs, reset_token_));
diff --git a/chromium/content/renderer/accessibility/renderer_accessibility.h b/chromium/content/renderer/accessibility/renderer_accessibility.h
index 2c3d8e846b4..5ab857f6348 100644
--- a/chromium/content/renderer/accessibility/renderer_accessibility.h
+++ b/chromium/content/renderer/accessibility/renderer_accessibility.h
@@ -46,6 +46,11 @@ class RenderFrameImpl;
// (e.g., change focus, or click on a button).
class CONTENT_EXPORT RendererAccessibility : public RenderFrameObserver {
public:
+ // Request a one-time snapshot of the accessibility tree without
+ // enabling accessibility if it wasn't already enabled.
+ static void SnapshotAccessibilityTree(RenderFrameImpl* render_frame,
+ ui::AXTreeUpdate* response);
+
explicit RendererAccessibility(RenderFrameImpl* render_frame);
~RendererAccessibility() override;
@@ -65,7 +70,7 @@ class CONTENT_EXPORT RendererAccessibility : public RenderFrameObserver {
const blink::WebAXObject& end_object,
int end_offset);
- void FocusedNodeChanged(const blink::WebNode& node);
+ void AccessibilityFocusedNodeChanged(const blink::WebNode& node);
// This can be called before deleting a RendererAccessibility instance due
// to the accessibility mode changing, as opposed to during frame destruction
diff --git a/chromium/content/renderer/accessibility/renderer_accessibility_browsertest.cc b/chromium/content/renderer/accessibility/renderer_accessibility_browsertest.cc
index c173c94f9e0..667294305a5 100644
--- a/chromium/content/renderer/accessibility/renderer_accessibility_browsertest.cc
+++ b/chromium/content/renderer/accessibility/renderer_accessibility_browsertest.cc
@@ -59,10 +59,10 @@ class RendererAccessibilityTest : public RenderViewTest {
const IPC::Message* message =
sink_->GetUniqueMessageMatching(AccessibilityHostMsg_Events::ID);
ASSERT_TRUE(message);
- Tuple2<std::vector<AccessibilityHostMsg_EventParams>, int> param;
+ Tuple<std::vector<AccessibilityHostMsg_EventParams>, int> param;
AccessibilityHostMsg_Events::Read(message, &param);
- ASSERT_GE(param.a.size(), 1U);
- *params = param.a[0];
+ ASSERT_GE(get<0>(param).size(), 1U);
+ *params = get<0>(param)[0];
}
int CountAccessibilityNodesSentToBrowser() {
@@ -178,7 +178,8 @@ TEST_F(RendererAccessibilityTest,
accessibility->HandleAXEvent(
root_obj,
ui::AX_EVENT_VALUE_CHANGED);
- view()->GetMainRenderFrame()->OnSwapOut(kProxyRoutingId);
+ view()->GetMainRenderFrame()->OnSwapOut(kProxyRoutingId, true,
+ content::FrameReplicationState());
accessibility->SendPendingAccessibilityEvents();
EXPECT_FALSE(sink_->GetUniqueMessageMatching(
AccessibilityHostMsg_Events::ID));
@@ -188,17 +189,16 @@ TEST_F(RendererAccessibilityTest,
// message that was queued up before will be quickly discarded
// because the element it was referring to no longer exists,
// so the event here is from loading this new page.
- FrameMsg_Navigate_Params nav_params;
- nav_params.common_params.url = GURL("data:text/html,<p>Hello, again.</p>");
- nav_params.common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
- nav_params.common_params.transition = ui::PAGE_TRANSITION_TYPED;
- nav_params.current_history_list_length = 1;
- nav_params.current_history_list_offset = 0;
- nav_params.pending_history_list_offset = 1;
- nav_params.page_id = -1;
- nav_params.commit_params.browser_navigation_start =
- base::TimeTicks::FromInternalValue(1);
- frame()->OnNavigate(nav_params);
+ CommonNavigationParams common_params;
+ RequestNavigationParams request_params;
+ common_params.url = GURL("data:text/html,<p>Hello, again.</p>");
+ common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
+ common_params.transition = ui::PAGE_TRANSITION_TYPED;
+ request_params.current_history_list_length = 1;
+ request_params.current_history_list_offset = 0;
+ request_params.pending_history_list_offset = 1;
+ request_params.page_id = -1;
+ frame()->OnNavigate(common_params, StartNavigationParams(), request_params);
accessibility->SendPendingAccessibilityEvents();
EXPECT_TRUE(sink_->GetUniqueMessageMatching(
AccessibilityHostMsg_Events::ID));
@@ -404,9 +404,9 @@ TEST_F(RendererAccessibilityTest, EventOnObjectNotInTree) {
const IPC::Message* message =
sink_->GetUniqueMessageMatching(AccessibilityHostMsg_Events::ID);
ASSERT_TRUE(message);
- Tuple2<std::vector<AccessibilityHostMsg_EventParams>, int> param;
+ Tuple<std::vector<AccessibilityHostMsg_EventParams>, int> param;
AccessibilityHostMsg_Events::Read(message, &param);
- ASSERT_EQ(0U, param.a.size());
+ ASSERT_EQ(0U, get<0>(param).size());
}
} // namespace content
diff --git a/chromium/content/renderer/active_notification_tracker.cc b/chromium/content/renderer/active_notification_tracker.cc
deleted file mode 100644
index 2a958a5877d..00000000000
--- a/chromium/content/renderer/active_notification_tracker.cc
+++ /dev/null
@@ -1,67 +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/renderer/active_notification_tracker.h"
-
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "third_party/WebKit/public/web/WebNotification.h"
-
-using blink::WebNotification;
-
-namespace content {
-
-ActiveNotificationTracker::ActiveNotificationTracker() {}
-
-ActiveNotificationTracker::~ActiveNotificationTracker() {}
-
-bool ActiveNotificationTracker::GetId(
- const WebNotification& notification, int& id) {
- ReverseTable::iterator iter = reverse_notification_table_.find(notification);
- if (iter == reverse_notification_table_.end())
- return false;
- id = iter->second;
- return true;
-}
-
-bool ActiveNotificationTracker::GetNotification(
- int id, WebNotification* notification) {
- WebNotification* lookup = notification_table_.Lookup(id);
- if (!lookup)
- return false;
-
- *notification = *lookup;
- return true;
-}
-
-int ActiveNotificationTracker::RegisterNotification(
- const blink::WebNotification& proxy) {
- if (reverse_notification_table_.find(proxy)
- != reverse_notification_table_.end()) {
- return reverse_notification_table_[proxy];
- } else {
- WebNotification* notification = new WebNotification(proxy);
- int id = notification_table_.Add(notification);
- reverse_notification_table_[proxy] = id;
- return id;
- }
-}
-
-void ActiveNotificationTracker::UnregisterNotification(int id) {
- // We want to free the notification after removing it from the table.
- scoped_ptr<WebNotification> notification(notification_table_.Lookup(id));
- notification_table_.Remove(id);
- DCHECK(notification.get());
- if (notification)
- reverse_notification_table_.erase(*notification);
-}
-
-void ActiveNotificationTracker::Clear() {
- while (!reverse_notification_table_.empty()) {
- ReverseTable::iterator iter = reverse_notification_table_.begin();
- UnregisterNotification((*iter).second);
- }
-}
-
-} // namespace content
diff --git a/chromium/content/renderer/active_notification_tracker.h b/chromium/content/renderer/active_notification_tracker.h
deleted file mode 100644
index e3f64d16cd6..00000000000
--- a/chromium/content/renderer/active_notification_tracker.h
+++ /dev/null
@@ -1,47 +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_RENDERER_ACTIVE_NOTIFICATION_TRACKER_H_
-#define CONTENT_RENDERER_ACTIVE_NOTIFICATION_TRACKER_H_
-
-#include <map>
-
-#include "base/basictypes.h"
-#include "base/containers/hash_tables.h"
-#include "base/id_map.h"
-#include "content/common/content_export.h"
-#include "third_party/WebKit/public/web/WebNotification.h"
-
-namespace content {
-
-// This class manages the set of active Notification objects in either
-// a render or worker process. This class should be accessed only on
-// the main thread.
-class CONTENT_EXPORT ActiveNotificationTracker {
- public:
- ActiveNotificationTracker();
- ~ActiveNotificationTracker();
-
- // Methods for tracking active notification objects.
- int RegisterNotification(const blink::WebNotification& notification);
- void UnregisterNotification(int id);
- bool GetId(const blink::WebNotification& notification, int& id);
- bool GetNotification(int id, blink::WebNotification* notification);
-
- // Clears out all active notifications. Useful on page navigation.
- void Clear();
-
- private:
- typedef std::map<blink::WebNotification, int> ReverseTable;
-
- // Tracking maps for active notifications.
- IDMap<blink::WebNotification> notification_table_;
- ReverseTable reverse_notification_table_;
-
- DISALLOW_COPY_AND_ASSIGN(ActiveNotificationTracker);
-};
-
-} // namespace content
-
-#endif // CONTENT_RENDERER_ACTIVE_NOTIFICATION_TRACKER_H_
diff --git a/chromium/content/renderer/active_notification_tracker_unittest.cc b/chromium/content/renderer/active_notification_tracker_unittest.cc
deleted file mode 100644
index 88e8dcd054a..00000000000
--- a/chromium/content/renderer/active_notification_tracker_unittest.cc
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. 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/renderer/active_notification_tracker.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace content {
-
-TEST(ActiveNotificationTrackerTest, TestLookupAndClear) {
- ActiveNotificationTracker tracker;
-
- blink::WebNotification notification1;
- int id1 = tracker.RegisterNotification(notification1);
-
- blink::WebNotification notification2;
- int id2 = tracker.RegisterNotification(notification2);
-
- blink::WebNotification result;
- tracker.GetNotification(id1, &result);
- EXPECT_TRUE(result == notification1);
-
- tracker.GetNotification(id2, &result);
- EXPECT_TRUE(result == notification2);
-
- tracker.Clear();
-}
-
-} // namespace content
diff --git a/chromium/content/renderer/android/address_detector.h b/chromium/content/renderer/android/address_detector.h
index e612339adf4..1db869ef167 100644
--- a/chromium/content/renderer/android/address_detector.h
+++ b/chromium/content/renderer/android/address_detector.h
@@ -15,17 +15,17 @@ namespace content {
class AddressDetector : public ContentDetector {
public:
AddressDetector();
- virtual ~AddressDetector();
+ ~AddressDetector() override;
private:
// Implementation of ContentDetector.
- virtual bool FindContent(const base::string16::const_iterator& begin,
- const base::string16::const_iterator& end,
- size_t* start_pos,
- size_t* end_pos,
- std::string* content_text) override;
- virtual GURL GetIntentURL(const std::string& content_text) override;
- virtual size_t GetMaximumContentLength() override;
+ bool FindContent(const base::string16::const_iterator& begin,
+ const base::string16::const_iterator& end,
+ size_t* start_pos,
+ size_t* end_pos,
+ std::string* content_text) override;
+ GURL GetIntentURL(const std::string& content_text) override;
+ size_t GetMaximumContentLength() override;
std::string GetContentText(const base::string16& text);
diff --git a/chromium/content/renderer/android/email_detector.h b/chromium/content/renderer/android/email_detector.h
index 97b35c72189..8d108492b65 100644
--- a/chromium/content/renderer/android/email_detector.h
+++ b/chromium/content/renderer/android/email_detector.h
@@ -23,13 +23,13 @@ class CONTENT_EXPORT EmailDetector : public ContentDetector {
friend class EmailDetectorTest;
// Implementation of ContentDetector.
- virtual bool FindContent(const base::string16::const_iterator& begin,
- const base::string16::const_iterator& end,
- size_t* start_pos,
- size_t* end_pos,
- std::string* content_text) override;
- virtual GURL GetIntentURL(const std::string& content_text) override;
- virtual size_t GetMaximumContentLength() override;
+ bool FindContent(const base::string16::const_iterator& begin,
+ const base::string16::const_iterator& end,
+ size_t* start_pos,
+ size_t* end_pos,
+ std::string* content_text) override;
+ GURL GetIntentURL(const std::string& content_text) override;
+ size_t GetMaximumContentLength() override;
DISALLOW_COPY_AND_ASSIGN(EmailDetector);
};
diff --git a/chromium/content/renderer/android/phone_number_detector.cc b/chromium/content/renderer/android/phone_number_detector.cc
index 18229ddb2b2..6d0e19c910c 100644
--- a/chromium/content/renderer/android/phone_number_detector.cc
+++ b/chromium/content/renderer/android/phone_number_detector.cc
@@ -63,15 +63,17 @@ bool PhoneNumberDetector::FindContent(
base::string16 utf16_input = base::string16(begin, end);
std::string utf8_input = base::UTF16ToUTF8(utf16_input);
+ PhoneNumberUtil* phone_util = PhoneNumberUtil::GetInstance();
+ if (phone_util->IsAlphaNumber(utf8_input))
+ phone_util->ConvertAlphaCharactersInNumber(&utf8_input);
PhoneNumberMatcher matcher(utf8_input, region_code_);
if (matcher.HasNext()) {
PhoneNumberMatch match;
matcher.Next(&match);
-
- PhoneNumberUtil* phone_util = PhoneNumberUtil::GetInstance();
phone_util->FormatNumberForMobileDialing(match.number(), region_code_,
false, /* with_formatting */
content_text);
+
// If the number can't be dialed from the current region, the formatted
// string will be empty.
if (content_text->empty())
diff --git a/chromium/content/renderer/android/phone_number_detector.h b/chromium/content/renderer/android/phone_number_detector.h
index 37413155df9..6503eee30b2 100644
--- a/chromium/content/renderer/android/phone_number_detector.h
+++ b/chromium/content/renderer/android/phone_number_detector.h
@@ -18,19 +18,19 @@ class CONTENT_EXPORT PhoneNumberDetector : public ContentDetector {
public:
PhoneNumberDetector();
explicit PhoneNumberDetector(const std::string& region);
- virtual ~PhoneNumberDetector();
+ ~PhoneNumberDetector() override;
private:
friend class PhoneNumberDetectorTest;
// Implementation of ContentDetector.
- virtual bool FindContent(const base::string16::const_iterator& begin,
- const base::string16::const_iterator& end,
- size_t* start_pos,
- size_t* end_pos,
- std::string* content_text) override;
- virtual GURL GetIntentURL(const std::string& content_text) override;
- virtual size_t GetMaximumContentLength() override;
+ bool FindContent(const base::string16::const_iterator& begin,
+ const base::string16::const_iterator& end,
+ size_t* start_pos,
+ size_t* end_pos,
+ std::string* content_text) override;
+ GURL GetIntentURL(const std::string& content_text) override;
+ size_t GetMaximumContentLength() override;
const std::string region_code_;
diff --git a/chromium/content/renderer/android/phone_number_detector_unittest.cc b/chromium/content/renderer/android/phone_number_detector_unittest.cc
index 5078cb559bb..d10744bfdc0 100644
--- a/chromium/content/renderer/android/phone_number_detector_unittest.cc
+++ b/chromium/content/renderer/android/phone_number_detector_unittest.cc
@@ -73,4 +73,17 @@ TEST_F(PhoneNumberDetectorTest, FindAndFormatNumber) {
"\xEF\xBC\x90", "us"));
}
+TEST_F(PhoneNumberDetectorTest, FindAndFormatAlphaNumber) {
+ // Tests cases with valid alpha numbers.
+ EXPECT_EQ("+18002378289", FindAndFormatNumber("1 800-BestBuy", "us"));
+ EXPECT_EQ("+18002378289", FindAndFormatNumber("1-800-BEST-BUY", "us"));
+ EXPECT_EQ("+18002378289", FindAndFormatNumber("1-800-BEST BUY", "us"));
+ // TODO(qinmin): support alpha number detection when there are characters on
+ // either side of the string.
+ EXPECT_EQ("", FindAndFormatNumber("hello 1-800-BEST-BUY", "us"));
+ EXPECT_EQ("", FindAndFormatNumber("BestBuy", "us"));
+ EXPECT_EQ("", FindAndFormatNumber("1-BestBuy", "us"));
+ EXPECT_EQ("", FindAndFormatNumber("1 BestBuy", "us"));
+}
+
} // namespace content
diff --git a/chromium/content/renderer/android/renderer_date_time_picker.h b/chromium/content/renderer/android/renderer_date_time_picker.h
index 481d288c055..970f93ba075 100644
--- a/chromium/content/renderer/android/renderer_date_time_picker.h
+++ b/chromium/content/renderer/android/renderer_date_time_picker.h
@@ -24,7 +24,7 @@ class RendererDateTimePicker : public RenderViewObserver {
RenderViewImpl* sender,
const blink::WebDateTimeChooserParams& params,
blink::WebDateTimeChooserCompletion* completion);
- virtual ~RendererDateTimePicker();
+ ~RendererDateTimePicker() override;
bool Open();
@@ -33,7 +33,7 @@ class RendererDateTimePicker : public RenderViewObserver {
void OnCancel();
// RenderViewObserver
- virtual bool OnMessageReceived(const IPC::Message& message) override;
+ bool OnMessageReceived(const IPC::Message& message) override;
blink::WebDateTimeChooserParams chooser_params_;
blink::WebDateTimeChooserCompletion* chooser_completion_; // Not owned by us
diff --git a/chromium/content/renderer/android/synchronous_compositor_factory.cc b/chromium/content/renderer/android/synchronous_compositor_factory.cc
index 7238b710dfc..b6093e7e9d6 100644
--- a/chromium/content/renderer/android/synchronous_compositor_factory.cc
+++ b/chromium/content/renderer/android/synchronous_compositor_factory.cc
@@ -20,7 +20,8 @@ void SynchronousCompositorFactory::SetInstance(
DCHECK(g_instance == NULL);
// This feature only makes sense in single process mode.
- CHECK(CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess));
+ CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSingleProcess));
g_instance = instance;
}
diff --git a/chromium/content/renderer/android/synchronous_compositor_factory.h b/chromium/content/renderer/android/synchronous_compositor_factory.h
index 9653bc265fd..7906f5f3ec8 100644
--- a/chromium/content/renderer/android/synchronous_compositor_factory.h
+++ b/chromium/content/renderer/android/synchronous_compositor_factory.h
@@ -14,15 +14,17 @@ class MessageLoopProxy;
}
namespace cc {
+class BeginFrameSource;
class ContextProvider;
class OutputSurface;
}
-namespace webkit {
-namespace gpu {
+namespace cc_blink {
class ContextProviderWebContext;
-class WebGraphicsContext3DInProcessCommandBufferImpl;
}
+
+namespace gpu_blink {
+class WebGraphicsContext3DInProcessCommandBufferImpl;
}
namespace content {
@@ -52,13 +54,16 @@ class SynchronousCompositorFactory {
// The factory maintains ownership of the returned interface.
virtual InputHandlerManagerClient* GetInputHandlerManagerClient() = 0;
- virtual scoped_refptr<webkit::gpu::ContextProviderWebContext>
- CreateOffscreenContextProvider(
- const blink::WebGraphicsContext3D::Attributes& attributes,
- const std::string& debug_name) = 0;
+ virtual scoped_ptr<cc::BeginFrameSource> CreateExternalBeginFrameSource(
+ int routing_id) = 0;
+
+ virtual scoped_refptr<cc_blink::ContextProviderWebContext>
+ CreateOffscreenContextProvider(
+ const blink::WebGraphicsContext3D::Attributes& attributes,
+ const std::string& debug_name) = 0;
virtual scoped_refptr<StreamTextureFactory> CreateStreamTextureFactory(
int frame_id) = 0;
- virtual webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl*
+ virtual gpu_blink::WebGraphicsContext3DInProcessCommandBufferImpl*
CreateOffscreenGraphicsContext3D(
const blink::WebGraphicsContext3D::Attributes& attributes) = 0;
diff --git a/chromium/content/renderer/battery_status/battery_status_dispatcher.cc b/chromium/content/renderer/battery_status/battery_status_dispatcher.cc
index e7496113d7e..66b8f91c125 100644
--- a/chromium/content/renderer/battery_status/battery_status_dispatcher.cc
+++ b/chromium/content/renderer/battery_status/battery_status_dispatcher.cc
@@ -15,16 +15,29 @@ BatteryStatusDispatcher::BatteryStatusDispatcher(
: listener_(listener) {
DCHECK(listener_);
- RenderThread::Get()->GetServiceRegistry()->ConnectToRemoteService(&monitor_);
- monitor_.set_client(this);
+ if (ServiceRegistry* registry = RenderThread::Get()->GetServiceRegistry()) {
+ // registry can be null during testing.
+ registry->ConnectToRemoteService(&monitor_);
+ QueryNextStatus();
+ }
}
BatteryStatusDispatcher::~BatteryStatusDispatcher() {
}
+void BatteryStatusDispatcher::QueryNextStatus() {
+ monitor_->QueryNextStatus(
+ base::Bind(&BatteryStatusDispatcher::DidChange, base::Unretained(this)));
+}
+
void BatteryStatusDispatcher::DidChange(
device::BatteryStatusPtr battery_status) {
+ // monitor_ can be null during testing.
+ if (monitor_)
+ QueryNextStatus();
+
DCHECK(battery_status);
+
blink::WebBatteryStatus web_battery_status;
web_battery_status.charging = battery_status->charging;
web_battery_status.chargingTime = battery_status->charging_time;
diff --git a/chromium/content/renderer/battery_status/battery_status_dispatcher.h b/chromium/content/renderer/battery_status/battery_status_dispatcher.h
index 9843246874f..f117a4b385e 100644
--- a/chromium/content/renderer/battery_status/battery_status_dispatcher.h
+++ b/chromium/content/renderer/battery_status/battery_status_dispatcher.h
@@ -5,6 +5,7 @@
#ifndef CONTENT_RENDERER_BATTERY_STATUS_BATTERY_STATUS_DISPATCHER_H_
#define CONTENT_RENDERER_BATTERY_STATUS_BATTERY_STATUS_DISPATCHER_H_
+#include "base/compiler_specific.h"
#include "base/macros.h"
#include "content/common/content_export.h"
#include "device/battery/battery_monitor.mojom.h"
@@ -15,18 +16,16 @@ class WebBatteryStatusListener;
namespace content {
-class CONTENT_EXPORT BatteryStatusDispatcher
- : public NON_EXPORTED_BASE(device::BatteryStatusObserver) {
+class CONTENT_EXPORT BatteryStatusDispatcher {
public:
explicit BatteryStatusDispatcher(blink::WebBatteryStatusListener* listener);
- ~BatteryStatusDispatcher() override;
+ ~BatteryStatusDispatcher();
private:
- // BatteryStatusObserver method.
- void DidChange(device::BatteryStatusPtr battery_status) override;
+ friend class BatteryStatusDispatcherTest;
- void Start();
- void Stop();
+ void QueryNextStatus();
+ void DidChange(device::BatteryStatusPtr battery_status);
device::BatteryMonitorPtr monitor_;
blink::WebBatteryStatusListener* listener_;
diff --git a/chromium/content/renderer/battery_status/battery_status_dispatcher_unittest.cc b/chromium/content/renderer/battery_status/battery_status_dispatcher_unittest.cc
index 31d2c666f0f..7e6068e8947 100644
--- a/chromium/content/renderer/battery_status/battery_status_dispatcher_unittest.cc
+++ b/chromium/content/renderer/battery_status/battery_status_dispatcher_unittest.cc
@@ -2,11 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "battery_status_dispatcher.h"
+#include "content/renderer/battery_status/battery_status_dispatcher.h"
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "content/common/battery_status_messages.h"
#include "content/public/test/mock_render_thread.h"
#include "content/public/test/test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -16,12 +13,11 @@ namespace content {
class MockBatteryStatusListener : public blink::WebBatteryStatusListener {
public:
- MockBatteryStatusListener() : did_change_battery_status_(false) { }
- virtual ~MockBatteryStatusListener() { }
+ MockBatteryStatusListener() : did_change_battery_status_(false) {}
+ virtual ~MockBatteryStatusListener() {}
// blink::WebBatteryStatusListener method.
- virtual void updateBatteryStatus(
- const blink::WebBatteryStatus& status) override {
+ void updateBatteryStatus(const blink::WebBatteryStatus& status) override {
status_ = status;
did_change_battery_status_ = true;
}
@@ -37,48 +33,48 @@ class MockBatteryStatusListener : public blink::WebBatteryStatusListener {
};
class BatteryStatusDispatcherTest : public testing::Test {
+ public:
+ void UpdateBatteryStatus(const device::BatteryStatus& status) {
+ device::BatteryStatusPtr status_ptr(device::BatteryStatus::New());
+ *status_ptr = status;
+ dispatcher_->DidChange(status_ptr.Pass());
+ }
+
+ const MockBatteryStatusListener& listener() const {
+ return listener_;
+ }
+
+ protected:
+ void SetUp() override {
+ dispatcher_.reset(new BatteryStatusDispatcher(&listener_));
+ }
+
private:
// We need to create a MockRenderThread so RenderThread::Get() doesn't return
// null.
MockRenderThread render_thread_;
+ MockBatteryStatusListener listener_;
+ scoped_ptr<BatteryStatusDispatcher> dispatcher_;
};
TEST_F(BatteryStatusDispatcherTest, UpdateListener) {
- MockBatteryStatusListener listener;
- BatteryStatusDispatcher dispatcher(0);
+ // TODO(darin): This test isn't super interesting. It just exercises
+ // conversion b/w device::BatteryStatus and blink::WebBatteryStatus.
- blink::WebBatteryStatus status;
+ device::BatteryStatus status;
status.charging = true;
- status.chargingTime = 100;
- status.dischargingTime = 200;
+ status.charging_time = 100;
+ status.discharging_time = 200;
status.level = 0.5;
- dispatcher.Start(&listener);
+ UpdateBatteryStatus(status);
- BatteryStatusMsg_DidChange message(status);
- dispatcher.OnControlMessageReceived(message);
-
- const blink::WebBatteryStatus& received_status = listener.status();
- EXPECT_TRUE(listener.did_change_battery_status());
+ const blink::WebBatteryStatus& received_status = listener().status();
+ EXPECT_TRUE(listener().did_change_battery_status());
EXPECT_EQ(status.charging, received_status.charging);
- EXPECT_EQ(status.chargingTime, received_status.chargingTime);
- EXPECT_EQ(status.dischargingTime, received_status.dischargingTime);
+ EXPECT_EQ(status.charging_time, received_status.chargingTime);
+ EXPECT_EQ(status.discharging_time, received_status.dischargingTime);
EXPECT_EQ(status.level, received_status.level);
-
- dispatcher.Stop();
-}
-
-TEST_F(BatteryStatusDispatcherTest, NoUpdateWhenNullListener) {
- MockBatteryStatusListener listener;
- BatteryStatusDispatcher dispatcher(0);
-
- dispatcher.Start(0);
- dispatcher.Stop();
-
- blink::WebBatteryStatus status;
- BatteryStatusMsg_DidChange message(status);
- dispatcher.OnControlMessageReceived(message);
- EXPECT_FALSE(listener.did_change_battery_status());
}
} // namespace content
diff --git a/chromium/content/renderer/browser_plugin/browser_plugin.cc b/chromium/content/renderer/browser_plugin/browser_plugin.cc
index 39e49d25a33..8f3ba727fe4 100644
--- a/chromium/content/renderer/browser_plugin/browser_plugin.cc
+++ b/chromium/content/renderer/browser_plugin/browser_plugin.cc
@@ -39,8 +39,8 @@ using blink::WebURL;
using blink::WebVector;
namespace {
-typedef std::map<blink::WebPluginContainer*, content::BrowserPlugin*>
- PluginContainerMap;
+using PluginContainerMap =
+ std::map<blink::WebPluginContainer*, content::BrowserPlugin*>;
static base::LazyInstance<PluginContainerMap> g_plugin_container_map =
LAZY_INSTANCE_INITIALIZER;
} // namespace
@@ -51,34 +51,30 @@ namespace content {
BrowserPlugin* BrowserPlugin::GetFromNode(blink::WebNode& node) {
blink::WebPluginContainer* container = node.pluginContainer();
if (!container)
- return NULL;
+ return nullptr;
PluginContainerMap* browser_plugins = g_plugin_container_map.Pointer();
PluginContainerMap::iterator it = browser_plugins->find(container);
- return it == browser_plugins->end() ? NULL : it->second;
+ return it == browser_plugins->end() ? nullptr : it->second;
}
-BrowserPlugin::BrowserPlugin(RenderViewImpl* render_view,
- blink::WebFrame* frame,
+BrowserPlugin::BrowserPlugin(RenderFrame* render_frame,
scoped_ptr<BrowserPluginDelegate> delegate)
: attached_(false),
- attach_pending_(false),
- render_view_(render_view->AsWeakPtr()),
- render_view_routing_id_(render_view->GetRoutingID()),
- container_(NULL),
- last_device_scale_factor_(GetDeviceScaleFactor()),
- sad_guest_(NULL),
+ render_frame_routing_id_(render_frame->GetRoutingID()),
+ container_(nullptr),
+ sad_guest_(nullptr),
guest_crashed_(false),
plugin_focused_(false),
visible_(true),
mouse_locked_(false),
ready_(false),
- browser_plugin_manager_(render_view->GetBrowserPluginManager()),
browser_plugin_instance_id_(browser_plugin::kInstanceIDNone),
contents_opaque_(true),
delegate_(delegate.Pass()),
weak_ptr_factory_(this) {
- browser_plugin_instance_id_ = browser_plugin_manager()->GetNextInstanceID();
+ browser_plugin_instance_id_ =
+ BrowserPluginManager::Get()->GetNextInstanceID();
if (delegate_)
delegate_->SetElementInstanceID(browser_plugin_instance_id_);
@@ -88,13 +84,12 @@ BrowserPlugin::~BrowserPlugin() {
if (compositing_helper_.get())
compositing_helper_->OnContainerDestroy();
- browser_plugin_manager()->RemoveBrowserPlugin(browser_plugin_instance_id_);
+ BrowserPluginManager::Get()->RemoveBrowserPlugin(browser_plugin_instance_id_);
}
bool BrowserPlugin::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(BrowserPlugin, message)
- IPC_MESSAGE_HANDLER(BrowserPluginMsg_Attach_ACK, OnAttachACK)
IPC_MESSAGE_HANDLER(BrowserPluginMsg_AdvanceFocus, OnAdvanceFocus)
IPC_MESSAGE_HANDLER_GENERIC(BrowserPluginMsg_CompositorFrameSwapped,
OnCompositorFrameSwapped(message))
@@ -105,7 +100,8 @@ bool BrowserPlugin::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(BrowserPluginMsg_SetTooltipText, OnSetTooltipText)
IPC_MESSAGE_HANDLER(BrowserPluginMsg_ShouldAcceptTouchEvents,
OnShouldAcceptTouchEvents)
- IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_MESSAGE_UNHANDLED(
+ handled = delegate_ && delegate_->OnMessageReceived(message))
IPC_END_MESSAGE_MAP()
return handled;
}
@@ -122,38 +118,40 @@ void BrowserPlugin::UpdateDOMAttribute(const std::string& attribute_name,
}
void BrowserPlugin::Attach() {
- if (ready()) {
- attached_ = false;
- guest_crashed_ = false;
- EnableCompositing(false);
- if (compositing_helper_.get()) {
- compositing_helper_->OnContainerDestroy();
- compositing_helper_ = NULL;
- }
- }
+ Detach();
- // TODO(fsamuel): Add support for reattachment.
BrowserPluginHostMsg_Attach_Params attach_params;
attach_params.focused = ShouldGuestBeFocused();
attach_params.visible = visible_;
- attach_params.origin = plugin_rect().origin();
+ attach_params.view_rect = view_rect();
attach_params.is_full_page_plugin = false;
if (container()) {
blink::WebLocalFrame* frame = container()->element().document().frame();
attach_params.is_full_page_plugin =
frame->view()->mainFrame()->document().isPluginDocument();
}
- gfx::Size view_size(width(), height());
- if (!view_size.IsEmpty()) {
- PopulateResizeGuestParameters(view_size,
- &attach_params.resize_guest_params);
- }
- browser_plugin_manager()->Send(new BrowserPluginHostMsg_Attach(
- render_view_routing_id_,
+ BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_Attach(
+ render_frame_routing_id_,
browser_plugin_instance_id_,
attach_params));
- attach_pending_ = true;
+ attached_ = true;
+}
+
+void BrowserPlugin::Detach() {
+ if (!attached())
+ return;
+
+ attached_ = false;
+ guest_crashed_ = false;
+ EnableCompositing(false);
+ if (compositing_helper_.get()) {
+ compositing_helper_->OnContainerDestroy();
+ compositing_helper_ = nullptr;
+ }
+
+ BrowserPluginManager::Get()->Send(
+ new BrowserPluginHostMsg_Detach(browser_plugin_instance_id_));
}
void BrowserPlugin::DidCommitCompositorFrame() {
@@ -163,17 +161,17 @@ void BrowserPlugin::DidCommitCompositorFrame() {
void BrowserPlugin::OnAdvanceFocus(int browser_plugin_instance_id,
bool reverse) {
- DCHECK(render_view_);
- render_view_->GetWebView()->advanceFocus(reverse);
-}
-
-void BrowserPlugin::OnAttachACK(int browser_plugin_instance_id) {
- DCHECK(!attached());
- attached_ = true;
- attach_pending_ = false;
+ auto render_frame = RenderFrameImpl::FromRoutingID(render_frame_routing_id());
+ auto render_view = render_frame ? render_frame->GetRenderView() : nullptr;
+ if (!render_view)
+ return;
+ render_view->GetWebView()->advanceFocus(reverse);
}
void BrowserPlugin::OnCompositorFrameSwapped(const IPC::Message& message) {
+ if (!attached())
+ return;
+
BrowserPluginMsg_CompositorFrameSwapped::Param param;
if (!BrowserPluginMsg_CompositorFrameSwapped::Read(&message, &param))
return;
@@ -182,14 +180,15 @@ void BrowserPlugin::OnCompositorFrameSwapped(const IPC::Message& message) {
guest_crashed_ = false;
scoped_ptr<cc::CompositorFrame> frame(new cc::CompositorFrame);
- param.b.frame.AssignTo(frame.get());
+ get<1>(param).frame.AssignTo(frame.get());
EnableCompositing(true);
- compositing_helper_->OnCompositorFrameSwapped(frame.Pass(),
- param.b.producing_route_id,
- param.b.output_surface_id,
- param.b.producing_host_id,
- param.b.shared_memory_handle);
+ compositing_helper_->OnCompositorFrameSwapped(
+ frame.Pass(),
+ get<1>(param).producing_route_id,
+ get<1>(param).output_surface_id,
+ get<1>(param).producing_host_id,
+ get<1>(param).shared_memory_handle);
}
void BrowserPlugin::OnGuestGone(int browser_plugin_instance_id) {
@@ -225,16 +224,21 @@ void BrowserPlugin::OnSetCursor(int browser_plugin_instance_id,
void BrowserPlugin::OnSetMouseLock(int browser_plugin_instance_id,
bool enable) {
+ auto render_frame = RenderFrameImpl::FromRoutingID(render_frame_routing_id());
+ auto render_view = static_cast<RenderViewImpl*>(
+ render_frame ? render_frame->GetRenderView() : nullptr);
if (enable) {
- if (mouse_locked_)
+ if (mouse_locked_ || !render_view)
return;
- render_view_->mouse_lock_dispatcher()->LockMouse(this);
+ render_view->mouse_lock_dispatcher()->LockMouse(this);
} else {
if (!mouse_locked_) {
OnLockMouseACK(false);
return;
}
- render_view_->mouse_lock_dispatcher()->UnlockMouse(this);
+ if (!render_view)
+ return;
+ render_view->mouse_lock_dispatcher()->UnlockMouse(this);
}
}
@@ -255,43 +259,28 @@ void BrowserPlugin::OnShouldAcceptTouchEvents(int browser_plugin_instance_id,
void BrowserPlugin::ShowSadGraphic() {
// If the BrowserPlugin is scheduled to be deleted, then container_ will be
- // NULL so we shouldn't attempt to access it.
+ // nullptr so we shouldn't attempt to access it.
if (container_)
container_->invalidate();
}
-float BrowserPlugin::GetDeviceScaleFactor() const {
- if (!render_view_)
- return 1.0f;
- return render_view_->GetWebView()->deviceScaleFactor();
-}
-
-void BrowserPlugin::UpdateDeviceScaleFactor() {
- if (last_device_scale_factor_ == GetDeviceScaleFactor())
- return;
-
- BrowserPluginHostMsg_ResizeGuest_Params params;
- PopulateResizeGuestParameters(plugin_size(), &params);
- browser_plugin_manager()->Send(new BrowserPluginHostMsg_ResizeGuest(
- render_view_routing_id_,
- browser_plugin_instance_id_,
- params));
-}
-
-void BrowserPlugin::UpdateGuestFocusState() {
- if (!ready())
+void BrowserPlugin::UpdateGuestFocusState(blink::WebFocusType focus_type) {
+ if (!attached())
return;
bool should_be_focused = ShouldGuestBeFocused();
- browser_plugin_manager()->Send(new BrowserPluginHostMsg_SetFocus(
- render_view_routing_id_,
+ BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_SetFocus(
browser_plugin_instance_id_,
- should_be_focused));
+ should_be_focused,
+ focus_type));
}
bool BrowserPlugin::ShouldGuestBeFocused() const {
bool embedder_focused = false;
- if (render_view_)
- embedder_focused = render_view_->has_focus();
+ auto render_frame = RenderFrameImpl::FromRoutingID(render_frame_routing_id());
+ auto render_view = static_cast<RenderViewImpl*>(
+ render_frame ? render_frame->GetRenderView() : nullptr);
+ if (render_view)
+ embedder_focused = render_view->has_focus();
return plugin_focused_ && embedder_focused;
}
@@ -308,16 +297,15 @@ bool BrowserPlugin::initialize(WebPluginContainer* container) {
g_plugin_container_map.Get().insert(std::make_pair(container_, this));
- browser_plugin_manager()->AddBrowserPlugin(browser_plugin_instance_id_, this);
-
- // This is a way to notify observers of our attributes that this plugin is
- // available in render tree.
- // TODO(lazyboy): This should be done through the delegate instead. Perhaps
- // by firing an event from there.
- UpdateDOMAttribute(
- "internalinstanceid",
- base::UTF8ToUTF16(base::IntToString(browser_plugin_instance_id_)));
+ BrowserPluginManager::Get()->AddBrowserPlugin(
+ browser_plugin_instance_id_, this);
+ // Defer attach call so that if there's any pending browser plugin
+ // destruction, then it can progress first.
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&BrowserPlugin::UpdateInternalInstanceId,
+ weak_ptr_factory_.GetWeakPtr()));
return true;
}
@@ -339,10 +327,20 @@ void BrowserPlugin::EnableCompositing(bool enable) {
if (!enable) {
DCHECK(compositing_helper_.get());
compositing_helper_->OnContainerDestroy();
- compositing_helper_ = NULL;
+ compositing_helper_ = nullptr;
}
}
+void BrowserPlugin::UpdateInternalInstanceId() {
+ // This is a way to notify observers of our attributes that this plugin is
+ // available in render tree.
+ // TODO(lazyboy): This should be done through the delegate instead. Perhaps
+ // by firing an event from there.
+ UpdateDOMAttribute(
+ "internalinstanceid",
+ base::UTF8ToUTF16(base::IntToString(browser_plugin_instance_id_)));
+}
+
void BrowserPlugin::destroy() {
if (container_) {
// The BrowserPlugin's WebPluginContainer is deleted immediately after this
@@ -350,13 +348,20 @@ void BrowserPlugin::destroy() {
g_plugin_container_map.Get().erase(container_);
}
- container_ = NULL;
+ container_ = nullptr;
// Will be a no-op if the mouse is not currently locked.
- if (render_view_)
- render_view_->mouse_lock_dispatcher()->OnLockTargetDestroyed(this);
+ auto render_frame = RenderFrameImpl::FromRoutingID(render_frame_routing_id());
+ auto render_view = static_cast<RenderViewImpl*>(
+ render_frame ? render_frame->GetRenderView() : nullptr);
+ if (render_view)
+ render_view->mouse_lock_dispatcher()->OnLockTargetDestroyed(this);
base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
}
+v8::Local<v8::Object> BrowserPlugin::v8ScriptableObject(v8::Isolate* isolate) {
+ return delegate_->V8ScriptableObject(isolate);
+}
+
bool BrowserPlugin::supportsKeyboardFocus() const {
return true;
}
@@ -381,17 +386,17 @@ void BrowserPlugin::paint(WebCanvas* canvas, const WebRect& rect) {
// content_shell does not have the sad plugin bitmap, so we'll paint black
// instead to make it clear that something went wrong.
if (sad_guest_) {
- PaintSadPlugin(canvas, plugin_rect_, *sad_guest_);
+ PaintSadPlugin(canvas, view_rect_, *sad_guest_);
return;
}
}
SkAutoCanvasRestore auto_restore(canvas, true);
- canvas->translate(plugin_rect_.x(), plugin_rect_.y());
+ canvas->translate(view_rect_.x(), view_rect_.y());
SkRect image_data_rect = SkRect::MakeXYWH(
SkIntToScalar(0),
SkIntToScalar(0),
- SkIntToScalar(plugin_rect_.width()),
- SkIntToScalar(plugin_rect_.height()));
+ SkIntToScalar(view_rect_.width()),
+ SkIntToScalar(view_rect_.height()));
canvas->clipRect(image_data_rect);
// Paint black or white in case we have nothing in our backing store or we
// need to show a gutter.
@@ -404,68 +409,40 @@ void BrowserPlugin::paint(WebCanvas* canvas, const WebRect& rect) {
// static
bool BrowserPlugin::ShouldForwardToBrowserPlugin(
const IPC::Message& message) {
- switch (message.type()) {
- case BrowserPluginMsg_Attach_ACK::ID:
- case BrowserPluginMsg_AdvanceFocus::ID:
- case BrowserPluginMsg_CompositorFrameSwapped::ID:
- case BrowserPluginMsg_GuestGone::ID:
- case BrowserPluginMsg_SetContentsOpaque::ID:
- case BrowserPluginMsg_SetCursor::ID:
- case BrowserPluginMsg_SetMouseLock::ID:
- case BrowserPluginMsg_SetTooltipText::ID:
- case BrowserPluginMsg_ShouldAcceptTouchEvents::ID:
- return true;
- default:
- break;
- }
- return false;
+ return IPC_MESSAGE_CLASS(message) == BrowserPluginMsgStart;
}
-void BrowserPlugin::updateGeometry(
- const WebRect& window_rect,
- const WebRect& clip_rect,
- const WebVector<WebRect>& cut_outs_rects,
- bool is_visible) {
- int old_width = width();
- int old_height = height();
- plugin_rect_ = window_rect;
+void BrowserPlugin::updateGeometry(const WebRect& window_rect,
+ const WebRect& clip_rect,
+ const WebRect& unobscured_rect,
+ const WebVector<WebRect>& cut_outs_rects,
+ bool is_visible) {
+ gfx::Rect old_view_rect = view_rect_;
+ view_rect_ = window_rect;
+
if (!ready_) {
if (delegate_)
delegate_->Ready();
ready_ = true;
}
+
+ if (delegate_ && (view_rect_.size() != old_view_rect.size()))
+ delegate_->DidResizeElement(view_rect_.size());
+
if (!attached())
return;
- if (old_width == window_rect.width && old_height == window_rect.height) {
+ if (old_view_rect.size() == view_rect_.size()) {
// Let the browser know about the updated view rect.
- browser_plugin_manager()->Send(new BrowserPluginHostMsg_UpdateGeometry(
- render_view_routing_id_, browser_plugin_instance_id_, plugin_rect_));
+ BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_UpdateGeometry(
+ browser_plugin_instance_id_, view_rect_));
return;
}
-
- BrowserPluginHostMsg_ResizeGuest_Params params;
- PopulateResizeGuestParameters(plugin_size(), &params);
- browser_plugin_manager()->Send(new BrowserPluginHostMsg_ResizeGuest(
- render_view_routing_id_,
- browser_plugin_instance_id_,
- params));
}
-void BrowserPlugin::PopulateResizeGuestParameters(
- const gfx::Size& view_size,
- BrowserPluginHostMsg_ResizeGuest_Params* params) {
- params->view_size = view_size;
- params->scale_factor = GetDeviceScaleFactor();
- if (last_device_scale_factor_ != params->scale_factor) {
- last_device_scale_factor_ = params->scale_factor;
- params->repaint = true;
- }
-}
-
-void BrowserPlugin::updateFocus(bool focused) {
+void BrowserPlugin::updateFocus(bool focused, blink::WebFocusType focus_type) {
plugin_focused_ = focused;
- UpdateGuestFocusState();
+ UpdateGuestFocusState(focus_type);
}
void BrowserPlugin::updateVisibility(bool visible) {
@@ -473,14 +450,13 @@ void BrowserPlugin::updateVisibility(bool visible) {
return;
visible_ = visible;
- if (!ready())
+ if (!attached())
return;
if (compositing_helper_.get())
compositing_helper_->UpdateVisibility(visible);
- browser_plugin_manager()->Send(new BrowserPluginHostMsg_SetVisibility(
- render_view_routing_id_,
+ BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_SetVisibility(
browser_plugin_instance_id_,
visible));
}
@@ -491,7 +467,7 @@ bool BrowserPlugin::acceptsInputEvents() {
bool BrowserPlugin::handleInputEvent(const blink::WebInputEvent& event,
blink::WebCursorInfo& cursor_info) {
- if (guest_crashed_ || !ready())
+ if (guest_crashed_ || !attached())
return false;
if (event.type == blink::WebInputEvent::ContextMenu)
@@ -499,18 +475,16 @@ bool BrowserPlugin::handleInputEvent(const blink::WebInputEvent& event,
if (blink::WebInputEvent::isKeyboardEventType(event.type) &&
!edit_commands_.empty()) {
- browser_plugin_manager()->Send(
+ BrowserPluginManager::Get()->Send(
new BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent(
- render_view_routing_id_,
browser_plugin_instance_id_,
edit_commands_));
edit_commands_.clear();
}
- browser_plugin_manager()->Send(
- new BrowserPluginHostMsg_HandleInputEvent(render_view_routing_id_,
- browser_plugin_instance_id_,
- plugin_rect_,
+ BrowserPluginManager::Get()->Send(
+ new BrowserPluginHostMsg_HandleInputEvent(browser_plugin_instance_id_,
+ view_rect_,
&event));
GetWebKitCursorInfo(cursor_, &cursor_info);
return true;
@@ -521,11 +495,10 @@ bool BrowserPlugin::handleDragStatusUpdate(blink::WebDragStatus drag_status,
blink::WebDragOperationsMask mask,
const blink::WebPoint& position,
const blink::WebPoint& screen) {
- if (guest_crashed_ || !ready())
+ if (guest_crashed_ || !attached())
return false;
- browser_plugin_manager()->Send(
+ BrowserPluginManager::Get()->Send(
new BrowserPluginHostMsg_DragStatusUpdate(
- render_view_routing_id_,
browser_plugin_instance_id_,
drag_status,
DropDataBuilder::Build(drag_data),
@@ -562,8 +535,7 @@ void BrowserPlugin::didFailLoadingFrameRequest(
}
bool BrowserPlugin::executeEditCommand(const blink::WebString& name) {
- browser_plugin_manager()->Send(new BrowserPluginHostMsg_ExecuteEditCommand(
- render_view_routing_id_,
+ BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_ExecuteEditCommand(
browser_plugin_instance_id_,
name.utf8()));
@@ -583,14 +555,13 @@ bool BrowserPlugin::setComposition(
const blink::WebVector<blink::WebCompositionUnderline>& underlines,
int selectionStart,
int selectionEnd) {
- if (!ready())
+ if (!attached())
return false;
std::vector<blink::WebCompositionUnderline> std_underlines;
for (size_t i = 0; i < underlines.size(); ++i) {
std_underlines.push_back(underlines[i]);
}
- browser_plugin_manager()->Send(new BrowserPluginHostMsg_ImeSetComposition(
- render_view_routing_id_,
+ BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_ImeSetComposition(
browser_plugin_instance_id_,
text.utf8(),
std_underlines,
@@ -603,24 +574,23 @@ bool BrowserPlugin::setComposition(
bool BrowserPlugin::confirmComposition(
const blink::WebString& text,
blink::WebWidget::ConfirmCompositionBehavior selectionBehavior) {
- if (!ready())
+ if (!attached())
return false;
bool keep_selection = (selectionBehavior == blink::WebWidget::KeepSelection);
- browser_plugin_manager()->Send(new BrowserPluginHostMsg_ImeConfirmComposition(
- render_view_routing_id_,
- browser_plugin_instance_id_,
- text.utf8(),
- keep_selection));
+ BrowserPluginManager::Get()->Send(
+ new BrowserPluginHostMsg_ImeConfirmComposition(
+ browser_plugin_instance_id_,
+ text.utf8(),
+ keep_selection));
// TODO(kochi): This assumes the IPC handling always succeeds.
return true;
}
void BrowserPlugin::extendSelectionAndDelete(int before, int after) {
- if (!ready())
+ if (!attached())
return;
- browser_plugin_manager()->Send(
+ BrowserPluginManager::Get()->Send(
new BrowserPluginHostMsg_ExtendSelectionAndDelete(
- render_view_routing_id_,
browser_plugin_instance_id_,
before,
after));
@@ -628,25 +598,22 @@ void BrowserPlugin::extendSelectionAndDelete(int before, int after) {
void BrowserPlugin::OnLockMouseACK(bool succeeded) {
mouse_locked_ = succeeded;
- browser_plugin_manager()->Send(new BrowserPluginHostMsg_LockMouse_ACK(
- render_view_routing_id_,
+ BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_LockMouse_ACK(
browser_plugin_instance_id_,
succeeded));
}
void BrowserPlugin::OnMouseLockLost() {
mouse_locked_ = false;
- browser_plugin_manager()->Send(new BrowserPluginHostMsg_UnlockMouse_ACK(
- render_view_routing_id_,
+ BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_UnlockMouse_ACK(
browser_plugin_instance_id_));
}
bool BrowserPlugin::HandleMouseLockedInputEvent(
const blink::WebMouseEvent& event) {
- browser_plugin_manager()->Send(
- new BrowserPluginHostMsg_HandleInputEvent(render_view_routing_id_,
- browser_plugin_instance_id_,
- plugin_rect_,
+ BrowserPluginManager::Get()->Send(
+ new BrowserPluginHostMsg_HandleInputEvent(browser_plugin_instance_id_,
+ view_rect_,
&event));
return true;
}
diff --git a/chromium/content/renderer/browser_plugin/browser_plugin.h b/chromium/content/renderer/browser_plugin/browser_plugin.h
index d072e7b0d6f..379369790a5 100644
--- a/chromium/content/renderer/browser_plugin/browser_plugin.h
+++ b/chromium/content/renderer/browser_plugin/browser_plugin.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_RENDERER_BROWSER_PLUGIN_BROWSER_PLUGIN_H_
-#define CONTENT_RENDERER_BROWSER_PLUGIN_BROWSER_PLUGIN_H_
+#ifndef CONTENT_RENDERER_BROWSER_PLUGIN_BROWSER_PLUGIN_H_
+#define CONTENT_RENDERER_BROWSER_PLUGIN_BROWSER_PLUGIN_H_
#include "third_party/WebKit/public/web/WebPlugin.h"
@@ -23,9 +23,8 @@ struct FrameMsg_BuffersSwapped_Params;
namespace content {
class BrowserPluginDelegate;
-class ChildFrameCompositingHelper;
class BrowserPluginManager;
-class MockBrowserPlugin;
+class ChildFrameCompositingHelper;
class CONTENT_EXPORT BrowserPlugin :
NON_EXPORTED_BASE(public blink::WebPlugin),
@@ -33,14 +32,9 @@ class CONTENT_EXPORT BrowserPlugin :
public:
static BrowserPlugin* GetFromNode(blink::WebNode& node);
- RenderViewImpl* render_view() const { return render_view_.get(); }
- int render_view_routing_id() const { return render_view_routing_id_; }
+ int render_frame_routing_id() const { return render_frame_routing_id_; }
int browser_plugin_instance_id() const { return browser_plugin_instance_id_; }
bool attached() const { return attached_; }
- bool ready() const { return attached_ || attach_pending_; }
- BrowserPluginManager* browser_plugin_manager() const {
- return browser_plugin_manager_.get();
- }
bool OnMessageReceived(const IPC::Message& msg);
@@ -53,22 +47,24 @@ class CONTENT_EXPORT BrowserPlugin :
bool guest_crashed() const { return guest_crashed_; }
// Informs the guest of an updated focus state.
- void UpdateGuestFocusState();
+ void UpdateGuestFocusState(blink::WebFocusType focus_type);
// Indicates whether the guest should be focused.
bool ShouldGuestBeFocused() const;
- // Embedder's device scale factor changed, we need to update the guest
- // renderer.
- void UpdateDeviceScaleFactor();
-
// A request to enable hardware compositing.
void EnableCompositing(bool enable);
+ void UpdateInternalInstanceId();
+
// Provided that a guest instance ID has been allocated, this method attaches
// this BrowserPlugin instance to that guest.
void Attach();
+ // This method detaches this BrowserPlugin instance from the guest that it's
+ // currently attached to, if any.
+ void Detach();
+
// Notify the plugin about a compositor commit so that frame ACKs could be
// sent, if needed.
void DidCommitCompositorFrame();
@@ -80,19 +76,24 @@ class CONTENT_EXPORT BrowserPlugin :
virtual blink::WebPluginContainer* container() const override;
virtual bool initialize(blink::WebPluginContainer* container) override;
virtual void destroy() override;
+ virtual v8::Local<v8::Object> v8ScriptableObject(
+ v8::Isolate* isolate) override;
virtual bool supportsKeyboardFocus() const override;
virtual bool supportsEditCommands() const override;
virtual bool supportsInputMethod() const override;
virtual bool canProcessDrag() const override;
+ virtual void layoutIfNeeded() override { }
virtual void paint(
blink::WebCanvas* canvas,
const blink::WebRect& rect) override;
virtual void updateGeometry(
- const blink::WebRect& frame_rect,
+ const blink::WebRect& window_rect,
const blink::WebRect& clip_rect,
+ const blink::WebRect& unobscured_rect,
const blink::WebVector<blink::WebRect>& cut_outs_rects,
bool is_visible) override;
- virtual void updateFocus(bool focused) override;
+ virtual void updateFocus(bool focused,
+ blink::WebFocusType focus_type) override;
virtual void updateVisibility(bool visible) override;
virtual bool acceptsInputEvents() override;
virtual bool handleInputEvent(
@@ -138,39 +139,24 @@ class CONTENT_EXPORT BrowserPlugin :
// Only the manager is allowed to create a BrowserPlugin.
friend class BrowserPluginManager;
- // For unit/integration tests.
- friend class MockBrowserPlugin;
-
// A BrowserPlugin object is a controller that represents an instance of a
// browser plugin within the embedder renderer process. Once a BrowserPlugin
// does an initial navigation or is attached to a newly created guest, it
// acquires a browser_plugin_instance_id as well. The guest instance ID
// uniquely identifies a guest WebContents that's hosted by this
// BrowserPlugin.
- BrowserPlugin(RenderViewImpl* render_view,
- blink::WebFrame* frame,
+ BrowserPlugin(RenderFrame* render_frame,
scoped_ptr<BrowserPluginDelegate> delegate);
~BrowserPlugin() override;
- int width() const { return plugin_rect_.width(); }
- int height() const { return plugin_rect_.height(); }
- gfx::Size plugin_size() const { return plugin_rect_.size(); }
- gfx::Rect plugin_rect() const { return plugin_rect_; }
-
- float GetDeviceScaleFactor() const;
+ gfx::Rect view_rect() const { return view_rect_; }
void ShowSadGraphic();
- // Populates BrowserPluginHostMsg_ResizeGuest_Params with resize state.
- void PopulateResizeGuestParameters(
- const gfx::Size& view_size,
- BrowserPluginHostMsg_ResizeGuest_Params* params);
-
// IPC message handlers.
// Please keep in alphabetical order.
void OnAdvanceFocus(int instance_id, bool reverse);
- void OnAttachACK(int browser_plugin_instance_id);
void OnCompositorFrameSwapped(const IPC::Message& message);
void OnGuestGone(int instance_id);
void OnSetContentsOpaque(int instance_id, bool opaque);
@@ -181,17 +167,14 @@ class CONTENT_EXPORT BrowserPlugin :
void OnShouldAcceptTouchEvents(int instance_id, bool accept);
// This indicates whether this BrowserPlugin has been attached to a
- // WebContents.
+ // WebContents and is ready to receive IPCs.
bool attached_;
- bool attach_pending_;
- const base::WeakPtr<RenderViewImpl> render_view_;
- // We cache the |render_view_|'s routing ID because we need it on destruction.
- // If the |render_view_| is destroyed before the BrowserPlugin is destroyed
- // then we will attempt to access a NULL pointer.
- const int render_view_routing_id_;
+ // We cache the |render_frame_routing_id| because we need it on destruction.
+ // If the RenderFrame is destroyed before the BrowserPlugin is destroyed
+ // then we will attempt to access a nullptr.
+ const int render_frame_routing_id_;
blink::WebPluginContainer* container_;
- gfx::Rect plugin_rect_;
- float last_device_scale_factor_;
+ gfx::Rect view_rect_;
// Bitmap for crashed plugin. Lazily initialized, non-owning pointer.
SkBitmap* sad_guest_;
bool guest_crashed_;
@@ -207,11 +190,6 @@ class CONTENT_EXPORT BrowserPlugin :
// This indicates that the BrowserPlugin has a geometry.
bool ready_;
- // BrowserPlugin outlives RenderViewImpl in Chrome Apps and so we need to
- // store the BrowserPlugin's BrowserPluginManager in a member variable to
- // avoid accessing the RenderViewImpl.
- const scoped_refptr<BrowserPluginManager> browser_plugin_manager_;
-
// Used for HW compositing.
scoped_refptr<ChildFrameCompositingHelper> compositing_helper_;
diff --git a/chromium/content/renderer/browser_plugin/browser_plugin_manager.cc b/chromium/content/renderer/browser_plugin/browser_plugin_manager.cc
index 16cc98e0009..a4861864f7c 100644
--- a/chromium/content/renderer/browser_plugin/browser_plugin_manager.cc
+++ b/chromium/content/renderer/browser_plugin/browser_plugin_manager.cc
@@ -3,28 +3,26 @@
// found in the LICENSE file.
#include "content/renderer/browser_plugin/browser_plugin_manager.h"
-
#include "base/memory/scoped_ptr.h"
#include "content/common/browser_plugin/browser_plugin_constants.h"
#include "content/common/browser_plugin/browser_plugin_messages.h"
#include "content/common/frame_messages.h"
#include "content/public/renderer/browser_plugin_delegate.h"
-#include "content/public/renderer/render_thread.h"
+#include "content/public/renderer/content_renderer_client.h"
#include "content/renderer/browser_plugin/browser_plugin.h"
+#include "content/renderer/render_thread_impl.h"
#include "ipc/ipc_message_macros.h"
namespace content {
// static
-BrowserPluginManager* BrowserPluginManager::Create(
- RenderViewImpl* render_view) {
- return new BrowserPluginManager(render_view);
+BrowserPluginManager* BrowserPluginManager::Get() {
+ if (!RenderThreadImpl::current())
+ return nullptr;
+ return RenderThreadImpl::current()->browser_plugin_manager();
}
-BrowserPluginManager::BrowserPluginManager(RenderViewImpl* render_view)
- : RenderViewObserver(render_view),
- current_instance_id_(browser_plugin::kInstanceIDNone),
- render_view_(render_view->AsWeakPtr()) {
+BrowserPluginManager::BrowserPluginManager() {
}
BrowserPluginManager::~BrowserPluginManager() {
@@ -46,21 +44,13 @@ BrowserPlugin* BrowserPluginManager::GetBrowserPlugin(
}
int BrowserPluginManager::GetNextInstanceID() {
- return ++current_instance_id_;
-}
-
-void BrowserPluginManager::UpdateDeviceScaleFactor() {
- IDMap<BrowserPlugin>::iterator iter(&instances_);
- while (!iter.IsAtEnd()) {
- iter.GetCurrentValue()->UpdateDeviceScaleFactor();
- iter.Advance();
- }
+ return RenderThreadImpl::current()->GenerateRoutingID();
}
void BrowserPluginManager::UpdateFocusState() {
IDMap<BrowserPlugin>::iterator iter(&instances_);
while (!iter.IsAtEnd()) {
- iter.GetCurrentValue()->UpdateGuestFocusState();
+ iter.GetCurrentValue()->UpdateGuestFocusState(blink::WebFocusTypeNone);
iter.Advance();
}
}
@@ -71,25 +61,37 @@ void BrowserPluginManager::Attach(int browser_plugin_instance_id) {
plugin->Attach();
}
+void BrowserPluginManager::Detach(int browser_plugin_instance_id) {
+ BrowserPlugin* plugin = GetBrowserPlugin(browser_plugin_instance_id);
+ if (plugin)
+ plugin->Detach();
+}
+
BrowserPlugin* BrowserPluginManager::CreateBrowserPlugin(
- RenderViewImpl* render_view,
- blink::WebFrame* frame,
+ RenderFrame* render_frame,
scoped_ptr<BrowserPluginDelegate> delegate) {
- return new BrowserPlugin(render_view, frame, delegate.Pass());
+ return new BrowserPlugin(render_frame, delegate.Pass());
}
-void BrowserPluginManager::DidCommitCompositorFrame() {
+void BrowserPluginManager::DidCommitCompositorFrame(
+ int render_frame_routing_id) {
IDMap<BrowserPlugin>::iterator iter(&instances_);
while (!iter.IsAtEnd()) {
- iter.GetCurrentValue()->DidCommitCompositorFrame();
+ if (iter.GetCurrentValue()->render_frame_routing_id() ==
+ render_frame_routing_id) {
+ iter.GetCurrentValue()->DidCommitCompositorFrame();
+ }
iter.Advance();
}
}
-bool BrowserPluginManager::OnMessageReceived(
+bool BrowserPluginManager::OnControlMessageReceived(
const IPC::Message& message) {
- if (!BrowserPlugin::ShouldForwardToBrowserPlugin(message))
+ if (!BrowserPlugin::ShouldForwardToBrowserPlugin(message) &&
+ !content::GetContentClient()->renderer()->
+ ShouldForwardToGuestContainer(message)) {
return false;
+ }
int browser_plugin_instance_id = browser_plugin::kInstanceIDNone;
// All allowed messages must have |browser_plugin_instance_id| as their
@@ -112,7 +114,7 @@ bool BrowserPluginManager::OnMessageReceived(
}
bool BrowserPluginManager::Send(IPC::Message* msg) {
- return RenderThread::Get()->Send(msg);
+ return RenderThreadImpl::current()->Send(msg);
}
void BrowserPluginManager::OnCompositorFrameSwappedPluginUnavailable(
@@ -122,11 +124,11 @@ void BrowserPluginManager::OnCompositorFrameSwappedPluginUnavailable(
return;
FrameHostMsg_CompositorFrameSwappedACK_Params params;
- params.producing_host_id = param.b.producing_host_id;
- params.producing_route_id = param.b.producing_route_id;
- params.output_surface_id = param.b.output_surface_id;
+ params.producing_host_id = get<1>(param).producing_host_id;
+ params.producing_route_id = get<1>(param).producing_route_id;
+ params.output_surface_id = get<1>(param).output_surface_id;
Send(new BrowserPluginHostMsg_CompositorFrameSwappedACK(
- routing_id(), param.a, params));
+ get<0>(param), params));
}
} // namespace content
diff --git a/chromium/content/renderer/browser_plugin/browser_plugin_manager.h b/chromium/content/renderer/browser_plugin/browser_plugin_manager.h
index 23cde185ed3..34386656ef0 100644
--- a/chromium/content/renderer/browser_plugin/browser_plugin_manager.h
+++ b/chromium/content/renderer/browser_plugin/browser_plugin_manager.h
@@ -6,9 +6,8 @@
#define CONTENT_RENDERER_BROWSER_PLUGIN_BROWSER_PLUGIN_MANAGER_H_
#include "base/id_map.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "content/public/renderer/render_view_observer.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/public/renderer/render_process_observer.h"
#include "ipc/ipc_sender.h"
namespace blink {
@@ -19,68 +18,57 @@ namespace content {
class BrowserPlugin;
class BrowserPluginDelegate;
-class RenderViewImpl;
+class RenderFrame;
// BrowserPluginManager manages the routing of messages to the appropriate
-// BrowserPlugin object based on its instance ID.
-class CONTENT_EXPORT BrowserPluginManager
- : public RenderViewObserver,
- public base::RefCounted<BrowserPluginManager> {
+// BrowserPlugin object based on its instance ID. There is one BrowserPlugin
+// for the RenderThread.
+class CONTENT_EXPORT BrowserPluginManager : public RenderProcessObserver {
public:
- // Returns the one BrowserPluginManager for this process.
- static BrowserPluginManager* Create(RenderViewImpl* render_view);
+ static BrowserPluginManager* Get();
- explicit BrowserPluginManager(RenderViewImpl* render_view);
+ BrowserPluginManager();
+ ~BrowserPluginManager() override;
// Creates a new BrowserPlugin object.
// BrowserPlugin is responsible for associating itself with the
// BrowserPluginManager via AddBrowserPlugin. When it is destroyed, it is
// responsible for removing its association via RemoveBrowserPlugin.
BrowserPlugin* CreateBrowserPlugin(
- RenderViewImpl* render_view,
- blink::WebFrame* frame,
+ RenderFrame* render_frame,
scoped_ptr<BrowserPluginDelegate> delegate);
void Attach(int browser_plugin_instance_id);
+ void Detach(int browser_plugin_instance_id);
+
void AddBrowserPlugin(int browser_plugin_instance_id,
BrowserPlugin* browser_plugin);
void RemoveBrowserPlugin(int browser_plugin_instance_id);
BrowserPlugin* GetBrowserPlugin(int browser_plugin_instance_id) const;
- void UpdateDeviceScaleFactor();
void UpdateFocusState();
- RenderViewImpl* render_view() const { return render_view_.get(); }
+
+ // Returns a new instance ID to be used by BrowserPlugin. Instance IDs are
+ // unique per process.
int GetNextInstanceID();
- // RenderViewObserver override. Call on render thread.
- void DidCommitCompositorFrame() override;
- bool OnMessageReceived(const IPC::Message& message) override;
- bool Send(IPC::Message* msg) override;
+ void DidCommitCompositorFrame(int render_frame_routing_id);
+ bool Send(IPC::Message* msg);
- // Don't destroy the BrowserPluginManager when the RenderViewImpl goes away.
- // BrowserPluginManager's lifetime is managed by a reference count. Once
- // the host RenderViewImpl and all BrowserPlugins release their references,
- // then the BrowserPluginManager will be destroyed.
- void OnDestruct() override {}
+ // RenderProcessObserver override.
+ bool OnControlMessageReceived(const IPC::Message& message) override;
private:
- // Friend RefCounted so that the dtor can be non-public.
- friend class base::RefCounted<BrowserPluginManager>;
-
- ~BrowserPluginManager() override;
-
// IPC message handlers.
void OnCompositorFrameSwappedPluginUnavailable(const IPC::Message& message);
// This map is keyed by guest instance IDs.
IDMap<BrowserPlugin> instances_;
- int current_instance_id_;
- base::WeakPtr<RenderViewImpl> render_view_;
DISALLOW_COPY_AND_ASSIGN(BrowserPluginManager);
};
} // namespace content
-#endif // CONTENT_RENDERER_BROWSER_PLUGIN_BROWSER_PLUGIN_MANAGER_H_
+#endif // CONTENT_RENDERER_BROWSER_PLUGIN_BROWSER_PLUGIN_MANAGER_H_
diff --git a/chromium/content/renderer/browser_render_view_browsertest.cc b/chromium/content/renderer/browser_render_view_browsertest.cc
index 2c12bc7a478..328a4efe398 100644
--- a/chromium/content/renderer/browser_render_view_browsertest.cc
+++ b/chromium/content/renderer/browser_render_view_browsertest.cc
@@ -137,7 +137,7 @@ class RenderViewBrowserTest : public ContentBrowserTest {
public:
RenderViewBrowserTest() {}
- void SetUpCommandLine(CommandLine* command_line) override {
+ void SetUpCommandLine(base::CommandLine* command_line) override {
// This method is needed to allow interaction with in-process renderer
// and use of a test ContentRendererClient.
command_line->AppendSwitch(switches::kSingleProcess);
diff --git a/chromium/content/renderer/cache_storage/OWNERS b/chromium/content/renderer/cache_storage/OWNERS
new file mode 100644
index 00000000000..2db987d718b
--- /dev/null
+++ b/chromium/content/renderer/cache_storage/OWNERS
@@ -0,0 +1,4 @@
+michaeln@chromium.org
+nhiroki@chromium.org
+jkarlin@chromium.org
+jsbell@chromium.org
diff --git a/chromium/content/renderer/cache_storage/cache_storage_dispatcher.cc b/chromium/content/renderer/cache_storage/cache_storage_dispatcher.cc
new file mode 100644
index 00000000000..da40cbf1ff8
--- /dev/null
+++ b/chromium/content/renderer/cache_storage/cache_storage_dispatcher.cc
@@ -0,0 +1,674 @@
+// Copyright 2014 The Chromium Authors. 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/renderer/cache_storage/cache_storage_dispatcher.h"
+
+#include <map>
+#include <string>
+#include <utility>
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_local.h"
+#include "content/child/thread_safe_sender.h"
+#include "content/common/cache_storage/cache_storage_messages.h"
+#include "content/public/common/referrer.h"
+#include "content/public/renderer/render_thread.h"
+#include "content/renderer/service_worker/service_worker_type_util.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerCache.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerRequest.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerResponse.h"
+
+using base::TimeTicks;
+
+namespace content {
+
+using blink::WebServiceWorkerCacheStorage;
+using blink::WebServiceWorkerCacheError;
+using blink::WebServiceWorkerRequest;
+
+static base::LazyInstance<base::ThreadLocalPointer<CacheStorageDispatcher>>::
+ Leaky g_cache_storage_dispatcher_tls = LAZY_INSTANCE_INITIALIZER;
+
+namespace {
+
+CacheStorageDispatcher* const kHasBeenDeleted =
+ reinterpret_cast<CacheStorageDispatcher*>(0x1);
+
+ServiceWorkerFetchRequest FetchRequestFromWebRequest(
+ const blink::WebServiceWorkerRequest& web_request) {
+ ServiceWorkerHeaderMap headers;
+ GetServiceWorkerHeaderMapFromWebRequest(web_request, &headers);
+
+ return ServiceWorkerFetchRequest(
+ web_request.url(), base::UTF16ToASCII(web_request.method()), headers,
+ Referrer(web_request.referrerUrl(), web_request.referrerPolicy()),
+ web_request.isReload());
+}
+
+void PopulateWebRequestFromFetchRequest(
+ const ServiceWorkerFetchRequest& request,
+ blink::WebServiceWorkerRequest* web_request) {
+ web_request->setURL(request.url);
+ web_request->setMethod(base::ASCIIToUTF16(request.method));
+ for (ServiceWorkerHeaderMap::const_iterator i = request.headers.begin(),
+ end = request.headers.end();
+ i != end; ++i) {
+ web_request->setHeader(base::ASCIIToUTF16(i->first),
+ base::ASCIIToUTF16(i->second));
+ }
+ web_request->setReferrer(base::ASCIIToUTF16(request.referrer.url.spec()),
+ request.referrer.policy);
+ web_request->setIsReload(request.is_reload);
+}
+
+blink::WebVector<blink::WebServiceWorkerRequest> WebRequestsFromRequests(
+ const std::vector<ServiceWorkerFetchRequest>& requests) {
+ blink::WebVector<blink::WebServiceWorkerRequest> web_requests(
+ requests.size());
+ for (size_t i = 0; i < requests.size(); ++i)
+ PopulateWebRequestFromFetchRequest(requests[i], &(web_requests[i]));
+ return web_requests;
+}
+
+ServiceWorkerResponse ResponseFromWebResponse(
+ const blink::WebServiceWorkerResponse& web_response) {
+ ServiceWorkerHeaderMap headers;
+ GetServiceWorkerHeaderMapFromWebResponse(web_response, &headers);
+ // We don't support streaming for cache.
+ DCHECK(web_response.streamURL().isEmpty());
+ return ServiceWorkerResponse(web_response.url(), web_response.status(),
+ base::UTF16ToASCII(web_response.statusText()),
+ web_response.responseType(), headers,
+ base::UTF16ToASCII(web_response.blobUUID()),
+ web_response.blobSize(),
+ web_response.streamURL());
+}
+
+CacheStorageCacheQueryParams QueryParamsFromWebQueryParams(
+ const blink::WebServiceWorkerCache::QueryParams& web_query_params) {
+ CacheStorageCacheQueryParams query_params;
+ query_params.ignore_search = web_query_params.ignoreSearch;
+ query_params.ignore_method = web_query_params.ignoreMethod;
+ query_params.ignore_vary = web_query_params.ignoreVary;
+ query_params.cache_name = web_query_params.cacheName;
+ return query_params;
+}
+
+CacheStorageCacheOperationType CacheOperationTypeFromWebCacheOperationType(
+ blink::WebServiceWorkerCache::OperationType operation_type) {
+ switch (operation_type) {
+ case blink::WebServiceWorkerCache::OperationTypePut:
+ return CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT;
+ case blink::WebServiceWorkerCache::OperationTypeDelete:
+ return CACHE_STORAGE_CACHE_OPERATION_TYPE_DELETE;
+ default:
+ return CACHE_STORAGE_CACHE_OPERATION_TYPE_UNDEFINED;
+ }
+}
+
+CacheStorageBatchOperation BatchOperationFromWebBatchOperation(
+ const blink::WebServiceWorkerCache::BatchOperation& web_operation) {
+ CacheStorageBatchOperation operation;
+ operation.operation_type =
+ CacheOperationTypeFromWebCacheOperationType(web_operation.operationType);
+ operation.request = FetchRequestFromWebRequest(web_operation.request);
+ operation.response = ResponseFromWebResponse(web_operation.response);
+ operation.match_params =
+ QueryParamsFromWebQueryParams(web_operation.matchParams);
+ return operation;
+}
+
+template <typename T>
+void ClearCallbacksMapWithErrors(T* callbacks_map) {
+ typename T::iterator iter(callbacks_map);
+ while (!iter.IsAtEnd()) {
+ blink::WebServiceWorkerCacheError reason =
+ blink::WebServiceWorkerCacheErrorNotFound;
+ iter.GetCurrentValue()->onError(&reason);
+ callbacks_map->Remove(iter.GetCurrentKey());
+ iter.Advance();
+ }
+}
+
+} // namespace
+
+// The WebCache object is the Chromium side implementation of the Blink
+// WebServiceWorkerCache API. Most of its methods delegate directly to the
+// ServiceWorkerStorage object, which is able to assign unique IDs as well
+// as have a lifetime longer than the requests.
+class CacheStorageDispatcher::WebCache : public blink::WebServiceWorkerCache {
+ public:
+ WebCache(base::WeakPtr<CacheStorageDispatcher> dispatcher, int cache_id)
+ : dispatcher_(dispatcher), cache_id_(cache_id) {}
+
+ virtual ~WebCache() {
+ if (dispatcher_)
+ dispatcher_->OnWebCacheDestruction(cache_id_);
+ }
+
+ // From blink::WebServiceWorkerCache:
+ virtual void dispatchMatch(CacheMatchCallbacks* callbacks,
+ const blink::WebServiceWorkerRequest& request,
+ const QueryParams& query_params) {
+ if (!dispatcher_)
+ return;
+ dispatcher_->dispatchMatchForCache(cache_id_, callbacks, request,
+ query_params);
+ }
+ virtual void dispatchMatchAll(CacheWithResponsesCallbacks* callbacks,
+ const blink::WebServiceWorkerRequest& request,
+ const QueryParams& query_params) {
+ if (!dispatcher_)
+ return;
+ dispatcher_->dispatchMatchAllForCache(cache_id_, callbacks, request,
+ query_params);
+ }
+ virtual void dispatchKeys(CacheWithRequestsCallbacks* callbacks,
+ const blink::WebServiceWorkerRequest* request,
+ const QueryParams& query_params) {
+ if (!dispatcher_)
+ return;
+ dispatcher_->dispatchKeysForCache(cache_id_, callbacks, request,
+ query_params);
+ }
+ virtual void dispatchBatch(
+ CacheBatchCallbacks* callbacks,
+ const blink::WebVector<BatchOperation>& batch_operations) {
+ if (!dispatcher_)
+ return;
+ dispatcher_->dispatchBatchForCache(cache_id_, callbacks, batch_operations);
+ }
+
+ private:
+ const base::WeakPtr<CacheStorageDispatcher> dispatcher_;
+ const int cache_id_;
+};
+
+CacheStorageDispatcher::CacheStorageDispatcher(
+ ThreadSafeSender* thread_safe_sender)
+ : thread_safe_sender_(thread_safe_sender), weak_factory_(this) {
+ g_cache_storage_dispatcher_tls.Pointer()->Set(this);
+}
+
+CacheStorageDispatcher::~CacheStorageDispatcher() {
+ ClearCallbacksMapWithErrors(&has_callbacks_);
+ ClearCallbacksMapWithErrors(&open_callbacks_);
+ ClearCallbacksMapWithErrors(&delete_callbacks_);
+ ClearCallbacksMapWithErrors(&keys_callbacks_);
+ ClearCallbacksMapWithErrors(&match_callbacks_);
+
+ ClearCallbacksMapWithErrors(&cache_match_callbacks_);
+ ClearCallbacksMapWithErrors(&cache_match_all_callbacks_);
+ ClearCallbacksMapWithErrors(&cache_keys_callbacks_);
+ ClearCallbacksMapWithErrors(&cache_batch_callbacks_);
+
+ g_cache_storage_dispatcher_tls.Pointer()->Set(kHasBeenDeleted);
+}
+
+CacheStorageDispatcher* CacheStorageDispatcher::ThreadSpecificInstance(
+ ThreadSafeSender* thread_safe_sender) {
+ if (g_cache_storage_dispatcher_tls.Pointer()->Get() == kHasBeenDeleted) {
+ NOTREACHED() << "Re-instantiating TLS CacheStorageDispatcher.";
+ g_cache_storage_dispatcher_tls.Pointer()->Set(NULL);
+ }
+ if (g_cache_storage_dispatcher_tls.Pointer()->Get())
+ return g_cache_storage_dispatcher_tls.Pointer()->Get();
+
+ CacheStorageDispatcher* dispatcher =
+ new CacheStorageDispatcher(thread_safe_sender);
+ if (WorkerTaskRunner::Instance()->CurrentWorkerId())
+ WorkerTaskRunner::Instance()->AddStopObserver(dispatcher);
+ return dispatcher;
+}
+
+void CacheStorageDispatcher::OnWorkerRunLoopStopped() {
+ delete this;
+}
+
+bool CacheStorageDispatcher::Send(IPC::Message* msg) {
+ return thread_safe_sender_->Send(msg);
+}
+
+bool CacheStorageDispatcher::OnMessageReceived(const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(CacheStorageDispatcher, message)
+ IPC_MESSAGE_HANDLER(CacheStorageMsg_CacheStorageHasSuccess,
+ OnCacheStorageHasSuccess)
+ IPC_MESSAGE_HANDLER(CacheStorageMsg_CacheStorageOpenSuccess,
+ OnCacheStorageOpenSuccess)
+ IPC_MESSAGE_HANDLER(CacheStorageMsg_CacheStorageDeleteSuccess,
+ OnCacheStorageDeleteSuccess)
+ IPC_MESSAGE_HANDLER(CacheStorageMsg_CacheStorageKeysSuccess,
+ OnCacheStorageKeysSuccess)
+ IPC_MESSAGE_HANDLER(CacheStorageMsg_CacheStorageMatchSuccess,
+ OnCacheStorageMatchSuccess)
+ IPC_MESSAGE_HANDLER(CacheStorageMsg_CacheStorageHasError,
+ OnCacheStorageHasError)
+ IPC_MESSAGE_HANDLER(CacheStorageMsg_CacheStorageOpenError,
+ OnCacheStorageOpenError)
+ IPC_MESSAGE_HANDLER(CacheStorageMsg_CacheStorageDeleteError,
+ OnCacheStorageDeleteError)
+ IPC_MESSAGE_HANDLER(CacheStorageMsg_CacheStorageKeysError,
+ OnCacheStorageKeysError)
+ IPC_MESSAGE_HANDLER(CacheStorageMsg_CacheStorageMatchError,
+ OnCacheStorageMatchError)
+ IPC_MESSAGE_HANDLER(CacheStorageMsg_CacheMatchSuccess,
+ OnCacheMatchSuccess)
+ IPC_MESSAGE_HANDLER(CacheStorageMsg_CacheMatchAllSuccess,
+ OnCacheMatchAllSuccess)
+ IPC_MESSAGE_HANDLER(CacheStorageMsg_CacheKeysSuccess, OnCacheKeysSuccess)
+ IPC_MESSAGE_HANDLER(CacheStorageMsg_CacheBatchSuccess,
+ OnCacheBatchSuccess)
+ IPC_MESSAGE_HANDLER(CacheStorageMsg_CacheMatchError, OnCacheMatchError)
+ IPC_MESSAGE_HANDLER(CacheStorageMsg_CacheMatchAllError,
+ OnCacheMatchAllError)
+ IPC_MESSAGE_HANDLER(CacheStorageMsg_CacheKeysError, OnCacheKeysError)
+ IPC_MESSAGE_HANDLER(CacheStorageMsg_CacheBatchError, OnCacheBatchError)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+
+ return handled;
+}
+
+void CacheStorageDispatcher::OnCacheStorageHasSuccess(int thread_id,
+ int request_id) {
+ DCHECK_EQ(thread_id, CurrentWorkerId());
+ UMA_HISTOGRAM_TIMES("ServiceWorkerCache.CacheStorage.Has",
+ TimeTicks::Now() - has_times_[request_id]);
+ WebServiceWorkerCacheStorage::CacheStorageCallbacks* callbacks =
+ has_callbacks_.Lookup(request_id);
+ callbacks->onSuccess();
+ has_callbacks_.Remove(request_id);
+ has_times_.erase(request_id);
+}
+
+void CacheStorageDispatcher::OnCacheStorageOpenSuccess(int thread_id,
+ int request_id,
+ int cache_id) {
+ DCHECK_EQ(thread_id, CurrentWorkerId());
+ WebCache* web_cache = new WebCache(weak_factory_.GetWeakPtr(), cache_id);
+ web_caches_.AddWithID(web_cache, cache_id);
+ UMA_HISTOGRAM_TIMES("ServiceWorkerCache.CacheStorage.Open",
+ TimeTicks::Now() - open_times_[request_id]);
+ WebServiceWorkerCacheStorage::CacheStorageWithCacheCallbacks* callbacks =
+ open_callbacks_.Lookup(request_id);
+ callbacks->onSuccess(web_cache);
+ open_callbacks_.Remove(request_id);
+ open_times_.erase(request_id);
+}
+
+void CacheStorageDispatcher::OnCacheStorageDeleteSuccess(int thread_id,
+ int request_id) {
+ DCHECK_EQ(thread_id, CurrentWorkerId());
+ UMA_HISTOGRAM_TIMES("ServiceWorkerCache.CacheStorage.Delete",
+ TimeTicks::Now() - delete_times_[request_id]);
+ WebServiceWorkerCacheStorage::CacheStorageCallbacks* callbacks =
+ delete_callbacks_.Lookup(request_id);
+ callbacks->onSuccess();
+ delete_callbacks_.Remove(request_id);
+ delete_times_.erase(request_id);
+}
+
+void CacheStorageDispatcher::OnCacheStorageKeysSuccess(
+ int thread_id,
+ int request_id,
+ const std::vector<base::string16>& keys) {
+ DCHECK_EQ(thread_id, CurrentWorkerId());
+ blink::WebVector<blink::WebString> webKeys(keys.size());
+ for (size_t i = 0; i < keys.size(); ++i)
+ webKeys[i] = keys[i];
+
+ UMA_HISTOGRAM_TIMES("ServiceWorkerCache.CacheStorage.Keys",
+ TimeTicks::Now() - keys_times_[request_id]);
+ WebServiceWorkerCacheStorage::CacheStorageKeysCallbacks* callbacks =
+ keys_callbacks_.Lookup(request_id);
+ callbacks->onSuccess(&webKeys);
+ keys_callbacks_.Remove(request_id);
+ keys_times_.erase(request_id);
+}
+
+void CacheStorageDispatcher::OnCacheStorageMatchSuccess(
+ int thread_id,
+ int request_id,
+ const ServiceWorkerResponse& response) {
+ DCHECK_EQ(thread_id, CurrentWorkerId());
+ blink::WebServiceWorkerResponse web_response;
+ PopulateWebResponseFromResponse(response, &web_response);
+
+ UMA_HISTOGRAM_TIMES("ServiceWorkerCache.CacheStorage.Match",
+ TimeTicks::Now() - match_times_[request_id]);
+ WebServiceWorkerCacheStorage::CacheStorageMatchCallbacks* callbacks =
+ match_callbacks_.Lookup(request_id);
+ callbacks->onSuccess(&web_response);
+ match_callbacks_.Remove(request_id);
+ match_times_.erase(request_id);
+}
+
+void CacheStorageDispatcher::OnCacheStorageHasError(
+ int thread_id,
+ int request_id,
+ blink::WebServiceWorkerCacheError reason) {
+ DCHECK_EQ(thread_id, CurrentWorkerId());
+ WebServiceWorkerCacheStorage::CacheStorageCallbacks* callbacks =
+ has_callbacks_.Lookup(request_id);
+ callbacks->onError(&reason);
+ has_callbacks_.Remove(request_id);
+ has_times_.erase(request_id);
+}
+
+void CacheStorageDispatcher::OnCacheStorageOpenError(
+ int thread_id,
+ int request_id,
+ blink::WebServiceWorkerCacheError reason) {
+ DCHECK_EQ(thread_id, CurrentWorkerId());
+ WebServiceWorkerCacheStorage::CacheStorageWithCacheCallbacks* callbacks =
+ open_callbacks_.Lookup(request_id);
+ callbacks->onError(&reason);
+ open_callbacks_.Remove(request_id);
+ open_times_.erase(request_id);
+}
+
+void CacheStorageDispatcher::OnCacheStorageDeleteError(
+ int thread_id,
+ int request_id,
+ blink::WebServiceWorkerCacheError reason) {
+ DCHECK_EQ(thread_id, CurrentWorkerId());
+ WebServiceWorkerCacheStorage::CacheStorageCallbacks* callbacks =
+ delete_callbacks_.Lookup(request_id);
+ callbacks->onError(&reason);
+ delete_callbacks_.Remove(request_id);
+ delete_times_.erase(request_id);
+}
+
+void CacheStorageDispatcher::OnCacheStorageKeysError(
+ int thread_id,
+ int request_id,
+ blink::WebServiceWorkerCacheError reason) {
+ DCHECK_EQ(thread_id, CurrentWorkerId());
+ WebServiceWorkerCacheStorage::CacheStorageKeysCallbacks* callbacks =
+ keys_callbacks_.Lookup(request_id);
+ callbacks->onError(&reason);
+ keys_callbacks_.Remove(request_id);
+ keys_times_.erase(request_id);
+}
+
+void CacheStorageDispatcher::OnCacheStorageMatchError(
+ int thread_id,
+ int request_id,
+ blink::WebServiceWorkerCacheError reason) {
+ DCHECK_EQ(thread_id, CurrentWorkerId());
+ WebServiceWorkerCacheStorage::CacheStorageMatchCallbacks* callbacks =
+ match_callbacks_.Lookup(request_id);
+ callbacks->onError(&reason);
+ match_callbacks_.Remove(request_id);
+ match_times_.erase(request_id);
+}
+
+void CacheStorageDispatcher::OnCacheMatchSuccess(
+ int thread_id,
+ int request_id,
+ const ServiceWorkerResponse& response) {
+ DCHECK_EQ(thread_id, CurrentWorkerId());
+ blink::WebServiceWorkerResponse web_response;
+ PopulateWebResponseFromResponse(response, &web_response);
+
+ UMA_HISTOGRAM_TIMES("ServiceWorkerCache.Cache.Match",
+ TimeTicks::Now() - cache_match_times_[request_id]);
+ blink::WebServiceWorkerCache::CacheMatchCallbacks* callbacks =
+ cache_match_callbacks_.Lookup(request_id);
+ callbacks->onSuccess(&web_response);
+ cache_match_callbacks_.Remove(request_id);
+ cache_match_times_.erase(request_id);
+}
+
+void CacheStorageDispatcher::OnCacheMatchAllSuccess(
+ int thread_id,
+ int request_id,
+ const std::vector<ServiceWorkerResponse>& responses) {
+ DCHECK_EQ(thread_id, CurrentWorkerId());
+ blink::WebVector<blink::WebServiceWorkerResponse> web_responses =
+ WebResponsesFromResponses(responses);
+
+ UMA_HISTOGRAM_TIMES("ServiceWorkerCache.Cache.MatchAll",
+ TimeTicks::Now() - cache_match_all_times_[request_id]);
+ blink::WebServiceWorkerCache::CacheWithResponsesCallbacks* callbacks =
+ cache_match_all_callbacks_.Lookup(request_id);
+ callbacks->onSuccess(&web_responses);
+ cache_match_all_callbacks_.Remove(request_id);
+ cache_match_all_times_.erase(request_id);
+}
+
+void CacheStorageDispatcher::OnCacheKeysSuccess(
+ int thread_id,
+ int request_id,
+ const std::vector<ServiceWorkerFetchRequest>& requests) {
+ DCHECK_EQ(thread_id, CurrentWorkerId());
+ blink::WebVector<blink::WebServiceWorkerRequest> web_requests =
+ WebRequestsFromRequests(requests);
+
+ UMA_HISTOGRAM_TIMES("ServiceWorkerCache.Cache.Keys",
+ TimeTicks::Now() - cache_keys_times_[request_id]);
+ blink::WebServiceWorkerCache::CacheWithRequestsCallbacks* callbacks =
+ cache_keys_callbacks_.Lookup(request_id);
+ callbacks->onSuccess(&web_requests);
+ cache_keys_callbacks_.Remove(request_id);
+ cache_keys_times_.erase(request_id);
+}
+
+void CacheStorageDispatcher::OnCacheBatchSuccess(
+ int thread_id,
+ int request_id) {
+ DCHECK_EQ(thread_id, CurrentWorkerId());
+
+ UMA_HISTOGRAM_TIMES("ServiceWorkerCache.Cache.Batch",
+ TimeTicks::Now() - cache_batch_times_[request_id]);
+ blink::WebServiceWorkerCache::CacheBatchCallbacks* callbacks =
+ cache_batch_callbacks_.Lookup(request_id);
+ callbacks->onSuccess();
+ cache_batch_callbacks_.Remove(request_id);
+ cache_batch_times_.erase(request_id);
+}
+
+void CacheStorageDispatcher::OnCacheMatchError(
+ int thread_id,
+ int request_id,
+ blink::WebServiceWorkerCacheError reason) {
+ DCHECK_EQ(thread_id, CurrentWorkerId());
+ blink::WebServiceWorkerCache::CacheMatchCallbacks* callbacks =
+ cache_match_callbacks_.Lookup(request_id);
+ callbacks->onError(&reason);
+ cache_match_callbacks_.Remove(request_id);
+ cache_match_times_.erase(request_id);
+}
+
+void CacheStorageDispatcher::OnCacheMatchAllError(
+ int thread_id,
+ int request_id,
+ blink::WebServiceWorkerCacheError reason) {
+ DCHECK_EQ(thread_id, CurrentWorkerId());
+ blink::WebServiceWorkerCache::CacheWithResponsesCallbacks* callbacks =
+ cache_match_all_callbacks_.Lookup(request_id);
+ callbacks->onError(&reason);
+ cache_match_all_callbacks_.Remove(request_id);
+ cache_match_all_times_.erase(request_id);
+}
+
+void CacheStorageDispatcher::OnCacheKeysError(
+ int thread_id,
+ int request_id,
+ blink::WebServiceWorkerCacheError reason) {
+ DCHECK_EQ(thread_id, CurrentWorkerId());
+ blink::WebServiceWorkerCache::CacheWithRequestsCallbacks* callbacks =
+ cache_keys_callbacks_.Lookup(request_id);
+ callbacks->onError(&reason);
+ cache_keys_callbacks_.Remove(request_id);
+ cache_keys_times_.erase(request_id);
+}
+
+void CacheStorageDispatcher::OnCacheBatchError(
+ int thread_id,
+ int request_id,
+ blink::WebServiceWorkerCacheError reason) {
+ DCHECK_EQ(thread_id, CurrentWorkerId());
+ blink::WebServiceWorkerCache::CacheBatchCallbacks* callbacks =
+ cache_batch_callbacks_.Lookup(request_id);
+ callbacks->onError(&reason);
+ cache_batch_callbacks_.Remove(request_id);
+ cache_batch_times_.erase(request_id);
+}
+
+void CacheStorageDispatcher::dispatchHas(
+ WebServiceWorkerCacheStorage::CacheStorageCallbacks* callbacks,
+ const GURL& origin,
+ const blink::WebString& cacheName) {
+ int request_id = has_callbacks_.Add(callbacks);
+ has_times_[request_id] = base::TimeTicks::Now();
+ Send(new CacheStorageHostMsg_CacheStorageHas(CurrentWorkerId(), request_id,
+ origin, cacheName));
+}
+
+void CacheStorageDispatcher::dispatchOpen(
+ WebServiceWorkerCacheStorage::CacheStorageWithCacheCallbacks* callbacks,
+ const GURL& origin,
+ const blink::WebString& cacheName) {
+ int request_id = open_callbacks_.Add(callbacks);
+ open_times_[request_id] = base::TimeTicks::Now();
+ Send(new CacheStorageHostMsg_CacheStorageOpen(CurrentWorkerId(), request_id,
+ origin, cacheName));
+}
+
+void CacheStorageDispatcher::dispatchDelete(
+ WebServiceWorkerCacheStorage::CacheStorageCallbacks* callbacks,
+ const GURL& origin,
+ const blink::WebString& cacheName) {
+ int request_id = delete_callbacks_.Add(callbacks);
+ delete_times_[request_id] = base::TimeTicks::Now();
+ Send(new CacheStorageHostMsg_CacheStorageDelete(CurrentWorkerId(), request_id,
+ origin, cacheName));
+}
+
+void CacheStorageDispatcher::dispatchKeys(
+ WebServiceWorkerCacheStorage::CacheStorageKeysCallbacks* callbacks,
+ const GURL& origin) {
+ int request_id = keys_callbacks_.Add(callbacks);
+ keys_times_[request_id] = base::TimeTicks::Now();
+ Send(new CacheStorageHostMsg_CacheStorageKeys(CurrentWorkerId(), request_id,
+ origin));
+}
+
+void CacheStorageDispatcher::dispatchMatch(
+ WebServiceWorkerCacheStorage::CacheStorageMatchCallbacks* callbacks,
+ const GURL& origin,
+ const blink::WebServiceWorkerRequest& request,
+ const blink::WebServiceWorkerCache::QueryParams& query_params) {
+ int request_id = match_callbacks_.Add(callbacks);
+ match_times_[request_id] = base::TimeTicks::Now();
+ Send(new CacheStorageHostMsg_CacheStorageMatch(
+ CurrentWorkerId(), request_id, origin,
+ FetchRequestFromWebRequest(request),
+ QueryParamsFromWebQueryParams(query_params)));
+}
+
+void CacheStorageDispatcher::dispatchMatchForCache(
+ int cache_id,
+ blink::WebServiceWorkerCache::CacheMatchCallbacks* callbacks,
+ const blink::WebServiceWorkerRequest& request,
+ const blink::WebServiceWorkerCache::QueryParams& query_params) {
+ int request_id = cache_match_callbacks_.Add(callbacks);
+ cache_match_times_[request_id] = base::TimeTicks::Now();
+
+ Send(new CacheStorageHostMsg_CacheMatch(
+ CurrentWorkerId(), request_id, cache_id,
+ FetchRequestFromWebRequest(request),
+ QueryParamsFromWebQueryParams(query_params)));
+}
+
+void CacheStorageDispatcher::dispatchMatchAllForCache(
+ int cache_id,
+ blink::WebServiceWorkerCache::CacheWithResponsesCallbacks* callbacks,
+ const blink::WebServiceWorkerRequest& request,
+ const blink::WebServiceWorkerCache::QueryParams& query_params) {
+ int request_id = cache_match_all_callbacks_.Add(callbacks);
+ cache_match_all_times_[request_id] = base::TimeTicks::Now();
+
+ Send(new CacheStorageHostMsg_CacheMatchAll(
+ CurrentWorkerId(), request_id, cache_id,
+ FetchRequestFromWebRequest(request),
+ QueryParamsFromWebQueryParams(query_params)));
+}
+
+void CacheStorageDispatcher::dispatchKeysForCache(
+ int cache_id,
+ blink::WebServiceWorkerCache::CacheWithRequestsCallbacks* callbacks,
+ const blink::WebServiceWorkerRequest* request,
+ const blink::WebServiceWorkerCache::QueryParams& query_params) {
+ int request_id = cache_keys_callbacks_.Add(callbacks);
+ cache_keys_times_[request_id] = base::TimeTicks::Now();
+
+ Send(new CacheStorageHostMsg_CacheKeys(
+ CurrentWorkerId(), request_id, cache_id,
+ request ? FetchRequestFromWebRequest(*request)
+ : ServiceWorkerFetchRequest(),
+ QueryParamsFromWebQueryParams(query_params)));
+}
+
+void CacheStorageDispatcher::dispatchBatchForCache(
+ int cache_id,
+ blink::WebServiceWorkerCache::CacheBatchCallbacks* callbacks,
+ const blink::WebVector<blink::WebServiceWorkerCache::BatchOperation>&
+ web_operations) {
+ int request_id = cache_batch_callbacks_.Add(callbacks);
+ cache_batch_times_[request_id] = base::TimeTicks::Now();
+
+ std::vector<CacheStorageBatchOperation> operations;
+ operations.reserve(web_operations.size());
+ for (size_t i = 0; i < web_operations.size(); ++i) {
+ operations.push_back(
+ BatchOperationFromWebBatchOperation(web_operations[i]));
+ }
+
+ Send(new CacheStorageHostMsg_CacheBatch(CurrentWorkerId(), request_id,
+ cache_id, operations));
+}
+
+void CacheStorageDispatcher::OnWebCacheDestruction(int cache_id) {
+ web_caches_.Remove(cache_id);
+ Send(new CacheStorageHostMsg_CacheClosed(cache_id));
+}
+
+void CacheStorageDispatcher::PopulateWebResponseFromResponse(
+ const ServiceWorkerResponse& response,
+ blink::WebServiceWorkerResponse* web_response) {
+ web_response->setURL(response.url);
+ web_response->setStatus(response.status_code);
+ web_response->setStatusText(base::ASCIIToUTF16(response.status_text));
+ web_response->setResponseType(response.response_type);
+
+ for (const auto& i : response.headers) {
+ web_response->setHeader(base::ASCIIToUTF16(i.first),
+ base::ASCIIToUTF16(i.second));
+ }
+
+ if (!response.blob_uuid.empty()) {
+ web_response->setBlob(blink::WebString::fromUTF8(response.blob_uuid),
+ response.blob_size);
+ // Let the host know that it can release its reference to the blob.
+ Send(new CacheStorageHostMsg_BlobDataHandled(response.blob_uuid));
+ }
+}
+
+blink::WebVector<blink::WebServiceWorkerResponse>
+CacheStorageDispatcher::WebResponsesFromResponses(
+ const std::vector<ServiceWorkerResponse>& responses) {
+ blink::WebVector<blink::WebServiceWorkerResponse> web_responses(
+ responses.size());
+ for (size_t i = 0; i < responses.size(); ++i)
+ PopulateWebResponseFromResponse(responses[i], &(web_responses[i]));
+ return web_responses;
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/cache_storage/cache_storage_dispatcher.h b/chromium/content/renderer/cache_storage/cache_storage_dispatcher.h
new file mode 100644
index 00000000000..de46d58ebe3
--- /dev/null
+++ b/chromium/content/renderer/cache_storage/cache_storage_dispatcher.h
@@ -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.
+
+#ifndef CONTENT_RENDERER_CACHE_STORAGE_CACHE_STORAGE_DISPATCHER_H_
+#define CONTENT_RENDERER_CACHE_STORAGE_CACHE_STORAGE_DISPATCHER_H_
+
+#include <vector>
+
+#include "base/id_map.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/strings/string16.h"
+#include "base/time/time.h"
+#include "content/child/worker_task_runner.h"
+#include "content/public/renderer/render_process_observer.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerCache.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerCacheError.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerCacheStorage.h"
+
+namespace content {
+
+class ThreadSafeSender;
+struct ServiceWorkerFetchRequest;
+struct ServiceWorkerResponse;
+
+// Handle the Cache Storage messaging for this context thread. The
+// main thread and each worker thread have their own instances.
+class CacheStorageDispatcher : public WorkerTaskRunner::Observer {
+ public:
+ explicit CacheStorageDispatcher(ThreadSafeSender* thread_safe_sender);
+ ~CacheStorageDispatcher() override;
+
+ // |thread_safe_sender| needs to be passed in because if the call leads to
+ // construction it will be needed.
+ static CacheStorageDispatcher* ThreadSpecificInstance(
+ ThreadSafeSender* thread_safe_sender);
+
+ // WorkerTaskRunner::Observer implementation.
+ void OnWorkerRunLoopStopped() override;
+
+ bool Send(IPC::Message* msg);
+
+ // ServiceWorkerScriptContext calls our OnMessageReceived directly.
+ bool OnMessageReceived(const IPC::Message& message);
+
+ // Message handlers for CacheStorage messages from the browser process.
+ void OnCacheStorageHasSuccess(int thread_id, int request_id);
+ void OnCacheStorageOpenSuccess(int thread_id, int request_id, int cache_id);
+ void OnCacheStorageDeleteSuccess(int thread_id, int request_id);
+ void OnCacheStorageKeysSuccess(int thread_id,
+ int request_id,
+ const std::vector<base::string16>& keys);
+ void OnCacheStorageMatchSuccess(int thread_id,
+ int request_id,
+ const ServiceWorkerResponse& response);
+
+ void OnCacheStorageHasError(int thread_id,
+ int request_id,
+ blink::WebServiceWorkerCacheError reason);
+ void OnCacheStorageOpenError(int thread_id,
+ int request_id,
+ blink::WebServiceWorkerCacheError reason);
+ void OnCacheStorageDeleteError(int thread_id,
+ int request_id,
+ blink::WebServiceWorkerCacheError reason);
+ void OnCacheStorageKeysError(int thread_id,
+ int request_id,
+ blink::WebServiceWorkerCacheError reason);
+ void OnCacheStorageMatchError(int thread_id,
+ int request_id,
+ blink::WebServiceWorkerCacheError reason);
+
+ // Message handlers for Cache messages from the browser process.
+ void OnCacheMatchSuccess(int thread_id,
+ int request_id,
+ const ServiceWorkerResponse& response);
+ void OnCacheMatchAllSuccess(
+ int thread_id,
+ int request_id,
+ const std::vector<ServiceWorkerResponse>& response);
+ void OnCacheKeysSuccess(
+ int thread_id,
+ int request_id,
+ const std::vector<ServiceWorkerFetchRequest>& response);
+ void OnCacheBatchSuccess(int thread_id,
+ int request_id);
+
+ void OnCacheMatchError(int thread_id,
+ int request_id,
+ blink::WebServiceWorkerCacheError reason);
+ void OnCacheMatchAllError(int thread_id,
+ int request_id,
+ blink::WebServiceWorkerCacheError reason);
+ void OnCacheKeysError(int thread_id,
+ int request_id,
+ blink::WebServiceWorkerCacheError reason);
+ void OnCacheBatchError(int thread_id,
+ int request_id,
+ blink::WebServiceWorkerCacheError reason);
+
+ // TODO(jsbell): These are only called by WebServiceWorkerCacheStorageImpl
+ // and should be renamed to match Chromium conventions. crbug.com/439389
+ void dispatchHas(
+ blink::WebServiceWorkerCacheStorage::CacheStorageCallbacks* callbacks,
+ const GURL& origin,
+ const blink::WebString& cacheName);
+ void dispatchOpen(
+ blink::WebServiceWorkerCacheStorage::CacheStorageWithCacheCallbacks*
+ callbacks,
+ const GURL& origin,
+ const blink::WebString& cacheName);
+ void dispatchDelete(
+ blink::WebServiceWorkerCacheStorage::CacheStorageCallbacks* callbacks,
+ const GURL& origin,
+ const blink::WebString& cacheName);
+ void dispatchKeys(
+ blink::WebServiceWorkerCacheStorage::CacheStorageKeysCallbacks* callbacks,
+ const GURL& origin);
+ void dispatchMatch(
+ blink::WebServiceWorkerCacheStorage::CacheStorageMatchCallbacks*
+ callbacks,
+ const GURL& origin,
+ const blink::WebServiceWorkerRequest& request,
+ const blink::WebServiceWorkerCache::QueryParams& query_params);
+
+ // These methods are used by WebCache to forward events to the browser
+ // process.
+ void dispatchMatchForCache(
+ int cache_id,
+ blink::WebServiceWorkerCache::CacheMatchCallbacks* callbacks,
+ const blink::WebServiceWorkerRequest& request,
+ const blink::WebServiceWorkerCache::QueryParams& query_params);
+ void dispatchMatchAllForCache(
+ int cache_id,
+ blink::WebServiceWorkerCache::CacheWithResponsesCallbacks* callbacks,
+ const blink::WebServiceWorkerRequest& request,
+ const blink::WebServiceWorkerCache::QueryParams& query_params);
+ void dispatchKeysForCache(
+ int cache_id,
+ blink::WebServiceWorkerCache::CacheWithRequestsCallbacks* callbacks,
+ const blink::WebServiceWorkerRequest* request,
+ const blink::WebServiceWorkerCache::QueryParams& query_params);
+ void dispatchBatchForCache(
+ int cache_id,
+ blink::WebServiceWorkerCache::CacheBatchCallbacks* callbacks,
+ const blink::WebVector<blink::WebServiceWorkerCache::BatchOperation>&
+ batch_operations);
+
+ void OnWebCacheDestruction(int cache_id);
+
+ private:
+ class WebCache;
+
+ typedef IDMap<blink::WebServiceWorkerCacheStorage::CacheStorageCallbacks,
+ IDMapOwnPointer> CallbacksMap;
+ typedef IDMap<
+ blink::WebServiceWorkerCacheStorage::CacheStorageWithCacheCallbacks,
+ IDMapOwnPointer> WithCacheCallbacksMap;
+ typedef IDMap<blink::WebServiceWorkerCacheStorage::CacheStorageKeysCallbacks,
+ IDMapOwnPointer> KeysCallbacksMap;
+ typedef IDMap<blink::WebServiceWorkerCacheStorage::CacheStorageMatchCallbacks,
+ IDMapOwnPointer> StorageMatchCallbacksMap;
+
+ typedef base::hash_map<int32, base::TimeTicks> TimeMap;
+
+ typedef IDMap<blink::WebServiceWorkerCache::CacheMatchCallbacks,
+ IDMapOwnPointer> MatchCallbacksMap;
+ typedef IDMap<blink::WebServiceWorkerCache::CacheWithResponsesCallbacks,
+ IDMapOwnPointer> WithResponsesCallbacksMap;
+ typedef IDMap<blink::WebServiceWorkerCache::CacheWithRequestsCallbacks,
+ IDMapOwnPointer> WithRequestsCallbacksMap;
+ using BatchCallbacksMap =
+ IDMap<blink::WebServiceWorkerCache::CacheBatchCallbacks, IDMapOwnPointer>;
+
+ static int32 CurrentWorkerId() {
+ return WorkerTaskRunner::Instance()->CurrentWorkerId();
+ }
+
+ void PopulateWebResponseFromResponse(
+ const ServiceWorkerResponse& response,
+ blink::WebServiceWorkerResponse* web_response);
+
+ blink::WebVector<blink::WebServiceWorkerResponse> WebResponsesFromResponses(
+ const std::vector<ServiceWorkerResponse>& responses);
+
+ scoped_refptr<ThreadSafeSender> thread_safe_sender_;
+
+ CallbacksMap has_callbacks_;
+ WithCacheCallbacksMap open_callbacks_;
+ CallbacksMap delete_callbacks_;
+ KeysCallbacksMap keys_callbacks_;
+ StorageMatchCallbacksMap match_callbacks_;
+
+ TimeMap has_times_;
+ TimeMap open_times_;
+ TimeMap delete_times_;
+ TimeMap keys_times_;
+ TimeMap match_times_;
+
+ // The individual caches created under this CacheStorage object.
+ IDMap<WebCache, IDMapExternalPointer> web_caches_;
+
+ // These ID maps are held in the CacheStorage object rather than the Cache
+ // object to ensure that the IDs are unique.
+ MatchCallbacksMap cache_match_callbacks_;
+ WithResponsesCallbacksMap cache_match_all_callbacks_;
+ WithRequestsCallbacksMap cache_keys_callbacks_;
+ BatchCallbacksMap cache_batch_callbacks_;
+
+ TimeMap cache_match_times_;
+ TimeMap cache_match_all_times_;
+ TimeMap cache_keys_times_;
+ TimeMap cache_batch_times_;
+
+ base::WeakPtrFactory<CacheStorageDispatcher> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(CacheStorageDispatcher);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_CACHE_STORAGE_CACHE_STORAGE_DISPATCHER_H_
diff --git a/chromium/content/renderer/cache_storage/cache_storage_message_filter.cc b/chromium/content/renderer/cache_storage/cache_storage_message_filter.cc
new file mode 100644
index 00000000000..e4d4835c663
--- /dev/null
+++ b/chromium/content/renderer/cache_storage/cache_storage_message_filter.cc
@@ -0,0 +1,38 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/cache_storage/cache_storage_message_filter.h"
+
+#include "content/child/thread_safe_sender.h"
+#include "content/common/cache_storage/cache_storage_messages.h"
+#include "content/renderer/cache_storage/cache_storage_dispatcher.h"
+
+namespace content {
+
+CacheStorageMessageFilter::CacheStorageMessageFilter(
+ ThreadSafeSender* thread_safe_sender)
+ : WorkerThreadMessageFilter(thread_safe_sender) {
+}
+
+CacheStorageMessageFilter::~CacheStorageMessageFilter() {
+}
+
+bool CacheStorageMessageFilter::ShouldHandleMessage(
+ const IPC::Message& msg) const {
+ return IPC_MESSAGE_CLASS(msg) == CacheStorageMsgStart;
+}
+
+void CacheStorageMessageFilter::OnFilteredMessageReceived(
+ const IPC::Message& msg) {
+ CacheStorageDispatcher::ThreadSpecificInstance(thread_safe_sender())
+ ->OnMessageReceived(msg);
+}
+
+bool CacheStorageMessageFilter::GetWorkerThreadIdForMessage(
+ const IPC::Message& msg,
+ int* ipc_thread_id) {
+ return PickleIterator(msg).ReadInt(ipc_thread_id);
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/cache_storage/cache_storage_message_filter.h b/chromium/content/renderer/cache_storage/cache_storage_message_filter.h
new file mode 100644
index 00000000000..5d92d696b31
--- /dev/null
+++ b/chromium/content/renderer/cache_storage/cache_storage_message_filter.h
@@ -0,0 +1,32 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_SERVICE_WORKER_CACHE_STORAGE_MESSAGE_FILTER_H_
+#define CONTENT_RENDERER_SERVICE_WORKER_CACHE_STORAGE_MESSAGE_FILTER_H_
+
+#include "base/memory/ref_counted.h"
+#include "content/child/worker_thread_message_filter.h"
+
+namespace content {
+
+class CacheStorageMessageFilter : public WorkerThreadMessageFilter {
+ public:
+ explicit CacheStorageMessageFilter(ThreadSafeSender* thread_safe_sender);
+
+ protected:
+ ~CacheStorageMessageFilter() override;
+
+ private:
+ // WorkerThreadMessageFilter:
+ bool ShouldHandleMessage(const IPC::Message& msg) const override;
+ void OnFilteredMessageReceived(const IPC::Message& msg) override;
+ bool GetWorkerThreadIdForMessage(const IPC::Message& msg,
+ int* ipc_thread_id) override;
+
+ DISALLOW_COPY_AND_ASSIGN(CacheStorageMessageFilter);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_SERVICE_WORKER_CACHE_STORAGE_MESSAGE_FILTER_H_
diff --git a/chromium/content/renderer/cache_storage/webserviceworkercachestorage_impl.cc b/chromium/content/renderer/cache_storage/webserviceworkercachestorage_impl.cc
new file mode 100644
index 00000000000..e8c2a05c4ea
--- /dev/null
+++ b/chromium/content/renderer/cache_storage/webserviceworkercachestorage_impl.cc
@@ -0,0 +1,63 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/cache_storage/webserviceworkercachestorage_impl.h"
+
+#include "content/child/thread_safe_sender.h"
+#include "content/renderer/cache_storage/cache_storage_dispatcher.h"
+#include "third_party/WebKit/public/platform/WebHTTPHeaderVisitor.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerCache.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerRequest.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerResponse.h"
+
+using base::TimeTicks;
+
+namespace content {
+
+WebServiceWorkerCacheStorageImpl::WebServiceWorkerCacheStorageImpl(
+ ThreadSafeSender* thread_safe_sender,
+ const GURL& origin)
+ : thread_safe_sender_(thread_safe_sender), origin_(origin) {
+}
+
+WebServiceWorkerCacheStorageImpl::~WebServiceWorkerCacheStorageImpl() {
+}
+
+void WebServiceWorkerCacheStorageImpl::dispatchHas(
+ CacheStorageCallbacks* callbacks,
+ const blink::WebString& cacheName) {
+ GetDispatcher()->dispatchHas(callbacks, origin_, cacheName);
+}
+
+void WebServiceWorkerCacheStorageImpl::dispatchOpen(
+ CacheStorageWithCacheCallbacks* callbacks,
+ const blink::WebString& cacheName) {
+ GetDispatcher()->dispatchOpen(callbacks, origin_, cacheName);
+}
+
+void WebServiceWorkerCacheStorageImpl::dispatchDelete(
+ CacheStorageCallbacks* callbacks,
+ const blink::WebString& cacheName) {
+ GetDispatcher()->dispatchDelete(callbacks, origin_, cacheName);
+}
+
+void WebServiceWorkerCacheStorageImpl::dispatchKeys(
+ CacheStorageKeysCallbacks* callbacks) {
+ GetDispatcher()->dispatchKeys(callbacks, origin_);
+}
+
+void WebServiceWorkerCacheStorageImpl::dispatchMatch(
+ CacheStorageMatchCallbacks* callbacks,
+ const blink::WebServiceWorkerRequest& request,
+ const blink::WebServiceWorkerCache::QueryParams& query_params) {
+ GetDispatcher()->dispatchMatch(callbacks, origin_, request, query_params);
+}
+
+CacheStorageDispatcher* WebServiceWorkerCacheStorageImpl::GetDispatcher()
+ const {
+ return CacheStorageDispatcher::ThreadSpecificInstance(
+ thread_safe_sender_.get());
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/cache_storage/webserviceworkercachestorage_impl.h b/chromium/content/renderer/cache_storage/webserviceworkercachestorage_impl.h
new file mode 100644
index 00000000000..0665936c8ad
--- /dev/null
+++ b/chromium/content/renderer/cache_storage/webserviceworkercachestorage_impl.h
@@ -0,0 +1,58 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_SERVICE_WORKER_WEB_SERVICE_WORKER_CACHE_STORAGE_IMPL_H_
+#define CONTENT_RENDERER_SERVICE_WORKER_WEB_SERVICE_WORKER_CACHE_STORAGE_IMPL_H_
+
+#include "content/child/thread_safe_sender.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerCache.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerCacheError.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerCacheStorage.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+
+namespace content {
+
+class CacheStorageDispatcher;
+class ThreadSafeSender;
+
+// This corresponds to an instance of the script-facing CacheStorage object.
+// One exists per script execution context (window, worker) and has an origin
+// which provides a namespace for the caches. Script calls to the CacheStorage
+// object are routed through here to the (per-thread) dispatcher then on to
+// the browser, with the origin added to the call parameters. Cache instances
+// returned by open() calls are minted by and implemented within the code of
+// the CacheStorageDispatcher, and include routing information.
+class WebServiceWorkerCacheStorageImpl
+ : public blink::WebServiceWorkerCacheStorage {
+ public:
+ WebServiceWorkerCacheStorageImpl(ThreadSafeSender* thread_safe_sender,
+ const GURL& origin);
+ ~WebServiceWorkerCacheStorageImpl();
+
+ // From WebServiceWorkerCacheStorage:
+ virtual void dispatchHas(CacheStorageCallbacks* callbacks,
+ const blink::WebString& cacheName);
+ virtual void dispatchOpen(CacheStorageWithCacheCallbacks* callbacks,
+ const blink::WebString& cacheName);
+ virtual void dispatchDelete(CacheStorageCallbacks* callbacks,
+ const blink::WebString& cacheName);
+ virtual void dispatchKeys(CacheStorageKeysCallbacks* callbacks);
+ virtual void dispatchMatch(
+ CacheStorageMatchCallbacks* callbacks,
+ const blink::WebServiceWorkerRequest& request,
+ const blink::WebServiceWorkerCache::QueryParams& query_params);
+
+ private:
+ // Helper to return the thread-specific dispatcher.
+ CacheStorageDispatcher* GetDispatcher() const;
+
+ scoped_refptr<ThreadSafeSender> thread_safe_sender_;
+ const GURL origin_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebServiceWorkerCacheStorageImpl);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_SERVICE_WORKER_WEB_SERVICE_WORKER_CACHE_STORAGE_IMPL_H_
diff --git a/chromium/content/renderer/child_frame_compositing_helper.cc b/chromium/content/renderer/child_frame_compositing_helper.cc
index 841cfadf704..4ac2315b6fa 100644
--- a/chromium/content/renderer/child_frame_compositing_helper.cc
+++ b/chromium/content/renderer/child_frame_compositing_helper.cc
@@ -25,7 +25,7 @@
#include "third_party/WebKit/public/web/WebFrame.h"
#include "third_party/WebKit/public/web/WebPluginContainer.h"
#include "third_party/khronos/GLES2/gl2.h"
-#include "ui/gfx/size_conversions.h"
+#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/skia_util.h"
namespace content {
@@ -34,7 +34,7 @@ ChildFrameCompositingHelper*
ChildFrameCompositingHelper::CreateForBrowserPlugin(
const base::WeakPtr<BrowserPlugin>& browser_plugin) {
return new ChildFrameCompositingHelper(
- browser_plugin, NULL, NULL, browser_plugin->render_view_routing_id());
+ browser_plugin, NULL, NULL, browser_plugin->render_frame_routing_id());
}
ChildFrameCompositingHelper*
@@ -61,13 +61,16 @@ ChildFrameCompositingHelper::ChildFrameCompositingHelper(
render_frame_proxy_(render_frame_proxy),
frame_(frame) {}
-ChildFrameCompositingHelper::~ChildFrameCompositingHelper() {}
+ChildFrameCompositingHelper::~ChildFrameCompositingHelper() {
+ if (resource_collection_.get())
+ resource_collection_->SetClient(NULL);
+}
BrowserPluginManager* ChildFrameCompositingHelper::GetBrowserPluginManager() {
if (!browser_plugin_)
return NULL;
- return browser_plugin_->browser_plugin_manager();
+ return BrowserPluginManager::Get();
}
blink::WebPluginContainer* ChildFrameCompositingHelper::GetContainer() {
@@ -91,7 +94,7 @@ void ChildFrameCompositingHelper::SendCompositorFrameSwappedACKToBrowser(
if (GetBrowserPluginManager()) {
GetBrowserPluginManager()->Send(
new BrowserPluginHostMsg_CompositorFrameSwappedACK(
- host_routing_id_, GetInstanceID(), params));
+ GetInstanceID(), params));
} else if (render_frame_proxy_) {
render_frame_proxy_->Send(
new FrameHostMsg_CompositorFrameSwappedACK(host_routing_id_, params));
@@ -105,7 +108,7 @@ void ChildFrameCompositingHelper::SendReclaimCompositorResourcesToBrowser(
if (GetBrowserPluginManager()) {
GetBrowserPluginManager()->Send(
new BrowserPluginHostMsg_ReclaimCompositorResources(
- host_routing_id_, GetInstanceID(), params));
+ GetInstanceID(), params));
} else if (render_frame_proxy_) {
render_frame_proxy_->Send(
new FrameHostMsg_ReclaimCompositorResources(host_routing_id_, params));
@@ -164,6 +167,10 @@ void ChildFrameCompositingHelper::CheckSizeAndAdjustLayerProperties(
}
void ChildFrameCompositingHelper::OnContainerDestroy() {
+ // If we have a pending ACK, then ACK now so we don't lose frames in the
+ // future.
+ DidCommitCompositorFrame();
+
if (GetContainer())
GetContainer()->setWebLayer(NULL);
diff --git a/chromium/content/renderer/child_frame_compositing_helper.h b/chromium/content/renderer/child_frame_compositing_helper.h
index b6c4d57f2de..0700d9cc24f 100644
--- a/chromium/content/renderer/child_frame_compositing_helper.h
+++ b/chromium/content/renderer/child_frame_compositing_helper.h
@@ -13,7 +13,7 @@
#include "base/memory/shared_memory.h"
#include "cc/layers/delegated_frame_resource_collection.h"
#include "content/common/content_export.h"
-#include "ui/gfx/size.h"
+#include "ui/gfx/geometry/size.h"
namespace base {
class SharedMemory;
diff --git a/chromium/content/renderer/chrome_object_extensions_utils.cc b/chromium/content/renderer/chrome_object_extensions_utils.cc
index b9c3cdebba2..d023d29e51d 100644
--- a/chromium/content/renderer/chrome_object_extensions_utils.cc
+++ b/chromium/content/renderer/chrome_object_extensions_utils.cc
@@ -9,16 +9,16 @@
namespace content {
-v8::Handle<v8::Object> GetOrCreateChromeObject(
- v8::Isolate* isolate, v8::Handle<v8::Object> global) {
- v8::Handle<v8::Object> chrome;
- v8::Handle<v8::Value> chrome_value =
+v8::Local<v8::Object> GetOrCreateChromeObject(
+ v8::Isolate* isolate, v8::Local<v8::Object> global) {
+ v8::Local<v8::Object> chrome;
+ v8::Local<v8::Value> chrome_value =
global->Get(gin::StringToV8(isolate, "chrome"));
if (chrome_value.IsEmpty() || !chrome_value->IsObject()) {
chrome = v8::Object::New(isolate);
global->Set(gin::StringToSymbol(isolate, "chrome"), chrome);
} else {
- chrome = chrome_value->ToObject();
+ chrome = v8::Local<v8::Object>::Cast(chrome_value);
}
return chrome;
}
diff --git a/chromium/content/renderer/chrome_object_extensions_utils.h b/chromium/content/renderer/chrome_object_extensions_utils.h
index 1048616d79c..b21c6575d7a 100644
--- a/chromium/content/renderer/chrome_object_extensions_utils.h
+++ b/chromium/content/renderer/chrome_object_extensions_utils.h
@@ -9,8 +9,8 @@
namespace content {
-v8::Handle<v8::Object> GetOrCreateChromeObject(
- v8::Isolate* isolate, v8::Handle<v8::Object> global);
+v8::Local<v8::Object> GetOrCreateChromeObject(
+ v8::Isolate* isolate, v8::Local<v8::Object> global);
} // namespace content
diff --git a/chromium/content/renderer/clipboard_client.h b/chromium/content/renderer/clipboard_client.h
deleted file mode 100644
index 7f1b2dcfdff..00000000000
--- a/chromium/content/renderer/clipboard_client.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_RENDERER_CLIPBOARD_CLIENT_H_
-#define CONTENT_RENDERER_CLIPBOARD_CLIENT_H_
-
-#include "content/common/clipboard_format.h"
-#include "ui/base/clipboard/clipboard.h"
-
-class GURL;
-
-namespace content {
-
-// Interface for the content embedder to implement to support clipboard.
-class ClipboardClient {
- public:
- class WriteContext {
- public:
- virtual ~WriteContext() { }
-
- // Writes bitmap data into the context, updating the ObjectMap.
- virtual void WriteBitmapFromPixels(ui::Clipboard::ObjectMap* objects,
- const void* pixels,
- const gfx::Size& size) = 0;
-
- // Flushes all gathered data.
- virtual void Flush(const ui::Clipboard::ObjectMap& objects) = 0;
- };
-
- virtual ~ClipboardClient() { }
-
- // Get a clipboard that can be used to construct a ScopedClipboardWriterGlue.
- virtual ui::Clipboard* GetClipboard() = 0;
-
- // Get a sequence number which uniquely identifies clipboard state.
- virtual uint64 GetSequenceNumber(ui::ClipboardType type) = 0;
-
- // Tests whether the clipboard contains a certain format
- virtual bool IsFormatAvailable(ClipboardFormat format,
- ui::ClipboardType type) = 0;
-
- // Clear the contents of the clipboard.
- virtual void Clear(ui::ClipboardType type) = 0;
-
- // Reads the available types from the clipboard, if available.
- virtual void ReadAvailableTypes(ui::ClipboardType type,
- std::vector<base::string16>* types,
- bool* contains_filenames) = 0;
-
- // Reads text from the clipboard, trying UNICODE first, then falling back to
- // ASCII.
- virtual void ReadText(ui::ClipboardType type,
- base::string16* result) = 0;
-
- // Reads HTML from the clipboard, if available.
- virtual void ReadHTML(ui::ClipboardType type,
- base::string16* markup,
- GURL* url,
- uint32* fragment_start,
- uint32* fragment_end) = 0;
-
- // Reads RTF from the clipboard, if available.
- virtual void ReadRTF(ui::ClipboardType type, std::string* result) = 0;
-
- // Reads and image from the clipboard, if available.
- virtual void ReadImage(ui::ClipboardType type, std::string* data) = 0;
-
- // Reads a custom data type from the clipboard, if available.
- virtual void ReadCustomData(ui::ClipboardType clipboard_type,
- const base::string16& type,
- base::string16* data) = 0;
-
- // Creates a context to write clipboard data. May return NULL.
- virtual WriteContext* CreateWriteContext() = 0;
-};
-
-} // namespace content
-
-#endif // CONTENT_RENDERER_CLIPBOARD_CLIENT_H_
-
diff --git a/chromium/content/renderer/clipboard_utils.h b/chromium/content/renderer/clipboard_utils.h
index 3acf7b43ebb..866511d5252 100644
--- a/chromium/content/renderer/clipboard_utils.h
+++ b/chromium/content/renderer/clipboard_utils.h
@@ -24,4 +24,4 @@ CONTENT_EXPORT std::string URLToImageMarkup(const blink::WebURL& url,
} // namespace content
-#endif // CONTENT_RENDERER_CLIPBOARD_UTILS_H_
+#endif // CONTENT_RENDERER_CLIPBOARD_UTILS_H_
diff --git a/chromium/content/renderer/context_menu_params_builder.cc b/chromium/content/renderer/context_menu_params_builder.cc
index 63dcd4d1e7b..d81fa13d17c 100644
--- a/chromium/content/renderer/context_menu_params_builder.cc
+++ b/chromium/content/renderer/context_menu_params_builder.cc
@@ -59,7 +59,7 @@ ContextMenuParams ContextMenuParamsBuilder::Build(
blink::WebNode selectedNode = DomUtils::ExtractParentAnchorNode(data.node);
blink::WebElement selectedElement = selectedNode.to<blink::WebElement>();
if (!selectedElement.isNull() && selectedNode.isLink()) {
- params.link_text = selectedElement.innerText();
+ params.link_text = selectedElement.textContent();
} else {
LOG(ERROR) << "Creating a ContextMenuParams for a node that has a link"
<< "url but is not an ElementNode or does not have an"
diff --git a/chromium/content/renderer/device_sensors/device_light_event_pump_unittest.cc b/chromium/content/renderer/device_sensors/device_light_event_pump_unittest.cc
index dadc4e3dc67..4f19f0db158 100644
--- a/chromium/content/renderer/device_sensors/device_light_event_pump_unittest.cc
+++ b/chromium/content/renderer/device_sensors/device_light_event_pump_unittest.cc
@@ -67,7 +67,7 @@ class DeviceLightEventPumpTest : public testing::Test {
protected:
void SetUp() override {
- const DeviceLightHardwareBuffer* null_buffer = NULL;
+ const DeviceLightHardwareBuffer* null_buffer = nullptr;
listener_.reset(new MockDeviceLightListener);
light_pump_.reset(new DeviceLightEventPumpForTesting);
buffer_ = static_cast<DeviceLightHardwareBuffer*>(shared_memory_.memory());
diff --git a/chromium/content/renderer/device_sensors/device_motion_event_pump.cc b/chromium/content/renderer/device_sensors/device_motion_event_pump.cc
index aca6df5c005..860cf68e2f1 100644
--- a/chromium/content/renderer/device_sensors/device_motion_event_pump.cc
+++ b/chromium/content/renderer/device_sensors/device_motion_event_pump.cc
@@ -6,7 +6,7 @@
#include "content/common/device_sensors/device_motion_messages.h"
#include "content/public/renderer/render_thread.h"
-#include "third_party/WebKit/public/platform/WebDeviceMotionListener.h"
+#include "third_party/WebKit/public/platform/modules/device_orientation/WebDeviceMotionListener.h"
namespace content {
diff --git a/chromium/content/renderer/device_sensors/device_motion_event_pump.h b/chromium/content/renderer/device_sensors/device_motion_event_pump.h
index af24caa6440..61b046d2f6d 100644
--- a/chromium/content/renderer/device_sensors/device_motion_event_pump.h
+++ b/chromium/content/renderer/device_sensors/device_motion_event_pump.h
@@ -8,7 +8,7 @@
#include "base/memory/scoped_ptr.h"
#include "content/renderer/device_sensors/device_sensor_event_pump.h"
#include "content/renderer/shared_memory_seqlock_reader.h"
-#include "third_party/WebKit/public/platform/WebDeviceMotionData.h"
+#include "third_party/WebKit/public/platform/modules/device_orientation/WebDeviceMotionData.h"
namespace blink {
class WebDeviceMotionListener;
diff --git a/chromium/content/renderer/device_sensors/device_motion_event_pump_unittest.cc b/chromium/content/renderer/device_sensors/device_motion_event_pump_unittest.cc
index 13b204f5947..95b0fea70ce 100644
--- a/chromium/content/renderer/device_sensors/device_motion_event_pump_unittest.cc
+++ b/chromium/content/renderer/device_sensors/device_motion_event_pump_unittest.cc
@@ -10,13 +10,14 @@
#include "content/common/device_sensors/device_motion_hardware_buffer.h"
#include "content/public/test/test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/public/platform/WebDeviceMotionListener.h"
+#include "third_party/WebKit/public/platform/modules/device_orientation/WebDeviceMotionListener.h"
namespace content {
class MockDeviceMotionListener : public blink::WebDeviceMotionListener {
public:
- MockDeviceMotionListener() : did_change_device_motion_(false) {
+ MockDeviceMotionListener()
+ : did_change_device_motion_(false), number_of_events_(0) {
memset(&data_, 0, sizeof(data_));
}
virtual ~MockDeviceMotionListener() { }
@@ -25,17 +26,22 @@ class MockDeviceMotionListener : public blink::WebDeviceMotionListener {
const blink::WebDeviceMotionData& data) override {
memcpy(&data_, &data, sizeof(data));
did_change_device_motion_ = true;
+ ++number_of_events_;
}
bool did_change_device_motion() const {
return did_change_device_motion_;
}
+
+ int number_of_events() const { return number_of_events_; }
+
const blink::WebDeviceMotionData& data() const {
return data_;
}
private:
bool did_change_device_motion_;
+ int number_of_events_;
blink::WebDeviceMotionData data_;
DISALLOW_COPY_AND_ASSIGN(MockDeviceMotionListener);
@@ -44,9 +50,17 @@ class MockDeviceMotionListener : public blink::WebDeviceMotionListener {
class DeviceMotionEventPumpForTesting : public DeviceMotionEventPump {
public:
DeviceMotionEventPumpForTesting()
- : DeviceMotionEventPump(0) { }
+ : DeviceMotionEventPump(0), stop_on_fire_event_(true) {}
~DeviceMotionEventPumpForTesting() override {}
+ void set_stop_on_fire_event(bool stop_on_fire_event) {
+ stop_on_fire_event_ = stop_on_fire_event;
+ }
+
+ bool stop_on_fire_event() { return stop_on_fire_event_; }
+
+ int pump_delay_microseconds() const { return pump_delay_microseconds_; }
+
void OnDidStart(base::SharedMemoryHandle renderer_handle) {
DeviceMotionEventPump::OnDidStart(renderer_handle);
}
@@ -54,11 +68,15 @@ class DeviceMotionEventPumpForTesting : public DeviceMotionEventPump {
void SendStopMessage() override {}
void FireEvent() override {
DeviceMotionEventPump::FireEvent();
- Stop();
- base::MessageLoop::current()->QuitWhenIdle();
+ if (stop_on_fire_event_) {
+ Stop();
+ base::MessageLoop::current()->QuitWhenIdle();
+ }
}
private:
+ bool stop_on_fire_event_;
+
DISALLOW_COPY_AND_ASSIGN(DeviceMotionEventPumpForTesting);
};
@@ -71,7 +89,7 @@ class DeviceMotionEventPumpTest : public testing::Test {
protected:
void SetUp() override {
- const DeviceMotionHardwareBuffer* null_buffer = NULL;
+ const DeviceMotionHardwareBuffer* null_buffer = nullptr;
listener_.reset(new MockDeviceMotionListener);
motion_pump_.reset(new DeviceMotionEventPumpForTesting);
buffer_ = static_cast<DeviceMotionHardwareBuffer*>(shared_memory_.memory());
@@ -158,4 +176,31 @@ TEST_F(DeviceMotionEventPumpTest, DidStartPollingNotAllSensorsActive) {
EXPECT_FALSE(received_data.hasRotationRateGamma);
}
+// Confirm that the frequency of pumping events is not greater than 60Hz. A rate
+// above 60Hz would allow for the detection of keystrokes (crbug.com/421691)
+TEST_F(DeviceMotionEventPumpTest, PumpThrottlesEventRate) {
+ // Confirm that the delay for pumping events is 60 Hz.
+ EXPECT_GE(60, base::Time::kMicrosecondsPerSecond /
+ motion_pump()->pump_delay_microseconds());
+
+ base::MessageLoopForUI loop;
+
+ InitBuffer(true);
+
+ motion_pump()->set_stop_on_fire_event(false);
+ motion_pump()->Start(listener());
+ motion_pump()->OnDidStart(handle());
+
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE, base::MessageLoop::QuitClosure(),
+ base::TimeDelta::FromMilliseconds(100));
+ base::MessageLoop::current()->Run();
+ motion_pump()->Stop();
+
+ // Check that the blink::WebDeviceMotionListener does not receive excess
+ // events.
+ EXPECT_TRUE(listener()->did_change_device_motion());
+ EXPECT_GE(6, listener()->number_of_events());
+}
+
} // namespace content
diff --git a/chromium/content/renderer/device_sensors/device_orientation_event_pump.cc b/chromium/content/renderer/device_sensors/device_orientation_event_pump.cc
index deea13632f8..093841b069f 100644
--- a/chromium/content/renderer/device_sensors/device_orientation_event_pump.cc
+++ b/chromium/content/renderer/device_sensors/device_orientation_event_pump.cc
@@ -8,7 +8,7 @@
#include "content/common/device_sensors/device_orientation_messages.h"
#include "content/public/renderer/render_thread.h"
-#include "third_party/WebKit/public/platform/WebDeviceOrientationListener.h"
+#include "third_party/WebKit/public/platform/modules/device_orientation/WebDeviceOrientationListener.h"
namespace content {
diff --git a/chromium/content/renderer/device_sensors/device_orientation_event_pump.h b/chromium/content/renderer/device_sensors/device_orientation_event_pump.h
index d9564e17cd0..8f0ce5ef55d 100644
--- a/chromium/content/renderer/device_sensors/device_orientation_event_pump.h
+++ b/chromium/content/renderer/device_sensors/device_orientation_event_pump.h
@@ -8,7 +8,7 @@
#include "base/memory/scoped_ptr.h"
#include "content/renderer/device_sensors/device_sensor_event_pump.h"
#include "content/renderer/shared_memory_seqlock_reader.h"
-#include "third_party/WebKit/public/platform/WebDeviceOrientationData.h"
+#include "third_party/WebKit/public/platform/modules/device_orientation/WebDeviceOrientationData.h"
namespace blink {
class WebDeviceOrientationListener;
diff --git a/chromium/content/renderer/device_sensors/device_orientation_event_pump_unittest.cc b/chromium/content/renderer/device_sensors/device_orientation_event_pump_unittest.cc
index 35792f9b10d..4a2ace1cad7 100644
--- a/chromium/content/renderer/device_sensors/device_orientation_event_pump_unittest.cc
+++ b/chromium/content/renderer/device_sensors/device_orientation_event_pump_unittest.cc
@@ -9,7 +9,7 @@
#include "content/common/device_sensors/device_orientation_hardware_buffer.h"
#include "content/public/test/test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/public/platform/WebDeviceOrientationListener.h"
+#include "third_party/WebKit/public/platform/modules/device_orientation/WebDeviceOrientationListener.h"
namespace content {
@@ -74,7 +74,7 @@ class DeviceOrientationEventPumpTest : public testing::Test {
protected:
void SetUp() override {
- const DeviceOrientationHardwareBuffer* null_buffer = NULL;
+ const DeviceOrientationHardwareBuffer* null_buffer = nullptr;
listener_.reset(new MockDeviceOrientationListener);
orientation_pump_.reset(new DeviceOrientationEventPumpForTesting);
buffer_ = static_cast<DeviceOrientationHardwareBuffer*>(
diff --git a/chromium/content/renderer/device_sensors/device_sensor_event_pump.h b/chromium/content/renderer/device_sensors/device_sensor_event_pump.h
index 43e0f64dca4..45e028d8679 100644
--- a/chromium/content/renderer/device_sensors/device_sensor_event_pump.h
+++ b/chromium/content/renderer/device_sensors/device_sensor_event_pump.h
@@ -22,7 +22,7 @@ class CONTENT_EXPORT DeviceSensorEventPump
base::Time::kMicrosecondsPerSecond / kDefaultPumpFrequencyHz;
// PlatformEventObserver
- virtual void Start(blink::WebPlatformEventListener* listener) override {
+ void Start(blink::WebPlatformEventListener* listener) override {
DVLOG(2) << "requested start";
if (state_ != STOPPED)
@@ -34,7 +34,7 @@ class CONTENT_EXPORT DeviceSensorEventPump
state_ = PENDING_START;
}
- virtual void Stop() override {
+ void Stop() override {
DVLOG(2) << "stop";
if (state_ == STOPPED)
@@ -55,7 +55,7 @@ class CONTENT_EXPORT DeviceSensorEventPump
pump_delay_microseconds_(kDefaultPumpDelayMicroseconds),
state_(STOPPED) {}
- virtual ~DeviceSensorEventPump() {
+ ~DeviceSensorEventPump() override {
PlatformEventObserver<ListenerType>::StopIfObserving();
}
diff --git a/chromium/content/renderer/devtools/devtools_agent.cc b/chromium/content/renderer/devtools/devtools_agent.cc
index f03bbb35857..9b627e0675b 100644
--- a/chromium/content/renderer/devtools/devtools_agent.cc
+++ b/chromium/content/renderer/devtools/devtools_agent.cc
@@ -6,28 +6,21 @@
#include <map>
-#include "base/debug/trace_event.h"
#include "base/lazy_instance.h"
#include "base/message_loop/message_loop.h"
-#include "base/process/process_handle.h"
#include "base/strings/string_number_conversions.h"
+#include "base/trace_event/trace_event.h"
#include "content/common/devtools_messages.h"
#include "content/common/frame_messages.h"
-#include "content/common/gpu/gpu_messages.h"
-#include "content/common/view_messages.h"
-#include "content/renderer/devtools/devtools_agent_filter.h"
#include "content/renderer/devtools/devtools_client.h"
-#include "content/renderer/render_thread_impl.h"
-#include "content/renderer/render_view_impl.h"
+#include "content/renderer/render_frame_impl.h"
+#include "content/renderer/render_widget.h"
+#include "ipc/ipc_channel.h"
#include "third_party/WebKit/public/platform/WebPoint.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/web/WebConsoleMessage.h"
-#include "third_party/WebKit/public/web/WebConsoleMessage.h"
#include "third_party/WebKit/public/web/WebDevToolsAgent.h"
-#include "third_party/WebKit/public/web/WebDeviceEmulationParams.h"
-#include "third_party/WebKit/public/web/WebFrame.h"
-#include "third_party/WebKit/public/web/WebSettings.h"
-#include "third_party/WebKit/public/web/WebView.h"
+#include "third_party/WebKit/public/web/WebLocalFrame.h"
#if defined(USE_TCMALLOC)
#include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h"
@@ -36,20 +29,15 @@
using blink::WebConsoleMessage;
using blink::WebDevToolsAgent;
using blink::WebDevToolsAgentClient;
-using blink::WebFrame;
+using blink::WebLocalFrame;
using blink::WebPoint;
using blink::WebString;
-using blink::WebCString;
-using blink::WebVector;
-using blink::WebView;
-using base::debug::TraceLog;
-using base::debug::TraceOptions;
+using base::trace_event::TraceLog;
+using base::trace_event::TraceOptions;
namespace content {
-base::subtle::AtomicWord DevToolsAgent::event_callback_;
-
namespace {
const size_t kMaxMessageChunkSize = IPC::Channel::kMaximumMessageSize / 4;
@@ -76,20 +64,19 @@ base::LazyInstance<IdToAgentMap>::Leaky
} // namespace
-DevToolsAgent::DevToolsAgent(RenderViewImpl* render_view)
- : RenderViewObserver(render_view),
+DevToolsAgent::DevToolsAgent(RenderFrameImpl* frame)
+ : RenderFrameObserver(frame),
is_attached_(false),
is_devtools_client_(false),
- gpu_route_id_(MSG_ROUTING_NONE),
- paused_in_mouse_move_(false) {
+ paused_in_mouse_move_(false),
+ paused_(false),
+ frame_(frame) {
g_agent_for_routing_id.Get()[routing_id()] = this;
-
- render_view->webview()->setDevToolsAgentClient(this);
+ frame_->GetWebFrame()->setDevToolsAgentClient(this);
}
DevToolsAgent::~DevToolsAgent() {
g_agent_for_routing_id.Get().erase(routing_id());
- resetTraceEventCallback();
}
// Called on the Renderer thread.
@@ -104,46 +91,26 @@ bool DevToolsAgent::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(DevToolsAgentMsg_InspectElement, OnInspectElement)
IPC_MESSAGE_HANDLER(DevToolsAgentMsg_AddMessageToConsole,
OnAddMessageToConsole)
- IPC_MESSAGE_HANDLER(DevToolsAgentMsg_GpuTasksChunk, OnGpuTasksChunk)
IPC_MESSAGE_HANDLER(DevToolsMsg_SetupDevToolsClient, OnSetupDevToolsClient)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
- if (message.type() == FrameMsg_Navigate::ID ||
- message.type() == ViewMsg_Close::ID)
+ if (message.type() == FrameMsg_Navigate::ID)
ContinueProgram(); // Don't want to swallow the message.
return handled;
}
-void DevToolsAgent::sendMessageToInspectorFrontend(
- const blink::WebString& message) {
- std::string msg(message.utf8());
- if (msg.length() < kMaxMessageChunkSize) {
- Send(new DevToolsClientMsg_DispatchOnInspectorFrontend(
- routing_id(), msg, msg.size()));
- return;
- }
-
- for (size_t pos = 0; pos < msg.length(); pos += kMaxMessageChunkSize) {
- Send(new DevToolsClientMsg_DispatchOnInspectorFrontend(
- routing_id(),
- msg.substr(pos, kMaxMessageChunkSize),
- pos ? 0 : msg.size()));
- }
-}
-
-long DevToolsAgent::processId() {
- return base::GetCurrentProcId();
+void DevToolsAgent::WidgetWillClose() {
+ ContinueProgram();
}
-int DevToolsAgent::debuggerId() {
- return routing_id();
-}
-
-void DevToolsAgent::saveAgentRuntimeState(
- const blink::WebString& state) {
- Send(new DevToolsHostMsg_SaveAgentRuntimeState(routing_id(), state.utf8()));
+void DevToolsAgent::sendProtocolMessage(
+ int call_id,
+ const blink::WebString& message,
+ const blink::WebString& state_cookie) {
+ SendChunkedProtocolMessage(
+ this, routing_id(), call_id, message.utf8(), state_cookie.utf8());
}
blink::WebDevToolsAgentClient::WebKitClientMessageLoop*
@@ -152,42 +119,26 @@ blink::WebDevToolsAgentClient::WebKitClientMessageLoop*
}
void DevToolsAgent::willEnterDebugLoop() {
- RenderViewImpl* impl = static_cast<RenderViewImpl*>(render_view());
- paused_in_mouse_move_ = impl->SendAckForMouseMoveFromDebugger();
+ paused_ = true;
+ if (RenderWidget* widget = frame_->GetRenderWidget())
+ paused_in_mouse_move_ = widget->SendAckForMouseMoveFromDebugger();
}
void DevToolsAgent::didExitDebugLoop() {
- RenderViewImpl* impl = static_cast<RenderViewImpl*>(render_view());
- if (paused_in_mouse_move_) {
- impl->IgnoreAckForMouseMoveFromDebugger();
+ paused_ = false;
+ if (!paused_in_mouse_move_)
+ return;
+ if (RenderWidget* widget = frame_->GetRenderWidget()) {
+ widget->IgnoreAckForMouseMoveFromDebugger();
paused_in_mouse_move_ = false;
}
}
-void DevToolsAgent::resetTraceEventCallback()
-{
- TraceLog::GetInstance()->SetEventCallbackDisabled();
- base::subtle::NoBarrier_Store(&event_callback_, 0);
-}
-
-void DevToolsAgent::setTraceEventCallback(const WebString& category_filter,
- TraceEventCallback cb) {
- TraceLog* trace_log = TraceLog::GetInstance();
- base::subtle::NoBarrier_Store(&event_callback_,
- reinterpret_cast<base::subtle::AtomicWord>(cb));
- if (!!cb) {
- trace_log->SetEventCallbackEnabled(base::debug::CategoryFilter(
- category_filter.utf8()), TraceEventCallbackWrapper);
- } else {
- trace_log->SetEventCallbackDisabled();
- }
-}
-
void DevToolsAgent::enableTracing(const WebString& category_filter) {
TraceLog* trace_log = TraceLog::GetInstance();
- trace_log->SetEnabled(base::debug::CategoryFilter(category_filter.utf8()),
- TraceLog::RECORDING_MODE,
- TraceOptions());
+ trace_log->SetEnabled(
+ base::trace_event::CategoryFilter(category_filter.utf8()),
+ TraceLog::RECORDING_MODE, TraceOptions());
}
void DevToolsAgent::disableTracing() {
@@ -195,85 +146,45 @@ void DevToolsAgent::disableTracing() {
}
// static
-void DevToolsAgent::TraceEventCallbackWrapper(
- base::TimeTicks timestamp,
- char phase,
- const unsigned char* category_group_enabled,
- const char* name,
- unsigned long long id,
- int num_args,
- const char* const arg_names[],
- const unsigned char arg_types[],
- const unsigned long long arg_values[],
- unsigned char flags) {
- TraceEventCallback callback =
- reinterpret_cast<TraceEventCallback>(
- base::subtle::NoBarrier_Load(&event_callback_));
- if (callback) {
- double timestamp_seconds = (timestamp - base::TimeTicks()).InSecondsF();
- callback(phase, category_group_enabled, name, id, num_args,
- arg_names, arg_types, arg_values, flags, timestamp_seconds);
- }
-}
-
-void DevToolsAgent::startGPUEventsRecording() {
- GpuChannelHost* gpu_channel_host =
- RenderThreadImpl::current()->GetGpuChannel();
- if (!gpu_channel_host)
- return;
- DCHECK(gpu_route_id_ == MSG_ROUTING_NONE);
- int32 route_id = gpu_channel_host->GenerateRouteID();
- bool succeeded = false;
- gpu_channel_host->Send(
- new GpuChannelMsg_DevToolsStartEventsRecording(route_id, &succeeded));
- DCHECK(succeeded);
- if (succeeded) {
- gpu_route_id_ = route_id;
- gpu_channel_host->AddRoute(gpu_route_id_, AsWeakPtr());
+DevToolsAgent* DevToolsAgent::FromRoutingId(int routing_id) {
+ IdToAgentMap::iterator it = g_agent_for_routing_id.Get().find(routing_id);
+ if (it != g_agent_for_routing_id.Get().end()) {
+ return it->second;
}
+ return NULL;
}
-void DevToolsAgent::stopGPUEventsRecording() {
- GpuChannelHost* gpu_channel_host =
- RenderThreadImpl::current()->GetGpuChannel();
- if (!gpu_channel_host || gpu_route_id_ == MSG_ROUTING_NONE)
- return;
- gpu_channel_host->Send(new GpuChannelMsg_DevToolsStopEventsRecording());
- gpu_channel_host->RemoveRoute(gpu_route_id_);
- gpu_route_id_ = MSG_ROUTING_NONE;
-}
-
-void DevToolsAgent::OnGpuTasksChunk(const std::vector<GpuTaskInfo>& tasks) {
- WebDevToolsAgent* web_agent = GetWebAgent();
- if (!web_agent)
+// static
+void DevToolsAgent::SendChunkedProtocolMessage(
+ IPC::Sender* sender,
+ int routing_id,
+ int call_id,
+ const std::string& message,
+ const std::string& post_state) {
+ DevToolsMessageChunk chunk;
+ chunk.message_size = message.size();
+ chunk.is_first = true;
+
+ if (message.length() < kMaxMessageChunkSize) {
+ chunk.data = message;
+ chunk.call_id = call_id;
+ chunk.post_state = post_state;
+ chunk.is_last = true;
+ sender->Send(new DevToolsClientMsg_DispatchOnInspectorFrontend(
+ routing_id, chunk));
return;
- for (size_t i = 0; i < tasks.size(); i++) {
- const GpuTaskInfo& task = tasks[i];
- WebDevToolsAgent::GPUEvent event(
- task.timestamp, task.phase, task.foreign, task.gpu_memory_used_bytes);
- event.limitGPUMemoryBytes = task.gpu_memory_limit_bytes;
- web_agent->processGPUEvent(event);
}
-}
-
-void DevToolsAgent::enableDeviceEmulation(
- const blink::WebDeviceEmulationParams& params) {
- RenderViewImpl* impl = static_cast<RenderViewImpl*>(render_view());
- impl->EnableScreenMetricsEmulation(params);
-}
-
-void DevToolsAgent::disableDeviceEmulation() {
- RenderViewImpl* impl = static_cast<RenderViewImpl*>(render_view());
- impl->DisableScreenMetricsEmulation();
-}
-// static
-DevToolsAgent* DevToolsAgent::FromRoutingId(int routing_id) {
- IdToAgentMap::iterator it = g_agent_for_routing_id.Get().find(routing_id);
- if (it != g_agent_for_routing_id.Get().end()) {
- return it->second;
+ for (size_t pos = 0; pos < message.length(); pos += kMaxMessageChunkSize) {
+ chunk.is_last = pos + kMaxMessageChunkSize >= message.length();
+ chunk.call_id = chunk.is_last ? call_id : 0;
+ chunk.post_state = chunk.is_last ? post_state : std::string();
+ chunk.data = message.substr(pos, kMaxMessageChunkSize);
+ sender->Send(new DevToolsClientMsg_DispatchOnInspectorFrontend(
+ routing_id, chunk));
+ chunk.is_first = false;
+ chunk.message_size = 0;
}
- return NULL;
}
void DevToolsAgent::OnAttach(const std::string& host_id) {
@@ -321,12 +232,8 @@ void DevToolsAgent::OnInspectElement(
void DevToolsAgent::OnAddMessageToConsole(ConsoleMessageLevel level,
const std::string& message) {
- WebView* web_view = render_view()->GetWebView();
- if (!web_view)
- return;
-
- WebFrame* main_frame = web_view->mainFrame();
- if (!main_frame)
+ WebLocalFrame* web_frame = frame_->GetWebFrame();
+ if (!web_frame)
return;
WebConsoleMessage::Level target_level = WebConsoleMessage::LevelLog;
@@ -344,7 +251,7 @@ void DevToolsAgent::OnAddMessageToConsole(ConsoleMessageLevel level,
target_level = WebConsoleMessage::LevelError;
break;
}
- main_frame->addMessageToConsole(
+ web_frame->addMessageToConsole(
WebConsoleMessage(target_level, WebString::fromUTF8(message)));
}
@@ -355,18 +262,17 @@ void DevToolsAgent::ContinueProgram() {
}
void DevToolsAgent::OnSetupDevToolsClient() {
- // We only want to register once per render view.
+ // We only want to register once; and only in main frame.
+ DCHECK(!frame_->GetWebFrame() || !frame_->GetWebFrame()->parent());
if (is_devtools_client_)
return;
is_devtools_client_ = true;
- new DevToolsClient(static_cast<RenderViewImpl*>(render_view()));
+ new DevToolsClient(frame_);
}
WebDevToolsAgent* DevToolsAgent::GetWebAgent() {
- WebView* web_view = render_view()->GetWebView();
- if (!web_view)
- return NULL;
- return web_view->devToolsAgent();
+ WebLocalFrame* web_frame = frame_->GetWebFrame();
+ return web_frame ? web_frame->devToolsAgent() : nullptr;
}
bool DevToolsAgent::IsAttached() {
diff --git a/chromium/content/renderer/devtools/devtools_agent.h b/chromium/content/renderer/devtools/devtools_agent.h
index dcb70c5f692..1979f3882a1 100644
--- a/chromium/content/renderer/devtools/devtools_agent.h
+++ b/chromium/content/renderer/devtools/devtools_agent.h
@@ -6,74 +6,62 @@
#define CONTENT_RENDERER_DEVTOOLS_DEVTOOLS_AGENT_H_
#include <string>
-#include <vector>
-#include "base/atomicops.h"
-#include "base/basictypes.h"
-#include "base/memory/weak_ptr.h"
-#include "base/time/time.h"
+#include "content/common/content_export.h"
#include "content/public/common/console_message_level.h"
-#include "content/public/renderer/render_view_observer.h"
+#include "content/public/renderer/render_frame_observer.h"
#include "third_party/WebKit/public/web/WebDevToolsAgentClient.h"
namespace blink {
class WebDevToolsAgent;
}
-struct GpuTaskInfo;
-
namespace content {
-class RenderViewImpl;
-
-// DevToolsAgent belongs to the inspectable RenderView and provides Glue's
-// agents with the communication capabilities. All messages from/to Glue's
-// agents infrastructure are flowing through this communication agent.
-// There is a corresponding DevToolsClient object on the client side.
-class DevToolsAgent : public RenderViewObserver,
- public base::SupportsWeakPtr<DevToolsAgent>,
- public blink::WebDevToolsAgentClient {
+
+class RenderFrameImpl;
+
+// DevToolsAgent belongs to the inspectable RenderFrameImpl and communicates
+// with WebDevToolsAgent. There is a corresponding DevToolsAgentHost
+// on the browser side.
+class CONTENT_EXPORT DevToolsAgent
+ : public RenderFrameObserver,
+ NON_EXPORTED_BASE(public blink::WebDevToolsAgentClient) {
public:
- explicit DevToolsAgent(RenderViewImpl* render_view);
+ explicit DevToolsAgent(RenderFrameImpl* frame);
~DevToolsAgent() override;
// Returns agent instance for its routing id.
static DevToolsAgent* FromRoutingId(int routing_id);
+ static void SendChunkedProtocolMessage(
+ IPC::Sender* sender,
+ int routing_id,
+ int call_id,
+ const std::string& message,
+ const std::string& post_state);
+
blink::WebDevToolsAgent* GetWebAgent();
bool IsAttached();
private:
- // RenderView::Observer implementation.
- bool OnMessageReceived(const IPC::Message& message) override;
+ friend class DevToolsAgentTest;
- // WebDevToolsAgentClient implementation
- virtual void sendMessageToInspectorFrontend(const blink::WebString& data);
+ // RenderFrameObserver implementation.
+ bool OnMessageReceived(const IPC::Message& message) override;
+ void WidgetWillClose() override;
- virtual long processId() override;
- virtual int debuggerId() override;
- virtual void saveAgentRuntimeState(const blink::WebString& state) override;
- virtual blink::WebDevToolsAgentClient::WebKitClientMessageLoop*
+ // WebDevToolsAgentClient implementation.
+ void sendProtocolMessage(int call_id,
+ const blink::WebString& response,
+ const blink::WebString& state) override;
+ blink::WebDevToolsAgentClient::WebKitClientMessageLoop*
createClientMessageLoop() override;
- virtual void willEnterDebugLoop() override;
- virtual void didExitDebugLoop() override;
-
- typedef void (*TraceEventCallback)(
- char phase, const unsigned char*, const char* name, unsigned long long id,
- int numArgs, const char* const* argNames, const unsigned char* argTypes,
- const unsigned long long* argValues,
- unsigned char flags, double timestamp);
- virtual void resetTraceEventCallback() override;
- virtual void setTraceEventCallback(const blink::WebString& category_filter,
- TraceEventCallback cb) override;
- virtual void enableTracing(const blink::WebString& category_filter) override;
- virtual void disableTracing() override;
- virtual void startGPUEventsRecording() override;
- virtual void stopGPUEventsRecording() override;
-
- virtual void enableDeviceEmulation(
- const blink::WebDeviceEmulationParams& params) override;
- virtual void disableDeviceEmulation() override;
+ void willEnterDebugLoop() override;
+ void didExitDebugLoop() override;
+
+ void enableTracing(const blink::WebString& category_filter) override;
+ void disableTracing() override;
void OnAttach(const std::string& host_id);
void OnReattach(const std::string& host_id,
@@ -83,28 +71,14 @@ class DevToolsAgent : public RenderViewObserver,
void OnInspectElement(const std::string& host_id, int x, int y);
void OnAddMessageToConsole(ConsoleMessageLevel level,
const std::string& message);
- void OnGpuTasksChunk(const std::vector<GpuTaskInfo>& tasks);
void ContinueProgram();
void OnSetupDevToolsClient();
- static void TraceEventCallbackWrapper(
- base::TimeTicks timestamp,
- char phase,
- const unsigned char* category_group_enabled,
- const char* name,
- unsigned long long id,
- int num_args,
- const char* const arg_names[],
- const unsigned char arg_types[],
- const unsigned long long arg_values[],
- unsigned char flags);
-
bool is_attached_;
bool is_devtools_client_;
- int32 gpu_route_id_;
bool paused_in_mouse_move_;
-
- static base::subtle::AtomicWord /* TraceEventCallback */ event_callback_;
+ bool paused_;
+ RenderFrameImpl* frame_;
DISALLOW_COPY_AND_ASSIGN(DevToolsAgent);
};
diff --git a/chromium/content/renderer/devtools/devtools_agent_filter.cc b/chromium/content/renderer/devtools/devtools_agent_filter.cc
index b0a60f00514..f070c1fb280 100644
--- a/chromium/content/renderer/devtools/devtools_agent_filter.cc
+++ b/chromium/content/renderer/devtools/devtools_agent_filter.cc
@@ -41,21 +41,18 @@ class MessageImpl : public WebDevToolsAgent::MessageDescriptor {
} // namespace
DevToolsAgentFilter::DevToolsAgentFilter()
- : message_handled_(false),
- render_thread_loop_(base::MessageLoop::current()),
+ : render_thread_loop_(base::MessageLoop::current()),
io_message_loop_proxy_(ChildProcess::current()->io_message_loop_proxy()),
current_routing_id_(0) {}
bool DevToolsAgentFilter::OnMessageReceived(const IPC::Message& message) {
// Dispatch debugger commands directly from IO.
- message_handled_ = true;
current_routing_id_ = message.routing_id();
IPC_BEGIN_MESSAGE_MAP(DevToolsAgentFilter, message)
IPC_MESSAGE_HANDLER(DevToolsAgentMsg_DispatchOnInspectorBackend,
OnDispatchOnInspectorBackend)
- IPC_MESSAGE_UNHANDLED(message_handled_ = false)
IPC_END_MESSAGE_MAP()
- return message_handled_;
+ return false;
}
DevToolsAgentFilter::~DevToolsAgentFilter() {}
@@ -64,19 +61,15 @@ void DevToolsAgentFilter::OnDispatchOnInspectorBackend(
const std::string& message) {
if (embedded_worker_routes_.find(current_routing_id_) !=
embedded_worker_routes_.end()) {
- message_handled_ = false;
return;
}
- if (!WebDevToolsAgent::shouldInterruptForMessage(
+
+ if (WebDevToolsAgent::shouldInterruptForMessage(
WebString::fromUTF8(message))) {
- message_handled_ = false;
- return;
+ WebDevToolsAgent::interruptAndDispatch(
+ new MessageImpl(message, current_routing_id_));
}
- WebDevToolsAgent::interruptAndDispatch(
- new MessageImpl(message, current_routing_id_));
- render_thread_loop_->PostTask(
- FROM_HERE, base::Bind(&WebDevToolsAgent::processPendingMessages));
}
void DevToolsAgentFilter::AddEmbeddedWorkerRouteOnMainThread(int32 routing_id) {
diff --git a/chromium/content/renderer/devtools/devtools_agent_filter.h b/chromium/content/renderer/devtools/devtools_agent_filter.h
index 48831a30c6d..5f2ce6411fc 100644
--- a/chromium/content/renderer/devtools/devtools_agent_filter.h
+++ b/chromium/content/renderer/devtools/devtools_agent_filter.h
@@ -49,7 +49,6 @@ class DevToolsAgentFilter : public IPC::MessageFilter {
void AddEmbeddedWorkerRoute(int32 routing_id);
void RemoveEmbeddedWorkerRoute(int32 routing_id);
- bool message_handled_;
base::MessageLoop* render_thread_loop_;
// Proxy to the IO message loop.
scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_;
diff --git a/chromium/content/renderer/devtools/devtools_client.cc b/chromium/content/renderer/devtools/devtools_client.cc
index 0d4f7dc520b..39bd12a60f4 100644
--- a/chromium/content/renderer/devtools/devtools_client.cc
+++ b/chromium/content/renderer/devtools/devtools_client.cc
@@ -22,15 +22,13 @@ using blink::WebString;
namespace content {
-DevToolsClient::DevToolsClient(RenderViewImpl* render_view)
- : RenderViewObserver(render_view) {
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
- web_tools_frontend_.reset(
- WebDevToolsFrontend::create(
- render_view->webview(),
- this,
- base::ASCIIToUTF16(
- command_line.GetSwitchValueASCII(switches::kLang))));
+DevToolsClient::DevToolsClient(RenderFrame* main_render_frame)
+ : RenderFrameObserver(main_render_frame) {
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
+ web_tools_frontend_.reset(WebDevToolsFrontend::create(
+ main_render_frame->GetRenderView()->GetWebView(), this,
+ base::ASCIIToUTF16(command_line.GetSwitchValueASCII(switches::kLang))));
}
DevToolsClient::~DevToolsClient() {
diff --git a/chromium/content/renderer/devtools/devtools_client.h b/chromium/content/renderer/devtools/devtools_client.h
index bf6e077f255..6460ca83c73 100644
--- a/chromium/content/renderer/devtools/devtools_client.h
+++ b/chromium/content/renderer/devtools/devtools_client.h
@@ -9,7 +9,7 @@
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
-#include "content/public/renderer/render_view_observer.h"
+#include "content/public/renderer/render_frame_observer.h"
#include "third_party/WebKit/public/web/WebDevToolsFrontendClient.h"
namespace blink {
@@ -19,8 +19,6 @@ class WebString;
namespace content {
-class RenderViewImpl;
-
// Developer tools UI end of communication channel between the render process of
// the page being inspected and tools UI renderer process. All messages will
// go through browser process. On the side of the inspected page there's
@@ -28,10 +26,10 @@ class RenderViewImpl;
// TODO(yurys): now the client is almost empty later it will delegate calls to
// code in glue
class CONTENT_EXPORT DevToolsClient
- : public RenderViewObserver,
- NON_EXPORTED_BASE(public blink::WebDevToolsFrontendClient) {
+ : public RenderFrameObserver,
+ NON_EXPORTED_BASE(public blink::WebDevToolsFrontendClient) {
public:
- explicit DevToolsClient(RenderViewImpl* render_view);
+ explicit DevToolsClient(RenderFrame* main_render_frame);
virtual ~DevToolsClient();
private:
diff --git a/chromium/content/renderer/devtools/lock_free_circular_queue.h b/chromium/content/renderer/devtools/lock_free_circular_queue.h
new file mode 100644
index 00000000000..dfa780bb5e7
--- /dev/null
+++ b/chromium/content/renderer/devtools/lock_free_circular_queue.h
@@ -0,0 +1,135 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_DEVTOOLS_LOCK_FREE_CIRCULAR_QUEUE_H_
+#define CONTENT_RENDERER_DEVTOOLS_LOCK_FREE_CIRCULAR_QUEUE_H_
+
+#include "base/atomicops.h"
+#include "base/memory/aligned_memory.h"
+
+#define CACHELINE_ALIGNED ALIGNAS(64)
+
+namespace content {
+
+MSVC_PUSH_DISABLE_WARNING(4324) // structure was padded due to align
+
+// Lock-free cache-friendly sampling circular queue for large
+// records. Intended for fast transfer of large records between a
+// single producer and a single consumer. If the queue is full,
+// StartEnqueue will return nullptr. The queue is designed with
+// a goal in mind to evade cache lines thrashing by preventing
+// simultaneous reads and writes to adjanced memory locations.
+template <typename T, unsigned Length>
+class LockFreeCircularQueue {
+ public:
+ // Executed on the application thread.
+ LockFreeCircularQueue();
+ ~LockFreeCircularQueue();
+
+ // StartEnqueue returns a pointer to a memory location for storing the next
+ // record or nullptr if all entries are full at the moment.
+ T* StartEnqueue();
+ // Notifies the queue that the producer has complete writing data into the
+ // memory returned by StartEnqueue and it can be passed to the consumer.
+ void FinishEnqueue();
+
+ // Executed on the consumer (analyzer) thread.
+ // Retrieves, but does not remove, the head of this queue, returning nullptr
+ // if this queue is empty. After the record had been read by a consumer,
+ // Remove must be called.
+ T* Peek();
+ void Remove();
+
+ // The class fields have stricter alignment requirements than a normal new
+ // can fulfil, so we need to provide our own new/delete here.
+ void* operator new(size_t size);
+ void operator delete(void* ptr);
+
+ private:
+ // Reserved values for the entry marker.
+ enum {
+ kEmpty, // Marks clean (processed) entries.
+ kFull // Marks entries already filled by the producer but not yet
+ // completely processed by the consumer.
+ };
+
+ struct CACHELINE_ALIGNED Entry {
+ Entry() : marker(kEmpty) {}
+ T record;
+ base::subtle::Atomic32 marker;
+ };
+
+ Entry* Next(Entry* entry);
+
+ Entry buffer_[Length];
+ CACHELINE_ALIGNED Entry* enqueue_pos_;
+ CACHELINE_ALIGNED Entry* dequeue_pos_;
+
+ DISALLOW_COPY_AND_ASSIGN(LockFreeCircularQueue);
+};
+
+MSVC_POP_WARNING()
+
+template <typename T, unsigned L>
+LockFreeCircularQueue<T, L>::LockFreeCircularQueue()
+ : enqueue_pos_(buffer_), dequeue_pos_(buffer_) {
+}
+
+template <typename T, unsigned L>
+LockFreeCircularQueue<T, L>::~LockFreeCircularQueue() {
+}
+
+template <typename T, unsigned L>
+T* LockFreeCircularQueue<T, L>::Peek() {
+ base::subtle::MemoryBarrier();
+ if (base::subtle::Acquire_Load(&dequeue_pos_->marker) == kFull) {
+ return &dequeue_pos_->record;
+ }
+ return nullptr;
+}
+
+template <typename T, unsigned L>
+void LockFreeCircularQueue<T, L>::Remove() {
+ base::subtle::Release_Store(&dequeue_pos_->marker, kEmpty);
+ dequeue_pos_ = Next(dequeue_pos_);
+}
+
+template <typename T, unsigned L>
+T* LockFreeCircularQueue<T, L>::StartEnqueue() {
+ base::subtle::MemoryBarrier();
+ if (base::subtle::Acquire_Load(&enqueue_pos_->marker) == kEmpty) {
+ return &enqueue_pos_->record;
+ }
+ return nullptr;
+}
+
+template <typename T, unsigned L>
+void LockFreeCircularQueue<T, L>::FinishEnqueue() {
+ base::subtle::Release_Store(&enqueue_pos_->marker, kFull);
+ enqueue_pos_ = Next(enqueue_pos_);
+}
+
+template <typename T, unsigned L>
+typename LockFreeCircularQueue<T, L>::Entry* LockFreeCircularQueue<T, L>::Next(
+ Entry* entry) {
+ Entry* next = entry + 1;
+ if (next == &buffer_[L])
+ return buffer_;
+ return next;
+}
+
+template <typename T, unsigned L>
+void* LockFreeCircularQueue<T, L>::operator new(size_t size) {
+ typedef LockFreeCircularQueue<T, L> QueueTypeAlias;
+ return base::AlignedAlloc(size, ALIGNOF(QueueTypeAlias));
+}
+
+template <typename T, unsigned L>
+void LockFreeCircularQueue<T, L>::operator delete(void* ptr) {
+ base::AlignedFree(ptr);
+}
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_DEVTOOLS_LOCK_FREE_CIRCULAR_QUEUE_H_
diff --git a/chromium/content/renderer/devtools/v8_sampling_profiler.cc b/chromium/content/renderer/devtools/v8_sampling_profiler.cc
new file mode 100644
index 00000000000..20b22387282
--- /dev/null
+++ b/chromium/content/renderer/devtools/v8_sampling_profiler.cc
@@ -0,0 +1,627 @@
+// Copyright 2014 The Chromium Authors. 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/renderer/devtools/v8_sampling_profiler.h"
+
+#if defined(OS_POSIX)
+#include <signal.h>
+#define USE_SIGNALS
+#endif
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+#include "base/format_macros.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/cancellation_flag.h"
+#include "base/threading/platform_thread.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "content/renderer/devtools/lock_free_circular_queue.h"
+#include "content/renderer/render_thread_impl.h"
+#include "v8/include/v8.h"
+
+using base::trace_event::ConvertableToTraceFormat;
+using base::trace_event::TraceLog;
+using base::trace_event::TracedValue;
+using v8::Isolate;
+
+namespace content {
+
+namespace {
+
+class PlatformDataCommon {
+ public:
+ base::PlatformThreadId thread_id() { return thread_id_; }
+
+ protected:
+ PlatformDataCommon() : thread_id_(base::PlatformThread::CurrentId()) {}
+
+ private:
+ base::PlatformThreadId thread_id_;
+};
+
+#if defined(USE_SIGNALS)
+
+class PlatformData : public PlatformDataCommon {
+ public:
+ PlatformData() : vm_tid_(pthread_self()) {}
+ pthread_t vm_tid() const { return vm_tid_; }
+
+ private:
+ pthread_t vm_tid_;
+};
+
+#elif defined(OS_WIN)
+
+class PlatformData : public PlatformDataCommon {
+ public:
+ // Get a handle to the calling thread. This is the thread that we are
+ // going to profile. We need to make a copy of the handle because we are
+ // going to use it in the sampler thread. Using GetThreadHandle() will
+ // not work in this case. We're using OpenThread because DuplicateHandle
+ // doesn't work in Chrome's sandbox.
+ PlatformData()
+ : thread_handle_(::OpenThread(THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME |
+ THREAD_QUERY_INFORMATION,
+ false,
+ ::GetCurrentThreadId())) {}
+
+ ~PlatformData() {
+ if (thread_handle_ == NULL)
+ return;
+ ::CloseHandle(thread_handle_);
+ thread_handle_ = NULL;
+ }
+
+ HANDLE thread_handle() { return thread_handle_; }
+
+ private:
+ HANDLE thread_handle_;
+};
+#endif
+
+std::string PtrToString(const void* value) {
+ return base::StringPrintf(
+ "0x%" PRIx64, static_cast<uint64>(reinterpret_cast<intptr_t>(value)));
+}
+
+class SampleRecord {
+ public:
+ static const int kMaxFramesCountLog2 = 8;
+ static const unsigned kMaxFramesCount = (1u << kMaxFramesCountLog2) - 1;
+
+ SampleRecord() {}
+
+ base::TimeTicks timestamp() const { return timestamp_; }
+ void Collect(v8::Isolate* isolate,
+ base::TimeTicks timestamp,
+ const v8::RegisterState& state);
+ scoped_refptr<ConvertableToTraceFormat> ToTraceFormat() const;
+
+ private:
+ base::TimeTicks timestamp_;
+ unsigned vm_state_ : 4;
+ unsigned frames_count_ : kMaxFramesCountLog2;
+ const void* frames_[kMaxFramesCount];
+
+ DISALLOW_COPY_AND_ASSIGN(SampleRecord);
+};
+
+void SampleRecord::Collect(v8::Isolate* isolate,
+ base::TimeTicks timestamp,
+ const v8::RegisterState& state) {
+ v8::SampleInfo sample_info;
+ isolate->GetStackSample(state, (void**)frames_, kMaxFramesCount,
+ &sample_info);
+ timestamp_ = timestamp;
+ frames_count_ = sample_info.frames_count;
+ vm_state_ = sample_info.vm_state;
+}
+
+scoped_refptr<ConvertableToTraceFormat> SampleRecord::ToTraceFormat() const {
+ scoped_refptr<TracedValue> data(new TracedValue());
+ const char* vm_state = nullptr;
+ switch (vm_state_) {
+ case v8::StateTag::JS:
+ vm_state = "js";
+ break;
+ case v8::StateTag::GC:
+ vm_state = "gc";
+ break;
+ case v8::StateTag::COMPILER:
+ vm_state = "compiler";
+ break;
+ case v8::StateTag::OTHER:
+ vm_state = "other";
+ break;
+ case v8::StateTag::EXTERNAL:
+ vm_state = "external";
+ break;
+ case v8::StateTag::IDLE:
+ vm_state = "idle";
+ break;
+ default:
+ NOTREACHED();
+ }
+ data->SetString("vm_state", vm_state);
+ data->BeginArray("stack");
+ for (unsigned i = 0; i < frames_count_; ++i) {
+ data->AppendString(PtrToString(frames_[i]));
+ }
+ data->EndArray();
+ return data;
+}
+
+} // namespace
+
+// The class implements a sampler responsible for sampling a single thread.
+class Sampler {
+ public:
+ ~Sampler();
+
+ static scoped_ptr<Sampler> CreateForCurrentThread();
+ static Sampler* GetInstance() { return tls_instance_.Pointer()->Get(); }
+
+ // These methods are called from the sampling thread.
+ void Start();
+ void Stop();
+ void Sample();
+
+ void DoSample(const v8::RegisterState& state);
+
+ void SetEventsToCollectForTest(int code_added_events, int sample_events) {
+ code_added_events_to_collect_for_test_ = code_added_events;
+ sample_events_to_collect_for_test_ = sample_events;
+ }
+
+ bool EventsCollectedForTest() const {
+ return base::subtle::NoBarrier_Load(&code_added_events_count_) >=
+ code_added_events_to_collect_for_test_ &&
+ base::subtle::NoBarrier_Load(&samples_count_) >=
+ sample_events_to_collect_for_test_;
+ }
+
+ private:
+ Sampler();
+
+ static void InstallJitCodeEventHandler(Isolate* isolate, void* data);
+ static void HandleJitCodeEvent(const v8::JitCodeEvent* event);
+ static scoped_refptr<ConvertableToTraceFormat> JitCodeEventToTraceFormat(
+ const v8::JitCodeEvent* event);
+
+ void InjectPendingEvents();
+
+ static const unsigned kNumberOfSamples = 10;
+ typedef LockFreeCircularQueue<SampleRecord, kNumberOfSamples> SamplingQueue;
+
+ PlatformData platform_data_;
+ Isolate* isolate_;
+ scoped_ptr<SamplingQueue> samples_data_;
+ base::subtle::Atomic32 code_added_events_count_;
+ base::subtle::Atomic32 samples_count_;
+ int code_added_events_to_collect_for_test_;
+ int sample_events_to_collect_for_test_;
+
+ static base::LazyInstance<base::ThreadLocalPointer<Sampler>>::Leaky
+ tls_instance_;
+};
+
+base::LazyInstance<base::ThreadLocalPointer<Sampler>>::Leaky
+ Sampler::tls_instance_ = LAZY_INSTANCE_INITIALIZER;
+
+Sampler::Sampler()
+ : isolate_(Isolate::GetCurrent()),
+ code_added_events_count_(0),
+ samples_count_(0),
+ code_added_events_to_collect_for_test_(0),
+ sample_events_to_collect_for_test_(0) {
+ DCHECK(isolate_);
+ DCHECK(!GetInstance());
+ tls_instance_.Pointer()->Set(this);
+}
+
+Sampler::~Sampler() {
+ DCHECK(GetInstance());
+ tls_instance_.Pointer()->Set(nullptr);
+}
+
+// static
+scoped_ptr<Sampler> Sampler::CreateForCurrentThread() {
+ return scoped_ptr<Sampler>(new Sampler());
+}
+
+void Sampler::Start() {
+ samples_data_.reset(new SamplingQueue());
+ v8::JitCodeEventHandler handler = &HandleJitCodeEvent;
+ isolate_->RequestInterrupt(&InstallJitCodeEventHandler,
+ reinterpret_cast<void*>(handler));
+}
+
+void Sampler::Stop() {
+ isolate_->RequestInterrupt(&InstallJitCodeEventHandler, nullptr);
+ samples_data_.reset();
+}
+
+#if ARCH_CPU_64_BITS
+#define REG_64_32(reg64, reg32) reg64
+#else
+#define REG_64_32(reg64, reg32) reg32
+#endif // ARCH_CPU_64_BITS
+
+void Sampler::Sample() {
+#if defined(OS_WIN)
+ const DWORD kSuspendFailed = static_cast<DWORD>(-1);
+ if (::SuspendThread(platform_data_.thread_handle()) == kSuspendFailed)
+ return;
+ CONTEXT context;
+ memset(&context, 0, sizeof(context));
+ context.ContextFlags = CONTEXT_FULL;
+ if (::GetThreadContext(platform_data_.thread_handle(), &context) != 0) {
+ v8::RegisterState state;
+ state.pc = reinterpret_cast<void*>(context.REG_64_32(Rip, Eip));
+ state.sp = reinterpret_cast<void*>(context.REG_64_32(Rsp, Esp));
+ state.fp = reinterpret_cast<void*>(context.REG_64_32(Rbp, Ebp));
+ // TODO(alph): It is not needed to buffer the events on Windows.
+ // We can just collect and fire trace event right away.
+ DoSample(state);
+ }
+ ::ResumeThread(platform_data_.thread_handle());
+#elif defined(USE_SIGNALS)
+ int error = pthread_kill(platform_data_.vm_tid(), SIGPROF);
+ if (error) {
+ LOG(ERROR) << "pthread_kill failed with error " << error << " "
+ << strerror(error);
+ }
+#endif
+ InjectPendingEvents();
+}
+
+void Sampler::DoSample(const v8::RegisterState& state) {
+ // Called in the sampled thread signal handler.
+ // Because of that it is not allowed to do any memory allocation here.
+ base::TimeTicks timestamp = base::TimeTicks::NowFromSystemTraceTime();
+ SampleRecord* record = samples_data_->StartEnqueue();
+ if (!record)
+ return;
+ record->Collect(isolate_, timestamp, state);
+ samples_data_->FinishEnqueue();
+}
+
+void Sampler::InjectPendingEvents() {
+ SampleRecord* record = samples_data_->Peek();
+ while (record) {
+ TRACE_EVENT_SAMPLE_WITH_TID_AND_TIMESTAMP1(
+ TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile"), "V8Sample",
+ platform_data_.thread_id(),
+ (record->timestamp() - base::TimeTicks()).InMicroseconds(), "data",
+ record->ToTraceFormat());
+ samples_data_->Remove();
+ record = samples_data_->Peek();
+ base::subtle::NoBarrier_AtomicIncrement(&samples_count_, 1);
+ }
+}
+
+// static
+void Sampler::InstallJitCodeEventHandler(Isolate* isolate, void* data) {
+ // Called on the sampled V8 thread.
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile"),
+ "Sampler::InstallJitCodeEventHandler");
+ v8::JitCodeEventHandler handler =
+ reinterpret_cast<v8::JitCodeEventHandler>(data);
+ isolate->SetJitCodeEventHandler(
+ v8::JitCodeEventOptions::kJitCodeEventEnumExisting, handler);
+}
+
+// static
+void Sampler::HandleJitCodeEvent(const v8::JitCodeEvent* event) {
+ // Called on the sampled V8 thread.
+ Sampler* sampler = GetInstance();
+ // The sampler may have already been destroyed.
+ // That's fine, we're not interested in these events anymore.
+ if (!sampler)
+ return;
+ switch (event->type) {
+ case v8::JitCodeEvent::CODE_ADDED:
+ TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile"),
+ "JitCodeAdded", TRACE_EVENT_SCOPE_THREAD, "data",
+ JitCodeEventToTraceFormat(event));
+ base::subtle::NoBarrier_AtomicIncrement(
+ &sampler->code_added_events_count_, 1);
+ break;
+
+ case v8::JitCodeEvent::CODE_MOVED:
+ TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile"),
+ "JitCodeMoved", TRACE_EVENT_SCOPE_THREAD, "data",
+ JitCodeEventToTraceFormat(event));
+ break;
+
+ case v8::JitCodeEvent::CODE_REMOVED:
+ TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile"),
+ "JitCodeRemoved", TRACE_EVENT_SCOPE_THREAD, "data",
+ JitCodeEventToTraceFormat(event));
+ break;
+
+ case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO:
+ case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING:
+ case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING:
+ break;
+ }
+}
+
+// static
+scoped_refptr<ConvertableToTraceFormat> Sampler::JitCodeEventToTraceFormat(
+ const v8::JitCodeEvent* event) {
+ switch (event->type) {
+ case v8::JitCodeEvent::CODE_ADDED: {
+ scoped_refptr<TracedValue> data(new TracedValue());
+ data->SetString("code_start", PtrToString(event->code_start));
+ data->SetInteger("code_len", static_cast<unsigned>(event->code_len));
+ data->SetString("name", std::string(event->name.str, event->name.len));
+ if (!event->script.IsEmpty()) {
+ data->SetInteger("script_id", event->script->GetId());
+ }
+ return data;
+ }
+
+ case v8::JitCodeEvent::CODE_MOVED: {
+ scoped_refptr<TracedValue> data(new TracedValue());
+ data->SetString("code_start", PtrToString(event->code_start));
+ data->SetInteger("code_len", static_cast<unsigned>(event->code_len));
+ data->SetString("new_code_start", PtrToString(event->new_code_start));
+ return data;
+ }
+
+ case v8::JitCodeEvent::CODE_REMOVED: {
+ scoped_refptr<TracedValue> data(new TracedValue());
+ data->SetString("code_start", PtrToString(event->code_start));
+ data->SetInteger("code_len", static_cast<unsigned>(event->code_len));
+ return data;
+ }
+
+ case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO:
+ case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING:
+ case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING:
+ return nullptr;
+ }
+ return nullptr;
+}
+
+class V8SamplingThread : public base::PlatformThread::Delegate {
+ public:
+ V8SamplingThread(Sampler*, base::WaitableEvent*);
+
+ // Implementation of PlatformThread::Delegate:
+ void ThreadMain() override;
+
+ void Start();
+ void Stop();
+
+ private:
+ void Sample();
+ void InstallSamplers();
+ void RemoveSamplers();
+ void StartSamplers();
+ void StopSamplers();
+
+ static void InstallSignalHandler();
+ static void RestoreSignalHandler();
+#ifdef USE_SIGNALS
+ static void HandleProfilerSignal(int signal, siginfo_t* info, void* context);
+#endif
+
+ static void HandleJitCodeEvent(const v8::JitCodeEvent* event);
+
+ Sampler* render_thread_sampler_;
+ base::CancellationFlag cancellation_flag_;
+ base::WaitableEvent* waitable_event_for_testing_;
+ base::PlatformThreadHandle sampling_thread_handle_;
+ std::vector<Sampler*> samplers_;
+
+#ifdef USE_SIGNALS
+ static bool signal_handler_installed_;
+ static struct sigaction old_signal_handler_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(V8SamplingThread);
+};
+
+#ifdef USE_SIGNALS
+bool V8SamplingThread::signal_handler_installed_;
+struct sigaction V8SamplingThread::old_signal_handler_;
+#endif
+
+V8SamplingThread::V8SamplingThread(Sampler* render_thread_sampler,
+ base::WaitableEvent* event)
+ : render_thread_sampler_(render_thread_sampler),
+ waitable_event_for_testing_(event) {
+}
+
+void V8SamplingThread::ThreadMain() {
+ base::PlatformThread::SetName("V8SamplingProfilerThread");
+ InstallSamplers();
+ StartSamplers();
+ InstallSignalHandler();
+ const int kSamplingFrequencyMicroseconds = 1000;
+ while (!cancellation_flag_.IsSet()) {
+ Sample();
+ if (waitable_event_for_testing_ &&
+ render_thread_sampler_->EventsCollectedForTest()) {
+ waitable_event_for_testing_->Signal();
+ }
+ // TODO(alph): make the samples firing interval not depend on the sample
+ // taking duration.
+ base::PlatformThread::Sleep(
+ base::TimeDelta::FromMicroseconds(kSamplingFrequencyMicroseconds));
+ }
+ RestoreSignalHandler();
+ StopSamplers();
+ RemoveSamplers();
+}
+
+void V8SamplingThread::Sample() {
+ for (Sampler* sampler : samplers_) {
+ sampler->Sample();
+ }
+}
+
+void V8SamplingThread::InstallSamplers() {
+ // Note that the list does not own samplers.
+ samplers_.push_back(render_thread_sampler_);
+ // TODO: add worker samplers.
+}
+
+void V8SamplingThread::RemoveSamplers() {
+ samplers_.clear();
+}
+
+void V8SamplingThread::StartSamplers() {
+ for (Sampler* sampler : samplers_) {
+ sampler->Start();
+ }
+}
+
+void V8SamplingThread::StopSamplers() {
+ for (Sampler* sampler : samplers_) {
+ sampler->Stop();
+ }
+}
+
+// static
+void V8SamplingThread::InstallSignalHandler() {
+#ifdef USE_SIGNALS
+ // There must be the only one!
+ DCHECK(!signal_handler_installed_);
+ struct sigaction sa;
+ sa.sa_sigaction = &HandleProfilerSignal;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESTART | SA_SIGINFO;
+ signal_handler_installed_ =
+ (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
+#endif
+}
+
+// static
+void V8SamplingThread::RestoreSignalHandler() {
+#ifdef USE_SIGNALS
+ if (!signal_handler_installed_)
+ return;
+ sigaction(SIGPROF, &old_signal_handler_, 0);
+ signal_handler_installed_ = false;
+#endif
+}
+
+#ifdef USE_SIGNALS
+// static
+void V8SamplingThread::HandleProfilerSignal(int signal,
+ siginfo_t* info,
+ void* context) {
+ if (signal != SIGPROF)
+ return;
+ ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
+ mcontext_t& mcontext = ucontext->uc_mcontext;
+ v8::RegisterState state;
+
+#if defined(ARCH_CPU_ARM_FAMILY)
+ state.pc = reinterpret_cast<void*>(mcontext.REG_64_32(pc, arm_pc));
+ state.sp = reinterpret_cast<void*>(mcontext.REG_64_32(sp, arm_sp));
+ state.fp = reinterpret_cast<void*>(mcontext.REG_64_32(regs[29], arm_fp));
+
+#elif defined(ARCH_CPU_X86_FAMILY)
+#if defined(OS_MACOSX)
+ state.pc = reinterpret_cast<void*>(mcontext->__ss.REG_64_32(__rip, __eip));
+ state.sp = reinterpret_cast<void*>(mcontext->__ss.REG_64_32(__rsp, __esp));
+ state.fp = reinterpret_cast<void*>(mcontext->__ss.REG_64_32(__rbp, __ebp));
+#else
+ state.pc =
+ reinterpret_cast<void*>(mcontext.gregs[REG_64_32(REG_RIP, REG_EIP)]);
+ state.sp =
+ reinterpret_cast<void*>(mcontext.gregs[REG_64_32(REG_RSP, REG_ESP)]);
+ state.fp =
+ reinterpret_cast<void*>(mcontext.gregs[REG_64_32(REG_RBP, REG_EBP)]);
+#endif // OS_MACOS
+#elif defined(ARCH_CPU_MIPS_FAMILY)
+ state.pc = reinterpret_cast<void*>(mcontext.pc);
+ state.sp = reinterpret_cast<void*>(mcontext.gregs[29]);
+ state.fp = reinterpret_cast<void*>(mcontext.gregs[30]);
+#endif // ARCH_CPU_MIPS_FAMILY
+
+ Sampler::GetInstance()->DoSample(state);
+}
+#endif
+
+void V8SamplingThread::Start() {
+ if (!base::PlatformThread::Create(0, this, &sampling_thread_handle_)) {
+ DCHECK(false) << "failed to create sampling thread";
+ }
+}
+
+void V8SamplingThread::Stop() {
+ cancellation_flag_.Set();
+ base::PlatformThread::Join(sampling_thread_handle_);
+}
+
+V8SamplingProfiler::V8SamplingProfiler(bool underTest)
+ : sampling_thread_(nullptr),
+ render_thread_sampler_(Sampler::CreateForCurrentThread()),
+ message_loop_proxy_(base::MessageLoopProxy::current()) {
+ DCHECK(underTest || RenderThreadImpl::current());
+ // Force the "v8.cpu_profile" category to show up in the trace viewer.
+ TraceLog::GetCategoryGroupEnabled(
+ TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile"));
+ TraceLog::GetInstance()->AddEnabledStateObserver(this);
+}
+
+V8SamplingProfiler::~V8SamplingProfiler() {
+ TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
+ DCHECK(!sampling_thread_.get());
+}
+
+void V8SamplingProfiler::StartSamplingThread() {
+ DCHECK(!sampling_thread_.get());
+ sampling_thread_.reset(new V8SamplingThread(
+ render_thread_sampler_.get(), waitable_event_for_testing_.get()));
+ sampling_thread_->Start();
+}
+
+void V8SamplingProfiler::OnTraceLogEnabled() {
+ bool enabled;
+ TRACE_EVENT_CATEGORY_GROUP_ENABLED(
+ TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile"), &enabled);
+ if (!enabled)
+ return;
+
+ // Do not enable sampling profiler in continuous mode, as losing
+ // Jit code events may not be afforded.
+ // TODO(alph): add support of infinite recording of meta trace events.
+ base::trace_event::TraceRecordMode record_mode =
+ TraceLog::GetInstance()->GetCurrentTraceOptions().record_mode;
+ if (record_mode == base::trace_event::TraceRecordMode::RECORD_CONTINUOUSLY)
+ return;
+
+ message_loop_proxy_->PostTask(
+ FROM_HERE, base::Bind(&V8SamplingProfiler::StartSamplingThread,
+ base::Unretained(this)));
+}
+
+void V8SamplingProfiler::OnTraceLogDisabled() {
+ if (!sampling_thread_.get())
+ return;
+ sampling_thread_->Stop();
+ sampling_thread_.reset();
+}
+
+void V8SamplingProfiler::EnableSamplingEventForTesting(int code_added_events,
+ int sample_events) {
+ render_thread_sampler_->SetEventsToCollectForTest(code_added_events,
+ sample_events);
+ waitable_event_for_testing_.reset(new base::WaitableEvent(false, false));
+}
+
+void V8SamplingProfiler::WaitSamplingEventForTesting() {
+ waitable_event_for_testing_->Wait();
+}
+
+} // namespace blink
diff --git a/chromium/content/renderer/devtools/v8_sampling_profiler.h b/chromium/content/renderer/devtools/v8_sampling_profiler.h
new file mode 100644
index 00000000000..5b7d0949a6f
--- /dev/null
+++ b/chromium/content/renderer/devtools/v8_sampling_profiler.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_RENDERER_DEVTOOLS_V8_SAMPLING_PROFILER_H_
+#define CONTENT_RENDERER_DEVTOOLS_V8_SAMPLING_PROFILER_H_
+
+#include "base/synchronization/waitable_event.h"
+#include "base/trace_event/trace_event_impl.h"
+#include "content/common/content_export.h"
+
+namespace content {
+
+class Sampler;
+class V8SamplingThread;
+
+// The class monitors enablement of V8 CPU profiler and
+// spawns a sampling thread when needed.
+class CONTENT_EXPORT V8SamplingProfiler final
+ : public base::trace_event::TraceLog::EnabledStateObserver {
+ public:
+ explicit V8SamplingProfiler(bool underTest = false);
+ ~V8SamplingProfiler();
+
+ // Implementation of TraceLog::EnabledStateObserver
+ void OnTraceLogEnabled() override;
+ void OnTraceLogDisabled() override;
+
+ void EnableSamplingEventForTesting(int code_added_events, int sample_events);
+ void WaitSamplingEventForTesting();
+
+ private:
+ void StartSamplingThread();
+
+ scoped_ptr<base::WaitableEvent> waitable_event_for_testing_;
+ scoped_ptr<V8SamplingThread> sampling_thread_;
+ scoped_ptr<Sampler> render_thread_sampler_;
+ scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
+
+ DISALLOW_COPY_AND_ASSIGN(V8SamplingProfiler);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_DEVTOOLS_V8_SAMPLING_PROFILER_H_
diff --git a/chromium/content/renderer/devtools/v8_sampling_profiler_browsertest.cc b/chromium/content/renderer/devtools/v8_sampling_profiler_browsertest.cc
new file mode 100644
index 00000000000..eedb97a3653
--- /dev/null
+++ b/chromium/content/renderer/devtools/v8_sampling_profiler_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/json/json_reader.h"
+#include "base/run_loop.h"
+#include "base/trace_event/trace_event.h"
+#include "content/public/test/render_view_test.h"
+#include "content/renderer/devtools/v8_sampling_profiler.h"
+
+using base::DictionaryValue;
+using base::ListValue;
+using base::Value;
+using base::trace_event::CategoryFilter;
+using base::trace_event::TraceLog;
+using base::trace_event::TraceOptions;
+using base::trace_event::TraceResultBuffer;
+
+namespace content {
+
+class V8SamplingProfilerTest : public RenderViewTest {
+ public:
+ void SetUp() override {
+ RenderViewTest::SetUp();
+ sampling_profiler_.reset(new V8SamplingProfiler(true));
+ trace_buffer_.SetOutputCallback(json_output_.GetCallback());
+ }
+
+ void TearDown() override {
+ sampling_profiler_.reset();
+ RenderViewTest::TearDown();
+ }
+
+ void KickV8() { ExecuteJavaScript("1"); }
+
+ void SyncFlush(TraceLog* trace_log) {
+ base::WaitableEvent flush_complete_event(false, false);
+ trace_log->Flush(
+ base::Bind(&V8SamplingProfilerTest::OnTraceDataCollected,
+ base::Unretained(static_cast<V8SamplingProfilerTest*>(this)),
+ base::Unretained(&flush_complete_event)));
+ base::RunLoop().RunUntilIdle();
+ flush_complete_event.Wait();
+ }
+
+ void OnTraceDataCollected(
+ base::WaitableEvent* flush_complete_event,
+ const scoped_refptr<base::RefCountedString>& events_str,
+ bool has_more_events) {
+ base::AutoLock lock(lock_);
+ json_output_.json_output.clear();
+ trace_buffer_.Start();
+ trace_buffer_.AddFragment(events_str->data());
+ trace_buffer_.Finish();
+
+ scoped_ptr<Value> root;
+ root.reset(base::JSONReader::Read(
+ json_output_.json_output,
+ base::JSON_PARSE_RFC | base::JSON_DETACHABLE_CHILDREN));
+
+ if (!root.get()) {
+ LOG(ERROR) << json_output_.json_output;
+ }
+
+ ListValue* root_list = NULL;
+ ASSERT_TRUE(root.get());
+ ASSERT_TRUE(root->GetAsList(&root_list));
+
+ // Move items into our aggregate collection
+ while (root_list->GetSize()) {
+ scoped_ptr<Value> item;
+ root_list->Remove(0, &item);
+ trace_parsed_.Append(item.release());
+ }
+
+ if (!has_more_events)
+ flush_complete_event->Signal();
+ }
+
+ void CollectTrace(int code_added_events, int sample_events) {
+ TraceLog* trace_log = TraceLog::GetInstance();
+ sampling_profiler_->EnableSamplingEventForTesting(code_added_events,
+ sample_events);
+ trace_log->SetEnabled(
+ CategoryFilter(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile")),
+ TraceLog::RECORDING_MODE, TraceOptions());
+ base::RunLoop().RunUntilIdle();
+ KickV8(); // Make a call to V8 so it can invoke interrupt request
+ // callbacks.
+ base::RunLoop().RunUntilIdle();
+ sampling_profiler_->WaitSamplingEventForTesting();
+ trace_log->SetDisabled();
+ SyncFlush(trace_log);
+ }
+
+ int CountEvents(const std::string& name) const {
+ size_t trace_parsed_count = trace_parsed_.GetSize();
+ int events_count = 0;
+ for (size_t i = 0; i < trace_parsed_count; i++) {
+ const DictionaryValue* dict;
+ if (!trace_parsed_.GetDictionary(i, &dict))
+ continue;
+ std::string value;
+ if (!dict->GetString("cat", &value) ||
+ value != TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile"))
+ continue;
+ if (!dict->GetString("name", &value) || value != name)
+ continue;
+ ++events_count;
+ }
+ return events_count;
+ }
+
+ scoped_ptr<V8SamplingProfiler> sampling_profiler_;
+ base::Lock lock_;
+
+ ListValue trace_parsed_;
+ TraceResultBuffer trace_buffer_;
+ TraceResultBuffer::SimpleOutput json_output_;
+};
+
+TEST_F(V8SamplingProfilerTest, V8SamplingEventFired) {
+ sampling_profiler_->EnableSamplingEventForTesting(0, 0);
+ TraceLog::GetInstance()->SetEnabled(
+ CategoryFilter(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile")),
+ TraceLog::RECORDING_MODE, TraceOptions());
+ base::RunLoop().RunUntilIdle();
+ sampling_profiler_->WaitSamplingEventForTesting();
+ TraceLog::GetInstance()->SetDisabled();
+}
+
+TEST_F(V8SamplingProfilerTest, V8SamplingJitCodeEventsCollected) {
+ CollectTrace(1, 0);
+ int jit_code_added_events_count = CountEvents("JitCodeAdded");
+ CHECK_LT(0, jit_code_added_events_count);
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(V8SamplingProfilerTest, V8SamplingSamplesCollected) {
+ CollectTrace(0, 1);
+ int sample_events_count = CountEvents("V8Sample");
+ CHECK_LT(0, sample_events_count);
+ base::RunLoop().RunUntilIdle();
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/disambiguation_popup_helper.cc b/chromium/content/renderer/disambiguation_popup_helper.cc
index 9fff7b9b99c..de17eb2289b 100644
--- a/chromium/content/renderer/disambiguation_popup_helper.cc
+++ b/chromium/content/renderer/disambiguation_popup_helper.cc
@@ -5,7 +5,7 @@
#include "content/renderer/disambiguation_popup_helper.h"
#include "third_party/WebKit/public/platform/WebRect.h"
-#include "ui/gfx/size_conversions.h"
+#include "ui/gfx/geometry/size_conversions.h"
using blink::WebRect;
using blink::WebVector;
diff --git a/chromium/content/renderer/disambiguation_popup_helper_unittest.cc b/chromium/content/renderer/disambiguation_popup_helper_unittest.cc
index 8cbbe4b5ab3..5921e308200 100644
--- a/chromium/content/renderer/disambiguation_popup_helper_unittest.cc
+++ b/chromium/content/renderer/disambiguation_popup_helper_unittest.cc
@@ -7,9 +7,9 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/public/platform/WebRect.h"
#include "third_party/WebKit/public/platform/WebVector.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/size.h"
-#include "ui/gfx/size_conversions.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/geometry/size_conversions.h"
// these constants are copied from the implementation class
namespace {
diff --git a/chromium/content/renderer/dom_automation_controller.cc b/chromium/content/renderer/dom_automation_controller.cc
index 13191d8bee6..f11454425b0 100644
--- a/chromium/content/renderer/dom_automation_controller.cc
+++ b/chromium/content/renderer/dom_automation_controller.cc
@@ -6,10 +6,10 @@
#include "base/json/json_string_value_serializer.h"
#include "base/strings/string_util.h"
+#include "content/child/v8_value_converter_impl.h"
#include "content/common/child_process_messages.h"
#include "content/common/frame_messages.h"
#include "content/renderer/render_view_impl.h"
-#include "content/renderer/v8_value_converter_impl.h"
#include "gin/handle.h"
#include "gin/object_template_builder.h"
#include "third_party/WebKit/public/web/WebFrame.h"
@@ -25,7 +25,7 @@ void DomAutomationController::Install(RenderFrame* render_frame,
blink::WebFrame* frame) {
v8::Isolate* isolate = blink::mainThreadIsolate();
v8::HandleScope handle_scope(isolate);
- v8::Handle<v8::Context> context = frame->mainWorldScriptContext();
+ v8::Local<v8::Context> context = frame->mainWorldScriptContext();
if (context.IsEmpty())
return;
@@ -36,7 +36,7 @@ void DomAutomationController::Install(RenderFrame* render_frame,
if (controller.IsEmpty())
return;
- v8::Handle<v8::Object> global = context->Global();
+ v8::Local<v8::Object> global = context->Global();
global->Set(gin::StringToV8(isolate, "domAutomationController"),
controller.ToV8());
}
diff --git a/chromium/content/renderer/dom_serializer_browsertest.cc b/chromium/content/renderer/dom_serializer_browsertest.cc
index 1bcd2bd0ddb..2cb395c18da 100644
--- a/chromium/content/renderer/dom_serializer_browsertest.cc
+++ b/chromium/content/renderer/dom_serializer_browsertest.cc
@@ -170,7 +170,7 @@ class DomSerializerTests : public ContentBrowserTest,
: serialized_(false),
local_directory_name_(FILE_PATH_LITERAL("./dummy_files/")) {}
- void SetUpCommandLine(CommandLine* command_line) override {
+ void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitch(switches::kSingleProcess);
#if defined(OS_WIN)
// Don't want to try to create a GPU process.
@@ -582,8 +582,9 @@ class DomSerializerTests : public ContentBrowserTest,
'%', 0x2285, 0x00b9, '\'', 0
};
WebString value = body_element.getAttribute("title");
+ WebString content = doc.contentAsTextForTesting();
ASSERT_TRUE(base::UTF16ToWide(value) == parsed_value);
- ASSERT_TRUE(base::UTF16ToWide(body_element.innerText()) == parsed_value);
+ ASSERT_TRUE(base::UTF16ToWide(content) == parsed_value);
// Do serialization.
SerializeDomForURL(file_url, false);
diff --git a/chromium/content/renderer/dom_storage/dom_storage_cached_area.cc b/chromium/content/renderer/dom_storage/dom_storage_cached_area.cc
index 2923fcb1def..a01d3c6f7fb 100644
--- a/chromium/content/renderer/dom_storage/dom_storage_cached_area.cc
+++ b/chromium/content/renderer/dom_storage/dom_storage_cached_area.cc
@@ -12,12 +12,6 @@
namespace content {
-namespace {
-
-static const int kMaxLogGetMessagesToSend = 16 * 1024;
-
-} // namespace
-
DOMStorageCachedArea::DOMStorageCachedArea(int64 namespace_id,
const GURL& origin,
DOMStorageProxy* proxy)
@@ -25,7 +19,6 @@ DOMStorageCachedArea::DOMStorageCachedArea(int64 namespace_id,
namespace_id_(namespace_id),
origin_(origin),
proxy_(proxy),
- remaining_log_get_messages_(0),
weak_factory_(this) {}
DOMStorageCachedArea::~DOMStorageCachedArea() {}
@@ -45,12 +38,7 @@ base::NullableString16 DOMStorageCachedArea::GetItem(
int connection_id,
const base::string16& key) {
PrimeIfNeeded(connection_id);
- base::NullableString16 result = map_->GetItem(key);
- if (remaining_log_get_messages_ > 0) {
- remaining_log_get_messages_--;
- proxy_->LogGetItem(connection_id, key, result);
- }
- return result;
+ return map_->GetItem(key);
}
bool DOMStorageCachedArea::SetItem(int connection_id,
@@ -167,11 +155,9 @@ void DOMStorageCachedArea::Prime(int connection_id) {
// Ignore all mutations until OnLoadComplete time.
ignore_all_mutations_ = true;
DOMStorageValuesMap values;
- bool send_log_get_messages = false;
base::TimeTicks before = base::TimeTicks::Now();
proxy_->LoadArea(connection_id,
&values,
- &send_log_get_messages,
base::Bind(&DOMStorageCachedArea::OnLoadComplete,
weak_factory_.GetWeakPtr()));
base::TimeDelta time_to_prime = base::TimeTicks::Now() - before;
@@ -181,8 +167,6 @@ void DOMStorageCachedArea::Prime(int connection_id) {
time_to_prime);
map_ = new DOMStorageMap(kPerStorageAreaQuota);
map_->SwapValues(&values);
- if (send_log_get_messages)
- remaining_log_get_messages_ = kMaxLogGetMessagesToSend;
size_t local_storage_size_kb = map_->bytes_used() / 1024;
// Track localStorage size, from 0-6MB. Note that the maximum size should be
diff --git a/chromium/content/renderer/dom_storage/dom_storage_cached_area.h b/chromium/content/renderer/dom_storage/dom_storage_cached_area.h
index 6942534cf87..b9910388553 100644
--- a/chromium/content/renderer/dom_storage/dom_storage_cached_area.h
+++ b/chromium/content/renderer/dom_storage/dom_storage_cached_area.h
@@ -51,9 +51,6 @@ class CONTENT_EXPORT DOMStorageCachedArea
size_t MemoryBytesUsedByCache() const;
- // Resets the object back to its newly constructed state.
- void Reset();
-
private:
friend class DOMStorageCachedAreaTest;
friend class base::RefCounted<DOMStorageCachedArea>;
@@ -66,6 +63,9 @@ class CONTENT_EXPORT DOMStorageCachedArea
Prime(connection_id);
}
+ // Resets the object back to its newly constructed state.
+ void Reset();
+
// Async completion callbacks for proxied operations.
// These are used to maintain cache consistency by preventing
// mutation events from other processes from overwriting local
@@ -86,11 +86,6 @@ class CONTENT_EXPORT DOMStorageCachedArea
GURL origin_;
scoped_refptr<DOMStorageMap> map_;
scoped_refptr<DOMStorageProxy> proxy_;
- // Sometimes, we need to send messages to the browser for each get access,
- // for logging purposes. However, we only do this for a fixed maximum number
- // of gets. Here, we keep track of how many remaining get log messages we
- // need to send.
- int remaining_log_get_messages_;
base::WeakPtrFactory<DOMStorageCachedArea> weak_factory_;
};
diff --git a/chromium/content/renderer/dom_storage/dom_storage_cached_area_unittest.cc b/chromium/content/renderer/dom_storage/dom_storage_cached_area_unittest.cc
index f17f5fed01e..631a281431f 100644
--- a/chromium/content/renderer/dom_storage/dom_storage_cached_area_unittest.cc
+++ b/chromium/content/renderer/dom_storage/dom_storage_cached_area_unittest.cc
@@ -25,13 +25,11 @@ class MockProxy : public DOMStorageProxy {
void LoadArea(int connection_id,
DOMStorageValuesMap* values,
- bool* send_log_get_messages,
const CompletionCallback& callback) override {
pending_callbacks_.push_back(callback);
observed_load_area_ = true;
observed_connection_id_ = connection_id;
*values = load_area_return_values_;
- *send_log_get_messages = false;
}
void SetItem(int connection_id,
@@ -47,10 +45,6 @@ class MockProxy : public DOMStorageProxy {
observed_page_url_ = page_url;
}
- void LogGetItem(int connection_id,
- const base::string16& key,
- const base::NullableString16& value) override {}
-
void RemoveItem(int connection_id,
const base::string16& key,
const GURL& page_url,
diff --git a/chromium/content/renderer/dom_storage/dom_storage_dispatcher.cc b/chromium/content/renderer/dom_storage/dom_storage_dispatcher.cc
index 94332709d40..a4d877f715f 100644
--- a/chromium/content/renderer/dom_storage/dom_storage_dispatcher.cc
+++ b/chromium/content/renderer/dom_storage/dom_storage_dispatcher.cc
@@ -104,23 +104,18 @@ class DomStorageDispatcher::ProxyImpl : public DOMStorageProxy {
void CloseCachedArea(DOMStorageCachedArea* area);
DOMStorageCachedArea* LookupCachedArea(
int64 namespace_id, const GURL& origin);
- void ResetAllCachedAreas(int64 namespace_id);
void CompleteOnePendingCallback(bool success);
void Shutdown();
// DOMStorageProxy interface for use by DOMStorageCachedArea.
void LoadArea(int connection_id,
DOMStorageValuesMap* values,
- bool* send_log_get_messages,
const CompletionCallback& callback) override;
void SetItem(int connection_id,
const base::string16& key,
const base::string16& value,
const GURL& page_url,
const CompletionCallback& callback) override;
- void LogGetItem(int connection_id,
- const base::string16& key,
- const base::NullableString16& value) override;
void RemoveItem(int connection_id,
const base::string16& key,
const GURL& page_url,
@@ -135,11 +130,9 @@ class DomStorageDispatcher::ProxyImpl : public DOMStorageProxy {
struct CachedAreaHolder {
scoped_refptr<DOMStorageCachedArea> area_;
int open_count_;
- int64 namespace_id_;
CachedAreaHolder() : open_count_(0) {}
- CachedAreaHolder(DOMStorageCachedArea* area, int count,
- int64 namespace_id)
- : area_(area), open_count_(count), namespace_id_(namespace_id) {}
+ CachedAreaHolder(DOMStorageCachedArea* area, int count)
+ : area_(area), open_count_(count) {}
};
typedef std::map<std::string, CachedAreaHolder> CachedAreaMap;
typedef std::list<CompletionCallback> CallbackList;
@@ -194,7 +187,7 @@ DOMStorageCachedArea* DomStorageDispatcher::ProxyImpl::OpenCachedArea(
}
scoped_refptr<DOMStorageCachedArea> area =
new DOMStorageCachedArea(namespace_id, origin, this);
- cached_areas_[key] = CachedAreaHolder(area.get(), 1, namespace_id);
+ cached_areas_[key] = CachedAreaHolder(area.get(), 1);
return area.get();
}
@@ -219,15 +212,6 @@ DOMStorageCachedArea* DomStorageDispatcher::ProxyImpl::LookupCachedArea(
return holder->area_.get();
}
-void DomStorageDispatcher::ProxyImpl::ResetAllCachedAreas(int64 namespace_id) {
- for (CachedAreaMap::iterator it = cached_areas_.begin();
- it != cached_areas_.end();
- ++it) {
- if (it->second.namespace_id_ == namespace_id)
- it->second.area_->Reset();
- }
-}
-
void DomStorageDispatcher::ProxyImpl::CompleteOnePendingCallback(bool success) {
PopPendingCallback().Run(success);
}
@@ -241,11 +225,11 @@ void DomStorageDispatcher::ProxyImpl::Shutdown() {
}
void DomStorageDispatcher::ProxyImpl::LoadArea(
- int connection_id, DOMStorageValuesMap* values, bool* send_log_get_messages,
+ int connection_id, DOMStorageValuesMap* values,
const CompletionCallback& callback) {
PushPendingCallback(callback);
throttling_filter_->SendThrottled(new DOMStorageHostMsg_LoadStorageArea(
- connection_id, values, send_log_get_messages));
+ connection_id, values));
}
void DomStorageDispatcher::ProxyImpl::SetItem(
@@ -257,12 +241,6 @@ void DomStorageDispatcher::ProxyImpl::SetItem(
connection_id, key, value, page_url));
}
-void DomStorageDispatcher::ProxyImpl::LogGetItem(
- int connection_id, const base::string16& key,
- const base::NullableString16& value) {
- sender_->Send(new DOMStorageHostMsg_LogGetItem(connection_id, key, value));
-}
-
void DomStorageDispatcher::ProxyImpl::RemoveItem(
int connection_id, const base::string16& key, const GURL& page_url,
const CompletionCallback& callback) {
@@ -310,8 +288,6 @@ bool DomStorageDispatcher::OnMessageReceived(const IPC::Message& msg) {
IPC_MESSAGE_HANDLER(DOMStorageMsg_Event, OnStorageEvent)
IPC_MESSAGE_HANDLER(DOMStorageMsg_AsyncOperationComplete,
OnAsyncOperationComplete)
- IPC_MESSAGE_HANDLER(DOMStorageMsg_ResetCachedValues,
- OnResetCachedValues)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
@@ -361,8 +337,4 @@ void DomStorageDispatcher::OnAsyncOperationComplete(bool success) {
proxy_->CompleteOnePendingCallback(success);
}
-void DomStorageDispatcher::OnResetCachedValues(int64 namespace_id) {
- proxy_->ResetAllCachedAreas(namespace_id);
-}
-
} // namespace content
diff --git a/chromium/content/renderer/dom_storage/dom_storage_dispatcher.h b/chromium/content/renderer/dom_storage/dom_storage_dispatcher.h
index 70595ca12fd..f395d575f5c 100644
--- a/chromium/content/renderer/dom_storage/dom_storage_dispatcher.h
+++ b/chromium/content/renderer/dom_storage/dom_storage_dispatcher.h
@@ -42,7 +42,6 @@ class DomStorageDispatcher {
// IPC message handlers
void OnStorageEvent(const DOMStorageMsg_Event_Params& params);
void OnAsyncOperationComplete(bool success);
- void OnResetCachedValues(int64 namespace_id);
scoped_refptr<ProxyImpl> proxy_;
};
diff --git a/chromium/content/renderer/dom_storage/dom_storage_proxy.h b/chromium/content/renderer/dom_storage/dom_storage_proxy.h
index 118aab34da3..80cd87cdcc4 100644
--- a/chromium/content/renderer/dom_storage/dom_storage_proxy.h
+++ b/chromium/content/renderer/dom_storage/dom_storage_proxy.h
@@ -21,7 +21,6 @@ class DOMStorageProxy : public base::RefCounted<DOMStorageProxy> {
virtual void LoadArea(int connection_id,
DOMStorageValuesMap* values,
- bool* send_log_get_messages,
const CompletionCallback& callback) = 0;
virtual void SetItem(int connection_id,
@@ -30,10 +29,6 @@ class DOMStorageProxy : public base::RefCounted<DOMStorageProxy> {
const GURL& page_url,
const CompletionCallback& callback) = 0;
- virtual void LogGetItem(int connection_id,
- const base::string16& key,
- const base::NullableString16& value) = 0;
-
virtual void RemoveItem(int connection_id,
const base::string16& key,
const GURL& page_url,
diff --git a/chromium/content/renderer/external_popup_menu.cc b/chromium/content/renderer/external_popup_menu.cc
index 3a635e528d3..f2363e31b53 100644
--- a/chromium/content/renderer/external_popup_menu.cc
+++ b/chromium/content/renderer/external_popup_menu.cc
@@ -23,7 +23,7 @@ ExternalPopupMenu::ExternalPopupMenu(
}
void ExternalPopupMenu::SetOriginScaleAndOffsetForEmulation(
- float scale, const gfx::Point& offset) {
+ float scale, const gfx::PointF& offset) {
origin_scale_for_emulation_ = scale;
origin_offset_for_emulation_ = offset;
}
diff --git a/chromium/content/renderer/external_popup_menu.h b/chromium/content/renderer/external_popup_menu.h
index 06e3715d185..ccd4fdc3185 100644
--- a/chromium/content/renderer/external_popup_menu.h
+++ b/chromium/content/renderer/external_popup_menu.h
@@ -10,7 +10,7 @@
#include "base/basictypes.h"
#include "third_party/WebKit/public/web/WebExternalPopupMenu.h"
#include "third_party/WebKit/public/web/WebPopupMenuInfo.h"
-#include "ui/gfx/point.h"
+#include "ui/gfx/geometry/point_f.h"
namespace blink {
class WebExternalPopupMenuClient;
@@ -28,7 +28,7 @@ class ExternalPopupMenu : public blink::WebExternalPopupMenu {
virtual ~ExternalPopupMenu() {}
void SetOriginScaleAndOffsetForEmulation(
- float scale, const gfx::Point& offset);
+ float scale, const gfx::PointF& offset);
#if defined(OS_MACOSX)
// Called when the user has selected an item. |selected_item| is -1 if the
@@ -53,7 +53,7 @@ class ExternalPopupMenu : public blink::WebExternalPopupMenu {
// Popups may be displaced when screen metrics emulation is enabled.
// These scale and offset are used to properly adjust popup position.
float origin_scale_for_emulation_;
- gfx::Point origin_offset_for_emulation_;
+ gfx::PointF origin_offset_for_emulation_;
DISALLOW_COPY_AND_ASSIGN(ExternalPopupMenu);
};
diff --git a/chromium/content/renderer/external_popup_menu_browsertest.cc b/chromium/content/renderer/external_popup_menu_browsertest.cc
index cadb51ffda6..0cd2ddb7b2e 100644
--- a/chromium/content/renderer/external_popup_menu_browsertest.cc
+++ b/chromium/content/renderer/external_popup_menu_browsertest.cc
@@ -33,7 +33,7 @@ class ExternalPopupMenuTest : public RenderViewTest {
return view()->GetMainRenderFrame();
}
- virtual void SetUp() {
+ void SetUp() override {
RenderViewTest::SetUp();
// We need to set this explictly as RenderMain is not run.
blink::WebView::setUseExternalPopupMenus(true);
@@ -86,10 +86,10 @@ TEST_F(ExternalPopupMenuTest, NormalCase) {
const IPC::Message* message =
sink.GetUniqueMessageMatching(FrameHostMsg_ShowPopup::ID);
ASSERT_TRUE(message != NULL);
- Tuple1<FrameHostMsg_ShowPopup_Params> param;
+ Tuple<FrameHostMsg_ShowPopup_Params> param;
FrameHostMsg_ShowPopup::Read(message, &param);
- ASSERT_EQ(3U, param.a.popup_items.size());
- EXPECT_EQ(1, param.a.selected_item);
+ ASSERT_EQ(3U, get<0>(param).popup_items.size());
+ EXPECT_EQ(1, get<0>(param).selected_item);
// Simulate the user canceling the popup; the index should not have changed.
frame()->OnSelectPopupMenuItem(-1);
@@ -106,8 +106,8 @@ TEST_F(ExternalPopupMenuTest, NormalCase) {
message = sink.GetUniqueMessageMatching(FrameHostMsg_ShowPopup::ID);
ASSERT_TRUE(message != NULL);
FrameHostMsg_ShowPopup::Read(message, &param);
- ASSERT_EQ(3U, param.a.popup_items.size());
- EXPECT_EQ(0, param.a.selected_item);
+ ASSERT_EQ(3U, get<0>(param).popup_items.size());
+ EXPECT_EQ(0, get<0>(param).selected_item);
}
// Page shows popup, then navigates away while popup showing, then select.
@@ -154,7 +154,7 @@ class ExternalPopupMenuDisplayNoneTest : public ExternalPopupMenuTest {
public:
ExternalPopupMenuDisplayNoneTest() {}
- virtual void SetUp() {
+ void SetUp() override {
RenderViewTest::SetUp();
// We need to set this explictly as RenderMain is not run.
blink::WebView::setUseExternalPopupMenus(true);
@@ -189,11 +189,11 @@ TEST_F(ExternalPopupMenuDisplayNoneTest, SelectItem) {
const IPC::Message* message =
sink.GetUniqueMessageMatching(FrameHostMsg_ShowPopup::ID);
ASSERT_TRUE(message != NULL);
- Tuple1<FrameHostMsg_ShowPopup_Params> param;
+ Tuple<FrameHostMsg_ShowPopup_Params> param;
FrameHostMsg_ShowPopup::Read(message, &param);
// Number of items should match item count minus the number
// of "display: none" items.
- ASSERT_EQ(5U, param.a.popup_items.size());
+ ASSERT_EQ(5U, get<0>(param).popup_items.size());
// Select index 1 item. This should select item with index 2,
// skipping the item with 'display: none'
diff --git a/chromium/content/renderer/fetchers/image_resource_fetcher.cc b/chromium/content/renderer/fetchers/image_resource_fetcher.cc
deleted file mode 100644
index ec0798ba86d..00000000000
--- a/chromium/content/renderer/fetchers/image_resource_fetcher.cc
+++ /dev/null
@@ -1,69 +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/renderer/fetchers/image_resource_fetcher.h"
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/debug/crash_logging.h"
-#include "content/child/image_decoder.h"
-#include "content/public/renderer/resource_fetcher.h"
-#include "third_party/WebKit/public/platform/WebURLResponse.h"
-#include "third_party/WebKit/public/web/WebFrame.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/gfx/size.h"
-
-using blink::WebFrame;
-using blink::WebURLRequest;
-using blink::WebURLResponse;
-
-namespace content {
-
-ImageResourceFetcher::ImageResourceFetcher(
- const GURL& image_url,
- WebFrame* frame,
- int id,
- int image_size,
- WebURLRequest::RequestContext request_context,
- const Callback& callback)
- : callback_(callback),
- id_(id),
- image_url_(image_url),
- image_size_(image_size) {
- fetcher_.reset(ResourceFetcher::Create(image_url));
- fetcher_->Start(frame,
- request_context,
- WebURLRequest::FrameTypeNone,
- ResourceFetcher::PLATFORM_LOADER,
- base::Bind(&ImageResourceFetcher::OnURLFetchComplete,
- base::Unretained(this)));
-
- // Set subresource URL for crash reporting.
- base::debug::SetCrashKeyValue("subresource_url", image_url.spec());
-}
-
-ImageResourceFetcher::~ImageResourceFetcher() {
-}
-
-void ImageResourceFetcher::OnURLFetchComplete(
- const WebURLResponse& response,
- const std::string& data) {
- SkBitmap bitmap;
- if (!response.isNull() && response.httpStatusCode() == 200) {
- // Request succeeded, try to convert it to an image.
- ImageDecoder decoder(gfx::Size(image_size_, image_size_));
- bitmap = decoder.Decode(
- reinterpret_cast<const unsigned char*>(data.data()), data.size());
- } // else case:
- // If we get here, it means no image from server or couldn't decode the
- // response as an image. The delegate will see a null image, indicating
- // that an error occurred.
-
- // Take a reference to the callback as running the callback may lead to our
- // destruction.
- Callback callback = callback_;
- callback.Run(this, bitmap);
-}
-
-} // namespace content
diff --git a/chromium/content/renderer/fetchers/image_resource_fetcher.h b/chromium/content/renderer/fetchers/image_resource_fetcher.h
deleted file mode 100644
index eca62af3e5e..00000000000
--- a/chromium/content/renderer/fetchers/image_resource_fetcher.h
+++ /dev/null
@@ -1,73 +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_RENDERER_FETCHERS_IMAGE_RESOURCE_FETCHER_H_
-#define CONTENT_RENDERER_FETCHERS_IMAGE_RESOURCE_FETCHER_H_
-
-#include "base/basictypes.h"
-#include "base/callback.h"
-#include "base/memory/scoped_ptr.h"
-#include "third_party/WebKit/public/platform/WebURLRequest.h"
-#include "url/gurl.h"
-
-class SkBitmap;
-
-namespace blink {
-class WebFrame;
-class WebURLResponse;
-}
-
-namespace content {
-
-class ResourceFetcher;
-
-// ImageResourceFetcher handles downloading an image for a webview. Once
-// downloading is done the supplied callback is notified. ImageResourceFetcher
-// is used to download the favicon and images for web apps.
-class ImageResourceFetcher {
- public:
- typedef base::Callback<void(ImageResourceFetcher*, const SkBitmap&)> Callback;
-
- ImageResourceFetcher(const GURL& image_url,
- blink::WebFrame* frame,
- int id,
- int image_size,
- blink::WebURLRequest::RequestContext request_context,
- const Callback& callback);
-
- virtual ~ImageResourceFetcher();
-
- // URL of the image we're downloading.
- const GURL& image_url() const { return image_url_; }
-
- // Unique identifier for the request.
- int id() const { return id_; }
-
- private:
- // ResourceFetcher::Callback. Decodes the image and invokes callback_.
- void OnURLFetchComplete(const blink::WebURLResponse& response,
- const std::string& data);
-
- Callback callback_;
-
- // Unique identifier for the request.
- const int id_;
-
- // URL of the image.
- const GURL image_url_;
-
- // The size of the image. This is only a hint that is used if the image
- // contains multiple sizes. A value of 0 results in using the first frame
- // of the image.
- const int image_size_;
-
- // Does the actual download.
- scoped_ptr<ResourceFetcher> fetcher_;
-
- DISALLOW_COPY_AND_ASSIGN(ImageResourceFetcher);
-};
-
-} // namespace content
-
-#endif // CONTENT_RENDERER_FETCHERS_IMAGE_RESOURCE_FETCHER_H_
diff --git a/chromium/content/renderer/fetchers/manifest_fetcher.cc b/chromium/content/renderer/fetchers/manifest_fetcher.cc
index c6a64c84f87..ba0cf3a6e34 100644
--- a/chromium/content/renderer/fetchers/manifest_fetcher.cc
+++ b/chromium/content/renderer/fetchers/manifest_fetcher.cc
@@ -24,6 +24,12 @@ ManifestFetcher::~ManifestFetcher() {
void ManifestFetcher::Start(blink::WebFrame* frame, const Callback& callback) {
callback_ = callback;
+
+ blink::WebURLLoaderOptions options;
+ options.crossOriginRequestPolicy =
+ blink::WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl;
+ fetcher_->SetLoaderOptions(options);
+
fetcher_->Start(frame,
blink::WebURLRequest::RequestContextManifest,
blink::WebURLRequest::FrameTypeNone,
diff --git a/chromium/content/renderer/fetchers/manifest_fetcher.h b/chromium/content/renderer/fetchers/manifest_fetcher.h
index daa8f0a7bac..8b83b3aa1bf 100644
--- a/chromium/content/renderer/fetchers/manifest_fetcher.h
+++ b/chromium/content/renderer/fetchers/manifest_fetcher.h
@@ -54,4 +54,4 @@ class CONTENT_EXPORT ManifestFetcher {
} // namespace content
-#endif // CONTENT_RENDERER_FETCHERS_MANIFEST_FETCHER_H_
+#endif // CONTENT_RENDERER_FETCHERS_MANIFEST_FETCHER_H_
diff --git a/chromium/content/renderer/fetchers/multi_resolution_image_resource_fetcher.cc b/chromium/content/renderer/fetchers/multi_resolution_image_resource_fetcher.cc
index d310f423cfe..fa88aa9e711 100644
--- a/chromium/content/renderer/fetchers/multi_resolution_image_resource_fetcher.cc
+++ b/chromium/content/renderer/fetchers/multi_resolution_image_resource_fetcher.cc
@@ -10,10 +10,12 @@
#include "content/public/renderer/resource_fetcher.h"
#include "third_party/WebKit/public/platform/WebURLResponse.h"
#include "third_party/WebKit/public/web/WebFrame.h"
+#include "third_party/WebKit/public/web/WebURLLoaderOptions.h"
#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/gfx/size.h"
+#include "ui/gfx/geometry/size.h"
using blink::WebFrame;
+using blink::WebURLLoaderOptions;
using blink::WebURLRequest;
using blink::WebURLResponse;
@@ -24,17 +26,33 @@ MultiResolutionImageResourceFetcher::MultiResolutionImageResourceFetcher(
WebFrame* frame,
int id,
WebURLRequest::RequestContext request_context,
+ blink::WebURLRequest::CachePolicy cache_policy,
const Callback& callback)
: callback_(callback),
id_(id),
http_status_code_(0),
image_url_(image_url) {
fetcher_.reset(ResourceFetcher::Create(image_url));
+
+ WebURLLoaderOptions options;
+ options.allowCredentials = true;
+ options.crossOriginRequestPolicy =
+ WebURLLoaderOptions::CrossOriginRequestPolicyAllow;
+ fetcher_->SetLoaderOptions(options);
+
+ // To prevent cache tainting, the favicon requests have to by-pass the service
+ // workers. This should ideally not happen or at least not all the time.
+ // See https://crbug.com/448427
+ if (request_context == WebURLRequest::RequestContextFavicon)
+ fetcher_->SetSkipServiceWorker(true);
+
+ fetcher_->SetCachePolicy(cache_policy);
+
fetcher_->Start(
frame,
request_context,
WebURLRequest::FrameTypeNone,
- ResourceFetcher::PLATFORM_LOADER,
+ ResourceFetcher::FRAME_ASSOCIATED_LOADER,
base::Bind(&MultiResolutionImageResourceFetcher::OnURLFetchComplete,
base::Unretained(this)));
}
diff --git a/chromium/content/renderer/fetchers/multi_resolution_image_resource_fetcher.h b/chromium/content/renderer/fetchers/multi_resolution_image_resource_fetcher.h
index c968a87f12e..de44acef7d5 100644
--- a/chromium/content/renderer/fetchers/multi_resolution_image_resource_fetcher.h
+++ b/chromium/content/renderer/fetchers/multi_resolution_image_resource_fetcher.h
@@ -37,6 +37,7 @@ class MultiResolutionImageResourceFetcher {
blink::WebFrame* frame,
int id,
blink::WebURLRequest::RequestContext request_context,
+ blink::WebURLRequest::CachePolicy cache_policy,
const Callback& callback);
virtual ~MultiResolutionImageResourceFetcher();
diff --git a/chromium/content/renderer/fetchers/resource_fetcher_impl.cc b/chromium/content/renderer/fetchers/resource_fetcher_impl.cc
index c175abcd79a..e296937f13e 100644
--- a/chromium/content/renderer/fetchers/resource_fetcher_impl.cc
+++ b/chromium/content/renderer/fetchers/resource_fetcher_impl.cc
@@ -9,8 +9,8 @@
#include "base/time/time.h"
#include "third_party/WebKit/public/platform/Platform.h"
#include "third_party/WebKit/public/platform/WebHTTPBody.h"
+#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/platform/WebURL.h"
-#include "third_party/WebKit/public/platform/WebURLError.h"
#include "third_party/WebKit/public/platform/WebURLLoader.h"
#include "third_party/WebKit/public/platform/WebURLRequest.h"
#include "third_party/WebKit/public/web/WebDocument.h"
@@ -18,15 +18,6 @@
#include "third_party/WebKit/public/web/WebKit.h"
#include "third_party/WebKit/public/web/WebSecurityPolicy.h"
-using base::TimeDelta;
-using blink::WebFrame;
-using blink::WebHTTPBody;
-using blink::WebSecurityPolicy;
-using blink::WebURLError;
-using blink::WebURLLoader;
-using blink::WebURLRequest;
-using blink::WebURLResponse;
-
namespace content {
// static
@@ -54,7 +45,7 @@ void ResourceFetcherImpl::SetBody(const std::string& body) {
DCHECK(!request_.isNull());
DCHECK(!loader_);
- WebHTTPBody web_http_body;
+ blink::WebHTTPBody web_http_body;
web_http_body.initialize();
web_http_body.appendData(blink::WebData(body));
request_.setHTTPBody(web_http_body);
@@ -66,10 +57,11 @@ void ResourceFetcherImpl::SetHeader(const std::string& header,
DCHECK(!loader_);
if (LowerCaseEqualsASCII(header, "referer")) {
- blink::WebString referrer = WebSecurityPolicy::generateReferrerHeader(
- blink::WebReferrerPolicyDefault,
- request_.url(),
- blink::WebString::fromUTF8(value));
+ blink::WebString referrer =
+ blink::WebSecurityPolicy::generateReferrerHeader(
+ blink::WebReferrerPolicyDefault,
+ request_.url(),
+ blink::WebString::fromUTF8(value));
request_.setHTTPReferrer(referrer, blink::WebReferrerPolicyDefault);
} else {
request_.setHTTPHeaderField(blink::WebString::fromUTF8(header),
@@ -77,11 +69,35 @@ void ResourceFetcherImpl::SetHeader(const std::string& header,
}
}
-void ResourceFetcherImpl::Start(WebFrame* frame,
- WebURLRequest::RequestContext request_context,
- WebURLRequest::FrameType frame_type,
- LoaderType loader_type,
- const Callback& callback) {
+void ResourceFetcherImpl::SetSkipServiceWorker(bool skip_service_worker) {
+ DCHECK(!request_.isNull());
+ DCHECK(!loader_);
+
+ request_.setSkipServiceWorker(skip_service_worker);
+}
+
+void ResourceFetcherImpl::SetCachePolicy(
+ blink::WebURLRequest::CachePolicy policy) {
+ DCHECK(!request_.isNull());
+ DCHECK(!loader_);
+
+ request_.setCachePolicy(policy);
+}
+
+void ResourceFetcherImpl::SetLoaderOptions(
+ const blink::WebURLLoaderOptions& options) {
+ DCHECK(!request_.isNull());
+ DCHECK(!loader_);
+
+ options_ = options;
+}
+
+void ResourceFetcherImpl::Start(
+ blink::WebFrame* frame,
+ blink::WebURLRequest::RequestContext request_context,
+ blink::WebURLRequest::FrameType frame_type,
+ LoaderType loader_type,
+ const Callback& callback) {
DCHECK(!loader_);
DCHECK(!request_.isNull());
DCHECK(callback_.is_null());
@@ -101,7 +117,7 @@ void ResourceFetcherImpl::Start(WebFrame* frame,
loader_.reset(blink::Platform::current()->createURLLoader());
break;
case FRAME_ASSOCIATED_LOADER:
- loader_.reset(frame->createAssociatedURLLoader());
+ loader_.reset(frame->createAssociatedURLLoader(options_));
break;
}
loader_->loadAsynchronously(request_, this);
diff --git a/chromium/content/renderer/fetchers/resource_fetcher_impl.h b/chromium/content/renderer/fetchers/resource_fetcher_impl.h
index 8064c1a2809..4e22ff02371 100644
--- a/chromium/content/renderer/fetchers/resource_fetcher_impl.h
+++ b/chromium/content/renderer/fetchers/resource_fetcher_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_RENDERER_FETCHERS_RESOURCE_FETCHER_H_
-#define CONTENT_RENDERER_FETCHERS_RESOURCE_FETCHER_H_
+#ifndef CONTENT_RENDERER_FETCHERS_RESOURCE_FETCHER_IMPL_H_
+#define CONTENT_RENDERER_FETCHERS_RESOURCE_FETCHER_IMPL_H_
#include <string>
@@ -16,13 +16,13 @@
#include "content/renderer/fetchers/web_url_loader_client_impl.h"
#include "third_party/WebKit/public/platform/WebURLRequest.h"
#include "third_party/WebKit/public/platform/WebURLResponse.h"
+#include "third_party/WebKit/public/web/WebURLLoaderOptions.h"
class GURL;
namespace blink {
class WebFrame;
class WebURLLoader;
-struct WebURLError;
}
namespace content {
@@ -34,6 +34,9 @@ class ResourceFetcherImpl : public ResourceFetcher,
void SetMethod(const std::string& method) override;
void SetBody(const std::string& body) override;
void SetHeader(const std::string& header, const std::string& value) override;
+ void SetSkipServiceWorker(bool skip_service_worker) override;
+ void SetCachePolicy(blink::WebURLRequest::CachePolicy policy) override;
+ void SetLoaderOptions(const blink::WebURLLoaderOptions& options) override;
void Start(blink::WebFrame* frame,
blink::WebURLRequest::RequestContext request_context,
blink::WebURLRequest::FrameType frame_type,
@@ -58,6 +61,9 @@ class ResourceFetcherImpl : public ResourceFetcher,
scoped_ptr<blink::WebURLLoader> loader_;
+ // Options to send to the loader.
+ blink::WebURLLoaderOptions options_;
+
// Request to send. Released once Start() is called.
blink::WebURLRequest request_;
@@ -72,4 +78,4 @@ class ResourceFetcherImpl : public ResourceFetcher,
} // namespace content
-#endif // CONTENT_RENDERER_FETCHERS_RESOURCE_FETCHER_H_
+#endif // CONTENT_RENDERER_FETCHERS_RESOURCE_FETCHER_IMPL_H_
diff --git a/chromium/content/renderer/fetchers/web_url_loader_client_impl.cc b/chromium/content/renderer/fetchers/web_url_loader_client_impl.cc
index 847a167928f..c78fa1b9e2e 100644
--- a/chromium/content/renderer/fetchers/web_url_loader_client_impl.cc
+++ b/chromium/content/renderer/fetchers/web_url_loader_client_impl.cc
@@ -30,7 +30,10 @@ void WebURLLoaderClientImpl::didReceiveData(
const char* data,
int data_length,
int encoded_data_length) {
- DCHECK(!completed_);
+ // The AssociatedURLLoader will continue after a load failure.
+ // For example, for an Access Control error.
+ if (completed_)
+ return;
DCHECK(data_length > 0);
data_.append(data, data_length);
@@ -50,6 +53,10 @@ void WebURLLoaderClientImpl::didFinishLoading(
blink::WebURLLoader* loader,
double finishTime,
int64_t total_encoded_data_length) {
+ // The AssociatedURLLoader will continue after a load failure.
+ // For example, for an Access Control error.
+ if (completed_)
+ return;
OnLoadCompleteInternal(LOAD_SUCCEEDED);
}
diff --git a/chromium/content/renderer/fetchers/web_url_loader_client_impl.h b/chromium/content/renderer/fetchers/web_url_loader_client_impl.h
index 1113862873f..d028b76ccbb 100644
--- a/chromium/content/renderer/fetchers/web_url_loader_client_impl.h
+++ b/chromium/content/renderer/fetchers/web_url_loader_client_impl.h
@@ -79,4 +79,4 @@ class WebURLLoaderClientImpl : public blink::WebURLLoaderClient {
} // namespace content
-#endif // CONTENT_RENDERER_FETCHERS_URL_LOADER_CLIENT_H_
+#endif // CONTENT_RENDERER_FETCHERS_WEB_URL_LOADER_CLIENT_IMPL_H_
diff --git a/chromium/content/renderer/gamepad_shared_memory_reader.cc b/chromium/content/renderer/gamepad_shared_memory_reader.cc
index ab75d7eaeb7..89ed79eb1fd 100644
--- a/chromium/content/renderer/gamepad_shared_memory_reader.cc
+++ b/chromium/content/renderer/gamepad_shared_memory_reader.cc
@@ -4,8 +4,8 @@
#include "content/renderer/gamepad_shared_memory_reader.h"
-#include "base/debug/trace_event.h"
#include "base/metrics/histogram.h"
+#include "base/trace_event/trace_event.h"
#include "content/common/gamepad_hardware_buffer.h"
#include "content/common/gamepad_user_gesture.h"
#include "content/public/renderer/render_thread.h"
diff --git a/chromium/content/renderer/geolocation_dispatcher.cc b/chromium/content/renderer/geolocation_dispatcher.cc
index fde4fc98cba..65b85a147a4 100644
--- a/chromium/content/renderer/geolocation_dispatcher.cc
+++ b/chromium/content/renderer/geolocation_dispatcher.cc
@@ -4,7 +4,7 @@
#include "content/renderer/geolocation_dispatcher.h"
-#include "content/common/geolocation_messages.h"
+#include "content/public/common/geoposition.h"
#include "content/renderer/render_view_impl.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/web/WebGeolocationPermissionRequest.h"
@@ -30,23 +30,14 @@ GeolocationDispatcher::GeolocationDispatcher(RenderFrame* render_frame)
GeolocationDispatcher::~GeolocationDispatcher() {}
-bool GeolocationDispatcher::OnMessageReceived(const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(GeolocationDispatcher, message)
- IPC_MESSAGE_HANDLER(GeolocationMsg_PermissionSet, OnPermissionSet)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
void GeolocationDispatcher::startUpdating() {
- if (!geolocation_service_.get()) {
+ if (!geolocation_service_) {
render_frame()->GetServiceRegistry()->ConnectToRemoteService(
&geolocation_service_);
- geolocation_service_.set_client(this);
}
if (enable_high_accuracy_)
geolocation_service_->SetHighAccuracy(true);
+ QueryNextPosition();
}
void GeolocationDispatcher::stopUpdating() {
@@ -61,7 +52,7 @@ void GeolocationDispatcher::setEnableHighAccuracy(bool enable_high_accuracy) {
bool has_changed = enable_high_accuracy_ != enable_high_accuracy;
enable_high_accuracy_ = enable_high_accuracy;
// We have a different accuracy requirement. Request browser to update.
- if (geolocation_service_.get() && has_changed)
+ if (geolocation_service_ && has_changed)
geolocation_service_->SetHighAccuracy(enable_high_accuracy_);
}
@@ -82,29 +73,48 @@ bool GeolocationDispatcher::lastPosition(WebGeolocationPosition&) {
// conversion is necessary.
void GeolocationDispatcher::requestPermission(
const WebGeolocationPermissionRequest& permissionRequest) {
- int bridge_id = pending_permissions_->add(permissionRequest);
- base::string16 origin = permissionRequest.securityOrigin().toString();
- Send(new GeolocationHostMsg_RequestPermission(
- routing_id(), bridge_id, GURL(origin),
- blink::WebUserGestureIndicator::isProcessingUserGesture()));
+ if (!permission_service_.get()) {
+ render_frame()->GetServiceRegistry()->ConnectToRemoteService(
+ &permission_service_);
+ }
+
+ int permission_request_id = pending_permissions_->add(permissionRequest);
+
+ permission_service_->RequestPermission(
+ PERMISSION_NAME_GEOLOCATION,
+ permissionRequest.securityOrigin().toString().utf8(),
+ blink::WebUserGestureIndicator::isProcessingUserGesture(),
+ base::Bind(&GeolocationDispatcher::OnPermissionSet,
+ base::Unretained(this),
+ permission_request_id));
}
void GeolocationDispatcher::cancelPermissionRequest(
- const WebGeolocationPermissionRequest& permissionRequest) {
- int bridge_id;
- pending_permissions_->remove(permissionRequest, bridge_id);
+ const blink::WebGeolocationPermissionRequest& permissionRequest) {
+ int permission_request_id;
+ pending_permissions_->remove(permissionRequest, permission_request_id);
}
// Permission for using geolocation has been set.
-void GeolocationDispatcher::OnPermissionSet(int bridge_id, bool is_allowed) {
+void GeolocationDispatcher::OnPermissionSet(
+ int permission_request_id,
+ PermissionStatus status) {
WebGeolocationPermissionRequest permissionRequest;
- if (!pending_permissions_->remove(bridge_id, permissionRequest))
+ if (!pending_permissions_->remove(permission_request_id, permissionRequest))
return;
- permissionRequest.setIsAllowed(is_allowed);
+
+ permissionRequest.setIsAllowed(status == PERMISSION_STATUS_GRANTED);
+}
+
+void GeolocationDispatcher::QueryNextPosition() {
+ DCHECK(geolocation_service_);
+ geolocation_service_->QueryNextPosition(
+ base::Bind(&GeolocationDispatcher::OnPositionUpdate,
+ base::Unretained(this)));
}
-void GeolocationDispatcher::OnLocationUpdate(MojoGeopositionPtr geoposition) {
- DCHECK(geolocation_service_.get());
+void GeolocationDispatcher::OnPositionUpdate(MojoGeopositionPtr geoposition) {
+ QueryNextPosition();
if (geoposition->valid) {
controller_->positionChanged(WebGeolocationPosition(
diff --git a/chromium/content/renderer/geolocation_dispatcher.h b/chromium/content/renderer/geolocation_dispatcher.h
index 454859d0525..391e65d105d 100644
--- a/chromium/content/renderer/geolocation_dispatcher.h
+++ b/chromium/content/renderer/geolocation_dispatcher.h
@@ -7,6 +7,7 @@
#include "base/memory/scoped_ptr.h"
#include "content/common/geolocation_service.mojom.h"
+#include "content/common/permission_service.mojom.h"
#include "content/public/renderer/render_frame_observer.h"
#include "third_party/WebKit/public/web/WebGeolocationClient.h"
#include "third_party/WebKit/public/web/WebGeolocationController.h"
@@ -26,16 +27,12 @@ struct Geoposition;
// It's the complement of GeolocationDispatcherHost.
class GeolocationDispatcher
: public RenderFrameObserver,
- public blink::WebGeolocationClient,
- public mojo::InterfaceImpl<GeolocationServiceClient> {
+ public blink::WebGeolocationClient {
public:
explicit GeolocationDispatcher(RenderFrame* render_frame);
virtual ~GeolocationDispatcher();
private:
- // RenderFrame::Observer implementation.
- bool OnMessageReceived(const IPC::Message& message) override;
-
// WebGeolocationClient
virtual void startUpdating();
virtual void stopUpdating();
@@ -47,11 +44,11 @@ class GeolocationDispatcher
virtual void cancelPermissionRequest(
const blink::WebGeolocationPermissionRequest& permissionRequest);
- // GeolocationServiceClient
- void OnLocationUpdate(MojoGeopositionPtr geoposition) override;
+ void QueryNextPosition();
+ void OnPositionUpdate(MojoGeopositionPtr geoposition);
// Permission for using geolocation has been set.
- void OnPermissionSet(int bridge_id, bool is_allowed);
+ void OnPermissionSet(int permission_request_id, PermissionStatus status);
scoped_ptr<blink::WebGeolocationController> controller_;
@@ -59,6 +56,7 @@ class GeolocationDispatcher
pending_permissions_;
GeolocationServicePtr geolocation_service_;
bool enable_high_accuracy_;
+ PermissionServicePtr permission_service_;
};
} // namespace content
diff --git a/chromium/content/renderer/gin_browsertest.cc b/chromium/content/renderer/gin_browsertest.cc
index 58fccd9f148..e536bd62699 100644
--- a/chromium/content/renderer/gin_browsertest.cc
+++ b/chromium/content/renderer/gin_browsertest.cc
@@ -43,7 +43,7 @@ class GinBrowserTest : public RenderViewTest {
~GinBrowserTest() override {}
void SetUp() override {
- CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
switches::kJavaScriptFlags, "--expose_gc");
RenderViewTest::SetUp();
diff --git a/chromium/content/renderer/gpu/OWNERS b/chromium/content/renderer/gpu/OWNERS
index 4cd2b20015b..68dda9d5c17 100644
--- a/chromium/content/renderer/gpu/OWNERS
+++ b/chromium/content/renderer/gpu/OWNERS
@@ -1,3 +1,4 @@
jbauman@chromium.org
kbr@chromium.org
piman@chromium.org
+enne@chromium.org
diff --git a/chromium/content/renderer/gpu/compositor_dependencies.h b/chromium/content/renderer/gpu/compositor_dependencies.h
new file mode 100644
index 00000000000..9973a65cdf2
--- /dev/null
+++ b/chromium/content/renderer/gpu/compositor_dependencies.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_RENDERER_GPU_COMPOSITOR_DEPENDENCIES_H_
+#define CONTENT_RENDERER_GPU_COMPOSITOR_DEPENDENCIES_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+}
+
+namespace cc {
+class BeginFrameSource;
+class ContextProvider;
+class SharedBitmapManager;
+class TaskGraphRunner;
+}
+
+namespace gpu {
+class GpuMemoryBufferManager;
+}
+
+namespace scheduler {
+class RendererScheduler;
+}
+
+namespace content {
+
+class CompositorDependencies {
+ public:
+ virtual bool IsImplSidePaintingEnabled() = 0;
+ virtual bool IsGpuRasterizationForced() = 0;
+ virtual bool IsGpuRasterizationEnabled() = 0;
+ virtual int GetGpuRasterizationMSAASampleCount() = 0;
+ virtual bool IsLcdTextEnabled() = 0;
+ virtual bool IsDistanceFieldTextEnabled() = 0;
+ virtual bool IsZeroCopyEnabled() = 0;
+ virtual bool IsOneCopyEnabled() = 0;
+ virtual bool IsElasticOverscrollEnabled() = 0;
+ // Only valid in single threaded mode.
+ virtual bool UseSingleThreadScheduler() = 0;
+ virtual uint32 GetImageTextureTarget() = 0;
+ virtual scoped_refptr<base::SingleThreadTaskRunner>
+ GetCompositorMainThreadTaskRunner() = 0;
+ // Returns null if the compositor is in single-threaded mode (ie. there is no
+ // compositor thread).
+ virtual scoped_refptr<base::SingleThreadTaskRunner>
+ GetCompositorImplThreadTaskRunner() = 0;
+ virtual cc::SharedBitmapManager* GetSharedBitmapManager() = 0;
+ virtual gpu::GpuMemoryBufferManager* GetGpuMemoryBufferManager() = 0;
+ virtual scheduler::RendererScheduler* GetRendererScheduler() = 0;
+ virtual cc::ContextProvider* GetSharedMainThreadContextProvider() = 0;
+ virtual scoped_ptr<cc::BeginFrameSource> CreateExternalBeginFrameSource(
+ int routing_id) = 0;
+ virtual cc::TaskGraphRunner* GetTaskGraphRunner() = 0;
+ virtual bool IsGatherPixelRefsEnabled() = 0;
+
+ virtual ~CompositorDependencies() {}
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_GPU_COMPOSITOR_DEPENDENCIES_H_
diff --git a/chromium/content/renderer/gpu/compositor_external_begin_frame_source.cc b/chromium/content/renderer/gpu/compositor_external_begin_frame_source.cc
new file mode 100644
index 00000000000..ae18568e04e
--- /dev/null
+++ b/chromium/content/renderer/gpu/compositor_external_begin_frame_source.cc
@@ -0,0 +1,73 @@
+// Copyright 2014 The Chromium Authors. 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/renderer/gpu/compositor_external_begin_frame_source.h"
+
+#include "content/common/view_messages.h"
+#include "ipc/ipc_sync_channel.h"
+#include "ipc/ipc_sync_message_filter.h"
+
+namespace content {
+
+CompositorExternalBeginFrameSource::CompositorExternalBeginFrameSource(
+ CompositorForwardingMessageFilter* filter,
+ IPC::SyncMessageFilter* sync_message_filter,
+ int routing_id)
+ : begin_frame_source_filter_(filter),
+ message_sender_(sync_message_filter),
+ routing_id_(routing_id) {
+ DCHECK(begin_frame_source_filter_.get());
+ DCHECK(message_sender_.get());
+ DetachFromThread();
+}
+
+CompositorExternalBeginFrameSource::~CompositorExternalBeginFrameSource() {
+ DCHECK(CalledOnValidThread());
+ if (begin_frame_source_proxy_.get()) {
+ begin_frame_source_proxy_->ClearBeginFrameSource();
+ begin_frame_source_filter_->RemoveHandlerOnCompositorThread(
+ routing_id_,
+ begin_frame_source_filter_handler_);
+ }
+}
+
+void CompositorExternalBeginFrameSource::OnNeedsBeginFramesChange(
+ bool needs_begin_frames) {
+ DCHECK(CalledOnValidThread());
+ Send(new ViewHostMsg_SetNeedsBeginFrames(routing_id_, needs_begin_frames));
+}
+
+void CompositorExternalBeginFrameSource::SetClientReady() {
+ DCHECK(CalledOnValidThread());
+ DCHECK(!begin_frame_source_proxy_.get());
+ begin_frame_source_proxy_ =
+ new CompositorExternalBeginFrameSourceProxy(this);
+ begin_frame_source_filter_handler_ = base::Bind(
+ &CompositorExternalBeginFrameSourceProxy::OnMessageReceived,
+ begin_frame_source_proxy_);
+ begin_frame_source_filter_->AddHandlerOnCompositorThread(
+ routing_id_,
+ begin_frame_source_filter_handler_);
+}
+
+void CompositorExternalBeginFrameSource::OnMessageReceived(
+ const IPC::Message& message) {
+ DCHECK(CalledOnValidThread());
+ DCHECK(begin_frame_source_proxy_.get());
+ IPC_BEGIN_MESSAGE_MAP(CompositorExternalBeginFrameSource, message)
+ IPC_MESSAGE_HANDLER(ViewMsg_BeginFrame, OnBeginFrame)
+ IPC_END_MESSAGE_MAP();
+}
+
+void CompositorExternalBeginFrameSource::OnBeginFrame(
+ const cc::BeginFrameArgs& args) {
+ DCHECK(CalledOnValidThread());
+ CallOnBeginFrame(args);
+}
+
+bool CompositorExternalBeginFrameSource::Send(IPC::Message* message) {
+ return message_sender_->Send(message);
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/gpu/compositor_external_begin_frame_source.h b/chromium/content/renderer/gpu/compositor_external_begin_frame_source.h
new file mode 100644
index 00000000000..839f6cffa3b
--- /dev/null
+++ b/chromium/content/renderer/gpu/compositor_external_begin_frame_source.h
@@ -0,0 +1,78 @@
+// Copyright 2014 The Chromium Authors. 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_GPU_COMPOSITOR_EXTERNAL_BEGIN_FRAME_SOURCE_H_
+#define CONTENT_RENDERER_GPU_COMPOSITOR_EXTERNAL_BEGIN_FRAME_SOURCE_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "cc/scheduler/begin_frame_source.h"
+#include "content/renderer/gpu/compositor_forwarding_message_filter.h"
+
+namespace IPC {
+class Message;
+class SyncMessageFilter;
+}
+
+namespace content {
+
+// This class can be created only on the main thread, but then becomes pinned
+// to a fixed thread where cc::Scheduler is running.
+class CompositorExternalBeginFrameSource
+ : public cc::BeginFrameSourceMixIn,
+ public NON_EXPORTED_BASE(base::NonThreadSafe) {
+ public:
+ explicit CompositorExternalBeginFrameSource(
+ CompositorForwardingMessageFilter* filter,
+ IPC::SyncMessageFilter* sync_message_filter,
+ int routing_id);
+ ~CompositorExternalBeginFrameSource() override;
+
+ // cc::BeginFrameSourceMixIn implementation.
+ void OnNeedsBeginFramesChange(bool needs_begin_frames) override;
+ void SetClientReady() override;
+
+ private:
+ class CompositorExternalBeginFrameSourceProxy
+ : public base::RefCountedThreadSafe<
+ CompositorExternalBeginFrameSourceProxy> {
+ public:
+ explicit CompositorExternalBeginFrameSourceProxy(
+ CompositorExternalBeginFrameSource* begin_frame_source)
+ : begin_frame_source_(begin_frame_source) {}
+ void ClearBeginFrameSource() { begin_frame_source_ = NULL; }
+ void OnMessageReceived(const IPC::Message& message) {
+ if (begin_frame_source_)
+ begin_frame_source_->OnMessageReceived(message);
+ }
+
+ private:
+ friend class base::RefCountedThreadSafe<
+ CompositorExternalBeginFrameSourceProxy>;
+ virtual ~CompositorExternalBeginFrameSourceProxy() {}
+
+ CompositorExternalBeginFrameSource* begin_frame_source_;
+
+ DISALLOW_COPY_AND_ASSIGN(CompositorExternalBeginFrameSourceProxy);
+ };
+
+ void OnMessageReceived(const IPC::Message& message);
+
+ void OnBeginFrame(const cc::BeginFrameArgs& args);
+ bool Send(IPC::Message* message);
+
+ scoped_refptr<CompositorForwardingMessageFilter> begin_frame_source_filter_;
+ scoped_refptr<CompositorExternalBeginFrameSourceProxy>
+ begin_frame_source_proxy_;
+ scoped_refptr<IPC::SyncMessageFilter> message_sender_;
+ int routing_id_;
+ CompositorForwardingMessageFilter::Handler begin_frame_source_filter_handler_;
+
+ DISALLOW_COPY_AND_ASSIGN(CompositorExternalBeginFrameSource);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_GPU_COMPOSITOR_EXTERNAL_BEGIN_FRAME_SOURCE_H_
diff --git a/chromium/content/renderer/gpu/compositor_forwarding_message_filter.cc b/chromium/content/renderer/gpu/compositor_forwarding_message_filter.cc
new file mode 100644
index 00000000000..ff657dc58f6
--- /dev/null
+++ b/chromium/content/renderer/gpu/compositor_forwarding_message_filter.cc
@@ -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.
+
+#include "content/renderer/gpu//compositor_forwarding_message_filter.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "content/common/view_messages.h"
+#include "ipc/ipc_message.h"
+
+namespace content {
+
+CompositorForwardingMessageFilter::CompositorForwardingMessageFilter(
+ base::TaskRunner* compositor_task_runner)
+ : compositor_task_runner_(compositor_task_runner) {
+ DCHECK(compositor_task_runner_.get());
+ // This check will only be used by functions running on compositor thread.
+ compositor_thread_checker_.DetachFromThread();
+}
+
+CompositorForwardingMessageFilter::~CompositorForwardingMessageFilter() {
+}
+
+void CompositorForwardingMessageFilter::AddHandlerOnCompositorThread(
+ int routing_id,
+ const Handler& handler) {
+ DCHECK(compositor_thread_checker_.CalledOnValidThread());
+ DCHECK(!handler.is_null());
+ multi_handlers_.insert(std::make_pair(routing_id, handler));
+}
+
+void CompositorForwardingMessageFilter::RemoveHandlerOnCompositorThread(
+ int routing_id,
+ const Handler& handler) {
+ DCHECK(compositor_thread_checker_.CalledOnValidThread());
+ auto handlers = multi_handlers_.equal_range(routing_id);
+ for (auto it = handlers.first; it != handlers.second; ++it) {
+ if (it->second.Equals(handler)) {
+ multi_handlers_.erase(it);
+ return;
+ }
+ }
+ NOTREACHED();
+}
+
+bool CompositorForwardingMessageFilter::OnMessageReceived(
+ const IPC::Message& message) {
+ switch(message.type()) {
+ case ViewMsg_BeginFrame::ID: // Fall through.
+ case ViewMsg_ReclaimCompositorResources::ID: // Fall through.
+ case ViewMsg_SwapCompositorFrameAck::ID: // Fall through.
+ case ViewMsg_UpdateVSyncParameters::ID:
+ break;
+ default:
+ return false;
+ }
+
+ compositor_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &CompositorForwardingMessageFilter::ProcessMessageOnCompositorThread,
+ this,
+ message));
+ return true;
+}
+
+void CompositorForwardingMessageFilter::ProcessMessageOnCompositorThread(
+ const IPC::Message& message) {
+ DCHECK(compositor_thread_checker_.CalledOnValidThread());
+ auto handlers = multi_handlers_.equal_range(message.routing_id());
+ if (handlers.first == handlers.second)
+ return;
+
+ for (auto it = handlers.first; it != handlers.second; ++it)
+ it->second.Run(message);
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/gpu/compositor_forwarding_message_filter.h b/chromium/content/renderer/gpu/compositor_forwarding_message_filter.h
new file mode 100644
index 00000000000..9e2afaf7bcb
--- /dev/null
+++ b/chromium/content/renderer/gpu/compositor_forwarding_message_filter.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_RENDERER_GPU_COMPOSITOR_FORWARDING_MESSAGE_FILTER_H_
+#define CONTENT_RENDERER_GPU_COMPOSITOR_FORWARDING_MESSAGE_FILTER_H_
+
+#include <map>
+#include <set>
+
+#include "base/bind.h"
+#include "base/callback_forward.h"
+#include "base/synchronization/lock.h"
+#include "base/task_runner.h"
+#include "base/threading/thread_checker.h"
+#include "content/common/content_export.h"
+#include "ipc/message_filter.h"
+
+namespace content {
+
+// This class can be used to intercept routed messages and
+// deliver them to a compositor task runner than they would otherwise
+// be sent. Messages are filtered based on type. To route these messages,
+// add a Handler to the filter.
+//
+// The user of this class implements CompositorForwardingMessageFilter::Handler,
+// which will receive the intercepted messages, on the compositor thread.
+// The caller must ensure that each handler in |multi_handlers_| outlives the
+// lifetime of the filter.
+// User can add multiple handlers for specific routing id. When messages have
+// arrived, all handlers in |multi_handlers_| for routing id will be executed.
+//
+// Note: When we want to add new message, add a new switch case in
+// OnMessageReceived() then add a new Handler for it.
+class CONTENT_EXPORT CompositorForwardingMessageFilter
+ : public IPC::MessageFilter {
+ public:
+ // The handler is invoked on the compositor thread with messages that were
+ // intercepted by this filter.
+ typedef base::Callback<void(const IPC::Message&)> Handler;
+
+ // This filter will intercept messages defined in OnMessageReceived() and run
+ // them by ProcessMessageOnCompositorThread on compositor thread.
+ CompositorForwardingMessageFilter(base::TaskRunner* compositor_task_runner);
+
+ void AddHandlerOnCompositorThread(int routing_id, const Handler& handler);
+ void RemoveHandlerOnCompositorThread(int routing_id, const Handler& handler);
+
+ // MessageFilter methods:
+ bool OnMessageReceived(const IPC::Message& message) override;
+
+ protected:
+ ~CompositorForwardingMessageFilter() override;
+
+ private:
+ void ProcessMessageOnCompositorThread(const IPC::Message& message);
+
+ // The handler only gets run on the compositor thread.
+ scoped_refptr<base::TaskRunner> compositor_task_runner_;
+
+ // This is used to check some functions that are only running on compositor
+ // thread.
+ base::ThreadChecker compositor_thread_checker_;
+
+ // Maps the routing_id for which messages should be filtered and handlers
+ // which will be routed.
+ std::multimap<int, Handler> multi_handlers_;
+
+ DISALLOW_COPY_AND_ASSIGN(CompositorForwardingMessageFilter);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_GPU_COMPOSITOR_FORWARDING_MESSAGE_FILTER_H_
diff --git a/chromium/content/renderer/gpu/compositor_forwarding_message_filter_unittest.cc b/chromium/content/renderer/gpu/compositor_forwarding_message_filter_unittest.cc
new file mode 100644
index 00000000000..97f67a36655
--- /dev/null
+++ b/chromium/content/renderer/gpu/compositor_forwarding_message_filter_unittest.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/renderer/gpu/compositor_forwarding_message_filter.h"
+
+#include "base/bind.h"
+#include "base/test/test_simple_task_runner.h"
+#include "cc/test/begin_frame_args_test.h"
+#include "content/common/view_messages.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+class CompositorForwardingMessageFilterTestHandler
+ : public base::RefCounted<CompositorForwardingMessageFilterTestHandler> {
+ public:
+ CompositorForwardingMessageFilterTestHandler() : count_(0) {
+ }
+
+ void OnPlusMethod(const IPC::Message& msg) {
+ count_++;
+ }
+
+ void OnMinusMethod(const IPC::Message& msg) {
+ count_--;
+ }
+
+ int count() { return count_; }
+
+ void ResetCount() { count_ = 0; }
+
+ private:
+ friend class base::RefCounted<CompositorForwardingMessageFilterTestHandler>;
+ ~CompositorForwardingMessageFilterTestHandler() {}
+
+ int count_;
+};
+
+TEST(CompositorForwardingMessageFilterTest, BasicTest) {
+ scoped_refptr<CompositorForwardingMessageFilterTestHandler> handler =
+ new CompositorForwardingMessageFilterTestHandler;
+ scoped_refptr<base::TestSimpleTaskRunner> task_runner(
+ new base::TestSimpleTaskRunner);
+ int route_id = 0;
+
+ ViewMsg_BeginFrame msg(
+ route_id, cc::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+
+ CompositorForwardingMessageFilter::Handler plus_handler =
+ base::Bind(&CompositorForwardingMessageFilterTestHandler::OnPlusMethod,
+ handler);
+ CompositorForwardingMessageFilter::Handler minus_handler =
+ base::Bind(&CompositorForwardingMessageFilterTestHandler::OnMinusMethod,
+ handler);
+
+ scoped_refptr<CompositorForwardingMessageFilter> filter =
+ new CompositorForwardingMessageFilter(task_runner.get());
+
+ filter->AddHandlerOnCompositorThread(route_id, plus_handler);
+ filter->OnMessageReceived(msg);
+ task_runner->RunPendingTasks();
+ EXPECT_EQ(1, handler->count());
+
+ handler->ResetCount();
+ EXPECT_EQ(0, handler->count());
+
+ filter->AddHandlerOnCompositorThread(route_id, minus_handler);
+ filter->OnMessageReceived(msg);
+ task_runner->RunPendingTasks();
+ EXPECT_EQ(0, handler->count());
+
+ handler->ResetCount();
+ EXPECT_EQ(0, handler->count());
+
+ filter->RemoveHandlerOnCompositorThread(route_id, plus_handler);
+ filter->OnMessageReceived(msg);
+ task_runner->RunPendingTasks();
+ EXPECT_EQ(-1, handler->count());
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/gpu/compositor_output_surface.cc b/chromium/content/renderer/gpu/compositor_output_surface.cc
index c579d8c4029..bdeefe0a8fc 100644
--- a/chromium/content/renderer/gpu/compositor_output_surface.cc
+++ b/chromium/content/renderer/gpu/compositor_output_surface.cc
@@ -19,7 +19,6 @@
#include "content/renderer/render_thread_impl.h"
#include "gpu/command_buffer/client/context_support.h"
#include "gpu/command_buffer/client/gles2_interface.h"
-#include "ipc/ipc_forwarding_message_filter.h"
#include "ipc/ipc_sync_channel.h"
namespace {
@@ -30,38 +29,21 @@ int g_prefer_smoothness_count = 0;
namespace content {
-//------------------------------------------------------------------------------
-
-// static
-IPC::ForwardingMessageFilter* CompositorOutputSurface::CreateFilter(
- base::TaskRunner* target_task_runner)
-{
- uint32 messages_to_filter[] = {
- ViewMsg_UpdateVSyncParameters::ID,
- ViewMsg_SwapCompositorFrameAck::ID,
- ViewMsg_ReclaimCompositorResources::ID,
-#if defined(OS_ANDROID)
- ViewMsg_BeginFrame::ID
-#endif
- };
-
- return new IPC::ForwardingMessageFilter(
- messages_to_filter, arraysize(messages_to_filter),
- target_task_runner);
-}
-
CompositorOutputSurface::CompositorOutputSurface(
int32 routing_id,
uint32 output_surface_id,
const scoped_refptr<ContextProviderCommandBuffer>& context_provider,
+ const scoped_refptr<ContextProviderCommandBuffer>& worker_context_provider,
scoped_ptr<cc::SoftwareOutputDevice> software_device,
scoped_refptr<FrameSwapMessageQueue> swap_frame_message_queue,
bool use_swap_compositor_frame_message)
- : OutputSurface(context_provider, software_device.Pass()),
+ : OutputSurface(context_provider,
+ worker_context_provider,
+ software_device.Pass()),
output_surface_id_(output_surface_id),
use_swap_compositor_frame_message_(use_swap_compositor_frame_message),
output_surface_filter_(
- RenderThreadImpl::current()->compositor_output_surface_filter()),
+ RenderThreadImpl::current()->compositor_message_filter()),
frame_swap_message_queue_(swap_frame_message_queue),
routing_id_(routing_id),
prefers_smoothness_(false),
@@ -84,13 +66,14 @@ CompositorOutputSurface::CompositorOutputSurface(
CompositorOutputSurface::~CompositorOutputSurface() {
DCHECK(CalledOnValidThread());
- SetNeedsBeginFrame(false);
if (!HasClient())
return;
UpdateSmoothnessTakesPriority(false);
if (output_surface_proxy_.get())
output_surface_proxy_->ClearOutputSurface();
- output_surface_filter_->RemoveRoute(routing_id_);
+ output_surface_filter_->RemoveHandlerOnCompositorThread(
+ routing_id_,
+ output_surface_filter_handler_);
}
bool CompositorOutputSurface::BindToClient(
@@ -101,10 +84,12 @@ bool CompositorOutputSurface::BindToClient(
return false;
output_surface_proxy_ = new CompositorOutputSurfaceProxy(this);
- output_surface_filter_->AddRoute(
- routing_id_,
+ output_surface_filter_handler_ =
base::Bind(&CompositorOutputSurfaceProxy::OnMessageReceived,
- output_surface_proxy_));
+ output_surface_proxy_);
+ output_surface_filter_->AddHandlerOnCompositorThread(
+ routing_id_,
+ output_surface_filter_handler_);
if (!context_provider()) {
// Without a GPU context, the memory policy otherwise wouldn't be set.
@@ -193,9 +178,6 @@ void CompositorOutputSurface::OnMessageReceived(const IPC::Message& message) {
OnUpdateVSyncParametersFromBrowser);
IPC_MESSAGE_HANDLER(ViewMsg_SwapCompositorFrameAck, OnSwapAck);
IPC_MESSAGE_HANDLER(ViewMsg_ReclaimCompositorResources, OnReclaimResources);
-#if defined(OS_ANDROID)
- IPC_MESSAGE_HANDLER(ViewMsg_BeginFrame, OnBeginFrame);
-#endif
IPC_END_MESSAGE_MAP()
}
@@ -206,18 +188,6 @@ void CompositorOutputSurface::OnUpdateVSyncParametersFromBrowser(
CommitVSyncParameters(timebase, interval);
}
-#if defined(OS_ANDROID)
-void CompositorOutputSurface::SetNeedsBeginFrame(bool enable) {
- DCHECK(CalledOnValidThread());
- Send(new ViewHostMsg_SetNeedsBeginFrame(routing_id_, enable));
-}
-
-void CompositorOutputSurface::OnBeginFrame(const cc::BeginFrameArgs& args) {
- DCHECK(CalledOnValidThread());
- client_->BeginFrame(args);
-}
-#endif // defined(OS_ANDROID)
-
void CompositorOutputSurface::OnSwapAck(uint32 output_surface_id,
const cc::CompositorFrameAck& ack) {
// Ignore message if it's a stale one coming from a different output surface
@@ -245,12 +215,12 @@ bool CompositorOutputSurface::Send(IPC::Message* message) {
namespace {
#if defined(OS_ANDROID)
void SetThreadPriorityToIdle(base::PlatformThreadHandle handle) {
- base::PlatformThread::SetThreadPriority(
- handle, base::kThreadPriority_Background);
+ base::PlatformThread::SetThreadPriority(handle,
+ base::ThreadPriority::BACKGROUND);
}
void SetThreadPriorityToDefault(base::PlatformThreadHandle handle) {
- base::PlatformThread::SetThreadPriority(
- handle, base::kThreadPriority_Normal);
+ base::PlatformThread::SetThreadPriority(handle,
+ base::ThreadPriority::NORMAL);
}
#else
void SetThreadPriorityToIdle(base::PlatformThreadHandle handle) {}
diff --git a/chromium/content/renderer/gpu/compositor_output_surface.h b/chromium/content/renderer/gpu/compositor_output_surface.h
index 7ee94270245..cb4bdba9b4b 100644
--- a/chromium/content/renderer/gpu/compositor_output_surface.h
+++ b/chromium/content/renderer/gpu/compositor_output_surface.h
@@ -15,14 +15,10 @@
#include "base/time/time.h"
#include "cc/output/begin_frame_args.h"
#include "cc/output/output_surface.h"
+#include "content/renderer/gpu/compositor_forwarding_message_filter.h"
#include "ipc/ipc_sync_message_filter.h"
-namespace base {
-class TaskRunner;
-}
-
namespace IPC {
-class ForwardingMessageFilter;
class Message;
}
@@ -43,13 +39,12 @@ class CompositorOutputSurface
: NON_EXPORTED_BASE(public cc::OutputSurface),
NON_EXPORTED_BASE(public base::NonThreadSafe) {
public:
- static IPC::ForwardingMessageFilter* CreateFilter(
- base::TaskRunner* target_task_runner);
-
CompositorOutputSurface(
int32 routing_id,
uint32 output_surface_id,
const scoped_refptr<ContextProviderCommandBuffer>& context_provider,
+ const scoped_refptr<ContextProviderCommandBuffer>&
+ worker_context_provider,
scoped_ptr<cc::SoftwareOutputDevice> software,
scoped_refptr<FrameSwapMessageQueue> swap_frame_message_queue,
bool use_swap_compositor_frame_message);
@@ -58,9 +53,6 @@ class CompositorOutputSurface
// cc::OutputSurface implementation.
bool BindToClient(cc::OutputSurfaceClient* client) override;
void SwapBuffers(cc::CompositorFrame* frame) override;
-#if defined(OS_ANDROID)
- virtual void SetNeedsBeginFrame(bool enable) override;
-#endif
// TODO(epenner): This seems out of place here and would be a better fit
// int CompositorThread after it is fully refactored (http://crbug/170828)
@@ -100,14 +92,12 @@ class CompositorOutputSurface
void OnMessageReceived(const IPC::Message& message);
void OnUpdateVSyncParametersFromBrowser(base::TimeTicks timebase,
base::TimeDelta interval);
-#if defined(OS_ANDROID)
- void OnBeginFrame(const cc::BeginFrameArgs& args);
-#endif
bool Send(IPC::Message* message);
bool use_swap_compositor_frame_message_;
- scoped_refptr<IPC::ForwardingMessageFilter> output_surface_filter_;
+ scoped_refptr<CompositorForwardingMessageFilter> output_surface_filter_;
+ CompositorForwardingMessageFilter::Handler output_surface_filter_handler_;
scoped_refptr<CompositorOutputSurfaceProxy> output_surface_proxy_;
scoped_refptr<IPC::SyncMessageFilter> message_sender_;
scoped_refptr<FrameSwapMessageQueue> frame_swap_message_queue_;
diff --git a/chromium/content/renderer/gpu/compositor_software_output_device.cc b/chromium/content/renderer/gpu/compositor_software_output_device.cc
deleted file mode 100644
index 4b23919203b..00000000000
--- a/chromium/content/renderer/gpu/compositor_software_output_device.cc
+++ /dev/null
@@ -1,233 +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/renderer/gpu/compositor_software_output_device.h"
-
-#include "base/logging.h"
-#include "cc/output/software_frame_data.h"
-#include "content/child/child_shared_bitmap_manager.h"
-#include "content/renderer/render_process.h"
-#include "content/renderer/render_thread_impl.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-#include "third_party/skia/include/core/SkPixelRef.h"
-#include "third_party/skia/include/core/SkRegion.h"
-#include "ui/gfx/skia_util.h"
-
-namespace {
-
-const size_t kInvalidIndex = static_cast<size_t>(-1);
-
-} // namespace
-
-namespace content {
-
-CompositorSoftwareOutputDevice::Buffer::Buffer(
- unsigned id,
- scoped_ptr<cc::SharedBitmap> bitmap)
- : id_(id), shared_bitmap_(bitmap.Pass()), free_(true), parent_(NULL) {}
-
-CompositorSoftwareOutputDevice::Buffer::~Buffer() {
-}
-
-void CompositorSoftwareOutputDevice::Buffer::SetParent(
- Buffer* parent, const gfx::Rect& damage) {
- parent_ = parent;
- damage_ = damage;
-}
-
-bool CompositorSoftwareOutputDevice::Buffer::FindDamageDifferenceFrom(
- Buffer* buffer, SkRegion* result) const {
- if (!buffer)
- return false;
-
- if (buffer == this) {
- *result = SkRegion();
- return true;
- }
-
- SkRegion damage;
- const Buffer* current = this;
- while (current->parent_) {
- damage.op(RectToSkIRect(current->damage_), SkRegion::kUnion_Op);
- if (current->parent_ == buffer) {
- *result = damage;
- return true;
- }
- current = current->parent_;
- }
-
- return false;
-}
-
-CompositorSoftwareOutputDevice::CompositorSoftwareOutputDevice()
- : current_index_(kInvalidIndex),
- next_buffer_id_(1),
- shared_bitmap_manager_(
- RenderThreadImpl::current()->shared_bitmap_manager()) {
- DetachFromThread();
-}
-
-CompositorSoftwareOutputDevice::~CompositorSoftwareOutputDevice() {
- DCHECK(CalledOnValidThread());
-}
-
-unsigned CompositorSoftwareOutputDevice::GetNextId() {
- unsigned id = next_buffer_id_++;
- // Zero is reserved to label invalid frame id.
- if (id == 0)
- id = next_buffer_id_++;
- return id;
-}
-
-CompositorSoftwareOutputDevice::Buffer*
-CompositorSoftwareOutputDevice::CreateBuffer() {
- scoped_ptr<cc::SharedBitmap> shared_bitmap =
- shared_bitmap_manager_->AllocateSharedBitmap(viewport_pixel_size_);
- CHECK(shared_bitmap);
- return new Buffer(GetNextId(), shared_bitmap.Pass());
-}
-
-size_t CompositorSoftwareOutputDevice::FindFreeBuffer(size_t hint) {
- for (size_t i = 0; i < buffers_.size(); ++i) {
- size_t index = (hint + i) % buffers_.size();
- if (buffers_[index]->free())
- return index;
- }
-
- buffers_.push_back(CreateBuffer());
- return buffers_.size() - 1;
-}
-
-void CompositorSoftwareOutputDevice::Resize(
- const gfx::Size& viewport_pixel_size,
- float scale_factor) {
- DCHECK(CalledOnValidThread());
-
- scale_factor_ = scale_factor;
-
- if (viewport_pixel_size_ == viewport_pixel_size)
- return;
-
- // Keep non-ACKed buffers in awaiting_ack_ until they get acknowledged.
- for (size_t i = 0; i < buffers_.size(); ++i) {
- if (!buffers_[i]->free()) {
- awaiting_ack_.push_back(buffers_[i]);
- buffers_[i] = NULL;
- }
- }
-
- buffers_.clear();
- current_index_ = kInvalidIndex;
- viewport_pixel_size_ = viewport_pixel_size;
-}
-
-void CompositorSoftwareOutputDevice::DiscardBackbuffer() {
- // Keep non-ACKed buffers in awaiting_ack_ until they get acknowledged.
- for (size_t i = 0; i < buffers_.size(); ++i) {
- if (!buffers_[i]->free()) {
- awaiting_ack_.push_back(buffers_[i]);
- buffers_[i] = NULL;
- }
- }
- buffers_.clear();
- current_index_ = kInvalidIndex;
-}
-
-void CompositorSoftwareOutputDevice::EnsureBackbuffer() {
-}
-
-SkCanvas* CompositorSoftwareOutputDevice::BeginPaint(
- const gfx::Rect& damage_rect) {
- DCHECK(CalledOnValidThread());
-
- Buffer* previous = NULL;
- if (current_index_ != kInvalidIndex)
- previous = buffers_[current_index_];
- current_index_ = FindFreeBuffer(current_index_ + 1);
- Buffer* current = buffers_[current_index_];
- DCHECK(current->free());
- current->SetFree(false);
-
- // Set up a canvas for the current front buffer.
- SkImageInfo info = SkImageInfo::MakeN32Premul(viewport_pixel_size_.width(),
- viewport_pixel_size_.height());
- SkBitmap bitmap;
- bitmap.installPixels(info, current->memory(), info.minRowBytes());
- canvas_ = skia::AdoptRef(new SkCanvas(bitmap));
-
- if (!previous) {
- DCHECK(damage_rect == gfx::Rect(viewport_pixel_size_));
- } else {
- // Find the smallest damage region that needs
- // to be copied from the |previous| buffer.
- SkRegion region;
- bool found =
- current->FindDamageDifferenceFrom(previous, &region) ||
- previous->FindDamageDifferenceFrom(current, &region);
- if (!found)
- region = SkRegion(RectToSkIRect(gfx::Rect(viewport_pixel_size_)));
- region.op(RectToSkIRect(damage_rect), SkRegion::kDifference_Op);
-
- // Copy over the damage region.
- if (!region.isEmpty()) {
- SkImageInfo info = SkImageInfo::MakeN32Premul(
- viewport_pixel_size_.width(), viewport_pixel_size_.height());
- SkBitmap back_bitmap;
- back_bitmap.installPixels(info, previous->memory(), info.minRowBytes());
-
- for (SkRegion::Iterator it(region); !it.done(); it.next()) {
- const SkIRect& src_rect = it.rect();
- SkRect dst_rect = SkRect::Make(src_rect);
- canvas_->drawBitmapRect(back_bitmap, &src_rect, dst_rect, NULL);
- }
- }
- }
-
- // Make |current| child of |previous| and orphan all of |current|'s children.
- current->SetParent(previous, damage_rect);
- for (size_t i = 0; i < buffers_.size(); ++i) {
- Buffer* buffer = buffers_[i];
- if (buffer->parent() == current)
- buffer->SetParent(NULL, gfx::Rect(viewport_pixel_size_));
- }
- damage_rect_ = damage_rect;
-
- return canvas_.get();
-}
-
-void CompositorSoftwareOutputDevice::EndPaint(
- cc::SoftwareFrameData* frame_data) {
- DCHECK(CalledOnValidThread());
- DCHECK(frame_data);
-
- Buffer* buffer = buffers_[current_index_];
- frame_data->id = buffer->id();
- frame_data->size = viewport_pixel_size_;
- frame_data->damage_rect = damage_rect_;
- frame_data->bitmap_id = buffer->shared_bitmap_id();
-}
-
-void CompositorSoftwareOutputDevice::ReclaimSoftwareFrame(unsigned id) {
- DCHECK(CalledOnValidThread());
-
- if (!id)
- return;
-
- // The reclaimed buffer id might not be among the currently
- // active buffers if we got a resize event in the mean time.
- ScopedVector<Buffer>::iterator it =
- std::find_if(buffers_.begin(), buffers_.end(), CompareById(id));
- if (it != buffers_.end()) {
- DCHECK(!(*it)->free());
- (*it)->SetFree(true);
- return;
- } else {
- it = std::find_if(awaiting_ack_.begin(), awaiting_ack_.end(),
- CompareById(id));
- DCHECK(it != awaiting_ack_.end());
- awaiting_ack_.erase(it);
- }
-}
-
-} // namespace content
diff --git a/chromium/content/renderer/gpu/compositor_software_output_device.h b/chromium/content/renderer/gpu/compositor_software_output_device.h
deleted file mode 100644
index 48fa0507ebe..00000000000
--- a/chromium/content/renderer/gpu/compositor_software_output_device.h
+++ /dev/null
@@ -1,101 +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_RENDERER_GPU_COMPOSITOR_SOFTWARE_OUTPUT_DEVICE_H_
-#define CONTENT_RENDERER_GPU_COMPOSITOR_SOFTWARE_OUTPUT_DEVICE_H_
-
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
-#include "base/memory/shared_memory.h"
-#include "base/threading/non_thread_safe.h"
-#include "cc/output/software_output_device.h"
-#include "cc/resources/shared_bitmap.h"
-#include "content/public/renderer/render_thread.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-
-class SkRegion;
-
-namespace cc {
-class SharedBitmapManager;
-}
-
-namespace content {
-
-// This class can be created only on the main thread, but then becomes pinned
-// to a fixed thread when BindToClient is called.
-class CompositorSoftwareOutputDevice
- : NON_EXPORTED_BASE(public cc::SoftwareOutputDevice),
- NON_EXPORTED_BASE(public base::NonThreadSafe) {
- public:
- CompositorSoftwareOutputDevice();
- ~CompositorSoftwareOutputDevice() override;
-
- void Resize(const gfx::Size& pixel_size, float scale_factor) override;
-
- SkCanvas* BeginPaint(const gfx::Rect& damage_rect) override;
- void EndPaint(cc::SoftwareFrameData* frame_data) override;
- void EnsureBackbuffer() override;
- void DiscardBackbuffer() override;
-
- void ReclaimSoftwareFrame(unsigned id) override;
-
- private:
- // Internal buffer class that manages shared memory lifetime and ownership.
- // It also tracks buffers' history so we can calculate what's the minimum
- // damage rect difference between any two given buffers (see SetParent and
- // FindDamageDifferenceFrom).
- class Buffer {
- public:
- explicit Buffer(unsigned id, scoped_ptr<cc::SharedBitmap> bitmap);
- ~Buffer();
-
- unsigned id() const { return id_; }
-
- void* memory() const { return shared_bitmap_->pixels(); }
- cc::SharedBitmapId shared_bitmap_id() const { return shared_bitmap_->id(); }
-
- bool free() const { return free_; }
- void SetFree(bool free) { free_ = free; }
-
- Buffer* parent() const { return parent_; }
- void SetParent(Buffer* parent, const gfx::Rect& damage);
-
- bool FindDamageDifferenceFrom(Buffer* buffer, SkRegion* result) const;
-
- private:
- const unsigned id_;
- scoped_ptr<cc::SharedBitmap> shared_bitmap_;
- bool free_;
- Buffer* parent_;
- gfx::Rect damage_;
-
- DISALLOW_COPY_AND_ASSIGN(Buffer);
- };
-
- class CompareById {
- public:
- CompareById(unsigned id) : id_(id) {}
-
- bool operator()(const Buffer* buffer) const {
- return buffer->id() == id_;
- }
-
- private:
- const unsigned id_;
- };
-
- unsigned GetNextId();
- Buffer* CreateBuffer();
- size_t FindFreeBuffer(size_t hint);
-
- size_t current_index_;
- unsigned next_buffer_id_;
- ScopedVector<Buffer> buffers_;
- ScopedVector<Buffer> awaiting_ack_;
- cc::SharedBitmapManager* shared_bitmap_manager_;
-};
-
-} // namespace content
-
-#endif // CONTENT_RENDERER_GPU_COMPOSITOR_SOFTWARE_OUTPUT_DEVICE_H_
diff --git a/chromium/content/renderer/gpu/delegated_compositor_output_surface.cc b/chromium/content/renderer/gpu/delegated_compositor_output_surface.cc
index d9ed4963f8d..d767ce4a788 100644
--- a/chromium/content/renderer/gpu/delegated_compositor_output_surface.cc
+++ b/chromium/content/renderer/gpu/delegated_compositor_output_surface.cc
@@ -11,10 +11,12 @@ DelegatedCompositorOutputSurface::DelegatedCompositorOutputSurface(
int32 routing_id,
uint32 output_surface_id,
const scoped_refptr<ContextProviderCommandBuffer>& context_provider,
+ const scoped_refptr<ContextProviderCommandBuffer>& worker_context_provider,
scoped_refptr<FrameSwapMessageQueue> swap_frame_message_queue)
: CompositorOutputSurface(routing_id,
output_surface_id,
context_provider,
+ worker_context_provider,
scoped_ptr<cc::SoftwareOutputDevice>(),
swap_frame_message_queue,
true) {
diff --git a/chromium/content/renderer/gpu/delegated_compositor_output_surface.h b/chromium/content/renderer/gpu/delegated_compositor_output_surface.h
index 6edc2d6b36d..061f1d39667 100644
--- a/chromium/content/renderer/gpu/delegated_compositor_output_surface.h
+++ b/chromium/content/renderer/gpu/delegated_compositor_output_surface.h
@@ -17,6 +17,8 @@ class DelegatedCompositorOutputSurface : public CompositorOutputSurface {
int32 routing_id,
uint32 output_surface_id,
const scoped_refptr<ContextProviderCommandBuffer>& context_provider,
+ const scoped_refptr<ContextProviderCommandBuffer>&
+ worker_context_provider,
scoped_refptr<FrameSwapMessageQueue> swap_frame_message_queue);
~DelegatedCompositorOutputSurface() override {}
};
diff --git a/chromium/content/renderer/gpu/frame_swap_message_queue.cc b/chromium/content/renderer/gpu/frame_swap_message_queue.cc
index bf91dd84e0f..84fcdd4e2ce 100644
--- a/chromium/content/renderer/gpu/frame_swap_message_queue.cc
+++ b/chromium/content/renderer/gpu/frame_swap_message_queue.cc
@@ -146,13 +146,17 @@ void FrameSwapMessageQueue::QueueMessageForFrame(MessageDeliveryPolicy policy,
GetSubQueue(policy)->QueueMessage(source_frame_number, msg.Pass(), is_first);
}
-void FrameSwapMessageQueue::DidSwap(int source_frame_number) {
+void FrameSwapMessageQueue::DidActivate(int source_frame_number) {
base::AutoLock lock(lock_);
-
visual_state_queue_->DrainMessages(source_frame_number,
&next_drain_messages_);
}
+void FrameSwapMessageQueue::DidSwap(int source_frame_number) {
+ base::AutoLock lock(lock_);
+ swap_queue_->DrainMessages(0, &next_drain_messages_);
+}
+
void FrameSwapMessageQueue::DidNotSwap(int source_frame_number,
cc::SwapPromise::DidNotSwapReason reason,
ScopedVector<IPC::Message>* messages) {
@@ -161,20 +165,21 @@ void FrameSwapMessageQueue::DidNotSwap(int source_frame_number,
case cc::SwapPromise::SWAP_FAILS:
case cc::SwapPromise::COMMIT_NO_UPDATE:
swap_queue_->DrainMessages(source_frame_number, messages);
- // fallthrough
- case cc::SwapPromise::COMMIT_FAILS:
visual_state_queue_->DrainMessages(source_frame_number, messages);
break;
- default:
- NOTREACHED();
+ case cc::SwapPromise::COMMIT_FAILS:
+ case cc::SwapPromise::ACTIVATION_FAILS:
+ // Do not queue any responses here. If ACTIVATION_FAILS or
+ // COMMIT_FAILS the renderer is shutting down, which will result
+ // in the RenderFrameHostImpl destructor firing the remaining
+ // response callbacks itself.
+ break;
}
}
void FrameSwapMessageQueue::DrainMessages(
ScopedVector<IPC::Message>* messages) {
lock_.AssertAcquired();
-
- swap_queue_->DrainMessages(0, messages);
messages->insert(messages->end(),
next_drain_messages_.begin(),
next_drain_messages_.end());
diff --git a/chromium/content/renderer/gpu/frame_swap_message_queue.h b/chromium/content/renderer/gpu/frame_swap_message_queue.h
index 6ebaf164243..b12b4176ac2 100644
--- a/chromium/content/renderer/gpu/frame_swap_message_queue.h
+++ b/chromium/content/renderer/gpu/frame_swap_message_queue.h
@@ -13,7 +13,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "base/synchronization/lock.h"
-#include "cc/base/swap_promise.h"
+#include "cc/output/swap_promise.h"
#include "content/common/content_export.h"
#include "content/renderer/message_delivery_policy.h"
@@ -52,14 +52,19 @@ class CONTENT_EXPORT FrameSwapMessageQueue
// Returns true if there are no messages in the queue.
bool Empty() const;
- // Should be called when a successful swap occurs. The messages for that swap
- // can be obtained by calling DrainMessages.
+ // Should be called when a successful activation occurs. The messages for
+ // that activation can be obtained by calling DrainMessages.
+ //
+ // |source_frame_number| frame number for which the activate occurred.
+ void DidActivate(int source_frame_number);
+
+ // Should be called when a successful swap occurs. The messages for that
+ // swap can be obtained by calling DrainMessages.
//
// |source_frame_number| frame number for which the swap occurred.
void DidSwap(int source_frame_number);
- // Should be called when we know a swap will not occur. This also means we
- // won't be expecting a DrainMessages call.
+ // Should be called when we know a swap will not occur.
//
// |source_frame_number| frame number for which the swap will not occur.
// |reason| reason for the which the swap will not occur.
diff --git a/chromium/content/renderer/gpu/frame_swap_message_queue_unittest.cc b/chromium/content/renderer/gpu/frame_swap_message_queue_unittest.cc
index 0b0ba8d1469..80405988717 100644
--- a/chromium/content/renderer/gpu/frame_swap_message_queue_unittest.cc
+++ b/chromium/content/renderer/gpu/frame_swap_message_queue_unittest.cc
@@ -47,6 +47,7 @@ class FrameSwapMessageQueueTest : public testing::Test {
void DrainMessages(int source_frame_number,
ScopedVector<IPC::Message>* messages) {
messages->clear();
+ queue_->DidActivate(source_frame_number);
queue_->DidSwap(source_frame_number);
scoped_ptr<FrameSwapMessageQueue::SendMessageScope> send_message_scope =
queue_->AcquireSendMessageScope();
@@ -92,6 +93,7 @@ TEST_F(FrameSwapMessageQueueTest, TestEmpty) {
ASSERT_TRUE(queue_->Empty());
QueueVisualStateMessage(1, CloneMessage(first_message_));
ASSERT_FALSE(queue_->Empty());
+ queue_->DidActivate(1);
queue_->DidSwap(1);
ASSERT_FALSE(queue_->Empty());
}
@@ -208,17 +210,31 @@ void FrameSwapMessageQueueTest::TestDidNotSwap(
QueueNextSwapMessage(CloneMessage(first_message_));
QueueVisualStateMessage(2, CloneMessage(second_message_));
QueueVisualStateMessage(3, CloneMessage(third_message_));
+ const int rid[] = {first_message_.routing_id(),
+ second_message_.routing_id(),
+ third_message_.routing_id()};
- queue_->DidNotSwap(2, cc::SwapPromise::COMMIT_NO_UPDATE, &messages);
- ASSERT_EQ(2u, messages.size());
- ASSERT_TRUE(HasMessageForId(messages, first_message_.routing_id()));
- ASSERT_TRUE(HasMessageForId(messages, second_message_.routing_id()));
+ bool msg_delivered = reason != cc::SwapPromise::COMMIT_FAILS &&
+ reason != cc::SwapPromise::ACTIVATION_FAILS;
+
+ queue_->DidNotSwap(2, reason, &messages);
+ ASSERT_TRUE(msg_delivered == HasMessageForId(messages, rid[0]));
+ ASSERT_TRUE(msg_delivered == HasMessageForId(messages, rid[1]));
+ ASSERT_FALSE(HasMessageForId(messages, rid[2]));
messages.clear();
- queue_->DidNotSwap(3, cc::SwapPromise::COMMIT_NO_UPDATE, &messages);
- ASSERT_EQ(1u, messages.size());
- ASSERT_TRUE(HasMessageForId(messages, third_message_.routing_id()));
+ queue_->DidNotSwap(3, reason, &messages);
+ ASSERT_FALSE(HasMessageForId(messages, rid[0]));
+ ASSERT_FALSE(HasMessageForId(messages, rid[1]));
+ ASSERT_TRUE(msg_delivered == HasMessageForId(messages, rid[2]));
messages.clear();
+
+ // all undelivered messages should still be available for RenderFrameHostImpl
+ // to deliver.
+ DrainMessages(3, &messages);
+ ASSERT_TRUE(msg_delivered != HasMessageForId(messages, rid[0]));
+ ASSERT_TRUE(msg_delivered != HasMessageForId(messages, rid[1]));
+ ASSERT_TRUE(msg_delivered != HasMessageForId(messages, rid[2]));
}
TEST_F(FrameSwapMessageQueueTest, TestDidNotSwapNoUpdate) {
@@ -230,25 +246,11 @@ TEST_F(FrameSwapMessageQueueTest, TestDidNotSwapSwapFails) {
}
TEST_F(FrameSwapMessageQueueTest, TestDidNotSwapCommitFails) {
- ScopedVector<IPC::Message> messages;
-
- QueueNextSwapMessage(CloneMessage(first_message_));
- QueueVisualStateMessage(2, CloneMessage(second_message_));
- QueueVisualStateMessage(3, CloneMessage(third_message_));
-
- queue_->DidNotSwap(2, cc::SwapPromise::COMMIT_FAILS, &messages);
- ASSERT_EQ(1u, messages.size());
- ASSERT_TRUE(HasMessageForId(messages, second_message_.routing_id()));
- messages.clear();
-
- queue_->DidNotSwap(3, cc::SwapPromise::COMMIT_FAILS, &messages);
- ASSERT_EQ(1u, messages.size());
- ASSERT_TRUE(HasMessageForId(messages, third_message_.routing_id()));
- messages.clear();
+ TestDidNotSwap(cc::SwapPromise::COMMIT_FAILS);
+}
- DrainMessages(1, &messages);
- ASSERT_EQ(1u, messages.size());
- ASSERT_TRUE(HasMessageForId(messages, first_message_.routing_id()));
+TEST_F(FrameSwapMessageQueueTest, TestDidNotSwapActivationFails) {
+ TestDidNotSwap(cc::SwapPromise::ACTIVATION_FAILS);
}
class NotifiesDeletionMessage : public IPC::Message {
@@ -283,6 +285,7 @@ TEST_F(FrameSwapMessageQueueTest, TestDeletesQueuedVisualStateMessage) {
QueueVisualStateMessage(1,
make_scoped_ptr(new NotifiesDeletionMessage(
&message_deleted, first_message_)));
+ queue_->DidActivate(1);
queue_->DidSwap(1);
queue_ = NULL;
ASSERT_TRUE(message_deleted);
diff --git a/chromium/content/renderer/gpu/gpu_benchmarking_extension.cc b/chromium/content/renderer/gpu/gpu_benchmarking_extension.cc
index f57a9a781e4..366d0a8b68a 100644
--- a/chromium/content/renderer/gpu/gpu_benchmarking_extension.cc
+++ b/chromium/content/renderer/gpu/gpu_benchmarking_extension.cc
@@ -14,10 +14,11 @@
#include "cc/layers/layer.h"
#include "content/common/input/synthetic_gesture_params.h"
#include "content/common/input/synthetic_pinch_gesture_params.h"
+#include "content/common/input/synthetic_smooth_drag_gesture_params.h"
#include "content/common/input/synthetic_smooth_scroll_gesture_params.h"
#include "content/common/input/synthetic_tap_gesture_params.h"
+#include "content/public/child/v8_value_converter.h"
#include "content/public/renderer/render_thread.h"
-#include "content/public/renderer/v8_value_converter.h"
#include "content/renderer/chrome_object_extensions_utils.h"
#include "content/renderer/gpu/render_widget_compositor.h"
#include "content/renderer/render_thread_impl.h"
@@ -34,6 +35,7 @@
#include "third_party/skia/include/core/SkGraphics.h"
#include "third_party/skia/include/core/SkPicture.h"
#include "third_party/skia/include/core/SkPixelRef.h"
+#include "third_party/skia/include/core/SkPixelSerializer.h"
#include "third_party/skia/include/core/SkStream.h"
#include "ui/gfx/codec/png_codec.h"
#include "v8/include/v8.h"
@@ -49,21 +51,24 @@ namespace content {
namespace {
-// offset parameter is deprecated/ignored, and will be remove from the
-// signature in a future skia release. <reed@google.com>
-SkData* EncodeBitmapToData(size_t* offset, const SkBitmap& bm) {
- SkPixelRef* pr = bm.pixelRef();
- if (pr != NULL) {
- SkData* data = pr->refEncodedData();
- if (data != NULL)
- return data;
- }
- std::vector<unsigned char> vector;
- if (gfx::PNGCodec::EncodeBGRASkBitmap(bm, false, &vector)) {
- return SkData::NewWithCopy(&vector.front(), vector.size());
+class PNGSerializer : public SkPixelSerializer {
+ protected:
+ bool onUseEncodedData(const void* data, size_t len) override { return true; }
+
+ SkData* onEncodePixels(const SkImageInfo& info,
+ const void* pixels,
+ size_t row_bytes) override {
+ SkBitmap bm;
+ // The const_cast is fine, since we only read from the bitmap.
+ if (bm.installPixels(info, const_cast<void*>(pixels), row_bytes)) {
+ std::vector<unsigned char> vector;
+ if (gfx::PNGCodec::EncodeBGRASkBitmap(bm, false, &vector)) {
+ return SkData::NewWithCopy(&vector.front(), vector.size());
+ }
+ }
+ return nullptr;
}
- return NULL;
-}
+};
class SkPictureSerializer {
public:
@@ -97,7 +102,9 @@ class SkPictureSerializer {
DCHECK(!filepath.empty());
SkFILEWStream file(filepath.c_str());
DCHECK(file.isValid());
- picture->serialize(&file, &EncodeBitmapToData);
+
+ PNGSerializer serializer;
+ picture->serialize(&file, &serializer);
}
private:
@@ -136,8 +143,8 @@ bool GetOptionalArg(gin::Arguments* args, T* value) {
class CallbackAndContext : public base::RefCounted<CallbackAndContext> {
public:
CallbackAndContext(v8::Isolate* isolate,
- v8::Handle<v8::Function> callback,
- v8::Handle<v8::Context> context)
+ v8::Local<v8::Function> callback,
+ v8::Local<v8::Context> context)
: isolate_(isolate) {
callback_.Reset(isolate_, callback);
context_.Reset(isolate_, context);
@@ -147,11 +154,11 @@ class CallbackAndContext : public base::RefCounted<CallbackAndContext> {
return isolate_;
}
- v8::Handle<v8::Function> GetCallback() {
+ v8::Local<v8::Function> GetCallback() {
return v8::Local<v8::Function>::New(isolate_, callback_);
}
- v8::Handle<v8::Context> GetContext() {
+ v8::Local<v8::Context> GetContext() {
return v8::Local<v8::Context>::New(isolate_, context_);
}
@@ -240,14 +247,14 @@ void OnMicroBenchmarkCompleted(
scoped_ptr<base::Value> result) {
v8::Isolate* isolate = callback_and_context->isolate();
v8::HandleScope scope(isolate);
- v8::Handle<v8::Context> context = callback_and_context->GetContext();
+ v8::Local<v8::Context> context = callback_and_context->GetContext();
v8::Context::Scope context_scope(context);
WebLocalFrame* frame = WebLocalFrame::frameForContext(context);
if (frame) {
scoped_ptr<V8ValueConverter> converter =
make_scoped_ptr(V8ValueConverter::create());
- v8::Handle<v8::Value> value = converter->ToV8Value(result.get(), context);
- v8::Handle<v8::Value> argv[] = { value };
+ v8::Local<v8::Value> value = converter->ToV8Value(result.get(), context);
+ v8::Local<v8::Value> argv[] = { value };
frame->callFunctionEvenIfScriptDisabled(
callback_and_context->GetCallback(),
@@ -257,54 +264,10 @@ void OnMicroBenchmarkCompleted(
}
}
-void OnSnapshotCompleted(CallbackAndContext* callback_and_context,
- const gfx::Size& size,
- const std::vector<unsigned char>& png) {
- v8::Isolate* isolate = callback_and_context->isolate();
- v8::HandleScope scope(isolate);
- v8::Handle<v8::Context> context = callback_and_context->GetContext();
- v8::Context::Scope context_scope(context);
- WebLocalFrame* frame = WebLocalFrame::frameForContext(context);
- if (frame) {
- v8::Handle<v8::Value> result;
-
- if (!size.IsEmpty()) {
- v8::Handle<v8::Object> result_object;
- result_object = v8::Object::New(isolate);
-
- result_object->Set(v8::String::NewFromUtf8(isolate, "width"),
- v8::Number::New(isolate, size.width()));
- result_object->Set(v8::String::NewFromUtf8(isolate, "height"),
- v8::Number::New(isolate, size.height()));
-
- std::string base64_png;
- base::Base64Encode(
- base::StringPiece(reinterpret_cast<const char*>(&*png.begin()),
- png.size()),
- &base64_png);
-
- result_object->Set(v8::String::NewFromUtf8(isolate, "data"),
- v8::String::NewFromUtf8(isolate,
- base64_png.c_str(),
- v8::String::kNormalString,
- base64_png.size()));
-
- result = result_object;
- } else {
- result = v8::Null(isolate);
- }
-
- v8::Handle<v8::Value> argv[] = {result};
-
- frame->callFunctionEvenIfScriptDisabled(
- callback_and_context->GetCallback(), v8::Object::New(isolate), 1, argv);
- }
-}
-
void OnSyntheticGestureCompleted(CallbackAndContext* callback_and_context) {
v8::Isolate* isolate = callback_and_context->isolate();
v8::HandleScope scope(isolate);
- v8::Handle<v8::Context> context = callback_and_context->GetContext();
+ v8::Local<v8::Context> context = callback_and_context->GetContext();
v8::Context::Scope context_scope(context);
WebLocalFrame* frame = WebLocalFrame::frameForContext(context);
if (frame) {
@@ -314,14 +277,14 @@ void OnSyntheticGestureCompleted(CallbackAndContext* callback_and_context) {
}
bool BeginSmoothScroll(v8::Isolate* isolate,
- int pixels_to_scroll,
- v8::Handle<v8::Function> callback,
+ float pixels_to_scroll,
+ v8::Local<v8::Function> callback,
int gesture_source_type,
const std::string& direction,
- int speed_in_pixels_s,
+ float speed_in_pixels_s,
bool prevent_fling,
- int start_x,
- int start_y) {
+ float start_x,
+ float start_y) {
GpuBenchmarkingContext context;
if (!context.Init(false))
return false;
@@ -350,8 +313,8 @@ bool BeginSmoothScroll(v8::Isolate* isolate,
gesture_params->anchor.SetPoint(start_x * page_scale_factor,
start_y * page_scale_factor);
- int distance_length = pixels_to_scroll * page_scale_factor;
- gfx::Vector2d distance;
+ float distance_length = pixels_to_scroll * page_scale_factor;
+ gfx::Vector2dF distance;
if (direction == "down")
distance.set_y(-distance_length);
else if (direction == "up")
@@ -360,7 +323,19 @@ bool BeginSmoothScroll(v8::Isolate* isolate,
distance.set_x(-distance_length);
else if (direction == "left")
distance.set_x(distance_length);
- else {
+ else if (direction == "upleft") {
+ distance.set_y(distance_length);
+ distance.set_x(distance_length);
+ } else if (direction == "upright") {
+ distance.set_y(distance_length);
+ distance.set_x(-distance_length);
+ } else if (direction == "downleft") {
+ distance.set_y(-distance_length);
+ distance.set_x(distance_length);
+ } else if (direction == "downright") {
+ distance.set_y(-distance_length);
+ distance.set_x(-distance_length);
+ } else {
return false;
}
gesture_params->distances.push_back(distance);
@@ -375,6 +350,48 @@ bool BeginSmoothScroll(v8::Isolate* isolate,
return true;
}
+bool BeginSmoothDrag(v8::Isolate* isolate,
+ float start_x,
+ float start_y,
+ float end_x,
+ float end_y,
+ v8::Local<v8::Function> callback,
+ int gesture_source_type,
+ float speed_in_pixels_s) {
+ GpuBenchmarkingContext context;
+ if (!context.Init(false))
+ return false;
+ scoped_refptr<CallbackAndContext> callback_and_context =
+ new CallbackAndContext(isolate, callback,
+ context.web_frame()->mainWorldScriptContext());
+
+ scoped_ptr<SyntheticSmoothDragGestureParams> gesture_params(
+ new SyntheticSmoothDragGestureParams);
+
+ // Convert coordinates from CSS pixels to density independent pixels (DIPs).
+ float page_scale_factor = context.web_view()->pageScaleFactor();
+
+ gesture_params->start_point.SetPoint(start_x * page_scale_factor,
+ start_y * page_scale_factor);
+ gfx::PointF end_point(end_x * page_scale_factor,
+ end_y * page_scale_factor);
+ gfx::Vector2dF distance = end_point - gesture_params->start_point;
+ gesture_params->distances.push_back(distance);
+ gesture_params->speed_in_pixels_s = speed_in_pixels_s * page_scale_factor;
+ gesture_params->gesture_source_type =
+ static_cast<SyntheticGestureParams::GestureSourceType>(
+ gesture_source_type);
+
+ // TODO(nduca): If the render_view_impl is destroyed while the gesture is in
+ // progress, we will leak the callback and context. This needs to be fixed,
+ // somehow.
+ context.render_view_impl()->QueueSyntheticGesture(
+ gesture_params.Pass(),
+ base::Bind(&OnSyntheticGestureCompleted, callback_and_context));
+
+ return true;
+}
+
} // namespace
gin::WrapperInfo GpuBenchmarking::kWrapperInfo = {gin::kEmbedderNativeGin};
@@ -383,7 +400,7 @@ gin::WrapperInfo GpuBenchmarking::kWrapperInfo = {gin::kEmbedderNativeGin};
void GpuBenchmarking::Install(blink::WebFrame* frame) {
v8::Isolate* isolate = blink::mainThreadIsolate();
v8::HandleScope handle_scope(isolate);
- v8::Handle<v8::Context> context = frame->mainWorldScriptContext();
+ v8::Local<v8::Context> context = frame->mainWorldScriptContext();
if (context.IsEmpty())
return;
@@ -394,7 +411,7 @@ void GpuBenchmarking::Install(blink::WebFrame* frame) {
if (controller.IsEmpty())
return;
- v8::Handle<v8::Object> chrome = GetOrCreateChromeObject(isolate,
+ v8::Local<v8::Object> chrome = GetOrCreateChromeObject(isolate,
context->Global());
chrome->Set(gin::StringToV8(isolate, "gpuBenchmarking"), controller.ToV8());
}
@@ -419,6 +436,7 @@ gin::ObjectTemplateBuilder GpuBenchmarking::GetObjectTemplateBuilder(
.SetMethod("gestureSourceTypeSupported",
&GpuBenchmarking::GestureSourceTypeSupported)
.SetMethod("smoothScrollBy", &GpuBenchmarking::SmoothScrollBy)
+ .SetMethod("smoothDrag", &GpuBenchmarking::SmoothDrag)
.SetMethod("swipe", &GpuBenchmarking::Swipe)
.SetMethod("scrollBounce", &GpuBenchmarking::ScrollBounce)
// TODO(dominikg): Remove once JS interface changes have rolled into
@@ -426,8 +444,6 @@ gin::ObjectTemplateBuilder GpuBenchmarking::GetObjectTemplateBuilder(
.SetValue("newPinchInterface", true)
.SetMethod("pinchBy", &GpuBenchmarking::PinchBy)
.SetMethod("tap", &GpuBenchmarking::Tap)
- .SetMethod("beginWindowSnapshotPNG",
- &GpuBenchmarking::BeginWindowSnapshotPNG)
.SetMethod("clearImageCache", &GpuBenchmarking::ClearImageCache)
.SetMethod("runMicroBenchmark", &GpuBenchmarking::RunMicroBenchmark)
.SetMethod("sendMessageToMicroBenchmark",
@@ -494,13 +510,13 @@ bool GpuBenchmarking::SmoothScrollBy(gin::Arguments* args) {
float page_scale_factor = context.web_view()->pageScaleFactor();
blink::WebRect rect = context.render_view_impl()->windowRect();
- int pixels_to_scroll = 0;
- v8::Handle<v8::Function> callback;
- int start_x = rect.width / (page_scale_factor * 2);
- int start_y = rect.height / (page_scale_factor * 2);
- int gesture_source_type = 0; // DEFAULT_INPUT
+ float pixels_to_scroll = 0;
+ v8::Local<v8::Function> callback;
+ float start_x = rect.width / (page_scale_factor * 2);
+ float start_y = rect.height / (page_scale_factor * 2);
+ int gesture_source_type = SyntheticGestureParams::DEFAULT_INPUT;
std::string direction = "down";
- int speed_in_pixels_s = 800;
+ float speed_in_pixels_s = 800;
if (!GetOptionalArg(args, &pixels_to_scroll) ||
!GetOptionalArg(args, &callback) ||
@@ -523,6 +539,39 @@ bool GpuBenchmarking::SmoothScrollBy(gin::Arguments* args) {
start_y);
}
+bool GpuBenchmarking::SmoothDrag(gin::Arguments* args) {
+ GpuBenchmarkingContext context;
+ if (!context.Init(true))
+ return false;
+
+ float start_x;
+ float start_y;
+ float end_x;
+ float end_y;
+ v8::Local<v8::Function> callback;
+ int gesture_source_type = SyntheticGestureParams::DEFAULT_INPUT;
+ float speed_in_pixels_s = 800;
+
+ if (!GetArg(args, &start_x) ||
+ !GetArg(args, &start_y) ||
+ !GetArg(args, &end_x) ||
+ !GetArg(args, &end_y) ||
+ !GetOptionalArg(args, &callback) ||
+ !GetOptionalArg(args, &gesture_source_type) ||
+ !GetOptionalArg(args, &speed_in_pixels_s)) {
+ return false;
+ }
+
+ return BeginSmoothDrag(args->isolate(),
+ start_x,
+ start_y,
+ end_x,
+ end_y,
+ callback,
+ gesture_source_type,
+ speed_in_pixels_s);
+}
+
bool GpuBenchmarking::Swipe(gin::Arguments* args) {
GpuBenchmarkingContext context;
if (!context.Init(true))
@@ -532,11 +581,11 @@ bool GpuBenchmarking::Swipe(gin::Arguments* args) {
blink::WebRect rect = context.render_view_impl()->windowRect();
std::string direction = "up";
- int pixels_to_scroll = 0;
- v8::Handle<v8::Function> callback;
- int start_x = rect.width / (page_scale_factor * 2);
- int start_y = rect.height / (page_scale_factor * 2);
- int speed_in_pixels_s = 800;
+ float pixels_to_scroll = 0;
+ v8::Local<v8::Function> callback;
+ float start_x = rect.width / (page_scale_factor * 2);
+ float start_y = rect.height / (page_scale_factor * 2);
+ float speed_in_pixels_s = 800;
if (!GetOptionalArg(args, &direction) ||
!GetOptionalArg(args, &pixels_to_scroll) ||
@@ -567,13 +616,13 @@ bool GpuBenchmarking::ScrollBounce(gin::Arguments* args) {
blink::WebRect rect = context.render_view_impl()->windowRect();
std::string direction = "down";
- int distance_length = 0;
- int overscroll_length = 0;
+ float distance_length = 0;
+ float overscroll_length = 0;
int repeat_count = 1;
- v8::Handle<v8::Function> callback;
- int start_x = rect.width / (page_scale_factor * 2);
- int start_y = rect.height / (page_scale_factor * 2);
- int speed_in_pixels_s = 800;
+ v8::Local<v8::Function> callback;
+ float start_x = rect.width / (page_scale_factor * 2);
+ float start_y = rect.height / (page_scale_factor * 2);
+ float speed_in_pixels_s = 800;
if (!GetOptionalArg(args, &direction) ||
!GetOptionalArg(args, &distance_length) ||
@@ -601,8 +650,8 @@ bool GpuBenchmarking::ScrollBounce(gin::Arguments* args) {
distance_length *= page_scale_factor;
overscroll_length *= page_scale_factor;
- gfx::Vector2d distance;
- gfx::Vector2d overscroll;
+ gfx::Vector2dF distance;
+ gfx::Vector2dF overscroll;
if (direction == "down") {
distance.set_y(-distance_length);
overscroll.set_y(overscroll_length);
@@ -640,10 +689,10 @@ bool GpuBenchmarking::PinchBy(gin::Arguments* args) {
return false;
float scale_factor;
- int anchor_x;
- int anchor_y;
- v8::Handle<v8::Function> callback;
- int relative_pointer_speed_in_pixels_s = 800;
+ float anchor_x;
+ float anchor_y;
+ v8::Local<v8::Function> callback;
+ float relative_pointer_speed_in_pixels_s = 800;
if (!GetArg(args, &scale_factor) ||
@@ -687,11 +736,11 @@ bool GpuBenchmarking::Tap(gin::Arguments* args) {
if (!context.Init(false))
return false;
- int position_x;
- int position_y;
- v8::Handle<v8::Function> callback;
+ float position_x;
+ float position_y;
+ v8::Local<v8::Function> callback;
int duration_ms = 50;
- int gesture_source_type = 0; // DEFAULT_INPUT
+ int gesture_source_type = SyntheticGestureParams::DEFAULT_INPUT;
if (!GetArg(args, &position_x) ||
!GetArg(args, &position_y) ||
@@ -734,22 +783,6 @@ bool GpuBenchmarking::Tap(gin::Arguments* args) {
return true;
}
-void GpuBenchmarking::BeginWindowSnapshotPNG(
- v8::Isolate* isolate,
- v8::Handle<v8::Function> callback) {
- GpuBenchmarkingContext context;
- if (!context.Init(false))
- return;
-
- scoped_refptr<CallbackAndContext> callback_and_context =
- new CallbackAndContext(isolate,
- callback,
- context.web_frame()->mainWorldScriptContext());
-
- context.render_view_impl()->GetWindowSnapshot(
- base::Bind(&OnSnapshotCompleted, callback_and_context));
-}
-
void GpuBenchmarking::ClearImageCache() {
WebImageCache::clear();
}
@@ -760,8 +793,8 @@ int GpuBenchmarking::RunMicroBenchmark(gin::Arguments* args) {
return 0;
std::string name;
- v8::Handle<v8::Function> callback;
- v8::Handle<v8::Object> arguments;
+ v8::Local<v8::Function> callback;
+ v8::Local<v8::Object> arguments;
if (!GetArg(args, &name) || !GetArg(args, &callback) ||
!GetOptionalArg(args, &arguments)) {
@@ -775,7 +808,7 @@ int GpuBenchmarking::RunMicroBenchmark(gin::Arguments* args) {
scoped_ptr<V8ValueConverter> converter =
make_scoped_ptr(V8ValueConverter::create());
- v8::Handle<v8::Context> v8_context = callback_and_context->GetContext();
+ v8::Local<v8::Context> v8_context = callback_and_context->GetContext();
scoped_ptr<base::Value> value =
make_scoped_ptr(converter->FromV8Value(arguments, v8_context));
@@ -787,14 +820,14 @@ int GpuBenchmarking::RunMicroBenchmark(gin::Arguments* args) {
bool GpuBenchmarking::SendMessageToMicroBenchmark(
int id,
- v8::Handle<v8::Object> message) {
+ v8::Local<v8::Object> message) {
GpuBenchmarkingContext context;
if (!context.Init(true))
return false;
scoped_ptr<V8ValueConverter> converter =
make_scoped_ptr(V8ValueConverter::create());
- v8::Handle<v8::Context> v8_context =
+ v8::Local<v8::Context> v8_context =
context.web_frame()->mainWorldScriptContext();
scoped_ptr<base::Value> value =
make_scoped_ptr(converter->FromV8Value(message, v8_context));
diff --git a/chromium/content/renderer/gpu/gpu_benchmarking_extension.h b/chromium/content/renderer/gpu/gpu_benchmarking_extension.h
index d4736dd840e..f2ff89d044a 100644
--- a/chromium/content/renderer/gpu/gpu_benchmarking_extension.h
+++ b/chromium/content/renderer/gpu/gpu_benchmarking_extension.h
@@ -20,7 +20,6 @@ namespace v8 {
class Function;
class Isolate;
class Object;
-template <typename T> class Handle;
}
namespace content {
@@ -45,15 +44,14 @@ class GpuBenchmarking : public gin::Wrappable<GpuBenchmarking> {
void PrintToSkPicture(v8::Isolate* isolate, const std::string& dirname);
bool GestureSourceTypeSupported(int gesture_source_type);
bool SmoothScrollBy(gin::Arguments* args);
+ bool SmoothDrag(gin::Arguments* args);
bool Swipe(gin::Arguments* args);
bool ScrollBounce(gin::Arguments* args);
bool PinchBy(gin::Arguments* args);
bool Tap(gin::Arguments* args);
- void BeginWindowSnapshotPNG(v8::Isolate* isolate,
- v8::Handle<v8::Function> callback);
void ClearImageCache();
int RunMicroBenchmark(gin::Arguments* args);
- bool SendMessageToMicroBenchmark(int id, v8::Handle<v8::Object> message);
+ bool SendMessageToMicroBenchmark(int id, v8::Local<v8::Object> message);
bool HasGpuProcess();
DISALLOW_COPY_AND_ASSIGN(GpuBenchmarking);
@@ -61,4 +59,4 @@ class GpuBenchmarking : public gin::Wrappable<GpuBenchmarking> {
} // namespace content
-#endif // CONTENT_RENDERER_GPU_GPU_BENCHMARKING_EXTENSION_H_
+#endif // CONTENT_RENDERER_GPU_GPU_BENCHMARKING_EXTENSION_H_
diff --git a/chromium/content/renderer/gpu/mailbox_output_surface.cc b/chromium/content/renderer/gpu/mailbox_output_surface.cc
index 6389f93856b..dbf7acbf7bb 100644
--- a/chromium/content/renderer/gpu/mailbox_output_surface.cc
+++ b/chromium/content/renderer/gpu/mailbox_output_surface.cc
@@ -26,12 +26,14 @@ MailboxOutputSurface::MailboxOutputSurface(
int32 routing_id,
uint32 output_surface_id,
const scoped_refptr<ContextProviderCommandBuffer>& context_provider,
+ const scoped_refptr<ContextProviderCommandBuffer>& worker_context_provider,
scoped_ptr<cc::SoftwareOutputDevice> software_device,
scoped_refptr<FrameSwapMessageQueue> swap_frame_message_queue,
cc::ResourceFormat format)
: CompositorOutputSurface(routing_id,
output_surface_id,
context_provider,
+ worker_context_provider,
software_device.Pass(),
swap_frame_message_queue,
true),
diff --git a/chromium/content/renderer/gpu/mailbox_output_surface.h b/chromium/content/renderer/gpu/mailbox_output_surface.h
index fc6ba221c13..098b9a9873f 100644
--- a/chromium/content/renderer/gpu/mailbox_output_surface.h
+++ b/chromium/content/renderer/gpu/mailbox_output_surface.h
@@ -11,7 +11,7 @@
#include "cc/resources/resource_format.h"
#include "cc/resources/transferable_resource.h"
#include "content/renderer/gpu/compositor_output_surface.h"
-#include "ui/gfx/size.h"
+#include "ui/gfx/geometry/size.h"
namespace cc {
class CompositorFrameAck;
@@ -30,6 +30,8 @@ class MailboxOutputSurface : public CompositorOutputSurface {
int32 routing_id,
uint32 output_surface_id,
const scoped_refptr<ContextProviderCommandBuffer>& context_provider,
+ const scoped_refptr<ContextProviderCommandBuffer>&
+ worker_context_provider,
scoped_ptr<cc::SoftwareOutputDevice> software_device,
scoped_refptr<FrameSwapMessageQueue> swap_frame_message_queue,
cc::ResourceFormat format);
diff --git a/chromium/content/renderer/gpu/queue_message_swap_promise.cc b/chromium/content/renderer/gpu/queue_message_swap_promise.cc
index 1cb5316e166..ff524418b7f 100644
--- a/chromium/content/renderer/gpu/queue_message_swap_promise.cc
+++ b/chromium/content/renderer/gpu/queue_message_swap_promise.cc
@@ -16,7 +16,7 @@ QueueMessageSwapPromise::QueueMessageSwapPromise(
: message_sender_(message_sender),
message_queue_(message_queue),
source_frame_number_(source_frame_number)
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
,
completed_(false)
#endif
@@ -27,13 +27,21 @@ QueueMessageSwapPromise::QueueMessageSwapPromise(
QueueMessageSwapPromise::~QueueMessageSwapPromise() {
// The promise should have either been kept or broken before it's deleted.
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
DCHECK(completed_);
#endif
}
+void QueueMessageSwapPromise::DidActivate() {
+#if DCHECK_IS_ON()
+ DCHECK(!completed_);
+#endif
+ message_queue_->DidActivate(source_frame_number_);
+ // The OutputSurface will take care of the Drain+Send.
+}
+
void QueueMessageSwapPromise::DidSwap(cc::CompositorFrameMetadata* metadata) {
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
DCHECK(!completed_);
#endif
message_queue_->DidSwap(source_frame_number_);
@@ -42,7 +50,7 @@ void QueueMessageSwapPromise::DidSwap(cc::CompositorFrameMetadata* metadata) {
}
void QueueMessageSwapPromise::DidNotSwap(DidNotSwapReason reason) {
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
DCHECK(!completed_);
#endif
ScopedVector<IPC::Message> messages;
@@ -57,7 +65,7 @@ void QueueMessageSwapPromise::DidNotSwap(DidNotSwapReason reason) {
}
void QueueMessageSwapPromise::PromiseCompleted() {
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
completed_ = true;
#endif
}
diff --git a/chromium/content/renderer/gpu/queue_message_swap_promise.h b/chromium/content/renderer/gpu/queue_message_swap_promise.h
index 4094b1b96ec..37198b253e2 100644
--- a/chromium/content/renderer/gpu/queue_message_swap_promise.h
+++ b/chromium/content/renderer/gpu/queue_message_swap_promise.h
@@ -2,12 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CONTENT_RENDERER_QUEUE_MESSAGE_SWAP_PROMISE_H_
-#define CONTENT_RENDERER_QUEUE_MESSAGE_SWAP_PROMISE_H_
+#ifndef CONTENT_RENDERER_GPU_QUEUE_MESSAGE_SWAP_PROMISE_H_
+#define CONTENT_RENDERER_GPU_QUEUE_MESSAGE_SWAP_PROMISE_H_
#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "cc/base/swap_promise.h"
+#include "cc/output/swap_promise.h"
namespace IPC {
class SyncMessageFilter;
@@ -25,8 +24,8 @@ class QueueMessageSwapPromise : public cc::SwapPromise {
~QueueMessageSwapPromise() override;
+ void DidActivate() override;
void DidSwap(cc::CompositorFrameMetadata* metadata) override;
-
void DidNotSwap(DidNotSwapReason reason) override;
int64 TraceId() const override;
@@ -37,11 +36,11 @@ class QueueMessageSwapPromise : public cc::SwapPromise {
scoped_refptr<IPC::SyncMessageFilter> message_sender_;
scoped_refptr<content::FrameSwapMessageQueue> message_queue_;
int source_frame_number_;
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
bool completed_;
#endif
};
} // namespace content
-#endif // CONTENT_RENDERER_QUEUE_MESSAGE_SWAP_PROMISE_H_
+#endif // CONTENT_RENDERER_GPU_QUEUE_MESSAGE_SWAP_PROMISE_H_
diff --git a/chromium/content/renderer/gpu/queue_message_swap_promise_unittest.cc b/chromium/content/renderer/gpu/queue_message_swap_promise_unittest.cc
index 101055e8b04..1261cb2bae6 100644
--- a/chromium/content/renderer/gpu/queue_message_swap_promise_unittest.cc
+++ b/chromium/content/renderer/gpu/queue_message_swap_promise_unittest.cc
@@ -7,7 +7,7 @@
#include <vector>
#include "base/memory/scoped_vector.h"
-#include "cc/base/swap_promise.h"
+#include "cc/output/swap_promise.h"
#include "content/renderer/gpu/frame_swap_message_queue.h"
#include "content/renderer/gpu/render_widget_compositor.h"
#include "content/renderer/render_widget.h"
@@ -50,7 +50,6 @@ class TestSyncMessageFilter : public IPC::SyncMessageFilter {
struct QueueMessageData {
MessageDeliveryPolicy policy;
- bool commit_requested;
int source_frame_number;
};
@@ -64,13 +63,11 @@ class QueueMessageSwapPromiseTest : public testing::Test {
scoped_ptr<cc::SwapPromise> QueueMessageImpl(IPC::Message* msg,
MessageDeliveryPolicy policy,
- bool commit_requested,
int source_frame_number) {
return TestRenderWidget::QueueMessageImpl(msg,
policy,
frame_swap_message_queue_.get(),
sync_message_filter_,
- commit_requested,
source_frame_number).Pass();
}
@@ -110,7 +107,6 @@ class QueueMessageSwapPromiseTest : public testing::Test {
promises_.push_back(
QueueMessageImpl(new IPC::Message(messages_[i]),
data[i].policy,
- data[i].commit_requested,
data[i].source_frame_number).release());
}
}
@@ -119,8 +115,10 @@ class QueueMessageSwapPromiseTest : public testing::Test {
for (ScopedVector<cc::SwapPromise>::iterator i = promises_.begin();
i != promises_.end();
++i) {
- if (*i)
+ if (*i) {
+ (*i)->DidActivate();
(*i)->DidSwap(NULL);
+ }
}
}
@@ -128,6 +126,7 @@ class QueueMessageSwapPromiseTest : public testing::Test {
void VisualStateSwapPromiseDidNotSwap(
cc::SwapPromise::DidNotSwapReason reason);
+ base::MessageLoop message_loop_;
scoped_refptr<FrameSwapMessageQueue> frame_swap_message_queue_;
scoped_refptr<TestSyncMessageFilter> sync_message_filter_;
std::vector<IPC::Message> messages_;
@@ -141,24 +140,26 @@ class QueueMessageSwapPromiseTest : public testing::Test {
TEST_F(QueueMessageSwapPromiseTest, NextSwapPolicySchedulesMessageForNextSwap) {
QueueMessageData data[] = {
- /* { policy, commit_requested, source_frame_number } */
- {MESSAGE_DELIVERY_POLICY_WITH_NEXT_SWAP, false, 1},
+ /* { policy, source_frame_number } */
+ {MESSAGE_DELIVERY_POLICY_WITH_NEXT_SWAP, 1},
};
QueueMessages(data, arraysize(data));
ASSERT_TRUE(promises_[0]);
+ promises_[0]->DidActivate();
+ promises_[0]->DidSwap(NULL);
+
EXPECT_TRUE(DirectSendMessages().empty());
EXPECT_FALSE(frame_swap_message_queue_->Empty());
+ // frame_swap_message_queue_->DidSwap(1);
EXPECT_TRUE(NextSwapHasMessage(messages_[0]));
-
- CleanupPromises();
}
TEST_F(QueueMessageSwapPromiseTest, NextSwapPolicyNeedsAtMostOnePromise) {
QueueMessageData data[] = {
- /* { policy, commit_requested, source_frame_number } */
- {MESSAGE_DELIVERY_POLICY_WITH_NEXT_SWAP, false, 1},
- {MESSAGE_DELIVERY_POLICY_WITH_NEXT_SWAP, false, 1},
+ /* { policy, source_frame_number } */
+ {MESSAGE_DELIVERY_POLICY_WITH_NEXT_SWAP, 1},
+ {MESSAGE_DELIVERY_POLICY_WITH_NEXT_SWAP, 1},
};
QueueMessages(data, arraysize(data));
@@ -170,8 +171,8 @@ TEST_F(QueueMessageSwapPromiseTest, NextSwapPolicyNeedsAtMostOnePromise) {
TEST_F(QueueMessageSwapPromiseTest, NextSwapPolicySendsMessageOnNoUpdate) {
QueueMessageData data[] = {
- /* { policy, commit_requested, source_frame_number } */
- {MESSAGE_DELIVERY_POLICY_WITH_NEXT_SWAP, false, 1},
+ /* { policy, source_frame_number } */
+ {MESSAGE_DELIVERY_POLICY_WITH_NEXT_SWAP, 1},
};
QueueMessages(data, arraysize(data));
@@ -183,8 +184,8 @@ TEST_F(QueueMessageSwapPromiseTest, NextSwapPolicySendsMessageOnNoUpdate) {
TEST_F(QueueMessageSwapPromiseTest, NextSwapPolicySendsMessageOnSwapFails) {
QueueMessageData data[] = {
- /* { policy, commit_requested, source_frame_number } */
- {MESSAGE_DELIVERY_POLICY_WITH_NEXT_SWAP, false, 1},
+ /* { policy, source_frame_number } */
+ {MESSAGE_DELIVERY_POLICY_WITH_NEXT_SWAP, 1},
};
QueueMessages(data, arraysize(data));
@@ -196,35 +197,23 @@ TEST_F(QueueMessageSwapPromiseTest, NextSwapPolicySendsMessageOnSwapFails) {
TEST_F(QueueMessageSwapPromiseTest, NextSwapPolicyRetainsMessageOnCommitFails) {
QueueMessageData data[] = {
- /* { policy, commit_requested, source_frame_number } */
- {MESSAGE_DELIVERY_POLICY_WITH_NEXT_SWAP, false, 1},
+ /* { policy, source_frame_number } */
+ {MESSAGE_DELIVERY_POLICY_WITH_NEXT_SWAP, 1},
};
QueueMessages(data, arraysize(data));
promises_[0]->DidNotSwap(cc::SwapPromise::COMMIT_FAILS);
EXPECT_TRUE(DirectSendMessages().empty());
EXPECT_FALSE(frame_swap_message_queue_->Empty());
+ frame_swap_message_queue_->DidSwap(2);
EXPECT_TRUE(NextSwapHasMessage(messages_[0]));
}
-TEST_F(QueueMessageSwapPromiseTest, VisualStateDirectSend) {
- QueueMessageData data[] = {
- /* { policy, commit_requested, source_frame_number } */
- {MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE, false, 1},
- };
- QueueMessages(data, arraysize(data));
-
- ASSERT_FALSE(promises_[0]);
- EXPECT_FALSE(DirectSendMessages().empty());
- EXPECT_TRUE(frame_swap_message_queue_->Empty());
- EXPECT_TRUE(NextSwapMessages().empty());
-}
-
TEST_F(QueueMessageSwapPromiseTest,
VisualStateQueuesMessageWhenCommitRequested) {
QueueMessageData data[] = {
- /* { policy, commit_requested, source_frame_number } */
- {MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE, true, 1},
+ /* { policy, source_frame_number } */
+ {MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE, 1},
};
QueueMessages(data, arraysize(data));
@@ -239,9 +228,9 @@ TEST_F(QueueMessageSwapPromiseTest,
TEST_F(QueueMessageSwapPromiseTest,
VisualStateQueuesMessageWhenOtherMessageAlreadyQueued) {
QueueMessageData data[] = {
- /* { policy, commit_requested, source_frame_number } */
- {MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE, true, 1},
- {MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE, true, 1},
+ /* { policy, source_frame_number } */
+ {MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE, 1},
+ {MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE, 1},
};
QueueMessages(data, arraysize(data));
@@ -252,15 +241,16 @@ TEST_F(QueueMessageSwapPromiseTest,
CleanupPromises();
}
-TEST_F(QueueMessageSwapPromiseTest, VisualStateSwapPromiseDidSwap) {
+TEST_F(QueueMessageSwapPromiseTest, VisualStateSwapPromiseDidActivate) {
QueueMessageData data[] = {
- /* { policy, commit_requested, source_frame_number } */
- {MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE, true, 1},
- {MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE, false, 1},
- {MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE, false, 2},
+ /* { policy, source_frame_number } */
+ {MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE, 1},
+ {MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE, 1},
+ {MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE, 2},
};
QueueMessages(data, arraysize(data));
+ promises_[0]->DidActivate();
promises_[0]->DidSwap(NULL);
ASSERT_FALSE(promises_[1]);
ScopedVector<IPC::Message> messages;
@@ -270,7 +260,8 @@ TEST_F(QueueMessageSwapPromiseTest, VisualStateSwapPromiseDidSwap) {
EXPECT_TRUE(ContainsMessage(messages, messages_[1]));
EXPECT_FALSE(ContainsMessage(messages, messages_[2]));
- promises_[2]->DidSwap(NULL);
+ promises_[2]->DidActivate();
+ promises_[2]->DidNotSwap(cc::SwapPromise::SWAP_FAILS);
messages.swap(NextSwapMessages());
EXPECT_EQ(1u, messages.size());
EXPECT_TRUE(ContainsMessage(messages, messages_[2]));
@@ -283,40 +274,50 @@ TEST_F(QueueMessageSwapPromiseTest, VisualStateSwapPromiseDidSwap) {
void QueueMessageSwapPromiseTest::VisualStateSwapPromiseDidNotSwap(
cc::SwapPromise::DidNotSwapReason reason) {
QueueMessageData data[] = {
- /* { policy, commit_requested, source_frame_number } */
- {MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE, true, 1},
- {MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE, false, 1},
- {MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE, false, 2},
+ /* { policy, source_frame_number } */
+ {MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE, 1},
+ {MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE, 1},
+ {MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE, 2},
};
QueueMessages(data, arraysize(data));
+ // If we fail to swap with COMMIT_FAILS or ACTIVATE_FAILS, then
+ // messages are delivered by the RenderFrameHostImpl destructor,
+ // rather than directly by the swap promise.
+ bool msg_delivered = reason != cc::SwapPromise::COMMIT_FAILS &&
+ reason != cc::SwapPromise::ACTIVATION_FAILS;
+
promises_[0]->DidNotSwap(reason);
ASSERT_FALSE(promises_[1]);
EXPECT_TRUE(NextSwapMessages().empty());
- EXPECT_EQ(2u, DirectSendMessages().size());
- EXPECT_TRUE(ContainsMessage(DirectSendMessages(), messages_[0]));
- EXPECT_TRUE(ContainsMessage(DirectSendMessages(), messages_[1]));
+ EXPECT_EQ(msg_delivered, ContainsMessage(DirectSendMessages(), messages_[0]));
+ EXPECT_EQ(msg_delivered, ContainsMessage(DirectSendMessages(), messages_[1]));
EXPECT_FALSE(ContainsMessage(DirectSendMessages(), messages_[2]));
promises_[2]->DidNotSwap(reason);
EXPECT_TRUE(NextSwapMessages().empty());
- EXPECT_TRUE(ContainsMessage(DirectSendMessages(), messages_[2]));
+ EXPECT_EQ(msg_delivered, ContainsMessage(DirectSendMessages(), messages_[2]));
EXPECT_TRUE(NextSwapMessages().empty());
- EXPECT_TRUE(frame_swap_message_queue_->Empty());
+ EXPECT_EQ(msg_delivered, frame_swap_message_queue_->Empty());
}
-TEST_F(QueueMessageSwapPromiseTest, VisalStateSwapPromiseDidNotSwapNoUpdate) {
+TEST_F(QueueMessageSwapPromiseTest, VisualStateSwapPromiseDidNotSwapNoUpdate) {
VisualStateSwapPromiseDidNotSwap(cc::SwapPromise::COMMIT_NO_UPDATE);
}
TEST_F(QueueMessageSwapPromiseTest,
- VisalStateSwapPromiseDidNotSwapCommitFails) {
+ VisualStateSwapPromiseDidNotSwapCommitFails) {
VisualStateSwapPromiseDidNotSwap(cc::SwapPromise::COMMIT_FAILS);
}
-TEST_F(QueueMessageSwapPromiseTest, VisalStateSwapPromiseDidNotSwapSwapFails) {
+TEST_F(QueueMessageSwapPromiseTest, VisualStateSwapPromiseDidNotSwapSwapFails) {
VisualStateSwapPromiseDidNotSwap(cc::SwapPromise::SWAP_FAILS);
}
+TEST_F(QueueMessageSwapPromiseTest,
+ VisualStateSwapPromiseDidNotSwapActivationFails) {
+ VisualStateSwapPromiseDidNotSwap(cc::SwapPromise::ACTIVATION_FAILS);
+}
+
} // namespace content
diff --git a/chromium/content/renderer/gpu/render_widget_compositor.cc b/chromium/content/renderer/gpu/render_widget_compositor.cc
index 6d0768bc435..c8400037005 100644
--- a/chromium/content/renderer/gpu/render_widget_compositor.cc
+++ b/chromium/content/renderer/gpu/render_widget_compositor.cc
@@ -9,14 +9,12 @@
#include "base/command_line.h"
#include "base/logging.h"
+#include "base/profiler/scoped_tracker.h"
#include "base/strings/string_number_conversions.h"
#include "base/synchronization/lock.h"
#include "base/sys_info.h"
#include "base/time/time.h"
#include "base/values.h"
-#include "cc/base/latency_info_swap_promise.h"
-#include "cc/base/latency_info_swap_promise_monitor.h"
-#include "cc/base/swap_promise.h"
#include "cc/base/switches.h"
#include "cc/blink/web_layer_impl.h"
#include "cc/debug/layer_tree_debug_state.h"
@@ -26,20 +24,24 @@
#include "cc/output/begin_frame_args.h"
#include "cc/output/copy_output_request.h"
#include "cc/output/copy_output_result.h"
+#include "cc/output/latency_info_swap_promise.h"
+#include "cc/output/swap_promise.h"
#include "cc/resources/single_release_callback.h"
+#include "cc/scheduler/begin_frame_source.h"
+#include "cc/trees/latency_info_swap_promise_monitor.h"
#include "cc/trees/layer_tree_host.h"
-#include "content/child/child_gpu_memory_buffer_manager.h"
-#include "content/child/child_shared_bitmap_manager.h"
+#include "components/scheduler/renderer/renderer_scheduler.h"
#include "content/common/content_switches_internal.h"
#include "content/common/gpu/client/context_provider_command_buffer.h"
#include "content/public/common/content_switches.h"
#include "content/renderer/input/input_handler_manager.h"
-#include "content/renderer/render_thread_impl.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "third_party/WebKit/public/platform/WebCompositeAndReadbackAsyncCallback.h"
-#include "third_party/WebKit/public/platform/WebSelectionBound.h"
+#include "third_party/WebKit/public/platform/WebLayoutAndPaintAsyncCallback.h"
#include "third_party/WebKit/public/platform/WebSize.h"
#include "third_party/WebKit/public/web/WebKit.h"
+#include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
+#include "third_party/WebKit/public/web/WebSelection.h"
#include "third_party/WebKit/public/web/WebWidget.h"
#include "ui/gfx/frame_time.h"
#include "ui/gl/gl_switches.h"
@@ -61,18 +63,18 @@ class Layer;
using blink::WebBeginFrameArgs;
using blink::WebFloatPoint;
using blink::WebRect;
-using blink::WebSelectionBound;
+using blink::WebSelection;
using blink::WebSize;
+using blink::WebTopControlsState;
namespace content {
namespace {
-bool GetSwitchValueAsInt(
- const CommandLine& command_line,
- const std::string& switch_string,
- int min_value,
- int max_value,
- int* result) {
+bool GetSwitchValueAsInt(const base::CommandLine& command_line,
+ const std::string& switch_string,
+ int min_value,
+ int max_value,
+ int* result) {
std::string string_value = command_line.GetSwitchValueASCII(switch_string);
int int_value;
if (base::StringToInt(string_value, &int_value) &&
@@ -87,20 +89,24 @@ bool GetSwitchValueAsInt(
}
cc::LayerSelectionBound ConvertWebSelectionBound(
- const WebSelectionBound& web_bound) {
- DCHECK(web_bound.layerId);
-
+ const WebSelection& web_selection,
+ bool is_start) {
cc::LayerSelectionBound cc_bound;
- switch (web_bound.type) {
- case blink::WebSelectionBound::Caret:
- cc_bound.type = cc::SELECTION_BOUND_CENTER;
- break;
- case blink::WebSelectionBound::SelectionLeft:
- cc_bound.type = cc::SELECTION_BOUND_LEFT;
- break;
- case blink::WebSelectionBound::SelectionRight:
- cc_bound.type = cc::SELECTION_BOUND_RIGHT;
- break;
+ if (web_selection.isNone())
+ return cc_bound;
+
+ const blink::WebSelectionBound& web_bound =
+ is_start ? web_selection.start() : web_selection.end();
+ DCHECK(web_bound.layerId);
+ cc_bound.type = cc::SELECTION_BOUND_CENTER;
+ if (web_selection.isRange()) {
+ if (is_start) {
+ cc_bound.type = web_bound.isTextDirectionRTL ? cc::SELECTION_BOUND_RIGHT
+ : cc::SELECTION_BOUND_LEFT;
+ } else {
+ cc_bound.type = web_bound.isTextDirectionRTL ? cc::SELECTION_BOUND_LEFT
+ : cc::SELECTION_BOUND_RIGHT;
+ }
}
cc_bound.layer_id = web_bound.layerId;
cc_bound.edge_top = gfx::Point(web_bound.edgeTopInLayer);
@@ -108,7 +114,17 @@ cc::LayerSelectionBound ConvertWebSelectionBound(
return cc_bound;
}
-gfx::Size CalculateDefaultTileSize() {
+cc::LayerSelection ConvertWebSelection(const WebSelection& web_selection) {
+ cc::LayerSelection cc_selection;
+ cc_selection.start = ConvertWebSelectionBound(web_selection, true);
+ cc_selection.end = ConvertWebSelectionBound(web_selection, false);
+ cc_selection.is_editable = web_selection.isEditable();
+ cc_selection.is_empty_text_form_control =
+ web_selection.isEmptyTextFormControl();
+ return cc_selection;
+}
+
+gfx::Size CalculateDefaultTileSize(RenderWidget* widget) {
int default_tile_size = 256;
#if defined(OS_ANDROID)
// TODO(epenner): unify this for all platforms if it
@@ -151,20 +167,53 @@ gfx::Size CalculateDefaultTileSize() {
if (numTiles >= 40)
default_tile_size = 512;
}
+#elif defined(OS_CHROMEOS)
+ // Use 512 for high DPI (dsf=2.0f) devices.
+ if (widget->screen_info().deviceScaleFactor >= 2.0f)
+ default_tile_size = 512;
#endif
+
return gfx::Size(default_tile_size, default_tile_size);
}
+// Check cc::TopControlsState, and blink::WebTopControlsState
+// are kept in sync.
+static_assert(int(blink::WebTopControlsBoth) == int(cc::BOTH),
+ "mismatching enums: BOTH");
+static_assert(int(blink::WebTopControlsHidden) == int(cc::HIDDEN),
+ "mismatching enums: HIDDEN");
+static_assert(int(blink::WebTopControlsShown) == int(cc::SHOWN),
+ "mismatching enums: SHOWN");
+
+static cc::TopControlsState ConvertTopControlsState(
+ WebTopControlsState state) {
+ return static_cast<cc::TopControlsState>(state);
+}
+
} // namespace
// static
scoped_ptr<RenderWidgetCompositor> RenderWidgetCompositor::Create(
RenderWidget* widget,
- bool threaded) {
+ CompositorDependencies* compositor_deps) {
scoped_ptr<RenderWidgetCompositor> compositor(
- new RenderWidgetCompositor(widget, threaded));
+ new RenderWidgetCompositor(widget, compositor_deps));
+ compositor->Initialize();
+ return compositor;
+}
- CommandLine* cmd = CommandLine::ForCurrentProcess();
+RenderWidgetCompositor::RenderWidgetCompositor(
+ RenderWidget* widget,
+ CompositorDependencies* compositor_deps)
+ : num_failed_recreate_attempts_(0),
+ widget_(widget),
+ compositor_deps_(compositor_deps),
+ layout_and_paint_async_callback_(nullptr),
+ weak_factory_(this) {
+}
+
+void RenderWidgetCompositor::Initialize() {
+ base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
cc::LayerTreeSettings settings;
@@ -174,16 +223,20 @@ scoped_ptr<RenderWidgetCompositor> RenderWidgetCompositor::Create(
settings.throttle_frame_production =
!cmd->HasSwitch(switches::kDisableGpuVsync);
- settings.begin_frame_scheduling_enabled =
- cmd->HasSwitch(switches::kEnableBeginFrameScheduling);
settings.main_frame_before_activation_enabled =
cmd->HasSwitch(cc::switches::kEnableMainFrameBeforeActivation) &&
!cmd->HasSwitch(cc::switches::kDisableMainFrameBeforeActivation);
- settings.report_overscroll_only_for_scrollable_axes = true;
+ settings.report_overscroll_only_for_scrollable_axes =
+ !compositor_deps_->IsElasticOverscrollEnabled();
settings.accelerated_animation_enabled =
!cmd->HasSwitch(cc::switches::kDisableThreadedAnimation);
+ settings.use_display_lists = cmd->HasSwitch(switches::kEnableSlimmingPaint);
+ if (cmd->HasSwitch(switches::kEnableCompositorAnimationTimelines)) {
+ settings.use_compositor_animation_timelines = true;
+ blink::WebRuntimeFeatures::enableCompositorAnimationTimelines(true);
+ }
- settings.default_tile_size = CalculateDefaultTileSize();
+ settings.default_tile_size = CalculateDefaultTileSize(widget_);
if (cmd->HasSwitch(switches::kDefaultTileWidth)) {
int tile_width = 0;
GetSwitchValueAsInt(*cmd,
@@ -219,39 +272,23 @@ scoped_ptr<RenderWidgetCompositor> RenderWidgetCompositor::Create(
settings.max_untiled_layer_size = gfx::Size(max_untiled_layer_width,
max_untiled_layer_height);
- RenderThreadImpl* render_thread = RenderThreadImpl::current();
- // render_thread may be NULL in tests.
- if (render_thread) {
- settings.impl_side_painting =
- render_thread->is_impl_side_painting_enabled();
- settings.gpu_rasterization_forced =
- render_thread->is_gpu_rasterization_forced();
- settings.gpu_rasterization_enabled =
- render_thread->is_gpu_rasterization_enabled();
- settings.can_use_lcd_text = render_thread->is_lcd_text_enabled();
- settings.use_distance_field_text =
- render_thread->is_distance_field_text_enabled();
- settings.use_zero_copy = render_thread->is_zero_copy_enabled();
- settings.use_one_copy = render_thread->is_one_copy_enabled();
- }
-
- settings.calculate_top_controls_position =
- cmd->HasSwitch(cc::switches::kEnableTopControlsPositionCalculation);
- if (cmd->HasSwitch(cc::switches::kTopControlsHeight)) {
- std::string controls_height_str =
- cmd->GetSwitchValueASCII(cc::switches::kTopControlsHeight);
- double controls_height;
- if (base::StringToDouble(controls_height_str, &controls_height) &&
- controls_height > 0)
- settings.top_controls_height = controls_height;
- }
-
- if (settings.calculate_top_controls_position &&
- settings.top_controls_height <= 0) {
- DCHECK(false)
- << "Top controls repositioning enabled without valid height set.";
- settings.calculate_top_controls_position = false;
- }
+ settings.gpu_rasterization_msaa_sample_count =
+ compositor_deps_->GetGpuRasterizationMSAASampleCount();
+ settings.impl_side_painting = compositor_deps_->IsImplSidePaintingEnabled();
+ settings.gpu_rasterization_forced =
+ compositor_deps_->IsGpuRasterizationForced();
+ settings.gpu_rasterization_enabled =
+ compositor_deps_->IsGpuRasterizationEnabled();
+
+ settings.can_use_lcd_text = compositor_deps_->IsLcdTextEnabled();
+ settings.use_distance_field_text =
+ compositor_deps_->IsDistanceFieldTextEnabled();
+ settings.use_zero_copy = compositor_deps_->IsZeroCopyEnabled();
+ settings.use_one_copy = compositor_deps_->IsOneCopyEnabled();
+ settings.enable_elastic_overscroll =
+ compositor_deps_->IsElasticOverscrollEnabled();
+ settings.use_image_texture_target = compositor_deps_->GetImageTextureTarget();
+ settings.gather_pixel_refs = compositor_deps_->IsGatherPixelRefsEnabled();
if (cmd->HasSwitch(cc::switches::kTopControlsShowThreshold)) {
std::string top_threshold_str =
@@ -273,10 +310,13 @@ scoped_ptr<RenderWidgetCompositor> RenderWidgetCompositor::Create(
settings.use_pinch_virtual_viewport =
cmd->HasSwitch(cc::switches::kEnablePinchVirtualViewport);
- settings.allow_antialiasing &=
+ settings.verify_property_trees =
+ cmd->HasSwitch(cc::switches::kEnablePropertyTreeVerification) &&
+ settings.impl_side_painting;
+ settings.renderer_settings.allow_antialiasing &=
!cmd->HasSwitch(cc::switches::kDisableCompositedAntialiasing);
settings.single_thread_proxy_scheduler =
- !cmd->HasSwitch(switches::kDisableSingleThreadProxyScheduler);
+ compositor_deps_->UseSingleThreadScheduler();
// These flags should be mirrored by UI versions in ui/compositor/.
settings.initial_debug_state.show_debug_borders =
@@ -295,10 +335,6 @@ scoped_ptr<RenderWidgetCompositor> RenderWidgetCompositor::Create(
cmd->HasSwitch(cc::switches::kShowScreenSpaceRects);
settings.initial_debug_state.show_replica_screen_space_rects =
cmd->HasSwitch(cc::switches::kShowReplicaScreenSpaceRects);
- settings.initial_debug_state.show_occluding_rects =
- cmd->HasSwitch(cc::switches::kShowOccludingRects);
- settings.initial_debug_state.show_non_occluding_rects =
- cmd->HasSwitch(cc::switches::kShowNonOccludingRects);
settings.initial_debug_state.SetRecordRenderingStats(
cmd->HasSwitch(cc::switches::kEnableGpuBenchmarking));
@@ -314,15 +350,6 @@ scoped_ptr<RenderWidgetCompositor> RenderWidgetCompositor::Create(
&settings.initial_debug_state.slow_down_raster_scale_factor);
}
- if (cmd->HasSwitch(cc::switches::kMaxTilesForInterestArea)) {
- int max_tiles_for_interest_area;
- if (GetSwitchValueAsInt(*cmd,
- cc::switches::kMaxTilesForInterestArea,
- 1, std::numeric_limits<int>::max(),
- &max_tiles_for_interest_area))
- settings.max_tiles_for_interest_area = max_tiles_for_interest_area;
- }
-
if (cmd->HasSwitch(cc::switches::kMaxUnusedResourceMemoryUsagePercentage)) {
int max_unused_resource_memory_percentage;
if (GetSwitchValueAsInt(
@@ -342,37 +369,39 @@ scoped_ptr<RenderWidgetCompositor> RenderWidgetCompositor::Create(
SynchronousCompositorFactory* synchronous_compositor_factory =
SynchronousCompositorFactory::GetInstance();
+ // We can't use GPU rasterization on low-end devices, because the Ganesh
+ // cache would consume too much memory.
+ if (base::SysInfo::IsLowEndDevice())
+ settings.gpu_rasterization_enabled = false;
settings.using_synchronous_renderer_compositor =
synchronous_compositor_factory;
- settings.record_full_layer =
- synchronous_compositor_factory &&
- synchronous_compositor_factory->RecordFullLayer();
+ settings.record_full_layer = widget_->DoesRecordFullLayer();
settings.report_overscroll_only_for_scrollable_axes =
!synchronous_compositor_factory;
settings.max_partial_texture_updates = 0;
if (synchronous_compositor_factory) {
// Android WebView uses system scrollbars, so make ours invisible.
- settings.scrollbar_animator = cc::LayerTreeSettings::NoAnimator;
+ settings.scrollbar_animator = cc::LayerTreeSettings::NO_ANIMATOR;
settings.solid_color_scrollbar_color = SK_ColorTRANSPARENT;
} else {
- settings.scrollbar_animator = cc::LayerTreeSettings::LinearFade;
+ settings.scrollbar_animator = cc::LayerTreeSettings::LINEAR_FADE;
settings.scrollbar_fade_delay_ms = 300;
settings.scrollbar_fade_resize_delay_ms = 2000;
settings.scrollbar_fade_duration_ms = 300;
settings.solid_color_scrollbar_color = SkColorSetARGB(128, 128, 128, 128);
}
- settings.highp_threshold_min = 2048;
+ settings.renderer_settings.highp_threshold_min = 2048;
// Android WebView handles root layer flings itself.
settings.ignore_root_layer_flings =
synchronous_compositor_factory;
// Memory policy on Android WebView does not depend on whether device is
// low end, so always use default policy.
- bool is_low_end_device =
+ bool use_low_memory_policy =
base::SysInfo::IsLowEndDevice() && !synchronous_compositor_factory;
// RGBA_4444 textures are only enabled for low end devices
// and are disabled for Android WebView as it doesn't support the format.
- settings.use_rgba_4444_textures = is_low_end_device;
- if (is_low_end_device) {
+ settings.renderer_settings.use_rgba_4444_textures = use_low_memory_policy;
+ if (use_low_memory_policy) {
// On low-end we want to be very carefull about killing other
// apps. So initially we use 50% more memory to avoid flickering
// or raster-on-demand.
@@ -384,49 +413,78 @@ scoped_ptr<RenderWidgetCompositor> RenderWidgetCompositor::Create(
settings.max_memory_for_prepaint_percentage = 50;
}
// Webview does not own the surface so should not clear it.
- settings.should_clear_root_render_pass =
+ settings.renderer_settings.should_clear_root_render_pass =
!synchronous_compositor_factory;
// TODO(danakj): Only do this on low end devices.
settings.create_low_res_tiling = true;
+ settings.use_external_begin_frame_source = true;
+
#elif !defined(OS_MACOSX)
if (ui::IsOverlayScrollbarEnabled()) {
- settings.scrollbar_animator = cc::LayerTreeSettings::Thinning;
+ settings.scrollbar_animator = cc::LayerTreeSettings::THINNING;
settings.solid_color_scrollbar_color = SkColorSetARGB(128, 128, 128, 128);
- } else if (cmd->HasSwitch(cc::switches::kEnablePinchVirtualViewport)) {
- // use_pinch_zoom_scrollbars is only true on desktop when non-overlay
- // scrollbars are in use.
- settings.use_pinch_zoom_scrollbars = true;
- settings.scrollbar_animator = cc::LayerTreeSettings::LinearFade;
+ } else if (settings.use_pinch_virtual_viewport) {
+ settings.scrollbar_animator = cc::LayerTreeSettings::LINEAR_FADE;
settings.solid_color_scrollbar_color = SkColorSetARGB(128, 128, 128, 128);
}
settings.scrollbar_fade_delay_ms = 500;
settings.scrollbar_fade_resize_delay_ms = 500;
settings.scrollbar_fade_duration_ms = 300;
+
+ // When pinching in, only show the pinch-viewport overlay scrollbars if the
+ // page scale is at least some threshold away from the minimum. i.e. don't
+ // show the pinch scrollbars when at minimum scale.
+ settings.scrollbar_show_scale_threshold = 1.05f;
#endif
if (cmd->HasSwitch(switches::kEnableLowResTiling))
settings.create_low_res_tiling = true;
if (cmd->HasSwitch(switches::kDisableLowResTiling))
settings.create_low_res_tiling = false;
+ if (cmd->HasSwitch(switches::kEnableBeginFrameScheduling))
+ settings.use_external_begin_frame_source = true;
- compositor->Initialize(settings);
-
- return compositor.Pass();
-}
+ if (widget_->for_oopif()) {
+ // TODO(simonhong): Apply BeginFrame scheduling for OOPIF.
+ // See crbug.com/471411.
+ settings.use_external_begin_frame_source = false;
+ }
-RenderWidgetCompositor::RenderWidgetCompositor(RenderWidget* widget,
- bool threaded)
- : threaded_(threaded),
- widget_(widget),
- send_v8_idle_notification_after_commit_(true) {
- CommandLine* cmd = CommandLine::ForCurrentProcess();
+ scoped_refptr<base::SingleThreadTaskRunner> compositor_thread_task_runner =
+ compositor_deps_->GetCompositorImplThreadTaskRunner();
+ scoped_refptr<base::SingleThreadTaskRunner>
+ main_thread_compositor_task_runner =
+ compositor_deps_->GetCompositorMainThreadTaskRunner();
+ cc::SharedBitmapManager* shared_bitmap_manager =
+ compositor_deps_->GetSharedBitmapManager();
+ gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager =
+ compositor_deps_->GetGpuMemoryBufferManager();
+ cc::TaskGraphRunner* task_graph_runner =
+ compositor_deps_->GetTaskGraphRunner();
+
+ scoped_ptr<cc::BeginFrameSource> external_begin_frame_source;
+ if (settings.use_external_begin_frame_source) {
+ external_begin_frame_source =
+ compositor_deps_->CreateExternalBeginFrameSource(widget_->routing_id());
+ }
- if (cmd->HasSwitch(switches::kEnableV8IdleNotificationAfterCommit))
- send_v8_idle_notification_after_commit_ = true;
- if (cmd->HasSwitch(switches::kDisableV8IdleNotificationAfterCommit))
- send_v8_idle_notification_after_commit_ = false;
+ cc::LayerTreeHost::InitParams params;
+ params.client = this;
+ params.shared_bitmap_manager = shared_bitmap_manager;
+ params.gpu_memory_buffer_manager = gpu_memory_buffer_manager;
+ params.settings = &settings;
+ params.task_graph_runner = task_graph_runner;
+ params.main_task_runner = main_thread_compositor_task_runner;
+ params.external_begin_frame_source = external_begin_frame_source.Pass();
+ if (compositor_thread_task_runner.get()) {
+ layer_tree_host_ = cc::LayerTreeHost::CreateThreaded(
+ compositor_thread_task_runner, &params);
+ } else {
+ layer_tree_host_ = cc::LayerTreeHost::CreateSingleThreaded(this, &params);
+ }
+ DCHECK(layer_tree_host_);
}
RenderWidgetCompositor::~RenderWidgetCompositor() {}
@@ -450,19 +508,6 @@ void RenderWidgetCompositor::SetRasterizeOnlyVisibleContent() {
layer_tree_host_->SetDebugState(current);
}
-void RenderWidgetCompositor::UpdateTopControlsState(
- cc::TopControlsState constraints,
- cc::TopControlsState current,
- bool animate) {
- layer_tree_host_->UpdateTopControlsState(constraints,
- current,
- animate);
-}
-
-void RenderWidgetCompositor::SetTopControlsLayoutHeight(float height) {
- layer_tree_host_->SetTopControlsLayoutHeight(height);
-}
-
void RenderWidgetCompositor::SetNeedsRedrawRect(gfx::Rect damage_rect) {
layer_tree_host_->SetNeedsRedrawRect(damage_rect);
}
@@ -485,14 +530,14 @@ void RenderWidgetCompositor::QueueSwapPromise(
layer_tree_host_->QueueSwapPromise(swap_promise.Pass());
}
-int RenderWidgetCompositor::GetLayerTreeId() const {
- return layer_tree_host_->id();
-}
-
int RenderWidgetCompositor::GetSourceFrameNumber() const {
return layer_tree_host_->source_frame_number();
}
+void RenderWidgetCompositor::SetNeedsUpdateLayers() {
+ layer_tree_host_->SetNeedsUpdateLayers();
+}
+
void RenderWidgetCompositor::SetNeedsCommit() {
layer_tree_host_->SetNeedsCommit();
}
@@ -518,47 +563,8 @@ bool RenderWidgetCompositor::SendMessageToMicroBenchmark(
return layer_tree_host_->SendMessageToMicroBenchmark(id, value.Pass());
}
-void RenderWidgetCompositor::Initialize(cc::LayerTreeSettings settings) {
- scoped_refptr<base::MessageLoopProxy> compositor_message_loop_proxy;
- scoped_refptr<base::SingleThreadTaskRunner>
- main_thread_compositor_task_runner(base::MessageLoopProxy::current());
- RenderThreadImpl* render_thread = RenderThreadImpl::current();
- cc::SharedBitmapManager* shared_bitmap_manager = NULL;
- gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager = NULL;
- // render_thread may be NULL in tests.
- if (render_thread) {
- compositor_message_loop_proxy =
- render_thread->compositor_message_loop_proxy();
- shared_bitmap_manager = render_thread->shared_bitmap_manager();
- gpu_memory_buffer_manager = render_thread->gpu_memory_buffer_manager();
- main_thread_compositor_task_runner =
- render_thread->main_thread_compositor_task_runner();
- }
- if (compositor_message_loop_proxy.get()) {
- layer_tree_host_ =
- cc::LayerTreeHost::CreateThreaded(this,
- shared_bitmap_manager,
- gpu_memory_buffer_manager,
- settings,
- main_thread_compositor_task_runner,
- compositor_message_loop_proxy);
- } else {
- layer_tree_host_ = cc::LayerTreeHost::CreateSingleThreaded(
- this,
- this,
- shared_bitmap_manager,
- gpu_memory_buffer_manager,
- settings,
- main_thread_compositor_task_runner);
- }
- DCHECK(layer_tree_host_);
-}
-
-void RenderWidgetCompositor::setSurfaceReady() {
- // In tests without a RenderThreadImpl, don't set ready as this kicks
- // off creating output surfaces that the test can't create.
- if (RenderThreadImpl::current())
- layer_tree_host_->SetLayerTreeHostClientReady();
+void RenderWidgetCompositor::StartCompositor() {
+ layer_tree_host_->SetLayerTreeHostClientReady();
}
void RenderWidgetCompositor::setRootLayer(const blink::WebLayer& layer) {
@@ -610,10 +616,6 @@ void RenderWidgetCompositor::setHasTransparentBackground(bool transparent) {
layer_tree_host_->set_has_transparent_background(transparent);
}
-void RenderWidgetCompositor::setOverhangBitmap(const SkBitmap& bitmap) {
- layer_tree_host_->SetOverhangBitmap(bitmap);
-}
-
void RenderWidgetCompositor::setVisible(bool visible) {
layer_tree_host_->SetVisible(visible);
}
@@ -662,36 +664,42 @@ void RenderWidgetCompositor::registerForAnimations(blink::WebLayer* layer) {
}
void RenderWidgetCompositor::registerViewportLayers(
+ const blink::WebLayer* overscrollElasticityLayer,
const blink::WebLayer* pageScaleLayer,
const blink::WebLayer* innerViewportScrollLayer,
const blink::WebLayer* outerViewportScrollLayer) {
layer_tree_host_->RegisterViewportLayers(
+ // The scroll elasticity layer will only exist when using pinch virtual
+ // viewports.
+ overscrollElasticityLayer
+ ? static_cast<const cc_blink::WebLayerImpl*>(
+ overscrollElasticityLayer)->layer()
+ : NULL,
static_cast<const cc_blink::WebLayerImpl*>(pageScaleLayer)->layer(),
static_cast<const cc_blink::WebLayerImpl*>(innerViewportScrollLayer)
->layer(),
// The outer viewport layer will only exist when using pinch virtual
// viewports.
- outerViewportScrollLayer ? static_cast<const cc_blink::WebLayerImpl*>(
- outerViewportScrollLayer)->layer()
- : NULL);
+ outerViewportScrollLayer
+ ? static_cast<const cc_blink::WebLayerImpl*>(outerViewportScrollLayer)
+ ->layer()
+ : NULL);
}
void RenderWidgetCompositor::clearViewportLayers() {
- layer_tree_host_->RegisterViewportLayers(scoped_refptr<cc::Layer>(),
- scoped_refptr<cc::Layer>(),
- scoped_refptr<cc::Layer>());
+ layer_tree_host_->RegisterViewportLayers(
+ scoped_refptr<cc::Layer>(), scoped_refptr<cc::Layer>(),
+ scoped_refptr<cc::Layer>(), scoped_refptr<cc::Layer>());
}
void RenderWidgetCompositor::registerSelection(
- const blink::WebSelectionBound& start,
- const blink::WebSelectionBound& end) {
- layer_tree_host_->RegisterSelection(ConvertWebSelectionBound(start),
- ConvertWebSelectionBound(end));
+ const blink::WebSelection& selection) {
+ layer_tree_host_->RegisterSelection(ConvertWebSelection(selection));
}
void RenderWidgetCompositor::clearSelection() {
- cc::LayerSelectionBound empty_selection;
- layer_tree_host_->RegisterSelection(empty_selection, empty_selection);
+ cc::LayerSelection empty_selection;
+ layer_tree_host_->RegisterSelection(empty_selection);
}
void CompositeAndReadbackAsyncCallback(
@@ -705,23 +713,45 @@ void CompositeAndReadbackAsyncCallback(
}
}
+void RenderWidgetCompositor::layoutAndPaintAsync(
+ blink::WebLayoutAndPaintAsyncCallback* callback) {
+ DCHECK(!temporary_copy_output_request_ && !layout_and_paint_async_callback_);
+ layout_and_paint_async_callback_ = callback;
+ ScheduleCommit();
+}
+
void RenderWidgetCompositor::compositeAndReadbackAsync(
blink::WebCompositeAndReadbackAsyncCallback* callback) {
- DCHECK(!temporary_copy_output_request_);
+ DCHECK(!temporary_copy_output_request_ && !layout_and_paint_async_callback_);
temporary_copy_output_request_ =
cc::CopyOutputRequest::CreateBitmapRequest(
base::Bind(&CompositeAndReadbackAsyncCallback, callback));
// Force a commit to happen. The temporary copy output request will
- // be installed after layout which will happen as a part of the commit, when
- // there is guaranteed to be a root layer.
- if (!threaded_ &&
- !layer_tree_host_->settings().single_thread_proxy_scheduler) {
- layer_tree_host_->Composite(gfx::FrameTime::Now());
+ // be installed after layout which will happen as a part of the commit, for
+ // widgets that delay the creation of their output surface.
+ ScheduleCommit();
+}
+
+bool RenderWidgetCompositor::CommitIsSynchronous() const {
+ return !compositor_deps_->GetCompositorImplThreadTaskRunner().get() &&
+ !layer_tree_host_->settings().single_thread_proxy_scheduler;
+}
+
+void RenderWidgetCompositor::ScheduleCommit() {
+ if (CommitIsSynchronous()) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(&RenderWidgetCompositor::SynchronousCommit,
+ weak_factory_.GetWeakPtr()));
} else {
layer_tree_host_->SetNeedsCommit();
}
}
+void RenderWidgetCompositor::SynchronousCommit() {
+ DCHECK(CommitIsSynchronous());
+ layer_tree_host_->Composite(gfx::FrameTime::Now());
+}
+
void RenderWidgetCompositor::finishAllRendering() {
layer_tree_host_->FinishAllRendering();
}
@@ -730,6 +760,10 @@ void RenderWidgetCompositor::setDeferCommits(bool defer_commits) {
layer_tree_host_->SetDeferCommits(defer_commits);
}
+int RenderWidgetCompositor::layerTreeId() const {
+ return layer_tree_host_->id();
+}
+
void RenderWidgetCompositor::setShowFPSCounter(bool show) {
cc::LayerTreeDebugState debug_state = layer_tree_host_->debug_state();
debug_state.show_fps_counter = show;
@@ -762,48 +796,69 @@ void RenderWidgetCompositor::setShowScrollBottleneckRects(bool show) {
layer_tree_host_->SetDebugState(debug_state);
}
-void RenderWidgetCompositor::setTopControlsContentOffset(float offset) {
- layer_tree_host_->SetTopControlsContentOffset(offset);
+void RenderWidgetCompositor::updateTopControlsState(
+ WebTopControlsState constraints,
+ WebTopControlsState current,
+ bool animate) {
+ layer_tree_host_->UpdateTopControlsState(ConvertTopControlsState(constraints),
+ ConvertTopControlsState(current),
+ animate);
+}
+
+void RenderWidgetCompositor::setTopControlsHeight(float height, bool shrink) {
+ layer_tree_host_->SetTopControlsHeight(height, shrink);
}
-void RenderWidgetCompositor::WillBeginMainFrame(int frame_id) {
- widget_->InstrumentWillBeginFrame(frame_id);
+void RenderWidgetCompositor::setTopControlsShownRatio(float ratio) {
+ layer_tree_host_->SetTopControlsShownRatio(ratio);
+}
+
+void RenderWidgetCompositor::WillBeginMainFrame() {
widget_->willBeginCompositorFrame();
}
void RenderWidgetCompositor::DidBeginMainFrame() {
- widget_->InstrumentDidBeginFrame();
}
void RenderWidgetCompositor::BeginMainFrame(const cc::BeginFrameArgs& args) {
- begin_main_frame_time_ = args.frame_time;
- begin_main_frame_interval_ = args.interval;
double frame_time_sec = (args.frame_time - base::TimeTicks()).InSecondsF();
double deadline_sec = (args.deadline - base::TimeTicks()).InSecondsF();
double interval_sec = args.interval.InSecondsF();
WebBeginFrameArgs web_begin_frame_args =
WebBeginFrameArgs(frame_time_sec, deadline_sec, interval_sec);
+ compositor_deps_->GetRendererScheduler()->WillBeginFrame(args);
widget_->webwidget()->beginFrame(web_begin_frame_args);
}
+void RenderWidgetCompositor::BeginMainFrameNotExpectedSoon() {
+ compositor_deps_->GetRendererScheduler()->BeginFrameNotExpectedSoon();
+}
+
void RenderWidgetCompositor::Layout() {
widget_->webwidget()->layout();
if (temporary_copy_output_request_) {
- DCHECK(layer_tree_host_->root_layer());
- layer_tree_host_->root_layer()->RequestCopyOfOutput(
- temporary_copy_output_request_.Pass());
+ // For WebViewImpl, this will always have a root layer. For other widgets,
+ // the widget may be closed before servicing this request, so ignore it.
+ if (cc::Layer* root_layer = layer_tree_host_->root_layer()) {
+ root_layer->RequestCopyOfOutput(temporary_copy_output_request_.Pass());
+ } else {
+ temporary_copy_output_request_->SendEmptyResult();
+ temporary_copy_output_request_ = nullptr;
+ }
}
}
void RenderWidgetCompositor::ApplyViewportDeltas(
- const gfx::Vector2d& inner_delta,
- const gfx::Vector2d& outer_delta,
+ const gfx::Vector2dF& inner_delta,
+ const gfx::Vector2dF& outer_delta,
+ const gfx::Vector2dF& elastic_overscroll_delta,
float page_scale,
float top_controls_delta) {
widget_->webwidget()->applyViewportDeltas(
inner_delta,
outer_delta,
+ elastic_overscroll_delta,
page_scale,
top_controls_delta);
}
@@ -818,35 +873,59 @@ void RenderWidgetCompositor::ApplyViewportDeltas(
top_controls_delta);
}
-void RenderWidgetCompositor::RequestNewOutputSurface(bool fallback) {
- layer_tree_host_->SetOutputSurface(widget_->CreateOutputSurface(fallback));
+void RenderWidgetCompositor::RequestNewOutputSurface() {
+ // If the host is closing, then no more compositing is possible. This
+ // prevents shutdown races between handling the close message and
+ // the CreateOutputSurface task.
+ if (widget_->host_closing())
+ return;
+
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/466870
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "466870 RenderWidgetCompositor::RequestNewOutputSurface"));
+
+ bool fallback =
+ num_failed_recreate_attempts_ >= OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK;
+ scoped_ptr<cc::OutputSurface> surface(widget_->CreateOutputSurface(fallback));
+
+ if (!surface) {
+ DidFailToInitializeOutputSurface();
+ return;
+ }
+
+ layer_tree_host_->SetOutputSurface(surface.Pass());
}
void RenderWidgetCompositor::DidInitializeOutputSurface() {
+ num_failed_recreate_attempts_ = 0;
+}
+
+void RenderWidgetCompositor::DidFailToInitializeOutputSurface() {
+ ++num_failed_recreate_attempts_;
+ // Tolerate a certain number of recreation failures to work around races
+ // in the output-surface-lost machinery.
+ LOG_IF(FATAL, (num_failed_recreate_attempts_ >= MAX_OUTPUT_SURFACE_RETRIES))
+ << "Failed to create a fallback OutputSurface.";
+
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(&RenderWidgetCompositor::RequestNewOutputSurface,
+ weak_factory_.GetWeakPtr()));
}
void RenderWidgetCompositor::WillCommit() {
- widget_->InstrumentWillComposite();
+ if (!layout_and_paint_async_callback_)
+ return;
+ layout_and_paint_async_callback_->didLayoutAndPaint();
+ layout_and_paint_async_callback_ = nullptr;
}
void RenderWidgetCompositor::DidCommit() {
DCHECK(!temporary_copy_output_request_);
- if (send_v8_idle_notification_after_commit_) {
- base::TimeDelta idle_time = begin_main_frame_time_ +
- begin_main_frame_interval_ -
- gfx::FrameTime::Now();
- if (idle_time > base::TimeDelta()) {
- // Convert to 32-bit microseconds first to avoid costly 64-bit division.
- int32 idle_time_in_us = idle_time.InMicroseconds();
- int32 idle_time_in_ms = idle_time_in_us / 1000;
- if (idle_time_in_ms)
- blink::mainThreadIsolate()->IdleNotification(idle_time_in_ms);
- }
- }
-
widget_->DidCommitCompositorFrame();
widget_->didBecomeReadyForAdditionalInput();
- widget_->webwidget()->didCommitFrameToCompositor();
+ compositor_deps_->GetRendererScheduler()->DidCommitFrameToCompositor();
}
void RenderWidgetCompositor::DidCommitAndDrawFrame() {
@@ -855,10 +934,15 @@ void RenderWidgetCompositor::DidCommitAndDrawFrame() {
void RenderWidgetCompositor::DidCompleteSwapBuffers() {
widget_->didCompleteSwapBuffers();
- if (!threaded_)
+ bool threaded = !!compositor_deps_->GetCompositorImplThreadTaskRunner().get();
+ if (!threaded)
widget_->OnSwapBuffersComplete();
}
+void RenderWidgetCompositor::DidCompletePageScaleAnimation() {
+ widget_->DidCompletePageScaleAnimation();
+}
+
void RenderWidgetCompositor::ScheduleAnimation() {
widget_->scheduleAnimation();
}
@@ -873,8 +957,17 @@ void RenderWidgetCompositor::DidAbortSwapBuffers() {
void RenderWidgetCompositor::RateLimitSharedMainThreadContext() {
cc::ContextProvider* provider =
- RenderThreadImpl::current()->SharedMainThreadContextProvider().get();
+ compositor_deps_->GetSharedMainThreadContextProvider();
+ // provider can be NULL after the GPU process crashed enough times and we
+ // don't want to restart it any more (falling back to software).
+ if (!provider)
+ return;
provider->ContextGL()->RateLimitOffscreenContextCHROMIUM();
}
+void RenderWidgetCompositor::SetSurfaceIdNamespace(
+ uint32_t surface_id_namespace) {
+ layer_tree_host_->set_surface_id_namespace(surface_id_namespace);
+}
+
} // namespace content
diff --git a/chromium/content/renderer/gpu/render_widget_compositor.h b/chromium/content/renderer/gpu/render_widget_compositor.h
index e0f369a2f69..a6d1981b0d5 100644
--- a/chromium/content/renderer/gpu/render_widget_compositor.h
+++ b/chromium/content/renderer/gpu/render_widget_compositor.h
@@ -9,16 +9,17 @@
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "base/values.h"
-#include "cc/base/swap_promise.h"
-#include "cc/base/swap_promise_monitor.h"
#include "cc/input/top_controls_state.h"
+#include "cc/output/swap_promise.h"
#include "cc/trees/layer_tree_host_client.h"
#include "cc/trees/layer_tree_host_single_thread_client.h"
#include "cc/trees/layer_tree_settings.h"
+#include "cc/trees/swap_promise_monitor.h"
#include "content/common/content_export.h"
+#include "content/renderer/gpu/compositor_dependencies.h"
#include "third_party/WebKit/public/platform/WebLayerTreeView.h"
#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/gfx/rect.h"
+#include "ui/gfx/geometry/rect.h"
namespace ui {
struct LatencyInfo;
@@ -41,8 +42,9 @@ class CONTENT_EXPORT RenderWidgetCompositor
public:
// Attempt to construct and initialize a compositor instance for the widget
// with the given settings. Returns NULL if initialization fails.
- static scoped_ptr<RenderWidgetCompositor> Create(RenderWidget* widget,
- bool threaded);
+ static scoped_ptr<RenderWidgetCompositor> Create(
+ RenderWidget* widget,
+ CompositorDependencies* compositor_deps);
virtual ~RenderWidgetCompositor();
@@ -50,26 +52,22 @@ class CONTENT_EXPORT RenderWidgetCompositor
bool BeginMainFrameRequested() const;
void SetNeedsDisplayOnAllLayers();
void SetRasterizeOnlyVisibleContent();
- void UpdateTopControlsState(cc::TopControlsState constraints,
- cc::TopControlsState current,
- bool animate);
- void SetTopControlsLayoutHeight(float height);
void SetNeedsRedrawRect(gfx::Rect damage_rect);
// Like setNeedsRedraw but forces the frame to be drawn, without early-outs.
// Redraw will be forced after the next commit
void SetNeedsForcedRedraw();
// Calling CreateLatencyInfoSwapPromiseMonitor() to get a scoped
// LatencyInfoSwapPromiseMonitor. During the life time of the
- // LatencyInfoSwapPromiseMonitor, if SetNeedsCommit() or SetNeedsUpdateLayer()
- // is called on LayerTreeHost, the original latency info will be turned
- // into a LatencyInfoSwapPromise.
+ // LatencyInfoSwapPromiseMonitor, if SetNeedsCommit() or
+ // SetNeedsUpdateLayers() is called on LayerTreeHost, the original latency
+ // info will be turned into a LatencyInfoSwapPromise.
scoped_ptr<cc::SwapPromiseMonitor> CreateLatencyInfoSwapPromiseMonitor(
ui::LatencyInfo* latency);
// Calling QueueSwapPromise() to directly queue a SwapPromise into
// LayerTreeHost.
void QueueSwapPromise(scoped_ptr<cc::SwapPromise> swap_promise);
- int GetLayerTreeId() const;
int GetSourceFrameNumber() const;
+ void SetNeedsUpdateLayers();
void SetNeedsCommit();
void NotifyInputThrottledUntilCommit();
const cc::Layer* GetRootLayer() const;
@@ -78,9 +76,10 @@ class CONTENT_EXPORT RenderWidgetCompositor
scoped_ptr<base::Value> value,
const base::Callback<void(scoped_ptr<base::Value>)>& callback);
bool SendMessageToMicroBenchmark(int id, scoped_ptr<base::Value> value);
+ void StartCompositor();
+ void SetSurfaceIdNamespace(uint32_t surface_id_namespace);
// WebLayerTreeView implementation.
- virtual void setSurfaceReady();
virtual void setRootLayer(const blink::WebLayer& layer);
virtual void clearRootLayer();
virtual void setViewportSize(
@@ -95,7 +94,6 @@ class CONTENT_EXPORT RenderWidgetCompositor
virtual float deviceScaleFactor() const;
virtual void setBackgroundColor(blink::WebColor color);
virtual void setHasTransparentBackground(bool transparent);
- virtual void setOverhangBitmap(const SkBitmap& bitmap);
virtual void setVisible(bool visible);
virtual void setPageScaleFactorAndLimits(float page_scale_factor,
float minimum,
@@ -108,44 +106,56 @@ class CONTENT_EXPORT RenderWidgetCompositor
virtual void setNeedsAnimate();
virtual bool commitRequested() const;
virtual void didStopFlinging();
+ virtual void layoutAndPaintAsync(
+ blink::WebLayoutAndPaintAsyncCallback* callback);
virtual void compositeAndReadbackAsync(
blink::WebCompositeAndReadbackAsyncCallback* callback);
virtual void finishAllRendering();
virtual void setDeferCommits(bool defer_commits);
virtual void registerForAnimations(blink::WebLayer* layer);
virtual void registerViewportLayers(
+ const blink::WebLayer* overscrollElasticityLayer,
const blink::WebLayer* pageScaleLayer,
const blink::WebLayer* innerViewportScrollLayer,
const blink::WebLayer* outerViewportScrollLayer) override;
virtual void clearViewportLayers() override;
- virtual void registerSelection(const blink::WebSelectionBound& start,
- const blink::WebSelectionBound& end) override;
+ virtual void registerSelection(const blink::WebSelection& selection) override;
virtual void clearSelection() override;
+ virtual int layerTreeId() const;
virtual void setShowFPSCounter(bool show);
virtual void setShowPaintRects(bool show);
virtual void setShowDebugBorders(bool show);
virtual void setContinuousPaintingEnabled(bool enabled);
virtual void setShowScrollBottleneckRects(bool show);
- virtual void setTopControlsContentOffset(float);
+
+ virtual void updateTopControlsState(blink::WebTopControlsState constraints,
+ blink::WebTopControlsState current,
+ bool animate);
+ virtual void setTopControlsHeight(float height, bool shrink);
+ virtual void setTopControlsShownRatio(float);
// cc::LayerTreeHostClient implementation.
- void WillBeginMainFrame(int frame_id) override;
+ void WillBeginMainFrame() override;
void DidBeginMainFrame() override;
void BeginMainFrame(const cc::BeginFrameArgs& args) override;
+ void BeginMainFrameNotExpectedSoon() override;
void Layout() override;
- void ApplyViewportDeltas(const gfx::Vector2d& inner_delta,
- const gfx::Vector2d& outer_delta,
+ void ApplyViewportDeltas(const gfx::Vector2dF& inner_delta,
+ const gfx::Vector2dF& outer_delta,
+ const gfx::Vector2dF& elastic_overscroll_delta,
float page_scale,
float top_controls_delta) override;
void ApplyViewportDeltas(const gfx::Vector2d& scroll_delta,
float page_scale,
float top_controls_delta) override;
- void RequestNewOutputSurface(bool fallback) override;
+ void RequestNewOutputSurface() override;
void DidInitializeOutputSurface() override;
+ void DidFailToInitializeOutputSurface() override;
void WillCommit() override;
void DidCommit() override;
void DidCommitAndDrawFrame() override;
void DidCompleteSwapBuffers() override;
+ void DidCompletePageScaleAnimation() override;
void RateLimitSharedMainThreadContext() override;
// cc::LayerTreeHostSingleThreadClient implementation.
@@ -153,21 +163,32 @@ class CONTENT_EXPORT RenderWidgetCompositor
void DidPostSwapBuffers() override;
void DidAbortSwapBuffers() override;
- private:
- RenderWidgetCompositor(RenderWidget* widget, bool threaded);
+ enum {
+ OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK = 4,
+ MAX_OUTPUT_SURFACE_RETRIES = 5,
+ };
- void Initialize(cc::LayerTreeSettings settings);
+ protected:
+ RenderWidgetCompositor(RenderWidget* widget,
+ CompositorDependencies* compositor_deps);
+
+ void Initialize();
+ cc::LayerTreeHost* layer_tree_host() { return layer_tree_host_.get(); }
+
+ private:
+ void ScheduleCommit();
+ bool CommitIsSynchronous() const;
+ void SynchronousCommit();
- bool threaded_;
+ int num_failed_recreate_attempts_;
RenderWidget* widget_;
+ CompositorDependencies* compositor_deps_;
scoped_ptr<cc::LayerTreeHost> layer_tree_host_;
+ blink::WebLayoutAndPaintAsyncCallback* layout_and_paint_async_callback_;
scoped_ptr<cc::CopyOutputRequest> temporary_copy_output_request_;
- bool send_v8_idle_notification_after_commit_;
- base::TimeTicks begin_main_frame_time_;
- // The time interval between BeginMainFrame calls, provided by the scheduler.
- base::TimeDelta begin_main_frame_interval_;
+ base::WeakPtrFactory<RenderWidgetCompositor> weak_factory_;
};
} // namespace content
diff --git a/chromium/content/renderer/gpu/render_widget_compositor_unittest.cc b/chromium/content/renderer/gpu/render_widget_compositor_unittest.cc
index 94c5baf6e63..e42fb5845b7 100644
--- a/chromium/content/renderer/gpu/render_widget_compositor_unittest.cc
+++ b/chromium/content/renderer/gpu/render_widget_compositor_unittest.cc
@@ -5,8 +5,13 @@
#include "content/renderer/gpu/render_widget_compositor.h"
#include "cc/output/begin_frame_args.h"
+#include "cc/test/failure_output_surface.h"
+#include "cc/trees/layer_tree_host.h"
+#include "components/scheduler/renderer/renderer_scheduler.h"
#include "content/public/test/mock_render_thread.h"
#include "content/renderer/render_widget.h"
+#include "content/test/fake_compositor_dependencies.h"
+#include "content/test/fake_renderer_scheduler.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/public/platform/WebScreenInfo.h"
@@ -15,6 +20,7 @@ using testing::AllOf;
using testing::Field;
namespace content {
+namespace {
class MockWebWidget : public blink::WebWidget {
public:
@@ -34,7 +40,7 @@ class TestRenderWidget : public RenderWidget {
MockWebWidget mock_webwidget_;
- private:
+ protected:
~TestRenderWidget() override { webwidget_ = NULL; }
DISALLOW_COPY_AND_ASSIGN(TestRenderWidget);
@@ -44,13 +50,17 @@ class RenderWidgetCompositorTest : public testing::Test {
public:
RenderWidgetCompositorTest()
: render_widget_(make_scoped_refptr(new TestRenderWidget())),
+ compositor_deps_(make_scoped_ptr(new FakeCompositorDependencies)),
render_widget_compositor_(
- RenderWidgetCompositor::Create(render_widget_.get(), false)) {}
+ RenderWidgetCompositor::Create(render_widget_.get(),
+ compositor_deps_.get())) {}
~RenderWidgetCompositorTest() override {}
protected:
+ base::MessageLoop loop_;
MockRenderThread render_thread_;
scoped_refptr<TestRenderWidget> render_widget_;
+ scoped_ptr<FakeCompositorDependencies> compositor_deps_;
scoped_ptr<RenderWidgetCompositor> render_widget_compositor_;
private:
@@ -63,7 +73,8 @@ TEST_F(RenderWidgetCompositorTest, BeginMainFrame) {
base::TimeTicks deadline(base::TimeTicks() + base::TimeDelta::FromSeconds(2));
base::TimeDelta interval(base::TimeDelta::FromSeconds(3));
cc::BeginFrameArgs args(
- cc::BeginFrameArgs::Create(frame_time, deadline, interval));
+ cc::BeginFrameArgs::Create(BEGINFRAME_FROM_HERE, frame_time, deadline,
+ interval, cc::BeginFrameArgs::NORMAL));
EXPECT_CALL(render_widget_->mock_webwidget_,
beginFrame(AllOf(
@@ -74,4 +85,235 @@ TEST_F(RenderWidgetCompositorTest, BeginMainFrame) {
render_widget_compositor_->BeginMainFrame(args);
}
+class RenderWidgetCompositorOutputSurface;
+
+class RenderWidgetOutputSurface : public TestRenderWidget {
+ public:
+ RenderWidgetOutputSurface() : compositor_(NULL) {}
+ void SetCompositor(RenderWidgetCompositorOutputSurface* compositor);
+
+ scoped_ptr<cc::OutputSurface> CreateOutputSurface(bool fallback) override;
+
+ protected:
+ ~RenderWidgetOutputSurface() override {}
+
+ private:
+ RenderWidgetCompositorOutputSurface* compositor_;
+
+ DISALLOW_COPY_AND_ASSIGN(RenderWidgetOutputSurface);
+};
+
+// Verify that failing to create an output surface will cause the compositor
+// to attempt to repeatedly create another output surface. After enough
+// failures, verify that it attempts to create a fallback output surface.
+// The use null output surface parameter allows testing whether failures
+// from RenderWidget (couldn't create an output surface) vs failures from
+// the compositor (couldn't bind the output surface) are handled identically.
+class RenderWidgetCompositorOutputSurface : public RenderWidgetCompositor {
+ public:
+ RenderWidgetCompositorOutputSurface(RenderWidget* widget,
+ CompositorDependencies* compositor_deps)
+ : RenderWidgetCompositor(widget, compositor_deps),
+ num_failures_before_success_(0),
+ expected_successes_(0),
+ expected_fallback_successes_(0),
+ expected_requests_(0),
+ num_requests_(0),
+ num_requests_since_last_success_(0),
+ num_successes_(0),
+ num_fallback_successes_(0),
+ num_failures_(0),
+ last_create_was_fallback_(false),
+ use_null_output_surface_(true) {}
+
+ using RenderWidgetCompositor::Initialize;
+
+ scoped_ptr<cc::OutputSurface> CreateOutputSurface(bool fallback) {
+ EXPECT_EQ(num_requests_since_last_success_ >
+ OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK,
+ fallback);
+ last_create_was_fallback_ = fallback;
+ bool success = num_failures_ >= num_failures_before_success_;
+ if (success) {
+ scoped_ptr<cc::TestWebGraphicsContext3D> context =
+ cc::TestWebGraphicsContext3D::Create();
+ // Image support required for synchronous compositing.
+ context->set_support_image(true);
+ return cc::FakeOutputSurface::Create3d(context.Pass());
+ }
+ return use_null_output_surface_
+ ? nullptr
+ : make_scoped_ptr(new cc::FailureOutputSurface(false));
+ }
+
+ // Force a new output surface to be created.
+ void SynchronousComposite() {
+ layer_tree_host()->DidLoseOutputSurface();
+
+ base::TimeTicks some_time;
+ layer_tree_host()->Composite(some_time);
+ }
+
+ void RequestNewOutputSurface() override {
+ ++num_requests_;
+ ++num_requests_since_last_success_;
+ RenderWidgetCompositor::RequestNewOutputSurface();
+ }
+
+ void DidInitializeOutputSurface() override {
+ if (last_create_was_fallback_)
+ ++num_fallback_successes_;
+ else
+ ++num_successes_;
+
+ if (num_requests_ == expected_requests_) {
+ EndTest();
+ } else {
+ num_requests_since_last_success_ = 0;
+ RenderWidgetCompositor::DidInitializeOutputSurface();
+ // Post the synchronous composite task so that it is not called
+ // reentrantly as a part of RequestNewOutputSurface.
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&RenderWidgetCompositorOutputSurface::SynchronousComposite,
+ base::Unretained(this)));
+ }
+ }
+
+ void DidFailToInitializeOutputSurface() override {
+ ++num_failures_;
+ if (num_requests_ == expected_requests_) {
+ EndTest();
+ return;
+ }
+
+ RenderWidgetCompositor::DidFailToInitializeOutputSurface();
+ }
+
+ void SetUp(bool use_null_output_surface,
+ int num_failures_before_success,
+ int expected_successes,
+ int expected_fallback_succeses) {
+ use_null_output_surface_ = use_null_output_surface;
+ num_failures_before_success_ = num_failures_before_success;
+ expected_successes_ = expected_successes;
+ expected_fallback_successes_ = expected_fallback_succeses;
+ expected_requests_ = num_failures_before_success_ + expected_successes_ +
+ expected_fallback_successes_;
+ }
+
+ void EndTest() { base::MessageLoop::current()->Quit(); }
+
+ void AfterTest() {
+ EXPECT_EQ(num_failures_before_success_, num_failures_);
+ EXPECT_EQ(expected_successes_, num_successes_);
+ EXPECT_EQ(expected_fallback_successes_, num_fallback_successes_);
+ EXPECT_EQ(expected_requests_, num_requests_);
+ }
+
+ private:
+ int num_failures_before_success_;
+ int expected_successes_;
+ int expected_fallback_successes_;
+ int expected_requests_;
+ int num_requests_;
+ int num_requests_since_last_success_;
+ int num_successes_;
+ int num_fallback_successes_;
+ int num_failures_;
+ bool last_create_was_fallback_;
+ bool use_null_output_surface_;
+
+ DISALLOW_COPY_AND_ASSIGN(RenderWidgetCompositorOutputSurface);
+};
+
+class RenderWidgetCompositorOutputSurfaceTest : public testing::Test {
+ public:
+ RenderWidgetCompositorOutputSurfaceTest()
+ : render_widget_(make_scoped_refptr(new RenderWidgetOutputSurface)),
+ compositor_deps_(make_scoped_ptr(new FakeCompositorDependencies)) {
+ // Required in order to call the synchronous LayerTreeHost::Composite.
+ compositor_deps_->set_use_single_thread_scheduler(false);
+ render_widget_compositor_.reset(new RenderWidgetCompositorOutputSurface(
+ render_widget_.get(), compositor_deps_.get()));
+ render_widget_compositor_->Initialize();
+ render_widget_->SetCompositor(render_widget_compositor_.get());
+ }
+
+ void RunTest(bool use_null_output_surface,
+ int num_failures_before_success,
+ int expected_successes,
+ int expected_fallback_succeses) {
+ render_widget_compositor_->SetUp(
+ use_null_output_surface, num_failures_before_success,
+ expected_successes, expected_fallback_succeses);
+ render_widget_compositor_->StartCompositor();
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&RenderWidgetCompositorOutputSurface::SynchronousComposite,
+ base::Unretained(render_widget_compositor_.get())));
+ base::MessageLoop::current()->Run();
+ render_widget_compositor_->AfterTest();
+ }
+
+ protected:
+ base::MessageLoop ye_olde_message_loope_;
+ MockRenderThread render_thread_;
+ scoped_refptr<RenderWidgetOutputSurface> render_widget_;
+ scoped_ptr<FakeCompositorDependencies> compositor_deps_;
+ scoped_ptr<RenderWidgetCompositorOutputSurface> render_widget_compositor_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RenderWidgetCompositorOutputSurfaceTest);
+};
+
+scoped_ptr<cc::OutputSurface> RenderWidgetOutputSurface::CreateOutputSurface(
+ bool fallback) {
+ return compositor_->CreateOutputSurface(fallback);
+}
+
+void RenderWidgetOutputSurface::SetCompositor(
+ RenderWidgetCompositorOutputSurface* compositor) {
+ compositor_ = compositor;
+}
+
+TEST_F(RenderWidgetCompositorOutputSurfaceTest, SucceedOnce) {
+ RunTest(false, 0, 1, 0);
+}
+
+TEST_F(RenderWidgetCompositorOutputSurfaceTest, SucceedTwice) {
+ RunTest(false, 0, 2, 0);
+}
+
+TEST_F(RenderWidgetCompositorOutputSurfaceTest, FailOnceNull) {
+ static_assert(
+ RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK >= 2,
+ "Adjust the values of this test if this fails");
+ RunTest(true, 1, 1, 0);
+}
+
+TEST_F(RenderWidgetCompositorOutputSurfaceTest, FailOnceBind) {
+ static_assert(
+ RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK >= 2,
+ "Adjust the values of this test if this fails");
+ RunTest(false, 1, 1, 0);
+}
+
+TEST_F(RenderWidgetCompositorOutputSurfaceTest, FallbackSuccessNull) {
+ RunTest(true, RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK,
+ 0, 1);
+}
+
+TEST_F(RenderWidgetCompositorOutputSurfaceTest, FallbackSuccessBind) {
+ RunTest(false, RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK,
+ 0, 1);
+}
+
+TEST_F(RenderWidgetCompositorOutputSurfaceTest, FallbackSuccessNormalSuccess) {
+ // The first success is a fallback, but the next should not be a fallback.
+ RunTest(false, RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK,
+ 1, 1);
+}
+
+} // namespace
} // namespace content
diff --git a/chromium/content/renderer/gpu/stream_texture_host_android.cc b/chromium/content/renderer/gpu/stream_texture_host_android.cc
index b62903fd15f..fe63557ca2b 100644
--- a/chromium/content/renderer/gpu/stream_texture_host_android.cc
+++ b/chromium/content/renderer/gpu/stream_texture_host_android.cc
@@ -60,8 +60,8 @@ void StreamTextureHost::OnFrameAvailable() {
void StreamTextureHost::OnMatrixChanged(
const GpuStreamTextureMsg_MatrixChanged_Params& params) {
- COMPILE_ASSERT(sizeof(params) == sizeof(float) * 16,
- bad_GpuStreamTextureMsg_MatrixChanged_Params_format);
+ static_assert(sizeof(params) == sizeof(float) * 16,
+ "bad GpuStreamTextureMsg MatrixChanged_Params format");
if (listener_)
listener_->OnMatrixChanged((const float*)&params);
}
diff --git a/chromium/content/renderer/gpu/stream_texture_host_android.h b/chromium/content/renderer/gpu/stream_texture_host_android.h
index 4bd841381bf..871cb63e045 100644
--- a/chromium/content/renderer/gpu/stream_texture_host_android.h
+++ b/chromium/content/renderer/gpu/stream_texture_host_android.h
@@ -24,7 +24,7 @@ class GpuChannelHost;
class StreamTextureHost : public IPC::Listener {
public:
explicit StreamTextureHost(GpuChannelHost* channel);
- virtual ~StreamTextureHost();
+ ~StreamTextureHost() override;
// Listener class that is listening to the stream texture updates. It is
// implemented by StreamTextureProxyImpl.
@@ -38,8 +38,8 @@ class StreamTextureHost : public IPC::Listener {
bool BindToCurrentThread(int32 stream_id, Listener* listener);
// IPC::Channel::Listener implementation:
- virtual bool OnMessageReceived(const IPC::Message& message) override;
- virtual void OnChannelError() override;
+ bool OnMessageReceived(const IPC::Message& message) override;
+ void OnChannelError() override;
private:
// Message handlers:
diff --git a/chromium/content/renderer/history_controller.cc b/chromium/content/renderer/history_controller.cc
index d6f1abdf5e3..f2d3d96d341 100644
--- a/chromium/content/renderer/history_controller.cc
+++ b/chromium/content/renderer/history_controller.cc
@@ -35,6 +35,7 @@
#include "content/renderer/history_controller.h"
+#include "content/common/navigation_params.h"
#include "content/renderer/render_frame_impl.h"
#include "content/renderer/render_view_impl.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
@@ -53,12 +54,15 @@ HistoryController::HistoryController(RenderViewImpl* render_view)
HistoryController::~HistoryController() {
}
-void HistoryController::GoToEntry(scoped_ptr<HistoryEntry> target_entry,
- WebURLRequest::CachePolicy cache_policy) {
+void HistoryController::GoToEntry(
+ scoped_ptr<HistoryEntry> target_entry,
+ scoped_ptr<NavigationParams> navigation_params,
+ WebURLRequest::CachePolicy cache_policy) {
HistoryFrameLoadVector same_document_loads;
HistoryFrameLoadVector different_document_loads;
provisional_entry_ = target_entry.Pass();
+ navigation_params_ = navigation_params.Pass();
WebFrame* main_frame = render_view_->GetMainRenderFrame()->GetWebFrame();
if (current_entry_) {
@@ -78,19 +82,25 @@ void HistoryController::GoToEntry(scoped_ptr<HistoryEntry> target_entry,
std::make_pair(main_frame, provisional_entry_->root()));
}
- for (size_t i = 0; i < same_document_loads.size(); ++i) {
- WebFrame* frame = same_document_loads[i].first;
- if (!RenderFrameImpl::FromWebFrame(frame))
+ for (const auto& item : same_document_loads) {
+ WebFrame* frame = item.first;
+ RenderFrameImpl* render_frame = RenderFrameImpl::FromWebFrame(frame);
+ if (!render_frame)
continue;
- frame->loadHistoryItem(same_document_loads[i].second,
+ render_frame->SetPendingNavigationParams(make_scoped_ptr(
+ new NavigationParams(*navigation_params_.get())));
+ frame->loadHistoryItem(item.second,
blink::WebHistorySameDocumentLoad,
cache_policy);
}
- for (size_t i = 0; i < different_document_loads.size(); ++i) {
- WebFrame* frame = different_document_loads[i].first;
- if (!RenderFrameImpl::FromWebFrame(frame))
+ for (const auto& item : different_document_loads) {
+ WebFrame* frame = item.first;
+ RenderFrameImpl* render_frame = RenderFrameImpl::FromWebFrame(frame);
+ if (!render_frame)
continue;
- frame->loadHistoryItem(different_document_loads[i].second,
+ render_frame->SetPendingNavigationParams(make_scoped_ptr(
+ new NavigationParams(*navigation_params_.get())));
+ frame->loadHistoryItem(item.second,
blink::WebHistoryDifferentDocumentLoad,
cache_policy);
}
@@ -139,6 +149,8 @@ void HistoryController::UpdateForInitialLoadInChildFrame(
}
RenderFrameImpl* parent =
RenderFrameImpl::FromWebFrame(frame->GetWebFrame()->parent());
+ if (!parent)
+ return;
if (HistoryEntry::HistoryNode* parent_history_node =
current_entry_->GetHistoryNodeForFrame(parent)) {
parent_history_node->AddChild(item, frame->GetRoutingID());
@@ -149,14 +161,30 @@ void HistoryController::UpdateForCommit(RenderFrameImpl* frame,
const WebHistoryItem& item,
WebHistoryCommitType commit_type,
bool navigation_within_page) {
- if (commit_type == blink::WebBackForwardCommit) {
- if (!provisional_entry_)
- return;
- current_entry_.reset(provisional_entry_.release());
- } else if (commit_type == blink::WebStandardCommit) {
- CreateNewBackForwardItem(frame, item, navigation_within_page);
- } else if (commit_type == blink::WebInitialCommitInChildFrame) {
- UpdateForInitialLoadInChildFrame(frame, item);
+ switch (commit_type) {
+ case blink::WebBackForwardCommit:
+ if (!provisional_entry_)
+ return;
+ current_entry_.reset(provisional_entry_.release());
+ break;
+ case blink::WebStandardCommit:
+ CreateNewBackForwardItem(frame, item, navigation_within_page);
+ break;
+ case blink::WebInitialCommitInChildFrame:
+ UpdateForInitialLoadInChildFrame(frame, item);
+ break;
+ case blink::WebHistoryInertCommit:
+ // Even for inert commits (e.g., location.replace, client redirects), make
+ // sure the current entry gets updated, if there is one.
+ if (current_entry_) {
+ if (HistoryEntry::HistoryNode* node =
+ current_entry_->GetHistoryNodeForFrame(frame)) {
+ node->set_item(item);
+ }
+ }
+ break;
+ default:
+ NOTREACHED() << "Invalid commit type: " << commit_type;
}
}
@@ -166,6 +194,11 @@ HistoryEntry* HistoryController::GetCurrentEntry() {
WebHistoryItem HistoryController::GetItemForNewChildFrame(
RenderFrameImpl* frame) const {
+ if (navigation_params_.get()) {
+ frame->SetPendingNavigationParams(make_scoped_ptr(
+ new NavigationParams(*navigation_params_.get())));
+ }
+
if (!current_entry_)
return WebHistoryItem();
return current_entry_->GetItemForFrame(frame);
diff --git a/chromium/content/renderer/history_controller.h b/chromium/content/renderer/history_controller.h
index 97969318aff..0a46eefa0d8 100644
--- a/chromium/content/renderer/history_controller.h
+++ b/chromium/content/renderer/history_controller.h
@@ -51,6 +51,7 @@ class WebFrame;
namespace content {
class RenderFrameImpl;
class RenderViewImpl;
+struct NavigationParams;
// A guide to history state in the renderer:
//
@@ -110,6 +111,7 @@ class CONTENT_EXPORT HistoryController {
~HistoryController();
void GoToEntry(scoped_ptr<HistoryEntry> entry,
+ scoped_ptr<NavigationParams> navigation_params,
blink::WebURLRequest::CachePolicy cache_policy);
void UpdateForCommit(RenderFrameImpl* frame,
@@ -136,8 +138,17 @@ class CONTENT_EXPORT HistoryController {
RenderViewImpl* render_view_;
+ // A HistoryEntry representing the currently-loaded page.
scoped_ptr<HistoryEntry> current_entry_;
+ // A HistoryEntry representing the page that is being loaded, or an empty
+ // scoped_ptr if no page is being loaded.
scoped_ptr<HistoryEntry> provisional_entry_;
+ // The NavigationParams corresponding to the last load that was initiated by
+ // |GoToEntry|. This is kept around so that it can be passed into existing
+ // frames modified during a history navigation in GoToEntry(), and can be
+ // passed into frames created after the commit that resulted from the
+ // navigation in GetItemForNewChildFrame().
+ scoped_ptr<NavigationParams> navigation_params_;
DISALLOW_COPY_AND_ASSIGN(HistoryController);
};
diff --git a/chromium/content/renderer/history_entry.cc b/chromium/content/renderer/history_entry.cc
index d1425165a87..7686165f4ee 100644
--- a/chromium/content/renderer/history_entry.cc
+++ b/chromium/content/renderer/history_entry.cc
@@ -86,6 +86,11 @@ HistoryEntry::HistoryNode* HistoryEntry::HistoryNode::CloneAndReplace(
child = child->nextSibling()) {
RenderFrameImpl* child_render_frame =
RenderFrameImpl::FromWebFrame(child);
+ // TODO(creis): A child frame may be a RenderFrameProxy. We should still
+ // process its children, but that will be possible when we move this code
+ // to the browser process in https://crbug.com/236848.
+ if (!child_render_frame)
+ continue;
HistoryNode* child_history_node =
entry_->GetHistoryNodeForFrame(child_render_frame);
if (!child_history_node)
diff --git a/chromium/content/renderer/history_serialization.cc b/chromium/content/renderer/history_serialization.cc
index 7a8167bcfa0..1d14357f5a6 100644
--- a/chromium/content/renderer/history_serialization.cc
+++ b/chromium/content/renderer/history_serialization.cc
@@ -26,7 +26,7 @@ namespace {
void ToNullableString16Vector(const WebVector<WebString>& input,
std::vector<base::NullableString16>* output) {
- output->reserve(input.size());
+ output->reserve(output->size() + input.size());
for (size_t i = 0; i < input.size(); ++i)
output->push_back(input[i]);
}
@@ -89,6 +89,7 @@ void GenerateFrameStateFromItem(const WebHistoryItem& item,
state->target = item.target();
if (!item.stateObject().isNull())
state->state_object = item.stateObject().toString();
+ state->scroll_restoration_type = item.scrollRestorationType();
state->pinch_viewport_scroll_offset = item.pinchViewportScrollOffset();
state->scroll_offset = item.scrollOffset();
state->item_sequence_number = item.itemSequenceNumber();
@@ -114,14 +115,20 @@ void GenerateFrameStateFromItem(const WebHistoryItem& item,
}
}
-void RecursivelyGenerateFrameState(HistoryEntry::HistoryNode* node,
- ExplodedFrameState* state) {
+void RecursivelyGenerateFrameState(
+ HistoryEntry::HistoryNode* node,
+ ExplodedFrameState* state,
+ std::vector<base::NullableString16>* referenced_files) {
GenerateFrameStateFromItem(node->item(), state);
+ ToNullableString16Vector(node->item().getReferencedFilePaths(),
+ referenced_files);
std::vector<HistoryEntry::HistoryNode*>& children = node->children();
state->children.resize(children.size());
- for (size_t i = 0; i < children.size(); ++i)
- RecursivelyGenerateFrameState(children[i], &state->children[i]);
+ for (size_t i = 0; i < children.size(); ++i) {
+ RecursivelyGenerateFrameState(children[i], &state->children[i],
+ referenced_files);
+ }
}
void RecursivelyGenerateHistoryItem(const ExplodedFrameState& state,
@@ -136,6 +143,7 @@ void RecursivelyGenerateHistoryItem(const ExplodedFrameState& state,
WebSerializedScriptValue::fromString(state.state_object));
}
item.setDocumentState(state.document_state);
+ item.setScrollRestorationType(state.scroll_restoration_type);
item.setPinchViewportScrollOffset(state.pinch_viewport_scroll_offset);
item.setScrollOffset(state.scroll_offset);
item.setPageScaleFactor(state.page_scale_factor);
@@ -169,10 +177,8 @@ void RecursivelyGenerateHistoryItem(const ExplodedFrameState& state,
PageState HistoryEntryToPageState(HistoryEntry* entry) {
ExplodedPageState state;
- ToNullableString16Vector(entry->root().getReferencedFilePaths(),
- &state.referenced_files);
-
- RecursivelyGenerateFrameState(entry->root_history_node(), &state.top);
+ RecursivelyGenerateFrameState(entry->root_history_node(), &state.top,
+ &state.referenced_files);
std::string encoded_data;
if (!EncodePageState(state, &encoded_data))
diff --git a/chromium/content/renderer/image_loading_helper.cc b/chromium/content/renderer/image_loading_helper.cc
index b0099ffce5b..afd0fee406d 100644
--- a/chromium/content/renderer/image_loading_helper.cc
+++ b/chromium/content/renderer/image_loading_helper.cc
@@ -17,7 +17,7 @@
#include "third_party/WebKit/public/web/WebLocalFrame.h"
#include "third_party/WebKit/public/web/WebView.h"
#include "ui/gfx/favicon_size.h"
-#include "ui/gfx/size.h"
+#include "ui/gfx/geometry/size.h"
#include "ui/gfx/skbitmap_operations.h"
#include "url/url_constants.h"
@@ -104,10 +104,12 @@ ImageLoadingHelper::ImageLoadingHelper(RenderFrame* render_frame)
ImageLoadingHelper::~ImageLoadingHelper() {
}
-void ImageLoadingHelper::OnDownloadImage(int id,
- const GURL& image_url,
- bool is_favicon,
- uint32_t max_image_size) {
+void ImageLoadingHelper::OnDownloadImage(
+ int id,
+ const GURL& image_url,
+ bool is_favicon,
+ uint32_t max_image_size,
+ bool bypass_cache) {
std::vector<SkBitmap> result_images;
std::vector<gfx::Size> result_original_image_sizes;
if (image_url.SchemeIs(url::kDataScheme)) {
@@ -118,7 +120,8 @@ void ImageLoadingHelper::OnDownloadImage(int id,
gfx::Size(data_image.width(), data_image.height()));
}
} else {
- if (DownloadImage(id, image_url, is_favicon, max_image_size)) {
+ if (DownloadImage(id, image_url, is_favicon, max_image_size,
+ bypass_cache)) {
// Will complete asynchronously via ImageLoadingHelper::DidDownloadImage
return;
}
@@ -132,19 +135,20 @@ void ImageLoadingHelper::OnDownloadImage(int id,
result_original_image_sizes));
}
-bool ImageLoadingHelper::DownloadImage(int id,
- const GURL& image_url,
- bool is_favicon,
- uint32_t max_image_size) {
+bool ImageLoadingHelper::DownloadImage(
+ int id,
+ const GURL& image_url,
+ bool is_favicon,
+ uint32_t max_image_size,
+ bool bypass_cache) {
// Create an image resource fetcher and assign it with a call back object.
image_fetchers_.push_back(new MultiResolutionImageResourceFetcher(
- image_url,
- render_frame()->GetWebFrame(),
- id,
+ image_url, render_frame()->GetWebFrame(), id,
is_favicon ? WebURLRequest::RequestContextFavicon
: WebURLRequest::RequestContextImage,
- base::Bind(&ImageLoadingHelper::DidDownloadImage,
- base::Unretained(this),
+ bypass_cache ? WebURLRequest::ReloadBypassingCache
+ : WebURLRequest::UseProtocolCachePolicy,
+ base::Bind(&ImageLoadingHelper::DidDownloadImage, base::Unretained(this),
max_image_size)));
return true;
}
diff --git a/chromium/content/renderer/image_loading_helper.h b/chromium/content/renderer/image_loading_helper.h
index 185f3b7e4f1..d5daf8fa517 100644
--- a/chromium/content/renderer/image_loading_helper.h
+++ b/chromium/content/renderer/image_loading_helper.h
@@ -31,7 +31,8 @@ class ImageLoadingHelper : public RenderFrameObserver {
void OnDownloadImage(int id,
const GURL& image_url,
bool is_favicon,
- uint32_t max_image_size);
+ uint32_t max_image_size,
+ bool bypass_cache);
// Requests to download an image. When done, the ImageLoadingHelper
// is notified by way of DidDownloadImage. Returns true if the
@@ -46,7 +47,8 @@ class ImageLoadingHelper : public RenderFrameObserver {
bool DownloadImage(int id,
const GURL& image_url,
bool is_favicon,
- uint32_t max_image_size);
+ uint32_t max_image_size,
+ bool bypass_cache);
// This callback is triggered when DownloadImage completes, either
// succesfully or with a failure. See DownloadImage for more
diff --git a/chromium/content/renderer/ime_event_guard.h b/chromium/content/renderer/ime_event_guard.h
index eb3ab576f7e..811540e988b 100644
--- a/chromium/content/renderer/ime_event_guard.h
+++ b/chromium/content/renderer/ime_event_guard.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 IME_EVENT_GUARD_H_
-#define IME_EVENT_GUARD_H_
+#ifndef CONTENT_RENDERER_IME_EVENT_GUARD_H_
+#define CONTENT_RENDERER_IME_EVENT_GUARD_H_
namespace content {
class RenderWidget;
@@ -19,5 +19,5 @@ class ImeEventGuard {
};
}
-#endif
+#endif // CONTENT_RENDERER_IME_EVENT_GUARD_H_
diff --git a/chromium/content/renderer/in_process_renderer_thread.cc b/chromium/content/renderer/in_process_renderer_thread.cc
index fa6b834b176..f2eecf9088e 100644
--- a/chromium/content/renderer/in_process_renderer_thread.cc
+++ b/chromium/content/renderer/in_process_renderer_thread.cc
@@ -10,8 +10,9 @@
namespace content {
-InProcessRendererThread::InProcessRendererThread(const std::string& channel_id)
- : Thread("Chrome_InProcRendererThread"), channel_id_(channel_id) {
+InProcessRendererThread::InProcessRendererThread(
+ const InProcessChildThreadParams& params)
+ : Thread("Chrome_InProcRendererThread"), params_(params) {
}
InProcessRendererThread::~InProcessRendererThread() {
@@ -20,7 +21,7 @@ InProcessRendererThread::~InProcessRendererThread() {
void InProcessRendererThread::Init() {
render_process_.reset(new RenderProcessImpl());
- new RenderThreadImpl(channel_id_);
+ new RenderThreadImpl(params_);
}
void InProcessRendererThread::CleanUp() {
@@ -38,8 +39,9 @@ void InProcessRendererThread::CleanUp() {
SetThreadWasQuitProperly(true);
}
-base::Thread* CreateInProcessRendererThread(const std::string& channel_id) {
- return new InProcessRendererThread(channel_id);
+base::Thread* CreateInProcessRendererThread(
+ const InProcessChildThreadParams& params) {
+ return new InProcessRendererThread(params);
}
} // namespace content
diff --git a/chromium/content/renderer/in_process_renderer_thread.h b/chromium/content/renderer/in_process_renderer_thread.h
index 4b4bc65608f..115616065a3 100644
--- a/chromium/content/renderer/in_process_renderer_thread.h
+++ b/chromium/content/renderer/in_process_renderer_thread.h
@@ -9,6 +9,7 @@
#include "base/threading/thread.h"
#include "content/common/content_export.h"
+#include "content/common/in_process_child_thread_params.h"
namespace content {
class RenderProcess;
@@ -17,7 +18,7 @@ class RenderProcess;
// single-process mode. It's not used in multi-process mode.
class InProcessRendererThread : public base::Thread {
public:
- explicit InProcessRendererThread(const std::string& channel_id);
+ explicit InProcessRendererThread(const InProcessChildThreadParams& params);
~InProcessRendererThread() override;
protected:
@@ -25,14 +26,14 @@ class InProcessRendererThread : public base::Thread {
void CleanUp() override;
private:
- std::string channel_id_;
+ InProcessChildThreadParams params_;
scoped_ptr<RenderProcess> render_process_;
DISALLOW_COPY_AND_ASSIGN(InProcessRendererThread);
};
CONTENT_EXPORT base::Thread* CreateInProcessRendererThread(
- const std::string& channel_id);
+ const InProcessChildThreadParams& params);
} // namespace content
diff --git a/chromium/content/renderer/input/input_event_filter.cc b/chromium/content/renderer/input/input_event_filter.cc
index d93836a981e..180be389354 100644
--- a/chromium/content/renderer/input/input_event_filter.cc
+++ b/chromium/content/renderer/input/input_event_filter.cc
@@ -6,11 +6,10 @@
#include "base/auto_reset.h"
#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/debug/trace_event.h"
#include "base/location.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/single_thread_task_runner.h"
+#include "base/trace_event/trace_event.h"
#include "cc/input/input_handler.h"
#include "content/common/input/did_overscroll_params.h"
#include "content/common/input/web_input_event_traits.h"
@@ -19,7 +18,7 @@
#include "content/public/common/content_switches.h"
#include "ipc/ipc_listener.h"
#include "ipc/ipc_sender.h"
-#include "ui/gfx/vector2d_f.h"
+#include "ui/gfx/geometry/vector2d_f.h"
using blink::WebInputEvent;
@@ -41,19 +40,15 @@ const char* GetInputMessageTypeName(const IPC::Message& message) {
namespace content {
InputEventFilter::InputEventFilter(
- IPC::Listener* main_listener,
+ const base::Callback<void(const IPC::Message&)>& main_listener,
const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner,
const scoped_refptr<base::MessageLoopProxy>& target_loop)
: main_task_runner_(main_task_runner),
main_listener_(main_listener),
sender_(NULL),
target_loop_(target_loop),
- overscroll_notifications_enabled_(false),
current_overscroll_params_(NULL) {
DCHECK(target_loop_.get());
- overscroll_notifications_enabled_ =
- CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableOverscrollNotifications);
}
void InputEventFilter::SetBoundHandler(const Handler& handler) {
@@ -74,9 +69,6 @@ void InputEventFilter::DidRemoveInputHandler(int routing_id) {
void InputEventFilter::DidOverscroll(int routing_id,
const DidOverscrollParams& params) {
- if (!overscroll_notifications_enabled_)
- return;
-
if (current_overscroll_params_) {
current_overscroll_params_->reset(new DidOverscrollParams(params));
return;
@@ -87,8 +79,7 @@ void InputEventFilter::DidOverscroll(int routing_id,
}
void InputEventFilter::DidStopFlinging(int routing_id) {
- SendMessage(
- scoped_ptr<IPC::Message>(new ViewHostMsg_DidStopFlinging(routing_id)));
+ SendMessage(make_scoped_ptr(new InputHostMsg_DidStopFlinging(routing_id)));
}
void InputEventFilter::OnFilterAdded(IPC::Sender* sender) {
@@ -135,10 +126,6 @@ InputEventFilter::~InputEventFilter() {
DCHECK(!current_overscroll_params_);
}
-void InputEventFilter::ForwardToMainListener(const IPC::Message& message) {
- main_listener_->OnMessageReceived(message);
-}
-
void InputEventFilter::ForwardToHandler(const IPC::Message& message) {
DCHECK(!handler_.is_null());
DCHECK(target_loop_->BelongsToCurrentThread());
@@ -150,9 +137,7 @@ void InputEventFilter::ForwardToHandler(const IPC::Message& message) {
"input",
"InputEventFilter::ForwardToHandler::ForwardToMainListener",
TRACE_EVENT_SCOPE_THREAD);
- main_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&InputEventFilter::ForwardToMainListener, this, message));
+ main_task_runner_->PostTask(FROM_HERE, base::Bind(main_listener_, message));
return;
}
@@ -160,9 +145,9 @@ void InputEventFilter::ForwardToHandler(const IPC::Message& message) {
InputMsg_HandleInputEvent::Param params;
if (!InputMsg_HandleInputEvent::Read(&message, &params))
return;
- const WebInputEvent* event = params.a;
- ui::LatencyInfo latency_info = params.b;
- bool is_keyboard_shortcut = params.c;
+ const WebInputEvent* event = get<0>(params);
+ ui::LatencyInfo latency_info = get<1>(params);
+ bool is_keyboard_shortcut = get<2>(params);
DCHECK(event);
const bool send_ack = !WebInputEventTraits::IgnoresAckDisposition(*event);
@@ -184,9 +169,7 @@ void InputEventFilter::ForwardToHandler(const IPC::Message& message) {
TRACE_EVENT_SCOPE_THREAD);
IPC::Message new_msg = InputMsg_HandleInputEvent(
routing_id, event, latency_info, is_keyboard_shortcut);
- main_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&InputEventFilter::ForwardToMainListener, this, new_msg));
+ main_task_runner_->PostTask(FROM_HERE, base::Bind(main_listener_, new_msg));
return;
}
diff --git a/chromium/content/renderer/input/input_event_filter.h b/chromium/content/renderer/input/input_event_filter.h
index e7982f6ffd4..e58798d4e7a 100644
--- a/chromium/content/renderer/input/input_event_filter.h
+++ b/chromium/content/renderer/input/input_event_filter.h
@@ -8,7 +8,7 @@
#include <queue>
#include <set>
-#include "base/callback_forward.h"
+#include "base/callback.h"
#include "base/synchronization/lock.h"
#include "content/common/content_export.h"
#include "content/common/input/input_event_ack_state.h"
@@ -40,7 +40,7 @@ class CONTENT_EXPORT InputEventFilter : public InputHandlerManagerClient,
public IPC::MessageFilter {
public:
InputEventFilter(
- IPC::Listener* main_listener,
+ const base::Callback<void(const IPC::Message&)>& main_listener,
const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner,
const scoped_refptr<base::MessageLoopProxy>& target_loop);
@@ -71,13 +71,12 @@ class CONTENT_EXPORT InputEventFilter : public InputHandlerManagerClient,
private:
~InputEventFilter() override;
- void ForwardToMainListener(const IPC::Message& message);
void ForwardToHandler(const IPC::Message& message);
void SendMessage(scoped_ptr<IPC::Message> message);
void SendMessageOnIOThread(scoped_ptr<IPC::Message> message);
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
- IPC::Listener* main_listener_;
+ base::Callback<void(const IPC::Message&)> main_listener_;
// The sender_ only gets invoked on the thread corresponding to io_loop_.
scoped_refptr<base::MessageLoopProxy> io_loop_;
@@ -93,9 +92,6 @@ class CONTENT_EXPORT InputEventFilter : public InputHandlerManagerClient,
// Indicates the routing_ids for which input events should be filtered.
std::set<int> routes_;
- // Specifies whether overscroll notifications are forwarded to the host.
- bool overscroll_notifications_enabled_;
-
// Used to intercept overscroll notifications while an event is being
// dispatched. If the event causes overscroll, the overscroll metadata can be
// bundled in the event ack, saving an IPC. Note that we must continue
diff --git a/chromium/content/renderer/input/input_event_filter_unittest.cc b/chromium/content/renderer/input/input_event_filter_unittest.cc
index b7befdb67cc..79cb66c803a 100644
--- a/chromium/content/renderer/input/input_event_filter_unittest.cc
+++ b/chromium/content/renderer/input/input_event_filter_unittest.cc
@@ -126,19 +126,18 @@ void AddEventsToFilter(IPC::MessageFilter* message_filter,
class InputEventFilterTest : public testing::Test {
public:
void SetUp() override {
- filter_ = new InputEventFilter(&message_recorder_,
- base::MessageLoopProxy::current(),
- message_loop_.message_loop_proxy());
- filter_->SetBoundHandler(
- base::Bind(&InputEventRecorder::HandleInputEvent,
- base::Unretained(&event_recorder_)));
+ filter_ = new InputEventFilter(
+ base::Bind(base::IgnoreResult(&IPCMessageRecorder::OnMessageReceived),
+ base::Unretained(&message_recorder_)),
+ base::MessageLoopProxy::current(), message_loop_.message_loop_proxy());
+ filter_->SetBoundHandler(base::Bind(&InputEventRecorder::HandleInputEvent,
+ base::Unretained(&event_recorder_)));
event_recorder_.set_filter(filter_.get());
filter_->OnFilterAdded(&ipc_sink_);
}
-
protected:
base::MessageLoop message_loop_;
@@ -180,8 +179,8 @@ TEST_F(InputEventFilterTest, Basic) {
InputHostMsg_HandleInputEvent_ACK::Param params;
EXPECT_TRUE(InputHostMsg_HandleInputEvent_ACK::Read(message, &params));
- WebInputEvent::Type event_type = params.a.type;
- InputEventAckState ack_result = params.a.state;
+ WebInputEvent::Type event_type = get<0>(params).type;
+ InputEventAckState ack_result = get<0>(params).state;
EXPECT_EQ(kEvents[i].type, event_type);
EXPECT_EQ(ack_result, INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
@@ -206,7 +205,7 @@ TEST_F(InputEventFilterTest, Basic) {
ASSERT_EQ(InputMsg_HandleInputEvent::ID, message.type());
InputMsg_HandleInputEvent::Param params;
EXPECT_TRUE(InputMsg_HandleInputEvent::Read(&message, &params));
- const WebInputEvent* event = params.a;
+ const WebInputEvent* event = get<0>(params);
EXPECT_EQ(kEvents[i].size, event->size);
EXPECT_TRUE(memcmp(&kEvents[i], event, event->size) == 0);
@@ -232,8 +231,8 @@ TEST_F(InputEventFilterTest, Basic) {
InputHostMsg_HandleInputEvent_ACK::Param params;
EXPECT_TRUE(InputHostMsg_HandleInputEvent_ACK::Read(message, &params));
- WebInputEvent::Type event_type = params.a.type;
- InputEventAckState ack_result = params.a.state;
+ WebInputEvent::Type event_type = get<0>(params).type;
+ InputEventAckState ack_result = get<0>(params).state;
EXPECT_EQ(kEvents[i].type, event_type);
EXPECT_EQ(ack_result, INPUT_EVENT_ACK_STATE_CONSUMED);
}
diff --git a/chromium/content/renderer/input/input_handler_manager.cc b/chromium/content/renderer/input/input_handler_manager.cc
index a5433de2a30..149b8b2d084 100644
--- a/chromium/content/renderer/input/input_handler_manager.cc
+++ b/chromium/content/renderer/input/input_handler_manager.cc
@@ -5,14 +5,17 @@
#include "content/renderer/input/input_handler_manager.h"
#include "base/bind.h"
-#include "base/debug/trace_event.h"
#include "base/message_loop/message_loop_proxy.h"
+#include "base/trace_event/trace_event.h"
#include "cc/input/input_handler.h"
+#include "components/scheduler/renderer/renderer_scheduler.h"
#include "content/renderer/input/input_event_filter.h"
#include "content/renderer/input/input_handler_manager_client.h"
#include "content/renderer/input/input_handler_wrapper.h"
+#include "content/renderer/input/input_scroll_elasticity_controller.h"
using blink::WebInputEvent;
+using scheduler::RendererScheduler;
namespace content {
@@ -36,9 +39,11 @@ InputEventAckState InputEventDispositionToAck(
InputHandlerManager::InputHandlerManager(
const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy,
- InputHandlerManagerClient* client)
+ InputHandlerManagerClient* client,
+ scheduler::RendererScheduler* renderer_scheduler)
: message_loop_proxy_(message_loop_proxy),
- client_(client) {
+ client_(client),
+ renderer_scheduler_(renderer_scheduler) {
DCHECK(client_);
client_->SetBoundHandler(base::Bind(&InputHandlerManager::HandleInputEvent,
base::Unretained(this)));
@@ -103,13 +108,38 @@ void InputHandlerManager::RemoveInputHandler(int routing_id) {
input_handlers_.erase(routing_id);
}
+void InputHandlerManager::ObserveWheelEventAndResultOnMainThread(
+ int routing_id,
+ const blink::WebMouseWheelEvent& wheel_event,
+ const cc::InputHandlerScrollResult& scroll_result) {
+ message_loop_proxy_->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &InputHandlerManager::ObserveWheelEventAndResultOnCompositorThread,
+ base::Unretained(this), routing_id, wheel_event, scroll_result));
+}
+
+void InputHandlerManager::ObserveWheelEventAndResultOnCompositorThread(
+ int routing_id,
+ const blink::WebMouseWheelEvent& wheel_event,
+ const cc::InputHandlerScrollResult& scroll_result) {
+ auto it = input_handlers_.find(routing_id);
+ if (it == input_handlers_.end())
+ return;
+
+ InputHandlerProxy* proxy = it->second->input_handler_proxy();
+ DCHECK(proxy->scroll_elasticity_controller());
+ proxy->scroll_elasticity_controller()->ObserveWheelEventAndResult(
+ wheel_event, scroll_result);
+}
+
InputEventAckState InputHandlerManager::HandleInputEvent(
int routing_id,
const WebInputEvent* input_event,
ui::LatencyInfo* latency_info) {
DCHECK(message_loop_proxy_->BelongsToCurrentThread());
- InputHandlerMap::iterator it = input_handlers_.find(routing_id);
+ auto it = input_handlers_.find(routing_id);
if (it == input_handlers_.end()) {
TRACE_EVENT1("input", "InputHandlerManager::HandleInputEvent",
"result", "NoInputHandlerFound");
@@ -118,8 +148,23 @@ InputEventAckState InputHandlerManager::HandleInputEvent(
}
InputHandlerProxy* proxy = it->second->input_handler_proxy();
- return InputEventDispositionToAck(
+ InputEventAckState input_event_ack_state = InputEventDispositionToAck(
proxy->HandleInputEventWithLatencyInfo(*input_event, latency_info));
+ switch (input_event_ack_state) {
+ case INPUT_EVENT_ACK_STATE_CONSUMED:
+ renderer_scheduler_->DidHandleInputEventOnCompositorThread(
+ *input_event,
+ RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
+ break;
+ case INPUT_EVENT_ACK_STATE_NOT_CONSUMED:
+ renderer_scheduler_->DidHandleInputEventOnCompositorThread(
+ *input_event,
+ RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
+ break;
+ default:
+ break;
+ }
+ return input_event_ack_state;
}
void InputHandlerManager::DidOverscroll(int routing_id,
@@ -131,4 +176,8 @@ void InputHandlerManager::DidStopFlinging(int routing_id) {
client_->DidStopFlinging(routing_id);
}
+void InputHandlerManager::DidAnimateForInput() {
+ renderer_scheduler_->DidAnimateForInputOnCompositorThread();
+}
+
} // namespace content
diff --git a/chromium/content/renderer/input/input_handler_manager.h b/chromium/content/renderer/input/input_handler_manager.h
index b6c70700526..9276ecc0eb4 100644
--- a/chromium/content/renderer/input/input_handler_manager.h
+++ b/chromium/content/renderer/input/input_handler_manager.h
@@ -17,10 +17,16 @@ class MessageLoopProxy;
namespace cc {
class InputHandler;
+struct InputHandlerScrollResult;
}
namespace blink {
class WebInputEvent;
+class WebMouseWheelEvent;
+}
+
+namespace scheduler {
+class RendererScheduler;
}
namespace content {
@@ -33,11 +39,14 @@ struct DidOverscrollParams;
// the WebViews in this renderer.
class InputHandlerManager {
public:
- // |message_loop_proxy| is the MessageLoopProxy of the compositor thread. Both
- // the underlying MessageLoop and supplied |client| must outlive this object.
+ // |message_loop_proxy| is the MessageLoopProxy of the compositor thread. The
+ // underlying MessageLoop and supplied |client| and the |renderer_scheduler|
+ // must outlive this object. The RendererScheduler needs to know when input
+ // events and fling animations occur, which is why it's passed in here.
InputHandlerManager(
const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy,
- InputHandlerManagerClient* client);
+ InputHandlerManagerClient* client,
+ scheduler::RendererScheduler* renderer_scheduler);
~InputHandlerManager();
// Callable from the main thread only.
@@ -46,6 +55,11 @@ class InputHandlerManager {
const base::WeakPtr<cc::InputHandler>& input_handler,
const base::WeakPtr<RenderViewImpl>& render_view_impl);
+ void ObserveWheelEventAndResultOnMainThread(
+ int routing_id,
+ const blink::WebMouseWheelEvent& wheel_event,
+ const cc::InputHandlerScrollResult& scroll_result);
+
// Callback only from the compositor's thread.
void RemoveInputHandler(int routing_id);
@@ -60,6 +74,9 @@ class InputHandlerManager {
// Called from the compositor's thread.
void DidStopFlinging(int routing_id);
+ // Called from the compositor's thread.
+ void DidAnimateForInput();
+
private:
// Called from the compositor's thread.
void AddInputHandlerOnCompositorThread(
@@ -68,12 +85,19 @@ class InputHandlerManager {
const base::WeakPtr<cc::InputHandler>& input_handler,
const base::WeakPtr<RenderViewImpl>& render_view_impl);
+ void ObserveWheelEventAndResultOnCompositorThread(
+ int routing_id,
+ const blink::WebMouseWheelEvent& wheel_event,
+ const cc::InputHandlerScrollResult& scroll_result);
+
typedef base::ScopedPtrHashMap<int, // routing_id
- InputHandlerWrapper> InputHandlerMap;
+ scoped_ptr<InputHandlerWrapper>>
+ InputHandlerMap;
InputHandlerMap input_handlers_;
scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
InputHandlerManagerClient* client_;
+ scheduler::RendererScheduler* renderer_scheduler_; // Not owned.
};
} // namespace content
diff --git a/chromium/content/renderer/input/input_handler_manager_client.h b/chromium/content/renderer/input/input_handler_manager_client.h
index 26a7b64b337..a5c4cf26b30 100644
--- a/chromium/content/renderer/input/input_handler_manager_client.h
+++ b/chromium/content/renderer/input/input_handler_manager_client.h
@@ -9,7 +9,7 @@
#include "base/callback.h"
#include "base/callback_forward.h"
#include "content/common/content_export.h"
-#include "ui/gfx/vector2d_f.h"
+#include "ui/gfx/geometry/vector2d_f.h"
namespace ui {
struct LatencyInfo;
@@ -58,4 +58,4 @@ class CONTENT_EXPORT InputHandlerManagerClient {
} // namespace content
-#endif // CONTENT_COMMON_GPU_INPUT_HANDLER_MANAGER_CLIENT_H_
+#endif // CONTENT_RENDERER_INPUT_INPUT_HANDLER_MANAGER_CLIENT_H_
diff --git a/chromium/content/renderer/input/input_handler_proxy.cc b/chromium/content/renderer/input/input_handler_proxy.cc
index 44b613914b3..b92fafd0aac 100644
--- a/chromium/content/renderer/input/input_handler_proxy.cc
+++ b/chromium/content/renderer/input/input_handler_proxy.cc
@@ -6,13 +6,14 @@
#include "base/auto_reset.h"
#include "base/command_line.h"
-#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
+#include "base/trace_event/trace_event.h"
#include "content/common/input/did_overscroll_params.h"
#include "content/common/input/web_input_event_traits.h"
#include "content/public/common/content_switches.h"
#include "content/renderer/input/input_handler_proxy_client.h"
+#include "content/renderer/input/input_scroll_elasticity_controller.h"
#include "third_party/WebKit/public/platform/Platform.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
#include "ui/events/latency_info.h"
@@ -114,12 +115,15 @@ WebGestureEvent ObtainGestureScrollBegin(const WebGestureEvent& event) {
return scroll_begin_event;
}
-void SendScrollLatencyUma(const WebInputEvent& event,
- const ui::LatencyInfo& latency_info) {
+void ReportInputEventLatencyUma(const WebInputEvent& event,
+ const ui::LatencyInfo& latency_info) {
if (!(event.type == WebInputEvent::GestureScrollBegin ||
event.type == WebInputEvent::GestureScrollUpdate ||
- event.type == WebInputEvent::GestureScrollUpdateWithoutPropagation))
+ event.type == WebInputEvent::GesturePinchBegin ||
+ event.type == WebInputEvent::GesturePinchUpdate ||
+ event.type == WebInputEvent::GestureFlingStart)) {
return;
+ }
ui::LatencyInfo::LatencyMap::const_iterator it =
latency_info.latency_components.find(std::make_pair(
@@ -128,19 +132,44 @@ void SendScrollLatencyUma(const WebInputEvent& event,
if (it == latency_info.latency_components.end())
return;
- base::TimeDelta delta = base::TimeTicks::HighResNow() - it->second.event_time;
+ base::TimeDelta delta = base::TimeTicks::Now() - it->second.event_time;
for (size_t i = 0; i < it->second.event_count; ++i) {
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "Event.Latency.RendererImpl.GestureScroll2",
- delta.InMicroseconds(),
- 1,
- 1000000,
- 100);
+ switch (event.type) {
+ case blink::WebInputEvent::GestureScrollBegin:
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ "Event.Latency.RendererImpl.GestureScrollBegin",
+ delta.InMicroseconds(), 1, 1000000, 100);
+ break;
+ case blink::WebInputEvent::GestureScrollUpdate:
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ // So named for historical reasons.
+ "Event.Latency.RendererImpl.GestureScroll2",
+ delta.InMicroseconds(), 1, 1000000, 100);
+ break;
+ case blink::WebInputEvent::GesturePinchBegin:
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ "Event.Latency.RendererImpl.GesturePinchBegin",
+ delta.InMicroseconds(), 1, 1000000, 100);
+ break;
+ case blink::WebInputEvent::GesturePinchUpdate:
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ "Event.Latency.RendererImpl.GesturePinchUpdate",
+ delta.InMicroseconds(), 1, 1000000, 100);
+ break;
+ case blink::WebInputEvent::GestureFlingStart:
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ "Event.Latency.RendererImpl.GestureFlingStart",
+ delta.InMicroseconds(), 1, 1000000, 100);
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
}
-} // namespace
-
}
+} // namespace
+
namespace content {
InputHandlerProxy::InputHandlerProxy(cc::InputHandler* input_handler,
@@ -156,16 +185,24 @@ InputHandlerProxy::InputHandlerProxy(cc::InputHandler* input_handler,
fling_may_be_active_on_main_thread_(false),
disallow_horizontal_fling_scroll_(false),
disallow_vertical_fling_scroll_(false),
- has_fling_animation_started_(false) {
+ has_fling_animation_started_(false),
+ uma_latency_reporting_enabled_(base::TimeTicks::IsHighResolution()) {
DCHECK(client);
input_handler_->BindToClient(this);
- smooth_scroll_enabled_ = CommandLine::ForCurrentProcess()->HasSwitch(
+ smooth_scroll_enabled_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableSmoothScrolling);
+ cc::ScrollElasticityHelper* scroll_elasticity_helper =
+ input_handler_->CreateScrollElasticityHelper();
+ if (scroll_elasticity_helper) {
+ scroll_elasticity_controller_.reset(
+ new InputScrollElasticityController(scroll_elasticity_helper));
+ }
}
InputHandlerProxy::~InputHandlerProxy() {}
void InputHandlerProxy::WillShutdown() {
+ scroll_elasticity_controller_.reset();
input_handler_ = NULL;
client_->WillShutdown();
}
@@ -176,9 +213,10 @@ InputHandlerProxy::HandleInputEventWithLatencyInfo(
ui::LatencyInfo* latency_info) {
DCHECK(input_handler_);
- SendScrollLatencyUma(event, *latency_info);
+ if (uma_latency_reporting_enabled_)
+ ReportInputEventLatencyUma(event, *latency_info);
- TRACE_EVENT_FLOW_STEP0("input",
+ TRACE_EVENT_FLOW_STEP0("input,benchmark",
"LatencyInfo.Flow",
TRACE_ID_DONT_MANGLE(latency_info->trace_id),
"HandleInputEventImpl");
@@ -192,202 +230,265 @@ InputHandlerProxy::HandleInputEventWithLatencyInfo(
InputHandlerProxy::EventDisposition InputHandlerProxy::HandleInputEvent(
const WebInputEvent& event) {
DCHECK(input_handler_);
- TRACE_EVENT1("input", "InputHandlerProxy::HandleInputEvent",
+ TRACE_EVENT1("input,benchmark", "InputHandlerProxy::HandleInputEvent",
"type", WebInputEventTraits::GetName(event.type));
- client_->DidReceiveInputEvent();
if (FilterInputEventForFlingBoosting(event))
return DID_HANDLE;
- if (event.type == WebInputEvent::MouseWheel) {
- const WebMouseWheelEvent& wheel_event =
- *static_cast<const WebMouseWheelEvent*>(&event);
- if (wheel_event.scrollByPage) {
- // TODO(jamesr): We don't properly handle scroll by page in the compositor
- // thread, so punt it to the main thread. http://crbug.com/236639
- return DID_NOT_HANDLE;
+ switch (event.type) {
+ case WebInputEvent::MouseWheel:
+ return HandleMouseWheel(static_cast<const WebMouseWheelEvent&>(event));
+
+ case WebInputEvent::GestureScrollBegin:
+ return HandleGestureScrollBegin(
+ static_cast<const WebGestureEvent&>(event));
+
+ case WebInputEvent::GestureScrollUpdate:
+ return HandleGestureScrollUpdate(
+ static_cast<const WebGestureEvent&>(event));
+
+ case WebInputEvent::GestureScrollEnd:
+ return HandleGestureScrollEnd(static_cast<const WebGestureEvent&>(event));
+
+ case WebInputEvent::GesturePinchBegin: {
+ DCHECK(!gesture_pinch_on_impl_thread_);
+ const WebGestureEvent& gesture_event =
+ static_cast<const WebGestureEvent&>(event);
+ if (gesture_event.sourceDevice == blink::WebGestureDeviceTouchpad &&
+ input_handler_->HaveWheelEventHandlersAt(
+ gfx::Point(gesture_event.x, gesture_event.y))) {
+ return DID_NOT_HANDLE;
+ } else {
+ input_handler_->PinchGestureBegin();
+ gesture_pinch_on_impl_thread_ = true;
+ return DID_HANDLE;
+ }
+ }
+
+ case WebInputEvent::GesturePinchEnd:
+ if (gesture_pinch_on_impl_thread_) {
+ gesture_pinch_on_impl_thread_ = false;
+ input_handler_->PinchGestureEnd();
+ return DID_HANDLE;
+ } else {
+ return DID_NOT_HANDLE;
+ }
+
+ case WebInputEvent::GesturePinchUpdate: {
+ if (gesture_pinch_on_impl_thread_) {
+ const WebGestureEvent& gesture_event =
+ static_cast<const WebGestureEvent&>(event);
+ if (gesture_event.data.pinchUpdate.zoomDisabled)
+ return DROP_EVENT;
+ input_handler_->PinchGestureUpdate(
+ gesture_event.data.pinchUpdate.scale,
+ gfx::Point(gesture_event.x, gesture_event.y));
+ return DID_HANDLE;
+ } else {
+ return DID_NOT_HANDLE;
+ }
}
- if (wheel_event.modifiers & WebInputEvent::ControlKey) {
- // Wheel events involving the control key never trigger scrolling, only
- // event handlers. Forward to the main thread.
+
+ case WebInputEvent::GestureFlingStart:
+ return HandleGestureFlingStart(
+ *static_cast<const WebGestureEvent*>(&event));
+
+ case WebInputEvent::GestureFlingCancel:
+ if (CancelCurrentFling())
+ return DID_HANDLE;
+ else if (!fling_may_be_active_on_main_thread_)
+ return DROP_EVENT;
+ return DID_NOT_HANDLE;
+
+ case WebInputEvent::TouchStart:
+ return HandleTouchStart(static_cast<const WebTouchEvent&>(event));
+
+ case WebInputEvent::MouseMove: {
+ const WebMouseEvent& mouse_event =
+ static_cast<const WebMouseEvent&>(event);
+ // TODO(tony): Ignore when mouse buttons are down?
+ // TODO(davemoore): This should never happen, but bug #326635 showed some
+ // surprising crashes.
+ CHECK(input_handler_);
+ input_handler_->MouseMoveAt(gfx::Point(mouse_event.x, mouse_event.y));
return DID_NOT_HANDLE;
}
- if (smooth_scroll_enabled_) {
- cc::InputHandler::ScrollStatus scroll_status =
- input_handler_->ScrollAnimated(
- gfx::Point(wheel_event.x, wheel_event.y),
- gfx::Vector2dF(-wheel_event.deltaX, -wheel_event.deltaY));
- switch (scroll_status) {
- case cc::InputHandler::ScrollStarted:
- return DID_HANDLE;
- case cc::InputHandler::ScrollIgnored:
- return DROP_EVENT;
- default:
- return DID_NOT_HANDLE;
+
+ default:
+ if (WebInputEvent::isKeyboardEventType(event.type)) {
+ // Only call |CancelCurrentFling()| if a fling was active, as it will
+ // otherwise disrupt an in-progress touch scroll.
+ if (fling_curve_)
+ CancelCurrentFling();
}
+ break;
+ }
+
+ return DID_NOT_HANDLE;
+}
+
+InputHandlerProxy::EventDisposition InputHandlerProxy::HandleMouseWheel(
+ const WebMouseWheelEvent& wheel_event) {
+ InputHandlerProxy::EventDisposition result = DID_NOT_HANDLE;
+ cc::InputHandlerScrollResult scroll_result;
+
+ // TODO(ccameron): The rail information should be pushed down into
+ // InputHandler.
+ gfx::Vector2dF scroll_delta(
+ wheel_event.railsMode != WebInputEvent::RailsModeVertical
+ ? -wheel_event.deltaX
+ : 0,
+ wheel_event.railsMode != WebInputEvent::RailsModeHorizontal
+ ? -wheel_event.deltaY
+ : 0);
+
+ if (wheel_event.scrollByPage) {
+ // TODO(jamesr): We don't properly handle scroll by page in the compositor
+ // thread, so punt it to the main thread. http://crbug.com/236639
+ result = DID_NOT_HANDLE;
+ } else if (!wheel_event.canScroll) {
+ // Wheel events with |canScroll| == false will not trigger scrolling,
+ // only event handlers. Forward to the main thread.
+ result = DID_NOT_HANDLE;
+ } else if (smooth_scroll_enabled_) {
+ cc::InputHandler::ScrollStatus scroll_status =
+ input_handler_->ScrollAnimated(gfx::Point(wheel_event.x, wheel_event.y),
+ scroll_delta);
+ switch (scroll_status) {
+ case cc::InputHandler::SCROLL_STARTED:
+ result = DID_HANDLE;
+ break;
+ case cc::InputHandler::SCROLL_IGNORED:
+ result = DROP_EVENT;
+ default:
+ result = DID_NOT_HANDLE;
+ break;
}
+ } else {
cc::InputHandler::ScrollStatus scroll_status = input_handler_->ScrollBegin(
- gfx::Point(wheel_event.x, wheel_event.y), cc::InputHandler::Wheel);
+ gfx::Point(wheel_event.x, wheel_event.y), cc::InputHandler::WHEEL);
switch (scroll_status) {
- case cc::InputHandler::ScrollStarted: {
- TRACE_EVENT_INSTANT2(
- "input",
- "InputHandlerProxy::handle_input wheel scroll",
- TRACE_EVENT_SCOPE_THREAD,
- "deltaX",
- -wheel_event.deltaX,
- "deltaY",
- -wheel_event.deltaY);
+ case cc::InputHandler::SCROLL_STARTED: {
+ TRACE_EVENT_INSTANT2("input",
+ "InputHandlerProxy::handle_input wheel scroll",
+ TRACE_EVENT_SCOPE_THREAD, "deltaX",
+ scroll_delta.x(), "deltaY", scroll_delta.y());
gfx::Point scroll_point(wheel_event.x, wheel_event.y);
- gfx::Vector2dF scroll_delta(-wheel_event.deltaX, -wheel_event.deltaY);
- cc::InputHandlerScrollResult scroll_result = input_handler_->ScrollBy(
- scroll_point, scroll_delta);
+ scroll_result = input_handler_->ScrollBy(scroll_point, scroll_delta);
HandleOverscroll(scroll_point, scroll_result);
input_handler_->ScrollEnd();
- return scroll_result.did_scroll ? DID_HANDLE : DROP_EVENT;
+ result = scroll_result.did_scroll ? DID_HANDLE : DROP_EVENT;
+ break;
}
- case cc::InputHandler::ScrollIgnored:
+ case cc::InputHandler::SCROLL_IGNORED:
// TODO(jamesr): This should be DROP_EVENT, but in cases where we fail
// to properly sync scrollability it's safer to send the event to the
// main thread. Change back to DROP_EVENT once we have synchronization
// bugs sorted out.
- return DID_NOT_HANDLE;
- case cc::InputHandler::ScrollUnknown:
- case cc::InputHandler::ScrollOnMainThread:
- return DID_NOT_HANDLE;
- case cc::InputHandler::ScrollStatusCount:
- NOTREACHED();
+ result = DID_NOT_HANDLE;
+ break;
+ case cc::InputHandler::SCROLL_UNKNOWN:
+ case cc::InputHandler::SCROLL_ON_MAIN_THREAD:
+ result = DID_NOT_HANDLE;
break;
- }
- } else if (event.type == WebInputEvent::GestureScrollBegin) {
- DCHECK(!gesture_scroll_on_impl_thread_);
-#ifndef NDEBUG
- DCHECK(!expect_scroll_update_end_);
- expect_scroll_update_end_ = true;
-#endif
- const WebGestureEvent& gesture_event =
- *static_cast<const WebGestureEvent*>(&event);
- cc::InputHandler::ScrollStatus scroll_status = input_handler_->ScrollBegin(
- gfx::Point(gesture_event.x, gesture_event.y),
- cc::InputHandler::Gesture);
- UMA_HISTOGRAM_ENUMERATION("Renderer4.CompositorScrollHitTestResult",
- scroll_status,
- cc::InputHandler::ScrollStatusCount);
- switch (scroll_status) {
- case cc::InputHandler::ScrollStarted:
- TRACE_EVENT_INSTANT0("input",
- "InputHandlerProxy::handle_input gesture scroll",
- TRACE_EVENT_SCOPE_THREAD);
- gesture_scroll_on_impl_thread_ = true;
- return DID_HANDLE;
- case cc::InputHandler::ScrollUnknown:
- case cc::InputHandler::ScrollOnMainThread:
- return DID_NOT_HANDLE;
- case cc::InputHandler::ScrollIgnored:
- return DROP_EVENT;
case cc::InputHandler::ScrollStatusCount:
NOTREACHED();
break;
}
- } else if (event.type == WebInputEvent::GestureScrollUpdate) {
-#ifndef NDEBUG
- DCHECK(expect_scroll_update_end_);
-#endif
+ }
- if (!gesture_scroll_on_impl_thread_ && !gesture_pinch_on_impl_thread_)
- return DID_NOT_HANDLE;
+ // Send the event and its disposition to the elasticity controller to update
+ // the over-scroll animation. If the event is to be handled on the main
+ // thread, the event and its disposition will be sent to the elasticity
+ // controller after being handled on the main thread.
+ if (scroll_elasticity_controller_ && result != DID_NOT_HANDLE) {
+ // Note that the call to the elasticity controller is made asynchronously,
+ // to minimize divergence between main thread and impl thread event
+ // handling paths.
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&InputScrollElasticityController::ObserveWheelEventAndResult,
+ scroll_elasticity_controller_->GetWeakPtr(), wheel_event,
+ scroll_result));
+ }
+ return result;
+}
- const WebGestureEvent& gesture_event =
- *static_cast<const WebGestureEvent*>(&event);
- gfx::Point scroll_point(gesture_event.x, gesture_event.y);
- gfx::Vector2dF scroll_delta(-gesture_event.data.scrollUpdate.deltaX,
- -gesture_event.data.scrollUpdate.deltaY);
- cc::InputHandlerScrollResult scroll_result = input_handler_->ScrollBy(
- scroll_point, scroll_delta);
- HandleOverscroll(scroll_point, scroll_result);
- return scroll_result.did_scroll ? DID_HANDLE : DROP_EVENT;
- } else if (event.type == WebInputEvent::GestureScrollEnd) {
+InputHandlerProxy::EventDisposition InputHandlerProxy::HandleGestureScrollBegin(
+ const WebGestureEvent& gesture_event) {
+ DCHECK(!gesture_scroll_on_impl_thread_);
#ifndef NDEBUG
- DCHECK(expect_scroll_update_end_);
- expect_scroll_update_end_ = false;
+ DCHECK(!expect_scroll_update_end_);
+ expect_scroll_update_end_ = true;
#endif
- input_handler_->ScrollEnd();
-
- if (!gesture_scroll_on_impl_thread_)
- return DID_NOT_HANDLE;
-
- gesture_scroll_on_impl_thread_ = false;
- return DID_HANDLE;
- } else if (event.type == WebInputEvent::GesturePinchBegin) {
- input_handler_->PinchGestureBegin();
- DCHECK(!gesture_pinch_on_impl_thread_);
- gesture_pinch_on_impl_thread_ = true;
- return DID_HANDLE;
- } else if (event.type == WebInputEvent::GesturePinchEnd) {
- DCHECK(gesture_pinch_on_impl_thread_);
- gesture_pinch_on_impl_thread_ = false;
- input_handler_->PinchGestureEnd();
- return DID_HANDLE;
- } else if (event.type == WebInputEvent::GesturePinchUpdate) {
- DCHECK(gesture_pinch_on_impl_thread_);
- const WebGestureEvent& gesture_event =
- *static_cast<const WebGestureEvent*>(&event);
- input_handler_->PinchGestureUpdate(
- gesture_event.data.pinchUpdate.scale,
- gfx::Point(gesture_event.x, gesture_event.y));
- return DID_HANDLE;
- } else if (event.type == WebInputEvent::GestureFlingStart) {
- const WebGestureEvent& gesture_event =
- *static_cast<const WebGestureEvent*>(&event);
- return HandleGestureFling(gesture_event);
- } else if (event.type == WebInputEvent::GestureFlingCancel) {
- if (CancelCurrentFling())
+ cc::InputHandler::ScrollStatus scroll_status = input_handler_->ScrollBegin(
+ gfx::Point(gesture_event.x, gesture_event.y), cc::InputHandler::GESTURE);
+ UMA_HISTOGRAM_ENUMERATION("Renderer4.CompositorScrollHitTestResult",
+ scroll_status,
+ cc::InputHandler::ScrollStatusCount);
+ switch (scroll_status) {
+ case cc::InputHandler::SCROLL_STARTED:
+ TRACE_EVENT_INSTANT0("input",
+ "InputHandlerProxy::handle_input gesture scroll",
+ TRACE_EVENT_SCOPE_THREAD);
+ gesture_scroll_on_impl_thread_ = true;
return DID_HANDLE;
- else if (!fling_may_be_active_on_main_thread_)
+ case cc::InputHandler::SCROLL_UNKNOWN:
+ case cc::InputHandler::SCROLL_ON_MAIN_THREAD:
+ return DID_NOT_HANDLE;
+ case cc::InputHandler::SCROLL_IGNORED:
return DROP_EVENT;
- } else if (event.type == WebInputEvent::TouchStart) {
- const WebTouchEvent& touch_event =
- *static_cast<const WebTouchEvent*>(&event);
- for (size_t i = 0; i < touch_event.touchesLength; ++i) {
- if (touch_event.touches[i].state != WebTouchPoint::StatePressed)
- continue;
- if (input_handler_->HaveTouchEventHandlersAt(
- gfx::Point(touch_event.touches[i].position.x,
- touch_event.touches[i].position.y))) {
- return DID_NOT_HANDLE;
- }
- }
- return DROP_EVENT;
- } else if (WebInputEvent::isKeyboardEventType(event.type)) {
- // Only call |CancelCurrentFling()| if a fling was active, as it will
- // otherwise disrupt an in-progress touch scroll.
- if (fling_curve_)
- CancelCurrentFling();
- } else if (event.type == WebInputEvent::MouseMove) {
- const WebMouseEvent& mouse_event =
- *static_cast<const WebMouseEvent*>(&event);
- // TODO(tony): Ignore when mouse buttons are down?
- // TODO(davemoore): This should never happen, but bug #326635 showed some
- // surprising crashes.
- CHECK(input_handler_);
- input_handler_->MouseMoveAt(gfx::Point(mouse_event.x, mouse_event.y));
+ case cc::InputHandler::ScrollStatusCount:
+ NOTREACHED();
+ break;
}
-
return DID_NOT_HANDLE;
}
InputHandlerProxy::EventDisposition
-InputHandlerProxy::HandleGestureFling(
+InputHandlerProxy::HandleGestureScrollUpdate(
+ const WebGestureEvent& gesture_event) {
+#ifndef NDEBUG
+ DCHECK(expect_scroll_update_end_);
+#endif
+
+ if (!gesture_scroll_on_impl_thread_ && !gesture_pinch_on_impl_thread_)
+ return DID_NOT_HANDLE;
+
+ gfx::Point scroll_point(gesture_event.x, gesture_event.y);
+ gfx::Vector2dF scroll_delta(-gesture_event.data.scrollUpdate.deltaX,
+ -gesture_event.data.scrollUpdate.deltaY);
+ cc::InputHandlerScrollResult scroll_result = input_handler_->ScrollBy(
+ scroll_point, scroll_delta);
+ HandleOverscroll(scroll_point, scroll_result);
+ return scroll_result.did_scroll ? DID_HANDLE : DROP_EVENT;
+}
+
+InputHandlerProxy::EventDisposition InputHandlerProxy::HandleGestureScrollEnd(
+ const WebGestureEvent& gesture_event) {
+#ifndef NDEBUG
+ DCHECK(expect_scroll_update_end_);
+ expect_scroll_update_end_ = false;
+#endif
+ input_handler_->ScrollEnd();
+ if (!gesture_scroll_on_impl_thread_)
+ return DID_NOT_HANDLE;
+ gesture_scroll_on_impl_thread_ = false;
+ return DID_HANDLE;
+}
+
+InputHandlerProxy::EventDisposition InputHandlerProxy::HandleGestureFlingStart(
const WebGestureEvent& gesture_event) {
cc::InputHandler::ScrollStatus scroll_status;
if (gesture_event.sourceDevice == blink::WebGestureDeviceTouchpad) {
scroll_status = input_handler_->ScrollBegin(
gfx::Point(gesture_event.x, gesture_event.y),
- cc::InputHandler::NonBubblingGesture);
+ cc::InputHandler::NON_BUBBLING_GESTURE);
} else {
if (!gesture_scroll_on_impl_thread_)
- scroll_status = cc::InputHandler::ScrollOnMainThread;
+ scroll_status = cc::InputHandler::SCROLL_ON_MAIN_THREAD;
else
scroll_status = input_handler_->FlingScrollBegin();
}
@@ -397,13 +498,14 @@ InputHandlerProxy::HandleGestureFling(
#endif
switch (scroll_status) {
- case cc::InputHandler::ScrollStarted: {
+ case cc::InputHandler::SCROLL_STARTED: {
if (gesture_event.sourceDevice == blink::WebGestureDeviceTouchpad)
input_handler_->ScrollEnd();
const float vx = gesture_event.data.flingStart.velocityX;
const float vy = gesture_event.data.flingStart.velocityY;
current_fling_velocity_ = gfx::Vector2dF(vx, vy);
+ DCHECK(!current_fling_velocity_.IsZero());
fling_curve_.reset(client_->CreateFlingAnimationCurve(
gesture_event.sourceDevice,
WebFloatPoint(vx, vy),
@@ -430,20 +532,22 @@ InputHandlerProxy::HandleGestureFling(
input_handler_->SetNeedsAnimate();
return DID_HANDLE;
}
- case cc::InputHandler::ScrollUnknown:
- case cc::InputHandler::ScrollOnMainThread: {
+ case cc::InputHandler::SCROLL_UNKNOWN:
+ case cc::InputHandler::SCROLL_ON_MAIN_THREAD: {
TRACE_EVENT_INSTANT0("input",
"InputHandlerProxy::HandleGestureFling::"
"scroll_on_main_thread",
TRACE_EVENT_SCOPE_THREAD);
+ gesture_scroll_on_impl_thread_ = false;
fling_may_be_active_on_main_thread_ = true;
return DID_NOT_HANDLE;
}
- case cc::InputHandler::ScrollIgnored: {
+ case cc::InputHandler::SCROLL_IGNORED: {
TRACE_EVENT_INSTANT0(
"input",
"InputHandlerProxy::HandleGestureFling::ignored",
TRACE_EVENT_SCOPE_THREAD);
+ gesture_scroll_on_impl_thread_ = false;
if (gesture_event.sourceDevice == blink::WebGestureDeviceTouchpad) {
// We still pass the curve to the main thread if there's nothing
// scrollable, in case something
@@ -459,6 +563,22 @@ InputHandlerProxy::HandleGestureFling(
return DID_NOT_HANDLE;
}
+InputHandlerProxy::EventDisposition InputHandlerProxy::HandleTouchStart(
+ const blink::WebTouchEvent& touch_event) {
+ for (size_t i = 0; i < touch_event.touchesLength; ++i) {
+ if (touch_event.touches[i].state != WebTouchPoint::StatePressed)
+ continue;
+ if (input_handler_->DoTouchEventsBlockScrollAt(
+ gfx::Point(touch_event.touches[i].position.x,
+ touch_event.touches[i].position.y))) {
+ // TODO(rbyers): We should consider still sending the touch events to
+ // main asynchronously (crbug.com/455539).
+ return DID_NOT_HANDLE;
+ }
+ }
+ return DROP_EVENT;
+}
+
bool InputHandlerProxy::FilterInputEventForFlingBoosting(
const WebInputEvent& event) {
if (!WebInputEvent::isGestureEventType(event.type))
@@ -472,6 +592,9 @@ bool InputHandlerProxy::FilterInputEventForFlingBoosting(
const WebGestureEvent& gesture_event =
static_cast<const WebGestureEvent&>(event);
if (gesture_event.type == WebInputEvent::GestureFlingCancel) {
+ if (gesture_event.data.flingCancel.preventBoosting)
+ return false;
+
if (current_fling_velocity_.LengthSquared() < kMinBoostFlingSpeedSquare)
return false;
@@ -503,8 +626,8 @@ bool InputHandlerProxy::FilterInputEventForFlingBoosting(
if (!input_handler_->IsCurrentlyScrollingLayerAt(
gfx::Point(gesture_event.x, gesture_event.y),
fling_parameters_.sourceDevice == blink::WebGestureDeviceTouchpad
- ? cc::InputHandler::NonBubblingGesture
- : cc::InputHandler::Gesture)) {
+ ? cc::InputHandler::NON_BUBBLING_GESTURE
+ : cc::InputHandler::GESTURE)) {
CancelCurrentFling();
return false;
}
@@ -545,6 +668,7 @@ bool InputHandlerProxy::FilterInputEventForFlingBoosting(
gfx::Vector2dF new_fling_velocity(
gesture_event.data.flingStart.velocityX,
gesture_event.data.flingStart.velocityY);
+ DCHECK(!new_fling_velocity.IsZero());
if (fling_boosted)
current_fling_velocity_ += new_fling_velocity;
@@ -602,6 +726,9 @@ void InputHandlerProxy::ExtendBoostedFlingTimeout(
}
void InputHandlerProxy::Animate(base::TimeTicks time) {
+ if (scroll_elasticity_controller_)
+ scroll_elasticity_controller_->Animate(time);
+
if (!fling_curve_)
return;
@@ -613,6 +740,8 @@ void InputHandlerProxy::Animate(base::TimeTicks time) {
return;
}
+ client_->DidAnimateForInput();
+
if (!has_fling_animation_started_) {
has_fling_animation_started_ = true;
// Guard against invalid, future or sufficiently stale start times, as there
@@ -649,6 +778,11 @@ void InputHandlerProxy::MainThreadHasStoppedFlinging() {
client_->DidStopFlinging();
}
+void InputHandlerProxy::ReconcileElasticOverscrollAndRootScroll() {
+ if (scroll_elasticity_controller_)
+ scroll_elasticity_controller_->ReconcileStretchAndScroll();
+}
+
void InputHandlerProxy::HandleOverscroll(
const gfx::Point& causal_event_viewport_point,
const cc::InputHandlerScrollResult& scroll_result) {
diff --git a/chromium/content/renderer/input/input_handler_proxy.h b/chromium/content/renderer/input/input_handler_proxy.h
index 39f4346b252..fd99af6f025 100644
--- a/chromium/content/renderer/input/input_handler_proxy.h
+++ b/chromium/content/renderer/input/input_handler_proxy.h
@@ -19,6 +19,7 @@
namespace content {
class InputHandlerProxyClient;
+class InputScrollElasticityController;
// This class is a proxy between the content input event filtering and the
// compositor's input handling logic. InputHandlerProxy instances live entirely
@@ -32,6 +33,10 @@ class CONTENT_EXPORT InputHandlerProxy
InputHandlerProxyClient* client);
virtual ~InputHandlerProxy();
+ InputScrollElasticityController* scroll_elasticity_controller() {
+ return scroll_elasticity_controller_.get();
+ }
+
enum EventDisposition {
DID_HANDLE,
DID_NOT_HANDLE,
@@ -46,6 +51,7 @@ class CONTENT_EXPORT InputHandlerProxy
void WillShutdown() override;
void Animate(base::TimeTicks time) override;
void MainThreadHasStoppedFlinging() override;
+ void ReconcileElasticOverscrollAndRootScroll() override;
// blink::WebGestureCurveTarget implementation.
virtual bool scrollBy(const blink::WebFloatSize& offset,
@@ -56,7 +62,19 @@ class CONTENT_EXPORT InputHandlerProxy
}
private:
- EventDisposition HandleGestureFling(const blink::WebGestureEvent& event);
+ // Helper functions for handling more complicated input events.
+ EventDisposition HandleMouseWheel(
+ const blink::WebMouseWheelEvent& event);
+ EventDisposition HandleGestureScrollBegin(
+ const blink::WebGestureEvent& event);
+ EventDisposition HandleGestureScrollUpdate(
+ const blink::WebGestureEvent& event);
+ EventDisposition HandleGestureScrollEnd(
+ const blink::WebGestureEvent& event);
+ EventDisposition HandleGestureFlingStart(
+ const blink::WebGestureEvent& event);
+ EventDisposition HandleTouchStart(
+ const blink::WebTouchEvent& event);
// Returns true if the event should be suppressed due to to an active,
// boost-enabled fling, in which case further processing should cease.
@@ -122,8 +140,13 @@ class CONTENT_EXPORT InputHandlerProxy
// Non-zero only within the scope of |scrollBy|.
gfx::Vector2dF current_fling_velocity_;
+ // Used to animate rubber-band over-scroll effect on Mac.
+ scoped_ptr<InputScrollElasticityController> scroll_elasticity_controller_;
+
bool smooth_scroll_enabled_;
+ bool uma_latency_reporting_enabled_;
+
DISALLOW_COPY_AND_ASSIGN(InputHandlerProxy);
};
diff --git a/chromium/content/renderer/input/input_handler_proxy_client.h b/chromium/content/renderer/input/input_handler_proxy_client.h
index bbb91e842c5..53b4bc94846 100644
--- a/chromium/content/renderer/input/input_handler_proxy_client.h
+++ b/chromium/content/renderer/input/input_handler_proxy_client.h
@@ -38,7 +38,7 @@ class InputHandlerProxyClient {
virtual void DidStopFlinging() = 0;
- virtual void DidReceiveInputEvent() = 0;
+ virtual void DidAnimateForInput() = 0;
protected:
virtual ~InputHandlerProxyClient() {}
diff --git a/chromium/content/renderer/input/input_handler_proxy_unittest.cc b/chromium/content/renderer/input/input_handler_proxy_unittest.cc
index 49fa56a72f3..cfa8631f2bd 100644
--- a/chromium/content/renderer/input/input_handler_proxy_unittest.cc
+++ b/chromium/content/renderer/input/input_handler_proxy_unittest.cc
@@ -6,7 +6,7 @@
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
-#include "cc/base/swap_promise_monitor.h"
+#include "cc/trees/swap_promise_monitor.h"
#include "content/common/input/did_overscroll_params.h"
#include "content/renderer/input/input_handler_proxy_client.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -30,6 +30,7 @@ using blink::WebPoint;
using blink::WebSize;
using blink::WebTouchEvent;
using blink::WebTouchPoint;
+using testing::Field;
namespace content {
namespace {
@@ -74,7 +75,7 @@ WebGestureEvent CreateFling(WebGestureDevice source_device,
class MockInputHandler : public cc::InputHandler {
public:
MockInputHandler() {}
- virtual ~MockInputHandler() {}
+ ~MockInputHandler() override {}
MOCK_METHOD0(PinchGestureBegin, void());
MOCK_METHOD2(PinchGestureUpdate,
@@ -99,26 +100,31 @@ class MockInputHandler : public cc::InputHandler {
MOCK_METHOD0(ScrollEnd, void());
MOCK_METHOD0(FlingScrollBegin, cc::InputHandler::ScrollStatus());
- virtual scoped_ptr<cc::SwapPromiseMonitor>
- CreateLatencyInfoSwapPromiseMonitor(ui::LatencyInfo* latency) override {
- return scoped_ptr<cc::SwapPromiseMonitor>();
+ scoped_ptr<cc::SwapPromiseMonitor> CreateLatencyInfoSwapPromiseMonitor(
+ ui::LatencyInfo* latency) override {
+ return scoped_ptr<cc::SwapPromiseMonitor>();
}
- virtual void BindToClient(cc::InputHandlerClient* client) override {}
+ cc::ScrollElasticityHelper* CreateScrollElasticityHelper() override {
+ return NULL;
+ }
+
+ void BindToClient(cc::InputHandlerClient* client) override {}
- virtual void MouseMoveAt(const gfx::Point& mouse_position) override {}
+ void MouseMoveAt(const gfx::Point& mouse_position) override {}
MOCK_METHOD2(IsCurrentlyScrollingLayerAt,
bool(const gfx::Point& point,
cc::InputHandler::ScrollInputType type));
- MOCK_METHOD1(HaveTouchEventHandlersAt, bool(const gfx::Point& point));
+ MOCK_METHOD1(HaveWheelEventHandlersAt, bool(const gfx::Point& point));
+ MOCK_METHOD1(DoTouchEventsBlockScrollAt, bool(const gfx::Point& point));
- virtual void SetRootLayerScrollOffsetDelegate(
+ void SetRootLayerScrollOffsetDelegate(
cc::LayerScrollOffsetDelegate* root_layer_scroll_offset_delegate)
override {}
- virtual void OnRootLayerDelegatedScrollOffsetChanged() override {}
+ void OnRootLayerDelegatedScrollOffsetChanged() override {}
DISALLOW_COPY_AND_ASSIGN(MockInputHandler);
};
@@ -157,14 +163,14 @@ class MockInputHandlerProxyClient
: public content::InputHandlerProxyClient {
public:
MockInputHandlerProxyClient() {}
- virtual ~MockInputHandlerProxyClient() {}
+ ~MockInputHandlerProxyClient() override {}
- virtual void WillShutdown() override {}
+ void WillShutdown() override {}
MOCK_METHOD1(TransferActiveWheelFlingAnimation,
void(const WebActiveWheelFlingParameters&));
- virtual blink::WebGestureCurve* CreateFlingAnimationCurve(
+ blink::WebGestureCurve* CreateFlingAnimationCurve(
WebGestureDevice deviceSource,
const WebFloatPoint& velocity,
const WebSize& cumulative_scroll) override {
@@ -174,23 +180,23 @@ class MockInputHandlerProxyClient
}
MOCK_METHOD1(DidOverscroll, void(const DidOverscrollParams&));
- virtual void DidStopFlinging() override {}
- virtual void DidReceiveInputEvent() override {}
+ void DidStopFlinging() override {}
+ void DidAnimateForInput() override {}
private:
DISALLOW_COPY_AND_ASSIGN(MockInputHandlerProxyClient);
};
-class MockInputHandlerProxyClientWithDidReceiveInputEvent
+class MockInputHandlerProxyClientWithDidAnimateForInput
: public MockInputHandlerProxyClient {
public:
- MockInputHandlerProxyClientWithDidReceiveInputEvent() {}
- virtual ~MockInputHandlerProxyClientWithDidReceiveInputEvent() {}
+ MockInputHandlerProxyClientWithDidAnimateForInput() {}
+ ~MockInputHandlerProxyClientWithDidAnimateForInput() override {}
- MOCK_METHOD0(DidReceiveInputEvent, void());
+ MOCK_METHOD0(DidAnimateForInput, void());
private:
- DISALLOW_COPY_AND_ASSIGN(MockInputHandlerProxyClientWithDidReceiveInputEvent);
+ DISALLOW_COPY_AND_ASSIGN(MockInputHandlerProxyClientWithDidAnimateForInput);
};
WebTouchPoint CreateWebTouchPoint(WebTouchPoint::State state, float x,
@@ -233,7 +239,7 @@ class InputHandlerProxyTest : public testing::Test {
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(cc::InputHandler::ScrollStarted));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
gesture_.type = WebInputEvent::GestureScrollBegin;
gesture_.sourceDevice = source_device;
EXPECT_EQ(expected_disposition_,
@@ -242,7 +248,7 @@ class InputHandlerProxyTest : public testing::Test {
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
- .WillOnce(testing::Return(cc::InputHandler::ScrollStarted));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
gesture_ =
@@ -282,12 +288,12 @@ TEST_F(InputHandlerProxyTest, MouseWheelByPageMainThread) {
testing::Mock::VerifyAndClearExpectations(&mock_client_);
}
-TEST_F(InputHandlerProxyTest, MouseWheelWithCtrl) {
+TEST_F(InputHandlerProxyTest, MouseWheelWithCtrlNotScroll) {
expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
WebMouseWheelEvent wheel;
wheel.type = WebInputEvent::MouseWheel;
wheel.modifiers = WebInputEvent::ControlKey;
-
+ wheel.canScroll = false;
EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(wheel));
testing::Mock::VerifyAndClearExpectations(&mock_client_);
}
@@ -298,7 +304,7 @@ TEST_F(InputHandlerProxyTest, GestureScrollStarted) {
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(cc::InputHandler::ScrollStarted));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
gesture_.type = WebInputEvent::GestureScrollBegin;
EXPECT_EQ(expected_disposition_,input_handler_->HandleInputEvent(gesture_));
@@ -343,7 +349,7 @@ TEST_F(InputHandlerProxyTest, GestureScrollOnMainThread) {
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(mock_input_handler_, ScrollBegin(::testing::_, ::testing::_))
- .WillOnce(testing::Return(cc::InputHandler::ScrollOnMainThread));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_ON_MAIN_THREAD));
gesture_.type = WebInputEvent::GestureScrollBegin;
EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -372,7 +378,7 @@ TEST_F(InputHandlerProxyTest, GestureScrollIgnored) {
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(cc::InputHandler::ScrollIgnored));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_IGNORED));
gesture_.type = WebInputEvent::GestureScrollBegin;
EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -389,6 +395,8 @@ TEST_F(InputHandlerProxyTest, GesturePinch) {
VERIFY_AND_RESET_MOCKS();
gesture_.type = WebInputEvent::GesturePinchBegin;
+ EXPECT_CALL(mock_input_handler_, HaveWheelEventHandlersAt(testing::_))
+ .WillOnce(testing::Return(false));
EXPECT_CALL(mock_input_handler_, PinchGestureBegin());
EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -405,6 +413,17 @@ TEST_F(InputHandlerProxyTest, GesturePinch) {
gesture_.type = WebInputEvent::GesturePinchUpdate;
gesture_.data.pinchUpdate.scale = 0.5;
+ gesture_.data.pinchUpdate.zoomDisabled = true;
+ gesture_.x = 9;
+ gesture_.y = 6;
+ EXPECT_EQ(InputHandlerProxy::DROP_EVENT,
+ input_handler_->HandleInputEvent(gesture_));
+ gesture_.data.pinchUpdate.zoomDisabled = false;
+
+ VERIFY_AND_RESET_MOCKS();
+
+ gesture_.type = WebInputEvent::GesturePinchUpdate;
+ gesture_.data.pinchUpdate.scale = 0.5;
gesture_.x = 9;
gesture_.y = 6;
EXPECT_CALL(mock_input_handler_, PinchGestureUpdate(.5, gfx::Point(9, 6)));
@@ -417,13 +436,45 @@ TEST_F(InputHandlerProxyTest, GesturePinch) {
EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
}
+TEST_F(InputHandlerProxyTest, GesturePinchWithWheelHandler) {
+ // We will send the synthetic wheel event to the widget.
+ expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
+ VERIFY_AND_RESET_MOCKS();
+
+ gesture_.type = WebInputEvent::GesturePinchBegin;
+ EXPECT_CALL(mock_input_handler_, HaveWheelEventHandlersAt(testing::_))
+ .WillOnce(testing::Return(true));
+ EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
+
+ VERIFY_AND_RESET_MOCKS();
+
+ gesture_.type = WebInputEvent::GesturePinchUpdate;
+ gesture_.data.pinchUpdate.scale = 1.5;
+ gesture_.x = 7;
+ gesture_.y = 13;
+ EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
+
+ VERIFY_AND_RESET_MOCKS();
+
+ gesture_.type = WebInputEvent::GesturePinchUpdate;
+ gesture_.data.pinchUpdate.scale = 0.5;
+ gesture_.x = 9;
+ gesture_.y = 6;
+ EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
+
+ VERIFY_AND_RESET_MOCKS();
+
+ gesture_.type = WebInputEvent::GesturePinchEnd;
+ EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
+}
+
TEST_F(InputHandlerProxyTest, GesturePinchAfterScrollOnMainThread) {
// Scrolls will start by being sent to the main thread.
expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(mock_input_handler_, ScrollBegin(::testing::_, ::testing::_))
- .WillOnce(testing::Return(cc::InputHandler::ScrollOnMainThread));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_ON_MAIN_THREAD));
gesture_.type = WebInputEvent::GestureScrollBegin;
EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -440,6 +491,8 @@ TEST_F(InputHandlerProxyTest, GesturePinchAfterScrollOnMainThread) {
VERIFY_AND_RESET_MOCKS();
gesture_.type = WebInputEvent::GesturePinchBegin;
+ EXPECT_CALL(mock_input_handler_, HaveWheelEventHandlersAt(testing::_))
+ .WillOnce(testing::Return(false));
EXPECT_CALL(mock_input_handler_, PinchGestureBegin());
EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -496,7 +549,7 @@ TEST_F(InputHandlerProxyTest, GestureFlingStartedTouchpad) {
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(cc::InputHandler::ScrollStarted));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
EXPECT_CALL(mock_input_handler_, ScrollEnd());
EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
@@ -519,7 +572,7 @@ TEST_F(InputHandlerProxyTest, GestureFlingOnMainThreadTouchpad) {
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(cc::InputHandler::ScrollOnMainThread));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_ON_MAIN_THREAD));
gesture_.type = WebInputEvent::GestureFlingStart;
gesture_.sourceDevice = blink::WebGestureDeviceTouchpad;
@@ -543,7 +596,7 @@ TEST_F(InputHandlerProxyTest, GestureFlingIgnoredTouchpad) {
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(cc::InputHandler::ScrollIgnored));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_IGNORED));
gesture_.type = WebInputEvent::GestureFlingStart;
gesture_.sourceDevice = blink::WebGestureDeviceTouchpad;
@@ -580,7 +633,7 @@ TEST_F(InputHandlerProxyTest, GestureFlingAnimatesTouchpad) {
modifiers);
EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(cc::InputHandler::ScrollStarted));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
EXPECT_CALL(mock_input_handler_, ScrollEnd());
EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -601,7 +654,7 @@ TEST_F(InputHandlerProxyTest, GestureFlingAnimatesTouchpad) {
// The second call should start scrolling in the -X direction.
EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(cc::InputHandler::ScrollStarted));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
EXPECT_CALL(mock_input_handler_,
ScrollBy(testing::_,
testing::Property(&gfx::Vector2dF::x, testing::Lt(0))))
@@ -618,7 +671,7 @@ TEST_F(InputHandlerProxyTest, GestureFlingAnimatesTouchpad) {
// rest of the fling can be
// transferred to the main thread.
EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(cc::InputHandler::ScrollOnMainThread));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_ON_MAIN_THREAD));
EXPECT_CALL(mock_input_handler_, ScrollBy(testing::_, testing::_)).Times(0);
EXPECT_CALL(mock_input_handler_, ScrollEnd()).Times(0);
// Expected wheel fling animation parameters:
@@ -685,7 +738,7 @@ TEST_F(InputHandlerProxyTest, GestureFlingTransferResetsTouchpad) {
modifiers);
EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(cc::InputHandler::ScrollStarted));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
EXPECT_CALL(mock_input_handler_, ScrollEnd());
EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -704,7 +757,7 @@ TEST_F(InputHandlerProxyTest, GestureFlingTransferResetsTouchpad) {
// The second call should start scrolling in the -X direction.
EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(cc::InputHandler::ScrollStarted));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
EXPECT_CALL(mock_input_handler_,
ScrollBy(testing::_,
testing::Property(&gfx::Vector2dF::x, testing::Lt(0))))
@@ -721,7 +774,7 @@ TEST_F(InputHandlerProxyTest, GestureFlingTransferResetsTouchpad) {
// rest of the fling can be
// transferred to the main thread.
EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(cc::InputHandler::ScrollOnMainThread));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_ON_MAIN_THREAD));
EXPECT_CALL(mock_input_handler_, ScrollBy(testing::_, testing::_)).Times(0);
EXPECT_CALL(mock_input_handler_, ScrollEnd()).Times(0);
@@ -786,7 +839,7 @@ TEST_F(InputHandlerProxyTest, GestureFlingTransferResetsTouchpad) {
modifiers);
EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(cc::InputHandler::ScrollStarted));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
EXPECT_CALL(mock_input_handler_, ScrollEnd());
expected_disposition_ = InputHandlerProxy::DID_HANDLE;
EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -805,7 +858,7 @@ TEST_F(InputHandlerProxyTest, GestureFlingTransferResetsTouchpad) {
// Tick the second fling once normally.
EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(cc::InputHandler::ScrollStarted));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
EXPECT_CALL(mock_input_handler_,
ScrollBy(testing::_,
testing::Property(&gfx::Vector2dF::y, testing::Gt(0))))
@@ -818,7 +871,7 @@ TEST_F(InputHandlerProxyTest, GestureFlingTransferResetsTouchpad) {
// Then abort the second fling.
EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(cc::InputHandler::ScrollOnMainThread));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_ON_MAIN_THREAD));
EXPECT_CALL(mock_input_handler_, ScrollBy(testing::_, testing::_)).Times(0);
EXPECT_CALL(mock_input_handler_, ScrollEnd()).Times(0);
@@ -849,7 +902,7 @@ TEST_F(InputHandlerProxyTest, GestureFlingStartedTouchscreen) {
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(cc::InputHandler::ScrollStarted));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
gesture_.type = WebInputEvent::GestureScrollBegin;
gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen;
EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -857,7 +910,7 @@ TEST_F(InputHandlerProxyTest, GestureFlingStartedTouchscreen) {
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
- .WillOnce(testing::Return(cc::InputHandler::ScrollStarted));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
gesture_.type = WebInputEvent::GestureFlingStart;
@@ -881,7 +934,7 @@ TEST_F(InputHandlerProxyTest, GestureFlingOnMainThreadTouchscreen) {
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(cc::InputHandler::ScrollOnMainThread));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_ON_MAIN_THREAD));
gesture_.type = WebInputEvent::GestureScrollBegin;
EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -908,7 +961,7 @@ TEST_F(InputHandlerProxyTest, GestureFlingIgnoredTouchscreen) {
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(cc::InputHandler::ScrollStarted));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
gesture_.type = WebInputEvent::GestureScrollBegin;
gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen;
@@ -917,8 +970,10 @@ TEST_F(InputHandlerProxyTest, GestureFlingIgnoredTouchscreen) {
expected_disposition_ = InputHandlerProxy::DROP_EVENT;
VERIFY_AND_RESET_MOCKS();
+ // Flings ignored by the InputHandler should be dropped, signalling the end
+ // of the touch scroll sequence.
EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
- .WillOnce(testing::Return(cc::InputHandler::ScrollIgnored));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_IGNORED));
gesture_.type = WebInputEvent::GestureFlingStart;
gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen;
@@ -926,9 +981,12 @@ TEST_F(InputHandlerProxyTest, GestureFlingIgnoredTouchscreen) {
VERIFY_AND_RESET_MOCKS();
- // Even if we didn't start a fling ourselves, we still need to send the cancel
- // event to the widget.
- gesture_.type = WebInputEvent::GestureFlingCancel;
+ // Subsequent scrolls should behave normally, even without an intervening
+ // GestureFlingCancel, as the original GestureFlingStart was dropped.
+ expected_disposition_ = InputHandlerProxy::DID_HANDLE;
+ EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+ gesture_.type = WebInputEvent::GestureScrollBegin;
gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen;
EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
}
@@ -939,7 +997,7 @@ TEST_F(InputHandlerProxyTest, GestureFlingAnimatesTouchscreen) {
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(cc::InputHandler::ScrollStarted));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
gesture_.type = WebInputEvent::GestureScrollBegin;
gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen;
@@ -961,7 +1019,7 @@ TEST_F(InputHandlerProxyTest, GestureFlingAnimatesTouchscreen) {
modifiers);
EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
- .WillOnce(testing::Return(cc::InputHandler::ScrollStarted));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
@@ -998,7 +1056,7 @@ TEST_F(InputHandlerProxyTest, GestureFlingWithValidTimestamp) {
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(cc::InputHandler::ScrollStarted));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
gesture_.type = WebInputEvent::GestureScrollBegin;
gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen;
@@ -1022,7 +1080,7 @@ TEST_F(InputHandlerProxyTest, GestureFlingWithValidTimestamp) {
modifiers);
EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
- .WillOnce(testing::Return(cc::InputHandler::ScrollStarted));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
@@ -1052,7 +1110,7 @@ TEST_F(InputHandlerProxyTest, GestureFlingWithInvalidTimestamp) {
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(cc::InputHandler::ScrollStarted));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
gesture_.type = WebInputEvent::GestureScrollBegin;
gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen;
@@ -1079,7 +1137,7 @@ TEST_F(InputHandlerProxyTest, GestureFlingWithInvalidTimestamp) {
gesture_.modifiers = modifiers;
EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
- .WillOnce(testing::Return(cc::InputHandler::ScrollStarted));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
@@ -1116,7 +1174,7 @@ TEST_F(InputHandlerProxyTest,
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(cc::InputHandler::ScrollStarted));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
gesture_.type = WebInputEvent::GestureScrollBegin;
EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -1141,7 +1199,7 @@ TEST_F(InputHandlerProxyTest,
modifiers);
EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
- .WillOnce(testing::Return(cc::InputHandler::ScrollStarted));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
// |gesture_scroll_on_impl_thread_| should still be true after
@@ -1192,7 +1250,7 @@ TEST_F(InputHandlerProxyTest, GestureFlingStopsAtContentEdge) {
gesture_.data.flingStart.velocityX = fling_delta.x;
gesture_.data.flingStart.velocityY = fling_delta.y;
EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(cc::InputHandler::ScrollStarted));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
EXPECT_CALL(mock_input_handler_, ScrollEnd());
EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -1206,7 +1264,7 @@ TEST_F(InputHandlerProxyTest, GestureFlingStopsAtContentEdge) {
// The second animate starts scrolling in the positive X and Y directions.
EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(cc::InputHandler::ScrollStarted));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
EXPECT_CALL(mock_input_handler_,
ScrollBy(testing::_,
testing::Property(&gfx::Vector2dF::y, testing::Lt(0))))
@@ -1225,7 +1283,7 @@ TEST_F(InputHandlerProxyTest, GestureFlingStopsAtContentEdge) {
overscroll.accumulated_root_overscroll = gfx::Vector2dF(0, 100);
overscroll.unused_scroll_delta = gfx::Vector2dF(0, 10);
EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(cc::InputHandler::ScrollStarted));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
EXPECT_CALL(mock_input_handler_,
ScrollBy(testing::_,
testing::Property(&gfx::Vector2dF::y, testing::Lt(0))))
@@ -1251,7 +1309,7 @@ TEST_F(InputHandlerProxyTest, GestureFlingStopsAtContentEdge) {
// The next call to animate will no longer scroll vertically.
EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(cc::InputHandler::ScrollStarted));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
EXPECT_CALL(mock_input_handler_,
ScrollBy(testing::_,
testing::Property(&gfx::Vector2dF::y, testing::Eq(0))))
@@ -1268,7 +1326,7 @@ TEST_F(InputHandlerProxyTest, GestureFlingNotCancelledBySmallTimeDelta) {
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(cc::InputHandler::ScrollStarted));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
gesture_.type = WebInputEvent::GestureScrollBegin;
gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen;
@@ -1292,7 +1350,7 @@ TEST_F(InputHandlerProxyTest, GestureFlingNotCancelledBySmallTimeDelta) {
modifiers);
EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
- .WillOnce(testing::Return(cc::InputHandler::ScrollStarted));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
@@ -1349,7 +1407,7 @@ TEST_F(InputHandlerProxyTest, GestureFlingCancelledAfterBothAxesStopScrolling) {
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(cc::InputHandler::ScrollStarted));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
gesture_.type = WebInputEvent::GestureScrollBegin;
gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen;
EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -1362,7 +1420,7 @@ TEST_F(InputHandlerProxyTest, GestureFlingCancelledAfterBothAxesStopScrolling) {
gesture_.data.flingStart.velocityX = fling_delta.x;
gesture_.data.flingStart.velocityY = fling_delta.y;
EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
- .WillOnce(testing::Return(cc::InputHandler::ScrollStarted));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
@@ -1458,11 +1516,11 @@ TEST_F(InputHandlerProxyTest, MultiTouchPointHitTestNegative) {
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(mock_input_handler_,
- HaveTouchEventHandlersAt(
+ DoTouchEventsBlockScrollAt(
testing::Property(&gfx::Point::x, testing::Gt(0))))
.WillOnce(testing::Return(false));
EXPECT_CALL(mock_input_handler_,
- HaveTouchEventHandlersAt(
+ DoTouchEventsBlockScrollAt(
testing::Property(&gfx::Point::x, testing::Lt(0))))
.WillOnce(testing::Return(false));
@@ -1483,11 +1541,11 @@ TEST_F(InputHandlerProxyTest, MultiTouchPointHitTestPositive) {
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(mock_input_handler_,
- HaveTouchEventHandlersAt(
+ DoTouchEventsBlockScrollAt(
testing::Property(&gfx::Point::x, testing::Eq(0))))
.WillOnce(testing::Return(false));
EXPECT_CALL(mock_input_handler_,
- HaveTouchEventHandlersAt(
+ DoTouchEventsBlockScrollAt(
testing::Property(&gfx::Point::x, testing::Gt(0))))
.WillOnce(testing::Return(true));
// Since the second touch point hits a touch-region, there should be no
@@ -1509,7 +1567,7 @@ TEST_F(InputHandlerProxyTest, GestureFlingCancelledByKeyboardEvent) {
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(cc::InputHandler::ScrollStarted));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
gesture_.type = WebInputEvent::GestureScrollBegin;
gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen;
EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -1530,7 +1588,7 @@ TEST_F(InputHandlerProxyTest, GestureFlingCancelledByKeyboardEvent) {
gesture_.data.flingStart.velocityX = fling_delta.x;
gesture_.data.flingStart.velocityY = fling_delta.y;
EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
- .WillOnce(testing::Return(cc::InputHandler::ScrollStarted));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
@@ -1561,7 +1619,7 @@ TEST_F(InputHandlerProxyTest, GestureFlingWithNegativeTimeDelta) {
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(cc::InputHandler::ScrollStarted));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
gesture_.type = WebInputEvent::GestureScrollBegin;
gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen;
@@ -1585,7 +1643,7 @@ TEST_F(InputHandlerProxyTest, GestureFlingWithNegativeTimeDelta) {
modifiers);
EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
- .WillOnce(testing::Return(cc::InputHandler::ScrollStarted));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
@@ -1774,7 +1832,7 @@ TEST_F(InputHandlerProxyTest, NoFlingBoostIfScrollTargetsDifferentLayer) {
.WillOnce(testing::Return(false));
EXPECT_CALL(mock_input_handler_, ScrollEnd());
EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(cc::InputHandler::ScrollStarted));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
time += dt;
gesture_.timeStampSeconds = InSecondsF(time);
@@ -1815,7 +1873,7 @@ TEST_F(InputHandlerProxyTest, NoFlingBoostIfScrollDelayed) {
time += base::TimeDelta::FromMilliseconds(100);
EXPECT_CALL(mock_input_handler_, ScrollEnd());
EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(cc::InputHandler::ScrollStarted));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
input_handler_->Animate(time);
VERIFY_AND_RESET_MOCKS();
@@ -1897,7 +1955,7 @@ TEST_F(InputHandlerProxyTest, NoFlingBoostIfScrollInDifferentDirection) {
gesture_.data.scrollUpdate.deltaX = -fling_delta.x;
EXPECT_CALL(mock_input_handler_, ScrollEnd());
EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(cc::InputHandler::ScrollStarted));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
EXPECT_CALL(mock_input_handler_,
ScrollBy(testing::_,
testing::Property(&gfx::Vector2dF::x,
@@ -1948,6 +2006,26 @@ TEST_F(InputHandlerProxyTest, NoFlingBoostIfFlingTooSlow) {
VERIFY_AND_RESET_MOCKS();
}
+TEST_F(InputHandlerProxyTest, NoFlingBoostIfPreventBoostingFlagIsSet) {
+ base::TimeDelta dt = base::TimeDelta::FromMilliseconds(10);
+ base::TimeTicks time = base::TimeTicks() + dt;
+ WebFloatPoint fling_delta = WebFloatPoint(1000, 0);
+ WebPoint fling_point = WebPoint(7, 13);
+
+ StartFling(
+ time, blink::WebGestureDeviceTouchscreen, fling_delta, fling_point);
+
+ EXPECT_CALL(mock_input_handler_, ScrollEnd());
+
+ // Cancel the fling. The fling cancellation should not be deferred because of
+ // prevent boosting flag set.
+ gesture_.data.flingCancel.preventBoosting = true;
+ time += dt;
+ CancelFling(time);
+
+ // VERIFY_AND_RESET_MOCKS already called by CancelFling
+}
+
TEST_F(InputHandlerProxyTest, FlingBoostTerminatedDuringScrollSequence) {
base::TimeDelta dt = base::TimeDelta::FromMilliseconds(10);
base::TimeTicks time = base::TimeTicks() + dt;
@@ -1987,7 +2065,7 @@ TEST_F(InputHandlerProxyTest, FlingBoostTerminatedDuringScrollSequence) {
.WillOnce(testing::Return(scroll_result_did_not_scroll_));
EXPECT_CALL(mock_input_handler_, ScrollEnd());
EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(cc::InputHandler::ScrollStarted));
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
input_handler_->Animate(time);
VERIFY_AND_RESET_MOCKS();
@@ -2018,20 +2096,30 @@ TEST_F(InputHandlerProxyTest, FlingBoostTerminatedDuringScrollSequence) {
VERIFY_AND_RESET_MOCKS();
}
-TEST_F(InputHandlerProxyTest, DidReceiveInputEvent) {
- testing::StrictMock<
- MockInputHandlerProxyClientWithDidReceiveInputEvent> mock_client;
+TEST_F(InputHandlerProxyTest, DidReceiveInputEvent_ForFling) {
+ testing::StrictMock<MockInputHandlerProxyClientWithDidAnimateForInput>
+ mock_client;
input_handler_.reset(
new content::InputHandlerProxy(&mock_input_handler_, &mock_client));
- // Note the type of input event isn't important.
- WebMouseWheelEvent wheel;
- wheel.type = WebInputEvent::MouseWheel;
- wheel.scrollByPage = true;
+ gesture_.type = WebInputEvent::GestureFlingStart;
+ WebFloatPoint fling_delta = WebFloatPoint(100, 100);
+ gesture_.data.flingStart.velocityX = fling_delta.x;
+ gesture_.data.flingStart.velocityY = fling_delta.y;
+ EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+ EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
+ .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+ EXPECT_CALL(mock_input_handler_, ScrollEnd());
+ EXPECT_EQ(InputHandlerProxy::DID_HANDLE,
+ input_handler_->HandleInputEvent(gesture_));
+ testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
+ testing::Mock::VerifyAndClearExpectations(&mock_client);
- EXPECT_CALL(mock_client, DidReceiveInputEvent());
+ EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+ EXPECT_CALL(mock_client, DidAnimateForInput());
+ base::TimeTicks time = base::TimeTicks() + base::TimeDelta::FromSeconds(10);
+ input_handler_->Animate(time);
- input_handler_->HandleInputEvent(wheel);
testing::Mock::VerifyAndClearExpectations(&mock_client);
}
diff --git a/chromium/content/renderer/input/input_handler_wrapper.cc b/chromium/content/renderer/input/input_handler_wrapper.cc
index e53f624a831..8e3dcc9c2a3 100644
--- a/chromium/content/renderer/input/input_handler_wrapper.cc
+++ b/chromium/content/renderer/input/input_handler_wrapper.cc
@@ -57,8 +57,8 @@ void InputHandlerWrapper::DidStopFlinging() {
input_handler_manager_->DidStopFlinging(routing_id_);
}
-void InputHandlerWrapper::DidReceiveInputEvent() {
- // TODO(skyostil): Hook this up into the renderer scheduler.
+void InputHandlerWrapper::DidAnimateForInput() {
+ input_handler_manager_->DidAnimateForInput();
}
} // namespace content
diff --git a/chromium/content/renderer/input/input_handler_wrapper.h b/chromium/content/renderer/input/input_handler_wrapper.h
index fd997ce2803..2b3c42be360 100644
--- a/chromium/content/renderer/input/input_handler_wrapper.h
+++ b/chromium/content/renderer/input/input_handler_wrapper.h
@@ -35,7 +35,7 @@ class InputHandlerWrapper : public InputHandlerProxyClient {
const blink::WebSize& cumulativeScroll) override;
void DidOverscroll(const DidOverscrollParams& params) override;
void DidStopFlinging() override;
- void DidReceiveInputEvent() override;
+ void DidAnimateForInput() override;
private:
InputHandlerManager* input_handler_manager_;
diff --git a/chromium/content/renderer/input/input_scroll_elasticity_controller.cc b/chromium/content/renderer/input/input_scroll_elasticity_controller.cc
index 059bc9d5127..00d078ff76c 100644
--- a/chromium/content/renderer/input/input_scroll_elasticity_controller.cc
+++ b/chromium/content/renderer/input/input_scroll_elasticity_controller.cc
@@ -6,8 +6,12 @@
#include <math.h>
-// ScrollElasticityController and ScrollElasticityControllerClient are based on
-// WebKit/Source/platform/mac/ScrollElasticityController.mm
+#include "base/bind.h"
+#include "cc/input/input_handler.h"
+#include "ui/gfx/geometry/vector2d_conversions.h"
+
+// InputScrollElasticityController is based on
+// WebKit/Source/platform/mac/InputScrollElasticityController.mm
/*
* Copyright (C) 2011 Apple Inc. All rights reserved.
*
@@ -37,437 +41,370 @@ namespace content {
namespace {
-// TODO(ccameron): This is advertised as system uptime, but it used to compute
-// deltas against the event timestamps, which are in seconds since epoch. Find
-// out which is right. Also, avoid querying time, and use frame time instead.
-double SystemUptime() {
- return base::Time::Now().ToDoubleT();
-}
-
const float kScrollVelocityZeroingTimeout = 0.10f;
-const float kRubberbandDirectionLockStretchRatio = 1;
const float kRubberbandMinimumRequiredDeltaBeforeStretch = 10;
const float kRubberbandStiffness = 20;
const float kRubberbandAmplitude = 0.31f;
const float kRubberbandPeriod = 1.6f;
-float ElasticDeltaForTimeDelta(float initial_position,
- float initial_velocity,
- float elapsed_time) {
+// For these functions which compute the stretch amount, always return a
+// rounded value, instead of a floating-point value. The reason for this is
+// that Blink's scrolling can become erratic with fractional scroll amounts (in
+// particular, if you have a scroll offset of 0.5, Blink will never actually
+// bring that value back to 0, which breaks the logic used to determine if a
+// layer is pinned in a direction).
+
+gfx::Vector2d StretchAmountForTimeDelta(const gfx::Vector2dF& initial_position,
+ const gfx::Vector2dF& initial_velocity,
+ float elapsed_time) {
+ // Compute the stretch amount at a given time after some initial conditions.
+ // Do this by first computing an intermediary position given the initial
+ // position, initial velocity, time elapsed, and no external forces. Then
+ // take the intermediary position and damp it towards zero by multiplying
+ // against a negative exponential.
float amplitude = kRubberbandAmplitude;
float period = kRubberbandPeriod;
float critical_dampening_factor =
expf((-elapsed_time * kRubberbandStiffness) / period);
- return (initial_position + (-initial_velocity * elapsed_time * amplitude)) *
- critical_dampening_factor;
+ return gfx::ToRoundedVector2d(gfx::ScaleVector2d(
+ initial_position +
+ gfx::ScaleVector2d(initial_velocity, elapsed_time * amplitude),
+ critical_dampening_factor));
}
-float ElasticDeltaForReboundDelta(float delta) {
+gfx::Vector2d StretchAmountForReboundDelta(const gfx::Vector2dF& delta) {
float stiffness = std::max(kRubberbandStiffness, 1.0f);
- return delta / stiffness;
-}
-
-float ReboundDeltaForElasticDelta(float delta) {
- return delta * kRubberbandStiffness;
+ return gfx::ToRoundedVector2d(gfx::ScaleVector2d(delta, 1.0f / stiffness));
}
-float ScrollWheelMultiplier() {
- static float multiplier = -1;
- if (multiplier < 0) {
- // TODO(ccameron): Find a place fo this in an Objective C file, or find an
- // equivalent C call.
- // multiplier = [[NSUserDefaults standardUserDefaults]
- // floatForKey:@"NSScrollWheelMultiplier"];
- if (multiplier <= 0)
- multiplier = 1;
- }
- return multiplier;
+gfx::Vector2d StretchScrollForceForStretchAmount(const gfx::Vector2dF& delta) {
+ return gfx::ToRoundedVector2d(
+ gfx::ScaleVector2d(delta, kRubberbandStiffness));
}
} // namespace
-ScrollElasticityController::ScrollElasticityController(
- ScrollElasticityControllerClient* client)
- : client_(client),
- in_scroll_gesture_(false),
- has_scrolled_(false),
- momentum_scroll_in_progress_(false),
- ignore_momentum_scrolls_(false),
- last_momentum_scroll_timestamp_(0),
- snap_rubberband_timer_is_active_(false) {
+InputScrollElasticityController::InputScrollElasticityController(
+ cc::ScrollElasticityHelper* helper)
+ : helper_(helper),
+ state_(kStateInactive),
+ momentum_animation_reset_at_next_frame_(false),
+ weak_factory_(this) {
}
-bool ScrollElasticityController::HandleWheelEvent(
- const blink::WebMouseWheelEvent& wheel_event) {
- if (wheel_event.phase == blink::WebMouseWheelEvent::PhaseMayBegin)
- return false;
-
- if (wheel_event.phase == blink::WebMouseWheelEvent::PhaseBegan) {
- in_scroll_gesture_ = true;
- has_scrolled_ = false;
- momentum_scroll_in_progress_ = false;
- ignore_momentum_scrolls_ = false;
- last_momentum_scroll_timestamp_ = 0;
- momentum_velocity_ = gfx::Vector2dF();
-
- gfx::Vector2dF stretch_amount = client_->StretchAmount();
- stretch_scroll_force_.set_x(
- ReboundDeltaForElasticDelta(stretch_amount.x()));
- stretch_scroll_force_.set_y(
- ReboundDeltaForElasticDelta(stretch_amount.y()));
- overflow_scroll_delta_ = gfx::Vector2dF();
-
- StopSnapRubberbandTimer();
-
- // TODO(erikchen): Use the commented out line once Chromium uses the
- // return value correctly.
- // crbug.com/375512
- // return ShouldHandleEvent(wheel_event);
-
- // This logic is incorrect, since diagonal wheel events are not consumed.
- if (client_->PinnedInDirection(gfx::Vector2dF(-wheel_event.deltaX, 0))) {
- if (wheel_event.deltaX > 0 && !wheel_event.canRubberbandLeft)
- return false;
- if (wheel_event.deltaX < 0 && !wheel_event.canRubberbandRight)
- return false;
- }
-
- return true;
- }
-
- if (wheel_event.phase == blink::WebMouseWheelEvent::PhaseEnded ||
- wheel_event.phase == blink::WebMouseWheelEvent::PhaseCancelled) {
- SnapRubberband();
- return has_scrolled_;
- }
-
- bool isMomentumScrollEvent =
- (wheel_event.momentumPhase != blink::WebMouseWheelEvent::PhaseNone);
- if (ignore_momentum_scrolls_ &&
- (isMomentumScrollEvent || snap_rubberband_timer_is_active_)) {
- if (wheel_event.momentumPhase == blink::WebMouseWheelEvent::PhaseEnded) {
- ignore_momentum_scrolls_ = false;
- return true;
- }
- return false;
- }
-
- if (!ShouldHandleEvent(wheel_event))
- return false;
-
- float delta_x = overflow_scroll_delta_.x() - wheel_event.deltaX;
- float delta_y = overflow_scroll_delta_.y() - wheel_event.deltaY;
- float event_coalesced_delta_x = -wheel_event.deltaX;
- float event_coalesced_delta_y = -wheel_event.deltaY;
-
- // Reset overflow values because we may decide to remove delta at various
- // points and put it into overflow.
- overflow_scroll_delta_ = gfx::Vector2dF();
-
- gfx::Vector2dF stretch_amount = client_->StretchAmount();
- bool is_vertically_stretched = stretch_amount.y() != 0.f;
- bool is_horizontally_stretched = stretch_amount.x() != 0.f;
-
- // Slightly prefer scrolling vertically by applying the = case to delta_y
- if (fabsf(delta_y) >= fabsf(delta_x))
- delta_x = 0;
- else
- delta_y = 0;
-
- bool should_stretch = false;
+InputScrollElasticityController::~InputScrollElasticityController() {
+}
- blink::WebMouseWheelEvent::Phase momentum_phase = wheel_event.momentumPhase;
+base::WeakPtr<InputScrollElasticityController>
+InputScrollElasticityController::GetWeakPtr() {
+ if (helper_)
+ return weak_factory_.GetWeakPtr();
+ return base::WeakPtr<InputScrollElasticityController>();
+}
- // If we are starting momentum scrolling then do some setup.
- if (!momentum_scroll_in_progress_ &&
- (momentum_phase == blink::WebMouseWheelEvent::PhaseBegan ||
- momentum_phase == blink::WebMouseWheelEvent::PhaseChanged)) {
- momentum_scroll_in_progress_ = true;
- // Start the snap rubber band timer if it's not running. This is needed to
- // snap back from the over scroll caused by momentum events.
- if (!snap_rubberband_timer_is_active_ && start_time_ == base::Time())
- SnapRubberband();
+void InputScrollElasticityController::ObserveWheelEventAndResult(
+ const blink::WebMouseWheelEvent& wheel_event,
+ const cc::InputHandlerScrollResult& scroll_result) {
+ // We should only get PhaseMayBegin or PhaseBegan events while in the
+ // Inactive or MomentumAnimated states, but in case we get bad input (e.g,
+ // abbreviated by tab-switch), always re-set the state to ActiveScrolling
+ // when those events are received.
+ if (wheel_event.phase == blink::WebMouseWheelEvent::PhaseMayBegin ||
+ wheel_event.phase == blink::WebMouseWheelEvent::PhaseBegan) {
+ scroll_velocity = gfx::Vector2dF();
+ last_scroll_event_timestamp_ = base::TimeTicks();
+ state_ = kStateActiveScroll;
+ pending_overscroll_delta_ = gfx::Vector2dF();
+ return;
}
- double time_delta =
- wheel_event.timeStampSeconds - last_momentum_scroll_timestamp_;
- if (in_scroll_gesture_ || momentum_scroll_in_progress_) {
- if (last_momentum_scroll_timestamp_ && time_delta > 0 &&
- time_delta < kScrollVelocityZeroingTimeout) {
- momentum_velocity_.set_x(event_coalesced_delta_x / (float)time_delta);
- momentum_velocity_.set_y(event_coalesced_delta_y / (float)time_delta);
- last_momentum_scroll_timestamp_ = wheel_event.timeStampSeconds;
- } else {
- last_momentum_scroll_timestamp_ = wheel_event.timeStampSeconds;
- momentum_velocity_ = gfx::Vector2dF();
+ gfx::Vector2dF event_delta(-wheel_event.deltaX, -wheel_event.deltaY);
+ base::TimeTicks event_timestamp =
+ base::TimeTicks() +
+ base::TimeDelta::FromSecondsD(wheel_event.timeStampSeconds);
+ switch (state_) {
+ case kStateInactive: {
+ // The PhaseMayBegin and PhaseBegan cases are handled at the top of the
+ // function.
+ if (wheel_event.momentumPhase == blink::WebMouseWheelEvent::PhaseBegan)
+ state_ = kStateMomentumScroll;
+ break;
}
-
- if (is_vertically_stretched) {
- if (!is_horizontally_stretched &&
- client_->PinnedInDirection(gfx::Vector2dF(delta_x, 0))) {
- // Stretching only in the vertical.
- if (delta_y != 0 &&
- (fabsf(delta_x / delta_y) < kRubberbandDirectionLockStretchRatio))
- delta_x = 0;
- else if (fabsf(delta_x) <
- kRubberbandMinimumRequiredDeltaBeforeStretch) {
- overflow_scroll_delta_.set_x(overflow_scroll_delta_.x() + delta_x);
- delta_x = 0;
- } else
- overflow_scroll_delta_.set_x(overflow_scroll_delta_.x() + delta_x);
- }
- } else if (is_horizontally_stretched) {
- // Stretching only in the horizontal.
- if (client_->PinnedInDirection(gfx::Vector2dF(0, delta_y))) {
- if (delta_x != 0 &&
- (fabsf(delta_y / delta_x) < kRubberbandDirectionLockStretchRatio))
- delta_y = 0;
- else if (fabsf(delta_y) <
- kRubberbandMinimumRequiredDeltaBeforeStretch) {
- overflow_scroll_delta_.set_y(overflow_scroll_delta_.y() + delta_y);
- delta_y = 0;
- } else
- overflow_scroll_delta_.set_y(overflow_scroll_delta_.y() + delta_y);
+ case kStateActiveScroll:
+ if (wheel_event.phase == blink::WebMouseWheelEvent::PhaseChanged) {
+ UpdateVelocity(event_delta, event_timestamp);
+ Overscroll(event_delta, scroll_result.unused_scroll_delta);
+ } else if (wheel_event.phase == blink::WebMouseWheelEvent::PhaseEnded ||
+ wheel_event.phase ==
+ blink::WebMouseWheelEvent::PhaseCancelled) {
+ if (helper_->StretchAmount().IsZero()) {
+ EnterStateInactive();
+ } else {
+ EnterStateMomentumAnimated(event_timestamp);
+ }
}
- } else {
- // Not stretching at all yet.
- if (client_->PinnedInDirection(gfx::Vector2dF(delta_x, delta_y))) {
- if (fabsf(delta_y) >= fabsf(delta_x)) {
- if (fabsf(delta_x) < kRubberbandMinimumRequiredDeltaBeforeStretch) {
- overflow_scroll_delta_.set_x(overflow_scroll_delta_.x() + delta_x);
- delta_x = 0;
- } else
- overflow_scroll_delta_.set_x(overflow_scroll_delta_.x() + delta_x);
+ break;
+ case kStateMomentumScroll:
+ if (wheel_event.momentumPhase ==
+ blink::WebMouseWheelEvent::PhaseChanged) {
+ UpdateVelocity(event_delta, event_timestamp);
+ Overscroll(event_delta, scroll_result.unused_scroll_delta);
+ if (!helper_->StretchAmount().IsZero()) {
+ EnterStateMomentumAnimated(event_timestamp);
}
- should_stretch = true;
+ } else if (wheel_event.momentumPhase ==
+ blink::WebMouseWheelEvent::PhaseEnded) {
+ EnterStateInactive();
}
- }
+ case kStateMomentumAnimated:
+ // The PhaseMayBegin and PhaseBegan cases are handled at the top of the
+ // function.
+ break;
}
+}
- if (delta_x != 0 || delta_y != 0) {
- has_scrolled_ = true;
- if (!(should_stretch || is_vertically_stretched ||
- is_horizontally_stretched)) {
- if (delta_y != 0) {
- delta_y *= ScrollWheelMultiplier();
- client_->ImmediateScrollBy(gfx::Vector2dF(0, delta_y));
- }
- if (delta_x != 0) {
- delta_x *= ScrollWheelMultiplier();
- client_->ImmediateScrollBy(gfx::Vector2dF(delta_x, 0));
- }
- } else {
- if (!client_->AllowsHorizontalStretching()) {
- delta_x = 0;
- event_coalesced_delta_x = 0;
- } else if ((delta_x != 0) && !is_horizontally_stretched &&
- !client_->PinnedInDirection(gfx::Vector2dF(delta_x, 0))) {
- delta_x *= ScrollWheelMultiplier();
-
- client_->ImmediateScrollByWithoutContentEdgeConstraints(
- gfx::Vector2dF(delta_x, 0));
- delta_x = 0;
- }
-
- if (!client_->AllowsVerticalStretching()) {
- delta_y = 0;
- event_coalesced_delta_y = 0;
- } else if ((delta_y != 0) && !is_vertically_stretched &&
- !client_->PinnedInDirection(gfx::Vector2dF(0, delta_y))) {
- delta_y *= ScrollWheelMultiplier();
-
- client_->ImmediateScrollByWithoutContentEdgeConstraints(
- gfx::Vector2dF(0, delta_y));
- delta_y = 0;
- }
+void InputScrollElasticityController::UpdateVelocity(
+ const gfx::Vector2dF& event_delta,
+ const base::TimeTicks& event_timestamp) {
+ float time_delta =
+ (event_timestamp - last_scroll_event_timestamp_).InSecondsF();
+ if (time_delta < kScrollVelocityZeroingTimeout && time_delta > 0) {
+ scroll_velocity = gfx::Vector2dF(event_delta.x() / time_delta,
+ event_delta.y() / time_delta);
+ } else {
+ scroll_velocity = gfx::Vector2dF();
+ }
+ last_scroll_event_timestamp_ = event_timestamp;
+}
- gfx::Vector2dF stretch_amount = client_->StretchAmount();
-
- if (momentum_scroll_in_progress_) {
- if ((client_->PinnedInDirection(gfx::Vector2dF(
- event_coalesced_delta_x, event_coalesced_delta_y)) ||
- (fabsf(event_coalesced_delta_x) + fabsf(event_coalesced_delta_y) <=
- 0)) &&
- last_momentum_scroll_timestamp_) {
- ignore_momentum_scrolls_ = true;
- momentum_scroll_in_progress_ = false;
- SnapRubberband();
- }
- }
+void InputScrollElasticityController::Overscroll(
+ const gfx::Vector2dF& input_delta,
+ const gfx::Vector2dF& overscroll_delta) {
+ // The effect can be dynamically disabled by setting disallowing user
+ // scrolling. When disabled, disallow active or momentum overscrolling, but
+ // allow any current overscroll to animate back.
+ if (!helper_->IsUserScrollable())
+ return;
- stretch_scroll_force_.set_x(stretch_scroll_force_.x() + delta_x);
- stretch_scroll_force_.set_y(stretch_scroll_force_.y() + delta_y);
+ gfx::Vector2dF adjusted_overscroll_delta =
+ pending_overscroll_delta_ + overscroll_delta;
+ pending_overscroll_delta_ = gfx::Vector2dF();
- gfx::Vector2dF damped_delta(
- ceilf(ElasticDeltaForReboundDelta(stretch_scroll_force_.x())),
- ceilf(ElasticDeltaForReboundDelta(stretch_scroll_force_.y())));
+ // Only allow one direction to overscroll at a time, and slightly prefer
+ // scrolling vertically by applying the equal case to delta_y.
+ if (fabsf(input_delta.y()) >= fabsf(input_delta.x()))
+ adjusted_overscroll_delta.set_x(0);
+ else
+ adjusted_overscroll_delta.set_y(0);
- client_->ImmediateScrollByWithoutContentEdgeConstraints(damped_delta -
- stretch_amount);
- }
+ // Don't allow overscrolling in a direction where scrolling is possible.
+ if (!PinnedHorizontally(adjusted_overscroll_delta.x()))
+ adjusted_overscroll_delta.set_x(0);
+ if (!PinnedVertically(adjusted_overscroll_delta.y())) {
+ adjusted_overscroll_delta.set_y(0);
}
- if (momentum_scroll_in_progress_ &&
- momentum_phase == blink::WebMouseWheelEvent::PhaseEnded) {
- momentum_scroll_in_progress_ = false;
- ignore_momentum_scrolls_ = false;
- last_momentum_scroll_timestamp_ = 0;
+ // Require a minimum of 10 units of overscroll before starting the rubber-band
+ // stretch effect, so that small stray motions don't trigger it. If that
+ // minimum isn't met, save what remains in |pending_overscroll_delta_| for
+ // the next event.
+ gfx::Vector2dF old_stretch_amount = helper_->StretchAmount();
+ gfx::Vector2dF stretch_scroll_force_delta;
+ if (old_stretch_amount.x() != 0 ||
+ fabsf(adjusted_overscroll_delta.x()) >=
+ kRubberbandMinimumRequiredDeltaBeforeStretch) {
+ stretch_scroll_force_delta.set_x(adjusted_overscroll_delta.x());
+ } else {
+ pending_overscroll_delta_.set_x(adjusted_overscroll_delta.x());
+ }
+ if (old_stretch_amount.y() != 0 ||
+ fabsf(adjusted_overscroll_delta.y()) >=
+ kRubberbandMinimumRequiredDeltaBeforeStretch) {
+ stretch_scroll_force_delta.set_y(adjusted_overscroll_delta.y());
+ } else {
+ pending_overscroll_delta_.set_y(adjusted_overscroll_delta.y());
}
- return true;
+ // Update the stretch amount according to the spring equations.
+ if (stretch_scroll_force_delta.IsZero())
+ return;
+ stretch_scroll_force_ += stretch_scroll_force_delta;
+ gfx::Vector2dF new_stretch_amount =
+ StretchAmountForReboundDelta(stretch_scroll_force_);
+ helper_->SetStretchAmount(new_stretch_amount);
}
-namespace {
-
-float RoundTowardZero(float num) {
- return num > 0 ? ceilf(num - 0.5f) : floorf(num + 0.5f);
+void InputScrollElasticityController::EnterStateInactive() {
+ DCHECK_NE(kStateInactive, state_);
+ DCHECK(helper_->StretchAmount().IsZero());
+ state_ = kStateInactive;
+ stretch_scroll_force_ = gfx::Vector2dF();
}
-float RoundToDevicePixelTowardZero(float num) {
- float rounded_num = roundf(num);
- if (fabs(num - rounded_num) < 0.125)
- num = rounded_num;
+void InputScrollElasticityController::EnterStateMomentumAnimated(
+ const base::TimeTicks& triggering_event_timestamp) {
+ DCHECK_NE(kStateMomentumAnimated, state_);
+ state_ = kStateMomentumAnimated;
- return RoundTowardZero(num);
-}
+ momentum_animation_start_time_ = triggering_event_timestamp;
+ momentum_animation_initial_stretch_ = helper_->StretchAmount();
+ momentum_animation_initial_velocity_ = scroll_velocity;
+ momentum_animation_reset_at_next_frame_ = false;
-} // namespace
+ // Similarly to the logic in Overscroll, prefer vertical scrolling to
+ // horizontal scrolling.
+ if (fabsf(momentum_animation_initial_velocity_.y()) >=
+ fabsf(momentum_animation_initial_velocity_.x()))
+ momentum_animation_initial_velocity_.set_x(0);
-void ScrollElasticityController::SnapRubberbandTimerFired() {
- if (!momentum_scroll_in_progress_ || ignore_momentum_scrolls_) {
- float time_delta = (base::Time::Now() - start_time_).InSecondsF();
+ if (!CanScrollHorizontally())
+ momentum_animation_initial_velocity_.set_x(0);
- if (start_stretch_ == gfx::Vector2dF()) {
- start_stretch_ = client_->StretchAmount();
- if (start_stretch_ == gfx::Vector2dF()) {
- StopSnapRubberbandTimer();
+ if (!CanScrollVertically())
+ momentum_animation_initial_velocity_.set_y(0);
- stretch_scroll_force_ = gfx::Vector2dF();
- start_time_ = base::Time();
- orig_origin_ = gfx::Vector2dF();
- orig_velocity_ = gfx::Vector2dF();
- return;
- }
+ helper_->RequestAnimate();
+}
+
+void InputScrollElasticityController::Animate(base::TimeTicks time) {
+ if (state_ != kStateMomentumAnimated)
+ return;
- orig_origin_ = client_->AbsoluteScrollPosition() - start_stretch_;
- orig_velocity_ = momentum_velocity_;
+ if (momentum_animation_reset_at_next_frame_) {
+ momentum_animation_start_time_ = time;
+ momentum_animation_initial_stretch_ = helper_->StretchAmount();
+ momentum_animation_initial_velocity_ = gfx::Vector2dF();
+ momentum_animation_reset_at_next_frame_ = false;
+ }
- // Just like normal scrolling, prefer vertical rubberbanding
- if (fabsf(orig_velocity_.y()) >= fabsf(orig_velocity_.x()))
- orig_velocity_.set_x(0);
+ float time_delta =
+ std::max((time - momentum_animation_start_time_).InSecondsF(), 0.0);
- // Don't rubber-band horizontally if it's not possible to scroll
- // horizontally
- if (!client_->CanScrollHorizontally())
- orig_velocity_.set_x(0);
+ gfx::Vector2dF old_stretch_amount = helper_->StretchAmount();
+ gfx::Vector2dF new_stretch_amount = StretchAmountForTimeDelta(
+ momentum_animation_initial_stretch_, momentum_animation_initial_velocity_,
+ time_delta);
+ gfx::Vector2dF stretch_delta = new_stretch_amount - old_stretch_amount;
- // Don't rubber-band vertically if it's not possible to scroll
- // vertically
- if (!client_->CanScrollVertically())
- orig_velocity_.set_y(0);
- }
+ // If the new stretch amount is near zero, set it directly to zero and enter
+ // the inactive state.
+ if (fabs(new_stretch_amount.x()) < 1 && fabs(new_stretch_amount.y()) < 1) {
+ helper_->SetStretchAmount(gfx::Vector2dF());
+ EnterStateInactive();
+ return;
+ }
- gfx::Vector2dF delta(
- RoundToDevicePixelTowardZero(ElasticDeltaForTimeDelta(
- start_stretch_.x(), -orig_velocity_.x(), time_delta)),
- RoundToDevicePixelTowardZero(ElasticDeltaForTimeDelta(
- start_stretch_.y(), -orig_velocity_.y(), time_delta)));
-
- if (fabs(delta.x()) >= 1 || fabs(delta.y()) >= 1) {
- client_->ImmediateScrollByWithoutContentEdgeConstraints(
- gfx::Vector2dF(delta.x(), delta.y()) - client_->StretchAmount());
-
- gfx::Vector2dF new_stretch = client_->StretchAmount();
-
- stretch_scroll_force_.set_x(ReboundDeltaForElasticDelta(new_stretch.x()));
- stretch_scroll_force_.set_y(ReboundDeltaForElasticDelta(new_stretch.y()));
- } else {
- client_->AdjustScrollPositionToBoundsIfNecessary();
-
- StopSnapRubberbandTimer();
- stretch_scroll_force_ = gfx::Vector2dF();
- start_time_ = base::Time();
- start_stretch_ = gfx::Vector2dF();
- orig_origin_ = gfx::Vector2dF();
- orig_velocity_ = gfx::Vector2dF();
- }
- } else {
- start_time_ = base::Time::Now();
- start_stretch_ = gfx::Vector2dF();
+ // If we are not pinned in the direction of the delta, then the delta is only
+ // allowed to decrease the existing stretch -- it cannot increase a stretch
+ // until it is pinned.
+ if (!PinnedHorizontally(stretch_delta.x())) {
+ if (stretch_delta.x() > 0 && old_stretch_amount.x() < 0)
+ stretch_delta.set_x(std::min(stretch_delta.x(), -old_stretch_amount.x()));
+ else if (stretch_delta.x() < 0 && old_stretch_amount.x() > 0)
+ stretch_delta.set_x(std::max(stretch_delta.x(), -old_stretch_amount.x()));
+ else
+ stretch_delta.set_x(0);
}
-}
+ if (!PinnedVertically(stretch_delta.y())) {
+ if (stretch_delta.y() > 0 && old_stretch_amount.y() < 0)
+ stretch_delta.set_y(std::min(stretch_delta.y(), -old_stretch_amount.y()));
+ else if (stretch_delta.y() < 0 && old_stretch_amount.y() > 0)
+ stretch_delta.set_y(std::max(stretch_delta.y(), -old_stretch_amount.y()));
+ else
+ stretch_delta.set_y(0);
+ }
+ new_stretch_amount = old_stretch_amount + stretch_delta;
-bool ScrollElasticityController::IsRubberbandInProgress() const {
- if (!in_scroll_gesture_ && !momentum_scroll_in_progress_ &&
- !snap_rubberband_timer_is_active_)
- return false;
+ stretch_scroll_force_ =
+ StretchScrollForceForStretchAmount(new_stretch_amount);
+ helper_->SetStretchAmount(new_stretch_amount);
+ helper_->RequestAnimate();
+}
- return !client_->StretchAmount().IsZero();
+bool InputScrollElasticityController::PinnedHorizontally(
+ float direction) const {
+ gfx::ScrollOffset scroll_offset = helper_->ScrollOffset();
+ gfx::ScrollOffset max_scroll_offset = helper_->MaxScrollOffset();
+ if (direction < 0)
+ return scroll_offset.x() <= 0;
+ if (direction > 0)
+ return scroll_offset.x() >= max_scroll_offset.x();
+ return false;
}
-void ScrollElasticityController::StopSnapRubberbandTimer() {
- client_->StopSnapRubberbandTimer();
- snap_rubberband_timer_is_active_ = false;
+bool InputScrollElasticityController::PinnedVertically(float direction) const {
+ gfx::ScrollOffset scroll_offset = helper_->ScrollOffset();
+ gfx::ScrollOffset max_scroll_offset = helper_->MaxScrollOffset();
+ if (direction < 0)
+ return scroll_offset.y() <= 0;
+ if (direction > 0)
+ return scroll_offset.y() >= max_scroll_offset.y();
+ return false;
}
-void ScrollElasticityController::SnapRubberband() {
- double time_delta = SystemUptime() - last_momentum_scroll_timestamp_;
- if (last_momentum_scroll_timestamp_ &&
- time_delta >= kScrollVelocityZeroingTimeout)
- momentum_velocity_ = gfx::Vector2dF();
+bool InputScrollElasticityController::CanScrollHorizontally() const {
+ return helper_->MaxScrollOffset().x() > 0;
+}
- in_scroll_gesture_ = false;
+bool InputScrollElasticityController::CanScrollVertically() const {
+ return helper_->MaxScrollOffset().y() > 0;
+}
- if (snap_rubberband_timer_is_active_)
+void InputScrollElasticityController::ReconcileStretchAndScroll() {
+ gfx::Vector2dF stretch = helper_->StretchAmount();
+ if (stretch.IsZero())
return;
- start_stretch_ = gfx::Vector2dF();
- orig_origin_ = gfx::Vector2dF();
- orig_velocity_ = gfx::Vector2dF();
+ gfx::ScrollOffset scroll_offset = helper_->ScrollOffset();
+ gfx::ScrollOffset max_scroll_offset = helper_->MaxScrollOffset();
- // If there's no momentum scroll or stretch amount, no need to start the
- // timer.
- if (!momentum_scroll_in_progress_ &&
- client_->StretchAmount() == gfx::Vector2dF()) {
- start_time_ = base::Time();
- stretch_scroll_force_ = gfx::Vector2dF();
- return;
+ // Compute stretch_adjustment which will be added to |stretch| and subtracted
+ // from the |scroll_offset|.
+ gfx::Vector2dF stretch_adjustment;
+ if (stretch.x() < 0 && scroll_offset.x() > 0) {
+ stretch_adjustment.set_x(
+ std::min(-stretch.x(), static_cast<float>(scroll_offset.x())));
+ }
+ if (stretch.x() > 0 && scroll_offset.x() < max_scroll_offset.x()) {
+ stretch_adjustment.set_x(std::max(
+ -stretch.x(),
+ static_cast<float>(scroll_offset.x() - max_scroll_offset.x())));
+ }
+ if (stretch.y() < 0 && scroll_offset.y() > 0) {
+ stretch_adjustment.set_y(
+ std::min(-stretch.y(), static_cast<float>(scroll_offset.y())));
+ }
+ if (stretch.y() > 0 && scroll_offset.y() < max_scroll_offset.y()) {
+ stretch_adjustment.set_y(std::max(
+ -stretch.y(),
+ static_cast<float>(scroll_offset.y() - max_scroll_offset.y())));
}
- start_time_ = base::Time::Now();
- client_->StartSnapRubberbandTimer();
- snap_rubberband_timer_is_active_ = true;
-}
+ if (stretch_adjustment.IsZero())
+ return;
-bool ScrollElasticityController::ShouldHandleEvent(
- const blink::WebMouseWheelEvent& wheel_event) {
- // Once any scrolling has happened, all future events should be handled.
- if (has_scrolled_)
- return true;
-
- // The event can't cause scrolling to start if its delta is 0.
- if (wheel_event.deltaX == 0 && wheel_event.deltaY == 0)
- return false;
-
- // If the client isn't pinned, then the event is guaranteed to cause
- // scrolling.
- if (!client_->PinnedInDirection(gfx::Vector2dF(-wheel_event.deltaX, 0)))
- return true;
-
- // If the event is pinned, then the client can't scroll, but it might rubber
- // band.
- // Check if the event allows rubber banding.
- if (wheel_event.deltaY == 0) {
- if (wheel_event.deltaX > 0 && !wheel_event.canRubberbandLeft)
- return false;
- if (wheel_event.deltaX < 0 && !wheel_event.canRubberbandRight)
- return false;
+ gfx::Vector2dF new_stretch_amount = stretch + stretch_adjustment;
+ helper_->ScrollBy(-stretch_adjustment);
+ helper_->SetStretchAmount(new_stretch_amount);
+
+ // Update the internal state for the active scroll or animation to avoid
+ // discontinuities.
+ switch (state_) {
+ case kStateActiveScroll:
+ stretch_scroll_force_ =
+ StretchScrollForceForStretchAmount(new_stretch_amount);
+ break;
+ case kStateMomentumAnimated:
+ momentum_animation_reset_at_next_frame_ = true;
+ break;
+ default:
+ // These cases should not be hit because the stretch must be zero in the
+ // Inactive and MomentumScroll states.
+ NOTREACHED();
+ break;
}
-
- // The event is going to either cause scrolling or rubber banding.
- return true;
}
} // namespace content
diff --git a/chromium/content/renderer/input/input_scroll_elasticity_controller.h b/chromium/content/renderer/input/input_scroll_elasticity_controller.h
index 79cb4ed4c13..c60a86e25b5 100644
--- a/chromium/content/renderer/input/input_scroll_elasticity_controller.h
+++ b/chromium/content/renderer/input/input_scroll_elasticity_controller.h
@@ -6,11 +6,12 @@
#define CONTENT_RENDERER_INPUT_INPUT_SCROLL_ELASTICITY_CONTROLLER_H_
#include "base/macros.h"
-#include "base/time/time.h"
+#include "base/memory/weak_ptr.h"
+#include "cc/input/scroll_elasticity_helper.h"
+#include "content/common/content_export.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
-#include "ui/gfx/geometry/vector2d_f.h"
-// ScrollElasticityController and ScrollElasticityControllerClient are based on
+// InputScrollElasticityController is based on
// WebKit/Source/platform/mac/ScrollElasticityController.h
/*
* Copyright (C) 2011 Apple Inc. All rights reserved.
@@ -37,105 +38,109 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-namespace content {
+namespace cc {
+struct InputHandlerScrollResult;
+} // namespace cc
-class ScrollElasticityControllerClient {
- protected:
- virtual ~ScrollElasticityControllerClient() {}
+namespace content {
+class CONTENT_EXPORT InputScrollElasticityController {
public:
- virtual bool AllowsHorizontalStretching() = 0;
- virtual bool AllowsVerticalStretching() = 0;
- // The amount that the view is stretched past the normal allowable bounds.
- // The "overhang" amount.
- virtual gfx::Vector2dF StretchAmount() = 0;
- virtual bool PinnedInDirection(const gfx::Vector2dF& direction) = 0;
- virtual bool CanScrollHorizontally() = 0;
- virtual bool CanScrollVertically() = 0;
-
- // Return the absolute scroll position, not relative to the scroll origin.
- virtual gfx::Vector2dF AbsoluteScrollPosition() = 0;
-
- virtual void ImmediateScrollBy(const gfx::Vector2dF& scroll) = 0;
- virtual void ImmediateScrollByWithoutContentEdgeConstraints(
- const gfx::Vector2dF& scroll) = 0;
- virtual void StartSnapRubberbandTimer() = 0;
- virtual void StopSnapRubberbandTimer() = 0;
-
- // If the current scroll position is within the overhang area, this function
- // will cause
- // the page to scroll to the nearest boundary point.
- virtual void AdjustScrollPositionToBoundsIfNecessary() = 0;
-};
+ explicit InputScrollElasticityController(cc::ScrollElasticityHelper* helper);
+ virtual ~InputScrollElasticityController();
-class ScrollElasticityController {
- public:
- explicit ScrollElasticityController(ScrollElasticityControllerClient*);
-
- // This method is responsible for both scrolling and rubber-banding.
- //
- // Events are passed by IPC from the embedder. Events on Mac are grouped
- // into "gestures". If this method returns 'true', then this object has
- // handled the event. It expects the embedder to continue to forward events
- // from the gesture.
- //
- // This method makes the assumption that there is only 1 input device being
- // used at a time. If the user simultaneously uses multiple input devices,
- // Cocoa does not correctly pass all the gestureBegin/End events. The state
- // of this class is guaranteed to become eventually consistent, once the
- // user stops using multiple input devices.
- bool HandleWheelEvent(const blink::WebMouseWheelEvent& wheel_event);
- void SnapRubberbandTimerFired();
-
- bool IsRubberbandInProgress() const;
+ base::WeakPtr<InputScrollElasticityController> GetWeakPtr();
+
+ // Update the overscroll state based a wheel event that has been processed.
+ // Note that this assumes that all events are coming from a single input
+ // device. If the user simultaneously uses multiple input devices, Cocoa may
+ // not correctly pass all the gesture begin and end events. In this case,
+ // this class may disregard some scrolls that come in at unexpected times.
+ void ObserveWheelEventAndResult(
+ const blink::WebMouseWheelEvent& wheel_event,
+ const cc::InputHandlerScrollResult& scroll_result);
+ void Animate(base::TimeTicks time);
+
+ void ReconcileStretchAndScroll();
private:
- void StopSnapRubberbandTimer();
- void SnapRubberband();
-
- // This method determines whether a given event should be handled. The
- // logic for control events of gestures (PhaseBegan, PhaseEnded) is handled
- // elsewhere.
- //
- // This class handles almost all wheel events. All of the following
- // conditions must be met for this class to ignore an event:
- // + No previous events in this gesture have caused any scrolling or rubber
- // banding.
- // + The event contains a horizontal component.
- // + The client's view is pinned in the horizontal direction of the event.
- // + The wheel event disallows rubber banding in the horizontal direction
- // of the event.
- bool ShouldHandleEvent(const blink::WebMouseWheelEvent& wheel_event);
-
- ScrollElasticityControllerClient* client_;
-
- // There is an active scroll gesture event. This parameter only gets set to
- // false after the rubber band has been snapped, and before a new gesture
- // has begun. A careful audit of the code may deprecate the need for this
- // parameter.
- bool in_scroll_gesture_;
- // At least one event in the current gesture has been consumed and has
- // caused the view to scroll or rubber band. All future events in this
- // gesture will be consumed and overscrolls will cause rubberbanding.
- bool has_scrolled_;
- bool momentum_scroll_in_progress_;
- bool ignore_momentum_scrolls_;
-
- // Used with blink::WebInputEvent::timeStampSeconds, in seconds since epoch.
- double last_momentum_scroll_timestamp_;
- gfx::Vector2dF overflow_scroll_delta_;
+ enum State {
+ // The initial state, during which the overscroll amount is zero and
+ // there are no active or momentum scroll events coming in. This state
+ // is briefly returned to between the active and momentum phases of a
+ // scroll (if there is no overscroll).
+ kStateInactive,
+ // The state between receiving PhaseBegan/MayBegin and PhaseEnd/Cancelled,
+ // corresponding to the period during which the user has fingers on the
+ // trackpad. The overscroll amount is updated as input events are received.
+ // When PhaseEnd is received, the state transitions to Inactive if there is
+ // no overscroll and MomentumAnimated if there is non-zero overscroll.
+ kStateActiveScroll,
+ // The state between receiving a momentum PhaseBegan and PhaseEnd, while
+ // there is no overscroll. The overscroll amount is updated as input events
+ // are received. If the overscroll is ever non-zero then the state
+ // immediately transitions to kStateMomentumAnimated.
+ kStateMomentumScroll,
+ // The state while the overscroll amount is updated by an animation. If
+ // the user places fingers on the trackpad (a PhaseMayBegin is received)
+ // then the state transition to kStateActiveScroll. Otherwise the state
+ // transitions to Inactive when the overscroll amount becomes zero.
+ kStateMomentumAnimated,
+ };
+
+ void UpdateVelocity(const gfx::Vector2dF& event_delta,
+ const base::TimeTicks& event_timestamp);
+ void Overscroll(const gfx::Vector2dF& input_delta,
+ const gfx::Vector2dF& overscroll_delta);
+ void EnterStateMomentumAnimated(
+ const base::TimeTicks& triggering_event_timestamp);
+ void EnterStateInactive();
+
+ // Returns true if |direction| is pointing in a direction in which it is not
+ // possible to scroll any farther horizontally (or vertically). It is only in
+ // this circumstance that an overscroll in that direction may begin.
+ bool PinnedHorizontally(float direction) const;
+ bool PinnedVertically(float direction) const;
+ // Whether or not the content of the page is scrollable horizontaly (or
+ // vertically).
+ bool CanScrollHorizontally() const;
+ bool CanScrollVertically() const;
+
+ cc::ScrollElasticityHelper* helper_;
+ State state_;
+
+ // If there is no overscroll, require a minimum overscroll delta before
+ // starting the rubber-band effect. Track the amount of scrolling that has
+ // has occurred but has not yet caused rubber-band stretching in
+ // |pending_overscroll_delta_|.
+ gfx::Vector2dF pending_overscroll_delta_;
+
+ // Maintain a calculation of the velocity of the scroll, based on the input
+ // scroll delta divide by the time between input events. Track this velocity
+ // in |scroll_velocity| and the previous input event timestamp for finite
+ // differencing in |last_scroll_event_timestamp_|.
+ gfx::Vector2dF scroll_velocity;
+ base::TimeTicks last_scroll_event_timestamp_;
+
+ // The force of the rubber-band spring. This is equal to the cumulative sum
+ // of all overscroll offsets since entering a non-Inactive state. This is
+ // reset to zero only when entering the Inactive state.
gfx::Vector2dF stretch_scroll_force_;
- gfx::Vector2dF momentum_velocity_;
- // Rubber band state.
- base::Time start_time_;
- gfx::Vector2dF start_stretch_;
- gfx::Vector2dF orig_origin_;
- gfx::Vector2dF orig_velocity_;
+ // Momentum animation state. This state is valid only while the state is
+ // MomentumAnimated, and is initialized in EnterStateMomentumAnimated.
+ base::TimeTicks momentum_animation_start_time_;
+ gfx::Vector2dF momentum_animation_initial_stretch_;
+ gfx::Vector2dF momentum_animation_initial_velocity_;
- bool snap_rubberband_timer_is_active_;
+ // This is set in response to a scroll (most likely programmatic) occuring
+ // while animating the momentum phase. In this case, re-set the initial
+ // velocity, stretch, and start time at the next frame (this is the same
+ // behavior as would happen if the scroll were caused by an active scroll).
+ bool momentum_animation_reset_at_next_frame_;
- DISALLOW_COPY_AND_ASSIGN(ScrollElasticityController);
+ base::WeakPtrFactory<InputScrollElasticityController> weak_factory_;
+ DISALLOW_COPY_AND_ASSIGN(InputScrollElasticityController);
};
} // namespace content
diff --git a/chromium/content/renderer/input/input_scroll_elasticity_controller_unittest.cc b/chromium/content/renderer/input/input_scroll_elasticity_controller_unittest.cc
new file mode 100644
index 00000000000..fa2c7f19bee
--- /dev/null
+++ b/chromium/content/renderer/input/input_scroll_elasticity_controller_unittest.cc
@@ -0,0 +1,387 @@
+// Copyright 2014 The Chromium Authors. 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/input/input_handler.h"
+#include "content/renderer/input/input_scroll_elasticity_controller.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
+
+namespace content {
+namespace {
+
+enum Phase {
+ PhaseNone = blink::WebMouseWheelEvent::PhaseNone,
+ PhaseBegan = blink::WebMouseWheelEvent::PhaseBegan,
+ PhaseStationary = blink::WebMouseWheelEvent::PhaseStationary,
+ PhaseChanged = blink::WebMouseWheelEvent::PhaseChanged,
+ PhaseEnded = blink::WebMouseWheelEvent::PhaseEnded,
+ PhaseCancelled = blink::WebMouseWheelEvent::PhaseCancelled,
+ PhaseMayBegin = blink::WebMouseWheelEvent::PhaseMayBegin,
+};
+
+class MockScrollElasticityHelper : public cc::ScrollElasticityHelper {
+ public:
+ MockScrollElasticityHelper()
+ : is_user_scrollable_(true),
+ set_stretch_amount_count_(0),
+ request_animate_count_(0) {}
+ ~MockScrollElasticityHelper() override {}
+
+ // cc::ScrollElasticityHelper implementation:
+ bool IsUserScrollable() const override { return is_user_scrollable_; }
+ gfx::Vector2dF StretchAmount() const override { return stretch_amount_; }
+ void SetStretchAmount(const gfx::Vector2dF& stretch_amount) override {
+ set_stretch_amount_count_ += 1;
+ stretch_amount_ = stretch_amount;
+ }
+ gfx::ScrollOffset ScrollOffset() const override { return scroll_offset_; }
+ gfx::ScrollOffset MaxScrollOffset() const override {
+ return max_scroll_offset_;
+ }
+ void ScrollBy(const gfx::Vector2dF& delta) override {
+ scroll_offset_ += gfx::ScrollOffset(delta);
+ }
+ void RequestAnimate() override { request_animate_count_ += 1; }
+
+ // Counters for number of times functions were called.
+ int request_animate_count() const { return request_animate_count_; }
+ int set_stretch_amount_count() const { return set_stretch_amount_count_; }
+
+ void SetScrollOffsetAndMaxScrollOffset(
+ const gfx::ScrollOffset& scroll_offset,
+ const gfx::ScrollOffset& max_scroll_offset) {
+ scroll_offset_ = scroll_offset;
+ max_scroll_offset_ = max_scroll_offset;
+ }
+ void SetUserScrollable(bool is_user_scrollable) {
+ is_user_scrollable_ = is_user_scrollable;
+ }
+
+ private:
+ bool is_user_scrollable_;
+ gfx::Vector2dF stretch_amount_;
+ int set_stretch_amount_count_;
+ int request_animate_count_;
+
+ gfx::ScrollOffset scroll_offset_;
+ gfx::ScrollOffset max_scroll_offset_;
+};
+
+class ScrollElasticityControllerTest : public testing::Test {
+ public:
+ ScrollElasticityControllerTest()
+ : controller_(&helper_),
+ input_event_count_(0),
+ current_time_(base::TimeTicks::FromInternalValue(100000000ull)) {}
+ ~ScrollElasticityControllerTest() override {}
+
+ void SendMouseWheelEvent(
+ Phase phase,
+ Phase momentum_phase,
+ const gfx::Vector2dF& event_delta = gfx::Vector2dF(),
+ const gfx::Vector2dF& overscroll_delta = gfx::Vector2dF()) {
+ blink::WebMouseWheelEvent event;
+ event.phase = static_cast<blink::WebMouseWheelEvent::Phase>(phase);
+ event.momentumPhase =
+ static_cast<blink::WebMouseWheelEvent::Phase>(momentum_phase);
+ event.deltaX = -event_delta.x();
+ event.deltaY = -event_delta.y();
+ TickCurrentTime();
+ event.timeStampSeconds = (current_time_ - base::TimeTicks()).InSecondsF();
+
+ cc::InputHandlerScrollResult scroll_result;
+ scroll_result.did_overscroll_root = !overscroll_delta.IsZero();
+ scroll_result.unused_scroll_delta = overscroll_delta;
+
+ controller_.ObserveWheelEventAndResult(event, scroll_result);
+ input_event_count_ += 1;
+ }
+
+ const base::TimeTicks& TickCurrentTime() {
+ current_time_ += base::TimeDelta::FromSecondsD(1 / 60.f);
+ return current_time_;
+ }
+ void TickCurrentTimeAndAnimate() {
+ TickCurrentTime();
+ controller_.Animate(current_time_);
+ }
+
+ MockScrollElasticityHelper helper_;
+ InputScrollElasticityController controller_;
+ int input_event_count_;
+ base::TimeTicks current_time_;
+};
+
+// Verify that stretching only occurs in one axis at a time, and that it
+// is biased to the Y axis.
+TEST_F(ScrollElasticityControllerTest, Axis) {
+ helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(0, 0),
+ gfx::ScrollOffset(0, 0));
+
+ // If we push equally in the X and Y directions, we should see a stretch only
+ // in the Y direction.
+ SendMouseWheelEvent(PhaseBegan, PhaseNone);
+ SendMouseWheelEvent(PhaseChanged, PhaseNone, gfx::Vector2dF(10, 10),
+ gfx::Vector2dF(10, 10));
+ EXPECT_EQ(1, helper_.set_stretch_amount_count());
+ EXPECT_EQ(0.f, helper_.StretchAmount().x());
+ EXPECT_LT(0.f, helper_.StretchAmount().y());
+ helper_.SetStretchAmount(gfx::Vector2dF());
+ EXPECT_EQ(2, helper_.set_stretch_amount_count());
+ SendMouseWheelEvent(PhaseEnded, PhaseNone);
+ EXPECT_EQ(0, helper_.request_animate_count());
+
+ // If we push more in the X direction than the Y direction, we should see a
+ // stretch only in the X direction. This decision should be based on the
+ // input delta, not the actual overscroll delta.
+ SendMouseWheelEvent(PhaseBegan, PhaseNone);
+ SendMouseWheelEvent(PhaseChanged, PhaseNone, gfx::Vector2dF(-25, 10),
+ gfx::Vector2dF(-25, 40));
+ EXPECT_EQ(3, helper_.set_stretch_amount_count());
+ EXPECT_GT(0.f, helper_.StretchAmount().x());
+ EXPECT_EQ(0.f, helper_.StretchAmount().y());
+ helper_.SetStretchAmount(gfx::Vector2dF());
+ EXPECT_EQ(4, helper_.set_stretch_amount_count());
+ SendMouseWheelEvent(PhaseEnded, PhaseNone);
+ EXPECT_EQ(0, helper_.request_animate_count());
+}
+
+// Verify that we need a total overscroll delta of at least 10 in a pinned
+// direction before we start stretching.
+TEST_F(ScrollElasticityControllerTest, MinimumDeltaBeforeStretch) {
+ // We should not start stretching while we are not pinned in the direction
+ // of the scroll (even if there is an overscroll delta). We have to wait for
+ // the regular scroll to eat all of the events.
+ helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(5, 5),
+ gfx::ScrollOffset(10, 10));
+ SendMouseWheelEvent(PhaseMayBegin, PhaseNone);
+ SendMouseWheelEvent(PhaseBegan, PhaseNone);
+ SendMouseWheelEvent(PhaseChanged, PhaseNone, gfx::Vector2dF(0, 10),
+ gfx::Vector2dF(0, 10));
+ SendMouseWheelEvent(PhaseChanged, PhaseNone, gfx::Vector2dF(0, 10),
+ gfx::Vector2dF(0, 10));
+ EXPECT_EQ(0, helper_.set_stretch_amount_count());
+
+ // Now pin the -X and +Y direction. The first event will not generate a
+ // stretch
+ // because it is below the delta threshold of 10.
+ helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(0, 10),
+ gfx::ScrollOffset(10, 10));
+ SendMouseWheelEvent(PhaseChanged, PhaseNone, gfx::Vector2dF(0, 10),
+ gfx::Vector2dF(0, 8));
+ EXPECT_EQ(0, helper_.set_stretch_amount_count());
+
+ // Make the next scroll be in the -X direction more than the +Y direction,
+ // which will erase the memory of the previous unused delta of 8.
+ SendMouseWheelEvent(PhaseChanged, PhaseNone, gfx::Vector2dF(-10, 5),
+ gfx::Vector2dF(-8, 10));
+ EXPECT_EQ(0, helper_.set_stretch_amount_count());
+
+ // Now push against the pinned +Y direction again by 8. We reset the
+ // previous delta, so this will not generate a stretch.
+ SendMouseWheelEvent(PhaseChanged, PhaseNone, gfx::Vector2dF(0, 10),
+ gfx::Vector2dF(0, 8));
+ EXPECT_EQ(0, helper_.set_stretch_amount_count());
+
+ // Push against +Y by another 8. This gets us above the delta threshold of
+ // 10, so we should now have had the stretch set, and it should be in the
+ // +Y direction. The scroll in the -X direction should have been forgotten.
+ SendMouseWheelEvent(PhaseChanged, PhaseNone, gfx::Vector2dF(0, 10),
+ gfx::Vector2dF(0, 8));
+ EXPECT_EQ(1, helper_.set_stretch_amount_count());
+ EXPECT_EQ(0.f, helper_.StretchAmount().x());
+ EXPECT_LT(0.f, helper_.StretchAmount().y());
+
+ // End the gesture. Because there is a non-zero stretch, we should be in the
+ // animated state, and should have had a frame requested.
+ EXPECT_EQ(0, helper_.request_animate_count());
+ SendMouseWheelEvent(PhaseEnded, PhaseNone);
+ EXPECT_EQ(1, helper_.request_animate_count());
+}
+
+// Verify that an stretch caused by a momentum scroll will switch to the
+// animating mode, where input events are ignored, and the stretch is updated
+// while animating.
+TEST_F(ScrollElasticityControllerTest, MomentumAnimate) {
+ // Do an active scroll, then switch to the momentum phase and scroll for a
+ // bit.
+ helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(5, 5),
+ gfx::ScrollOffset(10, 10));
+ SendMouseWheelEvent(PhaseBegan, PhaseNone);
+ SendMouseWheelEvent(PhaseChanged, PhaseNone, gfx::Vector2dF(0, -80),
+ gfx::Vector2dF(0, 0));
+ SendMouseWheelEvent(PhaseChanged, PhaseNone, gfx::Vector2dF(0, -80),
+ gfx::Vector2dF(0, 0));
+ SendMouseWheelEvent(PhaseChanged, PhaseNone, gfx::Vector2dF(0, -80),
+ gfx::Vector2dF(0, 0));
+ SendMouseWheelEvent(PhaseEnded, PhaseNone);
+ SendMouseWheelEvent(PhaseNone, PhaseBegan);
+ SendMouseWheelEvent(PhaseNone, PhaseChanged, gfx::Vector2dF(0, -80),
+ gfx::Vector2dF(0, 0));
+ SendMouseWheelEvent(PhaseNone, PhaseChanged, gfx::Vector2dF(0, -80),
+ gfx::Vector2dF(0, 0));
+ SendMouseWheelEvent(PhaseNone, PhaseChanged, gfx::Vector2dF(0, -80),
+ gfx::Vector2dF(0, 0));
+ EXPECT_EQ(0, helper_.set_stretch_amount_count());
+
+ // Hit the -Y edge and overscroll slightly, but not enough to go over the
+ // threshold to cause a stretch.
+ helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(5, 0),
+ gfx::ScrollOffset(10, 10));
+ SendMouseWheelEvent(PhaseNone, PhaseChanged, gfx::Vector2dF(0, -80),
+ gfx::Vector2dF(0, -8));
+ EXPECT_EQ(0, helper_.set_stretch_amount_count());
+ EXPECT_EQ(0, helper_.request_animate_count());
+
+ // Take another step, this time going over the threshold. This should update
+ // the stretch amount, and then switch to the animating mode.
+ SendMouseWheelEvent(PhaseNone, PhaseChanged, gfx::Vector2dF(0, -80),
+ gfx::Vector2dF(0, -80));
+ EXPECT_EQ(1, helper_.set_stretch_amount_count());
+ EXPECT_EQ(1, helper_.request_animate_count());
+ EXPECT_GT(-1.f, helper_.StretchAmount().y());
+
+ // Subsequent momentum events should do nothing.
+ SendMouseWheelEvent(PhaseNone, PhaseChanged, gfx::Vector2dF(0, -80),
+ gfx::Vector2dF(0, -80));
+ SendMouseWheelEvent(PhaseNone, PhaseChanged, gfx::Vector2dF(0, -80),
+ gfx::Vector2dF(0, -80));
+ SendMouseWheelEvent(PhaseNone, PhaseEnded, gfx::Vector2dF(0, -80),
+ gfx::Vector2dF(0, -80));
+ EXPECT_EQ(1, helper_.set_stretch_amount_count());
+ EXPECT_EQ(1, helper_.request_animate_count());
+
+ // Subsequent animate events should update the stretch amount and request
+ // another frame.
+ TickCurrentTimeAndAnimate();
+ EXPECT_EQ(2, helper_.set_stretch_amount_count());
+ EXPECT_EQ(2, helper_.request_animate_count());
+ EXPECT_GT(-1.f, helper_.StretchAmount().y());
+
+ // Touching the trackpad (a PhaseMayBegin event) should disable animation.
+ SendMouseWheelEvent(PhaseMayBegin, PhaseNone);
+ TickCurrentTimeAndAnimate();
+ EXPECT_EQ(2, helper_.set_stretch_amount_count());
+ EXPECT_EQ(2, helper_.request_animate_count());
+
+ // Releasing the trackpad should re-enable animation.
+ SendMouseWheelEvent(PhaseCancelled, PhaseNone);
+ EXPECT_EQ(2, helper_.set_stretch_amount_count());
+ EXPECT_EQ(3, helper_.request_animate_count());
+ TickCurrentTimeAndAnimate();
+ EXPECT_EQ(3, helper_.set_stretch_amount_count());
+ EXPECT_EQ(4, helper_.request_animate_count());
+
+ // Keep animating frames until the stretch returns to rest.
+ int stretch_count = 3;
+ int animate_count = 4;
+ while (1) {
+ TickCurrentTimeAndAnimate();
+ if (helper_.StretchAmount().IsZero()) {
+ stretch_count += 1;
+ EXPECT_EQ(stretch_count, helper_.set_stretch_amount_count());
+ EXPECT_EQ(animate_count, helper_.request_animate_count());
+ break;
+ }
+ stretch_count += 1;
+ animate_count += 1;
+ EXPECT_EQ(stretch_count, helper_.set_stretch_amount_count());
+ EXPECT_EQ(animate_count, helper_.request_animate_count());
+ }
+
+ // After coming to rest, no subsequent animate calls change anything.
+ TickCurrentTimeAndAnimate();
+ EXPECT_EQ(stretch_count, helper_.set_stretch_amount_count());
+ EXPECT_EQ(animate_count, helper_.request_animate_count());
+}
+
+// Verify that an stretch opposing a scroll is correctly resolved.
+TEST_F(ScrollElasticityControllerTest, ReconcileStretchAndScroll) {
+ SendMouseWheelEvent(PhaseBegan, PhaseNone);
+
+ // Verify completely knocking out the scroll in the -Y direction.
+ helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(5, 5),
+ gfx::ScrollOffset(10, 10));
+ helper_.SetStretchAmount(gfx::Vector2dF(0, -10));
+ controller_.ReconcileStretchAndScroll();
+ EXPECT_EQ(helper_.StretchAmount(), gfx::Vector2dF(0, -5));
+ EXPECT_EQ(helper_.ScrollOffset(), gfx::ScrollOffset(5, 0));
+
+ // Verify partially knocking out the scroll in the -Y direction.
+ helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(5, 8),
+ gfx::ScrollOffset(10, 10));
+ helper_.SetStretchAmount(gfx::Vector2dF(0, -5));
+ controller_.ReconcileStretchAndScroll();
+ EXPECT_EQ(helper_.StretchAmount(), gfx::Vector2dF(0, 0));
+ EXPECT_EQ(helper_.ScrollOffset(), gfx::ScrollOffset(5, 3));
+
+ // Verify completely knocking out the scroll in the +X direction.
+ helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(5, 5),
+ gfx::ScrollOffset(10, 10));
+ helper_.SetStretchAmount(gfx::Vector2dF(10, 0));
+ controller_.ReconcileStretchAndScroll();
+ EXPECT_EQ(helper_.StretchAmount(), gfx::Vector2dF(5, 0));
+ EXPECT_EQ(helper_.ScrollOffset(), gfx::ScrollOffset(10, 5));
+
+ // Verify partially knocking out the scroll in the +X and +Y directions.
+ helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(2, 3),
+ gfx::ScrollOffset(10, 10));
+ helper_.SetStretchAmount(gfx::Vector2dF(5, 5));
+ controller_.ReconcileStretchAndScroll();
+ EXPECT_EQ(helper_.StretchAmount(), gfx::Vector2dF(0, 0));
+ EXPECT_EQ(helper_.ScrollOffset(), gfx::ScrollOffset(7, 8));
+}
+
+// Verify that stretching only happens when the area is user scrollable.
+TEST_F(ScrollElasticityControllerTest, UserScrollableRequiredForStretch) {
+ helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(0, 0),
+ gfx::ScrollOffset(10, 10));
+ gfx::Vector2dF delta(0, -15);
+
+ // Do an active scroll, and ensure that the stretch amount doesn't change,
+ // and also that the stretch amount isn't even ever changed.
+ helper_.SetUserScrollable(false);
+ SendMouseWheelEvent(PhaseBegan, PhaseNone);
+ SendMouseWheelEvent(PhaseChanged, PhaseNone, delta, delta);
+ SendMouseWheelEvent(PhaseChanged, PhaseNone, delta, delta);
+ SendMouseWheelEvent(PhaseEnded, PhaseNone);
+ EXPECT_EQ(helper_.StretchAmount(), gfx::Vector2dF(0, 0));
+ EXPECT_EQ(0, helper_.set_stretch_amount_count());
+ SendMouseWheelEvent(PhaseNone, PhaseBegan);
+ SendMouseWheelEvent(PhaseNone, PhaseChanged, delta, delta);
+ SendMouseWheelEvent(PhaseNone, PhaseChanged, delta, delta);
+ SendMouseWheelEvent(PhaseNone, PhaseEnded);
+ EXPECT_EQ(helper_.StretchAmount(), gfx::Vector2dF(0, 0));
+ EXPECT_EQ(0, helper_.set_stretch_amount_count());
+
+ // Re-enable user scrolling and ensure that stretching is re-enabled.
+ helper_.SetUserScrollable(true);
+ SendMouseWheelEvent(PhaseBegan, PhaseNone);
+ SendMouseWheelEvent(PhaseChanged, PhaseNone, delta, delta);
+ SendMouseWheelEvent(PhaseChanged, PhaseNone, delta, delta);
+ SendMouseWheelEvent(PhaseEnded, PhaseNone);
+ EXPECT_NE(helper_.StretchAmount(), gfx::Vector2dF(0, 0));
+ EXPECT_GT(helper_.set_stretch_amount_count(), 0);
+ SendMouseWheelEvent(PhaseNone, PhaseBegan);
+ SendMouseWheelEvent(PhaseNone, PhaseChanged, delta, delta);
+ SendMouseWheelEvent(PhaseNone, PhaseChanged, delta, delta);
+ SendMouseWheelEvent(PhaseNone, PhaseEnded);
+ EXPECT_NE(helper_.StretchAmount(), gfx::Vector2dF(0, 0));
+ EXPECT_GT(helper_.set_stretch_amount_count(), 0);
+
+ // Disable user scrolling and tick the timer until the stretch goes back
+ // to zero. Ensure that the return to zero doesn't happen immediately.
+ helper_.SetUserScrollable(false);
+ int ticks_to_zero = 0;
+ while (1) {
+ TickCurrentTimeAndAnimate();
+ if (helper_.StretchAmount().IsZero())
+ break;
+ ticks_to_zero += 1;
+ }
+ EXPECT_GT(ticks_to_zero, 3);
+}
+
+} // namespace
+} // namespace content
diff --git a/chromium/content/renderer/input/main_thread_input_event_filter.cc b/chromium/content/renderer/input/main_thread_input_event_filter.cc
new file mode 100644
index 00000000000..cd6c2eaccdb
--- /dev/null
+++ b/chromium/content/renderer/input/main_thread_input_event_filter.cc
@@ -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.
+
+#include "content/renderer/input/main_thread_input_event_filter.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "content/common/input_messages.h"
+#include "ipc/ipc_listener.h"
+
+namespace content {
+
+MainThreadInputEventFilter::MainThreadInputEventFilter(
+ const base::Callback<void(const IPC::Message&)>& main_listener,
+ const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner)
+ : main_listener_(main_listener), main_task_runner_(main_task_runner) {
+ DCHECK(main_task_runner.get());
+}
+
+bool MainThreadInputEventFilter::OnMessageReceived(
+ const IPC::Message& message) {
+ DCHECK_EQ(static_cast<int>(IPC_MESSAGE_ID_CLASS(message.type())),
+ InputMsgStart);
+ bool handled = main_task_runner_->PostTask(
+ FROM_HERE, base::Bind(main_listener_, message));
+ return handled;
+}
+
+bool MainThreadInputEventFilter::GetSupportedMessageClasses(
+ std::vector<uint32>* supported_message_classes) const {
+ supported_message_classes->push_back(InputMsgStart);
+ return true;
+}
+
+MainThreadInputEventFilter::~MainThreadInputEventFilter() {
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/input/main_thread_input_event_filter.h b/chromium/content/renderer/input/main_thread_input_event_filter.h
new file mode 100644
index 00000000000..f540a9cde4d
--- /dev/null
+++ b/chromium/content/renderer/input/main_thread_input_event_filter.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_RENDERER_INPUT_MAIN_THREAD_INPUT_EVENT_FILTER_H_
+#define CONTENT_RENDERER_INPUT_MAIN_THREAD_INPUT_EVENT_FILTER_H_
+
+#include "base/callback.h"
+#include "ipc/message_filter.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+}
+
+namespace IPC {
+class Listener;
+}
+
+namespace content {
+
+// Used to intercept InputMsg* messages and deliver them to the given listener
+// via the provided main thread task runner. Note that usage should be
+// restricted to cases where compositor-thread event filtering (via
+// |InputEventFilter|) is disabled or otherwise unavailable.
+class MainThreadInputEventFilter : public IPC::MessageFilter {
+ public:
+ MainThreadInputEventFilter(
+ const base::Callback<void(const IPC::Message&)>& main_listener,
+ const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner);
+
+ // IPC::MessageFilter implementation.
+ bool OnMessageReceived(const IPC::Message& message) override;
+ bool GetSupportedMessageClasses(
+ std::vector<uint32>* supported_message_classes) const override;
+
+ private:
+ ~MainThreadInputEventFilter() override;
+
+ base::Callback<void(const IPC::Message&)> main_listener_;
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_INPUT_MAIN_THREAD_INPUT_EVENT_FILTER_H_
diff --git a/chromium/content/renderer/java/gin_java_bridge_dispatcher.cc b/chromium/content/renderer/java/gin_java_bridge_dispatcher.cc
index 400d58f3dea..820c6ce3437 100644
--- a/chromium/content/renderer/java/gin_java_bridge_dispatcher.cc
+++ b/chromium/content/renderer/java/gin_java_bridge_dispatcher.cc
@@ -4,6 +4,7 @@
#include "content/renderer/java/gin_java_bridge_dispatcher.h"
+#include "base/auto_reset.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "content/common/gin_java_bridge_messages.h"
@@ -32,32 +33,12 @@ bool GinJavaBridgeDispatcher::OnMessageReceived(const IPC::Message& msg) {
return handled;
}
-namespace {
-
-class ScopedFlag {
- public:
- ScopedFlag(bool* flag) : flag_(flag) {
- DCHECK(!*flag_);
- *flag_ = true;
- }
- ~ScopedFlag() {
- DCHECK(*flag_);
- *flag_ = false;
- }
- private:
- bool* flag_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedFlag);
-};
-
-} // namespace
-
void GinJavaBridgeDispatcher::DidClearWindowObject() {
// Accessing window object when adding properties to it may trigger
// a nested call to DidClearWindowObject.
if (inside_did_clear_window_object_)
return;
- ScopedFlag flag(&inside_did_clear_window_object_);
+ base::AutoReset<bool> flag_entry(&inside_did_clear_window_object_, true);
for (NamedObjectMap::const_iterator iter = named_objects_.begin();
iter != named_objects_.end(); ++iter) {
// Always create a new GinJavaBridgeObject, so we don't pull any of the V8
@@ -142,9 +123,11 @@ GinJavaBridgeObject* GinJavaBridgeDispatcher::GetObject(ObjectID object_id) {
return result;
}
-void GinJavaBridgeDispatcher::OnGinJavaBridgeObjectDeleted(ObjectID object_id) {
- if (!objects_.Lookup(object_id))
- return;
+void GinJavaBridgeDispatcher::OnGinJavaBridgeObjectDeleted(
+ GinJavaBridgeObject* object) {
+ int object_id = object->object_id();
+ // Ignore cleaning up of old object wrappers.
+ if (objects_.Lookup(object_id) != object) return;
objects_.Remove(object_id);
render_frame()->Send(
new GinJavaBridgeHostMsg_ObjectWrapperDeleted(routing_id(), object_id));
diff --git a/chromium/content/renderer/java/gin_java_bridge_dispatcher.h b/chromium/content/renderer/java/gin_java_bridge_dispatcher.h
index f9d5f5449ad..877e46f3021 100644
--- a/chromium/content/renderer/java/gin_java_bridge_dispatcher.h
+++ b/chromium/content/renderer/java/gin_java_bridge_dispatcher.h
@@ -41,11 +41,11 @@ class GinJavaBridgeDispatcher
typedef ObjectMap::KeyType ObjectID;
explicit GinJavaBridgeDispatcher(RenderFrame* render_frame);
- virtual ~GinJavaBridgeDispatcher();
+ ~GinJavaBridgeDispatcher() override;
// RenderFrameObserver override:
- virtual bool OnMessageReceived(const IPC::Message& message) override;
- virtual void DidClearWindowObject() override;
+ bool OnMessageReceived(const IPC::Message& message) override;
+ void DidClearWindowObject() override;
void GetJavaMethods(ObjectID object_id, std::set<std::string>* methods);
bool HasJavaMethod(ObjectID object_id, const std::string& method_name);
@@ -54,7 +54,7 @@ class GinJavaBridgeDispatcher
const base::ListValue& arguments,
GinJavaBridgeError* error);
GinJavaBridgeObject* GetObject(ObjectID object_id);
- void OnGinJavaBridgeObjectDeleted(ObjectID object_id);
+ void OnGinJavaBridgeObjectDeleted(GinJavaBridgeObject* object);
private:
void OnAddNamedObject(const std::string& name,
diff --git a/chromium/content/renderer/java/gin_java_bridge_object.cc b/chromium/content/renderer/java/gin_java_bridge_object.cc
index b4cf3bf669b..00e9aec45da 100644
--- a/chromium/content/renderer/java/gin_java_bridge_object.cc
+++ b/chromium/content/renderer/java/gin_java_bridge_object.cc
@@ -4,25 +4,13 @@
#include "content/renderer/java/gin_java_bridge_object.h"
-#include "base/strings/utf_string_conversions.h"
-#include "content/common/android/gin_java_bridge_errors.h"
-#include "content/common/android/gin_java_bridge_value.h"
-#include "content/public/renderer/v8_value_converter.h"
-#include "content/renderer/java/gin_java_bridge_value_converter.h"
+#include "content/renderer/java/gin_java_function_invocation_helper.h"
#include "gin/function_template.h"
#include "third_party/WebKit/public/web/WebFrame.h"
#include "third_party/WebKit/public/web/WebKit.h"
namespace content {
-namespace {
-
-const char kMethodInvocationErrorMessage[] =
- "Java bridge method invocation error";
-
-} // namespace
-
-
// static
GinJavaBridgeObject* GinJavaBridgeObject::InjectNamed(
blink::WebFrame* frame,
@@ -31,7 +19,7 @@ GinJavaBridgeObject* GinJavaBridgeObject::InjectNamed(
GinJavaBridgeDispatcher::ObjectID object_id) {
v8::Isolate* isolate = blink::mainThreadIsolate();
v8::HandleScope handle_scope(isolate);
- v8::Handle<v8::Context> context = frame->mainWorldScriptContext();
+ v8::Local<v8::Context> context = frame->mainWorldScriptContext();
if (context.IsEmpty())
return NULL;
@@ -39,7 +27,7 @@ GinJavaBridgeObject* GinJavaBridgeObject::InjectNamed(
new GinJavaBridgeObject(isolate, dispatcher, object_id);
v8::Context::Scope context_scope(context);
- v8::Handle<v8::Object> global = context->Global();
+ v8::Local<v8::Object> global = context->Global();
gin::Handle<GinJavaBridgeObject> controller =
gin::CreateHandle(isolate, object);
// WrappableBase instance deletes itself in case of a wrapper
@@ -66,12 +54,12 @@ GinJavaBridgeObject::GinJavaBridgeObject(
: gin::NamedPropertyInterceptor(isolate, this),
dispatcher_(dispatcher),
object_id_(object_id),
- converter_(new GinJavaBridgeValueConverter()) {
+ template_cache_(isolate) {
}
GinJavaBridgeObject::~GinJavaBridgeObject() {
if (dispatcher_)
- dispatcher_->OnGinJavaBridgeObjectDeleted(object_id_);
+ dispatcher_->OnGinJavaBridgeObjectDeleted(this);
}
gin::ObjectTemplateBuilder GinJavaBridgeObject::GetObjectTemplateBuilder(
@@ -91,15 +79,10 @@ v8::Local<v8::Value> GinJavaBridgeObject::GetNamedProperty(
}
known_methods_[property] = dispatcher_->HasJavaMethod(object_id_, property);
}
- if (known_methods_[property]) {
- return gin::CreateFunctionTemplate(
- isolate,
- base::Bind(&GinJavaBridgeObject::InvokeMethod,
- base::Unretained(this),
- property))->GetFunction();
- } else {
+ if (known_methods_[property])
+ return GetFunctionTemplate(isolate, property)->GetFunction();
+ else
return v8::Local<v8::Value>();
- }
}
std::vector<std::string> GinJavaBridgeObject::EnumerateNamedProperties(
@@ -110,64 +93,18 @@ std::vector<std::string> GinJavaBridgeObject::EnumerateNamedProperties(
return std::vector<std::string> (method_names.begin(), method_names.end());
}
-v8::Handle<v8::Value> GinJavaBridgeObject::InvokeMethod(
- const std::string& name,
- gin::Arguments* args) {
- if (!dispatcher_) {
- args->isolate()->ThrowException(v8::Exception::Error(gin::StringToV8(
- args->isolate(), kMethodInvocationErrorMessage)));
- return v8::Undefined(args->isolate());
- }
-
- base::ListValue arguments;
- {
- v8::HandleScope handle_scope(args->isolate());
- v8::Handle<v8::Context> context = args->isolate()->GetCurrentContext();
- v8::Handle<v8::Value> val;
- while (args->GetNext(&val)) {
- scoped_ptr<base::Value> arg(converter_->FromV8Value(val, context));
- if (arg.get()) {
- arguments.Append(arg.release());
- } else {
- arguments.Append(base::Value::CreateNullValue());
- }
- }
- }
-
- GinJavaBridgeError error;
- scoped_ptr<base::Value> result = dispatcher_->InvokeJavaMethod(
- object_id_, name, arguments, &error);
- if (!result.get()) {
- args->isolate()->ThrowException(v8::Exception::Error(gin::StringToV8(
- args->isolate(), GinJavaBridgeErrorToString(error))));
- return v8::Undefined(args->isolate());
- }
- if (!result->IsType(base::Value::TYPE_BINARY)) {
- return converter_->ToV8Value(result.get(),
- args->isolate()->GetCurrentContext());
- }
-
- scoped_ptr<const GinJavaBridgeValue> gin_value =
- GinJavaBridgeValue::FromValue(result.get());
- if (gin_value->IsType(GinJavaBridgeValue::TYPE_OBJECT_ID)) {
- GinJavaBridgeObject* result = NULL;
- GinJavaBridgeDispatcher::ObjectID object_id;
- if (gin_value->GetAsObjectID(&object_id)) {
- result = dispatcher_->GetObject(object_id);
- }
- if (result) {
- gin::Handle<GinJavaBridgeObject> controller =
- gin::CreateHandle(args->isolate(), result);
- if (controller.IsEmpty())
- return v8::Undefined(args->isolate());
- return controller.ToV8();
- }
- } else if (gin_value->IsType(GinJavaBridgeValue::TYPE_NONFINITE)) {
- float float_value;
- gin_value->GetAsNonFinite(&float_value);
- return v8::Number::New(args->isolate(), float_value);
- }
- return v8::Undefined(args->isolate());
+v8::Local<v8::FunctionTemplate> GinJavaBridgeObject::GetFunctionTemplate(
+ v8::Isolate* isolate,
+ const std::string& name) {
+ v8::Local<v8::FunctionTemplate> function_template = template_cache_.Get(name);
+ if (!function_template.IsEmpty())
+ return function_template;
+ function_template = gin::CreateFunctionTemplate(
+ isolate, base::Bind(&GinJavaFunctionInvocationHelper::Invoke,
+ base::Owned(new GinJavaFunctionInvocationHelper(
+ name, dispatcher_))));
+ template_cache_.Set(name, function_template);
+ return function_template;
}
gin::WrapperInfo GinJavaBridgeObject::kWrapperInfo = {gin::kEmbedderNativeGin};
diff --git a/chromium/content/renderer/java/gin_java_bridge_object.h b/chromium/content/renderer/java/gin_java_bridge_object.h
index f3a4c7b18f4..a498e14b788 100644
--- a/chromium/content/renderer/java/gin_java_bridge_object.h
+++ b/chromium/content/renderer/java/gin_java_bridge_object.h
@@ -7,13 +7,13 @@
#include <map>
-#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "content/renderer/java/gin_java_bridge_dispatcher.h"
#include "gin/handle.h"
#include "gin/interceptor.h"
#include "gin/object_template_builder.h"
#include "gin/wrappable.h"
+#include "v8/include/v8-util.h"
namespace blink {
class WebFrame;
@@ -21,8 +21,6 @@ class WebFrame;
namespace content {
-class GinJavaBridgeValueConverter;
-
class GinJavaBridgeObject : public gin::Wrappable<GinJavaBridgeObject>,
public gin::NamedPropertyInterceptor {
public:
@@ -31,13 +29,13 @@ class GinJavaBridgeObject : public gin::Wrappable<GinJavaBridgeObject>,
GinJavaBridgeDispatcher::ObjectID object_id() const { return object_id_; }
// gin::Wrappable.
- virtual gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
+ gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;
// gin::NamedPropertyInterceptor
- virtual v8::Local<v8::Value> GetNamedProperty(
- v8::Isolate* isolate, const std::string& property) override;
- virtual std::vector<std::string> EnumerateNamedProperties(
+ v8::Local<v8::Value> GetNamedProperty(v8::Isolate* isolate,
+ const std::string& property) override;
+ std::vector<std::string> EnumerateNamedProperties(
v8::Isolate* isolate) override;
static GinJavaBridgeObject* InjectNamed(
@@ -53,15 +51,15 @@ class GinJavaBridgeObject : public gin::Wrappable<GinJavaBridgeObject>,
GinJavaBridgeObject(v8::Isolate* isolate,
const base::WeakPtr<GinJavaBridgeDispatcher>& dispatcher,
GinJavaBridgeDispatcher::ObjectID object_id);
- virtual ~GinJavaBridgeObject();
+ ~GinJavaBridgeObject() override;
- v8::Handle<v8::Value> InvokeMethod(const std::string& name,
- gin::Arguments* args);
+ v8::Local<v8::FunctionTemplate> GetFunctionTemplate(v8::Isolate* isolate,
+ const std::string& name);
base::WeakPtr<GinJavaBridgeDispatcher> dispatcher_;
GinJavaBridgeDispatcher::ObjectID object_id_;
- scoped_ptr<GinJavaBridgeValueConverter> converter_;
std::map<std::string, bool> known_methods_;
+ v8::StdGlobalValueMap<std::string, v8::FunctionTemplate> template_cache_;
DISALLOW_COPY_AND_ASSIGN(GinJavaBridgeObject);
};
diff --git a/chromium/content/renderer/java/gin_java_bridge_value_converter.cc b/chromium/content/renderer/java/gin_java_bridge_value_converter.cc
index c1727a42bb5..2fdf658bcfc 100644
--- a/chromium/content/renderer/java/gin_java_bridge_value_converter.cc
+++ b/chromium/content/renderer/java/gin_java_bridge_value_converter.cc
@@ -4,7 +4,8 @@
#include "content/renderer/java/gin_java_bridge_value_converter.h"
-#include "base/float_util.h"
+#include <cmath>
+
#include "base/values.h"
#include "content/common/android/gin_java_bridge_value.h"
#include "content/renderer/java/gin_java_bridge_object.h"
@@ -23,20 +24,20 @@ GinJavaBridgeValueConverter::GinJavaBridgeValueConverter()
GinJavaBridgeValueConverter::~GinJavaBridgeValueConverter() {
}
-v8::Handle<v8::Value> GinJavaBridgeValueConverter::ToV8Value(
+v8::Local<v8::Value> GinJavaBridgeValueConverter::ToV8Value(
const base::Value* value,
- v8::Handle<v8::Context> context) const {
+ v8::Local<v8::Context> context) const {
return converter_->ToV8Value(value, context);
}
scoped_ptr<base::Value> GinJavaBridgeValueConverter::FromV8Value(
- v8::Handle<v8::Value> value,
- v8::Handle<v8::Context> context) const {
+ v8::Local<v8::Value> value,
+ v8::Local<v8::Context> context) const {
return make_scoped_ptr(converter_->FromV8Value(value, context));
}
bool GinJavaBridgeValueConverter::FromV8Object(
- v8::Handle<v8::Object> value,
+ v8::Local<v8::Object> value,
base::Value** out,
v8::Isolate* isolate,
const FromV8ValueCallback& callback) const {
@@ -55,7 +56,7 @@ class TypedArraySerializer {
public:
virtual ~TypedArraySerializer() {}
static scoped_ptr<TypedArraySerializer> Create(
- v8::Handle<v8::TypedArray> typed_array);
+ v8::Local<v8::TypedArray> typed_array);
virtual void serializeTo(char* data,
size_t data_length,
base::ListValue* out) = 0;
@@ -67,12 +68,12 @@ template <typename ElementType, typename ListType>
class TypedArraySerializerImpl : public TypedArraySerializer {
public:
static scoped_ptr<TypedArraySerializer> Create(
- v8::Handle<v8::TypedArray> typed_array) {
+ v8::Local<v8::TypedArray> typed_array) {
return make_scoped_ptr(
new TypedArraySerializerImpl<ElementType, ListType>(typed_array));
}
- virtual void serializeTo(char* data,
+ void serializeTo(char* data,
size_t data_length,
base::ListValue* out) override {
DCHECK_EQ(data_length, typed_array_->Length() * sizeof(ElementType));
@@ -86,17 +87,17 @@ class TypedArraySerializerImpl : public TypedArraySerializer {
}
private:
- explicit TypedArraySerializerImpl(v8::Handle<v8::TypedArray> typed_array)
+ explicit TypedArraySerializerImpl(v8::Local<v8::TypedArray> typed_array)
: typed_array_(typed_array) {}
- v8::Handle<v8::TypedArray> typed_array_;
+ v8::Local<v8::TypedArray> typed_array_;
DISALLOW_COPY_AND_ASSIGN(TypedArraySerializerImpl);
};
// static
scoped_ptr<TypedArraySerializer> TypedArraySerializer::Create(
- v8::Handle<v8::TypedArray> typed_array) {
+ v8::Local<v8::TypedArray> typed_array) {
if (typed_array->IsInt8Array() ||
typed_array->IsUint8Array() ||
typed_array->IsUint8ClampedArray()) {
@@ -117,7 +118,7 @@ scoped_ptr<TypedArraySerializer> TypedArraySerializer::Create(
} // namespace
bool GinJavaBridgeValueConverter::FromV8ArrayBuffer(
- v8::Handle<v8::Object> value,
+ v8::Local<v8::Object> value,
base::Value** out,
v8::Isolate* isolate) const {
if (!value->IsTypedArray()) {
@@ -145,10 +146,10 @@ bool GinJavaBridgeValueConverter::FromV8ArrayBuffer(
return true;
}
-bool GinJavaBridgeValueConverter::FromV8Number(v8::Handle<v8::Number> value,
+bool GinJavaBridgeValueConverter::FromV8Number(v8::Local<v8::Number> value,
base::Value** out) const {
double double_value = value->Value();
- if (base::IsFinite(double_value))
+ if (std::isfinite(double_value))
return false;
*out = GinJavaBridgeValue::CreateNonFiniteValue(double_value).release();
return true;
diff --git a/chromium/content/renderer/java/gin_java_bridge_value_converter.h b/chromium/content/renderer/java/gin_java_bridge_value_converter.h
index fd343b9fdd5..33e3af53dfc 100644
--- a/chromium/content/renderer/java/gin_java_bridge_value_converter.h
+++ b/chromium/content/renderer/java/gin_java_bridge_value_converter.h
@@ -7,33 +7,33 @@
#include "base/memory/scoped_ptr.h"
#include "content/common/content_export.h"
-#include "content/public/renderer/v8_value_converter.h"
+#include "content/public/child/v8_value_converter.h"
namespace content {
class GinJavaBridgeValueConverter : public content::V8ValueConverter::Strategy {
public:
CONTENT_EXPORT GinJavaBridgeValueConverter();
- CONTENT_EXPORT virtual ~GinJavaBridgeValueConverter();
+ CONTENT_EXPORT ~GinJavaBridgeValueConverter() override;
- CONTENT_EXPORT v8::Handle<v8::Value> ToV8Value(
+ CONTENT_EXPORT v8::Local<v8::Value> ToV8Value(
const base::Value* value,
- v8::Handle<v8::Context> context) const;
+ v8::Local<v8::Context> context) const;
CONTENT_EXPORT scoped_ptr<base::Value> FromV8Value(
- v8::Handle<v8::Value> value,
- v8::Handle<v8::Context> context) const;
+ v8::Local<v8::Value> value,
+ v8::Local<v8::Context> context) const;
// content::V8ValueConverter::Strategy
- virtual bool FromV8Object(v8::Handle<v8::Object> value,
- base::Value** out,
- v8::Isolate* isolate,
- const FromV8ValueCallback& callback) const override;
- virtual bool FromV8ArrayBuffer(v8::Handle<v8::Object> value,
- base::Value** out,
- v8::Isolate* isolate) const override;
- virtual bool FromV8Number(v8::Handle<v8::Number> value,
- base::Value** out) const override;
- virtual bool FromV8Undefined(base::Value** out) const override;
+ bool FromV8Object(v8::Local<v8::Object> value,
+ base::Value** out,
+ v8::Isolate* isolate,
+ const FromV8ValueCallback& callback) const override;
+ bool FromV8ArrayBuffer(v8::Local<v8::Object> value,
+ base::Value** out,
+ v8::Isolate* isolate) const override;
+ bool FromV8Number(v8::Local<v8::Number> value,
+ base::Value** out) const override;
+ bool FromV8Undefined(base::Value** out) const override;
private:
scoped_ptr<V8ValueConverter> converter_;
diff --git a/chromium/content/renderer/java/gin_java_bridge_value_converter_unittest.cc b/chromium/content/renderer/java/gin_java_bridge_value_converter_unittest.cc
index 1a0812b0d98..056aaebc6a2 100644
--- a/chromium/content/renderer/java/gin_java_bridge_value_converter_unittest.cc
+++ b/chromium/content/renderer/java/gin_java_bridge_value_converter_unittest.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 <cmath>
+
#include "base/basictypes.h"
-#include "base/float_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/stringprintf.h"
#include "content/common/android/gin_java_bridge_value.h"
@@ -20,15 +21,13 @@ class GinJavaBridgeValueConverterTest : public testing::Test {
}
protected:
- virtual void SetUp() {
+ void SetUp() override {
v8::HandleScope handle_scope(isolate_);
- v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate_);
+ v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate_);
context_.Reset(isolate_, v8::Context::New(isolate_, NULL, global));
}
- virtual void TearDown() {
- context_.Reset();
- }
+ void TearDown() override { context_.Reset(); }
v8::Isolate* isolate_;
@@ -45,7 +44,7 @@ TEST_F(GinJavaBridgeValueConverterTest, BasicValues) {
scoped_ptr<GinJavaBridgeValueConverter> converter(
new GinJavaBridgeValueConverter());
- v8::Handle<v8::Primitive> v8_undefined(v8::Undefined(isolate_));
+ v8::Local<v8::Primitive> v8_undefined(v8::Undefined(isolate_));
scoped_ptr<base::Value> undefined(
converter->FromV8Value(v8_undefined, context));
ASSERT_TRUE(undefined.get());
@@ -55,7 +54,7 @@ TEST_F(GinJavaBridgeValueConverterTest, BasicValues) {
ASSERT_TRUE(undefined_value.get());
EXPECT_TRUE(undefined_value->IsType(GinJavaBridgeValue::TYPE_UNDEFINED));
- v8::Handle<v8::Number> v8_infinity(
+ v8::Local<v8::Number> v8_infinity(
v8::Number::New(isolate_, std::numeric_limits<double>::infinity()));
scoped_ptr<base::Value> infinity(
converter->FromV8Value(v8_infinity, context));
@@ -69,8 +68,7 @@ TEST_F(GinJavaBridgeValueConverterTest, BasicValues) {
EXPECT_TRUE(
infinity_value->IsType(GinJavaBridgeValue::TYPE_NONFINITE));
EXPECT_TRUE(infinity_value->GetAsNonFinite(&native_float));
- EXPECT_FALSE(base::IsFinite(native_float));
- EXPECT_FALSE(base::IsNaN(native_float));
+ EXPECT_TRUE(std::isinf(native_float));
}
TEST_F(GinJavaBridgeValueConverterTest, ArrayBuffer) {
@@ -82,7 +80,7 @@ TEST_F(GinJavaBridgeValueConverterTest, ArrayBuffer) {
scoped_ptr<GinJavaBridgeValueConverter> converter(
new GinJavaBridgeValueConverter());
- v8::Handle<v8::ArrayBuffer> v8_array_buffer(
+ v8::Local<v8::ArrayBuffer> v8_array_buffer(
v8::ArrayBuffer::New(isolate_, 0));
scoped_ptr<base::Value> undefined(
converter->FromV8Value(v8_array_buffer, context));
@@ -117,11 +115,11 @@ TEST_F(GinJavaBridgeValueConverterTest, TypedArrays) {
};
for (size_t i = 0; i < arraysize(array_types); i += 2) {
const char* typed_array_type = array_types[i + 1];
- v8::Handle<v8::Script> script(v8::Script::Compile(v8::String::NewFromUtf8(
+ v8::Local<v8::Script> script(v8::Script::Compile(v8::String::NewFromUtf8(
isolate_,
base::StringPrintf(
source_template, array_types[i], typed_array_type).c_str())));
- v8::Handle<v8::Value> v8_typed_array = script->Run();
+ v8::Local<v8::Value> v8_typed_array = script->Run();
scoped_ptr<base::Value> list_value(
converter->FromV8Value(v8_typed_array, context));
ASSERT_TRUE(list_value.get()) << typed_array_type;
diff --git a/chromium/content/renderer/java/gin_java_function_invocation_helper.cc b/chromium/content/renderer/java/gin_java_function_invocation_helper.cc
new file mode 100644
index 00000000000..428a954fdd7
--- /dev/null
+++ b/chromium/content/renderer/java/gin_java_function_invocation_helper.cc
@@ -0,0 +1,109 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/java/gin_java_function_invocation_helper.h"
+
+#include "content/common/android/gin_java_bridge_errors.h"
+#include "content/common/android/gin_java_bridge_value.h"
+#include "content/public/child/v8_value_converter.h"
+#include "content/renderer/java/gin_java_bridge_object.h"
+#include "content/renderer/java/gin_java_bridge_value_converter.h"
+
+namespace content {
+
+namespace {
+
+const char kMethodInvocationAsConstructorDisallowed[] =
+ "Java bridge method can't be invoked as a constructor";
+const char kMethodInvocationOnNonInjectedObjectDisallowed[] =
+ "Java bridge method can't be invoked on a non-injected object";
+const char kMethodInvocationErrorMessage[] =
+ "Java bridge method invocation error";
+
+} // namespace
+
+GinJavaFunctionInvocationHelper::GinJavaFunctionInvocationHelper(
+ const std::string& method_name,
+ const base::WeakPtr<GinJavaBridgeDispatcher>& dispatcher)
+ : method_name_(method_name),
+ dispatcher_(dispatcher),
+ converter_(new GinJavaBridgeValueConverter()) {
+}
+
+GinJavaFunctionInvocationHelper::~GinJavaFunctionInvocationHelper() {
+}
+
+v8::Local<v8::Value> GinJavaFunctionInvocationHelper::Invoke(
+ gin::Arguments* args) {
+ if (!dispatcher_) {
+ args->isolate()->ThrowException(v8::Exception::Error(gin::StringToV8(
+ args->isolate(), kMethodInvocationErrorMessage)));
+ return v8::Undefined(args->isolate());
+ }
+
+ if (args->IsConstructCall()) {
+ args->isolate()->ThrowException(v8::Exception::Error(gin::StringToV8(
+ args->isolate(), kMethodInvocationAsConstructorDisallowed)));
+ return v8::Undefined(args->isolate());
+ }
+
+ content::GinJavaBridgeObject* object = NULL;
+ if (!args->GetHolder(&object) || !object) {
+ args->isolate()->ThrowException(v8::Exception::Error(gin::StringToV8(
+ args->isolate(), kMethodInvocationOnNonInjectedObjectDisallowed)));
+ return v8::Undefined(args->isolate());
+ }
+
+ base::ListValue arguments;
+ {
+ v8::HandleScope handle_scope(args->isolate());
+ v8::Local<v8::Context> context = args->isolate()->GetCurrentContext();
+ v8::Local<v8::Value> val;
+ while (args->GetNext(&val)) {
+ scoped_ptr<base::Value> arg(converter_->FromV8Value(val, context));
+ if (arg.get()) {
+ arguments.Append(arg.release());
+ } else {
+ arguments.Append(base::Value::CreateNullValue());
+ }
+ }
+ }
+
+ GinJavaBridgeError error;
+ scoped_ptr<base::Value> result = dispatcher_->InvokeJavaMethod(
+ object->object_id(), method_name_, arguments, &error);
+ if (!result.get()) {
+ args->isolate()->ThrowException(v8::Exception::Error(gin::StringToV8(
+ args->isolate(), GinJavaBridgeErrorToString(error))));
+ return v8::Undefined(args->isolate());
+ }
+ if (!result->IsType(base::Value::TYPE_BINARY)) {
+ return converter_->ToV8Value(result.get(),
+ args->isolate()->GetCurrentContext());
+ }
+
+ scoped_ptr<const GinJavaBridgeValue> gin_value =
+ GinJavaBridgeValue::FromValue(result.get());
+ if (gin_value->IsType(GinJavaBridgeValue::TYPE_OBJECT_ID)) {
+ GinJavaBridgeObject* result = NULL;
+ GinJavaBridgeDispatcher::ObjectID object_id;
+ if (gin_value->GetAsObjectID(&object_id)) {
+ result = dispatcher_->GetObject(object_id);
+ }
+ if (result) {
+ gin::Handle<GinJavaBridgeObject> controller =
+ gin::CreateHandle(args->isolate(), result);
+ if (controller.IsEmpty())
+ return v8::Undefined(args->isolate());
+ return controller.ToV8();
+ }
+ } else if (gin_value->IsType(GinJavaBridgeValue::TYPE_NONFINITE)) {
+ float float_value;
+ gin_value->GetAsNonFinite(&float_value);
+ return v8::Number::New(args->isolate(), float_value);
+ }
+ return v8::Undefined(args->isolate());
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/java/gin_java_function_invocation_helper.h b/chromium/content/renderer/java/gin_java_function_invocation_helper.h
new file mode 100644
index 00000000000..286082019cc
--- /dev/null
+++ b/chromium/content/renderer/java/gin_java_function_invocation_helper.h
@@ -0,0 +1,37 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_JAVA_GIN_JAVA_FUNCTION_INVOCATION_HELPER_H_
+#define CONTENT_RENDERER_JAVA_GIN_JAVA_FUNCTION_INVOCATION_HELPER_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "content/renderer/java/gin_java_bridge_dispatcher.h"
+#include "gin/arguments.h"
+#include "gin/handle.h"
+
+namespace content {
+
+class GinJavaBridgeValueConverter;
+
+class GinJavaFunctionInvocationHelper {
+ public:
+ GinJavaFunctionInvocationHelper(
+ const std::string& method_name,
+ const base::WeakPtr<GinJavaBridgeDispatcher>& dispatcher);
+ ~GinJavaFunctionInvocationHelper();
+
+ v8::Local<v8::Value> Invoke(gin::Arguments* args);
+
+ private:
+ std::string method_name_;
+ base::WeakPtr<GinJavaBridgeDispatcher> dispatcher_;
+ scoped_ptr<GinJavaBridgeValueConverter> converter_;
+
+ DISALLOW_COPY_AND_ASSIGN(GinJavaFunctionInvocationHelper);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_JAVA_GIN_JAVA_FUNCTION_INVOCATION_HELPER_H_
diff --git a/chromium/content/renderer/manifest/manifest_manager.cc b/chromium/content/renderer/manifest/manifest_manager.cc
index 9ccee4cb388..52667ba373b 100644
--- a/chromium/content/renderer/manifest/manifest_manager.cc
+++ b/chromium/content/renderer/manifest/manifest_manager.cc
@@ -12,6 +12,7 @@
#include "content/renderer/manifest/manifest_parser.h"
#include "content/renderer/manifest/manifest_uma_util.h"
#include "third_party/WebKit/public/platform/WebURLResponse.h"
+#include "third_party/WebKit/public/web/WebConsoleMessage.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
@@ -60,16 +61,21 @@ void ManifestManager::OnRequestManifestComplete(
ipc_manifest.short_name.string().substr(0,
Manifest::kMaxIPCStringLength),
ipc_manifest.short_name.is_null());
- for (size_t i = 0; i < ipc_manifest.icons.size(); ++i) {
- ipc_manifest.icons[i].type = base::NullableString16(
- ipc_manifest.icons[i].type.string().substr(
- 0, Manifest::kMaxIPCStringLength),
- ipc_manifest.icons[i].type.is_null());
+ for (auto& icon : ipc_manifest.icons) {
+ icon.type = base::NullableString16(
+ icon.type.string().substr(0, Manifest::kMaxIPCStringLength),
+ icon.type.is_null());
}
ipc_manifest.gcm_sender_id = base::NullableString16(
ipc_manifest.gcm_sender_id.string().substr(
0, Manifest::kMaxIPCStringLength),
ipc_manifest.gcm_sender_id.is_null());
+ for (auto& related_application : ipc_manifest.related_applications) {
+ related_application.id =
+ base::NullableString16(related_application.id.string().substr(
+ 0, Manifest::kMaxIPCStringLength),
+ related_application.id.is_null());
+ }
Send(new ManifestManagerHostMsg_RequestManifestResponse(
routing_id(), request_id, ipc_manifest));
@@ -100,6 +106,16 @@ void ManifestManager::DidChangeManifest() {
manifest_dirty_ = true;
}
+void ManifestManager::DidCommitProvisionalLoad(
+ bool is_new_navigation,
+ bool is_same_page_navigation) {
+ if (is_same_page_navigation)
+ return;
+
+ may_have_manifest_ = false;
+ manifest_dirty_ = true;
+}
+
void ManifestManager::FetchManifest() {
GURL url(render_frame()->GetWebFrame()->document().manifestURL());
@@ -110,9 +126,6 @@ void ManifestManager::FetchManifest() {
}
fetcher_.reset(new ManifestFetcher(url));
-
- // TODO(mlamouri,kenneth): this is not yet taking into account manifest-src
- // CSP rule, see http://crbug.com/409996.
fetcher_->Start(render_frame()->GetWebFrame(),
base::Bind(&ManifestManager::OnManifestFetchComplete,
base::Unretained(this),
@@ -130,9 +143,27 @@ void ManifestManager::OnManifestFetchComplete(
}
ManifestUmaUtil::FetchSucceeded();
- manifest_ = ManifestParser::Parse(data, response.url(), document_url);
+
+ ManifestParser parser(data, response.url(), document_url);
+ parser.Parse();
fetcher_.reset();
+
+ for (const std::string& msg : parser.errors()) {
+ blink::WebConsoleMessage message;
+ message.level = blink::WebConsoleMessage::LevelError;
+ message.text = blink::WebString::fromUTF8(msg);
+ render_frame()->GetWebFrame()->addMessageToConsole(message);
+ }
+
+ // Having errors while parsing the manifest doesn't mean the manifest parsing
+ // failed. Some properties might have been ignored but some others kept.
+ if (parser.failed()) {
+ ResolveCallbacks(ResolveStateFailure);
+ return;
+ }
+
+ manifest_ = parser.manifest();
ResolveCallbacks(ResolveStateSuccess);
}
diff --git a/chromium/content/renderer/manifest/manifest_manager.h b/chromium/content/renderer/manifest/manifest_manager.h
index 5874724e695..53f9db13826 100644
--- a/chromium/content/renderer/manifest/manifest_manager.h
+++ b/chromium/content/renderer/manifest/manifest_manager.h
@@ -42,6 +42,8 @@ class ManifestManager : public RenderFrameObserver {
// RenderFrameObserver implementation.
bool OnMessageReceived(const IPC::Message& message) override;
void DidChangeManifest() override;
+ void DidCommitProvisionalLoad(bool is_new_navigation,
+ bool is_same_page_navigation) override;
private:
enum ResolveState {
@@ -81,4 +83,4 @@ class ManifestManager : public RenderFrameObserver {
} // namespace content
-#endif // CONTENT_RENDERER_MANIFEST_MANIFEST_MANAGER_H_
+#endif // CONTENT_RENDERER_MANIFEST_MANIFEST_MANAGER_H_
diff --git a/chromium/content/renderer/manifest/manifest_parser.cc b/chromium/content/renderer/manifest/manifest_parser.cc
index bab85cd75f1..bb4fc4e37f4 100644
--- a/chromium/content/renderer/manifest/manifest_parser.cc
+++ b/chromium/content/renderer/manifest/manifest_parser.cc
@@ -19,21 +19,162 @@ namespace content {
namespace {
-enum TrimType {
- Trim,
- NoTrim
-};
-
-base::NullableString16 ParseString(const base::DictionaryValue& dictionary,
- const std::string& key,
- TrimType trim) {
+// Helper function that returns whether the given |str| is a valid width or
+// height value for an icon sizes per:
+// https://html.spec.whatwg.org/multipage/semantics.html#attr-link-sizes
+bool IsValidIconWidthOrHeight(const std::string& str) {
+ if (str.empty() || str[0] == '0')
+ return false;
+ for (size_t i = 0; i < str.size(); ++i)
+ if (!IsAsciiDigit(str[i]))
+ return false;
+ return true;
+}
+
+// Parses the 'sizes' attribute of an icon as described in the HTML spec:
+// https://html.spec.whatwg.org/multipage/semantics.html#attr-link-sizes
+// Return a vector of gfx::Size that contains the valid sizes found. "Any" is
+// represented by gfx::Size(0, 0).
+// TODO(mlamouri): this is implemented as a separate function because it should
+// be refactored with the other icon sizes parsing implementations, see
+// http://crbug.com/416477
+std::vector<gfx::Size> ParseIconSizesHTML(const base::string16& sizes_str16) {
+ if (!base::IsStringASCII(sizes_str16))
+ return std::vector<gfx::Size>();
+
+ std::vector<gfx::Size> sizes;
+ std::string sizes_str =
+ base::StringToLowerASCII(base::UTF16ToUTF8(sizes_str16));
+ std::vector<std::string> sizes_str_list;
+ base::SplitStringAlongWhitespace(sizes_str, &sizes_str_list);
+
+ for (size_t i = 0; i < sizes_str_list.size(); ++i) {
+ std::string& size_str = sizes_str_list[i];
+ if (size_str == "any") {
+ sizes.push_back(gfx::Size(0, 0));
+ continue;
+ }
+
+ // It is expected that [0] => width and [1] => height after the split.
+ std::vector<std::string> size_list;
+ base::SplitStringDontTrim(size_str, L'x', &size_list);
+ if (size_list.size() != 2)
+ continue;
+ if (!IsValidIconWidthOrHeight(size_list[0]) ||
+ !IsValidIconWidthOrHeight(size_list[1])) {
+ continue;
+ }
+
+ int width, height;
+ if (!base::StringToInt(size_list[0], &width) ||
+ !base::StringToInt(size_list[1], &height)) {
+ continue;
+ }
+
+ sizes.push_back(gfx::Size(width, height));
+ }
+
+ return sizes;
+}
+
+const std::string& GetErrorPrefix() {
+ CR_DEFINE_STATIC_LOCAL(std::string, error_prefix,
+ ("Manifest parsing error: "));
+ return error_prefix;
+}
+
+} // anonymous namespace
+
+
+ManifestParser::ManifestParser(const base::StringPiece& data,
+ const GURL& manifest_url,
+ const GURL& document_url)
+ : data_(data),
+ manifest_url_(manifest_url),
+ document_url_(document_url),
+ failed_(false) {
+}
+
+ManifestParser::~ManifestParser() {
+}
+
+void ManifestParser::Parse() {
+ std::string parse_error;
+ scoped_ptr<base::Value> value(
+ base::JSONReader::ReadAndReturnError(data_, base::JSON_PARSE_RFC,
+ nullptr, &parse_error));
+
+ if (!value) {
+ errors_.push_back(GetErrorPrefix() + parse_error);
+ ManifestUmaUtil::ParseFailed();
+ failed_ = true;
+ return;
+ }
+
+ base::DictionaryValue* dictionary = nullptr;
+ if (!value->GetAsDictionary(&dictionary)) {
+ errors_.push_back(GetErrorPrefix() +
+ "root element must be a valid JSON object.");
+ ManifestUmaUtil::ParseFailed();
+ failed_ = true;
+ return;
+ }
+ DCHECK(dictionary);
+
+ manifest_.name = ParseName(*dictionary);
+ manifest_.short_name = ParseShortName(*dictionary);
+ manifest_.start_url = ParseStartURL(*dictionary);
+ manifest_.display = ParseDisplay(*dictionary);
+ manifest_.orientation = ParseOrientation(*dictionary);
+ manifest_.icons = ParseIcons(*dictionary);
+ manifest_.related_applications = ParseRelatedApplications(*dictionary);
+ manifest_.prefer_related_applications =
+ ParsePreferRelatedApplications(*dictionary);
+ manifest_.gcm_sender_id = ParseGCMSenderID(*dictionary);
+ manifest_.gcm_user_visible_only = ParseGCMUserVisibleOnly(*dictionary);
+
+ ManifestUmaUtil::ParseSucceeded(manifest_);
+}
+
+const Manifest& ManifestParser::manifest() const {
+ return manifest_;
+}
+
+const std::vector<std::string>& ManifestParser::errors() const {
+ return errors_;
+}
+
+bool ManifestParser::failed() const {
+ return failed_;
+}
+
+bool ManifestParser::ParseBoolean(const base::DictionaryValue& dictionary,
+ const std::string& key,
+ bool default_value) {
+ if (!dictionary.HasKey(key))
+ return default_value;
+
+ bool value;
+ if (!dictionary.GetBoolean(key, &value)) {
+ errors_.push_back(GetErrorPrefix() +
+ "property '" + key + "' ignored, type boolean expected.");
+ return default_value;
+ }
+
+ return value;
+}
+
+base::NullableString16 ManifestParser::ParseString(
+ const base::DictionaryValue& dictionary,
+ const std::string& key,
+ TrimType trim) {
if (!dictionary.HasKey(key))
return base::NullableString16();
base::string16 value;
if (!dictionary.GetString(key, &value)) {
- // TODO(mlamouri): provide a custom message to the developer console about
- // the property being incorrectly set.
+ errors_.push_back(GetErrorPrefix() +
+ "property '" + key + "' ignored, type string expected.");
return base::NullableString16();
}
@@ -42,13 +183,9 @@ base::NullableString16 ParseString(const base::DictionaryValue& dictionary,
return base::NullableString16(value, false);
}
-// Helper function to parse URLs present on a given |dictionary| in a given
-// field identified by its |key|. The URL is first parsed as a string then
-// resolved using |base_url|.
-// Returns a GURL. If the parsing failed, the GURL will not be valid.
-GURL ParseURL(const base::DictionaryValue& dictionary,
- const std::string& key,
- const GURL& base_url) {
+GURL ManifestParser::ParseURL(const base::DictionaryValue& dictionary,
+ const std::string& key,
+ const GURL& base_url) {
base::NullableString16 url_str = ParseString(dictionary, key, NoTrim);
if (url_str.is_null())
return GURL();
@@ -56,44 +193,32 @@ GURL ParseURL(const base::DictionaryValue& dictionary,
return base_url.Resolve(url_str.string());
}
-// Parses the 'name' field of the manifest, as defined in:
-// http://w3c.github.io/manifest/#dfn-steps-for-processing-the-name-member
-// Returns the parsed string if any, a null string if the parsing failed.
-base::NullableString16 ParseName(const base::DictionaryValue& dictionary) {
+base::NullableString16 ManifestParser::ParseName(
+ const base::DictionaryValue& dictionary) {
return ParseString(dictionary, "name", Trim);
}
-// Parses the 'short_name' field of the manifest, as defined in:
-// http://w3c.github.io/manifest/#dfn-steps-for-processing-the-short-name-member
-// Returns the parsed string if any, a null string if the parsing failed.
-base::NullableString16 ParseShortName(
+base::NullableString16 ManifestParser::ParseShortName(
const base::DictionaryValue& dictionary) {
return ParseString(dictionary, "short_name", Trim);
}
-// Parses the 'start_url' field of the manifest, as defined in:
-// http://w3c.github.io/manifest/#dfn-steps-for-processing-the-start_url-member
-// Returns the parsed GURL if any, an empty GURL if the parsing failed.
-GURL ParseStartURL(const base::DictionaryValue& dictionary,
- const GURL& manifest_url,
- const GURL& document_url) {
- GURL start_url = ParseURL(dictionary, "start_url", manifest_url);
+GURL ManifestParser::ParseStartURL(const base::DictionaryValue& dictionary) {
+ GURL start_url = ParseURL(dictionary, "start_url", manifest_url_);
if (!start_url.is_valid())
return GURL();
- if (start_url.GetOrigin() != document_url.GetOrigin()) {
- // TODO(mlamouri): provide a custom message to the developer console.
+ if (start_url.GetOrigin() != document_url_.GetOrigin()) {
+ errors_.push_back(GetErrorPrefix() + "property 'start_url' ignored, should "
+ "be same origin as document.");
return GURL();
}
return start_url;
}
-// Parses the 'display' field of the manifest, as defined in:
-// http://w3c.github.io/manifest/#dfn-steps-for-processing-the-display-member
-// Returns the parsed DisplayMode if any, DISPLAY_MODE_UNSPECIFIED if the
-// parsing failed.
-Manifest::DisplayMode ParseDisplay(const base::DictionaryValue& dictionary) {
+Manifest::DisplayMode ManifestParser::ParseDisplay(
+ const base::DictionaryValue& dictionary) {
base::NullableString16 display = ParseString(dictionary, "display", Trim);
if (display.is_null())
return Manifest::DISPLAY_MODE_UNSPECIFIED;
@@ -106,15 +231,13 @@ Manifest::DisplayMode ParseDisplay(const base::DictionaryValue& dictionary) {
return Manifest::DISPLAY_MODE_MINIMAL_UI;
else if (LowerCaseEqualsASCII(display.string(), "browser"))
return Manifest::DISPLAY_MODE_BROWSER;
- else
+ else {
+ errors_.push_back(GetErrorPrefix() + "unknown 'display' value ignored.");
return Manifest::DISPLAY_MODE_UNSPECIFIED;
+ }
}
-// Parses the 'orientation' field of the manifest, as defined in:
-// http://w3c.github.io/manifest/#dfn-steps-for-processing-the-orientation-member
-// Returns the parsed WebScreenOrientationLockType if any,
-// WebScreenOrientationLockDefault if the parsing failed.
-blink::WebScreenOrientationLockType ParseOrientation(
+blink::WebScreenOrientationLockType ManifestParser::ParseOrientation(
const base::DictionaryValue& dictionary) {
base::NullableString16 orientation =
ParseString(dictionary, "orientation", Trim);
@@ -138,130 +261,69 @@ blink::WebScreenOrientationLockType ParseOrientation(
return blink::WebScreenOrientationLockPortraitPrimary;
else if (LowerCaseEqualsASCII(orientation.string(), "portrait-secondary"))
return blink::WebScreenOrientationLockPortraitSecondary;
- else
+ else {
+ errors_.push_back(GetErrorPrefix() +
+ "unknown 'orientation' value ignored.");
return blink::WebScreenOrientationLockDefault;
+ }
}
-// Parses the 'src' field of an icon, as defined in:
-// http://w3c.github.io/manifest/#dfn-steps-for-processing-the-src-member-of-an-icon
-// Returns the parsed GURL if any, an empty GURL if the parsing failed.
-GURL ParseIconSrc(const base::DictionaryValue& icon,
- const GURL& manifest_url) {
- return ParseURL(icon, "src", manifest_url);
+GURL ManifestParser::ParseIconSrc(const base::DictionaryValue& icon) {
+ return ParseURL(icon, "src", manifest_url_);
}
-// Parses the 'type' field of an icon, as defined in:
-// http://w3c.github.io/manifest/#dfn-steps-for-processing-the-type-member-of-an-icon
-// Returns the parsed string if any, a null string if the parsing failed.
-base::NullableString16 ParseIconType(const base::DictionaryValue& icon) {
- return ParseString(icon, "type", Trim);
+base::NullableString16 ManifestParser::ParseIconType(
+ const base::DictionaryValue& icon) {
+ return ParseString(icon, "type", Trim);
}
-// Parses the 'density' field of an icon, as defined in:
-// http://w3c.github.io/manifest/#dfn-steps-for-processing-a-density-member-of-an-icon
-// Returns the parsed double if any, Manifest::Icon::kDefaultDensity if the
-// parsing failed.
-double ParseIconDensity(const base::DictionaryValue& icon) {
+double ManifestParser::ParseIconDensity(const base::DictionaryValue& icon) {
double density;
- if (!icon.GetDouble("density", &density) || density <= 0)
+ if (!icon.HasKey("density"))
return Manifest::Icon::kDefaultDensity;
+
+ if (!icon.GetDouble("density", &density) || density <= 0) {
+ errors_.push_back(GetErrorPrefix() +
+ "icon 'density' ignored, must be float greater than 0.");
+ return Manifest::Icon::kDefaultDensity;
+ }
return density;
}
-// Helper function that returns whether the given |str| is a valid width or
-// height value for an icon sizes per:
-// https://html.spec.whatwg.org/multipage/semantics.html#attr-link-sizes
-bool IsValidIconWidthOrHeight(const std::string& str) {
- if (str.empty() || str[0] == '0')
- return false;
- for (size_t i = 0; i < str.size(); ++i)
- if (!IsAsciiDigit(str[i]))
- return false;
- return true;
-}
+std::vector<gfx::Size> ManifestParser::ParseIconSizes(
+ const base::DictionaryValue& icon) {
+ base::NullableString16 sizes_str = ParseString(icon, "sizes", NoTrim);
-// Parses the 'sizes' attribute of an icon as described in the HTML spec:
-// https://html.spec.whatwg.org/multipage/semantics.html#attr-link-sizes
-// Return a vector of gfx::Size that contains the valid sizes found. "Any" is
-// represented by gfx::Size(0, 0).
-// TODO(mlamouri): this is implemented as a separate function because it should
-// be refactored with the other icon sizes parsing implementations, see
-// http://crbug.com/416477
-std::vector<gfx::Size> ParseIconSizesHTML(const base::string16& sizes_str16) {
- if (!base::IsStringASCII(sizes_str16))
+ if (sizes_str.is_null())
return std::vector<gfx::Size>();
- std::vector<gfx::Size> sizes;
- std::string sizes_str =
- base::StringToLowerASCII(base::UTF16ToUTF8(sizes_str16));
- std::vector<std::string> sizes_str_list;
- base::SplitStringAlongWhitespace(sizes_str, &sizes_str_list);
-
- for (size_t i = 0; i < sizes_str_list.size(); ++i) {
- std::string& size_str = sizes_str_list[i];
- if (size_str == "any") {
- sizes.push_back(gfx::Size(0, 0));
- continue;
- }
-
- // It is expected that [0] => width and [1] => height after the split.
- std::vector<std::string> size_list;
- base::SplitStringDontTrim(size_str, L'x', &size_list);
- if (size_list.size() != 2)
- continue;
- if (!IsValidIconWidthOrHeight(size_list[0]) ||
- !IsValidIconWidthOrHeight(size_list[1])) {
- continue;
- }
-
- int width, height;
- if (!base::StringToInt(size_list[0], &width) ||
- !base::StringToInt(size_list[1], &height)) {
- continue;
- }
-
- sizes.push_back(gfx::Size(width, height));
+ std::vector<gfx::Size> sizes = ParseIconSizesHTML(sizes_str.string());
+ if (sizes.empty()) {
+ errors_.push_back(GetErrorPrefix() + "found icon with no valid size.");
}
-
return sizes;
}
-// Parses the 'sizes' field of an icon, as defined in:
-// http://w3c.github.io/manifest/#dfn-steps-for-processing-a-sizes-member-of-an-icon
-// Returns a vector of gfx::Size with the successfully parsed sizes, if any. An
-// empty vector if the field was not present or empty. "Any" is represented by
-// gfx::Size(0, 0).
-std::vector<gfx::Size> ParseIconSizes(const base::DictionaryValue& icon) {
- base::NullableString16 sizes_str = ParseString(icon, "sizes", NoTrim);
-
- return sizes_str.is_null() ? std::vector<gfx::Size>()
- : ParseIconSizesHTML(sizes_str.string());
-}
-
-// Parses the 'icons' field of a Manifest, as defined in:
-// http://w3c.github.io/manifest/#dfn-steps-for-processing-the-icons-member
-// Returns a vector of Manifest::Icon with the successfully parsed icons, if
-// any. An empty vector if the field was not present or empty.
-std::vector<Manifest::Icon> ParseIcons(const base::DictionaryValue& dictionary,
- const GURL& manifest_url) {
+std::vector<Manifest::Icon> ManifestParser::ParseIcons(
+ const base::DictionaryValue& dictionary) {
std::vector<Manifest::Icon> icons;
if (!dictionary.HasKey("icons"))
return icons;
- const base::ListValue* icons_list = 0;
+ const base::ListValue* icons_list = nullptr;
if (!dictionary.GetList("icons", &icons_list)) {
- // TODO(mlamouri): provide a custom message to the developer console about
- // the property being incorrectly set.
+ errors_.push_back(GetErrorPrefix() +
+ "property 'icons' ignored, type array expected.");
return icons;
}
for (size_t i = 0; i < icons_list->GetSize(); ++i) {
- const base::DictionaryValue* icon_dictionary = 0;
+ const base::DictionaryValue* icon_dictionary = nullptr;
if (!icons_list->GetDictionary(i, &icon_dictionary))
continue;
Manifest::Icon icon;
- icon.src = ParseIconSrc(*icon_dictionary, manifest_url);
+ icon.src = ParseIconSrc(*icon_dictionary);
// An icon MUST have a valid src. If it does not, it MUST be ignored.
if (!icon.src.is_valid())
continue;
@@ -275,54 +337,82 @@ std::vector<Manifest::Icon> ParseIcons(const base::DictionaryValue& dictionary,
return icons;
}
-// Parses the 'gcm_sender_id' field of the manifest.
-// This is a proprietary extension of the Web Manifest specification.
-// Returns the parsed string if any, a null string if the parsing failed.
-base::NullableString16 ParseGCMSenderID(
- const base::DictionaryValue& dictionary) {
- return ParseString(dictionary, "gcm_sender_id", Trim);
+base::NullableString16 ManifestParser::ParseRelatedApplicationPlatform(
+ const base::DictionaryValue& application) {
+ return ParseString(application, "platform", Trim);
}
-} // anonymous namespace
+GURL ManifestParser::ParseRelatedApplicationURL(
+ const base::DictionaryValue& application) {
+ return ParseURL(application, "url", manifest_url_);
+}
-Manifest ManifestParser::Parse(const base::StringPiece& json,
- const GURL& manifest_url,
- const GURL& document_url) {
- scoped_ptr<base::Value> value(base::JSONReader::Read(json));
- if (!value) {
- // TODO(mlamouri): get the JSON parsing error and report it to the developer
- // console.
- ManifestUmaUtil::ParseFailed();
- return Manifest();
- }
+base::NullableString16 ManifestParser::ParseRelatedApplicationId(
+ const base::DictionaryValue& application) {
+ return ParseString(application, "id", Trim);
+}
- if (value->GetType() != base::Value::TYPE_DICTIONARY) {
- // TODO(mlamouri): provide a custom message to the developer console.
- ManifestUmaUtil::ParseFailed();
- return Manifest();
+std::vector<Manifest::RelatedApplication>
+ManifestParser::ParseRelatedApplications(
+ const base::DictionaryValue& dictionary) {
+ std::vector<Manifest::RelatedApplication> applications;
+ if (!dictionary.HasKey("related_applications"))
+ return applications;
+
+ const base::ListValue* applications_list = nullptr;
+ if (!dictionary.GetList("related_applications", &applications_list)) {
+ errors_.push_back(
+ GetErrorPrefix() +
+ "property 'related_applications' ignored, type array expected.");
+ return applications;
}
- base::DictionaryValue* dictionary = 0;
- value->GetAsDictionary(&dictionary);
- if (!dictionary) {
- // TODO(mlamouri): provide a custom message to the developer console.
- ManifestUmaUtil::ParseFailed();
- return Manifest();
+ for (size_t i = 0; i < applications_list->GetSize(); ++i) {
+ const base::DictionaryValue* application_dictionary = nullptr;
+ if (!applications_list->GetDictionary(i, &application_dictionary))
+ continue;
+
+ Manifest::RelatedApplication application;
+ application.platform =
+ ParseRelatedApplicationPlatform(*application_dictionary);
+ // "If platform is undefined, move onto the next item if any are left."
+ if (application.platform.is_null()) {
+ errors_.push_back(
+ GetErrorPrefix() +
+ "'platform' is a required field, related application ignored.");
+ continue;
+ }
+
+ application.id = ParseRelatedApplicationId(*application_dictionary);
+ application.url = ParseRelatedApplicationURL(*application_dictionary);
+ // "If both id and url are undefined, move onto the next item if any are
+ // left."
+ if (application.url.is_empty() && application.id.is_null()) {
+ errors_.push_back(
+ GetErrorPrefix() +
+ "one of 'url' or 'id' is required, related application ignored.");
+ continue;
+ }
+
+ applications.push_back(application);
}
- Manifest manifest;
+ return applications;
+}
- manifest.name = ParseName(*dictionary);
- manifest.short_name = ParseShortName(*dictionary);
- manifest.start_url = ParseStartURL(*dictionary, manifest_url, document_url);
- manifest.display = ParseDisplay(*dictionary);
- manifest.orientation = ParseOrientation(*dictionary);
- manifest.icons = ParseIcons(*dictionary, manifest_url);
- manifest.gcm_sender_id = ParseGCMSenderID(*dictionary);
+bool ManifestParser::ParsePreferRelatedApplications(
+ const base::DictionaryValue& dictionary) {
+ return ParseBoolean(dictionary, "prefer_related_applications", false);
+}
- ManifestUmaUtil::ParseSucceeded(manifest);
+base::NullableString16 ManifestParser::ParseGCMSenderID(
+ const base::DictionaryValue& dictionary) {
+ return ParseString(dictionary, "gcm_sender_id", Trim);
+}
- return manifest;
+bool ManifestParser::ParseGCMUserVisibleOnly(
+ const base::DictionaryValue& dictionary) {
+ return ParseBoolean(dictionary, "gcm_user_visible_only", false);
}
} // namespace content
diff --git a/chromium/content/renderer/manifest/manifest_parser.h b/chromium/content/renderer/manifest/manifest_parser.h
index 48812795308..4beb55ed860 100644
--- a/chromium/content/renderer/manifest/manifest_parser.h
+++ b/chromium/content/renderer/manifest/manifest_parser.h
@@ -5,8 +5,10 @@
#ifndef CONTENT_RENDERER_MANIFEST_MANIFEST_PARSER_H_
#define CONTENT_RENDERER_MANIFEST_MANIFEST_PARSER_H_
+#include "base/strings/nullable_string16.h"
#include "base/strings/string_piece.h"
#include "content/common/content_export.h"
+#include "content/public/common/manifest.h"
class GURL;
@@ -16,18 +18,165 @@ class DictionaryValue;
namespace content {
-struct Manifest;
-
// ManifestParser handles the logic of parsing the Web Manifest from a string.
// It implements:
// http://w3c.github.io/manifest/#dfn-steps-for-processing-a-manifest
class CONTENT_EXPORT ManifestParser {
public:
- static Manifest Parse(const base::StringPiece&,
- const GURL& manifest_url,
- const GURL& document_url);
+ ManifestParser(const base::StringPiece& data,
+ const GURL& manifest_url,
+ const GURL& document_url);
+ ~ManifestParser();
+
+ // Parse the Manifest from a string using following:
+ // http://w3c.github.io/manifest/#dfn-steps-for-processing-a-manifest
+ void Parse();
+
+ const Manifest& manifest() const;
+ const std::vector<std::string>& errors() const;
+ bool failed() const;
+
+ private:
+ // Used to indicate whether to strip whitespace when parsing a string.
+ enum TrimType {
+ Trim,
+ NoTrim
+ };
+
+ // Helper function to parse booleans present on a given |dictionary| in a
+ // given field identified by its |key|.
+ // Returns the parsed boolean if any, or |default_value| if parsing failed.
+ bool ParseBoolean(const base::DictionaryValue& dictionary,
+ const std::string& key,
+ bool default_value);
+
+ // Helper function to parse strings present on a given |dictionary| in a given
+ // field identified by its |key|.
+ // Returns the parsed string if any, a null string if the parsing failed.
+ base::NullableString16 ParseString(const base::DictionaryValue& dictionary,
+ const std::string& key,
+ TrimType trim);
+
+ // Helper function to parse URLs present on a given |dictionary| in a given
+ // field identified by its |key|. The URL is first parsed as a string then
+ // resolved using |base_url|.
+ // Returns a GURL. If the parsing failed, the GURL will not be valid.
+ GURL ParseURL(const base::DictionaryValue& dictionary,
+ const std::string& key,
+ const GURL& base_url);
+
+ // Parses the 'name' field of the manifest, as defined in:
+ // http://w3c.github.io/manifest/#dfn-steps-for-processing-the-name-member
+ // Returns the parsed string if any, a null string if the parsing failed.
+ base::NullableString16 ParseName(const base::DictionaryValue& dictionary);
+
+ // Parses the 'short_name' field of the manifest, as defined in:
+ // http://w3c.github.io/manifest/#dfn-steps-for-processing-the-short-name-member
+ // Returns the parsed string if any, a null string if the parsing failed.
+ base::NullableString16 ParseShortName(
+ const base::DictionaryValue& dictionary);
+
+ // Parses the 'start_url' field of the manifest, as defined in:
+ // http://w3c.github.io/manifest/#dfn-steps-for-processing-the-start_url-member
+ // Returns the parsed GURL if any, an empty GURL if the parsing failed.
+ GURL ParseStartURL(const base::DictionaryValue& dictionary);
+
+ // Parses the 'display' field of the manifest, as defined in:
+ // http://w3c.github.io/manifest/#dfn-steps-for-processing-the-display-member
+ // Returns the parsed DisplayMode if any, DISPLAY_MODE_UNSPECIFIED if the
+ // parsing failed.
+ Manifest::DisplayMode ParseDisplay(const base::DictionaryValue& dictionary);
+
+ // Parses the 'orientation' field of the manifest, as defined in:
+ // http://w3c.github.io/manifest/#dfn-steps-for-processing-the-orientation-member
+ // Returns the parsed WebScreenOrientationLockType if any,
+ // WebScreenOrientationLockDefault if the parsing failed.
+ blink::WebScreenOrientationLockType ParseOrientation(
+ const base::DictionaryValue& dictionary);
+
+ // Parses the 'src' field of an icon, as defined in:
+ // http://w3c.github.io/manifest/#dfn-steps-for-processing-the-src-member-of-an-icon
+ // Returns the parsed GURL if any, an empty GURL if the parsing failed.
+ GURL ParseIconSrc(const base::DictionaryValue& icon);
+
+ // Parses the 'type' field of an icon, as defined in:
+ // http://w3c.github.io/manifest/#dfn-steps-for-processing-the-type-member-of-an-icon
+ // Returns the parsed string if any, a null string if the parsing failed.
+ base::NullableString16 ParseIconType(const base::DictionaryValue& icon);
+
+ // Parses the 'density' field of an icon, as defined in:
+ // http://w3c.github.io/manifest/#dfn-steps-for-processing-a-density-member-of-an-icon
+ // Returns the parsed double if any, Manifest::Icon::kDefaultDensity if the
+ // parsing failed.
+ double ParseIconDensity(const base::DictionaryValue& icon);
+
+ // Parses the 'sizes' field of an icon, as defined in:
+ // http://w3c.github.io/manifest/#dfn-steps-for-processing-a-sizes-member-of-an-icon
+ // Returns a vector of gfx::Size with the successfully parsed sizes, if any.
+ // An empty vector if the field was not present or empty. "Any" is represented
+ // by gfx::Size(0, 0).
+ std::vector<gfx::Size> ParseIconSizes(const base::DictionaryValue& icon);
+
+ // Parses the 'icons' field of a Manifest, as defined in:
+ // http://w3c.github.io/manifest/#dfn-steps-for-processing-the-icons-member
+ // Returns a vector of Manifest::Icon with the successfully parsed icons, if
+ // any. An empty vector if the field was not present or empty.
+ std::vector<Manifest::Icon> ParseIcons(
+ const base::DictionaryValue& dictionary);
+
+ // Parses the 'platform' field of a related application, as defined in:
+ // https://w3c.github.io/manifest/#dfn-steps-for-processing-the-platform-member-of-an-application
+ // Returns the parsed string if any, a null string if the parsing failed.
+ base::NullableString16 ParseRelatedApplicationPlatform(
+ const base::DictionaryValue& application);
+
+ // Parses the 'url' field of a related application, as defined in:
+ // https://w3c.github.io/manifest/#dfn-steps-for-processing-the-url-member-of-an-application
+ // Returns the paresed GURL if any, an empty GURL if the parsing failed.
+ GURL ParseRelatedApplicationURL(const base::DictionaryValue& application);
+
+ // Parses the 'id' field of a related application, as defined in:
+ // https://w3c.github.io/manifest/#dfn-steps-for-processing-the-id-member-of-an-application
+ // Returns the parsed string if any, a null string if the parsing failed.
+ base::NullableString16 ParseRelatedApplicationId(
+ const base::DictionaryValue& application);
+
+ // Parses the 'related_applications' field of the manifest, as defined in:
+ // https://w3c.github.io/manifest/#dfn-steps-for-processing-the-related_applications-member
+ // Returns a vector of Manifest::RelatedApplication with the successfully
+ // parsed applications, if any. An empty vector if the field was not present
+ // or empty.
+ std::vector<Manifest::RelatedApplication> ParseRelatedApplications(
+ const base::DictionaryValue& dictionary);
+
+ // Parses the 'prefer_related_applications' field on the manifest, as defined
+ // in:
+ // https://w3c.github.io/manifest/#dfn-steps-for-processing-the-prefer_related_applications-member
+ // returns true iff the field could be parsed as the boolean true.
+ bool ParsePreferRelatedApplications(const base::DictionaryValue& dictionary);
+
+ // Parses the 'gcm_sender_id' field of the manifest.
+ // This is a proprietary extension of the Web Manifest specification.
+ // Returns the parsed string if any, a null string if the parsing failed.
+ base::NullableString16 ParseGCMSenderID(
+ const base::DictionaryValue& dictionary);
+
+ // Parses the 'gcm_user_visible_only' field of the manifest.
+ // This is a proprietary extension of the Web Manifest specification.
+ // Returns true iff the string could be parsed as the boolean true.
+ bool ParseGCMUserVisibleOnly(const base::DictionaryValue& dictionary);
+
+ const base::StringPiece& data_;
+ GURL manifest_url_;
+ GURL document_url_;
+
+ bool failed_;
+ Manifest manifest_;
+ std::vector<std::string> errors_;
+
+ DISALLOW_COPY_AND_ASSIGN(ManifestParser);
};
} // namespace content
-#endif // CONTENT_RENDERER_MANIFEST_MANIFEST_PARSER_H_
+#endif // CONTENT_RENDERER_MANIFEST_MANIFEST_PARSER_H_
diff --git a/chromium/content/renderer/manifest/manifest_parser_unittest.cc b/chromium/content/renderer/manifest/manifest_parser_unittest.cc
index 1e3770b4e74..01fde51224f 100644
--- a/chromium/content/renderer/manifest/manifest_parser_unittest.cc
+++ b/chromium/content/renderer/manifest/manifest_parser_unittest.cc
@@ -15,16 +15,34 @@ class ManifestParserTest : public testing::Test {
ManifestParserTest() {}
~ManifestParserTest() override {}
- Manifest ParseManifest(const base::StringPiece& json,
- const GURL& document_url = default_document_url,
- const GURL& manifest_url = default_manifest_url) {
- return ManifestParser::Parse(json, document_url, manifest_url);
+ Manifest ParseManifestWithURLs(const base::StringPiece& data,
+ const GURL& document_url,
+ const GURL& manifest_url) {
+ ManifestParser parser(data, document_url, manifest_url);
+ parser.Parse();
+ errors_ = parser.errors();
+ return parser.manifest();
+ }
+
+ Manifest ParseManifest(const base::StringPiece& data) {
+ return ParseManifestWithURLs(
+ data, default_document_url, default_manifest_url);
+ }
+
+ const std::vector<std::string>& errors() const {
+ return errors_;
+ }
+
+ unsigned int GetErrorCount() const {
+ return errors_.size();
}
static const GURL default_document_url;
static const GURL default_manifest_url;
private:
+ std::vector<std::string> errors_;
+
DISALLOW_COPY_AND_ASSIGN(ManifestParserTest);
};
@@ -33,9 +51,26 @@ const GURL ManifestParserTest::default_document_url(
const GURL ManifestParserTest::default_manifest_url(
"http://foo.com/manifest.json");
+TEST_F(ManifestParserTest, CrashTest) {
+ // Passing temporary variables should not crash.
+ ManifestParser parser("{\"start_url\": \"/\"}",
+ GURL("http://example.com"),
+ GURL("http://example.com"));
+ parser.Parse();
+
+ // .Parse() should have been call without crashing and succeeded.
+ EXPECT_EQ(0u, parser.errors().size());
+ EXPECT_FALSE(parser.manifest().IsEmpty());
+}
+
TEST_F(ManifestParserTest, EmptyStringNull) {
Manifest manifest = ParseManifest("");
+ // This Manifest is not a valid JSON object, it's a parsing error.
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ("Manifest parsing error: Line: 1, column: 1, Unexpected token.",
+ errors()[0]);
+
// A parsing error is equivalent to an empty manifest.
ASSERT_TRUE(manifest.IsEmpty());
ASSERT_TRUE(manifest.name.is_null());
@@ -43,11 +78,16 @@ TEST_F(ManifestParserTest, EmptyStringNull) {
ASSERT_TRUE(manifest.start_url.is_empty());
ASSERT_EQ(manifest.display, Manifest::DISPLAY_MODE_UNSPECIFIED);
ASSERT_EQ(manifest.orientation, blink::WebScreenOrientationLockDefault);
+ ASSERT_TRUE(manifest.gcm_sender_id.is_null());
+ ASSERT_FALSE(manifest.gcm_user_visible_only);
}
TEST_F(ManifestParserTest, ValidNoContentParses) {
Manifest manifest = ParseManifest("{}");
+ // Empty Manifest is not a parsing error.
+ EXPECT_EQ(0u, GetErrorCount());
+
// Check that all the fields are null in that case.
ASSERT_TRUE(manifest.IsEmpty());
ASSERT_TRUE(manifest.name.is_null());
@@ -55,6 +95,37 @@ TEST_F(ManifestParserTest, ValidNoContentParses) {
ASSERT_TRUE(manifest.start_url.is_empty());
ASSERT_EQ(manifest.display, Manifest::DISPLAY_MODE_UNSPECIFIED);
ASSERT_EQ(manifest.orientation, blink::WebScreenOrientationLockDefault);
+ ASSERT_TRUE(manifest.gcm_sender_id.is_null());
+ ASSERT_FALSE(manifest.gcm_user_visible_only);
+}
+
+TEST_F(ManifestParserTest, MultipleErrorsReporting) {
+ Manifest manifest = ParseManifest("{ \"name\": 42, \"short_name\": 4,"
+ "\"orientation\": {}, \"display\": \"foo\", \"start_url\": null,"
+ "\"icons\": {}, \"gcm_user_visible_only\": 42 }");
+
+ EXPECT_EQ(7u, GetErrorCount());
+
+ EXPECT_EQ("Manifest parsing error: property 'name' ignored,"
+ " type string expected.",
+ errors()[0]);
+ EXPECT_EQ("Manifest parsing error: property 'short_name' ignored,"
+ " type string expected.",
+ errors()[1]);
+ EXPECT_EQ("Manifest parsing error: property 'start_url' ignored,"
+ " type string expected.",
+ errors()[2]);
+ EXPECT_EQ("Manifest parsing error: unknown 'display' value ignored.",
+ errors()[3]);
+ EXPECT_EQ("Manifest parsing error: property 'orientation' ignored,"
+ " type string expected.",
+ errors()[4]);
+ EXPECT_EQ("Manifest parsing error: property 'icons' ignored, "
+ "type array expected.",
+ errors()[5]);
+ EXPECT_EQ("Manifest parsing error: property 'gcm_user_visible_only' ignored, "
+ "type boolean expected.",
+ errors()[6]);
}
TEST_F(ManifestParserTest, NameParseRules) {
@@ -63,24 +134,34 @@ TEST_F(ManifestParserTest, NameParseRules) {
Manifest manifest = ParseManifest("{ \"name\": \"foo\" }");
ASSERT_TRUE(EqualsASCII(manifest.name.string(), "foo"));
ASSERT_FALSE(manifest.IsEmpty());
+ EXPECT_EQ(0u, GetErrorCount());
}
// Trim whitespaces.
{
Manifest manifest = ParseManifest("{ \"name\": \" foo \" }");
ASSERT_TRUE(EqualsASCII(manifest.name.string(), "foo"));
+ EXPECT_EQ(0u, GetErrorCount());
}
// Don't parse if name isn't a string.
{
Manifest manifest = ParseManifest("{ \"name\": {} }");
ASSERT_TRUE(manifest.name.is_null());
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ("Manifest parsing error: property 'name' ignored,"
+ " type string expected.",
+ errors()[0]);
}
// Don't parse if name isn't a string.
{
Manifest manifest = ParseManifest("{ \"name\": 42 }");
ASSERT_TRUE(manifest.name.is_null());
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ("Manifest parsing error: property 'name' ignored,"
+ " type string expected.",
+ errors()[0]);
}
}
@@ -90,24 +171,34 @@ TEST_F(ManifestParserTest, ShortNameParseRules) {
Manifest manifest = ParseManifest("{ \"short_name\": \"foo\" }");
ASSERT_TRUE(EqualsASCII(manifest.short_name.string(), "foo"));
ASSERT_FALSE(manifest.IsEmpty());
+ EXPECT_EQ(0u, GetErrorCount());
}
// Trim whitespaces.
{
Manifest manifest = ParseManifest("{ \"short_name\": \" foo \" }");
ASSERT_TRUE(EqualsASCII(manifest.short_name.string(), "foo"));
+ EXPECT_EQ(0u, GetErrorCount());
}
// Don't parse if name isn't a string.
{
Manifest manifest = ParseManifest("{ \"short_name\": {} }");
ASSERT_TRUE(manifest.short_name.is_null());
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ("Manifest parsing error: property 'short_name' ignored,"
+ " type string expected.",
+ errors()[0]);
}
// Don't parse if name isn't a string.
{
Manifest manifest = ParseManifest("{ \"short_name\": 42 }");
ASSERT_TRUE(manifest.short_name.is_null());
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ("Manifest parsing error: property 'short_name' ignored,"
+ " type string expected.",
+ errors()[0]);
}
}
@@ -118,6 +209,7 @@ TEST_F(ManifestParserTest, StartURLParseRules) {
ASSERT_EQ(manifest.start_url.spec(),
default_document_url.Resolve("land.html").spec());
ASSERT_FALSE(manifest.IsEmpty());
+ EXPECT_EQ(0u, GetErrorCount());
}
// Whitespaces.
@@ -125,45 +217,60 @@ TEST_F(ManifestParserTest, StartURLParseRules) {
Manifest manifest = ParseManifest("{ \"start_url\": \" land.html \" }");
ASSERT_EQ(manifest.start_url.spec(),
default_document_url.Resolve("land.html").spec());
+ EXPECT_EQ(0u, GetErrorCount());
}
// Don't parse if property isn't a string.
{
Manifest manifest = ParseManifest("{ \"start_url\": {} }");
ASSERT_TRUE(manifest.start_url.is_empty());
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ("Manifest parsing error: property 'start_url' ignored,"
+ " type string expected.",
+ errors()[0]);
}
// Don't parse if property isn't a string.
{
Manifest manifest = ParseManifest("{ \"start_url\": 42 }");
ASSERT_TRUE(manifest.start_url.is_empty());
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ("Manifest parsing error: property 'start_url' ignored,"
+ " type string expected.",
+ errors()[0]);
}
// Absolute start_url, same origin with document.
{
Manifest manifest =
- ParseManifest("{ \"start_url\": \"http://foo.com/land.html\" }",
- GURL("http://foo.com/manifest.json"),
- GURL("http://foo.com/index.html"));
+ ParseManifestWithURLs("{ \"start_url\": \"http://foo.com/land.html\" }",
+ GURL("http://foo.com/manifest.json"),
+ GURL("http://foo.com/index.html"));
ASSERT_EQ(manifest.start_url.spec(), "http://foo.com/land.html");
+ EXPECT_EQ(0u, GetErrorCount());
}
// Absolute start_url, cross origin with document.
{
Manifest manifest =
- ParseManifest("{ \"start_url\": \"http://bar.com/land.html\" }",
- GURL("http://foo.com/manifest.json"),
- GURL("http://foo.com/index.html"));
+ ParseManifestWithURLs("{ \"start_url\": \"http://bar.com/land.html\" }",
+ GURL("http://foo.com/manifest.json"),
+ GURL("http://foo.com/index.html"));
ASSERT_TRUE(manifest.start_url.is_empty());
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ("Manifest parsing error: property 'start_url' ignored, should "
+ "be same origin as document.",
+ errors()[0]);
}
// Resolving has to happen based on the manifest_url.
{
Manifest manifest =
- ParseManifest("{ \"start_url\": \"land.html\" }",
- GURL("http://foo.com/landing/manifest.json"),
- GURL("http://foo.com/index.html"));
+ ParseManifestWithURLs("{ \"start_url\": \"land.html\" }",
+ GURL("http://foo.com/landing/manifest.json"),
+ GURL("http://foo.com/index.html"));
ASSERT_EQ(manifest.start_url.spec(), "http://foo.com/landing/land.html");
+ EXPECT_EQ(0u, GetErrorCount());
}
}
@@ -173,60 +280,78 @@ TEST_F(ManifestParserTest, DisplayParserRules) {
Manifest manifest = ParseManifest("{ \"display\": \"browser\" }");
EXPECT_EQ(manifest.display, Manifest::DISPLAY_MODE_BROWSER);
EXPECT_FALSE(manifest.IsEmpty());
+ EXPECT_EQ(0u, GetErrorCount());
}
// Trim whitespaces.
{
Manifest manifest = ParseManifest("{ \"display\": \" browser \" }");
EXPECT_EQ(manifest.display, Manifest::DISPLAY_MODE_BROWSER);
+ EXPECT_EQ(0u, GetErrorCount());
}
// Don't parse if name isn't a string.
{
Manifest manifest = ParseManifest("{ \"display\": {} }");
EXPECT_EQ(manifest.display, Manifest::DISPLAY_MODE_UNSPECIFIED);
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ("Manifest parsing error: property 'display' ignored,"
+ " type string expected.",
+ errors()[0]);
}
// Don't parse if name isn't a string.
{
Manifest manifest = ParseManifest("{ \"display\": 42 }");
EXPECT_EQ(manifest.display, Manifest::DISPLAY_MODE_UNSPECIFIED);
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ("Manifest parsing error: property 'display' ignored,"
+ " type string expected.",
+ errors()[0]);
}
// Parse fails if string isn't known.
{
Manifest manifest = ParseManifest("{ \"display\": \"browser_something\" }");
EXPECT_EQ(manifest.display, Manifest::DISPLAY_MODE_UNSPECIFIED);
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ("Manifest parsing error: unknown 'display' value ignored.",
+ errors()[0]);
}
// Accept 'fullscreen'.
{
Manifest manifest = ParseManifest("{ \"display\": \"fullscreen\" }");
EXPECT_EQ(manifest.display, Manifest::DISPLAY_MODE_FULLSCREEN);
+ EXPECT_EQ(0u, GetErrorCount());
}
// Accept 'fullscreen'.
{
Manifest manifest = ParseManifest("{ \"display\": \"standalone\" }");
EXPECT_EQ(manifest.display, Manifest::DISPLAY_MODE_STANDALONE);
+ EXPECT_EQ(0u, GetErrorCount());
}
// Accept 'minimal-ui'.
{
Manifest manifest = ParseManifest("{ \"display\": \"minimal-ui\" }");
EXPECT_EQ(manifest.display, Manifest::DISPLAY_MODE_MINIMAL_UI);
+ EXPECT_EQ(0u, GetErrorCount());
}
// Accept 'browser'.
{
Manifest manifest = ParseManifest("{ \"display\": \"browser\" }");
EXPECT_EQ(manifest.display, Manifest::DISPLAY_MODE_BROWSER);
+ EXPECT_EQ(0u, GetErrorCount());
}
// Case insensitive.
{
Manifest manifest = ParseManifest("{ \"display\": \"BROWSER\" }");
EXPECT_EQ(manifest.display, Manifest::DISPLAY_MODE_BROWSER);
+ EXPECT_EQ(0u, GetErrorCount());
}
}
@@ -236,48 +361,64 @@ TEST_F(ManifestParserTest, OrientationParserRules) {
Manifest manifest = ParseManifest("{ \"orientation\": \"natural\" }");
EXPECT_EQ(manifest.orientation, blink::WebScreenOrientationLockNatural);
EXPECT_FALSE(manifest.IsEmpty());
+ EXPECT_EQ(0u, GetErrorCount());
}
// Trim whitespaces.
{
Manifest manifest = ParseManifest("{ \"orientation\": \"natural\" }");
EXPECT_EQ(manifest.orientation, blink::WebScreenOrientationLockNatural);
+ EXPECT_EQ(0u, GetErrorCount());
}
// Don't parse if name isn't a string.
{
Manifest manifest = ParseManifest("{ \"orientation\": {} }");
EXPECT_EQ(manifest.orientation, blink::WebScreenOrientationLockDefault);
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ("Manifest parsing error: property 'orientation' ignored,"
+ " type string expected.",
+ errors()[0]);
}
// Don't parse if name isn't a string.
{
Manifest manifest = ParseManifest("{ \"orientation\": 42 }");
EXPECT_EQ(manifest.orientation, blink::WebScreenOrientationLockDefault);
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ("Manifest parsing error: property 'orientation' ignored,"
+ " type string expected.",
+ errors()[0]);
}
// Parse fails if string isn't known.
{
Manifest manifest = ParseManifest("{ \"orientation\": \"naturalish\" }");
EXPECT_EQ(manifest.orientation, blink::WebScreenOrientationLockDefault);
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ("Manifest parsing error: unknown 'orientation' value ignored.",
+ errors()[0]);
}
// Accept 'any'.
{
Manifest manifest = ParseManifest("{ \"orientation\": \"any\" }");
EXPECT_EQ(manifest.orientation, blink::WebScreenOrientationLockAny);
+ EXPECT_EQ(0u, GetErrorCount());
}
// Accept 'natural'.
{
Manifest manifest = ParseManifest("{ \"orientation\": \"natural\" }");
EXPECT_EQ(manifest.orientation, blink::WebScreenOrientationLockNatural);
+ EXPECT_EQ(0u, GetErrorCount());
}
// Accept 'landscape'.
{
Manifest manifest = ParseManifest("{ \"orientation\": \"landscape\" }");
EXPECT_EQ(manifest.orientation, blink::WebScreenOrientationLockLandscape);
+ EXPECT_EQ(0u, GetErrorCount());
}
// Accept 'landscape-primary'.
@@ -286,6 +427,7 @@ TEST_F(ManifestParserTest, OrientationParserRules) {
ParseManifest("{ \"orientation\": \"landscape-primary\" }");
EXPECT_EQ(manifest.orientation,
blink::WebScreenOrientationLockLandscapePrimary);
+ EXPECT_EQ(0u, GetErrorCount());
}
// Accept 'landscape-secondary'.
@@ -294,12 +436,14 @@ TEST_F(ManifestParserTest, OrientationParserRules) {
ParseManifest("{ \"orientation\": \"landscape-secondary\" }");
EXPECT_EQ(manifest.orientation,
blink::WebScreenOrientationLockLandscapeSecondary);
+ EXPECT_EQ(0u, GetErrorCount());
}
// Accept 'portrait'.
{
Manifest manifest = ParseManifest("{ \"orientation\": \"portrait\" }");
EXPECT_EQ(manifest.orientation, blink::WebScreenOrientationLockPortrait);
+ EXPECT_EQ(0u, GetErrorCount());
}
// Accept 'portrait-primary'.
@@ -308,6 +452,7 @@ TEST_F(ManifestParserTest, OrientationParserRules) {
ParseManifest("{ \"orientation\": \"portrait-primary\" }");
EXPECT_EQ(manifest.orientation,
blink::WebScreenOrientationLockPortraitPrimary);
+ EXPECT_EQ(0u, GetErrorCount());
}
// Accept 'portrait-secondary'.
@@ -316,12 +461,14 @@ TEST_F(ManifestParserTest, OrientationParserRules) {
ParseManifest("{ \"orientation\": \"portrait-secondary\" }");
EXPECT_EQ(manifest.orientation,
blink::WebScreenOrientationLockPortraitSecondary);
+ EXPECT_EQ(0u, GetErrorCount());
}
// Case insensitive.
{
Manifest manifest = ParseManifest("{ \"orientation\": \"LANDSCAPE\" }");
EXPECT_EQ(manifest.orientation, blink::WebScreenOrientationLockLandscape);
+ EXPECT_EQ(0u, GetErrorCount());
}
}
@@ -331,6 +478,7 @@ TEST_F(ManifestParserTest, IconsParseRules) {
Manifest manifest = ParseManifest("{ \"icons\": [] }");
EXPECT_EQ(manifest.icons.size(), 0u);
EXPECT_TRUE(manifest.IsEmpty());
+ EXPECT_EQ(0u, GetErrorCount());
}
// Smoke test: if empty icon, empty list.
@@ -338,6 +486,7 @@ TEST_F(ManifestParserTest, IconsParseRules) {
Manifest manifest = ParseManifest("{ \"icons\": [ {} ] }");
EXPECT_EQ(manifest.icons.size(), 0u);
EXPECT_TRUE(manifest.IsEmpty());
+ EXPECT_EQ(0u, GetErrorCount());
}
// Smoke test: icon with invalid src, empty list.
@@ -345,6 +494,7 @@ TEST_F(ManifestParserTest, IconsParseRules) {
Manifest manifest = ParseManifest("{ \"icons\": [ { \"icons\": [] } ] }");
EXPECT_EQ(manifest.icons.size(), 0u);
EXPECT_TRUE(manifest.IsEmpty());
+ EXPECT_EQ(0u, GetErrorCount());
}
// Smoke test: if icon with empty src, it will be present in the list.
@@ -353,6 +503,7 @@ TEST_F(ManifestParserTest, IconsParseRules) {
EXPECT_EQ(manifest.icons.size(), 1u);
EXPECT_EQ(manifest.icons[0].src.spec(), "http://foo.com/index.html");
EXPECT_FALSE(manifest.IsEmpty());
+ EXPECT_EQ(0u, GetErrorCount());
}
// Smoke test: if one icons with valid src, it will be present in the list.
@@ -362,6 +513,7 @@ TEST_F(ManifestParserTest, IconsParseRules) {
EXPECT_EQ(manifest.icons.size(), 1u);
EXPECT_EQ(manifest.icons[0].src.spec(), "http://foo.com/foo.jpg");
EXPECT_FALSE(manifest.IsEmpty());
+ EXPECT_EQ(0u, GetErrorCount());
}
}
@@ -372,6 +524,7 @@ TEST_F(ManifestParserTest, IconSrcParseRules) {
ParseManifest("{ \"icons\": [ {\"src\": \"foo.png\" } ] }");
EXPECT_EQ(manifest.icons[0].src.spec(),
default_document_url.Resolve("foo.png").spec());
+ EXPECT_EQ(0u, GetErrorCount());
}
// Whitespaces.
@@ -380,27 +533,38 @@ TEST_F(ManifestParserTest, IconSrcParseRules) {
ParseManifest("{ \"icons\": [ {\"src\": \" foo.png \" } ] }");
EXPECT_EQ(manifest.icons[0].src.spec(),
default_document_url.Resolve("foo.png").spec());
+ EXPECT_EQ(0u, GetErrorCount());
}
// Don't parse if property isn't a string.
{
Manifest manifest = ParseManifest("{ \"icons\": [ {\"src\": {} } ] }");
EXPECT_TRUE(manifest.icons.empty());
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ("Manifest parsing error: property 'src' ignored,"
+ " type string expected.",
+ errors()[0]);
}
// Don't parse if property isn't a string.
{
Manifest manifest = ParseManifest("{ \"icons\": [ {\"src\": 42 } ] }");
EXPECT_TRUE(manifest.icons.empty());
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ("Manifest parsing error: property 'src' ignored,"
+ " type string expected.",
+ errors()[0]);
}
// Resolving has to happen based on the document_url.
{
- Manifest manifest =
- ParseManifest("{ \"icons\": [ {\"src\": \"icons/foo.png\" } ] }",
- GURL("http://foo.com/landing/index.html"));
+ Manifest manifest = ParseManifestWithURLs(
+ "{ \"icons\": [ {\"src\": \"icons/foo.png\" } ] }",
+ GURL("http://foo.com/landing/index.html"),
+ default_manifest_url);
EXPECT_EQ(manifest.icons[0].src.spec(),
"http://foo.com/landing/icons/foo.png");
+ EXPECT_EQ(0u, GetErrorCount());
}
}
@@ -410,6 +574,7 @@ TEST_F(ManifestParserTest, IconTypeParseRules) {
Manifest manifest =
ParseManifest("{ \"icons\": [ {\"src\": \"\", \"type\": \"foo\" } ] }");
EXPECT_TRUE(EqualsASCII(manifest.icons[0].type.string(), "foo"));
+ EXPECT_EQ(0u, GetErrorCount());
}
// Trim whitespaces.
@@ -417,6 +582,7 @@ TEST_F(ManifestParserTest, IconTypeParseRules) {
Manifest manifest = ParseManifest("{ \"icons\": [ {\"src\": \"\","
" \"type\": \" foo \" } ] }");
EXPECT_TRUE(EqualsASCII(manifest.icons[0].type.string(), "foo"));
+ EXPECT_EQ(0u, GetErrorCount());
}
// Don't parse if property isn't a string.
@@ -424,6 +590,10 @@ TEST_F(ManifestParserTest, IconTypeParseRules) {
Manifest manifest =
ParseManifest("{ \"icons\": [ {\"src\": \"\", \"type\": {} } ] }");
EXPECT_TRUE(manifest.icons[0].type.is_null());
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ("Manifest parsing error: property 'type' ignored,"
+ " type string expected.",
+ errors()[0]);
}
// Don't parse if property isn't a string.
@@ -431,6 +601,10 @@ TEST_F(ManifestParserTest, IconTypeParseRules) {
Manifest manifest =
ParseManifest("{ \"icons\": [ {\"src\": \"\", \"type\": 42 } ] }");
EXPECT_TRUE(manifest.icons[0].type.is_null());
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ("Manifest parsing error: property 'type' ignored,"
+ " type string expected.",
+ errors()[0]);
}
}
@@ -440,6 +614,7 @@ TEST_F(ManifestParserTest, IconDensityParseRules) {
Manifest manifest =
ParseManifest("{ \"icons\": [ {\"src\": \"\", \"density\": 42 } ] }");
EXPECT_EQ(manifest.icons[0].density, 42);
+ EXPECT_EQ(0u, GetErrorCount());
}
// Decimal value.
@@ -447,6 +622,7 @@ TEST_F(ManifestParserTest, IconDensityParseRules) {
Manifest manifest =
ParseManifest("{ \"icons\": [ {\"src\": \"\", \"density\": 2.5 } ] }");
EXPECT_EQ(manifest.icons[0].density, 2.5);
+ EXPECT_EQ(0u, GetErrorCount());
}
// Parse fail if it isn't a float.
@@ -454,6 +630,10 @@ TEST_F(ManifestParserTest, IconDensityParseRules) {
Manifest manifest =
ParseManifest("{ \"icons\": [ {\"src\": \"\", \"density\": {} } ] }");
EXPECT_EQ(manifest.icons[0].density, Manifest::Icon::kDefaultDensity);
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ("Manifest parsing error: icon 'density' ignored, "
+ "must be float greater than 0.",
+ errors()[0]);
}
// Parse fail if it isn't a float.
@@ -461,6 +641,10 @@ TEST_F(ManifestParserTest, IconDensityParseRules) {
Manifest manifest =
ParseManifest("{ \"icons\": [ {\"src\": \"\", \"density\":\"2\" } ] }");
EXPECT_EQ(manifest.icons[0].density, Manifest::Icon::kDefaultDensity);
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ("Manifest parsing error: icon 'density' ignored, "
+ "must be float greater than 0.",
+ errors()[0]);
}
// Edge case: 1.0.
@@ -468,6 +652,7 @@ TEST_F(ManifestParserTest, IconDensityParseRules) {
Manifest manifest =
ParseManifest("{ \"icons\": [ {\"src\": \"\", \"density\": 1.00 } ] }");
EXPECT_EQ(manifest.icons[0].density, 1);
+ EXPECT_EQ(0u, GetErrorCount());
}
// Edge case: values between 0.0 and 1.0 are allowed.
@@ -475,6 +660,7 @@ TEST_F(ManifestParserTest, IconDensityParseRules) {
Manifest manifest =
ParseManifest("{ \"icons\": [ {\"src\": \"\", \"density\": 0.42 } ] }");
EXPECT_EQ(manifest.icons[0].density, 0.42);
+ EXPECT_EQ(0u, GetErrorCount());
}
// 0 is an invalid value.
@@ -482,6 +668,10 @@ TEST_F(ManifestParserTest, IconDensityParseRules) {
Manifest manifest =
ParseManifest("{ \"icons\": [ {\"src\": \"\", \"density\": 0.0 } ] }");
EXPECT_EQ(manifest.icons[0].density, Manifest::Icon::kDefaultDensity);
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ("Manifest parsing error: icon 'density' ignored, "
+ "must be float greater than 0.",
+ errors()[0]);
}
// Negative values are invalid.
@@ -489,6 +679,10 @@ TEST_F(ManifestParserTest, IconDensityParseRules) {
Manifest manifest =
ParseManifest("{ \"icons\": [ {\"src\": \"\", \"density\": -2.5 } ] }");
EXPECT_EQ(manifest.icons[0].density, Manifest::Icon::kDefaultDensity);
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ("Manifest parsing error: icon 'density' ignored, "
+ "must be float greater than 0.",
+ errors()[0]);
}
}
@@ -498,6 +692,7 @@ TEST_F(ManifestParserTest, IconSizesParseRules) {
Manifest manifest = ParseManifest("{ \"icons\": [ {\"src\": \"\","
"\"sizes\": \"42x42\" } ] }");
EXPECT_EQ(manifest.icons[0].sizes.size(), 1u);
+ EXPECT_EQ(0u, GetErrorCount());
}
// Trim whitespaces.
@@ -505,20 +700,29 @@ TEST_F(ManifestParserTest, IconSizesParseRules) {
Manifest manifest = ParseManifest("{ \"icons\": [ {\"src\": \"\","
"\"sizes\": \" 42x42 \" } ] }");
EXPECT_EQ(manifest.icons[0].sizes.size(), 1u);
+ EXPECT_EQ(0u, GetErrorCount());
}
- // Don't parse if name isn't a string.
+ // Ignore sizes if property isn't a string.
{
Manifest manifest = ParseManifest("{ \"icons\": [ {\"src\": \"\","
"\"sizes\": {} } ] }");
EXPECT_EQ(manifest.icons[0].sizes.size(), 0u);
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ("Manifest parsing error: property 'sizes' ignored,"
+ " type string expected.",
+ errors()[0]);
}
- // Don't parse if name isn't a string.
+ // Ignore sizes if property isn't a string.
{
Manifest manifest = ParseManifest("{ \"icons\": [ {\"src\": \"\","
"\"sizes\": 42 } ] }");
EXPECT_EQ(manifest.icons[0].sizes.size(), 0u);
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ("Manifest parsing error: property 'sizes' ignored,"
+ " type string expected.",
+ errors()[0]);
}
// Smoke test: value correctly parsed.
@@ -527,6 +731,7 @@ TEST_F(ManifestParserTest, IconSizesParseRules) {
"\"sizes\": \"42x42 48x48\" } ] }");
EXPECT_EQ(manifest.icons[0].sizes[0], gfx::Size(42, 42));
EXPECT_EQ(manifest.icons[0].sizes[1], gfx::Size(48, 48));
+ EXPECT_EQ(0u, GetErrorCount());
}
// <WIDTH>'x'<HEIGHT> and <WIDTH>'X'<HEIGHT> are equivalent.
@@ -535,6 +740,7 @@ TEST_F(ManifestParserTest, IconSizesParseRules) {
"\"sizes\": \"42X42 48X48\" } ] }");
EXPECT_EQ(manifest.icons[0].sizes[0], gfx::Size(42, 42));
EXPECT_EQ(manifest.icons[0].sizes[1], gfx::Size(48, 48));
+ EXPECT_EQ(0u, GetErrorCount());
}
// Twice the same value is parsed twice.
@@ -543,6 +749,7 @@ TEST_F(ManifestParserTest, IconSizesParseRules) {
"\"sizes\": \"42X42 42x42\" } ] }");
EXPECT_EQ(manifest.icons[0].sizes[0], gfx::Size(42, 42));
EXPECT_EQ(manifest.icons[0].sizes[1], gfx::Size(42, 42));
+ EXPECT_EQ(0u, GetErrorCount());
}
// Width or height can't start with 0.
@@ -550,6 +757,9 @@ TEST_F(ManifestParserTest, IconSizesParseRules) {
Manifest manifest = ParseManifest("{ \"icons\": [ {\"src\": \"\","
"\"sizes\": \"004X007 042x00\" } ] }");
EXPECT_EQ(manifest.icons[0].sizes.size(), 0u);
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ("Manifest parsing error: found icon with no valid size.",
+ errors()[0]);
}
// Width and height MUST contain digits.
@@ -557,6 +767,9 @@ TEST_F(ManifestParserTest, IconSizesParseRules) {
Manifest manifest = ParseManifest("{ \"icons\": [ {\"src\": \"\","
"\"sizes\": \"e4X1.0 55ax1e10\" } ] }");
EXPECT_EQ(manifest.icons[0].sizes.size(), 0u);
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ("Manifest parsing error: found icon with no valid size.",
+ errors()[0]);
}
// 'any' is correctly parsed and transformed to gfx::Size(0,0).
@@ -569,6 +782,7 @@ TEST_F(ManifestParserTest, IconSizesParseRules) {
EXPECT_EQ(manifest.icons[0].sizes[1], any);
EXPECT_EQ(manifest.icons[0].sizes[2], any);
EXPECT_EQ(manifest.icons[0].sizes[3], any);
+ EXPECT_EQ(0u, GetErrorCount());
}
// Some invalid width/height combinations.
@@ -577,6 +791,191 @@ TEST_F(ManifestParserTest, IconSizesParseRules) {
"\"sizes\": \"x 40xx 1x2x3 x42 42xx42\" } ] }");
gfx::Size any = gfx::Size(0, 0);
EXPECT_EQ(manifest.icons[0].sizes.size(), 0u);
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ("Manifest parsing error: found icon with no valid size.",
+ errors()[0]);
+ }
+}
+
+TEST_F(ManifestParserTest, RelatedApplicationsParseRules) {
+ // If no application, empty list.
+ {
+ Manifest manifest = ParseManifest(
+ "{ \"related_applications\": []}");
+ EXPECT_EQ(manifest.related_applications.size(), 0u);
+ EXPECT_TRUE(manifest.IsEmpty());
+ EXPECT_EQ(0u, GetErrorCount());
+ }
+
+ // If empty application, empty list.
+ {
+ Manifest manifest = ParseManifest(
+ "{ \"related_applications\": [{}]}");
+ EXPECT_EQ(manifest.related_applications.size(), 0u);
+ EXPECT_TRUE(manifest.IsEmpty());
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ("Manifest parsing error: 'platform' is a required field, "
+ "related application ignored.",
+ errors()[0]);
+ }
+
+ // If invalid platform, application is ignored.
+ {
+ Manifest manifest = ParseManifest(
+ "{ \"related_applications\": [{\"platform\": 123}]}");
+ EXPECT_EQ(manifest.related_applications.size(), 0u);
+ EXPECT_TRUE(manifest.IsEmpty());
+ EXPECT_EQ(2u, GetErrorCount());
+ EXPECT_EQ(
+ "Manifest parsing error: property 'platform' ignored, type string "
+ "expected.",
+ errors()[0]);
+ EXPECT_EQ("Manifest parsing error: 'platform' is a required field, "
+ "related application ignored.",
+ errors()[1]);
+ }
+
+ // If missing platform, application is ignored.
+ {
+ Manifest manifest = ParseManifest(
+ "{ \"related_applications\": [{\"id\": \"foo\"}]}");
+ EXPECT_EQ(manifest.related_applications.size(), 0u);
+ EXPECT_TRUE(manifest.IsEmpty());
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ("Manifest parsing error: 'platform' is a required field, "
+ "related application ignored.",
+ errors()[0]);
+ }
+
+ // If missing id and url, application is ignored.
+ {
+ Manifest manifest = ParseManifest(
+ "{ \"related_applications\": [{\"platform\": \"play\"}]}");
+ EXPECT_EQ(manifest.related_applications.size(), 0u);
+ EXPECT_TRUE(manifest.IsEmpty());
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ("Manifest parsing error: one of 'url' or 'id' is required, "
+ "related application ignored.",
+ errors()[0]);
+ }
+
+ // Valid application, with url.
+ {
+ Manifest manifest = ParseManifest(
+ "{ \"related_applications\": ["
+ "{\"platform\": \"play\", \"url\": \"http://www.foo.com\"}]}");
+ EXPECT_EQ(manifest.related_applications.size(), 1u);
+ EXPECT_TRUE(EqualsASCII(manifest.related_applications[0].platform.string(),
+ "play"));
+ EXPECT_EQ(manifest.related_applications[0].url.spec(),
+ "http://www.foo.com/");
+ EXPECT_FALSE(manifest.IsEmpty());
+ EXPECT_EQ(0u, GetErrorCount());
+ }
+
+ // Valid application, with id.
+ {
+ Manifest manifest = ParseManifest(
+ "{ \"related_applications\": ["
+ "{\"platform\": \"itunes\", \"id\": \"foo\"}]}");
+ EXPECT_EQ(manifest.related_applications.size(), 1u);
+ EXPECT_TRUE(EqualsASCII(manifest.related_applications[0].platform.string(),
+ "itunes"));
+ EXPECT_TRUE(EqualsASCII(manifest.related_applications[0].id.string(),
+ "foo"));
+ EXPECT_FALSE(manifest.IsEmpty());
+ EXPECT_EQ(0u, GetErrorCount());
+ }
+
+ // All valid applications are in list.
+ {
+ Manifest manifest = ParseManifest(
+ "{ \"related_applications\": ["
+ "{\"platform\": \"play\", \"id\": \"foo\"},"
+ "{\"platform\": \"itunes\", \"id\": \"bar\"}]}");
+ EXPECT_EQ(manifest.related_applications.size(), 2u);
+ EXPECT_TRUE(EqualsASCII(manifest.related_applications[0].platform.string(),
+ "play"));
+ EXPECT_TRUE(EqualsASCII(manifest.related_applications[0].id.string(),
+ "foo"));
+ EXPECT_TRUE(EqualsASCII(manifest.related_applications[1].platform.string(),
+ "itunes"));
+ EXPECT_TRUE(EqualsASCII(manifest.related_applications[1].id.string(),
+ "bar"));
+ EXPECT_FALSE(manifest.IsEmpty());
+ EXPECT_EQ(0u, GetErrorCount());
+ }
+
+ // Two invalid applications and one valid. Only the valid application should
+ // be in the list.
+ {
+ Manifest manifest = ParseManifest(
+ "{ \"related_applications\": ["
+ "{\"platform\": \"itunes\"},"
+ "{\"platform\": \"play\", \"id\": \"foo\"},"
+ "{}]}");
+ EXPECT_EQ(manifest.related_applications.size(), 1u);
+ EXPECT_TRUE(EqualsASCII(manifest.related_applications[0].platform.string(),
+ "play"));
+ EXPECT_TRUE(EqualsASCII(manifest.related_applications[0].id.string(),
+ "foo"));
+ EXPECT_FALSE(manifest.IsEmpty());
+ EXPECT_EQ(2u, GetErrorCount());
+ EXPECT_EQ("Manifest parsing error: one of 'url' or 'id' is required, "
+ "related application ignored.",
+ errors()[0]);
+ EXPECT_EQ("Manifest parsing error: 'platform' is a required field, "
+ "related application ignored.",
+ errors()[1]);
+ }
+}
+
+TEST_F(ManifestParserTest, ParsePreferRelatedApplicationsParseRules) {
+ // Smoke test.
+ {
+ Manifest manifest =
+ ParseManifest("{ \"prefer_related_applications\": true }");
+ EXPECT_TRUE(manifest.prefer_related_applications);
+ EXPECT_EQ(0u, GetErrorCount());
+ }
+
+ // Don't parse if the property isn't a boolean.
+ {
+ Manifest manifest =
+ ParseManifest("{ \"prefer_related_applications\": {} }");
+ EXPECT_FALSE(manifest.prefer_related_applications);
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ(
+ "Manifest parsing error: property 'prefer_related_applications' "
+ "ignored, type boolean expected.",
+ errors()[0]);
+ }
+ {
+ Manifest manifest = ParseManifest(
+ "{ \"prefer_related_applications\": \"true\" }");
+ EXPECT_FALSE(manifest.prefer_related_applications);
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ(
+ "Manifest parsing error: property 'prefer_related_applications' "
+ "ignored, type boolean expected.",
+ errors()[0]);
+ }
+ {
+ Manifest manifest = ParseManifest("{ \"prefer_related_applications\": 1 }");
+ EXPECT_FALSE(manifest.prefer_related_applications);
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ(
+ "Manifest parsing error: property 'prefer_related_applications' "
+ "ignored, type boolean expected.",
+ errors()[0]);
+ }
+
+ // "False" should set the boolean false without throwing errors.
+ {
+ Manifest manifest =
+ ParseManifest("{ \"prefer_related_applications\": false }");
+ EXPECT_FALSE(manifest.prefer_related_applications);
+ EXPECT_EQ(0u, GetErrorCount());
}
}
@@ -585,22 +984,78 @@ TEST_F(ManifestParserTest, GCMSenderIDParseRules) {
{
Manifest manifest = ParseManifest("{ \"gcm_sender_id\": \"foo\" }");
EXPECT_TRUE(EqualsASCII(manifest.gcm_sender_id.string(), "foo"));
+ EXPECT_EQ(0u, GetErrorCount());
}
// Trim whitespaces.
{
Manifest manifest = ParseManifest("{ \"gcm_sender_id\": \" foo \" }");
EXPECT_TRUE(EqualsASCII(manifest.gcm_sender_id.string(), "foo"));
+ EXPECT_EQ(0u, GetErrorCount());
}
- // Don't parse if property isn't a string.
+ // Don't parse if the property isn't a string.
{
Manifest manifest = ParseManifest("{ \"gcm_sender_id\": {} }");
EXPECT_TRUE(manifest.gcm_sender_id.is_null());
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ("Manifest parsing error: property 'gcm_sender_id' ignored,"
+ " type string expected.",
+ errors()[0]);
}
{
Manifest manifest = ParseManifest("{ \"gcm_sender_id\": 42 }");
EXPECT_TRUE(manifest.gcm_sender_id.is_null());
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ("Manifest parsing error: property 'gcm_sender_id' ignored,"
+ " type string expected.",
+ errors()[0]);
+ }
+}
+
+TEST_F(ManifestParserTest, GCMUserVisibleOnlyParseRules) {
+ // Smoke test.
+ {
+ Manifest manifest = ParseManifest("{ \"gcm_user_visible_only\": true }");
+ EXPECT_TRUE(manifest.gcm_user_visible_only);
+ EXPECT_EQ(0u, GetErrorCount());
+ }
+
+ // Don't parse if the property isn't a boolean.
+ {
+ Manifest manifest = ParseManifest("{ \"gcm_user_visible_only\": {} }");
+ EXPECT_FALSE(manifest.gcm_user_visible_only);
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ(
+ "Manifest parsing error: property 'gcm_user_visible_only' ignored,"
+ " type boolean expected.",
+ errors()[0]);
+ }
+ {
+ Manifest manifest = ParseManifest(
+ "{ \"gcm_user_visible_only\": \"true\" }");
+ EXPECT_FALSE(manifest.gcm_user_visible_only);
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ(
+ "Manifest parsing error: property 'gcm_user_visible_only' ignored,"
+ " type boolean expected.",
+ errors()[0]);
+ }
+ {
+ Manifest manifest = ParseManifest("{ \"gcm_user_visible_only\": 1 }");
+ EXPECT_FALSE(manifest.gcm_user_visible_only);
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ(
+ "Manifest parsing error: property 'gcm_user_visible_only' ignored,"
+ " type boolean expected.",
+ errors()[0]);
+ }
+
+ // "False" should set the boolean false without throwing errors.
+ {
+ Manifest manifest = ParseManifest("{ \"gcm_user_visible_only\": false }");
+ EXPECT_FALSE(manifest.gcm_user_visible_only);
+ EXPECT_EQ(0u, GetErrorCount());
}
}
diff --git a/chromium/content/renderer/manifest/manifest_uma_util.h b/chromium/content/renderer/manifest/manifest_uma_util.h
index 9498145a1d8..9930f55907e 100644
--- a/chromium/content/renderer/manifest/manifest_uma_util.h
+++ b/chromium/content/renderer/manifest/manifest_uma_util.h
@@ -34,4 +34,4 @@ class ManifestUmaUtil {
} // namespace content
-#endif // CONTENT_RENDERER_MANIFEST_MANIFEST_UMA_UTIL_H_
+#endif // CONTENT_RENDERER_MANIFEST_MANIFEST_UMA_UTIL_H_
diff --git a/chromium/content/renderer/media/DEPS b/chromium/content/renderer/media/DEPS
new file mode 100644
index 00000000000..a6cd8ede329
--- /dev/null
+++ b/chromium/content/renderer/media/DEPS
@@ -0,0 +1,6 @@
+include_rules = [
+ # For video copying, cropping and scaling.
+ # TODO(wuchengli): remove this when RTCVideoEncoder supports zero copy.
+ "+third_party/libyuv",
+]
+
diff --git a/chromium/content/renderer/media/OWNERS b/chromium/content/renderer/media/OWNERS
index 1aa4b630692..58193fa3db3 100644
--- a/chromium/content/renderer/media/OWNERS
+++ b/chromium/content/renderer/media/OWNERS
@@ -1,17 +1,18 @@
dalecurtis@chromium.org
ddorwin@chromium.org
-perkj@chromium.org
+jrummell@chromium.org
+sandersd@chromium.org
scherkus@chromium.org
-tommi@chromium.org
-vrk@chromium.org
wolenetz@chromium.org
xhwang@chromium.org
-xians@chromium.org
-per-file cast_*=hclam@chromium.org
+# WebRTC OWNERS.
+perkj@chromium.org
+tommi@chromium.org
+
+# Cast Streaming OWNERS.
per-file cast_*=hubbe@chromium.org
-per-file cast_*=mikhal@chromium.org
-per-file cast_*=pwestin@google.com
+per-file cast_*=miu@chromium.org
per-file midi_*=toyoshim@chromium.org
per-file renderer_webmidi*=toyoshim@chromium.org
diff --git a/chromium/content/renderer/media/android/audio_decoder_android.cc b/chromium/content/renderer/media/android/audio_decoder_android.cc
index f3e118ce641..73a92257aaa 100644
--- a/chromium/content/renderer/media/android/audio_decoder_android.cc
+++ b/chromium/content/renderer/media/android/audio_decoder_android.cc
@@ -309,10 +309,10 @@ bool WAVEDecoder::CopyDataChunkToBus(blink::WebAudioBus* destination_bus) {
return false;
}
- VLOG(0) << "Decoding WAVE file: " << number_of_channels_ << " channels, "
- << sample_rate_ << " kHz, "
- << chunk_size_ / bytes_per_sample_ / number_of_channels_
- << " frames, " << 8 * bytes_per_sample_ << " bits/sample";
+ DVLOG(0) << "Decoding WAVE file: " << number_of_channels_ << " channels, "
+ << sample_rate_ << " kHz, "
+ << chunk_size_ / bytes_per_sample_ / number_of_channels_
+ << " frames, " << 8 * bytes_per_sample_ << " bits/sample";
// Create the destination bus of the appropriate size and then decode
// the data into the bus.
diff --git a/chromium/content/renderer/media/android/media_source_delegate.cc b/chromium/content/renderer/media/android/media_source_delegate.cc
index 504a08f3088..927057cafeb 100644
--- a/chromium/content/renderer/media/android/media_source_delegate.cc
+++ b/chromium/content/renderer/media/android/media_source_delegate.cc
@@ -40,11 +40,6 @@ const uint8 kVorbisPadding[] = { 0xff, 0xff, 0xff, 0xff };
namespace content {
-static void LogMediaSourceError(const scoped_refptr<media::MediaLog>& media_log,
- const std::string& error) {
- media_log->AddEvent(media_log->CreateMediaSourceErrorEvent(error));
-}
-
MediaSourceDelegate::MediaSourceDelegate(
RendererDemuxerAndroid* demuxer_client,
int demuxer_client_id,
@@ -65,8 +60,8 @@ MediaSourceDelegate::MediaSourceDelegate(
main_task_runner_(base::MessageLoopProxy::current()),
media_task_runner_(media_task_runner),
main_weak_factory_(this),
- media_weak_factory_(this),
- main_weak_this_(main_weak_factory_.GetWeakPtr()) {
+ media_weak_factory_(this) {
+ main_weak_this_ = main_weak_factory_.GetWeakPtr();
DCHECK(main_task_runner_->BelongsToCurrentThread());
}
@@ -148,25 +143,29 @@ void MediaSourceDelegate::StopDemuxer(const base::Closure& stop_cb) {
void MediaSourceDelegate::InitializeMediaSource(
const MediaSourceOpenedCB& media_source_opened_cb,
- const media::Demuxer::NeedKeyCB& need_key_cb,
+ const media::Demuxer::EncryptedMediaInitDataCB&
+ encrypted_media_init_data_cb,
const media::SetDecryptorReadyCB& set_decryptor_ready_cb,
const UpdateNetworkStateCB& update_network_state_cb,
- const DurationChangeCB& duration_change_cb) {
+ const DurationChangeCB& duration_change_cb,
+ const base::Closure& waiting_for_decryption_key_cb) {
DCHECK(main_task_runner_->BelongsToCurrentThread());
DCHECK(!media_source_opened_cb.is_null());
media_source_opened_cb_ = media_source_opened_cb;
- need_key_cb_ = need_key_cb;
- set_decryptor_ready_cb_ = set_decryptor_ready_cb;
+ encrypted_media_init_data_cb_ = encrypted_media_init_data_cb;
+ set_decryptor_ready_cb_ = media::BindToCurrentLoop(set_decryptor_ready_cb);
update_network_state_cb_ = media::BindToCurrentLoop(update_network_state_cb);
duration_change_cb_ = duration_change_cb;
+ waiting_for_decryption_key_cb_ =
+ media::BindToCurrentLoop(waiting_for_decryption_key_cb);
access_unit_size_ = kAccessUnitSizeForMediaSource;
chunk_demuxer_.reset(new media::ChunkDemuxer(
media::BindToCurrentLoop(
base::Bind(&MediaSourceDelegate::OnDemuxerOpened, main_weak_this_)),
- media::BindToCurrentLoop(
- base::Bind(&MediaSourceDelegate::OnNeedKey, main_weak_this_)),
- base::Bind(&LogMediaSourceError, media_log_),
+ media::BindToCurrentLoop(base::Bind(
+ &MediaSourceDelegate::OnEncryptedMediaInitData, main_weak_this_)),
+ base::Bind(&media::MediaLog::AddLogEvent, media_log_), media_log_,
false));
// |this| will be retained until StopDemuxer() is posted, so Unretained() is
@@ -413,10 +412,11 @@ void MediaSourceDelegate::OnBufferReady(
case DemuxerStream::kOk:
data->access_units[index].status = status;
if (buffer->end_of_stream()) {
- data->access_units[index].end_of_stream = true;
+ data->access_units[index].is_end_of_stream = true;
data->access_units.resize(index + 1);
break;
}
+ data->access_units[index].is_key_frame = buffer->is_key_frame();
// TODO(ycheo): We assume that the inputed stream will be decoded
// right away.
// Need to implement this properly using MediaPlayer.OnInfoListener.
@@ -520,7 +520,8 @@ void MediaSourceDelegate::InitAudioDecryptingDemuxerStream() {
DCHECK(!set_decryptor_ready_cb_.is_null());
audio_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream(
- media_task_runner_, set_decryptor_ready_cb_));
+ media_task_runner_, set_decryptor_ready_cb_,
+ waiting_for_decryption_key_cb_));
audio_decrypting_demuxer_stream_->Initialize(
audio_stream_,
base::Bind(&MediaSourceDelegate::OnAudioDecryptingDemuxerStreamInitDone,
@@ -533,7 +534,8 @@ void MediaSourceDelegate::InitVideoDecryptingDemuxerStream() {
DCHECK(!set_decryptor_ready_cb_.is_null());
video_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream(
- media_task_runner_, set_decryptor_ready_cb_));
+ media_task_runner_, set_decryptor_ready_cb_,
+ waiting_for_decryption_key_cb_));
video_decrypting_demuxer_stream_->Initialize(
video_stream_,
base::Bind(&MediaSourceDelegate::OnVideoDecryptingDemuxerStreamInitDone,
@@ -663,16 +665,18 @@ void MediaSourceDelegate::OnDemuxerOpened() {
return;
media_source_opened_cb_.Run(new media::WebMediaSourceImpl(
- chunk_demuxer_.get(), base::Bind(&LogMediaSourceError, media_log_)));
+ chunk_demuxer_.get(),
+ base::Bind(&media::MediaLog::AddLogEvent, media_log_)));
}
-void MediaSourceDelegate::OnNeedKey(const std::string& type,
- const std::vector<uint8>& init_data) {
+void MediaSourceDelegate::OnEncryptedMediaInitData(
+ media::EmeInitDataType init_data_type,
+ const std::vector<uint8>& init_data) {
DCHECK(main_task_runner_->BelongsToCurrentThread());
- if (need_key_cb_.is_null())
+ if (encrypted_media_init_data_cb_.is_null())
return;
- need_key_cb_.Run(type, init_data);
+ encrypted_media_init_data_cb_.Run(init_data_type, init_data);
}
bool MediaSourceDelegate::IsSeeking() const {
@@ -735,6 +739,13 @@ bool MediaSourceDelegate::GetDemuxerConfigFromStream(
configs->is_audio_encrypted = config.is_encrypted();
configs->audio_extra_data = std::vector<uint8>(
config.extra_data(), config.extra_data() + config.extra_data_size());
+ configs->audio_codec_delay_ns = static_cast<int64_t>(
+ config.codec_delay() *
+ (static_cast<double>(base::Time::kNanosecondsPerSecond) /
+ config.samples_per_second()));
+ configs->audio_seek_preroll_ns =
+ config.seek_preroll().InMicroseconds() *
+ base::Time::kNanosecondsPerMicrosecond;
return true;
}
if (!is_audio && video_stream_) {
diff --git a/chromium/content/renderer/media/android/media_source_delegate.h b/chromium/content/renderer/media/android/media_source_delegate.h
index c451e0724ae..e64423080a5 100644
--- a/chromium/content/renderer/media/android/media_source_delegate.h
+++ b/chromium/content/renderer/media/android/media_source_delegate.h
@@ -52,16 +52,18 @@ class MediaSourceDelegate : public media::DemuxerHost {
int demuxer_client_id,
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
const scoped_refptr<media::MediaLog> media_log);
- virtual ~MediaSourceDelegate();
+ ~MediaSourceDelegate() override;
// Initialize the MediaSourceDelegate. |media_source| will be owned by
// this object after this call.
void InitializeMediaSource(
const MediaSourceOpenedCB& media_source_opened_cb,
- const media::Demuxer::NeedKeyCB& need_key_cb,
+ const media::Demuxer::EncryptedMediaInitDataCB&
+ encrypted_media_init_data_cb,
const media::SetDecryptorReadyCB& set_decryptor_ready_cb,
const UpdateNetworkStateCB& update_network_state_cb,
- const DurationChangeCB& duration_change_cb);
+ const DurationChangeCB& duration_change_cb,
+ const base::Closure& waiting_for_decryption_key_cb);
blink::WebTimeRanges Buffered() const;
size_t DecodedFrameCount() const;
@@ -104,13 +106,13 @@ class MediaSourceDelegate : public media::DemuxerHost {
private:
// Methods inherited from DemuxerHost.
- virtual void AddBufferedTimeRange(base::TimeDelta start,
- base::TimeDelta end) override;
- virtual void SetDuration(base::TimeDelta duration) override;
- virtual void OnDemuxerError(media::PipelineStatus status) override;
- virtual void AddTextStream(media::DemuxerStream* text_stream,
- const media::TextTrackConfig& config) override;
- virtual void RemoveTextStream(media::DemuxerStream* text_stream) override;
+ void AddBufferedTimeRange(base::TimeDelta start,
+ base::TimeDelta end) override;
+ void SetDuration(base::TimeDelta duration) override;
+ void OnDemuxerError(media::PipelineStatus status) override;
+ void AddTextStream(media::DemuxerStream* text_stream,
+ const media::TextTrackConfig& config) override;
+ void RemoveTextStream(media::DemuxerStream* text_stream) override;
// Notifies |demuxer_client_| and fires |duration_changed_cb_|.
void OnDurationChanged(const base::TimeDelta& duration);
@@ -136,8 +138,8 @@ class MediaSourceDelegate : public media::DemuxerHost {
void FinishResettingDecryptingDemuxerStreams();
void OnDemuxerOpened();
- void OnNeedKey(const std::string& type,
- const std::vector<uint8>& init_data);
+ void OnEncryptedMediaInitData(media::EmeInitDataType init_data_type,
+ const std::vector<uint8>& init_data);
void NotifyDemuxerReady();
// Stops and clears objects on the media thread.
@@ -196,11 +198,8 @@ class MediaSourceDelegate : public media::DemuxerHost {
media::Ranges<base::TimeDelta> buffered_time_ranges_;
MediaSourceOpenedCB media_source_opened_cb_;
- media::Demuxer::NeedKeyCB need_key_cb_;
-
- // Temporary for EME v0.1. In the future the init data type should be passed
- // through GenerateKeyRequest() directly from WebKit.
- std::string init_data_type_;
+ media::Demuxer::EncryptedMediaInitDataCB encrypted_media_init_data_cb_;
+ base::Closure waiting_for_decryption_key_cb_;
// Lock used to serialize access for |seeking_|.
mutable base::Lock seeking_lock_;
@@ -226,9 +225,9 @@ class MediaSourceDelegate : public media::DemuxerHost {
const scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_;
// NOTE: Weak pointers must be invalidated before all other member variables.
+ base::WeakPtr<MediaSourceDelegate> main_weak_this_;
base::WeakPtrFactory<MediaSourceDelegate> main_weak_factory_;
base::WeakPtrFactory<MediaSourceDelegate> media_weak_factory_;
- base::WeakPtr<MediaSourceDelegate> main_weak_this_;
DISALLOW_COPY_AND_ASSIGN(MediaSourceDelegate);
};
diff --git a/chromium/content/renderer/media/android/renderer_demuxer_android.h b/chromium/content/renderer/media/android/renderer_demuxer_android.h
index 2fddc862048..29469edebb6 100644
--- a/chromium/content/renderer/media/android/renderer_demuxer_android.h
+++ b/chromium/content/renderer/media/android/renderer_demuxer_android.h
@@ -44,7 +44,7 @@ class RendererDemuxerAndroid : public IPC::MessageFilter {
void RemoveDelegate(int demuxer_client_id);
// IPC::MessageFilter overrides.
- virtual bool OnMessageReceived(const IPC::Message& message) override;
+ bool OnMessageReceived(const IPC::Message& message) override;
// media::DemuxerAndroidClient "implementation".
//
@@ -61,7 +61,7 @@ class RendererDemuxerAndroid : public IPC::MessageFilter {
protected:
friend class base::RefCountedThreadSafe<RendererDemuxerAndroid>;
- virtual ~RendererDemuxerAndroid();
+ ~RendererDemuxerAndroid() override;
private:
void DispatchMessage(const IPC::Message& message);
diff --git a/chromium/content/renderer/media/android/renderer_media_player_manager.cc b/chromium/content/renderer/media/android/renderer_media_player_manager.cc
index 9295b790280..9957ced350c 100644
--- a/chromium/content/renderer/media/android/renderer_media_player_manager.cc
+++ b/chromium/content/renderer/media/android/renderer_media_player_manager.cc
@@ -10,16 +10,15 @@
#include "content/renderer/media/android/webmediaplayer_android.h"
#include "content/renderer/media/crypto/renderer_cdm_manager.h"
#include "content/renderer/render_view_impl.h"
-#include "ui/gfx/rect_f.h"
+#include "media/base/cdm_context.h"
+#include "ui/gfx/geometry/rect_f.h"
namespace content {
RendererMediaPlayerManager::RendererMediaPlayerManager(
RenderFrame* render_frame)
: RenderFrameObserver(render_frame),
- next_media_player_id_(0),
- fullscreen_frame_(NULL),
- pending_fullscreen_frame_(NULL) {
+ next_media_player_id_(0) {
}
RendererMediaPlayerManager::~RendererMediaPlayerManager() {
@@ -43,6 +42,8 @@ bool RendererMediaPlayerManager::OnMessageReceived(const IPC::Message& msg) {
IPC_MESSAGE_HANDLER(MediaPlayerMsg_MediaVideoSizeChanged,
OnVideoSizeChanged)
IPC_MESSAGE_HANDLER(MediaPlayerMsg_MediaTimeUpdate, OnTimeUpdate)
+ IPC_MESSAGE_HANDLER(MediaPlayerMsg_WaitingForDecryptionKey,
+ OnWaitingForDecryptionKey)
IPC_MESSAGE_HANDLER(MediaPlayerMsg_MediaPlayerReleased,
OnMediaPlayerReleased)
IPC_MESSAGE_HANDLER(MediaPlayerMsg_ConnectedToRemoteDevice,
@@ -51,7 +52,6 @@ bool RendererMediaPlayerManager::OnMessageReceived(const IPC::Message& msg) {
OnDisconnectedFromRemoteDevice)
IPC_MESSAGE_HANDLER(MediaPlayerMsg_RequestFullscreen,
OnRequestFullscreen)
- IPC_MESSAGE_HANDLER(MediaPlayerMsg_DidEnterFullscreen, OnDidEnterFullscreen)
IPC_MESSAGE_HANDLER(MediaPlayerMsg_DidExitFullscreen, OnDidExitFullscreen)
IPC_MESSAGE_HANDLER(MediaPlayerMsg_DidMediaPlayerPlay, OnPlayerPlay)
IPC_MESSAGE_HANDLER(MediaPlayerMsg_DidMediaPlayerPause, OnPlayerPause)
@@ -191,6 +191,12 @@ void RendererMediaPlayerManager::OnTimeUpdate(
player->OnTimeUpdate(current_timestamp, current_time_ticks);
}
+void RendererMediaPlayerManager::OnWaitingForDecryptionKey(int player_id) {
+ WebMediaPlayerAndroid* player = GetMediaPlayer(player_id);
+ if (player)
+ player->OnWaitingForDecryptionKey();
+}
+
void RendererMediaPlayerManager::OnMediaPlayerReleased(int player_id) {
WebMediaPlayerAndroid* player = GetMediaPlayer(player_id);
if (player)
@@ -210,12 +216,6 @@ void RendererMediaPlayerManager::OnDisconnectedFromRemoteDevice(int player_id) {
player->OnDisconnectedFromRemoteDevice();
}
-void RendererMediaPlayerManager::OnDidEnterFullscreen(int player_id) {
- WebMediaPlayerAndroid* player = GetMediaPlayer(player_id);
- if (player)
- player->OnDidEnterFullscreen();
-}
-
void RendererMediaPlayerManager::OnDidExitFullscreen(int player_id) {
WebMediaPlayerAndroid* player = GetMediaPlayer(player_id);
if (player)
@@ -248,20 +248,16 @@ void RendererMediaPlayerManager::OnRemoteRouteAvailabilityChanged(
player->OnRemoteRouteAvailabilityChanged(routes_available);
}
-void RendererMediaPlayerManager::EnterFullscreen(int player_id,
- blink::WebFrame* frame) {
- pending_fullscreen_frame_ = frame;
+void RendererMediaPlayerManager::EnterFullscreen(int player_id) {
Send(new MediaPlayerHostMsg_EnterFullscreen(routing_id(), player_id));
}
void RendererMediaPlayerManager::ExitFullscreen(int player_id) {
- pending_fullscreen_frame_ = NULL;
- fullscreen_frame_ = NULL;
Send(new MediaPlayerHostMsg_ExitFullscreen(routing_id(), player_id));
}
void RendererMediaPlayerManager::SetCdm(int player_id, int cdm_id) {
- if (cdm_id == media::MediaKeys::kInvalidCdmId) {
+ if (cdm_id == media::CdmContext::kInvalidCdmId) {
NOTREACHED();
return;
}
@@ -299,28 +295,6 @@ WebMediaPlayerAndroid* RendererMediaPlayerManager::GetMediaPlayer(
return NULL;
}
-bool RendererMediaPlayerManager::CanEnterFullscreen(blink::WebFrame* frame) {
- return (!fullscreen_frame_ && !pending_fullscreen_frame_)
- || ShouldEnterFullscreen(frame);
-}
-
-void RendererMediaPlayerManager::DidEnterFullscreen(blink::WebFrame* frame) {
- pending_fullscreen_frame_ = NULL;
- fullscreen_frame_ = frame;
-}
-
-void RendererMediaPlayerManager::DidExitFullscreen() {
- fullscreen_frame_ = NULL;
-}
-
-bool RendererMediaPlayerManager::IsInFullscreen(blink::WebFrame* frame) {
- return fullscreen_frame_ == frame;
-}
-
-bool RendererMediaPlayerManager::ShouldEnterFullscreen(blink::WebFrame* frame) {
- return fullscreen_frame_ == frame || pending_fullscreen_frame_ == frame;
-}
-
#if defined(VIDEO_HOLE)
void RendererMediaPlayerManager::RequestExternalSurface(
int player_id,
diff --git a/chromium/content/renderer/media/android/renderer_media_player_manager.h b/chromium/content/renderer/media/android/renderer_media_player_manager.h
index 8a9fbb3763b..335c38a8333 100644
--- a/chromium/content/renderer/media/android/renderer_media_player_manager.h
+++ b/chromium/content/renderer/media/android/renderer_media_player_manager.h
@@ -34,11 +34,11 @@ class RendererMediaPlayerManager : public RenderFrameObserver {
public:
// Constructs a RendererMediaPlayerManager object for the |render_frame|.
explicit RendererMediaPlayerManager(RenderFrame* render_frame);
- virtual ~RendererMediaPlayerManager();
+ ~RendererMediaPlayerManager() override;
// RenderFrameObserver overrides.
- virtual bool OnMessageReceived(const IPC::Message& msg) override;
- virtual void WasHidden() override;
+ bool OnMessageReceived(const IPC::Message& msg) override;
+ void WasHidden() override;
// Initializes a MediaPlayerAndroid object in browser process.
void Initialize(MediaPlayerHostMsg_Initialize_Type type,
@@ -81,7 +81,7 @@ class RendererMediaPlayerManager : public RenderFrameObserver {
void RequestRemotePlaybackControl(int player_id);
// Requests the player to enter fullscreen.
- void EnterFullscreen(int player_id, blink::WebFrame* frame);
+ void EnterFullscreen(int player_id);
// Requests the player to exit fullscreen.
void ExitFullscreen(int player_id);
@@ -96,7 +96,7 @@ class RendererMediaPlayerManager : public RenderFrameObserver {
void RequestExternalSurface(int player_id, const gfx::RectF& geometry);
// RenderFrameObserver overrides.
- virtual void DidCommitCompositorFrame() override;
+ void DidCommitCompositorFrame() override;
// Returns true if a media player should use video-overlay for the embedded
// encrypted video.
@@ -107,19 +107,6 @@ class RendererMediaPlayerManager : public RenderFrameObserver {
int RegisterMediaPlayer(WebMediaPlayerAndroid* player);
void UnregisterMediaPlayer(int player_id);
- // Checks whether a player can enter fullscreen.
- bool CanEnterFullscreen(blink::WebFrame* frame);
-
- // Called when a player entered or exited fullscreen.
- void DidEnterFullscreen(blink::WebFrame* frame);
- void DidExitFullscreen();
-
- // Checks whether the Webframe is in fullscreen.
- bool IsInFullscreen(blink::WebFrame* frame);
-
- // True if a newly created media player should enter fullscreen.
- bool ShouldEnterFullscreen(blink::WebFrame* frame);
-
// Gets the pointer to WebMediaPlayerAndroid given the |player_id|.
WebMediaPlayerAndroid* GetMediaPlayer(int player_id);
@@ -145,6 +132,7 @@ class RendererMediaPlayerManager : public RenderFrameObserver {
void OnTimeUpdate(int player_id,
base::TimeDelta current_timestamp,
base::TimeTicks current_time_ticks);
+ void OnWaitingForDecryptionKey(int player_id);
void OnMediaPlayerReleased(int player_id);
void OnConnectedToRemoteDevice(int player_id,
const std::string& remote_playback_message);
@@ -168,12 +156,6 @@ class RendererMediaPlayerManager : public RenderFrameObserver {
int next_media_player_id_;
- // WebFrame of the fullscreen video.
- blink::WebFrame* fullscreen_frame_;
-
- // WebFrame of pending fullscreen request.
- blink::WebFrame* pending_fullscreen_frame_;
-
DISALLOW_COPY_AND_ASSIGN(RendererMediaPlayerManager);
};
diff --git a/chromium/content/renderer/media/android/stream_texture_factory.h b/chromium/content/renderer/media/android/stream_texture_factory.h
index 8d048007635..deb6dfebacf 100644
--- a/chromium/content/renderer/media/android/stream_texture_factory.h
+++ b/chromium/content/renderer/media/android/stream_texture_factory.h
@@ -10,7 +10,7 @@
#include "base/message_loop/message_loop_proxy.h"
#include "cc/layers/video_frame_provider.h"
#include "gpu/command_buffer/common/mailbox.h"
-#include "ui/gfx/size.h"
+#include "ui/gfx/geometry/size.h"
namespace gpu {
namespace gles2 {
diff --git a/chromium/content/renderer/media/android/stream_texture_factory_impl.cc b/chromium/content/renderer/media/android/stream_texture_factory_impl.cc
index 48b5861ddb6..e67fee9a7f1 100644
--- a/chromium/content/renderer/media/android/stream_texture_factory_impl.cc
+++ b/chromium/content/renderer/media/android/stream_texture_factory_impl.cc
@@ -9,7 +9,7 @@
#include "content/common/gpu/gpu_messages.h"
#include "content/renderer/gpu/stream_texture_host_android.h"
#include "gpu/command_buffer/client/gles2_interface.h"
-#include "ui/gfx/size.h"
+#include "ui/gfx/geometry/size.h"
namespace content {
@@ -19,17 +19,17 @@ class StreamTextureProxyImpl : public StreamTextureProxy,
public StreamTextureHost::Listener {
public:
explicit StreamTextureProxyImpl(StreamTextureHost* host);
- virtual ~StreamTextureProxyImpl();
+ ~StreamTextureProxyImpl() override;
// StreamTextureProxy implementation:
- virtual void BindToLoop(int32 stream_id,
- cc::VideoFrameProvider::Client* client,
- scoped_refptr<base::MessageLoopProxy> loop) override;
- virtual void Release() override;
+ void BindToLoop(int32 stream_id,
+ cc::VideoFrameProvider::Client* client,
+ scoped_refptr<base::MessageLoopProxy> loop) override;
+ void Release() override;
// StreamTextureHost::Listener implementation:
- virtual void OnFrameAvailable() override;
- virtual void OnMatrixChanged(const float matrix[16]) override;
+ void OnFrameAvailable() override;
+ void OnMatrixChanged(const float matrix[16]) override;
private:
void BindOnThread(int32 stream_id);
diff --git a/chromium/content/renderer/media/android/stream_texture_factory_impl.h b/chromium/content/renderer/media/android/stream_texture_factory_impl.h
index f5ded1c8b05..0374879a39a 100644
--- a/chromium/content/renderer/media/android/stream_texture_factory_impl.h
+++ b/chromium/content/renderer/media/android/stream_texture_factory_impl.h
@@ -29,17 +29,15 @@ class StreamTextureFactoryImpl : public StreamTextureFactory {
int frame_id);
// StreamTextureFactory implementation.
- virtual StreamTextureProxy* CreateProxy() override;
- virtual void EstablishPeer(int32 stream_id, int player_id) override;
- virtual unsigned CreateStreamTexture(unsigned texture_target,
- unsigned* texture_id,
- gpu::Mailbox* texture_mailbox) override;
- virtual void SetStreamTextureSize(int32 texture_id,
- const gfx::Size& size) override;
- virtual gpu::gles2::GLES2Interface* ContextGL() override;
- virtual void AddObserver(StreamTextureFactoryContextObserver* obs) override;
- virtual void RemoveObserver(
- StreamTextureFactoryContextObserver* obs) override;
+ StreamTextureProxy* CreateProxy() override;
+ void EstablishPeer(int32 stream_id, int player_id) override;
+ unsigned CreateStreamTexture(unsigned texture_target,
+ unsigned* texture_id,
+ gpu::Mailbox* texture_mailbox) override;
+ void SetStreamTextureSize(int32 texture_id, const gfx::Size& size) override;
+ gpu::gles2::GLES2Interface* ContextGL() override;
+ void AddObserver(StreamTextureFactoryContextObserver* obs) override;
+ void RemoveObserver(StreamTextureFactoryContextObserver* obs) override;
private:
friend class base::RefCounted<StreamTextureFactoryImpl>;
@@ -47,7 +45,7 @@ class StreamTextureFactoryImpl : public StreamTextureFactory {
const scoped_refptr<cc::ContextProvider>& context_provider,
GpuChannelHost* channel,
int frame_id);
- virtual ~StreamTextureFactoryImpl();
+ ~StreamTextureFactoryImpl() override;
scoped_refptr<cc::ContextProvider> context_provider_;
scoped_refptr<GpuChannelHost> channel_;
diff --git a/chromium/content/renderer/media/android/stream_texture_factory_synchronous_impl.cc b/chromium/content/renderer/media/android/stream_texture_factory_synchronous_impl.cc
index c6eb63d931d..9c0d61ab861 100644
--- a/chromium/content/renderer/media/android/stream_texture_factory_synchronous_impl.cc
+++ b/chromium/content/renderer/media/android/stream_texture_factory_synchronous_impl.cc
@@ -31,13 +31,13 @@ class StreamTextureProxyImpl
public:
explicit StreamTextureProxyImpl(
StreamTextureFactorySynchronousImpl::ContextProvider* provider);
- virtual ~StreamTextureProxyImpl();
+ ~StreamTextureProxyImpl() override;
// StreamTextureProxy implementation:
- virtual void BindToLoop(int32 stream_id,
- cc::VideoFrameProvider::Client* client,
- scoped_refptr<base::MessageLoopProxy> loop) override;
- virtual void Release() override;
+ void BindToLoop(int32 stream_id,
+ cc::VideoFrameProvider::Client* client,
+ scoped_refptr<base::MessageLoopProxy> loop) override;
+ void Release() override;
private:
void BindOnThread(int32 stream_id);
diff --git a/chromium/content/renderer/media/android/stream_texture_factory_synchronous_impl.h b/chromium/content/renderer/media/android/stream_texture_factory_synchronous_impl.h
index 3f33bd39b1a..1e2db8a539c 100644
--- a/chromium/content/renderer/media/android/stream_texture_factory_synchronous_impl.h
+++ b/chromium/content/renderer/media/android/stream_texture_factory_synchronous_impl.h
@@ -47,24 +47,22 @@ class StreamTextureFactorySynchronousImpl : public StreamTextureFactory {
const CreateContextProviderCallback& try_create_callback,
int frame_id);
- virtual StreamTextureProxy* CreateProxy() override;
- virtual void EstablishPeer(int32 stream_id, int player_id) override;
- virtual unsigned CreateStreamTexture(unsigned texture_target,
- unsigned* texture_id,
- gpu::Mailbox* texture_mailbox) override;
- virtual void SetStreamTextureSize(int32 stream_id,
- const gfx::Size& size) override;
- virtual gpu::gles2::GLES2Interface* ContextGL() override;
- virtual void AddObserver(StreamTextureFactoryContextObserver* obs) override;
- virtual void RemoveObserver(
- StreamTextureFactoryContextObserver* obs) override;
+ StreamTextureProxy* CreateProxy() override;
+ void EstablishPeer(int32 stream_id, int player_id) override;
+ unsigned CreateStreamTexture(unsigned texture_target,
+ unsigned* texture_id,
+ gpu::Mailbox* texture_mailbox) override;
+ void SetStreamTextureSize(int32 stream_id, const gfx::Size& size) override;
+ gpu::gles2::GLES2Interface* ContextGL() override;
+ void AddObserver(StreamTextureFactoryContextObserver* obs) override;
+ void RemoveObserver(StreamTextureFactoryContextObserver* obs) override;
private:
friend class base::RefCounted<StreamTextureFactorySynchronousImpl>;
StreamTextureFactorySynchronousImpl(
const CreateContextProviderCallback& try_create_callback,
int frame_id);
- virtual ~StreamTextureFactorySynchronousImpl();
+ ~StreamTextureFactorySynchronousImpl() override;
CreateContextProviderCallback create_context_provider_callback_;
scoped_refptr<ContextProvider> context_provider_;
diff --git a/chromium/content/renderer/media/android/webmediaplayer_android.cc b/chromium/content/renderer/media/android/webmediaplayer_android.cc
index 869bab6d066..a84941ef38b 100644
--- a/chromium/content/renderer/media/android/webmediaplayer_android.cc
+++ b/chromium/content/renderer/media/android/webmediaplayer_android.cc
@@ -20,30 +20,34 @@
#include "cc/layers/video_layer.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_switches.h"
+#include "content/public/common/renderer_preferences.h"
#include "content/public/renderer/render_frame.h"
#include "content/renderer/media/android/renderer_demuxer_android.h"
#include "content/renderer/media/android/renderer_media_player_manager.h"
-#include "content/renderer/media/crypto/key_systems.h"
#include "content/renderer/media/crypto/render_cdm_factory.h"
#include "content/renderer/media/crypto/renderer_cdm_manager.h"
-#include "content/renderer/media/webcontentdecryptionmodule_impl.h"
#include "content/renderer/render_frame_impl.h"
#include "content/renderer/render_thread_impl.h"
+#include "content/renderer/render_view_impl.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/command_buffer/common/mailbox_holder.h"
#include "media/base/android/media_common_android.h"
#include "media/base/android/media_player_android.h"
#include "media/base/bind_to_current_loop.h"
+#include "media/base/cdm_context.h"
+#include "media/base/key_systems.h"
#include "media/base/media_keys.h"
#include "media/base/media_log.h"
#include "media/base/media_switches.h"
#include "media/base/video_frame.h"
+#include "media/blink/webcontentdecryptionmodule_impl.h"
#include "media/blink/webmediaplayer_delegate.h"
#include "media/blink/webmediaplayer_util.h"
#include "net/base/mime_util.h"
#include "third_party/WebKit/public/platform/Platform.h"
#include "third_party/WebKit/public/platform/WebContentDecryptionModuleResult.h"
+#include "third_party/WebKit/public/platform/WebEncryptedMediaTypes.h"
#include "third_party/WebKit/public/platform/WebGraphicsContext3DProvider.h"
#include "third_party/WebKit/public/platform/WebMediaPlayerClient.h"
#include "third_party/WebKit/public/platform/WebString.h"
@@ -56,6 +60,8 @@
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkPaint.h"
#include "third_party/skia/include/core/SkTypeface.h"
+#include "third_party/skia/include/gpu/GrContext.h"
+#include "third_party/skia/include/gpu/SkGrPixelRef.h"
#include "ui/gfx/image/image.h"
static const uint32 kGLTextureExternalOES = 0x8D65;
@@ -83,16 +89,51 @@ void OnReleaseTexture(
gl->DeleteTextures(1, &texture_id);
}
+bool IsSkBitmapProperlySizedTexture(const SkBitmap* bitmap,
+ const gfx::Size& size) {
+ return bitmap->getTexture() && bitmap->width() == size.width() &&
+ bitmap->height() == size.height();
+}
+
+bool AllocateSkBitmapTexture(GrContext* gr,
+ SkBitmap* bitmap,
+ const gfx::Size& size) {
+ DCHECK(gr);
+ GrTextureDesc desc;
+ // Use kRGBA_8888_GrPixelConfig, not kSkia8888_GrPixelConfig, to avoid
+ // RGBA to BGRA conversion.
+ desc.fConfig = kRGBA_8888_GrPixelConfig;
+ // kRenderTarget_GrTextureFlagBit avoids a copy before readback in skia.
+ desc.fFlags = kRenderTarget_GrSurfaceFlag;
+ desc.fSampleCnt = 0;
+ desc.fOrigin = kTopLeft_GrSurfaceOrigin;
+ desc.fWidth = size.width();
+ desc.fHeight = size.height();
+ skia::RefPtr<GrTexture> texture = skia::AdoptRef(
+ gr->textureProvider()->refScratchTexture(
+ desc, GrTextureProvider::kExact_ScratchTexMatch));
+ if (!texture.get())
+ return false;
+
+ SkImageInfo info = SkImageInfo::MakeN32Premul(desc.fWidth, desc.fHeight);
+ SkGrPixelRef* pixel_ref = SkNEW_ARGS(SkGrPixelRef, (info, texture.get()));
+ if (!pixel_ref)
+ return false;
+ bitmap->setInfo(info);
+ bitmap->setPixelRef(pixel_ref)->unref();
+ return true;
+}
+
class SyncPointClientImpl : public media::VideoFrame::SyncPointClient {
public:
explicit SyncPointClientImpl(
blink::WebGraphicsContext3D* web_graphics_context)
: web_graphics_context_(web_graphics_context) {}
- virtual ~SyncPointClientImpl() {}
- virtual uint32 InsertSyncPoint() override {
+ ~SyncPointClientImpl() override {}
+ uint32 InsertSyncPoint() override {
return web_graphics_context_->insertSyncPoint();
}
- virtual void WaitSyncPoint(uint32 sync_point) override {
+ void WaitSyncPoint(uint32 sync_point) override {
web_graphics_context_->waitSyncPoint(sync_point);
}
@@ -100,10 +141,6 @@ class SyncPointClientImpl : public media::VideoFrame::SyncPointClient {
blink::WebGraphicsContext3D* web_graphics_context_;
};
-// Used for calls to decryptor_ready_cb_ where the result can be ignored.
-void DoNothing(bool) {
-}
-
} // namespace
namespace content {
@@ -113,7 +150,8 @@ WebMediaPlayerAndroid::WebMediaPlayerAndroid(
blink::WebMediaPlayerClient* client,
base::WeakPtr<media::WebMediaPlayerDelegate> delegate,
RendererMediaPlayerManager* player_manager,
- RendererCdmManager* cdm_manager,
+ media::CdmFactory* cdm_factory,
+ media::MediaPermission* media_permission,
blink::WebContentDecryptionModule* initial_cdm,
scoped_refptr<StreamTextureFactory> factory,
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
@@ -129,11 +167,13 @@ WebMediaPlayerAndroid::WebMediaPlayerAndroid(
seeking_(false),
did_loading_progress_(false),
player_manager_(player_manager),
- cdm_manager_(cdm_manager),
+ cdm_factory_(cdm_factory),
+ media_permission_(media_permission),
network_state_(WebMediaPlayer::NetworkStateEmpty),
ready_state_(WebMediaPlayer::ReadyStateHaveNothing),
texture_id_(0),
stream_id_(0),
+ is_player_initialized_(false),
is_playing_(false),
needs_establish_peer_(true),
has_size_info_(false),
@@ -144,17 +184,19 @@ WebMediaPlayerAndroid::WebMediaPlayerAndroid(
: base::MessageLoopProxy::current()),
stream_texture_factory_(factory),
needs_external_surface_(false),
+ is_fullscreen_(false),
video_frame_provider_client_(NULL),
player_type_(MEDIA_PLAYER_TYPE_URL),
is_remote_(false),
media_log_(media_log),
- web_cdm_(NULL),
+ init_data_type_(media::EmeInitDataType::UNKNOWN),
+ cdm_context_(NULL),
allow_stored_credentials_(false),
is_local_resource_(false),
interpolator_(&default_tick_clock_),
weak_factory_(this) {
DCHECK(player_manager_);
- DCHECK(cdm_manager_);
+ DCHECK(cdm_factory_);
DCHECK(main_thread_checker_.CalledOnValidThread());
stream_texture_factory_->AddObserver(this);
@@ -162,8 +204,11 @@ WebMediaPlayerAndroid::WebMediaPlayerAndroid(
player_id_ = player_manager_->RegisterMediaPlayer(this);
#if defined(VIDEO_HOLE)
- force_use_overlay_embedded_video_ = CommandLine::ForCurrentProcess()->
- HasSwitch(switches::kForceUseOverlayEmbeddedVideo);
+ const RendererPreferences& prefs =
+ static_cast<RenderFrameImpl*>(render_frame())
+ ->render_view()
+ ->renderer_preferences();
+ force_use_overlay_embedded_video_ = prefs.use_view_overlay_for_all_video;
if (force_use_overlay_embedded_video_ ||
player_manager_->ShouldUseVideoOverlayForEmbeddedEncryptedVideo()) {
// Defer stream texture creation until we are sure it's necessary.
@@ -174,11 +219,9 @@ WebMediaPlayerAndroid::WebMediaPlayerAndroid(
TryCreateStreamTextureProxyIfNeeded();
interpolator_.SetUpperBound(base::TimeDelta());
- // Set the initial CDM, if specified.
if (initial_cdm) {
- web_cdm_ = ToWebContentDecryptionModuleImpl(initial_cdm);
- if (web_cdm_->GetCdmId() != media::MediaKeys::kInvalidCdmId)
- player_manager_->SetCdm(player_id_, web_cdm_->GetCdmId());
+ cdm_context_ =
+ media::ToWebContentDecryptionModuleImpl(initial_cdm)->GetCdmContext();
}
}
@@ -187,10 +230,10 @@ WebMediaPlayerAndroid::~WebMediaPlayerAndroid() {
SetVideoFrameProviderClient(NULL);
client_->setWebLayer(NULL);
- if (player_manager_) {
+ if (is_player_initialized_)
player_manager_->DestroyPlayer(player_id_);
- player_manager_->UnregisterMediaPlayer(player_id_);
- }
+
+ player_manager_->UnregisterMediaPlayer(player_id_);
if (stream_id_) {
GLES2Interface* gl = stream_texture_factory_->ContextGL();
@@ -254,20 +297,18 @@ void WebMediaPlayerAndroid::load(LoadType load_type,
demuxer, demuxer_client_id, media_task_runner_, media_log_));
if (player_type_ == MEDIA_PLAYER_TYPE_MEDIA_SOURCE) {
- media::SetDecryptorReadyCB set_decryptor_ready_cb =
- media::BindToCurrentLoop(
- base::Bind(&WebMediaPlayerAndroid::SetDecryptorReadyCB,
- weak_factory_.GetWeakPtr()));
-
media_source_delegate_->InitializeMediaSource(
base::Bind(&WebMediaPlayerAndroid::OnMediaSourceOpened,
weak_factory_.GetWeakPtr()),
- base::Bind(&WebMediaPlayerAndroid::OnNeedKey,
+ base::Bind(&WebMediaPlayerAndroid::OnEncryptedMediaInitData,
+ weak_factory_.GetWeakPtr()),
+ base::Bind(&WebMediaPlayerAndroid::SetDecryptorReadyCB,
weak_factory_.GetWeakPtr()),
- set_decryptor_ready_cb,
base::Bind(&WebMediaPlayerAndroid::UpdateNetworkState,
weak_factory_.GetWeakPtr()),
base::Bind(&WebMediaPlayerAndroid::OnDurationChanged,
+ weak_factory_.GetWeakPtr()),
+ base::Bind(&WebMediaPlayerAndroid::OnWaitingForDecryptionKey,
weak_factory_.GetWeakPtr()));
InitializePlayer(url_, frame_->document().firstPartyForCookies(),
true, demuxer_client_id);
@@ -327,7 +368,7 @@ void WebMediaPlayerAndroid::play() {
// texture is bind to it. See http://crbug.com/400145.
#if defined(VIDEO_HOLE)
if ((hasVideo() || IsHLSStream()) && needs_external_surface_ &&
- !player_manager_->IsInFullscreen(frame_)) {
+ !is_fullscreen_) {
DCHECK(!needs_establish_peer_);
player_manager_->RequestExternalSurface(player_id_, last_computed_rect_);
}
@@ -337,7 +378,7 @@ void WebMediaPlayerAndroid::play() {
// There is no need to establish the surface texture peer for fullscreen
// video.
if ((hasVideo() || IsHLSStream()) && needs_establish_peer_ &&
- !player_manager_->IsInFullscreen(frame_)) {
+ !is_fullscreen_) {
EstablishSurfaceTexturePeer();
}
@@ -540,39 +581,6 @@ bool WebMediaPlayerAndroid::didLoadingProgress() {
return ret;
}
-bool WebMediaPlayerAndroid::EnsureTextureBackedSkBitmap(GrContext* gr,
- SkBitmap& bitmap,
- const WebSize& size,
- GrSurfaceOrigin origin,
- GrPixelConfig config) {
- DCHECK(main_thread_checker_.CalledOnValidThread());
- if (!bitmap.getTexture() || bitmap.width() != size.width
- || bitmap.height() != size.height) {
- if (!gr)
- return false;
- GrTextureDesc desc;
- desc.fConfig = config;
- desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
- desc.fSampleCnt = 0;
- desc.fOrigin = origin;
- desc.fWidth = size.width;
- desc.fHeight = size.height;
- skia::RefPtr<GrTexture> texture;
- texture = skia::AdoptRef(gr->createUncachedTexture(desc, 0, 0));
- if (!texture.get())
- return false;
-
- SkImageInfo info = SkImageInfo::MakeN32Premul(desc.fWidth, desc.fHeight);
- SkGrPixelRef* pixelRef = SkNEW_ARGS(SkGrPixelRef, (info, texture.get()));
- if (!pixelRef)
- return false;
- bitmap.setInfo(info);
- bitmap.setPixelRef(pixelRef)->unref();
- }
-
- return true;
-}
-
void WebMediaPlayerAndroid::paint(blink::WebCanvas* canvas,
const blink::WebRect& rect,
unsigned char alpha,
@@ -593,9 +601,11 @@ void WebMediaPlayerAndroid::paint(blink::WebCanvas* canvas,
// here. Check if we could reuse existing texture based bitmap.
// Otherwise, release existing texture based bitmap and allocate
// a new one based on video size.
- if (!EnsureTextureBackedSkBitmap(provider->grContext(), bitmap_,
- naturalSize(), kTopLeft_GrSurfaceOrigin, kSkia8888_GrPixelConfig)) {
- return;
+ if (!IsSkBitmapProperlySizedTexture(&bitmap_, naturalSize())) {
+ if (!AllocateSkBitmapTexture(provider->grContext(), &bitmap_,
+ naturalSize())) {
+ return;
+ }
}
unsigned textureId = static_cast<unsigned>(
@@ -627,6 +637,18 @@ bool WebMediaPlayerAndroid::copyVideoTextureToPlatformTexture(
unsigned int type,
bool premultiply_alpha,
bool flip_y) {
+ return copyVideoTextureToPlatformTexture(web_graphics_context, texture,
+ internal_format, type,
+ premultiply_alpha, flip_y);
+}
+
+bool WebMediaPlayerAndroid::copyVideoTextureToPlatformTexture(
+ blink::WebGraphicsContext3D* web_graphics_context,
+ unsigned int texture,
+ unsigned int internal_format,
+ unsigned int type,
+ bool premultiply_alpha,
+ bool flip_y) {
DCHECK(main_thread_checker_.CalledOnValidThread());
// Don't allow clients to copy an encrypted video frame.
if (needs_external_surface_)
@@ -641,17 +663,18 @@ bool WebMediaPlayerAndroid::copyVideoTextureToPlatformTexture(
if (!video_frame.get() ||
video_frame->format() != media::VideoFrame::NATIVE_TEXTURE)
return false;
- const gpu::MailboxHolder* mailbox_holder = video_frame->mailbox_holder();
+ DCHECK_EQ(1u, media::VideoFrame::NumTextures(video_frame->texture_format()));
+ const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0);
DCHECK((!is_remote_ &&
- mailbox_holder->texture_target == GL_TEXTURE_EXTERNAL_OES) ||
- (is_remote_ && mailbox_holder->texture_target == GL_TEXTURE_2D));
+ mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES) ||
+ (is_remote_ && mailbox_holder.texture_target == GL_TEXTURE_2D));
- web_graphics_context->waitSyncPoint(mailbox_holder->sync_point);
+ web_graphics_context->waitSyncPoint(mailbox_holder.sync_point);
// Ensure the target of texture is set before copyTextureCHROMIUM, otherwise
// an invalid texture target may be used for copy texture.
uint32 src_texture = web_graphics_context->createAndConsumeTextureCHROMIUM(
- mailbox_holder->texture_target, mailbox_holder->mailbox.name);
+ mailbox_holder.texture_target, mailbox_holder.mailbox.name);
// The video is stored in an unmultiplied format, so premultiply if
// necessary.
@@ -663,9 +686,8 @@ bool WebMediaPlayerAndroid::copyVideoTextureToPlatformTexture(
// flip_y==true means to reverse the video orientation while
// flip_y==false means to keep the intrinsic orientation.
web_graphics_context->pixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, flip_y);
- web_graphics_context->copyTextureCHROMIUM(GL_TEXTURE_2D, src_texture,
- texture, level, internal_format,
- type);
+ web_graphics_context->copyTextureCHROMIUM(GL_TEXTURE_2D, src_texture, texture,
+ internal_format, type);
web_graphics_context->pixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, false);
web_graphics_context->pixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM,
false);
@@ -848,12 +870,12 @@ void WebMediaPlayerAndroid::OnVideoSizeChanged(int width, int height) {
(media_source_delegate_ && media_source_delegate_->IsVideoEncrypted() &&
player_manager_->ShouldUseVideoOverlayForEmbeddedEncryptedVideo())) {
needs_external_surface_ = true;
- if (!paused() && !player_manager_->IsInFullscreen(frame_))
+ if (!paused() && !is_fullscreen_)
player_manager_->RequestExternalSurface(player_id_, last_computed_rect_);
- } else if (stream_texture_proxy_ && !stream_id_) {
+ } else if (!stream_texture_proxy_) {
// Do deferred stream texture creation finally.
- DoCreateStreamTexture();
SetNeedsEstablishPeer(true);
+ TryCreateStreamTextureProxyIfNeeded();
}
#endif // defined(VIDEO_HOLE)
natural_size_.width = width;
@@ -931,11 +953,6 @@ void WebMediaPlayerAndroid::OnDisconnectedFromRemoteDevice() {
client_->disconnectedFromRemoteDevice();
}
-void WebMediaPlayerAndroid::OnDidEnterFullscreen() {
- if (!player_manager_->IsInFullscreen(frame_))
- player_manager_->DidEnterFullscreen(frame_);
-}
-
void WebMediaPlayerAndroid::OnDidExitFullscreen() {
// |needs_external_surface_| is always false on non-TV devices.
if (!needs_external_surface_)
@@ -949,8 +966,7 @@ void WebMediaPlayerAndroid::OnDidExitFullscreen() {
if (!paused() && needs_external_surface_)
player_manager_->RequestExternalSurface(player_id_, last_computed_rect_);
#endif // defined(VIDEO_HOLE)
-
- player_manager_->DidExitFullscreen();
+ is_fullscreen_ = false;
client_->repaint();
}
@@ -1065,8 +1081,13 @@ void WebMediaPlayerAndroid::InitializePlayer(
player_manager_->Initialize(
player_type_, player_id_, url, first_party_for_cookies, demuxer_client_id,
frame_->document().url(), allow_stored_credentials);
- if (player_manager_->ShouldEnterFullscreen(frame_))
- player_manager_->EnterFullscreen(player_id_, frame_);
+ is_player_initialized_ = true;
+
+ if (is_fullscreen_)
+ player_manager_->EnterFullscreen(player_id_);
+
+ if (cdm_context_)
+ SetCdmInternal(base::Bind(&media::IgnoreCdmAttached));
}
void WebMediaPlayerAndroid::Pause(bool is_media_related_action) {
@@ -1103,7 +1124,7 @@ void WebMediaPlayerAndroid::DrawRemotePlaybackText(
SkPaint paint;
paint.setAntiAlias(true);
- paint.setFilterLevel(SkPaint::kHigh_FilterLevel);
+ paint.setFilterQuality(kHigh_SkFilterQuality);
paint.setColor(SK_ColorWHITE);
paint.setTypeface(SkTypeface::CreateFromName("sans", SkTypeface::kBold));
paint.setTextSize(kTextSize);
@@ -1183,16 +1204,14 @@ void WebMediaPlayerAndroid::DrawRemotePlaybackText(
GLuint texture_mailbox_sync_point = gl->InsertSyncPointCHROMIUM();
scoped_refptr<VideoFrame> new_frame = VideoFrame::WrapNativeTexture(
- make_scoped_ptr(new gpu::MailboxHolder(
- texture_mailbox, texture_target, texture_mailbox_sync_point)),
+ gpu::MailboxHolder(texture_mailbox, texture_target,
+ texture_mailbox_sync_point),
media::BindToCurrentLoop(base::Bind(&OnReleaseTexture,
stream_texture_factory_,
remote_playback_texture_id)),
- canvas_size /* coded_size */,
- gfx::Rect(canvas_size) /* visible_rect */,
- canvas_size /* natural_size */,
- base::TimeDelta() /* timestamp */,
- VideoFrame::ReadPixelsCB());
+ canvas_size /* coded_size */, gfx::Rect(canvas_size) /* visible_rect */,
+ canvas_size /* natural_size */, base::TimeDelta() /* timestamp */,
+ false /* allow overlay */, true /* has_alpha */);
SetCurrentFrameInternal(new_frame);
}
@@ -1202,6 +1221,9 @@ void WebMediaPlayerAndroid::ReallocateVideoFrame() {
// VideoFrame::CreateHoleFrame is only defined under VIDEO_HOLE.
#if defined(VIDEO_HOLE)
if (!natural_size_.isEmpty()) {
+ // Now we finally know that "stream texture" and "video frame" won't
+ // be needed. EME uses "external surface" and "video hole" instead.
+ ResetStreamTextureProxy();
scoped_refptr<VideoFrame> new_frame =
VideoFrame::CreateHoleFrame(natural_size_);
SetCurrentFrameInternal(new_frame);
@@ -1220,15 +1242,12 @@ void WebMediaPlayerAndroid::ReallocateVideoFrame() {
GLuint texture_mailbox_sync_point = gl->InsertSyncPointCHROMIUM();
scoped_refptr<VideoFrame> new_frame = VideoFrame::WrapNativeTexture(
- make_scoped_ptr(new gpu::MailboxHolder(
- texture_mailbox_, texture_target, texture_mailbox_sync_point)),
+ gpu::MailboxHolder(texture_mailbox_, texture_target,
+ texture_mailbox_sync_point),
media::BindToCurrentLoop(base::Bind(
&OnReleaseTexture, stream_texture_factory_, texture_id_ref)),
- natural_size_,
- gfx::Rect(natural_size_),
- natural_size_,
- base::TimeDelta(),
- VideoFrame::ReadPixelsCB());
+ natural_size_, gfx::Rect(natural_size_), natural_size_,
+ base::TimeDelta(), false /* allow_overlay */, true /* has_alpha */);
SetCurrentFrameInternal(new_frame);
}
}
@@ -1255,6 +1274,17 @@ void WebMediaPlayerAndroid::SetCurrentFrameInternal(
current_frame_ = video_frame;
}
+bool WebMediaPlayerAndroid::UpdateCurrentFrame(base::TimeTicks deadline_min,
+ base::TimeTicks deadline_max) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool WebMediaPlayerAndroid::HasCurrentFrame() {
+ base::AutoLock auto_lock(current_frame_lock_);
+ return current_frame_;
+}
+
scoped_refptr<media::VideoFrame> WebMediaPlayerAndroid::GetCurrentFrame() {
scoped_refptr<VideoFrame> video_frame;
{
@@ -1265,8 +1295,7 @@ scoped_refptr<media::VideoFrame> WebMediaPlayerAndroid::GetCurrentFrame() {
return video_frame;
}
-void WebMediaPlayerAndroid::PutCurrentFrame(
- const scoped_refptr<media::VideoFrame>& frame) {
+void WebMediaPlayerAndroid::PutCurrentFrame() {
}
void WebMediaPlayerAndroid::ResetStreamTextureProxy() {
@@ -1281,7 +1310,7 @@ void WebMediaPlayerAndroid::ResetStreamTextureProxy() {
}
stream_texture_proxy_.reset();
needs_establish_peer_ = !needs_external_surface_ && !is_remote_ &&
- !player_manager_->IsInFullscreen(frame_) &&
+ !is_fullscreen_ &&
(hasVideo() || IsHLSStream());
TryCreateStreamTextureProxyIfNeeded();
@@ -1416,7 +1445,7 @@ static void EmeUMAHistogramEnumeration(const std::string& key_system,
int sample,
int boundary_value) {
base::LinearHistogram::FactoryGet(
- kMediaEme + KeySystemNameForUMA(key_system) + "." + method,
+ kMediaEme + media::GetKeySystemNameForUMA(key_system) + "." + method,
1, boundary_value, boundary_value + 1,
base::Histogram::kUmaTargetedHistogramFlag)->Add(sample);
}
@@ -1426,7 +1455,7 @@ static void EmeUMAHistogramCounts(const std::string& key_system,
int sample) {
// Use the same parameters as UMA_HISTOGRAM_COUNTS.
base::Histogram::FactoryGet(
- kMediaEme + KeySystemNameForUMA(key_system) + "." + method,
+ kMediaEme + media::GetKeySystemNameForUMA(key_system) + "." + method,
1, 1000000, 50, base::Histogram::kUmaTargetedHistogramFlag)->Add(sample);
}
@@ -1468,7 +1497,7 @@ bool WebMediaPlayerAndroid::IsKeySystemSupported(
const std::string& key_system) {
// On Android, EME only works with MSE.
return player_type_ == MEDIA_PLAYER_TYPE_MEDIA_SOURCE &&
- IsConcreteSupportedKeySystem(key_system);
+ media::PrefixedIsSupportedConcreteKeySystem(key_system);
}
WebMediaPlayer::MediaKeyException WebMediaPlayerAndroid::generateKeyRequest(
@@ -1480,7 +1509,7 @@ WebMediaPlayer::MediaKeyException WebMediaPlayerAndroid::generateKeyRequest(
static_cast<size_t>(init_data_length));
std::string ascii_key_system =
- GetUnprefixedKeySystemName(ToASCIIOrEmpty(key_system));
+ media::GetUnprefixedKeySystemName(ToASCIIOrEmpty(key_system));
WebMediaPlayer::MediaKeyException e =
GenerateKeyRequestInternal(ascii_key_system, init_data, init_data_length);
@@ -1490,13 +1519,13 @@ WebMediaPlayer::MediaKeyException WebMediaPlayerAndroid::generateKeyRequest(
// Guess the type of |init_data|. This is only used to handle some corner cases
// so we keep it as simple as possible without breaking major use cases.
-static std::string GuessInitDataType(const unsigned char* init_data,
- unsigned init_data_length) {
+static media::EmeInitDataType GuessInitDataType(const unsigned char* init_data,
+ unsigned init_data_length) {
// Most WebM files use KeyId of 16 bytes. CENC init data is always >16 bytes.
if (init_data_length == 16)
- return "webm";
+ return media::EmeInitDataType::WEBM;
- return "cenc";
+ return media::EmeInitDataType::CENC;
}
// TODO(xhwang): Report an error when there is encrypted stream but EME is
@@ -1510,52 +1539,37 @@ WebMediaPlayerAndroid::GenerateKeyRequestInternal(
if (!IsKeySystemSupported(key_system))
return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
- // We do not support run-time switching between key systems for now.
- if (current_key_system_.empty()) {
- if (!proxy_decryptor_) {
- proxy_decryptor_.reset(new ProxyDecryptor(
- base::Bind(&WebMediaPlayerAndroid::OnKeyAdded,
- weak_factory_.GetWeakPtr()),
- base::Bind(&WebMediaPlayerAndroid::OnKeyError,
- weak_factory_.GetWeakPtr()),
- base::Bind(&WebMediaPlayerAndroid::OnKeyMessage,
- weak_factory_.GetWeakPtr())));
- }
+ if (!proxy_decryptor_) {
+ DCHECK(current_key_system_.empty());
+ proxy_decryptor_.reset(new media::ProxyDecryptor(
+ media_permission_,
+ player_manager_->ShouldUseVideoOverlayForEmbeddedEncryptedVideo(),
+ base::Bind(&WebMediaPlayerAndroid::OnKeyAdded,
+ weak_factory_.GetWeakPtr()),
+ base::Bind(&WebMediaPlayerAndroid::OnKeyError,
+ weak_factory_.GetWeakPtr()),
+ base::Bind(&WebMediaPlayerAndroid::OnKeyMessage,
+ weak_factory_.GetWeakPtr())));
GURL security_origin(frame_->document().securityOrigin().toString());
- RenderCdmFactory cdm_factory(cdm_manager_);
- if (!proxy_decryptor_->InitializeCDM(&cdm_factory, key_system,
- security_origin)) {
- return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
- }
-
- if (!decryptor_ready_cb_.is_null()) {
- base::ResetAndReturn(&decryptor_ready_cb_)
- .Run(proxy_decryptor_->GetDecryptor(), base::Bind(DoNothing));
- }
-
- // Only browser CDMs have CDM ID. Render side CDMs (e.g. ClearKey CDM) do
- // not have a CDM ID and there is no need to call player_manager_->SetCdm().
- if (proxy_decryptor_->GetCdmId() != media::MediaKeys::kInvalidCdmId)
- player_manager_->SetCdm(player_id_, proxy_decryptor_->GetCdmId());
-
+ proxy_decryptor_->CreateCdm(
+ cdm_factory_, key_system, security_origin,
+ base::Bind(&WebMediaPlayerAndroid::OnCdmContextReady,
+ weak_factory_.GetWeakPtr()));
current_key_system_ = key_system;
- } else if (key_system != current_key_system_) {
- return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState;
}
- std::string init_data_type = init_data_type_;
- if (init_data_type.empty())
+ // We do not support run-time switching between key systems for now.
+ DCHECK(!current_key_system_.empty());
+ if (key_system != current_key_system_)
+ return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState;
+
+ media::EmeInitDataType init_data_type = init_data_type_;
+ if (init_data_type == media::EmeInitDataType::UNKNOWN)
init_data_type = GuessInitDataType(init_data, init_data_length);
- // TODO(xhwang): We assume all streams are from the same container (thus have
- // the same "type") for now. In the future, the "type" should be passed down
- // from the application.
- if (!proxy_decryptor_->GenerateKeyRequest(
- init_data_type, init_data, init_data_length)) {
- current_key_system_.clear();
- return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
- }
+ proxy_decryptor_->GenerateKeyRequest(init_data_type, init_data,
+ init_data_length);
return WebMediaPlayer::MediaKeyExceptionNoError;
}
@@ -1575,7 +1589,7 @@ WebMediaPlayer::MediaKeyException WebMediaPlayerAndroid::addKey(
<< base::string16(session_id) << "]";
std::string ascii_key_system =
- GetUnprefixedKeySystemName(ToASCIIOrEmpty(key_system));
+ media::GetUnprefixedKeySystemName(ToASCIIOrEmpty(key_system));
std::string ascii_session_id = ToASCIIOrEmpty(session_id);
WebMediaPlayer::MediaKeyException e = AddKeyInternal(ascii_key_system,
@@ -1616,7 +1630,7 @@ WebMediaPlayer::MediaKeyException WebMediaPlayerAndroid::cancelKeyRequest(
<< " [" << base::string16(session_id) << "]";
std::string ascii_key_system =
- GetUnprefixedKeySystemName(ToASCIIOrEmpty(key_system));
+ media::GetUnprefixedKeySystemName(ToASCIIOrEmpty(key_system));
std::string ascii_session_id = ToASCIIOrEmpty(session_id);
WebMediaPlayer::MediaKeyException e =
@@ -1639,27 +1653,6 @@ WebMediaPlayerAndroid::CancelKeyRequestInternal(const std::string& key_system,
}
void WebMediaPlayerAndroid::setContentDecryptionModule(
- blink::WebContentDecryptionModule* cdm) {
- DCHECK(main_thread_checker_.CalledOnValidThread());
-
- // TODO(xhwang): Support setMediaKeys(0) if necessary: http://crbug.com/330324
- if (!cdm)
- return;
-
- web_cdm_ = ToWebContentDecryptionModuleImpl(cdm);
- if (!web_cdm_)
- return;
-
- if (!decryptor_ready_cb_.is_null()) {
- base::ResetAndReturn(&decryptor_ready_cb_)
- .Run(web_cdm_->GetDecryptor(), base::Bind(DoNothing));
- }
-
- if (web_cdm_->GetCdmId() != media::MediaKeys::kInvalidCdmId)
- player_manager_->SetCdm(player_id_, web_cdm_->GetCdmId());
-}
-
-void WebMediaPlayerAndroid::setContentDecryptionModule(
blink::WebContentDecryptionModule* cdm,
blink::WebContentDecryptionModuleResult result) {
DCHECK(main_thread_checker_.CalledOnValidThread());
@@ -1673,24 +1666,17 @@ void WebMediaPlayerAndroid::setContentDecryptionModule(
return;
}
- web_cdm_ = ToWebContentDecryptionModuleImpl(cdm);
- DCHECK(web_cdm_);
+ cdm_context_ = media::ToWebContentDecryptionModuleImpl(cdm)->GetCdmContext();
- if (!decryptor_ready_cb_.is_null()) {
- base::ResetAndReturn(&decryptor_ready_cb_).Run(
- web_cdm_->GetDecryptor(),
- media::BindToCurrentLoop(
- base::Bind(&WebMediaPlayerAndroid::ContentDecryptionModuleAttached,
- weak_factory_.GetWeakPtr(),
- result)));
+ if (is_player_initialized_) {
+ SetCdmInternal(media::BindToCurrentLoop(
+ base::Bind(&WebMediaPlayerAndroid::ContentDecryptionModuleAttached,
+ weak_factory_.GetWeakPtr(), result)));
} else {
// No pipeline/decoder connected, so resolve the promise. When something
// is connected, setting the CDM will happen in SetDecryptorReadyCB().
ContentDecryptionModuleAttached(result, true);
}
-
- if (web_cdm_->GetCdmId() != media::MediaKeys::kInvalidCdmId)
- player_manager_->SetCdm(player_id_, web_cdm_->GetCdmId());
}
void WebMediaPlayerAndroid::ContentDecryptionModuleAttached(
@@ -1711,7 +1697,7 @@ void WebMediaPlayerAndroid::OnKeyAdded(const std::string& session_id) {
EmeUMAHistogramCounts(current_key_system_, "KeyAdded", 1);
client_->keyAdded(
- WebString::fromUTF8(GetPrefixedKeySystemName(current_key_system_)),
+ WebString::fromUTF8(media::GetPrefixedKeySystemName(current_key_system_)),
WebString::fromUTF8(session_id));
}
@@ -1730,7 +1716,7 @@ void WebMediaPlayerAndroid::OnKeyError(const std::string& session_id,
}
client_->keyError(
- WebString::fromUTF8(GetPrefixedKeySystemName(current_key_system_)),
+ WebString::fromUTF8(media::GetPrefixedKeySystemName(current_key_system_)),
WebString::fromUTF8(session_id),
static_cast<blink::WebMediaPlayerClient::MediaKeyErrorCode>(error_code),
short_system_code);
@@ -1742,7 +1728,7 @@ void WebMediaPlayerAndroid::OnKeyMessage(const std::string& session_id,
DCHECK(destination_url.is_empty() || destination_url.is_valid());
client_->keyMessage(
- WebString::fromUTF8(GetPrefixedKeySystemName(current_key_system_)),
+ WebString::fromUTF8(media::GetPrefixedKeySystemName(current_key_system_)),
WebString::fromUTF8(session_id),
message.empty() ? NULL : &message[0],
message.size(),
@@ -1754,8 +1740,9 @@ void WebMediaPlayerAndroid::OnMediaSourceOpened(
client_->mediaSourceOpened(web_media_source);
}
-void WebMediaPlayerAndroid::OnNeedKey(const std::string& type,
- const std::vector<uint8>& init_data) {
+void WebMediaPlayerAndroid::OnEncryptedMediaInitData(
+ media::EmeInitDataType init_data_type,
+ const std::vector<uint8>& init_data) {
DCHECK(main_thread_checker_.CalledOnValidThread());
// Do not fire NeedKey event if encrypted media is not enabled.
@@ -1766,24 +1753,88 @@ void WebMediaPlayerAndroid::OnNeedKey(const std::string& type,
UMA_HISTOGRAM_COUNTS(kMediaEme + std::string("NeedKey"), 1);
- DCHECK(init_data_type_.empty() || type.empty() || type == init_data_type_);
- if (init_data_type_.empty())
- init_data_type_ = type;
+ DCHECK(init_data_type != media::EmeInitDataType::UNKNOWN);
+ DLOG_IF(WARNING, init_data_type_ != media::EmeInitDataType::UNKNOWN &&
+ init_data_type != init_data_type_)
+ << "Mixed init data type not supported. The new type is ignored.";
+ if (init_data_type_ == media::EmeInitDataType::UNKNOWN)
+ init_data_type_ = init_data_type;
+
+ client_->encrypted(ConvertToWebInitDataType(init_data_type),
+ vector_as_array(&init_data), init_data.size());
+}
+
+void WebMediaPlayerAndroid::OnWaitingForDecryptionKey() {
+ client_->didBlockPlaybackWaitingForKey();
- const uint8* init_data_ptr = init_data.empty() ? NULL : &init_data[0];
- client_->encrypted(
- WebString::fromUTF8(type), init_data_ptr, init_data.size());
+ // TODO(jrummell): didResumePlaybackBlockedForKey() should only be called
+ // when a key has been successfully added (e.g. OnSessionKeysChange() with
+ // |has_additional_usable_key| = true). http://crbug.com/461903
+ client_->didResumePlaybackBlockedForKey();
+}
+
+void WebMediaPlayerAndroid::OnCdmContextReady(media::CdmContext* cdm_context) {
+ DCHECK(!cdm_context_);
+
+ if (!cdm_context) {
+ LOG(ERROR) << "CdmContext not available (e.g. CDM creation failed).";
+ return;
+ }
+
+ cdm_context_ = cdm_context;
+
+ if (is_player_initialized_)
+ SetCdmInternal(base::Bind(&media::IgnoreCdmAttached));
+}
+
+void WebMediaPlayerAndroid::SetCdmInternal(
+ const media::CdmAttachedCB& cdm_attached_cb) {
+ DCHECK(cdm_context_ && is_player_initialized_);
+ DCHECK(cdm_context_->GetDecryptor() ||
+ cdm_context_->GetCdmId() != media::CdmContext::kInvalidCdmId)
+ << "CDM should support either a Decryptor or a CDM ID.";
+
+ media::Decryptor* decryptor = cdm_context_->GetDecryptor();
+
+ // Note:
+ // - If |decryptor| is non-null, only handles |decryptor_ready_cb_| and
+ // ignores the CDM ID.
+ // - If |decryptor| is null (in which case the CDM ID should be valid),
+ // returns any pending |decryptor_ready_cb_| with null, so that
+ // MediaSourceDelegate will fall back to use a browser side (IPC-based) CDM,
+ // then calls SetCdm() through the |player_manager_|.
+
+ if (decryptor) {
+ if (!decryptor_ready_cb_.is_null()) {
+ base::ResetAndReturn(&decryptor_ready_cb_)
+ .Run(decryptor, cdm_attached_cb);
+ } else {
+ cdm_attached_cb.Run(true);
+ }
+ return;
+ }
+
+ // |decryptor| is null.
+ if (!decryptor_ready_cb_.is_null()) {
+ base::ResetAndReturn(&decryptor_ready_cb_)
+ .Run(nullptr, base::Bind(&media::IgnoreCdmAttached));
+ }
+
+ DCHECK(cdm_context_->GetCdmId() != media::CdmContext::kInvalidCdmId);
+ player_manager_->SetCdm(player_id_, cdm_context_->GetCdmId());
+ cdm_attached_cb.Run(true);
}
void WebMediaPlayerAndroid::SetDecryptorReadyCB(
const media::DecryptorReadyCB& decryptor_ready_cb) {
DCHECK(main_thread_checker_.CalledOnValidThread());
+ DCHECK(is_player_initialized_);
// Cancels the previous decryptor request.
if (decryptor_ready_cb.is_null()) {
if (!decryptor_ready_cb_.is_null()) {
base::ResetAndReturn(&decryptor_ready_cb_)
- .Run(NULL, base::Bind(DoNothing));
+ .Run(NULL, base::Bind(&media::IgnoreCdmAttached));
}
return;
}
@@ -1795,17 +1846,9 @@ void WebMediaPlayerAndroid::SetDecryptorReadyCB(
// detail.
DCHECK(decryptor_ready_cb_.is_null());
- // Mixed use of prefixed and unprefixed EME APIs is disallowed by Blink.
- DCHECK(!proxy_decryptor_ || !web_cdm_);
-
- if (proxy_decryptor_) {
- decryptor_ready_cb.Run(proxy_decryptor_->GetDecryptor(),
- base::Bind(DoNothing));
- return;
- }
-
- if (web_cdm_) {
- decryptor_ready_cb.Run(web_cdm_->GetDecryptor(), base::Bind(DoNothing));
+ if (cdm_context_) {
+ decryptor_ready_cb.Run(cdm_context_->GetDecryptor(),
+ base::Bind(&media::IgnoreCdmAttached));
return;
}
@@ -1813,14 +1856,10 @@ void WebMediaPlayerAndroid::SetDecryptorReadyCB(
}
void WebMediaPlayerAndroid::enterFullscreen() {
- if (player_manager_->CanEnterFullscreen(frame_)) {
- player_manager_->EnterFullscreen(player_id_, frame_);
- SetNeedsEstablishPeer(false);
- }
-}
-
-bool WebMediaPlayerAndroid::canEnterFullscreen() const {
- return player_manager_->CanEnterFullscreen(frame_);
+ if (is_player_initialized_)
+ player_manager_->EnterFullscreen(player_id_);
+ SetNeedsEstablishPeer(false);
+ is_fullscreen_ = true;
}
bool WebMediaPlayerAndroid::IsHLSStream() const {
diff --git a/chromium/content/renderer/media/android/webmediaplayer_android.h b/chromium/content/renderer/media/android/webmediaplayer_android.h
index 83db690471d..2627ac03a5a 100644
--- a/chromium/content/renderer/media/android/webmediaplayer_android.h
+++ b/chromium/content/renderer/media/android/webmediaplayer_android.h
@@ -22,20 +22,19 @@
#include "content/renderer/media/android/media_info_loader.h"
#include "content/renderer/media/android/media_source_delegate.h"
#include "content/renderer/media/android/stream_texture_factory.h"
-#include "content/renderer/media/crypto/proxy_decryptor.h"
#include "gpu/command_buffer/common/mailbox.h"
#include "media/base/android/media_player_android.h"
+#include "media/base/cdm_context.h"
#include "media/base/demuxer_stream.h"
#include "media/base/media_keys.h"
#include "media/base/time_delta_interpolator.h"
+#include "media/cdm/proxy_decryptor.h"
#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
#include "third_party/WebKit/public/platform/WebMediaPlayer.h"
#include "third_party/WebKit/public/platform/WebSize.h"
#include "third_party/WebKit/public/platform/WebURL.h"
#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/gpu/GrContext.h"
-#include "third_party/skia/include/gpu/SkGrPixelRef.h"
-#include "ui/gfx/rect_f.h"
+#include "ui/gfx/geometry/rect_f.h"
namespace base {
class SingleThreadTaskRunner;
@@ -45,6 +44,7 @@ namespace blink {
class WebContentDecryptionModule;
class WebContentDecryptionModuleResult;
class WebFrame;
+class WebMediaPlayerClient;
class WebURL;
}
@@ -57,14 +57,18 @@ struct MailboxHolder;
}
namespace media {
+class CdmContext;
+class CdmFactory;
class MediaLog;
+class MediaPermission;
+class WebContentDecryptionModuleImpl;
class WebMediaPlayerDelegate;
}
namespace content {
+
class RendererCdmManager;
class RendererMediaPlayerManager;
-class WebContentDecryptionModuleImpl;
// This class implements blink::WebMediaPlayer by keeping the android
// media player in the browser process. It listens to all the status changes
@@ -86,7 +90,8 @@ class WebMediaPlayerAndroid : public blink::WebMediaPlayer,
blink::WebMediaPlayerClient* client,
base::WeakPtr<media::WebMediaPlayerDelegate> delegate,
RendererMediaPlayerManager* player_manager,
- RendererCdmManager* cdm_manager,
+ media::CdmFactory* cdm_factory,
+ media::MediaPermission* media_permission,
blink::WebContentDecryptionModule* initial_cdm,
scoped_refptr<StreamTextureFactory> factory,
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
@@ -95,7 +100,6 @@ class WebMediaPlayerAndroid : public blink::WebMediaPlayer,
// blink::WebMediaPlayer implementation.
virtual void enterFullscreen();
- virtual bool canEnterFullscreen() const;
// Resource loading.
virtual void load(LoadType load_type,
@@ -127,6 +131,7 @@ class WebMediaPlayerAndroid : public blink::WebMediaPlayer,
unsigned char alpha,
SkXfermode::Mode mode);
+ // TODO(dshwang): remove |level|. crbug.com/443151
virtual bool copyVideoTextureToPlatformTexture(
blink::WebGraphicsContext3D* web_graphics_context,
unsigned int texture,
@@ -135,6 +140,13 @@ class WebMediaPlayerAndroid : public blink::WebMediaPlayer,
unsigned int type,
bool premultiply_alpha,
bool flip_y);
+ virtual bool copyVideoTextureToPlatformTexture(
+ blink::WebGraphicsContext3D* web_graphics_context,
+ unsigned int texture,
+ unsigned int internal_format,
+ unsigned int type,
+ bool premultiply_alpha,
+ bool flip_y);
// True if the loaded media has a playable video/audio track.
virtual bool hasVideo() const;
@@ -171,11 +183,13 @@ class WebMediaPlayerAndroid : public blink::WebMediaPlayer,
// cc::VideoFrameProvider implementation. These methods are running on the
// compositor thread.
- virtual void SetVideoFrameProviderClient(
+ void SetVideoFrameProviderClient(
cc::VideoFrameProvider::Client* client) override;
- virtual scoped_refptr<media::VideoFrame> GetCurrentFrame() override;
- virtual void PutCurrentFrame(const scoped_refptr<media::VideoFrame>& frame)
- override;
+ bool UpdateCurrentFrame(base::TimeTicks deadline_min,
+ base::TimeTicks deadline_max) override;
+ bool HasCurrentFrame() override;
+ scoped_refptr<media::VideoFrame> GetCurrentFrame() override;
+ void PutCurrentFrame() override;
// Media player callback handlers.
void OnMediaMetadataChanged(const base::TimeDelta& duration, int width,
@@ -195,7 +209,6 @@ class WebMediaPlayerAndroid : public blink::WebMediaPlayer,
// Functions called when media player status changes.
void OnConnectedToRemoteDevice(const std::string& remote_playback_message);
void OnDisconnectedFromRemoteDevice();
- void OnDidEnterFullscreen();
void OnDidExitFullscreen();
void OnMediaPlayerPlay();
void OnMediaPlayerPause();
@@ -203,7 +216,7 @@ class WebMediaPlayerAndroid : public blink::WebMediaPlayer,
void OnRemoteRouteAvailabilityChanged(bool routes_available);
// StreamTextureFactoryContextObserver implementation.
- virtual void ResetStreamTextureProxy() override;
+ void ResetStreamTextureProxy() override;
// Called when the player is released.
virtual void OnPlayerReleased();
@@ -214,7 +227,7 @@ class WebMediaPlayerAndroid : public blink::WebMediaPlayer,
virtual void ReleaseMediaResources();
// RenderFrameObserver implementation.
- virtual void OnDestruct() override;
+ void OnDestruct() override;
#if defined(VIDEO_HOLE)
// Calculate the boundary rectangle of the media player (i.e. location and
@@ -239,10 +252,7 @@ class WebMediaPlayerAndroid : public blink::WebMediaPlayer,
virtual MediaKeyException cancelKeyRequest(
const blink::WebString& key_system,
const blink::WebString& session_id);
- // TODO(jrummell): Remove this method once Blink updated to use the other
- // two methods.
- virtual void setContentDecryptionModule(
- blink::WebContentDecryptionModule* cdm);
+
virtual void setContentDecryptionModule(
blink::WebContentDecryptionModule* cdm,
blink::WebContentDecryptionModuleResult result);
@@ -257,11 +267,12 @@ class WebMediaPlayerAndroid : public blink::WebMediaPlayer,
void OnMediaSourceOpened(blink::WebMediaSource* web_media_source);
- void OnNeedKey(const std::string& type,
- const std::vector<uint8>& init_data);
+ void OnEncryptedMediaInitData(media::EmeInitDataType init_data_type,
+ const std::vector<uint8>& init_data);
- // TODO(xhwang): Implement WebMediaPlayer::setContentDecryptionModule().
- // See: http://crbug.com/224786
+ // Called when a decoder detects that the key needed to decrypt the stream
+ // is not available.
+ void OnWaitingForDecryptionKey();
protected:
// Helper method to update the playing state.
@@ -310,6 +321,14 @@ class WebMediaPlayerAndroid : public blink::WebMediaPlayer,
MediaKeyException CancelKeyRequestInternal(const std::string& key_system,
const std::string& session_id);
+ // Called when |cdm_context| is ready.
+ void OnCdmContextReady(media::CdmContext* cdm_context);
+
+ // Sets the CDM. Should only be called when |is_player_initialized_| is true
+ // and a new non-null |cdm_context_| is available. Fires |cdm_attached_cb_|
+ // with the result after the CDM is attached.
+ void SetCdmInternal(const media::CdmAttachedCB& cdm_attached_cb);
+
// Requests that this object notifies when a decryptor is ready through the
// |decryptor_ready_cb| provided.
// If |decryptor_ready_cb| is null, the existing callback will be fired with
@@ -322,11 +341,6 @@ class WebMediaPlayerAndroid : public blink::WebMediaPlayer,
blink::WebContentDecryptionModuleResult result,
bool success);
- bool EnsureTextureBackedSkBitmap(GrContext* gr, SkBitmap& bitmap,
- const blink::WebSize& size,
- GrSurfaceOrigin origin,
- GrPixelConfig config);
-
bool IsHLSStream() const;
blink::WebFrame* const frame_;
@@ -387,12 +401,13 @@ class WebMediaPlayerAndroid : public blink::WebMediaPlayer,
// Manages this object and delegates player calls to the browser process.
// Owned by RenderFrameImpl.
- RendererMediaPlayerManager* player_manager_;
+ RendererMediaPlayerManager* const player_manager_;
- // Delegates EME calls to the browser process. Owned by RenderFrameImpl.
- // TODO(xhwang): Remove |cdm_manager_| when prefixed EME is deprecated. See
+ // TODO(xhwang): Remove |cdm_factory_| when prefixed EME is deprecated. See
// http://crbug.com/249976
- RendererCdmManager* cdm_manager_;
+ media::CdmFactory* const cdm_factory_;
+
+ media::MediaPermission* media_permission_;
// Player ID assigned by the |player_manager_|.
int player_id_;
@@ -411,7 +426,10 @@ class WebMediaPlayerAndroid : public blink::WebMediaPlayer,
// Stream texture ID allocated to the video.
unsigned int stream_id_;
- // Whether the mediaplayer is playing.
+ // Whether the media player has been initialized.
+ bool is_player_initialized_;
+
+ // Whether the media player is playing.
bool is_playing_;
// Whether media player needs to re-establish the surface texture peer.
@@ -435,6 +453,9 @@ class WebMediaPlayerAndroid : public blink::WebMediaPlayer,
// Only used for the VIDEO_HOLE logic.
bool needs_external_surface_;
+ // Whether the player is in fullscreen.
+ bool is_fullscreen_;
+
// A pointer back to the compositor to inform it about state changes. This is
// not NULL while the compositor is actively using this webmediaplayer.
// Accessed on main thread and on compositor thread when main thread is
@@ -466,16 +487,16 @@ class WebMediaPlayerAndroid : public blink::WebMediaPlayer,
// has been selected.
std::string current_key_system_;
- // Temporary for EME v0.1. In the future the init data type should be passed
- // through GenerateKeyRequest() directly from WebKit.
- std::string init_data_type_;
+ // Temporary for EME v0.1. Not needed for unprefixed EME, and can be removed
+ // when prefixed EME is removed.
+ media::EmeInitDataType init_data_type_;
// Manages decryption keys and decrypts encrypted frames.
- scoped_ptr<ProxyDecryptor> proxy_decryptor_;
+ scoped_ptr<media::ProxyDecryptor> proxy_decryptor_;
- // Non-owned pointer to the CDM. Updated via calls to
- // setContentDecryptionModule().
- WebContentDecryptionModuleImpl* web_cdm_;
+ // Non-owned pointer to the CdmContext. Updated in the constructor,
+ // generateKeyRequest() or setContentDecryptionModule().
+ media::CdmContext* cdm_context_;
// This is only Used by Clear Key key system implementation, where a renderer
// side CDM will be used. This is similar to WebMediaPlayerImpl. For other key
diff --git a/chromium/content/renderer/media/audio_device_factory.cc b/chromium/content/renderer/media/audio_device_factory.cc
index bc903be7146..6d0dd1db021 100644
--- a/chromium/content/renderer/media/audio_device_factory.cc
+++ b/chromium/content/renderer/media/audio_device_factory.cc
@@ -17,33 +17,32 @@ AudioDeviceFactory* AudioDeviceFactory::factory_ = NULL;
// static
scoped_refptr<media::AudioOutputDevice> AudioDeviceFactory::NewOutputDevice(
- int render_view_id, int render_frame_id) {
+ int render_frame_id) {
if (factory_) {
media::AudioOutputDevice* const device =
- factory_->CreateOutputDevice(render_view_id);
+ factory_->CreateOutputDevice(render_frame_id);
if (device)
return device;
}
AudioMessageFilter* const filter = AudioMessageFilter::Get();
return new media::AudioOutputDevice(
- filter->CreateAudioOutputIPC(render_view_id, render_frame_id),
- filter->io_message_loop());
+ filter->CreateAudioOutputIPC(render_frame_id), filter->io_message_loop());
}
// static
scoped_refptr<media::AudioInputDevice> AudioDeviceFactory::NewInputDevice(
- int render_view_id) {
+ int render_frame_id) {
if (factory_) {
media::AudioInputDevice* const device =
- factory_->CreateInputDevice(render_view_id);
+ factory_->CreateInputDevice(render_frame_id);
if (device)
return device;
}
AudioInputMessageFilter* const filter = AudioInputMessageFilter::Get();
return new media::AudioInputDevice(
- filter->CreateAudioInputIPC(render_view_id), filter->io_message_loop());
+ filter->CreateAudioInputIPC(render_frame_id), filter->io_message_loop());
}
AudioDeviceFactory::AudioDeviceFactory() {
diff --git a/chromium/content/renderer/media/audio_device_factory.h b/chromium/content/renderer/media/audio_device_factory.h
index 3865753d8d0..e50f13978be 100644
--- a/chromium/content/renderer/media/audio_device_factory.h
+++ b/chromium/content/renderer/media/audio_device_factory.h
@@ -22,16 +22,16 @@ namespace content {
class CONTENT_EXPORT AudioDeviceFactory {
public:
// Creates an AudioOutputDevice using the currently registered factory.
- // |render_view_id| and |render_frame_id| refer to the render view and render
- // frame containing the entity producing the audio.
+ // |render_frame_id| refers to the RenderFrame containing the entity
+ // producing the audio.
static scoped_refptr<media::AudioOutputDevice> NewOutputDevice(
- int render_view_id, int render_frame_id);
+ int render_frame_id);
// Creates an AudioInputDevice using the currently registered factory.
- // |render_view_id| refers to the render view containing the entity consuming
- // the audio.
+ // |render_frame_id| refers to the RenderFrame containing the entity
+ // consuming the audio.
static scoped_refptr<media::AudioInputDevice> NewInputDevice(
- int render_view_id);
+ int render_frame_id);
protected:
AudioDeviceFactory();
@@ -41,8 +41,8 @@ class CONTENT_EXPORT AudioDeviceFactory {
// functions to provide alternate audio device implementations.
// If the return value of either of these function is NULL, we fall back
// on the default implementation.
- virtual media::AudioOutputDevice* CreateOutputDevice(int render_view_id) = 0;
- virtual media::AudioInputDevice* CreateInputDevice(int render_view_id) = 0;
+ virtual media::AudioOutputDevice* CreateOutputDevice(int render_frame_id) = 0;
+ virtual media::AudioInputDevice* CreateInputDevice(int render_frame_id) = 0;
private:
// The current globally registered factory. This is NULL when we should
diff --git a/chromium/content/renderer/media/audio_input_message_filter.cc b/chromium/content/renderer/media/audio_input_message_filter.cc
index ac987afd360..6c2906f3678 100644
--- a/chromium/content/renderer/media/audio_input_message_filter.cc
+++ b/chromium/content/renderer/media/audio_input_message_filter.cc
@@ -31,7 +31,7 @@ class AudioInputMessageFilter::AudioInputIPCImpl
: public NON_EXPORTED_BASE(media::AudioInputIPC) {
public:
AudioInputIPCImpl(const scoped_refptr<AudioInputMessageFilter>& filter,
- int render_view_id);
+ int render_frame_id);
~AudioInputIPCImpl() override;
// media::AudioInputIPC implementation.
@@ -46,7 +46,7 @@ class AudioInputMessageFilter::AudioInputIPCImpl
private:
const scoped_refptr<AudioInputMessageFilter> filter_;
- const int render_view_id_;
+ const int render_frame_id_;
int stream_id_;
};
@@ -170,18 +170,20 @@ void AudioInputMessageFilter::OnStreamStateChanged(
}
AudioInputMessageFilter::AudioInputIPCImpl::AudioInputIPCImpl(
- const scoped_refptr<AudioInputMessageFilter>& filter, int render_view_id)
+ const scoped_refptr<AudioInputMessageFilter>& filter,
+ int render_frame_id)
: filter_(filter),
- render_view_id_(render_view_id),
- stream_id_(kStreamIDNotSet) {}
+ render_frame_id_(render_frame_id),
+ stream_id_(kStreamIDNotSet) {
+}
AudioInputMessageFilter::AudioInputIPCImpl::~AudioInputIPCImpl() {}
scoped_ptr<media::AudioInputIPC> AudioInputMessageFilter::CreateAudioInputIPC(
- int render_view_id) {
- DCHECK_GT(render_view_id, 0);
+ int render_frame_id) {
+ DCHECK_GT(render_frame_id, 0);
return scoped_ptr<media::AudioInputIPC>(
- new AudioInputIPCImpl(this, render_view_id));
+ new AudioInputIPCImpl(this, render_frame_id));
}
void AudioInputMessageFilter::AudioInputIPCImpl::CreateStream(
@@ -202,8 +204,8 @@ void AudioInputMessageFilter::AudioInputIPCImpl::CreateStream(
config.params = params;
config.automatic_gain_control = automatic_gain_control;
config.shared_memory_count = total_segments;
- filter_->Send(new AudioInputHostMsg_CreateStream(
- stream_id_, render_view_id_, session_id, config));
+ filter_->Send(new AudioInputHostMsg_CreateStream(stream_id_, render_frame_id_,
+ session_id, config));
}
void AudioInputMessageFilter::AudioInputIPCImpl::RecordStream() {
diff --git a/chromium/content/renderer/media/audio_input_message_filter.h b/chromium/content/renderer/media/audio_input_message_filter.h
index c1b4ba8a5a1..0b29cbc51e3 100644
--- a/chromium/content/renderer/media/audio_input_message_filter.h
+++ b/chromium/content/renderer/media/audio_input_message_filter.h
@@ -31,12 +31,12 @@ class CONTENT_EXPORT AudioInputMessageFilter : public IPC::MessageFilter {
// Getter for the one AudioInputMessageFilter object.
static AudioInputMessageFilter* Get();
- // Create an AudioInputIPC to be owned by one delegate. |render_view_id| is
- // the render view containing the entity consuming the audio.
+ // Create an AudioInputIPC to be owned by one delegate. |render_frame_id|
+ // refers to the RenderFrame containing the entity consuming the audio.
//
// The returned object is not thread-safe, and must be used on
// |io_message_loop|.
- scoped_ptr<media::AudioInputIPC> CreateAudioInputIPC(int render_view_id);
+ scoped_ptr<media::AudioInputIPC> CreateAudioInputIPC(int render_frame_id);
scoped_refptr<base::MessageLoopProxy> io_message_loop() const {
return io_message_loop_;
@@ -44,7 +44,7 @@ class CONTENT_EXPORT AudioInputMessageFilter : public IPC::MessageFilter {
private:
// Implementation of media::AudioInputIPC which augments IPC calls with
- // stream_id and the destination render_view_id.
+ // stream_id and the destination render_frame_id.
class AudioInputIPCImpl;
~AudioInputMessageFilter() override;
diff --git a/chromium/content/renderer/media/audio_message_filter.cc b/chromium/content/renderer/media/audio_message_filter.cc
index b03cdd61271..ce26c13b40c 100644
--- a/chromium/content/renderer/media/audio_message_filter.cc
+++ b/chromium/content/renderer/media/audio_message_filter.cc
@@ -22,7 +22,6 @@ class AudioMessageFilter::AudioOutputIPCImpl
: public NON_EXPORTED_BASE(media::AudioOutputIPC) {
public:
AudioOutputIPCImpl(const scoped_refptr<AudioMessageFilter>& filter,
- int render_view_id,
int render_frame_id);
~AudioOutputIPCImpl() override;
@@ -37,7 +36,6 @@ class AudioMessageFilter::AudioOutputIPCImpl
private:
const scoped_refptr<AudioMessageFilter> filter_;
- const int render_view_id_;
const int render_frame_id_;
int stream_id_;
};
@@ -47,7 +45,6 @@ AudioMessageFilter* AudioMessageFilter::g_filter = NULL;
AudioMessageFilter::AudioMessageFilter(
const scoped_refptr<base::MessageLoopProxy>& io_message_loop)
: sender_(NULL),
- audio_hardware_config_(NULL),
io_message_loop_(io_message_loop) {
DCHECK(!g_filter);
g_filter = this;
@@ -65,20 +62,18 @@ AudioMessageFilter* AudioMessageFilter::Get() {
AudioMessageFilter::AudioOutputIPCImpl::AudioOutputIPCImpl(
const scoped_refptr<AudioMessageFilter>& filter,
- int render_view_id,
int render_frame_id)
: filter_(filter),
- render_view_id_(render_view_id),
render_frame_id_(render_frame_id),
stream_id_(kStreamIDNotSet) {}
AudioMessageFilter::AudioOutputIPCImpl::~AudioOutputIPCImpl() {}
scoped_ptr<media::AudioOutputIPC> AudioMessageFilter::CreateAudioOutputIPC(
- int render_view_id, int render_frame_id) {
- DCHECK_GT(render_view_id, 0);
+ int render_frame_id) {
+ DCHECK_GT(render_frame_id, 0);
return scoped_ptr<media::AudioOutputIPC>(
- new AudioOutputIPCImpl(this, render_view_id, render_frame_id));
+ new AudioOutputIPCImpl(this, render_frame_id));
}
void AudioMessageFilter::AudioOutputIPCImpl::CreateStream(
@@ -89,8 +84,8 @@ void AudioMessageFilter::AudioOutputIPCImpl::CreateStream(
DCHECK(delegate);
DCHECK_EQ(stream_id_, kStreamIDNotSet);
stream_id_ = filter_->delegates_.Add(delegate);
- filter_->Send(new AudioHostMsg_CreateStream(
- stream_id_, render_view_id_, render_frame_id_, session_id, params));
+ filter_->Send(new AudioHostMsg_CreateStream(stream_id_, render_frame_id_,
+ session_id, params));
}
void AudioMessageFilter::AudioOutputIPCImpl::PlayStream() {
@@ -131,7 +126,6 @@ bool AudioMessageFilter::OnMessageReceived(const IPC::Message& message) {
IPC_BEGIN_MESSAGE_MAP(AudioMessageFilter, message)
IPC_MESSAGE_HANDLER(AudioMsg_NotifyStreamCreated, OnStreamCreated)
IPC_MESSAGE_HANDLER(AudioMsg_NotifyStreamStateChanged, OnStreamStateChanged)
- IPC_MESSAGE_HANDLER(AudioMsg_NotifyDeviceChanged, OnOutputDeviceChanged)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
@@ -202,44 +196,4 @@ void AudioMessageFilter::OnStreamStateChanged(
delegate->OnStateChanged(state);
}
-void AudioMessageFilter::OnOutputDeviceChanged(int stream_id,
- int new_buffer_size,
- int new_sample_rate) {
- DCHECK(io_message_loop_->BelongsToCurrentThread());
- base::AutoLock auto_lock(lock_);
-
- WebRtcLogMessage(base::StringPrintf(
- "AMF::OnOutputDeviceChanged. stream_id=%d"
- ", new_buffer_size=%d, new_sample_rate=%d",
- stream_id,
- new_buffer_size,
- new_sample_rate));
-
- // Ignore the message if an audio hardware config hasn't been created; this
- // can occur if the renderer is using the high latency audio path.
- CHECK(audio_hardware_config_);
-
- // TODO(crogers): fix OnOutputDeviceChanged() to pass AudioParameters.
- media::ChannelLayout channel_layout =
- audio_hardware_config_->GetOutputChannelLayout();
- int channels = audio_hardware_config_->GetOutputChannels();
-
- media::AudioParameters output_params;
- output_params.Reset(
- media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
- channel_layout,
- channels,
- new_sample_rate,
- 16,
- new_buffer_size);
-
- audio_hardware_config_->UpdateOutputConfig(output_params);
-}
-
-void AudioMessageFilter::SetAudioHardwareConfig(
- media::AudioHardwareConfig* config) {
- base::AutoLock auto_lock(lock_);
- audio_hardware_config_ = config;
-}
-
} // namespace content
diff --git a/chromium/content/renderer/media/audio_message_filter.h b/chromium/content/renderer/media/audio_message_filter.h
index db973d04fe7..2404ca0b026 100644
--- a/chromium/content/renderer/media/audio_message_filter.h
+++ b/chromium/content/renderer/media/audio_message_filter.h
@@ -34,20 +34,12 @@ class CONTENT_EXPORT AudioMessageFilter : public IPC::MessageFilter {
// Getter for the one AudioMessageFilter object.
static AudioMessageFilter* Get();
- // Create an AudioOutputIPC to be owned by one delegate. |render_view_id| and
- // |render_frame_id| are the render view and render frame containing the
- // entity producing the audio.
- // TODO(jam): remove render_view_id
+ // Create an AudioOutputIPC to be owned by one delegate. |render_frame_id| is
+ // the RenderFrame containing the entity producing the audio.
//
// The returned object is not thread-safe, and must be used on
// |io_message_loop|.
- scoped_ptr<media::AudioOutputIPC> CreateAudioOutputIPC(int render_view_id,
- int render_frame_id);
-
- // When set, AudioMessageFilter will update the AudioHardwareConfig with new
- // configuration values as received by OnOutputDeviceChanged(). The provided
- // |config| must outlive AudioMessageFilter.
- void SetAudioHardwareConfig(media::AudioHardwareConfig* config);
+ scoped_ptr<media::AudioOutputIPC> CreateAudioOutputIPC(int render_frame_id);
// IO message loop associated with this message filter.
scoped_refptr<base::MessageLoopProxy> io_message_loop() const {
@@ -62,7 +54,7 @@ class CONTENT_EXPORT AudioMessageFilter : public IPC::MessageFilter {
FRIEND_TEST_ALL_PREFIXES(AudioMessageFilterTest, Delegates);
// Implementation of media::AudioOutputIPC which augments IPC calls with
- // stream_id and the source render_view_id.
+ // stream_id and the source render_frame_id.
class AudioOutputIPCImpl;
// Sends an IPC message using |sender_|.
@@ -84,10 +76,6 @@ class CONTENT_EXPORT AudioMessageFilter : public IPC::MessageFilter {
void OnStreamStateChanged(int stream_id,
media::AudioOutputIPCDelegate::State state);
- // Received when the browser process detects an output device change.
- void OnOutputDeviceChanged(int stream_id, int new_buffer_size,
- int new_sample_rate);
-
// IPC sender for Send(); must only be accesed on |io_message_loop_|.
IPC::Sender* sender_;
@@ -95,11 +83,6 @@ class CONTENT_EXPORT AudioMessageFilter : public IPC::MessageFilter {
// |io_message_loop_|.
IDMap<media::AudioOutputIPCDelegate> delegates_;
- // Audio hardware configuration to update when OnOutputDeviceChanged() fires.
- // Access is guarded by |lock_|.
- base::Lock lock_;
- media::AudioHardwareConfig* audio_hardware_config_;
-
// Message loop on which IPC calls are driven.
const scoped_refptr<base::MessageLoopProxy> io_message_loop_;
diff --git a/chromium/content/renderer/media/audio_message_filter_unittest.cc b/chromium/content/renderer/media/audio_message_filter_unittest.cc
index 2626f4e52f9..45a06818089 100644
--- a/chromium/content/renderer/media/audio_message_filter_unittest.cc
+++ b/chromium/content/renderer/media/audio_message_filter_unittest.cc
@@ -11,7 +11,6 @@
namespace content {
namespace {
-const int kRenderViewId = 1;
const int kRenderFrameId = 2;
class MockAudioDelegate : public media::AudioOutputIPCDelegate {
@@ -78,7 +77,7 @@ TEST(AudioMessageFilterTest, Basic) {
MockAudioDelegate delegate;
const scoped_ptr<media::AudioOutputIPC> ipc =
- filter->CreateAudioOutputIPC(kRenderViewId, kRenderFrameId);
+ filter->CreateAudioOutputIPC(kRenderFrameId);
static const int kSessionId = 0;
ipc->CreateStream(&delegate, media::AudioParameters(), kSessionId);
static const int kStreamId = 1;
@@ -120,9 +119,9 @@ TEST(AudioMessageFilterTest, Delegates) {
MockAudioDelegate delegate1;
MockAudioDelegate delegate2;
const scoped_ptr<media::AudioOutputIPC> ipc1 =
- filter->CreateAudioOutputIPC(kRenderViewId, kRenderFrameId);
+ filter->CreateAudioOutputIPC(kRenderFrameId);
const scoped_ptr<media::AudioOutputIPC> ipc2 =
- filter->CreateAudioOutputIPC(kRenderViewId, kRenderFrameId);
+ filter->CreateAudioOutputIPC(kRenderFrameId);
static const int kSessionId = 0;
ipc1->CreateStream(&delegate1, media::AudioParameters(), kSessionId);
ipc2->CreateStream(&delegate2, media::AudioParameters(), kSessionId);
diff --git a/chromium/content/renderer/media/audio_renderer_mixer_manager.cc b/chromium/content/renderer/media/audio_renderer_mixer_manager.cc
index 4a62d1a1583..498fbfa1292 100644
--- a/chromium/content/renderer/media/audio_renderer_mixer_manager.cc
+++ b/chromium/content/renderer/media/audio_renderer_mixer_manager.cc
@@ -27,15 +27,12 @@ AudioRendererMixerManager::~AudioRendererMixerManager() {
}
media::AudioRendererMixerInput* AudioRendererMixerManager::CreateInput(
- int source_render_view_id, int source_render_frame_id) {
+ int source_render_frame_id) {
return new media::AudioRendererMixerInput(
- base::Bind(
- &AudioRendererMixerManager::GetMixer, base::Unretained(this),
- source_render_view_id,
- source_render_frame_id),
- base::Bind(
- &AudioRendererMixerManager::RemoveMixer, base::Unretained(this),
- source_render_view_id));
+ base::Bind(&AudioRendererMixerManager::GetMixer, base::Unretained(this),
+ source_render_frame_id),
+ base::Bind(&AudioRendererMixerManager::RemoveMixer,
+ base::Unretained(this), source_render_frame_id));
}
void AudioRendererMixerManager::SetAudioRendererSinkForTesting(
@@ -44,13 +41,12 @@ void AudioRendererMixerManager::SetAudioRendererSinkForTesting(
}
media::AudioRendererMixer* AudioRendererMixerManager::GetMixer(
- int source_render_view_id,
int source_render_frame_id,
const media::AudioParameters& params) {
// Effects are not passed through to output creation, so ensure none are set.
DCHECK_EQ(params.effects(), media::AudioParameters::NO_EFFECTS);
- const MixerKey key(source_render_view_id, params);
+ const MixerKey key(source_render_frame_id, params);
base::AutoLock auto_lock(mixers_lock_);
AudioRendererMixerMap::iterator it = mixers_.find(key);
@@ -85,8 +81,8 @@ media::AudioRendererMixer* AudioRendererMixerManager::GetMixer(
params, output_params, sink_for_testing_);
} else {
mixer = new media::AudioRendererMixer(
- params, output_params, AudioDeviceFactory::NewOutputDevice(
- source_render_view_id, source_render_frame_id));
+ params, output_params,
+ AudioDeviceFactory::NewOutputDevice(source_render_frame_id));
}
AudioRendererMixerReference mixer_reference = { mixer, 1 };
@@ -95,9 +91,9 @@ media::AudioRendererMixer* AudioRendererMixerManager::GetMixer(
}
void AudioRendererMixerManager::RemoveMixer(
- int source_render_view_id,
+ int source_render_frame_id,
const media::AudioParameters& params) {
- const MixerKey key(source_render_view_id, params);
+ const MixerKey key(source_render_frame_id, params);
base::AutoLock auto_lock(mixers_lock_);
AudioRendererMixerMap::iterator it = mixers_.find(key);
diff --git a/chromium/content/renderer/media/audio_renderer_mixer_manager.h b/chromium/content/renderer/media/audio_renderer_mixer_manager.h
index f3d35fcc53f..bfb29cf6267 100644
--- a/chromium/content/renderer/media/audio_renderer_mixer_manager.h
+++ b/chromium/content/renderer/media/audio_renderer_mixer_manager.h
@@ -45,23 +45,20 @@ class CONTENT_EXPORT AudioRendererMixerManager {
// Creates an AudioRendererMixerInput with the proper callbacks necessary to
// retrieve an AudioRendererMixer instance from AudioRendererMixerManager.
- // |source_render_view_id| refers to the RenderView containing the entity
- // rendering the audio. |source_render_frame_id| refers to the RenderFrame
- // containing the entity rendering the audio. Caller must ensure
- // AudioRendererMixerManager outlives the returned input.
- media::AudioRendererMixerInput* CreateInput(int source_render_view_id,
- int source_render_frame_id);
+ // |source_render_frame_id| refers to the RenderFrame containing the entity
+ // rendering the audio. Caller must ensure AudioRendererMixerManager outlives
+ // the returned input.
+ media::AudioRendererMixerInput* CreateInput(int source_render_frame_id);
// Returns a mixer instance based on AudioParameters; an existing one if one
// with the provided AudioParameters exists or a new one if not.
- media::AudioRendererMixer* GetMixer(int source_render_view_id,
- int source_render_frame_id,
+ media::AudioRendererMixer* GetMixer(int source_render_frame_id,
const media::AudioParameters& params);
// Remove a mixer instance given a mixer if the only other reference is held
// by AudioRendererMixerManager. Every AudioRendererMixer owner must call
// this method when it's done with a mixer.
- void RemoveMixer(int source_render_view_id,
+ void RemoveMixer(int source_render_frame_id,
const media::AudioParameters& params);
private:
diff --git a/chromium/content/renderer/media/audio_renderer_mixer_manager_unittest.cc b/chromium/content/renderer/media/audio_renderer_mixer_manager_unittest.cc
index f1915edf1a1..8ac2a5ff30e 100644
--- a/chromium/content/renderer/media/audio_renderer_mixer_manager_unittest.cc
+++ b/chromium/content/renderer/media/audio_renderer_mixer_manager_unittest.cc
@@ -23,9 +23,7 @@ static const int kSampleRate = 48000;
static const int kBufferSize = 8192;
static const media::ChannelLayout kChannelLayout = media::CHANNEL_LAYOUT_STEREO;
-static const int kRenderViewId = 123;
static const int kRenderFrameId = 124;
-static const int kAnotherRenderViewId = 456;
static const int kAnotherRenderFrameId = 678;
using media::AudioParameters;
@@ -50,14 +48,14 @@ class AudioRendererMixerManagerTest : public testing::Test {
manager_->SetAudioRendererSinkForTesting(mock_sink_.get());
}
- media::AudioRendererMixer* GetMixer(int source_render_view_id,
+ media::AudioRendererMixer* GetMixer(int source_render_frame_id,
const media::AudioParameters& params) {
- return manager_->GetMixer(source_render_view_id, MSG_ROUTING_NONE, params);
+ return manager_->GetMixer(source_render_frame_id, params);
}
- void RemoveMixer(int source_render_view_id,
+ void RemoveMixer(int source_render_frame_id,
const media::AudioParameters& params) {
- return manager_->RemoveMixer(source_render_view_id, params);
+ return manager_->RemoveMixer(source_render_frame_id, params);
}
// Number of instantiated mixers.
@@ -88,22 +86,22 @@ TEST_F(AudioRendererMixerManagerTest, GetRemoveMixer) {
AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate,
kBitsPerChannel, kBufferSize);
- media::AudioRendererMixer* mixer1 = GetMixer(kRenderViewId, params1);
+ media::AudioRendererMixer* mixer1 = GetMixer(kRenderFrameId, params1);
ASSERT_TRUE(mixer1);
EXPECT_EQ(mixer_count(), 1);
// The same parameters should return the same mixer1.
- EXPECT_EQ(mixer1, GetMixer(kRenderViewId, params1));
+ EXPECT_EQ(mixer1, GetMixer(kRenderFrameId, params1));
EXPECT_EQ(mixer_count(), 1);
// Remove the extra mixer we just acquired.
- RemoveMixer(kRenderViewId, params1);
+ RemoveMixer(kRenderFrameId, params1);
EXPECT_EQ(mixer_count(), 1);
media::AudioParameters params2(
AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate * 2,
kBitsPerChannel, kBufferSize * 2);
- media::AudioRendererMixer* mixer2 = GetMixer(kRenderViewId, params2);
+ media::AudioRendererMixer* mixer2 = GetMixer(kRenderFrameId, params2);
ASSERT_TRUE(mixer2);
EXPECT_EQ(mixer_count(), 2);
@@ -111,9 +109,9 @@ TEST_F(AudioRendererMixerManagerTest, GetRemoveMixer) {
EXPECT_NE(mixer1, mixer2);
// Remove both outstanding mixers.
- RemoveMixer(kRenderViewId, params1);
+ RemoveMixer(kRenderFrameId, params1);
EXPECT_EQ(mixer_count(), 1);
- RemoveMixer(kRenderViewId, params2);
+ RemoveMixer(kRenderFrameId, params2);
EXPECT_EQ(mixer_count(), 0);
}
@@ -129,7 +127,7 @@ TEST_F(AudioRendererMixerManagerTest, MixerReuse) {
kSampleRate,
kBitsPerChannel,
kBufferSize);
- media::AudioRendererMixer* mixer1 = GetMixer(kRenderViewId, params1);
+ media::AudioRendererMixer* mixer1 = GetMixer(kRenderFrameId, params1);
ASSERT_TRUE(mixer1);
EXPECT_EQ(mixer_count(), 1);
@@ -141,9 +139,9 @@ TEST_F(AudioRendererMixerManagerTest, MixerReuse) {
kBitsPerChannel * 2,
kBufferSize * 2,
AudioParameters::NO_EFFECTS);
- EXPECT_EQ(mixer1, GetMixer(kRenderViewId, params2));
+ EXPECT_EQ(mixer1, GetMixer(kRenderFrameId, params2));
EXPECT_EQ(mixer_count(), 1);
- RemoveMixer(kRenderViewId, params2);
+ RemoveMixer(kRenderFrameId, params2);
EXPECT_EQ(mixer_count(), 1);
// Modify some parameters that do matter.
@@ -155,13 +153,13 @@ TEST_F(AudioRendererMixerManagerTest, MixerReuse) {
AudioParameters::NO_EFFECTS);
ASSERT_NE(params3.channel_layout(), params1.channel_layout());
- EXPECT_NE(mixer1, GetMixer(kRenderViewId, params3));
+ EXPECT_NE(mixer1, GetMixer(kRenderFrameId, params3));
EXPECT_EQ(mixer_count(), 2);
- RemoveMixer(kRenderViewId, params3);
+ RemoveMixer(kRenderFrameId, params3);
EXPECT_EQ(mixer_count(), 1);
// Remove final mixer.
- RemoveMixer(kRenderViewId, params1);
+ RemoveMixer(kRenderFrameId, params1);
EXPECT_EQ(mixer_count(), 0);
}
@@ -183,12 +181,12 @@ TEST_F(AudioRendererMixerManagerTest, CreateInput) {
EXPECT_EQ(mixer_count(), 0);
media::FakeAudioRenderCallback callback(0);
scoped_refptr<media::AudioRendererMixerInput> input(
- manager_->CreateInput(kRenderViewId, kRenderFrameId));
+ manager_->CreateInput(kRenderFrameId));
input->Initialize(params, &callback);
EXPECT_EQ(mixer_count(), 0);
media::FakeAudioRenderCallback another_callback(1);
scoped_refptr<media::AudioRendererMixerInput> another_input(
- manager_->CreateInput(kAnotherRenderViewId, kAnotherRenderFrameId));
+ manager_->CreateInput(kAnotherRenderFrameId));
another_input->Initialize(params, &another_callback);
EXPECT_EQ(mixer_count(), 0);
diff --git a/chromium/content/renderer/media/cdm_session_adapter.cc b/chromium/content/renderer/media/cdm_session_adapter.cc
deleted file mode 100644
index 276bb3e3f2d..00000000000
--- a/chromium/content/renderer/media/cdm_session_adapter.cc
+++ /dev/null
@@ -1,199 +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/renderer/media/cdm_session_adapter.h"
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/memory/weak_ptr.h"
-#include "base/stl_util.h"
-#include "content/renderer/media/crypto/key_systems.h"
-#include "content/renderer/media/webcontentdecryptionmodulesession_impl.h"
-#include "media/base/cdm_factory.h"
-#include "media/base/cdm_promise.h"
-#include "media/base/media_keys.h"
-#include "url/gurl.h"
-
-namespace content {
-
-const char kMediaEME[] = "Media.EME.";
-const char kDot[] = ".";
-
-CdmSessionAdapter::CdmSessionAdapter() : weak_ptr_factory_(this) {
-}
-
-CdmSessionAdapter::~CdmSessionAdapter() {}
-
-bool CdmSessionAdapter::Initialize(media::CdmFactory* cdm_factory,
- const std::string& key_system,
- const GURL& security_origin) {
- // TODO(xhwang): This is why we need to include "key_systems.h". Move
- // KeySystemNameForUMA out of src/content so we can move CdmSessionAdapter to
- // src/media.
- key_system_uma_prefix_ = kMediaEME + KeySystemNameForUMA(key_system) + kDot;
-
- base::WeakPtr<CdmSessionAdapter> weak_this = weak_ptr_factory_.GetWeakPtr();
- media_keys_ = cdm_factory->Create(
- key_system,
- security_origin,
- base::Bind(&CdmSessionAdapter::OnSessionMessage, weak_this),
- base::Bind(&CdmSessionAdapter::OnSessionReady, weak_this),
- base::Bind(&CdmSessionAdapter::OnSessionClosed, weak_this),
- base::Bind(&CdmSessionAdapter::OnSessionError, weak_this),
- base::Bind(&CdmSessionAdapter::OnSessionKeysChange, weak_this),
- base::Bind(&CdmSessionAdapter::OnSessionExpirationUpdate, weak_this));
-
- // Success if |media_keys_| created.
- return media_keys_;
-}
-
-void CdmSessionAdapter::SetServerCertificate(
- const uint8* server_certificate,
- int server_certificate_length,
- scoped_ptr<media::SimpleCdmPromise> promise) {
- media_keys_->SetServerCertificate(
- server_certificate, server_certificate_length, promise.Pass());
-}
-
-WebContentDecryptionModuleSessionImpl* CdmSessionAdapter::CreateSession() {
- return new WebContentDecryptionModuleSessionImpl(this);
-}
-
-bool CdmSessionAdapter::RegisterSession(
- const std::string& web_session_id,
- base::WeakPtr<WebContentDecryptionModuleSessionImpl> session) {
- // If this session ID is already registered, don't register it again.
- if (ContainsKey(sessions_, web_session_id))
- return false;
-
- sessions_[web_session_id] = session;
- return true;
-}
-
-void CdmSessionAdapter::UnregisterSession(const std::string& web_session_id) {
- DCHECK(ContainsKey(sessions_, web_session_id));
- sessions_.erase(web_session_id);
-}
-
-void CdmSessionAdapter::InitializeNewSession(
- const std::string& init_data_type,
- const uint8* init_data,
- int init_data_length,
- media::MediaKeys::SessionType session_type,
- scoped_ptr<media::NewSessionCdmPromise> promise) {
- media_keys_->CreateSession(init_data_type,
- init_data,
- init_data_length,
- session_type,
- promise.Pass());
-}
-
-void CdmSessionAdapter::LoadSession(
- const std::string& web_session_id,
- scoped_ptr<media::NewSessionCdmPromise> promise) {
- media_keys_->LoadSession(web_session_id, promise.Pass());
-}
-
-void CdmSessionAdapter::UpdateSession(
- const std::string& web_session_id,
- const uint8* response,
- int response_length,
- scoped_ptr<media::SimpleCdmPromise> promise) {
- media_keys_->UpdateSession(
- web_session_id, response, response_length, promise.Pass());
-}
-
-void CdmSessionAdapter::CloseSession(
- const std::string& web_session_id,
- scoped_ptr<media::SimpleCdmPromise> promise) {
- media_keys_->CloseSession(web_session_id, promise.Pass());
-}
-
-void CdmSessionAdapter::RemoveSession(
- const std::string& web_session_id,
- scoped_ptr<media::SimpleCdmPromise> promise) {
- media_keys_->RemoveSession(web_session_id, promise.Pass());
-}
-
-void CdmSessionAdapter::GetUsableKeyIds(
- const std::string& web_session_id,
- scoped_ptr<media::KeyIdsPromise> promise) {
- media_keys_->GetUsableKeyIds(web_session_id, promise.Pass());
-}
-
-media::Decryptor* CdmSessionAdapter::GetDecryptor() {
- return media_keys_->GetDecryptor();
-}
-
-const std::string& CdmSessionAdapter::GetKeySystemUMAPrefix() const {
- return key_system_uma_prefix_;
-}
-
-#if defined(ENABLE_BROWSER_CDMS)
-int CdmSessionAdapter::GetCdmId() const {
- return media_keys_->GetCdmId();
-}
-#endif // defined(ENABLE_BROWSER_CDMS)
-
-void CdmSessionAdapter::OnSessionMessage(const std::string& web_session_id,
- const std::vector<uint8>& message,
- const GURL& destination_url) {
- WebContentDecryptionModuleSessionImpl* session = GetSession(web_session_id);
- DLOG_IF(WARNING, !session) << __FUNCTION__ << " for unknown session "
- << web_session_id;
- if (session)
- session->OnSessionMessage(message, destination_url);
-}
-
-void CdmSessionAdapter::OnSessionKeysChange(const std::string& web_session_id,
- bool has_additional_usable_key) {
- WebContentDecryptionModuleSessionImpl* session = GetSession(web_session_id);
- DLOG_IF(WARNING, !session) << __FUNCTION__ << " for unknown session "
- << web_session_id;
- if (session)
- session->OnSessionKeysChange(has_additional_usable_key);
-}
-
-void CdmSessionAdapter::OnSessionExpirationUpdate(
- const std::string& web_session_id,
- const base::Time& new_expiry_time) {
- WebContentDecryptionModuleSessionImpl* session = GetSession(web_session_id);
- DLOG_IF(WARNING, !session) << __FUNCTION__ << " for unknown session "
- << web_session_id;
- if (session)
- session->OnSessionExpirationUpdate(new_expiry_time);
-}
-
-void CdmSessionAdapter::OnSessionReady(const std::string& web_session_id) {
- // Ready events not used by unprefixed EME.
- // TODO(jrummell): Remove when prefixed EME removed.
-}
-
-void CdmSessionAdapter::OnSessionClosed(const std::string& web_session_id) {
- WebContentDecryptionModuleSessionImpl* session = GetSession(web_session_id);
- DLOG_IF(WARNING, !session) << __FUNCTION__ << " for unknown session "
- << web_session_id;
- if (session)
- session->OnSessionClosed();
-}
-
-void CdmSessionAdapter::OnSessionError(
- const std::string& web_session_id,
- media::MediaKeys::Exception exception_code,
- uint32 system_code,
- const std::string& error_message) {
- // Error events not used by unprefixed EME.
- // TODO(jrummell): Remove when prefixed EME removed.
-}
-
-WebContentDecryptionModuleSessionImpl* CdmSessionAdapter::GetSession(
- const std::string& web_session_id) {
- // Since session objects may get garbage collected, it is possible that there
- // are events coming back from the CDM and the session has been unregistered.
- // We can not tell if the CDM is firing events at sessions that never existed.
- SessionMap::iterator session = sessions_.find(web_session_id);
- return (session != sessions_.end()) ? session->second.get() : NULL;
-}
-
-} // namespace content
diff --git a/chromium/content/renderer/media/cdm_session_adapter.h b/chromium/content/renderer/media/cdm_session_adapter.h
deleted file mode 100644
index 264067e98fc..00000000000
--- a/chromium/content/renderer/media/cdm_session_adapter.h
+++ /dev/null
@@ -1,150 +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_RENDERER_MEDIA_CDM_SESSION_ADAPTER_H_
-#define CONTENT_RENDERER_MEDIA_CDM_SESSION_ADAPTER_H_
-
-#include <map>
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/containers/hash_tables.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "media/base/media_keys.h"
-#include "third_party/WebKit/public/platform/WebContentDecryptionModuleSession.h"
-
-class GURL;
-
-namespace media {
-class CdmFactory;
-}
-
-namespace content {
-
-class WebContentDecryptionModuleSessionImpl;
-
-// Owns the CDM instance and makes calls from session objects to the CDM.
-// Forwards the web session ID-based callbacks of the MediaKeys interface to the
-// appropriate session object. Callers should hold references to this class
-// as long as they need the CDM instance.
-class CdmSessionAdapter : public base::RefCounted<CdmSessionAdapter> {
- public:
- CdmSessionAdapter();
-
- // Returns true on success.
- bool Initialize(media::CdmFactory* cdm_factory,
- const std::string& key_system,
- const GURL& security_origin);
-
- // Provides a server certificate to be used to encrypt messages to the
- // license server.
- void SetServerCertificate(const uint8* server_certificate,
- int server_certificate_length,
- scoped_ptr<media::SimpleCdmPromise> promise);
-
- // Creates a new session and adds it to the internal map. The caller owns the
- // created session. RemoveSession() must be called when destroying it, if
- // RegisterSession() was called.
- WebContentDecryptionModuleSessionImpl* CreateSession();
-
- // Adds a session to the internal map. Called once the session is successfully
- // initialized. Returns true if the session was registered, false if there is
- // already an existing session with the same |web_session_id|.
- bool RegisterSession(
- const std::string& web_session_id,
- base::WeakPtr<WebContentDecryptionModuleSessionImpl> session);
-
- // Removes a session from the internal map.
- void UnregisterSession(const std::string& web_session_id);
-
- // Initializes a session with the |init_data_type|, |init_data| and
- // |session_type| provided.
- void InitializeNewSession(const std::string& init_data_type,
- const uint8* init_data,
- int init_data_length,
- media::MediaKeys::SessionType session_type,
- scoped_ptr<media::NewSessionCdmPromise> promise);
-
- // Loads the session specified by |web_session_id|.
- void LoadSession(const std::string& web_session_id,
- scoped_ptr<media::NewSessionCdmPromise> promise);
-
- // Updates the session specified by |web_session_id| with |response|.
- void UpdateSession(const std::string& web_session_id,
- const uint8* response,
- int response_length,
- scoped_ptr<media::SimpleCdmPromise> promise);
-
- // Closes the session specified by |web_session_id|.
- void CloseSession(const std::string& web_session_id,
- scoped_ptr<media::SimpleCdmPromise> promise);
-
- // Removes stored session data associated with the session specified by
- // |web_session_id|.
- void RemoveSession(const std::string& web_session_id,
- scoped_ptr<media::SimpleCdmPromise> promise);
-
- // Retrieves the key IDs for keys in the session that the CDM knows are
- // currently usable to decrypt media data.
- void GetUsableKeyIds(const std::string& web_session_id,
- scoped_ptr<media::KeyIdsPromise> promise);
-
- // Returns the Decryptor associated with this CDM. May be NULL if no
- // Decryptor is associated with the MediaKeys object.
- // TODO(jrummell): Figure out lifetimes, as WMPI may still use the decryptor
- // after WebContentDecryptionModule is freed. http://crbug.com/330324
- media::Decryptor* GetDecryptor();
-
- // Returns a prefix to use for UMAs.
- const std::string& GetKeySystemUMAPrefix() const;
-
-#if defined(ENABLE_BROWSER_CDMS)
- // Returns the CDM ID associated with the |media_keys_|. May be kInvalidCdmId
- // if no CDM ID is associated.
- int GetCdmId() const;
-#endif
-
- private:
- friend class base::RefCounted<CdmSessionAdapter>;
- typedef base::hash_map<std::string,
- base::WeakPtr<WebContentDecryptionModuleSessionImpl> >
- SessionMap;
-
- ~CdmSessionAdapter();
-
- // Callbacks for firing session events.
- void OnSessionMessage(const std::string& web_session_id,
- const std::vector<uint8>& message,
- const GURL& destination_url);
- void OnSessionKeysChange(const std::string& web_session_id,
- bool has_additional_usable_key);
- void OnSessionExpirationUpdate(const std::string& web_session_id,
- const base::Time& new_expiry_time);
- void OnSessionReady(const std::string& web_session_id);
- void OnSessionClosed(const std::string& web_session_id);
- void OnSessionError(const std::string& web_session_id,
- media::MediaKeys::Exception exception_code,
- uint32 system_code,
- const std::string& error_message);
-
- // Helper function of the callbacks.
- WebContentDecryptionModuleSessionImpl* GetSession(
- const std::string& web_session_id);
-
- scoped_ptr<media::MediaKeys> media_keys_;
-
- SessionMap sessions_;
-
- std::string key_system_uma_prefix_;
-
- // NOTE: Weak pointers must be invalidated before all other member variables.
- base::WeakPtrFactory<CdmSessionAdapter> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(CdmSessionAdapter);
-};
-
-} // namespace content
-
-#endif // CONTENT_RENDERER_MEDIA_CDM_SESSION_ADAPTER_H_
diff --git a/chromium/content/renderer/media/crypto/cdm_initialized_promise.cc b/chromium/content/renderer/media/crypto/cdm_initialized_promise.cc
new file mode 100644
index 00000000000..8d9b7afd631
--- /dev/null
+++ b/chromium/content/renderer/media/crypto/cdm_initialized_promise.cc
@@ -0,0 +1,30 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/media/crypto/cdm_initialized_promise.h"
+
+namespace content {
+
+CdmInitializedPromise::CdmInitializedPromise(
+ const media::CdmCreatedCB& cdm_created_cb,
+ scoped_ptr<media::MediaKeys> cdm)
+ : cdm_created_cb_(cdm_created_cb), cdm_(cdm.Pass()) {
+}
+
+CdmInitializedPromise::~CdmInitializedPromise() {
+}
+
+void CdmInitializedPromise::resolve() {
+ MarkPromiseSettled();
+ cdm_created_cb_.Run(cdm_.Pass(), "");
+}
+
+void CdmInitializedPromise::reject(media::MediaKeys::Exception exception_code,
+ uint32 system_code,
+ const std::string& error_message) {
+ MarkPromiseSettled();
+ cdm_created_cb_.Run(nullptr, error_message);
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/media/crypto/cdm_initialized_promise.h b/chromium/content/renderer/media/crypto/cdm_initialized_promise.h
new file mode 100644
index 00000000000..7c3d4c38116
--- /dev/null
+++ b/chromium/content/renderer/media/crypto/cdm_initialized_promise.h
@@ -0,0 +1,39 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_MEDIA_CRYPTO_CDM_INITIALIZED_PROMISE_H_
+#define CONTENT_RENDERER_MEDIA_CRYPTO_CDM_INITIALIZED_PROMISE_H_
+
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "media/base/cdm_factory.h"
+#include "media/base/cdm_promise.h"
+#include "media/base/media_keys.h"
+
+namespace content {
+
+// Promise to be resolved when the CDM is initialized. It owns the MediaKeys
+// object until the initialization completes, which it then passes to
+// |cdm_created_cb|.
+class CdmInitializedPromise : public media::SimpleCdmPromise {
+ public:
+ CdmInitializedPromise(const media::CdmCreatedCB& cdm_created_cb,
+ scoped_ptr<media::MediaKeys> cdm);
+ ~CdmInitializedPromise() override;
+
+ // SimpleCdmPromise implementation.
+ void resolve() override;
+ void reject(media::MediaKeys::Exception exception_code,
+ uint32 system_code,
+ const std::string& error_message) override;
+
+ private:
+ media::CdmCreatedCB cdm_created_cb_;
+ scoped_ptr<media::MediaKeys> cdm_;
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_MEDIA_CRYPTO_CDM_INITIALIZED_PROMISE_H_
diff --git a/chromium/content/renderer/media/crypto/encrypted_media_player_support_impl.cc b/chromium/content/renderer/media/crypto/encrypted_media_player_support_impl.cc
deleted file mode 100644
index cf24056f14f..00000000000
--- a/chromium/content/renderer/media/crypto/encrypted_media_player_support_impl.cc
+++ /dev/null
@@ -1,475 +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/renderer/media/crypto/encrypted_media_player_support_impl.h"
-
-#include <string>
-
-#include "base/bind.h"
-#include "base/callback_helpers.h"
-#include "base/metrics/histogram.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "content/renderer/media/crypto/key_systems.h"
-#include "content/renderer/media/crypto/render_cdm_factory.h"
-#include "content/renderer/media/webcontentdecryptionmodule_impl.h"
-#include "media/base/bind_to_current_loop.h"
-#include "media/blink/encrypted_media_player_support.h"
-#include "third_party/WebKit/public/platform/WebContentDecryptionModule.h"
-#include "third_party/WebKit/public/platform/WebContentDecryptionModuleResult.h"
-#include "third_party/WebKit/public/platform/WebMediaPlayerClient.h"
-#include "third_party/WebKit/public/web/WebDocument.h"
-#include "third_party/WebKit/public/web/WebLocalFrame.h"
-#include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
-
-#if defined(ENABLE_PEPPER_CDMS)
-#include "content/renderer/media/crypto/pepper_cdm_wrapper_impl.h"
-#elif defined(ENABLE_BROWSER_CDMS)
-#error Browser side CDM in WMPI for prefixed EME API not supported yet.
-#endif
-
-using blink::WebMediaPlayer;
-using blink::WebMediaPlayerClient;
-using blink::WebString;
-
-namespace content {
-
-#define BIND_TO_RENDER_LOOP(function) \
- (media::BindToCurrentLoop(base::Bind(function, AsWeakPtr())))
-
-#define BIND_TO_RENDER_LOOP1(function, arg1) \
- (media::BindToCurrentLoop(base::Bind(function, AsWeakPtr(), arg1)))
-
-// Prefix for histograms related to Encrypted Media Extensions.
-static const char* kMediaEme = "Media.EME.";
-
-// Used for calls to decryptor_ready_cb where the result can be ignored.
-static void DoNothing(bool success) {
-}
-
-// Convert a WebString to ASCII, falling back on an empty string in the case
-// of a non-ASCII string.
-static std::string ToASCIIOrEmpty(const WebString& string) {
- return base::IsStringASCII(string) ? base::UTF16ToASCII(string)
- : std::string();
-}
-
-// Helper functions to report media EME related stats to UMA. They follow the
-// convention of more commonly used macros UMA_HISTOGRAM_ENUMERATION and
-// UMA_HISTOGRAM_COUNTS. The reason that we cannot use those macros directly is
-// that UMA_* macros require the names to be constant throughout the process'
-// lifetime.
-static void EmeUMAHistogramEnumeration(const std::string& key_system,
- const std::string& method,
- int sample,
- int boundary_value) {
- base::LinearHistogram::FactoryGet(
- kMediaEme + KeySystemNameForUMA(key_system) + "." + method,
- 1, boundary_value, boundary_value + 1,
- base::Histogram::kUmaTargetedHistogramFlag)->Add(sample);
-}
-
-static void EmeUMAHistogramCounts(const std::string& key_system,
- const std::string& method,
- int sample) {
- // Use the same parameters as UMA_HISTOGRAM_COUNTS.
- base::Histogram::FactoryGet(
- kMediaEme + KeySystemNameForUMA(key_system) + "." + method,
- 1, 1000000, 50, base::Histogram::kUmaTargetedHistogramFlag)->Add(sample);
-}
-
-// Helper enum for reporting generateKeyRequest/addKey histograms.
-enum MediaKeyException {
- kUnknownResultId,
- kSuccess,
- kKeySystemNotSupported,
- kInvalidPlayerState,
- kMaxMediaKeyException
-};
-
-static MediaKeyException MediaKeyExceptionForUMA(
- WebMediaPlayer::MediaKeyException e) {
- switch (e) {
- case WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported:
- return kKeySystemNotSupported;
- case WebMediaPlayer::MediaKeyExceptionInvalidPlayerState:
- return kInvalidPlayerState;
- case WebMediaPlayer::MediaKeyExceptionNoError:
- return kSuccess;
- default:
- return kUnknownResultId;
- }
-}
-
-// Helper for converting |key_system| name and exception |e| to a pair of enum
-// values from above, for reporting to UMA.
-static void ReportMediaKeyExceptionToUMA(const std::string& method,
- const std::string& key_system,
- WebMediaPlayer::MediaKeyException e) {
- MediaKeyException result_id = MediaKeyExceptionForUMA(e);
- DCHECK_NE(result_id, kUnknownResultId) << e;
- EmeUMAHistogramEnumeration(
- key_system, method, result_id, kMaxMediaKeyException);
-}
-
-// Guess the type of |init_data|. This is only used to handle some corner cases
-// so we keep it as simple as possible without breaking major use cases.
-static std::string GuessInitDataType(const unsigned char* init_data,
- unsigned init_data_length) {
- // Most WebM files use KeyId of 16 bytes. CENC init data is always >16 bytes.
- if (init_data_length == 16)
- return "webm";
-
- return "cenc";
-}
-
-scoped_ptr<media::EncryptedMediaPlayerSupport>
-EncryptedMediaPlayerSupportImpl::Create(blink::WebMediaPlayerClient* client) {
- return scoped_ptr<EncryptedMediaPlayerSupport>(
- new EncryptedMediaPlayerSupportImpl(client));
-}
-
-EncryptedMediaPlayerSupportImpl::EncryptedMediaPlayerSupportImpl(
- blink::WebMediaPlayerClient* client)
- : client_(client),
- web_cdm_(NULL) {
-}
-
-EncryptedMediaPlayerSupportImpl::~EncryptedMediaPlayerSupportImpl() {
-}
-
-WebMediaPlayer::MediaKeyException
-EncryptedMediaPlayerSupportImpl::GenerateKeyRequest(
- blink::WebLocalFrame* frame,
- const WebString& key_system,
- const unsigned char* init_data,
- unsigned init_data_length) {
- DVLOG(1) << "generateKeyRequest: " << base::string16(key_system) << ": "
- << std::string(reinterpret_cast<const char*>(init_data),
- static_cast<size_t>(init_data_length));
-
- std::string ascii_key_system =
- GetUnprefixedKeySystemName(ToASCIIOrEmpty(key_system));
-
- WebMediaPlayer::MediaKeyException e =
- GenerateKeyRequestInternal(frame, ascii_key_system, init_data,
- init_data_length);
- ReportMediaKeyExceptionToUMA("generateKeyRequest", ascii_key_system, e);
- return e;
-}
-
-WebMediaPlayer::MediaKeyException
-EncryptedMediaPlayerSupportImpl::GenerateKeyRequestInternal(
- blink::WebLocalFrame* frame,
- const std::string& key_system,
- const unsigned char* init_data,
- unsigned init_data_length) {
- if (!IsConcreteSupportedKeySystem(key_system))
- return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
-
- // We do not support run-time switching between key systems for now.
- if (current_key_system_.empty()) {
- if (!proxy_decryptor_) {
- proxy_decryptor_.reset(new ProxyDecryptor(
- BIND_TO_RENDER_LOOP(&EncryptedMediaPlayerSupportImpl::OnKeyAdded),
- BIND_TO_RENDER_LOOP(&EncryptedMediaPlayerSupportImpl::OnKeyError),
- BIND_TO_RENDER_LOOP(&EncryptedMediaPlayerSupportImpl::OnKeyMessage)));
- }
-
- GURL security_origin(frame->document().securityOrigin().toString());
-
-#if defined(ENABLE_PEPPER_CDMS)
- RenderCdmFactory cdm_factory(
- base::Bind(&PepperCdmWrapperImpl::Create, frame));
-#else
- RenderCdmFactory cdm_factory;
-#endif
-
- if (!proxy_decryptor_->InitializeCDM(&cdm_factory, key_system,
- security_origin)) {
- return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
- }
-
- if (proxy_decryptor_ && !decryptor_ready_cb_.is_null()) {
- base::ResetAndReturn(&decryptor_ready_cb_)
- .Run(proxy_decryptor_->GetDecryptor(), base::Bind(DoNothing));
- }
-
- current_key_system_ = key_system;
- } else if (key_system != current_key_system_) {
- return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState;
- }
-
- std::string init_data_type = init_data_type_;
- if (init_data_type.empty())
- init_data_type = GuessInitDataType(init_data, init_data_length);
-
- // TODO(xhwang): We assume all streams are from the same container (thus have
- // the same "type") for now. In the future, the "type" should be passed down
- // from the application.
- if (!proxy_decryptor_->GenerateKeyRequest(
- init_data_type, init_data, init_data_length)) {
- current_key_system_.clear();
- return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
- }
-
- return WebMediaPlayer::MediaKeyExceptionNoError;
-}
-
-WebMediaPlayer::MediaKeyException EncryptedMediaPlayerSupportImpl::AddKey(
- const WebString& key_system,
- const unsigned char* key,
- unsigned key_length,
- const unsigned char* init_data,
- unsigned init_data_length,
- const WebString& session_id) {
- DVLOG(1) << "addKey: " << base::string16(key_system) << ": "
- << std::string(reinterpret_cast<const char*>(key),
- static_cast<size_t>(key_length)) << ", "
- << std::string(reinterpret_cast<const char*>(init_data),
- static_cast<size_t>(init_data_length)) << " ["
- << base::string16(session_id) << "]";
-
- std::string ascii_key_system =
- GetUnprefixedKeySystemName(ToASCIIOrEmpty(key_system));
- std::string ascii_session_id = ToASCIIOrEmpty(session_id);
-
- WebMediaPlayer::MediaKeyException e = AddKeyInternal(ascii_key_system,
- key,
- key_length,
- init_data,
- init_data_length,
- ascii_session_id);
- ReportMediaKeyExceptionToUMA("addKey", ascii_key_system, e);
- return e;
-}
-
-WebMediaPlayer::MediaKeyException
-EncryptedMediaPlayerSupportImpl::AddKeyInternal(
- const std::string& key_system,
- const unsigned char* key,
- unsigned key_length,
- const unsigned char* init_data,
- unsigned init_data_length,
- const std::string& session_id) {
- DCHECK(key);
- DCHECK_GT(key_length, 0u);
-
- if (!IsConcreteSupportedKeySystem(key_system))
- return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
-
- if (current_key_system_.empty() || key_system != current_key_system_)
- return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState;
-
- proxy_decryptor_->AddKey(
- key, key_length, init_data, init_data_length, session_id);
- return WebMediaPlayer::MediaKeyExceptionNoError;
-}
-
-WebMediaPlayer::MediaKeyException
-EncryptedMediaPlayerSupportImpl::CancelKeyRequest(
- const WebString& key_system,
- const WebString& session_id) {
- DVLOG(1) << "cancelKeyRequest: " << base::string16(key_system) << ": "
- << " [" << base::string16(session_id) << "]";
-
- std::string ascii_key_system =
- GetUnprefixedKeySystemName(ToASCIIOrEmpty(key_system));
- std::string ascii_session_id = ToASCIIOrEmpty(session_id);
-
- WebMediaPlayer::MediaKeyException e =
- CancelKeyRequestInternal(ascii_key_system, ascii_session_id);
- ReportMediaKeyExceptionToUMA("cancelKeyRequest", ascii_key_system, e);
- return e;
-}
-
-WebMediaPlayer::MediaKeyException
-EncryptedMediaPlayerSupportImpl::CancelKeyRequestInternal(
- const std::string& key_system,
- const std::string& session_id) {
- if (!IsConcreteSupportedKeySystem(key_system))
- return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
-
- if (current_key_system_.empty() || key_system != current_key_system_)
- return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState;
-
- proxy_decryptor_->CancelKeyRequest(session_id);
- return WebMediaPlayer::MediaKeyExceptionNoError;
-}
-
-void EncryptedMediaPlayerSupportImpl::SetInitialContentDecryptionModule(
- blink::WebContentDecryptionModule* initial_cdm) {
- // Used when loading media and no pipeline/decoder attached yet.
- DCHECK(decryptor_ready_cb_.is_null());
-
- web_cdm_ = ToWebContentDecryptionModuleImpl(initial_cdm);
-}
-
-void EncryptedMediaPlayerSupportImpl::SetContentDecryptionModule(
- blink::WebContentDecryptionModule* cdm) {
- // TODO(xhwang): Support setMediaKeys(0) if necessary: http://crbug.com/330324
- if (!cdm)
- return;
-
- web_cdm_ = ToWebContentDecryptionModuleImpl(cdm);
-
- if (web_cdm_ && !decryptor_ready_cb_.is_null())
- base::ResetAndReturn(&decryptor_ready_cb_)
- .Run(web_cdm_->GetDecryptor(), base::Bind(DoNothing));
-}
-
-void EncryptedMediaPlayerSupportImpl::SetContentDecryptionModule(
- blink::WebContentDecryptionModule* cdm,
- blink::WebContentDecryptionModuleResult result) {
- // TODO(xhwang): Support setMediaKeys(0) if necessary: http://crbug.com/330324
- if (!cdm) {
- result.completeWithError(
- blink::WebContentDecryptionModuleExceptionNotSupportedError,
- 0,
- "Null MediaKeys object is not supported.");
- return;
- }
-
- web_cdm_ = ToWebContentDecryptionModuleImpl(cdm);
-
- if (web_cdm_ && !decryptor_ready_cb_.is_null()) {
- base::ResetAndReturn(&decryptor_ready_cb_)
- .Run(web_cdm_->GetDecryptor(), BIND_TO_RENDER_LOOP1(
- &EncryptedMediaPlayerSupportImpl::ContentDecryptionModuleAttached,
- result));
- } else {
- // No pipeline/decoder connected, so resolve the promise. When something
- // is connected, setting the CDM will happen in SetDecryptorReadyCB().
- ContentDecryptionModuleAttached(result, true);
- }
-}
-
-void EncryptedMediaPlayerSupportImpl::ContentDecryptionModuleAttached(
- blink::WebContentDecryptionModuleResult result,
- bool success) {
- if (success) {
- result.complete();
- return;
- }
-
- result.completeWithError(
- blink::WebContentDecryptionModuleExceptionNotSupportedError,
- 0,
- "Unable to set MediaKeys object");
-}
-
-media::SetDecryptorReadyCB
-EncryptedMediaPlayerSupportImpl::CreateSetDecryptorReadyCB() {
- return BIND_TO_RENDER_LOOP(
- &EncryptedMediaPlayerSupportImpl::SetDecryptorReadyCB);
-}
-
-media::Demuxer::NeedKeyCB
-EncryptedMediaPlayerSupportImpl::CreateNeedKeyCB() {
- return BIND_TO_RENDER_LOOP(&EncryptedMediaPlayerSupportImpl::OnNeedKey);
-}
-
-void EncryptedMediaPlayerSupportImpl::OnPipelineDecryptError() {
- EmeUMAHistogramCounts(current_key_system_, "DecryptError", 1);
-}
-
-void EncryptedMediaPlayerSupportImpl::OnNeedKey(const std::string& type,
- const std::vector<uint8>& init_data) {
- // Do not fire NeedKey event if encrypted media is not enabled.
- if (!blink::WebRuntimeFeatures::isPrefixedEncryptedMediaEnabled() &&
- !blink::WebRuntimeFeatures::isEncryptedMediaEnabled()) {
- return;
- }
-
- UMA_HISTOGRAM_COUNTS(kMediaEme + std::string("NeedKey"), 1);
-
- DCHECK(init_data_type_.empty() || type.empty() || type == init_data_type_);
- if (init_data_type_.empty())
- init_data_type_ = type;
-
- const uint8* init_data_ptr = init_data.empty() ? NULL : &init_data[0];
- client_->encrypted(
- WebString::fromUTF8(type), init_data_ptr, init_data.size());
-}
-
-void EncryptedMediaPlayerSupportImpl::OnKeyAdded(
- const std::string& session_id) {
- EmeUMAHistogramCounts(current_key_system_, "KeyAdded", 1);
- client_->keyAdded(
- WebString::fromUTF8(GetPrefixedKeySystemName(current_key_system_)),
- WebString::fromUTF8(session_id));
-}
-
-void EncryptedMediaPlayerSupportImpl::OnKeyError(const std::string& session_id,
- media::MediaKeys::KeyError error_code,
- uint32 system_code) {
- EmeUMAHistogramEnumeration(current_key_system_, "KeyError",
- error_code, media::MediaKeys::kMaxKeyError);
-
- uint16 short_system_code = 0;
- if (system_code > std::numeric_limits<uint16>::max()) {
- LOG(WARNING) << "system_code exceeds unsigned short limit.";
- short_system_code = std::numeric_limits<uint16>::max();
- } else {
- short_system_code = static_cast<uint16>(system_code);
- }
-
- client_->keyError(
- WebString::fromUTF8(GetPrefixedKeySystemName(current_key_system_)),
- WebString::fromUTF8(session_id),
- static_cast<WebMediaPlayerClient::MediaKeyErrorCode>(error_code),
- short_system_code);
-}
-
-void EncryptedMediaPlayerSupportImpl::OnKeyMessage(
- const std::string& session_id,
- const std::vector<uint8>& message,
- const GURL& destination_url) {
- DCHECK(destination_url.is_empty() || destination_url.is_valid());
-
- client_->keyMessage(
- WebString::fromUTF8(GetPrefixedKeySystemName(current_key_system_)),
- WebString::fromUTF8(session_id),
- message.empty() ? NULL : &message[0],
- message.size(),
- destination_url);
-}
-
-void EncryptedMediaPlayerSupportImpl::SetDecryptorReadyCB(
- const media::DecryptorReadyCB& decryptor_ready_cb) {
- // Cancels the previous decryptor request.
- if (decryptor_ready_cb.is_null()) {
- if (!decryptor_ready_cb_.is_null()) {
- base::ResetAndReturn(&decryptor_ready_cb_)
- .Run(NULL, base::Bind(DoNothing));
- }
- return;
- }
-
- // TODO(xhwang): Support multiple decryptor notification request (e.g. from
- // video and audio). The current implementation is okay for the current
- // media pipeline since we initialize audio and video decoders in sequence.
- // But WebMediaPlayerImpl should not depend on media pipeline's implementation
- // detail.
- DCHECK(decryptor_ready_cb_.is_null());
-
- // Mixed use of prefixed and unprefixed EME APIs is disallowed by Blink.
- DCHECK(!proxy_decryptor_ || !web_cdm_);
-
- if (proxy_decryptor_) {
- decryptor_ready_cb.Run(proxy_decryptor_->GetDecryptor(),
- base::Bind(DoNothing));
- return;
- }
-
- if (web_cdm_) {
- decryptor_ready_cb.Run(web_cdm_->GetDecryptor(), base::Bind(DoNothing));
- return;
- }
-
- decryptor_ready_cb_ = decryptor_ready_cb;
-}
-
-} // namespace content
diff --git a/chromium/content/renderer/media/crypto/encrypted_media_player_support_impl.h b/chromium/content/renderer/media/crypto/encrypted_media_player_support_impl.h
deleted file mode 100644
index d68d40b7d5a..00000000000
--- a/chromium/content/renderer/media/crypto/encrypted_media_player_support_impl.h
+++ /dev/null
@@ -1,130 +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_RENDERER_MEDIA_CRYPTO_ENCRYPTED_MEDIA_PLAYER_SUPPORT_IMPL_H_
-#define CONTENT_RENDERER_MEDIA_CRYPTO_ENCRYPTED_MEDIA_PLAYER_SUPPORT_IMPL_H_
-
-#include <string>
-#include <vector>
-
-#include "base/memory/weak_ptr.h"
-#include "content/renderer/media/crypto/proxy_decryptor.h"
-#include "media/blink/encrypted_media_player_support.h"
-
-namespace blink {
-class WebMediaPlayerClient;
-}
-
-namespace content {
-
-class WebContentDecryptionModuleImpl;
-
-class EncryptedMediaPlayerSupportImpl
- : public media::EncryptedMediaPlayerSupport,
- public base::SupportsWeakPtr<EncryptedMediaPlayerSupportImpl> {
- public:
- static scoped_ptr<EncryptedMediaPlayerSupport> Create(
- blink::WebMediaPlayerClient* client);
-
- ~EncryptedMediaPlayerSupportImpl() override;
-
- // EncryptedMediaPlayerSupport implementation.
- blink::WebMediaPlayer::MediaKeyException GenerateKeyRequest(
- blink::WebLocalFrame* frame,
- const blink::WebString& key_system,
- const unsigned char* init_data,
- unsigned init_data_length) override;
-
- blink::WebMediaPlayer::MediaKeyException AddKey(
- const blink::WebString& key_system,
- const unsigned char* key,
- unsigned key_length,
- const unsigned char* init_data,
- unsigned init_data_length,
- const blink::WebString& session_id) override;
-
- blink::WebMediaPlayer::MediaKeyException CancelKeyRequest(
- const blink::WebString& key_system,
- const blink::WebString& session_id) override;
-
- void SetInitialContentDecryptionModule(
- blink::WebContentDecryptionModule* initial_cdm) override;
-
- void SetContentDecryptionModule(
- blink::WebContentDecryptionModule* cdm) override;
- void SetContentDecryptionModule(
- blink::WebContentDecryptionModule* cdm,
- blink::WebContentDecryptionModuleResult result) override;
-
- media::SetDecryptorReadyCB CreateSetDecryptorReadyCB() override;
- media::Demuxer::NeedKeyCB CreateNeedKeyCB() override;
-
- void OnPipelineDecryptError() override;
-
- private:
- explicit EncryptedMediaPlayerSupportImpl(blink::WebMediaPlayerClient* client);
-
- // Requests that this object notifies when a decryptor is ready through the
- // |decryptor_ready_cb| provided.
- // If |decryptor_ready_cb| is null, the existing callback will be fired with
- // NULL immediately and reset.
- void SetDecryptorReadyCB(const media::DecryptorReadyCB& decryptor_ready_cb);
-
- blink::WebMediaPlayer::MediaKeyException GenerateKeyRequestInternal(
- blink::WebLocalFrame* frame,
- const std::string& key_system,
- const unsigned char* init_data,
- unsigned init_data_length);
-
- blink::WebMediaPlayer::MediaKeyException AddKeyInternal(
- const std::string& key_system,
- const unsigned char* key,
- unsigned key_length,
- const unsigned char* init_data,
- unsigned init_data_length,
- const std::string& session_id);
-
- blink::WebMediaPlayer::MediaKeyException CancelKeyRequestInternal(
- const std::string& key_system,
- const std::string& session_id);
-
- void OnNeedKey(const std::string& type,
- const std::vector<uint8>& init_data);
-
- void OnKeyAdded(const std::string& session_id);
- void OnKeyError(const std::string& session_id,
- media::MediaKeys::KeyError error_code,
- uint32 system_code);
- void OnKeyMessage(const std::string& session_id,
- const std::vector<uint8>& message,
- const GURL& destination_url);
-
- void ContentDecryptionModuleAttached(
- blink::WebContentDecryptionModuleResult result,
- bool success);
-
- blink::WebMediaPlayerClient* client_;
-
- // The currently selected key system. Empty string means that no key system
- // has been selected.
- std::string current_key_system_;
-
- // Temporary for EME v0.1. In the future the init data type should be passed
- // through GenerateKeyRequest() directly from WebKit.
- std::string init_data_type_;
-
- // Manages decryption keys and decrypts encrypted frames.
- scoped_ptr<ProxyDecryptor> proxy_decryptor_;
-
- // Non-owned pointer to the CDM. Updated via calls to
- // setContentDecryptionModule().
- WebContentDecryptionModuleImpl* web_cdm_;
-
- media::DecryptorReadyCB decryptor_ready_cb_;
-
- DISALLOW_COPY_AND_ASSIGN(EncryptedMediaPlayerSupportImpl);
-};
-}
-
-#endif // CONTENT_RENDERER_MEDIA_CRYPTO_ENCRYPTED_MEDIA_PLAYER_SUPPORT_IMPL_H_
diff --git a/chromium/content/renderer/media/crypto/key_systems.cc b/chromium/content/renderer/media/crypto/key_systems.cc
deleted file mode 100644
index 9c3ce046ab6..00000000000
--- a/chromium/content/renderer/media/crypto/key_systems.cc
+++ /dev/null
@@ -1,650 +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/renderer/media/crypto/key_systems.h"
-
-#include <string>
-
-#include "base/containers/hash_tables.h"
-#include "base/lazy_instance.h"
-#include "base/logging.h"
-#include "base/strings/string_util.h"
-#include "base/threading/thread_checker.h"
-#include "base/time/time.h"
-#include "content/public/common/content_client.h"
-#include "content/public/renderer/content_renderer_client.h"
-#include "content/renderer/media/crypto/key_systems_support_uma.h"
-#include "media/base/eme_constants.h"
-#include "media/base/key_system_info.h"
-
-#if defined(OS_ANDROID)
-#include "media/base/android/media_codec_bridge.h"
-#endif
-
-#include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR.
-
-namespace content {
-
-using media::EmeCodec;
-using media::EmeInitDataType;
-using media::KeySystemInfo;
-using media::SupportedInitDataTypes;
-using media::SupportedCodecs;
-
-const char kClearKeyKeySystem[] = "org.w3.clearkey";
-const char kPrefixedClearKeyKeySystem[] = "webkit-org.w3.clearkey";
-const char kUnsupportedClearKeyKeySystem[] = "unsupported-org.w3.clearkey";
-
-struct NamedInitDataType {
- const char* name;
- EmeInitDataType type;
-};
-
-// Mapping between initialization data types names and enum values. When adding
-// entries, make sure to update IsSaneInitDataTypeWithContainer().
-static NamedInitDataType kInitDataTypeNames[] = {
- {"webm", media::EME_INIT_DATA_TYPE_WEBM},
-#if defined(USE_PROPRIETARY_CODECS)
- {"cenc", media::EME_INIT_DATA_TYPE_CENC}
-#endif // defined(USE_PROPRIETARY_CODECS)
-};
-
-struct NamedCodec {
- const char* name;
- EmeCodec type;
-};
-
-// Mapping between containers and their codecs.
-// Only audio codec can belong to a "audio/*" container. Both audio and video
-// codecs can belong to a "video/*" container.
-static NamedCodec kContainerToCodecMasks[] = {
- {"audio/webm", media::EME_CODEC_WEBM_AUDIO_ALL},
- {"video/webm", media::EME_CODEC_WEBM_ALL},
-#if defined(USE_PROPRIETARY_CODECS)
- {"audio/mp4", media::EME_CODEC_MP4_AUDIO_ALL},
- {"video/mp4", media::EME_CODEC_MP4_ALL}
-#endif // defined(USE_PROPRIETARY_CODECS)
-};
-
-// Mapping between codec names and enum values.
-static NamedCodec kCodecStrings[] = {
- {"vorbis", media::EME_CODEC_WEBM_VORBIS},
- {"vp8", media::EME_CODEC_WEBM_VP8},
- {"vp8.0", media::EME_CODEC_WEBM_VP8},
- {"vp9", media::EME_CODEC_WEBM_VP9},
- {"vp9.0", media::EME_CODEC_WEBM_VP9},
-#if defined(USE_PROPRIETARY_CODECS)
- {"mp4a", media::EME_CODEC_MP4_AAC},
- {"avc1", media::EME_CODEC_MP4_AVC1},
- {"avc3", media::EME_CODEC_MP4_AVC1}
-#endif // defined(USE_PROPRIETARY_CODECS)
-};
-
-static void AddClearKey(std::vector<KeySystemInfo>* concrete_key_systems) {
- KeySystemInfo info(kClearKeyKeySystem);
-
- // On Android, Vorbis, VP8, AAC and AVC1 are supported in MediaCodec:
- // http://developer.android.com/guide/appendix/media-formats.html
- // VP9 support is device dependent.
-
- info.supported_init_data_types = media::EME_INIT_DATA_TYPE_WEBM;
- info.supported_codecs = media::EME_CODEC_WEBM_ALL;
-
-#if defined(OS_ANDROID)
- // Temporarily disable VP9 support for Android.
- // TODO(xhwang): Use mime_util.h to query VP9 support on Android.
- info.supported_codecs &= ~media::EME_CODEC_WEBM_VP9;
-#endif // defined(OS_ANDROID)
-
-#if defined(USE_PROPRIETARY_CODECS)
- info.supported_init_data_types |= media::EME_INIT_DATA_TYPE_CENC;
- info.supported_codecs |= media::EME_CODEC_MP4_ALL;
-#endif // defined(USE_PROPRIETARY_CODECS)
-
- info.use_aes_decryptor = true;
-
- concrete_key_systems->push_back(info);
-}
-
-class KeySystems {
- public:
- static KeySystems& GetInstance();
-
- void UpdateIfNeeded();
-
- bool IsConcreteSupportedKeySystem(const std::string& key_system);
-
- bool IsSupportedKeySystem(const std::string& key_system);
-
- bool IsSupportedKeySystemWithInitDataType(
- const std::string& key_system,
- const std::string& init_data_type);
-
- bool IsSupportedKeySystemWithMediaMimeType(
- const std::string& mime_type,
- const std::vector<std::string>& codecs,
- const std::string& key_system);
-
- bool UseAesDecryptor(const std::string& concrete_key_system);
-
-#if defined(ENABLE_PEPPER_CDMS)
- std::string GetPepperType(const std::string& concrete_key_system);
-#endif
-
- void AddContainerMask(const std::string& container, uint32 mask);
- void AddCodecMask(const std::string& codec, uint32 mask);
-
- private:
- void UpdateSupportedKeySystems();
-
- void AddConcreteSupportedKeySystems(
- const std::vector<KeySystemInfo>& concrete_key_systems);
-
- void AddConcreteSupportedKeySystem(
- const std::string& key_system,
- bool use_aes_decryptor,
-#if defined(ENABLE_PEPPER_CDMS)
- const std::string& pepper_type,
-#endif
- SupportedInitDataTypes supported_init_data_types,
- SupportedCodecs supported_codecs,
- const std::string& parent_key_system);
-
- friend struct base::DefaultLazyInstanceTraits<KeySystems>;
-
- struct KeySystemProperties {
- KeySystemProperties()
- : use_aes_decryptor(false), supported_codecs(media::EME_CODEC_NONE) {}
-
- bool use_aes_decryptor;
-#if defined(ENABLE_PEPPER_CDMS)
- std::string pepper_type;
-#endif
- SupportedInitDataTypes supported_init_data_types;
- SupportedCodecs supported_codecs;
- };
-
- typedef base::hash_map<std::string, KeySystemProperties>
- KeySystemPropertiesMap;
- typedef base::hash_map<std::string, std::string> ParentKeySystemMap;
- typedef base::hash_map<std::string, SupportedCodecs> ContainerCodecsMap;
- typedef base::hash_map<std::string, EmeCodec> CodecsMap;
- typedef base::hash_map<std::string, media::EmeInitDataType> InitDataTypesMap;
-
- KeySystems();
- ~KeySystems() {}
-
- EmeInitDataType GetInitDataTypeForName(
- const std::string& init_data_type) const;
- // TODO(sandersd): Separate container enum from codec mask value.
- // http://crbug.com/417440
- SupportedCodecs GetCodecMaskForContainer(
- const std::string& container) const;
- EmeCodec GetCodecForString(const std::string& codec) const;
-
- const std::string& GetConcreteKeySystemName(
- const std::string& key_system) const;
-
- // Returns whether a |container| type is supported by checking
- // |key_system_supported_codecs|.
- // TODO(xhwang): Update this to actually check initDataType support.
- bool IsSupportedContainer(const std::string& container,
- SupportedCodecs key_system_supported_codecs) const;
-
- // Returns true if all |codecs| are supported in |container| by checking
- // |key_system_supported_codecs|.
- bool IsSupportedContainerAndCodecs(
- const std::string& container,
- const std::vector<std::string>& codecs,
- SupportedCodecs key_system_supported_codecs) const;
-
- // Map from key system string to capabilities.
- KeySystemPropertiesMap concrete_key_system_map_;
-
- // Map from parent key system to the concrete key system that should be used
- // to represent its capabilities.
- ParentKeySystemMap parent_key_system_map_;
-
- KeySystemsSupportUMA key_systems_support_uma_;
-
- InitDataTypesMap init_data_type_name_map_;
- ContainerCodecsMap container_to_codec_mask_map_;
- CodecsMap codec_string_map_;
-
- bool needs_update_;
- base::Time last_update_time_;
-
- // Makes sure all methods are called from the same thread.
- base::ThreadChecker thread_checker_;
-
- DISALLOW_COPY_AND_ASSIGN(KeySystems);
-};
-
-static base::LazyInstance<KeySystems> g_key_systems = LAZY_INSTANCE_INITIALIZER;
-
-KeySystems& KeySystems::GetInstance() {
- KeySystems& key_systems = g_key_systems.Get();
- key_systems.UpdateIfNeeded();
- return key_systems;
-}
-
-// Because we use a LazyInstance, the key systems info must be populated when
-// the instance is lazily initiated.
-KeySystems::KeySystems() : needs_update_(true) {
- for (size_t i = 0; i < arraysize(kInitDataTypeNames); ++i) {
- const std::string& name = kInitDataTypeNames[i].name;
- DCHECK(!init_data_type_name_map_.count(name));
- init_data_type_name_map_[name] = kInitDataTypeNames[i].type;
- }
- for (size_t i = 0; i < arraysize(kContainerToCodecMasks); ++i) {
- const std::string& name = kContainerToCodecMasks[i].name;
- DCHECK(!container_to_codec_mask_map_.count(name));
- container_to_codec_mask_map_[name] = kContainerToCodecMasks[i].type;
- }
- for (size_t i = 0; i < arraysize(kCodecStrings); ++i) {
- const std::string& name = kCodecStrings[i].name;
- DCHECK(!codec_string_map_.count(name));
- codec_string_map_[name] = kCodecStrings[i].type;
- }
-
- UpdateSupportedKeySystems();
-
-#if defined(WIDEVINE_CDM_AVAILABLE)
- key_systems_support_uma_.AddKeySystemToReport(kWidevineKeySystem);
-#endif // defined(WIDEVINE_CDM_AVAILABLE)
-}
-
-EmeInitDataType KeySystems::GetInitDataTypeForName(
- const std::string& init_data_type) const {
- InitDataTypesMap::const_iterator iter =
- init_data_type_name_map_.find(init_data_type);
- if (iter != init_data_type_name_map_.end())
- return iter->second;
- return media::EME_INIT_DATA_TYPE_NONE;
-}
-
-SupportedCodecs KeySystems::GetCodecMaskForContainer(
- const std::string& container) const {
- ContainerCodecsMap::const_iterator iter =
- container_to_codec_mask_map_.find(container);
- if (iter != container_to_codec_mask_map_.end())
- return iter->second;
- return media::EME_CODEC_NONE;
-}
-
-EmeCodec KeySystems::GetCodecForString(const std::string& codec) const {
- CodecsMap::const_iterator iter = codec_string_map_.find(codec);
- if (iter != codec_string_map_.end())
- return iter->second;
- return media::EME_CODEC_NONE;
-}
-
-const std::string& KeySystems::GetConcreteKeySystemName(
- const std::string& key_system) const {
- ParentKeySystemMap::const_iterator iter =
- parent_key_system_map_.find(key_system);
- if (iter != parent_key_system_map_.end())
- return iter->second;
- return key_system;
-}
-
-void KeySystems::UpdateIfNeeded() {
-#if defined(WIDEVINE_CDM_AVAILABLE)
- DCHECK(thread_checker_.CalledOnValidThread());
- if (!needs_update_)
- return;
-
- // The update could involve a sync IPC to the browser process. Use a minimum
- // update interval to avoid unnecessary frequent IPC to the browser.
- static const int kMinUpdateIntervalInSeconds = 1;
- base::Time now = base::Time::Now();
- if (now - last_update_time_ <
- base::TimeDelta::FromSeconds(kMinUpdateIntervalInSeconds)) {
- return;
- }
-
- UpdateSupportedKeySystems();
-#endif
-}
-
-void KeySystems::UpdateSupportedKeySystems() {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(needs_update_);
- concrete_key_system_map_.clear();
- parent_key_system_map_.clear();
-
- // Build KeySystemInfo.
- std::vector<KeySystemInfo> key_systems_info;
- GetContentClient()->renderer()->AddKeySystems(&key_systems_info);
- // Clear Key is always supported.
- AddClearKey(&key_systems_info);
-
- AddConcreteSupportedKeySystems(key_systems_info);
-
-#if defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT)
- if (IsConcreteSupportedKeySystem(kWidevineKeySystem))
- needs_update_ = false;
-#endif
-
- last_update_time_ = base::Time::Now();
-}
-
-void KeySystems::AddConcreteSupportedKeySystems(
- const std::vector<KeySystemInfo>& concrete_key_systems) {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(concrete_key_system_map_.empty());
- DCHECK(parent_key_system_map_.empty());
-
- for (size_t i = 0; i < concrete_key_systems.size(); ++i) {
- const KeySystemInfo& key_system_info = concrete_key_systems[i];
- AddConcreteSupportedKeySystem(key_system_info.key_system,
- key_system_info.use_aes_decryptor,
-#if defined(ENABLE_PEPPER_CDMS)
- key_system_info.pepper_type,
-#endif
- key_system_info.supported_init_data_types,
- key_system_info.supported_codecs,
- key_system_info.parent_key_system);
- }
-}
-
-void KeySystems::AddConcreteSupportedKeySystem(
- const std::string& concrete_key_system,
- bool use_aes_decryptor,
-#if defined(ENABLE_PEPPER_CDMS)
- const std::string& pepper_type,
-#endif
- SupportedInitDataTypes supported_init_data_types,
- SupportedCodecs supported_codecs,
- const std::string& parent_key_system) {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(!IsConcreteSupportedKeySystem(concrete_key_system))
- << "Key system '" << concrete_key_system << "' already registered";
- DCHECK(!parent_key_system_map_.count(concrete_key_system))
- << "'" << concrete_key_system << " is already registered as a parent";
-
- KeySystemProperties properties;
- properties.use_aes_decryptor = use_aes_decryptor;
-#if defined(ENABLE_PEPPER_CDMS)
- DCHECK_EQ(use_aes_decryptor, pepper_type.empty());
- properties.pepper_type = pepper_type;
-#endif
-
- properties.supported_init_data_types = supported_init_data_types;
- properties.supported_codecs = supported_codecs;
-
- concrete_key_system_map_[concrete_key_system] = properties;
-
- if (!parent_key_system.empty()) {
- DCHECK(!IsConcreteSupportedKeySystem(parent_key_system))
- << "Parent '" << parent_key_system << "' already registered concrete";
- DCHECK(!parent_key_system_map_.count(parent_key_system))
- << "Parent '" << parent_key_system << "' already registered";
- parent_key_system_map_[parent_key_system] = concrete_key_system;
- }
-}
-
-bool KeySystems::IsConcreteSupportedKeySystem(const std::string& key_system) {
- DCHECK(thread_checker_.CalledOnValidThread());
- return concrete_key_system_map_.count(key_system) != 0;
-}
-
-bool KeySystems::IsSupportedContainer(
- const std::string& container,
- SupportedCodecs key_system_supported_codecs) const {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(!container.empty());
-
- // When checking container support for EME, "audio/foo" should be treated the
- // same as "video/foo". Convert the |container| to achieve this.
- // TODO(xhwang): Replace this with real checks against supported initDataTypes
- // combined with supported demuxers.
- std::string canonical_container = container;
- if (container.find("audio/") == 0)
- canonical_container.replace(0, 6, "video/");
-
- // A container is supported iif at least one codec in that container is
- // supported.
- SupportedCodecs supported_codecs =
- GetCodecMaskForContainer(canonical_container);
- return (supported_codecs & key_system_supported_codecs) != 0;
-}
-
-bool KeySystems::IsSupportedContainerAndCodecs(
- const std::string& container,
- const std::vector<std::string>& codecs,
- SupportedCodecs key_system_supported_codecs) const {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(!container.empty());
- DCHECK(!codecs.empty());
- DCHECK(IsSupportedContainer(container, key_system_supported_codecs));
-
- SupportedCodecs container_supported_codecs =
- GetCodecMaskForContainer(container);
-
- for (size_t i = 0; i < codecs.size(); ++i) {
- // TODO(sandersd): This should fail for isTypeSupported().
- // http://crbug.com/417461
- if (codecs[i].empty())
- continue;
-
- EmeCodec codec = GetCodecForString(codecs[i]);
-
- // Unsupported codec.
- if (!(codec & key_system_supported_codecs))
- return false;
-
- // Unsupported codec/container combination, e.g. "video/webm" and "avc1".
- if (!(codec & container_supported_codecs))
- return false;
- }
-
- return true;
-}
-
-bool KeySystems::IsSupportedKeySystem(const std::string& key_system) {
- DCHECK(thread_checker_.CalledOnValidThread());
- return (concrete_key_system_map_.count(key_system) ||
- parent_key_system_map_.count(key_system));
-}
-
-bool KeySystems::IsSupportedKeySystemWithInitDataType(
- const std::string& key_system,
- const std::string& init_data_type) {
- DCHECK(thread_checker_.CalledOnValidThread());
-
- // If |key_system| is a parent key system, use its concrete child.
- const std::string& concrete_key_system = GetConcreteKeySystemName(key_system);
-
- // Locate |concrete_key_system|.
- KeySystemPropertiesMap::const_iterator key_system_iter =
- concrete_key_system_map_.find(concrete_key_system);
- if (key_system_iter == concrete_key_system_map_.end())
- return false;
-
- // Check |init_data_type| and |key_system| x |init_data_type|.
- const KeySystemProperties& properties = key_system_iter->second;
- EmeInitDataType eme_init_data_type = GetInitDataTypeForName(init_data_type);
- return (properties.supported_init_data_types & eme_init_data_type) != 0;
-}
-
-// TODO(sandersd): Reorganize to be more similar to
-// IsKeySystemSupportedWithInitDataType(). Note that a fork may still be
-// required; http://crbug.com/417461.
-bool KeySystems::IsSupportedKeySystemWithMediaMimeType(
- const std::string& mime_type,
- const std::vector<std::string>& codecs,
- const std::string& key_system) {
- DCHECK(thread_checker_.CalledOnValidThread());
-
- // If |key_system| is a parent key system, use its concrete child.
- const std::string& concrete_key_system = GetConcreteKeySystemName(key_system);
-
- bool has_type = !mime_type.empty();
-
- key_systems_support_uma_.ReportKeySystemQuery(key_system, has_type);
-
- // Check key system support.
- KeySystemPropertiesMap::const_iterator key_system_iter =
- concrete_key_system_map_.find(concrete_key_system);
- if (key_system_iter == concrete_key_system_map_.end())
- return false;
-
- key_systems_support_uma_.ReportKeySystemSupport(key_system, false);
-
- if (!has_type) {
- DCHECK(codecs.empty());
- return true;
- }
-
- SupportedCodecs key_system_supported_codecs =
- key_system_iter->second.supported_codecs;
-
- if (!IsSupportedContainer(mime_type, key_system_supported_codecs))
- return false;
-
- if (!codecs.empty() &&
- !IsSupportedContainerAndCodecs(
- mime_type, codecs, key_system_supported_codecs)) {
- return false;
- }
-
- key_systems_support_uma_.ReportKeySystemSupport(key_system, true);
- return true;
-}
-
-bool KeySystems::UseAesDecryptor(const std::string& concrete_key_system) {
- DCHECK(thread_checker_.CalledOnValidThread());
-
- KeySystemPropertiesMap::const_iterator key_system_iter =
- concrete_key_system_map_.find(concrete_key_system);
- if (key_system_iter == concrete_key_system_map_.end()) {
- DLOG(FATAL) << concrete_key_system << " is not a known concrete system";
- return false;
- }
-
- return key_system_iter->second.use_aes_decryptor;
-}
-
-#if defined(ENABLE_PEPPER_CDMS)
-std::string KeySystems::GetPepperType(const std::string& concrete_key_system) {
- DCHECK(thread_checker_.CalledOnValidThread());
-
- KeySystemPropertiesMap::const_iterator key_system_iter =
- concrete_key_system_map_.find(concrete_key_system);
- if (key_system_iter == concrete_key_system_map_.end()) {
- DLOG(FATAL) << concrete_key_system << " is not a known concrete system";
- return std::string();
- }
-
- const std::string& type = key_system_iter->second.pepper_type;
- DLOG_IF(FATAL, type.empty()) << concrete_key_system << " is not Pepper-based";
- return type;
-}
-#endif
-
-void KeySystems::AddContainerMask(const std::string& container, uint32 mask) {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(!container_to_codec_mask_map_.count(container));
- container_to_codec_mask_map_[container] = static_cast<EmeCodec>(mask);
-}
-
-void KeySystems::AddCodecMask(const std::string& codec, uint32 mask) {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(!codec_string_map_.count(codec));
- codec_string_map_[codec] = static_cast<EmeCodec>(mask);
-}
-
-//------------------------------------------------------------------------------
-
-std::string GetUnprefixedKeySystemName(const std::string& key_system) {
- if (key_system == kClearKeyKeySystem)
- return kUnsupportedClearKeyKeySystem;
-
- if (key_system == kPrefixedClearKeyKeySystem)
- return kClearKeyKeySystem;
-
- return key_system;
-}
-
-std::string GetPrefixedKeySystemName(const std::string& key_system) {
- DCHECK_NE(key_system, kPrefixedClearKeyKeySystem);
-
- if (key_system == kClearKeyKeySystem)
- return kPrefixedClearKeyKeySystem;
-
- return key_system;
-}
-
-bool IsSaneInitDataTypeWithContainer(
- const std::string& init_data_type,
- const std::string& container) {
- if (init_data_type == "cenc") {
- return container == "audio/mp4" || container == "video/mp4";
- } else if (init_data_type == "webm") {
- return container == "audio/webm" || container == "video/webm";
- } else {
- return true;
- }
-}
-
-bool IsConcreteSupportedKeySystem(const std::string& key_system) {
- return KeySystems::GetInstance().IsConcreteSupportedKeySystem(key_system);
-}
-
-bool IsSupportedKeySystem(const std::string& key_system) {
- return KeySystems::GetInstance().IsSupportedKeySystem(key_system);
-}
-
-bool IsSupportedKeySystemWithInitDataType(
- const std::string& key_system,
- const std::string& init_data_type) {
- return KeySystems::GetInstance().IsSupportedKeySystemWithInitDataType(
- key_system, init_data_type);
-}
-
-bool IsSupportedKeySystemWithMediaMimeType(
- const std::string& mime_type,
- const std::vector<std::string>& codecs,
- const std::string& key_system) {
- return KeySystems::GetInstance().IsSupportedKeySystemWithMediaMimeType(
- mime_type, codecs, key_system);
-}
-
-std::string KeySystemNameForUMA(const std::string& key_system) {
- if (key_system == kClearKeyKeySystem)
- return "ClearKey";
-#if defined(WIDEVINE_CDM_AVAILABLE)
- if (key_system == kWidevineKeySystem)
- return "Widevine";
-#endif // WIDEVINE_CDM_AVAILABLE
- return "Unknown";
-}
-
-bool CanUseAesDecryptor(const std::string& concrete_key_system) {
- return KeySystems::GetInstance().UseAesDecryptor(concrete_key_system);
-}
-
-#if defined(ENABLE_PEPPER_CDMS)
-std::string GetPepperType(const std::string& concrete_key_system) {
- return KeySystems::GetInstance().GetPepperType(concrete_key_system);
-}
-#endif
-
-// These two functions are for testing purpose only. The declaration in the
-// header file is guarded by "#if defined(UNIT_TEST)" so that they can be used
-// by tests but not non-test code. However, this .cc file is compiled as part of
-// "content" where "UNIT_TEST" is not defined. So we need to specify
-// "CONTENT_EXPORT" here again so that they are visible to tests.
-
-CONTENT_EXPORT void AddContainerMask(const std::string& container,
- uint32 mask) {
- KeySystems::GetInstance().AddContainerMask(container, mask);
-}
-
-CONTENT_EXPORT void AddCodecMask(const std::string& codec, uint32 mask) {
- KeySystems::GetInstance().AddCodecMask(codec, mask);
-}
-
-} // namespace content
diff --git a/chromium/content/renderer/media/crypto/key_systems.h b/chromium/content/renderer/media/crypto/key_systems.h
deleted file mode 100644
index 03d40024579..00000000000
--- a/chromium/content/renderer/media/crypto/key_systems.h
+++ /dev/null
@@ -1,80 +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_RENDERER_MEDIA_CRYPTO_KEY_SYSTEMS_H_
-#define CONTENT_RENDERER_MEDIA_CRYPTO_KEY_SYSTEMS_H_
-
-#include <string>
-#include <vector>
-
-#include "base/memory/scoped_ptr.h"
-#include "content/common/content_export.h"
-
-namespace content {
-
-// Prefixed EME API only supports prefixed (webkit-) key system name for
-// certain key systems. But internally only unprefixed key systems are
-// supported. The following two functions help convert between prefixed and
-// unprefixed key system names.
-
-// Gets the unprefixed key system name for |key_system|.
-std::string GetUnprefixedKeySystemName(const std::string& key_system);
-
-// Gets the prefixed key system name for |key_system|.
-std::string GetPrefixedKeySystemName(const std::string& key_system);
-
-// Returns false if a container-specific |init_data_type| is specified with an
-// inappropriate container.
-// TODO(sandersd): Remove this essentially internal detail if the spec is
-// updated to not convolve the two in a single method call.
-// TODO(sandersd): Use enum values instead of strings. http://crbug.com/417440
-bool IsSaneInitDataTypeWithContainer(
- const std::string& init_data_type,
- const std::string& container);
-
-// Note: Shouldn't be used for prefixed API as the original
-// IsSupportedKeySystemWithMediaMimeType() path reports UMAs, but this path does
-// not.
-bool IsSupportedKeySystem(const std::string& key_system);
-
-bool IsSupportedKeySystemWithInitDataType(
- const std::string& key_system,
- const std::string& init_data_type);
-
-// Returns whether |key_system| is a real supported key system that can be
-// instantiated.
-// Abstract parent |key_system| strings will return false.
-// Call IsSupportedKeySystemWithMediaMimeType() to determine whether a
-// |key_system| supports a specific type of media or to check parent key
-// systems.
-CONTENT_EXPORT bool IsConcreteSupportedKeySystem(const std::string& key_system);
-
-// Returns whether |key_sytem| supports the specified media type and codec(s).
-CONTENT_EXPORT bool IsSupportedKeySystemWithMediaMimeType(
- const std::string& mime_type,
- const std::vector<std::string>& codecs,
- const std::string& key_system);
-
-// Returns a name for |key_system| suitable to UMA logging.
-CONTENT_EXPORT std::string KeySystemNameForUMA(const std::string& key_system);
-
-// Returns whether AesDecryptor can be used for the given |concrete_key_system|.
-CONTENT_EXPORT bool CanUseAesDecryptor(const std::string& concrete_key_system);
-
-#if defined(ENABLE_PEPPER_CDMS)
-// Returns the Pepper MIME type for |concrete_key_system|.
-// Returns empty string if |concrete_key_system| is unknown or not Pepper-based.
-CONTENT_EXPORT std::string GetPepperType(
- const std::string& concrete_key_system);
-#endif
-
-#if defined(UNIT_TEST)
-// Helper functions to add container/codec types for testing purposes.
-CONTENT_EXPORT void AddContainerMask(const std::string& container, uint32 mask);
-CONTENT_EXPORT void AddCodecMask(const std::string& codec, uint32 mask);
-#endif // defined(UNIT_TEST)
-
-} // namespace content
-
-#endif // CONTENT_RENDERER_MEDIA_CRYPTO_KEY_SYSTEMS_H_
diff --git a/chromium/content/renderer/media/crypto/key_systems_support_uma.cc b/chromium/content/renderer/media/crypto/key_systems_support_uma.cc
deleted file mode 100644
index bd90aeb8bc9..00000000000
--- a/chromium/content/renderer/media/crypto/key_systems_support_uma.cc
+++ /dev/null
@@ -1,136 +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/renderer/media/crypto/key_systems_support_uma.h"
-
-#include <string>
-
-#include "base/metrics/histogram.h"
-#include "content/public/renderer/render_thread.h"
-#include "content/renderer/media/crypto/key_systems.h"
-
-namespace content {
-
-namespace {
-
-const char kKeySystemSupportUMAPrefix[] = "Media.EME.KeySystemSupport.";
-
-// These values are reported to UMA. Do not change the existing values!
-enum KeySystemSupportStatus {
- KEY_SYSTEM_QUERIED = 0,
- KEY_SYSTEM_SUPPORTED = 1,
- KEY_SYSTEM_WITH_TYPE_QUERIED = 2,
- KEY_SYSTEM_WITH_TYPE_SUPPORTED = 3,
- KEY_SYSTEM_SUPPORT_STATUS_COUNT
-};
-
-// Reports an event only once.
-class OneTimeReporter {
- public:
- OneTimeReporter(const std::string& key_system, KeySystemSupportStatus status);
- ~OneTimeReporter();
-
- void Report();
-
- private:
- bool is_reported_;
- const std::string key_system_;
- const KeySystemSupportStatus status_;
-};
-
-OneTimeReporter::OneTimeReporter(const std::string& key_system,
- KeySystemSupportStatus status)
- : is_reported_(false), key_system_(key_system), status_(status) {
-}
-
-OneTimeReporter::~OneTimeReporter() {}
-
-void OneTimeReporter::Report() {
- if (is_reported_)
- return;
-
- // Not using UMA_HISTOGRAM_ENUMERATION directly because UMA_* macros require
- // the names to be constant throughout the process' lifetime.
- base::LinearHistogram::FactoryGet(
- kKeySystemSupportUMAPrefix + KeySystemNameForUMA(key_system_), 1,
- KEY_SYSTEM_SUPPORT_STATUS_COUNT, KEY_SYSTEM_SUPPORT_STATUS_COUNT + 1,
- base::Histogram::kUmaTargetedHistogramFlag)->Add(status_);
-
- is_reported_ = true;
-}
-
-} // namespace
-
-class KeySystemsSupportUMA::Reporter {
- public:
- explicit Reporter(const std::string& key_system);
- ~Reporter();
-
- void Report(bool has_type, bool is_supported);
-
- private:
- const std::string key_system_;
-
- OneTimeReporter call_reporter_;
- OneTimeReporter call_with_type_reporter_;
- OneTimeReporter support_reporter_;
- OneTimeReporter support_with_type_reporter_;
-};
-
-KeySystemsSupportUMA::Reporter::Reporter(const std::string& key_system)
- : key_system_(key_system),
- call_reporter_(key_system, KEY_SYSTEM_QUERIED),
- call_with_type_reporter_(key_system, KEY_SYSTEM_WITH_TYPE_QUERIED),
- support_reporter_(key_system, KEY_SYSTEM_SUPPORTED),
- support_with_type_reporter_(key_system, KEY_SYSTEM_WITH_TYPE_SUPPORTED) {}
-
-KeySystemsSupportUMA::Reporter::~Reporter() {}
-
-void KeySystemsSupportUMA::Reporter::Report(bool has_type, bool is_supported) {
- call_reporter_.Report();
- if (has_type)
- call_with_type_reporter_.Report();
-
- if (!is_supported)
- return;
-
- support_reporter_.Report();
- if (has_type)
- support_with_type_reporter_.Report();
-}
-
-KeySystemsSupportUMA::KeySystemsSupportUMA() {}
-
-KeySystemsSupportUMA::~KeySystemsSupportUMA() {}
-
-void KeySystemsSupportUMA::AddKeySystemToReport(const std::string& key_system) {
- DCHECK(!GetReporter(key_system));
- reporters_.set(key_system, scoped_ptr<Reporter>(new Reporter(key_system)));
-}
-
-void KeySystemsSupportUMA::ReportKeySystemQuery(const std::string& key_system,
- bool has_type) {
- Reporter* reporter = GetReporter(key_system);
- if (!reporter)
- return;
- reporter->Report(has_type, false);
-}
-
-void KeySystemsSupportUMA::ReportKeySystemSupport(const std::string& key_system,
- bool has_type) {
- Reporter* reporter = GetReporter(key_system);
- if (!reporter)
- return;
- reporter->Report(has_type, true);
-}
-
-KeySystemsSupportUMA::Reporter* KeySystemsSupportUMA::GetReporter(
- const std::string& key_system) {
- Reporters::iterator reporter = reporters_.find(key_system);
- if (reporter == reporters_.end())
- return NULL;
- return reporter->second;
-}
-
-} // namespace content
diff --git a/chromium/content/renderer/media/crypto/key_systems_support_uma.h b/chromium/content/renderer/media/crypto/key_systems_support_uma.h
deleted file mode 100644
index 95e1b02bcd4..00000000000
--- a/chromium/content/renderer/media/crypto/key_systems_support_uma.h
+++ /dev/null
@@ -1,57 +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_RENDERER_MEDIA_CRYPTO_KEY_SYSTEMS_SUPPORT_UMA_H_
-#define CONTENT_RENDERER_MEDIA_CRYPTO_KEY_SYSTEMS_SUPPORT_UMA_H_
-
-#include <string>
-
-#include "base/containers/scoped_ptr_hash_map.h"
-
-namespace content {
-
-// Key system support UMA statistics for queried key systems.
-// 1. The key system is queried (with or without a MIME type).
-// 2. The key system is queried with a MIME type.
-// 3. The queried key system is supported (with or without a MIME type). This is
-// reported when the key system is supported when queried, regardless of
-// whether a MIME type is specified.
-// 4. The queried key system is supported with a MIME type. This is reported
-// when the key system is supported when queried without a MIME type
-// specified.
-// Note: All 4 stats are only reported once per renderer process per key system.
-class KeySystemsSupportUMA {
- public:
- KeySystemsSupportUMA();
- ~KeySystemsSupportUMA();
-
- // Adds a |key_system| for which query/support statistics are reported.
- // If you use this function to add key system to report, make sure to update
- // AddKeySystemSupportActions() in tools/metrics/actions/extract_actions.py.
- void AddKeySystemToReport(const std::string& key_system);
-
- // Reports that the |key_system| is queried. When |has_type|, also reports
- // that the |key_system| with a MIME type is queried.
- void ReportKeySystemQuery(const std::string& key_system, bool has_type);
-
- // Reports that the queried |key_system| is supported. When |has_type| (a
- // a MIME type is specified in the query), also reports that the queried
- // |key_system| is supported with that MIME type.
- void ReportKeySystemSupport(const std::string& key_system, bool has_type);
-
- private:
- class Reporter;
-
- // Returns the Reporter for |key_system|. Returns NULL if |key_system| was not
- // added for UMA reporting.
- Reporter* GetReporter(const std::string& key_system);
-
- // Key system <-> Reporter map.
- typedef base::ScopedPtrHashMap<std::string, Reporter> Reporters;
- Reporters reporters_;
-};
-
-} // namespace content
-
-#endif // CONTENT_RENDERER_MEDIA_CRYPTO_KEY_SYSTEMS_SUPPORT_UMA_H_
diff --git a/chromium/content/renderer/media/crypto/key_systems_unittest.cc b/chromium/content/renderer/media/crypto/key_systems_unittest.cc
deleted file mode 100644
index d7c980dd17f..00000000000
--- a/chromium/content/renderer/media/crypto/key_systems_unittest.cc
+++ /dev/null
@@ -1,649 +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 <string>
-#include <vector>
-
-#include "content/public/common/content_client.h"
-#include "content/public/renderer/content_renderer_client.h"
-#include "content/renderer/media/crypto/key_systems.h"
-#include "content/test/test_content_client.h"
-#include "media/base/eme_constants.h"
-#include "media/base/key_system_info.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/public/platform/WebString.h"
-
-#include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR.
-
-// Death tests are not always available, including on Android.
-// EXPECT_DEBUG_DEATH_PORTABLE executes tests correctly except in the case that
-// death tests are not available and NDEBUG is not defined.
-#if defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
-#define EXPECT_DEBUG_DEATH_PORTABLE(statement, regex) \
- EXPECT_DEBUG_DEATH(statement, regex)
-#else
-#if defined(NDEBUG)
-#define EXPECT_DEBUG_DEATH_PORTABLE(statement, regex) \
- do { statement; } while (false)
-#else
-#include "base/logging.h"
-#define EXPECT_DEBUG_DEATH_PORTABLE(statement, regex) \
- LOG(WARNING) << "Death tests are not supported on this platform.\n" \
- << "Statement '" #statement "' cannot be verified.";
-#endif // defined(NDEBUG)
-#endif // defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
-
-namespace content {
-
-using blink::WebString;
-using media::KeySystemInfo;
-
-// These are the (fake) key systems that are registered for these tests.
-// kUsesAes uses the AesDecryptor like Clear Key.
-// kExternal uses an external CDM, such as Pepper-based or Android platform CDM.
-const char kUsesAes[] = "org.example.clear";
-const char kUsesAesParent[] = "org.example"; // Not registered.
-const char kExternal[] = "com.example.test";
-const char kExternalParent[] = "com.example";
-
-const char kClearKey[] = "org.w3.clearkey";
-const char kPrefixedClearKey[] = "webkit-org.w3.clearkey";
-const char kExternalClearKey[] = "org.chromium.externalclearkey";
-
-const char kAudioWebM[] = "audio/webm";
-const char kVideoWebM[] = "video/webm";
-const char kAudioFoo[] = "audio/foo";
-const char kVideoFoo[] = "video/foo";
-
-// Pick some arbitrary bit fields as long as they are not in conflict with the
-// real ones.
-enum TestCodec {
- TEST_CODEC_FOO_AUDIO = 1 << 10, // An audio codec for foo container.
- TEST_CODEC_FOO_AUDIO_ALL = TEST_CODEC_FOO_AUDIO,
- TEST_CODEC_FOO_VIDEO = 1 << 11, // A video codec for foo container.
- TEST_CODEC_FOO_VIDEO_ALL = TEST_CODEC_FOO_VIDEO,
- TEST_CODEC_FOO_ALL = TEST_CODEC_FOO_AUDIO_ALL | TEST_CODEC_FOO_VIDEO_ALL
-};
-
-COMPILE_ASSERT((TEST_CODEC_FOO_ALL & media::EME_CODEC_ALL) ==
- media::EME_CODEC_NONE,
- test_codec_masks_should_only_use_invalid_codec_masks);
-
-// Adds test container and codec masks.
-// This function must be called after SetContentClient() is called.
-// More details: AddXxxMask() will create KeySystems if it hasn't been created.
-// During KeySystems's construction GetContentClient() will be used to add key
-// systems. In test code, the content client is set by SetContentClient().
-// Therefore, SetContentClient() must be called before this function to avoid
-// access violation.
-static void AddContainerAndCodecMasksForTest() {
- // Since KeySystems is a singleton. Make sure we only add test container and
- // codec masks once per process.
- static bool is_test_masks_added = false;
-
- if (is_test_masks_added)
- return;
-
- AddContainerMask("audio/foo", TEST_CODEC_FOO_AUDIO_ALL);
- AddContainerMask("video/foo", TEST_CODEC_FOO_ALL);
- AddCodecMask("fooaudio", TEST_CODEC_FOO_AUDIO);
- AddCodecMask("foovideo", TEST_CODEC_FOO_VIDEO);
-
- is_test_masks_added = true;
-}
-
-class TestContentRendererClient : public ContentRendererClient {
- void AddKeySystems(std::vector<media::KeySystemInfo>* key_systems) override;
-};
-
-void TestContentRendererClient::AddKeySystems(
- std::vector<media::KeySystemInfo>* key_systems) {
- KeySystemInfo aes(kUsesAes);
- aes.supported_codecs = media::EME_CODEC_WEBM_ALL;
- aes.supported_codecs |= TEST_CODEC_FOO_ALL;
- aes.supported_init_data_types = media::EME_INIT_DATA_TYPE_WEBM;
- aes.use_aes_decryptor = true;
- key_systems->push_back(aes);
-
- KeySystemInfo ext(kExternal);
- ext.supported_codecs = media::EME_CODEC_WEBM_ALL;
- ext.supported_codecs |= TEST_CODEC_FOO_ALL;
- ext.supported_init_data_types = media::EME_INIT_DATA_TYPE_WEBM;
- ext.parent_key_system = kExternalParent;
-#if defined(ENABLE_PEPPER_CDMS)
- ext.pepper_type = "application/x-ppapi-external-cdm";
-#endif // defined(ENABLE_PEPPER_CDMS)
- key_systems->push_back(ext);
-}
-
-// TODO(sandersd): Refactor. http://crbug.com/417444
-class KeySystemsTest : public testing::Test {
- protected:
- KeySystemsTest() {
- vp8_codec_.push_back("vp8");
-
- vp80_codec_.push_back("vp8.0");
-
- vp9_codec_.push_back("vp9");
-
- vp90_codec_.push_back("vp9.0");
-
- vorbis_codec_.push_back("vorbis");
-
- vp8_and_vorbis_codecs_.push_back("vp8");
- vp8_and_vorbis_codecs_.push_back("vorbis");
-
- vp9_and_vorbis_codecs_.push_back("vp9");
- vp9_and_vorbis_codecs_.push_back("vorbis");
-
- foovideo_codec_.push_back("foovideo");
-
- foovideo_extended_codec_.push_back("foovideo.4D400C");
-
- foovideo_dot_codec_.push_back("foovideo.");
-
- fooaudio_codec_.push_back("fooaudio");
-
- foovideo_and_fooaudio_codecs_.push_back("foovideo");
- foovideo_and_fooaudio_codecs_.push_back("fooaudio");
-
- unknown_codec_.push_back("unknown");
-
- mixed_codecs_.push_back("vorbis");
- mixed_codecs_.push_back("foovideo");
-
- // KeySystems requires a valid ContentRendererClient and thus ContentClient.
- // The TestContentClient is not available inside Death Tests on some
- // platforms (see below). Therefore, always provide a TestContentClient.
- // Explanation: When Death Tests fork, there is a valid ContentClient.
- // However, when they launch a new process instead of forking, the global
- // variable is not copied and for some reason TestContentClientInitializer
- // does not get created to set the global variable in the new process.
- SetContentClient(&test_content_client_);
- SetRendererClientForTesting(&content_renderer_client_);
- }
-
- void SetUp() override { AddContainerAndCodecMasksForTest(); }
-
- ~KeySystemsTest() override {
- // Clear the use of content_client_, which was set in SetUp().
- SetContentClient(NULL);
- }
-
- typedef std::vector<std::string> CodecVector;
-
- const CodecVector& no_codecs() const { return no_codecs_; }
-
- const CodecVector& vp8_codec() const { return vp8_codec_; }
- const CodecVector& vp80_codec() const { return vp80_codec_; }
- const CodecVector& vp9_codec() const { return vp9_codec_; }
- const CodecVector& vp90_codec() const { return vp90_codec_; }
-
- const CodecVector& vorbis_codec() const { return vorbis_codec_; }
-
- const CodecVector& vp8_and_vorbis_codecs() const {
- return vp8_and_vorbis_codecs_;
- }
- const CodecVector& vp9_and_vorbis_codecs() const {
- return vp9_and_vorbis_codecs_;
- }
-
- const CodecVector& foovideo_codec() const { return foovideo_codec_; }
- const CodecVector& foovideo_extended_codec() const {
- return foovideo_extended_codec_;
- }
- const CodecVector& foovideo_dot_codec() const { return foovideo_dot_codec_; }
- const CodecVector& fooaudio_codec() const { return fooaudio_codec_; }
- const CodecVector& foovideo_and_fooaudio_codecs() const {
- return foovideo_and_fooaudio_codecs_;
- }
-
- const CodecVector& unknown_codec() const { return unknown_codec_; }
-
- const CodecVector& mixed_codecs() const { return mixed_codecs_; }
-
- private:
- const CodecVector no_codecs_;
- CodecVector vp8_codec_;
- CodecVector vp80_codec_;
- CodecVector vp9_codec_;
- CodecVector vp90_codec_;
- CodecVector vorbis_codec_;
- CodecVector vp8_and_vorbis_codecs_;
- CodecVector vp9_and_vorbis_codecs_;
-
- CodecVector foovideo_codec_;
- CodecVector foovideo_extended_codec_;
- CodecVector foovideo_dot_codec_;
- CodecVector fooaudio_codec_;
- CodecVector foovideo_and_fooaudio_codecs_;
-
- CodecVector unknown_codec_;
-
- CodecVector mixed_codecs_;
-
- TestContentClient test_content_client_;
- TestContentRendererClient content_renderer_client_;
-};
-
-// TODO(ddorwin): Consider moving GetPepperType() calls out to their own test.
-
-TEST_F(KeySystemsTest, EmptyKeySystem) {
- EXPECT_FALSE(IsConcreteSupportedKeySystem(std::string()));
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, no_codecs(), std::string()));
- EXPECT_EQ("Unknown", KeySystemNameForUMA(std::string()));
-}
-
-// Clear Key is the only key system registered in content.
-TEST_F(KeySystemsTest, ClearKey) {
- EXPECT_TRUE(IsConcreteSupportedKeySystem(kClearKey));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, no_codecs(), kClearKey));
-
- EXPECT_EQ("ClearKey", KeySystemNameForUMA(kClearKey));
-
- // Prefixed Clear Key is not supported internally.
- EXPECT_FALSE(IsConcreteSupportedKeySystem(kPrefixedClearKey));
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, no_codecs(), kPrefixedClearKey));
- EXPECT_EQ("Unknown", KeySystemNameForUMA(kPrefixedClearKey));
-}
-
-// The key system is not registered and therefore is unrecognized.
-TEST_F(KeySystemsTest, Basic_UnrecognizedKeySystem) {
- static const char* const kUnrecognized = "org.example.unrecognized";
-
- EXPECT_FALSE(IsConcreteSupportedKeySystem(kUnrecognized));
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, no_codecs(), kUnrecognized));
-
- EXPECT_EQ("Unknown", KeySystemNameForUMA(kUnrecognized));
-
- bool can_use = false;
- EXPECT_DEBUG_DEATH_PORTABLE(
- can_use = CanUseAesDecryptor(kUnrecognized),
- "org.example.unrecognized is not a known concrete system");
- EXPECT_FALSE(can_use);
-
-#if defined(ENABLE_PEPPER_CDMS)
- std::string type;
- EXPECT_DEBUG_DEATH(type = GetPepperType(kUnrecognized),
- "org.example.unrecognized is not a known concrete system");
- EXPECT_TRUE(type.empty());
-#endif
-}
-
-TEST_F(KeySystemsTest, Basic_UsesAesDecryptor) {
- EXPECT_TRUE(IsConcreteSupportedKeySystem(kUsesAes));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, no_codecs(), kUsesAes));
-
- // No UMA value for this test key system.
- EXPECT_EQ("Unknown", KeySystemNameForUMA(kUsesAes));
-
- EXPECT_TRUE(CanUseAesDecryptor(kUsesAes));
-#if defined(ENABLE_PEPPER_CDMS)
- std::string type;
- EXPECT_DEBUG_DEATH(type = GetPepperType(kUsesAes),
- "org.example.clear is not Pepper-based");
- EXPECT_TRUE(type.empty());
-#endif
-}
-
-TEST_F(KeySystemsTest,
- IsSupportedKeySystemWithMediaMimeType_UsesAesDecryptor_TypesContainer1) {
- // Valid video types.
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, vp8_codec(), kUsesAes));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, vp80_codec(), kUsesAes));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, vp8_and_vorbis_codecs(), kUsesAes));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, vp9_codec(), kUsesAes));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, vp90_codec(), kUsesAes));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, vp9_and_vorbis_codecs(), kUsesAes));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, vorbis_codec(), kUsesAes));
-
- // Non-Webm codecs.
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, foovideo_codec(), kUsesAes));
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, unknown_codec(), kUsesAes));
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, mixed_codecs(), kUsesAes));
-
- // Valid audio types.
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kAudioWebM, no_codecs(), kUsesAes));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kAudioWebM, vorbis_codec(), kUsesAes));
-
- // Non-audio codecs.
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kAudioWebM, vp8_codec(), kUsesAes));
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kAudioWebM, vp8_and_vorbis_codecs(), kUsesAes));
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kAudioWebM, vp9_codec(), kUsesAes));
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kAudioWebM, vp9_and_vorbis_codecs(), kUsesAes));
-
- // Non-Webm codec.
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kAudioWebM, fooaudio_codec(), kUsesAes));
-}
-
-// No parent is registered for UsesAes.
-TEST_F(KeySystemsTest, Parent_NoParentRegistered) {
- EXPECT_FALSE(IsConcreteSupportedKeySystem(kUsesAesParent));
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, no_codecs(), kUsesAesParent));
-
- // The parent is not supported for most things.
- EXPECT_EQ("Unknown", KeySystemNameForUMA(kUsesAesParent));
- bool result = false;
- EXPECT_DEBUG_DEATH_PORTABLE(result = CanUseAesDecryptor(kUsesAesParent),
- "org.example is not a known concrete system");
- EXPECT_FALSE(result);
-#if defined(ENABLE_PEPPER_CDMS)
- std::string type;
- EXPECT_DEBUG_DEATH(type = GetPepperType(kUsesAesParent),
- "org.example is not a known concrete system");
- EXPECT_TRUE(type.empty());
-#endif
-}
-
-TEST_F(KeySystemsTest, IsSupportedKeySystem_InvalidVariants) {
- // Case sensitive.
- EXPECT_FALSE(IsConcreteSupportedKeySystem("org.example.ClEaR"));
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, no_codecs(), "org.example.ClEaR"));
-
- // TLDs are not allowed.
- EXPECT_FALSE(IsConcreteSupportedKeySystem("org."));
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, no_codecs(), "org."));
- EXPECT_FALSE(IsConcreteSupportedKeySystem("com"));
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, no_codecs(), "com"));
-
- // Extra period.
- EXPECT_FALSE(IsConcreteSupportedKeySystem("org.example."));
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, no_codecs(), "org.example."));
-
- // Incomplete.
- EXPECT_FALSE(IsConcreteSupportedKeySystem("org.example.clea"));
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, no_codecs(), "org.example.clea"));
-
- // Extra character.
- EXPECT_FALSE(IsConcreteSupportedKeySystem("org.example.clearz"));
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, no_codecs(), "org.example.clearz"));
-
- // There are no child key systems for UsesAes.
- EXPECT_FALSE(IsConcreteSupportedKeySystem("org.example.clear.foo"));
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, no_codecs(), "org.example.clear.foo"));
-}
-
-TEST_F(KeySystemsTest, IsSupportedKeySystemWithMediaMimeType_NoType) {
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- std::string(), no_codecs(), kUsesAes));
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- std::string(), no_codecs(), kUsesAesParent));
-
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- std::string(), no_codecs(), "org.example.foo"));
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- std::string(), no_codecs(), "org.example.clear.foo"));
-}
-
-// Tests the second registered container type.
-// TODO(ddorwin): Combined with TypesContainer1 in a future CL.
-TEST_F(KeySystemsTest,
- IsSupportedKeySystemWithMediaMimeType_UsesAesDecryptor_TypesContainer2) {
- // Valid video types.
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoFoo, no_codecs(), kUsesAes));
- // The parent should be supported but is not. See http://crbug.com/164303.
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kVideoFoo, no_codecs(), kUsesAesParent));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoFoo, foovideo_codec(), kUsesAes));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoFoo, foovideo_and_fooaudio_codecs(), kUsesAes));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoFoo, fooaudio_codec(), kUsesAes));
-
- // Extended codecs fail because this is handled by SimpleWebMimeRegistryImpl.
- // They should really pass canPlayType().
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kVideoFoo, foovideo_extended_codec(), kUsesAes));
-
- // Invalid codec format.
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kVideoFoo, foovideo_dot_codec(), kUsesAes));
-
- // Non-container2 codec.
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kVideoFoo, vp8_codec(), kUsesAes));
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kVideoFoo, unknown_codec(), kUsesAes));
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kVideoFoo, mixed_codecs(), kUsesAes));
-
- // Valid audio types.
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kAudioFoo, no_codecs(), kUsesAes));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kAudioFoo, fooaudio_codec(), kUsesAes));
-
- // Non-audio codecs.
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kAudioFoo, foovideo_codec(), kUsesAes));
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kAudioFoo, foovideo_and_fooaudio_codecs(), kUsesAes));
-
- // Non-container2 codec.
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kAudioFoo, vorbis_codec(), kUsesAes));
-}
-
-//
-// Non-AesDecryptor-based key system.
-//
-
-TEST_F(KeySystemsTest, Basic_ExternalDecryptor) {
- EXPECT_TRUE(IsConcreteSupportedKeySystem(kExternal));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, no_codecs(), kExternal));
-
- EXPECT_FALSE(CanUseAesDecryptor(kExternal));
-#if defined(ENABLE_PEPPER_CDMS)
- EXPECT_EQ("application/x-ppapi-external-cdm", GetPepperType(kExternal));
-#endif // defined(ENABLE_PEPPER_CDMS)
-
-}
-
-TEST_F(KeySystemsTest, Parent_ParentRegistered) {
- // The parent system is not a concrete system but is supported.
- EXPECT_FALSE(IsConcreteSupportedKeySystem(kExternalParent));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, no_codecs(), kExternalParent));
-
- // The parent is not supported for most things.
- EXPECT_EQ("Unknown", KeySystemNameForUMA(kExternalParent));
- bool result = false;
- EXPECT_DEBUG_DEATH_PORTABLE(result = CanUseAesDecryptor(kExternalParent),
- "com.example is not a known concrete system");
- EXPECT_FALSE(result);
-#if defined(ENABLE_PEPPER_CDMS)
- std::string type;
- EXPECT_DEBUG_DEATH(type = GetPepperType(kExternalParent),
- "com.example is not a known concrete system");
- EXPECT_TRUE(type.empty());
-#endif
-}
-
-TEST_F(
- KeySystemsTest,
- IsSupportedKeySystemWithMediaMimeType_ExternalDecryptor_TypesContainer1) {
- // Valid video types.
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, no_codecs(), kExternal));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, vp8_codec(), kExternal));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, vp80_codec(), kExternal));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, vp8_and_vorbis_codecs(), kExternal));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, vp9_codec(), kExternal));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, vp90_codec(), kExternal));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, vp9_and_vorbis_codecs(), kExternal));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, vorbis_codec(), kExternal));
-
- // Valid video types - parent key system.
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, no_codecs(), kExternalParent));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, vp8_codec(), kExternalParent));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, vp80_codec(), kExternalParent));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, vp8_and_vorbis_codecs(), kExternalParent));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, vp9_codec(), kExternalParent));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, vp90_codec(), kExternalParent));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, vp9_and_vorbis_codecs(), kExternalParent));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, vorbis_codec(), kExternalParent));
-
- // Non-Webm codecs.
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, foovideo_codec(), kExternal));
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, unknown_codec(), kExternal));
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, mixed_codecs(), kExternal));
-
- // Valid audio types.
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kAudioWebM, no_codecs(), kExternal));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kAudioWebM, vorbis_codec(), kExternal));
-
- // Valid audio types - parent key system.
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kAudioWebM, no_codecs(), kExternalParent));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kAudioWebM, vorbis_codec(), kExternalParent));
-
- // Non-audio codecs.
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kAudioWebM, vp8_codec(), kExternal));
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kAudioWebM, vp8_and_vorbis_codecs(), kExternal));
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kAudioWebM, vp9_codec(), kExternal));
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kAudioWebM, vp9_and_vorbis_codecs(), kExternal));
-
- // Non-Webm codec.
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kAudioWebM, fooaudio_codec(), kExternal));
-}
-
-TEST_F(
- KeySystemsTest,
- IsSupportedKeySystemWithMediaMimeType_ExternalDecryptor_TypesContainer2) {
- // Valid video types.
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoFoo, no_codecs(), kExternal));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoFoo, foovideo_codec(), kExternal));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoFoo, foovideo_and_fooaudio_codecs(), kExternal));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoFoo, fooaudio_codec(), kExternal));
-
- // Valid video types - parent key system.
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoFoo, no_codecs(), kExternalParent));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoFoo, foovideo_codec(), kExternalParent));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoFoo, foovideo_and_fooaudio_codecs(), kExternalParent));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kVideoFoo, fooaudio_codec(), kExternalParent));
-
- // Extended codecs fail because this is handled by SimpleWebMimeRegistryImpl.
- // They should really pass canPlayType().
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kVideoFoo, foovideo_extended_codec(), kExternal));
-
- // Invalid codec format.
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kVideoFoo, foovideo_dot_codec(), kExternal));
-
- // Non-container2 codecs.
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kVideoFoo, vp8_codec(), kExternal));
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kVideoFoo, unknown_codec(), kExternal));
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kVideoFoo, mixed_codecs(), kExternal));
-
- // Valid audio types.
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kAudioFoo, no_codecs(), kExternal));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kAudioFoo, fooaudio_codec(), kExternal));
-
- // Valid audio types - parent key system.
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kAudioFoo, no_codecs(), kExternalParent));
- EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
- kAudioFoo, fooaudio_codec(), kExternalParent));
-
- // Non-audio codecs.
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kAudioFoo, foovideo_codec(), kExternal));
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kAudioFoo, foovideo_and_fooaudio_codecs(), kExternal));
-
- // Non-container2 codec.
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kAudioFoo, vorbis_codec(), kExternal));
-}
-
-TEST_F(KeySystemsTest, KeySystemNameForUMA) {
- EXPECT_EQ("ClearKey", KeySystemNameForUMA(kClearKey));
- // Prefixed is not supported internally.
- EXPECT_EQ("Unknown", KeySystemNameForUMA(kPrefixedClearKey));
-
- // External Clear Key never has a UMA name.
- EXPECT_EQ("Unknown", KeySystemNameForUMA(kExternalClearKey));
-
-#if defined(WIDEVINE_CDM_AVAILABLE)
- const char* const kTestWidevineUmaName = "Widevine";
-#else
- const char* const kTestWidevineUmaName = "Unknown";
-#endif
- EXPECT_EQ(kTestWidevineUmaName, KeySystemNameForUMA("com.widevine.alpha"));
-}
-
-} // namespace content
diff --git a/chromium/content/renderer/media/crypto/ppapi_decryptor.cc b/chromium/content/renderer/media/crypto/ppapi_decryptor.cc
index 1af098c1fbe..b828de51d09 100644
--- a/chromium/content/renderer/media/crypto/ppapi_decryptor.cc
+++ b/chromium/content/renderer/media/crypto/ppapi_decryptor.cc
@@ -10,92 +10,103 @@
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "base/message_loop/message_loop_proxy.h"
-#include "content/renderer/media/crypto/key_systems.h"
+#include "content/renderer/media/crypto/cdm_initialized_promise.h"
#include "content/renderer/pepper/content_decryptor_delegate.h"
#include "content/renderer/pepper/pepper_plugin_instance_impl.h"
#include "media/base/audio_decoder_config.h"
+#include "media/base/cdm_key_information.h"
#include "media/base/data_buffer.h"
#include "media/base/decoder_buffer.h"
+#include "media/base/key_systems.h"
#include "media/base/video_decoder_config.h"
#include "media/base/video_frame.h"
namespace content {
-scoped_ptr<PpapiDecryptor> PpapiDecryptor::Create(
+void PpapiDecryptor::Create(
const std::string& key_system,
const GURL& security_origin,
+ bool allow_distinctive_identifier,
+ bool allow_persistent_state,
const CreatePepperCdmCB& create_pepper_cdm_cb,
const media::SessionMessageCB& session_message_cb,
- const media::SessionReadyCB& session_ready_cb,
const media::SessionClosedCB& session_closed_cb,
- const media::SessionErrorCB& session_error_cb,
+ const media::LegacySessionErrorCB& legacy_session_error_cb,
const media::SessionKeysChangeCB& session_keys_change_cb,
- const media::SessionExpirationUpdateCB& session_expiration_update_cb) {
- std::string plugin_type = GetPepperType(key_system);
+ const media::SessionExpirationUpdateCB& session_expiration_update_cb,
+ const media::CdmCreatedCB& cdm_created_cb) {
+ std::string plugin_type = media::GetPepperType(key_system);
DCHECK(!plugin_type.empty());
scoped_ptr<PepperCdmWrapper> pepper_cdm_wrapper =
create_pepper_cdm_cb.Run(plugin_type, security_origin);
if (!pepper_cdm_wrapper) {
DLOG(ERROR) << "Plugin instance creation failed.";
- return scoped_ptr<PpapiDecryptor>();
+ base::MessageLoopProxy::current()->PostTask(
+ FROM_HERE, base::Bind(cdm_created_cb, nullptr,
+ "Plugin instance creation failed."));
+ return;
}
- return scoped_ptr<PpapiDecryptor>(
- new PpapiDecryptor(key_system,
- pepper_cdm_wrapper.Pass(),
- session_message_cb,
- session_ready_cb,
- session_closed_cb,
- session_error_cb,
- session_keys_change_cb,
- session_expiration_update_cb));
+ scoped_ptr<PpapiDecryptor> ppapi_decryptor(
+ new PpapiDecryptor(pepper_cdm_wrapper.Pass(), session_message_cb,
+ session_closed_cb, legacy_session_error_cb,
+ session_keys_change_cb, session_expiration_update_cb));
+
+ // PpapiDecryptor ownership passed to the promise, but keep a copy in order
+ // to call InitializeCdm().
+ PpapiDecryptor* ppapi_decryptor_copy = ppapi_decryptor.get();
+ scoped_ptr<CdmInitializedPromise> promise(
+ new CdmInitializedPromise(cdm_created_cb, ppapi_decryptor.Pass()));
+ ppapi_decryptor_copy->InitializeCdm(key_system, allow_distinctive_identifier,
+ allow_persistent_state, promise.Pass());
}
PpapiDecryptor::PpapiDecryptor(
- const std::string& key_system,
scoped_ptr<PepperCdmWrapper> pepper_cdm_wrapper,
const media::SessionMessageCB& session_message_cb,
- const media::SessionReadyCB& session_ready_cb,
const media::SessionClosedCB& session_closed_cb,
- const media::SessionErrorCB& session_error_cb,
+ const media::LegacySessionErrorCB& legacy_session_error_cb,
const media::SessionKeysChangeCB& session_keys_change_cb,
const media::SessionExpirationUpdateCB& session_expiration_update_cb)
: pepper_cdm_wrapper_(pepper_cdm_wrapper.Pass()),
session_message_cb_(session_message_cb),
- session_ready_cb_(session_ready_cb),
session_closed_cb_(session_closed_cb),
- session_error_cb_(session_error_cb),
+ legacy_session_error_cb_(legacy_session_error_cb),
session_keys_change_cb_(session_keys_change_cb),
session_expiration_update_cb_(session_expiration_update_cb),
render_loop_proxy_(base::MessageLoopProxy::current()),
weak_ptr_factory_(this) {
DCHECK(pepper_cdm_wrapper_.get());
DCHECK(!session_message_cb_.is_null());
- DCHECK(!session_ready_cb_.is_null());
DCHECK(!session_closed_cb_.is_null());
- DCHECK(!session_error_cb_.is_null());
+ DCHECK(!legacy_session_error_cb_.is_null());
DCHECK(!session_keys_change_cb.is_null());
DCHECK(!session_expiration_update_cb.is_null());
+}
+
+PpapiDecryptor::~PpapiDecryptor() {
+ pepper_cdm_wrapper_.reset();
+}
+void PpapiDecryptor::InitializeCdm(
+ const std::string& key_system,
+ bool allow_distinctive_identifier,
+ bool allow_persistent_state,
+ scoped_ptr<media::SimpleCdmPromise> promise) {
base::WeakPtr<PpapiDecryptor> weak_this = weak_ptr_factory_.GetWeakPtr();
CdmDelegate()->Initialize(
- key_system,
+ key_system, allow_distinctive_identifier, allow_persistent_state,
base::Bind(&PpapiDecryptor::OnSessionMessage, weak_this),
- base::Bind(&PpapiDecryptor::OnSessionReady, weak_this),
base::Bind(&PpapiDecryptor::OnSessionClosed, weak_this),
- base::Bind(&PpapiDecryptor::OnSessionError, weak_this),
+ base::Bind(&PpapiDecryptor::OnLegacySessionError, weak_this),
base::Bind(&PpapiDecryptor::OnSessionKeysChange, weak_this),
base::Bind(&PpapiDecryptor::OnSessionExpirationUpdate, weak_this),
- base::Bind(&PpapiDecryptor::OnFatalPluginError, weak_this));
-}
-
-PpapiDecryptor::~PpapiDecryptor() {
- pepper_cdm_wrapper_.reset();
+ base::Bind(&PpapiDecryptor::OnFatalPluginError, weak_this),
+ promise.Pass());
}
void PpapiDecryptor::SetServerCertificate(
- const uint8* certificate_data,
- int certificate_data_length,
+ const std::vector<uint8_t>& certificate,
scoped_ptr<media::SimpleCdmPromise> promise) {
DVLOG(2) << __FUNCTION__;
DCHECK(render_loop_proxy_->BelongsToCurrentThread());
@@ -105,15 +116,13 @@ void PpapiDecryptor::SetServerCertificate(
return;
}
- CdmDelegate()->SetServerCertificate(
- certificate_data, certificate_data_length, promise.Pass());
+ CdmDelegate()->SetServerCertificate(certificate, promise.Pass());
}
-void PpapiDecryptor::CreateSession(
- const std::string& init_data_type,
- const uint8* init_data,
- int init_data_length,
+void PpapiDecryptor::CreateSessionAndGenerateRequest(
SessionType session_type,
+ media::EmeInitDataType init_data_type,
+ const std::vector<uint8_t>& init_data,
scoped_ptr<media::NewSessionCdmPromise> promise) {
DVLOG(2) << __FUNCTION__;
DCHECK(render_loop_proxy_->BelongsToCurrentThread());
@@ -123,15 +132,13 @@ void PpapiDecryptor::CreateSession(
return;
}
- CdmDelegate()->CreateSession(init_data_type,
- init_data,
- init_data_length,
- session_type,
- promise.Pass());
+ CdmDelegate()->CreateSessionAndGenerateRequest(session_type, init_data_type,
+ init_data, promise.Pass());
}
void PpapiDecryptor::LoadSession(
- const std::string& web_session_id,
+ SessionType session_type,
+ const std::string& session_id,
scoped_ptr<media::NewSessionCdmPromise> promise) {
DVLOG(2) << __FUNCTION__;
DCHECK(render_loop_proxy_->BelongsToCurrentThread());
@@ -140,13 +147,12 @@ void PpapiDecryptor::LoadSession(
promise->reject(INVALID_STATE_ERROR, 0, "CdmDelegate() does not exist.");
return;
}
- CdmDelegate()->LoadSession(web_session_id, promise.Pass());
+ CdmDelegate()->LoadSession(session_type, session_id, promise.Pass());
}
void PpapiDecryptor::UpdateSession(
- const std::string& web_session_id,
- const uint8* response,
- int response_length,
+ const std::string& session_id,
+ const std::vector<uint8_t>& response,
scoped_ptr<media::SimpleCdmPromise> promise) {
DCHECK(render_loop_proxy_->BelongsToCurrentThread());
@@ -154,11 +160,10 @@ void PpapiDecryptor::UpdateSession(
promise->reject(INVALID_STATE_ERROR, 0, "CdmDelegate() does not exist.");
return;
}
- CdmDelegate()->UpdateSession(web_session_id, response, response_length,
- promise.Pass());
+ CdmDelegate()->UpdateSession(session_id, response, promise.Pass());
}
-void PpapiDecryptor::CloseSession(const std::string& web_session_id,
+void PpapiDecryptor::CloseSession(const std::string& session_id,
scoped_ptr<media::SimpleCdmPromise> promise) {
DCHECK(render_loop_proxy_->BelongsToCurrentThread());
@@ -167,11 +172,11 @@ void PpapiDecryptor::CloseSession(const std::string& web_session_id,
return;
}
- CdmDelegate()->CloseSession(web_session_id, promise.Pass());
+ CdmDelegate()->CloseSession(session_id, promise.Pass());
}
void PpapiDecryptor::RemoveSession(
- const std::string& web_session_id,
+ const std::string& session_id,
scoped_ptr<media::SimpleCdmPromise> promise) {
DCHECK(render_loop_proxy_->BelongsToCurrentThread());
@@ -180,25 +185,21 @@ void PpapiDecryptor::RemoveSession(
return;
}
- CdmDelegate()->RemoveSession(web_session_id, promise.Pass());
+ CdmDelegate()->RemoveSession(session_id, promise.Pass());
}
-void PpapiDecryptor::GetUsableKeyIds(const std::string& web_session_id,
- scoped_ptr<media::KeyIdsPromise> promise) {
- DCHECK(render_loop_proxy_->BelongsToCurrentThread());
-
- if (!CdmDelegate()) {
- promise->reject(INVALID_STATE_ERROR, 0, "CdmDelegate() does not exist.");
- return;
- }
-
- CdmDelegate()->GetUsableKeyIds(web_session_id, promise.Pass());
+media::CdmContext* PpapiDecryptor::GetCdmContext() {
+ return this;
}
media::Decryptor* PpapiDecryptor::GetDecryptor() {
return this;
}
+int PpapiDecryptor::GetCdmId() const {
+ return kInvalidCdmId;
+}
+
void PpapiDecryptor::RegisterNewKeyCB(StreamType stream_type,
const NewKeyCB& new_key_cb) {
if (!render_loop_proxy_->BelongsToCurrentThread()) {
@@ -330,7 +331,7 @@ void PpapiDecryptor::DecryptAndDecodeAudio(
DVLOG(3) << __FUNCTION__;
if (!CdmDelegate() ||
!CdmDelegate()->DecryptAndDecodeAudio(encrypted, audio_decode_cb)) {
- audio_decode_cb.Run(kError, AudioBuffers());
+ audio_decode_cb.Run(kError, AudioFrames());
}
}
@@ -400,15 +401,18 @@ void PpapiDecryptor::OnDecoderInitialized(StreamType stream_type,
}
}
-void PpapiDecryptor::OnSessionMessage(const std::string& web_session_id,
- const std::vector<uint8>& message,
- const GURL& destination_url) {
+void PpapiDecryptor::OnSessionMessage(const std::string& session_id,
+ MessageType message_type,
+ const std::vector<uint8_t>& message,
+ const GURL& legacy_destination_url) {
DCHECK(render_loop_proxy_->BelongsToCurrentThread());
- session_message_cb_.Run(web_session_id, message, destination_url);
+ session_message_cb_.Run(session_id, message_type, message,
+ legacy_destination_url);
}
-void PpapiDecryptor::OnSessionKeysChange(const std::string& web_session_id,
- bool has_additional_usable_key) {
+void PpapiDecryptor::OnSessionKeysChange(const std::string& session_id,
+ bool has_additional_usable_key,
+ media::CdmKeysInfo keys_info) {
DCHECK(render_loop_proxy_->BelongsToCurrentThread());
// TODO(jrummell): Handling resume playback should be done in the media
@@ -416,33 +420,30 @@ void PpapiDecryptor::OnSessionKeysChange(const std::string& web_session_id,
if (has_additional_usable_key)
AttemptToResumePlayback();
- session_keys_change_cb_.Run(web_session_id, has_additional_usable_key);
+ session_keys_change_cb_.Run(session_id, has_additional_usable_key,
+ keys_info.Pass());
}
void PpapiDecryptor::OnSessionExpirationUpdate(
- const std::string& web_session_id,
+ const std::string& session_id,
const base::Time& new_expiry_time) {
DCHECK(render_loop_proxy_->BelongsToCurrentThread());
- session_expiration_update_cb_.Run(web_session_id, new_expiry_time);
-}
-
-void PpapiDecryptor::OnSessionReady(const std::string& web_session_id) {
- DCHECK(render_loop_proxy_->BelongsToCurrentThread());
- session_ready_cb_.Run(web_session_id);
+ session_expiration_update_cb_.Run(session_id, new_expiry_time);
}
-void PpapiDecryptor::OnSessionClosed(const std::string& web_session_id) {
+void PpapiDecryptor::OnSessionClosed(const std::string& session_id) {
DCHECK(render_loop_proxy_->BelongsToCurrentThread());
- session_closed_cb_.Run(web_session_id);
+ session_closed_cb_.Run(session_id);
}
-void PpapiDecryptor::OnSessionError(const std::string& web_session_id,
- MediaKeys::Exception exception_code,
- uint32 system_code,
- const std::string& error_description) {
+void PpapiDecryptor::OnLegacySessionError(
+ const std::string& session_id,
+ MediaKeys::Exception exception_code,
+ uint32_t system_code,
+ const std::string& error_description) {
DCHECK(render_loop_proxy_->BelongsToCurrentThread());
- session_error_cb_.Run(
- web_session_id, exception_code, system_code, error_description);
+ legacy_session_error_cb_.Run(session_id, exception_code, system_code,
+ error_description);
}
void PpapiDecryptor::AttemptToResumePlayback() {
diff --git a/chromium/content/renderer/media/crypto/ppapi_decryptor.h b/chromium/content/renderer/media/crypto/ppapi_decryptor.h
index 39c38c210f3..a4f26b5ac32 100644
--- a/chromium/content/renderer/media/crypto/ppapi_decryptor.h
+++ b/chromium/content/renderer/media/crypto/ppapi_decryptor.h
@@ -12,6 +12,8 @@
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "content/renderer/media/crypto/pepper_cdm_wrapper.h"
+#include "media/base/cdm_context.h"
+#include "media/base/cdm_factory.h"
#include "media/base/decryptor.h"
#include "media/base/media_keys.h"
#include "media/base/video_decoder_config.h"
@@ -29,44 +31,49 @@ class PepperPluginInstanceImpl;
// PpapiDecryptor implements media::MediaKeys and media::Decryptor and forwards
// all calls to the PluginInstance.
// This class should always be created & destroyed on the main renderer thread.
-class PpapiDecryptor : public media::MediaKeys, public media::Decryptor {
+class PpapiDecryptor : public media::MediaKeys,
+ public media::CdmContext,
+ public media::Decryptor {
public:
- static scoped_ptr<PpapiDecryptor> Create(
+ static void Create(
const std::string& key_system,
const GURL& security_origin,
+ bool allow_distinctive_identifier,
+ bool allow_persistent_state,
const CreatePepperCdmCB& create_pepper_cdm_cb,
const media::SessionMessageCB& session_message_cb,
- const media::SessionReadyCB& session_ready_cb,
const media::SessionClosedCB& session_closed_cb,
- const media::SessionErrorCB& session_error_cb,
+ const media::LegacySessionErrorCB& legacy_session_error_cb,
const media::SessionKeysChangeCB& session_keys_change_cb,
- const media::SessionExpirationUpdateCB& session_expiration_update_cb);
+ const media::SessionExpirationUpdateCB& session_expiration_update_cb,
+ const media::CdmCreatedCB& cdm_created_cb);
~PpapiDecryptor() override;
// media::MediaKeys implementation.
void SetServerCertificate(
- const uint8* certificate_data,
- int certificate_data_length,
+ const std::vector<uint8_t>& certificate,
scoped_ptr<media::SimpleCdmPromise> promise) override;
- void CreateSession(const std::string& init_data_type,
- const uint8* init_data,
- int init_data_length,
- SessionType session_type,
- scoped_ptr<media::NewSessionCdmPromise> promise) override;
- void LoadSession(const std::string& web_session_id,
+ void CreateSessionAndGenerateRequest(
+ SessionType session_type,
+ media::EmeInitDataType init_data_type,
+ const std::vector<uint8_t>& init_data,
+ scoped_ptr<media::NewSessionCdmPromise> promise) override;
+ void LoadSession(SessionType session_type,
+ const std::string& session_id,
scoped_ptr<media::NewSessionCdmPromise> promise) override;
- void UpdateSession(const std::string& web_session_id,
- const uint8* response,
- int response_length,
+ void UpdateSession(const std::string& session_id,
+ const std::vector<uint8_t>& response,
scoped_ptr<media::SimpleCdmPromise> promise) override;
- void CloseSession(const std::string& web_session_id,
+ void CloseSession(const std::string& session_id,
scoped_ptr<media::SimpleCdmPromise> promise) override;
- void RemoveSession(const std::string& web_session_id,
+ void RemoveSession(const std::string& session_id,
scoped_ptr<media::SimpleCdmPromise> promise) override;
- void GetUsableKeyIds(const std::string& web_session_id,
- scoped_ptr<media::KeyIdsPromise> promise) override;
+ CdmContext* GetCdmContext() override;
+
+ // media::CdmContext implementation.
Decryptor* GetDecryptor() override;
+ int GetCdmId() const override;
// media::Decryptor implementation.
void RegisterNewKeyCB(StreamType stream_type,
@@ -90,31 +97,35 @@ class PpapiDecryptor : public media::MediaKeys, public media::Decryptor {
private:
PpapiDecryptor(
- const std::string& key_system,
scoped_ptr<PepperCdmWrapper> pepper_cdm_wrapper,
const media::SessionMessageCB& session_message_cb,
- const media::SessionReadyCB& session_ready_cb,
const media::SessionClosedCB& session_closed_cb,
- const media::SessionErrorCB& session_error_cb,
+ const media::LegacySessionErrorCB& legacy_session_error_cb,
const media::SessionKeysChangeCB& session_keys_change_cb,
const media::SessionExpirationUpdateCB& session_expiration_update_cb);
+ void InitializeCdm(const std::string& key_system,
+ bool allow_distinctive_identifier,
+ bool allow_persistent_state,
+ scoped_ptr<media::SimpleCdmPromise> promise);
+
void OnDecoderInitialized(StreamType stream_type, bool success);
// Callbacks for |plugin_cdm_delegate_| to fire session events.
- void OnSessionMessage(const std::string& web_session_id,
- const std::vector<uint8>& message,
- const GURL& destination_url);
- void OnSessionKeysChange(const std::string& web_session_id,
- bool has_additional_usable_key);
- void OnSessionExpirationUpdate(const std::string& web_session_id,
+ void OnSessionMessage(const std::string& session_id,
+ MediaKeys::MessageType message_type,
+ const std::vector<uint8_t>& message,
+ const GURL& legacy_destination_url);
+ void OnSessionKeysChange(const std::string& session_id,
+ bool has_additional_usable_key,
+ media::CdmKeysInfo keys_info);
+ void OnSessionExpirationUpdate(const std::string& session_id,
const base::Time& new_expiry_time);
- void OnSessionReady(const std::string& web_session_id);
- void OnSessionClosed(const std::string& web_session_id);
- void OnSessionError(const std::string& web_session_id,
- MediaKeys::Exception exception_code,
- uint32 system_code,
- const std::string& error_description);
+ void OnSessionClosed(const std::string& session_id);
+ void OnLegacySessionError(const std::string& session_id,
+ MediaKeys::Exception exception_code,
+ uint32_t system_code,
+ const std::string& error_description);
void AttemptToResumePlayback();
@@ -131,9 +142,8 @@ class PpapiDecryptor : public media::MediaKeys, public media::Decryptor {
// Callbacks for firing session events.
media::SessionMessageCB session_message_cb_;
- media::SessionReadyCB session_ready_cb_;
media::SessionClosedCB session_closed_cb_;
- media::SessionErrorCB session_error_cb_;
+ media::LegacySessionErrorCB legacy_session_error_cb_;
media::SessionKeysChangeCB session_keys_change_cb_;
media::SessionExpirationUpdateCB session_expiration_update_cb_;
diff --git a/chromium/content/renderer/media/crypto/proxy_decryptor.cc b/chromium/content/renderer/media/crypto/proxy_decryptor.cc
deleted file mode 100644
index 44a30fd1f84..00000000000
--- a/chromium/content/renderer/media/crypto/proxy_decryptor.cc
+++ /dev/null
@@ -1,312 +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/renderer/media/crypto/proxy_decryptor.h"
-
-#include <cstring>
-
-#include "base/bind.h"
-#include "base/callback_helpers.h"
-#include "base/logging.h"
-#include "base/strings/string_util.h"
-#include "media/base/cdm_callback_promise.h"
-#include "media/base/cdm_factory.h"
-#include "media/cdm/json_web_key.h"
-#include "media/cdm/key_system_names.h"
-
-namespace content {
-
-// Special system code to signal a closed persistent session in a SessionError()
-// call. This is needed because there is no SessionClosed() call in the prefixed
-// EME API.
-const int kSessionClosedSystemCode = 29127;
-
-ProxyDecryptor::ProxyDecryptor(const KeyAddedCB& key_added_cb,
- const KeyErrorCB& key_error_cb,
- const KeyMessageCB& key_message_cb)
- : key_added_cb_(key_added_cb),
- key_error_cb_(key_error_cb),
- key_message_cb_(key_message_cb),
- is_clear_key_(false),
- weak_ptr_factory_(this) {
- DCHECK(!key_added_cb_.is_null());
- DCHECK(!key_error_cb_.is_null());
- DCHECK(!key_message_cb_.is_null());
-}
-
-ProxyDecryptor::~ProxyDecryptor() {
- // Destroy the decryptor explicitly before destroying the plugin.
- media_keys_.reset();
-}
-
-media::Decryptor* ProxyDecryptor::GetDecryptor() {
- return media_keys_ ? media_keys_->GetDecryptor() : NULL;
-}
-
-#if defined(ENABLE_BROWSER_CDMS)
-int ProxyDecryptor::GetCdmId() {
- return media_keys_->GetCdmId();
-}
-#endif
-
-bool ProxyDecryptor::InitializeCDM(media::CdmFactory* cdm_factory,
- const std::string& key_system,
- const GURL& security_origin) {
- DVLOG(1) << "InitializeCDM: key_system = " << key_system;
-
- DCHECK(!media_keys_);
- media_keys_ = CreateMediaKeys(cdm_factory, key_system, security_origin);
- if (!media_keys_)
- return false;
-
- is_clear_key_ =
- media::IsClearKey(key_system) || media::IsExternalClearKey(key_system);
- return true;
-}
-
-// Returns true if |data| is prefixed with |header| and has data after the
-// |header|.
-bool HasHeader(const uint8* data, int data_length, const std::string& header) {
- return static_cast<size_t>(data_length) > header.size() &&
- std::equal(data, data + header.size(), header.begin());
-}
-
-// Removes the first |length| items from |data|.
-void StripHeader(std::vector<uint8>& data, size_t length) {
- data.erase(data.begin(), data.begin() + length);
-}
-
-bool ProxyDecryptor::GenerateKeyRequest(const std::string& init_data_type,
- const uint8* init_data,
- int init_data_length) {
- DVLOG(1) << "GenerateKeyRequest()";
- const char kPrefixedApiPersistentSessionHeader[] = "PERSISTENT|";
- const char kPrefixedApiLoadSessionHeader[] = "LOAD_SESSION|";
-
- SessionCreationType session_creation_type = TemporarySession;
- std::vector<uint8> init_data_vector(init_data, init_data + init_data_length);
- if (HasHeader(init_data, init_data_length, kPrefixedApiLoadSessionHeader)) {
- session_creation_type = LoadSession;
- StripHeader(init_data_vector, strlen(kPrefixedApiLoadSessionHeader));
- } else if (HasHeader(init_data,
- init_data_length,
- kPrefixedApiPersistentSessionHeader)) {
- session_creation_type = PersistentSession;
- StripHeader(init_data_vector, strlen(kPrefixedApiPersistentSessionHeader));
- }
-
- scoped_ptr<media::NewSessionCdmPromise> promise(
- new media::CdmCallbackPromise<std::string>(
- base::Bind(&ProxyDecryptor::SetSessionId,
- weak_ptr_factory_.GetWeakPtr(),
- session_creation_type),
- base::Bind(&ProxyDecryptor::OnSessionError,
- weak_ptr_factory_.GetWeakPtr(),
- std::string()))); // No session id until created.
- uint8* init_data_vector_data =
- (init_data_vector.size() > 0) ? &init_data_vector[0] : nullptr;
-
- if (session_creation_type == LoadSession) {
- media_keys_->LoadSession(
- std::string(reinterpret_cast<const char*>(init_data_vector_data),
- init_data_vector.size()),
- promise.Pass());
- return true;
- }
-
- media::MediaKeys::SessionType session_type =
- session_creation_type == PersistentSession
- ? media::MediaKeys::PERSISTENT_SESSION
- : media::MediaKeys::TEMPORARY_SESSION;
-
- media_keys_->CreateSession(init_data_type,
- init_data_vector_data,
- init_data_vector.size(),
- session_type,
- promise.Pass());
- return true;
-}
-
-void ProxyDecryptor::AddKey(const uint8* key,
- int key_length,
- const uint8* init_data,
- int init_data_length,
- const std::string& web_session_id) {
- DVLOG(1) << "AddKey()";
-
- // In the prefixed API, the session parameter provided to addKey() is
- // optional, so use the single existing session if it exists.
- // TODO(jrummell): remove when the prefixed API is removed.
- std::string session_id(web_session_id);
- if (session_id.empty()) {
- if (active_sessions_.size() == 1) {
- base::hash_map<std::string, bool>::iterator it = active_sessions_.begin();
- session_id = it->first;
- } else {
- OnSessionError(std::string(),
- media::MediaKeys::NOT_SUPPORTED_ERROR,
- 0,
- "SessionId not specified.");
- return;
- }
- }
-
- scoped_ptr<media::SimpleCdmPromise> promise(new media::CdmCallbackPromise<>(
- base::Bind(&ProxyDecryptor::OnSessionReady,
- weak_ptr_factory_.GetWeakPtr(),
- web_session_id),
- base::Bind(&ProxyDecryptor::OnSessionError,
- weak_ptr_factory_.GetWeakPtr(),
- web_session_id)));
-
- // EME WD spec only supports a single array passed to the CDM. For
- // Clear Key using v0.1b, both arrays are used (|init_data| is key_id).
- // Since the EME WD spec supports the key as a JSON Web Key,
- // convert the 2 arrays to a JWK and pass it as the single array.
- if (is_clear_key_) {
- // Decryptor doesn't support empty key ID (see http://crbug.com/123265).
- // So ensure a non-empty value is passed.
- if (!init_data) {
- static const uint8 kDummyInitData[1] = {0};
- init_data = kDummyInitData;
- init_data_length = arraysize(kDummyInitData);
- }
-
- std::string jwk =
- media::GenerateJWKSet(key, key_length, init_data, init_data_length);
- DCHECK(!jwk.empty());
- media_keys_->UpdateSession(session_id,
- reinterpret_cast<const uint8*>(jwk.data()),
- jwk.size(),
- promise.Pass());
- return;
- }
-
- media_keys_->UpdateSession(session_id, key, key_length, promise.Pass());
-}
-
-void ProxyDecryptor::CancelKeyRequest(const std::string& web_session_id) {
- DVLOG(1) << "CancelKeyRequest()";
-
- scoped_ptr<media::SimpleCdmPromise> promise(new media::CdmCallbackPromise<>(
- base::Bind(&ProxyDecryptor::OnSessionClosed,
- weak_ptr_factory_.GetWeakPtr(),
- web_session_id),
- base::Bind(&ProxyDecryptor::OnSessionError,
- weak_ptr_factory_.GetWeakPtr(),
- web_session_id)));
- media_keys_->RemoveSession(web_session_id, promise.Pass());
-}
-
-scoped_ptr<media::MediaKeys> ProxyDecryptor::CreateMediaKeys(
- media::CdmFactory* cdm_factory,
- const std::string& key_system,
- const GURL& security_origin) {
- base::WeakPtr<ProxyDecryptor> weak_this = weak_ptr_factory_.GetWeakPtr();
- return cdm_factory->Create(
- key_system,
- security_origin,
- base::Bind(&ProxyDecryptor::OnSessionMessage, weak_this),
- base::Bind(&ProxyDecryptor::OnSessionReady, weak_this),
- base::Bind(&ProxyDecryptor::OnSessionClosed, weak_this),
- base::Bind(&ProxyDecryptor::OnSessionError, weak_this),
- base::Bind(&ProxyDecryptor::OnSessionKeysChange, weak_this),
- base::Bind(&ProxyDecryptor::OnSessionExpirationUpdate, weak_this));
-}
-
-void ProxyDecryptor::OnSessionMessage(const std::string& web_session_id,
- const std::vector<uint8>& message,
- const GURL& destination_url) {
- // Assumes that OnSessionCreated() has been called before this.
-
- // For ClearKey, convert the message from JSON into just passing the key
- // as the message. If unable to extract the key, return the message unchanged.
- if (is_clear_key_) {
- std::vector<uint8> key;
- if (media::ExtractFirstKeyIdFromLicenseRequest(message, &key)) {
- key_message_cb_.Run(web_session_id, key, destination_url);
- return;
- }
- }
-
- key_message_cb_.Run(web_session_id, message, destination_url);
-}
-
-void ProxyDecryptor::OnSessionKeysChange(const std::string& web_session_id,
- bool has_additional_usable_key) {
- // EME v0.1b doesn't support this event.
-}
-
-void ProxyDecryptor::OnSessionExpirationUpdate(
- const std::string& web_session_id,
- const base::Time& new_expiry_time) {
- // EME v0.1b doesn't support this event.
-}
-
-void ProxyDecryptor::OnSessionReady(const std::string& web_session_id) {
- key_added_cb_.Run(web_session_id);
-}
-
-void ProxyDecryptor::OnSessionClosed(const std::string& web_session_id) {
- base::hash_map<std::string, bool>::iterator it =
- active_sessions_.find(web_session_id);
-
- // Latest EME spec separates closing a session ("allows an application to
- // indicate that it no longer needs the session") and actually closing the
- // session (done by the CDM at any point "such as in response to a close()
- // call, when the session is no longer needed, or when system resources are
- // lost.") Thus the CDM may cause 2 close() events -- one to resolve the
- // close() promise, and a second to actually close the session. Prefixed EME
- // only expects 1 close event, so drop the second (and subsequent) events.
- // However, this means we can't tell if the CDM is generating spurious close()
- // events.
- if (it == active_sessions_.end())
- return;
-
- if (it->second) {
- OnSessionError(web_session_id,
- media::MediaKeys::NOT_SUPPORTED_ERROR,
- kSessionClosedSystemCode,
- "Do not close persistent sessions.");
- }
- active_sessions_.erase(it);
-}
-
-void ProxyDecryptor::OnSessionError(const std::string& web_session_id,
- media::MediaKeys::Exception exception_code,
- uint32 system_code,
- const std::string& error_message) {
- // Convert |error_name| back to MediaKeys::KeyError if possible. Prefixed
- // EME has different error message, so all the specific error events will
- // get lost.
- media::MediaKeys::KeyError error_code;
- switch (exception_code) {
- case media::MediaKeys::CLIENT_ERROR:
- error_code = media::MediaKeys::kClientError;
- break;
- case media::MediaKeys::OUTPUT_ERROR:
- error_code = media::MediaKeys::kOutputError;
- break;
- default:
- // This will include all other CDM4 errors and any error generated
- // by CDM5 or later.
- error_code = media::MediaKeys::kUnknownError;
- break;
- }
- key_error_cb_.Run(web_session_id, error_code, system_code);
-}
-
-void ProxyDecryptor::SetSessionId(SessionCreationType session_type,
- const std::string& web_session_id) {
- // Loaded sessions are considered persistent.
- bool is_persistent =
- session_type == PersistentSession || session_type == LoadSession;
- active_sessions_.insert(std::make_pair(web_session_id, is_persistent));
-
- // For LoadSession(), generate the SessionReady event.
- if (session_type == LoadSession)
- OnSessionReady(web_session_id);
-}
-
-} // namespace content
diff --git a/chromium/content/renderer/media/crypto/proxy_decryptor.h b/chromium/content/renderer/media/crypto/proxy_decryptor.h
deleted file mode 100644
index 62f2e8eb884..00000000000
--- a/chromium/content/renderer/media/crypto/proxy_decryptor.h
+++ /dev/null
@@ -1,131 +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_RENDERER_MEDIA_CRYPTO_PROXY_DECRYPTOR_H_
-#define CONTENT_RENDERER_MEDIA_CRYPTO_PROXY_DECRYPTOR_H_
-
-#include <string>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/containers/hash_tables.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "media/base/decryptor.h"
-#include "media/base/media_keys.h"
-
-class GURL;
-
-namespace media {
-class CdmFactory;
-}
-
-namespace content {
-
-// ProxyDecryptor is for EME v0.1b only. It should not be used for the WD API.
-// A decryptor proxy that creates a real decryptor object on demand and
-// forwards decryptor calls to it.
-//
-// TODO(xhwang): Currently we don't support run-time switching among decryptor
-// objects. Fix this when needed.
-// TODO(xhwang): The ProxyDecryptor is not a Decryptor. Find a better name!
-class ProxyDecryptor {
- public:
- // These are similar to the callbacks in media_keys.h, but pass back the
- // web session ID rather than the internal session ID.
- typedef base::Callback<void(const std::string& session_id)> KeyAddedCB;
- typedef base::Callback<void(const std::string& session_id,
- media::MediaKeys::KeyError error_code,
- uint32 system_code)> KeyErrorCB;
- typedef base::Callback<void(const std::string& session_id,
- const std::vector<uint8>& message,
- const GURL& destination_url)> KeyMessageCB;
-
- ProxyDecryptor(const KeyAddedCB& key_added_cb,
- const KeyErrorCB& key_error_cb,
- const KeyMessageCB& key_message_cb);
- virtual ~ProxyDecryptor();
-
- // Returns the Decryptor associated with this object. May be NULL if no
- // Decryptor is associated.
- media::Decryptor* GetDecryptor();
-
-#if defined(ENABLE_BROWSER_CDMS)
- // Returns the CDM ID associated with this object. May be kInvalidCdmId if no
- // CDM ID is associated, such as when Clear Key is used.
- int GetCdmId();
-#endif
-
- // Only call this once.
- bool InitializeCDM(media::CdmFactory* cdm_factory,
- const std::string& key_system,
- const GURL& security_origin);
-
- // May only be called after InitializeCDM() succeeds.
- bool GenerateKeyRequest(const std::string& init_data_type,
- const uint8* init_data,
- int init_data_length);
- void AddKey(const uint8* key, int key_length,
- const uint8* init_data, int init_data_length,
- const std::string& session_id);
- void CancelKeyRequest(const std::string& session_id);
-
- private:
- // Helper function to create MediaKeys to handle the given |key_system|.
- scoped_ptr<media::MediaKeys> CreateMediaKeys(
- media::CdmFactory* cdm_factory,
- const std::string& key_system,
- const GURL& security_origin);
-
- // Callbacks for firing session events.
- void OnSessionMessage(const std::string& web_session_id,
- const std::vector<uint8>& message,
- const GURL& default_url);
- void OnSessionKeysChange(const std::string& web_session_id,
- bool has_additional_usable_key);
- void OnSessionExpirationUpdate(const std::string& web_session_id,
- const base::Time& new_expiry_time);
- void OnSessionReady(const std::string& web_session_id);
- void OnSessionClosed(const std::string& web_session_id);
- void OnSessionError(const std::string& web_session_id,
- media::MediaKeys::Exception exception_code,
- uint32 system_code,
- const std::string& error_message);
-
- enum SessionCreationType {
- TemporarySession,
- PersistentSession,
- LoadSession
- };
-
- // Called when a session is actually created or loaded.
- void SetSessionId(SessionCreationType session_type,
- const std::string& web_session_id);
-
- // The real MediaKeys that manages key operations for the ProxyDecryptor.
- scoped_ptr<media::MediaKeys> media_keys_;
-
- // Callbacks for firing key events.
- KeyAddedCB key_added_cb_;
- KeyErrorCB key_error_cb_;
- KeyMessageCB key_message_cb_;
-
- // Keep track of both persistent and non-persistent sessions.
- base::hash_map<std::string, bool> active_sessions_;
-
- bool is_clear_key_;
-
-#if defined(ENABLE_BROWSER_CDMS)
- int cdm_id_;
-#endif
-
- // NOTE: Weak pointers must be invalidated before all other member variables.
- base::WeakPtrFactory<ProxyDecryptor> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(ProxyDecryptor);
-};
-
-} // namespace content
-
-#endif // CONTENT_RENDERER_MEDIA_CRYPTO_PROXY_DECRYPTOR_H_
diff --git a/chromium/content/renderer/media/crypto/proxy_media_keys.cc b/chromium/content/renderer/media/crypto/proxy_media_keys.cc
index e62c6cea1fd..4092324d661 100644
--- a/chromium/content/renderer/media/crypto/proxy_media_keys.cc
+++ b/chromium/content/renderer/media/crypto/proxy_media_keys.cc
@@ -9,287 +9,207 @@
#include "base/basictypes.h"
#include "base/logging.h"
#include "base/stl_util.h"
-#include "content/renderer/media/crypto/key_systems.h"
+#include "content/renderer/media/crypto/cdm_initialized_promise.h"
#include "content/renderer/media/crypto/renderer_cdm_manager.h"
+#include "media/base/cdm_key_information.h"
#include "media/base/cdm_promise.h"
+#include "media/base/key_systems.h"
namespace content {
-scoped_ptr<ProxyMediaKeys> ProxyMediaKeys::Create(
+void ProxyMediaKeys::Create(
const std::string& key_system,
const GURL& security_origin,
+ bool use_hw_secure_codecs,
RendererCdmManager* manager,
const media::SessionMessageCB& session_message_cb,
- const media::SessionReadyCB& session_ready_cb,
const media::SessionClosedCB& session_closed_cb,
- const media::SessionErrorCB& session_error_cb,
+ const media::LegacySessionErrorCB& legacy_session_error_cb,
const media::SessionKeysChangeCB& session_keys_change_cb,
- const media::SessionExpirationUpdateCB& session_expiration_update_cb) {
+ const media::SessionExpirationUpdateCB& session_expiration_update_cb,
+ const media::CdmCreatedCB& cdm_created_cb) {
DCHECK(manager);
+ scoped_ptr<ProxyMediaKeys> proxy_media_keys(new ProxyMediaKeys(
+ manager, session_message_cb, session_closed_cb, legacy_session_error_cb,
+ session_keys_change_cb, session_expiration_update_cb));
- // TODO(jrummell): Add support for SessionKeysChangeCB and
- // SessionExpirationUpdateCB.
- scoped_ptr<ProxyMediaKeys> proxy_media_keys(
- new ProxyMediaKeys(manager,
- session_message_cb,
- session_ready_cb,
- session_closed_cb,
- session_error_cb));
- proxy_media_keys->InitializeCdm(key_system, security_origin);
- return proxy_media_keys.Pass();
+ // ProxyMediaKeys ownership passed to the promise, but keep a copy in order
+ // to call InitializeCdm().
+ ProxyMediaKeys* proxy_media_keys_copy = proxy_media_keys.get();
+ scoped_ptr<CdmInitializedPromise> promise(
+ new CdmInitializedPromise(cdm_created_cb, proxy_media_keys.Pass()));
+ proxy_media_keys_copy->InitializeCdm(key_system, security_origin,
+ use_hw_secure_codecs, promise.Pass());
}
ProxyMediaKeys::~ProxyMediaKeys() {
manager_->DestroyCdm(cdm_id_);
manager_->UnregisterMediaKeys(cdm_id_);
-
- // Reject any outstanding promises.
- for (PromiseMap::iterator it = session_id_to_promise_map_.begin();
- it != session_id_to_promise_map_.end();
- ++it) {
- it->second->reject(
- media::MediaKeys::NOT_SUPPORTED_ERROR, 0, "The operation was aborted.");
- }
- session_id_to_promise_map_.clear();
+ cdm_promise_adapter_.Clear();
}
void ProxyMediaKeys::SetServerCertificate(
- const uint8* certificate_data,
- int certificate_data_length,
+ const std::vector<uint8_t>& certificate,
scoped_ptr<media::SimpleCdmPromise> promise) {
- promise->reject(NOT_SUPPORTED_ERROR, 0, "Not yet implemented.");
+ uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
+ manager_->SetServerCertificate(cdm_id_, promise_id, certificate);
}
-void ProxyMediaKeys::CreateSession(
- const std::string& init_data_type,
- const uint8* init_data,
- int init_data_length,
+void ProxyMediaKeys::CreateSessionAndGenerateRequest(
SessionType session_type,
+ media::EmeInitDataType init_data_type,
+ const std::vector<uint8_t>& init_data,
scoped_ptr<media::NewSessionCdmPromise> promise) {
+ if (session_type != media::MediaKeys::TEMPORARY_SESSION) {
+ promise->reject(NOT_SUPPORTED_ERROR, 0,
+ "Only the temporary session type is supported.");
+ return;
+ }
+
// TODO(xhwang): Move these checks up to blink and DCHECK here.
// See http://crbug.com/342510
- CdmHostMsg_CreateSession_ContentType create_session_content_type;
- if (init_data_type == "cenc") {
- create_session_content_type = CREATE_SESSION_TYPE_MP4;
- } else if (init_data_type == "webm") {
- create_session_content_type = CREATE_SESSION_TYPE_WEBM;
- } else {
- DLOG(ERROR) << "Unsupported EME CreateSession content type of "
- << init_data_type;
- promise->reject(
- NOT_SUPPORTED_ERROR,
- 0,
- "Unsupported EME CreateSession init data type of " + init_data_type);
- return;
+ CdmHostMsg_CreateSession_InitDataType create_session_init_data_type =
+ INIT_DATA_TYPE_WEBM;
+ switch (init_data_type) {
+ case media::EmeInitDataType::CENC:
+ create_session_init_data_type = INIT_DATA_TYPE_CENC;
+ break;
+ case media::EmeInitDataType::WEBM:
+ create_session_init_data_type = INIT_DATA_TYPE_WEBM;
+ break;
+ case media::EmeInitDataType::KEYIDS:
+ case media::EmeInitDataType::UNKNOWN:
+ DLOG(ERROR) << "Unsupported EME CreateSession init data type";
+ promise->reject(NOT_SUPPORTED_ERROR, 0,
+ "Unsupported EME CreateSession init data type");
+ return;
}
- uint32 session_id = CreateSessionId();
- SavePromise(session_id, promise.Pass());
- manager_->CreateSession(
- cdm_id_,
- session_id,
- create_session_content_type,
- std::vector<uint8>(init_data, init_data + init_data_length));
+ uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
+ manager_->CreateSessionAndGenerateRequest(
+ cdm_id_, promise_id, create_session_init_data_type, init_data);
}
void ProxyMediaKeys::LoadSession(
- const std::string& web_session_id,
+ SessionType session_type,
+ const std::string& session_id,
scoped_ptr<media::NewSessionCdmPromise> promise) {
// TODO(xhwang): Check key system and platform support for LoadSession in
- // blink and add NOTREACHED() here.
+ // blink and add NOTREACHED() here. See http://crbug.com/384152
DLOG(ERROR) << "ProxyMediaKeys doesn't support session loading.";
promise->reject(NOT_SUPPORTED_ERROR, 0, "LoadSession() is not supported.");
}
void ProxyMediaKeys::UpdateSession(
- const std::string& web_session_id,
- const uint8* response,
- int response_length,
+ const std::string& session_id,
+ const std::vector<uint8_t>& response,
scoped_ptr<media::SimpleCdmPromise> promise) {
- uint32 session_id = LookupSessionId(web_session_id);
- if (!session_id) {
- promise->reject(INVALID_ACCESS_ERROR, 0, "Session does not exist.");
- return;
- }
-
- SavePromise(session_id, promise.Pass());
- manager_->UpdateSession(
- cdm_id_,
- session_id,
- std::vector<uint8>(response, response + response_length));
+ uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
+ manager_->UpdateSession(cdm_id_, promise_id, session_id, response);
}
-void ProxyMediaKeys::CloseSession(const std::string& web_session_id,
+void ProxyMediaKeys::CloseSession(const std::string& session_id,
scoped_ptr<media::SimpleCdmPromise> promise) {
- uint32 session_id = LookupSessionId(web_session_id);
- if (!session_id) {
- promise->reject(INVALID_ACCESS_ERROR, 0, "Session does not exist.");
- return;
- }
-
- SavePromise(session_id, promise.Pass());
- manager_->ReleaseSession(cdm_id_, session_id);
+ uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
+ manager_->CloseSession(cdm_id_, promise_id, session_id);
}
void ProxyMediaKeys::RemoveSession(
- const std::string& web_session_id,
+ const std::string& session_id,
scoped_ptr<media::SimpleCdmPromise> promise) {
- promise->reject(NOT_SUPPORTED_ERROR, 0, "Not yet implemented.");
+ // TODO(xhwang): Check key system and platform support for LoadSession in
+ // blink and add NOTREACHED() here. See http://crbug.com/384152
+ promise->reject(NOT_SUPPORTED_ERROR, 0, "RemoveSession() not supported.");
}
-void ProxyMediaKeys::GetUsableKeyIds(const std::string& web_session_id,
- scoped_ptr<media::KeyIdsPromise> promise) {
- promise->reject(NOT_SUPPORTED_ERROR, 0, "Not yet implemented.");
+media::CdmContext* ProxyMediaKeys::GetCdmContext() {
+ return this;
+}
+
+media::Decryptor* ProxyMediaKeys::GetDecryptor() {
+ return nullptr;
}
int ProxyMediaKeys::GetCdmId() const {
return cdm_id_;
}
-void ProxyMediaKeys::OnSessionCreated(uint32 session_id,
- const std::string& web_session_id) {
- AssignWebSessionId(session_id, web_session_id);
- scoped_ptr<media::CdmPromise> promise = TakePromise(session_id);
- if (promise) {
- media::NewSessionCdmPromise* session_promise(
- static_cast<media::NewSessionCdmPromise*>(promise.get()));
- session_promise->resolve(web_session_id);
- }
+void ProxyMediaKeys::OnSessionMessage(
+ const std::string& session_id,
+ media::MediaKeys::MessageType message_type,
+ const std::vector<uint8_t>& message,
+ const GURL& legacy_destination_url) {
+ session_message_cb_.Run(session_id, message_type, message,
+ legacy_destination_url);
}
-void ProxyMediaKeys::OnSessionMessage(uint32 session_id,
- const std::vector<uint8>& message,
- const GURL& destination_url) {
- session_message_cb_.Run(
- LookupWebSessionId(session_id), message, destination_url);
+void ProxyMediaKeys::OnSessionClosed(const std::string& session_id) {
+ session_closed_cb_.Run(session_id);
}
-void ProxyMediaKeys::OnSessionReady(uint32 session_id) {
- scoped_ptr<media::CdmPromise> promise = TakePromise(session_id);
- if (promise) {
- media::SimpleCdmPromise* simple_promise(
- static_cast<media::SimpleCdmPromise*>(promise.get()));
- simple_promise->resolve();
- } else {
- // Still needed for keyadded.
- const std::string web_session_id = LookupWebSessionId(session_id);
- session_ready_cb_.Run(web_session_id);
- }
+void ProxyMediaKeys::OnLegacySessionError(const std::string& session_id,
+ media::MediaKeys::Exception exception,
+ uint32_t system_code,
+ const std::string& error_message) {
+ legacy_session_error_cb_.Run(session_id, exception, system_code,
+ error_message);
}
-void ProxyMediaKeys::OnSessionClosed(uint32 session_id) {
- const std::string web_session_id = LookupWebSessionId(session_id);
- DropWebSessionId(web_session_id);
- scoped_ptr<media::CdmPromise> promise = TakePromise(session_id);
- if (promise) {
- media::SimpleCdmPromise* simple_promise(
- static_cast<media::SimpleCdmPromise*>(promise.get()));
- simple_promise->resolve();
- } else {
- // It is possible for the CDM to close a session independent of a
- // Release() request.
- session_closed_cb_.Run(web_session_id);
- }
+void ProxyMediaKeys::OnSessionKeysChange(const std::string& session_id,
+ bool has_additional_usable_key,
+ media::CdmKeysInfo keys_info) {
+ session_keys_change_cb_.Run(session_id, has_additional_usable_key,
+ keys_info.Pass());
}
-void ProxyMediaKeys::OnSessionError(uint32 session_id,
- media::MediaKeys::KeyError error_code,
- uint32 system_code) {
- const std::string web_session_id = LookupWebSessionId(session_id);
- media::MediaKeys::Exception exception_code;
- switch (error_code) {
- case media::MediaKeys::kClientError:
- exception_code = media::MediaKeys::CLIENT_ERROR;
- break;
- case media::MediaKeys::kOutputError:
- exception_code = media::MediaKeys::OUTPUT_ERROR;
- break;
- case media::MediaKeys::kUnknownError:
- default:
- exception_code = media::MediaKeys::UNKNOWN_ERROR;
- break;
- }
+void ProxyMediaKeys::OnSessionExpirationUpdate(
+ const std::string& session_id,
+ const base::Time& new_expiry_time) {
+ session_expiration_update_cb_.Run(session_id, new_expiry_time);
+}
- scoped_ptr<media::CdmPromise> promise = TakePromise(session_id);
- if (promise) {
- promise->reject(exception_code, system_code, std::string());
- return;
- }
+void ProxyMediaKeys::OnPromiseResolved(uint32_t promise_id) {
+ cdm_promise_adapter_.ResolvePromise(promise_id);
+}
- // Errors generally happen in response to a request, but it is possible
- // for something bad to happen in the CDM and it needs to tell the client.
- session_error_cb_.Run(
- web_session_id, exception_code, system_code, std::string());
+void ProxyMediaKeys::OnPromiseResolvedWithSession(
+ uint32_t promise_id,
+ const std::string& session_id) {
+ cdm_promise_adapter_.ResolvePromise(promise_id, session_id);
+}
+
+void ProxyMediaKeys::OnPromiseRejected(uint32_t promise_id,
+ media::MediaKeys::Exception exception,
+ uint32_t system_code,
+ const std::string& error_message) {
+ cdm_promise_adapter_.RejectPromise(promise_id, exception, system_code,
+ error_message);
}
ProxyMediaKeys::ProxyMediaKeys(
RendererCdmManager* manager,
const media::SessionMessageCB& session_message_cb,
- const media::SessionReadyCB& session_ready_cb,
const media::SessionClosedCB& session_closed_cb,
- const media::SessionErrorCB& session_error_cb)
+ const media::LegacySessionErrorCB& legacy_session_error_cb,
+ const media::SessionKeysChangeCB& session_keys_change_cb,
+ const media::SessionExpirationUpdateCB& session_expiration_update_cb)
: manager_(manager),
session_message_cb_(session_message_cb),
- session_ready_cb_(session_ready_cb),
session_closed_cb_(session_closed_cb),
- session_error_cb_(session_error_cb),
- next_session_id_(1) {
+ legacy_session_error_cb_(legacy_session_error_cb),
+ session_keys_change_cb_(session_keys_change_cb),
+ session_expiration_update_cb_(session_expiration_update_cb) {
cdm_id_ = manager->RegisterMediaKeys(this);
}
-void ProxyMediaKeys::InitializeCdm(const std::string& key_system,
- const GURL& security_origin) {
- manager_->InitializeCdm(cdm_id_, this, key_system, security_origin);
-}
-
-uint32_t ProxyMediaKeys::CreateSessionId() {
- return next_session_id_++;
-}
-
-void ProxyMediaKeys::AssignWebSessionId(uint32_t session_id,
- const std::string& web_session_id) {
- DCHECK(!ContainsKey(web_session_to_session_id_map_, web_session_id));
- DCHECK(session_id);
- web_session_to_session_id_map_.insert(
- std::make_pair(web_session_id, session_id));
-}
-
-uint32_t ProxyMediaKeys::LookupSessionId(
- const std::string& web_session_id) const {
- SessionIdMap::const_iterator it =
- web_session_to_session_id_map_.find(web_session_id);
- return (it != web_session_to_session_id_map_.end()) ? it->second : 0;
-}
-
-std::string ProxyMediaKeys::LookupWebSessionId(uint32_t session_id) const {
- for (SessionIdMap::const_iterator it = web_session_to_session_id_map_.begin();
- it != web_session_to_session_id_map_.end();
- ++it) {
- if (it->second == session_id)
- return it->first;
- }
- // Possible to get an error creating a session, so no |web_session_id|
- // available.
- return std::string();
-}
-
-void ProxyMediaKeys::DropWebSessionId(const std::string& web_session_id) {
- web_session_to_session_id_map_.erase(web_session_id);
-}
-
-void ProxyMediaKeys::SavePromise(uint32_t session_id,
- scoped_ptr<media::CdmPromise> promise) {
- // Should only be one promise outstanding for any |session_id|.
- DCHECK(!ContainsKey(session_id_to_promise_map_, session_id));
- session_id_to_promise_map_.add(session_id, promise.Pass());
-}
-
-scoped_ptr<media::CdmPromise> ProxyMediaKeys::TakePromise(uint32_t session_id) {
- PromiseMap::iterator it = session_id_to_promise_map_.find(session_id);
- // May not be a promise associated with this session for asynchronous events.
- if (it == session_id_to_promise_map_.end())
- return scoped_ptr<media::CdmPromise>();
- return session_id_to_promise_map_.take_and_erase(it);
+void ProxyMediaKeys::InitializeCdm(
+ const std::string& key_system,
+ const GURL& security_origin,
+ bool use_hw_secure_codecs,
+ scoped_ptr<media::SimpleCdmPromise> promise) {
+ uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
+ manager_->InitializeCdm(cdm_id_, promise_id, this, key_system,
+ security_origin, use_hw_secure_codecs);
}
} // namespace content
diff --git a/chromium/content/renderer/media/crypto/proxy_media_keys.h b/chromium/content/renderer/media/crypto/proxy_media_keys.h
index 6b4df648276..b256dfa5e29 100644
--- a/chromium/content/renderer/media/crypto/proxy_media_keys.h
+++ b/chromium/content/renderer/media/crypto/proxy_media_keys.h
@@ -7,11 +7,15 @@
#include <map>
#include <string>
+#include <vector>
#include "base/basictypes.h"
#include "base/containers/hash_tables.h"
#include "base/containers/scoped_ptr_hash_map.h"
+#include "media/base/cdm_context.h"
+#include "media/base/cdm_factory.h"
#include "media/base/cdm_promise.h"
+#include "media/base/cdm_promise_adapter.h"
#include "media/base/media_keys.h"
class GURL;
@@ -21,114 +25,95 @@ namespace content {
class RendererCdmManager;
// A MediaKeys proxy that wraps the EME part of RendererCdmManager.
-class ProxyMediaKeys : public media::MediaKeys {
+class ProxyMediaKeys : public media::MediaKeys, public media::CdmContext {
public:
- static scoped_ptr<ProxyMediaKeys> Create(
+ static void Create(
const std::string& key_system,
const GURL& security_origin,
+ bool use_hw_secure_codecs,
RendererCdmManager* manager,
const media::SessionMessageCB& session_message_cb,
- const media::SessionReadyCB& session_ready_cb,
const media::SessionClosedCB& session_closed_cb,
- const media::SessionErrorCB& session_error_cb,
+ const media::LegacySessionErrorCB& legacy_session_error_cb,
const media::SessionKeysChangeCB& session_keys_change_cb,
- const media::SessionExpirationUpdateCB& session_expiration_update_cb);
+ const media::SessionExpirationUpdateCB& session_expiration_update_cb,
+ const media::CdmCreatedCB& cdm_created_cb);
- virtual ~ProxyMediaKeys();
+ ~ProxyMediaKeys() override;
// MediaKeys implementation.
- virtual void SetServerCertificate(
- const uint8* certificate_data,
- int certificate_data_length,
+ void SetServerCertificate(
+ const std::vector<uint8_t>& certificate,
scoped_ptr<media::SimpleCdmPromise> promise) override;
- virtual void CreateSession(
- const std::string& init_data_type,
- const uint8* init_data,
- int init_data_length,
+ void CreateSessionAndGenerateRequest(
SessionType session_type,
+ media::EmeInitDataType init_data_type,
+ const std::vector<uint8_t>& init_data,
scoped_ptr<media::NewSessionCdmPromise> promise) override;
- virtual void LoadSession(
- const std::string& web_session_id,
- scoped_ptr<media::NewSessionCdmPromise> promise) override;
- virtual void UpdateSession(
- const std::string& web_session_id,
- const uint8* response,
- int response_length,
- scoped_ptr<media::SimpleCdmPromise> promise) override;
- virtual void CloseSession(
- const std::string& web_session_id,
- scoped_ptr<media::SimpleCdmPromise> promise) override;
- virtual void RemoveSession(
- const std::string& web_session_id,
- scoped_ptr<media::SimpleCdmPromise> promise) override;
- virtual void GetUsableKeyIds(
- const std::string& web_session_id,
- scoped_ptr<media::KeyIdsPromise> promise) override;
- virtual int GetCdmId() const override;
+ void LoadSession(SessionType session_type,
+ const std::string& session_id,
+ scoped_ptr<media::NewSessionCdmPromise> promise) override;
+ void UpdateSession(const std::string& session_id,
+ const std::vector<uint8_t>& response,
+ scoped_ptr<media::SimpleCdmPromise> promise) override;
+ void CloseSession(const std::string& session_id,
+ scoped_ptr<media::SimpleCdmPromise> promise) override;
+ void RemoveSession(const std::string& session_id,
+ scoped_ptr<media::SimpleCdmPromise> promise) override;
+ media::CdmContext* GetCdmContext() override;
+
+ // media::CdmContext implementation.
+ media::Decryptor* GetDecryptor() override;
+ int GetCdmId() const override;
// Callbacks.
- void OnSessionCreated(uint32 session_id, const std::string& web_session_id);
- void OnSessionMessage(uint32 session_id,
- const std::vector<uint8>& message,
- const GURL& destination_url);
- void OnSessionReady(uint32 session_id);
- void OnSessionClosed(uint32 session_id);
- void OnSessionError(uint32 session_id,
- media::MediaKeys::KeyError error_code,
- uint32 system_code);
+ void OnSessionMessage(const std::string& session_id,
+ media::MediaKeys::MessageType message_type,
+ const std::vector<uint8_t>& message,
+ const GURL& legacy_destination_url);
+ void OnSessionClosed(const std::string& session_id);
+ void OnLegacySessionError(const std::string& session_id,
+ media::MediaKeys::Exception exception,
+ uint32_t system_code,
+ const std::string& error_message);
+ void OnSessionKeysChange(const std::string& session_id,
+ bool has_additional_usable_key,
+ media::CdmKeysInfo keys_info);
+ void OnSessionExpirationUpdate(const std::string& session_id,
+ const base::Time& new_expiry_time);
+
+ void OnPromiseResolved(uint32_t promise_id);
+ void OnPromiseResolvedWithSession(uint32_t promise_id,
+ const std::string& session_id);
+ void OnPromiseRejected(uint32_t promise_id,
+ media::MediaKeys::Exception exception,
+ uint32_t system_code,
+ const std::string& error_message);
private:
- // The Android-specific code that handles sessions uses integer session ids
- // (basically a reference id), but media::MediaKeys bases everything on
- // web_session_id (a string representing the actual session id as generated
- // by the CDM). SessionIdMap is used to map between the web_session_id and
- // the session_id used by the Android-specific code.
- typedef base::hash_map<std::string, uint32_t> SessionIdMap;
-
- // The following types keep track of Promises. The index is the
- // Android-specific session_id, so that returning results can be matched to
- // the corresponding promise.
- typedef base::ScopedPtrHashMap<uint32_t, media::CdmPromise> PromiseMap;
-
- ProxyMediaKeys(RendererCdmManager* manager,
- const media::SessionMessageCB& session_message_cb,
- const media::SessionReadyCB& session_ready_cb,
- const media::SessionClosedCB& session_closed_cb,
- const media::SessionErrorCB& session_error_cb);
+ ProxyMediaKeys(
+ RendererCdmManager* manager,
+ const media::SessionMessageCB& session_message_cb,
+ const media::SessionClosedCB& session_closed_cb,
+ const media::LegacySessionErrorCB& legacy_session_error_cb,
+ const media::SessionKeysChangeCB& session_keys_change_cb,
+ const media::SessionExpirationUpdateCB& session_expiration_update_cb);
void InitializeCdm(const std::string& key_system,
- const GURL& security_origin);
-
- // These functions keep track of Android-specific session_ids <->
- // web_session_ids mappings.
- // TODO(jrummell): Remove this once the Android-specific code changes to
- // support string web session ids.
- uint32_t CreateSessionId();
- void AssignWebSessionId(uint32_t session_id,
- const std::string& web_session_id);
- uint32_t LookupSessionId(const std::string& web_session_id) const;
- std::string LookupWebSessionId(uint32_t session_id) const;
- void DropWebSessionId(const std::string& web_session_id);
-
- // Helper function to keep track of promises. Adding takes ownership of the
- // promise, transferred back to caller on take.
- void SavePromise(uint32_t session_id, scoped_ptr<media::CdmPromise> promise);
- scoped_ptr<media::CdmPromise> TakePromise(uint32_t session_id);
+ const GURL& security_origin,
+ bool use_hw_secure_codecs,
+ scoped_ptr<media::SimpleCdmPromise> promise);
RendererCdmManager* manager_;
int cdm_id_;
media::SessionMessageCB session_message_cb_;
- media::SessionReadyCB session_ready_cb_;
media::SessionClosedCB session_closed_cb_;
- media::SessionErrorCB session_error_cb_;
-
- // Android-specific. See comment above CreateSessionId().
- uint32_t next_session_id_;
- SessionIdMap web_session_to_session_id_map_;
+ media::LegacySessionErrorCB legacy_session_error_cb_;
+ media::SessionKeysChangeCB session_keys_change_cb_;
+ media::SessionExpirationUpdateCB session_expiration_update_cb_;
- // Keep track of outstanding promises. This map owns the promise object.
- PromiseMap session_id_to_promise_map_;
+ media::CdmPromiseAdapter cdm_promise_adapter_;
DISALLOW_COPY_AND_ASSIGN(ProxyMediaKeys);
};
diff --git a/chromium/content/renderer/media/crypto/render_cdm_factory.cc b/chromium/content/renderer/media/crypto/render_cdm_factory.cc
index 63fec99ed31..fe1a5dae2e9 100644
--- a/chromium/content/renderer/media/crypto/render_cdm_factory.cc
+++ b/chromium/content/renderer/media/crypto/render_cdm_factory.cc
@@ -4,11 +4,17 @@
#include "content/renderer/media/crypto/render_cdm_factory.h"
+#include "base/bind.h"
+#include "base/location.h"
#include "base/logging.h"
-#include "content/renderer/media/crypto/key_systems.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "media/base/cdm_config.h"
+#include "media/base/cdm_promise.h"
+#include "media/base/key_systems.h"
+#include "media/base/media_keys.h"
#include "media/cdm/aes_decryptor.h"
#include "url/gurl.h"
-
#if defined(ENABLE_PEPPER_CDMS)
#include "content/renderer/media/crypto/ppapi_decryptor.h"
#elif defined(ENABLE_BROWSER_CDMS)
@@ -17,66 +23,76 @@
namespace content {
-#if defined(ENABLE_PEPPER_CDMS)
RenderCdmFactory::RenderCdmFactory(
- const CreatePepperCdmCB& create_pepper_cdm_cb)
- : create_pepper_cdm_cb_(create_pepper_cdm_cb) {
-}
+#if defined(ENABLE_PEPPER_CDMS)
+ const CreatePepperCdmCB& create_pepper_cdm_cb,
#elif defined(ENABLE_BROWSER_CDMS)
-RenderCdmFactory::RenderCdmFactory(RendererCdmManager* manager)
- : manager_(manager) {
-}
-#else
-RenderCdmFactory::RenderCdmFactory() {
-}
+ RendererCdmManager* manager,
#endif // defined(ENABLE_PEPPER_CDMS)
+ RenderFrame* render_frame)
+ : RenderFrameObserver(render_frame)
+#if defined(ENABLE_PEPPER_CDMS)
+ , create_pepper_cdm_cb_(create_pepper_cdm_cb)
+#elif defined(ENABLE_BROWSER_CDMS)
+ , manager_(manager)
+#endif // defined(ENABLE_PEPPER_CDMS)
+{
+}
RenderCdmFactory::~RenderCdmFactory() {
+ DCHECK(thread_checker_.CalledOnValidThread());
}
-scoped_ptr<media::MediaKeys> RenderCdmFactory::Create(
+void RenderCdmFactory::Create(
const std::string& key_system,
const GURL& security_origin,
+ const media::CdmConfig& cdm_config,
const media::SessionMessageCB& session_message_cb,
- const media::SessionReadyCB& session_ready_cb,
const media::SessionClosedCB& session_closed_cb,
- const media::SessionErrorCB& session_error_cb,
+ const media::LegacySessionErrorCB& legacy_session_error_cb,
const media::SessionKeysChangeCB& session_keys_change_cb,
- const media::SessionExpirationUpdateCB& session_expiration_update_cb) {
- // TODO(jrummell): Pass |security_origin| to all constructors.
- // TODO(jrummell): Enable the following line once blink code updated to
- // check the security origin before calling.
- // DCHECK(security_origin.is_valid());
+ const media::SessionExpirationUpdateCB& session_expiration_update_cb,
+ const media::CdmCreatedCB& cdm_created_cb) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ if (!security_origin.is_valid()) {
+ base::MessageLoopProxy::current()->PostTask(
+ FROM_HERE, base::Bind(cdm_created_cb, nullptr, "Invalid origin."));
+ return;
+ }
- if (CanUseAesDecryptor(key_system)) {
- return scoped_ptr<media::MediaKeys>(new media::AesDecryptor(
- session_message_cb, session_closed_cb, session_keys_change_cb));
+ if (media::CanUseAesDecryptor(key_system)) {
+ // TODO(sandersd): Currently the prefixed API always allows distinctive
+ // identifiers and persistent state. Once that changes we can sanity check
+ // here that neither is allowed for AesDecryptor, since it does not support
+ // them and should never be configured that way. http://crbug.com/455271
+ scoped_ptr<media::MediaKeys> cdm(
+ new media::AesDecryptor(security_origin, session_message_cb,
+ session_closed_cb, session_keys_change_cb));
+ base::MessageLoopProxy::current()->PostTask(
+ FROM_HERE, base::Bind(cdm_created_cb, base::Passed(&cdm), ""));
+ return;
}
#if defined(ENABLE_PEPPER_CDMS)
- return scoped_ptr<media::MediaKeys>(
- PpapiDecryptor::Create(key_system,
- security_origin,
- create_pepper_cdm_cb_,
- session_message_cb,
- session_ready_cb,
- session_closed_cb,
- session_error_cb,
- session_keys_change_cb,
- session_expiration_update_cb));
+ DCHECK(!cdm_config.use_hw_secure_codecs);
+ PpapiDecryptor::Create(
+ key_system, security_origin, cdm_config.allow_distinctive_identifier,
+ cdm_config.allow_persistent_state, create_pepper_cdm_cb_,
+ session_message_cb, session_closed_cb, legacy_session_error_cb,
+ session_keys_change_cb, session_expiration_update_cb, cdm_created_cb);
#elif defined(ENABLE_BROWSER_CDMS)
- return scoped_ptr<media::MediaKeys>(
- ProxyMediaKeys::Create(key_system,
- security_origin,
- manager_,
- session_message_cb,
- session_ready_cb,
- session_closed_cb,
- session_error_cb,
- session_keys_change_cb,
- session_expiration_update_cb));
+ DCHECK(cdm_config.allow_distinctive_identifier);
+ DCHECK(cdm_config.allow_persistent_state);
+ ProxyMediaKeys::Create(
+ key_system, security_origin, cdm_config.use_hw_secure_codecs, manager_,
+ session_message_cb, session_closed_cb, legacy_session_error_cb,
+ session_keys_change_cb, session_expiration_update_cb, cdm_created_cb);
#else
- return nullptr;
+ // No possible CDM to create, so fail the request.
+ base::MessageLoopProxy::current()->PostTask(
+ FROM_HERE,
+ base::Bind(cdm_created_cb, nullptr, "Key system not supported."));
#endif // defined(ENABLE_PEPPER_CDMS)
}
diff --git a/chromium/content/renderer/media/crypto/render_cdm_factory.h b/chromium/content/renderer/media/crypto/render_cdm_factory.h
index f09f01bf433..80502db9332 100644
--- a/chromium/content/renderer/media/crypto/render_cdm_factory.h
+++ b/chromium/content/renderer/media/crypto/render_cdm_factory.h
@@ -8,6 +8,8 @@
#include <string>
#include "base/memory/scoped_ptr.h"
+#include "base/threading/thread_checker.h"
+#include "content/public/renderer/render_frame_observer.h"
#include "media/base/cdm_factory.h"
#include "media/base/media_keys.h"
@@ -17,34 +19,41 @@
class GURL;
+namespace media {
+struct CdmConfig;
+} // namespace media
+
namespace content {
#if defined(ENABLE_BROWSER_CDMS)
class RendererCdmManager;
#endif
-class RenderCdmFactory : public media::CdmFactory {
+// CdmFactory implementation in content/renderer. This class is not thread safe
+// and should only be used on one thread.
+class RenderCdmFactory : public media::CdmFactory, public RenderFrameObserver {
public:
+ RenderCdmFactory(
#if defined(ENABLE_PEPPER_CDMS)
- explicit RenderCdmFactory(const CreatePepperCdmCB& create_pepper_cdm_cb);
+ const CreatePepperCdmCB& create_pepper_cdm_cb,
#elif defined(ENABLE_BROWSER_CDMS)
- explicit RenderCdmFactory(RendererCdmManager* manager);
-#else
- RenderCdmFactory();
+ RendererCdmManager* manager,
#endif // defined(ENABLE_PEPPER_CDMS)
+ RenderFrame* render_frame);
~RenderCdmFactory() override;
- scoped_ptr<media::MediaKeys> Create(
+ // CdmFactory implementation.
+ void Create(
const std::string& key_system,
const GURL& security_origin,
+ const media::CdmConfig& cdm_config,
const media::SessionMessageCB& session_message_cb,
- const media::SessionReadyCB& session_ready_cb,
const media::SessionClosedCB& session_closed_cb,
- const media::SessionErrorCB& session_error_cb,
+ const media::LegacySessionErrorCB& legacy_session_error_cb,
const media::SessionKeysChangeCB& session_keys_change_cb,
- const media::SessionExpirationUpdateCB& session_expiration_update_cb)
- override;
+ const media::SessionExpirationUpdateCB& session_expiration_update_cb,
+ const media::CdmCreatedCB& cdm_created_cb) override;
private:
#if defined(ENABLE_PEPPER_CDMS)
@@ -54,6 +63,8 @@ class RenderCdmFactory : public media::CdmFactory {
RendererCdmManager* manager_;
#endif
+ base::ThreadChecker thread_checker_;
+
DISALLOW_COPY_AND_ASSIGN(RenderCdmFactory);
};
diff --git a/chromium/content/renderer/media/crypto/renderer_cdm_manager.cc b/chromium/content/renderer/media/crypto/renderer_cdm_manager.cc
index 3bfdc6e0709..be9c5eaade7 100644
--- a/chromium/content/renderer/media/crypto/renderer_cdm_manager.cc
+++ b/chromium/content/renderer/media/crypto/renderer_cdm_manager.cc
@@ -7,18 +7,21 @@
#include "base/stl_util.h"
#include "content/common/media/cdm_messages.h"
#include "content/renderer/media/crypto/proxy_media_keys.h"
+#include "media/base/cdm_context.h"
+#include "media/base/limits.h"
namespace content {
+using media::MediaKeys;
+
// Maximum sizes for various EME API parameters. These are checks to prevent
// unnecessarily large messages from being passed around, and the sizes
// are somewhat arbitrary as the EME spec doesn't specify any limits.
-const size_t kMaxWebSessionIdLength = 512;
const size_t kMaxSessionMessageLength = 10240; // 10 KB
RendererCdmManager::RendererCdmManager(RenderFrame* render_frame)
: RenderFrameObserver(render_frame),
- next_cdm_id_(media::MediaKeys::kInvalidCdmId + 1) {
+ next_cdm_id_(media::CdmContext::kInvalidCdmId + 1) {
}
RendererCdmManager::~RendererCdmManager() {
@@ -30,46 +33,69 @@ RendererCdmManager::~RendererCdmManager() {
bool RendererCdmManager::OnMessageReceived(const IPC::Message& msg) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(RendererCdmManager, msg)
- IPC_MESSAGE_HANDLER(CdmMsg_SessionCreated, OnSessionCreated)
IPC_MESSAGE_HANDLER(CdmMsg_SessionMessage, OnSessionMessage)
- IPC_MESSAGE_HANDLER(CdmMsg_SessionReady, OnSessionReady)
IPC_MESSAGE_HANDLER(CdmMsg_SessionClosed, OnSessionClosed)
- IPC_MESSAGE_HANDLER(CdmMsg_SessionError, OnSessionError)
+ IPC_MESSAGE_HANDLER(CdmMsg_LegacySessionError, OnLegacySessionError)
+ IPC_MESSAGE_HANDLER(CdmMsg_SessionKeysChange, OnSessionKeysChange)
+ IPC_MESSAGE_HANDLER(CdmMsg_SessionExpirationUpdate,
+ OnSessionExpirationUpdate)
+ IPC_MESSAGE_HANDLER(CdmMsg_ResolvePromise, OnPromiseResolved)
+ IPC_MESSAGE_HANDLER(CdmMsg_ResolvePromiseWithSession,
+ OnPromiseResolvedWithSession)
+ IPC_MESSAGE_HANDLER(CdmMsg_RejectPromise, OnPromiseRejected)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void RendererCdmManager::InitializeCdm(int cdm_id,
+ uint32_t promise_id,
ProxyMediaKeys* media_keys,
const std::string& key_system,
- const GURL& security_origin) {
+ const GURL& security_origin,
+ bool use_hw_secure_codecs) {
+ DCHECK(GetMediaKeys(cdm_id)) << "|cdm_id| not registered.";
+ CdmHostMsg_InitializeCdm_Params params;
+ params.key_system = key_system;
+ params.security_origin = security_origin;
+ params.use_hw_secure_codecs = use_hw_secure_codecs;
+ Send(new CdmHostMsg_InitializeCdm(routing_id(), cdm_id, promise_id, params));
+}
+
+void RendererCdmManager::SetServerCertificate(
+ int cdm_id,
+ uint32_t promise_id,
+ const std::vector<uint8_t>& certificate) {
DCHECK(GetMediaKeys(cdm_id)) << "|cdm_id| not registered.";
- Send(new CdmHostMsg_InitializeCdm(
- routing_id(), cdm_id, key_system, security_origin));
+ Send(new CdmHostMsg_SetServerCertificate(routing_id(), cdm_id, promise_id,
+ certificate));
}
-void RendererCdmManager::CreateSession(
+void RendererCdmManager::CreateSessionAndGenerateRequest(
int cdm_id,
- uint32 session_id,
- CdmHostMsg_CreateSession_ContentType content_type,
- const std::vector<uint8>& init_data) {
+ uint32_t promise_id,
+ CdmHostMsg_CreateSession_InitDataType init_data_type,
+ const std::vector<uint8_t>& init_data) {
DCHECK(GetMediaKeys(cdm_id)) << "|cdm_id| not registered.";
- Send(new CdmHostMsg_CreateSession(
- routing_id(), cdm_id, session_id, content_type, init_data));
+ Send(new CdmHostMsg_CreateSessionAndGenerateRequest(
+ routing_id(), cdm_id, promise_id, init_data_type, init_data));
}
void RendererCdmManager::UpdateSession(int cdm_id,
- uint32 session_id,
- const std::vector<uint8>& response) {
+ uint32_t promise_id,
+ const std::string& session_id,
+ const std::vector<uint8_t>& response) {
DCHECK(GetMediaKeys(cdm_id)) << "|cdm_id| not registered.";
- Send(
- new CdmHostMsg_UpdateSession(routing_id(), cdm_id, session_id, response));
+ Send(new CdmHostMsg_UpdateSession(routing_id(), cdm_id, promise_id,
+ session_id, response));
}
-void RendererCdmManager::ReleaseSession(int cdm_id, uint32 session_id) {
+void RendererCdmManager::CloseSession(int cdm_id,
+ uint32_t promise_id,
+ const std::string& session_id) {
DCHECK(GetMediaKeys(cdm_id)) << "|cdm_id| not registered.";
- Send(new CdmHostMsg_ReleaseSession(routing_id(), cdm_id, session_id));
+ Send(new CdmHostMsg_CloseSession(routing_id(), cdm_id, promise_id,
+ session_id));
}
void RendererCdmManager::DestroyCdm(int cdm_id) {
@@ -77,57 +103,106 @@ void RendererCdmManager::DestroyCdm(int cdm_id) {
Send(new CdmHostMsg_DestroyCdm(routing_id(), cdm_id));
}
-void RendererCdmManager::OnSessionCreated(int cdm_id,
- uint32 session_id,
- const std::string& web_session_id) {
- if (web_session_id.length() > kMaxWebSessionIdLength) {
- OnSessionError(cdm_id, session_id, media::MediaKeys::kUnknownError, 0);
+void RendererCdmManager::OnSessionMessage(
+ int cdm_id,
+ const std::string& session_id,
+ media::MediaKeys::MessageType message_type,
+ const std::vector<uint8>& message,
+ const GURL& legacy_destination_url) {
+ if (message.size() > kMaxSessionMessageLength) {
+ NOTREACHED();
+ LOG(ERROR) << "Message is too long and dropped.";
return;
}
ProxyMediaKeys* media_keys = GetMediaKeys(cdm_id);
if (media_keys)
- media_keys->OnSessionCreated(session_id, web_session_id);
+ media_keys->OnSessionMessage(session_id, message_type, message,
+ legacy_destination_url);
}
-void RendererCdmManager::OnSessionMessage(int cdm_id,
- uint32 session_id,
- const std::vector<uint8>& message,
- const GURL& destination_url) {
- if (message.size() > kMaxSessionMessageLength) {
- OnSessionError(cdm_id, session_id, media::MediaKeys::kUnknownError, 0);
+void RendererCdmManager::OnSessionClosed(int cdm_id,
+ const std::string& session_id) {
+ ProxyMediaKeys* media_keys = GetMediaKeys(cdm_id);
+ if (media_keys)
+ media_keys->OnSessionClosed(session_id);
+}
+
+void RendererCdmManager::OnLegacySessionError(
+ int cdm_id,
+ const std::string& session_id,
+ MediaKeys::Exception exception,
+ uint32 system_code,
+ const std::string& error_message) {
+ ProxyMediaKeys* media_keys = GetMediaKeys(cdm_id);
+ if (media_keys)
+ media_keys->OnLegacySessionError(session_id, exception, system_code,
+ error_message);
+}
+
+void RendererCdmManager::OnSessionKeysChange(
+ int cdm_id,
+ const std::string& session_id,
+ bool has_additional_usable_key,
+ const std::vector<media::CdmKeyInformation>& key_info_vector) {
+ ProxyMediaKeys* media_keys = GetMediaKeys(cdm_id);
+ if (!media_keys)
return;
- }
+ media::CdmKeysInfo keys_info;
+ keys_info.reserve(key_info_vector.size());
+ for (const auto& key_info : key_info_vector)
+ keys_info.push_back(new media::CdmKeyInformation(key_info));
+
+ media_keys->OnSessionKeysChange(session_id, has_additional_usable_key,
+ keys_info.Pass());
+}
+
+void RendererCdmManager::OnSessionExpirationUpdate(
+ int cdm_id,
+ const std::string& session_id,
+ const base::Time& new_expiry_time) {
ProxyMediaKeys* media_keys = GetMediaKeys(cdm_id);
if (media_keys)
- media_keys->OnSessionMessage(session_id, message, destination_url);
+ media_keys->OnSessionExpirationUpdate(session_id, new_expiry_time);
}
-void RendererCdmManager::OnSessionReady(int cdm_id, uint32 session_id) {
+void RendererCdmManager::OnPromiseResolved(int cdm_id, uint32_t promise_id) {
ProxyMediaKeys* media_keys = GetMediaKeys(cdm_id);
if (media_keys)
- media_keys->OnSessionReady(session_id);
+ media_keys->OnPromiseResolved(promise_id);
}
-void RendererCdmManager::OnSessionClosed(int cdm_id, uint32 session_id) {
+void RendererCdmManager::OnPromiseResolvedWithSession(
+ int cdm_id,
+ uint32_t promise_id,
+ const std::string& session_id) {
+ if (session_id.length() > media::limits::kMaxSessionIdLength) {
+ NOTREACHED();
+ OnPromiseRejected(cdm_id, promise_id, MediaKeys::INVALID_ACCESS_ERROR, 0,
+ "Session ID is too long");
+ return;
+ }
+
ProxyMediaKeys* media_keys = GetMediaKeys(cdm_id);
if (media_keys)
- media_keys->OnSessionClosed(session_id);
+ media_keys->OnPromiseResolvedWithSession(promise_id, session_id);
}
-void RendererCdmManager::OnSessionError(int cdm_id,
- uint32 session_id,
- media::MediaKeys::KeyError error_code,
- uint32 system_code) {
+void RendererCdmManager::OnPromiseRejected(int cdm_id,
+ uint32_t promise_id,
+ MediaKeys::Exception exception,
+ uint32_t system_code,
+ const std::string& error_message) {
ProxyMediaKeys* media_keys = GetMediaKeys(cdm_id);
if (media_keys)
- media_keys->OnSessionError(session_id, error_code, system_code);
+ media_keys->OnPromiseRejected(promise_id, exception, system_code,
+ error_message);
}
int RendererCdmManager::RegisterMediaKeys(ProxyMediaKeys* media_keys) {
int cdm_id = next_cdm_id_++;
- DCHECK_NE(cdm_id, media::MediaKeys::kInvalidCdmId);
+ DCHECK_NE(cdm_id, media::CdmContext::kInvalidCdmId);
DCHECK(!ContainsKey(proxy_media_keys_map_, cdm_id));
proxy_media_keys_map_[cdm_id] = media_keys;
return cdm_id;
diff --git a/chromium/content/renderer/media/crypto/renderer_cdm_manager.h b/chromium/content/renderer/media/crypto/renderer_cdm_manager.h
index 4944144685d..1ab051324e6 100644
--- a/chromium/content/renderer/media/crypto/renderer_cdm_manager.h
+++ b/chromium/content/renderer/media/crypto/renderer_cdm_manager.h
@@ -28,24 +28,33 @@ class RendererCdmManager : public RenderFrameObserver {
public:
// Constructs a RendererCdmManager object for the |render_frame|.
explicit RendererCdmManager(RenderFrame* render_frame);
- virtual ~RendererCdmManager();
+ ~RendererCdmManager() override;
// RenderFrameObserver overrides.
- virtual bool OnMessageReceived(const IPC::Message& msg) override;
+ bool OnMessageReceived(const IPC::Message& msg) override;
// Encrypted media related methods.
void InitializeCdm(int cdm_id,
+ uint32_t promise_id,
ProxyMediaKeys* media_keys,
const std::string& key_system,
- const GURL& security_origin);
- void CreateSession(int cdm_id,
- uint32 session_id,
- CdmHostMsg_CreateSession_ContentType conent_type,
- const std::vector<uint8>& init_data);
+ const GURL& security_origin,
+ bool use_hw_secure_codecs);
+ void SetServerCertificate(int cdm_id,
+ uint32_t promise_id,
+ const std::vector<uint8>& certificate);
+ void CreateSessionAndGenerateRequest(
+ int cdm_id,
+ uint32_t promise_id,
+ CdmHostMsg_CreateSession_InitDataType init_data_type,
+ const std::vector<uint8>& init_data);
void UpdateSession(int cdm_id,
- uint32 session_id,
+ uint32_t promise_id,
+ const std::string& session_id,
const std::vector<uint8>& response);
- void ReleaseSession(int cdm_id, uint32 session_id);
+ void CloseSession(int cdm_id,
+ uint32_t promise_id,
+ const std::string& session_id);
void DestroyCdm(int cdm_id);
// Registers a ProxyMediaKeys object. Returns allocated CDM ID.
@@ -59,19 +68,35 @@ class RendererCdmManager : public RenderFrameObserver {
ProxyMediaKeys* GetMediaKeys(int cdm_id);
// Message handlers.
- void OnSessionCreated(int cdm_id,
- uint32 session_id,
- const std::string& web_session_id);
void OnSessionMessage(int cdm_id,
- uint32 session_id,
+ const std::string& session_id,
+ media::MediaKeys::MessageType message_type,
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,
- uint32 session_id,
- media::MediaKeys::KeyError error_code,
- uint32 system_code);
+ const GURL& legacy_destination_url);
+ void OnSessionClosed(int cdm_id, const std::string& session_id);
+ void OnLegacySessionError(int cdm_id,
+ const std::string& session_id,
+ media::MediaKeys::Exception exception,
+ uint32 system_code,
+ const std::string& error_message);
+ void OnSessionKeysChange(
+ int cdm_id,
+ const std::string& session_id,
+ bool has_additional_usable_key,
+ const std::vector<media::CdmKeyInformation>& key_info_vector);
+ void OnSessionExpirationUpdate(int cdm_id,
+ const std::string& session_id,
+ const base::Time& new_expiry_time);
+
+ void OnPromiseResolved(int cdm_id, uint32_t promise_id);
+ void OnPromiseResolvedWithSession(int cdm_id,
+ uint32_t promise_id,
+ const std::string& session_id);
+ void OnPromiseRejected(int cdm_id,
+ uint32_t promise_id,
+ media::MediaKeys::Exception exception,
+ uint32_t system_code,
+ const std::string& error_message);
// CDM ID should be unique per renderer frame.
// TODO(xhwang): Use uint32 to prevent undefined overflow behavior.
diff --git a/chromium/content/renderer/media/media_permission_dispatcher.cc b/chromium/content/renderer/media/media_permission_dispatcher.cc
new file mode 100644
index 00000000000..1e1f2a07a2a
--- /dev/null
+++ b/chromium/content/renderer/media/media_permission_dispatcher.cc
@@ -0,0 +1,96 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/media/media_permission_dispatcher.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "content/public/common/service_registry.h"
+#include "content/public/renderer/render_frame.h"
+#include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
+#include "url/gurl.h"
+
+namespace content {
+
+MediaPermissionDispatcher::MediaPermissionDispatcher(RenderFrame* render_frame)
+ : RenderFrameObserver(render_frame), next_request_id_(0) {
+}
+
+MediaPermissionDispatcher::~MediaPermissionDispatcher() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ // Fire all pending callbacks with |false|.
+ for (auto& request : requests_)
+ request.second.Run(false);
+
+ requests_.clear();
+}
+
+void MediaPermissionDispatcher::HasPermission(
+ Type type,
+ const GURL& security_origin,
+ const PermissionStatusCB& permission_status_cb) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ CHECK_EQ(PROTECTED_MEDIA_IDENTIFIER, type);
+
+ if (!permission_service_.get()) {
+ render_frame()->GetServiceRegistry()->ConnectToRemoteService(
+ &permission_service_);
+ }
+
+ uint32_t request_id = next_request_id_++;
+ DCHECK(!requests_.count(request_id));
+ requests_[request_id] = permission_status_cb;
+
+ DVLOG(2) << __FUNCTION__ << ": request ID " << request_id;
+
+ permission_service_->HasPermission(
+ PERMISSION_NAME_PROTECTED_MEDIA_IDENTIFIER, security_origin.spec(),
+ base::Bind(&MediaPermissionDispatcher::OnPermissionStatus,
+ base::Unretained(this), request_id));
+}
+
+void MediaPermissionDispatcher::RequestPermission(
+ Type type,
+ const GURL& security_origin,
+ const PermissionStatusCB& permission_status_cb) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ CHECK_EQ(PROTECTED_MEDIA_IDENTIFIER, type);
+
+ if (!permission_service_.get()) {
+ render_frame()->GetServiceRegistry()->ConnectToRemoteService(
+ &permission_service_);
+ }
+
+ uint32_t request_id = next_request_id_++;
+ DCHECK(!requests_.count(request_id));
+ requests_[request_id] = permission_status_cb;
+
+ DVLOG(2) << __FUNCTION__ << ": request ID " << request_id;
+
+ permission_service_->RequestPermission(
+ PERMISSION_NAME_PROTECTED_MEDIA_IDENTIFIER, security_origin.spec(),
+ blink::WebUserGestureIndicator::isProcessingUserGesture(),
+ base::Bind(&MediaPermissionDispatcher::OnPermissionStatus,
+ base::Unretained(this), request_id));
+}
+
+void MediaPermissionDispatcher::OnPermissionStatus(uint32_t request_id,
+ PermissionStatus status) {
+ DVLOG(2) << __FUNCTION__ << ": (" << request_id << ", " << status << ")";
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ RequestMap::iterator iter = requests_.find(request_id);
+ if (iter == requests_.end()) {
+ DVLOG(2) << "Request not found.";
+ return;
+ }
+
+ PermissionStatusCB permission_status_cb = iter->second;
+ requests_.erase(iter);
+
+ permission_status_cb.Run(status == PERMISSION_STATUS_GRANTED);
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/media/media_permission_dispatcher.h b/chromium/content/renderer/media/media_permission_dispatcher.h
new file mode 100644
index 00000000000..4e23bd717c9
--- /dev/null
+++ b/chromium/content/renderer/media/media_permission_dispatcher.h
@@ -0,0 +1,53 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_MEDIA_MEDIA_PERMISSION_DISPATCHER_H_
+#define CONTENT_RENDERER_MEDIA_MEDIA_PERMISSION_DISPATCHER_H_
+
+#include <map>
+
+#include "base/threading/thread_checker.h"
+#include "content/common/content_export.h"
+#include "content/common/permission_service.mojom.h"
+#include "content/public/renderer/render_frame_observer.h"
+#include "media/base/media_permission.h"
+
+namespace content {
+
+// MediaPermission implementation in content. This class is not thread safe
+// and should only be used on one thread.
+class CONTENT_EXPORT MediaPermissionDispatcher : public media::MediaPermission,
+ public RenderFrameObserver {
+ public:
+ explicit MediaPermissionDispatcher(RenderFrame* render_frame);
+ ~MediaPermissionDispatcher() override;
+
+ // media::MediaPermission implementation.
+ void HasPermission(Type type,
+ const GURL& security_origin,
+ const PermissionStatusCB& permission_status_cb) override;
+ void RequestPermission(
+ Type type,
+ const GURL& security_origin,
+ const PermissionStatusCB& permission_status_cb) override;
+
+ private:
+ // Map of request IDs and pending PermissionStatusCBs.
+ typedef std::map<uint32_t, PermissionStatusCB> RequestMap;
+
+ // Callback for |permission_service_| calls.
+ void OnPermissionStatus(uint32_t request_id, PermissionStatus status);
+
+ uint32_t next_request_id_;
+ RequestMap requests_;
+ PermissionServicePtr permission_service_;
+
+ base::ThreadChecker thread_checker_;
+
+ DISALLOW_COPY_AND_ASSIGN(MediaPermissionDispatcher);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_MEDIA_MEDIA_PERMISSION_DISPATCHER_H_
diff --git a/chromium/content/renderer/media/media_renderer_service_provider.cc b/chromium/content/renderer/media/media_renderer_service_provider.cc
new file mode 100644
index 00000000000..4f3b8f2effb
--- /dev/null
+++ b/chromium/content/renderer/media/media_renderer_service_provider.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/public/common/service_registry.h"
+#include "content/renderer/media/media_renderer_service_provider.h"
+
+namespace content {
+
+MediaRendererServiceProvider::MediaRendererServiceProvider(
+ ServiceRegistry* service_registry)
+ : service_registry_(service_registry) {
+}
+
+MediaRendererServiceProvider::~MediaRendererServiceProvider() {
+}
+
+void MediaRendererServiceProvider::ConnectToService(
+ mojo::InterfacePtr<mojo::MediaRenderer>* media_renderer_ptr) {
+ service_registry_->ConnectToRemoteService(media_renderer_ptr);
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/media/media_renderer_service_provider.h b/chromium/content/renderer/media/media_renderer_service_provider.h
new file mode 100644
index 00000000000..5da97278e75
--- /dev/null
+++ b/chromium/content/renderer/media/media_renderer_service_provider.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_RENDERER_MEDIA_MEDIA_RENDERER_SERVICE_PROVIDER_H_
+#define CONTENT_RENDERER_MEDIA_MEDIA_RENDERER_SERVICE_PROVIDER_H_
+
+#include "base/macros.h"
+#include "content/common/content_export.h"
+#include "media/mojo/services/mojo_renderer_factory.h"
+
+namespace content {
+
+class ServiceRegistry;
+
+// ServiceRegistry based media::MojoRendererFactory::ServiceProvider
+// implementation.
+class CONTENT_EXPORT MediaRendererServiceProvider
+ : public media::MojoRendererFactory::ServiceProvider {
+ public:
+ explicit MediaRendererServiceProvider(ServiceRegistry* service_registry);
+ ~MediaRendererServiceProvider() final;
+
+ void ConnectToService(
+ mojo::InterfacePtr<mojo::MediaRenderer>* media_renderer_ptr) final;
+
+ private:
+ ServiceRegistry* service_registry_;
+
+ DISALLOW_COPY_AND_ASSIGN(MediaRendererServiceProvider);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_MEDIA_MEDIA_RENDERER_SERVICE_PROVIDER_H_
diff --git a/chromium/content/renderer/media/media_stream_audio_level_calculator.cc b/chromium/content/renderer/media/media_stream_audio_level_calculator.cc
index 9994b695e11..ad76a43dd2f 100644
--- a/chromium/content/renderer/media/media_stream_audio_level_calculator.cc
+++ b/chromium/content/renderer/media/media_stream_audio_level_calculator.cc
@@ -4,26 +4,25 @@
#include "content/renderer/media/media_stream_audio_level_calculator.h"
+#include <cmath>
+
#include "base/logging.h"
#include "base/stl_util.h"
+#include "media/base/audio_bus.h"
namespace content {
namespace {
// Calculates the maximum absolute amplitude of the audio data.
-// Note, the return value can be bigger than std::numeric_limits<int16>::max().
-int MaxAmplitude(const int16* audio_data, int length) {
- int max = 0, absolute = 0;
+float MaxAmplitude(const float* audio_data, int length) {
+ float max = 0.0f;
for (int i = 0; i < length; ++i) {
- absolute = std::abs(audio_data[i]);
+ const float absolute = fabsf(audio_data[i]);
if (absolute > max)
max = absolute;
}
- // The range of int16 is [-32768, 32767], verify the |max| should not be
- // bigger than 32768.
- DCHECK(max <= std::abs(std::numeric_limits<int16>::min()));
-
+ DCHECK(std::isfinite(max));
return max;
}
@@ -31,32 +30,34 @@ int MaxAmplitude(const int16* audio_data, int length) {
MediaStreamAudioLevelCalculator::MediaStreamAudioLevelCalculator()
: counter_(0),
- max_amplitude_(0),
- level_(0) {
+ max_amplitude_(0.0f),
+ level_(0.0f) {
}
MediaStreamAudioLevelCalculator::~MediaStreamAudioLevelCalculator() {
}
-int MediaStreamAudioLevelCalculator::Calculate(
- const int16* audio_data,
- int number_of_channels,
- int number_of_frames,
- bool force_report_nonzero_energy) {
+float MediaStreamAudioLevelCalculator::Calculate(
+ const media::AudioBus& audio_bus) {
DCHECK(thread_checker_.CalledOnValidThread());
// |level_| is updated every 10 callbacks. For the case where callback comes
// every 10ms, |level_| will be updated approximately every 100ms.
static const int kUpdateFrequency = 10;
- int max = MaxAmplitude(audio_data, number_of_channels * number_of_frames);
+ float max = 0.0f;
+ for (int i = 0; i < audio_bus.channels(); ++i) {
+ const float max_this_channel =
+ MaxAmplitude(audio_bus.channel(i), audio_bus.frames());
+ if (max_this_channel > max)
+ max = max_this_channel;
+ }
max_amplitude_ = std::max(max_amplitude_, max);
if (counter_++ == kUpdateFrequency) {
- level_ = (max_amplitude_ == 0 ?
- force_report_nonzero_energy : max_amplitude_);
+ level_ = max_amplitude_;
// Decay the absolute maximum amplitude by 1/4.
- max_amplitude_ >>= 2;
+ max_amplitude_ /= 4.0f;
// Reset the counter.
counter_ = 0;
diff --git a/chromium/content/renderer/media/media_stream_audio_level_calculator.h b/chromium/content/renderer/media/media_stream_audio_level_calculator.h
index 48dda4ce0db..e7d25cc5d54 100644
--- a/chromium/content/renderer/media/media_stream_audio_level_calculator.h
+++ b/chromium/content/renderer/media/media_stream_audio_level_calculator.h
@@ -7,9 +7,13 @@
#include "base/threading/thread_checker.h"
+namespace media {
+class AudioBus;
+}
+
namespace content {
-// This class is used by the WebRtcLocalAudioTrack to calculate the level of
+// This class is used by the WebRtcLocalAudioTrack to calculate the level of
// the audio signal. And the audio level will be eventually used by the volume
// animation UI.
// The algorithm used by this class is the same as how it is done in
@@ -19,16 +23,9 @@ class MediaStreamAudioLevelCalculator {
MediaStreamAudioLevelCalculator();
~MediaStreamAudioLevelCalculator();
- // Calculates the signal level of the audio data.
- // Returns the absolute value of the amplitude of the signal.
- // |force_report_nonzero_energy| is a flag forcing the calculator to
- // report nonzero energy even if the energy of the processed audio is zero.
- // Since |audio_data| is post processed data, and the audio processing might
- // zero all the audio data, when the caller detects the pre processed data
- // contain energy, it could pass |force_report_nonzero_energy| as true to
- // force calculator to report 1 as energy when |audio_data| is all zero.
- int Calculate(const int16* audio_data, int number_of_channels,
- int number_of_frames, bool force_report_nonzero_energy);
+ // Calculates the signal level of the audio data, returning the absolute value
+ // of the amplitude of the signal.
+ float Calculate(const media::AudioBus& audio_bus);
private:
// Used to DCHECK that the constructor and Calculate() are always called on
@@ -38,8 +35,8 @@ class MediaStreamAudioLevelCalculator {
base::ThreadChecker thread_checker_;
int counter_;
- int max_amplitude_;
- int level_;
+ float max_amplitude_;
+ float level_;
};
} // namespace content
diff --git a/chromium/content/renderer/media/media_stream_audio_processor.cc b/chromium/content/renderer/media/media_stream_audio_processor.cc
index 548e74f5a2a..b4638d67b7f 100644
--- a/chromium/content/renderer/media/media_stream_audio_processor.cc
+++ b/chromium/content/renderer/media/media_stream_audio_processor.cc
@@ -5,11 +5,9 @@
#include "content/renderer/media/media_stream_audio_processor.h"
#include "base/command_line.h"
-#include "base/debug/trace_event.h"
-#if defined(OS_MACOSX)
#include "base/metrics/field_trial.h"
-#endif
#include "base/metrics/histogram.h"
+#include "base/trace_event/trace_event.h"
#include "content/public/common/content_switches.h"
#include "content/renderer/media/media_stream_audio_processor_options.h"
#include "content/renderer/media/rtc_media_constraints.h"
@@ -22,17 +20,16 @@
#include "third_party/libjingle/source/talk/app/webrtc/mediaconstraintsinterface.h"
#include "third_party/webrtc/modules/audio_processing/typing_detection.h"
+#if defined(OS_CHROMEOS)
+#include "base/sys_info.h"
+#endif
+
namespace content {
namespace {
using webrtc::AudioProcessing;
-#if defined(OS_ANDROID)
-const int kAudioProcessingSampleRate = 16000;
-#else
-const int kAudioProcessingSampleRate = 32000;
-#endif
const int kAudioProcessingNumberOfChannels = 1;
AudioProcessing::ChannelLayout MapLayout(media::ChannelLayout media_layout) {
@@ -75,6 +72,34 @@ void RecordProcessingState(AudioTrackProcessingStates state) {
state, AUDIO_PROCESSING_MAX);
}
+bool IsDelayAgnosticAecEnabled() {
+ // Note: It's important to query the field trial state first, to ensure that
+ // UMA reports the correct group.
+ const std::string group_name =
+ base::FieldTrialList::FindFullName("UseDelayAgnosticAEC");
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch(switches::kEnableDelayAgnosticAec))
+ return true;
+ if (command_line->HasSwitch(switches::kDisableDelayAgnosticAec))
+ return false;
+
+ return (group_name == "Enabled" || group_name == "DefaultEnabled");
+}
+
+bool IsBeamformingEnabled(const MediaAudioConstraints& audio_constraints) {
+ return base::FieldTrialList::FindFullName("ChromebookBeamforming") ==
+ "Enabled" ||
+ audio_constraints.GetProperty(MediaAudioConstraints::kGoogBeamforming);
+}
+
+bool IsAudioProcessing48kHzSupportEnabled(
+ const MediaAudioConstraints& audio_constraints) {
+ return base::FieldTrialList::FindFullName("AudioProcessing48kHzSupport") ==
+ "Enabled" ||
+ audio_constraints.GetProperty(
+ MediaAudioConstraints::kGoogAudioProcessing48kHzSupport);
+}
+
} // namespace
// Wraps AudioBus to provide access to the array of channel pointers, since this
@@ -122,13 +147,16 @@ class MediaStreamAudioFifo {
MediaStreamAudioFifo(int source_channels,
int destination_channels,
int source_frames,
- int destination_frames)
+ int destination_frames,
+ int sample_rate)
: source_channels_(source_channels),
source_frames_(source_frames),
+ sample_rate_(sample_rate),
destination_(
new MediaStreamAudioBus(destination_channels, destination_frames)),
data_available_(false) {
DCHECK_GE(source_channels, destination_channels);
+ DCHECK_GT(sample_rate_, 0);
if (source_channels > destination_channels) {
audio_source_intermediate_ =
@@ -147,34 +175,38 @@ class MediaStreamAudioFifo {
thread_checker_.DetachFromThread();
}
- void Push(const media::AudioBus* source) {
+ void Push(const media::AudioBus& source, base::TimeDelta audio_delay) {
DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK_EQ(source->channels(), source_channels_);
- DCHECK_EQ(source->frames(), source_frames_);
+ DCHECK_EQ(source.channels(), source_channels_);
+ DCHECK_EQ(source.frames(), source_frames_);
- const media::AudioBus* source_to_push = source;
+ const media::AudioBus* source_to_push = &source;
if (audio_source_intermediate_) {
for (int i = 0; i < destination_->bus()->channels(); ++i) {
audio_source_intermediate_->SetChannelData(
i,
- const_cast<float*>(source->channel(i)));
+ const_cast<float*>(source.channel(i)));
}
- audio_source_intermediate_->set_frames(source->frames());
+ audio_source_intermediate_->set_frames(source.frames());
source_to_push = audio_source_intermediate_.get();
}
if (fifo_) {
+ next_audio_delay_ = audio_delay +
+ fifo_->frames() * base::TimeDelta::FromSeconds(1) / sample_rate_;
fifo_->Push(source_to_push);
} else {
source_to_push->CopyTo(destination_->bus());
+ next_audio_delay_ = audio_delay;
data_available_ = true;
}
}
// Returns true if there are destination_frames() of data available to be
// consumed, and otherwise false.
- bool Consume(MediaStreamAudioBus** destination) {
+ bool Consume(MediaStreamAudioBus** destination,
+ base::TimeDelta* audio_delay) {
DCHECK(thread_checker_.CalledOnValidThread());
if (fifo_) {
@@ -182,10 +214,14 @@ class MediaStreamAudioFifo {
return false;
fifo_->Consume(destination_->bus(), 0, destination_->bus()->frames());
+ *audio_delay = next_audio_delay_;
+ next_audio_delay_ -=
+ destination_->bus()->frames() * base::TimeDelta::FromSeconds(1) /
+ sample_rate_;
} else {
if (!data_available_)
return false;
-
+ *audio_delay = next_audio_delay_;
// The data was already copied to |destination_| in this case.
data_available_ = false;
}
@@ -198,18 +234,21 @@ class MediaStreamAudioFifo {
base::ThreadChecker thread_checker_;
const int source_channels_; // For a DCHECK.
const int source_frames_; // For a DCHECK.
+ const int sample_rate_;
scoped_ptr<media::AudioBus> audio_source_intermediate_;
scoped_ptr<MediaStreamAudioBus> destination_;
scoped_ptr<media::AudioFifo> fifo_;
- // Only used when the FIFO is disabled;
+
+ // When using |fifo_|, this is the audio delay of the first sample to be
+ // consumed next from the FIFO. When not using |fifo_|, this is the audio
+ // delay of the first sample in |destination_|.
+ base::TimeDelta next_audio_delay_;
+
+ // True when |destination_| contains the data to be returned by the next call
+ // to Consume(). Only used when the FIFO is disabled.
bool data_available_;
};
-bool MediaStreamAudioProcessor::IsAudioTrackProcessingEnabled() {
- return !CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableAudioTrackProcessing);
-}
-
MediaStreamAudioProcessor::MediaStreamAudioProcessor(
const blink::WebMediaConstraints& constraints,
int effects,
@@ -218,18 +257,18 @@ MediaStreamAudioProcessor::MediaStreamAudioProcessor(
playout_data_source_(playout_data_source),
audio_mirroring_(false),
typing_detected_(false),
- stopped_(false) {
+ stopped_(false),
+ audio_proc_48kHz_support_(false) {
capture_thread_checker_.DetachFromThread();
render_thread_checker_.DetachFromThread();
InitializeAudioProcessingModule(constraints, effects);
- if (IsAudioTrackProcessingEnabled()) {
- aec_dump_message_filter_ = AecDumpMessageFilter::Get();
- // In unit tests not creating a message filter, |aec_dump_message_filter_|
- // will be NULL. We can just ignore that. Other unit tests and browser tests
- // ensure that we do get the filter when we should.
- if (aec_dump_message_filter_.get())
- aec_dump_message_filter_->AddDelegate(this);
- }
+
+ aec_dump_message_filter_ = AecDumpMessageFilter::Get();
+ // In unit tests not creating a message filter, |aec_dump_message_filter_|
+ // will be NULL. We can just ignore that. Other unit tests and browser tests
+ // ensure that we do get the filter when we should.
+ if (aec_dump_message_filter_.get())
+ aec_dump_message_filter_->AddDelegate(this);
}
MediaStreamAudioProcessor::~MediaStreamAudioProcessor() {
@@ -251,20 +290,28 @@ void MediaStreamAudioProcessor::OnCaptureFormatChanged(
}
void MediaStreamAudioProcessor::PushCaptureData(
- const media::AudioBus* audio_source) {
+ const media::AudioBus& audio_source,
+ base::TimeDelta capture_delay) {
DCHECK(capture_thread_checker_.CalledOnValidThread());
- capture_fifo_->Push(audio_source);
+ capture_fifo_->Push(audio_source, capture_delay);
}
bool MediaStreamAudioProcessor::ProcessAndConsumeData(
- base::TimeDelta capture_delay, int volume, bool key_pressed,
- int* new_volume, int16** out) {
+ int volume,
+ bool key_pressed,
+ media::AudioBus** processed_data,
+ base::TimeDelta* capture_delay,
+ int* new_volume) {
DCHECK(capture_thread_checker_.CalledOnValidThread());
+ DCHECK(processed_data);
+ DCHECK(capture_delay);
+ DCHECK(new_volume);
+
TRACE_EVENT0("audio", "MediaStreamAudioProcessor::ProcessAndConsumeData");
MediaStreamAudioBus* process_bus;
- if (!capture_fifo_->Consume(&process_bus))
+ if (!capture_fifo_->Consume(&process_bus, capture_delay))
return false;
// Use the process bus directly if audio processing is disabled.
@@ -273,7 +320,7 @@ bool MediaStreamAudioProcessor::ProcessAndConsumeData(
if (audio_processing_) {
output_bus = output_bus_.get();
*new_volume = ProcessData(process_bus->channel_ptrs(),
- process_bus->bus()->frames(), capture_delay,
+ process_bus->bus()->frames(), *capture_delay,
volume, key_pressed, output_bus->channel_ptrs());
}
@@ -284,10 +331,7 @@ bool MediaStreamAudioProcessor::ProcessAndConsumeData(
output_bus->bus()->SwapChannels(0, 1);
}
- output_bus->bus()->ToInterleaved(output_bus->bus()->frames(),
- sizeof(int16),
- output_data_.get());
- *out = output_data_.get();
+ *processed_data = output_bus->bus();
return true;
}
@@ -362,9 +406,12 @@ void MediaStreamAudioProcessor::OnPlayoutData(media::AudioBus* audio_bus,
InitializeRenderFifoIfNeeded(sample_rate, audio_bus->channels(),
audio_bus->frames());
- render_fifo_->Push(audio_bus);
+ render_fifo_->Push(
+ *audio_bus, base::TimeDelta::FromMilliseconds(audio_delay_milliseconds));
MediaStreamAudioBus* analysis_bus;
- while (render_fifo_->Consume(&analysis_bus)) {
+ base::TimeDelta audio_delay;
+ while (render_fifo_->Consume(&analysis_bus, &audio_delay)) {
+ // TODO(ajm): Should AnalyzeReverseStream() account for the |audio_delay|?
audio_processing_->AnalyzeReverseStream(
analysis_bus->channel_ptrs(),
analysis_bus->bus()->frames(),
@@ -384,9 +431,7 @@ void MediaStreamAudioProcessor::OnPlayoutDataSourceChanged() {
void MediaStreamAudioProcessor::GetStats(AudioProcessorStats* stats) {
stats->typing_noise_detected =
(base::subtle::Acquire_Load(&typing_detected_) != false);
- GetAecStats(audio_processing_.get(), stats);
- if (echo_information_)
- echo_information_.get()->UpdateAecDelayStats(stats->echo_delay_median_ms);
+ GetAecStats(audio_processing_.get()->echo_cancellation(), stats);
}
void MediaStreamAudioProcessor::InitializeAudioProcessingModule(
@@ -401,11 +446,6 @@ void MediaStreamAudioProcessor::InitializeAudioProcessingModule(
audio_mirroring_ = audio_constraints.GetProperty(
MediaAudioConstraints::kGoogAudioMirroring);
- if (!IsAudioTrackProcessingEnabled()) {
- RecordProcessingState(AUDIO_PROCESSING_IN_WEBRTC);
- return;
- }
-
#if defined(OS_IOS)
// On iOS, VPIO provides built-in AGC and AEC.
const bool echo_cancellation = false;
@@ -431,13 +471,15 @@ void MediaStreamAudioProcessor::InitializeAudioProcessingModule(
MediaAudioConstraints::kGoogNoiseSuppression);
const bool goog_experimental_ns = audio_constraints.GetProperty(
MediaAudioConstraints::kGoogExperimentalNoiseSuppression);
- const bool goog_high_pass_filter = audio_constraints.GetProperty(
- MediaAudioConstraints::kGoogHighpassFilter);
-
+ const bool goog_beamforming = IsBeamformingEnabled(audio_constraints);
+ const bool goog_high_pass_filter = audio_constraints.GetProperty(
+ MediaAudioConstraints::kGoogHighpassFilter);
+ audio_proc_48kHz_support_ =
+ IsAudioProcessing48kHzSupportEnabled(audio_constraints);
// Return immediately if no goog constraint is enabled.
if (!echo_cancellation && !goog_experimental_aec && !goog_ns &&
!goog_high_pass_filter && !goog_typing_detection &&
- !goog_agc && !goog_experimental_ns) {
+ !goog_agc && !goog_experimental_ns && !goog_beamforming) {
RecordProcessingState(AUDIO_PROCESSING_DISABLED);
return;
}
@@ -448,10 +490,13 @@ void MediaStreamAudioProcessor::InitializeAudioProcessingModule(
config.Set<webrtc::DelayCorrection>(new webrtc::DelayCorrection(true));
if (goog_experimental_ns)
config.Set<webrtc::ExperimentalNs>(new webrtc::ExperimentalNs(true));
-#if defined(OS_MACOSX)
- if (base::FieldTrialList::FindFullName("NoReportedDelayOnMac") == "Enabled")
+ if (IsDelayAgnosticAecEnabled())
config.Set<webrtc::ReportedDelay>(new webrtc::ReportedDelay(false));
-#endif
+ if (goog_beamforming) {
+ ConfigureBeamforming(&config);
+ }
+ config.Set<webrtc::AudioProcessing48kHzSupport>(
+ new webrtc::AudioProcessing48kHzSupport(audio_proc_48kHz_support_));
// Create and configure the webrtc::AudioProcessing.
audio_processing_.reset(webrtc::AudioProcessing::Create(config));
@@ -487,6 +532,22 @@ void MediaStreamAudioProcessor::InitializeAudioProcessingModule(
RecordProcessingState(AUDIO_PROCESSING_ENABLED);
}
+void MediaStreamAudioProcessor::ConfigureBeamforming(webrtc::Config* config) {
+ bool enabled = false;
+ std::vector<webrtc::Point> geometry(1, webrtc::Point(0.f, 0.f, 0.f));
+#if defined(OS_CHROMEOS)
+ const std::string board = base::SysInfo::GetLsbReleaseBoard();
+ if (board.find("peach_pi") != std::string::npos) {
+ enabled = true;
+ geometry.push_back(webrtc::Point(0.050f, 0.f, 0.f));
+ } else if (board.find("swanky") != std::string::npos) {
+ enabled = true;
+ geometry.push_back(webrtc::Point(0.052f, 0.f, 0.f));
+ }
+#endif
+ config->Set<webrtc::Beamforming>(new webrtc::Beamforming(enabled, geometry));
+}
+
void MediaStreamAudioProcessor::InitializeCaptureFifo(
const media::AudioParameters& input_format) {
DCHECK(main_thread_checker_.CalledOnValidThread());
@@ -498,8 +559,16 @@ void MediaStreamAudioProcessor::InitializeCaptureFifo(
// use the input parameters (in which case, audio processing will convert
// at output) or ideally, have a backchannel from the sink to know what
// format it would prefer.
+#if defined(OS_ANDROID)
+ int audio_processing_sample_rate = AudioProcessing::kSampleRate16kHz;
+#else
+ int audio_processing_sample_rate = audio_proc_48kHz_support_ ?
+ AudioProcessing::kSampleRate48kHz :
+ AudioProcessing::kSampleRate32kHz;
+#endif
const int output_sample_rate = audio_processing_ ?
- kAudioProcessingSampleRate : input_format.sample_rate();
+ audio_processing_sample_rate :
+ input_format.sample_rate();
media::ChannelLayout output_channel_layout = audio_processing_ ?
media::GuessChannelLayout(kAudioProcessingNumberOfChannels) :
input_format.channel_layout();
@@ -546,14 +615,13 @@ void MediaStreamAudioProcessor::InitializeCaptureFifo(
new MediaStreamAudioFifo(input_format.channels(),
fifo_output_channels,
input_format.frames_per_buffer(),
- processing_frames));
+ processing_frames,
+ input_format.sample_rate()));
if (audio_processing_) {
output_bus_.reset(new MediaStreamAudioBus(output_format_.channels(),
output_frames));
}
- output_data_.reset(new int16[output_format_.GetBytesPerBuffer() /
- sizeof(int16)]);
}
void MediaStreamAudioProcessor::InitializeRenderFifoIfNeeded(
@@ -579,7 +647,8 @@ void MediaStreamAudioProcessor::InitializeRenderFifoIfNeeded(
new MediaStreamAudioFifo(number_of_channels,
number_of_channels,
frames_per_buffer,
- analysis_frames));
+ analysis_frames,
+ sample_rate));
}
int MediaStreamAudioProcessor::ProcessData(const float* const* process_ptrs,
@@ -631,6 +700,10 @@ int MediaStreamAudioProcessor::ProcessData(const float* const* process_ptrs,
base::subtle::Release_Store(&typing_detected_, detected);
}
+ if (echo_information_) {
+ echo_information_.get()->UpdateAecDelayStats(ap->echo_cancellation());
+ }
+
// Return 0 if the volume hasn't been changed, and otherwise the new volume.
return (agc->stream_analog_level() == volume) ?
0 : agc->stream_analog_level();
diff --git a/chromium/content/renderer/media/media_stream_audio_processor.h b/chromium/content/renderer/media/media_stream_audio_processor.h
index a905b3f6518..39e0ce6f1e9 100644
--- a/chromium/content/renderer/media/media_stream_audio_processor.h
+++ b/chromium/content/renderer/media/media_stream_audio_processor.h
@@ -51,10 +51,6 @@ class CONTENT_EXPORT MediaStreamAudioProcessor :
NON_EXPORTED_BASE(public AudioProcessorInterface),
NON_EXPORTED_BASE(public AecDumpMessageFilter::AecDumpDelegate) {
public:
- // Returns false if |kDisableAudioTrackProcessing| is set to true, otherwise
- // returns true.
- static bool IsAudioTrackProcessingEnabled();
-
// |playout_data_source| is used to register this class as a sink to the
// WebRtc playout data for processing AEC. If clients do not enable AEC,
// |playout_data_source| won't be used.
@@ -73,26 +69,25 @@ class CONTENT_EXPORT MediaStreamAudioProcessor :
// this method should be followed by calls to ProcessAndConsumeData() while
// it returns false, to pull out all available data.
// Called on the capture audio thread.
- void PushCaptureData(const media::AudioBus* audio_source);
-
- // Processes a block of 10 ms data from the internal FIFO and outputs it via
- // |out|. |out| is the address of the pointer that will be pointed to
- // the post-processed data if the method is returning a true. The lifetime
- // of the data represeted by |out| is guaranteed until this method is called
- // again.
+ void PushCaptureData(const media::AudioBus& audio_source,
+ base::TimeDelta capture_delay);
+
+ // Processes a block of 10 ms data from the internal FIFO, returning true if
+ // |processed_data| contains the result. Returns false and does not modify the
+ // outputs if the internal FIFO has insufficient data. The caller does NOT own
+ // the object pointed to by |*processed_data|.
+ // |capture_delay| is an adjustment on the |capture_delay| value provided in
+ // the last call to PushCaptureData().
// |new_volume| receives the new microphone volume from the AGC.
// The new microphone volume range is [0, 255], and the value will be 0 if
// the microphone volume should not be adjusted.
- // Returns true if the internal FIFO has at least 10 ms data for processing,
- // otherwise false.
// Called on the capture audio thread.
- //
- // TODO(ajm): Don't we want this to output float?
- bool ProcessAndConsumeData(base::TimeDelta capture_delay,
- int volume,
- bool key_pressed,
- int* new_volume,
- int16** out);
+ bool ProcessAndConsumeData(
+ int volume,
+ bool key_pressed,
+ media::AudioBus** processed_data,
+ base::TimeDelta* capture_delay,
+ int* new_volume);
// Stops the audio processor, no more AEC dump or render data after calling
// this method.
@@ -133,6 +128,7 @@ class CONTENT_EXPORT MediaStreamAudioProcessor :
// Helper to initialize the WebRtc AudioProcessing.
void InitializeAudioProcessingModule(
const blink::WebMediaConstraints& constraints, int effects);
+ void ConfigureBeamforming(webrtc::Config* config);
// Helper to initialize the capture converter.
void InitializeCaptureFifo(const media::AudioParameters& input_format);
@@ -163,8 +159,6 @@ class CONTENT_EXPORT MediaStreamAudioProcessor :
scoped_ptr<MediaStreamAudioFifo> capture_fifo_;
// Receives processing output.
scoped_ptr<MediaStreamAudioBus> output_bus_;
- // Receives interleaved int16 data for output.
- scoped_ptr<int16[]> output_data_;
// FIFO to provide 10 ms render chunks when the AEC is enabled.
scoped_ptr<MediaStreamAudioFifo> render_fifo_;
@@ -207,6 +201,9 @@ class CONTENT_EXPORT MediaStreamAudioProcessor :
// the libjingle thread through GetStats().
scoped_ptr<EchoInformation> echo_information_;
+ // Flag is enabled if AudioProcessing supports 48kHz sample rate.
+ bool audio_proc_48kHz_support_;
+
DISALLOW_COPY_AND_ASSIGN(MediaStreamAudioProcessor);
};
diff --git a/chromium/content/renderer/media/media_stream_audio_processor_options.cc b/chromium/content/renderer/media/media_stream_audio_processor_options.cc
index 537ef908b14..8029b25dc81 100644
--- a/chromium/content/renderer/media/media_stream_audio_processor_options.cc
+++ b/chromium/content/renderer/media/media_stream_audio_processor_options.cc
@@ -11,7 +11,6 @@
#include "base/metrics/histogram.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/time/time.h"
#include "content/common/media/media_stream_options.h"
#include "content/renderer/media/media_stream_constraints_util.h"
#include "content/renderer/media/media_stream_source.h"
@@ -35,10 +34,13 @@ const char MediaAudioConstraints::kGoogNoiseSuppression[] =
"googNoiseSuppression";
const char MediaAudioConstraints::kGoogExperimentalNoiseSuppression[] =
"googNoiseSuppression2";
+const char MediaAudioConstraints::kGoogBeamforming[] = "googBeamforming";
const char MediaAudioConstraints::kGoogHighpassFilter[] = "googHighpassFilter";
const char MediaAudioConstraints::kGoogTypingNoiseDetection[] =
"googTypingNoiseDetection";
const char MediaAudioConstraints::kGoogAudioMirroring[] = "googAudioMirroring";
+const char MediaAudioConstraints::kGoogAudioProcessing48kHzSupport[] =
+ "googAudioProcessing48kHzSupport";
namespace {
@@ -62,11 +64,14 @@ struct {
{ MediaAudioConstraints::kGoogHighpassFilter, true },
{ MediaAudioConstraints::kGoogTypingNoiseDetection, true },
{ MediaAudioConstraints::kGoogExperimentalNoiseSuppression, false },
+ { MediaAudioConstraints::kGoogBeamforming, false },
#if defined(OS_WIN)
{ kMediaStreamAudioDucking, true },
#else
{ kMediaStreamAudioDucking, false },
#endif
+ { kMediaStreamAudioHotword, false },
+ { MediaAudioConstraints::kGoogAudioProcessing48kHzSupport, false },
};
bool IsAudioProcessingConstraint(const std::string& key) {
@@ -79,6 +84,7 @@ enum DelayBasedEchoQuality {
DELAY_BASED_ECHO_QUALITY_GOOD = 0,
DELAY_BASED_ECHO_QUALITY_SPURIOUS,
DELAY_BASED_ECHO_QUALITY_BAD,
+ DELAY_BASED_ECHO_QUALITY_INVALID,
DELAY_BASED_ECHO_QUALITY_MAX
};
@@ -91,7 +97,11 @@ DelayBasedEchoQuality EchoDelayFrequencyToQuality(float delay_frequency) {
// delay is out of bounds 10-80 % of the time.
// DELAY_BASED_ECHO_QUALITY_BAD
// delay is mostly out of bounds >= 80 % of the time.
- if (delay_frequency <= kEchoDelayFrequencyLowerLimit)
+ // DELAY_BASED_ECHO_QUALITY_INVALID
+ // delay_frequency is negative which happens if we have insufficient data.
+ if (delay_frequency < 0)
+ return DELAY_BASED_ECHO_QUALITY_INVALID;
+ else if (delay_frequency <= kEchoDelayFrequencyLowerLimit)
return DELAY_BASED_ECHO_QUALITY_GOOD;
else if (delay_frequency < kEchoDelayFrequencyUpperLimit)
return DELAY_BASED_ECHO_QUALITY_SPURIOUS;
@@ -140,26 +150,7 @@ MediaAudioConstraints::MediaAudioConstraints(
MediaAudioConstraints::~MediaAudioConstraints() {}
-// TODO(xians): Remove this method after the APM in WebRtc is deprecated.
-bool MediaAudioConstraints::NeedsAudioProcessing() {
- if (GetEchoCancellationProperty())
- return true;
-
- for (size_t i = 0; i < arraysize(kDefaultAudioConstraints); ++i) {
- // |kEchoCancellation| and |kGoogEchoCancellation| have been convered by
- // GetEchoCancellationProperty().
- if (kDefaultAudioConstraints[i].key != kEchoCancellation &&
- kDefaultAudioConstraints[i].key != kGoogEchoCancellation &&
- IsAudioProcessingConstraint(kDefaultAudioConstraints[i].key) &&
- GetProperty(kDefaultAudioConstraints[i].key)) {
- return true;
- }
- }
-
- return false;
-}
-
-bool MediaAudioConstraints::GetProperty(const std::string& key) {
+bool MediaAudioConstraints::GetProperty(const std::string& key) const {
// Return the value if the constraint is specified in |constraints|,
// otherwise return the default value.
bool value = false;
@@ -169,7 +160,7 @@ bool MediaAudioConstraints::GetProperty(const std::string& key) {
return value;
}
-bool MediaAudioConstraints::GetEchoCancellationProperty() {
+bool MediaAudioConstraints::GetEchoCancellationProperty() const {
// If platform echo canceller is enabled, disable the software AEC.
if (effects_ & media::AudioParameters::ECHO_CANCELLER)
return false;
@@ -183,7 +174,7 @@ bool MediaAudioConstraints::GetEchoCancellationProperty() {
return GetProperty(kGoogEchoCancellation);
}
-bool MediaAudioConstraints::IsValid() {
+bool MediaAudioConstraints::IsValid() const {
blink::WebVector<blink::WebMediaConstraint> mandatory;
constraints_.getMandatoryConstraints(mandatory);
for (size_t i = 0; i < mandatory.size(); ++i) {
@@ -213,7 +204,8 @@ bool MediaAudioConstraints::IsValid() {
}
bool MediaAudioConstraints::GetDefaultValueForConstraint(
- const blink::WebMediaConstraints& constraints, const std::string& key) {
+ const blink::WebMediaConstraints& constraints,
+ const std::string& key) const {
// |kMediaStreamAudioDucking| is not restricted by
// |default_audio_processing_constraint_value_| since it does not require
// audio processing.
@@ -230,59 +222,57 @@ bool MediaAudioConstraints::GetDefaultValueForConstraint(
}
EchoInformation::EchoInformation()
- : echo_poor_delay_counts_(0),
- echo_total_delay_counts_(0),
- last_log_time_(base::TimeTicks::Now()) {}
+ : num_chunks_(0), echo_frames_received_(false) {
+}
EchoInformation::~EchoInformation() {}
-void EchoInformation::UpdateAecDelayStats(int delay) {
- // One way to get an indication of how well the echo cancellation performs is
- // to compare the, by AEC, estimated delay with the AEC filter length.
- // |kMaxAecFilterLengthMs| is the maximum delay we can allow before we
- // consider the AEC to fail. This value should not be larger than the filter
- // length used inside AEC. This is for now set to match the extended filter
- // mode which is turned on for all platforms.
- const int kMaxAecFilterLengthMs = 128;
- if ((delay < -2) || (delay > kMaxAecFilterLengthMs)) {
- // The |delay| is out of bounds which indicates that the echo cancellation
- // filter can not handle the echo. Hence, we have a potential full echo
- // case. |delay| values {-1, -2} are reserved for errors.
- ++echo_poor_delay_counts_;
+void EchoInformation::UpdateAecDelayStats(
+ webrtc::EchoCancellation* echo_cancellation) {
+ // Only start collecting stats if we know echo cancellation has measured an
+ // echo. Otherwise we clutter the stats with for example cases where only the
+ // microphone is used.
+ if (!echo_frames_received_ & !echo_cancellation->stream_has_echo())
+ return;
+
+ echo_frames_received_ = true;
+ // In WebRTC, three echo delay metrics are calculated and updated every
+ // five seconds. We use one of them, |fraction_poor_delays| to log in a UMA
+ // histogram an Echo Cancellation quality metric. The stat in WebRTC has a
+ // fixed aggregation window of five seconds, so we use the same query
+ // frequency to avoid logging old values.
+ const int kNumChunksInFiveSeconds = 500;
+ if (!echo_cancellation->is_delay_logging_enabled() ||
+ !echo_cancellation->is_enabled()) {
+ return;
}
- ++echo_total_delay_counts_;
- LogAecDelayStats();
-}
-void EchoInformation::LogAecDelayStats() {
- // We update the UMA statistics every 5 seconds.
- const int kTimeBetweenLogsInSeconds = 5;
- const base::TimeDelta time_since_last_log =
- base::TimeTicks::Now() - last_log_time_;
- if (time_since_last_log.InSeconds() < kTimeBetweenLogsInSeconds)
+ num_chunks_++;
+ if (num_chunks_ < kNumChunksInFiveSeconds) {
return;
+ }
- // Calculate how frequent the AEC delay was out of bounds since last time we
- // updated UMA histograms. Then store the result into one of three histogram
- // buckets; see DelayBasedEchoQuality.
- float poor_delay_frequency = 0.f;
- if (echo_total_delay_counts_ > 0) {
- poor_delay_frequency = static_cast<float>(echo_poor_delay_counts_) /
- static_cast<float>(echo_total_delay_counts_);
- UMA_HISTOGRAM_ENUMERATION("Media.AecDelayBasedQuality",
- EchoDelayFrequencyToQuality(poor_delay_frequency),
+ int dummy_median = 0, dummy_std = 0;
+ float fraction_poor_delays = 0;
+ if (echo_cancellation->GetDelayMetrics(
+ &dummy_median, &dummy_std, &fraction_poor_delays) ==
+ webrtc::AudioProcessing::kNoError) {
+ num_chunks_ = 0;
+ // Map |fraction_poor_delays| to an Echo Cancellation quality and log in UMA
+ // histogram. See DelayBasedEchoQuality for information on histogram
+ // buckets.
+ UMA_HISTOGRAM_ENUMERATION("WebRTC.AecDelayBasedQuality",
+ EchoDelayFrequencyToQuality(fraction_poor_delays),
DELAY_BASED_ECHO_QUALITY_MAX);
}
- echo_poor_delay_counts_ = 0;
- echo_total_delay_counts_ = 0;
- last_log_time_ = base::TimeTicks::Now();
}
void EnableEchoCancellation(AudioProcessing* audio_processing) {
#if defined(OS_ANDROID) || defined(OS_IOS)
const std::string group_name =
base::FieldTrialList::FindFullName("ReplaceAECMWithAEC");
- if (group_name.empty() || group_name != "Enabled") {
+ if (group_name.empty() ||
+ !(group_name == "Enabled" || group_name == "DefaultEnabled")) {
// Mobile devices are using AECM.
int err = audio_processing->echo_control_mobile()->set_routing_mode(
webrtc::EchoControlMobile::kSpeakerphone);
@@ -353,14 +343,14 @@ void EnableAutomaticGainControl(AudioProcessing* audio_processing) {
CHECK_EQ(err, 0);
}
-void GetAecStats(AudioProcessing* audio_processing,
+void GetAecStats(webrtc::EchoCancellation* echo_cancellation,
webrtc::AudioProcessorInterface::AudioProcessorStats* stats) {
// These values can take on valid negative values, so use the lowest possible
// level as default rather than -1.
stats->echo_return_loss = -100;
stats->echo_return_loss_enhancement = -100;
- // These values can also be negative, but in practice -1 is only used to
+ // The median value can also be negative, but in practice -1 is only used to
// signal insufficient data, since the resolution is limited to multiples
// of 4ms.
stats->echo_delay_median_ms = -1;
@@ -369,9 +359,9 @@ void GetAecStats(AudioProcessing* audio_processing,
// TODO(ajm): Re-enable this metric once we have a reliable implementation.
stats->aec_quality_min = -1.0f;
- if (!audio_processing->echo_cancellation()->are_metrics_enabled() ||
- !audio_processing->echo_cancellation()->is_delay_logging_enabled() ||
- !audio_processing->echo_cancellation()->is_enabled()) {
+ if (!echo_cancellation->are_metrics_enabled() ||
+ !echo_cancellation->is_delay_logging_enabled() ||
+ !echo_cancellation->is_enabled()) {
return;
}
@@ -379,14 +369,16 @@ void GetAecStats(AudioProcessing* audio_processing,
// here, but it appears to be unsuitable currently. Revisit after this is
// investigated: http://b/issue?id=5666755
webrtc::EchoCancellation::Metrics echo_metrics;
- if (!audio_processing->echo_cancellation()->GetMetrics(&echo_metrics)) {
+ if (!echo_cancellation->GetMetrics(&echo_metrics)) {
stats->echo_return_loss = echo_metrics.echo_return_loss.instant;
stats->echo_return_loss_enhancement =
echo_metrics.echo_return_loss_enhancement.instant;
}
int median = 0, std = 0;
- if (!audio_processing->echo_cancellation()->GetDelayMetrics(&median, &std)) {
+ float dummy = 0;
+ if (echo_cancellation->GetDelayMetrics(&median, &std, &dummy) ==
+ webrtc::AudioProcessing::kNoError) {
stats->echo_delay_median_ms = median;
stats->echo_delay_std_ms = std;
}
diff --git a/chromium/content/renderer/media/media_stream_audio_processor_options.h b/chromium/content/renderer/media/media_stream_audio_processor_options.h
index 66476597d7f..8484b08cd37 100644
--- a/chromium/content/renderer/media/media_stream_audio_processor_options.h
+++ b/chromium/content/renderer/media/media_stream_audio_processor_options.h
@@ -8,7 +8,6 @@
#include <string>
#include "base/files/file.h"
-#include "base/time/time.h"
#include "content/common/content_export.h"
#include "third_party/WebKit/public/platform/WebMediaConstraints.h"
#include "third_party/libjingle/source/talk/app/webrtc/mediastreaminterface.h"
@@ -17,6 +16,7 @@ namespace webrtc {
class AudioFrame;
class AudioProcessing;
+class EchoCancellation;
class MediaConstraintsInterface;
class TypingDetection;
@@ -41,9 +41,11 @@ class CONTENT_EXPORT MediaAudioConstraints {
static const char kGoogExperimentalAutoGainControl[];
static const char kGoogNoiseSuppression[];
static const char kGoogExperimentalNoiseSuppression[];
+ static const char kGoogBeamforming[];
static const char kGoogHighpassFilter[];
static const char kGoogTypingNoiseDetection[];
static const char kGoogAudioMirroring[];
+ static const char kGoogAudioProcessing48kHzSupport[];
// Merge |constraints| with |kDefaultAudioConstraints|. For any key which
// exists in both, the value from |constraints| is maintained, including its
@@ -59,30 +61,27 @@ class CONTENT_EXPORT MediaAudioConstraints {
int effects);
virtual ~MediaAudioConstraints();
- // Checks if any audio constraints are set that requires audio processing to
- // be applied.
- bool NeedsAudioProcessing();
-
// Gets the property of the constraint named by |key| in |constraints_|.
// Returns the constraint's value if the key is found; Otherwise returns the
// default value of the constraint.
// Note, for constraint of |kEchoCancellation| or |kGoogEchoCancellation|,
// clients should use GetEchoCancellationProperty().
- bool GetProperty(const std::string& key);
+ bool GetProperty(const std::string& key) const;
// Gets the property of echo cancellation defined in |constraints_|. The
// returned value depends on a combination of |effects_|, |kEchoCancellation|
// and |kGoogEchoCancellation| in |constraints_|.
- bool GetEchoCancellationProperty();
+ bool GetEchoCancellationProperty() const;
// Returns true if all the mandatory constraints in |constraints_| are valid;
// Otherwise return false.
- bool IsValid();
+ bool IsValid() const;
private:
// Gets the default value of constraint named by |key| in |constraints|.
bool GetDefaultValueForConstraint(
- const blink::WebMediaConstraints& constraints, const std::string& key);
+ const blink::WebMediaConstraints& constraints,
+ const std::string& key) const;
const blink::WebMediaConstraints constraints_;
const int effects_;
@@ -96,18 +95,13 @@ class CONTENT_EXPORT EchoInformation {
EchoInformation();
virtual ~EchoInformation();
- // Updates delay statistics with a new |delay|.
- void UpdateAecDelayStats(int delay);
+ void UpdateAecDelayStats(webrtc::EchoCancellation* echo_cancellation);
private:
- // Updates UMA histograms with an interval of |kTimeBetweenLogsInSeconds|.
- void LogAecDelayStats();
-
- // Counters for determining how often the estimated delay in the AEC is out of
- // bounds.
- int echo_poor_delay_counts_;
- int echo_total_delay_counts_;
- base::TimeTicks last_log_time_;
+ // Counter to track 5 seconds of processed 10 ms chunks in order to query a
+ // new metric from webrtc::EchoCancellation::GetEchoDelayMetrics().
+ int num_chunks_;
+ bool echo_frames_received_;
DISALLOW_COPY_AND_ASSIGN(EchoInformation);
};
@@ -136,7 +130,7 @@ void StopEchoCancellationDump(AudioProcessing* audio_processing);
void EnableAutomaticGainControl(AudioProcessing* audio_processing);
-void GetAecStats(AudioProcessing* audio_processing,
+void GetAecStats(webrtc::EchoCancellation* echo_cancellation,
webrtc::AudioProcessorInterface::AudioProcessorStats* stats);
} // namespace content
diff --git a/chromium/content/renderer/media/media_stream_audio_processor_unittest.cc b/chromium/content/renderer/media/media_stream_audio_processor_unittest.cc
index 91d7b32847d..a2f1b4e8729 100644
--- a/chromium/content/renderer/media/media_stream_audio_processor_unittest.cc
+++ b/chromium/content/renderer/media/media_stream_audio_processor_unittest.cc
@@ -2,14 +2,12 @@
// 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/files/file_util.h"
#include "base/logging.h"
#include "base/memory/aligned_memory.h"
#include "base/path_service.h"
#include "base/time/time.h"
-#include "content/public/common/content_switches.h"
#include "content/public/common/media_stream_request.h"
#include "content/renderer/media/media_stream_audio_processor.h"
#include "content/renderer/media/media_stream_audio_processor_options.h"
@@ -94,9 +92,14 @@ class MediaStreamAudioProcessorTest : public ::testing::Test {
data_bus_playout_to_use = data_bus_playout.get();
}
+ const base::TimeDelta input_capture_delay =
+ base::TimeDelta::FromMilliseconds(20);
+ const base::TimeDelta output_buffer_duration =
+ expected_output_buffer_size * base::TimeDelta::FromSeconds(1) /
+ expected_output_sample_rate;
for (int i = 0; i < kNumberOfPacketsForTest; ++i) {
data_bus->FromInterleaved(data_ptr, data_bus->frames(), 2);
- audio_processor->PushCaptureData(data_bus.get());
+ audio_processor->PushCaptureData(*data_bus, input_capture_delay);
// |audio_processor| does nothing when the audio processing is off in
// the processor.
@@ -119,12 +122,15 @@ class MediaStreamAudioProcessorTest : public ::testing::Test {
params.sample_rate(), 10);
}
- int16* output = NULL;
+ media::AudioBus* processed_data = nullptr;
+ base::TimeDelta capture_delay;
int new_volume = 0;
- while(audio_processor->ProcessAndConsumeData(
- base::TimeDelta::FromMilliseconds(10), 255, false, &new_volume,
- &output)) {
- EXPECT_TRUE(output != NULL);
+ while (audio_processor->ProcessAndConsumeData(
+ 255, false, &processed_data, &capture_delay, &new_volume)) {
+ EXPECT_TRUE(processed_data);
+ EXPECT_NEAR(input_capture_delay.InMillisecondsF(),
+ capture_delay.InMillisecondsF(),
+ output_buffer_duration.InMillisecondsF());
EXPECT_EQ(audio_processor->OutputFormat().sample_rate(),
expected_output_sample_rate);
EXPECT_EQ(audio_processor->OutputFormat().channels(),
@@ -175,30 +181,13 @@ class MediaStreamAudioProcessorTest : public ::testing::Test {
media::AudioParameters params_;
};
-TEST_F(MediaStreamAudioProcessorTest, WithoutAudioProcessing) {
- // Setup the audio processor with disabled flag on.
- CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kDisableAudioTrackProcessing);
- MockMediaConstraintFactory constraint_factory;
- scoped_refptr<WebRtcAudioDeviceImpl> webrtc_audio_device(
- new WebRtcAudioDeviceImpl());
- scoped_refptr<MediaStreamAudioProcessor> audio_processor(
- new rtc::RefCountedObject<MediaStreamAudioProcessor>(
- constraint_factory.CreateWebMediaConstraints(), 0,
- webrtc_audio_device.get()));
- EXPECT_FALSE(audio_processor->has_audio_processing());
- audio_processor->OnCaptureFormatChanged(params_);
-
- ProcessDataAndVerifyFormat(audio_processor.get(),
- params_.sample_rate(),
- params_.channels(),
- params_.sample_rate() / 100);
- // Set |audio_processor| to NULL to make sure |webrtc_audio_device| outlives
- // |audio_processor|.
- audio_processor = NULL;
-}
-
-TEST_F(MediaStreamAudioProcessorTest, WithAudioProcessing) {
+// Test crashing with ASAN on Android. crbug.com/468762
+#if defined(OS_ANDROID) && defined(ADDRESS_SANITIZER)
+#define MAYBE_WithAudioProcessing DISABLED_WithAudioProcessing
+#else
+#define MAYBE_WithAudioProcessing WithAudioProcessing
+#endif
+TEST_F(MediaStreamAudioProcessorTest, MAYBE_WithAudioProcessing) {
MockMediaConstraintFactory constraint_factory;
scoped_refptr<WebRtcAudioDeviceImpl> webrtc_audio_device(
new WebRtcAudioDeviceImpl());
@@ -288,7 +277,8 @@ TEST_F(MediaStreamAudioProcessorTest, VerifyConstraints) {
MediaAudioConstraints::kGoogExperimentalNoiseSuppression,
MediaAudioConstraints::kGoogHighpassFilter,
MediaAudioConstraints::kGoogNoiseSuppression,
- MediaAudioConstraints::kGoogTypingNoiseDetection
+ MediaAudioConstraints::kGoogTypingNoiseDetection,
+ kMediaStreamAudioHotword
};
// Verify mandatory constraints.
@@ -355,13 +345,20 @@ TEST_F(MediaStreamAudioProcessorTest, VerifyConstraints) {
for (size_t i = 0; i < arraysize(kDefaultAudioConstraints); ++i) {
EXPECT_FALSE(audio_constraints.GetProperty(kDefaultAudioConstraints[i]));
}
- EXPECT_FALSE(audio_constraints.NeedsAudioProcessing());
#if defined(OS_WIN)
EXPECT_TRUE(audio_constraints.GetProperty(kMediaStreamAudioDucking));
#else
EXPECT_FALSE(audio_constraints.GetProperty(kMediaStreamAudioDucking));
#endif
}
+
+ {
+ // |kMediaStreamAudioHotword| is always off by default.
+ MockMediaConstraintFactory constraint_factory;
+ MediaAudioConstraints audio_constraints(
+ constraint_factory.CreateWebMediaConstraints(), 0);
+ EXPECT_FALSE(audio_constraints.GetProperty(kMediaStreamAudioHotword));
+ }
}
TEST_F(MediaStreamAudioProcessorTest, ValidateConstraints) {
@@ -373,7 +370,13 @@ TEST_F(MediaStreamAudioProcessorTest, ValidateConstraints) {
EXPECT_FALSE(audio_constraints.IsValid());
}
-TEST_F(MediaStreamAudioProcessorTest, TestAllSampleRates) {
+// Test crashing with ASAN on Android. crbug.com/468762
+#if defined(OS_ANDROID) && defined(ADDRESS_SANITIZER)
+#define MAYBE_TestAllSampleRates DISABLED_TestAllSampleRates
+#else
+#define MAYBE_TestAllSampleRates TestAllSampleRates
+#endif
+TEST_F(MediaStreamAudioProcessorTest, MAYBE_TestAllSampleRates) {
MockMediaConstraintFactory constraint_factory;
scoped_refptr<WebRtcAudioDeviceImpl> webrtc_audio_device(
new WebRtcAudioDeviceImpl());
@@ -465,24 +468,23 @@ TEST_F(MediaStreamAudioProcessorTest, TestStereoAudio) {
float* left_channel_ptr = left_channel.get();
left_channel_ptr[0] = 1.0f;
- // A audio bus used for verifying the output data values.
- scoped_ptr<media::AudioBus> output_bus = media::AudioBus::Create(
- audio_processor->OutputFormat());
-
// Run the test consecutively to make sure the stereo channels are not
// flipped back and forth.
static const int kNumberOfPacketsForTest = 100;
+ const base::TimeDelta pushed_capture_delay =
+ base::TimeDelta::FromMilliseconds(42);
for (int i = 0; i < kNumberOfPacketsForTest; ++i) {
- audio_processor->PushCaptureData(wrapper.get());
+ audio_processor->PushCaptureData(*wrapper, pushed_capture_delay);
- int16* output = NULL;
+ media::AudioBus* processed_data = nullptr;
+ base::TimeDelta capture_delay;
int new_volume = 0;
EXPECT_TRUE(audio_processor->ProcessAndConsumeData(
- base::TimeDelta::FromMilliseconds(0), 0, false, &new_volume, &output));
- output_bus->FromInterleaved(output, output_bus->frames(), 2);
- EXPECT_TRUE(output != NULL);
- EXPECT_EQ(output_bus->channel(0)[0], 0);
- EXPECT_NE(output_bus->channel(1)[0], 0);
+ 0, false, &processed_data, &capture_delay, &new_volume));
+ EXPECT_TRUE(processed_data);
+ EXPECT_EQ(processed_data->channel(0)[0], 0);
+ EXPECT_NE(processed_data->channel(1)[0], 0);
+ EXPECT_EQ(pushed_capture_delay, capture_delay);
}
// Set |audio_processor| to NULL to make sure |webrtc_audio_device| outlives
@@ -490,7 +492,14 @@ TEST_F(MediaStreamAudioProcessorTest, TestStereoAudio) {
audio_processor = NULL;
}
-TEST_F(MediaStreamAudioProcessorTest, TestWithKeyboardMicChannel) {
+// Disabled on android clang builds due to crbug.com/470499
+#if defined(__clang__) && defined(OS_ANDROID)
+#define MAYBE_TestWithKeyboardMicChannel DISABLED_TestWithKeyboardMicChannel
+#else
+#define MAYBE_TestWithKeyboardMicChannel TestWithKeyboardMicChannel
+#endif
+
+TEST_F(MediaStreamAudioProcessorTest, MAYBE_TestWithKeyboardMicChannel) {
MockMediaConstraintFactory constraint_factory;
constraint_factory.AddMandatory(
MediaAudioConstraints::kGoogExperimentalNoiseSuppression, true);
@@ -516,33 +525,4 @@ TEST_F(MediaStreamAudioProcessorTest, TestWithKeyboardMicChannel) {
audio_processor = NULL;
}
-TEST_F(MediaStreamAudioProcessorTest,
- TestWithKeyboardMicChannelWithoutProcessing) {
- // Setup the audio processor with disabled flag on.
- CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kDisableAudioTrackProcessing);
- MockMediaConstraintFactory constraint_factory;
- scoped_refptr<WebRtcAudioDeviceImpl> webrtc_audio_device(
- new WebRtcAudioDeviceImpl());
- scoped_refptr<MediaStreamAudioProcessor> audio_processor(
- new rtc::RefCountedObject<MediaStreamAudioProcessor>(
- constraint_factory.CreateWebMediaConstraints(), 0,
- webrtc_audio_device.get()));
- EXPECT_FALSE(audio_processor->has_audio_processing());
-
- media::AudioParameters params(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
- media::CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC,
- 48000, 16, 512);
- audio_processor->OnCaptureFormatChanged(params);
-
- ProcessDataAndVerifyFormat(
- audio_processor.get(),
- params.sample_rate(),
- media::ChannelLayoutToChannelCount(media::CHANNEL_LAYOUT_STEREO),
- params.sample_rate() / 100);
- // Set |audio_processor| to NULL to make sure |webrtc_audio_device| outlives
- // |audio_processor|.
- audio_processor = NULL;
-}
-
} // namespace content
diff --git a/chromium/content/renderer/media/media_stream_audio_sink_owner.cc b/chromium/content/renderer/media/media_stream_audio_sink_owner.cc
index 664988d8213..04500499b6b 100644
--- a/chromium/content/renderer/media/media_stream_audio_sink_owner.cc
+++ b/chromium/content/renderer/media/media_stream_audio_sink_owner.cc
@@ -13,26 +13,11 @@ MediaStreamAudioSinkOwner::MediaStreamAudioSinkOwner(MediaStreamAudioSink* sink)
: delegate_(sink) {
}
-int MediaStreamAudioSinkOwner::OnData(const int16* audio_data,
- int sample_rate,
- int number_of_channels,
- int number_of_frames,
- const std::vector<int>& channels,
- int audio_delay_milliseconds,
- int current_volume,
- bool need_audio_processing,
- bool key_pressed) {
+void MediaStreamAudioSinkOwner::OnData(const media::AudioBus& audio_bus,
+ base::TimeTicks estimated_capture_time) {
base::AutoLock lock(lock_);
- // TODO(xians): Investigate on the possibility of not calling out with the
- // lock.
- if (delegate_) {
- delegate_->OnData(audio_data,
- sample_rate,
- number_of_channels,
- number_of_frames);
- }
-
- return 0;
+ if (delegate_)
+ delegate_->OnData(audio_bus, estimated_capture_time);
}
void MediaStreamAudioSinkOwner::OnSetFormat(
@@ -61,10 +46,4 @@ bool MediaStreamAudioSinkOwner::IsEqual(
return (other == delegate_);
}
-bool MediaStreamAudioSinkOwner::IsEqual(
- const PeerConnectionAudioSink* other) const {
- DCHECK(other);
- return false;
-}
-
} // namespace content
diff --git a/chromium/content/renderer/media/media_stream_audio_sink_owner.h b/chromium/content/renderer/media/media_stream_audio_sink_owner.h
index 23acf69d716..f9fddf28200 100644
--- a/chromium/content/renderer/media/media_stream_audio_sink_owner.h
+++ b/chromium/content/renderer/media/media_stream_audio_sink_owner.h
@@ -20,21 +20,13 @@ class MediaStreamAudioSinkOwner : public MediaStreamAudioTrackSink {
explicit MediaStreamAudioSinkOwner(MediaStreamAudioSink* sink);
// MediaStreamAudioTrackSink implementation.
- int OnData(const int16* audio_data,
- int sample_rate,
- int number_of_channels,
- int number_of_frames,
- const std::vector<int>& channels,
- int audio_delay_milliseconds,
- int current_volume,
- bool need_audio_processing,
- bool key_pressed) override;
+ void OnData(const media::AudioBus& audio_bus,
+ base::TimeTicks estimated_capture_time) override;
void OnSetFormat(const media::AudioParameters& params) override;
void OnReadyStateChanged(
blink::WebMediaStreamSource::ReadyState state) override;
void Reset() override;
bool IsEqual(const MediaStreamAudioSink* other) const override;
- bool IsEqual(const PeerConnectionAudioSink* other) const override;
protected:
~MediaStreamAudioSinkOwner() override {}
diff --git a/chromium/content/renderer/media/media_stream_audio_source.cc b/chromium/content/renderer/media/media_stream_audio_source.cc
index dad7699e850..c643140e4db 100644
--- a/chromium/content/renderer/media/media_stream_audio_source.cc
+++ b/chromium/content/renderer/media/media_stream_audio_source.cc
@@ -5,35 +5,21 @@
#include "content/renderer/media/media_stream_audio_source.h"
#include "content/renderer/render_frame_impl.h"
-#include "content/renderer/render_view_impl.h"
namespace content {
-namespace {
-// TODO(miu): This is a temporary hack until the Chrome audio vertical is
-// migrated for the Cross-Site Isolation project. http://crbug.com/392596
-int ToRenderViewId(int render_frame_id) {
- RenderFrameImpl* const frame =
- RenderFrameImpl::FromRoutingID(render_frame_id);
- RenderViewImpl* const view = frame ? frame->render_view() : NULL;
- return view ? view->GetRoutingID() : -1;
-}
-} // namespace
-
MediaStreamAudioSource::MediaStreamAudioSource(
int render_frame_id,
const StreamDeviceInfo& device_info,
const SourceStoppedCallback& stop_callback,
PeerConnectionDependencyFactory* factory)
- : render_view_id_(ToRenderViewId(render_frame_id)),
- factory_(factory) {
+ : render_frame_id_(render_frame_id), factory_(factory) {
SetDeviceInfo(device_info);
SetStopCallback(stop_callback);
}
MediaStreamAudioSource::MediaStreamAudioSource()
- : render_view_id_(-1),
- factory_(NULL) {
+ : render_frame_id_(-1), factory_(NULL) {
}
MediaStreamAudioSource::~MediaStreamAudioSource() {}
@@ -49,9 +35,8 @@ void MediaStreamAudioSource::AddTrack(
const ConstraintsCallback& callback) {
// TODO(xians): Properly implement for audio sources.
if (!local_audio_source_.get()) {
- if (!factory_->InitializeMediaStreamAudioSource(render_view_id_,
- constraints,
- this)) {
+ if (!factory_->InitializeMediaStreamAudioSource(render_frame_id_,
+ constraints, this)) {
// The source failed to start.
// UserMediaClientImpl rely on the |stop_callback| to be triggered when
// the last track is removed from the source. But in this case, the
diff --git a/chromium/content/renderer/media/media_stream_audio_source.h b/chromium/content/renderer/media/media_stream_audio_source.h
index 23e68f69c33..5495afac4f2 100644
--- a/chromium/content/renderer/media/media_stream_audio_source.h
+++ b/chromium/content/renderer/media/media_stream_audio_source.h
@@ -49,7 +49,7 @@ class CONTENT_EXPORT MediaStreamAudioSource
void DoStopSource() override;
private:
- const int render_view_id_; // Render view ID that created this source.
+ const int render_frame_id_;
PeerConnectionDependencyFactory* const factory_;
// This member holds an instance of webrtc::LocalAudioSource. This is used
diff --git a/chromium/content/renderer/media/media_stream_audio_track_sink.h b/chromium/content/renderer/media/media_stream_audio_track_sink.h
index 6e511bd6534..3c67ba387b9 100644
--- a/chromium/content/renderer/media/media_stream_audio_track_sink.h
+++ b/chromium/content/renderer/media/media_stream_audio_track_sink.h
@@ -9,28 +9,26 @@
#include "base/logging.h"
#include "base/memory/ref_counted.h"
+#include "base/time/time.h"
#include "media/audio/audio_parameters.h"
#include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
+namespace media {
+class AudioBus;
+}
+
namespace content {
class MediaStreamAudioSink;
-class PeerConnectionAudioSink;
// Interface for reference counted holder of audio stream audio track sink.
class MediaStreamAudioTrackSink
: public base::RefCountedThreadSafe<MediaStreamAudioTrackSink> {
public:
- virtual int OnData(const int16* audio_data,
- int sample_rate,
- int number_of_channels,
- int number_of_frames,
- const std::vector<int>& channels,
- int audio_delay_milliseconds,
- int current_volume,
- bool need_audio_processing,
- bool key_pressed) = 0;
-
+ // Note: OnData() and OnSetFormat() have the same meaning and semantics as in
+ // content::MediaStreamAudioSink. See comments there for usage info.
+ virtual void OnData(const media::AudioBus& audio_bus,
+ base::TimeTicks estimated_capture_time) = 0;
virtual void OnSetFormat(const media::AudioParameters& params) = 0;
virtual void OnReadyStateChanged(
@@ -39,7 +37,6 @@ class MediaStreamAudioTrackSink
virtual void Reset() = 0;
virtual bool IsEqual(const MediaStreamAudioSink* other) const = 0;
- virtual bool IsEqual(const PeerConnectionAudioSink* other) const = 0;
// Wrapper which allows to use std::find_if() when adding and removing
// sinks to/from the list.
@@ -51,14 +48,6 @@ class MediaStreamAudioTrackSink
}
MediaStreamAudioSink* sink_;
};
- struct WrapsPeerConnectionSink {
- WrapsPeerConnectionSink(PeerConnectionAudioSink* sink) : sink_(sink) {}
- bool operator()(
- const scoped_refptr<MediaStreamAudioTrackSink>& owner) const {
- return owner->IsEqual(sink_);
- }
- PeerConnectionAudioSink* sink_;
- };
protected:
virtual ~MediaStreamAudioTrackSink() {}
diff --git a/chromium/content/renderer/media/media_stream_center.h b/chromium/content/renderer/media/media_stream_center.h
index ef4fbaa0db5..d3627557022 100644
--- a/chromium/content/renderer/media/media_stream_center.h
+++ b/chromium/content/renderer/media/media_stream_center.h
@@ -30,37 +30,32 @@ class CONTENT_EXPORT MediaStreamCenter
public:
MediaStreamCenter(blink::WebMediaStreamCenterClient* client,
PeerConnectionDependencyFactory* factory);
- virtual ~MediaStreamCenter();
+ ~MediaStreamCenter() override;
private:
- virtual void didCreateMediaStreamTrack(
+ void didCreateMediaStreamTrack(
const blink::WebMediaStreamTrack& track) override;
- virtual void didEnableMediaStreamTrack(
+ void didEnableMediaStreamTrack(
const blink::WebMediaStreamTrack& track) override;
- virtual void didDisableMediaStreamTrack(
+ void didDisableMediaStreamTrack(
const blink::WebMediaStreamTrack& track) override;
- virtual void didStopLocalMediaStream(
- const blink::WebMediaStream& stream) override;
+ void didStopLocalMediaStream(const blink::WebMediaStream& stream) override;
- virtual bool didStopMediaStreamTrack(
+ bool didStopMediaStreamTrack(
const blink::WebMediaStreamTrack& track) override;
- virtual blink::WebAudioSourceProvider*
- createWebAudioSourceFromMediaStreamTrack(
- const blink::WebMediaStreamTrack& track) override;
-
+ blink::WebAudioSourceProvider* createWebAudioSourceFromMediaStreamTrack(
+ const blink::WebMediaStreamTrack& track) override;
- virtual void didCreateMediaStream(
- blink::WebMediaStream& stream) override;
+ void didCreateMediaStream(blink::WebMediaStream& stream) override;
- virtual bool didAddMediaStreamTrack(
- const blink::WebMediaStream& stream,
- const blink::WebMediaStreamTrack& track) override;
+ bool didAddMediaStreamTrack(const blink::WebMediaStream& stream,
+ const blink::WebMediaStreamTrack& track) override;
- virtual bool didRemoveMediaStreamTrack(
+ bool didRemoveMediaStreamTrack(
const blink::WebMediaStream& stream,
const blink::WebMediaStreamTrack& track) override;
diff --git a/chromium/content/renderer/media/media_stream_renderer_factory.cc b/chromium/content/renderer/media/media_stream_renderer_factory.cc
index df633bd8efa..20ee8ad9781 100644
--- a/chromium/content/renderer/media/media_stream_renderer_factory.cc
+++ b/chromium/content/renderer/media/media_stream_renderer_factory.cc
@@ -58,7 +58,6 @@ bool GetAuthorizedDeviceInfoForAudioRenderer(
scoped_refptr<WebRtcAudioRenderer> CreateRemoteAudioRenderer(
webrtc::MediaStreamInterface* stream,
- int routing_id,
int render_frame_id) {
if (stream->GetAudioTracks().empty())
return NULL;
@@ -76,15 +75,13 @@ scoped_refptr<WebRtcAudioRenderer> CreateRemoteAudioRenderer(
}
return new WebRtcAudioRenderer(
- GetPeerConnectionDependencyFactory()->GetWebRtcSignalingThread(),
- stream, routing_id, render_frame_id, session_id,
- sample_rate, buffer_size);
+ GetPeerConnectionDependencyFactory()->GetWebRtcSignalingThread(), stream,
+ render_frame_id, session_id, sample_rate, buffer_size);
}
scoped_refptr<WebRtcLocalAudioRenderer> CreateLocalAudioRenderer(
const blink::WebMediaStreamTrack& audio_track,
- int routing_id,
int render_frame_id) {
DVLOG(1) << "MediaStreamRendererFactory::CreateLocalAudioRenderer";
@@ -99,7 +96,6 @@ scoped_refptr<WebRtcLocalAudioRenderer> CreateLocalAudioRenderer(
// existing WebRtcAudioCapturer so that the renderer can use it as source.
return new WebRtcLocalAudioRenderer(
audio_track,
- routing_id,
render_frame_id,
session_id,
buffer_size);
@@ -137,8 +133,8 @@ MediaStreamRendererFactory::GetVideoFrameProvider(
}
scoped_refptr<MediaStreamAudioRenderer>
-MediaStreamRendererFactory::GetAudioRenderer(
- const GURL& url, int render_view_id, int render_frame_id) {
+MediaStreamRendererFactory::GetAudioRenderer(const GURL& url,
+ int render_frame_id) {
blink::WebMediaStream web_stream =
blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(url);
@@ -168,8 +164,7 @@ MediaStreamRendererFactory::GetAudioRenderer(
// TODO(xians): Add support for the case where the media stream contains
// multiple audio tracks.
- return CreateLocalAudioRenderer(audio_tracks[0], render_view_id,
- render_frame_id);
+ return CreateLocalAudioRenderer(audio_tracks[0], render_frame_id);
}
webrtc::MediaStreamInterface* stream =
@@ -184,8 +179,7 @@ MediaStreamRendererFactory::GetAudioRenderer(
// Share the existing renderer if any, otherwise create a new one.
scoped_refptr<WebRtcAudioRenderer> renderer(audio_device->renderer());
if (!renderer.get()) {
- renderer = CreateRemoteAudioRenderer(stream, render_view_id,
- render_frame_id);
+ renderer = CreateRemoteAudioRenderer(stream, render_frame_id);
if (renderer.get() && !audio_device->SetAudioRenderer(renderer.get()))
renderer = NULL;
diff --git a/chromium/content/renderer/media/media_stream_renderer_factory.h b/chromium/content/renderer/media/media_stream_renderer_factory.h
index eb07e1cae4f..86a644ee4a9 100644
--- a/chromium/content/renderer/media/media_stream_renderer_factory.h
+++ b/chromium/content/renderer/media/media_stream_renderer_factory.h
@@ -30,7 +30,6 @@ class CONTENT_EXPORT MediaStreamRendererFactory {
virtual scoped_refptr<MediaStreamAudioRenderer> GetAudioRenderer(
const GURL& url,
- int render_view_id,
int render_frame_id);
private:
diff --git a/chromium/content/renderer/media/media_stream_track.h b/chromium/content/renderer/media/media_stream_track.h
index 14b991aeb88..951880a6223 100644
--- a/chromium/content/renderer/media/media_stream_track.h
+++ b/chromium/content/renderer/media/media_stream_track.h
@@ -14,7 +14,6 @@
namespace webrtc {
class AudioTrackInterface;
-class MediaStreamTrackInterface;
} // namespace webrtc
namespace content {
@@ -28,8 +27,7 @@ class CONTENT_EXPORT MediaStreamTrack
explicit MediaStreamTrack(bool is_local_track);
virtual ~MediaStreamTrack();
- static MediaStreamTrack* GetTrack(
- const blink::WebMediaStreamTrack& track);
+ static MediaStreamTrack* GetTrack(const blink::WebMediaStreamTrack& track);
virtual void SetEnabled(bool enabled) = 0;
@@ -43,7 +41,8 @@ class CONTENT_EXPORT MediaStreamTrack
protected:
const bool is_local_track_;
- base::ThreadChecker thread_checker_;
+ // Used to DCHECK that we are called on Render main Thread.
+ base::ThreadChecker main_render_thread_checker_;
DISALLOW_COPY_AND_ASSIGN(MediaStreamTrack);
};
diff --git a/chromium/content/renderer/media/media_stream_video_capture_source_unittest.cc b/chromium/content/renderer/media/media_stream_video_capture_source_unittest.cc
index 038acef7709..7995437891e 100644
--- a/chromium/content/renderer/media/media_stream_video_capture_source_unittest.cc
+++ b/chromium/content/renderer/media/media_stream_video_capture_source_unittest.cc
@@ -24,14 +24,14 @@ class MockVideoCapturerDelegate : public VideoCapturerDelegate {
explicit MockVideoCapturerDelegate(const StreamDeviceInfo& device_info)
: VideoCapturerDelegate(device_info) {}
- MOCK_METHOD3(StartCapture,
- void(const media::VideoCaptureParams& params,
- const VideoCaptureDeliverFrameCB& new_frame_callback,
- const RunningCallback& running_callback));
+ MOCK_METHOD4(
+ StartCapture,
+ void(const media::VideoCaptureParams& params,
+ const VideoCaptureDeliverFrameCB& new_frame_callback,
+ scoped_refptr<base::SingleThreadTaskRunner>
+ frame_callback_task_runner,
+ const RunningCallback& running_callback));
MOCK_METHOD0(StopCapture, void());
-
- private:
- virtual ~MockVideoCapturerDelegate() {}
};
class MediaStreamVideoCapturerSourceTest : public testing::Test {
@@ -39,6 +39,7 @@ class MediaStreamVideoCapturerSourceTest : public testing::Test {
MediaStreamVideoCapturerSourceTest()
: child_process_(new ChildProcess()),
source_(NULL),
+ delegate_(NULL),
source_stopped_(false) {
}
@@ -48,26 +49,32 @@ class MediaStreamVideoCapturerSourceTest : public testing::Test {
}
void InitWithDeviceInfo(const StreamDeviceInfo& device_info) {
- delegate_ = new MockVideoCapturerDelegate(device_info);
+ scoped_ptr<MockVideoCapturerDelegate> delegate(
+ new MockVideoCapturerDelegate(device_info));
+ delegate_ = delegate.get();
source_ = new MediaStreamVideoCapturerSource(
- device_info,
base::Bind(&MediaStreamVideoCapturerSourceTest::OnSourceStopped,
base::Unretained(this)),
- delegate_);
+ delegate.Pass());
+ source_->SetDeviceInfo(device_info);
webkit_source_.initialize(base::UTF8ToUTF16("dummy_source_id"),
blink::WebMediaStreamSource::TypeVideo,
- base::UTF8ToUTF16("dummy_source_name"));
+ base::UTF8ToUTF16("dummy_source_name"),
+ false /* remote */ , true /* readonly */);
webkit_source_.setExtraData(source_);
webkit_source_id_ = webkit_source_.id();
}
+ MockMediaConstraintFactory* constraint_factory() {
+ return &constraint_factory_;
+ }
+
blink::WebMediaStreamTrack StartSource() {
- MockMediaConstraintFactory factory;
bool enabled = true;
// CreateVideoTrack will trigger OnConstraintsApplied.
return MediaStreamVideoTrack::CreateVideoTrack(
- source_, factory.CreateWebMediaConstraints(),
+ source_, constraint_factory_.CreateWebMediaConstraints(),
base::Bind(
&MediaStreamVideoCapturerSourceTest::OnConstraintsApplied,
base::Unretained(this)),
@@ -75,7 +82,7 @@ class MediaStreamVideoCapturerSourceTest : public testing::Test {
}
MockVideoCapturerDelegate& mock_delegate() {
- return *static_cast<MockVideoCapturerDelegate*>(delegate_.get());
+ return *delegate_;
}
void OnSourceStopped(const blink::WebMediaStreamSource& source) {
@@ -92,20 +99,33 @@ class MediaStreamVideoCapturerSourceTest : public testing::Test {
base::MessageLoopForUI message_loop_;
scoped_ptr<ChildProcess> child_process_;
blink::WebMediaStreamSource webkit_source_;
- MediaStreamVideoCapturerSource* source_; // owned by webkit_source.
- scoped_refptr<VideoCapturerDelegate> delegate_;
+ MediaStreamVideoCapturerSource* source_; // owned by |webkit_source_|.
+ MockVideoCapturerDelegate* delegate_; // owned by |source|.
blink::WebString webkit_source_id_;
bool source_stopped_;
+ MockMediaConstraintFactory constraint_factory_;
};
-TEST_F(MediaStreamVideoCapturerSourceTest, TabCaptureAllowResolutionChange) {
+TEST_F(MediaStreamVideoCapturerSourceTest, TabCaptureFixedResolutionByDefault) {
StreamDeviceInfo device_info;
device_info.device.type = MEDIA_TAB_VIDEO_CAPTURE;
InitWithDeviceInfo(device_info);
+ // No constraints are being provided to the implementation, so expect only
+ // default values.
+ media::VideoCaptureParams expected_params;
+ expected_params.requested_format.frame_size.SetSize(
+ MediaStreamVideoSource::kDefaultWidth,
+ MediaStreamVideoSource::kDefaultHeight);
+ expected_params.requested_format.frame_rate =
+ MediaStreamVideoSource::kDefaultFrameRate;
+ expected_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
+ expected_params.resolution_change_policy =
+ media::RESOLUTION_POLICY_FIXED_RESOLUTION;
+
EXPECT_CALL(mock_delegate(), StartCapture(
- testing::Field(&media::VideoCaptureParams::resolution_change_policy,
- media::RESOLUTION_POLICY_DYNAMIC_WITHIN_LIMIT),
+ expected_params,
+ testing::_,
testing::_,
testing::_)).Times(1);
blink::WebMediaStreamTrack track = StartSource();
@@ -114,14 +134,89 @@ TEST_F(MediaStreamVideoCapturerSourceTest, TabCaptureAllowResolutionChange) {
}
TEST_F(MediaStreamVideoCapturerSourceTest,
- DesktopCaptureAllowResolutionChange) {
+ DesktopCaptureAllowAnyResolutionChangeByDefault) {
StreamDeviceInfo device_info;
device_info.device.type = MEDIA_DESKTOP_VIDEO_CAPTURE;
InitWithDeviceInfo(device_info);
+ // No constraints are being provided to the implementation, so expect only
+ // default values.
+ media::VideoCaptureParams expected_params;
+ expected_params.requested_format.frame_size.SetSize(
+ MediaStreamVideoSource::kDefaultWidth,
+ MediaStreamVideoSource::kDefaultHeight);
+ expected_params.requested_format.frame_rate =
+ MediaStreamVideoSource::kDefaultFrameRate;
+ expected_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
+ expected_params.resolution_change_policy =
+ media::RESOLUTION_POLICY_ANY_WITHIN_LIMIT;
+
+ EXPECT_CALL(mock_delegate(), StartCapture(
+ expected_params,
+ testing::_,
+ testing::_,
+ testing::_)).Times(1);
+ blink::WebMediaStreamTrack track = StartSource();
+ // When the track goes out of scope, the source will be stopped.
+ EXPECT_CALL(mock_delegate(), StopCapture());
+}
+
+TEST_F(MediaStreamVideoCapturerSourceTest,
+ TabCaptureConstraintsImplyFixedAspectRatio) {
+ StreamDeviceInfo device_info;
+ device_info.device.type = MEDIA_TAB_VIDEO_CAPTURE;
+ InitWithDeviceInfo(device_info);
+
+ // Specify max and min size constraints that have the same ~16:9 aspect ratio.
+ constraint_factory()->AddMandatory(MediaStreamVideoSource::kMaxWidth, 1920);
+ constraint_factory()->AddMandatory(MediaStreamVideoSource::kMaxHeight, 1080);
+ constraint_factory()->AddMandatory(MediaStreamVideoSource::kMinWidth, 854);
+ constraint_factory()->AddMandatory(MediaStreamVideoSource::kMinHeight, 480);
+ constraint_factory()->AddMandatory(MediaStreamVideoSource::kMaxFrameRate,
+ 60.0);
+
+ media::VideoCaptureParams expected_params;
+ expected_params.requested_format.frame_size.SetSize(1920, 1080);
+ expected_params.requested_format.frame_rate = 60.0;
+ expected_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
+ expected_params.resolution_change_policy =
+ media::RESOLUTION_POLICY_FIXED_ASPECT_RATIO;
+
EXPECT_CALL(mock_delegate(), StartCapture(
testing::Field(&media::VideoCaptureParams::resolution_change_policy,
- media::RESOLUTION_POLICY_DYNAMIC_WITHIN_LIMIT),
+ media::RESOLUTION_POLICY_FIXED_ASPECT_RATIO),
+ testing::_,
+ testing::_,
+ testing::_)).Times(1);
+ blink::WebMediaStreamTrack track = StartSource();
+ // When the track goes out of scope, the source will be stopped.
+ EXPECT_CALL(mock_delegate(), StopCapture());
+}
+
+TEST_F(MediaStreamVideoCapturerSourceTest,
+ TabCaptureConstraintsImplyAllowingAnyResolutionChange) {
+ StreamDeviceInfo device_info;
+ device_info.device.type = MEDIA_TAB_VIDEO_CAPTURE;
+ InitWithDeviceInfo(device_info);
+
+ // Specify max and min size constraints with different aspect ratios.
+ constraint_factory()->AddMandatory(MediaStreamVideoSource::kMaxWidth, 1920);
+ constraint_factory()->AddMandatory(MediaStreamVideoSource::kMaxHeight, 1080);
+ constraint_factory()->AddMandatory(MediaStreamVideoSource::kMinWidth, 0);
+ constraint_factory()->AddMandatory(MediaStreamVideoSource::kMinHeight, 0);
+ constraint_factory()->AddMandatory(MediaStreamVideoSource::kMaxFrameRate,
+ 60.0);
+
+ media::VideoCaptureParams expected_params;
+ expected_params.requested_format.frame_size.SetSize(1920, 1080);
+ expected_params.requested_format.frame_rate = 60.0;
+ expected_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
+ expected_params.resolution_change_policy =
+ media::RESOLUTION_POLICY_ANY_WITHIN_LIMIT;
+
+ EXPECT_CALL(mock_delegate(), StartCapture(
+ expected_params,
+ testing::_,
testing::_,
testing::_)).Times(1);
blink::WebMediaStreamTrack track = StartSource();
@@ -132,27 +227,30 @@ TEST_F(MediaStreamVideoCapturerSourceTest,
TEST_F(MediaStreamVideoCapturerSourceTest, Ended) {
StreamDeviceInfo device_info;
device_info.device.type = MEDIA_DESKTOP_VIDEO_CAPTURE;
- delegate_ = new VideoCapturerDelegate(device_info);
+ scoped_ptr<VideoCapturerDelegate> delegate(
+ new VideoCapturerDelegate(device_info));
+ VideoCapturerDelegate* delegate_ptr = delegate.get();
source_ = new MediaStreamVideoCapturerSource(
- device_info,
base::Bind(&MediaStreamVideoCapturerSourceTest::OnSourceStopped,
base::Unretained(this)),
- delegate_);
+ delegate.Pass());
+ source_->SetDeviceInfo(device_info);
webkit_source_.initialize(base::UTF8ToUTF16("dummy_source_id"),
blink::WebMediaStreamSource::TypeVideo,
- base::UTF8ToUTF16("dummy_source_name"));
+ base::UTF8ToUTF16("dummy_source_name"),
+ false /* remote */ , true /* readonly */);
webkit_source_.setExtraData(source_);
webkit_source_id_ = webkit_source_.id();
blink::WebMediaStreamTrack track = StartSource();
message_loop_.RunUntilIdle();
- delegate_->OnStateUpdateOnRenderThread(VIDEO_CAPTURE_STATE_STARTED);
+ delegate_ptr->OnStateUpdate(VIDEO_CAPTURE_STATE_STARTED);
message_loop_.RunUntilIdle();
EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateLive,
webkit_source_.readyState());
EXPECT_FALSE(source_stopped_);
- delegate_->OnStateUpdateOnRenderThread(VIDEO_CAPTURE_STATE_ERROR);
+ delegate_ptr->OnStateUpdate(VIDEO_CAPTURE_STATE_ERROR);
message_loop_.RunUntilIdle();
EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateEnded,
webkit_source_.readyState());
@@ -163,24 +261,30 @@ TEST_F(MediaStreamVideoCapturerSourceTest, Ended) {
class FakeMediaStreamVideoSink : public MediaStreamVideoSink {
public:
FakeMediaStreamVideoSink(base::TimeTicks* capture_time,
+ media::VideoFrameMetadata* metadata,
base::Closure got_frame_cb)
: capture_time_(capture_time),
+ metadata_(metadata),
got_frame_cb_(got_frame_cb) {
}
void OnVideoFrame(const scoped_refptr<media::VideoFrame>& frame,
- const media::VideoCaptureFormat& format,
const base::TimeTicks& capture_time) {
*capture_time_ = capture_time;
+ metadata_->Clear();
+ base::DictionaryValue tmp;
+ frame->metadata()->MergeInternalValuesInto(&tmp);
+ metadata_->MergeInternalValuesFrom(tmp);
base::ResetAndReturn(&got_frame_cb_).Run();
}
private:
- base::TimeTicks* capture_time_;
+ base::TimeTicks* const capture_time_;
+ media::VideoFrameMetadata* const metadata_;
base::Closure got_frame_cb_;
};
-TEST_F(MediaStreamVideoCapturerSourceTest, CaptureTime) {
+TEST_F(MediaStreamVideoCapturerSourceTest, CaptureTimeAndMetadataPlumbing) {
StreamDeviceInfo device_info;
device_info.device.type = MEDIA_DESKTOP_VIDEO_CAPTURE;
InitWithDeviceInfo(device_info);
@@ -191,35 +295,41 @@ TEST_F(MediaStreamVideoCapturerSourceTest, CaptureTime) {
EXPECT_CALL(mock_delegate(), StartCapture(
testing::_,
testing::_,
+ testing::_,
testing::_))
.Times(1)
.WillOnce(testing::DoAll(testing::SaveArg<1>(&deliver_frame_cb),
- testing::SaveArg<2>(&running_cb)));
+ testing::SaveArg<3>(&running_cb)));
EXPECT_CALL(mock_delegate(), StopCapture());
blink::WebMediaStreamTrack track = StartSource();
- running_cb.Run(MEDIA_DEVICE_OK);
+ running_cb.Run(true);
base::RunLoop run_loop;
base::TimeTicks reference_capture_time =
base::TimeTicks::FromInternalValue(60013);
base::TimeTicks capture_time;
+ media::VideoFrameMetadata metadata;
FakeMediaStreamVideoSink fake_sink(
&capture_time,
+ &metadata,
media::BindToCurrentLoop(run_loop.QuitClosure()));
FakeMediaStreamVideoSink::AddToVideoTrack(
&fake_sink,
base::Bind(&FakeMediaStreamVideoSink::OnVideoFrame,
base::Unretained(&fake_sink)),
track);
+ const scoped_refptr<media::VideoFrame> frame =
+ media::VideoFrame::CreateBlackFrame(gfx::Size(2, 2));
+ frame->metadata()->SetDouble(media::VideoFrameMetadata::FRAME_RATE, 30.0);
child_process_->io_message_loop()->PostTask(
- FROM_HERE,
- base::Bind(deliver_frame_cb,
- media::VideoFrame::CreateBlackFrame(gfx::Size(2, 2)),
- media::VideoCaptureFormat(),
- reference_capture_time));
+ FROM_HERE, base::Bind(deliver_frame_cb, frame, reference_capture_time));
run_loop.Run();
FakeMediaStreamVideoSink::RemoveFromVideoTrack(&fake_sink, track);
EXPECT_EQ(reference_capture_time, capture_time);
+ double metadata_value;
+ EXPECT_TRUE(metadata.GetDouble(media::VideoFrameMetadata::FRAME_RATE,
+ &metadata_value));
+ EXPECT_EQ(30.0, metadata_value);
}
} // namespace content
diff --git a/chromium/content/renderer/media/media_stream_video_capturer_source.cc b/chromium/content/renderer/media/media_stream_video_capturer_source.cc
index 7dcd92e3739..f2c1fd07c22 100644
--- a/chromium/content/renderer/media/media_stream_video_capturer_source.cc
+++ b/chromium/content/renderer/media/media_stream_video_capturer_source.cc
@@ -7,41 +7,172 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/location.h"
+#include "content/public/common/media_stream_request.h"
+#include "content/renderer/media/media_stream_constraints_util.h"
#include "content/renderer/media/video_capture_impl_manager.h"
#include "content/renderer/render_thread_impl.h"
#include "media/base/bind_to_current_loop.h"
+#include "media/base/limits.h"
#include "media/base/video_frame.h"
+namespace content {
+
namespace {
-struct SourceVideoResolution {
+// Resolutions used if the source doesn't support capability enumeration.
+struct {
int width;
int height;
-};
+} const kVideoResolutions[] = {{1920, 1080},
+ {1280, 720},
+ {960, 720},
+ {640, 480},
+ {640, 360},
+ {320, 240},
+ {320, 180}};
-// Resolutions used if the source doesn't support capability enumeration.
-const SourceVideoResolution kVideoResolutions[] = {{1920, 1080},
- {1280, 720},
- {960, 720},
- {640, 480},
- {640, 360},
- {320, 240},
- {320, 180}};
// Frame rates for sources with no support for capability enumeration.
const int kVideoFrameRates[] = {30, 60};
// Hard upper-bound frame rate for tab/desktop capture.
const double kMaxScreenCastFrameRate = 120.0;
-} // namespace
+// Returns true if the value for width or height is reasonable.
+bool DimensionValueIsValid(int x) {
+ return x > 0 && x <= media::limits::kMaxDimension;
+}
-namespace content {
+// Returns true if the value for frame rate is reasonable.
+bool FrameRateValueIsValid(double frame_rate) {
+ return (frame_rate > (1.0 / 60.0)) && // Lower-bound: One frame per minute.
+ (frame_rate <= media::limits::kMaxFramesPerSecond);
+}
+
+// Returns true if the aspect ratio of |a| and |b| are equivalent to two
+// significant digits.
+bool AreNearlyEquivalentInAspectRatio(const gfx::Size& a, const gfx::Size& b) {
+ DCHECK(!a.IsEmpty());
+ DCHECK(!b.IsEmpty());
+ const int aspect_ratio_a = (100 * a.width()) / a.height();
+ const int aspect_ratio_b = (100 * b.width()) / b.height();
+ return aspect_ratio_a == aspect_ratio_b;
+}
+
+// Interprets the properties in |constraints| to override values in |params| and
+// determine the resolution change policy.
+void SetScreenCastParamsFromConstraints(
+ const blink::WebMediaConstraints& constraints,
+ MediaStreamType type,
+ media::VideoCaptureParams* params) {
+ // The default resolution change policies for tab versus desktop capture are
+ // the way they are for legacy reasons.
+ if (type == MEDIA_TAB_VIDEO_CAPTURE) {
+ params->resolution_change_policy =
+ media::RESOLUTION_POLICY_FIXED_RESOLUTION;
+ } else if (type == MEDIA_DESKTOP_VIDEO_CAPTURE) {
+ params->resolution_change_policy =
+ media::RESOLUTION_POLICY_ANY_WITHIN_LIMIT;
+ } else {
+ NOTREACHED();
+ }
+
+ // If the maximum frame resolution was provided in the constraints, use it if
+ // either: 1) none has been set yet; or 2) the maximum specificed is smaller
+ // than the current setting.
+ int width = 0;
+ int height = 0;
+ gfx::Size desired_max_frame_size;
+ if (GetConstraintValueAsInteger(constraints,
+ MediaStreamVideoSource::kMaxWidth,
+ &width) &&
+ GetConstraintValueAsInteger(constraints,
+ MediaStreamVideoSource::kMaxHeight,
+ &height) &&
+ DimensionValueIsValid(width) &&
+ DimensionValueIsValid(height)) {
+ desired_max_frame_size.SetSize(width, height);
+ if (params->requested_format.frame_size.IsEmpty() ||
+ desired_max_frame_size.width() <
+ params->requested_format.frame_size.width() ||
+ desired_max_frame_size.height() <
+ params->requested_format.frame_size.height()) {
+ params->requested_format.frame_size = desired_max_frame_size;
+ }
+ }
+
+ // Set the default frame resolution if none was provided.
+ if (params->requested_format.frame_size.IsEmpty()) {
+ params->requested_format.frame_size.SetSize(
+ MediaStreamVideoSource::kDefaultWidth,
+ MediaStreamVideoSource::kDefaultHeight);
+ }
+
+ // If the maximum frame rate was provided, use it if either: 1) none has been
+ // set yet; or 2) the maximum specificed is smaller than the current setting.
+ double frame_rate = 0.0;
+ if (GetConstraintValueAsDouble(constraints,
+ MediaStreamVideoSource::kMaxFrameRate,
+ &frame_rate) &&
+ FrameRateValueIsValid(frame_rate)) {
+ if (params->requested_format.frame_rate <= 0.0f ||
+ frame_rate < params->requested_format.frame_rate) {
+ params->requested_format.frame_rate = frame_rate;
+ }
+ }
+
+ // Set the default frame rate if none was provided.
+ if (params->requested_format.frame_rate <= 0.0f) {
+ params->requested_format.frame_rate =
+ MediaStreamVideoSource::kDefaultFrameRate;
+ }
+
+ // If the minimum frame resolution was provided, compare it to the maximum
+ // frame resolution to determine the intended resolution change policy.
+ if (!desired_max_frame_size.IsEmpty() &&
+ GetConstraintValueAsInteger(constraints,
+ MediaStreamVideoSource::kMinWidth,
+ &width) &&
+ GetConstraintValueAsInteger(constraints,
+ MediaStreamVideoSource::kMinHeight,
+ &height) &&
+ width <= desired_max_frame_size.width() &&
+ height <= desired_max_frame_size.height()) {
+ if (width == desired_max_frame_size.width() &&
+ height == desired_max_frame_size.height()) {
+ // Constraints explicitly require a single frame resolution.
+ params->resolution_change_policy =
+ media::RESOLUTION_POLICY_FIXED_RESOLUTION;
+ } else if (DimensionValueIsValid(width) &&
+ DimensionValueIsValid(height) &&
+ AreNearlyEquivalentInAspectRatio(gfx::Size(width, height),
+ desired_max_frame_size)) {
+ // Constraints only mention a single aspect ratio.
+ params->resolution_change_policy =
+ media::RESOLUTION_POLICY_FIXED_ASPECT_RATIO;
+ } else {
+ // Constraints specify a minimum resolution that is smaller than the
+ // maximum resolution and has a different aspect ratio (possibly even
+ // 0x0). This indicates any frame resolution and aspect ratio is
+ // acceptable.
+ params->resolution_change_policy =
+ media::RESOLUTION_POLICY_ANY_WITHIN_LIMIT;
+ }
+ }
+
+ DVLOG(1) << "SetScreenCastParamsFromConstraints: "
+ << params->requested_format.ToString()
+ << " with resolution change policy "
+ << params->resolution_change_policy;
+}
+
+} // namespace
VideoCapturerDelegate::VideoCapturerDelegate(
const StreamDeviceInfo& device_info)
: session_id_(device_info.session_id),
is_screen_cast_(device_info.device.type == MEDIA_TAB_VIDEO_CAPTURE ||
- device_info.device.type == MEDIA_DESKTOP_VIDEO_CAPTURE) {
+ device_info.device.type == MEDIA_DESKTOP_VIDEO_CAPTURE),
+ weak_factory_(this) {
DVLOG(3) << "VideoCapturerDelegate::ctor";
// NULL in unit test.
@@ -54,6 +185,7 @@ VideoCapturerDelegate::VideoCapturerDelegate(
}
VideoCapturerDelegate::~VideoCapturerDelegate() {
+ DCHECK(thread_checker_.CalledOnValidThread());
DVLOG(3) << "VideoCapturerDelegate::dtor";
if (!release_device_cb_.is_null())
release_device_cb_.Run();
@@ -86,7 +218,7 @@ void VideoCapturerDelegate::GetCurrentSupportedFormats(
// NULL in unit test.
if (!RenderThreadImpl::current())
return;
- VideoCaptureImplManager* manager =
+ VideoCaptureImplManager* const manager =
RenderThreadImpl::current()->video_capture_impl_manager();
if (!manager)
return;
@@ -96,12 +228,14 @@ void VideoCapturerDelegate::GetCurrentSupportedFormats(
session_id_,
media::BindToCurrentLoop(
base::Bind(
- &VideoCapturerDelegate::OnDeviceFormatsInUseReceived, this)));
+ &VideoCapturerDelegate::OnDeviceFormatsInUseReceived,
+ weak_factory_.GetWeakPtr())));
}
void VideoCapturerDelegate::StartCapture(
const media::VideoCaptureParams& params,
const VideoCaptureDeliverFrameCB& new_frame_callback,
+ scoped_refptr<base::SingleThreadTaskRunner> frame_callback_task_runner,
const RunningCallback& running_callback) {
DCHECK(params.requested_format.IsValid());
DCHECK(thread_checker_.CalledOnValidThread());
@@ -110,16 +244,24 @@ void VideoCapturerDelegate::StartCapture(
// NULL in unit test.
if (!RenderThreadImpl::current())
return;
- VideoCaptureImplManager* manager =
+ VideoCaptureImplManager* const manager =
RenderThreadImpl::current()->video_capture_impl_manager();
if (!manager)
return;
+ if (frame_callback_task_runner !=
+ RenderThreadImpl::current()->GetIOMessageLoopProxy()) {
+ DCHECK(false) << "Only IO thread supported right now.";
+ running_callback.Run(false);
+ return;
+ }
+
stop_capture_cb_ =
manager->StartCapture(
session_id_,
- params,
- media::BindToCurrentLoop(base::Bind(
- &VideoCapturerDelegate::OnStateUpdateOnRenderThread, this)),
+ params,
+ media::BindToCurrentLoop(base::Bind(
+ &VideoCapturerDelegate::OnStateUpdate,
+ weak_factory_.GetWeakPtr())),
new_frame_callback);
}
@@ -134,17 +276,16 @@ void VideoCapturerDelegate::StopCapture() {
source_formats_callback_.Reset();
}
-void VideoCapturerDelegate::OnStateUpdateOnRenderThread(
+void VideoCapturerDelegate::OnStateUpdate(
VideoCaptureState state) {
DCHECK(thread_checker_.CalledOnValidThread());
- DVLOG(3) << "OnStateUpdateOnRenderThread state = " << state;
+ DVLOG(3) << "OnStateUpdate state = " << state;
if (state == VIDEO_CAPTURE_STATE_STARTED && !running_callback_.is_null()) {
- running_callback_.Run(MEDIA_DEVICE_OK);
+ running_callback_.Run(true);
return;
}
if (state > VIDEO_CAPTURE_STATE_STARTED && !running_callback_.is_null()) {
- base::ResetAndReturn(&running_callback_).Run(
- MEDIA_DEVICE_TRACK_START_FAILURE);
+ base::ResetAndReturn(&running_callback_).Run(false);
}
}
@@ -167,16 +308,17 @@ void VideoCapturerDelegate::OnDeviceFormatsInUseReceived(
// NULL in unit test.
if (!RenderThreadImpl::current())
return;
- VideoCaptureImplManager* manager =
+ VideoCaptureImplManager* const manager =
RenderThreadImpl::current()->video_capture_impl_manager();
if (!manager)
return;
+
manager->GetDeviceSupportedFormats(
session_id_,
media::BindToCurrentLoop(
base::Bind(
&VideoCapturerDelegate::OnDeviceSupportedFormatsEnumerated,
- this)));
+ weak_factory_.GetWeakPtr())));
}
void VideoCapturerDelegate::OnDeviceSupportedFormatsEnumerated(
@@ -189,35 +331,38 @@ void VideoCapturerDelegate::OnDeviceSupportedFormatsEnumerated(
if (source_formats_callback_.is_null())
return;
if (formats.size()) {
- source_formats_callback_.Run(formats);
+ base::ResetAndReturn(&source_formats_callback_).Run(formats);
} else {
// The capture device doesn't seem to support capability enumeration,
// compose a fallback list of capabilities.
media::VideoCaptureFormats default_formats;
- for (size_t i = 0; i < arraysize(kVideoResolutions); ++i) {
- for (size_t j = 0; j < arraysize(kVideoFrameRates); ++j) {
+ for (const auto& resolution : kVideoResolutions) {
+ for (const auto frame_rate : kVideoFrameRates) {
default_formats.push_back(media::VideoCaptureFormat(
- gfx::Size(kVideoResolutions[i].width, kVideoResolutions[i].height),
- kVideoFrameRates[j], media::PIXEL_FORMAT_I420));
+ gfx::Size(resolution.width, resolution.height),
+ frame_rate,
+ media::PIXEL_FORMAT_I420));
}
}
- source_formats_callback_.Run(default_formats);
+ base::ResetAndReturn(&source_formats_callback_).Run(default_formats);
}
- source_formats_callback_.Reset();
}
MediaStreamVideoCapturerSource::MediaStreamVideoCapturerSource(
- const StreamDeviceInfo& device_info,
const SourceStoppedCallback& stop_callback,
- const scoped_refptr<VideoCapturerDelegate>& delegate)
- : delegate_(delegate) {
- SetDeviceInfo(device_info);
+ scoped_ptr<media::VideoCapturerSource> delegate)
+ : delegate_(delegate.Pass()) {
SetStopCallback(stop_callback);
}
MediaStreamVideoCapturerSource::~MediaStreamVideoCapturerSource() {
}
+void MediaStreamVideoCapturerSource::SetDeviceInfo(
+ const StreamDeviceInfo& device_info) {
+ MediaStreamVideoSource::SetDeviceInfo(device_info);
+}
+
void MediaStreamVideoCapturerSource::GetCurrentSupportedFormats(
int max_requested_width,
int max_requested_height,
@@ -232,18 +377,22 @@ void MediaStreamVideoCapturerSource::GetCurrentSupportedFormats(
void MediaStreamVideoCapturerSource::StartSourceImpl(
const media::VideoCaptureFormat& format,
+ const blink::WebMediaConstraints& constraints,
const VideoCaptureDeliverFrameCB& frame_callback) {
media::VideoCaptureParams new_params;
new_params.requested_format = format;
if (device_info().device.type == MEDIA_TAB_VIDEO_CAPTURE ||
device_info().device.type == MEDIA_DESKTOP_VIDEO_CAPTURE) {
- new_params.resolution_change_policy =
- media::RESOLUTION_POLICY_DYNAMIC_WITHIN_LIMIT;
+ SetScreenCastParamsFromConstraints(
+ constraints, device_info().device.type, &new_params);
}
delegate_->StartCapture(
new_params,
frame_callback,
- base::Bind(&MediaStreamVideoCapturerSource::OnStartDone,
+ RenderThreadImpl::current() ?
+ RenderThreadImpl::current()->GetIOMessageLoopProxy() :
+ nullptr,
+ base::Bind(&MediaStreamVideoCapturerSource::OnStarted,
base::Unretained(this)));
}
@@ -251,4 +400,8 @@ void MediaStreamVideoCapturerSource::StopSourceImpl() {
delegate_->StopCapture();
}
+void MediaStreamVideoCapturerSource::OnStarted(bool result) {
+ OnStartDone(result ? MEDIA_DEVICE_OK : MEDIA_DEVICE_TRACK_START_FAILURE);
+}
+
} // namespace content
diff --git a/chromium/content/renderer/media/media_stream_video_capturer_source.h b/chromium/content/renderer/media/media_stream_video_capturer_source.h
index e22b6db9c60..3722b9d1881 100644
--- a/chromium/content/renderer/media/media_stream_video_capturer_source.h
+++ b/chromium/content/renderer/media/media_stream_video_capturer_source.h
@@ -7,10 +7,12 @@
#include "base/callback.h"
#include "base/gtest_prod_util.h"
+#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/threading/thread_checker.h"
#include "content/common/media/video_capture.h"
#include "content/renderer/media/media_stream_video_source.h"
+#include "media/base/video_capturer_source.h"
namespace content {
@@ -19,58 +21,43 @@ namespace content {
// and receive I420 frames from Chrome's video capture implementation.
//
// This is a render thread only object.
-class CONTENT_EXPORT VideoCapturerDelegate
- : public base::RefCountedThreadSafe<VideoCapturerDelegate> {
- public:
- typedef base::Callback<void(MediaStreamRequestResult result)> RunningCallback;
+class CONTENT_EXPORT VideoCapturerDelegate : public media::VideoCapturerSource {
+ public:
explicit VideoCapturerDelegate(const StreamDeviceInfo& device_info);
+ ~VideoCapturerDelegate() override;
- // Collects the formats that can currently be used.
- // |max_requested_height|, |max_requested_width|, and
- // |max_requested_frame_rate| is used by Tab and Screen capture to decide what
- // resolution/framerate to generate. |callback| is triggered when the formats
- // have been collected.
- virtual void GetCurrentSupportedFormats(
+ // VideoCaptureDelegate Implementation.
+ void GetCurrentSupportedFormats(
int max_requested_width,
int max_requested_height,
double max_requested_frame_rate,
- const VideoCaptureDeviceFormatsCB& callback);
-
- // Starts capturing frames using the resolution in |params|.
- // |new_frame_callback| is triggered when a new video frame is available.
- // If capturing is started successfully then |running_callback| will be
- // called with a parameter of true.
- // If capturing fails to start or stopped due to an external event then
- // |running_callback| will be called with a parameter of false.
- virtual void StartCapture(
+ const VideoCaptureDeviceFormatsCB& callback) override;
+
+ void StartCapture(
const media::VideoCaptureParams& params,
const VideoCaptureDeliverFrameCB& new_frame_callback,
- const RunningCallback& running_callback);
+ scoped_refptr<base::SingleThreadTaskRunner> frame_callback_task_runner,
+ const RunningCallback& running_callback) override;
- // Stops capturing frames and clears all callbacks including the
- // SupportedFormatsCallback callback.
- virtual void StopCapture();
+ void StopCapture() override;
private:
FRIEND_TEST_ALL_PREFIXES(MediaStreamVideoCapturerSourceTest, Ended);
- friend class base::RefCountedThreadSafe<VideoCapturerDelegate>;
friend class MockVideoCapturerDelegate;
- virtual ~VideoCapturerDelegate();
-
- void OnStateUpdateOnRenderThread(VideoCaptureState state);
+ void OnStateUpdate(VideoCaptureState state);
void OnDeviceFormatsInUseReceived(const media::VideoCaptureFormats& formats);
void OnDeviceSupportedFormatsEnumerated(
const media::VideoCaptureFormats& formats);
// The id identifies which video capture device is used for this video
// capture session.
- media::VideoCaptureSessionId session_id_;
+ const media::VideoCaptureSessionId session_id_;
base::Closure release_device_cb_;
base::Closure stop_capture_cb_;
- bool is_screen_cast_;
+ const bool is_screen_cast_;
// |running_callback| is provided to this class in StartCapture and must be
// valid until StopCapture is called.
@@ -81,6 +68,8 @@ class CONTENT_EXPORT VideoCapturerDelegate
// Bound to the render thread.
base::ThreadChecker thread_checker_;
+ base::WeakPtrFactory<VideoCapturerDelegate> weak_factory_;
+
DISALLOW_COPY_AND_ASSIGN(VideoCapturerDelegate);
};
@@ -92,12 +81,12 @@ class CONTENT_EXPORT MediaStreamVideoCapturerSource
: public MediaStreamVideoSource {
public:
MediaStreamVideoCapturerSource(
- const StreamDeviceInfo& device_info,
const SourceStoppedCallback& stop_callback,
- const scoped_refptr<VideoCapturerDelegate>& delegate);
-
+ scoped_ptr<media::VideoCapturerSource> delegate);
virtual ~MediaStreamVideoCapturerSource();
+ void SetDeviceInfo(const StreamDeviceInfo& device_info);
+
protected:
// Implements MediaStreamVideoSource.
void GetCurrentSupportedFormats(
@@ -108,13 +97,15 @@ class CONTENT_EXPORT MediaStreamVideoCapturerSource
void StartSourceImpl(
const media::VideoCaptureFormat& format,
+ const blink::WebMediaConstraints& constraints,
const VideoCaptureDeliverFrameCB& frame_callback) override;
void StopSourceImpl() override;
private:
+ void OnStarted(bool result);
// The delegate that provides video frames.
- scoped_refptr<VideoCapturerDelegate> delegate_;
+ const scoped_ptr<media::VideoCapturerSource> delegate_;
DISALLOW_COPY_AND_ASSIGN(MediaStreamVideoCapturerSource);
};
diff --git a/chromium/content/renderer/media/media_stream_video_source.cc b/chromium/content/renderer/media/media_stream_video_source.cc
index 6855adef140..c4b0c2265b7 100644
--- a/chromium/content/renderer/media/media_stream_video_source.cc
+++ b/chromium/content/renderer/media/media_stream_video_source.cc
@@ -8,9 +8,9 @@
#include <limits>
#include <string>
-#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
+#include "base/trace_event/trace_event.h"
#include "content/child/child_process.h"
#include "content/renderer/media/media_stream_constraints_util.h"
#include "content/renderer/media/media_stream_video_track.h"
@@ -39,11 +39,6 @@ const char* kSupportedConstraints[] = {
MediaStreamVideoSource::kMinFrameRate,
};
-const int MediaStreamVideoSource::kDefaultWidth = 640;
-const int MediaStreamVideoSource::kDefaultHeight = 480;
-const int MediaStreamVideoSource::kDefaultFrameRate = 30;
-const int MediaStreamVideoSource::kUnknownFrameRate = 0;
-
namespace {
// Google-specific key prefix. Constraints with this prefix are ignored if they
@@ -209,11 +204,10 @@ void FilterFormatsByConstraint(
while (format_it != formats->end()) {
// Modify the format_it to fulfill the constraint if possible.
// Delete it otherwise.
- if (!UpdateFormatForConstraint(constraint, mandatory, &(*format_it))) {
+ if (!UpdateFormatForConstraint(constraint, mandatory, &(*format_it)))
format_it = formats->erase(format_it);
- } else {
+ else
++format_it;
- }
}
}
@@ -222,9 +216,8 @@ media::VideoCaptureFormats FilterFormats(
const blink::WebMediaConstraints& constraints,
const media::VideoCaptureFormats& supported_formats,
blink::WebString* unsatisfied_constraint) {
- if (constraints.isNull()) {
+ if (constraints.isNull())
return supported_formats;
- }
double max_aspect_ratio;
double min_aspect_ratio;
@@ -291,9 +284,8 @@ media::VideoCaptureFormats FilterFormats(
for (size_t i = 0; i < optional.size(); ++i) {
media::VideoCaptureFormats current_candidates = candidates;
FilterFormatsByConstraint(optional[i], false, &current_candidates);
- if (!current_candidates.empty()) {
+ if (!current_candidates.empty())
candidates = current_candidates;
- }
}
// We have done as good as we can to filter the supported resolutions.
@@ -307,7 +299,7 @@ const media::VideoCaptureFormat& GetBestFormatBasedOnArea(
media::VideoCaptureFormats::const_iterator best_it = formats.begin();
int best_diff = std::numeric_limits<int>::max();
for (; it != formats.end(); ++it) {
- int diff = abs(area - it->frame_size.width() * it->frame_size.height());
+ const int diff = abs(area - it->frame_size.GetArea());
if (diff < best_diff) {
best_diff = diff;
best_it = it;
@@ -334,8 +326,10 @@ void GetBestCaptureFormat(
*capture_format = GetBestFormatBasedOnArea(
formats,
- std::min(max_width, MediaStreamVideoSource::kDefaultWidth) *
- std::min(max_height, MediaStreamVideoSource::kDefaultHeight));
+ std::min(max_width,
+ static_cast<int>(MediaStreamVideoSource::kDefaultWidth)) *
+ std::min(max_height,
+ static_cast<int>(MediaStreamVideoSource::kDefaultHeight)));
}
} // anonymous namespace
@@ -348,8 +342,8 @@ MediaStreamVideoSource* MediaStreamVideoSource::GetVideoSource(
// static
bool MediaStreamVideoSource::IsConstraintSupported(const std::string& name) {
- for (size_t i = 0; i < arraysize(kSupportedConstraints); ++i) {
- if (kSupportedConstraints[i] == name)
+ for (const char* constraint : kSupportedConstraints) {
+ if (constraint == name)
return true;
}
return false;
@@ -470,8 +464,10 @@ void MediaStreamVideoSource::OnSupportedFormats(
DCHECK_EQ(RETRIEVING_CAPABILITIES, state_);
supported_formats_ = formats;
+ blink::WebMediaConstraints fulfilled_constraints;
if (!FindBestFormatWithConstraints(supported_formats_,
- &current_format_)) {
+ &current_format_,
+ &fulfilled_constraints)) {
SetReadyState(blink::WebMediaStreamSource::ReadyStateEnded);
// This object can be deleted after calling FinalizeAddTrack. See comment
// in the header file.
@@ -484,24 +480,25 @@ void MediaStreamVideoSource::OnSupportedFormats(
StartSourceImpl(
current_format_,
+ fulfilled_constraints,
base::Bind(&VideoTrackAdapter::DeliverFrameOnIO, track_adapter_));
}
bool MediaStreamVideoSource::FindBestFormatWithConstraints(
const media::VideoCaptureFormats& formats,
- media::VideoCaptureFormat* best_format) {
+ media::VideoCaptureFormat* best_format,
+ blink::WebMediaConstraints* fulfilled_constraints) {
DCHECK(CalledOnValidThread());
// Find the first constraints that we can fulfill.
- for (std::vector<RequestedConstraints>::iterator request_it =
- requested_constraints_.begin();
- request_it != requested_constraints_.end(); ++request_it) {
+ for (const auto& request : requested_constraints_) {
const blink::WebMediaConstraints& requested_constraints =
- request_it->constraints;
+ request.constraints;
// If the source doesn't support capability enumeration it is still ok if
// no mandatory constraints have been specified. That just means that
// we will start with whatever format is native to the source.
if (formats.empty() && !HasMandatoryConstraints(requested_constraints)) {
+ *fulfilled_constraints = requested_constraints;
*best_format = media::VideoCaptureFormat();
return true;
}
@@ -510,6 +507,7 @@ bool MediaStreamVideoSource::FindBestFormatWithConstraints(
FilterFormats(requested_constraints, formats, &unsatisfied_constraint);
if (filtered_formats.size() > 0) {
// A request with constraints that can be fulfilled.
+ *fulfilled_constraints = requested_constraints;
GetBestCaptureFormat(filtered_formats,
requested_constraints,
best_format);
@@ -548,15 +546,15 @@ void MediaStreamVideoSource::FinalizeAddTrack() {
std::vector<RequestedConstraints> callbacks;
callbacks.swap(requested_constraints_);
- for (std::vector<RequestedConstraints>::iterator it = callbacks.begin();
- it != callbacks.end(); ++it) {
+ for (const auto& request : callbacks) {
MediaStreamRequestResult result = MEDIA_DEVICE_OK;
blink::WebString unsatisfied_constraint;
- if (HasMandatoryConstraints(it->constraints) &&
- FilterFormats(it->constraints, formats,
- &unsatisfied_constraint).empty())
+ if (HasMandatoryConstraints(request.constraints) &&
+ FilterFormats(request.constraints, formats,
+ &unsatisfied_constraint).empty()) {
result = MEDIA_DEVICE_CONSTRAINT_NOT_SATISFIED;
+ }
if (state_ != STARTED && result == MEDIA_DEVICE_OK)
result = MEDIA_DEVICE_TRACK_START_FAILURE;
@@ -564,17 +562,17 @@ void MediaStreamVideoSource::FinalizeAddTrack() {
if (result == MEDIA_DEVICE_OK) {
int max_width;
int max_height;
- GetDesiredMaxWidthAndHeight(it->constraints, &max_width, &max_height);
+ GetDesiredMaxWidthAndHeight(request.constraints, &max_width, &max_height);
double max_aspect_ratio;
double min_aspect_ratio;
- GetDesiredMinAndMaxAspectRatio(it->constraints,
+ GetDesiredMinAndMaxAspectRatio(request.constraints,
&min_aspect_ratio,
&max_aspect_ratio);
double max_frame_rate = 0.0f;
- GetConstraintValueAsDouble(it->constraints,
+ GetConstraintValueAsDouble(request.constraints,
kMaxFrameRate, &max_frame_rate);
- track_adapter_->AddTrack(it->track, it->frame_callback,
+ track_adapter_->AddTrack(request.track, request.frame_callback,
max_width, max_height,
min_aspect_ratio, max_aspect_ratio,
max_frame_rate);
@@ -582,8 +580,8 @@ void MediaStreamVideoSource::FinalizeAddTrack() {
DVLOG(3) << "FinalizeAddTrack() result " << result;
- if (!it->callback.is_null()) {
- it->callback.Run(this, result, unsatisfied_constraint);
+ if (!request.callback.is_null()) {
+ request.callback.Run(this, result, unsatisfied_constraint);
}
}
}
@@ -594,10 +592,8 @@ void MediaStreamVideoSource::SetReadyState(
DCHECK(CalledOnValidThread());
if (!owner().isNull())
owner().setReadyState(state);
- for (std::vector<MediaStreamVideoTrack*>::iterator it = tracks_.begin();
- it != tracks_.end(); ++it) {
- (*it)->OnReadyStateChanged(state);
- }
+ for (const auto& track : tracks_)
+ track->OnReadyStateChanged(state);
}
void MediaStreamVideoSource::SetMutedState(bool muted_state) {
diff --git a/chromium/content/renderer/media/media_stream_video_source.h b/chromium/content/renderer/media/media_stream_video_source.h
index e06dfc1708d..496bb854939 100644
--- a/chromium/content/renderer/media/media_stream_video_source.h
+++ b/chromium/content/renderer/media/media_stream_video_source.h
@@ -16,8 +16,8 @@
#include "content/common/media/video_capture.h"
#include "content/public/renderer/media_stream_video_sink.h"
#include "content/renderer/media/media_stream_source.h"
+#include "media/base/video_capture_types.h"
#include "media/base/video_frame.h"
-#include "media/video/capture/video_capture_types.h"
#include "third_party/WebKit/public/platform/WebMediaConstraints.h"
#include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
#include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
@@ -70,18 +70,21 @@ class CONTENT_EXPORT MediaStreamVideoSource
static const char kMinAspectRatio[]; // minAspectRatio
static const char kMaxAspectRatio[]; // maxAspectRatio
static const char kMaxWidth[]; // maxWidth
- static const char kMinWidth[]; // minWidthOnCaptureFormats
+ static const char kMinWidth[]; // minWidth
static const char kMaxHeight[]; // maxHeight
static const char kMinHeight[]; // minHeight
static const char kMaxFrameRate[]; // maxFrameRate
static const char kMinFrameRate[]; // minFrameRate
- // Default resolution. If no constraints are specified and the delegate
- // support it, this is the resolution that will be used.
- static const int kDefaultWidth;
- static const int kDefaultHeight;
- static const int kDefaultFrameRate;
- static const int kUnknownFrameRate;
+ enum {
+ // Default resolution. If no constraints are specified and the delegate
+ // support it, this is the resolution that will be used.
+ kDefaultWidth = 640,
+ kDefaultHeight = 480,
+
+ kDefaultFrameRate = 30,
+ kUnknownFrameRate = 0,
+ };
protected:
void DoStopSource() override;
@@ -104,12 +107,15 @@ class CONTENT_EXPORT MediaStreamVideoSource
double max_requested_frame_rate,
const VideoCaptureDeviceFormatsCB& callback) = 0;
- // An implementation must start capture frames using the resolution in
- // |params|. When the source has started or the source failed to start
- // OnStartDone must be called. An implementation must call
- // |frame_callback| on the IO thread with the captured frames.
+ // An implementation must start capturing frames using the requested
+ // |format|. The fulfilled |constraints| are provided as additional context,
+ // and may be used to modify the behavior of the source. When the source has
+ // started or the source failed to start OnStartDone must be called. An
+ // implementation must call |frame_callback| on the IO thread with the
+ // captured frames.
virtual void StartSourceImpl(
const media::VideoCaptureFormat& format,
+ const blink::WebMediaConstraints& constraints,
const VideoCaptureDeliverFrameCB& frame_callback) = 0;
void OnStartDone(MediaStreamRequestResult result);
@@ -130,12 +136,14 @@ class CONTENT_EXPORT MediaStreamVideoSource
private:
void OnSupportedFormats(const media::VideoCaptureFormats& formats);
- // Finds the first constraints in |requested_constraints_| that can be
- // fulfilled. |best_format| is set to the video resolution that can be
- // fulfilled.
+ // Finds the first WebMediaConstraints in |requested_constraints_| that allows
+ // the use of one of the |formats|. |best_format| and |fulfilled_constraints|
+ // are set to the results of this search-and-match operation. Returns false
+ // if no WebMediaConstraints allow the use any of the |formats|.
bool FindBestFormatWithConstraints(
const media::VideoCaptureFormats& formats,
- media::VideoCaptureFormat* best_format);
+ media::VideoCaptureFormat* best_format,
+ blink::WebMediaConstraints* fulfilled_constraints);
// Trigger all cached callbacks from AddTrack. AddTrack is successful
// if the capture delegate has started and the constraints provided in
@@ -167,7 +175,7 @@ class CONTENT_EXPORT MediaStreamVideoSource
media::VideoCaptureFormats supported_formats_;
// |track_adapter_| delivers video frames to the tracks on the IO-thread.
- scoped_refptr<VideoTrackAdapter> track_adapter_;
+ const scoped_refptr<VideoTrackAdapter> track_adapter_;
// Tracks that currently are connected to this source.
std::vector<MediaStreamVideoTrack*> tracks_;
diff --git a/chromium/content/renderer/media/media_stream_video_source_unittest.cc b/chromium/content/renderer/media/media_stream_video_source_unittest.cc
index 15ba1092823..3e150bf5344 100644
--- a/chromium/content/renderer/media/media_stream_video_source_unittest.cc
+++ b/chromium/content/renderer/media/media_stream_video_source_unittest.cc
@@ -52,7 +52,8 @@ class MediaStreamVideoSourceTest
mock_source_->SetSupportedFormats(formats);
webkit_source_.initialize(base::UTF8ToUTF16("dummy_source_id"),
blink::WebMediaStreamSource::TypeVideo,
- base::UTF8ToUTF16("dummy_source_name"));
+ base::UTF8ToUTF16("dummy_source_name"),
+ false /* remote */, true /* readonly */);
webkit_source_.setExtraData(mock_source_);
}
diff --git a/chromium/content/renderer/media/media_stream_video_track.cc b/chromium/content/renderer/media/media_stream_video_track.cc
index 04d8817cca4..751f764058b 100644
--- a/chromium/content/renderer/media/media_stream_video_track.cc
+++ b/chromium/content/renderer/media/media_stream_video_track.cc
@@ -15,6 +15,12 @@ namespace {
void ResetCallback(scoped_ptr<VideoCaptureDeliverFrameCB> callback) {
// |callback| will be deleted when this exits.
}
+
+// Empty method used for keeping a reference to the original media::VideoFrame.
+// The reference to |frame| is kept in the closure that calls this method.
+void ReleaseOriginalFrame(const scoped_refptr<media::VideoFrame>& frame) {
+}
+
} // namespace
// MediaStreamVideoTrack::FrameDeliverer is a helper class used for registering
@@ -26,6 +32,8 @@ void ResetCallback(scoped_ptr<VideoCaptureDeliverFrameCB> callback) {
class MediaStreamVideoTrack::FrameDeliverer
: public base::RefCountedThreadSafe<FrameDeliverer> {
public:
+ typedef MediaStreamVideoSink* VideoSinkId;
+
FrameDeliverer(
const scoped_refptr<base::MessageLoopProxy>& io_message_loop,
bool enabled);
@@ -34,42 +42,44 @@ class MediaStreamVideoTrack::FrameDeliverer
// Add |callback| to receive video frames on the IO-thread.
// Must be called on the main render thread.
- void AddCallback(void* id, const VideoCaptureDeliverFrameCB& callback);
+ void AddCallback(VideoSinkId id, const VideoCaptureDeliverFrameCB& callback);
// Removes |callback| associated with |id| from receiving video frames if |id|
// has been added. It is ok to call RemoveCallback even if the |id| has not
// been added. Note that the added callback will be reset on the main thread.
// Must be called on the main render thread.
- void RemoveCallback(void* id);
+ void RemoveCallback(VideoSinkId id);
// Triggers all registered callbacks with |frame|, |format| and
// |estimated_capture_time| as parameters. Must be called on the IO-thread.
void DeliverFrameOnIO(const scoped_refptr<media::VideoFrame>& frame,
- const media::VideoCaptureFormat& format,
const base::TimeTicks& estimated_capture_time);
private:
friend class base::RefCountedThreadSafe<FrameDeliverer>;
virtual ~FrameDeliverer();
- void AddCallbackOnIO(void* id, const VideoCaptureDeliverFrameCB& callback);
+ void AddCallbackOnIO(VideoSinkId id,
+ const VideoCaptureDeliverFrameCB& callback);
void RemoveCallbackOnIO(
- void* id, const scoped_refptr<base::MessageLoopProxy>& message_loop);
+ VideoSinkId id,
+ const scoped_refptr<base::MessageLoopProxy>& message_loop);
void SetEnabledOnIO(bool enabled);
- // Returns |black_frame_| where the size and time stamp is set to the same as
+ // Returns a black frame where the size and time stamp is set to the same as
// as in |reference_frame|.
- const scoped_refptr<media::VideoFrame>& GetBlackFrame(
+ scoped_refptr<media::VideoFrame> GetBlackFrame(
const scoped_refptr<media::VideoFrame>& reference_frame);
// Used to DCHECK that AddCallback and RemoveCallback are called on the main
- // render thread.
- base::ThreadChecker thread_checker_;
- scoped_refptr<base::MessageLoopProxy> io_message_loop_;
+ // Render Thread.
+ base::ThreadChecker main_render_thread_checker_;
+ const scoped_refptr<base::MessageLoopProxy> io_message_loop_;
bool enabled_;
scoped_refptr<media::VideoFrame> black_frame_;
- typedef std::pair<void*, VideoCaptureDeliverFrameCB> VideoIdCallbackPair;
+ typedef std::pair<VideoSinkId, VideoCaptureDeliverFrameCB>
+ VideoIdCallbackPair;
std::vector<VideoIdCallbackPair> callbacks_;
DISALLOW_COPY_AND_ASSIGN(FrameDeliverer);
@@ -87,9 +97,9 @@ MediaStreamVideoTrack::FrameDeliverer::~FrameDeliverer() {
}
void MediaStreamVideoTrack::FrameDeliverer::AddCallback(
- void* id,
+ VideoSinkId id,
const VideoCaptureDeliverFrameCB& callback) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(main_render_thread_checker_.CalledOnValidThread());
io_message_loop_->PostTask(
FROM_HERE,
base::Bind(&FrameDeliverer::AddCallbackOnIO,
@@ -97,14 +107,14 @@ void MediaStreamVideoTrack::FrameDeliverer::AddCallback(
}
void MediaStreamVideoTrack::FrameDeliverer::AddCallbackOnIO(
- void* id,
+ VideoSinkId id,
const VideoCaptureDeliverFrameCB& callback) {
DCHECK(io_message_loop_->BelongsToCurrentThread());
callbacks_.push_back(std::make_pair(id, callback));
}
-void MediaStreamVideoTrack::FrameDeliverer::RemoveCallback(void* id) {
- DCHECK(thread_checker_.CalledOnValidThread());
+void MediaStreamVideoTrack::FrameDeliverer::RemoveCallback(VideoSinkId id) {
+ DCHECK(main_render_thread_checker_.CalledOnValidThread());
io_message_loop_->PostTask(
FROM_HERE,
base::Bind(&FrameDeliverer::RemoveCallbackOnIO,
@@ -112,7 +122,8 @@ void MediaStreamVideoTrack::FrameDeliverer::RemoveCallback(void* id) {
}
void MediaStreamVideoTrack::FrameDeliverer::RemoveCallbackOnIO(
- void* id, const scoped_refptr<base::MessageLoopProxy>& message_loop) {
+ VideoSinkId id,
+ const scoped_refptr<base::MessageLoopProxy>& message_loop) {
DCHECK(io_message_loop_->BelongsToCurrentThread());
std::vector<VideoIdCallbackPair>::iterator it = callbacks_.begin();
for (; it != callbacks_.end(); ++it) {
@@ -129,7 +140,7 @@ void MediaStreamVideoTrack::FrameDeliverer::RemoveCallbackOnIO(
}
void MediaStreamVideoTrack::FrameDeliverer::SetEnabled(bool enabled) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(main_render_thread_checker_.CalledOnValidThread());
io_message_loop_->PostTask(
FROM_HERE,
base::Bind(&FrameDeliverer::SetEnabledOnIO,
@@ -145,19 +156,15 @@ void MediaStreamVideoTrack::FrameDeliverer::SetEnabledOnIO(bool enabled) {
void MediaStreamVideoTrack::FrameDeliverer::DeliverFrameOnIO(
const scoped_refptr<media::VideoFrame>& frame,
- const media::VideoCaptureFormat& format,
const base::TimeTicks& estimated_capture_time) {
DCHECK(io_message_loop_->BelongsToCurrentThread());
const scoped_refptr<media::VideoFrame>& video_frame =
enabled_ ? frame : GetBlackFrame(frame);
-
- for (std::vector<VideoIdCallbackPair>::iterator it = callbacks_.begin();
- it != callbacks_.end(); ++it) {
- it->second.Run(video_frame, format, estimated_capture_time);
- }
+ for (const auto& entry : callbacks_)
+ entry.second.Run(video_frame, estimated_capture_time);
}
-const scoped_refptr<media::VideoFrame>&
+scoped_refptr<media::VideoFrame>
MediaStreamVideoTrack::FrameDeliverer::GetBlackFrame(
const scoped_refptr<media::VideoFrame>& reference_frame) {
DCHECK(io_message_loop_->BelongsToCurrentThread());
@@ -166,8 +173,16 @@ MediaStreamVideoTrack::FrameDeliverer::GetBlackFrame(
black_frame_ =
media::VideoFrame::CreateBlackFrame(reference_frame->natural_size());
- black_frame_->set_timestamp(reference_frame->timestamp());
- return black_frame_;
+ // Wrap |black_frame_| so we get a fresh timestamp we can modify. Frames
+ // returned from this function may still be in use.
+ scoped_refptr<media::VideoFrame> wrapped_black_frame =
+ media::VideoFrame::WrapVideoFrame(
+ black_frame_, black_frame_->visible_rect(),
+ black_frame_->natural_size(),
+ base::Bind(&ReleaseOriginalFrame, black_frame_));
+
+ wrapped_black_frame->set_timestamp(reference_frame->timestamp());
+ return wrapped_black_frame;
}
// static
@@ -211,7 +226,7 @@ MediaStreamVideoTrack::MediaStreamVideoTrack(
}
MediaStreamVideoTrack::~MediaStreamVideoTrack() {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(main_render_thread_checker_.CalledOnValidThread());
DCHECK(sinks_.empty());
Stop();
DVLOG(3) << "~MediaStreamVideoTrack()";
@@ -219,14 +234,14 @@ MediaStreamVideoTrack::~MediaStreamVideoTrack() {
void MediaStreamVideoTrack::AddSink(
MediaStreamVideoSink* sink, const VideoCaptureDeliverFrameCB& callback) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(main_render_thread_checker_.CalledOnValidThread());
DCHECK(std::find(sinks_.begin(), sinks_.end(), sink) == sinks_.end());
sinks_.push_back(sink);
frame_deliverer_->AddCallback(sink, callback);
}
void MediaStreamVideoTrack::RemoveSink(MediaStreamVideoSink* sink) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(main_render_thread_checker_.CalledOnValidThread());
std::vector<MediaStreamVideoSink*>::iterator it =
std::find(sinks_.begin(), sinks_.end(), sink);
DCHECK(it != sinks_.end());
@@ -235,16 +250,14 @@ void MediaStreamVideoTrack::RemoveSink(MediaStreamVideoSink* sink) {
}
void MediaStreamVideoTrack::SetEnabled(bool enabled) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(main_render_thread_checker_.CalledOnValidThread());
frame_deliverer_->SetEnabled(enabled);
- for (std::vector<MediaStreamVideoSink*>::const_iterator it = sinks_.begin();
- it != sinks_.end(); ++it) {
- (*it)->OnEnabledChanged(enabled);
- }
+ for (auto* sink : sinks_)
+ sink->OnEnabledChanged(enabled);
}
void MediaStreamVideoTrack::Stop() {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(main_render_thread_checker_.CalledOnValidThread());
if (source_) {
source_->RemoveTrack(this);
source_ = NULL;
@@ -254,11 +267,9 @@ void MediaStreamVideoTrack::Stop() {
void MediaStreamVideoTrack::OnReadyStateChanged(
blink::WebMediaStreamSource::ReadyState state) {
- DCHECK(thread_checker_.CalledOnValidThread());
- for (std::vector<MediaStreamVideoSink*>::const_iterator it = sinks_.begin();
- it != sinks_.end(); ++it) {
- (*it)->OnReadyStateChanged(state);
- }
+ DCHECK(main_render_thread_checker_.CalledOnValidThread());
+ for (auto* sink : sinks_)
+ sink->OnReadyStateChanged(state);
}
} // namespace content
diff --git a/chromium/content/renderer/media/media_stream_video_track.h b/chromium/content/renderer/media/media_stream_video_track.h
index c3b5ed9de73..4e51dfd8f8b 100644
--- a/chromium/content/renderer/media/media_stream_video_track.h
+++ b/chromium/content/renderer/media/media_stream_video_track.h
@@ -59,10 +59,6 @@ class CONTENT_EXPORT MediaStreamVideoTrack : public MediaStreamTrack {
return constraints_;
}
- protected:
- // Used to DCHECK that we are called on the correct thread.
- base::ThreadChecker thread_checker_;
-
private:
// MediaStreamVideoSink is a friend to allow it to call AddSink() and
// RemoveSink().
@@ -86,9 +82,9 @@ class CONTENT_EXPORT MediaStreamVideoTrack : public MediaStreamTrack {
// |FrameDeliverer| is an internal helper object used for delivering video
// frames on the IO-thread using callbacks to all registered tracks.
class FrameDeliverer;
- scoped_refptr<FrameDeliverer> frame_deliverer_;
+ const scoped_refptr<FrameDeliverer> frame_deliverer_;
- blink::WebMediaConstraints constraints_;
+ const blink::WebMediaConstraints constraints_;
// Weak ref to the source this tracks is connected to. |source_| is owned
// by the blink::WebMediaStreamSource and is guaranteed to outlive the
diff --git a/chromium/content/renderer/media/media_stream_video_track_unittest.cc b/chromium/content/renderer/media/media_stream_video_track_unittest.cc
index 4c319ac910d..2fe85039b48 100644
--- a/chromium/content/renderer/media/media_stream_video_track_unittest.cc
+++ b/chromium/content/renderer/media/media_stream_video_track_unittest.cc
@@ -33,8 +33,9 @@ class MediaStreamVideoTrackTest : public ::testing::Test {
mock_source_(new MockMediaStreamVideoSource(false)),
source_started_(false) {
blink_source_.initialize(base::UTF8ToUTF16("dummy_source_id"),
- blink::WebMediaStreamSource::TypeVideo,
- base::UTF8ToUTF16("dummy_source_name"));
+ blink::WebMediaStreamSource::TypeVideo,
+ base::UTF8ToUTF16("dummy_source_name"),
+ false /* remote */, true /* readonly */);
blink_source_.setExtraData(mock_source_);
}
@@ -138,7 +139,6 @@ class CheckThreadHelper {
void CheckThreadVideoFrameReceiver(
CheckThreadHelper* helper,
const scoped_refptr<media::VideoFrame>& frame,
- const media::VideoCaptureFormat& format,
const base::TimeTicks& estimated_capture_time) {
// Do nothing.
}
diff --git a/chromium/content/renderer/media/midi_dispatcher.cc b/chromium/content/renderer/media/midi_dispatcher.cc
index b281389ee54..4442993524d 100644
--- a/chromium/content/renderer/media/midi_dispatcher.cc
+++ b/chromium/content/renderer/media/midi_dispatcher.cc
@@ -5,8 +5,8 @@
#include "content/renderer/media/midi_dispatcher.h"
#include "base/bind.h"
-#include "base/message_loop/message_loop.h"
-#include "content/common/media/midi_messages.h"
+#include "content/public/common/service_registry.h"
+#include "content/public/renderer/render_frame.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/web/WebMIDIPermissionRequest.h"
#include "third_party/WebKit/public/web/WebSecurityOrigin.h"
@@ -23,23 +23,23 @@ MidiDispatcher::MidiDispatcher(RenderFrame* render_frame)
MidiDispatcher::~MidiDispatcher() {}
-bool MidiDispatcher::OnMessageReceived(const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(MidiDispatcher, message)
- IPC_MESSAGE_HANDLER(MidiMsg_SysExPermissionApproved,
- OnSysExPermissionApproved)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
void MidiDispatcher::requestSysexPermission(
const WebMIDIPermissionRequest& request) {
- int bridge_id = requests_.Add(new WebMIDIPermissionRequest(request));
- WebSecurityOrigin security_origin = request.securityOrigin();
- GURL url(security_origin.toString());
- Send(new MidiHostMsg_RequestSysExPermission(routing_id(), bridge_id, url,
- blink::WebUserGestureIndicator::isProcessingUserGesture()));
+ if (!permission_service_.get()) {
+ render_frame()->GetServiceRegistry()->ConnectToRemoteService(
+ &permission_service_);
+ }
+
+ int permission_request_id =
+ requests_.Add(new WebMIDIPermissionRequest(request));
+
+ permission_service_->RequestPermission(
+ PERMISSION_NAME_MIDI_SYSEX,
+ request.securityOrigin().toString().utf8(),
+ blink::WebUserGestureIndicator::isProcessingUserGesture(),
+ base::Bind(&MidiDispatcher::OnSysExPermissionSet,
+ base::Unretained(this),
+ permission_request_id));
}
void MidiDispatcher::cancelSysexPermissionRequest(
@@ -53,14 +53,14 @@ void MidiDispatcher::cancelSysexPermissionRequest(
}
}
-void MidiDispatcher::OnSysExPermissionApproved(int bridge_id,
- bool is_allowed) {
+void MidiDispatcher::OnSysExPermissionSet(int request_id,
+ PermissionStatus status) {
// |request| can be NULL when the request is canceled.
- WebMIDIPermissionRequest* request = requests_.Lookup(bridge_id);
+ WebMIDIPermissionRequest* request = requests_.Lookup(request_id);
if (!request)
return;
- request->setIsAllowed(is_allowed);
- requests_.Remove(bridge_id);
+ request->setIsAllowed(status == PERMISSION_STATUS_GRANTED);
+ requests_.Remove(request_id);
}
} // namespace content
diff --git a/chromium/content/renderer/media/midi_dispatcher.h b/chromium/content/renderer/media/midi_dispatcher.h
index cfa77ee9b7b..65a11d117b7 100644
--- a/chromium/content/renderer/media/midi_dispatcher.h
+++ b/chromium/content/renderer/media/midi_dispatcher.h
@@ -6,6 +6,7 @@
#define CONTENT_RENDERER_MEDIA_MIDI_DISPATCHER_H_
#include "base/id_map.h"
+#include "content/common/permission_service.mojom.h"
#include "content/public/renderer/render_frame_observer.h"
#include "third_party/WebKit/public/web/WebMIDIClient.h"
@@ -17,9 +18,8 @@ namespace content {
// MidiDispatcher implements WebMIDIClient to handle permissions for using
// system exclusive messages.
-// It works as RenderFrameObserver to handle IPC messages between
-// MidiDispatcherHost owned by WebContents since permissions are managed in
-// the browser process.
+// It works as RenderFrameObserver to keep a 1:1 relationship with a RenderFrame
+// and make sure it has the same life cycle.
class MidiDispatcher : public RenderFrameObserver,
public blink::WebMIDIClient {
public:
@@ -27,9 +27,6 @@ class MidiDispatcher : public RenderFrameObserver,
virtual ~MidiDispatcher();
private:
- // RenderFrameObserver implementation.
- bool OnMessageReceived(const IPC::Message& message) override;
-
// blink::WebMIDIClient implementation.
virtual void requestSysexPermission(
const blink::WebMIDIPermissionRequest& request);
@@ -37,7 +34,7 @@ class MidiDispatcher : public RenderFrameObserver,
const blink::WebMIDIPermissionRequest& request);
// Permission for using system exclusive messages has been set.
- void OnSysExPermissionApproved(int client_id, bool is_allowed);
+ void OnSysExPermissionSet(int request_id, PermissionStatus status);
// Each WebMIDIPermissionRequest object is valid until
// cancelSysexPermissionRequest() is called with the object, or used to call
@@ -45,6 +42,8 @@ class MidiDispatcher : public RenderFrameObserver,
typedef IDMap<blink::WebMIDIPermissionRequest, IDMapOwnPointer> Requests;
Requests requests_;
+ PermissionServicePtr permission_service_;
+
DISALLOW_COPY_AND_ASSIGN(MidiDispatcher);
};
diff --git a/chromium/content/renderer/media/midi_message_filter.cc b/chromium/content/renderer/media/midi_message_filter.cc
index 982281f72d6..07b85436e65 100644
--- a/chromium/content/renderer/media/midi_message_filter.cc
+++ b/chromium/content/renderer/media/midi_message_filter.cc
@@ -7,14 +7,13 @@
#include <algorithm>
#include "base/bind.h"
-#include "base/debug/trace_event.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/trace_event/trace_event.h"
#include "content/common/media/midi_messages.h"
#include "content/renderer/render_thread_impl.h"
#include "ipc/ipc_logging.h"
-using media::MidiPortInfoList;
using base::AutoLock;
// The maximum number of bytes which we're allowed to send to the browser
@@ -30,7 +29,7 @@ MidiMessageFilter::MidiMessageFilter(
: sender_(nullptr),
io_message_loop_(io_message_loop),
main_message_loop_(base::MessageLoopProxy::current()),
- session_result_(media::MIDI_NOT_INITIALIZED),
+ session_result_(media::midi::MIDI_NOT_INITIALIZED),
unacknowledged_bytes_sent_(0u) {
}
@@ -40,7 +39,7 @@ void MidiMessageFilter::AddClient(blink::WebMIDIAccessorClient* client) {
DCHECK(main_message_loop_->BelongsToCurrentThread());
TRACE_EVENT0("midi", "MidiMessageFilter::AddClient");
clients_waiting_session_queue_.push_back(client);
- if (session_result_ != media::MIDI_NOT_INITIALIZED) {
+ if (session_result_ != media::midi::MIDI_NOT_INITIALIZED) {
HandleClientAdded(session_result_);
} else if (clients_waiting_session_queue_.size() == 1u) {
io_message_loop_->PostTask(FROM_HERE,
@@ -57,7 +56,7 @@ void MidiMessageFilter::RemoveClient(blink::WebMIDIAccessorClient* client) {
if (it != clients_waiting_session_queue_.end())
clients_waiting_session_queue_.erase(it);
if (clients_.empty() && clients_waiting_session_queue_.empty()) {
- session_result_ = media::MIDI_NOT_INITIALIZED;
+ session_result_ = media::midi::MIDI_NOT_INITIALIZED;
inputs_.clear();
outputs_.clear();
io_message_loop_->PostTask(FROM_HERE,
@@ -116,6 +115,8 @@ bool MidiMessageFilter::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(MidiMsg_SessionStarted, OnSessionStarted)
IPC_MESSAGE_HANDLER(MidiMsg_AddInputPort, OnAddInputPort)
IPC_MESSAGE_HANDLER(MidiMsg_AddOutputPort, OnAddOutputPort)
+ IPC_MESSAGE_HANDLER(MidiMsg_SetInputPortState, OnSetInputPortState)
+ IPC_MESSAGE_HANDLER(MidiMsg_SetOutputPortState, OnSetOutputPortState)
IPC_MESSAGE_HANDLER(MidiMsg_DataReceived, OnDataReceived)
IPC_MESSAGE_HANDLER(MidiMsg_AcknowledgeSentData, OnAcknowledgeSentData)
IPC_MESSAGE_UNHANDLED(handled = false)
@@ -140,7 +141,7 @@ void MidiMessageFilter::OnChannelClosing() {
sender_ = nullptr;
}
-void MidiMessageFilter::OnSessionStarted(media::MidiResult result) {
+void MidiMessageFilter::OnSessionStarted(media::midi::MidiResult result) {
TRACE_EVENT0("midi", "MidiMessageFilter::OnSessionStarted");
DCHECK(io_message_loop_->BelongsToCurrentThread());
// Handle on the main JS thread.
@@ -149,20 +150,38 @@ void MidiMessageFilter::OnSessionStarted(media::MidiResult result) {
base::Bind(&MidiMessageFilter::HandleClientAdded, this, result));
}
-void MidiMessageFilter::OnAddInputPort(media::MidiPortInfo info) {
+void MidiMessageFilter::OnAddInputPort(media::midi::MidiPortInfo info) {
DCHECK(io_message_loop_->BelongsToCurrentThread());
main_message_loop_->PostTask(
FROM_HERE,
base::Bind(&MidiMessageFilter::HandleAddInputPort, this, info));
}
-void MidiMessageFilter::OnAddOutputPort(media::MidiPortInfo info) {
+void MidiMessageFilter::OnAddOutputPort(media::midi::MidiPortInfo info) {
DCHECK(io_message_loop_->BelongsToCurrentThread());
main_message_loop_->PostTask(
FROM_HERE,
base::Bind(&MidiMessageFilter::HandleAddOutputPort, this, info));
}
+void MidiMessageFilter::OnSetInputPortState(uint32 port,
+ media::midi::MidiPortState state) {
+ DCHECK(io_message_loop_->BelongsToCurrentThread());
+ main_message_loop_->PostTask(
+ FROM_HERE,
+ base::Bind(&MidiMessageFilter::HandleSetInputPortState,
+ this, port, state));
+}
+
+void MidiMessageFilter::OnSetOutputPortState(uint32 port,
+ media::midi::MidiPortState state) {
+ DCHECK(io_message_loop_->BelongsToCurrentThread());
+ main_message_loop_->PostTask(
+ FROM_HERE,
+ base::Bind(&MidiMessageFilter::HandleSetOutputPortState,
+ this, port, state));
+}
+
void MidiMessageFilter::OnDataReceived(uint32 port,
const std::vector<uint8>& data,
double timestamp) {
@@ -183,19 +202,19 @@ void MidiMessageFilter::OnAcknowledgeSentData(size_t bytes_sent) {
bytes_sent));
}
-void MidiMessageFilter::HandleClientAdded(media::MidiResult result) {
+void MidiMessageFilter::HandleClientAdded(media::midi::MidiResult result) {
TRACE_EVENT0("midi", "MidiMessageFilter::HandleClientAdded");
DCHECK(main_message_loop_->BelongsToCurrentThread());
session_result_ = result;
std::string error;
std::string message;
switch (result) {
- case media::MIDI_OK:
+ case media::midi::MIDI_OK:
break;
- case media::MIDI_NOT_SUPPORTED:
+ case media::midi::MIDI_NOT_SUPPORTED:
error = "NotSupportedError";
break;
- case media::MIDI_INITIALIZATION_ERROR:
+ case media::midi::MIDI_INITIALIZATION_ERROR:
error = "InvalidStateError";
message = "Platform dependent initialization failed.";
break;
@@ -207,17 +226,21 @@ void MidiMessageFilter::HandleClientAdded(media::MidiResult result) {
}
base::string16 error16 = base::UTF8ToUTF16(error);
base::string16 message16 = base::UTF8ToUTF16(message);
- for (blink::WebMIDIAccessorClient* client : clients_waiting_session_queue_) {
- if (result == media::MIDI_OK) {
+
+ // A for-loop using iterators does not work because |client| may touch
+ // |clients_waiting_session_queue_| in callbacks.
+ while (!clients_waiting_session_queue_.empty()) {
+ auto client = clients_waiting_session_queue_.back();
+ clients_waiting_session_queue_.pop_back();
+ if (result == media::midi::MIDI_OK) {
// Add the client's input and output ports.
- const bool active = true;
for (const auto& info : inputs_) {
client->didAddInputPort(
base::UTF8ToUTF16(info.id),
base::UTF8ToUTF16(info.manufacturer),
base::UTF8ToUTF16(info.name),
base::UTF8ToUTF16(info.version),
- active);
+ ToBlinkState(info.state));
}
for (const auto& info : outputs_) {
@@ -226,25 +249,38 @@ void MidiMessageFilter::HandleClientAdded(media::MidiResult result) {
base::UTF8ToUTF16(info.manufacturer),
base::UTF8ToUTF16(info.name),
base::UTF8ToUTF16(info.version),
- active);
+ ToBlinkState(info.state));
}
}
- client->didStartSession(result == media::MIDI_OK, error16, message16);
+ client->didStartSession(result == media::midi::MIDI_OK, error16, message16);
clients_.insert(client);
}
- clients_waiting_session_queue_.clear();
}
-void MidiMessageFilter::HandleAddInputPort(media::MidiPortInfo info) {
+void MidiMessageFilter::HandleAddInputPort(media::midi::MidiPortInfo info) {
DCHECK(main_message_loop_->BelongsToCurrentThread());
inputs_.push_back(info);
- // TODO(toyoshim): Notify to clients that were already added.
+ const base::string16 id = base::UTF8ToUTF16(info.id);
+ const base::string16 manufacturer = base::UTF8ToUTF16(info.manufacturer);
+ const base::string16 name = base::UTF8ToUTF16(info.name);
+ const base::string16 version = base::UTF8ToUTF16(info.version);
+ const blink::WebMIDIAccessorClient::MIDIPortState state =
+ ToBlinkState(info.state);
+ for (auto client : clients_)
+ client->didAddInputPort(id, manufacturer, name, version, state);
}
-void MidiMessageFilter::HandleAddOutputPort(media::MidiPortInfo info) {
+void MidiMessageFilter::HandleAddOutputPort(media::midi::MidiPortInfo info) {
DCHECK(main_message_loop_->BelongsToCurrentThread());
outputs_.push_back(info);
- // TODO(toyoshim): Notify to clients that were already added.
+ const base::string16 id = base::UTF8ToUTF16(info.id);
+ const base::string16 manufacturer = base::UTF8ToUTF16(info.manufacturer);
+ const base::string16 name = base::UTF8ToUTF16(info.name);
+ const base::string16 version = base::UTF8ToUTF16(info.version);
+ const blink::WebMIDIAccessorClient::MIDIPortState state =
+ ToBlinkState(info.state);
+ for (auto client : clients_)
+ client->didAddOutputPort(id, manufacturer, name, version, state);
}
void MidiMessageFilter::HandleDataReceived(uint32 port,
@@ -254,7 +290,7 @@ void MidiMessageFilter::HandleDataReceived(uint32 port,
DCHECK(main_message_loop_->BelongsToCurrentThread());
DCHECK(!data.empty());
- for (blink::WebMIDIAccessorClient* client : clients_)
+ for (auto client : clients_)
client->didReceiveMIDIData(port, &data[0], data.size(), timestamp);
}
@@ -265,4 +301,22 @@ void MidiMessageFilter::HandleAckknowledgeSentData(size_t bytes_sent) {
unacknowledged_bytes_sent_ -= bytes_sent;
}
+void MidiMessageFilter::HandleSetInputPortState(
+ uint32 port,
+ media::midi::MidiPortState state) {
+ DCHECK(main_message_loop_->BelongsToCurrentThread());
+ inputs_[port].state = state;
+ for (auto client : clients_)
+ client->didSetInputPortState(port, ToBlinkState(state));
+}
+
+void MidiMessageFilter::HandleSetOutputPortState(
+ uint32 port,
+ media::midi::MidiPortState state) {
+ DCHECK(main_message_loop_->BelongsToCurrentThread());
+ outputs_[port].state = state;
+ for (auto client : clients_)
+ client->didSetOutputPortState(port, ToBlinkState(state));
+}
+
} // namespace content
diff --git a/chromium/content/renderer/media/midi_message_filter.h b/chromium/content/renderer/media/midi_message_filter.h
index f7e1a8474a4..8aa6bf8c4a6 100644
--- a/chromium/content/renderer/media/midi_message_filter.h
+++ b/chromium/content/renderer/media/midi_message_filter.h
@@ -44,6 +44,14 @@ class CONTENT_EXPORT MidiMessageFilter : public IPC::MessageFilter {
return io_message_loop_;
}
+ static blink::WebMIDIAccessorClient::MIDIPortState ToBlinkState(
+ media::midi::MidiPortState state) {
+ // "open" status is separately managed by blink per MIDIAccess instance.
+ if (state == media::midi::MIDI_PORT_OPENED)
+ state = media::midi::MIDI_PORT_CONNECTED;
+ return static_cast<blink::WebMIDIAccessorClient::MIDIPortState>(state);
+ }
+
protected:
~MidiMessageFilter() override;
@@ -67,15 +75,21 @@ class CONTENT_EXPORT MidiMessageFilter : public IPC::MessageFilter {
// Called when the browser process has approved (or denied) access to
// MIDI hardware.
- void OnSessionStarted(media::MidiResult result);
+ void OnSessionStarted(media::midi::MidiResult result);
// These functions are called in 2 cases:
// (1) Just before calling |OnSessionStarted|, to notify the recipient about
// existing ports.
// (2) To notify the recipient that a new device was connected and that new
// ports have been created.
- void OnAddInputPort(media::MidiPortInfo info);
- void OnAddOutputPort(media::MidiPortInfo info);
+ void OnAddInputPort(media::midi::MidiPortInfo info);
+ void OnAddOutputPort(media::midi::MidiPortInfo info);
+
+ // These functions are called to notify the recipient that a device that is
+ // notified via OnAddInputPort() or OnAddOutputPort() gets disconnected, or
+ // connected again.
+ void OnSetInputPortState(uint32 port, media::midi::MidiPortState state);
+ void OnSetOutputPortState(uint32 port, media::midi::MidiPortState state);
// Called when the browser process has sent MIDI data containing one or
// more messages.
@@ -89,10 +103,12 @@ class CONTENT_EXPORT MidiMessageFilter : public IPC::MessageFilter {
void OnAcknowledgeSentData(size_t bytes_sent);
// Following methods, Handle*, run on |main_message_loop_|.
- void HandleClientAdded(media::MidiResult result);
+ void HandleClientAdded(media::midi::MidiResult result);
- void HandleAddInputPort(media::MidiPortInfo info);
- void HandleAddOutputPort(media::MidiPortInfo info);
+ void HandleAddInputPort(media::midi::MidiPortInfo info);
+ void HandleAddOutputPort(media::midi::MidiPortInfo info);
+ void HandleSetInputPortState(uint32 port, media::midi::MidiPortState state);
+ void HandleSetOutputPortState(uint32 port, media::midi::MidiPortState state);
void HandleDataReceived(uint32 port,
const std::vector<uint8>& data,
@@ -113,20 +129,24 @@ class CONTENT_EXPORT MidiMessageFilter : public IPC::MessageFilter {
* Notice: Following members are designed to be accessed only on
* |main_message_loop_|.
*/
- // Keeps track of all MIDI clients.
+ // Keeps track of all MIDI clients. This should be std::set so that various
+ // for-loops work correctly. To change the type, make sure that the new type
+ // is safe to modify the container inside for-loops.
typedef std::set<blink::WebMIDIAccessorClient*> ClientsSet;
ClientsSet clients_;
// Represents clients that are waiting for a session being open.
+ // Note: std::vector is not safe to invoke callbacks inside iterator based
+ // for-loops.
typedef std::vector<blink::WebMIDIAccessorClient*> ClientsQueue;
ClientsQueue clients_waiting_session_queue_;
// Represents a result on starting a session. Can be accessed only on
- media::MidiResult session_result_;
+ media::midi::MidiResult session_result_;
// Holds MidiPortInfoList for input ports and output ports.
- media::MidiPortInfoList inputs_;
- media::MidiPortInfoList outputs_;
+ media::midi::MidiPortInfoList inputs_;
+ media::midi::MidiPortInfoList outputs_;
size_t unacknowledged_bytes_sent_;
diff --git a/chromium/content/renderer/media/midi_message_filter_unittest.cc b/chromium/content/renderer/media/midi_message_filter_unittest.cc
new file mode 100644
index 00000000000..4323b2e5408
--- /dev/null
+++ b/chromium/content/renderer/media/midi_message_filter_unittest.cc
@@ -0,0 +1,34 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/media/midi_message_filter.h"
+
+#include "base/message_loop/message_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+namespace {
+using BlinkState = blink::WebMIDIAccessorClient::MIDIPortState;
+} // namespace
+
+TEST(MidiMessageFilterTest, CastMidiPortState) {
+ // Check if static_cast of ToMIDIPortState() just works fine for all states.
+ EXPECT_EQ(
+ BlinkState::MIDIPortStateDisconnected,
+ MidiMessageFilter::ToBlinkState(media::midi::MIDI_PORT_DISCONNECTED));
+ EXPECT_EQ(BlinkState::MIDIPortStateConnected,
+ MidiMessageFilter::ToBlinkState(media::midi::MIDI_PORT_CONNECTED));
+ // Web MIDI API manages DeviceState and ConnectionState separately.
+ // "open", "pending", or "closed" are managed separately for ConnectionState
+ // by Blink per MIDIAccess instance. So, MIDI_PORT_OPENED in content can be
+ // converted to MIDIPortStateConnected.
+ EXPECT_EQ(BlinkState::MIDIPortStateConnected,
+ MidiMessageFilter::ToBlinkState(media::midi::MIDI_PORT_OPENED));
+
+ // Check if we do not have any unknown MidiPortState that is added later.
+ EXPECT_EQ(media::midi::MIDI_PORT_OPENED, media::midi::MIDI_PORT_STATE_LAST);
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/media/mock_data_channel_impl.cc b/chromium/content/renderer/media/mock_data_channel_impl.cc
new file mode 100644
index 00000000000..8a0a3a80c95
--- /dev/null
+++ b/chromium/content/renderer/media/mock_data_channel_impl.cc
@@ -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.
+
+#include "content/renderer/media/mock_data_channel_impl.h"
+
+namespace content {
+
+MockDataChannel::MockDataChannel(const std::string& label,
+ const webrtc::DataChannelInit* config)
+ : label_(label),
+ reliable_(config->reliable),
+ state_(webrtc::DataChannelInterface::kConnecting),
+ config_(*config),
+ observer_(nullptr) {
+}
+
+MockDataChannel::~MockDataChannel() {
+}
+
+void MockDataChannel::RegisterObserver(webrtc::DataChannelObserver* observer) {
+ observer_ = observer;
+}
+
+void MockDataChannel::UnregisterObserver() {
+ observer_ = nullptr;
+}
+
+std::string MockDataChannel::label() const { return label_; }
+
+bool MockDataChannel::reliable() const { return reliable_; }
+
+bool MockDataChannel::ordered() const { return config_.ordered; }
+
+unsigned short MockDataChannel::maxRetransmitTime() const {
+ return config_.maxRetransmitTime;
+}
+
+unsigned short MockDataChannel::maxRetransmits() const {
+ return config_.maxRetransmits;
+}
+
+std::string MockDataChannel::protocol() const { return config_.protocol; }
+
+bool MockDataChannel::negotiated() const { return config_.negotiated; }
+
+int MockDataChannel::id() const {
+ NOTIMPLEMENTED();
+ return 0;
+}
+
+MockDataChannel::DataState MockDataChannel::state() const { return state_; }
+
+// For testing.
+void MockDataChannel::changeState(DataState state) {
+ state_ = state;
+ if (observer_)
+ observer_->OnStateChange();
+}
+
+uint64 MockDataChannel::buffered_amount() const {
+ NOTIMPLEMENTED();
+ return 0;
+}
+
+void MockDataChannel::Close() {
+ changeState(webrtc::DataChannelInterface::kClosing);
+}
+
+bool MockDataChannel::Send(const webrtc::DataBuffer& buffer) {
+ return state_ == webrtc::DataChannelInterface::kOpen;
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/media/mock_data_channel_impl.h b/chromium/content/renderer/media/mock_data_channel_impl.h
new file mode 100644
index 00000000000..45e3b2a9765
--- /dev/null
+++ b/chromium/content/renderer/media/mock_data_channel_impl.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_RENDERER_MEDIA_MOCK_DATA_CHANNEL_IMPL_H_
+#define CONTENT_RENDERER_MEDIA_MOCK_DATA_CHANNEL_IMPL_H_
+
+#include <string>
+
+#include "third_party/libjingle/source/talk/app/webrtc/peerconnectioninterface.h"
+
+namespace content {
+
+class MockDataChannel : public webrtc::DataChannelInterface {
+ public:
+ MockDataChannel(const std::string& label,
+ const webrtc::DataChannelInit* config);
+
+ void RegisterObserver(webrtc::DataChannelObserver* observer) override;
+ void UnregisterObserver() override;
+ std::string label() const override;
+ bool reliable() const override;
+ bool ordered() const override;
+ unsigned short maxRetransmitTime() const override;
+ unsigned short maxRetransmits() const override;
+ std::string protocol() const override;
+ bool negotiated() const override;
+ int id() const override;
+ DataState state() const override;
+ uint64 buffered_amount() const override;
+ void Close() override;
+ bool Send(const webrtc::DataBuffer& buffer) override;
+
+ // For testing.
+ void changeState(DataState state);
+
+ protected:
+ ~MockDataChannel() override;
+
+ private:
+ std::string label_;
+ bool reliable_;
+ webrtc::DataChannelInterface::DataState state_;
+ webrtc::DataChannelInit config_;
+ webrtc::DataChannelObserver* observer_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockDataChannel);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_MEDIA_MOCK_DATA_CHANNEL_IMPL_H_
diff --git a/chromium/content/renderer/media/mock_media_constraint_factory.h b/chromium/content/renderer/media/mock_media_constraint_factory.h
index e98cb30429b..4632dacdfd9 100644
--- a/chromium/content/renderer/media/mock_media_constraint_factory.h
+++ b/chromium/content/renderer/media/mock_media_constraint_factory.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_RENDERER_MEDIA_MOCK_MEDIA_STREAM_CONSTRAINT_H_
-#define CONTENT_RENDERER_MEDIA_MOCK_MEDIA_STREAM_CONSTRAINT_H_
+#ifndef CONTENT_RENDERER_MEDIA_MOCK_MEDIA_CONSTRAINT_FACTORY_H_
+#define CONTENT_RENDERER_MEDIA_MOCK_MEDIA_CONSTRAINT_FACTORY_H_
#include <string>
#include <vector>
@@ -35,4 +35,4 @@ class MockMediaConstraintFactory {
} // namespace content
-#endif // CONTENT_RENDERER_MEDIA_MOCK_MEDIA_STREAM_CONSTRAINT_H_
+#endif // CONTENT_RENDERER_MEDIA_MOCK_MEDIA_CONSTRAINT_FACTORY_H_
diff --git a/chromium/content/renderer/media/mock_media_stream_registry.cc b/chromium/content/renderer/media/mock_media_stream_registry.cc
index 53bf948479a..deb60fc5e05 100644
--- a/chromium/content/renderer/media/mock_media_stream_registry.cc
+++ b/chromium/content/renderer/media/mock_media_stream_registry.cc
@@ -35,7 +35,8 @@ void MockMediaStreamRegistry::AddVideoTrack(const std::string& track_id) {
blink::WebMediaStreamSource blink_source;
blink_source.initialize("mock video source id",
blink::WebMediaStreamSource::TypeVideo,
- "mock video source name");
+ "mock video source name",
+ false /* remote */, true /* readonly */);
MockMediaStreamVideoSource* native_source =
new MockMediaStreamVideoSource(false);
blink_source.setExtraData(native_source);
diff --git a/chromium/content/renderer/media/mock_media_stream_video_sink.cc b/chromium/content/renderer/media/mock_media_stream_video_sink.cc
index 7a054ab3f71..2ded48ae3bf 100644
--- a/chromium/content/renderer/media/mock_media_stream_video_sink.cc
+++ b/chromium/content/renderer/media/mock_media_stream_video_sink.cc
@@ -29,7 +29,6 @@ MockMediaStreamVideoSink::GetDeliverFrameCB() {
void MockMediaStreamVideoSink::DeliverVideoFrame(
const scoped_refptr<media::VideoFrame>& frame,
- const media::VideoCaptureFormat& format,
const base::TimeTicks& estimated_capture_time) {
last_frame_ = frame;
++number_of_frames_;
diff --git a/chromium/content/renderer/media/mock_media_stream_video_sink.h b/chromium/content/renderer/media/mock_media_stream_video_sink.h
index eeb976a08e0..a7ca3500ea1 100644
--- a/chromium/content/renderer/media/mock_media_stream_video_sink.h
+++ b/chromium/content/renderer/media/mock_media_stream_video_sink.h
@@ -17,11 +17,11 @@ namespace content {
class MockMediaStreamVideoSink : public MediaStreamVideoSink {
public:
MockMediaStreamVideoSink();
- virtual ~MockMediaStreamVideoSink();
+ ~MockMediaStreamVideoSink() override;
- virtual void OnReadyStateChanged(
+ void OnReadyStateChanged(
blink::WebMediaStreamSource::ReadyState state) override;
- virtual void OnEnabledChanged(bool enabled) override;
+ void OnEnabledChanged(bool enabled) override;
// Triggered when OnVideoFrame(const scoped_refptr<media::VideoFrame>& frame)
// is called.
@@ -38,10 +38,8 @@ class MockMediaStreamVideoSink : public MediaStreamVideoSink {
blink::WebMediaStreamSource::ReadyState state() const { return state_; }
private:
- void DeliverVideoFrame(
- const scoped_refptr<media::VideoFrame>& frame,
- const media::VideoCaptureFormat& format,
- const base::TimeTicks& estimated_capture_time);
+ void DeliverVideoFrame(const scoped_refptr<media::VideoFrame>& frame,
+ const base::TimeTicks& estimated_capture_time);
int number_of_frames_;
bool enabled_;
@@ -54,4 +52,4 @@ class MockMediaStreamVideoSink : public MediaStreamVideoSink {
} // namespace content
-#endif
+#endif // CONTENT_RENDERER_MEDIA_MOCK_MEDIA_STREAM_VIDEO_SINK_H_
diff --git a/chromium/content/renderer/media/mock_media_stream_video_source.cc b/chromium/content/renderer/media/mock_media_stream_video_source.cc
index 19f7b6f74d1..cf9f6856e21 100644
--- a/chromium/content/renderer/media/mock_media_stream_video_source.cc
+++ b/chromium/content/renderer/media/mock_media_stream_video_source.cc
@@ -63,6 +63,7 @@ void MockMediaStreamVideoSource::GetCurrentSupportedFormats(
void MockMediaStreamVideoSource::StartSourceImpl(
const media::VideoCaptureFormat& format,
+ const blink::WebMediaConstraints& constraints,
const VideoCaptureDeliverFrameCB& frame_callback) {
DCHECK(frame_callback_.is_null());
format_ = format;
@@ -78,17 +79,7 @@ void MockMediaStreamVideoSource::DeliverVideoFrame(
DCHECK(!frame_callback_.is_null());
io_message_loop()->PostTask(
FROM_HERE,
- base::Bind(&MockMediaStreamVideoSource::DeliverVideoFrameOnIO,
- base::Unretained(this), frame, format_,
- base::TimeTicks(), frame_callback_));
-}
-
-void MockMediaStreamVideoSource::DeliverVideoFrameOnIO(
- const scoped_refptr<media::VideoFrame>& frame,
- media::VideoCaptureFormat format,
- const base::TimeTicks& estimated_capture_time,
- const VideoCaptureDeliverFrameCB& frame_callback) {
- frame_callback.Run(frame, format, estimated_capture_time);
+ base::Bind(frame_callback_, frame, base::TimeTicks()));
}
} // namespace content
diff --git a/chromium/content/renderer/media/mock_media_stream_video_source.h b/chromium/content/renderer/media/mock_media_stream_video_source.h
index 9602b2fb38e..f9126014385 100644
--- a/chromium/content/renderer/media/mock_media_stream_video_source.h
+++ b/chromium/content/renderer/media/mock_media_stream_video_source.h
@@ -44,27 +44,23 @@ class MockMediaStreamVideoSource : public MediaStreamVideoSource {
int max_requested_width() const { return max_requested_width_; }
double max_requested_frame_rate() const { return max_requested_frame_rate_; }
- virtual void SetMutedState(bool muted_state) override {
+ void SetMutedState(bool muted_state) override {
MediaStreamVideoSource::SetMutedState(muted_state);
DoSetMutedState(muted_state);
}
protected:
- void DeliverVideoFrameOnIO(const scoped_refptr<media::VideoFrame>& frame,
- media::VideoCaptureFormat format,
- const base::TimeTicks& estimated_capture_time,
- const VideoCaptureDeliverFrameCB& frame_callback);
-
// Implements MediaStreamVideoSource.
- virtual void GetCurrentSupportedFormats(
+ void GetCurrentSupportedFormats(
int max_requested_height,
int max_requested_width,
double max_requested_frame_rate,
const VideoCaptureDeviceFormatsCB& callback) override;
- virtual void StartSourceImpl(
+ void StartSourceImpl(
const media::VideoCaptureFormat& format,
+ const blink::WebMediaConstraints& constraints,
const VideoCaptureDeliverFrameCB& frame_callback) override;
- virtual void StopSourceImpl() override;
+ void StopSourceImpl() override;
private:
media::VideoCaptureFormat format_;
diff --git a/chromium/content/renderer/media/mock_peer_connection_impl.cc b/chromium/content/renderer/media/mock_peer_connection_impl.cc
index 6df5a327a21..4be2d7781b2 100644
--- a/chromium/content/renderer/media/mock_peer_connection_impl.cc
+++ b/chromium/content/renderer/media/mock_peer_connection_impl.cc
@@ -7,6 +7,7 @@
#include <vector>
#include "base/logging.h"
+#include "content/renderer/media/mock_data_channel_impl.h"
#include "content/renderer/media/webrtc/mock_peer_connection_dependency_factory.h"
using testing::_;
@@ -76,66 +77,6 @@ class MockStreamCollection : public webrtc::StreamCollectionInterface {
StreamVector streams_;
};
-class MockDataChannel : public webrtc::DataChannelInterface {
- public:
- MockDataChannel(const std::string& label,
- const webrtc::DataChannelInit* config)
- : label_(label),
- reliable_(config->reliable),
- state_(webrtc::DataChannelInterface::kConnecting),
- config_(*config) {
- }
-
- void RegisterObserver(webrtc::DataChannelObserver* observer) override {}
-
- void UnregisterObserver() override {}
-
- std::string label() const override { return label_; }
-
- bool reliable() const override { return reliable_; }
-
- bool ordered() const override { return config_.ordered; }
-
- unsigned short maxRetransmitTime() const override {
- return config_.maxRetransmitTime;
- }
-
- unsigned short maxRetransmits() const override {
- return config_.maxRetransmits;
- }
-
- std::string protocol() const override { return config_.protocol; }
-
- bool negotiated() const override { return config_.negotiated; }
-
- int id() const override {
- NOTIMPLEMENTED();
- return 0;
- }
-
- DataState state() const override { return state_; }
-
- uint64 buffered_amount() const override {
- NOTIMPLEMENTED();
- return 0;
- }
-
- void Close() override { state_ = webrtc::DataChannelInterface::kClosing; }
-
- bool Send(const webrtc::DataBuffer& buffer) override {
- return state_ == webrtc::DataChannelInterface::kOpen;
- }
-
- protected:
- ~MockDataChannel() override {}
-
- private:
- std::string label_;
- bool reliable_;
- webrtc::DataChannelInterface::DataState state_;
- webrtc::DataChannelInit config_;
-};
-
class MockDtmfSender : public DtmfSenderInterface {
public:
explicit MockDtmfSender(AudioTrackInterface* track)
@@ -240,14 +181,13 @@ bool MockPeerConnectionImpl::GetStats(
return false;
DCHECK_EQ(kStatsOutputLevelStandard, level);
- webrtc::StatsReport report1, report2;
- report1.id = "1234";
- report1.type = "ssrc";
- report1.timestamp = 42;
- report1.values.push_back(
- webrtc::StatsReport::Value(
- webrtc::StatsReport::kStatsValueNameFingerprint,
- "trackvalue"));
+ webrtc::StatsReport report1(webrtc::StatsReport::NewTypedId(
+ webrtc::StatsReport::kStatsReportTypeSsrc, "1234"));
+ webrtc::StatsReport report2(webrtc::StatsReport::NewTypedId(
+ webrtc::StatsReport::kStatsReportTypeSession, "nontrack"));
+ report1.set_timestamp(42);
+ report1.AddString(webrtc::StatsReport::kStatsValueNameFingerprint,
+ "trackvalue");
webrtc::StatsReports reports;
reports.push_back(&report1);
@@ -255,13 +195,9 @@ bool MockPeerConnectionImpl::GetStats(
// If selector is given, we pass back one report.
// If selector is not given, we pass back two.
if (!track) {
- report2.id = "nontrack";
- report2.type = "generic";
- report2.timestamp = 44;
- report2.values.push_back(
- webrtc::StatsReport::Value(
- webrtc::StatsReport::kStatsValueNameFingerprintAlgorithm,
- "somevalue"));
+ report2.set_timestamp(44);
+ report2.AddString(webrtc::StatsReport::kStatsValueNameFingerprintAlgorithm,
+ "somevalue");
reports.push_back(&report2);
}
diff --git a/chromium/content/renderer/media/mock_peer_connection_impl.h b/chromium/content/renderer/media/mock_peer_connection_impl.h
index 5e892944547..ef7d63bee5b 100644
--- a/chromium/content/renderer/media/mock_peer_connection_impl.h
+++ b/chromium/content/renderer/media/mock_peer_connection_impl.h
@@ -25,61 +25,55 @@ class MockPeerConnectionImpl : public webrtc::PeerConnectionInterface {
webrtc::PeerConnectionObserver* observer);
// PeerConnectionInterface implementation.
- virtual rtc::scoped_refptr<webrtc::StreamCollectionInterface>
+ rtc::scoped_refptr<webrtc::StreamCollectionInterface>
local_streams() override;
- virtual rtc::scoped_refptr<webrtc::StreamCollectionInterface>
+ rtc::scoped_refptr<webrtc::StreamCollectionInterface>
remote_streams() override;
- virtual bool AddStream(
+ bool AddStream(
webrtc::MediaStreamInterface* local_stream) override;
- virtual void RemoveStream(
+ void RemoveStream(
webrtc::MediaStreamInterface* local_stream) override;
- virtual rtc::scoped_refptr<webrtc::DtmfSenderInterface>
+ rtc::scoped_refptr<webrtc::DtmfSenderInterface>
CreateDtmfSender(webrtc::AudioTrackInterface* track) override;
- virtual rtc::scoped_refptr<webrtc::DataChannelInterface>
+ rtc::scoped_refptr<webrtc::DataChannelInterface>
CreateDataChannel(const std::string& label,
const webrtc::DataChannelInit* config) override;
-
- virtual bool GetStats(webrtc::StatsObserver* observer,
- webrtc::MediaStreamTrackInterface* track) {
- return false;
- }
- virtual bool GetStats(webrtc::StatsObserver* observer,
- webrtc::MediaStreamTrackInterface* track,
- StatsOutputLevel level) override;
+ bool GetStats(webrtc::StatsObserver* observer,
+ webrtc::MediaStreamTrackInterface* track,
+ StatsOutputLevel level) override;
// Set Call this function to make sure next call to GetStats fail.
void SetGetStatsResult(bool result) { getstats_result_ = result; }
- virtual SignalingState signaling_state() override {
+ SignalingState signaling_state() override {
NOTIMPLEMENTED();
return PeerConnectionInterface::kStable;
}
- virtual IceState ice_state() override {
+ IceState ice_state() override {
NOTIMPLEMENTED();
return PeerConnectionInterface::kIceNew;
}
- virtual IceConnectionState ice_connection_state() override {
+ IceConnectionState ice_connection_state() override {
NOTIMPLEMENTED();
return PeerConnectionInterface::kIceConnectionNew;
}
- virtual IceGatheringState ice_gathering_state() override {
+ IceGatheringState ice_gathering_state() override {
NOTIMPLEMENTED();
return PeerConnectionInterface::kIceGatheringNew;
}
- virtual void Close() override {
+ void Close() override {
NOTIMPLEMENTED();
}
- virtual const webrtc::SessionDescriptionInterface* local_description()
- const override;
- virtual const webrtc::SessionDescriptionInterface* remote_description()
+ const webrtc::SessionDescriptionInterface* local_description() const override;
+ const webrtc::SessionDescriptionInterface* remote_description()
const override;
// JSEP01 APIs
- virtual void CreateOffer(
+ void CreateOffer(
webrtc::CreateSessionDescriptionObserver* observer,
const webrtc::MediaConstraintsInterface* constraints) override;
- virtual void CreateAnswer(
+ void CreateAnswer(
webrtc::CreateSessionDescriptionObserver* observer,
const webrtc::MediaConstraintsInterface* constraints) override;
MOCK_METHOD2(SetLocalDescription,
@@ -94,12 +88,10 @@ class MockPeerConnectionImpl : public webrtc::PeerConnectionInterface {
void SetRemoteDescriptionWorker(
webrtc::SetSessionDescriptionObserver* observer,
webrtc::SessionDescriptionInterface* desc);
- virtual bool UpdateIce(
- const IceServers& configuration,
- const webrtc::MediaConstraintsInterface* constraints) override;
- virtual bool AddIceCandidate(
- const webrtc::IceCandidateInterface* candidate) override;
- virtual void RegisterUMAObserver(webrtc::UMAObserver* observer) override;
+ bool UpdateIce(const IceServers& configuration,
+ const webrtc::MediaConstraintsInterface* constraints) override;
+ bool AddIceCandidate(const webrtc::IceCandidateInterface* candidate) override;
+ void RegisterUMAObserver(webrtc::UMAObserver* observer) override;
void AddRemoteStream(webrtc::MediaStreamInterface* stream);
diff --git a/chromium/content/renderer/media/native_handle_impl.cc b/chromium/content/renderer/media/native_handle_impl.cc
deleted file mode 100644
index 3988e3934b1..00000000000
--- a/chromium/content/renderer/media/native_handle_impl.cc
+++ /dev/null
@@ -1,16 +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/renderer/media/native_handle_impl.h"
-
-namespace content {
-
-NativeHandleImpl::NativeHandleImpl(scoped_refptr<media::VideoFrame> frame)
- : frame_(frame) {}
-
-NativeHandleImpl::~NativeHandleImpl() {}
-
-void* NativeHandleImpl::GetHandle() { return frame_.get(); }
-
-} // namespace content
diff --git a/chromium/content/renderer/media/native_handle_impl.h b/chromium/content/renderer/media/native_handle_impl.h
deleted file mode 100644
index 20a4f038c6f..00000000000
--- a/chromium/content/renderer/media/native_handle_impl.h
+++ /dev/null
@@ -1,32 +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_RENDERER_MEDIA_NATIVE_HANDLE_IMPL_H_
-#define CONTENT_RENDERER_MEDIA_NATIVE_HANDLE_IMPL_H_
-
-#include "base/memory/ref_counted.h"
-#include "media/base/video_frame.h"
-#include "third_party/webrtc/common_video/interface/native_handle.h"
-
-namespace content {
-
-class NativeHandleImpl : public webrtc::NativeHandle {
- public:
- // Wraps a video frame in the handle.
- explicit NativeHandleImpl(scoped_refptr<media::VideoFrame> frame);
- ~NativeHandleImpl() override;
-
- // Retrieves the video frame in the handle. The frame is still ref-counted by
- // the handle. The ref count decreases when NativeHandleImpl is destroyed.
- void* GetHandle() override;
-
- private:
- scoped_refptr<media::VideoFrame> frame_;
-
- DISALLOW_COPY_AND_ASSIGN(NativeHandleImpl);
-};
-
-} // namespace content
-
-#endif // CONTENT_RENDERER_MEDIA_NATIVE_HANDLE_IMPL_H_
diff --git a/chromium/content/renderer/media/peer_connection_audio_sink_owner.cc b/chromium/content/renderer/media/peer_connection_audio_sink_owner.cc
deleted file mode 100644
index 4073ac61425..00000000000
--- a/chromium/content/renderer/media/peer_connection_audio_sink_owner.cc
+++ /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.
-
-#include "content/renderer/media/peer_connection_audio_sink_owner.h"
-
-#include "content/renderer/media/webrtc_audio_device_impl.h"
-
-namespace content {
-
-PeerConnectionAudioSinkOwner::PeerConnectionAudioSinkOwner(
- PeerConnectionAudioSink* sink)
- : delegate_(sink) {
-}
-
-int PeerConnectionAudioSinkOwner::OnData(const int16* audio_data,
- int sample_rate,
- int number_of_channels,
- int number_of_frames,
- const std::vector<int>& channels,
- int audio_delay_milliseconds,
- int current_volume,
- bool need_audio_processing,
- bool key_pressed) {
- base::AutoLock lock(lock_);
- if (delegate_) {
- return delegate_->OnData(audio_data,
- sample_rate,
- number_of_channels,
- number_of_frames,
- channels,
- audio_delay_milliseconds,
- current_volume,
- need_audio_processing,
- key_pressed);
- }
-
- return 0;
-}
-
-void PeerConnectionAudioSinkOwner::OnSetFormat(
- const media::AudioParameters& params) {
- base::AutoLock lock(lock_);
- if (delegate_)
- delegate_->OnSetFormat(params);
-}
-
-void PeerConnectionAudioSinkOwner::OnReadyStateChanged(
- blink::WebMediaStreamSource::ReadyState state) {
- // Not forwarded at the moment.
-}
-
-void PeerConnectionAudioSinkOwner::Reset() {
- base::AutoLock lock(lock_);
- delegate_ = NULL;
-}
-
-bool PeerConnectionAudioSinkOwner::IsEqual(
- const MediaStreamAudioSink* other) const {
- DCHECK(other);
- return false;
-}
-
-bool PeerConnectionAudioSinkOwner::IsEqual(
- const PeerConnectionAudioSink* other) const {
- DCHECK(other);
- base::AutoLock lock(lock_);
- return (other == delegate_);
-}
-
-} // namespace content
diff --git a/chromium/content/renderer/media/peer_connection_audio_sink_owner.h b/chromium/content/renderer/media/peer_connection_audio_sink_owner.h
deleted file mode 100644
index 0aaa0ea40b4..00000000000
--- a/chromium/content/renderer/media/peer_connection_audio_sink_owner.h
+++ /dev/null
@@ -1,54 +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_RENDERER_MEDIA_PEER_CONNECTION_AUDIO_SINK_OWNER_H_
-#define CONTENT_RENDERER_MEDIA_PEER_CONNECTION_AUDIO_SINK_OWNER_H_
-
-#include <vector>
-
-#include "base/synchronization/lock.h"
-#include "content/renderer/media/media_stream_audio_track_sink.h"
-
-namespace content {
-
-class PeerConnectionAudioSink;
-
-// Reference counted holder of PeerConnectionAudioSink.
-class PeerConnectionAudioSinkOwner : public MediaStreamAudioTrackSink {
- public:
- explicit PeerConnectionAudioSinkOwner(PeerConnectionAudioSink* sink);
-
- // MediaStreamAudioTrackSink implementation.
- int OnData(const int16* audio_data,
- int sample_rate,
- int number_of_channels,
- int number_of_frames,
- const std::vector<int>& channels,
- int audio_delay_milliseconds,
- int current_volume,
- bool need_audio_processing,
- bool key_pressed) override;
- void OnSetFormat(const media::AudioParameters& params) override;
- void OnReadyStateChanged(
- blink::WebMediaStreamSource::ReadyState state) override;
- void Reset() override;
- bool IsEqual(const MediaStreamAudioSink* other) const override;
- bool IsEqual(const PeerConnectionAudioSink* other) const override;
-
- protected:
- ~PeerConnectionAudioSinkOwner() override {}
-
- private:
- mutable base::Lock lock_;
-
- // Raw pointer to the delegate, the client need to call Reset() to set the
- // pointer to NULL before the delegate goes away.
- PeerConnectionAudioSink* delegate_;
-
- DISALLOW_COPY_AND_ASSIGN(PeerConnectionAudioSinkOwner);
-};
-
-} // namespace content
-
-#endif // CONTENT_RENDERER_MEDIA_PEER_CONNECTION_AUDIO_SINK_OWNER_H_
diff --git a/chromium/content/renderer/media/peer_connection_tracker.cc b/chromium/content/renderer/media/peer_connection_tracker.cc
index 25f1b2df9aa..5639efdc7e8 100644
--- a/chromium/content/renderer/media/peer_connection_tracker.cc
+++ b/chromium/content/renderer/media/peer_connection_tracker.cc
@@ -22,6 +22,8 @@
using std::string;
using webrtc::MediaConstraintsInterface;
+using webrtc::StatsReport;
+using webrtc::StatsReports;
using blink::WebRTCPeerConnectionHandlerClient;
namespace content {
@@ -145,6 +147,25 @@ static std::string SerializeIceTransportType(
return transport_type;
}
+static std::string SerializeBundlePolicy(
+ webrtc::PeerConnectionInterface::BundlePolicy policy) {
+ string policy_str;
+ switch (policy) {
+ case webrtc::PeerConnectionInterface::kBundlePolicyBalanced:
+ policy_str = "balanced";
+ break;
+ case webrtc::PeerConnectionInterface::kBundlePolicyMaxBundle:
+ policy_str = "max-bundle";
+ break;
+ case webrtc::PeerConnectionInterface::kBundlePolicyMaxCompat:
+ policy_str = "max-compat";
+ break;
+ default:
+ NOTREACHED();
+ };
+ return policy_str;
+}
+
#define GET_STRING_OF_STATE(state) \
case WebRTCPeerConnectionHandlerClient::state: \
result = #state; \
@@ -204,27 +225,49 @@ static string GetIceGatheringStateString(
// Note:
// The format must be consistent with what webrtc_internals.js expects.
// If you change it here, you must change webrtc_internals.js as well.
-static base::DictionaryValue* GetDictValueStats(
- const webrtc::StatsReport& report) {
- if (report.values.empty())
+static base::DictionaryValue* GetDictValueStats(const StatsReport& report) {
+ if (report.values().empty())
return NULL;
base::DictionaryValue* dict = new base::DictionaryValue();
- dict->SetDouble("timestamp", report.timestamp);
+ dict->SetDouble("timestamp", report.timestamp());
base::ListValue* values = new base::ListValue();
dict->Set("values", values);
- for (size_t i = 0; i < report.values.size(); ++i) {
- values->AppendString(report.values[i].display_name());
- values->AppendString(report.values[i].value);
+ for (const auto& v : report.values()) {
+ const StatsReport::ValuePtr& value = v.second;
+ values->AppendString(value->display_name());
+ switch (value->type()) {
+ case StatsReport::Value::kInt:
+ values->AppendInteger(value->int_val());
+ break;
+ case StatsReport::Value::kFloat:
+ values->AppendDouble(value->float_val());
+ break;
+ case StatsReport::Value::kString:
+ values->AppendString(value->string_val());
+ break;
+ case StatsReport::Value::kStaticString:
+ values->AppendString(value->static_string_val());
+ break;
+ case StatsReport::Value::kBool:
+ values->AppendBoolean(value->bool_val());
+ break;
+ case StatsReport::Value::kInt64: // int64 isn't supported, so use string.
+ case StatsReport::Value::kId:
+ default:
+ values->AppendString(value->ToString());
+ break;
+ }
}
+
return dict;
}
// Builds a DictionaryValue from the StatsReport.
// The caller takes the ownership of the returned value.
-static base::DictionaryValue* GetDictValue(const webrtc::StatsReport& report) {
+static base::DictionaryValue* GetDictValue(const StatsReport& report) {
scoped_ptr<base::DictionaryValue> stats, result;
stats.reset(GetDictValueStats(report));
@@ -236,8 +279,8 @@ static base::DictionaryValue* GetDictValue(const webrtc::StatsReport& report) {
// The format must be consistent with what webrtc_internals.js expects.
// If you change it here, you must change webrtc_internals.js as well.
result->Set("stats", stats.release());
- result->SetString("id", report.id);
- result->SetString("type", report.type);
+ result->SetString("id", report.id()->ToString());
+ result->SetString("type", report.TypeToString());
return result.release();
}
@@ -247,11 +290,11 @@ class InternalStatsObserver : public webrtc::StatsObserver {
InternalStatsObserver(int lid)
: lid_(lid), main_thread_(base::ThreadTaskRunnerHandle::Get()) {}
- void OnComplete(const std::vector<webrtc::StatsReport>& reports) override {
+ void OnComplete(const StatsReports& reports) override {
scoped_ptr<base::ListValue> list(new base::ListValue());
- for (size_t i = 0; i < reports.size(); ++i) {
- base::DictionaryValue* report = GetDictValue(reports[i]);
+ for (const auto* r : reports) {
+ base::DictionaryValue* report = GetDictValue(*r);
if (report)
list->Append(report);
}
@@ -338,7 +381,8 @@ void PeerConnectionTracker::RegisterPeerConnection(
info.lid = GetNextLocalID();
info.rtc_configuration =
"{ servers: " + SerializeServers(config.servers) + ", " +
- "iceTransportType: " + SerializeIceTransportType(config.type) + " }";
+ "iceTransportType: " + SerializeIceTransportType(config.type) + ", " +
+ "bundlePolicy: " + SerializeBundlePolicy(config.bundle_policy) + " }";
info.constraints = SerializeMediaConstraints(constraints);
info.url = frame->document().url().spec();
@@ -409,13 +453,17 @@ void PeerConnectionTracker::TrackUpdateIce(
string transport_type =
"iceTransportType: " + SerializeIceTransportType(config.type);
+ string bundle_policy =
+ "bundlePolicy: " + SerializeBundlePolicy(config.bundle_policy);
+
string constraints =
"constraints: {" + SerializeMediaConstraints(options) + "}";
SendPeerConnectionUpdate(
pc_handler,
"updateIce",
- servers_string + ", " + transport_type + ", " + constraints);
+ servers_string + ", " + transport_type + ", " +
+ bundle_policy + ", " + constraints);
}
void PeerConnectionTracker::TrackAddIceCandidate(
diff --git a/chromium/content/renderer/media/peer_connection_tracker.h b/chromium/content/renderer/media/peer_connection_tracker.h
index 08f908607fe..2e12a15c0e5 100644
--- a/chromium/content/renderer/media/peer_connection_tracker.h
+++ b/chromium/content/renderer/media/peer_connection_tracker.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_RENDERER_MEDIA_PEERCONNECTION_TRACKER_H_
-#define CONTENT_RENDERER_MEDIA_PEERCONNECTION_TRACKER_H_
+#ifndef CONTENT_RENDERER_MEDIA_PEER_CONNECTION_TRACKER_H_
+#define CONTENT_RENDERER_MEDIA_PEER_CONNECTION_TRACKER_H_
#include <map>
@@ -187,4 +187,4 @@ class CONTENT_EXPORT PeerConnectionTracker
} // namespace content
-#endif // CONTENT_RENDERER_MEDIA_PEERCONNECTION_TRACKER_H_
+#endif // CONTENT_RENDERER_MEDIA_PEER_CONNECTION_TRACKER_H_
diff --git a/chromium/content/renderer/media/remote_media_stream_impl.cc b/chromium/content/renderer/media/remote_media_stream_impl.cc
index 06f41772d44..1b0c64705b3 100644
--- a/chromium/content/renderer/media/remote_media_stream_impl.cc
+++ b/chromium/content/renderer/media/remote_media_stream_impl.cc
@@ -16,6 +16,7 @@
#include "content/renderer/media/media_stream_video_track.h"
#include "content/renderer/media/webrtc/media_stream_remote_video_source.h"
#include "content/renderer/media/webrtc/peer_connection_dependency_factory.h"
+#include "content/renderer/media/webrtc/track_observer.h"
#include "third_party/WebKit/public/platform/WebString.h"
namespace content {
@@ -124,7 +125,8 @@ class RemoteMediaStreamTrackAdapter
blink::WebString webkit_track_id(base::UTF8ToUTF16(id_));
blink::WebMediaStreamSource webkit_source;
- webkit_source.initialize(webkit_track_id, type, webkit_track_id);
+ webkit_source.initialize(webkit_track_id, type, webkit_track_id,
+ true /* remote */, true /* readonly */);
webkit_track_.initialize(webkit_track_id, webkit_source);
DCHECK(!webkit_track_.isNull());
}
@@ -154,43 +156,24 @@ class RemoteVideoTrackAdapter
const scoped_refptr<base::SingleThreadTaskRunner>& main_thread,
webrtc::VideoTrackInterface* webrtc_track)
: RemoteMediaStreamTrackAdapter(main_thread, webrtc_track) {
- source_observer_ = new MediaStreamRemoteVideoSource::Observer(main_thread,
- observed_track().get());
+ scoped_ptr<TrackObserver> observer(
+ new TrackObserver(main_thread, observed_track().get()));
// Here, we use base::Unretained() to avoid a circular reference.
webkit_initialize_ = base::Bind(
&RemoteVideoTrackAdapter::InitializeWebkitVideoTrack,
- base::Unretained(this), observed_track()->enabled());
+ base::Unretained(this), base::Passed(&observer),
+ observed_track()->enabled());
}
protected:
- ~RemoteVideoTrackAdapter() override {
- // If the source_observer_ is valid at this point, then that means we
- // haven't been initialized and we need to unregister the observer before
- // it gets automatically deleted. We can't unregister from the destructor
- // of the observer because at that point, the refcount will be 0 and we
- // could receive an event during that time which would attempt to increment
- // the refcount while we're running the dtor on this thread...
- if (source_observer_.get()) {
- DCHECK(!initialized());
- source_observer_->Unregister();
- }
-
- // TODO(tommi): There's got to be a smarter way of solving this.
- // We should probably separate the implementation of the observer itself
- // and the ownerof the weakptr to the main thread's implementation of
- // OnChanged.
- }
+ ~RemoteVideoTrackAdapter() override {}
private:
- void InitializeWebkitVideoTrack(bool enabled) {
+ void InitializeWebkitVideoTrack(scoped_ptr<TrackObserver> observer,
+ bool enabled) {
DCHECK(main_thread_->BelongsToCurrentThread());
scoped_ptr<MediaStreamRemoteVideoSource> video_source(
- new MediaStreamRemoteVideoSource(source_observer_));
- // Now that we're being initialized, we do not want to unregister the
- // observer in the dtor. This will be done when the source goes out of
- // scope. A source can be shared by more than one tracks (e.g via cloning)
- // so we must not unregister an observer that belongs to a live source.
- source_observer_ = nullptr;
+ new MediaStreamRemoteVideoSource(observer.Pass()));
InitializeWebkitTrack(blink::WebMediaStreamSource::TypeVideo);
webkit_track()->source().setExtraData(video_source.get());
// Initial constraints must be provided to a MediaStreamVideoTrack. But
@@ -202,11 +185,6 @@ class RemoteVideoTrackAdapter
MediaStreamVideoSource::ConstraintsCallback(), enabled);
webkit_track()->setExtraData(media_stream_track);
}
-
- // We hold on to the source observer in case we don't get initialized and
- // need to unregister it in the dtor.
- // TODO(tommi): There has to be a more elegant solution.
- scoped_refptr<MediaStreamRemoteVideoSource::Observer> source_observer_;
};
// RemoteAudioTrackAdapter is responsible for listening on state
@@ -235,7 +213,7 @@ class RemoteAudioTrackAdapter
void OnChangedOnMainThread(
webrtc::MediaStreamTrackInterface::TrackState state);
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
bool unregistered_;
#endif
@@ -249,10 +227,11 @@ RemoteAudioTrackAdapter::RemoteAudioTrackAdapter(
const scoped_refptr<base::SingleThreadTaskRunner>& main_thread,
webrtc::AudioTrackInterface* webrtc_track)
: RemoteMediaStreamTrackAdapter(main_thread, webrtc_track),
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
unregistered_(false),
#endif
state_(observed_track()->state()) {
+ // TODO(tommi): Use TrackObserver instead.
observed_track()->RegisterObserver(this);
scoped_ptr<RemoteMediaStreamAudioTrack> media_stream_track(
new RemoteMediaStreamAudioTrack(observed_track().get(),
@@ -264,13 +243,13 @@ RemoteAudioTrackAdapter::RemoteAudioTrackAdapter(
}
RemoteAudioTrackAdapter::~RemoteAudioTrackAdapter() {
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
DCHECK(unregistered_);
#endif
}
void RemoteAudioTrackAdapter::Unregister() {
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
DCHECK(!unregistered_);
unregistered_ = true;
#endif
@@ -373,9 +352,9 @@ RemoteMediaStreamImpl::RemoteMediaStreamImpl(
const scoped_refptr<base::SingleThreadTaskRunner>& main_thread,
webrtc::MediaStreamInterface* webrtc_stream)
: signaling_thread_(base::ThreadTaskRunnerHandle::Get()),
- weak_factory_(this),
- observer_(new RemoteMediaStreamImpl::Observer(weak_factory_.GetWeakPtr(),
- main_thread, webrtc_stream)) {
+ weak_factory_(this) {
+ observer_ = new RemoteMediaStreamImpl::Observer(
+ weak_factory_.GetWeakPtr(), main_thread, webrtc_stream);
CreateAdaptersForTracks(webrtc_stream->GetAudioTracks(),
&audio_track_observers_, main_thread);
CreateAdaptersForTracks(webrtc_stream->GetVideoTracks(),
diff --git a/chromium/content/renderer/media/remote_media_stream_impl.h b/chromium/content/renderer/media/remote_media_stream_impl.h
index 0c230bac73f..ec97f233ed9 100644
--- a/chromium/content/renderer/media/remote_media_stream_impl.h
+++ b/chromium/content/renderer/media/remote_media_stream_impl.h
@@ -91,13 +91,14 @@ class CONTENT_EXPORT RemoteMediaStreamImpl {
scoped_ptr<RemoteVideoTrackAdapters> video_tracks);
const scoped_refptr<base::SingleThreadTaskRunner> signaling_thread_;
- base::WeakPtrFactory<RemoteMediaStreamImpl> weak_factory_;
- const scoped_refptr<Observer> observer_; // must be after weak_factory_
+ scoped_refptr<Observer> observer_;
RemoteVideoTrackAdapters video_track_observers_;
RemoteAudioTrackAdapters audio_track_observers_;
blink::WebMediaStream webkit_stream_;
+ base::WeakPtrFactory<RemoteMediaStreamImpl> weak_factory_;
+
DISALLOW_COPY_AND_ASSIGN(RemoteMediaStreamImpl);
};
diff --git a/chromium/content/renderer/media/render_media_client.cc b/chromium/content/renderer/media/render_media_client.cc
new file mode 100644
index 00000000000..165db1773af
--- /dev/null
+++ b/chromium/content/renderer/media/render_media_client.cc
@@ -0,0 +1,103 @@
+// Copyright 2014 The Chromium Authors. 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/renderer/media/render_media_client.h"
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/time/default_tick_clock.h"
+#include "content/public/common/content_client.h"
+#include "content/public/renderer/content_renderer_client.h"
+
+namespace content {
+
+static base::LazyInstance<RenderMediaClient>::Leaky g_render_media_client =
+ LAZY_INSTANCE_INITIALIZER;
+
+void RenderMediaClient::Initialize() {
+ g_render_media_client.Get();
+}
+
+RenderMediaClient::RenderMediaClient()
+ : has_updated_(false),
+ is_update_needed_(true),
+ tick_clock_(new base::DefaultTickClock()) {
+ media::SetMediaClient(this);
+}
+
+RenderMediaClient::~RenderMediaClient() {
+}
+
+void RenderMediaClient::AddKeySystemsInfoForUMA(
+ std::vector<media::KeySystemInfoForUMA>* key_systems_info_for_uma) {
+ DVLOG(2) << __FUNCTION__;
+#if defined(WIDEVINE_CDM_AVAILABLE)
+ key_systems_info_for_uma->push_back(media::KeySystemInfoForUMA(
+ kWidevineKeySystem, kWidevineKeySystemNameForUMA, true));
+#endif // WIDEVINE_CDM_AVAILABLE
+}
+
+bool RenderMediaClient::IsKeySystemsUpdateNeeded() {
+ DVLOG(2) << __FUNCTION__;
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ // Always needs update if we have never updated, regardless the
+ // |last_update_time_ticks_|'s initial value.
+ if (!has_updated_) {
+ DCHECK(is_update_needed_);
+ return true;
+ }
+
+ if (!is_update_needed_)
+ return false;
+
+ // The update could be expensive. For example, it could involve a sync IPC to
+ // the browser process. Use a minimum update interval to avoid unnecessarily
+ // frequent update.
+ static const int kMinUpdateIntervalInMilliseconds = 1000;
+ if ((tick_clock_->NowTicks() - last_update_time_ticks_).InMilliseconds() <
+ kMinUpdateIntervalInMilliseconds) {
+ return false;
+ }
+
+ return true;
+}
+
+void RenderMediaClient::AddSupportedKeySystems(
+ std::vector<media::KeySystemInfo>* key_systems_info) {
+ DVLOG(2) << __FUNCTION__;
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ GetContentClient()->renderer()->AddKeySystems(key_systems_info);
+
+ has_updated_ = true;
+ last_update_time_ticks_ = tick_clock_->NowTicks();
+
+ // Check whether all potentially supported key systems are supported. If so,
+ // no need to update again.
+#if defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT)
+ for (const media::KeySystemInfo& key_system_info : *key_systems_info) {
+ if (key_system_info.key_system == kWidevineKeySystem)
+ is_update_needed_ = false;
+ }
+#else
+ is_update_needed_ = false;
+#endif
+}
+
+void RenderMediaClient::SetTickClockForTesting(
+ scoped_ptr<base::TickClock> tick_clock) {
+ tick_clock_.swap(tick_clock);
+}
+
+// This functions is for testing purpose only. The declaration in the
+// header file is guarded by "#if defined(UNIT_TEST)" so that it can be used
+// by tests but not non-test code. However, this .cc file is compiled as part of
+// "content" where "UNIT_TEST" is not defined. So we need to specify
+// "CONTENT_EXPORT" here again so that it is visible to tests.
+CONTENT_EXPORT RenderMediaClient* GetRenderMediaClientInstanceForTesting() {
+ return g_render_media_client.Pointer();
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/media/render_media_client.h b/chromium/content/renderer/media/render_media_client.h
new file mode 100644
index 00000000000..b873eb5bdf7
--- /dev/null
+++ b/chromium/content/renderer/media/render_media_client.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_RENDERER_MEDIA_RENDER_MEDIA_CLIENT_H_
+#define CONTENT_RENDERER_MEDIA_RENDER_MEDIA_CLIENT_H_
+
+#include "base/lazy_instance.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/threading/thread_checker.h"
+#include "base/time/tick_clock.h"
+#include "base/time/time.h"
+#include "content/common/content_export.h"
+#include "media/base/media_client.h"
+
+#include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR.
+
+namespace content {
+
+class CONTENT_EXPORT RenderMediaClient : public media::MediaClient {
+ public:
+ // Initialize RenderMediaClient and SetMediaClient(). Note that the instance
+ // is not exposed because no content code needs to directly access it.
+ static void Initialize();
+
+ // MediaClient implementation.
+ void AddKeySystemsInfoForUMA(std::vector<media::KeySystemInfoForUMA>*
+ key_systems_info_for_uma) override;
+ bool IsKeySystemsUpdateNeeded() override;
+ void AddSupportedKeySystems(
+ std::vector<media::KeySystemInfo>* key_systems_info) override;
+
+ void SetTickClockForTesting(scoped_ptr<base::TickClock> tick_clock);
+
+ private:
+ friend struct base::DefaultLazyInstanceTraits<RenderMediaClient>;
+
+ RenderMediaClient();
+ ~RenderMediaClient() override;
+
+ // Makes sure all methods are called from the same thread.
+ base::ThreadChecker thread_checker_;
+
+ // Whether AddSupportedKeySystems() has ever been called.
+ bool has_updated_;
+
+ // Whether a future update is needed. For example, when some potentially
+ // supported key systems are NOT supported yet. This could happen when the
+ // required component for a key system is not yet available.
+ bool is_update_needed_;
+
+ base::TimeTicks last_update_time_ticks_;
+ scoped_ptr<base::TickClock> tick_clock_;
+
+ DISALLOW_COPY_AND_ASSIGN(RenderMediaClient);
+};
+
+#if defined(UNIT_TEST)
+// Helper function to access the RenderMediaClient instance. Used only by unit
+// tests.
+CONTENT_EXPORT RenderMediaClient* GetRenderMediaClientInstanceForTesting();
+#endif
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_MEDIA_RENDER_MEDIA_CLIENT_H_
diff --git a/chromium/content/renderer/media/render_media_client_unittest.cc b/chromium/content/renderer/media/render_media_client_unittest.cc
new file mode 100644
index 00000000000..f40d0c5aa2d
--- /dev/null
+++ b/chromium/content/renderer/media/render_media_client_unittest.cc
@@ -0,0 +1,166 @@
+// Copyright 2014 The Chromium Authors. 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/test/simple_test_tick_clock.h"
+#include "content/public/renderer/content_renderer_client.h"
+#include "content/renderer/media/render_media_client.h"
+#include "content/test/test_content_client.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR.
+
+namespace content {
+
+namespace {
+
+class TestContentRendererClient : public ContentRendererClient {
+ public:
+ TestContentRendererClient() : is_extra_key_system_enabled_(false) {}
+
+ // ContentRendererClient implementation.
+ void AddKeySystems(
+ std::vector<media::KeySystemInfo>* key_systems_info) override {
+ // TODO(sandersd): Was this supposed to be added to the list?
+ media::KeySystemInfo key_system_info;
+ key_system_info.key_system = "test.keysystem";
+ key_system_info.max_audio_robustness = media::EmeRobustness::EMPTY;
+ key_system_info.max_video_robustness = media::EmeRobustness::EMPTY;
+ key_system_info.persistent_license_support =
+ media::EmeSessionTypeSupport::NOT_SUPPORTED;
+ key_system_info.persistent_release_message_support =
+ media::EmeSessionTypeSupport::NOT_SUPPORTED;
+ key_system_info.persistent_state_support =
+ media::EmeFeatureSupport::NOT_SUPPORTED;
+ key_system_info.distinctive_identifier_support =
+ media::EmeFeatureSupport::NOT_SUPPORTED;
+ key_systems_info->push_back(key_system_info);
+#if defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT)
+ if (is_extra_key_system_enabled_) {
+ media::KeySystemInfo wv_key_system_info;
+ wv_key_system_info.key_system = kWidevineKeySystem;
+ wv_key_system_info.max_audio_robustness = media::EmeRobustness::EMPTY;
+ wv_key_system_info.max_video_robustness = media::EmeRobustness::EMPTY;
+ wv_key_system_info.persistent_license_support =
+ media::EmeSessionTypeSupport::NOT_SUPPORTED;
+ wv_key_system_info.persistent_release_message_support =
+ media::EmeSessionTypeSupport::NOT_SUPPORTED;
+ wv_key_system_info.persistent_state_support =
+ media::EmeFeatureSupport::NOT_SUPPORTED;
+ wv_key_system_info.distinctive_identifier_support =
+ media::EmeFeatureSupport::NOT_SUPPORTED;
+ key_systems_info->push_back(wv_key_system_info);
+ }
+#endif
+ }
+
+ void EnableExtraKeySystem() { is_extra_key_system_enabled_ = true; }
+
+ private:
+ // Whether a platform-specific extra key system is "supported" by |this|.
+ bool is_extra_key_system_enabled_;
+};
+
+#if defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT)
+bool ContainsWidevine(
+ const std::vector<media::KeySystemInfo>& key_systems_info) {
+ for (const auto& key_system_info: key_systems_info) {
+ if (key_system_info.key_system == kWidevineKeySystem)
+ return true;
+ }
+ return false;
+}
+#endif
+
+} // namespace
+
+class RenderMediaClientTest : public testing::Test {
+ protected:
+ RenderMediaClientTest()
+ : render_media_client_(GetRenderMediaClientInstanceForTesting()) {
+ SetContentClient(&test_content_client_);
+ SetRendererClientForTesting(&test_content_renderer_client_);
+ }
+
+ void EnableExtraKeySystem() {
+ test_content_renderer_client_.EnableExtraKeySystem();
+ }
+
+ RenderMediaClient* render_media_client_;
+
+ private:
+ typedef base::hash_map<std::string, std::string> KeySystemNameForUMAMap;
+
+ TestContentClient test_content_client_;
+ TestContentRendererClient test_content_renderer_client_;
+ KeySystemNameForUMAMap key_system_name_for_uma_map_;
+};
+
+TEST_F(RenderMediaClientTest, KeySystemNameForUMA) {
+ std::vector<media::KeySystemInfoForUMA> key_systems_info_for_uma;
+ render_media_client_->AddKeySystemsInfoForUMA(&key_systems_info_for_uma);
+
+ std::string widevine_uma_name;
+ std::string clearkey_uma_name;
+ for (const media::KeySystemInfoForUMA& info : key_systems_info_for_uma) {
+ if (info.key_system == "com.widevine.alpha")
+ widevine_uma_name = info.key_system_name_for_uma;
+ if (info.key_system == "org.w3.clearkey")
+ clearkey_uma_name = info.key_system_name_for_uma;
+ }
+
+#if defined(WIDEVINE_CDM_AVAILABLE)
+ EXPECT_EQ("Widevine", widevine_uma_name);
+#else
+ EXPECT_TRUE(widevine_uma_name.empty());
+#endif
+
+ EXPECT_TRUE(clearkey_uma_name.empty()) << "Clear Key is added by media/ and "
+ "should not be added by the "
+ "MediaClient.";
+ ;
+}
+
+TEST_F(RenderMediaClientTest, IsKeySystemsUpdateNeeded) {
+ base::SimpleTestTickClock* tick_clock = new base::SimpleTestTickClock();
+ render_media_client_->SetTickClockForTesting(
+ scoped_ptr<base::TickClock>(tick_clock));
+
+ // IsKeySystemsUpdateNeeded() always returns true after construction.
+ EXPECT_TRUE(render_media_client_->IsKeySystemsUpdateNeeded());
+
+ std::vector<media::KeySystemInfo> key_systems_info;
+ render_media_client_->AddSupportedKeySystems(&key_systems_info);
+
+ // No update needed immediately after AddSupportedKeySystems() call.
+ EXPECT_FALSE(render_media_client_->IsKeySystemsUpdateNeeded());
+
+#if defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT)
+ // Widevine not supported because extra key system isn't enabled.
+ EXPECT_FALSE(ContainsWidevine(key_systems_info));
+
+ // This is timing related. The update interval for Widevine is 1000 ms.
+ EXPECT_FALSE(render_media_client_->IsKeySystemsUpdateNeeded());
+ tick_clock->Advance(base::TimeDelta::FromMilliseconds(990));
+ EXPECT_FALSE(render_media_client_->IsKeySystemsUpdateNeeded());
+ tick_clock->Advance(base::TimeDelta::FromMilliseconds(10));
+ EXPECT_TRUE(render_media_client_->IsKeySystemsUpdateNeeded());
+
+ EnableExtraKeySystem();
+
+ key_systems_info.clear();
+ render_media_client_->AddSupportedKeySystems(&key_systems_info);
+ EXPECT_TRUE(ContainsWidevine(key_systems_info));
+
+ EXPECT_FALSE(render_media_client_->IsKeySystemsUpdateNeeded());
+ tick_clock->Advance(base::TimeDelta::FromMilliseconds(1000));
+ EXPECT_FALSE(render_media_client_->IsKeySystemsUpdateNeeded());
+ tick_clock->Advance(base::TimeDelta::FromMilliseconds(1000));
+ EXPECT_FALSE(render_media_client_->IsKeySystemsUpdateNeeded());
+#endif
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/media/render_media_log.cc b/chromium/content/renderer/media/render_media_log.cc
index d20f622ec74..800fd9c6c86 100644
--- a/chromium/content/renderer/media/render_media_log.cc
+++ b/chromium/content/renderer/media/render_media_log.cc
@@ -10,52 +10,87 @@
#include "content/common/view_messages.h"
#include "content/public/renderer/render_thread.h"
+namespace {
+
+// Print an event to the chromium log.
+void Log(media::MediaLogEvent* event) {
+ if (event->type == media::MediaLogEvent::PIPELINE_ERROR) {
+ LOG(ERROR) << "MediaEvent: "
+ << media::MediaLog::MediaEventToLogString(*event);
+ } else if (event->type != media::MediaLogEvent::BUFFERED_EXTENTS_CHANGED &&
+ event->type != media::MediaLogEvent::PROPERTY_CHANGE &&
+ event->type != media::MediaLogEvent::NETWORK_ACTIVITY_SET) {
+ DVLOG(1) << "MediaEvent: "
+ << media::MediaLog::MediaEventToLogString(*event);
+ }
+}
+
+} // namespace
+
namespace content {
RenderMediaLog::RenderMediaLog()
- : render_loop_(base::MessageLoopProxy::current()),
+ : task_runner_(base::MessageLoopProxy::current()),
tick_clock_(new base::DefaultTickClock()),
last_ipc_send_time_(tick_clock_->NowTicks()) {
- DCHECK(RenderThread::Get()) <<
- "RenderMediaLog must be constructed on the render thread";
+ DCHECK(RenderThread::Get())
+ << "RenderMediaLog must be constructed on the render thread";
}
void RenderMediaLog::AddEvent(scoped_ptr<media::MediaLogEvent> event) {
- if (!RenderThread::Get()) {
- render_loop_->PostTask(FROM_HERE, base::Bind(
- &RenderMediaLog::AddEvent, this, base::Passed(&event)));
+ if (!task_runner_->BelongsToCurrentThread()) {
+ task_runner_->PostTask(FROM_HERE, base::Bind(&RenderMediaLog::AddEvent,
+ this, base::Passed(&event)));
return;
}
+ Log(event.get());
+
+ // If there is an event waiting to be sent, there must be a send task pending.
+ const bool delayed_ipc_send_pending =
+ !queued_media_events_.empty() || last_buffered_extents_changed_event_;
+
// Keep track of the latest buffered extents properties to avoid sending
// thousands of events over IPC. See http://crbug.com/352585 for details.
- //
- // TODO(scherkus): We should overhaul MediaLog entirely to have clearer
- // separation of properties vs. events.
if (event->type == media::MediaLogEvent::BUFFERED_EXTENTS_CHANGED)
last_buffered_extents_changed_event_.swap(event);
else
queued_media_events_.push_back(*event);
- // Limit the send rate of high frequency events.
- base::TimeTicks curr_time = tick_clock_->NowTicks();
- if ((curr_time - last_ipc_send_time_) < base::TimeDelta::FromSeconds(1))
+ if (delayed_ipc_send_pending)
+ return;
+
+ // Delay until it's been a second since the last ipc message was sent.
+ base::TimeDelta delay_for_next_ipc_send =
+ base::TimeDelta::FromSeconds(1) -
+ (tick_clock_->NowTicks() - last_ipc_send_time_);
+ if (delay_for_next_ipc_send > base::TimeDelta()) {
+ task_runner_->PostDelayedTask(
+ FROM_HERE, base::Bind(&RenderMediaLog::SendQueuedMediaEvents, this),
+ delay_for_next_ipc_send);
return;
- last_ipc_send_time_ = curr_time;
+ }
+
+ // It's been more than a second so send now.
+ SendQueuedMediaEvents();
+}
+
+void RenderMediaLog::SendQueuedMediaEvents() {
+ DCHECK(task_runner_->BelongsToCurrentThread());
if (last_buffered_extents_changed_event_) {
queued_media_events_.push_back(*last_buffered_extents_changed_event_);
last_buffered_extents_changed_event_.reset();
}
- DVLOG(1) << "media log events array size " << queued_media_events_.size();
-
RenderThread::Get()->Send(
new ViewHostMsg_MediaLogEvents(queued_media_events_));
queued_media_events_.clear();
+ last_ipc_send_time_ = tick_clock_->NowTicks();
}
-RenderMediaLog::~RenderMediaLog() {}
+RenderMediaLog::~RenderMediaLog() {
+}
void RenderMediaLog::SetTickClockForTesting(
scoped_ptr<base::TickClock> tick_clock) {
@@ -63,4 +98,9 @@ void RenderMediaLog::SetTickClockForTesting(
last_ipc_send_time_ = tick_clock_->NowTicks();
}
+void RenderMediaLog::SetTaskRunnerForTesting(
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) {
+ task_runner_ = task_runner;
+}
+
} // namespace content
diff --git a/chromium/content/renderer/media/render_media_log.h b/chromium/content/renderer/media/render_media_log.h
index dbadfa5e5f1..12c251de61e 100644
--- a/chromium/content/renderer/media/render_media_log.h
+++ b/chromium/content/renderer/media/render_media_log.h
@@ -22,6 +22,8 @@ namespace content {
//
// To minimize the number of events sent over the wire, only the latest event
// added is sent for high frequency events (e.g., BUFFERED_EXTENTS_CHANGED).
+//
+// It must be constructed on the render thread.
class CONTENT_EXPORT RenderMediaLog : public media::MediaLog {
public:
RenderMediaLog();
@@ -31,11 +33,16 @@ class CONTENT_EXPORT RenderMediaLog : public media::MediaLog {
// Will reset |last_ipc_send_time_| with the value of NowTicks().
void SetTickClockForTesting(scoped_ptr<base::TickClock> tick_clock);
+ void SetTaskRunnerForTesting(
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
private:
~RenderMediaLog() override;
- scoped_refptr<base::MessageLoopProxy> render_loop_;
+ // Posted as a delayed task to throttle ipc message frequency.
+ void SendQueuedMediaEvents();
+
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
scoped_ptr<base::TickClock> tick_clock_;
base::TimeTicks last_ipc_send_time_;
std::vector<media::MediaLogEvent> queued_media_events_;
diff --git a/chromium/content/renderer/media/render_media_log_unittest.cc b/chromium/content/renderer/media/render_media_log_unittest.cc
index a5d25cee3d6..e9774ac5187 100644
--- a/chromium/content/renderer/media/render_media_log_unittest.cc
+++ b/chromium/content/renderer/media/render_media_log_unittest.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/test/simple_test_tick_clock.h"
+#include "base/test/test_mock_time_task_runner.h"
#include "content/common/view_messages.h"
#include "content/public/test/mock_render_thread.h"
#include "content/renderer/media/render_media_log.h"
@@ -14,17 +15,24 @@ class RenderMediaLogTest : public testing::Test {
public:
RenderMediaLogTest()
: log_(new RenderMediaLog()),
- tick_clock_(new base::SimpleTestTickClock()) {
+ tick_clock_(new base::SimpleTestTickClock()),
+ task_runner_(new base::TestMockTimeTaskRunner()) {
log_->SetTickClockForTesting(scoped_ptr<base::TickClock>(tick_clock_));
+ log_->SetTaskRunnerForTesting(task_runner_);
}
- ~RenderMediaLogTest() override {}
+ ~RenderMediaLogTest() override {
+ task_runner_->ClearPendingTasks();
+ }
void AddEvent(media::MediaLogEvent::Type type) {
log_->AddEvent(log_->CreateEvent(type));
}
- void Advance(base::TimeDelta delta) { tick_clock_->Advance(delta); }
+ void Advance(base::TimeDelta delta) {
+ tick_clock_->Advance(delta);
+ task_runner_->FastForwardBy(delta);
+ }
int message_count() { return render_thread_.sink().message_count(); }
@@ -36,15 +44,16 @@ class RenderMediaLogTest : public testing::Test {
return std::vector<media::MediaLogEvent>();
}
- Tuple1<std::vector<media::MediaLogEvent> > events;
+ Tuple<std::vector<media::MediaLogEvent>> events;
ViewHostMsg_MediaLogEvents::Read(msg, &events);
- return events.a;
+ return get<0>(events);
}
private:
MockRenderThread render_thread_;
scoped_refptr<RenderMediaLog> log_;
base::SimpleTestTickClock* tick_clock_; // Owned by |log_|.
+ scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
DISALLOW_COPY_AND_ASSIGN(RenderMediaLogTest);
};
@@ -60,21 +69,31 @@ TEST_F(RenderMediaLogTest, ThrottleSendingEvents) {
// Now we should expect an IPC.
Advance(base::TimeDelta::FromMilliseconds(500));
- AddEvent(media::MediaLogEvent::PLAY);
EXPECT_EQ(1, message_count());
// Verify contents.
std::vector<media::MediaLogEvent> events = GetMediaLogEvents();
- ASSERT_EQ(3u, events.size());
+ ASSERT_EQ(2u, events.size());
EXPECT_EQ(media::MediaLogEvent::LOAD, events[0].type);
EXPECT_EQ(media::MediaLogEvent::SEEK, events[1].type);
- EXPECT_EQ(media::MediaLogEvent::PLAY, events[2].type);
// Adding another event shouldn't send anything.
AddEvent(media::MediaLogEvent::PIPELINE_ERROR);
EXPECT_EQ(1, message_count());
}
+TEST_F(RenderMediaLogTest, EventSentWithoutDelayAfterIpcInterval) {
+ AddEvent(media::MediaLogEvent::LOAD);
+ Advance(base::TimeDelta::FromMilliseconds(1000));
+ EXPECT_EQ(1, message_count());
+
+ // After the ipc send interval passes, the next event should be sent
+ // right away.
+ Advance(base::TimeDelta::FromMilliseconds(2000));
+ AddEvent(media::MediaLogEvent::LOAD);
+ EXPECT_EQ(2, message_count());
+}
+
TEST_F(RenderMediaLogTest, BufferedExtents) {
AddEvent(media::MediaLogEvent::LOAD);
AddEvent(media::MediaLogEvent::SEEK);
@@ -85,20 +104,17 @@ TEST_F(RenderMediaLogTest, BufferedExtents) {
AddEvent(media::MediaLogEvent::BUFFERED_EXTENTS_CHANGED);
AddEvent(media::MediaLogEvent::BUFFERED_EXTENTS_CHANGED);
- // Trigger IPC message.
EXPECT_EQ(0, message_count());
Advance(base::TimeDelta::FromMilliseconds(1000));
- AddEvent(media::MediaLogEvent::PLAY);
EXPECT_EQ(1, message_count());
// Verify contents. There should only be a single buffered extents changed
// event.
std::vector<media::MediaLogEvent> events = GetMediaLogEvents();
- ASSERT_EQ(4u, events.size());
+ ASSERT_EQ(3u, events.size());
EXPECT_EQ(media::MediaLogEvent::LOAD, events[0].type);
EXPECT_EQ(media::MediaLogEvent::SEEK, events[1].type);
- EXPECT_EQ(media::MediaLogEvent::PLAY, events[2].type);
- EXPECT_EQ(media::MediaLogEvent::BUFFERED_EXTENTS_CHANGED, events[3].type);
+ EXPECT_EQ(media::MediaLogEvent::BUFFERED_EXTENTS_CHANGED, events[2].type);
}
} // namespace content
diff --git a/chromium/content/renderer/media/renderer_gpu_video_accelerator_factories.cc b/chromium/content/renderer/media/renderer_gpu_video_accelerator_factories.cc
index ab3d2f76c2a..e7efe2904e2 100644
--- a/chromium/content/renderer/media/renderer_gpu_video_accelerator_factories.cc
+++ b/chromium/content/renderer/media/renderer_gpu_video_accelerator_factories.cc
@@ -8,18 +8,18 @@
#include <GLES2/gl2ext.h>
#include "base/bind.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_gpu_memory_buffer_manager.h"
+#include "content/child/child_thread_impl.h"
#include "content/common/gpu/client/context_provider_command_buffer.h"
#include "content/common/gpu/client/gl_helper.h"
#include "content/common/gpu/client/gpu_channel_host.h"
-#include "content/common/gpu/client/gpu_video_encode_accelerator_host.h"
#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
+#include "content/common/gpu/media/gpu_video_accelerator_util.h"
#include "content/renderer/render_thread_impl.h"
#include "gpu/command_buffer/client/gles2_implementation.h"
+#include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
#include "media/video/video_decode_accelerator.h"
#include "media/video/video_encode_accelerator.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkPixelRef.h"
namespace content {
@@ -48,7 +48,10 @@ RendererGpuVideoAcceleratorFactories::RendererGpuVideoAcceleratorFactories(
: task_runner_(task_runner),
gpu_channel_host_(gpu_channel_host),
context_provider_(context_provider),
- thread_safe_sender_(ChildThread::current()->thread_safe_sender()) {}
+ gpu_memory_buffer_manager_(
+ ChildThreadImpl::current()->gpu_memory_buffer_manager()),
+ thread_safe_sender_(ChildThreadImpl::current()->thread_safe_sender()) {
+}
RendererGpuVideoAcceleratorFactories::~RendererGpuVideoAcceleratorFactories() {}
@@ -187,58 +190,45 @@ void RendererGpuVideoAcceleratorFactories::WaitSyncPoint(uint32 sync_point) {
gles2->ShallowFlushCHROMIUM();
}
-void RendererGpuVideoAcceleratorFactories::ReadPixels(
- uint32 texture_id,
- const gfx::Rect& visible_rect,
- const SkBitmap& pixels) {
+scoped_ptr<gfx::GpuMemoryBuffer>
+RendererGpuVideoAcceleratorFactories::AllocateGpuMemoryBuffer(
+ const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
+ gfx::GpuMemoryBuffer::Usage usage) {
DCHECK(task_runner_->BelongsToCurrentThread());
+ scoped_ptr<gfx::GpuMemoryBuffer> buffer =
+ gpu_memory_buffer_manager_->AllocateGpuMemoryBuffer(size, format, usage);
+ return buffer.Pass();
+}
- GLHelper* gl_helper = GetGLHelper();
- WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
+bool RendererGpuVideoAcceleratorFactories::IsTextureRGSupported() {
+ DCHECK(task_runner_->BelongsToCurrentThread());
- if (!gl_helper || !context)
- return;
+ WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
+ if (!context)
+ return false;
+ return context->GetImplementation()->capabilities().texture_rg;
+}
- // Copy texture from texture_id to tmp_texture as texture might be external
- // (GL_TEXTURE_EXTERNAL_OES)
- GLuint tmp_texture;
- tmp_texture = gl_helper->CreateTexture();
- context->copyTextureCHROMIUM(
- GL_TEXTURE_2D, texture_id, tmp_texture, 0, GL_RGBA, GL_UNSIGNED_BYTE);
-
- unsigned char* pixel_data =
- static_cast<unsigned char*>(pixels.pixelRef()->pixels());
-
- if (gl_helper->IsReadbackConfigSupported(pixels.colorType())) {
- gl_helper->ReadbackTextureSync(
- tmp_texture, visible_rect, pixel_data, pixels.colorType());
- } else if (pixels.colorType() == kN32_SkColorType) {
- gl_helper->ReadbackTextureSync(
- tmp_texture, visible_rect, pixel_data, kRGBA_8888_SkColorType);
-
- int pixel_count = visible_rect.width() * visible_rect.height();
- uint32_t* pixels_ptr = static_cast<uint32_t*>(pixels.pixelRef()->pixels());
- for (int i = 0; i < pixel_count; ++i) {
- uint32_t r = pixels_ptr[i] & 0xFF;
- uint32_t g = (pixels_ptr[i] >> 8) & 0xFF;
- uint32_t b = (pixels_ptr[i] >> 16) & 0xFF;
- uint32_t a = (pixels_ptr[i] >> 24) & 0xFF;
- pixels_ptr[i] = (r << SK_R32_SHIFT) |
- (g << SK_G32_SHIFT) |
- (b << SK_B32_SHIFT) |
- (a << SK_A32_SHIFT);
- }
- } else {
- NOTREACHED();
- }
+gpu::gles2::GLES2Interface*
+RendererGpuVideoAcceleratorFactories::GetGLES2Interface() {
+ DCHECK(task_runner_->BelongsToCurrentThread());
- gl_helper->DeleteTexture(tmp_texture);
+ WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
+ if (!context)
+ return nullptr;
+ gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation();
+ return gles2;
}
-base::SharedMemory* RendererGpuVideoAcceleratorFactories::CreateSharedMemory(
- size_t size) {
+scoped_ptr<base::SharedMemory>
+RendererGpuVideoAcceleratorFactories::CreateSharedMemory(size_t size) {
DCHECK(task_runner_->BelongsToCurrentThread());
- return ChildThread::AllocateSharedMemory(size, thread_safe_sender_.get());
+ scoped_ptr<base::SharedMemory> mem(
+ ChildThreadImpl::AllocateSharedMemory(size, thread_safe_sender_.get()));
+ if (mem && !mem->Map(size))
+ return nullptr;
+ return mem;
}
scoped_refptr<base::SingleThreadTaskRunner>
@@ -246,10 +236,18 @@ RendererGpuVideoAcceleratorFactories::GetTaskRunner() {
return task_runner_;
}
-std::vector<media::VideoEncodeAccelerator::SupportedProfile>
+media::VideoDecodeAccelerator::SupportedProfiles
+RendererGpuVideoAcceleratorFactories::
+ GetVideoDecodeAcceleratorSupportedProfiles() {
+ return GpuVideoAcceleratorUtil::ConvertGpuToMediaDecodeProfiles(
+ gpu_channel_host_->gpu_info()
+ .video_decode_accelerator_supported_profiles);
+}
+
+media::VideoEncodeAccelerator::SupportedProfiles
RendererGpuVideoAcceleratorFactories::
GetVideoEncodeAcceleratorSupportedProfiles() {
- return GpuVideoEncodeAcceleratorHost::ConvertGpuToMediaProfiles(
+ return GpuVideoAcceleratorUtil::ConvertGpuToMediaEncodeProfiles(
gpu_channel_host_->gpu_info()
.video_encode_accelerator_supported_profiles);
}
diff --git a/chromium/content/renderer/media/renderer_gpu_video_accelerator_factories.h b/chromium/content/renderer/media/renderer_gpu_video_accelerator_factories.h
index 47232307f27..fb002c88b37 100644
--- a/chromium/content/renderer/media/renderer_gpu_video_accelerator_factories.h
+++ b/chromium/content/renderer/media/renderer_gpu_video_accelerator_factories.h
@@ -13,13 +13,17 @@
#include "base/synchronization/waitable_event.h"
#include "content/child/thread_safe_sender.h"
#include "content/common/content_export.h"
-#include "media/filters/gpu_video_accelerator_factories.h"
-#include "ui/gfx/size.h"
+#include "media/renderers/gpu_video_accelerator_factories.h"
+#include "ui/gfx/geometry/size.h"
namespace base {
class WaitableEvent;
}
+namespace gpu {
+class GpuMemoryBufferManager;
+}
+
namespace content {
class ContextProviderCommandBuffer;
class GLHelper;
@@ -58,13 +62,21 @@ class CONTENT_EXPORT RendererGpuVideoAcceleratorFactories
uint32 texture_target) override;
void DeleteTexture(uint32 texture_id) override;
void WaitSyncPoint(uint32 sync_point) override;
- void ReadPixels(uint32 texture_id,
- const gfx::Rect& visible_rect,
- const SkBitmap& pixels) override;
- base::SharedMemory* CreateSharedMemory(size_t size) override;
+
+ scoped_ptr<gfx::GpuMemoryBuffer> AllocateGpuMemoryBuffer(
+ const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
+ gfx::GpuMemoryBuffer::Usage usage) override;
+
+ bool IsTextureRGSupported() override;
+ gpu::gles2::GLES2Interface* GetGLES2Interface() override;
+ scoped_ptr<base::SharedMemory> CreateSharedMemory(size_t size) override;
scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner() override;
+
+ std::vector<media::VideoDecodeAccelerator::SupportedProfile>
+ GetVideoDecodeAcceleratorSupportedProfiles() override;
std::vector<media::VideoEncodeAccelerator::SupportedProfile>
- GetVideoEncodeAcceleratorSupportedProfiles() override;
+ GetVideoEncodeAcceleratorSupportedProfiles() override;
private:
friend class base::RefCountedThreadSafe<RendererGpuVideoAcceleratorFactories>;
@@ -87,6 +99,7 @@ class CONTENT_EXPORT RendererGpuVideoAcceleratorFactories
scoped_refptr<GpuChannelHost> gpu_channel_host_;
scoped_refptr<ContextProviderCommandBuffer> context_provider_;
scoped_ptr<GLHelper> gl_helper_;
+ gpu::GpuMemoryBufferManager* const gpu_memory_buffer_manager_;
// For sending requests to allocate shared memory in the Browser process.
scoped_refptr<ThreadSafeSender> thread_safe_sender_;
diff --git a/chromium/content/renderer/media/renderer_webaudiodevice_impl.cc b/chromium/content/renderer/media/renderer_webaudiodevice_impl.cc
index 536bb1e3889..81817f79818 100644
--- a/chromium/content/renderer/media/renderer_webaudiodevice_impl.cc
+++ b/chromium/content/renderer/media/renderer_webaudiodevice_impl.cc
@@ -8,7 +8,6 @@
#include "base/logging.h"
#include "content/renderer/media/audio_device_factory.h"
#include "content/renderer/render_frame_impl.h"
-#include "content/renderer/render_view_impl.h"
#include "media/audio/audio_output_device.h"
#include "media/base/media_switches.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
@@ -49,13 +48,9 @@ void RendererWebAudioDeviceImpl::start() {
// of the WebAudio objects might not be the actual source of the audio (e.g.,
// an extension creates a object that is passed and used within a page).
WebLocalFrame* const web_frame = WebLocalFrame::frameForCurrentContext();
- WebView* const web_view = web_frame ? web_frame->view() : NULL;
RenderFrame* const render_frame =
web_frame ? RenderFrame::FromWebFrame(web_frame) : NULL;
- RenderViewImpl* const render_view =
- web_view ? RenderViewImpl::FromWebView(web_view) : NULL;
output_device_ = AudioDeviceFactory::NewOutputDevice(
- render_view ? render_view->routing_id() : MSG_ROUTING_NONE,
render_frame ? render_frame->GetRoutingID(): MSG_ROUTING_NONE);
output_device_->InitializeWithSessionId(params_, this, session_id_);
output_device_->Start();
diff --git a/chromium/content/renderer/media/renderer_webaudiodevice_impl.h b/chromium/content/renderer/media/renderer_webaudiodevice_impl.h
index 03817fca750..13ce0f15948 100644
--- a/chromium/content/renderer/media/renderer_webaudiodevice_impl.h
+++ b/chromium/content/renderer/media/renderer_webaudiodevice_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_RENDERER_MEDIA_MEDIA_RENDERER_WEBAUDIODEVICE_IMPL_H_
-#define CONTENT_RENDERER_MEDIA_MEDIA_RENDERER_WEBAUDIODEVICE_IMPL_H_
+#ifndef CONTENT_RENDERER_MEDIA_RENDERER_WEBAUDIODEVICE_IMPL_H_
+#define CONTENT_RENDERER_MEDIA_RENDERER_WEBAUDIODEVICE_IMPL_H_
#include "base/memory/ref_counted.h"
#include "base/threading/thread_checker.h"
@@ -58,4 +58,4 @@ class RendererWebAudioDeviceImpl
} // namespace content
-#endif // CONTENT_RENDERER_MEDIA_MEDIA_RENDERER_WEBAUDIODEVICE_IMPL_H_
+#endif // CONTENT_RENDERER_MEDIA_RENDERER_WEBAUDIODEVICE_IMPL_H_
diff --git a/chromium/content/renderer/media/rtc_data_channel_handler.cc b/chromium/content/renderer/media/rtc_data_channel_handler.cc
index 084a02018cb..09a57a733b1 100644
--- a/chromium/content/renderer/media/rtc_data_channel_handler.cc
+++ b/chromium/content/renderer/media/rtc_data_channel_handler.cc
@@ -50,7 +50,10 @@ RtcDataChannelHandler::Observer::Observer(
channel_->RegisterObserver(this);
}
-RtcDataChannelHandler::Observer::~Observer() {}
+RtcDataChannelHandler::Observer::~Observer() {
+ DVLOG(3) << "dtor";
+ DCHECK(!channel_.get()) << "Unregister hasn't been called.";
+}
const scoped_refptr<base::SingleThreadTaskRunner>&
RtcDataChannelHandler::Observer::main_thread() const {
@@ -59,12 +62,19 @@ RtcDataChannelHandler::Observer::main_thread() const {
const scoped_refptr<webrtc::DataChannelInterface>&
RtcDataChannelHandler::Observer::channel() const {
+ DCHECK(main_thread_->BelongsToCurrentThread());
return channel_;
}
-void RtcDataChannelHandler::Observer::ClearHandler() {
+void RtcDataChannelHandler::Observer::Unregister() {
DCHECK(main_thread_->BelongsToCurrentThread());
handler_ = nullptr;
+ if (channel_.get()) {
+ channel_->UnregisterObserver();
+ // Now that we're guaranteed to not get further OnStateChange callbacks,
+ // it's safe to release our reference to the channel.
+ channel_ = nullptr;
+ }
}
void RtcDataChannelHandler::Observer::OnStateChange() {
@@ -127,13 +137,22 @@ RtcDataChannelHandler::RtcDataChannelHandler(
RtcDataChannelHandler::~RtcDataChannelHandler() {
DCHECK(thread_checker_.CalledOnValidThread());
DVLOG(1) << "::dtor";
- observer_->ClearHandler();
+ // setClient might not have been called at all if the data channel was not
+ // passed to Blink. So, we call it here explicitly just to make sure the
+ // observer gets properly unregistered.
+ // See RTCPeerConnectionHandler::OnDataChannel for more.
+ setClient(nullptr);
}
void RtcDataChannelHandler::setClient(
blink::WebRTCDataChannelHandlerClient* client) {
DCHECK(thread_checker_.CalledOnValidThread());
+ DVLOG(3) << "setClient " << client;
webkit_client_ = client;
+ if (!client && observer_.get()) {
+ observer_->Unregister();
+ observer_ = nullptr;
+ }
}
blink::WebString RtcDataChannelHandler::label() {
@@ -176,6 +195,38 @@ unsigned short RtcDataChannelHandler::id() const {
return channel()->id();
}
+blink::WebRTCDataChannelHandlerClient::ReadyState convertReadyState(
+ webrtc::DataChannelInterface::DataState state) {
+ switch (state) {
+ case webrtc::DataChannelInterface::kConnecting:
+ return blink::WebRTCDataChannelHandlerClient::ReadyStateConnecting;
+ break;
+ case webrtc::DataChannelInterface::kOpen:
+ return blink::WebRTCDataChannelHandlerClient::ReadyStateOpen;
+ break;
+ case webrtc::DataChannelInterface::kClosing:
+ return blink::WebRTCDataChannelHandlerClient::ReadyStateClosing;
+ break;
+ case webrtc::DataChannelInterface::kClosed:
+ return blink::WebRTCDataChannelHandlerClient::ReadyStateClosed;
+ break;
+ default:
+ NOTREACHED();
+ // MSVC does not respect |NOTREACHED()|, so we need a return value.
+ return blink::WebRTCDataChannelHandlerClient::ReadyStateClosed;
+ }
+}
+
+blink::WebRTCDataChannelHandlerClient::ReadyState
+ RtcDataChannelHandler::state() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (!observer_.get()) {
+ return blink::WebRTCDataChannelHandlerClient::ReadyStateConnecting;
+ } else {
+ return convertReadyState(observer_->channel()->state());
+ }
+}
+
unsigned long RtcDataChannelHandler::bufferedAmount() {
DCHECK(thread_checker_.CalledOnValidThread());
return channel()->buffered_amount();
@@ -226,28 +277,10 @@ void RtcDataChannelHandler::OnStateChange(
return;
}
- switch (state) {
- case webrtc::DataChannelInterface::kConnecting:
- webkit_client_->didChangeReadyState(
- blink::WebRTCDataChannelHandlerClient::ReadyStateConnecting);
- break;
- case webrtc::DataChannelInterface::kOpen:
- IncrementCounter(CHANNEL_OPENED);
- webkit_client_->didChangeReadyState(
- blink::WebRTCDataChannelHandlerClient::ReadyStateOpen);
- break;
- case webrtc::DataChannelInterface::kClosing:
- webkit_client_->didChangeReadyState(
- blink::WebRTCDataChannelHandlerClient::ReadyStateClosing);
- break;
- case webrtc::DataChannelInterface::kClosed:
- webkit_client_->didChangeReadyState(
- blink::WebRTCDataChannelHandlerClient::ReadyStateClosed);
- break;
- default:
- NOTREACHED();
- break;
- }
+ if (state == webrtc::DataChannelInterface::kOpen)
+ IncrementCounter(CHANNEL_OPENED);
+
+ webkit_client_->didChangeReadyState(convertReadyState(state));
}
void RtcDataChannelHandler::OnMessage(scoped_ptr<webrtc::DataBuffer> buffer) {
@@ -259,11 +292,11 @@ void RtcDataChannelHandler::OnMessage(scoped_ptr<webrtc::DataBuffer> buffer) {
}
if (buffer->binary) {
- webkit_client_->didReceiveRawData(buffer->data.data(),
- buffer->data.length());
+ webkit_client_->didReceiveRawData(buffer->data.data<char>(),
+ buffer->data.size());
} else {
base::string16 utf16;
- if (!base::UTF8ToUTF16(buffer->data.data(), buffer->data.length(),
+ if (!base::UTF8ToUTF16(buffer->data.data<char>(), buffer->data.size(),
&utf16)) {
LOG(ERROR) << "Failed convert received data to UTF16";
return;
@@ -273,6 +306,7 @@ void RtcDataChannelHandler::OnMessage(scoped_ptr<webrtc::DataBuffer> buffer) {
}
void RtcDataChannelHandler::RecordMessageSent(size_t num_bytes) {
+ DCHECK(thread_checker_.CalledOnValidThread());
// Currently, messages are capped at some fairly low limit (16 Kb?)
// but we may allow unlimited-size messages at some point, so making
// the histogram maximum quite large (100 Mb) to have some
diff --git a/chromium/content/renderer/media/rtc_data_channel_handler.h b/chromium/content/renderer/media/rtc_data_channel_handler.h
index 79addde1728..c1ae1336a7a 100644
--- a/chromium/content/renderer/media/rtc_data_channel_handler.h
+++ b/chromium/content/renderer/media/rtc_data_channel_handler.h
@@ -37,23 +37,24 @@ class CONTENT_EXPORT RtcDataChannelHandler
RtcDataChannelHandler(
const scoped_refptr<base::SingleThreadTaskRunner>& main_thread,
webrtc::DataChannelInterface* channel);
- virtual ~RtcDataChannelHandler();
+ ~RtcDataChannelHandler() override;
// blink::WebRTCDataChannelHandler implementation.
- virtual void setClient(
+ void setClient(
blink::WebRTCDataChannelHandlerClient* client) override;
- virtual blink::WebString label() override;
- virtual bool isReliable() override;
- virtual bool ordered() const override;
- virtual unsigned short maxRetransmitTime() const override;
- virtual unsigned short maxRetransmits() const override;
- virtual blink::WebString protocol() const override;
- virtual bool negotiated() const override;
- virtual unsigned short id() const override;
- virtual unsigned long bufferedAmount() override;
- virtual bool sendStringData(const blink::WebString& data) override;
- virtual bool sendRawData(const char* data, size_t length) override;
- virtual void close() override;
+ blink::WebString label() override;
+ bool isReliable() override;
+ bool ordered() const override;
+ unsigned short maxRetransmitTime() const override;
+ unsigned short maxRetransmits() const override;
+ blink::WebString protocol() const override;
+ bool negotiated() const override;
+ unsigned short id() const override;
+ blink::WebRTCDataChannelHandlerClient::ReadyState state() const override;
+ unsigned long bufferedAmount() override;
+ bool sendStringData(const blink::WebString& data) override;
+ bool sendRawData(const char* data, size_t length) override;
+ void close() override;
const scoped_refptr<webrtc::DataChannelInterface>& channel() const;
@@ -74,7 +75,10 @@ class CONTENT_EXPORT RtcDataChannelHandler
const scoped_refptr<base::SingleThreadTaskRunner>& main_thread() const;
const scoped_refptr<webrtc::DataChannelInterface>& channel() const;
- void ClearHandler();
+ // Clears the internal |handler_| pointer so that no further callbacks
+ // will be attempted, disassociates this observer from the channel and
+ // releases the channel pointer. Must be called on the main thread.
+ void Unregister();
private:
friend class base::RefCountedThreadSafe<RtcDataChannelHandler::Observer>;
@@ -89,7 +93,7 @@ class CONTENT_EXPORT RtcDataChannelHandler
RtcDataChannelHandler* handler_;
const scoped_refptr<base::SingleThreadTaskRunner> main_thread_;
- const scoped_refptr<webrtc::DataChannelInterface> channel_;
+ scoped_refptr<webrtc::DataChannelInterface> channel_;
};
scoped_refptr<Observer> observer_;
diff --git a/chromium/content/renderer/media/rtc_data_channel_handler_unittest.cc b/chromium/content/renderer/media/rtc_data_channel_handler_unittest.cc
new file mode 100644
index 00000000000..e33dbbe8d60
--- /dev/null
+++ b/chromium/content/renderer/media/rtc_data_channel_handler_unittest.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/memory/scoped_ptr.h"
+#include "base/test/test_simple_task_runner.h"
+#include "content/renderer/media/mock_data_channel_impl.h"
+#include "content/renderer/media/rtc_data_channel_handler.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/WebRTCDataChannelHandlerClient.h"
+
+namespace content {
+
+class MockDataChannelHandlerClient :
+ public blink::WebRTCDataChannelHandlerClient {
+ public:
+ MockDataChannelHandlerClient() : state_(ReadyStateConnecting) {}
+
+ void didChangeReadyState(ReadyState state) override { state_ = state; }
+ void didReceiveStringData(const blink::WebString& s) override {}
+ void didReceiveRawData(const char* data, size_t size) override {}
+ void didDetectError() override {}
+
+ ReadyState ready_state() const { return state_; }
+
+ private:
+ ReadyState state_;
+};
+
+class RtcDataChannelHandlerTest : public ::testing::Test {
+ public:
+ RtcDataChannelHandlerTest() {
+ signaling_thread_ = new base::TestSimpleTaskRunner();
+ }
+
+ void SetUp() override {
+ channel_ = new rtc::RefCountedObject<MockDataChannel>("test", &config);
+ }
+
+ void TearDown() override {
+ handler_.reset();
+ channel_ = nullptr;
+ signaling_thread_->ClearPendingTasks();
+ }
+
+ webrtc::DataChannelInit config;
+ scoped_refptr<base::TestSimpleTaskRunner> signaling_thread_;
+ scoped_refptr<MockDataChannel> channel_;
+ scoped_ptr<RtcDataChannelHandler> handler_;
+};
+
+// Add a client, change to the open state, and verify that the client has
+// reached the open state.
+TEST_F(RtcDataChannelHandlerTest, SetClient) {
+ handler_.reset(new RtcDataChannelHandler(signaling_thread_, channel_.get()));
+ MockDataChannelHandlerClient blink_channel;
+ handler_->setClient(&blink_channel);
+ channel_->changeState(webrtc::DataChannelInterface::kOpen);
+ signaling_thread_->RunPendingTasks();
+ EXPECT_EQ(MockDataChannelHandlerClient::ReadyStateOpen,
+ blink_channel.ready_state());
+}
+
+// Check that state() returns the expected default initial value.
+TEST_F(RtcDataChannelHandlerTest, InitialState) {
+ handler_.reset(new RtcDataChannelHandler(signaling_thread_, channel_.get()));
+ EXPECT_EQ(MockDataChannelHandlerClient::ReadyStateConnecting,
+ handler_->state());
+}
+
+// Check that state() returns the expected value when the channel opens early.
+TEST_F(RtcDataChannelHandlerTest, StateEarlyOpen) {
+ channel_->changeState(webrtc::DataChannelInterface::kOpen);
+ signaling_thread_->RunPendingTasks();
+ handler_.reset(new RtcDataChannelHandler(signaling_thread_, channel_.get()));
+ EXPECT_EQ(MockDataChannelHandlerClient::ReadyStateOpen,
+ handler_->state());
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/media/rtc_dtmf_sender_handler.cc b/chromium/content/renderer/media/rtc_dtmf_sender_handler.cc
index 3aea3d15fe0..65b60b8d3f8 100644
--- a/chromium/content/renderer/media/rtc_dtmf_sender_handler.cc
+++ b/chromium/content/renderer/media/rtc_dtmf_sender_handler.cc
@@ -49,15 +49,17 @@ class RtcDtmfSenderHandler::Observer :
RtcDtmfSenderHandler::RtcDtmfSenderHandler(DtmfSenderInterface* dtmf_sender)
: dtmf_sender_(dtmf_sender),
webkit_client_(NULL),
- weak_factory_(this),
- observer_(new Observer(weak_factory_.GetWeakPtr())) {
+ weak_factory_(this) {
DVLOG(1) << "::ctor";
+ observer_ = new Observer(weak_factory_.GetWeakPtr());
dtmf_sender_->RegisterObserver(observer_.get());
}
RtcDtmfSenderHandler::~RtcDtmfSenderHandler() {
DVLOG(1) << "::dtor";
dtmf_sender_->UnregisterObserver();
+ // Release |observer| before |weak_factory_| is destroyed.
+ observer_ = NULL;
}
void RtcDtmfSenderHandler::setClient(
diff --git a/chromium/content/renderer/media/rtc_dtmf_sender_handler.h b/chromium/content/renderer/media/rtc_dtmf_sender_handler.h
index eecad4b898e..7a0eabfc68b 100644
--- a/chromium/content/renderer/media/rtc_dtmf_sender_handler.h
+++ b/chromium/content/renderer/media/rtc_dtmf_sender_handler.h
@@ -43,9 +43,11 @@ class CONTENT_EXPORT RtcDtmfSenderHandler
private:
scoped_refptr<webrtc::DtmfSenderInterface> dtmf_sender_;
blink::WebRTCDTMFSenderHandlerClient* webkit_client_;
- base::WeakPtrFactory<RtcDtmfSenderHandler> weak_factory_;
class Observer;
- scoped_refptr<Observer> observer_; // must be after weak_factory_
+ scoped_refptr<Observer> observer_;
+
+ // |weak_factory_| must be the last member.
+ base::WeakPtrFactory<RtcDtmfSenderHandler> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(RtcDtmfSenderHandler);
};
diff --git a/chromium/content/renderer/media/rtc_peer_connection_handler.cc b/chromium/content/renderer/media/rtc_peer_connection_handler.cc
index 54c500141b5..26c412753b2 100644
--- a/chromium/content/renderer/media/rtc_peer_connection_handler.cc
+++ b/chromium/content/renderer/media/rtc_peer_connection_handler.cc
@@ -9,7 +9,6 @@
#include <vector>
#include "base/command_line.h"
-#include "base/debug/trace_event.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
@@ -17,6 +16,7 @@
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/thread_task_runner_handle.h"
+#include "base/trace_event/trace_event.h"
#include "content/public/common/content_switches.h"
#include "content/renderer/media/media_stream_track.h"
#include "content/renderer/media/peer_connection_tracker.h"
@@ -46,7 +46,6 @@ using webrtc::MediaStreamInterface;
using webrtc::PeerConnectionInterface;
using webrtc::PeerConnectionObserver;
using webrtc::StatsReport;
-using webrtc::StatsReportCopyable;
using webrtc::StatsReports;
namespace content {
@@ -170,32 +169,49 @@ void GetSdpAndTypeFromSessionDescription(
}
}
-// Converter functions from WebKit types to libjingle types.
+// Converter functions from WebKit types to WebRTC types.
void GetNativeRtcConfiguration(
- const blink::WebRTCConfiguration& server_configuration,
- webrtc::PeerConnectionInterface::RTCConfiguration* config) {
- if (server_configuration.isNull() || !config)
+ const blink::WebRTCConfiguration& blink_config,
+ webrtc::PeerConnectionInterface::RTCConfiguration* webrtc_config) {
+ if (blink_config.isNull() || !webrtc_config)
return;
- for (size_t i = 0; i < server_configuration.numberOfServers(); ++i) {
+ for (size_t i = 0; i < blink_config.numberOfServers(); ++i) {
webrtc::PeerConnectionInterface::IceServer server;
const blink::WebRTCICEServer& webkit_server =
- server_configuration.server(i);
+ blink_config.server(i);
server.username = base::UTF16ToUTF8(webkit_server.username());
server.password = base::UTF16ToUTF8(webkit_server.credential());
server.uri = webkit_server.uri().spec();
- config->servers.push_back(server);
+ webrtc_config->servers.push_back(server);
}
- switch (server_configuration.iceTransports()) {
+ switch (blink_config.iceTransports()) {
case blink::WebRTCIceTransportsNone:
- config->type = webrtc::PeerConnectionInterface::kNone;
+ webrtc_config->type = webrtc::PeerConnectionInterface::kNone;
break;
case blink::WebRTCIceTransportsRelay:
- config->type = webrtc::PeerConnectionInterface::kRelay;
+ webrtc_config->type = webrtc::PeerConnectionInterface::kRelay;
break;
case blink::WebRTCIceTransportsAll:
- config->type = webrtc::PeerConnectionInterface::kAll;
+ webrtc_config->type = webrtc::PeerConnectionInterface::kAll;
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ switch (blink_config.bundlePolicy()) {
+ case blink::WebRTCBundlePolicyBalanced:
+ webrtc_config->bundle_policy =
+ webrtc::PeerConnectionInterface::kBundlePolicyBalanced;
+ break;
+ case blink::WebRTCBundlePolicyMaxBundle:
+ webrtc_config->bundle_policy =
+ webrtc::PeerConnectionInterface::kBundlePolicyMaxBundle;
+ break;
+ case blink::WebRTCBundlePolicyMaxCompat:
+ webrtc_config->bundle_policy =
+ webrtc::PeerConnectionInterface::kBundlePolicyMaxCompat;
break;
default:
NOTREACHED();
@@ -263,6 +279,7 @@ class CreateSessionDescriptionRequest
tracker_.TrackOnSuccess(desc);
webkit_request_.requestSucceeded(CreateWebKitSessionDescription(desc));
+ webkit_request_.reset();
delete desc;
}
void OnFailure(const std::string& error) override {
@@ -274,10 +291,13 @@ class CreateSessionDescriptionRequest
tracker_.TrackOnFailure(error);
webkit_request_.requestFailed(base::UTF8ToUTF16(error));
+ webkit_request_.reset();
}
protected:
- ~CreateSessionDescriptionRequest() override {}
+ ~CreateSessionDescriptionRequest() override {
+ DCHECK(webkit_request_.isNull());
+ }
const scoped_refptr<base::SingleThreadTaskRunner> main_thread_;
blink::WebRTCSessionDescriptionRequest webkit_request_;
@@ -308,6 +328,7 @@ class SetSessionDescriptionRequest
}
tracker_.TrackOnSuccess(NULL);
webkit_request_.requestSucceeded();
+ webkit_request_.reset();
}
void OnFailure(const std::string& error) override {
if (!main_thread_->BelongsToCurrentThread()) {
@@ -317,10 +338,13 @@ class SetSessionDescriptionRequest
}
tracker_.TrackOnFailure(error);
webkit_request_.requestFailed(base::UTF8ToUTF16(error));
+ webkit_request_.reset();
}
protected:
- ~SetSessionDescriptionRequest() override {}
+ ~SetSessionDescriptionRequest() override {
+ DCHECK(webkit_request_.isNull());
+ }
private:
const scoped_refptr<base::SingleThreadTaskRunner> main_thread_;
@@ -343,33 +367,59 @@ class StatsResponse : public webrtc::StatsObserver {
void OnComplete(const StatsReports& reports) override {
DCHECK(signaling_thread_checker_.CalledOnValidThread());
TRACE_EVENT0("webrtc", "StatsResponse::OnComplete");
- // TODO(tommi): Get rid of these string copies somehow.
// We can't use webkit objects directly since they use a single threaded
// heap allocator.
- scoped_ptr<std::vector<StatsReportCopyable>> report_copies(
- new std::vector<StatsReportCopyable>());
+ std::vector<Report*>* report_copies = new std::vector<Report*>();
report_copies->reserve(reports.size());
- for (auto it : reports)
- report_copies->push_back(StatsReportCopyable(*it));
+ for (auto* r : reports)
+ report_copies->push_back(new Report(r));
- main_thread_->PostTask(FROM_HERE,
+ main_thread_->PostTaskAndReply(FROM_HERE,
base::Bind(&StatsResponse::DeliverCallback, this,
- base::Passed(&report_copies)));
+ base::Unretained(report_copies)),
+ base::Bind(&StatsResponse::DeleteReports,
+ base::Unretained(report_copies)));
}
private:
- void DeliverCallback(scoped_ptr<std::vector<StatsReportCopyable>> reports) {
+ struct Report {
+ Report(const StatsReport* report)
+ : thread_checker(), id(report->id()->ToString()),
+ type(report->TypeToString()), timestamp(report->timestamp()),
+ values(report->values()) {
+ }
+
+ ~Report() {
+ // Since the values vector holds pointers to const objects that are bound
+ // to the signaling thread, they must be released on the same thread.
+ DCHECK(thread_checker.CalledOnValidThread());
+ }
+
+ const base::ThreadChecker thread_checker;
+ const std::string id, type;
+ const double timestamp;
+ const StatsReport::Values values;
+ };
+
+ static void DeleteReports(std::vector<Report*>* reports) {
+ TRACE_EVENT0("webrtc", "StatsResponse::DeleteReports");
+ for (auto* p : *reports)
+ delete p;
+ delete reports;
+ }
+
+ void DeliverCallback(const std::vector<Report*>* reports) {
DCHECK(main_thread_->BelongsToCurrentThread());
TRACE_EVENT0("webrtc", "StatsResponse::DeliverCallback");
rtc::scoped_refptr<LocalRTCStatsResponse> response(
request_->createResponse().get());
- for (const auto& report : *reports.get()) {
- if (report.values.size() > 0)
- AddReport(response.get(), report);
+ for (const auto* report : *reports) {
+ if (report->values.size() > 0)
+ AddReport(response.get(), *report);
}
- // Record the getSync operation as done before calling into Blink so that
+ // Record the getStats operation as done before calling into Blink so that
// we don't skew the perf measurements of the native code with whatever the
// callback might be doing.
TRACE_EVENT_ASYNC_END0("webrtc", "getStats_Native", this);
@@ -377,14 +427,23 @@ class StatsResponse : public webrtc::StatsObserver {
request_ = nullptr; // must be freed on the main thread.
}
- void AddReport(LocalRTCStatsResponse* response, const StatsReport& report) {
+ void AddReport(LocalRTCStatsResponse* response, const Report& report) {
int idx = response->addReport(blink::WebString::fromUTF8(report.id),
blink::WebString::fromUTF8(report.type),
report.timestamp);
+ blink::WebString name, value_str;
for (const auto& value : report.values) {
- response->addStatistic(idx,
- blink::WebString::fromUTF8(value.display_name()),
- blink::WebString::fromUTF8(value.value));
+ const StatsReport::ValuePtr& v = value.second;
+ name = blink::WebString::fromUTF8(value.second->display_name());
+
+ if (v->type() == StatsReport::Value::kString)
+ value_str = blink::WebString::fromUTF8(v->string_val());
+ if (v->type() == StatsReport::Value::kStaticString)
+ value_str = blink::WebString::fromUTF8(v->static_string_val());
+ else
+ value_str = blink::WebString::fromUTF8(v->ToString());
+
+ response->addStatistic(idx, name, value_str);
}
}
diff --git a/chromium/content/renderer/media/rtc_peer_connection_handler.h b/chromium/content/renderer/media/rtc_peer_connection_handler.h
index 08003a95743..95846af2ae7 100644
--- a/chromium/content/renderer/media/rtc_peer_connection_handler.h
+++ b/chromium/content/renderer/media/rtc_peer_connection_handler.h
@@ -26,6 +26,7 @@ namespace blink {
class WebFrame;
class WebRTCDataChannelHandler;
class WebRTCOfferOptions;
+class WebRTCPeerConnectionHandlerClient;
}
namespace content {
diff --git a/chromium/content/renderer/media/rtc_peer_connection_handler_unittest.cc b/chromium/content/renderer/media/rtc_peer_connection_handler_unittest.cc
index 2ee286a5eff..7627e7d1028 100644
--- a/chromium/content/renderer/media/rtc_peer_connection_handler_unittest.cc
+++ b/chromium/content/renderer/media/rtc_peer_connection_handler_unittest.cc
@@ -245,16 +245,17 @@ class RTCPeerConnectionHandlerTest : public ::testing::Test {
const std::string& stream_label) {
std::string video_track_label("video-label");
std::string audio_track_label("audio-label");
-
blink::WebMediaStreamSource audio_source;
audio_source.initialize(blink::WebString::fromUTF8(audio_track_label),
blink::WebMediaStreamSource::TypeAudio,
- blink::WebString::fromUTF8("audio_track"));
+ blink::WebString::fromUTF8("audio_track"),
+ false /* remote */, true /* readonly */);
audio_source.setExtraData(new MediaStreamAudioSource());
blink::WebMediaStreamSource video_source;
video_source.initialize(blink::WebString::fromUTF8(video_track_label),
blink::WebMediaStreamSource::TypeVideo,
- blink::WebString::fromUTF8("video_track"));
+ blink::WebString::fromUTF8("video_track"),
+ false /* remote */, true /* readonly */);
MockMediaStreamVideoSource* native_video_source =
new MockMediaStreamVideoSource(false);
video_source.setExtraData(native_video_source);
@@ -268,8 +269,8 @@ class RTCPeerConnectionHandlerTest : public ::testing::Test {
const blink::WebMediaConstraints constraints =
constraint_factory.CreateWebMediaConstraints();
scoped_refptr<WebRtcAudioCapturer> capturer(
- WebRtcAudioCapturer::CreateCapturer(
- -1, device_info, constraints, nullptr, nullptr));
+ WebRtcAudioCapturer::CreateCapturer(-1, device_info, constraints,
+ nullptr, nullptr));
scoped_refptr<WebRtcLocalAudioTrackAdapter> adapter(
WebRtcLocalAudioTrackAdapter::Create(audio_track_label, nullptr));
scoped_ptr<WebRtcLocalAudioTrack> native_track(
@@ -966,6 +967,7 @@ TEST_F(RTCPeerConnectionHandlerTest, CreateDataChannel) {
pc_handler_->createDataChannel("d1", blink::WebRTCDataChannelInit()));
EXPECT_TRUE(channel.get() != NULL);
EXPECT_EQ(label, channel->label());
+ channel->setClient(nullptr);
}
TEST_F(RTCPeerConnectionHandlerTest, CreateDtmfSender) {
diff --git a/chromium/content/renderer/media/rtc_video_decoder.cc b/chromium/content/renderer/media/rtc_video_decoder.cc
index 60ae893d9d4..82c853c980c 100644
--- a/chromium/content/renderer/media/rtc_video_decoder.cc
+++ b/chromium/content/renderer/media/rtc_video_decoder.cc
@@ -13,14 +13,16 @@
#include "base/stl_util.h"
#include "base/synchronization/waitable_event.h"
#include "base/task_runner_util.h"
-#include "content/child/child_thread.h"
-#include "content/renderer/media/native_handle_impl.h"
#include "gpu/command_buffer/common/mailbox_holder.h"
#include "media/base/bind_to_current_loop.h"
-#include "media/filters/gpu_video_accelerator_factories.h"
+#include "media/renderers/gpu_video_accelerator_factories.h"
#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/webrtc/common_video/interface/texture_video_frame.h"
+#include "third_party/webrtc/base/bind.h"
#include "third_party/webrtc/system_wrappers/interface/ref_count.h"
+#include "third_party/webrtc/video_frame.h"
+
+static void ReleaseFrame(scoped_refptr<media::VideoFrame> frame) {
+}
namespace content {
@@ -48,16 +50,19 @@ static const size_t kMaxNumOfPendingBuffers = 300;
// of |shm|.
class RTCVideoDecoder::SHMBuffer {
public:
- SHMBuffer(base::SharedMemory* shm, size_t size);
+ SHMBuffer(scoped_ptr<base::SharedMemory> shm, size_t size);
~SHMBuffer();
- base::SharedMemory* const shm;
+ scoped_ptr<base::SharedMemory> const shm;
const size_t size;
};
-RTCVideoDecoder::SHMBuffer::SHMBuffer(base::SharedMemory* shm, size_t size)
- : shm(shm), size(size) {}
+RTCVideoDecoder::SHMBuffer::SHMBuffer(scoped_ptr<base::SharedMemory> shm,
+ size_t size)
+ : shm(shm.Pass()), size(size) {
+}
-RTCVideoDecoder::SHMBuffer::~SHMBuffer() { shm->Close(); }
+RTCVideoDecoder::SHMBuffer::~SHMBuffer() {
+}
RTCVideoDecoder::BufferData::BufferData(int32 bitstream_buffer_id,
uint32_t timestamp,
@@ -210,10 +215,20 @@ int32_t RTCVideoDecoder::Decode(
bool need_to_reset_for_midstream_resize = false;
if (inputImage._frameType == webrtc::kKeyFrame) {
- DVLOG(2) << "Got key frame. size=" << inputImage._encodedWidth << "x"
- << inputImage._encodedHeight;
+ gfx::Size new_frame_size(inputImage._encodedWidth,
+ inputImage._encodedHeight);
+ DVLOG(2) << "Got key frame. size=" << new_frame_size.ToString();
+
+ if (new_frame_size.width() > max_resolution_.width() ||
+ new_frame_size.width() < min_resolution_.width() ||
+ new_frame_size.height() > max_resolution_.height() ||
+ new_frame_size.height() < min_resolution_.height()) {
+ DVLOG(1) << "Resolution unsupported, falling back to software decode";
+ return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
+ }
+
gfx::Size prev_frame_size = frame_size_;
- frame_size_.SetSize(inputImage._encodedWidth, inputImage._encodedHeight);
+ frame_size_ = new_frame_size;
if (!kVDACanHandleMidstreamResize && !prev_frame_size.IsEmpty() &&
prev_frame_size != frame_size_) {
need_to_reset_for_midstream_resize = true;
@@ -386,13 +401,13 @@ void RTCVideoDecoder::PictureReady(const media::Picture& picture) {
DCHECK(inserted);
// Create a WebRTC video frame.
- webrtc::RefCountImpl<NativeHandleImpl>* handle =
- new webrtc::RefCountImpl<NativeHandleImpl>(frame);
- webrtc::TextureVideoFrame decoded_image(handle,
- picture.visible_rect().width(),
- picture.visible_rect().height(),
- timestamp,
- 0);
+ webrtc::I420VideoFrame decoded_image(frame.get(),
+ picture.visible_rect().width(),
+ picture.visible_rect().height(),
+ timestamp,
+ 0,
+ webrtc::kVideoRotation_0,
+ rtc::Bind(&ReleaseFrame, frame));
// Invoke decode callback. WebRTC expects no callback after Reset or Release.
{
@@ -405,33 +420,6 @@ void RTCVideoDecoder::PictureReady(const media::Picture& picture) {
}
}
-static void ReadPixelsSyncInner(
- const scoped_refptr<media::GpuVideoAcceleratorFactories>& factories,
- uint32 texture_id,
- const gfx::Rect& visible_rect,
- const SkBitmap& pixels,
- base::WaitableEvent* event) {
- factories->ReadPixels(texture_id, visible_rect, pixels);
- event->Signal();
-}
-
-static void ReadPixelsSync(
- const scoped_refptr<media::GpuVideoAcceleratorFactories>& factories,
- uint32 texture_id,
- const gfx::Rect& visible_rect,
- const SkBitmap& pixels) {
- base::WaitableEvent event(true, false);
- if (!factories->GetTaskRunner()->PostTask(FROM_HERE,
- base::Bind(&ReadPixelsSyncInner,
- factories,
- texture_id,
- visible_rect,
- pixels,
- &event)))
- return;
- event.Wait();
-}
-
scoped_refptr<media::VideoFrame> RTCVideoDecoder::CreateVideoFrame(
const media::Picture& picture,
const media::PictureBuffer& pb,
@@ -442,18 +430,12 @@ scoped_refptr<media::VideoFrame> RTCVideoDecoder::CreateVideoFrame(
base::TimeDelta timestamp_ms = base::TimeDelta::FromInternalValue(
base::checked_cast<uint64_t>(timestamp) * 1000 / 90);
return media::VideoFrame::WrapNativeTexture(
- make_scoped_ptr(new gpu::MailboxHolder(
- pb.texture_mailbox(), decoder_texture_target_, 0)),
- media::BindToCurrentLoop(base::Bind(&RTCVideoDecoder::ReleaseMailbox,
- weak_factory_.GetWeakPtr(),
- factories_,
- picture.picture_buffer_id(),
- pb.texture_id())),
- pb.size(),
- visible_rect,
- visible_rect.size(),
- timestamp_ms,
- base::Bind(&ReadPixelsSync, factories_, pb.texture_id(), visible_rect));
+ gpu::MailboxHolder(pb.texture_mailbox(), decoder_texture_target_, 0),
+ media::BindToCurrentLoop(base::Bind(
+ &RTCVideoDecoder::ReleaseMailbox, weak_factory_.GetWeakPtr(),
+ factories_, picture.picture_buffer_id(), pb.texture_id())),
+ pb.size(), visible_rect, visible_rect.size(), timestamp_ms,
+ picture.allow_overlay(), true /* has_alpha */);
}
void RTCVideoDecoder::NotifyEndOfBitstreamBuffer(int32 id) {
@@ -683,12 +665,34 @@ void RTCVideoDecoder::ReusePictureBuffer(int64 picture_buffer_id) {
vda_->ReusePictureBuffer(picture_buffer_id);
}
+bool RTCVideoDecoder::IsProfileSupported(media::VideoCodecProfile profile) {
+ DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
+ media::VideoDecodeAccelerator::SupportedProfiles supported_profiles =
+ factories_->GetVideoDecodeAcceleratorSupportedProfiles();
+
+ for (const auto& supported_profile : supported_profiles) {
+ if (profile == supported_profile.profile) {
+ min_resolution_ = supported_profile.min_resolution;
+ max_resolution_ = supported_profile.max_resolution;
+ return true;
+ }
+ }
+
+ return false;
+}
+
void RTCVideoDecoder::CreateVDA(media::VideoCodecProfile profile,
base::WaitableEvent* waiter) {
DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
- vda_ = factories_->CreateVideoDecodeAccelerator();
- if (vda_ && !vda_->Initialize(profile, this))
- vda_.release()->Destroy();
+
+ if (!IsProfileSupported(profile)) {
+ DVLOG(1) << "Unsupported profile " << profile;
+ } else {
+ vda_ = factories_->CreateVideoDecodeAccelerator();
+ if (vda_ && !vda_->Initialize(profile, this))
+ vda_.release()->Destroy();
+ }
+
waiter->Signal();
}
@@ -761,12 +765,13 @@ void RTCVideoDecoder::CreateSHM(int number, size_t min_size) {
}
size_t size_to_allocate = std::max(min_size, kSharedMemorySegmentBytes);
for (int i = 0; i < number_to_allocate; i++) {
- base::SharedMemory* shm = factories_->CreateSharedMemory(size_to_allocate);
- if (shm != NULL) {
+ scoped_ptr<base::SharedMemory> shm =
+ factories_->CreateSharedMemory(size_to_allocate);
+ if (shm) {
base::AutoLock auto_lock(lock_);
num_shm_buffers_++;
PutSHM_Locked(
- scoped_ptr<SHMBuffer>(new SHMBuffer(shm, size_to_allocate)));
+ scoped_ptr<SHMBuffer>(new SHMBuffer(shm.Pass(), size_to_allocate)));
}
}
// Kick off the decoding.
diff --git a/chromium/content/renderer/media/rtc_video_decoder.h b/chromium/content/renderer/media/rtc_video_decoder.h
index 29adee642e6..8bfcc7cd999 100644
--- a/chromium/content/renderer/media/rtc_video_decoder.h
+++ b/chromium/content/renderer/media/rtc_video_decoder.h
@@ -177,6 +177,11 @@ class CONTENT_EXPORT RTCVideoDecoder
// Assert the contract that this class is operated on the right thread.
void DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent() const;
+ // Query factories_ whether |profile| is supported and return true is so,
+ // false otherwise. If true, also set resolution limits for |profile|
+ // in min/max_resolution_.
+ bool IsProfileSupported(media::VideoCodecProfile profile);
+
enum State {
UNINITIALIZED, // The decoder has not initialized.
INITIALIZED, // The decoder has initialized.
@@ -257,6 +262,10 @@ class CONTENT_EXPORT RTCVideoDecoder
// Release has been called. Guarded by |lock_|.
int32 reset_bitstream_buffer_id_;
+ // Minimum and maximum supported resolutions for the current profile/VDA.
+ gfx::Size min_resolution_;
+ gfx::Size max_resolution_;
+
// Must be destroyed, or invalidated, on |vda_loop_proxy_|
// NOTE: Weak pointers must be invalidated before all other member variables.
base::WeakPtrFactory<RTCVideoDecoder> weak_factory_;
diff --git a/chromium/content/renderer/media/rtc_video_decoder_factory.cc b/chromium/content/renderer/media/rtc_video_decoder_factory.cc
index f59a38fa9b3..52e80a834c0 100644
--- a/chromium/content/renderer/media/rtc_video_decoder_factory.cc
+++ b/chromium/content/renderer/media/rtc_video_decoder_factory.cc
@@ -7,7 +7,7 @@
#include "base/location.h"
#include "base/memory/scoped_ptr.h"
#include "content/renderer/media/rtc_video_decoder.h"
-#include "media/filters/gpu_video_accelerator_factories.h"
+#include "media/renderers/gpu_video_accelerator_factories.h"
namespace content {
diff --git a/chromium/content/renderer/media/rtc_video_decoder_factory.h b/chromium/content/renderer/media/rtc_video_decoder_factory.h
index 19c8519b384..c52b831860b 100644
--- a/chromium/content/renderer/media/rtc_video_decoder_factory.h
+++ b/chromium/content/renderer/media/rtc_video_decoder_factory.h
@@ -39,7 +39,7 @@ class CONTENT_EXPORT RTCVideoDecoderFactory
void DestroyVideoDecoder(webrtc::VideoDecoder* decoder) override;
private:
- scoped_refptr<media::GpuVideoAcceleratorFactories> gpu_factories_;
+ const scoped_refptr<media::GpuVideoAcceleratorFactories> gpu_factories_;
DISALLOW_COPY_AND_ASSIGN(RTCVideoDecoderFactory);
};
diff --git a/chromium/content/renderer/media/rtc_video_decoder_unittest.cc b/chromium/content/renderer/media/rtc_video_decoder_unittest.cc
index 4500355bdd6..0e4a5581c66 100644
--- a/chromium/content/renderer/media/rtc_video_decoder_unittest.cc
+++ b/chromium/content/renderer/media/rtc_video_decoder_unittest.cc
@@ -8,7 +8,7 @@
#include "base/threading/thread.h"
#include "content/renderer/media/rtc_video_decoder.h"
#include "media/base/gmock_callback_support.h"
-#include "media/filters/mock_gpu_video_accelerator_factories.h"
+#include "media/renderers/mock_gpu_video_accelerator_factories.h"
#include "media/video/mock_video_decode_accelerator.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -35,12 +35,22 @@ class RTCVideoDecoderTest : public ::testing::Test,
ASSERT_TRUE(vda_thread_.Start());
vda_task_runner_ = vda_thread_.message_loop_proxy();
mock_vda_ = new media::MockVideoDecodeAccelerator;
+
+ media::VideoDecodeAccelerator::SupportedProfile supported_profile;
+ supported_profile.min_resolution.SetSize(16, 16);
+ supported_profile.max_resolution.SetSize(1920, 1088);
+ supported_profile.profile = media::H264PROFILE_MAIN;
+ supported_profiles_.push_back(supported_profile);
+ supported_profile.profile = media::VP8PROFILE_ANY;
+ supported_profiles_.push_back(supported_profile);
+
EXPECT_CALL(*mock_gpu_factories_.get(), GetTaskRunner())
.WillRepeatedly(Return(vda_task_runner_));
+ EXPECT_CALL(*mock_gpu_factories_.get(),
+ GetVideoDecodeAcceleratorSupportedProfiles())
+ .WillRepeatedly(Return(supported_profiles_));
EXPECT_CALL(*mock_gpu_factories_.get(), DoCreateVideoDecodeAccelerator())
.WillRepeatedly(Return(mock_vda_));
- EXPECT_CALL(*mock_gpu_factories_.get(), CreateSharedMemory(_))
- .WillRepeatedly(Return(static_cast<base::SharedMemory*>(NULL)));
EXPECT_CALL(*mock_vda_, Initialize(_, _))
.Times(1)
.WillRepeatedly(Return(true));
@@ -48,7 +58,7 @@ class RTCVideoDecoderTest : public ::testing::Test,
}
void TearDown() override {
- VLOG(2) << "TearDown";
+ DVLOG(2) << "TearDown";
EXPECT_TRUE(vda_thread_.IsRunning());
RunUntilIdle(); // Wait until all callbascks complete.
vda_task_runner_->DeleteSoon(FROM_HERE, rtc_decoder_.release());
@@ -58,27 +68,27 @@ class RTCVideoDecoderTest : public ::testing::Test,
}
int32_t Decoded(webrtc::I420VideoFrame& decoded_image) override {
- VLOG(2) << "Decoded";
+ DVLOG(2) << "Decoded";
EXPECT_EQ(vda_task_runner_, base::MessageLoopProxy::current());
return WEBRTC_VIDEO_CODEC_OK;
}
void CreateDecoder(webrtc::VideoCodecType codec_type) {
- VLOG(2) << "CreateDecoder";
+ DVLOG(2) << "CreateDecoder";
codec_.codecType = codec_type;
rtc_decoder_ =
RTCVideoDecoder::Create(codec_type, mock_gpu_factories_);
}
void Initialize() {
- VLOG(2) << "Initialize";
+ DVLOG(2) << "Initialize";
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, rtc_decoder_->InitDecode(&codec_, 1));
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
rtc_decoder_->RegisterDecodeCompleteCallback(this));
}
void NotifyResetDone() {
- VLOG(2) << "NotifyResetDone";
+ DVLOG(2) << "NotifyResetDone";
vda_task_runner_->PostTask(
FROM_HERE,
base::Bind(&RTCVideoDecoder::NotifyResetDone,
@@ -86,7 +96,7 @@ class RTCVideoDecoderTest : public ::testing::Test,
}
void RunUntilIdle() {
- VLOG(2) << "RunUntilIdle";
+ DVLOG(2) << "RunUntilIdle";
vda_task_runner_->PostTask(FROM_HERE,
base::Bind(&base::WaitableEvent::Signal,
base::Unretained(&idle_waiter_)));
@@ -99,6 +109,7 @@ class RTCVideoDecoderTest : public ::testing::Test,
scoped_ptr<RTCVideoDecoder> rtc_decoder_;
webrtc::VideoCodec codec_;
base::Thread vda_thread_;
+ media::VideoDecodeAccelerator::SupportedProfiles supported_profiles_;
private:
scoped_refptr<base::SingleThreadTaskRunner> vda_task_runner_;
diff --git a/chromium/content/renderer/media/rtc_video_encoder.cc b/chromium/content/renderer/media/rtc_video_encoder.cc
index 517b2d9c5d6..82e61f66e05 100644
--- a/chromium/content/renderer/media/rtc_video_encoder.cc
+++ b/chromium/content/renderer/media/rtc_video_encoder.cc
@@ -15,9 +15,10 @@
#include "media/base/bitstream_buffer.h"
#include "media/base/video_frame.h"
#include "media/base/video_util.h"
-#include "media/filters/gpu_video_accelerator_factories.h"
#include "media/filters/h264_parser.h"
+#include "media/renderers/gpu_video_accelerator_factories.h"
#include "media/video/video_encode_accelerator.h"
+#include "third_party/libyuv/include/libyuv.h"
#include "third_party/webrtc/system_wrappers/interface/tick_util.h"
#define NOTIFY_ERROR(x) \
@@ -356,7 +357,7 @@ void RTCVideoEncoder::Impl::RequireBitstreamBuffers(
input_frame_coded_size_ = input_coded_size;
for (unsigned int i = 0; i < input_count + kInputBufferExtraCount; ++i) {
- base::SharedMemory* shm =
+ scoped_ptr<base::SharedMemory> shm =
gpu_factories_->CreateSharedMemory(media::VideoFrame::AllocationSize(
media::VideoFrame::I420, input_coded_size));
if (!shm) {
@@ -365,12 +366,12 @@ void RTCVideoEncoder::Impl::RequireBitstreamBuffers(
NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError);
return;
}
- input_buffers_.push_back(shm);
+ input_buffers_.push_back(shm.release());
input_buffers_free_.push_back(i);
}
for (int i = 0; i < kOutputBufferCount; ++i) {
- base::SharedMemory* shm =
+ scoped_ptr<base::SharedMemory> shm =
gpu_factories_->CreateSharedMemory(output_buffer_size);
if (!shm) {
DLOG(ERROR) << "Impl::RequireBitstreamBuffers(): "
@@ -378,7 +379,7 @@ void RTCVideoEncoder::Impl::RequireBitstreamBuffers(
NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError);
return;
}
- output_buffers_.push_back(shm);
+ output_buffers_.push_back(shm.release());
}
// Immediately provide all output buffers to the VEA.
@@ -502,6 +503,7 @@ void RTCVideoEncoder::Impl::EncodeOneFrame() {
reinterpret_cast<uint8*>(input_buffer->memory()),
input_buffer->mapped_size(),
input_buffer->handle(),
+ 0,
base::TimeDelta(),
base::Bind(&RTCVideoEncoder::Impl::EncodeFrameFinished, this, index));
if (!frame.get()) {
@@ -513,18 +515,24 @@ void RTCVideoEncoder::Impl::EncodeOneFrame() {
// Do a strided copy of the input frame to match the input requirements for
// the encoder.
// TODO(sheu): support zero-copy from WebRTC. http://crbug.com/269312
- media::CopyYPlane(next_frame->buffer(webrtc::kYPlane),
- next_frame->stride(webrtc::kYPlane),
- next_frame->height(),
- frame.get());
- media::CopyUPlane(next_frame->buffer(webrtc::kUPlane),
- next_frame->stride(webrtc::kUPlane),
- next_frame->height(),
- frame.get());
- media::CopyVPlane(next_frame->buffer(webrtc::kVPlane),
- next_frame->stride(webrtc::kVPlane),
- next_frame->height(),
- frame.get());
+ if (libyuv::I420Copy(next_frame->buffer(webrtc::kYPlane),
+ next_frame->stride(webrtc::kYPlane),
+ next_frame->buffer(webrtc::kUPlane),
+ next_frame->stride(webrtc::kUPlane),
+ next_frame->buffer(webrtc::kVPlane),
+ next_frame->stride(webrtc::kVPlane),
+ frame->data(media::VideoFrame::kYPlane),
+ frame->stride(media::VideoFrame::kYPlane),
+ frame->data(media::VideoFrame::kUPlane),
+ frame->stride(media::VideoFrame::kUPlane),
+ frame->data(media::VideoFrame::kVPlane),
+ frame->stride(media::VideoFrame::kVPlane),
+ next_frame->width(),
+ next_frame->height())) {
+ DLOG(ERROR) << "Failed to copy buffer";
+ NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError);
+ return;
+ }
video_encoder_->Encode(frame, next_frame_keyframe);
input_buffers_free_.pop_back();
@@ -586,7 +594,7 @@ RTCVideoEncoder::~RTCVideoEncoder() {
int32_t RTCVideoEncoder::InitEncode(const webrtc::VideoCodec* codec_settings,
int32_t number_of_cores,
- uint32_t max_payload_size) {
+ size_t max_payload_size) {
DVLOG(1) << "InitEncode(): codecType=" << codec_settings->codecType
<< ", width=" << codec_settings->width
<< ", height=" << codec_settings->height
@@ -673,7 +681,8 @@ int32_t RTCVideoEncoder::Release() {
return WEBRTC_VIDEO_CODEC_OK;
}
-int32_t RTCVideoEncoder::SetChannelParameters(uint32_t packet_loss, int rtt) {
+int32_t RTCVideoEncoder::SetChannelParameters(uint32_t packet_loss,
+ int64_t rtt) {
DVLOG(3) << "SetChannelParameters(): packet_loss=" << packet_loss
<< ", rtt=" << rtt;
// Ignored.
diff --git a/chromium/content/renderer/media/rtc_video_encoder.h b/chromium/content/renderer/media/rtc_video_encoder.h
index 68ac9d04b60..e979ac88e61 100644
--- a/chromium/content/renderer/media/rtc_video_encoder.h
+++ b/chromium/content/renderer/media/rtc_video_encoder.h
@@ -15,18 +15,14 @@
#include "content/common/content_export.h"
#include "media/base/video_decoder_config.h"
#include "third_party/webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
-#include "ui/gfx/size.h"
+#include "ui/gfx/geometry/size.h"
namespace base {
-
class MessageLoopProxy;
-
} // namespace base
namespace media {
-
class GpuVideoAcceleratorFactories;
-
} // namespace media
namespace content {
@@ -54,7 +50,7 @@ class CONTENT_EXPORT RTCVideoEncoder
// appropriate VEA methods.
int32_t InitEncode(const webrtc::VideoCodec* codec_settings,
int32_t number_of_cores,
- uint32_t max_payload_size) override;
+ size_t max_payload_size) override;
int32_t Encode(
const webrtc::I420VideoFrame& input_image,
const webrtc::CodecSpecificInfo* codec_specific_info,
@@ -62,7 +58,7 @@ class CONTENT_EXPORT RTCVideoEncoder
int32_t RegisterEncodeCompleteCallback(
webrtc::EncodedImageCallback* callback) override;
int32_t Release() override;
- int32_t SetChannelParameters(uint32_t packet_loss, int rtt) override;
+ int32_t SetChannelParameters(uint32_t packet_loss, int64_t rtt) override;
int32_t SetRates(uint32_t new_bit_rate, uint32_t frame_rate) override;
private:
@@ -85,7 +81,7 @@ class CONTENT_EXPORT RTCVideoEncoder
const webrtc::VideoCodecType video_codec_type_;
// Factory for creating VEAs, shared memory buffers, etc.
- scoped_refptr<media::GpuVideoAcceleratorFactories> gpu_factories_;
+ const scoped_refptr<media::GpuVideoAcceleratorFactories> gpu_factories_;
// webrtc::VideoEncoder encode complete callback.
webrtc::EncodedImageCallback* encoded_image_callback_;
diff --git a/chromium/content/renderer/media/rtc_video_encoder_factory.cc b/chromium/content/renderer/media/rtc_video_encoder_factory.cc
index 2182f222796..d6fd5b7cc48 100644
--- a/chromium/content/renderer/media/rtc_video_encoder_factory.cc
+++ b/chromium/content/renderer/media/rtc_video_encoder_factory.cc
@@ -8,7 +8,7 @@
#include "content/common/gpu/client/gpu_video_encode_accelerator_host.h"
#include "content/public/common/content_switches.h"
#include "content/renderer/media/rtc_video_encoder.h"
-#include "media/filters/gpu_video_accelerator_factories.h"
+#include "media/renderers/gpu_video_accelerator_factories.h"
#include "media/video/video_encode_accelerator.h"
namespace content {
@@ -20,18 +20,16 @@ namespace {
void VEAToWebRTCCodecs(
std::vector<cricket::WebRtcVideoEncoderFactory::VideoCodec>* codecs,
const media::VideoEncodeAccelerator::SupportedProfile& profile) {
- int width = profile.max_resolution.width();
- int height = profile.max_resolution.height();
- int fps = profile.max_framerate_numerator;
+ const int width = profile.max_resolution.width();
+ const int height = profile.max_resolution.height();
+ const int fps = profile.max_framerate_numerator;
DCHECK_EQ(profile.max_framerate_denominator, 1U);
const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
if (profile.profile >= media::VP8PROFILE_MIN &&
profile.profile <= media::VP8PROFILE_MAX) {
- if (cmd_line->HasSwitch(switches::kEnableWebRtcHWVp8Encoding)) {
- codecs->push_back(cricket::WebRtcVideoEncoderFactory::VideoCodec(
- webrtc::kVideoCodecVP8, "VP8", width, height, fps));
- }
+ codecs->push_back(cricket::WebRtcVideoEncoderFactory::VideoCodec(
+ webrtc::kVideoCodecVP8, "VP8", width, height, fps));
} else if (profile.profile >= media::H264PROFILE_MIN &&
profile.profile <= media::H264PROFILE_MAX) {
if (cmd_line->HasSwitch(switches::kEnableWebRtcHWH264Encoding)) {
@@ -46,26 +44,21 @@ void VEAToWebRTCCodecs(
RTCVideoEncoderFactory::RTCVideoEncoderFactory(
const scoped_refptr<media::GpuVideoAcceleratorFactories>& gpu_factories)
: gpu_factories_(gpu_factories) {
- std::vector<media::VideoEncodeAccelerator::SupportedProfile> profiles =
+ const media::VideoEncodeAccelerator::SupportedProfiles& profiles =
gpu_factories_->GetVideoEncodeAcceleratorSupportedProfiles();
- for (size_t i = 0; i < profiles.size(); ++i)
- VEAToWebRTCCodecs(&codecs_, profiles[i]);
+ for (const auto& profile : profiles)
+ VEAToWebRTCCodecs(&codecs_, profile);
}
RTCVideoEncoderFactory::~RTCVideoEncoderFactory() {}
webrtc::VideoEncoder* RTCVideoEncoderFactory::CreateVideoEncoder(
webrtc::VideoCodecType type) {
- bool found = false;
- for (size_t i = 0; i < codecs_.size(); ++i) {
- if (codecs_[i].type == type) {
- found = true;
- break;
- }
+ for (const auto& codec : codecs_) {
+ if (codec.type == type)
+ return new RTCVideoEncoder(type, gpu_factories_);
}
- if (!found)
- return NULL;
- return new RTCVideoEncoder(type, gpu_factories_);
+ return nullptr;
}
const std::vector<cricket::WebRtcVideoEncoderFactory::VideoCodec>&
diff --git a/chromium/content/renderer/media/rtc_video_encoder_factory.h b/chromium/content/renderer/media/rtc_video_encoder_factory.h
index 986e983461c..11c0962de45 100644
--- a/chromium/content/renderer/media/rtc_video_encoder_factory.h
+++ b/chromium/content/renderer/media/rtc_video_encoder_factory.h
@@ -13,9 +13,7 @@
#include "third_party/libjingle/source/talk/media/webrtc/webrtcvideoencoderfactory.h"
namespace media {
-
class GpuVideoAcceleratorFactories;
-
} // namespace media
namespace content {
@@ -38,8 +36,7 @@ class CONTENT_EXPORT RTCVideoEncoderFactory
private:
const scoped_refptr<media::GpuVideoAcceleratorFactories> gpu_factories_;
- // Codec support list of cricket::WebRtcVideoEncoderFactory::VideoCodec
- // instances.
+ // List of supported cricket::WebRtcVideoEncoderFactory::VideoCodec.
std::vector<VideoCodec> codecs_;
DISALLOW_COPY_AND_ASSIGN(RTCVideoEncoderFactory);
@@ -47,4 +44,4 @@ class CONTENT_EXPORT RTCVideoEncoderFactory
} // namespace content
-#endif // CONTENT_RENDERER_MEDIA_RTC_VIDEO_ENCODER_FACTORY_H_
+#endif // CONTENT_RENDERER_MEDIA_RTC_VIDEO_ENCODER_FACTORY_H_
diff --git a/chromium/content/renderer/media/rtc_video_renderer.cc b/chromium/content/renderer/media/rtc_video_renderer.cc
index 323f0a3d795..76d2ab46d75 100644
--- a/chromium/content/renderer/media/rtc_video_renderer.cc
+++ b/chromium/content/renderer/media/rtc_video_renderer.cc
@@ -4,8 +4,8 @@
#include "content/renderer/media/rtc_video_renderer.h"
-#include "base/debug/trace_event.h"
#include "base/message_loop/message_loop_proxy.h"
+#include "base/trace_event/trace_event.h"
#include "media/base/bind_to_current_loop.h"
#include "media/base/video_frame.h"
#include "media/base/video_util.h"
@@ -62,16 +62,14 @@ void RTCVideoRenderer::Stop() {
void RTCVideoRenderer::Play() {
DCHECK(message_loop_proxy_->BelongsToCurrentThread());
- if (state_ == PAUSED) {
+ if (state_ == PAUSED)
state_ = STARTED;
- }
}
void RTCVideoRenderer::Pause() {
DCHECK(message_loop_proxy_->BelongsToCurrentThread());
- if (state_ == STARTED) {
+ if (state_ == STARTED)
state_ = PAUSED;
- }
}
void RTCVideoRenderer::OnReadyStateChanged(
@@ -83,12 +81,10 @@ void RTCVideoRenderer::OnReadyStateChanged(
void RTCVideoRenderer::OnVideoFrame(
const scoped_refptr<media::VideoFrame>& frame,
- const media::VideoCaptureFormat& format,
const base::TimeTicks& estimated_capture_time) {
DCHECK(message_loop_proxy_->BelongsToCurrentThread());
- if (state_ != STARTED) {
+ if (state_ != STARTED)
return;
- }
frame_size_ = frame->natural_size();
@@ -109,7 +105,7 @@ void RTCVideoRenderer::RenderSignalingFrame() {
// originates from a video camera.
scoped_refptr<media::VideoFrame> video_frame =
media::VideoFrame::CreateBlackFrame(frame_size_);
- OnVideoFrame(video_frame, media::VideoCaptureFormat(), base::TimeTicks());
+ OnVideoFrame(video_frame, base::TimeTicks());
}
} // namespace content
diff --git a/chromium/content/renderer/media/rtc_video_renderer.h b/chromium/content/renderer/media/rtc_video_renderer.h
index 699fe84d2ef..c68b8074fd5 100644
--- a/chromium/content/renderer/media/rtc_video_renderer.h
+++ b/chromium/content/renderer/media/rtc_video_renderer.h
@@ -12,7 +12,7 @@
#include "content/public/renderer/media_stream_video_sink.h"
#include "content/renderer/media/video_frame_provider.h"
#include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
-#include "ui/gfx/size.h"
+#include "ui/gfx/geometry/size.h"
namespace base {
class MessageLoopProxy;
@@ -20,13 +20,14 @@ class MessageLoopProxy;
namespace content {
-// RTCVideoRenderer is a VideoFrameProvider designed for rendering
-// Video MediaStreamTracks,
-// http://dev.w3.org/2011/webrtc/editor/getusermedia.html#mediastreamtrack
-// RTCVideoRenderer implements VideoTrackSink in order to render
-// video frames provided from a VideoTrack.
-// RTCVideoRenderer register itself as a sink to the VideoTrack when the
-// VideoFrameProvider is started and deregisters itself when it is stopped.
+// RTCVideoRenderer is a VideoFrameProvider designed for rendering Video
+// MediaStreamTracks [1], RTCVideoRenderer implements MediaStreamVideoSink in
+// order to render video frames provided from a MediaStreamVideoTrack, to which
+// it AddToVideoTrack()s itself when the VideoFrameProvider is Start()ed
+// and RemoveFromVideoTrack()s itself when the latter is Stop()ed.
+//
+// [1] http://dev.w3.org/2011/webrtc/editor/getusermedia.html#mediastreamtrack
+//
// TODO(wuchengli): Add unit test. See the link below for reference.
// http://src.chromium.org/viewvc/chrome/trunk/src/content/renderer/media/rtc_vi
// deo_decoder_unittest.cc?revision=180591&view=markup
@@ -55,21 +56,20 @@ class CONTENT_EXPORT RTCVideoRenderer
};
void OnVideoFrame(const scoped_refptr<media::VideoFrame>& frame,
- const media::VideoCaptureFormat& format,
const base::TimeTicks& estimated_capture_time);
- // VideoTrackSink implementation. Called on the main thread.
+ // MediaStreamVideoSink implementation. Called on the main thread.
void OnReadyStateChanged(
blink::WebMediaStreamSource::ReadyState state) override;
void RenderSignalingFrame();
- base::Closure error_cb_;
- RepaintCB repaint_cb_;
- scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
+ const base::Closure error_cb_;
+ const RepaintCB repaint_cb_;
+ const scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
State state_;
gfx::Size frame_size_;
- blink::WebMediaStreamTrack video_track_;
+ const blink::WebMediaStreamTrack video_track_;
base::WeakPtrFactory<RTCVideoRenderer> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(RTCVideoRenderer);
diff --git a/chromium/content/renderer/media/speech_recognition_audio_sink.cc b/chromium/content/renderer/media/speech_recognition_audio_sink.cc
index c51c695c879..6b80dd272ff 100644
--- a/chromium/content/renderer/media/speech_recognition_audio_sink.cc
+++ b/chromium/content/renderer/media/speech_recognition_audio_sink.cc
@@ -93,8 +93,6 @@ void SpeechRecognitionAudioSink::OnSetFormat(
static const int kNumberOfBuffersInFifo = 2;
int frames_in_fifo = kNumberOfBuffersInFifo * fifo_buffer_size_;
fifo_.reset(new media::AudioFifo(input_params.channels(), frames_in_fifo));
- input_bus_ = media::AudioBus::Create(input_params.channels(),
- input_params.frames_per_buffer());
// Create the audio converter with |disable_fifo| as false so that the
// converter will request input_params.frames_per_buffer() each time.
@@ -118,14 +116,13 @@ void SpeechRecognitionAudioSink::OnReadyStateChanged(
}
}
-void SpeechRecognitionAudioSink::OnData(const int16* audio_data,
- int sample_rate,
- int number_of_channels,
- int number_of_frames) {
+void SpeechRecognitionAudioSink::OnData(
+ const media::AudioBus& audio_bus,
+ base::TimeTicks estimated_capture_time) {
DCHECK(capture_thread_checker_.CalledOnValidThread());
- DCHECK_EQ(input_bus_->frames(), number_of_frames);
- DCHECK_EQ(input_bus_->channels(), number_of_channels);
- if (fifo_->frames() + number_of_frames > fifo_->max_frames()) {
+ DCHECK_EQ(audio_bus.frames(), input_params_.frames_per_buffer());
+ DCHECK_EQ(audio_bus.channels(), input_params_.channels());
+ if (fifo_->frames() + audio_bus.frames() > fifo_->max_frames()) {
// This would indicate a serious issue with the browser process or the
// SyncSocket and/or SharedMemory. We drop any previous buffers and try to
// recover by resuming where the peer left of.
@@ -133,12 +130,8 @@ void SpeechRecognitionAudioSink::OnData(const int16* audio_data,
fifo_->Clear();
buffer_index_ = GetAudioInputBuffer()->params.size;
}
- // TODO(xians): A better way to handle the interleaved and deinterleaved
- // format switching, see issue/317710.
- input_bus_->FromInterleaved(audio_data, number_of_frames,
- sizeof(audio_data[0]));
- fifo_->Push(input_bus_.get());
+ fifo_->Push(&audio_bus);
// Wait for FIFO to have at least |fifo_buffer_size_| frames ready.
if (fifo_->frames() < fifo_buffer_size_)
return;
diff --git a/chromium/content/renderer/media/speech_recognition_audio_sink.h b/chromium/content/renderer/media/speech_recognition_audio_sink.h
index bef5e46d447..d1200b2f29d 100644
--- a/chromium/content/renderer/media/speech_recognition_audio_sink.h
+++ b/chromium/content/renderer/media/speech_recognition_audio_sink.h
@@ -52,10 +52,8 @@ class CONTENT_EXPORT SpeechRecognitionAudioSink
void OnReadyStateChanged(
blink::WebMediaStreamSource::ReadyState state) override;
- void OnData(const int16* audio_data,
- int sample_rate,
- int number_of_channels,
- int number_of_frames) override;
+ void OnData(const media::AudioBus& audio_bus,
+ base::TimeTicks estimated_capture_time) override;
void OnSetFormat(const media::AudioParameters& params) override;
// media::AudioConverter::Inputcallback implementation.
@@ -92,9 +90,6 @@ class CONTENT_EXPORT SpeechRecognitionAudioSink
// FIFO is used for queuing audio frames before we resample.
scoped_ptr<media::AudioFifo> fifo_;
- // Audio delivered from source.
- scoped_ptr<media::AudioBus> input_bus_;
-
// Audio bus shared with the browser process via |shared_memory_|.
scoped_ptr<media::AudioBus> output_bus_;
diff --git a/chromium/content/renderer/media/speech_recognition_audio_sink_unittest.cc b/chromium/content/renderer/media/speech_recognition_audio_sink_unittest.cc
index 4366309f1ed..12e8cc1825c 100644
--- a/chromium/content/renderer/media/speech_recognition_audio_sink_unittest.cc
+++ b/chromium/content/renderer/media/speech_recognition_audio_sink_unittest.cc
@@ -224,7 +224,11 @@ class SpeechRecognitionAudioSinkTest : public testing::Test {
output_sample_rate,
kOutputBitsPerSample,
output_frames_per_buffer);
- source_data_.reset(new int16[input_frames_per_buffer * kInputChannels]{});
+ source_bus_ =
+ media::AudioBus::Create(kInputChannels, input_frames_per_buffer);
+ source_bus_->Zero();
+ first_frame_capture_time_ = base::TimeTicks::Now();
+ sample_frames_captured_ = 0;
// Prepare the track and audio source.
blink::WebMediaStreamTrack blink_track;
@@ -278,7 +282,8 @@ class SpeechRecognitionAudioSinkTest : public testing::Test {
blink::WebMediaStreamSource blink_audio_source;
blink_audio_source.initialize(base::UTF8ToUTF16("dummy_source_id"),
blink::WebMediaStreamSource::TypeAudio,
- base::UTF8ToUTF16("dummy_source_name"));
+ base::UTF8ToUTF16("dummy_source_name"),
+ false /* remote */, true /* readonly */);
MediaStreamSource::SourceStoppedCallback cb;
blink_audio_source.setExtraData(
new MediaStreamAudioSource(-1, device_info, cb, NULL));
@@ -289,10 +294,13 @@ class SpeechRecognitionAudioSinkTest : public testing::Test {
// Emulates an audio capture device capturing data from the source.
inline void CaptureAudio(const uint32 buffers) {
- for (uint32 i = 0; i < buffers; ++i)
- native_track()->Capture(source_data(),
- base::TimeDelta::FromMilliseconds(0), 1, false,
- false, false);
+ for (uint32 i = 0; i < buffers; ++i) {
+ const base::TimeTicks estimated_capture_time = first_frame_capture_time_ +
+ (sample_frames_captured_ * base::TimeDelta::FromSeconds(1) /
+ source_params_.sample_rate());
+ native_track()->Capture(*source_bus_, estimated_capture_time, false);
+ sample_frames_captured_ += source_bus_->frames();
+ }
}
// Used to simulate a problem with sockets.
@@ -321,14 +329,15 @@ class SpeechRecognitionAudioSinkTest : public testing::Test {
const int output_sample_rate,
const int output_frames_per_buffer,
const uint32 consumptions) {
- const uint32 kBuffersPerNotification = Initialize(input_sample_rate,
- input_frames_per_buffer,
- output_sample_rate,
- output_frames_per_buffer);
+ const uint32 buffers_per_notification =
+ Initialize(input_sample_rate,
+ input_frames_per_buffer,
+ output_sample_rate,
+ output_frames_per_buffer);
AssertConsumedBuffers(0U);
for (uint32 i = 1U; i <= consumptions; ++i) {
- CaptureAudio(kBuffersPerNotification);
+ CaptureAudio(buffers_per_notification);
ASSERT_EQ(i, recognizer()->GetAudioInputBuffer()->params.size)
<< "Tested at rates: "
<< "In(" << input_sample_rate << ", " << input_frames_per_buffer
@@ -338,13 +347,13 @@ class SpeechRecognitionAudioSinkTest : public testing::Test {
}
}
- int16* source_data() { return source_data_.get(); }
+ media::AudioBus* source_bus() const { return source_bus_.get(); }
- FakeSpeechRecognizer* recognizer() { return recognizer_.get(); }
+ FakeSpeechRecognizer* recognizer() const { return recognizer_.get(); }
- const media::AudioParameters& sink_params() { return sink_params_; }
+ const media::AudioParameters& sink_params() const { return sink_params_; }
- WebRtcLocalAudioTrack* native_track() { return native_track_; }
+ WebRtcLocalAudioTrack* native_track() const { return native_track_; }
private:
// Producer.
@@ -354,11 +363,14 @@ class SpeechRecognitionAudioSinkTest : public testing::Test {
scoped_ptr<FakeSpeechRecognizer> recognizer_;
// Audio related members.
- scoped_ptr<int16[]> source_data_;
+ scoped_ptr<media::AudioBus> source_bus_;
media::AudioParameters source_params_;
media::AudioParameters sink_params_;
WebRtcLocalAudioTrack* native_track_;
+ base::TimeTicks first_frame_capture_time_;
+ int64 sample_frames_captured_;
+
DISALLOW_COPY_AND_ASSIGN(SpeechRecognitionAudioSinkTest);
};
@@ -375,7 +387,7 @@ TEST_F(SpeechRecognitionAudioSinkTest, CheckIsSupportedAudioTrack) {
p[MEDIA_TAB_AUDIO_CAPTURE] = false;
p[MEDIA_TAB_VIDEO_CAPTURE] = false;
p[MEDIA_DESKTOP_VIDEO_CAPTURE] = false;
- p[MEDIA_LOOPBACK_AUDIO_CAPTURE] = false;
+ p[MEDIA_DESKTOP_AUDIO_CAPTURE] = false;
p[MEDIA_DEVICE_AUDIO_OUTPUT] = false;
// Ensure this test gets updated along with |content::MediaStreamType| enum.
@@ -419,13 +431,17 @@ TEST_F(SpeechRecognitionAudioSinkTest, AudioDataIsResampledOnSink) {
// Input audio is sampled at 44.1 KHz with data chunks of 10ms. Desired output
// is corresponding to the speech recognition engine requirements: 16 KHz with
// 100 ms chunks (1600 frames per buffer).
- const uint32 kBuffersPerNotification = Initialize(44100, 441, 16000, 1600);
+ const uint32 kSourceFrames = 441;
+ const uint32 buffers_per_notification =
+ Initialize(44100, kSourceFrames, 16000, 1600);
// Fill audio input frames with 0, 1, 2, 3, ..., 440.
- const uint32 kSourceDataLength = 441 * kInputChannels;
- for (uint32 i = 0; i < kSourceDataLength; ++i) {
+ int16 source_data[kSourceFrames * kInputChannels];
+ for (uint32 i = 0; i < kSourceFrames; ++i) {
for (int c = 0; c < kInputChannels; ++c)
- source_data()[i * kInputChannels + c] = i;
+ source_data[i * kInputChannels + c] = i;
}
+ source_bus()->FromInterleaved(
+ source_data, kSourceFrames, sizeof(source_data[0]));
// Prepare sink audio bus and data for rendering.
media::AudioBus* sink_bus = recognizer()->audio_bus();
@@ -447,13 +463,13 @@ TEST_F(SpeechRecognitionAudioSinkTest, AudioDataIsResampledOnSink) {
// Trigger the speech sink to resample the input data.
AssertConsumedBuffers(0U);
- CaptureAudioAndAssertConsumedBuffers(kBuffersPerNotification, 1U);
+ CaptureAudioAndAssertConsumedBuffers(buffers_per_notification, 1U);
// Render the audio data from the recognizer.
sink_bus->ToInterleaved(sink_bus->frames(),
sink_params().bits_per_sample() / 8, sink_data);
- // Resampled data expected frames. Extracted based on |source_data()|.
+ // Resampled data expected frames. Extracted based on |source_data|.
const int16 kExpectedData[kNumFramesToTest] = {0, 2, 5, 8, 11, 13,
16, 19, 22, 24, 27, 30};
@@ -466,14 +482,14 @@ TEST_F(SpeechRecognitionAudioSinkTest, AudioDataIsResampledOnSink) {
// Checks that the producer does not misbehave when a socket failure occurs.
TEST_F(SpeechRecognitionAudioSinkTest, SyncSocketFailsSendingData) {
- const uint32 kBuffersPerNotification = Initialize(44100, 441, 16000, 1600);
+ const uint32 buffers_per_notification = Initialize(44100, 441, 16000, 1600);
// Start with no problems on the socket.
AssertConsumedBuffers(0U);
- CaptureAudioAndAssertConsumedBuffers(kBuffersPerNotification, 1U);
+ CaptureAudioAndAssertConsumedBuffers(buffers_per_notification, 1U);
// A failure occurs (socket cannot send).
SetFailureModeOnForeignSocket(true);
- CaptureAudioAndAssertConsumedBuffers(kBuffersPerNotification, 1U);
+ CaptureAudioAndAssertConsumedBuffers(buffers_per_notification, 1U);
}
// A very unlikely scenario in which the peer is not synchronizing for a long
@@ -481,34 +497,34 @@ TEST_F(SpeechRecognitionAudioSinkTest, SyncSocketFailsSendingData) {
// We check that the FIFO overflow does not occur and that the producer is able
// to resume.
TEST_F(SpeechRecognitionAudioSinkTest, RepeatedSycnhronizationLag) {
- const uint32 kBuffersPerNotification = Initialize(44100, 441, 16000, 1600);
+ const uint32 buffers_per_notification = Initialize(44100, 441, 16000, 1600);
// Start with no synchronization problems.
AssertConsumedBuffers(0U);
- CaptureAudioAndAssertConsumedBuffers(kBuffersPerNotification, 1U);
+ CaptureAudioAndAssertConsumedBuffers(buffers_per_notification, 1U);
// Consumer gets out of sync.
recognizer()->SimulateResponsiveness(false);
- CaptureAudioAndAssertConsumedBuffers(kBuffersPerNotification, 1U);
- CaptureAudioAndAssertConsumedBuffers(kBuffersPerNotification, 1U);
- CaptureAudioAndAssertConsumedBuffers(kBuffersPerNotification, 1U);
+ CaptureAudioAndAssertConsumedBuffers(buffers_per_notification, 1U);
+ CaptureAudioAndAssertConsumedBuffers(buffers_per_notification, 1U);
+ CaptureAudioAndAssertConsumedBuffers(buffers_per_notification, 1U);
// Consumer recovers.
recognizer()->SimulateResponsiveness(true);
- CaptureAudioAndAssertConsumedBuffers(kBuffersPerNotification, 2U);
- CaptureAudioAndAssertConsumedBuffers(kBuffersPerNotification, 3U);
- CaptureAudioAndAssertConsumedBuffers(kBuffersPerNotification, 4U);
+ CaptureAudioAndAssertConsumedBuffers(buffers_per_notification, 2U);
+ CaptureAudioAndAssertConsumedBuffers(buffers_per_notification, 3U);
+ CaptureAudioAndAssertConsumedBuffers(buffers_per_notification, 4U);
}
// Checks that an OnStoppedCallback is issued when the track is stopped.
TEST_F(SpeechRecognitionAudioSinkTest, OnReadyStateChangedOccured) {
- const uint32 kBuffersPerNotification = Initialize(44100, 441, 16000, 1600);
+ const uint32 buffers_per_notification = Initialize(44100, 441, 16000, 1600);
AssertConsumedBuffers(0U);
- CaptureAudioAndAssertConsumedBuffers(kBuffersPerNotification, 1U);
+ CaptureAudioAndAssertConsumedBuffers(buffers_per_notification, 1U);
EXPECT_CALL(*this, StoppedCallback()).Times(1);
native_track()->Stop();
- CaptureAudioAndAssertConsumedBuffers(kBuffersPerNotification, 1U);
+ CaptureAudioAndAssertConsumedBuffers(buffers_per_notification, 1U);
}
} // namespace content
diff --git a/chromium/content/renderer/media/user_media_client_impl.cc b/chromium/content/renderer/media/user_media_client_impl.cc
index 047e07ae4fd..5475d2a60b0 100644
--- a/chromium/content/renderer/media/user_media_client_impl.cc
+++ b/chromium/content/renderer/media/user_media_client_impl.cc
@@ -499,7 +499,7 @@ void UserMediaClientImpl::OnStreamGenerationFailed(
return;
}
- GetUserMediaRequestFailed(&request_info->request, result);
+ GetUserMediaRequestFailed(request_info->request, result, "");
DeleteUserMediaRequestInfo(request_info);
}
@@ -550,7 +550,8 @@ void UserMediaClientImpl::InitializeSourceObject(
webkit_source->initialize(
base::UTF8ToUTF16(device.device.id),
type,
- base::UTF8ToUTF16(device.device.name));
+ base::UTF8ToUTF16(device.device.name),
+ false /* remote */, true /* readonly */);
DVLOG(1) << "Initialize source object :"
<< "id = " << webkit_source->id().utf8()
@@ -579,10 +580,12 @@ void UserMediaClientImpl::InitializeSourceObject(
MediaStreamVideoSource* UserMediaClientImpl::CreateVideoSource(
const StreamDeviceInfo& device,
const MediaStreamSource::SourceStoppedCallback& stop_callback) {
- return new content::MediaStreamVideoCapturerSource(
- device,
- stop_callback,
- new VideoCapturerDelegate(device));
+ content::MediaStreamVideoCapturerSource* ret =
+ new content::MediaStreamVideoCapturerSource(
+ stop_callback,
+ make_scoped_ptr(new VideoCapturerDelegate(device)));
+ ret->SetDeviceInfo(device);
+ return ret;
}
void UserMediaClientImpl::CreateVideoTracks(
@@ -650,12 +653,11 @@ void UserMediaClientImpl::OnCreateNativeTracksCompleted(
DVLOG(1) << "UserMediaClientImpl::OnCreateNativeTracksComplete("
<< "{request_id = " << request->request_id << "} "
<< "{result = " << result << "})";
+
if (result == content::MEDIA_DEVICE_OK)
- GetUserMediaRequestSucceeded(request->web_stream, &request->request);
+ GetUserMediaRequestSucceeded(request->web_stream, request->request);
else
- GetUserMediaRequestTrackStartedFailed(&request->request,
- result,
- result_name);
+ GetUserMediaRequestFailed(request->request, result, result_name);
DeleteUserMediaRequestInfo(request);
}
@@ -715,67 +717,89 @@ void UserMediaClientImpl::OnDeviceOpenFailed(int request_id) {
void UserMediaClientImpl::GetUserMediaRequestSucceeded(
const blink::WebMediaStream& stream,
- blink::WebUserMediaRequest* request_info) {
- DVLOG(1) << "UserMediaClientImpl::GetUserMediaRequestSucceeded";
+ blink::WebUserMediaRequest request_info) {
+ // Completing the getUserMedia request can lead to that the RenderFrame and
+ // the UserMediaClientImpl is destroyed if the JavaScript code request the
+ // frame to be destroyed within the scope of the callback. Therefore,
+ // post a task to complete the request with a clean stack.
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&UserMediaClientImpl::DelayedGetUserMediaRequestSucceeded,
+ weak_factory_.GetWeakPtr(), stream, request_info));
+}
+
+void UserMediaClientImpl::DelayedGetUserMediaRequestSucceeded(
+ const blink::WebMediaStream& stream,
+ blink::WebUserMediaRequest request_info) {
+ DVLOG(1) << "UserMediaClientImpl::DelayedGetUserMediaRequestSucceeded";
LogUserMediaRequestResult(MEDIA_DEVICE_OK);
- request_info->requestSucceeded(stream);
+ request_info.requestSucceeded(stream);
}
void UserMediaClientImpl::GetUserMediaRequestFailed(
- blink::WebUserMediaRequest* request_info,
- MediaStreamRequestResult result) {
+ blink::WebUserMediaRequest request_info,
+ MediaStreamRequestResult result,
+ const blink::WebString& result_name) {
+ // Completing the getUserMedia request can lead to that the RenderFrame and
+ // the UserMediaClientImpl is destroyed if the JavaScript code request the
+ // frame to be destroyed within the scope of the callback. Therefore,
+ // post a task to complete the request with a clean stack.
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&UserMediaClientImpl::DelayedGetUserMediaRequestFailed,
+ weak_factory_.GetWeakPtr(), request_info, result,
+ result_name));
+}
+
+void UserMediaClientImpl::DelayedGetUserMediaRequestFailed(
+ blink::WebUserMediaRequest request_info,
+ MediaStreamRequestResult result,
+ const blink::WebString& result_name) {
LogUserMediaRequestResult(result);
switch (result) {
case MEDIA_DEVICE_OK:
+ case NUM_MEDIA_REQUEST_RESULTS:
NOTREACHED();
- break;
+ return;
case MEDIA_DEVICE_PERMISSION_DENIED:
- request_info->requestDenied();
- break;
+ request_info.requestDenied();
+ return;
case MEDIA_DEVICE_PERMISSION_DISMISSED:
- request_info->requestFailedUASpecific("PermissionDismissedError");
- break;
+ request_info.requestFailedUASpecific("PermissionDismissedError");
+ return;
case MEDIA_DEVICE_INVALID_STATE:
- request_info->requestFailedUASpecific("InvalidStateError");
- break;
+ request_info.requestFailedUASpecific("InvalidStateError");
+ return;
case MEDIA_DEVICE_NO_HARDWARE:
- request_info->requestFailedUASpecific("DevicesNotFoundError");
- break;
+ request_info.requestFailedUASpecific("DevicesNotFoundError");
+ return;
case MEDIA_DEVICE_INVALID_SECURITY_ORIGIN:
- request_info->requestFailedUASpecific("InvalidSecurityOriginError");
- break;
+ request_info.requestFailedUASpecific("InvalidSecurityOriginError");
+ return;
case MEDIA_DEVICE_TAB_CAPTURE_FAILURE:
- request_info->requestFailedUASpecific("TabCaptureError");
- break;
+ request_info.requestFailedUASpecific("TabCaptureError");
+ return;
case MEDIA_DEVICE_SCREEN_CAPTURE_FAILURE:
- request_info->requestFailedUASpecific("ScreenCaptureError");
- break;
+ request_info.requestFailedUASpecific("ScreenCaptureError");
+ return;
case MEDIA_DEVICE_CAPTURE_FAILURE:
- request_info->requestFailedUASpecific("DeviceCaptureError");
- break;
- default:
- NOTREACHED();
- request_info->requestFailed();
- break;
- }
-}
-
-void UserMediaClientImpl::GetUserMediaRequestTrackStartedFailed(
- blink::WebUserMediaRequest* request_info,
- MediaStreamRequestResult result,
- const blink::WebString& result_name) {
- switch (result) {
+ request_info.requestFailedUASpecific("DeviceCaptureError");
+ return;
case MEDIA_DEVICE_CONSTRAINT_NOT_SATISFIED:
- request_info->requestFailedConstraint(result_name);
- break;
+ request_info.requestFailedConstraint(result_name);
+ return;
case MEDIA_DEVICE_TRACK_START_FAILURE:
- request_info->requestFailedUASpecific("TrackStartError");
- break;
- default:
- NOTREACHED();
- request_info->requestFailed();
- break;
+ request_info.requestFailedUASpecific("TrackStartError");
+ return;
+ case MEDIA_DEVICE_NOT_SUPPORTED:
+ request_info.requestFailedUASpecific("MediaDeviceNotSupported");
+ return;
+ case MEDIA_DEVICE_FAILED_DUE_TO_SHUTDOWN:
+ request_info.requestFailedUASpecific("MediaDeviceFailedDueToShutdown");
+ return;
}
+ NOTREACHED();
+ request_info.requestFailed();
}
void UserMediaClientImpl::EnumerateDevicesSucceded(
diff --git a/chromium/content/renderer/media/user_media_client_impl.h b/chromium/content/renderer/media/user_media_client_impl.h
index 9ec1e7367dd..78f19e498d5 100644
--- a/chromium/content/renderer/media/user_media_client_impl.h
+++ b/chromium/content/renderer/media/user_media_client_impl.h
@@ -96,14 +96,19 @@ class CONTENT_EXPORT UserMediaClientImpl
// |request| have completed.
virtual void GetUserMediaRequestSucceeded(
const blink::WebMediaStream& stream,
- blink::WebUserMediaRequest* request_info);
+ blink::WebUserMediaRequest request_info);
+ void DelayedGetUserMediaRequestSucceeded(
+ const blink::WebMediaStream& stream,
+ blink::WebUserMediaRequest request_info);
virtual void GetUserMediaRequestFailed(
- blink::WebUserMediaRequest* request_info,
- MediaStreamRequestResult result);
- virtual void GetUserMediaRequestTrackStartedFailed(
- blink::WebUserMediaRequest* request_info,
+ blink::WebUserMediaRequest request_info,
MediaStreamRequestResult result,
const blink::WebString& result_name);
+ void DelayedGetUserMediaRequestFailed(
+ blink::WebUserMediaRequest request_info,
+ MediaStreamRequestResult result,
+ const blink::WebString& result_name);
+
virtual void EnumerateDevicesSucceded(
blink::WebMediaDevicesRequest* request,
blink::WebVector<blink::WebMediaDeviceInfo>& devices);
diff --git a/chromium/content/renderer/media/user_media_client_impl_unittest.cc b/chromium/content/renderer/media/user_media_client_impl_unittest.cc
index 35c41a064cd..f92443ce7e7 100644
--- a/chromium/content/renderer/media/user_media_client_impl_unittest.cc
+++ b/chromium/content/renderer/media/user_media_client_impl_unittest.cc
@@ -77,22 +77,14 @@ class UserMediaClientImplUnderTest : public UserMediaClientImpl {
void GetUserMediaRequestSucceeded(
const blink::WebMediaStream& stream,
- blink::WebUserMediaRequest* request_info) override {
+ blink::WebUserMediaRequest request_info) override {
last_generated_stream_ = stream;
state_ = REQUEST_SUCCEEDED;
}
void GetUserMediaRequestFailed(
- blink::WebUserMediaRequest* request_info,
- content::MediaStreamRequestResult result) override {
- last_generated_stream_.reset();
- state_ = REQUEST_FAILED;
- result_ = result;
- }
-
- void GetUserMediaRequestTrackStartedFailed(
- blink::WebUserMediaRequest* request_info,
- MediaStreamRequestResult result,
+ blink::WebUserMediaRequest request_info,
+ content::MediaStreamRequestResult result,
const blink::WebString& result_name) override {
last_generated_stream_.reset();
state_ = REQUEST_FAILED;
diff --git a/chromium/content/renderer/media/video_capture_impl.cc b/chromium/content/renderer/media/video_capture_impl.cc
index 9688b464680..6b05dd29a12 100644
--- a/chromium/content/renderer/media/video_capture_impl.cc
+++ b/chromium/content/renderer/media/video_capture_impl.cc
@@ -52,27 +52,31 @@ VideoCaptureImpl::VideoCaptureImpl(
state_(VIDEO_CAPTURE_STATE_STOPPED),
weak_factory_(this) {
DCHECK(filter);
- thread_checker_.DetachFromThread();
}
VideoCaptureImpl::~VideoCaptureImpl() {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(io_message_loop_->BelongsToCurrentThread());
}
void VideoCaptureImpl::Init() {
- DCHECK(thread_checker_.CalledOnValidThread());
+ // For creating callbacks in unittest, this class may be constructed from a
+ // different thread than the IO thread, e.g. wherever unittest runs on.
+ // Therefore, this function should define the thread ownership.
+#if DCHECK_IS_ON()
+ io_message_loop_ = base::MessageLoopProxy::current();
+#endif
message_filter_->AddDelegate(this);
}
void VideoCaptureImpl::DeInit() {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(io_message_loop_->BelongsToCurrentThread());
if (state_ == VIDEO_CAPTURE_STATE_STARTED)
Send(new VideoCaptureHostMsg_Stop(device_id_));
message_filter_->RemoveDelegate(this);
}
void VideoCaptureImpl::SuspendCapture(bool suspend) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(io_message_loop_->BelongsToCurrentThread());
Send(suspend ?
static_cast<IPC::Message*>(new VideoCaptureHostMsg_Pause(device_id_)) :
static_cast<IPC::Message*>(
@@ -84,7 +88,7 @@ void VideoCaptureImpl::StartCapture(
const media::VideoCaptureParams& params,
const VideoCaptureStateUpdateCB& state_update_cb,
const VideoCaptureDeliverFrameCB& deliver_frame_cb) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(io_message_loop_->BelongsToCurrentThread());
ClientInfo client_info;
client_info.params = params;
client_info.state_update_cb = state_update_cb;
@@ -132,7 +136,7 @@ void VideoCaptureImpl::StartCapture(
}
void VideoCaptureImpl::StopCapture(int client_id) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(io_message_loop_->BelongsToCurrentThread());
// A client ID can be in only one client list.
// If this ID is in any client list, we can just remove it from
@@ -153,7 +157,7 @@ void VideoCaptureImpl::StopCapture(int client_id) {
void VideoCaptureImpl::GetDeviceSupportedFormats(
const VideoCaptureDeviceFormatsCB& callback) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(io_message_loop_->BelongsToCurrentThread());
device_formats_cb_queue_.push_back(callback);
if (device_formats_cb_queue_.size() == 1)
Send(new VideoCaptureHostMsg_GetDeviceSupportedFormats(device_id_,
@@ -162,7 +166,7 @@ void VideoCaptureImpl::GetDeviceSupportedFormats(
void VideoCaptureImpl::GetDeviceFormatsInUse(
const VideoCaptureDeviceFormatsCB& callback) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(io_message_loop_->BelongsToCurrentThread());
device_formats_in_use_cb_queue_.push_back(callback);
if (device_formats_in_use_cb_queue_.size() == 1)
Send(
@@ -172,7 +176,7 @@ void VideoCaptureImpl::GetDeviceFormatsInUse(
void VideoCaptureImpl::OnBufferCreated(
base::SharedMemoryHandle handle,
int length, int buffer_id) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(io_message_loop_->BelongsToCurrentThread());
// In case client calls StopCapture before the arrival of created buffer,
// just close this buffer and return.
@@ -196,9 +200,9 @@ void VideoCaptureImpl::OnBufferCreated(
}
void VideoCaptureImpl::OnBufferDestroyed(int buffer_id) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(io_message_loop_->BelongsToCurrentThread());
- ClientBufferMap::iterator iter = client_buffers_.find(buffer_id);
+ const ClientBufferMap::iterator iter = client_buffers_.find(buffer_id);
if (iter == client_buffers_.end())
return;
@@ -208,20 +212,17 @@ void VideoCaptureImpl::OnBufferDestroyed(int buffer_id) {
}
void VideoCaptureImpl::OnBufferReceived(int buffer_id,
- const media::VideoCaptureFormat& format,
+ const gfx::Size& coded_size,
const gfx::Rect& visible_rect,
- base::TimeTicks timestamp) {
- DCHECK(thread_checker_.CalledOnValidThread());
-
- // The capture pipeline supports only I420 for now.
- DCHECK_EQ(format.pixel_format, media::PIXEL_FORMAT_I420);
+ base::TimeTicks timestamp,
+ const base::DictionaryValue& metadata) {
+ DCHECK(io_message_loop_->BelongsToCurrentThread());
if (state_ != VIDEO_CAPTURE_STATE_STARTED || suspended_) {
Send(new VideoCaptureHostMsg_BufferReady(device_id_, buffer_id, 0));
return;
}
- last_frame_format_ = format;
if (first_frame_timestamp_.is_null())
first_frame_timestamp_ = timestamp;
@@ -232,18 +233,19 @@ void VideoCaptureImpl::OnBufferReceived(int buffer_id,
"timestamp", timestamp.ToInternalValue(),
"time_delta", (timestamp - first_frame_timestamp_).ToInternalValue());
- ClientBufferMap::iterator iter = client_buffers_.find(buffer_id);
+ const ClientBufferMap::const_iterator iter = client_buffers_.find(buffer_id);
DCHECK(iter != client_buffers_.end());
scoped_refptr<ClientBuffer> buffer = iter->second;
scoped_refptr<media::VideoFrame> frame =
media::VideoFrame::WrapExternalPackedMemory(
media::VideoFrame::I420,
- last_frame_format_.frame_size,
+ coded_size,
visible_rect,
gfx::Size(visible_rect.width(), visible_rect.height()),
reinterpret_cast<uint8*>(buffer->buffer->memory()),
buffer->buffer_size,
buffer->buffer->handle(),
+ 0,
timestamp - first_frame_timestamp_,
media::BindToCurrentLoop(
base::Bind(&VideoCaptureImpl::OnClientBufferFinished,
@@ -251,61 +253,53 @@ void VideoCaptureImpl::OnBufferReceived(int buffer_id,
buffer_id,
buffer,
0)));
+ frame->metadata()->MergeInternalValuesFrom(metadata);
- for (ClientInfoMap::iterator it = clients_.begin(); it != clients_.end();
- ++it) {
- it->second.deliver_frame_cb.Run(frame, format, timestamp);
- }
+ for (const auto& client : clients_)
+ client.second.deliver_frame_cb.Run(frame, timestamp);
}
-static void NullReadPixelsCB(const SkBitmap& bitmap) { NOTIMPLEMENTED(); }
-
void VideoCaptureImpl::OnMailboxBufferReceived(
int buffer_id,
const gpu::MailboxHolder& mailbox_holder,
- const media::VideoCaptureFormat& format,
- base::TimeTicks timestamp) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ const gfx::Size& packed_frame_size,
+ base::TimeTicks timestamp,
+ const base::DictionaryValue& metadata) {
+ DCHECK(io_message_loop_->BelongsToCurrentThread());
if (state_ != VIDEO_CAPTURE_STATE_STARTED || suspended_) {
Send(new VideoCaptureHostMsg_BufferReady(device_id_, buffer_id, 0));
return;
}
- last_frame_format_ = format;
if (first_frame_timestamp_.is_null())
first_frame_timestamp_ = timestamp;
scoped_refptr<media::VideoFrame> frame = media::VideoFrame::WrapNativeTexture(
- make_scoped_ptr(new gpu::MailboxHolder(mailbox_holder)),
- media::BindToCurrentLoop(
- base::Bind(&VideoCaptureImpl::OnClientBufferFinished,
- weak_factory_.GetWeakPtr(),
- buffer_id,
- scoped_refptr<ClientBuffer>())),
- last_frame_format_.frame_size,
- gfx::Rect(last_frame_format_.frame_size),
- last_frame_format_.frame_size,
- timestamp - first_frame_timestamp_,
- base::Bind(&NullReadPixelsCB));
-
- for (ClientInfoMap::iterator it = clients_.begin(); it != clients_.end();
- ++it) {
- it->second.deliver_frame_cb.Run(frame, format, timestamp);
- }
+ mailbox_holder,
+ media::BindToCurrentLoop(base::Bind(
+ &VideoCaptureImpl::OnClientBufferFinished, weak_factory_.GetWeakPtr(),
+ buffer_id, scoped_refptr<ClientBuffer>())),
+ packed_frame_size, gfx::Rect(packed_frame_size), packed_frame_size,
+ timestamp - first_frame_timestamp_, false /* allow_overlay */,
+ true /* has_alpha */);
+ frame->metadata()->MergeInternalValuesFrom(metadata);
+
+ for (const auto& client : clients_)
+ client.second.deliver_frame_cb.Run(frame, timestamp);
}
void VideoCaptureImpl::OnClientBufferFinished(
int buffer_id,
const scoped_refptr<ClientBuffer>& /* ignored_buffer */,
uint32 release_sync_point) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(io_message_loop_->BelongsToCurrentThread());
Send(new VideoCaptureHostMsg_BufferReady(
device_id_, buffer_id, release_sync_point));
}
void VideoCaptureImpl::OnStateChanged(VideoCaptureState state) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(io_message_loop_->BelongsToCurrentThread());
switch (state) {
case VIDEO_CAPTURE_STATE_STARTED:
@@ -321,26 +315,21 @@ void VideoCaptureImpl::OnStateChanged(VideoCaptureState state) {
RestartCapture();
break;
case VIDEO_CAPTURE_STATE_PAUSED:
- for (ClientInfoMap::iterator it = clients_.begin();
- it != clients_.end(); ++it) {
- it->second.state_update_cb.Run(VIDEO_CAPTURE_STATE_PAUSED);
- }
+ for (const auto& client : clients_)
+ client.second.state_update_cb.Run(VIDEO_CAPTURE_STATE_PAUSED);
break;
case VIDEO_CAPTURE_STATE_ERROR:
DVLOG(1) << "OnStateChanged: error!, device_id = " << device_id_;
- for (ClientInfoMap::iterator it = clients_.begin();
- it != clients_.end(); ++it) {
- it->second.state_update_cb.Run(VIDEO_CAPTURE_STATE_ERROR);
- }
+ for (const auto& client : clients_)
+ client.second.state_update_cb.Run(VIDEO_CAPTURE_STATE_ERROR);
clients_.clear();
state_ = VIDEO_CAPTURE_STATE_ERROR;
break;
case VIDEO_CAPTURE_STATE_ENDED:
DVLOG(1) << "OnStateChanged: ended!, device_id = " << device_id_;
- for (ClientInfoMap::iterator it = clients_.begin();
- it != clients_.end(); ++it) {
+ for (const auto& client : clients_) {
// We'll only notify the client that the stream has stopped.
- it->second.state_update_cb.Run(VIDEO_CAPTURE_STATE_STOPPED);
+ client.second.state_update_cb.Run(VIDEO_CAPTURE_STATE_STOPPED);
}
clients_.clear();
state_ = VIDEO_CAPTURE_STATE_ENDED;
@@ -352,7 +341,7 @@ void VideoCaptureImpl::OnStateChanged(VideoCaptureState state) {
void VideoCaptureImpl::OnDeviceSupportedFormatsEnumerated(
const media::VideoCaptureFormats& supported_formats) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(io_message_loop_->BelongsToCurrentThread());
for (size_t i = 0; i < device_formats_cb_queue_.size(); ++i)
device_formats_cb_queue_[i].Run(supported_formats);
device_formats_cb_queue_.clear();
@@ -360,33 +349,29 @@ void VideoCaptureImpl::OnDeviceSupportedFormatsEnumerated(
void VideoCaptureImpl::OnDeviceFormatsInUseReceived(
const media::VideoCaptureFormats& formats_in_use) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(io_message_loop_->BelongsToCurrentThread());
for (size_t i = 0; i < device_formats_in_use_cb_queue_.size(); ++i)
device_formats_in_use_cb_queue_[i].Run(formats_in_use);
device_formats_in_use_cb_queue_.clear();
}
void VideoCaptureImpl::OnDelegateAdded(int32 device_id) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(io_message_loop_->BelongsToCurrentThread());
DVLOG(1) << "OnDelegateAdded: device_id " << device_id;
device_id_ = device_id;
- for (ClientInfoMap::iterator it = clients_pending_on_filter_.begin();
- it != clients_pending_on_filter_.end(); ) {
- int client_id = it->first;
- VideoCaptureStateUpdateCB state_update_cb =
- it->second.state_update_cb;
- VideoCaptureDeliverFrameCB deliver_frame_cb =
- it->second.deliver_frame_cb;
- const media::VideoCaptureParams params = it->second.params;
+ ClientInfoMap::iterator it = clients_pending_on_filter_.begin();
+ while (it != clients_pending_on_filter_.end()) {
+ const int client_id = it->first;
+ const ClientInfo client_info = it->second;
clients_pending_on_filter_.erase(it++);
- StartCapture(client_id, params, state_update_cb,
- deliver_frame_cb);
+ StartCapture(client_id, client_info.params, client_info.state_update_cb,
+ client_info.deliver_frame_cb);
}
}
void VideoCaptureImpl::StopDevice() {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(io_message_loop_->BelongsToCurrentThread());
if (state_ == VIDEO_CAPTURE_STATE_STARTED) {
state_ = VIDEO_CAPTURE_STATE_STOPPING;
@@ -396,7 +381,7 @@ void VideoCaptureImpl::StopDevice() {
}
void VideoCaptureImpl::RestartCapture() {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(io_message_loop_->BelongsToCurrentThread());
DCHECK_EQ(state_, VIDEO_CAPTURE_STATE_STOPPED);
int width = 0;
@@ -404,12 +389,11 @@ void VideoCaptureImpl::RestartCapture() {
clients_.insert(clients_pending_on_restart_.begin(),
clients_pending_on_restart_.end());
clients_pending_on_restart_.clear();
- for (ClientInfoMap::iterator it = clients_.begin();
- it != clients_.end(); ++it) {
+ for (const auto& client : clients_) {
width = std::max(width,
- it->second.params.requested_format.frame_size.width());
- height = std::max(height,
- it->second.params.requested_format.frame_size.height());
+ client.second.params.requested_format.frame_size.width());
+ height = std::max(
+ height, client.second.params.requested_format.frame_size.height());
}
params_.requested_format.frame_size.SetSize(width, height);
DVLOG(1) << "RestartCapture, "
@@ -418,7 +402,7 @@ void VideoCaptureImpl::RestartCapture() {
}
void VideoCaptureImpl::StartCaptureInternal() {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(io_message_loop_->BelongsToCurrentThread());
DCHECK(device_id_);
Send(new VideoCaptureHostMsg_Start(device_id_, session_id_, params_));
@@ -426,15 +410,15 @@ void VideoCaptureImpl::StartCaptureInternal() {
}
void VideoCaptureImpl::Send(IPC::Message* message) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(io_message_loop_->BelongsToCurrentThread());
message_filter_->Send(message);
}
bool VideoCaptureImpl::RemoveClient(int client_id, ClientInfoMap* clients) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(io_message_loop_->BelongsToCurrentThread());
bool found = false;
- ClientInfoMap::iterator it = clients->find(client_id);
+ const ClientInfoMap::iterator it = clients->find(client_id);
if (it != clients->end()) {
it->second.state_update_cb.Run(VIDEO_CAPTURE_STATE_STOPPED);
clients->erase(it);
diff --git a/chromium/content/renderer/media/video_capture_impl.h b/chromium/content/renderer/media/video_capture_impl.h
index 4b39d549d02..38fc4fce3d3 100644
--- a/chromium/content/renderer/media/video_capture_impl.h
+++ b/chromium/content/renderer/media/video_capture_impl.h
@@ -2,21 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// VideoCaptureImpl represents a capture device in renderer process. It provides
-// interfaces for clients to Start/Stop capture. It also communicates to clients
-// when buffer is ready, state of capture device is changed.
-
-// VideoCaptureImpl is also a delegate of VideoCaptureMessageFilter which relays
-// operation of a capture device to the browser process and receives responses
-// from browser process.
-//
-// VideoCaptureImpl is an IO thread only object. See the comments in
-// video_capture_impl_manager.cc for the lifetime of this object.
-// All methods must be called on the IO thread.
-//
-// This is an internal class used by VideoCaptureImplManager only. Do not access
-// this directly.
-
#ifndef CONTENT_RENDERER_MEDIA_VIDEO_CAPTURE_IMPL_H_
#define CONTENT_RENDERER_MEDIA_VIDEO_CAPTURE_IMPL_H_
@@ -29,7 +14,7 @@
#include "content/common/media/video_capture.h"
#include "content/public/renderer/media_stream_video_sink.h"
#include "content/renderer/media/video_capture_message_filter.h"
-#include "media/video/capture/video_capture_types.h"
+#include "media/base/video_capture_types.h"
namespace base {
class MessageLoopProxy;
@@ -45,6 +30,20 @@ class VideoFrame;
namespace content {
+// VideoCaptureImpl represents a capture device in renderer process. It provides
+// interfaces for clients to Start/Stop capture. It also communicates to clients
+// when buffer is ready, state of capture device is changed.
+
+// VideoCaptureImpl is also a delegate of VideoCaptureMessageFilter which relays
+// operation of a capture device to the browser process and receives responses
+// from browser process.
+//
+// VideoCaptureImpl is an IO thread only object. See the comments in
+// video_capture_impl_manager.cc for the lifetime of this object.
+// All methods must be called on the IO thread.
+//
+// This is an internal class used by VideoCaptureImplManager only. Do not access
+// this directly.
class CONTENT_EXPORT VideoCaptureImpl
: public VideoCaptureMessageFilter::Delegate {
public:
@@ -67,24 +66,21 @@ class CONTENT_EXPORT VideoCaptureImpl
// used later to stop receiving video frames.
// |state_update_cb| will be called when state changes.
// |deliver_frame_cb| will be called when a frame is ready.
- void StartCapture(
- int client_id,
- const media::VideoCaptureParams& params,
- const VideoCaptureStateUpdateCB& state_update_cb,
- const VideoCaptureDeliverFrameCB& deliver_frame_cb);
+ void StartCapture(int client_id,
+ const media::VideoCaptureParams& params,
+ const VideoCaptureStateUpdateCB& state_update_cb,
+ const VideoCaptureDeliverFrameCB& deliver_frame_cb);
// Stop capturing. |client_id| is the identifier used to call StartCapture.
void StopCapture(int client_id);
// Get capturing formats supported by this device.
// |callback| will be invoked with the results.
- void GetDeviceSupportedFormats(
- const VideoCaptureDeviceFormatsCB& callback);
+ void GetDeviceSupportedFormats(const VideoCaptureDeviceFormatsCB& callback);
// Get capturing formats currently in use by this device.
// |callback| will be invoked with the results.
- void GetDeviceFormatsInUse(
- const VideoCaptureDeviceFormatsCB& callback);
+ void GetDeviceFormatsInUse(const VideoCaptureDeviceFormatsCB& callback);
media::VideoCaptureSessionId session_id() const { return session_id_; }
@@ -113,13 +109,15 @@ class CONTENT_EXPORT VideoCaptureImpl
int buffer_id) override;
void OnBufferDestroyed(int buffer_id) override;
void OnBufferReceived(int buffer_id,
- const media::VideoCaptureFormat& format,
+ const gfx::Size& coded_size,
const gfx::Rect& visible_rect,
- base::TimeTicks) override;
+ base::TimeTicks timestamp,
+ const base::DictionaryValue& metadata) override;
void OnMailboxBufferReceived(int buffer_id,
const gpu::MailboxHolder& mailbox_holder,
- const media::VideoCaptureFormat& format,
- base::TimeTicks timestamp) override;
+ const gfx::Size& packed_frame_size,
+ base::TimeTicks timestamp,
+ const base::DictionaryValue& metadata) override;
void OnStateChanged(VideoCaptureState state) override;
void OnDeviceSupportedFormatsEnumerated(
const media::VideoCaptureFormats& supported_formats) override;
@@ -165,17 +163,14 @@ class CONTENT_EXPORT VideoCaptureImpl
// client to this class via StartCapture().
media::VideoCaptureParams params_;
- // The device's video capture format sent from browser process side.
- media::VideoCaptureFormat last_frame_format_;
-
// The device's first captured frame timestamp sent from browser process side.
base::TimeTicks first_frame_timestamp_;
bool suspended_;
VideoCaptureState state_;
- // |weak_factory_| and |thread_checker_| are bound to the IO thread.
- base::ThreadChecker thread_checker_;
+ // IO message loop reference for checking correct class operation.
+ scoped_refptr<base::MessageLoopProxy> io_message_loop_;
// WeakPtrFactory pointing back to |this| object, for use with
// media::VideoFrames constructed in OnBufferReceived() from buffers cached
diff --git a/chromium/content/renderer/media/video_capture_impl_manager.cc b/chromium/content/renderer/media/video_capture_impl_manager.cc
index 686e6ad74c1..f72f3138e97 100644
--- a/chromium/content/renderer/media/video_capture_impl_manager.cc
+++ b/chromium/content/renderer/media/video_capture_impl_manager.cc
@@ -36,35 +36,33 @@ namespace content {
VideoCaptureImplManager::VideoCaptureImplManager()
: next_client_id_(0),
filter_(new VideoCaptureMessageFilter()),
+ render_main_message_loop_(base::MessageLoopProxy::current()),
weak_factory_(this) {
}
VideoCaptureImplManager::~VideoCaptureImplManager() {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(render_main_message_loop_->BelongsToCurrentThread());
if (devices_.empty())
return;
// Forcibly release all video capture resources.
- for (VideoCaptureDeviceMap::iterator it = devices_.begin();
- it != devices_.end(); ++it) {
- VideoCaptureImpl* impl = it->second.second;
+ for (const auto& device : devices_) {
+ VideoCaptureImpl* const impl = device.second.second;
ChildProcess::current()->io_message_loop_proxy()->PostTask(
FROM_HERE,
base::Bind(&VideoCaptureImpl::DeInit,
base::Unretained(impl)));
- ChildProcess::current()->io_message_loop_proxy()->PostTask(
- FROM_HERE,
- base::Bind(&base::DeletePointer<VideoCaptureImpl>,
- base::Unretained(impl)));
+ ChildProcess::current()->io_message_loop_proxy()->DeleteSoon(FROM_HERE,
+ impl);
}
devices_.clear();
}
base::Closure VideoCaptureImplManager::UseDevice(
media::VideoCaptureSessionId id) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(render_main_message_loop_->BelongsToCurrentThread());
VideoCaptureImpl* impl = NULL;
- VideoCaptureDeviceMap::iterator it = devices_.find(id);
+ const VideoCaptureDeviceMap::iterator it = devices_.find(id);
if (it == devices_.end()) {
impl = CreateVideoCaptureImplForTesting(id, filter_.get());
if (!impl)
@@ -86,10 +84,10 @@ base::Closure VideoCaptureImplManager::StartCapture(
const media::VideoCaptureParams& params,
const VideoCaptureStateUpdateCB& state_update_cb,
const VideoCaptureDeliverFrameCB& deliver_frame_cb) {
- DCHECK(thread_checker_.CalledOnValidThread());
- VideoCaptureDeviceMap::iterator it = devices_.find(id);
+ DCHECK(render_main_message_loop_->BelongsToCurrentThread());
+ const VideoCaptureDeviceMap::const_iterator it = devices_.find(id);
DCHECK(it != devices_.end());
- VideoCaptureImpl* impl = it->second.second;
+ VideoCaptureImpl* const impl = it->second.second;
// This ID is used to identify a client of VideoCaptureImpl.
const int client_id = ++next_client_id_;
@@ -110,10 +108,10 @@ base::Closure VideoCaptureImplManager::StartCapture(
void VideoCaptureImplManager::GetDeviceSupportedFormats(
media::VideoCaptureSessionId id,
const VideoCaptureDeviceFormatsCB& callback) {
- DCHECK(thread_checker_.CalledOnValidThread());
- VideoCaptureDeviceMap::iterator it = devices_.find(id);
+ DCHECK(render_main_message_loop_->BelongsToCurrentThread());
+ const VideoCaptureDeviceMap::const_iterator it = devices_.find(id);
DCHECK(it != devices_.end());
- VideoCaptureImpl* impl = it->second.second;
+ VideoCaptureImpl* const impl = it->second.second;
ChildProcess::current()->io_message_loop_proxy()->PostTask(
FROM_HERE,
base::Bind(&VideoCaptureImpl::GetDeviceSupportedFormats,
@@ -123,10 +121,10 @@ void VideoCaptureImplManager::GetDeviceSupportedFormats(
void VideoCaptureImplManager::GetDeviceFormatsInUse(
media::VideoCaptureSessionId id,
const VideoCaptureDeviceFormatsCB& callback) {
- DCHECK(thread_checker_.CalledOnValidThread());
- VideoCaptureDeviceMap::iterator it = devices_.find(id);
+ DCHECK(render_main_message_loop_->BelongsToCurrentThread());
+ const VideoCaptureDeviceMap::const_iterator it = devices_.find(id);
DCHECK(it != devices_.end());
- VideoCaptureImpl* impl = it->second.second;
+ VideoCaptureImpl* const impl = it->second.second;
ChildProcess::current()->io_message_loop_proxy()->PostTask(
FROM_HERE,
base::Bind(&VideoCaptureImpl::GetDeviceFormatsInUse,
@@ -140,12 +138,12 @@ VideoCaptureImplManager::CreateVideoCaptureImplForTesting(
return NULL;
}
-void VideoCaptureImplManager::StopCapture(
- int client_id, media::VideoCaptureSessionId id) {
- DCHECK(thread_checker_.CalledOnValidThread());
- VideoCaptureDeviceMap::iterator it = devices_.find(id);
+void VideoCaptureImplManager::StopCapture(int client_id,
+ media::VideoCaptureSessionId id) {
+ DCHECK(render_main_message_loop_->BelongsToCurrentThread());
+ const VideoCaptureDeviceMap::const_iterator it = devices_.find(id);
DCHECK(it != devices_.end());
- VideoCaptureImpl* impl = it->second.second;
+ VideoCaptureImpl* const impl = it->second.second;
ChildProcess::current()->io_message_loop_proxy()->PostTask(
FROM_HERE,
base::Bind(&VideoCaptureImpl::StopCapture,
@@ -154,10 +152,10 @@ void VideoCaptureImplManager::StopCapture(
void VideoCaptureImplManager::UnrefDevice(
media::VideoCaptureSessionId id) {
- DCHECK(thread_checker_.CalledOnValidThread());
- VideoCaptureDeviceMap::iterator it = devices_.find(id);
+ DCHECK(render_main_message_loop_->BelongsToCurrentThread());
+ const VideoCaptureDeviceMap::iterator it = devices_.find(id);
DCHECK(it != devices_.end());
- VideoCaptureImpl* impl = it->second.second;
+ VideoCaptureImpl* const impl = it->second.second;
// Unref and destroy on the IO thread if there's no more client.
DCHECK(it->second.first);
@@ -168,22 +166,18 @@ void VideoCaptureImplManager::UnrefDevice(
FROM_HERE,
base::Bind(&VideoCaptureImpl::DeInit,
base::Unretained(impl)));
- ChildProcess::current()->io_message_loop_proxy()->PostTask(
- FROM_HERE,
- base::Bind(&base::DeletePointer<VideoCaptureImpl>,
- base::Unretained(impl)));
+ ChildProcess::current()->io_message_loop_proxy()->DeleteSoon(FROM_HERE,
+ impl);
}
}
void VideoCaptureImplManager::SuspendDevices(bool suspend) {
- DCHECK(thread_checker_.CalledOnValidThread());
- for (VideoCaptureDeviceMap::iterator it = devices_.begin();
- it != devices_.end(); ++it) {
- VideoCaptureImpl* impl = it->second.second;
+ DCHECK(render_main_message_loop_->BelongsToCurrentThread());
+ for (const auto& device : devices_) {
+ VideoCaptureImpl* const impl = device.second.second;
ChildProcess::current()->io_message_loop_proxy()->PostTask(
- FROM_HERE,
- base::Bind(&VideoCaptureImpl::SuspendCapture,
- base::Unretained(impl), suspend));
+ FROM_HERE, base::Bind(&VideoCaptureImpl::SuspendCapture,
+ base::Unretained(impl), suspend));
}
}
diff --git a/chromium/content/renderer/media/video_capture_impl_manager.h b/chromium/content/renderer/media/video_capture_impl_manager.h
index 28b804c8743..4fce3c7af05 100644
--- a/chromium/content/renderer/media/video_capture_impl_manager.h
+++ b/chromium/content/renderer/media/video_capture_impl_manager.h
@@ -2,20 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// TODO(hclam): This class should be renamed to VideoCaptureService.
-
-// This class provides access to a video capture device in the browser
-// process through IPC. The main function is to deliver video frames
-// to a client.
-//
-// THREADING
-//
-// VideoCaptureImplManager lives only on the render thread. All methods
-// must be called on this thread.
-//
-// VideoFrames are delivered on the IO thread. Callbacks provided by
-// a client are also called on the IO thread.
-
#ifndef CONTENT_RENDERER_MEDIA_VIDEO_CAPTURE_IMPL_MANAGER_H_
#define CONTENT_RENDERER_MEDIA_VIDEO_CAPTURE_IMPL_MANAGER_H_
@@ -32,13 +18,26 @@
#include "content/common/content_export.h"
#include "content/common/media/video_capture.h"
#include "content/public/renderer/media_stream_video_sink.h"
-#include "media/video/capture/video_capture_types.h"
+#include "media/base/video_capture_types.h"
namespace content {
class VideoCaptureImpl;
class VideoCaptureMessageFilter;
+// TODO(hclam): This class should be renamed to VideoCaptureService.
+
+// This class provides access to a video capture device in the browser
+// process through IPC. The main function is to deliver video frames
+// to a client.
+//
+// THREADING
+//
+// VideoCaptureImplManager lives only on the Render Main thread. All methods
+// must be called on this thread.
+//
+// VideoFrames are delivered on the IO thread. Callbacks provided by
+// a client are also called on the IO thread.
class CONTENT_EXPORT VideoCaptureImplManager {
public:
VideoCaptureImplManager();
@@ -76,15 +75,13 @@ class CONTENT_EXPORT VideoCaptureImplManager {
// Get supported formats supported by the device for the given session
// ID. |callback| will be called on the IO thread.
- void GetDeviceSupportedFormats(
- media::VideoCaptureSessionId id,
- const VideoCaptureDeviceFormatsCB& callback);
+ void GetDeviceSupportedFormats(media::VideoCaptureSessionId id,
+ const VideoCaptureDeviceFormatsCB& callback);
// Get supported formats currently in use for the given session ID.
// |callback| will be called on the IO thread.
- void GetDeviceFormatsInUse(
- media::VideoCaptureSessionId id,
- const VideoCaptureDeviceFormatsCB& callback);
+ void GetDeviceFormatsInUse(media::VideoCaptureSessionId id,
+ const VideoCaptureDeviceFormatsCB& callback);
// Make all existing VideoCaptureImpl instances stop/resume delivering
// video frames to their clients, depends on flag |suspend|.
@@ -116,10 +113,11 @@ class CONTENT_EXPORT VideoCaptureImplManager {
// The ID is global for the render process.
int next_client_id_;
- scoped_refptr<VideoCaptureMessageFilter> filter_;
+ const scoped_refptr<VideoCaptureMessageFilter> filter_;
- // Bound to the render thread.
- base::ThreadChecker thread_checker_;
+ // Hold a pointer to the Render Main message loop to check we operate on the
+ // right thread.
+ const scoped_refptr<base::MessageLoopProxy> render_main_message_loop_;
// Bound to the render thread.
// NOTE: Weak pointers must be invalidated before all other member variables.
diff --git a/chromium/content/renderer/media/video_capture_impl_manager_unittest.cc b/chromium/content/renderer/media/video_capture_impl_manager_unittest.cc
index a688c12b57b..39c9e8e4fae 100644
--- a/chromium/content/renderer/media/video_capture_impl_manager_unittest.cc
+++ b/chromium/content/renderer/media/video_capture_impl_manager_unittest.cc
@@ -91,9 +91,8 @@ class VideoCaptureImplManagerTest : public ::testing::Test {
}
protected:
- MOCK_METHOD3(OnFrameReady,
+ MOCK_METHOD2(OnFrameReady,
void(const scoped_refptr<media::VideoFrame>&,
- const media::VideoCaptureFormat&,
const base::TimeTicks& estimated_capture_time));
MOCK_METHOD0(OnStarted, void());
MOCK_METHOD0(OnStopped, void());
@@ -138,10 +137,8 @@ TEST_F(VideoCaptureImplManagerTest, MultipleClients) {
base::Closure stop_cb1, stop_cb2;
{
base::RunLoop run_loop;
- base::Closure quit_closure = BindToCurrentLoop(
- run_loop.QuitClosure());
- EXPECT_CALL(*this, OnStarted()).WillOnce(
- RunClosure(quit_closure));
+ base::Closure quit_closure = BindToCurrentLoop(run_loop.QuitClosure());
+ EXPECT_CALL(*this, OnStarted()).WillOnce(RunClosure(quit_closure));
EXPECT_CALL(*this, OnStarted()).RetiresOnSaturation();
stop_cb1 = StartCapture(params_);
stop_cb2 = StartCapture(params_);
@@ -151,10 +148,8 @@ TEST_F(VideoCaptureImplManagerTest, MultipleClients) {
{
base::RunLoop run_loop;
- base::Closure quit_closure = BindToCurrentLoop(
- run_loop.QuitClosure());
- EXPECT_CALL(*this, OnStopped()).WillOnce(
- RunClosure(quit_closure));
+ base::Closure quit_closure = BindToCurrentLoop(run_loop.QuitClosure());
+ EXPECT_CALL(*this, OnStopped()).WillOnce(RunClosure(quit_closure));
EXPECT_CALL(*this, OnStopped()).RetiresOnSaturation();
stop_cb1.Run();
stop_cb2.Run();
diff --git a/chromium/content/renderer/media/video_capture_impl_unittest.cc b/chromium/content/renderer/media/video_capture_impl_unittest.cc
index 8c75e47663a..282cc3e3b63 100644
--- a/chromium/content/renderer/media/video_capture_impl_unittest.cc
+++ b/chromium/content/renderer/media/video_capture_impl_unittest.cc
@@ -129,9 +129,8 @@ class VideoCaptureImplTest : public ::testing::Test {
}
protected:
- MOCK_METHOD3(OnFrameReady,
+ MOCK_METHOD2(OnFrameReady,
void(const scoped_refptr<media::VideoFrame>&,
- const media::VideoCaptureFormat&,
const base::TimeTicks&));
MOCK_METHOD1(OnStateUpdate, void(VideoCaptureState));
MOCK_METHOD1(OnDeviceFormatsInUse,
diff --git a/chromium/content/renderer/media/video_capture_message_filter.cc b/chromium/content/renderer/media/video_capture_message_filter.cc
index 7157407fff2..80fd570a6a8 100644
--- a/chromium/content/renderer/media/video_capture_message_filter.cc
+++ b/chromium/content/renderer/media/video_capture_message_filter.cc
@@ -77,10 +77,9 @@ void VideoCaptureMessageFilter::OnFilterAdded(IPC::Sender* sender) {
DVLOG(1) << "VideoCaptureMessageFilter::OnFilterAdded()";
sender_ = sender;
- for (Delegates::iterator it = pending_delegates_.begin();
- it != pending_delegates_.end(); it++) {
- it->second->OnDelegateAdded(it->first);
- delegates_[it->first] = it->second;
+ for (const auto& pending_delegate : pending_delegates_) {
+ pending_delegate.second->OnDelegateAdded(pending_delegate.first);
+ delegates_[pending_delegate.first] = pending_delegate.second;
}
pending_delegates_.clear();
}
@@ -122,32 +121,29 @@ void VideoCaptureMessageFilter::OnBufferCreated(
}
void VideoCaptureMessageFilter::OnBufferReceived(
- int device_id,
- int buffer_id,
- const media::VideoCaptureFormat& format,
- const gfx::Rect& visible_rect,
- base::TimeTicks timestamp) {
- Delegate* delegate = find_delegate(device_id);
+ const VideoCaptureMsg_BufferReady_Params& params) {
+ Delegate* delegate = find_delegate(params.device_id);
if (!delegate) {
DLOG(WARNING) << "OnBufferReceived: Got video SHM buffer for a "
"non-existent or removed video capture.";
// Send the buffer back to Host in case it's waiting for all buffers
// to be returned.
- Send(new VideoCaptureHostMsg_BufferReady(device_id, buffer_id, 0));
+ Send(new VideoCaptureHostMsg_BufferReady(
+ params.device_id, params.buffer_id, 0));
return;
}
- delegate->OnBufferReceived(buffer_id, format, visible_rect, timestamp);
+ delegate->OnBufferReceived(params.buffer_id,
+ params.coded_size,
+ params.visible_rect,
+ params.timestamp,
+ params.metadata);
}
void VideoCaptureMessageFilter::OnMailboxBufferReceived(
- int device_id,
- int buffer_id,
- const gpu::MailboxHolder& mailbox_holder,
- const media::VideoCaptureFormat& format,
- base::TimeTicks timestamp) {
- Delegate* delegate = find_delegate(device_id);
+ const VideoCaptureMsg_MailboxBufferReady_Params& params) {
+ Delegate* delegate = find_delegate(params.device_id);
if (!delegate) {
DLOG(WARNING) << "OnMailboxBufferReceived: Got video mailbox buffer for a "
@@ -155,12 +151,17 @@ void VideoCaptureMessageFilter::OnMailboxBufferReceived(
// Send the buffer back to Host in case it's waiting for all buffers
// to be returned.
- Send(new VideoCaptureHostMsg_BufferReady(device_id, buffer_id, 0));
+ Send(new VideoCaptureHostMsg_BufferReady(
+ params.device_id, params.buffer_id, 0));
return;
}
delegate->OnMailboxBufferReceived(
- buffer_id, mailbox_holder, format, timestamp);
+ params.buffer_id,
+ params.mailbox_holder,
+ params.packed_frame_size,
+ params.timestamp,
+ params.metadata);
}
void VideoCaptureMessageFilter::OnBufferDestroyed(
diff --git a/chromium/content/renderer/media/video_capture_message_filter.h b/chromium/content/renderer/media/video_capture_message_filter.h
index c55d17f59ea..31712373fd7 100644
--- a/chromium/content/renderer/media/video_capture_message_filter.h
+++ b/chromium/content/renderer/media/video_capture_message_filter.h
@@ -13,10 +13,14 @@
#include <map>
#include "base/memory/shared_memory.h"
+#include "base/values.h"
#include "content/common/content_export.h"
#include "content/common/media/video_capture.h"
#include "ipc/message_filter.h"
-#include "media/video/capture/video_capture_types.h"
+#include "media/base/video_capture_types.h"
+
+struct VideoCaptureMsg_BufferReady_Params;
+struct VideoCaptureMsg_MailboxBufferReady_Params;
namespace gpu {
struct MailboxHolder;
@@ -36,17 +40,20 @@ class CONTENT_EXPORT VideoCaptureMessageFilter : public IPC::MessageFilter {
virtual void OnBufferDestroyed(int buffer_id) = 0;
// Called when a video frame buffer is received from the browser process.
- virtual void OnBufferReceived(int buffer_id,
- const media::VideoCaptureFormat& format,
- const gfx::Rect& visible_rect,
- base::TimeTicks timestamp) = 0;
+ virtual void OnBufferReceived(
+ int buffer_id,
+ const gfx::Size& coded_size,
+ const gfx::Rect& visible_rect,
+ base::TimeTicks timestamp,
+ const base::DictionaryValue& metadata) = 0;
// Called when a video mailbox buffer is received from the browser process.
virtual void OnMailboxBufferReceived(
int buffer_id,
const gpu::MailboxHolder& mailbox_holder,
- const media::VideoCaptureFormat& format,
- base::TimeTicks timestamp) = 0;
+ const gfx::Size& packed_frame_size,
+ base::TimeTicks timestamp,
+ const base::DictionaryValue& metadata) = 0;
// Called when state of a video capture device has changed in the browser
// process.
@@ -102,18 +109,11 @@ class CONTENT_EXPORT VideoCaptureMessageFilter : public IPC::MessageFilter {
int buffer_id);
// Receive a filled buffer from browser process.
- void OnBufferReceived(int device_id,
- int buffer_id,
- const media::VideoCaptureFormat& format,
- const gfx::Rect& visible_rect,
- base::TimeTicks timestamp);
+ void OnBufferReceived(const VideoCaptureMsg_BufferReady_Params& params);
// Receive a filled texture mailbox buffer from browser process.
- void OnMailboxBufferReceived(int device_id,
- int buffer_id,
- const gpu::MailboxHolder& mailbox_holder,
- const media::VideoCaptureFormat& format,
- base::TimeTicks timestamp);
+ void OnMailboxBufferReceived(
+ const VideoCaptureMsg_MailboxBufferReady_Params& params);
// State of browser process' video capture device has changed.
void OnDeviceStateChanged(int device_id, VideoCaptureState state);
diff --git a/chromium/content/renderer/media/video_capture_message_filter_unittest.cc b/chromium/content/renderer/media/video_capture_message_filter_unittest.cc
index 4633585164c..e2660b9259c 100644
--- a/chromium/content/renderer/media/video_capture_message_filter_unittest.cc
+++ b/chromium/content/renderer/media/video_capture_message_filter_unittest.cc
@@ -6,16 +6,19 @@
#include "content/common/media/video_capture_messages.h"
#include "content/renderer/media/video_capture_message_filter.h"
#include "ipc/ipc_test_sink.h"
-#include "media/video/capture/video_capture_types.h"
+#include "media/base/video_capture_types.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::_;
using ::testing::AnyNumber;
+using ::testing::DoAll;
+using ::testing::Invoke;
using ::testing::Mock;
using ::testing::Return;
using ::testing::SaveArg;
using ::testing::StrictMock;
+using ::testing::WithArg;
namespace content {
namespace {
@@ -29,23 +32,25 @@ class MockVideoCaptureDelegate : public VideoCaptureMessageFilter::Delegate {
int length,
int buffer_id));
MOCK_METHOD1(OnBufferDestroyed, void(int buffer_id));
- MOCK_METHOD4(OnBufferReceived,
+ MOCK_METHOD5(OnBufferReceived,
void(int buffer_id,
- const media::VideoCaptureFormat& format,
+ const gfx::Size& coded_size,
const gfx::Rect& visible_rect,
- base::TimeTicks timestamp));
- MOCK_METHOD4(OnMailboxBufferReceived,
+ base::TimeTicks timestamp,
+ const base::DictionaryValue& metadata));
+ MOCK_METHOD5(OnMailboxBufferReceived,
void(int buffer_id,
const gpu::MailboxHolder& mailbox_holder,
- const media::VideoCaptureFormat& format,
- base::TimeTicks timestamp));
+ const gfx::Size& packed_frame_size,
+ base::TimeTicks timestamp,
+ const base::DictionaryValue& metadata));
MOCK_METHOD1(OnStateChanged, void(VideoCaptureState state));
MOCK_METHOD1(OnDeviceSupportedFormatsEnumerated,
void(const media::VideoCaptureFormats& formats));
MOCK_METHOD1(OnDeviceFormatsInUseReceived,
void(const media::VideoCaptureFormats& formats_in_use));
- virtual void OnDelegateAdded(int32 device_id) override {
+ void OnDelegateAdded(int32 device_id) override {
ASSERT_TRUE(device_id != 0);
ASSERT_TRUE(device_id_ == 0);
device_id_ = device_id;
@@ -57,6 +62,16 @@ class MockVideoCaptureDelegate : public VideoCaptureMessageFilter::Delegate {
int device_id_;
};
+void ExpectMetadataContainsFooBarBaz(const base::DictionaryValue& metadata) {
+ std::string value;
+ if (metadata.GetString("foo", &value))
+ EXPECT_EQ(std::string("bar"), value);
+ else if (metadata.GetString("bar", &value))
+ EXPECT_EQ(std::string("baz"), value);
+ else
+ FAIL() << "Missing key 'foo' or key 'bar'.";
+}
+
} // namespace
TEST(VideoCaptureMessageFilterTest, Basic) {
@@ -89,56 +104,55 @@ TEST(VideoCaptureMessageFilterTest, Basic) {
Mock::VerifyAndClearExpectations(&delegate);
// VideoCaptureMsg_BufferReady
- int buffer_id = 22;
- base::TimeTicks timestamp = base::TimeTicks::FromInternalValue(1);
-
- const media::VideoCaptureFormat shm_format(
- gfx::Size(234, 512), 30, media::PIXEL_FORMAT_I420);
- media::VideoCaptureFormat saved_format;
- EXPECT_CALL(delegate, OnBufferReceived(buffer_id, _, _, timestamp))
- .WillRepeatedly(SaveArg<1>(&saved_format));
- filter->OnMessageReceived(VideoCaptureMsg_BufferReady(
- delegate.device_id(), buffer_id, shm_format, gfx::Rect(234, 512),
- timestamp));
+ VideoCaptureMsg_BufferReady_Params params;
+ params.device_id = delegate.device_id();
+ params.buffer_id = 22;
+ params.coded_size = gfx::Size(234, 512);
+ params.visible_rect = gfx::Rect(100, 200, 300, 400);
+ params.timestamp = base::TimeTicks::FromInternalValue(1);
+ params.metadata.SetString("foo", "bar");
+
+ EXPECT_CALL(delegate, OnBufferReceived(params.buffer_id,
+ params.coded_size,
+ params.visible_rect,
+ params.timestamp,
+ _))
+ .WillRepeatedly(WithArg<4>(Invoke(&ExpectMetadataContainsFooBarBaz)));
+ filter->OnMessageReceived(VideoCaptureMsg_BufferReady(params));
Mock::VerifyAndClearExpectations(&delegate);
- EXPECT_EQ(shm_format.frame_size, saved_format.frame_size);
- EXPECT_EQ(shm_format.frame_rate, saved_format.frame_rate);
- EXPECT_EQ(shm_format.pixel_format, saved_format.pixel_format);
// VideoCaptureMsg_MailboxBufferReady
- buffer_id = 33;
- timestamp = base::TimeTicks::FromInternalValue(2);
-
- const media::VideoCaptureFormat mailbox_format(
- gfx::Size(234, 512), 30, media::PIXEL_FORMAT_TEXTURE);
+ VideoCaptureMsg_MailboxBufferReady_Params params_m;
+ params_m.device_id = delegate.device_id();
+ params_m.buffer_id = 33;
gpu::Mailbox mailbox;
const int8 mailbox_name[arraysize(mailbox.name)] = "TEST MAILBOX";
mailbox.SetName(mailbox_name);
- unsigned int syncpoint = 44;
+ params_m.mailbox_holder = gpu::MailboxHolder(mailbox, 0, 44);
+ params_m.packed_frame_size = gfx::Size(345, 256);
+ params_m.timestamp = base::TimeTicks::FromInternalValue(2);
+ params_m.metadata.SetString("bar", "baz");
+
gpu::MailboxHolder saved_mailbox_holder;
- EXPECT_CALL(delegate, OnMailboxBufferReceived(buffer_id, _, _, timestamp))
- .WillRepeatedly(
- DoAll(SaveArg<1>(&saved_mailbox_holder), SaveArg<2>(&saved_format)));
- gpu::MailboxHolder mailbox_holder(mailbox, 0, syncpoint);
- filter->OnMessageReceived(
- VideoCaptureMsg_MailboxBufferReady(delegate.device_id(),
- buffer_id,
- mailbox_holder,
- mailbox_format,
- timestamp));
+ EXPECT_CALL(delegate, OnMailboxBufferReceived(params_m.buffer_id,
+ _,
+ params_m.packed_frame_size,
+ params_m.timestamp,
+ _))
+ .WillRepeatedly(DoAll(
+ SaveArg<1>(&saved_mailbox_holder),
+ WithArg<4>(Invoke(&ExpectMetadataContainsFooBarBaz))));
+ filter->OnMessageReceived(VideoCaptureMsg_MailboxBufferReady(params_m));
Mock::VerifyAndClearExpectations(&delegate);
- EXPECT_EQ(mailbox_format.frame_size, saved_format.frame_size);
- EXPECT_EQ(mailbox_format.frame_rate, saved_format.frame_rate);
- EXPECT_EQ(mailbox_format.pixel_format, saved_format.pixel_format);
EXPECT_EQ(memcmp(mailbox.name,
saved_mailbox_holder.mailbox.name,
sizeof(mailbox.name)),
0);
// VideoCaptureMsg_FreeBuffer
- EXPECT_CALL(delegate, OnBufferDestroyed(buffer_id));
+ EXPECT_CALL(delegate, OnBufferDestroyed(params_m.buffer_id));
filter->OnMessageReceived(VideoCaptureMsg_FreeBuffer(
- delegate.device_id(), buffer_id));
+ delegate.device_id(), params_m.buffer_id));
Mock::VerifyAndClearExpectations(&delegate);
}
diff --git a/chromium/content/renderer/media/video_source_handler.cc b/chromium/content/renderer/media/video_source_handler.cc
index b3d8238f2e3..13af886fe9b 100644
--- a/chromium/content/renderer/media/video_source_handler.cc
+++ b/chromium/content/renderer/media/video_source_handler.cc
@@ -6,15 +6,15 @@
#include <string>
-#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/memory/weak_ptr.h"
#include "base/synchronization/lock.h"
+#include "base/trace_event/trace_event.h"
#include "content/public/renderer/media_stream_video_sink.h"
#include "content/renderer/media/media_stream.h"
#include "content/renderer/media/media_stream_registry_interface.h"
#include "media/base/bind_to_current_loop.h"
-#include "media/video/capture/video_capture_types.h"
+#include "media/base/video_capture_types.h"
#include "third_party/WebKit/public/platform/WebMediaStream.h"
#include "third_party/WebKit/public/platform/WebURL.h"
#include "third_party/WebKit/public/web/WebMediaStreamRegistry.h"
@@ -53,10 +53,8 @@ class PpFrameReceiver : public MediaStreamVideoSink {
reader_ = reader;
}
- void OnVideoFrame(
- const scoped_refptr<media::VideoFrame>& frame,
- const media::VideoCaptureFormat& format,
- const base::TimeTicks& estimated_capture_time) {
+ void OnVideoFrame(const scoped_refptr<media::VideoFrame>& frame,
+ const base::TimeTicks& estimated_capture_time) {
TRACE_EVENT0("video", "PpFrameReceiver::OnVideoFrame");
if (reader_) {
reader_->GotFrame(frame);
@@ -141,8 +139,7 @@ void VideoSourceHandler::DeliverFrameForTesting(
return;
}
PpFrameReceiver* receiver = it->second->receiver_.get();
- receiver->OnVideoFrame(frame, media::VideoCaptureFormat(),
- base::TimeTicks());
+ receiver->OnVideoFrame(frame, base::TimeTicks());
}
VideoSourceHandler::SourceInfo::SourceInfo(
diff --git a/chromium/content/renderer/media/video_track_adapter.cc b/chromium/content/renderer/media/video_track_adapter.cc
index ada3502173e..453e10c6ede 100644
--- a/chromium/content/renderer/media/video_track_adapter.cc
+++ b/chromium/content/renderer/media/video_track_adapter.cc
@@ -9,9 +9,12 @@
#include <utility>
#include "base/bind.h"
-#include "base/debug/trace_event.h"
+#include "base/command_line.h"
#include "base/location.h"
#include "base/metrics/histogram.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/trace_event/trace_event.h"
+#include "content/public/common/content_switches.h"
#include "media/base/bind_to_current_loop.h"
#include "media/base/video_util.h"
@@ -27,13 +30,15 @@ const float kNormalFrameTimeoutInFrameIntervals = 25.0f;
// Min delta time between two frames allowed without being dropped if a max
// frame rate is specified.
-const int kMinTimeInMsBetweenFrames = 5;
+const double kMinTimeInMsBetweenFrames = 5;
+// If the delta between two frames is bigger than this, we will consider it to
+// be invalid and reset the fps calculation.
+const double kMaxTimeInMsBetweenFrames = 1000;
// Empty method used for keeping a reference to the original media::VideoFrame
// in VideoFrameResolutionAdapter::DeliverFrame if cropping is needed.
// The reference to |frame| is kept in the closure that calls this method.
-void ReleaseOriginalFrame(
- const scoped_refptr<media::VideoFrame>& frame) {
+void ReleaseOriginalFrame(const scoped_refptr<media::VideoFrame>& frame) {
}
void ResetCallbackOnMainRenderThread(
@@ -43,13 +48,14 @@ void ResetCallbackOnMainRenderThread(
} // anonymous namespace
-// VideoFrameResolutionAdapter is created on and lives on
-// on the IO-thread. It does the resolution adaptation and delivers frames to
-// all registered tracks on the IO-thread.
-// All method calls must be on the IO-thread.
+// VideoFrameResolutionAdapter is created on and lives on the IO-thread. It does
+// the resolution adaptation and delivers frames to all registered tracks on the
+// IO-thread. All method calls must be on the IO-thread.
class VideoTrackAdapter::VideoFrameResolutionAdapter
: public base::RefCountedThreadSafe<VideoFrameResolutionAdapter> {
public:
+ // Setting |max_frame_rate| to 0.0, means that no frame rate limitation
+ // will be done.
VideoFrameResolutionAdapter(
scoped_refptr<base::SingleThreadTaskRunner> render_message_loop,
const gfx::Size& max_size,
@@ -68,7 +74,6 @@ class VideoTrackAdapter::VideoFrameResolutionAdapter
void RemoveCallback(const MediaStreamVideoTrack* track);
void DeliverFrame(const scoped_refptr<media::VideoFrame>& frame,
- const media::VideoCaptureFormat& format,
const base::TimeTicks& estimated_capture_time);
// Returns true if all arguments match with the output of this adapter.
@@ -83,10 +88,8 @@ class VideoTrackAdapter::VideoFrameResolutionAdapter
virtual ~VideoFrameResolutionAdapter();
friend class base::RefCountedThreadSafe<VideoFrameResolutionAdapter>;
- virtual void DoDeliverFrame(
- const scoped_refptr<media::VideoFrame>& frame,
- const media::VideoCaptureFormat& format,
- const base::TimeTicks& estimated_capture_time);
+ void DoDeliverFrame(const scoped_refptr<media::VideoFrame>& frame,
+ const base::TimeTicks& estimated_capture_time);
// Returns |true| if the input frame rate is higher that the requested max
// frame rate and |frame| should be dropped.
@@ -98,18 +101,18 @@ class VideoTrackAdapter::VideoFrameResolutionAdapter
// The task runner where we will release VideoCaptureDeliverFrameCB
// registered in AddCallback.
- scoped_refptr<base::SingleThreadTaskRunner> renderer_task_runner_;
+ const scoped_refptr<base::SingleThreadTaskRunner> renderer_task_runner_;
- gfx::Size max_frame_size_;
- double min_aspect_ratio_;
- double max_aspect_ratio_;
+ const gfx::Size max_frame_size_;
+ const double min_aspect_ratio_;
+ const double max_aspect_ratio_;
double frame_rate_;
base::TimeDelta last_time_stamp_;
double max_frame_rate_;
double keep_frame_counter_;
- typedef std::pair<const void*, VideoCaptureDeliverFrameCB>
+ typedef std::pair<const MediaStreamVideoTrack*, VideoCaptureDeliverFrameCB>
VideoIdCallbackPair;
std::vector<VideoIdCallbackPair> callbacks_;
@@ -128,12 +131,28 @@ VideoFrameResolutionAdapter::VideoFrameResolutionAdapter(
min_aspect_ratio_(min_aspect_ratio),
max_aspect_ratio_(max_aspect_ratio),
frame_rate_(MediaStreamVideoSource::kDefaultFrameRate),
+ last_time_stamp_(base::TimeDelta::Max()),
max_frame_rate_(max_frame_rate),
- keep_frame_counter_(0.0f) {
+ keep_frame_counter_(0.0) {
DCHECK(renderer_task_runner_.get());
DCHECK(io_thread_checker_.CalledOnValidThread());
DCHECK_GE(max_aspect_ratio_, min_aspect_ratio_);
CHECK_NE(0, max_aspect_ratio_);
+
+ const std::string max_fps_str =
+ base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kWebRtcMaxCaptureFramerate);
+ if (!max_fps_str.empty()) {
+ double value;
+ if (base::StringToDouble(max_fps_str, &value) && value >= 0.0) {
+ DVLOG(1) << "Overriding max frame rate. Was=" << max_frame_rate
+ << ", Now=" << value;
+ max_frame_rate_ = value;
+ } else {
+ DLOG(ERROR) << "Unable to set max fps to " << max_fps_str;
+ }
+ }
+
DVLOG(3) << "VideoFrameResolutionAdapter("
<< "{ max_width =" << max_frame_size_.width() << "}, "
<< "{ max_height =" << max_frame_size_.height() << "}, "
@@ -148,19 +167,52 @@ VideoFrameResolutionAdapter::~VideoFrameResolutionAdapter() {
DCHECK(callbacks_.empty());
}
+void VideoTrackAdapter::VideoFrameResolutionAdapter::AddCallback(
+ const MediaStreamVideoTrack* track,
+ const VideoCaptureDeliverFrameCB& callback) {
+ DCHECK(io_thread_checker_.CalledOnValidThread());
+ callbacks_.push_back(std::make_pair(track, callback));
+}
+
+void VideoTrackAdapter::VideoFrameResolutionAdapter::RemoveCallback(
+ const MediaStreamVideoTrack* track) {
+ DCHECK(io_thread_checker_.CalledOnValidThread());
+ std::vector<VideoIdCallbackPair>::iterator it = callbacks_.begin();
+ for (; it != callbacks_.end(); ++it) {
+ if (it->first == track) {
+ // Make sure the VideoCaptureDeliverFrameCB is released on the main
+ // render thread since it was added on the main render thread in
+ // VideoTrackAdapter::AddTrack.
+ scoped_ptr<VideoCaptureDeliverFrameCB> callback(
+ new VideoCaptureDeliverFrameCB(it->second));
+ callbacks_.erase(it);
+ renderer_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&ResetCallbackOnMainRenderThread,
+ base::Passed(&callback)));
+
+ return;
+ }
+ }
+}
+
void VideoTrackAdapter::VideoFrameResolutionAdapter::DeliverFrame(
const scoped_refptr<media::VideoFrame>& frame,
- const media::VideoCaptureFormat& format,
const base::TimeTicks& estimated_capture_time) {
DCHECK(io_thread_checker_.CalledOnValidThread());
- if (MaybeDropFrame(frame, format.frame_rate))
+ double frame_rate;
+ if (!frame->metadata()->GetDouble(media::VideoFrameMetadata::FRAME_RATE,
+ &frame_rate)) {
+ frame_rate = MediaStreamVideoSource::kUnknownFrameRate;
+ }
+
+ if (MaybeDropFrame(frame, frame_rate))
return;
// TODO(perkj): Allow cropping / scaling of textures once
// http://crbug/362521 is fixed.
if (frame->format() == media::VideoFrame::NATIVE_TEXTURE) {
- DoDeliverFrame(frame, format, estimated_capture_time);
+ DoDeliverFrame(frame, estimated_capture_time);
return;
}
scoped_refptr<media::VideoFrame> video_frame(frame);
@@ -180,14 +232,11 @@ void VideoTrackAdapter::VideoFrameResolutionAdapter::DeliverFrame(
int desired_height = std::min(max_frame_size_.height(),
frame->natural_size().height());
- double resulting_ratio =
+ const double resulting_ratio =
static_cast<double>(desired_width) / desired_height;
- double requested_ratio = resulting_ratio;
-
- if (requested_ratio > max_aspect_ratio_)
- requested_ratio = max_aspect_ratio_;
- else if (requested_ratio < min_aspect_ratio_)
- requested_ratio = min_aspect_ratio_;
+ // Make sure |min_aspect_ratio_| < |requested_ratio| < |max_aspect_ratio_|.
+ const double requested_ratio = std::max(
+ std::min(resulting_ratio, max_aspect_ratio_), min_aspect_ratio_);
if (resulting_ratio < requested_ratio) {
desired_height = static_cast<int>((desired_height * resulting_ratio) /
@@ -201,13 +250,13 @@ void VideoTrackAdapter::VideoFrameResolutionAdapter::DeliverFrame(
desired_width = (desired_width + 1) & ~1;
}
- gfx::Size desired_size(desired_width, desired_height);
+ const gfx::Size desired_size(desired_width, desired_height);
// Get the largest centered rectangle with the same aspect ratio of
// |desired_size| that fits entirely inside of |frame->visible_rect()|.
// This will be the rect we need to crop the original frame to.
// From this rect, the original frame can be scaled down to |desired_size|.
- gfx::Rect region_in_frame =
+ const gfx::Rect region_in_frame =
media::ComputeLetterboxRegion(frame->visible_rect(), desired_size);
video_frame = media::VideoFrame::WrapVideoFrame(
@@ -222,7 +271,32 @@ void VideoTrackAdapter::VideoFrameResolutionAdapter::DeliverFrame(
<< " output visible rect "
<< video_frame->visible_rect().ToString();
}
- DoDeliverFrame(video_frame, format, estimated_capture_time);
+ DoDeliverFrame(video_frame, estimated_capture_time);
+}
+
+bool VideoTrackAdapter::VideoFrameResolutionAdapter::ConstraintsMatch(
+ const gfx::Size& max_size,
+ double min_aspect_ratio,
+ double max_aspect_ratio,
+ double max_frame_rate) const {
+ DCHECK(io_thread_checker_.CalledOnValidThread());
+ return max_frame_size_ == max_size &&
+ min_aspect_ratio_ == min_aspect_ratio &&
+ max_aspect_ratio_ == max_aspect_ratio &&
+ max_frame_rate_ == max_frame_rate;
+}
+
+bool VideoTrackAdapter::VideoFrameResolutionAdapter::IsEmpty() const {
+ DCHECK(io_thread_checker_.CalledOnValidThread());
+ return callbacks_.empty();
+}
+
+void VideoTrackAdapter::VideoFrameResolutionAdapter::DoDeliverFrame(
+ const scoped_refptr<media::VideoFrame>& frame,
+ const base::TimeTicks& estimated_capture_time) {
+ DCHECK(io_thread_checker_.CalledOnValidThread());
+ for (const auto& callback : callbacks_)
+ callback.second.Run(frame, estimated_capture_time);
}
bool VideoTrackAdapter::VideoFrameResolutionAdapter::MaybeDropFrame(
@@ -233,13 +307,23 @@ bool VideoTrackAdapter::VideoFrameResolutionAdapter::MaybeDropFrame(
// Do not drop frames if max frame rate hasn't been specified or the source
// frame rate is known and is lower than max.
if (max_frame_rate_ == 0.0f ||
- (source_frame_rate > 0 &&
- source_frame_rate <= max_frame_rate_)) {
+ (source_frame_rate > 0 && source_frame_rate <= max_frame_rate_)) {
+ return false;
+ }
+
+ const double delta_ms =
+ (frame->timestamp() - last_time_stamp_).InMillisecondsF();
+
+ // Check if the time since the last frame is completely off.
+ if (delta_ms < 0 || delta_ms > kMaxTimeInMsBetweenFrames) {
+ // Reset |last_time_stamp_| and fps calculation.
+ last_time_stamp_ = frame->timestamp();
+ frame_rate_ = MediaStreamVideoSource::kDefaultFrameRate;
+ keep_frame_counter_ = 0.0;
return false;
}
- base::TimeDelta delta = frame->timestamp() - last_time_stamp_;
- if (delta.InMilliseconds() < kMinTimeInMsBetweenFrames) {
+ if (delta_ms < kMinTimeInMsBetweenFrames) {
// We have seen video frames being delivered from camera devices back to
// back. The simple AR filter for frame rate calculation is too short to
// handle that. http://crbug/394315
@@ -249,15 +333,13 @@ bool VideoTrackAdapter::VideoFrameResolutionAdapter::MaybeDropFrame(
// Most likely the back to back problem is caused by software and not the
// actual camera.
DVLOG(3) << "Drop frame since delta time since previous frame is "
- << delta.InMilliseconds() << "ms.";
+ << delta_ms << "ms.";
return true;
}
last_time_stamp_ = frame->timestamp();
- if (delta == last_time_stamp_) // First received frame.
- return false;
// Calculate the frame rate using a simple AR filter.
// Use a simple filter with 0.1 weight of the current sample.
- frame_rate_ = 100 / delta.InMillisecondsF() + 0.9 * frame_rate_;
+ frame_rate_ = 100 / delta_ms + 0.9 * frame_rate_;
// Prefer to not drop frames.
if (max_frame_rate_ + 0.5f > frame_rate_)
@@ -275,63 +357,6 @@ bool VideoTrackAdapter::VideoFrameResolutionAdapter::MaybeDropFrame(
return true;
}
-void VideoTrackAdapter::
-VideoFrameResolutionAdapter::DoDeliverFrame(
- const scoped_refptr<media::VideoFrame>& frame,
- const media::VideoCaptureFormat& format,
- const base::TimeTicks& estimated_capture_time) {
- DCHECK(io_thread_checker_.CalledOnValidThread());
- for (std::vector<VideoIdCallbackPair>::const_iterator it = callbacks_.begin();
- it != callbacks_.end(); ++it) {
- it->second.Run(frame, format, estimated_capture_time);
- }
-}
-
-void VideoTrackAdapter::VideoFrameResolutionAdapter::AddCallback(
- const MediaStreamVideoTrack* track,
- const VideoCaptureDeliverFrameCB& callback) {
- DCHECK(io_thread_checker_.CalledOnValidThread());
- callbacks_.push_back(std::make_pair(track, callback));
-}
-
-void VideoTrackAdapter::VideoFrameResolutionAdapter::RemoveCallback(
- const MediaStreamVideoTrack* track) {
- DCHECK(io_thread_checker_.CalledOnValidThread());
- std::vector<VideoIdCallbackPair>::iterator it = callbacks_.begin();
- for (; it != callbacks_.end(); ++it) {
- if (it->first == track) {
- // Make sure the VideoCaptureDeliverFrameCB is released on the main
- // render thread since it was added on the main render thread in
- // VideoTrackAdapter::AddTrack.
- scoped_ptr<VideoCaptureDeliverFrameCB> callback(
- new VideoCaptureDeliverFrameCB(it->second));
- callbacks_.erase(it);
- renderer_task_runner_->PostTask(
- FROM_HERE, base::Bind(&ResetCallbackOnMainRenderThread,
- base::Passed(&callback)));
-
- return;
- }
- }
-}
-
-bool VideoTrackAdapter::VideoFrameResolutionAdapter::ConstraintsMatch(
- const gfx::Size& max_size,
- double min_aspect_ratio,
- double max_aspect_ratio,
- double max_frame_rate) const {
- DCHECK(io_thread_checker_.CalledOnValidThread());
- return max_frame_size_ == max_size &&
- min_aspect_ratio_ == min_aspect_ratio &&
- max_aspect_ratio_ == max_aspect_ratio &&
- max_frame_rate_ == max_frame_rate;
-}
-
-bool VideoTrackAdapter::VideoFrameResolutionAdapter::IsEmpty() const {
- DCHECK(io_thread_checker_.CalledOnValidThread());
- return callbacks_.empty();
-}
-
VideoTrackAdapter::VideoTrackAdapter(
const scoped_refptr<base::MessageLoopProxy>& io_message_loop)
: io_message_loop_(io_message_loop),
@@ -347,14 +372,13 @@ VideoTrackAdapter::~VideoTrackAdapter() {
DCHECK(adapters_.empty());
}
-void VideoTrackAdapter::AddTrack(
- const MediaStreamVideoTrack* track,
- VideoCaptureDeliverFrameCB frame_callback,
- int max_width,
- int max_height,
- double min_aspect_ratio,
- double max_aspect_ratio,
- double max_frame_rate) {
+void VideoTrackAdapter::AddTrack(const MediaStreamVideoTrack* track,
+ VideoCaptureDeliverFrameCB frame_callback,
+ int max_width,
+ int max_height,
+ double min_aspect_ratio,
+ double max_aspect_ratio,
+ double max_frame_rate) {
DCHECK(thread_checker_.CalledOnValidThread());
io_message_loop_->PostTask(
@@ -364,20 +388,18 @@ void VideoTrackAdapter::AddTrack(
min_aspect_ratio, max_aspect_ratio, max_frame_rate));
}
-void VideoTrackAdapter::AddTrackOnIO(
- const MediaStreamVideoTrack* track,
- VideoCaptureDeliverFrameCB frame_callback,
- const gfx::Size& max_frame_size,
- double min_aspect_ratio,
- double max_aspect_ratio,
- double max_frame_rate) {
+void VideoTrackAdapter::AddTrackOnIO(const MediaStreamVideoTrack* track,
+ VideoCaptureDeliverFrameCB frame_callback,
+ const gfx::Size& max_frame_size,
+ double min_aspect_ratio,
+ double max_aspect_ratio,
+ double max_frame_rate) {
DCHECK(io_message_loop_->BelongsToCurrentThread());
scoped_refptr<VideoFrameResolutionAdapter> adapter;
- for (FrameAdapters::const_iterator it = adapters_.begin();
- it != adapters_.end(); ++it) {
- if ((*it)->ConstraintsMatch(max_frame_size, min_aspect_ratio,
- max_aspect_ratio, max_frame_rate)) {
- adapter = it->get();
+ for (const auto& frame_adapter : adapters_) {
+ if (frame_adapter->ConstraintsMatch(max_frame_size, min_aspect_ratio,
+ max_aspect_ratio, max_frame_rate)) {
+ adapter = frame_adapter.get();
break;
}
}
@@ -414,6 +436,13 @@ void VideoTrackAdapter::StartFrameMonitoring(
this, bound_on_muted_callback, source_frame_rate));
}
+void VideoTrackAdapter::StopFrameMonitoring() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ io_message_loop_->PostTask(
+ FROM_HERE,
+ base::Bind(&VideoTrackAdapter::StopFrameMonitoringOnIO, this));
+}
+
void VideoTrackAdapter::StartFrameMonitoringOnIO(
const OnMutedCallback& on_muted_callback,
double source_frame_rate) {
@@ -435,13 +464,6 @@ void VideoTrackAdapter::StartFrameMonitoringOnIO(
source_frame_rate_));
}
-void VideoTrackAdapter::StopFrameMonitoring() {
- DCHECK(thread_checker_.CalledOnValidThread());
- io_message_loop_->PostTask(
- FROM_HERE,
- base::Bind(&VideoTrackAdapter::StopFrameMonitoringOnIO, this));
-}
-
void VideoTrackAdapter::StopFrameMonitoringOnIO() {
DCHECK(io_message_loop_->BelongsToCurrentThread());
monitoring_frame_rate_ = false;
@@ -461,15 +483,12 @@ void VideoTrackAdapter::RemoveTrackOnIO(const MediaStreamVideoTrack* track) {
void VideoTrackAdapter::DeliverFrameOnIO(
const scoped_refptr<media::VideoFrame>& frame,
- const media::VideoCaptureFormat& format,
const base::TimeTicks& estimated_capture_time) {
DCHECK(io_message_loop_->BelongsToCurrentThread());
TRACE_EVENT0("video", "VideoTrackAdapter::DeliverFrameOnIO");
++frame_counter_;
- for (FrameAdapters::iterator it = adapters_.begin();
- it != adapters_.end(); ++it) {
- (*it)->DeliverFrame(frame, format, estimated_capture_time);
- }
+ for (const auto& adapter : adapters_)
+ adapter->DeliverFrame(frame, estimated_capture_time);
}
void VideoTrackAdapter::CheckFramesReceivedOnIO(
diff --git a/chromium/content/renderer/media/video_track_adapter.h b/chromium/content/renderer/media/video_track_adapter.h
index 1a616126985..56aaa6a8397 100644
--- a/chromium/content/renderer/media/video_track_adapter.h
+++ b/chromium/content/renderer/media/video_track_adapter.h
@@ -50,7 +50,6 @@ class VideoTrackAdapter
// Must be called on the IO-thread.
void DeliverFrameOnIO(
const scoped_refptr<media::VideoFrame>& frame,
- const media::VideoCaptureFormat& format,
const base::TimeTicks& estimated_capture_time);
const scoped_refptr<base::MessageLoopProxy>& io_message_loop() {
@@ -91,11 +90,11 @@ class VideoTrackAdapter
// |thread_checker_| is bound to the main render thread.
base::ThreadChecker thread_checker_;
- scoped_refptr<base::MessageLoopProxy> io_message_loop_;
+ const scoped_refptr<base::MessageLoopProxy> io_message_loop_;
// |renderer_task_runner_| is used to ensure that
// VideoCaptureDeliverFrameCB is released on the main render thread.
- scoped_refptr<base::SingleThreadTaskRunner> renderer_task_runner_;
+ const scoped_refptr<base::SingleThreadTaskRunner> renderer_task_runner_;
// VideoFrameResolutionAdapter is an inner class that is created on the main
// render thread but operates on the IO-thread. It does the resolution
diff --git a/chromium/content/renderer/media/webaudio_capturer_source.cc b/chromium/content/renderer/media/webaudio_capturer_source.cc
index e175ad293d9..465e7bbdf57 100644
--- a/chromium/content/renderer/media/webaudio_capturer_source.cc
+++ b/chromium/content/renderer/media/webaudio_capturer_source.cc
@@ -6,7 +6,6 @@
#include "base/logging.h"
#include "base/time/time.h"
-#include "content/renderer/media/webrtc_audio_capturer.h"
#include "content/renderer/media/webrtc_local_audio_track.h"
using media::AudioBus;
@@ -20,13 +19,16 @@ static const int kMaxNumberOfBuffersInFifo = 5;
namespace content {
-WebAudioCapturerSource::WebAudioCapturerSource()
+WebAudioCapturerSource::WebAudioCapturerSource(
+ const blink::WebMediaStreamSource& blink_source)
: track_(NULL),
- capturer_(NULL),
- audio_format_changed_(false) {
+ audio_format_changed_(false),
+ blink_source_(blink_source) {
}
WebAudioCapturerSource::~WebAudioCapturerSource() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ removeFromBlinkSource();
}
void WebAudioCapturerSource::setFormat(
@@ -54,27 +56,23 @@ void WebAudioCapturerSource::setFormat(
wrapper_bus_ = AudioBus::CreateWrapper(params_.channels());
capture_bus_ = AudioBus::Create(params_);
- audio_data_.reset(
- new int16[params_.frames_per_buffer() * params_.channels()]);
fifo_.reset(new AudioFifo(
params_.channels(),
kMaxNumberOfBuffersInFifo * params_.frames_per_buffer()));
}
-void WebAudioCapturerSource::Start(
- WebRtcLocalAudioTrack* track, WebRtcAudioCapturer* capturer) {
+void WebAudioCapturerSource::Start(WebRtcLocalAudioTrack* track) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(track);
base::AutoLock auto_lock(lock_);
track_ = track;
- capturer_ = capturer;
}
void WebAudioCapturerSource::Stop() {
DCHECK(thread_checker_.CalledOnValidThread());
base::AutoLock auto_lock(lock_);
track_ = NULL;
- capturer_ = NULL;
+ removeFromBlinkSource();
}
void WebAudioCapturerSource::consumeAudio(
@@ -106,28 +104,32 @@ void WebAudioCapturerSource::consumeAudio(
return;
}
+ // Compute the estimated capture time of the first sample frame of audio that
+ // will be consumed from the FIFO in the loop below.
+ base::TimeTicks estimated_capture_time = base::TimeTicks::Now() -
+ fifo_->frames() * base::TimeDelta::FromSeconds(1) / params_.sample_rate();
+
fifo_->Push(wrapper_bus_.get());
- int capture_frames = params_.frames_per_buffer();
- base::TimeDelta delay;
- int volume = 0;
- bool key_pressed = false;
- if (capturer_) {
- capturer_->GetAudioProcessingParams(&delay, &volume, &key_pressed);
+ while (fifo_->frames() >= capture_bus_->frames()) {
+ fifo_->Consume(capture_bus_.get(), 0, capture_bus_->frames());
+ track_->Capture(*capture_bus_, estimated_capture_time, false);
+
+ // Advance the estimated capture time for the next FIFO consume operation.
+ estimated_capture_time +=
+ capture_bus_->frames() * base::TimeDelta::FromSeconds(1) /
+ params_.sample_rate();
}
+}
- // Turn off audio processing if the delay value is 0, since in such case,
- // it indicates the data is not from microphone.
- // TODO(xians): remove the flag when supporting one APM per audio track.
- // See crbug/264611 for details.
- bool need_audio_processing = (delay.InMilliseconds() != 0);
- while (fifo_->frames() >= capture_frames) {
- fifo_->Consume(capture_bus_.get(), 0, capture_frames);
- // TODO(xians): Avoid this interleave/deinterleave operation.
- capture_bus_->ToInterleaved(capture_bus_->frames(),
- params_.bits_per_sample() / 8,
- audio_data_.get());
- track_->Capture(audio_data_.get(), delay, volume, key_pressed,
- need_audio_processing, false);
+// If registered as audio consumer in |blink_source_|, deregister from
+// |blink_source_| and stop keeping a reference to |blink_source_|.
+// Failure to call this method when stopping the track might leave an invalid
+// WebAudioCapturerSource reference still registered as an audio consumer on
+// the blink side.
+void WebAudioCapturerSource::removeFromBlinkSource() {
+ if (!blink_source_.isNull()) {
+ blink_source_.removeAudioConsumer(this);
+ blink_source_.reset();
}
}
diff --git a/chromium/content/renderer/media/webaudio_capturer_source.h b/chromium/content/renderer/media/webaudio_capturer_source.h
index 6382bd31830..1e682576a0c 100644
--- a/chromium/content/renderer/media/webaudio_capturer_source.h
+++ b/chromium/content/renderer/media/webaudio_capturer_source.h
@@ -12,11 +12,11 @@
#include "media/base/audio_capturer_source.h"
#include "media/base/audio_fifo.h"
#include "third_party/WebKit/public/platform/WebAudioDestinationConsumer.h"
+#include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
#include "third_party/WebKit/public/platform/WebVector.h"
namespace content {
-class WebRtcAudioCapturer;
class WebRtcLocalAudioTrack;
// WebAudioCapturerSource is the missing link between
@@ -30,30 +30,35 @@ class WebAudioCapturerSource
: public base::RefCountedThreadSafe<WebAudioCapturerSource>,
public blink::WebAudioDestinationConsumer {
public:
- WebAudioCapturerSource();
+ explicit WebAudioCapturerSource(
+ const blink::WebMediaStreamSource& blink_source);
// WebAudioDestinationConsumer implementation.
// setFormat() is called early on, so that we can configure the audio track.
- virtual void setFormat(size_t number_of_channels, float sample_rate) override;
+ void setFormat(size_t number_of_channels, float sample_rate) override;
// MediaStreamAudioDestinationNode periodically calls consumeAudio().
// Called on the WebAudio audio thread.
- virtual void consumeAudio(const blink::WebVector<const float*>& audio_data,
- size_t number_of_frames) override;
+ void consumeAudio(const blink::WebVector<const float*>& audio_data,
+ size_t number_of_frames) override;
// Called when the WebAudioCapturerSource is hooking to a media audio track.
// |track| is the sink of the data flow. |source_provider| is the source of
// the data flow where stream information like delay, volume, key_pressed,
// is stored.
- void Start(WebRtcLocalAudioTrack* track, WebRtcAudioCapturer* capturer);
+ void Start(WebRtcLocalAudioTrack* track);
// Called when the media audio track is stopping.
void Stop();
protected:
friend class base::RefCountedThreadSafe<WebAudioCapturerSource>;
- virtual ~WebAudioCapturerSource();
+ ~WebAudioCapturerSource() override;
private:
+ // Removes this object from a blink::WebMediaStreamSource with which it
+ // might be registered. The goal is to avoid dangling pointers.
+ void removeFromBlinkSource();
+
// Used to DCHECK that some methods are called on the correct thread.
base::ThreadChecker thread_checker_;
@@ -62,11 +67,6 @@ class WebAudioCapturerSource
// To avoid circular reference, a raw pointer is kept here.
WebRtcLocalAudioTrack* track_;
- // A raw pointer to the capturer to get audio processing params like
- // delay, volume, key_pressed information.
- // This |capturer_| is guaranteed to outlive this object.
- WebRtcAudioCapturer* capturer_;
-
media::AudioParameters params_;
// Flag to help notify the |track_| when the audio format has changed.
@@ -81,13 +81,14 @@ class WebAudioCapturerSource
// Handles mismatch between WebAudio buffer size and WebRTC.
scoped_ptr<media::AudioFifo> fifo_;
- // Buffer to pass audio data to WebRtc.
- scoped_ptr<int16[]> audio_data_;
-
// Synchronizes HandleCapture() with AudioCapturerSource calls.
base::Lock lock_;
bool started_;
+ // This object registers with a blink::WebMediaStreamSource. We keep track of
+ // that in order to be able to deregister before stopping the audio track.
+ blink::WebMediaStreamSource blink_source_;
+
DISALLOW_COPY_AND_ASSIGN(WebAudioCapturerSource);
};
diff --git a/chromium/content/renderer/media/webcontentdecryptionmodule_impl.cc b/chromium/content/renderer/media/webcontentdecryptionmodule_impl.cc
deleted file mode 100644
index c2070ba5f03..00000000000
--- a/chromium/content/renderer/media/webcontentdecryptionmodule_impl.cc
+++ /dev/null
@@ -1,103 +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/renderer/media/webcontentdecryptionmodule_impl.h"
-
-#include "base/basictypes.h"
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "content/renderer/media/cdm_session_adapter.h"
-#include "content/renderer/media/crypto/key_systems.h"
-#include "content/renderer/media/webcontentdecryptionmodulesession_impl.h"
-#include "media/base/cdm_promise.h"
-#include "media/base/media_keys.h"
-#include "media/blink/cdm_result_promise.h"
-#include "third_party/WebKit/public/platform/WebString.h"
-#include "third_party/WebKit/public/web/WebSecurityOrigin.h"
-#include "url/gurl.h"
-
-namespace content {
-
-WebContentDecryptionModuleImpl* WebContentDecryptionModuleImpl::Create(
- media::CdmFactory* cdm_factory,
- const blink::WebSecurityOrigin& security_origin,
- const base::string16& key_system) {
- DCHECK(!security_origin.isNull());
- DCHECK(!key_system.empty());
-
- // TODO(ddorwin): Guard against this in supported types check and remove this.
- // Chromium only supports ASCII key systems.
- if (!base::IsStringASCII(key_system)) {
- NOTREACHED();
- return NULL;
- }
-
- std::string key_system_ascii = base::UTF16ToASCII(key_system);
- if (!IsConcreteSupportedKeySystem(key_system_ascii))
- return NULL;
-
- // If unique security origin, don't try to create the CDM.
- if (security_origin.isUnique() || security_origin.toString() == "null") {
- DLOG(ERROR) << "CDM use not allowed for unique security origin.";
- return NULL;
- }
-
- scoped_refptr<CdmSessionAdapter> adapter(new CdmSessionAdapter());
- GURL security_origin_as_gurl(security_origin.toString());
-
- if (!adapter->Initialize(
- cdm_factory, key_system_ascii, security_origin_as_gurl)) {
- return NULL;
- }
-
- return new WebContentDecryptionModuleImpl(adapter);
-}
-
-WebContentDecryptionModuleImpl::WebContentDecryptionModuleImpl(
- scoped_refptr<CdmSessionAdapter> adapter)
- : adapter_(adapter) {
-}
-
-WebContentDecryptionModuleImpl::~WebContentDecryptionModuleImpl() {
-}
-
-// The caller owns the created session.
-blink::WebContentDecryptionModuleSession*
-WebContentDecryptionModuleImpl::createSession() {
- return adapter_->CreateSession();
-}
-
-blink::WebContentDecryptionModuleSession*
-WebContentDecryptionModuleImpl::createSession(
- blink::WebContentDecryptionModuleSession::Client* client) {
- WebContentDecryptionModuleSessionImpl* session = adapter_->CreateSession();
- session->setClientInterface(client);
- return session;
-}
-
-void WebContentDecryptionModuleImpl::setServerCertificate(
- const uint8* server_certificate,
- size_t server_certificate_length,
- blink::WebContentDecryptionModuleResult result) {
- DCHECK(server_certificate);
- adapter_->SetServerCertificate(
- server_certificate,
- server_certificate_length,
- scoped_ptr<media::SimpleCdmPromise>(
- new media::CdmResultPromise<>(result, std::string())));
-}
-
-media::Decryptor* WebContentDecryptionModuleImpl::GetDecryptor() {
- return adapter_->GetDecryptor();
-}
-
-#if defined(ENABLE_BROWSER_CDMS)
-int WebContentDecryptionModuleImpl::GetCdmId() const {
- return adapter_->GetCdmId();
-}
-#endif // defined(ENABLE_BROWSER_CDMS)
-
-} // namespace content
diff --git a/chromium/content/renderer/media/webcontentdecryptionmodule_impl.h b/chromium/content/renderer/media/webcontentdecryptionmodule_impl.h
deleted file mode 100644
index c535db7f415..00000000000
--- a/chromium/content/renderer/media/webcontentdecryptionmodule_impl.h
+++ /dev/null
@@ -1,82 +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_RENDERER_MEDIA_WEBCONTENTDECRYPTIONMODULE_IMPL_H_
-#define CONTENT_RENDERER_MEDIA_WEBCONTENTDECRYPTIONMODULE_IMPL_H_
-
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/strings/string16.h"
-#include "third_party/WebKit/public/platform/WebContentDecryptionModule.h"
-#include "third_party/WebKit/public/platform/WebContentDecryptionModuleResult.h"
-
-namespace blink {
-#if defined(ENABLE_PEPPER_CDMS)
-class WebLocalFrame;
-#endif
-class WebSecurityOrigin;
-}
-
-namespace media {
-class CdmFactory;
-class Decryptor;
-class MediaKeys;
-}
-
-namespace content {
-
-class CdmSessionAdapter;
-class WebContentDecryptionModuleSessionImpl;
-
-class WebContentDecryptionModuleImpl
- : public blink::WebContentDecryptionModule {
- public:
- static WebContentDecryptionModuleImpl* Create(
- media::CdmFactory* cdm_factory,
- const blink::WebSecurityOrigin& security_origin,
- const base::string16& key_system);
-
- virtual ~WebContentDecryptionModuleImpl();
-
- // Returns the Decryptor associated with this CDM. May be NULL if no
- // Decryptor associated with the MediaKeys object.
- // TODO(jrummell): Figure out lifetimes, as WMPI may still use the decryptor
- // after WebContentDecryptionModule is freed. http://crbug.com/330324
- media::Decryptor* GetDecryptor();
-
-#if defined(ENABLE_BROWSER_CDMS)
- // Returns the CDM ID associated with this object. May be kInvalidCdmId if no
- // CDM ID is associated, such as when Clear Key is used.
- int GetCdmId() const;
-#endif // defined(ENABLE_BROWSER_CDMS)
-
- // blink::WebContentDecryptionModule implementation.
- virtual blink::WebContentDecryptionModuleSession* createSession();
- // TODO(jrummell): Remove this method once blink updated.
- virtual blink::WebContentDecryptionModuleSession* createSession(
- blink::WebContentDecryptionModuleSession::Client* client);
-
- virtual void setServerCertificate(
- const uint8* server_certificate,
- size_t server_certificate_length,
- blink::WebContentDecryptionModuleResult result);
-
- private:
- // Takes reference to |adapter|.
- WebContentDecryptionModuleImpl(scoped_refptr<CdmSessionAdapter> adapter);
-
- scoped_refptr<CdmSessionAdapter> adapter_;
-
- DISALLOW_COPY_AND_ASSIGN(WebContentDecryptionModuleImpl);
-};
-
-// Allow typecasting from blink type as this is the only implementation.
-inline WebContentDecryptionModuleImpl* ToWebContentDecryptionModuleImpl(
- blink::WebContentDecryptionModule* cdm) {
- return static_cast<WebContentDecryptionModuleImpl*>(cdm);
-}
-
-} // namespace content
-
-#endif // CONTENT_RENDERER_MEDIA_WEBCONTENTDECRYPTIONMODULE_IMPL_H_
diff --git a/chromium/content/renderer/media/webcontentdecryptionmodulesession_impl.cc b/chromium/content/renderer/media/webcontentdecryptionmodulesession_impl.cc
deleted file mode 100644
index 871c31fb3ee..00000000000
--- a/chromium/content/renderer/media/webcontentdecryptionmodulesession_impl.cc
+++ /dev/null
@@ -1,210 +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/renderer/media/webcontentdecryptionmodulesession_impl.h"
-
-#include "base/bind.h"
-#include "base/callback_helpers.h"
-#include "base/logging.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "content/renderer/media/cdm_session_adapter.h"
-#include "media/base/cdm_promise.h"
-#include "media/base/media_keys.h"
-#include "media/blink/cdm_result_promise.h"
-#include "media/blink/new_session_cdm_result_promise.h"
-#include "third_party/WebKit/public/platform/WebURL.h"
-
-namespace content {
-
-const char kCreateSessionUMAName[] = "CreateSession";
-const char kLoadSessionUMAName[] = "LoadSession";
-
-WebContentDecryptionModuleSessionImpl::WebContentDecryptionModuleSessionImpl(
- const scoped_refptr<CdmSessionAdapter>& adapter)
- : adapter_(adapter),
- is_closed_(false),
- weak_ptr_factory_(this) {
-}
-
-WebContentDecryptionModuleSessionImpl::
- ~WebContentDecryptionModuleSessionImpl() {
- if (!web_session_id_.empty())
- adapter_->UnregisterSession(web_session_id_);
-}
-
-void WebContentDecryptionModuleSessionImpl::setClientInterface(Client* client) {
- client_ = client;
-}
-
-blink::WebString WebContentDecryptionModuleSessionImpl::sessionId() const {
- return blink::WebString::fromUTF8(web_session_id_);
-}
-
-void WebContentDecryptionModuleSessionImpl::initializeNewSession(
- const blink::WebString& init_data_type,
- const uint8* init_data,
- size_t init_data_length) {
- // TODO(jrummell): Remove once blink updated.
- NOTREACHED();
-}
-
-void WebContentDecryptionModuleSessionImpl::update(const uint8* response,
- size_t response_length) {
- // TODO(jrummell): Remove once blink updated.
- NOTREACHED();
-}
-
-void WebContentDecryptionModuleSessionImpl::release() {
- // TODO(jrummell): Remove once blink updated.
- NOTREACHED();
-}
-
-void WebContentDecryptionModuleSessionImpl::initializeNewSession(
- const blink::WebString& init_data_type,
- const uint8* init_data,
- size_t init_data_length,
- const blink::WebString& session_type,
- blink::WebContentDecryptionModuleResult result) {
- DCHECK(web_session_id_.empty());
-
- // TODO(ddorwin): Guard against this in supported types check and remove this.
- // Chromium only supports ASCII MIME types.
- if (!base::IsStringASCII(init_data_type)) {
- NOTREACHED();
- std::string message = "The initialization data type " +
- init_data_type.utf8() +
- " is not supported by the key system.";
- result.completeWithError(
- blink::WebContentDecryptionModuleExceptionNotSupportedError,
- 0,
- blink::WebString::fromUTF8(message));
- return;
- }
-
- std::string init_data_type_as_ascii = base::UTF16ToASCII(init_data_type);
- DLOG_IF(WARNING, init_data_type_as_ascii.find('/') != std::string::npos)
- << "init_data_type '" << init_data_type_as_ascii
- << "' may be a MIME type";
-
- adapter_->InitializeNewSession(
- init_data_type_as_ascii,
- init_data,
- init_data_length,
- media::MediaKeys::TEMPORARY_SESSION,
- scoped_ptr<media::NewSessionCdmPromise>(
- new media::NewSessionCdmResultPromise(
- result,
- adapter_->GetKeySystemUMAPrefix() + kCreateSessionUMAName,
- base::Bind(
- &WebContentDecryptionModuleSessionImpl::OnSessionInitialized,
- base::Unretained(this)))));
-}
-
-void WebContentDecryptionModuleSessionImpl::load(
- const blink::WebString& session_id,
- blink::WebContentDecryptionModuleResult result) {
- DCHECK(!session_id.isEmpty());
- DCHECK(web_session_id_.empty());
-
- adapter_->LoadSession(
- base::UTF16ToASCII(session_id),
- scoped_ptr<media::NewSessionCdmPromise>(
- new media::NewSessionCdmResultPromise(
- result,
- adapter_->GetKeySystemUMAPrefix() + kLoadSessionUMAName,
- base::Bind(
- &WebContentDecryptionModuleSessionImpl::OnSessionInitialized,
- base::Unretained(this)))));
-}
-
-void WebContentDecryptionModuleSessionImpl::update(
- const uint8* response,
- size_t response_length,
- blink::WebContentDecryptionModuleResult result) {
- DCHECK(response);
- DCHECK(!web_session_id_.empty());
- adapter_->UpdateSession(
- web_session_id_,
- response,
- response_length,
- scoped_ptr<media::SimpleCdmPromise>(
- new media::CdmResultPromise<>(result, std::string())));
-}
-
-void WebContentDecryptionModuleSessionImpl::close(
- blink::WebContentDecryptionModuleResult result) {
- DCHECK(!web_session_id_.empty());
- adapter_->CloseSession(
- web_session_id_,
- scoped_ptr<media::SimpleCdmPromise>(
- new media::CdmResultPromise<>(result, std::string())));
-}
-
-void WebContentDecryptionModuleSessionImpl::remove(
- blink::WebContentDecryptionModuleResult result) {
- DCHECK(!web_session_id_.empty());
- adapter_->RemoveSession(
- web_session_id_,
- scoped_ptr<media::SimpleCdmPromise>(
- new media::CdmResultPromise<>(result, std::string())));
-}
-
-void WebContentDecryptionModuleSessionImpl::getUsableKeyIds(
- blink::WebContentDecryptionModuleResult result) {
- DCHECK(!web_session_id_.empty());
- adapter_->GetUsableKeyIds(
- web_session_id_,
- scoped_ptr<media::KeyIdsPromise>(
- new media::CdmResultPromise<media::KeyIdsVector>(result,
- std::string())));
-}
-
-void WebContentDecryptionModuleSessionImpl::release(
- blink::WebContentDecryptionModuleResult result) {
- close(result);
-}
-
-void WebContentDecryptionModuleSessionImpl::OnSessionMessage(
- const std::vector<uint8>& message,
- const GURL& destination_url) {
- DCHECK(client_) << "Client not set before message event";
- client_->message(
- message.empty() ? NULL : &message[0], message.size(), destination_url);
-}
-
-void WebContentDecryptionModuleSessionImpl::OnSessionKeysChange(
- bool has_additional_usable_key) {
- // TODO(jrummell): Update this once Blink client supports this.
-}
-
-void WebContentDecryptionModuleSessionImpl::OnSessionExpirationUpdate(
- const base::Time& new_expiry_time) {
- client_->expirationChanged(new_expiry_time.ToJsTime());
-}
-
-void WebContentDecryptionModuleSessionImpl::OnSessionClosed() {
- if (is_closed_)
- return;
-
- is_closed_ = true;
- client_->close();
-}
-
-blink::WebContentDecryptionModuleResult::SessionStatus
-WebContentDecryptionModuleSessionImpl::OnSessionInitialized(
- const std::string& web_session_id) {
- // CDM will return NULL if the session to be loaded can't be found.
- if (web_session_id.empty())
- return blink::WebContentDecryptionModuleResult::SessionNotFound;
-
- DCHECK(web_session_id_.empty()) << "Session ID may not be changed once set.";
- web_session_id_ = web_session_id;
- return adapter_->RegisterSession(web_session_id_,
- weak_ptr_factory_.GetWeakPtr())
- ? blink::WebContentDecryptionModuleResult::NewSession
- : blink::WebContentDecryptionModuleResult::SessionAlreadyExists;
-}
-
-} // namespace content
diff --git a/chromium/content/renderer/media/webcontentdecryptionmodulesession_impl.h b/chromium/content/renderer/media/webcontentdecryptionmodulesession_impl.h
deleted file mode 100644
index c54c2180113..00000000000
--- a/chromium/content/renderer/media/webcontentdecryptionmodulesession_impl.h
+++ /dev/null
@@ -1,98 +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_RENDERER_MEDIA_WEBCONTENTDECRYPTIONMODULESESSION_IMPL_H_
-#define CONTENT_RENDERER_MEDIA_WEBCONTENTDECRYPTIONMODULESESSION_IMPL_H_
-
-#include <map>
-#include <string>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/callback.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "media/base/media_keys.h"
-#include "third_party/WebKit/public/platform/WebContentDecryptionModuleSession.h"
-#include "third_party/WebKit/public/platform/WebString.h"
-
-namespace media {
-class MediaKeys;
-}
-
-namespace content {
-class CdmSessionAdapter;
-
-class WebContentDecryptionModuleSessionImpl
- : public blink::WebContentDecryptionModuleSession {
- public:
- WebContentDecryptionModuleSessionImpl(
- const scoped_refptr<CdmSessionAdapter>& adapter);
- virtual ~WebContentDecryptionModuleSessionImpl();
-
- // blink::WebContentDecryptionModuleSession implementation.
- virtual void setClientInterface(Client* client);
- virtual blink::WebString sessionId() const;
- // TODO(jrummell): Remove the next 3 methods once blink updated.
- virtual void initializeNewSession(const blink::WebString& mime_type,
- const uint8* init_data,
- size_t init_data_length);
- virtual void update(const uint8* response, size_t response_length);
- virtual void release();
- virtual void initializeNewSession(
- const blink::WebString& init_data_type,
- const uint8* init_data,
- size_t init_data_length,
- const blink::WebString& session_type,
- blink::WebContentDecryptionModuleResult result);
- virtual void load(const blink::WebString& session_id,
- blink::WebContentDecryptionModuleResult result);
- virtual void update(const uint8* response,
- size_t response_length,
- blink::WebContentDecryptionModuleResult result);
- virtual void close(blink::WebContentDecryptionModuleResult result);
- virtual void remove(blink::WebContentDecryptionModuleResult result);
- virtual void getUsableKeyIds(blink::WebContentDecryptionModuleResult result);
-
- // TODO(jrummell): Remove the next method once blink updated.
- virtual void release(blink::WebContentDecryptionModuleResult result);
-
- // Callbacks.
- void OnSessionMessage(const std::vector<uint8>& message,
- const GURL& destination_url);
- void OnSessionKeysChange(bool has_additional_usable_key);
- void OnSessionExpirationUpdate(const base::Time& new_expiry_time);
- void OnSessionClosed();
-
- private:
- // Called when a new session is created.
- blink::WebContentDecryptionModuleResult::SessionStatus OnSessionInitialized(
- const std::string& web_session_id);
-
- scoped_refptr<CdmSessionAdapter> adapter_;
-
- // Non-owned pointer.
- Client* client_;
-
- // Web session ID is the app visible ID for this session generated by the CDM.
- // This value is not set until the CDM resolves the initializeNewSession()
- // promise.
- std::string web_session_id_;
-
- // Don't pass more than 1 close() event to blink::
- // TODO(jrummell): Remove this once blink tests handle close() promise and
- // closed() event.
- bool is_closed_;
-
- // Since promises will live until they are fired, use a weak reference when
- // creating a promise in case this class disappears before the promise
- // actually fires.
- base::WeakPtrFactory<WebContentDecryptionModuleSessionImpl> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(WebContentDecryptionModuleSessionImpl);
-};
-
-} // namespace content
-
-#endif // CONTENT_RENDERER_MEDIA_WEBCONTENTDECRYPTIONMODULESESSION_IMPL_H_
diff --git a/chromium/content/renderer/media/webmediaplayer_ms.cc b/chromium/content/renderer/media/webmediaplayer_ms.cc
index 83f082ad07e..ed4981bc0d3 100644
--- a/chromium/content/renderer/media/webmediaplayer_ms.cc
+++ b/chromium/content/renderer/media/webmediaplayer_ms.cc
@@ -10,6 +10,7 @@
#include "base/callback.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram.h"
+#include "cc/blink/context_provider_web_context.h"
#include "cc/blink/web_layer_impl.h"
#include "cc/layers/video_layer.h"
#include "content/public/renderer/render_view.h"
@@ -17,6 +18,8 @@
#include "content/renderer/media/media_stream_renderer_factory.h"
#include "content/renderer/media/video_frame_provider.h"
#include "content/renderer/render_frame_impl.h"
+#include "content/renderer/render_thread_impl.h"
+#include "gpu/blink/webgraphicscontext3d_impl.h"
#include "media/base/media_log.h"
#include "media/base/video_frame.h"
#include "media/base/video_rotation.h"
@@ -36,12 +39,15 @@ using blink::WebMediaPlayer;
using blink::WebRect;
using blink::WebSize;
+namespace content {
+
namespace {
// This function copies a YV12 or NATIVE_TEXTURE to a new YV12
// media::VideoFrame.
scoped_refptr<media::VideoFrame> CopyFrameToYV12(
- const scoped_refptr<media::VideoFrame>& frame) {
+ const scoped_refptr<media::VideoFrame>& frame,
+ media::SkCanvasVideoRenderer* video_renderer) {
DCHECK(frame->format() == media::VideoFrame::YV12 ||
frame->format() == media::VideoFrame::I420 ||
frame->format() == media::VideoFrame::NATIVE_TEXTURE);
@@ -56,8 +62,19 @@ scoped_refptr<media::VideoFrame> CopyFrameToYV12(
SkBitmap bitmap;
bitmap.allocN32Pixels(frame->visible_rect().width(),
frame->visible_rect().height());
- frame->ReadPixelsFromNativeTexture(bitmap);
-
+ SkCanvas canvas(bitmap);
+
+ cc::ContextProvider* provider =
+ RenderThreadImpl::current()->SharedMainThreadContextProvider().get();
+ if (provider) {
+ media::Context3D context_3d =
+ media::Context3D(provider->ContextGL(), provider->GrContext());
+ DCHECK(context_3d.gl);
+ video_renderer->Copy(frame.get(), &canvas, context_3d);
+ } else {
+ // GPU Process crashed.
+ bitmap.eraseColor(SK_ColorTRANSPARENT);
+ }
media::CopyRGBToVideoFrame(
reinterpret_cast<uint8*>(bitmap.getPixels()),
bitmap.rowBytes(),
@@ -76,8 +93,6 @@ scoped_refptr<media::VideoFrame> CopyFrameToYV12(
} // anonymous namespace
-namespace content {
-
WebMediaPlayerMS::WebMediaPlayerMS(
blink::WebFrame* frame,
blink::WebMediaPlayerClient* client,
@@ -87,13 +102,12 @@ WebMediaPlayerMS::WebMediaPlayerMS(
: frame_(frame),
network_state_(WebMediaPlayer::NetworkStateEmpty),
ready_state_(WebMediaPlayer::ReadyStateHaveNothing),
- buffered_(static_cast<size_t>(1)),
+ buffered_(static_cast<size_t>(0)),
volume_(1.0f),
client_(client),
delegate_(delegate),
paused_(true),
current_frame_used_(false),
- pending_repaint_(false),
video_frame_provider_client_(NULL),
received_first_frame_(false),
total_frame_count_(0),
@@ -149,7 +163,6 @@ void WebMediaPlayerMS::load(LoadType load_type,
RenderFrame* frame = RenderFrame::FromWebFrame(frame_);
audio_renderer_ = renderer_factory_->GetAudioRenderer(
url,
- frame->GetRenderView()->GetRoutingID(),
frame->GetRoutingID());
if (video_frame_provider_.get() || audio_renderer_.get()) {
@@ -217,7 +230,9 @@ void WebMediaPlayerMS::pause() {
// The original frame must not be referenced when the player is paused since
// there might be a finite number of available buffers. E.g, video that
// originates from a video camera.
- scoped_refptr<media::VideoFrame> new_frame = CopyFrameToYV12(current_frame_);
+ scoped_refptr<media::VideoFrame> new_frame =
+ CopyFrameToYV12(current_frame_, &video_renderer_);
+
base::AutoLock auto_lock(current_frame_lock_);
current_frame_ = new_frame;
}
@@ -326,9 +341,20 @@ void WebMediaPlayerMS::paint(blink::WebCanvas* canvas,
DVLOG(3) << "WebMediaPlayerMS::paint";
DCHECK(thread_checker_.CalledOnValidThread());
+ media::Context3D context_3d;
+ if (current_frame_.get() &&
+ current_frame_->format() == media::VideoFrame::NATIVE_TEXTURE) {
+ cc::ContextProvider* provider =
+ RenderThreadImpl::current()->SharedMainThreadContextProvider().get();
+ // GPU Process crashed.
+ if (!provider)
+ return;
+ context_3d = media::Context3D(provider->ContextGL(), provider->GrContext());
+ DCHECK(context_3d.gl);
+ }
gfx::RectF dest_rect(rect.x, rect.y, rect.width, rect.height);
- video_renderer_.Paint(
- current_frame_, canvas, dest_rect, alpha, mode, media::VIDEO_ROTATION_0);
+ video_renderer_.Paint(current_frame_, canvas, dest_rect, alpha, mode,
+ media::VIDEO_ROTATION_0, context_3d);
{
base::AutoLock auto_lock(current_frame_lock_);
@@ -375,6 +401,51 @@ unsigned WebMediaPlayerMS::videoDecodedByteCount() const {
return 0;
}
+bool WebMediaPlayerMS::copyVideoTextureToPlatformTexture(
+ blink::WebGraphicsContext3D* web_graphics_context,
+ unsigned int texture,
+ unsigned int level,
+ unsigned int internal_format,
+ unsigned int type,
+ bool premultiply_alpha,
+ bool flip_y) {
+ return copyVideoTextureToPlatformTexture(web_graphics_context, texture,
+ internal_format, type,
+ premultiply_alpha, flip_y);
+}
+
+bool WebMediaPlayerMS::copyVideoTextureToPlatformTexture(
+ blink::WebGraphicsContext3D* web_graphics_context,
+ unsigned int texture,
+ unsigned int internal_format,
+ unsigned int type,
+ bool premultiply_alpha,
+ bool flip_y) {
+ TRACE_EVENT0("media", "WebMediaPlayerMS:copyVideoTextureToPlatformTexture");
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ scoped_refptr<media::VideoFrame> video_frame;
+ {
+ base::AutoLock auto_lock(current_frame_lock_);
+ video_frame = current_frame_;
+ }
+
+ if (!video_frame.get() ||
+ video_frame->format() != media::VideoFrame::NATIVE_TEXTURE) {
+ return false;
+ }
+
+ // TODO(dshwang): need more elegant way to convert WebGraphicsContext3D to
+ // GLES2Interface.
+ gpu::gles2::GLES2Interface* gl =
+ static_cast<gpu_blink::WebGraphicsContext3DImpl*>(web_graphics_context)
+ ->GetGLInterface();
+ media::SkCanvasVideoRenderer::CopyVideoFrameTextureToGLTexture(
+ gl, video_frame.get(), texture, internal_format, type, premultiply_alpha,
+ flip_y);
+ return true;
+}
+
void WebMediaPlayerMS::SetVideoFrameProviderClient(
cc::VideoFrameProvider::Client* client) {
// This is called from both the main renderer thread and the compositor
@@ -384,22 +455,30 @@ void WebMediaPlayerMS::SetVideoFrameProviderClient(
video_frame_provider_client_ = client;
}
+bool WebMediaPlayerMS::UpdateCurrentFrame(base::TimeTicks deadline_min,
+ base::TimeTicks deadline_max) {
+ // TODO(dalecurtis): This should make use of the deadline interval to ensure
+ // the painted frame is correct for the given interval.
+ NOTREACHED();
+ return false;
+}
+
+bool WebMediaPlayerMS::HasCurrentFrame() {
+ base::AutoLock auto_lock(current_frame_lock_);
+ return current_frame_;
+}
+
scoped_refptr<media::VideoFrame> WebMediaPlayerMS::GetCurrentFrame() {
DVLOG(3) << "WebMediaPlayerMS::GetCurrentFrame";
base::AutoLock auto_lock(current_frame_lock_);
- DCHECK(!pending_repaint_);
if (!current_frame_.get())
return NULL;
- pending_repaint_ = true;
current_frame_used_ = true;
return current_frame_;
}
-void WebMediaPlayerMS::PutCurrentFrame(
- const scoped_refptr<media::VideoFrame>& frame) {
+void WebMediaPlayerMS::PutCurrentFrame() {
DVLOG(3) << "WebMediaPlayerMS::PutCurrentFrame";
- DCHECK(pending_repaint_);
- pending_repaint_ = false;
}
void WebMediaPlayerMS::OnFrameAvailable(
diff --git a/chromium/content/renderer/media/webmediaplayer_ms.h b/chromium/content/renderer/media/webmediaplayer_ms.h
index 38667777dc9..c1d15aa8df8 100644
--- a/chromium/content/renderer/media/webmediaplayer_ms.h
+++ b/chromium/content/renderer/media/webmediaplayer_ms.h
@@ -11,13 +11,14 @@
#include "base/synchronization/lock.h"
#include "base/threading/thread_checker.h"
#include "cc/layers/video_frame_provider.h"
-#include "media/filters/skcanvas_video_renderer.h"
+#include "media/blink/skcanvas_video_renderer.h"
#include "skia/ext/platform_canvas.h"
#include "third_party/WebKit/public/platform/WebMediaPlayer.h"
#include "url/gurl.h"
namespace blink {
class WebFrame;
+class WebGraphicsContext3D;
class WebMediaPlayerClient;
}
@@ -113,11 +114,31 @@ class WebMediaPlayerMS
virtual unsigned audioDecodedByteCount() const;
virtual unsigned videoDecodedByteCount() const;
+ // TODO(dshwang): remove |level|. crbug.com/443151
+ bool copyVideoTextureToPlatformTexture(
+ blink::WebGraphicsContext3D* web_graphics_context,
+ unsigned int texture,
+ unsigned int level,
+ unsigned int internal_format,
+ unsigned int type,
+ bool premultiply_alpha,
+ bool flip_y) override;
+ virtual bool copyVideoTextureToPlatformTexture(
+ blink::WebGraphicsContext3D* web_graphics_context,
+ unsigned int texture,
+ unsigned int internal_format,
+ unsigned int type,
+ bool premultiply_alpha,
+ bool flip_y);
+
// VideoFrameProvider implementation.
void SetVideoFrameProviderClient(
cc::VideoFrameProvider::Client* client) override;
+ bool UpdateCurrentFrame(base::TimeTicks deadline_min,
+ base::TimeTicks deadline_max) override;
+ bool HasCurrentFrame() override;
scoped_refptr<media::VideoFrame> GetCurrentFrame() override;
- void PutCurrentFrame(const scoped_refptr<media::VideoFrame>& frame) override;
+ void PutCurrentFrame() override;
private:
// The callback for VideoFrameProvider to signal a new frame is available.
@@ -168,7 +189,6 @@ class WebMediaPlayerMS
bool current_frame_used_;
// |current_frame_lock_| protects |current_frame_used_| and |current_frame_|.
base::Lock current_frame_lock_;
- bool pending_repaint_;
scoped_ptr<cc_blink::WebLayerImpl> video_weblayer_;
diff --git a/chromium/content/renderer/media/webrtc/DEPS b/chromium/content/renderer/media/webrtc/DEPS
deleted file mode 100644
index 9d1e38610a8..00000000000
--- a/chromium/content/renderer/media/webrtc/DEPS
+++ /dev/null
@@ -1,5 +0,0 @@
-include_rules = [
- # For video cropping and scaling.
- "+third_party/libyuv",
-]
-
diff --git a/chromium/content/renderer/media/webrtc/OWNERS b/chromium/content/renderer/media/webrtc/OWNERS
index 7aa733c9da7..fb421af0efc 100644
--- a/chromium/content/renderer/media/webrtc/OWNERS
+++ b/chromium/content/renderer/media/webrtc/OWNERS
@@ -1,7 +1,5 @@
# Piranha Plant members.
-xians@chromium.org
perkj@chromium.org
-hclam@chromium.org
# To be able to roll new libjingle releases.
ronghuawu@chromium.org
diff --git a/chromium/content/renderer/media/webrtc/media_stream_remote_video_source.cc b/chromium/content/renderer/media/webrtc/media_stream_remote_video_source.cc
index 66de365164b..9fa3e5d2c0a 100644
--- a/chromium/content/renderer/media/webrtc/media_stream_remote_video_source.cc
+++ b/chromium/content/renderer/media/webrtc/media_stream_remote_video_source.cc
@@ -6,14 +6,13 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
-#include "base/debug/trace_event.h"
#include "base/location.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/threading/thread_checker.h"
-#include "content/renderer/media/native_handle_impl.h"
+#include "base/trace_event/trace_event.h"
+#include "content/renderer/media/webrtc/track_observer.h"
#include "media/base/bind_to_current_loop.h"
#include "media/base/video_frame.h"
-#include "media/base/video_frame_pool.h"
#include "media/base/video_util.h"
#include "third_party/libjingle/source/talk/media/base/videoframe.h"
@@ -36,19 +35,16 @@ class MediaStreamRemoteVideoSource::RemoteVideoSourceDelegate
// Implements webrtc::VideoRendererInterface used for receiving video frames
// from the PeerConnection video track. May be called on a libjingle internal
// thread.
- void SetSize(int width, int height) override;
void RenderFrame(const cricket::VideoFrame* frame) override;
- void DoRenderFrameOnIOThread(scoped_refptr<media::VideoFrame> video_frame,
- const media::VideoCaptureFormat& format);
+ void DoRenderFrameOnIOThread(
+ const scoped_refptr<media::VideoFrame>& video_frame);
+
private:
// Bound to the render thread.
base::ThreadChecker thread_checker_;
scoped_refptr<base::MessageLoopProxy> io_message_loop_;
- // |frame_pool_| is only accessed on whatever
- // thread webrtc::VideoRendererInterface::RenderFrame is called on.
- media::VideoFramePool frame_pool_;
// |frame_callback_| is accessed on the IO thread.
VideoCaptureDeliverFrameCB frame_callback_;
@@ -66,145 +62,67 @@ MediaStreamRemoteVideoSource::
RemoteVideoSourceDelegate::~RemoteVideoSourceDelegate() {
}
-void MediaStreamRemoteVideoSource::
-RemoteVideoSourceDelegate::SetSize(int width, int height) {
-}
-
-void MediaStreamRemoteVideoSource::
-RemoteVideoSourceDelegate::RenderFrame(
- const cricket::VideoFrame* frame) {
+void MediaStreamRemoteVideoSource::RemoteVideoSourceDelegate::RenderFrame(
+ const cricket::VideoFrame* incoming_frame) {
TRACE_EVENT0("webrtc", "RemoteVideoSourceDelegate::RenderFrame");
base::TimeDelta timestamp = base::TimeDelta::FromMicroseconds(
- frame->GetElapsedTime() / rtc::kNumNanosecsPerMicrosec);
+ incoming_frame->GetElapsedTime() / rtc::kNumNanosecsPerMicrosec);
scoped_refptr<media::VideoFrame> video_frame;
- if (frame->GetNativeHandle() != NULL) {
- NativeHandleImpl* handle =
- static_cast<NativeHandleImpl*>(frame->GetNativeHandle());
- video_frame = static_cast<media::VideoFrame*>(handle->GetHandle());
+ if (incoming_frame->GetNativeHandle() != NULL) {
+ video_frame =
+ static_cast<media::VideoFrame*>(incoming_frame->GetNativeHandle());
video_frame->set_timestamp(timestamp);
} else {
+ const cricket::VideoFrame* frame =
+ incoming_frame->GetCopyWithRotationApplied();
+
gfx::Size size(frame->GetWidth(), frame->GetHeight());
- video_frame = frame_pool_.CreateFrame(
- media::VideoFrame::YV12, size, gfx::Rect(size), size, timestamp);
// Non-square pixels are unsupported.
DCHECK_EQ(frame->GetPixelWidth(), 1u);
DCHECK_EQ(frame->GetPixelHeight(), 1u);
- int y_rows = frame->GetHeight();
- int uv_rows = frame->GetChromaHeight();
- CopyYPlane(
- frame->GetYPlane(), frame->GetYPitch(), y_rows, video_frame.get());
- CopyUPlane(
- frame->GetUPlane(), frame->GetUPitch(), uv_rows, video_frame.get());
- CopyVPlane(
- frame->GetVPlane(), frame->GetVPitch(), uv_rows, video_frame.get());
+ // Make a shallow copy. Both |frame| and |video_frame| will share a single
+ // reference counted frame buffer. Const cast and hope no one will overwrite
+ // the data.
+ // TODO(magjed): Update media::VideoFrame to support const data so we don't
+ // need to const cast here.
+ video_frame = media::VideoFrame::WrapExternalYuvData(
+ media::VideoFrame::YV12, size, gfx::Rect(size), size,
+ frame->GetYPitch(), frame->GetUPitch(), frame->GetVPitch(),
+ const_cast<uint8_t*>(frame->GetYPlane()),
+ const_cast<uint8_t*>(frame->GetUPlane()),
+ const_cast<uint8_t*>(frame->GetVPlane()), timestamp,
+ base::Bind(&base::DeletePointer<cricket::VideoFrame>, frame->Copy()));
}
- media::VideoPixelFormat pixel_format =
- (video_frame->format() == media::VideoFrame::YV12) ?
- media::PIXEL_FORMAT_YV12 : media::PIXEL_FORMAT_TEXTURE;
-
- media::VideoCaptureFormat format(
- gfx::Size(video_frame->natural_size().width(),
- video_frame->natural_size().height()),
- MediaStreamVideoSource::kUnknownFrameRate,
- pixel_format);
-
io_message_loop_->PostTask(
FROM_HERE,
base::Bind(&RemoteVideoSourceDelegate::DoRenderFrameOnIOThread,
- this, video_frame, format));
+ this, video_frame));
}
void MediaStreamRemoteVideoSource::
RemoteVideoSourceDelegate::DoRenderFrameOnIOThread(
- scoped_refptr<media::VideoFrame> video_frame,
- const media::VideoCaptureFormat& format) {
+ const scoped_refptr<media::VideoFrame>& video_frame) {
DCHECK(io_message_loop_->BelongsToCurrentThread());
TRACE_EVENT0("webrtc", "RemoteVideoSourceDelegate::DoRenderFrameOnIOThread");
// TODO(hclam): Give the estimated capture time.
- frame_callback_.Run(video_frame, format, base::TimeTicks());
-}
-
-MediaStreamRemoteVideoSource::Observer::Observer(
- const scoped_refptr<base::SingleThreadTaskRunner>& main_thread,
- webrtc::VideoTrackInterface* track)
- : main_thread_(main_thread),
-#if DCHECK_IS_ON
- source_set_(false),
-#endif
- track_(track),
- state_(track->state()) {
- track->RegisterObserver(this);
-}
-
-const scoped_refptr<webrtc::VideoTrackInterface>&
-MediaStreamRemoteVideoSource::Observer::track() {
- DCHECK(main_thread_->BelongsToCurrentThread());
- return track_;
-}
-
-webrtc::MediaStreamTrackInterface::TrackState
-MediaStreamRemoteVideoSource::Observer::state() const {
- DCHECK(main_thread_->BelongsToCurrentThread());
- return state_;
-}
-
-void MediaStreamRemoteVideoSource::Observer::Unregister() {
- DCHECK(main_thread_->BelongsToCurrentThread());
- track_->UnregisterObserver(this);
- track_ = nullptr;
-}
-
-MediaStreamRemoteVideoSource::Observer::~Observer() {
- DCHECK(main_thread_->BelongsToCurrentThread());
- DCHECK(!track_.get());
-}
-
-void MediaStreamRemoteVideoSource::Observer::SetSource(
- const base::WeakPtr<MediaStreamRemoteVideoSource>& source) {
- DCHECK(main_thread_->BelongsToCurrentThread());
- DCHECK(!source_);
- source_ = source;
-#if DCHECK_IS_ON
- // |source_set_| means that there is a MediaStreamRemoteVideoSource that
- // should handle all state changes. Since an Observer is always created when
- // a remote MediaStream changes in RemoteMediaStreamImpl::Observer::OnChanged,
- // it can happen that an Observer is created but SetSource is never called.
- source_set_ = true;
-#endif
-}
-
-void MediaStreamRemoteVideoSource::Observer::OnChanged() {
- webrtc::MediaStreamTrackInterface::TrackState state = track_->state();
- main_thread_->PostTask(FROM_HERE,
- base::Bind(&MediaStreamRemoteVideoSource::Observer::OnChangedImpl,
- this, state));
-}
-
-void MediaStreamRemoteVideoSource::Observer::OnChangedImpl(
- webrtc::MediaStreamTrackInterface::TrackState state) {
- DCHECK(main_thread_->BelongsToCurrentThread());
-#if DCHECK_IS_ON
- DCHECK(source_ || !source_set_) << "Dropping a state change event. " << state;
-#endif
- if (source_ && state != state_)
- source_->OnChanged(state);
- state_ = state;
+ frame_callback_.Run(video_frame, base::TimeTicks());
}
MediaStreamRemoteVideoSource::MediaStreamRemoteVideoSource(
- const scoped_refptr<MediaStreamRemoteVideoSource::Observer>& observer)
- : observer_(observer), weak_factory_(this) {
- observer->SetSource(weak_factory_.GetWeakPtr());
+ scoped_ptr<TrackObserver> observer)
+ : observer_(observer.Pass()) {
+ // The callback will be automatically cleared when 'observer_' goes out of
+ // scope and no further callbacks will occur.
+ observer_->SetCallback(base::Bind(&MediaStreamRemoteVideoSource::OnChanged,
+ base::Unretained(this)));
}
MediaStreamRemoteVideoSource::~MediaStreamRemoteVideoSource() {
DCHECK(CalledOnValidThread());
- observer_->Unregister();
- observer_ = nullptr;
}
void MediaStreamRemoteVideoSource::GetCurrentSupportedFormats(
@@ -221,18 +139,23 @@ void MediaStreamRemoteVideoSource::GetCurrentSupportedFormats(
void MediaStreamRemoteVideoSource::StartSourceImpl(
const media::VideoCaptureFormat& format,
+ const blink::WebMediaConstraints& constraints,
const VideoCaptureDeliverFrameCB& frame_callback) {
DCHECK(CalledOnValidThread());
DCHECK(!delegate_.get());
delegate_ = new RemoteVideoSourceDelegate(io_message_loop(), frame_callback);
- observer_->track()->AddRenderer(delegate_.get());
+ scoped_refptr<webrtc::VideoTrackInterface> video_track(
+ static_cast<webrtc::VideoTrackInterface*>(observer_->track().get()));
+ video_track->AddRenderer(delegate_.get());
OnStartDone(MEDIA_DEVICE_OK);
}
void MediaStreamRemoteVideoSource::StopSourceImpl() {
DCHECK(CalledOnValidThread());
DCHECK(state() != MediaStreamVideoSource::ENDED);
- observer_->track()->RemoveRenderer(delegate_.get());
+ scoped_refptr<webrtc::VideoTrackInterface> video_track(
+ static_cast<webrtc::VideoTrackInterface*>(observer_->track().get()));
+ video_track->RemoveRenderer(delegate_.get());
}
webrtc::VideoRendererInterface*
diff --git a/chromium/content/renderer/media/webrtc/media_stream_remote_video_source.h b/chromium/content/renderer/media/webrtc/media_stream_remote_video_source.h
index 4833da530fe..5607cd52c3c 100644
--- a/chromium/content/renderer/media/webrtc/media_stream_remote_video_source.h
+++ b/chromium/content/renderer/media/webrtc/media_stream_remote_video_source.h
@@ -14,6 +14,8 @@
namespace content {
+class TrackObserver;
+
// MediaStreamRemoteVideoSource implements the MediaStreamVideoSource interface
// for video tracks received on a PeerConnection. The purpose of the class is
// to make sure there is no difference between a video track where the source is
@@ -21,49 +23,7 @@ namespace content {
class CONTENT_EXPORT MediaStreamRemoteVideoSource
: public MediaStreamVideoSource {
public:
- class CONTENT_EXPORT Observer
- : public base::RefCountedThreadSafe<Observer>,
- NON_EXPORTED_BASE(public webrtc::ObserverInterface) {
- public:
- Observer(const scoped_refptr<base::SingleThreadTaskRunner>& main_thread,
- webrtc::VideoTrackInterface* track);
-
- const scoped_refptr<webrtc::VideoTrackInterface>& track();
- webrtc::MediaStreamTrackInterface::TrackState state() const;
-
- // This needs to be called by the owner of the observer instance before
- // the owner releases its reference.
- // The reason for this is to avoid a potential race when unregistration is
- // done from the main thread while an event is being delivered on the
- // signaling thread. If, on the main thread, we're releasing the last
- // reference to the observer and attempt to unregister from the observer's
- // dtor, and at the same time receive an OnChanged event on the signaling
- // thread, we will attempt to increment the refcount in the callback
- // from 0 to 1 while the object is being freed. Not good.
- void Unregister();
-
- private:
- friend class base::RefCountedThreadSafe<Observer>;
- ~Observer() override;
-
- friend class MediaStreamRemoteVideoSource;
- void SetSource(const base::WeakPtr<MediaStreamRemoteVideoSource>& source);
-
- // webrtc::ObserverInterface implementation.
- void OnChanged() override;
-
- void OnChangedImpl(webrtc::MediaStreamTrackInterface::TrackState state);
-
- const scoped_refptr<base::SingleThreadTaskRunner> main_thread_;
- base::WeakPtr<MediaStreamRemoteVideoSource> source_;
-#if DCHECK_IS_ON
- bool source_set_;
-#endif
- scoped_refptr<webrtc::VideoTrackInterface> track_;
- webrtc::MediaStreamTrackInterface::TrackState state_;
- };
-
- MediaStreamRemoteVideoSource(const scoped_refptr<Observer>& observer);
+ MediaStreamRemoteVideoSource(scoped_ptr<TrackObserver> observer);
virtual ~MediaStreamRemoteVideoSource();
protected:
@@ -76,6 +36,7 @@ class CONTENT_EXPORT MediaStreamRemoteVideoSource
void StartSourceImpl(
const media::VideoCaptureFormat& format,
+ const blink::WebMediaConstraints& constraints,
const VideoCaptureDeliverFrameCB& frame_callback) override;
void StopSourceImpl() override;
@@ -85,16 +46,13 @@ class CONTENT_EXPORT MediaStreamRemoteVideoSource
webrtc::VideoRendererInterface* RenderInterfaceForTest();
private:
- friend class Observer;
void OnChanged(webrtc::MediaStreamTrackInterface::TrackState state);
- scoped_refptr<Observer> observer_;
-
// Internal class used for receiving frames from the webrtc track on a
// libjingle thread and forward it to the IO-thread.
class RemoteVideoSourceDelegate;
scoped_refptr<RemoteVideoSourceDelegate> delegate_;
- base::WeakPtrFactory<MediaStreamRemoteVideoSource> weak_factory_;
+ scoped_ptr<TrackObserver> observer_;
DISALLOW_COPY_AND_ASSIGN(MediaStreamRemoteVideoSource);
};
diff --git a/chromium/content/renderer/media/webrtc/media_stream_remote_video_source_unittest.cc b/chromium/content/renderer/media/webrtc/media_stream_remote_video_source_unittest.cc
index 4026f43c5f4..c5ab00e050f 100644
--- a/chromium/content/renderer/media/webrtc/media_stream_remote_video_source_unittest.cc
+++ b/chromium/content/renderer/media/webrtc/media_stream_remote_video_source_unittest.cc
@@ -11,6 +11,7 @@
#include "content/renderer/media/mock_media_stream_video_sink.h"
#include "content/renderer/media/webrtc/media_stream_remote_video_source.h"
#include "content/renderer/media/webrtc/mock_peer_connection_dependency_factory.h"
+#include "content/renderer/media/webrtc/track_observer.h"
#include "media/base/video_frame.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/public/web/WebHeap.h"
@@ -25,8 +26,9 @@ ACTION_P(RunClosure, closure) {
class MediaStreamRemoteVideoSourceUnderTest
: public MediaStreamRemoteVideoSource {
public:
- MediaStreamRemoteVideoSourceUnderTest(const scoped_refptr<Observer>& observer)
- : MediaStreamRemoteVideoSource(observer) {
+ explicit MediaStreamRemoteVideoSourceUnderTest(
+ scoped_ptr<TrackObserver> observer)
+ : MediaStreamRemoteVideoSource(observer.Pass()) {
}
using MediaStreamRemoteVideoSource::RenderInterfaceForTest;
};
@@ -40,14 +42,16 @@ class MediaStreamRemoteVideoSourceTest
webrtc_video_track_(mock_factory_->CreateLocalVideoTrack(
"test",
static_cast<cricket::VideoCapturer*>(NULL))),
- observer_(new MediaStreamRemoteVideoSource::Observer(
- base::ThreadTaskRunnerHandle::Get(), webrtc_video_track_.get())),
- remote_source_(new MediaStreamRemoteVideoSourceUnderTest(observer_)),
+ remote_source_(new MediaStreamRemoteVideoSourceUnderTest(
+ scoped_ptr<TrackObserver>(
+ new TrackObserver(base::ThreadTaskRunnerHandle::Get(),
+ webrtc_video_track_.get())).Pass())),
number_of_successful_constraints_applied_(0),
number_of_failed_constraints_applied_(0) {
webkit_source_.initialize(base::UTF8ToUTF16("dummy_source_id"),
blink::WebMediaStreamSource::TypeVideo,
- base::UTF8ToUTF16("dummy_source_name"));
+ base::UTF8ToUTF16("dummy_source_name"),
+ true /* remote */ , true /* readonly */);
webkit_source_.setExtraData(remote_source_);
}
@@ -105,7 +109,6 @@ class MediaStreamRemoteVideoSourceTest
scoped_ptr<ChildProcess> child_process_;
scoped_ptr<MockPeerConnectionDependencyFactory> mock_factory_;
scoped_refptr<webrtc::VideoTrackInterface> webrtc_video_track_;
- scoped_refptr<MediaStreamRemoteVideoSource::Observer> observer_;
// |remote_source_| is owned by |webkit_source_|.
MediaStreamRemoteVideoSourceUnderTest* remote_source_;
blink::WebMediaStreamSource webkit_source_;
diff --git a/chromium/content/renderer/media/webrtc/media_stream_track_metrics.cc b/chromium/content/renderer/media/webrtc/media_stream_track_metrics.cc
index d6962c3f91c..0ec4444582b 100644
--- a/chromium/content/renderer/media/webrtc/media_stream_track_metrics.cc
+++ b/chromium/content/renderer/media/webrtc/media_stream_track_metrics.cc
@@ -389,7 +389,7 @@ uint64 MediaStreamTrackMetrics::MakeUniqueIdImpl(uint64 pc_id,
base::MD5Digest digest;
base::MD5Final(&digest, &ctx);
- COMPILE_ASSERT(sizeof(digest.a) > sizeof(uint64), NeedBiggerDigest);
+ static_assert(sizeof(digest.a) > sizeof(uint64), "need a bigger digest");
return *reinterpret_cast<uint64*>(digest.a);
}
diff --git a/chromium/content/renderer/media/webrtc/mock_peer_connection_dependency_factory.cc b/chromium/content/renderer/media/webrtc/mock_peer_connection_dependency_factory.cc
index ca3f29851a3..183b003f2cb 100644
--- a/chromium/content/renderer/media/webrtc/mock_peer_connection_dependency_factory.cc
+++ b/chromium/content/renderer/media/webrtc/mock_peer_connection_dependency_factory.cc
@@ -218,6 +218,13 @@ void MockVideoSource::RemoveSink(cricket::VideoRenderer* output) {
NOTIMPLEMENTED();
}
+void MockVideoSource::Stop() {
+ NOTIMPLEMENTED();
+}
+void MockVideoSource::Restart() {
+ NOTIMPLEMENTED();
+}
+
cricket::VideoRenderer* MockVideoSource::FrameInput() {
return &renderer_;
}
@@ -511,7 +518,8 @@ MockPeerConnectionDependencyFactory::CreateIceCandidate(
scoped_refptr<WebRtcAudioCapturer>
MockPeerConnectionDependencyFactory::CreateAudioCapturer(
- int render_view_id, const StreamDeviceInfo& device_info,
+ int render_frame_id,
+ const StreamDeviceInfo& device_info,
const blink::WebMediaConstraints& constraints,
MediaStreamAudioSource* audio_source) {
if (fail_to_create_next_audio_capturer_) {
@@ -519,8 +527,8 @@ MockPeerConnectionDependencyFactory::CreateAudioCapturer(
return NULL;
}
DCHECK(audio_source);
- return WebRtcAudioCapturer::CreateCapturer(-1, device_info,
- constraints, NULL, audio_source);
+ return WebRtcAudioCapturer::CreateCapturer(-1, device_info, constraints, NULL,
+ audio_source);
}
void MockPeerConnectionDependencyFactory::StartLocalAudioTrack(
diff --git a/chromium/content/renderer/media/webrtc/mock_peer_connection_dependency_factory.h b/chromium/content/renderer/media/webrtc/mock_peer_connection_dependency_factory.h
index b04282411c7..24b6a28cadf 100644
--- a/chromium/content/renderer/media/webrtc/mock_peer_connection_dependency_factory.h
+++ b/chromium/content/renderer/media/webrtc/mock_peer_connection_dependency_factory.h
@@ -48,6 +48,8 @@ class MockVideoSource : public webrtc::VideoSourceInterface {
void RemoveSink(cricket::VideoRenderer* output) override;
cricket::VideoRenderer* FrameInput() override;
const cricket::VideoOptions* options() const override;
+ void Stop() override;
+ void Restart() override;
// Changes the state of the source to live and notifies the observer.
void SetLive();
@@ -205,7 +207,7 @@ class MockPeerConnectionDependencyFactory
const std::string& sdp) override;
scoped_refptr<WebRtcAudioCapturer> CreateAudioCapturer(
- int render_view_id,
+ int render_frame_id,
const StreamDeviceInfo& device_info,
const blink::WebMediaConstraints& constraints,
MediaStreamAudioSource* audio_source) override;
diff --git a/chromium/content/renderer/media/webrtc/peer_connection_dependency_factory.cc b/chromium/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
index 1bc3c0536a0..b3d3283518c 100644
--- a/chromium/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
+++ b/chromium/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
@@ -11,6 +11,7 @@
#include "base/synchronization/waitable_event.h"
#include "content/common/media/media_stream_messages.h"
#include "content/public/common/content_switches.h"
+#include "content/public/common/renderer_preferences.h"
#include "content/renderer/media/media_stream.h"
#include "content/renderer/media/media_stream_audio_processor.h"
#include "content/renderer/media/media_stream_audio_processor_options.h"
@@ -33,8 +34,9 @@
#include "content/renderer/p2p/ipc_socket_factory.h"
#include "content/renderer/p2p/port_allocator.h"
#include "content/renderer/render_thread_impl.h"
+#include "content/renderer/render_view_impl.h"
#include "jingle/glue/thread_wrapper.h"
-#include "media/filters/gpu_video_accelerator_factories.h"
+#include "media/renderers/gpu_video_accelerator_factories.h"
#include "third_party/WebKit/public/platform/WebMediaConstraints.h"
#include "third_party/WebKit/public/platform/WebMediaStream.h"
#include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
@@ -114,14 +116,16 @@ void HarmonizeConstraintsAndEffects(RTCMediaConstraints* constraints,
class P2PPortAllocatorFactory : public webrtc::PortAllocatorFactoryInterface {
public:
- P2PPortAllocatorFactory(
- P2PSocketDispatcher* socket_dispatcher,
- rtc::NetworkManager* network_manager,
- rtc::PacketSocketFactory* socket_factory)
+ P2PPortAllocatorFactory(P2PSocketDispatcher* socket_dispatcher,
+ rtc::NetworkManager* network_manager,
+ rtc::PacketSocketFactory* socket_factory,
+ const GURL& origin,
+ bool enable_multiple_routes)
: socket_dispatcher_(socket_dispatcher),
network_manager_(network_manager),
- socket_factory_(socket_factory) {
- }
+ socket_factory_(socket_factory),
+ origin_(origin),
+ enable_multiple_routes_(enable_multiple_routes) {}
cricket::PortAllocator* CreatePortAllocator(
const std::vector<StunConfiguration>& stun_servers,
@@ -147,9 +151,11 @@ class P2PPortAllocatorFactory : public webrtc::PortAllocatorFactoryInterface {
turn_configurations[i].server.hostname(),
turn_configurations[i].server.port()));
}
+ config.enable_multiple_routes = enable_multiple_routes_;
return new P2PPortAllocator(
- socket_dispatcher_.get(), network_manager_, socket_factory_, config);
+ socket_dispatcher_.get(), network_manager_,
+ socket_factory_, config, origin_);
}
protected:
@@ -161,6 +167,12 @@ class P2PPortAllocatorFactory : public webrtc::PortAllocatorFactoryInterface {
// PeerConnectionDependencyFactory.
rtc::NetworkManager* network_manager_;
rtc::PacketSocketFactory* socket_factory_;
+ // The origin URL of the WebFrame that created the
+ // P2PPortAllocatorFactory.
+ GURL origin_;
+ // When false, only 'any' address (all 0s) will be bound for address
+ // discovery.
+ bool enable_multiple_routes_;
};
PeerConnectionDependencyFactory::PeerConnectionDependencyFactory(
@@ -174,9 +186,8 @@ PeerConnectionDependencyFactory::PeerConnectionDependencyFactory(
}
PeerConnectionDependencyFactory::~PeerConnectionDependencyFactory() {
- CleanupPeerConnectionFactory();
- if (aec_dump_message_filter_.get())
- aec_dump_message_filter_->RemoveDelegate(this);
+ DVLOG(1) << "~PeerConnectionDependencyFactory()";
+ DCHECK(pc_factory_ == NULL);
}
blink::WebRTCPeerConnectionHandler*
@@ -191,7 +202,7 @@ PeerConnectionDependencyFactory::CreateRTCPeerConnectionHandler(
}
bool PeerConnectionDependencyFactory::InitializeMediaStreamAudioSource(
- int render_view_id,
+ int render_frame_id,
const blink::WebMediaConstraints& audio_constraints,
MediaStreamAudioSource* source_data) {
DVLOG(1) << "InitializeMediaStreamAudioSources()";
@@ -207,9 +218,8 @@ bool PeerConnectionDependencyFactory::InitializeMediaStreamAudioSource(
HarmonizeConstraintsAndEffects(&constraints,
&device_info.device.input.effects);
- scoped_refptr<WebRtcAudioCapturer> capturer(
- CreateAudioCapturer(render_view_id, device_info, audio_constraints,
- source_data));
+ scoped_refptr<WebRtcAudioCapturer> capturer(CreateAudioCapturer(
+ render_frame_id, device_info, audio_constraints, source_data));
if (!capturer.get()) {
const std::string log_string =
"PCDF::InitializeMediaStreamAudioSource: fails to create capturer";
@@ -268,6 +278,11 @@ PeerConnectionDependencyFactory::GetPcFactory() {
return pc_factory_;
}
+
+void PeerConnectionDependencyFactory::WillDestroyCurrentMessageLoop() {
+ CleanupPeerConnectionFactory();
+}
+
void PeerConnectionDependencyFactory::CreatePeerConnectionFactory() {
DCHECK(!pc_factory_.get());
DCHECK(!signaling_thread_);
@@ -279,6 +294,7 @@ void PeerConnectionDependencyFactory::CreatePeerConnectionFactory() {
DVLOG(1) << "PeerConnectionDependencyFactory::CreatePeerConnectionFactory()";
+ base::MessageLoop::current()->AddDestructionObserver(this);
// To allow sending to the signaling/worker threads.
jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop();
jingle_glue::JingleThreadWrapper::current()->set_send_allowed(true);
@@ -323,17 +339,6 @@ void PeerConnectionDependencyFactory::CreatePeerConnectionFactory() {
RenderThreadImpl::current()->GetGpuFactories(),
&start_signaling_event));
- // TODO(xians): Remove the following code after kDisableAudioTrackProcessing
- // is removed.
- if (!MediaStreamAudioProcessor::IsAudioTrackProcessingEnabled()) {
- aec_dump_message_filter_ = AecDumpMessageFilter::Get();
- // In unit tests not creating a message filter, |aec_dump_message_filter_|
- // will be NULL. We can just ignore that. Other unit tests and browser tests
- // ensure that we do get the filter when we should.
- if (aec_dump_message_filter_.get())
- aec_dump_message_filter_->AddDelegate(this);
- }
-
start_signaling_event.Wait();
CHECK(signaling_thread_);
}
@@ -357,7 +362,7 @@ void PeerConnectionDependencyFactory::InitializeSignalingThread(
scoped_ptr<cricket::WebRtcVideoDecoderFactory> decoder_factory;
scoped_ptr<cricket::WebRtcVideoEncoderFactory> encoder_factory;
- const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
+ const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
if (gpu_factories.get()) {
if (!cmd_line->HasSwitch(switches::kDisableWebRtcHWDecoding))
decoder_factory.reset(new RTCVideoDecoderFactory(gpu_factories));
@@ -400,11 +405,22 @@ PeerConnectionDependencyFactory::CreatePeerConnection(
if (!GetPcFactory().get())
return NULL;
+ // Copy the flag from Preference associated with this WebFrame.
+ bool enable_multiple_routes = true;
+ if (web_frame && web_frame->view()) {
+ RenderViewImpl* renderer_view_impl =
+ RenderViewImpl::FromWebView(web_frame->view());
+ if (renderer_view_impl) {
+ enable_multiple_routes = renderer_view_impl->renderer_preferences()
+ .enable_webrtc_multiple_routes;
+ }
+ }
+
scoped_refptr<P2PPortAllocatorFactory> pa_factory =
- new rtc::RefCountedObject<P2PPortAllocatorFactory>(
- p2p_socket_dispatcher_.get(),
- network_manager_,
- socket_factory_.get());
+ new rtc::RefCountedObject<P2PPortAllocatorFactory>(
+ p2p_socket_dispatcher_.get(), network_manager_, socket_factory_.get(),
+ GURL(web_frame->document().url().spec()).GetOrigin(),
+ enable_multiple_routes);
PeerConnectionIdentityService* identity_service =
new PeerConnectionIdentityService(
@@ -476,12 +492,6 @@ void PeerConnectionDependencyFactory::CreateLocalAudioTrack(
void PeerConnectionDependencyFactory::StartLocalAudioTrack(
WebRtcLocalAudioTrack* audio_track) {
- // Add the WebRtcAudioDevice as the sink to the local audio track.
- // TODO(xians): Remove the following line of code after the APM in WebRTC is
- // completely deprecated. See http://crbug/365672.
- if (!MediaStreamAudioProcessor::IsAudioTrackProcessingEnabled())
- audio_track->AddSink(GetWebRtcAudioDevice());
-
// Start the audio track. This will hook the |audio_track| to the capturer
// as the sink of the audio, and only start the source of the capturer if
// it is the first audio track connecting to the capturer.
@@ -494,7 +504,7 @@ PeerConnectionDependencyFactory::CreateWebAudioSource(
DVLOG(1) << "PeerConnectionDependencyFactory::CreateWebAudioSource()";
scoped_refptr<WebAudioCapturerSource>
- webaudio_capturer_source(new WebAudioCapturerSource());
+ webaudio_capturer_source(new WebAudioCapturerSource(*source));
MediaStreamAudioSource* source_data = new MediaStreamAudioSource();
// Use the current default capturer for the WebAudio track so that the
@@ -584,6 +594,7 @@ void PeerConnectionDependencyFactory::DeleteIpcNetworkManager() {
}
void PeerConnectionDependencyFactory::CleanupPeerConnectionFactory() {
+ DVLOG(1) << "PeerConnectionDependencyFactory::CleanupPeerConnectionFactory()";
pc_factory_ = NULL;
if (network_manager_) {
// The network manager needs to free its resources on the thread they were
@@ -604,20 +615,19 @@ void PeerConnectionDependencyFactory::CleanupPeerConnectionFactory() {
scoped_refptr<WebRtcAudioCapturer>
PeerConnectionDependencyFactory::CreateAudioCapturer(
- int render_view_id,
+ int render_frame_id,
const StreamDeviceInfo& device_info,
const blink::WebMediaConstraints& constraints,
MediaStreamAudioSource* audio_source) {
// TODO(xians): Handle the cases when gUM is called without a proper render
// view, for example, by an extension.
- DCHECK_GE(render_view_id, 0);
+ DCHECK_GE(render_frame_id, 0);
EnsureWebRtcAudioDeviceImpl();
DCHECK(GetWebRtcAudioDevice());
- return WebRtcAudioCapturer::CreateCapturer(render_view_id, device_info,
- constraints,
- GetWebRtcAudioDevice(),
- audio_source);
+ return WebRtcAudioCapturer::CreateCapturer(
+ render_frame_id, device_info, constraints, GetWebRtcAudioDevice(),
+ audio_source);
}
scoped_refptr<base::MessageLoopProxy>
@@ -632,32 +642,6 @@ PeerConnectionDependencyFactory::GetWebRtcSignalingThread() const {
return chrome_signaling_thread_.message_loop_proxy();
}
-void PeerConnectionDependencyFactory::OnAecDumpFile(
- const IPC::PlatformFileForTransit& file_handle) {
- DCHECK(CalledOnValidThread());
- DCHECK(!MediaStreamAudioProcessor::IsAudioTrackProcessingEnabled());
- DCHECK(PeerConnectionFactoryCreated());
-
- base::File file = IPC::PlatformFileForTransitToFile(file_handle);
- DCHECK(file.IsValid());
-
- // |pc_factory_| always takes ownership of |aec_dump_file|. If StartAecDump()
- // fails, |aec_dump_file| will be closed.
- if (!GetPcFactory()->StartAecDump(file.TakePlatformFile()))
- VLOG(1) << "Could not start AEC dump.";
-}
-
-void PeerConnectionDependencyFactory::OnDisableAecDump() {
- DCHECK(CalledOnValidThread());
- DCHECK(!MediaStreamAudioProcessor::IsAudioTrackProcessingEnabled());
- // Do nothing. We never disable AEC dump for non-track-processing case.
-}
-
-void PeerConnectionDependencyFactory::OnIpcClosing() {
- DCHECK(CalledOnValidThread());
- aec_dump_message_filter_ = NULL;
-}
-
void PeerConnectionDependencyFactory::EnsureWebRtcAudioDeviceImpl() {
if (audio_device_.get())
return;
diff --git a/chromium/content/renderer/media/webrtc/peer_connection_dependency_factory.h b/chromium/content/renderer/media/webrtc/peer_connection_dependency_factory.h
index 67eae9d0ec4..65fef8f5fb3 100644
--- a/chromium/content/renderer/media/webrtc/peer_connection_dependency_factory.h
+++ b/chromium/content/renderer/media/webrtc/peer_connection_dependency_factory.h
@@ -9,6 +9,7 @@
#include "base/basictypes.h"
#include "base/files/file.h"
+#include "base/message_loop/message_loop.h"
#include "base/threading/thread.h"
#include "content/common/content_export.h"
#include "content/public/renderer/render_process_observer.h"
@@ -55,12 +56,12 @@ struct StreamDeviceInfo;
// Object factory for RTC PeerConnections.
class CONTENT_EXPORT PeerConnectionDependencyFactory
- : NON_EXPORTED_BASE(public base::NonThreadSafe),
- NON_EXPORTED_BASE(public AecDumpMessageFilter::AecDumpDelegate) {
+ : NON_EXPORTED_BASE(base::MessageLoop::DestructionObserver),
+ NON_EXPORTED_BASE(public base::NonThreadSafe) {
public:
PeerConnectionDependencyFactory(
P2PSocketDispatcher* p2p_socket_dispatcher);
- virtual ~PeerConnectionDependencyFactory();
+ ~PeerConnectionDependencyFactory() override;
// Create a RTCPeerConnectionHandler object that implements the
// WebKit WebRTCPeerConnectionHandler interface.
@@ -74,7 +75,7 @@ class CONTENT_EXPORT PeerConnectionDependencyFactory
// InitializeMediaStreamAudioSource initialize a MediaStream source object
// for audio input.
bool InitializeMediaStreamAudioSource(
- int render_view_id,
+ int render_frame_id,
const blink::WebMediaConstraints& audio_constraints,
MediaStreamAudioSource* source_data);
@@ -126,13 +127,6 @@ class CONTENT_EXPORT PeerConnectionDependencyFactory
scoped_refptr<base::MessageLoopProxy> GetWebRtcWorkerThread() const;
scoped_refptr<base::MessageLoopProxy> GetWebRtcSignalingThread() const;
- // AecDumpMessageFilter::AecDumpDelegate implementation.
- // TODO(xians): Remove when option to disable audio track processing is
- // removed.
- void OnAecDumpFile(const IPC::PlatformFileForTransit& file_handle) override;
- void OnDisableAecDump() override;
- void OnIpcClosing() override;
-
protected:
// Asks the PeerConnection factory to create a Local Audio Source.
virtual scoped_refptr<webrtc::AudioSourceInterface>
@@ -156,11 +150,12 @@ class CONTENT_EXPORT PeerConnectionDependencyFactory
GetPcFactory();
virtual bool PeerConnectionFactoryCreated();
- // Returns a new capturer or existing capturer based on the |render_view_id|
- // and |device_info|. When the |render_view_id| and |device_info| are valid,
- // it reuses existing capture if any; otherwise it creates a new capturer.
+ // Returns a new capturer or existing capturer based on the |render_frame_id|
+ // and |device_info|; if both are valid, it reuses existing capture if any --
+ // otherwise it creates a new capturer.
virtual scoped_refptr<WebRtcAudioCapturer> CreateAudioCapturer(
- int render_view_id, const StreamDeviceInfo& device_info,
+ int render_frame_id,
+ const StreamDeviceInfo& device_info,
const blink::WebMediaConstraints& constraints,
MediaStreamAudioSource* audio_source);
@@ -170,6 +165,11 @@ class CONTENT_EXPORT PeerConnectionDependencyFactory
virtual void StartLocalAudioTrack(WebRtcLocalAudioTrack* audio_track);
private:
+ // Implement base::MessageLoop::DestructionObserver.
+ // This makes sure the libjingle PeerConnectionFactory is released before
+ // the renderer message loop is destroyed.
+ void WillDestroyCurrentMessageLoop() override;
+
// Creates |pc_factory_|, which in turn is used for
// creating PeerConnection objects.
void CreatePeerConnectionFactory();
@@ -198,11 +198,6 @@ class CONTENT_EXPORT PeerConnectionDependencyFactory
scoped_refptr<P2PSocketDispatcher> p2p_socket_dispatcher_;
scoped_refptr<WebRtcAudioDeviceImpl> audio_device_;
- // This is only used if audio track processing is disabled.
- // TODO(xians): Remove when option to disable audio track processing is
- // removed.
- scoped_refptr<AecDumpMessageFilter> aec_dump_message_filter_;
-
// PeerConnection threads. signaling_thread_ is created from the
// "current" chrome thread.
rtc::Thread* signaling_thread_;
diff --git a/chromium/content/renderer/media/webrtc/track_observer.cc b/chromium/content/renderer/media/webrtc/track_observer.cc
new file mode 100644
index 00000000000..c8ef2d3c52f
--- /dev/null
+++ b/chromium/content/renderer/media/webrtc/track_observer.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/renderer/media/webrtc/track_observer.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/threading/thread_checker.h"
+
+namespace content {
+
+class CONTENT_EXPORT TrackObserver::TrackObserverImpl
+ : public base::RefCountedThreadSafe<TrackObserver::TrackObserverImpl>,
+ NON_EXPORTED_BASE(public webrtc::ObserverInterface) {
+ public:
+ TrackObserverImpl(
+ const scoped_refptr<base::SingleThreadTaskRunner>& main_thread,
+ const scoped_refptr<webrtc::MediaStreamTrackInterface>& track)
+ : main_thread_(main_thread), track_(track) {
+ // We're on the signaling thread.
+ track->RegisterObserver(this);
+ }
+
+ const scoped_refptr<webrtc::MediaStreamTrackInterface>& track() const {
+ return track_;
+ }
+
+ const scoped_refptr<base::SingleThreadTaskRunner> main_thread() const {
+ return main_thread_;
+ }
+
+ protected:
+ friend class TrackObserver;
+ void SetCallback(const OnChangedCallback& callback) {
+ DCHECK(main_thread_->BelongsToCurrentThread());
+ DCHECK(callback_.is_null());
+ DCHECK(!callback.is_null());
+ callback_ = callback;
+ }
+
+ // This needs to be called by the owner of the observer instance before
+ // the owner releases its reference.
+ // The reason for this is to avoid a potential race when unregistration is
+ // done from the main thread while an event is being delivered on the
+ // signaling thread. If, on the main thread, we're releasing the last
+ // reference to the observer and attempt to unregister from the observer's
+ // dtor, and at the same time receive an OnChanged event on the signaling
+ // thread, we will attempt to increment the refcount in the callback
+ // from 0 to 1 while the object is being freed. Not good.
+ void Unregister() {
+ DCHECK(main_thread_->BelongsToCurrentThread());
+ callback_.Reset();
+ track_->UnregisterObserver(this);
+ // At this point we're guaranteed to not get further callbacks, so it's
+ // OK to reset the pointer.
+ track_ = nullptr;
+ }
+
+ private:
+ friend class base::RefCountedThreadSafe<TrackObserverImpl>;
+ ~TrackObserverImpl() override {
+ DCHECK(!track_.get()) << "must have been unregistered before deleting";
+ }
+
+ // webrtc::ObserverInterface implementation.
+ void OnChanged() override {
+ DCHECK(signaling_thread_.CalledOnValidThread());
+ webrtc::MediaStreamTrackInterface::TrackState state = track_->state();
+ main_thread_->PostTask(FROM_HERE,
+ base::Bind(&TrackObserverImpl::OnChangedOnMainThread, this, state));
+ }
+
+ void OnChangedOnMainThread(
+ webrtc::MediaStreamTrackInterface::TrackState state) {
+ DCHECK(main_thread_->BelongsToCurrentThread());
+ if (!callback_.is_null())
+ callback_.Run(state);
+ }
+
+ const scoped_refptr<base::SingleThreadTaskRunner> main_thread_;
+ scoped_refptr<webrtc::MediaStreamTrackInterface> track_;
+ OnChangedCallback callback_; // Only touched on the main thread.
+ base::ThreadChecker signaling_thread_;
+};
+
+TrackObserver::TrackObserver(
+ const scoped_refptr<base::SingleThreadTaskRunner>& main_thread,
+ const scoped_refptr<webrtc::MediaStreamTrackInterface>& track)
+ : observer_(new TrackObserverImpl(main_thread, track)) {
+}
+
+TrackObserver::~TrackObserver() {
+ // Explicitly unregister before releasing our reference.
+ // We do this to avoid a race that could happen if we try to unregister
+ // inside the dtor of the observer and then receive an event that causes
+ // the ref count to go up while being destroyed.
+ observer_->Unregister();
+}
+
+void TrackObserver::SetCallback(const OnChangedCallback& callback) {
+ DCHECK(observer_->main_thread()->BelongsToCurrentThread());
+ observer_->SetCallback(callback);
+}
+
+const scoped_refptr<webrtc::MediaStreamTrackInterface>&
+TrackObserver::track() const {
+ return observer_->track();
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/media/webrtc/track_observer.h b/chromium/content/renderer/media/webrtc/track_observer.h
new file mode 100644
index 00000000000..0a39805ba03
--- /dev/null
+++ b/chromium/content/renderer/media/webrtc/track_observer.h
@@ -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.
+
+#ifndef CONTENT_RENDERER_MEDIA_WEBRTC_TRACK_OBSERVER_H_
+#define CONTENT_RENDERER_MEDIA_WEBRTC_TRACK_OBSERVER_H_
+
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
+#include "content/common/content_export.h"
+#include "third_party/libjingle/source/talk/app/webrtc/mediastreaminterface.h"
+
+namespace content {
+
+class CONTENT_EXPORT TrackObserver {
+ public:
+ typedef base::Callback<void(webrtc::MediaStreamTrackInterface::TrackState)>
+ OnChangedCallback;
+
+ TrackObserver(const scoped_refptr<base::SingleThreadTaskRunner>& main_thread,
+ const scoped_refptr<webrtc::MediaStreamTrackInterface>& track);
+ ~TrackObserver();
+
+ void SetCallback(const OnChangedCallback& callback);
+
+ const scoped_refptr<webrtc::MediaStreamTrackInterface>& track() const;
+
+ private:
+ class TrackObserverImpl;
+ const scoped_refptr<TrackObserverImpl> observer_;
+ DISALLOW_COPY_AND_ASSIGN(TrackObserver);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_MEDIA_WEBRTC_TRACK_OBSERVER_H_
diff --git a/chromium/content/renderer/media/webrtc/video_destination_handler.cc b/chromium/content/renderer/media/webrtc/video_destination_handler.cc
index 6e254699f83..febc4e0b78f 100644
--- a/chromium/content/renderer/media/webrtc/video_destination_handler.cc
+++ b/chromium/content/renderer/media/webrtc/video_destination_handler.cc
@@ -7,16 +7,16 @@
#include <string>
#include "base/base64.h"
-#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/rand_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/trace_event/trace_event.h"
#include "content/renderer/media/media_stream.h"
#include "content/renderer/media/media_stream_registry_interface.h"
#include "content/renderer/media/media_stream_video_track.h"
#include "content/renderer/pepper/ppb_image_data_impl.h"
#include "content/renderer/render_thread_impl.h"
-#include "media/video/capture/video_capture_types.h"
+#include "media/base/video_capture_types.h"
#include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
#include "third_party/WebKit/public/platform/WebURL.h"
#include "third_party/WebKit/public/web/WebMediaStreamRegistry.h"
@@ -32,14 +32,12 @@ class PpFrameWriter::FrameWriterDelegate
const scoped_refptr<base::MessageLoopProxy>& io_message_loop_proxy,
const VideoCaptureDeliverFrameCB& new_frame_callback);
- void DeliverFrame(const scoped_refptr<media::VideoFrame>& frame,
- const media::VideoCaptureFormat& format);
+ void DeliverFrame(const scoped_refptr<media::VideoFrame>& frame);
private:
friend class base::RefCountedThreadSafe<FrameWriterDelegate>;
virtual ~FrameWriterDelegate();
- void DeliverFrameOnIO(const scoped_refptr<media::VideoFrame>& frame,
- const media::VideoCaptureFormat& format);
+ void DeliverFrameOnIO(const scoped_refptr<media::VideoFrame>& frame);
scoped_refptr<base::MessageLoopProxy> io_message_loop_;
VideoCaptureDeliverFrameCB new_frame_callback_;
@@ -56,21 +54,18 @@ PpFrameWriter::FrameWriterDelegate::~FrameWriterDelegate() {
}
void PpFrameWriter::FrameWriterDelegate::DeliverFrame(
- const scoped_refptr<media::VideoFrame>& frame,
- const media::VideoCaptureFormat& format) {
+ const scoped_refptr<media::VideoFrame>& frame) {
io_message_loop_->PostTask(
FROM_HERE,
- base::Bind(&FrameWriterDelegate::DeliverFrameOnIO,
- this, frame, format));
+ base::Bind(&FrameWriterDelegate::DeliverFrameOnIO, this, frame));
}
void PpFrameWriter::FrameWriterDelegate::DeliverFrameOnIO(
- const scoped_refptr<media::VideoFrame>& frame,
- const media::VideoCaptureFormat& format) {
+ const scoped_refptr<media::VideoFrame>& frame) {
DCHECK(io_message_loop_->BelongsToCurrentThread());
// The local time when this frame is generated is unknown so give a null
// value to |estimated_capture_time|.
- new_frame_callback_.Run(frame, format, base::TimeTicks());
+ new_frame_callback_.Run(frame, base::TimeTicks());
}
PpFrameWriter::PpFrameWriter() {
@@ -96,6 +91,7 @@ void PpFrameWriter::GetCurrentSupportedFormats(
void PpFrameWriter::StartSourceImpl(
const media::VideoCaptureFormat& format,
+ const blink::WebMediaConstraints& constraints,
const VideoCaptureDeliverFrameCB& frame_callback) {
DCHECK(CalledOnValidThread());
DCHECK(!delegate_.get());
@@ -152,10 +148,6 @@ void PpFrameWriter::PutFrame(PPB_ImageData_Impl* image_data,
scoped_refptr<media::VideoFrame> new_frame =
frame_pool_.CreateFrame(media::VideoFrame::YV12, frame_size,
gfx::Rect(frame_size), frame_size, timestamp);
- media::VideoCaptureFormat format(
- frame_size,
- MediaStreamVideoSource::kUnknownFrameRate,
- media::PIXEL_FORMAT_YV12);
libyuv::ARGBToI420(src_data,
src_stride,
@@ -168,7 +160,7 @@ void PpFrameWriter::PutFrame(PPB_ImageData_Impl* image_data,
width,
height);
- delegate_->DeliverFrame(new_frame, format);
+ delegate_->DeliverFrame(new_frame);
}
// PpFrameWriterProxy is a helper class to make sure the user won't use
@@ -181,10 +173,9 @@ class PpFrameWriterProxy : public FrameWriterInterface {
DCHECK(writer_ != NULL);
}
- virtual ~PpFrameWriterProxy() {}
+ ~PpFrameWriterProxy() override {}
- virtual void PutFrame(PPB_ImageData_Impl* image_data,
- int64 time_stamp_ns) override {
+ void PutFrame(PPB_ImageData_Impl* image_data, int64 time_stamp_ns) override {
writer_->PutFrame(image_data, time_stamp_ns);
}
@@ -227,7 +218,8 @@ bool VideoDestinationHandler::Open(
blink::WebMediaStreamSource::Type type =
blink::WebMediaStreamSource::TypeVideo;
blink::WebString webkit_track_id = base::UTF8ToUTF16(track_id);
- webkit_source.initialize(webkit_track_id, type, webkit_track_id);
+ webkit_source.initialize(webkit_track_id, type, webkit_track_id,
+ false /* remote */, true /* readonly */);
webkit_source.setExtraData(writer);
blink::WebMediaConstraints constraints;
diff --git a/chromium/content/renderer/media/webrtc/video_destination_handler.h b/chromium/content/renderer/media/webrtc/video_destination_handler.h
index 2855e6feb82..c71ae69df27 100644
--- a/chromium/content/renderer/media/webrtc/video_destination_handler.h
+++ b/chromium/content/renderer/media/webrtc/video_destination_handler.h
@@ -45,8 +45,8 @@ class CONTENT_EXPORT PpFrameWriter
// FrameWriterInterface implementation.
// This method will be called by the Pepper host from render thread.
- virtual void PutFrame(PPB_ImageData_Impl* image_data,
- int64 time_stamp_ns) override;
+ void PutFrame(PPB_ImageData_Impl* image_data, int64 time_stamp_ns) override;
+
protected:
// MediaStreamVideoSource implementation.
void GetCurrentSupportedFormats(
@@ -56,6 +56,7 @@ class CONTENT_EXPORT PpFrameWriter
const VideoCaptureDeviceFormatsCB& callback) override;
void StartSourceImpl(
const media::VideoCaptureFormat& format,
+ const blink::WebMediaConstraints& constraints,
const VideoCaptureDeliverFrameCB& frame_callback) override;
void StopSourceImpl() override;
@@ -89,4 +90,4 @@ class CONTENT_EXPORT VideoDestinationHandler {
} // namespace content
-#endif // CONTENT_RENDERER_MEDIA_VIDEO_DESTINATION_HANDLER_H_
+#endif // CONTENT_RENDERER_MEDIA_WEBRTC_VIDEO_DESTINATION_HANDLER_H_
diff --git a/chromium/content/renderer/media/webrtc/video_destination_handler_unittest.cc b/chromium/content/renderer/media/webrtc/video_destination_handler_unittest.cc
index 806b6f468cd..3635841c101 100644
--- a/chromium/content/renderer/media/webrtc/video_destination_handler_unittest.cc
+++ b/chromium/content/renderer/media/webrtc/video_destination_handler_unittest.cc
@@ -8,6 +8,7 @@
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "content/child/child_process.h"
+#include "content/public/test/mock_render_thread.h"
#include "content/renderer/media/media_stream.h"
#include "content/renderer/media/media_stream_video_track.h"
#include "content/renderer/media/mock_media_stream_registry.h"
@@ -37,6 +38,7 @@ class VideoDestinationHandlerTest : public PpapiUnittest {
public:
VideoDestinationHandlerTest()
: child_process_(new ChildProcess()),
+ render_thread_(new MockRenderThread),
registry_(new MockMediaStreamRegistry()) {
registry_->Init(kTestStreamUrl);
}
@@ -53,6 +55,7 @@ class VideoDestinationHandlerTest : public PpapiUnittest {
protected:
scoped_ptr<ChildProcess> child_process_;
+ scoped_ptr<MockRenderThread> render_thread_;
scoped_ptr<MockMediaStreamRegistry> registry_;
};
diff --git a/chromium/content/renderer/media/webrtc/webrtc_audio_sink_adapter.cc b/chromium/content/renderer/media/webrtc/webrtc_audio_sink_adapter.cc
index 593f4d95777..914f704e3f9 100644
--- a/chromium/content/renderer/media/webrtc/webrtc_audio_sink_adapter.cc
+++ b/chromium/content/renderer/media/webrtc/webrtc_audio_sink_adapter.cc
@@ -4,6 +4,7 @@
#include "base/logging.h"
#include "content/renderer/media/webrtc/webrtc_audio_sink_adapter.h"
+#include "media/base/audio_bus.h"
#include "third_party/libjingle/source/talk/app/webrtc/mediastreaminterface.h"
namespace content {
@@ -22,19 +23,29 @@ bool WebRtcAudioSinkAdapter::IsEqual(
return (other == sink_);
}
-void WebRtcAudioSinkAdapter::OnData(const int16* audio_data,
- int sample_rate,
- int number_of_channels,
- int number_of_frames) {
- sink_->OnData(audio_data, 16, sample_rate, number_of_channels,
- number_of_frames);
+void WebRtcAudioSinkAdapter::OnData(const media::AudioBus& audio_bus,
+ base::TimeTicks estimated_capture_time) {
+ DCHECK_EQ(audio_bus.frames(), params_.frames_per_buffer());
+ DCHECK_EQ(audio_bus.channels(), params_.channels());
+ // TODO(henrika): Remove this conversion once the interface in libjingle
+ // supports float vectors.
+ audio_bus.ToInterleaved(audio_bus.frames(),
+ sizeof(interleaved_data_[0]),
+ interleaved_data_.get());
+ sink_->OnData(interleaved_data_.get(),
+ 16,
+ params_.sample_rate(),
+ audio_bus.channels(),
+ audio_bus.frames());
}
void WebRtcAudioSinkAdapter::OnSetFormat(
const media::AudioParameters& params) {
- // No need to forward the OnSetFormat() callback to
- // webrtc::AudioTrackSinkInterface sink since the sink will handle the
- // format change in OnData().
+ DCHECK(params.IsValid());
+ params_ = params;
+ const int num_pcm16_data_elements =
+ params_.frames_per_buffer() * params_.channels();
+ interleaved_data_.reset(new int16[num_pcm16_data_elements]);
}
} // namespace content
diff --git a/chromium/content/renderer/media/webrtc/webrtc_audio_sink_adapter.h b/chromium/content/renderer/media/webrtc/webrtc_audio_sink_adapter.h
index 91d8fa1e8f6..3b837a31735 100644
--- a/chromium/content/renderer/media/webrtc/webrtc_audio_sink_adapter.h
+++ b/chromium/content/renderer/media/webrtc/webrtc_audio_sink_adapter.h
@@ -7,6 +7,7 @@
#include "base/memory/scoped_ptr.h"
#include "content/public/renderer/media_stream_audio_sink.h"
+#include "media/audio/audio_parameters.h"
namespace webrtc {
class AudioTrackSinkInterface;
@@ -29,14 +30,15 @@ class WebRtcAudioSinkAdapter : public MediaStreamAudioSink {
private:
// MediaStreamAudioSink implementation.
- void OnData(const int16* audio_data,
- int sample_rate,
- int number_of_channels,
- int number_of_frames) override;
+ void OnData(const media::AudioBus& audio_bus,
+ base::TimeTicks estimated_capture_time) override;
void OnSetFormat(const media::AudioParameters& params) override;
webrtc::AudioTrackSinkInterface* const sink_;
+ media::AudioParameters params_;
+ scoped_ptr<int16[]> interleaved_data_;
+
DISALLOW_COPY_AND_ASSIGN(WebRtcAudioSinkAdapter);
};
diff --git a/chromium/content/renderer/media/webrtc/webrtc_local_audio_track_adapter.cc b/chromium/content/renderer/media/webrtc/webrtc_local_audio_track_adapter.cc
index f23e403c60d..14c48785947 100644
--- a/chromium/content/renderer/media/webrtc/webrtc_local_audio_track_adapter.cc
+++ b/chromium/content/renderer/media/webrtc/webrtc_local_audio_track_adapter.cc
@@ -127,14 +127,6 @@ void WebRtcLocalAudioTrackAdapter::RemoveSink(
bool WebRtcLocalAudioTrackAdapter::GetSignalLevel(int* level) {
DCHECK(signaling_thread_checker_.CalledOnValidThread());
- // It is required to provide the signal level after audio processing. In
- // case the audio processing is not enabled for the track, we return
- // false here in order not to overwrite the value from WebRTC.
- // TODO(xians): Remove this after we turn on the APM in Chrome by default.
- // http://crbug/365672 .
- if (!MediaStreamAudioProcessor::IsAudioTrackProcessingEnabled())
- return false;
-
base::AutoLock auto_lock(lock_);
*level = signal_level_;
return true;
@@ -191,16 +183,7 @@ webrtc::AudioSourceInterface* WebRtcLocalAudioTrackAdapter::GetSource() const {
}
cricket::AudioRenderer* WebRtcLocalAudioTrackAdapter::GetRenderer() {
- // When the audio track processing is enabled, return a NULL so that capture
- // data goes through Libjingle LocalAudioTrackHandler::LocalAudioSinkAdapter
- // ==> WebRtcVoiceMediaChannel::WebRtcVoiceChannelRenderer ==> WebRTC.
- // When the audio track processing is disabled, WebRtcLocalAudioTrackAdapter
- // is used to pass the channel ids to WebRtcAudioDeviceImpl, the data flow
- // becomes WebRtcAudioDeviceImpl ==> WebRTC.
- // TODO(xians): Only return NULL after the APM in WebRTC is deprecated.
- // See See http://crbug/365672 for details.
- return MediaStreamAudioProcessor::IsAudioTrackProcessingEnabled()?
- NULL : this;
+ return NULL;
}
} // namespace content
diff --git a/chromium/content/renderer/media/webrtc/webrtc_local_audio_track_adapter_unittest.cc b/chromium/content/renderer/media/webrtc/webrtc_local_audio_track_adapter_unittest.cc
index 184240cf380..1d2f0e0ab9c 100644
--- a/chromium/content/renderer/media/webrtc/webrtc_local_audio_track_adapter_unittest.cc
+++ b/chromium/content/renderer/media/webrtc/webrtc_local_audio_track_adapter_unittest.cc
@@ -2,10 +2,9 @@
// 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/renderer/media/mock_media_constraint_factory.h"
#include "content/renderer/media/webrtc/webrtc_local_audio_track_adapter.h"
+#include "content/renderer/media/webrtc_audio_capturer.h"
#include "content/renderer/media/webrtc_local_audio_track.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -64,24 +63,31 @@ TEST_F(WebRtcLocalAudioTrackAdapterTest, AddAndRemoveSink) {
static_cast<webrtc::AudioTrackInterface*>(adapter_.get());
webrtc_track->AddSink(sink.get());
- // Send a packet via |track_| and it data should reach the sink of the
+ // Send a packet via |track_| and the data should reach the sink of the
// |adapter_|.
- const int length = params_.frames_per_buffer() * params_.channels();
- scoped_ptr<int16[]> data(new int16[length]);
- // Initialize the data to 0 to avoid Memcheck:Uninitialized warning.
- memset(data.get(), 0, length * sizeof(data[0]));
-
+ const scoped_ptr<media::AudioBus> audio_bus =
+ media::AudioBus::Create(params_);
+ // While this test is not checking the signal data being passed around, the
+ // implementation in WebRtcLocalAudioTrack reads the data for its signal level
+ // computation. Initialize all samples to zero to make the memory sanitizer
+ // happy.
+ audio_bus->Zero();
+
+ base::TimeTicks estimated_capture_time = base::TimeTicks::Now();
EXPECT_CALL(*sink,
OnData(_, 16, params_.sample_rate(), params_.channels(),
params_.frames_per_buffer()));
- track_->Capture(data.get(), base::TimeDelta(), 255, false, false, false);
+ track_->Capture(*audio_bus, estimated_capture_time, false);
// Remove the sink from the webrtc track.
webrtc_track->RemoveSink(sink.get());
sink.reset();
// Verify that no more callback gets into the sink.
- track_->Capture(data.get(), base::TimeDelta(), 255, false, false, false);
+ estimated_capture_time +=
+ params_.frames_per_buffer() * base::TimeDelta::FromSeconds(1) /
+ params_.sample_rate();
+ track_->Capture(*audio_bus, estimated_capture_time, false);
}
TEST_F(WebRtcLocalAudioTrackAdapterTest, GetSignalLevel) {
@@ -89,11 +95,6 @@ TEST_F(WebRtcLocalAudioTrackAdapterTest, GetSignalLevel) {
static_cast<webrtc::AudioTrackInterface*>(adapter_.get());
int signal_level = 0;
EXPECT_TRUE(webrtc_track->GetSignalLevel(&signal_level));
-
- // Disable the audio processing in the audio track.
- CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kDisableAudioTrackProcessing);
- EXPECT_FALSE(webrtc_track->GetSignalLevel(&signal_level));
}
} // namespace content
diff --git a/chromium/content/renderer/media/webrtc/webrtc_media_stream_adapter_unittest.cc b/chromium/content/renderer/media/webrtc/webrtc_media_stream_adapter_unittest.cc
index 7070965888b..aef4a78a32f 100644
--- a/chromium/content/renderer/media/webrtc/webrtc_media_stream_adapter_unittest.cc
+++ b/chromium/content/renderer/media/webrtc/webrtc_media_stream_adapter_unittest.cc
@@ -43,7 +43,8 @@ class WebRtcMediaStreamAdapterTest : public ::testing::Test {
blink::WebMediaStreamSource audio_source;
audio_source.initialize("audio",
blink::WebMediaStreamSource::TypeAudio,
- "audio");
+ "audio",
+ false /* remote */, true /* readonly */);
audio_source.setExtraData(new MediaStreamAudioSource());
audio_track_vector[0].initialize(audio_source);
@@ -53,8 +54,8 @@ class WebRtcMediaStreamAdapterTest : public ::testing::Test {
const blink::WebMediaConstraints constraints =
constraint_factory.CreateWebMediaConstraints();
scoped_refptr<WebRtcAudioCapturer> capturer(
- WebRtcAudioCapturer::CreateCapturer(
- -1, device_info, constraints, nullptr, nullptr));
+ WebRtcAudioCapturer::CreateCapturer(-1, device_info, constraints,
+ nullptr, nullptr));
scoped_refptr<WebRtcLocalAudioTrackAdapter> adapter(
WebRtcLocalAudioTrackAdapter::Create(
audio_track_vector[0].id().utf8(), nullptr));
@@ -70,7 +71,8 @@ class WebRtcMediaStreamAdapterTest : public ::testing::Test {
blink::WebMediaStreamSource video_source;
video_source.initialize("video",
blink::WebMediaStreamSource::TypeVideo,
- "video");
+ "video",
+ false /* remote */, true /* readonly */);
MediaStreamVideoSource* native_source =
new MockMediaStreamVideoSource(false);
video_source.setExtraData(native_source);
@@ -128,7 +130,8 @@ TEST_F(WebRtcMediaStreamAdapterTest,
blink::WebMediaStreamSource audio_source;
audio_source.initialize("audio source",
blink::WebMediaStreamSource::TypeAudio,
- "something");
+ "something",
+ false /* remote */, true /* readonly */);
blink::WebVector<blink::WebMediaStreamTrack> audio_tracks(
static_cast<size_t>(1));
diff --git a/chromium/content/renderer/media/webrtc/webrtc_video_capturer_adapter.cc b/chromium/content/renderer/media/webrtc/webrtc_video_capturer_adapter.cc
index 06533e53214..370de9ac29d 100644
--- a/chromium/content/renderer/media/webrtc/webrtc_video_capturer_adapter.cc
+++ b/chromium/content/renderer/media/webrtc/webrtc_video_capturer_adapter.cc
@@ -5,15 +5,16 @@
#include "content/renderer/media/webrtc/webrtc_video_capturer_adapter.h"
#include "base/bind.h"
-#include "base/debug/trace_event.h"
#include "base/memory/aligned_memory.h"
+#include "base/trace_event/trace_event.h"
#include "media/base/video_frame.h"
#include "media/base/video_frame_pool.h"
-#include "third_party/libjingle/source/talk/media/base/videoframe.h"
#include "third_party/libjingle/source/talk/media/base/videoframefactory.h"
#include "third_party/libjingle/source/talk/media/webrtc/webrtcvideoframe.h"
#include "third_party/libyuv/include/libyuv/convert_from.h"
#include "third_party/libyuv/include/libyuv/scale.h"
+#include "third_party/webrtc/common_video/interface/video_frame_buffer.h"
+#include "third_party/webrtc/common_video/rotation.h"
namespace content {
namespace {
@@ -23,209 +24,53 @@ namespace {
void ReleaseOriginalFrame(const scoped_refptr<media::VideoFrame>& frame) {
}
-// Thin map between an existing media::VideoFrame and cricket::VideoFrame to
-// avoid premature deep copies.
-// This implementation is only safe to use in a const context and should never
-// be written to.
-class VideoFrameWrapper : public cricket::VideoFrame {
- public:
- VideoFrameWrapper(const scoped_refptr<media::VideoFrame>& frame,
- int64 elapsed_time)
- : frame_(media::VideoFrame::WrapVideoFrame(
- frame,
- frame->visible_rect(),
- frame->natural_size(),
- base::Bind(&ReleaseOriginalFrame, frame))),
- elapsed_time_(elapsed_time) {}
-
- VideoFrame* Copy() const override {
- DCHECK(thread_checker_.CalledOnValidThread());
- return new VideoFrameWrapper(frame_, elapsed_time_);
- }
-
- size_t GetWidth() const override {
- DCHECK(thread_checker_.CalledOnValidThread());
- return static_cast<size_t>(frame_->visible_rect().width());
- }
-
- size_t GetHeight() const override {
- DCHECK(thread_checker_.CalledOnValidThread());
- return static_cast<size_t>(frame_->visible_rect().height());
- }
-
- const uint8* GetYPlane() const override {
- DCHECK(thread_checker_.CalledOnValidThread());
- return frame_->visible_data(media::VideoFrame::kYPlane);
- }
-
- const uint8* GetUPlane() const override {
- DCHECK(thread_checker_.CalledOnValidThread());
- return frame_->visible_data(media::VideoFrame::kUPlane);
- }
-
- const uint8* GetVPlane() const override {
- DCHECK(thread_checker_.CalledOnValidThread());
- return frame_->visible_data(media::VideoFrame::kVPlane);
- }
-
- uint8* GetYPlane() override {
- DCHECK(thread_checker_.CalledOnValidThread());
- return frame_->visible_data(media::VideoFrame::kYPlane);
- }
-
- uint8* GetUPlane() override {
- DCHECK(thread_checker_.CalledOnValidThread());
- return frame_->visible_data(media::VideoFrame::kUPlane);
- }
-
- uint8* GetVPlane() override {
- DCHECK(thread_checker_.CalledOnValidThread());
- return frame_->visible_data(media::VideoFrame::kVPlane);
- }
-
- int32 GetYPitch() const override {
- DCHECK(thread_checker_.CalledOnValidThread());
- return frame_->stride(media::VideoFrame::kYPlane);
- }
-
- int32 GetUPitch() const override {
- DCHECK(thread_checker_.CalledOnValidThread());
- return frame_->stride(media::VideoFrame::kUPlane);
- }
-
- int32 GetVPitch() const override {
- DCHECK(thread_checker_.CalledOnValidThread());
- return frame_->stride(media::VideoFrame::kVPlane);
- }
-
- void* GetNativeHandle() const override {
- DCHECK(thread_checker_.CalledOnValidThread());
- return NULL;
- }
-
- size_t GetPixelWidth() const override {
- DCHECK(thread_checker_.CalledOnValidThread());
- return 1;
- }
- size_t GetPixelHeight() const override {
- DCHECK(thread_checker_.CalledOnValidThread());
- return 1;
- }
-
- int64 GetElapsedTime() const override {
- DCHECK(thread_checker_.CalledOnValidThread());
- return elapsed_time_;
- }
-
- int64 GetTimeStamp() const override {
- DCHECK(thread_checker_.CalledOnValidThread());
- return frame_->timestamp().InMicroseconds() *
- base::Time::kNanosecondsPerMicrosecond;
- }
-
- void SetElapsedTime(int64 elapsed_time) override {
- DCHECK(thread_checker_.CalledOnValidThread());
- elapsed_time_ = elapsed_time;
+int WebRtcToMediaPlaneType(webrtc::PlaneType type) {
+ switch (type) {
+ case webrtc::kYPlane:
+ return media::VideoFrame::kYPlane;
+ case webrtc::kUPlane:
+ return media::VideoFrame::kUPlane;
+ case webrtc::kVPlane:
+ return media::VideoFrame::kVPlane;
+ default:
+ NOTREACHED();
+ return media::VideoFrame::kMaxPlanes;
}
+}
- void SetTimeStamp(int64 time_stamp) override {
- DCHECK(thread_checker_.CalledOnValidThread());
- // Round to closest microsecond.
- frame_->set_timestamp(base::TimeDelta::FromMicroseconds(
- (time_stamp + base::Time::kNanosecondsPerMicrosecond / 2) /
- base::Time::kNanosecondsPerMicrosecond));
- }
+// Thin adapter from media::VideoFrame to webrtc::VideoFrameBuffer. This
+// implementation is read-only and will return null if trying to get a
+// non-const pointer to the pixel data. This object will be accessed from
+// different threads, but that's safe since it's read-only.
+class VideoFrameWrapper : public webrtc::VideoFrameBuffer {
+ public:
+ VideoFrameWrapper(const scoped_refptr<media::VideoFrame>& frame)
+ : frame_(frame) {}
- int GetRotation() const override {
- DCHECK(thread_checker_.CalledOnValidThread());
- return 0;
- }
+ private:
+ int width() const override { return frame_->visible_rect().width(); }
- // TODO(magjed): Refactor into base class.
- size_t ConvertToRgbBuffer(uint32 to_fourcc,
- uint8* buffer,
- size_t size,
- int stride_rgb) const override {
- DCHECK(thread_checker_.CalledOnValidThread());
- const size_t needed = std::abs(stride_rgb) * GetHeight();
- if (size < needed) {
- DLOG(WARNING) << "RGB buffer is not large enough";
- return needed;
- }
+ int height() const override { return frame_->visible_rect().height(); }
- if (libyuv::ConvertFromI420(GetYPlane(),
- GetYPitch(),
- GetUPlane(),
- GetUPitch(),
- GetVPlane(),
- GetVPitch(),
- buffer,
- stride_rgb,
- static_cast<int>(GetWidth()),
- static_cast<int>(GetHeight()),
- to_fourcc)) {
- DLOG(ERROR) << "RGB type not supported: " << to_fourcc;
- return 0; // 0 indicates error
- }
- return needed;
+ const uint8_t* data(webrtc::PlaneType type) const override {
+ return frame_->visible_data(WebRtcToMediaPlaneType(type));
}
- // The rest of the public methods are NOTIMPLEMENTED.
- bool InitToBlack(int w,
- int h,
- size_t pixel_width,
- size_t pixel_height,
- int64 elapsed_time,
- int64 time_stamp) override {
- NOTIMPLEMENTED();
- return false;
+ uint8_t* data(webrtc::PlaneType type) override {
+ NOTREACHED();
+ return nullptr;
}
- bool Reset(uint32 fourcc,
- int w,
- int h,
- int dw,
- int dh,
- uint8* sample,
- size_t sample_size,
- size_t pixel_width,
- size_t pixel_height,
- int64 elapsed_time,
- int64 time_stamp,
- int rotation) override {
- NOTIMPLEMENTED();
- return false;
+ int stride(webrtc::PlaneType type) const override {
+ return frame_->stride(WebRtcToMediaPlaneType(type));
}
- bool MakeExclusive() override {
- NOTIMPLEMENTED();
- return false;
- }
+ void* native_handle() const override { return nullptr; }
- size_t CopyToBuffer(uint8* buffer, size_t size) const override {
- NOTIMPLEMENTED();
- return 0;
- }
+ ~VideoFrameWrapper() override {}
+ friend class rtc::RefCountedObject<VideoFrameWrapper>;
- protected:
- // TODO(magjed): Refactor as a static method in WebRtcVideoFrame.
- VideoFrame* CreateEmptyFrame(int w,
- int h,
- size_t pixel_width,
- size_t pixel_height,
- int64 elapsed_time,
- int64 time_stamp) const override {
- DCHECK(thread_checker_.CalledOnValidThread());
- VideoFrame* frame = new cricket::WebRtcVideoFrame();
- frame->InitToBlack(
- w, h, pixel_width, pixel_height, elapsed_time, time_stamp);
- return frame;
- }
-
- private:
scoped_refptr<media::VideoFrame> frame_;
- int64 elapsed_time_;
- base::ThreadChecker thread_checker_;
};
} // anonymous namespace
@@ -250,7 +95,7 @@ class WebRtcVideoCapturerAdapter::MediaVideoFrameFactory
base::Time::kNanosecondsPerMicrosecond;
captured_frame_.pixel_height = 1;
captured_frame_.pixel_width = 1;
- captured_frame_.rotation = 0;
+ captured_frame_.rotation = webrtc::kVideoRotation_0;
captured_frame_.data = NULL;
captured_frame_.data_size = cricket::CapturedFrame::kUnknownDataSize;
captured_frame_.fourcc = static_cast<uint32>(cricket::FOURCC_ANY);
@@ -265,45 +110,69 @@ class WebRtcVideoCapturerAdapter::MediaVideoFrameFactory
}
cricket::VideoFrame* CreateAliasedFrame(
- const cricket::CapturedFrame* captured_frame,
- int dst_width,
- int dst_height) const override {
+ const cricket::CapturedFrame* input_frame,
+ int cropped_input_width,
+ int cropped_input_height,
+ int output_width,
+ int output_height) const override {
// Check that captured_frame is actually our frame.
- DCHECK(captured_frame == &captured_frame_);
+ DCHECK(input_frame == &captured_frame_);
DCHECK(frame_.get());
- scoped_refptr<media::VideoFrame> video_frame = frame_;
- // Check if scaling is needed.
- if (dst_width != frame_->visible_rect().width() ||
- dst_height != frame_->visible_rect().height()) {
- video_frame =
- scaled_frame_pool_.CreateFrame(media::VideoFrame::I420,
- gfx::Size(dst_width, dst_height),
- gfx::Rect(0, 0, dst_width, dst_height),
- gfx::Size(dst_width, dst_height),
- frame_->timestamp());
- libyuv::I420Scale(frame_->visible_data(media::VideoFrame::kYPlane),
- frame_->stride(media::VideoFrame::kYPlane),
- frame_->visible_data(media::VideoFrame::kUPlane),
- frame_->stride(media::VideoFrame::kUPlane),
- frame_->visible_data(media::VideoFrame::kVPlane),
- frame_->stride(media::VideoFrame::kVPlane),
- frame_->visible_rect().width(),
- frame_->visible_rect().height(),
- video_frame->data(media::VideoFrame::kYPlane),
- video_frame->stride(media::VideoFrame::kYPlane),
- video_frame->data(media::VideoFrame::kUPlane),
- video_frame->stride(media::VideoFrame::kUPlane),
- video_frame->data(media::VideoFrame::kVPlane),
- video_frame->stride(media::VideoFrame::kVPlane),
- dst_width,
- dst_height,
- libyuv::kFilterBilinear);
+ // Create a centered cropped visible rect that preservers aspect ratio for
+ // cropped natural size.
+ gfx::Rect visible_rect = frame_->visible_rect();
+ visible_rect.ClampToCenteredSize(gfx::Size(
+ visible_rect.width() * cropped_input_width / input_frame->width,
+ visible_rect.height() * cropped_input_height / input_frame->height));
+
+ const gfx::Size output_size(output_width, output_height);
+ scoped_refptr<media::VideoFrame> video_frame =
+ media::VideoFrame::WrapVideoFrame(
+ frame_, visible_rect, output_size,
+ base::Bind(&ReleaseOriginalFrame, frame_));
+
+ const int64_t timestamp_ns = frame_->timestamp().InMicroseconds() *
+ base::Time::kNanosecondsPerMicrosecond;
+
+ // If no scaling is needed, return a wrapped version of |frame_| directly.
+ if (video_frame->natural_size() == video_frame->visible_rect().size()) {
+ return new cricket::WebRtcVideoFrame(
+ new rtc::RefCountedObject<VideoFrameWrapper>(video_frame),
+ captured_frame_.elapsed_time, timestamp_ns);
}
- // Create a shallow cricket::VideoFrame wrapper around the
- // media::VideoFrame. The caller has ownership of the returned frame.
- return new VideoFrameWrapper(video_frame, captured_frame_.elapsed_time);
+ // We need to scale the frame before we hand it over to cricket.
+ scoped_refptr<media::VideoFrame> scaled_frame =
+ scaled_frame_pool_.CreateFrame(media::VideoFrame::I420, output_size,
+ gfx::Rect(output_size), output_size,
+ frame_->timestamp());
+ libyuv::I420Scale(video_frame->visible_data(media::VideoFrame::kYPlane),
+ video_frame->stride(media::VideoFrame::kYPlane),
+ video_frame->visible_data(media::VideoFrame::kUPlane),
+ video_frame->stride(media::VideoFrame::kUPlane),
+ video_frame->visible_data(media::VideoFrame::kVPlane),
+ video_frame->stride(media::VideoFrame::kVPlane),
+ video_frame->visible_rect().width(),
+ video_frame->visible_rect().height(),
+ scaled_frame->data(media::VideoFrame::kYPlane),
+ scaled_frame->stride(media::VideoFrame::kYPlane),
+ scaled_frame->data(media::VideoFrame::kUPlane),
+ scaled_frame->stride(media::VideoFrame::kUPlane),
+ scaled_frame->data(media::VideoFrame::kVPlane),
+ scaled_frame->stride(media::VideoFrame::kVPlane),
+ output_width, output_height, libyuv::kFilterBilinear);
+ return new cricket::WebRtcVideoFrame(
+ new rtc::RefCountedObject<VideoFrameWrapper>(scaled_frame),
+ captured_frame_.elapsed_time, timestamp_ns);
+ }
+
+ cricket::VideoFrame* CreateAliasedFrame(
+ const cricket::CapturedFrame* input_frame,
+ int output_width,
+ int output_height) const override {
+ return CreateAliasedFrame(input_frame, input_frame->width,
+ input_frame->height, output_width, output_height);
}
private:
diff --git a/chromium/content/renderer/media/webrtc/webrtc_video_capturer_adapter.h b/chromium/content/renderer/media/webrtc/webrtc_video_capturer_adapter.h
index f70ae8949d2..847dc74920c 100644
--- a/chromium/content/renderer/media/webrtc/webrtc_video_capturer_adapter.h
+++ b/chromium/content/renderer/media/webrtc/webrtc_video_capturer_adapter.h
@@ -11,8 +11,8 @@
#include "base/message_loop/message_loop_proxy.h"
#include "base/threading/thread_checker.h"
#include "content/common/content_export.h"
+#include "media/base/video_capture_types.h"
#include "media/base/video_frame.h"
-#include "media/video/capture/video_capture_types.h"
#include "third_party/libjingle/source/talk/media/base/videocapturer.h"
namespace content {
diff --git a/chromium/content/renderer/media/webrtc/webrtc_video_track_adapter.cc b/chromium/content/renderer/media/webrtc/webrtc_video_track_adapter.cc
index 6a9c2f4d30d..d3c2036c45f 100644
--- a/chromium/content/renderer/media/webrtc/webrtc_video_track_adapter.cc
+++ b/chromium/content/renderer/media/webrtc/webrtc_video_track_adapter.cc
@@ -44,14 +44,11 @@ class WebRtcVideoTrackAdapter::WebRtcVideoSourceAdapter
void ReleaseSourceOnMainThread();
void OnVideoFrameOnIO(const scoped_refptr<media::VideoFrame>& frame,
- const media::VideoCaptureFormat& format,
const base::TimeTicks& estimated_capture_time);
private:
void OnVideoFrameOnWorkerThread(
- const scoped_refptr<media::VideoFrame>& frame,
- const media::VideoCaptureFormat& format,
- const base::TimeTicks& estimated_capture_time);
+ const scoped_refptr<media::VideoFrame>& frame);
friend class base::RefCountedThreadSafe<WebRtcVideoSourceAdapter>;
virtual ~WebRtcVideoSourceAdapter();
@@ -113,20 +110,18 @@ ReleaseSourceOnMainThread() {
void WebRtcVideoTrackAdapter::WebRtcVideoSourceAdapter::OnVideoFrameOnIO(
const scoped_refptr<media::VideoFrame>& frame,
- const media::VideoCaptureFormat& format,
const base::TimeTicks& estimated_capture_time) {
DCHECK(io_thread_checker_.CalledOnValidThread());
libjingle_worker_thread_->PostTask(
FROM_HERE,
base::Bind(&WebRtcVideoSourceAdapter::OnVideoFrameOnWorkerThread,
- this, frame, format, estimated_capture_time));
+ this,
+ frame));
}
void
WebRtcVideoTrackAdapter::WebRtcVideoSourceAdapter::OnVideoFrameOnWorkerThread(
- const scoped_refptr<media::VideoFrame>& frame,
- const media::VideoCaptureFormat& format,
- const base::TimeTicks& estimated_capture_time) {
+ const scoped_refptr<media::VideoFrame>& frame) {
DCHECK(libjingle_worker_thread_->BelongsToCurrentThread());
base::AutoLock auto_lock(capture_adapter_stop_lock_);
if (capture_adapter_)
diff --git a/chromium/content/renderer/media/webrtc_audio_capturer.cc b/chromium/content/renderer/media/webrtc_audio_capturer.cc
index 45034e8b2f4..df46265d8fb 100644
--- a/chromium/content/renderer/media/webrtc_audio_capturer.cc
+++ b/chromium/content/renderer/media/webrtc_audio_capturer.cc
@@ -14,6 +14,7 @@
#include "content/renderer/media/media_stream_audio_processor.h"
#include "content/renderer/media/media_stream_audio_processor_options.h"
#include "content/renderer/media/media_stream_audio_source.h"
+#include "content/renderer/media/media_stream_constraints_util.h"
#include "content/renderer/media/webrtc_audio_device_impl.h"
#include "content/renderer/media/webrtc_local_audio_track.h"
#include "content/renderer/media/webrtc_logging.h"
@@ -23,6 +24,11 @@ namespace content {
namespace {
+// Audio buffer sizes are specified in milliseconds.
+const char kAudioLatency[] = "latencyMs";
+const int kMinAudioLatencyMs = 0;
+const int kMaxAudioLatencyMs = 10000;
+
// Method to check if any of the data in |audio_source| has energy.
bool HasDataEnergy(const media::AudioBus& audio_source) {
for (int ch = 0; ch < audio_source.channels(); ++ch) {
@@ -47,19 +53,13 @@ class WebRtcAudioCapturer::TrackOwner
explicit TrackOwner(WebRtcLocalAudioTrack* track)
: delegate_(track) {}
- void Capture(const int16* audio_data,
- base::TimeDelta delay,
- double volume,
- bool key_pressed,
- bool need_audio_processing,
+ void Capture(const media::AudioBus& audio_bus,
+ base::TimeTicks estimated_capture_time,
bool force_report_nonzero_energy) {
base::AutoLock lock(lock_);
if (delegate_) {
- delegate_->Capture(audio_data,
- delay,
- volume,
- key_pressed,
- need_audio_processing,
+ delegate_->Capture(audio_bus,
+ estimated_capture_time,
force_report_nonzero_energy);
}
}
@@ -95,7 +95,7 @@ class WebRtcAudioCapturer::TrackOwner
// Wrapper which allows to use std::find_if() when adding and removing
// sinks to/from the list.
struct TrackWrapper {
- TrackWrapper(WebRtcLocalAudioTrack* track) : track_(track) {}
+ explicit TrackWrapper(WebRtcLocalAudioTrack* track) : track_(track) {}
bool operator()(
const scoped_refptr<WebRtcAudioCapturer::TrackOwner>& owner) const {
return owner->IsEqual(track_);
@@ -123,12 +123,13 @@ class WebRtcAudioCapturer::TrackOwner
// static
scoped_refptr<WebRtcAudioCapturer> WebRtcAudioCapturer::CreateCapturer(
- int render_view_id, const StreamDeviceInfo& device_info,
+ int render_frame_id,
+ const StreamDeviceInfo& device_info,
const blink::WebMediaConstraints& constraints,
WebRtcAudioDeviceImpl* audio_device,
MediaStreamAudioSource* audio_source) {
scoped_refptr<WebRtcAudioCapturer> capturer = new WebRtcAudioCapturer(
- render_view_id, device_info, constraints, audio_device, audio_source);
+ render_frame_id, device_info, constraints, audio_device, audio_source);
if (capturer->Initialize())
return capturer;
@@ -139,20 +140,18 @@ bool WebRtcAudioCapturer::Initialize() {
DCHECK(thread_checker_.CalledOnValidThread());
DVLOG(1) << "WebRtcAudioCapturer::Initialize()";
WebRtcLogMessage(base::StringPrintf(
- "WAC::Initialize. render_view_id=%d"
+ "WAC::Initialize. render_frame_id=%d"
", channel_layout=%d, sample_rate=%d, buffer_size=%d"
", session_id=%d, paired_output_sample_rate=%d"
", paired_output_frames_per_buffer=%d, effects=%d. ",
- render_view_id_,
- device_info_.device.input.channel_layout,
+ render_frame_id_, device_info_.device.input.channel_layout,
device_info_.device.input.sample_rate,
- device_info_.device.input.frames_per_buffer,
- device_info_.session_id,
+ device_info_.device.input.frames_per_buffer, device_info_.session_id,
device_info_.device.matched_output.sample_rate,
device_info_.device.matched_output.frames_per_buffer,
device_info_.device.input.effects));
- if (render_view_id_ == -1) {
+ if (render_frame_id_ == -1) {
// Return true here to allow injecting a new source via
// SetCapturerSourceForTesting() at a later state.
return true;
@@ -170,7 +169,6 @@ bool WebRtcAudioCapturer::Initialize() {
// layout that includes the keyboard mic.
if ((device_info_.device.input.effects &
media::AudioParameters::KEYBOARD_MIC) &&
- MediaStreamAudioProcessor::IsAudioTrackProcessingEnabled() &&
audio_constraints.GetProperty(
MediaAudioConstraints::kGoogExperimentalNoiseSuppression)) {
if (channel_layout == media::CHANNEL_LAYOUT_STEREO) {
@@ -207,10 +205,27 @@ bool WebRtcAudioCapturer::Initialize() {
device_info_.device.input.sample_rate);
}
+ // Initialize the buffer size to zero, which means it wasn't specified.
+ // If it is out of range, we return it to zero.
+ int buffer_size_ms = 0;
+ int buffer_size_samples = 0;
+ GetConstraintValueAsInteger(constraints_, kAudioLatency, &buffer_size_ms);
+ if (buffer_size_ms < kMinAudioLatencyMs ||
+ buffer_size_ms > kMaxAudioLatencyMs) {
+ DVLOG(1) << "Ignoring out of range buffer size " << buffer_size_ms;
+ } else {
+ buffer_size_samples =
+ device_info_.device.input.sample_rate * buffer_size_ms / 1000;
+ }
+ DVLOG_IF(1, buffer_size_samples > 0)
+ << "Custom audio buffer size: " << buffer_size_samples << " samples";
+
// Create and configure the default audio capturing source.
- SetCapturerSource(AudioDeviceFactory::NewInputDevice(render_view_id_),
- channel_layout,
- static_cast<float>(device_info_.device.input.sample_rate));
+ SetCapturerSourceInternal(
+ AudioDeviceFactory::NewInputDevice(render_frame_id_),
+ channel_layout,
+ device_info_.device.input.sample_rate,
+ buffer_size_samples);
// Add the capturer to the WebRtcAudioDeviceImpl since it needs some hardware
// information from the capturer.
@@ -221,7 +236,7 @@ bool WebRtcAudioCapturer::Initialize() {
}
WebRtcAudioCapturer::WebRtcAudioCapturer(
- int render_view_id,
+ int render_frame_id,
const StreamDeviceInfo& device_info,
const blink::WebMediaConstraints& constraints,
WebRtcAudioDeviceImpl* audio_device,
@@ -232,12 +247,10 @@ WebRtcAudioCapturer::WebRtcAudioCapturer(
device_info.device.input.effects,
audio_device)),
running_(false),
- render_view_id_(render_view_id),
+ render_frame_id_(render_frame_id),
device_info_(device_info),
volume_(0),
peer_connection_mode_(false),
- key_pressed_(false),
- need_audio_processing_(false),
audio_device_(audio_device),
audio_source_(audio_source) {
DVLOG(1) << "WebRtcAudioCapturer::WebRtcAudioCapturer()";
@@ -294,10 +307,11 @@ void WebRtcAudioCapturer::RemoveTrack(WebRtcLocalAudioTrack* track) {
}
}
-void WebRtcAudioCapturer::SetCapturerSource(
+void WebRtcAudioCapturer::SetCapturerSourceInternal(
const scoped_refptr<media::AudioCapturerSource>& source,
media::ChannelLayout channel_layout,
- float sample_rate) {
+ int sample_rate,
+ int buffer_size) {
DCHECK(thread_checker_.CalledOnValidThread());
DVLOG(1) << "SetCapturerSource(channel_layout=" << channel_layout << ","
<< "sample_rate=" << sample_rate << ")";
@@ -318,15 +332,21 @@ void WebRtcAudioCapturer::SetCapturerSource(
if (old_source.get())
old_source->Stop();
+ // If the buffer size is zero, it has not been specified.
+ // We either default to 10ms, or use the hardware buffer size.
+ if (buffer_size == 0)
+ buffer_size = GetBufferSize(sample_rate);
+
// Dispatch the new parameters both to the sink(s) and to the new source,
// also apply the new |constraints|.
// The idea is to get rid of any dependency of the microphone parameters
// which would normally be used by default.
// bits_per_sample is always 16 for now.
- int buffer_size = GetBufferSize(sample_rate);
media::AudioParameters params(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
- channel_layout, sample_rate,
- 16, buffer_size,
+ channel_layout,
+ sample_rate,
+ 16,
+ buffer_size,
device_info_.device.input.effects);
{
@@ -334,9 +354,6 @@ void WebRtcAudioCapturer::SetCapturerSource(
// Notify the |audio_processor_| of the new format.
audio_processor_->OnCaptureFormatChanged(params);
- MediaAudioConstraints audio_constraints(constraints_,
- device_info_.device.input.effects);
- need_audio_processing_ = audio_constraints.NeedsAudioProcessing();
// Notify all tracks about the new format.
tracks_.TagAll();
}
@@ -355,16 +372,16 @@ void WebRtcAudioCapturer::EnablePeerConnectionMode() {
return;
peer_connection_mode_ = true;
- int render_view_id = -1;
+ int render_frame_id = -1;
media::AudioParameters input_params;
{
base::AutoLock auto_lock(lock_);
- // Simply return if there is no existing source or the |render_view_id_| is
+ // Simply return if there is no existing source or the |render_frame_id_| is
// not valid.
- if (!source_.get() || render_view_id_== -1)
+ if (!source_.get() || render_frame_id_ == -1)
return;
- render_view_id = render_view_id_;
+ render_frame_id = render_frame_id_;
input_params = audio_processor_->InputFormat();
}
@@ -376,9 +393,10 @@ void WebRtcAudioCapturer::EnablePeerConnectionMode() {
// Create a new audio stream as source which will open the hardware using
// WebRtc native buffer size.
- SetCapturerSource(AudioDeviceFactory::NewInputDevice(render_view_id),
- input_params.channel_layout(),
- static_cast<float>(input_params.sample_rate()));
+ SetCapturerSourceInternal(AudioDeviceFactory::NewInputDevice(render_frame_id),
+ input_params.channel_layout(),
+ input_params.sample_rate(),
+ 0);
}
void WebRtcAudioCapturer::Start() {
@@ -446,6 +464,11 @@ int WebRtcAudioCapturer::MaxVolume() const {
return WebRtcAudioDeviceImpl::kMaxVolumeLevel;
}
+media::AudioParameters WebRtcAudioCapturer::GetOutputFormat() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return audio_processor_->OutputFormat();
+}
+
void WebRtcAudioCapturer::Capture(const media::AudioBus* audio_source,
int audio_delay_milliseconds,
double volume,
@@ -464,11 +487,14 @@ void WebRtcAudioCapturer::Capture(const media::AudioBus* audio_source,
DCHECK_LE(volume, 1.6);
#endif
+ // TODO(miu): Plumbing is needed to determine the actual capture timestamp
+ // of the audio, instead of just snapshotting TimeTicks::Now(), for proper
+ // audio/video sync. http://crbug.com/335335
+ const base::TimeTicks reference_clock_snapshot = base::TimeTicks::Now();
+
TrackList::ItemList tracks;
TrackList::ItemList tracks_to_notify_format;
int current_volume = 0;
- base::TimeDelta audio_delay;
- bool need_audio_processing = true;
{
base::AutoLock auto_lock(lock_);
if (!running_)
@@ -479,17 +505,8 @@ void WebRtcAudioCapturer::Capture(const media::AudioBus* audio_source,
// 255 since AGC does not allow values out of range.
volume_ = static_cast<int>((volume * MaxVolume()) + 0.5);
current_volume = volume_ > MaxVolume() ? MaxVolume() : volume_;
- audio_delay = base::TimeDelta::FromMilliseconds(audio_delay_milliseconds);
- audio_delay_ = audio_delay;
- key_pressed_ = key_pressed;
tracks = tracks_.Items();
tracks_.RetrieveAndClearTags(&tracks_to_notify_format);
-
- // Set the flag to turn on the audio processing in PeerConnection level.
- // Note that, we turn off the audio processing in PeerConnection if the
- // processor has already processed the data.
- need_audio_processing = need_audio_processing_ ?
- !MediaStreamAudioProcessor::IsAudioTrackProcessingEnabled() : false;
}
DCHECK(audio_processor_->InputFormat().IsValid());
@@ -500,11 +517,11 @@ void WebRtcAudioCapturer::Capture(const media::AudioBus* audio_source,
// Notify the tracks on when the format changes. This will do nothing if
// |tracks_to_notify_format| is empty.
- media::AudioParameters output_params = audio_processor_->OutputFormat();
- for (TrackList::ItemList::const_iterator it = tracks_to_notify_format.begin();
- it != tracks_to_notify_format.end(); ++it) {
- (*it)->OnSetFormat(output_params);
- (*it)->SetAudioProcessor(audio_processor_);
+ const media::AudioParameters& output_params =
+ audio_processor_->OutputFormat();
+ for (const auto& track : tracks_to_notify_format) {
+ track->OnSetFormat(output_params);
+ track->SetAudioProcessor(audio_processor_);
}
// Figure out if the pre-processed data has any energy or not, the
@@ -514,19 +531,25 @@ void WebRtcAudioCapturer::Capture(const media::AudioBus* audio_source,
const bool force_report_nonzero_energy = HasDataEnergy(*audio_source);
// Push the data to the processor for processing.
- audio_processor_->PushCaptureData(audio_source);
+ audio_processor_->PushCaptureData(
+ *audio_source,
+ base::TimeDelta::FromMilliseconds(audio_delay_milliseconds));
// Process and consume the data in the processor until there is not enough
// data in the processor.
- int16* output = NULL;
+ media::AudioBus* processed_data = nullptr;
+ base::TimeDelta processed_data_audio_delay;
int new_volume = 0;
while (audio_processor_->ProcessAndConsumeData(
- audio_delay, current_volume, key_pressed, &new_volume, &output)) {
- // Feed the post-processed data to the tracks.
- for (TrackList::ItemList::const_iterator it = tracks.begin();
- it != tracks.end(); ++it) {
- (*it)->Capture(output, audio_delay, current_volume, key_pressed,
- need_audio_processing, force_report_nonzero_energy);
+ current_volume, key_pressed,
+ &processed_data, &processed_data_audio_delay, &new_volume)) {
+ DCHECK(processed_data);
+ const base::TimeTicks processed_data_capture_time =
+ reference_clock_snapshot - processed_data_audio_delay;
+ for (const auto& track : tracks) {
+ track->Capture(*processed_data,
+ processed_data_capture_time,
+ force_report_nonzero_energy);
}
if (new_volume) {
@@ -592,20 +615,14 @@ int WebRtcAudioCapturer::GetBufferSize(int sample_rate) const {
return (sample_rate / 100);
}
-void WebRtcAudioCapturer::GetAudioProcessingParams(
- base::TimeDelta* delay, int* volume, bool* key_pressed) {
- base::AutoLock auto_lock(lock_);
- *delay = audio_delay_;
- *volume = volume_;
- *key_pressed = key_pressed_;
-}
-
-void WebRtcAudioCapturer::SetCapturerSourceForTesting(
+void WebRtcAudioCapturer::SetCapturerSource(
const scoped_refptr<media::AudioCapturerSource>& source,
media::AudioParameters params) {
// Create a new audio stream as source which uses the new source.
- SetCapturerSource(source, params.channel_layout(),
- static_cast<float>(params.sample_rate()));
+ SetCapturerSourceInternal(source,
+ params.channel_layout(),
+ params.sample_rate(),
+ 0);
}
} // namespace content
diff --git a/chromium/content/renderer/media/webrtc_audio_capturer.h b/chromium/content/renderer/media/webrtc_audio_capturer.h
index d98db0f106c..f1ada132fd5 100644
--- a/chromium/content/renderer/media/webrtc_audio_capturer.h
+++ b/chromium/content/renderer/media/webrtc_audio_capturer.h
@@ -43,24 +43,19 @@ class CONTENT_EXPORT WebRtcAudioCapturer
: public base::RefCountedThreadSafe<WebRtcAudioCapturer>,
NON_EXPORTED_BASE(public media::AudioCapturerSource::CaptureCallback) {
public:
- // Used to construct the audio capturer. |render_view_id| specifies the
- // render view consuming audio for capture, |render_view_id| as -1 is used
- // by the unittests to skip creating a source via
- // AudioDeviceFactory::NewInputDevice(), and allow injecting their own source
- // via SetCapturerSourceForTesting() at a later state. |device_info|
- // contains all the device information that the capturer is created for.
- // |constraints| contains the settings for audio processing.
+ // Used to construct the audio capturer. |render_frame_id| specifies the
+ // RenderFrame consuming audio for capture; -1 is used for tests.
+ // |device_info| contains all the device information that the capturer is
+ // created for. |constraints| contains the settings for audio processing.
// TODO(xians): Implement the interface for the audio source and move the
- // |constraints| to ApplyConstraints().
- // Called on the main render thread.
+ // |constraints| to ApplyConstraints(). Called on the main render thread.
static scoped_refptr<WebRtcAudioCapturer> CreateCapturer(
- int render_view_id,
+ int render_frame_id,
const StreamDeviceInfo& device_info,
const blink::WebMediaConstraints& constraints,
WebRtcAudioDeviceImpl* audio_device,
MediaStreamAudioSource* audio_source);
-
// Add a audio track to the sinks of the capturer.
// WebRtcAudioDeviceImpl calls this method on the main render thread but
// other clients may call it from other threads. The current implementation
@@ -105,14 +100,12 @@ class CONTENT_EXPORT WebRtcAudioCapturer
// call Stop()
void Stop();
- // Called by the WebAudioCapturerSource to get the audio processing params.
- // This function is triggered by provideInput() on the WebAudio audio thread,
- // TODO(xians): Remove after moving APM from WebRtc to Chrome.
- void GetAudioProcessingParams(base::TimeDelta* delay, int* volume,
- bool* key_pressed);
+ // Returns the output format.
+ // Called on the main render thread.
+ media::AudioParameters GetOutputFormat() const;
- // Used by the unittests to inject their own source to the capturer.
- void SetCapturerSourceForTesting(
+ // Used by clients to inject their own source to the capturer.
+ void SetCapturerSource(
const scoped_refptr<media::AudioCapturerSource>& source,
media::AudioParameters params);
@@ -124,7 +117,7 @@ class CONTENT_EXPORT WebRtcAudioCapturer
class TrackOwner;
typedef TaggedList<TrackOwner> TrackList;
- WebRtcAudioCapturer(int render_view_id,
+ WebRtcAudioCapturer(int render_frame_id,
const StreamDeviceInfo& device_info,
const blink::WebMediaConstraints& constraints,
WebRtcAudioDeviceImpl* audio_device,
@@ -139,17 +132,19 @@ class CONTENT_EXPORT WebRtcAudioCapturer
void OnCaptureError() override;
// Initializes the default audio capturing source using the provided render
- // view id and device information. Return true if success, otherwise false.
+ // frame id and device information. Return true if success, otherwise false.
bool Initialize();
- // SetCapturerSource() is called if the client on the source side desires to
- // provide their own captured audio data. Client is responsible for calling
- // Start() on its own source to have the ball rolling.
+ // SetCapturerSourceInternal() is called if the client on the source side
+ // desires to provide their own captured audio data. Client is responsible
+ // for calling Start() on its own source to get the ball rolling.
// Called on the main render thread.
- void SetCapturerSource(
+ // buffer_size is optional. Set to 0 to let it be chosen automatically.
+ void SetCapturerSourceInternal(
const scoped_refptr<media::AudioCapturerSource>& source,
media::ChannelLayout channel_layout,
- float sample_rate);
+ int sample_rate,
+ int buffer_size);
// Starts recording audio.
// Triggered by AddSink() on the main render thread or a Libjingle working
@@ -184,7 +179,7 @@ class CONTENT_EXPORT WebRtcAudioCapturer
bool running_;
- int render_view_id_;
+ int render_frame_id_;
// Cached information of the device used by the capturer.
const StreamDeviceInfo device_info_;
@@ -196,13 +191,6 @@ class CONTENT_EXPORT WebRtcAudioCapturer
// Flag which affects the buffer size used by the capturer.
bool peer_connection_mode_;
- // Cache value for the audio processing params.
- base::TimeDelta audio_delay_;
- bool key_pressed_;
-
- // Flag to help deciding if the data needs audio processing.
- bool need_audio_processing_;
-
// Raw pointer to the WebRtcAudioDeviceImpl, which is valid for the lifetime
// of RenderThread.
WebRtcAudioDeviceImpl* audio_device_;
diff --git a/chromium/content/renderer/media/webrtc_audio_capturer_unittest.cc b/chromium/content/renderer/media/webrtc_audio_capturer_unittest.cc
index 9b2741041d2..92d291f9fc8 100644
--- a/chromium/content/renderer/media/webrtc_audio_capturer_unittest.cc
+++ b/chromium/content/renderer/media/webrtc_audio_capturer_unittest.cc
@@ -2,9 +2,8 @@
// 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/logging.h"
-#include "content/public/common/content_switches.h"
+#include "content/public/renderer/media_stream_audio_sink.h"
#include "content/renderer/media/mock_media_constraint_factory.h"
#include "content/renderer/media/webrtc/webrtc_local_audio_track_adapter.h"
#include "content/renderer/media/webrtc_audio_capturer.h"
@@ -34,32 +33,22 @@ class MockCapturerSource : public media::AudioCapturerSource {
MOCK_METHOD1(SetAutomaticGainControl, void(bool enable));
protected:
- virtual ~MockCapturerSource() {}
+ ~MockCapturerSource() override {}
};
-class MockPeerConnectionAudioSink : public PeerConnectionAudioSink {
+class MockMediaStreamAudioSink : public MediaStreamAudioSink {
public:
- MockPeerConnectionAudioSink() {}
- ~MockPeerConnectionAudioSink() {}
- virtual int OnData(const int16* audio_data, int sample_rate,
- int number_of_channels, int number_of_frames,
- const std::vector<int>& channels,
- int audio_delay_milliseconds, int current_volume,
- bool need_audio_processing, bool key_pressed) override {
- EXPECT_EQ(sample_rate, params_.sample_rate());
- EXPECT_EQ(number_of_channels, params_.channels());
- EXPECT_EQ(number_of_frames, params_.frames_per_buffer());
- OnDataCallback(audio_data, channels, audio_delay_milliseconds,
- current_volume, need_audio_processing, key_pressed);
- return 0;
+ MockMediaStreamAudioSink() {}
+ ~MockMediaStreamAudioSink() override {}
+ void OnData(const media::AudioBus& audio_bus,
+ base::TimeTicks estimated_capture_time) override {
+ EXPECT_EQ(audio_bus.channels(), params_.channels());
+ EXPECT_EQ(audio_bus.frames(), params_.frames_per_buffer());
+ EXPECT_FALSE(estimated_capture_time.is_null());
+ OnDataCallback();
}
- MOCK_METHOD6(OnDataCallback, void(const int16* audio_data,
- const std::vector<int>& channels,
- int audio_delay_milliseconds,
- int current_volume,
- bool need_audio_processing,
- bool key_pressed));
- virtual void OnSetFormat(const media::AudioParameters& params) override {
+ MOCK_METHOD0(OnDataCallback, void());
+ void OnSetFormat(const media::AudioParameters& params) override {
params_ = params;
FormatIsSet();
}
@@ -84,24 +73,18 @@ class WebRtcAudioCapturerTest : public testing::Test {
#endif
}
- void DisableAudioTrackProcessing() {
- CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kDisableAudioTrackProcessing);
- }
-
void VerifyAudioParams(const blink::WebMediaConstraints& constraints,
bool need_audio_processing) {
capturer_ = WebRtcAudioCapturer::CreateCapturer(
- -1, StreamDeviceInfo(MEDIA_DEVICE_AUDIO_CAPTURE,
- "", "", params_.sample_rate(),
- params_.channel_layout(),
+ -1, StreamDeviceInfo(MEDIA_DEVICE_AUDIO_CAPTURE, "", "",
+ params_.sample_rate(), params_.channel_layout(),
params_.frames_per_buffer()),
constraints, NULL, NULL);
capturer_source_ = new MockCapturerSource();
EXPECT_CALL(*capturer_source_.get(), Initialize(_, capturer_.get(), -1));
EXPECT_CALL(*capturer_source_.get(), SetAutomaticGainControl(true));
EXPECT_CALL(*capturer_source_.get(), Start());
- capturer_->SetCapturerSourceForTesting(capturer_source_, params_);
+ capturer_->SetCapturerSource(capturer_source_, params_);
scoped_refptr<WebRtcLocalAudioTrackAdapter> adapter(
WebRtcLocalAudioTrackAdapter::Create(std::string(), NULL));
@@ -109,17 +92,13 @@ class WebRtcAudioCapturerTest : public testing::Test {
track_->Start();
// Connect a mock sink to the track.
- scoped_ptr<MockPeerConnectionAudioSink> sink(
- new MockPeerConnectionAudioSink());
+ scoped_ptr<MockMediaStreamAudioSink> sink(new MockMediaStreamAudioSink());
track_->AddSink(sink.get());
int delay_ms = 65;
bool key_pressed = true;
double volume = 0.9;
- // MaxVolume() in WebRtcAudioCapturer is hard-coded to return 255, we add
- // 0.5 to do the correct truncation like the production code does.
- int expected_volume_value = volume * capturer_->MaxVolume() + 0.5;
scoped_ptr<media::AudioBus> audio_bus = media::AudioBus::Create(params_);
audio_bus->Zero();
@@ -129,22 +108,9 @@ class WebRtcAudioCapturerTest : public testing::Test {
// Verify the sink is getting the correct values.
EXPECT_CALL(*sink, FormatIsSet());
- EXPECT_CALL(*sink,
- OnDataCallback(_, _, delay_ms, expected_volume_value,
- need_audio_processing, key_pressed))
- .Times(AtLeast(1));
+ EXPECT_CALL(*sink, OnDataCallback()).Times(AtLeast(1));
callback->Capture(audio_bus.get(), delay_ms, volume, key_pressed);
- // Verify the cached values in the capturer fits what we expect.
- base::TimeDelta cached_delay;
- int cached_volume = !expected_volume_value;
- bool cached_key_pressed = !key_pressed;
- capturer_->GetAudioProcessingParams(&cached_delay, &cached_volume,
- &cached_key_pressed);
- EXPECT_EQ(cached_delay.InMilliseconds(), delay_ms);
- EXPECT_EQ(cached_volume, expected_volume_value);
- EXPECT_EQ(cached_key_pressed, key_pressed);
-
track_->RemoveSink(sink.get());
EXPECT_CALL(*capturer_source_.get(), Stop());
capturer_->Stop();
@@ -156,15 +122,6 @@ class WebRtcAudioCapturerTest : public testing::Test {
scoped_ptr<WebRtcLocalAudioTrack> track_;
};
-// Pass the delay value, volume and key_pressed info via capture callback, and
-// those values should be correctly stored and passed to the track.
-TEST_F(WebRtcAudioCapturerTest, VerifyAudioParamsWithoutAudioProcessing) {
- DisableAudioTrackProcessing();
- // Use constraints with default settings.
- MockMediaConstraintFactory constraint_factory;
- VerifyAudioParams(constraint_factory.CreateWebMediaConstraints(), true);
-}
-
TEST_F(WebRtcAudioCapturerTest, VerifyAudioParamsWithAudioProcessing) {
// Turn off the default constraints to verify that the sink will get packets
// with a buffer size smaller than 10ms.
@@ -180,12 +137,10 @@ TEST_F(WebRtcAudioCapturerTest, FailToCreateCapturerWithWrongConstraints) {
scoped_refptr<WebRtcAudioCapturer> capturer(
WebRtcAudioCapturer::CreateCapturer(
- 0, StreamDeviceInfo(MEDIA_DEVICE_AUDIO_CAPTURE,
- "", "", params_.sample_rate(),
- params_.channel_layout(),
- params_.frames_per_buffer()),
- constraint_factory.CreateWebMediaConstraints(), NULL, NULL)
- );
+ 0, StreamDeviceInfo(MEDIA_DEVICE_AUDIO_CAPTURE, "", "",
+ params_.sample_rate(), params_.channel_layout(),
+ params_.frames_per_buffer()),
+ constraint_factory.CreateWebMediaConstraints(), NULL, NULL));
EXPECT_TRUE(capturer.get() == NULL);
}
diff --git a/chromium/content/renderer/media/webrtc_audio_device_impl.cc b/chromium/content/renderer/media/webrtc_audio_device_impl.cc
index 49e90683afd..a0817200c8f 100644
--- a/chromium/content/renderer/media/webrtc_audio_device_impl.cc
+++ b/chromium/content/renderer/media/webrtc_audio_device_impl.cc
@@ -23,14 +23,11 @@ namespace content {
WebRtcAudioDeviceImpl::WebRtcAudioDeviceImpl()
: ref_count_(0),
audio_transport_callback_(NULL),
- input_delay_ms_(0),
output_delay_ms_(0),
initialized_(false),
playing_(false),
recording_(false),
- microphone_volume_(0),
- is_audio_track_processing_enabled_(
- MediaStreamAudioProcessor::IsAudioTrackProcessingEnabled()) {
+ microphone_volume_(0) {
DVLOG(1) << "WebRtcAudioDeviceImpl::WebRtcAudioDeviceImpl()";
// This object can be constructed on either the signaling thread or the main
// thread, so we need to detach these thread checkers here and have them
@@ -63,91 +60,21 @@ int32_t WebRtcAudioDeviceImpl::Release() {
return ret;
}
-int WebRtcAudioDeviceImpl::OnData(const int16* audio_data,
- int sample_rate,
- int number_of_channels,
- int number_of_frames,
- const std::vector<int>& channels,
- int audio_delay_milliseconds,
- int current_volume,
- bool need_audio_processing,
- bool key_pressed) {
- DCHECK(worker_thread_checker_.CalledOnValidThread());
- int total_delay_ms = 0;
- {
- base::AutoLock auto_lock(lock_);
- // Return immediately when not recording or |channels| is empty.
- // See crbug.com/274017: renderer crash dereferencing invalid channels[0].
- if (!recording_ || channels.empty())
- return 0;
-
- // Store the reported audio delay locally.
- input_delay_ms_ = audio_delay_milliseconds;
- total_delay_ms = input_delay_ms_ + output_delay_ms_;
- DVLOG(2) << "total delay: " << input_delay_ms_ + output_delay_ms_;
- }
-
- // Write audio frames in blocks of 10 milliseconds to the registered
- // webrtc::AudioTransport sink. Keep writing until our internal byte
- // buffer is empty.
- const int16* audio_buffer = audio_data;
- const int frames_per_10_ms = (sample_rate / 100);
- CHECK_EQ(number_of_frames % frames_per_10_ms, 0);
- int accumulated_audio_frames = 0;
- uint32_t new_volume = 0;
-
- // The lock here is to protect a race in the resampler inside webrtc when
- // there are more than one input stream calling OnData(), which can happen
- // when the users setup two getUserMedia, one for the microphone, another
- // for WebAudio. Currently we don't have a better way to fix it except for
- // adding a lock here to sequence the call.
- // TODO(xians): Remove this workaround after we move the
- // webrtc::AudioProcessing module to Chrome. See http://crbug/264611 for
- // details.
- base::AutoLock auto_lock(capture_callback_lock_);
- while (accumulated_audio_frames < number_of_frames) {
- // Deliver 10ms of recorded 16-bit linear PCM audio.
- int new_mic_level = audio_transport_callback_->OnDataAvailable(
- &channels[0],
- channels.size(),
- audio_buffer,
- sample_rate,
- number_of_channels,
- frames_per_10_ms,
- total_delay_ms,
- current_volume,
- key_pressed,
- need_audio_processing);
-
- accumulated_audio_frames += frames_per_10_ms;
- audio_buffer += frames_per_10_ms * number_of_channels;
-
- // The latest non-zero new microphone level will be returned.
- if (new_mic_level)
- new_volume = new_mic_level;
- }
-
- return new_volume;
-}
-
-void WebRtcAudioDeviceImpl::OnSetFormat(
- const media::AudioParameters& params) {
- DVLOG(1) << "WebRtcAudioDeviceImpl::OnSetFormat()";
-}
-
void WebRtcAudioDeviceImpl::RenderData(media::AudioBus* audio_bus,
int sample_rate,
int audio_delay_milliseconds,
base::TimeDelta* current_time) {
- render_buffer_.resize(audio_bus->frames() * audio_bus->channels());
-
{
base::AutoLock auto_lock(lock_);
+ if (!playing_) {
+ return;
+ }
DCHECK(audio_transport_callback_);
// Store the reported audio delay locally.
output_delay_ms_ = audio_delay_milliseconds;
}
+ render_buffer_.resize(audio_bus->frames() * audio_bus->channels());
int frames_per_10_ms = (sample_rate / 100);
int bytes_per_sample = sizeof(render_buffer_[0]);
const int bytes_per_10_ms =
@@ -157,40 +84,21 @@ void WebRtcAudioDeviceImpl::RenderData(media::AudioBus* audio_bus,
// Get audio frames in blocks of 10 milliseconds from the registered
// webrtc::AudioTransport source. Keep reading until our internal buffer
// is full.
- uint32_t num_audio_frames = 0;
int accumulated_audio_frames = 0;
int16* audio_data = &render_buffer_[0];
while (accumulated_audio_frames < audio_bus->frames()) {
// Get 10ms and append output to temporary byte buffer.
int64_t elapsed_time_ms = -1;
int64_t ntp_time_ms = -1;
- if (is_audio_track_processing_enabled_) {
- // When audio processing is enabled in the audio track, we use
- // PullRenderData() instead of NeedMorePlayData() to avoid passing the
- // render data to the APM in WebRTC as reference signal for echo
- // cancellation.
- static const int kBitsPerByte = 8;
- audio_transport_callback_->PullRenderData(bytes_per_sample * kBitsPerByte,
- sample_rate,
- audio_bus->channels(),
- frames_per_10_ms,
- audio_data,
- &elapsed_time_ms,
- &ntp_time_ms);
- accumulated_audio_frames += frames_per_10_ms;
- } else {
- // TODO(xians): Remove the following code after the APM in WebRTC is
- // deprecated.
- audio_transport_callback_->NeedMorePlayData(frames_per_10_ms,
- bytes_per_sample,
- audio_bus->channels(),
- sample_rate,
- audio_data,
- num_audio_frames,
- &elapsed_time_ms,
- &ntp_time_ms);
- accumulated_audio_frames += num_audio_frames;
- }
+ static const int kBitsPerByte = 8;
+ audio_transport_callback_->PullRenderData(bytes_per_sample * kBitsPerByte,
+ sample_rate,
+ audio_bus->channels(),
+ frames_per_10_ms,
+ audio_data,
+ &elapsed_time_ms,
+ &ntp_time_ms);
+ accumulated_audio_frames += frames_per_10_ms;
if (elapsed_time_ms >= 0) {
*current_time = base::TimeDelta::FromMilliseconds(elapsed_time_ms);
}
@@ -222,7 +130,6 @@ void WebRtcAudioDeviceImpl::RemoveAudioRenderer(WebRtcAudioRenderer* renderer) {
}
renderer_ = NULL;
- playing_ = false;
}
int32_t WebRtcAudioDeviceImpl::RegisterAudioCallback(
@@ -460,9 +367,11 @@ int32_t WebRtcAudioDeviceImpl::PlayoutDelay(uint16_t* delay_ms) const {
int32_t WebRtcAudioDeviceImpl::RecordingDelay(uint16_t* delay_ms) const {
DCHECK(signaling_thread_checker_.CalledOnValidThread());
- base::AutoLock auto_lock(lock_);
- *delay_ms = static_cast<uint16_t>(input_delay_ms_);
- return 0;
+
+ // There is no way to report a correct delay value to WebRTC since there
+ // might be multiple WebRtcAudioCapturer instances.
+ NOTREACHED();
+ return -1;
}
int32_t WebRtcAudioDeviceImpl::RecordingSampleRate(
@@ -489,13 +398,30 @@ bool WebRtcAudioDeviceImpl::SetAudioRenderer(WebRtcAudioRenderer* renderer) {
DCHECK(main_thread_checker_.CalledOnValidThread());
DCHECK(renderer);
- base::AutoLock auto_lock(lock_);
- if (renderer_.get())
- return false;
+ // Here we acquire |lock_| in order to protect the internal state.
+ {
+ base::AutoLock auto_lock(lock_);
+ if (renderer_.get())
+ return false;
+ }
+ // We release |lock_| here because invoking |renderer|->Initialize while
+ // holding |lock_| would result in locks taken in the sequence
+ // (|this->lock_|, |renderer->lock_|) while another thread (i.e, the
+ // AudioOutputDevice thread) might concurrently invoke a renderer method,
+ // which can itself invoke a method from |this|, resulting in locks taken in
+ // the sequence (|renderer->lock_|, |this->lock_|) in that thread.
+ // This order discrepancy can cause a deadlock (see Issue 433993).
+ // However, we do not need to hold |this->lock_| in order to invoke
+ // |renderer|->Initialize, since it does not involve any unprotected access to
+ // the internal state of |this|.
if (!renderer->Initialize(this))
return false;
+ // We acquire |lock_| again and assert our precondition, since we are
+ // accessing the internal state again.
+ base::AutoLock auto_lock(lock_);
+ DCHECK(!renderer_.get());
renderer_ = renderer;
return true;
}
diff --git a/chromium/content/renderer/media/webrtc_audio_device_impl.h b/chromium/content/renderer/media/webrtc_audio_device_impl.h
index debb4b71b2e..0368a90d496 100644
--- a/chromium/content/renderer/media/webrtc_audio_device_impl.h
+++ b/chromium/content/renderer/media/webrtc_audio_device_impl.h
@@ -167,7 +167,9 @@
// most methods are called on the same thread. However, some methods are
// also called on a Libjingle worker thread. RenderData is called on the
// AudioOutputDevice thread and CaptureData on the AudioInputDevice thread.
-// To summarize: this class lives on four different threads.
+// To summarize: this class lives on four different threads, so it is
+// important to be careful with the order in which locks are acquired in
+// order to avoid potential deadlocks.
// - The webrtc::AudioDeviceModule is reference counted.
// - AGC is only supported in combination with the WASAPI-based audio layer
// on Windows, i.e., it is not supported on Windows XP.
@@ -199,39 +201,6 @@ class WebRtcAudioRendererSource {
virtual ~WebRtcAudioRendererSource() {}
};
-class PeerConnectionAudioSink {
- public:
- // Callback to deliver the captured interleaved data.
- // |channels| contains a vector of WebRtc VoE channels.
- // |audio_data| is the pointer to the audio data.
- // |sample_rate| is the sample frequency of audio data.
- // |number_of_channels| is the number of channels reflecting the order of
- // surround sound channels.
- // |audio_delay_milliseconds| is recording delay value.
- // |current_volume| is current microphone volume, in range of |0, 255].
- // |need_audio_processing| indicates if the audio needs WebRtc AEC/NS/AGC
- // audio processing.
- // The return value is the new microphone volume, in the range of |0, 255].
- // When the volume does not need to be updated, it returns 0.
- virtual int OnData(const int16* audio_data,
- int sample_rate,
- int number_of_channels,
- int number_of_frames,
- const std::vector<int>& channels,
- int audio_delay_milliseconds,
- int current_volume,
- bool need_audio_processing,
- bool key_pressed) = 0;
-
- // Set the format for the capture audio parameters.
- // This is called when the capture format has changed, and it must be called
- // on the same thread as calling CaptureData().
- virtual void OnSetFormat(const media::AudioParameters& params) = 0;
-
- protected:
- virtual ~PeerConnectionAudioSink() {}
-};
-
// TODO(xians): Merge this interface with WebRtcAudioRendererSource.
// The reason why we could not do it today is that WebRtcAudioRendererSource
// gets the data by pulling, while the data is pushed into
@@ -268,8 +237,7 @@ class WebRtcPlayoutDataSource {
// the high number of non-implemented methods, we move the cruft over to the
// WebRtcAudioDeviceNotImpl.
class CONTENT_EXPORT WebRtcAudioDeviceImpl
- : NON_EXPORTED_BASE(public PeerConnectionAudioSink),
- NON_EXPORTED_BASE(public WebRtcAudioDeviceNotImpl),
+ : NON_EXPORTED_BASE(public WebRtcAudioDeviceNotImpl),
NON_EXPORTED_BASE(public WebRtcAudioRendererSource),
NON_EXPORTED_BASE(public WebRtcPlayoutDataSource) {
public:
@@ -363,22 +331,6 @@ class CONTENT_EXPORT WebRtcAudioDeviceImpl
// Make destructor private to ensure that we can only be deleted by Release().
~WebRtcAudioDeviceImpl() override;
- // PeerConnectionAudioSink implementation.
-
- // Called on the AudioInputDevice worker thread.
- int OnData(const int16* audio_data,
- int sample_rate,
- int number_of_channels,
- int number_of_frames,
- const std::vector<int>& channels,
- int audio_delay_milliseconds,
- int current_volume,
- bool need_audio_processing,
- bool key_pressed) override;
-
- // Called on the AudioInputDevice worker thread.
- void OnSetFormat(const media::AudioParameters& params) override;
-
// WebRtcAudioRendererSource implementation.
// Called on the AudioOutputDevice worker thread.
@@ -445,9 +397,6 @@ class CONTENT_EXPORT WebRtcAudioDeviceImpl
// It is only accessed by the audio render thread.
std::vector<int16> render_buffer_;
- // Flag to tell if audio processing is enabled in MediaStreamAudioProcessor.
- const bool is_audio_track_processing_enabled_;
-
DISALLOW_COPY_AND_ASSIGN(WebRtcAudioDeviceImpl);
};
diff --git a/chromium/content/renderer/media/webrtc_audio_device_not_impl.cc b/chromium/content/renderer/media/webrtc_audio_device_not_impl.cc
index b838c21ebc3..234bf87f7d3 100644
--- a/chromium/content/renderer/media/webrtc_audio_device_not_impl.cc
+++ b/chromium/content/renderer/media/webrtc_audio_device_not_impl.cc
@@ -4,27 +4,16 @@
#include "content/renderer/media/webrtc_audio_device_not_impl.h"
-namespace {
-
-const int64 kMillisecondsBetweenProcessCalls = 5000;
-
-} // namespace
-
namespace content {
WebRtcAudioDeviceNotImpl::WebRtcAudioDeviceNotImpl()
: last_process_time_(base::TimeTicks::Now()) {
}
-int32_t WebRtcAudioDeviceNotImpl::ChangeUniqueId(const int32_t id) {
- return 0;
-}
-
-int32_t WebRtcAudioDeviceNotImpl::TimeUntilNextProcess() {
+int64_t WebRtcAudioDeviceNotImpl::TimeUntilNextProcess() {
+ const int64_t kMillisecondsBetweenProcessCalls = 5000;
base::TimeDelta delta_time = (base::TimeTicks::Now() - last_process_time_);
- int64 time_until_next =
- kMillisecondsBetweenProcessCalls - delta_time.InMilliseconds();
- return static_cast<int32_t>(time_until_next);
+ return kMillisecondsBetweenProcessCalls - delta_time.InMilliseconds();
}
int32_t WebRtcAudioDeviceNotImpl::Process() {
@@ -274,4 +263,12 @@ bool WebRtcAudioDeviceNotImpl::AGC() const {
return true;
}
+bool WebRtcAudioDeviceNotImpl::BuiltInAECIsAvailable() const {
+ return false;
+}
+
+int32_t WebRtcAudioDeviceNotImpl::EnableBuiltInAEC(bool enable) {
+ return 0;
+}
+
} // namespace content
diff --git a/chromium/content/renderer/media/webrtc_audio_device_not_impl.h b/chromium/content/renderer/media/webrtc_audio_device_not_impl.h
index 00c6a231a8a..1ba1b078f9b 100644
--- a/chromium/content/renderer/media/webrtc_audio_device_not_impl.h
+++ b/chromium/content/renderer/media/webrtc_audio_device_not_impl.h
@@ -28,8 +28,7 @@ class CONTENT_EXPORT WebRtcAudioDeviceNotImpl
// TODO(henrika): it is possible to add functionality in these methods.
// Only adding very basic support for now without triggering any callback
// in the webrtc::AudioDeviceObserver interface.
- int32_t ChangeUniqueId(const int32_t id) override;
- int32_t TimeUntilNextProcess() override;
+ int64_t TimeUntilNextProcess() override;
int32_t Process() override;
// Methods in webrtc::AudioDeviceModule which are not yet implemented.
@@ -101,6 +100,8 @@ class CONTENT_EXPORT WebRtcAudioDeviceNotImpl
int32_t GetLoudspeakerStatus(bool* enabled) const override;
int32_t SetAGC(bool enable) override;
bool AGC() const override;
+ bool BuiltInAECIsAvailable() const override;
+ int32_t EnableBuiltInAEC(bool enable) override;
protected:
~WebRtcAudioDeviceNotImpl() override{};
diff --git a/chromium/content/renderer/media/webrtc_audio_renderer.cc b/chromium/content/renderer/media/webrtc_audio_renderer.cc
index 862c3fd72ac..dcc153c3bd7 100644
--- a/chromium/content/renderer/media/webrtc_audio_renderer.cc
+++ b/chromium/content/renderer/media/webrtc_audio_renderer.cc
@@ -178,13 +178,11 @@ int WebRtcAudioRenderer::GetOptimalBufferSize(int sample_rate,
WebRtcAudioRenderer::WebRtcAudioRenderer(
const scoped_refptr<base::SingleThreadTaskRunner>& signaling_thread,
const scoped_refptr<webrtc::MediaStreamInterface>& media_stream,
- int source_render_view_id,
int source_render_frame_id,
int session_id,
int sample_rate,
int frames_per_buffer)
: state_(UNINITIALIZED),
- source_render_view_id_(source_render_view_id),
source_render_frame_id_(source_render_frame_id),
session_id_(session_id),
signaling_thread_(signaling_thread),
@@ -200,12 +198,9 @@ WebRtcAudioRenderer::WebRtcAudioRenderer(
GetCurrentDuckingFlag(source_render_frame_id)),
render_callback_count_(0) {
WebRtcLogMessage(base::StringPrintf(
- "WAR::WAR. source_render_view_id=%d"
+ "WAR::WAR. source_render_frame_id=%d"
", session_id=%d, sample_rate=%d, frames_per_buffer=%d, effects=%i",
- source_render_view_id,
- session_id,
- sample_rate,
- frames_per_buffer,
+ source_render_frame_id, session_id, sample_rate, frames_per_buffer,
sink_params_.effects()));
}
@@ -288,8 +283,7 @@ bool WebRtcAudioRenderer::Initialize(WebRtcAudioRendererSource* source) {
source_ = source;
// Configure the audio rendering client and start rendering.
- sink_ = AudioDeviceFactory::NewOutputDevice(
- source_render_view_id_, source_render_frame_id_);
+ sink_ = AudioDeviceFactory::NewOutputDevice(source_render_frame_id_);
DCHECK_GE(session_id_, 0);
sink_->InitializeWithSessionId(sink_params_, this, session_id_);
diff --git a/chromium/content/renderer/media/webrtc_audio_renderer.h b/chromium/content/renderer/media/webrtc_audio_renderer.h
index d6bd923de8b..6d718e48abd 100644
--- a/chromium/content/renderer/media/webrtc_audio_renderer.h
+++ b/chromium/content/renderer/media/webrtc_audio_renderer.h
@@ -76,7 +76,6 @@ class CONTENT_EXPORT WebRtcAudioRenderer
WebRtcAudioRenderer(
const scoped_refptr<base::SingleThreadTaskRunner>& signaling_thread,
const scoped_refptr<webrtc::MediaStreamInterface>& media_stream,
- int source_render_view_id,
int source_render_frame_id,
int session_id,
int sample_rate,
@@ -185,8 +184,7 @@ class CONTENT_EXPORT WebRtcAudioRenderer
const scoped_refptr<webrtc::MediaStreamInterface>& media_stream,
PlayingState* state);
- // The render view and frame in which the audio is rendered into |sink_|.
- const int source_render_view_id_;
+ // The RenderFrame in which the audio is rendered into |sink_|.
const int source_render_frame_id_;
const int session_id_;
diff --git a/chromium/content/renderer/media/webrtc_audio_renderer_unittest.cc b/chromium/content/renderer/media/webrtc_audio_renderer_unittest.cc
index 545236492c1..a0fbba3855f 100644
--- a/chromium/content/renderer/media/webrtc_audio_renderer_unittest.cc
+++ b/chromium/content/renderer/media/webrtc_audio_renderer_unittest.cc
@@ -92,7 +92,10 @@ class WebRtcAudioRendererTest : public testing::Test {
source_(new MockAudioRendererSource()),
stream_(new rtc::RefCountedObject<MockMediaStream>("label")),
renderer_(new WebRtcAudioRenderer(message_loop_->message_loop_proxy(),
- stream_, 1, 1, 1, 44100,
+ stream_,
+ 1,
+ 1,
+ 44100,
kHardwareBufferSize)) {
EXPECT_CALL(*factory_.get(), CreateOutputDevice(1))
.WillOnce(Return(mock_output_device_.get()));
diff --git a/chromium/content/renderer/media/webrtc_identity_service_unittest.cc b/chromium/content/renderer/media/webrtc_identity_service_unittest.cc
index 38059714f21..1df1ea9aea1 100644
--- a/chromium/content/renderer/media/webrtc_identity_service_unittest.cc
+++ b/chromium/content/renderer/media/webrtc_identity_service_unittest.cc
@@ -20,7 +20,7 @@ static const char FAKE_CERTIFICATE[] = "fake cert";
static const char FAKE_PRIVATE_KEY[] = "fake private key";
static const int FAKE_ERROR = 100;
-class WebRTCIdentityServiceForTest : public WebRTCIdentityService {
+class WebRtcIdentityServiceForTest : public WebRTCIdentityService {
public:
bool Send(IPC::Message* message) override {
messages_.push_back(*message);
@@ -42,10 +42,10 @@ class WebRTCIdentityServiceForTest : public WebRTCIdentityService {
std::deque<IPC::Message> messages_;
};
-class WebRTCIdentityServiceTest : public ::testing::Test {
+class WebRtcIdentityServiceTest : public ::testing::Test {
public:
- WebRTCIdentityServiceTest()
- : service_(new WebRTCIdentityServiceForTest()), last_error_(0) {}
+ WebRtcIdentityServiceTest()
+ : service_(new WebRtcIdentityServiceForTest()), last_error_(0) {}
protected:
void OnIdentityReady(const std::string& cert, const std::string& key) {
@@ -66,13 +66,13 @@ class WebRTCIdentityServiceTest : public ::testing::Test {
GURL(FAKE_ORIGIN),
FAKE_IDENTITY_NAME,
FAKE_COMMON_NAME,
- base::Bind(&WebRTCIdentityServiceTest::OnIdentityReady,
+ base::Bind(&WebRtcIdentityServiceTest::OnIdentityReady,
base::Unretained(this)),
- base::Bind(&WebRTCIdentityServiceTest::OnRequestFailed,
+ base::Bind(&WebRtcIdentityServiceTest::OnRequestFailed,
base::Unretained(this)));
}
- scoped_ptr<WebRTCIdentityServiceForTest> service_;
+ scoped_ptr<WebRtcIdentityServiceForTest> service_;
std::string last_certificate_;
std::string last_private_key_;
int last_error_;
@@ -80,14 +80,14 @@ class WebRTCIdentityServiceTest : public ::testing::Test {
} // namespace
-TEST_F(WebRTCIdentityServiceTest, TestSendRequest) {
+TEST_F(WebRtcIdentityServiceTest, TestSendRequest) {
RequestIdentity();
IPC::Message ipc = service_->GetLastMessage();
EXPECT_EQ(ipc.type(), WebRTCIdentityMsg_RequestIdentity::ID);
}
-TEST_F(WebRTCIdentityServiceTest, TestSuccessCallback) {
+TEST_F(WebRtcIdentityServiceTest, TestSuccessCallback) {
int id = RequestIdentity();
service_->OnControlMessageReceived(WebRTCIdentityHostMsg_IdentityReady(
@@ -96,7 +96,7 @@ TEST_F(WebRTCIdentityServiceTest, TestSuccessCallback) {
EXPECT_EQ(FAKE_PRIVATE_KEY, last_private_key_);
}
-TEST_F(WebRTCIdentityServiceTest, TestFailureCallback) {
+TEST_F(WebRtcIdentityServiceTest, TestFailureCallback) {
int id = RequestIdentity();
service_->OnControlMessageReceived(
@@ -104,7 +104,7 @@ TEST_F(WebRTCIdentityServiceTest, TestFailureCallback) {
EXPECT_EQ(FAKE_ERROR, last_error_);
}
-TEST_F(WebRTCIdentityServiceTest, TestCancelRequest) {
+TEST_F(WebRtcIdentityServiceTest, TestCancelRequest) {
int request_id = RequestIdentity();
service_->ClearMessages();
@@ -114,7 +114,7 @@ TEST_F(WebRTCIdentityServiceTest, TestCancelRequest) {
EXPECT_EQ(ipc.type(), WebRTCIdentityMsg_CancelRequest::ID);
}
-TEST_F(WebRTCIdentityServiceTest, TestQueuedRequestSentAfterSuccess) {
+TEST_F(WebRtcIdentityServiceTest, TestQueuedRequestSentAfterSuccess) {
int id = RequestIdentity();
RequestIdentity();
EXPECT_EQ(1, service_->GetNumberOfMessages());
@@ -127,7 +127,7 @@ TEST_F(WebRTCIdentityServiceTest, TestQueuedRequestSentAfterSuccess) {
EXPECT_EQ(ipc.type(), WebRTCIdentityMsg_RequestIdentity::ID);
}
-TEST_F(WebRTCIdentityServiceTest, TestQueuedRequestSentAfterFailure) {
+TEST_F(WebRtcIdentityServiceTest, TestQueuedRequestSentAfterFailure) {
int id = RequestIdentity();
RequestIdentity();
EXPECT_EQ(1, service_->GetNumberOfMessages());
@@ -140,7 +140,7 @@ TEST_F(WebRTCIdentityServiceTest, TestQueuedRequestSentAfterFailure) {
EXPECT_EQ(ipc.type(), WebRTCIdentityMsg_RequestIdentity::ID);
}
-TEST_F(WebRTCIdentityServiceTest, TestQueuedRequestSentAfterCancelOutstanding) {
+TEST_F(WebRtcIdentityServiceTest, TestQueuedRequestSentAfterCancelOutstanding) {
int outstand_request_id = RequestIdentity();
RequestIdentity();
@@ -156,7 +156,7 @@ TEST_F(WebRTCIdentityServiceTest, TestQueuedRequestSentAfterCancelOutstanding) {
EXPECT_EQ(ipc.type(), WebRTCIdentityMsg_RequestIdentity::ID);
}
-TEST_F(WebRTCIdentityServiceTest, TestCancelQueuedRequest) {
+TEST_F(WebRtcIdentityServiceTest, TestCancelQueuedRequest) {
int sent_id = RequestIdentity();
int queued_request_id = RequestIdentity();
EXPECT_EQ(1, service_->GetNumberOfMessages());
@@ -172,7 +172,7 @@ TEST_F(WebRTCIdentityServiceTest, TestCancelQueuedRequest) {
EXPECT_EQ(0, service_->GetNumberOfMessages());
}
-TEST_F(WebRTCIdentityServiceTest, TestQueuedRequestSuccessCallback) {
+TEST_F(WebRtcIdentityServiceTest, TestQueuedRequestSuccessCallback) {
int id1 = RequestIdentity();
int id2 = RequestIdentity();
@@ -190,7 +190,7 @@ TEST_F(WebRTCIdentityServiceTest, TestQueuedRequestSuccessCallback) {
EXPECT_EQ(FAKE_PRIVATE_KEY, last_private_key_);
}
-TEST_F(WebRTCIdentityServiceTest, TestQueuedRequestFailureCallback) {
+TEST_F(WebRtcIdentityServiceTest, TestQueuedRequestFailureCallback) {
int id1 = RequestIdentity();
int id2 = RequestIdentity();
@@ -209,7 +209,7 @@ TEST_F(WebRTCIdentityServiceTest, TestQueuedRequestFailureCallback) {
// Verifies that receiving a response for a cancelled request does not incur the
// callbacks.
-TEST_F(WebRTCIdentityServiceTest, TestRequestCompletedAfterCancelled) {
+TEST_F(WebRtcIdentityServiceTest, TestRequestCompletedAfterCancelled) {
int id1 = RequestIdentity();
RequestIdentity();
service_->CancelRequest(id1);
diff --git a/chromium/content/renderer/media/webrtc_local_audio_renderer.cc b/chromium/content/renderer/media/webrtc_local_audio_renderer.cc
index dd657eb7c3e..727ed361d12 100644
--- a/chromium/content/renderer/media/webrtc_local_audio_renderer.cc
+++ b/chromium/content/renderer/media/webrtc_local_audio_renderer.cc
@@ -4,19 +4,19 @@
#include "content/renderer/media/webrtc_local_audio_renderer.h"
-#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/metrics/histogram.h"
#include "base/synchronization/lock.h"
+#include "base/trace_event/trace_event.h"
#include "content/renderer/media/audio_device_factory.h"
#include "content/renderer/media/media_stream_dispatcher.h"
#include "content/renderer/media/webrtc_audio_capturer.h"
#include "content/renderer/media/webrtc_audio_renderer.h"
#include "content/renderer/render_frame_impl.h"
#include "media/audio/audio_output_device.h"
-#include "media/base/audio_block_fifo.h"
#include "media/base/audio_bus.h"
+#include "media/base/audio_shifter.h"
namespace content {
@@ -36,23 +36,15 @@ int WebRtcLocalAudioRenderer::Render(
TRACE_EVENT0("audio", "WebRtcLocalAudioRenderer::Render");
base::AutoLock auto_lock(thread_lock_);
- if (!playing_ || !volume_ || !loopback_fifo_) {
+ if (!playing_ || !volume_ || !audio_shifter_) {
audio_bus->Zero();
return 0;
}
- // Provide data by reading from the FIFO if the FIFO contains enough
- // to fulfill the request.
- if (loopback_fifo_->available_blocks()) {
- const media::AudioBus* audio_data = loopback_fifo_->Consume();
- DCHECK_EQ(audio_data->frames(), audio_bus->frames());
- audio_data->CopyTo(audio_bus);
- } else {
- audio_bus->Zero();
- // This warning is perfectly safe if it happens for the first audio
- // frames. It should not happen in a steady-state mode.
- DVLOG(2) << "loopback FIFO is empty";
- }
+ audio_shifter_->Pull(
+ audio_bus,
+ base::TimeTicks::Now() -
+ base::TimeDelta::FromMilliseconds(audio_delay_milliseconds));
return audio_bus->frames();
}
@@ -62,26 +54,24 @@ void WebRtcLocalAudioRenderer::OnRenderError() {
}
// content::MediaStreamAudioSink implementation
-void WebRtcLocalAudioRenderer::OnData(const int16* audio_data,
- int sample_rate,
- int number_of_channels,
- int number_of_frames) {
+void WebRtcLocalAudioRenderer::OnData(const media::AudioBus& audio_bus,
+ base::TimeTicks estimated_capture_time) {
DCHECK(capture_thread_checker_.CalledOnValidThread());
+ DCHECK(!estimated_capture_time.is_null());
+
TRACE_EVENT0("audio", "WebRtcLocalAudioRenderer::CaptureData");
+
base::AutoLock auto_lock(thread_lock_);
- if (!playing_ || !volume_ || !loopback_fifo_)
+ if (!playing_ || !volume_ || !audio_shifter_)
return;
- // Push captured audio to FIFO so it can be read by a local sink.
- if (loopback_fifo_->GetUnfilledFrames() >= number_of_frames) {
- loopback_fifo_->Push(audio_data, number_of_frames, sizeof(audio_data[0]));
-
- const base::TimeTicks now = base::TimeTicks::Now();
- total_render_time_ += now - last_render_time_;
- last_render_time_ = now;
- } else {
- DVLOG(1) << "FIFO is full";
- }
+ scoped_ptr<media::AudioBus> audio_data(
+ media::AudioBus::Create(audio_bus.channels(), audio_bus.frames()));
+ audio_bus.CopyTo(audio_data.get());
+ audio_shifter_->Push(audio_data.Pass(), estimated_capture_time);
+ const base::TimeTicks now = base::TimeTicks::Now();
+ total_render_time_ += now - last_render_time_;
+ last_render_time_ = now;
}
void WebRtcLocalAudioRenderer::OnSetFormat(
@@ -103,12 +93,10 @@ void WebRtcLocalAudioRenderer::OnSetFormat(
// WebRtcLocalAudioRenderer::WebRtcLocalAudioRenderer implementation.
WebRtcLocalAudioRenderer::WebRtcLocalAudioRenderer(
const blink::WebMediaStreamTrack& audio_track,
- int source_render_view_id,
int source_render_frame_id,
int session_id,
int frames_per_buffer)
: audio_track_(audio_track),
- source_render_view_id_(source_render_view_id),
source_render_frame_id_(source_render_frame_id),
session_id_(session_id),
message_loop_(base::MessageLoopProxy::current()),
@@ -133,8 +121,7 @@ void WebRtcLocalAudioRenderer::Start() {
MediaStreamAudioSink::AddToAudioTrack(this, audio_track_);
// ...and |sink_| will get audio data from us.
DCHECK(!sink_.get());
- sink_ = AudioDeviceFactory::NewOutputDevice(source_render_view_id_,
- source_render_frame_id_);
+ sink_ = AudioDeviceFactory::NewOutputDevice(source_render_frame_id_);
base::AutoLock auto_lock(thread_lock_);
last_render_time_ = base::TimeTicks::Now();
@@ -148,7 +135,7 @@ void WebRtcLocalAudioRenderer::Stop() {
{
base::AutoLock auto_lock(thread_lock_);
playing_ = false;
- loopback_fifo_.reset();
+ audio_shifter_.reset();
}
// Stop the output audio stream, i.e, stop asking for data to render.
@@ -242,7 +229,7 @@ void WebRtcLocalAudioRenderer::MaybeStartSink() {
{
// Clear up the old data in the FIFO.
base::AutoLock auto_lock(thread_lock_);
- loopback_fifo_->Clear();
+ audio_shifter_->Flush();
}
if (!sink_params_.IsValid() || !playing_ || !volume_ || sink_started_)
@@ -292,21 +279,19 @@ void WebRtcLocalAudioRenderer::ReconfigureSink(
source_params_.effects() | implicit_ducking_effect);
{
- // TODO(henrika): we could add a more dynamic solution here but I prefer
- // a fixed size combined with bad audio at overflow. The alternative is
- // that we start to build up latency and that can be more difficult to
- // detect. Tests have shown that the FIFO never contains more than 2 or 3
- // audio frames but I have selected a max size of ten buffers just
- // in case since these tests were performed on a 16 core, 64GB Win 7
- // machine. We could also add some sort of error notifier in this area if
- // the FIFO overflows.
- const int blocks_of_buffers =
- 10 * params.frames_per_buffer() / sink_params_.frames_per_buffer() + 1;
- media::AudioBlockFifo* new_fifo = new media::AudioBlockFifo(
- params.channels(), sink_params_.frames_per_buffer(), blocks_of_buffers);
+ // Note: The max buffer is fairly large, but will rarely be used.
+ // Cast needs the buffer to hold at least one second of audio.
+ // The clock accuracy is set to 20ms because clock accuracy is
+ // ~15ms on windows.
+ media::AudioShifter* const new_shifter = new media::AudioShifter(
+ base::TimeDelta::FromSeconds(2),
+ base::TimeDelta::FromMilliseconds(20),
+ base::TimeDelta::FromSeconds(20),
+ source_params_.sample_rate(),
+ params.channels());
base::AutoLock auto_lock(thread_lock_);
- loopback_fifo_.reset(new_fifo);
+ audio_shifter_.reset(new_shifter);
}
if (!sink_.get())
@@ -319,8 +304,7 @@ void WebRtcLocalAudioRenderer::ReconfigureSink(
sink_started_ = false;
}
- sink_ = AudioDeviceFactory::NewOutputDevice(source_render_view_id_,
- source_render_frame_id_);
+ sink_ = AudioDeviceFactory::NewOutputDevice(source_render_frame_id_);
MaybeStartSink();
}
diff --git a/chromium/content/renderer/media/webrtc_local_audio_renderer.h b/chromium/content/renderer/media/webrtc_local_audio_renderer.h
index 95987f4d870..4764e1b8ee4 100644
--- a/chromium/content/renderer/media/webrtc_local_audio_renderer.h
+++ b/chromium/content/renderer/media/webrtc_local_audio_renderer.h
@@ -21,7 +21,7 @@
namespace media {
class AudioBus;
-class AudioBlockFifo;
+class AudioShifter;
class AudioOutputDevice;
class AudioParameters;
}
@@ -51,7 +51,6 @@ class CONTENT_EXPORT WebRtcLocalAudioRenderer
// The |source| is owned by the WebRtcAudioDeviceImpl.
// Called on the main thread.
WebRtcLocalAudioRenderer(const blink::WebMediaStreamTrack& audio_track,
- int source_render_view_id,
int source_render_frame_id,
int session_id,
int frames_per_buffer);
@@ -77,10 +76,8 @@ class CONTENT_EXPORT WebRtcLocalAudioRenderer
// MediaStreamAudioSink implementation.
// Called on the AudioInputDevice worker thread.
- void OnData(const int16* audio_data,
- int sample_rate,
- int number_of_channels,
- int number_of_frames) override;
+ void OnData(const media::AudioBus& audio_bus,
+ base::TimeTicks estimated_capture_time) override;
// Called on the AudioInputDevice worker thread.
void OnSetFormat(const media::AudioParameters& params) override;
@@ -111,7 +108,6 @@ class CONTENT_EXPORT WebRtcLocalAudioRenderer
blink::WebMediaStreamTrack audio_track_;
// The render view and frame in which the audio is rendered into |sink_|.
- const int source_render_view_id_;
const int source_render_frame_id_;
const int session_id_;
@@ -122,8 +118,8 @@ class CONTENT_EXPORT WebRtcLocalAudioRenderer
// The sink (destination) for rendered audio.
scoped_refptr<media::AudioOutputDevice> sink_;
- // Contains copies of captured audio frames.
- scoped_ptr<media::AudioBlockFifo> loopback_fifo_;
+ // This does all the synchronization/resampling/smoothing.
+ scoped_ptr<media::AudioShifter> audio_shifter_;
// Stores last time a render callback was received. The time difference
// between a new time stamp and this value can be used to derive the
@@ -144,7 +140,7 @@ class CONTENT_EXPORT WebRtcLocalAudioRenderer
// Set when playing, cleared when paused.
bool playing_;
- // Protects |loopback_fifo_|, |playing_| and |sink_|.
+ // Protects |audio_shifter_|, |playing_| and |sink_|.
mutable base::Lock thread_lock_;
// The preferred buffer size provided via the ctor.
diff --git a/chromium/content/renderer/media/webrtc_local_audio_source_provider.cc b/chromium/content/renderer/media/webrtc_local_audio_source_provider.cc
index 92539843864..a84151b10d4 100644
--- a/chromium/content/renderer/media/webrtc_local_audio_source_provider.cc
+++ b/chromium/content/renderer/media/webrtc_local_audio_source_provider.cc
@@ -75,8 +75,6 @@ void WebRtcLocalAudioSourceProvider::OnSetFormat(
fifo_.reset(new media::AudioFifo(
params.channels(),
kMaxNumberOfBuffers * params.frames_per_buffer()));
- input_bus_ = media::AudioBus::Create(params.channels(),
- params.frames_per_buffer());
}
void WebRtcLocalAudioSourceProvider::OnReadyStateChanged(
@@ -86,25 +84,21 @@ void WebRtcLocalAudioSourceProvider::OnReadyStateChanged(
}
void WebRtcLocalAudioSourceProvider::OnData(
- const int16* audio_data,
- int sample_rate,
- int number_of_channels,
- int number_of_frames) {
+ const media::AudioBus& audio_bus,
+ base::TimeTicks estimated_capture_time) {
DCHECK(capture_thread_checker_.CalledOnValidThread());
+ DCHECK_EQ(audio_bus.channels(), source_params_.channels());
+ DCHECK_EQ(audio_bus.frames(), source_params_.frames_per_buffer());
+ DCHECK(!estimated_capture_time.is_null());
+
base::AutoLock auto_lock(lock_);
if (!is_enabled_)
return;
DCHECK(fifo_.get());
- // TODO(xians): A better way to handle the interleaved and deinterleaved
- // format switching, see issue/317710.
- DCHECK(input_bus_->frames() == number_of_frames);
- DCHECK(input_bus_->channels() == number_of_channels);
- input_bus_->FromInterleaved(audio_data, number_of_frames, 2);
-
- if (fifo_->frames() + number_of_frames <= fifo_->max_frames()) {
- fifo_->Push(input_bus_.get());
+ if (fifo_->frames() + audio_bus.frames() <= fifo_->max_frames()) {
+ fifo_->Push(&audio_bus);
} else {
// This can happen if the data in FIFO is too slowly consumed or
// WebAudio stops consuming data.
diff --git a/chromium/content/renderer/media/webrtc_local_audio_source_provider.h b/chromium/content/renderer/media/webrtc_local_audio_source_provider.h
index 24e873ced11..12c51d0382d 100644
--- a/chromium/content/renderer/media/webrtc_local_audio_source_provider.h
+++ b/chromium/content/renderer/media/webrtc_local_audio_source_provider.h
@@ -50,21 +50,19 @@ class CONTENT_EXPORT WebRtcLocalAudioSourceProvider
explicit WebRtcLocalAudioSourceProvider(
const blink::WebMediaStreamTrack& track);
- virtual ~WebRtcLocalAudioSourceProvider();
+ ~WebRtcLocalAudioSourceProvider() override;
// MediaStreamAudioSink implementation.
- void OnData(const int16* audio_data,
- int sample_rate,
- int number_of_channels,
- int number_of_frames) override;
+ void OnData(const media::AudioBus& audio_bus,
+ base::TimeTicks estimated_capture_time) override;
void OnSetFormat(const media::AudioParameters& params) override;
void OnReadyStateChanged(
blink::WebMediaStreamSource::ReadyState state) override;
// blink::WebAudioSourceProvider implementation.
- virtual void setClient(blink::WebAudioSourceProviderClient* client) override;
- virtual void provideInput(const blink::WebVector<float*>& audio_data,
- size_t number_of_frames) override;
+ void setClient(blink::WebAudioSourceProviderClient* client) override;
+ void provideInput(const blink::WebVector<float*>& audio_data,
+ size_t number_of_frames) override;
// media::AudioConverter::Inputcallback implementation.
// This function is triggered by provideInput()on the WebAudio audio thread,
@@ -87,7 +85,6 @@ class CONTENT_EXPORT WebRtcLocalAudioSourceProvider
scoped_ptr<media::AudioConverter> audio_converter_;
scoped_ptr<media::AudioFifo> fifo_;
- scoped_ptr<media::AudioBus> input_bus_;
scoped_ptr<media::AudioBus> output_wrapper_;
bool is_enabled_;
media::AudioParameters source_params_;
diff --git a/chromium/content/renderer/media/webrtc_local_audio_source_provider_unittest.cc b/chromium/content/renderer/media/webrtc_local_audio_source_provider_unittest.cc
index 5b6499b2aa8..82ff8f5f02e 100644
--- a/chromium/content/renderer/media/webrtc_local_audio_source_provider_unittest.cc
+++ b/chromium/content/renderer/media/webrtc_local_audio_source_provider_unittest.cc
@@ -26,12 +26,9 @@ class WebRtcLocalAudioSourceProviderTest : public testing::Test {
media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
media::CHANNEL_LAYOUT_STEREO, 2, 44100, 16,
WebRtcLocalAudioSourceProvider::kWebAudioRenderBufferSize);
- const int length =
- source_params_.frames_per_buffer() * source_params_.channels();
- source_data_.reset(new int16[length]);
sink_bus_ = media::AudioBus::Create(sink_params_);
MockMediaConstraintFactory constraint_factory;
- scoped_refptr<WebRtcAudioCapturer> capturer(
+ scoped_refptr<WebRtcAudioCapturer> capturer(
WebRtcAudioCapturer::CreateCapturer(
-1, StreamDeviceInfo(),
constraint_factory.CreateWebMediaConstraints(), NULL, NULL));
@@ -42,7 +39,8 @@ class WebRtcLocalAudioSourceProviderTest : public testing::Test {
blink::WebMediaStreamSource audio_source;
audio_source.initialize(base::UTF8ToUTF16("dummy_source_id"),
blink::WebMediaStreamSource::TypeAudio,
- base::UTF8ToUTF16("dummy_source_name"));
+ base::UTF8ToUTF16("dummy_source_name"),
+ false /* remote */, true /* readonly */);
blink_track_.initialize(blink::WebString::fromUTF8("audio_track"),
audio_source);
blink_track_.setExtraData(native_track.release());
@@ -58,7 +56,6 @@ class WebRtcLocalAudioSourceProviderTest : public testing::Test {
}
media::AudioParameters source_params_;
- scoped_ptr<int16[]> source_data_;
media::AudioParameters sink_params_;
scoped_ptr<media::AudioBus> sink_bus_;
blink::WebMediaStreamTrack blink_track_;
@@ -78,18 +75,18 @@ TEST_F(WebRtcLocalAudioSourceProviderTest, VerifyDataFlow) {
source_provider_->provideInput(audio_data, sink_params_.frames_per_buffer());
EXPECT_TRUE(sink_bus_->channel(0)[0] == 0);
- // Set the value of source data to be 1.
- const int length =
- source_params_.frames_per_buffer() * source_params_.channels();
- std::fill(source_data_.get(), source_data_.get() + length, 1);
+ // Create a source AudioBus with channel data filled with non-zero values.
+ const scoped_ptr<media::AudioBus> source_bus =
+ media::AudioBus::Create(source_params_);
+ std::fill(source_bus->channel(0),
+ source_bus->channel(0) + source_bus->frames(),
+ 0.5f);
// Deliver data to |source_provider_|.
- source_provider_->OnData(source_data_.get(),
- source_params_.sample_rate(),
- source_params_.channels(),
- source_params_.frames_per_buffer());
+ base::TimeTicks estimated_capture_time = base::TimeTicks::Now();
+ source_provider_->OnData(*source_bus, estimated_capture_time);
- // Consume the first packet in the resampler, which contains only zero.
+ // Consume the first packet in the resampler, which contains only zeros.
// And the consumption of the data will trigger pulling the real packet from
// the source provider FIFO into the resampler.
// Note that we need to count in the provideInput() call a few lines above.
@@ -103,20 +100,21 @@ TEST_F(WebRtcLocalAudioSourceProviderTest, VerifyDataFlow) {
EXPECT_DOUBLE_EQ(0.0, sink_bus_->channel(1)[0]);
}
- // Prepare the second packet for featching.
- source_provider_->OnData(source_data_.get(),
- source_params_.sample_rate(),
- source_params_.channels(),
- source_params_.frames_per_buffer());
+ // Make a second data delivery.
+ estimated_capture_time +=
+ source_bus->frames() * base::TimeDelta::FromSeconds(1) /
+ source_params_.sample_rate();
+ source_provider_->OnData(*source_bus, estimated_capture_time);
- // Verify the packets.
+ // Verify that non-zero data samples are present in the results of the
+ // following calls to provideInput().
for (int i = 0; i < source_params_.frames_per_buffer();
i += sink_params_.frames_per_buffer()) {
sink_bus_->Zero();
source_provider_->provideInput(audio_data,
sink_params_.frames_per_buffer());
- EXPECT_GT(sink_bus_->channel(0)[0], 0);
- EXPECT_GT(sink_bus_->channel(1)[0], 0);
+ EXPECT_NEAR(0.5f, sink_bus_->channel(0)[0], 0.001f);
+ EXPECT_NEAR(0.5f, sink_bus_->channel(1)[0], 0.001f);
EXPECT_DOUBLE_EQ(sink_bus_->channel(0)[0], sink_bus_->channel(1)[0]);
}
}
diff --git a/chromium/content/renderer/media/webrtc_local_audio_track.cc b/chromium/content/renderer/media/webrtc_local_audio_track.cc
index 8fc1e4f9ae0..a51b37fb3fd 100644
--- a/chromium/content/renderer/media/webrtc_local_audio_track.cc
+++ b/chromium/content/renderer/media/webrtc_local_audio_track.cc
@@ -4,12 +4,13 @@
#include "content/renderer/media/webrtc_local_audio_track.h"
+#include <limits>
+
#include "content/public/renderer/media_stream_audio_sink.h"
#include "content/renderer/media/media_stream_audio_level_calculator.h"
#include "content/renderer/media/media_stream_audio_processor.h"
#include "content/renderer/media/media_stream_audio_sink_owner.h"
#include "content/renderer/media/media_stream_audio_track_sink.h"
-#include "content/renderer/media/peer_connection_audio_sink_owner.h"
#include "content/renderer/media/webaudio_capturer_source.h"
#include "content/renderer/media/webrtc/webrtc_local_audio_track_adapter.h"
#include "content/renderer/media/webrtc_audio_capturer.h"
@@ -39,19 +40,35 @@ WebRtcLocalAudioTrack::~WebRtcLocalAudioTrack() {
Stop();
}
-void WebRtcLocalAudioTrack::Capture(const int16* audio_data,
- base::TimeDelta delay,
- int volume,
- bool key_pressed,
- bool need_audio_processing,
+media::AudioParameters WebRtcLocalAudioTrack::GetOutputFormat() const {
+ DCHECK(main_render_thread_checker_.CalledOnValidThread());
+ if (webaudio_source_.get()) {
+ return media::AudioParameters();
+ } else {
+ return capturer_->GetOutputFormat();
+ }
+}
+
+void WebRtcLocalAudioTrack::Capture(const media::AudioBus& audio_bus,
+ base::TimeTicks estimated_capture_time,
bool force_report_nonzero_energy) {
DCHECK(capture_thread_checker_.CalledOnValidThread());
-
- // Calculate the signal level regardless if the track is disabled or enabled.
- int signal_level = level_calculator_->Calculate(
- audio_data, audio_parameters_.channels(),
- audio_parameters_.frames_per_buffer(), force_report_nonzero_energy);
- adapter_->SetSignalLevel(signal_level);
+ DCHECK(!estimated_capture_time.is_null());
+
+ // Calculate the signal level regardless of whether the track is disabled or
+ // enabled. If |force_report_nonzero_energy| is true, |audio_bus| contains
+ // post-processed data that may be all zeros even though the signal contained
+ // energy before the processing. In this case, report nonzero energy even if
+ // the energy of the data in |audio_bus| is zero.
+ const float minimum_signal_level = force_report_nonzero_energy ?
+ 1.0f / std::numeric_limits<int16>::max() : 0.0f;
+ const float signal_level = std::max(
+ minimum_signal_level,
+ std::min(1.0f, level_calculator_->Calculate(audio_bus)));
+ const int signal_level_as_pcm16 =
+ static_cast<int>(signal_level * std::numeric_limits<int16>::max() +
+ 0.5f /* rounding to nearest int */);
+ adapter_->SetSignalLevel(signal_level_as_pcm16);
scoped_refptr<WebRtcAudioCapturer> capturer;
SinkList::ItemList sinks;
@@ -65,10 +82,8 @@ void WebRtcLocalAudioTrack::Capture(const int16* audio_data,
// Notify the tracks on when the format changes. This will do nothing if
// |sinks_to_notify_format| is empty.
- for (SinkList::ItemList::const_iterator it = sinks_to_notify_format.begin();
- it != sinks_to_notify_format.end(); ++it) {
- (*it)->OnSetFormat(audio_parameters_);
- }
+ for (const auto& sink : sinks_to_notify_format)
+ sink->OnSetFormat(audio_parameters_);
// Feed the data to the sinks.
// TODO(jiayl): we should not pass the real audio data down if the track is
@@ -76,24 +91,8 @@ void WebRtcLocalAudioTrack::Capture(const int16* audio_data,
// detection and should be changed when audio processing is moved from
// WebRTC to the track.
std::vector<int> voe_channels = adapter_->VoeChannels();
- for (SinkList::ItemList::const_iterator it = sinks.begin();
- it != sinks.end();
- ++it) {
- int new_volume = (*it)->OnData(audio_data,
- audio_parameters_.sample_rate(),
- audio_parameters_.channels(),
- audio_parameters_.frames_per_buffer(),
- voe_channels,
- delay.InMilliseconds(),
- volume,
- need_audio_processing,
- key_pressed);
- if (new_volume != 0 && capturer.get() && !webaudio_source_.get()) {
- // Feed the new volume to WebRtc while changing the volume on the
- // browser.
- capturer->SetVolume(new_volume);
- }
- }
+ for (const auto& sink : sinks)
+ sink->OnData(audio_bus, estimated_capture_time);
}
void WebRtcLocalAudioTrack::OnSetFormat(
@@ -165,39 +164,6 @@ void WebRtcLocalAudioTrack::RemoveSink(MediaStreamAudioSink* sink) {
removed_item->Reset();
}
-void WebRtcLocalAudioTrack::AddSink(PeerConnectionAudioSink* sink) {
- DCHECK(main_render_thread_checker_.CalledOnValidThread());
- DVLOG(1) << "WebRtcLocalAudioTrack::AddSink()";
- base::AutoLock auto_lock(lock_);
-
- // Verify that |sink| is not already added to the list.
- DCHECK(!sinks_.Contains(
- MediaStreamAudioTrackSink::WrapsPeerConnectionSink(sink)));
-
- // Create (and add to the list) a new MediaStreamAudioTrackSink
- // which owns the |sink| and delagates all calls to the
- // MediaStreamAudioSink interface. It will be tagged in the list, so
- // we remember to call OnSetFormat() on the new sink.
- scoped_refptr<MediaStreamAudioTrackSink> sink_owner(
- new PeerConnectionAudioSinkOwner(sink));
- sinks_.AddAndTag(sink_owner.get());
-}
-
-void WebRtcLocalAudioTrack::RemoveSink(PeerConnectionAudioSink* sink) {
- DCHECK(main_render_thread_checker_.CalledOnValidThread());
- DVLOG(1) << "WebRtcLocalAudioTrack::RemoveSink()";
-
- base::AutoLock auto_lock(lock_);
-
- scoped_refptr<MediaStreamAudioTrackSink> removed_item = sinks_.Remove(
- MediaStreamAudioTrackSink::WrapsPeerConnectionSink(sink));
- // Clear the delegate to ensure that no more capture callbacks will
- // be sent to this sink. Also avoids a possible crash which can happen
- // if this method is called while capturing is active.
- if (removed_item.get())
- removed_item->Reset();
-}
-
void WebRtcLocalAudioTrack::Start() {
DCHECK(main_render_thread_checker_.CalledOnValidThread());
DVLOG(1) << "WebRtcLocalAudioTrack::Start()";
@@ -205,7 +171,7 @@ void WebRtcLocalAudioTrack::Start() {
// If the track is hooking up with WebAudio, do NOT add the track to the
// capturer as its sink otherwise two streams in different clock will be
// pushed through the same track.
- webaudio_source_->Start(this, capturer_.get());
+ webaudio_source_->Start(this);
} else if (capturer_.get()) {
capturer_->AddTrack(this);
}
@@ -223,7 +189,7 @@ void WebRtcLocalAudioTrack::Start() {
}
void WebRtcLocalAudioTrack::SetEnabled(bool enabled) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(main_render_thread_checker_.CalledOnValidThread());
if (adapter_.get())
adapter_->set_enabled(enabled);
}
@@ -266,7 +232,7 @@ void WebRtcLocalAudioTrack::Stop() {
}
webrtc::AudioTrackInterface* WebRtcLocalAudioTrack::GetAudioAdapter() {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(main_render_thread_checker_.CalledOnValidThread());
return adapter_.get();
}
diff --git a/chromium/content/renderer/media/webrtc_local_audio_track.h b/chromium/content/renderer/media/webrtc_local_audio_track.h
index fa8b05995bb..be2e719b9e2 100644
--- a/chromium/content/renderer/media/webrtc_local_audio_track.h
+++ b/chromium/content/renderer/media/webrtc_local_audio_track.h
@@ -13,7 +13,11 @@
#include "base/threading/thread_checker.h"
#include "content/renderer/media/media_stream_track.h"
#include "content/renderer/media/tagged_list.h"
-#include "content/renderer/media/webrtc_audio_device_impl.h"
+#include "media/audio/audio_parameters.h"
+
+namespace media {
+class AudioBus;
+}
namespace content {
@@ -22,7 +26,6 @@ class MediaStreamAudioProcessor;
class MediaStreamAudioSink;
class MediaStreamAudioSinkOwner;
class MediaStreamAudioTrackSink;
-class PeerConnectionAudioSink;
class WebAudioCapturerSource;
class WebRtcAudioCapturer;
class WebRtcLocalAudioTrackAdapter;
@@ -50,12 +53,6 @@ class CONTENT_EXPORT WebRtcLocalAudioTrack
// Called on the main render thread.
void RemoveSink(MediaStreamAudioSink* sink);
- // Add/remove PeerConnection sink to/from the track.
- // TODO(xians): Remove these two methods after PeerConnection can use the
- // same sink interface as MediaStreamAudioSink.
- void AddSink(PeerConnectionAudioSink* sink);
- void RemoveSink(PeerConnectionAudioSink* sink);
-
// Starts the local audio track. Called on the main render thread and
// should be called only once when audio track is created.
void Start();
@@ -70,13 +67,15 @@ class CONTENT_EXPORT WebRtcLocalAudioTrack
webrtc::AudioTrackInterface* GetAudioAdapter() override;
+ // Returns the output format of the capture source. May return an invalid
+ // AudioParameters if the format is not yet available.
+ // Called on the main render thread.
+ media::AudioParameters GetOutputFormat() const;
+
// Method called by the capturer to deliver the capture data.
// Called on the capture audio thread.
- void Capture(const int16* audio_data,
- base::TimeDelta delay,
- int volume,
- bool key_pressed,
- bool need_audio_processing,
+ void Capture(const media::AudioBus& audio_bus,
+ base::TimeTicks estimated_capture_time,
bool force_report_nonzero_energy);
// Method called by the capturer to set the audio parameters used by source
@@ -109,8 +108,6 @@ class CONTENT_EXPORT WebRtcLocalAudioTrack
// has changed.
SinkList sinks_;
- // Used to DCHECK that some methods are called on the main render thread.
- base::ThreadChecker main_render_thread_checker_;
// Tests that methods are called on libjingle's signaling thread.
base::ThreadChecker signal_thread_checker_;
diff --git a/chromium/content/renderer/media/webrtc_local_audio_track_unittest.cc b/chromium/content/renderer/media/webrtc_local_audio_track_unittest.cc
index 35ab61eb4aa..4eae198de57 100644
--- a/chromium/content/renderer/media/webrtc_local_audio_track_unittest.cc
+++ b/chromium/content/renderer/media/webrtc_local_audio_track_unittest.cc
@@ -4,11 +4,11 @@
#include "base/synchronization/waitable_event.h"
#include "base/test/test_timeouts.h"
+#include "content/public/renderer/media_stream_audio_sink.h"
#include "content/renderer/media/media_stream_audio_source.h"
#include "content/renderer/media/mock_media_constraint_factory.h"
#include "content/renderer/media/webrtc/webrtc_local_audio_track_adapter.h"
#include "content/renderer/media/webrtc_audio_capturer.h"
-#include "content/renderer/media/webrtc_audio_device_impl.h"
#include "content/renderer/media/webrtc_local_audio_track.h"
#include "media/audio/audio_parameters.h"
#include "media/base/audio_bus.h"
@@ -66,7 +66,7 @@ class FakeAudioThread : public base::PlatformThread::Delegate {
void Start() {
base::PlatformThread::CreateWithPriority(
- 0, this, &thread_, base::kThreadPriority_RealtimeAudio);
+ 0, this, &thread_, base::ThreadPriority::REALTIME_AUDIO);
CHECK(!thread_.is_null());
}
@@ -96,25 +96,25 @@ class MockCapturerSource : public media::AudioCapturerSource {
MOCK_METHOD1(SetVolume, void(double volume));
MOCK_METHOD1(SetAutomaticGainControl, void(bool enable));
- virtual void Initialize(const media::AudioParameters& params,
- CaptureCallback* callback,
- int session_id) override {
+ void Initialize(const media::AudioParameters& params,
+ CaptureCallback* callback,
+ int session_id) override {
DCHECK(params.IsValid());
params_ = params;
OnInitialize(params, callback, session_id);
}
- virtual void Start() override {
+ void Start() override {
audio_thread_.reset(new FakeAudioThread(capturer_, params_));
audio_thread_->Start();
OnStart();
}
- virtual void Stop() override {
+ void Stop() override {
audio_thread_->Stop();
audio_thread_.reset();
OnStop();
}
protected:
- virtual ~MockCapturerSource() {}
+ ~MockCapturerSource() override {}
private:
scoped_ptr<FakeAudioThread> audio_thread_;
@@ -122,36 +122,18 @@ class MockCapturerSource : public media::AudioCapturerSource {
media::AudioParameters params_;
};
-// TODO(xians): Use MediaStreamAudioSink.
-class MockMediaStreamAudioSink : public PeerConnectionAudioSink {
+class MockMediaStreamAudioSink : public MediaStreamAudioSink {
public:
MockMediaStreamAudioSink() {}
~MockMediaStreamAudioSink() {}
- int OnData(const int16* audio_data,
- int sample_rate,
- int number_of_channels,
- int number_of_frames,
- const std::vector<int>& channels,
- int audio_delay_milliseconds,
- int current_volume,
- bool need_audio_processing,
- bool key_pressed) override {
- EXPECT_EQ(params_.sample_rate(), sample_rate);
- EXPECT_EQ(params_.channels(), number_of_channels);
- EXPECT_EQ(params_.frames_per_buffer(), number_of_frames);
- CaptureData(channels.size(),
- audio_delay_milliseconds,
- current_volume,
- need_audio_processing,
- key_pressed);
- return 0;
+ void OnData(const media::AudioBus& audio_bus,
+ base::TimeTicks estimated_capture_time) override {
+ EXPECT_EQ(params_.channels(), audio_bus.channels());
+ EXPECT_EQ(params_.frames_per_buffer(), audio_bus.frames());
+ EXPECT_FALSE(estimated_capture_time.is_null());
+ CaptureData();
}
- MOCK_METHOD5(CaptureData,
- void(int number_of_network_channels,
- int audio_delay_milliseconds,
- int current_volume,
- bool need_audio_processing,
- bool key_pressed));
+ MOCK_METHOD0(CaptureData, void());
void OnSetFormat(const media::AudioParameters& params) {
params_ = params;
FormatIsSet();
@@ -173,7 +155,8 @@ class WebRtcLocalAudioTrackTest : public ::testing::Test {
media::CHANNEL_LAYOUT_STEREO, 2, 48000, 16, 480);
MockMediaConstraintFactory constraint_factory;
blink_source_.initialize("dummy", blink::WebMediaStreamSource::TypeAudio,
- "dummy");
+ "dummy",
+ false /* remote */, true /* readonly */);
MediaStreamAudioSource* audio_source = new MediaStreamAudioSource();
blink_source_.setExtraData(audio_source);
@@ -188,7 +171,7 @@ class WebRtcLocalAudioTrackTest : public ::testing::Test {
.WillOnce(Return());
EXPECT_CALL(*capturer_source_.get(), SetAutomaticGainControl(true));
EXPECT_CALL(*capturer_source_.get(), OnStart());
- capturer_->SetCapturerSourceForTesting(capturer_source_, params_);
+ capturer_->SetCapturerSource(capturer_source_, params_);
}
void TearDown() override {
@@ -218,11 +201,7 @@ TEST_F(WebRtcLocalAudioTrackTest, ConnectAndDisconnectOneSink) {
base::WaitableEvent event(false, false);
EXPECT_CALL(*sink, FormatIsSet());
EXPECT_CALL(*sink,
- CaptureData(0,
- 0,
- 0,
- _,
- false)).Times(AtLeast(1))
+ CaptureData()).Times(AtLeast(1))
.WillRepeatedly(SignalEvent(&event));
track->AddSink(sink.get());
EXPECT_TRUE(event.TimedWait(TestTimeouts::tiny_timeout()));
@@ -252,15 +231,14 @@ TEST_F(WebRtcLocalAudioTrackTest, DISABLED_DisableEnableAudioTrack) {
const media::AudioParameters params = capturer_->source_audio_parameters();
base::WaitableEvent event(false, false);
EXPECT_CALL(*sink, FormatIsSet()).Times(1);
- EXPECT_CALL(*sink,
- CaptureData(0, 0, 0, _, false)).Times(0);
+ EXPECT_CALL(*sink, CaptureData()).Times(0);
EXPECT_EQ(sink->audio_params().frames_per_buffer(),
params.sample_rate() / 100);
track->AddSink(sink.get());
EXPECT_FALSE(event.TimedWait(TestTimeouts::tiny_timeout()));
event.Reset();
- EXPECT_CALL(*sink, CaptureData(0, 0, 0, _, false)).Times(AtLeast(1))
+ EXPECT_CALL(*sink, CaptureData()).Times(AtLeast(1))
.WillRepeatedly(SignalEvent(&event));
EXPECT_TRUE(track->GetAudioAdapter()->set_enabled(true));
EXPECT_TRUE(event.TimedWait(TestTimeouts::tiny_timeout()));
@@ -285,8 +263,7 @@ TEST_F(WebRtcLocalAudioTrackTest, DISABLED_MultipleAudioTracks) {
const media::AudioParameters params = capturer_->source_audio_parameters();
base::WaitableEvent event_1(false, false);
EXPECT_CALL(*sink_1, FormatIsSet()).WillOnce(Return());
- EXPECT_CALL(*sink_1,
- CaptureData(0, 0, 0, _, false)).Times(AtLeast(1))
+ EXPECT_CALL(*sink_1, CaptureData()).Times(AtLeast(1))
.WillRepeatedly(SignalEvent(&event_1));
EXPECT_EQ(sink_1->audio_params().frames_per_buffer(),
params.sample_rate() / 100);
@@ -306,11 +283,11 @@ TEST_F(WebRtcLocalAudioTrackTest, DISABLED_MultipleAudioTracks) {
scoped_ptr<MockMediaStreamAudioSink> sink_2(new MockMediaStreamAudioSink());
EXPECT_CALL(*sink_2, FormatIsSet()).WillOnce(Return());
- EXPECT_CALL(*sink_1, CaptureData(0, 0, 0, _, false)).Times(AtLeast(1))
+ EXPECT_CALL(*sink_1, CaptureData()).Times(AtLeast(1))
.WillRepeatedly(SignalEvent(&event_1));
EXPECT_EQ(sink_1->audio_params().frames_per_buffer(),
params.sample_rate() / 100);
- EXPECT_CALL(*sink_2, CaptureData(0, 0, 0, _, false)).Times(AtLeast(1))
+ EXPECT_CALL(*sink_2, CaptureData()).Times(AtLeast(1))
.WillRepeatedly(SignalEvent(&event_2));
EXPECT_EQ(sink_2->audio_params().frames_per_buffer(),
params.sample_rate() / 100);
@@ -381,7 +358,7 @@ TEST_F(WebRtcLocalAudioTrackTest, StartAndStopAudioTracks) {
scoped_ptr<MockMediaStreamAudioSink> sink(new MockMediaStreamAudioSink());
event.Reset();
EXPECT_CALL(*sink, FormatIsSet()).WillOnce(SignalEvent(&event));
- EXPECT_CALL(*sink, CaptureData(_, 0, 0, _, false))
+ EXPECT_CALL(*sink, CaptureData())
.Times(AnyNumber()).WillRepeatedly(Return());
track_1->AddSink(sink.get());
EXPECT_TRUE(event.TimedWait(TestTimeouts::tiny_timeout()));
@@ -429,7 +406,7 @@ TEST_F(WebRtcLocalAudioTrackTest,
// Verify the data flow by connecting the |sink_1| to |track_1|.
scoped_ptr<MockMediaStreamAudioSink> sink_1(new MockMediaStreamAudioSink());
- EXPECT_CALL(*sink_1.get(), CaptureData(0, 0, 0, _, false))
+ EXPECT_CALL(*sink_1.get(), CaptureData())
.Times(AnyNumber()).WillRepeatedly(Return());
EXPECT_CALL(*sink_1.get(), FormatIsSet()).Times(AnyNumber());
track_1->AddSink(sink_1.get());
@@ -451,7 +428,7 @@ TEST_F(WebRtcLocalAudioTrackTest,
media::AudioParameters new_param(
media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
media::CHANNEL_LAYOUT_MONO, 44100, 16, 441);
- new_capturer->SetCapturerSourceForTesting(new_source, new_param);
+ new_capturer->SetCapturerSource(new_source, new_param);
// Setup the second audio track, connect it to the new capturer and start it.
scoped_refptr<WebRtcLocalAudioTrackAdapter> adapter_2(
@@ -463,7 +440,7 @@ TEST_F(WebRtcLocalAudioTrackTest,
// Verify the data flow by connecting the |sink_2| to |track_2|.
scoped_ptr<MockMediaStreamAudioSink> sink_2(new MockMediaStreamAudioSink());
base::WaitableEvent event(false, false);
- EXPECT_CALL(*sink_2, CaptureData(0, 0, 0, _, false))
+ EXPECT_CALL(*sink_2, CaptureData())
.Times(AnyNumber()).WillRepeatedly(Return());
EXPECT_CALL(*sink_2, FormatIsSet()).WillOnce(SignalEvent(&event));
track_2->AddSink(sink_2.get());
@@ -493,19 +470,16 @@ TEST_F(WebRtcLocalAudioTrackTest, TrackWorkWithSmallBufferSize) {
factory.DisableDefaultAudioConstraints();
scoped_refptr<WebRtcAudioCapturer> capturer(
WebRtcAudioCapturer::CreateCapturer(
- -1,
- StreamDeviceInfo(MEDIA_DEVICE_AUDIO_CAPTURE,
- "", "", params.sample_rate(),
- params.channel_layout(),
- params.frames_per_buffer()),
- factory.CreateWebMediaConstraints(),
- NULL, NULL));
+ -1, StreamDeviceInfo(MEDIA_DEVICE_AUDIO_CAPTURE, "", "",
+ params.sample_rate(), params.channel_layout(),
+ params.frames_per_buffer()),
+ factory.CreateWebMediaConstraints(), NULL, NULL));
scoped_refptr<MockCapturerSource> source(
new MockCapturerSource(capturer.get()));
EXPECT_CALL(*source.get(), OnInitialize(_, capturer.get(), -1));
EXPECT_CALL(*source.get(), SetAutomaticGainControl(true));
EXPECT_CALL(*source.get(), OnStart());
- capturer->SetCapturerSourceForTesting(source, params);
+ capturer->SetCapturerSource(source, params);
// Setup a audio track, connect it to the capturer and start it.
scoped_refptr<WebRtcLocalAudioTrackAdapter> adapter(
@@ -524,8 +498,7 @@ TEST_F(WebRtcLocalAudioTrackTest, TrackWorkWithSmallBufferSize) {
#else
const int expected_buffer_size = params.frames_per_buffer();
#endif
- EXPECT_CALL(*sink, CaptureData(
- 0, 0, 0, _, false))
+ EXPECT_CALL(*sink, CaptureData())
.Times(AtLeast(1)).WillRepeatedly(SignalEvent(&event));
track->AddSink(sink.get());
EXPECT_TRUE(event.TimedWait(TestTimeouts::tiny_timeout()));
diff --git a/chromium/content/renderer/media/webrtc_logging.h b/chromium/content/renderer/media/webrtc_logging.h
index 0aafa9cc7d5..aa1958df798 100644
--- a/chromium/content/renderer/media/webrtc_logging.h
+++ b/chromium/content/renderer/media/webrtc_logging.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_RENDERER_WEBRTC_LOGGING_H_
-#define CONTENT_RENDERER_WEBRTC_LOGGING_H_
+#ifndef CONTENT_RENDERER_MEDIA_WEBRTC_LOGGING_H_
+#define CONTENT_RENDERER_MEDIA_WEBRTC_LOGGING_H_
#include <string>
@@ -19,4 +19,4 @@ void WebRtcLogMessage(const std::string& message);
} // namespace content
-#endif // CONTENT_RENDERER_WEBRTC_LOGGING_H_
+#endif // CONTENT_RENDERER_MEDIA_WEBRTC_LOGGING_H_
diff --git a/chromium/content/renderer/memory_benchmarking_extension.cc b/chromium/content/renderer/memory_benchmarking_extension.cc
index 0f5320daa06..b2b27229f40 100644
--- a/chromium/content/renderer/memory_benchmarking_extension.cc
+++ b/chromium/content/renderer/memory_benchmarking_extension.cc
@@ -26,7 +26,7 @@ gin::WrapperInfo MemoryBenchmarkingExtension::kWrapperInfo = {
void MemoryBenchmarkingExtension::Install(blink::WebFrame* frame) {
v8::Isolate* isolate = blink::mainThreadIsolate();
v8::HandleScope handle_scope(isolate);
- v8::Handle<v8::Context> context = frame->mainWorldScriptContext();
+ v8::Local<v8::Context> context = frame->mainWorldScriptContext();
if (context.IsEmpty())
return;
@@ -36,7 +36,7 @@ void MemoryBenchmarkingExtension::Install(blink::WebFrame* frame) {
if (controller.IsEmpty())
return;
- v8::Handle<v8::Object> chrome = GetOrCreateChromeObject(isolate,
+ v8::Local<v8::Object> chrome = GetOrCreateChromeObject(isolate,
context->Global());
chrome->Set(gin::StringToV8(isolate, "memoryBenchmarking"),
controller.ToV8());
diff --git a/chromium/content/renderer/menu_item_builder.cc b/chromium/content/renderer/menu_item_builder.cc
index 0bbd5d89190..7db35929636 100644
--- a/chromium/content/renderer/menu_item_builder.cc
+++ b/chromium/content/renderer/menu_item_builder.cc
@@ -12,6 +12,7 @@ MenuItem MenuItemBuilder::Build(const blink::WebMenuItemInfo& item) {
MenuItem result;
result.label = item.label;
+ result.icon = item.icon;
result.tool_tip = item.toolTip;
result.type = static_cast<MenuItem::Type>(item.type);
result.action = item.action;
diff --git a/chromium/content/renderer/mojo/service_registry_js_wrapper.cc b/chromium/content/renderer/mojo/service_registry_js_wrapper.cc
index 73a591e3906..4840b1ecaf1 100644
--- a/chromium/content/renderer/mojo/service_registry_js_wrapper.cc
+++ b/chromium/content/renderer/mojo/service_registry_js_wrapper.cc
@@ -6,7 +6,7 @@
#include "content/common/mojo/service_registry_impl.h"
#include "content/public/common/service_registry.h"
-#include "mojo/edk/js/handle.h"
+#include "third_party/mojo/src/mojo/edk/js/handle.h"
namespace content {
diff --git a/chromium/content/renderer/mojo/service_registry_js_wrapper.h b/chromium/content/renderer/mojo/service_registry_js_wrapper.h
index 2be7f9557b8..fa0eee9704c 100644
--- a/chromium/content/renderer/mojo/service_registry_js_wrapper.h
+++ b/chromium/content/renderer/mojo/service_registry_js_wrapper.h
@@ -11,7 +11,7 @@
#include "gin/handle.h"
#include "gin/object_template_builder.h"
#include "gin/wrappable.h"
-#include "mojo/public/cpp/system/core.h"
+#include "third_party/mojo/src/mojo/public/cpp/system/core.h"
namespace content {
diff --git a/chromium/content/renderer/navigation_state_impl.cc b/chromium/content/renderer/navigation_state_impl.cc
new file mode 100644
index 00000000000..38d1eed8d56
--- /dev/null
+++ b/chromium/content/renderer/navigation_state_impl.cc
@@ -0,0 +1,51 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/navigation_state_impl.h"
+
+namespace content {
+
+NavigationStateImpl::~NavigationStateImpl() {
+}
+
+NavigationStateImpl* NavigationStateImpl::CreateBrowserInitiated(
+ const CommonNavigationParams& common_params,
+ const StartNavigationParams& start_params,
+ const RequestNavigationParams& request_params) {
+ return new NavigationStateImpl(common_params, start_params, request_params,
+ false);
+}
+
+NavigationStateImpl* NavigationStateImpl::CreateContentInitiated() {
+ return new NavigationStateImpl(CommonNavigationParams(),
+ StartNavigationParams(),
+ RequestNavigationParams(), true);
+}
+
+ui::PageTransition NavigationStateImpl::GetTransitionType() {
+ return common_params_.transition;
+}
+
+bool NavigationStateImpl::WasWithinSamePage() {
+ return was_within_same_page_;
+}
+
+bool NavigationStateImpl::IsContentInitiated() {
+ return is_content_initiated_;
+}
+
+NavigationStateImpl::NavigationStateImpl(
+ const CommonNavigationParams& common_params,
+ const StartNavigationParams& start_params,
+ const RequestNavigationParams& request_params,
+ bool is_content_initiated)
+ : request_committed_(false),
+ was_within_same_page_(false),
+ is_content_initiated_(is_content_initiated),
+ common_params_(common_params),
+ start_params_(start_params),
+ request_params_(request_params) {
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/navigation_state_impl.h b/chromium/content/renderer/navigation_state_impl.h
new file mode 100644
index 00000000000..07b7688155e
--- /dev/null
+++ b/chromium/content/renderer/navigation_state_impl.h
@@ -0,0 +1,77 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_NAVIGATION_STATE_IMPL_H_
+#define CONTENT_RENDERER_NAVIGATION_STATE_IMPL_H_
+
+#include <string>
+
+#include "content/common/navigation_params.h"
+#include "content/public/renderer/navigation_state.h"
+
+namespace content {
+
+class CONTENT_EXPORT NavigationStateImpl : public NavigationState {
+ public:
+ ~NavigationStateImpl() override;
+
+ static NavigationStateImpl* CreateBrowserInitiated(
+ const CommonNavigationParams& common_params,
+ const StartNavigationParams& start_params,
+ const RequestNavigationParams& request_params);
+
+ static NavigationStateImpl* CreateContentInitiated();
+
+ // NavigationState implementation.
+ ui::PageTransition GetTransitionType() override;
+ bool WasWithinSamePage() override;
+ bool IsContentInitiated() override;
+
+ const CommonNavigationParams& common_params() const { return common_params_; }
+ const StartNavigationParams& start_params() const { return start_params_; }
+ const RequestNavigationParams& request_params() const {
+ return request_params_;
+ }
+ bool request_committed() const { return request_committed_; }
+ void set_request_committed(bool value) { request_committed_ = value; }
+ void set_was_within_same_page(bool value) { was_within_same_page_ = value; }
+
+ void set_transition_type(ui::PageTransition transition) {
+ common_params_.transition = transition;
+ }
+
+ private:
+ NavigationStateImpl(const CommonNavigationParams& common_params,
+ const StartNavigationParams& start_params,
+ const RequestNavigationParams& request_params,
+ bool is_content_initiated);
+
+ bool request_committed_;
+ bool was_within_same_page_;
+
+ // True if this navigation was not initiated via WebFrame::LoadRequest.
+ const bool is_content_initiated_;
+
+ CommonNavigationParams common_params_;
+ const StartNavigationParams start_params_;
+
+ // Note: if IsContentInitiated() is false, whether this navigation should
+ // replace the current entry in the back/forward history list is determined by
+ // the should_replace_current_entry field in |history_params|. Otherwise, use
+ // replacesCurrentHistoryItem() on the WebDataSource.
+ //
+ // TODO(davidben): It would be good to unify these and have only one source
+ // for the two cases. We can plumb this through WebFrame::loadRequest to set
+ // lockBackForwardList on the FrameLoadRequest. However, this breaks process
+ // swaps because FrameLoader::loadWithNavigationAction treats loads before a
+ // FrameLoader has committedFirstRealDocumentLoad as a replacement. (Added for
+ // http://crbug.com/178380).
+ const RequestNavigationParams request_params_;
+
+ DISALLOW_COPY_AND_ASSIGN(NavigationStateImpl);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_NAVIGATION_STATE_IMPL_H_
diff --git a/chromium/content/renderer/net_info_helper.h b/chromium/content/renderer/net_info_helper.h
index a9e19a03cfd..cc876cae138 100644
--- a/chromium/content/renderer/net_info_helper.h
+++ b/chromium/content/renderer/net_info_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_PUBLIC_RENDERER_NET_INFO_HELPER_H_
-#define CONTENT_PUBLIC_RENDERER_NET_INFO_HELPER_H_
+#ifndef CONTENT_RENDERER_NET_INFO_HELPER_H_
+#define CONTENT_RENDERER_NET_INFO_HELPER_H_
#include "net/base/network_change_notifier.h"
#include "third_party/WebKit/public/platform/WebConnectionType.h"
@@ -15,4 +15,4 @@ blink::WebConnectionType NetConnectionTypeToWebConnectionType(
} // namespace content
-#endif // CONTENT_PUBLIC_RENDERER_NET_INFO_HELPER_H_
+#endif // CONTENT_RENDERER_NET_INFO_HELPER_H_
diff --git a/chromium/content/renderer/notification_icon_loader.cc b/chromium/content/renderer/notification_icon_loader.cc
deleted file mode 100644
index d535837dbf9..00000000000
--- a/chromium/content/renderer/notification_icon_loader.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/renderer/notification_icon_loader.h"
-
-#include "base/logging.h"
-#include "content/child/image_decoder.h"
-#include "third_party/WebKit/public/platform/Platform.h"
-#include "third_party/WebKit/public/platform/WebURL.h"
-#include "third_party/WebKit/public/platform/WebURLLoader.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-
-using blink::WebURL;
-using blink::WebURLError;
-using blink::WebURLLoader;
-using blink::WebURLRequest;
-
-namespace content {
-
-NotificationIconLoader::NotificationIconLoader(
- int notification_id,
- const DownloadCompletedCallback& callback)
- : notification_id_(notification_id),
- callback_(callback),
- completed_(false) {}
-
-NotificationIconLoader::~NotificationIconLoader() {}
-
-void NotificationIconLoader::Start(const WebURL& icon_url) {
- DCHECK(!loader_);
-
- WebURLRequest request(icon_url);
- request.setRequestContext(WebURLRequest::RequestContextImage);
-
- loader_.reset(blink::Platform::current()->createURLLoader());
- loader_->loadAsynchronously(request, this);
-}
-
-void NotificationIconLoader::Cancel() {
- DCHECK(loader_);
-
- completed_ = true;
- loader_->cancel();
-}
-
-void NotificationIconLoader::didReceiveData(
- WebURLLoader* loader,
- const char* data,
- int data_length,
- int encoded_data_length) {
- DCHECK(!completed_);
- DCHECK_GT(data_length, 0);
-
- buffer_.insert(buffer_.end(), data, data + data_length);
-}
-
-void NotificationIconLoader::didFinishLoading(
- WebURLLoader* loader,
- double finish_time,
- int64_t total_encoded_data_length) {
- DCHECK(!completed_);
-
- SkBitmap icon;
- if (!buffer_.empty()) {
- ImageDecoder decoder;
- icon = decoder.Decode(&buffer_[0], buffer_.size());
- }
-
- completed_ = true;
- callback_.Run(notification_id_, icon);
-}
-
-void NotificationIconLoader::didFail(
- WebURLLoader* loader, const WebURLError& error) {
- if (completed_)
- return;
-
- completed_ = true;
- callback_.Run(notification_id_, SkBitmap());
-}
-
-} // namespace content
diff --git a/chromium/content/renderer/notification_icon_loader.h b/chromium/content/renderer/notification_icon_loader.h
deleted file mode 100644
index 5bb95f80479..00000000000
--- a/chromium/content/renderer/notification_icon_loader.h
+++ /dev/null
@@ -1,73 +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_RENDERER_NOTIFICATION_ICON_LOADER_H_
-#define CONTENT_RENDERER_NOTIFICATION_ICON_LOADER_H_
-
-#include <vector>
-
-#include "base/callback.h"
-#include "base/memory/scoped_ptr.h"
-#include "third_party/WebKit/public/platform/WebURLLoaderClient.h"
-
-class SkBitmap;
-
-namespace blink {
-class WebURL;
-struct WebURLError;
-class WebURLLoader;
-}
-
-namespace content {
-
-// Downloads the icon associated with a notification and decodes the received
-// image. This must be completed before notifications are shown to the user.
-// Icon downloaders must not be re-used for multiple notifications or icons.
-class NotificationIconLoader : public blink::WebURLLoaderClient {
- typedef base::Callback<void(int, const SkBitmap&)> DownloadCompletedCallback;
-
- public:
- NotificationIconLoader(int notification_id,
- const DownloadCompletedCallback& callback);
-
- virtual ~NotificationIconLoader();
-
- // Downloads the notification's image and invokes the callback with the
- // decoded SkBitmap when the download has succeeded, or with an empty SkBitmap
- // in case the download has failed.
- void Start(const blink::WebURL& icon_url);
-
- // Cancels the current image download. The callback will not be invoked.
- void Cancel();
-
- // blink::WebURLLoaderClient implementation.
- virtual void didReceiveData(blink::WebURLLoader* loader,
- const char* data,
- int data_length,
- int encoded_data_length);
- virtual void didFinishLoading(blink::WebURLLoader* loader,
- double finish_time,
- int64_t total_encoded_data_length);
- virtual void didFail(blink::WebURLLoader* loader,
- const blink::WebURLError& error);
-
- int notification_id() const {
- return notification_id_;
- }
-
- private:
- int notification_id_;
- DownloadCompletedCallback callback_;
-
- scoped_ptr<blink::WebURLLoader> loader_;
- bool completed_;
-
- std::vector<uint8_t> buffer_;
-
- DISALLOW_COPY_AND_ASSIGN(NotificationIconLoader);
-};
-
-} // namespace content
-
-#endif // CONTENT_RENDERER_NOTIFICATION_ICON_LOADER_H_
diff --git a/chromium/content/renderer/notification_permission_dispatcher.cc b/chromium/content/renderer/notification_permission_dispatcher.cc
index 92d5529122b..60cac36976e 100644
--- a/chromium/content/renderer/notification_permission_dispatcher.cc
+++ b/chromium/content/renderer/notification_permission_dispatcher.cc
@@ -4,11 +4,13 @@
#include "content/renderer/notification_permission_dispatcher.h"
-#include "content/common/platform_notification_messages.h"
+#include "base/bind.h"
+#include "content/public/common/service_registry.h"
+#include "content/public/renderer/render_frame.h"
#include "third_party/WebKit/public/platform/WebString.h"
-#include "third_party/WebKit/public/web/WebNotificationPermissionCallback.h"
#include "third_party/WebKit/public/web/WebSecurityOrigin.h"
-#include "url/gurl.h"
+#include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
+#include "third_party/WebKit/public/web/modules/notifications/WebNotificationPermissionCallback.h"
namespace content {
@@ -22,30 +24,43 @@ NotificationPermissionDispatcher::~NotificationPermissionDispatcher() {
void NotificationPermissionDispatcher::RequestPermission(
const blink::WebSecurityOrigin& origin,
blink::WebNotificationPermissionCallback* callback) {
- int request_id = pending_requests_.Add(callback);
- Send(new PlatformNotificationHostMsg_RequestPermission(
- routing_id(), GURL(origin.toString()), request_id));
-}
+ if (!permission_service_.get()) {
+ render_frame()->GetServiceRegistry()->ConnectToRemoteService(
+ &permission_service_);
+ }
-bool NotificationPermissionDispatcher::OnMessageReceived(
- const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(NotificationPermissionDispatcher, message)
- IPC_MESSAGE_HANDLER(PlatformNotificationMsg_PermissionRequestComplete,
- OnPermissionRequestComplete);
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
+ int request_id = pending_requests_.Add(callback);
- return handled;
+ permission_service_->RequestPermission(
+ PERMISSION_NAME_NOTIFICATIONS,
+ origin.toString().utf8(),
+ blink::WebUserGestureIndicator::isProcessingUserGesture(),
+ base::Bind(&NotificationPermissionDispatcher::OnPermissionRequestComplete,
+ base::Unretained(this),
+ request_id));
}
void NotificationPermissionDispatcher::OnPermissionRequestComplete(
- int request_id, blink::WebNotificationPermission result) {
+ int request_id, PermissionStatus status) {
blink::WebNotificationPermissionCallback* callback =
pending_requests_.Lookup(request_id);
DCHECK(callback);
- callback->permissionRequestComplete(result);
+ blink::WebNotificationPermission permission =
+ blink::WebNotificationPermissionDefault;
+ switch (status) {
+ case PERMISSION_STATUS_GRANTED:
+ permission = blink::WebNotificationPermissionAllowed;
+ break;
+ case PERMISSION_STATUS_DENIED:
+ permission = blink::WebNotificationPermissionDenied;
+ break;
+ case PERMISSION_STATUS_ASK:
+ permission = blink::WebNotificationPermissionDefault;
+ break;
+ }
+
+ callback->permissionRequestComplete(permission);
pending_requests_.Remove(request_id);
}
diff --git a/chromium/content/renderer/notification_permission_dispatcher.h b/chromium/content/renderer/notification_permission_dispatcher.h
index c01b0632784..5c32693b18a 100644
--- a/chromium/content/renderer/notification_permission_dispatcher.h
+++ b/chromium/content/renderer/notification_permission_dispatcher.h
@@ -6,9 +6,8 @@
#define CONTENT_RENDERER_NOTIFICATION_PERMISSION_DISPATCHER_H_
#include "base/id_map.h"
+#include "content/common/permission_service.mojom.h"
#include "content/public/renderer/render_frame_observer.h"
-#include "ipc/ipc_message.h"
-#include "third_party/WebKit/public/platform/WebNotificationPermission.h"
namespace blink {
class WebNotificationPermissionCallback;
@@ -31,17 +30,16 @@ class NotificationPermissionDispatcher : public RenderFrameObserver {
blink::WebNotificationPermissionCallback* callback);
private:
- // RenderFrameObserver implementation.
- bool OnMessageReceived(const IPC::Message& message) override;
-
void OnPermissionRequestComplete(
- int request_id, blink::WebNotificationPermission result);
+ int request_id, PermissionStatus status);
// Tracks the active notification permission requests. This class takes
// ownership of the created WebNotificationPermissionCallback objects.
IDMap<blink::WebNotificationPermissionCallback, IDMapOwnPointer>
pending_requests_;
+ PermissionServicePtr permission_service_;
+
DISALLOW_COPY_AND_ASSIGN(NotificationPermissionDispatcher);
};
diff --git a/chromium/content/renderer/notification_provider.cc b/chromium/content/renderer/notification_provider.cc
deleted file mode 100644
index b5e749386cc..00000000000
--- a/chromium/content/renderer/notification_provider.cc
+++ /dev/null
@@ -1,165 +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/renderer/notification_provider.h"
-
-#include <vector>
-
-#include "base/strings/string_util.h"
-#include "content/common/desktop_notification_messages.h"
-#include "content/common/frame_messages.h"
-#include "content/renderer/notification_icon_loader.h"
-#include "content/renderer/render_frame_impl.h"
-#include "third_party/WebKit/public/web/WebDocument.h"
-#include "third_party/WebKit/public/web/WebLocalFrame.h"
-
-using blink::WebDocument;
-using blink::WebNotification;
-using blink::WebNotificationPresenter;
-using blink::WebSecurityOrigin;
-using blink::WebString;
-
-namespace content {
-
-NotificationProvider::NotificationProvider(RenderFrame* render_frame)
- : RenderFrameObserver(render_frame) {}
-
-NotificationProvider::~NotificationProvider() {}
-
-bool NotificationProvider::show(const WebNotification& notification) {
- int notification_id = manager_.RegisterNotification(notification);
- if (notification.iconURL().isEmpty()) {
- DisplayNotification(notification_id, SkBitmap());
- return true;
- }
-
- scoped_ptr<NotificationIconLoader> loader(
- new NotificationIconLoader(
- notification_id,
- base::Bind(&NotificationProvider::DisplayNotification,
- base::Unretained(this))));
-
- loader->Start(notification.iconURL());
-
- pending_notifications_.push_back(loader.release());
- return true;
-}
-
-void NotificationProvider::DisplayNotification(int notification_id,
- const SkBitmap& icon) {
- WebDocument document = render_frame()->GetWebFrame()->document();
- WebNotification notification;
-
- if (!manager_.GetNotification(notification_id, &notification)) {
- NOTREACHED();
- return;
- }
-
- RemovePendingNotification(notification_id);
-
- ShowDesktopNotificationHostMsgParams params;
- params.origin = GURL(document.securityOrigin().toString());
- params.icon = icon;
- params.title = notification.title();
- params.body = notification.body();
- params.direction = notification.direction();
- params.replace_id = notification.replaceId();
-
- Send(new DesktopNotificationHostMsg_Show(routing_id(),
- notification_id,
- params));
-}
-
-bool NotificationProvider::RemovePendingNotification(int notification_id) {
- PendingNotifications::iterator iter = pending_notifications_.begin();
- for (; iter != pending_notifications_.end(); ++iter) {
- if ((*iter)->notification_id() != notification_id)
- continue;
-
- pending_notifications_.erase(iter);
- return true;
- }
-
- return false;
-}
-
-void NotificationProvider::cancel(const WebNotification& notification) {
- int id;
- bool id_found = manager_.GetId(notification, id);
- // Won't be found if the notification has already been closed by the user,
- // or if the notification's icon is still being requested.
- if (id_found && !RemovePendingNotification(id))
- Send(new DesktopNotificationHostMsg_Cancel(routing_id(), id));
-}
-
-void NotificationProvider::objectDestroyed(
- const WebNotification& notification) {
- int id;
- bool id_found = manager_.GetId(notification, id);
- // Won't be found if the notification has already been closed by the user.
- if (id_found) {
- RemovePendingNotification(id);
- manager_.UnregisterNotification(id);
- }
-}
-
-WebNotificationPresenter::Permission NotificationProvider::checkPermission(
- const WebSecurityOrigin& origin) {
- int permission = WebNotificationPresenter::PermissionNotAllowed;
- Send(new DesktopNotificationHostMsg_CheckPermission(
- routing_id(),
- GURL(origin.toString()),
- &permission));
- return static_cast<WebNotificationPresenter::Permission>(permission);
-}
-
-bool NotificationProvider::OnMessageReceived(const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(NotificationProvider, message)
- IPC_MESSAGE_HANDLER(DesktopNotificationMsg_PostDisplay, OnDisplay);
- IPC_MESSAGE_HANDLER(DesktopNotificationMsg_PostClose, OnClose);
- IPC_MESSAGE_HANDLER(DesktopNotificationMsg_PostClick, OnClick);
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
-
- if (message.type() == FrameMsg_Navigate::ID)
- OnNavigate(); // Don't want to swallow the message.
-
- return handled;
-}
-
-void NotificationProvider::OnDisplay(int id) {
- WebNotification notification;
- bool found = manager_.GetNotification(id, &notification);
- // |found| may be false if the WebNotification went out of scope in
- // the page before it was actually displayed to the user.
- if (found)
- notification.dispatchDisplayEvent();
-}
-
-void NotificationProvider::OnClose(int id, bool by_user) {
- WebNotification notification;
- bool found = manager_.GetNotification(id, &notification);
- // |found| may be false if the WebNotification went out of scope in
- // the page before the associated toast was closed by the user.
- if (found) {
- notification.dispatchCloseEvent(by_user);
- manager_.UnregisterNotification(id);
- }
-}
-
-void NotificationProvider::OnClick(int id) {
- WebNotification notification;
- bool found = manager_.GetNotification(id, &notification);
- // |found| may be false if the WebNotification went out of scope in
- // the page before the associated toast was clicked on.
- if (found)
- notification.dispatchClickEvent();
-}
-
-void NotificationProvider::OnNavigate() {
- manager_.Clear();
-}
-
-} // namespace content
diff --git a/chromium/content/renderer/notification_provider.h b/chromium/content/renderer/notification_provider.h
deleted file mode 100644
index 7428e2f5da1..00000000000
--- a/chromium/content/renderer/notification_provider.h
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_RENDERER_NOTIFICATION_PROVIDER_H_
-#define CONTENT_RENDERER_NOTIFICATION_PROVIDER_H_
-
-#include "base/memory/scoped_vector.h"
-#include "content/public/renderer/render_frame_observer.h"
-#include "content/renderer/active_notification_tracker.h"
-#include "third_party/WebKit/public/web/WebNotification.h"
-#include "third_party/WebKit/public/web/WebNotificationPresenter.h"
-
-class SkBitmap;
-
-namespace content {
-
-class NotificationIconLoader;
-
-// NotificationProvider class is owned by the RenderFrame. Only to be used on
-// the main thread.
-class NotificationProvider : public RenderFrameObserver,
- public blink::WebNotificationPresenter {
- public:
- explicit NotificationProvider(RenderFrame* render_frame);
- ~NotificationProvider() override;
-
- private:
- // RenderFrameObserver implementation.
- bool OnMessageReceived(const IPC::Message& message) override;
-
- // blink::WebNotificationPresenter implementation.
- virtual bool show(const blink::WebNotification& proxy);
- virtual void cancel(const blink::WebNotification& proxy);
- virtual void objectDestroyed(const blink::WebNotification& proxy);
- virtual blink::WebNotificationPresenter::Permission checkPermission(
- const blink::WebSecurityOrigin& origin);
-
- // Sends an IPC to the browser process to display the notification identified
- // by |notification|, accompanied by the downloaded icon.
- void DisplayNotification(int notification_id, const SkBitmap& icon);
-
- // Removes the IconDownload object associated with |notification_id|, stopping
- // any in-progress download. Returns whether the notification was removed.
- bool RemovePendingNotification(int notification_id);
-
- // IPC handlers.
- void OnDisplay(int id);
- void OnClose(int id, bool by_user);
- void OnClick(int id);
- void OnNavigate();
-
- // A vector tracking notifications whose icon is still being downloaded.
- typedef ScopedVector<NotificationIconLoader> PendingNotifications;
- PendingNotifications pending_notifications_;
-
- // A tracker object which manages the active notifications and the IDs
- // that are used to refer to them over IPC.
- ActiveNotificationTracker manager_;
-
- DISALLOW_COPY_AND_ASSIGN(NotificationProvider);
-};
-
-} // namespace content
-
-#endif // CONTENT_RENDERER_NOTIFICATION_PROVIDER_H_
diff --git a/chromium/content/renderer/npapi/webplugin_delegate_proxy.cc b/chromium/content/renderer/npapi/webplugin_delegate_proxy.cc
index 3576b19fa0d..8e83b869424 100644
--- a/chromium/content/renderer/npapi/webplugin_delegate_proxy.cc
+++ b/chromium/content/renderer/npapi/webplugin_delegate_proxy.cc
@@ -18,7 +18,9 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/version.h"
+#include "cc/resources/shared_bitmap.h"
#include "content/child/child_process.h"
+#include "content/child/child_shared_bitmap_manager.h"
#include "content/child/npapi/npobject_proxy.h"
#include "content/child/npapi/npobject_stub.h"
#include "content/child/npapi/npobject_util.h"
@@ -45,19 +47,16 @@
#include "third_party/WebKit/public/web/WebView.h"
#include "ui/gfx/blit.h"
#include "ui/gfx/canvas.h"
+#include "ui/gfx/geometry/size.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/size.h"
#include "ui/gfx/skia_util.h"
#if defined(OS_POSIX)
#include "ipc/ipc_channel_posix.h"
#endif
-#if defined(OS_MACOSX)
-#include "base/mac/mac_util.h"
-#endif
-
#if defined(OS_WIN)
+#include "base/win/scoped_handle.h"
#include "content/public/common/sandbox_init.h"
#endif
@@ -312,13 +311,13 @@ bool WebPluginDelegateProxy::Initialize(
if (!info_.path.empty()) {
render_view_->GetMainRenderFrame()->PluginCrashed(
info_.path, base::kNullProcessId);
- LOG(ERROR) << "Plug-in crashed on start";
+ LOG(ERROR) << "Plugin crashed on start";
// Return true so that the plugin widget is created and we can paint the
// crashed plugin there.
return true;
}
- LOG(ERROR) << "Plug-in couldn't be found";
+ LOG(ERROR) << "Plugin couldn't be found";
return false;
}
@@ -495,12 +494,12 @@ void WebPluginDelegateProxy::OnChannelError() {
#endif
}
-static void CopyTransportDIBHandleForMessage(
- const TransportDIB::Handle& handle_in,
- TransportDIB::Handle* handle_out,
+static void CopySharedMemoryHandleForMessage(
+ const base::SharedMemoryHandle& handle_in,
+ base::SharedMemoryHandle* handle_out,
base::ProcessId peer_pid) {
-#if defined(OS_MACOSX)
- // On Mac, TransportDIB::Handle is typedef'ed to FileDescriptor, and
+#if defined(OS_POSIX)
+ // On POSIX, base::ShardMemoryHandle is typedef'ed to FileDescriptor, and
// FileDescriptor message fields needs to remain valid until the message is
// sent or else the sendmsg() call will fail.
if ((handle_out->fd = HANDLE_EINTR(dup(handle_in.fd))) < 0) {
@@ -515,8 +514,7 @@ static void CopyTransportDIBHandleForMessage(
FILE_MAP_READ | FILE_MAP_WRITE, 0);
DCHECK(*handle_out != NULL);
#else
- // Don't need to do anything special for other platforms.
- *handle_out = handle_in;
+#error Shared memory copy not implemented.
#endif
}
@@ -528,8 +526,8 @@ void WebPluginDelegateProxy::SendUpdateGeometry(
PluginMsg_UpdateGeometry_Param param;
param.window_rect = plugin_rect_;
param.clip_rect = clip_rect_;
- param.windowless_buffer0 = TransportDIB::DefaultHandleValue();
- param.windowless_buffer1 = TransportDIB::DefaultHandleValue();
+ param.windowless_buffer0 = base::SharedMemory::NULLHandle();
+ param.windowless_buffer1 = base::SharedMemory::NULLHandle();
param.windowless_buffer_index = back_buffer_index();
#if defined(OS_POSIX)
@@ -539,15 +537,15 @@ void WebPluginDelegateProxy::SendUpdateGeometry(
if (bitmaps_changed)
#endif
{
- if (transport_stores_[0].dib)
- CopyTransportDIBHandleForMessage(transport_stores_[0].dib->handle(),
- &param.windowless_buffer0,
- channel_host_->peer_pid());
-
- if (transport_stores_[1].dib)
- CopyTransportDIBHandleForMessage(transport_stores_[1].dib->handle(),
- &param.windowless_buffer1,
- channel_host_->peer_pid());
+ if (transport_stores_[0].bitmap)
+ CopySharedMemoryHandleForMessage(
+ transport_stores_[0].bitmap->shared_memory()->handle(),
+ &param.windowless_buffer0, channel_host_->peer_pid());
+
+ if (transport_stores_[1].bitmap)
+ CopySharedMemoryHandleForMessage(
+ transport_stores_[1].bitmap->shared_memory()->handle(),
+ &param.windowless_buffer1, channel_host_->peer_pid());
}
IPC::Message* msg;
@@ -593,9 +591,9 @@ void WebPluginDelegateProxy::UpdateGeometry(const gfx::Rect& window_rect,
// asynchronously.
ResetWindowlessBitmaps();
if (!window_rect.IsEmpty()) {
- if (!CreateSharedBitmap(&transport_stores_[0].dib,
+ if (!CreateSharedBitmap(&transport_stores_[0].bitmap,
&transport_stores_[0].canvas) ||
- !CreateSharedBitmap(&transport_stores_[1].dib,
+ !CreateSharedBitmap(&transport_stores_[1].bitmap,
&transport_stores_[1].canvas)) {
DCHECK(false);
ResetWindowlessBitmaps();
@@ -609,8 +607,8 @@ void WebPluginDelegateProxy::UpdateGeometry(const gfx::Rect& window_rect,
}
void WebPluginDelegateProxy::ResetWindowlessBitmaps() {
- transport_stores_[0].dib.reset();
- transport_stores_[1].dib.reset();
+ transport_stores_[0].bitmap.reset();
+ transport_stores_[1].bitmap.reset();
transport_stores_[0].canvas.reset();
transport_stores_[1].canvas.reset();
@@ -640,28 +638,23 @@ bool WebPluginDelegateProxy::CreateLocalBitmap(
#endif
bool WebPluginDelegateProxy::CreateSharedBitmap(
- scoped_ptr<TransportDIB>* memory,
+ scoped_ptr<SharedMemoryBitmap>* memory,
scoped_ptr<skia::PlatformCanvas>* canvas) {
- const size_t size = BitmapSizeForPluginRect(plugin_rect_);
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
- memory->reset(TransportDIB::Create(size, 0));
+ *memory = ChildThreadImpl::current()
+ ->shared_bitmap_manager()
+ ->AllocateSharedMemoryBitmap(plugin_rect_.size());
if (!memory->get())
return false;
-#endif
-#if defined(OS_POSIX) && !defined(OS_ANDROID)
- TransportDIB::Handle handle;
- IPC::Message* msg = new ViewHostMsg_AllocTransportDIB(size, false, &handle);
- if (!RenderThreadImpl::current()->Send(msg))
- return false;
- if (handle.fd < 0)
- return false;
- memory->reset(TransportDIB::Map(handle));
+ DCHECK((*memory)->shared_memory());
+#if defined(OS_POSIX)
+ canvas->reset(skia::CreatePlatformCanvas(
+ plugin_rect_.width(), plugin_rect_.height(), true, (*memory)->pixels(),
+ skia::RETURN_NULL_ON_FAILURE));
#else
- static uint32 sequence_number = 0;
- memory->reset(TransportDIB::Create(size, sequence_number++));
+ canvas->reset(skia::CreatePlatformCanvas(
+ plugin_rect_.width(), plugin_rect_.height(), true,
+ (*memory)->shared_memory()->handle(), skia::RETURN_NULL_ON_FAILURE));
#endif
- canvas->reset((*memory)->GetPlatformCanvas(plugin_rect_.width(),
- plugin_rect_.height()));
return !!canvas->get();
}
@@ -720,7 +713,7 @@ void WebPluginDelegateProxy::Paint(SkCanvas* canvas,
if (invalidate_pending_) {
// Only send the PaintAck message if this paint is in response to an
// invalidate from the plugin, since this message acts as an access token
- // to ensure only one process is using the transport dib at a time.
+ // to ensure only one process is using the shared bitmap at a time.
invalidate_pending_ = false;
Send(new PluginMsg_DidPaint(instance_id_));
}
@@ -738,6 +731,9 @@ NPObject* WebPluginDelegateProxy::GetPluginScriptableObject() {
if (route_id == MSG_ROUTING_NONE)
return NULL;
+ if (!channel_host_.get())
+ return nullptr;
+
npobject_ = NPObjectProxy::Create(
channel_host_.get(), route_id, 0, page_url_, GetPluginNPP());
@@ -805,7 +801,7 @@ void WebPluginDelegateProxy::ImeCompositionUpdated(
const std::vector<int>& target,
int cursor_position,
int plugin_id) {
- // Dispatch the raw IME data if this plug-in is the focused one.
+ // Dispatch the raw IME data if this plugin is the focused one.
if (instance_id_ != plugin_id)
return;
@@ -817,7 +813,7 @@ void WebPluginDelegateProxy::ImeCompositionUpdated(
void WebPluginDelegateProxy::ImeCompositionCompleted(const base::string16& text,
int plugin_id) {
- // Dispatch the IME text if this plug-in is the focused one.
+ // Dispatch the IME text if this plugin is the focused one.
if (instance_id_ != plugin_id)
return;
@@ -897,10 +893,12 @@ void WebPluginDelegateProxy::WillDestroyWindow() {
#if defined(OS_WIN)
void WebPluginDelegateProxy::OnSetWindowlessData(
- HANDLE modal_loop_pump_messages_event,
+ HANDLE modal_loop_pump_messages_event_handle,
gfx::NativeViewId dummy_activation_window) {
- DCHECK(modal_loop_pump_messages_event_ == NULL);
- DCHECK(dummy_activation_window_ == NULL);
+ DCHECK(!modal_loop_pump_messages_event_.get());
+ DCHECK(!dummy_activation_window_);
+ base::win::ScopedHandle modal_loop_pump_messages_event(
+ modal_loop_pump_messages_event_handle);
dummy_activation_window_ = dummy_activation_window;
render_view_->Send(new ViewHostMsg_WindowlessPluginDummyWindowCreated(
@@ -908,11 +906,11 @@ void WebPluginDelegateProxy::OnSetWindowlessData(
// Bug 25583: this can be null because some "virus scanners" block the
// DuplicateHandle call in the plugin process.
- if (!modal_loop_pump_messages_event)
+ if (!modal_loop_pump_messages_event.IsValid())
return;
modal_loop_pump_messages_event_.reset(
- new base::WaitableEvent(modal_loop_pump_messages_event));
+ new base::WaitableEvent(modal_loop_pump_messages_event.Pass()));
}
void WebPluginDelegateProxy::OnNotifyIMEStatus(int input_type,
@@ -1020,12 +1018,12 @@ void WebPluginDelegateProxy::CopyFromBackBufferToFrontBuffer(
const size_t stride =
skia::PlatformCanvasStrideForWidth(plugin_rect_.width());
const size_t chunk_size = 4 * rect.width();
- DCHECK(back_buffer_dib() != NULL);
- uint8* source_data = static_cast<uint8*>(back_buffer_dib()->memory()) +
- rect.y() * stride + 4 * rect.x();
- DCHECK(front_buffer_dib() != NULL);
- uint8* target_data = static_cast<uint8*>(front_buffer_dib()->memory()) +
- rect.y() * stride + 4 * rect.x();
+ DCHECK(back_buffer_bitmap() != NULL);
+ uint8* source_data =
+ back_buffer_bitmap()->pixels() + rect.y() * stride + 4 * rect.x();
+ DCHECK(front_buffer_bitmap() != NULL);
+ uint8* target_data =
+ front_buffer_bitmap()->pixels() + rect.y() * stride + 4 * rect.x();
for (int row = 0; row < rect.height(); ++row) {
memcpy(target_data, source_data, chunk_size);
source_data += stride;
@@ -1121,7 +1119,7 @@ void WebPluginDelegateProxy::FetchURL(unsigned long resource_id,
const std::string& method,
const char* buf,
unsigned int len,
- const GURL& referrer,
+ const Referrer& referrer,
bool notify_redirects,
bool is_plugin_src_load,
int origin_pid,
@@ -1137,7 +1135,8 @@ void WebPluginDelegateProxy::FetchURL(unsigned long resource_id,
params.post_data.resize(len);
memcpy(&params.post_data.front(), buf, len);
}
- params.referrer = referrer;
+ params.referrer = referrer.url;
+ params.referrer_policy = referrer.policy;
params.notify_redirect = notify_redirects;
params.is_plugin_src_load = is_plugin_src_load;
params.render_frame_id = render_frame_id;
diff --git a/chromium/content/renderer/npapi/webplugin_delegate_proxy.h b/chromium/content/renderer/npapi/webplugin_delegate_proxy.h
index 5b8c62c6aa1..2d770eeaea8 100644
--- a/chromium/content/renderer/npapi/webplugin_delegate_proxy.h
+++ b/chromium/content/renderer/npapi/webplugin_delegate_proxy.h
@@ -17,9 +17,8 @@
#include "ipc/ipc_listener.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_sender.h"
+#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/rect.h"
-#include "ui/surface/transport_dib.h"
#include "url/gurl.h"
#if defined(OS_MACOSX)
@@ -35,11 +34,13 @@ namespace base {
class WaitableEvent;
}
+
namespace content {
class NPObjectStub;
class PluginChannelHost;
class RenderFrameImpl;
class RenderViewImpl;
+class SharedMemoryBitmap;
class WebPluginImpl;
// An implementation of WebPluginDelegate that proxies all calls to
@@ -137,7 +138,7 @@ class WebPluginDelegateProxy
const std::string& method,
const char* buf,
unsigned int len,
- const GURL& referrer,
+ const Referrer& referrer,
bool notify_redirects,
bool is_plugin_src_load,
int origin_pid,
@@ -155,7 +156,7 @@ class WebPluginDelegateProxy
SharedBitmap();
~SharedBitmap();
- scoped_ptr<TransportDIB> dib;
+ scoped_ptr<SharedMemoryBitmap> bitmap;
scoped_ptr<SkCanvas> canvas;
};
@@ -195,7 +196,7 @@ class WebPluginDelegateProxy
void OnAcceleratedPluginSwappedIOSurface();
#endif
#if defined(OS_WIN)
- void OnSetWindowlessData(HANDLE modal_loop_pump_messages_event,
+ void OnSetWindowlessData(HANDLE modal_loop_pump_messages_event_handle,
gfx::NativeViewId dummy_activation_window);
void OnNotifyIMEStatus(const int input_mode, const gfx::Rect& caret_rect);
#endif
@@ -229,12 +230,12 @@ class WebPluginDelegateProxy
return transport_stores_[back_buffer_index()].canvas.get();
}
- TransportDIB* front_buffer_dib() const {
- return transport_stores_[front_buffer_index()].dib.get();
+ SharedMemoryBitmap* front_buffer_bitmap() const {
+ return transport_stores_[front_buffer_index()].bitmap.get();
}
- TransportDIB* back_buffer_dib() const {
- return transport_stores_[back_buffer_index()].dib.get();
+ SharedMemoryBitmap* back_buffer_bitmap() const {
+ return transport_stores_[back_buffer_index()].bitmap.get();
}
#if !defined(OS_WIN)
@@ -245,7 +246,7 @@ class WebPluginDelegateProxy
#endif
// Creates a shared memory section and canvas.
- bool CreateSharedBitmap(scoped_ptr<TransportDIB>* memory,
+ bool CreateSharedBitmap(scoped_ptr<SharedMemoryBitmap>* memory,
scoped_ptr<SkCanvas>* canvas);
// Called for cleanup during plugin destruction. Normally right before the
diff --git a/chromium/content/renderer/npapi/webplugin_impl.cc b/chromium/content/renderer/npapi/webplugin_impl.cc
index 4370dec7922..558cd47c58b 100644
--- a/chromium/content/renderer/npapi/webplugin_impl.cc
+++ b/chromium/content/renderer/npapi/webplugin_impl.cc
@@ -55,7 +55,7 @@
#include "third_party/WebKit/public/web/WebPluginParams.h"
#include "third_party/WebKit/public/web/WebURLLoaderOptions.h"
#include "third_party/WebKit/public/web/WebView.h"
-#include "ui/gfx/rect.h"
+#include "ui/gfx/geometry/rect.h"
#include "url/gurl.h"
#include "url/url_util.h"
@@ -298,31 +298,40 @@ bool WebPluginImpl::getFormValue(blink::WebString& value) {
return true;
}
-void WebPluginImpl::paint(WebCanvas* canvas, const WebRect& paint_rect) {
- if (!delegate_ || !container_)
+void WebPluginImpl::layoutIfNeeded() {
+ if (!container_)
return;
#if defined(OS_WIN)
// Force a geometry update if needed to allow plugins like media player
- // which defer the initial geometry update to work.
+ // which defer the initial geometry update to work. Do it now, rather
+ // than in paint, so that the paint rect invalidation is registered.
+ // Otherwise we may never get the paint call.
container_->reportGeometry();
#endif // OS_WIN
+}
+
+void WebPluginImpl::paint(WebCanvas* canvas, const WebRect& paint_rect) {
+ if (!delegate_ || !container_)
+ return;
// Note that |canvas| is only used when in windowless mode.
delegate_->Paint(canvas, paint_rect);
}
-void WebPluginImpl::updateGeometry(
- const WebRect& window_rect, const WebRect& clip_rect,
- const WebVector<WebRect>& cutout_rects, bool is_visible) {
+void WebPluginImpl::updateGeometry(const WebRect& window_rect,
+ const WebRect& clip_rect,
+ const WebRect& unobscured_rect,
+ const WebVector<WebRect>& cut_outs_rects,
+ bool is_visible) {
WebPluginGeometry new_geometry;
new_geometry.window = window_;
new_geometry.window_rect = window_rect;
new_geometry.clip_rect = clip_rect;
new_geometry.visible = is_visible;
new_geometry.rects_valid = true;
- for (size_t i = 0; i < cutout_rects.size(); ++i)
- new_geometry.cutout_rects.push_back(cutout_rects[i]);
+ for (size_t i = 0; i < cut_outs_rects.size(); ++i)
+ new_geometry.cutout_rects.push_back(cut_outs_rects[i]);
// Only send DidMovePlugin if the geometry changed in some way.
if (window_ && (first_geometry_update_ || !new_geometry.Equals(geometry_))) {
@@ -379,7 +388,7 @@ void WebPluginImpl::updateGeometry(
first_geometry_update_ = false;
}
-void WebPluginImpl::updateFocus(bool focused) {
+void WebPluginImpl::updateFocus(bool focused, blink::WebFocusType focus_type) {
if (accepts_input_events_)
delegate_->SetFocus(focused);
}
@@ -650,7 +659,7 @@ bool WebPluginImpl::SetPostData(WebURLRequest* request,
return rv;
}
-bool WebPluginImpl::IsValidUrl(const GURL& url, Referrer referrer_flag) {
+bool WebPluginImpl::IsValidUrl(const GURL& url, ReferrerValue referrer_flag) {
if (referrer_flag == PLUGIN_SRC &&
mime_type_ == kFlashPluginSwfMimeType &&
url.GetOrigin() != plugin_url_.GetOrigin()) {
@@ -682,7 +691,7 @@ WebPluginImpl::RoutingStatus WebPluginImpl::RouteToFrame(
const char* buf,
unsigned int len,
int notify_id,
- Referrer referrer_flag) {
+ ReferrerValue referrer_flag) {
// If there is no target, there is nothing to do
if (!target)
return NOT_ROUTED;
@@ -917,7 +926,7 @@ void WebPluginImpl::willSendRequest(WebURLLoader* loader,
// Currently this check is just to catch an https -> http redirect when
// loading the main plugin src URL. Longer term, we could investigate
// firing mixed diplay or scripting issues for subresource loads
- // initiated by plug-ins.
+ // initiated by plugins.
if (client_info->is_plugin_src_load &&
webframe_ &&
!webframe_->checkIfRunInsecureContent(request.url())) {
@@ -1161,7 +1170,7 @@ void WebPluginImpl::HandleURLRequestInternal(const char* url,
unsigned int len,
int notify_id,
bool popups_allowed,
- Referrer referrer_flag,
+ ReferrerValue referrer_flag,
bool notify_redirects,
bool is_plugin_src_load) {
// For this request, we either route the output to a frame
@@ -1219,7 +1228,7 @@ void WebPluginImpl::HandleURLRequestInternal(const char* url,
if (!delegate_)
return;
- if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableDirectNPAPIRequests)) {
// We got here either because the plugin called GetURL/PostURL, or because
// we're fetching the data for an embed tag. If we're in multi-process mode,
@@ -1233,8 +1242,9 @@ void WebPluginImpl::HandleURLRequestInternal(const char* url,
// WebFrameImpl::setReferrerForRequest does.
WebURLRequest request(complete_url);
SetReferrer(&request, referrer_flag);
- GURL referrer(
- request.httpHeaderField(WebString::fromUTF8("Referer")).utf8());
+ Referrer referrer(
+ GURL(request.httpHeaderField(WebString::fromUTF8("Referer"))),
+ request.referrerPolicy());
GURL first_party_for_cookies = webframe_->document().firstPartyForCookies();
delegate_->FetchURL(resource_id, notify_id, complete_url,
@@ -1269,7 +1279,7 @@ bool WebPluginImpl::InitiateHTTPRequest(unsigned long resource_id,
const char* buf,
int buf_len,
const char* range_info,
- Referrer referrer_flag,
+ ReferrerValue referrer_flag,
bool notify_redirects,
bool is_plugin_src_load) {
if (!client) {
@@ -1520,7 +1530,7 @@ void WebPluginImpl::TearDownPluginInstance(
}
void WebPluginImpl::SetReferrer(blink::WebURLRequest* request,
- Referrer referrer_flag) {
+ ReferrerValue referrer_flag) {
switch (referrer_flag) {
case DOCUMENT_URL:
webframe_->setReferrerForRequest(*request, GURL());
diff --git a/chromium/content/renderer/npapi/webplugin_impl.h b/chromium/content/renderer/npapi/webplugin_impl.h
index 6115d08346f..918f578c1d7 100644
--- a/chromium/content/renderer/npapi/webplugin_impl.h
+++ b/chromium/content/renderer/npapi/webplugin_impl.h
@@ -36,6 +36,7 @@ class WebPluginContainer;
class WebURLResponse;
class WebURLLoader;
class WebURLRequest;
+struct WebPluginParams;
}
namespace content {
@@ -72,12 +73,16 @@ class WebPluginImpl : public WebPlugin,
virtual NPObject* scriptableObject();
virtual struct _NPP* pluginNPP();
virtual bool getFormValue(blink::WebString& value);
+ virtual void layoutIfNeeded() override;
virtual void paint(
blink::WebCanvas* canvas, const blink::WebRect& paint_rect);
virtual void updateGeometry(
- const blink::WebRect& frame_rect, const blink::WebRect& clip_rect,
- const blink::WebVector<blink::WebRect>& cut_outs, bool is_visible);
- virtual void updateFocus(bool focused);
+ const blink::WebRect& window_rect,
+ const blink::WebRect& clip_rect,
+ const blink::WebRect& unobscured_rect,
+ const blink::WebVector<blink::WebRect>& cut_outs_rects,
+ bool is_visible);
+ virtual void updateFocus(bool focused, blink::WebFocusType focus_type);
virtual void updateVisibility(bool visible);
virtual bool acceptsInputEvents();
virtual bool handleInputEvent(
@@ -128,7 +133,7 @@ class WebPluginImpl : public WebPlugin,
bool CheckIfRunInsecureContent(const GURL& url) override;
#if defined(OS_WIN)
void SetWindowlessData(HANDLE pump_messages_event,
- gfx::NativeViewId dummy_activation_window) { }
+ gfx::NativeViewId dummy_activation_window) override {}
void ReparentPluginWindow(HWND window, HWND parent) { }
void ReportExecutableMemory(size_t size) { }
#endif
@@ -155,7 +160,7 @@ class WebPluginImpl : public WebPlugin,
// Determines the referrer value sent along with outgoing HTTP requests
// issued by plugins.
- enum Referrer {
+ enum ReferrerValue {
PLUGIN_SRC,
DOCUMENT_URL,
NO_REFERRER
@@ -172,7 +177,7 @@ class WebPluginImpl : public WebPlugin,
const char* buf,
unsigned int len,
int notify_id,
- Referrer referrer_flag);
+ ReferrerValue referrer_flag);
// Returns the next avaiable resource id. Returns 0 if the operation fails.
// It may fail if the page has already been closed.
@@ -187,7 +192,7 @@ class WebPluginImpl : public WebPlugin,
const char* buf,
int len,
const char* range_info,
- Referrer referrer_flag,
+ ReferrerValue referrer_flag,
bool notify_redirects,
bool check_mixed_scripting);
@@ -242,7 +247,7 @@ class WebPluginImpl : public WebPlugin,
unsigned int len,
int notify_id,
bool popups_allowed,
- Referrer referrer_flag,
+ ReferrerValue referrer_flag,
bool notify_redirects,
bool check_mixed_scripting);
@@ -260,10 +265,10 @@ class WebPluginImpl : public WebPlugin,
ClientInfo* GetClientInfoFromLoader(blink::WebURLLoader* loader);
// Helper function to set the referrer on the request passed in.
- void SetReferrer(blink::WebURLRequest* request, Referrer referrer_flag);
+ void SetReferrer(blink::WebURLRequest* request, ReferrerValue referrer_flag);
// Check for invalid chars like @, ;, \ before the first / (in path).
- bool IsValidUrl(const GURL& url, Referrer referrer_flag);
+ bool IsValidUrl(const GURL& url, ReferrerValue referrer_flag);
std::vector<ClientInfo> clients_;
diff --git a/chromium/content/renderer/p2p/ipc_network_manager.cc b/chromium/content/renderer/p2p/ipc_network_manager.cc
index ec48e4006a1..e279f9830f9 100644
--- a/chromium/content/renderer/p2p/ipc_network_manager.cc
+++ b/chromium/content/renderer/p2p/ipc_network_manager.cc
@@ -74,8 +74,6 @@ void IpcNetworkManager::OnNetworkListChanged(
// rtc::Network uses these prefix_length to compare network
// interfaces discovered.
std::vector<rtc::Network*> networks;
- int ipv4_interfaces = 0;
- int ipv6_interfaces = 0;
for (net::NetworkInterfaceList::const_iterator it = list.begin();
it != list.end(); it++) {
if (it->address.size() == net::kIPv4AddressSize) {
@@ -83,45 +81,37 @@ void IpcNetworkManager::OnNetworkListChanged(
memcpy(&address, &it->address[0], sizeof(uint32));
address = rtc::NetworkToHost32(address);
rtc::IPAddress prefix =
- rtc::TruncateIP(rtc::IPAddress(address), it->network_prefix);
+ rtc::TruncateIP(rtc::IPAddress(address), it->prefix_length);
rtc::Network* network =
- new rtc::Network(it->name,
- it->name,
- prefix,
- it->network_prefix,
+ new rtc::Network(it->name, it->name, prefix, it->prefix_length,
ConvertConnectionTypeToAdapterType(it->type));
network->AddIP(rtc::IPAddress(address));
networks.push_back(network);
- ++ipv4_interfaces;
} else if (it->address.size() == net::kIPv6AddressSize) {
in6_addr address;
memcpy(&address, &it->address[0], sizeof(in6_addr));
- rtc::IPAddress ip6_addr(address);
+ rtc::InterfaceAddress ip6_addr(address, it->ip_address_attributes);
+
+ // Only allow non-deprecated IPv6 addresses which don't contain MAC.
+ if (rtc::IPIsMacBased(ip6_addr) ||
+ (it->ip_address_attributes & net::IP_ADDRESS_ATTRIBUTE_DEPRECATED)) {
+ continue;
+ }
+
if (!rtc::IPIsPrivate(ip6_addr)) {
rtc::IPAddress prefix =
- rtc::TruncateIP(rtc::IPAddress(ip6_addr), it->network_prefix);
+ rtc::TruncateIP(rtc::IPAddress(ip6_addr), it->prefix_length);
rtc::Network* network =
- new rtc::Network(it->name,
- it->name,
- prefix,
- it->network_prefix,
+ new rtc::Network(it->name, it->name, prefix, it->prefix_length,
ConvertConnectionTypeToAdapterType(it->type));
network->AddIP(ip6_addr);
networks.push_back(network);
- ++ipv6_interfaces;
}
}
}
-
- // Send interface counts to UMA.
- UMA_HISTOGRAM_COUNTS_100("WebRTC.PeerConnection.IPv4Interfaces",
- ipv4_interfaces);
- UMA_HISTOGRAM_COUNTS_100("WebRTC.PeerConnection.IPv6Interfaces",
- ipv6_interfaces);
-
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kAllowLoopbackInPeerConnection)) {
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kAllowLoopbackInPeerConnection)) {
std::string name_v4("loopback_ipv4");
rtc::IPAddress ip_address_v4(INADDR_LOOPBACK);
rtc::Network* network_v4 = new rtc::Network(
@@ -138,9 +128,16 @@ void IpcNetworkManager::OnNetworkListChanged(
}
bool changed = false;
- MergeNetworkList(networks, &changed);
+ NetworkManager::Stats stats;
+ MergeNetworkList(networks, &changed, &stats);
if (changed)
SignalNetworksChanged();
+
+ // Send interface counts to UMA.
+ UMA_HISTOGRAM_COUNTS_100("WebRTC.PeerConnection.IPv4Interfaces",
+ stats.ipv4_network_count);
+ UMA_HISTOGRAM_COUNTS_100("WebRTC.PeerConnection.IPv6Interfaces",
+ stats.ipv6_network_count);
}
void IpcNetworkManager::SendNetworksChangedSignal() {
diff --git a/chromium/content/renderer/p2p/ipc_socket_factory.cc b/chromium/content/renderer/p2p/ipc_socket_factory.cc
index 27d6825b3e5..e3808e802f5 100644
--- a/chromium/content/renderer/p2p/ipc_socket_factory.cc
+++ b/chromium/content/renderer/p2p/ipc_socket_factory.cc
@@ -5,15 +5,17 @@
#include "content/renderer/p2p/ipc_socket_factory.h"
#include <algorithm>
-#include <deque>
+#include <list>
#include "base/compiler_specific.h"
-#include "base/debug/trace_event.h"
#include "base/message_loop/message_loop.h"
#include "base/message_loop/message_loop_proxy.h"
+#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
+#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/threading/non_thread_safe.h"
+#include "base/trace_event/trace_event.h"
#include "content/renderer/media/webrtc_logging.h"
#include "content/renderer/p2p/host_address_request.h"
#include "content/renderer/p2p/socket_client_delegate.h"
@@ -63,7 +65,7 @@ bool JingleSocketOptionToP2PSocketOption(rtc::Socket::Option option,
// TODO(miu): This needs tuning. http://crbug.com/237960
// http://crbug.com/427555
-const size_t kMaximumInFlightBytes = 256 * 1024; // 256 KB
+const size_t kMaximumInFlightBytes = 64 * 1024; // 64 KB
// IpcPacketSocket implements rtc::AsyncPacketSocket interface
// using P2PSocketClient that works over IPC-channel. It must be used
@@ -74,6 +76,19 @@ class IpcPacketSocket : public rtc::AsyncPacketSocket,
IpcPacketSocket();
~IpcPacketSocket() override;
+ // Struct to track information when a packet is received by this socket for
+ // send. The information tracked here will be used to match with the
+ // P2PSendPacketMetrics from the underneath system socket.
+ struct InFlightPacketRecord {
+ InFlightPacketRecord(uint64_t packet_id, size_t packet_size)
+ : packet_id(packet_id), packet_size(packet_size) {}
+
+ uint64_t packet_id;
+ size_t packet_size;
+ };
+
+ typedef std::list<InFlightPacketRecord> InFlightPacketList;
+
// Always takes ownership of client even if initialization fails.
bool Init(P2PSocketType type, P2PSocketClientImpl* client,
const rtc::SocketAddress& local_address,
@@ -101,7 +116,7 @@ class IpcPacketSocket : public rtc::AsyncPacketSocket,
const net::IPEndPoint& remote_address) override;
void OnIncomingTcpConnection(const net::IPEndPoint& address,
P2PSocketClient* client) override;
- void OnSendComplete() override;
+ void OnSendComplete(const P2PSendPacketMetrics& send_metrics) override;
void OnError() override;
void OnDataReceived(const net::IPEndPoint& address,
const std::vector<char>& data,
@@ -122,7 +137,7 @@ class IpcPacketSocket : public rtc::AsyncPacketSocket,
// Update trace of send throttling internal state. This should be called
// immediately after any changes to |send_bytes_available_| and/or
- // |in_flight_packet_sizes_|.
+ // |in_flight_packet_records_|.
void TraceSendThrottlingState() const;
void InitAcceptedTcp(P2PSocketClient* client,
@@ -131,6 +146,10 @@ class IpcPacketSocket : public rtc::AsyncPacketSocket,
int DoSetOption(P2PSocketOption option, int value);
+ // Allow a finch experiment to control the initial value of
+ // send_bytes_available_;
+ void AdjustUdpSendBufferSize();
+
P2PSocketType type_;
// Message loop on which this socket was created and being used.
@@ -157,7 +176,11 @@ class IpcPacketSocket : public rtc::AsyncPacketSocket,
// allows short bursts of high-rate sending without dropping packets, but
// quickly restricts the client to a sustainable steady-state rate.
size_t send_bytes_available_;
- std::deque<size_t> in_flight_packet_sizes_;
+
+ // Used to detect when browser doesn't send SendComplete message for some
+ // packets. In normal case, the first packet should be the one that we're
+ // going to receive the next completion signal.
+ InFlightPacketList in_flight_packet_records_;
// Set to true once EWOULDBLOCK was returned from Send(). Indicates that the
// caller expects SignalWritable notification.
@@ -215,7 +238,7 @@ IpcPacketSocket::IpcPacketSocket()
current_discard_bytes_sequence_(0),
packets_discarded_(0),
total_packets_(0) {
- COMPILE_ASSERT(kMaximumInFlightBytes > 0, would_send_at_zero_rate);
+ static_assert(kMaximumInFlightBytes > 0, "would send at zero rate");
std::fill_n(options_, static_cast<int> (P2P_SOCKET_OPT_MAX),
kDefaultNonSetOptionValue);
}
@@ -226,9 +249,8 @@ IpcPacketSocket::~IpcPacketSocket() {
Close();
}
- UMA_HISTOGRAM_COUNTS_10000("WebRTC.ApplicationMaxConsecutiveBytesDiscard",
- max_discard_bytes_sequence_);
-
+ UMA_HISTOGRAM_CUSTOM_COUNTS("WebRTC.ApplicationMaxConsecutiveBytesDiscard.v2",
+ max_discard_bytes_sequence_, 1, 1000000, 200);
if (total_packets_ > 0) {
UMA_HISTOGRAM_PERCENTAGE("WebRTC.ApplicationPercentPacketsDiscarded",
(packets_discarded_ * 100) / total_packets_);
@@ -239,7 +261,7 @@ void IpcPacketSocket::TraceSendThrottlingState() const {
TRACE_COUNTER_ID1("p2p", "P2PSendBytesAvailable", local_address_.port(),
send_bytes_available_);
TRACE_COUNTER_ID1("p2p", "P2PSendPacketsInFlight", local_address_.port(),
- in_flight_packet_sizes_.size());
+ in_flight_packet_records_.size());
}
void IpcPacketSocket::IncrementDiscardCounters(size_t bytes_discarded) {
@@ -251,6 +273,19 @@ void IpcPacketSocket::IncrementDiscardCounters(size_t bytes_discarded) {
}
}
+void IpcPacketSocket::AdjustUdpSendBufferSize() {
+ DCHECK_EQ(type_, P2P_SOCKET_UDP);
+ unsigned int send_buffer_size = 0;
+
+ base::StringToUint(
+ base::FieldTrialList::FindFullName("WebRTC-ApplicationUDPSendSocketSize"),
+ &send_buffer_size);
+
+ if (send_buffer_size > 0) {
+ send_bytes_available_ = send_buffer_size;
+ }
+}
+
bool IpcPacketSocket::Init(P2PSocketType type,
P2PSocketClientImpl* client,
const rtc::SocketAddress& local_address,
@@ -270,6 +305,10 @@ bool IpcPacketSocket::Init(P2PSocketType type,
return false;
}
+ if (type_ == P2P_SOCKET_UDP) {
+ AdjustUdpSendBufferSize();
+ }
+
net::IPEndPoint remote_endpoint;
if (!remote_address.IsNil()) {
DCHECK(IsTcpClientSocket(type_));
@@ -362,7 +401,7 @@ int IpcPacketSocket::SendTo(const void *data, size_t data_size,
if (!writable_signal_expected_) {
WebRtcLogMessage(base::StringPrintf(
"IpcPacketSocket: sending is blocked. %d packets_in_flight.",
- static_cast<int>(in_flight_packet_sizes_.size())));
+ static_cast<int>(in_flight_packet_records_.size())));
writable_signal_expected_ = true;
}
@@ -375,22 +414,33 @@ int IpcPacketSocket::SendTo(const void *data, size_t data_size,
}
net::IPEndPoint address_chrome;
- if (!jingle_glue::SocketAddressToIPEndPoint(address, &address_chrome)) {
- VLOG(1) << "Failed to convert remote address to IPEndPoint: address = "
- << address.ToSensitiveString() << ", remote_address_ = "
- << remote_address_.ToSensitiveString();
- NOTREACHED();
- error_ = EINVAL;
- return -1;
+ if (address.IsUnresolvedIP()) {
+ address_chrome = net::IPEndPoint(net::IPAddressNumber(), address.port());
+ } else {
+ if (!jingle_glue::SocketAddressToIPEndPoint(address, &address_chrome)) {
+ LOG(WARNING) << "Failed to convert remote address to IPEndPoint: address="
+ << address.ipaddr().ToSensitiveString()
+ << ", remote_address_="
+ << remote_address_.ipaddr().ToSensitiveString();
+ NOTREACHED();
+ error_ = EINVAL;
+ return -1;
+ }
}
send_bytes_available_ -= data_size;
- in_flight_packet_sizes_.push_back(data_size);
- TraceSendThrottlingState();
const char* data_char = reinterpret_cast<const char*>(data);
std::vector<char> data_vector(data_char, data_char + data_size);
- client_->SendWithDscp(address_chrome, data_vector, options);
+ uint64_t packet_id = client_->Send(address_chrome, data_vector, options);
+
+ // Ensure packet_id is not 0. It can't be the case according to
+ // P2PSocketClientImpl::Send().
+ DCHECK_NE(packet_id, 0uL);
+
+ in_flight_packet_records_.push_back(
+ InFlightPacketRecord(packet_id, data_size));
+ TraceSendThrottlingState();
// Fake successful send. The caller ignores result anyway.
return data_size;
@@ -506,12 +556,14 @@ void IpcPacketSocket::OnOpen(const net::IPEndPoint& local_address,
// over the network.
if (remote_address_.IsUnresolvedIP()) {
rtc::SocketAddress jingle_socket_address;
- if (!jingle_glue::IPEndPointToSocketAddress(
- remote_address, &jingle_socket_address)) {
- NOTREACHED();
+ // |remote_address| could be unresolved if the connection is behind a
+ // proxy.
+ if (!remote_address.address().empty() &&
+ jingle_glue::IPEndPointToSocketAddress(
+ remote_address, &jingle_socket_address)) {
+ // Set only the IP address.
+ remote_address_.SetResolvedIP(jingle_socket_address.ipaddr());
}
- // Set only the IP address.
- remote_address_.SetResolvedIP(jingle_socket_address.ipaddr());
}
// SignalConnect after updating the |remote_address_| so that the listener
@@ -536,21 +588,29 @@ void IpcPacketSocket::OnIncomingTcpConnection(
SignalNewConnection(this, socket.release());
}
-void IpcPacketSocket::OnSendComplete() {
+void IpcPacketSocket::OnSendComplete(const P2PSendPacketMetrics& send_metrics) {
DCHECK_EQ(base::MessageLoop::current(), message_loop_);
- CHECK(!in_flight_packet_sizes_.empty());
- send_bytes_available_ += in_flight_packet_sizes_.front();
+ CHECK(!in_flight_packet_records_.empty());
+
+ const InFlightPacketRecord& record = in_flight_packet_records_.front();
+
+ // Tracking is not turned on for TCP so it's always 0. For UDP, this will
+ // cause a crash when the packet ids don't match.
+ CHECK(send_metrics.packet_id == 0 ||
+ record.packet_id == send_metrics.packet_id);
+
+ send_bytes_available_ += record.packet_size;
DCHECK_LE(send_bytes_available_, kMaximumInFlightBytes);
- in_flight_packet_sizes_.pop_front();
+ in_flight_packet_records_.pop_front();
TraceSendThrottlingState();
if (writable_signal_expected_ && send_bytes_available_ > 0) {
WebRtcLogMessage(base::StringPrintf(
"IpcPacketSocket: sending is unblocked. %d packets in flight.",
- static_cast<int>(in_flight_packet_sizes_.size())));
+ static_cast<int>(in_flight_packet_records_.size())));
SignalReadyToSend(this);
writable_signal_expected_ = false;
@@ -573,11 +633,18 @@ void IpcPacketSocket::OnDataReceived(const net::IPEndPoint& address,
DCHECK_EQ(base::MessageLoop::current(), message_loop_);
rtc::SocketAddress address_lj;
- if (!jingle_glue::IPEndPointToSocketAddress(address, &address_lj)) {
- // We should always be able to convert address here because we
- // don't expect IPv6 address on IPv4 connections.
- NOTREACHED();
- return;
+
+ if (address.address().empty()) {
+ DCHECK(IsTcpClientSocket(type_));
+ // |address| could be empty for TCP connections behind a proxy.
+ address_lj = remote_address_;
+ } else {
+ if (!jingle_glue::IPEndPointToSocketAddress(address, &address_lj)) {
+ // We should always be able to convert address here because we
+ // don't expect IPv6 address on IPv4 connections.
+ NOTREACHED();
+ return;
+ }
}
rtc::PacketTime packet_time(timestamp.ToInternalValue(), 0);
diff --git a/chromium/content/renderer/p2p/port_allocator.cc b/chromium/content/renderer/p2p/port_allocator.cc
index 7beb3ecc444..7a1abdc2166 100644
--- a/chromium/content/renderer/p2p/port_allocator.cc
+++ b/chromium/content/renderer/p2p/port_allocator.cc
@@ -4,6 +4,9 @@
#include "content/renderer/p2p/port_allocator.h"
+#include "base/command_line.h"
+#include "content/public/common/content_switches.h"
+
namespace content {
P2PPortAllocator::Config::Config()
@@ -24,15 +27,26 @@ P2PPortAllocator::P2PPortAllocator(
P2PSocketDispatcher* socket_dispatcher,
rtc::NetworkManager* network_manager,
rtc::PacketSocketFactory* socket_factory,
- const Config& config)
+ const Config& config,
+ const GURL& origin)
: cricket::BasicPortAllocator(network_manager, socket_factory),
socket_dispatcher_(socket_dispatcher),
- config_(config) {
+ config_(config),
+ origin_(origin)
+ {
uint32 flags = 0;
if (config_.disable_tcp_transport)
flags |= cricket::PORTALLOCATOR_DISABLE_TCP;
+ if (!config_.enable_multiple_routes)
+ flags |= cricket::PORTALLOCATOR_DISABLE_ADAPTER_ENUMERATION;
set_flags(flags);
set_allow_tcp_listen(false);
+ const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
+ bool enable_webrtc_stun_origin =
+ cmd_line->HasSwitch(switches::kEnableWebRtcStunOrigin);
+ if (enable_webrtc_stun_origin) {
+ set_origin(origin.spec());
+ }
}
P2PPortAllocator::~P2PPortAllocator() {
diff --git a/chromium/content/renderer/p2p/port_allocator.h b/chromium/content/renderer/p2p/port_allocator.h
index 3cb1377a1de..3d1ae5fa161 100644
--- a/chromium/content/renderer/p2p/port_allocator.h
+++ b/chromium/content/renderer/p2p/port_allocator.h
@@ -6,6 +6,7 @@
#define CONTENT_RENDERER_P2P_PORT_ALLOCATOR_H_
#include "third_party/webrtc/p2p/client/basicportallocator.h"
+#include "url/gurl.h"
namespace content {
@@ -36,12 +37,16 @@ class P2PPortAllocator : public cricket::BasicPortAllocator {
// Disable TCP-based transport when set to true.
bool disable_tcp_transport;
+
+ // Disable binding to individual NICs when set to false.
+ bool enable_multiple_routes;
};
P2PPortAllocator(P2PSocketDispatcher* socket_dispatcher,
rtc::NetworkManager* network_manager,
rtc::PacketSocketFactory* socket_factory,
- const Config& config);
+ const Config& config,
+ const GURL& origin);
~P2PPortAllocator() override;
cricket::PortAllocatorSession* CreateSessionInternal(
@@ -55,6 +60,7 @@ class P2PPortAllocator : public cricket::BasicPortAllocator {
P2PSocketDispatcher* socket_dispatcher_;
Config config_;
+ GURL origin_;
DISALLOW_COPY_AND_ASSIGN(P2PPortAllocator);
};
diff --git a/chromium/content/renderer/p2p/socket_client.h b/chromium/content/renderer/p2p/socket_client.h
index d92407cd5c9..a2cefdcc4c2 100644
--- a/chromium/content/renderer/p2p/socket_client.h
+++ b/chromium/content/renderer/p2p/socket_client.h
@@ -36,15 +36,11 @@ class P2PSocketClient : public base::RefCountedThreadSafe<P2PSocketClient> {
P2PSocketClient() {}
- // Send the |data| to the |address|.
- virtual void Send(const net::IPEndPoint& address,
- const std::vector<char>& data) = 0;
-
// Send the |data| to the |address| using Differentiated Services Code Point
- // |dscp|.
- virtual void SendWithDscp(const net::IPEndPoint& address,
- const std::vector<char>& data,
- const rtc::PacketOptions& options) = 0;
+ // |dscp|. Return value is the unique packet_id for this packet.
+ virtual uint64_t Send(const net::IPEndPoint& address,
+ const std::vector<char>& data,
+ const rtc::PacketOptions& options) = 0;
virtual void SetOption(P2PSocketOption option, int value) = 0;
diff --git a/chromium/content/renderer/p2p/socket_client_delegate.h b/chromium/content/renderer/p2p/socket_client_delegate.h
index 204d5cd4aab..4652bb7d15c 100644
--- a/chromium/content/renderer/p2p/socket_client_delegate.h
+++ b/chromium/content/renderer/p2p/socket_client_delegate.h
@@ -31,7 +31,7 @@ class P2PSocketClientDelegate {
P2PSocketClient* client) = 0;
// Called once for each Send() call after the send is complete.
- virtual void OnSendComplete() = 0;
+ virtual void OnSendComplete(const P2PSendPacketMetrics& send_metrics) = 0;
// Called if an non-retryable error occurs.
virtual void OnError() = 0;
diff --git a/chromium/content/renderer/p2p/socket_client_impl.cc b/chromium/content/renderer/p2p/socket_client_impl.cc
index 1425151089c..2dc0c7cbdeb 100644
--- a/chromium/content/renderer/p2p/socket_client_impl.cc
+++ b/chromium/content/renderer/p2p/socket_client_impl.cc
@@ -15,8 +15,8 @@
namespace {
-uint64 GetUniqueId(uint32 random_socket_id, uint32 packet_id) {
- uint64 uid = random_socket_id;
+uint64_t GetUniqueId(uint32 random_socket_id, uint32 packet_id) {
+ uint64_t uid = random_socket_id;
uid <<= 32;
uid |= packet_id;
return uid;
@@ -69,31 +69,33 @@ void P2PSocketClientImpl::DoInit(P2PSocketType type,
type, socket_id_, local_address, remote_address));
}
-void P2PSocketClientImpl::SendWithDscp(
- const net::IPEndPoint& address,
- const std::vector<char>& data,
- const rtc::PacketOptions& options) {
+uint64_t P2PSocketClientImpl::Send(const net::IPEndPoint& address,
+ const std::vector<char>& data,
+ const rtc::PacketOptions& options) {
+ uint64_t unique_id = GetUniqueId(random_socket_id_, ++next_packet_id_);
if (!ipc_message_loop_->BelongsToCurrentThread()) {
ipc_message_loop_->PostTask(
- FROM_HERE, base::Bind(
- &P2PSocketClientImpl::SendWithDscp, this, address, data, options));
- return;
+ FROM_HERE, base::Bind(&P2PSocketClientImpl::SendWithPacketId, this,
+ address, data, options, unique_id));
+ return unique_id;
}
// Can send data only when the socket is open.
DCHECK(state_ == STATE_OPEN || state_ == STATE_ERROR);
if (state_ == STATE_OPEN) {
- uint64 unique_id = GetUniqueId(random_socket_id_, ++next_packet_id_);
- TRACE_EVENT_ASYNC_BEGIN0("p2p", "Send", unique_id);
- dispatcher_->SendP2PMessage(new P2PHostMsg_Send(socket_id_, address, data,
- options, unique_id));
+ SendWithPacketId(address, data, options, unique_id);
}
+
+ return unique_id;
}
-void P2PSocketClientImpl::Send(const net::IPEndPoint& address,
- const std::vector<char>& data) {
- rtc::PacketOptions options(rtc::DSCP_DEFAULT);
- SendWithDscp(address, data, options);
+void P2PSocketClientImpl::SendWithPacketId(const net::IPEndPoint& address,
+ const std::vector<char>& data,
+ const rtc::PacketOptions& options,
+ uint64_t packet_id) {
+ TRACE_EVENT_ASYNC_BEGIN0("p2p", "Send", packet_id);
+ dispatcher_->SendP2PMessage(
+ new P2PHostMsg_Send(socket_id_, address, data, options, packet_id));
}
void P2PSocketClientImpl::SetOption(P2PSocketOption option,
@@ -196,17 +198,20 @@ void P2PSocketClientImpl::DeliverOnIncomingTcpConnection(
}
}
-void P2PSocketClientImpl::OnSendComplete() {
+void P2PSocketClientImpl::OnSendComplete(
+ const P2PSendPacketMetrics& send_metrics) {
DCHECK(ipc_message_loop_->BelongsToCurrentThread());
delegate_message_loop_->PostTask(
- FROM_HERE, base::Bind(&P2PSocketClientImpl::DeliverOnSendComplete, this));
+ FROM_HERE, base::Bind(&P2PSocketClientImpl::DeliverOnSendComplete, this,
+ send_metrics));
}
-void P2PSocketClientImpl::DeliverOnSendComplete() {
+void P2PSocketClientImpl::DeliverOnSendComplete(
+ const P2PSendPacketMetrics& send_metrics) {
DCHECK(delegate_message_loop_->BelongsToCurrentThread());
if (delegate_)
- delegate_->OnSendComplete();
+ delegate_->OnSendComplete(send_metrics);
}
void P2PSocketClientImpl::OnError() {
diff --git a/chromium/content/renderer/p2p/socket_client_impl.h b/chromium/content/renderer/p2p/socket_client_impl.h
index 4cda52ddb87..868f6121f83 100644
--- a/chromium/content/renderer/p2p/socket_client_impl.h
+++ b/chromium/content/renderer/p2p/socket_client_impl.h
@@ -39,15 +39,11 @@ class P2PSocketClientImpl : public P2PSocketClient {
const P2PHostAndIPEndPoint& remote_address,
P2PSocketClientDelegate* delegate);
- // Send the |data| to the |address|.
- void Send(const net::IPEndPoint& address,
- const std::vector<char>& data) override;
-
// Send the |data| to the |address| using Differentiated Services Code Point
- // |dscp|.
- void SendWithDscp(const net::IPEndPoint& address,
- const std::vector<char>& data,
- const rtc::PacketOptions& options) override;
+ // |dscp|. Return value is the unique packet_id for this packet.
+ uint64_t Send(const net::IPEndPoint& address,
+ const std::vector<char>& data,
+ const rtc::PacketOptions& options) override;
// Setting socket options.
void SetOption(P2PSocketOption option, int value) override;
@@ -77,8 +73,7 @@ class P2PSocketClientImpl : public P2PSocketClient {
void OnSocketCreated(const net::IPEndPoint& local_address,
const net::IPEndPoint& remote_address);
void OnIncomingTcpConnection(const net::IPEndPoint& address);
- void OnSendComplete(int packet_id);
- void OnSendComplete();
+ void OnSendComplete(const P2PSendPacketMetrics& send_metrics);
void OnError();
void OnDataReceived(const net::IPEndPoint& address,
const std::vector<char>& data,
@@ -90,12 +85,19 @@ class P2PSocketClientImpl : public P2PSocketClient {
void DeliverOnIncomingTcpConnection(
const net::IPEndPoint& address,
scoped_refptr<P2PSocketClient> new_client);
- void DeliverOnSendComplete();
+ void DeliverOnSendComplete(const P2PSendPacketMetrics& send_metrics);
void DeliverOnError();
void DeliverOnDataReceived(const net::IPEndPoint& address,
const std::vector<char>& data,
const base::TimeTicks& timestamp);
+ // Helper function to be called by Send to handle different threading
+ // condition.
+ void SendWithPacketId(const net::IPEndPoint& address,
+ const std::vector<char>& data,
+ const rtc::PacketOptions& options,
+ uint64_t packet_id);
+
// Scheduled on the IPC thread to finish initialization.
void DoInit(P2PSocketType type,
const net::IPEndPoint& local_address,
diff --git a/chromium/content/renderer/p2p/socket_dispatcher.cc b/chromium/content/renderer/p2p/socket_dispatcher.cc
index f189354478a..06f6b1e2b54 100644
--- a/chromium/content/renderer/p2p/socket_dispatcher.cc
+++ b/chromium/content/renderer/p2p/socket_dispatcher.cc
@@ -123,7 +123,7 @@ void P2PSocketDispatcher::UnregisterHostAddressRequest(int id) {
void P2PSocketDispatcher::OnNetworkListChanged(
const net::NetworkInterfaceList& networks) {
network_list_observers_->Notify(
- &NetworkListObserver::OnNetworkListChanged, networks);
+ FROM_HERE, &NetworkListObserver::OnNetworkListChanged, networks);
}
void P2PSocketDispatcher::OnGetHostAddressResult(
@@ -131,7 +131,7 @@ void P2PSocketDispatcher::OnGetHostAddressResult(
const net::IPAddressList& addresses) {
P2PAsyncAddressResolver* request = host_address_requests_.Lookup(request_id);
if (!request) {
- VLOG(1) << "Received P2P message for socket that doesn't exist.";
+ DVLOG(1) << "Received P2P message for socket that doesn't exist.";
return;
}
@@ -156,10 +156,12 @@ void P2PSocketDispatcher::OnIncomingTcpConnection(
}
}
-void P2PSocketDispatcher::OnSendComplete(int socket_id) {
+void P2PSocketDispatcher::OnSendComplete(
+ int socket_id,
+ const P2PSendPacketMetrics& send_metrics) {
P2PSocketClientImpl* client = GetClient(socket_id);
if (client) {
- client->OnSendComplete();
+ client->OnSendComplete(send_metrics);
}
}
@@ -186,7 +188,7 @@ P2PSocketClientImpl* P2PSocketDispatcher::GetClient(int socket_id) {
// This may happen if the socket was closed, but the browser side
// hasn't processed the close message by the time it sends the
// message to the renderer.
- VLOG(1) << "Received P2P message for socket that doesn't exist.";
+ DVLOG(1) << "Received P2P message for socket that doesn't exist.";
return NULL;
}
diff --git a/chromium/content/renderer/p2p/socket_dispatcher.h b/chromium/content/renderer/p2p/socket_dispatcher.h
index 69cb21f5359..0b180ec4e7d 100644
--- a/chromium/content/renderer/p2p/socket_dispatcher.h
+++ b/chromium/content/renderer/p2p/socket_dispatcher.h
@@ -96,7 +96,7 @@ class CONTENT_EXPORT P2PSocketDispatcher : public IPC::MessageFilter,
const net::IPEndPoint& local_address,
const net::IPEndPoint& remote_address);
void OnIncomingTcpConnection(int socket_id, const net::IPEndPoint& address);
- void OnSendComplete(int socket_id);
+ void OnSendComplete(int socket_id, const P2PSendPacketMetrics& send_metrics);
void OnError(int socket_id);
void OnDataReceived(int socket_id, const net::IPEndPoint& address,
const std::vector<char>& data,
diff --git a/chromium/content/renderer/pepper/DEPS b/chromium/content/renderer/pepper/DEPS
index 677f3096b40..0f254f5d483 100644
--- a/chromium/content/renderer/pepper/DEPS
+++ b/chromium/content/renderer/pepper/DEPS
@@ -6,6 +6,7 @@ include_rules = [
"+media/audio",
"+media/base",
"+media/video",
+ "+third_party/libvpx",
"+third_party/libyuv",
"+ui/base/ime",
"+ui/base/range",
diff --git a/chromium/content/renderer/pepper/audio_helper.cc b/chromium/content/renderer/pepper/audio_helper.cc
index ad6e8f87583..a9a9568a379 100644
--- a/chromium/content/renderer/pepper/audio_helper.cc
+++ b/chromium/content/renderer/pepper/audio_helper.cc
@@ -5,6 +5,7 @@
#include "content/renderer/pepper/audio_helper.h"
#include "base/logging.h"
+#include "content/common/pepper_file_util.h"
#include "ppapi/c/pp_completion_callback.h"
#include "ppapi/c/pp_errors.h"
@@ -20,13 +21,8 @@ AudioHelper::~AudioHelper() {}
int32_t AudioHelper::GetSyncSocketImpl(int* sync_socket) {
if (socket_for_create_callback_) {
-#if defined(OS_POSIX)
- *sync_socket = socket_for_create_callback_->handle();
-#elif defined(OS_WIN)
- *sync_socket = reinterpret_cast<int>(socket_for_create_callback_->handle());
-#else
-#error "Platform not supported."
-#endif
+ *sync_socket = IntegerFromSyncSocketHandle(
+ socket_for_create_callback_->handle());
return PP_OK;
}
return PP_ERROR_FAILED;
@@ -34,14 +30,8 @@ int32_t AudioHelper::GetSyncSocketImpl(int* sync_socket) {
int32_t AudioHelper::GetSharedMemoryImpl(int* shm_handle, uint32_t* shm_size) {
if (shared_memory_for_create_callback_) {
-#if defined(OS_POSIX)
- *shm_handle = shared_memory_for_create_callback_->handle().fd;
-#elif defined(OS_WIN)
- *shm_handle =
- reinterpret_cast<int>(shared_memory_for_create_callback_->handle());
-#else
-#error "Platform not supported."
-#endif
+ *shm_handle = reinterpret_cast<int>(PlatformFileFromSharedMemoryHandle(
+ shared_memory_for_create_callback_->handle()));
*shm_size = shared_memory_size_for_create_callback_;
return PP_OK;
}
diff --git a/chromium/content/renderer/pepper/content_decryptor_delegate.cc b/chromium/content/renderer/pepper/content_decryptor_delegate.cc
index ded599bf2f3..82f9894376b 100644
--- a/chromium/content/renderer/pepper/content_decryptor_delegate.cc
+++ b/chromium/content/renderer/pepper/content_decryptor_delegate.cc
@@ -5,20 +5,21 @@
#include "content/renderer/pepper/content_decryptor_delegate.h"
#include "base/callback_helpers.h"
-#include "base/debug/trace_event.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/metrics/sparse_histogram.h"
#include "base/numerics/safe_conversions.h"
-#include "content/renderer/media/crypto/key_systems.h"
+#include "base/stl_util.h"
+#include "base/trace_event/trace_event.h"
#include "content/renderer/pepper/ppb_buffer_impl.h"
#include "media/base/audio_buffer.h"
#include "media/base/audio_decoder_config.h"
#include "media/base/bind_to_current_loop.h"
-#include "media/base/cdm_promise.h"
+#include "media/base/cdm_key_information.h"
#include "media/base/channel_layout.h"
#include "media/base/data_buffer.h"
#include "media/base/decoder_buffer.h"
#include "media/base/decrypt_config.h"
+#include "media/base/key_systems.h"
#include "media/base/limits.h"
#include "media/base/video_decoder_config.h"
#include "media/base/video_frame.h"
@@ -30,11 +31,9 @@
#include "ppapi/shared_impl/var_tracker.h"
#include "ppapi/thunk/enter.h"
#include "ppapi/thunk/ppb_buffer_api.h"
-#include "ui/gfx/rect.h"
+#include "ui/gfx/geometry/rect.h"
-using media::CdmPromise;
using media::Decryptor;
-using media::KeyIdsPromise;
using media::MediaKeys;
using media::NewSessionCdmPromise;
using media::SimpleCdmPromise;
@@ -55,7 +54,7 @@ namespace {
// reference-count of 0. If |data| is NULL, sets |*resource| to NULL. Returns
// true upon success and false if any error happened.
bool MakeBufferResource(PP_Instance instance,
- const uint8* data,
+ const uint8_t* data,
uint32_t size,
scoped_refptr<PPB_Buffer_Impl>* resource) {
TRACE_EVENT0("media", "ContentDecryptorDelegate - MakeBufferResource");
@@ -85,7 +84,7 @@ bool MakeBufferResource(PP_Instance instance,
// Returns true if copy succeeded. Returns false if copy failed, e.g. if the
// |array_size| is smaller than the |str| length.
template <uint32_t array_size>
-bool CopyStringToArray(const std::string& str, uint8 (&array)[array_size]) {
+bool CopyStringToArray(const std::string& str, uint8_t(&array)[array_size]) {
if (array_size < str.size())
return false;
@@ -260,14 +259,32 @@ PP_SessionType MediaSessionTypeToPpSessionType(
switch (session_type) {
case MediaKeys::TEMPORARY_SESSION:
return PP_SESSIONTYPE_TEMPORARY;
- case MediaKeys::PERSISTENT_SESSION:
- return PP_SESSIONTYPE_PERSISTENT;
+ case MediaKeys::PERSISTENT_LICENSE_SESSION:
+ return PP_SESSIONTYPE_PERSISTENT_LICENSE;
+ case MediaKeys::PERSISTENT_RELEASE_MESSAGE_SESSION:
+ return PP_SESSIONTYPE_PERSISTENT_RELEASE;
default:
NOTREACHED();
return PP_SESSIONTYPE_TEMPORARY;
}
}
+PP_InitDataType MediaInitDataTypeToPpInitDataType(
+ media::EmeInitDataType init_data_type) {
+ switch (init_data_type) {
+ case media::EmeInitDataType::CENC:
+ return PP_INITDATATYPE_CENC;
+ case media::EmeInitDataType::KEYIDS:
+ return PP_INITDATATYPE_KEYIDS;
+ case media::EmeInitDataType::WEBM:
+ return PP_INITDATATYPE_WEBM;
+ case media::EmeInitDataType::UNKNOWN:
+ break;
+ }
+ NOTREACHED();
+ return PP_INITDATATYPE_KEYIDS;
+}
+
MediaKeys::Exception PpExceptionTypeToMediaException(
PP_CdmExceptionCode exception_code) {
switch (exception_code) {
@@ -291,13 +308,49 @@ MediaKeys::Exception PpExceptionTypeToMediaException(
}
}
+media::CdmKeyInformation::KeyStatus PpCdmKeyStatusToCdmKeyInformationKeyStatus(
+ PP_CdmKeyStatus status) {
+ switch (status) {
+ case PP_CDMKEYSTATUS_USABLE:
+ return media::CdmKeyInformation::USABLE;
+ case PP_CDMKEYSTATUS_INVALID:
+ return media::CdmKeyInformation::INTERNAL_ERROR;
+ case PP_CDMKEYSTATUS_EXPIRED:
+ return media::CdmKeyInformation::EXPIRED;
+ case PP_CDMKEYSTATUS_OUTPUTNOTALLOWED:
+ return media::CdmKeyInformation::OUTPUT_NOT_ALLOWED;
+ case PP_CDMKEYSTATUS_OUTPUTDOWNSCALED:
+ return media::CdmKeyInformation::OUTPUT_DOWNSCALED;
+ case PP_CDMKEYSTATUS_STATUSPENDING:
+ return media::CdmKeyInformation::KEY_STATUS_PENDING;
+ default:
+ NOTREACHED();
+ return media::CdmKeyInformation::INTERNAL_ERROR;
+ }
+}
+
+MediaKeys::MessageType PpCdmMessageTypeToMediaMessageType(
+ PP_CdmMessageType message_type) {
+ switch (message_type) {
+ case PP_CDMMESSAGETYPE_LICENSE_REQUEST:
+ return MediaKeys::LICENSE_REQUEST;
+ case PP_CDMMESSAGETYPE_LICENSE_RENEWAL:
+ return MediaKeys::LICENSE_RENEWAL;
+ case PP_CDMMESSAGETYPE_LICENSE_RELEASE:
+ return MediaKeys::LICENSE_RELEASE;
+ default:
+ NOTREACHED();
+ return MediaKeys::LICENSE_REQUEST;
+ }
+}
+
// TODO(xhwang): Unify EME UMA reporting code when prefixed EME is deprecated.
// See http://crbug.com/412987 for details.
-void ReportSystemCodeUMA(const std::string& key_system, uint32 system_code) {
+void ReportSystemCodeUMA(const std::string& key_system, uint32_t system_code) {
// Sparse histogram macro does not cache the histogram, so it's safe to use
// macro with non-static histogram name here.
UMA_HISTOGRAM_SPARSE_SLOWLY(
- "Media.EME." + KeySystemNameForUMA(key_system) + ".SystemCode",
+ "Media.EME." + media::GetKeySystemNameForUMA(key_system) + ".SystemCode",
system_code);
}
@@ -312,7 +365,6 @@ ContentDecryptorDelegate::ContentDecryptorDelegate(
audio_samples_per_second_(0),
audio_channel_count_(0),
audio_channel_layout_(media::CHANNEL_LAYOUT_NONE),
- next_promise_id_(1),
weak_ptr_factory_(this) {
weak_this_ = weak_ptr_factory_.GetWeakPtr();
}
@@ -323,27 +375,31 @@ ContentDecryptorDelegate::~ContentDecryptorDelegate() {
void ContentDecryptorDelegate::Initialize(
const std::string& key_system,
+ bool allow_distinctive_identifier,
+ bool allow_persistent_state,
const media::SessionMessageCB& session_message_cb,
- const media::SessionReadyCB& session_ready_cb,
const media::SessionClosedCB& session_closed_cb,
- const media::SessionErrorCB& session_error_cb,
+ const media::LegacySessionErrorCB& legacy_session_error_cb,
const media::SessionKeysChangeCB& session_keys_change_cb,
const media::SessionExpirationUpdateCB& session_expiration_update_cb,
- const base::Closure& fatal_plugin_error_cb) {
+ const base::Closure& fatal_plugin_error_cb,
+ scoped_ptr<media::SimpleCdmPromise> promise) {
DCHECK(!key_system.empty());
DCHECK(key_system_.empty());
key_system_ = key_system;
session_message_cb_ = session_message_cb;
- session_ready_cb_ = session_ready_cb;
session_closed_cb_ = session_closed_cb;
- session_error_cb_ = session_error_cb;
+ legacy_session_error_cb_ = legacy_session_error_cb;
session_keys_change_cb_ = session_keys_change_cb;
session_expiration_update_cb_ = session_expiration_update_cb;
fatal_plugin_error_cb_ = fatal_plugin_error_cb;
+ uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
plugin_decryption_interface_->Initialize(
- pp_instance_, StringVar::StringToPPVar(key_system_));
+ pp_instance_, promise_id, StringVar::StringToPPVar(key_system_),
+ PP_FromBool(allow_distinctive_identifier),
+ PP_FromBool(allow_persistent_state));
}
void ContentDecryptorDelegate::InstanceCrashed() {
@@ -352,107 +408,89 @@ void ContentDecryptorDelegate::InstanceCrashed() {
}
void ContentDecryptorDelegate::SetServerCertificate(
- const uint8_t* certificate,
- uint32_t certificate_length,
+ const std::vector<uint8_t>& certificate,
scoped_ptr<media::SimpleCdmPromise> promise) {
- if (!certificate ||
- certificate_length < media::limits::kMinCertificateLength ||
- certificate_length > media::limits::kMaxCertificateLength) {
+ if (certificate.size() < media::limits::kMinCertificateLength ||
+ certificate.size() > media::limits::kMaxCertificateLength) {
promise->reject(
media::MediaKeys::INVALID_ACCESS_ERROR, 0, "Incorrect certificate.");
return;
}
- uint32_t promise_id = SavePromise(promise.Pass());
+ uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
PP_Var certificate_array =
PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
- certificate_length, certificate);
+ base::checked_cast<uint32>(certificate.size()),
+ vector_as_array(&certificate));
plugin_decryption_interface_->SetServerCertificate(
pp_instance_, promise_id, certificate_array);
}
-void ContentDecryptorDelegate::CreateSession(
- const std::string& init_data_type,
- const uint8* init_data,
- int init_data_length,
+void ContentDecryptorDelegate::CreateSessionAndGenerateRequest(
MediaKeys::SessionType session_type,
+ media::EmeInitDataType init_data_type,
+ const std::vector<uint8_t>& init_data,
scoped_ptr<NewSessionCdmPromise> promise) {
- uint32_t promise_id = SavePromise(promise.Pass());
+ uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
PP_Var init_data_array =
PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
- init_data_length, init_data);
- plugin_decryption_interface_->CreateSession(
- pp_instance_,
- promise_id,
- StringVar::StringToPPVar(init_data_type),
- init_data_array,
- MediaSessionTypeToPpSessionType(session_type));
+ base::checked_cast<uint32>(init_data.size()),
+ vector_as_array(&init_data));
+ plugin_decryption_interface_->CreateSessionAndGenerateRequest(
+ pp_instance_, promise_id, MediaSessionTypeToPpSessionType(session_type),
+ MediaInitDataTypeToPpInitDataType(init_data_type), init_data_array);
}
void ContentDecryptorDelegate::LoadSession(
- const std::string& web_session_id,
+ media::MediaKeys::SessionType session_type,
+ const std::string& session_id,
scoped_ptr<NewSessionCdmPromise> promise) {
- uint32_t promise_id = SavePromise(promise.Pass());
+ uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
plugin_decryption_interface_->LoadSession(
- pp_instance_, promise_id, StringVar::StringToPPVar(web_session_id));
+ pp_instance_, promise_id, MediaSessionTypeToPpSessionType(session_type),
+ StringVar::StringToPPVar(session_id));
}
void ContentDecryptorDelegate::UpdateSession(
- const std::string& web_session_id,
- const uint8* response,
- int response_length,
+ const std::string& session_id,
+ const std::vector<uint8_t>& response,
scoped_ptr<SimpleCdmPromise> promise) {
- uint32_t promise_id = SavePromise(promise.Pass());
+ uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
PP_Var response_array =
PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
- response_length, response);
+ base::checked_cast<uint32>(response.size()),
+ vector_as_array(&response));
plugin_decryption_interface_->UpdateSession(
- pp_instance_,
- promise_id,
- StringVar::StringToPPVar(web_session_id),
+ pp_instance_, promise_id, StringVar::StringToPPVar(session_id),
response_array);
}
void ContentDecryptorDelegate::CloseSession(
- const std::string& web_session_id,
+ const std::string& session_id,
scoped_ptr<SimpleCdmPromise> promise) {
- if (web_session_id.length() > media::limits::kMaxWebSessionIdLength) {
+ if (session_id.length() > media::limits::kMaxSessionIdLength) {
promise->reject(
media::MediaKeys::INVALID_ACCESS_ERROR, 0, "Incorrect session.");
return;
}
- uint32_t promise_id = SavePromise(promise.Pass());
+ uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
plugin_decryption_interface_->CloseSession(
- pp_instance_, promise_id, StringVar::StringToPPVar(web_session_id));
+ pp_instance_, promise_id, StringVar::StringToPPVar(session_id));
}
void ContentDecryptorDelegate::RemoveSession(
- const std::string& web_session_id,
+ const std::string& session_id,
scoped_ptr<SimpleCdmPromise> promise) {
- if (web_session_id.length() > media::limits::kMaxWebSessionIdLength) {
+ if (session_id.length() > media::limits::kMaxSessionIdLength) {
promise->reject(
media::MediaKeys::INVALID_ACCESS_ERROR, 0, "Incorrect session.");
return;
}
- uint32_t promise_id = SavePromise(promise.Pass());
+ uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
plugin_decryption_interface_->RemoveSession(
- pp_instance_, promise_id, StringVar::StringToPPVar(web_session_id));
-}
-
-void ContentDecryptorDelegate::GetUsableKeyIds(
- const std::string& web_session_id,
- scoped_ptr<media::KeyIdsPromise> promise) {
- if (web_session_id.length() > media::limits::kMaxWebSessionIdLength) {
- promise->reject(
- media::MediaKeys::INVALID_ACCESS_ERROR, 0, "Incorrect session.");
- return;
- }
-
- uint32_t promise_id = SavePromise(promise.Pass());
- plugin_decryption_interface_->GetUsableKeyIds(
- pp_instance_, promise_id, StringVar::StringToPPVar(web_session_id));
+ pp_instance_, promise_id, StringVar::StringToPPVar(session_id));
}
// TODO(xhwang): Remove duplication of code in Decrypt(),
@@ -698,189 +736,138 @@ bool ContentDecryptorDelegate::DecryptAndDecodeVideo(
return true;
}
-void ContentDecryptorDelegate::OnPromiseResolved(uint32 promise_id) {
- scoped_ptr<CdmPromise> promise = TakePromise(promise_id);
- if (!promise ||
- promise->GetResolveParameterType() != media::CdmPromise::VOID_TYPE) {
- NOTREACHED();
- return;
- }
-
- SimpleCdmPromise* simple_promise =
- static_cast<SimpleCdmPromise*>(promise.get());
- simple_promise->resolve();
-}
-
-void ContentDecryptorDelegate::OnPromiseResolvedWithSession(
- uint32 promise_id,
- PP_Var web_session_id) {
- scoped_ptr<CdmPromise> promise = TakePromise(promise_id);
- if (!promise ||
- promise->GetResolveParameterType() != media::CdmPromise::STRING_TYPE) {
- NOTREACHED();
- return;
- }
-
- StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
- DCHECK(web_session_id_string);
-
- NewSessionCdmPromise* session_promise =
- static_cast<NewSessionCdmPromise*>(promise.get());
- session_promise->resolve(web_session_id_string->value());
+void ContentDecryptorDelegate::OnPromiseResolved(uint32_t promise_id) {
+ cdm_promise_adapter_.ResolvePromise(promise_id);
}
-void ContentDecryptorDelegate::OnPromiseResolvedWithKeyIds(
- uint32 promise_id,
- PP_Var key_ids_array) {
- scoped_ptr<CdmPromise> promise = TakePromise(promise_id);
-
- ArrayVar* key_ids = ArrayVar::FromPPVar(key_ids_array);
- DCHECK(key_ids && key_ids->GetLength() <= media::limits::kMaxKeyIds);
- media::KeyIdsVector key_ids_vector;
- if (key_ids && key_ids->GetLength() <= media::limits::kMaxKeyIds) {
- for (size_t i = 0; i < key_ids->GetLength(); ++i) {
- ArrayBufferVar* array_buffer = ArrayBufferVar::FromPPVar(key_ids->Get(i));
-
- if (!array_buffer ||
- array_buffer->ByteLength() < media::limits::kMinKeyIdLength ||
- array_buffer->ByteLength() > media::limits::kMaxKeyIdLength) {
- NOTREACHED();
- continue;
- }
-
- std::vector<uint8> key_id;
- const uint8* data = static_cast<const uint8*>(array_buffer->Map());
- key_id.assign(data, data + array_buffer->ByteLength());
- key_ids_vector.push_back(key_id);
- }
- }
-
- if (!promise ||
- promise->GetResolveParameterType() !=
- media::CdmPromise::KEY_IDS_VECTOR_TYPE) {
- NOTREACHED();
- return;
- }
-
- KeyIdsPromise* key_ids_promise(static_cast<KeyIdsPromise*>(promise.get()));
- key_ids_promise->resolve(key_ids_vector);
+void ContentDecryptorDelegate::OnPromiseResolvedWithSession(uint32_t promise_id,
+ PP_Var session_id) {
+ StringVar* session_id_string = StringVar::FromPPVar(session_id);
+ DCHECK(session_id_string);
+ cdm_promise_adapter_.ResolvePromise(promise_id, session_id_string->value());
}
void ContentDecryptorDelegate::OnPromiseRejected(
- uint32 promise_id,
+ uint32_t promise_id,
PP_CdmExceptionCode exception_code,
- uint32 system_code,
+ uint32_t system_code,
PP_Var error_description) {
ReportSystemCodeUMA(key_system_, system_code);
StringVar* error_description_string = StringVar::FromPPVar(error_description);
DCHECK(error_description_string);
-
- scoped_ptr<CdmPromise> promise = TakePromise(promise_id);
- DCHECK(promise);
- if (promise) {
- promise->reject(PpExceptionTypeToMediaException(exception_code),
- system_code,
- error_description_string->value());
- }
+ cdm_promise_adapter_.RejectPromise(
+ promise_id, PpExceptionTypeToMediaException(exception_code), system_code,
+ error_description_string->value());
}
-void ContentDecryptorDelegate::OnSessionMessage(PP_Var web_session_id,
+void ContentDecryptorDelegate::OnSessionMessage(PP_Var session_id,
+ PP_CdmMessageType message_type,
PP_Var message,
- PP_Var destination_url) {
+ PP_Var legacy_destination_url) {
if (session_message_cb_.is_null())
return;
- StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
- DCHECK(web_session_id_string);
+ StringVar* session_id_string = StringVar::FromPPVar(session_id);
+ DCHECK(session_id_string);
ArrayBufferVar* message_array_buffer = ArrayBufferVar::FromPPVar(message);
- std::vector<uint8> message_vector;
+ std::vector<uint8_t> message_vector;
if (message_array_buffer) {
- const uint8* data = static_cast<const uint8*>(message_array_buffer->Map());
+ const uint8_t* data =
+ static_cast<const uint8_t*>(message_array_buffer->Map());
message_vector.assign(data, data + message_array_buffer->ByteLength());
}
- StringVar* destination_url_string = StringVar::FromPPVar(destination_url);
- DCHECK(destination_url_string);
+ StringVar* destination_url_string =
+ StringVar::FromPPVar(legacy_destination_url);
+ if (!destination_url_string) {
+ NOTREACHED();
+ return;
+ }
GURL verified_gurl = GURL(destination_url_string->value());
- if (!verified_gurl.is_valid() && !verified_gurl.is_empty()) {
- DLOG(WARNING) << "SessionMessage default_url is invalid : "
+ if (!verified_gurl.is_valid()) {
+ DLOG(WARNING) << "SessionMessage legacy_destination_url is invalid : "
<< verified_gurl.possibly_invalid_spec();
verified_gurl = GURL::EmptyGURL(); // Replace invalid destination_url.
}
- session_message_cb_.Run(
- web_session_id_string->value(), message_vector, verified_gurl);
+ session_message_cb_.Run(session_id_string->value(),
+ PpCdmMessageTypeToMediaMessageType(message_type),
+ message_vector, verified_gurl);
}
void ContentDecryptorDelegate::OnSessionKeysChange(
- PP_Var web_session_id,
- PP_Bool has_additional_usable_key) {
+ PP_Var session_id,
+ PP_Bool has_additional_usable_key,
+ uint32_t key_count,
+ const struct PP_KeyInformation key_information[]) {
if (session_keys_change_cb_.is_null())
return;
- StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
- DCHECK(web_session_id_string);
+ StringVar* session_id_string = StringVar::FromPPVar(session_id);
+ DCHECK(session_id_string);
+
+ media::CdmKeysInfo keys_info;
+ keys_info.reserve(key_count);
+ for (uint32_t i = 0; i < key_count; ++i) {
+ scoped_ptr<media::CdmKeyInformation> key_info(new media::CdmKeyInformation);
+ const auto& info = key_information[i];
+ key_info->key_id.assign(info.key_id, info.key_id + info.key_id_size);
+ key_info->status =
+ PpCdmKeyStatusToCdmKeyInformationKeyStatus(info.key_status);
+ key_info->system_code = info.system_code;
+ keys_info.push_back(key_info.release());
+ }
- session_keys_change_cb_.Run(web_session_id_string->value(),
- PP_ToBool(has_additional_usable_key));
+ session_keys_change_cb_.Run(session_id_string->value(),
+ PP_ToBool(has_additional_usable_key),
+ keys_info.Pass());
}
void ContentDecryptorDelegate::OnSessionExpirationChange(
- PP_Var web_session_id,
+ PP_Var session_id,
PP_Time new_expiry_time) {
if (session_expiration_update_cb_.is_null())
return;
- StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
- DCHECK(web_session_id_string);
+ StringVar* session_id_string = StringVar::FromPPVar(session_id);
+ DCHECK(session_id_string);
- session_expiration_update_cb_.Run(web_session_id_string->value(),
+ session_expiration_update_cb_.Run(session_id_string->value(),
ppapi::PPTimeToTime(new_expiry_time));
}
-void ContentDecryptorDelegate::OnSessionReady(PP_Var web_session_id) {
- if (session_ready_cb_.is_null())
- return;
-
- StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
- DCHECK(web_session_id_string);
-
- session_ready_cb_.Run(web_session_id_string->value());
-}
-
-void ContentDecryptorDelegate::OnSessionClosed(PP_Var web_session_id) {
+void ContentDecryptorDelegate::OnSessionClosed(PP_Var session_id) {
if (session_closed_cb_.is_null())
return;
- StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
- DCHECK(web_session_id_string);
+ StringVar* session_id_string = StringVar::FromPPVar(session_id);
+ DCHECK(session_id_string);
- session_closed_cb_.Run(web_session_id_string->value());
+ session_closed_cb_.Run(session_id_string->value());
}
-void ContentDecryptorDelegate::OnSessionError(
- PP_Var web_session_id,
+void ContentDecryptorDelegate::OnLegacySessionError(
+ PP_Var session_id,
PP_CdmExceptionCode exception_code,
- uint32 system_code,
+ uint32_t system_code,
PP_Var error_description) {
ReportSystemCodeUMA(key_system_, system_code);
- if (session_error_cb_.is_null())
+ if (legacy_session_error_cb_.is_null())
return;
- StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
- DCHECK(web_session_id_string);
+ StringVar* session_id_string = StringVar::FromPPVar(session_id);
+ DCHECK(session_id_string);
StringVar* error_description_string = StringVar::FromPPVar(error_description);
DCHECK(error_description_string);
- session_error_cb_.Run(web_session_id_string->value(),
- PpExceptionTypeToMediaException(exception_code),
- system_code,
- error_description_string->value());
+ legacy_session_error_cb_.Run(session_id_string->value(),
+ PpExceptionTypeToMediaException(exception_code),
+ system_code, error_description_string->value());
}
void ContentDecryptorDelegate::DecoderInitializeDone(
@@ -965,7 +952,7 @@ void ContentDecryptorDelegate::DeliverBlock(
// TODO(tomfinegan): Find a way to take ownership of the shared memory
// managed by the PPB_Buffer_Dev, and avoid the extra copy.
scoped_refptr<media::DecoderBuffer> decrypted_buffer(
- media::DecoderBuffer::CopyFrom(static_cast<uint8*>(mapper.data()),
+ media::DecoderBuffer::CopyFrom(static_cast<uint8_t*>(mapper.data()),
block_info->data_size));
decrypted_buffer->set_timestamp(
base::TimeDelta::FromMicroseconds(block_info->tracking_info.timestamp));
@@ -984,13 +971,13 @@ static void BufferNoLongerNeeded(
// Enters |resource|, maps shared memory and returns pointer of mapped data.
// Returns NULL if any error occurs.
-static uint8* GetMappedBuffer(PP_Resource resource,
- scoped_refptr<PPB_Buffer_Impl>* ppb_buffer) {
+static uint8_t* GetMappedBuffer(PP_Resource resource,
+ scoped_refptr<PPB_Buffer_Impl>* ppb_buffer) {
EnterResourceNoLock<PPB_Buffer_API> enter(resource, true);
if (!enter.succeeded())
return NULL;
- uint8* mapped_data = static_cast<uint8*>(enter.object()->Map());
+ uint8_t* mapped_data = static_cast<uint8_t*>(enter.object()->Map());
if (!enter.object()->IsMapped() || !mapped_data)
return NULL;
@@ -1034,7 +1021,7 @@ void ContentDecryptorDelegate::DeliverFrame(
}
scoped_refptr<PPB_Buffer_Impl> ppb_buffer;
- uint8* frame_data = GetMappedBuffer(decrypted_frame, &ppb_buffer);
+ uint8_t* frame_data = GetMappedBuffer(decrypted_frame, &ppb_buffer);
if (!frame_data) {
FreeBuffer(frame_info->tracking_info.buffer_id);
video_decode_cb.Run(Decryptor::kError, NULL);
@@ -1086,7 +1073,7 @@ void ContentDecryptorDelegate::DeliverSamples(
Decryptor::AudioDecodeCB audio_decode_cb = audio_decode_cb_.ResetAndReturn();
- const Decryptor::AudioBuffers empty_frames;
+ const Decryptor::AudioFrames empty_frames;
Decryptor::Status status =
PpDecryptResultToMediaDecryptorStatus(sample_info->result);
@@ -1098,7 +1085,7 @@ void ContentDecryptorDelegate::DeliverSamples(
media::SampleFormat sample_format =
PpDecryptedSampleFormatToMediaSampleFormat(sample_info->format);
- Decryptor::AudioBuffers audio_frame_list;
+ Decryptor::AudioFrames audio_frame_list;
if (!DeserializeAudioFrames(audio_frames,
sample_info->data_size,
sample_format,
@@ -1121,7 +1108,7 @@ void ContentDecryptorDelegate::CancelDecode(Decryptor::StreamType stream_type) {
audio_input_resource_ = NULL;
if (!audio_decode_cb_.is_null())
audio_decode_cb_.ResetAndReturn().Run(Decryptor::kSuccess,
- Decryptor::AudioBuffers());
+ Decryptor::AudioFrames());
break;
case Decryptor::kVideo:
// Release the shared memory as it can still be in use by the plugin.
@@ -1210,7 +1197,7 @@ bool ContentDecryptorDelegate::DeserializeAudioFrames(
PP_Resource audio_frames,
size_t data_size,
media::SampleFormat sample_format,
- Decryptor::AudioBuffers* frames) {
+ Decryptor::AudioFrames* frames) {
DCHECK(frames);
EnterResourceNoLock<PPB_Buffer_API> enter(audio_frames, true);
if (!enter.succeeded())
@@ -1224,7 +1211,7 @@ bool ContentDecryptorDelegate::DeserializeAudioFrames(
// TODO(jrummell): Pass ownership of data() directly to AudioBuffer to avoid
// the copy. Since it is possible to get multiple buffers, it would need to be
// sliced and ref counted appropriately. http://crbug.com/255576.
- const uint8* cur = static_cast<uint8*>(mapper.data());
+ const uint8_t* cur = static_cast<uint8_t*>(mapper.data());
size_t bytes_left = data_size;
const int audio_bytes_per_frame =
@@ -1234,8 +1221,7 @@ bool ContentDecryptorDelegate::DeserializeAudioFrames(
return false;
// Allocate space for the channel pointers given to AudioBuffer.
- std::vector<const uint8*> channel_ptrs(audio_channel_count_,
- static_cast<const uint8*>(NULL));
+ std::vector<const uint8_t*> channel_ptrs(audio_channel_count_, nullptr);
do {
int64 timestamp = 0;
int64 frame_size = -1;
@@ -1299,7 +1285,7 @@ void ContentDecryptorDelegate::SatisfyAllPendingCallbacksOnError() {
video_decrypt_cb_.ResetAndReturn().Run(media::Decryptor::kError, NULL);
if (!audio_decode_cb_.is_null()) {
- const media::Decryptor::AudioBuffers empty_frames;
+ const media::Decryptor::AudioFrames empty_frames;
audio_decode_cb_.ResetAndReturn().Run(media::Decryptor::kError,
empty_frames);
}
@@ -1307,27 +1293,7 @@ void ContentDecryptorDelegate::SatisfyAllPendingCallbacksOnError() {
if (!video_decode_cb_.is_null())
video_decode_cb_.ResetAndReturn().Run(media::Decryptor::kError, NULL);
- // Reject all outstanding promises.
- for (PromiseMap::iterator it = promises_.begin(); it != promises_.end();
- ++it) {
- it->second->reject(
- media::MediaKeys::UNKNOWN_ERROR, 0, "Failure calling plugin.");
- }
- promises_.clear();
-}
-
-uint32_t ContentDecryptorDelegate::SavePromise(scoped_ptr<CdmPromise> promise) {
- uint32_t promise_id = next_promise_id_++;
- promises_.add(promise_id, promise.Pass());
- return promise_id;
-}
-
-scoped_ptr<CdmPromise> ContentDecryptorDelegate::TakePromise(
- uint32_t promise_id) {
- PromiseMap::iterator it = promises_.find(promise_id);
- if (it == promises_.end())
- return scoped_ptr<CdmPromise>();
- return promises_.take_and_erase(it);
+ cdm_promise_adapter_.Clear();
}
} // namespace content
diff --git a/chromium/content/renderer/pepper/content_decryptor_delegate.h b/chromium/content/renderer/pepper/content_decryptor_delegate.h
index 5fb3fb233b3..09b0917cbfd 100644
--- a/chromium/content/renderer/pepper/content_decryptor_delegate.h
+++ b/chromium/content/renderer/pepper/content_decryptor_delegate.h
@@ -8,14 +8,15 @@
#include <map>
#include <queue>
#include <string>
+#include <vector>
#include "base/basictypes.h"
#include "base/callback_helpers.h"
#include "base/compiler_specific.h"
-#include "base/containers/scoped_ptr_hash_map.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "media/base/cdm_promise.h"
+#include "media/base/cdm_promise_adapter.h"
#include "media/base/channel_layout.h"
#include "media/base/decryptor.h"
#include "media/base/media_keys.h"
@@ -23,7 +24,7 @@
#include "ppapi/c/pp_time.h"
#include "ppapi/c/private/pp_content_decryptor.h"
#include "ppapi/c/private/ppp_content_decryptor_private.h"
-#include "ui/gfx/size.h"
+#include "ui/gfx/geometry/size.h"
namespace media {
class AudioDecoderConfig;
@@ -48,37 +49,36 @@ class ContentDecryptorDelegate {
// This object should not be accessed after |fatal_plugin_error_cb| is called.
void Initialize(
const std::string& key_system,
+ bool allow_distinctive_identifier,
+ bool allow_persistent_state,
const media::SessionMessageCB& session_message_cb,
- const media::SessionReadyCB& session_ready_cb,
const media::SessionClosedCB& session_closed_cb,
- const media::SessionErrorCB& session_error_cb,
+ const media::LegacySessionErrorCB& legacy_session_error_cb,
const media::SessionKeysChangeCB& session_keys_change_cb,
const media::SessionExpirationUpdateCB& session_expiration_update_cb,
- const base::Closure& fatal_plugin_error_cb);
+ const base::Closure& fatal_plugin_error_cb,
+ scoped_ptr<media::SimpleCdmPromise> promise);
void InstanceCrashed();
// Provides access to PPP_ContentDecryptor_Private.
- void SetServerCertificate(const uint8_t* certificate,
- uint32_t certificate_length,
+ void SetServerCertificate(const std::vector<uint8_t>& certificate,
scoped_ptr<media::SimpleCdmPromise> promise);
- void CreateSession(const std::string& init_data_type,
- const uint8* init_data,
- int init_data_length,
- media::MediaKeys::SessionType session_type,
- scoped_ptr<media::NewSessionCdmPromise> promise);
- void LoadSession(const std::string& web_session_id,
+ void CreateSessionAndGenerateRequest(
+ media::MediaKeys::SessionType session_type,
+ media::EmeInitDataType init_data_type,
+ const std::vector<uint8_t>& init_data,
+ scoped_ptr<media::NewSessionCdmPromise> promise);
+ void LoadSession(media::MediaKeys::SessionType session_type,
+ const std::string& session_id,
scoped_ptr<media::NewSessionCdmPromise> promise);
- void UpdateSession(const std::string& web_session_id,
- const uint8* response,
- int response_length,
+ void UpdateSession(const std::string& session_id,
+ const std::vector<uint8_t>& response,
scoped_ptr<media::SimpleCdmPromise> promise);
- void CloseSession(const std::string& web_session_id,
+ void CloseSession(const std::string& session_id,
scoped_ptr<media::SimpleCdmPromise> promise);
- void RemoveSession(const std::string& web_session_id,
+ void RemoveSession(const std::string& session_id,
scoped_ptr<media::SimpleCdmPromise> promise);
- void GetUsableKeyIds(const std::string& web_session_id,
- scoped_ptr<media::KeyIdsPromise> promise);
bool Decrypt(media::Decryptor::StreamType stream_type,
const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
const media::Decryptor::DecryptCB& decrypt_cb);
@@ -102,26 +102,26 @@ class ContentDecryptorDelegate {
const media::Decryptor::VideoDecodeCB& video_decode_cb);
// PPB_ContentDecryptor_Private dispatching methods.
- void OnPromiseResolved(uint32 promise_id);
- void OnPromiseResolvedWithSession(uint32 promise_id, PP_Var web_session_id);
- void OnPromiseResolvedWithKeyIds(uint32 promise_id, PP_Var key_ids_array);
- void OnPromiseRejected(uint32 promise_id,
+ void OnPromiseResolved(uint32_t promise_id);
+ void OnPromiseResolvedWithSession(uint32_t promise_id, PP_Var session_id);
+ void OnPromiseRejected(uint32_t promise_id,
PP_CdmExceptionCode exception_code,
- uint32 system_code,
+ uint32_t system_code,
PP_Var error_description);
- void OnSessionMessage(PP_Var web_session_id,
+ void OnSessionMessage(PP_Var session_id,
+ PP_CdmMessageType message_type,
PP_Var message,
- PP_Var destination_url);
- void OnSessionKeysChange(PP_Var web_session_id,
- PP_Bool has_additional_usable_key);
- void OnSessionExpirationChange(PP_Var web_session_id,
- PP_Time new_expiry_time);
- void OnSessionReady(PP_Var web_session_id);
- void OnSessionClosed(PP_Var web_session_id);
- void OnSessionError(PP_Var web_session_id,
- PP_CdmExceptionCode exception_code,
- uint32 system_code,
- PP_Var error_description);
+ PP_Var legacy_destination_url);
+ void OnSessionKeysChange(PP_Var session_id,
+ PP_Bool has_additional_usable_key,
+ uint32_t key_count,
+ const struct PP_KeyInformation key_information[]);
+ void OnSessionExpirationChange(PP_Var session_id, PP_Time new_expiry_time);
+ void OnSessionClosed(PP_Var session_id);
+ void OnLegacySessionError(PP_Var session_id,
+ PP_CdmExceptionCode exception_code,
+ uint32_t system_code,
+ PP_Var error_description);
void DeliverBlock(PP_Resource decrypted_block,
const PP_DecryptedBlockInfo* block_info);
void DecoderInitializeDone(PP_DecryptorStreamType decoder_type,
@@ -137,10 +137,6 @@ class ContentDecryptorDelegate {
const PP_DecryptedSampleInfo* sample_info);
private:
- // The following types keep track of Promises. The index is the promise_id,
- // so that returning results can be matched to the corresponding promise.
- typedef base::ScopedPtrHashMap<uint32_t, media::CdmPromise> PromiseMap;
-
template <typename Callback>
class TrackableCallback {
public:
@@ -199,18 +195,10 @@ class ContentDecryptorDelegate {
bool DeserializeAudioFrames(PP_Resource audio_frames,
size_t data_size,
media::SampleFormat sample_format,
- media::Decryptor::AudioBuffers* frames);
+ media::Decryptor::AudioFrames* frames);
void SatisfyAllPendingCallbacksOnError();
- // Takes ownership of |promise| and returns an identifier to be passed via
- // Pepper.
- uint32_t SavePromise(scoped_ptr<media::CdmPromise> promise);
-
- // Find the promise for a specified |promise_id|. Caller is responsible to
- // delete the CdmPromise<> once done with it.
- scoped_ptr<media::CdmPromise> TakePromise(uint32_t promise_id);
-
const PP_Instance pp_instance_;
const PPP_ContentDecryptor_Private* const plugin_decryption_interface_;
@@ -219,9 +207,8 @@ class ContentDecryptorDelegate {
// Callbacks for firing session events.
media::SessionMessageCB session_message_cb_;
- media::SessionReadyCB session_ready_cb_;
media::SessionClosedCB session_closed_cb_;
- media::SessionErrorCB session_error_cb_;
+ media::LegacySessionErrorCB legacy_session_error_cb_;
media::SessionKeysChangeCB session_keys_change_cb_;
media::SessionExpirationUpdateCB session_expiration_update_cb_;
@@ -255,9 +242,7 @@ class ContentDecryptorDelegate {
int audio_channel_count_;
media::ChannelLayout audio_channel_layout_;
- // Keep track of outstanding promises. Maps have ownership of the promises.
- uint32_t next_promise_id_;
- PromiseMap promises_;
+ media::CdmPromiseAdapter cdm_promise_adapter_;
base::WeakPtr<ContentDecryptorDelegate> weak_this_;
base::WeakPtrFactory<ContentDecryptorDelegate> weak_ptr_factory_;
diff --git a/chromium/content/renderer/pepper/content_renderer_pepper_host_factory.cc b/chromium/content/renderer/pepper/content_renderer_pepper_host_factory.cc
index 93306eb5865..0187d7d0f46 100644
--- a/chromium/content/renderer/pepper/content_renderer_pepper_host_factory.cc
+++ b/chromium/content/renderer/pepper/content_renderer_pepper_host_factory.cc
@@ -6,9 +6,11 @@
#include "base/logging.h"
#include "base/strings/string_util.h"
+#include "content/common/content_switches_internal.h"
#include "content/public/common/content_client.h"
#include "content/public/renderer/content_renderer_client.h"
#include "content/renderer/pepper/pepper_audio_input_host.h"
+#include "content/renderer/pepper/pepper_camera_device_host.h"
#include "content/renderer/pepper/pepper_compositor_host.h"
#include "content/renderer/pepper/pepper_file_chooser_host.h"
#include "content/renderer/pepper/pepper_file_ref_renderer_host.h"
@@ -20,6 +22,7 @@
#include "content/renderer/pepper/pepper_video_capture_host.h"
#include "content/renderer/pepper/pepper_video_decoder_host.h"
#include "content/renderer/pepper/pepper_video_destination_host.h"
+#include "content/renderer/pepper/pepper_video_encoder_host.h"
#include "content/renderer/pepper/pepper_video_source_host.h"
#include "content/renderer/pepper/pepper_websocket_host.h"
#include "content/renderer/pepper/ppb_image_data_impl.h"
@@ -35,9 +38,7 @@
#include "third_party/WebKit/public/web/WebPluginContainer.h"
#if defined(OS_WIN)
-#include "base/command_line.h"
#include "base/win/windows_version.h"
-#include "content/public/common/content_switches.h"
#endif
using ppapi::host::ResourceHost;
@@ -61,7 +62,8 @@ bool CanUseMediaStreamAPI(const RendererPpapiHost* host, PP_Instance instance) {
}
#endif // defined(ENABLE_WEBRTC)
-bool CanUseCompositorAPI(const RendererPpapiHost* host, PP_Instance instance) {
+static bool CanUseCameraDeviceAPI(const RendererPpapiHost* host,
+ PP_Instance instance) {
blink::WebPluginContainer* container =
host->GetContainerForInstance(instance);
if (!container)
@@ -70,11 +72,11 @@ bool CanUseCompositorAPI(const RendererPpapiHost* host, PP_Instance instance) {
GURL document_url = container->element().document().url();
ContentRendererClient* content_renderer_client =
GetContentClient()->renderer();
- return content_renderer_client->IsPluginAllowedToUseCompositorAPI(
+ return content_renderer_client->IsPluginAllowedToUseCameraDeviceAPI(
document_url);
}
-bool CanUseVideoDecodeAPI(const RendererPpapiHost* host, PP_Instance instance) {
+bool CanUseCompositorAPI(const RendererPpapiHost* host, PP_Instance instance) {
blink::WebPluginContainer* container =
host->GetContainerForInstance(instance);
if (!container)
@@ -83,7 +85,7 @@ bool CanUseVideoDecodeAPI(const RendererPpapiHost* host, PP_Instance instance) {
GURL document_url = container->element().document().url();
ContentRendererClient* content_renderer_client =
GetContentClient()->renderer();
- return content_renderer_client->IsPluginAllowedToUseVideoDecodeAPI(
+ return content_renderer_client->IsPluginAllowedToUseCompositorAPI(
document_url);
}
@@ -97,7 +99,7 @@ ContentRendererPepperHostFactory::~ContentRendererPepperHostFactory() {}
scoped_ptr<ResourceHost> ContentRendererPepperHostFactory::CreateResourceHost(
ppapi::host::PpapiHost* host,
- const ppapi::proxy::ResourceMessageCallParams& params,
+ PP_Resource resource,
PP_Instance instance,
const IPC::Message& message) {
DCHECK(host == host_->GetPpapiHost());
@@ -117,7 +119,7 @@ scoped_ptr<ResourceHost> ContentRendererPepperHostFactory::CreateResourceHost(
if (!CanUseCompositorAPI(host_, instance))
return scoped_ptr<ResourceHost>();
return scoped_ptr<ResourceHost>(
- new PepperCompositorHost(host_, instance, params.pp_resource()));
+ new PepperCompositorHost(host_, instance, resource));
}
case PpapiHostMsg_FileRef_CreateForFileAPI::ID: {
PP_Resource file_system;
@@ -128,7 +130,7 @@ scoped_ptr<ResourceHost> ContentRendererPepperHostFactory::CreateResourceHost(
return scoped_ptr<ResourceHost>();
}
return scoped_ptr<ResourceHost>(new PepperFileRefRendererHost(
- host_, instance, params.pp_resource(), file_system, internal_path));
+ host_, instance, resource, file_system, internal_path));
}
case PpapiHostMsg_FileSystem_Create::ID: {
PP_FileSystemType file_system_type;
@@ -138,7 +140,7 @@ scoped_ptr<ResourceHost> ContentRendererPepperHostFactory::CreateResourceHost(
return scoped_ptr<ResourceHost>();
}
return scoped_ptr<ResourceHost>(new PepperFileSystemHost(
- host_, instance, params.pp_resource(), file_system_type));
+ host_, instance, resource, file_system_type));
}
case PpapiHostMsg_Graphics2D_Create::ID: {
PP_Size size;
@@ -158,49 +160,41 @@ scoped_ptr<ResourceHost> ContentRendererPepperHostFactory::CreateResourceHost(
// TODO(ananta)
// Look into whether this causes a loss of functionality. From cursory
// testing things seem to work well.
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableWin32kRendererLockDown) &&
- base::win::GetVersion() >= base::win::VERSION_WIN8) {
+ if (IsWin32kRendererLockdownEnabled())
image_type = ppapi::PPB_ImageData_Shared::SIMPLE;
- }
#endif
scoped_refptr<PPB_ImageData_Impl> image_data(new PPB_ImageData_Impl(
instance, image_type));
- return scoped_ptr<ResourceHost>(
- PepperGraphics2DHost::Create(host_,
- instance,
- params.pp_resource(),
- size,
- is_always_opaque,
- image_data));
+ return scoped_ptr<ResourceHost>(PepperGraphics2DHost::Create(
+ host_, instance, resource, size, is_always_opaque, image_data));
}
case PpapiHostMsg_URLLoader_Create::ID:
- return scoped_ptr<ResourceHost>(new PepperURLLoaderHost(
- host_, false, instance, params.pp_resource()));
- case PpapiHostMsg_VideoDecoder_Create::ID: {
- if (!CanUseVideoDecodeAPI(host_, instance))
- return scoped_ptr<ResourceHost>();
return scoped_ptr<ResourceHost>(
- new PepperVideoDecoderHost(host_, instance, params.pp_resource()));
- }
+ new PepperURLLoaderHost(host_, false, instance, resource));
+ case PpapiHostMsg_VideoDecoder_Create::ID:
+ return scoped_ptr<ResourceHost>(
+ new PepperVideoDecoderHost(host_, instance, resource));
+ case PpapiHostMsg_VideoEncoder_Create::ID:
+ return scoped_ptr<ResourceHost>(
+ new PepperVideoEncoderHost(host_, instance, resource));
case PpapiHostMsg_WebSocket_Create::ID:
return scoped_ptr<ResourceHost>(
- new PepperWebSocketHost(host_, instance, params.pp_resource()));
+ new PepperWebSocketHost(host_, instance, resource));
#if defined(ENABLE_WEBRTC)
case PpapiHostMsg_MediaStreamVideoTrack_Create::ID:
- return scoped_ptr<ResourceHost>(new PepperMediaStreamVideoTrackHost(
- host_, instance, params.pp_resource()));
+ return scoped_ptr<ResourceHost>(
+ new PepperMediaStreamVideoTrackHost(host_, instance, resource));
// These private MediaStream interfaces are exposed as if they were public
// so they can be used by NaCl plugins. However, they are available only
// for whitelisted apps.
case PpapiHostMsg_VideoDestination_Create::ID:
if (CanUseMediaStreamAPI(host_, instance))
- return scoped_ptr<ResourceHost>(new PepperVideoDestinationHost(
- host_, instance, params.pp_resource()));
+ return scoped_ptr<ResourceHost>(
+ new PepperVideoDestinationHost(host_, instance, resource));
case PpapiHostMsg_VideoSource_Create::ID:
if (CanUseMediaStreamAPI(host_, instance))
return scoped_ptr<ResourceHost>(
- new PepperVideoSourceHost(host_, instance, params.pp_resource()));
+ new PepperVideoSourceHost(host_, instance, resource));
#endif // defined(ENABLE_WEBRTC)
}
@@ -209,13 +203,13 @@ scoped_ptr<ResourceHost> ContentRendererPepperHostFactory::CreateResourceHost(
switch (message.type()) {
case PpapiHostMsg_AudioInput_Create::ID:
return scoped_ptr<ResourceHost>(
- new PepperAudioInputHost(host_, instance, params.pp_resource()));
+ new PepperAudioInputHost(host_, instance, resource));
case PpapiHostMsg_FileChooser_Create::ID:
return scoped_ptr<ResourceHost>(
- new PepperFileChooserHost(host_, instance, params.pp_resource()));
+ new PepperFileChooserHost(host_, instance, resource));
case PpapiHostMsg_VideoCapture_Create::ID: {
PepperVideoCaptureHost* host =
- new PepperVideoCaptureHost(host_, instance, params.pp_resource());
+ new PepperVideoCaptureHost(host_, instance, resource);
if (!host->Init()) {
delete host;
return scoped_ptr<ResourceHost>();
@@ -225,6 +219,17 @@ scoped_ptr<ResourceHost> ContentRendererPepperHostFactory::CreateResourceHost(
}
}
+ // Permissions of the following interfaces are available for whitelisted apps
+ // which may not have access to the other private interfaces.
+ if (message.type() == PpapiHostMsg_CameraDevice_Create::ID) {
+ if (!GetPermissions().HasPermission(ppapi::PERMISSION_PRIVATE) &&
+ !CanUseCameraDeviceAPI(host_, instance))
+ return nullptr;
+ scoped_ptr<PepperCameraDeviceHost> host(
+ new PepperCameraDeviceHost(host_, instance, resource));
+ return host->Init() ? host.Pass() : nullptr;
+ }
+
return scoped_ptr<ResourceHost>();
}
diff --git a/chromium/content/renderer/pepper/content_renderer_pepper_host_factory.h b/chromium/content/renderer/pepper/content_renderer_pepper_host_factory.h
index 9a4ef85687f..e6feec9f2b3 100644
--- a/chromium/content/renderer/pepper/content_renderer_pepper_host_factory.h
+++ b/chromium/content/renderer/pepper/content_renderer_pepper_host_factory.h
@@ -25,7 +25,7 @@ class ContentRendererPepperHostFactory : public ppapi::host::HostFactory {
scoped_ptr<ppapi::host::ResourceHost> CreateResourceHost(
ppapi::host::PpapiHost* host,
- const ppapi::proxy::ResourceMessageCallParams& params,
+ PP_Resource resource,
PP_Instance instance,
const IPC::Message& message) override;
diff --git a/chromium/content/renderer/pepper/event_conversion.cc b/chromium/content/renderer/pepper/event_conversion.cc
index 4de55559fff..f66cf184a03 100644
--- a/chromium/content/renderer/pepper/event_conversion.cc
+++ b/chromium/content/renderer/pepper/event_conversion.cc
@@ -13,13 +13,13 @@
#include "base/strings/utf_string_conversion_utils.h"
#include "base/strings/utf_string_conversions.h"
#include "content/common/input/web_touch_event_traits.h"
-#include "content/renderer/pepper/usb_key_code_conversion.h"
#include "ppapi/c/pp_input_event.h"
#include "ppapi/shared_impl/ppb_input_event_shared.h"
#include "ppapi/shared_impl/time_conversion.h"
#include "third_party/WebKit/public/platform/WebGamepads.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
+#include "ui/events/keycodes/dom/keycode_converter.h"
using ppapi::EventTimeToPPTimeTicks;
using ppapi::InputEventData;
@@ -40,45 +40,45 @@ namespace {
// Verify the modifier flags WebKit uses match the Pepper ones. If these start
// not matching, we'll need to write conversion code to preserve the Pepper
// values (since plugins will be depending on them).
-COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_SHIFTKEY) ==
- static_cast<int>(WebInputEvent::ShiftKey),
- ShiftKeyMatches);
-COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_CONTROLKEY) ==
- static_cast<int>(WebInputEvent::ControlKey),
- ControlKeyMatches);
-COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_ALTKEY) ==
- static_cast<int>(WebInputEvent::AltKey),
- AltKeyMatches);
-COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_METAKEY) ==
- static_cast<int>(WebInputEvent::MetaKey),
- MetaKeyMatches);
-COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_ISKEYPAD) ==
- static_cast<int>(WebInputEvent::IsKeyPad),
- KeyPadMatches);
-COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_ISAUTOREPEAT) ==
- static_cast<int>(WebInputEvent::IsAutoRepeat),
- AutoRepeatMatches);
-COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_LEFTBUTTONDOWN) ==
- static_cast<int>(WebInputEvent::LeftButtonDown),
- LeftButtonMatches);
-COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_MIDDLEBUTTONDOWN) ==
- static_cast<int>(WebInputEvent::MiddleButtonDown),
- MiddleButtonMatches);
-COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_RIGHTBUTTONDOWN) ==
- static_cast<int>(WebInputEvent::RightButtonDown),
- RightButtonMatches);
-COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_CAPSLOCKKEY) ==
- static_cast<int>(WebInputEvent::CapsLockOn),
- CapsLockMatches);
-COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_NUMLOCKKEY) ==
- static_cast<int>(WebInputEvent::NumLockOn),
- NumLockMatches);
-COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_ISLEFT) ==
- static_cast<int>(WebInputEvent::IsLeft),
- LeftMatches);
-COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_ISRIGHT) ==
- static_cast<int>(WebInputEvent::IsRight),
- RightMatches);
+static_assert(static_cast<int>(PP_INPUTEVENT_MODIFIER_SHIFTKEY) ==
+ static_cast<int>(WebInputEvent::ShiftKey),
+ "ShiftKey should match");
+static_assert(static_cast<int>(PP_INPUTEVENT_MODIFIER_CONTROLKEY) ==
+ static_cast<int>(WebInputEvent::ControlKey),
+ "ControlKey should match");
+static_assert(static_cast<int>(PP_INPUTEVENT_MODIFIER_ALTKEY) ==
+ static_cast<int>(WebInputEvent::AltKey),
+ "AltKey should match");
+static_assert(static_cast<int>(PP_INPUTEVENT_MODIFIER_METAKEY) ==
+ static_cast<int>(WebInputEvent::MetaKey),
+ "MetaKey should match");
+static_assert(static_cast<int>(PP_INPUTEVENT_MODIFIER_ISKEYPAD) ==
+ static_cast<int>(WebInputEvent::IsKeyPad),
+ "KeyPad should match");
+static_assert(static_cast<int>(PP_INPUTEVENT_MODIFIER_ISAUTOREPEAT) ==
+ static_cast<int>(WebInputEvent::IsAutoRepeat),
+ "AutoRepeat should match");
+static_assert(static_cast<int>(PP_INPUTEVENT_MODIFIER_LEFTBUTTONDOWN) ==
+ static_cast<int>(WebInputEvent::LeftButtonDown),
+ "LeftButton should match");
+static_assert(static_cast<int>(PP_INPUTEVENT_MODIFIER_MIDDLEBUTTONDOWN) ==
+ static_cast<int>(WebInputEvent::MiddleButtonDown),
+ "MiddleButton should match");
+static_assert(static_cast<int>(PP_INPUTEVENT_MODIFIER_RIGHTBUTTONDOWN) ==
+ static_cast<int>(WebInputEvent::RightButtonDown),
+ "RightButton should match");
+static_assert(static_cast<int>(PP_INPUTEVENT_MODIFIER_CAPSLOCKKEY) ==
+ static_cast<int>(WebInputEvent::CapsLockOn),
+ "CapsLock should match");
+static_assert(static_cast<int>(PP_INPUTEVENT_MODIFIER_NUMLOCKKEY) ==
+ static_cast<int>(WebInputEvent::NumLockOn),
+ "NumLock should match");
+static_assert(static_cast<int>(PP_INPUTEVENT_MODIFIER_ISLEFT) ==
+ static_cast<int>(WebInputEvent::IsLeft),
+ "IsLeft should match");
+static_assert(static_cast<int>(PP_INPUTEVENT_MODIFIER_ISRIGHT) ==
+ static_cast<int>(WebInputEvent::IsRight),
+ "IsRight should match");
PP_InputEvent_Type ConvertEventTypes(WebInputEvent::Type wetype) {
switch (wetype) {
@@ -135,7 +135,14 @@ void AppendKeyEvent(const WebInputEvent& event,
InputEventData result = GetEventWithCommonFieldsAndType(event);
result.event_modifiers = key_event.modifiers;
result.key_code = key_event.windowsKeyCode;
- result.code = CodeForKeyboardEvent(key_event);
+#if defined(OS_MACOSX)
+ // Workaround for |domCode| not being set on OS X. crbug.com/493833
+ result.code = ui::KeycodeConverter::DomCodeToCodeString(
+ ui::KeycodeConverter::NativeKeycodeToDomCode(key_event.nativeKeyCode));
+#else
+ result.code = ui::KeycodeConverter::DomCodeToCodeString(
+ static_cast<ui::DomCode>(key_event.domCode));
+#endif
result_events->push_back(result);
}
@@ -169,18 +176,18 @@ void AppendCharEvent(const WebInputEvent& event,
void AppendMouseEvent(const WebInputEvent& event,
std::vector<InputEventData>* result_events) {
- COMPILE_ASSERT(static_cast<int>(WebMouseEvent::ButtonNone) ==
- static_cast<int>(PP_INPUTEVENT_MOUSEBUTTON_NONE),
- MouseNone);
- COMPILE_ASSERT(static_cast<int>(WebMouseEvent::ButtonLeft) ==
- static_cast<int>(PP_INPUTEVENT_MOUSEBUTTON_LEFT),
- MouseLeft);
- COMPILE_ASSERT(static_cast<int>(WebMouseEvent::ButtonRight) ==
- static_cast<int>(PP_INPUTEVENT_MOUSEBUTTON_RIGHT),
- MouseRight);
- COMPILE_ASSERT(static_cast<int>(WebMouseEvent::ButtonMiddle) ==
- static_cast<int>(PP_INPUTEVENT_MOUSEBUTTON_MIDDLE),
- MouseMiddle);
+ static_assert(static_cast<int>(WebMouseEvent::ButtonNone) ==
+ static_cast<int>(PP_INPUTEVENT_MOUSEBUTTON_NONE),
+ "MouseNone should match");
+ static_assert(static_cast<int>(WebMouseEvent::ButtonLeft) ==
+ static_cast<int>(PP_INPUTEVENT_MOUSEBUTTON_LEFT),
+ "MouseLeft should match");
+ static_assert(static_cast<int>(WebMouseEvent::ButtonRight) ==
+ static_cast<int>(PP_INPUTEVENT_MOUSEBUTTON_RIGHT),
+ "MouseRight should match");
+ static_assert(static_cast<int>(WebMouseEvent::ButtonMiddle) ==
+ static_cast<int>(PP_INPUTEVENT_MOUSEBUTTON_MIDDLE),
+ "MouseMiddle should match");
const WebMouseEvent& mouse_event = static_cast<const WebMouseEvent&>(event);
InputEventData result = GetEventWithCommonFieldsAndType(event);
diff --git a/chromium/content/renderer/pepper/fullscreen_container.h b/chromium/content/renderer/pepper/fullscreen_container.h
index d91cc668f49..9cc540bc27d 100644
--- a/chromium/content/renderer/pepper/fullscreen_container.h
+++ b/chromium/content/renderer/pepper/fullscreen_container.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_RENDERER_PEPPER_PPB_FULLSCREEN_CONTAINER_IMPL_H_
-#define CONTENT_RENDERER_PEPPER_PPB_FULLSCREEN_CONTAINER_IMPL_H_
+#ifndef CONTENT_RENDERER_PEPPER_FULLSCREEN_CONTAINER_H_
+#define CONTENT_RENDERER_PEPPER_FULLSCREEN_CONTAINER_H_
namespace blink {
class WebLayer;
@@ -41,4 +41,4 @@ class FullscreenContainer {
} // namespace content
-#endif // CONTENT_RENDERER_PEPPER_PPB_FULLSCREEN_CONTAINER_IMPL_H_
+#endif // CONTENT_RENDERER_PEPPER_FULLSCREEN_CONTAINER_H_
diff --git a/chromium/content/renderer/pepper/gfx_conversion.h b/chromium/content/renderer/pepper/gfx_conversion.h
index 1c1fa11a333..1fe529be63a 100644
--- a/chromium/content/renderer/pepper/gfx_conversion.h
+++ b/chromium/content/renderer/pepper/gfx_conversion.h
@@ -8,10 +8,10 @@
#include "ppapi/c/pp_point.h"
#include "ppapi/c/pp_rect.h"
#include "ppapi/c/pp_size.h"
-#include "ui/gfx/point.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/rect_f.h"
-#include "ui/gfx/size.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/geometry/size.h"
// Conversions for graphics types between our gfx library and PPAPI.
// The style of naming is to match the PP_Bool conversions.
diff --git a/chromium/content/renderer/pepper/host_array_buffer_var.cc b/chromium/content/renderer/pepper/host_array_buffer_var.cc
index ad8e97b46bf..ad9e5e6bd43 100644
--- a/chromium/content/renderer/pepper/host_array_buffer_var.cc
+++ b/chromium/content/renderer/pepper/host_array_buffer_var.cc
@@ -11,6 +11,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/shared_memory.h"
#include "base/process/process_handle.h"
+#include "content/common/pepper_file_util.h"
#include "content/common/sandbox_util.h"
#include "content/renderer/pepper/host_globals.h"
#include "content/renderer/pepper/plugin_module.h"
@@ -80,13 +81,7 @@ bool HostArrayBufferVar::CopyToNewShmem(
}
base::PlatformFile platform_file =
-#if defined(OS_WIN)
- shm->handle();
-#elif defined(OS_POSIX)
- shm->handle().fd;
-#else
-#error Not implemented.
-#endif
+ PlatformFileFromSharedMemoryHandle(shm->handle());
*plugin_shm_handle = BrokerGetFileHandleForProcess(platform_file, p, false);
*host_shm_handle_id = -1;
diff --git a/chromium/content/renderer/pepper/host_array_buffer_var.h b/chromium/content/renderer/pepper/host_array_buffer_var.h
index 9722f5fe058..3f917d46cd4 100644
--- a/chromium/content/renderer/pepper/host_array_buffer_var.h
+++ b/chromium/content/renderer/pepper/host_array_buffer_var.h
@@ -2,14 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef PPAPI_CONTENT_RENDERER_PEPPER_HOST_ARRAY_BUFFER_VAR_H_
-#define PPAPI_CONTENT_RENDERER_PEPPER_HOST_ARRAY_BUFFER_VAR_H_
+#ifndef CONTENT_RENDERER_PEPPER_HOST_ARRAY_BUFFER_VAR_H_
+#define CONTENT_RENDERER_PEPPER_HOST_ARRAY_BUFFER_VAR_H_
#include "base/memory/shared_memory.h"
#include "ppapi/c/pp_instance.h"
#include "ppapi/shared_impl/host_resource.h"
#include "ppapi/shared_impl/var.h"
-#include "third_party/WebKit/public/platform/WebArrayBuffer.h"
+#include "third_party/WebKit/public/web/WebArrayBuffer.h"
namespace content {
@@ -43,4 +43,4 @@ class HostArrayBufferVar : public ppapi::ArrayBufferVar {
} // namespace content
-#endif // PPAPI_CONTENT_RENDERER_PEPPER_HOST_ARRAY_BUFFER_VAR_H_
+#endif // CONTENT_RENDERER_PEPPER_HOST_ARRAY_BUFFER_VAR_H_
diff --git a/chromium/content/renderer/pepper/host_dispatcher_wrapper.cc b/chromium/content/renderer/pepper/host_dispatcher_wrapper.cc
index df05521fbca..b14a8a01043 100644
--- a/chromium/content/renderer/pepper/host_dispatcher_wrapper.cc
+++ b/chromium/content/renderer/pepper/host_dispatcher_wrapper.cc
@@ -5,6 +5,7 @@
#include "content/renderer/pepper/host_dispatcher_wrapper.h"
#include "content/common/view_messages.h"
+#include "content/public/common/origin_util.h"
#include "content/renderer/pepper/pepper_hung_plugin_filter.h"
#include "content/renderer/pepper/pepper_plugin_instance_impl.h"
#include "content/renderer/pepper/pepper_proxy_channel_delegate_impl.h"
@@ -12,6 +13,9 @@
#include "content/renderer/pepper/renderer_ppapi_host_impl.h"
#include "content/renderer/pepper/renderer_restrict_dispatch_group.h"
#include "content/renderer/render_frame_impl.h"
+#include "third_party/WebKit/public/web/WebDocument.h"
+#include "third_party/WebKit/public/web/WebElement.h"
+#include "third_party/WebKit/public/web/WebPluginContainer.h"
namespace content {
@@ -85,14 +89,19 @@ void HostDispatcherWrapper::AddInstance(PP_Instance instance) {
if (host) {
RenderFrame* render_frame = host->GetRenderFrameForInstance(instance);
PepperPluginInstance* plugin_instance = host->GetPluginInstance(instance);
+ blink::WebString unused;
+ bool is_privileged_context =
+ plugin_instance->GetContainer()
+ ->element()
+ .document()
+ .isPrivilegedContext(unused) &&
+ content::IsOriginSecure(plugin_instance->GetPluginURL());
render_frame->Send(new ViewHostMsg_DidCreateOutOfProcessPepperInstance(
- plugin_child_id_,
- instance,
+ plugin_child_id_, instance,
PepperRendererInstanceData(
0, // The render process id will be supplied in the browser.
- render_frame->GetRoutingID(),
- host->GetDocumentURL(instance),
- plugin_instance->GetPluginURL()),
+ render_frame->GetRoutingID(), host->GetDocumentURL(instance),
+ plugin_instance->GetPluginURL(), is_privileged_context),
is_external_));
}
}
diff --git a/chromium/content/renderer/pepper/host_globals.cc b/chromium/content/renderer/pepper/host_globals.cc
index c8c44fa560f..a00748794b4 100644
--- a/chromium/content/renderer/pepper/host_globals.cc
+++ b/chromium/content/renderer/pepper/host_globals.cc
@@ -135,7 +135,7 @@ PP_Module HostGlobals::GetModuleForInstance(PP_Instance instance) {
}
std::string HostGlobals::GetCmdLine() {
- return CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ return base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kPpapiFlashArgs);
}
diff --git a/chromium/content/renderer/pepper/host_resource_var.h b/chromium/content/renderer/pepper/host_resource_var.h
index 152b9a99b1f..9897a46c62f 100644
--- a/chromium/content/renderer/pepper/host_resource_var.h
+++ b/chromium/content/renderer/pepper/host_resource_var.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 PPAPI_CONTENT_RENDERER_PEPPER_HOST_RESOURCE_VAR_H_
-#define PPAPI_CONTENT_RENDERER_PEPPER_HOST_RESOURCE_VAR_H_
+#ifndef CONTENT_RENDERER_PEPPER_HOST_RESOURCE_VAR_H_
+#define CONTENT_RENDERER_PEPPER_HOST_RESOURCE_VAR_H_
#include "base/memory/scoped_ptr.h"
#include "ipc/ipc_message.h"
@@ -63,4 +63,4 @@ class HostResourceVar : public ppapi::ResourceVar {
} // namespace content
-#endif
+#endif // CONTENT_RENDERER_PEPPER_HOST_RESOURCE_VAR_H_
diff --git a/chromium/content/renderer/pepper/host_var_tracker.cc b/chromium/content/renderer/pepper/host_var_tracker.cc
index 494d9b9a173..e3da98312cf 100644
--- a/chromium/content/renderer/pepper/host_var_tracker.cc
+++ b/chromium/content/renderer/pepper/host_var_tracker.cc
@@ -24,7 +24,7 @@ HostVarTracker::V8ObjectVarKey::V8ObjectVarKey(V8ObjectVar* object_var)
}
HostVarTracker::V8ObjectVarKey::V8ObjectVarKey(PP_Instance instance,
- v8::Handle<v8::Object> object)
+ v8::Local<v8::Object> object)
: instance(instance),
hash(object.IsEmpty() ? 0 : object->GetIdentityHash()) {}
@@ -70,7 +70,7 @@ void HostVarTracker::RemoveV8ObjectVar(V8ObjectVar* object_var) {
}
PP_Var HostVarTracker::V8ObjectVarForV8Object(PP_Instance instance,
- v8::Handle<v8::Object> object) {
+ v8::Local<v8::Object> object) {
CheckThreadingPreconditions();
ObjectMap::const_iterator it = GetForV8Object(instance, object);
if (it == object_map_.end())
@@ -83,7 +83,7 @@ int HostVarTracker::GetLiveV8ObjectVarsForTest(PP_Instance instance) {
int count = 0;
// Use a key with an empty handle to find the v8 object var in the map with
// the given instance and the lowest hash.
- V8ObjectVarKey key(instance, v8::Handle<v8::Object>());
+ V8ObjectVarKey key(instance, v8::Local<v8::Object>());
ObjectMap::const_iterator it = object_map_.lower_bound(key);
while (it != object_map_.end() && it->first.instance == instance) {
++count;
@@ -119,7 +119,7 @@ void HostVarTracker::DidDeleteInstance(PP_Instance pp_instance) {
// Use a key with an empty handle to find the v8 object var in the map with
// the given instance and the lowest hash.
- V8ObjectVarKey key(pp_instance, v8::Handle<v8::Object>());
+ V8ObjectVarKey key(pp_instance, v8::Local<v8::Object>());
ObjectMap::iterator it = object_map_.lower_bound(key);
while (it != object_map_.end() && it->first.instance == pp_instance) {
ForceReleaseV8Object(it->second);
@@ -141,7 +141,7 @@ void HostVarTracker::ForceReleaseV8Object(ppapi::V8ObjectVar* object_var) {
HostVarTracker::ObjectMap::iterator HostVarTracker::GetForV8Object(
PP_Instance instance,
- v8::Handle<v8::Object> object) {
+ v8::Local<v8::Object> object) {
std::pair<ObjectMap::iterator, ObjectMap::iterator> range =
object_map_.equal_range(V8ObjectVarKey(instance, object));
diff --git a/chromium/content/renderer/pepper/host_var_tracker.h b/chromium/content/renderer/pepper/host_var_tracker.h
index 0be5d1d2eb6..9f1c61d51a4 100644
--- a/chromium/content/renderer/pepper/host_var_tracker.h
+++ b/chromium/content/renderer/pepper/host_var_tracker.h
@@ -40,7 +40,7 @@ class HostVarTracker : public ppapi::VarTracker {
void RemoveV8ObjectVar(ppapi::V8ObjectVar* object_var);
// Creates or retrieves a V8ObjectVar.
PP_Var V8ObjectVarForV8Object(PP_Instance instance,
- v8::Handle<v8::Object> object);
+ v8::Local<v8::Object> object);
// Returns the number of V8ObjectVars associated with the given instance.
// Returns 0 if the instance isn't known.
CONTENT_EXPORT int GetLiveV8ObjectVarsForTest(PP_Instance instance);
@@ -76,7 +76,7 @@ class HostVarTracker : public ppapi::VarTracker {
// and the instance it is associated with.
struct V8ObjectVarKey {
explicit V8ObjectVarKey(ppapi::V8ObjectVar* object_var);
- V8ObjectVarKey(PP_Instance i, v8::Handle<v8::Object> object);
+ V8ObjectVarKey(PP_Instance i, v8::Local<v8::Object> object);
~V8ObjectVarKey();
bool operator<(const V8ObjectVarKey& other) const;
@@ -89,7 +89,7 @@ class HostVarTracker : public ppapi::VarTracker {
// Returns an iterator into |object_map| which points to V8Object which
// is associated with the given instance and object.
ObjectMap::iterator GetForV8Object(PP_Instance instance,
- v8::Handle<v8::Object> object);
+ v8::Local<v8::Object> object);
// A multimap of V8ObjectVarKey -> ObjectMap.
diff --git a/chromium/content/renderer/pepper/host_var_tracker_unittest.cc b/chromium/content/renderer/pepper/host_var_tracker_unittest.cc
index 32e9e56ea89..55b6b86158c 100644
--- a/chromium/content/renderer/pepper/host_var_tracker_unittest.cc
+++ b/chromium/content/renderer/pepper/host_var_tracker_unittest.cc
@@ -30,7 +30,7 @@ class MyObject : public gin::Wrappable<MyObject> {
public:
static gin::WrapperInfo kWrapperInfo;
- static v8::Handle<v8::Value> Create(v8::Isolate* isolate) {
+ static v8::Local<v8::Value> Create(v8::Isolate* isolate) {
return gin::CreateHandle(isolate, new MyObject()).ToV8();
}
@@ -53,7 +53,7 @@ class PepperTryCatchForTest : public PepperTryCatch {
void SetException(const char* message) override { NOTREACHED(); }
bool HasException() override { return false; }
- v8::Handle<v8::Context> GetContext() override {
+ v8::Local<v8::Context> GetContext() override {
return instance_->GetIsolate()->GetCurrentContext();
}
@@ -112,7 +112,7 @@ TEST_F(HostVarTrackerTest, ReuseVar) {
instance()->pp_instance(), V8VarConverter::kAllowObjectVars);
PepperTryCatchForTest try_catch(instance(), &converter);
- v8::Handle<v8::Value> v8_object = MyObject::Create(v8::Isolate::GetCurrent());
+ v8::Local<v8::Value> v8_object = MyObject::Create(v8::Isolate::GetCurrent());
ppapi::ScopedPPVar pp_object1 = try_catch.FromV8(v8_object);
ppapi::ScopedPPVar pp_object2 = try_catch.FromV8(v8_object);
diff --git a/chromium/content/renderer/pepper/message_channel.cc b/chromium/content/renderer/pepper/message_channel.cc
index 1a4e6383b52..32956e4ea89 100644
--- a/chromium/content/renderer/pepper/message_channel.cc
+++ b/chromium/content/renderer/pepper/message_channel.cc
@@ -92,7 +92,8 @@ MessageChannel* MessageChannel::Create(PepperPluginInstanceImpl* instance,
v8::Context::Scope context_scope(instance->GetMainWorldContext());
gin::Handle<MessageChannel> handle =
gin::CreateHandle(instance->GetIsolate(), message_channel);
- result->Reset(instance->GetIsolate(), handle.ToV8()->ToObject());
+ result->Reset(instance->GetIsolate(),
+ handle.ToV8()->ToObject(instance->GetIsolate()));
return message_channel;
}
@@ -120,7 +121,7 @@ void MessageChannel::PostMessageToJavaScript(PP_Var message_data) {
v8::Context::Scope context_scope(context);
- v8::Handle<v8::Value> v8_val;
+ v8::Local<v8::Value> v8_val;
if (!var_converter_.ToV8Value(message_data, context, &v8_val)) {
PpapiGlobals::Get()->LogWithSource(instance_->pp_instance(),
PP_LOGLEVEL_ERROR,
@@ -166,7 +167,7 @@ void MessageChannel::Start() {
DrainCompletedPluginMessages();
}
-void MessageChannel::SetPassthroughObject(v8::Handle<v8::Object> passthrough) {
+void MessageChannel::SetPassthroughObject(v8::Local<v8::Object> passthrough) {
passthrough_object_.Reset(instance_->GetIsolate(), passthrough);
}
@@ -187,6 +188,7 @@ MessageChannel::MessageChannel(PepperPluginInstanceImpl* instance)
plugin_message_queue_state_(WAITING_TO_START),
var_converter_(instance->pp_instance(),
V8VarConverter::kDisallowObjectVars),
+ template_cache_(instance->GetIsolate()),
weak_ptr_factory_(this) {
}
@@ -216,19 +218,19 @@ v8::Local<v8::Value> MessageChannel::GetNamedProperty(
PepperTryCatchV8 try_catch(instance_, &var_converter_, isolate);
if (identifier == kPostMessage) {
- return gin::CreateFunctionTemplate(isolate,
- base::Bind(&MessageChannel::PostMessageToNative,
- weak_ptr_factory_.GetWeakPtr()))->GetFunction();
+ return GetFunctionTemplate(isolate, identifier,
+ &MessageChannel::PostMessageToNative)
+ ->GetFunction();
} else if (identifier == kPostMessageAndAwaitResponse) {
- return gin::CreateFunctionTemplate(isolate,
- base::Bind(&MessageChannel::PostBlockingMessageToNative,
- weak_ptr_factory_.GetWeakPtr()))->GetFunction();
+ return GetFunctionTemplate(isolate, identifier,
+ &MessageChannel::PostBlockingMessageToNative)
+ ->GetFunction();
}
std::map<std::string, ScopedPPVar>::const_iterator it =
internal_named_properties_.find(identifier);
if (it != internal_named_properties_.end()) {
- v8::Handle<v8::Value> result = try_catch.ToV8(it->second.get());
+ v8::Local<v8::Value> result = try_catch.ToV8(it->second.get());
if (try_catch.ThrowException())
return v8::Local<v8::Value>();
return result;
@@ -282,7 +284,7 @@ void MessageChannel::PostMessageToNative(gin::Arguments* args) {
return;
}
- v8::Handle<v8::Value> message_data;
+ v8::Local<v8::Value> message_data;
if (!args->GetNext(&message_data)) {
NOTREACHED();
}
@@ -301,7 +303,7 @@ void MessageChannel::PostBlockingMessageToNative(gin::Arguments* args) {
return;
}
- v8::Handle<v8::Value> message_data;
+ v8::Local<v8::Value> message_data;
if (!args->GetNext(&message_data)) {
NOTREACHED();
}
@@ -343,7 +345,7 @@ void MessageChannel::PostBlockingMessageToNative(gin::Arguments* args) {
"and PPP_MessageHandler.");
return;
}
- v8::Handle<v8::Value> v8_result = try_catch.ToV8(pp_result.get());
+ v8::Local<v8::Value> v8_result = try_catch.ToV8(pp_result.get());
if (try_catch.ThrowException())
return;
@@ -386,7 +388,7 @@ PluginObject* MessageChannel::GetPluginObject(v8::Isolate* isolate) {
v8::Local<v8::Object>::New(isolate, passthrough_object_));
}
-void MessageChannel::EnqueuePluginMessage(v8::Handle<v8::Value> v8_value) {
+void MessageChannel::EnqueuePluginMessage(v8::Local<v8::Value> v8_value) {
plugin_message_queue_.push_back(VarConversionResult());
// Convert the v8 value in to an appropriate PP_Var like Dictionary,
// Array, etc. (We explicitly don't want an "Object" PP_Var, which we don't
@@ -467,4 +469,17 @@ void MessageChannel::UnregisterSyncMessageStatusObserver() {
}
}
+v8::Local<v8::FunctionTemplate> MessageChannel::GetFunctionTemplate(
+ v8::Isolate* isolate,
+ const std::string& name,
+ void (MessageChannel::*memberFuncPtr)(gin::Arguments* args)) {
+ v8::Local<v8::FunctionTemplate> function_template = template_cache_.Get(name);
+ if (!function_template.IsEmpty())
+ return function_template;
+ function_template = gin::CreateFunctionTemplate(
+ isolate, base::Bind(memberFuncPtr, weak_ptr_factory_.GetWeakPtr()));
+ template_cache_.Set(name, function_template);
+ return function_template;
+}
+
} // namespace content
diff --git a/chromium/content/renderer/pepper/message_channel.h b/chromium/content/renderer/pepper/message_channel.h
index 4889777ed76..cac8f358c54 100644
--- a/chromium/content/renderer/pepper/message_channel.h
+++ b/chromium/content/renderer/pepper/message_channel.h
@@ -18,6 +18,7 @@
#include "ppapi/proxy/host_dispatcher.h"
#include "ppapi/shared_impl/resource.h"
#include "third_party/WebKit/public/web/WebSerializedScriptValue.h"
+#include "v8/include/v8-util.h"
#include "v8/include/v8.h"
struct PP_Var;
@@ -80,7 +81,7 @@ class MessageChannel :
// related to postMessage. Note that this can be empty; it only gets set if
// there is a scriptable 'InstanceObject' associated with this channel's
// instance.
- void SetPassthroughObject(v8::Handle<v8::Object> passthrough);
+ void SetPassthroughObject(v8::Local<v8::Object> passthrough);
PepperPluginInstanceImpl* instance() { return instance_; }
@@ -123,7 +124,7 @@ class MessageChannel :
PluginObject* GetPluginObject(v8::Isolate* isolate);
- void EnqueuePluginMessage(v8::Handle<v8::Value> v8_value);
+ void EnqueuePluginMessage(v8::Local<v8::Value> v8_value);
void FromV8ValueComplete(VarConversionResult* result_holder,
const ppapi::ScopedPPVar& result_var,
@@ -142,6 +143,11 @@ class MessageChannel :
void UnregisterSyncMessageStatusObserver();
+ v8::Local<v8::FunctionTemplate> GetFunctionTemplate(
+ v8::Isolate* isolate,
+ const std::string& name,
+ void (MessageChannel::*memberFuncPtr)(gin::Arguments* args));
+
PepperPluginInstanceImpl* instance_;
// We pass all non-postMessage calls through to the passthrough_object_.
@@ -186,6 +192,8 @@ class MessageChannel :
// Observers for sync messages.
base::Closure unregister_observer_callback_;
+ v8::StdGlobalValueMap<std::string, v8::FunctionTemplate> template_cache_;
+
// This is used to ensure pending tasks will not fire after this object is
// destroyed.
base::WeakPtrFactory<MessageChannel> weak_ptr_factory_;
diff --git a/chromium/content/renderer/pepper/mock_renderer_ppapi_host.cc b/chromium/content/renderer/pepper/mock_renderer_ppapi_host.cc
index 0f7b6e85573..1ff1ec5898e 100644
--- a/chromium/content/renderer/pepper/mock_renderer_ppapi_host.cc
+++ b/chromium/content/renderer/pepper/mock_renderer_ppapi_host.cc
@@ -5,7 +5,7 @@
#include "content/renderer/pepper/mock_renderer_ppapi_host.h"
#include "content/renderer/pepper/fake_pepper_plugin_instance.h"
-#include "ui/gfx/point.h"
+#include "ui/gfx/geometry/point.h"
namespace content {
diff --git a/chromium/content/renderer/pepper/pepper_audio_input_host.cc b/chromium/content/renderer/pepper/pepper_audio_input_host.cc
index 0da9cd1d99c..e96e7ea3d52 100644
--- a/chromium/content/renderer/pepper/pepper_audio_input_host.cc
+++ b/chromium/content/renderer/pepper/pepper_audio_input_host.cc
@@ -6,6 +6,7 @@
#include "base/logging.h"
#include "build/build_config.h"
+#include "content/common/pepper_file_util.h"
#include "content/renderer/pepper/pepper_media_device_manager.h"
#include "content/renderer/pepper/pepper_platform_audio_input.h"
#include "content/renderer/pepper/pepper_plugin_instance_impl.h"
@@ -26,17 +27,6 @@ base::PlatformFile ConvertSyncSocketHandle(const base::SyncSocket& socket) {
return socket.handle();
}
-base::PlatformFile ConvertSharedMemoryHandle(
- const base::SharedMemory& shared_memory) {
-#if defined(OS_POSIX)
- return shared_memory.handle().fd;
-#elif defined(OS_WIN)
- return shared_memory.handle();
-#else
-#error "Platform not supported."
-#endif
-}
-
} // namespace
PepperAudioInputHost::PepperAudioInputHost(RendererPpapiHostImpl* host,
@@ -183,7 +173,7 @@ int32_t PepperAudioInputHost::GetRemoteHandles(
return PP_ERROR_FAILED;
*remote_shared_memory_handle = renderer_ppapi_host_->ShareHandleWithRemote(
- ConvertSharedMemoryHandle(shared_memory), false);
+ PlatformFileFromSharedMemoryHandle(shared_memory.handle()), false);
if (*remote_shared_memory_handle == IPC::InvalidPlatformFileForTransit())
return PP_ERROR_FAILED;
diff --git a/chromium/content/renderer/pepper/pepper_browser_connection.cc b/chromium/content/renderer/pepper/pepper_browser_connection.cc
index 892506ede2f..f8e08b21d17 100644
--- a/chromium/content/renderer/pepper/pepper_browser_connection.cc
+++ b/chromium/content/renderer/pepper/pepper_browser_connection.cc
@@ -42,11 +42,15 @@ void PepperBrowserConnection::DidCreateInProcessInstance(
int render_frame_id,
const GURL& document_url,
const GURL& plugin_url) {
+ // We don't need to know if it's a privileged context for in-process plugins.
+ // In process plugins are deprecated and the only in-process plugin that
+ // exists is the "NaCl plugin" which will never need to know this.
+ bool is_privileged_context = false;
Send(new ViewHostMsg_DidCreateInProcessInstance(
instance,
// Browser provides the render process id.
- PepperRendererInstanceData(
- 0, render_frame_id, document_url, plugin_url)));
+ PepperRendererInstanceData(0, render_frame_id, document_url, plugin_url,
+ is_privileged_context)));
}
void PepperBrowserConnection::DidDeleteInProcessInstance(PP_Instance instance) {
diff --git a/chromium/content/renderer/pepper/pepper_camera_device_host.cc b/chromium/content/renderer/pepper/pepper_camera_device_host.cc
new file mode 100644
index 00000000000..cf199e23c3a
--- /dev/null
+++ b/chromium/content/renderer/pepper/pepper_camera_device_host.cc
@@ -0,0 +1,126 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/pepper/pepper_camera_device_host.h"
+
+#include "content/renderer/pepper/pepper_platform_camera_device.h"
+#include "content/renderer/pepper/renderer_ppapi_host_impl.h"
+#include "content/renderer/render_frame_impl.h"
+#include "ppapi/host/dispatch_host_message.h"
+#include "ppapi/proxy/ppapi_messages.h"
+
+namespace content {
+
+PepperCameraDeviceHost::PepperCameraDeviceHost(RendererPpapiHostImpl* host,
+ PP_Instance instance,
+ PP_Resource resource)
+ : ResourceHost(host->GetPpapiHost(), instance, resource),
+ renderer_ppapi_host_(host) {
+}
+
+PepperCameraDeviceHost::~PepperCameraDeviceHost() {
+ DetachPlatformCameraDevice();
+}
+
+bool PepperCameraDeviceHost::Init() {
+ return !!renderer_ppapi_host_->GetPluginInstance(pp_instance());
+}
+
+int32_t PepperCameraDeviceHost::OnResourceMessageReceived(
+ const IPC::Message& msg,
+ ppapi::host::HostMessageContext* context) {
+ int32_t result = PP_ERROR_FAILED;
+
+ PPAPI_BEGIN_MESSAGE_MAP(PepperCameraDeviceHost, msg)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_CameraDevice_Open, OnOpen)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
+ PpapiHostMsg_CameraDevice_GetSupportedVideoCaptureFormats,
+ OnGetSupportedVideoCaptureFormats)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_CameraDevice_Close,
+ OnClose)
+ PPAPI_END_MESSAGE_MAP()
+ return result;
+}
+
+void PepperCameraDeviceHost::OnInitialized(bool succeeded) {
+ if (!open_reply_context_.is_valid())
+ return;
+
+ if (succeeded) {
+ open_reply_context_.params.set_result(PP_OK);
+ } else {
+ DetachPlatformCameraDevice();
+ open_reply_context_.params.set_result(PP_ERROR_FAILED);
+ }
+
+ host()->SendReply(open_reply_context_,
+ PpapiPluginMsg_CameraDevice_OpenReply());
+ open_reply_context_ = ppapi::host::ReplyMessageContext();
+}
+
+void PepperCameraDeviceHost::OnVideoCaptureFormatsEnumerated(
+ const std::vector<PP_VideoCaptureFormat>& formats) {
+ if (!video_capture_formats_reply_context_.is_valid())
+ return;
+
+ if (formats.size() > 0)
+ video_capture_formats_reply_context_.params.set_result(PP_OK);
+ else
+ video_capture_formats_reply_context_.params.set_result(PP_ERROR_FAILED);
+ host()->SendReply(
+ video_capture_formats_reply_context_,
+ PpapiPluginMsg_CameraDevice_GetSupportedVideoCaptureFormatsReply(
+ formats));
+ video_capture_formats_reply_context_ = ppapi::host::ReplyMessageContext();
+}
+
+int32_t PepperCameraDeviceHost::OnOpen(ppapi::host::HostMessageContext* context,
+ const std::string& device_id) {
+ if (open_reply_context_.is_valid())
+ return PP_ERROR_INPROGRESS;
+
+ if (platform_camera_device_.get())
+ return PP_ERROR_FAILED;
+
+ GURL document_url = renderer_ppapi_host_->GetDocumentURL(pp_instance());
+ if (!document_url.is_valid())
+ return PP_ERROR_FAILED;
+
+ platform_camera_device_.reset(new PepperPlatformCameraDevice(
+ renderer_ppapi_host_->GetRenderFrameForInstance(pp_instance())
+ ->GetRoutingID(),
+ device_id, document_url, this));
+
+ open_reply_context_ = context->MakeReplyMessageContext();
+
+ return PP_OK_COMPLETIONPENDING;
+}
+
+int32_t PepperCameraDeviceHost::OnClose(
+ ppapi::host::HostMessageContext* context) {
+ DetachPlatformCameraDevice();
+ return PP_OK;
+}
+
+int32_t PepperCameraDeviceHost::OnGetSupportedVideoCaptureFormats(
+ ppapi::host::HostMessageContext* context) {
+ if (video_capture_formats_reply_context_.is_valid())
+ return PP_ERROR_INPROGRESS;
+ if (!platform_camera_device_)
+ return PP_ERROR_FAILED;
+
+ video_capture_formats_reply_context_ = context->MakeReplyMessageContext();
+ platform_camera_device_->GetSupportedVideoCaptureFormats();
+
+ return PP_OK_COMPLETIONPENDING;
+}
+
+void PepperCameraDeviceHost::DetachPlatformCameraDevice() {
+ if (platform_camera_device_) {
+ platform_camera_device_->DetachEventHandler();
+ platform_camera_device_.reset();
+ }
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/pepper/pepper_camera_device_host.h b/chromium/content/renderer/pepper/pepper_camera_device_host.h
new file mode 100644
index 00000000000..3a13cac5704
--- /dev/null
+++ b/chromium/content/renderer/pepper/pepper_camera_device_host.h
@@ -0,0 +1,67 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_PEPPER_PEPPER_CAMERA_DEVICE_HOST_H_
+#define CONTENT_RENDERER_PEPPER_PEPPER_CAMERA_DEVICE_HOST_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "content/public/renderer/renderer_ppapi_host.h"
+#include "content/renderer/pepper/ppb_buffer_impl.h"
+#include "ppapi/c/pp_size.h"
+#include "ppapi/c/private/pp_video_capture_format.h"
+#include "ppapi/host/host_message_context.h"
+#include "ppapi/host/resource_host.h"
+
+namespace content {
+class PepperPlatformCameraDevice;
+class RendererPpapiHostImpl;
+
+class PepperCameraDeviceHost : public ppapi::host::ResourceHost {
+ public:
+ PepperCameraDeviceHost(RendererPpapiHostImpl* host,
+ PP_Instance instance,
+ PP_Resource resource);
+
+ ~PepperCameraDeviceHost() override;
+
+ bool Init();
+
+ int32_t OnResourceMessageReceived(
+ const IPC::Message& msg,
+ ppapi::host::HostMessageContext* context) override;
+
+ // These methods are called by PepperPlatformCameraDevice only.
+
+ // Called when camera device is initialized.
+ void OnInitialized(bool succeeded);
+
+ // Called when the video capture formats are enumerated.
+ void OnVideoCaptureFormatsEnumerated(
+ const std::vector<PP_VideoCaptureFormat>& formats);
+
+ private:
+ // Plugin -> host message handlers.
+ int32_t OnOpen(ppapi::host::HostMessageContext* context,
+ const std::string& device_id);
+ int32_t OnClose(ppapi::host::HostMessageContext* context);
+ int32_t OnGetSupportedVideoCaptureFormats(
+ ppapi::host::HostMessageContext* context);
+
+ // Utility methods.
+ void DetachPlatformCameraDevice();
+
+ scoped_ptr<PepperPlatformCameraDevice> platform_camera_device_;
+
+ RendererPpapiHostImpl* renderer_ppapi_host_;
+
+ ppapi::host::ReplyMessageContext open_reply_context_;
+
+ ppapi::host::ReplyMessageContext video_capture_formats_reply_context_;
+
+ DISALLOW_COPY_AND_ASSIGN(PepperCameraDeviceHost);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_PEPPER_PEPPER_CAMERA_DEVICE_HOST_H_
diff --git a/chromium/content/renderer/pepper/pepper_compositor_host.cc b/chromium/content/renderer/pepper/pepper_compositor_host.cc
index 284d36c3cae..d366db4bff7 100644
--- a/chromium/content/renderer/pepper/pepper_compositor_host.cc
+++ b/chromium/content/renderer/pepper/pepper_compositor_host.cc
@@ -4,6 +4,8 @@
#include "content/renderer/pepper/pepper_compositor_host.h"
+#include <limits>
+
#include "base/logging.h"
#include "base/memory/shared_memory.h"
#include "cc/layers/layer.h"
@@ -11,6 +13,8 @@
#include "cc/layers/texture_layer.h"
#include "cc/resources/texture_mailbox.h"
#include "cc/trees/layer_tree_host.h"
+#include "content/child/child_shared_bitmap_manager.h"
+#include "content/child/child_thread_impl.h"
#include "content/public/renderer/renderer_ppapi_host.h"
#include "content/renderer/pepper/gfx_conversion.h"
#include "content/renderer/pepper/host_globals.h"
@@ -33,6 +37,14 @@ namespace content {
namespace {
+bool CheckPPFloatRect(const PP_FloatRect& rect, float width, float height) {
+ const float kEpsilon = std::numeric_limits<float>::epsilon();
+ return (rect.point.x >= -kEpsilon &&
+ rect.point.y >= -kEpsilon &&
+ rect.point.x + rect.size.width <= width + kEpsilon &&
+ rect.point.y + rect.size.height <= height + kEpsilon);
+}
+
int32_t VerifyCommittedLayer(
const ppapi::CompositorLayerData* old_layer,
const ppapi::CompositorLayerData* new_layer,
@@ -61,6 +73,11 @@ int32_t VerifyCommittedLayer(
}
if (!new_layer->texture->mailbox.Verify())
return PP_ERROR_BADARGUMENT;
+
+ // Make sure the source rect is not beyond the dimensions of the
+ // texture.
+ if (!CheckPPFloatRect(new_layer->texture->source_rect, 1.0f, 1.0f))
+ return PP_ERROR_BADARGUMENT;
return PP_OK;
}
@@ -77,6 +94,7 @@ int32_t VerifyCommittedLayer(
return PP_OK;
}
}
+
EnterResourceNoLock<PPB_ImageData_API> enter(new_layer->image->resource,
true);
if (enter.failed())
@@ -90,6 +108,13 @@ int32_t VerifyCommittedLayer(
return PP_ERROR_BADARGUMENT;
}
+ // Make sure the source rect is not beyond the dimensions of the
+ // image.
+ if (!CheckPPFloatRect(new_layer->image->source_rect,
+ desc.size.width, desc.size.height)) {
+ return PP_ERROR_BADARGUMENT;
+ }
+
int handle;
uint32_t byte_count;
if (enter.object()->GetSharedMemory(&handle, &byte_count) != PP_OK)
@@ -168,13 +193,14 @@ void PepperCompositorHost::ViewInitiatedPaint() {
SendCommitLayersReplyIfNecessary();
}
-void PepperCompositorHost::ViewFlushedPaint() {}
-
void PepperCompositorHost::ImageReleased(
int32_t id,
- const scoped_ptr<base::SharedMemory>& shared_memory,
+ scoped_ptr<base::SharedMemory> shared_memory,
+ scoped_ptr<cc::SharedBitmap> bitmap,
uint32_t sync_point,
bool is_lost) {
+ bitmap.reset();
+ shared_memory.reset();
ResourceReleased(id, sync_point, is_lost);
}
@@ -284,15 +310,18 @@ void PepperCompositorHost::UpdateLayer(
DCHECK_EQ(rv, PP_TRUE);
DCHECK_EQ(desc.stride, desc.size.width * 4);
DCHECK_EQ(desc.format, PP_IMAGEDATAFORMAT_RGBA_PREMUL);
-
- cc::TextureMailbox mailbox(image_shm.get(),
- PP_ToGfxSize(desc.size));
- image_layer->SetTextureMailbox(mailbox,
- cc::SingleReleaseCallback::Create(
- base::Bind(&PepperCompositorHost::ImageReleased,
- weak_factory_.GetWeakPtr(),
- new_layer->common.resource_id,
- base::Passed(&image_shm))));
+ scoped_ptr<cc::SharedBitmap> bitmap =
+ ChildThreadImpl::current()
+ ->shared_bitmap_manager()
+ ->GetBitmapForSharedMemory(image_shm.get());
+
+ cc::TextureMailbox mailbox(bitmap.get(), PP_ToGfxSize(desc.size));
+ image_layer->SetTextureMailbox(
+ mailbox,
+ cc::SingleReleaseCallback::Create(base::Bind(
+ &PepperCompositorHost::ImageReleased, weak_factory_.GetWeakPtr(),
+ new_layer->common.resource_id, base::Passed(&image_shm),
+ base::Passed(&bitmap))));
// TODO(penghuang): get a damage region from the application and
// pass it to SetNeedsDisplayRect().
image_layer->SetNeedsDisplay();
diff --git a/chromium/content/renderer/pepper/pepper_compositor_host.h b/chromium/content/renderer/pepper/pepper_compositor_host.h
index d0ecac0b800..cd17aef4c9f 100644
--- a/chromium/content/renderer/pepper/pepper_compositor_host.h
+++ b/chromium/content/renderer/pepper/pepper_compositor_host.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_RENDERER_PEPPER_PEPPER_COMPOSITOR_H_
-#define CONTENT_RENDERER_PEPPER_PEPPER_COMPOSITOR_H_
+#ifndef CONTENT_RENDERER_PEPPER_PEPPER_COMPOSITOR_HOST_H_
+#define CONTENT_RENDERER_PEPPER_PEPPER_COMPOSITOR_HOST_H_
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
@@ -18,6 +18,7 @@ class SharedMemory;
namespace cc {
class Layer;
+class SharedBitmap;
} // namespace cc
namespace content {
@@ -39,13 +40,13 @@ class PepperCompositorHost : public ppapi::host::ResourceHost {
const scoped_refptr<cc::Layer> layer() { return layer_; };
void ViewInitiatedPaint();
- void ViewFlushedPaint();
private:
~PepperCompositorHost() override;
void ImageReleased(int32_t id,
- const scoped_ptr<base::SharedMemory>& shared_memory,
+ scoped_ptr<base::SharedMemory> shared_memory,
+ scoped_ptr<cc::SharedBitmap> bitmap,
uint32_t sync_point,
bool is_lost);
void ResourceReleased(int32_t id,
@@ -99,4 +100,4 @@ class PepperCompositorHost : public ppapi::host::ResourceHost {
} // namespace content
-#endif // CONTENT_RENDERER_PEPPER_PEPPER_COMPOSITOR_H_
+#endif // CONTENT_RENDERER_PEPPER_PEPPER_COMPOSITOR_HOST_H_
diff --git a/chromium/content/renderer/pepper/pepper_file_chooser_host_unittest.cc b/chromium/content/renderer/pepper/pepper_file_chooser_host_unittest.cc
index 3df6520440e..0585b04416b 100644
--- a/chromium/content/renderer/pepper/pepper_file_chooser_host_unittest.cc
+++ b/chromium/content/renderer/pepper/pepper_file_chooser_host_unittest.cc
@@ -36,7 +36,6 @@ class PepperFileChooserHostTest : public RenderViewTest {
void SetUp() override {
SetContentClient(&client_);
RenderViewTest::SetUp();
- ppapi::ProxyLock::DisableLockingOnThreadForTest();
globals_.GetResourceTracker()->DidCreateInstance(pp_instance_);
}
@@ -51,6 +50,8 @@ class PepperFileChooserHostTest : public RenderViewTest {
private:
PP_Instance pp_instance_;
+ // Disables locking for the duration of the test.
+ ppapi::ProxyLock::LockingDisablerForTest disable_locking_;
ppapi::TestGlobals globals_;
TestContentClient client_;
};
@@ -91,7 +92,7 @@ TEST_F(PepperFileChooserHostTest, Show) {
ASSERT_TRUE(msg);
ViewHostMsg_RunFileChooser::Schema::Param call_msg_param;
ASSERT_TRUE(ViewHostMsg_RunFileChooser::Read(msg, &call_msg_param));
- const FileChooserParams& chooser_params = call_msg_param.a;
+ const FileChooserParams& chooser_params = get<0>(call_msg_param);
// Basic validation of request.
EXPECT_EQ(FileChooserParams::Open, chooser_params.mode);
@@ -123,7 +124,7 @@ TEST_F(PepperFileChooserHostTest, Show) {
ASSERT_TRUE(
PpapiPluginMsg_FileChooser_ShowReply::Read(&reply_msg, &reply_msg_param));
const std::vector<ppapi::FileRefCreateInfo>& chooser_results =
- reply_msg_param.a;
+ get<0>(reply_msg_param);
ASSERT_EQ(1u, chooser_results.size());
EXPECT_EQ(FilePathToUTF8(selected_info.display_name),
chooser_results[0].display_name);
diff --git a/chromium/content/renderer/pepper/pepper_file_system_host.cc b/chromium/content/renderer/pepper/pepper_file_system_host.cc
index 69945341014..bce63a28be0 100644
--- a/chromium/content/renderer/pepper/pepper_file_system_host.cc
+++ b/chromium/content/renderer/pepper/pepper_file_system_host.cc
@@ -6,7 +6,7 @@
#include "base/bind.h"
#include "base/callback.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
#include "content/child/fileapi/file_system_dispatcher.h"
#include "content/common/pepper_file_util.h"
#include "content/renderer/pepper/pepper_plugin_instance_impl.h"
@@ -102,7 +102,7 @@ int32_t PepperFileSystemHost::OnHostMsgOpen(
return PP_ERROR_FAILED;
FileSystemDispatcher* file_system_dispatcher =
- ChildThread::current()->file_system_dispatcher();
+ ChildThreadImpl::current()->file_system_dispatcher();
reply_context_ = context->MakeReplyMessageContext();
file_system_dispatcher->OpenFileSystem(
document_url.GetOrigin(),
diff --git a/chromium/content/renderer/pepper/pepper_graphics_2d_host.cc b/chromium/content/renderer/pepper/pepper_graphics_2d_host.cc
index 790ac761421..4449e4a5583 100644
--- a/chromium/content/renderer/pepper/pepper_graphics_2d_host.cc
+++ b/chromium/content/renderer/pepper/pepper_graphics_2d_host.cc
@@ -5,9 +5,9 @@
#include "content/renderer/pepper/pepper_graphics_2d_host.h"
#include "base/bind.h"
-#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
+#include "base/trace_event/trace_event.h"
#include "cc/resources/shared_bitmap.h"
#include "cc/resources/texture_mailbox.h"
#include "content/child/child_shared_bitmap_manager.h"
@@ -15,6 +15,7 @@
#include "content/public/renderer/renderer_ppapi_host.h"
#include "content/renderer/pepper/gfx_conversion.h"
#include "content/renderer/pepper/pepper_plugin_instance_impl.h"
+#include "content/renderer/pepper/plugin_instance_throttler_impl.h"
#include "content/renderer/pepper/ppb_image_data_impl.h"
#include "content/renderer/render_thread_impl.h"
#include "ppapi/c/pp_bool.h"
@@ -30,15 +31,14 @@
#include "skia/ext/platform_canvas.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/blit.h"
-#include "ui/gfx/point_conversions.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/rect_conversions.h"
+#include "ui/gfx/geometry/point_conversions.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
-#include "ui/gfx/size_conversions.h"
#include "ui/gfx/skia_util.h"
#if defined(OS_MACOSX)
-#include "base/mac/mac_util.h"
#include "base/mac/scoped_cftyperef.h"
#endif
@@ -383,10 +383,8 @@ void PepperGraphics2DHost::Paint(blink::WebCanvas* canvas,
canvas->drawBitmap(image, pixel_origin.x(), pixel_origin.y(), &paint);
}
-void PepperGraphics2DHost::ViewInitiatedPaint() {}
-
-void PepperGraphics2DHost::ViewFlushedPaint() {
- TRACE_EVENT0("pepper", "PepperGraphics2DHost::ViewFlushedPaint");
+void PepperGraphics2DHost::ViewInitiatedPaint() {
+ TRACE_EVENT0("pepper", "PepperGraphics2DHost::ViewInitiatedPaint");
if (need_flush_ack_) {
SendFlushAck();
need_flush_ack_ = false;
@@ -591,7 +589,7 @@ bool PepperGraphics2DHost::PrepareTextureMailbox(
cc::SharedBitmap::CheckedSizeInBytes(pixel_image_size));
image_data_->Unmap();
- *mailbox = cc::TextureMailbox(shared_bitmap->memory(), pixel_image_size);
+ *mailbox = cc::TextureMailbox(shared_bitmap.get(), pixel_image_size);
*release_callback = cc::SingleReleaseCallback::Create(
base::Bind(&PepperGraphics2DHost::ReleaseCallback,
this->AsWeakPtr(),
@@ -690,6 +688,11 @@ int32_t PepperGraphics2DHost::Flush(PP_Resource* old_image_data) {
need_flush_ack_ = true;
}
+ if (bound_instance_ && bound_instance_->throttler() &&
+ bound_instance_->throttler()->needs_representative_keyframe()) {
+ bound_instance_->throttler()->OnImageFlush(image_data_->GetMappedBitmap());
+ }
+
return PP_OK_COMPLETIONPENDING;
}
diff --git a/chromium/content/renderer/pepper/pepper_graphics_2d_host.h b/chromium/content/renderer/pepper/pepper_graphics_2d_host.h
index 7347a0ace3d..df80cd556e7 100644
--- a/chromium/content/renderer/pepper/pepper_graphics_2d_host.h
+++ b/chromium/content/renderer/pepper/pepper_graphics_2d_host.h
@@ -16,8 +16,8 @@
#include "ppapi/host/resource_host.h"
#include "third_party/WebKit/public/platform/WebCanvas.h"
#include "ui/events/latency_info.h"
-#include "ui/gfx/point.h"
-#include "ui/gfx/size.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/size.h"
namespace cc {
class SharedBitmap;
@@ -78,7 +78,6 @@ class CONTENT_EXPORT PepperGraphics2DHost
// Notifications about the view's progress painting. See PluginInstance.
// These messages are used to send Flush callbacks to the plugin.
void ViewInitiatedPaint();
- void ViewFlushedPaint();
void SetScale(float scale);
float GetScale() const;
diff --git a/chromium/content/renderer/pepper/pepper_graphics_2d_host_unittest.cc b/chromium/content/renderer/pepper/pepper_graphics_2d_host_unittest.cc
index b0f7bdff37e..ad65748ffb4 100644
--- a/chromium/content/renderer/pepper/pepper_graphics_2d_host_unittest.cc
+++ b/chromium/content/renderer/pepper/pepper_graphics_2d_host_unittest.cc
@@ -16,8 +16,8 @@
#include "third_party/WebKit/public/platform/WebCanvas.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "ui/events/latency_info.h"
-#include "ui/gfx/point.h"
-#include "ui/gfx/rect.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
using blink::WebCanvas;
@@ -67,7 +67,7 @@ class PepperGraphics2DHostTest : public testing::Test {
ppapi::proxy::ResourceMessageCallParams(host_->pp_resource(), 0));
std::vector<ui::LatencyInfo> latency;
host_->OnHostMsgFlush(&context, latency);
- host_->ViewFlushedPaint();
+ host_->ViewInitiatedPaint();
host_->SendOffscreenFlushAck();
}
diff --git a/chromium/content/renderer/pepper/pepper_media_stream_audio_track_host.cc b/chromium/content/renderer/pepper/pepper_media_stream_audio_track_host.cc
index 72279f65290..c4b4694f113 100644
--- a/chromium/content/renderer/pepper/pepper_media_stream_audio_track_host.cc
+++ b/chromium/content/renderer/pepper/pepper_media_stream_audio_track_host.cc
@@ -12,6 +12,7 @@
#include "base/macros.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/numerics/safe_math.h"
+#include "media/base/audio_bus.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/c/ppb_audio_buffer.h"
#include "ppapi/host/dispatch_host_message.h"
@@ -66,14 +67,14 @@ namespace content {
PepperMediaStreamAudioTrackHost::AudioSink::AudioSink(
PepperMediaStreamAudioTrackHost* host)
: host_(host),
- buffer_data_size_(0),
active_buffer_index_(-1),
active_buffers_generation_(0),
- active_buffer_offset_(0),
+ active_buffer_frame_offset_(0),
buffers_generation_(0),
main_message_loop_proxy_(base::MessageLoopProxy::current()),
number_of_buffers_(kDefaultNumberOfBuffers),
bytes_per_second_(0),
+ bytes_per_frame_(0),
user_buffer_duration_(kDefaultDuration),
weak_factory_(this) {}
@@ -193,35 +194,33 @@ void PepperMediaStreamAudioTrackHost::AudioSink::
host_->SendEnqueueBufferMessageToPlugin(index);
}
-void PepperMediaStreamAudioTrackHost::AudioSink::OnData(const int16* audio_data,
- int sample_rate,
- int number_of_channels,
- int number_of_frames) {
+void PepperMediaStreamAudioTrackHost::AudioSink::OnData(
+ const media::AudioBus& audio_bus,
+ base::TimeTicks estimated_capture_time) {
DCHECK(audio_thread_checker_.CalledOnValidThread());
- DCHECK(audio_data);
- DCHECK_EQ(sample_rate, audio_params_.sample_rate());
- DCHECK_EQ(number_of_channels, audio_params_.channels());
- // Here, |number_of_frames| and |audio_params_.frames_per_buffer()| refer to
- // the incomming audio buffer. However, this doesn't necessarily equal
+ DCHECK(audio_params_.IsValid());
+ DCHECK_EQ(audio_bus.channels(), audio_params_.channels());
+ // Here, |audio_params_.frames_per_buffer()| refers to the incomming audio
+ // buffer. However, this doesn't necessarily equal
// |buffer->number_of_samples|, which is configured by the user when they set
// buffer duration.
- DCHECK_EQ(number_of_frames, audio_params_.frames_per_buffer());
+ DCHECK_EQ(audio_bus.frames(), audio_params_.frames_per_buffer());
+ DCHECK(!estimated_capture_time.is_null());
- const uint32_t bytes_per_frame = number_of_channels *
- audio_params_.bits_per_sample() / 8;
+ if (first_frame_capture_time_.is_null())
+ first_frame_capture_time_ = estimated_capture_time;
- int frames_remaining = number_of_frames;
- base::TimeDelta timestamp_offset;
+ const int bytes_per_frame = audio_params_.GetBytesPerFrame();
base::AutoLock lock(lock_);
- while (frames_remaining) {
+ for (int frame_offset = 0; frame_offset < audio_bus.frames(); ) {
if (active_buffers_generation_ != buffers_generation_) {
// Buffers have changed, so drop the active buffer.
active_buffer_index_ = -1;
}
if (active_buffer_index_ == -1 && !buffers_.empty()) {
active_buffers_generation_ = buffers_generation_;
- active_buffer_offset_ = 0;
+ active_buffer_frame_offset_ = 0;
active_buffer_index_ = buffers_.front();
buffers_.pop_front();
}
@@ -230,39 +229,43 @@ void PepperMediaStreamAudioTrackHost::AudioSink::OnData(const int16* audio_data,
break;
}
- // TODO(penghuang): support re-sampling, etc.
+ // TODO(penghuang): Support re-sampling and channel mixing by using
+ // media::AudioConverter.
ppapi::MediaStreamBuffer::Audio* buffer =
&(host_->buffer_manager()->GetBufferPointer(active_buffer_index_)
->audio);
- if (active_buffer_offset_ == 0) {
+ if (active_buffer_frame_offset_ == 0) {
// The active buffer is new, so initialise the header and metadata fields.
buffer->header.size = host_->buffer_manager()->buffer_size();
buffer->header.type = ppapi::MediaStreamBuffer::TYPE_AUDIO;
- buffer->timestamp = (timestamp_ + timestamp_offset).InMillisecondsF();
- buffer->sample_rate = static_cast<PP_AudioBuffer_SampleRate>(sample_rate);
+ const base::TimeTicks time_at_offset = estimated_capture_time +
+ frame_offset * base::TimeDelta::FromSeconds(1) /
+ audio_params_.sample_rate();
+ buffer->timestamp =
+ (time_at_offset - first_frame_capture_time_).InSecondsF();
+ buffer->sample_rate =
+ static_cast<PP_AudioBuffer_SampleRate>(audio_params_.sample_rate());
buffer->data_size = output_buffer_size_;
- buffer->number_of_channels = number_of_channels;
- buffer->number_of_samples = buffer->data_size * number_of_channels /
+ buffer->number_of_channels = audio_params_.channels();
+ buffer->number_of_samples = buffer->data_size * audio_params_.channels() /
bytes_per_frame;
}
- uint32_t buffer_bytes_remaining =
- buffer->data_size - active_buffer_offset_;
- DCHECK_EQ(buffer_bytes_remaining % bytes_per_frame, 0U);
- uint32_t incoming_bytes_remaining = frames_remaining * bytes_per_frame;
- uint32_t bytes_to_copy = std::min(buffer_bytes_remaining,
- incoming_bytes_remaining);
- uint32_t frames_to_copy = bytes_to_copy / bytes_per_frame;
- DCHECK_EQ(bytes_to_copy % bytes_per_frame, 0U);
- memcpy(buffer->data + active_buffer_offset_,
- audio_data, bytes_to_copy);
- active_buffer_offset_ += bytes_to_copy;
- audio_data += bytes_to_copy / sizeof(*audio_data);
- frames_remaining -= frames_to_copy;
- timestamp_offset += base::TimeDelta::FromMilliseconds(
- frames_to_copy * base::Time::kMillisecondsPerSecond / sample_rate);
-
- DCHECK_LE(active_buffer_offset_, buffer->data_size);
- if (active_buffer_offset_ == buffer->data_size) {
+
+ const int frames_per_buffer =
+ buffer->number_of_samples / audio_params_.channels();
+ const int frames_to_copy = std::min(
+ frames_per_buffer - active_buffer_frame_offset_,
+ audio_bus.frames() - frame_offset);
+ audio_bus.ToInterleavedPartial(
+ frame_offset,
+ frames_to_copy,
+ audio_params_.bits_per_sample() / 8,
+ buffer->data + active_buffer_frame_offset_ * bytes_per_frame);
+ active_buffer_frame_offset_ += frames_to_copy;
+ frame_offset += frames_to_copy;
+
+ DCHECK_LE(active_buffer_frame_offset_, frames_per_buffer);
+ if (active_buffer_frame_offset_ == frames_per_buffer) {
main_message_loop_proxy_->PostTask(
FROM_HERE,
base::Bind(&AudioSink::SendEnqueueBufferMessageOnMainThread,
@@ -272,7 +275,6 @@ void PepperMediaStreamAudioTrackHost::AudioSink::OnData(const int16* audio_data,
active_buffer_index_ = -1;
}
}
- timestamp_ += buffer_duration_;
}
void PepperMediaStreamAudioTrackHost::AudioSink::OnSetFormat(
@@ -288,28 +290,21 @@ void PepperMediaStreamAudioTrackHost::AudioSink::OnSetFormat(
DCHECK_NE(GetPPSampleRate(params.sample_rate()),
PP_AUDIOBUFFER_SAMPLERATE_UNKNOWN);
- audio_params_ = params;
-
// TODO(penghuang): support setting format more than once.
- buffer_duration_ = params.GetBufferDuration();
- buffer_data_size_ = params.GetBytesPerBuffer();
-
- if (original_audio_params_.IsValid()) {
- DCHECK_EQ(params.sample_rate(), original_audio_params_.sample_rate());
- DCHECK_EQ(params.bits_per_sample(),
- original_audio_params_.bits_per_sample());
- DCHECK_EQ(params.channels(), original_audio_params_.channels());
+ if (audio_params_.IsValid()) {
+ DCHECK_EQ(params.sample_rate(), audio_params_.sample_rate());
+ DCHECK_EQ(params.bits_per_sample(), audio_params_.bits_per_sample());
+ DCHECK_EQ(params.channels(), audio_params_.channels());
} else {
audio_thread_checker_.DetachFromThread();
- original_audio_params_ = params;
+ audio_params_ = params;
- int bytes_per_frame = params.channels() * params.bits_per_sample() / 8;
main_message_loop_proxy_->PostTask(
FROM_HERE,
base::Bind(&AudioSink::SetFormatOnMainThread,
weak_factory_.GetWeakPtr(),
params.GetBytesPerSecond(),
- bytes_per_frame));
+ params.GetBytesPerFrame()));
}
}
@@ -369,6 +364,13 @@ void PepperMediaStreamAudioTrackHost::OnNewBufferEnqueued() {
void PepperMediaStreamAudioTrackHost::DidConnectPendingHostToResource() {
if (!connected_) {
+ media::AudioParameters format =
+ MediaStreamAudioSink::GetFormatFromAudioTrack(track_);
+ // Although this should only be called on the audio capture thread, that
+ // can't happen until the sink is added to the audio track below.
+ if (format.IsValid())
+ audio_sink_.OnSetFormat(format);
+
MediaStreamAudioSink::AddToAudioTrack(&audio_sink_, track_);
connected_ = true;
}
diff --git a/chromium/content/renderer/pepper/pepper_media_stream_audio_track_host.h b/chromium/content/renderer/pepper/pepper_media_stream_audio_track_host.h
index 1580441fc11..2c93bd2d9aa 100644
--- a/chromium/content/renderer/pepper/pepper_media_stream_audio_track_host.h
+++ b/chromium/content/renderer/pepper/pepper_media_stream_audio_track_host.h
@@ -52,6 +52,16 @@ class PepperMediaStreamAudioTrackHost : public PepperMediaStreamTrackHostBase {
// Send a reply to the currently pending |Configure()| request.
void SendConfigureReply(int32_t result);
+ // MediaStreamAudioSink overrides:
+ // These two functions should be called on the audio thread.
+ // NOTE: For this specific instance, |OnSetFormat()| is also called on the
+ // main thread. However, the call to |OnSetFormat()| happens before this
+ // sink is added to an audio track, also on the main thread, which should
+ // avoid any potential races.
+ void OnData(const media::AudioBus& audio_bus,
+ base::TimeTicks estimated_capture_time) override;
+ void OnSetFormat(const media::AudioParameters& params) override;
+
private:
// Initializes buffers on the main thread.
void SetFormatOnMainThread(int bytes_per_second, int bytes_per_frame);
@@ -62,14 +72,6 @@ class PepperMediaStreamAudioTrackHost : public PepperMediaStreamTrackHostBase {
void SendEnqueueBufferMessageOnMainThread(int32_t index,
int32_t buffers_generation);
- // MediaStreamAudioSink overrides:
- // These two functions should be called on the audio thread.
- void OnData(const int16* audio_data,
- int sample_rate,
- int number_of_channels,
- int number_of_frames) override;
- void OnSetFormat(const media::AudioParameters& params) override;
-
// Unowned host which is available during the AudioSink's lifespan.
// It is mainly used in the main thread. But the audio thread will use
// host_->buffer_manager() to read some buffer properties. It is safe
@@ -77,27 +79,15 @@ class PepperMediaStreamAudioTrackHost : public PepperMediaStreamTrackHostBase {
// initialization.
PepperMediaStreamAudioTrackHost* host_;
- // Timestamp of the next received audio buffer.
- // Access only on the audio thread.
- base::TimeDelta timestamp_;
-
- // Duration of one audio buffer.
+ // The estimated capture time of the first sample frame of audio. This is
+ // used as the timebase to compute the buffer timestamps.
// Access only on the audio thread.
- base::TimeDelta buffer_duration_;
+ base::TimeTicks first_frame_capture_time_;
// The current audio parameters.
// Access only on the audio thread.
media::AudioParameters audio_params_;
- // The original audio parameters which is set in the first time of
- // OnSetFormat being called.
- // Access only on the audio thread.
- media::AudioParameters original_audio_params_;
-
- // The audio data size of one audio buffer in bytes.
- // Access only on the audio thread.
- uint32_t buffer_data_size_;
-
// Index of the currently active buffer.
// Access only on the audio thread.
int active_buffer_index_;
@@ -107,9 +97,9 @@ class PepperMediaStreamAudioTrackHost : public PepperMediaStreamTrackHostBase {
// Access only on the audio thread.
int32_t active_buffers_generation_;
- // Current offset, in bytes, within the currently active buffer.
+ // Current offset, in sample frames, within the currently active buffer.
// Access only on the audio thread.
- uint32_t active_buffer_offset_;
+ int active_buffer_frame_offset_;
// A lock to protect the index queue |buffers_|, |buffers_generation_|,
// buffers in |host_->buffer_manager()|, and |output_buffer_size_|.
diff --git a/chromium/content/renderer/pepper/pepper_media_stream_track_host_base.cc b/chromium/content/renderer/pepper/pepper_media_stream_track_host_base.cc
index c7713135a15..c9a75f6ffca 100644
--- a/chromium/content/renderer/pepper/pepper_media_stream_track_host_base.cc
+++ b/chromium/content/renderer/pepper/pepper_media_stream_track_host_base.cc
@@ -6,6 +6,7 @@
#include "base/logging.h"
#include "base/numerics/safe_math.h"
+#include "content/common/pepper_file_util.h"
#include "content/public/renderer/render_thread.h"
#include "content/public/renderer/renderer_ppapi_host.h"
#include "ppapi/c/pp_errors.h"
@@ -63,13 +64,7 @@ bool PepperMediaStreamTrackHostBase::InitBuffers(int32_t number_of_buffers,
}
base::PlatformFile platform_file =
-#if defined(OS_WIN)
- shm_handle;
-#elif defined(OS_POSIX)
- shm_handle.fd;
-#else
-#error Not implemented.
-#endif
+ PlatformFileFromSharedMemoryHandle(shm_handle);
SerializedHandle handle(host_->ShareHandleWithRemote(platform_file, false),
size.ValueOrDie());
bool readonly = (track_type == kRead);
diff --git a/chromium/content/renderer/pepper/pepper_media_stream_video_track_host.cc b/chromium/content/renderer/pepper/pepper_media_stream_video_track_host.cc
index ade9cafb3a1..14c6731d5d3 100644
--- a/chromium/content/renderer/pepper/pepper_media_stream_video_track_host.cc
+++ b/chromium/content/renderer/pepper/pepper_media_stream_video_track_host.cc
@@ -97,24 +97,24 @@ void ConvertFromMediaVideoFrame(const scoped_refptr<media::VideoFrame>& src,
uint8_t* dst) {
CHECK(src->format() == VideoFrame::YV12 || src->format() == VideoFrame::I420);
if (dst_format == PP_VIDEOFRAME_FORMAT_BGRA) {
- if (src->coded_size() == dst_size) {
- libyuv::I420ToARGB(src->data(VideoFrame::kYPlane),
+ if (src->visible_rect().size() == dst_size) {
+ libyuv::I420ToARGB(src->visible_data(VideoFrame::kYPlane),
src->stride(VideoFrame::kYPlane),
- src->data(VideoFrame::kUPlane),
+ src->visible_data(VideoFrame::kUPlane),
src->stride(VideoFrame::kUPlane),
- src->data(VideoFrame::kVPlane),
+ src->visible_data(VideoFrame::kVPlane),
src->stride(VideoFrame::kVPlane),
dst,
dst_size.width() * 4,
dst_size.width(),
dst_size.height());
} else {
- media::ScaleYUVToRGB32(src->data(VideoFrame::kYPlane),
- src->data(VideoFrame::kUPlane),
- src->data(VideoFrame::kVPlane),
+ media::ScaleYUVToRGB32(src->visible_data(VideoFrame::kYPlane),
+ src->visible_data(VideoFrame::kUPlane),
+ src->visible_data(VideoFrame::kVPlane),
dst,
- src->coded_size().width(),
- src->coded_size().height(),
+ src->visible_rect().width(),
+ src->visible_rect().height(),
dst_size.width(),
dst_size.height(),
src->stride(VideoFrame::kYPlane),
@@ -135,21 +135,21 @@ void ConvertFromMediaVideoFrame(const scoped_refptr<media::VideoFrame>& src,
const int plane_order = (dst_format == PP_VIDEOFRAME_FORMAT_YV12) ? 0 : 1;
int dst_width = dst_size.width();
int dst_height = dst_size.height();
- libyuv::ScalePlane(src->data(kPlanesOrder[plane_order][0]),
+ libyuv::ScalePlane(src->visible_data(kPlanesOrder[plane_order][0]),
src->stride(kPlanesOrder[plane_order][0]),
- src->coded_size().width(),
- src->coded_size().height(),
+ src->visible_rect().width(),
+ src->visible_rect().height(),
dst,
dst_width,
dst_width,
dst_height,
kFilterMode);
dst += dst_width * dst_height;
- const int src_halfwidth = (src->coded_size().width() + 1) >> 1;
- const int src_halfheight = (src->coded_size().height() + 1) >> 1;
+ const int src_halfwidth = (src->visible_rect().width() + 1) >> 1;
+ const int src_halfheight = (src->visible_rect().height() + 1) >> 1;
const int dst_halfwidth = (dst_width + 1) >> 1;
const int dst_halfheight = (dst_height + 1) >> 1;
- libyuv::ScalePlane(src->data(kPlanesOrder[plane_order][1]),
+ libyuv::ScalePlane(src->visible_data(kPlanesOrder[plane_order][1]),
src->stride(kPlanesOrder[plane_order][1]),
src_halfwidth,
src_halfheight,
@@ -159,7 +159,7 @@ void ConvertFromMediaVideoFrame(const scoped_refptr<media::VideoFrame>& src,
dst_halfheight,
kFilterMode);
dst += dst_halfwidth * dst_halfheight;
- libyuv::ScalePlane(src->data(kPlanesOrder[plane_order][2]),
+ libyuv::ScalePlane(src->visible_data(kPlanesOrder[plane_order][2]),
src->stride(kPlanesOrder[plane_order][2]),
src_halfwidth,
src_halfheight,
@@ -186,15 +186,13 @@ class PepperMediaStreamVideoTrackHost::FrameDeliverer
const scoped_refptr<base::MessageLoopProxy>& io_message_loop_proxy,
const VideoCaptureDeliverFrameCB& new_frame_callback);
- void DeliverVideoFrame(const scoped_refptr<media::VideoFrame>& frame,
- const media::VideoCaptureFormat& format);
+ void DeliverVideoFrame(const scoped_refptr<media::VideoFrame>& frame);
private:
friend class base::RefCountedThreadSafe<FrameDeliverer>;
virtual ~FrameDeliverer();
- void DeliverFrameOnIO(const scoped_refptr<media::VideoFrame>& frame,
- const media::VideoCaptureFormat& format);
+ void DeliverFrameOnIO(const scoped_refptr<media::VideoFrame>& frame);
scoped_refptr<base::MessageLoopProxy> io_message_loop_;
VideoCaptureDeliverFrameCB new_frame_callback_;
@@ -213,21 +211,18 @@ PepperMediaStreamVideoTrackHost::FrameDeliverer::~FrameDeliverer() {
}
void PepperMediaStreamVideoTrackHost::FrameDeliverer::DeliverVideoFrame(
- const scoped_refptr<media::VideoFrame>& frame,
- const media::VideoCaptureFormat& format) {
+ const scoped_refptr<media::VideoFrame>& frame) {
io_message_loop_->PostTask(
FROM_HERE,
- base::Bind(&FrameDeliverer::DeliverFrameOnIO,
- this, frame, format));
+ base::Bind(&FrameDeliverer::DeliverFrameOnIO, this, frame));
}
void PepperMediaStreamVideoTrackHost::FrameDeliverer::DeliverFrameOnIO(
- const scoped_refptr<media::VideoFrame>& frame,
- const media::VideoCaptureFormat& format) {
+ const scoped_refptr<media::VideoFrame>& frame) {
DCHECK(io_message_loop_->BelongsToCurrentThread());
// The time when this frame is generated is unknown so give a null value to
// |estimated_capture_time|.
- new_frame_callback_.Run(frame, format, base::TimeTicks());
+ new_frame_callback_.Run(frame, base::TimeTicks());
}
PepperMediaStreamVideoTrackHost::PepperMediaStreamVideoTrackHost(
@@ -369,11 +364,7 @@ int32_t PepperMediaStreamVideoTrackHost::SendFrameToTrack(int32_t index) {
base::TimeDelta::FromMilliseconds(ts_ms),
base::Closure());
- frame_deliverer_->DeliverVideoFrame(
- frame,
- media::VideoCaptureFormat(plugin_frame_size_,
- kDefaultOutputFrameRate,
- ToPixelFormat(plugin_frame_format_)));
+ frame_deliverer_->DeliverVideoFrame(frame);
}
// Makes the frame available again for plugin.
@@ -383,7 +374,6 @@ int32_t PepperMediaStreamVideoTrackHost::SendFrameToTrack(int32_t index) {
void PepperMediaStreamVideoTrackHost::OnVideoFrame(
const scoped_refptr<VideoFrame>& frame,
- const media::VideoCaptureFormat& format,
const base::TimeTicks& estimated_capture_time) {
DCHECK(frame.get());
// TODO(penghuang): Check |frame->end_of_stream()| and close the track.
@@ -392,7 +382,7 @@ void PepperMediaStreamVideoTrackHost::OnVideoFrame(
return;
if (source_frame_size_.IsEmpty()) {
- source_frame_size_ = frame->coded_size();
+ source_frame_size_ = frame->visible_rect().size();
source_frame_format_ = ppformat;
InitBuffers();
}
@@ -443,6 +433,7 @@ void PepperMediaStreamVideoTrackHost::GetCurrentSupportedFormats(
void PepperMediaStreamVideoTrackHost::StartSourceImpl(
const media::VideoCaptureFormat& format,
+ const blink::WebMediaConstraints& constraints,
const VideoCaptureDeliverFrameCB& frame_callback) {
output_started_ = true;
frame_deliverer_ = new FrameDeliverer(io_message_loop(), frame_callback);
@@ -523,7 +514,8 @@ void PepperMediaStreamVideoTrackHost::InitBlinkTrack() {
blink::WebMediaStreamSource webkit_source;
webkit_source.initialize(base::UTF8ToUTF16(source_id),
blink::WebMediaStreamSource::TypeVideo,
- base::UTF8ToUTF16(kPepperVideoSourceName));
+ base::UTF8ToUTF16(kPepperVideoSourceName),
+ false /* remote */, true /* readonly */);
webkit_source.setExtraData(this);
const bool enabled = true;
diff --git a/chromium/content/renderer/pepper/pepper_media_stream_video_track_host.h b/chromium/content/renderer/pepper/pepper_media_stream_video_track_host.h
index 1ed80524550..b0c7f679139 100644
--- a/chromium/content/renderer/pepper/pepper_media_stream_video_track_host.h
+++ b/chromium/content/renderer/pepper/pepper_media_stream_video_track_host.h
@@ -14,7 +14,7 @@
#include "ppapi/c/ppb_video_frame.h"
#include "ppapi/shared_impl/media_stream_video_track_shared.h"
#include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
-#include "ui/gfx/size.h"
+#include "ui/gfx/geometry/size.h"
namespace content {
@@ -56,7 +56,6 @@ class PepperMediaStreamVideoTrackHost : public PepperMediaStreamTrackHostBase,
int32_t SendFrameToTrack(int32_t index);
void OnVideoFrame(const scoped_refptr<media::VideoFrame>& frame,
- const media::VideoCaptureFormat& format,
const base::TimeTicks& estimated_capture_time);
// MediaStreamVideoSource overrides:
@@ -68,6 +67,7 @@ class PepperMediaStreamVideoTrackHost : public PepperMediaStreamTrackHostBase,
void StartSourceImpl(
const media::VideoCaptureFormat& format,
+ const blink::WebMediaConstraints& constraints,
const VideoCaptureDeliverFrameCB& frame_callback) override;
void StopSourceImpl() override;
diff --git a/chromium/content/renderer/pepper/pepper_platform_audio_input.cc b/chromium/content/renderer/pepper/pepper_platform_audio_input.cc
index 9b461206805..04c14a70543 100644
--- a/chromium/content/renderer/pepper/pepper_platform_audio_input.cc
+++ b/chromium/content/renderer/pepper/pepper_platform_audio_input.cc
@@ -167,7 +167,7 @@ bool PepperPlatformAudioInput::Initialize(
ipc_ = RenderThreadImpl::current()
->audio_input_message_filter()
- ->CreateAudioInputIPC(render_frame->render_view()->GetRoutingID());
+ ->CreateAudioInputIPC(render_frame_id);
params_.Reset(media::AudioParameters::AUDIO_PCM_LINEAR,
media::CHANNEL_LAYOUT_MONO,
diff --git a/chromium/content/renderer/pepper/pepper_platform_audio_output.cc b/chromium/content/renderer/pepper/pepper_platform_audio_output.cc
index 7d65685cafa..ce18f86b9d2 100644
--- a/chromium/content/renderer/pepper/pepper_platform_audio_output.cc
+++ b/chromium/content/renderer/pepper/pepper_platform_audio_output.cc
@@ -22,14 +22,12 @@ namespace content {
PepperPlatformAudioOutput* PepperPlatformAudioOutput::Create(
int sample_rate,
int frames_per_buffer,
- int source_render_view_id,
int source_render_frame_id,
AudioHelper* client) {
scoped_refptr<PepperPlatformAudioOutput> audio_output(
new PepperPlatformAudioOutput());
if (audio_output->Initialize(sample_rate,
frames_per_buffer,
- source_render_view_id,
source_render_frame_id,
client)) {
// Balanced by Release invoked in
@@ -119,7 +117,6 @@ PepperPlatformAudioOutput::PepperPlatformAudioOutput()
bool PepperPlatformAudioOutput::Initialize(int sample_rate,
int frames_per_buffer,
- int source_render_view_id,
int source_render_frame_id,
AudioHelper* client) {
DCHECK(client);
@@ -127,7 +124,7 @@ bool PepperPlatformAudioOutput::Initialize(int sample_rate,
RenderThreadImpl* const render_thread = RenderThreadImpl::current();
ipc_ = render_thread->audio_message_filter()->CreateAudioOutputIPC(
- source_render_view_id, source_render_frame_id);
+ source_render_frame_id);
CHECK(ipc_);
media::AudioParameters params(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
diff --git a/chromium/content/renderer/pepper/pepper_platform_audio_output.h b/chromium/content/renderer/pepper/pepper_platform_audio_output.h
index 8c1c45cd9be..c0f455b592d 100644
--- a/chromium/content/renderer/pepper/pepper_platform_audio_output.h
+++ b/chromium/content/renderer/pepper/pepper_platform_audio_output.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_RENDERER_PEPPER_PEPPER_PLATFORM_AUDIO_OUTPUT_IMPL_H_
-#define CONTENT_RENDERER_PEPPER_PEPPER_PLATFORM_AUDIO_OUTPUT_IMPL_H_
+#ifndef CONTENT_RENDERER_PEPPER_PEPPER_PLATFORM_AUDIO_OUTPUT_H_
+#define CONTENT_RENDERER_PEPPER_PEPPER_PLATFORM_AUDIO_OUTPUT_H_
#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
@@ -29,7 +29,6 @@ class PepperPlatformAudioOutput
// when the stream is created.
static PepperPlatformAudioOutput* Create(int sample_rate,
int frames_per_buffer,
- int source_render_view_id,
int source_render_frame_id,
AudioHelper* client);
@@ -64,7 +63,6 @@ class PepperPlatformAudioOutput
bool Initialize(int sample_rate,
int frames_per_buffer,
- int source_render_view_id,
int source_render_frame_id,
AudioHelper* client);
@@ -90,4 +88,4 @@ class PepperPlatformAudioOutput
} // namespace content
-#endif // CONTENT_RENDERER_PEPPER_PEPPER_PLATFORM_AUDIO_OUTPUT_IMPL_H_
+#endif // CONTENT_RENDERER_PEPPER_PEPPER_PLATFORM_AUDIO_OUTPUT_H_
diff --git a/chromium/content/renderer/pepper/pepper_platform_camera_device.cc b/chromium/content/renderer/pepper/pepper_platform_camera_device.cc
new file mode 100644
index 00000000000..c3dfff222a6
--- /dev/null
+++ b/chromium/content/renderer/pepper/pepper_platform_camera_device.cc
@@ -0,0 +1,131 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/pepper/pepper_platform_camera_device.h"
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "content/renderer/media/video_capture_impl_manager.h"
+#include "content/renderer/pepper/gfx_conversion.h"
+#include "content/renderer/pepper/pepper_camera_device_host.h"
+#include "content/renderer/pepper/pepper_media_device_manager.h"
+#include "content/renderer/render_frame_impl.h"
+#include "content/renderer/render_thread_impl.h"
+#include "media/base/bind_to_current_loop.h"
+#include "url/gurl.h"
+
+namespace content {
+
+PepperPlatformCameraDevice::PepperPlatformCameraDevice(
+ int render_frame_id,
+ const std::string& device_id,
+ const GURL& document_url,
+ PepperCameraDeviceHost* handler)
+ : render_frame_id_(render_frame_id),
+ device_id_(device_id),
+ session_id_(0),
+ handler_(handler),
+ pending_open_device_(false),
+ pending_open_device_id_(-1),
+ weak_factory_(this) {
+ // We need to open the device and obtain the label and session ID before
+ // initializing.
+ PepperMediaDeviceManager* const device_manager = GetMediaDeviceManager();
+ if (device_manager) {
+ pending_open_device_id_ = device_manager->OpenDevice(
+ PP_DEVICETYPE_DEV_VIDEOCAPTURE, device_id, document_url,
+ base::Bind(&PepperPlatformCameraDevice::OnDeviceOpened,
+ weak_factory_.GetWeakPtr()));
+ pending_open_device_ = true;
+ }
+}
+
+void PepperPlatformCameraDevice::GetSupportedVideoCaptureFormats() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ VideoCaptureImplManager* manager =
+ RenderThreadImpl::current()->video_capture_impl_manager();
+ manager->GetDeviceSupportedFormats(
+ session_id_,
+ media::BindToCurrentLoop(base::Bind(
+ &PepperPlatformCameraDevice::OnDeviceSupportedFormatsEnumerated,
+ weak_factory_.GetWeakPtr())));
+}
+
+void PepperPlatformCameraDevice::DetachEventHandler() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ handler_ = NULL;
+ if (!release_device_cb_.is_null()) {
+ base::ResetAndReturn(&release_device_cb_).Run();
+ }
+ if (!label_.empty()) {
+ PepperMediaDeviceManager* const device_manager = GetMediaDeviceManager();
+ if (device_manager)
+ device_manager->CloseDevice(label_);
+ label_.clear();
+ }
+ if (pending_open_device_) {
+ PepperMediaDeviceManager* const device_manager = GetMediaDeviceManager();
+ if (device_manager)
+ device_manager->CancelOpenDevice(pending_open_device_id_);
+ pending_open_device_ = false;
+ pending_open_device_id_ = -1;
+ }
+}
+
+PepperPlatformCameraDevice::~PepperPlatformCameraDevice() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(release_device_cb_.is_null());
+ DCHECK(label_.empty());
+ DCHECK(!pending_open_device_);
+}
+
+void PepperPlatformCameraDevice::OnDeviceOpened(int request_id,
+ bool succeeded,
+ const std::string& label) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(handler_);
+
+ pending_open_device_ = false;
+ pending_open_device_id_ = -1;
+
+ PepperMediaDeviceManager* const device_manager = GetMediaDeviceManager();
+ succeeded = succeeded && device_manager;
+ if (succeeded) {
+ label_ = label;
+ session_id_ =
+ device_manager->GetSessionID(PP_DEVICETYPE_DEV_VIDEOCAPTURE, label);
+ VideoCaptureImplManager* manager =
+ RenderThreadImpl::current()->video_capture_impl_manager();
+ release_device_cb_ = manager->UseDevice(session_id_);
+ }
+
+ handler_->OnInitialized(succeeded);
+}
+
+void PepperPlatformCameraDevice::OnDeviceSupportedFormatsEnumerated(
+ const media::VideoCaptureFormats& formats) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(handler_);
+
+ std::vector<PP_VideoCaptureFormat> output_formats;
+ for (const auto& format : formats) {
+ PP_VideoCaptureFormat output_format;
+ output_format.frame_size = PP_FromGfxSize(format.frame_size);
+ output_format.frame_rate = format.frame_rate;
+ output_formats.push_back(output_format);
+ }
+ handler_->OnVideoCaptureFormatsEnumerated(output_formats);
+}
+
+PepperMediaDeviceManager* PepperPlatformCameraDevice::GetMediaDeviceManager() {
+ RenderFrameImpl* const render_frame =
+ RenderFrameImpl::FromRoutingID(render_frame_id_);
+ return render_frame
+ ? PepperMediaDeviceManager::GetForRenderFrame(render_frame).get()
+ : NULL;
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/pepper/pepper_platform_camera_device.h b/chromium/content/renderer/pepper/pepper_platform_camera_device.h
new file mode 100644
index 00000000000..bccfdb3da1b
--- /dev/null
+++ b/chromium/content/renderer/pepper/pepper_platform_camera_device.h
@@ -0,0 +1,73 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_PEPPER_PEPPER_PLATFORM_CAMERA_DEVICE_H_
+#define CONTENT_RENDERER_PEPPER_PEPPER_PLATFORM_CAMERA_DEVICE_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
+#include "content/common/media/video_capture.h"
+#include "media/base/video_capture_types.h"
+
+class GURL;
+
+namespace content {
+class PepperMediaDeviceManager;
+class PepperCameraDeviceHost;
+
+// This object must only be used on the thread it's constructed on.
+class PepperPlatformCameraDevice {
+ public:
+ PepperPlatformCameraDevice(int render_frame_id,
+ const std::string& device_id,
+ const GURL& document_url,
+ PepperCameraDeviceHost* handler);
+ ~PepperPlatformCameraDevice();
+
+ // Detaches the event handler and stops sending notifications to it.
+ void DetachEventHandler();
+
+ void GetSupportedVideoCaptureFormats();
+
+ private:
+ void OnDeviceOpened(int request_id, bool succeeded, const std::string& label);
+
+ // Called by VideoCaptureImplManager.
+ void OnDeviceSupportedFormatsEnumerated(
+ const media::VideoCaptureFormats& formats);
+
+ // Can return NULL if the RenderFrame referenced by |render_frame_id_| has
+ // gone away.
+ PepperMediaDeviceManager* GetMediaDeviceManager();
+
+ const int render_frame_id_;
+ const std::string device_id_;
+
+ std::string label_;
+ int session_id_;
+ base::Closure release_device_cb_;
+
+ PepperCameraDeviceHost* handler_;
+
+ // Whether we have a pending request to open a device. We have to make sure
+ // there isn't any pending request before this object goes away.
+ bool pending_open_device_;
+ int pending_open_device_id_;
+
+ base::ThreadChecker thread_checker_;
+
+ base::WeakPtrFactory<PepperPlatformCameraDevice> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(PepperPlatformCameraDevice);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_PEPPER_PEPPER_PLATFORM_CAMERA_DEVICE_H_
diff --git a/chromium/content/renderer/pepper/pepper_platform_video_capture.cc b/chromium/content/renderer/pepper/pepper_platform_video_capture.cc
index 0d011f3fdc4..68ef4800402 100644
--- a/chromium/content/renderer/pepper/pepper_platform_video_capture.cc
+++ b/chromium/content/renderer/pepper/pepper_platform_video_capture.cc
@@ -142,10 +142,9 @@ void PepperPlatformVideoCapture::OnStateUpdate(VideoCaptureState state) {
void PepperPlatformVideoCapture::OnFrameReady(
const scoped_refptr<media::VideoFrame>& frame,
- const media::VideoCaptureFormat& format,
const base::TimeTicks& estimated_capture_time) {
if (handler_ && !stop_capture_cb_.is_null())
- handler_->OnFrameReady(frame, format);
+ handler_->OnFrameReady(frame);
}
PepperMediaDeviceManager* PepperPlatformVideoCapture::GetMediaDeviceManager() {
diff --git a/chromium/content/renderer/pepper/pepper_platform_video_capture.h b/chromium/content/renderer/pepper/pepper_platform_video_capture.h
index 2412f492bd6..dd6ed78dade 100644
--- a/chromium/content/renderer/pepper/pepper_platform_video_capture.h
+++ b/chromium/content/renderer/pepper/pepper_platform_video_capture.h
@@ -15,7 +15,7 @@
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
#include "content/common/media/video_capture.h"
-#include "media/video/capture/video_capture_types.h"
+#include "media/base/video_capture_types.h"
class GURL;
@@ -42,7 +42,6 @@ class PepperPlatformVideoCapture {
void OnDeviceOpened(int request_id, bool succeeded, const std::string& label);
void OnStateUpdate(VideoCaptureState state);
void OnFrameReady(const scoped_refptr<media::VideoFrame>& frame,
- const media::VideoCaptureFormat& format,
const base::TimeTicks& estimated_capture_time);
// Can return NULL if the RenderFrame referenced by |render_frame_id_| has
diff --git a/chromium/content/renderer/pepper/pepper_plugin_instance_impl.cc b/chromium/content/renderer/pepper/pepper_plugin_instance_impl.cc
index 5886cf1f71f..85dfd025883 100644
--- a/chromium/content/renderer/pepper/pepper_plugin_instance_impl.cc
+++ b/chromium/content/renderer/pepper/pepper_plugin_instance_impl.cc
@@ -6,27 +6,25 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
-#include "base/command_line.h"
-#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/memory/linked_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram.h"
-#include "base/metrics/sparse_histogram.h"
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_offset_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
-#include "cc/base/latency_info_swap_promise.h"
+#include "base/trace_event/trace_event.h"
#include "cc/blink/web_layer_impl.h"
#include "cc/layers/texture_layer.h"
+#include "cc/output/latency_info_swap_promise.h"
#include "cc/trees/layer_tree_host.h"
#include "content/common/content_constants_internal.h"
#include "content/common/frame_messages.h"
#include "content/common/input/web_input_event_traits.h"
+#include "content/common/view_messages.h"
#include "content/public/common/content_constants.h"
-#include "content/public/common/content_switches.h"
#include "content/public/common/page_zoom.h"
#include "content/public/renderer/content_renderer_client.h"
#include "content/renderer/gpu/render_widget_compositor.h"
@@ -42,13 +40,12 @@
#include "content/renderer/pepper/pepper_file_ref_renderer_host.h"
#include "content/renderer/pepper/pepper_graphics_2d_host.h"
#include "content/renderer/pepper/pepper_in_process_router.h"
-#include "content/renderer/pepper/pepper_plugin_instance_impl.h"
-#include "content/renderer/pepper/pepper_plugin_instance_throttler.h"
+#include "content/renderer/pepper/pepper_plugin_instance_metrics.h"
#include "content/renderer/pepper/pepper_try_catch.h"
#include "content/renderer/pepper/pepper_url_loader_host.h"
+#include "content/renderer/pepper/plugin_instance_throttler_impl.h"
#include "content/renderer/pepper/plugin_module.h"
#include "content/renderer/pepper/plugin_object.h"
-#include "content/renderer/pepper/plugin_power_saver_helper.h"
#include "content/renderer/pepper/ppapi_preferences_builder.h"
#include "content/renderer/pepper/ppb_buffer_impl.h"
#include "content/renderer/pepper/ppb_graphics_3d_impl.h"
@@ -85,7 +82,6 @@
#include "ppapi/proxy/uma_private_resource.h"
#include "ppapi/proxy/url_loader_resource.h"
#include "ppapi/shared_impl/ppapi_permissions.h"
-#include "ppapi/shared_impl/ppapi_preferences.h"
#include "ppapi/shared_impl/ppb_gamepad_shared.h"
#include "ppapi/shared_impl/ppb_input_event_shared.h"
#include "ppapi/shared_impl/ppb_url_util_shared.h"
@@ -113,11 +109,11 @@
#include "third_party/WebKit/public/web/WebCompositionUnderline.h"
#include "third_party/WebKit/public/web/WebDataSource.h"
#include "third_party/WebKit/public/web/WebDocument.h"
-#include "third_party/WebKit/public/web/WebElement.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
#include "third_party/WebKit/public/web/WebPluginContainer.h"
#include "third_party/WebKit/public/web/WebPrintParams.h"
+#include "third_party/WebKit/public/web/WebPrintPresetOptions.h"
#include "third_party/WebKit/public/web/WebPrintScalingOption.h"
#include "third_party/WebKit/public/web/WebScopedUserGesture.h"
#include "third_party/WebKit/public/web/WebScriptSource.h"
@@ -134,12 +130,6 @@
#include "ui/events/keycodes/keyboard_codes_posix.h"
#endif
-#if defined(OS_WIN)
-#include "base/metrics/histogram.h"
-#include "base/win/windows_version.h"
-#include "skia/ext/platform_canvas.h"
-#endif
-
using base::StringPrintf;
using ppapi::InputEventData;
using ppapi::PpapiGlobals;
@@ -187,32 +177,27 @@ namespace content {
namespace {
-static const int kInfiniteRatio = 99999;
-
-#define UMA_HISTOGRAM_ASPECT_RATIO(name, width, height) \
- UMA_HISTOGRAM_SPARSE_SLOWLY( \
- name, \
- (height) ? ((width) * 100) / (height) : kInfiniteRatio);
+#define STATIC_ASSERT_PP_MATCHING_ENUM(a, b) \
+ static_assert(static_cast<int>(a) == static_cast<int>(b), \
+ "mismatching enums: " #a)
// Check PP_TextInput_Type and ui::TextInputType are kept in sync.
-COMPILE_ASSERT(int(ui::TEXT_INPUT_TYPE_NONE) == int(PP_TEXTINPUT_TYPE_NONE),
- mismatching_enums);
-COMPILE_ASSERT(int(ui::TEXT_INPUT_TYPE_TEXT) == int(PP_TEXTINPUT_TYPE_TEXT),
- mismatching_enums);
-COMPILE_ASSERT(int(ui::TEXT_INPUT_TYPE_PASSWORD) ==
- int(PP_TEXTINPUT_TYPE_PASSWORD),
- mismatching_enums);
-COMPILE_ASSERT(int(ui::TEXT_INPUT_TYPE_SEARCH) == int(PP_TEXTINPUT_TYPE_SEARCH),
- mismatching_enums);
-COMPILE_ASSERT(int(ui::TEXT_INPUT_TYPE_EMAIL) == int(PP_TEXTINPUT_TYPE_EMAIL),
- mismatching_enums);
-COMPILE_ASSERT(int(ui::TEXT_INPUT_TYPE_NUMBER) == int(PP_TEXTINPUT_TYPE_NUMBER),
- mismatching_enums);
-COMPILE_ASSERT(int(ui::TEXT_INPUT_TYPE_TELEPHONE) ==
- int(PP_TEXTINPUT_TYPE_TELEPHONE),
- mismatching_enums);
-COMPILE_ASSERT(int(ui::TEXT_INPUT_TYPE_URL) == int(PP_TEXTINPUT_TYPE_URL),
- mismatching_enums);
+STATIC_ASSERT_PP_MATCHING_ENUM(ui::TEXT_INPUT_TYPE_NONE,
+ PP_TEXTINPUT_TYPE_NONE);
+STATIC_ASSERT_PP_MATCHING_ENUM(ui::TEXT_INPUT_TYPE_TEXT,
+ PP_TEXTINPUT_TYPE_TEXT);
+STATIC_ASSERT_PP_MATCHING_ENUM(ui::TEXT_INPUT_TYPE_PASSWORD,
+ PP_TEXTINPUT_TYPE_PASSWORD);
+STATIC_ASSERT_PP_MATCHING_ENUM(ui::TEXT_INPUT_TYPE_SEARCH,
+ PP_TEXTINPUT_TYPE_SEARCH);
+STATIC_ASSERT_PP_MATCHING_ENUM(ui::TEXT_INPUT_TYPE_EMAIL,
+ PP_TEXTINPUT_TYPE_EMAIL);
+STATIC_ASSERT_PP_MATCHING_ENUM(ui::TEXT_INPUT_TYPE_NUMBER,
+ PP_TEXTINPUT_TYPE_NUMBER);
+STATIC_ASSERT_PP_MATCHING_ENUM(ui::TEXT_INPUT_TYPE_TELEPHONE,
+ PP_TEXTINPUT_TYPE_TELEPHONE);
+STATIC_ASSERT_PP_MATCHING_ENUM(ui::TEXT_INPUT_TYPE_URL,
+ PP_TEXTINPUT_TYPE_URL);
// The default text input type is to regard the plugin always accept text input.
// This is for allowing users to use input methods even on completely-IME-
@@ -221,90 +206,86 @@ COMPILE_ASSERT(int(ui::TEXT_INPUT_TYPE_URL) == int(PP_TEXTINPUT_TYPE_URL),
// that they don't accept texts.
const ui::TextInputType kPluginDefaultTextInputType = ui::TEXT_INPUT_TYPE_TEXT;
-#define COMPILE_ASSERT_MATCHING_ENUM(webkit_name, np_name) \
- COMPILE_ASSERT(static_cast<int>(WebCursorInfo::webkit_name) == \
- static_cast<int>(np_name), \
- mismatching_enums)
-
-#define COMPILE_ASSERT_PRINT_SCALING_MATCHING_ENUM(webkit_name, pp_name) \
- COMPILE_ASSERT(static_cast<int>(webkit_name) == static_cast<int>(pp_name), \
- mismatching_enums)
-
// <embed>/<object> attributes.
const char kWidth[] = "width";
const char kHeight[] = "height";
const char kBorder[] = "border"; // According to w3c, deprecated.
const char kStyle[] = "style";
-COMPILE_ASSERT_MATCHING_ENUM(TypePointer, PP_MOUSECURSOR_TYPE_POINTER);
-COMPILE_ASSERT_MATCHING_ENUM(TypeCross, PP_MOUSECURSOR_TYPE_CROSS);
-COMPILE_ASSERT_MATCHING_ENUM(TypeHand, PP_MOUSECURSOR_TYPE_HAND);
-COMPILE_ASSERT_MATCHING_ENUM(TypeIBeam, PP_MOUSECURSOR_TYPE_IBEAM);
-COMPILE_ASSERT_MATCHING_ENUM(TypeWait, PP_MOUSECURSOR_TYPE_WAIT);
-COMPILE_ASSERT_MATCHING_ENUM(TypeHelp, PP_MOUSECURSOR_TYPE_HELP);
-COMPILE_ASSERT_MATCHING_ENUM(TypeEastResize, PP_MOUSECURSOR_TYPE_EASTRESIZE);
-COMPILE_ASSERT_MATCHING_ENUM(TypeNorthResize, PP_MOUSECURSOR_TYPE_NORTHRESIZE);
-COMPILE_ASSERT_MATCHING_ENUM(TypeNorthEastResize,
- PP_MOUSECURSOR_TYPE_NORTHEASTRESIZE);
-COMPILE_ASSERT_MATCHING_ENUM(TypeNorthWestResize,
- PP_MOUSECURSOR_TYPE_NORTHWESTRESIZE);
-COMPILE_ASSERT_MATCHING_ENUM(TypeSouthResize, PP_MOUSECURSOR_TYPE_SOUTHRESIZE);
-COMPILE_ASSERT_MATCHING_ENUM(TypeSouthEastResize,
- PP_MOUSECURSOR_TYPE_SOUTHEASTRESIZE);
-COMPILE_ASSERT_MATCHING_ENUM(TypeSouthWestResize,
- PP_MOUSECURSOR_TYPE_SOUTHWESTRESIZE);
-COMPILE_ASSERT_MATCHING_ENUM(TypeWestResize, PP_MOUSECURSOR_TYPE_WESTRESIZE);
-COMPILE_ASSERT_MATCHING_ENUM(TypeNorthSouthResize,
- PP_MOUSECURSOR_TYPE_NORTHSOUTHRESIZE);
-COMPILE_ASSERT_MATCHING_ENUM(TypeEastWestResize,
- PP_MOUSECURSOR_TYPE_EASTWESTRESIZE);
-COMPILE_ASSERT_MATCHING_ENUM(TypeNorthEastSouthWestResize,
- PP_MOUSECURSOR_TYPE_NORTHEASTSOUTHWESTRESIZE);
-COMPILE_ASSERT_MATCHING_ENUM(TypeNorthWestSouthEastResize,
- PP_MOUSECURSOR_TYPE_NORTHWESTSOUTHEASTRESIZE);
-COMPILE_ASSERT_MATCHING_ENUM(TypeColumnResize,
- PP_MOUSECURSOR_TYPE_COLUMNRESIZE);
-COMPILE_ASSERT_MATCHING_ENUM(TypeRowResize, PP_MOUSECURSOR_TYPE_ROWRESIZE);
-COMPILE_ASSERT_MATCHING_ENUM(TypeMiddlePanning,
- PP_MOUSECURSOR_TYPE_MIDDLEPANNING);
-COMPILE_ASSERT_MATCHING_ENUM(TypeEastPanning, PP_MOUSECURSOR_TYPE_EASTPANNING);
-COMPILE_ASSERT_MATCHING_ENUM(TypeNorthPanning,
- PP_MOUSECURSOR_TYPE_NORTHPANNING);
-COMPILE_ASSERT_MATCHING_ENUM(TypeNorthEastPanning,
- PP_MOUSECURSOR_TYPE_NORTHEASTPANNING);
-COMPILE_ASSERT_MATCHING_ENUM(TypeNorthWestPanning,
- PP_MOUSECURSOR_TYPE_NORTHWESTPANNING);
-COMPILE_ASSERT_MATCHING_ENUM(TypeSouthPanning,
- PP_MOUSECURSOR_TYPE_SOUTHPANNING);
-COMPILE_ASSERT_MATCHING_ENUM(TypeSouthEastPanning,
- PP_MOUSECURSOR_TYPE_SOUTHEASTPANNING);
-COMPILE_ASSERT_MATCHING_ENUM(TypeSouthWestPanning,
- PP_MOUSECURSOR_TYPE_SOUTHWESTPANNING);
-COMPILE_ASSERT_MATCHING_ENUM(TypeWestPanning, PP_MOUSECURSOR_TYPE_WESTPANNING);
-COMPILE_ASSERT_MATCHING_ENUM(TypeMove, PP_MOUSECURSOR_TYPE_MOVE);
-COMPILE_ASSERT_MATCHING_ENUM(TypeVerticalText,
- PP_MOUSECURSOR_TYPE_VERTICALTEXT);
-COMPILE_ASSERT_MATCHING_ENUM(TypeCell, PP_MOUSECURSOR_TYPE_CELL);
-COMPILE_ASSERT_MATCHING_ENUM(TypeContextMenu, PP_MOUSECURSOR_TYPE_CONTEXTMENU);
-COMPILE_ASSERT_MATCHING_ENUM(TypeAlias, PP_MOUSECURSOR_TYPE_ALIAS);
-COMPILE_ASSERT_MATCHING_ENUM(TypeProgress, PP_MOUSECURSOR_TYPE_PROGRESS);
-COMPILE_ASSERT_MATCHING_ENUM(TypeNoDrop, PP_MOUSECURSOR_TYPE_NODROP);
-COMPILE_ASSERT_MATCHING_ENUM(TypeCopy, PP_MOUSECURSOR_TYPE_COPY);
-COMPILE_ASSERT_MATCHING_ENUM(TypeNone, PP_MOUSECURSOR_TYPE_NONE);
-COMPILE_ASSERT_MATCHING_ENUM(TypeNotAllowed, PP_MOUSECURSOR_TYPE_NOTALLOWED);
-COMPILE_ASSERT_MATCHING_ENUM(TypeZoomIn, PP_MOUSECURSOR_TYPE_ZOOMIN);
-COMPILE_ASSERT_MATCHING_ENUM(TypeZoomOut, PP_MOUSECURSOR_TYPE_ZOOMOUT);
-COMPILE_ASSERT_MATCHING_ENUM(TypeGrab, PP_MOUSECURSOR_TYPE_GRAB);
-COMPILE_ASSERT_MATCHING_ENUM(TypeGrabbing, PP_MOUSECURSOR_TYPE_GRABBING);
+#define STATIC_ASSERT_MATCHING_ENUM(webkit_name, np_name) \
+ static_assert(static_cast<int>(WebCursorInfo::webkit_name) == \
+ static_cast<int>(np_name), \
+ "mismatching enums: " #webkit_name)
+
+STATIC_ASSERT_MATCHING_ENUM(TypePointer, PP_MOUSECURSOR_TYPE_POINTER);
+STATIC_ASSERT_MATCHING_ENUM(TypeCross, PP_MOUSECURSOR_TYPE_CROSS);
+STATIC_ASSERT_MATCHING_ENUM(TypeHand, PP_MOUSECURSOR_TYPE_HAND);
+STATIC_ASSERT_MATCHING_ENUM(TypeIBeam, PP_MOUSECURSOR_TYPE_IBEAM);
+STATIC_ASSERT_MATCHING_ENUM(TypeWait, PP_MOUSECURSOR_TYPE_WAIT);
+STATIC_ASSERT_MATCHING_ENUM(TypeHelp, PP_MOUSECURSOR_TYPE_HELP);
+STATIC_ASSERT_MATCHING_ENUM(TypeEastResize, PP_MOUSECURSOR_TYPE_EASTRESIZE);
+STATIC_ASSERT_MATCHING_ENUM(TypeNorthResize, PP_MOUSECURSOR_TYPE_NORTHRESIZE);
+STATIC_ASSERT_MATCHING_ENUM(TypeNorthEastResize,
+ PP_MOUSECURSOR_TYPE_NORTHEASTRESIZE);
+STATIC_ASSERT_MATCHING_ENUM(TypeNorthWestResize,
+ PP_MOUSECURSOR_TYPE_NORTHWESTRESIZE);
+STATIC_ASSERT_MATCHING_ENUM(TypeSouthResize, PP_MOUSECURSOR_TYPE_SOUTHRESIZE);
+STATIC_ASSERT_MATCHING_ENUM(TypeSouthEastResize,
+ PP_MOUSECURSOR_TYPE_SOUTHEASTRESIZE);
+STATIC_ASSERT_MATCHING_ENUM(TypeSouthWestResize,
+ PP_MOUSECURSOR_TYPE_SOUTHWESTRESIZE);
+STATIC_ASSERT_MATCHING_ENUM(TypeWestResize, PP_MOUSECURSOR_TYPE_WESTRESIZE);
+STATIC_ASSERT_MATCHING_ENUM(TypeNorthSouthResize,
+ PP_MOUSECURSOR_TYPE_NORTHSOUTHRESIZE);
+STATIC_ASSERT_MATCHING_ENUM(TypeEastWestResize,
+ PP_MOUSECURSOR_TYPE_EASTWESTRESIZE);
+STATIC_ASSERT_MATCHING_ENUM(TypeNorthEastSouthWestResize,
+ PP_MOUSECURSOR_TYPE_NORTHEASTSOUTHWESTRESIZE);
+STATIC_ASSERT_MATCHING_ENUM(TypeNorthWestSouthEastResize,
+ PP_MOUSECURSOR_TYPE_NORTHWESTSOUTHEASTRESIZE);
+STATIC_ASSERT_MATCHING_ENUM(TypeColumnResize,
+ PP_MOUSECURSOR_TYPE_COLUMNRESIZE);
+STATIC_ASSERT_MATCHING_ENUM(TypeRowResize, PP_MOUSECURSOR_TYPE_ROWRESIZE);
+STATIC_ASSERT_MATCHING_ENUM(TypeMiddlePanning,
+ PP_MOUSECURSOR_TYPE_MIDDLEPANNING);
+STATIC_ASSERT_MATCHING_ENUM(TypeEastPanning, PP_MOUSECURSOR_TYPE_EASTPANNING);
+STATIC_ASSERT_MATCHING_ENUM(TypeNorthPanning,
+ PP_MOUSECURSOR_TYPE_NORTHPANNING);
+STATIC_ASSERT_MATCHING_ENUM(TypeNorthEastPanning,
+ PP_MOUSECURSOR_TYPE_NORTHEASTPANNING);
+STATIC_ASSERT_MATCHING_ENUM(TypeNorthWestPanning,
+ PP_MOUSECURSOR_TYPE_NORTHWESTPANNING);
+STATIC_ASSERT_MATCHING_ENUM(TypeSouthPanning,
+ PP_MOUSECURSOR_TYPE_SOUTHPANNING);
+STATIC_ASSERT_MATCHING_ENUM(TypeSouthEastPanning,
+ PP_MOUSECURSOR_TYPE_SOUTHEASTPANNING);
+STATIC_ASSERT_MATCHING_ENUM(TypeSouthWestPanning,
+ PP_MOUSECURSOR_TYPE_SOUTHWESTPANNING);
+STATIC_ASSERT_MATCHING_ENUM(TypeWestPanning, PP_MOUSECURSOR_TYPE_WESTPANNING);
+STATIC_ASSERT_MATCHING_ENUM(TypeMove, PP_MOUSECURSOR_TYPE_MOVE);
+STATIC_ASSERT_MATCHING_ENUM(TypeVerticalText,
+ PP_MOUSECURSOR_TYPE_VERTICALTEXT);
+STATIC_ASSERT_MATCHING_ENUM(TypeCell, PP_MOUSECURSOR_TYPE_CELL);
+STATIC_ASSERT_MATCHING_ENUM(TypeContextMenu, PP_MOUSECURSOR_TYPE_CONTEXTMENU);
+STATIC_ASSERT_MATCHING_ENUM(TypeAlias, PP_MOUSECURSOR_TYPE_ALIAS);
+STATIC_ASSERT_MATCHING_ENUM(TypeProgress, PP_MOUSECURSOR_TYPE_PROGRESS);
+STATIC_ASSERT_MATCHING_ENUM(TypeNoDrop, PP_MOUSECURSOR_TYPE_NODROP);
+STATIC_ASSERT_MATCHING_ENUM(TypeCopy, PP_MOUSECURSOR_TYPE_COPY);
+STATIC_ASSERT_MATCHING_ENUM(TypeNone, PP_MOUSECURSOR_TYPE_NONE);
+STATIC_ASSERT_MATCHING_ENUM(TypeNotAllowed, PP_MOUSECURSOR_TYPE_NOTALLOWED);
+STATIC_ASSERT_MATCHING_ENUM(TypeZoomIn, PP_MOUSECURSOR_TYPE_ZOOMIN);
+STATIC_ASSERT_MATCHING_ENUM(TypeZoomOut, PP_MOUSECURSOR_TYPE_ZOOMOUT);
+STATIC_ASSERT_MATCHING_ENUM(TypeGrab, PP_MOUSECURSOR_TYPE_GRAB);
+STATIC_ASSERT_MATCHING_ENUM(TypeGrabbing, PP_MOUSECURSOR_TYPE_GRABBING);
// Do not assert WebCursorInfo::TypeCustom == PP_CURSORTYPE_CUSTOM;
// PP_CURSORTYPE_CUSTOM is pinned to allow new cursor types.
-COMPILE_ASSERT_PRINT_SCALING_MATCHING_ENUM(blink::WebPrintScalingOptionNone,
+STATIC_ASSERT_PP_MATCHING_ENUM(blink::WebPrintScalingOptionNone,
PP_PRINTSCALINGOPTION_NONE);
-COMPILE_ASSERT_PRINT_SCALING_MATCHING_ENUM(
+STATIC_ASSERT_PP_MATCHING_ENUM(
blink::WebPrintScalingOptionFitToPrintableArea,
PP_PRINTSCALINGOPTION_FIT_TO_PRINTABLE_AREA);
-COMPILE_ASSERT_PRINT_SCALING_MATCHING_ENUM(
+STATIC_ASSERT_PP_MATCHING_ENUM(
blink::WebPrintScalingOptionSourceSize,
PP_PRINTSCALINGOPTION_SOURCE_SIZE);
@@ -364,7 +345,7 @@ bool IsReservedSystemInputEvent(const blink::WebInputEvent& event) {
class PluginInstanceLockTarget : public MouseLockDispatcher::LockTarget {
public:
- PluginInstanceLockTarget(PepperPluginInstanceImpl* plugin)
+ explicit PluginInstanceLockTarget(PepperPluginInstanceImpl* plugin)
: plugin_(plugin) {}
void OnLockMouseACK(bool succeeded) override {
@@ -386,11 +367,11 @@ void InitLatencyInfo(ui::LatencyInfo* new_latency,
const ui::LatencyInfo* old_latency,
blink::WebInputEvent::Type type,
int64 input_sequence) {
- new_latency->AddLatencyNumber(
+ new_latency->AddLatencyNumberWithTraceName(
ui::INPUT_EVENT_LATENCY_BEGIN_PLUGIN_COMPONENT,
0,
- input_sequence);
- new_latency->TraceEventType(WebInputEventTraits::GetName(type));
+ input_sequence,
+ WebInputEventTraits::GetName(type));
if (old_latency) {
new_latency->CopyLatencyFrom(*old_latency,
ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT);
@@ -399,77 +380,6 @@ void InitLatencyInfo(ui::LatencyInfo* new_latency,
}
}
-// Histogram tracking prevalence of tiny Flash instances. Units in pixels.
-enum PluginFlashTinyContentSize {
- TINY_CONTENT_SIZE_1_1 = 0,
- TINY_CONTENT_SIZE_5_5 = 1,
- TINY_CONTENT_SIZE_10_10 = 2,
- TINY_CONTENT_SIZE_LARGE = 3,
- TINY_CONTENT_SIZE_NUM_ITEMS
-};
-
-// How the throttled power saver is unthrottled, if ever.
-// These numeric values are used in UMA logs; do not change them.
-enum PowerSaverUnthrottleMethod {
- UNTHROTTLE_METHOD_NEVER = 0,
- UNTHROTTLE_METHOD_BY_CLICK = 1,
- UNTHROTTLE_METHOD_BY_WHITELIST = 2,
- UNTHROTTLE_METHOD_NUM_ITEMS
-};
-
-const char kFlashClickSizeAspectRatioHistogram[] =
- "Plugin.Flash.ClickSize.AspectRatio";
-const char kFlashClickSizeHeightHistogram[] = "Plugin.Flash.ClickSize.Height";
-const char kFlashClickSizeWidthHistogram[] = "Plugin.Flash.ClickSize.Width";
-const char kFlashTinyContentSizeHistogram[] = "Plugin.Flash.TinyContentSize";
-const char kPowerSaverUnthrottleHistogram[] = "Plugin.PowerSaver.Unthrottle";
-
-// Record size metrics for all Flash instances.
-void RecordFlashSizeMetric(int width, int height) {
- PluginFlashTinyContentSize size = TINY_CONTENT_SIZE_LARGE;
-
- if (width <= 1 && height <= 1)
- size = TINY_CONTENT_SIZE_1_1;
- else if (width <= 5 && height <= 5)
- size = TINY_CONTENT_SIZE_5_5;
- else if (width <= 10 && height <= 10)
- size = TINY_CONTENT_SIZE_10_10;
-
- UMA_HISTOGRAM_ENUMERATION(kFlashTinyContentSizeHistogram, size,
- TINY_CONTENT_SIZE_NUM_ITEMS);
-}
-
-// Records size metrics for Flash instances that are clicked.
-void RecordFlashClickSizeMetric(int width, int height) {
- base::HistogramBase* width_histogram = base::LinearHistogram::FactoryGet(
- kFlashClickSizeWidthHistogram,
- 0, // minimum width
- 500, // maximum width
- 100, // number of buckets.
- base::HistogramBase::kUmaTargetedHistogramFlag);
- width_histogram->Add(width);
-
- base::HistogramBase* height_histogram = base::LinearHistogram::FactoryGet(
- kFlashClickSizeHeightHistogram,
- 0, // minimum height
- 400, // maximum height
- 100, // number of buckets.
- base::HistogramBase::kUmaTargetedHistogramFlag);
- height_histogram->Add(height);
-
- UMA_HISTOGRAM_ASPECT_RATIO(kFlashClickSizeAspectRatioHistogram, width,
- height);
-}
-
-void RecordUnthrottleMethodMetric(PowerSaverUnthrottleMethod method) {
- UMA_HISTOGRAM_ENUMERATION(kPowerSaverUnthrottleHistogram, method,
- UNTHROTTLE_METHOD_NUM_ITEMS);
-}
-
-bool IsFlashPlugin(PluginModule* module) {
- return module->name() == kFlashPluginName;
-}
-
} // namespace
// static
@@ -570,10 +480,11 @@ PepperPluginInstanceImpl::PepperPluginInstanceImpl(
layer_bound_to_fullscreen_(false),
layer_is_hardware_(false),
plugin_url_(plugin_url),
+ document_url_(container ? GURL(container->element().document().url())
+ : GURL()),
+ is_flash_plugin_(module->name() == kFlashPluginName),
has_been_clicked_(false),
- power_saver_enabled_(false),
- is_peripheral_content_(false),
- plugin_throttled_(false),
+ javascript_used_(false),
full_frame_(false),
sent_initial_did_change_view_(false),
bound_graphics_2d_platform_(NULL),
@@ -615,6 +526,7 @@ PepperPluginInstanceImpl::PepperPluginInstanceImpl(
is_deleted_(false),
last_input_number_(0),
is_tracking_latency_(false),
+ initialized_(false),
view_change_weak_ptr_factory_(this),
weak_factory_(this) {
pp_instance_ = HostGlobals::Get()->AddInstance(this);
@@ -655,7 +567,7 @@ PepperPluginInstanceImpl::PepperPluginInstanceImpl(
browser_connection->DidCreateInProcessInstance(
pp_instance(),
render_frame_->GetRoutingID(),
- container_->element().document().url(),
+ document_url_,
GetPluginURL());
}
}
@@ -671,9 +583,6 @@ PepperPluginInstanceImpl::PepperPluginInstanceImpl(
PepperPluginInstanceImpl::~PepperPluginInstanceImpl() {
DCHECK(!fullscreen_container_);
- if (plugin_throttled_)
- RecordUnthrottleMethodMetric(UNTHROTTLE_METHOD_NEVER);
-
// Notify all the plugin objects of deletion. This will prevent blink from
// calling into the plugin any more.
//
@@ -712,6 +621,9 @@ PepperPluginInstanceImpl::~PepperPluginInstanceImpl() {
// This should be last since some of the above "instance deleted" calls will
// want to look up in the global map to get info off of our object.
HostGlobals::Get()->InstanceDeleted(pp_instance_);
+
+ if (throttler_)
+ throttler_->RemoveObserver(this);
}
// NOTE: Any of these methods that calls into the plugin needs to take into
@@ -731,16 +643,16 @@ void PepperPluginInstanceImpl::MessageChannelDestroyed() {
v8::Local<v8::Context> PepperPluginInstanceImpl::GetMainWorldContext() {
if (!container_)
- return v8::Handle<v8::Context>();
+ return v8::Local<v8::Context>();
if (container_->element().isNull())
- return v8::Handle<v8::Context>();
+ return v8::Local<v8::Context>();
if (container_->element().document().isNull())
- return v8::Handle<v8::Context>();
+ return v8::Local<v8::Context>();
if (!container_->element().document().frame())
- return v8::Handle<v8::Context>();
+ return v8::Local<v8::Context>();
v8::Local<v8::Context> context =
container_->element().document().frame()->mainWorldScriptContext();
@@ -758,19 +670,33 @@ void PepperPluginInstanceImpl::Delete() {
// Keep a reference on the stack. See NOTE above.
scoped_refptr<PepperPluginInstanceImpl> ref(this);
+
+ // It is important to destroy the throttler before anything else.
+ // The plugin instance may flush its graphics pipeline during its postmortem
+ // spasm, causing the throttler to engage and obtain new dangling reference
+ // to the plugin container being destroyed.
+ throttler_.reset();
+
// Force the MessageChannel to release its "passthrough object" which should
// release our last reference to the "InstanceObject" and will probably
// destroy it. We want to do this prior to calling DidDestroy in case the
// destructor of the instance object tries to use the instance.
if (message_channel_)
- message_channel_->SetPassthroughObject(v8::Handle<v8::Object>());
+ message_channel_->SetPassthroughObject(v8::Local<v8::Object>());
// If this is a NaCl plugin instance, shut down the NaCl plugin by calling
// its DidDestroy. Don't call DidDestroy on the untrusted plugin instance,
// since there is little that it can do at this point.
- if (original_instance_interface_)
+ if (original_instance_interface_) {
+ base::TimeTicks start = base::TimeTicks::Now();
original_instance_interface_->DidDestroy(pp_instance());
- else
+ UMA_HISTOGRAM_CUSTOM_TIMES("NaCl.Perf.ShutdownTime.Total",
+ base::TimeTicks::Now() - start,
+ base::TimeDelta::FromMilliseconds(1),
+ base::TimeDelta::FromSeconds(20),
+ 100);
+ } else {
instance_interface_->DidDestroy(pp_instance());
+ }
// Ensure we don't attempt to call functions on the destroyed instance.
original_instance_interface_.reset();
instance_interface_.reset();
@@ -888,80 +814,19 @@ void PepperPluginInstanceImpl::InstanceCrashed() {
UnSetAndDeleteLockTargetAdapter();
}
-static void SetGPUHistogram(const ppapi::Preferences& prefs,
- const std::vector<std::string>& arg_names,
- const std::vector<std::string>& arg_values) {
-// Calculate a histogram to let us determine how likely people are to try to
-// run Stage3D content on machines that have it blacklisted.
-#if defined(OS_WIN)
- bool needs_gpu = false;
- bool is_xp = base::win::GetVersion() <= base::win::VERSION_XP;
-
- for (size_t i = 0; i < arg_names.size(); i++) {
- if (arg_names[i] == "wmode") {
- // In theory content other than Flash could have a "wmode" argument,
- // but that's pretty unlikely.
- if (arg_values[i] == "direct" || arg_values[i] == "gpu")
- needs_gpu = true;
- break;
- }
- }
- // 0 : No 3D content and GPU is blacklisted
- // 1 : No 3D content and GPU is not blacklisted
- // 2 : 3D content but GPU is blacklisted
- // 3 : 3D content and GPU is not blacklisted
- // 4 : No 3D content and GPU is blacklisted on XP
- // 5 : No 3D content and GPU is not blacklisted on XP
- // 6 : 3D content but GPU is blacklisted on XP
- // 7 : 3D content and GPU is not blacklisted on XP
- UMA_HISTOGRAM_ENUMERATION(
- "Flash.UsesGPU", is_xp * 4 + needs_gpu * 2 + prefs.is_webgl_supported, 8);
-#endif
-}
-
bool PepperPluginInstanceImpl::Initialize(
const std::vector<std::string>& arg_names,
const std::vector<std::string>& arg_values,
- bool full_frame) {
+ bool full_frame,
+ scoped_ptr<PluginInstanceThrottlerImpl> throttler) {
+ DCHECK(!throttler_);
+
if (!render_frame_)
return false;
- blink::WebRect bounds = container_->element().boundsInViewportSpace();
- if (IsFlashPlugin(module_.get())) {
- RenderThread::Get()->RecordAction(
- base::UserMetricsAction("Flash.PluginInstanceCreated"));
- RecordFlashSizeMetric(bounds.width, bounds.height);
- }
-
- PluginPowerSaverHelper* power_saver_helper =
- render_frame_->plugin_power_saver_helper();
- GURL content_origin = plugin_url_.GetOrigin();
-
- bool cross_origin = false;
- is_peripheral_content_ =
- IsFlashPlugin(module_.get()) &&
- power_saver_helper->ShouldThrottleContent(content_origin, bounds.width,
- bounds.height, &cross_origin);
-
- power_saver_enabled_ = is_peripheral_content_ &&
- base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnablePluginPowerSaver);
-
- if (is_peripheral_content_) {
- // To collect UMAs, register peripheral content even if we don't throttle.
- power_saver_helper->RegisterPeripheralPlugin(
- content_origin,
- base::Bind(
- &PepperPluginInstanceImpl::DisablePowerSaverByRetroactiveWhitelist,
- weak_factory_.GetWeakPtr()));
-
- if (power_saver_enabled_) {
- throttler_.reset(new PepperPluginInstanceThrottler(
- base::Bind(&PepperPluginInstanceImpl::SetPluginThrottled,
- weak_factory_.GetWeakPtr(), true /* throttled */)));
- }
- } else if (cross_origin) {
- power_saver_helper->WhitelistContentOrigin(content_origin);
+ if (throttler) {
+ throttler_ = throttler.Pass();
+ throttler_->AddObserver(this);
}
message_channel_ = MessageChannel::Create(this, &message_channel_object_);
@@ -980,8 +845,15 @@ bool PepperPluginInstanceImpl::Initialize(
argv_ = arg_values;
scoped_ptr<const char * []> argn_array(StringVectorToArgArray(argn_));
scoped_ptr<const char * []> argv_array(StringVectorToArgArray(argv_));
+ auto weak_this = weak_factory_.GetWeakPtr();
bool success = PP_ToBool(instance_interface_->DidCreate(
pp_instance(), argn_.size(), argn_array.get(), argv_array.get()));
+ if (!weak_this) {
+ // The plugin may do synchronous scripting during "DidCreate", so |this|
+ // may be deleted. In that case, return failure and don't touch any
+ // member variables.
+ return false;
+ }
// If this is a plugin that hosts external plugins, we should delay messages
// so that the child plugin that's created later will receive all the
// messages. (E.g., NaCl trusted plugin starting a child NaCl app.)
@@ -992,6 +864,7 @@ bool PepperPluginInstanceImpl::Initialize(
if (message_channel_)
message_channel_->Start();
}
+ initialized_ = success;
return success;
}
@@ -1219,24 +1092,16 @@ bool PepperPluginInstanceImpl::HandleInputEvent(
WebCursorInfo* cursor_info) {
TRACE_EVENT0("ppapi", "PepperPluginInstanceImpl::HandleInputEvent");
- if (event.type == blink::WebInputEvent::MouseDown && !has_been_clicked_ &&
- IsFlashPlugin(module_.get())) {
+ if (!has_been_clicked_ && is_flash_plugin_ &&
+ event.type == blink::WebInputEvent::MouseDown &&
+ (event.modifiers & blink::WebInputEvent::LeftButtonDown)) {
has_been_clicked_ = true;
- blink::WebRect bounds = container_->element().boundsInViewportSpace();
+ blink::WebRect bounds = container()->element().boundsInViewportSpace();
RecordFlashClickSizeMetric(bounds.width, bounds.height);
}
- if (event.type == blink::WebInputEvent::MouseUp && is_peripheral_content_) {
- is_peripheral_content_ = false;
- power_saver_enabled_ = false;
-
- RecordUnthrottleMethodMetric(UNTHROTTLE_METHOD_BY_CLICK);
-
- if (plugin_throttled_) {
- SetPluginThrottled(false /* throttled */);
- return true;
- }
- }
+ if (throttler_ && throttler_->ConsumeInputEvent(event))
+ return true;
if (!render_frame_)
return false;
@@ -1363,6 +1228,7 @@ PP_Var PepperPluginInstanceImpl::GetInstanceObject(v8::Isolate* isolate) {
scoped_refptr<PepperPluginInstanceImpl> ref(this);
DCHECK_EQ(isolate, isolate_);
+ RecordFlashJavaScriptUse();
// If the plugin supports the private instance interface, try to retrieve its
// instance object.
@@ -1372,8 +1238,9 @@ PP_Var PepperPluginInstanceImpl::GetInstanceObject(v8::Isolate* isolate) {
}
void PepperPluginInstanceImpl::ViewChanged(
- const gfx::Rect& position,
+ const gfx::Rect& window,
const gfx::Rect& clip,
+ const gfx::Rect& unobscured,
const std::vector<gfx::Rect>& cut_outs_rects) {
// WebKit can give weird (x,y) positions for empty clip rects (since the
// position technically doesn't matter). But we want to make these
@@ -1383,9 +1250,11 @@ void PepperPluginInstanceImpl::ViewChanged(
if (!clip.IsEmpty())
new_clip = clip;
+ unobscured_rect_ = unobscured;
+
cut_outs_rects_ = cut_outs_rects;
- view_data_.rect = PP_FromGfxRect(position);
+ view_data_.rect = PP_FromGfxRect(window);
view_data_.clip_rect = PP_FromGfxRect(clip);
view_data_.device_scale = container_->deviceScaleFactor();
view_data_.css_scale =
@@ -1401,7 +1270,7 @@ void PepperPluginInstanceImpl::ViewChanged(
WebDocument document = element.document();
bool is_fullscreen_element = (element == document.fullScreenElement());
if (!view_data_.is_fullscreen && desired_fullscreen_state_ &&
- render_frame()->GetRenderWidget()->is_fullscreen() &&
+ render_frame()->GetRenderWidget()->is_fullscreen_granted() &&
is_fullscreen_element) {
// Entered fullscreen. Only possible via SetFullscreen().
view_data_.is_fullscreen = true;
@@ -1427,7 +1296,12 @@ void PepperPluginInstanceImpl::ViewChanged(
UpdateFlashFullscreenState(fullscreen_container_ != NULL);
- SendDidChangeView();
+ // During plugin initialization, there are often re-layouts. Avoid sending
+ // intermediate sizes the plugin and throttler.
+ if (sent_initial_did_change_view_)
+ SendDidChangeView();
+ else
+ ScheduleAsyncDidChangeView();
}
void PepperPluginInstanceImpl::SetWebKitFocus(bool has_focus) {
@@ -1473,17 +1347,6 @@ void PepperPluginInstanceImpl::ViewInitiatedPaint() {
bound_compositor_->ViewInitiatedPaint();
}
-void PepperPluginInstanceImpl::ViewFlushedPaint() {
- // Keep a reference on the stack. See NOTE above.
- scoped_refptr<PepperPluginInstanceImpl> ref(this);
- if (bound_graphics_2d_platform_)
- bound_graphics_2d_platform_->ViewFlushedPaint();
- else if (bound_graphics_3d_.get())
- bound_graphics_3d_->ViewFlushedPaint();
- else if (bound_compositor_)
- bound_compositor_->ViewFlushedPaint();
-}
-
void PepperPluginInstanceImpl::SetSelectedText(
const base::string16& selected_text) {
selected_text_ = selected_text;
@@ -1515,16 +1378,6 @@ int32_t PepperPluginInstanceImpl::RegisterMessageHandler(
return PP_ERROR_FAILED;
}
-int32_t PepperPluginInstanceImpl::RegisterMessageHandler_1_1_Deprecated(
- PP_Instance instance,
- void* user_data,
- const PPP_MessageHandler_0_1_Deprecated* handler,
- PP_Resource message_loop) {
- // Not supported in-process.
- NOTIMPLEMENTED();
- return PP_ERROR_FAILED;
-}
-
void PepperPluginInstanceImpl::UnregisterMessageHandler(PP_Instance instance) {
// Not supported in-process.
NOTIMPLEMENTED();
@@ -1643,7 +1496,7 @@ bool PepperPluginInstanceImpl::LoadMouseLockInterface() {
bool PepperPluginInstanceImpl::LoadPdfInterface() {
if (!checked_for_plugin_pdf_interface_) {
checked_for_plugin_pdf_interface_ = true;
- plugin_pdf_interface_ = static_cast<const PPP_Pdf_1*>(
+ plugin_pdf_interface_ = static_cast<const PPP_Pdf*>(
module_->GetPluginInterface(PPP_PDF_INTERFACE_1));
}
@@ -1784,17 +1637,42 @@ void PepperPluginInstanceImpl::SendAsyncDidChangeView() {
}
void PepperPluginInstanceImpl::SendDidChangeView() {
+ // An asynchronous view update is scheduled. Skip sending this update.
+ if (view_change_weak_ptr_factory_.HasWeakPtrs())
+ return;
+
// Don't send DidChangeView to crashed plugins.
if (module()->is_crashed())
return;
- // When plugin is throttled, send ViewData indicating it's in the background.
- const ppapi::ViewData& view_data =
- plugin_throttled_ ? empty_view_data_ : view_data_;
+ // During the first view update, initialize the throttler.
+ if (!sent_initial_did_change_view_) {
+ if (is_flash_plugin_ && RenderThread::Get()) {
+ RenderThread::Get()->RecordAction(
+ base::UserMetricsAction("Flash.PluginInstanceCreated"));
+ RecordFlashSizeMetric(unobscured_rect_.width(),
+ unobscured_rect_.height());
+ }
- if (view_change_weak_ptr_factory_.HasWeakPtrs() ||
- (sent_initial_did_change_view_ &&
- last_sent_view_data_.Equals(view_data)))
+ if (throttler_) {
+ throttler_->Initialize(render_frame_, plugin_url_.GetOrigin(),
+ module()->name(), unobscured_rect_.size());
+ }
+ }
+
+ ppapi::ViewData view_data = view_data_;
+
+ // When plugin content is throttled, fake the page being offscreen. We cannot
+ // send empty view data here, as some plugins rely on accurate view data.
+ if (throttler_ && throttler_->IsThrottled()) {
+ view_data.is_page_visible = false;
+ view_data.clip_rect.point.x = 0;
+ view_data.clip_rect.point.y = 0;
+ view_data.clip_rect.size.width = 0;
+ view_data.clip_rect.size.height = 0;
+ }
+
+ if (sent_initial_did_change_view_ && last_sent_view_data_.Equals(view_data))
return; // Nothing to update.
sent_initial_did_change_view_ = true;
@@ -1952,10 +1830,47 @@ void PepperPluginInstanceImpl::PrintEnd() {
#endif // defined(OS_MACOSX)
}
-bool PepperPluginInstanceImpl::CanRotateView() {
+bool PepperPluginInstanceImpl::GetPrintPresetOptionsFromDocument(
+ blink::WebPrintPresetOptions* preset_options) {
+ // Keep a reference on the stack. See NOTE above.
+ scoped_refptr<PepperPluginInstanceImpl> ref(this);
if (!LoadPdfInterface())
return false;
+ PP_PdfPrintPresetOptions_Dev options;
+ if (!plugin_pdf_interface_->GetPrintPresetOptionsFromDocument(pp_instance(),
+ &options)) {
+ return false;
+ }
+
+ preset_options->isScalingDisabled = PP_ToBool(options.is_scaling_disabled);
+ switch (options.duplex) {
+ case PP_PRIVATEDUPLEXMODE_SIMPLEX:
+ preset_options->duplexMode = blink::WebSimplex;
+ break;
+ case PP_PRIVATEDUPLEXMODE_SHORT_EDGE:
+ preset_options->duplexMode = blink::WebShortEdge;
+ break;
+ case PP_PRIVATEDUPLEXMODE_LONG_EDGE:
+ preset_options->duplexMode = blink::WebLongEdge;
+ break;
+ default:
+ preset_options->duplexMode = blink::WebUnknownDuplexMode;
+ break;
+ }
+ preset_options->copies = options.copies;
+ preset_options->isPageSizeUniform = PP_ToBool(options.is_page_size_uniform);
+ preset_options->uniformPageSize =
+ blink::WebSize(options.uniform_page_size.width,
+ options.uniform_page_size.height);
+
+ return true;
+}
+
+bool PepperPluginInstanceImpl::CanRotateView() {
+ if (!LoadPdfInterface() || module()->is_crashed())
+ return false;
+
return true;
}
@@ -2004,7 +1919,7 @@ bool PepperPluginInstanceImpl::SetFullscreen(bool fullscreen) {
if (fullscreen && !IsProcessingUserGesture())
return false;
- VLOG(1) << "Setting fullscreen to " << (fullscreen ? "on" : "off");
+ DVLOG(1) << "Setting fullscreen to " << (fullscreen ? "on" : "off");
desired_fullscreen_state_ = fullscreen;
if (fullscreen) {
@@ -2095,6 +2010,8 @@ bool PepperPluginInstanceImpl::PrintPDFOutput(PP_Resource print_output,
void PepperPluginInstanceImpl::UpdateLayer(bool device_changed) {
if (!container_)
return;
+ if (throttler_ && throttler_->IsHiddenForPlaceholder())
+ return;
gpu::Mailbox mailbox;
uint32 sync_point = 0;
@@ -2121,7 +2038,10 @@ void PepperPluginInstanceImpl::UpdateLayer(bool device_changed) {
else if (fullscreen_container_)
fullscreen_container_->SetLayer(NULL);
web_layer_.reset();
- texture_layer_ = NULL;
+ if (texture_layer_) {
+ texture_layer_->ClearClient();
+ texture_layer_ = NULL;
+ }
compositor_layer_ = NULL;
}
@@ -2177,6 +2097,22 @@ bool PepperPluginInstanceImpl::PrepareTextureMailbox(
void PepperPluginInstanceImpl::OnDestruct() { render_frame_ = NULL; }
+void PepperPluginInstanceImpl::OnThrottleStateChange() {
+ SendDidChangeView();
+
+ bool is_throttled = throttler_->IsThrottled();
+ render_frame()->Send(new ViewHostMsg_PluginInstanceThrottleStateChange(
+ module_->GetPluginChildId(), pp_instance_, is_throttled));
+}
+
+void PepperPluginInstanceImpl::OnHiddenForPlaceholder(bool hidden) {
+ if (hidden) {
+ container_->setWebLayer(nullptr);
+ } else {
+ UpdateLayer(true /* device_changed */);
+ }
+}
+
void PepperPluginInstanceImpl::AddLatencyInfo(
const std::vector<ui::LatencyInfo>& latency_info) {
if (render_frame_ && render_frame_->GetRenderWidget()) {
@@ -2423,7 +2359,7 @@ PP_Bool PepperPluginInstanceImpl::FlashIsFullscreen(PP_Instance instance) {
PP_Var PepperPluginInstanceImpl::GetWindowObject(PP_Instance instance) {
if (!container_)
return PP_MakeUndefined();
-
+ RecordFlashJavaScriptUse();
V8VarConverter converter(pp_instance_, V8VarConverter::kAllowObjectVars);
PepperTryCatchVar try_catch(this, &converter, NULL);
WebLocalFrame* frame = container_->element().document().frame();
@@ -2441,6 +2377,7 @@ PP_Var PepperPluginInstanceImpl::GetWindowObject(PP_Instance instance) {
PP_Var PepperPluginInstanceImpl::GetOwnerElementObject(PP_Instance instance) {
if (!container_)
return PP_MakeUndefined();
+ RecordFlashJavaScriptUse();
V8VarConverter converter(pp_instance_, V8VarConverter::kAllowObjectVars);
PepperTryCatchVar try_catch(this, &converter, NULL);
ScopedPPVar result = try_catch.FromV8(container_->v8ObjectForElement());
@@ -2453,6 +2390,7 @@ PP_Var PepperPluginInstanceImpl::ExecuteScript(PP_Instance instance,
PP_Var* exception) {
if (!container_)
return PP_MakeUndefined();
+ RecordFlashJavaScriptUse();
// Executing the script may remove the plugin from the DOM, so we need to keep
// a reference to ourselves so that we can still process the result after the
@@ -2480,7 +2418,7 @@ PP_Var PepperPluginInstanceImpl::ExecuteScript(PP_Instance instance,
std::string script_string = script_string_var->value();
blink::WebScriptSource script(
blink::WebString::fromUTF8(script_string.c_str()));
- v8::Handle<v8::Value> result;
+ v8::Local<v8::Value> result;
if (IsProcessingUserGesture()) {
blink::WebScopedUserGesture user_gesture(CurrentUserGestureToken());
result = frame->executeScriptAndReturnValue(script);
@@ -2488,10 +2426,6 @@ PP_Var PepperPluginInstanceImpl::ExecuteScript(PP_Instance instance,
result = frame->executeScriptAndReturnValue(script);
}
- // Check for an exception due to the context being destroyed.
- if (try_catch.HasException())
- return PP_MakeUndefined();
-
ScopedPPVar var_result = try_catch.FromV8(result);
if (try_catch.HasException())
return PP_MakeUndefined();
@@ -2530,16 +2464,9 @@ void PepperPluginInstanceImpl::PromiseResolved(PP_Instance instance,
void PepperPluginInstanceImpl::PromiseResolvedWithSession(
PP_Instance instance,
uint32 promise_id,
- PP_Var web_session_id_var) {
+ PP_Var session_id_var) {
content_decryptor_delegate_->OnPromiseResolvedWithSession(promise_id,
- web_session_id_var);
-}
-
-void PepperPluginInstanceImpl::PromiseResolvedWithKeyIds(PP_Instance instance,
- uint32 promise_id,
- PP_Var key_ids_var) {
- content_decryptor_delegate_->OnPromiseResolvedWithKeyIds(promise_id,
- key_ids_var);
+ session_id_var);
}
void PepperPluginInstanceImpl::PromiseRejected(
@@ -2553,46 +2480,45 @@ void PepperPluginInstanceImpl::PromiseRejected(
}
void PepperPluginInstanceImpl::SessionMessage(PP_Instance instance,
- PP_Var web_session_id_var,
+ PP_Var session_id_var,
+ PP_CdmMessageType message_type,
PP_Var message_var,
- PP_Var destination_url_var) {
+ PP_Var legacy_destination_url) {
content_decryptor_delegate_->OnSessionMessage(
- web_session_id_var, message_var, destination_url_var);
+ session_id_var, message_type, message_var, legacy_destination_url);
}
void PepperPluginInstanceImpl::SessionKeysChange(
PP_Instance instance,
- PP_Var web_session_id_var,
- PP_Bool has_additional_usable_key) {
- content_decryptor_delegate_->OnSessionKeysChange(web_session_id_var,
- has_additional_usable_key);
+ PP_Var session_id_var,
+ PP_Bool has_additional_usable_key,
+ uint32_t key_count,
+ const struct PP_KeyInformation key_information[]) {
+ content_decryptor_delegate_->OnSessionKeysChange(
+ session_id_var, has_additional_usable_key, key_count, key_information);
}
void PepperPluginInstanceImpl::SessionExpirationChange(
PP_Instance instance,
- PP_Var web_session_id_var,
+ PP_Var session_id_var,
PP_Time new_expiry_time) {
- content_decryptor_delegate_->OnSessionExpirationChange(web_session_id_var,
+ content_decryptor_delegate_->OnSessionExpirationChange(session_id_var,
new_expiry_time);
}
-void PepperPluginInstanceImpl::SessionReady(PP_Instance instance,
- PP_Var web_session_id_var) {
- content_decryptor_delegate_->OnSessionReady(web_session_id_var);
-}
-
void PepperPluginInstanceImpl::SessionClosed(PP_Instance instance,
- PP_Var web_session_id_var) {
- content_decryptor_delegate_->OnSessionClosed(web_session_id_var);
+ PP_Var session_id_var) {
+ content_decryptor_delegate_->OnSessionClosed(session_id_var);
}
-void PepperPluginInstanceImpl::SessionError(PP_Instance instance,
- PP_Var web_session_id_var,
- PP_CdmExceptionCode exception_code,
- uint32 system_code,
- PP_Var error_description_var) {
- content_decryptor_delegate_->OnSessionError(
- web_session_id_var, exception_code, system_code, error_description_var);
+void PepperPluginInstanceImpl::LegacySessionError(
+ PP_Instance instance,
+ PP_Var session_id_var,
+ PP_CdmExceptionCode exception_code,
+ uint32 system_code,
+ PP_Var error_description_var) {
+ content_decryptor_delegate_->OnLegacySessionError(
+ session_id_var, exception_code, system_code, error_description_var);
}
void PepperPluginInstanceImpl::DeliverBlock(
@@ -2685,7 +2611,6 @@ void PepperPluginInstanceImpl::SetTickmarks(PP_Instance instance,
tickmarks[i].point.y,
tickmarks[i].size.width,
tickmarks[i].size.height);
- ;
}
blink::WebFrame* frame = render_frame_->GetWebFrame();
frame->setTickmarks(tickmarks_converted);
@@ -2714,7 +2639,6 @@ ppapi::Resource* PepperPluginInstanceImpl::GetSingletonResource(
switch (id) {
case ppapi::BROKER_SINGLETON_ID:
case ppapi::BROWSER_FONT_SINGLETON_ID:
- case ppapi::FILE_MAPPING_SINGLETON_ID:
case ppapi::FLASH_CLIPBOARD_SINGLETON_ID:
case ppapi::FLASH_FILE_SINGLETON_ID:
case ppapi::FLASH_FULLSCREEN_SINGLETON_ID:
@@ -3197,7 +3121,7 @@ bool PepperPluginInstanceImpl::FlashSetFullscreen(bool fullscreen,
return false;
// Unbind current 2D or 3D graphics context.
- VLOG(1) << "Setting fullscreen to " << (fullscreen ? "on" : "off");
+ DVLOG(1) << "Setting fullscreen to " << (fullscreen ? "on" : "off");
if (fullscreen) {
DCHECK(!fullscreen_container_);
fullscreen_container_ =
@@ -3247,7 +3171,8 @@ int32_t PepperPluginInstanceImpl::Navigate(
return PP_ERROR_FAILED;
}
web_request.setFirstPartyForCookies(document.firstPartyForCookies());
- web_request.setHasUserGesture(from_user_action);
+ if (IsProcessingUserGesture())
+ web_request.setHasUserGesture(true);
GURL gurl(web_request.url());
if (gurl.SchemeIs(url::kJavaScriptScheme)) {
@@ -3260,7 +3185,8 @@ int32_t PepperPluginInstanceImpl::Navigate(
// TODO(viettrungluu): NPAPI sends the result back to the plugin -- do we
// need that?
- WebString result = container_->executeScriptURL(gurl, from_user_action);
+ blink::WebScopedUserGesture user_gesture(CurrentUserGestureToken());
+ WebString result = container_->executeScriptURL(gurl, false);
return result.isNull() ? PP_ERROR_FAILED : PP_OK;
}
@@ -3269,6 +3195,7 @@ int32_t PepperPluginInstanceImpl::Navigate(
return PP_ERROR_BADARGUMENT;
WebString target_str = WebString::fromUTF8(target);
+ blink::WebScopedUserGesture user_gesture(CurrentUserGestureToken());
container_->loadFrameRequest(web_request, target_str, false, NULL);
return PP_OK;
}
@@ -3420,24 +3347,12 @@ void PepperPluginInstanceImpl::DidDataFromWebURLResponse(
}
}
-void PepperPluginInstanceImpl::SetPluginThrottled(bool throttled) {
- // Do not throttle if we've already disabled power saver.
- if (!power_saver_enabled_ && throttled)
- return;
-
- plugin_throttled_ = throttled;
- SendDidChangeView();
-}
-
-void PepperPluginInstanceImpl::DisablePowerSaverByRetroactiveWhitelist() {
- if (!is_peripheral_content_)
- return;
-
- is_peripheral_content_ = false;
- power_saver_enabled_ = false;
- SetPluginThrottled(false);
-
- RecordUnthrottleMethodMetric(UNTHROTTLE_METHOD_BY_WHITELIST);
+void PepperPluginInstanceImpl::RecordFlashJavaScriptUse() {
+ if (initialized_ && !javascript_used_ && is_flash_plugin_) {
+ javascript_used_ = true;
+ RenderThread::Get()->RecordAction(
+ base::UserMetricsAction("Flash.JavaScriptUsed"));
+ }
}
} // namespace content
diff --git a/chromium/content/renderer/pepper/pepper_plugin_instance_impl.h b/chromium/content/renderer/pepper/pepper_plugin_instance_impl.h
index c056a93bc11..096874475a0 100644
--- a/chromium/content/renderer/pepper/pepper_plugin_instance_impl.h
+++ b/chromium/content/renderer/pepper/pepper_plugin_instance_impl.h
@@ -21,6 +21,8 @@
#include "cc/layers/texture_layer_client.h"
#include "content/common/content_export.h"
#include "content/public/renderer/pepper_plugin_instance.h"
+#include "content/public/renderer/plugin_instance_throttler.h"
+#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_frame_observer.h"
#include "content/renderer/mouse_lock_dispatcher.h"
#include "gin/handle.h"
@@ -58,7 +60,7 @@
#include "third_party/WebKit/public/web/WebUserGestureToken.h"
#include "ui/base/ime/text_input_type.h"
#include "ui/events/latency_info.h"
-#include "ui/gfx/rect.h"
+#include "ui/gfx/geometry/rect.h"
#include "url/gurl.h"
#include "v8/include/v8.h"
@@ -103,7 +105,7 @@ class FullscreenContainer;
class MessageChannel;
class PepperCompositorHost;
class PepperGraphics2DHost;
-class PepperPluginInstanceThrottler;
+class PluginInstanceThrottlerImpl;
class PluginModule;
class PluginObject;
class PPB_Graphics3D_Impl;
@@ -121,7 +123,8 @@ class CONTENT_EXPORT PepperPluginInstanceImpl
public NON_EXPORTED_BASE(PepperPluginInstance),
public ppapi::PPB_Instance_Shared,
public NON_EXPORTED_BASE(cc::TextureLayerClient),
- public RenderFrameObserver {
+ public RenderFrameObserver,
+ public NON_EXPORTED_BASE(PluginInstanceThrottler::Observer) {
public:
// Create and return a PepperPluginInstanceImpl object which supports the most
// recent version of PPP_Instance possible by querying the given
@@ -136,6 +139,8 @@ class CONTENT_EXPORT PepperPluginInstanceImpl
blink::WebPluginContainer* container() const { return container_; }
+ PluginInstanceThrottlerImpl* throttler() const { return throttler_.get(); }
+
// Returns the PP_Instance uniquely identifying this instance. Guaranteed
// nonzero.
PP_Instance pp_instance() const { return pp_instance_; }
@@ -166,6 +171,8 @@ class CONTENT_EXPORT PepperPluginInstanceImpl
// Returns true if Delete() has been called on this object.
bool is_deleted() const;
+ GURL document_url() const { return document_url_; }
+
// Paints the current backing store to the web page.
void Paint(blink::WebCanvas* canvas,
const gfx::Rect& plugin_rect,
@@ -196,13 +203,15 @@ class CONTENT_EXPORT PepperPluginInstanceImpl
// PPP_Instance and PPP_Instance_Private.
bool Initialize(const std::vector<std::string>& arg_names,
const std::vector<std::string>& arg_values,
- bool full_frame);
+ bool full_frame,
+ scoped_ptr<PluginInstanceThrottlerImpl> throttler);
bool HandleDocumentLoad(const blink::WebURLResponse& response);
bool HandleInputEvent(const blink::WebInputEvent& event,
blink::WebCursorInfo* cursor_info);
PP_Var GetInstanceObject(v8::Isolate* isolate);
- void ViewChanged(const gfx::Rect& position,
+ void ViewChanged(const gfx::Rect& window,
const gfx::Rect& clip,
+ const gfx::Rect& unobscured,
const std::vector<gfx::Rect>& cut_outs_rects);
// Handlers for composition events.
@@ -228,11 +237,9 @@ class CONTENT_EXPORT PepperPluginInstanceImpl
// Notification about page visibility. The default is "visible".
void PageVisibilityChanged(bool is_visible);
- // Notifications that the view has started painting, and has flushed the
- // painted content to the screen. These messages are used to send Flush
- // callbacks to the plugin for DeviceContext2D/3D.
+ // Notifications that the view has started painting. This message is used to
+ // send Flush callbacks to the plugin for Graphics2D/3D.
void ViewInitiatedPaint();
- void ViewFlushedPaint();
// Tracks all live PluginObjects.
void AddPluginObject(PluginObject* plugin_object);
@@ -253,6 +260,8 @@ class CONTENT_EXPORT PepperPluginInstanceImpl
int PrintBegin(const blink::WebPrintParams& print_params);
bool PrintPage(int page_number, blink::WebCanvas* canvas);
void PrintEnd();
+ bool GetPrintPresetOptionsFromDocument(
+ blink::WebPrintPresetOptions* preset_options);
bool CanRotateView();
void RotateView(blink::WebPlugin::RotationType type);
@@ -426,11 +435,6 @@ class CONTENT_EXPORT PepperPluginInstanceImpl
void* user_data,
const PPP_MessageHandler_0_2* handler,
PP_Resource message_loop) override;
- int32_t RegisterMessageHandler_1_1_Deprecated(
- PP_Instance instance,
- void* user_data,
- const PPP_MessageHandler_0_1_Deprecated* handler,
- PP_Resource message_loop) override;
void UnregisterMessageHandler(PP_Instance instance) override;
PP_Bool SetCursor(PP_Instance instance,
PP_MouseCursor_Type type,
@@ -466,32 +470,32 @@ class CONTENT_EXPORT PepperPluginInstanceImpl
void PromiseResolved(PP_Instance instance, uint32 promise_id) override;
void PromiseResolvedWithSession(PP_Instance instance,
uint32 promise_id,
- PP_Var web_session_id_var) override;
- void PromiseResolvedWithKeyIds(PP_Instance instance,
- uint32 promise_id,
- PP_Var key_ids_var) override;
+ PP_Var session_id_var) override;
void PromiseRejected(PP_Instance instance,
uint32 promise_id,
PP_CdmExceptionCode exception_code,
uint32 system_code,
PP_Var error_description_var) override;
void SessionMessage(PP_Instance instance,
- PP_Var web_session_id_var,
+ PP_Var session_id_var,
+ PP_CdmMessageType message_type,
PP_Var message_var,
- PP_Var destination_url_var) override;
- void SessionKeysChange(PP_Instance instance,
- PP_Var web_session_id_var,
- PP_Bool has_additional_usable_key) override;
+ PP_Var legacy_destination_url) override;
+ void SessionKeysChange(
+ PP_Instance instance,
+ PP_Var session_id_var,
+ PP_Bool has_additional_usable_key,
+ uint32_t key_count,
+ const struct PP_KeyInformation key_information[]) override;
void SessionExpirationChange(PP_Instance instance,
- PP_Var web_session_id_var,
+ PP_Var session_id_var,
PP_Time new_expiry_time) override;
- void SessionReady(PP_Instance instance, PP_Var web_session_id_var) override;
- void SessionClosed(PP_Instance instance, PP_Var web_session_id_var) override;
- void SessionError(PP_Instance instance,
- PP_Var web_session_id_var,
- PP_CdmExceptionCode exception_code,
- uint32 system_code,
- PP_Var error_description_var) override;
+ void SessionClosed(PP_Instance instance, PP_Var session_id_var) override;
+ void LegacySessionError(PP_Instance instance,
+ PP_Var session_id_var,
+ PP_CdmExceptionCode exception_code,
+ uint32 system_code,
+ PP_Var error_description_var) override;
void DeliverBlock(PP_Instance instance,
PP_Resource decrypted_block,
const PP_DecryptedBlockInfo* block_info) override;
@@ -535,6 +539,10 @@ class CONTENT_EXPORT PepperPluginInstanceImpl
// RenderFrameObserver
void OnDestruct() override;
+ // PluginInstanceThrottler::Observer
+ void OnThrottleStateChange() override;
+ void OnHiddenForPlaceholder(bool hidden) override;
+
void AddLatencyInfo(const std::vector<ui::LatencyInfo>& latency_info);
private:
@@ -687,8 +695,7 @@ class CONTENT_EXPORT PepperPluginInstanceImpl
int pending_host_id,
const ppapi::URLResponseInfoData& data);
- void SetPluginThrottled(bool throttled);
- void DisablePowerSaverByRetroactiveWhitelist();
+ void RecordFlashJavaScriptUse();
RenderFrameImpl* render_frame_;
base::Closure instance_deleted_callback_;
@@ -711,28 +718,21 @@ class CONTENT_EXPORT PepperPluginInstanceImpl
bool layer_is_hardware_;
// Plugin URL.
- GURL plugin_url_;
+ const GURL plugin_url_;
- // Set to true first time plugin is clicked. Used to collect metrics.
- bool has_been_clicked_;
-
- // Indicates whether this plugin may be throttled to reduce power consumption.
- // |power_saver_enabled_| implies |is_peripheral_content_|.
- bool power_saver_enabled_;
+ GURL document_url_;
- // Indicates whether this plugin was found to be peripheral content.
- // This is separately tracked from |power_saver_enabled_| to collect UMAs.
- // Always true if |power_saver_enabled_| is true.
- bool is_peripheral_content_;
+ // Used to track Flash-specific metrics.
+ const bool is_flash_plugin_;
- // Indicates if the plugin is currently throttled.
- bool plugin_throttled_;
+ // Set to true the first time the plugin is clicked. Used to collect metrics.
+ bool has_been_clicked_;
- // Fake view data used by the Power Saver feature to throttle plugins.
- const ppapi::ViewData empty_view_data_;
+ // Used to track if JavaScript has ever been used for this plugin instance.
+ bool javascript_used_;
// Responsible for turning on throttling if Power Saver is on.
- scoped_ptr<PepperPluginInstanceThrottler> throttler_;
+ scoped_ptr<PluginInstanceThrottlerImpl> throttler_;
// Indicates whether this is a full frame instance, which means it represents
// an entire document rather than an embed tag.
@@ -743,6 +743,8 @@ class CONTENT_EXPORT PepperPluginInstanceImpl
// The last state sent to the plugin. It is only valid after
// |sent_initial_did_change_view_| is set to true.
ppapi::ViewData last_sent_view_data_;
+ // The current unobscured portion of the plugin.
+ gfx::Rect unobscured_rect_;
// Indicates if we've ever sent a didChangeView to the plugin. This ensures we
// always send an initial notification, even if the position and clip are the
@@ -925,6 +927,8 @@ class CONTENT_EXPORT PepperPluginInstanceImpl
bool is_tracking_latency_;
+ bool initialized_;
+
// We use a weak ptr factory for scheduling DidChangeView events so that we
// can tell whether updates are pending and consolidate them. When there's
// already a weak ptr pending (HasWeakPtrs is true), code should update the
diff --git a/chromium/content/renderer/pepper/pepper_plugin_instance_metrics.cc b/chromium/content/renderer/pepper/pepper_plugin_instance_metrics.cc
new file mode 100644
index 00000000000..1c8a0e28f5a
--- /dev/null
+++ b/chromium/content/renderer/pepper/pepper_plugin_instance_metrics.cc
@@ -0,0 +1,108 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/pepper/pepper_plugin_instance_metrics.h"
+
+#include "base/metrics/histogram.h"
+#include "base/metrics/sparse_histogram.h"
+#include "ppapi/shared_impl/ppapi_preferences.h"
+
+#if defined(OS_WIN)
+#include "base/win/windows_version.h"
+#endif
+
+#define UMA_HISTOGRAM_ASPECT_RATIO(name, width, height) \
+ UMA_HISTOGRAM_SPARSE_SLOWLY( \
+ name, (height) ? ((width)*100) / (height) : kInfiniteRatio);
+
+namespace content {
+
+namespace {
+
+// Histogram tracking prevalence of tiny Flash instances. Units in pixels.
+enum PluginFlashTinyContentSize {
+ TINY_CONTENT_SIZE_1_1 = 0,
+ TINY_CONTENT_SIZE_5_5 = 1,
+ TINY_CONTENT_SIZE_10_10 = 2,
+ TINY_CONTENT_SIZE_LARGE = 3,
+ TINY_CONTENT_SIZE_NUM_ITEMS
+};
+
+const int kInfiniteRatio = 99999;
+
+const char kFlashClickSizeAspectRatioHistogram[] =
+ "Plugin.Flash.ClickSize.AspectRatio";
+const char kFlashClickSizeHeightHistogram[] = "Plugin.Flash.ClickSize.Height";
+const char kFlashClickSizeWidthHistogram[] = "Plugin.Flash.ClickSize.Width";
+const char kFlashTinyContentSizeHistogram[] = "Plugin.Flash.TinyContentSize";
+
+} // namespace
+
+void RecordFlashSizeMetric(int width, int height) {
+ PluginFlashTinyContentSize size = TINY_CONTENT_SIZE_LARGE;
+
+ if (width <= 1 && height <= 1)
+ size = TINY_CONTENT_SIZE_1_1;
+ else if (width <= 5 && height <= 5)
+ size = TINY_CONTENT_SIZE_5_5;
+ else if (width <= 10 && height <= 10)
+ size = TINY_CONTENT_SIZE_10_10;
+
+ UMA_HISTOGRAM_ENUMERATION(kFlashTinyContentSizeHistogram, size,
+ TINY_CONTENT_SIZE_NUM_ITEMS);
+}
+
+void RecordFlashClickSizeMetric(int width, int height) {
+ base::HistogramBase* width_histogram = base::LinearHistogram::FactoryGet(
+ kFlashClickSizeWidthHistogram,
+ 0, // minimum width
+ 500, // maximum width
+ 100, // number of buckets.
+ base::HistogramBase::kUmaTargetedHistogramFlag);
+ width_histogram->Add(width);
+
+ base::HistogramBase* height_histogram = base::LinearHistogram::FactoryGet(
+ kFlashClickSizeHeightHistogram,
+ 0, // minimum height
+ 400, // maximum height
+ 100, // number of buckets.
+ base::HistogramBase::kUmaTargetedHistogramFlag);
+ height_histogram->Add(height);
+
+ UMA_HISTOGRAM_ASPECT_RATIO(kFlashClickSizeAspectRatioHistogram, width,
+ height);
+}
+
+void SetGPUHistogram(const ppapi::Preferences& prefs,
+ const std::vector<std::string>& arg_names,
+ const std::vector<std::string>& arg_values) {
+// Calculate a histogram to let us determine how likely people are to try to
+// run Stage3D content on machines that have it blacklisted.
+#if defined(OS_WIN)
+ bool needs_gpu = false;
+ bool is_xp = base::win::GetVersion() <= base::win::VERSION_XP;
+
+ for (size_t i = 0; i < arg_names.size(); i++) {
+ if (arg_names[i] == "wmode") {
+ // In theory content other than Flash could have a "wmode" argument,
+ // but that's pretty unlikely.
+ if (arg_values[i] == "direct" || arg_values[i] == "gpu")
+ needs_gpu = true;
+ break;
+ }
+ }
+ // 0 : No 3D content and GPU is blacklisted
+ // 1 : No 3D content and GPU is not blacklisted
+ // 2 : 3D content but GPU is blacklisted
+ // 3 : 3D content and GPU is not blacklisted
+ // 4 : No 3D content and GPU is blacklisted on XP
+ // 5 : No 3D content and GPU is not blacklisted on XP
+ // 6 : 3D content but GPU is blacklisted on XP
+ // 7 : 3D content and GPU is not blacklisted on XP
+ UMA_HISTOGRAM_ENUMERATION(
+ "Flash.UsesGPU", is_xp * 4 + needs_gpu * 2 + prefs.is_webgl_supported, 8);
+#endif
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/pepper/pepper_plugin_instance_metrics.h b/chromium/content/renderer/pepper/pepper_plugin_instance_metrics.h
new file mode 100644
index 00000000000..02d92e06056
--- /dev/null
+++ b/chromium/content/renderer/pepper/pepper_plugin_instance_metrics.h
@@ -0,0 +1,29 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_PEPPER_PEPPER_PLUGIN_INSTANCE_METRICS_H_
+#define CONTENT_RENDERER_PEPPER_PEPPER_PLUGIN_INSTANCE_METRICS_H_
+
+#include <string>
+#include <vector>
+
+namespace ppapi {
+struct Preferences;
+}
+
+namespace content {
+
+// Record size metrics for all Flash instances.
+void RecordFlashSizeMetric(int width, int height);
+
+// Records size metrics for Flash instances that are clicked.
+void RecordFlashClickSizeMetric(int width, int height);
+
+void SetGPUHistogram(const ppapi::Preferences& prefs,
+ const std::vector<std::string>& arg_names,
+ const std::vector<std::string>& arg_values);
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_PEPPER_PEPPER_PLUGIN_INSTANCE_METRICS_H_
diff --git a/chromium/content/renderer/pepper/pepper_plugin_instance_throttler.cc b/chromium/content/renderer/pepper/pepper_plugin_instance_throttler.cc
deleted file mode 100644
index f1d02b9e068..00000000000
--- a/chromium/content/renderer/pepper/pepper_plugin_instance_throttler.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/renderer/pepper/pepper_plugin_instance_throttler.h"
-
-#include "base/message_loop/message_loop.h"
-#include "base/time/time.h"
-
-namespace content {
-
-namespace {
-
-// When we give up waiting for a suitable preview frame, and simply suspend
-// the plugin where it's at. In milliseconds.
-const int kThrottleTimeout = 5000;
-}
-
-PepperPluginInstanceThrottler::PepperPluginInstanceThrottler(
- const base::Closure& throttle_closure) {
- DCHECK(!throttle_closure.is_null());
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE, throttle_closure,
- base::TimeDelta::FromMilliseconds(kThrottleTimeout));
-}
-
-PepperPluginInstanceThrottler::~PepperPluginInstanceThrottler() {
-}
-
-} // namespace content
diff --git a/chromium/content/renderer/pepper/pepper_plugin_instance_throttler.h b/chromium/content/renderer/pepper/pepper_plugin_instance_throttler.h
deleted file mode 100644
index 15a5c10af3c..00000000000
--- a/chromium/content/renderer/pepper/pepper_plugin_instance_throttler.h
+++ /dev/null
@@ -1,29 +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_RENDERER_PEPPER_PEPPER_PLUGIN_INSTANCE_THROTTLER_H_
-#define CONTENT_RENDERER_PEPPER_PEPPER_PLUGIN_INSTANCE_THROTTLER_H_
-
-#include "base/callback_forward.h"
-#include "base/macros.h"
-
-namespace content {
-
-// Throttles Pepper Plugin instances in Power Saver mode. Currently just a
-// stub implementation that engages throttling after a fixed timeout.
-// In the future, will examine plugin frames to find a suitable preview
-// image before engaging throttling.
-class PepperPluginInstanceThrottler {
- public:
- // |throttle_closure| is called to engage throttling.
- explicit PepperPluginInstanceThrottler(const base::Closure& throttle_closure);
-
- virtual ~PepperPluginInstanceThrottler();
-
- private:
- DISALLOW_COPY_AND_ASSIGN(PepperPluginInstanceThrottler);
-};
-}
-
-#endif // CONTENT_RENDERER_PEPPER_PEPPER_PLUGIN_INSTANCE_THROTTLER_H_
diff --git a/chromium/content/renderer/pepper/pepper_try_catch.cc b/chromium/content/renderer/pepper/pepper_try_catch.cc
index ec843692214..938dac405d8 100644
--- a/chromium/content/renderer/pepper/pepper_try_catch.cc
+++ b/chromium/content/renderer/pepper/pepper_try_catch.cc
@@ -26,22 +26,22 @@ PepperTryCatch::PepperTryCatch(PepperPluginInstanceImpl* instance,
PepperTryCatch::~PepperTryCatch() {}
-v8::Handle<v8::Value> PepperTryCatch::ToV8(PP_Var var) {
+v8::Local<v8::Value> PepperTryCatch::ToV8(PP_Var var) {
if (HasException()) {
SetException(kConversionException);
- return v8::Handle<v8::Value>();
+ return v8::Local<v8::Value>();
}
- v8::Handle<v8::Value> result;
+ v8::Local<v8::Value> result;
bool success = var_converter_->ToV8Value(var, GetContext(), &result);
if (!success) {
SetException(kConversionException);
- return v8::Handle<v8::Value>();
+ return v8::Local<v8::Value>();
}
return result;
}
-ppapi::ScopedPPVar PepperTryCatch::FromV8(v8::Handle<v8::Value> v8_value) {
+ppapi::ScopedPPVar PepperTryCatch::FromV8(v8::Local<v8::Value> v8_value) {
if (HasException() || v8_value.IsEmpty()) {
SetException(kConversionException);
return ppapi::ScopedPPVar();
@@ -79,7 +79,7 @@ bool PepperTryCatchV8::HasException() {
return GetContext().IsEmpty() || exception_.type != PP_VARTYPE_UNDEFINED;
}
-v8::Handle<v8::Context> PepperTryCatchV8::GetContext() {
+v8::Local<v8::Context> PepperTryCatchV8::GetContext() {
// When calling from JS into the plugin always use the current context.
return instance_->GetIsolate()->GetCurrentContext();
}
@@ -122,9 +122,17 @@ PepperTryCatchVar::PepperTryCatchVar(PepperPluginInstanceImpl* instance,
PP_Var* exception)
: PepperTryCatch(instance, var_converter),
handle_scope_(instance_->GetIsolate()),
- context_(GetContext()),
exception_(exception),
exception_is_set_(false) {
+ // Store a handle to the context here for 2 reasons:
+ // 1) To hold a handle to it in case all other handles are destroyed.
+ // 2) Because calling PepperPluginInstanceImpl::GetMainWorldContext() later
+ // can result in trying to access the plugin element. However the plugin
+ // element may have been destroyed during the PepperTryCatchVar (for
+ // example if a script is executed which destroys the plugin element). So
+ // we want to avoid accessing the plugin element again beyond this point.
+ context_ = instance_->GetMainWorldContext();
+
// We switch to the plugin context if it's not empty.
if (!context_.IsEmpty())
context_->Enter();
@@ -140,11 +148,16 @@ bool PepperTryCatchVar::HasException() {
return true;
std::string exception_message;
- if (GetContext().IsEmpty()) {
+ if (context_.IsEmpty()) {
exception_message = "The v8 context has been destroyed.";
} else if (try_catch_.HasCaught()) {
- v8::String::Utf8Value utf8(try_catch_.Message()->Get());
- exception_message = std::string(*utf8, utf8.length());
+ v8::Local<v8::Message> message(try_catch_.Message());
+ if (!message.IsEmpty()) {
+ v8::String::Utf8Value utf8(try_catch_.Message()->Get());
+ exception_message = std::string(*utf8, utf8.length());
+ } else {
+ exception_message = "There was a v8 exception.";
+ }
}
if (!exception_message.empty()) {
@@ -156,9 +169,8 @@ bool PepperTryCatchVar::HasException() {
return exception_is_set_;
}
-v8::Handle<v8::Context> PepperTryCatchVar::GetContext() {
- // When calling into JS from the plugin, always use the plugin context.
- return instance_->GetMainWorldContext();
+v8::Local<v8::Context> PepperTryCatchVar::GetContext() {
+ return context_;
}
void PepperTryCatchVar::SetException(const char* message) {
diff --git a/chromium/content/renderer/pepper/pepper_try_catch.h b/chromium/content/renderer/pepper/pepper_try_catch.h
index 72d03bf928a..8dbbb9b51cc 100644
--- a/chromium/content/renderer/pepper/pepper_try_catch.h
+++ b/chromium/content/renderer/pepper/pepper_try_catch.h
@@ -29,12 +29,12 @@ class CONTENT_EXPORT PepperTryCatch {
virtual void SetException(const char* message) = 0;
virtual bool HasException() = 0;
// Gets the context to execute scripts in.
- virtual v8::Handle<v8::Context> GetContext() = 0;
+ virtual v8::Local<v8::Context> GetContext() = 0;
// Convenience functions for doing conversions to/from V8 values and sets an
// exception if there is an error in the conversion.
- v8::Handle<v8::Value> ToV8(PP_Var var);
- ppapi::ScopedPPVar FromV8(v8::Handle<v8::Value> v8_value);
+ v8::Local<v8::Value> ToV8(PP_Var var);
+ ppapi::ScopedPPVar FromV8(v8::Local<v8::Value> v8_value);
protected:
// Make sure that |instance_| is alive for the lifetime of PepperTryCatch.
@@ -64,7 +64,7 @@ class PepperTryCatchV8 : public PepperTryCatch {
// PepperTryCatch
void SetException(const char* message) override;
bool HasException() override;
- v8::Handle<v8::Context> GetContext() override;
+ v8::Local<v8::Context> GetContext() override;
private:
PP_Var exception_;
@@ -86,14 +86,14 @@ class PepperTryCatchVar : public PepperTryCatch {
// PepperTryCatch
void SetException(const char* message) override;
bool HasException() override;
- v8::Handle<v8::Context> GetContext() override;
+ v8::Local<v8::Context> GetContext() override;
private:
// Code which uses PepperTryCatchVar doesn't typically have a HandleScope,
// make one for them. Note that this class is always allocated on the stack.
v8::HandleScope handle_scope_;
- v8::Handle<v8::Context> context_;
+ v8::Local<v8::Context> context_;
v8::TryCatch try_catch_;
diff --git a/chromium/content/renderer/pepper/pepper_url_loader_host.cc b/chromium/content/renderer/pepper/pepper_url_loader_host.cc
index 5f70dfa83b7..637125bc5f7 100644
--- a/chromium/content/renderer/pepper/pepper_url_loader_host.cc
+++ b/chromium/content/renderer/pepper/pepper_url_loader_host.cc
@@ -378,9 +378,10 @@ void PepperURLLoaderHost::Close() {
}
blink::WebLocalFrame* PepperURLLoaderHost::GetFrame() {
- PepperPluginInstance* instance_object =
- renderer_ppapi_host_->GetPluginInstance(pp_instance());
- if (!instance_object)
+ PepperPluginInstanceImpl* instance_object =
+ static_cast<PepperPluginInstanceImpl*>(
+ renderer_ppapi_host_->GetPluginInstance(pp_instance()));
+ if (!instance_object || instance_object->is_deleted())
return NULL;
return instance_object->GetContainer()->element().document().frame();
}
diff --git a/chromium/content/renderer/pepper/pepper_url_request_unittest.cc b/chromium/content/renderer/pepper/pepper_url_request_unittest.cc
index e9008ec5800..bd5f3ae37ba 100644
--- a/chromium/content/renderer/pepper/pepper_url_request_unittest.cc
+++ b/chromium/content/renderer/pepper/pepper_url_request_unittest.cc
@@ -59,8 +59,6 @@ class URLRequestInfoTest : public RenderViewTest {
void SetUp() override {
RenderViewTest::SetUp();
- ppapi::ProxyLock::DisableLockingOnThreadForTest();
-
test_globals_.GetResourceTracker()->DidCreateInstance(pp_instance_);
// This resource doesn't do IPC, so a null connection is fine.
@@ -114,6 +112,9 @@ class URLRequestInfoTest : public RenderViewTest {
PP_Instance pp_instance_;
+ // Disables locking for the duration of the test.
+ ppapi::ProxyLock::LockingDisablerForTest disable_locking_;
+
// Needs to be alive for resource tracking to work.
ppapi::TestGlobals test_globals_;
diff --git a/chromium/content/renderer/pepper/pepper_video_capture_host.cc b/chromium/content/renderer/pepper/pepper_video_capture_host.cc
index 6e8ea32f8b0..820dd12b67c 100644
--- a/chromium/content/renderer/pepper/pepper_video_capture_host.cc
+++ b/chromium/content/renderer/pepper/pepper_video_capture_host.cc
@@ -4,6 +4,7 @@
#include "content/renderer/pepper/pepper_video_capture_host.h"
+#include "content/renderer/media/media_stream_video_source.h"
#include "content/renderer/pepper/host_globals.h"
#include "content/renderer/pepper/pepper_media_device_manager.h"
#include "content/renderer/pepper/pepper_platform_video_capture.h"
@@ -120,31 +121,36 @@ void PepperVideoCaptureHost::PostErrorReply() {
}
void PepperVideoCaptureHost::OnFrameReady(
- const scoped_refptr<media::VideoFrame>& frame,
- media::VideoCaptureFormat format) {
+ const scoped_refptr<media::VideoFrame>& frame) {
DCHECK(frame.get());
- if (alloc_size_ != frame->coded_size() || buffers_.empty()) {
- AllocBuffers(frame->coded_size(), format.frame_rate);
- alloc_size_ = frame->coded_size();
+ if (alloc_size_ != frame->visible_rect().size() || buffers_.empty()) {
+ alloc_size_ = frame->visible_rect().size();
+ double frame_rate;
+ int rounded_frame_rate;
+ if (frame->metadata()->GetDouble(media::VideoFrameMetadata::FRAME_RATE,
+ &frame_rate))
+ rounded_frame_rate = static_cast<int>(frame_rate + 0.5 /* round */);
+ else
+ rounded_frame_rate = MediaStreamVideoSource::kUnknownFrameRate;
+ AllocBuffers(alloc_size_, rounded_frame_rate);
}
for (uint32_t i = 0; i < buffers_.size(); ++i) {
if (!buffers_[i].in_use) {
DCHECK_EQ(frame->format(), media::VideoFrame::I420);
if (buffers_[i].buffer->size() <
- media::VideoFrame::AllocationSize(frame->format(),
- frame->coded_size())) {
+ media::VideoFrame::AllocationSize(frame->format(), alloc_size_)) {
// TODO(ihf): handle size mismatches gracefully here.
return;
}
uint8* dst = reinterpret_cast<uint8*>(buffers_[i].data);
- COMPILE_ASSERT(media::VideoFrame::kYPlane == 0, y_plane_should_be_0);
- COMPILE_ASSERT(media::VideoFrame::kUPlane == 1, u_plane_should_be_1);
- COMPILE_ASSERT(media::VideoFrame::kVPlane == 2, v_plane_should_be_2);
+ static_assert(media::VideoFrame::kYPlane == 0, "y plane should be 0");
+ static_assert(media::VideoFrame::kUPlane == 1, "u plane should be 1");
+ static_assert(media::VideoFrame::kVPlane == 2, "v plane should be 2");
for (size_t j = 0; j < media::VideoFrame::NumPlanes(frame->format());
++j) {
- const uint8* src = frame->data(j);
+ const uint8* src = frame->visible_data(j);
const size_t row_bytes = frame->row_bytes(j);
const size_t src_stride = frame->stride(j);
for (int k = 0; k < frame->rows(j); ++k) {
diff --git a/chromium/content/renderer/pepper/pepper_video_capture_host.h b/chromium/content/renderer/pepper/pepper_video_capture_host.h
index 3c5ec12d15a..24061b5e750 100644
--- a/chromium/content/renderer/pepper/pepper_video_capture_host.h
+++ b/chromium/content/renderer/pepper/pepper_video_capture_host.h
@@ -12,7 +12,7 @@
#include "content/public/renderer/renderer_ppapi_host.h"
#include "content/renderer/pepper/pepper_device_enumeration_host_helper.h"
#include "content/renderer/pepper/ppb_buffer_impl.h"
-#include "media/video/capture/video_capture_types.h"
+#include "media/base/video_capture_types.h"
#include "ppapi/c/dev/ppp_video_capture_dev.h"
#include "ppapi/host/host_message_context.h"
#include "ppapi/host/resource_host.h"
@@ -59,8 +59,7 @@ class PepperVideoCaptureHost : public ppapi::host::ResourceHost {
void OnError();
// Called when a video frame is ready.
- void OnFrameReady(const scoped_refptr<media::VideoFrame>& frame,
- media::VideoCaptureFormat format);
+ void OnFrameReady(const scoped_refptr<media::VideoFrame>& frame);
private:
int32_t OnOpen(ppapi::host::HostMessageContext* context,
diff --git a/chromium/content/renderer/pepper/pepper_video_decoder_host.cc b/chromium/content/renderer/pepper/pepper_video_decoder_host.cc
index 02e14f3be5c..4aecd5322eb 100644
--- a/chromium/content/renderer/pepper/pepper_video_decoder_host.cc
+++ b/chromium/content/renderer/pepper/pepper_video_decoder_host.cc
@@ -7,6 +7,7 @@
#include "base/bind.h"
#include "base/memory/shared_memory.h"
#include "content/common/gpu/client/gpu_channel_host.h"
+#include "content/common/pepper_file_util.h"
#include "content/public/renderer/render_thread.h"
#include "content/public/renderer/renderer_ppapi_host.h"
#include "content/renderer/pepper/gfx_conversion.h"
@@ -195,13 +196,8 @@ int32_t PepperVideoDecoderHost::OnHostMsgGetShm(
shm_buffers_[shm_id] = shm.release();
}
-#if defined(OS_WIN)
- base::PlatformFile platform_file = shm_handle;
-#elif defined(OS_POSIX)
- base::PlatformFile platform_file = shm_handle.fd;
-#else
-#error Not implemented.
-#endif
+ base::PlatformFile platform_file =
+ PlatformFileFromSharedMemoryHandle(shm_handle);
SerializedHandle handle(
renderer_ppapi_host_->ShareHandleWithRemote(platform_file, false),
shm_size);
@@ -272,7 +268,24 @@ int32_t PepperVideoDecoderHost::OnHostMsgRecyclePicture(
return PP_ERROR_FAILED;
DCHECK(decoder_);
- decoder_->ReusePictureBuffer(texture_id);
+ TextureSet::iterator it = pictures_in_use_.find(texture_id);
+ if (it == pictures_in_use_.end())
+ return PP_ERROR_BADARGUMENT;
+
+ pictures_in_use_.erase(it);
+
+ TextureSet::iterator dismissed_texture =
+ dismissed_pictures_in_use_.find(texture_id);
+ if (dismissed_texture != dismissed_pictures_in_use_.end()) {
+ // The texture was already dismissed by the decoder. Notify the plugin.
+ host()->SendUnsolicitedReply(
+ pp_resource(),
+ PpapiPluginMsg_VideoDecoder_DismissPicture(texture_id));
+ dismissed_pictures_in_use_.erase(dismissed_texture);
+ } else {
+ decoder_->ReusePictureBuffer(texture_id);
+ }
+
return PP_OK;
}
@@ -317,6 +330,10 @@ void PepperVideoDecoderHost::ProvidePictureBuffers(
void PepperVideoDecoderHost::PictureReady(const media::Picture& picture) {
// Don't bother validating the visible rect, since the plugin process is less
// trusted than the gpu process.
+ DCHECK(pictures_in_use_.find(picture.picture_buffer_id()) ==
+ pictures_in_use_.end());
+ pictures_in_use_.insert(picture.picture_buffer_id());
+
PP_Rect visible_rect = PP_FromGfxRect(picture.visible_rect());
host()->SendUnsolicitedReply(pp_resource(),
PpapiPluginMsg_VideoDecoder_PictureReady(
@@ -325,6 +342,13 @@ void PepperVideoDecoderHost::PictureReady(const media::Picture& picture) {
}
void PepperVideoDecoderHost::DismissPictureBuffer(int32 picture_buffer_id) {
+ // If the texture is still used by the plugin keep it until the plugin
+ // recycles it.
+ if (pictures_in_use_.find(picture_buffer_id) != pictures_in_use_.end()) {
+ dismissed_pictures_in_use_.insert(picture_buffer_id);
+ return;
+ }
+
host()->SendUnsolicitedReply(
pp_resource(),
PpapiPluginMsg_VideoDecoder_DismissPicture(picture_buffer_id));
diff --git a/chromium/content/renderer/pepper/pepper_video_decoder_host.h b/chromium/content/renderer/pepper/pepper_video_decoder_host.h
index fab65d891ad..0a92aebbb9d 100644
--- a/chromium/content/renderer/pepper/pepper_video_decoder_host.h
+++ b/chromium/content/renderer/pepper/pepper_video_decoder_host.h
@@ -109,6 +109,10 @@ class CONTENT_EXPORT PepperVideoDecoderHost
// This is parallel to |shm_buffers_|.
std::vector<uint8_t> shm_buffer_busy_;
+ typedef std::set<uint32_t> TextureSet;
+ TextureSet pictures_in_use_;
+ TextureSet dismissed_pictures_in_use_;
+
// Maps decode uid to PendingDecode info.
typedef base::hash_map<int32_t, PendingDecode> PendingDecodeMap;
PendingDecodeMap pending_decodes_;
diff --git a/chromium/content/renderer/pepper/pepper_video_destination_host.cc b/chromium/content/renderer/pepper/pepper_video_destination_host.cc
index 5254374b1b0..8773046fd2c 100644
--- a/chromium/content/renderer/pepper/pepper_video_destination_host.cc
+++ b/chromium/content/renderer/pepper/pepper_video_destination_host.cc
@@ -24,7 +24,9 @@ PepperVideoDestinationHost::PepperVideoDestinationHost(RendererPpapiHost* host,
PP_Instance instance,
PP_Resource resource)
: ResourceHost(host->GetPpapiHost(), instance, resource),
- renderer_ppapi_host_(host),
+#if DCHECK_IS_ON()
+ has_received_frame_(false),
+#endif
weak_factory_(this) {}
PepperVideoDestinationHost::~PepperVideoDestinationHost() {}
@@ -80,13 +82,18 @@ int32_t PepperVideoDestinationHost::OnHostMsgPutFrame(
if (!frame_writer_.get())
return PP_ERROR_FAILED;
- // Convert PP_TimeTicks (a double, in seconds) to a TimeDelta (int64,
- // microseconds) and then to a video timestamp (int64, nanoseconds). All times
- // are relative to the Unix Epoch so don't subtract it to get a delta.
- base::TimeDelta time_delta =
- base::Time::FromDoubleT(timestamp) - base::Time();
- int64_t timestamp_ns =
- time_delta.InMicroseconds() * base::Time::kNanosecondsPerMicrosecond;
+ // Convert PP_TimeTicks (a double, in seconds) to a video timestamp (int64,
+ // nanoseconds).
+ const int64_t timestamp_ns =
+ static_cast<int64_t>(timestamp * base::Time::kNanosecondsPerSecond);
+ // Check that timestamps are strictly increasing.
+#if DCHECK_IS_ON()
+ if (has_received_frame_)
+ DCHECK_GT(timestamp_ns, previous_timestamp_ns_);
+ has_received_frame_ = true;
+ previous_timestamp_ns_ = timestamp_ns;
+#endif
+
frame_writer_->PutFrame(image_data_impl, timestamp_ns);
return PP_OK;
diff --git a/chromium/content/renderer/pepper/pepper_video_destination_host.h b/chromium/content/renderer/pepper/pepper_video_destination_host.h
index 3eb2b222625..7d56d058301 100644
--- a/chromium/content/renderer/pepper/pepper_video_destination_host.h
+++ b/chromium/content/renderer/pepper/pepper_video_destination_host.h
@@ -38,9 +38,12 @@ class CONTENT_EXPORT PepperVideoDestinationHost
PP_TimeTicks timestamp);
int32_t OnHostMsgClose(ppapi::host::HostMessageContext* context);
- RendererPpapiHost* renderer_ppapi_host_;
-
scoped_ptr<FrameWriterInterface> frame_writer_;
+ // Used for checking that timestamps are strictly increasing.
+#if DCHECK_IS_ON()
+ bool has_received_frame_;
+ int64_t previous_timestamp_ns_;
+#endif
base::WeakPtrFactory<PepperVideoDestinationHost> weak_factory_;
diff --git a/chromium/content/renderer/pepper/pepper_video_encoder_host.cc b/chromium/content/renderer/pepper/pepper_video_encoder_host.cc
new file mode 100644
index 00000000000..732cf741e1c
--- /dev/null
+++ b/chromium/content/renderer/pepper/pepper_video_encoder_host.cc
@@ -0,0 +1,671 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/memory/shared_memory.h"
+#include "base/numerics/safe_math.h"
+#include "content/common/gpu/client/command_buffer_proxy_impl.h"
+#include "content/common/gpu/media/gpu_video_accelerator_util.h"
+#include "content/common/pepper_file_util.h"
+#include "content/public/renderer/renderer_ppapi_host.h"
+#include "content/renderer/pepper/gfx_conversion.h"
+#include "content/renderer/pepper/host_globals.h"
+#include "content/renderer/pepper/pepper_video_encoder_host.h"
+#include "content/renderer/pepper/video_encoder_shim.h"
+#include "content/renderer/render_thread_impl.h"
+#include "media/base/bind_to_current_loop.h"
+#include "media/base/video_frame.h"
+#include "media/renderers/gpu_video_accelerator_factories.h"
+#include "media/video/video_encode_accelerator.h"
+#include "ppapi/c/pp_codecs.h"
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/c/pp_graphics_3d.h"
+#include "ppapi/host/dispatch_host_message.h"
+#include "ppapi/host/ppapi_host.h"
+#include "ppapi/proxy/ppapi_messages.h"
+#include "ppapi/shared_impl/media_stream_buffer.h"
+
+using ppapi::proxy::SerializedHandle;
+
+namespace content {
+
+namespace {
+
+const uint32_t kDefaultNumberOfBitstreamBuffers = 4;
+
+int32_t PP_FromMediaEncodeAcceleratorError(
+ media::VideoEncodeAccelerator::Error error) {
+ switch (error) {
+ case media::VideoEncodeAccelerator::kInvalidArgumentError:
+ return PP_ERROR_MALFORMED_INPUT;
+ case media::VideoEncodeAccelerator::kIllegalStateError:
+ case media::VideoEncodeAccelerator::kPlatformFailureError:
+ return PP_ERROR_RESOURCE_FAILED;
+ // No default case, to catch unhandled enum values.
+ }
+ return PP_ERROR_FAILED;
+}
+
+// TODO(llandwerlin): move following to media_conversion.cc/h?
+media::VideoCodecProfile PP_ToMediaVideoProfile(PP_VideoProfile profile) {
+ switch (profile) {
+ case PP_VIDEOPROFILE_H264BASELINE:
+ return media::H264PROFILE_BASELINE;
+ case PP_VIDEOPROFILE_H264MAIN:
+ return media::H264PROFILE_MAIN;
+ case PP_VIDEOPROFILE_H264EXTENDED:
+ return media::H264PROFILE_EXTENDED;
+ case PP_VIDEOPROFILE_H264HIGH:
+ return media::H264PROFILE_HIGH;
+ case PP_VIDEOPROFILE_H264HIGH10PROFILE:
+ return media::H264PROFILE_HIGH10PROFILE;
+ case PP_VIDEOPROFILE_H264HIGH422PROFILE:
+ return media::H264PROFILE_HIGH422PROFILE;
+ case PP_VIDEOPROFILE_H264HIGH444PREDICTIVEPROFILE:
+ return media::H264PROFILE_HIGH444PREDICTIVEPROFILE;
+ case PP_VIDEOPROFILE_H264SCALABLEBASELINE:
+ return media::H264PROFILE_SCALABLEBASELINE;
+ case PP_VIDEOPROFILE_H264SCALABLEHIGH:
+ return media::H264PROFILE_SCALABLEHIGH;
+ case PP_VIDEOPROFILE_H264STEREOHIGH:
+ return media::H264PROFILE_STEREOHIGH;
+ case PP_VIDEOPROFILE_H264MULTIVIEWHIGH:
+ return media::H264PROFILE_MULTIVIEWHIGH;
+ case PP_VIDEOPROFILE_VP8_ANY:
+ return media::VP8PROFILE_ANY;
+ case PP_VIDEOPROFILE_VP9_ANY:
+ return media::VP9PROFILE_ANY;
+ // No default case, to catch unhandled PP_VideoProfile values.
+ }
+ return media::VIDEO_CODEC_PROFILE_UNKNOWN;
+}
+
+PP_VideoProfile PP_FromMediaVideoProfile(media::VideoCodecProfile profile) {
+ switch (profile) {
+ case media::H264PROFILE_BASELINE:
+ return PP_VIDEOPROFILE_H264BASELINE;
+ case media::H264PROFILE_MAIN:
+ return PP_VIDEOPROFILE_H264MAIN;
+ case media::H264PROFILE_EXTENDED:
+ return PP_VIDEOPROFILE_H264EXTENDED;
+ case media::H264PROFILE_HIGH:
+ return PP_VIDEOPROFILE_H264HIGH;
+ case media::H264PROFILE_HIGH10PROFILE:
+ return PP_VIDEOPROFILE_H264HIGH10PROFILE;
+ case media::H264PROFILE_HIGH422PROFILE:
+ return PP_VIDEOPROFILE_H264HIGH422PROFILE;
+ case media::H264PROFILE_HIGH444PREDICTIVEPROFILE:
+ return PP_VIDEOPROFILE_H264HIGH444PREDICTIVEPROFILE;
+ case media::H264PROFILE_SCALABLEBASELINE:
+ return PP_VIDEOPROFILE_H264SCALABLEBASELINE;
+ case media::H264PROFILE_SCALABLEHIGH:
+ return PP_VIDEOPROFILE_H264SCALABLEHIGH;
+ case media::H264PROFILE_STEREOHIGH:
+ return PP_VIDEOPROFILE_H264STEREOHIGH;
+ case media::H264PROFILE_MULTIVIEWHIGH:
+ return PP_VIDEOPROFILE_H264MULTIVIEWHIGH;
+ case media::VP8PROFILE_ANY:
+ return PP_VIDEOPROFILE_VP8_ANY;
+ case media::VP9PROFILE_ANY:
+ return PP_VIDEOPROFILE_VP9_ANY;
+ default:
+ NOTREACHED();
+ return static_cast<PP_VideoProfile>(-1);
+ }
+}
+
+media::VideoFrame::Format PP_ToMediaVideoFormat(PP_VideoFrame_Format format) {
+ switch (format) {
+ case PP_VIDEOFRAME_FORMAT_UNKNOWN:
+ return media::VideoFrame::UNKNOWN;
+ case PP_VIDEOFRAME_FORMAT_YV12:
+ return media::VideoFrame::YV12;
+ case PP_VIDEOFRAME_FORMAT_I420:
+ return media::VideoFrame::I420;
+ case PP_VIDEOFRAME_FORMAT_BGRA:
+ return media::VideoFrame::UNKNOWN;
+ // No default case, to catch unhandled PP_VideoFrame_Format values.
+ }
+ return media::VideoFrame::UNKNOWN;
+}
+
+PP_VideoFrame_Format PP_FromMediaVideoFormat(media::VideoFrame::Format format) {
+ switch (format) {
+ case media::VideoFrame::UNKNOWN:
+ return PP_VIDEOFRAME_FORMAT_UNKNOWN;
+ case media::VideoFrame::YV12:
+ return PP_VIDEOFRAME_FORMAT_YV12;
+ case media::VideoFrame::I420:
+ return PP_VIDEOFRAME_FORMAT_I420;
+ default:
+ return PP_VIDEOFRAME_FORMAT_UNKNOWN;
+ }
+}
+
+PP_VideoProfileDescription PP_FromVideoEncodeAcceleratorSupportedProfile(
+ media::VideoEncodeAccelerator::SupportedProfile profile,
+ PP_Bool hardware_accelerated) {
+ PP_VideoProfileDescription pp_profile;
+ pp_profile.profile = PP_FromMediaVideoProfile(profile.profile);
+ pp_profile.max_resolution = PP_FromGfxSize(profile.max_resolution);
+ pp_profile.max_framerate_numerator = profile.max_framerate_numerator;
+ pp_profile.max_framerate_denominator = profile.max_framerate_denominator;
+ pp_profile.hardware_accelerated = hardware_accelerated;
+ return pp_profile;
+}
+
+bool PP_HardwareAccelerationCompatible(bool accelerated,
+ PP_HardwareAcceleration requested) {
+ switch (requested) {
+ case PP_HARDWAREACCELERATION_ONLY:
+ return accelerated;
+ case PP_HARDWAREACCELERATION_NONE:
+ return !accelerated;
+ case PP_HARDWAREACCELERATION_WITHFALLBACK:
+ return true;
+ // No default case, to catch unhandled PP_HardwareAcceleration values.
+ }
+ return false;
+}
+
+} // namespace
+
+PepperVideoEncoderHost::ShmBuffer::ShmBuffer(uint32_t id,
+ scoped_ptr<base::SharedMemory> shm)
+ : id(id), shm(shm.Pass()), in_use(true) {
+ DCHECK(this->shm);
+}
+
+PepperVideoEncoderHost::ShmBuffer::~ShmBuffer() {
+}
+
+media::BitstreamBuffer PepperVideoEncoderHost::ShmBuffer::ToBitstreamBuffer() {
+ return media::BitstreamBuffer(id, shm->handle(), shm->mapped_size());
+}
+
+PepperVideoEncoderHost::PepperVideoEncoderHost(RendererPpapiHost* host,
+ PP_Instance instance,
+ PP_Resource resource)
+ : ResourceHost(host->GetPpapiHost(), instance, resource),
+ renderer_ppapi_host_(host),
+ buffer_manager_(this),
+ command_buffer_(nullptr),
+ initialized_(false),
+ encoder_last_error_(PP_ERROR_FAILED),
+ frame_count_(0),
+ media_input_format_(media::VideoFrame::UNKNOWN),
+ weak_ptr_factory_(this) {
+}
+
+PepperVideoEncoderHost::~PepperVideoEncoderHost() {
+ Close();
+}
+
+int32_t PepperVideoEncoderHost::OnResourceMessageReceived(
+ const IPC::Message& msg,
+ ppapi::host::HostMessageContext* context) {
+ PPAPI_BEGIN_MESSAGE_MAP(PepperVideoEncoderHost, msg)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
+ PpapiHostMsg_VideoEncoder_GetSupportedProfiles,
+ OnHostMsgGetSupportedProfiles)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoEncoder_Initialize,
+ OnHostMsgInitialize)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
+ PpapiHostMsg_VideoEncoder_GetVideoFrames,
+ OnHostMsgGetVideoFrames)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoEncoder_Encode,
+ OnHostMsgEncode)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL(
+ PpapiHostMsg_VideoEncoder_RecycleBitstreamBuffer,
+ OnHostMsgRecycleBitstreamBuffer)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL(
+ PpapiHostMsg_VideoEncoder_RequestEncodingParametersChange,
+ OnHostMsgRequestEncodingParametersChange)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_VideoEncoder_Close,
+ OnHostMsgClose)
+ PPAPI_END_MESSAGE_MAP()
+ return PP_ERROR_FAILED;
+}
+
+int32_t PepperVideoEncoderHost::OnHostMsgGetSupportedProfiles(
+ ppapi::host::HostMessageContext* context) {
+ std::vector<PP_VideoProfileDescription> pp_profiles;
+ GetSupportedProfiles(&pp_profiles);
+
+ host()->SendReply(
+ context->MakeReplyMessageContext(),
+ PpapiPluginMsg_VideoEncoder_GetSupportedProfilesReply(pp_profiles));
+
+ return PP_OK_COMPLETIONPENDING;
+}
+
+int32_t PepperVideoEncoderHost::OnHostMsgInitialize(
+ ppapi::host::HostMessageContext* context,
+ PP_VideoFrame_Format input_format,
+ const PP_Size& input_visible_size,
+ PP_VideoProfile output_profile,
+ uint32_t initial_bitrate,
+ PP_HardwareAcceleration acceleration) {
+ if (initialized_)
+ return PP_ERROR_FAILED;
+
+ media_input_format_ = PP_ToMediaVideoFormat(input_format);
+ if (media_input_format_ == media::VideoFrame::UNKNOWN)
+ return PP_ERROR_BADARGUMENT;
+
+ media::VideoCodecProfile media_profile =
+ PP_ToMediaVideoProfile(output_profile);
+ if (media_profile == media::VIDEO_CODEC_PROFILE_UNKNOWN)
+ return PP_ERROR_BADARGUMENT;
+
+ gfx::Size input_size(input_visible_size.width, input_visible_size.height);
+ if (input_size.IsEmpty())
+ return PP_ERROR_BADARGUMENT;
+
+ if (!IsInitializationValid(input_visible_size, output_profile, acceleration))
+ return PP_ERROR_NOTSUPPORTED;
+
+ int32_t error = PP_ERROR_NOTSUPPORTED;
+ initialize_reply_context_ = context->MakeReplyMessageContext();
+
+ if (acceleration != PP_HARDWAREACCELERATION_NONE) {
+ if (InitializeHardware(media_input_format_, input_size, media_profile,
+ initial_bitrate))
+ return PP_OK_COMPLETIONPENDING;
+
+ if (acceleration == PP_HARDWAREACCELERATION_ONLY)
+ error = PP_ERROR_FAILED;
+ }
+
+#if defined(OS_ANDROID)
+ initialize_reply_context_ = ppapi::host::ReplyMessageContext();
+ Close();
+ return error;
+#else
+ if (acceleration != PP_HARDWAREACCELERATION_ONLY) {
+ encoder_.reset(new VideoEncoderShim(this));
+ if (encoder_->Initialize(media_input_format_, input_size, media_profile,
+ initial_bitrate, this))
+ return PP_OK_COMPLETIONPENDING;
+ error = PP_ERROR_FAILED;
+ }
+
+ initialize_reply_context_ = ppapi::host::ReplyMessageContext();
+ Close();
+ return error;
+#endif
+}
+
+int32_t PepperVideoEncoderHost::OnHostMsgGetVideoFrames(
+ ppapi::host::HostMessageContext* context) {
+ if (encoder_last_error_)
+ return encoder_last_error_;
+
+ get_video_frames_reply_context_ = context->MakeReplyMessageContext();
+ AllocateVideoFrames();
+
+ return PP_OK_COMPLETIONPENDING;
+}
+
+int32_t PepperVideoEncoderHost::OnHostMsgEncode(
+ ppapi::host::HostMessageContext* context,
+ uint32_t frame_id,
+ bool force_keyframe) {
+ if (encoder_last_error_)
+ return encoder_last_error_;
+
+ if (frame_id >= frame_count_)
+ return PP_ERROR_FAILED;
+
+ encoder_->Encode(
+ CreateVideoFrame(frame_id, context->MakeReplyMessageContext()),
+ force_keyframe);
+
+ return PP_OK_COMPLETIONPENDING;
+}
+
+int32_t PepperVideoEncoderHost::OnHostMsgRecycleBitstreamBuffer(
+ ppapi::host::HostMessageContext* context,
+ uint32_t buffer_id) {
+ if (encoder_last_error_)
+ return encoder_last_error_;
+
+ if (buffer_id >= shm_buffers_.size() || shm_buffers_[buffer_id]->in_use)
+ return PP_ERROR_FAILED;
+
+ shm_buffers_[buffer_id]->in_use = true;
+ encoder_->UseOutputBitstreamBuffer(
+ shm_buffers_[buffer_id]->ToBitstreamBuffer());
+
+ return PP_OK;
+}
+
+int32_t PepperVideoEncoderHost::OnHostMsgRequestEncodingParametersChange(
+ ppapi::host::HostMessageContext* context,
+ uint32_t bitrate,
+ uint32_t framerate) {
+ if (encoder_last_error_)
+ return encoder_last_error_;
+
+ encoder_->RequestEncodingParametersChange(bitrate, framerate);
+
+ return PP_OK;
+}
+
+int32_t PepperVideoEncoderHost::OnHostMsgClose(
+ ppapi::host::HostMessageContext* context) {
+ encoder_last_error_ = PP_ERROR_FAILED;
+ Close();
+
+ return PP_OK;
+}
+
+void PepperVideoEncoderHost::RequireBitstreamBuffers(
+ unsigned int frame_count,
+ const gfx::Size& input_coded_size,
+ size_t output_buffer_size) {
+ DCHECK(RenderThreadImpl::current());
+ // We assume RequireBitstreamBuffers is only called once.
+ DCHECK(!initialized_);
+
+ input_coded_size_ = input_coded_size;
+ frame_count_ = frame_count;
+
+ for (uint32_t i = 0; i < kDefaultNumberOfBitstreamBuffers; ++i) {
+ scoped_ptr<base::SharedMemory> shm(
+ RenderThread::Get()
+ ->HostAllocateSharedMemoryBuffer(output_buffer_size)
+ .Pass());
+
+ if (!shm || !shm->Map(output_buffer_size)) {
+ shm_buffers_.clear();
+ break;
+ }
+
+ shm_buffers_.push_back(new ShmBuffer(i, shm.Pass()));
+ }
+
+ // Feed buffers to the encoder.
+ std::vector<SerializedHandle> handles;
+ for (size_t i = 0; i < shm_buffers_.size(); ++i) {
+ encoder_->UseOutputBitstreamBuffer(shm_buffers_[i]->ToBitstreamBuffer());
+ handles.push_back(SerializedHandle(
+ renderer_ppapi_host_->ShareHandleWithRemote(
+ PlatformFileFromSharedMemoryHandle(shm_buffers_[i]->shm->handle()),
+ false),
+ output_buffer_size));
+ }
+
+ host()->SendUnsolicitedReplyWithHandles(
+ pp_resource(), PpapiPluginMsg_VideoEncoder_BitstreamBuffers(
+ static_cast<uint32_t>(output_buffer_size)),
+ handles);
+
+ if (!initialized_) {
+ // Tell the plugin that initialization has been successful if we
+ // haven't already.
+ initialized_ = true;
+ encoder_last_error_ = PP_OK;
+ host()->SendReply(initialize_reply_context_,
+ PpapiPluginMsg_VideoEncoder_InitializeReply(
+ frame_count, PP_FromGfxSize(input_coded_size)));
+ }
+
+ if (shm_buffers_.empty()) {
+ NotifyPepperError(PP_ERROR_NOMEMORY);
+ return;
+ }
+
+ // If the plugin already requested video frames, we can now answer
+ // that request.
+ if (get_video_frames_reply_context_.is_valid())
+ AllocateVideoFrames();
+}
+
+void PepperVideoEncoderHost::BitstreamBufferReady(int32 buffer_id,
+ size_t payload_size,
+ bool key_frame) {
+ DCHECK(RenderThreadImpl::current());
+ DCHECK(shm_buffers_[buffer_id]->in_use);
+
+ shm_buffers_[buffer_id]->in_use = false;
+ host()->SendUnsolicitedReply(
+ pp_resource(),
+ PpapiPluginMsg_VideoEncoder_BitstreamBufferReady(
+ buffer_id, static_cast<uint32_t>(payload_size), key_frame));
+}
+
+void PepperVideoEncoderHost::NotifyError(
+ media::VideoEncodeAccelerator::Error error) {
+ DCHECK(RenderThreadImpl::current());
+ NotifyPepperError(PP_FromMediaEncodeAcceleratorError(error));
+}
+
+void PepperVideoEncoderHost::GetSupportedProfiles(
+ std::vector<PP_VideoProfileDescription>* pp_profiles) {
+ DCHECK(RenderThreadImpl::current());
+
+ media::VideoEncodeAccelerator::SupportedProfiles profiles;
+
+ if (EnsureGpuChannel()) {
+ profiles = GpuVideoAcceleratorUtil::ConvertGpuToMediaEncodeProfiles(
+ channel_->gpu_info().video_encode_accelerator_supported_profiles);
+ for (media::VideoEncodeAccelerator::SupportedProfile profile : profiles) {
+ pp_profiles->push_back(
+ PP_FromVideoEncodeAcceleratorSupportedProfile(profile, PP_TRUE));
+ }
+ }
+
+#if !defined(OS_ANDROID)
+ VideoEncoderShim software_encoder(this);
+ profiles = software_encoder.GetSupportedProfiles();
+ for (media::VideoEncodeAccelerator::SupportedProfile profile : profiles) {
+ pp_profiles->push_back(
+ PP_FromVideoEncodeAcceleratorSupportedProfile(profile, PP_FALSE));
+ }
+#endif
+}
+
+bool PepperVideoEncoderHost::IsInitializationValid(
+ const PP_Size& input_size,
+ PP_VideoProfile output_profile,
+ PP_HardwareAcceleration acceleration) {
+ DCHECK(RenderThreadImpl::current());
+
+ std::vector<PP_VideoProfileDescription> profiles;
+ GetSupportedProfiles(&profiles);
+
+ for (const PP_VideoProfileDescription& profile : profiles) {
+ if (output_profile == profile.profile &&
+ input_size.width <= profile.max_resolution.width &&
+ input_size.height <= profile.max_resolution.height &&
+ PP_HardwareAccelerationCompatible(
+ profile.hardware_accelerated == PP_TRUE, acceleration))
+ return true;
+ }
+
+ return false;
+}
+
+bool PepperVideoEncoderHost::EnsureGpuChannel() {
+ DCHECK(RenderThreadImpl::current());
+
+ if (command_buffer_)
+ return true;
+
+ // There is no guarantee that we have a 3D context to work with. So
+ // we create a dummy command buffer to communicate with the gpu process.
+ channel_ = RenderThreadImpl::current()->EstablishGpuChannelSync(
+ CAUSE_FOR_GPU_LAUNCH_PEPPERVIDEOENCODERACCELERATOR_INITIALIZE);
+ if (!channel_)
+ return false;
+
+ std::vector<int32> attribs(1, PP_GRAPHICS3DATTRIB_NONE);
+ command_buffer_ = channel_->CreateOffscreenCommandBuffer(
+ gfx::Size(), nullptr, attribs, GURL::EmptyGURL(),
+ gfx::PreferIntegratedGpu);
+ if (!command_buffer_) {
+ Close();
+ return false;
+ }
+
+ command_buffer_->SetContextLostCallback(media::BindToCurrentLoop(
+ base::Bind(&PepperVideoEncoderHost::NotifyPepperError,
+ weak_ptr_factory_.GetWeakPtr(), PP_ERROR_RESOURCE_FAILED)));
+ if (!command_buffer_->Initialize()) {
+ Close();
+ return false;
+ }
+
+ return true;
+}
+
+bool PepperVideoEncoderHost::InitializeHardware(
+ media::VideoFrame::Format input_format,
+ const gfx::Size& input_visible_size,
+ media::VideoCodecProfile output_profile,
+ uint32_t initial_bitrate) {
+ DCHECK(RenderThreadImpl::current());
+
+ if (!EnsureGpuChannel())
+ return false;
+
+ encoder_ = command_buffer_->CreateVideoEncoder();
+ if (!encoder_ ||
+ !encoder_->Initialize(input_format, input_visible_size, output_profile,
+ initial_bitrate, this))
+ return false;
+
+ return true;
+}
+
+void PepperVideoEncoderHost::Close() {
+ DCHECK(RenderThreadImpl::current());
+
+ encoder_ = nullptr;
+ if (command_buffer_) {
+ DCHECK(channel_);
+ channel_->DestroyCommandBuffer(command_buffer_);
+ command_buffer_ = nullptr;
+ }
+}
+
+void PepperVideoEncoderHost::AllocateVideoFrames() {
+ DCHECK(RenderThreadImpl::current());
+ DCHECK(get_video_frames_reply_context_.is_valid());
+
+ // Frames have already been allocated.
+ if (buffer_manager_.number_of_buffers() > 0) {
+ SendGetFramesErrorReply(PP_ERROR_FAILED);
+ NOTREACHED();
+ return;
+ }
+
+ base::CheckedNumeric<uint32_t> size =
+ media::VideoFrame::AllocationSize(media_input_format_, input_coded_size_);
+ uint32_t frame_size = size.ValueOrDie();
+ size += sizeof(ppapi::MediaStreamBuffer::Video);
+ uint32_t buffer_size = size.ValueOrDie();
+ // Make each buffer 4 byte aligned.
+ size += (4 - buffer_size % 4);
+ uint32_t buffer_size_aligned = size.ValueOrDie();
+ size *= frame_count_;
+ uint32_t total_size = size.ValueOrDie();
+
+ scoped_ptr<base::SharedMemory> shm(
+ RenderThreadImpl::current()
+ ->HostAllocateSharedMemoryBuffer(total_size)
+ .Pass());
+ if (!shm ||
+ !buffer_manager_.SetBuffers(frame_count_,
+ buffer_size_aligned,
+ shm.Pass(),
+ true)) {
+ SendGetFramesErrorReply(PP_ERROR_NOMEMORY);
+ return;
+ }
+
+ VLOG(4) << " frame_count=" << frame_count_ << " frame_size=" << frame_size
+ << " buffer_size=" << buffer_size_aligned;
+
+ for (int32_t i = 0; i < buffer_manager_.number_of_buffers(); ++i) {
+ ppapi::MediaStreamBuffer::Video* buffer =
+ &(buffer_manager_.GetBufferPointer(i)->video);
+ buffer->header.size = buffer_manager_.buffer_size();
+ buffer->header.type = ppapi::MediaStreamBuffer::TYPE_VIDEO;
+ buffer->format = PP_FromMediaVideoFormat(media_input_format_);
+ buffer->size.width = input_coded_size_.width();
+ buffer->size.height = input_coded_size_.height();
+ buffer->data_size = frame_size;
+ }
+
+ DCHECK(get_video_frames_reply_context_.is_valid());
+ get_video_frames_reply_context_.params.AppendHandle(SerializedHandle(
+ renderer_ppapi_host_->ShareHandleWithRemote(
+ PlatformFileFromSharedMemoryHandle(buffer_manager_.shm()->handle()),
+ false),
+ total_size));
+
+ host()->SendReply(get_video_frames_reply_context_,
+ PpapiPluginMsg_VideoEncoder_GetVideoFramesReply(
+ frame_count_, buffer_size_aligned,
+ PP_FromGfxSize(input_coded_size_)));
+ get_video_frames_reply_context_ = ppapi::host::ReplyMessageContext();
+}
+
+void PepperVideoEncoderHost::SendGetFramesErrorReply(int32_t error) {
+ get_video_frames_reply_context_.params.set_result(error);
+ host()->SendReply(
+ get_video_frames_reply_context_,
+ PpapiPluginMsg_VideoEncoder_GetVideoFramesReply(0, 0, PP_MakeSize(0, 0)));
+ get_video_frames_reply_context_ = ppapi::host::ReplyMessageContext();
+}
+
+scoped_refptr<media::VideoFrame> PepperVideoEncoderHost::CreateVideoFrame(
+ uint32_t frame_id,
+ const ppapi::host::ReplyMessageContext& reply_context) {
+ DCHECK(RenderThreadImpl::current());
+
+ ppapi::MediaStreamBuffer* buffer = buffer_manager_.GetBufferPointer(frame_id);
+ DCHECK(buffer);
+ uint32_t shm_offset = static_cast<uint8*>(buffer->video.data) -
+ static_cast<uint8*>(buffer_manager_.shm()->memory());
+
+ return media::VideoFrame::WrapExternalPackedMemory(
+ media_input_format_, input_coded_size_, gfx::Rect(input_coded_size_),
+ input_coded_size_, static_cast<uint8*>(buffer->video.data),
+ buffer->video.data_size, buffer_manager_.shm()->handle(), shm_offset,
+ base::TimeDelta(),
+ base::Bind(&PepperVideoEncoderHost::FrameReleased,
+ weak_ptr_factory_.GetWeakPtr(), reply_context, frame_id));
+}
+
+void PepperVideoEncoderHost::FrameReleased(
+ const ppapi::host::ReplyMessageContext& reply_context,
+ uint32_t frame_id) {
+ DCHECK(RenderThreadImpl::current());
+
+ ppapi::host::ReplyMessageContext context = reply_context;
+ context.params.set_result(encoder_last_error_);
+ host()->SendReply(context, PpapiPluginMsg_VideoEncoder_EncodeReply(frame_id));
+}
+
+void PepperVideoEncoderHost::NotifyPepperError(int32_t error) {
+ DCHECK(RenderThreadImpl::current());
+
+ encoder_last_error_ = error;
+ Close();
+ host()->SendUnsolicitedReply(
+ pp_resource(),
+ PpapiPluginMsg_VideoEncoder_NotifyError(encoder_last_error_));
+}
+
+uint8_t* PepperVideoEncoderHost::ShmHandleToAddress(int32 buffer_id) {
+ DCHECK(RenderThreadImpl::current());
+ DCHECK_GE(buffer_id, 0);
+ DCHECK_LT(buffer_id, static_cast<int32>(shm_buffers_.size()));
+ return static_cast<uint8_t*>(shm_buffers_[buffer_id]->shm->memory());
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/pepper/pepper_video_encoder_host.h b/chromium/content/renderer/pepper/pepper_video_encoder_host.h
new file mode 100644
index 00000000000..86168b9dc8b
--- /dev/null
+++ b/chromium/content/renderer/pepper/pepper_video_encoder_host.h
@@ -0,0 +1,164 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_PEPPER_PEPPER_VIDEO_ENCODER_HOST_H_
+#define CONTENT_RENDERER_PEPPER_PEPPER_VIDEO_ENCODER_HOST_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "content/common/content_export.h"
+#include "media/video/video_encode_accelerator.h"
+#include "ppapi/c/pp_codecs.h"
+#include "ppapi/c/ppb_video_frame.h"
+#include "ppapi/host/host_message_context.h"
+#include "ppapi/host/resource_host.h"
+#include "ppapi/proxy/resource_message_params.h"
+#include "ppapi/shared_impl/media_stream_buffer_manager.h"
+
+namespace media {
+class GpuVideoAcceleratorFactories;
+}
+
+namespace content {
+
+class CommandBufferProxyImpl;
+class GpuChannelHost;
+class RendererPpapiHost;
+class VideoEncoderShim;
+
+class CONTENT_EXPORT PepperVideoEncoderHost
+ : public ppapi::host::ResourceHost,
+ public media::VideoEncodeAccelerator::Client,
+ public ppapi::MediaStreamBufferManager::Delegate {
+ public:
+ PepperVideoEncoderHost(RendererPpapiHost* host,
+ PP_Instance instance,
+ PP_Resource resource);
+ ~PepperVideoEncoderHost() override;
+
+ private:
+ friend class VideoEncoderShim;
+
+ // Shared memory buffers.
+ struct ShmBuffer {
+ ShmBuffer(uint32_t id, scoped_ptr<base::SharedMemory> shm);
+ ~ShmBuffer();
+
+ media::BitstreamBuffer ToBitstreamBuffer();
+
+ // Index of the buffer in the ScopedVector. Buffers have the same id in
+ // the plugin and the host.
+ uint32_t id;
+ scoped_ptr<base::SharedMemory> shm;
+ bool in_use;
+ };
+
+ // media::VideoEncodeAccelerator implementation.
+ void RequireBitstreamBuffers(unsigned int input_count,
+ const gfx::Size& input_coded_size,
+ size_t output_buffer_size) override;
+ void BitstreamBufferReady(int32 bitstream_buffer_id,
+ size_t payload_size,
+ bool key_frame) override;
+ void NotifyError(media::VideoEncodeAccelerator::Error error) override;
+
+ // ResourceHost implementation.
+ int32_t OnResourceMessageReceived(
+ const IPC::Message& msg,
+ ppapi::host::HostMessageContext* context) override;
+
+ int32_t OnHostMsgGetSupportedProfiles(
+ ppapi::host::HostMessageContext* context);
+ int32_t OnHostMsgInitialize(ppapi::host::HostMessageContext* context,
+ PP_VideoFrame_Format input_format,
+ const PP_Size& input_visible_size,
+ PP_VideoProfile output_profile,
+ uint32_t initial_bitrate,
+ PP_HardwareAcceleration acceleration);
+ int32_t OnHostMsgGetVideoFrames(ppapi::host::HostMessageContext* context);
+ int32_t OnHostMsgEncode(ppapi::host::HostMessageContext* context,
+ uint32_t frame_id,
+ bool force_keyframe);
+ int32_t OnHostMsgRecycleBitstreamBuffer(
+ ppapi::host::HostMessageContext* context,
+ uint32_t buffer_id);
+ int32_t OnHostMsgRequestEncodingParametersChange(
+ ppapi::host::HostMessageContext* context,
+ uint32_t bitrate,
+ uint32_t framerate);
+ int32_t OnHostMsgClose(ppapi::host::HostMessageContext* context);
+
+ // Internal methods.
+ void GetSupportedProfiles(
+ std::vector<PP_VideoProfileDescription>* pp_profiles);
+ bool IsInitializationValid(const PP_Size& input_size,
+ PP_VideoProfile ouput_profile,
+ PP_HardwareAcceleration acceleration);
+ bool EnsureGpuChannel();
+ bool InitializeHardware(media::VideoFrame::Format input_format,
+ const gfx::Size& input_visible_size,
+ media::VideoCodecProfile output_profile,
+ uint32_t initial_bitrate);
+ void Close();
+ void AllocateVideoFrames();
+ void SendGetFramesErrorReply(int32_t error);
+ scoped_refptr<media::VideoFrame> CreateVideoFrame(
+ uint32_t frame_id,
+ const ppapi::host::ReplyMessageContext& reply_context);
+ void FrameReleased(const ppapi::host::ReplyMessageContext& reply_context,
+ uint32_t frame_id);
+ void NotifyPepperError(int32_t error);
+
+ // Helper method for VideoEncoderShim.
+ uint8_t* ShmHandleToAddress(int32 buffer_id);
+
+ // Non-owning pointer.
+ RendererPpapiHost* renderer_ppapi_host_;
+
+ ScopedVector<ShmBuffer> shm_buffers_;
+
+ // Buffer manager for shared memory that holds video frames.
+ ppapi::MediaStreamBufferManager buffer_manager_;
+
+ scoped_refptr<GpuChannelHost> channel_;
+ CommandBufferProxyImpl* command_buffer_;
+
+ scoped_ptr<media::VideoEncodeAccelerator> encoder_;
+
+ // Whether the encoder has been successfully initialized.
+ bool initialized_;
+
+ // Saved context to answer an Initialize message from the plugin.
+ ppapi::host::ReplyMessageContext initialize_reply_context_;
+
+ // Saved context to answer a GetVideoFrames message from the plugin.
+ ppapi::host::ReplyMessageContext get_video_frames_reply_context_;
+
+ // This represents the current error state of the encoder, i.e. PP_OK
+ // normally, or a Pepper error code if the encoder is uninitialized,
+ // has been notified of an encoder error, has encountered some
+ // other unrecoverable error, or has been closed by the plugin.
+ // This field is checked in most message handlers to decide whether
+ // operations should proceed or fail.
+ int32_t encoder_last_error_;
+
+ // Size of the frames allocated for the encoder (matching hardware
+ // constraints).
+ gfx::Size input_coded_size_;
+
+ // Number of frames the encoder needs.
+ uint32_t frame_count_;
+
+ // Format of the frames to give to the encoder.
+ media::VideoFrame::Format media_input_format_;
+
+ base::WeakPtrFactory<PepperVideoEncoderHost> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(PepperVideoEncoderHost);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_PEPPER_PEPPER_VIDEO_ENCODER_HOST_H_
diff --git a/chromium/content/renderer/pepper/pepper_video_source_host.cc b/chromium/content/renderer/pepper/pepper_video_source_host.cc
index b75eabb0535..fdaf42b614c 100644
--- a/chromium/content/renderer/pepper/pepper_video_source_host.cc
+++ b/chromium/content/renderer/pepper/pepper_video_source_host.cc
@@ -19,6 +19,7 @@
#include "ppapi/thunk/enter.h"
#include "ppapi/thunk/ppb_image_data_api.h"
#include "third_party/libyuv/include/libyuv/convert.h"
+#include "third_party/libyuv/include/libyuv/scale.h"
#include "third_party/skia/include/core/SkBitmap.h"
using ppapi::host::HostMessageContext;
@@ -48,7 +49,6 @@ PepperVideoSourceHost::PepperVideoSourceHost(RendererPpapiHost* host,
PP_Instance instance,
PP_Resource resource)
: ResourceHost(host->GetPpapiHost(), instance, resource),
- renderer_ppapi_host_(host),
source_handler_(new VideoSourceHandler(NULL)),
get_frame_pending_(false),
weak_factory_(this) {
@@ -115,19 +115,15 @@ void PepperVideoSourceHost::SendGetFrameReply() {
get_frame_pending_ = false;
DCHECK(last_frame_.get());
- scoped_refptr<media::VideoFrame> frame(last_frame_);
- last_frame_ = NULL;
-
- const int dst_width = frame->visible_rect().width();
- const int dst_height = frame->visible_rect().height();
+ const gfx::Size dst_size = last_frame_->natural_size();
// Note: We try to reuse the shared memory for the previous frame here. This
// means that the previous frame may be overwritten and is no longer valid
// after calling this function again.
IPC::PlatformFileForTransit image_handle;
uint32_t byte_count;
- if (shared_image_.get() && dst_width == shared_image_->width() &&
- dst_height == shared_image_->height()) {
+ if (shared_image_.get() && dst_size.width() == shared_image_->width() &&
+ dst_size.height() == shared_image_->height()) {
// We have already allocated the correct size in shared memory. We need to
// duplicate the handle for IPC however, which will close down the
// duplicated handle when it's done.
@@ -162,7 +158,7 @@ void PepperVideoSourceHost::SendGetFrameReply() {
pp_instance(),
ppapi::PPB_ImageData_Shared::SIMPLE,
PP_IMAGEDATAFORMAT_BGRA_PREMUL,
- PP_MakeSize(dst_width, dst_height),
+ PP_MakeSize(dst_size.width(), dst_size.height()),
false /* init_to_zero */,
&shared_image_desc_,
&image_handle,
@@ -206,34 +202,61 @@ void PepperVideoSourceHost::SendGetFrameReply() {
return;
}
- // Calculate that portion of the |frame| that should be copied into
- // |bitmap|. If |frame| has been cropped,
- // frame->coded_size() != frame->visible_rect().
- const int src_width = frame->coded_size().width();
- const int src_height = frame->coded_size().height();
- DCHECK(src_width >= dst_width && src_height >= dst_height);
-
- const int horiz_crop = frame->visible_rect().x();
- const int vert_crop = frame->visible_rect().y();
-
- const uint8* src_y = frame->data(media::VideoFrame::kYPlane) +
- (src_width * vert_crop + horiz_crop);
- const int center = (src_width + 1) / 2;
- const uint8* src_u = frame->data(media::VideoFrame::kUPlane) +
- (center * vert_crop + horiz_crop) / 2;
- const uint8* src_v = frame->data(media::VideoFrame::kVPlane) +
- (center * vert_crop + horiz_crop) / 2;
-
- libyuv::I420ToARGB(src_y,
+ // Calculate the portion of the |last_frame_| that should be copied into
+ // |bitmap|. If |last_frame_| is lazily scaled, then
+ // last_frame_->visible_rect()._size() != last_frame_.natural_size().
+ scoped_refptr<media::VideoFrame> frame;
+ if (dst_size == last_frame_->visible_rect().size()) {
+ // No scaling is needed, convert directly from last_frame_.
+ frame = last_frame_;
+ // Frame resolution doesn't change frequently, so don't keep any unnecessary
+ // buffers around.
+ scaled_frame_ = NULL;
+ } else {
+ // We need to create an intermediate scaled frame. Make sure we have
+ // allocated one of correct size.
+ if (!scaled_frame_.get() || scaled_frame_->coded_size() != dst_size) {
+ scaled_frame_ = media::VideoFrame::CreateFrame(
+ media::VideoFrame::I420, dst_size, gfx::Rect(dst_size), dst_size,
+ last_frame_->timestamp());
+ if (!scaled_frame_.get()) {
+ LOG(ERROR) << "Failed to allocate a media::VideoFrame";
+ SendGetFrameErrorReply(PP_ERROR_FAILED);
+ return;
+ }
+ }
+ scaled_frame_->set_timestamp(last_frame_->timestamp());
+ libyuv::I420Scale(last_frame_->visible_data(media::VideoFrame::kYPlane),
+ last_frame_->stride(media::VideoFrame::kYPlane),
+ last_frame_->visible_data(media::VideoFrame::kUPlane),
+ last_frame_->stride(media::VideoFrame::kUPlane),
+ last_frame_->visible_data(media::VideoFrame::kVPlane),
+ last_frame_->stride(media::VideoFrame::kVPlane),
+ last_frame_->visible_rect().width(),
+ last_frame_->visible_rect().height(),
+ scaled_frame_->data(media::VideoFrame::kYPlane),
+ scaled_frame_->stride(media::VideoFrame::kYPlane),
+ scaled_frame_->data(media::VideoFrame::kUPlane),
+ scaled_frame_->stride(media::VideoFrame::kUPlane),
+ scaled_frame_->data(media::VideoFrame::kVPlane),
+ scaled_frame_->stride(media::VideoFrame::kVPlane),
+ dst_size.width(),
+ dst_size.height(),
+ libyuv::kFilterBilinear);
+ frame = scaled_frame_;
+ }
+ last_frame_ = NULL;
+
+ libyuv::I420ToARGB(frame->visible_data(media::VideoFrame::kYPlane),
frame->stride(media::VideoFrame::kYPlane),
- src_u,
+ frame->visible_data(media::VideoFrame::kUPlane),
frame->stride(media::VideoFrame::kUPlane),
- src_v,
+ frame->visible_data(media::VideoFrame::kVPlane),
frame->stride(media::VideoFrame::kVPlane),
bitmap_pixels,
bitmap->rowBytes(),
- dst_width,
- dst_height);
+ dst_size.width(),
+ dst_size.height());
ppapi::HostResource host_resource;
host_resource.SetHostResource(pp_instance(), shared_image_->GetReference());
diff --git a/chromium/content/renderer/pepper/pepper_video_source_host.h b/chromium/content/renderer/pepper/pepper_video_source_host.h
index 6010aad4ca2..512de301982 100644
--- a/chromium/content/renderer/pepper/pepper_video_source_host.h
+++ b/chromium/content/renderer/pepper/pepper_video_source_host.h
@@ -71,14 +71,15 @@ class CONTENT_EXPORT PepperVideoSourceHost : public ppapi::host::ResourceHost {
void Close();
- RendererPpapiHost* renderer_ppapi_host_;
-
ppapi::host::ReplyMessageContext reply_context_;
scoped_ptr<VideoSourceHandler> source_handler_;
scoped_refptr<FrameReceiver> frame_receiver_;
std::string stream_url_;
scoped_refptr<media::VideoFrame> last_frame_;
+ // An internal frame buffer to avoid reallocations. It is only allocated if
+ // scaling is needed.
+ scoped_refptr<media::VideoFrame> scaled_frame_;
bool get_frame_pending_;
// We use only one ImageData resource in order to avoid allocating
// shared memory repeatedly. We send the same one each time the plugin
diff --git a/chromium/content/renderer/pepper/pepper_webplugin_impl.cc b/chromium/content/renderer/pepper/pepper_webplugin_impl.cc
index ecdd9e5b857..25b96337996 100644
--- a/chromium/content/renderer/pepper/pepper_webplugin_impl.cc
+++ b/chromium/content/renderer/pepper/pepper_webplugin_impl.cc
@@ -12,6 +12,7 @@
#include "content/public/renderer/content_renderer_client.h"
#include "content/renderer/pepper/message_channel.h"
#include "content/renderer/pepper/pepper_plugin_instance_impl.h"
+#include "content/renderer/pepper/plugin_instance_throttler_impl.h"
#include "content/renderer/pepper/plugin_module.h"
#include "content/renderer/pepper/v8object_var.h"
#include "content/renderer/render_frame_impl.h"
@@ -28,6 +29,7 @@
#include "third_party/WebKit/public/web/WebPluginContainer.h"
#include "third_party/WebKit/public/web/WebPluginParams.h"
#include "third_party/WebKit/public/web/WebPrintParams.h"
+#include "third_party/WebKit/public/web/WebPrintPresetOptions.h"
#include "third_party/WebKit/public/web/WebPrintScalingOption.h"
#include "url/gurl.h"
@@ -54,11 +56,14 @@ struct PepperWebPluginImpl::InitData {
GURL url;
};
-PepperWebPluginImpl::PepperWebPluginImpl(PluginModule* plugin_module,
- const WebPluginParams& params,
- RenderFrameImpl* render_frame)
+PepperWebPluginImpl::PepperWebPluginImpl(
+ PluginModule* plugin_module,
+ const WebPluginParams& params,
+ RenderFrameImpl* render_frame,
+ scoped_ptr<PluginInstanceThrottlerImpl> throttler)
: init_data_(new InitData()),
full_frame_(params.loadManually),
+ throttler_(throttler.Pass()),
instance_object_(PP_MakeUndefined()),
container_(NULL) {
DCHECK(plugin_module);
@@ -72,6 +77,9 @@ PepperWebPluginImpl::PepperWebPluginImpl(PluginModule* plugin_module,
// Set subresource URL for crash reporting.
base::debug::SetCrashKeyValue("subresource_url", init_data_->url.spec());
+
+ if (throttler_)
+ throttler_->SetWebPlugin(this);
}
PepperWebPluginImpl::~PepperWebPluginImpl() {}
@@ -90,8 +98,9 @@ bool PepperWebPluginImpl::initialize(WebPluginContainer* container) {
// Enable script objects for this plugin.
container->allowScriptObjects();
- bool success = instance_->Initialize(
- init_data_->arg_names, init_data_->arg_values, full_frame_);
+ bool success =
+ instance_->Initialize(init_data_->arg_names, init_data_->arg_values,
+ full_frame_, throttler_.Pass());
if (!success) {
instance_->Delete();
instance_ = NULL;
@@ -147,7 +156,7 @@ v8::Local<v8::Object> PepperWebPluginImpl::v8ScriptableObject(
message_channel->SetPassthroughObject(object_var->GetHandle());
}
- v8::Handle<v8::Object> result = instance_->GetMessageChannelObject();
+ v8::Local<v8::Object> result = instance_->GetMessageChannelObject();
return result;
}
@@ -161,18 +170,20 @@ void PepperWebPluginImpl::paint(WebCanvas* canvas, const WebRect& rect) {
void PepperWebPluginImpl::updateGeometry(
const WebRect& window_rect,
const WebRect& clip_rect,
+ const WebRect& unobscured_rect,
const WebVector<WebRect>& cut_outs_rects,
bool is_visible) {
plugin_rect_ = window_rect;
- if (!instance_->FlashIsFullscreenOrPending()) {
+ if (instance_ && !instance_->FlashIsFullscreenOrPending()) {
std::vector<gfx::Rect> cut_outs;
for (size_t i = 0; i < cut_outs_rects.size(); ++i)
cut_outs.push_back(cut_outs_rects[i]);
- instance_->ViewChanged(plugin_rect_, clip_rect, cut_outs);
+ instance_->ViewChanged(plugin_rect_, clip_rect, unobscured_rect, cut_outs);
}
}
-void PepperWebPluginImpl::updateFocus(bool focused) {
+void PepperWebPluginImpl::updateFocus(bool focused,
+ blink::WebFocusType focus_type) {
instance_->SetWebKitFocus(focused);
}
@@ -270,6 +281,11 @@ bool PepperWebPluginImpl::printPage(int page_number, blink::WebCanvas* canvas) {
void PepperWebPluginImpl::printEnd() { return instance_->PrintEnd(); }
+bool PepperWebPluginImpl::getPrintPresetOptionsFromDocument(
+ blink::WebPrintPresetOptions* preset_options) {
+ return instance_->GetPrintPresetOptionsFromDocument(preset_options);
+}
+
bool PepperWebPluginImpl::canRotateView() { return instance_->CanRotateView(); }
void PepperWebPluginImpl::rotateView(RotationType type) {
diff --git a/chromium/content/renderer/pepper/pepper_webplugin_impl.h b/chromium/content/renderer/pepper/pepper_webplugin_impl.h
index c11bcebce3b..9b90e8be24a 100644
--- a/chromium/content/renderer/pepper/pepper_webplugin_impl.h
+++ b/chromium/content/renderer/pepper/pepper_webplugin_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_RENDERER_PEPPER_PPEPPER_WEBPLUGIN_IMPL_H_
-#define CONTENT_RENDERER_PEPPER_PPEPPER_WEBPLUGIN_IMPL_H_
+#ifndef CONTENT_RENDERER_PEPPER_PEPPER_WEBPLUGIN_IMPL_H_
+#define CONTENT_RENDERER_PEPPER_PEPPER_WEBPLUGIN_IMPL_H_
#include <string>
#include <vector>
@@ -13,7 +13,7 @@
#include "base/sequenced_task_runner_helpers.h"
#include "ppapi/c/pp_var.h"
#include "third_party/WebKit/public/web/WebPlugin.h"
-#include "ui/gfx/rect.h"
+#include "ui/gfx/geometry/rect.h"
struct _NPP;
@@ -25,6 +25,7 @@ struct WebPrintParams;
namespace content {
class PepperPluginInstanceImpl;
+class PluginInstanceThrottlerImpl;
class PluginModule;
class PPB_URLLoader_Impl;
class RenderFrameImpl;
@@ -33,7 +34,8 @@ class PepperWebPluginImpl : public blink::WebPlugin {
public:
PepperWebPluginImpl(PluginModule* module,
const blink::WebPluginParams& params,
- RenderFrameImpl* render_frame);
+ RenderFrameImpl* render_frame,
+ scoped_ptr<PluginInstanceThrottlerImpl> throttler);
PepperPluginInstanceImpl* instance() { return instance_.get(); }
@@ -44,13 +46,15 @@ class PepperWebPluginImpl : public blink::WebPlugin {
virtual v8::Local<v8::Object> v8ScriptableObject(
v8::Isolate* isolate) override;
virtual bool getFormValue(blink::WebString& value);
+ virtual void layoutIfNeeded() override { }
virtual void paint(blink::WebCanvas* canvas, const blink::WebRect& rect);
virtual void updateGeometry(
- const blink::WebRect& frame_rect,
+ const blink::WebRect& window_rect,
const blink::WebRect& clip_rect,
+ const blink::WebRect& unobscured_rect,
const blink::WebVector<blink::WebRect>& cut_outs_rects,
bool is_visible);
- virtual void updateFocus(bool focused);
+ virtual void updateFocus(bool focused, blink::WebFocusType focus_type);
virtual void updateVisibility(bool visible);
virtual bool acceptsInputEvents();
virtual bool handleInputEvent(const blink::WebInputEvent& event,
@@ -68,6 +72,8 @@ class PepperWebPluginImpl : public blink::WebPlugin {
virtual blink::WebString selectionAsText() const;
virtual blink::WebString selectionAsMarkup() const;
virtual blink::WebURL linkAtPosition(const blink::WebPoint& position) const;
+ virtual bool getPrintPresetOptionsFromDocument(
+ blink::WebPrintPresetOptions* preset_options);
virtual void setZoomLevel(double level, bool text_only);
virtual bool startFind(const blink::WebString& search_text,
bool case_sensitive,
@@ -95,6 +101,7 @@ class PepperWebPluginImpl : public blink::WebPlugin {
// True if the instance represents the entire document in a frame instead of
// being an embedded resource.
bool full_frame_;
+ scoped_ptr<PluginInstanceThrottlerImpl> throttler_;
scoped_refptr<PepperPluginInstanceImpl> instance_;
gfx::Rect plugin_rect_;
PP_Var instance_object_;
@@ -105,4 +112,4 @@ class PepperWebPluginImpl : public blink::WebPlugin {
} // namespace content
-#endif // CONTENT_RENDERER_PEPPER_PPEPPER_WEBPLUGIN_IMPL_H_
+#endif // CONTENT_RENDERER_PEPPER_PEPPER_WEBPLUGIN_IMPL_H_
diff --git a/chromium/content/renderer/pepper/pepper_webplugin_impl_browsertest.cc b/chromium/content/renderer/pepper/pepper_webplugin_impl_browsertest.cc
new file mode 100644
index 00000000000..6dd2e0adb60
--- /dev/null
+++ b/chromium/content/renderer/pepper/pepper_webplugin_impl_browsertest.cc
@@ -0,0 +1,207 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/command_line.h"
+#include "content/public/common/content_client.h"
+#include "content/public/common/content_constants.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/common/pepper_plugin_info.h"
+#include "content/public/renderer/content_renderer_client.h"
+#include "content/public/test/render_view_test.h"
+#include "content/renderer/pepper/pepper_webplugin_impl.h"
+#include "content/renderer/pepper/plugin_instance_throttler_impl.h"
+#include "content/renderer/pepper/plugin_module.h"
+#include "content/renderer/pepper/renderer_ppapi_host_impl.h"
+#include "content/renderer/render_frame_impl.h"
+#include "content/test/test_content_client.h"
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/c/ppb_core.h"
+#include "ppapi/c/ppb_graphics_2d.h"
+#include "ppapi/c/ppb_image_data.h"
+#include "ppapi/c/ppb_instance.h"
+#include "ppapi/c/ppp_instance.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/web/WebLocalFrame.h"
+
+namespace content {
+namespace {
+
+class PepperWebPluginImplBrowserTest
+ : public RenderViewTest,
+ public PluginInstanceThrottler::Observer {
+ public:
+ PepperWebPluginImplBrowserTest()
+ : throttler_(nullptr),
+ throttle_engaged_(false),
+ pp_module_(0),
+ pp_instance_(0),
+ graphics2d_(0) {}
+
+ void SetUp() override {
+ base::CommandLine& command_line = *base::CommandLine::ForCurrentProcess();
+ command_line.AppendSwitchASCII(
+ switches::kOverridePluginPowerSaverForTesting, "always");
+
+ current_test_ = this;
+ RenderViewTest::SetUp();
+ }
+ void TearDown() override {
+ RenderViewTest::TearDown();
+ current_test_ = nullptr;
+ }
+ ContentClient* CreateContentClient() override {
+ return new MockContentClient;
+ }
+ ContentRendererClient* CreateContentRendererClient() override {
+ return new MockContentRendererClient;
+ }
+
+ // PluginInstanceThrottler::Observer implementation
+ void OnThrottleStateChange() override {
+ if (throttler_->IsThrottled())
+ throttle_engaged_ = true;
+ }
+
+ protected:
+ // PPP implementation
+ static const void* GetInterface(const char* name) {
+ static PPP_Instance ppp_instance = {
+ &PepperWebPluginImplBrowserTest::DidCreate,
+ &PepperWebPluginImplBrowserTest::DidDestroy,
+ &PepperWebPluginImplBrowserTest::DidChangeView,
+ &PepperWebPluginImplBrowserTest::DidChangeFocus,
+ &PepperWebPluginImplBrowserTest::HandleDocumentLoad};
+ if (!strcmp(name, PPP_INSTANCE_INTERFACE))
+ return &ppp_instance;
+ return nullptr;
+ }
+ static int InitializeModule(PP_Module module,
+ PPB_GetInterface get_interface) {
+ EXPECT_EQ(0, current_test_->pp_module_);
+ current_test_->pp_module_ = module;
+ ppb_core_ = static_cast<const PPB_Core*>(get_interface(PPB_CORE_INTERFACE));
+ ppb_graphics2d_ = static_cast<const PPB_Graphics2D*>(
+ get_interface(PPB_GRAPHICS_2D_INTERFACE));
+ ppb_image_data_ = static_cast<const PPB_ImageData*>(
+ get_interface(PPB_IMAGEDATA_INTERFACE));
+ ppb_instance_ =
+ static_cast<const PPB_Instance*>(get_interface(PPB_INSTANCE_INTERFACE));
+ return PP_OK;
+ }
+ static void ShutdownModule() {
+ EXPECT_NE(0, current_test_->pp_module_);
+ current_test_->pp_module_ = 0;
+ }
+
+ static void DummyCallback(void*, int32_t) {}
+
+ void PaintSomething() {
+ PP_Size size = {2, 1};
+ PP_Resource image = ppb_image_data_->Create(
+ pp_instance_, ppb_image_data_->GetNativeImageDataFormat(), &size,
+ PP_TRUE);
+ int32_t* pixels = static_cast<int32_t*>(ppb_image_data_->Map(image));
+ pixels[0] = 0xff000000;
+ pixels[1] = 0xffffffff;
+ ppb_image_data_->Unmap(image);
+ ppb_graphics2d_->ReplaceContents(graphics2d_, image);
+ PP_CompletionCallback callback = {
+ &PepperWebPluginImplBrowserTest::DummyCallback, nullptr, 0};
+ ppb_graphics2d_->Flush(graphics2d_, callback);
+ ppb_core_->ReleaseResource(image);
+ }
+
+ // PPP_Instance implementation
+ static PP_Bool DidCreate(PP_Instance instance,
+ uint32_t,
+ const char* [],
+ const char* []) {
+ EXPECT_EQ(0, current_test_->pp_instance_);
+ current_test_->pp_instance_ = instance;
+ PP_Size size = {2, 1};
+ current_test_->graphics2d_ =
+ ppb_graphics2d_->Create(instance, &size, PP_TRUE);
+ ppb_instance_->BindGraphics(instance, current_test_->graphics2d_);
+ return PP_TRUE;
+ }
+ static void DidDestroy(PP_Instance instance) {
+ EXPECT_NE(0, current_test_->pp_instance_);
+ current_test_->PaintSomething();
+ ppb_core_->ReleaseResource(current_test_->graphics2d_);
+ current_test_->pp_instance_ = 0;
+ }
+ static void DidChangeView(PP_Instance, PP_Resource) {}
+ static void DidChangeFocus(PP_Instance, PP_Bool) {}
+ static PP_Bool HandleDocumentLoad(PP_Instance, PP_Resource) {
+ return PP_FALSE;
+ }
+
+ static PepperPluginInfo GetPluginInfo() {
+ PepperPluginInfo info;
+ info.is_internal = true;
+ info.path = base::FilePath(FILE_PATH_LITERAL("internal-always-throttle"));
+ info.name = "Always Throttle";
+ info.mime_types.push_back(
+ WebPluginMimeType("test/always-throttle", "", ""));
+ info.internal_entry_points.get_interface =
+ &PepperWebPluginImplBrowserTest::GetInterface;
+ info.internal_entry_points.initialize_module =
+ &PepperWebPluginImplBrowserTest::InitializeModule;
+ info.internal_entry_points.shutdown_module =
+ &PepperWebPluginImplBrowserTest::ShutdownModule;
+ return info;
+ }
+
+ class MockContentClient : public TestContentClient {
+ public:
+ void AddPepperPlugins(std::vector<PepperPluginInfo>* plugins) override {
+ plugins->push_back(GetPluginInfo());
+ }
+ };
+ class MockContentRendererClient : public ContentRendererClient {
+ public:
+ bool OverrideCreatePlugin(RenderFrame* render_frame,
+ blink::WebLocalFrame* frame,
+ const blink::WebPluginParams& params,
+ blink::WebPlugin** plugin) override {
+ current_test_->throttler_ = new PluginInstanceThrottlerImpl;
+ current_test_->throttler_->AddObserver(current_test_);
+ *plugin = render_frame->CreatePlugin(frame,
+ GetPluginInfo().ToWebPluginInfo(), params,
+ make_scoped_ptr(current_test_->throttler_));
+ return *plugin;
+ }
+ };
+
+ PluginInstanceThrottlerImpl* throttler_;
+ bool throttle_engaged_;
+ PP_Module pp_module_;
+ PP_Instance pp_instance_;
+ PP_Resource graphics2d_;
+ static PepperWebPluginImplBrowserTest* current_test_;
+ static const PPB_Core* ppb_core_;
+ static const PPB_Graphics2D* ppb_graphics2d_;
+ static const PPB_ImageData* ppb_image_data_;
+ static const PPB_Instance* ppb_instance_;
+};
+PepperWebPluginImplBrowserTest* PepperWebPluginImplBrowserTest::current_test_;
+const PPB_Core* PepperWebPluginImplBrowserTest::ppb_core_;
+const PPB_Graphics2D* PepperWebPluginImplBrowserTest::ppb_graphics2d_;
+const PPB_ImageData* PepperWebPluginImplBrowserTest::ppb_image_data_;
+const PPB_Instance* PepperWebPluginImplBrowserTest::ppb_instance_;
+
+// This test simulates the behavior of a plugin that emits new frames during
+// destruction. The throttler shouldn't engage and create a placeholder for
+// a to-be destroyed plugin in such case. See crbug.com/483068
+TEST_F(PepperWebPluginImplBrowserTest, NotEngageThrottleDuringDestroy) {
+ LoadHTML("<!DOCTYPE html><object type='test/always-throttle'></object>");
+ EXPECT_NE(0, pp_instance_);
+ LoadHTML("");
+ EXPECT_EQ(0, pp_instance_);
+ EXPECT_FALSE(throttle_engaged_);
+}
+
+} // unnamed namespace
+
+} // namespace content
diff --git a/chromium/content/renderer/pepper/pepper_websocket_host.cc b/chromium/content/renderer/pepper/pepper_websocket_host.cc
index 6b55bb6975b..b5f1e959791 100644
--- a/chromium/content/renderer/pepper/pepper_websocket_host.cc
+++ b/chromium/content/renderer/pepper/pepper_websocket_host.cc
@@ -14,9 +14,9 @@
#include "ppapi/host/host_message_context.h"
#include "ppapi/host/ppapi_host.h"
#include "ppapi/proxy/ppapi_messages.h"
-#include "third_party/WebKit/public/platform/WebArrayBuffer.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/platform/WebURL.h"
+#include "third_party/WebKit/public/web/WebArrayBuffer.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebElement.h"
#include "third_party/WebKit/public/web/WebPluginContainer.h"
@@ -213,7 +213,7 @@ int32_t PepperWebSocketHost::OnHostMsgConnect(
return PP_ERROR_BADARGUMENT;
if (gurl.has_ref())
return PP_ERROR_BADARGUMENT;
- if (!net::IsPortAllowedByDefault(gurl.IntPort()))
+ if (!net::IsPortAllowedByDefault(gurl.EffectiveIntPort()))
return PP_ERROR_BADARGUMENT;
WebURL web_url(gurl);
diff --git a/chromium/content/renderer/pepper/plugin_instance_throttler_impl.cc b/chromium/content/renderer/pepper/plugin_instance_throttler_impl.cc
new file mode 100644
index 00000000000..a73a22436e3
--- /dev/null
+++ b/chromium/content/renderer/pepper/plugin_instance_throttler_impl.cc
@@ -0,0 +1,220 @@
+// Copyright 2014 The Chromium Authors. 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/renderer/pepper/plugin_instance_throttler_impl.h"
+
+#include "base/metrics/histogram.h"
+#include "base/time/time.h"
+#include "content/public/common/content_constants.h"
+#include "content/public/renderer/render_thread.h"
+#include "content/renderer/pepper/pepper_plugin_instance_impl.h"
+#include "content/renderer/render_frame_impl.h"
+#include "ppapi/shared_impl/ppapi_constants.h"
+#include "third_party/WebKit/public/platform/WebRect.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
+#include "third_party/WebKit/public/web/WebPluginParams.h"
+#include "ui/gfx/color_utils.h"
+#include "url/gurl.h"
+
+namespace content {
+
+namespace {
+
+// Threshold for 'boring' score to accept a frame as good enough to be a
+// representative keyframe. Units are the ratio of all pixels that are within
+// the most common luma bin. The same threshold is used for history thumbnails.
+const double kAcceptableFrameMaximumBoringness = 0.94;
+
+// When plugin audio is throttled, the plugin will sometimes stop generating
+// video frames. We use this timeout to prevent waiting forever for a good
+// poster image. Chosen arbitrarily.
+const int kAudioThrottledFrameTimeoutMilliseconds = 500;
+
+} // namespace
+
+// static
+const int PluginInstanceThrottlerImpl::kMaximumFramesToExamine = 150;
+
+// static
+scoped_ptr<PluginInstanceThrottler> PluginInstanceThrottler::Create() {
+ return make_scoped_ptr(new PluginInstanceThrottlerImpl);
+}
+
+// static
+void PluginInstanceThrottler::RecordUnthrottleMethodMetric(
+ PluginInstanceThrottlerImpl::PowerSaverUnthrottleMethod method) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "Plugin.PowerSaver.Unthrottle", method,
+ PluginInstanceThrottler::UNTHROTTLE_METHOD_NUM_ITEMS);
+}
+
+PluginInstanceThrottlerImpl::PluginInstanceThrottlerImpl()
+ : state_(THROTTLER_STATE_AWAITING_KEYFRAME),
+ is_hidden_for_placeholder_(false),
+ web_plugin_(nullptr),
+ frames_examined_(0),
+ audio_throttled_(false),
+ audio_throttled_frame_timeout_(
+ FROM_HERE,
+ base::TimeDelta::FromMilliseconds(
+ kAudioThrottledFrameTimeoutMilliseconds),
+ this,
+ &PluginInstanceThrottlerImpl::EngageThrottle),
+ weak_factory_(this) {
+}
+
+PluginInstanceThrottlerImpl::~PluginInstanceThrottlerImpl() {
+ FOR_EACH_OBSERVER(Observer, observer_list_, OnThrottlerDestroyed());
+ if (state_ != THROTTLER_STATE_MARKED_ESSENTIAL)
+ RecordUnthrottleMethodMetric(UNTHROTTLE_METHOD_NEVER);
+}
+
+void PluginInstanceThrottlerImpl::AddObserver(Observer* observer) {
+ observer_list_.AddObserver(observer);
+}
+
+void PluginInstanceThrottlerImpl::RemoveObserver(Observer* observer) {
+ observer_list_.RemoveObserver(observer);
+}
+
+bool PluginInstanceThrottlerImpl::IsThrottled() const {
+ return state_ == THROTTLER_STATE_PLUGIN_THROTTLED;
+}
+
+bool PluginInstanceThrottlerImpl::IsHiddenForPlaceholder() const {
+ return is_hidden_for_placeholder_;
+}
+
+void PluginInstanceThrottlerImpl::MarkPluginEssential(
+ PowerSaverUnthrottleMethod method) {
+ if (state_ == THROTTLER_STATE_MARKED_ESSENTIAL)
+ return;
+
+ bool was_throttled = IsThrottled();
+ state_ = THROTTLER_STATE_MARKED_ESSENTIAL;
+ RecordUnthrottleMethodMetric(method);
+
+ FOR_EACH_OBSERVER(Observer, observer_list_, OnPeripheralStateChange());
+
+ if (was_throttled)
+ FOR_EACH_OBSERVER(Observer, observer_list_, OnThrottleStateChange());
+}
+
+void PluginInstanceThrottlerImpl::SetHiddenForPlaceholder(bool hidden) {
+ is_hidden_for_placeholder_ = hidden;
+ FOR_EACH_OBSERVER(Observer, observer_list_, OnHiddenForPlaceholder(hidden));
+}
+
+PepperWebPluginImpl* PluginInstanceThrottlerImpl::GetWebPlugin() const {
+ DCHECK(web_plugin_);
+ return web_plugin_;
+}
+
+const gfx::Size& PluginInstanceThrottlerImpl::GetSize() const {
+ return unobscured_size_;
+}
+
+void PluginInstanceThrottlerImpl::NotifyAudioThrottled() {
+ audio_throttled_ = true;
+ audio_throttled_frame_timeout_.Reset();
+}
+
+void PluginInstanceThrottlerImpl::SetWebPlugin(
+ PepperWebPluginImpl* web_plugin) {
+ DCHECK(!web_plugin_);
+ web_plugin_ = web_plugin;
+}
+
+void PluginInstanceThrottlerImpl::Initialize(
+ RenderFrameImpl* frame,
+ const GURL& content_origin,
+ const std::string& plugin_module_name,
+ const gfx::Size& unobscured_size) {
+ DCHECK(unobscured_size_.IsEmpty());
+ unobscured_size_ = unobscured_size;
+
+ // |frame| may be nullptr in tests.
+ if (frame) {
+ PluginPowerSaverHelper* helper = frame->plugin_power_saver_helper();
+ bool cross_origin_main_content = false;
+ if (!helper->ShouldThrottleContent(content_origin, plugin_module_name,
+ unobscured_size.width(),
+ unobscured_size.height(),
+ &cross_origin_main_content)) {
+ DCHECK_NE(THROTTLER_STATE_MARKED_ESSENTIAL, state_);
+ state_ = THROTTLER_STATE_MARKED_ESSENTIAL;
+ FOR_EACH_OBSERVER(Observer, observer_list_, OnPeripheralStateChange());
+
+ if (cross_origin_main_content)
+ helper->WhitelistContentOrigin(content_origin);
+
+ return;
+ }
+
+ // To collect UMAs, register peripheral content even if power saver mode
+ // is disabled.
+ helper->RegisterPeripheralPlugin(
+ content_origin,
+ base::Bind(&PluginInstanceThrottlerImpl::MarkPluginEssential,
+ weak_factory_.GetWeakPtr(), UNTHROTTLE_METHOD_BY_WHITELIST));
+ }
+}
+
+void PluginInstanceThrottlerImpl::OnImageFlush(const SkBitmap* bitmap) {
+ DCHECK(needs_representative_keyframe());
+ if (!bitmap)
+ return;
+
+ ++frames_examined_;
+
+ // Does not make a copy, just takes a reference to the underlying pixel data.
+ last_received_frame_ = *bitmap;
+
+ if (audio_throttled_)
+ audio_throttled_frame_timeout_.Reset();
+
+ double boring_score = color_utils::CalculateBoringScore(*bitmap);
+ if (boring_score <= kAcceptableFrameMaximumBoringness ||
+ frames_examined_ >= kMaximumFramesToExamine) {
+ EngageThrottle();
+ }
+}
+
+bool PluginInstanceThrottlerImpl::ConsumeInputEvent(
+ const blink::WebInputEvent& event) {
+ // Always allow right-clicks through so users may verify it's a plugin.
+ // TODO(tommycli): We should instead show a custom context menu (probably
+ // using PluginPlaceholder) so users aren't confused and try to click the
+ // Flash-internal 'Play' menu item. This is a stopgap solution.
+ if (event.modifiers & blink::WebInputEvent::Modifiers::RightButtonDown)
+ return false;
+
+ if (state_ != THROTTLER_STATE_MARKED_ESSENTIAL &&
+ event.type == blink::WebInputEvent::MouseUp &&
+ (event.modifiers & blink::WebInputEvent::LeftButtonDown)) {
+ bool was_throttled = IsThrottled();
+ MarkPluginEssential(UNTHROTTLE_METHOD_BY_CLICK);
+ return was_throttled;
+ }
+
+ return IsThrottled();
+}
+
+void PluginInstanceThrottlerImpl::EngageThrottle() {
+ if (state_ != THROTTLER_STATE_AWAITING_KEYFRAME)
+ return;
+
+ if (!last_received_frame_.empty()) {
+ FOR_EACH_OBSERVER(Observer, observer_list_,
+ OnKeyframeExtracted(&last_received_frame_));
+
+ // Release our reference to the underlying pixel data.
+ last_received_frame_.reset();
+ }
+
+ state_ = THROTTLER_STATE_PLUGIN_THROTTLED;
+ FOR_EACH_OBSERVER(Observer, observer_list_, OnThrottleStateChange());
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/pepper/plugin_instance_throttler_impl.h b/chromium/content/renderer/pepper/plugin_instance_throttler_impl.h
new file mode 100644
index 00000000000..ec3eed68403
--- /dev/null
+++ b/chromium/content/renderer/pepper/plugin_instance_throttler_impl.h
@@ -0,0 +1,118 @@
+// Copyright 2014 The Chromium Authors. 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_PEPPER_PLUGIN_INSTANCE_THROTTLER_IMPL_H_
+#define CONTENT_RENDERER_PEPPER_PLUGIN_INSTANCE_THROTTLER_IMPL_H_
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "base/timer/timer.h"
+#include "content/common/content_export.h"
+#include "content/public/renderer/plugin_instance_throttler.h"
+#include "content/renderer/pepper/pepper_webplugin_impl.h"
+#include "ppapi/shared_impl/ppb_view_shared.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace blink {
+class WebInputEvent;
+struct WebRect;
+}
+
+namespace content {
+
+class PepperWebPluginImpl;
+class RenderFrameImpl;
+
+class CONTENT_EXPORT PluginInstanceThrottlerImpl
+ : public PluginInstanceThrottler {
+ public:
+ PluginInstanceThrottlerImpl();
+
+ ~PluginInstanceThrottlerImpl() override;
+
+ // PluginInstanceThrottler implementation:
+ void AddObserver(Observer* observer) override;
+ void RemoveObserver(Observer* observer) override;
+ bool IsThrottled() const override;
+ bool IsHiddenForPlaceholder() const override;
+ void MarkPluginEssential(PowerSaverUnthrottleMethod method) override;
+ void SetHiddenForPlaceholder(bool hidden) override;
+ PepperWebPluginImpl* GetWebPlugin() const override;
+ const gfx::Size& GetSize() const override;
+ void NotifyAudioThrottled() override;
+
+ void SetWebPlugin(PepperWebPluginImpl* web_plugin);
+
+ bool needs_representative_keyframe() const {
+ return state_ == THROTTLER_STATE_AWAITING_KEYFRAME;
+ }
+
+ bool power_saver_enabled() const {
+ return state_ != THROTTLER_STATE_MARKED_ESSENTIAL;
+ }
+
+ void Initialize(RenderFrameImpl* frame,
+ const GURL& content_origin,
+ const std::string& plugin_module_name,
+ const gfx::Size& unobscured_size);
+
+ // Called when the plugin flushes it's graphics context. Supplies the
+ // throttler with a candidate to use as the representative keyframe.
+ void OnImageFlush(const SkBitmap* bitmap);
+
+ // Returns true if |event| was handled and shouldn't be further processed.
+ bool ConsumeInputEvent(const blink::WebInputEvent& event);
+
+ private:
+ friend class PluginInstanceThrottlerImplTest;
+
+ enum ThrottlerState {
+ // Plugin has been found to be peripheral, Plugin Power Saver is enabled,
+ // and throttler is awaiting a representative keyframe.
+ THROTTLER_STATE_AWAITING_KEYFRAME,
+ // A representative keyframe has been chosen and the plugin is throttled.
+ THROTTLER_STATE_PLUGIN_THROTTLED,
+ // Plugin instance has been marked essential.
+ THROTTLER_STATE_MARKED_ESSENTIAL,
+ };
+
+ // Maximum number of frames to examine for a suitable keyframe. After that, we
+ // simply suspend the plugin where it's at. Chosen arbitrarily.
+ static const int kMaximumFramesToExamine;
+
+ void AudioThrottledFrameTimeout();
+ void EngageThrottle();
+
+ ThrottlerState state_;
+
+ bool is_hidden_for_placeholder_;
+
+ PepperWebPluginImpl* web_plugin_;
+
+ // Holds a reference to the last received frame. This doesn't actually copy
+ // the pixel data, but rather increments the reference count to the pixels.
+ SkBitmap last_received_frame_;
+
+ // Number of frames we've examined to find a keyframe.
+ int frames_examined_;
+
+ // Plugin's unobscured dimensions as of initialization.
+ gfx::Size unobscured_size_;
+
+ // Video plugins with throttled audio often stop generating frames.
+ // This timer is so we don't wait forever for candidate poster frames.
+ bool audio_throttled_;
+ base::DelayTimer<PluginInstanceThrottlerImpl> audio_throttled_frame_timeout_;
+
+ ObserverList<Observer> observer_list_;
+
+ base::WeakPtrFactory<PluginInstanceThrottlerImpl> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(PluginInstanceThrottlerImpl);
+};
+}
+
+#endif // CONTENT_RENDERER_PEPPER_PLUGIN_INSTANCE_THROTTLER_IMPL_H_
diff --git a/chromium/content/renderer/pepper/plugin_instance_throttler_impl_unittest.cc b/chromium/content/renderer/pepper/plugin_instance_throttler_impl_unittest.cc
new file mode 100644
index 00000000000..65bef9399e3
--- /dev/null
+++ b/chromium/content/renderer/pepper/plugin_instance_throttler_impl_unittest.cc
@@ -0,0 +1,219 @@
+// Copyright 2014 The Chromium Authors. 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 "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/renderer/render_frame.h"
+#include "content/renderer/pepper/plugin_instance_throttler_impl.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
+#include "third_party/WebKit/public/web/WebPluginParams.h"
+#include "ui/gfx/canvas.h"
+
+using testing::_;
+using testing::Return;
+
+class GURL;
+
+namespace content {
+
+class PluginInstanceThrottlerImplTest
+ : public testing::Test,
+ public PluginInstanceThrottler::Observer {
+ protected:
+ const int kMaximumFramesToExamine =
+ PluginInstanceThrottlerImpl::kMaximumFramesToExamine;
+
+ PluginInstanceThrottlerImplTest() : change_callback_calls_(0) {}
+ ~PluginInstanceThrottlerImplTest() override {
+ throttler_->RemoveObserver(this);
+ }
+
+ void SetUp() override {
+ throttler_.reset(new PluginInstanceThrottlerImpl);
+ throttler_->Initialize(nullptr, GURL("http://example.com"),
+ "Shockwave Flash", gfx::Size(100, 100));
+ throttler_->AddObserver(this);
+ }
+
+ PluginInstanceThrottlerImpl* throttler() {
+ DCHECK(throttler_.get());
+ return throttler_.get();
+ }
+
+ void DisablePowerSaverByRetroactiveWhitelist() {
+ throttler()->MarkPluginEssential(
+ PluginInstanceThrottlerImpl::UNTHROTTLE_METHOD_BY_WHITELIST);
+ }
+
+ int change_callback_calls() { return change_callback_calls_; }
+
+ void EngageThrottle() { throttler_->EngageThrottle(); }
+
+ void SendEventAndTest(blink::WebInputEvent::Type event_type,
+ bool expect_consumed,
+ bool expect_throttled,
+ int expect_change_callback_count) {
+ blink::WebMouseEvent event;
+ event.type = event_type;
+ event.modifiers = blink::WebInputEvent::Modifiers::LeftButtonDown;
+ EXPECT_EQ(expect_consumed, throttler()->ConsumeInputEvent(event));
+ EXPECT_EQ(expect_throttled, throttler()->IsThrottled());
+ EXPECT_EQ(expect_change_callback_count, change_callback_calls());
+ }
+
+ private:
+ // PluginInstanceThrottlerImpl::Observer
+ void OnThrottleStateChange() override { ++change_callback_calls_; }
+
+ scoped_ptr<PluginInstanceThrottlerImpl> throttler_;
+
+ int change_callback_calls_;
+
+ base::MessageLoop loop_;
+};
+
+TEST_F(PluginInstanceThrottlerImplTest, ThrottleAndUnthrottleByClick) {
+ EXPECT_FALSE(throttler()->IsThrottled());
+ EXPECT_EQ(0, change_callback_calls());
+
+ EngageThrottle();
+ EXPECT_TRUE(throttler()->IsThrottled());
+ EXPECT_EQ(1, change_callback_calls());
+
+ // MouseUp while throttled should be consumed and disengage throttling.
+ SendEventAndTest(blink::WebInputEvent::Type::MouseUp, true, false, 2);
+}
+
+TEST_F(PluginInstanceThrottlerImplTest, ThrottleByKeyframe) {
+ EXPECT_FALSE(throttler()->IsThrottled());
+ EXPECT_EQ(0, change_callback_calls());
+
+ SkBitmap boring_bitmap;
+ gfx::Canvas canvas(gfx::Size(20, 10), 1.0f, true);
+ canvas.FillRect(gfx::Rect(20, 10), SK_ColorBLACK);
+ canvas.FillRect(gfx::Rect(10, 10), SK_ColorWHITE);
+ SkBitmap interesting_bitmap =
+ skia::GetTopDevice(*canvas.sk_canvas())->accessBitmap(false);
+
+ // Don't throttle for a boring frame.
+ throttler()->OnImageFlush(&boring_bitmap);
+ EXPECT_FALSE(throttler()->IsThrottled());
+ EXPECT_EQ(0, change_callback_calls());
+
+ // Throttle after an interesting frame.
+ throttler()->OnImageFlush(&interesting_bitmap);
+ EXPECT_TRUE(throttler()->IsThrottled());
+ EXPECT_EQ(1, change_callback_calls());
+}
+
+TEST_F(PluginInstanceThrottlerImplTest, MaximumKeyframesAnalyzed) {
+ EXPECT_FALSE(throttler()->IsThrottled());
+ EXPECT_EQ(0, change_callback_calls());
+
+ SkBitmap boring_bitmap;
+
+ // Throttle after tons of boring bitmaps.
+ for (int i = 0; i < kMaximumFramesToExamine; ++i) {
+ throttler()->OnImageFlush(&boring_bitmap);
+ }
+ EXPECT_TRUE(throttler()->IsThrottled());
+ EXPECT_EQ(1, change_callback_calls());
+}
+TEST_F(PluginInstanceThrottlerImplTest, IgnoreThrottlingAfterMouseUp) {
+ EXPECT_FALSE(throttler()->IsThrottled());
+ EXPECT_EQ(0, change_callback_calls());
+
+ // MouseUp before throttling engaged should not be consumed, but should
+ // prevent subsequent throttling from engaging.
+ SendEventAndTest(blink::WebInputEvent::Type::MouseUp, false, false, 0);
+
+ EngageThrottle();
+ EXPECT_FALSE(throttler()->IsThrottled());
+ EXPECT_EQ(0, change_callback_calls());
+}
+
+TEST_F(PluginInstanceThrottlerImplTest, FastWhitelisting) {
+ EXPECT_FALSE(throttler()->IsThrottled());
+ EXPECT_EQ(0, change_callback_calls());
+
+ DisablePowerSaverByRetroactiveWhitelist();
+
+ EngageThrottle();
+ EXPECT_FALSE(throttler()->IsThrottled());
+ EXPECT_EQ(0, change_callback_calls());
+}
+
+TEST_F(PluginInstanceThrottlerImplTest, SlowWhitelisting) {
+ EXPECT_FALSE(throttler()->IsThrottled());
+ EXPECT_EQ(0, change_callback_calls());
+
+ EngageThrottle();
+ EXPECT_TRUE(throttler()->IsThrottled());
+ EXPECT_EQ(1, change_callback_calls());
+
+ DisablePowerSaverByRetroactiveWhitelist();
+ EXPECT_FALSE(throttler()->IsThrottled());
+ EXPECT_EQ(2, change_callback_calls());
+}
+
+TEST_F(PluginInstanceThrottlerImplTest, EventConsumption) {
+ EXPECT_FALSE(throttler()->IsThrottled());
+ EXPECT_EQ(0, change_callback_calls());
+
+ EngageThrottle();
+ EXPECT_TRUE(throttler()->IsThrottled());
+ EXPECT_EQ(1, change_callback_calls());
+
+ // Consume but don't unthrottle on a variety of other events.
+ SendEventAndTest(blink::WebInputEvent::Type::MouseDown, true, true, 1);
+ SendEventAndTest(blink::WebInputEvent::Type::MouseWheel, true, true, 1);
+ SendEventAndTest(blink::WebInputEvent::Type::MouseMove, true, true, 1);
+ SendEventAndTest(blink::WebInputEvent::Type::KeyDown, true, true, 1);
+ SendEventAndTest(blink::WebInputEvent::Type::KeyUp, true, true, 1);
+
+ // Consume and unthrottle on MouseUp
+ SendEventAndTest(blink::WebInputEvent::Type::MouseUp, true, false, 2);
+
+ // Don't consume events after unthrottle.
+ SendEventAndTest(blink::WebInputEvent::Type::MouseDown, false, false, 2);
+ SendEventAndTest(blink::WebInputEvent::Type::MouseWheel, false, false, 2);
+ SendEventAndTest(blink::WebInputEvent::Type::MouseMove, false, false, 2);
+ SendEventAndTest(blink::WebInputEvent::Type::KeyDown, false, false, 2);
+ SendEventAndTest(blink::WebInputEvent::Type::KeyUp, false, false, 2);
+
+ // Subsequent MouseUps should also not be consumed.
+ SendEventAndTest(blink::WebInputEvent::Type::MouseUp, false, false, 2);
+}
+
+TEST_F(PluginInstanceThrottlerImplTest, ThrottleOnLeftClickOnly) {
+ EXPECT_FALSE(throttler()->IsThrottled());
+ EXPECT_EQ(0, change_callback_calls());
+
+ EngageThrottle();
+ EXPECT_TRUE(throttler()->IsThrottled());
+ EXPECT_EQ(1, change_callback_calls());
+
+ blink::WebMouseEvent event;
+ event.type = blink::WebInputEvent::Type::MouseUp;
+
+ event.modifiers = blink::WebInputEvent::Modifiers::RightButtonDown;
+ EXPECT_FALSE(throttler()->ConsumeInputEvent(event));
+ EXPECT_TRUE(throttler()->IsThrottled());
+
+ event.modifiers = blink::WebInputEvent::Modifiers::MiddleButtonDown;
+ EXPECT_TRUE(throttler()->ConsumeInputEvent(event));
+ EXPECT_TRUE(throttler()->IsThrottled());
+
+ event.modifiers = blink::WebInputEvent::Modifiers::LeftButtonDown;
+ EXPECT_TRUE(throttler()->ConsumeInputEvent(event));
+ EXPECT_FALSE(throttler()->IsThrottled());
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/pepper/plugin_module.cc b/chromium/content/renderer/pepper/plugin_module.cc
index 9a467940d41..2752840e2f4 100644
--- a/chromium/content/renderer/pepper/plugin_module.cc
+++ b/chromium/content/renderer/pepper/plugin_module.cc
@@ -21,6 +21,7 @@
#include "content/renderer/pepper/pepper_hung_plugin_filter.h"
#include "content/renderer/pepper/pepper_plugin_instance_impl.h"
#include "content/renderer/pepper/pepper_plugin_registry.h"
+#include "content/renderer/pepper/plugin_instance_throttler_impl.h"
#include "content/renderer/pepper/ppapi_preferences_builder.h"
#include "content/renderer/pepper/ppb_image_data_impl.h"
#include "content/renderer/pepper/ppb_proxy_impl.h"
@@ -63,7 +64,6 @@
#include "ppapi/c/ppb_console.h"
#include "ppapi/c/ppb_core.h"
#include "ppapi/c/ppb_file_io.h"
-#include "ppapi/c/ppb_file_mapping.h"
#include "ppapi/c/ppb_file_ref.h"
#include "ppapi/c/ppb_file_system.h"
#include "ppapi/c/ppb_fullscreen.h"
@@ -93,10 +93,13 @@
#include "ppapi/c/ppb_var_array_buffer.h"
#include "ppapi/c/ppb_var_dictionary.h"
#include "ppapi/c/ppb_video_decoder.h"
+#include "ppapi/c/ppb_video_encoder.h"
#include "ppapi/c/ppb_video_frame.h"
#include "ppapi/c/ppb_view.h"
#include "ppapi/c/ppp.h"
#include "ppapi/c/ppp_instance.h"
+#include "ppapi/c/private/ppb_camera_capabilities_private.h"
+#include "ppapi/c/private/ppb_camera_device_private.h"
#include "ppapi/c/private/ppb_ext_crx_file_system_private.h"
#include "ppapi/c/private/ppb_file_io_private.h"
#include "ppapi/c/private/ppb_file_ref_private.h"
@@ -118,7 +121,6 @@
#include "ppapi/c/private/ppb_output_protection_private.h"
#include "ppapi/c/private/ppb_pdf.h"
#include "ppapi/c/private/ppb_proxy_private.h"
-#include "ppapi/c/private/ppb_talk_private.h"
#include "ppapi/c/private/ppb_tcp_server_socket_private.h"
#include "ppapi/c/private/ppb_tcp_socket_private.h"
#include "ppapi/c/private/ppb_testing_private.h"
@@ -133,6 +135,7 @@
#include "ppapi/c/trusted/ppb_file_chooser_trusted.h"
#include "ppapi/c/trusted/ppb_url_loader_trusted.h"
#include "ppapi/shared_impl/callback_tracker.h"
+#include "ppapi/shared_impl/dictionary_var.h"
#include "ppapi/shared_impl/ppapi_preferences.h"
#include "ppapi/shared_impl/ppapi_switches.h"
#include "ppapi/shared_impl/ppb_input_event_shared.h"
@@ -179,6 +182,72 @@ PluginModuleSet* GetLivePluginSet() {
return &live_plugin_libs;
}
+class PowerSaverTestPluginDelegate : public PluginInstanceThrottler::Observer {
+ public:
+ explicit PowerSaverTestPluginDelegate(PluginInstanceThrottlerImpl* throttler)
+ : throttler_(throttler) {
+ throttler_->AddObserver(this);
+ PostPowerSaverStatusToJavaScript("initial");
+ }
+
+ virtual ~PowerSaverTestPluginDelegate() { throttler_->RemoveObserver(this); }
+
+ static void PostPowerSaverStatusToJavaScript(
+ PepperPluginInstanceImpl* instance,
+ const std::string& source) {
+ DCHECK(instance);
+
+ bool is_hidden_for_placeholder = false;
+ bool is_peripheral = false;
+ bool is_throttled = false;
+
+ if (instance->throttler()) {
+ PluginInstanceThrottlerImpl* throttler = instance->throttler();
+ is_hidden_for_placeholder = throttler->IsHiddenForPlaceholder();
+ is_peripheral = throttler->power_saver_enabled();
+ is_throttled = throttler->IsThrottled();
+ }
+
+ // Refcounted by the returned PP_Var.
+ ppapi::DictionaryVar* dictionary = new ppapi::DictionaryVar;
+ dictionary->Set(ppapi::StringVar::StringToPPVar("source"),
+ ppapi::StringVar::StringToPPVar(source));
+ dictionary->Set(ppapi::StringVar::StringToPPVar("isHiddenForPlaceholder"),
+ PP_MakeBool(PP_FromBool(is_hidden_for_placeholder)));
+ dictionary->Set(ppapi::StringVar::StringToPPVar("isPeripheral"),
+ PP_MakeBool(PP_FromBool(is_peripheral)));
+ dictionary->Set(ppapi::StringVar::StringToPPVar("isThrottled"),
+ PP_MakeBool(PP_FromBool(is_throttled)));
+
+ instance->PostMessageToJavaScript(dictionary->GetPPVar());
+ }
+
+ private:
+ void OnThrottleStateChange() override {
+ PostPowerSaverStatusToJavaScript("throttleStatusChange");
+ }
+
+ void OnPeripheralStateChange() override {
+ PostPowerSaverStatusToJavaScript("peripheralStatusChange");
+ }
+
+ void OnHiddenForPlaceholder(bool hidden) override {
+ PostPowerSaverStatusToJavaScript("hiddenForPlaceholderStatusChange");
+ }
+
+ void OnThrottlerDestroyed() override { delete this; }
+
+ void PostPowerSaverStatusToJavaScript(const std::string& source) {
+ if (!throttler_->GetWebPlugin() || !throttler_->GetWebPlugin()->instance())
+ return;
+ PostPowerSaverStatusToJavaScript(throttler_->GetWebPlugin()->instance(),
+ source);
+ }
+
+ // Non-owning pointer.
+ PluginInstanceThrottlerImpl* const throttler_;
+};
+
// PPB_Core --------------------------------------------------------------------
void AddRefResource(PP_Resource resource) {
@@ -244,6 +313,32 @@ uint32_t GetLiveObjectsForInstance(PP_Instance instance_id) {
PP_Bool IsOutOfProcess() { return PP_FALSE; }
+void PostPowerSaverStatus(PP_Instance instance_id) {
+ PepperPluginInstanceImpl* plugin_instance =
+ host_globals->GetInstance(instance_id);
+ if (!plugin_instance)
+ return;
+
+ PowerSaverTestPluginDelegate::PostPowerSaverStatusToJavaScript(
+ plugin_instance, "getPowerSaverStatusResponse");
+}
+
+void SubscribeToPowerSaverNotifications(PP_Instance instance_id) {
+ PepperPluginInstanceImpl* plugin_instance =
+ host_globals->GetInstance(instance_id);
+ if (!plugin_instance)
+ return;
+
+ if (plugin_instance->throttler()) {
+ // Manages its own lifetime.
+ new PowerSaverTestPluginDelegate(plugin_instance->throttler());
+ } else {
+ // Just send an initial status. This status will never be updated.
+ PowerSaverTestPluginDelegate::PostPowerSaverStatusToJavaScript(
+ plugin_instance, "initial");
+ }
+}
+
void SimulateInputEvent(PP_Instance instance, PP_Resource input_event) {
PepperPluginInstanceImpl* plugin_instance =
host_globals->GetInstance(instance);
@@ -287,11 +382,18 @@ void RunV8GC(PP_Instance instance) {
}
const PPB_Testing_Private testing_interface = {
- &ReadImageData, &RunMessageLoop,
- &QuitMessageLoop, &GetLiveObjectsForInstance,
- &IsOutOfProcess, &SimulateInputEvent,
- &GetDocumentURL, &GetLiveVars,
- &SetMinimumArrayBufferSizeForShmem,&RunV8GC};
+ &ReadImageData,
+ &RunMessageLoop,
+ &QuitMessageLoop,
+ &GetLiveObjectsForInstance,
+ &IsOutOfProcess,
+ &PostPowerSaverStatus,
+ &SubscribeToPowerSaverNotifications,
+ &SimulateInputEvent,
+ &GetDocumentURL,
+ &GetLiveVars,
+ &SetMinimumArrayBufferSizeForShmem,
+ &RunV8GC};
// GetInterface ----------------------------------------------------------------
@@ -327,7 +429,7 @@ const void* InternalGetInterface(const char* name) {
// Only support the testing interface when the command line switch is
// specified. This allows us to prevent people from (ab)using this interface
// in production code.
- if (CommandLine::ForCurrentProcess()->HasSwitch(
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnablePepperTesting)) {
if (strcmp(name, PPB_TESTING_PRIVATE_INTERFACE) == 0)
return &testing_interface;
diff --git a/chromium/content/renderer/pepper/plugin_object.cc b/chromium/content/renderer/pepper/plugin_object.cc
index 729b4801452..2c82c3f32d6 100644
--- a/chromium/content/renderer/pepper/plugin_object.cc
+++ b/chromium/content/renderer/pepper/plugin_object.cc
@@ -58,7 +58,7 @@ gin::WrapperInfo PluginObject::kWrapperInfo = {gin::kEmbedderNativeGin};
// static
PluginObject* PluginObject::FromV8Object(v8::Isolate* isolate,
- v8::Handle<v8::Object> v8_object) {
+ v8::Local<v8::Object> v8_object) {
PluginObject* plugin_object;
if (!v8_object.IsEmpty() &&
gin::ConvertFromV8(isolate, v8_object, &plugin_object)) {
@@ -169,6 +169,7 @@ PluginObject::PluginObject(PepperPluginInstanceImpl* instance,
instance_(instance),
ppp_class_(ppp_class),
ppp_class_data_(ppp_class_data),
+ template_cache_(instance->GetIsolate()),
weak_factory_(this) {
instance_->AddPluginObject(this);
}
@@ -200,7 +201,7 @@ v8::Local<v8::Value> PluginObject::GetPropertyOrMethod(v8::Isolate* isolate,
if (try_catch.ThrowException())
return v8::Local<v8::Value>();
- v8::Handle<v8::Value> result = try_catch.ToV8(result_var.get());
+ v8::Local<v8::Value> result = try_catch.ToV8(result_var.get());
if (try_catch.ThrowException())
return v8::Local<v8::Value>();
@@ -216,10 +217,7 @@ v8::Local<v8::Value> PluginObject::GetPropertyOrMethod(v8::Isolate* isolate,
if (has_method) {
const std::string& identifier =
StringVar::FromPPVar(identifier_var)->value();
- return gin::CreateFunctionTemplate(isolate,
- base::Bind(&PluginObject::Call,
- weak_factory_.GetWeakPtr(),
- identifier))->GetFunction();
+ return GetFunctionTemplate(isolate, identifier)->GetFunction();
}
return v8::Local<v8::Value>();
@@ -238,7 +236,7 @@ void PluginObject::Call(const std::string& identifier,
ScopedPPVarArray argument_vars(args->Length());
for (uint32_t i = 0; i < argument_vars.size(); ++i) {
- v8::Handle<v8::Value> arg;
+ v8::Local<v8::Value> arg;
if (!args->GetNext(&arg)) {
NOTREACHED();
}
@@ -261,11 +259,25 @@ void PluginObject::Call(const std::string& identifier,
if (try_catch.ThrowException())
return;
- v8::Handle<v8::Value> result = try_catch.ToV8(result_var.get());
+ v8::Local<v8::Value> result = try_catch.ToV8(result_var.get());
if (try_catch.ThrowException())
return;
args->Return(result);
}
+v8::Local<v8::FunctionTemplate> PluginObject::GetFunctionTemplate(
+ v8::Isolate* isolate,
+ const std::string& name) {
+ v8::Local<v8::FunctionTemplate> function_template = template_cache_.Get(name);
+ if (!function_template.IsEmpty())
+ return function_template;
+ function_template =
+ gin::CreateFunctionTemplate(
+ isolate, base::Bind(&PluginObject::Call, weak_factory_.GetWeakPtr(),
+ name));
+ template_cache_.Set(name, function_template);
+ return function_template;
+}
+
} // namespace content
diff --git a/chromium/content/renderer/pepper/plugin_object.h b/chromium/content/renderer/pepper/plugin_object.h
index 4dec6205d58..d5502d8ee76 100644
--- a/chromium/content/renderer/pepper/plugin_object.h
+++ b/chromium/content/renderer/pepper/plugin_object.h
@@ -12,6 +12,7 @@
#include "gin/interceptor.h"
#include "gin/wrappable.h"
#include "ppapi/c/pp_var.h"
+#include "v8/include/v8-util.h"
struct PPP_Class_Deprecated;
@@ -37,7 +38,7 @@ class PluginObject : public gin::Wrappable<PluginObject>,
// Returns the PluginObject which is contained in the given v8 object, or NULL
// if the object isn't backed by a PluginObject.
static PluginObject* FromV8Object(v8::Isolate* isolate,
- v8::Handle<v8::Object> v8_object);
+ v8::Local<v8::Object> v8_object);
// Allocates a new PluginObject and returns it as a PP_Var with a
// refcount of 1.
@@ -75,11 +76,16 @@ class PluginObject : public gin::Wrappable<PluginObject>,
void Call(const std::string& identifier, gin::Arguments* args);
+ v8::Local<v8::FunctionTemplate> GetFunctionTemplate(v8::Isolate* isolate,
+ const std::string& name);
+
PepperPluginInstanceImpl* instance_;
const PPP_Class_Deprecated* ppp_class_;
void* ppp_class_data_;
+ v8::StdGlobalValueMap<std::string, v8::FunctionTemplate> template_cache_;
+
base::WeakPtrFactory<PluginObject> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(PluginObject);
diff --git a/chromium/content/renderer/pepper/plugin_power_saver_helper.cc b/chromium/content/renderer/pepper/plugin_power_saver_helper.cc
index 3c60c16d2db..7931b41d7d1 100644
--- a/chromium/content/renderer/pepper/plugin_power_saver_helper.cc
+++ b/chromium/content/renderer/pepper/plugin_power_saver_helper.cc
@@ -2,15 +2,21 @@
// 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 "content/renderer/pepper/plugin_power_saver_helper.h"
+
+#include <string>
+
+#include "base/command_line.h"
#include "base/metrics/histogram.h"
+#include "base/strings/string_number_conversions.h"
#include "content/common/frame_messages.h"
-#include "content/public/renderer/document_state.h"
-#include "content/public/renderer/navigation_state.h"
+#include "content/public/common/content_constants.h"
+#include "content/public/common/content_switches.h"
#include "content/public/renderer/render_frame.h"
-#include "content/renderer/pepper/plugin_power_saver_helper.h"
+#include "ppapi/shared_impl/ppapi_constants.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
+#include "third_party/WebKit/public/web/WebPluginParams.h"
#include "third_party/WebKit/public/web/WebView.h"
namespace content {
@@ -24,16 +30,22 @@ enum PeripheralHeuristicDecision {
HEURISTIC_DECISION_ESSENTIAL_SAME_ORIGIN = 1,
HEURISTIC_DECISION_ESSENTIAL_CROSS_ORIGIN_BIG = 2,
HEURISTIC_DECISION_ESSENTIAL_CROSS_ORIGIN_WHITELISTED = 3,
+ HEURISTIC_DECISION_ESSENTIAL_CROSS_ORIGIN_TINY = 4,
HEURISTIC_DECISION_NUM_ITEMS
};
const char kPeripheralHeuristicHistogram[] =
"Plugin.PowerSaver.PeripheralHeuristic";
-// Maximum dimensions plug-in content may have while still being considered
-// peripheral content. These match the sizes used by Safari.
-const int kPeripheralContentMaxWidth = 400;
-const int kPeripheralContentMaxHeight = 300;
+// Maximum dimensions plugin content may have while still being considered
+// peripheral content. These are similar to the numbers used by WebKit.
+const int kPeripheralContentMaxWidth = 398;
+const int kPeripheralContentMaxHeight = 298;
+
+// Plugin content below this size in height and width is considered "tiny".
+// Tiny content is never peripheral, as tiny plugins often serve a critical
+// purpose, and the user often cannot find and click to unthrottle it.
+const int kPeripheralContentTinySize = 5;
void RecordDecisionMetric(PeripheralHeuristicDecision decision) {
UMA_HISTOGRAM_ENUMERATION(kPeripheralHeuristicHistogram, decision,
@@ -52,30 +64,39 @@ PluginPowerSaverHelper::PeripheralPlugin::~PeripheralPlugin() {
}
PluginPowerSaverHelper::PluginPowerSaverHelper(RenderFrame* render_frame)
- : RenderFrameObserver(render_frame) {
+ : RenderFrameObserver(render_frame)
+ , override_for_testing_(Normal) {
+ base::CommandLine& command_line = *base::CommandLine::ForCurrentProcess();
+ std::string override_for_testing = command_line.GetSwitchValueASCII(
+ switches::kOverridePluginPowerSaverForTesting);
+ if (override_for_testing == "never")
+ override_for_testing_ = Never;
+ else if (override_for_testing == "ignore-list")
+ override_for_testing_ = IgnoreList;
+ else if (override_for_testing == "always")
+ override_for_testing_ = Always;
}
PluginPowerSaverHelper::~PluginPowerSaverHelper() {
}
-void PluginPowerSaverHelper::DidCommitProvisionalLoad(bool is_new_navigation) {
+void PluginPowerSaverHelper::DidCommitProvisionalLoad(
+ bool is_new_navigation,
+ bool is_same_page_navigation) {
blink::WebFrame* frame = render_frame()->GetWebFrame();
- if (frame->parent())
+ // Only apply to top-level and new page navigation.
+ if (frame->parent() || is_same_page_navigation)
return; // Not a top-level navigation.
- DocumentState* document_state =
- DocumentState::FromDataSource(frame->dataSource());
- NavigationState* navigation_state = document_state->navigation_state();
- if (!navigation_state->was_within_same_page())
- origin_whitelist_.clear();
+ origin_whitelist_.clear();
}
bool PluginPowerSaverHelper::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(PluginPowerSaverHelper, message)
- IPC_MESSAGE_HANDLER(FrameMsg_UpdatePluginContentOriginWhitelist,
- OnUpdatePluginContentOriginWhitelist)
- IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_MESSAGE_HANDLER(FrameMsg_UpdatePluginContentOriginWhitelist,
+ OnUpdatePluginContentOriginWhitelist)
+ IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
@@ -96,12 +117,37 @@ void PluginPowerSaverHelper::OnUpdatePluginContentOriginWhitelist(
}
}
-bool PluginPowerSaverHelper::ShouldThrottleContent(const GURL& content_origin,
- int width,
- int height,
- bool* cross_origin) const {
- DCHECK(cross_origin);
- *cross_origin = true;
+void PluginPowerSaverHelper::RegisterPeripheralPlugin(
+ const GURL& content_origin,
+ const base::Closure& unthrottle_callback) {
+ DCHECK_EQ(content_origin.GetOrigin(), content_origin);
+ peripheral_plugins_.push_back(
+ PeripheralPlugin(content_origin, unthrottle_callback));
+}
+
+bool PluginPowerSaverHelper::ShouldThrottleContent(
+ const GURL& content_origin,
+ const std::string& plugin_module_name,
+ int width,
+ int height,
+ bool* cross_origin_main_content) const {
+ DCHECK_EQ(content_origin.GetOrigin(), content_origin);
+ if (cross_origin_main_content)
+ *cross_origin_main_content = false;
+
+ // This feature has only been tested throughly with Flash thus far.
+ // It is also enabled for the Power Saver test plugin for browser tests.
+ if (override_for_testing_ == Always) {
+ return true;
+ } else if (override_for_testing_ == Never) {
+ return false;
+ } else if (override_for_testing_ == Normal &&
+ plugin_module_name != content::kFlashPluginName) {
+ return false;
+ }
+
+ if (width <= 0 || height <= 0)
+ return false;
// TODO(alexmos): Update this to use the origin of the RemoteFrame when 426512
// is fixed. For now, case 3 in the class level comment doesn't work in
@@ -117,7 +163,6 @@ bool PluginPowerSaverHelper::ShouldThrottleContent(const GURL& content_origin,
GURL main_frame_origin = GURL(main_frame->document().url()).GetOrigin();
if (content_origin == main_frame_origin) {
RecordDecisionMetric(HEURISTIC_DECISION_ESSENTIAL_SAME_ORIGIN);
- *cross_origin = false;
return false;
}
@@ -127,27 +172,29 @@ bool PluginPowerSaverHelper::ShouldThrottleContent(const GURL& content_origin,
return false;
}
- // Cross-origin plugin content is peripheral if smaller than a maximum size.
- bool content_is_small = width < kPeripheralContentMaxWidth ||
- height < kPeripheralContentMaxHeight;
+ // Never mark tiny content as peripheral.
+ if (width <= kPeripheralContentTinySize &&
+ height <= kPeripheralContentTinySize) {
+ RecordDecisionMetric(HEURISTIC_DECISION_ESSENTIAL_CROSS_ORIGIN_TINY);
+ return false;
+ }
- if (content_is_small)
- RecordDecisionMetric(HEURISTIC_DECISION_PERIPHERAL);
- else
+ // Plugin content large in both dimensions are the "main attraction".
+ if (width >= kPeripheralContentMaxWidth &&
+ height >= kPeripheralContentMaxHeight) {
RecordDecisionMetric(HEURISTIC_DECISION_ESSENTIAL_CROSS_ORIGIN_BIG);
+ if (cross_origin_main_content)
+ *cross_origin_main_content = true;
+ return false;
+ }
- return content_is_small;
-}
-
-void PluginPowerSaverHelper::RegisterPeripheralPlugin(
- const GURL& content_origin,
- const base::Closure& unthrottle_callback) {
- peripheral_plugins_.push_back(
- PeripheralPlugin(content_origin, unthrottle_callback));
+ RecordDecisionMetric(HEURISTIC_DECISION_PERIPHERAL);
+ return true;
}
void PluginPowerSaverHelper::WhitelistContentOrigin(
const GURL& content_origin) {
+ DCHECK_EQ(content_origin.GetOrigin(), content_origin);
if (origin_whitelist_.insert(content_origin).second) {
Send(new FrameHostMsg_PluginContentOriginAllowed(
render_frame()->GetRoutingID(), content_origin));
diff --git a/chromium/content/renderer/pepper/plugin_power_saver_helper.h b/chromium/content/renderer/pepper/plugin_power_saver_helper.h
index e4678a63464..3e88b10ac05 100644
--- a/chromium/content/renderer/pepper/plugin_power_saver_helper.h
+++ b/chromium/content/renderer/pepper/plugin_power_saver_helper.h
@@ -8,23 +8,31 @@
#include <set>
#include <vector>
-#include "base/callback_forward.h"
+#include "base/callback.h"
+#include "content/common/content_export.h"
#include "content/public/renderer/render_frame_observer.h"
#include "url/gurl.h"
+namespace blink {
+struct WebPluginParams;
+struct WebRect;
+}
+
namespace content {
-// PluginPowerSaverWhitelist manages the plugin content origin whitelist for
-// a single render frame.
class CONTENT_EXPORT PluginPowerSaverHelper : public RenderFrameObserver {
public:
explicit PluginPowerSaverHelper(RenderFrame* render_frame);
- virtual ~PluginPowerSaverHelper();
+ ~PluginPowerSaverHelper() override;
+
+ // See RenderFrame for documentation.
+ void RegisterPeripheralPlugin(const GURL& content_origin,
+ const base::Closure& unthrottle_callback);
// Returns true if this plugin should have power saver enabled.
//
// Power Saver is enabled for plugin content that are cross-origin and
- // heuristically determined to be not the "main attraction" of the webpage.
+ // heuristically determined to be not essential to the web page content.
//
// Plugin content is defined to be cross-origin when the plugin source's
// origin differs from the top level frame's origin. For example:
@@ -32,18 +40,22 @@ class CONTENT_EXPORT PluginPowerSaverHelper : public RenderFrameObserver {
// - Cross-origin: a.com -> b.com/iframe.html -> b.com/plugin.swf
// - Same-origin: a.com -> b.com/iframe-to-a.html -> a.com/plugin.swf
//
- // |cross_origin| may not be NULL.
+ // |page_frame_url| is the URL of the frame containing the plugin, which may
+ // be different from the URL of the top level document.
+ //
+ // |poster_image| may be NULL. It is set to the absolute URL of the poster
+ // image if it exists and this method returns true. Otherwise, an empty GURL.
+ //
+ // |cross_origin_main_content| may be NULL. It is set to true if the
+ // plugin content is cross-origin but still the "main attraction" of the page.
bool ShouldThrottleContent(const GURL& content_origin,
+ const std::string& plugin_module_name,
int width,
int height,
- bool* cross_origin) const;
-
- // Registers a plugin that has been marked peripheral. If the origin
- // whitelist is later updated and includes |content_origin|, then
- // |unthrottle_callback| will be called.
- void RegisterPeripheralPlugin(const GURL& content_origin,
- const base::Closure& unthrottle_callback);
+ bool* cross_origin_main_content) const;
+ // Whitelists a |content_origin| so its content will never be throttled in
+ // this RenderFrame. Whitelist is cleared by top level navigation.
void WhitelistContentOrigin(const GURL& content_origin);
private:
@@ -56,13 +68,23 @@ class CONTENT_EXPORT PluginPowerSaverHelper : public RenderFrameObserver {
base::Closure unthrottle_callback;
};
+ enum OverrideForTesting {
+ Normal,
+ Never,
+ IgnoreList,
+ Always
+ };
+
// RenderFrameObserver implementation.
- void DidCommitProvisionalLoad(bool is_new_navigation) override;
+ void DidCommitProvisionalLoad(bool is_new_navigation,
+ bool is_same_page_navigation) override;
bool OnMessageReceived(const IPC::Message& message) override;
void OnUpdatePluginContentOriginWhitelist(
const std::set<GURL>& origin_whitelist);
+ OverrideForTesting override_for_testing_;
+
// Local copy of the whitelist for the entire tab.
std::set<GURL> origin_whitelist_;
diff --git a/chromium/content/renderer/pepper/plugin_power_saver_helper_browsertest.cc b/chromium/content/renderer/pepper/plugin_power_saver_helper_browsertest.cc
index 0cdec0f3140..7444d1cc45c 100644
--- a/chromium/content/renderer/pepper/plugin_power_saver_helper_browsertest.cc
+++ b/chromium/content/renderer/pepper/plugin_power_saver_helper_browsertest.cc
@@ -5,6 +5,7 @@
#include "base/run_loop.h"
#include "content/common/frame_messages.h"
#include "content/common/view_message_enums.h"
+#include "content/public/common/content_constants.h"
#include "content/public/test/render_view_test.h"
#include "content/renderer/pepper/plugin_power_saver_helper.h"
#include "content/renderer/render_frame_impl.h"
@@ -12,6 +13,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
+#include "third_party/WebKit/public/web/WebPluginParams.h"
#include "url/gurl.h"
namespace content {
@@ -24,7 +26,7 @@ class PluginPowerSaverHelperTest : public RenderViewTest {
return static_cast<RenderFrameImpl*>(view_->GetMainRenderFrame());
}
- PluginPowerSaverHelper* power_saver_helper() {
+ PluginPowerSaverHelper* helper() {
return frame()->plugin_power_saver_helper();
}
@@ -33,6 +35,30 @@ class PluginPowerSaverHelperTest : public RenderViewTest {
sink_ = &render_thread_->sink();
}
+ blink::WebPluginParams MakeParams(const std::string& url,
+ const std::string& poster,
+ const std::string& width,
+ const std::string& height) {
+ const size_t size = 3;
+ blink::WebVector<blink::WebString> names(size);
+ blink::WebVector<blink::WebString> values(size);
+
+ blink::WebPluginParams params;
+ params.url = GURL(url);
+
+ params.attributeNames.swap(names);
+ params.attributeValues.swap(values);
+
+ params.attributeNames[0] = "poster";
+ params.attributeNames[1] = "height";
+ params.attributeNames[2] = "width";
+ params.attributeValues[0] = blink::WebString::fromUTF8(poster);
+ params.attributeValues[1] = blink::WebString::fromUTF8(height);
+ params.attributeValues[2] = blink::WebString::fromUTF8(width);
+
+ return params;
+ }
+
protected:
IPC::TestSink* sink_;
@@ -40,40 +66,62 @@ class PluginPowerSaverHelperTest : public RenderViewTest {
};
TEST_F(PluginPowerSaverHelperTest, AllowSameOrigin) {
- bool cross_origin = false;
- EXPECT_FALSE(power_saver_helper()->ShouldThrottleContent(
- GURL(), 100, 100, &cross_origin));
- EXPECT_FALSE(cross_origin);
-
- EXPECT_FALSE(power_saver_helper()->ShouldThrottleContent(
- GURL(), 1000, 1000, &cross_origin));
- EXPECT_FALSE(cross_origin);
+ EXPECT_FALSE(helper()->ShouldThrottleContent(GURL(), kFlashPluginName, 100,
+ 100, nullptr));
+ EXPECT_FALSE(helper()->ShouldThrottleContent(GURL(), kFlashPluginName, 1000,
+ 1000, nullptr));
}
TEST_F(PluginPowerSaverHelperTest, DisallowCrossOriginUnlessLarge) {
- bool cross_origin = false;
- EXPECT_TRUE(power_saver_helper()->ShouldThrottleContent(
- GURL("http://other.com"), 100, 100, &cross_origin));
- EXPECT_TRUE(cross_origin);
-
- EXPECT_FALSE(power_saver_helper()->ShouldThrottleContent(
- GURL("http://other.com"), 1000, 1000, &cross_origin));
- EXPECT_TRUE(cross_origin);
+ bool cross_origin_main_content = false;
+ EXPECT_TRUE(helper()->ShouldThrottleContent(GURL("http://b.com"),
+ kFlashPluginName, 100, 100,
+ &cross_origin_main_content));
+ EXPECT_FALSE(cross_origin_main_content);
+
+ EXPECT_FALSE(helper()->ShouldThrottleContent(GURL("http://b.com"),
+ kFlashPluginName, 1000, 1000,
+ &cross_origin_main_content));
+ EXPECT_TRUE(cross_origin_main_content);
+}
+
+TEST_F(PluginPowerSaverHelperTest, AlwaysAllowTinyContent) {
+ bool cross_origin_main_content = false;
+ EXPECT_FALSE(
+ helper()->ShouldThrottleContent(GURL(), kFlashPluginName, 1, 1, nullptr));
+ EXPECT_FALSE(cross_origin_main_content);
+
+ EXPECT_FALSE(helper()->ShouldThrottleContent(GURL("http://b.com"),
+ kFlashPluginName, 1, 1,
+ &cross_origin_main_content));
+ EXPECT_FALSE(cross_origin_main_content);
+
+ EXPECT_FALSE(helper()->ShouldThrottleContent(GURL("http://b.com"),
+ kFlashPluginName, 5, 5,
+ &cross_origin_main_content));
+ EXPECT_FALSE(cross_origin_main_content);
+
+ EXPECT_TRUE(helper()->ShouldThrottleContent(GURL("http://b.com"),
+ kFlashPluginName, 10, 10,
+ &cross_origin_main_content));
+ EXPECT_FALSE(cross_origin_main_content);
}
TEST_F(PluginPowerSaverHelperTest, TemporaryOriginWhitelist) {
- bool cross_origin = false;
- EXPECT_TRUE(power_saver_helper()->ShouldThrottleContent(
- GURL("http://other.com"), 100, 100, &cross_origin));
- EXPECT_TRUE(cross_origin);
+ bool cross_origin_main_content = false;
+ EXPECT_TRUE(helper()->ShouldThrottleContent(GURL("http://b.com"),
+ kFlashPluginName, 100, 100,
+ &cross_origin_main_content));
+ EXPECT_FALSE(cross_origin_main_content);
// Clear out other messages so we find just the plugin power saver IPCs.
sink_->ClearMessages();
- power_saver_helper()->WhitelistContentOrigin(GURL("http://other.com"));
- EXPECT_FALSE(power_saver_helper()->ShouldThrottleContent(
- GURL("http://other.com"), 100, 100, &cross_origin));
- EXPECT_TRUE(cross_origin);
+ helper()->WhitelistContentOrigin(GURL("http://b.com"));
+ EXPECT_FALSE(helper()->ShouldThrottleContent(GURL("http://b.com"),
+ kFlashPluginName, 100, 100,
+ &cross_origin_main_content));
+ EXPECT_FALSE(cross_origin_main_content);
// Test that we've sent an IPC to the browser.
ASSERT_EQ(1u, sink_->message_count());
@@ -81,13 +129,13 @@ TEST_F(PluginPowerSaverHelperTest, TemporaryOriginWhitelist) {
EXPECT_EQ(FrameHostMsg_PluginContentOriginAllowed::ID, msg->type());
FrameHostMsg_PluginContentOriginAllowed::Param params;
FrameHostMsg_PluginContentOriginAllowed::Read(msg, &params);
- EXPECT_EQ(GURL("http://other.com"), params.a);
+ EXPECT_EQ(GURL("http://b.com"), get<0>(params));
}
TEST_F(PluginPowerSaverHelperTest, UnthrottleOnExPostFactoWhitelist) {
base::RunLoop loop;
- power_saver_helper()->RegisterPeripheralPlugin(GURL("http://other.com"),
- loop.QuitClosure());
+ frame()->RegisterPeripheralPlugin(GURL("http://other.com"),
+ loop.QuitClosure());
std::set<GURL> origin_whitelist;
origin_whitelist.insert(GURL("http://other.com"));
@@ -99,18 +147,15 @@ TEST_F(PluginPowerSaverHelperTest, UnthrottleOnExPostFactoWhitelist) {
}
TEST_F(PluginPowerSaverHelperTest, ClearWhitelistOnNavigate) {
- power_saver_helper()->WhitelistContentOrigin(GURL("http://other.com"));
+ helper()->WhitelistContentOrigin(GURL("http://b.com"));
- bool cross_origin = false;
- EXPECT_FALSE(power_saver_helper()->ShouldThrottleContent(
- GURL("http://other.com"), 100, 100, &cross_origin));
- EXPECT_TRUE(cross_origin);
+ EXPECT_FALSE(helper()->ShouldThrottleContent(
+ GURL("http://b.com"), kFlashPluginName, 100, 100, nullptr));
LoadHTML("<html></html>");
- EXPECT_TRUE(power_saver_helper()->ShouldThrottleContent(
- GURL("http://other.com"), 100, 100, &cross_origin));
- EXPECT_TRUE(cross_origin);
+ EXPECT_TRUE(helper()->ShouldThrottleContent(
+ GURL("http://b.com"), kFlashPluginName, 100, 100, nullptr));
}
} // namespace content
diff --git a/chromium/content/renderer/pepper/ppb_audio_impl.cc b/chromium/content/renderer/pepper/ppb_audio_impl.cc
index 6db6edf410d..d5b1b753a90 100644
--- a/chromium/content/renderer/pepper/ppb_audio_impl.cc
+++ b/chromium/content/renderer/pepper/ppb_audio_impl.cc
@@ -7,6 +7,7 @@
#include "base/logging.h"
#include "content/renderer/pepper/pepper_platform_audio_output.h"
#include "content/renderer/pepper/pepper_plugin_instance_impl.h"
+#include "content/renderer/pepper/plugin_instance_throttler_impl.h"
#include "content/renderer/render_frame_impl.h"
#include "content/renderer/render_view_impl.h"
#include "media/audio/audio_output_controller.h"
@@ -29,9 +30,24 @@ namespace content {
// PPB_Audio_Impl --------------------------------------------------------------
PPB_Audio_Impl::PPB_Audio_Impl(PP_Instance instance)
- : Resource(ppapi::OBJECT_IS_IMPL, instance), audio_(NULL) {}
+ : Resource(ppapi::OBJECT_IS_IMPL, instance),
+ audio_(NULL),
+ playback_throttled_(false) {
+ PepperPluginInstanceImpl* plugin_instance =
+ static_cast<PepperPluginInstanceImpl*>(
+ PepperPluginInstance::Get(pp_instance()));
+ if (plugin_instance && plugin_instance->throttler()) {
+ plugin_instance->throttler()->AddObserver(this);
+ }
+}
PPB_Audio_Impl::~PPB_Audio_Impl() {
+ PepperPluginInstanceImpl* instance = static_cast<PepperPluginInstanceImpl*>(
+ PepperPluginInstance::Get(pp_instance()));
+ if (instance && instance->throttler()) {
+ instance->throttler()->RemoveObserver(this);
+ }
+
// Calling ShutDown() makes sure StreamCreated cannot be called anymore and
// releases the audio data associated with the pointer. Note however, that
// until ShutDown returns, StreamCreated may still be called. This will be
@@ -56,6 +72,17 @@ PP_Bool PPB_Audio_Impl::StartPlayback() {
return PP_FALSE;
if (playing())
return PP_TRUE;
+
+ // If plugin is in power saver mode, defer audio IPC communication.
+ PepperPluginInstanceImpl* instance = static_cast<PepperPluginInstanceImpl*>(
+ PepperPluginInstance::Get(pp_instance()));
+ if (instance && instance->throttler() &&
+ instance->throttler()->power_saver_enabled()) {
+ instance->throttler()->NotifyAudioThrottled();
+ playback_throttled_ = true;
+ return PP_TRUE;
+ }
+
SetStartPlaybackState();
return PP_FromBool(audio_->StartPlayback());
}
@@ -63,11 +90,19 @@ PP_Bool PPB_Audio_Impl::StartPlayback() {
PP_Bool PPB_Audio_Impl::StopPlayback() {
if (!audio_)
return PP_FALSE;
+
+ if (playback_throttled_) {
+ // If a start playback request is still deferred, we must fulfill it first
+ // to shut down the audio thread correctly.
+ StartDeferredPlayback();
+ }
+
if (!playing())
return PP_TRUE;
if (!audio_->StopPlayback())
return PP_FALSE;
SetStopPlaybackState();
+
return PP_TRUE;
}
@@ -89,7 +124,6 @@ int32_t PPB_Audio_Impl::Open(PP_Resource config,
audio_ = PepperPlatformAudioOutput::Create(
static_cast<int>(enter.object()->GetSampleRate()),
static_cast<int>(enter.object()->GetSampleFrameCount()),
- instance->GetRenderView()->GetRoutingID(),
instance->render_frame()->GetRoutingID(),
this);
if (!audio_)
@@ -124,4 +158,22 @@ void PPB_Audio_Impl::OnSetStreamInfo(
enter.object()->GetSampleFrameCount());
}
+void PPB_Audio_Impl::OnThrottleStateChange() {
+ PepperPluginInstanceImpl* instance = static_cast<PepperPluginInstanceImpl*>(
+ PepperPluginInstance::Get(pp_instance()));
+ if (playback_throttled_ && instance && instance->throttler() &&
+ !instance->throttler()->power_saver_enabled()) {
+ // If we have become unthrottled, and we have a pending playback, start it.
+ StartDeferredPlayback();
+ }
+}
+
+void PPB_Audio_Impl::StartDeferredPlayback() {
+ DCHECK(playback_throttled_);
+ playback_throttled_ = false;
+
+ SetStartPlaybackState();
+ audio_->StartPlayback();
+}
+
} // namespace content
diff --git a/chromium/content/renderer/pepper/ppb_audio_impl.h b/chromium/content/renderer/pepper/ppb_audio_impl.h
index 3348527028e..6c0af8f90fb 100644
--- a/chromium/content/renderer/pepper/ppb_audio_impl.h
+++ b/chromium/content/renderer/pepper/ppb_audio_impl.h
@@ -9,6 +9,7 @@
#include "base/memory/ref_counted.h"
#include "base/memory/shared_memory.h"
#include "base/sync_socket.h"
+#include "content/public/renderer/plugin_instance_throttler.h"
#include "content/renderer/pepper/audio_helper.h"
#include "ppapi/c/pp_completion_callback.h"
#include "ppapi/c/ppb_audio.h"
@@ -28,7 +29,8 @@ class PepperPlatformAudioOutput;
// to look more like typical HostResource implementations.
class PPB_Audio_Impl : public ppapi::Resource,
public ppapi::PPB_Audio_Shared,
- public AudioHelper {
+ public AudioHelper,
+ public PluginInstanceThrottler::Observer {
public:
explicit PPB_Audio_Impl(PP_Instance instance);
@@ -52,6 +54,12 @@ class PPB_Audio_Impl : public ppapi::Resource,
size_t shared_memory_size_,
base::SyncSocket::Handle socket) override;
+ // PluginInstanceThrottler::Observer implementation.
+ void OnThrottleStateChange() override;
+
+ // Starts the deferred playback and unsubscribes from the throttler.
+ void StartDeferredPlayback();
+
// AudioConfig used for creating this Audio object. We own a ref.
ppapi::ScopedPPResource config_;
@@ -59,6 +67,9 @@ class PPB_Audio_Impl : public ppapi::Resource,
// own this pointer but are responsible for calling Shutdown on it.
PepperPlatformAudioOutput* audio_;
+ // Stream is playing, but throttled due to Plugin Power Saver.
+ bool playback_throttled_;
+
DISALLOW_COPY_AND_ASSIGN(PPB_Audio_Impl);
};
diff --git a/chromium/content/renderer/pepper/ppb_broker_impl.cc b/chromium/content/renderer/pepper/ppb_broker_impl.cc
index 33181a25d6d..ead54a0717f 100644
--- a/chromium/content/renderer/pepper/ppb_broker_impl.cc
+++ b/chromium/content/renderer/pepper/ppb_broker_impl.cc
@@ -32,7 +32,7 @@ PPB_Broker_Impl::PPB_Broker_Impl(PP_Instance instance)
connect_callback_(),
pipe_handle_(PlatformFileToInt(base::SyncSocket::kInvalidHandle)),
routing_id_(RenderThreadImpl::current()->GenerateRoutingID()) {
- ChildThread::current()->GetRouter()->AddRoute(routing_id_, this);
+ ChildThreadImpl::current()->GetRouter()->AddRoute(routing_id_, this);
}
PPB_Broker_Impl::~PPB_Broker_Impl() {
@@ -43,7 +43,7 @@ PPB_Broker_Impl::~PPB_Broker_Impl() {
// The plugin owns the handle.
pipe_handle_ = PlatformFileToInt(base::SyncSocket::kInvalidHandle);
- ChildThread::current()->GetRouter()->RemoveRoute(routing_id_);
+ ChildThreadImpl::current()->GetRouter()->RemoveRoute(routing_id_);
}
PPB_Broker_API* PPB_Broker_Impl::AsPPB_Broker_API() { return this; }
diff --git a/chromium/content/renderer/pepper/ppb_broker_impl.h b/chromium/content/renderer/pepper/ppb_broker_impl.h
index 0f7485535d5..b43d3a6a371 100644
--- a/chromium/content/renderer/pepper/ppb_broker_impl.h
+++ b/chromium/content/renderer/pepper/ppb_broker_impl.h
@@ -40,7 +40,7 @@ class PPB_Broker_Impl : public ppapi::Resource,
scoped_refptr<ppapi::TrackedCallback> connect_callback) override;
int32_t GetHandle(int32_t* handle) override;
- // Returns the URL of the document this plug-in runs in. This is necessary to
+ // Returns the URL of the document this plugin runs in. This is necessary to
// decide whether to grant access to the PPAPI broker.
GURL GetDocumentUrl();
diff --git a/chromium/content/renderer/pepper/ppb_buffer_impl.cc b/chromium/content/renderer/pepper/ppb_buffer_impl.cc
index 4ad4b2824d9..a818fce5530 100644
--- a/chromium/content/renderer/pepper/ppb_buffer_impl.cc
+++ b/chromium/content/renderer/pepper/ppb_buffer_impl.cc
@@ -8,6 +8,7 @@
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
+#include "content/common/pepper_file_util.h"
#include "content/renderer/render_thread_impl.h"
#include "ppapi/c/dev/ppb_buffer_dev.h"
#include "ppapi/c/pp_bool.h"
@@ -78,13 +79,8 @@ void PPB_Buffer_Impl::Unmap() {
}
int32_t PPB_Buffer_Impl::GetSharedMemory(int* shm_handle) {
-#if defined(OS_POSIX)
- *shm_handle = shared_memory_->handle().fd;
-#elif defined(OS_WIN)
- *shm_handle = reinterpret_cast<int>(shared_memory_->handle());
-#else
-#error "Platform not supported."
-#endif
+ *shm_handle = reinterpret_cast<int>(PlatformFileFromSharedMemoryHandle(
+ shared_memory_->handle()));
return PP_OK;
}
diff --git a/chromium/content/renderer/pepper/ppb_graphics_3d_impl.cc b/chromium/content/renderer/pepper/ppb_graphics_3d_impl.cc
index 12d1db923a1..2de5e1092e0 100644
--- a/chromium/content/renderer/pepper/ppb_graphics_3d_impl.cc
+++ b/chromium/content/renderer/pepper/ppb_graphics_3d_impl.cc
@@ -14,6 +14,7 @@
#include "content/public/common/web_preferences.h"
#include "content/renderer/pepper/host_globals.h"
#include "content/renderer/pepper/pepper_plugin_instance_impl.h"
+#include "content/renderer/pepper/plugin_instance_throttler_impl.h"
#include "content/renderer/pepper/plugin_module.h"
#include "content/renderer/render_thread_impl.h"
#include "content/renderer/render_view_impl.h"
@@ -37,10 +38,11 @@ using blink::WebString;
namespace content {
namespace {
+
const int32 kCommandBufferSize = 1024 * 1024;
const int32 kTransferBufferSize = 1024 * 1024;
-} // namespace.
+} // namespace
PPB_Graphics3D_Impl::PPB_Graphics3D_Impl(PP_Instance instance)
: PPB_Graphics3D_Shared(instance),
@@ -163,8 +165,6 @@ void PPB_Graphics3D_Impl::ViewInitiatedPaint() {
SwapBuffersACK(PP_OK);
}
-void PPB_Graphics3D_Impl::ViewFlushedPaint() {}
-
int PPB_Graphics3D_Impl::GetCommandBufferRouteId() {
DCHECK(command_buffer_);
return command_buffer_->GetRouteID();
@@ -242,6 +242,11 @@ bool PPB_Graphics3D_Impl::InitRaw(
if (!prefs.pepper_3d_enabled)
return false;
+ // Force SW rendering for keyframe extraction to avoid pixel reads from VRAM.
+ PluginInstanceThrottlerImpl* throttler = plugin_instance->throttler();
+ if (throttler && throttler->needs_representative_keyframe())
+ return false;
+
RenderThreadImpl* render_thread = RenderThreadImpl::current();
if (!render_thread)
return false;
@@ -307,7 +312,7 @@ bool PPB_Graphics3D_Impl::InitRaw(
return false;
sync_point_ = command_buffer_->InsertSyncPoint();
- command_buffer_->SetChannelErrorCallback(base::Bind(
+ command_buffer_->SetContextLostCallback(base::Bind(
&PPB_Graphics3D_Impl::OnContextLost, weak_ptr_factory_.GetWeakPtr()));
command_buffer_->SetOnConsoleMessageCallback(base::Bind(
diff --git a/chromium/content/renderer/pepper/ppb_graphics_3d_impl.h b/chromium/content/renderer/pepper/ppb_graphics_3d_impl.h
index 5fcd1638a7b..729971275ac 100644
--- a/chromium/content/renderer/pepper/ppb_graphics_3d_impl.h
+++ b/chromium/content/renderer/pepper/ppb_graphics_3d_impl.h
@@ -55,7 +55,6 @@ class PPB_Graphics3D_Impl : public ppapi::PPB_Graphics3D_Shared {
// Notifications about the view's progress painting. See PluginInstance.
// These messages are used to send Flush callbacks to the plugin.
void ViewInitiatedPaint();
- void ViewFlushedPaint();
void GetBackingMailbox(gpu::Mailbox* mailbox, uint32* sync_point) {
*mailbox = mailbox_;
diff --git a/chromium/content/renderer/pepper/ppb_image_data_impl.cc b/chromium/content/renderer/pepper/ppb_image_data_impl.cc
index 28f23c99c71..cac25c301dd 100644
--- a/chromium/content/renderer/pepper/ppb_image_data_impl.cc
+++ b/chromium/content/renderer/pepper/ppb_image_data_impl.cc
@@ -9,6 +9,7 @@
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
+#include "content/common/pepper_file_util.h"
#include "content/common/view_messages.h"
#include "content/renderer/render_thread_impl.h"
#include "ppapi/c/pp_errors.h"
@@ -24,19 +25,6 @@ using ppapi::thunk::PPB_ImageData_API;
namespace content {
-namespace {
-// Returns true if the ImageData shared memory should be allocated in the
-// browser process for the current platform.
-bool IsBrowserAllocated() {
-#if defined(OS_POSIX) && !defined(OS_ANDROID)
- // On the Mac, shared memory has to be created in the browser in order to
- // work in the sandbox.
- return true;
-#endif
- return false;
-}
-} // namespace
-
PPB_ImageData_Impl::PPB_ImageData_Impl(PP_Instance instance,
PPB_ImageData_Shared::ImageDataType type)
: Resource(ppapi::OBJECT_IS_IMPL, instance),
@@ -45,7 +33,7 @@ PPB_ImageData_Impl::PPB_ImageData_Impl(PP_Instance instance,
height_(0) {
switch (type) {
case PPB_ImageData_Shared::PLATFORM:
- backend_.reset(new ImageDataPlatformBackend(IsBrowserAllocated()));
+ backend_.reset(new ImageDataPlatformBackend());
return;
case PPB_ImageData_Shared::SIMPLE:
backend_.reset(new ImageDataSimpleBackend);
@@ -60,7 +48,7 @@ PPB_ImageData_Impl::PPB_ImageData_Impl(PP_Instance instance, ForTest)
format_(PP_IMAGEDATAFORMAT_BGRA_PREMUL),
width_(0),
height_(0) {
- backend_.reset(new ImageDataPlatformBackend(false));
+ backend_.reset(new ImageDataPlatformBackend());
}
PPB_ImageData_Impl::~PPB_ImageData_Impl() {}
@@ -137,19 +125,10 @@ const SkBitmap* PPB_ImageData_Impl::GetMappedBitmap() const {
// ImageDataPlatformBackend ----------------------------------------------------
-ImageDataPlatformBackend::ImageDataPlatformBackend(bool is_browser_allocated)
- : width_(0), height_(0), is_browser_allocated_(is_browser_allocated) {}
+ImageDataPlatformBackend::ImageDataPlatformBackend() : width_(0), height_(0) {
+}
-// On POSIX, we have to tell the browser to free the transport DIB.
ImageDataPlatformBackend::~ImageDataPlatformBackend() {
- if (is_browser_allocated_) {
-#if defined(OS_POSIX)
- if (dib_) {
- RenderThreadImpl::current()->Send(
- new ViewHostMsg_FreeTransportDIB(dib_->id()));
- }
-#endif
- }
}
bool ImageDataPlatformBackend::Init(PPB_ImageData_Impl* impl,
@@ -161,35 +140,20 @@ bool ImageDataPlatformBackend::Init(PPB_ImageData_Impl* impl,
width_ = width;
height_ = height;
uint32 buffer_size = width_ * height_ * 4;
+ scoped_ptr<base::SharedMemory> shared_memory =
+ RenderThread::Get()->HostAllocateSharedMemoryBuffer(buffer_size);
+ if (!shared_memory)
+ return false;
- // Allocate the transport DIB and the PlatformCanvas pointing to it.
- TransportDIB* dib = NULL;
- if (is_browser_allocated_) {
-#if defined(OS_POSIX)
- // Allocate the image data by sending a message to the browser requesting a
- // TransportDIB (see also chrome/renderer/webplugin_delegate_proxy.cc,
- // method WebPluginDelegateProxy::CreateBitmap() for similar code). The
- // TransportDIB is cached in the browser, and is freed (in typical cases) by
- // the TransportDIB's destructor.
- TransportDIB::Handle dib_handle;
- IPC::Message* msg =
- new ViewHostMsg_AllocTransportDIB(buffer_size, true, &dib_handle);
- if (!RenderThreadImpl::current()->Send(msg))
- return false;
- if (!TransportDIB::is_valid_handle(dib_handle))
- return false;
-
- dib = TransportDIB::CreateWithHandle(dib_handle);
-#endif
- } else {
- static int next_dib_id = 0;
- dib = TransportDIB::Create(buffer_size, next_dib_id++);
- if (!dib)
- return false;
- }
- DCHECK(dib);
- dib_.reset(dib);
- return true;
+ // The TransportDIB is always backed by shared memory, so give the shared
+ // memory handle to it.
+ base::SharedMemoryHandle handle;
+ if (!shared_memory->GiveToProcess(base::GetCurrentProcessHandle(), &handle))
+ return false;
+
+ dib_.reset(TransportDIB::CreateWithHandle(handle));
+
+ return !!dib_;
}
bool ImageDataPlatformBackend::IsMapped() const {
@@ -226,12 +190,8 @@ void ImageDataPlatformBackend::Unmap() {
int32_t ImageDataPlatformBackend::GetSharedMemory(int* handle,
uint32_t* byte_count) {
*byte_count = dib_->size();
-#if defined(OS_WIN)
- *handle = reinterpret_cast<intptr_t>(dib_->handle());
-#else
- *handle = static_cast<intptr_t>(dib_->handle().fd);
-#endif
-
+ *handle = reinterpret_cast<int>(PlatformFileFromSharedMemoryHandle(
+ dib_->handle()));
return PP_OK;
}
@@ -292,13 +252,8 @@ void ImageDataSimpleBackend::Unmap() {
int32_t ImageDataSimpleBackend::GetSharedMemory(int* handle,
uint32_t* byte_count) {
*byte_count = skia_bitmap_.getSize();
-#if defined(OS_POSIX)
- *handle = shared_memory_->handle().fd;
-#elif defined(OS_WIN)
- *handle = reinterpret_cast<int>(shared_memory_->handle());
-#else
-#error "Platform not supported."
-#endif
+ *handle = reinterpret_cast<int>(PlatformFileFromSharedMemoryHandle(
+ shared_memory_->handle()));
return PP_OK;
}
diff --git a/chromium/content/renderer/pepper/ppb_image_data_impl.h b/chromium/content/renderer/pepper/ppb_image_data_impl.h
index 61f2b70276d..d31e7b1d12c 100644
--- a/chromium/content/renderer/pepper/ppb_image_data_impl.h
+++ b/chromium/content/renderer/pepper/ppb_image_data_impl.h
@@ -112,7 +112,7 @@ class ImageDataPlatformBackend : public PPB_ImageData_Impl::Backend {
public:
// |is_browser_allocated| indicates whether the backing shared memory should
// be allocated by the browser process.
- ImageDataPlatformBackend(bool is_browser_allocated);
+ ImageDataPlatformBackend();
~ImageDataPlatformBackend() override;
// PPB_ImageData_Impl::Backend implementation.
@@ -137,8 +137,6 @@ class ImageDataPlatformBackend : public PPB_ImageData_Impl::Backend {
int height_;
scoped_ptr<TransportDIB> dib_;
- bool is_browser_allocated_;
-
// When the device is mapped, this is the image. Null when umapped.
scoped_ptr<SkCanvas> mapped_canvas_;
diff --git a/chromium/content/renderer/pepper/ppb_scrollbar_impl.h b/chromium/content/renderer/pepper/ppb_scrollbar_impl.h
index 3c94ad8e86e..91dec8ed754 100644
--- a/chromium/content/renderer/pepper/ppb_scrollbar_impl.h
+++ b/chromium/content/renderer/pepper/ppb_scrollbar_impl.h
@@ -14,7 +14,7 @@
#include "ppapi/thunk/ppb_scrollbar_api.h"
#include "third_party/WebKit/public/platform/WebRect.h"
#include "third_party/WebKit/public/web/WebPluginScrollbarClient.h"
-#include "ui/gfx/rect.h"
+#include "ui/gfx/geometry/rect.h"
namespace content {
diff --git a/chromium/content/renderer/pepper/ppb_var_deprecated_impl.cc b/chromium/content/renderer/pepper/ppb_var_deprecated_impl.cc
index c5a93e2f389..4188ee6e3d4 100644
--- a/chromium/content/renderer/pepper/ppb_var_deprecated_impl.cc
+++ b/chromium/content/renderer/pepper/ppb_var_deprecated_impl.cc
@@ -63,7 +63,7 @@ class ObjectAccessor {
}
// Lazily grab the object so that the handle is created in the current handle
// scope.
- v8::Handle<v8::Object> GetObject() { return object_var_->GetHandle(); }
+ v8::Local<v8::Object> GetObject() { return object_var_->GetHandle(); }
PepperPluginInstanceImpl* instance() { return instance_; }
V8VarConverter* converter() { return converter_.get(); }
@@ -90,7 +90,7 @@ bool HasPropertyDeprecated(PP_Var var, PP_Var name, PP_Var* exception) {
PepperTryCatchVar try_catch(accessor.instance(), accessor.converter(),
exception);
- v8::Handle<v8::Value> v8_name = try_catch.ToV8(name);
+ v8::Local<v8::Value> v8_name = try_catch.ToV8(name);
if (try_catch.HasException())
return false;
@@ -107,7 +107,7 @@ bool HasMethodDeprecated(PP_Var var, PP_Var name, PP_Var* exception) {
PepperTryCatchVar try_catch(accessor.instance(), accessor.converter(),
exception);
- v8::Handle<v8::Value> v8_name = try_catch.ToV8(name);
+ v8::Local<v8::Value> v8_name = try_catch.ToV8(name);
if (try_catch.HasException())
return false;
@@ -125,7 +125,7 @@ PP_Var GetProperty(PP_Var var, PP_Var name, PP_Var* exception) {
PepperTryCatchVar try_catch(accessor.instance(), accessor.converter(),
exception);
- v8::Handle<v8::Value> v8_name = try_catch.ToV8(name);
+ v8::Local<v8::Value> v8_name = try_catch.ToV8(name);
if (try_catch.HasException())
return PP_MakeUndefined();
@@ -177,8 +177,8 @@ void SetPropertyDeprecated(PP_Var var,
PepperTryCatchVar try_catch(accessor.instance(), accessor.converter(),
exception);
- v8::Handle<v8::Value> v8_name = try_catch.ToV8(name);
- v8::Handle<v8::Value> v8_value = try_catch.ToV8(value);
+ v8::Local<v8::Value> v8_name = try_catch.ToV8(name);
+ v8::Local<v8::Value> v8_value = try_catch.ToV8(value);
if (try_catch.HasException())
return;
@@ -194,7 +194,7 @@ void DeletePropertyDeprecated(PP_Var var, PP_Var name, PP_Var* exception) {
PepperTryCatchVar try_catch(accessor.instance(), accessor.converter(),
exception);
- v8::Handle<v8::Value> v8_name = try_catch.ToV8(name);
+ v8::Local<v8::Value> v8_name = try_catch.ToV8(name);
if (try_catch.HasException())
return;
@@ -222,7 +222,7 @@ PP_Var CallDeprecatedInternal(PP_Var var,
PepperTryCatchVar try_catch(accessor.instance(), accessor.converter(),
exception);
- v8::Handle<v8::Value> v8_method_name = try_catch.ToV8(scoped_name.get());
+ v8::Local<v8::Value> v8_method_name = try_catch.ToV8(scoped_name.get());
if (try_catch.HasException())
return PP_MakeUndefined();
@@ -231,11 +231,12 @@ PP_Var CallDeprecatedInternal(PP_Var var,
return PP_MakeUndefined();
}
- v8::Handle<v8::Object> function = accessor.GetObject();
- v8::Handle<v8::Object> recv =
+ v8::Local<v8::Object> function = accessor.GetObject();
+ v8::Local<v8::Object> recv =
accessor.instance()->GetMainWorldContext()->Global();
if (v8_method_name.As<v8::String>()->Length() != 0) {
- function = function->Get(v8_method_name)->ToObject();
+ function = function->Get(v8_method_name)
+ ->ToObject(accessor.instance()->GetIsolate());
recv = accessor.GetObject();
}
@@ -247,8 +248,8 @@ PP_Var CallDeprecatedInternal(PP_Var var,
return PP_MakeUndefined();
}
- scoped_ptr<v8::Handle<v8::Value>[] > converted_args(
- new v8::Handle<v8::Value>[argc]);
+ scoped_ptr<v8::Local<v8::Value>[] > converted_args(
+ new v8::Local<v8::Value>[argc]);
for (uint32_t i = 0; i < argc; ++i) {
converted_args[i] = try_catch.ToV8(argv[i]);
if (try_catch.HasException())
@@ -265,7 +266,7 @@ PP_Var CallDeprecatedInternal(PP_Var var,
return PP_MakeUndefined();
}
- v8::Handle<v8::Value> result = frame->callFunctionEvenIfScriptDisabled(
+ v8::Local<v8::Value> result = frame->callFunctionEvenIfScriptDisabled(
function.As<v8::Function>(), recv, argc, converted_args.get());
ScopedPPVar result_var = try_catch.FromV8(result);
@@ -303,7 +304,7 @@ bool IsInstanceOfDeprecated(PP_Var var,
return false; // Not an object at all.
v8::HandleScope handle_scope(object->instance()->GetIsolate());
- v8::Handle<v8::Context> context = object->instance()->GetMainWorldContext();
+ v8::Local<v8::Context> context = object->instance()->GetMainWorldContext();
if (context.IsEmpty())
return false;
v8::Context::Scope context_scope(context);
diff --git a/chromium/content/renderer/pepper/ppb_video_decoder_impl.cc b/chromium/content/renderer/pepper/ppb_video_decoder_impl.cc
index 53b2ef96b91..ca052ea8b56 100644
--- a/chromium/content/renderer/pepper/ppb_video_decoder_impl.cc
+++ b/chromium/content/renderer/pepper/ppb_video_decoder_impl.cc
@@ -95,12 +95,6 @@ namespace content {
PPB_VideoDecoder_Impl::PPB_VideoDecoder_Impl(PP_Instance instance)
: PPB_VideoDecoder_Shared(instance), ppp_videodecoder_(NULL) {
- PluginModule* plugin_module =
- HostGlobals::Get()->GetInstance(pp_instance())->module();
- if (plugin_module) {
- ppp_videodecoder_ = static_cast<const PPP_VideoDecoder_Dev*>(
- plugin_module->GetPluginInterface(PPP_VIDEODECODER_DEV_INTERFACE));
- }
}
PPB_VideoDecoder_Impl::~PPB_VideoDecoder_Impl() { Destroy(); }
@@ -140,6 +134,18 @@ bool PPB_VideoDecoder_Impl::Init(PP_Resource graphics_context,
return (decoder_ && decoder_->Initialize(PPToMediaProfile(profile), this));
}
+const PPP_VideoDecoder_Dev* PPB_VideoDecoder_Impl::GetPPP() {
+ if (!ppp_videodecoder_) {
+ PluginModule* plugin_module =
+ HostGlobals::Get()->GetInstance(pp_instance())->module();
+ if (plugin_module) {
+ ppp_videodecoder_ = static_cast<const PPP_VideoDecoder_Dev*>(
+ plugin_module->GetPluginInterface(PPP_VIDEODECODER_DEV_INTERFACE));
+ }
+ }
+ return ppp_videodecoder_;
+}
+
int32_t PPB_VideoDecoder_Impl::Decode(
const PP_VideoBitstreamBuffer_Dev* bitstream_buffer,
scoped_refptr<TrackedCallback> callback) {
@@ -234,46 +240,44 @@ void PPB_VideoDecoder_Impl::ProvidePictureBuffers(
const gfx::Size& dimensions,
uint32 texture_target) {
DCHECK(RenderThreadImpl::current());
- if (!ppp_videodecoder_)
+ if (!GetPPP())
return;
PP_Size out_dim = PP_MakeSize(dimensions.width(), dimensions.height());
- ppp_videodecoder_->ProvidePictureBuffers(pp_instance(),
- pp_resource(),
- requested_num_of_buffers,
- &out_dim,
- texture_target);
+ GetPPP()->ProvidePictureBuffers(pp_instance(), pp_resource(),
+ requested_num_of_buffers, &out_dim,
+ texture_target);
}
void PPB_VideoDecoder_Impl::PictureReady(const media::Picture& picture) {
// So far picture.visible_rect is not used. If used, visible_rect should
// be validated since it comes from GPU process and may not be trustworthy.
DCHECK(RenderThreadImpl::current());
- if (!ppp_videodecoder_)
+ if (!GetPPP())
return;
PP_Picture_Dev output;
output.picture_buffer_id = picture.picture_buffer_id();
output.bitstream_buffer_id = picture.bitstream_buffer_id();
- ppp_videodecoder_->PictureReady(pp_instance(), pp_resource(), &output);
+ GetPPP()->PictureReady(pp_instance(), pp_resource(), &output);
}
void PPB_VideoDecoder_Impl::DismissPictureBuffer(int32 picture_buffer_id) {
DCHECK(RenderThreadImpl::current());
- if (!ppp_videodecoder_)
+ if (!GetPPP())
return;
- ppp_videodecoder_->DismissPictureBuffer(
- pp_instance(), pp_resource(), picture_buffer_id);
+ GetPPP()->DismissPictureBuffer(pp_instance(), pp_resource(),
+ picture_buffer_id);
}
void PPB_VideoDecoder_Impl::NotifyError(
media::VideoDecodeAccelerator::Error error) {
DCHECK(RenderThreadImpl::current());
- if (!ppp_videodecoder_)
+ if (!GetPPP())
return;
PP_VideoDecodeError_Dev pp_error = MediaToPPError(error);
- ppp_videodecoder_->NotifyError(pp_instance(), pp_resource(), pp_error);
+ GetPPP()->NotifyError(pp_instance(), pp_resource(), pp_error);
UMA_HISTOGRAM_ENUMERATION("Media.PepperVideoDecoderError",
error,
media::VideoDecodeAccelerator::LARGEST_ERROR_ENUM);
diff --git a/chromium/content/renderer/pepper/ppb_video_decoder_impl.h b/chromium/content/renderer/pepper/ppb_video_decoder_impl.h
index e3037b9eb5a..094bcff7b43 100644
--- a/chromium/content/renderer/pepper/ppb_video_decoder_impl.h
+++ b/chromium/content/renderer/pepper/ppb_video_decoder_impl.h
@@ -58,12 +58,19 @@ class PPB_VideoDecoder_Impl : public ppapi::PPB_VideoDecoder_Shared,
explicit PPB_VideoDecoder_Impl(PP_Instance instance);
bool Init(PP_Resource graphics_context,
PP_VideoDecoder_Profile profile);
+ // Returns the associated PPP_VideoDecoder_Dev interface to use when
+ // making calls on the plugin. This fetches the interface lazily. For
+ // out-of-process plugins, this means a synchronous message to the plugin,
+ // so it's important to never call this in response to a synchronous
+ // plugin->renderer message (such as the Create message).
+ const PPP_VideoDecoder_Dev* GetPPP();
// This is NULL before initialization, and after destruction.
// Holds a GpuVideoDecodeAcceleratorHost.
scoped_ptr<media::VideoDecodeAccelerator> decoder_;
- // Reference to the plugin requesting this interface.
+ // The interface to use when making calls on the plugin. For the most part,
+ // methods should not use this directly but should call GetPPP() instead.
const PPP_VideoDecoder_Dev* ppp_videodecoder_;
DISALLOW_COPY_AND_ASSIGN(PPB_VideoDecoder_Impl);
diff --git a/chromium/content/renderer/pepper/renderer_ppapi_host_impl.cc b/chromium/content/renderer/pepper/renderer_ppapi_host_impl.cc
index b6e6e9e7e46..61c1ba66f00 100644
--- a/chromium/content/renderer/pepper/renderer_ppapi_host_impl.cc
+++ b/chromium/content/renderer/pepper/renderer_ppapi_host_impl.cc
@@ -27,7 +27,7 @@
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebElement.h"
#include "third_party/WebKit/public/web/WebPluginContainer.h"
-#include "ui/gfx/point.h"
+#include "ui/gfx/geometry/point.h"
namespace content {
// static
@@ -258,12 +258,11 @@ void RendererPpapiHostImpl::CreateBrowserResourceHosts(
}
}
-GURL RendererPpapiHostImpl::GetDocumentURL(PP_Instance instance) const {
- PepperPluginInstanceImpl* instance_object = GetAndValidateInstance(instance);
- if (!instance_object)
+GURL RendererPpapiHostImpl::GetDocumentURL(PP_Instance pp_instance) const {
+ PepperPluginInstanceImpl* instance = GetAndValidateInstance(pp_instance);
+ if (!instance)
return GURL();
-
- return instance_object->container()->element().document().url();
+ return instance->document_url();
}
PepperPluginInstanceImpl* RendererPpapiHostImpl::GetAndValidateInstance(
diff --git a/chromium/content/renderer/pepper/renderer_ppapi_host_impl.h b/chromium/content/renderer/pepper/renderer_ppapi_host_impl.h
index f8f7aac5402..b2e329c7c7d 100644
--- a/chromium/content/renderer/pepper/renderer_ppapi_host_impl.h
+++ b/chromium/content/renderer/pepper/renderer_ppapi_host_impl.h
@@ -99,7 +99,7 @@ class RendererPpapiHostImpl : public RendererPpapiHost {
const std::vector<IPC::Message>& nested_msgs,
const base::Callback<void(const std::vector<int>&)>& callback)
const override;
- GURL GetDocumentURL(PP_Instance instance) const override;
+ GURL GetDocumentURL(PP_Instance pp_instance) const override;
private:
RendererPpapiHostImpl(PluginModule* module,
diff --git a/chromium/content/renderer/pepper/renderer_restrict_dispatch_group.h b/chromium/content/renderer/pepper/renderer_restrict_dispatch_group.h
index 6cdb44be80b..27fe85c15c6 100644
--- a/chromium/content/renderer/pepper/renderer_restrict_dispatch_group.h
+++ b/chromium/content/renderer/pepper/renderer_restrict_dispatch_group.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_RENDERER_PEPPER_RESTRICT_DISPATCH_GROUP_H_
-#define CONTENT_RENDERER_PEPPER_RESTRICT_DISPATCH_GROUP_H_
+#ifndef CONTENT_RENDERER_PEPPER_RENDERER_RESTRICT_DISPATCH_GROUP_H_
+#define CONTENT_RENDERER_PEPPER_RENDERER_RESTRICT_DISPATCH_GROUP_H_
#include "ipc/ipc_sync_channel.h"
@@ -21,4 +21,4 @@ enum RendererRestrictDispatchGroup {
} // namespace content
-#endif // CONTENT_RENDERER_PEPPER_RESTRICT_DISPATCH_GROUP_H_
+#endif // CONTENT_RENDERER_PEPPER_RENDERER_RESTRICT_DISPATCH_GROUP_H_
diff --git a/chromium/content/renderer/pepper/resource_converter.cc b/chromium/content/renderer/pepper/resource_converter.cc
index 2af3bba3e77..c4d4cf047e7 100644
--- a/chromium/content/renderer/pepper/resource_converter.cc
+++ b/chromium/content/renderer/pepper/resource_converter.cc
@@ -122,8 +122,8 @@ bool DOMFileSystemToResource(
bool ResourceHostToDOMFileSystem(
content::PepperFileSystemHost* file_system_host,
- v8::Handle<v8::Context> context,
- v8::Handle<v8::Value>* dom_file_system) {
+ v8::Local<v8::Context> context,
+ v8::Local<v8::Value>* dom_file_system) {
GURL root_url = file_system_host->GetRootUrl();
GURL origin;
storage::FileSystemType type;
@@ -148,8 +148,8 @@ bool ResourceHostToDOMFileSystem(
bool ResourceHostToDOMMediaStreamVideoTrack(
content::PepperMediaStreamVideoTrackHost* host,
- v8::Handle<v8::Context> context,
- v8::Handle<v8::Value>* dom_video_track) {
+ v8::Local<v8::Context> context,
+ v8::Local<v8::Value>* dom_video_track) {
// TODO(ronghuawu): Implement this once crbug/352219 is resolved.
// blink::WebMediaStreamTrack track = host->track();
// *dom_video_track = track.toV8Value();
@@ -206,8 +206,8 @@ ResourceConverterImpl::~ResourceConverterImpl() {
DCHECK(browser_vars_.empty());
}
-bool ResourceConverterImpl::FromV8Value(v8::Handle<v8::Object> val,
- v8::Handle<v8::Context> context,
+bool ResourceConverterImpl::FromV8Value(v8::Local<v8::Object> val,
+ v8::Local<v8::Context> context,
PP_Var* result,
bool* was_resource) {
v8::Context::Scope context_scope(context);
@@ -285,8 +285,8 @@ void ResourceConverterImpl::Flush(const base::Callback<void(bool)>& callback) {
}
bool ResourceConverterImpl::ToV8Value(const PP_Var& var,
- v8::Handle<v8::Context> context,
- v8::Handle<v8::Value>* result) {
+ v8::Local<v8::Context> context,
+ v8::Local<v8::Value>* result) {
DCHECK(var.type == PP_VARTYPE_RESOURCE);
ResourceVar* resource = ResourceVar::FromPPVar(var);
diff --git a/chromium/content/renderer/pepper/resource_converter.h b/chromium/content/renderer/pepper/resource_converter.h
index d669e7464b4..2c20d7ee0ef 100644
--- a/chromium/content/renderer/pepper/resource_converter.h
+++ b/chromium/content/renderer/pepper/resource_converter.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_RENDERER_PEPPER_RESOURCE_CONVERTER_H
-#define CONTENT_RENDERER_PEPPER_RESOURCE_CONVERTER_H
+#ifndef CONTENT_RENDERER_PEPPER_RESOURCE_CONVERTER_H_
+#define CONTENT_RENDERER_PEPPER_RESOURCE_CONVERTER_H_
#include <vector>
@@ -48,8 +48,8 @@ class CONTENT_EXPORT ResourceConverter {
// On success, writes the resulting var to |result|, sets |was_resource| to
// true and returns true. If |val| is not a resource, sets |was_resource| to
// false and returns true. If an error occurs, returns false.
- virtual bool FromV8Value(v8::Handle<v8::Object> val,
- v8::Handle<v8::Context> context,
+ virtual bool FromV8Value(v8::Local<v8::Object> val,
+ v8::Local<v8::Context> context,
PP_Var* result,
bool* was_resource) = 0;
@@ -57,8 +57,8 @@ class CONTENT_EXPORT ResourceConverter {
// PP_VARTYPE_RESOURCE. On success, writes the resulting value to |result| and
// returns true. If an error occurs, returns false.
virtual bool ToV8Value(const PP_Var& var,
- v8::Handle<v8::Context> context,
- v8::Handle<v8::Value>* result) = 0;
+ v8::Local<v8::Context> context,
+ v8::Local<v8::Value>* result) = 0;
};
class ResourceConverterImpl : public ResourceConverter {
@@ -70,13 +70,13 @@ class ResourceConverterImpl : public ResourceConverter {
void Reset() override;
bool NeedsFlush() override;
void Flush(const base::Callback<void(bool)>& callback) override;
- bool FromV8Value(v8::Handle<v8::Object> val,
- v8::Handle<v8::Context> context,
+ bool FromV8Value(v8::Local<v8::Object> val,
+ v8::Local<v8::Context> context,
PP_Var* result,
bool* was_resource) override;
bool ToV8Value(const PP_Var& var,
- v8::Handle<v8::Context> context,
- v8::Handle<v8::Value>* result) override;
+ v8::Local<v8::Context> context,
+ v8::Local<v8::Value>* result) override;
private:
// Creates a resource var with the given |pending_renderer_id| and
@@ -107,4 +107,4 @@ class ResourceConverterImpl : public ResourceConverter {
};
} // namespace content
-#endif // CONTENT_RENDERER_PEPPER_RESOURCE_CONVERTER_H
+#endif // CONTENT_RENDERER_PEPPER_RESOURCE_CONVERTER_H_
diff --git a/chromium/content/renderer/pepper/resource_creation_impl.cc b/chromium/content/renderer/pepper/resource_creation_impl.cc
index 4a693256ae0..425cad725ff 100644
--- a/chromium/content/renderer/pepper/resource_creation_impl.cc
+++ b/chromium/content/renderer/pepper/resource_creation_impl.cc
@@ -4,6 +4,7 @@
#include "content/renderer/pepper/resource_creation_impl.h"
+#include "content/common/content_switches_internal.h"
#include "content/renderer/pepper/ppb_audio_impl.h"
#include "content/renderer/pepper/ppb_broker_impl.h"
#include "content/renderer/pepper/ppb_buffer_impl.h"
@@ -24,7 +25,6 @@
#if defined(OS_WIN)
#include "base/command_line.h"
#include "base/win/windows_version.h"
-#include "content/public/common/content_switches.h"
#endif
using ppapi::InputEventData;
@@ -82,6 +82,11 @@ PP_Resource ResourceCreationImpl::CreateBuffer(PP_Instance instance,
return PPB_Buffer_Impl::Create(instance, size);
}
+PP_Resource ResourceCreationImpl::CreateCameraDevicePrivate(
+ PP_Instance instance) {
+ return 0; // Not supported in-process.
+}
+
PP_Resource ResourceCreationImpl::CreateFlashDRM(PP_Instance instance) {
return 0; // Not supported in-process.
}
@@ -140,11 +145,8 @@ PP_Resource ResourceCreationImpl::CreateImageData(PP_Instance instance,
// TODO(ananta)
// Look into whether this causes a loss of functionality. From cursory
// testing things seem to work well.
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableWin32kRendererLockDown) &&
- base::win::GetVersion() >= base::win::VERSION_WIN8) {
+ if (IsWin32kRendererLockdownEnabled())
return CreateImageDataSimple(instance, format, size, init_to_zero);
- }
#endif
return PPB_ImageData_Impl::Create(instance,
ppapi::PPB_ImageData_Shared::PLATFORM,
@@ -285,10 +287,6 @@ PP_Resource ResourceCreationImpl::CreateScrollbar(PP_Instance instance,
return PPB_Scrollbar_Impl::Create(instance, PP_ToBool(vertical));
}
-PP_Resource ResourceCreationImpl::CreateTalk(PP_Instance /* instance */) {
- return 0; // Not supported in-process.
-}
-
PP_Resource ResourceCreationImpl::CreateTCPServerSocketPrivate(
PP_Instance instance) {
return 0; // Not supported in-process.
@@ -341,6 +339,10 @@ PP_Resource ResourceCreationImpl::CreateVideoDestination(PP_Instance instance) {
return 0; // Not supported in-process.
}
+PP_Resource ResourceCreationImpl::CreateVideoEncoder(PP_Instance instance) {
+ return 0; // Not supported in-process.
+}
+
PP_Resource ResourceCreationImpl::CreateVideoSource(PP_Instance instance) {
return 0; // Not supported in-process.
}
diff --git a/chromium/content/renderer/pepper/resource_creation_impl.h b/chromium/content/renderer/pepper/resource_creation_impl.h
index 52c44fc06f1..35e701639de 100644
--- a/chromium/content/renderer/pepper/resource_creation_impl.h
+++ b/chromium/content/renderer/pepper/resource_creation_impl.h
@@ -39,6 +39,7 @@ class ResourceCreationImpl : public ppapi::thunk::ResourceCreationAPI {
PP_Resource CreateCompositor(PP_Instance instance) override;
PP_Resource CreateBroker(PP_Instance instance) override;
PP_Resource CreateBuffer(PP_Instance instance, uint32_t size) override;
+ PP_Resource CreateCameraDevicePrivate(PP_Instance instance) override;
PP_Resource CreateFlashDRM(PP_Instance instance) override;
PP_Resource CreateFlashFontFile(
PP_Instance instance,
@@ -110,7 +111,6 @@ class ResourceCreationImpl : public ppapi::thunk::ResourceCreationAPI {
PP_Resource CreatePlatformVerificationPrivate(PP_Instance instance) override;
PP_Resource CreateScrollbar(PP_Instance instance, PP_Bool vertical) override;
PP_Resource CreateOutputProtectionPrivate(PP_Instance instance) override;
- PP_Resource CreateTalk(PP_Instance instance) override;
PP_Resource CreateTCPServerSocketPrivate(PP_Instance instance) override;
PP_Resource CreateTCPSocket1_0(PP_Instance instance) override;
PP_Resource CreateTCPSocket(PP_Instance instance) override;
@@ -127,6 +127,7 @@ class ResourceCreationImpl : public ppapi::thunk::ResourceCreationAPI {
PP_Resource graphics3d_id,
PP_VideoDecoder_Profile profile) override;
PP_Resource CreateVideoDestination(PP_Instance instance) override;
+ PP_Resource CreateVideoEncoder(PP_Instance instance) override;
PP_Resource CreateVideoSource(PP_Instance instance) override;
PP_Resource CreateWheelInputEvent(PP_Instance instance,
PP_TimeTicks time_stamp,
diff --git a/chromium/content/renderer/pepper/url_request_info_util.h b/chromium/content/renderer/pepper/url_request_info_util.h
index aaafb234703..7eabfef58e1 100644
--- a/chromium/content/renderer/pepper/url_request_info_util.h
+++ b/chromium/content/renderer/pepper/url_request_info_util.h
@@ -35,4 +35,4 @@ CONTENT_EXPORT bool URLRequestRequiresUniversalAccess(
} // namespace content
-#endif // CONTENT_RENDERER_PEPPER_PPB_URL_REQUEST_INFO_UTIL_H_
+#endif // CONTENT_RENDERER_PEPPER_URL_REQUEST_INFO_UTIL_H_
diff --git a/chromium/content/renderer/pepper/usb_key_code_conversion.cc b/chromium/content/renderer/pepper/usb_key_code_conversion.cc
deleted file mode 100644
index 129e663a5ed..00000000000
--- a/chromium/content/renderer/pepper/usb_key_code_conversion.cc
+++ /dev/null
@@ -1,25 +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/renderer/pepper/usb_key_code_conversion.h"
-
-#include "build/build_config.h"
-
-using blink::WebKeyboardEvent;
-
-namespace content {
-
-#if !defined(OS_LINUX) && !defined(OS_MACOSX) && !defined(OS_WIN)
-
-uint32_t UsbKeyCodeForKeyboardEvent(const WebKeyboardEvent& key_event) {
- return 0;
-}
-
-const char* CodeForKeyboardEvent(const WebKeyboardEvent& key_event) {
- return NULL;
-}
-
-#endif
-
-} // namespace content
diff --git a/chromium/content/renderer/pepper/usb_key_code_conversion.h b/chromium/content/renderer/pepper/usb_key_code_conversion.h
deleted file mode 100644
index 9554c57222a..00000000000
--- a/chromium/content/renderer/pepper/usb_key_code_conversion.h
+++ /dev/null
@@ -1,29 +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_RENDERER_PEPPER_USB_KEY_CODE_CONVERSION_H_
-#define CONTENT_RENDERER_PEPPER_USB_KEY_CODE_CONVERSION_H_
-
-#include "ppapi/c/pp_stdint.h"
-
-namespace blink {
-class WebKeyboardEvent;
-} // namespace blink
-
-namespace content {
-
-// Returns a 32-bit "USB Key Code" for the key identifier by the supplied
-// WebKeyboardEvent. The supplied event must be a KeyDown or KeyUp.
-// The code consists of the USB Page (in the high-order 16-bit word) and
-// USB Usage Id of the key. If no translation can be performed then zero
-// is returned.
-uint32_t UsbKeyCodeForKeyboardEvent(const blink::WebKeyboardEvent& key_event);
-
-// Returns a string that represents the UI Event |code| parameter as specified
-// in http://www.w3.org/TR/uievents/
-const char* CodeForKeyboardEvent(const blink::WebKeyboardEvent& key_event);
-
-} // namespace content
-
-#endif // CONTENT_RENDERER_PEPPER_USB_KEY_CODE_CONVERSION_H_
diff --git a/chromium/content/renderer/pepper/usb_key_code_conversion_linux.cc b/chromium/content/renderer/pepper/usb_key_code_conversion_linux.cc
index 09ff82bb04a..9164e7bf3a1 100644
--- a/chromium/content/renderer/pepper/usb_key_code_conversion_linux.cc
+++ b/chromium/content/renderer/pepper/usb_key_code_conversion_linux.cc
@@ -6,7 +6,7 @@
#include "base/basictypes.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
-#include "ui/events/keycodes/dom4/keycode_converter.h"
+#include "ui/events/keycodes/dom/keycode_converter.h"
using blink::WebKeyboardEvent;
@@ -22,7 +22,8 @@ uint32_t UsbKeyCodeForKeyboardEvent(const WebKeyboardEvent& key_event) {
}
const char* CodeForKeyboardEvent(const WebKeyboardEvent& key_event) {
- return ui::KeycodeConverter::NativeKeycodeToCode(key_event.nativeKeyCode);
+ return ui::KeycodeConverter::DomCodeToCodeString(
+ ui::KeycodeConverter::NativeKeycodeToDomCode(key_event.nativeKeyCode));
}
} // namespace content
diff --git a/chromium/content/renderer/pepper/usb_key_code_conversion_mac.cc b/chromium/content/renderer/pepper/usb_key_code_conversion_mac.cc
index 784fdd0c602..15e16da1b4e 100644
--- a/chromium/content/renderer/pepper/usb_key_code_conversion_mac.cc
+++ b/chromium/content/renderer/pepper/usb_key_code_conversion_mac.cc
@@ -6,7 +6,7 @@
#include "base/basictypes.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
-#include "ui/events/keycodes/dom4/keycode_converter.h"
+#include "ui/events/keycodes/dom/keycode_converter.h"
using blink::WebKeyboardEvent;
@@ -18,7 +18,8 @@ uint32_t UsbKeyCodeForKeyboardEvent(const WebKeyboardEvent& key_event) {
}
const char* CodeForKeyboardEvent(const WebKeyboardEvent& key_event) {
- return ui::KeycodeConverter::NativeKeycodeToCode(key_event.nativeKeyCode);
+ return ui::KeycodeConverter::DomCodeToCodeString(
+ ui::KeycodeConverter::NativeKeycodeToDomCode(key_event.nativeKeyCode));
}
} // namespace content
diff --git a/chromium/content/renderer/pepper/usb_key_code_conversion_win.cc b/chromium/content/renderer/pepper/usb_key_code_conversion_win.cc
index 3dfa807c7b8..637a583bd9d 100644
--- a/chromium/content/renderer/pepper/usb_key_code_conversion_win.cc
+++ b/chromium/content/renderer/pepper/usb_key_code_conversion_win.cc
@@ -6,7 +6,7 @@
#include "base/basictypes.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
-#include "ui/events/keycodes/dom4/keycode_converter.h"
+#include "ui/events/keycodes/dom/keycode_converter.h"
using blink::WebKeyboardEvent;
@@ -27,7 +27,8 @@ const char* CodeForKeyboardEvent(const WebKeyboardEvent& key_event) {
if ((key_event.nativeKeyCode & (1 << 24)) != 0)
scancode |= 0xe000;
- return ui::KeycodeConverter::NativeKeycodeToCode(scancode);
+ return ui::KeycodeConverter::DomCodeToCodeString(
+ ui::KeycodeConverter::NativeKeycodeToDomCode(scancode));
}
} // namespace content
diff --git a/chromium/content/renderer/pepper/v8_var_converter.cc b/chromium/content/renderer/pepper/v8_var_converter.cc
index 42d744d2872..494219205f3 100644
--- a/chromium/content/renderer/pepper/v8_var_converter.cc
+++ b/chromium/content/renderer/pepper/v8_var_converter.cc
@@ -22,7 +22,7 @@
#include "ppapi/shared_impl/dictionary_var.h"
#include "ppapi/shared_impl/var.h"
#include "ppapi/shared_impl/var_tracker.h"
-#include "third_party/WebKit/public/platform/WebArrayBuffer.h"
+#include "third_party/WebKit/public/web/WebArrayBuffer.h"
#include "third_party/WebKit/public/web/WebArrayBufferConverter.h"
using ppapi::ArrayBufferVar;
@@ -44,10 +44,10 @@ struct StackEntry {
};
struct HashedHandle {
- HashedHandle(v8::Handle<v8::Object> h) : handle(h) {}
+ HashedHandle(v8::Local<v8::Object> h) : handle(h) {}
size_t hash() const { return handle->GetIdentityHash(); }
bool operator==(const HashedHandle& h) const { return handle == h.handle; }
- v8::Handle<v8::Object> handle;
+ v8::Local<v8::Object> handle;
};
} // namespace
@@ -64,7 +64,7 @@ namespace content {
namespace {
// Maps PP_Var IDs to the V8 value handle they correspond to.
-typedef base::hash_map<int64_t, v8::Handle<v8::Value> > VarHandleMap;
+typedef base::hash_map<int64_t, v8::Local<v8::Value> > VarHandleMap;
typedef base::hash_set<int64_t> ParentVarSet;
// Maps V8 value handles to the PP_Var they correspond to.
@@ -76,10 +76,10 @@ typedef base::hash_set<HashedHandle> ParentHandleSet;
// associated with it in the map will be returned, otherwise a new V8 value will
// be created and added to the map. |did_create| indicates whether a new v8
// value was created as a result of calling the function.
-bool GetOrCreateV8Value(v8::Handle<v8::Context> context,
+bool GetOrCreateV8Value(v8::Local<v8::Context> context,
const PP_Var& var,
V8VarConverter::AllowObjectVars object_vars_allowed,
- v8::Handle<v8::Value>* result,
+ v8::Local<v8::Value>* result,
bool* did_create,
VarHandleMap* visited_ids,
ParentVarSet* parent_ids,
@@ -187,8 +187,8 @@ bool GetOrCreateV8Value(v8::Handle<v8::Context> context,
// it will be returned, otherwise a new V8 value will be created and added to
// the map. |did_create| indicates if a new PP_Var was created as a result of
// calling the function.
-bool GetOrCreateVar(v8::Handle<v8::Value> val,
- v8::Handle<v8::Context> context,
+bool GetOrCreateVar(v8::Local<v8::Value> val,
+ v8::Local<v8::Context> context,
PP_Instance instance,
V8VarConverter::AllowObjectVars object_vars_allowed,
PP_Var* result,
@@ -199,34 +199,34 @@ bool GetOrCreateVar(v8::Handle<v8::Value> val,
CHECK(!val.IsEmpty());
*did_create = false;
+ v8::Isolate* isolate = context->GetIsolate();
// Even though every v8 string primitive encountered will be a unique object,
// we still add them to |visited_handles| so that the corresponding string
// PP_Var created will be properly refcounted.
if (val->IsObject() || val->IsString()) {
- if (parent_handles->count(HashedHandle(val->ToObject())) != 0)
+ if (parent_handles->count(HashedHandle(val->ToObject(isolate))) != 0)
return false;
HandleVarMap::const_iterator it =
- visited_handles->find(HashedHandle(val->ToObject()));
+ visited_handles->find(HashedHandle(val->ToObject(isolate)));
if (it != visited_handles->end()) {
*result = it->second.get();
return true;
}
}
- v8::Isolate* isolate = context->GetIsolate();
if (val->IsUndefined()) {
*result = PP_MakeUndefined();
} else if (val->IsNull()) {
*result = PP_MakeNull();
} else if (val->IsBoolean() || val->IsBooleanObject()) {
- *result = PP_MakeBool(PP_FromBool(val->ToBoolean()->Value()));
+ *result = PP_MakeBool(PP_FromBool(val->ToBoolean(isolate)->Value()));
} else if (val->IsInt32()) {
- *result = PP_MakeInt32(val->ToInt32()->Value());
+ *result = PP_MakeInt32(val->ToInt32(isolate)->Value());
} else if (val->IsNumber() || val->IsNumberObject()) {
- *result = PP_MakeDouble(val->ToNumber()->Value());
+ *result = PP_MakeDouble(val->ToNumber(isolate)->Value());
} else if (val->IsString() || val->IsStringObject()) {
- v8::String::Utf8Value utf8(val->ToString());
+ v8::String::Utf8Value utf8(val->ToString(isolate));
*result = StringVar::StringToPPVar(std::string(*utf8, utf8.length()));
} else if (val->IsObject()) {
// For any other v8 objects, the conversion happens as follows:
@@ -244,15 +244,15 @@ bool GetOrCreateVar(v8::Handle<v8::Value> val,
new HostArrayBufferVar(*web_array_buffer));
*result = buffer_var->GetPPVar();
} else if (object_vars_allowed == V8VarConverter::kAllowObjectVars) {
- v8::Handle<v8::Object> object = val->ToObject();
+ v8::Local<v8::Object> object = val.As<v8::Object>();
*result = content::HostGlobals::Get()->
host_var_tracker()->V8ObjectVarForV8Object(instance, object);
} else if (val->IsArray()) {
*result = (new ArrayVar())->GetPPVar();
} else {
bool was_resource;
- if (!resource_converter->FromV8Value(
- val->ToObject(), context, result, &was_resource))
+ if (!resource_converter->FromV8Value(val.As<v8::Object>(), context,
+ result, &was_resource))
return false;
if (!was_resource) {
*result = (new DictionaryVar())->GetPPVar();
@@ -268,7 +268,7 @@ bool GetOrCreateVar(v8::Handle<v8::Value> val,
*did_create = true;
if (val->IsObject() || val->IsString()) {
visited_handles->insert(
- make_pair(HashedHandle(val->ToObject()),
+ make_pair(HashedHandle(val->ToObject(isolate)),
ScopedPPVar(ScopedPPVar::PassRef(), *result)));
}
return true;
@@ -306,8 +306,8 @@ V8VarConverter::~V8VarConverter() {}
// stack and erase it from the list of parents.
// static
bool V8VarConverter::ToV8Value(const PP_Var& var,
- v8::Handle<v8::Context> context,
- v8::Handle<v8::Value>* result) {
+ v8::Local<v8::Context> context,
+ v8::Local<v8::Value>* result) {
v8::Context::Scope context_scope(context);
v8::Isolate* isolate = context->GetIsolate();
v8::EscapableHandleScope handle_scope(isolate);
@@ -322,7 +322,7 @@ bool V8VarConverter::ToV8Value(const PP_Var& var,
while (!stack.empty()) {
const PP_Var& current_var = stack.top().val;
- v8::Handle<v8::Value> current_v8;
+ v8::Local<v8::Value> current_v8;
if (stack.top().sentinel) {
stack.pop();
@@ -359,11 +359,11 @@ bool V8VarConverter::ToV8Value(const PP_Var& var,
return false;
}
DCHECK(current_v8->IsArray());
- v8::Handle<v8::Array> v8_array = current_v8.As<v8::Array>();
+ v8::Local<v8::Array> v8_array = current_v8.As<v8::Array>();
for (size_t i = 0; i < array_var->elements().size(); ++i) {
const PP_Var& child_var = array_var->elements()[i].get();
- v8::Handle<v8::Value> child_v8;
+ v8::Local<v8::Value> child_v8;
if (!GetOrCreateV8Value(context,
child_var,
object_vars_allowed_,
@@ -391,7 +391,7 @@ bool V8VarConverter::ToV8Value(const PP_Var& var,
return false;
}
DCHECK(current_v8->IsObject());
- v8::Handle<v8::Object> v8_object = current_v8->ToObject();
+ v8::Local<v8::Object> v8_object = current_v8.As<v8::Object>();
for (DictionaryVar::KeyValueMap::const_iterator iter =
dict_var->key_value_map().begin();
@@ -399,7 +399,7 @@ bool V8VarConverter::ToV8Value(const PP_Var& var,
++iter) {
const std::string& key = iter->first;
const PP_Var& child_var = iter->second.get();
- v8::Handle<v8::Value> child_v8;
+ v8::Local<v8::Value> child_v8;
if (!GetOrCreateV8Value(context,
child_var,
object_vars_allowed_,
@@ -431,8 +431,8 @@ bool V8VarConverter::ToV8Value(const PP_Var& var,
}
V8VarConverter::VarResult V8VarConverter::FromV8Value(
- v8::Handle<v8::Value> val,
- v8::Handle<v8::Context> context,
+ v8::Local<v8::Value> val,
+ v8::Local<v8::Context> context,
const base::Callback<void(const ScopedPPVar&, bool)>& callback) {
VarResult result;
result.success = FromV8ValueInternal(val, context, &result.var);
@@ -446,8 +446,8 @@ V8VarConverter::VarResult V8VarConverter::FromV8Value(
}
bool V8VarConverter::FromV8ValueSync(
- v8::Handle<v8::Value> val,
- v8::Handle<v8::Context> context,
+ v8::Local<v8::Value> val,
+ v8::Local<v8::Context> context,
ppapi::ScopedPPVar* result_var) {
bool success = FromV8ValueInternal(val, context, result_var);
if (!success || resource_converter_->NeedsFlush()) {
@@ -458,8 +458,8 @@ bool V8VarConverter::FromV8ValueSync(
}
bool V8VarConverter::FromV8ValueInternal(
- v8::Handle<v8::Value> val,
- v8::Handle<v8::Context> context,
+ v8::Local<v8::Value> val,
+ v8::Local<v8::Context> context,
ppapi::ScopedPPVar* result_var) {
v8::Context::Scope context_scope(context);
v8::HandleScope handle_scope(context->GetIsolate());
@@ -467,20 +467,20 @@ bool V8VarConverter::FromV8ValueInternal(
HandleVarMap visited_handles;
ParentHandleSet parent_handles;
- std::stack<StackEntry<v8::Handle<v8::Value> > > stack;
- stack.push(StackEntry<v8::Handle<v8::Value> >(val));
+ std::stack<StackEntry<v8::Local<v8::Value> > > stack;
+ stack.push(StackEntry<v8::Local<v8::Value> >(val));
ScopedPPVar root;
*result_var = PP_MakeUndefined();
bool is_root = true;
while (!stack.empty()) {
- v8::Handle<v8::Value> current_v8 = stack.top().val;
+ v8::Local<v8::Value> current_v8 = stack.top().val;
PP_Var current_var;
if (stack.top().sentinel) {
stack.pop();
if (current_v8->IsObject())
- parent_handles.erase(HashedHandle(current_v8->ToObject()));
+ parent_handles.erase(HashedHandle(current_v8.As<v8::Object>()));
continue;
} else {
stack.top().sentinel = true;
@@ -507,7 +507,7 @@ bool V8VarConverter::FromV8ValueInternal(
// Add child nodes to the stack.
if (current_var.type == PP_VARTYPE_ARRAY) {
DCHECK(current_v8->IsArray());
- v8::Handle<v8::Array> v8_array = current_v8.As<v8::Array>();
+ v8::Local<v8::Array> v8_array = current_v8.As<v8::Array>();
parent_handles.insert(HashedHandle(v8_array));
ArrayVar* array_var = ArrayVar::FromPPVar(current_var);
@@ -518,7 +518,7 @@ bool V8VarConverter::FromV8ValueInternal(
for (uint32 i = 0; i < v8_array->Length(); ++i) {
v8::TryCatch try_catch;
- v8::Handle<v8::Value> child_v8 = v8_array->Get(i);
+ v8::Local<v8::Value> child_v8 = v8_array->Get(i);
if (try_catch.HasCaught())
return false;
@@ -544,7 +544,7 @@ bool V8VarConverter::FromV8ValueInternal(
}
} else if (current_var.type == PP_VARTYPE_DICTIONARY) {
DCHECK(current_v8->IsObject());
- v8::Handle<v8::Object> v8_object = current_v8->ToObject();
+ v8::Local<v8::Object> v8_object = current_v8.As<v8::Object>();
parent_handles.insert(HashedHandle(v8_object));
DictionaryVar* dict_var = DictionaryVar::FromPPVar(current_var);
@@ -553,9 +553,9 @@ bool V8VarConverter::FromV8ValueInternal(
return false;
}
- v8::Handle<v8::Array> property_names(v8_object->GetOwnPropertyNames());
+ v8::Local<v8::Array> property_names(v8_object->GetOwnPropertyNames());
for (uint32 i = 0; i < property_names->Length(); ++i) {
- v8::Handle<v8::Value> key(property_names->Get(i));
+ v8::Local<v8::Value> key(property_names->Get(i));
// Extend this test to cover more types as necessary and if sensible.
if (!key->IsString() && !key->IsNumber()) {
@@ -565,14 +565,16 @@ bool V8VarConverter::FromV8ValueInternal(
return false;
}
+ v8::Local<v8::String> key_string =
+ key->ToString(context->GetIsolate());
// Skip all callbacks: crbug.com/139933
- if (v8_object->HasRealNamedCallbackProperty(key->ToString()))
+ if (v8_object->HasRealNamedCallbackProperty(key_string))
continue;
- v8::String::Utf8Value name_utf8(key->ToString());
+ v8::String::Utf8Value name_utf8(key_string);
v8::TryCatch try_catch;
- v8::Handle<v8::Value> child_v8 = v8_object->Get(key);
+ v8::Local<v8::Value> child_v8 = v8_object->Get(key);
if (try_catch.HasCaught())
return false;
diff --git a/chromium/content/renderer/pepper/v8_var_converter.h b/chromium/content/renderer/pepper/v8_var_converter.h
index c03701d4c71..2a5a9f9c85a 100644
--- a/chromium/content/renderer/pepper/v8_var_converter.h
+++ b/chromium/content/renderer/pepper/v8_var_converter.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_RENDERER_PEPPER_V8_VAR_CONVERTER_H
-#define CONTENT_RENDERER_PEPPER_V8_VAR_CONVERTER_H
+#ifndef CONTENT_RENDERER_PEPPER_V8_VAR_CONVERTER_H_
+#define CONTENT_RENDERER_PEPPER_V8_VAR_CONVERTER_H_
#include "base/basictypes.h"
#include "base/callback.h"
@@ -36,8 +36,8 @@ class CONTENT_EXPORT V8VarConverter {
// Converts the given PP_Var to a v8::Value. True is returned upon success.
bool ToV8Value(const PP_Var& var,
- v8::Handle<v8::Context> context,
- v8::Handle<v8::Value>* result);
+ v8::Local<v8::Context> context,
+ v8::Local<v8::Value>* result);
struct VarResult {
public:
@@ -66,16 +66,16 @@ class CONTENT_EXPORT V8VarConverter {
// the conversion can occur synchronously, |callback| will not be run,
// otherwise it will be run.
VarResult FromV8Value(
- v8::Handle<v8::Value> val,
- v8::Handle<v8::Context> context,
+ v8::Local<v8::Value> val,
+ v8::Local<v8::Context> context,
const base::Callback<void(const ppapi::ScopedPPVar&, bool)>& callback);
- bool FromV8ValueSync(v8::Handle<v8::Value> val,
- v8::Handle<v8::Context> context,
+ bool FromV8ValueSync(v8::Local<v8::Value> val,
+ v8::Local<v8::Context> context,
ppapi::ScopedPPVar* result_var);
private:
// Returns true on success, false on failure.
- bool FromV8ValueInternal(v8::Handle<v8::Value> val,
- v8::Handle<v8::Context> context,
+ bool FromV8ValueInternal(v8::Local<v8::Value> val,
+ v8::Local<v8::Context> context,
ppapi::ScopedPPVar* result_var);
PP_Instance instance_;
@@ -91,4 +91,4 @@ class CONTENT_EXPORT V8VarConverter {
} // namespace content
-#endif // CONTENT_RENDERER_PEPPER_V8_VAR_CONVERTER_H
+#endif // CONTENT_RENDERER_PEPPER_V8_VAR_CONVERTER_H_
diff --git a/chromium/content/renderer/pepper/v8_var_converter_unittest.cc b/chromium/content/renderer/pepper/v8_var_converter_unittest.cc
index f43d66a0fce..8eb717b8ad6 100644
--- a/chromium/content/renderer/pepper/v8_var_converter_unittest.cc
+++ b/chromium/content/renderer/pepper/v8_var_converter_unittest.cc
@@ -22,7 +22,7 @@
#include "ppapi/shared_impl/proxy_lock.h"
#include "ppapi/shared_impl/scoped_pp_var.h"
#include "ppapi/shared_impl/test_globals.h"
-#include "ppapi/shared_impl/unittest_utils.h"
+#include "ppapi/shared_impl/test_utils.h"
#include "ppapi/shared_impl/var.h"
#include "ppapi/shared_impl/var_tracker.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -56,25 +56,25 @@ class MockResourceConverter : public content::ResourceConverter {
void Flush(const base::Callback<void(bool)>& callback) override {
NOTREACHED();
}
- bool FromV8Value(v8::Handle<v8::Object> val,
- v8::Handle<v8::Context> context,
+ bool FromV8Value(v8::Local<v8::Object> val,
+ v8::Local<v8::Context> context,
PP_Var* result,
bool* was_resource) override {
*was_resource = false;
return true;
}
bool ToV8Value(const PP_Var& var,
- v8::Handle<v8::Context> context,
- v8::Handle<v8::Value>* result) override {
+ v8::Local<v8::Context> context,
+ v8::Local<v8::Value>* result) override {
return false;
}
};
// Maps PP_Var IDs to the V8 value handle they correspond to.
-typedef base::hash_map<int64_t, v8::Handle<v8::Value> > VarHandleMap;
+typedef base::hash_map<int64_t, v8::Local<v8::Value> > VarHandleMap;
bool Equals(const PP_Var& var,
- v8::Handle<v8::Value> val,
+ v8::Local<v8::Value> val,
VarHandleMap* visited_ids) {
if (ppapi::VarTracker::IsVarTypeRefcounted(var.type)) {
VarHandleMap::iterator it = visited_ids->find(var.value.as_id);
@@ -83,36 +83,38 @@ bool Equals(const PP_Var& var,
(*visited_ids)[var.value.as_id] = val;
}
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
if (val->IsUndefined()) {
return var.type == PP_VARTYPE_UNDEFINED;
} else if (val->IsNull()) {
return var.type == PP_VARTYPE_NULL;
} else if (val->IsBoolean() || val->IsBooleanObject()) {
return var.type == PP_VARTYPE_BOOL &&
- PP_FromBool(val->ToBoolean()->Value()) == var.value.as_bool;
+ PP_FromBool(val->ToBoolean(isolate)->Value()) == var.value.as_bool;
} else if (val->IsInt32()) {
return var.type == PP_VARTYPE_INT32 &&
- val->ToInt32()->Value() == var.value.as_int;
+ val->ToInt32(isolate)->Value() == var.value.as_int;
} else if (val->IsNumber() || val->IsNumberObject()) {
return var.type == PP_VARTYPE_DOUBLE &&
- fabs(val->ToNumber()->Value() - var.value.as_double) <= 1.0e-4;
+ fabs(val->ToNumber(isolate)->Value() - var.value.as_double) <=
+ 1.0e-4;
} else if (val->IsString() || val->IsStringObject()) {
if (var.type != PP_VARTYPE_STRING)
return false;
StringVar* string_var = StringVar::FromPPVar(var);
DCHECK(string_var);
- v8::String::Utf8Value utf8(val->ToString());
+ v8::String::Utf8Value utf8(val);
return std::string(*utf8, utf8.length()) == string_var->value();
} else if (val->IsArray()) {
if (var.type != PP_VARTYPE_ARRAY)
return false;
ArrayVar* array_var = ArrayVar::FromPPVar(var);
DCHECK(array_var);
- v8::Handle<v8::Array> v8_array = val.As<v8::Array>();
+ v8::Local<v8::Array> v8_array = val.As<v8::Array>();
if (v8_array->Length() != array_var->elements().size())
return false;
for (uint32 i = 0; i < v8_array->Length(); ++i) {
- v8::Handle<v8::Value> child_v8 = v8_array->Get(i);
+ v8::Local<v8::Value> child_v8 = v8_array->Get(i);
if (!Equals(array_var->elements()[i].get(), child_v8, visited_ids))
return false;
}
@@ -123,22 +125,22 @@ bool Equals(const PP_Var& var,
NOTIMPLEMENTED();
return false;
} else {
- v8::Handle<v8::Object> v8_object = val->ToObject();
+ v8::Local<v8::Object> v8_object = val.As<v8::Object>();
if (var.type != PP_VARTYPE_DICTIONARY)
return false;
DictionaryVar* dict_var = DictionaryVar::FromPPVar(var);
DCHECK(dict_var);
- v8::Handle<v8::Array> property_names(v8_object->GetOwnPropertyNames());
+ v8::Local<v8::Array> property_names(v8_object->GetOwnPropertyNames());
if (property_names->Length() != dict_var->key_value_map().size())
return false;
for (uint32 i = 0; i < property_names->Length(); ++i) {
- v8::Handle<v8::Value> key(property_names->Get(i));
+ v8::Local<v8::Value> key(property_names->Get(i));
if (!key->IsString() && !key->IsNumber())
return false;
- v8::Handle<v8::Value> child_v8 = v8_object->Get(key);
+ v8::Local<v8::Value> child_v8 = v8_object->Get(key);
- v8::String::Utf8Value name_utf8(key->ToString());
+ v8::String::Utf8Value name_utf8(key);
ScopedPPVar release_key(ScopedPPVar::PassRef(),
StringVar::StringToPPVar(std::string(
*name_utf8, name_utf8.length())));
@@ -155,7 +157,7 @@ bool Equals(const PP_Var& var,
return false;
}
-bool Equals(const PP_Var& var, v8::Handle<v8::Value> val) {
+bool Equals(const PP_Var& var, v8::Local<v8::Value> val) {
VarHandleMap var_handle_map;
return Equals(var, val, &var_handle_map);
}
@@ -175,7 +177,7 @@ class V8VarConverterTest : public testing::Test {
void SetUp() override {
ProxyLock::Acquire();
v8::HandleScope handle_scope(isolate_);
- v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate_);
+ v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate_);
context_.Reset(isolate_, v8::Context::New(isolate_, NULL, global));
}
void TearDown() override {
@@ -185,8 +187,8 @@ class V8VarConverterTest : public testing::Test {
}
protected:
- bool FromV8ValueSync(v8::Handle<v8::Value> val,
- v8::Handle<v8::Context> context,
+ bool FromV8ValueSync(v8::Local<v8::Value> val,
+ v8::Local<v8::Context> context,
PP_Var* result) {
V8VarConverter::VarResult conversion_result =
converter_->FromV8Value(val,
@@ -204,7 +206,7 @@ class V8VarConverterTest : public testing::Test {
v8::Local<v8::Context> context =
v8::Local<v8::Context>::New(isolate_, context_);
v8::Context::Scope context_scope(context);
- v8::Handle<v8::Value> v8_result;
+ v8::Local<v8::Value> v8_result;
if (!converter_->ToV8Value(var, context, &v8_result))
return false;
if (!Equals(var, v8_result))
@@ -342,7 +344,7 @@ TEST_F(V8VarConverterTest, Cycles) {
dictionary->SetWithStringKey("1", release_array.get());
array->Set(0, release_dictionary.get());
- v8::Handle<v8::Value> v8_result;
+ v8::Local<v8::Value> v8_result;
// Array <-> dictionary cycle.
dictionary->SetWithStringKey("1", release_array.get());
@@ -363,8 +365,8 @@ TEST_F(V8VarConverterTest, Cycles) {
// V8->Var conversion.
{
- v8::Handle<v8::Object> object = v8::Object::New(isolate_);
- v8::Handle<v8::Array> array = v8::Array::New(isolate_);
+ v8::Local<v8::Object> object = v8::Object::New(isolate_);
+ v8::Local<v8::Array> array = v8::Array::New(isolate_);
PP_Var var_result;
@@ -412,9 +414,9 @@ TEST_F(V8VarConverterTest, StrangeDictionaryKeyTest) {
"};"
"})();";
- v8::Handle<v8::Script> script(
+ v8::Local<v8::Script> script(
v8::Script::Compile(v8::String::NewFromUtf8(isolate_, source)));
- v8::Handle<v8::Object> object = script->Run().As<v8::Object>();
+ v8::Local<v8::Object> object = script->Run().As<v8::Object>();
ASSERT_FALSE(object.IsEmpty());
PP_Var actual;
diff --git a/chromium/content/renderer/pepper/v8object_var.cc b/chromium/content/renderer/pepper/v8object_var.cc
index faf8bef8e7a..a95c529cd49 100644
--- a/chromium/content/renderer/pepper/v8object_var.cc
+++ b/chromium/content/renderer/pepper/v8object_var.cc
@@ -15,7 +15,7 @@ namespace ppapi {
// V8ObjectVar -----------------------------------------------------------------
V8ObjectVar::V8ObjectVar(PP_Instance instance,
- v8::Handle<v8::Object> v8_object)
+ v8::Local<v8::Object> v8_object)
: instance_(content::HostGlobals::Get()->GetInstance(instance)) {
v8_object_.Reset(instance_->GetIsolate(), v8_object);
content::HostGlobals::Get()->host_var_tracker()->AddV8ObjectVar(this);
diff --git a/chromium/content/renderer/pepper/v8object_var.h b/chromium/content/renderer/pepper/v8object_var.h
index 0480fbe8245..4a4feb1f231 100644
--- a/chromium/content/renderer/pepper/v8object_var.h
+++ b/chromium/content/renderer/pepper/v8object_var.h
@@ -30,7 +30,7 @@ namespace ppapi {
// plugins that may be running at the same time.
class CONTENT_EXPORT V8ObjectVar : public Var {
public:
- V8ObjectVar(PP_Instance instance, v8::Handle<v8::Object> v8_object);
+ V8ObjectVar(PP_Instance instance, v8::Local<v8::Object> v8_object);
// Var overrides.
V8ObjectVar* AsV8ObjectVar() override;
diff --git a/chromium/content/renderer/pepper/video_decoder_shim.cc b/chromium/content/renderer/pepper/video_decoder_shim.cc
index 9bad6c044db..faf6446fd24 100644
--- a/chromium/content/renderer/pepper/video_decoder_shim.cc
+++ b/chromium/content/renderer/pepper/video_decoder_shim.cc
@@ -9,8 +9,12 @@
#include <GLES2/gl2extchromium.h>
#include "base/bind.h"
+#ifndef NDEBUG
+#include "base/logging.h"
+#endif
#include "base/numerics/safe_conversions.h"
#include "base/single_thread_task_runner.h"
+#include "cc/blink/context_provider_web_context.h"
#include "content/public/renderer/render_thread.h"
#include "content/renderer/pepper/pepper_video_decoder_host.h"
#include "content/renderer/render_thread_impl.h"
@@ -18,16 +22,559 @@
#include "media/base/decoder_buffer.h"
#include "media/base/limits.h"
#include "media/base/video_decoder.h"
+#include "media/blink/skcanvas_video_renderer.h"
#include "media/filters/ffmpeg_video_decoder.h"
#include "media/filters/vpx_video_decoder.h"
#include "media/video/picture.h"
#include "media/video/video_decode_accelerator.h"
#include "ppapi/c/pp_errors.h"
-#include "third_party/libyuv/include/libyuv.h"
-#include "webkit/common/gpu/context_provider_web_context.h"
+#include "third_party/skia/include/gpu/GrTypes.h"
namespace content {
+static const uint32_t kGrInvalidateState =
+ kRenderTarget_GrGLBackendState | kTextureBinding_GrGLBackendState |
+ kView_GrGLBackendState | kVertex_GrGLBackendState |
+ kProgram_GrGLBackendState | kPixelStore_GrGLBackendState;
+
+// YUV->RGB converter class using a shader and FBO.
+class VideoDecoderShim::YUVConverter {
+ public:
+ YUVConverter(const scoped_refptr<cc_blink::ContextProviderWebContext>&);
+ ~YUVConverter();
+ bool Initialize();
+ void Convert(const scoped_refptr<media::VideoFrame>& frame, GLuint tex_out);
+
+ private:
+ GLuint CreateShader();
+ GLuint CompileShader(const char* name, GLuint type, const char* code);
+ GLuint CreateProgram(const char* name, GLuint vshader, GLuint fshader);
+ GLuint CreateTexture();
+
+ scoped_refptr<cc_blink::ContextProviderWebContext> context_provider_;
+ gpu::gles2::GLES2Interface* gl_;
+ GLuint frame_buffer_;
+ GLuint vertex_buffer_;
+ GLuint program_;
+
+ GLuint y_texture_;
+ GLuint u_texture_;
+ GLuint v_texture_;
+ GLuint a_texture_;
+
+ GLuint internal_format_;
+ GLuint format_;
+ media::VideoFrame::Format video_format_;
+
+ GLuint y_width_;
+ GLuint y_height_;
+
+ GLuint uv_width_;
+ GLuint uv_height_;
+ uint32_t uv_height_divisor_;
+ uint32_t uv_width_divisor_;
+
+ GLint yuv_matrix_loc_;
+ GLint yuv_adjust_loc_;
+
+ DISALLOW_COPY_AND_ASSIGN(YUVConverter);
+};
+
+VideoDecoderShim::YUVConverter::YUVConverter(
+ const scoped_refptr<cc_blink::ContextProviderWebContext>& context_provider)
+ : context_provider_(context_provider),
+ gl_(context_provider_->ContextGL()),
+ frame_buffer_(0),
+ vertex_buffer_(0),
+ program_(0),
+ y_texture_(0),
+ u_texture_(0),
+ v_texture_(0),
+ a_texture_(0),
+ internal_format_(0),
+ format_(0),
+ video_format_(media::VideoFrame::UNKNOWN),
+ y_width_(2),
+ y_height_(2),
+ uv_width_(2),
+ uv_height_(2),
+ uv_height_divisor_(1),
+ uv_width_divisor_(1),
+ yuv_matrix_loc_(0),
+ yuv_adjust_loc_(0) {
+ DCHECK(gl_);
+}
+
+VideoDecoderShim::YUVConverter::~YUVConverter() {
+ if (y_texture_)
+ gl_->DeleteTextures(1, &y_texture_);
+
+ if (u_texture_)
+ gl_->DeleteTextures(1, &u_texture_);
+
+ if (v_texture_)
+ gl_->DeleteTextures(1, &v_texture_);
+
+ if (a_texture_)
+ gl_->DeleteTextures(1, &a_texture_);
+
+ if (frame_buffer_)
+ gl_->DeleteFramebuffers(1, &frame_buffer_);
+
+ if (vertex_buffer_)
+ gl_->DeleteBuffers(1, &vertex_buffer_);
+
+ if (program_)
+ gl_->DeleteProgram(program_);
+}
+
+GLuint VideoDecoderShim::YUVConverter::CreateTexture() {
+ GLuint tex = 0;
+
+ gl_->GenTextures(1, &tex);
+ gl_->BindTexture(GL_TEXTURE_2D, tex);
+
+ // Create texture with default size - will be resized upon first frame.
+ gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, 2, 2, 0, format_,
+ GL_UNSIGNED_BYTE, NULL);
+
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ gl_->BindTexture(GL_TEXTURE_2D, 0);
+
+ return tex;
+}
+
+GLuint VideoDecoderShim::YUVConverter::CompileShader(const char* name,
+ GLuint type,
+ const char* code) {
+ GLuint shader = gl_->CreateShader(type);
+
+ gl_->ShaderSource(shader, 1, (const GLchar**)&code, NULL);
+ gl_->CompileShader(shader);
+
+#ifndef NDEBUG
+ GLint status = 0;
+
+ gl_->GetShaderiv(shader, GL_COMPILE_STATUS, &status);
+ if (status != GL_TRUE) {
+ GLint max_length = 0;
+ GLint actual_length = 0;
+ gl_->GetShaderiv(shader, GL_INFO_LOG_LENGTH, &max_length);
+
+ // The max_length includes the NULL character.
+ std::string error_log(max_length, 0);
+ gl_->GetShaderInfoLog(shader, max_length, &actual_length, &error_log[0]);
+
+ LOG(ERROR) << name << " shader compilation failed: " << error_log.c_str();
+ gl_->DeleteShader(shader);
+ return 0;
+ }
+#endif
+
+ return shader;
+}
+
+GLuint VideoDecoderShim::YUVConverter::CreateProgram(const char* name,
+ GLuint vshader,
+ GLuint fshader) {
+ GLuint program = gl_->CreateProgram();
+ gl_->AttachShader(program, vshader);
+ gl_->AttachShader(program, fshader);
+
+ gl_->BindAttribLocation(program, 0, "position");
+
+ gl_->LinkProgram(program);
+
+#ifndef NDEBUG
+ GLint status = 0;
+
+ gl_->GetProgramiv(program, GL_LINK_STATUS, &status);
+ if (status != GL_TRUE) {
+ GLint max_length = 0;
+ GLint actual_length = 0;
+ gl_->GetProgramiv(program, GL_INFO_LOG_LENGTH, &max_length);
+
+ // The max_length includes the NULL character.
+ std::string error_log(max_length, 0);
+ gl_->GetProgramInfoLog(program, max_length, &actual_length, &error_log[0]);
+
+ LOG(ERROR) << name << " program linking failed: " << error_log.c_str();
+ return 0;
+ }
+#endif
+
+ return program;
+}
+
+GLuint VideoDecoderShim::YUVConverter::CreateShader() {
+ const char* vert_shader =
+ "precision mediump float;\n"
+ "attribute vec2 position;\n"
+ "varying vec2 texcoord;\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = vec4( position.xy, 0, 1 );\n"
+ " texcoord = position*0.5+0.5;\n"
+ "}";
+
+ const char* frag_shader =
+ "precision mediump float;\n"
+ "varying vec2 texcoord;\n"
+ "uniform sampler2D y_sampler;\n"
+ "uniform sampler2D u_sampler;\n"
+ "uniform sampler2D v_sampler;\n"
+ "uniform sampler2D a_sampler;\n"
+ "uniform mat3 yuv_matrix;\n"
+ "uniform vec3 yuv_adjust;\n"
+ "void main()\n"
+ "{\n"
+ " vec3 yuv = vec3(texture2D(y_sampler, texcoord).x,\n"
+ " texture2D(u_sampler, texcoord).x,\n"
+ " texture2D(v_sampler, texcoord).x) +\n"
+ " yuv_adjust;\n"
+ " gl_FragColor = vec4(yuv_matrix * yuv, texture2D(a_sampler, "
+ "texcoord).x);\n"
+ "}";
+
+ GLuint vertex_shader =
+ CompileShader("Vertex Shader", GL_VERTEX_SHADER, vert_shader);
+ if (!vertex_shader) {
+ return 0;
+ }
+
+ GLuint fragment_shader =
+ CompileShader("Fragment Shader", GL_FRAGMENT_SHADER, frag_shader);
+ if (!fragment_shader) {
+ gl_->DeleteShader(vertex_shader);
+ return 0;
+ }
+
+ GLuint program =
+ CreateProgram("YUVConverter Program", vertex_shader, fragment_shader);
+
+ gl_->DeleteShader(vertex_shader);
+ gl_->DeleteShader(fragment_shader);
+
+ if (!program) {
+ return 0;
+ }
+
+ gl_->UseProgram(program);
+
+ GLint uniform_location;
+ uniform_location = gl_->GetUniformLocation(program, "y_sampler");
+ DCHECK(uniform_location != -1);
+ gl_->Uniform1i(uniform_location, 0);
+
+ uniform_location = gl_->GetUniformLocation(program, "u_sampler");
+ DCHECK(uniform_location != -1);
+ gl_->Uniform1i(uniform_location, 1);
+
+ uniform_location = gl_->GetUniformLocation(program, "v_sampler");
+ DCHECK(uniform_location != -1);
+ gl_->Uniform1i(uniform_location, 2);
+
+ uniform_location = gl_->GetUniformLocation(program, "a_sampler");
+ DCHECK(uniform_location != -1);
+ gl_->Uniform1i(uniform_location, 3);
+
+ gl_->UseProgram(0);
+
+ yuv_matrix_loc_ = gl_->GetUniformLocation(program, "yuv_matrix");
+ DCHECK(yuv_matrix_loc_ != -1);
+
+ yuv_adjust_loc_ = gl_->GetUniformLocation(program, "yuv_adjust");
+ DCHECK(yuv_adjust_loc_ != -1);
+
+ return program;
+}
+
+bool VideoDecoderShim::YUVConverter::Initialize() {
+ // If texture_rg extension is not available, use slower GL_LUMINANCE.
+ if (context_provider_->ContextCapabilities().gpu.texture_rg) {
+ internal_format_ = GL_RED_EXT;
+ format_ = GL_RED_EXT;
+ } else {
+ internal_format_ = GL_LUMINANCE;
+ format_ = GL_LUMINANCE;
+ }
+
+ if (context_provider_->ContextCapabilities().gpu.max_texture_image_units <
+ 4) {
+ // We support YUVA textures and require 4 texture units in the fragment
+ // stage.
+ return false;
+ }
+
+ gl_->PushGroupMarkerEXT(0, "YUVConverterContext");
+
+ gl_->GenFramebuffers(1, &frame_buffer_);
+
+ y_texture_ = CreateTexture();
+ u_texture_ = CreateTexture();
+ v_texture_ = CreateTexture();
+ a_texture_ = CreateTexture();
+
+ // Vertex positions. Also converted to texcoords in vertex shader.
+ GLfloat vertex_positions[] = {-1.f, -1.f, 1.f, -1.f, -1.f, 1.f, 1.f, 1.f};
+
+ gl_->GenBuffers(1, &vertex_buffer_);
+ gl_->BindBuffer(GL_ARRAY_BUFFER, vertex_buffer_);
+ gl_->BufferData(GL_ARRAY_BUFFER, 2 * sizeof(GLfloat) * 4, vertex_positions,
+ GL_STATIC_DRAW);
+ gl_->BindBuffer(GL_ARRAY_BUFFER, 0);
+
+ program_ = CreateShader();
+
+ gl_->PopGroupMarkerEXT();
+
+ context_provider_->InvalidateGrContext(kGrInvalidateState);
+
+ return (program_ != 0);
+}
+
+void VideoDecoderShim::YUVConverter::Convert(
+ const scoped_refptr<media::VideoFrame>& frame,
+ GLuint tex_out) {
+ const float* yuv_matrix = 0;
+ const float* yuv_adjust = 0;
+
+ if (video_format_ != frame->format()) {
+ // The constants below were taken from cc/output/gl_renderer.cc.
+ // These values are magic numbers that are used in the transformation from
+ // YUV to RGB color values. They are taken from the following webpage:
+ // http://www.fourcc.org/fccyvrgb.php
+ const float yuv_to_rgb_rec601[9] = {
+ 1.164f, 1.164f, 1.164f, 0.0f, -.391f, 2.018f, 1.596f, -.813f, 0.0f,
+ };
+ const float yuv_to_rgb_jpeg[9] = {
+ 1.f, 1.f, 1.f, 0.0f, -.34414f, 1.772f, 1.402f, -.71414f, 0.0f,
+ };
+ const float yuv_to_rgb_rec709[9] = {
+ 1.164f, 1.164f, 1.164f, 0.0f, -0.213f, 2.112f, 1.793f, -0.533f, 0.0f,
+ };
+
+ // These values map to 16, 128, and 128 respectively, and are computed
+ // as a fraction over 256 (e.g. 16 / 256 = 0.0625).
+ // They are used in the YUV to RGBA conversion formula:
+ // Y - 16 : Gives 16 values of head and footroom for overshooting
+ // U - 128 : Turns unsigned U into signed U [-128,127]
+ // V - 128 : Turns unsigned V into signed V [-128,127]
+ const float yuv_adjust_constrained[3] = {
+ -0.0625f, -0.5f, -0.5f,
+ };
+ // Same as above, but without the head and footroom.
+ const float yuv_adjust_full[3] = {
+ 0.0f, -0.5f, -0.5f,
+ };
+
+ switch (frame->format()) {
+ case media::VideoFrame::YV12: // 420
+ case media::VideoFrame::YV12A:
+ case media::VideoFrame::I420:
+ uv_height_divisor_ = 2;
+ uv_width_divisor_ = 2;
+ yuv_matrix = yuv_to_rgb_rec601;
+ yuv_adjust = yuv_adjust_constrained;
+ break;
+
+ case media::VideoFrame::YV12HD: // 420
+ uv_height_divisor_ = 2;
+ uv_width_divisor_ = 2;
+ yuv_matrix = yuv_to_rgb_rec709;
+ yuv_adjust = yuv_adjust_constrained;
+ break;
+
+ case media::VideoFrame::YV12J: // 420
+ uv_height_divisor_ = 2;
+ uv_width_divisor_ = 2;
+ yuv_matrix = yuv_to_rgb_jpeg;
+ yuv_adjust = yuv_adjust_full;
+ break;
+
+ case media::VideoFrame::YV16: // 422
+ uv_width_divisor_ = 2;
+ uv_height_divisor_ = 1;
+ yuv_matrix = yuv_to_rgb_rec601;
+ yuv_adjust = yuv_adjust_constrained;
+ break;
+ case media::VideoFrame::YV24: // 444
+ uv_width_divisor_ = 1;
+ uv_height_divisor_ = 1;
+ yuv_matrix = yuv_to_rgb_rec601;
+ yuv_adjust = yuv_adjust_constrained;
+ break;
+
+ default:
+ NOTREACHED();
+ }
+
+ video_format_ = frame->format();
+
+ // Zero these so everything is reset below.
+ y_width_ = y_height_ = 0;
+ }
+
+ gl_->PushGroupMarkerEXT(0, "YUVConverterContext");
+
+ uint32_t ywidth = frame->coded_size().width();
+ uint32_t yheight = frame->coded_size().height();
+
+ DCHECK_EQ(frame->stride(media::VideoFrame::kUPlane),
+ frame->stride(media::VideoFrame::kVPlane));
+
+ uint32_t ystride = frame->stride(media::VideoFrame::kYPlane);
+ uint32_t uvstride = frame->stride(media::VideoFrame::kUPlane);
+
+ // The following code assumes that extended GLES 2.0 state like
+ // UNPACK_SKIP* (if available) are set to defaults.
+ gl_->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+ if (ywidth != y_width_ || yheight != y_height_) {
+ y_width_ = ywidth;
+ y_height_ = yheight;
+
+ uv_width_ = y_width_ / uv_width_divisor_;
+ uv_height_ = y_height_ / uv_height_divisor_;
+
+ // Re-create to resize the textures and upload data.
+ gl_->PixelStorei(GL_UNPACK_ROW_LENGTH, ystride);
+ gl_->ActiveTexture(GL_TEXTURE0);
+ gl_->BindTexture(GL_TEXTURE_2D, y_texture_);
+ gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, y_width_, y_height_, 0,
+ format_, GL_UNSIGNED_BYTE,
+ frame->data(media::VideoFrame::kYPlane));
+
+ if (video_format_ == media::VideoFrame::YV12A) {
+ DCHECK_EQ(frame->stride(media::VideoFrame::kYPlane),
+ frame->stride(media::VideoFrame::kAPlane));
+ gl_->ActiveTexture(GL_TEXTURE3);
+ gl_->BindTexture(GL_TEXTURE_2D, a_texture_);
+ gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, y_width_, y_height_,
+ 0, format_, GL_UNSIGNED_BYTE,
+ frame->data(media::VideoFrame::kAPlane));
+ } else {
+ // if there is no alpha channel, then create a 2x2 texture with full
+ // alpha.
+ gl_->PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ const uint8_t alpha[4] = {0xff, 0xff, 0xff, 0xff};
+ gl_->ActiveTexture(GL_TEXTURE3);
+ gl_->BindTexture(GL_TEXTURE_2D, a_texture_);
+ gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, 2, 2, 0, format_,
+ GL_UNSIGNED_BYTE, alpha);
+ }
+
+ gl_->PixelStorei(GL_UNPACK_ROW_LENGTH, uvstride);
+ gl_->ActiveTexture(GL_TEXTURE1);
+ gl_->BindTexture(GL_TEXTURE_2D, u_texture_);
+ gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, uv_width_, uv_height_,
+ 0, format_, GL_UNSIGNED_BYTE,
+ frame->data(media::VideoFrame::kUPlane));
+
+ gl_->ActiveTexture(GL_TEXTURE2);
+ gl_->BindTexture(GL_TEXTURE_2D, v_texture_);
+ gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, uv_width_, uv_height_,
+ 0, format_, GL_UNSIGNED_BYTE,
+ frame->data(media::VideoFrame::kVPlane));
+ } else {
+ // Bind textures and upload texture data
+ gl_->PixelStorei(GL_UNPACK_ROW_LENGTH, ystride);
+ gl_->ActiveTexture(GL_TEXTURE0);
+ gl_->BindTexture(GL_TEXTURE_2D, y_texture_);
+ gl_->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, y_width_, y_height_, format_,
+ GL_UNSIGNED_BYTE,
+ frame->data(media::VideoFrame::kYPlane));
+
+ if (video_format_ == media::VideoFrame::YV12A) {
+ DCHECK_EQ(frame->stride(media::VideoFrame::kYPlane),
+ frame->stride(media::VideoFrame::kAPlane));
+ gl_->ActiveTexture(GL_TEXTURE3);
+ gl_->BindTexture(GL_TEXTURE_2D, a_texture_);
+ gl_->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, y_width_, y_height_, format_,
+ GL_UNSIGNED_BYTE,
+ frame->data(media::VideoFrame::kAPlane));
+ } else {
+ gl_->ActiveTexture(GL_TEXTURE3);
+ gl_->BindTexture(GL_TEXTURE_2D, a_texture_);
+ }
+
+ gl_->PixelStorei(GL_UNPACK_ROW_LENGTH, uvstride);
+ gl_->ActiveTexture(GL_TEXTURE1);
+ gl_->BindTexture(GL_TEXTURE_2D, u_texture_);
+ gl_->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, uv_width_, uv_height_, format_,
+ GL_UNSIGNED_BYTE,
+ frame->data(media::VideoFrame::kUPlane));
+
+ gl_->ActiveTexture(GL_TEXTURE2);
+ gl_->BindTexture(GL_TEXTURE_2D, v_texture_);
+ gl_->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, uv_width_, uv_height_, format_,
+ GL_UNSIGNED_BYTE,
+ frame->data(media::VideoFrame::kVPlane));
+ }
+
+ gl_->BindFramebuffer(GL_FRAMEBUFFER, frame_buffer_);
+ gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ tex_out, 0);
+
+#ifndef NDEBUG
+ // We should probably check for framebuffer complete here, but that
+ // will slow this method down so check only in debug mode.
+ GLint status = gl_->CheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ return;
+ }
+#endif
+
+ gl_->Viewport(0, 0, ywidth, yheight);
+
+ gl_->UseProgram(program_);
+
+ if (yuv_matrix) {
+ gl_->UniformMatrix3fv(yuv_matrix_loc_, 1, 0, yuv_matrix);
+ gl_->Uniform3fv(yuv_adjust_loc_, 1, yuv_adjust);
+ }
+
+ gl_->BindBuffer(GL_ARRAY_BUFFER, vertex_buffer_);
+ gl_->EnableVertexAttribArray(0);
+ gl_->VertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat),
+ static_cast<const void*>(0));
+
+ gl_->DrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+ // The YUVConverter shares the context with Skia and possibly other modules
+ // that may make OpenGL calls. To be a "good OpenGL citizen" for other
+ // (non-Skia) modules that may share this context we restore
+ // buffer/texture/state bindings to OpenGL defaults here. If we were only
+ // sharing the context with Skia this may not be necessary as we also
+ // Invalidate the GrContext below so that Skia is aware that its state
+ // caches need to be reset.
+
+ gl_->BindBuffer(GL_ARRAY_BUFFER, 0);
+ gl_->DisableVertexAttribArray(0);
+ gl_->UseProgram(0);
+ gl_->BindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ gl_->BindTexture(GL_TEXTURE_2D, 0);
+
+ gl_->ActiveTexture(GL_TEXTURE2);
+ gl_->BindTexture(GL_TEXTURE_2D, 0);
+
+ gl_->ActiveTexture(GL_TEXTURE1);
+ gl_->BindTexture(GL_TEXTURE_2D, 0);
+
+ gl_->ActiveTexture(GL_TEXTURE0);
+ gl_->BindTexture(GL_TEXTURE_2D, 0);
+ gl_->PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+
+ gl_->PopGroupMarkerEXT();
+
+ context_provider_->InvalidateGrContext(kGrInvalidateState);
+}
+
struct VideoDecoderShim::PendingDecode {
PendingDecode(uint32_t decode_id,
const scoped_refptr<media::DecoderBuffer>& buffer);
@@ -49,14 +596,11 @@ VideoDecoderShim::PendingDecode::~PendingDecode() {
struct VideoDecoderShim::PendingFrame {
explicit PendingFrame(uint32_t decode_id);
PendingFrame(uint32_t decode_id,
- const gfx::Size& coded_size,
- const gfx::Rect& visible_rect);
+ const scoped_refptr<media::VideoFrame>& frame);
~PendingFrame();
const uint32_t decode_id;
- const gfx::Size coded_size;
- const gfx::Rect visible_rect;
- std::vector<uint8_t> argb_pixels;
+ scoped_refptr<media::VideoFrame> video_frame;
private:
// This could be expensive to copy, so guard against that.
@@ -67,13 +611,10 @@ VideoDecoderShim::PendingFrame::PendingFrame(uint32_t decode_id)
: decode_id(decode_id) {
}
-VideoDecoderShim::PendingFrame::PendingFrame(uint32_t decode_id,
- const gfx::Size& coded_size,
- const gfx::Rect& visible_rect)
- : decode_id(decode_id),
- coded_size(coded_size),
- visible_rect(visible_rect),
- argb_pixels(coded_size.width() * coded_size.height() * 4) {
+VideoDecoderShim::PendingFrame::PendingFrame(
+ uint32_t decode_id,
+ const scoped_refptr<media::VideoFrame>& frame)
+ : decode_id(decode_id), video_frame(frame) {
}
VideoDecoderShim::PendingFrame::~PendingFrame() {
@@ -96,7 +637,7 @@ class VideoDecoderShim::DecoderImpl {
private:
void OnPipelineStatus(media::PipelineStatus status);
void DoDecode();
- void OnDecodeComplete(uint32_t decode_id, media::VideoDecoder::Status status);
+ void OnDecodeComplete(media::VideoDecoder::Status status);
void OnOutputComplete(const scoped_refptr<media::VideoFrame>& frame);
void OnResetComplete();
@@ -107,11 +648,12 @@ class VideoDecoderShim::DecoderImpl {
// Queue of decodes waiting for the decoder.
typedef std::queue<PendingDecode> PendingDecodeQueue;
PendingDecodeQueue pending_decodes_;
- int max_decodes_at_decoder_;
- int num_decodes_at_decoder_;
+ bool awaiting_decoder_;
// VideoDecoder returns pictures without information about the decode buffer
- // that generated it. Save the decode_id from the last decode that completed,
- // which is close for most decoders, which only decode one buffer at a time.
+ // that generated it, but VideoDecoder implementations used in this class
+ // (media::FFmpegVideoDecoder and media::VpxVideoDecoder) always generate
+ // corresponding frames before decode is finished. |decode_id_| is used to
+ // store id of the current buffer while Decode() call is pending.
uint32_t decode_id_;
};
@@ -119,8 +661,7 @@ VideoDecoderShim::DecoderImpl::DecoderImpl(
const base::WeakPtr<VideoDecoderShim>& proxy)
: shim_(proxy),
main_message_loop_(base::MessageLoopProxy::current()),
- max_decodes_at_decoder_(0),
- num_decodes_at_decoder_(0),
+ awaiting_decoder_(false),
decode_id_(0) {
}
@@ -143,7 +684,11 @@ void VideoDecoderShim::DecoderImpl::Initialize(
ffmpeg_video_decoder->set_decode_nalus(true);
decoder_ = ffmpeg_video_decoder.Pass();
}
- max_decodes_at_decoder_ = decoder_->GetMaxDecodeRequests();
+
+ // VpxVideoDecoder and FFmpegVideoDecoder support only one pending Decode()
+ // request.
+ DCHECK_EQ(decoder_->GetMaxDecodeRequests(), 1);
+
// We can use base::Unretained() safely in decoder callbacks because
// |decoder_| is owned by DecoderImpl. During Stop(), the |decoder_| will be
// destroyed and all outstanding callbacks will be fired.
@@ -207,8 +752,7 @@ void VideoDecoderShim::DecoderImpl::OnPipelineStatus(
}
// Calculate how many textures the shim should create.
- uint32_t shim_texture_pool_size =
- max_decodes_at_decoder_ + media::limits::kMaxVideoFrames;
+ uint32_t shim_texture_pool_size = media::limits::kMaxVideoFrames + 1;
main_message_loop_->PostTask(
FROM_HERE,
base::Bind(&VideoDecoderShim::OnInitializeComplete,
@@ -218,24 +762,22 @@ void VideoDecoderShim::DecoderImpl::OnPipelineStatus(
}
void VideoDecoderShim::DecoderImpl::DoDecode() {
- while (!pending_decodes_.empty() &&
- num_decodes_at_decoder_ < max_decodes_at_decoder_) {
- num_decodes_at_decoder_++;
- const PendingDecode& decode = pending_decodes_.front();
- decoder_->Decode(
- decode.buffer,
- base::Bind(&VideoDecoderShim::DecoderImpl::OnDecodeComplete,
- base::Unretained(this),
- decode.decode_id));
- pending_decodes_.pop();
- }
+ if (pending_decodes_.empty() || awaiting_decoder_)
+ return;
+
+ awaiting_decoder_ = true;
+ const PendingDecode& decode = pending_decodes_.front();
+ decode_id_ = decode.decode_id;
+ decoder_->Decode(decode.buffer,
+ base::Bind(&VideoDecoderShim::DecoderImpl::OnDecodeComplete,
+ base::Unretained(this)));
+ pending_decodes_.pop();
}
void VideoDecoderShim::DecoderImpl::OnDecodeComplete(
- uint32_t decode_id,
media::VideoDecoder::Status status) {
- num_decodes_at_decoder_--;
- decode_id_ = decode_id;
+ DCHECK(awaiting_decoder_);
+ awaiting_decoder_ = false;
int32_t result;
switch (status) {
@@ -255,28 +797,20 @@ void VideoDecoderShim::DecoderImpl::OnDecodeComplete(
main_message_loop_->PostTask(
FROM_HERE,
base::Bind(
- &VideoDecoderShim::OnDecodeComplete, shim_, result, decode_id));
+ &VideoDecoderShim::OnDecodeComplete, shim_, result, decode_id_));
DoDecode();
}
void VideoDecoderShim::DecoderImpl::OnOutputComplete(
const scoped_refptr<media::VideoFrame>& frame) {
+ // Software decoders are expected to generated frames only when a Decode()
+ // call is pending.
+ DCHECK(awaiting_decoder_);
+
scoped_ptr<PendingFrame> pending_frame;
if (!frame->end_of_stream()) {
- pending_frame.reset(new PendingFrame(
- decode_id_, frame->coded_size(), frame->visible_rect()));
- // Convert the VideoFrame pixels to ABGR to match VideoDecodeAccelerator.
- libyuv::I420ToABGR(frame->data(media::VideoFrame::kYPlane),
- frame->stride(media::VideoFrame::kYPlane),
- frame->data(media::VideoFrame::kUPlane),
- frame->stride(media::VideoFrame::kUPlane),
- frame->data(media::VideoFrame::kVPlane),
- frame->stride(media::VideoFrame::kVPlane),
- &pending_frame->argb_pixels.front(),
- frame->coded_size().width() * 4,
- frame->coded_size().width(),
- frame->coded_size().height());
+ pending_frame.reset(new PendingFrame(decode_id_, frame));
} else {
pending_frame.reset(new PendingFrame(decode_id_));
}
@@ -301,6 +835,7 @@ VideoDecoderShim::VideoDecoderShim(PepperVideoDecoderHost* host)
RenderThreadImpl::current()->SharedMainThreadContextProvider()),
texture_pool_size_(0),
num_pending_decodes_(0),
+ yuv_converter_(new YUVConverter(context_provider_)),
weak_ptr_factory_(this) {
DCHECK(host_);
DCHECK(media_task_runner_.get());
@@ -344,6 +879,10 @@ bool VideoDecoderShim::Initialize(
codec = media::kCodecVP9;
DCHECK_NE(codec, media::kUnknownVideoCodec);
+ if (!yuv_converter_->Initialize()) {
+ return false;
+ }
+
media::VideoDecoderConfig config(
codec,
profile,
@@ -437,7 +976,7 @@ void VideoDecoderShim::Reset() {
}
void VideoDecoderShim::Destroy() {
- // This will be called, but our destructor does the actual work.
+ delete this;
}
void VideoDecoderShim::OnInitializeComplete(int32_t result,
@@ -476,15 +1015,15 @@ void VideoDecoderShim::OnOutputComplete(scoped_ptr<PendingFrame> frame) {
DCHECK(RenderThreadImpl::current());
DCHECK(host_);
- if (!frame->argb_pixels.empty()) {
- if (texture_size_ != frame->coded_size) {
+ if (frame->video_frame) {
+ if (texture_size_ != frame->video_frame->coded_size()) {
// If the size has changed, all current textures must be dismissed. Add
// all textures to |textures_to_dismiss_| and dismiss any that aren't in
// use by the plugin. We will dismiss the rest as they are recycled.
for (TextureIdMap::const_iterator it = texture_id_map_.begin();
it != texture_id_map_.end();
++it) {
- textures_to_dismiss_.insert(it->second);
+ textures_to_dismiss_.insert(it->first);
}
for (TextureIdSet::const_iterator it = available_textures_.begin();
it != available_textures_.end();
@@ -499,10 +1038,9 @@ void VideoDecoderShim::OnOutputComplete(scoped_ptr<PendingFrame> frame) {
pending_texture_mailboxes_.push_back(gpu::Mailbox::Generate());
host_->RequestTextures(texture_pool_size_,
- frame->coded_size,
- GL_TEXTURE_2D,
+ frame->video_frame->coded_size(), GL_TEXTURE_2D,
pending_texture_mailboxes_);
- texture_size_ = frame->coded_size;
+ texture_size_ = frame->video_frame->coded_size();
}
pending_frames_.push(linked_ptr<PendingFrame>(frame.release()));
@@ -521,21 +1059,12 @@ void VideoDecoderShim::SendPictures() {
available_textures_.erase(it);
uint32_t local_texture_id = texture_id_map_[texture_id];
- gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
- gles2->ActiveTexture(GL_TEXTURE0);
- gles2->BindTexture(GL_TEXTURE_2D, local_texture_id);
- gles2->TexImage2D(GL_TEXTURE_2D,
- 0,
- GL_RGBA,
- texture_size_.width(),
- texture_size_.height(),
- 0,
- GL_RGBA,
- GL_UNSIGNED_BYTE,
- &frame->argb_pixels.front());
-
- host_->PictureReady(
- media::Picture(texture_id, frame->decode_id, frame->visible_rect));
+
+ yuv_converter_->Convert(frame->video_frame, local_texture_id);
+
+ host_->PictureReady(media::Picture(texture_id, frame->decode_id,
+ frame->video_frame->visible_rect(),
+ false));
pending_frames_.pop();
}
diff --git a/chromium/content/renderer/pepper/video_decoder_shim.h b/chromium/content/renderer/pepper/video_decoder_shim.h
index 42335c1f87c..0d71d4b16a2 100644
--- a/chromium/content/renderer/pepper/video_decoder_shim.h
+++ b/chromium/content/renderer/pepper/video_decoder_shim.h
@@ -23,6 +23,10 @@ namespace base {
class SingleThreadTaskRunner;
}
+namespace cc_blink {
+class ContextProviderWebContext;
+}
+
namespace gpu {
namespace gles2 {
class GLES2Interface;
@@ -33,12 +37,6 @@ namespace media {
class DecoderBuffer;
}
-namespace webkit {
-namespace gpu {
-class ContextProviderWebContext;
-}
-}
-
namespace content {
class PepperVideoDecoderHost;
@@ -74,6 +72,7 @@ class VideoDecoderShim : public media::VideoDecodeAccelerator {
struct PendingDecode;
struct PendingFrame;
class DecoderImpl;
+ class YUVConverter;
void OnInitializeComplete(int32_t result, uint32_t texture_pool_size);
void OnDecodeComplete(int32_t result, uint32_t decode_id);
@@ -92,7 +91,7 @@ class VideoDecoderShim : public media::VideoDecodeAccelerator {
PepperVideoDecoderHost* host_;
scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_;
- scoped_refptr<webkit::gpu::ContextProviderWebContext> context_provider_;
+ scoped_refptr<cc_blink::ContextProviderWebContext> context_provider_;
// The current decoded frame size.
gfx::Size texture_size_;
@@ -111,8 +110,7 @@ class VideoDecoderShim : public media::VideoDecodeAccelerator {
typedef std::queue<uint32_t> CompletedDecodeQueue;
CompletedDecodeQueue completed_decodes_;
- // Queue of decoded frames that have been converted to RGB and await upload to
- // a GL texture.
+ // Queue of decoded frames that await rgb->yuv conversion.
typedef std::queue<linked_ptr<PendingFrame> > PendingFrameQueue;
PendingFrameQueue pending_frames_;
@@ -121,6 +119,8 @@ class VideoDecoderShim : public media::VideoDecodeAccelerator {
uint32_t num_pending_decodes_;
+ scoped_ptr<YUVConverter> yuv_converter_;
+
base::WeakPtrFactory<VideoDecoderShim> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(VideoDecoderShim);
diff --git a/chromium/content/renderer/pepper/video_encoder_shim.cc b/chromium/content/renderer/pepper/video_encoder_shim.cc
new file mode 100644
index 00000000000..3fcf261189c
--- /dev/null
+++ b/chromium/content/renderer/pepper/video_encoder_shim.cc
@@ -0,0 +1,402 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/pepper/video_encoder_shim.h"
+
+#include <inttypes.h>
+
+#include <deque>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/memory/scoped_vector.h"
+#include "base/memory/shared_memory.h"
+#include "base/message_loop/message_loop.h"
+#include "content/renderer/pepper/pepper_video_encoder_host.h"
+#include "content/renderer/render_thread_impl.h"
+#include "third_party/libvpx/source/libvpx/vpx/vp8cx.h"
+#include "third_party/libvpx/source/libvpx/vpx/vpx_encoder.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace content {
+
+// TODO(llandwerlin): Libvpx doesn't seem to have a maximum frame size
+// limitation. We currently limit the size of the frames to encode at
+// 1080p (%64 pixels blocks), this seems like a reasonable limit for
+// software encoding.
+const int32_t kMaxWidth = 1920;
+const int32_t kMaxHeight = 1088;
+
+// Default speed for the encoder (same as WebRTC). Increases the CPU
+// usage as the value is more negative (VP8 valid range: -16..16).
+const int32_t kDefaultCpuUsed = -6;
+
+// Default quantizer min/max values.
+const int32_t kDefaultMinQuantizer = 2;
+const int32_t kDefaultMaxQuantizer = 52;
+
+// Bitstream buffer size.
+const uint32_t kBitstreamBufferSize = 2 * 1024 * 1024;
+
+// Number of frames needs at any given time.
+const uint32_t kInputFrameCount = 1;
+
+class VideoEncoderShim::EncoderImpl {
+ public:
+ explicit EncoderImpl(const base::WeakPtr<VideoEncoderShim>& shim);
+ ~EncoderImpl();
+
+ void Initialize(media::VideoFrame::Format input_format,
+ const gfx::Size& input_visible_size,
+ media::VideoCodecProfile output_profile,
+ uint32 initial_bitrate);
+ void Encode(const scoped_refptr<media::VideoFrame>& frame,
+ bool force_keyframe);
+ void UseOutputBitstreamBuffer(const media::BitstreamBuffer& buffer,
+ uint8_t* mem);
+ void RequestEncodingParametersChange(uint32 bitrate, uint32 framerate);
+ void Stop();
+
+ private:
+ struct PendingEncode {
+ PendingEncode(const scoped_refptr<media::VideoFrame>& frame,
+ bool force_keyframe)
+ : frame(frame), force_keyframe(force_keyframe) {}
+ ~PendingEncode() {}
+
+ scoped_refptr<media::VideoFrame> frame;
+ bool force_keyframe;
+ };
+
+ struct BitstreamBuffer {
+ BitstreamBuffer(const media::BitstreamBuffer buffer, uint8_t* mem)
+ : buffer(buffer), mem(mem) {}
+ ~BitstreamBuffer() {}
+
+ media::BitstreamBuffer buffer;
+ uint8_t* mem;
+ };
+
+ void DoEncode();
+ void NotifyError(media::VideoEncodeAccelerator::Error error);
+
+ base::WeakPtr<VideoEncoderShim> shim_;
+ scoped_refptr<base::SingleThreadTaskRunner> renderer_task_runner_;
+
+ bool initialized_;
+
+ // Libvpx internal objects. Only valid if |initialized_| is true.
+ vpx_codec_enc_cfg_t config_;
+ vpx_codec_ctx_t encoder_;
+
+ uint32 framerate_;
+
+ std::deque<PendingEncode> frames_;
+ std::deque<BitstreamBuffer> buffers_;
+};
+
+VideoEncoderShim::EncoderImpl::EncoderImpl(
+ const base::WeakPtr<VideoEncoderShim>& shim)
+ : shim_(shim),
+ renderer_task_runner_(base::MessageLoopProxy::current()),
+ initialized_(false) {
+}
+
+VideoEncoderShim::EncoderImpl::~EncoderImpl() {
+ if (initialized_)
+ vpx_codec_destroy(&encoder_);
+}
+
+void VideoEncoderShim::EncoderImpl::Initialize(
+ media::VideoFrame::Format input_format,
+ const gfx::Size& input_visible_size,
+ media::VideoCodecProfile output_profile,
+ uint32 initial_bitrate) {
+ gfx::Size coded_size =
+ media::VideoFrame::PlaneSize(input_format, 0, input_visible_size);
+
+ // Populate encoder configuration with default values.
+ if (vpx_codec_enc_config_default(vpx_codec_vp8_cx(), &config_, 0) !=
+ VPX_CODEC_OK) {
+ NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
+ return;
+ }
+
+ config_.g_threads = 1;
+ config_.g_w = input_visible_size.width();
+ config_.g_h = input_visible_size.height();
+
+ framerate_ = config_.g_timebase.den;
+
+ config_.g_lag_in_frames = 0;
+ config_.g_timebase.num = 1;
+ config_.g_timebase.den = base::Time::kMicrosecondsPerSecond;
+ config_.rc_target_bitrate = initial_bitrate / 1000;
+ config_.rc_min_quantizer = kDefaultMinQuantizer;
+ config_.rc_max_quantizer = kDefaultMaxQuantizer;
+
+ vpx_codec_flags_t flags = 0;
+ if (vpx_codec_enc_init(&encoder_, vpx_codec_vp8_cx(), &config_, flags) !=
+ VPX_CODEC_OK) {
+ NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
+ return;
+ }
+ initialized_ = true;
+
+ if (vpx_codec_enc_config_set(&encoder_, &config_) != VPX_CODEC_OK) {
+ NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
+ return;
+ }
+
+ if (vpx_codec_control(&encoder_, VP8E_SET_CPUUSED, kDefaultCpuUsed) !=
+ VPX_CODEC_OK) {
+ NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
+ return;
+ }
+
+ renderer_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&VideoEncoderShim::OnRequireBitstreamBuffers, shim_,
+ kInputFrameCount, coded_size, kBitstreamBufferSize));
+}
+
+void VideoEncoderShim::EncoderImpl::Encode(
+ const scoped_refptr<media::VideoFrame>& frame,
+ bool force_keyframe) {
+ frames_.push_back(PendingEncode(frame, force_keyframe));
+ DoEncode();
+}
+
+void VideoEncoderShim::EncoderImpl::UseOutputBitstreamBuffer(
+ const media::BitstreamBuffer& buffer,
+ uint8_t* mem) {
+ buffers_.push_back(BitstreamBuffer(buffer, mem));
+ DoEncode();
+}
+
+void VideoEncoderShim::EncoderImpl::RequestEncodingParametersChange(
+ uint32 bitrate,
+ uint32 framerate) {
+ framerate_ = framerate;
+
+ uint32 bitrate_kbit = bitrate / 1000;
+ if (config_.rc_target_bitrate == bitrate_kbit)
+ return;
+
+ config_.rc_target_bitrate = bitrate_kbit;
+ if (vpx_codec_enc_config_set(&encoder_, &config_) != VPX_CODEC_OK)
+ NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
+}
+
+void VideoEncoderShim::EncoderImpl::Stop() {
+ // Release frames on the renderer thread.
+ while (!frames_.empty()) {
+ PendingEncode frame = frames_.front();
+ frames_.pop_front();
+
+ frame.frame->AddRef();
+ media::VideoFrame* raw_frame = frame.frame.get();
+ frame.frame = nullptr;
+ renderer_task_runner_->ReleaseSoon(FROM_HERE, raw_frame);
+ }
+ buffers_.clear();
+}
+
+void VideoEncoderShim::EncoderImpl::DoEncode() {
+ while (!frames_.empty() && !buffers_.empty()) {
+ PendingEncode frame = frames_.front();
+ frames_.pop_front();
+
+ // Wrapper for vpx_codec_encode() to access the YUV data in the
+ // |video_frame|. Only the VISIBLE rectangle within |video_frame|
+ // is exposed to the codec.
+ vpx_image_t vpx_image;
+ vpx_image_t* const result = vpx_img_wrap(
+ &vpx_image, VPX_IMG_FMT_I420, frame.frame->visible_rect().width(),
+ frame.frame->visible_rect().height(), 1,
+ frame.frame->data(media::VideoFrame::kYPlane));
+ DCHECK_EQ(result, &vpx_image);
+ vpx_image.planes[VPX_PLANE_Y] =
+ frame.frame->visible_data(media::VideoFrame::kYPlane);
+ vpx_image.planes[VPX_PLANE_U] =
+ frame.frame->visible_data(media::VideoFrame::kUPlane);
+ vpx_image.planes[VPX_PLANE_V] =
+ frame.frame->visible_data(media::VideoFrame::kVPlane);
+ vpx_image.stride[VPX_PLANE_Y] =
+ frame.frame->stride(media::VideoFrame::kYPlane);
+ vpx_image.stride[VPX_PLANE_U] =
+ frame.frame->stride(media::VideoFrame::kUPlane);
+ vpx_image.stride[VPX_PLANE_V] =
+ frame.frame->stride(media::VideoFrame::kVPlane);
+
+ vpx_codec_flags_t flags = 0;
+ if (frame.force_keyframe)
+ flags = VPX_EFLAG_FORCE_KF;
+
+ const base::TimeDelta frame_duration =
+ base::TimeDelta::FromSecondsD(1.0 / framerate_);
+ if (vpx_codec_encode(&encoder_, &vpx_image, 0,
+ frame_duration.InMicroseconds(), flags,
+ VPX_DL_REALTIME) != VPX_CODEC_OK) {
+ NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
+ return;
+ }
+
+ const vpx_codec_cx_pkt_t* packet = nullptr;
+ vpx_codec_iter_t iter = nullptr;
+ while ((packet = vpx_codec_get_cx_data(&encoder_, &iter)) != nullptr) {
+ if (packet->kind != VPX_CODEC_CX_FRAME_PKT)
+ continue;
+
+ BitstreamBuffer buffer = buffers_.front();
+ buffers_.pop_front();
+
+ CHECK(buffer.buffer.size() >= packet->data.frame.sz);
+ memcpy(buffer.mem, packet->data.frame.buf, packet->data.frame.sz);
+
+ // Pass the media::VideoFrame back to the renderer thread so it's
+ // freed on the right thread.
+ renderer_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&VideoEncoderShim::OnBitstreamBufferReady, shim_,
+ frame.frame, buffer.buffer.id(),
+ base::checked_cast<size_t>(packet->data.frame.sz),
+ (packet->data.frame.flags & VPX_FRAME_IS_KEY) != 0));
+ break; // Done, since all data is provided in one CX_FRAME_PKT packet.
+ }
+ }
+}
+
+void VideoEncoderShim::EncoderImpl::NotifyError(
+ media::VideoEncodeAccelerator::Error error) {
+ renderer_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&VideoEncoderShim::OnNotifyError, shim_, error));
+ Stop();
+}
+
+VideoEncoderShim::VideoEncoderShim(PepperVideoEncoderHost* host)
+ : host_(host),
+ media_task_runner_(
+ RenderThreadImpl::current()->GetMediaThreadTaskRunner()),
+ weak_ptr_factory_(this) {
+ encoder_impl_.reset(new EncoderImpl(weak_ptr_factory_.GetWeakPtr()));
+}
+
+VideoEncoderShim::~VideoEncoderShim() {
+ DCHECK(RenderThreadImpl::current());
+
+ media_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&VideoEncoderShim::EncoderImpl::Stop,
+ base::Owned(encoder_impl_.release())));
+}
+
+media::VideoEncodeAccelerator::SupportedProfiles
+VideoEncoderShim::GetSupportedProfiles() {
+ media::VideoEncodeAccelerator::SupportedProfiles profiles;
+
+ // Get the default VP8 config from Libvpx.
+ vpx_codec_enc_cfg_t config;
+ vpx_codec_err_t ret =
+ vpx_codec_enc_config_default(vpx_codec_vp8_cx(), &config, 0);
+ if (ret == VPX_CODEC_OK) {
+ media::VideoEncodeAccelerator::SupportedProfile profile;
+ profile.profile = media::VP8PROFILE_ANY;
+ profile.max_resolution = gfx::Size(kMaxWidth, kMaxHeight);
+ // Libvpx and media::VideoEncodeAccelerator are using opposite
+ // notions of denominator/numerator.
+ profile.max_framerate_numerator = config.g_timebase.den;
+ profile.max_framerate_denominator = config.g_timebase.num;
+ profiles.push_back(profile);
+ }
+
+ return profiles;
+}
+
+bool VideoEncoderShim::Initialize(
+ media::VideoFrame::Format input_format,
+ const gfx::Size& input_visible_size,
+ media::VideoCodecProfile output_profile,
+ uint32 initial_bitrate,
+ media::VideoEncodeAccelerator::Client* client) {
+ DCHECK(RenderThreadImpl::current());
+ DCHECK_EQ(client, host_);
+
+ if (input_format != media::VideoFrame::I420)
+ return false;
+
+ media_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&VideoEncoderShim::EncoderImpl::Initialize,
+ base::Unretained(encoder_impl_.get()), input_format,
+ input_visible_size, output_profile, initial_bitrate));
+
+ return true;
+}
+
+void VideoEncoderShim::Encode(const scoped_refptr<media::VideoFrame>& frame,
+ bool force_keyframe) {
+ DCHECK(RenderThreadImpl::current());
+
+ media_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&VideoEncoderShim::EncoderImpl::Encode,
+ base::Unretained(encoder_impl_.get()), frame, force_keyframe));
+}
+
+void VideoEncoderShim::UseOutputBitstreamBuffer(
+ const media::BitstreamBuffer& buffer) {
+ DCHECK(RenderThreadImpl::current());
+
+ media_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&VideoEncoderShim::EncoderImpl::UseOutputBitstreamBuffer,
+ base::Unretained(encoder_impl_.get()), buffer,
+ host_->ShmHandleToAddress(buffer.id())));
+}
+
+void VideoEncoderShim::RequestEncodingParametersChange(uint32 bitrate,
+ uint32 framerate) {
+ DCHECK(RenderThreadImpl::current());
+
+ media_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &VideoEncoderShim::EncoderImpl::RequestEncodingParametersChange,
+ base::Unretained(encoder_impl_.get()), bitrate, framerate));
+}
+
+void VideoEncoderShim::Destroy() {
+ DCHECK(RenderThreadImpl::current());
+
+ delete this;
+}
+
+void VideoEncoderShim::OnRequireBitstreamBuffers(
+ unsigned int input_count,
+ const gfx::Size& input_coded_size,
+ size_t output_buffer_size) {
+ DCHECK(RenderThreadImpl::current());
+
+ host_->RequireBitstreamBuffers(input_count, input_coded_size,
+ output_buffer_size);
+}
+
+void VideoEncoderShim::OnBitstreamBufferReady(
+ scoped_refptr<media::VideoFrame> frame,
+ int32 bitstream_buffer_id,
+ size_t payload_size,
+ bool key_frame) {
+ DCHECK(RenderThreadImpl::current());
+
+ host_->BitstreamBufferReady(bitstream_buffer_id, payload_size, key_frame);
+}
+
+void VideoEncoderShim::OnNotifyError(
+ media::VideoEncodeAccelerator::Error error) {
+ DCHECK(RenderThreadImpl::current());
+
+ host_->NotifyError(error);
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/pepper/video_encoder_shim.h b/chromium/content/renderer/pepper/video_encoder_shim.h
new file mode 100644
index 00000000000..29449ab6273
--- /dev/null
+++ b/chromium/content/renderer/pepper/video_encoder_shim.h
@@ -0,0 +1,76 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_PEPPER_VIDEO_ENCODER_SHIM_H_
+#define CONTENT_RENDERER_PEPPER_VIDEO_ENCODER_SHIM_H_
+
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "media/video/video_encode_accelerator.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+}
+
+namespace gfx {
+class Size;
+}
+
+namespace content {
+
+class PepperVideoEncoderHost;
+
+// This class is a shim to wrap a media::cast::SoftwareVideoEncoder so that it
+// can be used by PepperVideoEncoderHost in place of a
+// media::VideoEncodeAccelerator. This class should be constructed, used, and
+// destructed on the main (render) thread.
+class VideoEncoderShim : public media::VideoEncodeAccelerator {
+ public:
+ explicit VideoEncoderShim(PepperVideoEncoderHost* host);
+ ~VideoEncoderShim() override;
+
+ // media::VideoEncodeAccelerator implementation.
+ media::VideoEncodeAccelerator::SupportedProfiles GetSupportedProfiles()
+ override;
+ bool Initialize(media::VideoFrame::Format input_format,
+ const gfx::Size& input_visible_size,
+ media::VideoCodecProfile output_profile,
+ uint32 initial_bitrate,
+ media::VideoEncodeAccelerator::Client* client) override;
+ void Encode(const scoped_refptr<media::VideoFrame>& frame,
+ bool force_keyframe) override;
+ void UseOutputBitstreamBuffer(const media::BitstreamBuffer& buffer) override;
+ void RequestEncodingParametersChange(uint32 bitrate,
+ uint32 framerate) override;
+ void Destroy() override;
+
+ private:
+ class EncoderImpl;
+
+ void OnRequireBitstreamBuffers(unsigned int input_count,
+ const gfx::Size& input_coded_size,
+ size_t output_buffer_size);
+ void OnBitstreamBufferReady(scoped_refptr<media::VideoFrame> frame,
+ int32 bitstream_buffer_id,
+ size_t payload_size,
+ bool key_frame);
+ void OnNotifyError(media::VideoEncodeAccelerator::Error error);
+
+ scoped_ptr<EncoderImpl> encoder_impl_;
+
+ PepperVideoEncoderHost* host_;
+
+ // Task doing the encoding.
+ scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_;
+
+ base::WeakPtrFactory<VideoEncoderShim> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(VideoEncoderShim);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_PEPPER_VIDEO_ENCODER_SHIM_H_
diff --git a/chromium/content/renderer/presentation/OWNERS b/chromium/content/renderer/presentation/OWNERS
new file mode 100644
index 00000000000..44b349ce215
--- /dev/null
+++ b/chromium/content/renderer/presentation/OWNERS
@@ -0,0 +1,3 @@
+avayvod@chromium.org
+imcheng@chromium.org
+mfoltz@chromium.org \ No newline at end of file
diff --git a/chromium/content/renderer/presentation/presentation_dispatcher.cc b/chromium/content/renderer/presentation/presentation_dispatcher.cc
new file mode 100644
index 00000000000..29f5047f0b5
--- /dev/null
+++ b/chromium/content/renderer/presentation/presentation_dispatcher.cc
@@ -0,0 +1,366 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/presentation/presentation_dispatcher.h"
+
+#include "base/logging.h"
+#include "content/common/presentation/presentation_service.mojom.h"
+#include "content/public/common/presentation_constants.h"
+#include "content/public/common/service_registry.h"
+#include "content/public/renderer/render_frame.h"
+#include "content/renderer/presentation/presentation_session_client.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/platform/modules/presentation/WebPresentationController.h"
+#include "third_party/WebKit/public/platform/modules/presentation/WebPresentationError.h"
+#include "third_party/WebKit/public/web/WebDocument.h"
+#include "third_party/WebKit/public/web/WebLocalFrame.h"
+#include "url/gurl.h"
+
+namespace {
+
+blink::WebPresentationError::ErrorType GetWebPresentationErrorTypeFromMojo(
+ presentation::PresentationErrorType mojoErrorType) {
+ switch (mojoErrorType) {
+ case presentation::PRESENTATION_ERROR_TYPE_NO_AVAILABLE_SCREENS:
+ return blink::WebPresentationError::ErrorTypeNoAvailableScreens;
+ case presentation::PRESENTATION_ERROR_TYPE_SESSION_REQUEST_CANCELLED:
+ return blink::WebPresentationError::ErrorTypeSessionRequestCancelled;
+ case presentation::PRESENTATION_ERROR_TYPE_NO_PRESENTATION_FOUND:
+ return blink::WebPresentationError::ErrorTypeNoPresentationFound;
+ case presentation::PRESENTATION_ERROR_TYPE_UNKNOWN:
+ default:
+ return blink::WebPresentationError::ErrorTypeUnknown;
+ }
+}
+
+blink::WebPresentationSessionState GetWebPresentationSessionStateFromMojo(
+ presentation::PresentationSessionState mojoSessionState) {
+ switch (mojoSessionState) {
+ case presentation::PRESENTATION_SESSION_STATE_CONNECTED:
+ return blink::WebPresentationSessionState::Connected;
+ case presentation::PRESENTATION_SESSION_STATE_DISCONNECTED:
+ return blink::WebPresentationSessionState::Disconnected;
+ }
+
+ NOTREACHED();
+ return blink::WebPresentationSessionState::Disconnected;
+}
+
+GURL GetPresentationURLFromFrame(content::RenderFrame* frame) {
+ DCHECK(frame);
+
+ GURL url(frame->GetWebFrame()->document().defaultPresentationURL());
+ return url.is_valid() ? url : GURL();
+}
+
+} // namespace
+
+namespace content {
+
+PresentationDispatcher::PresentationDispatcher(RenderFrame* render_frame)
+ : RenderFrameObserver(render_frame),
+ controller_(nullptr),
+ binding_(this) {
+}
+
+PresentationDispatcher::~PresentationDispatcher() {
+ // Controller should be destroyed before the dispatcher when frame is
+ // destroyed.
+ DCHECK(!controller_);
+}
+
+void PresentationDispatcher::setController(
+ blink::WebPresentationController* controller) {
+ // There shouldn't be any swapping from one non-null controller to another.
+ DCHECK(controller != controller_ && (!controller || !controller_));
+ controller_ = controller;
+ // The controller is set to null when the frame is about to be detached.
+ // Nothing is listening for screen availability anymore but the Mojo service
+ // will know about the frame being detached anyway.
+}
+
+void PresentationDispatcher::updateAvailableChangeWatched(bool watched) {
+ ConnectToPresentationServiceIfNeeded();
+ if (watched)
+ presentation_service_->ListenForScreenAvailability();
+ else
+ presentation_service_->StopListeningForScreenAvailability();
+}
+
+void PresentationDispatcher::startSession(
+ const blink::WebString& presentationUrl,
+ const blink::WebString& presentationId,
+ blink::WebPresentationSessionClientCallbacks* callback) {
+ DCHECK(callback);
+ ConnectToPresentationServiceIfNeeded();
+
+ // The dispatcher owns the service so |this| will be valid when
+ // OnSessionCreated() is called. |callback| needs to be alive and also needs
+ // to be destroyed so we transfer its ownership to the mojo callback.
+ presentation_service_->StartSession(
+ presentationUrl.utf8(),
+ presentationId.utf8(),
+ base::Bind(&PresentationDispatcher::OnSessionCreated,
+ base::Unretained(this),
+ base::Owned(callback)));
+}
+
+void PresentationDispatcher::joinSession(
+ const blink::WebString& presentationUrl,
+ const blink::WebString& presentationId,
+ blink::WebPresentationSessionClientCallbacks* callback) {
+ DCHECK(callback);
+ ConnectToPresentationServiceIfNeeded();
+
+ // The dispatcher owns the service so |this| will be valid when
+ // OnSessionCreated() is called. |callback| needs to be alive and also needs
+ // to be destroyed so we transfer its ownership to the mojo callback.
+ presentation_service_->JoinSession(
+ presentationUrl.utf8(),
+ presentationId.utf8(),
+ base::Bind(&PresentationDispatcher::OnSessionCreated,
+ base::Unretained(this),
+ base::Owned(callback)));
+}
+
+void PresentationDispatcher::sendString(
+ const blink::WebString& presentationUrl,
+ const blink::WebString& presentationId,
+ const blink::WebString& message) {
+ if (message.utf8().size() > kMaxPresentationSessionMessageSize) {
+ // TODO(crbug.com/459008): Limit the size of individual messages to 64k
+ // for now. Consider throwing DOMException or splitting bigger messages
+ // into smaller chunks later.
+ LOG(WARNING) << "message size exceeded limit!";
+ return;
+ }
+
+ presentation::SessionMessage* session_message =
+ new presentation::SessionMessage();
+ session_message->presentation_url = presentationUrl.utf8();
+ session_message->presentation_id = presentationId.utf8();
+ session_message->type = presentation::PresentationMessageType::
+ PRESENTATION_MESSAGE_TYPE_TEXT;
+ session_message->message = message.utf8();
+
+ message_request_queue_.push(make_linked_ptr(session_message));
+ // Start processing request if only one in the queue.
+ if (message_request_queue_.size() == 1) {
+ const linked_ptr<presentation::SessionMessage>& request =
+ message_request_queue_.front();
+ DoSendMessage(*request);
+ }
+}
+
+void PresentationDispatcher::sendArrayBuffer(
+ const blink::WebString& presentationUrl,
+ const blink::WebString& presentationId,
+ const uint8* data,
+ size_t length) {
+ DCHECK(data);
+ if (length > kMaxPresentationSessionMessageSize) {
+ // TODO(crbug.com/459008): Same as in sendString().
+ LOG(WARNING) << "data size exceeded limit!";
+ return;
+ }
+
+ const std::vector<uint8> vector(data, data + length);
+ presentation::SessionMessage* session_message =
+ new presentation::SessionMessage();
+ session_message->presentation_url = presentationUrl.utf8();
+ session_message->presentation_id = presentationId.utf8();
+ session_message->type = presentation::PresentationMessageType::
+ PRESENTATION_MESSAGE_TYPE_ARRAY_BUFFER;
+ session_message->data = mojo::Array<uint8>::From(vector);
+
+ message_request_queue_.push(make_linked_ptr(session_message));
+ // Start processing request if only one in the queue.
+ if (message_request_queue_.size() == 1) {
+ const linked_ptr<presentation::SessionMessage>& request =
+ message_request_queue_.front();
+ DoSendMessage(*request);
+ }
+}
+
+void PresentationDispatcher::DoSendMessage(
+ const presentation::SessionMessage& session_message) {
+ ConnectToPresentationServiceIfNeeded();
+
+ presentation::SessionMessagePtr message_request(
+ presentation::SessionMessage::New());
+ message_request->presentation_url = session_message.presentation_url;
+ message_request->presentation_id = session_message.presentation_id;
+ message_request->type = session_message.type;
+ if (session_message.type == presentation::PresentationMessageType::
+ PRESENTATION_MESSAGE_TYPE_TEXT) {
+ message_request->message = session_message.message;
+ } else if (session_message.type == presentation::PresentationMessageType::
+ PRESENTATION_MESSAGE_TYPE_ARRAY_BUFFER) {
+ message_request->data = mojo::Array<uint8>::From(
+ session_message.data.storage());
+ }
+
+ presentation_service_->SendSessionMessage(
+ message_request.Pass(),
+ base::Bind(&PresentationDispatcher::HandleSendMessageRequests,
+ base::Unretained(this)));
+}
+
+void PresentationDispatcher::HandleSendMessageRequests(bool success) {
+ // In normal cases, message_request_queue_ should not be empty at this point
+ // of time, but when DidCommitProvisionalLoad() is invoked before receiving
+ // the callback for previous send mojo call, queue would have been emptied.
+ if (message_request_queue_.empty())
+ return;
+
+ if (!success) {
+ // PresentationServiceImpl is informing that Frame has been detached or
+ // navigated away. Invalidate all pending requests.
+ MessageRequestQueue empty;
+ std::swap(message_request_queue_, empty);
+ return;
+ }
+
+ message_request_queue_.pop();
+ if (!message_request_queue_.empty()) {
+ const linked_ptr<presentation::SessionMessage>& request =
+ message_request_queue_.front();
+ DoSendMessage(*request);
+ }
+}
+
+void PresentationDispatcher::closeSession(
+ const blink::WebString& presentationUrl,
+ const blink::WebString& presentationId) {
+ ConnectToPresentationServiceIfNeeded();
+
+ presentation_service_->CloseSession(
+ presentationUrl.utf8(),
+ presentationId.utf8());
+}
+
+void PresentationDispatcher::DidChangeDefaultPresentation() {
+ GURL presentation_url(GetPresentationURLFromFrame(render_frame()));
+
+ ConnectToPresentationServiceIfNeeded();
+ presentation_service_->SetDefaultPresentationURL(
+ presentation_url.spec(), mojo::String());
+}
+
+void PresentationDispatcher::DidCommitProvisionalLoad(
+ bool is_new_navigation,
+ bool is_same_page_navigation) {
+ blink::WebFrame* frame = render_frame()->GetWebFrame();
+ // If not top-level navigation.
+ if (frame->parent() || is_same_page_navigation)
+ return;
+
+ // Remove all pending send message requests.
+ MessageRequestQueue empty;
+ std::swap(message_request_queue_, empty);
+}
+
+void PresentationDispatcher::OnScreenAvailabilityUpdated(bool available) {
+ if (controller_)
+ controller_->didChangeAvailability(available);
+}
+
+void PresentationDispatcher::OnDefaultSessionStarted(
+ presentation::PresentationSessionInfoPtr session_info) {
+ if (!controller_)
+ return;
+
+ // Reset the callback to get the next event.
+ presentation_service_->ListenForDefaultSessionStart(base::Bind(
+ &PresentationDispatcher::OnDefaultSessionStarted,
+ base::Unretained(this)));
+
+ if (!session_info.is_null()) {
+ controller_->didStartDefaultSession(
+ new PresentationSessionClient(session_info.Pass()));
+ }
+}
+
+void PresentationDispatcher::OnSessionCreated(
+ blink::WebPresentationSessionClientCallbacks* callback,
+ presentation::PresentationSessionInfoPtr session_info,
+ presentation::PresentationErrorPtr error) {
+ DCHECK(callback);
+ if (!error.is_null()) {
+ DCHECK(session_info.is_null());
+ callback->onError(new blink::WebPresentationError(
+ GetWebPresentationErrorTypeFromMojo(error->error_type),
+ blink::WebString::fromUTF8(error->message)));
+ return;
+ }
+
+ DCHECK(!session_info.is_null());
+ callback->onSuccess(new PresentationSessionClient(session_info.Pass()));
+}
+
+void PresentationDispatcher::OnSessionStateChange(
+ presentation::PresentationSessionInfoPtr session_info,
+ presentation::PresentationSessionState session_state) {
+ if (!controller_)
+ return;
+
+ presentation_service_->ListenForSessionStateChange(base::Bind(
+ &PresentationDispatcher::OnSessionStateChange,
+ base::Unretained(this)));
+
+ DCHECK(!session_info.is_null());
+ controller_->didChangeSessionState(
+ new PresentationSessionClient(session_info.Pass()),
+ GetWebPresentationSessionStateFromMojo(session_state));
+}
+
+void PresentationDispatcher::OnSessionMessagesReceived(
+ mojo::Array<presentation::SessionMessagePtr> messages) {
+ // When messages is null, there is an error at presentation service side.
+ if (!controller_ || messages.is_null())
+ return;
+
+ for (size_t i = 0; i < messages.size(); ++i) {
+ if (messages[i]->type ==
+ presentation::PresentationMessageType::PRESENTATION_MESSAGE_TYPE_TEXT) {
+ controller_->didReceiveSessionTextMessage(
+ new PresentationSessionClient(messages[i]->presentation_url,
+ messages[i]->presentation_id),
+ blink::WebString::fromUTF8(messages[i]->message));
+ } else {
+ // TODO(haibinlu): handle binary message
+ }
+ }
+
+ presentation_service_->ListenForSessionMessages(
+ base::Bind(&PresentationDispatcher::OnSessionMessagesReceived,
+ base::Unretained(this)));
+}
+
+void PresentationDispatcher::ConnectToPresentationServiceIfNeeded() {
+ if (presentation_service_.get())
+ return;
+
+ render_frame()->GetServiceRegistry()->ConnectToRemoteService(
+ &presentation_service_);
+ presentation::PresentationServiceClientPtr client_ptr;
+ binding_.Bind(GetProxy(&client_ptr));
+ presentation_service_->SetClient(client_ptr.Pass());
+
+ // TODO(imcheng): Uncomment these once they are implemented on the browser
+ // side. (crbug.com/459006)
+ /*
+ presentation_service_->ListenForDefaultSessionStart(base::Bind(
+ &PresentationDispatcher::OnDefaultSessionStarted,
+ base::Unretained(this)));
+ presentation_service_->ListenForSessionStateChange(base::Bind(
+ &PresentationDispatcher::OnSessionStateChange,
+ base::Unretained(this)));
+ presentation_service_->ListenForSessionMessages(
+ base::Bind(&PresentationDispatcher::OnSessionMessagesReceived,
+ base::Unretained(this)));
+ */
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/presentation/presentation_dispatcher.h b/chromium/content/renderer/presentation/presentation_dispatcher.h
new file mode 100644
index 00000000000..89f6b9f1305
--- /dev/null
+++ b/chromium/content/renderer/presentation/presentation_dispatcher.h
@@ -0,0 +1,98 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_PRESENTATION_PRESENTATION_DISPATCHER_H_
+#define CONTENT_RENDERER_PRESENTATION_PRESENTATION_DISPATCHER_H_
+
+#include "base/compiler_specific.h"
+#include "base/memory/linked_ptr.h"
+#include "content/common/content_export.h"
+#include "content/common/presentation/presentation_service.mojom.h"
+#include "content/public/renderer/render_frame_observer.h"
+#include "third_party/WebKit/public/platform/modules/presentation/WebPresentationClient.h"
+
+namespace blink {
+class WebString;
+} // namespace blink
+
+namespace content {
+
+// PresentationDispatcher is a delegate for Presentation API messages used by
+// Blink. It forwards the calls to the Mojo PresentationService.
+class CONTENT_EXPORT PresentationDispatcher
+ : public RenderFrameObserver,
+ public NON_EXPORTED_BASE(blink::WebPresentationClient),
+ public NON_EXPORTED_BASE(presentation::PresentationServiceClient) {
+ public:
+ explicit PresentationDispatcher(RenderFrame* render_frame);
+ ~PresentationDispatcher() override;
+
+ private:
+ // WebPresentationClient implementation.
+ virtual void setController(
+ blink::WebPresentationController* controller);
+ virtual void updateAvailableChangeWatched(bool watched);
+ virtual void startSession(
+ const blink::WebString& presentationUrl,
+ const blink::WebString& presentationId,
+ blink::WebPresentationSessionClientCallbacks* callback);
+ virtual void joinSession(
+ const blink::WebString& presentationUrl,
+ const blink::WebString& presentationId,
+ blink::WebPresentationSessionClientCallbacks* callback);
+ virtual void sendString(
+ const blink::WebString& presentationUrl,
+ const blink::WebString& presentationId,
+ const blink::WebString& message);
+ virtual void sendArrayBuffer(
+ const blink::WebString& presentationUrl,
+ const blink::WebString& presentationId,
+ const uint8* data,
+ size_t length);
+ virtual void closeSession(
+ const blink::WebString& presentationUrl,
+ const blink::WebString& presentationId);
+
+ // RenderFrameObserver implementation.
+ void DidChangeDefaultPresentation() override;
+ void DidCommitProvisionalLoad(
+ bool is_new_navigation,
+ bool is_same_page_navigation) override;
+
+ // presentation::PresentationServiceClient
+ void OnScreenAvailabilityUpdated(bool available) override;
+
+ void OnSessionCreated(
+ blink::WebPresentationSessionClientCallbacks* callback,
+ presentation::PresentationSessionInfoPtr session_info,
+ presentation::PresentationErrorPtr error);
+ void OnDefaultSessionStarted(
+ presentation::PresentationSessionInfoPtr session_info);
+ void OnSessionStateChange(
+ presentation::PresentationSessionInfoPtr session_info,
+ presentation::PresentationSessionState session_state);
+ void OnSessionMessagesReceived(
+ mojo::Array<presentation::SessionMessagePtr> messages);
+ void DoSendMessage(const presentation::SessionMessage& session_message);
+ void HandleSendMessageRequests(bool success);
+
+ void ConnectToPresentationServiceIfNeeded();
+
+ // Used as a weak reference. Can be null since lifetime is bound to the frame.
+ blink::WebPresentationController* controller_;
+ presentation::PresentationServicePtr presentation_service_;
+ mojo::Binding<presentation::PresentationServiceClient> binding_;
+
+ // Message requests are queued here and only one message at a time is sent
+ // over mojo channel.
+ using MessageRequestQueue =
+ std::queue<linked_ptr<presentation::SessionMessage>>;
+ MessageRequestQueue message_request_queue_;
+
+ DISALLOW_COPY_AND_ASSIGN(PresentationDispatcher);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_PRESENTATION_PRESENTATION_DISPATCHER_H_
diff --git a/chromium/content/renderer/presentation/presentation_session_client.cc b/chromium/content/renderer/presentation/presentation_session_client.cc
new file mode 100644
index 00000000000..be8c754d894
--- /dev/null
+++ b/chromium/content/renderer/presentation/presentation_session_client.cc
@@ -0,0 +1,35 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/presentation/presentation_session_client.h"
+
+#include "base/logging.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+
+namespace content {
+
+PresentationSessionClient::PresentationSessionClient(
+ presentation::PresentationSessionInfoPtr session_info)
+ : url_(blink::WebString::fromUTF8(session_info->url)),
+ id_(blink::WebString::fromUTF8(session_info->id)) {
+}
+
+PresentationSessionClient::PresentationSessionClient(const mojo::String& url,
+ const mojo::String& id)
+ : url_(blink::WebString::fromUTF8(url)),
+ id_(blink::WebString::fromUTF8(id)) {
+}
+
+PresentationSessionClient::~PresentationSessionClient() {
+}
+
+blink::WebString PresentationSessionClient::getUrl() {
+ return url_;
+}
+
+blink::WebString PresentationSessionClient::getId() {
+ return id_;
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/presentation/presentation_session_client.h b/chromium/content/renderer/presentation/presentation_session_client.h
new file mode 100644
index 00000000000..3f2bb20216d
--- /dev/null
+++ b/chromium/content/renderer/presentation/presentation_session_client.h
@@ -0,0 +1,37 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_PRESENTATION_PRESENTATION_SESSION_CLIENT_H_
+#define CONTENT_RENDERER_PRESENTATION_PRESENTATION_SESSION_CLIENT_H_
+
+#include "base/compiler_specific.h"
+#include "content/common/content_export.h"
+#include "content/common/presentation/presentation_service.mojom.h"
+#include "third_party/WebKit/public/platform/modules/presentation/WebPresentationSessionClient.h"
+
+namespace content {
+
+// PresentationSessionClient is passed to the Blink layer if presentation
+// session has been created successfully. Owned by the callback.
+class CONTENT_EXPORT PresentationSessionClient
+ : public NON_EXPORTED_BASE(blink::WebPresentationSessionClient) {
+ public:
+ explicit PresentationSessionClient(
+ presentation::PresentationSessionInfoPtr session_info);
+ explicit PresentationSessionClient(const mojo::String& url,
+ const mojo::String& id);
+ ~PresentationSessionClient() override;
+
+ // WebPresentationSessionClient implementation.
+ virtual blink::WebString getUrl();
+ virtual blink::WebString getId();
+
+ private:
+ blink::WebString url_;
+ blink::WebString id_;
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_PRESENTATION_PRESENTATION_SESSION_CLIENT_H_
diff --git a/chromium/content/renderer/push_messaging/OWNERS b/chromium/content/renderer/push_messaging/OWNERS
new file mode 100644
index 00000000000..d09ffef01de
--- /dev/null
+++ b/chromium/content/renderer/push_messaging/OWNERS
@@ -0,0 +1 @@
+file://content/browser/push_messaging/OWNERS
diff --git a/chromium/content/renderer/push_messaging/push_messaging_dispatcher.cc b/chromium/content/renderer/push_messaging/push_messaging_dispatcher.cc
new file mode 100644
index 00000000000..1ef6fb8876c
--- /dev/null
+++ b/chromium/content/renderer/push_messaging/push_messaging_dispatcher.cc
@@ -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.
+
+#include "content/renderer/push_messaging/push_messaging_dispatcher.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "content/child/service_worker/web_service_worker_registration_impl.h"
+#include "content/common/push_messaging_messages.h"
+#include "content/renderer/manifest/manifest_manager.h"
+#include "content/renderer/render_frame_impl.h"
+#include "ipc/ipc_message.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerRegistration.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/platform/modules/push_messaging/WebPushError.h"
+#include "third_party/WebKit/public/platform/modules/push_messaging/WebPushSubscription.h"
+#include "third_party/WebKit/public/platform/modules/push_messaging/WebPushSubscriptionOptions.h"
+#include "third_party/WebKit/public/web/WebConsoleMessage.h"
+#include "third_party/WebKit/public/web/WebLocalFrame.h"
+#include "url/gurl.h"
+
+using blink::WebString;
+
+namespace content {
+
+const char kManifestDeprecationWarning[] =
+ "The 'gcm_user_visible_only' manifest key is deprecated and will be "
+ "removed in Chrome 45, around August 2015. Use pushManager.subscribe({"
+ "userVisibleOnly: true}) instead. See https://goo.gl/RHFwWx for more "
+ "details.";
+
+PushMessagingDispatcher::PushMessagingDispatcher(RenderFrame* render_frame)
+ : RenderFrameObserver(render_frame) {
+}
+
+PushMessagingDispatcher::~PushMessagingDispatcher() {}
+
+bool PushMessagingDispatcher::OnMessageReceived(const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(PushMessagingDispatcher, message)
+ IPC_MESSAGE_HANDLER(PushMessagingMsg_RegisterFromDocumentSuccess,
+ OnRegisterFromDocumentSuccess)
+ IPC_MESSAGE_HANDLER(PushMessagingMsg_RegisterFromDocumentError,
+ OnRegisterFromDocumentError)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void PushMessagingDispatcher::subscribe(
+ blink::WebServiceWorkerRegistration* service_worker_registration,
+ const blink::WebPushSubscriptionOptions& options,
+ blink::WebPushSubscriptionCallbacks* callbacks) {
+ DCHECK(service_worker_registration);
+ DCHECK(callbacks);
+ RenderFrameImpl::FromRoutingID(routing_id())
+ ->manifest_manager()
+ ->GetManifest(base::Bind(&PushMessagingDispatcher::DoSubscribe,
+ base::Unretained(this),
+ service_worker_registration,
+ options,
+ callbacks));
+}
+
+void PushMessagingDispatcher::DoSubscribe(
+ blink::WebServiceWorkerRegistration* service_worker_registration,
+ const blink::WebPushSubscriptionOptions& options,
+ blink::WebPushSubscriptionCallbacks* callbacks,
+ const Manifest& manifest) {
+ int request_id = subscription_callbacks_.Add(callbacks);
+ int64_t service_worker_registration_id =
+ static_cast<WebServiceWorkerRegistrationImpl*>(
+ service_worker_registration)->registration_id();
+
+ std::string sender_id =
+ manifest.gcm_sender_id.is_null()
+ ? std::string()
+ : base::UTF16ToUTF8(manifest.gcm_sender_id.string());
+ if (sender_id.empty()) {
+ OnRegisterFromDocumentError(request_id,
+ PUSH_REGISTRATION_STATUS_NO_SENDER_ID);
+ return;
+ }
+
+ // Support for the "gcm_user_visible_only" Manifest key has been deprecated
+ // in favor of the userVisibleOnly subscription option, and will be removed
+ // in a future Chrome release. Inform developers of this deprecation.
+ if (manifest.gcm_user_visible_only && !options.userVisibleOnly) {
+ blink::WebConsoleMessage message(
+ blink::WebConsoleMessage::LevelWarning,
+ blink::WebString::fromUTF8(kManifestDeprecationWarning));
+
+ render_frame()->GetWebFrame()->addMessageToConsole(message);
+ }
+
+ const bool user_visible = manifest.gcm_user_visible_only ||
+ options.userVisibleOnly;
+
+ Send(new PushMessagingHostMsg_RegisterFromDocument(
+ routing_id(), request_id,
+ manifest.gcm_sender_id.is_null()
+ ? std::string()
+ : base::UTF16ToUTF8(manifest.gcm_sender_id.string()),
+ user_visible, service_worker_registration_id));
+}
+
+void PushMessagingDispatcher::OnRegisterFromDocumentSuccess(
+ int32_t request_id,
+ const GURL& endpoint,
+ const std::string& registration_id) {
+ blink::WebPushSubscriptionCallbacks* callbacks =
+ subscription_callbacks_.Lookup(request_id);
+ DCHECK(callbacks);
+
+ scoped_ptr<blink::WebPushSubscription> subscription(
+ new blink::WebPushSubscription(
+ WebString::fromUTF8(endpoint.spec()),
+ WebString::fromUTF8(registration_id)));
+ callbacks->onSuccess(subscription.release());
+
+ subscription_callbacks_.Remove(request_id);
+}
+
+void PushMessagingDispatcher::OnRegisterFromDocumentError(
+ int32_t request_id,
+ PushRegistrationStatus status) {
+ blink::WebPushSubscriptionCallbacks* callbacks =
+ subscription_callbacks_.Lookup(request_id);
+ DCHECK(callbacks);
+
+ scoped_ptr<blink::WebPushError> error(new blink::WebPushError(
+ blink::WebPushError::ErrorTypeAbort,
+ WebString::fromUTF8(PushRegistrationStatusToString(status))));
+ callbacks->onError(error.release());
+
+ subscription_callbacks_.Remove(request_id);
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/push_messaging/push_messaging_dispatcher.h b/chromium/content/renderer/push_messaging/push_messaging_dispatcher.h
new file mode 100644
index 00000000000..56eaa852820
--- /dev/null
+++ b/chromium/content/renderer/push_messaging/push_messaging_dispatcher.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_RENDERER_PUSH_MESSAGING_PUSH_MESSAGING_DISPATCHER_H_
+#define CONTENT_RENDERER_PUSH_MESSAGING_PUSH_MESSAGING_DISPATCHER_H_
+
+#include <stdint.h>
+#include <string>
+
+#include "base/id_map.h"
+#include "content/public/common/push_messaging_status.h"
+#include "content/public/renderer/render_frame_observer.h"
+#include "third_party/WebKit/public/platform/modules/push_messaging/WebPushClient.h"
+#include "third_party/WebKit/public/platform/modules/push_messaging/WebPushPermissionStatus.h"
+
+class GURL;
+
+namespace blink {
+struct WebPushSubscriptionOptions;
+}
+
+namespace IPC {
+class Message;
+} // namespace IPC
+
+namespace content {
+
+struct Manifest;
+
+class PushMessagingDispatcher : public RenderFrameObserver,
+ public blink::WebPushClient {
+ public:
+ explicit PushMessagingDispatcher(RenderFrame* render_frame);
+ virtual ~PushMessagingDispatcher();
+
+ private:
+ // RenderFrame::Observer implementation.
+ bool OnMessageReceived(const IPC::Message& message) override;
+
+ // WebPushClient implementation.
+ virtual void subscribe(
+ blink::WebServiceWorkerRegistration* service_worker_registration,
+ const blink::WebPushSubscriptionOptions& options,
+ blink::WebPushSubscriptionCallbacks* callbacks);
+
+ void DoSubscribe(
+ blink::WebServiceWorkerRegistration* service_worker_registration,
+ const blink::WebPushSubscriptionOptions& options,
+ blink::WebPushSubscriptionCallbacks* callbacks,
+ const Manifest& manifest);
+
+ void OnRegisterFromDocumentSuccess(int32_t request_id,
+ const GURL& endpoint,
+ const std::string& registration_id);
+
+ void OnRegisterFromDocumentError(int32_t request_id,
+ PushRegistrationStatus status);
+
+ IDMap<blink::WebPushSubscriptionCallbacks, IDMapOwnPointer>
+ subscription_callbacks_;
+
+ DISALLOW_COPY_AND_ASSIGN(PushMessagingDispatcher);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_PUSH_MESSAGING_PUSH_MESSAGING_DISPATCHER_H_
diff --git a/chromium/content/renderer/push_messaging_dispatcher.cc b/chromium/content/renderer/push_messaging_dispatcher.cc
deleted file mode 100644
index e387d3972d9..00000000000
--- a/chromium/content/renderer/push_messaging_dispatcher.cc
+++ /dev/null
@@ -1,136 +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/renderer/push_messaging_dispatcher.h"
-
-#include "base/strings/utf_string_conversions.h"
-#include "content/child/service_worker/web_service_worker_provider_impl.h"
-#include "content/common/push_messaging_messages.h"
-#include "content/renderer/manifest/manifest_manager.h"
-#include "content/renderer/render_frame_impl.h"
-#include "ipc/ipc_message.h"
-#include "third_party/WebKit/public/platform/WebPushError.h"
-#include "third_party/WebKit/public/platform/WebPushRegistration.h"
-#include "third_party/WebKit/public/platform/WebServiceWorkerProvider.h"
-#include "third_party/WebKit/public/platform/WebString.h"
-#include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
-#include "url/gurl.h"
-
-using blink::WebString;
-
-namespace content {
-
-PushMessagingDispatcher::PushMessagingDispatcher(RenderFrame* render_frame)
- : RenderFrameObserver(render_frame) {
-}
-
-PushMessagingDispatcher::~PushMessagingDispatcher() {}
-
-bool PushMessagingDispatcher::OnMessageReceived(const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(PushMessagingDispatcher, message)
- IPC_MESSAGE_HANDLER(PushMessagingMsg_RegisterSuccess, OnRegisterSuccess)
- IPC_MESSAGE_HANDLER(PushMessagingMsg_RegisterError, OnRegisterError)
- IPC_MESSAGE_HANDLER(PushMessagingMsg_PermissionStatusResult,
- OnPermissionStatus)
- IPC_MESSAGE_HANDLER(PushMessagingMsg_PermissionStatusFailure,
- OnPermissionStatusFailure)
-
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-void PushMessagingDispatcher::registerPushMessaging(
- blink::WebPushRegistrationCallbacks* callbacks,
- blink::WebServiceWorkerProvider* service_worker_provider) {
- RenderFrameImpl::FromRoutingID(routing_id())->manifest_manager()->GetManifest(
- base::Bind(&PushMessagingDispatcher::DoRegister,
- base::Unretained(this),
- callbacks,
- service_worker_provider));
-}
-
-void PushMessagingDispatcher::DoRegister(
- blink::WebPushRegistrationCallbacks* callbacks,
- blink::WebServiceWorkerProvider* service_worker_provider,
- const Manifest& manifest) {
- DCHECK(callbacks);
- int callbacks_id = registration_callbacks_.Add(callbacks);
- int service_worker_provider_id = static_cast<WebServiceWorkerProviderImpl*>(
- service_worker_provider)->provider_id();
-
- std::string sender_id = manifest.gcm_sender_id.is_null()
- ? std::string() : base::UTF16ToUTF8(manifest.gcm_sender_id.string());
- if (sender_id.empty()) {
- OnRegisterError(callbacks_id, PUSH_REGISTRATION_STATUS_NO_SENDER_ID);
- return;
- }
-
- Send(new PushMessagingHostMsg_Register(
- routing_id(),
- callbacks_id,
- manifest.gcm_sender_id.is_null()
- ? std::string()
- : base::UTF16ToUTF8(manifest.gcm_sender_id.string()),
- blink::WebUserGestureIndicator::isProcessingUserGesture(),
- service_worker_provider_id));
-}
-
-void PushMessagingDispatcher::getPermissionStatus(
- blink::WebPushPermissionStatusCallback* callback,
- blink::WebServiceWorkerProvider* service_worker_provider) {
- int permission_callback_id = permission_check_callbacks_.Add(callback);
- int service_worker_provider_id = static_cast<WebServiceWorkerProviderImpl*>(
- service_worker_provider)->provider_id();
- Send(new PushMessagingHostMsg_PermissionStatus(
- routing_id(), service_worker_provider_id, permission_callback_id));
-}
-
-void PushMessagingDispatcher::OnRegisterSuccess(
- int32 callbacks_id,
- const GURL& endpoint,
- const std::string& registration_id) {
- blink::WebPushRegistrationCallbacks* callbacks =
- registration_callbacks_.Lookup(callbacks_id);
- CHECK(callbacks);
-
- scoped_ptr<blink::WebPushRegistration> registration(
- new blink::WebPushRegistration(
- WebString::fromUTF8(endpoint.spec()),
- WebString::fromUTF8(registration_id)));
- callbacks->onSuccess(registration.release());
- registration_callbacks_.Remove(callbacks_id);
-}
-
-void PushMessagingDispatcher::OnRegisterError(int32 callbacks_id,
- PushRegistrationStatus status) {
- blink::WebPushRegistrationCallbacks* callbacks =
- registration_callbacks_.Lookup(callbacks_id);
- CHECK(callbacks);
-
- scoped_ptr<blink::WebPushError> error(new blink::WebPushError(
- blink::WebPushError::ErrorTypeAbort,
- WebString::fromUTF8(PushRegistrationStatusToString(status))));
- callbacks->onError(error.release());
- registration_callbacks_.Remove(callbacks_id);
-}
-
-void PushMessagingDispatcher::OnPermissionStatus(
- int32 callback_id,
- blink::WebPushPermissionStatus status) {
- blink::WebPushPermissionStatusCallback* callback =
- permission_check_callbacks_.Lookup(callback_id);
- callback->onSuccess(&status);
- permission_check_callbacks_.Remove(callback_id);
-}
-
-void PushMessagingDispatcher::OnPermissionStatusFailure(int32 callback_id) {
- blink::WebPushPermissionStatusCallback* callback =
- permission_check_callbacks_.Lookup(callback_id);
- callback->onError();
- permission_check_callbacks_.Remove(callback_id);
-}
-
-} // namespace content
diff --git a/chromium/content/renderer/push_messaging_dispatcher.h b/chromium/content/renderer/push_messaging_dispatcher.h
deleted file mode 100644
index 6c472dd96b2..00000000000
--- a/chromium/content/renderer/push_messaging_dispatcher.h
+++ /dev/null
@@ -1,72 +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_RENDERER_PUSH_MESSAGING_DISPATCHER_H_
-#define CONTENT_RENDERER_PUSH_MESSAGING_DISPATCHER_H_
-
-#include <string>
-
-#include "base/id_map.h"
-#include "content/public/common/push_messaging_status.h"
-#include "content/public/renderer/render_frame_observer.h"
-#include "third_party/WebKit/public/platform/WebPushClient.h"
-#include "third_party/WebKit/public/platform/WebPushPermissionStatus.h"
-
-class GURL;
-
-namespace IPC {
-class Message;
-} // namespace IPC
-
-namespace blink {
-class WebServiceWorkerProvider;
-} // namespace blink
-
-namespace content {
-
-struct Manifest;
-
-class PushMessagingDispatcher : public RenderFrameObserver,
- public blink::WebPushClient {
- public:
- explicit PushMessagingDispatcher(RenderFrame* render_frame);
- virtual ~PushMessagingDispatcher();
-
- private:
- // RenderFrame::Observer implementation.
- bool OnMessageReceived(const IPC::Message& message) override;
-
- // WebPushClient implementation.
- virtual void registerPushMessaging(
- blink::WebPushRegistrationCallbacks* callbacks,
- blink::WebServiceWorkerProvider* service_worker_provider); // override
- virtual void getPermissionStatus(
- blink::WebPushPermissionStatusCallback* callback,
- blink::WebServiceWorkerProvider* service_worker_provider); // override
-
- void DoRegister(blink::WebPushRegistrationCallbacks* callbacks,
- blink::WebServiceWorkerProvider* service_worker_provider,
- const Manifest& manifest);
-
- void OnRegisterSuccess(int32 callbacks_id,
- const GURL& endpoint,
- const std::string& registration_id);
-
- void OnRegisterError(int32 callbacks_id, PushRegistrationStatus status);
-
- void OnPermissionStatus(int32 callback_id,
- blink::WebPushPermissionStatus status);
- void OnPermissionStatusFailure(int32 callback_id);
-
- IDMap<blink::WebPushRegistrationCallbacks, IDMapOwnPointer>
- registration_callbacks_;
- IDMap<blink::WebPushPermissionStatusCallback, IDMapOwnPointer>
- permission_check_callbacks_;
-
- DISALLOW_COPY_AND_ASSIGN(PushMessagingDispatcher);
-};
-
-} // namespace content
-
-#endif // CONTENT_RENDERER_PUSH_MESSAGING_DISPATCHER_H_
diff --git a/chromium/content/renderer/push_permission_dispatcher.cc b/chromium/content/renderer/push_permission_dispatcher.cc
deleted file mode 100644
index d5ced151a9b..00000000000
--- a/chromium/content/renderer/push_permission_dispatcher.cc
+++ /dev/null
@@ -1,48 +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/renderer/push_permission_dispatcher.h"
-
-#include "content/common/push_messaging_messages.h"
-#include "content/renderer/render_frame_impl.h"
-#include "ipc/ipc_message.h"
-#include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
-
-namespace content {
-
-PushPermissionDispatcher::PushPermissionDispatcher(RenderFrame* render_frame)
- : RenderFrameObserver(render_frame) {
-}
-
-PushPermissionDispatcher::~PushPermissionDispatcher() {
-}
-
-void PushPermissionDispatcher::RequestPermission(blink::WebCallback* callback) {
- DCHECK(callback);
- int request_id = callbacks_.Add(callback);
- Send(new PushMessagingHostMsg_RequestPermission(
- routing_id(),
- request_id,
- blink::WebUserGestureIndicator::isProcessingUserGesture()));
-}
-
-bool PushPermissionDispatcher::OnMessageReceived(const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(PushPermissionDispatcher, message)
- IPC_MESSAGE_HANDLER(PushMessagingMsg_RequestPermissionResponse,
- OnRequestPermissionResponse)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-void PushPermissionDispatcher::OnRequestPermissionResponse(int32 request_id) {
- blink::WebCallback* callback = callbacks_.Lookup(request_id);
- CHECK(callback);
-
- callback->run();
- callbacks_.Remove(request_id);
-}
-
-} // namespace content
diff --git a/chromium/content/renderer/push_permission_dispatcher.h b/chromium/content/renderer/push_permission_dispatcher.h
deleted file mode 100644
index b4bb3bcd594..00000000000
--- a/chromium/content/renderer/push_permission_dispatcher.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_RENDERER_PUSH_PERMISSION_DISPATCHER_H_
-#define CONTENT_RENDERER_PUSH_PERMISSION_DISPATCHER_H_
-
-#include "base/id_map.h"
-#include "content/public/renderer/render_frame_observer.h"
-#include "ipc/ipc_message.h"
-#include "third_party/WebKit/public/platform/WebCallback.h"
-
-namespace content {
-
-// Dispatcher for Push API permission requests.
-class PushPermissionDispatcher : public RenderFrameObserver {
- public:
- explicit PushPermissionDispatcher(RenderFrame* render_frame);
- ~PushPermissionDispatcher() override;
-
- // Requests permission to use the Push API for |origin|. The callback
- // will be invoked when the permission status is available. This class will
- // take ownership of |callback|.
- void RequestPermission(blink::WebCallback* callback);
-
- private:
- // RenderFrame::Observer implementation.
- bool OnMessageReceived(const IPC::Message& message) override;
-
- void OnRequestPermissionResponse(int32 request_id);
-
- // Tracks the active permission requests. This class takes ownership of the
- // callback objects.
- IDMap<blink::WebCallback, IDMapOwnPointer> callbacks_;
-
- DISALLOW_COPY_AND_ASSIGN(PushPermissionDispatcher);
-};
-
-} // namespace content
-
-#endif // CONTENT_RENDERER_PUSH_PERMISSION_DISPATCHER_H_
diff --git a/chromium/content/renderer/render_font_warmup_win.cc b/chromium/content/renderer/render_font_warmup_win.cc
index 90bbab220bb..3fc90f19003 100644
--- a/chromium/content/renderer/render_font_warmup_win.cc
+++ b/chromium/content/renderer/render_font_warmup_win.cc
@@ -10,7 +10,7 @@
#include "base/logging.h"
#include "base/win/iat_patch_function.h"
#include "base/win/windows_version.h"
-#include "content/renderer/renderer_font_platform_win.h"
+#include "content/public/common/dwrite_font_platform_win.h"
#include "third_party/WebKit/public/web/win/WebFontRendering.h"
#include "third_party/skia/include/core/SkPaint.h"
#include "third_party/skia/include/ports/SkFontMgr.h"
@@ -191,7 +191,7 @@ SkFontMgr* GetPreSandboxWarmupFontMgr() {
IDWriteFactory* factory;
CreateDirectWriteFactory(&factory);
- IDWriteFontCollection* collection = GetCustomFontCollection(factory);
+ GetCustomFontCollection(factory);
PatchDWriteFactory(factory);
diff --git a/chromium/content/renderer/render_frame_impl.cc b/chromium/content/renderer/render_frame_impl.cc
index 6088aba4230..d21b492c09e 100644
--- a/chromium/content/renderer/render_frame_impl.cc
+++ b/chromium/content/renderer/render_frame_impl.cc
@@ -14,12 +14,13 @@
#include "base/debug/dump_without_crashing.h"
#include "base/i18n/char_iterator.h"
#include "base/metrics/histogram.h"
-#include "base/process/kill.h"
#include "base/process/process.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
+#include "cc/base/switches.h"
#include "content/child/appcache/appcache_dispatcher.h"
+#include "content/child/permissions/permission_dispatcher.h"
#include "content/child/plugin_messages.h"
#include "content/child/quota_dispatcher.h"
#include "content/child/request_extra_data.h"
@@ -27,6 +28,7 @@
#include "content/child/service_worker/service_worker_network_provider.h"
#include "content/child/service_worker/service_worker_provider_context.h"
#include "content/child/service_worker/web_service_worker_provider_impl.h"
+#include "content/child/v8_value_converter_impl.h"
#include "content/child/web_url_loader_impl.h"
#include "content/child/web_url_request_util.h"
#include "content/child/webmessageportchannel_impl.h"
@@ -34,7 +36,9 @@
#include "content/child/weburlresponse_extradata_impl.h"
#include "content/common/clipboard_messages.h"
#include "content/common/frame_messages.h"
+#include "content/common/frame_replication_state.h"
#include "content/common/input_messages.h"
+#include "content/common/navigation_params.h"
#include "content/common/service_worker/service_worker_types.h"
#include "content/common/swapped_out_messages.h"
#include "content/common/view_messages.h"
@@ -50,6 +54,7 @@
#include "content/public/renderer/content_renderer_client.h"
#include "content/public/renderer/context_menu_client.h"
#include "content/public/renderer/document_state.h"
+#include "content/public/renderer/isolated_world_ids.h"
#include "content/public/renderer/navigation_state.h"
#include "content/public/renderer/render_frame_observer.h"
#include "content/public/renderer/renderer_ppapi_host.h"
@@ -63,6 +68,7 @@
#include "content/renderer/dom_utils.h"
#include "content/renderer/external_popup_menu.h"
#include "content/renderer/geolocation_dispatcher.h"
+#include "content/renderer/gpu/gpu_benchmarking_extension.h"
#include "content/renderer/history_controller.h"
#include "content/renderer/history_serialization.h"
#include "content/renderer/image_loading_helper.h"
@@ -70,21 +76,22 @@
#include "content/renderer/internal_document_state_data.h"
#include "content/renderer/manifest/manifest_manager.h"
#include "content/renderer/media/audio_renderer_mixer_manager.h"
-#include "content/renderer/media/crypto/encrypted_media_player_support_impl.h"
#include "content/renderer/media/crypto/render_cdm_factory.h"
+#include "content/renderer/media/media_permission_dispatcher.h"
#include "content/renderer/media/media_stream_dispatcher.h"
#include "content/renderer/media/media_stream_renderer_factory.h"
#include "content/renderer/media/midi_dispatcher.h"
#include "content/renderer/media/render_media_log.h"
#include "content/renderer/media/user_media_client_impl.h"
-#include "content/renderer/media/webcontentdecryptionmodule_impl.h"
#include "content/renderer/media/webmediaplayer_ms.h"
+#include "content/renderer/memory_benchmarking_extension.h"
#include "content/renderer/mojo/service_registry_js_wrapper.h"
+#include "content/renderer/navigation_state_impl.h"
#include "content/renderer/notification_permission_dispatcher.h"
-#include "content/renderer/notification_provider.h"
#include "content/renderer/npapi/plugin_channel_host.h"
-#include "content/renderer/push_messaging_dispatcher.h"
-#include "content/renderer/push_permission_dispatcher.h"
+#include "content/renderer/pepper/plugin_instance_throttler_impl.h"
+#include "content/renderer/presentation/presentation_dispatcher.h"
+#include "content/renderer/push_messaging/push_messaging_dispatcher.h"
#include "content/renderer/render_frame_proxy.h"
#include "content/renderer/render_process.h"
#include "content/renderer/render_thread_impl.h"
@@ -94,16 +101,17 @@
#include "content/renderer/renderer_webcolorchooser_impl.h"
#include "content/renderer/screen_orientation/screen_orientation_dispatcher.h"
#include "content/renderer/shared_worker_repository.h"
-#include "content/renderer/v8_value_converter_impl.h"
+#include "content/renderer/skia_benchmarking_extension.h"
+#include "content/renderer/stats_collection_controller.h"
+#include "content/renderer/web_ui_extension.h"
#include "content/renderer/websharedworker_proxy.h"
#include "gin/modules/module_registry.h"
#include "media/base/audio_renderer_mixer_input.h"
-#include "media/base/renderer.h"
+#include "media/base/media_log.h"
+#include "media/blink/webencryptedmediaclient_impl.h"
#include "media/blink/webmediaplayer_impl.h"
#include "media/blink/webmediaplayer_params.h"
-#include "media/filters/gpu_video_accelerator_factories.h"
-#include "mojo/edk/js/core.h"
-#include "mojo/edk/js/support.h"
+#include "media/renderers/gpu_video_accelerator_factories.h"
#include "net/base/data_url.h"
#include "net/base/net_errors.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
@@ -116,7 +124,9 @@
#include "third_party/WebKit/public/platform/WebVector.h"
#include "third_party/WebKit/public/web/WebColorSuggestion.h"
#include "third_party/WebKit/public/web/WebDocument.h"
+#include "third_party/WebKit/public/web/WebFrameWidget.h"
#include "third_party/WebKit/public/web/WebGlyphCache.h"
+#include "third_party/WebKit/public/web/WebKit.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
#include "third_party/WebKit/public/web/WebMediaStreamRegistry.h"
#include "third_party/WebKit/public/web/WebNavigationPolicy.h"
@@ -124,13 +134,18 @@
#include "third_party/WebKit/public/web/WebPluginParams.h"
#include "third_party/WebKit/public/web/WebPluginPlaceholder.h"
#include "third_party/WebKit/public/web/WebRange.h"
+#include "third_party/WebKit/public/web/WebScopedUserGesture.h"
#include "third_party/WebKit/public/web/WebScriptSource.h"
#include "third_party/WebKit/public/web/WebSearchableFormData.h"
#include "third_party/WebKit/public/web/WebSecurityOrigin.h"
#include "third_party/WebKit/public/web/WebSecurityPolicy.h"
+#include "third_party/WebKit/public/web/WebSerializedScriptValue.h"
+#include "third_party/WebKit/public/web/WebSettings.h"
#include "third_party/WebKit/public/web/WebSurroundingText.h"
#include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
#include "third_party/WebKit/public/web/WebView.h"
+#include "third_party/mojo/src/mojo/edk/js/core.h"
+#include "third_party/mojo/src/mojo/edk/js/support.h"
#if defined(ENABLE_PLUGINS)
#include "content/renderer/npapi/webplugin_impl.h"
@@ -138,7 +153,6 @@
#include "content/renderer/pepper/pepper_plugin_instance_impl.h"
#include "content/renderer/pepper/pepper_webplugin_impl.h"
#include "content/renderer/pepper/plugin_module.h"
-#include "content/renderer/pepper/plugin_power_saver_helper.h"
#endif
#if defined(ENABLE_WEBRTC)
@@ -154,6 +168,8 @@
#include "content/renderer/media/android/renderer_media_player_manager.h"
#include "content/renderer/media/android/stream_texture_factory_impl.h"
#include "content/renderer/media/android/webmediaplayer_android.h"
+#else
+#include "cc/blink/context_provider_web_context.h"
#endif
#if defined(ENABLE_PEPPER_CDMS)
@@ -162,10 +178,19 @@
#include "content/renderer/media/crypto/renderer_cdm_manager.h"
#endif
+#if defined(ENABLE_MEDIA_MOJO_RENDERER)
+#include "content/renderer/media/media_renderer_service_provider.h"
+#include "media/mojo/services/mojo_renderer_factory.h"
+#else
+#include "media/renderers/default_renderer_factory.h"
+#endif
+
using blink::WebContextMenuData;
using blink::WebData;
using blink::WebDataSource;
using blink::WebDocument;
+using blink::WebDOMEvent;
+using blink::WebDOMMessageEvent;
using blink::WebElement;
using blink::WebExternalPopupMenu;
using blink::WebExternalPopupMenuClient;
@@ -186,6 +211,7 @@ using blink::WebScriptSource;
using blink::WebSearchableFormData;
using blink::WebSecurityOrigin;
using blink::WebSecurityPolicy;
+using blink::WebSerializedScriptValue;
using blink::WebServiceWorkerProvider;
using blink::WebStorageQuotaCallbacks;
using blink::WebString;
@@ -217,11 +243,12 @@ static base::LazyInstance<RoutingIDFrameMap> g_routing_id_frame_map =
typedef std::map<blink::WebFrame*, RenderFrameImpl*> FrameMap;
base::LazyInstance<FrameMap> g_frame_map = LAZY_INSTANCE_INITIALIZER;
-int64 ExtractPostId(const WebHistoryItem& item) {
- if (item.isNull())
+int64 ExtractPostId(HistoryEntry* entry) {
+ if (!entry)
return -1;
- if (item.httpBody().isNull())
+ const WebHistoryItem& item = entry->root();
+ if (item.isNull() || item.httpBody().isNull())
return -1;
return item.httpBody().identifier();
@@ -249,7 +276,7 @@ void GetRedirectChain(WebDataSource* ds, std::vector<GURL>* result) {
// Returns the original request url. If there is no redirect, the original
// url is the same as ds->request()->url(). If the WebDataSource belongs to a
// frame was loaded by loadData, the original url will be ds->unreachableURL()
-static GURL GetOriginalRequestURL(WebDataSource* ds) {
+GURL GetOriginalRequestURL(WebDataSource* ds) {
// WebDataSource has unreachable URL means that the frame is loaded through
// blink::WebFrame::loadData(), and the base URL will be in the redirect
// chain. However, we never visited the baseURL. So in this case, we should
@@ -265,7 +292,7 @@ static GURL GetOriginalRequestURL(WebDataSource* ds) {
return ds->originalRequest().url();
}
-NOINLINE static void CrashIntentionally() {
+NOINLINE void CrashIntentionally() {
// NOTE(shess): Crash directly rather than using NOTREACHED() so
// that the signature is easier to triage in crash reports.
volatile int* zero = NULL;
@@ -273,7 +300,7 @@ NOINLINE static void CrashIntentionally() {
}
#if defined(ADDRESS_SANITIZER) || defined(SYZYASAN)
-NOINLINE static void MaybeTriggerAsanError(const GURL& url) {
+NOINLINE void MaybeTriggerAsanError(const GURL& url) {
// NOTE(rogerm): We intentionally perform an invalid heap access here in
// order to trigger an Address Sanitizer (ASAN) error report.
const char kCrashDomain[] = "crash";
@@ -308,7 +335,7 @@ NOINLINE static void MaybeTriggerAsanError(const GURL& url) {
}
#endif // ADDRESS_SANITIZER || SYZYASAN
-static void MaybeHandleDebugURL(const GURL& url) {
+void MaybeHandleDebugURL(const GURL& url) {
if (!url.SchemeIs(kChromeUIScheme))
return;
if (url == GURL(kChromeUICrashURL)) {
@@ -320,7 +347,7 @@ static void MaybeHandleDebugURL(const GURL& url) {
// of base::debug::DumpWithoutCrashing for more details.
base::debug::DumpWithoutCrashing();
} else if (url == GURL(kChromeUIKillURL)) {
- base::KillProcess(base::GetCurrentProcessHandle(), 1, false);
+ base::Process::Current().Terminate(1, false);
} else if (url == GURL(kChromeUIHangURL)) {
for (;;) {
base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
@@ -335,15 +362,15 @@ static void MaybeHandleDebugURL(const GURL& url) {
}
// Returns false unless this is a top-level navigation.
-static bool IsTopLevelNavigation(WebFrame* frame) {
+bool IsTopLevelNavigation(WebFrame* frame) {
return frame->parent() == NULL;
}
// Returns false unless this is a top-level navigation that crosses origins.
-static bool IsNonLocalTopLevelNavigation(const GURL& url,
- WebFrame* frame,
- WebNavigationType type,
- bool is_form_post) {
+bool IsNonLocalTopLevelNavigation(const GURL& url,
+ WebFrame* frame,
+ WebNavigationType type,
+ bool is_form_post) {
if (!IsTopLevelNavigation(frame))
return false;
@@ -374,7 +401,6 @@ static bool IsNonLocalTopLevelNavigation(const GURL& url,
WebURLRequest CreateURLRequestForNavigation(
const CommonNavigationParams& common_params,
- const RequestNavigationParams& request_params,
scoped_ptr<StreamOverrideParameters> stream_override,
bool is_view_source_mode_enabled) {
WebURLRequest request(common_params.url);
@@ -390,35 +416,20 @@ WebURLRequest CreateURLRequestForNavigation(
request.setHTTPReferrer(web_referrer, common_params.referrer.policy);
}
- if (!request_params.extra_headers.empty()) {
- for (net::HttpUtil::HeadersIterator i(request_params.extra_headers.begin(),
- request_params.extra_headers.end(),
- "\n");
- i.GetNext();) {
- request.addHTTPHeaderField(WebString::fromUTF8(i.name()),
- WebString::fromUTF8(i.values()));
- }
- }
-
- if (request_params.is_post) {
- request.setHTTPMethod(WebString::fromUTF8("POST"));
-
- // Set post data.
- WebHTTPBody http_body;
- http_body.initialize();
- const char* data = NULL;
- if (request_params.browser_initiated_post_data.size()) {
- data = reinterpret_cast<const char*>(
- &request_params.browser_initiated_post_data.front());
- }
- http_body.appendData(
- WebData(data, request_params.browser_initiated_post_data.size()));
- request.setHTTPBody(http_body);
- }
-
RequestExtraData* extra_data = new RequestExtraData();
extra_data->set_stream_override(stream_override.Pass());
request.setExtraData(extra_data);
+
+ // Set the ui timestamp for this navigation. Currently the timestamp here is
+ // only non empty when the navigation was triggered by an Android intent. The
+ // timestamp is converted to a double version supported by blink. It will be
+ // passed back to the browser in the DidCommitProvisionalLoad and the
+ // DocumentLoadComplete IPCs.
+ base::TimeDelta ui_timestamp = common_params.ui_timestamp - base::TimeTicks();
+ request.setUiStartTime(ui_timestamp.InSecondsF());
+ request.setInputPerfMetricReportPolicy(
+ static_cast<WebURLRequest::InputToLoadPerfMetricReportPolicy>(
+ common_params.report_type));
return request;
}
@@ -447,38 +458,88 @@ void UpdateFrameNavigationTiming(WebFrame* frame,
}
// PlzNavigate
-FrameHostMsg_BeginNavigation_Params MakeBeginNavigationParams(
- const blink::WebURLRequest& request) {
- FrameHostMsg_BeginNavigation_Params params;
- params.method = request.httpMethod().latin1();
- params.headers = GetWebURLRequestHeaders(request);
- params.load_flags = GetLoadFlagsForWebURLRequest(request);
- // TODO(clamy): fill the http body.
- params.has_user_gesture = request.hasUserGesture();
- return params;
-}
-
-// PlzNavigate
CommonNavigationParams MakeCommonNavigationParams(
- const blink::WebURLRequest& request) {
+ blink::WebURLRequest* request) {
const RequestExtraData kEmptyData;
const RequestExtraData* extra_data =
- static_cast<RequestExtraData*>(request.extraData());
+ static_cast<RequestExtraData*>(request->extraData());
if (!extra_data)
extra_data = &kEmptyData;
- CommonNavigationParams params;
- params.url = request.url();
- params.referrer = Referrer(
- GURL(request.httpHeaderField(WebString::fromUTF8("Referer")).latin1()),
- request.referrerPolicy());
- params.transition = extra_data->transition_type();
- return params;
+ Referrer referrer(
+ GURL(request->httpHeaderField(WebString::fromUTF8("Referer")).latin1()),
+ request->referrerPolicy());
+
+ // Set the ui timestamp for this navigation. Currently the timestamp here is
+ // only non empty when the navigation was triggered by an Android intent, or
+ // by the user clicking on a link. The timestamp is converted from a double
+ // version supported by blink. It will be passed back to the renderer in the
+ // CommitNavigation IPC, and then back to the browser again in the
+ // DidCommitProvisionalLoad and the DocumentLoadComplete IPCs.
+ base::TimeTicks ui_timestamp =
+ base::TimeTicks() + base::TimeDelta::FromSecondsD(request->uiStartTime());
+ FrameMsg_UILoadMetricsReportType::Value report_type =
+ static_cast<FrameMsg_UILoadMetricsReportType::Value>(
+ request->inputPerfMetricReportPolicy());
+ return CommonNavigationParams(request->url(), referrer,
+ extra_data->transition_type(),
+ FrameMsg_Navigate_Type::NORMAL, true,
+ ui_timestamp, report_type, GURL(), GURL());
+}
+
+#if !defined(OS_ANDROID)
+media::Context3D GetSharedMainThreadContext3D() {
+ cc::ContextProvider* provider =
+ RenderThreadImpl::current()->SharedMainThreadContextProvider().get();
+ if (!provider)
+ return media::Context3D();
+ return media::Context3D(provider->ContextGL(), provider->GrContext());
}
+#endif
-} // namespace
+bool IsReload(FrameMsg_Navigate_Type::Value navigation_type) {
+ return navigation_type == FrameMsg_Navigate_Type::RELOAD ||
+ navigation_type == FrameMsg_Navigate_Type::RELOAD_IGNORING_CACHE ||
+ navigation_type == FrameMsg_Navigate_Type::RELOAD_ORIGINAL_REQUEST_URL;
+}
+
+RenderFrameImpl::CreateRenderFrameImplFunction g_create_render_frame_impl =
+ nullptr;
+
+#define STATIC_ASSERT_MATCHING_ENUMS(content_name, blink_name) \
+ static_assert( \
+ static_cast<int>(content_name) == static_cast<int>(blink_name), \
+ "enum values must match")
+
+// Check that blink::WebSandboxFlags is kept in sync with
+// content::SandboxFlags.
+STATIC_ASSERT_MATCHING_ENUMS(SandboxFlags::NONE,
+ blink::WebSandboxFlags::None);
+STATIC_ASSERT_MATCHING_ENUMS(SandboxFlags::NAVIGATION,
+ blink::WebSandboxFlags::Navigation);
+STATIC_ASSERT_MATCHING_ENUMS(SandboxFlags::PLUGINS,
+ blink::WebSandboxFlags::Plugins);
+STATIC_ASSERT_MATCHING_ENUMS(SandboxFlags::ORIGIN,
+ blink::WebSandboxFlags::Origin);
+STATIC_ASSERT_MATCHING_ENUMS(SandboxFlags::FORMS,
+ blink::WebSandboxFlags::Forms);
+STATIC_ASSERT_MATCHING_ENUMS(SandboxFlags::SCRIPTS,
+ blink::WebSandboxFlags::Scripts);
+STATIC_ASSERT_MATCHING_ENUMS(SandboxFlags::TOP_NAVIGATION,
+ blink::WebSandboxFlags::TopNavigation);
+STATIC_ASSERT_MATCHING_ENUMS(SandboxFlags::POPUPS,
+ blink::WebSandboxFlags::Popups);
+STATIC_ASSERT_MATCHING_ENUMS(SandboxFlags::AUTOMATIC_FEATURES,
+ blink::WebSandboxFlags::AutomaticFeatures);
+STATIC_ASSERT_MATCHING_ENUMS(SandboxFlags::POINTER_LOCK,
+ blink::WebSandboxFlags::PointerLock);
+STATIC_ASSERT_MATCHING_ENUMS(SandboxFlags::DOCUMENT_DOMAIN,
+ blink::WebSandboxFlags::DocumentDomain);
+STATIC_ASSERT_MATCHING_ENUMS(SandboxFlags::ORIENTATION_LOCK,
+ blink::WebSandboxFlags::OrientationLock);
+STATIC_ASSERT_MATCHING_ENUMS(SandboxFlags::ALL,
+ blink::WebSandboxFlags::All);
-static RenderFrameImpl* (*g_create_render_frame_impl)(RenderViewImpl*, int32) =
- NULL;
+} // namespace
// static
RenderFrameImpl* RenderFrameImpl::Create(RenderViewImpl* render_view,
@@ -501,9 +562,14 @@ RenderFrameImpl* RenderFrameImpl::FromRoutingID(int32 routing_id) {
}
// static
-void RenderFrameImpl::CreateFrame(int routing_id,
- int parent_routing_id,
- int proxy_routing_id) {
+void RenderFrameImpl::CreateFrame(
+ int routing_id,
+ int parent_routing_id,
+ int previous_sibling_routing_id,
+ int proxy_routing_id,
+ const FrameReplicationState& replicated_state,
+ CompositorDependencies* compositor_deps,
+ const FrameMsg_NewFrame_WidgetParams& widget_params) {
// TODO(nasko): For now, this message is only sent for subframes, as the
// top level frame is created when the RenderView is created through the
// ViewMsg_New IPC.
@@ -519,10 +585,19 @@ void RenderFrameImpl::CreateFrame(int routing_id,
CHECK(parent_proxy);
blink::WebRemoteFrame* parent_web_frame = parent_proxy->web_frame();
+ blink::WebFrame* previous_sibling_web_frame = nullptr;
+ RenderFrameProxy* previous_sibling_proxy =
+ RenderFrameProxy::FromRoutingID(previous_sibling_routing_id);
+ if (previous_sibling_proxy)
+ previous_sibling_web_frame = previous_sibling_proxy->web_frame();
+
// Create the RenderFrame and WebLocalFrame, linking the two.
render_frame =
RenderFrameImpl::Create(parent_proxy->render_view(), routing_id);
- web_frame = parent_web_frame->createLocalChild("", render_frame);
+ web_frame = parent_web_frame->createLocalChild(
+ WebString::fromUTF8(replicated_state.name),
+ ContentToWebSandboxFlags(replicated_state.sandbox_flags), render_frame,
+ previous_sibling_web_frame);
} else {
RenderFrameProxy* proxy =
RenderFrameProxy::FromRoutingID(proxy_routing_id);
@@ -530,9 +605,25 @@ void RenderFrameImpl::CreateFrame(int routing_id,
render_frame = RenderFrameImpl::Create(proxy->render_view(), routing_id);
web_frame = blink::WebLocalFrame::create(render_frame);
render_frame->proxy_routing_id_ = proxy_routing_id;
- web_frame->initializeToReplaceRemoteFrame(proxy->web_frame());
+ web_frame->initializeToReplaceRemoteFrame(
+ proxy->web_frame(), WebString::fromUTF8(replicated_state.name),
+ ContentToWebSandboxFlags(replicated_state.sandbox_flags));
}
render_frame->SetWebFrame(web_frame);
+
+ if (widget_params.routing_id != MSG_ROUTING_NONE) {
+ CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess));
+ render_frame->render_widget_ = RenderWidget::CreateForFrame(
+ widget_params.routing_id, widget_params.surface_id,
+ widget_params.hidden, render_frame->render_view_->screen_info(),
+ compositor_deps, web_frame);
+ // TODO(kenrb): Observing shouldn't be necessary when we sort out
+ // WasShown and WasHidden, separating page-level visibility from
+ // frame-level visibility.
+ render_frame->render_widget_->RegisterRenderFrame(render_frame);
+ }
+
render_frame->Initialize();
}
@@ -551,14 +642,28 @@ RenderFrameImpl* RenderFrameImpl::FromWebFrame(blink::WebFrame* web_frame) {
// static
void RenderFrameImpl::InstallCreateHook(
- RenderFrameImpl* (*create_render_frame_impl)(RenderViewImpl*, int32)) {
+ CreateRenderFrameImplFunction create_render_frame_impl) {
CHECK(!g_create_render_frame_impl);
g_create_render_frame_impl = create_render_frame_impl;
}
+// static
+content::SandboxFlags RenderFrameImpl::WebToContentSandboxFlags(
+ blink::WebSandboxFlags flags) {
+ return static_cast<content::SandboxFlags>(flags);
+}
+
+// static
+blink::WebSandboxFlags RenderFrameImpl::ContentToWebSandboxFlags(
+ content::SandboxFlags flags) {
+ return static_cast<blink::WebSandboxFlags>(flags);
+}
+
// RenderFrameImpl ----------------------------------------------------------
RenderFrameImpl::RenderFrameImpl(RenderViewImpl* render_view, int routing_id)
: frame_(NULL),
+ is_subframe_(false),
+ is_local_root_(false),
render_view_(render_view->AsWeakPtr()),
routing_id_(routing_id),
is_swapped_out_(false),
@@ -573,8 +678,8 @@ RenderFrameImpl::RenderFrameImpl(RenderViewImpl* render_view, int routing_id)
selection_range_(gfx::Range::InvalidRange()),
handling_select_range_(false),
notification_permission_dispatcher_(NULL),
- notification_provider_(NULL),
web_user_media_client_(NULL),
+ media_permission_dispatcher_(NULL),
midi_dispatcher_(NULL),
#if defined(OS_ANDROID)
media_player_manager_(NULL),
@@ -582,11 +687,14 @@ RenderFrameImpl::RenderFrameImpl(RenderViewImpl* render_view, int routing_id)
#if defined(ENABLE_BROWSER_CDMS)
cdm_manager_(NULL),
#endif
+ cdm_factory_(NULL),
#if defined(VIDEO_HOLE)
contains_media_player_(false),
#endif
+ devtools_agent_(nullptr),
geolocation_dispatcher_(NULL),
push_messaging_dispatcher_(NULL),
+ presentation_dispatcher_(NULL),
screen_orientation_dispatcher_(NULL),
manifest_manager_(NULL),
accessibility_mode_(AccessibilityModeOff),
@@ -610,10 +718,6 @@ RenderFrameImpl::RenderFrameImpl(RenderViewImpl* render_view, int routing_id)
plugin_power_saver_helper_ = new PluginPowerSaverHelper(this);
#endif
-#if defined(ENABLE_NOTIFICATIONS)
- notification_provider_ = new NotificationProvider(this);
-#endif
-
manifest_manager_ = new ManifestManager(this);
}
@@ -626,8 +730,19 @@ RenderFrameImpl::~RenderFrameImpl() {
render_view_->UnregisterVideoHoleFrame(this);
#endif
- if (render_frame_proxy_)
- delete render_frame_proxy_;
+ if (!is_subframe_) {
+ // RenderFrameProxy is "owned" by RenderFrameImpl in the case it is
+ // the main frame. Ensure it is deleted along with this object.
+ if (render_frame_proxy_) {
+ // The following method calls back into this object and clears
+ // |render_frame_proxy_|.
+ render_frame_proxy_->frameDetached();
+ }
+
+ // Ensure the RenderView doesn't point to this object, once it is destroyed.
+ CHECK_EQ(render_view_->main_render_frame_, this);
+ render_view_->main_render_frame_ = nullptr;
+ }
render_view_->UnregisterRenderFrame(this);
g_routing_id_frame_map.Get().erase(routing_id_);
@@ -645,6 +760,9 @@ void RenderFrameImpl::SetWebFrame(blink::WebLocalFrame* web_frame) {
}
void RenderFrameImpl::Initialize() {
+ is_subframe_ = !!frame_->parent();
+ is_local_root_ = !frame_->parent() || frame_->parent()->isWebRemoteFrame();
+
#if defined(ENABLE_PLUGINS)
new PepperBrowserConnection(this);
#endif
@@ -653,6 +771,12 @@ void RenderFrameImpl::Initialize() {
if (!frame_->parent())
new ImageLoadingHelper(this);
+ if (is_local_root_ && !render_frame_proxy_) {
+ // DevToolsAgent is a RenderFrameObserver, and will destruct itself
+ // when |this| is deleted.
+ devtools_agent_ = new DevToolsAgent(this);
+ }
+
// We delay calling this until we have the WebFrame so that any observer or
// embedder can call GetWebFrame on any RenderFrame.
GetContentClient()->renderer()->RenderFrameCreated(this);
@@ -695,8 +819,8 @@ void RenderFrameImpl::PepperTextInputTypeChanged(
return;
GetRenderWidget()->UpdateTextInputType();
- if (renderer_accessibility())
- renderer_accessibility()->FocusedNodeChanged(WebNode());
+
+ FocusedNodeChangedForAccessibility(WebNode());
}
void RenderFrameImpl::PepperCaretPositionChanged(
@@ -729,8 +853,8 @@ RenderWidgetFullscreenPepper* RenderFrameImpl::CreatePepperFullscreenContainer(
if (render_view_->webview() && render_view_->webview()->mainFrame())
active_url = GURL(render_view_->webview()->mainFrame()->document().url());
RenderWidgetFullscreenPepper* widget = RenderWidgetFullscreenPepper::Create(
- GetRenderWidget()->routing_id(), plugin, active_url,
- GetRenderWidget()->screenInfo());
+ GetRenderWidget()->routing_id(), GetRenderWidget()->compositor_deps(),
+ plugin, active_url, GetRenderWidget()->screenInfo());
widget->show(blink::WebNavigationPolicyIgnore);
return widget;
}
@@ -842,11 +966,6 @@ void RenderFrameImpl::OnImeConfirmComposition(
}
pepper_composition_text_.clear();
}
-
-PluginPowerSaverHelper* RenderFrameImpl::plugin_power_saver_helper() {
- DCHECK(plugin_power_saver_helper_);
- return plugin_power_saver_helper_;
-}
#endif // defined(ENABLE_PLUGINS)
MediaStreamDispatcher* RenderFrameImpl::GetMediaStreamDispatcher() {
@@ -861,18 +980,11 @@ bool RenderFrameImpl::Send(IPC::Message* message) {
delete message;
return false;
}
- if (frame_->parent() == NULL &&
- (is_swapped_out_ || render_view_->is_swapped_out())) {
+ if (is_swapped_out_) {
if (!SwappedOutMessages::CanSendWhileSwappedOut(message)) {
delete message;
return false;
}
-
- // In most cases, send IPCs through the proxy when swapped out. In some
- // calls the associated RenderViewImpl routing id is used to send
- // messages, so don't use the proxy.
- if (render_frame_proxy_ && message->routing_id() == routing_id_)
- return render_frame_proxy_->Send(message);
}
return RenderThread::Get()->Send(message);
@@ -887,6 +999,11 @@ void RenderFrameImpl::DidHideExternalPopupMenu() {
#endif
bool RenderFrameImpl::OnMessageReceived(const IPC::Message& msg) {
+ // We may get here while detaching, when the WebFrame has been deleted. Do
+ // not process any messages in this state.
+ if (!frame_)
+ return false;
+
// TODO(kenrb): document() should not be null, but as a transitional step
// we have RenderFrameProxy 'wrapping' a RenderFrameImpl, passing messages
// to this method. This happens for a top-level remote frame, where a
@@ -895,7 +1012,7 @@ bool RenderFrameImpl::OnMessageReceived(const IPC::Message& msg) {
if (!frame_->document().isNull())
GetContentClient()->SetActiveURL(frame_->document().url());
- ObserverListBase<RenderFrameObserver>::Iterator it(observers_);
+ ObserverListBase<RenderFrameObserver>::Iterator it(&observers_);
RenderFrameObserver* observer;
while ((observer = it.GetNext()) != NULL) {
if (observer->OnMessageReceived(msg))
@@ -929,15 +1046,26 @@ bool RenderFrameImpl::OnMessageReceived(const IPC::Message& msg) {
OnExtendSelectionAndDelete)
IPC_MESSAGE_HANDLER(InputMsg_SetCompositionFromExistingText,
OnSetCompositionFromExistingText)
+ IPC_MESSAGE_HANDLER(InputMsg_ExecuteNoValueEditCommand,
+ OnExecuteNoValueEditCommand)
IPC_MESSAGE_HANDLER(FrameMsg_CSSInsertRequest, OnCSSInsertRequest)
IPC_MESSAGE_HANDLER(FrameMsg_JavaScriptExecuteRequest,
OnJavaScriptExecuteRequest)
IPC_MESSAGE_HANDLER(FrameMsg_JavaScriptExecuteRequestForTests,
OnJavaScriptExecuteRequestForTests)
+ IPC_MESSAGE_HANDLER(FrameMsg_JavaScriptExecuteRequestInIsolatedWorld,
+ OnJavaScriptExecuteRequestInIsolatedWorld)
+ IPC_MESSAGE_HANDLER(FrameMsg_VisualStateRequest,
+ OnVisualStateRequest)
IPC_MESSAGE_HANDLER(FrameMsg_SetEditableSelectionOffsets,
OnSetEditableSelectionOffsets)
IPC_MESSAGE_HANDLER(FrameMsg_SetupTransitionView, OnSetupTransitionView)
IPC_MESSAGE_HANDLER(FrameMsg_BeginExitTransition, OnBeginExitTransition)
+ IPC_MESSAGE_HANDLER(FrameMsg_RevertExitTransition, OnRevertExitTransition)
+ IPC_MESSAGE_HANDLER(FrameMsg_HideTransitionElements,
+ OnHideTransitionElements)
+ IPC_MESSAGE_HANDLER(FrameMsg_ShowTransitionElements,
+ OnShowTransitionElements)
IPC_MESSAGE_HANDLER(FrameMsg_Reload, OnReload)
IPC_MESSAGE_HANDLER(FrameMsg_TextSurroundingSelectionRequest,
OnTextSurroundingSelectionRequest)
@@ -945,9 +1073,15 @@ bool RenderFrameImpl::OnMessageReceived(const IPC::Message& msg) {
OnAddStyleSheetByURL)
IPC_MESSAGE_HANDLER(FrameMsg_SetAccessibilityMode,
OnSetAccessibilityMode)
+ IPC_MESSAGE_HANDLER(AccessibilityMsg_SnapshotTree,
+ OnSnapshotAccessibilityTree)
IPC_MESSAGE_HANDLER(FrameMsg_DisownOpener, OnDisownOpener)
- IPC_MESSAGE_HANDLER(FrameMsg_RequestNavigation, OnRequestNavigation)
IPC_MESSAGE_HANDLER(FrameMsg_CommitNavigation, OnCommitNavigation)
+ IPC_MESSAGE_HANDLER(FrameMsg_DidUpdateSandboxFlags, OnDidUpdateSandboxFlags)
+ IPC_MESSAGE_HANDLER(FrameMsg_SetTextTrackSettings,
+ OnTextTrackSettingsChanged)
+ IPC_MESSAGE_HANDLER(FrameMsg_PostMessageEvent, OnPostMessageEvent)
+ IPC_MESSAGE_HANDLER(FrameMsg_FailedNavigation, OnFailedNavigation)
#if defined(OS_ANDROID)
IPC_MESSAGE_HANDLER(FrameMsg_SelectPopupMenuItems, OnSelectPopupMenuItems)
#elif defined(OS_MACOSX)
@@ -959,137 +1093,47 @@ bool RenderFrameImpl::OnMessageReceived(const IPC::Message& msg) {
return handled;
}
-void RenderFrameImpl::OnNavigate(const FrameMsg_Navigate_Params& params) {
- TRACE_EVENT2("navigation", "RenderFrameImpl::OnNavigate",
- "id", routing_id_,
- "url", params.common_params.url.possibly_invalid_spec());
- bool is_reload =
- RenderViewImpl::IsReload(params.common_params.navigation_type);
- WebURLRequest::CachePolicy cache_policy =
- WebURLRequest::UseProtocolCachePolicy;
- if (!RenderFrameImpl::PrepareRenderViewForNavigation(
- params.common_params.url, params.common_params.navigation_type,
- params.commit_params.page_state, true, params.pending_history_list_offset,
- params.page_id, &is_reload, &cache_policy)) {
- return;
- }
-
- int pending_history_list_offset = params.pending_history_list_offset;
- int current_history_list_offset = params.current_history_list_offset;
- int current_history_list_length = params.current_history_list_length;
- if (params.should_clear_history_list) {
- CHECK_EQ(pending_history_list_offset, -1);
- CHECK_EQ(current_history_list_offset, -1);
- CHECK_EQ(current_history_list_length, 0);
- }
- render_view_->history_list_offset_ = current_history_list_offset;
- render_view_->history_list_length_ = current_history_list_length;
- if (render_view_->history_list_length_ >= 0) {
- render_view_->history_page_ids_.resize(
- render_view_->history_list_length_, -1);
- }
- if (pending_history_list_offset >= 0 &&
- pending_history_list_offset < render_view_->history_list_length_) {
- render_view_->history_page_ids_[pending_history_list_offset] =
- params.page_id;
- }
-
- GetContentClient()->SetActiveURL(params.common_params.url);
-
- WebFrame* frame = frame_;
- if (!params.frame_to_navigate.empty()) {
- // TODO(nasko): Move this lookup to the browser process.
- frame = render_view_->webview()->findFrameByName(
- WebString::fromUTF8(params.frame_to_navigate));
- CHECK(frame) << "Invalid frame name passed: " << params.frame_to_navigate;
- }
-
- if (is_reload && !render_view_->history_controller()->GetCurrentEntry()) {
- // We cannot reload if we do not have any history state. This happens, for
- // example, when recovering from a crash.
- is_reload = false;
- cache_policy = WebURLRequest::ReloadIgnoringCacheData;
- }
-
- render_view_->pending_navigation_params_.reset(
- new FrameMsg_Navigate_Params(params));
-
- // If we are reloading, then WebKit will use the history state of the current
- // page, so we should just ignore any given history state. Otherwise, if we
- // have history state, then we need to navigate to it, which corresponds to a
- // back/forward navigation event.
- if (is_reload) {
- bool reload_original_url =
- (params.common_params.navigation_type ==
- FrameMsg_Navigate_Type::RELOAD_ORIGINAL_REQUEST_URL);
- bool ignore_cache = (params.common_params.navigation_type ==
- FrameMsg_Navigate_Type::RELOAD_IGNORING_CACHE);
-
- if (reload_original_url)
- frame->reloadWithOverrideURL(params.common_params.url, true);
- else
- frame->reload(ignore_cache);
- } else if (params.commit_params.page_state.IsValid()) {
- // We must know the page ID of the page we are navigating back to.
- DCHECK_NE(params.page_id, -1);
- scoped_ptr<HistoryEntry> entry =
- PageStateToHistoryEntry(params.commit_params.page_state);
- if (entry) {
- // Ensure we didn't save the swapped out URL in UpdateState, since the
- // browser should never be telling us to navigate to swappedout://.
- CHECK(entry->root().urlString() != WebString::fromUTF8(kSwappedOutURL));
- render_view_->history_controller()->GoToEntry(entry.Pass(), cache_policy);
- }
- } else if (!params.base_url_for_data_url.is_empty()) {
- // A loadData request with a specified base URL.
- std::string mime_type, charset, data;
- if (net::DataURL::Parse(
- params.common_params.url, &mime_type, &charset, &data)) {
- frame->loadData(
- WebData(data.c_str(), data.length()),
- WebString::fromUTF8(mime_type),
- WebString::fromUTF8(charset),
- params.base_url_for_data_url,
- params.history_url_for_data_url,
- false);
- } else {
- CHECK(false) << "Invalid URL passed: "
- << params.common_params.url.possibly_invalid_spec();
- }
- } else {
- // Navigate to the given URL.
- WebURLRequest request =
- CreateURLRequestForNavigation(params.common_params,
- params.request_params,
- scoped_ptr<StreamOverrideParameters>(),
- frame->isViewSourceModeEnabled());
-
- // A session history navigation should have been accompanied by state.
- CHECK_EQ(params.page_id, -1);
-
- // Record this before starting the load, we need a lower bound of this time
- // to sanitize the navigationStart override set below.
- base::TimeTicks renderer_navigation_start = base::TimeTicks::Now();
- frame->loadRequest(request);
-
- UpdateFrameNavigationTiming(
- frame, params.commit_params.browser_navigation_start,
- renderer_navigation_start);
- }
-
- // In case LoadRequest failed before DidCreateDataSource was called.
- render_view_->pending_navigation_params_.reset();
+void RenderFrameImpl::OnNavigate(
+ const CommonNavigationParams& common_params,
+ const StartNavigationParams& start_params,
+ const RequestNavigationParams& request_params) {
+ DCHECK(!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation));
+ TRACE_EVENT2("navigation", "RenderFrameImpl::OnNavigate", "id", routing_id_,
+ "url", common_params.url.possibly_invalid_spec());
+ NavigateInternal(common_params, start_params, request_params,
+ scoped_ptr<StreamOverrideParameters>());
+}
+
+void RenderFrameImpl::NavigateToSwappedOutURL() {
+ // We use loadRequest instead of loadHTMLString because the former commits
+ // synchronously. Otherwise a new navigation can interrupt the navigation
+ // to kSwappedOutURL. If that happens to be to the page we had been
+ // showing, then WebKit will never send a commit and we'll be left spinning.
+ // Set the is_swapped_out_ bit to true, so IPC filtering is in effect and
+ // the navigation to swappedout:// is not announced to the browser side.
+ is_swapped_out_ = true;
+ GURL swappedOutURL(kSwappedOutURL);
+ WebURLRequest request(swappedOutURL);
+ frame_->loadRequest(request);
}
void RenderFrameImpl::BindServiceRegistry(
- mojo::ScopedMessagePipeHandle service_provider_handle) {
- service_registry_.BindRemoteServiceProvider(service_provider_handle.Pass());
+ mojo::InterfaceRequest<mojo::ServiceProvider> services,
+ mojo::ServiceProviderPtr exposed_services) {
+ service_registry_.Bind(services.Pass());
+ service_registry_.BindRemoteServiceProvider(exposed_services.Pass());
}
ManifestManager* RenderFrameImpl::manifest_manager() {
return manifest_manager_;
}
+void RenderFrameImpl::SetPendingNavigationParams(
+ scoped_ptr<NavigationParams> navigation_params) {
+ pending_navigation_params_ = navigation_params.Pass();
+}
+
void RenderFrameImpl::OnBeforeUnload() {
TRACE_EVENT1("navigation", "RenderFrameImpl::OnBeforeUnload",
"id", routing_id_);
@@ -1106,15 +1150,18 @@ void RenderFrameImpl::OnBeforeUnload() {
before_unload_end_time));
}
-void RenderFrameImpl::OnSwapOut(int proxy_routing_id) {
+void RenderFrameImpl::OnSwapOut(
+ int proxy_routing_id,
+ bool is_loading,
+ const FrameReplicationState& replicated_frame_state) {
TRACE_EVENT1("navigation", "RenderFrameImpl::OnSwapOut", "id", routing_id_);
RenderFrameProxy* proxy = NULL;
- bool is_site_per_process =
- CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess);
+ bool is_site_per_process = base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess);
bool is_main_frame = !frame_->parent();
// Only run unload if we're not swapped out yet, but send the ack either way.
- if (!is_swapped_out_ || !render_view_->is_swapped_out_) {
+ if (!is_swapped_out_) {
// Swap this RenderFrame out so the frame can navigate to a page rendered by
// a different process. This involves running the unload handler and
// clearing the page. We also allow this process to exit if there are no
@@ -1137,11 +1184,16 @@ void RenderFrameImpl::OnSwapOut(int proxy_routing_id) {
frame_->dispatchUnloadEvent();
// Swap out and stop sending any IPC messages that are not ACKs.
- // TODO(nasko): Do we need RenderFrameImpl::is_swapped_out_ anymore?
if (is_main_frame)
render_view_->SetSwappedOut(true);
is_swapped_out_ = true;
+ // Set the proxy here, since OnStop() below could cause an onload event
+ // handler to execute, which could trigger code such as
+ // willCheckAndDispatchMessageEvent() that needs the proxy.
+ if (proxy)
+ set_render_frame_proxy(proxy);
+
// Now that we're swapped out and filtering IPC messages, stop loading to
// ensure that no other in-progress navigation continues. We do this here
// to avoid sending a DidStopLoading message to the browser process.
@@ -1160,7 +1212,7 @@ void RenderFrameImpl::OnSwapOut(int proxy_routing_id) {
// TODO(creis): Need to add a better way to do this that avoids running the
// beforeunload handler. For now, we just run it a second time silently.
if (!is_site_per_process || is_main_frame)
- render_view_->NavigateToSwappedOutURL(frame_);
+ NavigateToSwappedOutURL();
// Let WebKit know that this view is hidden so it can drop resources and
// stop compositing.
@@ -1183,15 +1235,28 @@ void RenderFrameImpl::OnSwapOut(int proxy_routing_id) {
if (proxy) {
if (!is_main_frame) {
frame_->swap(proxy->web_frame());
+
+ if (is_loading)
+ proxy->OnDidStartLoading();
+
if (is_site_per_process) {
// TODO(nasko): delete the frame here, since we've replaced it with a
// proxy.
}
- } else {
- set_render_frame_proxy(proxy);
}
}
+ // In --site-per-process, initialize the WebRemoteFrame with the replication
+ // state passed by the process that is now rendering the frame.
+ // TODO(alexmos): We cannot yet do this for swapped-out main frames, because
+ // in that case we leave the LocalFrame as the main frame visible to Blink
+ // and don't call swap() above. Because swap() is what creates a RemoteFrame
+ // in proxy->web_frame(), the RemoteFrame will not exist for main frames.
+ // When we do an unconditional swap for all frames, we can remove
+ // !is_main_frame below.
+ if (is_site_per_process && proxy && !is_main_frame)
+ proxy->SetReplicatedState(replicated_frame_state);
+
// Safe to exit if no one else is using the process.
if (is_main_frame)
render_view_->WasSwappedOut();
@@ -1334,7 +1399,7 @@ void RenderFrameImpl::OnJavaScriptExecuteRequest(
TRACE_EVENT_SCOPE_THREAD);
v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
- v8::Handle<v8::Value> result =
+ v8::Local<v8::Value> result =
frame_->executeScriptAndReturnValue(WebScriptSource(jscript));
HandleJavascriptExecutionResult(jscript, id, notify_result, result);
@@ -1343,22 +1408,102 @@ void RenderFrameImpl::OnJavaScriptExecuteRequest(
void RenderFrameImpl::OnJavaScriptExecuteRequestForTests(
const base::string16& jscript,
int id,
- bool notify_result) {
+ bool notify_result,
+ bool has_user_gesture) {
TRACE_EVENT_INSTANT0("test_tracing", "OnJavaScriptExecuteRequestForTests",
TRACE_EVENT_SCOPE_THREAD);
- v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
- v8::Handle<v8::Value> result =
- frame_->executeScriptAndReturnValueForTests(WebScriptSource(jscript));
+ // A bunch of tests expect to run code in the context of a user gesture, which
+ // can grant additional privileges (e.g. the ability to create popups).
+ scoped_ptr<blink::WebScopedUserGesture> gesture(
+ has_user_gesture ? new blink::WebScopedUserGesture : nullptr);
+ v8::HandleScope handle_scope(blink::mainThreadIsolate());
+ v8::Local<v8::Value> result =
+ frame_->executeScriptAndReturnValue(WebScriptSource(jscript));
HandleJavascriptExecutionResult(jscript, id, notify_result, result);
}
+void RenderFrameImpl::OnJavaScriptExecuteRequestInIsolatedWorld(
+ const base::string16& jscript,
+ int id,
+ bool notify_result,
+ int world_id) {
+ TRACE_EVENT_INSTANT0("test_tracing",
+ "OnJavaScriptExecuteRequestInIsolatedWorld",
+ TRACE_EVENT_SCOPE_THREAD);
+
+ if (world_id <= ISOLATED_WORLD_ID_GLOBAL ||
+ world_id > ISOLATED_WORLD_ID_MAX) {
+ // Return if the world_id is not valid. world_id is passed as a plain int
+ // over IPC and needs to be verified here, in the IPC endpoint.
+ NOTREACHED();
+ return;
+ }
+
+ v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
+ WebScriptSource script = WebScriptSource(jscript);
+ JavaScriptIsolatedWorldRequest* request = new JavaScriptIsolatedWorldRequest(
+ id, notify_result, routing_id_, weak_factory_.GetWeakPtr());
+ frame_->requestExecuteScriptInIsolatedWorld(world_id, &script, 1, 0, false,
+ request);
+}
+
+RenderFrameImpl::JavaScriptIsolatedWorldRequest::JavaScriptIsolatedWorldRequest(
+ int id,
+ bool notify_result,
+ int routing_id,
+ base::WeakPtr<RenderFrameImpl> render_frame_impl)
+ : id_(id),
+ notify_result_(notify_result),
+ routing_id_(routing_id),
+ render_frame_impl_(render_frame_impl) {
+}
+
+RenderFrameImpl::JavaScriptIsolatedWorldRequest::
+ ~JavaScriptIsolatedWorldRequest() {
+}
+
+void RenderFrameImpl::JavaScriptIsolatedWorldRequest::completed(
+ const blink::WebVector<v8::Local<v8::Value>>& result) {
+ if (!render_frame_impl_.get()) {
+ return;
+ }
+
+ if (notify_result_) {
+ base::ListValue list;
+ if (!result.isEmpty()) {
+ // It's safe to always use the main world context when converting
+ // here. V8ValueConverterImpl shouldn't actually care about the
+ // context scope, and it switches to v8::Object's creation context
+ // when encountered. (from extensions/renderer/script_injection.cc)
+ v8::Local<v8::Context> context =
+ render_frame_impl_.get()->frame_->mainWorldScriptContext();
+ v8::Context::Scope context_scope(context);
+ V8ValueConverterImpl converter;
+ converter.SetDateAllowed(true);
+ converter.SetRegExpAllowed(true);
+ for (const auto& value : result) {
+ scoped_ptr<base::Value> result_value(
+ converter.FromV8Value(value, context));
+ list.Append(result_value ? result_value.Pass()
+ : base::Value::CreateNullValue());
+ }
+ } else {
+ list.Set(0, base::Value::CreateNullValue());
+ }
+ render_frame_impl_.get()->Send(
+ new FrameHostMsg_JavaScriptExecuteResponse(routing_id_, id_, list));
+ }
+
+ delete this;
+}
+
void RenderFrameImpl::HandleJavascriptExecutionResult(
const base::string16& jscript,
int id,
bool notify_result,
- v8::Handle<v8::Value> result) {
+ v8::Local<v8::Value> result) {
if (notify_result) {
base::ListValue list;
if (!result.IsEmpty()) {
@@ -1367,8 +1512,10 @@ void RenderFrameImpl::HandleJavascriptExecutionResult(
V8ValueConverterImpl converter;
converter.SetDateAllowed(true);
converter.SetRegExpAllowed(true);
- base::Value* result_value = converter.FromV8Value(result, context);
- list.Set(0, result_value ? result_value : base::Value::CreateNullValue());
+ scoped_ptr<base::Value> result_value(
+ converter.FromV8Value(result, context));
+ list.Set(0, result_value ? result_value.Pass()
+ : base::Value::CreateNullValue());
} else {
list.Set(0, base::Value::CreateNullValue());
}
@@ -1376,6 +1523,12 @@ void RenderFrameImpl::HandleJavascriptExecutionResult(
}
}
+void RenderFrameImpl::OnVisualStateRequest(uint64 id) {
+ GetRenderWidget()->QueueMessage(
+ new FrameHostMsg_VisualStateResponse(routing_id_, id),
+ MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE);
+}
+
void RenderFrameImpl::OnSetEditableSelectionOffsets(int start, int end) {
base::AutoReset<bool> handling_select_range(&handling_select_range_, true);
if (!GetRenderWidget()->ShouldHandleImeEvent())
@@ -1393,6 +1546,10 @@ void RenderFrameImpl::OnSetCompositionFromExistingText(
frame_->setCompositionFromExistingText(start, end, underlines);
}
+void RenderFrameImpl::OnExecuteNoValueEditCommand(const std::string& name) {
+ frame_->executeCommand(WebString::fromUTF8(name), GetFocusedElement());
+}
+
void RenderFrameImpl::OnExtendSelectionAndDelete(int before, int after) {
if (!GetRenderWidget()->ShouldHandleImeEvent())
return;
@@ -1420,6 +1577,13 @@ void RenderFrameImpl::OnSetAccessibilityMode(AccessibilityMode new_mode) {
renderer_accessibility_ = new RendererAccessibility(this);
}
+void RenderFrameImpl::OnSnapshotAccessibilityTree(int callback_id) {
+ ui::AXTreeUpdate response;
+ RendererAccessibility::SnapshotAccessibilityTree(this, &response);
+ Send(new AccessibilityHostMsg_SnapshotResponse(
+ routing_id_, callback_id, response));
+}
+
void RenderFrameImpl::OnDisownOpener() {
// TODO(creis): We should only see this for main frames for now. To support
// disowning the opener on subframes, we will need to move WebContentsImpl's
@@ -1430,6 +1594,102 @@ void RenderFrameImpl::OnDisownOpener() {
frame_->setOpener(NULL);
}
+void RenderFrameImpl::OnDidUpdateSandboxFlags(SandboxFlags flags) {
+ frame_->setFrameOwnerSandboxFlags(ContentToWebSandboxFlags(flags));
+}
+
+void RenderFrameImpl::OnTextTrackSettingsChanged(
+ const FrameMsg_TextTrackSettings_Params& params) {
+ DCHECK(!frame_->parent());
+ if (!render_view_->webview())
+ return;
+ render_view_->webview()->settings()->setTextTrackBackgroundColor(
+ WebString::fromUTF8(params.text_track_background_color));
+ render_view_->webview()->settings()->setTextTrackFontFamily(
+ WebString::fromUTF8(params.text_track_font_family));
+ render_view_->webview()->settings()->setTextTrackFontStyle(
+ WebString::fromUTF8(params.text_track_font_style));
+ render_view_->webview()->settings()->setTextTrackFontVariant(
+ WebString::fromUTF8(params.text_track_font_variant));
+ render_view_->webview()->settings()->setTextTrackTextColor(
+ WebString::fromUTF8(params.text_track_text_color));
+ render_view_->webview()->settings()->setTextTrackTextShadow(
+ WebString::fromUTF8(params.text_track_text_shadow));
+ render_view_->webview()->settings()->setTextTrackTextSize(
+ WebString::fromUTF8(params.text_track_text_size));
+}
+
+void RenderFrameImpl::OnPostMessageEvent(
+ const FrameMsg_PostMessage_Params& params) {
+ // Find the source frame if it exists.
+ WebFrame* source_frame = NULL;
+ if (params.source_view_routing_id != MSG_ROUTING_NONE) {
+ // Support a legacy postMessage path for specifying a source RenderView;
+ // this is currently used when sending messages to Android WebView.
+ // TODO(alexmos): This path can be removed once crbug.com/473258 is fixed.
+ RenderViewImpl* source_view =
+ RenderViewImpl::FromRoutingID(params.source_view_routing_id);
+ if (source_view)
+ source_frame = source_view->webview()->mainFrame();
+ } else if (params.source_routing_id != MSG_ROUTING_NONE) {
+ RenderFrameProxy* source_proxy =
+ RenderFrameProxy::FromRoutingID(params.source_routing_id);
+ if (source_proxy) {
+ // Currently, navigating a top-level frame cross-process does not swap
+ // the WebLocalFrame for a WebRemoteFrame in the frame tree, and the
+ // WebRemoteFrame will not have an associated blink::Frame. If this is
+ // the case for |source_proxy|, use the corresponding (swapped-out)
+ // WebLocalFrame instead, so that event.source for this message can be
+ // set and used properly.
+ if (source_proxy->IsMainFrameDetachedFromTree())
+ source_frame = source_proxy->render_view()->webview()->mainFrame();
+ else
+ source_frame = source_proxy->web_frame();
+ }
+ }
+
+ // If the message contained MessagePorts, create the corresponding endpoints.
+ blink::WebMessagePortChannelArray channels =
+ WebMessagePortChannelImpl::CreatePorts(
+ params.message_ports, params.new_routing_ids,
+ base::MessageLoopProxy::current().get());
+
+ WebSerializedScriptValue serialized_script_value;
+ if (params.is_data_raw_string) {
+ v8::HandleScope handle_scope(blink::mainThreadIsolate());
+ v8::Local<v8::Context> context = frame_->mainWorldScriptContext();
+ v8::Context::Scope context_scope(context);
+ V8ValueConverterImpl converter;
+ converter.SetDateAllowed(true);
+ converter.SetRegExpAllowed(true);
+ scoped_ptr<base::Value> value(new base::StringValue(params.data));
+ v8::Local<v8::Value> result_value = converter.ToV8Value(value.get(),
+ context);
+ serialized_script_value = WebSerializedScriptValue::serialize(result_value);
+ } else {
+ serialized_script_value = WebSerializedScriptValue::fromString(params.data);
+ }
+
+ // Create an event with the message. The next-to-last parameter to
+ // initMessageEvent is the last event ID, which is not used with postMessage.
+ WebDOMEvent event = frame_->document().createEvent("MessageEvent");
+ WebDOMMessageEvent msg_event = event.to<WebDOMMessageEvent>();
+ msg_event.initMessageEvent("message",
+ // |canBubble| and |cancellable| are always false
+ false, false,
+ serialized_script_value,
+ params.source_origin, source_frame, "", channels);
+
+ // We must pass in the target_origin to do the security check on this side,
+ // since it may have changed since the original postMessage call was made.
+ WebSecurityOrigin target_origin;
+ if (!params.target_origin.empty()) {
+ target_origin =
+ WebSecurityOrigin::createFromString(WebString(params.target_origin));
+ }
+ frame_->dispatchMessageEventWithOriginCheck(target_origin, msg_event);
+}
+
#if defined(OS_ANDROID)
void RenderFrameImpl::OnSelectPopupMenuItems(
bool canceled,
@@ -1484,13 +1744,30 @@ void RenderFrameImpl::OnAddStyleSheetByURL(const std::string& url) {
}
void RenderFrameImpl::OnSetupTransitionView(const std::string& markup) {
- frame_->document().setIsTransitionDocument();
+ frame_->document().setIsTransitionDocument(true);
frame_->navigateToSandboxedMarkup(WebData(markup.data(), markup.length()));
}
-void RenderFrameImpl::OnBeginExitTransition(const std::string& css_selector) {
- frame_->document().setIsTransitionDocument();
- frame_->document().beginExitTransition(WebString::fromUTF8(css_selector));
+void RenderFrameImpl::OnBeginExitTransition(const std::string& css_selector,
+ bool exit_to_native_app) {
+ frame_->document().setIsTransitionDocument(true);
+ frame_->document().beginExitTransition(WebString::fromUTF8(css_selector),
+ exit_to_native_app);
+}
+
+void RenderFrameImpl::OnRevertExitTransition() {
+ frame_->document().setIsTransitionDocument(false);
+ frame_->document().revertExitTransition();
+}
+
+void RenderFrameImpl::OnHideTransitionElements(
+ const std::string& css_selector) {
+ frame_->document().hideTransitionElements(WebString::fromUTF8(css_selector));
+}
+
+void RenderFrameImpl::OnShowTransitionElements(
+ const std::string& css_selector) {
+ frame_->document().showTransitionElements(WebString::fromUTF8(css_selector));
}
bool RenderFrameImpl::RunJavaScriptMessage(JavaScriptMessageType type,
@@ -1530,6 +1807,8 @@ void RenderFrameImpl::LoadNavigationErrorPage(
}
void RenderFrameImpl::DidCommitCompositorFrame() {
+ if (BrowserPluginManager::Get())
+ BrowserPluginManager::Get()->DidCommitCompositorFrame(GetRoutingID());
FOR_EACH_OBSERVER(
RenderFrameObserver, observers_, DidCommitCompositorFrame());
}
@@ -1547,6 +1826,14 @@ blink::WebLocalFrame* RenderFrameImpl::GetWebFrame() {
return frame_;
}
+WebElement RenderFrameImpl::GetFocusedElement() const {
+ WebDocument doc = frame_->document();
+ if (!doc.isNull())
+ return doc.focusedElement();
+
+ return WebElement();
+}
+
WebPreferences& RenderFrameImpl::GetWebkitPreferences() {
return render_view_->GetWebkitPreferences();
}
@@ -1572,15 +1859,27 @@ blink::WebNode RenderFrameImpl::GetContextMenuNode() const {
blink::WebPlugin* RenderFrameImpl::CreatePlugin(
blink::WebFrame* frame,
const WebPluginInfo& info,
- const blink::WebPluginParams& params) {
+ const blink::WebPluginParams& params,
+ scoped_ptr<content::PluginInstanceThrottler> throttler) {
DCHECK_EQ(frame_, frame);
#if defined(ENABLE_PLUGINS)
+ if (info.type == WebPluginInfo::PLUGIN_TYPE_BROWSER_PLUGIN) {
+ scoped_ptr<BrowserPluginDelegate> browser_plugin_delegate(
+ GetContentClient()->renderer()->CreateBrowserPluginDelegate(
+ this, params.mimeType.utf8(), GURL(params.url)));
+ return BrowserPluginManager::Get()->CreateBrowserPlugin(
+ this, browser_plugin_delegate.Pass());
+ }
+
bool pepper_plugin_was_registered = false;
scoped_refptr<PluginModule> pepper_module(PluginModule::Create(
this, info, &pepper_plugin_was_registered));
if (pepper_plugin_was_registered) {
if (pepper_module.get()) {
- return new PepperWebPluginImpl(pepper_module.get(), params, this);
+ return new PepperWebPluginImpl(
+ pepper_module.get(), params, this,
+ make_scoped_ptr(
+ static_cast<PluginInstanceThrottlerImpl*>(throttler.release())));
}
}
#if defined(OS_CHROMEOS)
@@ -1610,6 +1909,15 @@ ServiceRegistry* RenderFrameImpl::GetServiceRegistry() {
return &service_registry_;
}
+#if defined(ENABLE_PLUGINS)
+void RenderFrameImpl::RegisterPeripheralPlugin(
+ const GURL& content_origin,
+ const base::Closure& unthrottle_callback) {
+ return plugin_power_saver_helper_->RegisterPeripheralPlugin(
+ content_origin, unthrottle_callback);
+}
+#endif // defined(ENABLE_PLUGINS)
+
bool RenderFrameImpl::IsFTPDirectoryListing() {
WebURLResponseExtraDataImpl* extra_data =
GetExtraDataFromResponse(frame_->dataSource()->response());
@@ -1617,7 +1925,11 @@ bool RenderFrameImpl::IsFTPDirectoryListing() {
}
void RenderFrameImpl::AttachGuest(int element_instance_id) {
- render_view_->GetBrowserPluginManager()->Attach(element_instance_id);
+ BrowserPluginManager::Get()->Attach(element_instance_id);
+}
+
+void RenderFrameImpl::DetachGuest(int element_instance_id) {
+ BrowserPluginManager::Get()->Detach(element_instance_id);
}
void RenderFrameImpl::SetSelectedText(const base::string16& selection_text,
@@ -1632,7 +1944,7 @@ void RenderFrameImpl::SetSelectedText(const base::string16& selection_text,
void RenderFrameImpl::EnsureMojoBuiltinsAreAvailable(
v8::Isolate* isolate,
- v8::Handle<v8::Context> context) {
+ v8::Local<v8::Context> context) {
gin::ModuleRegistry* registry = gin::ModuleRegistry::From(context);
if (registry->available_modules().count(mojo::js::Core::kModuleName))
return;
@@ -1675,8 +1987,8 @@ blink::WebPlugin* RenderFrameImpl::createPlugin(
scoped_ptr<BrowserPluginDelegate> browser_plugin_delegate(
GetContentClient()->renderer()->CreateBrowserPluginDelegate(this,
kBrowserPluginMimeType, GURL(params.url)));
- return render_view_->GetBrowserPluginManager()->CreateBrowserPlugin(
- render_view_.get(), frame, browser_plugin_delegate.Pass());
+ return BrowserPluginManager::Get()->CreateBrowserPlugin(
+ this, browser_plugin_delegate.Pass());
}
#if defined(ENABLE_PLUGINS)
@@ -1689,18 +2001,9 @@ blink::WebPlugin* RenderFrameImpl::createPlugin(
if (!found)
return NULL;
- if (info.type == WebPluginInfo::PLUGIN_TYPE_BROWSER_PLUGIN) {
- scoped_ptr<BrowserPluginDelegate> browser_plugin_delegate(
- GetContentClient()->renderer()->CreateBrowserPluginDelegate(
- this, mime_type, GURL(params.url)));
- return render_view_->GetBrowserPluginManager()->CreateBrowserPlugin(
- render_view_.get(), frame, browser_plugin_delegate.Pass());
- }
-
-
WebPluginParams params_to_use = params;
params_to_use.mimeType = WebString::fromUTF8(mime_type);
- return CreatePlugin(frame, info, params_to_use);
+ return CreatePlugin(frame, info, params_to_use, nullptr /* throttler */);
#else
return NULL;
#endif // defined(ENABLE_PLUGINS)
@@ -1710,7 +2013,7 @@ blink::WebMediaPlayer* RenderFrameImpl::createMediaPlayer(
blink::WebLocalFrame* frame,
const blink::WebURL& url,
blink::WebMediaPlayerClient* client) {
- return createMediaPlayer(frame, url, client, NULL);
+ return createMediaPlayer(frame, url, client, nullptr);
}
blink::WebMediaPlayer* RenderFrameImpl::createMediaPlayer(
@@ -1731,45 +2034,42 @@ blink::WebMediaPlayer* RenderFrameImpl::createMediaPlayer(
return CreateWebMediaPlayerForMediaStream(url, client);
#if defined(OS_ANDROID)
- return CreateAndroidWebMediaPlayer(url, client, initial_cdm);
+ return CreateAndroidWebMediaPlayer(url, client, GetMediaPermission(),
+ initial_cdm);
#else
+ scoped_refptr<media::MediaLog> media_log(new RenderMediaLog());
+
RenderThreadImpl* render_thread = RenderThreadImpl::current();
media::WebMediaPlayerParams params(
base::Bind(&ContentRendererClient::DeferMediaLoad,
base::Unretained(GetContentClient()->renderer()),
static_cast<RenderFrame*>(this)),
- render_thread->GetAudioRendererMixerManager()->CreateInput(
- render_view_->routing_id_, routing_id_),
- *render_thread->GetAudioHardwareConfig(),
- new RenderMediaLog(),
- render_thread->GetGpuFactories(),
- render_thread->GetMediaThreadTaskRunner(),
+ render_thread->GetAudioRendererMixerManager()->CreateInput(routing_id_),
+ media_log, render_thread->GetMediaThreadTaskRunner(),
render_thread->compositor_message_loop_proxy(),
- base::Bind(&EncryptedMediaPlayerSupportImpl::Create),
+ base::Bind(&GetSharedMainThreadContext3D), GetMediaPermission(),
initial_cdm);
- return new media::WebMediaPlayerImpl(
- frame, client, weak_factory_.GetWeakPtr(), nullptr, params);
-#endif // defined(OS_ANDROID)
-}
-
-blink::WebContentDecryptionModule*
-RenderFrameImpl::createContentDecryptionModule(
- blink::WebLocalFrame* frame,
- const blink::WebSecurityOrigin& security_origin,
- const blink::WebString& key_system) {
- DCHECK(!frame_ || frame_ == frame);
-#if defined(ENABLE_PEPPER_CDMS)
- RenderCdmFactory cdm_factory(
- base::Bind(&PepperCdmWrapperImpl::Create, frame));
-#elif defined(ENABLE_BROWSER_CDMS)
- RenderCdmFactory cdm_factory(GetCdmManager());
+#if defined(ENABLE_MEDIA_MOJO_RENDERER)
+ scoped_ptr<media::RendererFactory> media_renderer_factory(
+ new media::MojoRendererFactory(make_scoped_ptr(
+ new MediaRendererServiceProvider(GetServiceRegistry()))));
#else
- RenderCdmFactory cdm_factory;
-#endif
+ scoped_ptr<media::RendererFactory> media_renderer_factory =
+ GetContentClient()->renderer()->CreateMediaRendererFactory(this,
+ media_log);
+
+ if (!media_renderer_factory.get()) {
+ media_renderer_factory.reset(new media::DefaultRendererFactory(
+ media_log, render_thread->GetGpuFactories(),
+ *render_thread->GetAudioHardwareConfig()));
+ }
+#endif // defined(ENABLE_MEDIA_MOJO_RENDERER)
- return WebContentDecryptionModuleImpl::Create(&cdm_factory, security_origin,
- key_system);
+ return new media::WebMediaPlayerImpl(
+ frame, client, weak_factory_.GetWeakPtr(), media_renderer_factory.Pass(),
+ GetCdmFactory(), params);
+#endif // defined(OS_ANDROID)
}
blink::WebApplicationCacheHost* RenderFrameImpl::createApplicationCacheHost(
@@ -1783,13 +2083,13 @@ blink::WebApplicationCacheHost* RenderFrameImpl::createApplicationCacheHost(
RenderThreadImpl::current()->appcache_dispatcher()->backend_proxy());
}
-blink::WebWorkerPermissionClientProxy*
-RenderFrameImpl::createWorkerPermissionClientProxy(
+blink::WebWorkerContentSettingsClientProxy*
+RenderFrameImpl::createWorkerContentSettingsClientProxy(
blink::WebLocalFrame* frame) {
if (!frame || !frame->view())
return NULL;
DCHECK(!frame_ || frame_ == frame);
- return GetContentClient()->renderer()->CreateWorkerPermissionClientProxy(
+ return GetContentClient()->renderer()->CreateWorkerContentSettingsClientProxy(
this, frame);
}
@@ -1828,50 +2128,50 @@ blink::WebServiceWorkerProvider* RenderFrameImpl::createServiceWorkerProvider(
DCHECK(!frame_ || frame_ == frame);
// At this point we should have non-null data source.
DCHECK(frame->dataSource());
- if (!ChildThread::current())
+ if (!ChildThreadImpl::current())
return NULL; // May be null in some tests.
ServiceWorkerNetworkProvider* provider =
ServiceWorkerNetworkProvider::FromDocumentState(
DocumentState::FromDataSource(frame->dataSource()));
return new WebServiceWorkerProviderImpl(
- ChildThread::current()->thread_safe_sender(),
+ ChildThreadImpl::current()->thread_safe_sender(),
provider ? provider->context() : NULL);
}
void RenderFrameImpl::didAccessInitialDocument(blink::WebLocalFrame* frame) {
DCHECK(!frame_ || frame_ == frame);
- // Notify the browser process that it is no longer safe to show the pending
- // URL of the main frame, since a URL spoof is now possible.
- if (!frame->parent() && render_view_->page_id_ == -1)
- Send(new FrameHostMsg_DidAccessInitialDocument(routing_id_));
+ // If the request hasn't yet committed, notify the browser process that it is
+ // no longer safe to show the pending URL of the main frame, since a URL spoof
+ // is now possible. (If the request has committed, the browser already knows.)
+ if (!frame->parent()) {
+ DocumentState* document_state =
+ DocumentState::FromDataSource(frame->dataSource());
+ NavigationStateImpl* navigation_state =
+ static_cast<NavigationStateImpl*>(document_state->navigation_state());
+
+ if (!navigation_state->request_committed()) {
+ Send(new FrameHostMsg_DidAccessInitialDocument(routing_id_));
+ }
+ }
}
blink::WebFrame* RenderFrameImpl::createChildFrame(
blink::WebLocalFrame* parent,
- const blink::WebString& name) {
+ const blink::WebString& name,
+ blink::WebSandboxFlags sandbox_flags) {
// Synchronously notify the browser of a child frame creation to get the
// routing_id for the RenderFrame.
int child_routing_id = MSG_ROUTING_NONE;
- Send(new FrameHostMsg_CreateChildFrame(routing_id_,
- base::UTF16ToUTF8(name),
- &child_routing_id));
+ Send(new FrameHostMsg_CreateChildFrame(
+ routing_id_, base::UTF16ToUTF8(name),
+ WebToContentSandboxFlags(sandbox_flags), &child_routing_id));
+
// Allocation of routing id failed, so we can't create a child frame. This can
// happen if this RenderFrameImpl's IPCs are being filtered when in swapped
- // out state.
+ // out state or synchronous IPC message above has failed.
if (child_routing_id == MSG_ROUTING_NONE) {
-#if !defined(OS_LINUX)
- // DumpWithoutCrashing() crashes on Linux in renderer processes when
- // breakpad and sandboxing are enabled: crbug.com/349600
- base::debug::Alias(parent);
- base::debug::Alias(&routing_id_);
- bool render_view_is_swapped_out = GetRenderWidget()->is_swapped_out();
- base::debug::Alias(&render_view_is_swapped_out);
- bool render_view_is_closing = GetRenderWidget()->closing();
- base::debug::Alias(&render_view_is_closing);
- base::debug::Alias(&is_swapped_out_);
- base::debug::DumpWithoutCrashing();
-#endif
- return NULL;
+ NOTREACHED() << "Failed to allocate routing id for child frame.";
+ return nullptr;
}
// Create the RenderFrame and WebLocalFrame, linking the two.
@@ -1893,7 +2193,7 @@ void RenderFrameImpl::didDisownOpener(blink::WebLocalFrame* frame) {
// its opener. We can ignore cases where a swapped out frame clears its
// opener after hearing about it from the browser, and the browser does not
// (yet) care about subframe openers.
- if (render_view_->is_swapped_out_ || frame->parent())
+ if (is_swapped_out_ || frame->parent())
return;
// Notify WebContents and all its swapped out RenderViews.
@@ -1907,19 +2207,16 @@ void RenderFrameImpl::frameDetached(blink::WebFrame* frame) {
CHECK(!is_detaching_);
DCHECK(!frame_ || frame_ == frame);
- bool is_subframe = !!frame->parent();
+ FOR_EACH_OBSERVER(RenderFrameObserver, observers_, FrameDetached());
+ FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(),
+ FrameDetached(frame));
Send(new FrameHostMsg_Detach(routing_id_));
// The |is_detaching_| flag disables Send(). FrameHostMsg_Detach must be
- // sent before setting |is_detaching_| to true. In contrast, Observers
- // should only be notified afterwards so they cannot call back into here and
- // have IPCs fired off.
+ // sent before setting |is_detaching_| to true.
is_detaching_ = true;
- FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(),
- FrameDetached(frame));
-
// We need to clean up subframes by removing them from the map and deleting
// the RenderFrameImpl. In contrast, the main frame is owned by its
// containing RenderViewHost (so that they have the same lifetime), so only
@@ -1929,16 +2226,22 @@ void RenderFrameImpl::frameDetached(blink::WebFrame* frame) {
CHECK_EQ(it->second, this);
g_frame_map.Get().erase(it);
- if (is_subframe)
+ if (is_subframe_) {
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess) && render_widget_) {
+ render_widget_->UnregisterRenderFrame(this);
+ }
frame->parent()->removeChild(frame);
+ }
- // |frame| is invalid after here.
+ // |frame| is invalid after here. Be sure to clear frame_ as well, since this
+ // object may not be deleted immediately and other methods may try to access
+ // it.
frame->close();
+ frame_ = nullptr;
- if (is_subframe) {
- delete this;
- // Object is invalid after this point.
- }
+ delete this;
+ // Object is invalid after this point.
}
void RenderFrameImpl::frameFocused() {
@@ -1956,10 +2259,36 @@ void RenderFrameImpl::willClose(blink::WebFrame* frame) {
void RenderFrameImpl::didChangeName(blink::WebLocalFrame* frame,
const blink::WebString& name) {
DCHECK(!frame_ || frame_ == frame);
- if (!render_view_->renderer_preferences_.report_frame_name_changes)
- return;
- FOR_EACH_OBSERVER(RenderFrameObserver, observers_, DidChangeName(name));
+ // TODO(alexmos): According to https://crbug.com/169110, sending window.name
+ // updates may have performance implications for benchmarks like SunSpider.
+ // For now, send these updates only for --site-per-process, which needs to
+ // replicate frame names to frame proxies, and when
+ // |report_frame_name_changes| is set (used by <webview>). If needed, this
+ // can be optimized further by only sending the update if there are any
+ // remote frames in the frame tree, or delaying and batching up IPCs if
+ // updates are happening too frequently.
+ bool is_site_per_process = base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess);
+ if (is_site_per_process ||
+ render_view_->renderer_preferences_.report_frame_name_changes) {
+ Send(new FrameHostMsg_DidChangeName(routing_id_, base::UTF16ToUTF8(name)));
+ }
+}
+
+void RenderFrameImpl::didChangeSandboxFlags(blink::WebFrame* child_frame,
+ blink::WebSandboxFlags flags) {
+ int frame_routing_id = MSG_ROUTING_NONE;
+ if (child_frame->isWebRemoteFrame()) {
+ frame_routing_id =
+ RenderFrameProxy::FromWebFrame(child_frame)->routing_id();
+ } else {
+ frame_routing_id =
+ RenderFrameImpl::FromWebFrame(child_frame)->GetRoutingID();
+ }
+
+ Send(new FrameHostMsg_DidChangeSandboxFlags(routing_id_, frame_routing_id,
+ WebToContentSandboxFlags(flags)));
}
void RenderFrameImpl::didMatchCSS(
@@ -2001,7 +2330,7 @@ void RenderFrameImpl::didAddMessageToConsole(
log_severity = logging::LOG_ERROR;
break;
default:
- NOTREACHED();
+ log_severity = logging::LOG_VERBOSE;
}
if (shouldReportDetailedMessageForSource(source_name)) {
@@ -2053,8 +2382,7 @@ void RenderFrameImpl::willSendSubmitEvent(blink::WebLocalFrame* frame,
const blink::WebFormElement& form) {
DCHECK(!frame_ || frame_ == frame);
- FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(),
- WillSendSubmitEvent(frame, form));
+ FOR_EACH_OBSERVER(RenderFrameObserver, observers_, WillSendSubmitEvent(form));
}
void RenderFrameImpl::willSubmitForm(blink::WebLocalFrame* frame,
@@ -2062,11 +2390,12 @@ void RenderFrameImpl::willSubmitForm(blink::WebLocalFrame* frame,
DCHECK(!frame_ || frame_ == frame);
DocumentState* document_state =
DocumentState::FromDataSource(frame->provisionalDataSource());
- NavigationState* navigation_state = document_state->navigation_state();
+ NavigationStateImpl* navigation_state =
+ static_cast<NavigationStateImpl*>(document_state->navigation_state());
InternalDocumentStateData* internal_data =
InternalDocumentStateData::FromDocumentState(document_state);
- if (ui::PageTransitionCoreTypeIs(navigation_state->transition_type(),
+ if (ui::PageTransitionCoreTypeIs(navigation_state->GetTransitionType(),
ui::PAGE_TRANSITION_LINK)) {
navigation_state->set_transition_type(ui::PAGE_TRANSITION_FORM_SUBMIT);
}
@@ -2077,32 +2406,123 @@ void RenderFrameImpl::willSubmitForm(blink::WebLocalFrame* frame,
internal_data->set_searchable_form_encoding(
web_searchable_form_data.encoding().utf8());
- FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(),
- WillSubmitForm(frame, form));
+ FOR_EACH_OBSERVER(RenderFrameObserver, observers_, WillSubmitForm(form));
}
void RenderFrameImpl::didCreateDataSource(blink::WebLocalFrame* frame,
blink::WebDataSource* datasource) {
DCHECK(!frame_ || frame_ == frame);
- // TODO(nasko): Move implementation here. Needed state:
- // * pending_navigation_params_
- // * webview
- // Needed methods:
- // * PopulateDocumentStateFromPending
- // * CreateNavigationStateFromPending
- render_view_->didCreateDataSource(frame, datasource);
+ bool content_initiated = !pending_navigation_params_.get();
+
+ // Make sure any previous redirect URLs end up in our new data source.
+ if (pending_navigation_params_.get()) {
+ for (const auto& i :
+ pending_navigation_params_->request_params.redirects) {
+ datasource->appendRedirect(i);
+ }
+ }
+
+ DocumentState* document_state = DocumentState::FromDataSource(datasource);
+ if (!document_state) {
+ document_state = new DocumentState;
+ datasource->setExtraData(document_state);
+ if (!content_initiated)
+ PopulateDocumentStateFromPending(document_state);
+ }
+
+ // Carry over the user agent override flag, if it exists.
+ blink::WebView* webview = render_view_->webview();
+ if (content_initiated && webview && webview->mainFrame() &&
+ webview->mainFrame()->isWebLocalFrame() &&
+ webview->mainFrame()->dataSource()) {
+ DocumentState* old_document_state =
+ DocumentState::FromDataSource(webview->mainFrame()->dataSource());
+ if (old_document_state) {
+ InternalDocumentStateData* internal_data =
+ InternalDocumentStateData::FromDocumentState(document_state);
+ InternalDocumentStateData* old_internal_data =
+ InternalDocumentStateData::FromDocumentState(old_document_state);
+ internal_data->set_is_overriding_user_agent(
+ old_internal_data->is_overriding_user_agent());
+ }
+ }
+
+ // The rest of RenderView assumes that a WebDataSource will always have a
+ // non-null NavigationState.
+ if (content_initiated) {
+ document_state->set_navigation_state(
+ NavigationStateImpl::CreateContentInitiated());
+ } else {
+ document_state->set_navigation_state(CreateNavigationStateFromPending());
+ pending_navigation_params_.reset();
+ }
+
+ // DocumentState::referred_by_prefetcher_ is true if we are
+ // navigating from a page that used prefetching using a link on that
+ // page. We are early enough in the request process here that we
+ // can still see the DocumentState of the previous page and set
+ // this value appropriately.
+ // TODO(gavinp): catch the important case of navigation in a new
+ // renderer process.
+ if (webview) {
+ if (WebFrame* old_frame = webview->mainFrame()) {
+ const WebURLRequest& original_request = datasource->originalRequest();
+ const GURL referrer(
+ original_request.httpHeaderField(WebString::fromUTF8("Referer")));
+ if (!referrer.is_empty() && old_frame->isWebLocalFrame() &&
+ DocumentState::FromDataSource(old_frame->dataSource())
+ ->was_prefetcher()) {
+ for (; old_frame; old_frame = old_frame->traverseNext(false)) {
+ WebDataSource* old_frame_datasource = old_frame->dataSource();
+ if (old_frame_datasource &&
+ referrer == GURL(old_frame_datasource->request().url())) {
+ document_state->set_was_referred_by_prefetcher(true);
+ break;
+ }
+ }
+ }
+ }
+ }
- // Create the serviceworker's per-document network observing object.
- scoped_ptr<ServiceWorkerNetworkProvider>
- network_provider(new ServiceWorkerNetworkProvider());
- ServiceWorkerNetworkProvider::AttachToDocumentState(
- DocumentState::FromDataSource(datasource),
- network_provider.Pass());
+ if (content_initiated) {
+ const WebURLRequest& request = datasource->request();
+ switch (request.cachePolicy()) {
+ case WebURLRequest::UseProtocolCachePolicy: // normal load.
+ document_state->set_load_type(DocumentState::LINK_LOAD_NORMAL);
+ break;
+ case WebURLRequest::ReloadIgnoringCacheData: // reload.
+ case WebURLRequest::ReloadBypassingCache: // end-to-end reload.
+ document_state->set_load_type(DocumentState::LINK_LOAD_RELOAD);
+ break;
+ case WebURLRequest::ReturnCacheDataElseLoad: // allow stale data.
+ document_state->set_load_type(DocumentState::LINK_LOAD_CACHE_STALE_OK);
+ break;
+ case WebURLRequest::ReturnCacheDataDontLoad: // Don't re-post.
+ document_state->set_load_type(DocumentState::LINK_LOAD_CACHE_ONLY);
+ break;
+ default:
+ NOTREACHED();
+ }
+ }
+
+ // Create the serviceworker's per-document network observing object if it
+ // does not exist (When navigation happens within a page, the provider already
+ // exists).
+ if (!ServiceWorkerNetworkProvider::FromDocumentState(
+ DocumentState::FromDataSource(datasource))) {
+ scoped_ptr<ServiceWorkerNetworkProvider> network_provider(
+ new ServiceWorkerNetworkProvider(routing_id_,
+ SERVICE_WORKER_PROVIDER_FOR_WINDOW));
+ ServiceWorkerNetworkProvider::AttachToDocumentState(
+ DocumentState::FromDataSource(datasource),
+ network_provider.Pass());
+ }
}
void RenderFrameImpl::didStartProvisionalLoad(blink::WebLocalFrame* frame,
- bool is_transition_navigation) {
+ bool is_transition_navigation,
+ double triggering_event_time) {
DCHECK(!frame_ || frame_ == frame);
WebDataSource* ds = frame->provisionalDataSource();
@@ -2117,15 +2537,13 @@ void RenderFrameImpl::didStartProvisionalLoad(blink::WebLocalFrame* frame,
// We should only navigate to swappedout:// when is_swapped_out_ is true.
CHECK((ds->request().url() != GURL(kSwappedOutURL)) ||
- is_swapped_out_ ||
- render_view_->is_swapped_out()) <<
+ is_swapped_out_) <<
"Heard swappedout:// when not swapped out.";
// Update the request time if WebKit has better knowledge of it.
- if (document_state->request_time().is_null()) {
- double event_time = ds->triggeringEventTime();
- if (event_time != 0.0)
- document_state->set_request_time(Time::FromDoubleT(event_time));
+ if (document_state->request_time().is_null() &&
+ triggering_event_time != 0.0) {
+ document_state->set_request_time(Time::FromDoubleT(triggering_event_time));
}
// Start time is only set after request time.
@@ -2140,8 +2558,8 @@ void RenderFrameImpl::didStartProvisionalLoad(blink::WebLocalFrame* frame,
// Subframe navigations that don't add session history items must be
// marked with AUTO_SUBFRAME. See also didFailProvisionalLoad for how we
// handle loading of error pages.
- document_state->navigation_state()->set_transition_type(
- ui::PAGE_TRANSITION_AUTO_SUBFRAME);
+ static_cast<NavigationStateImpl*>(document_state->navigation_state())
+ ->set_transition_type(ui::PAGE_TRANSITION_AUTO_SUBFRAME);
}
FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(),
@@ -2158,8 +2576,10 @@ void RenderFrameImpl::didReceiveServerRedirectForProvisionalLoad(
render_view_->history_controller()->RemoveChildrenForRedirect(this);
}
-void RenderFrameImpl::didFailProvisionalLoad(blink::WebLocalFrame* frame,
- const blink::WebURLError& error) {
+void RenderFrameImpl::didFailProvisionalLoad(
+ blink::WebLocalFrame* frame,
+ const blink::WebURLError& error,
+ blink::WebHistoryCommitType commit_type) {
TRACE_EVENT1("navigation", "RenderFrameImpl::didFailProvisionalLoad",
"id", routing_id_);
DCHECK(!frame_ || frame_ == frame);
@@ -2179,84 +2599,32 @@ void RenderFrameImpl::didFailProvisionalLoad(blink::WebLocalFrame* frame,
FOR_EACH_OBSERVER(RenderFrameObserver, observers_,
DidFailProvisionalLoad(error));
- bool show_repost_interstitial =
- (error.reason == net::ERR_CACHE_MISS &&
- EqualsASCII(failed_request.httpMethod(), "POST"));
-
- FrameHostMsg_DidFailProvisionalLoadWithError_Params params;
- params.error_code = error.reason;
- GetContentClient()->renderer()->GetNavigationErrorStrings(
- render_view_.get(),
- frame,
- failed_request,
- error,
- NULL,
- &params.error_description);
- params.url = error.unreachableURL;
- params.showing_repost_interstitial = show_repost_interstitial;
- Send(new FrameHostMsg_DidFailProvisionalLoadWithError(
- routing_id_, params));
-
- // Don't display an error page if this is simply a cancelled load. Aside
- // from being dumb, WebCore doesn't expect it and it will cause a crash.
- if (error.reason == net::ERR_ABORTED)
- return;
-
- // Don't display "client blocked" error page if browser has asked us not to.
- if (error.reason == net::ERR_BLOCKED_BY_CLIENT &&
- render_view_->renderer_preferences_.disable_client_blocked_error_page) {
- return;
- }
-
- // Allow the embedder to suppress an error page.
- if (GetContentClient()->renderer()->ShouldSuppressErrorPage(this,
- error.unreachableURL)) {
- return;
- }
+ SendFailedProvisionalLoad(failed_request, error, frame);
- if (RenderThreadImpl::current() &&
- RenderThreadImpl::current()->layout_test_mode()) {
+ if (!ShouldDisplayErrorPageForFailedLoad(error.reason, error.unreachableURL))
return;
- }
// Make sure we never show errors in view source mode.
frame->enableViewSourceMode(false);
DocumentState* document_state = DocumentState::FromDataSource(ds);
- NavigationState* navigation_state = document_state->navigation_state();
+ NavigationStateImpl* navigation_state =
+ static_cast<NavigationStateImpl*>(document_state->navigation_state());
// If this is a failed back/forward/reload navigation, then we need to do a
// 'replace' load. This is necessary to avoid messing up session history.
// Otherwise, we do a normal load, which simulates a 'go' navigation as far
// as session history is concerned.
- //
- // AUTO_SUBFRAME loads should always be treated as loads that do not advance
- // the page id.
- //
- // TODO(davidben): This should also take the failed navigation's replacement
- // state into account, if a location.replace() failed.
- bool replace =
- navigation_state->pending_page_id() != -1 ||
- ui::PageTransitionCoreTypeIs(navigation_state->transition_type(),
- ui::PAGE_TRANSITION_AUTO_SUBFRAME);
+ bool replace = commit_type != blink::WebStandardCommit;
// If we failed on a browser initiated request, then make sure that our error
// page load is regarded as the same browser initiated request.
- if (!navigation_state->is_content_initiated()) {
- render_view_->pending_navigation_params_.reset(
- new FrameMsg_Navigate_Params);
- render_view_->pending_navigation_params_->page_id =
- navigation_state->pending_page_id();
- render_view_->pending_navigation_params_->pending_history_list_offset =
- navigation_state->pending_history_list_offset();
- render_view_->pending_navigation_params_->should_clear_history_list =
- navigation_state->history_list_was_cleared();
- render_view_->pending_navigation_params_->common_params.transition =
- navigation_state->transition_type();
- render_view_->pending_navigation_params_->request_time =
+ if (!navigation_state->IsContentInitiated()) {
+ pending_navigation_params_.reset(new NavigationParams(
+ navigation_state->common_params(), navigation_state->start_params(),
+ navigation_state->request_params()));
+ pending_navigation_params_->request_params.request_time =
document_state->request_time();
- render_view_->pending_navigation_params_->should_replace_current_entry =
- replace;
}
// Load an error page.
@@ -2273,7 +2641,8 @@ void RenderFrameImpl::didCommitProvisionalLoad(
DCHECK(!frame_ || frame_ == frame);
DocumentState* document_state =
DocumentState::FromDataSource(frame->dataSource());
- NavigationState* navigation_state = document_state->navigation_state();
+ NavigationStateImpl* navigation_state =
+ static_cast<NavigationStateImpl*>(document_state->navigation_state());
if (proxy_routing_id_ != MSG_ROUTING_NONE) {
RenderFrameProxy* proxy =
@@ -2281,6 +2650,13 @@ void RenderFrameImpl::didCommitProvisionalLoad(
CHECK(proxy);
proxy->web_frame()->swap(frame_);
proxy_routing_id_ = MSG_ROUTING_NONE;
+
+ // If this is the main frame going from a remote frame to a local frame,
+ // it needs to set RenderViewImpl's pointer for the main frame to itself.
+ if (!is_subframe_) {
+ CHECK(!render_view_->main_render_frame_);
+ render_view_->main_render_frame_ = this;
+ }
}
// When we perform a new navigation, we need to update the last committed
@@ -2288,8 +2664,8 @@ void RenderFrameImpl::didCommitProvisionalLoad(
// before updating the HistoryController state.
render_view_->UpdateSessionHistory(frame);
- render_view_->history_controller()->UpdateForCommit(this, item, commit_type,
- navigation_state->was_within_same_page());
+ render_view_->history_controller()->UpdateForCommit(
+ this, item, commit_type, navigation_state->WasWithinSamePage());
InternalDocumentStateData* internal_data =
InternalDocumentStateData::FromDocumentState(document_state);
@@ -2308,13 +2684,17 @@ void RenderFrameImpl::didCommitProvisionalLoad(
// We bump our Page ID to correspond with the new session history entry.
render_view_->page_id_ = render_view_->next_page_id_++;
- // Don't update history_page_ids_ (etc) for kSwappedOutURL, since
+ // Don't update history list values for kSwappedOutURL, since
// we don't want to forget the entry that was there, and since we will
// never come back to kSwappedOutURL. Note that we have to call
// UpdateSessionHistory and update page_id_ even in this case, so that
// the current entry gets a state update and so that we don't send a
// state update to the wrong entry when we swap back in.
- if (GetLoadingUrl() != GURL(kSwappedOutURL)) {
+ DCHECK_IMPLIES(
+ navigation_state->start_params().should_replace_current_entry,
+ render_view_->history_list_length_ > 0);
+ if (GetLoadingUrl() != GURL(kSwappedOutURL) &&
+ !navigation_state->start_params().should_replace_current_entry) {
// Advance our offset in session history, applying the length limit.
// There is now no forward history.
render_view_->history_list_offset_++;
@@ -2322,38 +2702,17 @@ void RenderFrameImpl::didCommitProvisionalLoad(
render_view_->history_list_offset_ = kMaxSessionHistoryEntries - 1;
render_view_->history_list_length_ =
render_view_->history_list_offset_ + 1;
- render_view_->history_page_ids_.resize(
- render_view_->history_list_length_, -1);
- render_view_->history_page_ids_[render_view_->history_list_offset_] =
- render_view_->page_id_;
}
} else {
- // Inspect the navigation_state on this frame to see if the navigation
- // corresponds to a session history navigation... Note: |frame| may or
- // may not be the toplevel frame, but for the case of capturing session
- // history, the first committed frame suffices. We keep track of whether
- // we've seen this commit before so that only capture session history once
- // per navigation.
- //
- // Note that we need to check if the page ID changed. In the case of a
- // reload, the page ID doesn't change, and UpdateSessionHistory gets the
- // previous URL and the current page ID, which would be wrong.
- if (navigation_state->pending_page_id() != -1 &&
- navigation_state->pending_page_id() != render_view_->page_id_ &&
- !navigation_state->request_committed()) {
+ const RequestNavigationParams& request_params =
+ navigation_state->request_params();
+ if (request_params.nav_entry_id != 0 &&
+ !request_params.intended_as_new_entry) {
// This is a successful session history navigation!
- render_view_->page_id_ = navigation_state->pending_page_id();
+ render_view_->page_id_ = request_params.page_id;
render_view_->history_list_offset_ =
- navigation_state->pending_history_list_offset();
-
- // If the history list is valid, our list of page IDs should be correct.
- DCHECK(render_view_->history_list_length_ <= 0 ||
- render_view_->history_list_offset_ < 0 ||
- render_view_->history_list_offset_ >=
- render_view_->history_list_length_ ||
- render_view_->history_page_ids_[render_view_->history_list_offset_]
- == render_view_->page_id_);
+ request_params.pending_history_list_offset;
}
}
@@ -2363,8 +2722,10 @@ void RenderFrameImpl::didCommitProvisionalLoad(
FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers_,
DidCommitProvisionalLoad(frame, is_new_navigation));
- FOR_EACH_OBSERVER(RenderFrameObserver, observers_,
- DidCommitProvisionalLoad(is_new_navigation));
+ FOR_EACH_OBSERVER(
+ RenderFrameObserver, observers_,
+ DidCommitProvisionalLoad(is_new_navigation,
+ navigation_state->WasWithinSamePage()));
if (!frame->parent()) { // Only for top frames.
RenderThreadImpl* render_thread_impl = RenderThreadImpl::current();
@@ -2382,24 +2743,47 @@ void RenderFrameImpl::didCommitProvisionalLoad(
// new navigation.
navigation_state->set_request_committed(true);
- SendDidCommitProvisionalLoad(frame);
+ SendDidCommitProvisionalLoad(frame, commit_type);
// Check whether we have new encoding name.
UpdateEncoding(frame, frame->view()->pageEncoding().utf8());
}
+void RenderFrameImpl::didCreateNewDocument(blink::WebLocalFrame* frame) {
+ DCHECK(!frame_ || frame_ == frame);
+
+ FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(),
+ DidCreateNewDocument(frame));
+}
+
void RenderFrameImpl::didClearWindowObject(blink::WebLocalFrame* frame) {
DCHECK(!frame_ || frame_ == frame);
- // TODO(nasko): Move implementation here. Needed state:
- // * enabled_bindings_
- // * dom_automation_controller_
- // * stats_collection_controller_
- render_view_->didClearWindowObject(frame);
+ int enabled_bindings = render_view_->GetEnabledBindings();
+
+ if (enabled_bindings & BINDINGS_POLICY_WEB_UI)
+ WebUIExtension::Install(frame);
- if (render_view_->GetEnabledBindings() & BINDINGS_POLICY_DOM_AUTOMATION)
+ if (enabled_bindings & BINDINGS_POLICY_DOM_AUTOMATION)
DomAutomationController::Install(this, frame);
+ if (enabled_bindings & BINDINGS_POLICY_STATS_COLLECTION)
+ StatsCollectionController::Install(frame);
+
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
+
+ if (command_line.HasSwitch(cc::switches::kEnableGpuBenchmarking))
+ GpuBenchmarking::Install(frame);
+
+ if (command_line.HasSwitch(switches::kEnableMemoryBenchmarking))
+ MemoryBenchmarkingExtension::Install(frame);
+
+ if (command_line.HasSwitch(switches::kEnableSkiaBenchmarking))
+ SkiaBenchmarking::Install(frame);
+
+ FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(),
+ DidClearWindowObject(frame));
FOR_EACH_OBSERVER(RenderFrameObserver, observers_, DidClearWindowObject());
}
@@ -2433,7 +2817,7 @@ void RenderFrameImpl::didReceiveTitle(blink::WebLocalFrame* frame,
// Ignore all but top level navigations.
if (!frame->parent()) {
base::string16 title16 = title;
- base::debug::TraceLog::GetInstance()->UpdateProcessLabel(
+ base::trace_event::TraceLog::GetInstance()->UpdateProcessLabel(
routing_id_, base::UTF16ToUTF8(title16));
base::string16 shortened_title = title16.substr(0, kMaxTitleChars);
@@ -2472,12 +2856,22 @@ void RenderFrameImpl::didFinishDocumentLoad(blink::WebLocalFrame* frame) {
void RenderFrameImpl::didHandleOnloadEvents(blink::WebLocalFrame* frame) {
DCHECK(!frame_ || frame_ == frame);
- if (!frame->parent())
- Send(new FrameHostMsg_DocumentOnLoadCompleted(routing_id_));
+ if (!frame->parent()) {
+ FrameMsg_UILoadMetricsReportType::Value report_type =
+ static_cast<FrameMsg_UILoadMetricsReportType::Value>(
+ frame->dataSource()->request().inputPerfMetricReportPolicy());
+ base::TimeTicks ui_timestamp = base::TimeTicks() +
+ base::TimeDelta::FromSecondsD(
+ frame->dataSource()->request().uiStartTime());
+
+ Send(new FrameHostMsg_DocumentOnLoadCompleted(
+ routing_id_, report_type, ui_timestamp));
+ }
}
void RenderFrameImpl::didFailLoad(blink::WebLocalFrame* frame,
- const blink::WebURLError& error) {
+ const blink::WebURLError& error,
+ blink::WebHistoryCommitType commit_type) {
TRACE_EVENT1("navigation", "RenderFrameImpl::didFailLoad",
"id", routing_id_);
DCHECK(!frame_ || frame_ == frame);
@@ -2541,13 +2935,13 @@ void RenderFrameImpl::didNavigateWithinPage(blink::WebLocalFrame* frame,
// ExtraData will get the new NavigationState. Similarly, if we did not
// initiate this navigation, then we need to take care to reset any pre-
// existing navigation state to a content-initiated navigation state.
- // DidCreateDataSource conveniently takes care of this for us.
+ // didCreateDataSource conveniently takes care of this for us.
didCreateDataSource(frame, frame->dataSource());
DocumentState* document_state =
DocumentState::FromDataSource(frame->dataSource());
- NavigationState* new_state = document_state->navigation_state();
- new_state->set_was_within_same_page(true);
+ static_cast<NavigationStateImpl*>(document_state->navigation_state())
+ ->set_was_within_same_page(true);
didCommitProvisionalLoad(frame, item, commit_type);
}
@@ -2559,37 +2953,18 @@ void RenderFrameImpl::didUpdateCurrentHistoryItem(blink::WebLocalFrame* frame) {
render_view_->didUpdateCurrentHistoryItem(frame);
}
-// TODO(zhenw): This will be removed once the blink side implementation is done.
-void RenderFrameImpl::addNavigationTransitionData(
- const blink::WebString& allowed_destination_host_pattern,
- const blink::WebString& selector,
- const blink::WebString& markup) {
- FrameHostMsg_AddNavigationTransitionData_Params params;
- params.render_frame_id = routing_id_;
- params.allowed_destination_host_pattern =
- allowed_destination_host_pattern.utf8();
- params.selector = selector.utf8();
- params.markup = markup.utf8();
-
- Send(new FrameHostMsg_AddNavigationTransitionData(params));
-}
-
void RenderFrameImpl::addNavigationTransitionData(
- const blink::WebString& allowed_destination_host_pattern,
- const blink::WebString& selector,
- const blink::WebString& markup,
- const blink::WebVector<blink::WebString>& web_names,
- const blink::WebVector<blink::WebRect>& web_rects) {
+ const blink::WebTransitionElementData& data) {
FrameHostMsg_AddNavigationTransitionData_Params params;
params.render_frame_id = routing_id_;
params.allowed_destination_host_pattern =
- allowed_destination_host_pattern.utf8();
- params.selector = selector.utf8();
- params.markup = markup.utf8();
- params.elements.resize(web_names.size());
- for (size_t i = 0; i < web_names.size(); i++) {
- params.elements[i].name = web_names[i].utf8();
- params.elements[i].rect = gfx::Rect(web_rects[i]);
+ data.scope.utf8();
+ params.selector = data.selector.utf8();
+ params.markup = data.markup.utf8();
+ params.elements.resize(data.elements.size());
+ for (size_t i = 0; i < data.elements.size(); i++) {
+ params.elements[i].id = data.elements[i].id.utf8();
+ params.elements[i].rect = gfx::Rect(data.elements[i].rect);
}
Send(new FrameHostMsg_AddNavigationTransitionData(params));
@@ -2603,6 +2978,10 @@ void RenderFrameImpl::didChangeThemeColor() {
routing_id_, frame_->document().themeColor()));
}
+void RenderFrameImpl::dispatchLoad() {
+ Send(new FrameHostMsg_DispatchLoad(routing_id_));
+}
+
void RenderFrameImpl::requestNotificationPermission(
const blink::WebSecurityOrigin& origin,
blink::WebNotificationPermissionCallback* callback) {
@@ -2614,10 +2993,6 @@ void RenderFrameImpl::requestNotificationPermission(
notification_permission_dispatcher_->RequestPermission(origin, callback);
}
-blink::WebNotificationPresenter* RenderFrameImpl::notificationPresenter() {
- return notification_provider_;
-}
-
void RenderFrameImpl::didChangeSelection(bool is_empty_selection) {
if (!GetRenderWidget()->handling_input_event() && !handling_select_range_)
return;
@@ -2689,7 +3064,7 @@ bool RenderFrameImpl::runModalBeforeUnloadDialog(
// If we are swapping out, we have already run the beforeunload handler.
// TODO(creis): Fix OnSwapOut to clear the frame without running beforeunload
// at all, to avoid running it twice.
- if (render_view()->is_swapped_out_)
+ if (is_swapped_out_)
return true;
// Don't allow further dialogs if we are waiting to swap out, since the
@@ -2778,13 +3153,18 @@ void RenderFrameImpl::willSendRequest(
WebDataSource* data_source =
provisional_data_source ? provisional_data_source : top_data_source;
- ui::PageTransition transition_type = ui::PAGE_TRANSITION_LINK;
DocumentState* document_state = DocumentState::FromDataSource(data_source);
DCHECK(document_state);
InternalDocumentStateData* internal_data =
InternalDocumentStateData::FromDocumentState(document_state);
- NavigationState* navigation_state = document_state->navigation_state();
- transition_type = navigation_state->transition_type();
+ NavigationStateImpl* navigation_state =
+ static_cast<NavigationStateImpl*>(document_state->navigation_state());
+ ui::PageTransition transition_type = navigation_state->GetTransitionType();
+ WebDataSource* frame_ds = frame->provisionalDataSource();
+ if (frame_ds && frame_ds->isClientRedirect()) {
+ transition_type = ui::PageTransitionFromInt(
+ transition_type | ui::PAGE_TRANSITION_CLIENT_REDIRECT);
+ }
GURL request_url(request.url());
GURL new_url;
@@ -2848,7 +3228,7 @@ void RenderFrameImpl::willSendRequest(
// this navigation later require a request transfer, all state is preserved
// when it is re-created in the new process.
bool should_replace_current_entry = false;
- if (navigation_state->is_content_initiated()) {
+ if (navigation_state->IsContentInitiated()) {
should_replace_current_entry = data_source->replacesCurrentHistoryItem();
} else {
// If the navigation is browser-initiated, the NavigationState contains the
@@ -2857,7 +3237,7 @@ void RenderFrameImpl::willSendRequest(
// TODO(davidben): Avoid this awkward duplication of state. See comment on
// NavigationState::should_replace_current_entry().
should_replace_current_entry =
- navigation_state->should_replace_current_entry();
+ navigation_state->start_params().should_replace_current_entry;
}
int provider_id = kInvalidServiceWorkerProviderId;
@@ -2893,18 +3273,19 @@ void RenderFrameImpl::willSendRequest(
extra_data->set_custom_user_agent(custom_user_agent);
extra_data->set_requested_with(requested_with);
extra_data->set_render_frame_id(routing_id_);
- extra_data->set_is_main_frame(frame == top_frame);
+ extra_data->set_is_main_frame(!parent);
extra_data->set_frame_origin(
GURL(frame->document().securityOrigin().toString()));
- extra_data->set_parent_is_main_frame(frame->parent() == top_frame);
+ extra_data->set_parent_is_main_frame(parent && !parent->parent());
extra_data->set_parent_render_frame_id(parent_routing_id);
- extra_data->set_allow_download(navigation_state->allow_download());
+ extra_data->set_allow_download(
+ navigation_state->common_params().allow_download);
extra_data->set_transition_type(transition_type);
extra_data->set_should_replace_current_entry(should_replace_current_entry);
extra_data->set_transferred_request_child_id(
- navigation_state->transferred_request_child_id());
+ navigation_state->start_params().transferred_request_child_id);
extra_data->set_transferred_request_request_id(
- navigation_state->transferred_request_request_id());
+ navigation_state->start_params().transferred_request_request_id);
extra_data->set_service_worker_provider_id(provider_id);
extra_data->set_stream_override(stream_override.Pass());
request.setExtraData(extra_data);
@@ -2925,11 +3306,11 @@ void RenderFrameImpl::willSendRequest(
request.setRequestorID(render_view_->GetRoutingID());
request.setHasUserGesture(WebUserGestureIndicator::isProcessingUserGesture());
- if (!navigation_state->extra_headers().empty()) {
+ if (!navigation_state->start_params().extra_headers.empty()) {
for (net::HttpUtil::HeadersIterator i(
- navigation_state->extra_headers().begin(),
- navigation_state->extra_headers().end(), "\n");
- i.GetNext(); ) {
+ navigation_state->start_params().extra_headers.begin(),
+ navigation_state->start_params().extra_headers.end(), "\n");
+ i.GetNext();) {
if (LowerCaseEqualsASCII(i.name(), "referer")) {
WebString referrer = WebSecurityPolicy::generateReferrerHeader(
blink::WebReferrerPolicyDefault,
@@ -3004,7 +3385,13 @@ void RenderFrameImpl::didFinishResourceLoad(blink::WebLocalFrame* frame,
return;
// Do not show error page when DevTools is attached.
- if (render_view_->devtools_agent_->IsAttached())
+ RenderFrameImpl* localRoot = this;
+ while (localRoot->frame_ && localRoot->frame_->parent() &&
+ localRoot->frame_->parent()->isWebLocalFrame()) {
+ localRoot = RenderFrameImpl::FromWebFrame(localRoot->frame_->parent());
+ DCHECK(localRoot);
+ }
+ if (localRoot->devtools_agent_ && localRoot->devtools_agent_->IsAttached())
return;
// Display error page, if appropriate.
@@ -3072,16 +3459,17 @@ void RenderFrameImpl::didAbortLoading(blink::WebLocalFrame* frame) {
}
void RenderFrameImpl::didCreateScriptContext(blink::WebLocalFrame* frame,
- v8::Handle<v8::Context> context,
+ v8::Local<v8::Context> context,
int extension_group,
int world_id) {
DCHECK(!frame_ || frame_ == frame);
- GetContentClient()->renderer()->DidCreateScriptContext(
- frame, context, extension_group, world_id);
+
+ FOR_EACH_OBSERVER(RenderFrameObserver, observers_,
+ DidCreateScriptContext(context, extension_group, world_id));
}
void RenderFrameImpl::willReleaseScriptContext(blink::WebLocalFrame* frame,
- v8::Handle<v8::Context> context,
+ v8::Local<v8::Context> context,
int world_id) {
DCHECK(!frame_ || frame_ == frame);
@@ -3115,6 +3503,8 @@ void RenderFrameImpl::didChangeScrollOffset(blink::WebLocalFrame* frame) {
// TODO(nasko): Move implementation here. Needed methods:
// * StartNavStateSyncTimerIfNecessary
render_view_->didChangeScrollOffset(frame);
+
+ FOR_EACH_OBSERVER(RenderFrameObserver, observers_, DidChangeScrollOffset());
}
void RenderFrameImpl::willInsertBody(blink::WebLocalFrame* frame) {
@@ -3158,7 +3548,7 @@ void RenderFrameImpl::requestStorageQuota(
callbacks.didFail(blink::WebStorageQuotaErrorAbort);
return;
}
- ChildThread::current()->quota_dispatcher()->RequestStorageQuota(
+ ChildThreadImpl::current()->quota_dispatcher()->RequestStorageQuota(
render_view_->GetRoutingID(),
GURL(origin.toString()),
static_cast<storage::StorageType>(type),
@@ -3177,10 +3567,10 @@ blink::WebGeolocationClient* RenderFrameImpl::geolocationClient() {
return geolocation_dispatcher_;
}
-void RenderFrameImpl::requestPushPermission(blink::WebCallback* callback) {
- if (!push_permission_dispatcher_)
- push_permission_dispatcher_ = new PushPermissionDispatcher(this);
- push_permission_dispatcher_->RequestPermission(callback);
+blink::WebPresentationClient* RenderFrameImpl::presentationClient() {
+ if (!presentation_dispatcher_)
+ presentation_dispatcher_ = new PresentationDispatcher(this);
+ return presentation_dispatcher_;
}
blink::WebPushClient* RenderFrameImpl::pushClient() {
@@ -3204,6 +3594,19 @@ blink::WebUserMediaClient* RenderFrameImpl::userMediaClient() {
return web_user_media_client_;
}
+blink::WebEncryptedMediaClient* RenderFrameImpl::encryptedMediaClient() {
+ if (!web_encrypted_media_client_) {
+ web_encrypted_media_client_.reset(new media::WebEncryptedMediaClientImpl(
+ // base::Unretained(this) is safe because WebEncryptedMediaClientImpl
+ // is destructed before |this|, and does not give away ownership of the
+ // callback.
+ base::Bind(&RenderFrameImpl::AreSecureCodecsSupported,
+ base::Unretained(this)),
+ GetCdmFactory(), GetMediaPermission()));
+ }
+ return web_encrypted_media_client_.get();
+}
+
blink::WebMIDIClient* RenderFrameImpl::webMIDIClient() {
if (!midi_dispatcher_)
midi_dispatcher_ = new MidiDispatcher(this);
@@ -3217,42 +3620,34 @@ bool RenderFrameImpl::willCheckAndDispatchMessageEvent(
blink::WebDOMMessageEvent event) {
DCHECK(!frame_ || frame_ == target_frame);
- if (!render_view_->is_swapped_out_)
+ // Currently, a postMessage that targets a cross-process frame can be plumbed
+ // either through this function or RenderFrameProxy::postMessageEvent. This
+ // function is used when the target cross-process frame is a top-level frame
+ // which has been swapped out. In that case, the corresponding WebLocalFrame
+ // currently remains in the frame tree even in site-per-process mode (see
+ // OnSwapOut). RenderFrameProxy::postMessageEvent is used in
+ // --site-per-process mode for all other cases.
+ //
+ // TODO(alexmos, nasko): When swapped-out:// disappears, this should be
+ // cleaned up so that RenderFrameProxy::postMessageEvent is the only path for
+ // cross-process postMessages.
+ if (!is_swapped_out_)
return false;
- ViewMsg_PostMessage_Params params;
- params.is_data_raw_string = false;
- params.data = event.data().toString();
- params.source_origin = event.origin();
- if (!target_origin.isNull())
- params.target_origin = target_origin.toString();
-
- blink::WebMessagePortChannelArray channels = event.releaseChannels();
- if (!channels.isEmpty()) {
- std::vector<int> message_port_ids(channels.size());
- // Extract the port IDs from the channel array.
- for (size_t i = 0; i < channels.size(); ++i) {
- WebMessagePortChannelImpl* webchannel =
- static_cast<WebMessagePortChannelImpl*>(channels[i]);
- message_port_ids[i] = webchannel->message_port_id();
- webchannel->QueueMessages();
- DCHECK_NE(message_port_ids[i], MSG_ROUTING_NONE);
- }
- params.message_port_ids = message_port_ids;
- }
-
- // Include the routing ID for the source frame (if one exists), which the
- // browser process will translate into the routing ID for the equivalent
- // frame in the target process.
- params.source_routing_id = MSG_ROUTING_NONE;
- if (source_frame) {
- RenderViewImpl* source_view =
- RenderViewImpl::FromWebView(source_frame->view());
- if (source_view)
- params.source_routing_id = source_view->routing_id();
- }
+ // It is possible to get here on a swapped-out frame without a
+ // |render_frame_proxy_|. This happens when:
+ // - This process only has one active RenderView and is about to go away
+ // (e.g., due to cross-process navigation).
+ // - The top frame has a subframe with an unload handler.
+ // - The subframe sends a postMessage to the top-level frame in its unload
+ // handler.
+ // See https://crbug.com/475651 for details. We return false here, since we
+ // don't want to deliver the message to the new process in this case.
+ if (!render_frame_proxy_)
+ return false;
- Send(new ViewHostMsg_RouteMessageEvent(render_view_->routing_id_, params));
+ render_frame_proxy_->postMessageEvent(
+ source_frame, render_frame_proxy_->web_frame(), target_origin, event);
return true;
}
@@ -3367,13 +3762,46 @@ void RenderFrameImpl::handleAccessibilityFindInPageResult(
}
}
-void RenderFrameImpl::didChangeManifest(blink::WebLocalFrame* frame)
-{
+void RenderFrameImpl::didChangeManifest(blink::WebLocalFrame* frame) {
DCHECK(!frame_ || frame_ == frame);
FOR_EACH_OBSERVER(RenderFrameObserver, observers_, DidChangeManifest());
}
+void RenderFrameImpl::didChangeDefaultPresentation(
+ blink::WebLocalFrame* frame) {
+ DCHECK(!frame_ || frame_ == frame);
+
+ FOR_EACH_OBSERVER(
+ RenderFrameObserver, observers_, DidChangeDefaultPresentation());
+}
+
+bool RenderFrameImpl::enterFullscreen() {
+ Send(new FrameHostMsg_ToggleFullscreen(routing_id_, true));
+ return true;
+}
+
+bool RenderFrameImpl::exitFullscreen() {
+ Send(new FrameHostMsg_ToggleFullscreen(routing_id_, false));
+ return true;
+}
+
+blink::WebPermissionClient* RenderFrameImpl::permissionClient() {
+ if (!permission_client_)
+ permission_client_.reset(new PermissionDispatcher(GetServiceRegistry()));
+
+ return permission_client_.get();
+}
+
+blink::WebAppBannerClient* RenderFrameImpl::appBannerClient() {
+ if (!app_banner_client_) {
+ app_banner_client_ =
+ GetContentClient()->renderer()->CreateAppBannerClient(this);
+ }
+
+ return app_banner_client_.get();
+}
+
void RenderFrameImpl::DidPlay(blink::WebMediaPlayer* player) {
Send(new FrameHostMsg_MediaPlayingNotification(
routing_id_, reinterpret_cast<int64>(player), player->hasVideo(),
@@ -3412,15 +3840,28 @@ void RenderFrameImpl::WasHidden() {
}
void RenderFrameImpl::WasShown() {
+ // TODO(kenrb): Need to figure out how to do this better. Should
+ // VisibilityState remain a page-level concept or move to frames?
+ // The semantics of 'Show' might have to change here.
+ if (render_widget_) {
+ static_cast<blink::WebFrameWidget*>(render_widget_->webwidget())->
+ setVisibilityState(blink::WebPageVisibilityStateVisible, false);
+ }
FOR_EACH_OBSERVER(RenderFrameObserver, observers_, WasShown());
}
+void RenderFrameImpl::WidgetWillClose() {
+ FOR_EACH_OBSERVER(RenderFrameObserver, observers_, WidgetWillClose());
+}
+
bool RenderFrameImpl::IsHidden() {
return GetRenderWidget()->is_hidden();
}
// Tell the embedding application that the URL of the active page has changed.
-void RenderFrameImpl::SendDidCommitProvisionalLoad(blink::WebFrame* frame) {
+void RenderFrameImpl::SendDidCommitProvisionalLoad(
+ blink::WebFrame* frame,
+ blink::WebHistoryCommitType commit_type) {
DCHECK(!frame_ || frame_ == frame);
WebDataSource* ds = frame->dataSource();
DCHECK(ds);
@@ -3429,7 +3870,8 @@ void RenderFrameImpl::SendDidCommitProvisionalLoad(blink::WebFrame* frame) {
const WebURLResponse& response = ds->response();
DocumentState* document_state = DocumentState::FromDataSource(ds);
- NavigationState* navigation_state = document_state->navigation_state();
+ NavigationStateImpl* navigation_state =
+ static_cast<NavigationStateImpl*>(document_state->navigation_state());
InternalDocumentStateData* internal_data =
InternalDocumentStateData::FromDocumentState(document_state);
@@ -3437,8 +3879,12 @@ void RenderFrameImpl::SendDidCommitProvisionalLoad(blink::WebFrame* frame) {
params.http_status_code = response.httpStatusCode();
params.url_is_unreachable = ds->hasUnreachableURL();
params.is_post = false;
+ params.intended_as_new_entry =
+ navigation_state->request_params().intended_as_new_entry;
+ params.did_create_new_entry = commit_type == blink::WebStandardCommit;
params.post_id = -1;
params.page_id = render_view_->page_id_;
+ params.nav_entry_id = navigation_state->request_params().nav_entry_id;
// We need to track the RenderViewHost routing_id because of downstream
// dependencies (crbug.com/392171 DownloadRequestHandle, SaveFileManager,
// ResourceDispatcherHostImpl, MediaStreamUIProxy,
@@ -3452,13 +3898,23 @@ void RenderFrameImpl::SendDidCommitProvisionalLoad(blink::WebFrame* frame) {
WebURLResponseExtraDataImpl* extra_data = GetExtraDataFromResponse(response);
if (extra_data)
params.was_fetched_via_proxy = extra_data->was_fetched_via_proxy();
- params.was_within_same_page = navigation_state->was_within_same_page();
+ params.was_within_same_page = navigation_state->WasWithinSamePage();
params.security_info = response.securityInfo();
// Set the URL to be displayed in the browser UI to the user.
params.url = GetLoadingUrl();
DCHECK(!is_swapped_out_ || params.url == GURL(kSwappedOutURL));
+ // Set the origin of the frame. This will be replicated to the corresponding
+ // RenderFrameProxies in other processes.
+ // TODO(alexmos): Origins for URLs with non-standard schemes are excluded due
+ // to https://crbug.com/439608 and will be replicated as unique origins.
+ if (!is_swapped_out_) {
+ WebString serialized_origin(frame->document().securityOrigin().toString());
+ if (GURL(serialized_origin).IsStandard())
+ params.origin = url::Origin(serialized_origin.utf8());
+ }
+
if (frame->document().baseURL() != params.url)
params.base_url = frame->document().baseURL();
@@ -3473,7 +3929,7 @@ void RenderFrameImpl::SendDidCommitProvisionalLoad(blink::WebFrame* frame) {
render_view_->navigation_gesture_ = NavigationGestureUnknown;
// Make navigation state a part of the DidCommitProvisionalLoad message so
- // that commited entry has it at all times.
+ // that committed entry has it at all times.
HistoryEntry* entry = render_view_->history_controller()->GetCurrentEntry();
if (entry)
params.page_state = HistoryEntryToPageState(entry);
@@ -3514,7 +3970,7 @@ void RenderFrameImpl::SendDidCommitProvisionalLoad(blink::WebFrame* frame) {
// Update contents MIME type for main frame.
params.contents_mime_type = ds->response().mimeType().utf8();
- params.transition = navigation_state->transition_type();
+ params.transition = navigation_state->GetTransitionType();
if (!ui::PageTransitionIsMainFrame(params.transition)) {
// If the main frame does a load, it should not be reported as a subframe
// navigation. This can occur in the following case:
@@ -3545,7 +4001,7 @@ void RenderFrameImpl::SendDidCommitProvisionalLoad(blink::WebFrame* frame) {
base::string16 method = request.httpMethod();
if (EqualsASCII(method, "POST")) {
params.is_post = true;
- params.post_id = ExtractPostId(entry->root());
+ params.post_id = ExtractPostId(entry);
}
// Send the user agent override back.
@@ -3557,7 +4013,12 @@ void RenderFrameImpl::SendDidCommitProvisionalLoad(blink::WebFrame* frame) {
params.original_request_url = GetOriginalRequestURL(ds);
params.history_list_was_cleared =
- navigation_state->history_list_was_cleared();
+ navigation_state->request_params().should_clear_history_list;
+
+ params.report_type = static_cast<FrameMsg_UILoadMetricsReportType::Value>(
+ frame->dataSource()->request().inputPerfMetricReportPolicy());
+ params.ui_timestamp = base::TimeTicks() + base::TimeDelta::FromSecondsD(
+ frame->dataSource()->request().uiStartTime());
// Save some histogram data so we can compute the average memory used per
// page load of the glyphs.
@@ -3573,39 +4034,26 @@ void RenderFrameImpl::SendDidCommitProvisionalLoad(blink::WebFrame* frame) {
// Subframe navigation: the type depends on whether this navigation
// generated a new session history entry. When they do generate a session
// history entry, it means the user initiated the navigation and we should
- // mark it as such. This test checks if this is the first time
- // SendDidCommitProvisionalLoad has been called since WillNavigateToURL was
- // called to initiate the load.
- if (render_view_->page_id_ > render_view_->last_page_id_sent_to_browser_)
+ // mark it as such.
+ if (commit_type == blink::WebStandardCommit)
params.transition = ui::PAGE_TRANSITION_MANUAL_SUBFRAME;
else
params.transition = ui::PAGE_TRANSITION_AUTO_SUBFRAME;
- DCHECK(!navigation_state->history_list_was_cleared());
+ DCHECK(!navigation_state->request_params().should_clear_history_list);
params.history_list_was_cleared = false;
+ params.report_type = FrameMsg_UILoadMetricsReportType::NO_REPORT;
// Don't send this message while the subframe is swapped out.
if (!is_swapped_out())
Send(new FrameHostMsg_DidCommitProvisionalLoad(routing_id_, params));
}
- render_view_->last_page_id_sent_to_browser_ =
- std::max(render_view_->last_page_id_sent_to_browser_,
- render_view_->page_id_);
-
// If we end up reusing this WebRequest (for example, due to a #ref click),
// we don't want the transition type to persist. Just clear it.
navigation_state->set_transition_type(ui::PAGE_TRANSITION_LINK);
}
-WebElement RenderFrameImpl::GetFocusedElement() {
- WebDocument doc = frame_->document();
- if (!doc.isNull())
- return doc.focusedElement();
-
- return WebElement();
-}
-
void RenderFrameImpl::didStartLoading(bool to_different_document) {
TRACE_EVENT1("navigation", "RenderFrameImpl::didStartLoading",
"id", routing_id_);
@@ -3631,42 +4079,12 @@ void RenderFrameImpl::HandleWebAccessibilityEvent(
}
void RenderFrameImpl::FocusedNodeChanged(const WebNode& node) {
- if (renderer_accessibility_)
- renderer_accessibility_->FocusedNodeChanged(node);
+ FOR_EACH_OBSERVER(RenderFrameObserver, observers_, FocusedNodeChanged(node));
}
-// PlzNavigate
-void RenderFrameImpl::OnRequestNavigation(
- const CommonNavigationParams& common_params,
- const RequestNavigationParams& request_params) {
- CHECK(CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableBrowserSideNavigation));
-
- // TODO(clamy): Execute the beforeunload event.
-
- WebURLRequest request =
- CreateURLRequestForNavigation(common_params,
- request_params,
- scoped_ptr<StreamOverrideParameters>(),
- frame_->isViewSourceModeEnabled());
-
- // Note: At this stage, the goal is to apply all the modifications the
- // renderer wants to make to the request, and then send it to the browser, so
- // that the actual network request can be started. Ideally, all such
- // modifications should take place in willSendRequest, and in the
- // implementation of willSendRequest for the various InspectorAgents
- // (devtools).
- //
- // TODO(clamy): Apply devtools override.
- // TODO(clamy): Make sure that navigation requests are not modified somewhere
- // else in blink.
- willSendRequest(frame_, 0, request, blink::WebURLResponse());
-
- // TODO(clamy): Same-document navigations should not be sent back to the
- // browser.
- Send(new FrameHostMsg_BeginNavigation(routing_id_,
- MakeBeginNavigationParams(request),
- MakeCommonNavigationParams(request)));
+void RenderFrameImpl::FocusedNodeChangedForAccessibility(const WebNode& node) {
+ if (renderer_accessibility())
+ renderer_accessibility()->AccessibilityFocusedNodeChanged(node);
}
// PlzNavigate
@@ -3674,42 +4092,71 @@ void RenderFrameImpl::OnCommitNavigation(
const ResourceResponseHead& response,
const GURL& stream_url,
const CommonNavigationParams& common_params,
- const CommitNavigationParams& commit_params) {
- CHECK(CommandLine::ForCurrentProcess()->HasSwitch(
+ const RequestNavigationParams& request_params) {
+ CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableBrowserSideNavigation));
- bool is_reload = false;
+ // This will override the url requested by the WebURLLoader, as well as
+ // provide it with the response to the request.
+ scoped_ptr<StreamOverrideParameters> stream_override(
+ new StreamOverrideParameters());
+ stream_override->stream_url = stream_url;
+ stream_override->response = response;
+
+ NavigateInternal(common_params, StartNavigationParams(), request_params,
+ stream_override.Pass());
+}
+
+void RenderFrameImpl::OnFailedNavigation(
+ const CommonNavigationParams& common_params,
+ const RequestNavigationParams& request_params,
+ bool has_stale_copy_in_cache,
+ int error_code) {
+ bool is_reload = IsReload(common_params.navigation_type);
+ bool is_history_navigation = request_params.page_state.IsValid();
WebURLRequest::CachePolicy cache_policy =
WebURLRequest::UseProtocolCachePolicy;
if (!RenderFrameImpl::PrepareRenderViewForNavigation(
- common_params.url, common_params.navigation_type,
- commit_params.page_state, false, -1, -1, &is_reload, &cache_policy)) {
+ common_params.url, is_history_navigation, request_params, &is_reload,
+ &cache_policy)) {
+ Send(new FrameHostMsg_DidDropNavigation(routing_id_));
return;
}
GetContentClient()->SetActiveURL(common_params.url);
- // Create a WebURLRequest that blink can use to get access to the body of the
- // response through a stream in the browser. Blink will then commit the
- // navigation.
- // TODO(clamy): Have the navigation commit directly, without going through
- // loading a WebURLRequest.
- scoped_ptr<StreamOverrideParameters> stream_override(
- new StreamOverrideParameters());
- stream_override->stream_url = stream_url;
- stream_override->response = response;
- WebURLRequest request =
- CreateURLRequestForNavigation(common_params,
- RequestNavigationParams(),
- stream_override.Pass(),
- frame_->isViewSourceModeEnabled());
-
- // Record this before starting the load. A lower bound of this time is needed
- // to sanitize the navigationStart override set below.
- base::TimeTicks renderer_navigation_start = base::TimeTicks::Now();
- frame_->loadRequest(request);
- UpdateFrameNavigationTiming(
- frame_, commit_params.browser_navigation_start,
- renderer_navigation_start);
+ pending_navigation_params_.reset(new NavigationParams(
+ common_params, StartNavigationParams(), request_params));
+
+ // Inform the browser of the start of the provisional load. This is needed so
+ // that the load is properly tracked by the WebNavigation API.
+ // TODO(clamy): Properly set is_transition_navigation.
+ Send(new FrameHostMsg_DidStartProvisionalLoadForFrame(
+ routing_id_, common_params.url, false));
+
+ // Send the provisional load failure.
+ blink::WebURLError error =
+ CreateWebURLError(common_params.url, has_stale_copy_in_cache, error_code);
+ WebURLRequest failed_request = CreateURLRequestForNavigation(
+ common_params, scoped_ptr<StreamOverrideParameters>(),
+ frame_->isViewSourceModeEnabled());
+ SendFailedProvisionalLoad(failed_request, error, frame_);
+
+ if (!ShouldDisplayErrorPageForFailedLoad(error_code, common_params.url)) {
+ Send(new FrameHostMsg_DidDropNavigation(routing_id_));
+ return;
+ }
+
+ // Make sure errors are not shown in view source mode.
+ frame_->enableViewSourceMode(false);
+
+ // Replace the current history entry in reloads, history navigations and loads
+ // of the same url. This corresponds to Blink's notion of a standard
+ // commit.
+ // TODO(clamy): see if initial commits in subframes should be handled
+ // separately.
+ bool replace = is_reload || is_history_navigation ||
+ common_params.url == GetLoadingUrl();
+ LoadNavigationErrorPage(failed_request, error, replace);
}
WebNavigationPolicy RenderFrameImpl::DecidePolicyForNavigation(
@@ -3734,15 +4181,14 @@ WebNavigationPolicy RenderFrameImpl::DecidePolicyForNavigation(
Referrer referrer(RenderViewImpl::GetReferrerFromRequest(info.frame,
info.urlRequest));
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
- bool is_subframe = !!info.frame->parent();
-
- if (command_line.HasSwitch(switches::kSitePerProcess) && is_subframe) {
+ if (command_line.HasSwitch(switches::kSitePerProcess) && is_subframe_) {
// There's no reason to ignore navigations on subframes, since the swap out
// logic no longer applies.
} else {
- if (is_swapped_out_ || render_view_->is_swapped_out()) {
+ if (is_swapped_out_) {
if (info.urlRequest.url() != GURL(kSwappedOutURL)) {
// Targeted links may try to navigate a swapped out frame. Allow the
// browser process to navigate the tab instead. Note that it is also
@@ -3774,8 +4220,9 @@ WebNavigationPolicy RenderFrameImpl::DecidePolicyForNavigation(
// A content initiated navigation may have originated from a link-click,
// script, drag-n-drop operation, etc.
- bool is_content_initiated = static_cast<DocumentState*>(info.extraData)->
- navigation_state()->is_content_initiated();
+ DocumentState* document_state = static_cast<DocumentState*>(info.extraData);
+ bool is_content_initiated =
+ document_state->navigation_state()->IsContentInitiated();
// Experimental:
// If --enable-strict-site-isolation is enabled, send all top-level
@@ -3861,7 +4308,7 @@ WebNavigationPolicy RenderFrameImpl::DecidePolicyForNavigation(
// handled by the browser so that ordinary renderer processes don't get
// blessed with file permissions.
int cumulative_bindings = RenderProcess::current()->GetEnabledBindings();
- bool is_initial_navigation = render_view_->page_id_ == -1;
+ bool is_initial_navigation = render_view_->history_list_length_ == 0;
bool should_fork = HasWebUIScheme(url) || HasWebUIScheme(old_url) ||
(cumulative_bindings & BINDINGS_POLICY_WEB_UI) ||
url.SchemeIs(kViewSourceScheme) ||
@@ -3931,6 +4378,14 @@ WebNavigationPolicy RenderFrameImpl::DecidePolicyForNavigation(
return blink::WebNavigationPolicyIgnore;
}
+ // PlzNavigate: send the request to the browser if needed.
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation) &&
+ info.urlRequest.checkForBrowserSideNavigation()) {
+ BeginNavigation(&info.urlRequest);
+ return blink::WebNavigationPolicyIgnore;
+ }
+
return info.defaultPolicy;
}
@@ -3947,9 +4402,12 @@ void RenderFrameImpl::OpenURL(WebFrame* frame,
WebDataSource* ds = frame->provisionalDataSource();
if (ds) {
DocumentState* document_state = DocumentState::FromDataSource(ds);
- NavigationState* navigation_state = document_state->navigation_state();
- if (navigation_state->is_content_initiated()) {
- params.should_replace_current_entry = ds->replacesCurrentHistoryItem();
+ NavigationStateImpl* navigation_state =
+ static_cast<NavigationStateImpl*>(document_state->navigation_state());
+ if (navigation_state->IsContentInitiated()) {
+ params.should_replace_current_entry =
+ ds->replacesCurrentHistoryItem() &&
+ render_view_->history_list_length_;
} else {
// This is necessary to preserve the should_replace_current_entry value on
// cross-process redirects, in the event it was set by a previous process.
@@ -3957,7 +4415,7 @@ void RenderFrameImpl::OpenURL(WebFrame* frame,
// TODO(davidben): Avoid this awkward duplication of state. See comment on
// NavigationState::should_replace_current_entry().
params.should_replace_current_entry =
- navigation_state->should_replace_current_entry();
+ navigation_state->start_params().should_replace_current_entry;
}
} else {
params.should_replace_current_entry = false;
@@ -3976,6 +4434,131 @@ void RenderFrameImpl::OpenURL(WebFrame* frame,
Send(new FrameHostMsg_OpenURL(routing_id_, params));
}
+void RenderFrameImpl::NavigateInternal(
+ const CommonNavigationParams& common_params,
+ const StartNavigationParams& start_params,
+ const RequestNavigationParams& request_params,
+ scoped_ptr<StreamOverrideParameters> stream_params) {
+ bool browser_side_navigation =
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation);
+ bool is_reload = IsReload(common_params.navigation_type);
+ bool is_history_navigation = request_params.page_state.IsValid();
+ WebURLRequest::CachePolicy cache_policy =
+ WebURLRequest::UseProtocolCachePolicy;
+ if (!RenderFrameImpl::PrepareRenderViewForNavigation(
+ common_params.url, is_history_navigation, request_params, &is_reload,
+ &cache_policy)) {
+ Send(new FrameHostMsg_DidDropNavigation(routing_id_));
+ return;
+ }
+
+ GetContentClient()->SetActiveURL(common_params.url);
+
+ if (is_reload && !render_view_->history_controller()->GetCurrentEntry()) {
+ // We cannot reload if we do not have any history state. This happens, for
+ // example, when recovering from a crash.
+ is_reload = false;
+ cache_policy = WebURLRequest::ReloadIgnoringCacheData;
+ }
+
+ pending_navigation_params_.reset(
+ new NavigationParams(common_params, start_params, request_params));
+
+ // If we are reloading, then Blink will use the history state of the current
+ // page, so we should just ignore any given history state. Otherwise, if we
+ // have history state, then we need to navigate to it, which corresponds to a
+ // back/forward navigation event.
+ if (is_reload && !browser_side_navigation) {
+ // TODO(clamy): adapt this code for PlzNavigate. In particular the stream
+ // override should be given to the generated request.
+ bool reload_original_url =
+ (common_params.navigation_type ==
+ FrameMsg_Navigate_Type::RELOAD_ORIGINAL_REQUEST_URL);
+ bool ignore_cache = (common_params.navigation_type ==
+ FrameMsg_Navigate_Type::RELOAD_IGNORING_CACHE);
+
+ if (reload_original_url)
+ frame_->reloadWithOverrideURL(common_params.url, true);
+ else
+ frame_->reload(ignore_cache);
+ } else if (is_history_navigation && !browser_side_navigation) {
+ // TODO(clamy): adapt this code for PlzNavigate. In particular the stream
+ // override should be given to the generated request.
+
+ // We must know the page ID of the page we are navigating back to.
+ DCHECK_NE(request_params.page_id, -1);
+ // We must know the nav entry ID of the page we are navigating back to,
+ // which should be the case because history navigations are routed via the
+ // browser.
+ DCHECK_NE(0, request_params.nav_entry_id);
+ scoped_ptr<HistoryEntry> entry =
+ PageStateToHistoryEntry(request_params.page_state);
+ if (entry) {
+ // Ensure we didn't save the swapped out URL in UpdateState, since the
+ // browser should never be telling us to navigate to swappedout://.
+ CHECK(entry->root().urlString() != WebString::fromUTF8(kSwappedOutURL));
+ scoped_ptr<NavigationParams> navigation_params(
+ new NavigationParams(*pending_navigation_params_.get()));
+ render_view_->history_controller()->GoToEntry(
+ entry.Pass(), navigation_params.Pass(), cache_policy);
+ }
+ } else if (!common_params.base_url_for_data_url.is_empty() ||
+ (browser_side_navigation &&
+ common_params.url.SchemeIs(url::kDataScheme))) {
+ LoadDataURL(common_params, frame_);
+ } else {
+ // Navigate to the given URL.
+ WebURLRequest request = CreateURLRequestForNavigation(
+ common_params, stream_params.Pass(), frame_->isViewSourceModeEnabled());
+
+ if (!start_params.extra_headers.empty() && !browser_side_navigation) {
+ for (net::HttpUtil::HeadersIterator i(start_params.extra_headers.begin(),
+ start_params.extra_headers.end(),
+ "\n");
+ i.GetNext();) {
+ request.addHTTPHeaderField(WebString::fromUTF8(i.name()),
+ WebString::fromUTF8(i.values()));
+ }
+ }
+
+ if (start_params.is_post && !browser_side_navigation) {
+ request.setHTTPMethod(WebString::fromUTF8("POST"));
+
+ // Set post data.
+ WebHTTPBody http_body;
+ http_body.initialize();
+ const char* data = nullptr;
+ if (start_params.browser_initiated_post_data.size()) {
+ data = reinterpret_cast<const char*>(
+ &start_params.browser_initiated_post_data.front());
+ }
+ http_body.appendData(
+ WebData(data, start_params.browser_initiated_post_data.size()));
+ request.setHTTPBody(http_body);
+ }
+
+ // A session history navigation should have been accompanied by state.
+ CHECK_EQ(request_params.page_id, -1);
+
+ // PlzNavigate: Make sure that Blink's loader will not try to use browser
+ // side navigation for this request (since it already went to the browser).
+ if (browser_side_navigation)
+ request.setCheckForBrowserSideNavigation(false);
+
+ // Record this before starting the load. We need a lower bound of this time
+ // to sanitize the navigationStart override set below.
+ base::TimeTicks renderer_navigation_start = base::TimeTicks::Now();
+ frame_->loadRequest(request);
+
+ UpdateFrameNavigationTiming(frame_, request_params.browser_navigation_start,
+ renderer_navigation_start);
+ }
+
+ // In case LoadRequest failed before didCreateDataSource was called.
+ pending_navigation_params_.reset();
+}
+
void RenderFrameImpl::UpdateEncoding(WebFrame* frame,
const std::string& encoding_name) {
// Only update main frame's encoding_name.
@@ -4015,8 +4598,7 @@ void RenderFrameImpl::SyncSelectionIfRequired() {
length = location + length - offset + kExtraCharsBeforeAndAfterSelection;
WebRange webrange = WebRange::fromDocumentRange(frame_, offset, length);
if (!webrange.isNull())
- text = WebRange::fromDocumentRange(
- frame_, offset, length).toPlainText();
+ text = webrange.toPlainText();
} else {
offset = location;
text = frame_->selectionAsText();
@@ -4047,7 +4629,8 @@ void RenderFrameImpl::InitializeUserMediaClient() {
return;
#if defined(OS_ANDROID)
- if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableWebRTC))
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableWebRTC))
return;
#endif
@@ -4090,11 +4673,8 @@ RenderFrameImpl::CreateRendererFactory() {
bool RenderFrameImpl::PrepareRenderViewForNavigation(
const GURL& url,
- FrameMsg_Navigate_Type::Value navigate_type,
- const PageState& state,
- bool check_history,
- int pending_history_list_offset,
- int32 page_id,
+ bool is_history_navigation,
+ const RequestNavigationParams& request_params,
bool* is_reload,
WebURLRequest::CachePolicy* cache_policy) {
MaybeHandleDebugURL(url);
@@ -4105,13 +4685,24 @@ bool RenderFrameImpl::PrepareRenderViewForNavigation(
RenderViewObserver, render_view_->observers_, Navigate(url));
// If this is a stale back/forward (due to a recent navigation the browser
- // didn't know about), ignore it.
- if (check_history && render_view_->IsBackForwardToStaleEntry(
- state, pending_history_list_offset, page_id, *is_reload))
+ // didn't know about), ignore it. Only check if swapped in because if the
+ // frame is swapped out, it won't commit before asking the browser.
+ if (!render_view_->is_swapped_out() && is_history_navigation &&
+ render_view_->history_list_offset_ !=
+ request_params.current_history_list_offset) {
return false;
+ }
+
+ render_view_->history_list_offset_ =
+ request_params.current_history_list_offset;
+ render_view_->history_list_length_ =
+ request_params.current_history_list_length;
+ if (request_params.should_clear_history_list) {
+ CHECK_EQ(-1, render_view_->history_list_offset_);
+ CHECK_EQ(0, render_view_->history_list_length_);
+ }
- if (!render_view_->is_swapped_out_ ||
- GetWebFrame() != render_view_->webview()->mainFrame())
+ if (!is_swapped_out_ || frame_->parent())
return true;
// This is a swapped out main frame, so swap the renderer back in.
@@ -4137,6 +4728,102 @@ bool RenderFrameImpl::PrepareRenderViewForNavigation(
return true;
}
+void RenderFrameImpl::BeginNavigation(blink::WebURLRequest* request) {
+ CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation));
+ DCHECK(request);
+ // TODO(clamy): Execute the beforeunload event.
+
+ // Note: At this stage, the goal is to apply all the modifications the
+ // renderer wants to make to the request, and then send it to the browser, so
+ // that the actual network request can be started. Ideally, all such
+ // modifications should take place in willSendRequest, and in the
+ // implementation of willSendRequest for the various InspectorAgents
+ // (devtools).
+ //
+ // TODO(clamy): Apply devtools override.
+ // TODO(clamy): Make sure that navigation requests are not modified somewhere
+ // else in blink.
+ willSendRequest(frame_, 0, *request, blink::WebURLResponse());
+
+ // TODO(clamy): Same-document navigations should not be sent back to the
+ // browser.
+ // TODO(clamy): Data urls should not be sent back to the browser either.
+ Send(new FrameHostMsg_DidStartLoading(routing_id_, true));
+ Send(new FrameHostMsg_BeginNavigation(
+ routing_id_, MakeCommonNavigationParams(request),
+ BeginNavigationParams(request->httpMethod().latin1(),
+ GetWebURLRequestHeaders(*request),
+ GetLoadFlagsForWebURLRequest(*request),
+ request->hasUserGesture()),
+ GetRequestBodyForWebURLRequest(*request)));
+}
+
+void RenderFrameImpl::LoadDataURL(const CommonNavigationParams& params,
+ WebFrame* frame) {
+ // A loadData request with a specified base URL.
+ std::string mime_type, charset, data;
+ if (net::DataURL::Parse(params.url, &mime_type, &charset, &data)) {
+ const GURL base_url = params.base_url_for_data_url.is_empty() ?
+ params.url : params.base_url_for_data_url;
+ frame->loadData(
+ WebData(data.c_str(), data.length()),
+ WebString::fromUTF8(mime_type),
+ WebString::fromUTF8(charset),
+ base_url,
+ params.history_url_for_data_url,
+ false);
+ } else {
+ CHECK(false) << "Invalid URL passed: "
+ << params.url.possibly_invalid_spec();
+ }
+}
+
+void RenderFrameImpl::SendFailedProvisionalLoad(
+ const blink::WebURLRequest& request,
+ const blink::WebURLError& error,
+ blink::WebLocalFrame* frame) {
+ bool show_repost_interstitial = (error.reason == net::ERR_CACHE_MISS &&
+ EqualsASCII(request.httpMethod(), "POST"));
+
+ FrameHostMsg_DidFailProvisionalLoadWithError_Params params;
+ params.error_code = error.reason;
+ GetContentClient()->renderer()->GetNavigationErrorStrings(
+ render_view_.get(), frame, request, error, NULL,
+ &params.error_description);
+ params.url = error.unreachableURL;
+ params.showing_repost_interstitial = show_repost_interstitial;
+ Send(new FrameHostMsg_DidFailProvisionalLoadWithError(routing_id_, params));
+}
+
+bool RenderFrameImpl::ShouldDisplayErrorPageForFailedLoad(
+ int error_code,
+ const GURL& unreachable_url) {
+ // Don't display an error page if this is simply a cancelled load. Aside
+ // from being dumb, Blink doesn't expect it and it will cause a crash.
+ if (error_code == net::ERR_ABORTED)
+ return false;
+
+ // Don't display "client blocked" error page if browser has asked us not to.
+ if (error_code == net::ERR_BLOCKED_BY_CLIENT &&
+ render_view_->renderer_preferences_.disable_client_blocked_error_page) {
+ return false;
+ }
+
+ // Allow the embedder to suppress an error page.
+ if (GetContentClient()->renderer()->ShouldSuppressErrorPage(
+ this, unreachable_url)) {
+ return false;
+ }
+
+ if (RenderThreadImpl::current() &&
+ RenderThreadImpl::current()->layout_test_mode()) {
+ return false;
+ }
+
+ return true;
+}
+
GURL RenderFrameImpl::GetLoadingUrl() const {
WebDataSource* ds = frame_->dataSource();
if (ds->hasUnreachableURL())
@@ -4146,11 +4833,68 @@ GURL RenderFrameImpl::GetLoadingUrl() const {
return request.url();
}
+void RenderFrameImpl::PopulateDocumentStateFromPending(
+ DocumentState* document_state) {
+ document_state->set_request_time(
+ pending_navigation_params_->request_params.request_time);
+
+ InternalDocumentStateData* internal_data =
+ InternalDocumentStateData::FromDocumentState(document_state);
+
+ if (!pending_navigation_params_->common_params.url.SchemeIs(
+ url::kJavaScriptScheme) &&
+ pending_navigation_params_->common_params.navigation_type ==
+ FrameMsg_Navigate_Type::RESTORE) {
+ // We're doing a load of a page that was restored from the last session. By
+ // default this prefers the cache over loading (LOAD_PREFERRING_CACHE) which
+ // can result in stale data for pages that are set to expire. We explicitly
+ // override that by setting the policy here so that as necessary we load
+ // from the network.
+ //
+ // TODO(davidben): Remove this in favor of passing a cache policy to the
+ // loadHistoryItem call in OnNavigate. That requires not overloading
+ // UseProtocolCachePolicy to mean both "normal load" and "determine cache
+ // policy based on load type, etc".
+ internal_data->set_cache_policy_override(
+ WebURLRequest::UseProtocolCachePolicy);
+ }
+
+ if (IsReload(pending_navigation_params_->common_params.navigation_type))
+ document_state->set_load_type(DocumentState::RELOAD);
+ else if (pending_navigation_params_->request_params.page_state.IsValid())
+ document_state->set_load_type(DocumentState::HISTORY_LOAD);
+ else
+ document_state->set_load_type(DocumentState::NORMAL_LOAD);
+
+ internal_data->set_is_overriding_user_agent(
+ pending_navigation_params_->request_params.is_overriding_user_agent);
+ internal_data->set_must_reset_scroll_and_scale_state(
+ pending_navigation_params_->common_params.navigation_type ==
+ FrameMsg_Navigate_Type::RELOAD_ORIGINAL_REQUEST_URL);
+ document_state->set_can_load_local_resources(
+ pending_navigation_params_->request_params.can_load_local_resources);
+}
+
+NavigationState* RenderFrameImpl::CreateNavigationStateFromPending() {
+ // A navigation resulting from loading a javascript URL should not be treated
+ // as a browser initiated event. Instead, we want it to look as if the page
+ // initiated any load resulting from JS execution.
+ if (!pending_navigation_params_->common_params.url.SchemeIs(
+ url::kJavaScriptScheme)) {
+ return NavigationStateImpl::CreateBrowserInitiated(
+ pending_navigation_params_->common_params,
+ pending_navigation_params_->start_params,
+ pending_navigation_params_->request_params);
+ }
+ return NavigationStateImpl::CreateContentInitiated();
+}
+
#if defined(OS_ANDROID)
WebMediaPlayer* RenderFrameImpl::CreateAndroidWebMediaPlayer(
const blink::WebURL& url,
WebMediaPlayerClient* client,
+ media::MediaPermission* media_permission,
blink::WebContentDecryptionModule* initial_cdm) {
GpuChannelHost* gpu_channel_host =
RenderThreadImpl::current()->EstablishGpuChannelSync(
@@ -4165,7 +4909,7 @@ WebMediaPlayer* RenderFrameImpl::CreateAndroidWebMediaPlayer(
SynchronousCompositorFactory::GetInstance()) {
stream_texture_factory = factory->CreateStreamTextureFactory(routing_id_);
} else {
- scoped_refptr<webkit::gpu::ContextProviderWebContext> context_provider =
+ scoped_refptr<cc_blink::ContextProviderWebContext> context_provider =
RenderThreadImpl::current()->SharedMainThreadContextProvider();
if (!context_provider.get()) {
@@ -4178,13 +4922,8 @@ WebMediaPlayer* RenderFrameImpl::CreateAndroidWebMediaPlayer(
}
return new WebMediaPlayerAndroid(
- frame_,
- client,
- weak_factory_.GetWeakPtr(),
- GetMediaPlayerManager(),
- GetCdmManager(),
- initial_cdm,
- stream_texture_factory,
+ frame_, client, weak_factory_.GetWeakPtr(), GetMediaPlayerManager(),
+ GetCdmFactory(), media_permission, initial_cdm, stream_texture_factory,
RenderThreadImpl::current()->GetMediaThreadTaskRunner(),
new RenderMediaLog());
}
@@ -4197,12 +4936,40 @@ RendererMediaPlayerManager* RenderFrameImpl::GetMediaPlayerManager() {
#endif // defined(OS_ANDROID)
+media::MediaPermission* RenderFrameImpl::GetMediaPermission() {
+ if (!media_permission_dispatcher_)
+ media_permission_dispatcher_ = new MediaPermissionDispatcher(this);
+ return media_permission_dispatcher_;
+}
+
+bool RenderFrameImpl::AreSecureCodecsSupported() {
+#if defined(OS_ANDROID)
+ // Hardware-secure codecs are only supported if secure surfaces are enabled.
+ return render_view_->renderer_preferences_
+ .use_video_overlay_for_embedded_encrypted_video;
+#else
+ return false;
+#endif // defined(OS_ANDROID)
+}
+
+media::CdmFactory* RenderFrameImpl::GetCdmFactory() {
#if defined(ENABLE_BROWSER_CDMS)
-RendererCdmManager* RenderFrameImpl::GetCdmManager() {
if (!cdm_manager_)
cdm_manager_ = new RendererCdmManager(this);
- return cdm_manager_;
-}
#endif // defined(ENABLE_BROWSER_CDMS)
+ if (!cdm_factory_) {
+ DCHECK(frame_);
+ cdm_factory_ = new RenderCdmFactory(
+#if defined(ENABLE_PEPPER_CDMS)
+ base::Bind(&PepperCdmWrapperImpl::Create, frame_),
+#elif defined(ENABLE_BROWSER_CDMS)
+ cdm_manager_,
+#endif
+ this);
+ }
+
+ return cdm_factory_;
+}
+
} // namespace content
diff --git a/chromium/content/renderer/render_frame_impl.h b/chromium/content/renderer/render_frame_impl.h
index 77d49414589..ea47e628fe8 100644
--- a/chromium/content/renderer/render_frame_impl.h
+++ b/chromium/content/renderer/render_frame_impl.h
@@ -11,6 +11,7 @@
#include "base/files/file_path.h"
#include "base/gtest_prod_util.h"
#include "base/id_map.h"
+#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/process/process_handle.h"
@@ -24,12 +25,19 @@
#include "content/renderer/renderer_webcookiejar_impl.h"
#include "ipc/ipc_message.h"
#include "media/blink/webmediaplayer_delegate.h"
+#include "third_party/WebKit/public/platform/modules/app_banner/WebAppBannerClient.h"
#include "third_party/WebKit/public/web/WebAXObject.h"
#include "third_party/WebKit/public/web/WebDataSource.h"
#include "third_party/WebKit/public/web/WebFrameClient.h"
#include "third_party/WebKit/public/web/WebHistoryCommitType.h"
+#include "third_party/WebKit/public/web/WebScriptExecutionCallback.h"
+#include "third_party/WebKit/public/web/WebTransitionElementData.h"
#include "ui/gfx/range/range.h"
+#if defined(ENABLE_PLUGINS)
+#include "content/renderer/pepper/plugin_power_saver_helper.h"
+#endif
+
#if defined(OS_ANDROID)
#include "content/renderer/media/android/renderer_media_player_manager.h"
#endif
@@ -37,20 +45,22 @@
class GURL;
class TransportDIB;
struct FrameHostMsg_AddNavigationTransitionData_Params;
-struct FrameMsg_Navigate_Params;
-struct FrameMsg_RequestNavigation_Params;
+struct FrameMsg_NewFrame_WidgetParams;
+struct FrameMsg_PostMessage_Params;
+struct FrameMsg_TextTrackSettings_Params;
namespace blink {
class WebGeolocationClient;
class WebMouseEvent;
class WebContentDecryptionModule;
class WebMediaPlayer;
-class WebNotificationPresenter;
+class WebPresentationClient;
class WebPushClient;
class WebSecurityOrigin;
struct WebCompositionUnderline;
struct WebContextMenuData;
struct WebCursorInfo;
+struct WebTransitionElementData;
}
namespace gfx {
@@ -59,22 +69,33 @@ class Range;
class Rect;
}
+namespace media {
+class CdmFactory;
+class MediaPermission;
+class WebEncryptedMediaClientImpl;
+}
+
namespace content {
class ChildFrameCompositingHelper;
+class CompositorDependencies;
+class DevToolsAgent;
+class DocumentState;
class ExternalPopupMenu;
class GeolocationDispatcher;
class ManifestManager;
class MediaStreamDispatcher;
class MediaStreamRendererFactory;
+class MediaPermissionDispatcher;
class MidiDispatcher;
+class NavigationState;
class NotificationPermissionDispatcher;
-class NotificationProvider;
class PageState;
class PepperPluginInstanceImpl;
-class PluginPowerSaverHelper;
+class PermissionDispatcher;
+class PresentationDispatcher;
class PushMessagingDispatcher;
-class PushPermissionDispatcher;
+class RenderCdmFactory;
class RendererAccessibility;
class RendererCdmManager;
class RendererMediaPlayerManager;
@@ -85,11 +106,15 @@ class RenderWidget;
class RenderWidgetFullscreenPepper;
class ScreenOrientationDispatcher;
class UserMediaClientImpl;
-struct CommitNavigationParams;
+enum class SandboxFlags;
struct CommonNavigationParams;
struct CustomContextMenuContext;
+struct FrameReplicationState;
+struct NavigationParams;
struct RequestNavigationParams;
struct ResourceResponseHead;
+struct StartNavigationParams;
+struct StreamOverrideParameters;
class CONTENT_EXPORT RenderFrameImpl
: public RenderFrame,
@@ -107,15 +132,20 @@ class CONTENT_EXPORT RenderFrameImpl
// Creates a new RenderFrame with |routing_id| as a child of the RenderFrame
// identified by |parent_routing_id| or as the top-level frame if the latter
// is MSG_ROUTING_NONE. If |proxy_routing_id| is MSG_ROUTING_NONE, it creates
- // the Blink WebLocalFrame and inserts it in the proper place in the frame
- // tree. Otherwise, the frame is semi-orphaned until it commits, at which
- // point it replaces the proxy identified by |proxy_routing_id|.
- // Note: This is called only when RenderFrame is being created in response to
- // IPC message from the browser process. All other frame creation is driven
- // through Blink and Create.
+ // the Blink WebLocalFrame and inserts it into the frame tree after the frame
+ // identified by |previous_sibling_routing_id|, or as the first child if
+ // |previous_sibling_routing_id| is MSG_ROUTING_NONE. Otherwise, the frame is
+ // semi-orphaned until it commits, at which point it replaces the proxy
+ // identified by |proxy_routing_id|. Note: This is called only when
+ // RenderFrame is being created in response to IPC message from the browser
+ // process. All other frame creation is driven through Blink and Create.
static void CreateFrame(int routing_id,
int parent_routing_id,
- int proxy_routing_id);
+ int previous_sibling_routing_id,
+ int proxy_routing_id,
+ const FrameReplicationState& replicated_state,
+ CompositorDependencies* compositor_deps,
+ const FrameMsg_NewFrame_WidgetParams& params);
// Returns the RenderFrameImpl for the given routing ID.
static RenderFrameImpl* FromRoutingID(int routing_id);
@@ -125,8 +155,16 @@ class CONTENT_EXPORT RenderFrameImpl
// Used by content_layouttest_support to hook into the creation of
// RenderFrameImpls.
+ using CreateRenderFrameImplFunction = RenderFrameImpl* (*)(RenderViewImpl*,
+ int32);
static void InstallCreateHook(
- RenderFrameImpl* (*create_render_frame_impl)(RenderViewImpl*, int32));
+ CreateRenderFrameImplFunction create_render_frame_impl);
+
+ static content::SandboxFlags WebToContentSandboxFlags(
+ blink::WebSandboxFlags flags);
+
+ static blink::WebSandboxFlags ContentToWebSandboxFlags(
+ content::SandboxFlags flags);
virtual ~RenderFrameImpl();
@@ -153,6 +191,8 @@ class CONTENT_EXPORT RenderFrameImpl
// Returns the RenderWidget associated with this frame.
RenderWidget* GetRenderWidget();
+ DevToolsAgent* devtools_agent() { return devtools_agent_; }
+
// This is called right after creation with the WebLocalFrame for this
// RenderFrame. It must be called before Initialize.
void SetWebFrame(blink::WebLocalFrame* web_frame);
@@ -165,6 +205,7 @@ class CONTENT_EXPORT RenderFrameImpl
// Notifications from RenderWidget.
void WasHidden();
void WasShown();
+ void WidgetWillClose();
// Start/Stop loading notifications.
// TODO(nasko): Those are page-level methods at this time and come from
@@ -187,10 +228,14 @@ class CONTENT_EXPORT RenderFrameImpl
void HandleWebAccessibilityEvent(const blink::WebAXObject& obj,
blink::WebAXEvent event);
+ // The focused node changed to |node|. If focus was lost from this frame,
+ // |node| will be null.
+ void FocusedNodeChanged(const blink::WebNode& node);
+
// TODO(dmazzoni): the only reason this is here is to plumb it through to
- // RendererAccessibility. It should be part of RenderFrameObserver, once
+ // RendererAccessibility. It should use the RenderFrameObserver method, once
// blink has a separate accessibility tree per frame.
- void FocusedNodeChanged(const blink::WebNode& node);
+ void FocusedNodeChangedForAccessibility(const blink::WebNode& node);
#if defined(ENABLE_PLUGINS)
// Notification that a PPAPI plugin has been created.
@@ -244,8 +289,6 @@ class CONTENT_EXPORT RenderFrameImpl
void OnImeConfirmComposition(const base::string16& text,
const gfx::Range& replacement_range,
bool keep_selection);
-
- PluginPowerSaverHelper* plugin_power_saver_helper();
#endif // defined(ENABLE_PLUGINS)
// May return NULL in some cases, especially if userMediaClient() returns
@@ -266,27 +309,39 @@ class CONTENT_EXPORT RenderFrameImpl
RenderView* GetRenderView() override;
int GetRoutingID() override;
blink::WebLocalFrame* GetWebFrame() override;
+ blink::WebElement GetFocusedElement() const override;
WebPreferences& GetWebkitPreferences() override;
int ShowContextMenu(ContextMenuClient* client,
const ContextMenuParams& params) override;
void CancelContextMenu(int request_id) override;
blink::WebNode GetContextMenuNode() const override;
- blink::WebPlugin* CreatePlugin(blink::WebFrame* frame,
- const WebPluginInfo& info,
- const blink::WebPluginParams& params) override;
+ blink::WebPlugin* CreatePlugin(
+ blink::WebFrame* frame,
+ const WebPluginInfo& info,
+ const blink::WebPluginParams& params,
+ scoped_ptr<PluginInstanceThrottler> throttler) override;
void LoadURLExternally(blink::WebLocalFrame* frame,
const blink::WebURLRequest& request,
blink::WebNavigationPolicy policy) override;
void ExecuteJavaScript(const base::string16& javascript) override;
bool IsHidden() override;
ServiceRegistry* GetServiceRegistry() override;
+#if defined(ENABLE_PLUGINS)
+ void RegisterPeripheralPlugin(
+ const GURL& content_origin,
+ const base::Closure& unthrottle_callback) override;
+ PluginPowerSaverHelper* plugin_power_saver_helper() {
+ return plugin_power_saver_helper_;
+ }
+#endif
bool IsFTPDirectoryListing() override;
void AttachGuest(int element_instance_id) override;
+ void DetachGuest(int element_instance_id) override;
void SetSelectedText(const base::string16& selection_text,
size_t offset,
const gfx::Range& range) override;
void EnsureMojoBuiltinsAreAvailable(v8::Isolate* isolate,
- v8::Handle<v8::Context> context) override;
+ v8::Local<v8::Context> context) override;
// blink::WebFrameClient implementation:
blink::WebPluginPlaceholder* createPluginPlaceholder(
@@ -304,15 +359,11 @@ class CONTENT_EXPORT RenderFrameImpl
const blink::WebURL& url,
blink::WebMediaPlayerClient* client,
blink::WebContentDecryptionModule* initial_cdm);
- virtual blink::WebContentDecryptionModule* createContentDecryptionModule(
- blink::WebLocalFrame* frame,
- const blink::WebSecurityOrigin& security_origin,
- const blink::WebString& key_system);
virtual blink::WebApplicationCacheHost* createApplicationCacheHost(
blink::WebLocalFrame* frame,
blink::WebApplicationCacheHostClient* client);
- virtual blink::WebWorkerPermissionClientProxy*
- createWorkerPermissionClientProxy(blink::WebLocalFrame* frame);
+ virtual blink::WebWorkerContentSettingsClientProxy*
+ createWorkerContentSettingsClientProxy(blink::WebLocalFrame* frame);
virtual blink::WebExternalPopupMenu* createExternalPopupMenu(
const blink::WebPopupMenuInfo& popup_menu_info,
blink::WebExternalPopupMenuClient* popup_menu_client);
@@ -320,14 +371,18 @@ class CONTENT_EXPORT RenderFrameImpl
virtual blink::WebServiceWorkerProvider* createServiceWorkerProvider(
blink::WebLocalFrame* frame);
virtual void didAccessInitialDocument(blink::WebLocalFrame* frame);
- virtual blink::WebFrame* createChildFrame(blink::WebLocalFrame* parent,
- const blink::WebString& name);
+ virtual blink::WebFrame* createChildFrame(
+ blink::WebLocalFrame* parent,
+ const blink::WebString& name,
+ blink::WebSandboxFlags sandboxFlags);
virtual void didDisownOpener(blink::WebLocalFrame* frame);
virtual void frameDetached(blink::WebFrame* frame);
virtual void frameFocused();
virtual void willClose(blink::WebFrame* frame);
virtual void didChangeName(blink::WebLocalFrame* frame,
const blink::WebString& name);
+ virtual void didChangeSandboxFlags(blink::WebFrame* child_frame,
+ blink::WebSandboxFlags flags);
virtual void didMatchCSS(
blink::WebLocalFrame* frame,
const blink::WebVector<blink::WebString>& newly_matching_selectors,
@@ -354,16 +409,19 @@ class CONTENT_EXPORT RenderFrameImpl
virtual void didCreateDataSource(blink::WebLocalFrame* frame,
blink::WebDataSource* datasource);
virtual void didStartProvisionalLoad(blink::WebLocalFrame* frame,
- bool is_transition_navigation);
+ bool is_transition_navigation,
+ double triggering_event_time);
virtual void didReceiveServerRedirectForProvisionalLoad(
blink::WebLocalFrame* frame);
virtual void didFailProvisionalLoad(
blink::WebLocalFrame* frame,
- const blink::WebURLError& error);
+ const blink::WebURLError& error,
+ blink::WebHistoryCommitType commit_type);
virtual void didCommitProvisionalLoad(
blink::WebLocalFrame* frame,
const blink::WebHistoryItem& item,
blink::WebHistoryCommitType commit_type);
+ virtual void didCreateNewDocument(blink::WebLocalFrame* frame);
virtual void didClearWindowObject(blink::WebLocalFrame* frame);
virtual void didCreateDocumentElement(blink::WebLocalFrame* frame);
virtual void didReceiveTitle(blink::WebLocalFrame* frame,
@@ -374,27 +432,20 @@ class CONTENT_EXPORT RenderFrameImpl
virtual void didFinishDocumentLoad(blink::WebLocalFrame* frame);
virtual void didHandleOnloadEvents(blink::WebLocalFrame* frame);
virtual void didFailLoad(blink::WebLocalFrame* frame,
- const blink::WebURLError& error);
+ const blink::WebURLError& error,
+ blink::WebHistoryCommitType commit_type);
virtual void didFinishLoad(blink::WebLocalFrame* frame);
virtual void didNavigateWithinPage(blink::WebLocalFrame* frame,
const blink::WebHistoryItem& item,
blink::WebHistoryCommitType commit_type);
virtual void didUpdateCurrentHistoryItem(blink::WebLocalFrame* frame);
virtual void addNavigationTransitionData(
- const blink::WebString& allowedDestinationOrigin,
- const blink::WebString& selector,
- const blink::WebString& markup);
- virtual void addNavigationTransitionData(
- const blink::WebString& allowedDestinationOrigin,
- const blink::WebString& selector,
- const blink::WebString& markup,
- const blink::WebVector<blink::WebString>& web_names,
- const blink::WebVector<blink::WebRect>& web_rects);
+ const blink::WebTransitionElementData& data);
virtual void didChangeThemeColor();
+ virtual void dispatchLoad();
virtual void requestNotificationPermission(
const blink::WebSecurityOrigin& origin,
blink::WebNotificationPermissionCallback* callback);
- virtual blink::WebNotificationPresenter* notificationPresenter();
virtual void didChangeSelection(bool is_empty_selection);
virtual blink::WebColorChooser* createColorChooser(
blink::WebColorChooserClient* client,
@@ -428,11 +479,11 @@ class CONTENT_EXPORT RenderFrameImpl
const blink::WebURL& target);
virtual void didAbortLoading(blink::WebLocalFrame* frame);
virtual void didCreateScriptContext(blink::WebLocalFrame* frame,
- v8::Handle<v8::Context> context,
+ v8::Local<v8::Context> context,
int extension_group,
int world_id);
virtual void willReleaseScriptContext(blink::WebLocalFrame* frame,
- v8::Handle<v8::Context> context,
+ v8::Local<v8::Context> context,
int world_id);
virtual void didFirstVisuallyNonEmptyLayout(blink::WebLocalFrame* frame);
virtual void didChangeScrollOffset(blink::WebLocalFrame* frame);
@@ -449,12 +500,13 @@ class CONTENT_EXPORT RenderFrameImpl
blink::WebStorageQuotaCallbacks callbacks);
virtual void willOpenWebSocket(blink::WebSocketHandle* handle);
virtual blink::WebGeolocationClient* geolocationClient();
- virtual void requestPushPermission(blink::WebCallback* callback);
virtual blink::WebPushClient* pushClient();
+ virtual blink::WebPresentationClient* presentationClient();
virtual void willStartUsingPeerConnectionHandler(
blink::WebLocalFrame* frame,
blink::WebRTCPeerConnectionHandler* handler);
virtual blink::WebUserMediaClient* userMediaClient();
+ virtual blink::WebEncryptedMediaClient* encryptedMediaClient();
virtual blink::WebMIDIClient* webMIDIClient();
virtual bool willCheckAndDispatchMessageEvent(
blink::WebLocalFrame* source_frame,
@@ -480,6 +532,11 @@ class CONTENT_EXPORT RenderFrameImpl
const blink::WebAXObject& end_object,
int end_offset);
virtual void didChangeManifest(blink::WebLocalFrame*);
+ virtual void didChangeDefaultPresentation(blink::WebLocalFrame*);
+ virtual bool enterFullscreen();
+ virtual bool exitFullscreen();
+ virtual blink::WebPermissionClient* permissionClient();
+ virtual blink::WebAppBannerClient* appBannerClient();
// WebMediaPlayerDelegate implementation:
void DidPlay(blink::WebMediaPlayer* player) override;
@@ -488,20 +545,33 @@ class CONTENT_EXPORT RenderFrameImpl
// TODO(nasko): Make all tests in RenderViewImplTest friends and then move
// this back to private member.
- void OnNavigate(const FrameMsg_Navigate_Params& params);
+ void OnNavigate(const CommonNavigationParams& common_params,
+ const StartNavigationParams& start_params,
+ const RequestNavigationParams& request_params);
- // Binds this render frame's service registry to a handle to the remote
- // service registry.
+ // Make this frame show an empty, unscriptable page.
+ // TODO(nasko): Remove this method once swapped out state is no longer used.
+ void NavigateToSwappedOutURL();
+
+ // Binds this render frame's service registry.
void BindServiceRegistry(
- mojo::ScopedMessagePipeHandle service_provider_handle);
+ mojo::InterfaceRequest<mojo::ServiceProvider> services,
+ mojo::ServiceProviderPtr exposed_services);
ManifestManager* manifest_manager();
+ // TODO(creis): Remove when the only caller, the HistoryController, is no
+ // more.
+ void SetPendingNavigationParams(
+ scoped_ptr<NavigationParams> navigation_params);
+
protected:
RenderFrameImpl(RenderViewImpl* render_view, int32 routing_id);
private:
+ friend class RenderFrameImplTest;
friend class RenderFrameObserver;
+ friend class RenderViewImplTest;
friend class RendererAccessibilityTest;
FRIEND_TEST_ALL_PREFIXES(ExternalPopupMenuDisplayNoneTest, SelectItem);
FRIEND_TEST_ALL_PREFIXES(ExternalPopupMenuRemoveTest, RemoveOnChange);
@@ -509,14 +579,30 @@ class CONTENT_EXPORT RenderFrameImpl
FRIEND_TEST_ALL_PREFIXES(ExternalPopupMenuTest, ShowPopupThenNavigate);
FRIEND_TEST_ALL_PREFIXES(RendererAccessibilityTest,
AccessibilityMessagesQueueWhileSwappedOut);
- FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest,
- OnExtendSelectionAndDelete);
- FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest, ReloadWhileSwappedOut);
- FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest, SendSwapOutACK);
- FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest,
- SetEditableSelectionAndComposition);
- FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest,
- OnSetAccessibilityMode);
+
+ // A wrapper class used as the callback for JavaScript executed
+ // in an isolated world.
+ class JavaScriptIsolatedWorldRequest
+ : public blink::WebScriptExecutionCallback {
+ public:
+ JavaScriptIsolatedWorldRequest(
+ int id,
+ bool notify_result,
+ int routing_id,
+ base::WeakPtr<RenderFrameImpl> render_frame_impl);
+ void completed(
+ const blink::WebVector<v8::Local<v8::Value>>& result) override;
+
+ private:
+ ~JavaScriptIsolatedWorldRequest();
+
+ int id_;
+ bool notify_result_;
+ int routing_id_;
+ base::WeakPtr<RenderFrameImpl> render_frame_impl_;
+
+ DISALLOW_COPY_AND_ASSIGN(JavaScriptIsolatedWorldRequest);
+ };
typedef std::map<GURL, double> HostZoomLevels;
@@ -525,18 +611,17 @@ class CONTENT_EXPORT RenderFrameImpl
void RemoveObserver(RenderFrameObserver* observer);
// Builds and sends DidCommitProvisionalLoad to the host.
- void SendDidCommitProvisionalLoad(blink::WebFrame* frame);
-
- // Gets the focused element. If no such element exists then the element will
- // be NULL.
- blink::WebElement GetFocusedElement();
+ void SendDidCommitProvisionalLoad(blink::WebFrame* frame,
+ blink::WebHistoryCommitType commit_type);
// IPC message handlers ------------------------------------------------------
//
// The documentation for these functions should be in
// content/common/*_messages.h for the message that the function is handling.
void OnBeforeUnload();
- void OnSwapOut(int proxy_routing_id);
+ void OnSwapOut(int proxy_routing_id,
+ bool is_loading,
+ const FrameReplicationState& replicated_frame_state);
void OnStop();
void OnShowContextMenu(const gfx::Point& location);
void OnContextMenuClosed(const CustomContextMenuContext& custom_context);
@@ -561,19 +646,35 @@ class CONTENT_EXPORT RenderFrameImpl
bool notify_result);
void OnJavaScriptExecuteRequestForTests(const base::string16& javascript,
int id,
- bool notify_result);
+ bool notify_result,
+ bool has_user_gesture);
+ void OnJavaScriptExecuteRequestInIsolatedWorld(const base::string16& jscript,
+ int id,
+ bool notify_result,
+ int world_id);
+ void OnVisualStateRequest(uint64 key);
void OnSetEditableSelectionOffsets(int start, int end);
void OnSetCompositionFromExistingText(
int start, int end,
const std::vector<blink::WebCompositionUnderline>& underlines);
+ void OnExecuteNoValueEditCommand(const std::string& name);
void OnExtendSelectionAndDelete(int before, int after);
void OnReload(bool ignore_cache);
void OnTextSurroundingSelectionRequest(size_t max_length);
void OnAddStyleSheetByURL(const std::string& url);
void OnSetupTransitionView(const std::string& markup);
- void OnBeginExitTransition(const std::string& css_selector);
+ void OnBeginExitTransition(const std::string& css_selector,
+ bool exit_to_native_app);
+ void OnRevertExitTransition();
+ void OnHideTransitionElements(const std::string& css_selector);
+ void OnShowTransitionElements(const std::string& css_selector);
void OnSetAccessibilityMode(AccessibilityMode new_mode);
+ void OnSnapshotAccessibilityTree(int callback_id);
void OnDisownOpener();
+ void OnDidUpdateSandboxFlags(SandboxFlags flags);
+ void OnTextTrackSettingsChanged(
+ const FrameMsg_TextTrackSettings_Params& params);
+ void OnPostMessageEvent(const FrameMsg_PostMessage_Params& params);
#if defined(OS_ANDROID)
void OnSelectPopupMenuItems(bool canceled,
const std::vector<int>& selected_indices);
@@ -582,13 +683,14 @@ class CONTENT_EXPORT RenderFrameImpl
void OnCopyToFindPboard();
#endif
- // PlzNavigate
- void OnRequestNavigation(const CommonNavigationParams& common_params,
- const RequestNavigationParams& request_params);
void OnCommitNavigation(const ResourceResponseHead& response,
const GURL& stream_url,
const CommonNavigationParams& common_params,
- const CommitNavigationParams& commit_params);
+ const RequestNavigationParams& request_params);
+ void OnFailedNavigation(const CommonNavigationParams& common_params,
+ const RequestNavigationParams& request_params,
+ bool has_stale_copy_in_cache,
+ int error_code);
// Virtual since overridden by WebTestProxy for layout tests.
virtual blink::WebNavigationPolicy DecidePolicyForNavigation(
@@ -599,6 +701,19 @@ class CONTENT_EXPORT RenderFrameImpl
const Referrer& referrer,
blink::WebNavigationPolicy policy);
+ // Performs a navigation in the frame. This provides a unified function for
+ // the current code path and the browser-side navigation path (in
+ // development). Currently used by OnNavigate, with all *NavigationParams
+ // provided by the browser. |stream_params| should be null.
+ // PlzNavigate: used by OnCommitNavigation, with |common_params| and
+ // |request_params| received by the browser. |stream_params| should be non
+ // null and created from the information provided by the browser.
+ // |start_params| is not used.
+ void NavigateInternal(const CommonNavigationParams& common_params,
+ const StartNavigationParams& start_params,
+ const RequestNavigationParams& request_params,
+ scoped_ptr<StreamOverrideParameters> stream_params);
+
// Update current main frame's encoding and send it to browser window.
// Since we want to let users see the right encoding info from menu
// before finishing loading, we call the UpdateEncoding in
@@ -635,7 +750,7 @@ class CONTENT_EXPORT RenderFrameImpl
void HandleJavascriptExecutionResult(const base::string16& javascript,
int id,
bool notify_result,
- v8::Handle<v8::Value> result);
+ v8::Local<v8::Value> result);
// Initializes |web_user_media_client_|. If this fails, because it wasn't
// possible to create a MediaStreamClient (e.g., WebRTC is disabled), then
@@ -651,39 +766,76 @@ class CONTENT_EXPORT RenderFrameImpl
virtual scoped_ptr<MediaStreamRendererFactory> CreateRendererFactory();
// Checks that the RenderView is ready to display the navigation to |url|. If
- // the return value is false, the navigation should be abandonned.
+ // the return value is false, the navigation should be abandoned.
bool PrepareRenderViewForNavigation(
const GURL& url,
- FrameMsg_Navigate_Type::Value navigate_type,
- const PageState& state,
- bool check_history,
- int pending_history_list_offset,
- int32 page_id,
+ bool is_history_navigation,
+ const RequestNavigationParams& request_params,
bool* is_reload,
blink::WebURLRequest::CachePolicy* cache_policy);
+ // PlzNavigate
+ // Sends a FrameHostMsg_BeginNavigation to the browser based on the contents
+ // of the WebURLRequest.
+ void BeginNavigation(blink::WebURLRequest* request);
+
+ // Loads a data url.
+ void LoadDataURL(const CommonNavigationParams& params,
+ blink::WebFrame* frame);
+
+ // Sends a proper FrameHostMsg_DidFailProvisionalLoadWithError_Params IPC for
+ // the failed request |request|.
+ void SendFailedProvisionalLoad(const blink::WebURLRequest& request,
+ const blink::WebURLError& error,
+ blink::WebLocalFrame* frame);
+
+ bool ShouldDisplayErrorPageForFailedLoad(int error_code,
+ const GURL& unreachable_url);
+
// Returns the URL being loaded by the |frame_|'s request.
GURL GetLoadingUrl() const;
+ // If we initiated a navigation, this function will populate |document_state|
+ // with the navigation information saved in OnNavigate().
+ void PopulateDocumentStateFromPending(DocumentState* document_state);
+
+ // Returns a new NavigationState populated with the navigation information
+ // saved in OnNavigate().
+ NavigationState* CreateNavigationStateFromPending();
+
#if defined(OS_ANDROID)
blink::WebMediaPlayer* CreateAndroidWebMediaPlayer(
const blink::WebURL& url,
blink::WebMediaPlayerClient* client,
+ media::MediaPermission* media_permission,
blink::WebContentDecryptionModule* initial_cdm);
RendererMediaPlayerManager* GetMediaPlayerManager();
#endif
-#if defined(ENABLE_BROWSER_CDMS)
- RendererCdmManager* GetCdmManager();
-#endif
+ bool AreSecureCodecsSupported();
+ media::MediaPermission* GetMediaPermission();
+ media::CdmFactory* GetCdmFactory();
- // Stores the WebLocalFrame we are associated with.
+ // Stores the WebLocalFrame we are associated with. This is null from the
+ // constructor until SetWebFrame is called, and it is null after
+ // frameDetached is called until destruction (which is asynchronous in the
+ // case of the main frame, but not subframes).
blink::WebLocalFrame* frame_;
+ // Boolean value indicating whether this RenderFrameImpl object is for a
+ // subframe or not. It remains accurate during destruction, even when |frame_|
+ // has been invalidated.
+ bool is_subframe_;
+
+ // Frame is a local root if it is rendered in a process different than parent
+ // or it is a main frame.
+ bool is_local_root_;
+
base::WeakPtr<RenderViewImpl> render_view_;
int routing_id_;
bool is_swapped_out_;
+
// RenderFrameProxy exists only when is_swapped_out_ is true.
// TODO(nasko): This can be removed once we don't have a swapped out state on
// RenderFrame. See https://crbug.com/357747.
@@ -696,6 +848,18 @@ class CONTENT_EXPORT RenderFrameImpl
// TODO(creis): Remove this after switching to PlzNavigate.
int proxy_routing_id_;
+ // Used when the RenderFrame is a local root. For now, RenderWidgets are
+ // added only when a child frame is in a different process from its parent
+ // frame, but eventually this will also apply to top-level frames.
+ // TODO(kenrb): Correct the above statement when top-level frames have their
+ // own RenderWidgets.
+ scoped_refptr<RenderWidget> render_widget_;
+
+ // Temporarily holds state pertaining to a navigation that has been initiated
+ // until the NavigationState corresponding to the new navigation is created in
+ // didCreateDataSource().
+ scoped_ptr<NavigationParams> pending_navigation_params_;
+
#if defined(ENABLE_PLUGINS)
// Current text input composition text. Empty if no composition is in
// progress.
@@ -749,13 +913,15 @@ class CONTENT_EXPORT RenderFrameImpl
// Dispatches permission requests for Web Notifications.
NotificationPermissionDispatcher* notification_permission_dispatcher_;
- // Holds a reference to the service which provides desktop notifications.
- // TODO(peter) Remove this once Web Notifications are routed through Platform.
- NotificationProvider* notification_provider_;
-
// Destroyed via the RenderFrameObserver::OnDestruct() mechanism.
UserMediaClientImpl* web_user_media_client_;
+ // EncryptedMediaClient attached to this frame; lazily initialized.
+ scoped_ptr<media::WebEncryptedMediaClientImpl> web_encrypted_media_client_;
+
+ // The media permission dispatcher attached to this frame, lazily initialized.
+ MediaPermissionDispatcher* media_permission_dispatcher_;
+
// MidiClient attached to this frame; lazily initialized.
MidiDispatcher* midi_dispatcher_;
@@ -773,22 +939,29 @@ class CONTENT_EXPORT RenderFrameImpl
RendererCdmManager* cdm_manager_;
#endif
+ // The CDM factory attached to this frame, lazily initialized.
+ RenderCdmFactory* cdm_factory_;
+
#if defined(VIDEO_HOLE)
// Whether or not this RenderFrameImpl contains a media player. Used to
// register as an observer for video-hole-specific events.
bool contains_media_player_;
#endif
+ // The devtools agent for this frame; only created for main frame and
+ // local roots.
+ DevToolsAgent* devtools_agent_;
+
// The geolocation dispatcher attached to this frame, lazily initialized.
GeolocationDispatcher* geolocation_dispatcher_;
- // Dispatches permission requests for the Push API. Lazily initialized.
- PushPermissionDispatcher* push_permission_dispatcher_;
-
// The push messaging dispatcher attached to this frame, lazily initialized.
- // TODO(mvanouwerkerk): Route this functionality through Platform.
PushMessagingDispatcher* push_messaging_dispatcher_;
+ // The presentation dispatcher implementation attached to this frame, lazily
+ // initialized.
+ PresentationDispatcher* presentation_dispatcher_;
+
ServiceRegistryImpl service_registry_;
// The screen orientation dispatcher attached to the frame, lazily
@@ -806,6 +979,10 @@ class CONTENT_EXPORT RenderFrameImpl
// AccessibilityModeOff.
RendererAccessibility* renderer_accessibility_;
+ scoped_ptr<PermissionDispatcher> permission_client_;
+
+ scoped_ptr<blink::WebAppBannerClient> app_banner_client_;
+
#if defined(OS_MACOSX) || defined(OS_ANDROID)
// The external popup for the currently showing select popup.
scoped_ptr<ExternalPopupMenu> external_popup_menu_;
diff --git a/chromium/content/renderer/render_frame_impl_browsertest.cc b/chromium/content/renderer/render_frame_impl_browsertest.cc
new file mode 100644
index 00000000000..9c0e3b20981
--- /dev/null
+++ b/chromium/content/renderer/render_frame_impl_browsertest.cc
@@ -0,0 +1,150 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/command_line.h"
+#include "content/common/frame_messages.h"
+#include "content/common/view_messages.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/test/frame_load_waiter.h"
+#include "content/public/test/render_view_test.h"
+#include "content/renderer/render_frame_impl.h"
+#include "content/renderer/render_view_impl.h"
+#include "content/test/fake_compositor_dependencies.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/WebURLRequest.h"
+#include "third_party/WebKit/public/web/WebLocalFrame.h"
+
+namespace {
+const int32 kSubframeRouteId = 20;
+const int32 kSubframeWidgetRouteId = 21;
+const int32 kFrameProxyRouteId = 22;
+const int32 kSubframeSurfaceId = 43;
+} // namespace
+
+namespace content {
+
+// RenderFrameImplTest creates a RenderFrameImpl that is a child of the
+// main frame, and has its own RenderWidget. This behaves like an out
+// of process frame even though it is in the same process as its parent.
+class RenderFrameImplTest : public RenderViewTest {
+ public:
+ ~RenderFrameImplTest() override {}
+
+ void SetUp() override {
+ RenderViewTest::SetUp();
+ EXPECT_FALSE(static_cast<RenderFrameImpl*>(view_->GetMainRenderFrame())
+ ->is_subframe_);
+
+ FrameMsg_NewFrame_WidgetParams widget_params;
+ widget_params.routing_id = kSubframeWidgetRouteId;
+ widget_params.surface_id = kSubframeSurfaceId;
+ widget_params.hidden = false;
+
+ compositor_deps_.reset(new FakeCompositorDependencies);
+
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kSitePerProcess);
+
+ LoadHTML("Parent frame <iframe name='frame'></iframe>");
+
+ RenderFrameImpl::FromWebFrame(
+ view_->GetMainRenderFrame()->GetWebFrame()->firstChild())
+ ->OnSwapOut(kFrameProxyRouteId, false, FrameReplicationState());
+
+ RenderFrameImpl::CreateFrame(kSubframeRouteId, kFrameProxyRouteId,
+ MSG_ROUTING_NONE, MSG_ROUTING_NONE,
+ FrameReplicationState(),
+ compositor_deps_.get(), widget_params);
+
+ frame_ = RenderFrameImpl::FromRoutingID(kSubframeRouteId);
+ EXPECT_TRUE(frame_->is_subframe_);
+ }
+
+ // Loads the given HTML into the frame as a data: URL and blocks until
+ // the navigation is committed.
+ void LoadHTMLInFrame(const char* html) {
+ std::string url_str = "data:text/html;charset=utf-8,";
+ url_str.append(html);
+ GURL url(url_str);
+ frame_->GetWebFrame()->loadRequest(blink::WebURLRequest(url));
+ // The load actually happens asynchronously, so we pump messages to process
+ // the pending continuation.
+ FrameLoadWaiter(frame_).Wait();
+ }
+
+ RenderFrameImpl* frame() { return frame_; }
+
+ content::RenderWidget* FrameWidget() { return frame_->render_widget_.get(); }
+
+ private:
+ RenderFrameImpl* frame_;
+ scoped_ptr<CompositorDependencies> compositor_deps_;
+};
+
+class RenderFrameTestObserver : public RenderFrameObserver {
+ public:
+ RenderFrameTestObserver(RenderFrame* render_frame)
+ : RenderFrameObserver(render_frame), visible_(false) {}
+
+ ~RenderFrameTestObserver() override {}
+
+ void WasShown() override { visible_ = true; }
+ void WasHidden() override { visible_ = false; }
+
+ bool visible() { return visible_; }
+
+ private:
+ bool visible_;
+};
+
+#if defined(OS_ANDROID)
+// See https://crbug.com/472717
+#define MAYBE_SubframeWidget DISABLED_SubframeWidget
+#define MAYBE_FrameResize DISABLED_FrameResize
+#define MAYBE_FrameWasShown DISABLED_FrameWasShown
+#else
+#define MAYBE_SubframeWidget SubframeWidget
+#define MAYBE_FrameResize FrameResize
+#define MAYBE_FrameWasShown FrameWasShown
+#endif
+
+// Verify that a frame with a RenderFrameProxy as a parent has its own
+// RenderWidget.
+TEST_F(RenderFrameImplTest, MAYBE_SubframeWidget) {
+ EXPECT_TRUE(FrameWidget());
+ EXPECT_NE(FrameWidget(), (content::RenderWidget*)view_);
+}
+
+// Verify a subframe RenderWidget properly processes its viewport being
+// resized.
+TEST_F(RenderFrameImplTest, MAYBE_FrameResize) {
+ ViewMsg_Resize_Params resize_params;
+ gfx::Size size(200, 200);
+ resize_params.screen_info = blink::WebScreenInfo();
+ resize_params.new_size = size;
+ resize_params.physical_backing_size = size;
+ resize_params.top_controls_height = 0.f;
+ resize_params.top_controls_shrink_blink_size = false;
+ resize_params.resizer_rect = gfx::Rect();
+ resize_params.is_fullscreen_granted = false;
+
+ scoped_ptr<IPC::Message> resize_message(new ViewMsg_Resize(0, resize_params));
+ FrameWidget()->OnMessageReceived(*resize_message);
+
+ EXPECT_EQ(FrameWidget()->webwidget()->size(), blink::WebSize(size));
+}
+
+// Verify a subframe RenderWidget properly processes a WasShown message.
+TEST_F(RenderFrameImplTest, MAYBE_FrameWasShown) {
+ RenderFrameTestObserver observer(frame());
+
+ scoped_ptr<IPC::Message> was_shown_message(
+ new ViewMsg_WasShown(0, true, ui::LatencyInfo()));
+ FrameWidget()->OnMessageReceived(*was_shown_message);
+
+ EXPECT_FALSE(FrameWidget()->is_hidden());
+ EXPECT_TRUE(observer.visible());
+}
+
+} // namespace
diff --git a/chromium/content/renderer/render_frame_proxy.cc b/chromium/content/renderer/render_frame_proxy.cc
index 6b8c760fe24..eaaa2abeaa5 100644
--- a/chromium/content/renderer/render_frame_proxy.cc
+++ b/chromium/content/renderer/render_frame_proxy.cc
@@ -9,12 +9,14 @@
#include "base/lazy_instance.h"
#include "content/child/webmessageportchannel_impl.h"
#include "content/common/frame_messages.h"
+#include "content/common/frame_replication_state.h"
#include "content/common/swapped_out_messages.h"
#include "content/common/view_messages.h"
#include "content/renderer/child_frame_compositing_helper.h"
#include "content/renderer/render_frame_impl.h"
#include "content/renderer/render_thread_impl.h"
#include "content/renderer/render_view_impl.h"
+#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
#include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
#include "third_party/WebKit/public/web/WebView.h"
@@ -54,7 +56,8 @@ RenderFrameProxy* RenderFrameProxy::CreateProxyToReplaceFrame(
RenderFrameProxy* RenderFrameProxy::CreateFrameProxy(
int routing_id,
int parent_routing_id,
- int render_view_routing_id) {
+ int render_view_routing_id,
+ const FrameReplicationState& replicated_state) {
scoped_ptr<RenderFrameProxy> proxy(
new RenderFrameProxy(routing_id, MSG_ROUTING_NONE));
RenderViewImpl* render_view = NULL;
@@ -70,12 +73,20 @@ RenderFrameProxy* RenderFrameProxy::CreateFrameProxy(
// should not wind up here.
RenderFrameProxy* parent =
RenderFrameProxy::FromRoutingID(parent_routing_id);
- web_frame = parent->web_frame()->createRemoteChild("", proxy.get());
+ web_frame = parent->web_frame()->createRemoteChild(
+ blink::WebString::fromUTF8(replicated_state.name),
+ RenderFrameImpl::ContentToWebSandboxFlags(
+ replicated_state.sandbox_flags),
+ proxy.get());
render_view = parent->render_view();
}
proxy->Init(web_frame, render_view);
+ // Initialize proxy's WebRemoteFrame with the security origin and other
+ // replicated information.
+ proxy->SetReplicatedState(replicated_state);
+
return proxy.release();
}
@@ -109,13 +120,18 @@ RenderFrameProxy::RenderFrameProxy(int routing_id, int frame_routing_id)
}
RenderFrameProxy::~RenderFrameProxy() {
- render_view()->UnregisterRenderFrameProxy(this);
+ // TODO(nasko): Set the render_frame_proxy to null to avoid a double deletion
+ // when detaching the main frame. This can be removed once RenderFrameImpl and
+ // RenderFrameProxy have been completely decoupled. See
+ // https://crbug.com/357747.
+ RenderFrameImpl* render_frame =
+ RenderFrameImpl::FromRoutingID(frame_routing_id_);
+ if (render_frame)
+ render_frame->set_render_frame_proxy(nullptr);
- FrameMap::iterator it = g_frame_map.Get().find(web_frame_);
- CHECK(it != g_frame_map.Get().end());
- CHECK_EQ(it->second, this);
- g_frame_map.Get().erase(it);
+ render_view()->UnregisterRenderFrameProxy(this);
+ CHECK(!web_frame_);
RenderThread::Get()->RemoveRoute(routing_id_);
g_routing_id_proxy_map.Get().erase(routing_id_);
}
@@ -136,11 +152,48 @@ void RenderFrameProxy::Init(blink::WebRemoteFrame* web_frame,
CHECK(result.second) << "Inserted a duplicate item.";
}
+bool RenderFrameProxy::IsMainFrameDetachedFromTree() const {
+ return web_frame_->top() == web_frame_ &&
+ render_view_->webview()->mainFrame()->isWebLocalFrame();
+}
+
void RenderFrameProxy::DidCommitCompositorFrame() {
if (compositing_helper_.get())
compositing_helper_->DidCommitCompositorFrame();
}
+void RenderFrameProxy::SetReplicatedState(const FrameReplicationState& state) {
+ DCHECK(web_frame_);
+ web_frame_->setReplicatedOrigin(blink::WebSecurityOrigin::createFromString(
+ blink::WebString::fromUTF8(state.origin.string())));
+ web_frame_->setReplicatedSandboxFlags(
+ RenderFrameImpl::ContentToWebSandboxFlags(state.sandbox_flags));
+ web_frame_->setReplicatedName(blink::WebString::fromUTF8(state.name));
+}
+
+// Update the proxy's SecurityContext and FrameOwner with new sandbox flags
+// that were set by its parent in another process.
+//
+// Normally, when a frame's sandbox attribute is changed dynamically, the
+// frame's FrameOwner is updated with the new sandbox flags right away, while
+// the frame's SecurityContext is updated when the frame is navigated and the
+// new sandbox flags take effect.
+//
+// Currently, there is no use case for a proxy's pending FrameOwner sandbox
+// flags, so there's no message sent to proxies when the sandbox attribute is
+// first updated. Instead, the update message is sent and this function is
+// called when the new flags take effect, so that the proxy updates its
+// SecurityContext. This is needed to ensure that sandbox flags are inherited
+// properly if this proxy ever parents a local frame. The proxy's FrameOwner
+// flags are also updated here with the caveat that the FrameOwner won't learn
+// about updates to its flags until they take effect.
+void RenderFrameProxy::OnDidUpdateSandboxFlags(SandboxFlags flags) {
+ web_frame_->setReplicatedSandboxFlags(
+ RenderFrameImpl::ContentToWebSandboxFlags(flags));
+ web_frame_->setFrameOwnerSandboxFlags(
+ RenderFrameImpl::ContentToWebSandboxFlags(flags));
+}
+
bool RenderFrameProxy::OnMessageReceived(const IPC::Message& msg) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(RenderFrameProxy, msg)
@@ -149,24 +202,20 @@ bool RenderFrameProxy::OnMessageReceived(const IPC::Message& msg) {
IPC_MESSAGE_HANDLER_GENERIC(FrameMsg_CompositorFrameSwapped,
OnCompositorFrameSwapped(msg))
IPC_MESSAGE_HANDLER(FrameMsg_DisownOpener, OnDisownOpener)
+ IPC_MESSAGE_HANDLER(FrameMsg_DidStartLoading, OnDidStartLoading)
+ IPC_MESSAGE_HANDLER(FrameMsg_DidStopLoading, OnDidStopLoading)
+ IPC_MESSAGE_HANDLER(FrameMsg_DidUpdateSandboxFlags, OnDidUpdateSandboxFlags)
+ IPC_MESSAGE_HANDLER(FrameMsg_DispatchLoad, OnDispatchLoad)
+ IPC_MESSAGE_HANDLER(FrameMsg_DidUpdateName, OnDidUpdateName)
+ IPC_MESSAGE_HANDLER(FrameMsg_DidUpdateOrigin, OnDidUpdateOrigin)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
- // If |handled| is true, |this| may have been deleted.
- if (handled)
- return true;
-
- RenderFrameImpl* render_frame =
- RenderFrameImpl::FromRoutingID(frame_routing_id_);
- return render_frame && render_frame->OnMessageReceived(msg);
+ // Note: If |handled| is true, |this| may have been deleted.
+ return handled;
}
bool RenderFrameProxy::Send(IPC::Message* message) {
- if (!SwappedOutMessages::CanSendWhileSwappedOut(message)) {
- delete message;
- return false;
- }
- message->set_routing_id(routing_id_);
return RenderThread::Get()->Send(message);
}
@@ -181,23 +230,31 @@ void RenderFrameProxy::OnChildFrameProcessGone() {
}
void RenderFrameProxy::OnCompositorFrameSwapped(const IPC::Message& message) {
+ // If this WebFrame has already been detached, its parent will be null. This
+ // can happen when swapping a WebRemoteFrame with a WebLocalFrame, where this
+ // message may arrive after the frame was removed from the frame tree, but
+ // before the frame has been destroyed. http://crbug.com/446575.
+ if (!web_frame()->parent())
+ return;
+
FrameMsg_CompositorFrameSwapped::Param param;
if (!FrameMsg_CompositorFrameSwapped::Read(&message, &param))
return;
scoped_ptr<cc::CompositorFrame> frame(new cc::CompositorFrame);
- param.a.frame.AssignTo(frame.get());
+ get<0>(param).frame.AssignTo(frame.get());
if (!compositing_helper_.get()) {
compositing_helper_ =
ChildFrameCompositingHelper::CreateForRenderFrameProxy(this);
compositing_helper_->EnableCompositing(true);
}
- compositing_helper_->OnCompositorFrameSwapped(frame.Pass(),
- param.a.producing_route_id,
- param.a.output_surface_id,
- param.a.producing_host_id,
- param.a.shared_memory_handle);
+ compositing_helper_->OnCompositorFrameSwapped(
+ frame.Pass(),
+ get<0>(param).producing_route_id,
+ get<0>(param).output_surface_id,
+ get<0>(param).producing_host_id,
+ get<0>(param).shared_memory_handle);
}
void RenderFrameProxy::OnDisownOpener() {
@@ -221,11 +278,53 @@ void RenderFrameProxy::OnDisownOpener() {
web_frame_->setOpener(NULL);
}
+void RenderFrameProxy::OnDidStartLoading() {
+ if (IsMainFrameDetachedFromTree())
+ return;
+
+ web_frame_->didStartLoading();
+}
+
+void RenderFrameProxy::OnDidStopLoading() {
+ if (IsMainFrameDetachedFromTree())
+ return;
+
+ web_frame_->didStopLoading();
+}
+
+void RenderFrameProxy::OnDispatchLoad() {
+ web_frame_->DispatchLoadEventForFrameOwner();
+}
+
+void RenderFrameProxy::OnDidUpdateName(const std::string& name) {
+ web_frame_->setReplicatedName(blink::WebString::fromUTF8(name));
+}
+
+void RenderFrameProxy::OnDidUpdateOrigin(const url::Origin& origin) {
+ web_frame_->setReplicatedOrigin(blink::WebSecurityOrigin::createFromString(
+ blink::WebString::fromUTF8(origin.string())));
+}
+
void RenderFrameProxy::frameDetached() {
- if (web_frame_->parent())
+ if (web_frame_->parent()) {
web_frame_->parent()->removeChild(web_frame_);
+ // Let the browser process know this subframe is removed, so that it is
+ // destroyed in its current process.
+ Send(new FrameHostMsg_Detach(routing_id_));
+ }
+
web_frame_->close();
+
+ // Remove the entry in the WebFrame->RenderFrameProxy map, as the |web_frame_|
+ // is no longer valid.
+ FrameMap::iterator it = g_frame_map.Get().find(web_frame_);
+ CHECK(it != g_frame_map.Get().end());
+ CHECK_EQ(it->second, this);
+ g_frame_map.Get().erase(it);
+
+ web_frame_ = nullptr;
+
delete this;
}
@@ -236,39 +335,29 @@ void RenderFrameProxy::postMessageEvent(
blink::WebDOMMessageEvent event) {
DCHECK(!web_frame_ || web_frame_ == target_frame);
- ViewMsg_PostMessage_Params params;
+ FrameMsg_PostMessage_Params params;
params.is_data_raw_string = false;
params.data = event.data().toString();
params.source_origin = event.origin();
if (!target_origin.isNull())
params.target_origin = target_origin.toString();
- blink::WebMessagePortChannelArray channels = event.releaseChannels();
- if (!channels.isEmpty()) {
- std::vector<int> message_port_ids(channels.size());
- // Extract the port IDs from the channel array.
- for (size_t i = 0; i < channels.size(); ++i) {
- WebMessagePortChannelImpl* webchannel =
- static_cast<WebMessagePortChannelImpl*>(channels[i]);
- message_port_ids[i] = webchannel->message_port_id();
- webchannel->QueueMessages();
- DCHECK_NE(message_port_ids[i], MSG_ROUTING_NONE);
- }
- params.message_port_ids = message_port_ids;
- }
+ params.message_ports =
+ WebMessagePortChannelImpl::ExtractMessagePortIDs(event.releaseChannels());
// Include the routing ID for the source frame (if one exists), which the
// browser process will translate into the routing ID for the equivalent
// frame in the target process.
params.source_routing_id = MSG_ROUTING_NONE;
if (source_frame) {
- RenderViewImpl* source_view =
- RenderViewImpl::FromWebView(source_frame->view());
- if (source_view)
- params.source_routing_id = source_view->routing_id();
+ RenderFrameImpl* source_render_frame =
+ RenderFrameImpl::FromWebFrame(source_frame);
+ if (source_render_frame)
+ params.source_routing_id = source_render_frame->GetRoutingID();
}
+ params.source_view_routing_id = MSG_ROUTING_NONE;
- Send(new ViewHostMsg_RouteMessageEvent(render_view_->GetRoutingID(), params));
+ Send(new FrameHostMsg_RouteMessageEvent(routing_id_, params));
}
void RenderFrameProxy::initializeChildFrame(
diff --git a/chromium/content/renderer/render_frame_proxy.h b/chromium/content/renderer/render_frame_proxy.h
index 2afd45383e3..fba8c9afef4 100644
--- a/chromium/content/renderer/render_frame_proxy.h
+++ b/chromium/content/renderer/render_frame_proxy.h
@@ -10,9 +10,9 @@
#include "content/common/content_export.h"
#include "ipc/ipc_listener.h"
#include "ipc/ipc_sender.h"
-
#include "third_party/WebKit/public/web/WebRemoteFrame.h"
#include "third_party/WebKit/public/web/WebRemoteFrameClient.h"
+#include "url/origin.h"
struct FrameMsg_BuffersSwapped_Params;
struct FrameMsg_CompositorFrameSwapped_Params;
@@ -26,6 +26,8 @@ namespace content {
class ChildFrameCompositingHelper;
class RenderFrameImpl;
class RenderViewImpl;
+enum class SandboxFlags;
+struct FrameReplicationState;
// When a page's frames are rendered by multiple processes, each renderer has a
// full copy of the frame tree. It has full RenderFrames for the frames it is
@@ -74,9 +76,11 @@ class CONTENT_EXPORT RenderFrameProxy
// |parent_routing_id| always identifies a RenderFrameProxy (never a
// RenderFrame) because a new child of a local frame should always start out
// as a frame, not a proxy.
- static RenderFrameProxy* CreateFrameProxy(int routing_id,
- int parent_routing_id,
- int render_view_routing_id);
+ static RenderFrameProxy* CreateFrameProxy(
+ int routing_id,
+ int parent_routing_id,
+ int render_view_routing_id,
+ const FrameReplicationState& replicated_state);
// Returns the RenderFrameProxy for the given routing ID.
static RenderFrameProxy* FromRoutingID(int routing_id);
@@ -93,6 +97,16 @@ class CONTENT_EXPORT RenderFrameProxy
// when a compositor frame has committed.
void DidCommitCompositorFrame();
+ // Pass replicated information, such as security origin, to this
+ // RenderFrameProxy's WebRemoteFrame.
+ void SetReplicatedState(const FrameReplicationState& state);
+
+ // Navigating a top-level frame cross-process does not swap the WebLocalFrame
+ // for a WebRemoteFrame in the frame tree. In this case, this WebRemoteFrame
+ // is not attached to the frame tree and there is no blink::Frame associated
+ // with it, so it is not in state where most operations on it will succeed.
+ bool IsMainFrameDetachedFromTree() const;
+
int routing_id() { return routing_id_; }
RenderViewImpl* render_view() { return render_view_; }
blink::WebRemoteFrame* web_frame() { return web_frame_; }
@@ -111,6 +125,9 @@ class CONTENT_EXPORT RenderFrameProxy
bool should_replace_current_entry);
virtual void forwardInputEvent(const blink::WebInputEvent* event);
+ // IPC handlers
+ void OnDidStartLoading();
+
private:
RenderFrameProxy(int routing_id, int frame_routing_id);
@@ -124,6 +141,11 @@ class CONTENT_EXPORT RenderFrameProxy
void OnChildFrameProcessGone();
void OnCompositorFrameSwapped(const IPC::Message& message);
void OnDisownOpener();
+ void OnDidStopLoading();
+ void OnDidUpdateSandboxFlags(SandboxFlags flags);
+ void OnDispatchLoad();
+ void OnDidUpdateName(const std::string& name);
+ void OnDidUpdateOrigin(const url::Origin& origin);
// The routing ID by which this RenderFrameProxy is known.
const int routing_id_;
diff --git a/chromium/content/renderer/render_process_impl.cc b/chromium/content/renderer/render_process_impl.cc
index 421e60bcf96..1f4dc4a35e0 100644
--- a/chromium/content/renderer/render_process_impl.cc
+++ b/chromium/content/renderer/render_process_impl.cc
@@ -49,7 +49,8 @@ RenderProcessImpl::RenderProcessImpl()
static_cast<int>(optimize_flag.size()));
}
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
if (command_line.HasSwitch(switches::kJavaScriptFlags)) {
std::string flags(
command_line.GetSwitchValueASCII(switches::kJavaScriptFlags));
diff --git a/chromium/content/renderer/render_thread_impl.cc b/chromium/content/renderer/render_thread_impl.cc
index 6984b137743..5ade8f03cf2 100644
--- a/chromium/content/renderer/render_thread_impl.cc
+++ b/chromium/content/renderer/render_thread_impl.cc
@@ -11,34 +11,36 @@
#include "base/allocator/allocator_extension.h"
#include "base/command_line.h"
-#include "base/debug/trace_event.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
-#include "base/memory/discardable_memory.h"
-#include "base/memory/discardable_memory_emulated.h"
-#include "base/memory/discardable_memory_shmem_allocator.h"
+#include "base/memory/discardable_memory_allocator.h"
#include "base/memory/shared_memory.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
-#include "base/metrics/stats_table.h"
#include "base/path_service.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_tokenizer.h"
+#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/threading/simple_thread.h"
#include "base/threading/thread_local.h"
#include "base/threading/thread_restrictions.h"
+#include "base/trace_event/trace_event.h"
#include "base/values.h"
#include "cc/base/switches.h"
#include "cc/blink/web_external_bitmap_impl.h"
#include "cc/blink/web_layer_impl.h"
-#include "cc/resources/raster_worker_pool.h"
+#include "cc/raster/task_graph_runner.h"
+#include "components/scheduler/renderer/renderer_scheduler.h"
#include "content/child/appcache/appcache_dispatcher.h"
#include "content/child/appcache/appcache_frontend_impl.h"
#include "content/child/child_discardable_shared_memory_manager.h"
#include "content/child/child_gpu_memory_buffer_manager.h"
#include "content/child/child_histogram_message_filter.h"
+#include "content/child/child_resource_message_filter.h"
+#include "content/child/child_shared_bitmap_manager.h"
#include "content/child/content_child_helpers.h"
#include "content/child/db_message_filter.h"
#include "content/child/indexed_db/indexed_db_dispatcher.h"
@@ -46,6 +48,7 @@
#include "content/child/npapi/npobject_util.h"
#include "content/child/plugin_messages.h"
#include "content/child/resource_dispatcher.h"
+#include "content/child/resource_scheduling_filter.h"
#include "content/child/runtime_features.h"
#include "content/child/thread_safe_sender.h"
#include "content/child/web_database_observer_impl.h"
@@ -66,24 +69,33 @@
#include "content/public/common/content_constants.h"
#include "content/public/common/content_paths.h"
#include "content/public/common/content_switches.h"
+#include "content/public/common/mojo_channel_switches.h"
#include "content/public/common/renderer_preferences.h"
#include "content/public/common/url_constants.h"
#include "content/public/renderer/content_renderer_client.h"
#include "content/public/renderer/render_process_observer.h"
#include "content/public/renderer/render_view_visitor.h"
+#include "content/renderer/browser_plugin/browser_plugin_manager.h"
+#include "content/renderer/cache_storage/cache_storage_dispatcher.h"
+#include "content/renderer/cache_storage/cache_storage_message_filter.h"
#include "content/renderer/devtools/devtools_agent_filter.h"
+#include "content/renderer/devtools/v8_sampling_profiler.h"
#include "content/renderer/dom_storage/dom_storage_dispatcher.h"
#include "content/renderer/dom_storage/webstoragearea_impl.h"
#include "content/renderer/dom_storage/webstoragenamespace_impl.h"
+#include "content/renderer/gpu/compositor_external_begin_frame_source.h"
+#include "content/renderer/gpu/compositor_forwarding_message_filter.h"
#include "content/renderer/gpu/compositor_output_surface.h"
#include "content/renderer/input/input_event_filter.h"
#include "content/renderer/input/input_handler_manager.h"
+#include "content/renderer/input/main_thread_input_event_filter.h"
#include "content/renderer/media/aec_dump_message_filter.h"
#include "content/renderer/media/audio_input_message_filter.h"
#include "content/renderer/media/audio_message_filter.h"
#include "content/renderer/media/audio_renderer_mixer_manager.h"
#include "content/renderer/media/media_stream_center.h"
#include "content/renderer/media/midi_message_filter.h"
+#include "content/renderer/media/render_media_client.h"
#include "content/renderer/media/renderer_gpu_video_accelerator_factories.h"
#include "content/renderer/media/video_capture_impl_manager.h"
#include "content/renderer/media/video_capture_message_filter.h"
@@ -93,23 +105,26 @@
#include "content/renderer/render_process_impl.h"
#include "content/renderer/render_view_impl.h"
#include "content/renderer/renderer_blink_platform_impl.h"
-#include "content/renderer/scheduler/renderer_scheduler.h"
+#include "content/renderer/scheduler/resource_dispatch_throttler.h"
#include "content/renderer/service_worker/embedded_worker_context_message_filter.h"
#include "content/renderer/service_worker/embedded_worker_dispatcher.h"
#include "content/renderer/shared_worker/embedded_shared_worker_stub.h"
+#include "gin/public/debug.h"
+#include "gpu/GLES2/gl2extchromium.h"
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
#include "ipc/ipc_channel_handle.h"
-#include "ipc/ipc_forwarding_message_filter.h"
#include "ipc/ipc_platform_file.h"
#include "ipc/mojo/ipc_channel_mojo.h"
#include "media/base/audio_hardware_config.h"
#include "media/base/media.h"
-#include "media/filters/gpu_video_accelerator_factories.h"
+#include "media/renderers/gpu_video_accelerator_factories.h"
#include "mojo/common/common_type_converters.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
#include "skia/ext/event_tracer_impl.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/platform/WebThread.h"
+#include "third_party/WebKit/public/web/WebCache.h"
#include "third_party/WebKit/public/web/WebColorName.h"
#include "third_party/WebKit/public/web/WebDatabase.h"
#include "third_party/WebKit/public/web/WebDocument.h"
@@ -122,6 +137,7 @@
#include "third_party/WebKit/public/web/WebScriptController.h"
#include "third_party/WebKit/public/web/WebSecurityPolicy.h"
#include "third_party/WebKit/public/web/WebView.h"
+#include "third_party/icu/source/i18n/unicode/timezone.h"
#include "third_party/skia/include/core/SkGraphics.h"
#include "ui/base/layout.h"
#include "ui/base/ui_base_switches.h"
@@ -134,6 +150,7 @@
#endif
#if defined(OS_MACOSX)
+#include "base/mac/mac_util.h"
#include "content/renderer/webscrollbarbehavior_impl_mac.h"
#endif
@@ -160,6 +177,10 @@
#include "content/renderer/media/webrtc_identity_service.h"
#endif
+#ifdef ENABLE_VTUNE_JIT_INTERFACE
+#include "v8/src/third_party/vtune/v8-vtune.h"
+#endif
+
using base::ThreadRestrictions;
using blink::WebDocument;
using blink::WebFrame;
@@ -177,15 +198,22 @@ namespace {
const int64 kInitialIdleHandlerDelayMs = 1000;
const int64 kLongIdleHandlerDelayMs = 30*1000;
+#if defined(OS_ANDROID)
+// On Android, resource messages can each take ~1.5ms to dispatch on the browser
+// IO thread. Limiting the message rate to 3/frame at 60hz ensures that the
+// induced work takes but a fraction (~1/4) of the overall frame budget.
+const int kMaxResourceRequestsPerFlushWhenThrottled = 3;
+#else
+const int kMaxResourceRequestsPerFlushWhenThrottled = 8;
+#endif
+const double kThrottledResourceRequestFlushPeriodS = 1. / 60.;
+
// Maximum allocation size allowed for image scaling filters that
// require pre-scaling. Skia will fallback to a filter that doesn't
// require pre-scaling if the default filter would require an
// allocation that exceeds this limit.
const size_t kImageCacheSingleAllocationByteLimit = 64 * 1024 * 1024;
-const size_t kEmulatedDiscardableMemoryBytesToKeepWhenWidgetsHidden =
- 4 * 1024 * 1024;
-
// Keep the global RenderThreadImpl in a TLS slot so it is impossible to access
// incorrectly from the wrong thread.
base::LazyInstance<base::ThreadLocalPointer<RenderThreadImpl> >
@@ -202,6 +230,13 @@ class RenderViewZoomer : public RenderViewVisitor {
bool Visit(RenderView* render_view) override {
WebView* webview = render_view->GetWebView();
+ // Remote frames don't host documents.
+ // TODO(wjmaclean) Although it seems likely that a frame without a
+ // document can safely early-out here, we should confirm this is truly
+ // the case. https://crbug.com/477007
+ if (webview->mainFrame()->isWebRemoteFrame())
+ return true;
+
WebDocument document = webview->mainFrame()->document();
// Don't set zoom level for full-page plugin since they don't use the same
@@ -228,6 +263,22 @@ class RenderViewZoomer : public RenderViewVisitor {
DISALLOW_COPY_AND_ASSIGN(RenderViewZoomer);
};
+class CompositorRasterThread : public base::SimpleThread {
+ public:
+ CompositorRasterThread(cc::TaskGraphRunner* task_graph_runner,
+ const std::string& name_prefix)
+ : base::SimpleThread(name_prefix),
+ task_graph_runner_(task_graph_runner) {}
+
+ // Overridden from base::SimpleThread:
+ void Run() override { task_graph_runner_->Run(); }
+
+ private:
+ cc::TaskGraphRunner* task_graph_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(CompositorRasterThread);
+};
+
std::string HostToCustomHistogramSuffix(const std::string& host) {
if (host == "mail.google.com")
return ".gmail";
@@ -261,8 +312,10 @@ void AddHistogramSample(void* hist, int sample) {
histogram->Add(sample);
}
-scoped_ptr<base::SharedMemory> AllocateSharedMemoryFunction(size_t size) {
- return RenderThreadImpl::Get()->HostAllocateSharedMemoryBuffer(size);
+scoped_ptr<cc::SharedBitmap> AllocateSharedBitmapFunction(
+ const gfx::Size& size) {
+ return ChildThreadImpl::current()->shared_bitmap_manager()->
+ AllocateSharedBitmap(size);
}
void EnableBlinkPlatformLogChannels(const std::string& channels) {
@@ -280,15 +333,24 @@ void NotifyTimezoneChangeOnThisThread() {
v8::Date::DateTimeConfigurationChangeNotification(isolate);
}
+void LowMemoryNotificationOnThisThread() {
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ if (!isolate)
+ return;
+ isolate->LowMemoryNotification();
+}
+
class RenderFrameSetupImpl : public mojo::InterfaceImpl<RenderFrameSetup> {
public:
RenderFrameSetupImpl()
: routing_id_highmark_(-1) {
}
- void GetServiceProviderForFrame(
+ void ExchangeServiceProviders(
int32_t frame_routing_id,
- mojo::InterfaceRequest<mojo::ServiceProvider> request) override {
+ mojo::InterfaceRequest<mojo::ServiceProvider> services,
+ mojo::ServiceProviderPtr exposed_services)
+ override {
// TODO(morrita): This is for investigating http://crbug.com/415059 and
// should be removed once it is fixed.
CHECK_LT(routing_id_highmark_, frame_routing_id);
@@ -300,11 +362,11 @@ class RenderFrameSetupImpl : public mojo::InterfaceImpl<RenderFrameSetup> {
// triggers creation of the RenderFrame we want.
if (!frame) {
RenderThreadImpl::current()->RegisterPendingRenderFrameConnect(
- frame_routing_id, request.PassMessagePipe());
+ frame_routing_id, services.Pass(), exposed_services.Pass());
return;
}
- frame->BindServiceRegistry(request.PassMessagePipe());
+ frame->BindServiceRegistry(services.Pass(), exposed_services.Pass());
}
private:
@@ -315,12 +377,6 @@ void CreateRenderFrameSetup(mojo::InterfaceRequest<RenderFrameSetup> request) {
mojo::BindToRequest(new RenderFrameSetupImpl(), &request);
}
-bool ShouldUseMojoChannel() {
- return CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableRendererMojoChannel) ||
- IPC::ChannelMojo::ShouldBeUsed();
-}
-
blink::WebGraphicsContext3D::Attributes GetOffscreenAttribs() {
blink::WebGraphicsContext3D::Attributes attributes;
attributes.shareResources = true;
@@ -359,8 +415,8 @@ RenderThreadImpl::HistogramCustomizer::~HistogramCustomizer() {}
void RenderThreadImpl::HistogramCustomizer::RenderViewNavigatedToHost(
const std::string& host, size_t view_count) {
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableHistogramCustomizer)) {
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableHistogramCustomizer)) {
return;
}
// Check if all RenderViews are displaying a page from the same host. If there
@@ -396,22 +452,29 @@ RenderThreadImpl* RenderThreadImpl::current() {
return lazy_tls.Pointer()->Get();
}
-// When we run plugins in process, we actually run them on the render thread,
-// which means that we need to make the render thread pump UI events.
-RenderThreadImpl::RenderThreadImpl()
- : ChildThread(Options(ShouldUseMojoChannel())) {
+RenderThreadImpl::RenderThreadImpl(const InProcessChildThreadParams& params)
+ : ChildThreadImpl(Options::Builder()
+ .InBrowserProcess(params)
+ .UseMojoChannel(ShouldUseMojoChannel())
+ .Build()) {
Init();
}
-RenderThreadImpl::RenderThreadImpl(const std::string& channel_name)
- : ChildThread(Options(channel_name, ShouldUseMojoChannel())) {
+// When we run plugins in process, we actually run them on the render thread,
+// which means that we need to make the render thread pump UI events.
+RenderThreadImpl::RenderThreadImpl(
+ scoped_ptr<base::MessageLoop> main_message_loop)
+ : ChildThreadImpl(Options::Builder()
+ .UseMojoChannel(ShouldUseMojoChannel())
+ .Build()),
+ main_message_loop_(main_message_loop.Pass()) {
Init();
}
void RenderThreadImpl::Init() {
TRACE_EVENT_BEGIN_ETW("RenderThreadImpl::Init", 0, "");
- base::debug::TraceLog::GetInstance()->SetThreadSortIndex(
+ base::trace_event::TraceLog::GetInstance()->SetThreadSortIndex(
base::PlatformThread::CurrentId(),
kTraceEventRendererMainThreadSortIndex);
@@ -426,7 +489,6 @@ void RenderThreadImpl::Init() {
ChildProcess::current()->set_main_thread(this);
// In single process the single process is all there is.
- suspend_webkit_shared_timer_ = true;
notify_webkit_of_modal_loop_ = true;
webkit_shared_timer_suspended_ = false;
widget_count_ = 0;
@@ -440,9 +502,20 @@ void RenderThreadImpl::Init() {
dom_storage_dispatcher_.reset(new DomStorageDispatcher());
main_thread_indexed_db_dispatcher_.reset(new IndexedDBDispatcher(
thread_safe_sender()));
- renderer_scheduler_ = RendererScheduler::Create();
+ renderer_scheduler_ = scheduler::RendererScheduler::Create();
+ channel()->SetListenerTaskRunner(renderer_scheduler_->DefaultTaskRunner());
+ main_thread_cache_storage_dispatcher_.reset(
+ new CacheStorageDispatcher(thread_safe_sender()));
embedded_worker_dispatcher_.reset(new EmbeddedWorkerDispatcher());
+ // Note: This may reorder messages from the ResourceDispatcher with respect to
+ // other subsystems.
+ resource_dispatch_throttler_.reset(new ResourceDispatchThrottler(
+ static_cast<RenderThread*>(this), renderer_scheduler_.get(),
+ base::TimeDelta::FromSecondsD(kThrottledResourceRequestFlushPeriodS),
+ kMaxResourceRequestsPerFlushWhenThrottled));
+ resource_dispatcher()->set_message_sender(resource_dispatch_throttler_.get());
+
media_stream_center_ = NULL;
db_message_filter_ = new DBMessageFilter();
@@ -451,6 +524,9 @@ void RenderThreadImpl::Init() {
vc_manager_.reset(new VideoCaptureImplManager());
AddFilter(vc_manager_->video_capture_message_filter());
+ browser_plugin_manager_.reset(new BrowserPluginManager());
+ AddObserver(browser_plugin_manager_.get());
+
#if defined(ENABLE_WEBRTC)
peer_connection_tracker_.reset(new PeerConnectionTracker());
AddObserver(peer_connection_tracker_.get());
@@ -482,27 +558,46 @@ void RenderThreadImpl::Init() {
AddFilter((new IndexedDBMessageFilter(thread_safe_sender()))->GetFilter());
+ AddFilter((new CacheStorageMessageFilter(thread_safe_sender()))->GetFilter());
+
AddFilter((new EmbeddedWorkerContextMessageFilter())->GetFilter());
GetContentClient()->renderer()->RenderThreadStarted();
InitSkiaEventTracer();
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
is_impl_side_painting_enabled_ =
- command_line.HasSwitch(switches::kEnableImplSidePainting);
+ !command_line.HasSwitch(switches::kDisableImplSidePainting);
cc_blink::WebLayerImpl::SetImplSidePaintingEnabled(
is_impl_side_painting_enabled_);
is_zero_copy_enabled_ = command_line.HasSwitch(switches::kEnableZeroCopy);
+ is_one_copy_enabled_ = !command_line.HasSwitch(switches::kDisableOneCopy);
-#if defined(OS_MACOSX) || defined(OS_ANDROID)
- is_one_copy_enabled_ = command_line.HasSwitch(switches::kEnableOneCopy);
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+ is_elastic_overscroll_enabled_ = base::mac::IsOSLionOrLater();
+ if (is_elastic_overscroll_enabled_) {
+ base::ScopedCFTypeRef<CFStringRef> key(
+ base::SysUTF8ToCFStringRef("NSScrollViewRubberbanding"));
+ Boolean key_exists = false;
+ Boolean value = CFPreferencesGetAppBooleanValue(
+ key, kCFPreferencesCurrentApplication, &key_exists);
+ if (key_exists && !value)
+ is_elastic_overscroll_enabled_ = false;
+ }
#else
- is_one_copy_enabled_ = !command_line.HasSwitch(switches::kDisableOneCopy);
+ is_elastic_overscroll_enabled_ = false;
#endif
+ std::string image_texture_target_string =
+ command_line.GetSwitchValueASCII(switches::kUseImageTextureTarget);
+ bool parsed_image_texture_target = base::StringToUint(
+ image_texture_target_string, &use_image_texture_target_);
+ DCHECK(parsed_image_texture_target);
+
if (command_line.HasSwitch(switches::kDisableLCDText)) {
is_lcd_text_enabled_ = false;
} else if (command_line.HasSwitch(switches::kEnableLCDText)) {
@@ -520,6 +615,17 @@ void RenderThreadImpl::Init() {
is_gpu_rasterization_forced_ =
command_line.HasSwitch(switches::kForceGpuRasterization);
+ if (command_line.HasSwitch(switches::kGpuRasterizationMSAASampleCount)) {
+ std::string string_value = command_line.GetSwitchValueASCII(
+ switches::kGpuRasterizationMSAASampleCount);
+ bool parsed_msaa_sample_count =
+ base::StringToInt(string_value, &gpu_rasterization_msaa_sample_count_);
+ DCHECK(parsed_msaa_sample_count) << string_value;
+ DCHECK_GE(gpu_rasterization_msaa_sample_count_, 0);
+ } else {
+ gpu_rasterization_msaa_sample_count_ = 0;
+ }
+
if (command_line.HasSwitch(switches::kDisableDistanceFieldText)) {
is_distance_field_text_enabled_ = false;
} else if (command_line.HasSwitch(switches::kEnableDistanceFieldText)) {
@@ -538,28 +644,9 @@ void RenderThreadImpl::Init() {
memory_pressure_listener_.reset(new base::MemoryPressureListener(
base::Bind(&RenderThreadImpl::OnMemoryPressure, base::Unretained(this))));
- std::vector<base::DiscardableMemoryType> supported_types;
- base::DiscardableMemory::GetSupportedTypes(&supported_types);
- DCHECK(!supported_types.empty());
-
- // The default preferred type is always the first one in list.
- base::DiscardableMemoryType type = supported_types[0];
-
- if (command_line.HasSwitch(switches::kUseDiscardableMemory)) {
- std::string requested_type_name = command_line.GetSwitchValueASCII(
- switches::kUseDiscardableMemory);
- base::DiscardableMemoryType requested_type =
- base::DiscardableMemory::GetNamedType(requested_type_name);
- if (std::find(supported_types.begin(),
- supported_types.end(),
- requested_type) != supported_types.end()) {
- type = requested_type;
- } else {
- LOG(ERROR) << "Requested discardable memory type is not supported.";
- }
- }
+ compositor_task_graph_runner_.reset(new cc::TaskGraphRunner);
- base::DiscardableMemory::SetPreferredType(type);
+ is_gather_pixel_refs_enabled_ = false;
if (is_impl_side_painting_enabled_) {
int num_raster_threads = 0;
@@ -569,11 +656,39 @@ void RenderThreadImpl::Init() {
base::StringToInt(string_value, &num_raster_threads);
DCHECK(parsed_num_raster_threads) << string_value;
DCHECK_GT(num_raster_threads, 0);
- cc::RasterWorkerPool::SetNumRasterThreads(num_raster_threads);
+
+ // Note: Currently, gathering of pixel refs when using a single
+ // raster thread doesn't provide any benefit. This might change
+ // in the future but we avoid it for now to reduce the cost of
+ // Picture::Create.
+ is_gather_pixel_refs_enabled_ = num_raster_threads > 1;
+
+ while (compositor_raster_threads_.size() <
+ static_cast<size_t>(num_raster_threads)) {
+ scoped_ptr<CompositorRasterThread> raster_thread(
+ new CompositorRasterThread(
+ compositor_task_graph_runner_.get(),
+ base::StringPrintf(
+ "CompositorTileWorker%u",
+ static_cast<unsigned>(compositor_raster_threads_.size() + 1))
+ .c_str()));
+ raster_thread->Start();
+#if defined(OS_ANDROID) || defined(OS_LINUX)
+ if (!command_line.HasSwitch(
+ switches::kUseNormalPriorityForTileTaskWorkerThreads)) {
+ raster_thread->SetThreadPriority(base::ThreadPriority::BACKGROUND);
+ }
+#endif
+ compositor_raster_threads_.push_back(raster_thread.Pass());
+ }
}
- base::DiscardableMemoryShmemAllocator::SetInstance(
- ChildThread::discardable_shared_memory_manager());
+ // In single process, browser main loop set up the discardable memory
+ // allocator.
+ if (!command_line.HasSwitch(switches::kSingleProcess)) {
+ base::DiscardableMemoryAllocator::SetInstance(
+ ChildThreadImpl::discardable_shared_memory_manager());
+ }
service_registry()->AddService<RenderFrameSetup>(
base::Bind(CreateRenderFrameSetup));
@@ -582,19 +697,13 @@ void RenderThreadImpl::Init() {
}
RenderThreadImpl::~RenderThreadImpl() {
- for (std::map<int, mojo::MessagePipeHandle>::iterator it =
- pending_render_frame_connects_.begin();
- it != pending_render_frame_connects_.end();
- ++it) {
- mojo::CloseRaw(it->second);
- }
}
void RenderThreadImpl::Shutdown() {
FOR_EACH_OBSERVER(
RenderProcessObserver, observers_, OnRenderProcessShutdown());
- ChildThread::Shutdown();
+ ChildThreadImpl::Shutdown();
if (memory_observer_) {
message_loop()->RemoveTaskObserver(memory_observer_.get());
@@ -623,8 +732,11 @@ void RenderThreadImpl::Shutdown() {
#if defined(ENABLE_WEBRTC)
RTCPeerConnectionHandler::DestructAllHandlers();
-
- peer_connection_factory_.reset();
+ // |peer_connection_factory_| cannot be deleted until after the main message
+ // loop has been destroyed. This is because there may be pending tasks that
+ // hold on to objects produced by the PC factory that depend on threads owned
+ // by the PC factory. Once those tasks have been freed, the factory can be
+ // deleted.
#endif
RemoveFilter(vc_manager_->video_capture_message_filter());
vc_manager_.reset();
@@ -636,9 +748,9 @@ void RenderThreadImpl::Shutdown() {
if (file_thread_)
file_thread_->Stop();
- if (compositor_output_surface_filter_.get()) {
- RemoveFilter(compositor_output_surface_filter_.get());
- compositor_output_surface_filter_ = NULL;
+ if (compositor_message_filter_.get()) {
+ RemoveFilter(compositor_message_filter_.get());
+ compositor_message_filter_ = NULL;
}
media_thread_.reset();
@@ -648,6 +760,16 @@ void RenderThreadImpl::Shutdown() {
audio_message_filter_ = NULL;
compositor_thread_.reset();
+
+ // Shutdown raster threads.
+ compositor_task_graph_runner_->Shutdown();
+ while (!compositor_raster_threads_.empty()) {
+ compositor_raster_threads_.back()->Join();
+ compositor_raster_threads_.pop_back();
+ }
+ compositor_task_graph_runner_.reset();
+
+ main_input_callback_.Cancel();
input_handler_manager_.reset();
if (input_event_filter_.get()) {
RemoveFilter(input_event_filter_.get());
@@ -665,25 +787,39 @@ void RenderThreadImpl::Shutdown() {
main_thread_compositor_task_runner_ = NULL;
- if (blink_platform_impl_)
- blink::shutdown();
+ // Context providers must be released prior to destroying the GPU channel.
+ gpu_va_context_provider_ = nullptr;
+ shared_main_thread_contexts_ = nullptr;
- lazy_tls.Pointer()->Set(NULL);
+ if (gpu_channel_.get())
+ gpu_channel_->DestroyChannel();
// TODO(port)
#if defined(OS_WIN)
// Clean up plugin channels before this thread goes away.
NPChannelBase::CleanupChannels();
#endif
+
+ // Shut down the message loop and the renderer scheduler before shutting down
+ // Blink. This prevents a scenario where a pending task in the message loop
+ // accesses Blink objects after Blink shuts down.
+ // This must be at the very end of the shutdown sequence. You must not touch
+ // the message loop after this.
+ renderer_scheduler_->Shutdown();
+ main_message_loop_.reset();
+ if (blink_platform_impl_)
+ blink::shutdown();
+
+ lazy_tls.Pointer()->Set(NULL);
}
bool RenderThreadImpl::Send(IPC::Message* msg) {
// Certain synchronous messages cannot always be processed synchronously by
// the browser, e.g., putting up UI and waiting for the user. This could cause
- // a complete hang of Chrome if a windowed plug-in is trying to communicate
+ // a complete hang of Chrome if a windowed plugin is trying to communicate
// with the renderer thread since the browser's UI thread could be stuck
// (within a Windows API call) trying to synchronously communicate with the
- // plug-in. The remedy is to pump messages on this thread while the browser
+ // plugin. The remedy is to pump messages on this thread while the browser
// is processing this request. This creates an opportunity for re-entrancy
// into WebKit, so we need to take care to disable callbacks, timers, and
// pending network loads that could trigger such callbacks.
@@ -694,9 +830,6 @@ bool RenderThreadImpl::Send(IPC::Message* msg) {
}
}
- bool suspend_webkit_shared_timer = true; // default value
- std::swap(suspend_webkit_shared_timer, suspend_webkit_shared_timer_);
-
bool notify_webkit_of_modal_loop = true; // default value
std::swap(notify_webkit_of_modal_loop, notify_webkit_of_modal_loop_);
@@ -705,8 +838,9 @@ bool RenderThreadImpl::Send(IPC::Message* msg) {
#endif
if (pumping_events) {
- if (suspend_webkit_shared_timer)
- blink_platform_impl_->SuspendSharedTimer();
+ // TODO(alexclarke): Remove the shared timer.
+ blink_platform_impl_->SuspendSharedTimer();
+ renderer_scheduler_->SuspendTimerQueue();
if (notify_webkit_of_modal_loop)
WebView::willEnterModalLoop();
@@ -721,7 +855,7 @@ bool RenderThreadImpl::Send(IPC::Message* msg) {
#endif
}
- bool rv = ChildThread::Send(msg);
+ bool rv = ChildThreadImpl::Send(msg);
if (pumping_events) {
#if defined(ENABLE_PLUGINS)
@@ -734,15 +868,16 @@ bool RenderThreadImpl::Send(IPC::Message* msg) {
if (notify_webkit_of_modal_loop)
WebView::didExitModalLoop();
- if (suspend_webkit_shared_timer)
- blink_platform_impl_->ResumeSharedTimer();
+ // TODO(alexclarke): Remove the shared timer.
+ blink_platform_impl_->ResumeSharedTimer();
+ renderer_scheduler_->ResumeTimerQueue();
}
return rv;
}
-base::MessageLoop* RenderThreadImpl::GetMessageLoop() {
- return message_loop();
+scoped_refptr<base::SingleThreadTaskRunner> RenderThreadImpl::GetTaskRunner() {
+ return GetRendererScheduler()->DefaultTaskRunner();
}
IPC::SyncChannel* RenderThreadImpl::GetChannel() {
@@ -752,7 +887,8 @@ IPC::SyncChannel* RenderThreadImpl::GetChannel() {
std::string RenderThreadImpl::GetLocale() {
// The browser process should have passed the locale to the renderer via the
// --lang command line flag.
- const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
+ const base::CommandLine& parsed_command_line =
+ *base::CommandLine::ForCurrentProcess();
const std::string& lang =
parsed_command_line.GetSwitchValueASCII(switches::kLang);
DCHECK(!lang.empty());
@@ -769,8 +905,8 @@ scoped_refptr<base::MessageLoopProxy>
}
void RenderThreadImpl::AddRoute(int32 routing_id, IPC::Listener* listener) {
- ChildThread::GetRouter()->AddRoute(routing_id, listener);
- std::map<int, mojo::MessagePipeHandle>::iterator it =
+ ChildThreadImpl::GetRouter()->AddRoute(routing_id, listener);
+ PendingRenderFrameConnectMap::iterator it =
pending_render_frame_connects_.find(routing_id);
if (it == pending_render_frame_connects_.end())
return;
@@ -779,13 +915,19 @@ void RenderThreadImpl::AddRoute(int32 routing_id, IPC::Listener* listener) {
if (!frame)
return;
- mojo::ScopedMessagePipeHandle handle(it->second);
+ scoped_refptr<PendingRenderFrameConnect> connection(it->second);
+ mojo::InterfaceRequest<mojo::ServiceProvider> services(
+ connection->services().Pass());
+ mojo::ServiceProviderPtr exposed_services(
+ connection->exposed_services().Pass());
+ exposed_services.set_error_handler(nullptr);
pending_render_frame_connects_.erase(it);
- frame->BindServiceRegistry(handle.Pass());
+
+ frame->BindServiceRegistry(services.Pass(), exposed_services.Pass());
}
void RenderThreadImpl::RemoveRoute(int32 routing_id) {
- ChildThread::GetRouter()->RemoveRoute(routing_id);
+ ChildThreadImpl::GetRouter()->RemoveRoute(routing_id);
}
void RenderThreadImpl::AddEmbeddedWorkerRoute(int32 routing_id,
@@ -807,10 +949,13 @@ void RenderThreadImpl::RemoveEmbeddedWorkerRoute(int32 routing_id) {
void RenderThreadImpl::RegisterPendingRenderFrameConnect(
int routing_id,
- mojo::ScopedMessagePipeHandle handle) {
- std::pair<std::map<int, mojo::MessagePipeHandle>::iterator, bool> result =
- pending_render_frame_connects_.insert(
- std::make_pair(routing_id, handle.release()));
+ mojo::InterfaceRequest<mojo::ServiceProvider> services,
+ mojo::ServiceProviderPtr exposed_services) {
+ std::pair<PendingRenderFrameConnectMap::iterator, bool> result =
+ pending_render_frame_connects_.insert(std::make_pair(
+ routing_id,
+ make_scoped_refptr(new PendingRenderFrameConnect(
+ routing_id, services.Pass(), exposed_services.Pass()))));
CHECK(result.second) << "Inserting a duplicate item.";
}
@@ -841,24 +986,50 @@ void RenderThreadImpl::SetResourceDispatcherDelegate(
resource_dispatcher()->set_delegate(delegate);
}
+void RenderThreadImpl::SetResourceDispatchTaskQueue(
+ const scoped_refptr<base::SingleThreadTaskRunner>& resource_task_queue) {
+ // Add a filter that forces resource messages to be dispatched via a
+ // particular task runner.
+ resource_scheduling_filter_ =
+ new ResourceSchedulingFilter(resource_task_queue, resource_dispatcher());
+ channel()->AddFilter(resource_scheduling_filter_.get());
+
+ // The ChildResourceMessageFilter and the ResourceDispatcher need to use the
+ // same queue to ensure tasks are executed in the expected order.
+ child_resource_message_filter()->SetMainThreadTaskRunner(resource_task_queue);
+ resource_dispatcher()->SetMainThreadTaskRunner(resource_task_queue);
+}
+
void RenderThreadImpl::EnsureWebKitInitialized() {
if (blink_platform_impl_)
return;
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
+
+#ifdef ENABLE_VTUNE_JIT_INTERFACE
+ if (command_line.HasSwitch(switches::kEnableVtune))
+ gin::Debug::SetJitCodeEventHandler(vTune::GetVtuneCodeEventHandler());
+#endif
+
+ SetRuntimeFeaturesDefaultsAndUpdateFromArgs(command_line);
+
blink_platform_impl_.reset(
new RendererBlinkPlatformImpl(renderer_scheduler_.get()));
blink::initialize(blink_platform_impl_.get());
v8::Isolate* isolate = blink::mainThreadIsolate();
-
- isolate->SetCounterFunction(base::StatsTable::FindLocation);
isolate->SetCreateHistogramFunction(CreateHistogram);
isolate->SetAddHistogramSampleFunction(AddHistogramSample);
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
-
main_thread_compositor_task_runner_ =
- renderer_scheduler()->CompositorTaskRunner();
+ renderer_scheduler_->CompositorTaskRunner();
+
+ main_input_callback_.Reset(
+ base::Bind(base::IgnoreResult(&RenderThreadImpl::OnMessageReceived),
+ base::Unretained(this)));
+
+ SetResourceDispatchTaskQueue(renderer_scheduler_->LoadingTaskRunner());
bool enable = !command_line.HasSwitch(switches::kDisableThreadedCompositing);
if (enable) {
@@ -872,7 +1043,7 @@ void RenderThreadImpl::EnsureWebKitInitialized() {
compositor_thread_.reset(new base::Thread("Compositor"));
compositor_thread_->Start();
#if defined(OS_ANDROID)
- compositor_thread_->SetPriority(base::kThreadPriority_Display);
+ compositor_thread_->SetPriority(base::ThreadPriority::DISPLAY);
#endif
compositor_message_loop_proxy_ =
compositor_thread_->message_loop_proxy();
@@ -890,48 +1061,60 @@ void RenderThreadImpl::EnsureWebKitInitialized() {
}
#endif
if (!input_handler_manager_client) {
- input_event_filter_ =
- new InputEventFilter(this,
+ scoped_refptr<InputEventFilter> compositor_input_event_filter(
+ new InputEventFilter(main_input_callback_.callback(),
main_thread_compositor_task_runner_,
- compositor_message_loop_proxy_);
- AddFilter(input_event_filter_.get());
- input_handler_manager_client = input_event_filter_.get();
+ compositor_message_loop_proxy_));
+ input_handler_manager_client = compositor_input_event_filter.get();
+ input_event_filter_ = compositor_input_event_filter;
}
- input_handler_manager_.reset(
- new InputHandlerManager(compositor_message_loop_proxy_,
- input_handler_manager_client));
+ input_handler_manager_.reset(new InputHandlerManager(
+ compositor_message_loop_proxy_, input_handler_manager_client,
+ renderer_scheduler_.get()));
+ }
+
+ if (!input_event_filter_.get()) {
+ // Always provide an input event filter implementation to ensure consistent
+ // input event scheduling and prioritization.
+ // TODO(jdduke): Merge InputEventFilter, InputHandlerManager and
+ // MainThreadInputEventFilter, crbug.com/436057.
+ input_event_filter_ = new MainThreadInputEventFilter(
+ main_input_callback_.callback(), main_thread_compositor_task_runner_);
}
+ AddFilter(input_event_filter_.get());
- scoped_refptr<base::MessageLoopProxy> output_surface_loop;
+ scoped_refptr<base::MessageLoopProxy> compositor_impl_side_loop;
if (enable)
- output_surface_loop = compositor_message_loop_proxy_;
+ compositor_impl_side_loop = compositor_message_loop_proxy_;
else
- output_surface_loop = base::MessageLoopProxy::current();
+ compositor_impl_side_loop = base::MessageLoopProxy::current();
- compositor_output_surface_filter_ =
- CompositorOutputSurface::CreateFilter(output_surface_loop.get());
- AddFilter(compositor_output_surface_filter_.get());
+ compositor_message_filter_ = new CompositorForwardingMessageFilter(
+ compositor_impl_side_loop.get());
+ AddFilter(compositor_message_filter_.get());
RenderThreadImpl::RegisterSchemes();
EnableBlinkPlatformLogChannels(
command_line.GetSwitchValueASCII(switches::kBlinkPlatformLogChannels));
- SetRuntimeFeaturesDefaultsAndUpdateFromArgs(command_line);
-
if (!media::IsMediaLibraryInitialized()) {
WebRuntimeFeatures::enableWebAudio(false);
}
+ RenderMediaClient::Initialize();
+
FOR_EACH_OBSERVER(RenderProcessObserver, observers_, WebKitInitialized());
devtools_agent_message_filter_ = new DevToolsAgentFilter();
AddFilter(devtools_agent_message_filter_.get());
+ v8_sampling_profiler_.reset(new V8SamplingProfiler());
+
if (GetContentClient()->renderer()->RunIdleHandlerWhenWidgetsHidden())
ScheduleIdleHandler(kLongIdleHandlerDelayMs);
- cc_blink::SetSharedMemoryAllocationFunction(AllocateSharedMemoryFunction);
+ cc_blink::SetSharedBitmapAllocationFunction(AllocateSharedBitmapFunction);
// Limit use of the scaled image cache to when deferred image decoding is
// enabled.
@@ -946,6 +1129,12 @@ void RenderThreadImpl::EnsureWebKitInitialized() {
memory_observer_.reset(new MemoryObserver());
message_loop()->AddTaskObserver(memory_observer_.get());
}
+
+ if (command_line.HasSwitch(switches::kExplicitlyAllowedPorts)) {
+ std::string allowed_ports =
+ command_line.GetSwitchValueASCII(switches::kExplicitlyAllowedPorts);
+ net::SetExplicitlyAllowedPorts(allowed_ports);
+ }
}
void RenderThreadImpl::RegisterSchemes() {
@@ -972,27 +1161,11 @@ void RenderThreadImpl::RecordComputedAction(const std::string& action) {
scoped_ptr<base::SharedMemory>
RenderThreadImpl::HostAllocateSharedMemoryBuffer(size_t size) {
- if (size > static_cast<size_t>(std::numeric_limits<int>::max()))
- return scoped_ptr<base::SharedMemory>();
-
- base::SharedMemoryHandle handle;
- bool success;
- IPC::Message* message =
- new ChildProcessHostMsg_SyncAllocateSharedMemory(size, &handle);
-
- // Allow calling this from the compositor thread.
- if (base::MessageLoop::current() == message_loop())
- success = ChildThread::Send(message);
- else
- success = sync_message_filter()->Send(message);
-
- if (!success)
- return scoped_ptr<base::SharedMemory>();
-
- if (!base::SharedMemory::IsHandleValid(handle))
- return scoped_ptr<base::SharedMemory>();
+ return ChildThreadImpl::AllocateSharedMemory(size, thread_safe_sender());
+}
- return scoped_ptr<base::SharedMemory>(new base::SharedMemory(handle, false));
+cc::SharedBitmapManager* RenderThreadImpl::GetSharedBitmapManager() {
+ return shared_bitmap_manager();
}
void RenderThreadImpl::RegisterExtension(v8::Extension* extension) {
@@ -1016,24 +1189,22 @@ void RenderThreadImpl::IdleHandler() {
--idle_notifications_to_skip_;
} else {
base::allocator::ReleaseFreeMemory();
- base::DiscardableMemory::ReduceMemoryUsage();
+ discardable_shared_memory_manager()->ReleaseFreeMemory();
}
ScheduleIdleHandler(kLongIdleHandlerDelayMs);
return;
}
base::allocator::ReleaseFreeMemory();
- base::DiscardableMemory::ReleaseFreeMemory();
+ discardable_shared_memory_manager()->ReleaseFreeMemory();
// Continue the idle timer if the webkit shared timer is not suspended or
// something is left to do.
bool continue_timer = !webkit_shared_timer_suspended_;
if (blink::mainThreadIsolate() &&
- !blink::mainThreadIsolate()->IdleNotification(1000)) {
- continue_timer = true;
- }
- if (!base::DiscardableMemory::ReduceMemoryUsage()) {
+ !blink::mainThreadIsolate()->IdleNotificationDeadline(
+ blink_platform_impl_->monotonicallyIncreasingTime() + 1.0)) {
continue_timer = true;
}
@@ -1095,7 +1266,7 @@ RenderThreadImpl::GetGpuFactories() {
DCHECK(IsMainThread());
scoped_refptr<GpuChannelHost> gpu_channel_host = GetGpuChannel();
- const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
+ const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
scoped_refptr<media::GpuVideoAcceleratorFactories> gpu_factories;
scoped_refptr<base::SingleThreadTaskRunner> media_task_runner =
GetMediaThreadTaskRunner();
@@ -1117,7 +1288,7 @@ RenderThreadImpl::GetGpuFactories() {
GURL("chrome://gpu/RenderThreadImpl::GetGpuVDAContext3D"),
WebGraphicsContext3DCommandBufferImpl::SharedMemoryLimits(),
NULL)),
- "GPU-VideoAccelerator-Offscreen");
+ GPU_VIDEO_ACCELERATOR_CONTEXT);
}
}
if (gpu_va_context_provider_.get()) {
@@ -1144,7 +1315,7 @@ RenderThreadImpl::CreateOffscreenContext3d() {
NULL));
}
-scoped_refptr<webkit::gpu::ContextProviderWebContext>
+scoped_refptr<cc_blink::ContextProviderWebContext>
RenderThreadImpl::SharedMainThreadContextProvider() {
DCHECK(IsMainThread());
if (!shared_main_thread_contexts_.get() ||
@@ -1159,7 +1330,7 @@ RenderThreadImpl::SharedMainThreadContextProvider() {
#endif
if (!shared_main_thread_contexts_.get()) {
shared_main_thread_contexts_ = ContextProviderCommandBuffer::Create(
- CreateOffscreenContext3d(), "Offscreen-MainThread");
+ CreateOffscreenContext3d(), RENDERER_MAINTHREAD_CONTEXT);
}
if (shared_main_thread_contexts_.get() &&
!shared_main_thread_contexts_->BindToCurrentThread())
@@ -1186,7 +1357,6 @@ media::AudioHardwareConfig* RenderThreadImpl::GetAudioHardwareConfig() {
audio_hardware_config_.reset(new media::AudioHardwareConfig(
input_params, output_params));
- audio_message_filter_->SetAudioHardwareConfig(audio_hardware_config_.get());
}
return audio_hardware_config_.get();
@@ -1202,30 +1372,107 @@ void RenderThreadImpl::PreCacheFontCharacters(const LOGFONT& log_font,
Send(new ViewHostMsg_PreCacheFontCharacters(log_font, str));
}
-void RenderThreadImpl::PreCacheFont(const LOGFONT& log_font) {
- Send(new ChildProcessHostMsg_PreCacheFont(log_font));
+#endif // OS_WIN
+
+ServiceRegistry* RenderThreadImpl::GetServiceRegistry() {
+ return service_registry();
}
-void RenderThreadImpl::ReleaseCachedFonts() {
- Send(new ChildProcessHostMsg_ReleaseCachedFonts());
+bool RenderThreadImpl::IsImplSidePaintingEnabled() {
+ return is_impl_side_painting_enabled_;
}
-#endif // OS_WIN
+bool RenderThreadImpl::IsGpuRasterizationForced() {
+ return is_gpu_rasterization_forced_;
+}
-ServiceRegistry* RenderThreadImpl::GetServiceRegistry() {
- return service_registry();
+bool RenderThreadImpl::IsGpuRasterizationEnabled() {
+ return is_gpu_rasterization_enabled_;
}
-bool RenderThreadImpl::IsMainThread() {
- return !!current();
+int RenderThreadImpl::GetGpuRasterizationMSAASampleCount() {
+ return gpu_rasterization_msaa_sample_count_;
+}
+
+bool RenderThreadImpl::IsLcdTextEnabled() {
+ return is_lcd_text_enabled_;
}
-base::MessageLoop* RenderThreadImpl::GetMainLoop() {
- return message_loop();
+bool RenderThreadImpl::IsDistanceFieldTextEnabled() {
+ return is_distance_field_text_enabled_;
}
-scoped_refptr<base::MessageLoopProxy> RenderThreadImpl::GetIOLoopProxy() {
- return io_message_loop_proxy_;
+bool RenderThreadImpl::IsZeroCopyEnabled() {
+ return is_zero_copy_enabled_;
+}
+
+bool RenderThreadImpl::IsOneCopyEnabled() {
+ return is_one_copy_enabled_;
+}
+
+bool RenderThreadImpl::IsElasticOverscrollEnabled() {
+ return is_elastic_overscroll_enabled_;
+}
+
+bool RenderThreadImpl::UseSingleThreadScheduler() {
+ // TODO(enne): using the scheduler introduces additional composite steps
+ // that create flakiness. This should go away eventually.
+ return !layout_test_mode_;
+}
+
+uint32 RenderThreadImpl::GetImageTextureTarget() {
+ return use_image_texture_target_;
+}
+
+scoped_refptr<base::SingleThreadTaskRunner>
+RenderThreadImpl::GetCompositorMainThreadTaskRunner() {
+ return main_thread_compositor_task_runner_;
+}
+
+scoped_refptr<base::SingleThreadTaskRunner>
+RenderThreadImpl::GetCompositorImplThreadTaskRunner() {
+ return compositor_message_loop_proxy_;
+}
+
+gpu::GpuMemoryBufferManager* RenderThreadImpl::GetGpuMemoryBufferManager() {
+ return gpu_memory_buffer_manager();
+}
+
+scheduler::RendererScheduler* RenderThreadImpl::GetRendererScheduler() {
+ return renderer_scheduler_.get();
+}
+
+cc::ContextProvider* RenderThreadImpl::GetSharedMainThreadContextProvider() {
+ return SharedMainThreadContextProvider().get();
+}
+
+scoped_ptr<cc::BeginFrameSource>
+RenderThreadImpl::CreateExternalBeginFrameSource(int routing_id) {
+#if defined(OS_ANDROID)
+ if (SynchronousCompositorFactory* factory =
+ SynchronousCompositorFactory::GetInstance()) {
+ return factory->CreateExternalBeginFrameSource(routing_id);
+ }
+#endif
+ return make_scoped_ptr(new CompositorExternalBeginFrameSource(
+ compositor_message_filter_.get(), sync_message_filter(), routing_id));
+}
+
+cc::TaskGraphRunner* RenderThreadImpl::GetTaskGraphRunner() {
+ return compositor_task_graph_runner_.get();
+}
+
+bool RenderThreadImpl::IsGatherPixelRefsEnabled() {
+ return is_gather_pixel_refs_enabled_;
+}
+
+bool RenderThreadImpl::IsMainThread() {
+ return !!current();
+}
+
+scoped_refptr<base::SingleThreadTaskRunner>
+RenderThreadImpl::GetIOThreadTaskRunner() {
+ return io_thread_task_runner_;
}
scoped_ptr<base::SharedMemory> RenderThreadImpl::AllocateSharedMemory(
@@ -1256,16 +1503,12 @@ CreateCommandBufferResult RenderThreadImpl::CreateViewCommandBuffer(
return result;
}
-void RenderThreadImpl::DoNotSuspendWebKitSharedTimer() {
- suspend_webkit_shared_timer_ = false;
-}
-
void RenderThreadImpl::DoNotNotifyWebKitOfModalLoop() {
notify_webkit_of_modal_loop_ = false;
}
bool RenderThreadImpl::OnControlMessageReceived(const IPC::Message& msg) {
- ObserverListBase<RenderProcessObserver>::Iterator it(observers_);
+ ObserverListBase<RenderProcessObserver>::Iterator it(&observers_);
RenderProcessObserver* observer;
while ((observer = it.GetNext()) != NULL) {
if (observer->OnControlMessageReceived(msg))
@@ -1307,17 +1550,21 @@ bool RenderThreadImpl::OnControlMessageReceived(const IPC::Message& msg) {
return handled;
}
-void RenderThreadImpl::OnCreateNewFrame(int routing_id,
- int parent_routing_id,
- int proxy_routing_id) {
- RenderFrameImpl::CreateFrame(routing_id, parent_routing_id, proxy_routing_id);
+void RenderThreadImpl::OnCreateNewFrame(FrameMsg_NewFrame_Params params) {
+ CompositorDependencies* compositor_deps = this;
+ RenderFrameImpl::CreateFrame(
+ params.routing_id, params.parent_routing_id,
+ params.previous_sibling_routing_id, params.proxy_routing_id,
+ params.replication_state, compositor_deps, params.widget_params);
}
-void RenderThreadImpl::OnCreateNewFrameProxy(int routing_id,
- int parent_routing_id,
- int render_view_routing_id) {
- RenderFrameProxy::CreateFrameProxy(
- routing_id, parent_routing_id, render_view_routing_id);
+void RenderThreadImpl::OnCreateNewFrameProxy(
+ int routing_id,
+ int parent_routing_id,
+ int render_view_routing_id,
+ const FrameReplicationState& replicated_state) {
+ RenderFrameProxy::CreateFrameProxy(routing_id, parent_routing_id,
+ render_view_routing_id, replicated_state);
}
void RenderThreadImpl::OnSetZoomLevelForCurrentURL(const std::string& scheme,
@@ -1329,23 +1576,9 @@ void RenderThreadImpl::OnSetZoomLevelForCurrentURL(const std::string& scheme,
void RenderThreadImpl::OnCreateNewView(const ViewMsg_New_Params& params) {
EnsureWebKitInitialized();
+ CompositorDependencies* compositor_deps = this;
// When bringing in render_view, also bring in webkit's glue and jsbindings.
- RenderViewImpl::Create(params.opener_route_id,
- params.window_was_created_with_opener,
- params.renderer_preferences,
- params.web_preferences,
- params.view_id,
- params.main_frame_routing_id,
- params.surface_id,
- params.session_storage_namespace_id,
- params.frame_name,
- false,
- params.swapped_out,
- params.proxy_routing_id,
- params.hidden,
- params.never_visible,
- params.next_page_id,
- params.screen_info);
+ RenderViewImpl::Create(params, compositor_deps, false);
}
GpuChannelHost* RenderThreadImpl::EstablishGpuChannelSync(
@@ -1359,6 +1592,7 @@ GpuChannelHost* RenderThreadImpl::EstablishGpuChannelSync(
return gpu_channel_.get();
// Recreate the channel if it has been lost.
+ gpu_channel_->DestroyChannel();
gpu_channel_ = NULL;
}
@@ -1382,7 +1616,7 @@ GpuChannelHost* RenderThreadImpl::EstablishGpuChannelSync(
// Cache some variables that are needed on the compositor thread for our
// implementation of GpuChannelHostFactory.
- io_message_loop_proxy_ = ChildProcess::current()->io_message_loop_proxy();
+ io_thread_task_runner_ = ChildProcess::current()->io_message_loop_proxy();
gpu_channel_ =
GpuChannelHost::Create(this,
@@ -1396,8 +1630,8 @@ GpuChannelHost* RenderThreadImpl::EstablishGpuChannelSync(
blink::WebMediaStreamCenter* RenderThreadImpl::CreateMediaStreamCenter(
blink::WebMediaStreamCenterClient* client) {
#if defined(OS_ANDROID)
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableWebRTC))
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableWebRTC))
return NULL;
#endif
@@ -1463,23 +1697,30 @@ void RenderThreadImpl::OnTempCrashWithData(const GURL& data) {
CHECK(false);
}
-void RenderThreadImpl::OnUpdateTimezone() {
+void RenderThreadImpl::OnUpdateTimezone(const std::string& zone_id) {
if (!blink_platform_impl_)
return;
+ if (!zone_id.empty()) {
+ icu::TimeZone *new_zone = icu::TimeZone::createTimeZone(
+ icu::UnicodeString::fromUTF8(zone_id));
+ icu::TimeZone::adoptDefault(new_zone);
+ VLOG(1) << "ICU default timezone is set to " << zone_id;
+ }
NotifyTimezoneChange();
}
#if defined(OS_ANDROID)
void RenderThreadImpl::OnSetWebKitSharedTimersSuspended(bool suspend) {
- if (suspend_webkit_shared_timer_) {
- EnsureWebKitInitialized();
- if (suspend) {
- blink_platform_impl_->SuspendSharedTimer();
- } else {
- blink_platform_impl_->ResumeSharedTimer();
- }
- webkit_shared_timer_suspended_ = suspend;
+ EnsureWebKitInitialized();
+ // TODO(alexclarke): Remove the shared timer.
+ if (suspend) {
+ blink_platform_impl_->SuspendSharedTimer();
+ renderer_scheduler_->SuspendTimerQueue();
+ } else {
+ blink_platform_impl_->ResumeSharedTimer();
+ renderer_scheduler_->ResumeTimerQueue();
}
+ webkit_shared_timer_suspended_ = suspend;
}
#endif
@@ -1515,25 +1756,32 @@ void RenderThreadImpl::OnCreateNewSharedWorker(
void RenderThreadImpl::OnMemoryPressure(
base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
base::allocator::ReleaseFreeMemory();
+ discardable_shared_memory_manager()->ReleaseFreeMemory();
- // Trigger full v8 garbage collection on critical memory notification. This
- // will potentially hang the renderer for a long time, however, when we
- // receive a memory pressure notification, we might be about to be killed.
- if (blink_platform_impl_ && blink::mainThreadIsolate()) {
- blink::mainThreadIsolate()->LowMemoryNotification();
- }
+ // Do not call into blink if it is not initialized.
+ if (blink_platform_impl_) {
+ blink::WebCache::pruneAll();
+
+ if (blink::mainThreadIsolate()) {
+ // Trigger full v8 garbage collection on memory pressure notifications.
+ // This will potentially hang the renderer for a long time, however, when
+ // we receive a memory pressure notification, we might be about to be
+ // killed.
+ blink::mainThreadIsolate()->LowMemoryNotification();
+ RenderThread::Get()->PostTaskToAllWebWorkers(
+ base::Bind(&LowMemoryNotificationOnThisThread));
+ }
- if (memory_pressure_level ==
- base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) {
- if (blink_platform_impl_) {
- // Clear the image cache. Do not call into blink if it is not initialized.
+ if (memory_pressure_level ==
+ base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) {
+ // Clear the image cache.
blink::WebImageCache::clear();
- }
- // Purge Skia font cache, by setting it to 0 and then again to the previous
- // limit.
- size_t font_cache_limit = SkGraphics::SetFontCacheLimit(0);
- SkGraphics::SetFontCacheLimit(font_cache_limit);
+ // Purge Skia font cache, by setting it to 0 and then again to the
+ // previous limit.
+ size_t font_cache_limit = SkGraphics::SetFontCacheLimit(0);
+ SkGraphics::SetFontCacheLimit(font_cache_limit);
+ }
}
}
@@ -1566,39 +1814,81 @@ void RenderThreadImpl::SampleGamepads(blink::WebGamepads* data) {
blink_platform_impl_->sampleGamepads(*data);
}
+bool RenderThreadImpl::RendererIsHidden() const {
+ return widget_count_ > 0 && hidden_widget_count_ == widget_count_;
+}
+
void RenderThreadImpl::WidgetCreated() {
+ bool renderer_was_hidden = RendererIsHidden();
widget_count_++;
+ if (renderer_was_hidden)
+ OnRendererVisible();
}
void RenderThreadImpl::WidgetDestroyed() {
+ // TODO(rmcilroy): Remove the restriction that destroyed widgets must be
+ // unhidden before WidgetDestroyed is called.
+ DCHECK_GT(widget_count_, 0);
+ DCHECK_GT(widget_count_, hidden_widget_count_);
widget_count_--;
+ if (RendererIsHidden())
+ OnRendererHidden();
}
void RenderThreadImpl::WidgetHidden() {
DCHECK_LT(hidden_widget_count_, widget_count_);
hidden_widget_count_++;
-
- if (widget_count_ && hidden_widget_count_ == widget_count_) {
- // TODO(reveman): Remove this when we have a better mechanism to prevent
- // total discardable memory used by all renderers from growing too large.
- base::internal::DiscardableMemoryEmulated::
- ReduceMemoryUsageUntilWithinLimit(
- kEmulatedDiscardableMemoryBytesToKeepWhenWidgetsHidden);
-
- if (GetContentClient()->renderer()->RunIdleHandlerWhenWidgetsHidden())
- ScheduleIdleHandler(kInitialIdleHandlerDelayMs);
- }
+ if (RendererIsHidden())
+ OnRendererHidden();
}
void RenderThreadImpl::WidgetRestored() {
+ bool renderer_was_hidden = RendererIsHidden();
DCHECK_GT(hidden_widget_count_, 0);
hidden_widget_count_--;
+ if (renderer_was_hidden)
+ OnRendererVisible();
+}
+
+void RenderThreadImpl::OnRendererHidden() {
+ renderer_scheduler_->OnRendererHidden();
- if (!GetContentClient()->renderer()->RunIdleHandlerWhenWidgetsHidden()) {
+ // TODO(rmcilroy): Remove IdleHandler and replace it with an IdleTask
+ // scheduled by the RendererScheduler - http://crbug.com/469210.
+ if (GetContentClient()->renderer()->RunIdleHandlerWhenWidgetsHidden())
+ ScheduleIdleHandler(kInitialIdleHandlerDelayMs);
+}
+
+void RenderThreadImpl::OnRendererVisible() {
+ renderer_scheduler_->OnRendererVisible();
+
+ if (!GetContentClient()->renderer()->RunIdleHandlerWhenWidgetsHidden())
return;
- }
ScheduleIdleHandler(kLongIdleHandlerDelayMs);
}
+RenderThreadImpl::PendingRenderFrameConnect::PendingRenderFrameConnect(
+ int routing_id,
+ mojo::InterfaceRequest<mojo::ServiceProvider> services,
+ mojo::ServiceProviderPtr exposed_services)
+ : routing_id_(routing_id),
+ services_(services.Pass()),
+ exposed_services_(exposed_services.Pass()) {
+ // The RenderFrame may be deleted before the ExchangeServiceProviders message
+ // is received. In that case, the RenderFrameHost should close the connection,
+ // which is detected by setting an error handler on |exposed_services_|.
+ exposed_services_.set_error_handler(this);
+}
+
+RenderThreadImpl::PendingRenderFrameConnect::~PendingRenderFrameConnect() {
+}
+
+void RenderThreadImpl::PendingRenderFrameConnect::OnConnectionError() {
+ size_t erased =
+ RenderThreadImpl::current()->pending_render_frame_connects_.erase(
+ routing_id_);
+ DCHECK_EQ(1u, erased);
+}
+
} // namespace content
diff --git a/chromium/content/renderer/render_thread_impl.h b/chromium/content/renderer/render_thread_impl.h
index 831c9822220..5b79e723018 100644
--- a/chromium/content/renderer/render_thread_impl.h
+++ b/chromium/content/renderer/render_thread_impl.h
@@ -9,18 +9,22 @@
#include <string>
#include <vector>
+#include "base/cancelable_callback.h"
#include "base/memory/memory_pressure_listener.h"
+#include "base/memory/ref_counted.h"
#include "base/metrics/user_metrics_action.h"
#include "base/observer_list.h"
#include "base/strings/string16.h"
#include "base/threading/thread_checker.h"
#include "base/timer/timer.h"
#include "build/build_config.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
#include "content/common/content_export.h"
+#include "content/common/frame_replication_state.h"
#include "content/common/gpu/client/gpu_channel_host.h"
#include "content/common/gpu/gpu_result_codes.h"
#include "content/public/renderer/render_thread.h"
+#include "content/renderer/gpu/compositor_dependencies.h"
#include "net/base/network_change_notifier.h"
#include "third_party/WebKit/public/platform/WebConnectionType.h"
#include "ui/gfx/native_widget_types.h"
@@ -31,6 +35,7 @@
class GrContext;
class SkBitmap;
+struct FrameMsg_NewFrame_Params;
struct ViewMsg_New_Params;
struct WorkerProcessMsg_CreateWorker_Params;
@@ -49,10 +54,14 @@ class Thread;
namespace cc {
class ContextProvider;
+class TaskGraphRunner;
+}
+
+namespace cc_blink {
+class ContextProviderWebContext;
}
namespace IPC {
-class ForwardingMessageFilter;
class MessageFilter;
}
@@ -61,15 +70,12 @@ class AudioHardwareConfig;
class GpuVideoAcceleratorFactories;
}
-namespace v8 {
-class Extension;
+namespace scheduler {
+class RendererScheduler;
}
-namespace webkit {
-namespace gpu {
-class ContextProviderWebContext;
-class GrContextForWebGraphicsContext3D;
-}
+namespace v8 {
+class Extension;
}
namespace content {
@@ -79,6 +85,9 @@ class AecDumpMessageFilter;
class AudioInputMessageFilter;
class AudioMessageFilter;
class AudioRendererMixerManager;
+class BrowserPluginManager;
+class CacheStorageDispatcher;
+class CompositorForwardingMessageFilter;
class ContextProviderCommandBuffer;
class DBMessageFilter;
class DevToolsAgentFilter;
@@ -86,23 +95,30 @@ class DomStorageDispatcher;
class EmbeddedWorkerDispatcher;
class GpuChannelHost;
class IndexedDBDispatcher;
-class InputEventFilter;
class InputHandlerManager;
class MediaStreamCenter;
class MemoryObserver;
-class PeerConnectionDependencyFactory;
class MidiMessageFilter;
class NetInfoDispatcher;
class P2PSocketDispatcher;
+class PeerConnectionDependencyFactory;
class PeerConnectionTracker;
class RenderProcessObserver;
class RendererBlinkPlatformImpl;
class RendererDemuxerAndroid;
-class RendererScheduler;
+class ResourceDispatchThrottler;
+class ResourceSchedulingFilter;
+class V8SamplingProfiler;
class VideoCaptureImplManager;
class WebGraphicsContext3DCommandBufferImpl;
class WebRTCIdentityService;
+#if defined(COMPILER_MSVC)
+// See explanation for other RenderViewHostImpl which is the same issue.
+#pragma warning(push)
+#pragma warning(disable: 4250)
+#endif
+
// The RenderThreadImpl class represents a background thread where RenderView
// instances live. The RenderThread supports an API that is used by its
// consumer to talk indirectly to the RenderViews and supporting objects.
@@ -112,15 +128,16 @@ class WebRTCIdentityService;
// Most of the communication occurs in the form of IPC messages. They are
// routed to the RenderThread according to the routing IDs of the messages.
// The routing IDs correspond to RenderView instances.
-class CONTENT_EXPORT RenderThreadImpl : public RenderThread,
- public ChildThread,
- public GpuChannelHostFactory {
+class CONTENT_EXPORT RenderThreadImpl
+ : public RenderThread,
+ public ChildThreadImpl,
+ public GpuChannelHostFactory,
+ NON_EXPORTED_BASE(public CompositorDependencies) {
public:
static RenderThreadImpl* current();
- RenderThreadImpl();
- // Constructor that's used when running in single process mode.
- explicit RenderThreadImpl(const std::string& channel_name);
+ explicit RenderThreadImpl(const InProcessChildThreadParams& params);
+ explicit RenderThreadImpl(scoped_ptr<base::MessageLoop> main_message_loop);
~RenderThreadImpl() override;
void Shutdown() override;
@@ -134,7 +151,7 @@ class CONTENT_EXPORT RenderThreadImpl : public RenderThread,
// RenderThread implementation:
bool Send(IPC::Message* msg) override;
- base::MessageLoop* GetMessageLoop() override;
+ scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner() override;
IPC::SyncChannel* GetChannel() override;
std::string GetLocale() override;
IPC::SyncMessageFilter* GetSyncMessageFilter() override;
@@ -153,6 +170,7 @@ class CONTENT_EXPORT RenderThreadImpl : public RenderThread,
void RecordComputedAction(const std::string& action) override;
scoped_ptr<base::SharedMemory> HostAllocateSharedMemoryBuffer(
size_t buffer_size) override;
+ cc::SharedBitmapManager* GetSharedBitmapManager() override;
void RegisterExtension(v8::Extension* extension) override;
void ScheduleIdleHandler(int64 initial_delay_ms) override;
void IdleHandler() override;
@@ -163,12 +181,32 @@ class CONTENT_EXPORT RenderThreadImpl : public RenderThread,
int PostTaskToAllWebWorkers(const base::Closure& closure) override;
bool ResolveProxy(const GURL& url, std::string* proxy_list) override;
base::WaitableEvent* GetShutdownEvent() override;
-#if defined(OS_WIN)
- virtual void PreCacheFont(const LOGFONT& log_font) override;
- virtual void ReleaseCachedFonts() override;
-#endif
ServiceRegistry* GetServiceRegistry() override;
+ // CompositorDependencies implementation.
+ bool IsImplSidePaintingEnabled() override;
+ bool IsGpuRasterizationForced() override;
+ bool IsGpuRasterizationEnabled() override;
+ int GetGpuRasterizationMSAASampleCount() override;
+ bool IsLcdTextEnabled() override;
+ bool IsDistanceFieldTextEnabled() override;
+ bool IsZeroCopyEnabled() override;
+ bool IsOneCopyEnabled() override;
+ bool IsElasticOverscrollEnabled() override;
+ bool UseSingleThreadScheduler() override;
+ uint32 GetImageTextureTarget() override;
+ scoped_refptr<base::SingleThreadTaskRunner>
+ GetCompositorMainThreadTaskRunner() override;
+ scoped_refptr<base::SingleThreadTaskRunner>
+ GetCompositorImplThreadTaskRunner() override;
+ gpu::GpuMemoryBufferManager* GetGpuMemoryBufferManager() override;
+ scheduler::RendererScheduler* GetRendererScheduler() override;
+ cc::ContextProvider* GetSharedMainThreadContextProvider() override;
+ scoped_ptr<cc::BeginFrameSource> CreateExternalBeginFrameSource(
+ int routing_id) override;
+ cc::TaskGraphRunner* GetTaskGraphRunner() override;
+ bool IsGatherPixelRefsEnabled() override;
+
// Synchronously establish a channel to the GPU plugin if not previously
// established or if it has been lost (for example if the GPU plugin crashed).
// If there is a pending asynchronous request, it will be completed by the
@@ -176,12 +214,11 @@ class CONTENT_EXPORT RenderThreadImpl : public RenderThread,
GpuChannelHost* EstablishGpuChannelSync(CauseForGpuLaunch);
- // These methods modify how the next message is sent. Normally, when sending
+ // This method modifies how the next message is sent. Normally, when sending
// a synchronous message that runs a nested message loop, we need to suspend
// callbacks into WebKit. This involves disabling timers and deferring
// resource loads. However, there are exceptions when we need to customize
// the behavior.
- void DoNotSuspendWebKitSharedTimer();
void DoNotNotifyWebKitOfModalLoop();
// True if we are running layout tests. This currently disables forwarding
@@ -194,56 +231,24 @@ class CONTENT_EXPORT RenderThreadImpl : public RenderThread,
layout_test_mode_ = layout_test_mode;
}
- RendererScheduler* renderer_scheduler() const {
- DCHECK(renderer_scheduler_);
- return renderer_scheduler_.get();
- }
-
RendererBlinkPlatformImpl* blink_platform_impl() const {
DCHECK(blink_platform_impl_);
return blink_platform_impl_.get();
}
- scoped_refptr<base::SingleThreadTaskRunner>
- main_thread_compositor_task_runner() const {
- return main_thread_compositor_task_runner_;
- }
-
- IPC::ForwardingMessageFilter* compositor_output_surface_filter() const {
- return compositor_output_surface_filter_.get();
+ CompositorForwardingMessageFilter* compositor_message_filter() const {
+ return compositor_message_filter_.get();
}
InputHandlerManager* input_handler_manager() const {
return input_handler_manager_.get();
}
- // Will be NULL if threaded compositing has not been enabled.
+ // Will be null if threaded compositing has not been enabled.
scoped_refptr<base::MessageLoopProxy> compositor_message_loop_proxy() const {
return compositor_message_loop_proxy_;
}
- bool is_gpu_rasterization_enabled() const {
- return is_gpu_rasterization_enabled_;
- }
-
- bool is_gpu_rasterization_forced() const {
- return is_gpu_rasterization_forced_;
- }
-
- bool is_impl_side_painting_enabled() const {
- return is_impl_side_painting_enabled_;
- }
-
- bool is_lcd_text_enabled() const { return is_lcd_text_enabled_; }
-
- bool is_distance_field_text_enabled() const {
- return is_distance_field_text_enabled_;
- }
-
- bool is_zero_copy_enabled() const { return is_zero_copy_enabled_; }
-
- bool is_one_copy_enabled() const { return is_one_copy_enabled_; }
-
AppCacheDispatcher* appcache_dispatcher() const {
return appcache_dispatcher_.get();
}
@@ -279,6 +284,10 @@ class CONTENT_EXPORT RenderThreadImpl : public RenderThread,
blink::WebMediaStreamCenter* CreateMediaStreamCenter(
blink::WebMediaStreamCenterClient* client);
+ BrowserPluginManager* browser_plugin_manager() const {
+ return browser_plugin_manager_.get();
+ }
+
#if defined(ENABLE_WEBRTC)
// Returns a factory used for creating RTC PeerConnection objects.
PeerConnectionDependencyFactory* GetPeerConnectionDependencyFactory();
@@ -318,8 +327,8 @@ class CONTENT_EXPORT RenderThreadImpl : public RenderThread,
scoped_refptr<media::GpuVideoAcceleratorFactories> GetGpuFactories();
- scoped_refptr<webkit::gpu::ContextProviderWebContext>
- SharedMainThreadContextProvider();
+ scoped_refptr<cc_blink::ContextProviderWebContext>
+ SharedMainThreadContextProvider();
// AudioRendererMixerManager instance which manages renderer side mixer
// instances shared based on configured audio parameters. Lazily created on
@@ -394,6 +403,8 @@ class CONTENT_EXPORT RenderThreadImpl : public RenderThread,
// Called by a RenderWidget when it is created or destroyed. This
// allows the process to know when there are no visible widgets.
void WidgetCreated();
+ // Note: A widget must not be hidden when it is destroyed - ensure that
+ // WidgetRestored is called before WidgetDestroyed for any hidden widget.
void WidgetDestroyed();
void WidgetHidden();
void WidgetRestored();
@@ -401,8 +412,14 @@ class CONTENT_EXPORT RenderThreadImpl : public RenderThread,
void AddEmbeddedWorkerRoute(int32 routing_id, IPC::Listener* listener);
void RemoveEmbeddedWorkerRoute(int32 routing_id);
- void RegisterPendingRenderFrameConnect(int routing_id,
- mojo::ScopedMessagePipeHandle handle);
+ void RegisterPendingRenderFrameConnect(
+ int routing_id,
+ mojo::InterfaceRequest<mojo::ServiceProvider> services,
+ mojo::ServiceProviderPtr exposed_services);
+
+ protected:
+ virtual void SetResourceDispatchTaskQueue(
+ const scoped_refptr<base::SingleThreadTaskRunner>& resource_task_queue);
private:
// ChildThread
@@ -410,8 +427,7 @@ class CONTENT_EXPORT RenderThreadImpl : public RenderThread,
// GpuChannelHostFactory implementation:
bool IsMainThread() override;
- base::MessageLoop* GetMainLoop() override;
- scoped_refptr<base::MessageLoopProxy> GetIOLoopProxy() override;
+ scoped_refptr<base::SingleThreadTaskRunner> GetIOThreadTaskRunner() override;
scoped_ptr<base::SharedMemory> AllocateSharedMemory(size_t size) override;
CreateCommandBufferResult CreateViewCommandBuffer(
int32 surface_id,
@@ -420,12 +436,11 @@ class CONTENT_EXPORT RenderThreadImpl : public RenderThread,
void Init();
- void OnCreateNewFrame(int routing_id,
- int parent_routing_id,
- int proxy_routing_id);
+ void OnCreateNewFrame(FrameMsg_NewFrame_Params params);
void OnCreateNewFrameProxy(int routing_id,
int parent_routing_id,
- int render_view_routing_id);
+ int render_view_routing_id,
+ const FrameReplicationState& replicated_state);
void OnSetZoomLevelForCurrentURL(const std::string& scheme,
const std::string& host,
double zoom_level);
@@ -437,7 +452,7 @@ class CONTENT_EXPORT RenderThreadImpl : public RenderThread,
void OnNetworkTypeChanged(net::NetworkChangeNotifier::ConnectionType type);
void OnGetAccessibilityTree();
void OnTempCrashWithData(const GURL& data);
- void OnUpdateTimezone();
+ void OnUpdateTimezone(const std::string& zoneId);
void OnMemoryPressure(
base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level);
#if defined(OS_ANDROID)
@@ -452,6 +467,9 @@ class CONTENT_EXPORT RenderThreadImpl : public RenderThread,
#endif
void OnCreateNewSharedWorker(
const WorkerProcessMsg_CreateWorker_Params& params);
+ bool RendererIsHidden() const;
+ void OnRendererHidden();
+ void OnRendererVisible();
scoped_ptr<WebGraphicsContext3DCommandBufferImpl> CreateOffscreenContext3d();
@@ -459,8 +477,10 @@ class CONTENT_EXPORT RenderThreadImpl : public RenderThread,
scoped_ptr<AppCacheDispatcher> appcache_dispatcher_;
scoped_ptr<DomStorageDispatcher> dom_storage_dispatcher_;
scoped_ptr<IndexedDBDispatcher> main_thread_indexed_db_dispatcher_;
- scoped_ptr<RendererScheduler> renderer_scheduler_;
+ scoped_ptr<scheduler::RendererScheduler> renderer_scheduler_;
scoped_ptr<RendererBlinkPlatformImpl> blink_platform_impl_;
+ scoped_ptr<ResourceDispatchThrottler> resource_dispatch_throttler_;
+ scoped_ptr<CacheStorageDispatcher> main_thread_cache_storage_dispatcher_;
scoped_ptr<EmbeddedWorkerDispatcher> embedded_worker_dispatcher_;
// Used on the render thread and deleted by WebKit at shutdown.
@@ -475,6 +495,9 @@ class CONTENT_EXPORT RenderThreadImpl : public RenderThread,
scoped_refptr<RendererDemuxerAndroid> renderer_demuxer_;
#endif
scoped_refptr<DevToolsAgentFilter> devtools_agent_message_filter_;
+ scoped_ptr<V8SamplingProfiler> v8_sampling_profiler_;
+
+ scoped_ptr<BrowserPluginManager> browser_plugin_manager_;
#if defined(ENABLE_WEBRTC)
scoped_ptr<PeerConnectionDependencyFactory> peer_connection_factory_;
@@ -508,7 +531,6 @@ class CONTENT_EXPORT RenderThreadImpl : public RenderThread,
// The number of idle handler calls that skip sending idle notifications.
int idle_notifications_to_skip_;
- bool suspend_webkit_shared_timer_;
bool notify_webkit_of_modal_loop_;
bool webkit_shared_timer_suspended_;
@@ -523,7 +545,12 @@ class CONTENT_EXPORT RenderThreadImpl : public RenderThread,
// Cache of variables that are needed on the compositor thread by
// GpuChannelHostFactory methods.
- scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_;
+ scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner_;
+
+ // The message loop of the renderer main thread.
+ // This message loop should be destructed before the RenderThreadImpl
+ // shuts down Blink.
+ scoped_ptr<base::MessageLoop> main_message_loop_;
// A lazily initiated thread on which file operations are run.
scoped_ptr<base::Thread> file_thread_;
@@ -538,12 +565,15 @@ class CONTENT_EXPORT RenderThreadImpl : public RenderThread,
// regardless of whether |compositor_thread_| is overriden.
scoped_refptr<base::MessageLoopProxy> compositor_message_loop_proxy_;
- // May be null if unused by the |input_handler_manager_|.
- scoped_refptr<InputEventFilter> input_event_filter_;
+ // Threads used by compositor for rasterization.
+ ScopedVector<base::SimpleThread> compositor_raster_threads_;
+
+ base::CancelableCallback<void(const IPC::Message&)> main_input_callback_;
+ scoped_refptr<IPC::MessageFilter> input_event_filter_;
scoped_ptr<InputHandlerManager> input_handler_manager_;
- scoped_refptr<IPC::ForwardingMessageFilter> compositor_output_surface_filter_;
+ scoped_refptr<CompositorForwardingMessageFilter> compositor_message_filter_;
- scoped_refptr<webkit::gpu::ContextProviderWebContext>
+ scoped_refptr<cc_blink::ContextProviderWebContext>
shared_main_thread_contexts_;
ObserverList<RenderProcessObserver> observers_;
@@ -566,20 +596,61 @@ class CONTENT_EXPORT RenderThreadImpl : public RenderThread,
scoped_refptr<base::SingleThreadTaskRunner>
main_thread_compositor_task_runner_;
- // Compositor settings
+ scoped_refptr<ResourceSchedulingFilter> resource_scheduling_filter_;
+
+ scoped_ptr<cc::TaskGraphRunner> compositor_task_graph_runner_;
+
+ // Compositor settings.
bool is_gpu_rasterization_enabled_;
bool is_gpu_rasterization_forced_;
+ int gpu_rasterization_msaa_sample_count_;
bool is_impl_side_painting_enabled_;
bool is_lcd_text_enabled_;
bool is_distance_field_text_enabled_;
bool is_zero_copy_enabled_;
bool is_one_copy_enabled_;
+ bool is_elastic_overscroll_enabled_;
+ unsigned use_image_texture_target_;
+ bool is_gather_pixel_refs_enabled_;
+
+ class PendingRenderFrameConnect
+ : public base::RefCounted<PendingRenderFrameConnect>,
+ public mojo::ErrorHandler {
+ public:
+ PendingRenderFrameConnect(
+ int routing_id,
+ mojo::InterfaceRequest<mojo::ServiceProvider> services,
+ mojo::ServiceProviderPtr exposed_services);
+
+ mojo::InterfaceRequest<mojo::ServiceProvider>& services() {
+ return services_;
+ }
+
+ mojo::ServiceProviderPtr& exposed_services() { return exposed_services_; }
+
+ private:
+ friend class base::RefCounted<PendingRenderFrameConnect>;
+
+ ~PendingRenderFrameConnect() override;
- std::map<int, mojo::MessagePipeHandle> pending_render_frame_connects_;
+ void OnConnectionError() override;
+
+ int routing_id_;
+ mojo::InterfaceRequest<mojo::ServiceProvider> services_;
+ mojo::ServiceProviderPtr exposed_services_;
+ };
+
+ typedef std::map<int, scoped_refptr<PendingRenderFrameConnect>>
+ PendingRenderFrameConnectMap;
+ PendingRenderFrameConnectMap pending_render_frame_connects_;
DISALLOW_COPY_AND_ASSIGN(RenderThreadImpl);
};
+#if defined(COMPILER_MSVC)
+#pragma warning(pop)
+#endif
+
} // namespace content
#endif // CONTENT_RENDERER_RENDER_THREAD_IMPL_H_
diff --git a/chromium/content/renderer/render_thread_impl_browsertest.cc b/chromium/content/renderer/render_thread_impl_browsertest.cc
index e98822e222c..264826d815e 100644
--- a/chromium/content/renderer/render_thread_impl_browsertest.cc
+++ b/chromium/content/renderer/render_thread_impl_browsertest.cc
@@ -2,9 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/callback.h"
#include "base/command_line.h"
#include "base/memory/discardable_memory.h"
#include "base/memory/scoped_vector.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/thread_task_runner_handle.h"
+#include "content/common/in_process_child_thread_params.h"
+#include "content/common/resource_messages.h"
+#include "content/common/websocket_messages.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_switches.h"
@@ -12,19 +18,170 @@
#include "content/renderer/render_process_impl.h"
#include "content/renderer/render_thread_impl.h"
#include "content/test/mock_render_process.h"
+#include "content/test/render_thread_impl_browser_test_ipc_helper.h"
+#include "gpu/GLES2/gl2extchromium.h"
#include "testing/gtest/include/gtest/gtest.h"
+// IPC messages for testing ----------------------------------------------------
+
+#define IPC_MESSAGE_IMPL
+#include "ipc/ipc_message_macros.h"
+
+#undef IPC_MESSAGE_START
+#define IPC_MESSAGE_START TestMsgStart
+IPC_MESSAGE_CONTROL0(TestMsg_QuitRunLoop)
+
+// -----------------------------------------------------------------------------
+
+// These tests leak memory, this macro disables the test when under the
+// LeakSanitizer.
+#ifdef LEAK_SANITIZER
+#define WILL_LEAK(NAME) DISABLED_##NAME
+#else
+#define WILL_LEAK(NAME) NAME
+#endif
+
namespace content {
namespace {
-class RenderThreadImplBrowserTest : public testing::Test {
+// FIXME: It would be great if there was a reusable mock SingleThreadTaskRunner
+class TestTaskCounter : public base::SingleThreadTaskRunner {
+ public:
+ TestTaskCounter() : count_(0) {}
+
+ // SingleThreadTaskRunner implementation.
+ bool PostDelayedTask(const tracked_objects::Location&,
+ const base::Closure&,
+ base::TimeDelta) override {
+ base::AutoLock auto_lock(lock_);
+ count_++;
+ return true;
+ }
+
+ bool PostNonNestableDelayedTask(const tracked_objects::Location&,
+ const base::Closure&,
+ base::TimeDelta) override {
+ base::AutoLock auto_lock(lock_);
+ count_++;
+ return true;
+ }
+
+ bool RunsTasksOnCurrentThread() const override { return true; }
+
+ int NumTasksPosted() const {
+ base::AutoLock auto_lock(lock_);
+ return count_;
+ }
+
+ private:
+ ~TestTaskCounter() override {}
+
+ mutable base::Lock lock_;
+ int count_;
+};
+
+#if defined(COMPILER_MSVC)
+// See explanation for other RenderViewHostImpl which is the same issue.
+#pragma warning(push)
+#pragma warning(disable: 4250)
+#endif
+
+class RenderThreadImplForTest : public RenderThreadImpl {
+ public:
+ RenderThreadImplForTest(const InProcessChildThreadParams& params,
+ scoped_refptr<TestTaskCounter> test_task_counter)
+ : RenderThreadImpl(params), test_task_counter_(test_task_counter) {}
+
+ ~RenderThreadImplForTest() override {}
+
+ void SetResourceDispatchTaskQueue(
+ const scoped_refptr<base::SingleThreadTaskRunner>&) override {
+ // Use our TestTaskCounter instead.
+ RenderThreadImpl::SetResourceDispatchTaskQueue(test_task_counter_);
+ }
+
+ using ChildThreadImpl::OnMessageReceived;
+
+ private:
+ scoped_refptr<TestTaskCounter> test_task_counter_;
+};
+
+#if defined(COMPILER_MSVC)
+#pragma warning(pop)
+#endif
+
+void QuitTask(base::MessageLoop* message_loop) {
+ message_loop->QuitWhenIdle();
+}
+
+class QuitOnTestMsgFilter : public IPC::MessageFilter {
public:
- ~RenderThreadImplBrowserTest() override {}
+ explicit QuitOnTestMsgFilter(base::MessageLoop* message_loop)
+ : message_loop_(message_loop) {}
+
+ // IPC::MessageFilter overrides:
+ bool OnMessageReceived(const IPC::Message& message) override {
+ message_loop_->PostTask(FROM_HERE, base::Bind(&QuitTask, message_loop_));
+ return true;
+ }
+
+ bool GetSupportedMessageClasses(
+ std::vector<uint32>* supported_message_classes) const override {
+ supported_message_classes->push_back(TestMsgStart);
+ return true;
+ }
+
+ private:
+ ~QuitOnTestMsgFilter() override {}
+
+ base::MessageLoop* message_loop_;
};
-class DummyListener : public IPC::Listener {
+class RenderThreadImplBrowserTest : public testing::Test {
public:
- bool OnMessageReceived(const IPC::Message& message) override { return true; }
+ void SetUp() override {
+ content_client_.reset(new ContentClient());
+ content_browser_client_.reset(new ContentBrowserClient());
+ content_renderer_client_.reset(new ContentRendererClient());
+ SetContentClient(content_client_.get());
+ SetBrowserClientForTesting(content_browser_client_.get());
+ SetRendererClientForTesting(content_renderer_client_.get());
+
+ test_helper_.reset(new RenderThreadImplBrowserIPCTestHelper());
+
+ mock_process_.reset(new MockRenderProcess);
+ test_task_counter_ = make_scoped_refptr(new TestTaskCounter());
+
+ // RenderThreadImpl expects the browser to pass these flags.
+ base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
+ base::CommandLine::StringVector old_argv = cmd->argv();
+
+ cmd->AppendSwitchASCII(switches::kNumRasterThreads, "1");
+ cmd->AppendSwitchASCII(switches::kUseImageTextureTarget,
+ base::UintToString(GL_TEXTURE_2D));
+
+ thread_ = new RenderThreadImplForTest(
+ InProcessChildThreadParams(test_helper_->GetChannelId(),
+ test_helper_->GetIOTaskRunner()),
+ test_task_counter_);
+ cmd->InitFromArgv(old_argv);
+
+ thread_->EnsureWebKitInitialized();
+
+ test_msg_filter_ = make_scoped_refptr(
+ new QuitOnTestMsgFilter(test_helper_->GetMessageLoop()));
+ thread_->AddFilter(test_msg_filter_.get());
+ }
+
+ scoped_refptr<TestTaskCounter> test_task_counter_;
+ scoped_ptr<ContentClient> content_client_;
+ scoped_ptr<ContentBrowserClient> content_browser_client_;
+ scoped_ptr<ContentRendererClient> content_renderer_client_;
+ scoped_ptr<RenderThreadImplBrowserIPCTestHelper> test_helper_;
+ scoped_ptr<MockRenderProcess> mock_process_;
+ scoped_refptr<QuitOnTestMsgFilter> test_msg_filter_;
+ RenderThreadImplForTest* thread_; // Owned by mock_process_.
+ std::string channel_id_;
};
void CheckRenderThreadInputHandlerManager(RenderThreadImpl* thread) {
@@ -34,98 +191,35 @@ void CheckRenderThreadInputHandlerManager(RenderThreadImpl* thread) {
// Check that InputHandlerManager outlives compositor thread because it uses
// raw pointers to post tasks.
// Disabled under LeakSanitizer due to memory leaks. http://crbug.com/348994
-#if defined(LEAK_SANITIZER)
-#define MAYBE_InputHandlerManagerDestroyedAfterCompositorThread \
- DISABLED_InputHandlerManagerDestroyedAfterCompositorThread
-#else
-#define MAYBE_InputHandlerManagerDestroyedAfterCompositorThread \
- InputHandlerManagerDestroyedAfterCompositorThread
-#endif
TEST_F(RenderThreadImplBrowserTest,
- MAYBE_InputHandlerManagerDestroyedAfterCompositorThread) {
- ContentClient content_client;
- ContentBrowserClient content_browser_client;
- ContentRendererClient content_renderer_client;
- SetContentClient(&content_client);
- SetBrowserClientForTesting(&content_browser_client);
- SetRendererClientForTesting(&content_renderer_client);
- base::MessageLoopForIO message_loop_;
-
- std::string channel_id = IPC::Channel::GenerateVerifiedChannelID(
- std::string());
- DummyListener dummy_listener;
- scoped_ptr<IPC::Channel> channel(
- IPC::Channel::CreateServer(channel_id, &dummy_listener));
- ASSERT_TRUE(channel->Connect());
-
- scoped_ptr<MockRenderProcess> mock_process(new MockRenderProcess);
- // Owned by mock_process.
- RenderThreadImpl* thread = new RenderThreadImpl(channel_id);
- thread->EnsureWebKitInitialized();
+ WILL_LEAK(InputHandlerManagerDestroyedAfterCompositorThread)) {
+ ASSERT_TRUE(thread_->input_handler_manager());
- ASSERT_TRUE(thread->input_handler_manager());
-
- thread->compositor_message_loop_proxy()->PostTask(
- FROM_HERE,
- base::Bind(&CheckRenderThreadInputHandlerManager, thread));
+ thread_->compositor_message_loop_proxy()->PostTask(
+ FROM_HERE, base::Bind(&CheckRenderThreadInputHandlerManager, thread_));
}
-// Checks that emulated discardable memory is discarded when the last widget
-// is hidden.
// Disabled under LeakSanitizer due to memory leaks.
-#if defined(LEAK_SANITIZER)
-#define MAYBE_EmulatedDiscardableMemoryDiscardedWhenWidgetsHidden \
- DISABLED_EmulatedDiscardableMemoryDiscardedWhenWidgetsHidden
-#else
-#define MAYBE_EmulatedDiscardableMemoryDiscardedWhenWidgetsHidden \
- EmulatedDiscardableMemoryDiscardedWhenWidgetsHidden
-#endif
TEST_F(RenderThreadImplBrowserTest,
- MAYBE_EmulatedDiscardableMemoryDiscardedWhenWidgetsHidden) {
- ContentClient content_client;
- ContentBrowserClient content_browser_client;
- ContentRendererClient content_renderer_client;
- SetContentClient(&content_client);
- SetBrowserClientForTesting(&content_browser_client);
- SetRendererClientForTesting(&content_renderer_client);
- base::MessageLoopForIO message_loop_;
-
- std::string channel_id =
- IPC::Channel::GenerateVerifiedChannelID(std::string());
- DummyListener dummy_listener;
- scoped_ptr<IPC::Channel> channel(
- IPC::Channel::CreateServer(channel_id, &dummy_listener));
- ASSERT_TRUE(channel->Connect());
-
- scoped_ptr<MockRenderProcess> mock_process(new MockRenderProcess);
- // Owned by mock_process.
- RenderThreadImpl* thread = new RenderThreadImpl(channel_id);
- thread->EnsureWebKitInitialized();
- thread->WidgetCreated();
-
- // Allocate 128MB of discardable memory.
- ScopedVector<base::DiscardableMemory> discardable_memory;
- for (int i = 0; i < 32; ++i) {
- discardable_memory.push_back(
- base::DiscardableMemory::CreateLockedMemoryWithType(
- base::DISCARDABLE_MEMORY_TYPE_EMULATED, 4 * 1024 * 1024).release());
- ASSERT_TRUE(discardable_memory.back());
- discardable_memory.back()->Unlock();
- }
+ WILL_LEAK(ResourceDispatchIPCTasksGoThroughScheduler)) {
+ test_helper_->Sender()->Send(new ResourceHostMsg_FollowRedirect(0));
+ test_helper_->Sender()->Send(new TestMsg_QuitRunLoop());
- // Hide all widgets.
- thread->WidgetHidden();
+ test_helper_->GetMessageLoop()->Run();
+ EXPECT_EQ(1, test_task_counter_->NumTasksPosted());
+}
- // Count how much memory is left, should be at most one block.
- int blocks_left = 0;
- for (auto iter = discardable_memory.begin(); iter != discardable_memory.end();
- ++iter) {
- if ((*iter)->Lock() == base::DISCARDABLE_MEMORY_LOCK_STATUS_SUCCESS)
- ++blocks_left;
- }
- EXPECT_LE(blocks_left, 1);
+// Disabled under LeakSanitizer due to memory leaks.
+TEST_F(RenderThreadImplBrowserTest,
+ WILL_LEAK(NonResourceDispatchIPCTasksDontGoThroughScheduler)) {
+ // NOTE other than not being a resource message, the actual message is
+ // unimportant.
+ test_helper_->Sender()->Send(new WebSocketMsg_NotifyFailure(1, ""));
+ test_helper_->Sender()->Send(new TestMsg_QuitRunLoop());
+
+ test_helper_->GetMessageLoop()->Run();
- thread->WidgetDestroyed();
+ EXPECT_EQ(0, test_task_counter_->NumTasksPosted());
}
} // namespace
diff --git a/chromium/content/renderer/render_view_browsertest.cc b/chromium/content/renderer/render_view_browsertest.cc
index 7dc2da83b50..bf2f15de09c 100644
--- a/chromium/content/renderer/render_view_browsertest.cc
+++ b/chromium/content/renderer/render_view_browsertest.cc
@@ -19,6 +19,7 @@
#include "content/public/browser/native_web_keyboard_event.h"
#include "content/public/browser/web_ui_controller_factory.h"
#include "content/public/common/bindings_policy.h"
+#include "content/public/common/content_switches.h"
#include "content/public/common/page_zoom.h"
#include "content/public/common/url_constants.h"
#include "content/public/common/url_utils.h"
@@ -30,8 +31,10 @@
#include "content/public/test/render_view_test.h"
#include "content/public/test/test_utils.h"
#include "content/renderer/accessibility/renderer_accessibility.h"
+#include "content/renderer/devtools/devtools_agent.h"
#include "content/renderer/history_controller.h"
#include "content/renderer/history_serialization.h"
+#include "content/renderer/navigation_state_impl.h"
#include "content/renderer/render_process.h"
#include "content/renderer/render_view_impl.h"
#include "content/shell/browser/shell.h"
@@ -46,20 +49,18 @@
#include "third_party/WebKit/public/platform/WebURLResponse.h"
#include "third_party/WebKit/public/web/WebDataSource.h"
#include "third_party/WebKit/public/web/WebDeviceEmulationParams.h"
+#include "third_party/WebKit/public/web/WebHistoryCommitType.h"
#include "third_party/WebKit/public/web/WebHistoryItem.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
#include "third_party/WebKit/public/web/WebPerformance.h"
#include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
#include "third_party/WebKit/public/web/WebView.h"
#include "third_party/WebKit/public/web/WebWindowFeatures.h"
+#include "ui/events/event.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/codec/jpeg_codec.h"
#include "ui/gfx/range/range.h"
-#if defined(USE_AURA)
-#include "ui/events/event.h"
-#endif
-
#if defined(USE_AURA) && defined(USE_X11)
#include <X11/Xlib.h>
#include "ui/events/event_constants.h"
@@ -187,30 +188,18 @@ class RenderViewImplTest : public RenderViewTest {
// WM_KEYDOWN and WM_KEYUP sends virtual-key codes. On the other hand,
// WM_CHAR sends a composed Unicode character.
MSG msg1 = { NULL, WM_KEYDOWN, key_code, 0 };
-#if defined(USE_AURA)
ui::KeyEvent evt1(msg1);
- NativeWebKeyboardEvent keydown_event(&evt1);
-#else
- NativeWebKeyboardEvent keydown_event(msg1);
-#endif
+ NativeWebKeyboardEvent keydown_event(evt1);
SendNativeKeyEvent(keydown_event);
MSG msg2 = { NULL, WM_CHAR, (*output)[0], 0 };
-#if defined(USE_AURA)
ui::KeyEvent evt2(msg2);
- NativeWebKeyboardEvent char_event(&evt2);
-#else
- NativeWebKeyboardEvent char_event(msg2);
-#endif
+ NativeWebKeyboardEvent char_event(evt2);
SendNativeKeyEvent(char_event);
MSG msg3 = { NULL, WM_KEYUP, key_code, 0 };
-#if defined(USE_AURA)
ui::KeyEvent evt3(msg3);
- NativeWebKeyboardEvent keyup_event(&evt3);
-#else
- NativeWebKeyboardEvent keyup_event(msg3);
-#endif
+ NativeWebKeyboardEvent keyup_event(evt3);
SendNativeKeyEvent(keyup_event);
return length;
@@ -225,7 +214,7 @@ class RenderViewImplTest : public RenderViewTest {
static_cast<ui::KeyboardCode>(key_code),
flags);
ui::KeyEvent event1(xevent);
- NativeWebKeyboardEvent keydown_event(&event1);
+ NativeWebKeyboardEvent keydown_event(event1);
SendNativeKeyEvent(keydown_event);
// X11 doesn't actually have native character events, but give the test
@@ -238,14 +227,14 @@ class RenderViewImplTest : public RenderViewTest {
event2.flags()));
ui::KeyEventTestApi test_event2(&event2);
test_event2.set_is_char(true);
- NativeWebKeyboardEvent char_event(&event2);
+ NativeWebKeyboardEvent char_event(event2);
SendNativeKeyEvent(char_event);
xevent.InitKeyEvent(ui::ET_KEY_RELEASED,
static_cast<ui::KeyboardCode>(key_code),
flags);
ui::KeyEvent event3(xevent);
- NativeWebKeyboardEvent keyup_event(&event3);
+ NativeWebKeyboardEvent keyup_event(event3);
SendNativeKeyEvent(keyup_event);
long c = GetCharacterFromKeyCode(static_cast<ui::KeyboardCode>(key_code),
@@ -258,19 +247,19 @@ class RenderViewImplTest : public RenderViewTest {
ui::KeyEvent keydown_event(ui::ET_KEY_PRESSED,
static_cast<ui::KeyboardCode>(key_code),
flags);
- NativeWebKeyboardEvent keydown_web_event(&keydown_event);
+ NativeWebKeyboardEvent keydown_web_event(keydown_event);
SendNativeKeyEvent(keydown_web_event);
ui::KeyEvent char_event(keydown_event.GetCharacter(),
static_cast<ui::KeyboardCode>(key_code),
flags);
- NativeWebKeyboardEvent char_web_event(&char_event);
+ NativeWebKeyboardEvent char_web_event(char_event);
SendNativeKeyEvent(char_web_event);
ui::KeyEvent keyup_event(ui::ET_KEY_RELEASED,
static_cast<ui::KeyboardCode>(key_code),
flags);
- NativeWebKeyboardEvent keyup_web_event(&keyup_event);
+ NativeWebKeyboardEvent keyup_web_event(keyup_event);
SendNativeKeyEvent(keyup_web_event);
long c = GetCharacterFromKeyCode(static_cast<ui::KeyboardCode>(key_code),
@@ -283,10 +272,120 @@ class RenderViewImplTest : public RenderViewTest {
#endif
}
+ void EnablePreferredSizeMode() {
+ view()->OnEnablePreferredSizeChangedMode();
+ }
+
+ const gfx::Size& GetPreferredSize() {
+ view()->CheckPreferredSize();
+ return view()->preferred_size_;
+ }
+
+ void SetZoomLevel(double level) {
+ view()->OnSetZoomLevelForView(false, level);
+ }
+
+ void NavigateMainFrame(const CommonNavigationParams& common_params,
+ const StartNavigationParams& start_params,
+ const RequestNavigationParams& request_params) {
+ NavigateFrame(frame(), common_params, start_params, request_params);
+ }
+
+ void NavigateFrame(RenderFrameImpl* frame,
+ const CommonNavigationParams& common_params,
+ const StartNavigationParams& start_params,
+ const RequestNavigationParams& request_params) {
+ // PlzNavigate
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation)) {
+ frame->OnCommitNavigation(ResourceResponseHead(), common_params.url,
+ common_params, request_params);
+ return;
+ }
+ frame->OnNavigate(common_params, start_params, request_params);
+ }
+
+ void SwapOut(RenderFrameImpl* frame,
+ int proxy_routing_id,
+ bool is_loading,
+ const FrameReplicationState& replicated_frame_state) {
+ frame->OnSwapOut(proxy_routing_id, is_loading, replicated_frame_state);
+ }
+
+ void SetEditableSelectionOffsets(int start, int end) {
+ frame()->OnSetEditableSelectionOffsets(start, end);
+ }
+
+ void ExtendSelectionAndDelete(int before, int after) {
+ frame()->OnExtendSelectionAndDelete(before, after);
+ }
+
+ void Unselect() { frame()->OnUnselect(); }
+
+ void SetAccessibilityMode(AccessibilityMode new_mode) {
+ frame()->OnSetAccessibilityMode(new_mode);
+ }
+
+ void SetCompositionFromExistingText(
+ int start,
+ int end,
+ const std::vector<blink::WebCompositionUnderline>& underlines) {
+ frame()->OnSetCompositionFromExistingText(start, end, underlines);
+ }
+
private:
scoped_ptr<MockKeyboard> mock_keyboard_;
};
+class DevToolsAgentTest : public RenderViewImplTest {
+ public:
+ void Attach() {
+ std::string host_id = "host_id";
+ agent()->OnAttach(host_id);
+ }
+
+ void Detach() {
+ agent()->OnDetach();
+ }
+
+ bool IsPaused() {
+ return agent()->paused_;
+ }
+
+ void DispatchDevToolsMessage(const std::string& message) {
+ agent()->OnDispatchOnInspectorBackend(message);
+ }
+
+ void CloseWhilePaused() {
+ EXPECT_TRUE(IsPaused());
+ view()->NotifyOnClose();
+ }
+
+ private:
+ DevToolsAgent* agent() {
+ return frame()->devtools_agent();
+ }
+};
+
+// Ensure that the main RenderFrame is deleted and cleared from the RenderView
+// after closing it.
+TEST_F(RenderViewImplTest, RenderFrameClearedAfterClose) {
+ // Create a new main frame RenderFrame so that we don't interfere with the
+ // shutdown of frame() in RenderViewTest.TearDown.
+ blink::WebURLRequest popup_request(GURL("http://foo.com"));
+ blink::WebView* new_web_view = view()->createView(
+ GetMainFrame(), popup_request, blink::WebWindowFeatures(), "foo",
+ blink::WebNavigationPolicyNewForegroundTab, false);
+ RenderViewImpl* new_view = RenderViewImpl::FromWebView(new_web_view);
+
+ // Close the view, causing the main RenderFrame to be detached and deleted.
+ new_view->Close();
+ EXPECT_FALSE(new_view->GetMainRenderFrame());
+
+ // Clean up after the new view so we don't leak it.
+ new_view->Release();
+}
+
TEST_F(RenderViewImplTest, SaveImageFromDataURL) {
const IPC::Message* msg1 = render_thread_->sink().GetFirstMessageMatching(
ViewHostMsg_SaveImageFromDataURL::ID);
@@ -304,8 +403,8 @@ TEST_F(RenderViewImplTest, SaveImageFromDataURL) {
ViewHostMsg_SaveImageFromDataURL::Param param1;
ViewHostMsg_SaveImageFromDataURL::Read(msg2, &param1);
- EXPECT_EQ(param1.b.length(), image_data_url.length());
- EXPECT_EQ(param1.b, image_data_url);
+ EXPECT_EQ(get<1>(param1).length(), image_data_url.length());
+ EXPECT_EQ(get<1>(param1), image_data_url);
ProcessPendingMessages();
render_thread_->sink().ClearMessages();
@@ -320,8 +419,8 @@ TEST_F(RenderViewImplTest, SaveImageFromDataURL) {
ViewHostMsg_SaveImageFromDataURL::Param param2;
ViewHostMsg_SaveImageFromDataURL::Read(msg3, &param2);
- EXPECT_EQ(param2.b.length(), large_data_url.length());
- EXPECT_EQ(param2.b, large_data_url);
+ EXPECT_EQ(get<1>(param2).length(), large_data_url.length());
+ EXPECT_EQ(get<1>(param2), large_data_url);
ProcessPendingMessages();
render_thread_->sink().ClearMessages();
@@ -358,25 +457,24 @@ TEST_F(RenderViewImplTest, DISABLED_OnNavStateChanged) {
}
TEST_F(RenderViewImplTest, OnNavigationHttpPost) {
- FrameMsg_Navigate_Params nav_params;
-
// An http url will trigger a resource load so cannot be used here.
- nav_params.common_params.url = GURL("data:text/html,<div>Page</div>");
- nav_params.common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
- nav_params.common_params.transition = ui::PAGE_TRANSITION_TYPED;
- nav_params.page_id = -1;
- nav_params.request_params.is_post = true;
- nav_params.commit_params.browser_navigation_start =
- base::TimeTicks::FromInternalValue(1);
+ CommonNavigationParams common_params;
+ StartNavigationParams start_params;
+ RequestNavigationParams request_params;
+ common_params.url = GURL("data:text/html,<div>Page</div>");
+ common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
+ common_params.transition = ui::PAGE_TRANSITION_TYPED;
+ request_params.page_id = -1;
// Set up post data.
const unsigned char* raw_data = reinterpret_cast<const unsigned char*>(
"post \0\ndata");
const unsigned int length = 11;
const std::vector<unsigned char> post_data(raw_data, raw_data + length);
- nav_params.request_params.browser_initiated_post_data = post_data;
+ start_params.is_post = true;
+ start_params.browser_initiated_post_data = post_data;
- frame()->OnNavigate(nav_params);
+ NavigateMainFrame(common_params, start_params, request_params);
ProcessPendingMessages();
const IPC::Message* frame_navigate_msg =
@@ -387,12 +485,12 @@ TEST_F(RenderViewImplTest, OnNavigationHttpPost) {
FrameHostMsg_DidCommitProvisionalLoad::Param host_nav_params;
FrameHostMsg_DidCommitProvisionalLoad::Read(frame_navigate_msg,
&host_nav_params);
- EXPECT_TRUE(host_nav_params.a.is_post);
+ EXPECT_TRUE(get<0>(host_nav_params).is_post);
// Check post data sent to browser matches
- EXPECT_TRUE(host_nav_params.a.page_state.IsValid());
+ EXPECT_TRUE(get<0>(host_nav_params).page_state.IsValid());
scoped_ptr<HistoryEntry> entry =
- PageStateToHistoryEntry(host_nav_params.a.page_state);
+ PageStateToHistoryEntry(get<0>(host_nav_params).page_state);
blink::WebHTTPBody body = entry->root().httpBody();
blink::WebHTTPBody::Element element;
bool successful = body.elementAt(0, element);
@@ -407,7 +505,7 @@ TEST_F(RenderViewImplTest, DecideNavigationPolicy) {
WebUIControllerFactory::RegisterFactory(&factory);
DocumentState state;
- state.set_navigation_state(NavigationState::CreateContentInitiated());
+ state.set_navigation_state(NavigationStateImpl::CreateContentInitiated());
// Navigations to normal HTTP URLs can be handled locally.
blink::WebURLRequest request(GURL("http://foo.com"));
@@ -444,7 +542,7 @@ TEST_F(RenderViewImplTest, DecideNavigationPolicy) {
TEST_F(RenderViewImplTest, DecideNavigationPolicyHandlesAllTopLevel) {
DocumentState state;
- state.set_navigation_state(NavigationState::CreateContentInitiated());
+ state.set_navigation_state(NavigationStateImpl::CreateContentInitiated());
RendererPreferences prefs = view()->renderer_preferences();
prefs.browser_handles_all_top_level_requests = true;
@@ -479,7 +577,7 @@ TEST_F(RenderViewImplTest, DecideNavigationPolicyForWebUI) {
view()->OnAllowBindings(BINDINGS_POLICY_WEB_UI);
DocumentState state;
- state.set_navigation_state(NavigationState::CreateContentInitiated());
+ state.set_navigation_state(NavigationStateImpl::CreateContentInitiated());
// Navigations to normal HTTP URLs will be sent to browser process.
blink::WebURLRequest request(GURL("http://foo.com"));
@@ -546,7 +644,7 @@ TEST_F(RenderViewImplTest, SendSwapOutACK) {
RenderProcess::current()->AddRefProcess();
// Respond to a swap out request.
- view()->GetMainRenderFrame()->OnSwapOut(kProxyRoutingId);
+ SwapOut(frame(), kProxyRoutingId, true, content::FrameReplicationState());
// Ensure the swap out commits synchronously.
EXPECT_NE(initial_page_id, view_page_id());
@@ -559,24 +657,23 @@ TEST_F(RenderViewImplTest, SendSwapOutACK) {
// It is possible to get another swap out request. Ensure that we send
// an ACK, even if we don't have to do anything else.
render_thread_->sink().ClearMessages();
- view()->GetMainRenderFrame()->OnSwapOut(kProxyRoutingId);
+ SwapOut(frame(), kProxyRoutingId, false, content::FrameReplicationState());
const IPC::Message* msg2 = render_thread_->sink().GetUniqueMessageMatching(
FrameHostMsg_SwapOut_ACK::ID);
ASSERT_TRUE(msg2);
// If we navigate back to this RenderView, ensure we don't send a state
// update for the swapped out URL. (http://crbug.com/72235)
- FrameMsg_Navigate_Params nav_params;
- nav_params.common_params.url = GURL("data:text/html,<div>Page B</div>");
- nav_params.common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
- nav_params.common_params.transition = ui::PAGE_TRANSITION_TYPED;
- nav_params.current_history_list_length = 1;
- nav_params.current_history_list_offset = 0;
- nav_params.pending_history_list_offset = 1;
- nav_params.page_id = -1;
- nav_params.commit_params.browser_navigation_start =
- base::TimeTicks::FromInternalValue(1);
- frame()->OnNavigate(nav_params);
+ CommonNavigationParams common_params;
+ RequestNavigationParams request_params;
+ common_params.url = GURL("data:text/html,<div>Page B</div>");
+ common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
+ common_params.transition = ui::PAGE_TRANSITION_TYPED;
+ request_params.current_history_list_length = 1;
+ request_params.current_history_list_offset = 0;
+ request_params.pending_history_list_offset = 1;
+ request_params.page_id = -1;
+ NavigateMainFrame(common_params, StartNavigationParams(), request_params);
ProcessPendingMessages();
const IPC::Message* msg3 = render_thread_->sink().GetUniqueMessageMatching(
ViewHostMsg_UpdateState::ID);
@@ -599,27 +696,30 @@ TEST_F(RenderViewImplTest, ReloadWhileSwappedOut) {
ASSERT_TRUE(msg_A);
ViewHostMsg_UpdateState::Param params;
ViewHostMsg_UpdateState::Read(msg_A, &params);
- int page_id_A = params.a;
- PageState state_A = params.b;
+ int page_id_A = get<0>(params);
+ PageState state_A = get<1>(params);
EXPECT_EQ(1, page_id_A);
render_thread_->sink().ClearMessages();
// Back to page A (page_id 1) and commit.
- FrameMsg_Navigate_Params params_A;
- params_A.common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
- params_A.common_params.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
- params_A.current_history_list_length = 2;
- params_A.current_history_list_offset = 1;
- params_A.pending_history_list_offset = 0;
- params_A.page_id = 1;
- params_A.commit_params.page_state = state_A;
- params_A.commit_params.browser_navigation_start =
- base::TimeTicks::FromInternalValue(1);
- frame()->OnNavigate(params_A);
+ CommonNavigationParams common_params_A;
+ RequestNavigationParams request_params_A;
+ common_params_A.navigation_type = FrameMsg_Navigate_Type::NORMAL;
+ common_params_A.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
+ request_params_A.current_history_list_length = 2;
+ request_params_A.current_history_list_offset = 1;
+ request_params_A.pending_history_list_offset = 0;
+ request_params_A.page_id = 1;
+ request_params_A.nav_entry_id = 1;
+ request_params_A.page_state = state_A;
+ NavigateMainFrame(common_params_A, StartNavigationParams(), request_params_A);
+ EXPECT_EQ(1, view()->historyBackListCount());
+ EXPECT_EQ(2, view()->historyBackListCount() +
+ view()->historyForwardListCount() + 1);
ProcessPendingMessages();
// Respond to a swap out request.
- view()->GetMainRenderFrame()->OnSwapOut(kProxyRoutingId);
+ SwapOut(frame(), kProxyRoutingId, true, content::FrameReplicationState());
// Check for a OnSwapOutACK.
const IPC::Message* msg = render_thread_->sink().GetUniqueMessageMatching(
@@ -631,18 +731,18 @@ TEST_F(RenderViewImplTest, ReloadWhileSwappedOut) {
// params.page_state of the initial page (e.g., if the new page fails the
// provisional load in the renderer process, after we unload the old page).
// Ensure the old page gets reloaded, not swappedout://.
- FrameMsg_Navigate_Params nav_params;
- nav_params.common_params.url = GURL("data:text/html,<div>Page A</div>");
- nav_params.common_params.navigation_type = FrameMsg_Navigate_Type::RELOAD;
- nav_params.common_params.transition = ui::PAGE_TRANSITION_RELOAD;
- nav_params.current_history_list_length = 2;
- nav_params.current_history_list_offset = 0;
- nav_params.pending_history_list_offset = 0;
- nav_params.page_id = 1;
- nav_params.commit_params.page_state = state_A;
- nav_params.commit_params.browser_navigation_start =
- base::TimeTicks::FromInternalValue(1);
- frame()->OnNavigate(nav_params);
+ CommonNavigationParams common_params;
+ RequestNavigationParams request_params;
+ common_params.url = GURL("data:text/html,<div>Page A</div>");
+ common_params.navigation_type = FrameMsg_Navigate_Type::RELOAD;
+ common_params.transition = ui::PAGE_TRANSITION_RELOAD;
+ request_params.current_history_list_length = 2;
+ request_params.current_history_list_offset = 0;
+ request_params.pending_history_list_offset = 0;
+ request_params.page_id = 1;
+ request_params.nav_entry_id = 1;
+ request_params.page_state = state_A;
+ NavigateMainFrame(common_params, StartNavigationParams(), request_params);
ProcessPendingMessages();
// Verify page A committed, not swappedout://.
@@ -652,12 +752,51 @@ TEST_F(RenderViewImplTest, ReloadWhileSwappedOut) {
EXPECT_TRUE(frame_navigate_msg);
// Read URL out of the parent trait of the params object.
- FrameHostMsg_DidCommitProvisionalLoad::Param commit_params;
+ FrameHostMsg_DidCommitProvisionalLoad::Param commit_load_params;
FrameHostMsg_DidCommitProvisionalLoad::Read(frame_navigate_msg,
- &commit_params);
- EXPECT_NE(GURL("swappedout://"), commit_params.a.url);
+ &commit_load_params);
+ EXPECT_NE(GURL("swappedout://"), get<0>(commit_load_params).url);
}
+// Verify that security origins are replicated properly to RenderFrameProxies
+// when swapping out.
+TEST_F(RenderViewImplTest, OriginReplicationForSwapOut) {
+ // This test should only run with --site-per-process, since origin
+ // replication only happens in that mode.
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess))
+ return;
+
+ LoadHTML(
+ "Hello <iframe src='data:text/html,frame 1'></iframe>"
+ "<iframe src='data:text/html,frame 2'></iframe>");
+ WebFrame* web_frame = frame()->GetWebFrame();
+ RenderFrameImpl* child_frame = static_cast<RenderFrameImpl*>(
+ RenderFrame::FromWebFrame(web_frame->firstChild()));
+
+ // Swap the child frame out and pass a serialized origin to be set for
+ // WebRemoteFrame.
+ content::FrameReplicationState replication_state;
+ replication_state.origin = url::Origin("http://foo.com");
+ SwapOut(child_frame, kProxyRoutingId, true, replication_state);
+
+ // The child frame should now be a WebRemoteFrame.
+ EXPECT_TRUE(web_frame->firstChild()->isWebRemoteFrame());
+
+ // Expect the origin to be updated properly.
+ blink::WebSecurityOrigin origin = web_frame->firstChild()->securityOrigin();
+ EXPECT_EQ(origin.toString(),
+ WebString::fromUTF8(replication_state.origin.string()));
+
+ // Now, swap out the second frame using a unique origin and verify that it is
+ // replicated correctly.
+ replication_state.origin = url::Origin();
+ RenderFrameImpl* child_frame2 = static_cast<RenderFrameImpl*>(
+ RenderFrame::FromWebFrame(web_frame->lastChild()));
+ SwapOut(child_frame2, kProxyRoutingId + 1, true, replication_state);
+ EXPECT_TRUE(web_frame->lastChild()->isWebRemoteFrame());
+ EXPECT_TRUE(web_frame->lastChild()->securityOrigin().isUnique());
+}
// Test that we get the correct UpdateState message when we go back twice
// quickly without committing. Regression test for http://crbug.com/58082.
@@ -676,8 +815,8 @@ TEST_F(RenderViewImplTest, DISABLED_LastCommittedUpdateState) {
ASSERT_TRUE(msg_A);
ViewHostMsg_UpdateState::Param param;
ViewHostMsg_UpdateState::Read(msg_A, &param);
- int page_id_A = param.a;
- PageState state_A = param.b;
+ int page_id_A = get<0>(param);
+ PageState state_A = get<1>(param);
EXPECT_EQ(1, page_id_A);
render_thread_->sink().ClearMessages();
@@ -690,8 +829,8 @@ TEST_F(RenderViewImplTest, DISABLED_LastCommittedUpdateState) {
ViewHostMsg_UpdateState::ID);
ASSERT_TRUE(msg_B);
ViewHostMsg_UpdateState::Read(msg_B, &param);
- int page_id_B = param.a;
- PageState state_B = param.b;
+ int page_id_B = get<0>(param);
+ PageState state_B = get<1>(param);
EXPECT_EQ(2, page_id_B);
EXPECT_NE(state_A, state_B);
render_thread_->sink().ClearMessages();
@@ -705,24 +844,23 @@ TEST_F(RenderViewImplTest, DISABLED_LastCommittedUpdateState) {
ViewHostMsg_UpdateState::ID);
ASSERT_TRUE(msg_C);
ViewHostMsg_UpdateState::Read(msg_C, &param);
- int page_id_C = param.a;
- PageState state_C = param.b;
+ int page_id_C = get<0>(param);
+ PageState state_C = get<1>(param);
EXPECT_EQ(3, page_id_C);
EXPECT_NE(state_B, state_C);
render_thread_->sink().ClearMessages();
// Go back to C and commit, preparing for our real test.
- FrameMsg_Navigate_Params params_C;
- params_C.common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
- params_C.common_params.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
- params_C.current_history_list_length = 4;
- params_C.current_history_list_offset = 3;
- params_C.pending_history_list_offset = 2;
- params_C.page_id = 3;
- params_C.commit_params.page_state = state_C;
- params_C.commit_params.browser_navigation_start =
- base::TimeTicks::FromInternalValue(1);
- frame()->OnNavigate(params_C);
+ CommonNavigationParams common_params_C;
+ RequestNavigationParams request_params_C;
+ common_params_C.navigation_type = FrameMsg_Navigate_Type::NORMAL;
+ common_params_C.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
+ request_params_C.current_history_list_length = 4;
+ request_params_C.current_history_list_offset = 3;
+ request_params_C.pending_history_list_offset = 2;
+ request_params_C.page_id = 3;
+ request_params_C.page_state = state_C;
+ NavigateMainFrame(common_params_C, StartNavigationParams(), request_params_C);
ProcessPendingMessages();
render_thread_->sink().ClearMessages();
@@ -731,30 +869,28 @@ TEST_F(RenderViewImplTest, DISABLED_LastCommittedUpdateState) {
// the RenderView's page ID.
// Back to page B (page_id 2), without committing.
- FrameMsg_Navigate_Params params_B;
- params_B.common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
- params_B.common_params.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
- params_B.current_history_list_length = 4;
- params_B.current_history_list_offset = 2;
- params_B.pending_history_list_offset = 1;
- params_B.page_id = 2;
- params_B.commit_params.page_state = state_B;
- params_B.commit_params.browser_navigation_start =
- base::TimeTicks::FromInternalValue(1);
- frame()->OnNavigate(params_B);
+ CommonNavigationParams common_params_B;
+ RequestNavigationParams request_params_B;
+ common_params_B.navigation_type = FrameMsg_Navigate_Type::NORMAL;
+ common_params_B.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
+ request_params_B.current_history_list_length = 4;
+ request_params_B.current_history_list_offset = 2;
+ request_params_B.pending_history_list_offset = 1;
+ request_params_B.page_id = 2;
+ request_params_B.page_state = state_B;
+ NavigateMainFrame(common_params_B, StartNavigationParams(), request_params_B);
// Back to page A (page_id 1) and commit.
- FrameMsg_Navigate_Params params;
- params.common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
- params.common_params.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
- params_B.current_history_list_length = 4;
- params_B.current_history_list_offset = 2;
- params_B.pending_history_list_offset = 0;
- params.page_id = 1;
- params.commit_params.page_state = state_A;
- params.commit_params.browser_navigation_start =
- base::TimeTicks::FromInternalValue(1);
- frame()->OnNavigate(params);
+ CommonNavigationParams common_params;
+ RequestNavigationParams request_params;
+ common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
+ common_params.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
+ request_params.current_history_list_length = 4;
+ request_params.current_history_list_offset = 2;
+ request_params.pending_history_list_offset = 0;
+ request_params.page_id = 1;
+ request_params.page_state = state_A;
+ NavigateMainFrame(common_params, StartNavigationParams(), request_params);
ProcessPendingMessages();
// Now ensure that the UpdateState message we receive is consistent
@@ -763,29 +899,26 @@ TEST_F(RenderViewImplTest, DISABLED_LastCommittedUpdateState) {
ViewHostMsg_UpdateState::ID);
ASSERT_TRUE(msg);
ViewHostMsg_UpdateState::Read(msg, &param);
- int page_id = param.a;
- PageState state = param.b;
+ int page_id = get<0>(param);
+ PageState state = get<1>(param);
EXPECT_EQ(page_id_C, page_id);
EXPECT_NE(state_A, state);
EXPECT_NE(state_B, state);
EXPECT_EQ(state_C, state);
}
-// Test that the history_page_ids_ list can reveal when a stale back/forward
-// navigation arrives from the browser and can be ignored. See
-// http://crbug.com/86758.
+// Test that stale back/forward navigations arriving from the browser are
+// ignored. See http://crbug.com/86758.
TEST_F(RenderViewImplTest, StaleNavigationsIgnored) {
// Load page A.
- LoadHTML("<div>Page A</div>");
+ LoadHTML("<div id=pagename>Page A</div>");
EXPECT_EQ(1, view()->history_list_length_);
EXPECT_EQ(0, view()->history_list_offset_);
- EXPECT_EQ(1, view()->history_page_ids_[0]);
// Load page B, which will trigger an UpdateState message for page A.
- LoadHTML("<div>Page B</div>");
+ LoadHTML("<div id=pagename>Page B</div>");
EXPECT_EQ(2, view()->history_list_length_);
EXPECT_EQ(1, view()->history_list_offset_);
- EXPECT_EQ(2, view()->history_page_ids_[1]);
// Check for a valid UpdateState message for page A.
ProcessPendingMessages();
@@ -794,118 +927,64 @@ TEST_F(RenderViewImplTest, StaleNavigationsIgnored) {
ASSERT_TRUE(msg_A);
ViewHostMsg_UpdateState::Param param;
ViewHostMsg_UpdateState::Read(msg_A, &param);
- int page_id_A = param.a;
- PageState state_A = param.b;
+ int page_id_A = get<0>(param);
+ PageState state_A = get<1>(param);
EXPECT_EQ(1, page_id_A);
render_thread_->sink().ClearMessages();
- // Back to page A (page_id 1) and commit.
- FrameMsg_Navigate_Params params_A;
- params_A.common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
- params_A.common_params.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
- params_A.current_history_list_length = 2;
- params_A.current_history_list_offset = 1;
- params_A.pending_history_list_offset = 0;
- params_A.page_id = 1;
- params_A.commit_params.page_state = state_A;
- params_A.commit_params.browser_navigation_start =
- base::TimeTicks::FromInternalValue(1);
- frame()->OnNavigate(params_A);
+ // Back to page A (nav_entry_id 1) and commit.
+ CommonNavigationParams common_params_A;
+ RequestNavigationParams request_params_A;
+ common_params_A.navigation_type = FrameMsg_Navigate_Type::NORMAL;
+ common_params_A.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
+ request_params_A.current_history_list_length = 2;
+ request_params_A.current_history_list_offset = 1;
+ request_params_A.pending_history_list_offset = 0;
+ request_params_A.page_id = 1;
+ request_params_A.nav_entry_id = 1;
+ request_params_A.page_state = state_A;
+ NavigateMainFrame(common_params_A, StartNavigationParams(), request_params_A);
ProcessPendingMessages();
// A new navigation commits, clearing the forward history.
- LoadHTML("<div>Page C</div>");
+ LoadHTML("<div id=pagename>Page C</div>");
EXPECT_EQ(2, view()->history_list_length_);
EXPECT_EQ(1, view()->history_list_offset_);
- EXPECT_EQ(3, view()->history_page_ids_[1]);
+ EXPECT_EQ(3, view()->page_id_); // page C is now page id 3
+ int was_page_c = -1;
+ base::string16 check_page_c = base::ASCIIToUTF16(
+ "Number(document.getElementById('pagename').innerHTML == 'Page C')");
+ EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c, &was_page_c));
+ EXPECT_EQ(1, was_page_c);
// The browser then sends a stale navigation to B, which should be ignored.
- FrameMsg_Navigate_Params params_B;
- params_B.common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
- params_B.common_params.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
- params_B.current_history_list_length = 2;
- params_B.current_history_list_offset = 0;
- params_B.pending_history_list_offset = 1;
- params_B.page_id = 2;
- params_B.commit_params.page_state =
+ CommonNavigationParams common_params_B;
+ RequestNavigationParams request_params_B;
+ common_params_B.navigation_type = FrameMsg_Navigate_Type::NORMAL;
+ common_params_B.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
+ request_params_B.current_history_list_length = 2;
+ request_params_B.current_history_list_offset = 0;
+ request_params_B.pending_history_list_offset = 1;
+ request_params_B.page_id = 2;
+ request_params_B.nav_entry_id = 2;
+ request_params_B.page_state =
state_A; // Doesn't matter, just has to be present.
- params_B.commit_params.browser_navigation_start =
- base::TimeTicks::FromInternalValue(1);
- frame()->OnNavigate(params_B);
+ NavigateMainFrame(common_params_B, StartNavigationParams(), request_params_B);
// State should be unchanged.
EXPECT_EQ(2, view()->history_list_length_);
EXPECT_EQ(1, view()->history_list_offset_);
- EXPECT_EQ(3, view()->history_page_ids_[1]);
-}
-
-// Test that we do not ignore navigations after the entry limit is reached,
-// in which case the browser starts dropping entries from the front. In this
-// case, we'll see a page_id mismatch but the RenderView's id will be older,
-// not newer, than params.page_id. Use this as a cue that we should update the
-// state and not treat it like a navigation to a cropped forward history item.
-// See http://crbug.com/89798.
-TEST_F(RenderViewImplTest, DontIgnoreBackAfterNavEntryLimit) {
- // Load page A.
- LoadHTML("<div>Page A</div>");
- EXPECT_EQ(1, view()->history_list_length_);
- EXPECT_EQ(0, view()->history_list_offset_);
- EXPECT_EQ(1, view()->history_page_ids_[0]);
-
- // Load page B, which will trigger an UpdateState message for page A.
- LoadHTML("<div>Page B</div>");
- EXPECT_EQ(2, view()->history_list_length_);
- EXPECT_EQ(1, view()->history_list_offset_);
- EXPECT_EQ(2, view()->history_page_ids_[1]);
-
- // Check for a valid UpdateState message for page A.
- ProcessPendingMessages();
- const IPC::Message* msg_A = render_thread_->sink().GetUniqueMessageMatching(
- ViewHostMsg_UpdateState::ID);
- ASSERT_TRUE(msg_A);
- ViewHostMsg_UpdateState::Param param;
- ViewHostMsg_UpdateState::Read(msg_A, &param);
- int page_id_A = param.a;
- PageState state_A = param.b;
- EXPECT_EQ(1, page_id_A);
- render_thread_->sink().ClearMessages();
-
- // Load page C, which will trigger an UpdateState message for page B.
- LoadHTML("<div>Page C</div>");
- EXPECT_EQ(3, view()->history_list_length_);
- EXPECT_EQ(2, view()->history_list_offset_);
- EXPECT_EQ(3, view()->history_page_ids_[2]);
+ EXPECT_EQ(3, view()->page_id_); // page C, not page B
+ was_page_c = -1;
+ EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c, &was_page_c));
+ EXPECT_EQ(1, was_page_c);
- // Check for a valid UpdateState message for page B.
+ // Check for a valid DidDropNavigation message.
ProcessPendingMessages();
- const IPC::Message* msg_B = render_thread_->sink().GetUniqueMessageMatching(
- ViewHostMsg_UpdateState::ID);
- ASSERT_TRUE(msg_B);
- ViewHostMsg_UpdateState::Read(msg_B, &param);
- int page_id_B = param.a;
- PageState state_B = param.b;
- EXPECT_EQ(2, page_id_B);
+ const IPC::Message* msg = render_thread_->sink().GetUniqueMessageMatching(
+ FrameHostMsg_DidDropNavigation::ID);
+ ASSERT_TRUE(msg);
render_thread_->sink().ClearMessages();
-
- // Suppose the browser has limited the number of NavigationEntries to 2.
- // It has now dropped the first entry, but the renderer isn't notified.
- // Ensure that going back to page B (page_id 2) at offset 0 is successful.
- FrameMsg_Navigate_Params params_B;
- params_B.common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
- params_B.common_params.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
- params_B.current_history_list_length = 2;
- params_B.current_history_list_offset = 1;
- params_B.pending_history_list_offset = 0;
- params_B.page_id = 2;
- params_B.commit_params.page_state = state_B;
- params_B.commit_params.browser_navigation_start =
- base::TimeTicks::FromInternalValue(1);
- frame()->OnNavigate(params_B);
- ProcessPendingMessages();
-
- EXPECT_EQ(2, view()->history_list_length_);
- EXPECT_EQ(0, view()->history_list_offset_);
- EXPECT_EQ(2, view()->history_page_ids_[0]);
}
// Test that our IME backend sends a notification message when the input focus
@@ -978,9 +1057,9 @@ TEST_F(RenderViewImplTest, OnImeTypeChanged) {
EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID, msg->type());
ViewHostMsg_TextInputTypeChanged::Param params;
ViewHostMsg_TextInputTypeChanged::Read(msg, &params);
- ui::TextInputType type = params.a;
- ui::TextInputMode input_mode = params.b;
- bool can_compose_inline = params.c;
+ ui::TextInputType type = get<0>(params);
+ ui::TextInputMode input_mode = get<1>(params);
+ bool can_compose_inline = get<2>(params);
EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, type);
EXPECT_EQ(true, can_compose_inline);
@@ -997,8 +1076,8 @@ TEST_F(RenderViewImplTest, OnImeTypeChanged) {
EXPECT_TRUE(msg != NULL);
EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID, msg->type());
ViewHostMsg_TextInputTypeChanged::Read(msg, & params);
- type = params.a;
- input_mode = params.b;
+ type = get<0>(params);
+ input_mode = get<1>(params);
EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, type);
for (size_t i = 0; i < arraysize(kInputModeTestCases); i++) {
@@ -1019,8 +1098,8 @@ TEST_F(RenderViewImplTest, OnImeTypeChanged) {
EXPECT_TRUE(msg != NULL);
EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID, msg->type());
ViewHostMsg_TextInputTypeChanged::Read(msg, & params);
- type = params.a;
- input_mode = params.b;
+ type = get<0>(params);
+ input_mode = get<1>(params);
EXPECT_EQ(test_case->expected_mode, input_mode);
}
}
@@ -1605,16 +1684,15 @@ TEST_F(RenderViewImplTest, DISABLED_DidFailProvisionalLoadWithErrorForError) {
// Start a load that will reach provisional state synchronously,
// but won't complete synchronously.
- FrameMsg_Navigate_Params params;
- params.page_id = -1;
- params.common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
- params.common_params.url = GURL("data:text/html,test data");
- params.commit_params.browser_navigation_start =
- base::TimeTicks::FromInternalValue(1);
- frame()->OnNavigate(params);
+ CommonNavigationParams common_params;
+ common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
+ common_params.url = GURL("data:text/html,test data");
+ NavigateMainFrame(common_params, StartNavigationParams(),
+ RequestNavigationParams());
// An error occurred.
- view()->GetMainRenderFrame()->didFailProvisionalLoad(web_frame, error);
+ view()->GetMainRenderFrame()->didFailProvisionalLoad(
+ web_frame, error, blink::WebStandardCommit);
// Frame should exit view-source mode.
EXPECT_FALSE(web_frame->isViewSourceModeEnabled());
}
@@ -1629,16 +1707,15 @@ TEST_F(RenderViewImplTest, DidFailProvisionalLoadWithErrorForCancellation) {
// Start a load that will reach provisional state synchronously,
// but won't complete synchronously.
- FrameMsg_Navigate_Params params;
- params.page_id = -1;
- params.common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
- params.common_params.url = GURL("data:text/html,test data");
- params.commit_params.browser_navigation_start =
- base::TimeTicks::FromInternalValue(1);
- frame()->OnNavigate(params);
+ CommonNavigationParams common_params;
+ common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
+ common_params.url = GURL("data:text/html,test data");
+ NavigateMainFrame(common_params, StartNavigationParams(),
+ RequestNavigationParams());
// A cancellation occurred.
- view()->GetMainRenderFrame()->didFailProvisionalLoad(web_frame, error);
+ view()->GetMainRenderFrame()->didFailProvisionalLoad(
+ web_frame, error, blink::WebStandardCommit);
// Frame should stay in view-source mode.
EXPECT_TRUE(web_frame->isViewSourceModeEnabled());
}
@@ -1650,203 +1727,16 @@ TEST_F(RenderViewImplTest, UpdateTargetURLWithInvalidURL) {
EXPECT_EQ(invalid_gurl, view()->target_url_);
}
-TEST_F(RenderViewImplTest, SetHistoryLengthAndPrune) {
- int expected_page_id = -1;
-
- // No history to merge and no committed pages.
- view()->OnSetHistoryLengthAndPrune(0, -1);
- EXPECT_EQ(0, view()->history_list_length_);
- EXPECT_EQ(-1, view()->history_list_offset_);
-
- // History to merge and no committed pages.
- view()->OnSetHistoryLengthAndPrune(2, -1);
- EXPECT_EQ(2, view()->history_list_length_);
- EXPECT_EQ(1, view()->history_list_offset_);
- EXPECT_EQ(-1, view()->history_page_ids_[0]);
- EXPECT_EQ(-1, view()->history_page_ids_[1]);
- ClearHistory();
-
- blink::WebHistoryItem item;
- item.initialize();
-
- // No history to merge and a committed page to be kept.
- frame()->didCommitProvisionalLoad(GetMainFrame(),
- item,
- blink::WebStandardCommit);
- expected_page_id = view()->page_id_;
- view()->OnSetHistoryLengthAndPrune(0, expected_page_id);
- EXPECT_EQ(1, view()->history_list_length_);
- EXPECT_EQ(0, view()->history_list_offset_);
- EXPECT_EQ(expected_page_id, view()->history_page_ids_[0]);
- ClearHistory();
-
- // No history to merge and a committed page to be pruned.
- frame()->didCommitProvisionalLoad(GetMainFrame(),
- item,
- blink::WebStandardCommit);
- expected_page_id = view()->page_id_;
- view()->OnSetHistoryLengthAndPrune(0, expected_page_id + 1);
- EXPECT_EQ(0, view()->history_list_length_);
- EXPECT_EQ(-1, view()->history_list_offset_);
- ClearHistory();
-
- // No history to merge and a committed page that the browser was unaware of.
- frame()->didCommitProvisionalLoad(GetMainFrame(),
- item,
- blink::WebStandardCommit);
- expected_page_id = view()->page_id_;
- view()->OnSetHistoryLengthAndPrune(0, -1);
- EXPECT_EQ(1, view()->history_list_length_);
- EXPECT_EQ(0, view()->history_list_offset_);
- EXPECT_EQ(expected_page_id, view()->history_page_ids_[0]);
- ClearHistory();
-
- // History to merge and a committed page to be kept.
- frame()->didCommitProvisionalLoad(GetMainFrame(),
- item,
- blink::WebStandardCommit);
- expected_page_id = view()->page_id_;
- view()->OnSetHistoryLengthAndPrune(2, expected_page_id);
- EXPECT_EQ(3, view()->history_list_length_);
- EXPECT_EQ(2, view()->history_list_offset_);
- EXPECT_EQ(-1, view()->history_page_ids_[0]);
- EXPECT_EQ(-1, view()->history_page_ids_[1]);
- EXPECT_EQ(expected_page_id, view()->history_page_ids_[2]);
- ClearHistory();
-
- // History to merge and a committed page to be pruned.
- frame()->didCommitProvisionalLoad(GetMainFrame(),
- item,
- blink::WebStandardCommit);
- expected_page_id = view()->page_id_;
- view()->OnSetHistoryLengthAndPrune(2, expected_page_id + 1);
- EXPECT_EQ(2, view()->history_list_length_);
- EXPECT_EQ(1, view()->history_list_offset_);
- EXPECT_EQ(-1, view()->history_page_ids_[0]);
- EXPECT_EQ(-1, view()->history_page_ids_[1]);
- ClearHistory();
-
- // History to merge and a committed page that the browser was unaware of.
- frame()->didCommitProvisionalLoad(GetMainFrame(),
- item,
- blink::WebStandardCommit);
- expected_page_id = view()->page_id_;
- view()->OnSetHistoryLengthAndPrune(2, -1);
- EXPECT_EQ(3, view()->history_list_length_);
- EXPECT_EQ(2, view()->history_list_offset_);
- EXPECT_EQ(-1, view()->history_page_ids_[0]);
- EXPECT_EQ(-1, view()->history_page_ids_[1]);
- EXPECT_EQ(expected_page_id, view()->history_page_ids_[2]);
- ClearHistory();
-
- int expected_page_id_2 = -1;
-
- // No history to merge and two committed pages, both to be kept.
- frame()->didCommitProvisionalLoad(GetMainFrame(),
- item,
- blink::WebStandardCommit);
- expected_page_id = view()->page_id_;
- frame()->didCommitProvisionalLoad(GetMainFrame(),
- item,
- blink::WebStandardCommit);
- expected_page_id_2 = view()->page_id_;
- EXPECT_GT(expected_page_id_2, expected_page_id);
- view()->OnSetHistoryLengthAndPrune(0, expected_page_id);
- EXPECT_EQ(2, view()->history_list_length_);
- EXPECT_EQ(1, view()->history_list_offset_);
- EXPECT_EQ(expected_page_id, view()->history_page_ids_[0]);
- EXPECT_EQ(expected_page_id_2, view()->history_page_ids_[1]);
- ClearHistory();
-
- // No history to merge and two committed pages, and only the second is kept.
- frame()->didCommitProvisionalLoad(GetMainFrame(),
- item,
- blink::WebStandardCommit);
- expected_page_id = view()->page_id_;
- frame()->didCommitProvisionalLoad(GetMainFrame(),
- item,
- blink::WebStandardCommit);
- expected_page_id_2 = view()->page_id_;
- EXPECT_GT(expected_page_id_2, expected_page_id);
- view()->OnSetHistoryLengthAndPrune(0, expected_page_id_2);
+TEST_F(RenderViewImplTest, SetHistoryLengthAndOffset) {
+ // No history to merge; one committed page.
+ view()->OnSetHistoryOffsetAndLength(0, 1);
EXPECT_EQ(1, view()->history_list_length_);
EXPECT_EQ(0, view()->history_list_offset_);
- EXPECT_EQ(expected_page_id_2, view()->history_page_ids_[0]);
- ClearHistory();
-
- // No history to merge and two committed pages, both of which the browser was
- // unaware of.
- frame()->didCommitProvisionalLoad(GetMainFrame(),
- item,
- blink::WebStandardCommit);
- expected_page_id = view()->page_id_;
- frame()->didCommitProvisionalLoad(GetMainFrame(),
- item,
- blink::WebStandardCommit);
- expected_page_id_2 = view()->page_id_;
- EXPECT_GT(expected_page_id_2, expected_page_id);
- view()->OnSetHistoryLengthAndPrune(0, -1);
+
+ // History of length 1 to merge; one committed page.
+ view()->OnSetHistoryOffsetAndLength(1, 2);
EXPECT_EQ(2, view()->history_list_length_);
EXPECT_EQ(1, view()->history_list_offset_);
- EXPECT_EQ(expected_page_id, view()->history_page_ids_[0]);
- EXPECT_EQ(expected_page_id_2, view()->history_page_ids_[1]);
- ClearHistory();
-
- // History to merge and two committed pages, both to be kept.
- frame()->didCommitProvisionalLoad(GetMainFrame(),
- item,
- blink::WebStandardCommit);
- expected_page_id = view()->page_id_;
- frame()->didCommitProvisionalLoad(GetMainFrame(),
- item,
- blink::WebStandardCommit);
- expected_page_id_2 = view()->page_id_;
- EXPECT_GT(expected_page_id_2, expected_page_id);
- view()->OnSetHistoryLengthAndPrune(2, expected_page_id);
- EXPECT_EQ(4, view()->history_list_length_);
- EXPECT_EQ(3, view()->history_list_offset_);
- EXPECT_EQ(-1, view()->history_page_ids_[0]);
- EXPECT_EQ(-1, view()->history_page_ids_[1]);
- EXPECT_EQ(expected_page_id, view()->history_page_ids_[2]);
- EXPECT_EQ(expected_page_id_2, view()->history_page_ids_[3]);
- ClearHistory();
-
- // History to merge and two committed pages, and only the second is kept.
- frame()->didCommitProvisionalLoad(GetMainFrame(),
- item,
- blink::WebStandardCommit);
- expected_page_id = view()->page_id_;
- frame()->didCommitProvisionalLoad(GetMainFrame(),
- item,
- blink::WebStandardCommit);
- expected_page_id_2 = view()->page_id_;
- EXPECT_GT(expected_page_id_2, expected_page_id);
- view()->OnSetHistoryLengthAndPrune(2, expected_page_id_2);
- EXPECT_EQ(3, view()->history_list_length_);
- EXPECT_EQ(2, view()->history_list_offset_);
- EXPECT_EQ(-1, view()->history_page_ids_[0]);
- EXPECT_EQ(-1, view()->history_page_ids_[1]);
- EXPECT_EQ(expected_page_id_2, view()->history_page_ids_[2]);
- ClearHistory();
-
- // History to merge and two committed pages, both of which the browser was
- // unaware of.
- frame()->didCommitProvisionalLoad(GetMainFrame(),
- item,
- blink::WebStandardCommit);
- expected_page_id = view()->page_id_;
- frame()->didCommitProvisionalLoad(GetMainFrame(),
- item,
- blink::WebStandardCommit);
- expected_page_id_2 = view()->page_id_;
- EXPECT_GT(expected_page_id_2, expected_page_id);
- view()->OnSetHistoryLengthAndPrune(2, -1);
- EXPECT_EQ(4, view()->history_list_length_);
- EXPECT_EQ(3, view()->history_list_offset_);
- EXPECT_EQ(-1, view()->history_page_ids_[0]);
- EXPECT_EQ(-1, view()->history_page_ids_[1]);
- EXPECT_EQ(expected_page_id, view()->history_page_ids_[2]);
- EXPECT_EQ(expected_page_id_2, view()->history_page_ids_[3]);
}
TEST_F(RenderViewImplTest, ContextMenu) {
@@ -1900,7 +1790,7 @@ TEST_F(RenderViewImplTest, TestBackForward) {
base::ASCIIToUTF16(
"Number(document.getElementById('pagename').innerHTML == 'Page C')");
EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c, &was_page_c));
- EXPECT_EQ(1, was_page_b);
+ EXPECT_EQ(1, was_page_c);
PageState forward_state =
HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
@@ -2012,27 +1902,24 @@ TEST_F(RenderViewImplTest, ZoomLimit) {
const double kMinZoomLevel = ZoomFactorToZoomLevel(kMinimumZoomFactor);
const double kMaxZoomLevel = ZoomFactorToZoomLevel(kMaximumZoomFactor);
- FrameMsg_Navigate_Params params;
- params.page_id = -1;
- params.common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
- params.commit_params.browser_navigation_start =
- base::TimeTicks::FromInternalValue(1);
-
// Verifies navigation to a URL with preset zoom level indeed sets the level.
// Regression test for http://crbug.com/139559, where the level was not
// properly set when it is out of the default zoom limits of WebView.
- params.common_params.url = GURL("data:text/html,min_zoomlimit_test");
- view()->OnSetZoomLevelForLoadingURL(params.common_params.url, kMinZoomLevel);
- frame()->OnNavigate(params);
+ CommonNavigationParams common_params;
+ common_params.url = GURL("data:text/html,min_zoomlimit_test");
+ view()->OnSetZoomLevelForLoadingURL(common_params.url, kMinZoomLevel);
+ NavigateMainFrame(common_params, StartNavigationParams(),
+ RequestNavigationParams());
ProcessPendingMessages();
EXPECT_DOUBLE_EQ(kMinZoomLevel, view()->GetWebView()->zoomLevel());
// It should work even when the zoom limit is temporarily changed in the page.
view()->GetWebView()->zoomLimitsChanged(ZoomFactorToZoomLevel(1.0),
ZoomFactorToZoomLevel(1.0));
- params.common_params.url = GURL("data:text/html,max_zoomlimit_test");
- view()->OnSetZoomLevelForLoadingURL(params.common_params.url, kMaxZoomLevel);
- frame()->OnNavigate(params);
+ common_params.url = GURL("data:text/html,max_zoomlimit_test");
+ view()->OnSetZoomLevelForLoadingURL(common_params.url, kMaxZoomLevel);
+ NavigateMainFrame(common_params, StartNavigationParams(),
+ RequestNavigationParams());
ProcessPendingMessages();
EXPECT_DOUBLE_EQ(kMaxZoomLevel, view()->GetWebView()->zoomLevel());
}
@@ -2047,15 +1934,15 @@ TEST_F(RenderViewImplTest, SetEditableSelectionAndComposition) {
"</body>"
"</html>");
ExecuteJavaScript("document.getElementById('test1').focus();");
- frame()->OnSetEditableSelectionOffsets(4, 8);
+ SetEditableSelectionOffsets(4, 8);
const std::vector<blink::WebCompositionUnderline> empty_underline;
- frame()->OnSetCompositionFromExistingText(7, 10, empty_underline);
+ SetCompositionFromExistingText(7, 10, empty_underline);
blink::WebTextInputInfo info = view()->webview()->textInputInfo();
EXPECT_EQ(4, info.selectionStart);
EXPECT_EQ(8, info.selectionEnd);
EXPECT_EQ(7, info.compositionStart);
EXPECT_EQ(10, info.compositionEnd);
- frame()->OnUnselect();
+ Unselect();
info = view()->webview()->textInputInfo();
EXPECT_EQ(0, info.selectionStart);
EXPECT_EQ(0, info.selectionEnd);
@@ -2072,14 +1959,14 @@ TEST_F(RenderViewImplTest, OnExtendSelectionAndDelete) {
"</body>"
"</html>");
ExecuteJavaScript("document.getElementById('test1').focus();");
- frame()->OnSetEditableSelectionOffsets(10, 10);
- frame()->OnExtendSelectionAndDelete(3, 4);
+ SetEditableSelectionOffsets(10, 10);
+ ExtendSelectionAndDelete(3, 4);
blink::WebTextInputInfo info = view()->webview()->textInputInfo();
EXPECT_EQ("abcdefgopqrstuvwxyz", info.value);
EXPECT_EQ(7, info.selectionStart);
EXPECT_EQ(7, info.selectionEnd);
- frame()->OnSetEditableSelectionOffsets(4, 8);
- frame()->OnExtendSelectionAndDelete(2, 5);
+ SetEditableSelectionOffsets(4, 8);
+ ExtendSelectionAndDelete(2, 5);
info = view()->webview()->textInputInfo();
EXPECT_EQ("abuvwxyz", info.value);
EXPECT_EQ(2, info.selectionStart);
@@ -2087,25 +1974,28 @@ TEST_F(RenderViewImplTest, OnExtendSelectionAndDelete) {
}
// Test that the navigating specific frames works correctly.
-TEST_F(RenderViewImplTest, NavigateFrame) {
+TEST_F(RenderViewImplTest, NavigateSubframe) {
// Load page A.
LoadHTML("hello <iframe srcdoc='fail' name='frame'></iframe>");
// Navigate the frame only.
- FrameMsg_Navigate_Params nav_params;
- nav_params.common_params.url = GURL("data:text/html,world");
- nav_params.common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
- nav_params.common_params.transition = ui::PAGE_TRANSITION_TYPED;
- nav_params.current_history_list_length = 1;
- nav_params.current_history_list_offset = 0;
- nav_params.pending_history_list_offset = 1;
- nav_params.page_id = -1;
- nav_params.frame_to_navigate = "frame";
- nav_params.commit_params.browser_navigation_start =
+ CommonNavigationParams common_params;
+ RequestNavigationParams request_params;
+ common_params.url = GURL("data:text/html,world");
+ common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
+ common_params.transition = ui::PAGE_TRANSITION_TYPED;
+ request_params.current_history_list_length = 1;
+ request_params.current_history_list_offset = 0;
+ request_params.pending_history_list_offset = 1;
+ request_params.page_id = -1;
+ request_params.browser_navigation_start =
base::TimeTicks::FromInternalValue(1);
- frame()->OnNavigate(nav_params);
- FrameLoadWaiter(
- RenderFrame::FromWebFrame(frame()->GetWebFrame()->firstChild())).Wait();
+
+ RenderFrameImpl* subframe = RenderFrameImpl::FromWebFrame(
+ view()->webview()->findFrameByName("frame"));
+ NavigateFrame(subframe, common_params, StartNavigationParams(),
+ request_params);
+ FrameLoadWaiter(subframe).Wait();
// Copy the document content to std::wstring and compare with the
// expected result.
@@ -2118,7 +2008,7 @@ TEST_F(RenderViewImplTest, NavigateFrame) {
// This test ensures that a RenderFrame object is created for the top level
// frame in the RenderView.
TEST_F(RenderViewImplTest, BasicRenderFrame) {
- EXPECT_TRUE(view()->main_render_frame_.get());
+ EXPECT_TRUE(view()->main_render_frame_);
}
TEST_F(RenderViewImplTest, GetSSLStatusOfFrame) {
@@ -2167,7 +2057,7 @@ TEST_F(RenderViewImplTest, MessageOrderInDidChangeSelection) {
EXPECT_LT(last_input_type, last_selection);
}
-class SuppressErrorPageTest : public RenderViewTest {
+class SuppressErrorPageTest : public RenderViewImplTest {
public:
ContentRendererClient* CreateContentRendererClient() override {
return new TestContentRendererClient;
@@ -2217,16 +2107,15 @@ TEST_F(SuppressErrorPageTest, MAYBE_Suppresses) {
// Start a load that will reach provisional state synchronously,
// but won't complete synchronously.
- FrameMsg_Navigate_Params params;
- params.page_id = -1;
- params.common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
- params.common_params.url = GURL("data:text/html,test data");
- params.commit_params.browser_navigation_start =
- base::TimeTicks::FromInternalValue(1);
- frame()->OnNavigate(params);
+ CommonNavigationParams common_params;
+ common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
+ common_params.url = GURL("data:text/html,test data");
+ NavigateMainFrame(common_params, StartNavigationParams(),
+ RequestNavigationParams());
// An error occurred.
- view()->GetMainRenderFrame()->didFailProvisionalLoad(web_frame, error);
+ view()->GetMainRenderFrame()->didFailProvisionalLoad(
+ web_frame, error, blink::WebStandardCommit);
const int kMaxOutputCharacters = 22;
EXPECT_EQ("",
base::UTF16ToASCII(web_frame->contentAsText(kMaxOutputCharacters)));
@@ -2248,16 +2137,15 @@ TEST_F(SuppressErrorPageTest, MAYBE_DoesNotSuppress) {
// Start a load that will reach provisional state synchronously,
// but won't complete synchronously.
- FrameMsg_Navigate_Params params;
- params.page_id = -1;
- params.common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
- params.common_params.url = GURL("data:text/html,test data");
- params.commit_params.browser_navigation_start =
- base::TimeTicks::FromInternalValue(1);
- frame()->OnNavigate(params);
+ CommonNavigationParams common_params;
+ common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
+ common_params.url = GURL("data:text/html,test data");
+ NavigateMainFrame(common_params, StartNavigationParams(),
+ RequestNavigationParams());
// An error occurred.
- view()->GetMainRenderFrame()->didFailProvisionalLoad(web_frame, error);
+ view()->GetMainRenderFrame()->didFailProvisionalLoad(
+ web_frame, error, blink::WebStandardCommit);
// The error page itself is loaded asynchronously.
FrameLoadWaiter(frame()).Wait();
const int kMaxOutputCharacters = 22;
@@ -2336,7 +2224,7 @@ TEST_F(RenderViewImplTest, FocusElementCallsFocusedNodeChanged) {
ViewHostMsg_FocusedNodeChanged::Param params;
ViewHostMsg_FocusedNodeChanged::Read(msg1, &params);
- EXPECT_TRUE(params.a);
+ EXPECT_TRUE(get<0>(params));
render_thread_->sink().ClearMessages();
ExecuteJavaScript("document.getElementById('test2').focus();");
@@ -2344,7 +2232,7 @@ TEST_F(RenderViewImplTest, FocusElementCallsFocusedNodeChanged) {
ViewHostMsg_FocusedNodeChanged::ID);
EXPECT_TRUE(msg2);
ViewHostMsg_FocusedNodeChanged::Read(msg2, &params);
- EXPECT_TRUE(params.a);
+ EXPECT_TRUE(get<0>(params));
render_thread_->sink().ClearMessages();
view()->webview()->clearFocusedElement();
@@ -2352,7 +2240,7 @@ TEST_F(RenderViewImplTest, FocusElementCallsFocusedNodeChanged) {
ViewHostMsg_FocusedNodeChanged::ID);
EXPECT_TRUE(msg3);
ViewHostMsg_FocusedNodeChanged::Read(msg3, &params);
- EXPECT_FALSE(params.a);
+ EXPECT_FALSE(get<0>(params));
render_thread_->sink().ClearMessages();
}
@@ -2402,15 +2290,15 @@ TEST_F(RenderViewImplTest, OnSetAccessibilityMode) {
ASSERT_EQ(AccessibilityModeOff, frame()->accessibility_mode());
ASSERT_EQ((RendererAccessibility*) NULL, frame()->renderer_accessibility());
- frame()->OnSetAccessibilityMode(AccessibilityModeTreeOnly);
+ SetAccessibilityMode(AccessibilityModeTreeOnly);
ASSERT_EQ(AccessibilityModeTreeOnly, frame()->accessibility_mode());
ASSERT_NE((RendererAccessibility*) NULL, frame()->renderer_accessibility());
- frame()->OnSetAccessibilityMode(AccessibilityModeOff);
+ SetAccessibilityMode(AccessibilityModeOff);
ASSERT_EQ(AccessibilityModeOff, frame()->accessibility_mode());
ASSERT_EQ((RendererAccessibility*) NULL, frame()->renderer_accessibility());
- frame()->OnSetAccessibilityMode(AccessibilityModeComplete);
+ SetAccessibilityMode(AccessibilityModeComplete);
ASSERT_EQ(AccessibilityModeComplete, frame()->accessibility_mode());
ASSERT_NE((RendererAccessibility*) NULL, frame()->renderer_accessibility());
}
@@ -2425,7 +2313,7 @@ TEST_F(RenderViewImplTest, ScreenMetricsEmulation) {
params.viewSize.width = 327;
params.viewSize.height = 415;
- view()->EnableScreenMetricsEmulation(params);
+ view()->OnEnableDeviceEmulation(params);
EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_width, &width));
EXPECT_EQ(params.viewSize.width, width);
EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_height, &height));
@@ -2433,15 +2321,15 @@ TEST_F(RenderViewImplTest, ScreenMetricsEmulation) {
params.viewSize.width = 1005;
params.viewSize.height = 1102;
- view()->EnableScreenMetricsEmulation(params);
+ view()->OnEnableDeviceEmulation(params);
EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_width, &width));
EXPECT_EQ(params.viewSize.width, width);
EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_height, &height));
EXPECT_EQ(params.viewSize.height, height);
- view()->DisableScreenMetricsEmulation();
+ view()->OnDisableDeviceEmulation();
- view()->EnableScreenMetricsEmulation(params);
+ view()->OnEnableDeviceEmulation(params);
// Don't disable here to test that emulation is being shutdown properly.
}
@@ -2453,17 +2341,18 @@ TEST_F(RenderViewImplTest, NavigationStartOverride) {
// possible TimeTicks is indeed reported as one that started before
// OnNavigate() is called.
base::Time before_navigation = base::Time::Now();
- FrameMsg_Navigate_Params early_nav_params;
- early_nav_params.common_params.url = GURL("data:text/html,<div>Page</div>");
- early_nav_params.common_params.navigation_type =
- FrameMsg_Navigate_Type::NORMAL;
- early_nav_params.common_params.transition = ui::PAGE_TRANSITION_TYPED;
- early_nav_params.page_id = -1;
- early_nav_params.request_params.is_post = true;
- early_nav_params.commit_params.browser_navigation_start =
+ CommonNavigationParams early_common_params;
+ StartNavigationParams early_start_params;
+ RequestNavigationParams early_request_params;
+ early_common_params.url = GURL("data:text/html,<div>Page</div>");
+ early_common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
+ early_common_params.transition = ui::PAGE_TRANSITION_TYPED;
+ early_start_params.is_post = true;
+ early_request_params.browser_navigation_start =
base::TimeTicks::FromInternalValue(1);
- frame()->OnNavigate(early_nav_params);
+ NavigateMainFrame(early_common_params, early_start_params,
+ early_request_params);
ProcessPendingMessages();
base::Time early_nav_reported_start =
@@ -2473,18 +2362,17 @@ TEST_F(RenderViewImplTest, NavigationStartOverride) {
// Verify that a navigation that claims to have started in the future - 42
// days from now is *not* reported as one that starts in the future; as we
// sanitize the override allowing a maximum of ::Now().
- FrameMsg_Navigate_Params late_nav_params;
- late_nav_params.common_params.url =
- GURL("data:text/html,<div>Another page</div>");
- late_nav_params.common_params.navigation_type =
- FrameMsg_Navigate_Type::NORMAL;
- late_nav_params.common_params.transition = ui::PAGE_TRANSITION_TYPED;
- late_nav_params.page_id = -1;
- late_nav_params.request_params.is_post = true;
- late_nav_params.commit_params.browser_navigation_start =
+ CommonNavigationParams late_common_params;
+ RequestNavigationParams late_request_params;
+ StartNavigationParams late_start_params;
+ late_common_params.url = GURL("data:text/html,<div>Another page</div>");
+ late_common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
+ late_common_params.transition = ui::PAGE_TRANSITION_TYPED;
+ late_start_params.is_post = true;
+ late_request_params.browser_navigation_start =
base::TimeTicks::Now() + base::TimeDelta::FromDays(42);
- frame()->OnNavigate(late_nav_params);
+ NavigateMainFrame(late_common_params, late_start_params, late_request_params);
ProcessPendingMessages();
base::Time after_navigation =
base::Time::Now() + base::TimeDelta::FromDays(1);
@@ -2494,4 +2382,56 @@ TEST_F(RenderViewImplTest, NavigationStartOverride) {
EXPECT_LE(late_nav_reported_start, after_navigation);
}
+TEST_F(RenderViewImplTest, PreferredSizeZoomed) {
+ LoadHTML("<body style='margin:0;'><div style='display:inline-block; "
+ "width:400px; height:400px;'/></body>");
+ view()->webview()->mainFrame()->setCanHaveScrollbars(false);
+ EnablePreferredSizeMode();
+
+ gfx::Size size = GetPreferredSize();
+ EXPECT_EQ(gfx::Size(400, 400), size);
+
+ SetZoomLevel(ZoomFactorToZoomLevel(2.0));
+ size = GetPreferredSize();
+ EXPECT_EQ(gfx::Size(800, 800), size);
+}
+
+// Ensure the RenderViewImpl history list is properly updated when starting a
+// new browser-initiated navigation.
+TEST_F(RenderViewImplTest, HistoryIsProperlyUpdatedOnNavigation) {
+ EXPECT_EQ(0, view()->historyBackListCount());
+ EXPECT_EQ(0, view()->historyBackListCount() +
+ view()->historyForwardListCount() + 1);
+
+ // Receive a Navigate message with history parameters.
+ RequestNavigationParams request_params;
+ request_params.current_history_list_length = 2;
+ request_params.current_history_list_offset = 1;
+ request_params.pending_history_list_offset = 2;
+ request_params.page_id = -1;
+ NavigateMainFrame(CommonNavigationParams(), StartNavigationParams(),
+ request_params);
+
+ // The history list in RenderView should have been updated.
+ EXPECT_EQ(1, view()->historyBackListCount());
+ EXPECT_EQ(2, view()->historyBackListCount() +
+ view()->historyForwardListCount() + 1);
+}
+
+TEST_F(DevToolsAgentTest, DevToolsResumeOnClose) {
+ Attach();
+ EXPECT_FALSE(IsPaused());
+ DispatchDevToolsMessage("{\"id\":1,\"method\":\"Debugger.enable\"}");
+
+ // Executing javascript will pause the thread and create nested message loop.
+ // Posting task simulates message coming from browser.
+ base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+ &DevToolsAgentTest::CloseWhilePaused, base::Unretained(this)));
+ ExecuteJavaScript("debugger;");
+
+ // CloseWhilePaused should resume execution and continue here.
+ EXPECT_FALSE(IsPaused());
+ Detach();
+}
+
} // namespace content
diff --git a/chromium/content/renderer/render_view_impl.cc b/chromium/content/renderer/render_view_impl.cc
index 0c839e267a3..48df2c47c64 100644
--- a/chromium/content/renderer/render_view_impl.cc
+++ b/chromium/content/renderer/render_view_impl.cc
@@ -13,7 +13,6 @@
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/debug/alias.h"
-#include "base/debug/trace_event.h"
#include "base/files/file_path.h"
#include "base/i18n/rtl.h"
#include "base/json/json_writer.h"
@@ -31,19 +30,20 @@
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
-#include "cc/base/switches.h"
+#include "base/trace_event/trace_event.h"
#include "content/child/appcache/appcache_dispatcher.h"
#include "content/child/appcache/web_application_cache_host_impl.h"
#include "content/child/child_shared_bitmap_manager.h"
-#include "content/child/child_thread.h"
#include "content/child/npapi/webplugin_delegate_impl.h"
#include "content/child/request_extra_data.h"
+#include "content/child/v8_value_converter_impl.h"
#include "content/child/webmessageportchannel_impl.h"
#include "content/common/content_constants_internal.h"
#include "content/common/database_messages.h"
#include "content/common/dom_storage/dom_storage_types.h"
#include "content/common/drag_messages.h"
#include "content/common/frame_messages.h"
+#include "content/common/frame_replication_state.h"
#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
#include "content/common/input_messages.h"
#include "content/common/pepper_messages.h"
@@ -71,11 +71,9 @@
#include "content/public/renderer/render_view_visitor.h"
#include "content/renderer/browser_plugin/browser_plugin.h"
#include "content/renderer/browser_plugin/browser_plugin_manager.h"
-#include "content/renderer/devtools/devtools_agent.h"
#include "content/renderer/disambiguation_popup_helper.h"
#include "content/renderer/dom_storage/webstoragenamespace_impl.h"
#include "content/renderer/drop_data_builder.h"
-#include "content/renderer/gpu/gpu_benchmarking_extension.h"
#include "content/renderer/gpu/render_widget_compositor.h"
#include "content/renderer/history_controller.h"
#include "content/renderer/history_serialization.h"
@@ -85,33 +83,27 @@
#include "content/renderer/internal_document_state_data.h"
#include "content/renderer/media/audio_device_factory.h"
#include "content/renderer/media/video_capture_impl_manager.h"
-#include "content/renderer/memory_benchmarking_extension.h"
#include "content/renderer/mhtml_generator.h"
+#include "content/renderer/navigation_state_impl.h"
#include "content/renderer/net_info_helper.h"
#include "content/renderer/render_frame_impl.h"
#include "content/renderer/render_frame_proxy.h"
#include "content/renderer/render_process.h"
#include "content/renderer/render_thread_impl.h"
-#include "content/renderer/render_view_impl_params.h"
#include "content/renderer/render_view_mouse_lock_dispatcher.h"
#include "content/renderer/render_widget_fullscreen_pepper.h"
#include "content/renderer/renderer_webapplicationcachehost_impl.h"
#include "content/renderer/resizing_mode_selector.h"
#include "content/renderer/savable_resources.h"
-#include "content/renderer/skia_benchmarking_extension.h"
#include "content/renderer/speech_recognition_dispatcher.h"
-#include "content/renderer/stats_collection_controller.h"
-#include "content/renderer/stats_collection_observer.h"
#include "content/renderer/text_input_client_observer.h"
-#include "content/renderer/v8_value_converter_impl.h"
-#include "content/renderer/web_ui_extension.h"
#include "content/renderer/web_ui_extension_data.h"
#include "content/renderer/web_ui_mojo.h"
#include "content/renderer/websharedworker_proxy.h"
#include "media/audio/audio_output_device.h"
#include "media/base/media_switches.h"
-#include "media/filters/audio_renderer_impl.h"
-#include "media/filters/gpu_video_accelerator_factories.h"
+#include "media/renderers/audio_renderer_impl.h"
+#include "media/renderers/gpu_video_accelerator_factories.h"
#include "net/base/data_url.h"
#include "net/base/escape.h"
#include "net/base/net_errors.h"
@@ -142,7 +134,6 @@
#include "third_party/WebKit/public/web/WebDataSource.h"
#include "third_party/WebKit/public/web/WebDateTimeChooserCompletion.h"
#include "third_party/WebKit/public/web/WebDateTimeChooserParams.h"
-#include "third_party/WebKit/public/web/WebDevToolsAgent.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebElement.h"
#include "third_party/WebKit/public/web/WebFileChooserParams.h"
@@ -155,7 +146,6 @@
#include "third_party/WebKit/public/web/WebHitTestResult.h"
#include "third_party/WebKit/public/web/WebInputElement.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
-#include "third_party/WebKit/public/web/WebKit.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
#include "third_party/WebKit/public/web/WebMediaPlayerAction.h"
#include "third_party/WebKit/public/web/WebNavigationPolicy.h"
@@ -172,7 +162,6 @@
#include "third_party/WebKit/public/web/WebSearchableFormData.h"
#include "third_party/WebKit/public/web/WebSecurityOrigin.h"
#include "third_party/WebKit/public/web/WebSecurityPolicy.h"
-#include "third_party/WebKit/public/web/WebSerializedScriptValue.h"
#include "third_party/WebKit/public/web/WebSettings.h"
#include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
#include "third_party/WebKit/public/web/WebView.h"
@@ -183,11 +172,11 @@
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/ui_base_switches_util.h"
#include "ui/events/latency_info.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/point.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/rect_conversions.h"
-#include "ui/gfx/size_conversions.h"
#include "v8/include/v8.h"
#if defined(OS_ANDROID)
@@ -197,10 +186,9 @@
#include "content/renderer/android/content_detector.h"
#include "content/renderer/android/email_detector.h"
#include "content/renderer/android/phone_number_detector.h"
-#include "net/android/network_library.h"
#include "third_party/WebKit/public/platform/WebFloatPoint.h"
#include "third_party/WebKit/public/platform/WebFloatRect.h"
-#include "ui/gfx/rect_f.h"
+#include "ui/gfx/geometry/rect_f.h"
#elif defined(OS_WIN)
// TODO(port): these files are currently Windows only because they concern:
@@ -233,8 +221,6 @@ using blink::WebConsoleMessage;
using blink::WebData;
using blink::WebDataSource;
using blink::WebDocument;
-using blink::WebDOMEvent;
-using blink::WebDOMMessageEvent;
using blink::WebDragData;
using blink::WebDragOperation;
using blink::WebDragOperationsMask;
@@ -274,7 +260,6 @@ using blink::WebScriptSource;
using blink::WebSearchableFormData;
using blink::WebSecurityOrigin;
using blink::WebSecurityPolicy;
-using blink::WebSerializedScriptValue;
using blink::WebSettings;
using blink::WebSize;
using blink::WebStorageNamespace;
@@ -333,17 +318,10 @@ const int kDelaySecondsForContentStateSync = 1;
const size_t kContentIntentDelayMilliseconds = 700;
#endif
-static RenderViewImpl* (*g_create_render_view_impl)(RenderViewImplParams*) =
+static RenderViewImpl* (*g_create_render_view_impl)(const ViewMsg_New_Params&) =
NULL;
// static
-bool RenderViewImpl::IsReload(FrameMsg_Navigate_Type::Value navigation_type) {
- return navigation_type == FrameMsg_Navigate_Type::RELOAD ||
- navigation_type == FrameMsg_Navigate_Type::RELOAD_IGNORING_CACHE ||
- navigation_type == FrameMsg_Navigate_Type::RELOAD_ORIGINAL_REQUEST_URL;
-}
-
-// static
Referrer RenderViewImpl::GetReferrerFromRequest(
WebFrame* frame,
const WebURLRequest& request) {
@@ -387,33 +365,19 @@ static bool DeviceScaleEnsuresTextQuality(float device_scale_factor) {
}
-static bool PreferCompositingToLCDText(float device_scale_factor) {
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+static bool PreferCompositingToLCDText(CompositorDependencies* compositor_deps,
+ float device_scale_factor) {
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
if (command_line.HasSwitch(switches::kDisablePreferCompositingToLCDText))
return false;
if (command_line.HasSwitch(switches::kEnablePreferCompositingToLCDText))
return true;
- if (RenderThreadImpl::current() &&
- !RenderThreadImpl::current()->is_lcd_text_enabled())
+ if (!compositor_deps->IsLcdTextEnabled())
return true;
return DeviceScaleEnsuresTextQuality(device_scale_factor);
}
-static bool ShouldUseTransitionCompositing(float device_scale_factor) {
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
-
- if (command_line.HasSwitch(switches::kDisableCompositingForTransition))
- return false;
-
- if (command_line.HasSwitch(switches::kEnableCompositingForTransition))
- return true;
-
- // TODO(ajuma): Re-enable this by default for high-DPI once the problem
- // of excessive layer promotion caused by overlap has been addressed.
- // http://crbug.com/178119.
- return false;
-}
-
static FaviconURL::IconType ToFaviconType(blink::WebIconURL::Type type) {
switch (type) {
case blink::WebIconURL::TypeFavicon:
@@ -473,15 +437,6 @@ class WebWidgetLockTarget : public MouseLockDispatcher::LockTarget {
blink::WebWidget* webwidget_;
};
-bool TouchEnabled() {
-// Based on the definition of chrome::kEnableTouchIcon.
-#if defined(OS_ANDROID)
- return true;
-#else
- return false;
-#endif
-}
-
WebDragData DropDataToWebDragData(const DropData& drop_data) {
std::vector<WebDragData::Item> item_list;
@@ -639,15 +594,33 @@ void ApplyFontsFromMap(const ScriptFontFamilyMap& map,
}
}
+void ApplyBlinkSettings(const base::CommandLine& command_line,
+ WebSettings* settings) {
+ if (!command_line.HasSwitch(switches::kBlinkSettings))
+ return;
+
+ std::vector<std::string> blink_settings;
+ base::SplitString(
+ command_line.GetSwitchValueASCII(switches::kBlinkSettings), ',',
+ &blink_settings);
+ for (const std::string& setting : blink_settings) {
+ size_t pos = setting.find('=');
+ settings->setFromStrings(
+ blink::WebString::fromLatin1(setting.substr(0, pos)),
+ blink::WebString::fromLatin1(
+ pos == std::string::npos ? "" : setting.substr(pos + 1)));
+ }
+}
+
} // namespace
-RenderViewImpl::RenderViewImpl(RenderViewImplParams* params)
+RenderViewImpl::RenderViewImpl(const ViewMsg_New_Params& params)
: RenderWidget(blink::WebPopupTypeNone,
- params->screen_info,
- params->swapped_out,
- params->hidden,
- params->never_visible),
- webkit_preferences_(params->webkit_prefs),
+ params.initial_size.screen_info,
+ params.swapped_out,
+ params.hidden,
+ params.never_visible),
+ webkit_preferences_(params.web_preferences),
send_content_state_immediately_(false),
enabled_bindings_(0),
send_preferred_size_changes_(false),
@@ -656,20 +629,17 @@ RenderViewImpl::RenderViewImpl(RenderViewImplParams* params)
opener_suppressed_(false),
suppress_dialogs_until_swap_out_(false),
page_id_(-1),
- last_page_id_sent_to_browser_(-1),
- next_page_id_(params->next_page_id),
+ next_page_id_(params.next_page_id),
history_list_offset_(-1),
history_list_length_(0),
frames_in_progress_(0),
target_url_status_(TARGET_NONE),
uses_temporary_zoom_level_(false),
#if defined(OS_ANDROID)
- top_controls_constraints_(cc::BOTH),
+ top_controls_constraints_(TOP_CONTROLS_STATE_BOTH),
#endif
has_scrolled_focused_editable_node_into_rect_(false),
speech_recognition_dispatcher_(NULL),
- browser_plugin_manager_(NULL),
- devtools_agent_(NULL),
mouse_lock_dispatcher_(NULL),
#if defined(OS_ANDROID)
expected_content_intent_id_(0),
@@ -683,50 +653,56 @@ RenderViewImpl::RenderViewImpl(RenderViewImplParams* params)
pepper_last_mouse_event_target_(NULL),
#endif
enumeration_completion_id_(0),
- session_storage_namespace_id_(params->session_storage_namespace_id),
- next_snapshot_id_(0) {
+ session_storage_namespace_id_(params.session_storage_namespace_id),
+ page_scale_factor_is_one_(true) {
}
-void RenderViewImpl::Initialize(RenderViewImplParams* params) {
- routing_id_ = params->routing_id;
- surface_id_ = params->surface_id;
- if (params->opener_id != MSG_ROUTING_NONE && params->is_renderer_created)
- opener_id_ = params->opener_id;
+void RenderViewImpl::Initialize(const ViewMsg_New_Params& params,
+ CompositorDependencies* compositor_deps,
+ bool was_created_by_renderer) {
+ routing_id_ = params.view_id;
+ surface_id_ = params.surface_id;
+ if (params.opener_route_id != MSG_ROUTING_NONE && was_created_by_renderer)
+ opener_id_ = params.opener_route_id;
+ display_mode_= params.initial_size.display_mode;
// Ensure we start with a valid next_page_id_ from the browser.
DCHECK_GE(next_page_id_, 0);
- main_render_frame_.reset(RenderFrameImpl::Create(
- this, params->main_frame_routing_id));
+ main_render_frame_ = RenderFrameImpl::Create(
+ this, params.main_frame_routing_id);
// The main frame WebLocalFrame object is closed by
// RenderFrameImpl::frameDetached().
- WebLocalFrame* web_frame = WebLocalFrame::create(main_render_frame_.get());
+ WebLocalFrame* web_frame = WebLocalFrame::create(main_render_frame_);
main_render_frame_->SetWebFrame(web_frame);
+ compositor_deps_ = compositor_deps;
webwidget_ = WebView::create(this);
webwidget_mouse_lock_target_.reset(new WebWidgetLockTarget(webwidget_));
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
if (command_line.HasSwitch(switches::kStatsCollectionController))
stats_collection_observer_.reset(new StatsCollectionObserver(this));
#if defined(OS_ANDROID)
- const std::string region_code =
- command_line.HasSwitch(switches::kNetworkCountryIso)
- ? command_line.GetSwitchValueASCII(switches::kNetworkCountryIso)
- : net::android::GetTelephonyNetworkCountryIso();
content_detectors_.push_back(linked_ptr<ContentDetector>(
new AddressDetector()));
- content_detectors_.push_back(linked_ptr<ContentDetector>(
- new PhoneNumberDetector(region_code)));
+ const std::string& contry_iso =
+ params.renderer_preferences.network_contry_iso;
+ if (!contry_iso.empty()) {
+ content_detectors_.push_back(linked_ptr<ContentDetector>(
+ new PhoneNumberDetector(contry_iso)));
+ }
content_detectors_.push_back(linked_ptr<ContentDetector>(
new EmailDetector()));
#endif
RenderThread::Get()->AddRoute(routing_id_, this);
// Take a reference on behalf of the RenderThread. This will be balanced
- // when we receive ViewMsg_ClosePage.
+ // when we receive ViewMsg_Close in the RenderWidget (which RenderView
+ // inherits from).
AddRef();
if (RenderThreadImpl::current()) {
RenderThreadImpl::current()->WidgetCreated();
@@ -744,10 +720,9 @@ void RenderViewImpl::Initialize(RenderViewImplParams* params) {
g_view_map.Get().insert(std::make_pair(webview(), this));
g_routing_id_view_map.Get().insert(std::make_pair(routing_id_, this));
webview()->setDeviceScaleFactor(device_scale_factor_);
+ webview()->setDisplayMode(display_mode_);
webview()->settings()->setPreferCompositingToLCDTextEnabled(
- PreferCompositingToLCDText(device_scale_factor_));
- webview()->settings()->setAcceleratedCompositingForTransitionEnabled(
- ShouldUseTransitionCompositing(device_scale_factor_));
+ PreferCompositingToLCDText(compositor_deps_, device_scale_factor_));
webview()->settings()->setThreadedScrollingEnabled(
!command_line.HasSwitch(switches::kDisableThreadedScrolling));
webview()->settings()->setRootLayerScrolls(
@@ -755,21 +730,20 @@ void RenderViewImpl::Initialize(RenderViewImplParams* params) {
ApplyWebPreferences(webkit_preferences_, webview());
- webview()->settings()->setAllowConnectingInsecureWebSocket(
- command_line.HasSwitch(switches::kAllowInsecureWebSocketFromHttpsOrigin));
-
RenderFrameProxy* proxy = NULL;
- if (params->proxy_routing_id != MSG_ROUTING_NONE) {
- CHECK(params->swapped_out);
+ if (params.proxy_routing_id != MSG_ROUTING_NONE) {
+ CHECK(params.swapped_out);
proxy = RenderFrameProxy::CreateProxyToReplaceFrame(
- main_render_frame_.get(), params->proxy_routing_id);
+ main_render_frame_, params.proxy_routing_id);
main_render_frame_->set_render_frame_proxy(proxy);
}
// In --site-per-process, just use the WebRemoteFrame as the main frame.
- if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess) &&
- proxy) {
+ if (command_line.HasSwitch(switches::kSitePerProcess) && proxy) {
webview()->setMainFrame(proxy->web_frame());
+ // Initialize the WebRemoteFrame with information replicated from the
+ // browser process.
+ proxy->SetReplicatedState(params.replicated_frame_state);
} else {
webview()->setMainFrame(main_render_frame_->GetWebFrame());
}
@@ -781,14 +755,31 @@ void RenderViewImpl::Initialize(RenderViewImplParams* params) {
if (switches::IsTouchEditingEnabled())
webview()->settings()->setTouchEditingEnabled(true);
- if (!params->frame_name.empty())
- webview()->mainFrame()->setName(params->frame_name);
+ WebSettings::SelectionStrategyType selection_strategy =
+ WebSettings::SelectionStrategyType::Character;
+ const std::string selection_strategy_str =
+ base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kTouchTextSelectionStrategy);
+ if (selection_strategy_str == "direction")
+ selection_strategy = WebSettings::SelectionStrategyType::Direction;
+ webview()->settings()->setSelectionStrategy(selection_strategy);
+
+ if (!params.frame_name.empty())
+ webview()->mainFrame()->setName(params.frame_name);
// TODO(davidben): Move this state from Blink into content.
- if (params->window_was_created_with_opener)
+ if (params.window_was_created_with_opener)
webview()->setOpenedByDOM();
- OnSetRendererPrefs(params->renderer_prefs);
+ OnSetRendererPrefs(params.renderer_preferences);
+
+ ApplyBlinkSettings(command_line, webview()->settings());
+
+ if (!params.enable_auto_resize) {
+ OnResize(params.initial_size);
+ } else {
+ OnEnableAutoResize(params.min_size, params.max_size);
+ }
new MHTMLGenerator(this);
#if defined(OS_MACOSX)
@@ -797,10 +788,6 @@ void RenderViewImpl::Initialize(RenderViewImplParams* params) {
// The next group of objects all implement RenderViewObserver, so are deleted
// along with the RenderView automatically.
- devtools_agent_ = new DevToolsAgent(this);
- if (RenderWidgetCompositor* rwc = compositor()) {
- webview()->devToolsAgent()->setLayerTreeId(rwc->GetLayerTreeId());
- }
mouse_lock_dispatcher_ = new RenderViewMouseLockDispatcher(this);
history_controller_.reset(new HistoryController(this));
@@ -812,14 +799,12 @@ void RenderViewImpl::Initialize(RenderViewImplParams* params) {
if (command_line.HasSwitch(switches::kStatsCollectionController))
enabled_bindings_ |= BINDINGS_POLICY_STATS_COLLECTION;
- ProcessViewLayoutFlags(command_line);
-
GetContentClient()->renderer()->RenderViewCreated(this);
// If we have an opener_id but we weren't created by a renderer, then
// it's the browser asking us to set our opener to another RenderView.
- if (params->opener_id != MSG_ROUTING_NONE && !params->is_renderer_created) {
- RenderViewImpl* opener_view = FromRoutingID(params->opener_id);
+ if (params.opener_route_id != MSG_ROUTING_NONE && !was_created_by_renderer) {
+ RenderViewImpl* opener_view = FromRoutingID(params.opener_route_id);
if (opener_view)
webview()->mainFrame()->setOpener(opener_view->webview()->mainFrame());
}
@@ -827,7 +812,7 @@ void RenderViewImpl::Initialize(RenderViewImplParams* params) {
// If we are initially swapped out, navigate to kSwappedOutURL.
// This ensures we are in a unique origin that others cannot script.
if (is_swapped_out_ && webview()->mainFrame()->isWebLocalFrame())
- NavigateToSwappedOutURL(webview()->mainFrame());
+ main_render_frame_->NavigateToSwappedOutURL();
}
RenderViewImpl::~RenderViewImpl() {
@@ -835,9 +820,7 @@ RenderViewImpl::~RenderViewImpl() {
it != disambiguation_bitmaps_.end();
++it)
delete it->second;
- history_page_ids_.clear();
-
- base::debug::TraceLog::GetInstance()->RemoveProcessLabel(routing_id_);
+ base::trace_event::TraceLog::GetInstance()->RemoveProcessLabel(routing_id_);
// If file chooser is still waiting for answer, dispatch empty answer.
while (!file_chooser_completions_.empty()) {
@@ -939,8 +922,6 @@ void RenderView::ApplyWebPreferences(const WebPreferences& prefs,
settings->setImagesEnabled(prefs.images_enabled);
settings->setPluginsEnabled(prefs.plugins_enabled);
settings->setDOMPasteAllowed(prefs.dom_paste_enabled);
- settings->setShrinksStandaloneImagesToFit(
- prefs.shrinks_standalone_images_to_fit);
settings->setUsesEncodingDetector(prefs.uses_universal_detector);
settings->setTextAreasAreResizable(prefs.text_areas_are_resizable);
settings->setAllowScriptsToCloseWindows(prefs.allow_scripts_to_close_windows);
@@ -988,8 +969,6 @@ void RenderView::ApplyWebPreferences(const WebPreferences& prefs,
// Uses the mock theme engine for scrollbars.
settings->setMockScrollbarsEnabled(prefs.mock_scrollbars_enabled);
- settings->setLayerSquashingEnabled(prefs.layer_squashing_enabled);
-
// Enable gpu-accelerated 2d canvas if requested on the command line.
settings->setAccelerated2dCanvasEnabled(prefs.accelerated_2d_canvas_enabled);
@@ -1010,9 +989,6 @@ void RenderView::ApplyWebPreferences(const WebPreferences& prefs,
settings->setAccelerated2dCanvasMSAASampleCount(
prefs.accelerated_2d_canvas_msaa_sample_count);
- // Enable container culling if requested on the command line.
- settings->setContainerCullingEnabled(prefs.container_culling_enabled);
-
WebRuntimeFeatures::enableTextBlobs(prefs.text_blobs_enabled);
settings->setAsynchronousSpellCheckingEnabled(
@@ -1027,6 +1003,10 @@ void RenderView::ApplyWebPreferences(const WebPreferences& prefs,
prefs.allow_displaying_insecure_content);
settings->setAllowRunningOfInsecureContent(
prefs.allow_running_insecure_content);
+ settings->setDisableReadingFromCanvas(prefs.disable_reading_from_canvas);
+ settings->setStrictMixedContentChecking(prefs.strict_mixed_content_checking);
+ settings->setStrictPowerfulFeatureRestrictions(
+ prefs.strict_powerful_feature_restrictions);
settings->setPasswordEchoEnabled(prefs.password_echo_enabled);
settings->setShouldPrintBackgrounds(prefs.should_print_backgrounds);
settings->setShouldClearDocumentBackground(
@@ -1037,9 +1017,17 @@ void RenderView::ApplyWebPreferences(const WebPreferences& prefs,
WebRuntimeFeatures::enableTouch(prefs.touch_enabled);
settings->setMaxTouchPoints(prefs.pointer_events_max_touch_points);
+ settings->setAvailablePointerTypes(prefs.available_pointer_types);
+ settings->setPrimaryPointerType(
+ static_cast<WebSettings::PointerType>(prefs.primary_pointer_type));
+ settings->setAvailableHoverTypes(prefs.available_hover_types);
+ settings->setPrimaryHoverType(
+ static_cast<WebSettings::HoverType>(prefs.primary_hover_type));
settings->setDeviceSupportsTouch(prefs.device_supports_touch);
settings->setDeviceSupportsMouse(prefs.device_supports_mouse);
settings->setEnableTouchAdjustment(prefs.touch_adjustment_enabled);
+ settings->setMultiTargetTapNotificationEnabled(
+ switches::IsLinkDisambiguationPopupEnabled());
settings->setDeferredImageDecodingEnabled(
prefs.deferred_image_decoding_enabled);
@@ -1069,10 +1057,13 @@ void RenderView::ApplyWebPreferences(const WebPreferences& prefs,
settings->setV8CacheOptions(
static_cast<WebSettings::V8CacheOptions>(prefs.v8_cache_options));
- settings->setV8ScriptStreamingEnabled(prefs.v8_script_streaming_enabled);
- settings->setV8ScriptStreamingMode(
- static_cast<WebSettings::V8ScriptStreamingMode>(
- prefs.v8_script_streaming_mode));
+ settings->setImageAnimationPolicy(
+ static_cast<WebSettings::ImageAnimationPolicy>(prefs.animation_policy));
+
+ // Needs to happen before setIgnoreVIewportTagScaleLimits below.
+ web_view->setDefaultPageScaleLimits(
+ prefs.default_minimum_page_scale_factor,
+ prefs.default_maximum_page_scale_factor);
#if defined(OS_ANDROID)
settings->setAllowCustomScrollbarInMainFrame(false);
@@ -1109,9 +1100,15 @@ void RenderView::ApplyWebPreferences(const WebPreferences& prefs,
prefs.ignore_main_frame_overflow_hidden_quirk);
settings->setReportScreenSizeInPhysicalPixelsQuirk(
prefs.report_screen_size_in_physical_pixels_quirk);
- settings->setMainFrameClipsContent(false);
- settings->setShrinksStandaloneImagesToFit(false);
+
+ bool record_full_layer =
+ RenderViewImpl::FromWebView(web_view)
+ ? RenderViewImpl::FromWebView(web_view)->DoesRecordFullLayer()
+ : false;
+ settings->setMainFrameClipsContent(!record_full_layer);
+
settings->setShrinksViewportContentToFit(true);
+ settings->setUseMobileViewportStyle(true);
#endif
WebNetworkStateNotifier::setOnLine(prefs.is_online);
@@ -1123,56 +1120,33 @@ void RenderView::ApplyWebPreferences(const WebPreferences& prefs,
settings->setPinchOverlayScrollbarThickness(
prefs.pinch_overlay_scrollbar_thickness);
settings->setUseSolidColorScrollbars(prefs.use_solid_color_scrollbars);
+
+ settings->setShowContextMenuOnMouseUp(prefs.context_menu_on_mouse_up);
+
+#if defined(OS_MACOSX)
+ settings->setDoubleTapToZoomEnabled(true);
+ web_view->setMaximumLegibleScale(prefs.default_maximum_page_scale_factor);
+#endif
}
/*static*/
-RenderViewImpl* RenderViewImpl::Create(
- int32 opener_id,
- bool window_was_created_with_opener,
- const RendererPreferences& renderer_prefs,
- const WebPreferences& webkit_prefs,
- int32 routing_id,
- int32 main_frame_routing_id,
- int32 surface_id,
- int64 session_storage_namespace_id,
- const base::string16& frame_name,
- bool is_renderer_created,
- bool swapped_out,
- int32 proxy_routing_id,
- bool hidden,
- bool never_visible,
- int32 next_page_id,
- const blink::WebScreenInfo& screen_info) {
- DCHECK(routing_id != MSG_ROUTING_NONE);
- RenderViewImplParams params(opener_id,
- window_was_created_with_opener,
- renderer_prefs,
- webkit_prefs,
- routing_id,
- main_frame_routing_id,
- surface_id,
- session_storage_namespace_id,
- frame_name,
- is_renderer_created,
- swapped_out,
- proxy_routing_id,
- hidden,
- never_visible,
- next_page_id,
- screen_info);
+RenderViewImpl* RenderViewImpl::Create(const ViewMsg_New_Params& params,
+ CompositorDependencies* compositor_deps,
+ bool was_created_by_renderer) {
+ DCHECK(params.view_id != MSG_ROUTING_NONE);
RenderViewImpl* render_view = NULL;
if (g_create_render_view_impl)
- render_view = g_create_render_view_impl(&params);
+ render_view = g_create_render_view_impl(params);
else
- render_view = new RenderViewImpl(&params);
+ render_view = new RenderViewImpl(params);
- render_view->Initialize(&params);
+ render_view->Initialize(params, compositor_deps, was_created_by_renderer);
return render_view;
}
// static
void RenderViewImpl::InstallCreateHook(
- RenderViewImpl* (*create_render_view_impl)(RenderViewImplParams*)) {
+ RenderViewImpl* (*create_render_view_impl)(const ViewMsg_New_Params&)) {
CHECK(!g_create_render_view_impl);
g_create_render_view_impl = create_render_view_impl;
}
@@ -1292,7 +1266,7 @@ bool RenderViewImpl::OnMessageReceived(const IPC::Message& message) {
if (main_frame && main_frame->isWebLocalFrame())
GetContentClient()->SetActiveURL(main_frame->document().url());
- ObserverListBase<RenderViewObserver>::Iterator it(observers_);
+ ObserverListBase<RenderViewObserver>::Iterator it(&observers_);
RenderViewObserver* observer;
while ((observer = it.GetNext()) != NULL)
if (observer->OnMessageReceived(message))
@@ -1310,6 +1284,7 @@ bool RenderViewImpl::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(ViewMsg_SaveImageAt, OnSaveImageAt)
IPC_MESSAGE_HANDLER(ViewMsg_Find, OnFind)
IPC_MESSAGE_HANDLER(ViewMsg_StopFinding, OnStopFinding)
+ IPC_MESSAGE_HANDLER(ViewMsg_ResetPageScale, OnResetPageScale)
IPC_MESSAGE_HANDLER(ViewMsg_Zoom, OnZoom)
IPC_MESSAGE_HANDLER(ViewMsg_SetZoomLevelForLoadingURL,
OnSetZoomLevelForLoadingURL)
@@ -1318,7 +1293,6 @@ bool RenderViewImpl::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(ViewMsg_SetPageEncoding, OnSetPageEncoding)
IPC_MESSAGE_HANDLER(ViewMsg_ResetPageEncodingToDefault,
OnResetPageEncodingToDefault)
- IPC_MESSAGE_HANDLER(ViewMsg_PostMessageEvent, OnPostMessageEvent)
IPC_MESSAGE_HANDLER(DragMsg_TargetDragEnter, OnDragTargetDragEnter)
IPC_MESSAGE_HANDLER(DragMsg_TargetDragOver, OnDragTargetDragOver)
IPC_MESSAGE_HANDLER(DragMsg_TargetDragLeave, OnDragTargetDragLeave)
@@ -1357,13 +1331,11 @@ bool RenderViewImpl::OnMessageReceived(const IPC::Message& message) {
OnGetSerializedHtmlDataForCurrentPageWithLocalLinks)
IPC_MESSAGE_HANDLER(ViewMsg_ShowContextMenu, OnShowContextMenu)
// TODO(viettrungluu): Move to a separate message filter.
- IPC_MESSAGE_HANDLER(ViewMsg_SetHistoryLengthAndPrune,
- OnSetHistoryLengthAndPrune)
+ IPC_MESSAGE_HANDLER(ViewMsg_SetHistoryOffsetAndLength,
+ OnSetHistoryOffsetAndLength)
IPC_MESSAGE_HANDLER(ViewMsg_EnableViewSourceMode, OnEnableViewSourceMode)
IPC_MESSAGE_HANDLER(ViewMsg_ReleaseDisambiguationPopupBitmap,
OnReleaseDisambiguationPopupBitmap)
- IPC_MESSAGE_HANDLER(ViewMsg_WindowSnapshotCompleted,
- OnWindowSnapshotCompleted)
IPC_MESSAGE_HANDLER(ViewMsg_ForceRedraw, OnForceRedraw)
IPC_MESSAGE_HANDLER(ViewMsg_SelectWordAroundCaret, OnSelectWordAroundCaret)
#if defined(OS_ANDROID)
@@ -1378,6 +1350,7 @@ bool RenderViewImpl::OnMessageReceived(const IPC::Message& message) {
OnGetRenderedText)
IPC_MESSAGE_HANDLER(ViewMsg_PluginImeCompositionCompleted,
OnPluginImeCompositionCompleted)
+ IPC_MESSAGE_HANDLER(ViewMsg_Close, OnClose)
IPC_MESSAGE_HANDLER(ViewMsg_SetInLiveResize, OnSetInLiveResize)
IPC_MESSAGE_HANDLER(ViewMsg_SetWindowVisibility, OnSetWindowVisibility)
IPC_MESSAGE_HANDLER(ViewMsg_WindowFrameChanged, OnWindowFrameChanged)
@@ -1401,44 +1374,6 @@ void RenderViewImpl::OnSelectWordAroundCaret() {
handling_input_event_ = false;
}
-bool RenderViewImpl::IsBackForwardToStaleEntry(const PageState& state,
- int pending_history_list_offset,
- int32 page_id,
- bool is_reload) {
- // Make sure this isn't a back/forward to an entry we have already cropped
- // or replaced from our history, before the browser knew about it. If so,
- // a new navigation has committed in the mean time, and we can ignore this.
- bool is_back_forward = !is_reload && state.IsValid();
-
- // Note: if the history_list_length_ is 0 for a back/forward, we must be
- // restoring from a previous session. We'll update our state in OnNavigate.
- if (!is_back_forward || history_list_length_ <= 0)
- return false;
-
- DCHECK_EQ(static_cast<int>(history_page_ids_.size()), history_list_length_);
-
- // Check for whether the forward history has been cropped due to a recent
- // navigation the browser didn't know about.
- if (pending_history_list_offset >= history_list_length_)
- return true;
-
- // Check for whether this entry has been replaced with a new one.
- int expected_page_id =
- history_page_ids_[pending_history_list_offset];
- if (expected_page_id > 0 && page_id != expected_page_id) {
- if (page_id < expected_page_id)
- return true;
-
- // Otherwise we've removed an earlier entry and should have shifted all
- // entries left. For now, it's ok to lazily update the list.
- // TODO(creis): Notify all live renderers when we remove entries from
- // the front of the list, so that we don't hit this case.
- history_page_ids_[pending_history_list_offset] = page_id;
- }
-
- return false;
-}
-
void RenderViewImpl::OnCopyImageAt(int x, int y) {
webview()->copyImageAt(WebPoint(x, y));
}
@@ -1477,15 +1412,20 @@ void RenderViewImpl::OnScrollFocusedEditableNodeIntoRect(
const gfx::Rect& rect) {
if (has_scrolled_focused_editable_node_into_rect_ &&
rect == rect_for_scrolled_focused_editable_node_) {
+ FocusChangeComplete();
return;
}
blink::WebElement element = GetFocusedElement();
+ bool will_animate = false;
if (!element.isNull() && IsEditableNode(element)) {
rect_for_scrolled_focused_editable_node_ = rect;
has_scrolled_focused_editable_node_into_rect_ = true;
- webview()->scrollFocusedNodeIntoRect(rect);
+ will_animate = webview()->scrollFocusedNodeIntoRect(rect);
}
+
+ if (!will_animate)
+ FocusChangeComplete();
}
void RenderViewImpl::OnSetEditCommandsForNextKeyEvent(
@@ -1493,27 +1433,15 @@ void RenderViewImpl::OnSetEditCommandsForNextKeyEvent(
edit_commands_ = edit_commands;
}
-void RenderViewImpl::OnSetHistoryLengthAndPrune(int history_length,
- int32 minimum_page_id) {
+void RenderViewImpl::OnSetHistoryOffsetAndLength(int history_offset,
+ int history_length) {
+ DCHECK_GE(history_offset, -1);
DCHECK_GE(history_length, 0);
- DCHECK(history_list_offset_ == history_list_length_ - 1);
- DCHECK_GE(minimum_page_id, -1);
-
- // Generate the new list.
- std::vector<int32> new_history_page_ids(history_length, -1);
- for (size_t i = 0; i < history_page_ids_.size(); ++i) {
- if (minimum_page_id >= 0 && history_page_ids_[i] < minimum_page_id)
- continue;
- new_history_page_ids.push_back(history_page_ids_[i]);
- }
- new_history_page_ids.swap(history_page_ids_);
- // Update indexes.
- history_list_length_ = history_page_ids_.size();
- history_list_offset_ = history_list_length_ - 1;
+ history_list_offset_ = history_offset;
+ history_list_length_ = history_length;
}
-
void RenderViewImpl::OnSetInitialFocus(bool reverse) {
if (!webview())
return;
@@ -1568,21 +1496,6 @@ bool RenderViewImpl::SendAndRunNestedMessageLoop(IPC::SyncMessage* message) {
return Send(message);
}
-void RenderViewImpl::GetWindowSnapshot(const WindowSnapshotCallback& callback) {
- int id = next_snapshot_id_++;
- pending_snapshots_.insert(std::make_pair(id, callback));
- ui::LatencyInfo latency_info;
- latency_info.AddLatencyNumber(ui::WINDOW_OLD_SNAPSHOT_FRAME_NUMBER_COMPONENT,
- 0,
- id);
- scoped_ptr<cc::SwapPromiseMonitor> latency_info_swap_promise_monitor;
- if (RenderWidgetCompositor* rwc = compositor()) {
- latency_info_swap_promise_monitor =
- rwc->CreateLatencyInfoSwapPromiseMonitor(&latency_info).Pass();
- }
- ScheduleCompositeWithForcedRedraw();
-}
-
void RenderViewImpl::OnForceRedraw(int id) {
ui::LatencyInfo latency_info;
if (id) {
@@ -1598,22 +1511,6 @@ void RenderViewImpl::OnForceRedraw(int id) {
ScheduleCompositeWithForcedRedraw();
}
-void RenderViewImpl::OnWindowSnapshotCompleted(const int snapshot_id,
- const gfx::Size& size, const std::vector<unsigned char>& png) {
-
- // 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_snapshots_.begin();
- while(it != pending_snapshots_.end()) {
- if (it->first <= snapshot_id) {
- it->second.Run(size, png);
- pending_snapshots_.erase(it++);
- } else {
- ++it;
- }
- }
-}
-
// blink::WebViewClient ------------------------------------------------------
WebView* RenderViewImpl::createView(WebLocalFrame* creator,
@@ -1655,12 +1552,9 @@ WebView* RenderViewImpl::createView(WebLocalFrame* creator,
int32 surface_id = 0;
int64 cloned_session_storage_namespace_id = 0;
- RenderThread::Get()->Send(
- new ViewHostMsg_CreateWindow(params,
- &routing_id,
- &main_frame_routing_id,
- &surface_id,
- &cloned_session_storage_namespace_id));
+ RenderThread::Get()->Send(new ViewHostMsg_CreateWindow(
+ params, &routing_id, &main_frame_routing_id, &surface_id,
+ &cloned_session_storage_namespace_id));
if (routing_id == MSG_ROUTING_NONE)
return NULL;
@@ -1672,28 +1566,39 @@ WebView* RenderViewImpl::createView(WebLocalFrame* creator,
// TODO(vangelis): Can we tell if the new view will be a background page?
bool never_visible = false;
+ ViewMsg_Resize_Params initial_size = ViewMsg_Resize_Params();
+ initial_size.screen_info = screen_info_;
+
// The initial hidden state for the RenderViewImpl here has to match what the
// browser will eventually decide for the given disposition. Since we have to
// return from this call synchronously, we just have to make our best guess
// and rely on the browser sending a WasHidden / WasShown message if it
// disagrees.
- RenderViewImpl* view = RenderViewImpl::Create(
- routing_id_,
- true, // window_was_created_with_opener
- renderer_preferences_,
- webkit_preferences_,
- routing_id,
- main_frame_routing_id,
- surface_id,
- cloned_session_storage_namespace_id,
- base::string16(), // WebCore will take care of setting the correct name.
- true, // is_renderer_created
- false, // swapped_out
- MSG_ROUTING_NONE, // proxy_routing_id
- params.disposition == NEW_BACKGROUND_TAB, // hidden
- never_visible,
- 1, // next_page_id
- screen_info_);
+ ViewMsg_New_Params view_params;
+ view_params.opener_route_id = routing_id_;
+ view_params.window_was_created_with_opener = true;
+ view_params.renderer_preferences = renderer_preferences_;
+ view_params.web_preferences = webkit_preferences_;
+ view_params.view_id = routing_id;
+ view_params.main_frame_routing_id = main_frame_routing_id;
+ view_params.surface_id = surface_id;
+ view_params.session_storage_namespace_id =
+ cloned_session_storage_namespace_id;
+ // WebCore will take care of setting the correct name.
+ view_params.frame_name = base::string16();
+ view_params.swapped_out = false;
+ view_params.replicated_frame_state = FrameReplicationState();
+ view_params.proxy_routing_id = MSG_ROUTING_NONE;
+ view_params.hidden = (params.disposition == NEW_BACKGROUND_TAB);
+ view_params.never_visible = never_visible;
+ view_params.next_page_id = 1;
+ view_params.initial_size = initial_size;
+ view_params.enable_auto_resize = false;
+ view_params.min_size = gfx::Size();
+ view_params.max_size = gfx::Size();
+
+ RenderViewImpl* view =
+ RenderViewImpl::Create(view_params, compositor_deps_, true);
view->opened_by_user_gesture_ = params.user_gesture;
// Record whether the creator frame is trying to suppress the opener field.
@@ -1703,8 +1608,8 @@ WebView* RenderViewImpl::createView(WebLocalFrame* creator,
}
WebWidget* RenderViewImpl::createPopupMenu(blink::WebPopupType popup_type) {
- RenderWidget* widget =
- RenderWidget::Create(routing_id_, popup_type, screen_info_);
+ RenderWidget* widget = RenderWidget::Create(routing_id_, compositor_deps_,
+ popup_type, screen_info_);
if (!widget)
return NULL;
if (screen_metrics_emulator_) {
@@ -1808,7 +1713,7 @@ bool RenderViewImpl::runFileChooser(
ipc_params.mode = FileChooserParams::Open;
ipc_params.title = params.title;
ipc_params.default_file_name =
- base::FilePath::FromUTF16Unsafe(params.initialValue);
+ base::FilePath::FromUTF16Unsafe(params.initialValue).BaseName();
ipc_params.accept_types.reserve(params.acceptTypes.size());
for (size_t i = 0; i < params.acceptTypes.size(); ++i)
ipc_params.accept_types.push_back(params.acceptTypes[i]);
@@ -1969,15 +1874,35 @@ void RenderViewImpl::focusPrevious() {
Send(new ViewHostMsg_TakeFocus(routing_id_, true));
}
-void RenderViewImpl::focusedNodeChanged(const WebNode& node) {
+void RenderViewImpl::focusedNodeChanged(const WebNode& fromNode,
+ const WebNode& toNode) {
has_scrolled_focused_editable_node_into_rect_ = false;
- Send(new ViewHostMsg_FocusedNodeChanged(routing_id_, IsEditableNode(node)));
+ gfx::Rect node_bounds;
+ if (!toNode.isNull() && toNode.isElementNode()) {
+ WebNode web_node = const_cast<WebNode&>(toNode);
+ node_bounds = gfx::Rect(web_node.to<WebElement>().boundsInViewportSpace());
+ }
+ Send(new ViewHostMsg_FocusedNodeChanged(routing_id_, IsEditableNode(toNode),
+ node_bounds));
+
+ // TODO(estade): remove.
+ FOR_EACH_OBSERVER(RenderViewObserver, observers_, FocusedNodeChanged(toNode));
+
+ RenderFrameImpl* previous_frame = nullptr;
+ if (!fromNode.isNull())
+ previous_frame = RenderFrameImpl::FromWebFrame(fromNode.document().frame());
+ RenderFrameImpl* new_frame = nullptr;
+ if (!toNode.isNull())
+ new_frame = RenderFrameImpl::FromWebFrame(toNode.document().frame());
- FOR_EACH_OBSERVER(RenderViewObserver, observers_, FocusedNodeChanged(node));
+ if (previous_frame && previous_frame != new_frame)
+ previous_frame->FocusedNodeChanged(WebNode());
+ if (new_frame)
+ new_frame->FocusedNodeChanged(toNode);
- // TODO(dmazzoni): this should be part of RenderFrameObserver.
- GetMainRenderFrame()->FocusedNodeChanged(node);
+ // TODO(dmazzoni): remove once there's a separate a11y tree per frame.
+ GetMainRenderFrame()->FocusedNodeChangedForAccessibility(toNode);
}
void RenderViewImpl::didUpdateLayout() {
@@ -2047,44 +1972,13 @@ void RenderViewImpl::show(WebNavigationPolicy policy) {
DCHECK(opener_id_ != MSG_ROUTING_NONE);
- // NOTE: initial_pos_ may still have its default values at this point, but
+ // NOTE: initial_rect_ may still have its default values at this point, but
// that's okay. It'll be ignored if disposition is not NEW_POPUP, or the
// browser process will impose a default position otherwise.
Send(new ViewHostMsg_ShowView(opener_id_, routing_id_,
- NavigationPolicyToDisposition(policy), initial_pos_,
+ NavigationPolicyToDisposition(policy), initial_rect_,
opened_by_user_gesture_));
- SetPendingWindowRect(initial_pos_);
-}
-
-void RenderViewImpl::runModal() {
- DCHECK(did_show_) << "should already have shown the view";
-
- // Don't allow further dialogs if we are waiting to swap out, since the
- // PageGroupLoadDeferrer in our stack prevents it.
- if (suppress_dialogs_until_swap_out_)
- return;
-
- // We must keep WebKit's shared timer running in this case in order to allow
- // showModalDialog to function properly.
- //
- // TODO(darin): WebKit should really be smarter about suppressing events and
- // timers so that we do not need to manage the shared timer in such a heavy
- // handed manner.
- //
- if (RenderThreadImpl::current()) // Will be NULL during unit tests.
- RenderThreadImpl::current()->DoNotSuspendWebKitSharedTimer();
-
- SendAndRunNestedMessageLoop(new ViewHostMsg_RunModal(
- routing_id_, opener_id_));
-}
-
-bool RenderViewImpl::enterFullScreen() {
- Send(new ViewHostMsg_ToggleFullscreen(routing_id_, true));
- return true;
-}
-
-void RenderViewImpl::exitFullScreen() {
- Send(new ViewHostMsg_ToggleFullscreen(routing_id_, false));
+ SetPendingWindowRect(initial_rect_);
}
bool RenderViewImpl::requestPointerLock() {
@@ -2131,15 +2025,15 @@ void RenderViewImpl::initializeLayerTreeView() {
RenderWidgetCompositor* rwc = compositor();
if (!rwc)
return;
- if (webview() && webview()->devToolsAgent())
- webview()->devToolsAgent()->setLayerTreeId(rwc->GetLayerTreeId());
bool use_threaded_event_handling = true;
#if defined(OS_MACOSX) && !defined(OS_IOS)
- // Development flag because many events are still unhandled on Mac.
- // http://crbug.com/138003
- use_threaded_event_handling = CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableThreadedEventHandlingMac);
+ // Disable threaded event handling if content is not handling the elastic
+ // overscroll effect. This includes the cases where the elastic overscroll
+ // effect is being handled by Blink (because of command line flags) and older
+ // operating system versions which do not have an elastic overscroll effect
+ // (SnowLeopard, which has Aqua scrollbars which need synchronous updates).
+ use_threaded_event_handling = compositor_deps_->IsElasticOverscrollEnabled();
#endif
if (use_threaded_event_handling) {
RenderThreadImpl* render_thread = RenderThreadImpl::current();
@@ -2189,219 +2083,11 @@ const std::string& RenderViewImpl::GetAcceptLanguages() const {
return renderer_preferences_.accept_languages;
}
-void RenderViewImpl::didCreateDataSource(WebLocalFrame* frame,
- WebDataSource* ds) {
- bool content_initiated = !pending_navigation_params_.get();
-
- // Make sure any previous redirect URLs end up in our new data source.
- if (pending_navigation_params_.get()) {
- for (std::vector<GURL>::const_iterator i =
- pending_navigation_params_->redirects.begin();
- i != pending_navigation_params_->redirects.end(); ++i) {
- ds->appendRedirect(*i);
- }
- }
-
- DocumentState* document_state = DocumentState::FromDataSource(ds);
- if (!document_state) {
- document_state = new DocumentState;
- ds->setExtraData(document_state);
- if (!content_initiated)
- PopulateDocumentStateFromPending(document_state);
- }
-
- // Carry over the user agent override flag, if it exists.
- if (content_initiated && webview() && webview()->mainFrame() &&
- webview()->mainFrame()->isWebLocalFrame() &&
- webview()->mainFrame()->dataSource()) {
- DocumentState* old_document_state =
- DocumentState::FromDataSource(webview()->mainFrame()->dataSource());
- if (old_document_state) {
- InternalDocumentStateData* internal_data =
- InternalDocumentStateData::FromDocumentState(document_state);
- InternalDocumentStateData* old_internal_data =
- InternalDocumentStateData::FromDocumentState(old_document_state);
- internal_data->set_is_overriding_user_agent(
- old_internal_data->is_overriding_user_agent());
- }
- }
-
- // The rest of RenderView assumes that a WebDataSource will always have a
- // non-null NavigationState.
- if (content_initiated) {
- document_state->set_navigation_state(
- NavigationState::CreateContentInitiated());
- } else {
- document_state->set_navigation_state(CreateNavigationStateFromPending());
- pending_navigation_params_.reset();
- }
-
- // DocumentState::referred_by_prefetcher_ is true if we are
- // navigating from a page that used prefetching using a link on that
- // page. We are early enough in the request process here that we
- // can still see the DocumentState of the previous page and set
- // this value appropriately.
- // TODO(gavinp): catch the important case of navigation in a new
- // renderer process.
- if (webview()) {
- if (WebFrame* old_frame = webview()->mainFrame()) {
- const WebURLRequest& original_request = ds->originalRequest();
- const GURL referrer(
- original_request.httpHeaderField(WebString::fromUTF8("Referer")));
- if (!referrer.is_empty() && old_frame->isWebLocalFrame() &&
- DocumentState::FromDataSource(old_frame->dataSource())
- ->was_prefetcher()) {
- for (; old_frame; old_frame = old_frame->traverseNext(false)) {
- WebDataSource* old_frame_ds = old_frame->dataSource();
- if (old_frame_ds && referrer == GURL(old_frame_ds->request().url())) {
- document_state->set_was_referred_by_prefetcher(true);
- break;
- }
- }
- }
- }
- }
-
- if (content_initiated) {
- const WebURLRequest& request = ds->request();
- switch (request.cachePolicy()) {
- case WebURLRequest::UseProtocolCachePolicy: // normal load.
- document_state->set_load_type(DocumentState::LINK_LOAD_NORMAL);
- break;
- case WebURLRequest::ReloadIgnoringCacheData: // reload.
- case WebURLRequest::ReloadBypassingCache: // end-to-end reload.
- document_state->set_load_type(DocumentState::LINK_LOAD_RELOAD);
- break;
- case WebURLRequest::ReturnCacheDataElseLoad: // allow stale data.
- document_state->set_load_type(
- DocumentState::LINK_LOAD_CACHE_STALE_OK);
- break;
- case WebURLRequest::ReturnCacheDataDontLoad: // Don't re-post.
- document_state->set_load_type(DocumentState::LINK_LOAD_CACHE_ONLY);
- break;
- default:
- NOTREACHED();
- }
- }
-
- FOR_EACH_OBSERVER(
- RenderViewObserver, observers_, DidCreateDataSource(frame, ds));
-}
-
-void RenderViewImpl::PopulateDocumentStateFromPending(
- DocumentState* document_state) {
- const FrameMsg_Navigate_Params& params = *pending_navigation_params_.get();
- document_state->set_request_time(params.request_time);
-
- InternalDocumentStateData* internal_data =
- InternalDocumentStateData::FromDocumentState(document_state);
-
- if (!params.common_params.url.SchemeIs(url::kJavaScriptScheme) &&
- params.common_params.navigation_type == FrameMsg_Navigate_Type::RESTORE) {
- // We're doing a load of a page that was restored from the last session. By
- // default this prefers the cache over loading (LOAD_PREFERRING_CACHE) which
- // can result in stale data for pages that are set to expire. We explicitly
- // override that by setting the policy here so that as necessary we load
- // from the network.
- //
- // TODO(davidben): Remove this in favor of passing a cache policy to the
- // loadHistoryItem call in OnNavigate. That requires not overloading
- // UseProtocolCachePolicy to mean both "normal load" and "determine cache
- // policy based on load type, etc".
- internal_data->set_cache_policy_override(
- WebURLRequest::UseProtocolCachePolicy);
- }
-
- if (IsReload(params.common_params.navigation_type))
- document_state->set_load_type(DocumentState::RELOAD);
- else if (params.commit_params.page_state.IsValid())
- document_state->set_load_type(DocumentState::HISTORY_LOAD);
- else
- document_state->set_load_type(DocumentState::NORMAL_LOAD);
-
- internal_data->set_is_overriding_user_agent(
- params.commit_params.is_overriding_user_agent);
- internal_data->set_must_reset_scroll_and_scale_state(
- params.common_params.navigation_type ==
- FrameMsg_Navigate_Type::RELOAD_ORIGINAL_REQUEST_URL);
- document_state->set_can_load_local_resources(params.can_load_local_resources);
-}
-
-NavigationState* RenderViewImpl::CreateNavigationStateFromPending() {
- const FrameMsg_Navigate_Params& params = *pending_navigation_params_.get();
- NavigationState* navigation_state = NULL;
-
- // A navigation resulting from loading a javascript URL should not be treated
- // as a browser initiated event. Instead, we want it to look as if the page
- // initiated any load resulting from JS execution.
- if (!params.common_params.url.SchemeIs(url::kJavaScriptScheme)) {
- navigation_state = NavigationState::CreateBrowserInitiated(
- params.page_id,
- params.pending_history_list_offset,
- params.should_clear_history_list,
- params.common_params.transition);
- navigation_state->set_should_replace_current_entry(
- params.should_replace_current_entry);
- navigation_state->set_transferred_request_child_id(
- params.transferred_request_child_id);
- navigation_state->set_transferred_request_request_id(
- params.transferred_request_request_id);
- navigation_state->set_allow_download(params.common_params.allow_download);
- navigation_state->set_extra_headers(params.request_params.extra_headers);
- } else {
- navigation_state = NavigationState::CreateContentInitiated();
- }
- return navigation_state;
-}
-
-void RenderViewImpl::ProcessViewLayoutFlags(const CommandLine& command_line) {
- bool enable_viewport =
- command_line.HasSwitch(switches::kEnableViewport) ||
- command_line.HasSwitch(switches::kEnableViewportMeta);
-
- // If viewport tag is enabled, then the WebKit side will take care
- // of setting the fixed layout size and page scale limits.
- if (enable_viewport)
- return;
-
- // When navigating to a new page, reset the page scale factor to be 1.0.
- webview()->setInitialPageScaleOverride(1.f);
-
- float maxPageScaleFactor =
- command_line.HasSwitch(switches::kEnablePinch) ? 4.f : 1.f ;
- webview()->setPageScaleFactorLimits(1, maxPageScaleFactor);
-}
-
-void RenderViewImpl::didClearWindowObject(WebLocalFrame* frame) {
- FOR_EACH_OBSERVER(
- RenderViewObserver, observers_, DidClearWindowObject(frame));
-
- if (enabled_bindings_& BINDINGS_POLICY_WEB_UI)
- WebUIExtension::Install(frame);
-
- if (enabled_bindings_ & BINDINGS_POLICY_STATS_COLLECTION)
- StatsCollectionController::Install(frame);
-
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
-
- if (command_line.HasSwitch(switches::kEnableSkiaBenchmarking))
- SkiaBenchmarking::Install(frame);
-
- if (command_line.HasSwitch(cc::switches::kEnableGpuBenchmarking))
- GpuBenchmarking::Install(frame);
-
- if (command_line.HasSwitch(switches::kEnableMemoryBenchmarking))
- MemoryBenchmarkingExtension::Install(frame);
-}
-
void RenderViewImpl::didChangeIcon(WebLocalFrame* frame,
WebIconURL::Type icon_type) {
if (frame->parent())
return;
- if (!TouchEnabled() && icon_type != WebIconURL::TypeFavicon)
- return;
-
WebVector<WebIconURL> icon_urls = frame->iconURLs(icon_type);
std::vector<FaviconURL> urls;
for (size_t i = 0; i < icon_urls.size(); i++) {
@@ -2425,13 +2111,6 @@ void RenderViewImpl::CheckPreferredSize() {
return;
gfx::Size size = webview()->contentsPreferredMinimumSize();
-
- // In the presence of zoom, these sizes are still reported as if unzoomed,
- // so we need to adjust.
- double zoom_factor = ZoomLevelToZoomFactor(webview()->zoomLevel());
- size.set_width(static_cast<int>(size.width() * zoom_factor));
- size.set_height(static_cast<int>(size.height() * zoom_factor));
-
if (size == preferred_size_)
return;
@@ -2440,17 +2119,8 @@ void RenderViewImpl::CheckPreferredSize() {
preferred_size_));
}
-BrowserPluginManager* RenderViewImpl::GetBrowserPluginManager() {
- if (!browser_plugin_manager_.get())
- browser_plugin_manager_ = BrowserPluginManager::Create(this);
- return browser_plugin_manager_.get();
-}
-
void RenderViewImpl::didChangeScrollOffset(WebLocalFrame* frame) {
StartNavStateSyncTimerIfNecessary();
-
- FOR_EACH_OBSERVER(
- RenderViewObserver, observers_, DidChangeScrollOffset(frame));
}
void RenderViewImpl::SendFindReply(int request_id,
@@ -2490,7 +2160,7 @@ bool RenderViewImpl::Send(IPC::Message* message) {
}
RenderFrameImpl* RenderViewImpl::GetMainRenderFrame() {
- return main_render_frame_.get();
+ return main_render_frame_;
}
int RenderViewImpl::GetRoutingID() const {
@@ -2513,19 +2183,6 @@ blink::WebView* RenderViewImpl::GetWebView() {
return webview();
}
-blink::WebElement RenderViewImpl::GetFocusedElement() const {
- if (!webview())
- return WebElement();
- WebFrame* focused_frame = webview()->focusedFrame();
- if (focused_frame) {
- WebDocument doc = focused_frame->document();
- if (!doc.isNull())
- return doc.focusedElement();
- }
-
- return WebElement();
-}
-
bool RenderViewImpl::IsEditableNode(const WebNode& node) const {
if (node.isNull())
return false;
@@ -2554,13 +2211,6 @@ bool RenderViewImpl::IsEditableNode(const WebNode& node) const {
return false;
}
-bool RenderViewImpl::NodeContainsPoint(const WebNode& node,
- const gfx::Point& point) const {
- blink::WebHitTestResult hit_test =
- webview()->hitTestResultAt(WebPoint(point.x(), point.y()));
- return node.containsIncludingShadowDOM(hit_test.node());
-}
-
bool RenderViewImpl::ShouldDisplayScrollbars(int width, int height) const {
return (!send_preferred_size_changes_ ||
(disable_scrollbars_size_limit_.width() <= width ||
@@ -2593,6 +2243,19 @@ void RenderViewImpl::SyncNavigationState() {
SendUpdateState(history_controller_->GetCurrentEntry());
}
+blink::WebElement RenderViewImpl::GetFocusedElement() const {
+ if (!webview())
+ return WebElement();
+ WebFrame* focused_frame = webview()->focusedFrame();
+ if (focused_frame) {
+ WebDocument doc = focused_frame->document();
+ if (!doc.isNull())
+ return doc.focusedElement();
+ }
+
+ return WebElement();
+}
+
blink::WebPlugin* RenderViewImpl::GetWebPluginForFind() {
if (!webview())
return NULL;
@@ -2814,6 +2477,12 @@ void RenderViewImpl::OnFindMatchRects(int current_version) {
}
#endif
+void RenderViewImpl::OnResetPageScale() {
+ if (!webview())
+ return;
+ webview()->setPageScaleFactor(1);
+}
+
void RenderViewImpl::OnZoom(PageZoom zoom) {
if (!webview()) // Not sure if this can happen, but no harm in being safe.
return;
@@ -2871,67 +2540,6 @@ void RenderViewImpl::OnResetPageEncodingToDefault() {
webview()->setPageEncoding(no_encoding);
}
-void RenderViewImpl::OnPostMessageEvent(
- const ViewMsg_PostMessage_Params& params) {
- // TODO(nasko): Support sending to subframes.
- WebFrame* frame = webview()->mainFrame();
-
- // Find the source frame if it exists.
- WebFrame* source_frame = NULL;
- if (params.source_routing_id != MSG_ROUTING_NONE) {
- RenderViewImpl* source_view = FromRoutingID(params.source_routing_id);
- if (source_view)
- source_frame = source_view->webview()->mainFrame();
- }
-
- // If the message contained MessagePorts, create the corresponding endpoints.
- DCHECK_EQ(params.message_port_ids.size(), params.new_routing_ids.size());
- blink::WebMessagePortChannelArray channels(params.message_port_ids.size());
- for (size_t i = 0;
- i < params.message_port_ids.size() && i < params.new_routing_ids.size();
- ++i) {
- channels[i] =
- new WebMessagePortChannelImpl(params.new_routing_ids[i],
- params.message_port_ids[i],
- base::MessageLoopProxy::current().get());
- }
-
- WebSerializedScriptValue serialized_script_value;
- if (params.is_data_raw_string) {
- v8::HandleScope handle_scope(blink::mainThreadIsolate());
- v8::Local<v8::Context> context = frame->mainWorldScriptContext();
- v8::Context::Scope context_scope(context);
- V8ValueConverterImpl converter;
- converter.SetDateAllowed(true);
- converter.SetRegExpAllowed(true);
- scoped_ptr<base::Value> value(new base::StringValue(params.data));
- v8::Handle<v8::Value> result_value = converter.ToV8Value(value.get(),
- context);
- serialized_script_value = WebSerializedScriptValue::serialize(result_value);
- } else {
- serialized_script_value = WebSerializedScriptValue::fromString(params.data);
- }
-
- // Create an event with the message. The final parameter to initMessageEvent
- // is the last event ID, which is not used with postMessage.
- WebDOMEvent event = frame->document().createEvent("MessageEvent");
- WebDOMMessageEvent msg_event = event.to<WebDOMMessageEvent>();
- msg_event.initMessageEvent("message",
- // |canBubble| and |cancellable| are always false
- false, false,
- serialized_script_value,
- params.source_origin, source_frame, "", channels);
-
- // We must pass in the target_origin to do the security check on this side,
- // since it may have changed since the original postMessage call was made.
- WebSecurityOrigin target_origin;
- if (!params.target_origin.empty()) {
- target_origin =
- WebSecurityOrigin::createFromString(WebString(params.target_origin));
- }
- frame->dispatchMessageEventWithOriginCheck(target_origin, msg_event);
-}
-
void RenderViewImpl::OnAllowBindings(int enabled_bindings_flags) {
if ((enabled_bindings_flags & BINDINGS_POLICY_WEB_UI) &&
!(enabled_bindings_ & BINDINGS_POLICY_WEB_UI)) {
@@ -3071,10 +2679,12 @@ void RenderViewImpl::OnDisableAutoResize(const gfx::Size& new_size) {
if (!new_size.IsEmpty()) {
Resize(new_size,
physical_backing_size_,
- top_controls_layout_height_,
+ top_controls_shrink_blink_size_,
+ top_controls_height_,
visible_viewport_size_,
resizer_rect_,
- is_fullscreen_,
+ is_fullscreen_granted_,
+ display_mode_,
NO_RESIZE_ACK);
}
}
@@ -3100,7 +2710,9 @@ void RenderViewImpl::OnSetRendererPrefs(
std::string old_accept_languages = renderer_preferences_.accept_languages;
renderer_preferences_ = renderer_prefs;
+
UpdateFontRenderingFromRendererPrefs();
+ UpdateThemePrefs();
#if defined(USE_DEFAULT_RENDER_THEME)
if (renderer_prefs.use_custom_colors) {
@@ -3143,12 +2755,8 @@ void RenderViewImpl::OnMediaPlayerActionAt(const gfx::Point& location,
}
void RenderViewImpl::OnOrientationChange() {
- // TODO(mlamouri): consumers of that event should be using DisplayObserver.
- FOR_EACH_OBSERVER(RenderViewObserver,
- observers_,
- OrientationChangeEvent());
-
- webview()->mainFrame()->toWebLocalFrame()->sendOrientationChangeEvent();
+ if (webview() && webview()->mainFrame()->isWebLocalFrame())
+ webview()->mainFrame()->toWebLocalFrame()->sendOrientationChangeEvent();
}
void RenderViewImpl::OnPluginActionAt(const gfx::Point& location,
@@ -3223,21 +2831,6 @@ void RenderViewImpl::OnSuppressDialogsUntilSwapOut() {
suppress_dialogs_until_swap_out_ = true;
}
-void RenderViewImpl::NavigateToSwappedOutURL(blink::WebFrame* frame) {
- // We use loadRequest instead of loadHTMLString because the former commits
- // synchronously. Otherwise a new navigation can interrupt the navigation
- // to kSwappedOutURL. If that happens to be to the page we had been
- // showing, then WebKit will never send a commit and we'll be left spinning.
- // TODO(creis): Until we move this to RenderFrame, we may call this from a
- // swapped out RenderFrame while our own is_swapped_out_ is false.
- RenderFrameImpl* rf = RenderFrameImpl::FromWebFrame(frame);
- CHECK(is_swapped_out_ || rf->is_swapped_out());
- GURL swappedOutURL(kSwappedOutURL);
- WebURLRequest request(swappedOutURL);
- if (frame->isWebLocalFrame())
- frame->loadRequest(request);
-}
-
void RenderViewImpl::OnClosePage() {
FOR_EACH_OBSERVER(RenderViewObserver, observers_, ClosePage());
// TODO(creis): We'd rather use webview()->Close() here, but that currently
@@ -3252,6 +2845,12 @@ void RenderViewImpl::OnClosePage() {
Send(new ViewHostMsg_ClosePage_ACK(routing_id_));
}
+void RenderViewImpl::OnClose() {
+ if (closing_)
+ RenderThread::Get()->Send(new ViewHostMsg_Close_ACK(routing_id_));
+ RenderWidget::OnClose();
+}
+
void RenderViewImpl::OnThemeChanged() {
#if defined(USE_AURA)
// Aura doesn't care if we switch themes.
@@ -3279,6 +2878,10 @@ void RenderViewImpl::OnResize(const ViewMsg_Resize_Params& params) {
ShouldDisplayScrollbars(params.new_size.width(),
params.new_size.height()));
}
+ if (display_mode_ != params.display_mode) {
+ display_mode_ = params.display_mode;
+ webview()->setDisplayMode(display_mode_);
+ }
}
gfx::Size old_visible_viewport_size = visible_viewport_size_;
@@ -3287,10 +2890,6 @@ void RenderViewImpl::OnResize(const ViewMsg_Resize_Params& params) {
if (old_visible_viewport_size != visible_viewport_size_)
has_scrolled_focused_editable_node_into_rect_ = false;
-
- FOR_EACH_OBSERVER(RenderViewObserver,
- observers_,
- Resized());
}
void RenderViewImpl::DidInitiatePaint() {
@@ -3307,34 +2906,6 @@ void RenderViewImpl::DidInitiatePaint() {
}
void RenderViewImpl::DidFlushPaint() {
-#if defined(ENABLE_PLUGINS)
- // Notify all instances that we flushed. This will call into the plugin, and
- // we it may ask to close itself as a result. This will, in turn, modify our
- // set, possibly invalidating the iterator. So we iterate on a copy that
- // won't change out from under us.
- PepperPluginSet plugins = active_pepper_instances_;
- for (PepperPluginSet::iterator i = plugins.begin(); i != plugins.end(); ++i) {
- // The copy above makes sure our iterator is never invalid if some plugins
- // are destroyed. But some plugin may decide to close all of its views in
- // response to a paint in one of them, so we need to make sure each one is
- // still "current" before using it.
- //
- // It's possible that a plugin was destroyed, but another one was created
- // with the same address. In this case, we'll call ViewFlushedPaint on that
- // new plugin. But that's OK for this particular case since we're just
- // notifying all of our instances that the view flushed, and the new one is
- // one of our instances.
- //
- // What about the case where a new one is created in a callback at a new
- // address and we don't issue the callback? We're still OK since this
- // callback is used for flush callbacks and we could not have possibly
- // started a new paint for the new plugin while processing a previous paint
- // for an existing one.
- if (active_pepper_instances_.find(*i) != active_pepper_instances_.end())
- (*i)->ViewFlushedPaint();
- }
-#endif
-
// If the RenderWidget is closing down then early-exit, otherwise we'll crash.
// See crbug.com/112921.
if (!webview())
@@ -3356,6 +2927,9 @@ void RenderViewImpl::DidFlushPaint() {
// of loading and we don't want to save stats.
if (!main_frame->provisionalDataSource()) {
WebDataSource* ds = main_frame->dataSource();
+ if (!ds)
+ return;
+
DocumentState* document_state = DocumentState::FromDataSource(ds);
// TODO(jar): The following code should all be inside a method, probably in
@@ -3449,12 +3023,6 @@ void RenderViewImpl::OnPluginImeCompositionCompleted(const base::string16& text,
}
#endif // OS_MACOSX
-void RenderViewImpl::OnClose() {
- if (closing_)
- RenderThread::Get()->Send(new ViewHostMsg_Close_ACK(routing_id_));
- RenderWidget::OnClose();
-}
-
void RenderViewImpl::Close() {
// We need to grab a pointer to the doomed WebView before we destroy it.
WebView* doomed = webview();
@@ -3503,10 +3071,6 @@ void RenderViewImpl::DidHandleMouseEvent(const WebMouseEvent& event) {
FOR_EACH_OBSERVER(RenderViewObserver, observers_, DidHandleMouseEvent(event));
}
-void RenderViewImpl::DidHandleTouchEvent(const WebTouchEvent& event) {
- FOR_EACH_OBSERVER(RenderViewObserver, observers_, DidHandleTouchEvent(event));
-}
-
bool RenderViewImpl::HasTouchEventHandlersAt(const gfx::Point& point) const {
if (!webview())
return false;
@@ -3602,8 +3166,8 @@ void RenderViewImpl::OnSetFocus(bool enable) {
(*i)->SetContentAreaFocus(enable);
#endif
// Notify all BrowserPlugins of the RenderView's focus state.
- if (browser_plugin_manager_.get())
- browser_plugin_manager_->UpdateFocusState();
+ if (BrowserPluginManager::Get())
+ BrowserPluginManager::Get()->UpdateFocusState();
}
void RenderViewImpl::OnImeSetComposition(
@@ -3619,8 +3183,8 @@ void RenderViewImpl::OnImeSetComposition(
}
#if defined(OS_WIN)
- // When a plug-in has focus, we create platform-specific IME data used by
- // our IME emulator and send it directly to the focused plug-in, i.e. we
+ // When a plugin has focus, we create platform-specific IME data used by
+ // our IME emulator and send it directly to the focused plugin, i.e. we
// bypass WebKit. (WebPluginDelegate dispatches this IME data only when its
// instance ID is the same one as the specified ID.)
if (focused_plugin_id_ >= 0) {
@@ -3662,7 +3226,7 @@ void RenderViewImpl::OnImeConfirmComposition(
}
#if defined(OS_WIN)
// Same as OnImeSetComposition(), we send the text from IMEs directly to
- // plug-ins. When we send IME text directly to plug-ins, we should not send
+ // plugins. When we send IME text directly to plugins, we should not send
// it to WebKit to prevent WebKit from controlling IMEs.
// TODO(thakis): Honor |replacement_range| for plugins?
if (focused_plugin_id_ >= 0) {
@@ -3695,15 +3259,10 @@ void RenderViewImpl::SetDeviceScaleFactor(float device_scale_factor) {
if (webview()) {
webview()->setDeviceScaleFactor(device_scale_factor);
webview()->settings()->setPreferCompositingToLCDTextEnabled(
- PreferCompositingToLCDText(device_scale_factor_));
- webview()->settings()->setAcceleratedCompositingForTransitionEnabled(
- ShouldUseTransitionCompositing(device_scale_factor_));
+ PreferCompositingToLCDText(compositor_deps_, device_scale_factor_));
}
if (auto_resize_mode_)
AutoResizeCompositor();
-
- if (browser_plugin_manager_.get())
- browser_plugin_manager_->UpdateDeviceScaleFactor();
}
bool RenderViewImpl::SetDeviceColorProfile(
@@ -3746,7 +3305,11 @@ void RenderViewImpl::GetSelectionBounds(gfx::Rect* start, gfx::Rect* end) {
RenderWidget::GetSelectionBounds(start, end);
}
-#if defined(OS_MACOSX) || defined(USE_AURA) || defined(OS_ANDROID)
+void RenderViewImpl::FocusChangeComplete() {
+ RenderWidget::FocusChangeComplete();
+ FOR_EACH_OBSERVER(RenderViewObserver, observers_, FocusChangeComplete());
+}
+
void RenderViewImpl::GetCompositionCharacterBounds(
std::vector<gfx::Rect>* bounds) {
DCHECK(bounds);
@@ -3791,7 +3354,6 @@ void RenderViewImpl::GetCompositionRange(gfx::Range* range) {
#endif
RenderWidget::GetCompositionRange(range);
}
-#endif
bool RenderViewImpl::CanComposeInline() {
#if defined(ENABLE_PLUGINS)
@@ -3801,48 +3363,18 @@ bool RenderViewImpl::CanComposeInline() {
return true;
}
-void RenderViewImpl::InstrumentWillBeginFrame(int frame_id) {
- if (!webview())
- return;
- if (!webview()->devToolsAgent())
- return;
- webview()->devToolsAgent()->didBeginFrame(frame_id);
-}
-
-void RenderViewImpl::InstrumentDidBeginFrame() {
- if (!webview())
- return;
- if (!webview()->devToolsAgent())
- return;
- // TODO(jamesr/caseq): Decide if this needs to be renamed.
- webview()->devToolsAgent()->didComposite();
-}
-
-void RenderViewImpl::InstrumentDidCancelFrame() {
- if (!webview())
- return;
- if (!webview()->devToolsAgent())
- return;
- webview()->devToolsAgent()->didCancelFrame();
-}
-
-void RenderViewImpl::InstrumentWillComposite() {
- if (!webview())
- return;
- if (!webview()->devToolsAgent())
- return;
- webview()->devToolsAgent()->willComposite();
+void RenderViewImpl::DidCompletePageScaleAnimation() {
+ FocusChangeComplete();
}
void RenderViewImpl::SetScreenMetricsEmulationParameters(
- float device_scale_factor,
- const gfx::Point& root_layer_offset,
- float root_layer_scale) {
+ bool enabled,
+ const blink::WebDeviceEmulationParams& params) {
if (webview() && compositor()) {
- webview()->setCompositorDeviceScaleFactorOverride(device_scale_factor);
- webview()->setRootLayerTransform(
- blink::WebSize(root_layer_offset.x(), root_layer_offset.y()),
- root_layer_scale);
+ if (enabled)
+ webview()->enableDeviceEmulation(params);
+ else
+ webview()->disableDeviceEmulation();
}
}
@@ -3879,9 +3411,11 @@ blink::WebSpeechRecognizer* RenderViewImpl::speechRecognizer() {
void RenderViewImpl::zoomLimitsChanged(double minimum_level,
double maximum_level) {
- int minimum_percent = static_cast<int>(
+ // Round the double to avoid returning incorrect minimum/maximum zoom
+ // percentages.
+ int minimum_percent = round(
ZoomLevelToZoomFactor(minimum_level) * 100);
- int maximum_percent = static_cast<int>(
+ int maximum_percent = round(
ZoomLevelToZoomFactor(maximum_level) * 100);
Send(new ViewHostMsg_UpdateZoomLimits(
@@ -3902,6 +3436,17 @@ void RenderViewImpl::zoomLevelChanged() {
}
}
+void RenderViewImpl::pageScaleFactorChanged() {
+ if (!webview())
+ return;
+ bool page_scale_factor_is_one = webview()->pageScaleFactor() == 1;
+ if (page_scale_factor_is_one == page_scale_factor_is_one_)
+ return;
+ page_scale_factor_is_one_ = page_scale_factor_is_one;
+ Send(new ViewHostMsg_PageScaleFactorIsOneChanged(routing_id_,
+ page_scale_factor_is_one_));
+}
+
double RenderViewImpl::zoomLevelToZoomFactor(double zoom_level) const {
return ZoomLevelToZoomFactor(zoom_level);
}
@@ -3937,18 +3482,12 @@ blink::WebPageVisibilityState RenderViewImpl::visibilityState() const {
blink::WebPageVisibilityState override_state = current_state;
// TODO(jam): move this method to WebFrameClient.
if (GetContentClient()->renderer()->
- ShouldOverridePageVisibilityState(main_render_frame_.get(),
+ ShouldOverridePageVisibilityState(main_render_frame_,
&override_state))
return override_state;
return current_state;
}
-blink::WebPushClient* RenderViewImpl::webPushClient() {
- // TODO(mvanouwerkerk): Remove this method once the Push API code in Blink
- // has also switched over to Frame.
- return main_render_frame_->pushClient();
-}
-
void RenderViewImpl::draggableRegionsChanged() {
FOR_EACH_OBSERVER(
RenderViewObserver,
@@ -3959,8 +3498,6 @@ void RenderViewImpl::draggableRegionsChanged() {
#if defined(OS_ANDROID)
WebContentDetectionResult RenderViewImpl::detectContentAround(
const WebHitTestResult& touch_hit) {
- DCHECK(!touch_hit.isNull());
- DCHECK(!touch_hit.node().isNull());
DCHECK(touch_hit.node().isTextNode());
// Process the position with all the registered content detectors until
@@ -3994,7 +3531,7 @@ void RenderViewImpl::cancelScheduledContentIntents() {
void RenderViewImpl::LaunchAndroidContentIntent(const GURL& intent,
size_t request_id) {
if (request_id != expected_content_intent_id_)
- return;
+ return;
// Remove the content highlighting if any.
scheduleComposite();
@@ -4045,8 +3582,7 @@ bool RenderViewImpl::didTapMultipleTargets(
const WebSize& inner_viewport_offset,
const WebRect& touch_rect,
const WebVector<WebRect>& target_rects) {
- if (!switches::IsLinkDisambiguationPopupEnabled())
- return false;
+ DCHECK(switches::IsLinkDisambiguationPopupEnabled());
// Never show a disambiguation popup when accessibility is enabled,
// as this interferes with "touch exploration".
@@ -4066,7 +3602,7 @@ bool RenderViewImpl::didTapMultipleTargets(
touch_rect, target_rects, GetSize(),
gfx::Rect(webview()->mainFrame()->visibleContentRect()).size(),
device_scale_factor_ * webview()->pageScaleFactor(), &zoom_rect);
- if (!new_total_scale)
+ if (!new_total_scale || zoom_rect.IsEmpty())
return false;
bool handled = false;
@@ -4081,6 +3617,7 @@ bool RenderViewImpl::didTapMultipleTargets(
RenderThreadImpl::current()->shared_bitmap_manager();
scoped_ptr<cc::SharedBitmap> shared_bitmap =
manager->AllocateSharedBitmap(canvas_size);
+ CHECK(!!shared_bitmap);
{
SkBitmap bitmap;
SkImageInfo info = SkImageInfo::MakeN32Premul(canvas_size.width(),
@@ -4154,9 +3691,11 @@ void RenderViewImpl::SetDeviceScaleFactorForTesting(float factor) {
params.visible_viewport_size = visible_viewport_size_;
params.physical_backing_size =
gfx::ToCeiledSize(gfx::ScaleSize(size(), factor));
- params.top_controls_layout_height = 0.f;
+ params.top_controls_shrink_blink_size = false;
+ params.top_controls_height = 0.f;
params.resizer_rect = WebRect();
- params.is_fullscreen = is_fullscreen();
+ params.is_fullscreen_granted = is_fullscreen_granted();
+ params.display_mode = display_mode_;
OnResize(params);
}
@@ -4166,11 +3705,11 @@ void RenderViewImpl::SetDeviceColorProfileForTesting(
}
void RenderViewImpl::ForceResizeForTesting(const gfx::Size& new_size) {
- gfx::Rect new_position(rootWindowRect().x,
- rootWindowRect().y,
- new_size.width(),
- new_size.height());
- ResizeSynchronously(new_position, new_size);
+ gfx::Rect new_window_rect(rootWindowRect().x,
+ rootWindowRect().y,
+ new_size.width(),
+ new_size.height());
+ SetWindowRectSynchronously(new_window_rect);
}
void RenderViewImpl::UseSynchronousResizeModeForTesting(bool enable) {
@@ -4205,9 +3744,8 @@ void RenderViewImpl::SendUpdateFaviconURL(const std::vector<FaviconURL>& urls) {
}
void RenderViewImpl::DidStopLoadingIcons() {
- int icon_types = WebIconURL::TypeFavicon;
- if (TouchEnabled())
- icon_types |= WebIconURL::TypeTouchPrecomposed | WebIconURL::TypeTouch;
+ int icon_types = WebIconURL::TypeFavicon | WebIconURL::TypeTouchPrecomposed |
+ WebIconURL::TypeTouch;
// Favicons matter only for the top-level frame. If it is a WebRemoteFrame,
// just return early.
diff --git a/chromium/content/renderer/render_view_impl.h b/chromium/content/renderer/render_view_impl.h
index 67adc197503..9609e35258b 100644
--- a/chromium/content/renderer/render_view_impl.h
+++ b/chromium/content/renderer/render_view_impl.h
@@ -29,7 +29,6 @@
#include "content/common/frame_message_enums.h"
#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
#include "content/common/navigation_gesture.h"
-#include "content/common/navigation_params.h"
#include "content/common/view_message_enums.h"
#include "content/public/common/page_zoom.h"
#include "content/public/common/referrer.h"
@@ -44,6 +43,7 @@
#include "content/renderer/stats_collection_observer.h"
#include "ipc/ipc_platform_file.h"
#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
+#include "third_party/WebKit/public/platform/WebPageVisibilityState.h"
#include "third_party/WebKit/public/web/WebAXObject.h"
#include "third_party/WebKit/public/web/WebConsoleMessage.h"
#include "third_party/WebKit/public/web/WebDataSource.h"
@@ -54,7 +54,6 @@
#include "third_party/WebKit/public/web/WebNavigationType.h"
#include "third_party/WebKit/public/web/WebNode.h"
#include "third_party/WebKit/public/web/WebPageSerializerClient.h"
-#include "third_party/WebKit/public/web/WebPageVisibilityState.h"
#include "third_party/WebKit/public/web/WebSecurityOrigin.h"
#include "third_party/WebKit/public/web/WebViewClient.h"
#include "ui/base/window_open_disposition.h"
@@ -76,8 +75,8 @@
class PepperDeviceTest;
class SkBitmap;
struct PP_NetAddress_Private;
-struct FrameMsg_Navigate_Params;
-struct ViewMsg_PostMessage_Params;
+struct ViewMsg_New_Params;
+struct ViewMsg_Resize_Params;
struct ViewMsg_StopFinding_Params;
namespace base {
@@ -119,14 +118,9 @@ class WebHitTestResult;
namespace content {
-class BrowserPluginManager;
-class DevToolsAgent;
-class DocumentState;
class HistoryController;
class HistoryEntry;
-class ImageResourceFetcher;
class MouseLockDispatcher;
-class NavigationState;
class PageState;
class PepperPluginInstanceImpl;
class RenderViewImplTest;
@@ -150,6 +144,11 @@ class WebMediaPlayerProxyAndroid;
// RenderView is an object that manages a WebView object, and provides a
// communication interface with an embedding application process.
//
+// DEPRECATED: RenderViewImpl is being removed as part of the SiteIsolation
+// project. New code should be added to RenderFrameImpl instead.
+//
+// For context, please see https://crbug.com/467770 and
+// http://www.chromium.org/developers/design-documents/site-isolation.
class CONTENT_EXPORT RenderViewImpl
: public RenderWidget,
NON_EXPORTED_BASE(public blink::WebViewClient),
@@ -163,27 +162,14 @@ class CONTENT_EXPORT RenderViewImpl
// |opener_id| will be MSG_ROUTING_NONE. When |swapped_out| is true, the
// |proxy_routing_id| is specified, so a RenderFrameProxy can be created for
// this RenderView's main RenderFrame.
- static RenderViewImpl* Create(int32 opener_id,
- bool window_was_created_with_opener,
- const RendererPreferences& renderer_prefs,
- const WebPreferences& webkit_prefs,
- int32 routing_id,
- int32 main_frame_routing_id,
- int32 surface_id,
- int64 session_storage_namespace_id,
- const base::string16& frame_name,
- bool is_renderer_created,
- bool swapped_out,
- int32 proxy_routing_id,
- bool hidden,
- bool never_visible,
- int32 next_page_id,
- const blink::WebScreenInfo& screen_info);
+ static RenderViewImpl* Create(const ViewMsg_New_Params& params,
+ CompositorDependencies* compositor_deps,
+ bool was_created_by_renderer);
// Used by content_layouttest_support to hook into the creation of
// RenderViewImpls.
static void InstallCreateHook(
- RenderViewImpl* (*create_render_view_impl)(RenderViewImplParams*));
+ RenderViewImpl* (*create_render_view_impl)(const ViewMsg_New_Params&));
// Returns the RenderViewImpl containing the given WebView.
static RenderViewImpl* FromWebView(blink::WebView* webview);
@@ -196,8 +182,6 @@ class CONTENT_EXPORT RenderViewImpl
// May return NULL when the view is closing.
blink::WebView* webview() const;
- int history_list_offset() const { return history_list_offset_; }
-
const WebPreferences& webkit_preferences() const {
return webkit_preferences_;
}
@@ -218,9 +202,6 @@ class CONTENT_EXPORT RenderViewImpl
return history_controller_.get();
}
- // Lazily initialize this view's BrowserPluginManager and return it.
- BrowserPluginManager* GetBrowserPluginManager();
-
// Functions to add and remove observers for this object.
void AddObserver(RenderViewObserver* observer);
void RemoveObserver(RenderViewObserver* observer);
@@ -300,16 +281,9 @@ class CONTENT_EXPORT RenderViewImpl
// Returns true if the focused element is editable text from the perspective
// of IME support (also used for on-screen keyboard). Works correctly inside
- // supported PPAPI plug-ins.
+ // supported PPAPI plugins.
bool HasIMETextFocus();
- // Callback for use with GetWindowSnapshot.
- typedef base::Callback<void(
- const gfx::Size&, const std::vector<unsigned char>&)>
- WindowSnapshotCallback;
-
- void GetWindowSnapshot(const WindowSnapshotCallback& callback);
-
// Dispatches the current navigation state to the browser. Called on a
// periodic timer so we don't send too many messages.
void SyncNavigationState();
@@ -351,9 +325,6 @@ class CONTENT_EXPORT RenderViewImpl
virtual void didFocus();
virtual void didBlur();
virtual void show(blink::WebNavigationPolicy policy);
- virtual void runModal();
- virtual bool enterFullScreen();
- virtual void exitFullScreen();
virtual bool requestPointerLock();
virtual void requestPointerUnlock();
virtual bool isPointerLocked();
@@ -404,7 +375,8 @@ class CONTENT_EXPORT RenderViewImpl
virtual bool acceptsLoadDrops();
virtual void focusNext();
virtual void focusPrevious();
- virtual void focusedNodeChanged(const blink::WebNode& node);
+ virtual void focusedNodeChanged(const blink::WebNode& fromNode,
+ const blink::WebNode& toNode);
virtual void didUpdateLayout();
#if defined(OS_ANDROID) || defined(TOOLKIT_VIEWS)
virtual bool didTapMultipleTargets(
@@ -419,6 +391,7 @@ class CONTENT_EXPORT RenderViewImpl
virtual blink::WebSpeechRecognizer* speechRecognizer();
virtual void zoomLimitsChanged(double minimum_level, double maximum_level);
virtual void zoomLevelChanged();
+ virtual void pageScaleFactorChanged();
virtual double zoomLevelToZoomFactor(double zoom_level) const;
virtual double zoomFactorToZoomLevel(double factor) const;
virtual void registerProtocolHandler(const blink::WebString& scheme,
@@ -427,7 +400,6 @@ class CONTENT_EXPORT RenderViewImpl
virtual void unregisterProtocolHandler(const blink::WebString& scheme,
const blink::WebURL& url);
virtual blink::WebPageVisibilityState visibilityState() const;
- virtual blink::WebPushClient* webPushClient();
virtual void draggableRegionsChanged();
#if defined(OS_ANDROID)
@@ -459,10 +431,7 @@ class CONTENT_EXPORT RenderViewImpl
WebPreferences& GetWebkitPreferences() override;
void SetWebkitPreferences(const WebPreferences& preferences) override;
blink::WebView* GetWebView() override;
- blink::WebElement GetFocusedElement() const override;
bool IsEditableNode(const blink::WebNode& node) const override;
- bool NodeContainsPoint(const blink::WebNode& node,
- const gfx::Point& point) const override;
bool ShouldDisplayScrollbars(int width, int height) const override;
int GetEnabledBindings() const override;
bool GetContentStateImmediately() const override;
@@ -476,9 +445,9 @@ class CONTENT_EXPORT RenderViewImpl
SSLStatus GetSSLStatusOfFrame(blink::WebFrame* frame) const override;
const std::string& GetAcceptLanguages() const override;
#if defined(OS_ANDROID)
- virtual void UpdateTopControlsState(TopControlsState constraints,
- TopControlsState current,
- bool animate) override;
+ void UpdateTopControlsState(TopControlsState constraints,
+ TopControlsState current,
+ bool animate) override;
#endif
bool uses_temporary_zoom_level() const { return uses_temporary_zoom_level_; }
@@ -486,14 +455,8 @@ class CONTENT_EXPORT RenderViewImpl
// appropriate section, add it there. If not, there are some random functions
// nearer to the top you can add it to.
- // Cannot use std::set unfortunately since linked_ptr<> does not support
- // operator<.
- typedef std::vector<linked_ptr<ImageResourceFetcher> >
- ImageResourceFetcherList;
-
protected:
// RenderWidget overrides:
- void OnClose() override;
void Close() override;
void OnResize(const ViewMsg_Resize_Params& params) override;
void DidInitiatePaint() override;
@@ -503,7 +466,6 @@ class CONTENT_EXPORT RenderViewImpl
bool WillHandleMouseEvent(const blink::WebMouseEvent& event) override;
bool WillHandleGestureEvent(const blink::WebGestureEvent& event) override;
void DidHandleMouseEvent(const blink::WebMouseEvent& event) override;
- void DidHandleTouchEvent(const blink::WebTouchEvent& event) override;
bool HasTouchEventHandlersAt(const gfx::Point& point) const override;
void OnSetFocus(bool enable) override;
void OnWasHidden() override;
@@ -523,31 +485,30 @@ class CONTENT_EXPORT RenderViewImpl
void OnOrientationChange() override;
ui::TextInputType GetTextInputType() override;
void GetSelectionBounds(gfx::Rect* start, gfx::Rect* end) override;
-#if defined(OS_MACOSX) || defined(USE_AURA) || defined(OS_ANDROID)
+ void FocusChangeComplete() override;
void GetCompositionCharacterBounds(
std::vector<gfx::Rect>* character_bounds) override;
void GetCompositionRange(gfx::Range* range) override;
-#endif
bool CanComposeInline() override;
void DidCommitCompositorFrame() override;
- void InstrumentWillBeginFrame(int frame_id) override;
- void InstrumentDidBeginFrame() override;
- void InstrumentDidCancelFrame() override;
- void InstrumentWillComposite() override;
+ void DidCompletePageScaleAnimation() override;
protected:
- explicit RenderViewImpl(RenderViewImplParams* params);
+ explicit RenderViewImpl(const ViewMsg_New_Params& params);
- void Initialize(RenderViewImplParams* params);
- void SetScreenMetricsEmulationParameters(float device_scale_factor,
- const gfx::Point& root_layer_offset,
- float root_layer_scale) override;
+ void Initialize(const ViewMsg_New_Params& params,
+ CompositorDependencies* compositor_deps,
+ bool was_created_by_renderer);
+ void SetScreenMetricsEmulationParameters(
+ bool enabled,
+ const blink::WebDeviceEmulationParams& params) override;
// Do not delete directly. This class is reference counted.
virtual ~RenderViewImpl();
private:
// For unit tests.
+ friend class DevToolsAgentTest;
friend class PepperDeviceTest;
friend class RenderViewImplTest;
friend class RenderViewTest;
@@ -558,13 +519,12 @@ class CONTENT_EXPORT RenderViewImpl
// code away from this class.
friend class RenderFrameImpl;
+ FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest, RenderFrameMessageAfterDetach);
FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest, DecideNavigationPolicyForWebUI);
FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest,
DidFailProvisionalLoadWithErrorForError);
FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest,
DidFailProvisionalLoadWithErrorForCancellation);
- FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest,
- DontIgnoreBackAfterNavEntryLimit);
FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest, ImeComposition);
FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest, InsertCharacters);
FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest, JSBlockSentAfterPageLoad);
@@ -577,16 +537,19 @@ class CONTENT_EXPORT RenderViewImpl
FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest,
SetEditableSelectionAndComposition);
FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest, StaleNavigationsIgnored);
+ FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest,
+ DontIgnoreBackAfterNavEntryLimit);
FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest, UpdateTargetURLWithInvalidURL);
FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest,
GetCompositionCharacterBoundsTest);
FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest, OnNavigationHttpPost);
+ FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest, ScreenMetricsEmulation);
FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest,
DecideNavigationPolicyHandlesAllTopLevel);
#if defined(OS_MACOSX)
FRIEND_TEST_ALL_PREFIXES(RenderViewTest, MacTestCmdUp);
#endif
- FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest, SetHistoryLengthAndPrune);
+ FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest, SetHistoryLengthAndOffset);
FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest, ZoomLimit);
FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest, NavigateFrame);
FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest, BasicRenderFrame);
@@ -594,6 +557,7 @@ class CONTENT_EXPORT RenderViewImpl
FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest,
MessageOrderInDidChangeSelection);
FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest, SendCandidateWindowEvents);
+ FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest, RenderFrameClearedAfterClose);
FRIEND_TEST_ALL_PREFIXES(SuppressErrorPageTest, Suppresses);
FRIEND_TEST_ALL_PREFIXES(SuppressErrorPageTest, DoesNotSuppress);
@@ -612,15 +576,10 @@ class CONTENT_EXPORT RenderViewImpl
// still live here and are called from RenderFrameImpl. These implementations
// are to be moved to RenderFrameImpl <http://crbug.com/361761>.
- void didCreateDataSource(blink::WebLocalFrame* frame,
- blink::WebDataSource* datasource);
- void didClearWindowObject(blink::WebLocalFrame* frame);
void didChangeIcon(blink::WebLocalFrame*, blink::WebIconURL::Type);
void didUpdateCurrentHistoryItem(blink::WebLocalFrame* frame);
void didChangeScrollOffset(blink::WebLocalFrame* frame);
- static bool IsReload(FrameMsg_Navigate_Type::Value navigation_type);
-
static Referrer GetReferrerFromRequest(
blink::WebFrame* frame,
const blink::WebURLRequest& request);
@@ -647,6 +606,8 @@ class CONTENT_EXPORT RenderViewImpl
void OnCancelDownload(int32 download_id);
void OnClearFocusedElement();
void OnClosePage();
+ void OnClose();
+
void OnShowContextMenu(ui::MenuSourceType source_type,
const gfx::Point& location);
void OnCopyImageAt(int x, int y);
@@ -691,13 +652,12 @@ class CONTENT_EXPORT RenderViewImpl
void OnPluginActionAt(const gfx::Point& location,
const blink::WebPluginAction& action);
void OnMoveOrResizeStarted();
- void OnPostMessageEvent(const ViewMsg_PostMessage_Params& params);
void OnReleaseDisambiguationPopupBitmap(const cc::SharedBitmapId& id);
void OnResetPageEncodingToDefault();
void OnSetActive(bool active);
void OnSetBackgroundOpaque(bool opaque);
void OnExitFullscreen();
- void OnSetHistoryLengthAndPrune(int history_length, int32 minimum_page_id);
+ void OnSetHistoryOffsetAndLength(int history_offset, int history_length);
void OnSetInitialFocus(bool reverse);
void OnSetPageEncoding(const std::string& encoding_name);
void OnSetRendererPrefs(const RendererPreferences& renderer_prefs);
@@ -709,10 +669,9 @@ class CONTENT_EXPORT RenderViewImpl
void OnThemeChanged();
void OnUpdateTargetURLAck();
void OnUpdateWebPreferences(const WebPreferences& prefs);
+ void OnResetPageScale();
void OnZoom(PageZoom zoom);
void OnEnableViewSourceMode();
- void OnWindowSnapshotCompleted(const int snapshot_id,
- const gfx::Size& size, const std::vector<unsigned char>& png);
void OnForceRedraw(int request_id);
void OnSelectWordAroundCaret();
#if defined(OS_ANDROID)
@@ -740,33 +699,13 @@ class CONTENT_EXPORT RenderViewImpl
// Check whether the preferred size has changed.
void CheckPreferredSize();
+ // Gets the currently focused element, if any.
+ blink::WebElement GetFocusedElement() const;
+
// Called to get the WebPlugin to handle find requests in the document.
// Returns NULL if there is no such WebPlugin.
blink::WebPlugin* GetWebPluginForFind();
- // Returns true if the |params| navigation is to an entry that has been
- // cropped due to a recent navigation the browser did not know about.
- bool IsBackForwardToStaleEntry(const PageState& state,
- int pending_history_list_offset,
- int32 page_id,
- bool is_reload);
-
- // Make the given |frame| show an empty, unscriptable page.
- // TODO(creis): Move this to RenderFrame.
- void NavigateToSwappedOutURL(blink::WebFrame* frame);
-
- // If we initiated a navigation, this function will populate |document_state|
- // with the navigation information saved in OnNavigate().
- void PopulateDocumentStateFromPending(DocumentState* document_state);
-
- // Returns a new NavigationState populated with the navigation information
- // saved in OnNavigate().
- NavigationState* CreateNavigationStateFromPending();
-
- // Processes the command-line flags --enable-viewport,
- // --enable-fixed-layout[=w,h] and --enable-pinch.
- void ProcessViewLayoutFlags(const base::CommandLine& command_line);
-
#if defined(OS_ANDROID)
// Launch an Android content intent with the given URL.
void LaunchAndroidContentIntent(const GURL& intent_url, size_t request_id);
@@ -783,7 +722,7 @@ class CONTENT_EXPORT RenderViewImpl
// Starts nav_state_sync_timer_ if it isn't already running.
void StartNavStateSyncTimerIfNecessary();
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
+#if defined(OS_WIN) || (defined(OS_POSIX) && !defined(OS_MACOSX))
void UpdateFontRenderingFromRendererPrefs();
#else
void UpdateFontRenderingFromRendererPrefs() {}
@@ -826,6 +765,13 @@ class CONTENT_EXPORT RenderViewImpl
navigation_gesture_ = gesture;
}
+ // Platform specific theme preferences if any are updated here.
+#if defined(OS_WIN)
+ void UpdateThemePrefs();
+#else
+ void UpdateThemePrefs() {}
+#endif
+
// ---------------------------------------------------------------------------
// ADDING NEW FUNCTIONS? Please keep private functions alphabetized and put
// it in the same order in the .cc file as it was in the header.
@@ -880,13 +826,6 @@ class CONTENT_EXPORT RenderViewImpl
// PageGroupLoadDeferrer on the stack that interferes with swapping out.
bool suppress_dialogs_until_swap_out_;
- // Holds state pertaining to a navigation that we initiated. This is held by
- // the WebDataSource::ExtraData attribute. We use pending_navigation_state_
- // as a temporary holder for the state until the WebDataSource corresponding
- // to the new navigation is created. See DidCreateDataSource.
- // TODO(nasko): Move to RenderFrame, as this is per-frame state.
- scoped_ptr<FrameMsg_Navigate_Params> pending_navigation_params_;
-
// Timer used to delay the updating of nav state (see SyncNavigationState).
base::OneShotTimer<RenderViewImpl> nav_state_sync_timer_;
@@ -894,13 +833,6 @@ class CONTENT_EXPORT RenderViewImpl
// See documentation in RenderView.
int32 page_id_;
- // Indicates the ID of the last page that we sent a FrameNavigate to the
- // browser for. This is used to determine if the most recent transition
- // generated a history entry (less than page_id_), or not (equal to or
- // greater than). Note that this will be greater than page_id_ if the user
- // goes back.
- int32 last_page_id_sent_to_browser_;
-
// The next available page ID to use for this RenderView. These IDs are
// specific to a given RenderView and the frames within it.
int32 next_page_id_;
@@ -920,12 +852,6 @@ class CONTENT_EXPORT RenderViewImpl
// are gone.
int frames_in_progress_;
- // The list of page IDs for each history item this RenderView knows about.
- // Some entries may be -1 if they were rendered by other processes or were
- // restored from a previous session. This lets us detect attempts to
- // navigate to stale entries that have been cropped from our history.
- std::vector<int32> history_page_ids_;
-
// UI state ------------------------------------------------------------------
// The state of our target_url transmissions. When we receive a request to
@@ -963,7 +889,7 @@ class CONTENT_EXPORT RenderViewImpl
#if defined(OS_ANDROID)
// Cache the old top controls state constraints. Used when updating
// current value only without altering the constraints.
- cc::TopControlsState top_controls_constraints_;
+ TopControlsState top_controls_constraints_;
#endif
// View ----------------------------------------------------------------------
@@ -983,7 +909,7 @@ class CONTENT_EXPORT RenderViewImpl
// Helper objects ------------------------------------------------------------
- scoped_ptr<RenderFrameImpl> main_render_frame_;
+ RenderFrameImpl* main_render_frame_;
// The next group of objects all implement RenderViewObserver, so are deleted
// along with the RenderView automatically. This is why we just store
@@ -993,11 +919,6 @@ class CONTENT_EXPORT RenderViewImpl
// initialized.
SpeechRecognitionDispatcher* speech_recognition_dispatcher_;
- // BrowserPluginManager attached to this view; lazily initialized.
- scoped_refptr<BrowserPluginManager> browser_plugin_manager_;
-
- DevToolsAgent* devtools_agent_;
-
// Mouse Lock dispatcher attached to this view.
MouseLockDispatcher* mouse_lock_dispatcher_;
@@ -1026,7 +947,7 @@ class CONTENT_EXPORT RenderViewImpl
std::set<WebPluginDelegateProxy*> plugin_delegates_;
#if defined(OS_WIN)
- // The ID of the focused NPAPI plug-in.
+ // The ID of the focused NPAPI plugin.
int focused_plugin_id_;
#endif
@@ -1080,11 +1001,6 @@ class CONTENT_EXPORT RenderViewImpl
// Wraps the |webwidget_| as a MouseLockDispatcher::LockTarget interface.
scoped_ptr<MouseLockDispatcher::LockTarget> webwidget_mouse_lock_target_;
- // State associated with the GetWindowSnapshot function.
- int next_snapshot_id_;
- typedef std::map<int, WindowSnapshotCallback> PendingSnapshotMap;
- PendingSnapshotMap pending_snapshots_;
-
// This field stores drag/drop related info for the event that is currently
// being handled. If the current event results in starting a drag/drop
// session, this info is sent to the browser along with other drag/drop info.
@@ -1097,6 +1013,8 @@ class CONTENT_EXPORT RenderViewImpl
typedef std::map<cc::SharedBitmapId, cc::SharedBitmap*> BitmapMap;
BitmapMap disambiguation_bitmaps_;
+ bool page_scale_factor_is_one_;
+
// ---------------------------------------------------------------------------
// ADDING NEW DATA? Please see if it fits appropriately in one of the above
// sections rather than throwing it randomly at the end. If you're adding a
diff --git a/chromium/content/renderer/render_view_impl_android.cc b/chromium/content/renderer/render_view_impl_android.cc
index 50b10aa5667..9ba176cfcb5 100644
--- a/chromium/content/renderer/render_view_impl_android.cc
+++ b/chromium/content/renderer/render_view_impl_android.cc
@@ -13,19 +13,24 @@
namespace content {
-// Check content::TopControlsState and cc::TopControlsState are kept in sync.
-COMPILE_ASSERT(int(TOP_CONTROLS_STATE_SHOWN) == int(cc::SHOWN),
- mismatching_enums);
-COMPILE_ASSERT(int(TOP_CONTROLS_STATE_HIDDEN) == int(cc::HIDDEN),
- mismatching_enums);
-COMPILE_ASSERT(int(TOP_CONTROLS_STATE_BOTH) == int(cc::BOTH),
- mismatching_enums);
+// Check content::TopControlsState, and blink::WebWidget::TopControlsState
+// are kept in sync.
+static_assert(
+ int(TOP_CONTROLS_STATE_SHOWN) == int(blink::WebTopControlsShown),
+ "mismatching enums: SHOWN");
+static_assert(
+ int(TOP_CONTROLS_STATE_HIDDEN) == int(blink::WebTopControlsHidden),
+ "mismatching enums: HIDDEN");
+static_assert(
+ int(TOP_CONTROLS_STATE_BOTH) == int(blink::WebTopControlsBoth),
+ "mismatching enums: BOTH");
-cc::TopControlsState ContentToCcTopControlsState(
+blink::WebTopControlsState ContentToBlink(
TopControlsState state) {
- return static_cast<cc::TopControlsState>(state);
+ return static_cast<blink::WebTopControlsState>(state);
}
+
// TODO(mvanouwerkerk): Stop calling this code path and delete it.
void RenderViewImpl::OnUpdateTopControlsState(bool enable_hiding,
bool enable_showing,
@@ -33,38 +38,35 @@ void RenderViewImpl::OnUpdateTopControlsState(bool enable_hiding,
// TODO(tedchoc): Investigate why messages are getting here before the
// compositor has been initialized.
LOG_IF(WARNING, !compositor_) << "OnUpdateTopControlsState was unhandled.";
- if (compositor_) {
- cc::TopControlsState constraints = cc::BOTH;
- if (!enable_showing)
- constraints = cc::HIDDEN;
- if (!enable_hiding)
- constraints = cc::SHOWN;
- cc::TopControlsState current = cc::BOTH;
- compositor_->UpdateTopControlsState(constraints, current, animate);
- top_controls_constraints_ = constraints;
- }
+ TopControlsState constraints = TOP_CONTROLS_STATE_BOTH;
+ if (!enable_showing)
+ constraints = TOP_CONTROLS_STATE_HIDDEN;
+ if (!enable_hiding)
+ constraints = TOP_CONTROLS_STATE_SHOWN;
+ TopControlsState current = TOP_CONTROLS_STATE_BOTH;
+
+ UpdateTopControlsState(constraints, current, animate);
}
void RenderViewImpl::UpdateTopControlsState(TopControlsState constraints,
TopControlsState current,
bool animate) {
- cc::TopControlsState constraints_cc =
- ContentToCcTopControlsState(constraints);
- cc::TopControlsState current_cc = ContentToCcTopControlsState(current);
- if (compositor_)
- compositor_->UpdateTopControlsState(constraints_cc, current_cc, animate);
- top_controls_constraints_ = constraints_cc;
+ if (webwidget())
+ webwidget()->updateTopControlsState(ContentToBlink(constraints),
+ ContentToBlink(current),
+ animate);
+
+ top_controls_constraints_ = constraints;
}
void RenderViewImpl::didScrollWithKeyboard(const blink::WebSize& delta) {
if (delta.height == 0)
return;
- if (compositor_) {
- cc::TopControlsState current = delta.height < 0 ? cc::SHOWN : cc::HIDDEN;
- compositor_->UpdateTopControlsState(top_controls_constraints_,
- current,
- true);
- }
+
+ TopControlsState current = delta.height < 0 ? TOP_CONTROLS_STATE_SHOWN
+ : TOP_CONTROLS_STATE_HIDDEN;
+
+ UpdateTopControlsState(top_controls_constraints_, current, true);
}
void RenderViewImpl::OnExtractSmartClipData(const gfx::Rect& rect) {
diff --git a/chromium/content/renderer/render_view_impl_params.cc b/chromium/content/renderer/render_view_impl_params.cc
deleted file mode 100644
index 6864a3d0edc..00000000000
--- a/chromium/content/renderer/render_view_impl_params.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/renderer/render_view_impl_params.h"
-
-namespace content {
-
-RenderViewImplParams::RenderViewImplParams(
- int32 opener_id,
- bool window_was_created_with_opener,
- const RendererPreferences& renderer_prefs,
- const WebPreferences& webkit_prefs,
- int32 routing_id,
- int32 main_frame_routing_id,
- int32 surface_id,
- int64 session_storage_namespace_id,
- const base::string16& frame_name,
- bool is_renderer_created,
- bool swapped_out,
- int32 proxy_routing_id,
- bool hidden,
- bool never_visible,
- int32 next_page_id,
- const blink::WebScreenInfo& screen_info)
- : opener_id(opener_id),
- window_was_created_with_opener(window_was_created_with_opener),
- renderer_prefs(renderer_prefs),
- webkit_prefs(webkit_prefs),
- routing_id(routing_id),
- main_frame_routing_id(main_frame_routing_id),
- surface_id(surface_id),
- session_storage_namespace_id(session_storage_namespace_id),
- frame_name(frame_name),
- is_renderer_created(is_renderer_created),
- swapped_out(swapped_out),
- proxy_routing_id(proxy_routing_id),
- hidden(hidden),
- never_visible(never_visible),
- next_page_id(next_page_id),
- screen_info(screen_info) {}
-
-RenderViewImplParams::~RenderViewImplParams() {}
-
-} // namespace content
diff --git a/chromium/content/renderer/render_view_impl_params.h b/chromium/content/renderer/render_view_impl_params.h
deleted file mode 100644
index ad9a26c61d3..00000000000
--- a/chromium/content/renderer/render_view_impl_params.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_RENDERER_RENDER_VIEW_IMPL_PARAMS_H_
-#define CONTENT_RENDERER_RENDER_VIEW_IMPL_PARAMS_H_
-
-#include "base/basictypes.h"
-#include "base/memory/ref_counted.h"
-#include "base/strings/string16.h"
-#include "content/common/content_export.h"
-#include "content/common/view_message_enums.h"
-
-namespace blink {
-struct WebScreenInfo;
-}
-
-namespace content {
-
-struct RendererPreferences;
-struct WebPreferences;
-
-// Container for all parameters passed to RenderViewImpl's constructor.
-struct CONTENT_EXPORT RenderViewImplParams {
- RenderViewImplParams(int32 opener_id,
- bool window_was_created_with_opener,
- const RendererPreferences& renderer_prefs,
- const WebPreferences& webkit_prefs,
- int32 routing_id,
- int32 main_frame_routing_id,
- int32 surface_id,
- int64 session_storage_namespace_id,
- const base::string16& frame_name,
- bool is_renderer_created,
- bool swapped_out,
- int32 proxy_routing_id,
- bool hidden,
- bool never_visible,
- int32 next_page_id,
- const blink::WebScreenInfo& screen_info);
- ~RenderViewImplParams();
-
- int32 opener_id;
- bool window_was_created_with_opener;
- const RendererPreferences& renderer_prefs;
- const WebPreferences& webkit_prefs;
- int32 routing_id;
- int32 main_frame_routing_id;
- int32 surface_id;
- int64 session_storage_namespace_id;
- const base::string16& frame_name;
- bool is_renderer_created;
- bool swapped_out;
- int32 proxy_routing_id;
- bool hidden;
- bool never_visible;
- int32 next_page_id;
- const blink::WebScreenInfo& screen_info;
-};
-
-} // namespace content
-
-#endif // CONTENT_RENDERER_RENDER_VIEW_IMPL_PARAMS_H_
diff --git a/chromium/content/renderer/render_view_linux.cc b/chromium/content/renderer/render_view_linux.cc
index f4ef02e7435..7f3ab8db297 100644
--- a/chromium/content/renderer/render_view_linux.cc
+++ b/chromium/content/renderer/render_view_linux.cc
@@ -6,6 +6,7 @@
#include "content/public/common/renderer_preferences.h"
#include "third_party/WebKit/public/web/linux/WebFontRendering.h"
+#include "ui/gfx/font_render_params.h"
using blink::WebFontRendering;
@@ -43,38 +44,6 @@ SkPaint::Hinting RendererPreferencesToSkiaHinting(
}
}
-SkFontHost::LCDOrder RendererPreferencesToSkiaLCDOrder(
- const RendererPreferences& prefs) {
- switch (prefs.subpixel_rendering) {
- case gfx::FontRenderParams::SUBPIXEL_RENDERING_NONE:
- case gfx::FontRenderParams::SUBPIXEL_RENDERING_RGB:
- case gfx::FontRenderParams::SUBPIXEL_RENDERING_VRGB:
- return SkFontHost::kRGB_LCDOrder;
- case gfx::FontRenderParams::SUBPIXEL_RENDERING_BGR:
- case gfx::FontRenderParams::SUBPIXEL_RENDERING_VBGR:
- return SkFontHost::kBGR_LCDOrder;
- default:
- NOTREACHED();
- return SkFontHost::kRGB_LCDOrder;
- }
-}
-
-SkFontHost::LCDOrientation RendererPreferencesToSkiaLCDOrientation(
- const RendererPreferences& prefs) {
- switch (prefs.subpixel_rendering) {
- case gfx::FontRenderParams::SUBPIXEL_RENDERING_NONE:
- case gfx::FontRenderParams::SUBPIXEL_RENDERING_RGB:
- case gfx::FontRenderParams::SUBPIXEL_RENDERING_BGR:
- return SkFontHost::kHorizontal_LCDOrientation;
- case gfx::FontRenderParams::SUBPIXEL_RENDERING_VRGB:
- case gfx::FontRenderParams::SUBPIXEL_RENDERING_VBGR:
- return SkFontHost::kVertical_LCDOrientation;
- default:
- NOTREACHED();
- return SkFontHost::kHorizontal_LCDOrientation;
- }
-}
-
} // namespace
void RenderViewImpl::UpdateFontRenderingFromRendererPrefs() {
@@ -82,9 +51,12 @@ void RenderViewImpl::UpdateFontRenderingFromRendererPrefs() {
WebFontRendering::setHinting(RendererPreferencesToSkiaHinting(prefs));
WebFontRendering::setAutoHint(prefs.use_autohinter);
WebFontRendering::setUseBitmaps(prefs.use_bitmaps);
- WebFontRendering::setLCDOrder(RendererPreferencesToSkiaLCDOrder(prefs));
+ WebFontRendering::setLCDOrder(
+ gfx::FontRenderParams::SubpixelRenderingToSkiaLCDOrder(
+ prefs.subpixel_rendering));
WebFontRendering::setLCDOrientation(
- RendererPreferencesToSkiaLCDOrientation(prefs));
+ gfx::FontRenderParams::SubpixelRenderingToSkiaLCDOrientation(
+ prefs.subpixel_rendering));
WebFontRendering::setAntiAlias(prefs.should_antialias_text);
WebFontRendering::setSubpixelRendering(
prefs.subpixel_rendering !=
diff --git a/chromium/content/renderer/render_view_win.cc b/chromium/content/renderer/render_view_win.cc
new file mode 100644
index 00000000000..15cb47bf7cd
--- /dev/null
+++ b/chromium/content/renderer/render_view_win.cc
@@ -0,0 +1,45 @@
+// 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/common/renderer_preferences.h"
+#include "content/child/webthemeengine_impl_default.h"
+#include "content/renderer/render_view_impl.h"
+#include "third_party/WebKit/public/web/win/WebFontRendering.h"
+#include "ui/gfx/font_render_params.h"
+
+using blink::WebFontRendering;
+
+namespace content {
+
+void RenderViewImpl::UpdateFontRenderingFromRendererPrefs() {
+ const RendererPreferences& prefs = renderer_preferences_;
+
+ // Cache the system font metrics in blink.
+ blink::WebFontRendering::setMenuFontMetrics(
+ prefs.menu_font_family_name.c_str(), prefs.menu_font_height);
+
+ blink::WebFontRendering::setSmallCaptionFontMetrics(
+ prefs.small_caption_font_family_name.c_str(),
+ prefs.small_caption_font_height);
+
+ blink::WebFontRendering::setStatusFontMetrics(
+ prefs.status_font_family_name.c_str(), prefs.status_font_height);
+
+ blink::WebFontRendering::setLCDOrder(
+ gfx::FontRenderParams::SubpixelRenderingToSkiaLCDOrder(
+ prefs.subpixel_rendering));
+ blink::WebFontRendering::setLCDOrientation(
+ gfx::FontRenderParams::SubpixelRenderingToSkiaLCDOrientation(
+ prefs.subpixel_rendering));
+}
+
+void RenderViewImpl::UpdateThemePrefs() {
+ WebThemeEngineImpl::cacheScrollBarMetrics(
+ renderer_preferences_.vertical_scroll_bar_width_in_dips,
+ renderer_preferences_.horizontal_scroll_bar_height_in_dips,
+ renderer_preferences_.arrow_bitmap_height_vertical_scroll_bar_in_dips,
+ renderer_preferences_.arrow_bitmap_width_horizontal_scroll_bar_in_dips);
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/render_widget.cc b/chromium/content/renderer/render_widget.cc
index 2592258bd63..7d0723f6fef 100644
--- a/chromium/content/renderer/render_widget.cc
+++ b/chromium/content/renderer/render_widget.cc
@@ -7,8 +7,6 @@
#include "base/auto_reset.h"
#include "base/bind.h"
#include "base/command_line.h"
-#include "base/debug/trace_event.h"
-#include "base/debug/trace_event_synthetic_delay.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h"
@@ -17,11 +15,14 @@
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/sys_info.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_synthetic_delay.h"
#include "build/build_config.h"
#include "cc/base/switches.h"
#include "cc/debug/benchmark_instrumentation.h"
#include "cc/output/output_surface.h"
#include "cc/trees/layer_tree_host.h"
+#include "components/scheduler/renderer/renderer_scheduler.h"
#include "content/child/npapi/webplugin.h"
#include "content/common/gpu/client/context_provider_command_buffer.h"
#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
@@ -36,7 +37,6 @@
#include "content/renderer/cursor_utils.h"
#include "content/renderer/external_popup_menu.h"
#include "content/renderer/gpu/compositor_output_surface.h"
-#include "content/renderer/gpu/compositor_software_output_device.h"
#include "content/renderer/gpu/delegated_compositor_output_surface.h"
#include "content/renderer/gpu/frame_swap_message_queue.h"
#include "content/renderer/gpu/mailbox_output_surface.h"
@@ -55,29 +55,33 @@
#include "skia/ext/platform_canvas.h"
#include "third_party/WebKit/public/platform/WebCursorInfo.h"
#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
+#include "third_party/WebKit/public/platform/WebPoint.h"
#include "third_party/WebKit/public/platform/WebRect.h"
#include "third_party/WebKit/public/platform/WebScreenInfo.h"
#include "third_party/WebKit/public/platform/WebSize.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/web/WebDeviceEmulationParams.h"
+#include "third_party/WebKit/public/web/WebFrameWidget.h"
+#include "third_party/WebKit/public/web/WebLocalFrame.h"
+#include "third_party/WebKit/public/web/WebNode.h"
#include "third_party/WebKit/public/web/WebPagePopup.h"
#include "third_party/WebKit/public/web/WebPopupMenu.h"
#include "third_party/WebKit/public/web/WebPopupMenuInfo.h"
#include "third_party/WebKit/public/web/WebRange.h"
#include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
+#include "third_party/WebKit/public/web/WebView.h"
#include "third_party/skia/include/core/SkShader.h"
#include "ui/base/ui_base_switches.h"
#include "ui/gfx/frame_time.h"
-#include "ui/gfx/point_conversions.h"
-#include "ui/gfx/rect_conversions.h"
-#include "ui/gfx/size_conversions.h"
+#include "ui/gfx/geometry/point_conversions.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/skia_util.h"
#include "ui/gl/gl_switches.h"
#include "ui/surface/transport_dib.h"
#if defined(OS_ANDROID)
#include <android/keycodes.h>
-#include "base/android/build_info.h"
#include "content/renderer/android/synchronous_compositor_factory.h"
#endif
@@ -98,7 +102,9 @@ using blink::WebKeyboardEvent;
using blink::WebMouseEvent;
using blink::WebMouseWheelEvent;
using blink::WebNavigationPolicy;
+using blink::WebNode;
using blink::WebPagePopup;
+using blink::WebPoint;
using blink::WebPopupMenu;
using blink::WebPopupMenuInfo;
using blink::WebPopupType;
@@ -153,17 +159,79 @@ ui::TextInputMode ConvertInputMode(const blink::WebString& input_mode) {
return it->second;
}
-bool IsThreadedCompositingEnabled() {
- content::RenderThreadImpl* impl = content::RenderThreadImpl::current();
- return impl && !!impl->compositor_message_loop_proxy().get();
-}
-
// TODO(brianderson): Replace the hard-coded threshold with a fraction of
// the BeginMainFrame interval.
// 4166us will allow 1/4 of a 60Hz interval or 1/2 of a 120Hz interval to
// be spent in input hanlders before input starts getting throttled.
const int kInputHandlingTimeThrottlingThresholdMicroseconds = 4166;
+int64 GetEventLatencyMicros(const WebInputEvent& event, base::TimeTicks now) {
+ return (now - base::TimeDelta::FromSecondsD(event.timeStampSeconds))
+ .ToInternalValue();
+}
+
+void LogInputEventLatencyUma(const WebInputEvent& event, base::TimeTicks now) {
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ "Event.AggregatedLatency.Renderer2",
+ GetEventLatencyMicros(event, now),
+ 1,
+ 10000000,
+ 100);
+
+#define CASE_TYPE(t) \
+ case WebInputEvent::t: \
+ UMA_HISTOGRAM_CUSTOM_COUNTS( \
+ "Event.Latency.Renderer2." #t, \
+ GetEventLatencyMicros(event, now), \
+ 1, \
+ 10000000, \
+ 100); \
+ break;
+
+ switch(event.type) {
+ CASE_TYPE(Undefined);
+ CASE_TYPE(MouseDown);
+ CASE_TYPE(MouseUp);
+ CASE_TYPE(MouseMove);
+ CASE_TYPE(MouseEnter);
+ CASE_TYPE(MouseLeave);
+ CASE_TYPE(ContextMenu);
+ CASE_TYPE(MouseWheel);
+ CASE_TYPE(RawKeyDown);
+ CASE_TYPE(KeyDown);
+ CASE_TYPE(KeyUp);
+ CASE_TYPE(Char);
+ CASE_TYPE(GestureScrollBegin);
+ CASE_TYPE(GestureScrollEnd);
+ CASE_TYPE(GestureScrollUpdate);
+ CASE_TYPE(GestureFlingStart);
+ CASE_TYPE(GestureFlingCancel);
+ CASE_TYPE(GestureShowPress);
+ CASE_TYPE(GestureTap);
+ CASE_TYPE(GestureTapUnconfirmed);
+ CASE_TYPE(GestureTapDown);
+ CASE_TYPE(GestureTapCancel);
+ CASE_TYPE(GestureDoubleTap);
+ CASE_TYPE(GestureTwoFingerTap);
+ CASE_TYPE(GestureLongPress);
+ CASE_TYPE(GestureLongTap);
+ CASE_TYPE(GesturePinchBegin);
+ CASE_TYPE(GesturePinchEnd);
+ CASE_TYPE(GesturePinchUpdate);
+ CASE_TYPE(TouchStart);
+ CASE_TYPE(TouchMove);
+ CASE_TYPE(TouchEnd);
+ CASE_TYPE(TouchCancel);
+ default:
+ // Must include default to let blink::WebInputEvent add new event types
+ // before they're added here.
+ DLOG(WARNING) << "Unhandled WebInputEvent type: " << event.type;
+ break;
+ }
+
+#undef CASE_TYPE
+}
+
} // namespace
namespace content {
@@ -180,7 +248,7 @@ class RenderWidget::ScreenMetricsEmulator {
// Scale and offset used to convert between host coordinates
// and webwidget coordinates.
float scale() { return scale_; }
- gfx::Point offset() { return offset_; }
+ gfx::PointF offset() { return offset_; }
gfx::Rect applied_widget_rect() const { return applied_widget_rect_; }
gfx::Rect original_screen_rect() const { return original_view_screen_rect_; }
const WebScreenInfo& original_screen_info() { return original_screen_info_; }
@@ -198,9 +266,11 @@ class RenderWidget::ScreenMetricsEmulator {
private:
void Reapply();
- void Apply(float top_controls_layout_height,
+ void Apply(bool top_controls_shrink_blink_size,
+ float top_controls_height,
gfx::Rect resizer_rect,
- bool is_fullscreen);
+ bool is_fullscreen_granted,
+ blink::WebDisplayMode display_mode);
RenderWidget* widget_;
@@ -209,7 +279,7 @@ class RenderWidget::ScreenMetricsEmulator {
// The computed scale and offset used to fit widget into browser window.
float scale_;
- gfx::Point offset_;
+ gfx::PointF offset_;
// Widget rect as passed to webwidget.
gfx::Rect applied_widget_rect_;
@@ -235,23 +305,28 @@ RenderWidget::ScreenMetricsEmulator::ScreenMetricsEmulator(
original_screen_info_ = widget_->screen_info_;
original_view_screen_rect_ = widget_->view_screen_rect_;
original_window_screen_rect_ = widget_->window_screen_rect_;
- Apply(widget_->top_controls_layout_height_, widget_->resizer_rect_,
- widget_->is_fullscreen_);
+ Apply(widget_->top_controls_shrink_blink_size_,
+ widget_->top_controls_height_,
+ widget_->resizer_rect_,
+ widget_->is_fullscreen_granted_,
+ widget_->display_mode_);
}
RenderWidget::ScreenMetricsEmulator::~ScreenMetricsEmulator() {
widget_->screen_info_ = original_screen_info_;
widget_->SetDeviceScaleFactor(original_screen_info_.deviceScaleFactor);
- widget_->SetScreenMetricsEmulationParameters(0.f, gfx::Point(), 1.f);
+ widget_->SetScreenMetricsEmulationParameters(false, params_);
widget_->view_screen_rect_ = original_view_screen_rect_;
widget_->window_screen_rect_ = original_window_screen_rect_;
widget_->Resize(original_size_,
original_physical_backing_size_,
- widget_->top_controls_layout_height_,
+ widget_->top_controls_shrink_blink_size_,
+ widget_->top_controls_height_,
original_visible_viewport_size_,
widget_->resizer_rect_,
- widget_->is_fullscreen_,
+ widget_->is_fullscreen_granted_,
+ widget_->display_mode_,
NO_RESIZE_ACK);
}
@@ -262,14 +337,19 @@ void RenderWidget::ScreenMetricsEmulator::ChangeEmulationParams(
}
void RenderWidget::ScreenMetricsEmulator::Reapply() {
- Apply(widget_->top_controls_layout_height_, widget_->resizer_rect_,
- widget_->is_fullscreen_);
+ Apply(widget_->top_controls_shrink_blink_size_,
+ widget_->top_controls_height_,
+ widget_->resizer_rect_,
+ widget_->is_fullscreen_granted_,
+ widget_->display_mode_);
}
void RenderWidget::ScreenMetricsEmulator::Apply(
- float top_controls_layout_height,
+ bool top_controls_shrink_blink_size,
+ float top_controls_height,
gfx::Rect resizer_rect,
- bool is_fullscreen) {
+ bool is_fullscreen_granted,
+ blink::WebDisplayMode display_mode) {
applied_widget_rect_.set_size(gfx::Size(params_.viewSize));
if (!applied_widget_rect_.width())
applied_widget_rect_.set_width(original_size_.width());
@@ -317,17 +397,26 @@ void RenderWidget::ScreenMetricsEmulator::Apply(
// even when emulating different scale factor;
// - in order to fit into view, WebView applies offset and scale to the
// root layer.
- widget_->SetScreenMetricsEmulationParameters(
- original_screen_info_.deviceScaleFactor, offset_, scale_);
+ blink::WebDeviceEmulationParams modified_params = params_;
+ modified_params.deviceScaleFactor = original_screen_info_.deviceScaleFactor;
+ modified_params.offset = blink::WebFloatPoint(offset_.x(), offset_.y());
+ modified_params.scale = scale_;
+ widget_->SetScreenMetricsEmulationParameters(true, modified_params);
widget_->SetDeviceScaleFactor(applied_device_scale_factor);
widget_->view_screen_rect_ = applied_widget_rect_;
gfx::Size physical_backing_size = gfx::ToCeiledSize(gfx::ScaleSize(
original_size_, original_screen_info_.deviceScaleFactor));
- widget_->Resize(applied_widget_rect_.size(), physical_backing_size,
- top_controls_layout_height, applied_widget_rect_.size(), resizer_rect,
- is_fullscreen, NO_RESIZE_ACK);
+ widget_->Resize(applied_widget_rect_.size(),
+ physical_backing_size,
+ top_controls_shrink_blink_size,
+ top_controls_height,
+ applied_widget_rect_.size(),
+ resizer_rect,
+ is_fullscreen_granted,
+ display_mode,
+ NO_RESIZE_ACK);
}
void RenderWidget::ScreenMetricsEmulator::OnResizeMessage(
@@ -338,8 +427,11 @@ void RenderWidget::ScreenMetricsEmulator::OnResizeMessage(
original_physical_backing_size_ = params.physical_backing_size;
original_screen_info_ = params.screen_info;
original_visible_viewport_size_ = params.visible_viewport_size;
- Apply(params.top_controls_layout_height, params.resizer_rect,
- params.is_fullscreen);
+ Apply(params.top_controls_shrink_blink_size,
+ params.top_controls_height,
+ params.resizer_rect,
+ params.is_fullscreen_granted,
+ params.display_mode);
if (need_ack) {
widget_->set_next_paint_is_resize_ack();
@@ -382,17 +474,20 @@ RenderWidget::RenderWidget(blink::WebPopupType popup_type,
bool never_visible)
: routing_id_(MSG_ROUTING_NONE),
surface_id_(0),
- webwidget_(NULL),
+ compositor_deps_(nullptr),
+ webwidget_(nullptr),
opener_id_(MSG_ROUTING_NONE),
init_complete_(false),
- top_controls_layout_height_(0.f),
+ top_controls_shrink_blink_size_(false),
+ top_controls_height_(0.f),
next_paint_flags_(0),
auto_resize_mode_(false),
need_update_rect_for_auto_resize_(false),
did_show_(false),
is_hidden_(hidden),
never_visible_(never_visible),
- is_fullscreen_(false),
+ is_fullscreen_granted_(false),
+ display_mode_(blink::WebDisplayModeUndefined),
has_focus_(false),
handling_input_event_(false),
handling_ime_event_(false),
@@ -401,6 +496,7 @@ RenderWidget::RenderWidget(blink::WebPopupType popup_type,
closing_(false),
host_closing_(false),
is_swapped_out_(swapped_out),
+ for_oopif_(false),
input_method_is_active_(false),
text_input_type_(ui::TEXT_INPUT_TYPE_NONE),
text_input_mode_(ui::TEXT_INPUT_MODE_DEFAULT),
@@ -439,19 +535,46 @@ RenderWidget::~RenderWidget() {
// static
RenderWidget* RenderWidget::Create(int32 opener_id,
+ CompositorDependencies* compositor_deps,
blink::WebPopupType popup_type,
const blink::WebScreenInfo& screen_info) {
DCHECK(opener_id != MSG_ROUTING_NONE);
scoped_refptr<RenderWidget> widget(
new RenderWidget(popup_type, screen_info, false, false, false));
- if (widget->Init(opener_id)) { // adds reference on success.
+ if (widget->Init(opener_id, compositor_deps)) { // adds reference on success.
return widget.get();
}
return NULL;
}
// static
-WebWidget* RenderWidget::CreateWebWidget(RenderWidget* render_widget) {
+RenderWidget* RenderWidget::CreateForFrame(
+ int routing_id,
+ int surface_id,
+ bool hidden,
+ const blink::WebScreenInfo& screen_info,
+ CompositorDependencies* compositor_deps,
+ blink::WebLocalFrame* frame) {
+ CHECK_NE(routing_id, MSG_ROUTING_NONE);
+ scoped_refptr<RenderWidget> widget(new RenderWidget(
+ blink::WebPopupTypeNone, screen_info, false, hidden, false));
+ widget->routing_id_ = routing_id;
+ widget->surface_id_ = surface_id;
+ widget->compositor_deps_ = compositor_deps;
+ widget->for_oopif_ = true;
+ // DoInit increments the reference count on |widget|, keeping it alive after
+ // this function returns.
+ if (widget->DoInit(MSG_ROUTING_NONE, compositor_deps,
+ RenderWidget::CreateWebFrameWidget(widget.get(), frame),
+ nullptr)) {
+ widget->CompleteInit();
+ return widget.get();
+ }
+ return nullptr;
+}
+
+// static
+blink::WebWidget* RenderWidget::CreateWebWidget(RenderWidget* render_widget) {
switch (render_widget->popup_type_) {
case blink::WebPopupTypeNone: // Nothing to create.
break;
@@ -466,14 +589,22 @@ WebWidget* RenderWidget::CreateWebWidget(RenderWidget* render_widget) {
return NULL;
}
-bool RenderWidget::Init(int32 opener_id) {
- return DoInit(opener_id,
- RenderWidget::CreateWebWidget(this),
+// static
+blink::WebWidget* RenderWidget::CreateWebFrameWidget(
+ RenderWidget* render_widget,
+ blink::WebLocalFrame* frame) {
+ return blink::WebFrameWidget::create(render_widget, frame);
+}
+
+bool RenderWidget::Init(int32 opener_id,
+ CompositorDependencies* compositor_deps) {
+ return DoInit(opener_id, compositor_deps, RenderWidget::CreateWebWidget(this),
new ViewHostMsg_CreateWidget(opener_id, popup_type_,
&routing_id_, &surface_id_));
}
bool RenderWidget::DoInit(int32 opener_id,
+ CompositorDependencies* compositor_deps,
WebWidget* web_widget,
IPC::SyncMessage* create_widget_message) {
DCHECK(!webwidget_);
@@ -481,9 +612,13 @@ bool RenderWidget::DoInit(int32 opener_id,
if (opener_id != MSG_ROUTING_NONE)
opener_id_ = opener_id;
+ compositor_deps_ = compositor_deps;
webwidget_ = web_widget;
- bool result = RenderThread::Get()->Send(create_widget_message);
+ bool result = true;
+ if (create_widget_message)
+ result = RenderThread::Get()->Send(create_widget_message);
+
if (result) {
RenderThread::Get()->AddRoute(routing_id_, this);
// Take a reference on behalf of the RenderThread. This will be balanced
@@ -534,18 +669,6 @@ void RenderWidget::WasSwappedOut() {
RenderProcess::current()->ReleaseProcess();
}
-void RenderWidget::EnableScreenMetricsEmulation(
- const WebDeviceEmulationParams& params) {
- if (!screen_metrics_emulator_)
- screen_metrics_emulator_.reset(new ScreenMetricsEmulator(this, params));
- else
- screen_metrics_emulator_->ChangeEmulationParams(params);
-}
-
-void RenderWidget::DisableScreenMetricsEmulation() {
- screen_metrics_emulator_.reset();
-}
-
void RenderWidget::SetPopupOriginAdjustmentsForEmulation(
ScreenMetricsEmulator* emulator) {
popup_origin_scale_for_emulation_ = emulator->scale();
@@ -564,9 +687,8 @@ gfx::Rect RenderWidget::AdjustValidationMessageAnchor(const gfx::Rect& anchor) {
}
void RenderWidget::SetScreenMetricsEmulationParameters(
- float device_scale_factor,
- const gfx::Point& root_layer_offset,
- float root_layer_scale) {
+ bool enabled,
+ const blink::WebDeviceEmulationParams& params) {
// This is only supported in RenderView.
NOTREACHED();
}
@@ -610,6 +732,10 @@ bool RenderWidget::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(ViewMsg_Close, OnClose)
IPC_MESSAGE_HANDLER(ViewMsg_CreatingNew_ACK, OnCreatingNewAck)
IPC_MESSAGE_HANDLER(ViewMsg_Resize, OnResize)
+ IPC_MESSAGE_HANDLER(ViewMsg_EnableDeviceEmulation,
+ OnEnableDeviceEmulation)
+ IPC_MESSAGE_HANDLER(ViewMsg_DisableDeviceEmulation,
+ OnDisableDeviceEmulation)
IPC_MESSAGE_HANDLER(ViewMsg_ColorProfile, OnColorProfile)
IPC_MESSAGE_HANDLER(ViewMsg_ChangeResizeRect, OnChangeResizeRect)
IPC_MESSAGE_HANDLER(ViewMsg_WasHidden, OnWasHidden)
@@ -623,6 +749,7 @@ bool RenderWidget::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(ViewMsg_SetTextDirection, OnSetTextDirection)
IPC_MESSAGE_HANDLER(ViewMsg_Move_ACK, OnRequestMoveAck)
IPC_MESSAGE_HANDLER(ViewMsg_UpdateScreenRects, OnUpdateScreenRects)
+ IPC_MESSAGE_HANDLER(ViewMsg_SetSurfaceIdNamespace, OnSetSurfaceIdNamespace)
#if defined(OS_ANDROID)
IPC_MESSAGE_HANDLER(ViewMsg_ShowImeIfNeeded, OnShowImeIfNeeded)
IPC_MESSAGE_HANDLER(ViewMsg_ImeEventAck, OnImeEventAck)
@@ -651,11 +778,13 @@ bool RenderWidget::Send(IPC::Message* message) {
void RenderWidget::Resize(const gfx::Size& new_size,
const gfx::Size& physical_backing_size,
- float top_controls_layout_height,
+ bool top_controls_shrink_blink_size,
+ float top_controls_height,
const gfx::Size& visible_viewport_size,
const gfx::Rect& resizer_rect,
- bool is_fullscreen,
- ResizeAck resize_ack) {
+ bool is_fullscreen_granted,
+ blink::WebDisplayMode display_mode,
+ const ResizeAck resize_ack) {
if (resizing_mode_selector_->NeverUsesSynchronousResize()) {
// A resize ack shouldn't be requested if we have not ACK'd the previous
// one.
@@ -669,21 +798,23 @@ void RenderWidget::Resize(const gfx::Size& new_size,
if (compositor_) {
compositor_->setViewportSize(new_size, physical_backing_size);
- compositor_->SetTopControlsLayoutHeight(top_controls_layout_height);
}
physical_backing_size_ = physical_backing_size;
- top_controls_layout_height_ = top_controls_layout_height;
+ top_controls_shrink_blink_size_ = top_controls_shrink_blink_size;
+ top_controls_height_ = top_controls_height;
visible_viewport_size_ = visible_viewport_size;
resizer_rect_ = resizer_rect;
// NOTE: We may have entered fullscreen mode without changing our size.
- bool fullscreen_change = is_fullscreen_ != is_fullscreen;
+ bool fullscreen_change = is_fullscreen_granted_ != is_fullscreen_granted;
if (fullscreen_change)
WillToggleFullscreen();
- is_fullscreen_ = is_fullscreen;
+ is_fullscreen_granted_ = is_fullscreen_granted;
+ display_mode_ = display_mode;
- webwidget_->setTopControlsLayoutHeight(top_controls_layout_height);
+ webwidget_->setTopControlsHeight(top_controls_height,
+ top_controls_shrink_blink_size_);
if (size_ != new_size) {
size_ = new_size;
@@ -692,8 +823,6 @@ void RenderWidget::Resize(const gfx::Size& new_size,
// ensures that we only resize as fast as we can paint. We only need to
// send an ACK if we are resized to a non-empty rect.
webwidget_->resize(new_size);
- } else if (!resizing_mode_selector_->is_synchronous_mode()) {
- resize_ack = NO_RESIZE_ACK;
}
webwidget()->resizePinchViewport(gfx::Size(
@@ -701,9 +830,10 @@ void RenderWidget::Resize(const gfx::Size& new_size,
visible_viewport_size.height()));
if (new_size.IsEmpty() || physical_backing_size.IsEmpty()) {
- // For empty size or empty physical_backing_size, there is no next paint
- // (along with which to send the ack) until they are set to non-empty.
- resize_ack = NO_RESIZE_ACK;
+ // In this case there is no paint/composite and therefore no
+ // ViewHostMsg_UpdateRect to send the resize ack with. We'd need to send the
+ // ack through a fake ViewHostMsg_UpdateRect or a different message.
+ DCHECK_EQ(resize_ack, NO_RESIZE_ACK);
}
// Send the Resize_ACK flag once we paint again if requested.
@@ -718,39 +848,41 @@ void RenderWidget::Resize(const gfx::Size& new_size,
DCHECK(resize_ack != SEND_RESIZE_ACK || next_paint_is_resize_ack());
}
-void RenderWidget::ResizeSynchronously(
- const gfx::Rect& new_position,
- const gfx::Size& visible_viewport_size) {
- Resize(new_position.size(),
- new_position.size(),
- top_controls_layout_height_,
- visible_viewport_size,
+void RenderWidget::SetWindowRectSynchronously(
+ const gfx::Rect& new_window_rect) {
+ Resize(new_window_rect.size(),
+ new_window_rect.size(),
+ top_controls_shrink_blink_size_,
+ top_controls_height_,
+ new_window_rect.size(),
gfx::Rect(),
- is_fullscreen_,
+ is_fullscreen_granted_,
+ display_mode_,
NO_RESIZE_ACK);
- view_screen_rect_ = new_position;
- window_screen_rect_ = new_position;
+ view_screen_rect_ = new_window_rect;
+ window_screen_rect_ = new_window_rect;
if (!did_show_)
- initial_pos_ = new_position;
+ initial_rect_ = new_window_rect;
}
void RenderWidget::OnClose() {
if (closing_)
return;
+ NotifyOnClose();
closing_ = true;
// Browser correspondence is no longer needed at this point.
if (routing_id_ != MSG_ROUTING_NONE) {
- if (RenderThreadImpl::current())
- RenderThreadImpl::current()->WidgetDestroyed();
RenderThread::Get()->RemoveRoute(routing_id_);
SetHidden(false);
+ if (RenderThreadImpl::current())
+ RenderThreadImpl::current()->WidgetDestroyed();
}
// If there is a Send call on the stack, then it could be dangerous to close
// now. Post a task that only gets invoked when there are no nested message
// loops.
- base::MessageLoop::current()->PostNonNestableTask(
+ RenderThread::Get()->GetTaskRunner()->PostNonNestableTask(
FROM_HERE, base::Bind(&RenderWidget::Close, this));
// Balances the AddRef taken when we called AddRoute.
@@ -779,15 +911,32 @@ void RenderWidget::OnResize(const ViewMsg_Resize_Params& params) {
screen_info_ = params.screen_info;
SetDeviceScaleFactor(screen_info_.deviceScaleFactor);
- Resize(params.new_size, params.physical_backing_size,
- params.top_controls_layout_height,
- params.visible_viewport_size, params.resizer_rect,
- params.is_fullscreen, SEND_RESIZE_ACK);
+ Resize(params.new_size,
+ params.physical_backing_size,
+ params.top_controls_shrink_blink_size,
+ params.top_controls_height,
+ params.visible_viewport_size,
+ params.resizer_rect,
+ params.is_fullscreen_granted,
+ params.display_mode,
+ params.needs_resize_ack ? SEND_RESIZE_ACK : NO_RESIZE_ACK);
if (orientation_changed)
OnOrientationChange();
}
+void RenderWidget::OnEnableDeviceEmulation(
+ const blink::WebDeviceEmulationParams& params) {
+ if (!screen_metrics_emulator_)
+ screen_metrics_emulator_.reset(new ScreenMetricsEmulator(this, params));
+ else
+ screen_metrics_emulator_->ChangeEmulationParams(params);
+}
+
+void RenderWidget::OnDisableDeviceEmulation() {
+ screen_metrics_emulator_.reset();
+}
+
void RenderWidget::OnColorProfile(const std::vector<char>& color_profile) {
SetDeviceColorProfile(color_profile);
}
@@ -855,68 +1004,64 @@ scoped_ptr<cc::OutputSurface> RenderWidget::CreateOutputSurface(bool fallback) {
}
#endif
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
bool use_software = fallback;
if (command_line.HasSwitch(switches::kDisableGpuCompositing))
use_software = true;
scoped_refptr<ContextProviderCommandBuffer> context_provider;
+ scoped_refptr<ContextProviderCommandBuffer> worker_context_provider;
if (!use_software) {
context_provider = ContextProviderCommandBuffer::Create(
- CreateGraphicsContext3D(), "RenderCompositor");
+ CreateGraphicsContext3D(), RENDER_COMPOSITOR_CONTEXT);
if (!context_provider.get()) {
// Cause the compositor to wait and try again.
return scoped_ptr<cc::OutputSurface>();
}
+
+ worker_context_provider = ContextProviderCommandBuffer::Create(
+ CreateGraphicsContext3D(), RENDER_WORKER_CONTEXT);
+ if (!worker_context_provider.get()) {
+ // Cause the compositor to wait and try again.
+ return scoped_ptr<cc::OutputSurface>();
+ }
}
uint32 output_surface_id = next_output_surface_id_++;
if (command_line.HasSwitch(switches::kEnableDelegatedRenderer)) {
- DCHECK(IsThreadedCompositingEnabled());
- return scoped_ptr<cc::OutputSurface>(
- new DelegatedCompositorOutputSurface(routing_id(),
- output_surface_id,
- context_provider,
- frame_swap_message_queue_));
+ DCHECK(compositor_deps_->GetCompositorImplThreadTaskRunner());
+ return scoped_ptr<cc::OutputSurface>(new DelegatedCompositorOutputSurface(
+ routing_id(), output_surface_id, context_provider,
+ worker_context_provider, frame_swap_message_queue_));
}
if (!context_provider.get()) {
scoped_ptr<cc::SoftwareOutputDevice> software_device(
- new CompositorSoftwareOutputDevice());
+ new cc::SoftwareOutputDevice());
- return scoped_ptr<cc::OutputSurface>(
- new CompositorOutputSurface(routing_id(),
- output_surface_id,
- NULL,
- software_device.Pass(),
- frame_swap_message_queue_,
- true));
+ return scoped_ptr<cc::OutputSurface>(new CompositorOutputSurface(
+ routing_id(), output_surface_id, nullptr, nullptr,
+ software_device.Pass(), frame_swap_message_queue_, true));
}
if (command_line.HasSwitch(cc::switches::kCompositeToMailbox)) {
// Composite-to-mailbox is currently used for layout tests in order to cause
// them to draw inside in the renderer to do the readback there. This should
// no longer be the case when crbug.com/311404 is fixed.
- DCHECK(IsThreadedCompositingEnabled() ||
- RenderThreadImpl::current()->layout_test_mode());
+ DCHECK(RenderThreadImpl::current()->layout_test_mode());
cc::ResourceFormat format = cc::RGBA_8888;
if (base::SysInfo::IsLowEndDevice())
format = cc::RGB_565;
- return scoped_ptr<cc::OutputSurface>(
- new MailboxOutputSurface(routing_id(),
- output_surface_id,
- context_provider,
- scoped_ptr<cc::SoftwareOutputDevice>(),
- frame_swap_message_queue_,
- format));
+ return scoped_ptr<cc::OutputSurface>(new MailboxOutputSurface(
+ routing_id(), output_surface_id, context_provider,
+ worker_context_provider, scoped_ptr<cc::SoftwareOutputDevice>(),
+ frame_swap_message_queue_, format));
}
bool use_swap_compositor_frame_message = false;
- return scoped_ptr<cc::OutputSurface>(
- new CompositorOutputSurface(routing_id(),
- output_surface_id,
- context_provider,
- scoped_ptr<cc::SoftwareOutputDevice>(),
- frame_swap_message_queue_,
- use_swap_compositor_frame_message));
+ return scoped_ptr<cc::OutputSurface>(new CompositorOutputSurface(
+ routing_id(), output_surface_id, context_provider,
+ worker_context_provider, scoped_ptr<cc::SoftwareOutputDevice>(),
+ frame_swap_message_queue_, use_swap_compositor_frame_message));
}
void RenderWidget::OnSwapBuffersAborted() {
@@ -958,7 +1103,11 @@ void RenderWidget::OnHandleInputEvent(const blink::WebInputEvent* input_event,
*static_cast<const WebKeyboardEvent*>(input_event);
// Some keys are special and it's essential that no events get blocked.
if (key_event.nativeKeyCode != AKEYCODE_TAB &&
- key_event.nativeKeyCode != AKEYCODE_DPAD_CENTER)
+ key_event.nativeKeyCode != AKEYCODE_DPAD_CENTER &&
+ key_event.nativeKeyCode != AKEYCODE_DPAD_LEFT &&
+ key_event.nativeKeyCode != AKEYCODE_DPAD_RIGHT &&
+ key_event.nativeKeyCode != AKEYCODE_DPAD_UP &&
+ key_event.nativeKeyCode != AKEYCODE_DPAD_DOWN)
ime_event_guard_maybe.reset(new ImeEventGuard(this));
}
#endif
@@ -967,20 +1116,23 @@ void RenderWidget::OnHandleInputEvent(const blink::WebInputEvent* input_event,
&latency_info);
base::TimeTicks start_time;
- if (base::TimeTicks::IsHighResNowFastAndReliable())
- start_time = base::TimeTicks::HighResNow();
+ if (base::TimeTicks::IsHighResolution())
+ start_time = base::TimeTicks::Now();
- const char* const event_name =
- WebInputEventTraits::GetName(input_event->type);
- TRACE_EVENT1("renderer", "RenderWidget::OnHandleInputEvent",
- "event", event_name);
+ TRACE_EVENT1("renderer,benchmark", "RenderWidget::OnHandleInputEvent",
+ "event", WebInputEventTraits::GetName(input_event->type));
TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("blink.HandleInputEvent");
TRACE_EVENT_FLOW_STEP0(
- "input",
+ "input,benchmark",
"LatencyInfo.Flow",
TRACE_ID_DONT_MANGLE(latency_info.trace_id),
"HanldeInputEventMain");
+ // If we don't have a high res timer, these metrics won't be accurate enough
+ // to be worth collecting. Note that this does introduce some sampling bias.
+ if (!start_time.is_null())
+ LogInputEventLatencyUma(*input_event, start_time);
+
scoped_ptr<cc::SwapPromiseMonitor> latency_info_swap_promise_monitor;
ui::LatencyInfo swap_latency_info(latency_info);
if (compositor_) {
@@ -989,28 +1141,6 @@ void RenderWidget::OnHandleInputEvent(const blink::WebInputEvent* input_event,
.Pass();
}
- if (base::TimeTicks::IsHighResNowFastAndReliable()) {
- // If we don't have a high res timer, these metrics won't be accurate enough
- // to be worth collecting. Note that this does introduce some sampling bias.
-
- base::TimeDelta now = base::TimeDelta::FromInternalValue(
- base::TimeTicks::HighResNow().ToInternalValue());
-
- int64 delta =
- static_cast<int64>((now.InSecondsF() - input_event->timeStampSeconds) *
- base::Time::kMicrosecondsPerSecond);
-
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "Event.AggregatedLatency.Renderer2", delta, 1, 10000000, 100);
- base::HistogramBase* counter_for_type = base::Histogram::FactoryGet(
- base::StringPrintf("Event.Latency.Renderer2.%s", event_name),
- 1,
- 10000000,
- 100,
- base::HistogramBase::kUmaTargetedHistogramFlag);
- counter_for_type->Add(delta);
- }
-
bool prevent_default = false;
if (WebInputEvent::isMouseEventType(input_event->type)) {
const WebMouseEvent& mouse_event =
@@ -1082,17 +1212,22 @@ void RenderWidget::OnHandleInputEvent(const blink::WebInputEvent* input_event,
}
}
- bool event_type_can_be_rate_limited =
- input_event->type == WebInputEvent::MouseMove ||
- input_event->type == WebInputEvent::MouseWheel;
+ // Send mouse wheel events and their disposition to the compositor thread, so
+ // that they can be used to produce the elastic overscroll effect on Mac.
+ if (input_event->type == WebInputEvent::MouseWheel) {
+ ObserveWheelEventAndResult(
+ static_cast<const WebMouseWheelEvent&>(*input_event), processed);
+ }
bool frame_pending = compositor_ && compositor_->BeginMainFrameRequested();
- // If we don't have a fast and accurate HighResNow, we assume the input
- // handlers are heavy and rate limit them.
- bool rate_limiting_wanted = true;
- if (base::TimeTicks::IsHighResNowFastAndReliable()) {
- base::TimeTicks end_time = base::TimeTicks::HighResNow();
+ // If we don't have a fast and accurate Now(), we assume the input handlers
+ // are heavy and rate limit them.
+ bool rate_limiting_wanted =
+ input_event->type == WebInputEvent::MouseMove ||
+ input_event->type == WebInputEvent::MouseWheel;
+ if (rate_limiting_wanted && !start_time.is_null()) {
+ base::TimeTicks end_time = base::TimeTicks::Now();
total_input_handling_time_this_frame_ += (end_time - start_time);
rate_limiting_wanted =
total_input_handling_time_this_frame_.InMicroseconds() >
@@ -1112,26 +1247,34 @@ void RenderWidget::OnHandleInputEvent(const blink::WebInputEvent* input_event,
ack.latency = swap_latency_info;
scoped_ptr<IPC::Message> response(
new InputHostMsg_HandleInputEvent_ACK(routing_id_, ack));
- if (rate_limiting_wanted && event_type_can_be_rate_limited &&
- frame_pending && !is_hidden_) {
+ if (rate_limiting_wanted && frame_pending && !is_hidden_) {
// We want to rate limit the input events in this case, so we'll wait for
// painting to finish before ACKing this message.
TRACE_EVENT_INSTANT0("renderer",
"RenderWidget::OnHandleInputEvent ack throttled",
TRACE_EVENT_SCOPE_THREAD);
if (pending_input_event_ack_) {
+ TRACE_EVENT_ASYNC_END0("input", "RenderWidget::ThrottledInputEventAck",
+ pending_input_event_ack_.get());
// As two different kinds of events could cause us to postpone an ack
// we send it now, if we have one pending. The Browser should never
// send us the same kind of event we are delaying the ack for.
Send(pending_input_event_ack_.release());
}
pending_input_event_ack_ = response.Pass();
+ TRACE_EVENT_ASYNC_BEGIN0("input", "RenderWidget::ThrottledInputEventAck",
+ pending_input_event_ack_.get());
if (compositor_)
compositor_->NotifyInputThrottledUntilCommit();
} else {
Send(response.release());
}
}
+ if (!no_ack && RenderThreadImpl::current()) {
+ RenderThreadImpl::current()
+ ->GetRendererScheduler()
+ ->DidHandleInputEventOnMainThread(*input_event);
+ }
if (input_event->type == WebInputEvent::MouseMove)
ignore_ack_for_mouse_move_from_debugger_ = false;
@@ -1144,8 +1287,9 @@ void RenderWidget::OnHandleInputEvent(const blink::WebInputEvent* input_event,
// Show the virtual keyboard if enabled and a user gesture triggers a focus
// change.
if (processed && (input_event->type == WebInputEvent::TouchEnd ||
- input_event->type == WebInputEvent::MouseUp))
+ input_event->type == WebInputEvent::MouseUp)) {
UpdateTextInputState(SHOW_IME_IF_NEEDED, FROM_IME);
+ }
#endif
if (!prevent_default) {
@@ -1153,9 +1297,17 @@ void RenderWidget::OnHandleInputEvent(const blink::WebInputEvent* input_event,
DidHandleKeyEvent();
if (WebInputEvent::isMouseEventType(input_event->type))
DidHandleMouseEvent(*(static_cast<const WebMouseEvent*>(input_event)));
- if (WebInputEvent::isTouchEventType(input_event->type))
- DidHandleTouchEvent(*(static_cast<const WebTouchEvent*>(input_event)));
}
+
+// TODO(rouslan): Fix ChromeOS and Windows 8 behavior of autofill popup with
+// virtual keyboard.
+#if !defined(OS_ANDROID)
+ // Virtual keyboard is not supported, so react to focus change immediately.
+ if (processed && (input_event->type == WebInputEvent::TouchEnd ||
+ input_event->type == WebInputEvent::MouseUp)) {
+ FocusChangeComplete();
+ }
+#endif
}
void RenderWidget::OnCursorVisibilityChange(bool is_visible) {
@@ -1182,8 +1334,11 @@ void RenderWidget::ClearFocus() {
}
void RenderWidget::FlushPendingInputEventAck() {
- if (pending_input_event_ack_)
+ if (pending_input_event_ack_) {
+ TRACE_EVENT_ASYNC_END0("input", "RenderWidget::ThrottledInputEventAck",
+ pending_input_event_ack_.get());
Send(pending_input_event_ack_.release());
+ }
total_input_handling_time_this_frame_ = base::TimeDelta();
}
@@ -1220,19 +1375,23 @@ void RenderWidget::AutoResizeCompositor() {
void RenderWidget::initializeLayerTreeView() {
DCHECK(!host_closing_);
- compositor_ =
- RenderWidgetCompositor::Create(this, IsThreadedCompositingEnabled());
+ compositor_ = RenderWidgetCompositor::Create(this, compositor_deps_);
compositor_->setViewportSize(size_, physical_backing_size_);
if (init_complete_)
StartCompositor();
}
-void RenderWidget::DestroyLayerTreeView() {
+void RenderWidget::WillCloseLayerTreeView() {
+ if (host_closing_)
+ return;
+
+ // Prevent new compositors or output surfaces from being created.
+ host_closing_ = true;
+
// Always send this notification to prevent new layer tree views from
// being created, even if one hasn't been created yet.
if (webwidget_)
webwidget_->willCloseLayerTreeView();
- compositor_.reset();
}
blink::WebLayerTreeView* RenderWidget::layerTreeView() {
@@ -1258,6 +1417,8 @@ void RenderWidget::didBecomeReadyForAdditionalInput() {
}
void RenderWidget::DidCommitCompositorFrame() {
+ FOR_EACH_OBSERVER(RenderFrameImpl, render_frames_,
+ DidCommitCompositorFrame());
FOR_EACH_OBSERVER(RenderFrameProxy, render_frame_proxies_,
DidCommitCompositorFrame());
#if defined(VIDEO_HOLE)
@@ -1272,18 +1433,7 @@ scoped_ptr<cc::SwapPromise> RenderWidget::QueueMessageImpl(
MessageDeliveryPolicy policy,
FrameSwapMessageQueue* frame_swap_message_queue,
scoped_refptr<IPC::SyncMessageFilter> sync_message_filter,
- bool commit_requested,
int source_frame_number) {
- if (policy == MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE &&
- // No need for lock: this gets changed only on this thread.
- !commit_requested &&
- // No need for lock: Messages are only enqueued from this thread, if we
- // don't have any now, no other thread will add any.
- frame_swap_message_queue->Empty()) {
- sync_message_filter->Send(msg);
- return nullptr;
- }
-
bool first_message_for_frame = false;
frame_swap_message_queue->QueueMessageForFrame(policy,
source_frame_number,
@@ -1310,12 +1460,17 @@ void RenderWidget::QueueMessage(IPC::Message* msg,
policy,
frame_swap_message_queue_.get(),
RenderThreadImpl::current()->sync_message_filter(),
- compositor_->commitRequested(),
compositor_->GetSourceFrameNumber());
if (swap_promise) {
compositor_->QueueSwapPromise(swap_promise.Pass());
- compositor_->SetNeedsCommit();
+ // Request a commit. This might either A) request a commit ahead of time
+ // or B) request a commit which is not needed because there are not
+ // pending updates. If B) then the commit will be skipped and the swap
+ // promises will be broken (see EarlyOut_NoUpdates). To achieve that we
+ // call SetNeedsUpdateLayers instead of SetNeedsCommit so that
+ // can_cancel_commit is not unset.
+ compositor_->SetNeedsUpdateLayers();
}
}
@@ -1350,10 +1505,8 @@ void RenderWidget::didCompleteSwapBuffers() {
}
void RenderWidget::scheduleComposite() {
- RenderThreadImpl* render_thread = RenderThreadImpl::current();
- // render_thread may be NULL in tests.
- if (render_thread && render_thread->compositor_message_loop_proxy().get() &&
- compositor_) {
+ if (compositor_ &&
+ compositor_deps_->GetCompositorImplThreadTaskRunner().get()) {
compositor_->setNeedsAnimate();
}
}
@@ -1385,11 +1538,11 @@ void RenderWidget::show(WebNavigationPolicy) {
return;
did_show_ = true;
- // NOTE: initial_pos_ may still have its default values at this point, but
+ // NOTE: initial_rect_ may still have its default values at this point, but
// that's okay. It'll be ignored if as_popup is false, or the browser
// process will impose a default position otherwise.
- Send(new ViewHostMsg_ShowWidget(opener_id_, routing_id_, initial_pos_));
- SetPendingWindowRect(initial_pos_);
+ Send(new ViewHostMsg_ShowWidget(opener_id_, routing_id_, initial_rect_));
+ SetPendingWindowRect(initial_rect_);
}
void RenderWidget::didFocus() {
@@ -1399,15 +1552,14 @@ void RenderWidget::didBlur() {
}
void RenderWidget::DoDeferredClose() {
- // No more compositing is possible. This prevents shutdown races between
- // previously posted CreateOutputSurface tasks and the host being unable to
- // create them because the close message was handled.
- DestroyLayerTreeView();
- // Also prevent new compositors from being created.
- host_closing_ = true;
+ WillCloseLayerTreeView();
Send(new ViewHostMsg_Close(routing_id_));
}
+void RenderWidget::NotifyOnClose() {
+ FOR_EACH_OBSERVER(RenderFrameImpl, render_frames_, WidgetWillClose());
+}
+
void RenderWidget::closeWidgetSoon() {
if (is_swapped_out_) {
// This widget is currently swapped out, and the active widget is in a
@@ -1425,7 +1577,7 @@ void RenderWidget::closeWidgetSoon() {
// could be closed before the JS finishes executing. So instead, post a
// message back to the message loop, which won't run until the JS is
// complete, and then the Close message can be sent.
- base::MessageLoop::current()->PostNonNestableTask(
+ RenderThread::Get()->GetTaskRunner()->PostTask(
FROM_HERE, base::Bind(&RenderWidget::DoDeferredClose, this));
}
@@ -1444,7 +1596,8 @@ void RenderWidget::QueueSyntheticGesture(
void RenderWidget::Close() {
screen_metrics_emulator_.reset();
- DestroyLayerTreeView();
+ WillCloseLayerTreeView();
+ compositor_.reset();
if (webwidget_) {
webwidget_->close();
webwidget_ = NULL;
@@ -1464,24 +1617,24 @@ void RenderWidget::setToolTipText(const blink::WebString& text,
}
void RenderWidget::setWindowRect(const WebRect& rect) {
- WebRect pos = rect;
+ WebRect window_rect = rect;
if (popup_origin_scale_for_emulation_) {
float scale = popup_origin_scale_for_emulation_;
- pos.x = popup_screen_origin_for_emulation_.x() +
- (pos.x - popup_view_origin_for_emulation_.x()) * scale;
- pos.y = popup_screen_origin_for_emulation_.y() +
- (pos.y - popup_view_origin_for_emulation_.y()) * scale;
+ window_rect.x = popup_screen_origin_for_emulation_.x() +
+ (window_rect.x - popup_view_origin_for_emulation_.x()) * scale;
+ window_rect.y = popup_screen_origin_for_emulation_.y() +
+ (window_rect.y - popup_view_origin_for_emulation_.y()) * scale;
}
if (!resizing_mode_selector_->is_synchronous_mode()) {
if (did_show_) {
- Send(new ViewHostMsg_RequestMove(routing_id_, pos));
- SetPendingWindowRect(pos);
+ Send(new ViewHostMsg_RequestMove(routing_id_, window_rect));
+ SetPendingWindowRect(window_rect);
} else {
- initial_pos_ = pos;
+ initial_rect_ = window_rect;
}
} else {
- ResizeSynchronously(pos, visible_viewport_size_);
+ SetWindowRectSynchronously(window_rect);
}
}
@@ -1541,9 +1694,7 @@ void RenderWidget::OnImeSetComposition(
// sure we are in a consistent state.
Send(new InputHostMsg_ImeCancelComposition(routing_id()));
}
-#if defined(OS_MACOSX) || defined(USE_AURA) || defined(OS_ANDROID)
UpdateCompositionInfo(true);
-#endif
}
void RenderWidget::OnImeConfirmComposition(const base::string16& text,
@@ -1560,9 +1711,7 @@ void RenderWidget::OnImeConfirmComposition(const base::string16& text,
else
webwidget_->confirmComposition(WebWidget::DoNotKeepSelection);
handling_input_event_ = false;
-#if defined(OS_MACOSX) || defined(USE_AURA) || defined(OS_ANDROID)
UpdateCompositionInfo(true);
-#endif
}
void RenderWidget::OnRepaint(gfx::Size size_to_paint) {
@@ -1606,6 +1755,11 @@ void RenderWidget::OnUpdateScreenRects(const gfx::Rect& view_screen_rect,
Send(new ViewHostMsg_UpdateScreenRects_ACK(routing_id()));
}
+void RenderWidget::OnSetSurfaceIdNamespace(uint32_t surface_id_namespace) {
+ if (compositor_)
+ compositor_->SetSurfaceIdNamespace(surface_id_namespace);
+}
+
void RenderWidget::showImeIfNeeded() {
OnShowImeIfNeeded();
}
@@ -1614,6 +1768,12 @@ void RenderWidget::OnShowImeIfNeeded() {
#if defined(OS_ANDROID) || defined(USE_AURA)
UpdateTextInputState(SHOW_IME_IF_NEEDED, FROM_NON_IME);
#endif
+
+// TODO(rouslan): Fix ChromeOS and Windows 8 behavior of autofill popup with
+// virtual keyboard.
+#if !defined(OS_ANDROID)
+ FocusChangeComplete();
+#endif
}
#if defined(OS_ANDROID)
@@ -1644,8 +1804,8 @@ bool RenderWidget::SendAckForMouseMoveFromDebugger() {
ack.type = handling_event_type_;
ack.state = INPUT_EVENT_ACK_STATE_CONSUMED;
Send(new InputHostMsg_HandleInputEvent_ACK(routing_id_, ack));
+ return true;
}
- return true;
}
return false;
}
@@ -1689,8 +1849,11 @@ void RenderWidget::SetHidden(bool hidden) {
if (is_hidden_ == hidden)
return;
- // The status has changed. Tell the RenderThread about it.
+ // The status has changed. Tell the RenderThread about it and ensure
+ // throttled acks are released in case frame production ceases.
is_hidden_ = hidden;
+ FlushPendingInputEventAck();
+
if (is_hidden_)
RenderThreadImpl::current()->WidgetHidden();
else
@@ -1701,7 +1864,7 @@ void RenderWidget::WillToggleFullscreen() {
if (!webwidget_)
return;
- if (is_fullscreen_) {
+ if (is_fullscreen_granted_) {
webwidget_->willExitFullScreen();
} else {
webwidget_->willEnterFullScreen();
@@ -1712,7 +1875,7 @@ void RenderWidget::DidToggleFullscreen() {
if (!webwidget_)
return;
- if (is_fullscreen_) {
+ if (is_fullscreen_granted_) {
webwidget_->didEnterFullScreen();
} else {
webwidget_->didExitFullScreen();
@@ -1892,46 +2055,32 @@ void RenderWidget::UpdateSelectionBounds() {
}
}
-#if defined(OS_MACOSX) || defined(USE_AURA) || defined(OS_ANDROID)
UpdateCompositionInfo(false);
-#endif
}
// Check blink::WebTextInputType and ui::TextInputType is kept in sync.
-COMPILE_ASSERT(int(blink::WebTextInputTypeNone) == \
- int(ui::TEXT_INPUT_TYPE_NONE), mismatching_enums);
-COMPILE_ASSERT(int(blink::WebTextInputTypeText) == \
- int(ui::TEXT_INPUT_TYPE_TEXT), mismatching_enums);
-COMPILE_ASSERT(int(blink::WebTextInputTypePassword) == \
- int(ui::TEXT_INPUT_TYPE_PASSWORD), mismatching_enums);
-COMPILE_ASSERT(int(blink::WebTextInputTypeSearch) == \
- int(ui::TEXT_INPUT_TYPE_SEARCH), mismatching_enums);
-COMPILE_ASSERT(int(blink::WebTextInputTypeEmail) == \
- int(ui::TEXT_INPUT_TYPE_EMAIL), mismatching_enums);
-COMPILE_ASSERT(int(blink::WebTextInputTypeNumber) == \
- int(ui::TEXT_INPUT_TYPE_NUMBER), mismatching_enums);
-COMPILE_ASSERT(int(blink::WebTextInputTypeTelephone) == \
- int(ui::TEXT_INPUT_TYPE_TELEPHONE), mismatching_enums);
-COMPILE_ASSERT(int(blink::WebTextInputTypeURL) == \
- int(ui::TEXT_INPUT_TYPE_URL), mismatching_enums);
-COMPILE_ASSERT(int(blink::WebTextInputTypeDate) == \
- int(ui::TEXT_INPUT_TYPE_DATE), mismatching_enum);
-COMPILE_ASSERT(int(blink::WebTextInputTypeDateTime) == \
- int(ui::TEXT_INPUT_TYPE_DATE_TIME), mismatching_enum);
-COMPILE_ASSERT(int(blink::WebTextInputTypeDateTimeLocal) == \
- int(ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL), mismatching_enum);
-COMPILE_ASSERT(int(blink::WebTextInputTypeMonth) == \
- int(ui::TEXT_INPUT_TYPE_MONTH), mismatching_enum);
-COMPILE_ASSERT(int(blink::WebTextInputTypeTime) == \
- int(ui::TEXT_INPUT_TYPE_TIME), mismatching_enum);
-COMPILE_ASSERT(int(blink::WebTextInputTypeWeek) == \
- int(ui::TEXT_INPUT_TYPE_WEEK), mismatching_enum);
-COMPILE_ASSERT(int(blink::WebTextInputTypeTextArea) == \
- int(ui::TEXT_INPUT_TYPE_TEXT_AREA), mismatching_enums);
-COMPILE_ASSERT(int(blink::WebTextInputTypeContentEditable) == \
- int(ui::TEXT_INPUT_TYPE_CONTENT_EDITABLE), mismatching_enums);
-COMPILE_ASSERT(int(blink::WebTextInputTypeDateTimeField) == \
- int(ui::TEXT_INPUT_TYPE_DATE_TIME_FIELD), mismatching_enums);
+#define STATIC_ASSERT_WTIT_ENUM_MATCH(a, b) \
+ static_assert(int(blink::WebTextInputType##a) \
+ == int(ui::TEXT_INPUT_TYPE_##b), \
+ "mismatching enums: " #a)
+
+STATIC_ASSERT_WTIT_ENUM_MATCH(None, NONE);
+STATIC_ASSERT_WTIT_ENUM_MATCH(Text, TEXT);
+STATIC_ASSERT_WTIT_ENUM_MATCH(Password, PASSWORD);
+STATIC_ASSERT_WTIT_ENUM_MATCH(Search, SEARCH);
+STATIC_ASSERT_WTIT_ENUM_MATCH(Email, EMAIL);
+STATIC_ASSERT_WTIT_ENUM_MATCH(Number, NUMBER);
+STATIC_ASSERT_WTIT_ENUM_MATCH(Telephone, TELEPHONE);
+STATIC_ASSERT_WTIT_ENUM_MATCH(URL, URL);
+STATIC_ASSERT_WTIT_ENUM_MATCH(Date, DATE);
+STATIC_ASSERT_WTIT_ENUM_MATCH(DateTime, DATE_TIME);
+STATIC_ASSERT_WTIT_ENUM_MATCH(DateTimeLocal, DATE_TIME_LOCAL);
+STATIC_ASSERT_WTIT_ENUM_MATCH(Month, MONTH);
+STATIC_ASSERT_WTIT_ENUM_MATCH(Time, TIME);
+STATIC_ASSERT_WTIT_ENUM_MATCH(Week, WEEK);
+STATIC_ASSERT_WTIT_ENUM_MATCH(TextArea, TEXT_AREA);
+STATIC_ASSERT_WTIT_ENUM_MATCH(ContentEditable, CONTENT_EDITABLE);
+STATIC_ASSERT_WTIT_ENUM_MATCH(DateTimeField, DATE_TIME_FIELD);
ui::TextInputType RenderWidget::WebKitToUiTextInputType(
blink::WebTextInputType type) {
@@ -1947,15 +2096,11 @@ ui::TextInputType RenderWidget::GetTextInputType() {
return ui::TEXT_INPUT_TYPE_NONE;
}
-#if defined(OS_MACOSX) || defined(USE_AURA) || defined(OS_ANDROID)
void RenderWidget::UpdateCompositionInfo(bool should_update_range) {
#if defined(OS_ANDROID)
- // Sending composition info makes sense only in Lollipop (API level 21)
- // and above due to the API availability.
- if (base::android::BuildInfo::GetInstance()->sdk_int() < 21)
- return;
-#endif
-
+ // TODO(yukawa): Start sending character bounds when the browser side
+ // implementation becomes ready (crbug.com/424866).
+#else
gfx::Range range = gfx::Range();
if (should_update_range) {
GetCompositionRange(&range);
@@ -1971,6 +2116,7 @@ void RenderWidget::UpdateCompositionInfo(bool should_update_range) {
composition_range_ = range;
Send(new InputHostMsg_ImeCompositionRangeChanged(
routing_id(), composition_range_, composition_character_bounds_));
+#endif
}
void RenderWidget::GetCompositionCharacterBounds(
@@ -2005,7 +2151,6 @@ bool RenderWidget::ShouldUpdateCompositionInfo(
}
return false;
}
-#endif
#if defined(OS_ANDROID)
void RenderWidget::DidChangeBodyBackgroundColor(SkColor bg_color) {
@@ -2019,6 +2164,19 @@ void RenderWidget::DidChangeBodyBackgroundColor(SkColor bg_color) {
Send(new ViewHostMsg_DidChangeBodyBackgroundColor(routing_id(), bg_color));
}
}
+
+bool RenderWidget::DoesRecordFullLayer() const {
+ SynchronousCompositorFactory* synchronous_compositor_factory =
+ SynchronousCompositorFactory::GetInstance();
+
+ // We assume that the absence of synchronous_compositor_factory
+ // means we are in Chrome. In chrome, we want to clip, i.e.
+ // *not* to record the full layer.
+ if (!synchronous_compositor_factory)
+ return false;
+
+ return synchronous_compositor_factory->RecordFullLayer();
+}
#endif
bool RenderWidget::CanComposeInline() {
@@ -2047,11 +2205,25 @@ void RenderWidget::resetInputMethod() {
Send(new InputHostMsg_ImeCancelComposition(routing_id()));
}
-#if defined(OS_MACOSX) || defined(USE_AURA) || defined(OS_ANDROID)
UpdateCompositionInfo(true);
-#endif
}
+#if defined(OS_ANDROID)
+void RenderWidget::showUnhandledTapUIIfNeeded(
+ const WebPoint& tapped_position,
+ const WebNode& tapped_node,
+ bool page_changed) {
+ DCHECK(handling_input_event_);
+ bool should_trigger = !page_changed && tapped_node.isTextNode() &&
+ !tapped_node.isContentEditable() &&
+ !tapped_node.isInsideFocusableElementOrARIAWidget();
+ if (should_trigger) {
+ Send(new ViewHostMsg_ShowUnhandledTapUIIfNeeded(routing_id_,
+ tapped_position.x, tapped_position.y));
+ }
+}
+#endif
+
void RenderWidget::didHandleGestureEvent(
const WebGestureEvent& event,
bool event_cancelled) {
@@ -2075,7 +2247,11 @@ void RenderWidget::StartCompositor() {
// at all.
if (never_visible_)
return;
- compositor_->setSurfaceReady();
+ // In tests without a RenderThreadImpl, don't set ready as this kicks
+ // off creating output surfaces that the test can't create.
+ if (!RenderThreadImpl::current())
+ return;
+ compositor_->StartCompositor();
}
void RenderWidget::SchedulePluginMove(const WebPluginGeometry& move) {
@@ -2119,10 +2295,51 @@ bool RenderWidget::WillHandleGestureEvent(
return false;
}
+void RenderWidget::ObserveWheelEventAndResult(
+ const blink::WebMouseWheelEvent& wheel_event,
+ bool event_processed) {
+ if (!compositor_deps_->IsElasticOverscrollEnabled())
+ return;
+
+ // Blink does not accurately compute scroll bubbling or overscroll. For now,
+ // assume that an unprocessed event was entirely an overscroll, and that a
+ // processed event was entirely scroll.
+ // TODO(ccameron): Retrieve an accurate scroll result from Blink.
+ // http://crbug.com/442859
+ cc::InputHandlerScrollResult scroll_result;
+ if (event_processed) {
+ scroll_result.did_scroll = true;
+ } else {
+ scroll_result.did_overscroll_root = true;
+ scroll_result.unused_scroll_delta =
+ gfx::Vector2dF(-wheel_event.deltaX, -wheel_event.deltaY);
+ }
+
+ RenderThreadImpl* render_thread = RenderThreadImpl::current();
+ InputHandlerManager* input_handler_manager =
+ render_thread ? render_thread->input_handler_manager() : NULL;
+ if (input_handler_manager) {
+ input_handler_manager->ObserveWheelEventAndResultOnMainThread(
+ routing_id_, wheel_event, scroll_result);
+ }
+}
+
void RenderWidget::hasTouchEventHandlers(bool has_handlers) {
Send(new ViewHostMsg_HasTouchEventHandlers(routing_id_, has_handlers));
}
+// Check blink::WebTouchAction and blink::WebTouchActionAuto is kept in sync
+#define STATIC_ASSERT_WTI_ENUM_MATCH(a, b) \
+ static_assert(int(blink::WebTouchAction##a) == int(TOUCH_ACTION_##b), \
+ "mismatching enums: " #a)
+
+inline content::TouchAction& operator|=(content::TouchAction& a,
+ content::TouchAction b) {
+ a = static_cast<content::TouchAction>(static_cast<int>(a) |
+ static_cast<int>(b));
+ return a;
+}
+
void RenderWidget::setTouchAction(
blink::WebTouchAction web_touch_action) {
@@ -2131,26 +2348,35 @@ void RenderWidget::setTouchAction(
if (handling_event_type_ != WebInputEvent::TouchStart)
return;
- // Verify the same values are used by the types so we can cast between them.
- COMPILE_ASSERT(static_cast<blink::WebTouchAction>(TOUCH_ACTION_AUTO) ==
- blink::WebTouchActionAuto,
- enum_values_must_match_for_touch_action);
- COMPILE_ASSERT(static_cast<blink::WebTouchAction>(TOUCH_ACTION_NONE) ==
- blink::WebTouchActionNone,
- enum_values_must_match_for_touch_action);
- COMPILE_ASSERT(static_cast<blink::WebTouchAction>(TOUCH_ACTION_PAN_X) ==
- blink::WebTouchActionPanX,
- enum_values_must_match_for_touch_action);
- COMPILE_ASSERT(static_cast<blink::WebTouchAction>(TOUCH_ACTION_PAN_Y) ==
- blink::WebTouchActionPanY,
- enum_values_must_match_for_touch_action);
- COMPILE_ASSERT(
- static_cast<blink::WebTouchAction>(TOUCH_ACTION_PINCH_ZOOM) ==
- blink::WebTouchActionPinchZoom,
- enum_values_must_match_for_touch_action);
+// TODO(dtapuska): A dependant change needs to land in blink to change
+// the blink::WebTouchAction enum; in the meantime don't do
+// a static cast between the values. (http://crbug.com/476556)
+#if 0
+ // Verify the same values are used by the types so we can cast between them.
+ STATIC_ASSERT_WTI_ENUM_MATCH(Auto, AUTO);
+ STATIC_ASSERT_WTI_ENUM_MATCH(None, NONE);
+ STATIC_ASSERT_WTI_ENUM_MATCH(PanLeft, PAN_LEFT);
+ STATIC_ASSERT_WTI_ENUM_MATCH(PanRight, PAN_RIGHT);
+ STATIC_ASSERT_WTI_ENUM_MATCH(PanX, PAN_X);
+ STATIC_ASSERT_WTI_ENUM_MATCH(PanUp, PAN_UP);
+ STATIC_ASSERT_WTI_ENUM_MATCH(PanDown, PAN_DOWN);
+ STATIC_ASSERT_WTI_ENUM_MATCH(PanY, PAN_Y);
+ STATIC_ASSERT_WTI_ENUM_MATCH(PinchZoom, PINCH_ZOOM);
content::TouchAction content_touch_action =
static_cast<content::TouchAction>(web_touch_action);
+#else
+ content::TouchAction content_touch_action = TOUCH_ACTION_AUTO;
+ if (web_touch_action & blink::WebTouchActionNone)
+ content_touch_action |= TOUCH_ACTION_NONE;
+ if (web_touch_action & blink::WebTouchActionPanX)
+ content_touch_action |= TOUCH_ACTION_PAN_X;
+ if (web_touch_action & blink::WebTouchActionPanY)
+ content_touch_action |= TOUCH_ACTION_PAN_Y;
+ if (web_touch_action & blink::WebTouchActionPinchZoom)
+ content_touch_action |= TOUCH_ACTION_PINCH_ZOOM;
+
+#endif
Send(new InputHostMsg_SetTouchAction(routing_id_, content_touch_action));
}
@@ -2168,7 +2394,7 @@ scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
RenderWidget::CreateGraphicsContext3D() {
if (!webwidget_)
return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>();
- if (CommandLine::ForCurrentProcess()->HasSwitch(
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableGpuCompositing))
return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>();
if (!RenderThreadImpl::current())
diff --git a/chromium/content/renderer/render_widget.h b/chromium/content/renderer/render_widget.h
index 523a38e2c52..95cd8c2ac0b 100644
--- a/chromium/content/renderer/render_widget.h
+++ b/chromium/content/renderer/render_widget.h
@@ -23,6 +23,7 @@
#include "content/renderer/message_delivery_policy.h"
#include "ipc/ipc_listener.h"
#include "ipc/ipc_sender.h"
+#include "third_party/WebKit/public/platform/WebDisplayMode.h"
#include "third_party/WebKit/public/platform/WebRect.h"
#include "third_party/WebKit/public/web/WebCompositionUnderline.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
@@ -36,11 +37,11 @@
#include "ui/base/ime/text_input_mode.h"
#include "ui/base/ime/text_input_type.h"
#include "ui/base/ui_base_types.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/vector2d.h"
+#include "ui/gfx/geometry/vector2d_f.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/range/range.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/vector2d.h"
-#include "ui/gfx/vector2d_f.h"
#include "ui/surface/transport_dib.h"
struct ViewHostMsg_UpdateRect_Params;
@@ -54,13 +55,19 @@ class SyncMessageFilter;
namespace blink {
struct WebDeviceEmulationParams;
+class WebFrameWidget;
class WebGestureEvent;
class WebKeyboardEvent;
+class WebLocalFrame;
class WebMouseEvent;
+class WebNode;
+struct WebPoint;
class WebTouchEvent;
+class WebView;
}
namespace cc {
+struct InputHandlerScrollResult;
class OutputSurface;
class SwapPromise;
}
@@ -70,6 +77,7 @@ class Range;
}
namespace content {
+class CompositorDependencies;
class ExternalPopupMenu;
class FrameSwapMessageQueue;
class PepperPluginInstanceImpl;
@@ -92,23 +100,38 @@ class CONTENT_EXPORT RenderWidget
// Creates a new RenderWidget. The opener_id is the routing ID of the
// RenderView that this widget lives inside.
static RenderWidget* Create(int32 opener_id,
+ CompositorDependencies* compositor_deps,
blink::WebPopupType popup_type,
const blink::WebScreenInfo& screen_info);
+ // Creates a new RenderWidget that will be attached to a RenderFrame.
+ static RenderWidget* CreateForFrame(int routing_id,
+ int surface_id,
+ bool hidden,
+ const blink::WebScreenInfo& screen_info,
+ CompositorDependencies* compositor_deps,
+ blink::WebLocalFrame* frame);
+
+ static blink::WebWidget* CreateWebFrameWidget(RenderWidget* render_widget,
+ blink::WebLocalFrame* frame);
+
// Creates a WebWidget based on the popup type.
static blink::WebWidget* CreateWebWidget(RenderWidget* render_widget);
int32 routing_id() const { return routing_id_; }
int32 surface_id() const { return surface_id_; }
+ CompositorDependencies* compositor_deps() const { return compositor_deps_; }
blink::WebWidget* webwidget() const { return webwidget_; }
gfx::Size size() const { return size_; }
bool has_focus() const { return has_focus_; }
- bool is_fullscreen() const { return is_fullscreen_; }
+ bool is_fullscreen_granted() const { return is_fullscreen_granted_; }
+ blink::WebDisplayMode display_mode() const { return display_mode_; }
bool is_hidden() const { return is_hidden_; }
bool handling_input_event() const { return handling_input_event_; }
// Temporary for debugging purposes...
bool closing() const { return closing_; }
bool is_swapped_out() { return is_swapped_out_; }
+ bool for_oopif() { return for_oopif_; }
ui::MenuSourceType context_menu_source_type() {
return context_menu_source_type_;
}
@@ -119,6 +142,9 @@ class CONTENT_EXPORT RenderWidget
return host_context_menu_location_;
}
+ // ScreenInfo exposed so it can be passed to subframe RenderWidgets.
+ blink::WebScreenInfo screen_info() const { return screen_info_; }
+
// Functions to track out-of-process frames for special notifications.
void RegisterRenderFrameProxy(RenderFrameProxy* proxy);
void UnregisterRenderFrameProxy(RenderFrameProxy* proxy);
@@ -153,7 +179,6 @@ class CONTENT_EXPORT RenderWidget
virtual void didChangeCursor(const blink::WebCursorInfo&);
virtual void closeWidgetSoon();
virtual void show(blink::WebNavigationPolicy);
- virtual void runModal() {}
virtual blink::WebRect windowRect();
virtual void setToolTipText(const blink::WebString& text,
blink::WebTextDirection hint);
@@ -167,11 +192,22 @@ class CONTENT_EXPORT RenderWidget
bool event_cancelled);
virtual void showImeIfNeeded();
+#if defined(OS_ANDROID)
+ // Notifies that a tap was not consumed, so showing a UI for the unhandled
+ // tap may be needed.
+ // Performs various checks on the given WebNode to apply heuristics to
+ // determine if triggering is appropriate.
+ virtual void showUnhandledTapUIIfNeeded(
+ const blink::WebPoint& tapped_position,
+ const blink::WebNode& tapped_node,
+ bool page_changed) override;
+#endif
+
// Begins the compositor's scheduler to start producing frames.
void StartCompositor();
// Stop compositing.
- void DestroyLayerTreeView();
+ void WillCloseLayerTreeView();
// Called when a plugin is moved. These events are queued up and sent with
// the next paint or scroll message to the host.
@@ -223,10 +259,8 @@ class CONTENT_EXPORT RenderWidget
// Returns whether we currently should handle an IME event.
bool ShouldHandleImeEvent();
- virtual void InstrumentWillBeginFrame(int frame_id) {}
- virtual void InstrumentDidBeginFrame() {}
- virtual void InstrumentDidCancelFrame() {}
- virtual void InstrumentWillComposite() {}
+ // Called by the compositor when page scale animation completed.
+ virtual void DidCompletePageScaleAnimation() {}
// When paused in debugger, we send ack for mouse event early. This ensures
// that we continue receiving mouse moves and pass them to debugger. Returns
@@ -243,11 +277,6 @@ class CONTENT_EXPORT RenderWidget
// widget if required to fit into the browser window.
class ScreenMetricsEmulator;
- // Emulates screen and widget metrics. Supplied values override everything
- // coming from host.
- void EnableScreenMetricsEmulation(
- const blink::WebDeviceEmulationParams& params);
- void DisableScreenMetricsEmulation();
void SetPopupOriginAdjustmentsForEmulation(ScreenMetricsEmulator* emulator);
gfx::Rect AdjustValidationMessageAnchor(const gfx::Rect& anchor);
@@ -291,18 +320,23 @@ class CONTENT_EXPORT RenderWidget
void UpdateTextInputState(ShowIme show_ime, ChangeSource change_source);
#endif
-#if defined(OS_MACOSX) || defined(USE_AURA) || defined(OS_ANDROID)
+ // Called when animations due to focus change have completed (if any). Can be
+ // called from the renderer, browser, or compositor.
+ virtual void FocusChangeComplete() {}
+
// Checks if the composition range or composition character bounds have been
// changed. If they are changed, the new value will be sent to the browser
// process. This method does nothing when the browser process is not able to
// handle composition range and composition character bounds.
void UpdateCompositionInfo(bool should_update_range);
-#endif
#if defined(OS_ANDROID)
void DidChangeBodyBackgroundColor(SkColor bg_color);
+ bool DoesRecordFullLayer() const;
#endif
+ bool host_closing() const { return host_closing_; }
+
protected:
// Friend RefCounted so that the dtor can be non-public. Using this class
// without ref-counting is an error.
@@ -325,10 +359,11 @@ class CONTENT_EXPORT RenderWidget
// Initializes this view with the given opener. CompleteInit must be called
// later.
- bool Init(int32 opener_id);
+ bool Init(int32 opener_id, CompositorDependencies* compositor_deps);
// Called by Init and subclasses to perform initialization.
bool DoInit(int32 opener_id,
+ CompositorDependencies* compositor_deps,
blink::WebWidget* web_widget,
IPC::SyncMessage* create_widget_message);
@@ -348,23 +383,23 @@ class CONTENT_EXPORT RenderWidget
void FlushPendingInputEventAck();
void DoDeferredClose();
void DoDeferredSetWindowRect(const blink::WebRect& pos);
+ void NotifyOnClose();
// Resizes the render widget.
void Resize(const gfx::Size& new_size,
const gfx::Size& physical_backing_size,
- float top_controls_layout_height,
+ bool top_controls_shrink_blink_size,
+ float top_controls_height,
const gfx::Size& visible_viewport_size,
const gfx::Rect& resizer_rect,
- bool is_fullscreen,
+ bool is_fullscreen_granted,
+ blink::WebDisplayMode display_mode,
ResizeAck resize_ack);
// Used to force the size of a window when running layout tests.
- void ResizeSynchronously(
- const gfx::Rect& new_position,
- const gfx::Size& visible_viewport_size);
+ void SetWindowRectSynchronously(const gfx::Rect& new_window_rect);
virtual void SetScreenMetricsEmulationParameters(
- float device_scale_factor,
- const gfx::Point& root_layer_offset,
- float root_layer_scale);
+ bool enabled,
+ const blink::WebDeviceEmulationParams& params);
#if defined(OS_MACOSX) || defined(OS_ANDROID)
void SetExternalPopupOriginAdjustmentsForEmulation(
ExternalPopupMenu* popup, ScreenMetricsEmulator* emulator);
@@ -377,9 +412,11 @@ class CONTENT_EXPORT RenderWidget
void OnCursorVisibilityChange(bool is_visible);
void OnMouseCaptureLost();
virtual void OnSetFocus(bool enable);
- virtual void OnClose();
+ void OnClose();
void OnCreatingNewAck();
virtual void OnResize(const ViewMsg_Resize_Params& params);
+ void OnEnableDeviceEmulation(const blink::WebDeviceEmulationParams& params);
+ void OnDisableDeviceEmulation();
void OnColorProfile(const std::vector<char>& color_profile);
void OnChangeResizeRect(const gfx::Rect& resizer_rect);
virtual void OnWasHidden();
@@ -407,6 +444,7 @@ class CONTENT_EXPORT RenderWidget
void OnUpdateScreenRects(const gfx::Rect& view_screen_rect,
const gfx::Rect& window_screen_rect);
void OnShowImeIfNeeded();
+ void OnSetSurfaceIdNamespace(uint32_t surface_id_namespace);
#if defined(OS_ANDROID)
// Whenever an IME event that needs an acknowledgement is sent to the browser,
@@ -464,7 +502,6 @@ class CONTENT_EXPORT RenderWidget
MessageDeliveryPolicy policy,
FrameSwapMessageQueue* frame_swap_message_queue,
scoped_refptr<IPC::SyncMessageFilter> sync_message_filter,
- bool commit_requested,
int source_frame_number);
// Override point to obtain that the current input method state and caret
@@ -473,7 +510,6 @@ class CONTENT_EXPORT RenderWidget
virtual ui::TextInputType WebKitToUiTextInputType(
blink::WebTextInputType type);
-#if defined(OS_MACOSX) || defined(USE_AURA) || defined(OS_ANDROID)
// Override point to obtain that the current composition character bounds.
// In the case of surrogate pairs, the character is treated as two characters:
// the bounds for first character is actual one, and the bounds for second
@@ -490,7 +526,6 @@ class CONTENT_EXPORT RenderWidget
bool ShouldUpdateCompositionInfo(
const gfx::Range& range,
const std::vector<gfx::Rect>& bounds);
-#endif
// Override point to obtain that the current input method state about
// composition text.
@@ -528,9 +563,10 @@ class CONTENT_EXPORT RenderWidget
// just handled.
virtual void DidHandleMouseEvent(const blink::WebMouseEvent& event) {}
- // Called by OnHandleInputEvent() to notify subclasses that a touch event was
- // just handled.
- virtual void DidHandleTouchEvent(const blink::WebTouchEvent& event) {}
+ // Called by OnHandleInputEvent() to forward a mouse wheel event to the
+ // compositor thread, to effect the elastic overscroll effect.
+ void ObserveWheelEventAndResult(const blink::WebMouseWheelEvent& wheel_event,
+ bool event_processed);
// Check whether the WebWidget has any touch event handlers registered
// at the given point.
@@ -555,6 +591,10 @@ class CONTENT_EXPORT RenderWidget
int32 surface_id_;
+ // Dependencies for initializing a compositor, including flags for optional
+ // features.
+ CompositorDependencies* compositor_deps_;
+
// We are responsible for destroying this object via its Close method.
// May be NULL when the window is closing.
blink::WebWidget* webwidget_;
@@ -571,8 +611,8 @@ class CONTENT_EXPORT RenderWidget
// view is.
int32 opener_id_;
- // The position where this view should be initially shown.
- gfx::Rect initial_pos_;
+ // The rect where this view should be initially shown.
+ gfx::Rect initial_rect_;
bool init_complete_;
@@ -586,9 +626,13 @@ class CONTENT_EXPORT RenderWidget
// The size of the view's backing surface in non-DPI-adjusted pixels.
gfx::Size physical_backing_size_;
- // 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_;
+ // Whether or not Blink's viewport size should be shrunk by the height of the
+ // URL-bar (always false on platforms where URL-bar hiding isn't supported).
+ bool top_controls_shrink_blink_size_;
+
+ // The height of the top controls (always 0 on platforms where URL-bar hiding
+ // isn't supported).
+ float top_controls_height_;
// The size of the visible viewport in DPI-adjusted pixels.
gfx::Size visible_viewport_size_;
@@ -616,8 +660,11 @@ class CONTENT_EXPORT RenderWidget
// Indicates that we are never visible, so never produce graphical output.
bool never_visible_;
- // Indicates that we are in fullscreen mode.
- bool is_fullscreen_;
+ // Indicates whether tab-initiated fullscreen was granted.
+ bool is_fullscreen_granted_;
+
+ // Indicates the display mode.
+ blink::WebDisplayMode display_mode_;
// Indicates whether we have been focused/unfocused by the browser.
bool has_focus_;
@@ -646,6 +693,11 @@ class CONTENT_EXPORT RenderWidget
// swapped out, the process can exit.
bool is_swapped_out_;
+ // TODO(simonhong): Remove this when we enable BeginFrame scheduling for
+ // OOPIF(crbug.com/471411).
+ // Whether this RenderWidget is for an out-of-process iframe or not.
+ bool for_oopif_;
+
// Indicates if an input method is active in the browser process.
bool input_method_is_active_;
@@ -738,8 +790,8 @@ class CONTENT_EXPORT RenderWidget
// Popups may be displaced when screen metrics emulation is enabled.
// These values are used to properly adjust popup position.
- gfx::Point popup_view_origin_for_emulation_;
- gfx::Point popup_screen_origin_for_emulation_;
+ gfx::PointF popup_view_origin_for_emulation_;
+ gfx::PointF popup_screen_origin_for_emulation_;
float popup_origin_scale_for_emulation_;
scoped_refptr<FrameSwapMessageQueue> frame_swap_message_queue_;
diff --git a/chromium/content/renderer/render_widget_browsertest.cc b/chromium/content/renderer/render_widget_browsertest.cc
index 3a2bb1aaac6..ab3142722a9 100644
--- a/chromium/content/renderer/render_widget_browsertest.cc
+++ b/chromium/content/renderer/render_widget_browsertest.cc
@@ -2,12 +2,89 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "content/common/view_messages.h"
#include "content/public/test/render_widget_test.h"
+#include "content/renderer/render_widget.h"
namespace content {
TEST_F(RenderWidgetTest, OnResize) {
- TestOnResize();
+ // The initial bounds is empty, so setting it to the same thing should do
+ // nothing.
+ ViewMsg_Resize_Params resize_params;
+ resize_params.screen_info = blink::WebScreenInfo();
+ resize_params.new_size = gfx::Size();
+ resize_params.physical_backing_size = gfx::Size();
+ resize_params.top_controls_height = 0.f;
+ resize_params.top_controls_shrink_blink_size = false;
+ resize_params.resizer_rect = gfx::Rect();
+ resize_params.is_fullscreen_granted = false;
+ resize_params.needs_resize_ack = false;
+ OnResize(resize_params);
+ EXPECT_EQ(resize_params.needs_resize_ack, next_paint_is_resize_ack());
+
+ // Setting empty physical backing size should not send the ack.
+ resize_params.new_size = gfx::Size(10, 10);
+ OnResize(resize_params);
+ EXPECT_EQ(resize_params.needs_resize_ack, next_paint_is_resize_ack());
+
+ // Setting the bounds to a "real" rect should send the ack.
+ render_thread_->sink().ClearMessages();
+ gfx::Size size(100, 100);
+ resize_params.new_size = size;
+ resize_params.physical_backing_size = size;
+ resize_params.needs_resize_ack = true;
+ OnResize(resize_params);
+ EXPECT_EQ(resize_params.needs_resize_ack, next_paint_is_resize_ack());
+
+ // Clear the flag.
+ widget()->didCompleteSwapBuffers();
+
+ // Setting the same size again should not send the ack.
+ resize_params.needs_resize_ack = false;
+ OnResize(resize_params);
+ EXPECT_EQ(resize_params.needs_resize_ack, next_paint_is_resize_ack());
+
+ // Resetting the rect to empty should not send the ack.
+ resize_params.new_size = gfx::Size();
+ resize_params.physical_backing_size = gfx::Size();
+ OnResize(resize_params);
+ EXPECT_EQ(resize_params.needs_resize_ack, next_paint_is_resize_ack());
+
+ // Changing the screen info should not send the ack.
+ resize_params.screen_info.orientationAngle = 90;
+ OnResize(resize_params);
+ EXPECT_EQ(resize_params.needs_resize_ack, next_paint_is_resize_ack());
+
+ resize_params.screen_info.orientationType =
+ blink::WebScreenOrientationPortraitPrimary;
+ OnResize(resize_params);
+ EXPECT_EQ(resize_params.needs_resize_ack, next_paint_is_resize_ack());
}
+class RenderWidgetInitialSizeTest : public RenderWidgetTest {
+ public:
+ RenderWidgetInitialSizeTest()
+ : RenderWidgetTest(), initial_size_(200, 100) {}
+
+ protected:
+ scoped_ptr<ViewMsg_Resize_Params> InitialSizeParams() override {
+ scoped_ptr<ViewMsg_Resize_Params> initial_size_params(
+ new ViewMsg_Resize_Params());
+ initial_size_params->new_size = initial_size_;
+ initial_size_params->physical_backing_size = initial_size_;
+ initial_size_params->needs_resize_ack = true;
+ return initial_size_params.Pass();
+ }
+
+ gfx::Size initial_size_;
+};
+
+TEST_F(RenderWidgetInitialSizeTest, InitialSize) {
+ EXPECT_EQ(initial_size_, widget()->size());
+ EXPECT_EQ(initial_size_, gfx::Size(widget()->webwidget()->size()));
+ EXPECT_TRUE(next_paint_is_resize_ack());
+}
+
+
} // namespace content
diff --git a/chromium/content/renderer/render_widget_fullscreen.cc b/chromium/content/renderer/render_widget_fullscreen.cc
index af2c28187db..1e01a056e84 100644
--- a/chromium/content/renderer/render_widget_fullscreen.cc
+++ b/chromium/content/renderer/render_widget_fullscreen.cc
@@ -19,7 +19,7 @@ void RenderWidgetFullscreen::show(blink::WebNavigationPolicy) {
if (!did_show_) {
did_show_ = true;
Send(new ViewHostMsg_ShowFullscreenWidget(opener_id_, routing_id_));
- SetPendingWindowRect(initial_pos_);
+ SetPendingWindowRect(initial_rect_);
}
}
@@ -34,14 +34,13 @@ WebWidget* RenderWidgetFullscreen::CreateWebWidget() {
return RenderWidget::CreateWebWidget(this);
}
-bool RenderWidgetFullscreen::Init(int32 opener_id) {
+bool RenderWidgetFullscreen::Init(int32 opener_id,
+ CompositorDependencies* compositor_deps) {
DCHECK(!webwidget_);
- return RenderWidget::DoInit(
- opener_id,
- CreateWebWidget(),
- new ViewHostMsg_CreateFullscreenWidget(
- opener_id, &routing_id_, &surface_id_));
+ return RenderWidget::DoInit(opener_id, compositor_deps, CreateWebWidget(),
+ new ViewHostMsg_CreateFullscreenWidget(
+ opener_id, &routing_id_, &surface_id_));
}
} // namespace content
diff --git a/chromium/content/renderer/render_widget_fullscreen.h b/chromium/content/renderer/render_widget_fullscreen.h
index 83ce34952e9..81af2df58b9 100644
--- a/chromium/content/renderer/render_widget_fullscreen.h
+++ b/chromium/content/renderer/render_widget_fullscreen.h
@@ -10,6 +10,7 @@
#include "third_party/WebKit/public/web/WebWidget.h"
namespace content {
+class CompositorDependencies;
// TODO(boliu): Override non-supported methods with no-op? eg setWindowRect().
class RenderWidgetFullscreen : public RenderWidget {
@@ -22,7 +23,7 @@ class RenderWidgetFullscreen : public RenderWidget {
virtual blink::WebWidget* CreateWebWidget();
- bool Init(int32 opener_id);
+ bool Init(int32 opener_id, CompositorDependencies* compositor_deps);
};
} // namespace content
diff --git a/chromium/content/renderer/render_widget_fullscreen_pepper.cc b/chromium/content/renderer/render_widget_fullscreen_pepper.cc
index f58304ef1df..29bc75950cb 100644
--- a/chromium/content/renderer/render_widget_fullscreen_pepper.cc
+++ b/chromium/content/renderer/render_widget_fullscreen_pepper.cc
@@ -23,7 +23,7 @@
#include "third_party/WebKit/public/platform/WebLayer.h"
#include "third_party/WebKit/public/platform/WebSize.h"
#include "third_party/WebKit/public/web/WebWidget.h"
-#include "ui/gfx/size_conversions.h"
+#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gl/gpu_preference.h"
using blink::WebCanvas;
@@ -155,7 +155,7 @@ class PepperWidget : public WebWidget {
size_ = size;
WebRect plugin_rect(0, 0, size_.width, size_.height);
- widget_->plugin()->ViewChanged(plugin_rect, plugin_rect,
+ widget_->plugin()->ViewChanged(plugin_rect, plugin_rect, plugin_rect,
std::vector<gfx::Rect>());
widget_->Invalidate();
}
@@ -264,13 +264,14 @@ class PepperWidget : public WebWidget {
// static
RenderWidgetFullscreenPepper* RenderWidgetFullscreenPepper::Create(
int32 opener_id,
+ CompositorDependencies* compositor_deps,
PepperPluginInstanceImpl* plugin,
const GURL& active_url,
const blink::WebScreenInfo& screen_info) {
DCHECK_NE(MSG_ROUTING_NONE, opener_id);
scoped_refptr<RenderWidgetFullscreenPepper> widget(
new RenderWidgetFullscreenPepper(plugin, active_url, screen_info));
- widget->Init(opener_id);
+ widget->Init(opener_id, compositor_deps);
widget->AddRef();
return widget.get();
}
@@ -359,8 +360,6 @@ void RenderWidgetFullscreenPepper::DidInitiatePaint() {
}
void RenderWidgetFullscreenPepper::DidFlushPaint() {
- if (plugin_)
- plugin_->ViewFlushedPaint();
}
void RenderWidgetFullscreenPepper::Close() {
diff --git a/chromium/content/renderer/render_widget_fullscreen_pepper.h b/chromium/content/renderer/render_widget_fullscreen_pepper.h
index 24808e8f54b..e94f6137c8d 100644
--- a/chromium/content/renderer/render_widget_fullscreen_pepper.h
+++ b/chromium/content/renderer/render_widget_fullscreen_pepper.h
@@ -26,6 +26,7 @@ class RenderWidgetFullscreenPepper : public RenderWidgetFullscreen,
public:
static RenderWidgetFullscreenPepper* Create(
int32 opener_id,
+ CompositorDependencies* compositor_deps,
PepperPluginInstanceImpl* plugin,
const GURL& active_url,
const blink::WebScreenInfo& screen_info);
diff --git a/chromium/content/renderer/render_widget_unittest.cc b/chromium/content/renderer/render_widget_unittest.cc
index e0dbc83d614..431b2fa5fd5 100644
--- a/chromium/content/renderer/render_widget_unittest.cc
+++ b/chromium/content/renderer/render_widget_unittest.cc
@@ -13,7 +13,7 @@
#include "ipc/ipc_test_sink.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
-#include "ui/gfx/rect.h"
+#include "ui/gfx/geometry/rect.h"
namespace content {
@@ -89,7 +89,7 @@ TEST_F(RenderWidgetUnittest, TouchHitTestSinglePoint) {
EXPECT_EQ(InputHostMsg_HandleInputEvent_ACK::ID, message->type());
InputHostMsg_HandleInputEvent_ACK::Param params;
InputHostMsg_HandleInputEvent_ACK::Read(message, &params);
- InputEventAckState ack_state = params.a.state;
+ InputEventAckState ack_state = get<0>(params).state;
EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, ack_state);
widget->sink()->ClearMessages();
@@ -103,7 +103,7 @@ TEST_F(RenderWidgetUnittest, TouchHitTestSinglePoint) {
message = widget->sink()->GetMessageAt(0);
EXPECT_EQ(InputHostMsg_HandleInputEvent_ACK::ID, message->type());
InputHostMsg_HandleInputEvent_ACK::Read(message, &params);
- ack_state = params.a.state;
+ ack_state = get<0>(params).state;
EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, ack_state);
widget->sink()->ClearMessages();
}
@@ -127,7 +127,7 @@ TEST_F(RenderWidgetUnittest, TouchHitTestMultiplePoints) {
EXPECT_EQ(InputHostMsg_HandleInputEvent_ACK::ID, message->type());
InputHostMsg_HandleInputEvent_ACK::Param params;
InputHostMsg_HandleInputEvent_ACK::Read(message, &params);
- InputEventAckState ack_state = params.a.state;
+ InputEventAckState ack_state = get<0>(params).state;
EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, ack_state);
widget->sink()->ClearMessages();
@@ -138,7 +138,7 @@ TEST_F(RenderWidgetUnittest, TouchHitTestMultiplePoints) {
message = widget->sink()->GetMessageAt(0);
EXPECT_EQ(InputHostMsg_HandleInputEvent_ACK::ID, message->type());
InputHostMsg_HandleInputEvent_ACK::Read(message, &params);
- ack_state = params.a.state;
+ ack_state = get<0>(params).state;
EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, ack_state);
widget->sink()->ClearMessages();
}
diff --git a/chromium/content/renderer/renderer.gni b/chromium/content/renderer/renderer.gni
index 2b638894a28..a6d4c0cf8c8 100644
--- a/chromium/content/renderer/renderer.gni
+++ b/chromium/content/renderer/renderer.gni
@@ -6,9 +6,8 @@
# and cached, which is a performance optimization that allows us to share the
# results of parsing the .gypi file between the public and private BUILD.gn
# files. It also saves us from duplicating this exec_script call.
-content_renderer_gypi_values = exec_script(
- "//build/gypi_to_gn.py",
- [ rebase_path("../content_renderer.gypi") ],
- "scope",
- [ "../content_renderer.gypi" ])
-
+content_renderer_gypi_values =
+ exec_script("//build/gypi_to_gn.py",
+ [ rebase_path("../content_renderer.gypi") ],
+ "scope",
+ [ "../content_renderer.gypi" ])
diff --git a/chromium/content/renderer/renderer_blink_platform_impl.cc b/chromium/content/renderer/renderer_blink_platform_impl.cc
index 2aa359bd43f..0e9864fdc6f 100644
--- a/chromium/content/renderer/renderer_blink_platform_impl.cc
+++ b/chromium/content/renderer/renderer_blink_platform_impl.cc
@@ -14,7 +14,10 @@
#include "base/numerics/safe_conversions.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
-#include "content/child/bluetooth/web_bluetooth_impl.h"
+#include "cc/blink/context_provider_web_context.h"
+#include "components/scheduler/child/web_scheduler_impl.h"
+#include "components/scheduler/renderer/renderer_scheduler.h"
+#include "components/scheduler/renderer/webthread_impl_for_renderer_scheduler.h"
#include "content/child/database_util.h"
#include "content/child/file_info_util.h"
#include "content/child/fileapi/webfilesystem_impl.h"
@@ -36,23 +39,21 @@
#include "content/common/mime_registry_messages.h"
#include "content/common/view_messages.h"
#include "content/public/common/content_switches.h"
+#include "content/public/common/service_registry.h"
#include "content/public/common/webplugininfo.h"
#include "content/public/renderer/content_renderer_client.h"
#include "content/renderer/battery_status/battery_status_dispatcher.h"
+#include "content/renderer/cache_storage/webserviceworkercachestorage_impl.h"
#include "content/renderer/device_sensors/device_light_event_pump.h"
#include "content/renderer/device_sensors/device_motion_event_pump.h"
#include "content/renderer/device_sensors/device_orientation_event_pump.h"
#include "content/renderer/dom_storage/webstoragenamespace_impl.h"
#include "content/renderer/gamepad_shared_memory_reader.h"
#include "content/renderer/media/audio_decoder.h"
-#include "content/renderer/media/crypto/key_systems.h"
#include "content/renderer/media/renderer_webaudiodevice_impl.h"
#include "content/renderer/media/renderer_webmidiaccessor_impl.h"
-#include "content/renderer/media/webcontentdecryptionmodule_impl.h"
#include "content/renderer/render_thread_impl.h"
-#include "content/renderer/renderer_clipboard_client.h"
-#include "content/renderer/scheduler/renderer_scheduler.h"
-#include "content/renderer/scheduler/web_scheduler_impl.h"
+#include "content/renderer/renderer_clipboard_delegate.h"
#include "content/renderer/screen_orientation/screen_orientation_observer.h"
#include "content/renderer/webclipboard_impl.h"
#include "content/renderer/webgraphicscontext3d_provider_impl.h"
@@ -61,15 +62,16 @@
#include "ipc/ipc_sync_message_filter.h"
#include "media/audio/audio_output_device.h"
#include "media/base/audio_hardware_config.h"
+#include "media/base/key_systems.h"
+#include "media/blink/webcontentdecryptionmodule_impl.h"
#include "media/filters/stream_parser_factory.h"
#include "net/base/mime_util.h"
#include "net/base/net_util.h"
+#include "storage/common/database/database_identifier.h"
#include "storage/common/quota/quota_types.h"
#include "third_party/WebKit/public/platform/WebBatteryStatusListener.h"
#include "third_party/WebKit/public/platform/WebBlobRegistry.h"
#include "third_party/WebKit/public/platform/WebDeviceLightListener.h"
-#include "third_party/WebKit/public/platform/WebDeviceMotionListener.h"
-#include "third_party/WebKit/public/platform/WebDeviceOrientationListener.h"
#include "third_party/WebKit/public/platform/WebFileInfo.h"
#include "third_party/WebKit/public/platform/WebGamepads.h"
#include "third_party/WebKit/public/platform/WebMediaStreamCenter.h"
@@ -77,14 +79,15 @@
#include "third_party/WebKit/public/platform/WebPluginListBuilder.h"
#include "third_party/WebKit/public/platform/WebURL.h"
#include "third_party/WebKit/public/platform/WebVector.h"
+#include "third_party/WebKit/public/platform/modules/device_orientation/WebDeviceMotionListener.h"
+#include "third_party/WebKit/public/platform/modules/device_orientation/WebDeviceOrientationListener.h"
#include "ui/gfx/color_profile.h"
#include "url/gurl.h"
-#include "webkit/common/gpu/context_provider_web_context.h"
#if defined(OS_ANDROID)
#include "content/renderer/android/synchronous_compositor_factory.h"
#include "content/renderer/media/android/audio_decoder_android.h"
-#include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"
+#include "gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.h"
#endif
#if defined(OS_MACOSX)
@@ -110,7 +113,6 @@
#if defined(OS_WIN)
#include "content/common/child_process_messages.h"
-#include "third_party/WebKit/public/platform/win/WebSandboxSupport.h"
#endif
#if defined(USE_AURA)
@@ -171,9 +173,6 @@ class RendererBlinkPlatformImpl::MimeRegistry
const blink::WebString& key_system);
virtual bool supportsMediaSourceMIMEType(const blink::WebString& mime_type,
const blink::WebString& codecs);
- virtual bool supportsEncryptedMediaMIMEType(const WebString& key_system,
- const WebString& mime_type,
- const WebString& codecs) override;
virtual blink::WebString mimeTypeForExtension(
const blink::WebString& file_extension);
virtual blink::WebString mimeTypeFromFile(
@@ -190,19 +189,13 @@ class RendererBlinkPlatformImpl::FileUtilities : public WebFileUtilitiesImpl {
scoped_refptr<ThreadSafeSender> thread_safe_sender_;
};
-#if defined(OS_ANDROID)
-// WebKit doesn't use WebSandboxSupport on android so we don't need to
-// implement anything here.
-class RendererBlinkPlatformImpl::SandboxSupport {};
-#else
+#if !defined(OS_ANDROID) && !defined(OS_WIN)
class RendererBlinkPlatformImpl::SandboxSupport
: public blink::WebSandboxSupport {
public:
virtual ~SandboxSupport() {}
-#if defined(OS_WIN)
- virtual bool ensureFontLoaded(HFONT);
-#elif defined(OS_MACOSX)
+#if defined(OS_MACOSX)
virtual bool loadFont(
NSFont* src_font,
CGFontRef* container,
@@ -223,33 +216,35 @@ class RendererBlinkPlatformImpl::SandboxSupport
std::map<int32_t, blink::WebFallbackFont> unicode_font_families_;
#endif
};
-#endif // defined(OS_ANDROID)
+#endif // !defined(OS_ANDROID) && !defined(OS_WIN)
//------------------------------------------------------------------------------
RendererBlinkPlatformImpl::RendererBlinkPlatformImpl(
- RendererScheduler* renderer_scheduler)
- : web_scheduler_(new WebSchedulerImpl(renderer_scheduler)),
- clipboard_client_(new RendererClipboardClient),
- clipboard_(new WebClipboardImpl(clipboard_client_.get())),
+ scheduler::RendererScheduler* renderer_scheduler)
+ : BlinkPlatformImpl(renderer_scheduler->DefaultTaskRunner()),
+ main_thread_(
+ new scheduler::WebThreadImplForRendererScheduler(renderer_scheduler)),
+ clipboard_delegate_(new RendererClipboardDelegate),
+ clipboard_(new WebClipboardImpl(clipboard_delegate_.get())),
mime_registry_(new RendererBlinkPlatformImpl::MimeRegistry),
sudden_termination_disables_(0),
plugin_refresh_allowed_(true),
default_task_runner_(renderer_scheduler->DefaultTaskRunner()),
- child_thread_loop_(base::MessageLoopProxy::current()),
- web_scrollbar_behavior_(new WebScrollbarBehaviorImpl),
- bluetooth_(new WebBluetoothImpl) {
+ web_scrollbar_behavior_(new WebScrollbarBehaviorImpl) {
+#if !defined(OS_ANDROID) && !defined(OS_WIN)
if (g_sandbox_enabled && sandboxEnabled()) {
sandbox_support_.reset(new RendererBlinkPlatformImpl::SandboxSupport);
} else {
DVLOG(1) << "Disabling sandbox support for testing.";
}
+#endif
// ChildThread may not exist in some tests.
- if (ChildThread::current()) {
- sync_message_filter_ = ChildThread::current()->sync_message_filter();
- thread_safe_sender_ = ChildThread::current()->thread_safe_sender();
- quota_message_filter_ = ChildThread::current()->quota_message_filter();
+ if (ChildThreadImpl::current()) {
+ sync_message_filter_ = ChildThreadImpl::current()->sync_message_filter();
+ thread_safe_sender_ = ChildThreadImpl::current()->thread_safe_sender();
+ quota_message_filter_ = ChildThreadImpl::current()->quota_message_filter();
blob_registry_.reset(new WebBlobRegistryImpl(thread_safe_sender_.get()));
web_idb_factory_.reset(new WebIDBFactoryImpl(thread_safe_sender_.get()));
web_database_observer_impl_.reset(
@@ -263,13 +258,10 @@ RendererBlinkPlatformImpl::~RendererBlinkPlatformImpl() {
//------------------------------------------------------------------------------
-void RendererBlinkPlatformImpl::callOnMainThread(void (*func)(void*),
- void* context) {
- default_task_runner_->PostTask(FROM_HERE, base::Bind(func, context));
-}
-
-blink::WebScheduler* RendererBlinkPlatformImpl::scheduler() {
- return web_scheduler_.get();
+blink::WebThread* RendererBlinkPlatformImpl::currentThread() {
+ if (main_thread_->isCurrentThread())
+ return main_thread_.get();
+ return BlinkPlatformImpl::currentThread();
}
blink::WebClipboard* RendererBlinkPlatformImpl::clipboard() {
@@ -293,8 +285,8 @@ blink::WebFileUtilities* RendererBlinkPlatformImpl::fileUtilities() {
}
blink::WebSandboxSupport* RendererBlinkPlatformImpl::sandboxSupport() {
-#if defined(OS_ANDROID)
- // WebKit doesn't use WebSandboxSupport on android.
+#if defined(OS_ANDROID) || defined(OS_WIN)
+ // These platforms do not require sandbox support.
return NULL;
#else
return sandbox_support_.get();
@@ -322,7 +314,8 @@ bool RendererBlinkPlatformImpl::sandboxEnabled() {
// case, we have no other choice. Platform.h discourages using
// this switch unless absolutely necessary, so hopefully we won't end up
// with too many code paths being different in single-process mode.
- return !CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess);
+ return !base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSingleProcess);
}
unsigned long long RendererBlinkPlatformImpl::visitedLinkHash(
@@ -339,7 +332,7 @@ void RendererBlinkPlatformImpl::createMessageChannel(
blink::WebMessagePortChannel** channel1,
blink::WebMessagePortChannel** channel2) {
WebMessagePortChannelImpl::CreatePair(
- child_thread_loop_.get(), channel1, channel2);
+ default_task_runner_, channel1, channel2);
}
blink::WebPrescientNetworking*
@@ -348,15 +341,15 @@ RendererBlinkPlatformImpl::prescientNetworking() {
}
void RendererBlinkPlatformImpl::cacheMetadata(const blink::WebURL& url,
- double response_time,
+ int64 response_time,
const char* data,
size_t size) {
// Let the browser know we generated cacheable metadata for this resource. The
// browser may cache it and return it on subsequent responses to speed
// the processing of this resource.
std::vector<char> copy(data, data + size);
- RenderThread::Get()->Send(
- new ViewHostMsg_DidGenerateCacheableMetadata(url, response_time, copy));
+ RenderThread::Get()->Send(new ViewHostMsg_DidGenerateCacheableMetadata(
+ url, base::Time::FromInternalValue(response_time), copy));
}
WebString RendererBlinkPlatformImpl::defaultLocale() {
@@ -396,8 +389,18 @@ WebIDBFactory* RendererBlinkPlatformImpl::idbFactory() {
//------------------------------------------------------------------------------
+blink::WebServiceWorkerCacheStorage* RendererBlinkPlatformImpl::cacheStorage(
+ const WebString& origin_identifier) {
+ const GURL origin =
+ storage::GetOriginFromIdentifier(origin_identifier.utf8());
+ return new WebServiceWorkerCacheStorageImpl(thread_safe_sender_.get(),
+ origin);
+}
+
+//------------------------------------------------------------------------------
+
WebFileSystem* RendererBlinkPlatformImpl::fileSystem() {
- return WebFileSystemImpl::ThreadSpecificInstance(child_thread_loop_.get());
+ return WebFileSystemImpl::ThreadSpecificInstance(default_task_runner_);
}
//------------------------------------------------------------------------------
@@ -420,11 +423,11 @@ RendererBlinkPlatformImpl::MimeRegistry::supportsMediaMIMEType(
return IsNotSupported;
std::string key_system_ascii =
- GetUnprefixedKeySystemName(base::UTF16ToASCII(key_system));
+ media::GetUnprefixedKeySystemName(base::UTF16ToASCII(key_system));
std::vector<std::string> strict_codecs;
net::ParseCodecString(ToASCIIOrEmpty(codecs), &strict_codecs, true);
- if (!IsSupportedKeySystemWithMediaMimeType(
+ if (!media::PrefixedIsSupportedKeySystemWithMediaMimeType(
mime_type_ascii, strict_codecs, key_system_ascii)) {
return IsNotSupported;
}
@@ -463,30 +466,6 @@ bool RendererBlinkPlatformImpl::MimeRegistry::supportsMediaSourceMIMEType(
mime_type_ascii, parsed_codec_ids);
}
-bool RendererBlinkPlatformImpl::MimeRegistry::supportsEncryptedMediaMIMEType(
- const WebString& key_system,
- const WebString& mime_type,
- const WebString& codecs) {
- // Chromium only supports ASCII parameters.
- if (!base::IsStringASCII(key_system) || !base::IsStringASCII(mime_type) ||
- !base::IsStringASCII(codecs)) {
- return false;
- }
-
- if (key_system.isEmpty())
- return false;
-
- const std::string mime_type_ascii = base::UTF16ToASCII(mime_type);
-
- std::vector<std::string> codec_vector;
- bool strip_suffix = !net::IsStrictMediaMimeType(mime_type_ascii);
- net::ParseCodecString(base::UTF16ToASCII(codecs), &codec_vector,
- strip_suffix);
-
- return IsSupportedKeySystemWithMediaMimeType(
- mime_type_ascii, codec_vector, base::UTF16ToASCII(key_system));
-}
-
WebString RendererBlinkPlatformImpl::MimeRegistry::mimeTypeForExtension(
const WebString& file_extension) {
if (IsPluginProcess())
@@ -543,16 +522,7 @@ bool RendererBlinkPlatformImpl::FileUtilities::SendSyncMessageFromAnyThread(
//------------------------------------------------------------------------------
-#if defined(OS_WIN)
-
-bool RendererBlinkPlatformImpl::SandboxSupport::ensureFontLoaded(HFONT font) {
- LOGFONT logfont;
- GetObject(font, sizeof(LOGFONT), &logfont);
- RenderThread::Get()->PreCacheFont(logfont);
- return true;
-}
-
-#elif defined(OS_MACOSX)
+#if defined(OS_MACOSX)
bool RendererBlinkPlatformImpl::SandboxSupport::loadFont(NSFont* src_font,
CGFontRef* out,
@@ -583,13 +553,7 @@ bool RendererBlinkPlatformImpl::SandboxSupport::loadFont(NSFont* src_font,
return FontLoader::CGFontRefFromBuffer(font_data, font_data_size, out);
}
-#elif defined(OS_ANDROID)
-
-// WebKit doesn't use WebSandboxSupport on android so we don't need to
-// implement anything here. This is cleaner to support than excluding the
-// whole class for android.
-
-#elif defined(OS_POSIX)
+#elif defined(OS_POSIX) && !defined(OS_ANDROID)
void RendererBlinkPlatformImpl::SandboxSupport::getFallbackFontForCharacter(
blink::WebUChar32 character,
@@ -655,6 +619,12 @@ long long RendererBlinkPlatformImpl::databaseGetSpaceAvailableForOrigin(
sync_message_filter_.get());
}
+bool RendererBlinkPlatformImpl::databaseSetFileSize(
+ const WebString& vfs_file_name, long long size) {
+ return DatabaseUtil::DatabaseSetFileSize(
+ vfs_file_name, size, sync_message_filter_.get());
+}
+
bool RendererBlinkPlatformImpl::canAccelerate2dCanvas() {
RenderThreadImpl* thread = RenderThreadImpl::current();
GpuChannelHost* host = thread->EstablishGpuChannelSync(
@@ -969,7 +939,7 @@ RendererBlinkPlatformImpl::createOffscreenGraphicsContext3D(
#if defined(OS_ANDROID)
if (SynchronousCompositorFactory* factory =
SynchronousCompositorFactory::GetInstance()) {
- scoped_ptr<webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl>
+ scoped_ptr<gpu_blink::WebGraphicsContext3DInProcessCommandBufferImpl>
in_process_context(
factory->CreateOffscreenGraphicsContext3D(attributes));
if (!in_process_context ||
@@ -985,11 +955,27 @@ RendererBlinkPlatformImpl::createOffscreenGraphicsContext3D(
if (gpu_channel_host.get() && gl_info) {
const gpu::GPUInfo& gpu_info = gpu_channel_host->gpu_info();
- gl_info->vendorInfo.assign(blink::WebString::fromUTF8(gpu_info.gl_vendor));
- gl_info->rendererInfo.assign(
- blink::WebString::fromUTF8(gpu_info.gl_renderer));
- gl_info->driverVersion.assign(
- blink::WebString::fromUTF8(gpu_info.gl_version));
+ switch (gpu_info.context_info_state) {
+ case gpu::kCollectInfoSuccess:
+ case gpu::kCollectInfoNonFatalFailure:
+ gl_info->vendorInfo.assign(
+ blink::WebString::fromUTF8(gpu_info.gl_vendor));
+ gl_info->rendererInfo.assign(
+ blink::WebString::fromUTF8(gpu_info.gl_renderer));
+ gl_info->driverVersion.assign(
+ blink::WebString::fromUTF8(gpu_info.driver_version));
+ gl_info->vendorId = gpu_info.gpu.vendor_id;
+ gl_info->deviceId = gpu_info.gpu.device_id;
+ break;
+ case gpu::kCollectInfoFatalFailure:
+ case gpu::kCollectInfoNone:
+ gl_info->contextInfoCollectionFailure.assign(blink::WebString::fromUTF8(
+ "GPUInfoCollectionFailure: GPU initialization Failed. GPU "
+ "Info not Collected."));
+ break;
+ default:
+ NOTREACHED();
+ };
}
WebGraphicsContext3DCommandBufferImpl::SharedMemoryLimits limits;
@@ -1014,7 +1000,7 @@ RendererBlinkPlatformImpl::createOffscreenGraphicsContext3D(
blink::WebGraphicsContext3DProvider*
RendererBlinkPlatformImpl::createSharedOffscreenGraphicsContext3DProvider() {
- scoped_refptr<webkit::gpu::ContextProviderWebContext> provider =
+ scoped_refptr<cc_blink::ContextProviderWebContext> provider =
RenderThreadImpl::current()->SharedMainThreadContextProvider();
if (!provider.get())
return NULL;
@@ -1037,6 +1023,18 @@ blink::WebString RendererBlinkPlatformImpl::convertIDNToUnicode(
//------------------------------------------------------------------------------
+void RendererBlinkPlatformImpl::recordRappor(const char* metric,
+ const blink::WebString& sample) {
+ GetContentClient()->renderer()->RecordRappor(metric, sample.utf8());
+}
+
+void RendererBlinkPlatformImpl::recordRapporURL(const char* metric,
+ const blink::WebURL& url) {
+ GetContentClient()->renderer()->RecordRapporURL(metric, url);
+}
+
+//------------------------------------------------------------------------------
+
// static
void RendererBlinkPlatformImpl::SetMockDeviceLightDataForTesting(double data) {
g_test_device_light_data = data;
@@ -1061,12 +1059,23 @@ void RendererBlinkPlatformImpl::SetMockDeviceOrientationDataForTesting(
//------------------------------------------------------------------------------
void RendererBlinkPlatformImpl::vibrate(unsigned int milliseconds) {
- RenderThread::Get()->Send(
- new ViewHostMsg_Vibrate(base::checked_cast<int64>(milliseconds)));
+ GetConnectedVibrationManagerService()->Vibrate(
+ base::checked_cast<int64>(milliseconds));
+ vibration_manager_.reset();
}
void RendererBlinkPlatformImpl::cancelVibration() {
- RenderThread::Get()->Send(new ViewHostMsg_CancelVibration());
+ GetConnectedVibrationManagerService()->Cancel();
+ vibration_manager_.reset();
+}
+
+device::VibrationManagerPtr&
+RendererBlinkPlatformImpl::GetConnectedVibrationManagerService() {
+ if (!vibration_manager_) {
+ RenderThread::Get()->GetServiceRegistry()
+ ->ConnectToRemoteService(&vibration_manager_);
+ }
+ return vibration_manager_;
}
//------------------------------------------------------------------------------
@@ -1097,8 +1106,8 @@ RendererBlinkPlatformImpl::CreatePlatformEventObserverFromType(
default:
// A default statement is required to prevent compilation errors when
// Blink adds a new type.
- VLOG(1) << "RendererBlinkPlatformImpl::startListening() with "
- "unknown type.";
+ DVLOG(1) << "RendererBlinkPlatformImpl::startListening() with "
+ "unknown type.";
}
return NULL;
@@ -1217,12 +1226,6 @@ void RendererBlinkPlatformImpl::queryStorageUsageAndQuota(
//------------------------------------------------------------------------------
-blink::WebBluetooth* RendererBlinkPlatformImpl::bluetooth() {
- return bluetooth_.get();
-}
-
-//------------------------------------------------------------------------------
-
void RendererBlinkPlatformImpl::MockBatteryStatusChangedForTesting(
const blink::WebBatteryStatus& status) {
if (!g_test_battery_status_listener)
diff --git a/chromium/content/renderer/renderer_blink_platform_impl.h b/chromium/content/renderer/renderer_blink_platform_impl.h
index f4f84deb08f..98f9e9c8abb 100644
--- a/chromium/content/renderer/renderer_blink_platform_impl.h
+++ b/chromium/content/renderer/renderer_blink_platform_impl.h
@@ -12,9 +12,10 @@
#include "content/child/blink_platform_impl.h"
#include "content/common/content_export.h"
#include "content/renderer/webpublicsuffixlist_impl.h"
+#include "device/vibration/vibration_manager.mojom.h"
#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
-#include "third_party/WebKit/public/platform/WebIDBFactory.h"
#include "third_party/WebKit/public/platform/WebScreenOrientationType.h"
+#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBFactory.h"
namespace base {
class MessageLoopProxy;
@@ -33,6 +34,12 @@ class WebBatteryStatus;
class WebDeviceMotionData;
class WebDeviceOrientationData;
class WebGraphicsContext3DProvider;
+class WebServiceWorkerCacheStorage;
+}
+
+namespace scheduler {
+class RendererScheduler;
+class WebThreadImplForRendererScheduler;
}
namespace content {
@@ -42,26 +49,23 @@ class DeviceMotionEventPump;
class DeviceOrientationEventPump;
class PlatformEventObserverBase;
class QuotaMessageFilter;
-class RendererClipboardClient;
-class RendererScheduler;
+class RendererClipboardDelegate;
class RenderView;
class ThreadSafeSender;
-class WebBluetoothImpl;
class WebClipboardImpl;
class WebDatabaseObserverImpl;
class WebFileSystemImpl;
-class WebSchedulerImpl;
class CONTENT_EXPORT RendererBlinkPlatformImpl : public BlinkPlatformImpl {
public:
- RendererBlinkPlatformImpl(RendererScheduler* renderer_scheduler);
+ explicit RendererBlinkPlatformImpl(
+ scheduler::RendererScheduler* renderer_scheduler);
virtual ~RendererBlinkPlatformImpl();
void set_plugin_refresh_allowed(bool plugin_refresh_allowed) {
plugin_refresh_allowed_ = plugin_refresh_allowed;
}
// Platform methods:
- virtual void callOnMainThread(void (*func)(void*), void* context);
virtual blink::WebClipboard* clipboard();
virtual blink::WebMimeRegistry* mimeRegistry();
virtual blink::WebFileUtilities* fileUtilities();
@@ -77,8 +81,7 @@ class CONTENT_EXPORT RendererBlinkPlatformImpl : public BlinkPlatformImpl {
virtual void createMessageChannel(blink::WebMessagePortChannel** channel1,
blink::WebMessagePortChannel** channel2);
virtual blink::WebPrescientNetworking* prescientNetworking();
- virtual void cacheMetadata(
- const blink::WebURL&, double, const char*, size_t);
+ virtual void cacheMetadata(const blink::WebURL&, int64, const char*, size_t);
virtual blink::WebString defaultLocale();
virtual void suddenTerminationChanged(bool enabled);
virtual blink::WebStorageNamespace* createLocalStorageNamespace();
@@ -92,6 +95,8 @@ class CONTENT_EXPORT RendererBlinkPlatformImpl : public BlinkPlatformImpl {
const blink::WebString& vfs_file_name);
virtual long long databaseGetSpaceAvailableForOrigin(
const blink::WebString& origin_identifier);
+ virtual bool databaseSetFileSize(
+ const blink::WebString& vfs_file_name, long long size);
virtual blink::WebString signedPublicKeyAndChallengeString(
unsigned key_size_index,
const blink::WebString& challenge,
@@ -102,6 +107,8 @@ class CONTENT_EXPORT RendererBlinkPlatformImpl : public BlinkPlatformImpl {
virtual void screenColorProfile(blink::WebVector<char>* to_profile);
virtual blink::WebScrollbarBehavior* scrollbarBehavior();
virtual blink::WebIDBFactory* idbFactory();
+ virtual blink::WebServiceWorkerCacheStorage* cacheStorage(
+ const blink::WebString& origin_identifier);
virtual blink::WebFileSystem* fileSystem();
virtual bool canAccelerate2dCanvas();
virtual bool isThreadedCompositingEnabled();
@@ -151,10 +158,11 @@ class CONTENT_EXPORT RendererBlinkPlatformImpl : public BlinkPlatformImpl {
const blink::WebURL& storage_partition,
blink::WebStorageQuotaType,
blink::WebStorageQuotaCallbacks);
- virtual blink::WebBluetooth* bluetooth();
virtual void vibrate(unsigned int milliseconds);
virtual void cancelVibration();
- virtual blink::WebScheduler* scheduler();
+ virtual blink::WebThread* currentThread();
+ virtual void recordRappor(const char* metric, const blink::WebString& sample);
+ virtual void recordRapporURL(const char* metric, const blink::WebURL& url);
// Set the PlatformEventObserverBase in |platform_event_observers_| associated
// with |type| to |observer|. If there was already an observer associated to
@@ -191,8 +199,6 @@ class CONTENT_EXPORT RendererBlinkPlatformImpl : public BlinkPlatformImpl {
return web_database_observer_impl_.get();
}
- WebBluetoothImpl* BluetoothImplForTesting() { return bluetooth_.get(); }
-
private:
bool CheckPreparsedJsCachingEnabled() const;
@@ -204,10 +210,11 @@ class CONTENT_EXPORT RendererBlinkPlatformImpl : public BlinkPlatformImpl {
// Use the data previously set via SetMockDevice...DataForTesting() and send
// them to the registered listener.
void SendFakeDeviceEventDataForTesting(blink::WebPlatformEventType type);
+ device::VibrationManagerPtr& GetConnectedVibrationManagerService();
- scoped_ptr<WebSchedulerImpl> web_scheduler_;
+ scoped_ptr<scheduler::WebThreadImplForRendererScheduler> main_thread_;
- scoped_ptr<RendererClipboardClient> clipboard_client_;
+ scoped_ptr<RendererClipboardDelegate> clipboard_delegate_;
scoped_ptr<WebClipboardImpl> clipboard_;
class FileUtilities;
@@ -216,8 +223,10 @@ class CONTENT_EXPORT RendererBlinkPlatformImpl : public BlinkPlatformImpl {
class MimeRegistry;
scoped_ptr<MimeRegistry> mime_registry_;
+#if !defined(OS_ANDROID) && !defined(OS_WIN)
class SandboxSupport;
scoped_ptr<SandboxSupport> sandbox_support_;
+#endif
// This counter keeps track of the number of times sudden termination is
// enabled or disabled. It starts at 0 (enabled) and for every disable
@@ -239,7 +248,6 @@ class CONTENT_EXPORT RendererBlinkPlatformImpl : public BlinkPlatformImpl {
scoped_ptr<DeviceOrientationEventPump> device_orientation_event_pump_;
scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_;
- scoped_refptr<base::MessageLoopProxy> child_thread_loop_;
scoped_refptr<IPC::SyncMessageFilter> sync_message_filter_;
scoped_refptr<ThreadSafeSender> thread_safe_sender_;
scoped_refptr<QuotaMessageFilter> quota_message_filter_;
@@ -252,7 +260,8 @@ class CONTENT_EXPORT RendererBlinkPlatformImpl : public BlinkPlatformImpl {
scoped_ptr<BatteryStatusDispatcher> battery_status_dispatcher_;
- scoped_ptr<WebBluetoothImpl> bluetooth_;
+ // Handle to the Vibration mojo service.
+ device::VibrationManagerPtr vibration_manager_;
IDMap<PlatformEventObserverBase, IDMapOwnPointer> platform_event_observers_;
diff --git a/chromium/content/renderer/renderer_clipboard_client.cc b/chromium/content/renderer/renderer_clipboard_client.cc
deleted file mode 100644
index 1e2953ea989..00000000000
--- a/chromium/content/renderer/renderer_clipboard_client.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.
-
-// This file provides the embedder's side of the Clipboard interface.
-
-#include "content/renderer/renderer_clipboard_client.h"
-
-#include "base/memory/shared_memory.h"
-#include "base/numerics/safe_math.h"
-#include "base/strings/string16.h"
-#include "content/common/clipboard_messages.h"
-#include "content/public/renderer/content_renderer_client.h"
-#include "content/renderer/render_thread_impl.h"
-#include "content/renderer/scoped_clipboard_writer_glue.h"
-#include "ui/base/clipboard/clipboard.h"
-#include "ui/gfx/size.h"
-
-namespace content {
-
-namespace {
-
-class RendererClipboardWriteContext : public ClipboardClient::WriteContext {
- public:
- RendererClipboardWriteContext();
- ~RendererClipboardWriteContext() override;
- void WriteBitmapFromPixels(ui::Clipboard::ObjectMap* objects,
- const void* pixels,
- const gfx::Size& size) override;
- void Flush(const ui::Clipboard::ObjectMap& objects) override;
-
- private:
- scoped_ptr<base::SharedMemory> shared_buf_;
- DISALLOW_COPY_AND_ASSIGN(RendererClipboardWriteContext);
-};
-
-RendererClipboardWriteContext::RendererClipboardWriteContext() {
-}
-
-RendererClipboardWriteContext::~RendererClipboardWriteContext() {
-}
-
-// This definition of WriteBitmapFromPixels uses shared memory to communicate
-// across processes.
-void RendererClipboardWriteContext::WriteBitmapFromPixels(
- ui::Clipboard::ObjectMap* objects,
- const void* pixels,
- const gfx::Size& size) {
- // Do not try to write a bitmap more than once
- if (shared_buf_)
- return;
-
- base::CheckedNumeric<uint32> checked_buf_size = 4;
- checked_buf_size *= size.width();
- checked_buf_size *= size.height();
- if (!checked_buf_size.IsValid())
- return;
-
- uint32 buf_size = checked_buf_size.ValueOrDie();
-
- // Allocate a shared memory buffer to hold the bitmap bits.
- shared_buf_.reset(ChildThread::current()->AllocateSharedMemory(buf_size));
- if (!shared_buf_)
- return;
-
- // Copy the bits into shared memory
- DCHECK(shared_buf_->memory());
- memcpy(shared_buf_->memory(), pixels, buf_size);
- shared_buf_->Unmap();
-
- ui::Clipboard::ObjectMapParam size_param;
- const char* size_data = reinterpret_cast<const char*>(&size);
- for (size_t i = 0; i < sizeof(gfx::Size); ++i)
- size_param.push_back(size_data[i]);
-
- ui::Clipboard::ObjectMapParams params;
-
- // The first parameter is replaced on the receiving end with a pointer to
- // a shared memory object containing the bitmap. We reserve space for it here.
- ui::Clipboard::ObjectMapParam place_holder_param;
- params.push_back(place_holder_param);
- params.push_back(size_param);
- (*objects)[ui::Clipboard::CBF_SMBITMAP] = params;
-}
-
-// Flushes the objects to the clipboard with an IPC.
-void RendererClipboardWriteContext::Flush(
- const ui::Clipboard::ObjectMap& objects) {
- if (shared_buf_) {
- RenderThreadImpl::current()->Send(
- new ClipboardHostMsg_WriteObjectsSync(objects, shared_buf_->handle()));
- } else {
- RenderThreadImpl::current()->Send(
- new ClipboardHostMsg_WriteObjectsAsync(objects));
- }
-}
-
-} // anonymous namespace
-
-RendererClipboardClient::RendererClipboardClient() {
-}
-
-RendererClipboardClient::~RendererClipboardClient() {
-}
-
-ui::Clipboard* RendererClipboardClient::GetClipboard() {
- return NULL;
-}
-
-uint64 RendererClipboardClient::GetSequenceNumber(ui::ClipboardType type) {
- uint64 sequence_number = 0;
- RenderThreadImpl::current()->Send(
- new ClipboardHostMsg_GetSequenceNumber(type, &sequence_number));
- return sequence_number;
-}
-
-bool RendererClipboardClient::IsFormatAvailable(content::ClipboardFormat format,
- ui::ClipboardType type) {
- bool result = false;
- RenderThreadImpl::current()->Send(
- new ClipboardHostMsg_IsFormatAvailable(format, type, &result));
- return result;
-}
-
-void RendererClipboardClient::Clear(ui::ClipboardType type) {
- RenderThreadImpl::current()->Send(new ClipboardHostMsg_Clear(type));
-}
-
-void RendererClipboardClient::ReadAvailableTypes(
- ui::ClipboardType type,
- std::vector<base::string16>* types,
- bool* contains_filenames) {
- RenderThreadImpl::current()->Send(new ClipboardHostMsg_ReadAvailableTypes(
- type, types, contains_filenames));
-}
-
-void RendererClipboardClient::ReadText(ui::ClipboardType type,
- base::string16* result) {
- RenderThreadImpl::current()->Send(
- new ClipboardHostMsg_ReadText(type, result));
-}
-
-void RendererClipboardClient::ReadHTML(ui::ClipboardType type,
- base::string16* markup,
- GURL* url, uint32* fragment_start,
- uint32* fragment_end) {
- RenderThreadImpl::current()->Send(new ClipboardHostMsg_ReadHTML(
- type, markup, url, fragment_start, fragment_end));
-}
-
-void RendererClipboardClient::ReadRTF(ui::ClipboardType type,
- std::string* result) {
- RenderThreadImpl::current()->Send(new ClipboardHostMsg_ReadRTF(type, result));
-}
-
-void RendererClipboardClient::ReadImage(ui::ClipboardType type,
- std::string* data) {
- base::SharedMemoryHandle image_handle;
- uint32 image_size = 0;
- RenderThreadImpl::current()->Send(
- new ClipboardHostMsg_ReadImage(type, &image_handle, &image_size));
- if (base::SharedMemory::IsHandleValid(image_handle)) {
- base::SharedMemory buffer(image_handle, true);
- buffer.Map(image_size);
- data->append(static_cast<char*>(buffer.memory()), image_size);
- }
-}
-
-void RendererClipboardClient::ReadCustomData(ui::ClipboardType clipboard_type,
- const base::string16& type,
- base::string16* data) {
- RenderThreadImpl::current()->Send(
- new ClipboardHostMsg_ReadCustomData(clipboard_type, type, data));
-}
-
-ClipboardClient::WriteContext* RendererClipboardClient::CreateWriteContext() {
- return new RendererClipboardWriteContext;
-}
-
-} // namespace content
diff --git a/chromium/content/renderer/renderer_clipboard_client.h b/chromium/content/renderer/renderer_clipboard_client.h
deleted file mode 100644
index de9e9c14864..00000000000
--- a/chromium/content/renderer/renderer_clipboard_client.h
+++ /dev/null
@@ -1,43 +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_RENDERER_RENDERER_CLIPBOARD_CLIENT_H_
-#define CONTENT_RENDERER_RENDERER_CLIPBOARD_CLIENT_H_
-
-#include "base/compiler_specific.h"
-#include "content/renderer/clipboard_client.h"
-
-namespace content {
-
-// An implementation of ClipboardClient that gets and sends data over IPC.
-class RendererClipboardClient : public ClipboardClient {
- public:
- RendererClipboardClient();
- ~RendererClipboardClient() override;
-
- ui::Clipboard* GetClipboard() override;
- uint64 GetSequenceNumber(ui::ClipboardType type) override;
- bool IsFormatAvailable(ClipboardFormat format,
- ui::ClipboardType type) override;
- void Clear(ui::ClipboardType type) override;
- void ReadAvailableTypes(ui::ClipboardType type,
- std::vector<base::string16>* types,
- bool* contains_filenames) override;
- void ReadText(ui::ClipboardType type, base::string16* result) override;
- void ReadHTML(ui::ClipboardType type,
- base::string16* markup,
- GURL* url,
- uint32* fragment_start,
- uint32* fragment_end) override;
- void ReadRTF(ui::ClipboardType type, std::string* result) override;
- void ReadImage(ui::ClipboardType type, std::string* data) override;
- void ReadCustomData(ui::ClipboardType clipboard_type,
- const base::string16& type,
- base::string16* data) override;
- WriteContext* CreateWriteContext() override;
-};
-
-} // namespace content
-
-#endif // CONTENT_RENDERER_RENDERER_CLIPBOARD_CLIENT_H_
diff --git a/chromium/content/renderer/renderer_clipboard_delegate.cc b/chromium/content/renderer/renderer_clipboard_delegate.cc
new file mode 100644
index 00000000000..e1285d2c07b
--- /dev/null
+++ b/chromium/content/renderer/renderer_clipboard_delegate.cc
@@ -0,0 +1,167 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file provides the embedder's side of the Clipboard interface.
+
+#include "content/renderer/renderer_clipboard_delegate.h"
+
+#include "base/memory/shared_memory.h"
+#include "base/numerics/safe_math.h"
+#include "content/common/clipboard_messages.h"
+#include "content/public/renderer/content_renderer_client.h"
+#include "content/renderer/render_thread_impl.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/base/clipboard/clipboard.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace content {
+
+RendererClipboardDelegate::RendererClipboardDelegate() {
+}
+
+uint64 RendererClipboardDelegate::GetSequenceNumber(ui::ClipboardType type) {
+ uint64 sequence_number = 0;
+ RenderThreadImpl::current()->Send(
+ new ClipboardHostMsg_GetSequenceNumber(type, &sequence_number));
+ return sequence_number;
+}
+
+bool RendererClipboardDelegate::IsFormatAvailable(
+ content::ClipboardFormat format,
+ ui::ClipboardType type) {
+ bool result = false;
+ RenderThreadImpl::current()->Send(
+ new ClipboardHostMsg_IsFormatAvailable(format, type, &result));
+ return result;
+}
+
+void RendererClipboardDelegate::Clear(ui::ClipboardType type) {
+ RenderThreadImpl::current()->Send(new ClipboardHostMsg_Clear(type));
+}
+
+void RendererClipboardDelegate::ReadAvailableTypes(
+ ui::ClipboardType type,
+ std::vector<base::string16>* types,
+ bool* contains_filenames) {
+ RenderThreadImpl::current()->Send(
+ new ClipboardHostMsg_ReadAvailableTypes(type, types, contains_filenames));
+}
+
+void RendererClipboardDelegate::ReadText(ui::ClipboardType type,
+ base::string16* result) {
+ RenderThreadImpl::current()->Send(
+ new ClipboardHostMsg_ReadText(type, result));
+}
+
+void RendererClipboardDelegate::ReadHTML(ui::ClipboardType type,
+ base::string16* markup,
+ GURL* url,
+ uint32* fragment_start,
+ uint32* fragment_end) {
+ RenderThreadImpl::current()->Send(new ClipboardHostMsg_ReadHTML(
+ type, markup, url, fragment_start, fragment_end));
+}
+
+void RendererClipboardDelegate::ReadRTF(ui::ClipboardType type,
+ std::string* result) {
+ RenderThreadImpl::current()->Send(new ClipboardHostMsg_ReadRTF(type, result));
+}
+
+void RendererClipboardDelegate::ReadImage(ui::ClipboardType type,
+ std::string* data) {
+ base::SharedMemoryHandle image_handle;
+ uint32 image_size = 0;
+ RenderThreadImpl::current()->Send(
+ new ClipboardHostMsg_ReadImage(type, &image_handle, &image_size));
+ if (base::SharedMemory::IsHandleValid(image_handle)) {
+ base::SharedMemory buffer(image_handle, true);
+ buffer.Map(image_size);
+ data->append(static_cast<char*>(buffer.memory()), image_size);
+ }
+}
+
+void RendererClipboardDelegate::ReadCustomData(ui::ClipboardType clipboard_type,
+ const base::string16& type,
+ base::string16* data) {
+ RenderThreadImpl::current()->Send(
+ new ClipboardHostMsg_ReadCustomData(clipboard_type, type, data));
+}
+
+void RendererClipboardDelegate::WriteText(ui::ClipboardType clipboard_type,
+ const base::string16& text) {
+ RenderThreadImpl::current()->Send(
+ new ClipboardHostMsg_WriteText(clipboard_type, text));
+}
+
+void RendererClipboardDelegate::WriteHTML(ui::ClipboardType clipboard_type,
+ const base::string16& markup,
+ const GURL& url) {
+ RenderThreadImpl::current()->Send(
+ new ClipboardHostMsg_WriteHTML(clipboard_type, markup, url));
+}
+
+void RendererClipboardDelegate::WriteSmartPasteMarker(
+ ui::ClipboardType clipboard_type) {
+ RenderThreadImpl::current()->Send(
+ new ClipboardHostMsg_WriteSmartPasteMarker(clipboard_type));
+}
+
+void RendererClipboardDelegate::WriteCustomData(
+ ui::ClipboardType clipboard_type,
+ const std::map<base::string16, base::string16>& data) {
+ RenderThreadImpl::current()->Send(
+ new ClipboardHostMsg_WriteCustomData(clipboard_type, data));
+}
+
+void RendererClipboardDelegate::WriteBookmark(ui::ClipboardType clipboard_type,
+ const GURL& url,
+ const base::string16& title) {
+ RenderThreadImpl::current()->Send(
+ new ClipboardHostMsg_WriteBookmark(clipboard_type, url.spec(), title));
+}
+
+bool RendererClipboardDelegate::WriteImage(ui::ClipboardType clipboard_type,
+ const SkBitmap& bitmap) {
+ // Only 32-bit bitmaps are supported.
+ DCHECK_EQ(bitmap.colorType(), kN32_SkColorType);
+
+ const gfx::Size size(bitmap.width(), bitmap.height());
+ scoped_ptr<base::SharedMemory> shared_buf;
+ {
+ SkAutoLockPixels locked(bitmap);
+ void* pixels = bitmap.getPixels();
+ // TODO(piman): this should not be NULL, but it is. crbug.com/369621
+ if (!pixels)
+ return false;
+
+ base::CheckedNumeric<uint32> checked_buf_size = 4;
+ checked_buf_size *= size.width();
+ checked_buf_size *= size.height();
+ if (!checked_buf_size.IsValid())
+ return false;
+
+ // Allocate a shared memory buffer to hold the bitmap bits.
+ uint32 buf_size = checked_buf_size.ValueOrDie();
+ shared_buf = ChildThreadImpl::current()->AllocateSharedMemory(buf_size);
+ if (!shared_buf)
+ return false;
+ if (!shared_buf->Map(buf_size))
+ return false;
+ // Copy the bits into shared memory
+ DCHECK(shared_buf->memory());
+ memcpy(shared_buf->memory(), pixels, buf_size);
+ shared_buf->Unmap();
+ }
+
+ RenderThreadImpl::current()->Send(new ClipboardHostMsg_WriteImage(
+ clipboard_type, size, shared_buf->handle()));
+ return true;
+}
+
+void RendererClipboardDelegate::CommitWrite(ui::ClipboardType clipboard_type) {
+ RenderThreadImpl::current()->Send(
+ new ClipboardHostMsg_CommitWrite(clipboard_type));
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/renderer_clipboard_delegate.h b/chromium/content/renderer/renderer_clipboard_delegate.h
new file mode 100644
index 00000000000..ef8e034fce9
--- /dev/null
+++ b/chromium/content/renderer/renderer_clipboard_delegate.h
@@ -0,0 +1,66 @@
+// 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_RENDERER_RENDERER_CLIPBOARD_DELEGATE_H_
+#define CONTENT_RENDERER_RENDERER_CLIPBOARD_DELEGATE_H_
+
+#include <stdint.h>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "content/common/clipboard_format.h"
+#include "ui/base/clipboard/clipboard_types.h"
+
+class GURL;
+class SkBitmap;
+
+namespace content {
+
+// Renderer interface to read/write from the clipboard over IPC.
+class RendererClipboardDelegate {
+ public:
+ RendererClipboardDelegate();
+
+ uint64 GetSequenceNumber(ui::ClipboardType type);
+ bool IsFormatAvailable(ClipboardFormat format, ui::ClipboardType type);
+ void Clear(ui::ClipboardType type);
+ void ReadAvailableTypes(ui::ClipboardType type,
+ std::vector<base::string16>* types,
+ bool* contains_filenames);
+ void ReadText(ui::ClipboardType type, base::string16* result);
+ void ReadHTML(ui::ClipboardType type,
+ base::string16* markup,
+ GURL* url,
+ uint32* fragment_start,
+ uint32* fragment_end);
+ void ReadRTF(ui::ClipboardType type, std::string* result);
+ void ReadImage(ui::ClipboardType type, std::string* data);
+ void ReadCustomData(ui::ClipboardType clipboard_type,
+ const base::string16& type,
+ base::string16* data);
+
+ void WriteText(ui::ClipboardType type, const base::string16& text);
+ void WriteHTML(ui::ClipboardType type,
+ const base::string16& markup,
+ const GURL& url);
+ void WriteSmartPasteMarker(ui::ClipboardType type);
+ void WriteCustomData(ui::ClipboardType type,
+ const std::map<base::string16, base::string16>& data);
+ void WriteBookmark(ui::ClipboardType type,
+ const GURL& url,
+ const base::string16& title);
+ bool WriteImage(ui::ClipboardType type, const SkBitmap& bitmap);
+ void CommitWrite(ui::ClipboardType type);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RendererClipboardDelegate);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_RENDERER_CLIPBOARD_DELEGATE_H_
diff --git a/chromium/content/renderer/renderer_font_platform_win.cc b/chromium/content/renderer/renderer_font_platform_win.cc
deleted file mode 100644
index 380bbd44669..00000000000
--- a/chromium/content/renderer/renderer_font_platform_win.cc
+++ /dev/null
@@ -1,423 +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/renderer/renderer_font_platform_win.h"
-
-#include <dwrite.h>
-#include <string>
-#include <vector>
-#include <wrl/implements.h>
-#include <wrl/wrappers/corewrappers.h>
-
-#include "base/debug/alias.h"
-#include "base/debug/crash_logging.h"
-#include "base/files/file_enumerator.h"
-#include "base/files/file_path.h"
-#include "base/files/memory_mapped_file.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
-#include "base/metrics/histogram.h"
-#include "base/path_service.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/time/time.h"
-#include "base/win/iat_patch_function.h"
-#include "base/win/registry.h"
-#include "base/win/scoped_comptr.h"
-
-namespace {
-
-namespace mswr = Microsoft::WRL;
-namespace mswrw = Microsoft::WRL::Wrappers;
-
-static const char kFontKeyName[] = "font_key_name";
-
-class FontCollectionLoader
- : public mswr::RuntimeClass<mswr::RuntimeClassFlags<mswr::ClassicCom>,
- IDWriteFontCollectionLoader> {
- public:
- // IDWriteFontCollectionLoader methods.
- virtual HRESULT STDMETHODCALLTYPE
- CreateEnumeratorFromKey(IDWriteFactory* factory,
- void const* key,
- UINT32 key_size,
- IDWriteFontFileEnumerator** file_enumerator);
-
- static HRESULT Initialize(IDWriteFactory* factory);
-
- UINT32 GetFontMapSize();
-
- std::wstring GetFontNameFromKey(UINT32 idx);
-
- bool LoadFontListFromRegistry();
- bool LoadRestrictedFontList();
-
- FontCollectionLoader() {};
- virtual ~FontCollectionLoader() {};
-
- private:
- mswr::ComPtr<IDWriteFontFileLoader> file_loader_;
-
- std::vector<std::wstring> reg_fonts_;
-};
-
-mswr::ComPtr<FontCollectionLoader> g_font_loader;
-
-class FontFileStream
- : public mswr::RuntimeClass<mswr::RuntimeClassFlags<mswr::ClassicCom>,
- IDWriteFontFileStream> {
- public:
- // IDWriteFontFileStream methods.
- virtual HRESULT STDMETHODCALLTYPE
- ReadFileFragment(void const** fragment_start,
- UINT64 file_offset,
- UINT64 fragment_size,
- void** context) {
- if (!memory_.get() || !memory_->IsValid() ||
- file_offset >= memory_->length() ||
- (file_offset + fragment_size) > memory_->length())
- return E_FAIL;
-
- *fragment_start = static_cast<BYTE const*>(memory_->data()) +
- static_cast<size_t>(file_offset);
- *context = NULL;
- return S_OK;
- }
-
- virtual void STDMETHODCALLTYPE ReleaseFileFragment(void* context) {}
-
- virtual HRESULT STDMETHODCALLTYPE GetFileSize(UINT64* file_size) {
- if (!memory_.get() || !memory_->IsValid())
- return E_FAIL;
-
- *file_size = memory_->length();
- return S_OK;
- }
-
- virtual HRESULT STDMETHODCALLTYPE GetLastWriteTime(UINT64* last_write_time) {
- if (!memory_.get() || !memory_->IsValid())
- return E_FAIL;
-
- // According to MSDN article http://goo.gl/rrSYzi the "last modified time"
- // is used by DirectWrite font selection algorithms to determine whether
- // one font resource is more up to date than another one.
- // So by returning 0 we are assuming that it will treat all fonts to be
- // equally up to date.
- // TODO(shrikant): We should further investigate this.
- *last_write_time = 0;
- return S_OK;
- }
-
- FontFileStream::FontFileStream() : font_key_(0) {
- };
-
- HRESULT RuntimeClassInitialize(UINT32 font_key) {
- base::FilePath path;
- PathService::Get(base::DIR_WINDOWS_FONTS, &path);
- std::wstring font_key_name(g_font_loader->GetFontNameFromKey(font_key));
- path = path.Append(font_key_name.c_str());
- memory_.reset(new base::MemoryMappedFile());
-
- // Put some debug information on stack.
- WCHAR font_name[256];
- path.value().copy(font_name, arraysize(font_name));
- base::debug::Alias(font_name);
-
- if (!memory_->Initialize(path)) {
- memory_.reset();
- return E_FAIL;
- }
-
- font_key_ = font_key;
-
- base::debug::SetCrashKeyValue(kFontKeyName,
- base::WideToUTF8(font_key_name));
- return S_OK;
- }
-
- virtual ~FontFileStream() {}
-
- UINT32 font_key_;
- scoped_ptr<base::MemoryMappedFile> memory_;
-};
-
-class FontFileLoader
- : public mswr::RuntimeClass<mswr::RuntimeClassFlags<mswr::ClassicCom>,
- IDWriteFontFileLoader> {
- public:
- // IDWriteFontFileLoader methods.
- virtual HRESULT STDMETHODCALLTYPE
- CreateStreamFromKey(void const* ref_key,
- UINT32 ref_key_size,
- IDWriteFontFileStream** stream) {
- if (ref_key_size != sizeof(UINT32))
- return E_FAIL;
-
- UINT32 font_key = *static_cast<const UINT32*>(ref_key);
- mswr::ComPtr<FontFileStream> font_stream;
- HRESULT hr = mswr::MakeAndInitialize<FontFileStream>(&font_stream,
- font_key);
- if (SUCCEEDED(hr)) {
- *stream = font_stream.Detach();
- return S_OK;
- }
- return E_FAIL;
- }
-
- FontFileLoader() {}
- virtual ~FontFileLoader() {}
-};
-
-class FontFileEnumerator
- : public mswr::RuntimeClass<mswr::RuntimeClassFlags<mswr::ClassicCom>,
- IDWriteFontFileEnumerator> {
- public:
- // IDWriteFontFileEnumerator methods.
- virtual HRESULT STDMETHODCALLTYPE MoveNext(BOOL* has_current_file) {
- *has_current_file = FALSE;
-
- if (current_file_)
- current_file_.ReleaseAndGetAddressOf();
-
- if (font_idx_ < g_font_loader->GetFontMapSize()) {
- HRESULT hr =
- factory_->CreateCustomFontFileReference(&font_idx_,
- sizeof(UINT32),
- file_loader_.Get(),
- current_file_.GetAddressOf());
- DCHECK(SUCCEEDED(hr));
- *has_current_file = TRUE;
- font_idx_++;
- }
- return S_OK;
- }
-
- virtual HRESULT STDMETHODCALLTYPE
- GetCurrentFontFile(IDWriteFontFile** font_file) {
- if (!current_file_) {
- *font_file = NULL;
- return E_FAIL;
- }
-
- *font_file = current_file_.Detach();
- return S_OK;
- }
-
- FontFileEnumerator(const void* keys,
- UINT32 buffer_size,
- IDWriteFactory* factory,
- IDWriteFontFileLoader* file_loader)
- : factory_(factory), file_loader_(file_loader), font_idx_(0) {}
-
- virtual ~FontFileEnumerator() {}
-
- mswr::ComPtr<IDWriteFactory> factory_;
- mswr::ComPtr<IDWriteFontFile> current_file_;
- mswr::ComPtr<IDWriteFontFileLoader> file_loader_;
- UINT32 font_idx_;
-};
-
-// IDWriteFontCollectionLoader methods.
-HRESULT STDMETHODCALLTYPE FontCollectionLoader::CreateEnumeratorFromKey(
- IDWriteFactory* factory,
- void const* key,
- UINT32 key_size,
- IDWriteFontFileEnumerator** file_enumerator) {
- *file_enumerator = mswr::Make<FontFileEnumerator>(
- key, key_size, factory, file_loader_.Get()).Detach();
- return S_OK;
-}
-
-// static
-HRESULT FontCollectionLoader::Initialize(IDWriteFactory* factory) {
- DCHECK(g_font_loader == NULL);
-
- g_font_loader = mswr::Make<FontCollectionLoader>();
- if (!g_font_loader) {
- DCHECK(FALSE);
- return E_FAIL;
- }
-
- CHECK(g_font_loader->LoadFontListFromRegistry());
-
- g_font_loader->file_loader_ = mswr::Make<FontFileLoader>().Detach();
-
- factory->RegisterFontFileLoader(g_font_loader->file_loader_.Get());
- factory->RegisterFontCollectionLoader(g_font_loader.Get());
-
- return S_OK;
-}
-
-UINT32 FontCollectionLoader::GetFontMapSize() {
- return reg_fonts_.size();
-}
-
-std::wstring FontCollectionLoader::GetFontNameFromKey(UINT32 idx) {
- DCHECK(idx < reg_fonts_.size());
- return reg_fonts_[idx];
-}
-
-bool FontCollectionLoader::LoadFontListFromRegistry() {
- const wchar_t kFontsRegistry[] =
- L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts";
- CHECK(reg_fonts_.empty());
- base::win::RegKey regkey;
- if (regkey.Open(HKEY_LOCAL_MACHINE, kFontsRegistry, KEY_READ) !=
- ERROR_SUCCESS) {
- return false;
- }
-
- base::FilePath system_font_path;
- PathService::Get(base::DIR_WINDOWS_FONTS, &system_font_path);
-
- std::wstring name;
- std::wstring value;
- for (DWORD idx = 0; idx < regkey.GetValueCount(); idx++) {
- if (regkey.GetValueNameAt(idx, &name) == ERROR_SUCCESS &&
- regkey.ReadValue(name.c_str(), &value) == ERROR_SUCCESS) {
- base::FilePath path(value.c_str());
- // We need to check if file name is the only component that exists,
- // we will ignore all other registry entries.
- std::vector<base::FilePath::StringType> components;
- path.GetComponents(&components);
- if (components.size() == 1 ||
- base::FilePath::CompareEqualIgnoreCase(system_font_path.value(),
- path.DirName().value())) {
- reg_fonts_.push_back(path.BaseName().value());
- }
- }
- }
- UMA_HISTOGRAM_COUNTS("DirectWrite.Fonts.Loaded", reg_fonts_.size());
- UMA_HISTOGRAM_COUNTS("DirectWrite.Fonts.Ignored",
- regkey.GetValueCount() - reg_fonts_.size());
- return true;
-}
-
-// This list is mainly based on prefs/prefs_tab_helper.cc kFontDefaults.
-const wchar_t* kRestrictedFontSet[] = {
- // These are the "Web Safe" fonts.
- L"times.ttf", // IDS_STANDARD_FONT_FAMILY
- L"timesbd.ttf", // IDS_STANDARD_FONT_FAMILY
- L"timesbi.ttf", // IDS_STANDARD_FONT_FAMILY
- L"timesi.ttf", // IDS_STANDARD_FONT_FAMILY
- L"cour.ttf", // IDS_FIXED_FONT_FAMILY
- L"courbd.ttf", // IDS_FIXED_FONT_FAMILY
- L"courbi.ttf", // IDS_FIXED_FONT_FAMILY
- L"couri.ttf", // IDS_FIXED_FONT_FAMILY
- L"consola.ttf", // IDS_FIXED_FONT_FAMILY_ALT_WIN
- L"consolab.ttf", // IDS_FIXED_FONT_FAMILY_ALT_WIN
- L"consolai.ttf", // IDS_FIXED_FONT_FAMILY_ALT_WIN
- L"consolaz.ttf", // IDS_FIXED_FONT_FAMILY_ALT_WIN
- L"arial.ttf", // IDS_SANS_SERIF_FONT_FAMILY
- L"arialbd.ttf", // IDS_SANS_SERIF_FONT_FAMILY
- L"arialbi.ttf", // IDS_SANS_SERIF_FONT_FAMILY
- L"ariali.ttf", // IDS_SANS_SERIF_FONT_FAMILY
- L"comic.ttf", // IDS_CURSIVE_FONT_FAMILY
- L"comicbd.ttf", // IDS_CURSIVE_FONT_FAMILY
- L"comici.ttf", // IDS_CURSIVE_FONT_FAMILY
- L"comicz.ttf", // IDS_CURSIVE_FONT_FAMILY
- L"impact.ttf", // IDS_FANTASY_FONT_FAMILY
- L"georgia.ttf",
- L"georgiab.ttf",
- L"georgiai.ttf",
- L"georgiaz.ttf",
- L"trebuc.ttf",
- L"trebucbd.ttf",
- L"trebucbi.ttf",
- L"trebucit.ttf",
- L"verdana.ttf",
- L"verdanab.ttf",
- L"verdanai.ttf",
- L"verdanaz.ttf",
- L"segoeui.ttf", // IDS_PICTOGRAPH_FONT_FAMILY
- L"segoeuib.ttf", // IDS_PICTOGRAPH_FONT_FAMILY
- L"segoeuii.ttf", // IDS_PICTOGRAPH_FONT_FAMILY
- L"msgothic.ttc", // IDS_STANDARD_FONT_FAMILY_JAPANESE
- L"msmincho.ttc", // IDS_SERIF_FONT_FAMILY_JAPANESE
- L"gulim.ttc", // IDS_FIXED_FONT_FAMILY_KOREAN
- L"batang.ttc", // IDS_SERIF_FONT_FAMILY_KOREAN
- L"simsun.ttc", // IDS_STANDARD_FONT_FAMILY_SIMPLIFIED_HAN
- L"mingliu.ttc", // IDS_SERIF_FONT_FAMILY_TRADITIONAL_HAN
-
- // These are from the Blink fallback list.
- L"david.ttf", // USCRIPT_HEBREW
- L"davidbd.ttf", // USCRIPT_HEBREW
- L"euphemia.ttf", // USCRIPT_CANADIAN_ABORIGINAL
- L"gautami.ttf", // USCRIPT_TELUGU
- L"gautamib.ttf", // USCRIPT_TELUGU
- L"latha.ttf", // USCRIPT_TAMIL
- L"lathab.ttf", // USCRIPT_TAMIL
- L"mangal.ttf", // USCRIPT_DEVANAGARI
- L"mangalb.ttf", // USCRIPT_DEVANAGARI
- L"monbaiti.ttf", // USCRIPT_MONGOLIAN
- L"mvboli.ttf", // USCRIPT_THAANA
- L"plantc.ttf", // USCRIPT_CHEROKEE
- L"raavi.ttf", // USCRIPT_GURMUKHI
- L"raavib.ttf", // USCRIPT_GURMUKHI
- L"shruti.ttf", // USCRIPT_GUJARATI
- L"shrutib.ttf", // USCRIPT_GUJARATI
- L"sylfaen.ttf", // USCRIPT_GEORGIAN and USCRIPT_ARMENIAN
- L"tahoma.ttf", // USCRIPT_ARABIC,
- L"tahomabd.ttf", // USCRIPT_ARABIC,
- L"tunga.ttf", // USCRIPT_KANNADA
- L"tungab.ttf", // USCRIPT_KANNADA
- L"vrinda.ttf", // USCRIPT_BENGALI
- L"vrindab.ttf", // USCRIPT_BENGALI
-};
-
-bool FontCollectionLoader::LoadRestrictedFontList() {
- reg_fonts_.clear();
- reg_fonts_.assign(kRestrictedFontSet,
- kRestrictedFontSet + _countof(kRestrictedFontSet));
- return true;
-}
-
-} // namespace
-
-namespace content {
-
-mswr::ComPtr<IDWriteFontCollection> g_font_collection;
-
-IDWriteFontCollection* GetCustomFontCollection(IDWriteFactory* factory) {
- if (g_font_collection.Get() != NULL)
- return g_font_collection.Get();
-
- base::TimeTicks start_tick = base::TimeTicks::Now();
-
- FontCollectionLoader::Initialize(factory);
-
- // We try here to put arbitrary limit on max number of fonts that could
- // be loaded, otherwise we fallback to restricted set of fonts.
- const UINT32 kMaxFontThreshold = 1750;
- HRESULT hr = E_FAIL;
- if (g_font_loader->GetFontMapSize() < kMaxFontThreshold) {
- hr = factory->CreateCustomFontCollection(
- g_font_loader.Get(), NULL, 0, g_font_collection.GetAddressOf());
- }
-
- bool loadingRestricted = false;
- if (FAILED(hr) || !g_font_collection.Get()) {
- // We will try here just one more time with restricted font set.
- g_font_loader->LoadRestrictedFontList();
- hr = factory->CreateCustomFontCollection(
- g_font_loader.Get(), NULL, 0, g_font_collection.GetAddressOf());
- }
-
- base::TimeDelta time_delta = base::TimeTicks::Now() - start_tick;
- int64 delta = time_delta.ToInternalValue();
- base::debug::Alias(&delta);
- UINT32 size = g_font_loader->GetFontMapSize();
- base::debug::Alias(&size);
- base::debug::Alias(&loadingRestricted);
-
- CHECK(SUCCEEDED(hr));
- CHECK(g_font_collection.Get() != NULL);
-
- UMA_HISTOGRAM_TIMES("DirectWrite.Fonts.LoadTime", time_delta);
-
- base::debug::ClearCrashKey(kFontKeyName);
-
- return g_font_collection.Get();
-}
-
-} // namespace content
diff --git a/chromium/content/renderer/renderer_font_platform_win.h b/chromium/content/renderer/renderer_font_platform_win.h
deleted file mode 100644
index a04901b73d2..00000000000
--- a/chromium/content/renderer/renderer_font_platform_win.h
+++ /dev/null
@@ -1,17 +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_RENDERER_RENDERER_FONT_PLATFORM_WIN_H_
-#define CHROME_RENDERER_RENDERER_FONT_PLATFORM_WIN_H_
-
-struct IDWriteFactory;
-struct IDWriteFontCollection;
-
-namespace content {
-
-IDWriteFontCollection* GetCustomFontCollection(IDWriteFactory* factory);
-
-} // namespace content
-
-#endif // CHROME_RENDERER_RENDERER_FONT_PLATFORM_WIN_H_
diff --git a/chromium/content/renderer/renderer_main.cc b/chromium/content/renderer/renderer_main.cc
index e82712cf7e0..a76df805790 100644
--- a/chromium/content/renderer/renderer_main.cc
+++ b/chromium/content/renderer/renderer_main.cc
@@ -5,21 +5,21 @@
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/debug/debugger.h"
+#include "base/debug/leak_annotations.h"
#include "base/debug/stack_trace.h"
-#include "base/debug/trace_event.h"
#include "base/i18n/rtl.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
#include "base/metrics/statistics_recorder.h"
-#include "base/metrics/stats_counters.h"
#include "base/pending_task.h"
#include "base/strings/string_util.h"
#include "base/sys_info.h"
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
#include "base/timer/hi_res_timer_manager.h"
+#include "base/trace_event/trace_event.h"
#include "content/child/child_process.h"
#include "content/common/content_constants_internal.h"
#include "content/public/common/content_switches.h"
@@ -40,7 +40,6 @@
#include <signal.h>
#include <unistd.h>
-#include "base/mac/mac_util.h"
#include "base/mac/scoped_nsautorelease_pool.h"
#include "base/message_loop/message_pump_mac.h"
#include "third_party/WebKit/public/web/WebView.h"
@@ -58,17 +57,13 @@ namespace content {
namespace {
// This function provides some ways to test crash and assertion handling
// behavior of the renderer.
-static void HandleRendererErrorTestParameters(const CommandLine& command_line) {
+static void HandleRendererErrorTestParameters(
+ const base::CommandLine& command_line) {
if (command_line.HasSwitch(switches::kWaitForDebugger))
base::debug::WaitForDebugger(60, true);
if (command_line.HasSwitch(switches::kRendererStartupDialog))
ChildProcess::WaitForDebugger("Renderer");
-
- // This parameter causes an assertion.
- if (command_line.HasSwitch(switches::kRendererAssertTest)) {
- DCHECK(false);
- }
}
// This is a simplified version of the browser Jankometer, which measures
@@ -101,11 +96,11 @@ class RendererMessageLoopObserver : public base::MessageLoop::TaskObserver {
// mainline routine for running as the Renderer process
int RendererMain(const MainFunctionParams& parameters) {
TRACE_EVENT_BEGIN_ETW("RendererMain", 0, "");
- base::debug::TraceLog::GetInstance()->SetProcessName("Renderer");
- base::debug::TraceLog::GetInstance()->SetProcessSortIndex(
+ base::trace_event::TraceLog::GetInstance()->SetProcessName("Renderer");
+ base::trace_event::TraceLog::GetInstance()->SetProcessSortIndex(
kTraceEventRendererProcessSortIndex);
- const CommandLine& parsed_command_line = parameters.command_line;
+ const base::CommandLine& parsed_command_line = parameters.command_line;
#if defined(OS_MACOSX)
base::mac::ScopedNSAutoreleasePool* pool = parameters.autorelease_pool;
@@ -137,23 +132,19 @@ int RendererMain(const MainFunctionParams& parameters) {
HandleRendererErrorTestParameters(parsed_command_line);
RendererMainPlatformDelegate platform(parameters);
-
-
- base::StatsCounterTimer stats_counter_timer("Content.RendererInit");
- base::StatsScope<base::StatsCounterTimer> startup_timer(stats_counter_timer);
-
RendererMessageLoopObserver task_observer;
#if defined(OS_MACOSX)
// As long as scrollbars on Mac are painted with Cocoa, the message pump
// needs to be backed by a Foundation-level loop to process NSTimers. See
// http://crbug.com/306348#c24 for details.
scoped_ptr<base::MessagePump> pump(new base::MessagePumpNSRunLoop());
- base::MessageLoop main_message_loop(pump.Pass());
+ scoped_ptr<base::MessageLoop> main_message_loop(
+ new base::MessageLoop(pump.Pass()));
#else
// The main message loop of the renderer services doesn't have IO or UI tasks.
- base::MessageLoop main_message_loop;
+ scoped_ptr<base::MessageLoop> main_message_loop(new base::MessageLoop());
#endif
- main_message_loop.AddTaskObserver(&task_observer);
+ main_message_loop->AddTaskObserver(&task_observer);
base::PlatformThread::SetName("CrRendererMain");
@@ -173,11 +164,9 @@ int RendererMain(const MainFunctionParams& parameters) {
base::FieldTrialList field_trial_list(NULL);
// Ensure any field trials in browser are reflected into renderer.
if (parsed_command_line.HasSwitch(switches::kForceFieldTrials)) {
- // Field trials are created in an "activated" state to ensure they get
- // reported in crash reports.
bool result = base::FieldTrialList::CreateTrialsFromString(
parsed_command_line.GetSwitchValueASCII(switches::kForceFieldTrials),
- base::FieldTrialList::ACTIVATE_TRIALS,
+ base::FieldTrialList::DONT_ACTIVATE_TRIALS,
std::set<std::string>());
DCHECK(result);
}
@@ -202,7 +191,7 @@ int RendererMain(const MainFunctionParams& parameters) {
// TODO(markus): Check if it is OK to unconditionally move this
// instruction down.
RenderProcessImpl render_process;
- new RenderThreadImpl();
+ new RenderThreadImpl(main_message_loop.Pass());
#endif
bool run_loop = true;
if (!no_sandbox) {
@@ -218,13 +207,10 @@ int RendererMain(const MainFunctionParams& parameters) {
}
#if defined(OS_POSIX) && !defined(OS_MACOSX)
RenderProcessImpl render_process;
- new RenderThreadImpl();
+ new RenderThreadImpl(main_message_loop.Pass());
#endif
-
base::HighResolutionTimerManager hi_res_timer_manager;
- startup_timer.Stop(); // End of Startup Time Measurement.
-
if (run_loop) {
#if defined(OS_MACOSX)
if (pool)
@@ -234,6 +220,11 @@ int RendererMain(const MainFunctionParams& parameters) {
base::MessageLoop::current()->Run();
TRACE_EVENT_END_ETW("RendererMain.START_MSG_LOOP", 0, 0);
}
+#if defined(LEAK_SANITIZER)
+ // Run leak detection before RenderProcessImpl goes out of scope. This helps
+ // ignore shutdown-only leaks.
+ __lsan_do_leak_check();
+#endif
}
platform.PlatformUninitialize();
TRACE_EVENT_END_ETW("RendererMain", 0, "");
diff --git a/chromium/content/renderer/renderer_main_platform_delegate.h b/chromium/content/renderer/renderer_main_platform_delegate.h
index 8d2f8ed96ba..f51644a78fa 100644
--- a/chromium/content/renderer/renderer_main_platform_delegate.h
+++ b/chromium/content/renderer/renderer_main_platform_delegate.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 CHROME_RENDERER_RENDERER_MAIN_PLATFORM_DELEGATE_H_
-#define CHROME_RENDERER_RENDERER_MAIN_PLATFORM_DELEGATE_H_
+#ifndef CONTENT_RENDERER_RENDERER_MAIN_PLATFORM_DELEGATE_H_
+#define CONTENT_RENDERER_RENDERER_MAIN_PLATFORM_DELEGATE_H_
#include "build/build_config.h"
@@ -50,4 +50,4 @@ class CONTENT_EXPORT RendererMainPlatformDelegate {
} // namespace content
-#endif // CHROME_RENDERER_RENDERER_MAIN_PLATFORM_DELEGATE_H_
+#endif // CONTENT_RENDERER_RENDERER_MAIN_PLATFORM_DELEGATE_H_
diff --git a/chromium/content/renderer/renderer_main_platform_delegate_android.cc b/chromium/content/renderer/renderer_main_platform_delegate_android.cc
index ab006bea1df..8ef130375a7 100644
--- a/chromium/content/renderer/renderer_main_platform_delegate_android.cc
+++ b/chromium/content/renderer/renderer_main_platform_delegate_android.cc
@@ -13,10 +13,6 @@
#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
#endif
-#ifdef ENABLE_VTUNE_JIT_INTERFACE
-#include "v8/src/third_party/vtune/v8-vtune.h"
-#endif
-
namespace content {
RendererMainPlatformDelegate::RendererMainPlatformDelegate(
@@ -28,11 +24,6 @@ RendererMainPlatformDelegate::~RendererMainPlatformDelegate() {
}
void RendererMainPlatformDelegate::PlatformInitialize() {
-#ifdef ENABLE_VTUNE_JIT_INTERFACE
- const CommandLine& command_line = parameters_.command_line;
- if (command_line.HasSwitch(switches::kEnableVtune))
- vTune::InitializeVtuneForV8();
-#endif
}
void RendererMainPlatformDelegate::PlatformUninitialize() {
@@ -44,10 +35,16 @@ bool RendererMainPlatformDelegate::EnableSandbox() {
switches::kEnableSeccompFilterSandbox)) {
return true;
}
+ if (!sandbox::SandboxBPF::SupportsSeccompSandbox(
+ sandbox::SandboxBPF::SeccompLevel::MULTI_THREADED)) {
+ LOG(WARNING) << "Seccomp-BPF sandbox enabled without kernel support. "
+ << "Ignoring flag and proceeding without seccomp sandbox.";
+ return true;
+ }
- sandbox::SandboxBPF sandbox;
- sandbox.SetSandboxPolicy(new SandboxBPFBasePolicyAndroid());
- CHECK(sandbox.StartSandbox(sandbox::SandboxBPF::PROCESS_MULTI_THREADED));
+ sandbox::SandboxBPF sandbox(new SandboxBPFBasePolicyAndroid());
+ CHECK(
+ sandbox.StartSandbox(sandbox::SandboxBPF::SeccompLevel::MULTI_THREADED));
#endif
return true;
}
diff --git a/chromium/content/renderer/renderer_main_platform_delegate_linux.cc b/chromium/content/renderer/renderer_main_platform_delegate_linux.cc
index 54c68517664..21dd251027a 100644
--- a/chromium/content/renderer/renderer_main_platform_delegate_linux.cc
+++ b/chromium/content/renderer/renderer_main_platform_delegate_linux.cc
@@ -14,10 +14,6 @@
#include "content/public/common/content_switches.h"
#include "content/public/common/sandbox_init.h"
-#ifdef ENABLE_VTUNE_JIT_INTERFACE
-#include "v8/src/third_party/vtune/v8-vtune.h"
-#endif
-
namespace content {
RendererMainPlatformDelegate::RendererMainPlatformDelegate(
@@ -29,11 +25,6 @@ RendererMainPlatformDelegate::~RendererMainPlatformDelegate() {
}
void RendererMainPlatformDelegate::PlatformInitialize() {
-#ifdef ENABLE_VTUNE_JIT_INTERFACE
- const CommandLine& command_line = parameters_.command_line;
- if (command_line.HasSwitch(switches::kEnableVtune))
- vTune::InitializeVtuneForV8();
-#endif
}
void RendererMainPlatformDelegate::PlatformUninitialize() {
diff --git a/chromium/content/renderer/renderer_main_platform_delegate_win.cc b/chromium/content/renderer/renderer_main_platform_delegate_win.cc
index 952d00d3df7..6fa56ebef6c 100644
--- a/chromium/content/renderer/renderer_main_platform_delegate_win.cc
+++ b/chromium/content/renderer/renderer_main_platform_delegate_win.cc
@@ -18,19 +18,15 @@
#include "content/renderer/render_thread_impl.h"
#include "sandbox/win/src/sandbox.h"
#include "skia/ext/fontmgr_default_win.h"
-#include "skia/ext/vector_platform_device_emf_win.h"
#include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
#include "third_party/WebKit/public/web/win/WebFontRendering.h"
#include "third_party/icu/source/i18n/unicode/timezone.h"
#include "third_party/skia/include/ports/SkFontMgr.h"
#include "third_party/skia/include/ports/SkTypeface_win.h"
+#include "ui/gfx/hud_font.h"
#include "ui/gfx/win/direct_write.h"
#include "ui/gfx/win/dpi.h"
-#ifdef ENABLE_VTUNE_JIT_INTERFACE
-#include "v8/src/third_party/vtune/v8-vtune.h"
-#endif
-
#include <dwrite.h>
namespace content {
@@ -59,10 +55,16 @@ void SkiaPreCacheFontCharacters(const LOGFONT& logfont,
void WarmupDirectWrite() {
// The objects used here are intentionally not freed as we want the Skia
// code to use these objects after warmup.
- SkTypeface* typeface =
- GetPreSandboxWarmupFontMgr()->legacyCreateTypeface("Times New Roman", 0);
- DoPreSandboxWarmupForTypeface(typeface);
SetDefaultSkiaFactory(GetPreSandboxWarmupFontMgr());
+
+ // We need to warm up *some* font for DirectWrite. We also need to pass one
+ // down for the CC HUD code, so use the same one here. Note that we don't use
+ // a monospace as would be nice in an attempt to avoid a small startup time
+ // regression, see http://crbug.com/463613.
+ skia::RefPtr<SkTypeface> hud_typeface = skia::AdoptRef(
+ GetPreSandboxWarmupFontMgr()->legacyCreateTypeface("Times New Roman", 0));
+ DoPreSandboxWarmupForTypeface(hud_typeface.get());
+ gfx::SetHudTypeface(hud_typeface);
}
} // namespace
@@ -77,12 +79,7 @@ RendererMainPlatformDelegate::~RendererMainPlatformDelegate() {
}
void RendererMainPlatformDelegate::PlatformInitialize() {
- const CommandLine& command_line = parameters_.command_line;
-
-#ifdef ENABLE_VTUNE_JIT_INTERFACE
- if (command_line.HasSwitch(switches::kEnableVtune))
- vTune::InitializeVtuneForV8();
-#endif
+ const base::CommandLine& command_line = parameters_.command_line;
// Be mindful of what resources you acquire here. They can be used by
// malicious code if the renderer gets compromised.
@@ -102,15 +99,10 @@ void RendererMainPlatformDelegate::PlatformInitialize() {
WarmupDirectWrite();
} else {
SkTypeface_SetEnsureLOGFONTAccessibleProc(SkiaPreCacheFont);
- skia::SetSkiaEnsureTypefaceCharactersAccessible(
- SkiaPreCacheFontCharacters);
}
}
blink::WebFontRendering::setUseDirectWrite(use_direct_write);
blink::WebFontRendering::setDeviceScaleFactor(gfx::GetDPIScale());
- if (use_direct_write) {
- blink::WebRuntimeFeatures::enableSubpixelFontScaling(true);
- }
}
void RendererMainPlatformDelegate::PlatformUninitialize() {
@@ -128,6 +120,13 @@ bool RendererMainPlatformDelegate::EnableSandbox() {
::GetUserDefaultLangID();
::GetUserDefaultLCID();
+#if defined(ADDRESS_SANITIZER)
+ // Bind and leak dbghelp.dll before the token is lowered, otherwise
+ // AddressSanitizer will crash when trying to symbolize a report.
+ if (!LoadLibraryA("dbghelp.dll"))
+ return false;
+#endif
+
target_services->LowerToken();
return true;
}
diff --git a/chromium/content/renderer/renderer_webcookiejar_impl.cc b/chromium/content/renderer/renderer_webcookiejar_impl.cc
index f1d9a587e14..f33d21b14ab 100644
--- a/chromium/content/renderer/renderer_webcookiejar_impl.cc
+++ b/chromium/content/renderer/renderer_webcookiejar_impl.cc
@@ -5,16 +5,12 @@
#include "content/renderer/renderer_webcookiejar_impl.h"
#include "base/strings/utf_string_conversions.h"
-#include "content/common/cookie_data.h"
-#include "content/common/view_messages.h"
+#include "content/common/frame_messages.h"
#include "content/public/renderer/content_renderer_client.h"
-#include "content/renderer/render_view_impl.h"
-#include "third_party/WebKit/public/platform/WebCookie.h"
+#include "content/renderer/render_frame_impl.h"
-using blink::WebCookie;
using blink::WebString;
using blink::WebURL;
-using blink::WebVector;
namespace content {
@@ -22,14 +18,14 @@ void RendererWebCookieJarImpl::setCookie(
const WebURL& url, const WebURL& first_party_for_cookies,
const WebString& value) {
std::string value_utf8 = base::UTF16ToUTF8(value);
- sender_->Send(new ViewHostMsg_SetCookie(
+ sender_->Send(new FrameHostMsg_SetCookie(
sender_->GetRoutingID(), url, first_party_for_cookies, value_utf8));
}
WebString RendererWebCookieJarImpl::cookies(
const WebURL& url, const WebURL& first_party_for_cookies) {
std::string value_utf8;
- sender_->Send(new ViewHostMsg_GetCookies(
+ sender_->Send(new FrameHostMsg_GetCookies(
sender_->GetRoutingID(), url, first_party_for_cookies, &value_utf8));
return WebString::fromUTF8(value_utf8);
}
@@ -39,38 +35,10 @@ WebString RendererWebCookieJarImpl::cookieRequestHeaderFieldValue(
return cookies(url, first_party_for_cookies);
}
-void RendererWebCookieJarImpl::rawCookies(
- const WebURL& url, const WebURL& first_party_for_cookies,
- WebVector<WebCookie>& raw_cookies) {
- std::vector<CookieData> cookies;
- sender_->Send(new ViewHostMsg_GetRawCookies(
- url, first_party_for_cookies, &cookies));
-
- WebVector<WebCookie> result(cookies.size());
- for (size_t i = 0; i < cookies.size(); ++i) {
- const CookieData& c = cookies[i];
- result[i] = WebCookie(WebString::fromUTF8(c.name),
- WebString::fromUTF8(c.value),
- WebString::fromUTF8(c.domain),
- WebString::fromUTF8(c.path),
- c.expires,
- c.http_only,
- c.secure,
- c.session);
- }
- raw_cookies.swap(result);
-}
-
-void RendererWebCookieJarImpl::deleteCookie(
- const WebURL& url, const WebString& cookie_name) {
- std::string cookie_name_utf8 = base::UTF16ToUTF8(cookie_name);
- sender_->Send(new ViewHostMsg_DeleteCookie(url, cookie_name_utf8));
-}
-
bool RendererWebCookieJarImpl::cookiesEnabled(
const WebURL& url, const WebURL& first_party_for_cookies) {
bool cookies_enabled = false;
- sender_->Send(new ViewHostMsg_CookiesEnabled(
+ sender_->Send(new FrameHostMsg_CookiesEnabled(
sender_->GetRoutingID(), url, first_party_for_cookies, &cookies_enabled));
return cookies_enabled;
}
diff --git a/chromium/content/renderer/renderer_webcookiejar_impl.h b/chromium/content/renderer/renderer_webcookiejar_impl.h
index ad911f20f86..efcee0382af 100644
--- a/chromium/content/renderer/renderer_webcookiejar_impl.h
+++ b/chromium/content/renderer/renderer_webcookiejar_impl.h
@@ -27,11 +27,6 @@ class RendererWebCookieJarImpl : public blink::WebCookieJar {
const blink::WebURL& url, const blink::WebURL& first_party_for_cookies);
virtual blink::WebString cookieRequestHeaderFieldValue(
const blink::WebURL& url, const blink::WebURL& first_party_for_cookies);
- virtual void rawCookies(
- const blink::WebURL& url, const blink::WebURL& first_party_for_cookies,
- blink::WebVector<blink::WebCookie>& cookies);
- virtual void deleteCookie(
- const blink::WebURL& url, const blink::WebString& cookie_name);
virtual bool cookiesEnabled(
const blink::WebURL& url, const blink::WebURL& first_party_for_cookies);
diff --git a/chromium/content/renderer/resizing_mode_selector.cc b/chromium/content/renderer/resizing_mode_selector.cc
index d51b4570627..58b4af1c02a 100644
--- a/chromium/content/renderer/resizing_mode_selector.cc
+++ b/chromium/content/renderer/resizing_mode_selector.cc
@@ -22,7 +22,8 @@ bool ResizingModeSelector::ShouldAbortOnResize(
RenderWidget* widget,
const ViewMsg_Resize_Params& params) {
return is_synchronous_mode_ &&
- params.is_fullscreen == widget->is_fullscreen() &&
+ params.is_fullscreen_granted == widget->is_fullscreen_granted() &&
+ params.display_mode == widget->display_mode() &&
params.screen_info.deviceScaleFactor ==
widget->screenInfo().deviceScaleFactor;
}
diff --git a/chromium/content/renderer/resource_fetcher_browsertest.cc b/chromium/content/renderer/resource_fetcher_browsertest.cc
index c016754ef3f..92a57a63680 100644
--- a/chromium/content/renderer/resource_fetcher_browsertest.cc
+++ b/chromium/content/renderer/resource_fetcher_browsertest.cc
@@ -131,7 +131,7 @@ class EvilFetcherDelegate : public FetcherDelegate {
class ResourceFetcherTests : public ContentBrowserTest {
public:
- void SetUpCommandLine(CommandLine* command_line) override {
+ void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitch(switches::kSingleProcess);
#if defined(OS_WIN)
// Don't want to try to create a GPU process.
@@ -286,28 +286,9 @@ class ResourceFetcherTests : public ContentBrowserTest {
}
};
-#if defined(OS_ANDROID)
-// Disable (http://crbug.com/248796).
-#define MAYBE_ResourceFetcher404 DISABLED_ResourceFetcher404
-#define MAYBE_ResourceFetcherDeletedInCallback \
- DISABLED_ResourceFetcherDeletedInCallback
-#define MAYBE_ResourceFetcherTimeout DISABLED_ResourceFetcherTimeout
-#define MAYBE_ResourceFetcherDownload DISABLED_ResourceFetcherDownload
-// Disable (http://crbug.com/341142).
-#define MAYBE_ResourceFetcherPost DISABLED_ResourceFetcherPost
-#define MAYBE_ResourceFetcherSetHeader DISABLED_ResourceFetcherSetHeader
-#else
-#define MAYBE_ResourceFetcher404 ResourceFetcher404
-#define MAYBE_ResourceFetcherDeletedInCallback ResourceFetcherDeletedInCallback
-#define MAYBE_ResourceFetcherTimeout ResourceFetcherTimeout
-#define MAYBE_ResourceFetcherDownload ResourceFetcherDownload
-#define MAYBE_ResourceFetcherPost ResourceFetcherPost
-#define MAYBE_ResourceFetcherSetHeader ResourceFetcherSetHeader
-#endif
-
// Test a fetch from the test server.
// If this flakes, use http://crbug.com/51622.
-IN_PROC_BROWSER_TEST_F(ResourceFetcherTests, MAYBE_ResourceFetcherDownload) {
+IN_PROC_BROWSER_TEST_F(ResourceFetcherTests, ResourceFetcherDownload) {
// Need to spin up the renderer.
NavigateToURL(shell(), GURL(url::kAboutBlankURL));
@@ -319,7 +300,7 @@ IN_PROC_BROWSER_TEST_F(ResourceFetcherTests, MAYBE_ResourceFetcherDownload) {
base::Unretained(this), url));
}
-IN_PROC_BROWSER_TEST_F(ResourceFetcherTests, MAYBE_ResourceFetcher404) {
+IN_PROC_BROWSER_TEST_F(ResourceFetcherTests, ResourceFetcher404) {
// Need to spin up the renderer.
NavigateToURL(shell(), GURL(url::kAboutBlankURL));
@@ -342,7 +323,7 @@ IN_PROC_BROWSER_TEST_F(ResourceFetcherTests, ResourceFetcherDidFail) {
base::Unretained(this)));
}
-IN_PROC_BROWSER_TEST_F(ResourceFetcherTests, MAYBE_ResourceFetcherTimeout) {
+IN_PROC_BROWSER_TEST_F(ResourceFetcherTests, ResourceFetcherTimeout) {
// Need to spin up the renderer.
NavigateToURL(shell(), GURL(url::kAboutBlankURL));
@@ -356,8 +337,7 @@ IN_PROC_BROWSER_TEST_F(ResourceFetcherTests, MAYBE_ResourceFetcherTimeout) {
base::Unretained(this), url));
}
-IN_PROC_BROWSER_TEST_F(ResourceFetcherTests,
- MAYBE_ResourceFetcherDeletedInCallback) {
+IN_PROC_BROWSER_TEST_F(ResourceFetcherTests, ResourceFetcherDeletedInCallback) {
// Need to spin up the renderer.
NavigateToURL(shell(), GURL(url::kAboutBlankURL));
@@ -375,7 +355,7 @@ IN_PROC_BROWSER_TEST_F(ResourceFetcherTests,
// Test that ResourceFetchers can handle POSTs.
-IN_PROC_BROWSER_TEST_F(ResourceFetcherTests, MAYBE_ResourceFetcherPost) {
+IN_PROC_BROWSER_TEST_F(ResourceFetcherTests, ResourceFetcherPost) {
// Need to spin up the renderer.
NavigateToURL(shell(), GURL(url::kAboutBlankURL));
@@ -390,7 +370,7 @@ IN_PROC_BROWSER_TEST_F(ResourceFetcherTests, MAYBE_ResourceFetcherPost) {
}
// Test that ResourceFetchers can set headers.
-IN_PROC_BROWSER_TEST_F(ResourceFetcherTests, MAYBE_ResourceFetcherSetHeader) {
+IN_PROC_BROWSER_TEST_F(ResourceFetcherTests, ResourceFetcherSetHeader) {
// Need to spin up the renderer.
NavigateToURL(shell(), GURL(url::kAboutBlankURL));
diff --git a/chromium/content/renderer/sad_plugin.cc b/chromium/content/renderer/sad_plugin.cc
index 52d613d5d4f..5f1c712cba2 100644
--- a/chromium/content/renderer/sad_plugin.cc
+++ b/chromium/content/renderer/sad_plugin.cc
@@ -9,7 +9,7 @@
#include "base/memory/scoped_ptr.h"
#include "skia/ext/platform_canvas.h"
#include "ui/gfx/blit.h"
-#include "ui/gfx/rect.h"
+#include "ui/gfx/geometry/rect.h"
namespace content {
diff --git a/chromium/content/renderer/savable_resources_browsertest.cc b/chromium/content/renderer/savable_resources_browsertest.cc
index e63a3904c51..0a8dab7751d 100644
--- a/chromium/content/renderer/savable_resources_browsertest.cc
+++ b/chromium/content/renderer/savable_resources_browsertest.cc
@@ -18,7 +18,7 @@ namespace content {
class SavableResourcesTest : public ContentBrowserTest {
public:
- void SetUpCommandLine(CommandLine* command_line) override {
+ void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitch(switches::kSingleProcess);
#if defined(OS_WIN)
// Don't want to try to create a GPU process.
diff --git a/chromium/content/renderer/scheduler/OWNERS b/chromium/content/renderer/scheduler/OWNERS
new file mode 100644
index 00000000000..6dc4cb43ab1
--- /dev/null
+++ b/chromium/content/renderer/scheduler/OWNERS
@@ -0,0 +1,3 @@
+alexclarke@chromium.org
+rmcilroy@chromium.org
+skyostil@chromium.org
diff --git a/chromium/content/renderer/scheduler/null_renderer_scheduler.cc b/chromium/content/renderer/scheduler/null_renderer_scheduler.cc
deleted file mode 100644
index af9379973ac..00000000000
--- a/chromium/content/renderer/scheduler/null_renderer_scheduler.cc
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/renderer/scheduler/null_renderer_scheduler.h"
-
-#include "base/bind.h"
-#include "base/message_loop/message_loop_proxy.h"
-
-namespace content {
-
-namespace {
-
-class NullIdleTaskRunner : public SingleThreadIdleTaskRunner {
- public:
- NullIdleTaskRunner(scoped_refptr<base::SingleThreadTaskRunner> task_runner);
- void PostIdleTask(const tracked_objects::Location& from_here,
- const IdleTask& idle_task) override;
-
- protected:
- ~NullIdleTaskRunner() override;
-};
-
-} // namespace
-
-NullIdleTaskRunner::NullIdleTaskRunner(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner)
- : SingleThreadIdleTaskRunner(task_runner,
- base::Callback<void(base::TimeTicks*)>()) {
-}
-
-NullIdleTaskRunner::~NullIdleTaskRunner() {
-}
-
-void NullIdleTaskRunner::PostIdleTask(
- const tracked_objects::Location& from_here,
- const IdleTask& idle_task) {
-}
-
-NullRendererScheduler::NullRendererScheduler()
- : task_runner_(base::MessageLoopProxy::current()),
- idle_task_runner_(new NullIdleTaskRunner(task_runner_)) {
-}
-
-NullRendererScheduler::~NullRendererScheduler() {
-}
-
-scoped_refptr<base::SingleThreadTaskRunner>
-NullRendererScheduler::DefaultTaskRunner() {
- return task_runner_;
-}
-
-scoped_refptr<base::SingleThreadTaskRunner>
-NullRendererScheduler::CompositorTaskRunner() {
- return task_runner_;
-}
-
-scoped_refptr<SingleThreadIdleTaskRunner>
-NullRendererScheduler::IdleTaskRunner() {
- return idle_task_runner_;
-}
-
-void NullRendererScheduler::WillBeginFrame(const cc::BeginFrameArgs& args) {
-}
-
-void NullRendererScheduler::DidCommitFrameToCompositor() {
-}
-
-void NullRendererScheduler::DidReceiveInputEventOnCompositorThread() {
-}
-
-bool NullRendererScheduler::ShouldYieldForHighPriorityWork() {
- return false;
-}
-
-void NullRendererScheduler::Shutdown() {
-}
-
-} // namespace content
diff --git a/chromium/content/renderer/scheduler/null_renderer_scheduler.h b/chromium/content/renderer/scheduler/null_renderer_scheduler.h
deleted file mode 100644
index c5bdb14e558..00000000000
--- a/chromium/content/renderer/scheduler/null_renderer_scheduler.h
+++ /dev/null
@@ -1,36 +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_RENDERER_SCHEDULER_NULL_RENDERER_SCHEDULER_H_
-#define CONTENT_RENDERER_SCHEDULER_NULL_RENDERER_SCHEDULER_H_
-
-#include "content/renderer/scheduler/renderer_scheduler.h"
-
-namespace content {
-
-class NullRendererScheduler : public RendererScheduler {
- public:
- NullRendererScheduler();
- ~NullRendererScheduler() override;
-
- scoped_refptr<base::SingleThreadTaskRunner> DefaultTaskRunner() override;
- scoped_refptr<base::SingleThreadTaskRunner> CompositorTaskRunner() override;
- scoped_refptr<SingleThreadIdleTaskRunner> IdleTaskRunner() override;
-
- void WillBeginFrame(const cc::BeginFrameArgs& args) override;
- void DidCommitFrameToCompositor() override;
- void DidReceiveInputEventOnCompositorThread() override;
- bool ShouldYieldForHighPriorityWork() override;
- void Shutdown() override;
-
- private:
- scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
- scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_;
-
- DISALLOW_COPY_AND_ASSIGN(NullRendererScheduler);
-};
-
-} // namespace content
-
-#endif // CONTENT_RENDERER_SCHEDULER_NULL_RENDERER_SCHEDULER_H_
diff --git a/chromium/content/renderer/scheduler/renderer_scheduler.cc b/chromium/content/renderer/scheduler/renderer_scheduler.cc
deleted file mode 100644
index ec30f7f5eb9..00000000000
--- a/chromium/content/renderer/scheduler/renderer_scheduler.cc
+++ /dev/null
@@ -1,23 +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/renderer/scheduler/renderer_scheduler.h"
-
-#include "content/renderer/scheduler/null_renderer_scheduler.h"
-
-namespace content {
-
-RendererScheduler::RendererScheduler() {
-}
-
-RendererScheduler::~RendererScheduler() {
-}
-
-// static
-scoped_ptr<RendererScheduler> RendererScheduler::Create() {
- // TODO(rmcilroy): Use the RendererSchedulerImpl when the scheduler is enabled
- return make_scoped_ptr(new NullRendererScheduler());
-}
-
-} // namespace content
diff --git a/chromium/content/renderer/scheduler/renderer_scheduler.h b/chromium/content/renderer/scheduler/renderer_scheduler.h
deleted file mode 100644
index 39945ae65b3..00000000000
--- a/chromium/content/renderer/scheduler/renderer_scheduler.h
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_RENDERER_SCHEDULER_RENDERER_SCHEDULER_H_
-#define CONTENT_RENDERER_SCHEDULER_RENDERER_SCHEDULER_H_
-
-#include "content/renderer/scheduler/single_thread_idle_task_runner.h"
-#include "content/renderer/scheduler/task_queue_manager.h"
-
-namespace cc {
-struct BeginFrameArgs;
-}
-
-namespace content {
-
-class CONTENT_EXPORT RendererScheduler {
- public:
- virtual ~RendererScheduler();
- static scoped_ptr<RendererScheduler> Create();
-
- // Returns the default task runner.
- virtual scoped_refptr<base::SingleThreadTaskRunner> DefaultTaskRunner() = 0;
-
- // Returns the compositor task runner.
- virtual scoped_refptr<base::SingleThreadTaskRunner>
- CompositorTaskRunner() = 0;
-
- // Returns the idle task runner. Tasks posted to this runner may be reordered
- // relative to other task types and may be starved for an arbitrarily long
- // time if no idle time is available.
- virtual scoped_refptr<SingleThreadIdleTaskRunner> IdleTaskRunner() = 0;
-
- // Called to notify about the start of a new frame. Must be called from the
- // main thread.
- virtual void WillBeginFrame(const cc::BeginFrameArgs& args) = 0;
-
- // Called to notify that a previously begun frame was committed. Must be
- // called from the main thread.
- virtual void DidCommitFrameToCompositor() = 0;
-
- // Tells the scheduler that the system received an input event. Called by the
- // compositor (impl) thread.
- virtual void DidReceiveInputEventOnCompositorThread() = 0;
-
- // Returns true if there is high priority work pending on the main thread
- // and the caller should yield to let the scheduler service that work.
- // Must be called from the main thread.
- virtual bool ShouldYieldForHighPriorityWork() = 0;
-
- // Shuts down the scheduler by dropping any remaining pending work in the work
- // queues. After this call any work posted to the task runners will be
- // silently dropped.
- virtual void Shutdown() = 0;
-
- protected:
- RendererScheduler();
- DISALLOW_COPY_AND_ASSIGN(RendererScheduler);
-};
-
-} // namespace content
-
-#endif // CONTENT_RENDERER_SCHEDULER_RENDERER_SCHEDULER_H_
diff --git a/chromium/content/renderer/scheduler/renderer_scheduler_impl.cc b/chromium/content/renderer/scheduler/renderer_scheduler_impl.cc
deleted file mode 100644
index aef2bdf7bcc..00000000000
--- a/chromium/content/renderer/scheduler/renderer_scheduler_impl.cc
+++ /dev/null
@@ -1,218 +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/renderer/scheduler/renderer_scheduler_impl.h"
-
-#include "base/bind.h"
-#include "cc/output/begin_frame_args.h"
-#include "content/renderer/scheduler/renderer_task_queue_selector.h"
-#include "ui/gfx/frame_time.h"
-
-namespace content {
-
-RendererSchedulerImpl::RendererSchedulerImpl(
- scoped_refptr<base::SingleThreadTaskRunner> main_task_runner)
- : renderer_task_queue_selector_(new RendererTaskQueueSelector()),
- task_queue_manager_(
- new TaskQueueManager(TASK_QUEUE_COUNT,
- main_task_runner,
- renderer_task_queue_selector_.get())),
- control_task_runner_(
- task_queue_manager_->TaskRunnerForQueue(CONTROL_TASK_QUEUE)),
- default_task_runner_(
- task_queue_manager_->TaskRunnerForQueue(DEFAULT_TASK_QUEUE)),
- compositor_task_runner_(
- task_queue_manager_->TaskRunnerForQueue(COMPOSITOR_TASK_QUEUE)),
- current_policy_(NORMAL_PRIORITY_POLICY),
- policy_may_need_update_(&incoming_signals_lock_),
- weak_factory_(this) {
- weak_renderer_scheduler_ptr_ = weak_factory_.GetWeakPtr();
- update_policy_closure_ = base::Bind(&RendererSchedulerImpl::UpdatePolicy,
- weak_renderer_scheduler_ptr_);
- end_idle_period_closure_ = base::Bind(&RendererSchedulerImpl::EndIdlePeriod,
- weak_renderer_scheduler_ptr_);
- idle_task_runner_ = make_scoped_refptr(new SingleThreadIdleTaskRunner(
- task_queue_manager_->TaskRunnerForQueue(IDLE_TASK_QUEUE),
- base::Bind(&RendererSchedulerImpl::CurrentIdleTaskDeadlineCallback,
- weak_renderer_scheduler_ptr_)));
- renderer_task_queue_selector_->SetQueuePriority(
- CONTROL_TASK_QUEUE, RendererTaskQueueSelector::CONTROL_PRIORITY);
- renderer_task_queue_selector_->DisableQueue(IDLE_TASK_QUEUE);
- task_queue_manager_->SetAutoPump(IDLE_TASK_QUEUE, false);
-}
-
-RendererSchedulerImpl::~RendererSchedulerImpl() {
-}
-
-void RendererSchedulerImpl::Shutdown() {
- main_thread_checker_.CalledOnValidThread();
- task_queue_manager_.reset();
-}
-
-scoped_refptr<base::SingleThreadTaskRunner>
-RendererSchedulerImpl::DefaultTaskRunner() {
- main_thread_checker_.CalledOnValidThread();
- return default_task_runner_;
-}
-
-scoped_refptr<base::SingleThreadTaskRunner>
-RendererSchedulerImpl::CompositorTaskRunner() {
- main_thread_checker_.CalledOnValidThread();
- return compositor_task_runner_;
-}
-
-scoped_refptr<SingleThreadIdleTaskRunner>
-RendererSchedulerImpl::IdleTaskRunner() {
- main_thread_checker_.CalledOnValidThread();
- return idle_task_runner_;
-}
-
-void RendererSchedulerImpl::WillBeginFrame(const cc::BeginFrameArgs& args) {
- main_thread_checker_.CalledOnValidThread();
- if (!task_queue_manager_)
- return;
-
- EndIdlePeriod();
- estimated_next_frame_begin_ = args.frame_time + args.interval;
-}
-
-void RendererSchedulerImpl::DidCommitFrameToCompositor() {
- main_thread_checker_.CalledOnValidThread();
- if (!task_queue_manager_)
- return;
-
- base::TimeTicks now(Now());
- if (now < estimated_next_frame_begin_) {
- StartIdlePeriod();
- control_task_runner_->PostDelayedTask(FROM_HERE, end_idle_period_closure_,
- estimated_next_frame_begin_ - now);
- }
-}
-
-void RendererSchedulerImpl::DidReceiveInputEventOnCompositorThread() {
- // TODO(rmcilroy): Decide whether only a subset of input events should trigger
- // compositor priority policy - http://crbug.com/429814.
- base::AutoLock lock(incoming_signals_lock_);
- if (last_input_time_.is_null()) {
- // Update scheduler policy if should start a new compositor policy mode.
- policy_may_need_update_.SetLocked(true);
- PostUpdatePolicyOnControlRunner(base::TimeDelta());
- }
- last_input_time_ = Now();
-}
-
-bool RendererSchedulerImpl::ShouldYieldForHighPriorityWork() {
- main_thread_checker_.CalledOnValidThread();
- if (!task_queue_manager_)
- return false;
-
- MaybeUpdatePolicy();
- // We only yield if we are in the compositor priority and there is compositor
- // work outstanding. Note: even though the control queue is higher priority
- // we don't yield for it since these tasks are not user-provided work and they
- // are only intended to run before the next task, not interrupt the tasks.
- return SchedulerPolicy() == COMPOSITOR_PRIORITY_POLICY &&
- !task_queue_manager_->IsQueueEmpty(COMPOSITOR_TASK_QUEUE);
-}
-
-void RendererSchedulerImpl::CurrentIdleTaskDeadlineCallback(
- base::TimeTicks* deadline_out) const {
- main_thread_checker_.CalledOnValidThread();
- *deadline_out = estimated_next_frame_begin_;
-}
-
-RendererSchedulerImpl::Policy RendererSchedulerImpl::SchedulerPolicy() const {
- main_thread_checker_.CalledOnValidThread();
- return current_policy_;
-}
-
-void RendererSchedulerImpl::MaybeUpdatePolicy() {
- main_thread_checker_.CalledOnValidThread();
- if (policy_may_need_update_.IsSet()) {
- UpdatePolicy();
- }
-}
-
-void RendererSchedulerImpl::PostUpdatePolicyOnControlRunner(
- base::TimeDelta delay) {
- control_task_runner_->PostDelayedTask(FROM_HERE, update_policy_closure_,
- delay);
-}
-
-void RendererSchedulerImpl::UpdatePolicy() {
- main_thread_checker_.CalledOnValidThread();
- if (!task_queue_manager_)
- return;
-
- base::AutoLock lock(incoming_signals_lock_);
- policy_may_need_update_.SetLocked(false);
-
- Policy new_policy = NORMAL_PRIORITY_POLICY;
- if (!last_input_time_.is_null()) {
- base::TimeDelta compositor_priority_duration =
- base::TimeDelta::FromMilliseconds(kCompositorPriorityAfterTouchMillis);
- base::TimeTicks compositor_priority_end(last_input_time_ +
- compositor_priority_duration);
- base::TimeTicks now(Now());
- if (compositor_priority_end > now) {
- PostUpdatePolicyOnControlRunner(compositor_priority_end - now);
- new_policy = COMPOSITOR_PRIORITY_POLICY;
- } else {
- // Null out last_input_time_ to ensure
- // DidReceiveInputEventOnCompositorThread will post an
- // UpdatePolicy task when it's next called.
- last_input_time_ = base::TimeTicks();
- }
- }
-
- if (new_policy == current_policy_)
- return;
-
- switch (new_policy) {
- case COMPOSITOR_PRIORITY_POLICY:
- renderer_task_queue_selector_->SetQueuePriority(
- COMPOSITOR_TASK_QUEUE, RendererTaskQueueSelector::HIGH_PRIORITY);
- break;
- case NORMAL_PRIORITY_POLICY:
- renderer_task_queue_selector_->SetQueuePriority(
- COMPOSITOR_TASK_QUEUE, RendererTaskQueueSelector::NORMAL_PRIORITY);
- break;
- }
- current_policy_ = new_policy;
-}
-
-void RendererSchedulerImpl::StartIdlePeriod() {
- main_thread_checker_.CalledOnValidThread();
- renderer_task_queue_selector_->EnableQueue(
- IDLE_TASK_QUEUE, RendererTaskQueueSelector::BEST_EFFORT_PRIORITY);
- task_queue_manager_->PumpQueue(IDLE_TASK_QUEUE);
-}
-
-void RendererSchedulerImpl::EndIdlePeriod() {
- main_thread_checker_.CalledOnValidThread();
- renderer_task_queue_selector_->DisableQueue(IDLE_TASK_QUEUE);
-}
-
-base::TimeTicks RendererSchedulerImpl::Now() const {
- return gfx::FrameTime::Now();
-}
-
-RendererSchedulerImpl::PollableNeedsUpdateFlag::PollableNeedsUpdateFlag(
- base::Lock* write_lock_)
- : flag_(false), write_lock_(write_lock_) {
-}
-
-RendererSchedulerImpl::PollableNeedsUpdateFlag::~PollableNeedsUpdateFlag() {
-}
-
-void RendererSchedulerImpl::PollableNeedsUpdateFlag::SetLocked(bool value) {
- write_lock_->AssertAcquired();
- base::subtle::Release_Store(&flag_, value);
-}
-
-bool RendererSchedulerImpl::PollableNeedsUpdateFlag::IsSet() const {
- thread_checker_.CalledOnValidThread();
- return base::subtle::Acquire_Load(&flag_) != 0;
-}
-} // namespace content
diff --git a/chromium/content/renderer/scheduler/renderer_scheduler_impl.h b/chromium/content/renderer/scheduler/renderer_scheduler_impl.h
deleted file mode 100644
index e45379be2ed..00000000000
--- a/chromium/content/renderer/scheduler/renderer_scheduler_impl.h
+++ /dev/null
@@ -1,128 +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_RENDERER_SCHEDULER_RENDERER_SCHEDULER_IMPL_H_
-#define CONTENT_RENDERER_SCHEDULER_RENDERER_SCHEDULER_IMPL_H_
-
-#include "base/atomicops.h"
-#include "base/synchronization/lock.h"
-#include "base/threading/thread_checker.h"
-#include "content/renderer/scheduler/renderer_scheduler.h"
-#include "content/renderer/scheduler/single_thread_idle_task_runner.h"
-#include "content/renderer/scheduler/task_queue_manager.h"
-
-namespace content {
-
-class RendererTaskQueueSelector;
-
-class CONTENT_EXPORT RendererSchedulerImpl : public RendererScheduler {
- public:
- RendererSchedulerImpl(
- scoped_refptr<base::SingleThreadTaskRunner> main_task_runner);
- ~RendererSchedulerImpl() override;
-
- // RendererScheduler implementation:
- scoped_refptr<base::SingleThreadTaskRunner> DefaultTaskRunner() override;
- scoped_refptr<base::SingleThreadTaskRunner> CompositorTaskRunner() override;
- scoped_refptr<SingleThreadIdleTaskRunner> IdleTaskRunner() override;
- void WillBeginFrame(const cc::BeginFrameArgs& args) override;
- void DidCommitFrameToCompositor() override;
- void DidReceiveInputEventOnCompositorThread() override;
- bool ShouldYieldForHighPriorityWork() override;
- void Shutdown() override;
-
- protected:
- // Virtual for testing.
- virtual base::TimeTicks Now() const;
-
- private:
- friend class RendererSchedulerImplTest;
-
- enum QueueId {
- DEFAULT_TASK_QUEUE,
- COMPOSITOR_TASK_QUEUE,
- IDLE_TASK_QUEUE,
- CONTROL_TASK_QUEUE,
- // Must be the last entry.
- TASK_QUEUE_COUNT,
- };
-
- enum Policy {
- NORMAL_PRIORITY_POLICY,
- COMPOSITOR_PRIORITY_POLICY,
- };
-
- class PollableNeedsUpdateFlag {
- public:
- PollableNeedsUpdateFlag(base::Lock* write_lock);
- ~PollableNeedsUpdateFlag();
-
- // Set the flag. May only be called if |write_lock| is held.
- void SetLocked(bool value);
-
- // Returns true iff the flag was set to true.
- bool IsSet() const;
-
- private:
- base::subtle::Atomic32 flag_;
- base::Lock* write_lock_; // Not owned.
- base::ThreadChecker thread_checker_;
-
- DISALLOW_COPY_AND_ASSIGN(PollableNeedsUpdateFlag);
- };
-
- // The time we should stay in CompositorPriority mode for after a touch event.
- static const int kCompositorPriorityAfterTouchMillis = 100;
-
- // IdleTaskDeadlineSupplier Implementation:
- void CurrentIdleTaskDeadlineCallback(base::TimeTicks* deadline_out) const;
-
- // Returns the current scheduler policy. Must be called from the main thread.
- Policy SchedulerPolicy() const;
-
- // Posts a call to UpdatePolicy on the control runner to be run after |delay|
- void PostUpdatePolicyOnControlRunner(base::TimeDelta delay);
-
- // Update the policy if a new signal has arrived. Must be called from the main
- // thread.
- void MaybeUpdatePolicy();
-
- // Updates the scheduler policy. Must be called from the main thread.
- void UpdatePolicy();
-
- // Start and end an idle period.
- void StartIdlePeriod();
- void EndIdlePeriod();
-
- base::ThreadChecker main_thread_checker_;
- scoped_ptr<RendererTaskQueueSelector> renderer_task_queue_selector_;
- scoped_ptr<TaskQueueManager> task_queue_manager_;
- scoped_refptr<base::SingleThreadTaskRunner> control_task_runner_;
- scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_;
- scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_;
- scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_;
-
- base::Closure update_policy_closure_;
- base::Closure end_idle_period_closure_;
-
- // Don't access current_policy_ directly, instead use SchedulerPolicy().
- Policy current_policy_;
-
- base::TimeTicks estimated_next_frame_begin_;
-
- // The incoming_signals_lock_ mutex protects access to last_input_time_
- // and write access to policy_may_need_update_.
- base::Lock incoming_signals_lock_;
- base::TimeTicks last_input_time_;
- PollableNeedsUpdateFlag policy_may_need_update_;
-
- base::WeakPtr<RendererSchedulerImpl> weak_renderer_scheduler_ptr_;
- base::WeakPtrFactory<RendererSchedulerImpl> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(RendererSchedulerImpl);
-};
-
-} // namespace content
-
-#endif // CONTENT_RENDERER_SCHEDULER_RENDERER_SCHEDULER_IMPL_H_
diff --git a/chromium/content/renderer/scheduler/renderer_scheduler_impl_unittest.cc b/chromium/content/renderer/scheduler/renderer_scheduler_impl_unittest.cc
deleted file mode 100644
index 701a222c71e..00000000000
--- a/chromium/content/renderer/scheduler/renderer_scheduler_impl_unittest.cc
+++ /dev/null
@@ -1,411 +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/renderer/scheduler/renderer_scheduler_impl.h"
-
-#include "base/callback.h"
-#include "cc/output/begin_frame_args.h"
-#include "cc/test/ordered_simple_task_runner.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace content {
-
-class RendererSchedulerImplForTest : public RendererSchedulerImpl {
- public:
- RendererSchedulerImplForTest(
- scoped_refptr<cc::OrderedSimpleTaskRunner> task_runner,
- scoped_refptr<cc::TestNowSource> clock)
- : RendererSchedulerImpl(task_runner), clock_(clock) {}
- ~RendererSchedulerImplForTest() override {}
-
- protected:
- base::TimeTicks Now() const override { return clock_->Now(); }
-
- private:
- scoped_refptr<cc::TestNowSource> clock_;
-};
-
-class RendererSchedulerImplTest : public testing::Test {
- public:
- RendererSchedulerImplTest()
- : clock_(cc::TestNowSource::Create(5000)),
- mock_task_runner_(new cc::OrderedSimpleTaskRunner(clock_, false)),
- scheduler_(new RendererSchedulerImplForTest(mock_task_runner_, clock_)),
- default_task_runner_(scheduler_->DefaultTaskRunner()),
- compositor_task_runner_(scheduler_->CompositorTaskRunner()),
- idle_task_runner_(scheduler_->IdleTaskRunner()) {}
- ~RendererSchedulerImplTest() override {}
-
- void RunUntilIdle() { mock_task_runner_->RunUntilIdle(); }
-
- void EnableIdleTasks() {
- scheduler_->WillBeginFrame(
- cc::BeginFrameArgs::Create(clock_->Now(), base::TimeTicks(),
- base::TimeDelta::FromMilliseconds(1000)));
- scheduler_->DidCommitFrameToCompositor();
- }
-
- protected:
- scoped_refptr<cc::TestNowSource> clock_;
- scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_;
-
- scoped_ptr<RendererSchedulerImpl> scheduler_;
- scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_;
- scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_;
- scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_;
-
- DISALLOW_COPY_AND_ASSIGN(RendererSchedulerImplTest);
-};
-
-void NullTask() {
-}
-
-void OrderedTestTask(int value, int* result) {
- *result = (*result << 4) | value;
-}
-
-void UnorderedTestTask(int value, int* result) {
- *result += value;
-}
-
-void AppendToVectorTestTask(std::vector<std::string>* vector,
- std::string value) {
- vector->push_back(value);
-}
-
-void AppendToVectorIdleTestTask(std::vector<std::string>* vector,
- std::string value,
- base::TimeTicks deadline) {
- AppendToVectorTestTask(vector, value);
-}
-
-void AppendToVectorReentrantTask(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- std::vector<int>* vector,
- int* reentrant_count,
- int max_reentrant_count) {
- vector->push_back((*reentrant_count)++);
- if (*reentrant_count < max_reentrant_count) {
- task_runner->PostTask(
- FROM_HERE, base::Bind(AppendToVectorReentrantTask, task_runner, vector,
- reentrant_count, max_reentrant_count));
- }
-}
-
-void IdleTestTask(bool* task_run,
- base::TimeTicks* deadline_out,
- base::TimeTicks deadline) {
- EXPECT_FALSE(*task_run);
- *deadline_out = deadline;
- *task_run = true;
-}
-
-void RepostingIdleTestTask(
- scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner,
- int* run_count,
- base::TimeTicks deadline) {
- if (*run_count == 0) {
- idle_task_runner->PostIdleTask(
- FROM_HERE,
- base::Bind(&RepostingIdleTestTask, idle_task_runner, run_count));
- }
- (*run_count)++;
-}
-
-void UpdateClockToDeadlineIdleTestTask(
- scoped_refptr<cc::TestNowSource> clock,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- int* run_count,
- base::TimeTicks deadline) {
- clock->SetNow(deadline);
- // Due to the way in which OrderedSimpleTestRunner orders tasks and the fact
- // that we updated the time within a task, the delayed pending task to call
- // EndIdlePeriod will not happen until after a TaskQueueManager DoWork, so
- // post a normal task here to ensure it runs before the next idle task.
- task_runner->PostTask(FROM_HERE, base::Bind(NullTask));
- (*run_count)++;
-}
-
-void PostingYieldingTestTask(
- RendererSchedulerImpl* scheduler,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- bool simulate_input,
- bool* should_yield_before,
- bool* should_yield_after) {
- *should_yield_before = scheduler->ShouldYieldForHighPriorityWork();
- task_runner->PostTask(FROM_HERE, base::Bind(NullTask));
- if (simulate_input) {
- scheduler->DidReceiveInputEventOnCompositorThread();
- }
- *should_yield_after = scheduler->ShouldYieldForHighPriorityWork();
-}
-
-TEST_F(RendererSchedulerImplTest, TestPostDefaultTask) {
- int result = 0;
- default_task_runner_->PostTask(FROM_HERE,
- base::Bind(OrderedTestTask, 1, &result));
- default_task_runner_->PostTask(FROM_HERE,
- base::Bind(OrderedTestTask, 2, &result));
- default_task_runner_->PostTask(FROM_HERE,
- base::Bind(OrderedTestTask, 3, &result));
- default_task_runner_->PostTask(FROM_HERE,
- base::Bind(OrderedTestTask, 4, &result));
- RunUntilIdle();
- EXPECT_EQ(0x1234, result);
-}
-
-TEST_F(RendererSchedulerImplTest, TestPostDefaultAndCompositor) {
- int result = 0;
- default_task_runner_->PostTask(FROM_HERE,
- base::Bind(&UnorderedTestTask, 1, &result));
- compositor_task_runner_->PostTask(FROM_HERE,
- base::Bind(&UnorderedTestTask, 2, &result));
- RunUntilIdle();
- EXPECT_EQ(3, result);
-}
-
-TEST_F(RendererSchedulerImplTest, TestRentrantTask) {
- int count = 0;
- std::vector<int> order;
- default_task_runner_->PostTask(
- FROM_HERE, base::Bind(AppendToVectorReentrantTask, default_task_runner_,
- &order, &count, 5));
- RunUntilIdle();
-
- EXPECT_THAT(order, testing::ElementsAre(0, 1, 2, 3, 4));
-}
-
-TEST_F(RendererSchedulerImplTest, TestPostIdleTask) {
- bool task_run = false;
- base::TimeTicks expected_deadline =
- clock_->Now() + base::TimeDelta::FromMilliseconds(2300);
- base::TimeTicks deadline_in_task;
-
- clock_->AdvanceNow(base::TimeDelta::FromMilliseconds(100));
- idle_task_runner_->PostIdleTask(
- FROM_HERE, base::Bind(&IdleTestTask, &task_run, &deadline_in_task));
-
- RunUntilIdle();
- EXPECT_FALSE(task_run); // Shouldn't run yet as no WillBeginFrame.
-
- scheduler_->WillBeginFrame(
- cc::BeginFrameArgs::Create(clock_->Now(), base::TimeTicks(),
- base::TimeDelta::FromMilliseconds(1000)));
- RunUntilIdle();
- EXPECT_FALSE(task_run); // Shouldn't run as no DidCommitFrameToCompositor.
-
- clock_->AdvanceNow(base::TimeDelta::FromMilliseconds(1200));
- scheduler_->DidCommitFrameToCompositor();
- RunUntilIdle();
- EXPECT_FALSE(task_run); // We missed the deadline.
-
- scheduler_->WillBeginFrame(
- cc::BeginFrameArgs::Create(clock_->Now(), base::TimeTicks(),
- base::TimeDelta::FromMilliseconds(1000)));
- clock_->AdvanceNow(base::TimeDelta::FromMilliseconds(800));
- scheduler_->DidCommitFrameToCompositor();
- RunUntilIdle();
- EXPECT_TRUE(task_run);
- EXPECT_EQ(expected_deadline, deadline_in_task);
-}
-
-TEST_F(RendererSchedulerImplTest, TestRepostingIdleTask) {
- int run_count = 0;
-
- idle_task_runner_->PostIdleTask(
- FROM_HERE,
- base::Bind(&RepostingIdleTestTask, idle_task_runner_, &run_count));
- EnableIdleTasks();
- RunUntilIdle();
- EXPECT_EQ(1, run_count);
-
- // Reposted tasks shouldn't run until next idle period.
- RunUntilIdle();
- EXPECT_EQ(1, run_count);
-
- EnableIdleTasks();
- RunUntilIdle();
- EXPECT_EQ(2, run_count);
-}
-
-TEST_F(RendererSchedulerImplTest, TestIdleTaskExceedsDeadline) {
- mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true);
- int run_count = 0;
-
- // Post two UpdateClockToDeadlineIdleTestTask tasks.
- idle_task_runner_->PostIdleTask(
- FROM_HERE, base::Bind(&UpdateClockToDeadlineIdleTestTask, clock_,
- default_task_runner_, &run_count));
- idle_task_runner_->PostIdleTask(
- FROM_HERE, base::Bind(&UpdateClockToDeadlineIdleTestTask, clock_,
- default_task_runner_, &run_count));
-
- EnableIdleTasks();
- RunUntilIdle();
- // Only the first idle task should execute since it's used up the deadline.
- EXPECT_EQ(1, run_count);
-
- EnableIdleTasks();
- RunUntilIdle();
- // Second task should be run on the next idle period.
- EXPECT_EQ(2, run_count);
-}
-
-TEST_F(RendererSchedulerImplTest, TestDefaultPolicy) {
- std::vector<std::string> order;
-
- idle_task_runner_->PostIdleTask(
- FROM_HERE,
- base::Bind(&AppendToVectorIdleTestTask, &order, std::string("I1")));
- default_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&AppendToVectorTestTask, &order, std::string("D1")));
- compositor_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&AppendToVectorTestTask, &order, std::string("C1")));
- default_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&AppendToVectorTestTask, &order, std::string("D2")));
- compositor_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&AppendToVectorTestTask, &order, std::string("C2")));
-
- EnableIdleTasks();
- RunUntilIdle();
- EXPECT_THAT(order, testing::ElementsAre(std::string("D1"), std::string("C1"),
- std::string("D2"), std::string("C2"),
- std::string("I1")));
-}
-
-TEST_F(RendererSchedulerImplTest, TestCompositorPolicy) {
- std::vector<std::string> order;
-
- idle_task_runner_->PostIdleTask(
- FROM_HERE,
- base::Bind(&AppendToVectorIdleTestTask, &order, std::string("I1")));
- default_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&AppendToVectorTestTask, &order, std::string("D1")));
- compositor_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&AppendToVectorTestTask, &order, std::string("C1")));
- default_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&AppendToVectorTestTask, &order, std::string("D2")));
- compositor_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&AppendToVectorTestTask, &order, std::string("C2")));
-
- scheduler_->DidReceiveInputEventOnCompositorThread();
- EnableIdleTasks();
- RunUntilIdle();
- EXPECT_THAT(order, testing::ElementsAre(std::string("C1"), std::string("C2"),
- std::string("D1"), std::string("D2"),
- std::string("I1")));
-}
-
-TEST_F(RendererSchedulerImplTest,
- TestCompositorPolicyDoesNotStarveDefaultTasks) {
- std::vector<std::string> order;
-
- default_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&AppendToVectorTestTask, &order, std::string("D1")));
- compositor_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&AppendToVectorTestTask, &order, std::string("C1")));
- for (int i = 0; i < 20; i++) {
- compositor_task_runner_->PostTask(FROM_HERE, base::Bind(&NullTask));
- }
- compositor_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&AppendToVectorTestTask, &order, std::string("C2")));
-
- scheduler_->DidReceiveInputEventOnCompositorThread();
- RunUntilIdle();
- // Ensure that the default D1 task gets to run at some point before the final
- // C2 compositor task.
- EXPECT_THAT(order, testing::ElementsAre(std::string("C1"), std::string("D1"),
- std::string("C2")));
-}
-
-TEST_F(RendererSchedulerImplTest, TestCompositorPolicyEnds) {
- std::vector<std::string> order;
-
- default_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&AppendToVectorTestTask, &order, std::string("D1")));
- compositor_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&AppendToVectorTestTask, &order, std::string("C1")));
- default_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&AppendToVectorTestTask, &order, std::string("D2")));
- compositor_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&AppendToVectorTestTask, &order, std::string("C2")));
-
- scheduler_->DidReceiveInputEventOnCompositorThread();
- RunUntilIdle();
- EXPECT_THAT(order,
- testing::ElementsAre(std::string("C1"), std::string("C2"),
- std::string("D1"), std::string("D2")));
-
- order.clear();
- clock_->AdvanceNow(base::TimeDelta::FromMilliseconds(1000));
-
- default_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&AppendToVectorTestTask, &order, std::string("D1")));
- compositor_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&AppendToVectorTestTask, &order, std::string("C1")));
- default_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&AppendToVectorTestTask, &order, std::string("D2")));
- compositor_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&AppendToVectorTestTask, &order, std::string("C2")));
-
- // Compositor policy mode should have ended now that the clock has advanced.
- RunUntilIdle();
- EXPECT_THAT(order,
- testing::ElementsAre(std::string("D1"), std::string("C1"),
- std::string("D2"), std::string("C2")));
-}
-
-TEST_F(RendererSchedulerImplTest, TestShouldYield) {
- bool should_yield_before = false;
- bool should_yield_after = false;
-
- default_task_runner_->PostTask(
- FROM_HERE, base::Bind(&PostingYieldingTestTask, scheduler_.get(),
- default_task_runner_, false, &should_yield_before,
- &should_yield_after));
- RunUntilIdle();
- // Posting to default runner shouldn't cause yielding.
- EXPECT_FALSE(should_yield_before);
- EXPECT_FALSE(should_yield_after);
-
- default_task_runner_->PostTask(
- FROM_HERE, base::Bind(&PostingYieldingTestTask, scheduler_.get(),
- compositor_task_runner_, false,
- &should_yield_before, &should_yield_after));
- RunUntilIdle();
- // Posting while not in compositor priority shouldn't cause yielding.
- EXPECT_FALSE(should_yield_before);
- EXPECT_FALSE(should_yield_after);
-
- default_task_runner_->PostTask(
- FROM_HERE, base::Bind(&PostingYieldingTestTask, scheduler_.get(),
- compositor_task_runner_, true, &should_yield_before,
- &should_yield_after));
- RunUntilIdle();
- // We should be able to switch to compositor priority mid-task.
- EXPECT_FALSE(should_yield_before);
- EXPECT_TRUE(should_yield_after);
-}
-
-} // namespace content
diff --git a/chromium/content/renderer/scheduler/renderer_task_queue_selector.cc b/chromium/content/renderer/scheduler/renderer_task_queue_selector.cc
deleted file mode 100644
index c804437bd41..00000000000
--- a/chromium/content/renderer/scheduler/renderer_task_queue_selector.cc
+++ /dev/null
@@ -1,122 +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/renderer/scheduler/renderer_task_queue_selector.h"
-
-#include "base/logging.h"
-#include "base/pending_task.h"
-
-namespace content {
-
-RendererTaskQueueSelector::RendererTaskQueueSelector() : starvation_count_(0) {
-}
-
-RendererTaskQueueSelector::~RendererTaskQueueSelector() {
-}
-
-void RendererTaskQueueSelector::RegisterWorkQueues(
- const std::vector<const base::TaskQueue*>& work_queues) {
- main_thread_checker_.CalledOnValidThread();
- work_queues_ = work_queues;
- for (QueuePriority priority = FIRST_QUEUE_PRIORITY;
- priority < QUEUE_PRIORITY_COUNT;
- priority = NextPriority(priority)) {
- queue_priorities_[priority].clear();
- }
- // By default, all work queues are set to normal priority.
- for (size_t i = 0; i < work_queues.size(); i++) {
- queue_priorities_[NORMAL_PRIORITY].insert(i);
- }
-}
-
-void RendererTaskQueueSelector::SetQueuePriority(size_t queue_index,
- QueuePriority priority) {
- main_thread_checker_.CalledOnValidThread();
- DCHECK_LT(queue_index, work_queues_.size());
- DCHECK_LT(priority, QUEUE_PRIORITY_COUNT);
- DisableQueue(queue_index);
- queue_priorities_[priority].insert(queue_index);
-}
-
-void RendererTaskQueueSelector::EnableQueue(size_t queue_index,
- QueuePriority priority) {
- SetQueuePriority(queue_index, priority);
-}
-
-void RendererTaskQueueSelector::DisableQueue(size_t queue_index) {
- main_thread_checker_.CalledOnValidThread();
- DCHECK_LT(queue_index, work_queues_.size());
- for (QueuePriority priority = FIRST_QUEUE_PRIORITY;
- priority < QUEUE_PRIORITY_COUNT;
- priority = NextPriority(priority)) {
- queue_priorities_[priority].erase(queue_index);
- }
-}
-
-bool RendererTaskQueueSelector::IsOlder(const base::TaskQueue* queueA,
- const base::TaskQueue* queueB) {
- // Note: the comparison is correct due to the fact that the PendingTask
- // operator inverts its comparison operation in order to work well in a heap
- // based priority queue.
- return queueB->front() < queueA->front();
-}
-
-RendererTaskQueueSelector::QueuePriority
-RendererTaskQueueSelector::NextPriority(QueuePriority priority) {
- DCHECK(priority < QUEUE_PRIORITY_COUNT);
- return static_cast<QueuePriority>(static_cast<int>(priority) + 1);
-}
-
-bool RendererTaskQueueSelector::ChooseOldestWithPriority(
- QueuePriority priority,
- size_t* out_queue_index) const {
- bool found_non_empty_queue = false;
- size_t chosen_queue = 0;
- for (int queue_index : queue_priorities_[priority]) {
- if (work_queues_[queue_index]->empty()) {
- continue;
- }
- if (!found_non_empty_queue ||
- IsOlder(work_queues_[queue_index], work_queues_[chosen_queue])) {
- found_non_empty_queue = true;
- chosen_queue = queue_index;
- }
- }
-
- if (found_non_empty_queue) {
- *out_queue_index = chosen_queue;
- }
- return found_non_empty_queue;
-}
-
-bool RendererTaskQueueSelector::SelectWorkQueueToService(
- size_t* out_queue_index) {
- main_thread_checker_.CalledOnValidThread();
- DCHECK(work_queues_.size());
- // Always service the control queue if it has any work.
- if (ChooseOldestWithPriority(CONTROL_PRIORITY, out_queue_index)) {
- return true;
- }
- // Select from the normal priority queue if we are starving it.
- if (starvation_count_ >= kMaxStarvationTasks &&
- ChooseOldestWithPriority(NORMAL_PRIORITY, out_queue_index)) {
- starvation_count_ = 0;
- return true;
- }
- // Otherwise choose in priority order.
- for (QueuePriority priority = HIGH_PRIORITY; priority < QUEUE_PRIORITY_COUNT;
- priority = NextPriority(priority)) {
- if (ChooseOldestWithPriority(priority, out_queue_index)) {
- if (priority == HIGH_PRIORITY) {
- starvation_count_++;
- } else {
- starvation_count_ = 0;
- }
- return true;
- }
- }
- return false;
-}
-
-} // namespace content
diff --git a/chromium/content/renderer/scheduler/renderer_task_queue_selector.h b/chromium/content/renderer/scheduler/renderer_task_queue_selector.h
deleted file mode 100644
index 085a628fd54..00000000000
--- a/chromium/content/renderer/scheduler/renderer_task_queue_selector.h
+++ /dev/null
@@ -1,91 +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_RENDERER_SCHEDULER_RENDERER_TASK_QUEUE_SELECTOR_H
-#define CONTENT_RENDERER_SCHEDULER_RENDERER_TASK_QUEUE_SELECTOR_H
-
-#include <set>
-
-#include "base/compiler_specific.h"
-#include "base/threading/thread_checker.h"
-#include "content/common/content_export.h"
-#include "content/renderer/scheduler/task_queue_selector.h"
-
-namespace content {
-
-// A RendererTaskQueueSelector is a TaskQueueSelector which is used by the
-// RendererScheduler to enable prioritization of particular task queues.
-class CONTENT_EXPORT RendererTaskQueueSelector
- : NON_EXPORTED_BASE(public TaskQueueSelector) {
- public:
- enum QueuePriority {
- // Queues with control priority will run before any other queue, and will
- // explicitly starve other queues. Typically this should only be used for
- // private queues which perform control operations.
- CONTROL_PRIORITY,
- // Queues with high priority will be selected preferentially over normal or
- // best effort queues. The selector will ensure that high priority queues
- // cannot completely starve normal priority queues.
- HIGH_PRIORITY,
- // Queues with normal priority are the default.
- NORMAL_PRIORITY,
- // Queues with best effort priority will only be run if all other queues are
- // empty. They can be starved by the other queues.
- BEST_EFFORT_PRIORITY,
- // Must be the last entry.
- QUEUE_PRIORITY_COUNT,
- FIRST_QUEUE_PRIORITY = CONTROL_PRIORITY,
- };
-
- RendererTaskQueueSelector();
- ~RendererTaskQueueSelector() override;
-
- // Set the priority of |queue_index| to |priority|.
- void SetQueuePriority(size_t queue_index, QueuePriority priority);
-
- // Enable the |queue_index| with a priority of |priority|. By default all
- // queues are enabled with normal priority.
- void EnableQueue(size_t queue_index, QueuePriority priority);
-
- // Disable the |queue_index|.
- void DisableQueue(size_t queue_index);
-
- // TaskQueueSelector implementation:
- void RegisterWorkQueues(
- const std::vector<const base::TaskQueue*>& work_queues) override;
- bool SelectWorkQueueToService(size_t* out_queue_index) override;
-
- private:
- // Returns true if queueA contains an older task than queueB.
- static bool IsOlder(const base::TaskQueue* queueA,
- const base::TaskQueue* queueB);
-
- // Returns the priority which is next after |priority|.
- static QueuePriority NextPriority(QueuePriority priority);
-
- // Return true if |out_queue_index| indicates the index of the queue with
- // the oldest pending task from the set of queues of |priority|, or
- // false if all queues of that priority are empty.
- bool ChooseOldestWithPriority(QueuePriority priority,
- size_t* out_queue_index) const;
-
- // Returns true if |queue_index| is enabled with the given |priority|.
- bool QueueEnabledWithPriority(size_t queue_index,
- QueuePriority priority) const;
-
- // Number of high priority tasks which can be run before a normal priority
- // task should be selected to prevent starvation.
- // TODO(rmcilroy): Check if this is a good value.
- static const size_t kMaxStarvationTasks = 5;
-
- base::ThreadChecker main_thread_checker_;
- std::vector<const base::TaskQueue*> work_queues_;
- std::set<size_t> queue_priorities_[QUEUE_PRIORITY_COUNT];
- size_t starvation_count_;
- DISALLOW_COPY_AND_ASSIGN(RendererTaskQueueSelector);
-};
-
-} // namespace content
-
-#endif // CONTENT_RENDERER_SCHEDULER_RENDERER_TASK_QUEUE_SELECTOR_H
diff --git a/chromium/content/renderer/scheduler/renderer_task_queue_selector_unittest.cc b/chromium/content/renderer/scheduler/renderer_task_queue_selector_unittest.cc
deleted file mode 100644
index 5f9197ee158..00000000000
--- a/chromium/content/renderer/scheduler/renderer_task_queue_selector_unittest.cc
+++ /dev/null
@@ -1,201 +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/renderer/scheduler/renderer_task_queue_selector.h"
-
-#include "base/bind.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
-#include "base/pending_task.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace content {
-
-class RendererTaskQueueSelectorTest : public testing::Test {
- public:
- RendererTaskQueueSelectorTest()
- : test_closure_(
- base::Bind(&RendererTaskQueueSelectorTest::TestFunction)) {}
- ~RendererTaskQueueSelectorTest() override {}
-
- std::vector<base::PendingTask> GetTasks(int count) {
- std::vector<base::PendingTask> tasks;
- for (int i = 0; i < count; i++) {
- base::PendingTask task = base::PendingTask(FROM_HERE, test_closure_);
- task.sequence_num = i;
- tasks.push_back(task);
- }
- return tasks;
- }
-
- void PushTasks(const std::vector<base::PendingTask>& tasks,
- const size_t queue_indices[]) {
- for (size_t i = 0; i < tasks.size(); i++) {
- task_queues_[queue_indices[i]]->push(tasks[i]);
- }
- }
-
- std::vector<size_t> PopTasks() {
- std::vector<size_t> order;
- size_t chosen_queue_index;
- while (selector_.SelectWorkQueueToService(&chosen_queue_index)) {
- order.push_back(chosen_queue_index);
- task_queues_[chosen_queue_index]->pop();
- }
- return order;
- }
-
- static void TestFunction() {}
-
- protected:
- void SetUp() final {
- std::vector<const base::TaskQueue*> const_task_queues;
- for (size_t i = 0; i < kTaskQueueCount; i++) {
- scoped_ptr<base::TaskQueue> task_queue(new base::TaskQueue());
- const_task_queues.push_back(task_queue.get());
- task_queues_.push_back(task_queue.release());
- }
- selector_.RegisterWorkQueues(const_task_queues);
- }
-
- const size_t kTaskQueueCount = 5;
- base::Closure test_closure_;
- RendererTaskQueueSelector selector_;
- ScopedVector<base::TaskQueue> task_queues_;
-};
-
-TEST_F(RendererTaskQueueSelectorTest, TestDefaultPriority) {
- std::vector<base::PendingTask> tasks = GetTasks(5);
- size_t queue_order[] = {4, 3, 2, 1, 0};
- PushTasks(tasks, queue_order);
- EXPECT_THAT(PopTasks(), testing::ElementsAre(4, 3, 2, 1, 0));
-}
-
-TEST_F(RendererTaskQueueSelectorTest, TestHighPriority) {
- std::vector<base::PendingTask> tasks = GetTasks(5);
- size_t queue_order[] = {0, 1, 2, 3, 4};
- PushTasks(tasks, queue_order);
- selector_.SetQueuePriority(2, RendererTaskQueueSelector::HIGH_PRIORITY);
- EXPECT_THAT(PopTasks(), testing::ElementsAre(2, 0, 1, 3, 4));
-}
-
-TEST_F(RendererTaskQueueSelectorTest, TestBestEffortPriority) {
- std::vector<base::PendingTask> tasks = GetTasks(5);
- size_t queue_order[] = {0, 1, 2, 3, 4};
- PushTasks(tasks, queue_order);
- selector_.SetQueuePriority(0,
- RendererTaskQueueSelector::BEST_EFFORT_PRIORITY);
- selector_.SetQueuePriority(2, RendererTaskQueueSelector::HIGH_PRIORITY);
- EXPECT_THAT(PopTasks(), testing::ElementsAre(2, 1, 3, 4, 0));
-}
-
-TEST_F(RendererTaskQueueSelectorTest, TestControlPriority) {
- std::vector<base::PendingTask> tasks = GetTasks(5);
- size_t queue_order[] = {0, 1, 2, 3, 4};
- PushTasks(tasks, queue_order);
- selector_.SetQueuePriority(4, RendererTaskQueueSelector::CONTROL_PRIORITY);
- selector_.SetQueuePriority(2, RendererTaskQueueSelector::HIGH_PRIORITY);
- EXPECT_THAT(PopTasks(), testing::ElementsAre(4, 2, 0, 1, 3));
-}
-
-TEST_F(RendererTaskQueueSelectorTest, TestDisableEnable) {
- std::vector<base::PendingTask> tasks = GetTasks(5);
- size_t queue_order[] = {0, 1, 2, 3, 4};
- PushTasks(tasks, queue_order);
- selector_.DisableQueue(2);
- selector_.DisableQueue(4);
- EXPECT_THAT(PopTasks(), testing::ElementsAre(0, 1, 3));
- selector_.EnableQueue(2, RendererTaskQueueSelector::BEST_EFFORT_PRIORITY);
- EXPECT_THAT(PopTasks(), testing::ElementsAre(2));
- selector_.EnableQueue(4, RendererTaskQueueSelector::NORMAL_PRIORITY);
- EXPECT_THAT(PopTasks(), testing::ElementsAre(4));
-}
-
-TEST_F(RendererTaskQueueSelectorTest, TestEmptyQueues) {
- size_t chosen_queue_index = 0;
- EXPECT_FALSE(selector_.SelectWorkQueueToService(&chosen_queue_index));
-
- // Test only disabled queues.
- std::vector<base::PendingTask> tasks = GetTasks(1);
- size_t queue_order[] = {0};
- PushTasks(tasks, queue_order);
- selector_.DisableQueue(0);
- EXPECT_FALSE(selector_.SelectWorkQueueToService(&chosen_queue_index));
-}
-
-TEST_F(RendererTaskQueueSelectorTest, TestDelay) {
- std::vector<base::PendingTask> tasks = GetTasks(5);
- tasks[0].delayed_run_time =
- base::TimeTicks() + base::TimeDelta::FromMilliseconds(200);
- tasks[3].delayed_run_time =
- base::TimeTicks() + base::TimeDelta::FromMilliseconds(100);
- size_t queue_order[] = {0, 1, 2, 3, 4};
- PushTasks(tasks, queue_order);
- EXPECT_THAT(PopTasks(), testing::ElementsAre(1, 2, 4, 3, 0));
-}
-
-TEST_F(RendererTaskQueueSelectorTest, TestControlStarvesOthers) {
- std::vector<base::PendingTask> tasks = GetTasks(4);
- size_t queue_order[] = {0, 1, 2, 3};
- PushTasks(tasks, queue_order);
- selector_.SetQueuePriority(3, RendererTaskQueueSelector::CONTROL_PRIORITY);
- selector_.SetQueuePriority(2, RendererTaskQueueSelector::HIGH_PRIORITY);
- selector_.SetQueuePriority(1,
- RendererTaskQueueSelector::BEST_EFFORT_PRIORITY);
- for (int i = 0; i < 100; i++) {
- size_t chosen_queue_index = 0;
- EXPECT_TRUE(selector_.SelectWorkQueueToService(&chosen_queue_index));
- EXPECT_EQ(3ul, chosen_queue_index);
- // Don't remove task from queue to simulate all queues still being full.
- }
-}
-
-TEST_F(RendererTaskQueueSelectorTest, TestHighPriorityDoesNotStarveNormal) {
- std::vector<base::PendingTask> tasks = GetTasks(3);
- size_t queue_order[] = {0, 1, 2};
- PushTasks(tasks, queue_order);
- selector_.SetQueuePriority(2, RendererTaskQueueSelector::HIGH_PRIORITY);
- selector_.SetQueuePriority(1,
- RendererTaskQueueSelector::BEST_EFFORT_PRIORITY);
- size_t counts[] = {0, 0, 0};
- for (int i = 0; i < 100; i++) {
- size_t chosen_queue_index = 0;
- EXPECT_TRUE(selector_.SelectWorkQueueToService(&chosen_queue_index));
- counts[chosen_queue_index]++;
- // Don't remove task from queue to simulate all queues still being full.
- }
- EXPECT_GT(counts[0], 0ul); // Check high doesn't starve normal.
- EXPECT_GT(counts[2], counts[0]); // Check high gets more chance to run.
- EXPECT_EQ(0ul, counts[1]); // Check best effort is starved.
-}
-
-TEST_F(RendererTaskQueueSelectorTest, TestBestEffortGetsStarved) {
- std::vector<base::PendingTask> tasks = GetTasks(2);
- size_t queue_order[] = {0, 1};
- PushTasks(tasks, queue_order);
- selector_.SetQueuePriority(0,
- RendererTaskQueueSelector::BEST_EFFORT_PRIORITY);
- selector_.SetQueuePriority(1, RendererTaskQueueSelector::NORMAL_PRIORITY);
- size_t chosen_queue_index = 0;
- for (int i = 0; i < 100; i++) {
- EXPECT_TRUE(selector_.SelectWorkQueueToService(&chosen_queue_index));
- EXPECT_EQ(1ul, chosen_queue_index);
- // Don't remove task from queue to simulate all queues still being full.
- }
- selector_.SetQueuePriority(1, RendererTaskQueueSelector::HIGH_PRIORITY);
- for (int i = 0; i < 100; i++) {
- EXPECT_TRUE(selector_.SelectWorkQueueToService(&chosen_queue_index));
- EXPECT_EQ(1ul, chosen_queue_index);
- // Don't remove task from queue to simulate all queues still being full.
- }
- selector_.SetQueuePriority(1, RendererTaskQueueSelector::CONTROL_PRIORITY);
- for (int i = 0; i < 100; i++) {
- EXPECT_TRUE(selector_.SelectWorkQueueToService(&chosen_queue_index));
- EXPECT_EQ(1ul, chosen_queue_index);
- // Don't remove task from queue to simulate all queues still being full.
- }
-}
-
-} // namespace content
diff --git a/chromium/content/renderer/scheduler/resource_dispatch_throttler.cc b/chromium/content/renderer/scheduler/resource_dispatch_throttler.cc
new file mode 100644
index 00000000000..d2f79165076
--- /dev/null
+++ b/chromium/content/renderer/scheduler/resource_dispatch_throttler.cc
@@ -0,0 +1,146 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/scheduler/resource_dispatch_throttler.h"
+
+#include "base/auto_reset.h"
+#include "base/trace_event/trace_event.h"
+#include "components/scheduler/renderer/renderer_scheduler.h"
+#include "content/common/resource_messages.h"
+#include "ipc/ipc_message_macros.h"
+
+namespace content {
+namespace {
+
+bool IsResourceRequest(const IPC::Message& msg) {
+ return msg.type() == ResourceHostMsg_RequestResource::ID;
+}
+
+} // namespace
+
+ResourceDispatchThrottler::ResourceDispatchThrottler(
+ IPC::Sender* proxied_sender,
+ scheduler::RendererScheduler* scheduler,
+ base::TimeDelta flush_period,
+ uint32 max_requests_per_flush)
+ : proxied_sender_(proxied_sender),
+ scheduler_(scheduler),
+ flush_period_(flush_period),
+ max_requests_per_flush_(max_requests_per_flush),
+ flush_timer_(
+ FROM_HERE,
+ flush_period_,
+ base::Bind(&ResourceDispatchThrottler::Flush, base::Unretained(this)),
+ false /* is_repeating */),
+ sent_requests_since_last_flush_(0) {
+ DCHECK(proxied_sender);
+ DCHECK(scheduler);
+ DCHECK_NE(flush_period_, base::TimeDelta());
+ DCHECK(max_requests_per_flush_);
+ flush_timer_.SetTaskRunner(scheduler->LoadingTaskRunner());
+}
+
+ResourceDispatchThrottler::~ResourceDispatchThrottler() {
+ FlushAll();
+}
+
+bool ResourceDispatchThrottler::Send(IPC::Message* msg) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (msg->is_sync()) {
+ // Flush any pending requests, preserving dispatch order between async and
+ // sync requests.
+ FlushAll();
+ return ForwardMessage(msg);
+ }
+
+ // Always defer message forwarding if there are pending messages, ensuring
+ // message dispatch ordering consistency.
+ if (!throttled_messages_.empty()) {
+ TRACE_EVENT_INSTANT0("loader", "ResourceDispatchThrottler::ThrottleMessage",
+ TRACE_EVENT_SCOPE_THREAD);
+ throttled_messages_.push_back(msg);
+ return true;
+ }
+
+ if (!IsResourceRequest(*msg))
+ return ForwardMessage(msg);
+
+ if (!scheduler_->IsHighPriorityWorkAnticipated())
+ return ForwardMessage(msg);
+
+ if (Now() > (last_sent_request_time_ + flush_period_)) {
+ // If sufficient time has passed since the previous send, we can effectively
+ // mark the pipeline as flushed.
+ sent_requests_since_last_flush_ = 0;
+ return ForwardMessage(msg);
+ }
+
+ if (sent_requests_since_last_flush_ < max_requests_per_flush_)
+ return ForwardMessage(msg);
+
+ TRACE_EVENT_INSTANT0("loader", "ResourceDispatchThrottler::ThrottleRequest",
+ TRACE_EVENT_SCOPE_THREAD);
+ throttled_messages_.push_back(msg);
+ ScheduleFlush();
+ return true;
+}
+
+base::TimeTicks ResourceDispatchThrottler::Now() const {
+ return base::TimeTicks::Now();
+}
+
+void ResourceDispatchThrottler::ScheduleFlush() {
+ DCHECK(!flush_timer_.IsRunning());
+ flush_timer_.Reset();
+}
+
+void ResourceDispatchThrottler::Flush() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ TRACE_EVENT1("loader", "ResourceDispatchThrottler::Flush",
+ "total_throttled_messages", throttled_messages_.size());
+ sent_requests_since_last_flush_ = 0;
+
+ // If high-priority work is no longer anticipated, dispatch can be safely
+ // accelerated. Avoid completely flushing in such case in the event that
+ // a large number of requests have been throttled.
+ uint32 max_requests = scheduler_->IsHighPriorityWorkAnticipated()
+ ? max_requests_per_flush_
+ : max_requests_per_flush_ * 2;
+
+ while (!throttled_messages_.empty() &&
+ (sent_requests_since_last_flush_ < max_requests ||
+ !IsResourceRequest(*throttled_messages_.front()))) {
+ IPC::Message* msg = throttled_messages_.front();
+ throttled_messages_.pop_front();
+ ForwardMessage(msg);
+ }
+
+ if (!throttled_messages_.empty())
+ ScheduleFlush();
+}
+
+void ResourceDispatchThrottler::FlushAll() {
+ if (throttled_messages_.empty())
+ return;
+
+ TRACE_EVENT1("loader", "ResourceDispatchThrottler::FlushAll",
+ "total_throttled_messages", throttled_messages_.size());
+ std::deque<IPC::Message*> throttled_messages;
+ throttled_messages.swap(throttled_messages_);
+ for (auto& message : throttled_messages)
+ ForwardMessage(message);
+ // There shouldn't be re-entrancy issues when forwarding an IPC, but validate
+ // as a safeguard.
+ DCHECK(throttled_messages_.empty());
+}
+
+bool ResourceDispatchThrottler::ForwardMessage(IPC::Message* msg) {
+ if (IsResourceRequest(*msg)) {
+ last_sent_request_time_ = Now();
+ ++sent_requests_since_last_flush_;
+ }
+ return proxied_sender_->Send(msg);
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/scheduler/resource_dispatch_throttler.h b/chromium/content/renderer/scheduler/resource_dispatch_throttler.h
new file mode 100644
index 00000000000..66fc78660d9
--- /dev/null
+++ b/chromium/content/renderer/scheduler/resource_dispatch_throttler.h
@@ -0,0 +1,72 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_SCHEDULER_RESOURCE_DISPATCH_THROTTLER_H_
+#define CONTENT_RENDERER_SCHEDULER_RESOURCE_DISPATCH_THROTTLER_H_
+
+#include <deque>
+
+#include "base/threading/thread_checker.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+#include "content/common/content_export.h"
+#include "ipc/ipc_sender.h"
+
+namespace scheduler {
+class RendererScheduler;
+}
+
+namespace content {
+
+// Utility class for throttling a stream of resource requests targetted to a
+// specific IPC sender. The throttling itself is very basic:
+// * When there is no high-priority work imminent to the main thread, as
+// indicated by the RendererScheduler, throttling is disabled.
+// * When >= N requests have been sent in a given time window, requests are
+// throttled. A timer periodically flushes a portion of the queued requests
+// until all such requests have been flushed.
+// TODO(jdduke): Remove this class after resource requests become sufficiently
+// cheap on the IO thread, crbug.com/440037.
+class CONTENT_EXPORT ResourceDispatchThrottler : public IPC::Sender {
+ public:
+ // |flush_period| and |max_requests_per_flush| must be strictly positive
+ // in duration/value.
+ ResourceDispatchThrottler(IPC::Sender* proxied_sender,
+ scheduler::RendererScheduler* scheduler,
+ base::TimeDelta flush_period,
+ uint32 max_requests_per_flush);
+ ~ResourceDispatchThrottler() override;
+
+ // IPC::Sender implementation:
+ bool Send(IPC::Message* msg) override;
+
+ private:
+ friend class ResourceDispatchThrottlerForTest;
+
+ // Virtual for testing.
+ virtual base::TimeTicks Now() const;
+ virtual void ScheduleFlush();
+
+ void Flush();
+ void FlushAll();
+ bool ForwardMessage(IPC::Message* msg);
+
+ base::ThreadChecker thread_checker_;
+
+ IPC::Sender* const proxied_sender_;
+ scheduler::RendererScheduler* const scheduler_;
+ const base::TimeDelta flush_period_;
+ const uint32 max_requests_per_flush_;
+
+ base::Timer flush_timer_;
+ base::TimeTicks last_sent_request_time_;
+ uint32 sent_requests_since_last_flush_;
+ std::deque<IPC::Message*> throttled_messages_;
+
+ DISALLOW_COPY_AND_ASSIGN(ResourceDispatchThrottler);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_SCHEDULER_RESOURCE_DISPATCH_THROTTLER_H_
diff --git a/chromium/content/renderer/scheduler/resource_dispatch_throttler_unittest.cc b/chromium/content/renderer/scheduler/resource_dispatch_throttler_unittest.cc
new file mode 100644
index 00000000000..8b9dc14fc75
--- /dev/null
+++ b/chromium/content/renderer/scheduler/resource_dispatch_throttler_unittest.cc
@@ -0,0 +1,370 @@
+// Copyright 2014 The Chromium Authors. 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/renderer/scheduler/resource_dispatch_throttler.h"
+
+#include "base/memory/scoped_vector.h"
+#include "content/common/resource_messages.h"
+#include "content/test/fake_renderer_scheduler.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+namespace {
+
+const uint32 kRequestsPerFlush = 4;
+const double kFlushPeriodSeconds = 1.f / 60;
+const int kRoutingId = 1;
+
+typedef ScopedVector<IPC::Message> ScopedMessages;
+
+int GetRequestId(const IPC::Message& msg) {
+ int request_id = -1;
+ switch (msg.type()) {
+ case ResourceHostMsg_RequestResource::ID: {
+ PickleIterator iter(msg);
+ int routing_id = -1;
+ if (!iter.ReadInt(&routing_id) || !iter.ReadInt(&request_id))
+ NOTREACHED() << "Invalid id for resource request message.";
+ } break;
+
+ case ResourceHostMsg_DidChangePriority::ID:
+ case ResourceHostMsg_ReleaseDownloadedFile::ID:
+ case ResourceHostMsg_CancelRequest::ID:
+ if (!PickleIterator(msg).ReadInt(&request_id))
+ NOTREACHED() << "Invalid id for resource message.";
+ break;
+
+ default:
+ NOTREACHED() << "Invalid message for resource throttling.";
+ break;
+ }
+ return request_id;
+}
+
+class RendererSchedulerForTest : public FakeRendererScheduler {
+ public:
+ RendererSchedulerForTest() : high_priority_work_anticipated_(false) {}
+ ~RendererSchedulerForTest() override {}
+
+ // RendererScheduler implementation:
+ bool IsHighPriorityWorkAnticipated() override {
+ return high_priority_work_anticipated_;
+ }
+
+ void set_high_priority_work_anticipated(bool anticipated) {
+ high_priority_work_anticipated_ = anticipated;
+ }
+
+ private:
+ bool high_priority_work_anticipated_;
+};
+
+} // namespace
+
+class ResourceDispatchThrottlerForTest : public ResourceDispatchThrottler {
+ public:
+ ResourceDispatchThrottlerForTest(IPC::Sender* sender,
+ scheduler::RendererScheduler* scheduler)
+ : ResourceDispatchThrottler(
+ sender,
+ scheduler,
+ base::TimeDelta::FromSecondsD(kFlushPeriodSeconds),
+ kRequestsPerFlush),
+ flush_scheduled_(false) {}
+ ~ResourceDispatchThrottlerForTest() override {}
+
+ void Advance(base::TimeDelta delta) { now_ += delta; }
+
+ bool RunScheduledFlush() {
+ if (!flush_scheduled_)
+ return false;
+
+ flush_scheduled_ = false;
+ Flush();
+ return true;
+ }
+
+ bool flush_scheduled() const { return flush_scheduled_; }
+
+ private:
+ // ResourceDispatchThrottler overrides:
+ base::TimeTicks Now() const override { return now_; }
+ void ScheduleFlush() override { flush_scheduled_ = true; }
+
+ base::TimeTicks now_;
+ bool flush_scheduled_;
+};
+
+class ResourceDispatchThrottlerTest : public testing::Test, public IPC::Sender {
+ public:
+ ResourceDispatchThrottlerTest() : last_request_id_(0) {
+ throttler_.reset(new ResourceDispatchThrottlerForTest(this, &scheduler_));
+ }
+ ~ResourceDispatchThrottlerTest() override {}
+
+ // IPC::Sender implementation:
+ bool Send(IPC::Message* msg) override {
+ sent_messages_.push_back(msg);
+ return true;
+ }
+
+ protected:
+ void SetHighPriorityWorkAnticipated(bool anticipated) {
+ scheduler_.set_high_priority_work_anticipated(anticipated);
+ }
+
+ void Advance(base::TimeDelta delta) { throttler_->Advance(delta); }
+
+ bool RunScheduledFlush() { return throttler_->RunScheduledFlush(); }
+
+ bool FlushScheduled() { return throttler_->flush_scheduled(); }
+
+ bool RequestResource() {
+ ResourceHostMsg_Request request;
+ request.download_to_file = true;
+ return throttler_->Send(new ResourceHostMsg_RequestResource(
+ kRoutingId, ++last_request_id_, request));
+ }
+
+ bool RequestResourceSync() {
+ SyncLoadResult result;
+ return throttler_->Send(new ResourceHostMsg_SyncLoad(
+ kRoutingId, ++last_request_id_, ResourceHostMsg_Request(), &result));
+ }
+
+ void RequestResourcesUntilThrottled() {
+ SetHighPriorityWorkAnticipated(true);
+ GetAndResetSentMessageCount();
+ RequestResource();
+ while (GetAndResetSentMessageCount())
+ RequestResource();
+ }
+
+ bool UpdateRequestPriority(int request_id, net::RequestPriority priority) {
+ return throttler_->Send(
+ new ResourceHostMsg_DidChangePriority(request_id, priority, 0));
+ }
+
+ bool ReleaseDownloadedFile(int request_id) {
+ return throttler_->Send(
+ new ResourceHostMsg_ReleaseDownloadedFile(request_id));
+ }
+
+ bool CancelRequest(int request_id) {
+ return throttler_->Send(new ResourceHostMsg_CancelRequest(request_id));
+ }
+
+ size_t GetAndResetSentMessageCount() {
+ size_t sent_message_count = sent_messages_.size();
+ sent_messages_.clear();
+ return sent_message_count;
+ }
+
+ const IPC::Message* LastSentMessage() const {
+ return sent_messages_.empty() ? nullptr : sent_messages_.back();
+ }
+
+ int LastSentRequestId() const {
+ const IPC::Message* msg = LastSentMessage();
+ if (!msg)
+ return -1;
+
+ int routing_id = -1;
+ int request_id = -1;
+ PickleIterator iter(*msg);
+ CHECK(IPC::ReadParam(msg, &iter, &routing_id));
+ CHECK(IPC::ReadParam(msg, &iter, &request_id));
+ return request_id;
+ }
+
+ int last_request_id() const { return last_request_id_; }
+
+ ScopedMessages sent_messages_;
+
+ private:
+ scoped_ptr<ResourceDispatchThrottlerForTest> throttler_;
+ RendererSchedulerForTest scheduler_;
+ int last_request_id_;
+ bool flush_scheduled_;
+
+ DISALLOW_COPY_AND_ASSIGN(ResourceDispatchThrottlerTest);
+};
+
+TEST_F(ResourceDispatchThrottlerTest, NotThrottledByDefault) {
+ SetHighPriorityWorkAnticipated(false);
+ for (size_t i = 0; i < kRequestsPerFlush * 2; ++i) {
+ RequestResource();
+ EXPECT_EQ(i + 1, sent_messages_.size());
+ }
+}
+
+TEST_F(ResourceDispatchThrottlerTest, NotThrottledIfSendLimitNotReached) {
+ SetHighPriorityWorkAnticipated(true);
+ for (size_t i = 0; i < kRequestsPerFlush; ++i) {
+ RequestResource();
+ EXPECT_EQ(i + 1, sent_messages_.size());
+ }
+}
+
+TEST_F(ResourceDispatchThrottlerTest, ThrottledWhenHighPriorityWork) {
+ SetHighPriorityWorkAnticipated(true);
+ for (size_t i = 0; i < kRequestsPerFlush; ++i)
+ RequestResource();
+ ASSERT_EQ(kRequestsPerFlush, GetAndResetSentMessageCount());
+
+ RequestResource();
+ EXPECT_EQ(0U, sent_messages_.size());
+
+ EXPECT_TRUE(RunScheduledFlush());
+ EXPECT_EQ(1U, sent_messages_.size());
+}
+
+TEST_F(ResourceDispatchThrottlerTest,
+ ThrottledWhenDeferredMessageQueueNonEmpty) {
+ SetHighPriorityWorkAnticipated(true);
+ for (size_t i = 0; i < kRequestsPerFlush; ++i)
+ RequestResource();
+ ASSERT_EQ(kRequestsPerFlush, GetAndResetSentMessageCount());
+
+ RequestResource();
+ EXPECT_EQ(0U, sent_messages_.size());
+ SetHighPriorityWorkAnticipated(false);
+ RequestResource();
+ EXPECT_EQ(0U, sent_messages_.size());
+
+ EXPECT_TRUE(RunScheduledFlush());
+ EXPECT_EQ(2U, sent_messages_.size());
+}
+
+TEST_F(ResourceDispatchThrottlerTest, NotThrottledIfSufficientTimePassed) {
+ SetHighPriorityWorkAnticipated(true);
+
+ for (size_t i = 0; i < kRequestsPerFlush * 2; ++i) {
+ Advance(base::TimeDelta::FromSecondsD(kFlushPeriodSeconds * 2));
+ RequestResource();
+ EXPECT_EQ(1U, GetAndResetSentMessageCount());
+ EXPECT_FALSE(FlushScheduled());
+ }
+}
+
+TEST_F(ResourceDispatchThrottlerTest, NotThrottledIfSyncMessage) {
+ SetHighPriorityWorkAnticipated(true);
+
+ RequestResourceSync();
+ EXPECT_EQ(1U, GetAndResetSentMessageCount());
+
+ // Saturate the queue.
+ for (size_t i = 0; i < kRequestsPerFlush * 2; ++i)
+ RequestResource();
+ ASSERT_EQ(kRequestsPerFlush, GetAndResetSentMessageCount());
+
+ // Synchronous messages should flush any previously throttled messages.
+ RequestResourceSync();
+ EXPECT_EQ(1U + kRequestsPerFlush, GetAndResetSentMessageCount());
+ RequestResourceSync();
+ EXPECT_EQ(1U, GetAndResetSentMessageCount());
+
+ // Previously throttled messages should already have been flushed.
+ RunScheduledFlush();
+ EXPECT_EQ(0U, GetAndResetSentMessageCount());
+}
+
+TEST_F(ResourceDispatchThrottlerTest, MultipleFlushes) {
+ SetHighPriorityWorkAnticipated(true);
+ for (size_t i = 0; i < kRequestsPerFlush * 4; ++i)
+ RequestResource();
+ ASSERT_EQ(kRequestsPerFlush, GetAndResetSentMessageCount());
+
+ for (size_t i = 0; i < 3; ++i) {
+ SCOPED_TRACE(i);
+ EXPECT_TRUE(RunScheduledFlush());
+ EXPECT_EQ(kRequestsPerFlush, GetAndResetSentMessageCount());
+ }
+
+ EXPECT_FALSE(FlushScheduled());
+ EXPECT_EQ(0U, sent_messages_.size());
+}
+
+TEST_F(ResourceDispatchThrottlerTest, MultipleFlushesWhileReceiving) {
+ SetHighPriorityWorkAnticipated(true);
+ for (size_t i = 0; i < kRequestsPerFlush * 4; ++i)
+ RequestResource();
+ ASSERT_EQ(kRequestsPerFlush, GetAndResetSentMessageCount());
+
+ for (size_t i = 0; i < 3; ++i) {
+ SCOPED_TRACE(i);
+ EXPECT_TRUE(RunScheduledFlush());
+ EXPECT_EQ(kRequestsPerFlush, GetAndResetSentMessageCount());
+ for (size_t j = 0; j < kRequestsPerFlush; ++j)
+ RequestResource();
+ EXPECT_EQ(0U, sent_messages_.size());
+ }
+
+ for (size_t i = 0; i < 3; ++i) {
+ EXPECT_TRUE(RunScheduledFlush());
+ EXPECT_EQ(kRequestsPerFlush, GetAndResetSentMessageCount());
+ }
+
+ EXPECT_FALSE(FlushScheduled());
+ EXPECT_EQ(0U, sent_messages_.size());
+}
+
+TEST_F(ResourceDispatchThrottlerTest, NonRequestsNeverTriggerThrottling) {
+ RequestResource();
+ ASSERT_EQ(1U, GetAndResetSentMessageCount());
+
+ for (size_t i = 0; i < kRequestsPerFlush * 3; ++i)
+ UpdateRequestPriority(last_request_id(), net::HIGHEST);
+ EXPECT_EQ(kRequestsPerFlush * 3, sent_messages_.size());
+
+ RequestResource();
+ EXPECT_EQ(1U + kRequestsPerFlush * 3, GetAndResetSentMessageCount());
+}
+
+TEST_F(ResourceDispatchThrottlerTest, NonRequestsDeferredWhenThrottling) {
+ RequestResource();
+ ASSERT_EQ(1U, GetAndResetSentMessageCount());
+
+ RequestResourcesUntilThrottled();
+ UpdateRequestPriority(last_request_id(), net::HIGHEST);
+ ReleaseDownloadedFile(last_request_id());
+ CancelRequest(last_request_id());
+
+ EXPECT_TRUE(RunScheduledFlush());
+ EXPECT_EQ(4U, GetAndResetSentMessageCount());
+ EXPECT_FALSE(FlushScheduled());
+}
+
+TEST_F(ResourceDispatchThrottlerTest, MessageOrderingPreservedWhenThrottling) {
+ SetHighPriorityWorkAnticipated(true);
+ for (size_t i = 0; i < kRequestsPerFlush; ++i)
+ RequestResource();
+ ASSERT_EQ(kRequestsPerFlush, GetAndResetSentMessageCount());
+
+ for (size_t i = 0; i < kRequestsPerFlush; ++i) {
+ RequestResource();
+ UpdateRequestPriority(last_request_id(), net::HIGHEST);
+ CancelRequest(last_request_id() - 1);
+ }
+ ASSERT_EQ(0U, sent_messages_.size());
+
+ EXPECT_TRUE(RunScheduledFlush());
+ ASSERT_EQ(kRequestsPerFlush * 3, sent_messages_.size());
+ for (size_t i = 0; i < sent_messages_.size(); i += 3) {
+ SCOPED_TRACE(i);
+ const auto& request_msg = *sent_messages_[i];
+ const auto& priority_msg = *sent_messages_[i + 1];
+ const auto& cancel_msg = *sent_messages_[i + 2];
+
+ EXPECT_EQ(request_msg.type(), ResourceHostMsg_RequestResource::ID);
+ EXPECT_EQ(priority_msg.type(), ResourceHostMsg_DidChangePriority::ID);
+ EXPECT_EQ(cancel_msg.type(), ResourceHostMsg_CancelRequest::ID);
+
+ EXPECT_EQ(GetRequestId(request_msg), GetRequestId(priority_msg));
+ EXPECT_EQ(GetRequestId(request_msg) - 1, GetRequestId(cancel_msg));
+ }
+ EXPECT_FALSE(FlushScheduled());
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/scheduler/single_thread_idle_task_runner.cc b/chromium/content/renderer/scheduler/single_thread_idle_task_runner.cc
deleted file mode 100644
index 56cf0e9e5b8..00000000000
--- a/chromium/content/renderer/scheduler/single_thread_idle_task_runner.cc
+++ /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.
-
-#include "content/renderer/scheduler/single_thread_idle_task_runner.h"
-
-#include "base/location.h"
-
-namespace content {
-
-SingleThreadIdleTaskRunner::SingleThreadIdleTaskRunner(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- base::Callback<void(base::TimeTicks*)> deadline_supplier)
- : task_runner_(task_runner), deadline_supplier_(deadline_supplier) {
-}
-
-SingleThreadIdleTaskRunner::~SingleThreadIdleTaskRunner() {
-}
-
-bool SingleThreadIdleTaskRunner::RunsTasksOnCurrentThread() const {
- return task_runner_->RunsTasksOnCurrentThread();
-}
-
-void SingleThreadIdleTaskRunner::PostIdleTask(
- const tracked_objects::Location& from_here,
- const IdleTask& idle_task) {
- task_runner_->PostTask(
- from_here,
- base::Bind(&SingleThreadIdleTaskRunner::RunTask, this, idle_task));
-}
-
-void SingleThreadIdleTaskRunner::RunTask(IdleTask idle_task) {
- base::TimeTicks deadline;
- deadline_supplier_.Run(&deadline);
- idle_task.Run(deadline);
-}
-
-} // namespace content
diff --git a/chromium/content/renderer/scheduler/single_thread_idle_task_runner.h b/chromium/content/renderer/scheduler/single_thread_idle_task_runner.h
deleted file mode 100644
index 79002438781..00000000000
--- a/chromium/content/renderer/scheduler/single_thread_idle_task_runner.h
+++ /dev/null
@@ -1,49 +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_RENDERER_SCHEDULER_SINGLE_THREAD_IDLE_TASK_RUNNER_H_
-#define CONTENT_RENDERER_SCHEDULER_SINGLE_THREAD_IDLE_TASK_RUNNER_H_
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/memory/ref_counted.h"
-#include "base/single_thread_task_runner.h"
-#include "base/time/time.h"
-
-namespace content {
-
-// A SingleThreadIdleTaskRunner is a task runner for running idle tasks. Idle
-// tasks have an unbound argument which is bound to a deadline
-// (in base::TimeTicks) when they are run. The idle task is expected to
-// complete by this deadline.
-class SingleThreadIdleTaskRunner
- : public base::RefCountedThreadSafe<SingleThreadIdleTaskRunner> {
- public:
- typedef base::Callback<void(base::TimeTicks)> IdleTask;
-
- SingleThreadIdleTaskRunner(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- base::Callback<void(base::TimeTicks*)> deadline_supplier);
-
- virtual void PostIdleTask(const tracked_objects::Location& from_here,
- const IdleTask& idle_task);
-
- bool RunsTasksOnCurrentThread() const;
-
- protected:
- virtual ~SingleThreadIdleTaskRunner();
-
- private:
- friend class base::RefCountedThreadSafe<SingleThreadIdleTaskRunner>;
-
- void RunTask(IdleTask idle_task);
-
- scoped_refptr<base::TaskRunner> task_runner_;
- base::Callback<void(base::TimeTicks*)> deadline_supplier_;
- DISALLOW_COPY_AND_ASSIGN(SingleThreadIdleTaskRunner);
-};
-
-} // namespace content
-
-#endif // CONTENT_RENDERER_SCHEDULER_SINGLE_THREAD_IDLE_TASK_RUNNER_H_
diff --git a/chromium/content/renderer/scheduler/task_queue_manager.cc b/chromium/content/renderer/scheduler/task_queue_manager.cc
deleted file mode 100644
index 658aef72060..00000000000
--- a/chromium/content/renderer/scheduler/task_queue_manager.cc
+++ /dev/null
@@ -1,294 +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/renderer/scheduler/task_queue_manager.h"
-
-#include "base/bind.h"
-#include "base/debug/trace_event.h"
-#include "content/renderer/scheduler/task_queue_selector.h"
-
-namespace content {
-namespace internal {
-
-class TaskQueue : public base::SingleThreadTaskRunner {
- public:
- TaskQueue(TaskQueueManager* task_queue_manager);
-
- // base::SingleThreadTaskRunner implementation.
- bool RunsTasksOnCurrentThread() const override;
- 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;
-
- // Adds a task at the end of the incoming task queue and schedules a call to
- // TaskQueueManager::DoWork() if the incoming queue was empty and automatic
- // pumping is enabled. Can be called on an arbitrary thread.
- void EnqueueTask(const base::PendingTask& pending_task);
-
- bool IsQueueEmpty() const;
-
- void SetAutoPump(bool auto_pump);
- void PumpQueue();
-
- bool UpdateWorkQueue();
- base::PendingTask TakeTaskFromWorkQueue();
-
- void WillDeleteTaskQueueManager();
-
- base::TaskQueue& work_queue() { return work_queue_; }
-
- private:
- ~TaskQueue() override;
-
- void PumpQueueLocked();
- void EnqueueTaskLocked(const base::PendingTask& pending_task);
-
- // This lock protects all members except the work queue.
- mutable base::Lock lock_;
- TaskQueueManager* task_queue_manager_;
- base::TaskQueue incoming_queue_;
- bool auto_pump_;
-
- base::TaskQueue work_queue_;
-
- DISALLOW_COPY_AND_ASSIGN(TaskQueue);
-};
-
-TaskQueue::TaskQueue(TaskQueueManager* task_queue_manager)
- : task_queue_manager_(task_queue_manager), auto_pump_(true) {
-}
-
-TaskQueue::~TaskQueue() {
-}
-
-void TaskQueue::WillDeleteTaskQueueManager() {
- base::AutoLock lock(lock_);
- task_queue_manager_ = nullptr;
-}
-
-bool TaskQueue::RunsTasksOnCurrentThread() const {
- base::AutoLock lock(lock_);
- if (!task_queue_manager_)
- return false;
- return task_queue_manager_->RunsTasksOnCurrentThread();
-}
-
-bool TaskQueue::PostDelayedTask(const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta delay) {
- base::AutoLock lock(lock_);
- if (!task_queue_manager_)
- return false;
-
- base::PendingTask pending_task(from_here, task);
- task_queue_manager_->DidQueueTask(&pending_task);
-
- if (delay > base::TimeDelta()) {
- return task_queue_manager_->PostDelayedTask(
- from_here, Bind(&TaskQueue::EnqueueTask, this, pending_task), delay);
- }
- EnqueueTaskLocked(pending_task);
- return true;
-}
-
-bool TaskQueue::PostNonNestableDelayedTask(
- const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta delay) {
- base::AutoLock lock(lock_);
- if (!task_queue_manager_)
- return false;
- return task_queue_manager_->PostNonNestableDelayedTask(
- from_here, task, delay);
-}
-
-bool TaskQueue::IsQueueEmpty() const {
- if (!work_queue_.empty())
- return false;
-
- {
- base::AutoLock lock(lock_);
- return incoming_queue_.empty();
- }
-}
-
-bool TaskQueue::UpdateWorkQueue() {
- if (!work_queue_.empty())
- return true;
-
- {
- base::AutoLock lock(lock_);
- if (!auto_pump_ || incoming_queue_.empty())
- return false;
- work_queue_.Swap(&incoming_queue_);
- return true;
- }
-}
-
-base::PendingTask TaskQueue::TakeTaskFromWorkQueue() {
- base::PendingTask pending_task = work_queue_.front();
- work_queue_.pop();
- return pending_task;
-}
-
-void TaskQueue::EnqueueTask(const base::PendingTask& pending_task) {
- base::AutoLock lock(lock_);
- EnqueueTaskLocked(pending_task);
-}
-
-void TaskQueue::EnqueueTaskLocked(const base::PendingTask& pending_task) {
- lock_.AssertAcquired();
- if (!task_queue_manager_)
- return;
- if (auto_pump_ && incoming_queue_.empty())
- task_queue_manager_->PostDoWorkOnMainRunner();
- incoming_queue_.push(pending_task);
-}
-
-void TaskQueue::SetAutoPump(bool auto_pump) {
- base::AutoLock lock(lock_);
- if (auto_pump) {
- auto_pump_ = true;
- PumpQueueLocked();
- } else {
- auto_pump_ = false;
- }
-}
-
-void TaskQueue::PumpQueueLocked() {
- lock_.AssertAcquired();
- while (!incoming_queue_.empty()) {
- work_queue_.push(incoming_queue_.front());
- incoming_queue_.pop();
- }
- if (!work_queue_.empty())
- task_queue_manager_->PostDoWorkOnMainRunner();
-}
-
-void TaskQueue::PumpQueue() {
- base::AutoLock lock(lock_);
- PumpQueueLocked();
-}
-
-} // namespace
-
-TaskQueueManager::TaskQueueManager(
- size_t task_queue_count,
- scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
- TaskQueueSelector* selector)
- : main_task_runner_(main_task_runner),
- selector_(selector),
- weak_factory_(this) {
- DCHECK(main_task_runner->RunsTasksOnCurrentThread());
-
- task_queue_manager_weak_ptr_ = weak_factory_.GetWeakPtr();
- for (size_t i = 0; i < task_queue_count; i++) {
- scoped_refptr<internal::TaskQueue> queue(
- make_scoped_refptr(new internal::TaskQueue(this)));
- queues_.push_back(queue);
- }
-
- std::vector<const base::TaskQueue*> work_queues;
- for (const auto& queue: queues_)
- work_queues.push_back(&queue->work_queue());
- selector_->RegisterWorkQueues(work_queues);
-}
-
-TaskQueueManager::~TaskQueueManager() {
- for (auto& queue : queues_)
- queue->WillDeleteTaskQueueManager();
-}
-
-internal::TaskQueue* TaskQueueManager::Queue(size_t queue_index) const {
- DCHECK_LT(queue_index, queues_.size());
- return queues_[queue_index].get();
-}
-
-scoped_refptr<base::SingleThreadTaskRunner>
-TaskQueueManager::TaskRunnerForQueue(size_t queue_index) const {
- return Queue(queue_index);
-}
-
-bool TaskQueueManager::IsQueueEmpty(size_t queue_index) const {
- internal::TaskQueue* queue = Queue(queue_index);
- return queue->IsQueueEmpty();
-}
-
-void TaskQueueManager::SetAutoPump(size_t queue_index, bool auto_pump) {
- main_thread_checker_.CalledOnValidThread();
- internal::TaskQueue* queue = Queue(queue_index);
- queue->SetAutoPump(auto_pump);
-}
-
-void TaskQueueManager::PumpQueue(size_t queue_index) {
- main_thread_checker_.CalledOnValidThread();
- internal::TaskQueue* queue = Queue(queue_index);
- queue->PumpQueue();
-}
-
-bool TaskQueueManager::UpdateWorkQueues() {
- // TODO(skyostil): This is not efficient when the number of queues grows very
- // large due to the number of locks taken. Consider optimizing when we get
- // there.
- main_thread_checker_.CalledOnValidThread();
- bool has_work = false;
- for (auto& queue : queues_)
- has_work |= queue->UpdateWorkQueue();
- return has_work;
-}
-
-void TaskQueueManager::PostDoWorkOnMainRunner() {
- main_task_runner_->PostTask(
- FROM_HERE, Bind(&TaskQueueManager::DoWork, task_queue_manager_weak_ptr_));
-}
-
-void TaskQueueManager::DoWork() {
- main_thread_checker_.CalledOnValidThread();
- if (!UpdateWorkQueues())
- return;
-
- size_t queue_index;
- if (!selector_->SelectWorkQueueToService(&queue_index))
- return;
- PostDoWorkOnMainRunner();
- RunTaskFromWorkQueue(queue_index);
-}
-
-void TaskQueueManager::DidQueueTask(base::PendingTask* pending_task) {
- pending_task->sequence_num = task_sequence_num_.GetNext();
- task_annotator_.DidQueueTask("TaskQueueManager::PostTask", *pending_task);
-}
-
-void TaskQueueManager::RunTaskFromWorkQueue(size_t queue_index) {
- main_thread_checker_.CalledOnValidThread();
- internal::TaskQueue* queue = Queue(queue_index);
- base::PendingTask pending_task = queue->TakeTaskFromWorkQueue();
- task_annotator_.RunTask(
- "TaskQueueManager::PostTask", "TaskQueueManager::RunTask", pending_task);
-}
-
-bool TaskQueueManager::RunsTasksOnCurrentThread() const {
- return main_task_runner_->RunsTasksOnCurrentThread();
-}
-
-bool TaskQueueManager::PostDelayedTask(
- const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta delay) {
- DCHECK(delay > base::TimeDelta());
- return main_task_runner_->PostDelayedTask(from_here, task, delay);
-}
-
-bool TaskQueueManager::PostNonNestableDelayedTask(
- const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta delay) {
- // Defer non-nestable work to the main task runner.
- return main_task_runner_->PostNonNestableDelayedTask(from_here, task, delay);
-}
-
-} // namespace content
diff --git a/chromium/content/renderer/scheduler/task_queue_manager.h b/chromium/content/renderer/scheduler/task_queue_manager.h
deleted file mode 100644
index b1b79357ad3..00000000000
--- a/chromium/content/renderer/scheduler/task_queue_manager.h
+++ /dev/null
@@ -1,118 +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_RENDERER_SCHEDULER_TASK_QUEUE_MANAGER_H_
-#define CONTENT_RENDERER_SCHEDULER_TASK_QUEUE_MANAGER_H_
-
-#include "base/atomic_sequence_num.h"
-#include "base/debug/task_annotator.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/pending_task.h"
-#include "base/single_thread_task_runner.h"
-#include "base/synchronization/lock.h"
-#include "base/threading/thread_checker.h"
-#include "content/common/content_export.h"
-
-namespace content {
-namespace internal {
-class TaskQueue;
-}
-class TaskQueueSelector;
-
-// The task queue manager provides N task queues and a selector interface for
-// choosing which task queue to service next. Each task queue consists of two
-// sub queues:
-//
-// 1. Incoming task queue. Tasks that are posted get immediately appended here.
-// When a task is appended into an empty incoming queue, the task manager
-// work function (DoWork) is scheduled to run on the main task runner.
-//
-// 2. Work queue. If a work queue is empty when DoWork() is entered, tasks from
-// the incoming task queue (if any) are moved here. The work queues are
-// registered with the selector as input to the scheduling decision.
-//
-class CONTENT_EXPORT TaskQueueManager {
- public:
- // Create a task queue manager with |task_queue_count| task queues.
- // |main_task_runner| identifies the thread on which where the tasks are
- // eventually run. |selector| is used to choose which task queue to service.
- // It should outlive this class.
- TaskQueueManager(size_t task_queue_count,
- scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
- TaskQueueSelector* selector);
- ~TaskQueueManager();
-
- // Returns the task runner which targets the queue selected by |queue_index|.
- scoped_refptr<base::SingleThreadTaskRunner> TaskRunnerForQueue(
- size_t queue_index) const;
-
- // If |auto_pump| is false, tasks posted to the given incoming queue will not
- // be automatically scheduled for execution or transferred to the work queue.
- // Instead, the selector should call PumpQueue() when necessary to bring in
- // new tasks for execution.
- void SetAutoPump(size_t queue_index, bool auto_pump);
-
- // Reloads new tasks from the incoming queue for |queue_index| into the work
- // queue, regardless of whether the work queue is empty or not. After this,
- // this function ensures that the tasks in the work queue, if any, are
- // scheduled for execution.
- //
- // This function only needs to be called if automatic pumping is disabled
- // for |queue_index|. See |SetQueueAutoPump|. By default automatic pumping is
- // enabled for all queues.
- void PumpQueue(size_t queue_index);
-
- // Returns true if there no tasks in either the work or incoming task queue
- // identified by |queue_index|. Note that this function involves taking a
- // lock, so calling it has some overhead.
- bool IsQueueEmpty(size_t queue_index) const;
-
- private:
- friend class internal::TaskQueue;
-
- // Called by the task queue to register a new pending task and allocate a
- // sequence number for it.
- void DidQueueTask(base::PendingTask* pending_task);
-
- // Post a task to call DoWork() on the main task runner.
- void PostDoWorkOnMainRunner();
-
- // Use the selector to choose a pending task and run it.
- void DoWork();
-
- // Reloads any empty work queues which have automatic pumping enabled.
- // Returns true if any work queue has tasks after doing this.
- bool UpdateWorkQueues();
-
- // Runs a single task from the work queue designated by |queue_index|. The
- // queue must not be empty.
- void RunTaskFromWorkQueue(size_t queue_index);
-
- bool RunsTasksOnCurrentThread() const;
- bool PostDelayedTask(const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta delay);
- bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta delay);
- internal::TaskQueue* Queue(size_t queue_index) const;
-
- std::vector<scoped_refptr<internal::TaskQueue>> queues_;
- base::AtomicSequenceNumber task_sequence_num_;
- base::debug::TaskAnnotator task_annotator_;
-
- base::ThreadChecker main_thread_checker_;
- scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
- TaskQueueSelector* selector_;
-
- base::WeakPtr<TaskQueueManager> task_queue_manager_weak_ptr_;
- base::WeakPtrFactory<TaskQueueManager> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(TaskQueueManager);
-};
-
-} // namespace content
-
-#endif // CONTENT_RENDERER_SCHEDULER_TASK_QUEUE_MANAGER_H_
diff --git a/chromium/content/renderer/scheduler/task_queue_manager_unittest.cc b/chromium/content/renderer/scheduler/task_queue_manager_unittest.cc
deleted file mode 100644
index 43238250180..00000000000
--- a/chromium/content/renderer/scheduler/task_queue_manager_unittest.cc
+++ /dev/null
@@ -1,358 +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/renderer/scheduler/task_queue_manager.h"
-
-#include "base/test/test_simple_task_runner.h"
-#include "base/threading/thread.h"
-#include "content/renderer/scheduler/task_queue_selector.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace content {
-namespace {
-
-class SelectorForTest : public TaskQueueSelector {
- public:
- SelectorForTest() {}
-
- void RegisterWorkQueues(
- const std::vector<const base::TaskQueue*>& work_queues) override {
- work_queues_ = work_queues;
- }
-
- bool SelectWorkQueueToService(size_t* out_queue_index) override {
- if (queues_to_service_.empty())
- return false;
- *out_queue_index = queues_to_service_.front();
- queues_to_service_.pop_front();
- return true;
- }
-
- void AppendQueueToService(size_t queue_index) {
- queues_to_service_.push_back(queue_index);
- }
-
- const std::vector<const base::TaskQueue*>& work_queues() {
- return work_queues_;
- }
-
- private:
- std::deque<size_t> queues_to_service_;
- std::vector<const base::TaskQueue*> work_queues_;
-
- DISALLOW_COPY_AND_ASSIGN(SelectorForTest);
-};
-
-class TaskQueueManagerTest : public testing::Test {
- protected:
- void Initialize(size_t num_queues) {
- test_task_runner_ = make_scoped_refptr(new base::TestSimpleTaskRunner());
- selector_ = make_scoped_ptr(new SelectorForTest);
- manager_ = make_scoped_ptr(
- new TaskQueueManager(num_queues, test_task_runner_, selector_.get()));
- }
-
- scoped_refptr<base::TestSimpleTaskRunner> test_task_runner_;
- scoped_ptr<SelectorForTest> selector_;
- scoped_ptr<TaskQueueManager> manager_;
-};
-
-void TestTask(int value, std::vector<int>* out_result) {
- out_result->push_back(value);
-}
-
-TEST_F(TaskQueueManagerTest, SingleQueuePosting) {
- Initialize(1u);
- EXPECT_EQ(1u, selector_->work_queues().size());
-
- std::vector<int> run_order;
- scoped_refptr<base::SingleThreadTaskRunner> runner =
- manager_->TaskRunnerForQueue(0);
-
- runner->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
- runner->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
- runner->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order));
-
- selector_->AppendQueueToService(0);
- selector_->AppendQueueToService(0);
- selector_->AppendQueueToService(0);
-
- test_task_runner_->RunUntilIdle();
- EXPECT_EQ(1, run_order[0]);
- EXPECT_EQ(2, run_order[1]);
- EXPECT_EQ(3, run_order[2]);
-}
-
-TEST_F(TaskQueueManagerTest, MultiQueuePosting) {
- Initialize(3u);
- EXPECT_EQ(3u, selector_->work_queues().size());
-
- std::vector<int> run_order;
- scoped_refptr<base::SingleThreadTaskRunner> runners[3] = {
- manager_->TaskRunnerForQueue(0),
- manager_->TaskRunnerForQueue(1),
- manager_->TaskRunnerForQueue(2)};
-
- selector_->AppendQueueToService(0);
- selector_->AppendQueueToService(1);
- selector_->AppendQueueToService(2);
- selector_->AppendQueueToService(0);
- selector_->AppendQueueToService(1);
- selector_->AppendQueueToService(2);
-
- runners[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
- runners[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
- runners[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order));
- runners[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 4, &run_order));
- runners[2]->PostTask(FROM_HERE, base::Bind(&TestTask, 5, &run_order));
- runners[2]->PostTask(FROM_HERE, base::Bind(&TestTask, 6, &run_order));
-
- test_task_runner_->RunUntilIdle();
- EXPECT_EQ(1, run_order[0]);
- EXPECT_EQ(3, run_order[1]);
- EXPECT_EQ(5, run_order[2]);
- EXPECT_EQ(2, run_order[3]);
- EXPECT_EQ(4, run_order[4]);
- EXPECT_EQ(6, run_order[5]);
-}
-
-TEST_F(TaskQueueManagerTest, NonNestableTaskPosting) {
- Initialize(1u);
- EXPECT_EQ(1u, selector_->work_queues().size());
-
- std::vector<int> run_order;
- scoped_refptr<base::SingleThreadTaskRunner> runner =
- manager_->TaskRunnerForQueue(0);
-
- runner->PostNonNestableTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
-
- // Non-nestable tasks never make it to the selector.
- test_task_runner_->RunUntilIdle();
- EXPECT_EQ(1, run_order[0]);
-}
-
-TEST_F(TaskQueueManagerTest, QueuePolling) {
- Initialize(1u);
-
- std::vector<int> run_order;
- scoped_refptr<base::SingleThreadTaskRunner> runner =
- manager_->TaskRunnerForQueue(0);
-
- EXPECT_TRUE(manager_->IsQueueEmpty(0));
- runner->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
- EXPECT_FALSE(manager_->IsQueueEmpty(0));
-
- selector_->AppendQueueToService(0);
- test_task_runner_->RunUntilIdle();
- EXPECT_TRUE(manager_->IsQueueEmpty(0));
-}
-
-TEST_F(TaskQueueManagerTest, DelayedTaskPosting) {
- Initialize(1u);
-
- std::vector<int> run_order;
- scoped_refptr<base::SingleThreadTaskRunner> runner =
- manager_->TaskRunnerForQueue(0);
-
- selector_->AppendQueueToService(0);
-
- base::TimeDelta delay(base::TimeDelta::FromMilliseconds(10));
- runner->PostDelayedTask(
- FROM_HERE, base::Bind(&TestTask, 1, &run_order), delay);
- EXPECT_EQ(delay, test_task_runner_->NextPendingTaskDelay());
- EXPECT_TRUE(manager_->IsQueueEmpty(0));
- EXPECT_TRUE(run_order.empty());
-
- // The task is inserted to the incoming queue only after the delay.
- test_task_runner_->RunPendingTasks();
- EXPECT_FALSE(manager_->IsQueueEmpty(0));
- EXPECT_TRUE(run_order.empty());
-
- // After the delay the task runs normally.
- selector_->AppendQueueToService(0);
- test_task_runner_->RunUntilIdle();
- EXPECT_EQ(1, run_order[0]);
-}
-
-TEST_F(TaskQueueManagerTest, ManualPumping) {
- Initialize(1u);
- manager_->SetAutoPump(0, false);
-
- std::vector<int> run_order;
- scoped_refptr<base::SingleThreadTaskRunner> runner =
- manager_->TaskRunnerForQueue(0);
-
- // Posting a task when pumping is disabled doesn't result in work getting
- // posted.
- runner->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
- EXPECT_FALSE(test_task_runner_->HasPendingTask());
-
- // However polling still works.
- EXPECT_FALSE(manager_->IsQueueEmpty(0));
-
- // After pumping the task runs normally.
- manager_->PumpQueue(0);
- EXPECT_TRUE(test_task_runner_->HasPendingTask());
- selector_->AppendQueueToService(0);
- test_task_runner_->RunUntilIdle();
- EXPECT_EQ(1, run_order[0]);
-}
-
-TEST_F(TaskQueueManagerTest, ManualPumpingToggle) {
- Initialize(1u);
- manager_->SetAutoPump(0, false);
-
- std::vector<int> run_order;
- scoped_refptr<base::SingleThreadTaskRunner> runner =
- manager_->TaskRunnerForQueue(0);
-
- // Posting a task when pumping is disabled doesn't result in work getting
- // posted.
- runner->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
- EXPECT_FALSE(test_task_runner_->HasPendingTask());
-
- // When pumping is enabled the task runs normally.
- manager_->SetAutoPump(0, true);
- EXPECT_TRUE(test_task_runner_->HasPendingTask());
- selector_->AppendQueueToService(0);
- test_task_runner_->RunUntilIdle();
- EXPECT_EQ(1, run_order[0]);
-}
-
-TEST_F(TaskQueueManagerTest, DenyRunning) {
- Initialize(1u);
-
- std::vector<int> run_order;
- scoped_refptr<base::SingleThreadTaskRunner> runner =
- manager_->TaskRunnerForQueue(0);
- runner->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
-
- // Since we haven't appended a work queue to be selected, the task doesn't
- // run.
- test_task_runner_->RunUntilIdle();
- EXPECT_TRUE(run_order.empty());
-
- // Pumping the queue again with a selected work queue runs the task.
- manager_->PumpQueue(0);
- selector_->AppendQueueToService(0);
- test_task_runner_->RunUntilIdle();
- EXPECT_EQ(1, run_order[0]);
-}
-
-TEST_F(TaskQueueManagerTest, ManualPumpingWithDelayedTask) {
- Initialize(1u);
- manager_->SetAutoPump(0, false);
-
- std::vector<int> run_order;
- scoped_refptr<base::SingleThreadTaskRunner> runner =
- manager_->TaskRunnerForQueue(0);
-
- // Posting a delayed task when pumping will apply the delay, but won't cause
- // work to executed afterwards.
- base::TimeDelta delay(base::TimeDelta::FromMilliseconds(10));
- runner->PostDelayedTask(
- FROM_HERE, base::Bind(&TestTask, 1, &run_order), delay);
- test_task_runner_->RunUntilIdle();
- EXPECT_TRUE(run_order.empty());
-
- // After pumping the task runs normally.
- manager_->PumpQueue(0);
- EXPECT_TRUE(test_task_runner_->HasPendingTask());
- selector_->AppendQueueToService(0);
- test_task_runner_->RunUntilIdle();
- EXPECT_EQ(1, run_order[0]);
-}
-
-TEST_F(TaskQueueManagerTest, ManualPumpingWithNonEmptyWorkQueue) {
- Initialize(1u);
- manager_->SetAutoPump(0, false);
-
- std::vector<int> run_order;
- scoped_refptr<base::SingleThreadTaskRunner> runner =
- manager_->TaskRunnerForQueue(0);
-
- // Posting two tasks and pumping twice should result in two tasks in the work
- // queue.
- runner->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
- manager_->PumpQueue(0);
- runner->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
- manager_->PumpQueue(0);
-
- EXPECT_EQ(2u, selector_->work_queues()[0]->size());
-}
-
-void ReentrantTestTask(scoped_refptr<base::SingleThreadTaskRunner> runner,
- int countdown,
- std::vector<int>* out_result) {
- out_result->push_back(countdown);
- if (--countdown) {
- runner->PostTask(FROM_HERE,
- Bind(&ReentrantTestTask, runner, countdown, out_result));
- }
-}
-
-TEST_F(TaskQueueManagerTest, ReentrantPosting) {
- Initialize(1u);
- EXPECT_EQ(1u, selector_->work_queues().size());
-
- std::vector<int> run_order;
- scoped_refptr<base::SingleThreadTaskRunner> runner =
- manager_->TaskRunnerForQueue(0);
-
- runner->PostTask(FROM_HERE, Bind(&ReentrantTestTask, runner, 3, &run_order));
-
- selector_->AppendQueueToService(0);
- selector_->AppendQueueToService(0);
- selector_->AppendQueueToService(0);
-
- test_task_runner_->RunUntilIdle();
- EXPECT_EQ(3, run_order[0]);
- EXPECT_EQ(2, run_order[1]);
- EXPECT_EQ(1, run_order[2]);
-}
-
-TEST_F(TaskQueueManagerTest, NoTasksAfterShutdown) {
- Initialize(1u);
-
- std::vector<int> run_order;
- scoped_refptr<base::SingleThreadTaskRunner> runner =
- manager_->TaskRunnerForQueue(0);
-
- runner->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
- manager_.reset();
- selector_.reset();
- runner->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
-
- test_task_runner_->RunUntilIdle();
- EXPECT_TRUE(run_order.empty());
-}
-
-void PostTaskToRunner(scoped_refptr<base::SingleThreadTaskRunner> runner,
- std::vector<int>* run_order) {
- runner->PostTask(FROM_HERE, base::Bind(&TestTask, 1, run_order));
-}
-
-TEST_F(TaskQueueManagerTest, PostFromThread) {
- base::MessageLoop message_loop;
- selector_ = make_scoped_ptr(new SelectorForTest);
- manager_ = make_scoped_ptr(
- new TaskQueueManager(1u, message_loop.task_runner(), selector_.get()));
-
- std::vector<int> run_order;
- scoped_refptr<base::SingleThreadTaskRunner> runner =
- manager_->TaskRunnerForQueue(0);
-
- base::Thread thread("TestThread");
- thread.Start();
- thread.message_loop()->PostTask(
- FROM_HERE, base::Bind(&PostTaskToRunner, runner, &run_order));
- thread.Stop();
-
- selector_->AppendQueueToService(0);
- message_loop.RunUntilIdle();
- EXPECT_EQ(1, run_order[0]);
-}
-
-} // namespace
-} // namespace content
diff --git a/chromium/content/renderer/scheduler/task_queue_selector.h b/chromium/content/renderer/scheduler/task_queue_selector.h
deleted file mode 100644
index afab36aa1a5..00000000000
--- a/chromium/content/renderer/scheduler/task_queue_selector.h
+++ /dev/null
@@ -1,37 +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_RENDERER_SCHEDULER_TASK_QUEUE_SELECTOR_H_
-#define CONTENT_RENDERER_SCHEDULER_TASK_QUEUE_SELECTOR_H_
-
-#include <vector>
-
-#include "base/basictypes.h"
-
-namespace base {
-class TaskQueue;
-}
-
-namespace content {
-
-class TaskQueueSelector {
- public:
- virtual ~TaskQueueSelector() {}
-
- // Called once to register the work queues to be selected from. This function
- // is called on the main thread.
- virtual void RegisterWorkQueues(
- const std::vector<const base::TaskQueue*>& work_queues) = 0;
-
- // Called to choose the work queue from which the next task should be taken
- // and run. Return true if |out_queue| indicates the queue to service or
- // false to avoid running any task.
- //
- // This function is called on the main thread.
- virtual bool SelectWorkQueueToService(size_t* out_queue_index) = 0;
-};
-
-} // namespace content
-
-#endif // CONTENT_RENDERER_SCHEDULER_TASK_QUEUE_SELECTOR_H_
diff --git a/chromium/content/renderer/scheduler/web_scheduler_impl.cc b/chromium/content/renderer/scheduler/web_scheduler_impl.cc
deleted file mode 100644
index c0a340795b7..00000000000
--- a/chromium/content/renderer/scheduler/web_scheduler_impl.cc
+++ /dev/null
@@ -1,45 +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/renderer/scheduler/web_scheduler_impl.h"
-
-#include "base/bind.h"
-#include "content/renderer/scheduler/renderer_scheduler.h"
-#include "third_party/WebKit/public/platform/WebTraceLocation.h"
-
-namespace content {
-
-WebSchedulerImpl::WebSchedulerImpl(RendererScheduler* renderer_scheduler)
- : renderer_scheduler_(renderer_scheduler),
- idle_task_runner_(renderer_scheduler_->IdleTaskRunner()) {
-}
-
-WebSchedulerImpl::~WebSchedulerImpl() {
-}
-
-bool WebSchedulerImpl::shouldYieldForHighPriorityWork() {
- return renderer_scheduler_->ShouldYieldForHighPriorityWork();
-}
-
-void WebSchedulerImpl::runIdleTask(
- scoped_ptr<blink::WebScheduler::IdleTask> task,
- base::TimeTicks deadline) {
- task->run((deadline - base::TimeTicks()).InSecondsF());
-}
-
-void WebSchedulerImpl::postIdleTask(const blink::WebTraceLocation& web_location,
- blink::WebScheduler::IdleTask* task) {
- scoped_ptr<blink::WebScheduler::IdleTask> scoped_task(task);
- tracked_objects::Location location(web_location.functionName(),
- web_location.fileName(), -1, nullptr);
- idle_task_runner_->PostIdleTask(
- location,
- base::Bind(&WebSchedulerImpl::runIdleTask, base::Passed(&scoped_task)));
-}
-
-void WebSchedulerImpl::shutdown() {
- return renderer_scheduler_->Shutdown();
-}
-
-} // namespace content
diff --git a/chromium/content/renderer/scheduler/web_scheduler_impl.h b/chromium/content/renderer/scheduler/web_scheduler_impl.h
deleted file mode 100644
index 98bdaafc4dd..00000000000
--- a/chromium/content/renderer/scheduler/web_scheduler_impl.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_RENDERER_SCHEDULER_WEB_SCHEDULER_IMPL_H_
-#define CONTENT_RENDERER_SCHEDULER_WEB_SCHEDULER_IMPL_H_
-
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/time/time.h"
-#include "third_party/WebKit/public/platform/WebScheduler.h"
-
-namespace content {
-
-class RendererScheduler;
-class SingleThreadIdleTaskRunner;
-
-class WebSchedulerImpl : public blink::WebScheduler {
- public:
- WebSchedulerImpl(RendererScheduler* renderer_scheduler);
- ~WebSchedulerImpl() override;
-
- virtual bool shouldYieldForHighPriorityWork();
- virtual void postIdleTask(const blink::WebTraceLocation& location,
- blink::WebScheduler::IdleTask* task);
- virtual void shutdown();
-
- private:
- static void runIdleTask(scoped_ptr<blink::WebScheduler::IdleTask> task,
- base::TimeTicks deadline);
-
- RendererScheduler* renderer_scheduler_;
- scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_;
-};
-
-} // namespace content
-
-#endif // CONTENT_RENDERER_SCHEDULER_WEB_SCHEDULER_IMPL_H_
diff --git a/chromium/content/renderer/scoped_clipboard_writer_glue.cc b/chromium/content/renderer/scoped_clipboard_writer_glue.cc
deleted file mode 100644
index 71471344fd5..00000000000
--- a/chromium/content/renderer/scoped_clipboard_writer_glue.cc
+++ /dev/null
@@ -1,36 +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/renderer/scoped_clipboard_writer_glue.h"
-#include "base/logging.h"
-
-namespace content {
-
-ScopedClipboardWriterGlue::ScopedClipboardWriterGlue(ClipboardClient* client)
- : ui::ScopedClipboardWriter(ui::CLIPBOARD_TYPE_COPY_PASTE),
- context_(client->CreateWriteContext()) {
- DCHECK(context_);
-}
-
-ScopedClipboardWriterGlue::~ScopedClipboardWriterGlue() {
- if (!objects_.empty() && context_) {
- context_->Flush(objects_);
- // TODO(dcheng): Temporary hack while the clipboard IPCs are cleaned up.
- // This prevents the base class destructor from also trying to (probably
- // unsuccessfully) flush things to the clipboard.
- objects_.clear();
- }
-}
-
-void ScopedClipboardWriterGlue::WriteBitmapFromPixels(const void* pixels,
- const gfx::Size& size) {
- if (context_) {
- context_->WriteBitmapFromPixels(&objects_, pixels, size);
- } else {
- NOTREACHED();
- }
-}
-
-} // namespace content
-
diff --git a/chromium/content/renderer/scoped_clipboard_writer_glue.h b/chromium/content/renderer/scoped_clipboard_writer_glue.h
deleted file mode 100644
index d64ae63eee0..00000000000
--- a/chromium/content/renderer/scoped_clipboard_writer_glue.h
+++ /dev/null
@@ -1,30 +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_RENDERER_SCOPED_CLIPBOARD_WRITER_GLUE_H_
-#define CONTENT_RENDERER_SCOPED_CLIPBOARD_WRITER_GLUE_H_
-
-#include "ui/base/clipboard/scoped_clipboard_writer.h"
-#include "base/memory/scoped_ptr.h"
-#include "content/renderer/clipboard_client.h"
-
-namespace content {
-
-class ScopedClipboardWriterGlue
- : public ui::ScopedClipboardWriter {
- public:
- explicit ScopedClipboardWriterGlue(ClipboardClient* client);
-
- virtual ~ScopedClipboardWriterGlue();
-
- void WriteBitmapFromPixels(const void* pixels, const gfx::Size& size);
-
- private:
- scoped_ptr<ClipboardClient::WriteContext> context_;
- DISALLOW_COPY_AND_ASSIGN(ScopedClipboardWriterGlue);
-};
-
-} // namespace content
-
-#endif // CONTENT_RENDERER_SCOPED_CLIPBOARD_WRITER_GLUE_H_
diff --git a/chromium/content/renderer/screen_orientation/screen_orientation_dispatcher.h b/chromium/content/renderer/screen_orientation/screen_orientation_dispatcher.h
index 27523491ce5..e04c0d3aac1 100644
--- a/chromium/content/renderer/screen_orientation/screen_orientation_dispatcher.h
+++ b/chromium/content/renderer/screen_orientation/screen_orientation_dispatcher.h
@@ -60,4 +60,4 @@ class CONTENT_EXPORT ScreenOrientationDispatcher :
} // namespace content
-#endif // CONTENT_RENDERER_SCREEN_ORIENTATION_SCREEN_ORIENTATION_DISPATCHER_H_
+#endif // CONTENT_RENDERER_SCREEN_ORIENTATION_SCREEN_ORIENTATION_DISPATCHER_H_
diff --git a/chromium/content/renderer/screen_orientation/screen_orientation_dispatcher_unittest.cc b/chromium/content/renderer/screen_orientation/screen_orientation_dispatcher_unittest.cc
index 4d7714169aa..afaef3a73de 100644
--- a/chromium/content/renderer/screen_orientation/screen_orientation_dispatcher_unittest.cc
+++ b/chromium/content/renderer/screen_orientation/screen_orientation_dispatcher_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 "screen_orientation_dispatcher.h"
+#include "content/renderer/screen_orientation/screen_orientation_dispatcher.h"
#include <list>
@@ -23,8 +23,7 @@ namespace content {
// callback is resolved, it will be killed so we use the
// LockOrientationResultHolder to know in which state the callback object is at
// any time.
-class MockLockOrientationCallback :
- public blink::WebLockOrientationCallback {
+class MockLockOrientationCallback : public blink::WebLockOrientationCallback {
public:
struct LockOrientationResultHolder {
LockOrientationResultHolder()
@@ -75,9 +74,9 @@ class ScreenOrientationDispatcherTest : public testing::Test {
ScreenOrientationHostMsg_LockRequest::ID);
EXPECT_TRUE(msg != NULL);
- Tuple2<blink::WebScreenOrientationLockType,int> params;
+ Tuple<blink::WebScreenOrientationLockType,int> params;
ScreenOrientationHostMsg_LockRequest::Read(msg, &params);
- return params.b;
+ return get<1>(params);
}
IPC::TestSink& sink() {
diff --git a/chromium/content/renderer/service_worker/embedded_worker_context_client.cc b/chromium/content/renderer/service_worker/embedded_worker_context_client.cc
index 010ecc71bfd..c393502617e 100644
--- a/chromium/content/renderer/service_worker/embedded_worker_context_client.cc
+++ b/chromium/content/renderer/service_worker/embedded_worker_context_client.cc
@@ -7,25 +7,33 @@
#include <map>
#include <string>
-#include "base/debug/trace_event.h"
#include "base/lazy_instance.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/pickle.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
#include "base/threading/thread_local.h"
+#include "base/trace_event/trace_event.h"
#include "content/child/request_extra_data.h"
+#include "content/child/service_worker/service_worker_dispatcher.h"
#include "content/child/service_worker/service_worker_network_provider.h"
+#include "content/child/service_worker/service_worker_provider_context.h"
+#include "content/child/service_worker/service_worker_registration_handle_reference.h"
+#include "content/child/service_worker/web_service_worker_impl.h"
+#include "content/child/service_worker/web_service_worker_provider_impl.h"
+#include "content/child/service_worker/web_service_worker_registration_impl.h"
#include "content/child/thread_safe_sender.h"
#include "content/child/worker_task_runner.h"
-#include "content/child/worker_thread_task_runner.h"
#include "content/common/devtools_messages.h"
#include "content/common/service_worker/embedded_worker_messages.h"
#include "content/common/service_worker/service_worker_types.h"
#include "content/public/renderer/document_state.h"
+#include "content/renderer/devtools/devtools_agent.h"
#include "content/renderer/render_thread_impl.h"
#include "content/renderer/service_worker/embedded_worker_dispatcher.h"
#include "content/renderer/service_worker/service_worker_script_context.h"
+#include "content/renderer/service_worker/service_worker_type_util.h"
#include "ipc/ipc_message_macros.h"
#include "third_party/WebKit/public/platform/WebServiceWorkerResponse.h"
#include "third_party/WebKit/public/platform/WebString.h"
@@ -36,8 +44,6 @@ namespace content {
namespace {
-const size_t kMaxMessageChunkSize = IPC::Channel::kMaximumMessageSize / 4;
-
// For now client must be a per-thread instance.
// TODO(kinuko): This needs to be refactored when we start using thread pool
// or having multiple clients per one thread.
@@ -99,8 +105,8 @@ EmbeddedWorkerContextClient::EmbeddedWorkerContextClient(
service_worker_scope_(service_worker_scope),
script_url_(script_url),
worker_devtools_agent_route_id_(worker_devtools_agent_route_id),
- sender_(ChildThread::current()->thread_safe_sender()),
- main_thread_proxy_(base::MessageLoopProxy::current()),
+ sender_(ChildThreadImpl::current()->thread_safe_sender()),
+ main_thread_task_runner_(RenderThreadImpl::current()->GetTaskRunner()),
weak_factory_(this) {
TRACE_EVENT_ASYNC_BEGIN0("ServiceWorker",
"EmbeddedWorkerContextClient::StartingWorkerContext",
@@ -134,19 +140,35 @@ blink::WebURL EmbeddedWorkerContextClient::scope() const {
return service_worker_scope_;
}
-blink::WebServiceWorkerCacheStorage*
- EmbeddedWorkerContextClient::cacheStorage() {
- return script_context_->cache_storage();
-}
-
void EmbeddedWorkerContextClient::didPauseAfterDownload() {
Send(new EmbeddedWorkerHostMsg_DidPauseAfterDownload(embedded_worker_id_));
}
void EmbeddedWorkerContextClient::getClients(
+ const blink::WebServiceWorkerClientQueryOptions& options,
blink::WebServiceWorkerClientsCallbacks* callbacks) {
DCHECK(script_context_);
- script_context_->GetClientDocuments(callbacks);
+ script_context_->GetClients(options, callbacks);
+}
+
+void EmbeddedWorkerContextClient::openWindow(
+ const blink::WebURL& url,
+ blink::WebServiceWorkerClientCallbacks* callbacks) {
+ DCHECK(script_context_);
+ script_context_->OpenWindow(url, callbacks);
+}
+
+void EmbeddedWorkerContextClient::setCachedMetadata(const blink::WebURL& url,
+ const char* data,
+ size_t size) {
+ DCHECK(script_context_);
+ script_context_->SetCachedMetadata(url, data, size);
+}
+
+void EmbeddedWorkerContextClient::clearCachedMetadata(
+ const blink::WebURL& url) {
+ DCHECK(script_context_);
+ script_context_->ClearCachedMetadata(url);
}
void EmbeddedWorkerContextClient::workerReadyForInspection() {
@@ -154,7 +176,7 @@ void EmbeddedWorkerContextClient::workerReadyForInspection() {
}
void EmbeddedWorkerContextClient::workerContextFailedToStart() {
- DCHECK(main_thread_proxy_->RunsTasksOnCurrentThread());
+ DCHECK(main_thread_task_runner_->RunsTasksOnCurrentThread());
DCHECK(!script_context_);
Send(new EmbeddedWorkerHostMsg_WorkerScriptLoadFailed(embedded_worker_id_));
@@ -166,9 +188,8 @@ void EmbeddedWorkerContextClient::workerContextFailedToStart() {
void EmbeddedWorkerContextClient::workerContextStarted(
blink::WebServiceWorkerContextProxy* proxy) {
DCHECK(!worker_task_runner_.get());
- worker_task_runner_ = new WorkerThreadTaskRunner(
- WorkerTaskRunner::Instance()->CurrentWorkerId());
DCHECK_NE(0, WorkerTaskRunner::Instance()->CurrentWorkerId());
+ worker_task_runner_ = base::ThreadTaskRunnerHandle::Get();
// g_worker_client_tls.Pointer()->Get() could return NULL if this context
// gets deleted before workerContextStarted() is called.
DCHECK(g_worker_client_tls.Pointer()->Get() == NULL);
@@ -176,17 +197,13 @@ void EmbeddedWorkerContextClient::workerContextStarted(
g_worker_client_tls.Pointer()->Set(this);
script_context_.reset(new ServiceWorkerScriptContext(this, proxy));
+ SetRegistrationInServiceWorkerGlobalScope();
+
Send(new EmbeddedWorkerHostMsg_WorkerScriptLoaded(
embedded_worker_id_,
- WorkerTaskRunner::Instance()->CurrentWorkerId()));
+ WorkerTaskRunner::Instance()->CurrentWorkerId(),
+ provider_context_->provider_id()));
- // Schedule a task to send back WorkerStarted asynchronously,
- // so that at the time we send it we can be sure that the worker
- // script has been evaluated and worker run loop has been started.
- worker_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&EmbeddedWorkerContextClient::SendWorkerStarted,
- weak_factory_.GetWeakPtr()));
TRACE_EVENT_ASYNC_STEP_INTO0(
"ServiceWorker",
"EmbeddedWorkerContextClient::StartingWorkerContext",
@@ -197,6 +214,13 @@ void EmbeddedWorkerContextClient::workerContextStarted(
void EmbeddedWorkerContextClient::didEvaluateWorkerScript(bool success) {
Send(new EmbeddedWorkerHostMsg_WorkerScriptEvaluated(
embedded_worker_id_, success));
+
+ // Schedule a task to send back WorkerStarted asynchronously,
+ // so that at the time we send it we can be sure that the
+ // worker run loop has been started.
+ worker_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&EmbeddedWorkerContextClient::SendWorkerStarted,
+ weak_factory_.GetWeakPtr()));
}
void EmbeddedWorkerContextClient::willDestroyWorkerContext() {
@@ -215,7 +239,7 @@ void EmbeddedWorkerContextClient::workerContextDestroyed() {
// Now we should be able to free the WebEmbeddedWorker container on the
// main thread.
- main_thread_proxy_->PostTask(
+ main_thread_task_runner_->PostTask(
FROM_HERE,
base::Bind(&CallWorkerContextDestroyedOnMainThread,
embedded_worker_id_));
@@ -248,28 +272,13 @@ void EmbeddedWorkerContextClient::reportConsoleMessage(
embedded_worker_id_, params));
}
-void EmbeddedWorkerContextClient::dispatchDevToolsMessage(
- const blink::WebString& message) {
- std::string msg(message.utf8());
-
- if (msg.length() < kMaxMessageChunkSize) {
- sender_->Send(new DevToolsClientMsg_DispatchOnInspectorFrontend(
- worker_devtools_agent_route_id_, msg, msg.size()));
- return;
- }
-
- for (size_t pos = 0; pos < msg.length(); pos += kMaxMessageChunkSize) {
- sender_->Send(new DevToolsClientMsg_DispatchOnInspectorFrontend(
- worker_devtools_agent_route_id_,
- msg.substr(pos, kMaxMessageChunkSize),
- pos ? 0 : msg.size()));
- }
-}
-
-void EmbeddedWorkerContextClient::saveDevToolsAgentState(
- const blink::WebString& state) {
- sender_->Send(new DevToolsHostMsg_SaveAgentRuntimeState(
- worker_devtools_agent_route_id_, state.utf8()));
+void EmbeddedWorkerContextClient::sendDevToolsMessage(
+ int call_id,
+ const blink::WebString& message,
+ const blink::WebString& state_cookie) {
+ DevToolsAgent::SendChunkedProtocolMessage(
+ sender_.get(), worker_devtools_agent_route_id_,
+ call_id, message.utf8(), state_cookie.utf8());
}
void EmbeddedWorkerContextClient::didHandleActivateEvent(
@@ -299,36 +308,57 @@ void EmbeddedWorkerContextClient::didHandleFetchEvent(
const blink::WebServiceWorkerResponse& web_response) {
DCHECK(script_context_);
ServiceWorkerHeaderMap headers;
- const blink::WebVector<blink::WebString>& header_keys =
- web_response.getHeaderKeys();
- for (size_t i = 0; i < header_keys.size(); ++i) {
- const base::string16& key = header_keys[i];
- headers[base::UTF16ToUTF8(key)] =
- base::UTF16ToUTF8(web_response.getHeader(key));
- }
+ GetServiceWorkerHeaderMapFromWebResponse(web_response, &headers);
ServiceWorkerResponse response(web_response.url(),
web_response.status(),
web_response.statusText().utf8(),
web_response.responseType(),
headers,
web_response.blobUUID().utf8(),
- web_response.blobSize());
+ web_response.blobSize(),
+ web_response.streamURL());
script_context_->DidHandleFetchEvent(
request_id, SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE, response);
}
+void EmbeddedWorkerContextClient::didHandleNotificationClickEvent(
+ int request_id,
+ blink::WebServiceWorkerEventResult result) {
+ DCHECK(script_context_);
+ script_context_->DidHandleNotificationClickEvent(request_id, result);
+}
+
+void EmbeddedWorkerContextClient::didHandlePushEvent(
+ int request_id,
+ blink::WebServiceWorkerEventResult result) {
+ DCHECK(script_context_);
+ script_context_->DidHandlePushEvent(request_id, result);
+}
+
void EmbeddedWorkerContextClient::didHandleSyncEvent(int request_id) {
DCHECK(script_context_);
script_context_->DidHandleSyncEvent(request_id);
}
+void EmbeddedWorkerContextClient::didHandleCrossOriginConnectEvent(
+ int request_id,
+ bool accept_connection) {
+ DCHECK(script_context_);
+ script_context_->DidHandleCrossOriginConnectEvent(request_id,
+ accept_connection);
+}
+
blink::WebServiceWorkerNetworkProvider*
EmbeddedWorkerContextClient::createServiceWorkerNetworkProvider(
blink::WebDataSource* data_source) {
+ DCHECK(main_thread_task_runner_->RunsTasksOnCurrentThread());
+
// Create a content::ServiceWorkerNetworkProvider for this data source so
// we can observe its requests.
scoped_ptr<ServiceWorkerNetworkProvider> provider(
- new ServiceWorkerNetworkProvider());
+ new ServiceWorkerNetworkProvider(
+ MSG_ROUTING_NONE, SERVICE_WORKER_PROVIDER_FOR_CONTROLLER));
+ provider_context_ = provider->context();
// Tell the network provider about which version to load.
provider->SetServiceWorkerVersionId(service_worker_version_id_);
@@ -344,13 +374,51 @@ EmbeddedWorkerContextClient::createServiceWorkerNetworkProvider(
return new WebServiceWorkerNetworkProviderImpl();
}
+blink::WebServiceWorkerProvider*
+EmbeddedWorkerContextClient::createServiceWorkerProvider() {
+ DCHECK(main_thread_task_runner_->RunsTasksOnCurrentThread());
+ DCHECK(provider_context_);
+
+ // Blink is responsible for deleting the returned object.
+ return new WebServiceWorkerProviderImpl(
+ thread_safe_sender(), provider_context_.get());
+}
+
void EmbeddedWorkerContextClient::postMessageToClient(
- int client_id,
+ const blink::WebString& uuid,
const blink::WebString& message,
blink::WebMessagePortChannelArray* channels) {
DCHECK(script_context_);
- script_context_->PostMessageToDocument(client_id, message,
- make_scoped_ptr(channels));
+ script_context_->PostMessageToClient(
+ uuid, message, make_scoped_ptr(channels));
+}
+
+void EmbeddedWorkerContextClient::postMessageToCrossOriginClient(
+ const blink::WebCrossOriginServiceWorkerClient& client,
+ const blink::WebString& message,
+ blink::WebMessagePortChannelArray* channels) {
+ DCHECK(script_context_);
+ script_context_->PostCrossOriginMessageToClient(client, message,
+ make_scoped_ptr(channels));
+}
+
+void EmbeddedWorkerContextClient::focus(
+ const blink::WebString& uuid,
+ blink::WebServiceWorkerClientCallbacks* callback) {
+ DCHECK(script_context_);
+ script_context_->FocusClient(uuid, callback);
+}
+
+void EmbeddedWorkerContextClient::skipWaiting(
+ blink::WebServiceWorkerSkipWaitingCallbacks* callbacks) {
+ DCHECK(script_context_);
+ script_context_->SkipWaiting(callbacks);
+}
+
+void EmbeddedWorkerContextClient::claim(
+ blink::WebServiceWorkerClientsClaimCallbacks* callbacks) {
+ DCHECK(script_context_);
+ script_context_->ClaimClients(callbacks);
}
void EmbeddedWorkerContextClient::OnMessageToWorker(
@@ -371,4 +439,35 @@ void EmbeddedWorkerContextClient::SendWorkerStarted() {
Send(new EmbeddedWorkerHostMsg_WorkerStarted(embedded_worker_id_));
}
+void EmbeddedWorkerContextClient::SetRegistrationInServiceWorkerGlobalScope() {
+ DCHECK(worker_task_runner_->RunsTasksOnCurrentThread());
+ DCHECK(provider_context_);
+ DCHECK(script_context_);
+
+ ServiceWorkerRegistrationObjectInfo info;
+ ServiceWorkerVersionAttributes attrs;
+ bool found =
+ provider_context_->GetRegistrationInfoAndVersionAttributes(&info, &attrs);
+ if (!found)
+ return; // Cannot be associated with a registration in some tests.
+
+ ServiceWorkerDispatcher* dispatcher =
+ ServiceWorkerDispatcher::GetOrCreateThreadSpecificInstance(
+ thread_safe_sender());
+
+ // Register a registration and its version attributes with the dispatcher
+ // living on the worker thread.
+ scoped_ptr<WebServiceWorkerRegistrationImpl> registration(
+ dispatcher->CreateServiceWorkerRegistration(info, false));
+ registration->SetInstalling(
+ dispatcher->GetServiceWorker(attrs.installing, false));
+ registration->SetWaiting(
+ dispatcher->GetServiceWorker(attrs.waiting, false));
+ registration->SetActive(
+ dispatcher->GetServiceWorker(attrs.active, false));
+
+ script_context_->SetRegistrationInServiceWorkerGlobalScope(
+ registration.Pass());
+}
+
} // namespace content
diff --git a/chromium/content/renderer/service_worker/embedded_worker_context_client.h b/chromium/content/renderer/service_worker/embedded_worker_context_client.h
index bc92a341b5d..248591ec908 100644
--- a/chromium/content/renderer/service_worker/embedded_worker_context_client.h
+++ b/chromium/content/renderer/service_worker/embedded_worker_context_client.h
@@ -10,30 +10,27 @@
#include "base/strings/string16.h"
#include "content/common/service_worker/service_worker_types.h"
#include "ipc/ipc_listener.h"
-#include "third_party/WebKit/public/platform/WebServiceWorkerClientsInfo.h"
-#include "third_party/WebKit/public/platform/WebServiceWorkerEventResult.h"
-#include "third_party/WebKit/public/platform/WebURL.h"
#include "third_party/WebKit/public/web/WebServiceWorkerContextClient.h"
#include "url/gurl.h"
namespace base {
-class MessageLoopProxy;
+class SingleThreadTaskRunner;
class TaskRunner;
}
namespace blink {
class WebDataSource;
+class WebServiceWorkerProvider;
}
namespace content {
+class ServiceWorkerProviderContext;
class ServiceWorkerScriptContext;
class ThreadSafeSender;
// This class provides access to/from an embedded worker's WorkerGlobalScope.
-// All methods other than the constructor (it's created on the main thread)
-// and createServiceWorkerNetworkProvider (also called on the main thread)
-// are called on the worker thread.
+// Unless otherwise noted, all methods are called on the worker thread.
//
// TODO(kinuko): Currently EW/SW separation is made a little hazily.
// This should implement WebEmbeddedWorkerContextClient
@@ -48,6 +45,7 @@ class EmbeddedWorkerContextClient
// new instance.
static EmbeddedWorkerContextClient* ThreadSpecificInstance();
+ // Called on the main thread.
EmbeddedWorkerContextClient(int embedded_worker_id,
int64 service_worker_version_id,
const GURL& service_worker_scope,
@@ -63,11 +61,20 @@ class EmbeddedWorkerContextClient
// WebServiceWorkerContextClient overrides, some of them are just dispatched
// on to script_context_.
virtual blink::WebURL scope() const;
- virtual blink::WebServiceWorkerCacheStorage* cacheStorage();
virtual void didPauseAfterDownload();
- virtual void getClients(blink::WebServiceWorkerClientsCallbacks*);
+ virtual void getClients(const blink::WebServiceWorkerClientQueryOptions&,
+ blink::WebServiceWorkerClientsCallbacks*);
+ virtual void openWindow(const blink::WebURL&,
+ blink::WebServiceWorkerClientCallbacks*);
+ virtual void setCachedMetadata(const blink::WebURL&,
+ const char* data,
+ size_t size);
+ virtual void clearCachedMetadata(const blink::WebURL&);
virtual void workerReadyForInspection();
+
+ // Called on the main thread.
virtual void workerContextFailedToStart();
+
virtual void workerContextStarted(blink::WebServiceWorkerContextProxy* proxy);
virtual void didEvaluateWorkerScript(bool success);
virtual void willDestroyWorkerContext();
@@ -81,8 +88,9 @@ class EmbeddedWorkerContextClient
const blink::WebString& message,
int line_number,
const blink::WebString& source_url);
- virtual void dispatchDevToolsMessage(const blink::WebString&);
- virtual void saveDevToolsAgentState(const blink::WebString&);
+ virtual void sendDevToolsMessage(int call_id,
+ const blink::WebString& message,
+ const blink::WebString& state);
virtual void didHandleActivateEvent(int request_id,
blink::WebServiceWorkerEventResult);
virtual void didHandleInstallEvent(int request_id,
@@ -91,19 +99,39 @@ class EmbeddedWorkerContextClient
virtual void didHandleFetchEvent(
int request_id,
const blink::WebServiceWorkerResponse& response);
+ virtual void didHandleNotificationClickEvent(
+ int request_id,
+ blink::WebServiceWorkerEventResult result);
+ virtual void didHandlePushEvent(int request_id,
+ blink::WebServiceWorkerEventResult result);
virtual void didHandleSyncEvent(int request_id);
+ virtual void didHandleCrossOriginConnectEvent(int request_id,
+ bool accept_connection);
+
+ // Called on the main thread.
virtual blink::WebServiceWorkerNetworkProvider*
createServiceWorkerNetworkProvider(blink::WebDataSource* data_source);
+ virtual blink::WebServiceWorkerProvider* createServiceWorkerProvider();
+
virtual void postMessageToClient(
- int client_id,
+ const blink::WebString& uuid,
+ const blink::WebString& message,
+ blink::WebMessagePortChannelArray* channels);
+ virtual void postMessageToCrossOriginClient(
+ const blink::WebCrossOriginServiceWorkerClient& client,
const blink::WebString& message,
blink::WebMessagePortChannelArray* channels);
+ virtual void focus(const blink::WebString& uuid,
+ blink::WebServiceWorkerClientCallbacks*);
+ virtual void skipWaiting(
+ blink::WebServiceWorkerSkipWaitingCallbacks* callbacks);
+ virtual void claim(blink::WebServiceWorkerClientsClaimCallbacks* callbacks);
// TODO: Implement DevTools related method overrides.
int embedded_worker_id() const { return embedded_worker_id_; }
- base::MessageLoopProxy* main_thread_proxy() const {
- return main_thread_proxy_.get();
+ base::SingleThreadTaskRunner* main_thread_task_runner() const {
+ return main_thread_task_runner_.get();
}
ThreadSafeSender* thread_safe_sender() { return sender_.get(); }
@@ -112,6 +140,7 @@ class EmbeddedWorkerContextClient
int embedded_worker_id,
const IPC::Message& message);
void SendWorkerStarted();
+ void SetRegistrationInServiceWorkerGlobalScope();
const int embedded_worker_id_;
const int64 service_worker_version_id_;
@@ -119,10 +148,11 @@ class EmbeddedWorkerContextClient
const GURL script_url_;
const int worker_devtools_agent_route_id_;
scoped_refptr<ThreadSafeSender> sender_;
- scoped_refptr<base::MessageLoopProxy> main_thread_proxy_;
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
scoped_refptr<base::TaskRunner> worker_task_runner_;
scoped_ptr<ServiceWorkerScriptContext> script_context_;
+ scoped_refptr<ServiceWorkerProviderContext> provider_context_;
base::WeakPtrFactory<EmbeddedWorkerContextClient> weak_factory_;
diff --git a/chromium/content/renderer/service_worker/embedded_worker_context_message_filter.cc b/chromium/content/renderer/service_worker/embedded_worker_context_message_filter.cc
index cbc141df56a..4ecaa171667 100644
--- a/chromium/content/renderer/service_worker/embedded_worker_context_message_filter.cc
+++ b/chromium/content/renderer/service_worker/embedded_worker_context_message_filter.cc
@@ -4,45 +4,38 @@
#include "content/renderer/service_worker/embedded_worker_context_message_filter.h"
-#include "base/message_loop/message_loop_proxy.h"
-#include "content/child/child_thread.h"
-#include "content/child/thread_safe_sender.h"
-#include "content/child/worker_thread_task_runner.h"
+#include "content/child/child_thread_impl.h"
#include "content/renderer/service_worker/embedded_worker_context_client.h"
#include "ipc/ipc_message_macros.h"
namespace content {
EmbeddedWorkerContextMessageFilter::EmbeddedWorkerContextMessageFilter()
- : main_thread_loop_proxy_(base::MessageLoopProxy::current()),
- thread_safe_sender_(ChildThread::current()->thread_safe_sender()) {}
+ : WorkerThreadMessageFilter(
+ ChildThreadImpl::current()->thread_safe_sender()) {
+}
EmbeddedWorkerContextMessageFilter::~EmbeddedWorkerContextMessageFilter() {}
-base::TaskRunner*
-EmbeddedWorkerContextMessageFilter::OverrideTaskRunnerForMessage(
- const IPC::Message& msg) {
- if (IPC_MESSAGE_CLASS(msg) != EmbeddedWorkerContextMsgStart)
- return NULL;
- int ipc_thread_id = 0;
- const bool success = PickleIterator(msg).ReadInt(&ipc_thread_id);
- DCHECK(success);
- if (!ipc_thread_id)
- return main_thread_loop_proxy_.get();
- return new WorkerThreadTaskRunner(ipc_thread_id);
+bool EmbeddedWorkerContextMessageFilter::ShouldHandleMessage(
+ const IPC::Message& msg) const {
+ return IPC_MESSAGE_CLASS(msg) == EmbeddedWorkerContextMsgStart;
}
-bool EmbeddedWorkerContextMessageFilter::OnMessageReceived(
+void EmbeddedWorkerContextMessageFilter::OnFilteredMessageReceived(
const IPC::Message& msg) {
- if (IPC_MESSAGE_CLASS(msg) != EmbeddedWorkerContextMsgStart)
- return false;
EmbeddedWorkerContextClient* client =
EmbeddedWorkerContextClient::ThreadSpecificInstance();
- if (!client) {
+ if (!client)
LOG(ERROR) << "Stray message is sent to nonexistent worker";
- return true;
- }
- return client->OnMessageReceived(msg);
+ else
+ client->OnMessageReceived(msg);
+}
+
+bool EmbeddedWorkerContextMessageFilter::GetWorkerThreadIdForMessage(
+ const IPC::Message& msg,
+ int* ipc_thread_id) {
+ return PickleIterator(msg).ReadInt(ipc_thread_id);
}
} // namespace content
diff --git a/chromium/content/renderer/service_worker/embedded_worker_context_message_filter.h b/chromium/content/renderer/service_worker/embedded_worker_context_message_filter.h
index 366c39f0c75..cefdc58a596 100644
--- a/chromium/content/renderer/service_worker/embedded_worker_context_message_filter.h
+++ b/chromium/content/renderer/service_worker/embedded_worker_context_message_filter.h
@@ -5,30 +5,24 @@
#ifndef CONTENT_RENDERER_SERVICE_WORKER_EMBEDDED_WORKER_CONTEXT_MESSAGE_FILTER_H_
#define CONTENT_RENDERER_SERVICE_WORKER_EMBEDDED_WORKER_CONTEXT_MESSAGE_FILTER_H_
-#include "content/child/child_message_filter.h"
-
-namespace base {
-class MessageLoopProxy;
-}
+#include "content/child/worker_thread_message_filter.h"
namespace content {
-class EmbeddedWorkerContextMessageFilter : public ChildMessageFilter {
+class EmbeddedWorkerContextMessageFilter : public WorkerThreadMessageFilter {
public:
EmbeddedWorkerContextMessageFilter();
protected:
~EmbeddedWorkerContextMessageFilter() override;
- // ChildMessageFilter implementation:
- base::TaskRunner* OverrideTaskRunnerForMessage(
- const IPC::Message& msg) override;
- bool OnMessageReceived(const IPC::Message& msg) override;
+ // WorkerThreadMessageFilter:
+ bool ShouldHandleMessage(const IPC::Message& msg) const override;
+ void OnFilteredMessageReceived(const IPC::Message& msg) override;
+ bool GetWorkerThreadIdForMessage(const IPC::Message& msg,
+ int* ipc_thread_id) override;
private:
- scoped_refptr<base::MessageLoopProxy> main_thread_loop_proxy_;
- scoped_refptr<ThreadSafeSender> thread_safe_sender_;
-
DISALLOW_COPY_AND_ASSIGN(EmbeddedWorkerContextMessageFilter);
};
diff --git a/chromium/content/renderer/service_worker/embedded_worker_devtools_agent.cc b/chromium/content/renderer/service_worker/embedded_worker_devtools_agent.cc
index 791a2ca9a9d..e1c640a8344 100644
--- a/chromium/content/renderer/service_worker/embedded_worker_devtools_agent.cc
+++ b/chromium/content/renderer/service_worker/embedded_worker_devtools_agent.cc
@@ -4,7 +4,6 @@
#include "content/renderer/service_worker/embedded_worker_devtools_agent.h"
-#include "content/child/child_thread.h"
#include "content/common/devtools_messages.h"
#include "content/renderer/render_thread_impl.h"
#include "third_party/WebKit/public/platform/WebCString.h"
diff --git a/chromium/content/renderer/service_worker/embedded_worker_dispatcher.cc b/chromium/content/renderer/service_worker/embedded_worker_dispatcher.cc
index e62bb2e9ce8..f852114af02 100644
--- a/chromium/content/renderer/service_worker/embedded_worker_dispatcher.cc
+++ b/chromium/content/renderer/service_worker/embedded_worker_dispatcher.cc
@@ -93,6 +93,8 @@ void EmbeddedWorkerDispatcher::OnStartWorker(
params.wait_for_debugger ?
blink::WebEmbeddedWorkerStartData::WaitForDebugger :
blink::WebEmbeddedWorkerStartData::DontWaitForDebugger;
+ start_data.v8CacheOptions =
+ static_cast<blink::WebSettings::V8CacheOptions>(params.v8_cache_options);
wrapper->worker()->startWorkerContext(start_data);
workers_.AddWithID(wrapper.release(), params.embedded_worker_id);
diff --git a/chromium/content/renderer/service_worker/embedded_worker_dispatcher.h b/chromium/content/renderer/service_worker/embedded_worker_dispatcher.h
index 170d282071e..8bf8e84468f 100644
--- a/chromium/content/renderer/service_worker/embedded_worker_dispatcher.h
+++ b/chromium/content/renderer/service_worker/embedded_worker_dispatcher.h
@@ -13,10 +13,6 @@
struct EmbeddedWorkerMsg_StartWorker_Params;
class GURL;
-namespace WebKit {
-class WebEmbeddedWorker;
-}
-
namespace content {
// A tiny dispatcher which handles embedded worker start/stop messages.
diff --git a/chromium/content/renderer/service_worker/service_worker_cache_storage_dispatcher.cc b/chromium/content/renderer/service_worker/service_worker_cache_storage_dispatcher.cc
deleted file mode 100644
index 2f6e1b2121b..00000000000
--- a/chromium/content/renderer/service_worker/service_worker_cache_storage_dispatcher.cc
+++ /dev/null
@@ -1,542 +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/renderer/service_worker/service_worker_cache_storage_dispatcher.h"
-
-#include <map>
-#include <string>
-#include <utility>
-
-#include "base/logging.h"
-#include "base/strings/utf_string_conversions.h"
-#include "content/common/service_worker/service_worker_messages.h"
-#include "content/public/renderer/render_thread.h"
-#include "content/renderer/service_worker/service_worker_script_context.h"
-#include "third_party/WebKit/public/platform/WebHTTPHeaderVisitor.h"
-#include "third_party/WebKit/public/platform/WebServiceWorkerCache.h"
-#include "third_party/WebKit/public/platform/WebServiceWorkerRequest.h"
-#include "third_party/WebKit/public/platform/WebServiceWorkerResponse.h"
-
-namespace content {
-
-using blink::WebServiceWorkerCacheError;
-using blink::WebServiceWorkerRequest;
-
-namespace {
-
-class HeaderVisitor : public blink::WebHTTPHeaderVisitor {
- public:
- HeaderVisitor(ServiceWorkerHeaderMap* headers) : headers_(headers) {}
- virtual ~HeaderVisitor() {}
-
- virtual void visitHeader(const blink::WebString& name,
- const blink::WebString& value) {
- headers_->insert(ServiceWorkerHeaderMap::value_type(
- base::UTF16ToASCII(name), base::UTF16ToASCII(value)));
- }
-
- private:
- ServiceWorkerHeaderMap* headers_;
-};
-
-scoped_ptr<HeaderVisitor> MakeHeaderVisitor(ServiceWorkerHeaderMap* headers) {
- return scoped_ptr<HeaderVisitor>(new HeaderVisitor(headers)).Pass();
-}
-
-ServiceWorkerFetchRequest FetchRequestFromWebRequest(
- const blink::WebServiceWorkerRequest& web_request) {
- ServiceWorkerHeaderMap headers;
- web_request.visitHTTPHeaderFields(MakeHeaderVisitor(&headers).get());
-
- return ServiceWorkerFetchRequest(web_request.url(),
- base::UTF16ToASCII(web_request.method()),
- headers, web_request.referrerUrl(),
- web_request.isReload());
-}
-
-void PopulateWebRequestFromFetchRequest(
- const ServiceWorkerFetchRequest& request,
- blink::WebServiceWorkerRequest* web_request) {
- web_request->setURL(request.url);
- web_request->setMethod(base::ASCIIToUTF16(request.method));
- for (ServiceWorkerHeaderMap::const_iterator i = request.headers.begin(),
- end = request.headers.end();
- i != end; ++i) {
- web_request->setHeader(base::ASCIIToUTF16(i->first),
- base::ASCIIToUTF16(i->second));
- }
- web_request->setReferrer(base::ASCIIToUTF16(request.referrer.spec()),
- blink::WebReferrerPolicy::WebReferrerPolicyNever);
- web_request->setIsReload(request.is_reload);
-}
-
-blink::WebVector<blink::WebServiceWorkerRequest> WebRequestsFromRequests(
- const std::vector<ServiceWorkerFetchRequest>& requests) {
- blink::WebVector<blink::WebServiceWorkerRequest>
- web_requests(requests.size());
- for (size_t i = 0; i < requests.size(); ++i)
- PopulateWebRequestFromFetchRequest(requests[i], &(web_requests[i]));
- return web_requests;
-}
-
-ServiceWorkerResponse ResponseFromWebResponse(
- const blink::WebServiceWorkerResponse& web_response) {
- ServiceWorkerHeaderMap headers;
- web_response.visitHTTPHeaderFields(MakeHeaderVisitor(&headers).get());
-
- return ServiceWorkerResponse(web_response.url(),
- web_response.status(),
- base::UTF16ToASCII(web_response.statusText()),
- web_response.responseType(),
- headers,
- base::UTF16ToASCII(web_response.blobUUID()),
- web_response.blobSize());
-}
-
-ServiceWorkerCacheQueryParams QueryParamsFromWebQueryParams(
- const blink::WebServiceWorkerCache::QueryParams& web_query_params) {
- ServiceWorkerCacheQueryParams query_params;
- query_params.ignore_search = web_query_params.ignoreSearch;
- query_params.ignore_method = web_query_params.ignoreMethod;
- query_params.ignore_vary = web_query_params.ignoreVary;
- query_params.prefix_match = web_query_params.prefixMatch;
-
- return query_params;
-}
-
-ServiceWorkerCacheOperationType CacheOperationTypeFromWebCacheOperationType(
- blink::WebServiceWorkerCache::OperationType operation_type) {
- switch (operation_type) {
- case blink::WebServiceWorkerCache::OperationTypePut:
- return SERVICE_WORKER_CACHE_OPERATION_TYPE_PUT;
- case blink::WebServiceWorkerCache::OperationTypeDelete:
- return SERVICE_WORKER_CACHE_OPERATION_TYPE_DELETE;
- default:
- return SERVICE_WORKER_CACHE_OPERATION_TYPE_UNDEFINED;
- }
-}
-
-ServiceWorkerBatchOperation BatchOperationFromWebBatchOperation(
- const blink::WebServiceWorkerCache::BatchOperation& web_operation) {
- ServiceWorkerBatchOperation operation;
- operation.operation_type =
- CacheOperationTypeFromWebCacheOperationType(web_operation.operationType);
- operation.request = FetchRequestFromWebRequest(web_operation.request);
- operation.response = ResponseFromWebResponse(web_operation.response);
- operation.match_params =
- QueryParamsFromWebQueryParams(web_operation.matchParams);
- return operation;
-}
-
-template<typename T>
-void ClearCallbacksMapWithErrors(T* callbacks_map) {
- typename T::iterator iter(callbacks_map);
- while (!iter.IsAtEnd()) {
- blink::WebServiceWorkerCacheError reason =
- blink::WebServiceWorkerCacheErrorNotFound;
- iter.GetCurrentValue()->onError(&reason);
- callbacks_map->Remove(iter.GetCurrentKey());
- iter.Advance();
- }
-}
-
-} // namespace
-
-// The WebCache object is the Chromium side implementation of the Blink
-// WebServiceWorkerCache API. Most of its methods delegate directly to the
-// ServiceWorkerStorage object, which is able to assign unique IDs as well
-// as have a lifetime longer than the requests.
-class ServiceWorkerCacheStorageDispatcher::WebCache
- : public blink::WebServiceWorkerCache {
- public:
- WebCache(base::WeakPtr<ServiceWorkerCacheStorageDispatcher> dispatcher,
- int cache_id)
- : dispatcher_(dispatcher),
- cache_id_(cache_id) {}
-
- virtual ~WebCache() {
- if (dispatcher_)
- dispatcher_->OnWebCacheDestruction(cache_id_);
- }
-
- // From blink::WebServiceWorkerCache:
- virtual void dispatchMatch(CacheMatchCallbacks* callbacks,
- const blink::WebServiceWorkerRequest& request,
- const QueryParams& query_params) {
- if (!dispatcher_)
- return;
- dispatcher_->dispatchMatchForCache(cache_id_, callbacks, request,
- query_params);
- }
- virtual void dispatchMatchAll(CacheWithResponsesCallbacks* callbacks,
- const blink::WebServiceWorkerRequest& request,
- const QueryParams& query_params) {
- if (!dispatcher_)
- return;
- dispatcher_->dispatchMatchAllForCache(cache_id_, callbacks, request,
- query_params);
- }
- virtual void dispatchKeys(CacheWithRequestsCallbacks* callbacks,
- const blink::WebServiceWorkerRequest* request,
- const QueryParams& query_params) {
- if (!dispatcher_)
- return;
- dispatcher_->dispatchKeysForCache(cache_id_, callbacks, request,
- query_params);
- }
- virtual void dispatchBatch(
- CacheWithResponsesCallbacks* callbacks,
- const blink::WebVector<BatchOperation>& batch_operations) {
- if (!dispatcher_)
- return;
- dispatcher_->dispatchBatchForCache(cache_id_, callbacks, batch_operations);
- }
-
- private:
- const base::WeakPtr<ServiceWorkerCacheStorageDispatcher> dispatcher_;
- const int cache_id_;
-};
-
-ServiceWorkerCacheStorageDispatcher::ServiceWorkerCacheStorageDispatcher(
- ServiceWorkerScriptContext* script_context)
- : script_context_(script_context),
- weak_factory_(this) {}
-
-ServiceWorkerCacheStorageDispatcher::~ServiceWorkerCacheStorageDispatcher() {
- ClearCallbacksMapWithErrors(&has_callbacks_);
- ClearCallbacksMapWithErrors(&open_callbacks_);
- ClearCallbacksMapWithErrors(&delete_callbacks_);
- ClearCallbacksMapWithErrors(&keys_callbacks_);
-
- ClearCallbacksMapWithErrors(&cache_match_callbacks_);
- ClearCallbacksMapWithErrors(&cache_match_all_callbacks_);
- ClearCallbacksMapWithErrors(&cache_keys_callbacks_);
- ClearCallbacksMapWithErrors(&cache_batch_callbacks_);
-}
-
-bool ServiceWorkerCacheStorageDispatcher::OnMessageReceived(
- const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(ServiceWorkerCacheStorageDispatcher, message)
- IPC_MESSAGE_HANDLER(ServiceWorkerMsg_CacheStorageHasSuccess,
- OnCacheStorageHasSuccess)
- IPC_MESSAGE_HANDLER(ServiceWorkerMsg_CacheStorageOpenSuccess,
- OnCacheStorageOpenSuccess)
- IPC_MESSAGE_HANDLER(ServiceWorkerMsg_CacheStorageDeleteSuccess,
- OnCacheStorageDeleteSuccess)
- IPC_MESSAGE_HANDLER(ServiceWorkerMsg_CacheStorageKeysSuccess,
- OnCacheStorageKeysSuccess)
- IPC_MESSAGE_HANDLER(ServiceWorkerMsg_CacheStorageHasError,
- OnCacheStorageHasError)
- IPC_MESSAGE_HANDLER(ServiceWorkerMsg_CacheStorageOpenError,
- OnCacheStorageOpenError)
- IPC_MESSAGE_HANDLER(ServiceWorkerMsg_CacheStorageDeleteError,
- OnCacheStorageDeleteError)
- IPC_MESSAGE_HANDLER(ServiceWorkerMsg_CacheStorageKeysError,
- OnCacheStorageKeysError)
- IPC_MESSAGE_HANDLER(ServiceWorkerMsg_CacheMatchSuccess,
- OnCacheMatchSuccess)
- IPC_MESSAGE_HANDLER(ServiceWorkerMsg_CacheMatchAllSuccess,
- OnCacheMatchAllSuccess)
- IPC_MESSAGE_HANDLER(ServiceWorkerMsg_CacheKeysSuccess,
- OnCacheKeysSuccess)
- IPC_MESSAGE_HANDLER(ServiceWorkerMsg_CacheBatchSuccess,
- OnCacheBatchSuccess)
- IPC_MESSAGE_HANDLER(ServiceWorkerMsg_CacheMatchError,
- OnCacheMatchError)
- IPC_MESSAGE_HANDLER(ServiceWorkerMsg_CacheMatchAllError,
- OnCacheMatchAllError)
- IPC_MESSAGE_HANDLER(ServiceWorkerMsg_CacheKeysError,
- OnCacheKeysError)
- IPC_MESSAGE_HANDLER(ServiceWorkerMsg_CacheBatchError,
- OnCacheBatchError)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
-
- return handled;
-}
-
-void ServiceWorkerCacheStorageDispatcher::OnCacheStorageHasSuccess(
- int request_id) {
- CacheStorageCallbacks* callbacks = has_callbacks_.Lookup(request_id);
- callbacks->onSuccess();
- has_callbacks_.Remove(request_id);
-}
-
-void ServiceWorkerCacheStorageDispatcher::OnCacheStorageOpenSuccess(
- int request_id,
- int cache_id) {
- WebCache* web_cache = new WebCache(weak_factory_.GetWeakPtr(), cache_id);
- web_caches_.AddWithID(web_cache, cache_id);
- CacheStorageWithCacheCallbacks* callbacks =
- open_callbacks_.Lookup(request_id);
- callbacks->onSuccess(web_cache);
- open_callbacks_.Remove(request_id);
-}
-
-void ServiceWorkerCacheStorageDispatcher::OnCacheStorageDeleteSuccess(
- int request_id) {
- CacheStorageCallbacks* callbacks = delete_callbacks_.Lookup(request_id);
- callbacks->onSuccess();
- delete_callbacks_.Remove(request_id);
-}
-
-void ServiceWorkerCacheStorageDispatcher::OnCacheStorageKeysSuccess(
- int request_id,
- const std::vector<base::string16>& keys) {
- CacheStorageKeysCallbacks* callbacks = keys_callbacks_.Lookup(request_id);
- blink::WebVector<blink::WebString> webKeys(keys.size());
- for (size_t i = 0; i < keys.size(); ++i)
- webKeys[i] = keys[i];
-
- callbacks->onSuccess(&webKeys);
- keys_callbacks_.Remove(request_id);
-}
-
-void ServiceWorkerCacheStorageDispatcher::OnCacheStorageHasError(
- int request_id,
- blink::WebServiceWorkerCacheError reason) {
- CacheStorageCallbacks* callbacks = has_callbacks_.Lookup(request_id);
- callbacks->onError(&reason);
- has_callbacks_.Remove(request_id);
-}
-
-void ServiceWorkerCacheStorageDispatcher::OnCacheStorageOpenError(
- int request_id,
- blink::WebServiceWorkerCacheError reason) {
- CacheStorageWithCacheCallbacks* callbacks =
- open_callbacks_.Lookup(request_id);
- callbacks->onError(&reason);
- open_callbacks_.Remove(request_id);
-}
-
-void ServiceWorkerCacheStorageDispatcher::OnCacheStorageDeleteError(
- int request_id,
- blink::WebServiceWorkerCacheError reason) {
- CacheStorageCallbacks* callbacks = delete_callbacks_.Lookup(request_id);
- callbacks->onError(&reason);
- delete_callbacks_.Remove(request_id);
-}
-
-void ServiceWorkerCacheStorageDispatcher::OnCacheStorageKeysError(
- int request_id,
- blink::WebServiceWorkerCacheError reason) {
- CacheStorageKeysCallbacks* callbacks = keys_callbacks_.Lookup(request_id);
- callbacks->onError(&reason);
- keys_callbacks_.Remove(request_id);
-}
-
-void ServiceWorkerCacheStorageDispatcher::OnCacheMatchSuccess(
- int request_id,
- const ServiceWorkerResponse& response) {
- blink::WebServiceWorkerCache::CacheMatchCallbacks* callbacks =
- cache_match_callbacks_.Lookup(request_id);
-
- blink::WebServiceWorkerResponse web_response;
- PopulateWebResponseFromResponse(response, &web_response);
- callbacks->onSuccess(&web_response);
- cache_match_callbacks_.Remove(request_id);
-}
-
-void ServiceWorkerCacheStorageDispatcher::OnCacheMatchAllSuccess(
- int request_id,
- const std::vector<ServiceWorkerResponse>& responses) {
- blink::WebServiceWorkerCache::CacheWithResponsesCallbacks* callbacks =
- cache_match_all_callbacks_.Lookup(request_id);
-
- blink::WebVector<blink::WebServiceWorkerResponse>
- web_responses = WebResponsesFromResponses(responses);
- callbacks->onSuccess(&web_responses);
- cache_match_all_callbacks_.Remove(request_id);
-}
-
-void ServiceWorkerCacheStorageDispatcher::OnCacheKeysSuccess(
-
- int request_id,
- const std::vector<ServiceWorkerFetchRequest>& requests) {
- blink::WebServiceWorkerCache::CacheWithRequestsCallbacks* callbacks =
- cache_keys_callbacks_.Lookup(request_id);
-
- blink::WebVector<blink::WebServiceWorkerRequest>
- web_requests = WebRequestsFromRequests(requests);
- callbacks->onSuccess(&web_requests);
- cache_keys_callbacks_.Remove(request_id);
-}
-
-void ServiceWorkerCacheStorageDispatcher::OnCacheBatchSuccess(
- int request_id,
- const std::vector<ServiceWorkerResponse>& responses) {
- blink::WebServiceWorkerCache::CacheWithResponsesCallbacks* callbacks =
- cache_batch_callbacks_.Lookup(request_id);
-
- blink::WebVector<blink::WebServiceWorkerResponse>
- web_responses = WebResponsesFromResponses(responses);
- callbacks->onSuccess(&web_responses);
- cache_batch_callbacks_.Remove(request_id);
-}
-
-void ServiceWorkerCacheStorageDispatcher::OnCacheMatchError(
- int request_id,
- blink::WebServiceWorkerCacheError reason) {
- blink::WebServiceWorkerCache::CacheMatchCallbacks* callbacks =
- cache_match_callbacks_.Lookup(request_id);
- callbacks->onError(&reason);
- cache_match_callbacks_.Remove(request_id);
-}
-
-void ServiceWorkerCacheStorageDispatcher::OnCacheMatchAllError(
- int request_id,
- blink::WebServiceWorkerCacheError reason) {
- blink::WebServiceWorkerCache::CacheWithResponsesCallbacks* callbacks =
- cache_match_all_callbacks_.Lookup(request_id);
- callbacks->onError(&reason);
- cache_match_all_callbacks_.Remove(request_id);
-}
-
-void ServiceWorkerCacheStorageDispatcher::OnCacheKeysError(
- int request_id,
- blink::WebServiceWorkerCacheError reason) {
- blink::WebServiceWorkerCache::CacheWithRequestsCallbacks* callbacks =
- cache_keys_callbacks_.Lookup(request_id);
- callbacks->onError(&reason);
- cache_keys_callbacks_.Remove(request_id);
-}
-
-void ServiceWorkerCacheStorageDispatcher::OnCacheBatchError(
- int request_id,
- blink::WebServiceWorkerCacheError reason) {
- blink::WebServiceWorkerCache::CacheWithResponsesCallbacks* callbacks =
- cache_batch_callbacks_.Lookup(request_id);
- callbacks->onError(&reason);
- cache_batch_callbacks_.Remove(request_id);
-}
-
-void ServiceWorkerCacheStorageDispatcher::dispatchHas(
- CacheStorageCallbacks* callbacks,
- const blink::WebString& cacheName) {
- int request_id = has_callbacks_.Add(callbacks);
- script_context_->Send(new ServiceWorkerHostMsg_CacheStorageHas(
- script_context_->GetRoutingID(), request_id, cacheName));
-}
-
-void ServiceWorkerCacheStorageDispatcher::dispatchOpen(
- CacheStorageWithCacheCallbacks* callbacks,
- const blink::WebString& cacheName) {
- int request_id = open_callbacks_.Add(callbacks);
- script_context_->Send(new ServiceWorkerHostMsg_CacheStorageOpen(
- script_context_->GetRoutingID(), request_id, cacheName));
-}
-
-void ServiceWorkerCacheStorageDispatcher::dispatchDelete(
- CacheStorageCallbacks* callbacks,
- const blink::WebString& cacheName) {
- int request_id = delete_callbacks_.Add(callbacks);
- script_context_->Send(new ServiceWorkerHostMsg_CacheStorageDelete(
- script_context_->GetRoutingID(), request_id, cacheName));
-}
-
-void ServiceWorkerCacheStorageDispatcher::dispatchKeys(
- CacheStorageKeysCallbacks* callbacks) {
- int request_id = keys_callbacks_.Add(callbacks);
- script_context_->Send(new ServiceWorkerHostMsg_CacheStorageKeys(
- script_context_->GetRoutingID(), request_id));
-}
-
-void ServiceWorkerCacheStorageDispatcher::dispatchMatchForCache(
- int cache_id,
- blink::WebServiceWorkerCache::CacheMatchCallbacks* callbacks,
- const blink::WebServiceWorkerRequest& request,
- const blink::WebServiceWorkerCache::QueryParams& query_params) {
- int request_id = cache_match_callbacks_.Add(callbacks);
-
- script_context_->Send(new ServiceWorkerHostMsg_CacheMatch(
- script_context_->GetRoutingID(), request_id, cache_id,
- FetchRequestFromWebRequest(request),
- QueryParamsFromWebQueryParams(query_params)));
-}
-
-void ServiceWorkerCacheStorageDispatcher::dispatchMatchAllForCache(
- int cache_id,
- blink::WebServiceWorkerCache::CacheWithResponsesCallbacks* callbacks,
- const blink::WebServiceWorkerRequest& request,
- const blink::WebServiceWorkerCache::QueryParams& query_params) {
- int request_id = cache_match_all_callbacks_.Add(callbacks);
-
- script_context_->Send(new ServiceWorkerHostMsg_CacheMatchAll(
- script_context_->GetRoutingID(), request_id, cache_id,
- FetchRequestFromWebRequest(request),
- QueryParamsFromWebQueryParams(query_params)));
-}
-
-void ServiceWorkerCacheStorageDispatcher::dispatchKeysForCache(
- int cache_id,
- blink::WebServiceWorkerCache::CacheWithRequestsCallbacks* callbacks,
- const blink::WebServiceWorkerRequest* request,
- const blink::WebServiceWorkerCache::QueryParams& query_params) {
- int request_id = cache_keys_callbacks_.Add(callbacks);
-
- script_context_->Send(new ServiceWorkerHostMsg_CacheKeys(
- script_context_->GetRoutingID(), request_id, cache_id,
- request ? FetchRequestFromWebRequest(*request)
- : ServiceWorkerFetchRequest(),
- QueryParamsFromWebQueryParams(query_params)));
-}
-
-void ServiceWorkerCacheStorageDispatcher::dispatchBatchForCache(
- int cache_id,
- blink::WebServiceWorkerCache::CacheWithResponsesCallbacks* callbacks,
- const blink::WebVector<
- blink::WebServiceWorkerCache::BatchOperation>& web_operations) {
- int request_id = cache_batch_callbacks_.Add(callbacks);
-
- std::vector<ServiceWorkerBatchOperation> operations;
- operations.reserve(web_operations.size());
- for (size_t i = 0; i < web_operations.size(); ++i) {
- operations.push_back(
- BatchOperationFromWebBatchOperation(web_operations[i]));
- }
-
- script_context_->Send(new ServiceWorkerHostMsg_CacheBatch(
- script_context_->GetRoutingID(), request_id, cache_id, operations));
-}
-
-void ServiceWorkerCacheStorageDispatcher::OnWebCacheDestruction(int cache_id) {
- web_caches_.Remove(cache_id);
- script_context_->Send(new ServiceWorkerHostMsg_CacheClosed(
- script_context_->GetRoutingID(), cache_id));
-}
-
-void ServiceWorkerCacheStorageDispatcher::PopulateWebResponseFromResponse(
- const ServiceWorkerResponse& response,
- blink::WebServiceWorkerResponse* web_response) {
- web_response->setURL(response.url);
- web_response->setStatus(response.status_code);
- web_response->setStatusText(base::ASCIIToUTF16(response.status_text));
- web_response->setResponseType(response.response_type);
-
- for (const auto& i : response.headers) {
- web_response->setHeader(base::ASCIIToUTF16(i.first),
- base::ASCIIToUTF16(i.second));
- }
-
- if (!response.blob_uuid.empty()) {
- web_response->setBlob(blink::WebString::fromUTF8(response.blob_uuid),
- response.blob_size);
- // Let the host know that it can release its reference to the blob.
- script_context_->Send(new ServiceWorkerHostMsg_BlobDataHandled(
- script_context_->GetRoutingID(), response.blob_uuid));
- }
-}
-
-blink::WebVector<blink::WebServiceWorkerResponse>
-ServiceWorkerCacheStorageDispatcher::WebResponsesFromResponses(
- const std::vector<ServiceWorkerResponse>& responses) {
- blink::WebVector<blink::WebServiceWorkerResponse> web_responses(
- responses.size());
- for (size_t i = 0; i < responses.size(); ++i)
- PopulateWebResponseFromResponse(responses[i], &(web_responses[i]));
- return web_responses;
-}
-
-} // namespace content
diff --git a/chromium/content/renderer/service_worker/service_worker_cache_storage_dispatcher.h b/chromium/content/renderer/service_worker/service_worker_cache_storage_dispatcher.h
deleted file mode 100644
index 41aa8170522..00000000000
--- a/chromium/content/renderer/service_worker/service_worker_cache_storage_dispatcher.h
+++ /dev/null
@@ -1,159 +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_RENDERER_SERVICE_WORKER_SERVICE_WORKER_CACHE_STORAGE_DISPATCHER_H_
-#define CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_CACHE_STORAGE_DISPATCHER_H_
-
-#include <vector>
-
-#include "base/id_map.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/strings/string16.h"
-#include "content/public/renderer/render_process_observer.h"
-#include "third_party/WebKit/public/platform/WebServiceWorkerCache.h"
-#include "third_party/WebKit/public/platform/WebServiceWorkerCacheError.h"
-#include "third_party/WebKit/public/platform/WebServiceWorkerCacheStorage.h"
-
-namespace content {
-
-struct ServiceWorkerFetchRequest;
-class ServiceWorkerScriptContext;
-struct ServiceWorkerResponse;
-
-// There is one ServiceWorkerCacheStorageDispatcher per
-// ServiceWorkerScriptContext. It handles CacheStorage operations with messages
-// to/from the browser, creating Cache objects (for which it also handles
-// messages) as it goes.
-
-class ServiceWorkerCacheStorageDispatcher
- : public blink::WebServiceWorkerCacheStorage {
- public:
- explicit ServiceWorkerCacheStorageDispatcher(
- ServiceWorkerScriptContext* script_context);
- virtual ~ServiceWorkerCacheStorageDispatcher();
-
- // ServiceWorkerScriptContext calls our OnMessageReceived directly.
- bool OnMessageReceived(const IPC::Message& message);
-
- // Message handlers for CacheStorage messages from the browser process.
- void OnCacheStorageHasSuccess(int request_id);
- void OnCacheStorageOpenSuccess(int request_id, int cache_id);
- void OnCacheStorageDeleteSuccess(int request_id);
- void OnCacheStorageKeysSuccess(int request_id,
- const std::vector<base::string16>& keys);
-
- void OnCacheStorageHasError(int request_id,
- blink::WebServiceWorkerCacheError reason);
- void OnCacheStorageOpenError(int request_id,
- blink::WebServiceWorkerCacheError reason);
- void OnCacheStorageDeleteError(int request_id,
- blink::WebServiceWorkerCacheError reason);
- void OnCacheStorageKeysError(int request_id,
- blink::WebServiceWorkerCacheError reason);
-
- // Message handlers for Cache messages from the browser process.
- void OnCacheMatchSuccess(int request_id,
- const ServiceWorkerResponse& response);
- void OnCacheMatchAllSuccess(
- int request_id,
- const std::vector<ServiceWorkerResponse>& response);
- void OnCacheKeysSuccess(
- int request_id,
- const std::vector<ServiceWorkerFetchRequest>& response);
- void OnCacheBatchSuccess(int request_id,
- const std::vector<ServiceWorkerResponse>& response);
-
- void OnCacheMatchError(int request_id,
- blink::WebServiceWorkerCacheError reason);
- void OnCacheMatchAllError(int request_id,
- blink::WebServiceWorkerCacheError reason);
- void OnCacheKeysError(int request_id,
- blink::WebServiceWorkerCacheError reason);
- void OnCacheBatchError(int request_id,
- blink::WebServiceWorkerCacheError reason);
-
- // From WebServiceWorkerCacheStorage:
- virtual void dispatchHas(CacheStorageCallbacks* callbacks,
- const blink::WebString& cacheName);
- virtual void dispatchOpen(CacheStorageWithCacheCallbacks* callbacks,
- const blink::WebString& cacheName);
- virtual void dispatchDelete(CacheStorageCallbacks* callbacks,
- const blink::WebString& cacheName);
- virtual void dispatchKeys(CacheStorageKeysCallbacks* callbacks);
-
- // These methods are used by WebCache to forward events to the browser
- // process.
- void dispatchMatchForCache(
- int cache_id,
- blink::WebServiceWorkerCache::CacheMatchCallbacks* callbacks,
- const blink::WebServiceWorkerRequest& request,
- const blink::WebServiceWorkerCache::QueryParams& query_params);
- void dispatchMatchAllForCache(
- int cache_id,
- blink::WebServiceWorkerCache::CacheWithResponsesCallbacks* callbacks,
- const blink::WebServiceWorkerRequest& request,
- const blink::WebServiceWorkerCache::QueryParams& query_params);
- void dispatchKeysForCache(
- int cache_id,
- blink::WebServiceWorkerCache::CacheWithRequestsCallbacks* callbacks,
- const blink::WebServiceWorkerRequest* request,
- const blink::WebServiceWorkerCache::QueryParams& query_params);
- void dispatchBatchForCache(
- int cache_id,
- blink::WebServiceWorkerCache::CacheWithResponsesCallbacks* callbacks,
- const blink::WebVector<blink::WebServiceWorkerCache::BatchOperation>&
- batch_operations);
-
- void OnWebCacheDestruction(int cache_id);
-
- private:
- class WebCache;
-
- typedef IDMap<CacheStorageCallbacks, IDMapOwnPointer> CallbacksMap;
- typedef IDMap<CacheStorageWithCacheCallbacks, IDMapOwnPointer>
- WithCacheCallbacksMap;
- typedef IDMap<CacheStorageKeysCallbacks, IDMapOwnPointer>
- KeysCallbacksMap;
-
- typedef IDMap<blink::WebServiceWorkerCache::CacheMatchCallbacks,
- IDMapOwnPointer> MatchCallbacksMap;
- typedef IDMap<blink::WebServiceWorkerCache::CacheWithResponsesCallbacks,
- IDMapOwnPointer> WithResponsesCallbacksMap;
- typedef IDMap<blink::WebServiceWorkerCache::CacheWithRequestsCallbacks,
- IDMapOwnPointer> WithRequestsCallbacksMap;
-
- void PopulateWebResponseFromResponse(
- const ServiceWorkerResponse& response,
- blink::WebServiceWorkerResponse* web_response);
-
- blink::WebVector<blink::WebServiceWorkerResponse> WebResponsesFromResponses(
- const std::vector<ServiceWorkerResponse>& responses);
-
- // Not owned. The script context containing this object.
- ServiceWorkerScriptContext* script_context_;
-
- CallbacksMap has_callbacks_;
- WithCacheCallbacksMap open_callbacks_;
- CallbacksMap delete_callbacks_;
- KeysCallbacksMap keys_callbacks_;
-
- // The individual caches created under this CacheStorage object.
- IDMap<WebCache, IDMapExternalPointer> web_caches_;
-
- // These ID maps are held in the CacheStorage object rather than the Cache
- // object to ensure that the IDs are unique.
- MatchCallbacksMap cache_match_callbacks_;
- WithResponsesCallbacksMap cache_match_all_callbacks_;
- WithRequestsCallbacksMap cache_keys_callbacks_;
- WithResponsesCallbacksMap cache_batch_callbacks_;
-
- base::WeakPtrFactory<ServiceWorkerCacheStorageDispatcher> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(ServiceWorkerCacheStorageDispatcher);
-};
-
-} // namespace content
-
-#endif // CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_CACHE_STORAGE_DISPATCHER_H_
diff --git a/chromium/content/renderer/service_worker/service_worker_script_context.cc b/chromium/content/renderer/service_worker/service_worker_script_context.cc
index 9aa65d5661b..de32db8ddc3 100644
--- a/chromium/content/renderer/service_worker/service_worker_script_context.cc
+++ b/chromium/content/renderer/service_worker/service_worker_script_context.cc
@@ -4,18 +4,26 @@
#include "content/renderer/service_worker/service_worker_script_context.h"
-#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/trace_event/trace_event.h"
+#include "content/child/notifications/notification_data_conversions.h"
+#include "content/child/service_worker/web_service_worker_registration_impl.h"
#include "content/child/thread_safe_sender.h"
#include "content/child/webmessageportchannel_impl.h"
+#include "content/common/message_port_messages.h"
#include "content/common/service_worker/service_worker_messages.h"
+#include "content/public/common/referrer.h"
#include "content/renderer/service_worker/embedded_worker_context_client.h"
#include "ipc/ipc_message.h"
+#include "third_party/WebKit/public/platform/WebCrossOriginServiceWorkerClient.h"
#include "third_party/WebKit/public/platform/WebReferrerPolicy.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerClientQueryOptions.h"
#include "third_party/WebKit/public/platform/WebServiceWorkerRequest.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/platform/WebURL.h"
+#include "third_party/WebKit/public/platform/modules/notifications/WebNotificationData.h"
#include "third_party/WebKit/public/web/WebServiceWorkerContextClient.h"
#include "third_party/WebKit/public/web/WebServiceWorkerContextProxy.h"
@@ -23,17 +31,29 @@ namespace content {
namespace {
-void SendPostMessageToDocumentOnMainThread(
+void SendPostMessageToClientOnMainThread(
ThreadSafeSender* sender,
int routing_id,
- int client_id,
+ const std::string& uuid,
const base::string16& message,
scoped_ptr<blink::WebMessagePortChannelArray> channels) {
- sender->Send(new ServiceWorkerHostMsg_PostMessageToDocument(
- routing_id, client_id, message,
+ sender->Send(new ServiceWorkerHostMsg_PostMessageToClient(
+ routing_id, uuid, message,
WebMessagePortChannelImpl::ExtractMessagePortIDs(channels.release())));
}
+void SendCrossOriginMessageToClientOnMainThread(
+ ThreadSafeSender* sender,
+ int message_port_id,
+ const base::string16& message,
+ scoped_ptr<blink::WebMessagePortChannelArray> channels) {
+ sender->Send(new MessagePortHostMsg_PostMessage(
+ message_port_id,
+ MessagePortMessage(message),
+ WebMessagePortChannelImpl::ExtractMessagePortIDs(
+ channels.release())));
+}
+
blink::WebURLRequest::FetchRequestMode GetBlinkFetchRequestMode(
FetchRequestMode mode) {
return static_cast<blink::WebURLRequest::FetchRequestMode>(mode);
@@ -56,13 +76,28 @@ blink::WebURLRequest::FrameType GetBlinkFrameType(
return static_cast<blink::WebURLRequest::FrameType>(frame_type);
}
+blink::WebServiceWorkerClientInfo
+ToWebServiceWorkerClientInfo(const ServiceWorkerClientInfo& client_info) {
+ DCHECK(client_info.IsValid());
+
+ blink::WebServiceWorkerClientInfo web_client_info;
+
+ web_client_info.uuid = base::UTF8ToUTF16(client_info.client_uuid);
+ web_client_info.pageVisibilityState = client_info.page_visibility_state;
+ web_client_info.isFocused = client_info.is_focused;
+ web_client_info.url = client_info.url;
+ web_client_info.frameType = GetBlinkFrameType(client_info.frame_type);
+ web_client_info.clientType = client_info.client_type;
+
+ return web_client_info;
+}
+
} // namespace
ServiceWorkerScriptContext::ServiceWorkerScriptContext(
EmbeddedWorkerContextClient* embedded_context,
blink::WebServiceWorkerContextProxy* proxy)
- : cache_storage_dispatcher_(new ServiceWorkerCacheStorageDispatcher(this)),
- embedded_context_(embedded_context),
+ : embedded_context_(embedded_context),
proxy_(proxy) {
}
@@ -76,22 +111,38 @@ void ServiceWorkerScriptContext::OnMessageReceived(
IPC_MESSAGE_HANDLER(ServiceWorkerMsg_FetchEvent, OnFetchEvent)
IPC_MESSAGE_HANDLER(ServiceWorkerMsg_InstallEvent, OnInstallEvent)
IPC_MESSAGE_HANDLER(ServiceWorkerMsg_SyncEvent, OnSyncEvent)
+ IPC_MESSAGE_HANDLER(ServiceWorkerMsg_NotificationClickEvent,
+ OnNotificationClickEvent)
IPC_MESSAGE_HANDLER(ServiceWorkerMsg_PushEvent, OnPushEvent)
IPC_MESSAGE_HANDLER(ServiceWorkerMsg_GeofencingEvent, OnGeofencingEvent)
+ IPC_MESSAGE_HANDLER(ServiceWorkerMsg_CrossOriginConnectEvent,
+ OnCrossOriginConnectEvent)
IPC_MESSAGE_HANDLER(ServiceWorkerMsg_MessageToWorker, OnPostMessage)
- IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DidGetClientDocuments,
- OnDidGetClientDocuments)
+ IPC_MESSAGE_HANDLER(ServiceWorkerMsg_CrossOriginMessageToWorker,
+ OnCrossOriginMessageToWorker)
+ IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DidGetClients,
+ OnDidGetClients)
+ IPC_MESSAGE_HANDLER(ServiceWorkerMsg_OpenWindowResponse,
+ OnOpenWindowResponse)
+ IPC_MESSAGE_HANDLER(ServiceWorkerMsg_OpenWindowError,
+ OnOpenWindowError)
+ IPC_MESSAGE_HANDLER(ServiceWorkerMsg_FocusClientResponse,
+ OnFocusClientResponse)
+ IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DidSkipWaiting, OnDidSkipWaiting)
+ IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DidClaimClients, OnDidClaimClients)
+ IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ClaimClientsError, OnClaimClientsError)
+ IPC_MESSAGE_HANDLER(ServiceWorkerMsg_Ping, OnPing);
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
- // TODO(gavinp): Would it be preferable to put an AddListener() method to
- // EmbeddedWorkerContextClient?
- if (!handled)
- handled = cache_storage_dispatcher_->OnMessageReceived(message);
-
DCHECK(handled);
}
+void ServiceWorkerScriptContext::SetRegistrationInServiceWorkerGlobalScope(
+ scoped_ptr<WebServiceWorkerRegistrationImpl> registration) {
+ proxy_->setRegistration(registration.release());
+}
+
void ServiceWorkerScriptContext::DidHandleActivateEvent(
int request_id,
blink::WebServiceWorkerEventResult result) {
@@ -129,32 +180,127 @@ void ServiceWorkerScriptContext::DidHandleFetchEvent(
GetRoutingID(), request_id, result, response));
}
+void ServiceWorkerScriptContext::DidHandleNotificationClickEvent(
+ int request_id,
+ blink::WebServiceWorkerEventResult result) {
+ UMA_HISTOGRAM_TIMES(
+ "ServiceWorker.NotificationClickEventExecutionTime",
+ base::TimeTicks::Now() - notification_click_start_timings_[request_id]);
+ notification_click_start_timings_.erase(request_id);
+
+ Send(new ServiceWorkerHostMsg_NotificationClickEventFinished(
+ GetRoutingID(), request_id));
+}
+
+void ServiceWorkerScriptContext::DidHandlePushEvent(
+ int request_id,
+ blink::WebServiceWorkerEventResult result) {
+ if (result == blink::WebServiceWorkerEventResultCompleted) {
+ UMA_HISTOGRAM_TIMES(
+ "ServiceWorker.PushEventExecutionTime",
+ base::TimeTicks::Now() - push_start_timings_[request_id]);
+ }
+ push_start_timings_.erase(request_id);
+
+ Send(new ServiceWorkerHostMsg_PushEventFinished(
+ GetRoutingID(), request_id, result));
+}
+
void ServiceWorkerScriptContext::DidHandleSyncEvent(int request_id) {
Send(new ServiceWorkerHostMsg_SyncEventFinished(
GetRoutingID(), request_id));
}
-void ServiceWorkerScriptContext::GetClientDocuments(
+void ServiceWorkerScriptContext::DidHandleCrossOriginConnectEvent(
+ int request_id,
+ bool accept_connection) {
+ Send(new ServiceWorkerHostMsg_CrossOriginConnectEventFinished(
+ GetRoutingID(), request_id, accept_connection));
+}
+
+void ServiceWorkerScriptContext::GetClients(
+ const blink::WebServiceWorkerClientQueryOptions& weboptions,
blink::WebServiceWorkerClientsCallbacks* callbacks) {
DCHECK(callbacks);
int request_id = pending_clients_callbacks_.Add(callbacks);
- Send(new ServiceWorkerHostMsg_GetClientDocuments(
- GetRoutingID(), request_id));
+ ServiceWorkerClientQueryOptions options;
+ options.client_type = weboptions.clientType;
+ options.include_uncontrolled = weboptions.includeUncontrolled;
+ Send(new ServiceWorkerHostMsg_GetClients(
+ GetRoutingID(), request_id, options));
+}
+
+void ServiceWorkerScriptContext::OpenWindow(
+ const GURL& url, blink::WebServiceWorkerClientCallbacks* callbacks) {
+ DCHECK(callbacks);
+ int request_id = pending_client_callbacks_.Add(callbacks);
+ Send(new ServiceWorkerHostMsg_OpenWindow(GetRoutingID(), request_id, url));
+}
+
+void ServiceWorkerScriptContext::SetCachedMetadata(const GURL& url,
+ const char* data,
+ size_t size) {
+ std::vector<char> copy(data, data + size);
+ Send(new ServiceWorkerHostMsg_SetCachedMetadata(GetRoutingID(), url, copy));
+}
+
+void ServiceWorkerScriptContext::ClearCachedMetadata(const GURL& url) {
+ Send(new ServiceWorkerHostMsg_ClearCachedMetadata(GetRoutingID(), url));
+}
+
+void ServiceWorkerScriptContext::PostMessageToClient(
+ const base::string16& uuid,
+ const base::string16& message,
+ scoped_ptr<blink::WebMessagePortChannelArray> channels) {
+ // This may send channels for MessagePorts, and all internal book-keeping
+ // messages for MessagePort (e.g. QueueMessages) are sent from main thread
+ // (with thread hopping), so we need to do the same thread hopping here not
+ // to overtake those messages.
+ embedded_context_->main_thread_task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&SendPostMessageToClientOnMainThread,
+ make_scoped_refptr(embedded_context_->thread_safe_sender()),
+ GetRoutingID(),
+ base::UTF16ToUTF8(uuid),
+ message, base::Passed(&channels)));
}
-void ServiceWorkerScriptContext::PostMessageToDocument(
- int client_id,
+void ServiceWorkerScriptContext::PostCrossOriginMessageToClient(
+ const blink::WebCrossOriginServiceWorkerClient& client,
const base::string16& message,
scoped_ptr<blink::WebMessagePortChannelArray> channels) {
// This may send channels for MessagePorts, and all internal book-keeping
// messages for MessagePort (e.g. QueueMessages) are sent from main thread
// (with thread hopping), so we need to do the same thread hopping here not
// to overtake those messages.
- embedded_context_->main_thread_proxy()->PostTask(
+ embedded_context_->main_thread_task_runner()->PostTask(
FROM_HERE,
- base::Bind(&SendPostMessageToDocumentOnMainThread,
+ base::Bind(&SendCrossOriginMessageToClientOnMainThread,
make_scoped_refptr(embedded_context_->thread_safe_sender()),
- GetRoutingID(), client_id, message, base::Passed(&channels)));
+ client.clientID, message, base::Passed(&channels)));
+}
+
+void ServiceWorkerScriptContext::FocusClient(
+ const base::string16& uuid,
+ blink::WebServiceWorkerClientCallbacks* callback) {
+ DCHECK(callback);
+ int request_id = pending_client_callbacks_.Add(callback);
+ Send(new ServiceWorkerHostMsg_FocusClient(GetRoutingID(), request_id,
+ base::UTF16ToUTF8(uuid)));
+}
+
+void ServiceWorkerScriptContext::ClaimClients(
+ blink::WebServiceWorkerClientsClaimCallbacks* callbacks) {
+ DCHECK(callbacks);
+ int request_id = pending_claim_clients_callbacks_.Add(callbacks);
+ Send(new ServiceWorkerHostMsg_ClaimClients(GetRoutingID(), request_id));
+}
+
+void ServiceWorkerScriptContext::SkipWaiting(
+ blink::WebServiceWorkerSkipWaitingCallbacks* callbacks) {
+ DCHECK(callbacks);
+ int request_id = pending_skip_waiting_callbacks_.Add(callbacks);
+ Send(new ServiceWorkerHostMsg_SkipWaiting(GetRoutingID(), request_id));
}
void ServiceWorkerScriptContext::Send(IPC::Message* message) {
@@ -172,8 +318,7 @@ void ServiceWorkerScriptContext::OnActivateEvent(int request_id) {
proxy_->dispatchActivateEvent(request_id);
}
-void ServiceWorkerScriptContext::OnInstallEvent(int request_id,
- int active_version_id) {
+void ServiceWorkerScriptContext::OnInstallEvent(int request_id) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerScriptContext::OnInstallEvent");
install_start_timings_[request_id] = base::TimeTicks::Now();
@@ -198,8 +343,9 @@ void ServiceWorkerScriptContext::OnFetchEvent(
webRequest.setBlob(blink::WebString::fromUTF8(request.blob_uuid),
request.blob_size);
}
- webRequest.setReferrer(blink::WebString::fromUTF8(request.referrer.spec()),
- blink::WebReferrerPolicyDefault);
+ webRequest.setReferrer(
+ blink::WebString::fromUTF8(request.referrer.url.spec()),
+ request.referrer.policy);
webRequest.setMode(GetBlinkFetchRequestMode(request.mode));
webRequest.setCredentialsMode(
GetBlinkFetchCredentialsMode(request.credentials_mode));
@@ -217,13 +363,25 @@ void ServiceWorkerScriptContext::OnSyncEvent(int request_id) {
proxy_->dispatchSyncEvent(request_id);
}
+void ServiceWorkerScriptContext::OnNotificationClickEvent(
+ int request_id,
+ int64_t persistent_notification_id,
+ const PlatformNotificationData& notification_data) {
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerScriptContext::OnNotificationClickEvent");
+ notification_click_start_timings_[request_id] = base::TimeTicks::Now();
+ proxy_->dispatchNotificationClickEvent(
+ request_id,
+ persistent_notification_id,
+ ToWebNotificationData(notification_data));
+}
+
void ServiceWorkerScriptContext::OnPushEvent(int request_id,
const std::string& data) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerScriptContext::OnPushEvent");
+ push_start_timings_[request_id] = base::TimeTicks::Now();
proxy_->dispatchPushEvent(request_id, blink::WebString::fromUTF8(data));
- Send(new ServiceWorkerHostMsg_PushEventFinished(
- GetRoutingID(), request_id));
}
void ServiceWorkerScriptContext::OnGeofencingEvent(
@@ -239,21 +397,28 @@ void ServiceWorkerScriptContext::OnGeofencingEvent(
request_id));
}
+void ServiceWorkerScriptContext::OnCrossOriginConnectEvent(
+ int request_id,
+ const NavigatorConnectClient& client) {
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerScriptContext::OnCrossOriginConnectEvent");
+ blink::WebCrossOriginServiceWorkerClient web_client;
+ web_client.origin = client.origin;
+ web_client.targetURL = client.target_url;
+ web_client.clientID = client.message_port_id;
+ proxy_->dispatchCrossOriginConnectEvent(request_id, web_client);
+}
+
void ServiceWorkerScriptContext::OnPostMessage(
const base::string16& message,
- const std::vector<int>& sent_message_port_ids,
+ const std::vector<TransferredMessagePort>& sent_message_ports,
const std::vector<int>& new_routing_ids) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerScriptContext::OnPostEvent");
- std::vector<WebMessagePortChannelImpl*> ports;
- if (!sent_message_port_ids.empty()) {
- base::MessageLoopProxy* loop_proxy = embedded_context_->main_thread_proxy();
- ports.resize(sent_message_port_ids.size());
- for (size_t i = 0; i < sent_message_port_ids.size(); ++i) {
- ports[i] = new WebMessagePortChannelImpl(
- new_routing_ids[i], sent_message_port_ids[i], loop_proxy);
- }
- }
+ blink::WebMessagePortChannelArray ports =
+ WebMessagePortChannelImpl::CreatePorts(
+ sent_message_ports, new_routing_ids,
+ embedded_context_->main_thread_task_runner());
// dispatchMessageEvent is expected to execute onmessage function
// synchronously.
@@ -264,10 +429,29 @@ void ServiceWorkerScriptContext::OnPostMessage(
base::TimeTicks::Now() - before);
}
-void ServiceWorkerScriptContext::OnDidGetClientDocuments(
- int request_id, const std::vector<int>& client_ids) {
+void ServiceWorkerScriptContext::OnCrossOriginMessageToWorker(
+ const NavigatorConnectClient& client,
+ const base::string16& message,
+ const std::vector<TransferredMessagePort>& sent_message_ports,
+ const std::vector<int>& new_routing_ids) {
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerScriptContext::OnCrossOriginMessageToWorker");
+ blink::WebMessagePortChannelArray ports =
+ WebMessagePortChannelImpl::CreatePorts(
+ sent_message_ports, new_routing_ids,
+ embedded_context_->main_thread_task_runner());
+
+ blink::WebCrossOriginServiceWorkerClient web_client;
+ web_client.origin = client.origin;
+ web_client.targetURL = client.target_url;
+ web_client.clientID = client.message_port_id;
+ proxy_->dispatchCrossOriginMessageEvent(web_client, message, ports);
+}
+
+void ServiceWorkerScriptContext::OnDidGetClients(
+ int request_id, const std::vector<ServiceWorkerClientInfo>& clients) {
TRACE_EVENT0("ServiceWorker",
- "ServiceWorkerScriptContext::OnDidGetClientDocuments");
+ "ServiceWorkerScriptContext::OnDidGetClients");
blink::WebServiceWorkerClientsCallbacks* callbacks =
pending_clients_callbacks_.Lookup(request_id);
if (!callbacks) {
@@ -276,9 +460,128 @@ void ServiceWorkerScriptContext::OnDidGetClientDocuments(
}
scoped_ptr<blink::WebServiceWorkerClientsInfo> info(
new blink::WebServiceWorkerClientsInfo);
- info->clientIDs = client_ids;
+ blink::WebVector<blink::WebServiceWorkerClientInfo> convertedClients(
+ clients.size());
+ for (size_t i = 0; i < clients.size(); ++i)
+ convertedClients[i] = ToWebServiceWorkerClientInfo(clients[i]);
+ info->clients.swap(convertedClients);
callbacks->onSuccess(info.release());
pending_clients_callbacks_.Remove(request_id);
}
+void ServiceWorkerScriptContext::OnOpenWindowResponse(
+ int request_id,
+ const ServiceWorkerClientInfo& client) {
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerScriptContext::OnOpenWindowResponse");
+ blink::WebServiceWorkerClientCallbacks* callbacks =
+ pending_client_callbacks_.Lookup(request_id);
+ if (!callbacks) {
+ NOTREACHED() << "Got stray response: " << request_id;
+ return;
+ }
+ scoped_ptr<blink::WebServiceWorkerClientInfo> web_client;
+ if (!client.IsEmpty()) {
+ DCHECK(client.IsValid());
+ web_client.reset(new blink::WebServiceWorkerClientInfo(
+ ToWebServiceWorkerClientInfo(client)));
+ }
+ callbacks->onSuccess(web_client.release());
+ pending_client_callbacks_.Remove(request_id);
+}
+
+void ServiceWorkerScriptContext::OnOpenWindowError(
+ int request_id,
+ const std::string& message) {
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerScriptContext::OnOpenWindowError");
+ blink::WebServiceWorkerClientCallbacks* callbacks =
+ pending_client_callbacks_.Lookup(request_id);
+ if (!callbacks) {
+ NOTREACHED() << "Got stray response: " << request_id;
+ return;
+ }
+ scoped_ptr<blink::WebServiceWorkerError> error(
+ new blink::WebServiceWorkerError(
+ blink::WebServiceWorkerError::ErrorTypeUnknown,
+ blink::WebString::fromUTF8(message)));
+ callbacks->onError(error.release());
+ pending_client_callbacks_.Remove(request_id);
+}
+
+void ServiceWorkerScriptContext::OnFocusClientResponse(
+ int request_id, const ServiceWorkerClientInfo& client) {
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerScriptContext::OnFocusClientResponse");
+ blink::WebServiceWorkerClientCallbacks* callback =
+ pending_client_callbacks_.Lookup(request_id);
+ if (!callback) {
+ NOTREACHED() << "Got stray response: " << request_id;
+ return;
+ }
+ if (!client.IsEmpty()) {
+ DCHECK(client.IsValid());
+ scoped_ptr<blink::WebServiceWorkerClientInfo> web_client (
+ new blink::WebServiceWorkerClientInfo(
+ ToWebServiceWorkerClientInfo(client)));
+ callback->onSuccess(web_client.release());
+ } else {
+ scoped_ptr<blink::WebServiceWorkerError> error(
+ new blink::WebServiceWorkerError(
+ blink::WebServiceWorkerError::ErrorTypeNotFound,
+ "The WindowClient was not found."));
+ callback->onError(error.release());
+ }
+
+ pending_client_callbacks_.Remove(request_id);
+}
+
+void ServiceWorkerScriptContext::OnDidSkipWaiting(int request_id) {
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerScriptContext::OnDidSkipWaiting");
+ blink::WebServiceWorkerSkipWaitingCallbacks* callbacks =
+ pending_skip_waiting_callbacks_.Lookup(request_id);
+ if (!callbacks) {
+ NOTREACHED() << "Got stray response: " << request_id;
+ return;
+ }
+ callbacks->onSuccess();
+ pending_skip_waiting_callbacks_.Remove(request_id);
+}
+
+void ServiceWorkerScriptContext::OnDidClaimClients(int request_id) {
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerScriptContext::OnDidClaimClients");
+ blink::WebServiceWorkerClientsClaimCallbacks* callbacks =
+ pending_claim_clients_callbacks_.Lookup(request_id);
+ if (!callbacks) {
+ NOTREACHED() << "Got stray response: " << request_id;
+ return;
+ }
+ callbacks->onSuccess();
+ pending_claim_clients_callbacks_.Remove(request_id);
+}
+
+void ServiceWorkerScriptContext::OnClaimClientsError(
+ int request_id,
+ blink::WebServiceWorkerError::ErrorType error_type,
+ const base::string16& message) {
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerScriptContext::OnClaimClientsError");
+ blink::WebServiceWorkerClientsClaimCallbacks* callbacks =
+ pending_claim_clients_callbacks_.Lookup(request_id);
+ if (!callbacks) {
+ NOTREACHED() << "Got stray response: " << request_id;
+ return;
+ }
+ scoped_ptr<blink::WebServiceWorkerError> error(
+ new blink::WebServiceWorkerError(error_type, message));
+ callbacks->onError(error.release());
+ pending_claim_clients_callbacks_.Remove(request_id);
+}
+
+void ServiceWorkerScriptContext::OnPing() {
+ Send(new ServiceWorkerHostMsg_Pong(GetRoutingID()));
+}
+
} // namespace content
diff --git a/chromium/content/renderer/service_worker/service_worker_script_context.h b/chromium/content/renderer/service_worker/service_worker_script_context.h
index f98250d04b1..f0c82585d38 100644
--- a/chromium/content/renderer/service_worker/service_worker_script_context.h
+++ b/chromium/content/renderer/service_worker/service_worker_script_context.h
@@ -16,14 +16,18 @@
#include "base/time/time.h"
#include "content/child/webmessageportchannel_impl.h"
#include "content/common/service_worker/service_worker_types.h"
-#include "content/renderer/service_worker/service_worker_cache_storage_dispatcher.h"
#include "third_party/WebKit/public/platform/WebGeofencingEventType.h"
#include "third_party/WebKit/public/platform/WebMessagePortChannel.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerClientsClaimCallbacks.h"
#include "third_party/WebKit/public/platform/WebServiceWorkerClientsInfo.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerError.h"
#include "third_party/WebKit/public/platform/WebServiceWorkerEventResult.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerSkipWaitingCallbacks.h"
namespace blink {
struct WebCircularGeofencingRegion;
+struct WebCrossOriginServiceWorkerClient;
+struct WebServiceWorkerClientQueryOptions;
class WebServiceWorkerContextProxy;
}
@@ -34,6 +38,10 @@ class Message;
namespace content {
class EmbeddedWorkerContextClient;
+class WebServiceWorkerRegistrationImpl;
+struct NavigatorConnectClient;
+struct PlatformNotificationData;
+struct ServiceWorkerClientInfo;
// TODO(kinuko): This should implement WebServiceWorkerContextClient
// rather than having EmbeddedWorkerContextClient implement it.
@@ -48,6 +56,8 @@ class ServiceWorkerScriptContext {
void OnMessageReceived(const IPC::Message& message);
+ void SetRegistrationInServiceWorkerGlobalScope(
+ scoped_ptr<WebServiceWorkerRegistrationImpl> registration);
void DidHandleActivateEvent(int request_id,
blink::WebServiceWorkerEventResult);
void DidHandleInstallEvent(int request_id,
@@ -55,13 +65,32 @@ class ServiceWorkerScriptContext {
void DidHandleFetchEvent(int request_id,
ServiceWorkerFetchEventResult result,
const ServiceWorkerResponse& response);
+ void DidHandleNotificationClickEvent(
+ int request_id,
+ blink::WebServiceWorkerEventResult result);
+ void DidHandlePushEvent(int request_id,
+ blink::WebServiceWorkerEventResult result);
void DidHandleSyncEvent(int request_id);
- void GetClientDocuments(
+ void DidHandleCrossOriginConnectEvent(int request_id, bool accept_connection);
+ void GetClients(
+ const blink::WebServiceWorkerClientQueryOptions& options,
blink::WebServiceWorkerClientsCallbacks* callbacks);
- void PostMessageToDocument(
- int client_id,
+ void OpenWindow(const GURL& url,
+ blink::WebServiceWorkerClientCallbacks* callbacks);
+ void SetCachedMetadata(const GURL& url, const char* data, size_t size);
+ void ClearCachedMetadata(const GURL& url);
+ void PostMessageToClient(
+ const base::string16& uuid,
const base::string16& message,
scoped_ptr<blink::WebMessagePortChannelArray> channels);
+ void PostCrossOriginMessageToClient(
+ const blink::WebCrossOriginServiceWorkerClient& client,
+ const base::string16& message,
+ scoped_ptr<blink::WebMessagePortChannelArray> channels);
+ void FocusClient(const base::string16& uuid,
+ blink::WebServiceWorkerClientCallbacks* callback);
+ void SkipWaiting(blink::WebServiceWorkerSkipWaitingCallbacks* callbacks);
+ void ClaimClients(blink::WebServiceWorkerClientsClaimCallbacks* callbacks);
// Send a message to the browser. Takes ownership of |message|.
void Send(IPC::Message* message);
@@ -70,31 +99,53 @@ class ServiceWorkerScriptContext {
// in the browser process.
int GetRoutingID() const;
- blink::WebServiceWorkerCacheStorage* cache_storage() {
- return cache_storage_dispatcher_.get();
- }
-
private:
typedef IDMap<blink::WebServiceWorkerClientsCallbacks, IDMapOwnPointer>
ClientsCallbacksMap;
-
+ typedef IDMap<blink::WebServiceWorkerClientsClaimCallbacks, IDMapOwnPointer>
+ ClaimClientsCallbacksMap;
+ typedef IDMap<blink::WebServiceWorkerClientCallbacks, IDMapOwnPointer>
+ ClientCallbacksMap;
+ typedef IDMap<blink::WebServiceWorkerSkipWaitingCallbacks, IDMapOwnPointer>
+ SkipWaitingCallbacksMap;
void OnActivateEvent(int request_id);
- void OnInstallEvent(int request_id, int active_version_id);
+ void OnInstallEvent(int request_id);
void OnFetchEvent(int request_id, const ServiceWorkerFetchRequest& request);
void OnSyncEvent(int request_id);
+ void OnNotificationClickEvent(
+ int request_id,
+ int64_t persistent_notification_id,
+ const PlatformNotificationData& notification_data);
void OnPushEvent(int request_id, const std::string& data);
void OnGeofencingEvent(int request_id,
blink::WebGeofencingEventType event_type,
const std::string& region_id,
const blink::WebCircularGeofencingRegion& region);
- void OnPostMessage(const base::string16& message,
- const std::vector<int>& sent_message_port_ids,
- const std::vector<int>& new_routing_ids);
- void OnDidGetClientDocuments(
- int request_id, const std::vector<int>& client_ids);
-
- scoped_ptr<ServiceWorkerCacheStorageDispatcher> cache_storage_dispatcher_;
+ void OnCrossOriginConnectEvent(int request_id,
+ const NavigatorConnectClient& client);
+ void OnPostMessage(
+ const base::string16& message,
+ const std::vector<TransferredMessagePort>& sent_message_ports,
+ const std::vector<int>& new_routing_ids);
+ void OnCrossOriginMessageToWorker(
+ const NavigatorConnectClient& client,
+ const base::string16& message,
+ const std::vector<TransferredMessagePort>& sent_message_ports,
+ const std::vector<int>& new_routing_ids);
+ void OnDidGetClients(
+ int request_id, const std::vector<ServiceWorkerClientInfo>& clients);
+ void OnOpenWindowResponse(int request_id,
+ const ServiceWorkerClientInfo& client);
+ void OnOpenWindowError(int request_id, const std::string& message);
+ void OnFocusClientResponse(int request_id,
+ const ServiceWorkerClientInfo& client);
+ void OnDidSkipWaiting(int request_id);
+ void OnDidClaimClients(int request_id);
+ void OnClaimClientsError(int request_id,
+ blink::WebServiceWorkerError::ErrorType error_type,
+ const base::string16& message);
+ void OnPing();
// Not owned; embedded_context_ owns this.
EmbeddedWorkerContextClient* embedded_context_;
@@ -110,10 +161,21 @@ class ServiceWorkerScriptContext {
// Pending callbacks for GetClientDocuments().
ClientsCallbacksMap pending_clients_callbacks_;
+ // Pending callbacks for OpenWindow() and FocusClient().
+ ClientCallbacksMap pending_client_callbacks_;
+
+ // Pending callbacks for SkipWaiting().
+ SkipWaitingCallbacksMap pending_skip_waiting_callbacks_;
+
+ // Pending callbacks for ClaimClients().
+ ClaimClientsCallbacksMap pending_claim_clients_callbacks_;
+
// Capture timestamps for UMA
std::map<int, base::TimeTicks> activate_start_timings_;
std::map<int, base::TimeTicks> fetch_start_timings_;
std::map<int, base::TimeTicks> install_start_timings_;
+ std::map<int, base::TimeTicks> notification_click_start_timings_;
+ std::map<int, base::TimeTicks> push_start_timings_;
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerScriptContext);
};
diff --git a/chromium/content/renderer/service_worker/service_worker_type_util.cc b/chromium/content/renderer/service_worker/service_worker_type_util.cc
new file mode 100644
index 00000000000..14df3a34c44
--- /dev/null
+++ b/chromium/content/renderer/service_worker/service_worker_type_util.cc
@@ -0,0 +1,62 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/service_worker/service_worker_type_util.h"
+
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/common/service_worker/service_worker_types.h"
+#include "third_party/WebKit/public/platform/WebHTTPHeaderVisitor.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerRequest.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerResponse.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+
+namespace content {
+
+namespace {
+
+class HeaderVisitor : public blink::WebHTTPHeaderVisitor {
+ public:
+ HeaderVisitor(ServiceWorkerHeaderMap* headers) : headers_(headers) {}
+ virtual ~HeaderVisitor() {}
+
+ virtual void visitHeader(const blink::WebString& name,
+ const blink::WebString& value) {
+ const std::string header_name = base::UTF16ToASCII(name);
+ const std::string header_value = base::UTF16ToASCII(value);
+ CHECK(header_name.find('\0') == std::string::npos);
+ CHECK(header_value.find('\0') == std::string::npos);
+ headers_->insert(ServiceWorkerHeaderMap::value_type(
+ header_name, header_value));
+ }
+
+ private:
+ ServiceWorkerHeaderMap* headers_;
+};
+
+scoped_ptr<HeaderVisitor> MakeHeaderVisitor(ServiceWorkerHeaderMap* headers) {
+ return scoped_ptr<HeaderVisitor>(new HeaderVisitor(headers)).Pass();
+}
+
+} // namespace
+
+void GetServiceWorkerHeaderMapFromWebRequest(
+ const blink::WebServiceWorkerRequest& web_request,
+ ServiceWorkerHeaderMap* headers) {
+ DCHECK(headers);
+ DCHECK(!headers->size());
+ web_request.visitHTTPHeaderFields(MakeHeaderVisitor(headers).get());
+}
+
+void GetServiceWorkerHeaderMapFromWebResponse(
+ const blink::WebServiceWorkerResponse& web_response,
+ ServiceWorkerHeaderMap* headers) {
+ DCHECK(headers);
+ DCHECK(!headers->size());
+ web_response.visitHTTPHeaderFields(MakeHeaderVisitor(headers).get());
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/service_worker/service_worker_type_util.h b/chromium/content/renderer/service_worker/service_worker_type_util.h
new file mode 100644
index 00000000000..439231fdebd
--- /dev/null
+++ b/chromium/content/renderer/service_worker/service_worker_type_util.h
@@ -0,0 +1,27 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_TYPE_UTIL_H_
+#define CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_TYPE_UTIL_H_
+
+#include "content/common/service_worker/service_worker_types.h"
+
+namespace blink {
+class WebServiceWorkerRequest;
+class WebServiceWorkerResponse;
+}
+
+namespace content {
+
+void GetServiceWorkerHeaderMapFromWebRequest(
+ const blink::WebServiceWorkerRequest& web_request,
+ ServiceWorkerHeaderMap* headers);
+
+void GetServiceWorkerHeaderMapFromWebResponse(
+ const blink::WebServiceWorkerResponse& web_response,
+ ServiceWorkerHeaderMap* headers);
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_TYPE_UTIL_H_
diff --git a/chromium/content/renderer/shared_memory_seqlock_reader.cc b/chromium/content/renderer/shared_memory_seqlock_reader.cc
index 5cf93478db4..2727aa52f99 100644
--- a/chromium/content/renderer/shared_memory_seqlock_reader.cc
+++ b/chromium/content/renderer/shared_memory_seqlock_reader.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 "shared_memory_seqlock_reader.h"
+#include "content/renderer/shared_memory_seqlock_reader.h"
namespace content {
namespace internal {
diff --git a/chromium/content/renderer/shared_worker/embedded_shared_worker_content_settings_client_proxy.cc b/chromium/content/renderer/shared_worker/embedded_shared_worker_content_settings_client_proxy.cc
new file mode 100644
index 00000000000..11463635f86
--- /dev/null
+++ b/chromium/content/renderer/shared_worker/embedded_shared_worker_content_settings_client_proxy.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/renderer/shared_worker/embedded_shared_worker_content_settings_client_proxy.h"
+
+#include "content/child/thread_safe_sender.h"
+#include "content/common/worker_messages.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "url/gurl.h"
+
+namespace content {
+
+EmbeddedSharedWorkerContentSettingsClientProxy::
+ EmbeddedSharedWorkerContentSettingsClientProxy(
+ const GURL& origin_url,
+ bool is_unique_origin,
+ int routing_id,
+ ThreadSafeSender* thread_safe_sender)
+ : origin_url_(origin_url),
+ is_unique_origin_(is_unique_origin),
+ routing_id_(routing_id),
+ thread_safe_sender_(thread_safe_sender) {
+}
+
+EmbeddedSharedWorkerContentSettingsClientProxy::
+ ~EmbeddedSharedWorkerContentSettingsClientProxy() {
+}
+
+bool EmbeddedSharedWorkerContentSettingsClientProxy::allowDatabase(
+ const blink::WebString& name,
+ const blink::WebString& display_name,
+ unsigned long estimated_size) {
+ if (is_unique_origin_)
+ return false;
+ bool result = false;
+ thread_safe_sender_->Send(new WorkerProcessHostMsg_AllowDatabase(
+ routing_id_, origin_url_, name, display_name, estimated_size, &result));
+ return result;
+}
+
+bool
+EmbeddedSharedWorkerContentSettingsClientProxy::requestFileSystemAccessSync() {
+ if (is_unique_origin_)
+ return false;
+ bool result = false;
+ thread_safe_sender_->Send(
+ new WorkerProcessHostMsg_RequestFileSystemAccessSync(
+ routing_id_, origin_url_, &result));
+ return result;
+}
+
+bool EmbeddedSharedWorkerContentSettingsClientProxy::allowIndexedDB(
+ const blink::WebString& name) {
+ if (is_unique_origin_)
+ return false;
+ bool result = false;
+ thread_safe_sender_->Send(new WorkerProcessHostMsg_AllowIndexedDB(
+ routing_id_, origin_url_, name, &result));
+ return result;
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/shared_worker/embedded_shared_worker_content_settings_client_proxy.h b/chromium/content/renderer/shared_worker/embedded_shared_worker_content_settings_client_proxy.h
new file mode 100644
index 00000000000..ed4bdd97f0d
--- /dev/null
+++ b/chromium/content/renderer/shared_worker/embedded_shared_worker_content_settings_client_proxy.h
@@ -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.
+
+#ifndef CONTENT_RENDERER_SHARED_WORKER_EMBEDDED_SHARED_WORKER_CONTENT_SETTINGS_CLIENT_PROXY_H_
+#define CONTENT_RENDERER_SHARED_WORKER_EMBEDDED_SHARED_WORKER_CONTENT_SETTINGS_CLIENT_PROXY_H_
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "third_party/WebKit/public/web/WebWorkerContentSettingsClientProxy.h"
+#include "url/gurl.h"
+
+namespace content {
+
+class ThreadSafeSender;
+
+// This proxy is created on the main renderer thread then passed onto
+// the blink's worker thread.
+class EmbeddedSharedWorkerContentSettingsClientProxy
+ : public blink::WebWorkerContentSettingsClientProxy {
+ public:
+ EmbeddedSharedWorkerContentSettingsClientProxy(
+ const GURL& origin_url,
+ bool is_unique_origin,
+ int routing_id,
+ ThreadSafeSender* thread_safe_sender);
+ virtual ~EmbeddedSharedWorkerContentSettingsClientProxy();
+
+ // WebWorkerContentSettingsClientProxy overrides.
+ virtual bool allowDatabase(const blink::WebString& name,
+ const blink::WebString& display_name,
+ unsigned long estimated_size);
+ virtual bool requestFileSystemAccessSync();
+ virtual bool allowIndexedDB(const blink::WebString& name);
+
+ private:
+ const GURL origin_url_;
+ const bool is_unique_origin_;
+ const int routing_id_;
+ scoped_refptr<ThreadSafeSender> thread_safe_sender_;
+
+ DISALLOW_COPY_AND_ASSIGN(EmbeddedSharedWorkerContentSettingsClientProxy);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_SHARED_WORKER_EMBEDDED_SHARED_WORKER_CONTENT_SETTINGS_CLIENT_PROXY_H_
diff --git a/chromium/content/renderer/shared_worker/embedded_shared_worker_permission_client_proxy.cc b/chromium/content/renderer/shared_worker/embedded_shared_worker_permission_client_proxy.cc
deleted file mode 100644
index 97cdffa200d..00000000000
--- a/chromium/content/renderer/shared_worker/embedded_shared_worker_permission_client_proxy.cc
+++ /dev/null
@@ -1,62 +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/renderer/shared_worker/embedded_shared_worker_permission_client_proxy.h"
-
-#include "content/child/thread_safe_sender.h"
-#include "content/common/worker_messages.h"
-#include "third_party/WebKit/public/platform/WebString.h"
-#include "url/gurl.h"
-
-namespace content {
-
-EmbeddedSharedWorkerPermissionClientProxy::
- EmbeddedSharedWorkerPermissionClientProxy(
- const GURL& origin_url,
- bool is_unique_origin,
- int routing_id,
- ThreadSafeSender* thread_safe_sender)
- : origin_url_(origin_url),
- is_unique_origin_(is_unique_origin),
- routing_id_(routing_id),
- thread_safe_sender_(thread_safe_sender) {
-}
-
-EmbeddedSharedWorkerPermissionClientProxy::
- ~EmbeddedSharedWorkerPermissionClientProxy() {
-}
-
-bool EmbeddedSharedWorkerPermissionClientProxy::allowDatabase(
- const blink::WebString& name,
- const blink::WebString& display_name,
- unsigned long estimated_size) {
- if (is_unique_origin_)
- return false;
- bool result = false;
- thread_safe_sender_->Send(new WorkerProcessHostMsg_AllowDatabase(
- routing_id_, origin_url_, name, display_name, estimated_size, &result));
- return result;
-}
-
-bool EmbeddedSharedWorkerPermissionClientProxy::requestFileSystemAccessSync() {
- if (is_unique_origin_)
- return false;
- bool result = false;
- thread_safe_sender_->Send(
- new WorkerProcessHostMsg_RequestFileSystemAccessSync(
- routing_id_, origin_url_, &result));
- return result;
-}
-
-bool EmbeddedSharedWorkerPermissionClientProxy::allowIndexedDB(
- const blink::WebString& name) {
- if (is_unique_origin_)
- return false;
- bool result = false;
- thread_safe_sender_->Send(new WorkerProcessHostMsg_AllowIndexedDB(
- routing_id_, origin_url_, name, &result));
- return result;
-}
-
-} // namespace content
diff --git a/chromium/content/renderer/shared_worker/embedded_shared_worker_permission_client_proxy.h b/chromium/content/renderer/shared_worker/embedded_shared_worker_permission_client_proxy.h
deleted file mode 100644
index 2be7b77c1c9..00000000000
--- a/chromium/content/renderer/shared_worker/embedded_shared_worker_permission_client_proxy.h
+++ /dev/null
@@ -1,47 +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_RENDERER_SHARED_WORKER_EMBEDDED_SHARED_WORKER_PERMISSION_CLIENT_PROXY_H_
-#define CONTENT_RENDERER_SHARED_WORKER_EMBEDDED_SHARED_WORKER_PERMISSION_CLIENT_PROXY_H_
-
-#include "base/basictypes.h"
-#include "base/memory/ref_counted.h"
-#include "third_party/WebKit/public/web/WebWorkerPermissionClientProxy.h"
-#include "url/gurl.h"
-
-namespace content {
-
-class ThreadSafeSender;
-
-// This proxy is created on the main renderer thread then passed onto
-// the blink's worker thread.
-class EmbeddedSharedWorkerPermissionClientProxy
- : public blink::WebWorkerPermissionClientProxy {
- public:
- EmbeddedSharedWorkerPermissionClientProxy(
- const GURL& origin_url,
- bool is_unique_origin,
- int routing_id,
- ThreadSafeSender* thread_safe_sender);
- virtual ~EmbeddedSharedWorkerPermissionClientProxy();
-
- // WebWorkerPermissionClientProxy overrides.
- virtual bool allowDatabase(const blink::WebString& name,
- const blink::WebString& display_name,
- unsigned long estimated_size);
- virtual bool requestFileSystemAccessSync();
- virtual bool allowIndexedDB(const blink::WebString& name);
-
- private:
- const GURL origin_url_;
- const bool is_unique_origin_;
- const int routing_id_;
- scoped_refptr<ThreadSafeSender> thread_safe_sender_;
-
- DISALLOW_COPY_AND_ASSIGN(EmbeddedSharedWorkerPermissionClientProxy);
-};
-
-} // namespace content
-
-#endif // CONTENT_RENDERER_SHARED_WORKER_EMBEDDED_SHARED_WORKER_PERMISSION_CLIENT_PROXY_H_
diff --git a/chromium/content/renderer/shared_worker/embedded_shared_worker_stub.cc b/chromium/content/renderer/shared_worker/embedded_shared_worker_stub.cc
index a2b6639c3b0..9d1f82e791c 100644
--- a/chromium/content/renderer/shared_worker/embedded_shared_worker_stub.cc
+++ b/chromium/content/renderer/shared_worker/embedded_shared_worker_stub.cc
@@ -7,14 +7,21 @@
#include "base/message_loop/message_loop_proxy.h"
#include "content/child/appcache/appcache_dispatcher.h"
#include "content/child/appcache/web_application_cache_host_impl.h"
+#include "content/child/request_extra_data.h"
#include "content/child/scoped_child_process_reference.h"
+#include "content/child/service_worker/service_worker_handle_reference.h"
+#include "content/child/service_worker/service_worker_network_provider.h"
+#include "content/child/service_worker/service_worker_provider_context.h"
#include "content/child/shared_worker_devtools_agent.h"
#include "content/child/webmessageportchannel_impl.h"
#include "content/common/worker_messages.h"
#include "content/renderer/render_thread_impl.h"
-#include "content/renderer/shared_worker/embedded_shared_worker_permission_client_proxy.h"
+#include "content/renderer/shared_worker/embedded_shared_worker_content_settings_client_proxy.h"
#include "ipc/ipc_message_macros.h"
+#include "third_party/WebKit/public/platform/WebURLRequest.h"
+#include "third_party/WebKit/public/web/WebDataSource.h"
#include "third_party/WebKit/public/web/WebSecurityOrigin.h"
+#include "third_party/WebKit/public/web/WebServiceWorkerNetworkProvider.h"
#include "third_party/WebKit/public/web/WebSharedWorker.h"
#include "third_party/WebKit/public/web/WebSharedWorkerClient.h"
@@ -52,6 +59,58 @@ class SharedWorkerWebApplicationCacheHostImpl
}
};
+// We store an instance of this class in the "extra data" of the WebDataSource
+// and attach a ServiceWorkerNetworkProvider to it as base::UserData.
+// (see createServiceWorkerNetworkProvider).
+class DataSourceExtraData
+ : public blink::WebDataSource::ExtraData,
+ public base::SupportsUserData {
+ public:
+ DataSourceExtraData() {}
+ virtual ~DataSourceExtraData() {}
+};
+
+// Called on the main thread only and blink owns it.
+class WebServiceWorkerNetworkProviderImpl
+ : public blink::WebServiceWorkerNetworkProvider {
+ public:
+ // Blink calls this method for each request starting with the main script,
+ // we tag them with the provider id.
+ virtual void willSendRequest(
+ blink::WebDataSource* data_source,
+ blink::WebURLRequest& request) {
+ ServiceWorkerNetworkProvider* provider =
+ GetNetworkProviderFromDataSource(data_source);
+ scoped_ptr<RequestExtraData> extra_data(new RequestExtraData);
+ extra_data->set_service_worker_provider_id(provider->provider_id());
+ request.setExtraData(extra_data.release());
+ }
+
+ virtual bool isControlledByServiceWorker(
+ blink::WebDataSource& data_source) {
+ ServiceWorkerNetworkProvider* provider =
+ GetNetworkProviderFromDataSource(&data_source);
+ return provider->context()->controller_handle_id() !=
+ kInvalidServiceWorkerHandleId;
+ }
+
+ virtual int64_t serviceWorkerID(
+ blink::WebDataSource& data_source) {
+ ServiceWorkerNetworkProvider* provider =
+ GetNetworkProviderFromDataSource(&data_source);
+ if (provider->context()->controller())
+ return provider->context()->controller()->version_id();
+ return kInvalidServiceWorkerVersionId;
+ }
+
+ private:
+ ServiceWorkerNetworkProvider* GetNetworkProviderFromDataSource(
+ const blink::WebDataSource* data_source) {
+ return ServiceWorkerNetworkProvider::FromDocumentState(
+ static_cast<DataSourceExtraData*>(data_source->extraData()));
+ }
+};
+
} // namespace
EmbeddedSharedWorkerStub::EmbeddedSharedWorkerStub(
@@ -161,24 +220,41 @@ EmbeddedSharedWorkerStub::createApplicationCacheHost(
return app_cache_host_;
}
-blink::WebWorkerPermissionClientProxy*
- EmbeddedSharedWorkerStub::createWorkerPermissionClientProxy(
+blink::WebWorkerContentSettingsClientProxy*
+ EmbeddedSharedWorkerStub::createWorkerContentSettingsClientProxy(
const blink::WebSecurityOrigin& origin) {
- return new EmbeddedSharedWorkerPermissionClientProxy(
+ return new EmbeddedSharedWorkerContentSettingsClientProxy(
GURL(origin.toString()),
origin.isUnique(),
route_id_,
- ChildThread::current()->thread_safe_sender());
+ ChildThreadImpl::current()->thread_safe_sender());
}
-void EmbeddedSharedWorkerStub::dispatchDevToolsMessage(
- const blink::WebString& message) {
- worker_devtools_agent_->SendDevToolsMessage(message);
+blink::WebServiceWorkerNetworkProvider*
+EmbeddedSharedWorkerStub::createServiceWorkerNetworkProvider(
+ blink::WebDataSource* data_source) {
+ // Create a content::ServiceWorkerNetworkProvider for this data source so
+ // we can observe its requests.
+ scoped_ptr<ServiceWorkerNetworkProvider> provider(
+ new ServiceWorkerNetworkProvider(
+ MSG_ROUTING_NONE, SERVICE_WORKER_PROVIDER_FOR_SHARED_WORKER));
+
+ // The provider is kept around for the lifetime of the DataSource
+ // and ownership is transferred to the DataSource.
+ DataSourceExtraData* extra_data = new DataSourceExtraData();
+ data_source->setExtraData(extra_data);
+ ServiceWorkerNetworkProvider::AttachToDocumentState(
+ extra_data, provider.Pass());
+
+ // Blink is responsible for deleting the returned object.
+ return new WebServiceWorkerNetworkProviderImpl();
}
-void EmbeddedSharedWorkerStub::saveDevToolsAgentState(
- const blink::WebString& state) {
- worker_devtools_agent_->SaveDevToolsAgentState(state);
+void EmbeddedSharedWorkerStub::sendDevToolsMessage(
+ int call_id,
+ const blink::WebString& message,
+ const blink::WebString& state) {
+ worker_devtools_agent_->SendDevToolsMessage(call_id, message, state);
}
void EmbeddedSharedWorkerStub::Shutdown() {
@@ -198,9 +274,11 @@ void EmbeddedSharedWorkerStub::ConnectToChannel(
void EmbeddedSharedWorkerStub::OnConnect(int sent_message_port_id,
int routing_id) {
+ TransferredMessagePort port;
+ port.id = sent_message_port_id;
WebMessagePortChannelImpl* channel =
new WebMessagePortChannelImpl(routing_id,
- sent_message_port_id,
+ port,
base::MessageLoopProxy::current().get());
if (runing_) {
ConnectToChannel(channel);
diff --git a/chromium/content/renderer/shared_worker/embedded_shared_worker_stub.h b/chromium/content/renderer/shared_worker/embedded_shared_worker_stub.h
index c710efa0cc1..8f40d44f90e 100644
--- a/chromium/content/renderer/shared_worker/embedded_shared_worker_stub.h
+++ b/chromium/content/renderer/shared_worker/embedded_shared_worker_stub.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_RENDERER_SHARED_WORKER_EMBEDDED_SHARED_WORKER_STUB_H
-#define CONTENT_RENDERER_SHARED_WORKER_EMBEDDED_SHARED_WORKER_STUB_H
+#ifndef CONTENT_RENDERER_SHARED_WORKER_EMBEDDED_SHARED_WORKER_STUB_H_
+#define CONTENT_RENDERER_SHARED_WORKER_EMBEDDED_SHARED_WORKER_STUB_H_
#include <vector>
@@ -22,7 +22,7 @@ class WebMessagePortChannel;
class WebNotificationPresenter;
class WebSecurityOrigin;
class WebSharedWorker;
-class WebWorkerPermissionClientProxy;
+class WebWorkerContentSettingsClientProxy;
}
namespace content {
@@ -55,12 +55,15 @@ class EmbeddedSharedWorkerStub : public IPC::Listener,
virtual blink::WebNotificationPresenter* notificationPresenter() override;
virtual blink::WebApplicationCacheHost* createApplicationCacheHost(
blink::WebApplicationCacheHostClient*) override;
- virtual blink::WebWorkerPermissionClientProxy*
- createWorkerPermissionClientProxy(
+ virtual blink::WebWorkerContentSettingsClientProxy*
+ createWorkerContentSettingsClientProxy(
const blink::WebSecurityOrigin& origin) override;
- virtual void dispatchDevToolsMessage(
- const blink::WebString& message) override;
- virtual void saveDevToolsAgentState(const blink::WebString& state) override;
+ virtual blink::WebServiceWorkerNetworkProvider*
+ createServiceWorkerNetworkProvider(blink::WebDataSource*) override;
+ virtual void sendDevToolsMessage(
+ int call_id,
+ const blink::WebString& message,
+ const blink::WebString& state) override;
private:
~EmbeddedSharedWorkerStub() override;
@@ -91,4 +94,4 @@ class EmbeddedSharedWorkerStub : public IPC::Listener,
} // namespace content
-#endif // CONTENT_RENDERER_SHARED_WORKER_EMBEDDED_SHARED_WORKER_STUB_H
+#endif // CONTENT_RENDERER_SHARED_WORKER_EMBEDDED_SHARED_WORKER_STUB_H_
diff --git a/chromium/content/renderer/shared_worker_repository.cc b/chromium/content/renderer/shared_worker_repository.cc
index a883464f9b4..46dcb9151f2 100644
--- a/chromium/content/renderer/shared_worker_repository.cc
+++ b/chromium/content/renderer/shared_worker_repository.cc
@@ -4,7 +4,7 @@
#include "content/renderer/shared_worker_repository.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
#include "content/common/view_messages.h"
#include "content/renderer/render_frame_impl.h"
#include "content/renderer/websharedworker_proxy.h"
@@ -39,7 +39,7 @@ SharedWorkerRepository::createSharedWorkerConnector(
if (route_id == MSG_ROUTING_NONE)
return NULL;
documents_with_workers_.insert(document_id);
- return new WebSharedWorkerProxy(ChildThread::current()->GetRouter(),
+ return new WebSharedWorkerProxy(ChildThreadImpl::current()->GetRouter(),
document_id,
route_id,
params.render_frame_route_id);
diff --git a/chromium/content/renderer/skia_benchmarking_extension.cc b/chromium/content/renderer/skia_benchmarking_extension.cc
index 6645fa0265d..51abfd15c73 100644
--- a/chromium/content/renderer/skia_benchmarking_extension.cc
+++ b/chromium/content/renderer/skia_benchmarking_extension.cc
@@ -8,35 +8,33 @@
#include "base/time/time.h"
#include "base/values.h"
#include "cc/base/math_util.h"
-#include "cc/resources/picture.h"
-#include "content/public/renderer/v8_value_converter.h"
+#include "cc/playback/picture.h"
+#include "content/public/child/v8_value_converter.h"
#include "content/renderer/chrome_object_extensions_utils.h"
#include "content/renderer/render_thread_impl.h"
#include "gin/arguments.h"
#include "gin/handle.h"
#include "gin/object_template_builder.h"
#include "skia/ext/benchmarking_canvas.h"
-#include "third_party/WebKit/public/platform/WebArrayBuffer.h"
+#include "third_party/WebKit/public/web/WebArrayBuffer.h"
#include "third_party/WebKit/public/web/WebArrayBufferConverter.h"
#include "third_party/WebKit/public/web/WebFrame.h"
#include "third_party/WebKit/public/web/WebKit.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkColorPriv.h"
#include "third_party/skia/include/core/SkGraphics.h"
+#include "third_party/skia/include/core/SkPicture.h"
#include "third_party/skia/include/core/SkStream.h"
-#include "third_party/skia/src/utils/debugger/SkDebugCanvas.h"
-#include "third_party/skia/src/utils/debugger/SkDrawCommand.h"
-#include "ui/gfx/rect_conversions.h"
+#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/skia_util.h"
#include "v8/include/v8.h"
-
namespace content {
namespace {
scoped_ptr<base::Value> ParsePictureArg(v8::Isolate* isolate,
- v8::Handle<v8::Value> arg) {
+ v8::Local<v8::Value> arg) {
scoped_ptr<content::V8ValueConverter> converter(
content::V8ValueConverter::create());
return scoped_ptr<base::Value>(
@@ -44,7 +42,7 @@ scoped_ptr<base::Value> ParsePictureArg(v8::Isolate* isolate,
}
scoped_refptr<cc::Picture> ParsePictureStr(v8::Isolate* isolate,
- v8::Handle<v8::Value> arg) {
+ v8::Local<v8::Value> arg) {
scoped_ptr<base::Value> picture_value = ParsePictureArg(isolate, arg);
if (!picture_value)
return NULL;
@@ -52,13 +50,26 @@ scoped_refptr<cc::Picture> ParsePictureStr(v8::Isolate* isolate,
}
scoped_refptr<cc::Picture> ParsePictureHash(v8::Isolate* isolate,
- v8::Handle<v8::Value> arg) {
+ v8::Local<v8::Value> arg) {
scoped_ptr<base::Value> picture_value = ParsePictureArg(isolate, arg);
if (!picture_value)
return NULL;
return cc::Picture::CreateFromValue(picture_value.get());
}
+class PicturePlaybackController : public SkPicture::AbortCallback {
+ public:
+ PicturePlaybackController(const skia::BenchmarkingCanvas& canvas,
+ size_t count)
+ : canvas_(canvas), playback_count_(count) {}
+
+ bool abort() override { return canvas_.CommandCount() > playback_count_; }
+
+ private:
+ const skia::BenchmarkingCanvas& canvas_;
+ size_t playback_count_;
+};
+
} // namespace
gin::WrapperInfo SkiaBenchmarking::kWrapperInfo = {gin::kEmbedderNativeGin};
@@ -67,7 +78,7 @@ gin::WrapperInfo SkiaBenchmarking::kWrapperInfo = {gin::kEmbedderNativeGin};
void SkiaBenchmarking::Install(blink::WebFrame* frame) {
v8::Isolate* isolate = blink::mainThreadIsolate();
v8::HandleScope handle_scope(isolate);
- v8::Handle<v8::Context> context = frame->mainWorldScriptContext();
+ v8::Local<v8::Context> context = frame->mainWorldScriptContext();
if (context.IsEmpty())
return;
@@ -78,7 +89,7 @@ void SkiaBenchmarking::Install(blink::WebFrame* frame) {
if (controller.IsEmpty())
return;
- v8::Handle<v8::Object> chrome = GetOrCreateChromeObject(isolate,
+ v8::Local<v8::Object> chrome = GetOrCreateChromeObject(isolate,
context->Global());
chrome->Set(gin::StringToV8(isolate, "skiaBenchmarking"), controller.ToV8());
}
@@ -115,7 +126,7 @@ void SkiaBenchmarking::Rasterize(gin::Arguments* args) {
v8::Isolate* isolate = args->isolate();
if (args->PeekNext().IsEmpty())
return;
- v8::Handle<v8::Value> picture_handle;
+ v8::Local<v8::Value> picture_handle;
args->GetNext(&picture_handle);
scoped_refptr<cc::Picture> picture =
ParsePictureHash(isolate, picture_handle);
@@ -127,9 +138,9 @@ void SkiaBenchmarking::Rasterize(gin::Arguments* args) {
int stop_index = -1;
bool overdraw = false;
- v8::Handle<v8::Context> context = isolate->GetCurrentContext();
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
if (!args->PeekNext().IsEmpty()) {
- v8::Handle<v8::Value> params;
+ v8::Local<v8::Value> params;
args->GetNext(&params);
scoped_ptr<content::V8ValueConverter> converter(
content::V8ValueConverter::create());
@@ -164,19 +175,13 @@ void SkiaBenchmarking::Rasterize(gin::Arguments* args) {
canvas.scale(scale, scale);
canvas.translate(picture->LayerRect().x(), picture->LayerRect().y());
- // First, build a debug canvas for the given picture.
- SkDebugCanvas debug_canvas(picture->LayerRect().width(),
- picture->LayerRect().height());
- picture->Replay(&debug_canvas);
-
- // Raster the requested command subset into the bitmap-backed canvas.
- int last_index = debug_canvas.getSize() - 1;
- if (last_index >= 0) {
- debug_canvas.setOverdrawViz(overdraw);
- debug_canvas.drawTo(
- &canvas,
- stop_index < 0 ? last_index : std::min(last_index, stop_index));
- }
+ skia::BenchmarkingCanvas benchmarking_canvas(
+ &canvas,
+ overdraw ? skia::BenchmarkingCanvas::kOverdrawVisualization_Flag : 0);
+ size_t playback_count =
+ (stop_index < 0) ? std::numeric_limits<size_t>::max() : stop_index;
+ PicturePlaybackController controller(benchmarking_canvas, playback_count);
+ picture->Replay(&benchmarking_canvas, &controller);
blink::WebArrayBuffer buffer =
blink::WebArrayBuffer::create(bitmap.getSize(), 1);
@@ -191,7 +196,7 @@ void SkiaBenchmarking::Rasterize(gin::Arguments* args) {
buffer_pixels[i + 3] = SkGetPackedA32(c);
}
- v8::Handle<v8::Object> result = v8::Object::New(isolate);
+ v8::Local<v8::Object> result = v8::Object::New(isolate);
result->Set(v8::String::NewFromUtf8(isolate, "width"),
v8::Number::New(isolate, snapped_clip.width()));
result->Set(v8::String::NewFromUtf8(isolate, "height"),
@@ -207,50 +212,29 @@ void SkiaBenchmarking::GetOps(gin::Arguments* args) {
v8::Isolate* isolate = args->isolate();
if (args->PeekNext().IsEmpty())
return;
- v8::Handle<v8::Value> picture_handle;
+ v8::Local<v8::Value> picture_handle;
args->GetNext(&picture_handle);
scoped_refptr<cc::Picture> picture =
ParsePictureHash(isolate, picture_handle);
if (!picture.get())
return;
- gfx::Rect bounds = picture->LayerRect();
- SkDebugCanvas canvas(bounds.width(), bounds.height());
- picture->Replay(&canvas);
-
- v8::Handle<v8::Array> result = v8::Array::New(isolate, canvas.getSize());
- for (int i = 0; i < canvas.getSize(); ++i) {
- DrawType cmd_type = canvas.getDrawCommandAt(i)->getType();
- v8::Handle<v8::Object> cmd = v8::Object::New(isolate);
- cmd->Set(v8::String::NewFromUtf8(isolate, "cmd_type"),
- v8::Integer::New(isolate, cmd_type));
- cmd->Set(v8::String::NewFromUtf8(isolate, "cmd_string"),
- v8::String::NewFromUtf8(
- isolate, SkDrawCommand::GetCommandString(cmd_type)));
-
- const SkTDArray<SkString*>* info = canvas.getCommandInfo(i);
- DCHECK(info);
-
- v8::Local<v8::Array> v8_info = v8::Array::New(isolate, info->count());
- for (int j = 0; j < info->count(); ++j) {
- const SkString* info_str = (*info)[j];
- DCHECK(info_str);
- v8_info->Set(j, v8::String::NewFromUtf8(isolate, info_str->c_str()));
- }
-
- cmd->Set(v8::String::NewFromUtf8(isolate, "info"), v8_info);
+ SkCanvas canvas(picture->LayerRect().width(), picture->LayerRect().height());
+ skia::BenchmarkingCanvas benchmarking_canvas(&canvas);
+ picture->Replay(&benchmarking_canvas);
- result->Set(i, cmd);
- }
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ scoped_ptr<content::V8ValueConverter> converter(
+ content::V8ValueConverter::create());
- args->Return(result.As<v8::Object>());
+ args->Return(converter->ToV8Value(&benchmarking_canvas.Commands(), context));
}
void SkiaBenchmarking::GetOpTimings(gin::Arguments* args) {
v8::Isolate* isolate = args->isolate();
if (args->PeekNext().IsEmpty())
return;
- v8::Handle<v8::Value> picture_handle;
+ v8::Local<v8::Value> picture_handle;
args->GetNext(&picture_handle);
scoped_refptr<cc::Picture> picture =
ParsePictureHash(isolate, picture_handle);
@@ -264,20 +248,23 @@ void SkiaBenchmarking::GetOpTimings(gin::Arguments* args) {
bitmap.allocN32Pixels(bounds.width(), bounds.height());
SkCanvas bitmap_canvas(bitmap);
bitmap_canvas.clear(SK_ColorTRANSPARENT);
- base::TimeTicks t0 = base::TimeTicks::HighResNow();
+ base::TimeTicks t0 = base::TimeTicks::Now();
picture->Replay(&bitmap_canvas);
- base::TimeDelta total_time = base::TimeTicks::HighResNow() - t0;
+ base::TimeDelta total_time = base::TimeTicks::Now() - t0;
// Gather per-op timing info by drawing into a BenchmarkingCanvas.
- skia::BenchmarkingCanvas benchmarking_canvas(bounds.width(), bounds.height());
+ SkCanvas canvas(bitmap);
+ canvas.clear(SK_ColorTRANSPARENT);
+ skia::BenchmarkingCanvas benchmarking_canvas(&canvas);
picture->Replay(&benchmarking_canvas);
v8::Local<v8::Array> op_times =
v8::Array::New(isolate, benchmarking_canvas.CommandCount());
- for (size_t i = 0; i < benchmarking_canvas.CommandCount(); ++i)
+ for (size_t i = 0; i < benchmarking_canvas.CommandCount(); ++i) {
op_times->Set(i, v8::Number::New(isolate, benchmarking_canvas.GetTime(i)));
+ }
- v8::Handle<v8::Object> result = v8::Object::New(isolate);
+ v8::Local<v8::Object> result = v8::Object::New(isolate);
result->Set(v8::String::NewFromUtf8(isolate, "total_time"),
v8::Number::New(isolate, total_time.InMillisecondsF()));
result->Set(v8::String::NewFromUtf8(isolate, "cmd_times"), op_times);
@@ -289,14 +276,14 @@ void SkiaBenchmarking::GetInfo(gin::Arguments* args) {
v8::Isolate* isolate = args->isolate();
if (args->PeekNext().IsEmpty())
return;
- v8::Handle<v8::Value> picture_handle;
+ v8::Local<v8::Value> picture_handle;
args->GetNext(&picture_handle);
scoped_refptr<cc::Picture> picture =
ParsePictureStr(isolate, picture_handle);
if (!picture.get())
return;
- v8::Handle<v8::Object> result = v8::Object::New(isolate);
+ v8::Local<v8::Object> result = v8::Object::New(isolate);
result->Set(v8::String::NewFromUtf8(isolate, "width"),
v8::Number::New(isolate, picture->LayerRect().width()));
result->Set(v8::String::NewFromUtf8(isolate, "height"),
diff --git a/chromium/content/renderer/skia_benchmarking_extension.h b/chromium/content/renderer/skia_benchmarking_extension.h
index 2e0faf16d83..103a490fbb7 100644
--- a/chromium/content/renderer/skia_benchmarking_extension.h
+++ b/chromium/content/renderer/skia_benchmarking_extension.h
@@ -75,4 +75,4 @@ class SkiaBenchmarking : public gin::Wrappable<SkiaBenchmarking> {
} // namespace content
-#endif // CONTENT_RENDERER_SKIA_BENCHMARKING_EXTENSION_H_
+#endif // CONTENT_RENDERER_SKIA_BENCHMARKING_EXTENSION_H_
diff --git a/chromium/content/renderer/skia_benchmarking_extension_unittest.cc b/chromium/content/renderer/skia_benchmarking_extension_unittest.cc
index 1c1bf9a9c0c..0e97ae701df 100644
--- a/chromium/content/renderer/skia_benchmarking_extension_unittest.cc
+++ b/chromium/content/renderer/skia_benchmarking_extension_unittest.cc
@@ -4,101 +4,102 @@
#include "content/renderer/skia_benchmarking_extension.h"
+#include "base/values.h"
+#include "skia/ext/benchmarking_canvas.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkGraphics.h"
-#include "third_party/skia/src/utils/debugger/SkDebugCanvas.h"
-#include "third_party/skia/src/utils/debugger/SkDrawCommand.h"
namespace {
-testing::AssertionResult HasInfoField(SkDebugCanvas& canvas, int index,
- const char* field) {
+testing::AssertionResult HasArg(const base::ListValue* args,
+ const char name[]) {
+ const base::DictionaryValue* arg;
- const SkTDArray<SkString*>* info = canvas.getCommandInfo(index);
- if (info == NULL)
- return testing::AssertionFailure() << " command info not found for index "
- << index;
+ for (size_t i = 0; i < args->GetSize(); ++i) {
+ if (!args->GetDictionary(i, &arg) || arg->size() != 1)
+ return testing::AssertionFailure() << " malformed argument for index "
+ << i;
- for (int i = 0; i < info->count(); ++i) {
- const SkString* info_str = (*info)[i];
- if (info_str == NULL)
- return testing::AssertionFailure() << " NULL info string for index "
- << index;
-
- // FIXME: loose info paramter test.
- if (strstr(info_str->c_str(), field) != NULL)
- return testing::AssertionSuccess() << field << " found";
+ if (arg->HasKey(name))
+ return testing::AssertionSuccess() << " argument '" << name
+ << "' found at index " << i;
}
- return testing::AssertionFailure() << field << " not found";
+ return testing::AssertionFailure() << "argument not found: '" << name << "'";
}
}
namespace content {
-TEST(SkiaBenchmarkingExtensionTest, SkDebugCanvas) {
+TEST(SkiaBenchmarkingExtensionTest, BenchmarkingCanvas) {
SkGraphics::Init();
// Prepare canvas and resources.
- SkDebugCanvas canvas(100, 100);
+ SkCanvas canvas(100, 100);
+ skia::BenchmarkingCanvas benchmarking_canvas(&canvas);
+
SkPaint red_paint;
red_paint.setColor(SkColorSetARGB(255, 255, 0, 0));
SkRect fullRect = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100));
SkRect fillRect = SkRect::MakeXYWH(SkIntToScalar(25), SkIntToScalar(25),
SkIntToScalar(50), SkIntToScalar(50));
+ SkMatrix trans;
+ trans.setTranslate(SkIntToScalar(10), SkIntToScalar(10));
+
// Draw a trivial scene.
- canvas.save();
- canvas.clipRect(fullRect, SkRegion::kIntersect_Op, false);
- canvas.translate(SkIntToScalar(10), SkIntToScalar(10));
- canvas.scale(SkIntToScalar(2), SkIntToScalar(2));
- canvas.drawRect(fillRect, red_paint);
- canvas.restore();
+ benchmarking_canvas.save();
+ benchmarking_canvas.clipRect(fullRect, SkRegion::kIntersect_Op, false);
+ benchmarking_canvas.setMatrix(trans);
+ benchmarking_canvas.drawRect(fillRect, red_paint);
+ benchmarking_canvas.restore();
// Verify the recorded commands.
- DrawType cmd;
- int idx = 0;
- ASSERT_EQ(canvas.getSize(), 6);
-
- ASSERT_TRUE(canvas.getDrawCommandAt(idx) != NULL);
- cmd = canvas.getDrawCommandAt(idx)->getType();
- EXPECT_EQ(cmd, SAVE);
- EXPECT_STREQ(SkDrawCommand::GetCommandString(cmd), "Save");
-
- ASSERT_TRUE(canvas.getDrawCommandAt(++idx) != NULL);
- cmd = canvas.getDrawCommandAt(idx)->getType();
- EXPECT_EQ(cmd, CLIP_RECT);
- EXPECT_STREQ(SkDrawCommand::GetCommandString(cmd), "Clip Rect");
- EXPECT_TRUE(HasInfoField(canvas, idx, "SkRect"));
- EXPECT_TRUE(HasInfoField(canvas, idx, "Op"));
- EXPECT_TRUE(HasInfoField(canvas, idx, "doAA"));
-
- ASSERT_TRUE(canvas.getDrawCommandAt(++idx) != NULL);
- cmd = canvas.getDrawCommandAt(idx)->getType();
- EXPECT_EQ(cmd, TRANSLATE);
- EXPECT_STREQ(SkDrawCommand::GetCommandString(cmd), "Translate");
- EXPECT_TRUE(HasInfoField(canvas, idx, "dx"));
- EXPECT_TRUE(HasInfoField(canvas, idx, "dy"));
-
- ASSERT_TRUE(canvas.getDrawCommandAt(++idx) != NULL);
- cmd = canvas.getDrawCommandAt(idx)->getType();
- EXPECT_EQ(cmd, SCALE);
- EXPECT_STREQ(SkDrawCommand::GetCommandString(cmd), "Scale");
- EXPECT_TRUE(HasInfoField(canvas, idx, "sx"));
- EXPECT_TRUE(HasInfoField(canvas, idx, "sy"));
-
- ASSERT_TRUE(canvas.getDrawCommandAt(++idx) != NULL);
- cmd = canvas.getDrawCommandAt(idx)->getType();
- EXPECT_EQ(cmd, DRAW_RECT);
- EXPECT_STREQ(SkDrawCommand::GetCommandString(cmd), "Draw Rect");
- EXPECT_TRUE(HasInfoField(canvas, idx, "SkRect"));
-
- ASSERT_TRUE(canvas.getDrawCommandAt(++idx) != NULL);
- cmd = canvas.getDrawCommandAt(idx)->getType();
- EXPECT_EQ(cmd, RESTORE);
- EXPECT_STREQ(SkDrawCommand::GetCommandString(cmd), "Restore");
+ const base::ListValue& ops = benchmarking_canvas.Commands();
+ ASSERT_EQ(ops.GetSize(), static_cast<size_t>(5));
+
+ size_t index = 0;
+ const base::DictionaryValue* op;
+ const base::ListValue* op_args;
+ std::string op_name;
+
+ ASSERT_TRUE(ops.GetDictionary(index++, &op));
+ EXPECT_TRUE(op->GetString("cmd_string", &op_name));
+ EXPECT_EQ(op_name, "Save");
+ ASSERT_TRUE(op->GetList("info", &op_args));
+ EXPECT_EQ(op_args->GetSize(), static_cast<size_t>(0));
+
+ ASSERT_TRUE(ops.GetDictionary(index++, &op));
+ EXPECT_TRUE(op->GetString("cmd_string", &op_name));
+ EXPECT_EQ(op_name, "ClipRect");
+ ASSERT_TRUE(op->GetList("info", &op_args));
+ EXPECT_EQ(op_args->GetSize(), static_cast<size_t>(3));
+ EXPECT_TRUE(HasArg(op_args, "rect"));
+ EXPECT_TRUE(HasArg(op_args, "op"));
+ EXPECT_TRUE(HasArg(op_args, "anti-alias"));
+
+ ASSERT_TRUE(ops.GetDictionary(index++, &op));
+ EXPECT_TRUE(op->GetString("cmd_string", &op_name));
+ EXPECT_EQ(op_name, "SetMatrix");
+ ASSERT_TRUE(op->GetList("info", &op_args));
+ EXPECT_EQ(op_args->GetSize(), static_cast<size_t>(1));
+ EXPECT_TRUE(HasArg(op_args, "matrix"));
+
+ ASSERT_TRUE(ops.GetDictionary(index++, &op));
+ EXPECT_TRUE(op->GetString("cmd_string", &op_name));
+ EXPECT_EQ(op_name, "DrawRect");
+ ASSERT_TRUE(op->GetList("info", &op_args));
+ EXPECT_EQ(op_args->GetSize(), static_cast<size_t>(2));
+ EXPECT_TRUE(HasArg(op_args, "rect"));
+ EXPECT_TRUE(HasArg(op_args, "paint"));
+
+ ASSERT_TRUE(ops.GetDictionary(index++, &op));
+ EXPECT_TRUE(op->GetString("cmd_string", &op_name));
+ EXPECT_EQ(op_name, "Restore");
+ ASSERT_TRUE(op->GetList("info", &op_args));
+ EXPECT_EQ(op_args->GetSize(), static_cast<size_t>(0));
}
} // namespace content
diff --git a/chromium/content/renderer/speech_recognition_dispatcher.cc b/chromium/content/renderer/speech_recognition_dispatcher.cc
index dea16bc5cfe..cb787359f73 100644
--- a/chromium/content/renderer/speech_recognition_dispatcher.cc
+++ b/chromium/content/renderer/speech_recognition_dispatcher.cc
@@ -164,21 +164,25 @@ static WebSpeechRecognizerClient::ErrorCode WebKitErrorCode(
case SPEECH_RECOGNITION_ERROR_NONE:
NOTREACHED();
return WebSpeechRecognizerClient::OtherError;
+ case SPEECH_RECOGNITION_ERROR_NO_SPEECH:
+ return WebSpeechRecognizerClient::NoSpeechError;
case SPEECH_RECOGNITION_ERROR_ABORTED:
return WebSpeechRecognizerClient::AbortedError;
- case SPEECH_RECOGNITION_ERROR_AUDIO:
+ case SPEECH_RECOGNITION_ERROR_AUDIO_CAPTURE:
return WebSpeechRecognizerClient::AudioCaptureError;
case SPEECH_RECOGNITION_ERROR_NETWORK:
return WebSpeechRecognizerClient::NetworkError;
case SPEECH_RECOGNITION_ERROR_NOT_ALLOWED:
return WebSpeechRecognizerClient::NotAllowedError;
- case SPEECH_RECOGNITION_ERROR_NO_SPEECH:
- return WebSpeechRecognizerClient::NoSpeechError;
+ case SPEECH_RECOGNITION_ERROR_SERVICE_NOT_ALLOWED:
+ return WebSpeechRecognizerClient::ServiceNotAllowedError;
+ case SPEECH_RECOGNITION_ERROR_BAD_GRAMMAR:
+ return WebSpeechRecognizerClient::BadGrammarError;
+ case SPEECH_RECOGNITION_ERROR_LANGUAGE_NOT_SUPPORTED:
+ return WebSpeechRecognizerClient::LanguageNotSupportedError;
case SPEECH_RECOGNITION_ERROR_NO_MATCH:
NOTREACHED();
return WebSpeechRecognizerClient::OtherError;
- case SPEECH_RECOGNITION_ERROR_BAD_GRAMMAR:
- return WebSpeechRecognizerClient::BadGrammarError;
}
NOTREACHED();
return WebSpeechRecognizerClient::OtherError;
diff --git a/chromium/content/renderer/stats_collection_controller.cc b/chromium/content/renderer/stats_collection_controller.cc
index da615e0dde6..6f42a02721c 100644
--- a/chromium/content/renderer/stats_collection_controller.cc
+++ b/chromium/content/renderer/stats_collection_controller.cc
@@ -80,7 +80,7 @@ gin::WrapperInfo StatsCollectionController::kWrapperInfo = {
void StatsCollectionController::Install(blink::WebFrame* frame) {
v8::Isolate* isolate = blink::mainThreadIsolate();
v8::HandleScope handle_scope(isolate);
- v8::Handle<v8::Context> context = frame->mainWorldScriptContext();
+ v8::Local<v8::Context> context = frame->mainWorldScriptContext();
if (context.IsEmpty())
return;
@@ -90,7 +90,7 @@ void StatsCollectionController::Install(blink::WebFrame* frame) {
gin::CreateHandle(isolate, new StatsCollectionController());
if (controller.IsEmpty())
return;
- v8::Handle<v8::Object> global = context->Global();
+ v8::Local<v8::Object> global = context->Global();
global->Set(gin::StringToV8(isolate, "statsCollectionController"),
controller.ToV8());
}
diff --git a/chromium/content/renderer/text_input_client_observer.cc b/chromium/content/renderer/text_input_client_observer.cc
index 8a516877f6d..049f87c5e02 100644
--- a/chromium/content/renderer/text_input_client_observer.cc
+++ b/chromium/content/renderer/text_input_client_observer.cc
@@ -14,7 +14,7 @@
#include "third_party/WebKit/public/web/WebLocalFrame.h"
#include "third_party/WebKit/public/web/WebView.h"
#include "third_party/WebKit/public/web/mac/WebSubstringUtil.h"
-#include "ui/gfx/rect.h"
+#include "ui/gfx/geometry/rect.h"
namespace content {
diff --git a/chromium/content/renderer/text_input_client_observer.h b/chromium/content/renderer/text_input_client_observer.h
index c8d1b4a2e13..f7e872300ab 100644
--- a/chromium/content/renderer/text_input_client_observer.h
+++ b/chromium/content/renderer/text_input_client_observer.h
@@ -8,7 +8,7 @@
#include "base/basictypes.h"
#include "build/build_config.h"
#include "content/public/renderer/render_view_observer.h"
-#include "ui/gfx/point.h"
+#include "ui/gfx/geometry/point.h"
#include "ui/gfx/range/range.h"
namespace blink {
diff --git a/chromium/content/renderer/v8_value_converter_impl.cc b/chromium/content/renderer/v8_value_converter_impl.cc
deleted file mode 100644
index 2c222bd772a..00000000000
--- a/chromium/content/renderer/v8_value_converter_impl.cc
+++ /dev/null
@@ -1,557 +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/renderer/v8_value_converter_impl.h"
-
-#include <string>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/float_util.h"
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/values.h"
-#include "third_party/WebKit/public/platform/WebArrayBuffer.h"
-#include "third_party/WebKit/public/web/WebArrayBufferConverter.h"
-#include "third_party/WebKit/public/web/WebArrayBufferView.h"
-#include "v8/include/v8.h"
-
-namespace content {
-
-// Default implementation of V8ValueConverter::Strategy
-
-bool V8ValueConverter::Strategy::FromV8Object(
- v8::Handle<v8::Object> value,
- base::Value** out,
- v8::Isolate* isolate,
- const FromV8ValueCallback& callback) const {
- return false;
-}
-
-bool V8ValueConverter::Strategy::FromV8Array(
- v8::Handle<v8::Array> value,
- base::Value** out,
- v8::Isolate* isolate,
- const FromV8ValueCallback& callback) const {
- return false;
-}
-
-bool V8ValueConverter::Strategy::FromV8ArrayBuffer(v8::Handle<v8::Object> value,
- base::Value** out,
- v8::Isolate* isolate) const {
- return false;
-}
-
-bool V8ValueConverter::Strategy::FromV8Number(v8::Handle<v8::Number> value,
- base::Value** out) const {
- return false;
-}
-
-bool V8ValueConverter::Strategy::FromV8Undefined(base::Value** out) const {
- return false;
-}
-
-
-namespace {
-
-// For the sake of the storage API, make this quite large.
-const int kMaxRecursionDepth = 100;
-
-} // namespace
-
-// The state of a call to FromV8Value.
-class V8ValueConverterImpl::FromV8ValueState {
- public:
- // Level scope which updates the current depth of some FromV8ValueState.
- class Level {
- public:
- explicit Level(FromV8ValueState* state) : state_(state) {
- state_->max_recursion_depth_--;
- }
- ~Level() {
- state_->max_recursion_depth_++;
- }
-
- private:
- FromV8ValueState* state_;
- };
-
- explicit FromV8ValueState(bool avoid_identity_hash_for_testing)
- : max_recursion_depth_(kMaxRecursionDepth),
- avoid_identity_hash_for_testing_(avoid_identity_hash_for_testing) {}
-
- // If |handle| is not in |unique_map_|, then add it to |unique_map_| and
- // return true.
- //
- // Otherwise do nothing and return false. Here "A is unique" means that no
- // other handle B in the map points to the same object as A. Note that A can
- // be unique even if there already is another handle with the same identity
- // hash (key) in the map, because two objects can have the same hash.
- bool UpdateAndCheckUniqueness(v8::Handle<v8::Object> handle) {
- typedef HashToHandleMap::const_iterator Iterator;
- int hash = avoid_identity_hash_for_testing_ ? 0 : handle->GetIdentityHash();
- // We only compare using == with handles to objects with the same identity
- // hash. Different hash obviously means different objects, but two objects
- // in a couple of thousands could have the same identity hash.
- std::pair<Iterator, Iterator> range = unique_map_.equal_range(hash);
- for (Iterator it = range.first; it != range.second; ++it) {
- // Operator == for handles actually compares the underlying objects.
- if (it->second == handle)
- return false;
- }
- unique_map_.insert(std::make_pair(hash, handle));
- return true;
- }
-
- bool HasReachedMaxRecursionDepth() {
- return max_recursion_depth_ < 0;
- }
-
- private:
- typedef std::multimap<int, v8::Handle<v8::Object> > HashToHandleMap;
- HashToHandleMap unique_map_;
-
- int max_recursion_depth_;
-
- bool avoid_identity_hash_for_testing_;
-};
-
-V8ValueConverter* V8ValueConverter::create() {
- return new V8ValueConverterImpl();
-}
-
-V8ValueConverterImpl::V8ValueConverterImpl()
- : date_allowed_(false),
- reg_exp_allowed_(false),
- function_allowed_(false),
- strip_null_from_objects_(false),
- avoid_identity_hash_for_testing_(false),
- strategy_(NULL) {}
-
-void V8ValueConverterImpl::SetDateAllowed(bool val) {
- date_allowed_ = val;
-}
-
-void V8ValueConverterImpl::SetRegExpAllowed(bool val) {
- reg_exp_allowed_ = val;
-}
-
-void V8ValueConverterImpl::SetFunctionAllowed(bool val) {
- function_allowed_ = val;
-}
-
-void V8ValueConverterImpl::SetStripNullFromObjects(bool val) {
- strip_null_from_objects_ = val;
-}
-
-void V8ValueConverterImpl::SetStrategy(Strategy* strategy) {
- strategy_ = strategy;
-}
-
-v8::Handle<v8::Value> V8ValueConverterImpl::ToV8Value(
- const base::Value* value, v8::Handle<v8::Context> context) const {
- v8::Context::Scope context_scope(context);
- v8::EscapableHandleScope handle_scope(context->GetIsolate());
- return handle_scope.Escape(
- ToV8ValueImpl(context->GetIsolate(), context->Global(), value));
-}
-
-base::Value* V8ValueConverterImpl::FromV8Value(
- v8::Handle<v8::Value> val,
- v8::Handle<v8::Context> context) const {
- v8::Context::Scope context_scope(context);
- v8::HandleScope handle_scope(context->GetIsolate());
- FromV8ValueState state(avoid_identity_hash_for_testing_);
- return FromV8ValueImpl(&state, val, context->GetIsolate());
-}
-
-v8::Local<v8::Value> V8ValueConverterImpl::ToV8ValueImpl(
- v8::Isolate* isolate,
- v8::Handle<v8::Object> creation_context,
- const base::Value* value) const {
- CHECK(value);
- switch (value->GetType()) {
- case base::Value::TYPE_NULL:
- return v8::Null(isolate);
-
- case base::Value::TYPE_BOOLEAN: {
- bool val = false;
- CHECK(value->GetAsBoolean(&val));
- return v8::Boolean::New(isolate, val);
- }
-
- case base::Value::TYPE_INTEGER: {
- int val = 0;
- CHECK(value->GetAsInteger(&val));
- return v8::Integer::New(isolate, val);
- }
-
- case base::Value::TYPE_DOUBLE: {
- double val = 0.0;
- CHECK(value->GetAsDouble(&val));
- return v8::Number::New(isolate, val);
- }
-
- case base::Value::TYPE_STRING: {
- std::string val;
- CHECK(value->GetAsString(&val));
- return v8::String::NewFromUtf8(
- isolate, val.c_str(), v8::String::kNormalString, val.length());
- }
-
- case base::Value::TYPE_LIST:
- return ToV8Array(isolate,
- creation_context,
- static_cast<const base::ListValue*>(value));
-
- case base::Value::TYPE_DICTIONARY:
- return ToV8Object(isolate,
- creation_context,
- static_cast<const base::DictionaryValue*>(value));
-
- case base::Value::TYPE_BINARY:
- return ToArrayBuffer(isolate,
- creation_context,
- static_cast<const base::BinaryValue*>(value));
-
- default:
- LOG(ERROR) << "Unexpected value type: " << value->GetType();
- return v8::Null(isolate);
- }
-}
-
-v8::Handle<v8::Value> V8ValueConverterImpl::ToV8Array(
- v8::Isolate* isolate,
- v8::Handle<v8::Object> creation_context,
- const base::ListValue* val) const {
- v8::Handle<v8::Array> result(v8::Array::New(isolate, val->GetSize()));
-
- for (size_t i = 0; i < val->GetSize(); ++i) {
- const base::Value* child = NULL;
- CHECK(val->Get(i, &child));
-
- v8::Handle<v8::Value> child_v8 =
- ToV8ValueImpl(isolate, creation_context, child);
- CHECK(!child_v8.IsEmpty());
-
- v8::TryCatch try_catch;
- result->Set(static_cast<uint32>(i), child_v8);
- if (try_catch.HasCaught())
- LOG(ERROR) << "Setter for index " << i << " threw an exception.";
- }
-
- return result;
-}
-
-v8::Handle<v8::Value> V8ValueConverterImpl::ToV8Object(
- v8::Isolate* isolate,
- v8::Handle<v8::Object> creation_context,
- const base::DictionaryValue* val) const {
- v8::Handle<v8::Object> result(v8::Object::New(isolate));
-
- for (base::DictionaryValue::Iterator iter(*val);
- !iter.IsAtEnd(); iter.Advance()) {
- const std::string& key = iter.key();
- v8::Handle<v8::Value> child_v8 =
- ToV8ValueImpl(isolate, creation_context, &iter.value());
- CHECK(!child_v8.IsEmpty());
-
- v8::TryCatch try_catch;
- result->Set(
- v8::String::NewFromUtf8(
- isolate, key.c_str(), v8::String::kNormalString, key.length()),
- child_v8);
- if (try_catch.HasCaught()) {
- LOG(ERROR) << "Setter for property " << key.c_str() << " threw an "
- << "exception.";
- }
- }
-
- return result;
-}
-
-v8::Handle<v8::Value> V8ValueConverterImpl::ToArrayBuffer(
- v8::Isolate* isolate,
- v8::Handle<v8::Object> creation_context,
- const base::BinaryValue* value) const {
- blink::WebArrayBuffer buffer =
- blink::WebArrayBuffer::create(value->GetSize(), 1);
- memcpy(buffer.data(), value->GetBuffer(), value->GetSize());
- return blink::WebArrayBufferConverter::toV8Value(
- &buffer, creation_context, isolate);
-}
-
-base::Value* V8ValueConverterImpl::FromV8ValueImpl(
- FromV8ValueState* state,
- v8::Handle<v8::Value> val,
- v8::Isolate* isolate) const {
- CHECK(!val.IsEmpty());
-
- FromV8ValueState::Level state_level(state);
- if (state->HasReachedMaxRecursionDepth())
- return NULL;
-
- if (val->IsNull())
- return base::Value::CreateNullValue();
-
- if (val->IsBoolean())
- return new base::FundamentalValue(val->ToBoolean()->Value());
-
- if (val->IsNumber() && strategy_) {
- base::Value* out = NULL;
- if (strategy_->FromV8Number(val->ToNumber(), &out))
- return out;
- }
-
- if (val->IsInt32())
- return new base::FundamentalValue(val->ToInt32()->Value());
-
- if (val->IsNumber()) {
- double val_as_double = val->ToNumber()->Value();
- if (!base::IsFinite(val_as_double))
- return NULL;
- return new base::FundamentalValue(val_as_double);
- }
-
- if (val->IsString()) {
- v8::String::Utf8Value utf8(val->ToString());
- return new base::StringValue(std::string(*utf8, utf8.length()));
- }
-
- if (val->IsUndefined()) {
- if (strategy_) {
- base::Value* out = NULL;
- if (strategy_->FromV8Undefined(&out))
- return out;
- }
- // JSON.stringify ignores undefined.
- return NULL;
- }
-
- if (val->IsDate()) {
- if (!date_allowed_)
- // JSON.stringify would convert this to a string, but an object is more
- // consistent within this class.
- return FromV8Object(val->ToObject(), state, isolate);
- v8::Date* date = v8::Date::Cast(*val);
- return new base::FundamentalValue(date->ValueOf() / 1000.0);
- }
-
- if (val->IsRegExp()) {
- if (!reg_exp_allowed_)
- // JSON.stringify converts to an object.
- return FromV8Object(val->ToObject(), state, isolate);
- return new base::StringValue(*v8::String::Utf8Value(val->ToString()));
- }
-
- // v8::Value doesn't have a ToArray() method for some reason.
- if (val->IsArray())
- return FromV8Array(val.As<v8::Array>(), state, isolate);
-
- if (val->IsFunction()) {
- if (!function_allowed_)
- // JSON.stringify refuses to convert function(){}.
- return NULL;
- return FromV8Object(val->ToObject(), state, isolate);
- }
-
- if (val->IsArrayBuffer() || val->IsArrayBufferView())
- return FromV8ArrayBuffer(val->ToObject(), isolate);
-
- if (val->IsObject())
- return FromV8Object(val->ToObject(), state, isolate);
-
- LOG(ERROR) << "Unexpected v8 value type encountered.";
- return NULL;
-}
-
-base::Value* V8ValueConverterImpl::FromV8Array(
- v8::Handle<v8::Array> val,
- FromV8ValueState* state,
- v8::Isolate* isolate) const {
- if (!state->UpdateAndCheckUniqueness(val))
- return base::Value::CreateNullValue();
-
- scoped_ptr<v8::Context::Scope> scope;
- // If val was created in a different context than our current one, change to
- // that context, but change back after val is converted.
- if (!val->CreationContext().IsEmpty() &&
- val->CreationContext() != isolate->GetCurrentContext())
- scope.reset(new v8::Context::Scope(val->CreationContext()));
-
- if (strategy_) {
- // These base::Unretained's are safe, because Strategy::FromV8Value should
- // be synchronous, so this object can't be out of scope.
- V8ValueConverter::Strategy::FromV8ValueCallback callback =
- base::Bind(&V8ValueConverterImpl::FromV8ValueImpl,
- base::Unretained(this),
- base::Unretained(state));
- base::Value* out = NULL;
- if (strategy_->FromV8Array(val, &out, isolate, callback))
- return out;
- }
-
- base::ListValue* result = new base::ListValue();
-
- // Only fields with integer keys are carried over to the ListValue.
- for (uint32 i = 0; i < val->Length(); ++i) {
- v8::TryCatch try_catch;
- v8::Handle<v8::Value> child_v8 = val->Get(i);
- if (try_catch.HasCaught()) {
- LOG(ERROR) << "Getter for index " << i << " threw an exception.";
- child_v8 = v8::Null(isolate);
- }
-
- if (!val->HasRealIndexedProperty(i)) {
- result->Append(base::Value::CreateNullValue());
- continue;
- }
-
- base::Value* child = FromV8ValueImpl(state, child_v8, isolate);
- if (child)
- result->Append(child);
- else
- // JSON.stringify puts null in places where values don't serialize, for
- // example undefined and functions. Emulate that behavior.
- result->Append(base::Value::CreateNullValue());
- }
- return result;
-}
-
-base::Value* V8ValueConverterImpl::FromV8ArrayBuffer(
- v8::Handle<v8::Object> val,
- v8::Isolate* isolate) const {
- if (strategy_) {
- base::Value* out = NULL;
- if (strategy_->FromV8ArrayBuffer(val, &out, isolate))
- return out;
- }
-
- char* data = NULL;
- size_t length = 0;
-
- scoped_ptr<blink::WebArrayBuffer> array_buffer(
- blink::WebArrayBufferConverter::createFromV8Value(val, isolate));
- scoped_ptr<blink::WebArrayBufferView> view;
- if (array_buffer) {
- data = reinterpret_cast<char*>(array_buffer->data());
- length = array_buffer->byteLength();
- } else {
- view.reset(blink::WebArrayBufferView::createFromV8Value(val));
- if (view) {
- data = reinterpret_cast<char*>(view->baseAddress()) + view->byteOffset();
- length = view->byteLength();
- }
- }
-
- if (data)
- return base::BinaryValue::CreateWithCopiedBuffer(data, length);
- else
- return NULL;
-}
-
-base::Value* V8ValueConverterImpl::FromV8Object(
- v8::Handle<v8::Object> val,
- FromV8ValueState* state,
- v8::Isolate* isolate) const {
- if (!state->UpdateAndCheckUniqueness(val))
- return base::Value::CreateNullValue();
-
- scoped_ptr<v8::Context::Scope> scope;
- // If val was created in a different context than our current one, change to
- // that context, but change back after val is converted.
- if (!val->CreationContext().IsEmpty() &&
- val->CreationContext() != isolate->GetCurrentContext())
- scope.reset(new v8::Context::Scope(val->CreationContext()));
-
- if (strategy_) {
- // These base::Unretained's are safe, because Strategy::FromV8Value should
- // be synchronous, so this object can't be out of scope.
- V8ValueConverter::Strategy::FromV8ValueCallback callback =
- base::Bind(&V8ValueConverterImpl::FromV8ValueImpl,
- base::Unretained(this),
- base::Unretained(state));
- base::Value* out = NULL;
- if (strategy_->FromV8Object(val, &out, isolate, callback))
- return out;
- }
-
- // Don't consider DOM objects. This check matches isHostObject() in Blink's
- // bindings/v8/V8Binding.h used in structured cloning. It reads:
- //
- // If the object has any internal fields, then we won't be able to serialize
- // or deserialize them; conveniently, this is also a quick way to detect DOM
- // wrapper objects, because the mechanism for these relies on data stored in
- // these fields.
- //
- // NOTE: check this after |strategy_| so that callers have a chance to
- // do something else, such as convert to the node's name rather than NULL.
- //
- // ANOTHER NOTE: returning an empty dictionary here to minimise surprise.
- // See also http://crbug.com/330559.
- if (val->InternalFieldCount())
- return new base::DictionaryValue();
-
- scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue());
- v8::Handle<v8::Array> property_names(val->GetOwnPropertyNames());
-
- for (uint32 i = 0; i < property_names->Length(); ++i) {
- v8::Handle<v8::Value> key(property_names->Get(i));
-
- // Extend this test to cover more types as necessary and if sensible.
- if (!key->IsString() &&
- !key->IsNumber()) {
- NOTREACHED() << "Key \"" << *v8::String::Utf8Value(key) << "\" "
- "is neither a string nor a number";
- continue;
- }
-
- v8::String::Utf8Value name_utf8(key->ToString());
-
- v8::TryCatch try_catch;
- v8::Handle<v8::Value> child_v8 = val->Get(key);
-
- if (try_catch.HasCaught()) {
- LOG(WARNING) << "Getter for property " << *name_utf8
- << " threw an exception.";
- child_v8 = v8::Null(isolate);
- }
-
- scoped_ptr<base::Value> child(FromV8ValueImpl(state, child_v8, isolate));
- if (!child)
- // JSON.stringify skips properties whose values don't serialize, for
- // example undefined and functions. Emulate that behavior.
- continue;
-
- // Strip null if asked (and since undefined is turned into null, undefined
- // too). The use case for supporting this is JSON-schema support,
- // specifically for extensions, where "optional" JSON properties may be
- // represented as null, yet due to buggy legacy code elsewhere isn't
- // treated as such (potentially causing crashes). For example, the
- // "tabs.create" function takes an object as its first argument with an
- // optional "windowId" property.
- //
- // Given just
- //
- // tabs.create({})
- //
- // this will work as expected on code that only checks for the existence of
- // a "windowId" property (such as that legacy code). However given
- //
- // tabs.create({windowId: null})
- //
- // there *is* a "windowId" property, but since it should be an int, code
- // on the browser which doesn't additionally check for null will fail.
- // We can avoid all bugs related to this by stripping null.
- if (strip_null_from_objects_ && child->IsType(base::Value::TYPE_NULL))
- continue;
-
- result->SetWithoutPathExpansion(std::string(*name_utf8, name_utf8.length()),
- child.release());
- }
-
- return result.release();
-}
-
-} // namespace content
diff --git a/chromium/content/renderer/v8_value_converter_impl.h b/chromium/content/renderer/v8_value_converter_impl.h
deleted file mode 100644
index decc10b3863..00000000000
--- a/chromium/content/renderer/v8_value_converter_impl.h
+++ /dev/null
@@ -1,98 +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_RENDERER_V8_VALUE_CONVERTER_IMPL_H_
-#define CONTENT_RENDERER_V8_VALUE_CONVERTER_IMPL_H_
-
-#include <map>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "content/common/content_export.h"
-#include "content/public/renderer/v8_value_converter.h"
-
-namespace base {
-class BinaryValue;
-class DictionaryValue;
-class ListValue;
-class Value;
-}
-
-namespace content {
-
-class CONTENT_EXPORT V8ValueConverterImpl : public V8ValueConverter {
- public:
- V8ValueConverterImpl();
-
- // V8ValueConverter implementation.
- void SetDateAllowed(bool val) override;
- void SetRegExpAllowed(bool val) override;
- void SetFunctionAllowed(bool val) override;
- void SetStripNullFromObjects(bool val) override;
- void SetStrategy(Strategy* strategy) override;
- v8::Handle<v8::Value> ToV8Value(
- const base::Value* value,
- v8::Handle<v8::Context> context) const override;
- base::Value* FromV8Value(v8::Handle<v8::Value> value,
- v8::Handle<v8::Context> context) const override;
-
- private:
- friend class ScopedAvoidIdentityHashForTesting;
-
- class FromV8ValueState;
-
- v8::Local<v8::Value> ToV8ValueImpl(v8::Isolate* isolate,
- v8::Handle<v8::Object> creation_context,
- const base::Value* value) const;
- v8::Handle<v8::Value> ToV8Array(v8::Isolate* isolate,
- v8::Handle<v8::Object> creation_context,
- const base::ListValue* list) const;
- v8::Handle<v8::Value> ToV8Object(
- v8::Isolate* isolate,
- v8::Handle<v8::Object> creation_context,
- const base::DictionaryValue* dictionary) const;
- v8::Handle<v8::Value> ToArrayBuffer(v8::Isolate* isolate,
- v8::Handle<v8::Object> creation_context,
- const base::BinaryValue* value) const;
-
- base::Value* FromV8ValueImpl(FromV8ValueState* state,
- v8::Handle<v8::Value> value,
- v8::Isolate* isolate) const;
- base::Value* FromV8Array(v8::Handle<v8::Array> array,
- FromV8ValueState* state,
- v8::Isolate* isolate) const;
-
- // This will convert objects of type ArrayBuffer or any of the
- // ArrayBufferView subclasses.
- base::Value* FromV8ArrayBuffer(v8::Handle<v8::Object> val,
- v8::Isolate* isolate) const;
-
- base::Value* FromV8Object(v8::Handle<v8::Object> object,
- FromV8ValueState* state,
- v8::Isolate* isolate) const;
-
- // If true, we will convert Date JavaScript objects to doubles.
- bool date_allowed_;
-
- // If true, we will convert RegExp JavaScript objects to string.
- bool reg_exp_allowed_;
-
- // If true, we will convert Function JavaScript objects to dictionaries.
- bool function_allowed_;
-
- // If true, undefined and null values are ignored when converting v8 objects
- // into Values.
- bool strip_null_from_objects_;
-
- bool avoid_identity_hash_for_testing_;
-
- // Strategy object that changes the converter's behavior.
- Strategy* strategy_;
-
- DISALLOW_COPY_AND_ASSIGN(V8ValueConverterImpl);
-};
-
-} // namespace content
-
-#endif // CONTENT_RENDERER_V8_VALUE_CONVERTER_IMPL_H_
diff --git a/chromium/content/renderer/v8_value_converter_impl_unittest.cc b/chromium/content/renderer/v8_value_converter_impl_unittest.cc
deleted file mode 100644
index 5cd30a9f291..00000000000
--- a/chromium/content/renderer/v8_value_converter_impl_unittest.cc
+++ /dev/null
@@ -1,875 +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 <cmath>
-
-#include "base/memory/scoped_ptr.h"
-#include "base/stl_util.h"
-#include "base/test/values_test_util.h"
-#include "base/values.h"
-#include "content/renderer/v8_value_converter_impl.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "v8/include/v8.h"
-
-namespace content {
-
-// To improve the performance of
-// V8ValueConverterImpl::UpdateAndCheckUniqueness, identity hashes of objects
-// are used during checking for duplicates. For testing purposes we need to
-// ignore the hash sometimes. Create this helper object to avoid using identity
-// hashes for the lifetime of the helper.
-class ScopedAvoidIdentityHashForTesting {
- public:
- // The hashes will be ignored in |converter|, which must not be NULL and it
- // must outlive the created instance of this helper.
- explicit ScopedAvoidIdentityHashForTesting(
- content::V8ValueConverterImpl* converter);
- ~ScopedAvoidIdentityHashForTesting();
-
- private:
- content::V8ValueConverterImpl* converter_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedAvoidIdentityHashForTesting);
-};
-
-ScopedAvoidIdentityHashForTesting::ScopedAvoidIdentityHashForTesting(
- content::V8ValueConverterImpl* converter)
- : converter_(converter) {
- CHECK(converter_);
- converter_->avoid_identity_hash_for_testing_ = true;
-}
-
-ScopedAvoidIdentityHashForTesting::~ScopedAvoidIdentityHashForTesting() {
- converter_->avoid_identity_hash_for_testing_ = false;
-}
-
-class V8ValueConverterImplTest : public testing::Test {
- public:
- V8ValueConverterImplTest()
- : isolate_(v8::Isolate::GetCurrent()) {
- }
-
- protected:
- void SetUp() override {
- v8::HandleScope handle_scope(isolate_);
- v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate_);
- context_.Reset(isolate_, v8::Context::New(isolate_, NULL, global));
- }
-
- void TearDown() override { context_.Reset(); }
-
- std::string GetString(base::DictionaryValue* value, const std::string& key) {
- std::string temp;
- if (!value->GetString(key, &temp)) {
- ADD_FAILURE();
- return std::string();
- }
- return temp;
- }
-
- std::string GetString(v8::Handle<v8::Object> value, const std::string& key) {
- v8::Handle<v8::String> temp =
- value->Get(v8::String::NewFromUtf8(isolate_, key.c_str()))
- .As<v8::String>();
- if (temp.IsEmpty()) {
- ADD_FAILURE();
- return std::string();
- }
- v8::String::Utf8Value utf8(temp);
- return std::string(*utf8, utf8.length());
- }
-
- std::string GetString(base::ListValue* value, uint32 index) {
- std::string temp;
- if (!value->GetString(static_cast<size_t>(index), &temp)) {
- ADD_FAILURE();
- return std::string();
- }
- return temp;
- }
-
- std::string GetString(v8::Handle<v8::Array> value, uint32 index) {
- v8::Handle<v8::String> temp = value->Get(index).As<v8::String>();
- if (temp.IsEmpty()) {
- ADD_FAILURE();
- return std::string();
- }
- v8::String::Utf8Value utf8(temp);
- return std::string(*utf8, utf8.length());
- }
-
- bool IsNull(base::DictionaryValue* value, const std::string& key) {
- base::Value* child = NULL;
- if (!value->Get(key, &child)) {
- ADD_FAILURE();
- return false;
- }
- return child->GetType() == base::Value::TYPE_NULL;
- }
-
- bool IsNull(v8::Handle<v8::Object> value, const std::string& key) {
- v8::Handle<v8::Value> child =
- value->Get(v8::String::NewFromUtf8(isolate_, key.c_str()));
- if (child.IsEmpty()) {
- ADD_FAILURE();
- return false;
- }
- return child->IsNull();
- }
-
- bool IsNull(base::ListValue* value, uint32 index) {
- base::Value* child = NULL;
- if (!value->Get(static_cast<size_t>(index), &child)) {
- ADD_FAILURE();
- return false;
- }
- return child->GetType() == base::Value::TYPE_NULL;
- }
-
- bool IsNull(v8::Handle<v8::Array> value, uint32 index) {
- v8::Handle<v8::Value> child = value->Get(index);
- if (child.IsEmpty()) {
- ADD_FAILURE();
- return false;
- }
- return child->IsNull();
- }
-
- void TestWeirdType(const V8ValueConverterImpl& converter,
- v8::Handle<v8::Value> val,
- base::Value::Type expected_type,
- scoped_ptr<base::Value> expected_value) {
- v8::Local<v8::Context> context =
- v8::Local<v8::Context>::New(isolate_, context_);
- scoped_ptr<base::Value> raw(converter.FromV8Value(val, context));
-
- if (expected_value) {
- ASSERT_TRUE(raw.get());
- EXPECT_TRUE(expected_value->Equals(raw.get()));
- EXPECT_EQ(expected_type, raw->GetType());
- } else {
- EXPECT_FALSE(raw.get());
- }
-
- v8::Handle<v8::Object> object(v8::Object::New(isolate_));
- object->Set(v8::String::NewFromUtf8(isolate_, "test"), val);
- scoped_ptr<base::DictionaryValue> dictionary(
- static_cast<base::DictionaryValue*>(
- converter.FromV8Value(object, context)));
- ASSERT_TRUE(dictionary.get());
-
- if (expected_value) {
- base::Value* temp = NULL;
- ASSERT_TRUE(dictionary->Get("test", &temp));
- EXPECT_EQ(expected_type, temp->GetType());
- EXPECT_TRUE(expected_value->Equals(temp));
- } else {
- EXPECT_FALSE(dictionary->HasKey("test"));
- }
-
- v8::Handle<v8::Array> array(v8::Array::New(isolate_));
- array->Set(0, val);
- scoped_ptr<base::ListValue> list(
- static_cast<base::ListValue*>(converter.FromV8Value(array, context)));
- ASSERT_TRUE(list.get());
- if (expected_value) {
- base::Value* temp = NULL;
- ASSERT_TRUE(list->Get(0, &temp));
- EXPECT_EQ(expected_type, temp->GetType());
- EXPECT_TRUE(expected_value->Equals(temp));
- } else {
- // Arrays should preserve their length, and convert unconvertible
- // types into null.
- base::Value* temp = NULL;
- ASSERT_TRUE(list->Get(0, &temp));
- EXPECT_EQ(base::Value::TYPE_NULL, temp->GetType());
- }
- }
-
- v8::Isolate* isolate_;
-
- // Context for the JavaScript in the test.
- v8::Persistent<v8::Context> context_;
-};
-
-TEST_F(V8ValueConverterImplTest, BasicRoundTrip) {
- scoped_ptr<base::Value> original_root = base::test::ParseJson(
- "{ \n"
- " \"null\": null, \n"
- " \"true\": true, \n"
- " \"false\": false, \n"
- " \"positive-int\": 42, \n"
- " \"negative-int\": -42, \n"
- " \"zero\": 0, \n"
- " \"double\": 88.8, \n"
- " \"big-integral-double\": 9007199254740992.0, \n" // 2.0^53
- " \"string\": \"foobar\", \n"
- " \"empty-string\": \"\", \n"
- " \"dictionary\": { \n"
- " \"foo\": \"bar\",\n"
- " \"hot\": \"dog\",\n"
- " }, \n"
- " \"empty-dictionary\": {}, \n"
- " \"list\": [ \"monkey\", \"balls\" ], \n"
- " \"empty-list\": [], \n"
- "}");
-
- v8::HandleScope handle_scope(isolate_);
- v8::Local<v8::Context> context =
- v8::Local<v8::Context>::New(isolate_, context_);
- v8::Context::Scope context_scope(context);
-
- V8ValueConverterImpl converter;
- v8::Handle<v8::Object> v8_object =
- converter.ToV8Value(original_root.get(), context).As<v8::Object>();
- ASSERT_FALSE(v8_object.IsEmpty());
-
- EXPECT_EQ(static_cast<const base::DictionaryValue&>(*original_root).size(),
- v8_object->GetPropertyNames()->Length());
- EXPECT_TRUE(
- v8_object->Get(v8::String::NewFromUtf8(isolate_, "null"))->IsNull());
- EXPECT_TRUE(
- v8_object->Get(v8::String::NewFromUtf8(isolate_, "true"))->IsTrue());
- EXPECT_TRUE(
- v8_object->Get(v8::String::NewFromUtf8(isolate_, "false"))->IsFalse());
- EXPECT_TRUE(v8_object->Get(v8::String::NewFromUtf8(isolate_, "positive-int"))
- ->IsInt32());
- EXPECT_TRUE(v8_object->Get(v8::String::NewFromUtf8(isolate_, "negative-int"))
- ->IsInt32());
- EXPECT_TRUE(
- v8_object->Get(v8::String::NewFromUtf8(isolate_, "zero"))->IsInt32());
- EXPECT_TRUE(
- v8_object->Get(v8::String::NewFromUtf8(isolate_, "double"))->IsNumber());
- EXPECT_TRUE(v8_object->Get(v8::String::NewFromUtf8(
- isolate_, "big-integral-double"))->IsNumber());
- EXPECT_TRUE(
- v8_object->Get(v8::String::NewFromUtf8(isolate_, "string"))->IsString());
- EXPECT_TRUE(v8_object->Get(v8::String::NewFromUtf8(isolate_, "empty-string"))
- ->IsString());
- EXPECT_TRUE(v8_object->Get(v8::String::NewFromUtf8(isolate_, "dictionary"))
- ->IsObject());
- EXPECT_TRUE(v8_object->Get(v8::String::NewFromUtf8(
- isolate_, "empty-dictionary"))->IsObject());
- EXPECT_TRUE(
- v8_object->Get(v8::String::NewFromUtf8(isolate_, "list"))->IsArray());
- EXPECT_TRUE(v8_object->Get(v8::String::NewFromUtf8(isolate_, "empty-list"))
- ->IsArray());
-
- scoped_ptr<base::Value> new_root(converter.FromV8Value(v8_object, context));
- EXPECT_NE(original_root.get(), new_root.get());
- EXPECT_TRUE(original_root->Equals(new_root.get()));
-}
-
-TEST_F(V8ValueConverterImplTest, KeysWithDots) {
- scoped_ptr<base::Value> original =
- base::test::ParseJson("{ \"foo.bar\": \"baz\" }");
-
- v8::HandleScope handle_scope(isolate_);
- v8::Local<v8::Context> context =
- v8::Local<v8::Context>::New(isolate_, context_);
- v8::Context::Scope context_scope(context);
-
- V8ValueConverterImpl converter;
- scoped_ptr<base::Value> copy(
- converter.FromV8Value(
- converter.ToV8Value(original.get(), context), context));
-
- EXPECT_TRUE(original->Equals(copy.get()));
-}
-
-TEST_F(V8ValueConverterImplTest, ObjectExceptions) {
- v8::HandleScope handle_scope(isolate_);
- v8::Local<v8::Context> context =
- v8::Local<v8::Context>::New(isolate_, context_);
- v8::Context::Scope context_scope(context);
-
- // Set up objects to throw when reading or writing 'foo'.
- const char* source =
- "Object.prototype.__defineSetter__('foo', "
- " function() { throw new Error('muah!'); });"
- "Object.prototype.__defineGetter__('foo', "
- " function() { throw new Error('muah!'); });";
-
- v8::Handle<v8::Script> script(
- v8::Script::Compile(v8::String::NewFromUtf8(isolate_, source)));
- script->Run();
-
- v8::Handle<v8::Object> object(v8::Object::New(isolate_));
- object->Set(v8::String::NewFromUtf8(isolate_, "bar"),
- v8::String::NewFromUtf8(isolate_, "bar"));
-
- // Converting from v8 value should replace the foo property with null.
- V8ValueConverterImpl converter;
- scoped_ptr<base::DictionaryValue> converted(
- static_cast<base::DictionaryValue*>(
- converter.FromV8Value(object, context)));
- EXPECT_TRUE(converted.get());
- // http://code.google.com/p/v8/issues/detail?id=1342
- // EXPECT_EQ(2u, converted->size());
- // EXPECT_TRUE(IsNull(converted.get(), "foo"));
- EXPECT_EQ(1u, converted->size());
- EXPECT_EQ("bar", GetString(converted.get(), "bar"));
-
- // Converting to v8 value should drop the foo property.
- converted->SetString("foo", "foo");
- v8::Handle<v8::Object> copy =
- converter.ToV8Value(converted.get(), context).As<v8::Object>();
- EXPECT_FALSE(copy.IsEmpty());
- EXPECT_EQ(2u, copy->GetPropertyNames()->Length());
- EXPECT_EQ("bar", GetString(copy, "bar"));
-}
-
-TEST_F(V8ValueConverterImplTest, ArrayExceptions) {
- v8::HandleScope handle_scope(isolate_);
- v8::Local<v8::Context> context =
- v8::Local<v8::Context>::New(isolate_, context_);
- v8::Context::Scope context_scope(context);
-
- const char* source = "(function() {"
- "var arr = [];"
- "arr.__defineSetter__(0, "
- " function() { throw new Error('muah!'); });"
- "arr.__defineGetter__(0, "
- " function() { throw new Error('muah!'); });"
- "arr[1] = 'bar';"
- "return arr;"
- "})();";
-
- v8::Handle<v8::Script> script(
- v8::Script::Compile(v8::String::NewFromUtf8(isolate_, source)));
- v8::Handle<v8::Array> array = script->Run().As<v8::Array>();
- ASSERT_FALSE(array.IsEmpty());
-
- // Converting from v8 value should replace the first item with null.
- V8ValueConverterImpl converter;
- scoped_ptr<base::ListValue> converted(static_cast<base::ListValue*>(
- converter.FromV8Value(array, context)));
- ASSERT_TRUE(converted.get());
- // http://code.google.com/p/v8/issues/detail?id=1342
- EXPECT_EQ(2u, converted->GetSize());
- EXPECT_TRUE(IsNull(converted.get(), 0));
-
- // Converting to v8 value should drop the first item and leave a hole.
- converted.reset(static_cast<base::ListValue*>(
- base::test::ParseJson("[ \"foo\", \"bar\" ]").release()));
- v8::Handle<v8::Array> copy =
- converter.ToV8Value(converted.get(), context).As<v8::Array>();
- ASSERT_FALSE(copy.IsEmpty());
- EXPECT_EQ(2u, copy->Length());
- EXPECT_EQ("bar", GetString(copy, 1));
-}
-
-TEST_F(V8ValueConverterImplTest, WeirdTypes) {
- v8::HandleScope handle_scope(isolate_);
- v8::Local<v8::Context> context =
- v8::Local<v8::Context>::New(isolate_, context_);
- v8::Context::Scope context_scope(context);
-
- v8::Handle<v8::RegExp> regex(v8::RegExp::New(
- v8::String::NewFromUtf8(isolate_, "."), v8::RegExp::kNone));
-
- V8ValueConverterImpl converter;
- TestWeirdType(converter,
- v8::Undefined(isolate_),
- base::Value::TYPE_NULL, // Arbitrary type, result is NULL.
- scoped_ptr<base::Value>());
- TestWeirdType(converter,
- v8::Date::New(isolate_, 1000),
- base::Value::TYPE_DICTIONARY,
- scoped_ptr<base::Value>(new base::DictionaryValue()));
- TestWeirdType(converter,
- regex,
- base::Value::TYPE_DICTIONARY,
- scoped_ptr<base::Value>(new base::DictionaryValue()));
-
- converter.SetDateAllowed(true);
- TestWeirdType(converter,
- v8::Date::New(isolate_, 1000),
- base::Value::TYPE_DOUBLE,
- scoped_ptr<base::Value>(new base::FundamentalValue(1.0)));
-
- converter.SetRegExpAllowed(true);
- TestWeirdType(converter,
- regex,
- base::Value::TYPE_STRING,
- scoped_ptr<base::Value>(new base::StringValue("/./")));
-}
-
-TEST_F(V8ValueConverterImplTest, Prototype) {
- v8::HandleScope handle_scope(isolate_);
- v8::Local<v8::Context> context =
- v8::Local<v8::Context>::New(isolate_, context_);
- v8::Context::Scope context_scope(context);
-
- const char* source = "(function() {"
- "Object.prototype.foo = 'foo';"
- "return {};"
- "})();";
-
- v8::Handle<v8::Script> script(
- v8::Script::Compile(v8::String::NewFromUtf8(isolate_, source)));
- v8::Handle<v8::Object> object = script->Run().As<v8::Object>();
- ASSERT_FALSE(object.IsEmpty());
-
- V8ValueConverterImpl converter;
- scoped_ptr<base::DictionaryValue> result(
- static_cast<base::DictionaryValue*>(
- converter.FromV8Value(object, context)));
- ASSERT_TRUE(result.get());
- EXPECT_EQ(0u, result->size());
-}
-
-TEST_F(V8ValueConverterImplTest, StripNullFromObjects) {
- v8::HandleScope handle_scope(isolate_);
- v8::Local<v8::Context> context =
- v8::Local<v8::Context>::New(isolate_, context_);
- v8::Context::Scope context_scope(context);
-
- const char* source = "(function() {"
- "return { foo: undefined, bar: null };"
- "})();";
-
- v8::Handle<v8::Script> script(
- v8::Script::Compile(v8::String::NewFromUtf8(isolate_, source)));
- v8::Handle<v8::Object> object = script->Run().As<v8::Object>();
- ASSERT_FALSE(object.IsEmpty());
-
- V8ValueConverterImpl converter;
- converter.SetStripNullFromObjects(true);
-
- scoped_ptr<base::DictionaryValue> result(
- static_cast<base::DictionaryValue*>(
- converter.FromV8Value(object, context)));
- ASSERT_TRUE(result.get());
- EXPECT_EQ(0u, result->size());
-}
-
-TEST_F(V8ValueConverterImplTest, RecursiveObjects) {
- v8::HandleScope handle_scope(isolate_);
- v8::Local<v8::Context> context =
- v8::Local<v8::Context>::New(isolate_, context_);
- v8::Context::Scope context_scope(context);
-
- V8ValueConverterImpl converter;
-
- v8::Handle<v8::Object> object = v8::Object::New(isolate_).As<v8::Object>();
- ASSERT_FALSE(object.IsEmpty());
- object->Set(v8::String::NewFromUtf8(isolate_, "foo"),
- v8::String::NewFromUtf8(isolate_, "bar"));
- object->Set(v8::String::NewFromUtf8(isolate_, "obj"), object);
-
- scoped_ptr<base::DictionaryValue> object_result(
- static_cast<base::DictionaryValue*>(
- converter.FromV8Value(object, context)));
- ASSERT_TRUE(object_result.get());
- EXPECT_EQ(2u, object_result->size());
- EXPECT_TRUE(IsNull(object_result.get(), "obj"));
-
- v8::Handle<v8::Array> array = v8::Array::New(isolate_).As<v8::Array>();
- ASSERT_FALSE(array.IsEmpty());
- array->Set(0, v8::String::NewFromUtf8(isolate_, "1"));
- array->Set(1, array);
-
- scoped_ptr<base::ListValue> list_result(
- static_cast<base::ListValue*>(converter.FromV8Value(array, context)));
- ASSERT_TRUE(list_result.get());
- EXPECT_EQ(2u, list_result->GetSize());
- EXPECT_TRUE(IsNull(list_result.get(), 1));
-}
-
-TEST_F(V8ValueConverterImplTest, WeirdProperties) {
- v8::HandleScope handle_scope(isolate_);
- v8::Local<v8::Context> context =
- v8::Local<v8::Context>::New(isolate_, context_);
- v8::Context::Scope context_scope(context);
-
- const char* source = "(function() {"
- "return {"
- "1: 'foo',"
- "'2': 'bar',"
- "true: 'baz',"
- "false: 'qux',"
- "null: 'quux',"
- "undefined: 'oops'"
- "};"
- "})();";
-
- v8::Handle<v8::Script> script(
- v8::Script::Compile(v8::String::NewFromUtf8(isolate_, source)));
- v8::Handle<v8::Object> object = script->Run().As<v8::Object>();
- ASSERT_FALSE(object.IsEmpty());
-
- V8ValueConverterImpl converter;
- scoped_ptr<base::Value> actual(converter.FromV8Value(object, context));
-
- scoped_ptr<base::Value> expected = base::test::ParseJson(
- "{ \n"
- " \"1\": \"foo\", \n"
- " \"2\": \"bar\", \n"
- " \"true\": \"baz\", \n"
- " \"false\": \"qux\", \n"
- " \"null\": \"quux\", \n"
- " \"undefined\": \"oops\", \n"
- "}");
-
- EXPECT_TRUE(expected->Equals(actual.get()));
-}
-
-TEST_F(V8ValueConverterImplTest, ArrayGetters) {
- v8::HandleScope handle_scope(isolate_);
- v8::Local<v8::Context> context =
- v8::Local<v8::Context>::New(isolate_, context_);
- v8::Context::Scope context_scope(context);
-
- const char* source = "(function() {"
- "var a = [0];"
- "a.__defineGetter__(1, function() { return 'bar'; });"
- "return a;"
- "})();";
-
- v8::Handle<v8::Script> script(
- v8::Script::Compile(v8::String::NewFromUtf8(isolate_, source)));
- v8::Handle<v8::Array> array = script->Run().As<v8::Array>();
- ASSERT_FALSE(array.IsEmpty());
-
- V8ValueConverterImpl converter;
- scoped_ptr<base::ListValue> result(
- static_cast<base::ListValue*>(converter.FromV8Value(array, context)));
- ASSERT_TRUE(result.get());
- EXPECT_EQ(2u, result->GetSize());
-}
-
-TEST_F(V8ValueConverterImplTest, UndefinedValueBehavior) {
- v8::HandleScope handle_scope(isolate_);
- v8::Local<v8::Context> context =
- v8::Local<v8::Context>::New(isolate_, context_);
- v8::Context::Scope context_scope(context);
-
- v8::Handle<v8::Object> object;
- {
- const char* source = "(function() {"
- "return { foo: undefined, bar: null, baz: function(){} };"
- "})();";
- v8::Handle<v8::Script> script(
- v8::Script::Compile(v8::String::NewFromUtf8(isolate_, source)));
- object = script->Run().As<v8::Object>();
- ASSERT_FALSE(object.IsEmpty());
- }
-
- v8::Handle<v8::Array> array;
- {
- const char* source = "(function() {"
- "return [ undefined, null, function(){} ];"
- "})();";
- v8::Handle<v8::Script> script(
- v8::Script::Compile(v8::String::NewFromUtf8(isolate_, source)));
- array = script->Run().As<v8::Array>();
- ASSERT_FALSE(array.IsEmpty());
- }
-
- v8::Handle<v8::Array> sparse_array;
- {
- const char* source = "(function() {"
- "return new Array(3);"
- "})();";
- v8::Handle<v8::Script> script(
- v8::Script::Compile(v8::String::NewFromUtf8(isolate_, source)));
- sparse_array = script->Run().As<v8::Array>();
- ASSERT_FALSE(sparse_array.IsEmpty());
- }
-
- V8ValueConverterImpl converter;
-
- scoped_ptr<base::Value> actual_object(
- converter.FromV8Value(object, context));
- EXPECT_TRUE(base::Value::Equals(
- base::test::ParseJson("{ \"bar\": null }").get(), actual_object.get()));
-
- // Everything is null because JSON stringification preserves array length.
- scoped_ptr<base::Value> actual_array(converter.FromV8Value(array, context));
- EXPECT_TRUE(base::Value::Equals(
- base::test::ParseJson("[ null, null, null ]").get(), actual_array.get()));
-
- scoped_ptr<base::Value> actual_sparse_array(
- converter.FromV8Value(sparse_array, context));
- EXPECT_TRUE(
- base::Value::Equals(base::test::ParseJson("[ null, null, null ]").get(),
- actual_sparse_array.get()));
-}
-
-TEST_F(V8ValueConverterImplTest, ObjectsWithClashingIdentityHash) {
- v8::HandleScope handle_scope(isolate_);
- v8::Local<v8::Context> context =
- v8::Local<v8::Context>::New(isolate_, context_);
- v8::Context::Scope context_scope(context);
- V8ValueConverterImpl converter;
-
- // We check that the converter checks identity correctly by disabling the
- // optimization of using identity hashes.
- ScopedAvoidIdentityHashForTesting scoped_hash_avoider(&converter);
-
- // Create the v8::Object to be converted.
- v8::Handle<v8::Array> root(v8::Array::New(isolate_, 4));
- root->Set(0, v8::Handle<v8::Object>(v8::Object::New(isolate_)));
- root->Set(1, v8::Handle<v8::Object>(v8::Object::New(isolate_)));
- root->Set(2, v8::Handle<v8::Object>(v8::Array::New(isolate_, 0)));
- root->Set(3, v8::Handle<v8::Object>(v8::Array::New(isolate_, 0)));
-
- // The expected base::Value result.
- scoped_ptr<base::Value> expected = base::test::ParseJson("[{},{},[],[]]");
- ASSERT_TRUE(expected.get());
-
- // The actual result.
- scoped_ptr<base::Value> value(converter.FromV8Value(root, context));
- ASSERT_TRUE(value.get());
-
- EXPECT_TRUE(expected->Equals(value.get()));
-}
-
-TEST_F(V8ValueConverterImplTest, DetectCycles) {
- v8::HandleScope handle_scope(isolate_);
- v8::Local<v8::Context> context =
- v8::Local<v8::Context>::New(isolate_, context_);
- v8::Context::Scope context_scope(context);
- V8ValueConverterImpl converter;
-
- // Create a recursive array.
- v8::Handle<v8::Array> recursive_array(v8::Array::New(isolate_, 1));
- recursive_array->Set(0, recursive_array);
-
- // The first repetition should be trimmed and replaced by a null value.
- base::ListValue expected_list;
- expected_list.Append(base::Value::CreateNullValue());
-
- // The actual result.
- scoped_ptr<base::Value> actual_list(
- converter.FromV8Value(recursive_array, context));
- ASSERT_TRUE(actual_list.get());
-
- EXPECT_TRUE(expected_list.Equals(actual_list.get()));
-
- // Now create a recursive object
- const std::string key("key");
- v8::Handle<v8::Object> recursive_object(v8::Object::New(isolate_));
- v8::TryCatch try_catch;
- recursive_object->Set(
- v8::String::NewFromUtf8(
- isolate_, key.c_str(), v8::String::kNormalString, key.length()),
- recursive_object);
- ASSERT_FALSE(try_catch.HasCaught());
-
- // The first repetition should be trimmed and replaced by a null value.
- base::DictionaryValue expected_dictionary;
- expected_dictionary.Set(key, base::Value::CreateNullValue());
-
- // The actual result.
- scoped_ptr<base::Value> actual_dictionary(
- converter.FromV8Value(recursive_object, context));
- ASSERT_TRUE(actual_dictionary.get());
-
- EXPECT_TRUE(expected_dictionary.Equals(actual_dictionary.get()));
-}
-
-TEST_F(V8ValueConverterImplTest, MaxRecursionDepth) {
- v8::HandleScope handle_scope(isolate_);
- v8::Local<v8::Context> context =
- v8::Local<v8::Context>::New(isolate_, context_);
- v8::Context::Scope context_scope(context);
-
- // Must larger than kMaxRecursionDepth in v8_value_converter_impl.cc.
- int kDepth = 1000;
- const char kKey[] = "key";
-
- v8::Local<v8::Object> deep_object = v8::Object::New(isolate_);
-
- v8::Local<v8::Object> leaf = deep_object;
- for (int i = 0; i < kDepth; ++i) {
- v8::Local<v8::Object> new_object = v8::Object::New(isolate_);
- leaf->Set(v8::String::NewFromUtf8(isolate_, kKey), new_object);
- leaf = new_object;
- }
-
- V8ValueConverterImpl converter;
- scoped_ptr<base::Value> value(converter.FromV8Value(deep_object, context));
- ASSERT_TRUE(value);
-
- // Expected depth is kMaxRecursionDepth in v8_value_converter_impl.cc.
- int kExpectedDepth = 100;
-
- base::Value* current = value.get();
- for (int i = 1; i < kExpectedDepth; ++i) {
- base::DictionaryValue* current_as_object = NULL;
- ASSERT_TRUE(current->GetAsDictionary(&current_as_object)) << i;
- ASSERT_TRUE(current_as_object->Get(kKey, &current)) << i;
- }
-
- // The leaf node shouldn't have any properties.
- base::DictionaryValue empty;
- EXPECT_TRUE(base::Value::Equals(&empty, current)) << *current;
-}
-
-class V8ValueConverterOverridingStrategyForTesting
- : public V8ValueConverter::Strategy {
- public:
- V8ValueConverterOverridingStrategyForTesting()
- : reference_value_(NewReferenceValue()) {}
- bool FromV8Object(v8::Handle<v8::Object> value,
- base::Value** out,
- v8::Isolate* isolate,
- const FromV8ValueCallback& callback) const override {
- *out = NewReferenceValue();
- return true;
- }
- bool FromV8Array(v8::Handle<v8::Array> value,
- base::Value** out,
- v8::Isolate* isolate,
- const FromV8ValueCallback& callback) const override {
- *out = NewReferenceValue();
- return true;
- }
- bool FromV8ArrayBuffer(v8::Handle<v8::Object> value,
- base::Value** out,
- v8::Isolate* isolate) const override {
- *out = NewReferenceValue();
- return true;
- }
- bool FromV8Number(v8::Handle<v8::Number> value,
- base::Value** out) const override {
- *out = NewReferenceValue();
- return true;
- }
- bool FromV8Undefined(base::Value** out) const override {
- *out = NewReferenceValue();
- return true;
- }
- base::Value* reference_value() const { return reference_value_.get(); }
-
- private:
- static base::Value* NewReferenceValue() {
- return new base::StringValue("strategy");
- }
- scoped_ptr<base::Value> reference_value_;
-};
-
-TEST_F(V8ValueConverterImplTest, StrategyOverrides) {
- v8::HandleScope handle_scope(isolate_);
- v8::Local<v8::Context> context =
- v8::Local<v8::Context>::New(isolate_, context_);
- v8::Context::Scope context_scope(context);
-
- V8ValueConverterImpl converter;
- V8ValueConverterOverridingStrategyForTesting strategy;
- converter.SetStrategy(&strategy);
-
- v8::Handle<v8::Object> object(v8::Object::New(isolate_));
- scoped_ptr<base::Value> object_value(converter.FromV8Value(object, context));
- ASSERT_TRUE(object_value);
- EXPECT_TRUE(
- base::Value::Equals(strategy.reference_value(), object_value.get()));
-
- v8::Handle<v8::Array> array(v8::Array::New(isolate_));
- scoped_ptr<base::Value> array_value(converter.FromV8Value(array, context));
- ASSERT_TRUE(array_value);
- EXPECT_TRUE(
- base::Value::Equals(strategy.reference_value(), array_value.get()));
-
- v8::Handle<v8::ArrayBuffer> array_buffer(v8::ArrayBuffer::New(isolate_, 0));
- scoped_ptr<base::Value> array_buffer_value(
- converter.FromV8Value(array_buffer, context));
- ASSERT_TRUE(array_buffer_value);
- EXPECT_TRUE(base::Value::Equals(strategy.reference_value(),
- array_buffer_value.get()));
-
- v8::Handle<v8::ArrayBufferView> array_buffer_view(
- v8::Uint8Array::New(array_buffer, 0, 0));
- scoped_ptr<base::Value> array_buffer_view_value(
- converter.FromV8Value(array_buffer_view, context));
- ASSERT_TRUE(array_buffer_view_value);
- EXPECT_TRUE(base::Value::Equals(strategy.reference_value(),
- array_buffer_view_value.get()));
-
- v8::Handle<v8::Number> number(v8::Number::New(isolate_, 0.0));
- scoped_ptr<base::Value> number_value(converter.FromV8Value(number, context));
- ASSERT_TRUE(number_value);
- EXPECT_TRUE(
- base::Value::Equals(strategy.reference_value(), number_value.get()));
-
- v8::Handle<v8::Primitive> undefined(v8::Undefined(isolate_));
- scoped_ptr<base::Value> undefined_value(
- converter.FromV8Value(undefined, context));
- ASSERT_TRUE(undefined_value);
- EXPECT_TRUE(
- base::Value::Equals(strategy.reference_value(), undefined_value.get()));
-}
-
-class V8ValueConverterBypassStrategyForTesting
- : public V8ValueConverter::Strategy {
- public:
- bool FromV8Object(v8::Handle<v8::Object> value,
- base::Value** out,
- v8::Isolate* isolate,
- const FromV8ValueCallback& callback) const override {
- return false;
- }
- bool FromV8Array(v8::Handle<v8::Array> value,
- base::Value** out,
- v8::Isolate* isolate,
- const FromV8ValueCallback& callback) const override {
- return false;
- }
- bool FromV8ArrayBuffer(v8::Handle<v8::Object> value,
- base::Value** out,
- v8::Isolate* isolate) const override {
- return false;
- }
- bool FromV8Number(v8::Handle<v8::Number> value,
- base::Value** out) const override {
- return false;
- }
- bool FromV8Undefined(base::Value** out) const override { return false; }
-};
-
-// Verify that having a strategy that fallbacks to default behaviour
-// actually preserves it.
-TEST_F(V8ValueConverterImplTest, StrategyBypass) {
- v8::HandleScope handle_scope(isolate_);
- v8::Local<v8::Context> context =
- v8::Local<v8::Context>::New(isolate_, context_);
- v8::Context::Scope context_scope(context);
-
- V8ValueConverterImpl converter;
- V8ValueConverterBypassStrategyForTesting strategy;
- converter.SetStrategy(&strategy);
-
- v8::Handle<v8::Object> object(v8::Object::New(isolate_));
- scoped_ptr<base::Value> object_value(converter.FromV8Value(object, context));
- ASSERT_TRUE(object_value);
- scoped_ptr<base::Value> reference_object_value(base::test::ParseJson("{}"));
- EXPECT_TRUE(
- base::Value::Equals(reference_object_value.get(), object_value.get()));
-
- v8::Handle<v8::Array> array(v8::Array::New(isolate_));
- scoped_ptr<base::Value> array_value(converter.FromV8Value(array, context));
- ASSERT_TRUE(array_value);
- scoped_ptr<base::Value> reference_array_value(base::test::ParseJson("[]"));
- EXPECT_TRUE(
- base::Value::Equals(reference_array_value.get(), array_value.get()));
-
- // Not testing ArrayBuffers as V8ValueConverter uses blink helpers and
- // this requires having blink to be initialized.
-
- v8::Handle<v8::Number> number(v8::Number::New(isolate_, 0.0));
- scoped_ptr<base::Value> number_value(converter.FromV8Value(number, context));
- ASSERT_TRUE(number_value);
- scoped_ptr<base::Value> reference_number_value(base::test::ParseJson("0"));
- EXPECT_TRUE(
- base::Value::Equals(reference_number_value.get(), number_value.get()));
-
- v8::Handle<v8::Primitive> undefined(v8::Undefined(isolate_));
- scoped_ptr<base::Value> undefined_value(
- converter.FromV8Value(undefined, context));
- EXPECT_FALSE(undefined_value);
-}
-
-} // namespace content
diff --git a/chromium/content/renderer/visual_state_browsertest.cc b/chromium/content/renderer/visual_state_browsertest.cc
new file mode 100644
index 00000000000..26d9a6ddd26
--- /dev/null
+++ b/chromium/content/renderer/visual_state_browsertest.cc
@@ -0,0 +1,123 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/command_line.h"
+#include "base/run_loop.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/renderer/render_view.h"
+#include "content/public/renderer/render_view_observer.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/public/test/content_browser_test_utils.h"
+#include "content/public/test/test_utils.h"
+#include "content/renderer/render_frame_impl.h"
+#include "content/shell/browser/shell.h"
+
+namespace content {
+
+class CommitObserver : public RenderViewObserver {
+ public:
+ CommitObserver(RenderView* render_view)
+ : RenderViewObserver(render_view), quit_closures_(), commit_count_(0) {}
+
+ void DidCommitCompositorFrame() override {
+ commit_count_++;
+ for (base::Closure* closure : quit_closures_) {
+ closure->Run();
+ }
+ }
+
+ void QuitAfterCommit(int commit_number,
+ scoped_refptr<MessageLoopRunner> runner) {
+ if (commit_number >= commit_count_) runner->Quit();
+ }
+
+ void WaitForCommitNumber(int commit_number) {
+ if (commit_number > commit_count_) {
+ scoped_refptr<MessageLoopRunner> runner = new MessageLoopRunner;
+ base::Closure quit_closure =
+ base::Bind(&CommitObserver::QuitAfterCommit, base::Unretained(this),
+ commit_number, runner);
+ quit_closures_.insert(&quit_closure);
+ runner->Run();
+ quit_closures_.erase(&quit_closure);
+ }
+ }
+
+ int GetCommitCount() { return commit_count_; }
+
+ private:
+ std::set<base::Closure*> quit_closures_;
+ int commit_count_;
+};
+
+class VisualStateTest : public ContentBrowserTest {
+ public:
+ VisualStateTest() : callback_count_(0) {}
+
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ command_line->AppendSwitch(switches::kSingleProcess);
+ }
+
+ void WaitForCommit(CommitObserver *observer, int commit_number) {
+ observer->WaitForCommitNumber(commit_number);
+ EXPECT_EQ(commit_number, observer->GetCommitCount());
+ }
+
+ void AssertIsIdle() {
+ ASSERT_TRUE(base::MessageLoop::current()->IsIdleForTesting());
+ }
+
+ void InvokeVisualStateCallback(bool result) {
+ EXPECT_TRUE(result);
+ callback_count_++;
+ }
+
+ int GetCallbackCount() { return callback_count_; }
+
+ private:
+ int callback_count_;
+};
+
+// This test verifies that visual state callbacks do not deadlock. In other
+// words, the visual state callback should be received even if there are no
+// pending updates or commits.
+// Disabled due to cross-platform flakes; http://crbug.com/462580.
+IN_PROC_BROWSER_TEST_F(VisualStateTest, DISABLED_CallbackDoesNotDeadlock) {
+ // This test relies on the fact that loading "about:blank" only requires a
+ // single commit. We first load "about:blank" and wait for this single
+ // commit. At that point we know that the page has stabilized and no
+ // further commits are expected. We then insert a visual state callback
+ // and verify that this causes an additional commit in order to deliver
+ // the callback.
+ // Unfortunately, if loading "about:blank" changes and starts requiring
+ // two commits then this test will prove nothing. We could detect this
+ // with a high level of confidence if we used a timeout, but that's
+ // discouraged (see https://codereview.chromium.org/939673002).
+ NavigateToURL(shell(), GURL("about:blank"));
+ CommitObserver observer(
+ RenderView::FromRoutingID(shell()->web_contents()->GetRoutingID()));
+
+ // Wait for the commit corresponding to the load.
+
+ PostTaskToInProcessRendererAndWait(base::Bind(
+ &VisualStateTest::WaitForCommit, base::Unretained(this), &observer, 1));
+
+ // Try our best to check that there are no pending updates or commits.
+ PostTaskToInProcessRendererAndWait(
+ base::Bind(&VisualStateTest::AssertIsIdle, base::Unretained(this)));
+
+ // Insert a visual state callback.
+ shell()->web_contents()->GetMainFrame()->InsertVisualStateCallback(base::Bind(
+ &VisualStateTest::InvokeVisualStateCallback, base::Unretained(this)));
+
+ // Verify that the callback is invoked and a new commit completed.
+ PostTaskToInProcessRendererAndWait(base::Bind(
+ &VisualStateTest::WaitForCommit, base::Unretained(this), &observer, 2));
+ EXPECT_EQ(1, GetCallbackCount());
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/web_ui_extension.cc b/chromium/content/renderer/web_ui_extension.cc
index 127912630d8..94c33817b97 100644
--- a/chromium/content/renderer/web_ui_extension.cc
+++ b/chromium/content/renderer/web_ui_extension.cc
@@ -7,11 +7,11 @@
#include "base/memory/scoped_ptr.h"
#include "base/values.h"
#include "content/common/view_messages.h"
+#include "content/public/child/v8_value_converter.h"
#include "content/public/common/bindings_policy.h"
#include "content/public/common/url_constants.h"
#include "content/public/renderer/render_thread.h"
#include "content/public/renderer/render_view.h"
-#include "content/public/renderer/v8_value_converter.h"
#include "content/renderer/chrome_object_extensions_utils.h"
#include "content/renderer/web_ui_extension_data.h"
#include "gin/arguments.h"
@@ -64,13 +64,13 @@ bool ShouldRespondToRequest(
void WebUIExtension::Install(blink::WebFrame* frame) {
v8::Isolate* isolate = blink::mainThreadIsolate();
v8::HandleScope handle_scope(isolate);
- v8::Handle<v8::Context> context = frame->mainWorldScriptContext();
+ v8::Local<v8::Context> context = frame->mainWorldScriptContext();
if (context.IsEmpty())
return;
v8::Context::Scope context_scope(context);
- v8::Handle<v8::Object> chrome = GetOrCreateChromeObject(isolate,
+ v8::Local<v8::Object> chrome = GetOrCreateChromeObject(isolate,
context->Global());
chrome->Set(gin::StringToSymbol(isolate, "send"),
gin::CreateFunctionTemplate(
@@ -100,7 +100,7 @@ void WebUIExtension::Send(gin::Arguments* args) {
if (args->PeekNext().IsEmpty() || args->PeekNext()->IsUndefined()) {
content.reset(new base::ListValue());
} else {
- v8::Handle<v8::Object> obj;
+ v8::Local<v8::Object> obj;
if (!args->GetNext(&obj)) {
args->ThrowError();
return;
diff --git a/chromium/content/renderer/web_ui_mojo.cc b/chromium/content/renderer/web_ui_mojo.cc
index 968ca523350..aab0af22ce4 100644
--- a/chromium/content/renderer/web_ui_mojo.cc
+++ b/chromium/content/renderer/web_ui_mojo.cc
@@ -36,7 +36,7 @@ WebUIMojo::MainFrameObserver::~MainFrameObserver() {
}
void WebUIMojo::MainFrameObserver::WillReleaseScriptContext(
- v8::Handle<v8::Context> context,
+ v8::Local<v8::Context> context,
int world_id) {
web_ui_mojo_->DestroyContextState(context);
}
@@ -45,6 +45,9 @@ void WebUIMojo::MainFrameObserver::DidFinishDocumentLoad() {
web_ui_mojo_->OnDidFinishDocumentLoad();
}
+void WebUIMojo::MainFrameObserver::OnDestruct() {
+}
+
WebUIMojo::WebUIMojo(RenderView* render_view)
: RenderViewObserver(render_view),
RenderViewObserverTracker<WebUIMojo>(render_view),
@@ -58,7 +61,7 @@ void WebUIMojo::CreateContextState() {
v8::HandleScope handle_scope(blink::mainThreadIsolate());
blink::WebLocalFrame* frame =
render_view()->GetWebView()->mainFrame()->toWebLocalFrame();
- v8::Handle<v8::Context> context = frame->mainWorldScriptContext();
+ v8::Local<v8::Context> context = frame->mainWorldScriptContext();
gin::PerContextData* context_data = gin::PerContextData::From(context);
WebUIMojoContextStateData* data = new WebUIMojoContextStateData;
data->state.reset(new WebUIMojoContextState(
@@ -66,7 +69,7 @@ void WebUIMojo::CreateContextState() {
context_data->SetUserData(kWebUIMojoContextStateKey, data);
}
-void WebUIMojo::DestroyContextState(v8::Handle<v8::Context> context) {
+void WebUIMojo::DestroyContextState(v8::Local<v8::Context> context) {
gin::PerContextData* context_data = gin::PerContextData::From(context);
if (!context_data)
return;
@@ -84,7 +87,7 @@ WebUIMojoContextState* WebUIMojo::GetContextState() {
blink::WebLocalFrame* frame =
render_view()->GetWebView()->mainFrame()->toWebLocalFrame();
v8::HandleScope handle_scope(blink::mainThreadIsolate());
- v8::Handle<v8::Context> context = frame->mainWorldScriptContext();
+ v8::Local<v8::Context> context = frame->mainWorldScriptContext();
gin::PerContextData* context_data = gin::PerContextData::From(context);
if (!context_data)
return NULL;
diff --git a/chromium/content/renderer/web_ui_mojo.h b/chromium/content/renderer/web_ui_mojo.h
index dd9e752b238..769722ece01 100644
--- a/chromium/content/renderer/web_ui_mojo.h
+++ b/chromium/content/renderer/web_ui_mojo.h
@@ -10,7 +10,7 @@
#include "content/public/renderer/render_frame_observer.h"
#include "content/public/renderer/render_view_observer.h"
#include "content/public/renderer/render_view_observer_tracker.h"
-#include "mojo/public/cpp/system/core.h"
+#include "third_party/mojo/src/mojo/public/cpp/system/core.h"
namespace gin {
class PerContextData;
@@ -37,9 +37,14 @@ class WebUIMojo
~MainFrameObserver() override;
// RenderFrameObserver overrides:
- void WillReleaseScriptContext(v8::Handle<v8::Context> context,
+ void WillReleaseScriptContext(v8::Local<v8::Context> context,
int world_id) override;
void DidFinishDocumentLoad() override;
+ // MainFrameObserver is inline owned by WebUIMojo and should not be
+ // destroyed when the main RenderFrame is deleted. Overriding the
+ // OnDestruct method allows this object to remain alive and be cleaned
+ // up as part of WebUIMojo deletion.
+ void OnDestruct() override;
private:
WebUIMojo* web_ui_mojo_;
@@ -50,7 +55,7 @@ class WebUIMojo
~WebUIMojo() override;
void CreateContextState();
- void DestroyContextState(v8::Handle<v8::Context> context);
+ void DestroyContextState(v8::Local<v8::Context> context);
// Invoked when the frame finishes loading. Invokes Run() on the
// WebUIMojoContextState.
diff --git a/chromium/content/renderer/web_ui_mojo_context_state.cc b/chromium/content/renderer/web_ui_mojo_context_state.cc
index ac13448cd30..cb75e907e51 100644
--- a/chromium/content/renderer/web_ui_mojo_context_state.cc
+++ b/chromium/content/renderer/web_ui_mojo_context_state.cc
@@ -34,9 +34,9 @@ namespace {
const char kModulePrefix[] = "chrome://mojo/";
void RunMain(base::WeakPtr<gin::Runner> runner,
- v8::Handle<v8::Value> module) {
+ v8::Local<v8::Value> module) {
v8::Isolate* isolate = runner->GetContextHolder()->isolate();
- v8::Handle<v8::Function> start;
+ v8::Local<v8::Function> start;
CHECK(gin::ConvertFromV8(isolate, module, &start));
runner->Call(start, runner->global(), 0, NULL);
}
@@ -46,7 +46,7 @@ void RunMain(base::WeakPtr<gin::Runner> runner,
// WebUIMojo -------------------------------------------------------------------
WebUIMojoContextState::WebUIMojoContextState(blink::WebFrame* frame,
- v8::Handle<v8::Context> context)
+ v8::Local<v8::Context> context)
: frame_(frame),
module_added_(false) {
gin::PerContextData* context_data = gin::PerContextData::From(context);
diff --git a/chromium/content/renderer/web_ui_mojo_context_state.h b/chromium/content/renderer/web_ui_mojo_context_state.h
index e8879afa5e8..4aa12e51532 100644
--- a/chromium/content/renderer/web_ui_mojo_context_state.h
+++ b/chromium/content/renderer/web_ui_mojo_context_state.h
@@ -34,7 +34,7 @@ class WebUIRunner;
class WebUIMojoContextState : public gin::ModuleRegistryObserver {
public:
WebUIMojoContextState(blink::WebFrame* frame,
- v8::Handle<v8::Context> context);
+ v8::Local<v8::Context> context);
~WebUIMojoContextState() override;
void Run();
diff --git a/chromium/content/renderer/web_ui_runner.cc b/chromium/content/renderer/web_ui_runner.cc
index 5d6f05cc66a..f1d0cce17c1 100644
--- a/chromium/content/renderer/web_ui_runner.cc
+++ b/chromium/content/renderer/web_ui_runner.cc
@@ -41,10 +41,10 @@ void WebUIRunner::Run(const std::string& source,
blink::WebScriptSource(blink::WebString::fromUTF8(source)));
}
-v8::Handle<v8::Value> WebUIRunner::Call(v8::Handle<v8::Function> function,
- v8::Handle<v8::Value> receiver,
+v8::Local<v8::Value> WebUIRunner::Call(v8::Local<v8::Function> function,
+ v8::Local<v8::Value> receiver,
int argc,
- v8::Handle<v8::Value> argv[]) {
+ v8::Local<v8::Value> argv[]) {
return frame_->callFunctionEvenIfScriptDisabled(function, receiver, argc,
argv);
}
diff --git a/chromium/content/renderer/web_ui_runner.h b/chromium/content/renderer/web_ui_runner.h
index 2f17ab59deb..3778a423f23 100644
--- a/chromium/content/renderer/web_ui_runner.h
+++ b/chromium/content/renderer/web_ui_runner.h
@@ -23,10 +23,10 @@ class WebUIRunner : public gin::Runner {
// Runner overrides:
void Run(const std::string& source,
const std::string& resource_name) override;
- v8::Handle<v8::Value> Call(v8::Handle<v8::Function> function,
- v8::Handle<v8::Value> receiver,
+ v8::Local<v8::Value> Call(v8::Local<v8::Function> function,
+ v8::Local<v8::Value> receiver,
int argc,
- v8::Handle<v8::Value> argv[]) override;
+ v8::Local<v8::Value> argv[]) override;
gin::ContextHolder* GetContextHolder() override;
private:
diff --git a/chromium/content/renderer/webclipboard_impl.cc b/chromium/content/renderer/webclipboard_impl.cc
index e248c517a06..19f2362b1c0 100644
--- a/chromium/content/renderer/webclipboard_impl.cc
+++ b/chromium/content/renderer/webclipboard_impl.cc
@@ -5,14 +5,13 @@
#include "content/renderer/webclipboard_impl.h"
#include "base/logging.h"
-#include "base/pickle.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "content/common/clipboard_format.h"
#include "content/public/common/drop_data.h"
#include "content/renderer/clipboard_utils.h"
#include "content/renderer/drop_data_builder.h"
-#include "content/renderer/scoped_clipboard_writer_glue.h"
+#include "content/renderer/renderer_clipboard_delegate.h"
#include "third_party/WebKit/public/platform/WebData.h"
#include "third_party/WebKit/public/platform/WebDragData.h"
#include "third_party/WebKit/public/platform/WebImage.h"
@@ -20,9 +19,6 @@
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/platform/WebURL.h"
#include "third_party/WebKit/public/platform/WebVector.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/base/clipboard/clipboard.h"
-#include "ui/base/clipboard/custom_data_helper.h"
#include "url/gurl.h"
using blink::WebClipboard;
@@ -35,8 +31,9 @@ using blink::WebVector;
namespace content {
-WebClipboardImpl::WebClipboardImpl(ClipboardClient* client)
- : client_(client) {
+WebClipboardImpl::WebClipboardImpl(RendererClipboardDelegate* delegate)
+ : delegate_(delegate) {
+ DCHECK(delegate);
}
WebClipboardImpl::~WebClipboardImpl() {
@@ -47,7 +44,7 @@ uint64 WebClipboardImpl::sequenceNumber(Buffer buffer) {
if (!ConvertBufferType(buffer, &clipboard_type))
return 0;
- return client_->GetSequenceNumber(clipboard_type);
+ return delegate_->GetSequenceNumber(clipboard_type);
}
bool WebClipboardImpl::isFormatAvailable(Format format, Buffer buffer) {
@@ -58,16 +55,17 @@ bool WebClipboardImpl::isFormatAvailable(Format format, Buffer buffer) {
switch (format) {
case FormatPlainText:
- return client_->IsFormatAvailable(CLIPBOARD_FORMAT_PLAINTEXT,
- clipboard_type);
+ return delegate_->IsFormatAvailable(CLIPBOARD_FORMAT_PLAINTEXT,
+ clipboard_type);
case FormatHTML:
- return client_->IsFormatAvailable(CLIPBOARD_FORMAT_HTML, clipboard_type);
+ return delegate_->IsFormatAvailable(CLIPBOARD_FORMAT_HTML,
+ clipboard_type);
case FormatSmartPaste:
- return client_->IsFormatAvailable(CLIPBOARD_FORMAT_SMART_PASTE,
- clipboard_type);
+ return delegate_->IsFormatAvailable(CLIPBOARD_FORMAT_SMART_PASTE,
+ clipboard_type);
case FormatBookmark:
- return client_->IsFormatAvailable(CLIPBOARD_FORMAT_BOOKMARK,
- clipboard_type);
+ return delegate_->IsFormatAvailable(CLIPBOARD_FORMAT_BOOKMARK,
+ clipboard_type);
default:
NOTREACHED();
}
@@ -80,7 +78,7 @@ WebVector<WebString> WebClipboardImpl::readAvailableTypes(
ui::ClipboardType clipboard_type;
std::vector<base::string16> types;
if (ConvertBufferType(buffer, &clipboard_type)) {
- client_->ReadAvailableTypes(clipboard_type, &types, contains_filenames);
+ delegate_->ReadAvailableTypes(clipboard_type, &types, contains_filenames);
}
return types;
}
@@ -91,7 +89,7 @@ WebString WebClipboardImpl::readPlainText(Buffer buffer) {
return WebString();
base::string16 text;
- client_->ReadText(clipboard_type, &text);
+ delegate_->ReadText(clipboard_type, &text);
return text;
}
@@ -104,9 +102,9 @@ WebString WebClipboardImpl::readHTML(Buffer buffer, WebURL* source_url,
base::string16 html_stdstr;
GURL gurl;
- client_->ReadHTML(clipboard_type, &html_stdstr, &gurl,
- static_cast<uint32*>(fragment_start),
- static_cast<uint32*>(fragment_end));
+ delegate_->ReadHTML(clipboard_type, &html_stdstr, &gurl,
+ static_cast<uint32*>(fragment_start),
+ static_cast<uint32*>(fragment_end));
*source_url = gurl;
return html_stdstr;
}
@@ -117,7 +115,7 @@ WebData WebClipboardImpl::readImage(Buffer buffer) {
return WebData();
std::string png_data;
- client_->ReadImage(clipboard_type, &png_data);
+ delegate_->ReadImage(clipboard_type, &png_data);
return WebData(png_data);
}
@@ -128,46 +126,36 @@ WebString WebClipboardImpl::readCustomData(Buffer buffer,
return WebString();
base::string16 data;
- client_->ReadCustomData(clipboard_type, type, &data);
+ delegate_->ReadCustomData(clipboard_type, type, &data);
return data;
}
void WebClipboardImpl::writePlainText(const WebString& plain_text) {
- ScopedClipboardWriterGlue scw(client_);
- scw.WriteText(plain_text);
+ delegate_->WriteText(ui::CLIPBOARD_TYPE_COPY_PASTE, plain_text);
+ delegate_->CommitWrite(ui::CLIPBOARD_TYPE_COPY_PASTE);
}
void WebClipboardImpl::writeHTML(
const WebString& html_text, const WebURL& source_url,
const WebString& plain_text, bool write_smart_paste) {
- ScopedClipboardWriterGlue scw(client_);
- scw.WriteHTML(html_text, source_url.spec());
- scw.WriteText(plain_text);
+ delegate_->WriteHTML(ui::CLIPBOARD_TYPE_COPY_PASTE, html_text, source_url);
+ delegate_->WriteText(ui::CLIPBOARD_TYPE_COPY_PASTE, plain_text);
if (write_smart_paste)
- scw.WriteWebSmartPaste();
+ delegate_->WriteSmartPasteMarker(ui::CLIPBOARD_TYPE_COPY_PASTE);
+ delegate_->CommitWrite(ui::CLIPBOARD_TYPE_COPY_PASTE);
}
void WebClipboardImpl::writeImage(const WebImage& image,
const WebURL& url,
const WebString& title) {
- ScopedClipboardWriterGlue scw(client_);
-
- if (!image.isNull()) {
- const SkBitmap& bitmap = image.getSkBitmap();
- // WriteBitmapFromPixels expects 32-bit data.
- DCHECK_EQ(bitmap.colorType(), kN32_SkColorType);
-
- SkAutoLockPixels locked(bitmap);
- void *pixels = bitmap.getPixels();
- // TODO(piman): this should not be NULL, but it is. crbug.com/369621
- if (!pixels)
- return;
- scw.WriteBitmapFromPixels(pixels, image.size());
- }
+ DCHECK(!image.isNull());
+ const SkBitmap& bitmap = image.getSkBitmap();
+ if (!delegate_->WriteImage(ui::CLIPBOARD_TYPE_COPY_PASTE, bitmap))
+ return;
if (!url.isEmpty()) {
- scw.WriteBookmark(title, url.spec());
+ delegate_->WriteBookmark(ui::CLIPBOARD_TYPE_COPY_PASTE, url, title);
#if !defined(OS_MACOSX)
// When writing the image, we also write the image markup so that pasting
// into rich text editors, such as Gmail, reveals the image. We also don't
@@ -176,31 +164,30 @@ void WebClipboardImpl::writeImage(const WebImage& image,
// We also don't want to write HTML on a Mac, since Mail.app prefers to use
// the image markup over attaching the actual image. See
// http://crbug.com/33016 for details.
- scw.WriteHTML(base::UTF8ToUTF16(URLToImageMarkup(url, title)),
- std::string());
+ delegate_->WriteHTML(ui::CLIPBOARD_TYPE_COPY_PASTE,
+ base::UTF8ToUTF16(URLToImageMarkup(url, title)),
+ GURL());
#endif
}
+ delegate_->CommitWrite(ui::CLIPBOARD_TYPE_COPY_PASTE);
}
void WebClipboardImpl::writeDataObject(const WebDragData& data) {
- ScopedClipboardWriterGlue scw(client_);
-
const DropData& data_object = DropDataBuilder::Build(data);
// TODO(dcheng): Properly support text/uri-list here.
+ // Avoid calling the WriteFoo functions if there is no data associated with a
+ // type. This prevents stomping on clipboard contents that might have been
+ // written by extension functions such as chrome.bookmarkManagerPrivate.copy.
if (!data_object.text.is_null())
- scw.WriteText(data_object.text.string());
+ delegate_->WriteText(ui::CLIPBOARD_TYPE_COPY_PASTE,
+ data_object.text.string());
if (!data_object.html.is_null())
- scw.WriteHTML(data_object.html.string(), std::string());
- // If there is no custom data, avoid calling WritePickledData. This ensures
- // that ScopedClipboardWriterGlue's dtor remains a no-op if the page didn't
- // modify the DataTransfer object, which is important to avoid stomping on
- // any clipboard contents written by extension functions such as
- // chrome.bookmarkManagerPrivate.copy.
- if (!data_object.custom_data.empty()) {
- Pickle pickle;
- ui::WriteCustomDataToPickle(data_object.custom_data, &pickle);
- scw.WritePickledData(pickle, ui::Clipboard::GetWebCustomDataFormatType());
- }
+ delegate_->WriteHTML(ui::CLIPBOARD_TYPE_COPY_PASTE,
+ data_object.html.string(), GURL());
+ if (!data_object.custom_data.empty())
+ delegate_->WriteCustomData(ui::CLIPBOARD_TYPE_COPY_PASTE,
+ data_object.custom_data);
+ delegate_->CommitWrite(ui::CLIPBOARD_TYPE_COPY_PASTE);
}
bool WebClipboardImpl::ConvertBufferType(Buffer buffer,
diff --git a/chromium/content/renderer/webclipboard_impl.h b/chromium/content/renderer/webclipboard_impl.h
index 477f53b08fb..9288546b641 100644
--- a/chromium/content/renderer/webclipboard_impl.h
+++ b/chromium/content/renderer/webclipboard_impl.h
@@ -6,18 +6,17 @@
#define CONTENT_RENDERER_WEBCLIPBOARD_IMPL_H_
#include "base/compiler_specific.h"
-
#include "third_party/WebKit/public/platform/WebClipboard.h"
#include "ui/base/clipboard/clipboard.h"
#include <string>
namespace content {
-class ClipboardClient;
+class RendererClipboardDelegate;
class WebClipboardImpl : public blink::WebClipboard {
public:
- explicit WebClipboardImpl(ClipboardClient* client);
+ explicit WebClipboardImpl(RendererClipboardDelegate* delegate);
virtual ~WebClipboardImpl();
@@ -49,7 +48,7 @@ class WebClipboardImpl : public blink::WebClipboard {
private:
bool ConvertBufferType(Buffer, ui::ClipboardType*);
- ClipboardClient* client_;
+ RendererClipboardDelegate* const delegate_;
};
} // namespace content
diff --git a/chromium/content/renderer/webgraphicscontext3d_provider_impl.cc b/chromium/content/renderer/webgraphicscontext3d_provider_impl.cc
index 7a31a05ceea..855bd3df44d 100644
--- a/chromium/content/renderer/webgraphicscontext3d_provider_impl.cc
+++ b/chromium/content/renderer/webgraphicscontext3d_provider_impl.cc
@@ -4,13 +4,14 @@
#include "content/renderer/webgraphicscontext3d_provider_impl.h"
-#include "webkit/common/gpu/context_provider_web_context.h"
+#include "cc/blink/context_provider_web_context.h"
namespace content {
WebGraphicsContext3DProviderImpl::WebGraphicsContext3DProviderImpl(
- scoped_refptr<webkit::gpu::ContextProviderWebContext> provider)
- : provider_(provider) {}
+ scoped_refptr<cc_blink::ContextProviderWebContext> provider)
+ : provider_(provider) {
+}
WebGraphicsContext3DProviderImpl::~WebGraphicsContext3DProviderImpl() {}
diff --git a/chromium/content/renderer/webgraphicscontext3d_provider_impl.h b/chromium/content/renderer/webgraphicscontext3d_provider_impl.h
index 69c2e984c1f..8225ded4fdf 100644
--- a/chromium/content/renderer/webgraphicscontext3d_provider_impl.h
+++ b/chromium/content/renderer/webgraphicscontext3d_provider_impl.h
@@ -10,11 +10,9 @@
#include "content/common/content_export.h"
#include "third_party/WebKit/public/platform/WebGraphicsContext3DProvider.h"
-namespace webkit {
-namespace gpu {
+namespace cc_blink {
class ContextProviderWebContext;
-} // namespace webkit
-} // namespace gpu
+}
namespace content {
@@ -22,7 +20,7 @@ class CONTENT_EXPORT WebGraphicsContext3DProviderImpl
: public NON_EXPORTED_BASE(blink::WebGraphicsContext3DProvider) {
public:
explicit WebGraphicsContext3DProviderImpl(
- scoped_refptr<webkit::gpu::ContextProviderWebContext> provider);
+ scoped_refptr<cc_blink::ContextProviderWebContext> provider);
virtual ~WebGraphicsContext3DProviderImpl();
// WebGraphicsContext3DProvider implementation.
@@ -30,7 +28,7 @@ class CONTENT_EXPORT WebGraphicsContext3DProviderImpl
virtual GrContext* grContext() override;
private:
- scoped_refptr<webkit::gpu::ContextProviderWebContext> provider_;
+ scoped_refptr<cc_blink::ContextProviderWebContext> provider_;
};
} // namespace content
diff --git a/chromium/content/renderer/webscrollbarbehavior_impl_gtkoraura.h b/chromium/content/renderer/webscrollbarbehavior_impl_gtkoraura.h
index 7d681d37250..30ccb239f37 100644
--- a/chromium/content/renderer/webscrollbarbehavior_impl_gtkoraura.h
+++ b/chromium/content/renderer/webscrollbarbehavior_impl_gtkoraura.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_CHILD_WEBSCROLLBARBEHAVIOR_IMPL_GTKORAURA_H_
-#define CONTENT_CHILD_WEBSCROLLBARBEHAVIOR_IMPL_GTKORAURA_H_
+#ifndef CONTENT_RENDERER_WEBSCROLLBARBEHAVIOR_IMPL_GTKORAURA_H_
+#define CONTENT_RENDERER_WEBSCROLLBARBEHAVIOR_IMPL_GTKORAURA_H_
#include "third_party/WebKit/public/platform/WebScrollbarBehavior.h"
@@ -22,4 +22,4 @@ class WebScrollbarBehaviorImpl : public blink::WebScrollbarBehavior {
} // namespace content
-#endif // CONTENT_CHILD_WEBSCROLLBARBEHAVIOR_IMPL_GTKORAURA_H_
+#endif // CONTENT_RENDERER_WEBSCROLLBARBEHAVIOR_IMPL_GTKORAURA_H_
diff --git a/chromium/content/renderer/webscrollbarbehavior_impl_mac.h b/chromium/content/renderer/webscrollbarbehavior_impl_mac.h
index 56322994878..0163d822eb9 100644
--- a/chromium/content/renderer/webscrollbarbehavior_impl_mac.h
+++ b/chromium/content/renderer/webscrollbarbehavior_impl_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_CHILD_WEBSCROLLBARBEHAVIOR_IMPL_MAC_H_
-#define CONTENT_CHILD_WEBSCROLLBARBEHAVIOR_IMPL_MAC_H_
+#ifndef CONTENT_RENDERER_WEBSCROLLBARBEHAVIOR_IMPL_MAC_H_
+#define CONTENT_RENDERER_WEBSCROLLBARBEHAVIOR_IMPL_MAC_H_
#include "third_party/WebKit/public/platform/WebScrollbarBehavior.h"
@@ -29,4 +29,4 @@ class WebScrollbarBehaviorImpl : public blink::WebScrollbarBehavior {
} // namespace content
-#endif // CONTENT_CHILD_WEBSCROLLBARBEHAVIOR_IMPL_MAC_H_
+#endif // CONTENT_RENDERER_WEBSCROLLBARBEHAVIOR_IMPL_MAC_H_
diff --git a/chromium/content/shell/common/DEPS b/chromium/content/shell/common/DEPS
new file mode 100644
index 00000000000..5f52568085a
--- /dev/null
+++ b/chromium/content/shell/common/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+gin/public",
+]
diff --git a/chromium/content/shell/common/layout_test/layout_test_messages.cc b/chromium/content/shell/common/layout_test/layout_test_messages.cc
new file mode 100644
index 00000000000..afb5b261e86
--- /dev/null
+++ b/chromium/content/shell/common/layout_test/layout_test_messages.cc
@@ -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.
+
+// Get basic type definitions.
+#define IPC_MESSAGE_IMPL
+#include "content/shell/common/layout_test/layout_test_messages.h"
+
+// Generate constructors.
+#include "ipc/struct_constructor_macros.h"
+#include "content/shell/common/layout_test/layout_test_messages.h"
+
+// Generate destructors.
+#include "ipc/struct_destructor_macros.h"
+#include "content/shell/common/layout_test/layout_test_messages.h"
+
+// Generate param traits write methods.
+#include "ipc/param_traits_write_macros.h"
+namespace IPC {
+#include "content/shell/common/layout_test/layout_test_messages.h"
+} // namespace IPC
+
+// Generate param traits read methods.
+#include "ipc/param_traits_read_macros.h"
+namespace IPC {
+#include "content/shell/common/layout_test/layout_test_messages.h"
+} // namespace IPC
+
+// Generate param traits log methods.
+#include "ipc/param_traits_log_macros.h"
+namespace IPC {
+#include "content/shell/common/layout_test/layout_test_messages.h"
+} // namespace IPC
diff --git a/chromium/content/shell/common/layout_test/layout_test_messages.h b/chromium/content/shell/common/layout_test/layout_test_messages.h
new file mode 100644
index 00000000000..7ab85bf19d0
--- /dev/null
+++ b/chromium/content/shell/common/layout_test/layout_test_messages.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.
+
+// Multiply-included file, no traditional include guard.
+#include <string>
+#include <vector>
+
+#include "content/public/common/common_param_traits.h"
+#include "content/public/common/permission_status.mojom.h"
+#include "ipc/ipc_message_macros.h"
+#include "ipc/ipc_platform_file.h"
+#include "url/gurl.h"
+
+#define IPC_MESSAGE_START LayoutTestMsgStart
+
+IPC_ENUM_TRAITS_MIN_MAX_VALUE(content::PermissionStatus,
+ content::PERMISSION_STATUS_GRANTED,
+ content::PERMISSION_STATUS_ASK)
+
+IPC_SYNC_MESSAGE_ROUTED1_1(LayoutTestHostMsg_ReadFileToString,
+ base::FilePath /* local path */,
+ std::string /* contents */)
+IPC_SYNC_MESSAGE_ROUTED1_1(LayoutTestHostMsg_RegisterIsolatedFileSystem,
+ std::vector<base::FilePath> /* absolute_filenames */,
+ std::string /* filesystem_id */)
+IPC_MESSAGE_ROUTED0(LayoutTestHostMsg_ClearAllDatabases)
+IPC_MESSAGE_ROUTED1(LayoutTestHostMsg_SetDatabaseQuota,
+ int /* quota */)
+IPC_MESSAGE_ROUTED1(LayoutTestHostMsg_SimulateWebNotificationClick,
+ std::string /* title */)
+IPC_MESSAGE_ROUTED1(LayoutTestHostMsg_AcceptAllCookies,
+ bool /* accept */)
+IPC_MESSAGE_ROUTED0(LayoutTestHostMsg_DeleteAllCookies)
+IPC_MESSAGE_ROUTED4(LayoutTestHostMsg_SetPermission,
+ std::string /* name */,
+ content::PermissionStatus /* status */,
+ GURL /* origin */,
+ GURL /* embedding_origin */ )
+IPC_MESSAGE_ROUTED0(LayoutTestHostMsg_ResetPermissions)
diff --git a/chromium/content/shell/common/leak_detection_result.h b/chromium/content/shell/common/leak_detection_result.h
new file mode 100644
index 00000000000..873a172a592
--- /dev/null
+++ b/chromium/content/shell/common/leak_detection_result.h
@@ -0,0 +1,19 @@
+// Copyright 2014 The Chromium Authors. 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_SHELL_COMMON_LEAK_DETECTION_RESULT_H_
+#define CONTENT_SHELL_COMMON_LEAK_DETECTION_RESULT_H_
+
+#include <string>
+
+namespace content {
+
+struct LeakDetectionResult {
+ bool leaked;
+ std::string detail;
+};
+
+} // namespace content
+
+#endif // CONTENT_SHELL_COMMON_LEAK_DETECTION_RESULT_H_
diff --git a/chromium/content/shell/common/shell_content_client.cc b/chromium/content/shell/common/shell_content_client.cc
new file mode 100644
index 00000000000..2e420895e28
--- /dev/null
+++ b/chromium/content/shell/common/shell_content_client.cc
@@ -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.
+
+#include "content/shell/common/shell_content_client.h"
+
+#include "base/command_line.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/utf_string_conversions.h"
+#include "blink/public/resources/grit/blink_image_resources.h"
+#include "content/app/resources/grit/content_resources.h"
+#include "content/app/strings/grit/content_strings.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/common/user_agent.h"
+#include "content/shell/common/shell_switches.h"
+#include "grit/shell_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+
+namespace content {
+
+std::string GetShellUserAgent() {
+ std::string product = "Chrome/" CONTENT_SHELL_VERSION;
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch(switches::kUseMobileUserAgent))
+ product += " Mobile";
+ return BuildUserAgentFromProduct(product);
+}
+
+ShellContentClient::~ShellContentClient() {
+}
+
+std::string ShellContentClient::GetUserAgent() const {
+ return GetShellUserAgent();
+}
+
+base::string16 ShellContentClient::GetLocalizedString(int message_id) const {
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kRunLayoutTest)) {
+ switch (message_id) {
+ case IDS_FORM_OTHER_DATE_LABEL:
+ return base::ASCIIToUTF16("<<OtherDateLabel>>");
+ case IDS_FORM_OTHER_MONTH_LABEL:
+ return base::ASCIIToUTF16("<<OtherMonthLabel>>");
+ case IDS_FORM_OTHER_TIME_LABEL:
+ return base::ASCIIToUTF16("<<OtherTimeLabel>>");
+ case IDS_FORM_OTHER_WEEK_LABEL:
+ return base::ASCIIToUTF16("<<OtherWeekLabel>>");
+ case IDS_FORM_CALENDAR_CLEAR:
+ return base::ASCIIToUTF16("<<CalendarClear>>");
+ case IDS_FORM_CALENDAR_TODAY:
+ return base::ASCIIToUTF16("<<CalendarToday>>");
+ case IDS_FORM_THIS_MONTH_LABEL:
+ return base::ASCIIToUTF16("<<ThisMonthLabel>>");
+ case IDS_FORM_THIS_WEEK_LABEL:
+ return base::ASCIIToUTF16("<<ThisWeekLabel>>");
+ }
+ }
+ return l10n_util::GetStringUTF16(message_id);
+}
+
+base::StringPiece ShellContentClient::GetDataResource(
+ int resource_id,
+ ui::ScaleFactor scale_factor) const {
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kRunLayoutTest)) {
+ switch (resource_id) {
+ case IDR_BROKENIMAGE:
+#if defined(OS_MACOSX)
+ resource_id = IDR_CONTENT_SHELL_MISSING_IMAGE_PNG;
+#else
+ resource_id = IDR_CONTENT_SHELL_MISSING_IMAGE_GIF;
+#endif
+ break;
+
+ case IDR_TEXTAREA_RESIZER:
+ resource_id = IDR_CONTENT_SHELL_TEXT_AREA_RESIZE_CORNER_PNG;
+ break;
+ }
+ }
+ return ResourceBundle::GetSharedInstance().GetRawDataResourceForScale(
+ resource_id, scale_factor);
+}
+
+base::RefCountedStaticMemory* ShellContentClient::GetDataResourceBytes(
+ int resource_id) const {
+ return ResourceBundle::GetSharedInstance().LoadDataResourceBytes(resource_id);
+}
+
+gfx::Image& ShellContentClient::GetNativeImageNamed(int resource_id) const {
+ return ResourceBundle::GetSharedInstance().GetNativeImageNamed(resource_id);
+}
+
+} // namespace content
diff --git a/chromium/content/shell/common/shell_content_client.h b/chromium/content/shell/common/shell_content_client.h
new file mode 100644
index 00000000000..9ea4fb5b729
--- /dev/null
+++ b/chromium/content/shell/common/shell_content_client.h
@@ -0,0 +1,34 @@
+// 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_SHELL_COMMON_SHELL_CONTENT_CLIENT_H_
+#define CONTENT_SHELL_COMMON_SHELL_CONTENT_CLIENT_H_
+
+#include <string>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "content/public/common/content_client.h"
+
+namespace content {
+
+std::string GetShellUserAgent();
+
+class ShellContentClient : public ContentClient {
+ public:
+ ~ShellContentClient() override;
+
+ std::string GetUserAgent() const override;
+ base::string16 GetLocalizedString(int message_id) const override;
+ base::StringPiece GetDataResource(
+ int resource_id,
+ ui::ScaleFactor scale_factor) const override;
+ base::RefCountedStaticMemory* GetDataResourceBytes(
+ int resource_id) const override;
+ gfx::Image& GetNativeImageNamed(int resource_id) const override;
+};
+
+} // namespace content
+
+#endif // CONTENT_SHELL_COMMON_SHELL_CONTENT_CLIENT_H_
diff --git a/chromium/content/shell/common/shell_messages.cc b/chromium/content/shell/common/shell_messages.cc
new file mode 100644
index 00000000000..3eae912b154
--- /dev/null
+++ b/chromium/content/shell/common/shell_messages.cc
@@ -0,0 +1,33 @@
+// 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.
+
+// Get basic type definitions.
+#define IPC_MESSAGE_IMPL
+#include "content/shell/common/shell_messages.h"
+
+// Generate constructors.
+#include "ipc/struct_constructor_macros.h"
+#include "content/shell/common/shell_messages.h"
+
+// Generate destructors.
+#include "ipc/struct_destructor_macros.h"
+#include "content/shell/common/shell_messages.h"
+
+// Generate param traits write methods.
+#include "ipc/param_traits_write_macros.h"
+namespace IPC {
+#include "content/shell/common/shell_messages.h"
+} // namespace IPC
+
+// Generate param traits read methods.
+#include "ipc/param_traits_read_macros.h"
+namespace IPC {
+#include "content/shell/common/shell_messages.h"
+} // namespace IPC
+
+// Generate param traits log methods.
+#include "ipc/param_traits_log_macros.h"
+namespace IPC {
+#include "content/shell/common/shell_messages.h"
+} // namespace IPC
diff --git a/chromium/content/shell/common/shell_messages.h b/chromium/content/shell/common/shell_messages.h
new file mode 100644
index 00000000000..5c0cad838d8
--- /dev/null
+++ b/chromium/content/shell/common/shell_messages.h
@@ -0,0 +1,111 @@
+// 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.
+
+// Multiply-included file, no traditional include guard.
+#include <string>
+#include <vector>
+
+#include "content/public/common/common_param_traits.h"
+#include "content/public/common/page_state.h"
+#include "content/shell/common/leak_detection_result.h"
+#include "content/shell/common/shell_test_configuration.h"
+#include "ipc/ipc_message_macros.h"
+#include "ipc/ipc_platform_file.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/ipc/gfx_param_traits.h"
+
+#define IPC_MESSAGE_START ShellMsgStart
+
+IPC_STRUCT_TRAITS_BEGIN(content::ShellTestConfiguration)
+IPC_STRUCT_TRAITS_MEMBER(current_working_directory)
+IPC_STRUCT_TRAITS_MEMBER(temp_path)
+IPC_STRUCT_TRAITS_MEMBER(test_url)
+IPC_STRUCT_TRAITS_MEMBER(enable_pixel_dumping)
+IPC_STRUCT_TRAITS_MEMBER(allow_external_pages)
+IPC_STRUCT_TRAITS_MEMBER(expected_pixel_hash)
+IPC_STRUCT_TRAITS_MEMBER(initial_size)
+IPC_STRUCT_TRAITS_END()
+
+// Tells the renderer to reset all test runners.
+IPC_MESSAGE_ROUTED0(ShellViewMsg_Reset)
+
+// Sets the path to the WebKit checkout.
+IPC_MESSAGE_CONTROL1(ShellViewMsg_SetWebKitSourceDir,
+ base::FilePath /* webkit source dir */)
+
+// Sets the initial configuration to use for layout tests.
+IPC_MESSAGE_ROUTED1(ShellViewMsg_SetTestConfiguration,
+ content::ShellTestConfiguration)
+
+// Tells the main window that a secondary window in a different process invoked
+// notifyDone().
+IPC_MESSAGE_ROUTED0(ShellViewMsg_NotifyDone)
+
+// Pushes a snapshot of the current session history from the browser process.
+// This includes only information about those RenderViews that are in the
+// same process as the main window of the layout test and that are the current
+// active RenderView of their WebContents.
+IPC_MESSAGE_ROUTED3(
+ ShellViewMsg_SessionHistory,
+ std::vector<int> /* routing_ids */,
+ std::vector<std::vector<content::PageState> > /* session_histories */,
+ std::vector<unsigned> /* current_entry_indexes */)
+
+IPC_MESSAGE_ROUTED0(ShellViewMsg_TryLeakDetection)
+
+// Send a text dump of the WebContents to the render host.
+IPC_MESSAGE_ROUTED1(ShellViewHostMsg_TextDump,
+ std::string /* dump */)
+
+// Send an image dump of the WebContents to the render host.
+IPC_MESSAGE_ROUTED2(ShellViewHostMsg_ImageDump,
+ std::string /* actual pixel hash */,
+ SkBitmap /* image */)
+
+// Send an audio dump to the render host.
+IPC_MESSAGE_ROUTED1(ShellViewHostMsg_AudioDump,
+ std::vector<unsigned char> /* audio data */)
+
+IPC_MESSAGE_ROUTED0(ShellViewHostMsg_TestFinished)
+
+IPC_MESSAGE_ROUTED0(ShellViewHostMsg_ResetDone)
+
+IPC_MESSAGE_ROUTED0(ShellViewHostMsg_TestFinishedInSecondaryWindow)
+
+// WebTestDelegate related.
+IPC_MESSAGE_ROUTED1(ShellViewHostMsg_OverridePreferences,
+ content::WebPreferences /* preferences */)
+IPC_MESSAGE_ROUTED1(ShellViewHostMsg_PrintMessage,
+ std::string /* message */)
+IPC_MESSAGE_ROUTED0(ShellViewHostMsg_ClearDevToolsLocalStorage)
+IPC_MESSAGE_ROUTED2(ShellViewHostMsg_ShowDevTools,
+ std::string /* settings */,
+ std::string /* frontend_url */)
+IPC_MESSAGE_ROUTED0(ShellViewHostMsg_CloseDevTools)
+IPC_MESSAGE_ROUTED1(ShellViewHostMsg_GoToOffset,
+ int /* offset */)
+IPC_MESSAGE_ROUTED0(ShellViewHostMsg_Reload)
+IPC_MESSAGE_ROUTED2(ShellViewHostMsg_LoadURLForFrame,
+ GURL /* url */,
+ std::string /* frame_name */)
+IPC_MESSAGE_ROUTED1(ShellViewHostMsg_SetDeviceScaleFactor,
+ float /* factor */)
+IPC_MESSAGE_ROUTED0(ShellViewHostMsg_CaptureSessionHistory)
+IPC_MESSAGE_ROUTED0(ShellViewHostMsg_CloseRemainingWindows)
+
+IPC_MESSAGE_CONTROL3(ShellViewHostMsg_EchoPing,
+ int /* routing_id */,
+ int /* id */,
+ std::string /* body */)
+IPC_MESSAGE_ROUTED2(ShellViewMsg_EchoPong,
+ int /* id */,
+ std::string /* body */)
+
+IPC_STRUCT_TRAITS_BEGIN(content::LeakDetectionResult)
+IPC_STRUCT_TRAITS_MEMBER(leaked)
+IPC_STRUCT_TRAITS_MEMBER(detail)
+IPC_STRUCT_TRAITS_END()
+
+IPC_MESSAGE_ROUTED1(ShellViewHostMsg_LeakDetectionDone,
+ content::LeakDetectionResult /* result */)
diff --git a/chromium/content/shell/common/shell_switches.cc b/chromium/content/shell/common/shell_switches.cc
new file mode 100644
index 00000000000..d2f0a2942ca
--- /dev/null
+++ b/chromium/content/shell/common/shell_switches.cc
@@ -0,0 +1,71 @@
+// 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/shell/common/shell_switches.h"
+
+namespace switches {
+
+// Allow access to external pages during layout tests.
+const char kAllowExternalPages[] = "allow-external-pages";
+
+// Check whether all system dependencies for running layout tests are met.
+const char kCheckLayoutTestSysDeps[] = "check-layout-test-sys-deps";
+
+// Tells Content Shell that it's running as a content_browsertest.
+const char kContentBrowserTest[] = "browser-test";
+
+// Makes Content Shell use the given path for its data directory.
+const char kContentShellDataPath[] = "data-path";
+
+// The directory breakpad should store minidumps in.
+const char kCrashDumpsDir[] = "crash-dumps-dir";
+
+// When specified to "enable-leak-detection" command-line option,
+// causes the leak detector to cause immediate crash when found leak.
+const char kCrashOnFailure[] = "crash-on-failure";
+
+// Request the render trees of pages to be dumped as text once they have
+// finished loading. Note that this switch has been deprecated, and the
+// identically functioning |kRunLayoutTest| switch should be used instead.
+const char kDumpRenderTree[] = "dump-render-tree";
+
+// Expose window.ipcTester object for testing
+const char kExposeIpcEcho[] = "expose-ipc-echo";
+
+// Enable accelerated 2D canvas.
+const char kEnableAccelerated2DCanvas[] = "enable-accelerated-2d-canvas";
+
+// Enable font antialiasing for pixel tests.
+const char kEnableFontAntialiasing[] = "enable-font-antialiasing";
+
+// Enables the leak detection of loading webpages. This allows us to check
+// whether or not reloading a webpage releases web-related objects correctly.
+const char kEnableLeakDetection[] = "enable-leak-detection";
+
+// Encode binary layout test results (images, audio) using base64.
+const char kEncodeBinary[] = "encode-binary";
+
+// Exposes the window.internals object to JavaScript for interactive development
+// and debugging of layout tests that rely on it.
+const char kExposeInternalsForTesting[] = "expose-internals-for-testing";
+
+// Registers additional font files on Windows (for fonts outside the usual
+// %WINDIR%\Fonts location). Multiple files can be used by separating them
+// with a semicolon (;).
+const char kRegisterFontFiles[] = "register-font-files";
+
+// Request the render trees of pages to be dumped as text once they have
+// finished loading.
+const char kRunLayoutTest[] = "run-layout-test";
+
+// This makes us disable some web-platform runtime features so that we test
+// content_shell as if it was a stable release. It is only followed when
+// kRunLayoutTest is set. For the features' level, see
+// http://dev.chromium.org/blink/runtime-enabled-features.
+const char kStableReleaseMode[] = "stable-release-mode";
+
+// Size for the content_shell's host window (i.e. "800x600").
+const char kContentShellHostWindowSize[] = "content-shell-host-window-size";
+
+} // namespace switches
diff --git a/chromium/content/shell/common/shell_switches.h b/chromium/content/shell/common/shell_switches.h
new file mode 100644
index 00000000000..8ebbc98f8d7
--- /dev/null
+++ b/chromium/content/shell/common/shell_switches.h
@@ -0,0 +1,32 @@
+// 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.
+
+// Defines all the "content_shell" command-line switches.
+
+#ifndef CONTENT_SHELL_COMMON_SHELL_SWITCHES_H_
+#define CONTENT_SHELL_COMMON_SHELL_SWITCHES_H_
+
+namespace switches {
+
+extern const char kAllowExternalPages[];
+extern const char kCheckLayoutTestSysDeps[];
+extern const char kContentBrowserTest[];
+extern const char kContentShellDataPath[];
+extern const char kCrashDumpsDir[];
+extern const char kCrashOnFailure[];
+extern const char kDumpRenderTree[];
+extern const char kExposeIpcEcho[];
+extern const char kEnableAccelerated2DCanvas[];
+extern const char kEnableFontAntialiasing[];
+extern const char kEnableLeakDetection[];
+extern const char kEncodeBinary[];
+extern const char kExposeInternalsForTesting[];
+extern const char kRegisterFontFiles[];
+extern const char kRunLayoutTest[];
+extern const char kStableReleaseMode[];
+extern const char kContentShellHostWindowSize[];
+
+} // namespace switches
+
+#endif // CONTENT_SHELL_COMMON_SHELL_SWITCHES_H_
diff --git a/chromium/content/shell/common/shell_test_configuration.cc b/chromium/content/shell/common/shell_test_configuration.cc
new file mode 100644
index 00000000000..979adb63e90
--- /dev/null
+++ b/chromium/content/shell/common/shell_test_configuration.cc
@@ -0,0 +1,15 @@
+// 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/shell/common/shell_test_configuration.h"
+
+namespace content {
+
+ShellTestConfiguration::ShellTestConfiguration()
+ : enable_pixel_dumping(true),
+ allow_external_pages(false) {}
+
+ShellTestConfiguration::~ShellTestConfiguration() {}
+
+} // namespace content
diff --git a/chromium/content/shell/common/shell_test_configuration.h b/chromium/content/shell/common/shell_test_configuration.h
new file mode 100644
index 00000000000..74b5d0b2127
--- /dev/null
+++ b/chromium/content/shell/common/shell_test_configuration.h
@@ -0,0 +1,44 @@
+// 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_SHELL_COMMON_SHELL_TEST_CONFIGURATION_H_
+#define CONTENT_SHELL_COMMON_SHELL_TEST_CONFIGURATION_H_
+
+#include <string>
+
+#include "base/files/file_path.h"
+#include "ui/gfx/geometry/size.h"
+#include "url/gurl.h"
+
+namespace content {
+
+struct ShellTestConfiguration {
+ ShellTestConfiguration();
+ ~ShellTestConfiguration();
+
+ // The current working directory.
+ base::FilePath current_working_directory;
+
+ // The temporary directory of the system.
+ base::FilePath temp_path;
+
+ // The URL of the current layout test.
+ GURL test_url;
+
+ // True if pixel tests are enabled.
+ bool enable_pixel_dumping;
+
+ // True if tests can open external URLs
+ bool allow_external_pages;
+
+ // The expected MD5 hash of the pixel results.
+ std::string expected_pixel_hash;
+
+ // The initial size of the test window.
+ gfx::Size initial_size;
+};
+
+} // namespace content
+
+#endif // CONTENT_SHELL_COMMON_SHELL_TEST_CONFIGURATION_H_
diff --git a/chromium/content/shell/common/test_runner/OWNERS b/chromium/content/shell/common/test_runner/OWNERS
new file mode 100644
index 00000000000..d574f9abf5d
--- /dev/null
+++ b/chromium/content/shell/common/test_runner/OWNERS
@@ -0,0 +1,6 @@
+abarth@chromium.org
+dmazzoni@chromium.org
+dpranke@chromium.org
+pfeldman@chromium.org
+tkent@chromium.org
+tommyw@chromium.org
diff --git a/chromium/content/shell/common/test_runner/test_preferences.cc b/chromium/content/shell/common/test_runner/test_preferences.cc
new file mode 100644
index 00000000000..e87d1e785fa
--- /dev/null
+++ b/chromium/content/shell/common/test_runner/test_preferences.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/shell/common/test_runner/test_preferences.h"
+
+#include "build/build_config.h"
+
+using blink::WebSettings;
+using blink::WebString;
+
+namespace content {
+
+TestPreferences::TestPreferences() { Reset(); }
+
+void TestPreferences::Reset() {
+ default_font_size = 16;
+ minimum_font_size = 0;
+ dom_paste_allowed = true;
+ xss_auditor_enabled = false;
+ allow_display_of_insecure_content = true;
+ allow_file_access_from_file_urls = true;
+ allow_running_of_insecure_content = true;
+ default_text_encoding_name = WebString::fromUTF8("ISO-8859-1");
+ experimental_webgl_enabled = false;
+ experimental_css_regions_enabled = true;
+ experimental_css_grid_layout_enabled = true;
+ java_enabled = false;
+ java_script_can_access_clipboard = true;
+ java_script_can_open_windows_automatically = true;
+ supports_multiple_windows = true;
+ java_script_enabled = true;
+ loads_images_automatically = true;
+ offline_web_application_cache_enabled = true;
+ plugins_enabled = true;
+ caret_browsing_enabled = false;
+
+ // Allow those layout tests running as local files, i.e. under
+ // LayoutTests/http/tests/local, to access http server.
+ allow_universal_access_from_file_urls = true;
+
+#if defined(OS_MACOSX)
+ editing_behavior = WebSettings::EditingBehaviorMac;
+#else
+ editing_behavior = WebSettings::EditingBehaviorWin;
+#endif
+
+ tabs_to_links = false;
+ hyperlink_auditing_enabled = false;
+ should_respect_image_orientation = false;
+ asynchronous_spell_checking_enabled = false;
+ web_security_enabled = true;
+ disable_reading_from_canvas = false;
+ strict_mixed_content_checking = false;
+ strict_powerful_feature_restrictions = false;
+}
+
+} // namespace content
diff --git a/chromium/content/shell/common/test_runner/test_preferences.h b/chromium/content/shell/common/test_runner/test_preferences.h
new file mode 100644
index 00000000000..ef4c90dcd3c
--- /dev/null
+++ b/chromium/content/shell/common/test_runner/test_preferences.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_SHELL_COMMON_TEST_RUNNER_TEST_PREFERENCES_H_
+#define CONTENT_SHELL_COMMON_TEST_RUNNER_TEST_PREFERENCES_H_
+
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/platform/WebURL.h"
+#include "third_party/WebKit/public/web/WebSettings.h"
+
+namespace blink {
+class WebView;
+}
+
+namespace content {
+
+struct TestPreferences {
+ int default_font_size;
+ int minimum_font_size;
+ bool dom_paste_allowed;
+ bool xss_auditor_enabled;
+ bool allow_display_of_insecure_content;
+ bool allow_file_access_from_file_urls;
+ bool allow_running_of_insecure_content;
+ bool author_and_user_styles_enabled;
+ blink::WebString default_text_encoding_name;
+ bool experimental_webgl_enabled;
+ bool experimental_css_regions_enabled;
+ bool experimental_css_grid_layout_enabled;
+ bool java_enabled;
+ bool java_script_can_access_clipboard;
+ bool java_script_can_open_windows_automatically;
+ bool supports_multiple_windows;
+ bool java_script_enabled;
+ bool loads_images_automatically;
+ bool offline_web_application_cache_enabled;
+ bool plugins_enabled;
+ bool allow_universal_access_from_file_urls;
+ blink::WebSettings::EditingBehavior editing_behavior;
+ bool tabs_to_links;
+ bool hyperlink_auditing_enabled;
+ bool caret_browsing_enabled;
+ bool should_respect_image_orientation;
+ bool asynchronous_spell_checking_enabled;
+ bool web_security_enabled;
+ bool disable_reading_from_canvas;
+ bool strict_mixed_content_checking;
+ bool strict_powerful_feature_restrictions;
+
+ TestPreferences();
+ void Reset();
+};
+
+}
+
+#endif // CONTENT_SHELL_COMMON_TEST_RUNNER_TEST_PREFERENCES_H_
diff --git a/chromium/content/shell/common/v8_breakpad_support_win.cc b/chromium/content/shell/common/v8_breakpad_support_win.cc
new file mode 100644
index 00000000000..584b3ad1868
--- /dev/null
+++ b/chromium/content/shell/common/v8_breakpad_support_win.cc
@@ -0,0 +1,32 @@
+// 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/shell/common/v8_breakpad_support_win.h"
+
+#include <windows.h>
+
+#include "base/logging.h"
+#include "gin/public/debug.h"
+
+namespace v8_breakpad_support {
+
+void SetUp() {
+#ifdef _WIN64
+ // Get the breakpad pointer from content_shell.exe
+ gin::Debug::CodeRangeCreatedCallback create_callback =
+ reinterpret_cast<gin::Debug::CodeRangeCreatedCallback>(
+ ::GetProcAddress(::GetModuleHandle(L"content_shell.exe"),
+ "RegisterNonABICompliantCodeRange"));
+ gin::Debug::CodeRangeDeletedCallback delete_callback =
+ reinterpret_cast<gin::Debug::CodeRangeDeletedCallback>(
+ ::GetProcAddress(::GetModuleHandle(L"content_shell.exe"),
+ "UnregisterNonABICompliantCodeRange"));
+ if (create_callback && delete_callback) {
+ gin::Debug::SetCodeRangeCreatedCallback(create_callback);
+ gin::Debug::SetCodeRangeDeletedCallback(delete_callback);
+ }
+#endif
+}
+
+} // namespace v8_breakpad_support
diff --git a/chromium/content/shell/common/v8_breakpad_support_win.h b/chromium/content/shell/common/v8_breakpad_support_win.h
new file mode 100644
index 00000000000..a10f34a49db
--- /dev/null
+++ b/chromium/content/shell/common/v8_breakpad_support_win.h
@@ -0,0 +1,15 @@
+// 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_SHELL_COMMON_V8_BREAKPAD_SUPPORT_WIN_H_
+#define CONTENT_SHELL_COMMON_V8_BREAKPAD_SUPPORT_WIN_H_
+
+namespace v8_breakpad_support {
+
+// Hook up V8 to breakpad.
+void SetUp();
+
+} // namespace v8_breakpad_support
+
+#endif // CONTENT_SHELL_COMMON_V8_BREAKPAD_SUPPORT_WIN_H_
diff --git a/chromium/content/utility/BUILD.gn b/chromium/content/utility/BUILD.gn
index 5a23de87f05..7a8f4acc314 100644
--- a/chromium/content/utility/BUILD.gn
+++ b/chromium/content/utility/BUILD.gn
@@ -10,9 +10,13 @@ source_set("utility") {
sources = [
"in_process_utility_thread.cc",
"in_process_utility_thread.h",
+ "utility_blink_platform_impl.cc",
+ "utility_blink_platform_impl.h",
"utility_main.cc",
"utility_thread_impl.cc",
"utility_thread_impl.h",
+ "webthread_impl_for_utility_thread.cc",
+ "webthread_impl_for_utility_thread.h",
]
configs += [ "//content:content_implementation" ]
@@ -23,8 +27,7 @@ source_set("utility") {
"//content/public/child:child_sources",
"//content/public/common:common_sources",
"//courgette:courgette_lib",
- "//mojo/public/interfaces/application",
+ "//mojo/application/public/interfaces",
"//third_party/WebKit/public:blink_headers",
]
}
-
diff --git a/chromium/content/utility/DEPS b/chromium/content/utility/DEPS
index 0818b2c996d..47166e2f530 100644
--- a/chromium/content/utility/DEPS
+++ b/chromium/content/utility/DEPS
@@ -1,4 +1,5 @@
include_rules = [
+ "+components/scheduler/child",
"+content/child",
"+content/public/utility",
"+sandbox/win/src",
diff --git a/chromium/content/utility/in_process_utility_thread.cc b/chromium/content/utility/in_process_utility_thread.cc
index a91bac58418..ab5a229ac07 100644
--- a/chromium/content/utility/in_process_utility_thread.cc
+++ b/chromium/content/utility/in_process_utility_thread.cc
@@ -13,8 +13,9 @@ namespace content {
// are many globals used in the utility process.
static base::LazyInstance<base::Lock> g_one_utility_thread_lock;
-InProcessUtilityThread::InProcessUtilityThread(const std::string& channel_id)
- : Thread("Chrome_InProcUtilityThread"), channel_id_(channel_id) {
+InProcessUtilityThread::InProcessUtilityThread(
+ const InProcessChildThreadParams& params)
+ : Thread("Chrome_InProcUtilityThread"), params_(params) {
}
InProcessUtilityThread::~InProcessUtilityThread() {
@@ -44,11 +45,12 @@ void InProcessUtilityThread::CleanUp() {
void InProcessUtilityThread::InitInternal() {
g_one_utility_thread_lock.Get().Acquire();
child_process_.reset(new ChildProcess());
- child_process_->set_main_thread(new UtilityThreadImpl(channel_id_));
+ child_process_->set_main_thread(new UtilityThreadImpl(params_));
}
-base::Thread* CreateInProcessUtilityThread(const std::string& channel_id) {
- return new InProcessUtilityThread(channel_id);
+base::Thread* CreateInProcessUtilityThread(
+ const InProcessChildThreadParams& params) {
+ return new InProcessUtilityThread(params);
}
} // namespace content
diff --git a/chromium/content/utility/in_process_utility_thread.h b/chromium/content/utility/in_process_utility_thread.h
index 00c71a1dd28..2e16d1e1c39 100644
--- a/chromium/content/utility/in_process_utility_thread.h
+++ b/chromium/content/utility/in_process_utility_thread.h
@@ -9,6 +9,7 @@
#include "base/threading/thread.h"
#include "content/common/content_export.h"
+#include "content/common/in_process_child_thread_params.h"
namespace content {
@@ -16,7 +17,7 @@ class ChildProcess;
class InProcessUtilityThread : public base::Thread {
public:
- InProcessUtilityThread(const std::string& channel_id);
+ InProcessUtilityThread(const InProcessChildThreadParams& params);
~InProcessUtilityThread() override;
private:
@@ -26,14 +27,14 @@ class InProcessUtilityThread : public base::Thread {
void InitInternal();
- std::string channel_id_;
+ InProcessChildThreadParams params_;
scoped_ptr<ChildProcess> child_process_;
DISALLOW_COPY_AND_ASSIGN(InProcessUtilityThread);
};
CONTENT_EXPORT base::Thread* CreateInProcessUtilityThread(
- const std::string& channel_id);
+ const InProcessChildThreadParams& params);
} // namespace content
diff --git a/chromium/content/utility/utility_blink_platform_impl.cc b/chromium/content/utility/utility_blink_platform_impl.cc
new file mode 100644
index 00000000000..b3b73bcbf1f
--- /dev/null
+++ b/chromium/content/utility/utility_blink_platform_impl.cc
@@ -0,0 +1,24 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/utility/utility_blink_platform_impl.h"
+
+#include "content/utility/webthread_impl_for_utility_thread.h"
+
+namespace content {
+
+UtilityBlinkPlatformImpl::UtilityBlinkPlatformImpl()
+ : main_thread_(new WebThreadImplForUtilityThread()) {
+}
+
+UtilityBlinkPlatformImpl::~UtilityBlinkPlatformImpl() {
+}
+
+blink::WebThread* UtilityBlinkPlatformImpl::currentThread() {
+ if (main_thread_->isCurrentThread())
+ return main_thread_.get();
+ return BlinkPlatformImpl::currentThread();
+}
+
+} // namespace content
diff --git a/chromium/content/utility/utility_blink_platform_impl.h b/chromium/content/utility/utility_blink_platform_impl.h
new file mode 100644
index 00000000000..2d2b824214f
--- /dev/null
+++ b/chromium/content/utility/utility_blink_platform_impl.h
@@ -0,0 +1,30 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_UTILITY_UTILITY_BLINK_PLATFORM_IMPL_H_
+#define CONTENT_UTILITY_UTILITY_BLINK_PLATFORM_IMPL_H_
+
+#include "content/child/blink_platform_impl.h"
+
+namespace content {
+
+class WebThreadImplForUtilityThread;
+
+class UtilityBlinkPlatformImpl : public BlinkPlatformImpl {
+ public:
+ UtilityBlinkPlatformImpl();
+ ~UtilityBlinkPlatformImpl() override;
+
+ // BlinkPlatformImpl implementation.
+ blink::WebThread* currentThread() override;
+
+ private:
+ scoped_ptr<WebThreadImplForUtilityThread> main_thread_;
+
+ DISALLOW_COPY_AND_ASSIGN(UtilityBlinkPlatformImpl);
+};
+
+} // namespace content
+
+#endif // CONTENT_UTILITY_UTILITY_BLINK_PLATFORM_IMPL_H_
diff --git a/chromium/content/utility/utility_main.cc b/chromium/content/utility/utility_main.cc
index 1be9918d823..4c6e721287a 100644
--- a/chromium/content/utility/utility_main.cc
+++ b/chromium/content/utility/utility_main.cc
@@ -46,6 +46,12 @@ int UtilityMain(const MainFunctionParams& parameters) {
parameters.sandbox_info->target_services;
if (!target_services)
return false;
+#if defined(ADDRESS_SANITIZER)
+ // Bind and leak dbghelp.dll before the token is lowered, otherwise
+ // AddressSanitizer will crash when trying to symbolize a report.
+ if (!LoadLibraryA("dbghelp.dll"))
+ return false;
+#endif
target_services->LowerToken();
}
#endif
diff --git a/chromium/content/utility/utility_thread_impl.cc b/chromium/content/utility/utility_thread_impl.cc
index 32f9814ee03..1a020ea31ce 100644
--- a/chromium/content/utility/utility_thread_impl.cc
+++ b/chromium/content/utility/utility_thread_impl.cc
@@ -14,6 +14,7 @@
#include "content/common/utility_messages.h"
#include "content/public/common/content_switches.h"
#include "content/public/utility/content_utility_client.h"
+#include "content/utility/utility_blink_platform_impl.h"
#include "ipc/ipc_sync_channel.h"
#include "third_party/WebKit/public/web/WebKit.h"
@@ -35,13 +36,15 @@ void ConvertVector(const SRC& src, DEST* dest) {
} // namespace
-UtilityThreadImpl::UtilityThreadImpl() : single_process_(false) {
+UtilityThreadImpl::UtilityThreadImpl()
+ : ChildThreadImpl(ChildThreadImpl::Options::Builder().Build()) {
Init();
}
-UtilityThreadImpl::UtilityThreadImpl(const std::string& channel_name)
- : ChildThread(Options(channel_name, false)),
- single_process_(true) {
+UtilityThreadImpl::UtilityThreadImpl(const InProcessChildThreadParams& params)
+ : ChildThreadImpl(ChildThreadImpl::Options::Builder()
+ .InBrowserProcess(params)
+ .Build()) {
Init();
}
@@ -49,21 +52,17 @@ UtilityThreadImpl::~UtilityThreadImpl() {
}
void UtilityThreadImpl::Shutdown() {
- ChildThread::Shutdown();
+ ChildThreadImpl::Shutdown();
- if (!single_process_)
+ if (!IsInBrowserProcess())
blink::shutdown();
}
-bool UtilityThreadImpl::Send(IPC::Message* msg) {
- return ChildThread::Send(msg);
-}
-
void UtilityThreadImpl::ReleaseProcessIfNeeded() {
if (batch_mode_)
return;
- if (single_process_) {
+ if (IsInBrowserProcess()) {
// Close the channel to cause UtilityProcessHostImpl to be deleted. We need
// to take a different code path than the multi-process case because that
// depends on the child process going away to close the channel, but that
@@ -74,30 +73,19 @@ void UtilityThreadImpl::ReleaseProcessIfNeeded() {
}
}
-#if defined(OS_WIN)
-
-void UtilityThreadImpl::PreCacheFont(const LOGFONT& log_font) {
- Send(new ChildProcessHostMsg_PreCacheFont(log_font));
-}
-
-void UtilityThreadImpl::ReleaseCachedFonts() {
- Send(new ChildProcessHostMsg_ReleaseCachedFonts());
-}
-
-#endif // OS_WIN
-
void UtilityThreadImpl::Init() {
batch_mode_ = false;
ChildProcess::current()->AddRefProcess();
- if (!single_process_) {
+ if (!IsInBrowserProcess()) {
// We can only initialize WebKit on one thread, and in single process mode
// we run the utility thread on separate thread. This means that if any code
// needs WebKit initialized in the utility process, they need to have
// another path to support single process mode.
- blink_platform_impl_.reset(new BlinkPlatformImpl);
+ blink_platform_impl_.reset(new UtilityBlinkPlatformImpl);
blink::initialize(blink_platform_impl_.get());
}
GetContentClient()->utility()->UtilityThreadStarted();
+ GetContentClient()->utility()->RegisterMojoServices(service_registry());
}
bool UtilityThreadImpl::OnControlMessageReceived(const IPC::Message& msg) {
@@ -131,8 +119,8 @@ void UtilityThreadImpl::OnLoadPlugins(
PluginList* plugin_list = PluginList::Singleton();
std::vector<WebPluginInfo> plugins;
- // TODO(bauerb): If we restart loading plug-ins, we might mess up the logic in
- // PluginList::ShouldLoadPlugin due to missing the previously loaded plug-ins
+ // TODO(bauerb): If we restart loading plugins, we might mess up the logic in
+ // PluginList::ShouldLoadPlugin due to missing the previously loaded plugins
// in |plugin_groups|.
for (size_t i = 0; i < plugin_paths.size(); ++i) {
WebPluginInfo plugin;
diff --git a/chromium/content/utility/utility_thread_impl.h b/chromium/content/utility/utility_thread_impl.h
index 5b186fc21cf..3b1d66d65d4 100644
--- a/chromium/content/utility/utility_thread_impl.h
+++ b/chromium/content/utility/utility_thread_impl.h
@@ -10,7 +10,7 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
#include "content/common/content_export.h"
#include "content/public/utility/utility_thread.h"
@@ -20,23 +20,25 @@ class FilePath;
namespace content {
class BlinkPlatformImpl;
+class UtilityBlinkPlatformImpl;
+
+#if defined(COMPILER_MSVC)
+// See explanation for other RenderViewHostImpl which is the same issue.
+#pragma warning(push)
+#pragma warning(disable: 4250)
+#endif
// This class represents the background thread where the utility task runs.
class UtilityThreadImpl : public UtilityThread,
- public ChildThread {
+ public ChildThreadImpl {
public:
UtilityThreadImpl();
// Constructor that's used when running in single process mode.
- explicit UtilityThreadImpl(const std::string& channel_name);
+ explicit UtilityThreadImpl(const InProcessChildThreadParams& params);
~UtilityThreadImpl() override;
void Shutdown() override;
- bool Send(IPC::Message* msg) override;
void ReleaseProcessIfNeeded() override;
-#if defined(OS_WIN)
- virtual void PreCacheFont(const LOGFONT& log_font) override;
- virtual void ReleaseCachedFonts() override;
-#endif
private:
void Init();
@@ -55,14 +57,15 @@ class UtilityThreadImpl : public UtilityThread,
// True when we're running in batch mode.
bool batch_mode_;
- // True if running in single process mode.
- bool single_process_;
-
- scoped_ptr<BlinkPlatformImpl> blink_platform_impl_;
+ scoped_ptr<UtilityBlinkPlatformImpl> blink_platform_impl_;
DISALLOW_COPY_AND_ASSIGN(UtilityThreadImpl);
};
+#if defined(COMPILER_MSVC)
+#pragma warning(pop)
+#endif
+
} // namespace content
#endif // CONTENT_UTILITY_UTILITY_THREAD_IMPL_H_
diff --git a/chromium/content/utility/webthread_impl_for_utility_thread.cc b/chromium/content/utility/webthread_impl_for_utility_thread.cc
new file mode 100644
index 00000000000..12c4caa6607
--- /dev/null
+++ b/chromium/content/utility/webthread_impl_for_utility_thread.cc
@@ -0,0 +1,37 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/utility/webthread_impl_for_utility_thread.h"
+
+namespace content {
+
+WebThreadImplForUtilityThread::WebThreadImplForUtilityThread()
+ : task_runner_(base::MessageLoopProxy::current()),
+ thread_id_(base::PlatformThread::CurrentId()) {
+}
+
+WebThreadImplForUtilityThread::~WebThreadImplForUtilityThread() {
+}
+
+blink::WebScheduler* WebThreadImplForUtilityThread::scheduler() const {
+ NOTIMPLEMENTED();
+ return nullptr;
+}
+
+blink::PlatformThreadId WebThreadImplForUtilityThread::threadId() const {
+ return thread_id_;
+}
+
+base::SingleThreadTaskRunner* WebThreadImplForUtilityThread::TaskRunner()
+ const {
+ return task_runner_.get();
+}
+
+scheduler::SingleThreadIdleTaskRunner*
+WebThreadImplForUtilityThread::IdleTaskRunner() const {
+ NOTIMPLEMENTED();
+ return nullptr;
+}
+
+} // namespace content
diff --git a/chromium/content/utility/webthread_impl_for_utility_thread.h b/chromium/content/utility/webthread_impl_for_utility_thread.h
new file mode 100644
index 00000000000..15d7e57fe7d
--- /dev/null
+++ b/chromium/content/utility/webthread_impl_for_utility_thread.h
@@ -0,0 +1,35 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_UTILITY_WEBTHREAD_IMPL_FOR_UTILITY_THREAD_H_
+#define CONTENT_UTILITY_WEBTHREAD_IMPL_FOR_UTILITY_THREAD_H_
+
+#include "base/memory/ref_counted.h"
+#include "components/scheduler/child/webthread_base.h"
+
+namespace content {
+
+class WebThreadImplForUtilityThread : public scheduler::WebThreadBase {
+ public:
+ WebThreadImplForUtilityThread();
+ ~WebThreadImplForUtilityThread() override;
+
+ // blink::WebThread implementation.
+ blink::WebScheduler* scheduler() const override;
+ blink::PlatformThreadId threadId() const override;
+
+ // WebThreadBase implementation.
+ base::SingleThreadTaskRunner* TaskRunner() const override;
+ scheduler::SingleThreadIdleTaskRunner* IdleTaskRunner() const override;
+
+ private:
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+ blink::PlatformThreadId thread_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebThreadImplForUtilityThread);
+};
+
+} // namespace content
+
+#endif // CONTENT_UTILITY_WEBTHREAD_IMPL_FOR_UTILITY_THREAD_H_
diff --git a/chromium/content/zygote/zygote_linux.cc b/chromium/content/zygote/zygote_linux.cc
index a464fcdf6a7..5a84dec6db9 100644
--- a/chromium/content/zygote/zygote_linux.cc
+++ b/chromium/content/zygote/zygote_linux.cc
@@ -11,7 +11,6 @@
#include <sys/wait.h>
#include "base/command_line.h"
-#include "base/debug/trace_event.h"
#include "base/files/file_util.h"
#include "base/linux_util.h"
#include "base/logging.h"
@@ -22,6 +21,10 @@
#include "base/posix/global_descriptors.h"
#include "base/posix/unix_domain_socket_linux.h"
#include "base/process/kill.h"
+#include "base/process/launch.h"
+#include "base/process/process.h"
+#include "base/process/process_handle.h"
+#include "base/trace_event/trace_event.h"
#include "content/common/child_process_sandbox_support_impl_linux.h"
#include "content/common/sandbox_linux/sandbox_linux.h"
#include "content/common/set_process_title.h"
@@ -29,13 +32,12 @@
#include "content/public/common/content_descriptors.h"
#include "content/public/common/result_codes.h"
#include "content/public/common/sandbox_linux.h"
+#include "content/public/common/send_zygote_child_ping_linux.h"
#include "content/public/common/zygote_fork_delegate_linux.h"
#include "ipc/ipc_channel.h"
#include "ipc/ipc_switches.h"
-
-#if defined(ADDRESS_SANITIZER)
-#include <sanitizer/asan_interface.h>
-#endif
+#include "sandbox/linux/services/credentials.h"
+#include "sandbox/linux/services/namespace_sandbox.h"
// See http://code.google.com/p/chromium/wiki/LinuxZygote
@@ -47,10 +49,18 @@ namespace {
void SIGCHLDHandler(int signal) {
}
+// On Linux, when a process is the init process of a PID namespace, it cannot be
+// terminated by signals like SIGTERM or SIGINT, since they are ignored unless
+// we register a handler for them. In the handlers, we exit with this special
+// exit code that GetTerminationStatus understands to mean that we were
+// terminated by an external signal.
+const int kKilledExitCode = 0x80;
+const int kUnexpectedExitCode = 0x81;
+
int LookUpFd(const base::GlobalDescriptors::Mapping& fd_mapping, uint32_t key) {
for (size_t index = 0; index < fd_mapping.size(); ++index) {
- if (fd_mapping[index].first == key)
- return fd_mapping[index].second;
+ if (fd_mapping[index].key == key)
+ return fd_mapping[index].fd;
}
return -1;
}
@@ -104,9 +114,9 @@ bool Zygote::ProcessRequests() {
struct sigaction action;
memset(&action, 0, sizeof(action));
action.sa_handler = &SIGCHLDHandler;
- CHECK(sigaction(SIGCHLD, &action, NULL) == 0);
+ PCHECK(sigaction(SIGCHLD, &action, NULL) == 0);
- if (UsingSUIDSandbox()) {
+ if (UsingSUIDSandbox() || UsingNSSandbox()) {
// Let the ZygoteHost know we are ready to go.
// The receiving code is in content/browser/zygote_host_linux.cc.
bool r = UnixDomainSocket::SendMsg(kZygoteSocketPairFd,
@@ -147,6 +157,10 @@ bool Zygote::UsingSUIDSandbox() const {
return sandbox_flags_ & kSandboxLinuxSUID;
}
+bool Zygote::UsingNSSandbox() const {
+ return sandbox_flags_ & kSandboxLinuxUserNS;
+}
+
bool Zygote::HandleRequestFromBrowser(int fd) {
ScopedVector<base::ScopedFD> fds;
char buf[kZygoteMaxMessageLength];
@@ -161,8 +175,9 @@ bool Zygote::HandleRequestFromBrowser(int fd) {
it < extra_fds_.end(); ++it) {
PCHECK(0 == IGNORE_EINTR(close(*it)));
}
-#if !defined(ADDRESS_SANITIZER)
- // TODO(earthdok): add watchdog thread before using this in non-ASAN builds.
+#if !defined(SANITIZER_COVERAGE)
+ // TODO(earthdok): add watchdog thread before using this in builds not
+ // using sanitizer coverage.
CHECK(extra_children_.empty());
#endif
for (std::vector<base::ProcessHandle>::iterator it =
@@ -183,24 +198,24 @@ bool Zygote::HandleRequestFromBrowser(int fd) {
PickleIterator iter(pickle);
int kind;
- if (pickle.ReadInt(&iter, &kind)) {
+ if (iter.ReadInt(&kind)) {
switch (kind) {
case kZygoteCommandFork:
// This function call can return multiple times, once per fork().
- return HandleForkRequest(fd, pickle, iter, fds.Pass());
+ return HandleForkRequest(fd, iter, fds.Pass());
case kZygoteCommandReap:
if (!fds.empty())
break;
- HandleReapRequest(fd, pickle, iter);
+ HandleReapRequest(fd, iter);
return false;
case kZygoteCommandGetTerminationStatus:
if (!fds.empty())
break;
- HandleGetTerminationStatus(fd, pickle, iter);
+ HandleGetTerminationStatus(fd, iter);
return false;
case kZygoteCommandGetSandboxStatus:
- HandleGetSandboxStatus(fd, pickle, iter);
+ HandleGetSandboxStatus(fd, iter);
return false;
case kZygoteCommandForkRealPID:
// This shouldn't happen in practice, but some failure paths in
@@ -221,11 +236,10 @@ bool Zygote::HandleRequestFromBrowser(int fd) {
// TODO(jln): remove callers to this broken API. See crbug.com/274855.
void Zygote::HandleReapRequest(int fd,
- const Pickle& pickle,
PickleIterator iter) {
base::ProcessId child;
- if (!pickle.ReadInt(&iter, &child)) {
+ if (!iter.ReadInt(&child)) {
LOG(WARNING) << "Error parsing reap request from browser";
return;
}
@@ -247,7 +261,7 @@ void Zygote::HandleReapRequest(int fd,
// with this for now.
#if !defined(THREAD_SANITIZER)
// TODO(jln): this old code is completely broken. See crbug.com/274855.
- base::EnsureProcessTerminated(child_info.internal_pid);
+ base::EnsureProcessTerminated(base::Process(child_info.internal_pid));
#else
LOG(WARNING) << "Zygote process omitting a call to "
<< "base::EnsureProcessTerminated() for child pid " << child
@@ -301,17 +315,20 @@ bool Zygote::GetTerminationStatus(base::ProcessHandle real_pid,
// Time to forget about this process.
process_info_map_.erase(real_pid);
}
+
+ if (WIFEXITED(*exit_code) && WEXITSTATUS(*exit_code) == kKilledExitCode) {
+ *status = base::TERMINATION_STATUS_PROCESS_WAS_KILLED;
+ }
+
return true;
}
void Zygote::HandleGetTerminationStatus(int fd,
- const Pickle& pickle,
PickleIterator iter) {
bool known_dead;
base::ProcessHandle child_requested;
- if (!pickle.ReadBool(&iter, &known_dead) ||
- !pickle.ReadInt(&iter, &child_requested)) {
+ if (!iter.ReadBool(&known_dead) || !iter.ReadInt(&child_requested)) {
LOG(WARNING) << "Error parsing GetTerminationStatus request "
<< "from browser";
return;
@@ -373,10 +390,33 @@ int Zygote::ForkWithRealPid(const std::string& process_type,
CHECK_NE(pid, 0);
} else {
CreatePipe(&read_pipe, &write_pipe);
- pid = fork();
+ if (sandbox_flags_ & kSandboxLinuxPIDNS &&
+ sandbox_flags_ & kSandboxLinuxUserNS) {
+ pid = sandbox::NamespaceSandbox::ForkInNewPidNamespace(
+ /*drop_capabilities_in_child=*/true);
+ } else {
+ pid = fork();
+ }
}
if (pid == 0) {
+ // If the process is the init process inside a PID namespace, it must have
+ // explicit signal handlers.
+ if (getpid() == 1) {
+ for (const int sig : {SIGINT, SIGTERM}) {
+ sandbox::NamespaceSandbox::InstallTerminationSignalHandler(
+ sig, kKilledExitCode);
+ }
+
+ static const int kUnexpectedSignals[] = {
+ SIGHUP, SIGQUIT, SIGABRT, SIGPIPE, SIGUSR1, SIGUSR2,
+ };
+ for (const int sig : kUnexpectedSignals) {
+ sandbox::NamespaceSandbox::InstallTerminationSignalHandler(
+ sig, kUnexpectedExitCode);
+ }
+ }
+
// In the child process.
write_pipe.reset();
@@ -399,7 +439,7 @@ int Zygote::ForkWithRealPid(const std::string& process_type,
IPC::Channel::SetGlobalPid(real_pid);
// Force the real PID so chrome event data have a PID that corresponds
// to system trace event data.
- base::debug::TraceLog::GetInstance()->SetProcessID(
+ base::trace_event::TraceLog::GetInstance()->SetProcessID(
static_cast<int>(real_pid));
#endif
return 0;
@@ -424,9 +464,9 @@ int Zygote::ForkWithRealPid(const std::string& process_type,
PickleIterator iter(pickle);
int kind;
- CHECK(pickle.ReadInt(&iter, &kind));
+ CHECK(iter.ReadInt(&kind));
CHECK(kind == kZygoteCommandForkRealPID);
- CHECK(pickle.ReadInt(&iter, &real_pid));
+ CHECK(iter.ReadInt(&real_pid));
}
// Fork failed.
@@ -462,8 +502,7 @@ int Zygote::ForkWithRealPid(const std::string& process_type,
return real_pid;
}
-base::ProcessId Zygote::ReadArgsAndFork(const Pickle& pickle,
- PickleIterator iter,
+base::ProcessId Zygote::ReadArgsAndFork(PickleIterator iter,
ScopedVector<base::ScopedFD> fds,
std::string* uma_name,
int* uma_sample,
@@ -477,21 +516,21 @@ base::ProcessId Zygote::ReadArgsAndFork(const Pickle& pickle,
const std::string channel_id_prefix = std::string("--")
+ switches::kProcessChannelID + std::string("=");
- if (!pickle.ReadString(&iter, &process_type))
+ if (!iter.ReadString(&process_type))
return -1;
- if (!pickle.ReadInt(&iter, &argc))
+ if (!iter.ReadInt(&argc))
return -1;
for (int i = 0; i < argc; ++i) {
std::string arg;
- if (!pickle.ReadString(&iter, &arg))
+ if (!iter.ReadString(&arg))
return -1;
args.push_back(arg);
if (arg.compare(0, channel_id_prefix.length(), channel_id_prefix) == 0)
channel_id = arg.substr(channel_id_prefix.length());
}
- if (!pickle.ReadInt(&iter, &numfds))
+ if (!iter.ReadInt(&numfds))
return -1;
if (numfds != static_cast<int>(fds.size()))
return -1;
@@ -504,12 +543,12 @@ base::ProcessId Zygote::ReadArgsAndFork(const Pickle& pickle,
// Remaining FDs are for the global descriptor mapping.
for (int i = 1; i < numfds; ++i) {
base::GlobalDescriptors::Key key;
- if (!pickle.ReadUInt32(&iter, &key))
+ if (!iter.ReadUInt32(&key))
return -1;
- mapping.push_back(std::make_pair(key, fds[i]->get()));
+ mapping.push_back(base::GlobalDescriptors::Descriptor(key, fds[i]->get()));
}
- mapping.push_back(std::make_pair(
+ mapping.push_back(base::GlobalDescriptors::Descriptor(
static_cast<uint32_t>(kSandboxIPCChannel), GetSandboxFD()));
// Returns twice, once per process.
@@ -533,9 +572,9 @@ base::ProcessId Zygote::ReadArgsAndFork(const Pickle& pickle,
base::GlobalDescriptors::GetInstance()->Reset(mapping);
// Reset the process-wide command line to our new command line.
- CommandLine::Reset();
- CommandLine::Init(0, NULL);
- CommandLine::ForCurrentProcess()->InitFromArgv(args);
+ base::CommandLine::Reset();
+ base::CommandLine::Init(0, NULL);
+ base::CommandLine::ForCurrentProcess()->InitFromArgv(args);
// Update the process title. The argv was already cached by the call to
// SetProcessTitleFromCommandLine in ChromeMain, so we can pass NULL here
@@ -549,14 +588,13 @@ base::ProcessId Zygote::ReadArgsAndFork(const Pickle& pickle,
}
bool Zygote::HandleForkRequest(int fd,
- const Pickle& pickle,
PickleIterator iter,
ScopedVector<base::ScopedFD> fds) {
std::string uma_name;
int uma_sample;
int uma_boundary_value;
base::ProcessId child_pid = ReadArgsAndFork(
- pickle, iter, fds.Pass(), &uma_name, &uma_sample, &uma_boundary_value);
+ iter, fds.Pass(), &uma_name, &uma_sample, &uma_boundary_value);
if (child_pid == 0)
return true;
// If there's no UMA report for this particular fork, then check if any
@@ -580,7 +618,6 @@ bool Zygote::HandleForkRequest(int fd,
}
bool Zygote::HandleGetSandboxStatus(int fd,
- const Pickle& pickle,
PickleIterator iter) {
if (HANDLE_EINTR(write(fd, &sandbox_flags_, sizeof(sandbox_flags_))) !=
sizeof(sandbox_flags_)) {
diff --git a/chromium/content/zygote/zygote_linux.h b/chromium/content/zygote/zygote_linux.h
index f93ea035564..80d4a2933b5 100644
--- a/chromium/content/zygote/zygote_linux.h
+++ b/chromium/content/zygote/zygote_linux.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_ZYGOTE_ZYGOTE_H_
-#define CONTENT_ZYGOTE_ZYGOTE_H_
+#ifndef CONTENT_ZYGOTE_ZYGOTE_LINUX_H_
+#define CONTENT_ZYGOTE_ZYGOTE_LINUX_H_
#include <stddef.h>
@@ -53,6 +53,8 @@ class Zygote {
// Returns true if the SUID sandbox is active.
bool UsingSUIDSandbox() const;
+ // Returns true if the NS sandbox is active.
+ bool UsingNSSandbox() const;
// ---------------------------------------------------------------------------
// Requests from the browser...
@@ -61,7 +63,7 @@ class Zygote {
// new process and thus need to unwind back into ChromeMain.
bool HandleRequestFromBrowser(int fd);
- void HandleReapRequest(int fd, const Pickle& pickle, PickleIterator iter);
+ void HandleReapRequest(int fd, PickleIterator iter);
// Get the termination status of |real_pid|. |real_pid| is the PID as it
// appears outside of the sandbox.
@@ -72,7 +74,6 @@ class Zygote {
int* exit_code);
void HandleGetTerminationStatus(int fd,
- const Pickle& pickle,
PickleIterator iter);
// This is equivalent to fork(), except that, when using the SUID sandbox, it
@@ -91,11 +92,10 @@ class Zygote {
int* uma_sample,
int* uma_boundary_value);
- // Unpacks process type and arguments from |pickle| and forks a new process.
+ // Unpacks process type and arguments from |iter| and forks a new process.
// Returns -1 on error, otherwise returns twice, returning 0 to the child
// process and the child process ID to the parent process, like fork().
- base::ProcessId ReadArgsAndFork(const Pickle& pickle,
- PickleIterator iter,
+ base::ProcessId ReadArgsAndFork(PickleIterator iter,
ScopedVector<base::ScopedFD> fds,
std::string* uma_name,
int* uma_sample,
@@ -106,12 +106,10 @@ class Zygote {
// otherwise writes the child_pid back to the browser via |fd|. Writes a
// child_pid of -1 on error.
bool HandleForkRequest(int fd,
- const Pickle& pickle,
PickleIterator iter,
ScopedVector<base::ScopedFD> fds);
bool HandleGetSandboxStatus(int fd,
- const Pickle& pickle,
PickleIterator iter);
// The Zygote needs to keep some information about each process. Most
@@ -140,4 +138,4 @@ class Zygote {
} // namespace content
-#endif // CONTENT_ZYGOTE_ZYGOTE_H_
+#endif // CONTENT_ZYGOTE_ZYGOTE_LINUX_H_
diff --git a/chromium/content/zygote/zygote_main_linux.cc b/chromium/content/zygote/zygote_main_linux.cc
index 361511e3737..1aee6bd77ad 100644
--- a/chromium/content/zygote/zygote_main_linux.cc
+++ b/chromium/content/zygote/zygote_main_linux.cc
@@ -13,6 +13,8 @@
#include <sys/types.h>
#include <unistd.h>
+#include <vector>
+
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/command_line.h"
@@ -29,6 +31,7 @@
#include "build/build_config.h"
#include "content/common/child_process_sandbox_support_impl_linux.h"
#include "content/common/font_config_ipc_linux.h"
+#include "content/common/sandbox_linux/sandbox_debug_handling_linux.h"
#include "content/common/sandbox_linux/sandbox_linux.h"
#include "content/common/zygote_commands_linux.h"
#include "content/public/common/content_switches.h"
@@ -37,8 +40,11 @@
#include "content/public/common/zygote_fork_delegate_linux.h"
#include "content/zygote/zygote_linux.h"
#include "crypto/nss_util.h"
+#include "sandbox/linux/services/credentials.h"
#include "sandbox/linux/services/init_process_reaper.h"
#include "sandbox/linux/services/libc_urandom_override.h"
+#include "sandbox/linux/services/namespace_sandbox.h"
+#include "sandbox/linux/services/thread_helpers.h"
#include "sandbox/linux/suid/client/setuid_sandbox_client.h"
#include "third_party/icu/source/i18n/unicode/timezone.h"
#include "third_party/skia/include/ports/SkFontConfigInterface.h"
@@ -60,47 +66,26 @@
#include "third_party/libjingle/overrides/init_webrtc.h"
#endif
-#if defined(ADDRESS_SANITIZER)
-#include <sanitizer/asan_interface.h>
+#if defined(SANITIZER_COVERAGE)
+#include <sanitizer/common_interface_defs.h>
+#include <sanitizer/coverage_interface.h>
#endif
namespace content {
namespace {
-void DoChrootSignalHandler(int) {
- const int old_errno = errno;
- const char kFirstMessage[] = "Chroot signal handler called.\n";
- ignore_result(write(STDERR_FILENO, kFirstMessage, sizeof(kFirstMessage) - 1));
-
- const int chroot_ret = chroot("/");
-
- char kSecondMessage[100];
- const ssize_t printed =
- base::strings::SafeSPrintf(kSecondMessage,
- "chroot() returned %d. Errno is %d.\n",
- chroot_ret,
- errno);
- if (printed > 0 && printed < static_cast<ssize_t>(sizeof(kSecondMessage))) {
- ignore_result(write(STDERR_FILENO, kSecondMessage, printed));
+void CloseFds(const std::vector<int>& fds) {
+ for (const auto& it : fds) {
+ PCHECK(0 == IGNORE_EINTR(close(it)));
}
- errno = old_errno;
}
-// This is a quick hack to allow testing sandbox crash reports in production
-// binaries.
-// This installs a signal handler for SIGUSR2 that performs a chroot().
-// In most of our BPF policies, it is a "watched" system call which will
-// trigger a SIGSYS signal whose handler will crash.
-// This has been added during the investigation of https://crbug.com/415842.
-void InstallSandboxCrashTestHandler() {
- struct sigaction act = {};
- act.sa_handler = DoChrootSignalHandler;
- CHECK_EQ(0, sigemptyset(&act.sa_mask));
- act.sa_flags = 0;
-
- PCHECK(0 == sigaction(SIGUSR2, &act, NULL));
+void RunTwoClosures(const base::Closure* first, const base::Closure* second) {
+ first->Run();
+ second->Run();
}
+
} // namespace
// See http://code.google.com/p/chromium/wiki/LinuxZygote
@@ -125,8 +110,8 @@ static void ProxyLocaltimeCallToBrowser(time_t input, struct tm* output,
Pickle reply(reinterpret_cast<char*>(reply_buf), r);
PickleIterator iter(reply);
std::string result, timezone;
- if (!reply.ReadString(&iter, &result) ||
- !reply.ReadString(&iter, &timezone) ||
+ if (!iter.ReadString(&result) ||
+ !iter.ReadString(&timezone) ||
result.size() != sizeof(struct tm)) {
memset(output, 0, sizeof(struct tm));
return;
@@ -324,7 +309,7 @@ void PreloadPepperPlugins() {
std::vector<PepperPluginInfo> plugins;
ComputePepperPluginList(&plugins);
for (size_t i = 0; i < plugins.size(); ++i) {
- if (!plugins[i].is_internal && plugins[i].is_sandboxed) {
+ if (!plugins[i].is_internal) {
base::NativeLibraryLoadError error;
base::NativeLibrary library = base::LoadNativeLibrary(plugins[i].path,
&error);
@@ -353,7 +338,7 @@ static void ZygotePreSandboxInit() {
// cached and there's no more need to access the file system.
scoped_ptr<icu::TimeZone> zone(icu::TimeZone::createDefault());
-#if defined(USE_NSS)
+#if defined(USE_NSS_CERTS)
// NSS libraries are loaded before sandbox is activated. This is to allow
// successful initialization of NSS which tries to load extra library files.
crypto::LoadNSSLibraries();
@@ -424,43 +409,28 @@ static bool EnterSuidSandbox(sandbox::SetuidSandboxClient* setuid_sandbox,
CHECK(CreateInitProcessReaper(post_fork_parent_callback));
}
-#if !defined(OS_OPENBSD)
- // Previously, we required that the binary be non-readable. This causes the
- // kernel to mark the process as non-dumpable at startup. The thinking was
- // that, although we were putting the renderers into a PID namespace (with
- // the SUID sandbox), they would nonetheless be in the /same/ PID
- // namespace. So they could ptrace each other unless they were non-dumpable.
- //
- // If the binary was readable, then there would be a window between process
- // startup and the point where we set the non-dumpable flag in which a
- // compromised renderer could ptrace attach.
- //
- // However, now that we have a zygote model, only the (trusted) zygote
- // exists at this point and we can set the non-dumpable flag which is
- // inherited by all our renderer children.
- //
- // Note: a non-dumpable process can't be debugged. To debug sandbox-related
- // issues, one can specify --allow-sandbox-debugging to let the process be
- // dumpable.
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
- if (!command_line.HasSwitch(switches::kAllowSandboxDebugging)) {
- prctl(PR_SET_DUMPABLE, 0, 0, 0, 0);
- if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) {
- LOG(ERROR) << "Failed to set non-dumpable flag";
- return false;
- }
- } else {
- // If sandbox debugging is allowed, install a handler for sandbox-related
- // crash testing.
- InstallSandboxCrashTestHandler();
- }
+ CHECK(SandboxDebugHandling::SetDumpableStatusAndHandlers());
+ return true;
+}
-#endif
+static void DropAllCapabilities(int proc_fd) {
+ CHECK(sandbox::Credentials::DropAllCapabilities(proc_fd));
+}
- return true;
+static void EnterNamespaceSandbox(LinuxSandbox* linux_sandbox,
+ base::Closure* post_fork_parent_callback) {
+ linux_sandbox->EngageNamespaceSandbox();
+
+ if (getpid() == 1) {
+ base::Closure drop_all_caps_callback =
+ base::Bind(&DropAllCapabilities, linux_sandbox->proc_fd());
+ base::Closure callback = base::Bind(
+ &RunTwoClosures, &drop_all_caps_callback, post_fork_parent_callback);
+ CHECK(CreateInitProcessReaper(&callback));
+ }
}
-#if defined(ADDRESS_SANITIZER)
+#if defined(SANITIZER_COVERAGE)
const size_t kSanitizerMaxMessageLength = 1 * 1024 * 1024;
// A helper process which collects code coverage data from the renderers over a
@@ -494,13 +464,17 @@ static void CreateSanitizerCoverageSocketPair(int fds[2]) {
PCHECK(0 == shutdown(fds[1], SHUT_RD));
}
-static pid_t ForkSanitizerCoverageHelper(int child_fd, int parent_fd,
- base::ScopedFD file_fd) {
+static pid_t ForkSanitizerCoverageHelper(
+ int child_fd,
+ int parent_fd,
+ base::ScopedFD file_fd,
+ const std::vector<int>& extra_fds_to_close) {
pid_t pid = fork();
PCHECK(pid >= 0);
if (pid == 0) {
// In the child.
PCHECK(0 == IGNORE_EINTR(close(parent_fd)));
+ CloseFds(extra_fds_to_close);
SanitizerCoverageHelper(child_fd, file_fd.get());
_exit(0);
} else {
@@ -510,16 +484,10 @@ static pid_t ForkSanitizerCoverageHelper(int child_fd, int parent_fd,
}
}
-void CloseFdPair(const int fds[2]) {
- PCHECK(0 == IGNORE_EINTR(close(fds[0])));
- PCHECK(0 == IGNORE_EINTR(close(fds[1])));
-}
-#endif // defined(ADDRESS_SANITIZER)
+#endif // defined(SANITIZER_COVERAGE)
-// If |is_suid_sandbox_child|, then make sure that the setuid sandbox is
-// engaged.
static void EnterLayerOneSandbox(LinuxSandbox* linux_sandbox,
- bool is_suid_sandbox_child,
+ const bool using_layer1_sandbox,
base::Closure* post_fork_parent_callback) {
DCHECK(linux_sandbox);
@@ -527,15 +495,18 @@ static void EnterLayerOneSandbox(LinuxSandbox* linux_sandbox,
// Check that the pre-sandbox initialization didn't spawn threads.
#if !defined(THREAD_SANITIZER)
- DCHECK(linux_sandbox->IsSingleThreaded());
+ DCHECK(sandbox::ThreadHelpers::IsSingleThreaded());
#endif
sandbox::SetuidSandboxClient* setuid_sandbox =
linux_sandbox->setuid_sandbox_client();
-
- if (is_suid_sandbox_child) {
+ if (setuid_sandbox->IsSuidSandboxChild()) {
CHECK(EnterSuidSandbox(setuid_sandbox, post_fork_parent_callback))
<< "Failed to enter setuid sandbox";
+ } else if (sandbox::NamespaceSandbox::InNewUserNamespace()) {
+ EnterNamespaceSandbox(linux_sandbox, post_fork_parent_callback);
+ } else {
+ CHECK(!using_layer1_sandbox);
}
}
@@ -544,11 +515,11 @@ bool ZygoteMain(const MainFunctionParams& params,
g_am_zygote_or_renderer = true;
sandbox::InitLibcUrandomOverrides();
- base::Closure *post_fork_parent_callback = NULL;
+ std::vector<int> fds_to_close_post_fork;
LinuxSandbox* linux_sandbox = LinuxSandbox::GetInstance();
-#if defined(ADDRESS_SANITIZER)
+#if defined(SANITIZER_COVERAGE)
const std::string sancov_file_name =
"zygote." + base::Uint64ToString(base::RandUint64());
base::ScopedFD sancov_file_fd(
@@ -562,19 +533,29 @@ bool ZygoteMain(const MainFunctionParams& params,
// Zygote termination will block until the helper process exits, which will
// not happen until the write end of the socket is closed everywhere. Make
// sure the init process does not hold on to it.
- base::Closure close_sancov_socket_fds =
- base::Bind(&CloseFdPair, sancov_socket_fds);
- post_fork_parent_callback = &close_sancov_socket_fds;
-#endif
-
- // This will pre-initialize the various sandboxes that need it.
- linux_sandbox->PreinitializeSandbox();
+ fds_to_close_post_fork.push_back(sancov_socket_fds[0]);
+ fds_to_close_post_fork.push_back(sancov_socket_fds[1]);
+#endif // SANITIZER_COVERAGE
+
+ // Skip pre-initializing sandbox under --no-sandbox for crbug.com/444900.
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kNoSandbox)) {
+ // This will pre-initialize the various sandboxes that need it.
+ linux_sandbox->PreinitializeSandbox();
+ }
- const bool must_enable_setuid_sandbox =
+ const bool using_setuid_sandbox =
linux_sandbox->setuid_sandbox_client()->IsSuidSandboxChild();
- if (must_enable_setuid_sandbox) {
+ const bool using_namespace_sandbox =
+ sandbox::NamespaceSandbox::InNewUserNamespace();
+ const bool using_layer1_sandbox =
+ using_setuid_sandbox || using_namespace_sandbox;
+
+ if (using_setuid_sandbox) {
linux_sandbox->setuid_sandbox_client()->CloseDummyFile();
+ }
+ if (using_layer1_sandbox) {
// Let the ZygoteHost know we're booting up.
CHECK(UnixDomainSocket::SendMsg(kZygoteSocketPairFd,
kZygoteBootMessage,
@@ -584,22 +565,32 @@ bool ZygoteMain(const MainFunctionParams& params,
VLOG(1) << "ZygoteMain: initializing " << fork_delegates.size()
<< " fork delegates";
- for (ScopedVector<ZygoteForkDelegate>::iterator i = fork_delegates.begin();
- i != fork_delegates.end();
- ++i) {
- (*i)->Init(GetSandboxFD(), must_enable_setuid_sandbox);
+ for (ZygoteForkDelegate* fork_delegate : fork_delegates) {
+ fork_delegate->Init(GetSandboxFD(), using_layer1_sandbox);
}
+ const std::vector<int> sandbox_fds_to_close_post_fork =
+ linux_sandbox->GetFileDescriptorsToClose();
+
+ fds_to_close_post_fork.insert(fds_to_close_post_fork.end(),
+ sandbox_fds_to_close_post_fork.begin(),
+ sandbox_fds_to_close_post_fork.end());
+ base::Closure post_fork_parent_callback =
+ base::Bind(&CloseFds, fds_to_close_post_fork);
+
// Turn on the first layer of the sandbox if the configuration warrants it.
- EnterLayerOneSandbox(linux_sandbox, must_enable_setuid_sandbox,
- post_fork_parent_callback);
+ EnterLayerOneSandbox(linux_sandbox, using_layer1_sandbox,
+ &post_fork_parent_callback);
+ // Extra children and file descriptors created that the Zygote must have
+ // knowledge of.
std::vector<pid_t> extra_children;
std::vector<int> extra_fds;
-#if defined(ADDRESS_SANITIZER)
+#if defined(SANITIZER_COVERAGE)
pid_t sancov_helper_pid = ForkSanitizerCoverageHelper(
- sancov_socket_fds[0], sancov_socket_fds[1], sancov_file_fd.Pass());
+ sancov_socket_fds[0], sancov_socket_fds[1], sancov_file_fd.Pass(),
+ sandbox_fds_to_close_post_fork);
// It's important that the zygote reaps the helper before dying. Otherwise,
// the destruction of the PID namespace could kill the helper before it
// completes its I/O tasks. |sancov_helper_pid| will exit once the last
@@ -609,11 +600,15 @@ bool ZygoteMain(const MainFunctionParams& params,
// from the zygote. We must keep it open until the very end of the zygote's
// lifetime, even though we don't explicitly use it.
extra_fds.push_back(sancov_socket_fds[1]);
-#endif
+#endif // SANITIZER_COVERAGE
+
+ const int sandbox_flags = linux_sandbox->GetStatus();
+
+ const bool setuid_sandbox_engaged = sandbox_flags & kSandboxLinuxSUID;
+ CHECK_EQ(using_setuid_sandbox, setuid_sandbox_engaged);
- int sandbox_flags = linux_sandbox->GetStatus();
- bool setuid_sandbox_engaged = sandbox_flags & kSandboxLinuxSUID;
- CHECK_EQ(must_enable_setuid_sandbox, setuid_sandbox_engaged);
+ const bool namespace_sandbox_engaged = sandbox_flags & kSandboxLinuxUserNS;
+ CHECK_EQ(using_namespace_sandbox, namespace_sandbox_engaged);
Zygote zygote(sandbox_flags, fork_delegates.Pass(), extra_children,
extra_fds);